diff --git a/Makefile b/Makefile index 67d9d854d1..17a7f5512b 100644 --- a/Makefile +++ b/Makefile @@ -65,6 +65,7 @@ $(TESTDIRS): $(CLEANTESTDIRS): @make -C $(@:clean-%=%) clean + @rm -fr results .PHONY: release release: diff --git a/nanostack/fhss_config.h b/nanostack/fhss_config.h index debb62503f..a388f5643f 100644 --- a/nanostack/fhss_config.h +++ b/nanostack/fhss_config.h @@ -183,6 +183,12 @@ typedef struct fhss_statistics { /** FHSS synchronization lost counter. */ uint32_t fhss_synch_lost; + + /** FHSS TX to unknown neighbour counter. */ + uint32_t fhss_unknown_neighbor; + + /** FHSS channel retry counter. */ + uint32_t fhss_channel_retry; } fhss_statistics_t; /** diff --git a/nanostack/net_fhss.h b/nanostack/net_fhss.h index b201420e14..6d6003c986 100644 --- a/nanostack/net_fhss.h +++ b/nanostack/net_fhss.h @@ -76,6 +76,14 @@ extern int ns_fhss_ws_configuration_set(const fhss_api_t *fhss_api, const fhss_w */ extern int ns_fhss_delete(fhss_api_t *fhss_api); +/** + * @brief Starts collecting FHSS statistics. + * @param fhss_api FHSS instance. + * @param fhss_statistics Pointer to stored statistics. + * @return 0 on success, -1 on fail. + */ +extern int ns_fhss_statistics_start(const fhss_api_t *fhss_api, fhss_statistics_t *fhss_statistics); + #ifdef __cplusplus } diff --git a/nanostack/ns_conf.h b/nanostack/ns_conf.h new file mode 100644 index 0000000000..c8e6d50602 --- /dev/null +++ b/nanostack/ns_conf.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2019, Arm Limited and affiliates. + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _NS_CONF_H_ +#define _NS_CONF_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \file ns_conf.h + * \brief Nanostack configuration API. + */ + +/** + * \brief Set threshold for memory garbage collection. + * + * Nanostack heap usage is monitored in regular intervals. If too much memory has been used then garbage collection (GC) + * is triggered. GC has two adjustable thresholds: HIGH and CRITICAL. HIGH threshold is lower one and once exceeded + * a GC will try to release memory that is used for caching. When CRITTICAL threshold is exceeded them GC will try to release + * memory more aggressiveliy. + * + * Nanostack memory monitoring can only work if memory statistics are enabled in nsdynmemLIB. + + * + * \param percentage_high Percentage of total heap when garbage collection is first time triggered + * \param percentage_critical Percentage of total heap when critical garbage collection is triggered + * + * \return 0 in success, negative value in case of error. + * + */ +int ns_conf_gc_threshold_set(uint8_t percentage_high, uint8_t percentage_critical); + +/** + * \brief Limit amount of incoming packets if system does not have enough free memory. + * Memory statistics must been initialized in nsdynmemLIB to get this feature working. + * + * \param free_heap_percentage Percentage of free heap that must be available when packet arrives to MAC layer. + * \return 0 in case of success, <0 otherwise. + */ +int ns_conf_packet_ingress_rate_limit_by_mem(uint8_t free_heap_percentage); + +#ifdef __cplusplus +} +#endif + +#endif /* _NS_CONF_H_ */ diff --git a/nanostack/ns_file_system.h b/nanostack/ns_file_system.h index 8fac78ccef..00ce97eb32 100644 --- a/nanostack/ns_file_system.h +++ b/nanostack/ns_file_system.h @@ -18,6 +18,10 @@ #ifndef _NS_FILE_SYSTEM_H_ #define _NS_FILE_SYSTEM_H_ +#ifdef __cplusplus +extern "C" { +#endif + /** * \file ns_file_system.h * \brief Nanostack file system API. @@ -35,9 +39,7 @@ * \return 0 in success, negative value in case of error. * */ -#ifdef __cplusplus -extern "C" { -#endif + int ns_file_system_set_root_path(const char *root_path); /** @@ -47,6 +49,7 @@ int ns_file_system_set_root_path(const char *root_path); * */ char *ns_file_system_get_root_path(void); + #ifdef __cplusplus } #endif diff --git a/nanostack/sw_mac.h b/nanostack/sw_mac.h index 3ebbd15277..000f53c73b 100644 --- a/nanostack/sw_mac.h +++ b/nanostack/sw_mac.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2018, Arm Limited and affiliates. + * Copyright (c) 2016-2019, Arm Limited and affiliates. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -81,6 +81,13 @@ extern struct fhss_api *ns_sw_mac_get_fhss_api(struct mac_api_s *mac_api); */ extern int ns_sw_mac_statistics_start(struct mac_api_s *mac_api, struct mac_statistics_s *mac_statistics); +/** + * @brief Read current timestamp. + * @param mac_api MAC instance. + * @return Current timestamp in us + */ +extern uint32_t ns_sw_mac_read_current_timestamp(struct mac_api_s *mac_api); + #ifdef __cplusplus } #endif diff --git a/nanostack/ws_management_api.h b/nanostack/ws_management_api.h index a52809d0a4..604de467f0 100644 --- a/nanostack/ws_management_api.h +++ b/nanostack/ws_management_api.h @@ -77,6 +77,7 @@ extern "C" { #define NETWORK_SIZE_AUTOMATIC 0x00 #define NETWORK_SIZE_SMALL 0x01 +#define NETWORK_SIZE_MEDIUM 0x08 #define NETWORK_SIZE_LARGE 0x10 @@ -85,6 +86,16 @@ extern "C" { */ #define WS_MANAGEMENT_API_VER_2 +/** + * \brief Struct ws_statistics defines the Wi-SUN statistics storage structure. + */ +typedef struct ws_statistics { + /** Asynch TX counter */ + uint32_t asynch_tx_count; + /** Asynch RX counter */ + uint32_t asynch_rx_count; +} ws_statistics_t; + /** * Initialize Wi-SUN stack. * @@ -255,6 +266,30 @@ int ws_management_fhss_broadcast_channel_function_configure( uint8_t dwell_interval, uint32_t broadcast_interval); +/** + * Start collecting Wi-SUN statistics. + * + * \param interface_id Network interface ID. + * \param stats_ptr Pointer to stored statistics. + * + * \return 0 Success. + * \return <0 Failure. + */ +int ws_statistics_start( + int8_t interface_id, + ws_statistics_t *stats_ptr); + +/** + * Stop collecting Wi-SUN statistics. + * + * \param interface_id Network interface ID. + * + * \return 0 Success. + * \return <0 Failure. + */ +int ws_statistics_stop( + int8_t interface_id); + #ifdef __cplusplus } #endif diff --git a/source/6LoWPAN/Bootstraps/Generic/protocol_6lowpan_bootstrap.c b/source/6LoWPAN/Bootstraps/Generic/protocol_6lowpan_bootstrap.c index 5f3f17becc..e6b009e500 100644 --- a/source/6LoWPAN/Bootstraps/Generic/protocol_6lowpan_bootstrap.c +++ b/source/6LoWPAN/Bootstraps/Generic/protocol_6lowpan_bootstrap.c @@ -1605,7 +1605,7 @@ static void lowpan_neighbor_entry_remove_notify(mac_neighbor_table_entry_t *entr protocol_6lowpan_release_short_link_address_from_neighcache(cur_interface, entry_ptr->mac16); protocol_6lowpan_release_long_link_address_from_neighcache(cur_interface, entry_ptr->mac64); } - mac_helper_devicetable_remove(cur_interface->mac_api, entry_ptr->index); + mac_helper_devicetable_remove(cur_interface->mac_api, entry_ptr->index, entry_ptr->mac64); //Removes ETX neighbor etx_neighbor_remove(cur_interface->id, entry_ptr->index); //Remove MLE frame counter info diff --git a/source/6LoWPAN/MAC/mac_helper.c b/source/6LoWPAN/MAC/mac_helper.c index 5bc8ee417f..177113f46e 100644 --- a/source/6LoWPAN/MAC/mac_helper.c +++ b/source/6LoWPAN/MAC/mac_helper.c @@ -866,7 +866,7 @@ int8_t mac_helper_link_frame_counter_set(int8_t interface_id, uint32_t seq_ptr) return 0; } -void mac_helper_devicetable_remove(mac_api_t *mac_api, uint8_t attribute_index) +void mac_helper_devicetable_remove(mac_api_t *mac_api, uint8_t attribute_index, uint8_t *mac64) { if (!mac_api) { return; @@ -880,7 +880,7 @@ void mac_helper_devicetable_remove(mac_api_t *mac_api, uint8_t attribute_index) set_req.attr_index = attribute_index; set_req.value_pointer = (void *)&device_desc; set_req.value_size = sizeof(mlme_device_descriptor_t); - tr_debug("unRegister Device"); + tr_debug("Unregister Device %u, mac64: %s", attribute_index, trace_array(mac64, 8)); mac_api->mlme_req(mac_api, MLME_SET, &set_req); } @@ -910,7 +910,7 @@ void mac_helper_devicetable_set(const mlme_device_descriptor_t *device_desc, pro set_req.attr_index = attribute_index; set_req.value_pointer = (void *)device_desc; set_req.value_size = sizeof(mlme_device_descriptor_t); - tr_debug("Register Device"); + tr_debug("Register Device %u, mac16 %x mac64: %s, %"PRIu32, attribute_index, device_desc->ShortAddress, trace_array(device_desc->ExtAddress, 8), device_desc->FrameCounter); cur->mac_api->mlme_req(cur->mac_api, MLME_SET, &set_req); } diff --git a/source/6LoWPAN/MAC/mac_helper.h b/source/6LoWPAN/MAC/mac_helper.h index 8435328a53..025df0313b 100644 --- a/source/6LoWPAN/MAC/mac_helper.h +++ b/source/6LoWPAN/MAC/mac_helper.h @@ -115,7 +115,7 @@ int8_t mac_helper_link_frame_counter_read(int8_t interface_id, uint32_t *seq_ptr int8_t mac_helper_link_frame_counter_set(int8_t interface_id, uint32_t seq_ptr); -void mac_helper_devicetable_remove(struct mac_api_s *mac_api, uint8_t attribute_index); +void mac_helper_devicetable_remove(struct mac_api_s *mac_api, uint8_t attribute_index, uint8_t *mac64); void mac_helper_device_description_write(struct protocol_interface_info_entry *cur, mlme_device_descriptor_t *device_desc, uint8_t *mac64, uint16_t mac16, uint32_t frame_counter, bool exempt); diff --git a/source/6LoWPAN/ND/nd_router_object.c b/source/6LoWPAN/ND/nd_router_object.c index 9c8f50351f..c397bfa66c 100644 --- a/source/6LoWPAN/ND/nd_router_object.c +++ b/source/6LoWPAN/ND/nd_router_object.c @@ -855,8 +855,14 @@ static void nd_update_registration(protocol_interface_info_entry_t *cur_interfac */ mac_neighbor_table_entry_t *entry = mac_neighbor_table_address_discover(mac_neighbor_info(cur_interface), ipv6_neighbour_eui64(&cur_interface->ipv6_neighbour_cache, neigh), ADDR_802_15_4_LONG); - if (entry && !entry->ffd_device) { - rpl_control_publish_host_address(protocol_6lowpan_rpl_domain, neigh->ip_address, neigh->lifetime); + if (entry) { + if (ws_info(cur_interface)) { + ws_common_etx_validate(cur_interface, entry); + } + + if (!entry->ffd_device) { + rpl_control_publish_host_address(protocol_6lowpan_rpl_domain, neigh->ip_address, neigh->lifetime); + } } protocol_6lowpan_neighbor_address_state_synch(cur_interface, aro->eui64, neigh->ip_address + 8); diff --git a/source/6LoWPAN/Thread/thread_common.c b/source/6LoWPAN/Thread/thread_common.c index 953f039091..36c3171b1b 100644 --- a/source/6LoWPAN/Thread/thread_common.c +++ b/source/6LoWPAN/Thread/thread_common.c @@ -2015,7 +2015,7 @@ void thread_reset_neighbour_info(protocol_interface_info_entry_t *cur, mac_neigh thread_routing_remove_link(cur, neighbour->mac16); thread_router_bootstrap_reset_child_info(cur, neighbour); protocol_6lowpan_release_long_link_address_from_neighcache(cur, neighbour->mac64); - mac_helper_devicetable_remove(cur->mac_api, neighbour->index); + mac_helper_devicetable_remove(cur->mac_api, neighbour->index, neighbour->mac64); thread_neighbor_class_entry_remove(&cur->thread_info->neighbor_class, neighbour->index); } diff --git a/source/6LoWPAN/ws/ws_bbr_api.c b/source/6LoWPAN/ws/ws_bbr_api.c index 2cabf92da2..12328fc57b 100644 --- a/source/6LoWPAN/ws/ws_bbr_api.c +++ b/source/6LoWPAN/ws/ws_bbr_api.c @@ -40,25 +40,31 @@ #include "ws_bbr_api.h" -#define TRACE_GROUP "wsbs" +#define TRACE_GROUP "BBRw" #define RPL_INSTANCE_ID 1 #ifdef HAVE_WS_BORDER_ROUTER +#define WS_ULA_LIFETIME 24*3600 +#define WS_ROUTE_LIFETIME WS_ULA_LIFETIME +#define WS_DHCP_ADDRESS_LIFETIME 2*3600 +#define BBR_CHECK_INTERVAL 60 +#define BBR_BACKUP_ULA_DELAY 300 /* when creating BBR make ULA dodag ID always and when network becomes available add prefix to DHCP * * */ static int8_t backbone_interface_id = -1; // BBR backbone information -static uint16_t configuration = BBR_ULA_C | BBR_GUA_C | BBR_GUA_ROUTE; +static uint16_t configuration = 0; static uint8_t static_dodag_prefix[8] = {0xfd, 0x00, 0x61, 0x72, 0x6d}; -static uint8_t static_ula_address[16] = {0}; -static uint8_t static_dodag_id[16] = {0}; -static uint8_t global_dodag_id[16] = {0}; -static uint32_t bbr_delay_timer = 20; // initial delay. +static uint8_t current_dodag_id[16] = {0}; +static uint8_t current_local_prefix[8] = {0}; +static uint8_t current_global_prefix[8] = {0}; +static uint32_t bbr_delay_timer = BBR_CHECK_INTERVAL; // initial delay. +static uint32_t global_prefix_unavailable_timer = 0; // initial delay. static rpl_dodag_conf_t rpl_conf = { // Lifetime values @@ -68,7 +74,7 @@ static rpl_dodag_conf_t rpl_conf = { .authentication = 0, .path_control_size = 7, .dag_max_rank_increase = 2048, - .min_hop_rank_increase = 256, + .min_hop_rank_increase = 196, // DIO configuration .dio_interval_min = WS_RPL_DIO_IMIN, .dio_interval_doublings = WS_RPL_DIO_DOUBLING, @@ -115,31 +121,20 @@ static void ws_bbr_rpl_root_start(uint8_t *dodag_id) } // RPL memory limits set larger for Border router rpl_control_set_memory_limits(64 * 1024, 0); - // Save configured static id to check for changes later - memcpy(static_dodag_id, dodag_id, 16); } static void ws_bbr_rpl_root_stop(void) { tr_info("RPL root stop"); - rpl_control_delete_dodag_root(protocol_6lowpan_rpl_domain, protocol_6lowpan_rpl_root_dodag); - protocol_6lowpan_rpl_root_dodag = NULL; - memset(static_ula_address, 0, 16); - memset(static_dodag_id, 0, 16); - memset(global_dodag_id, 0, 16); + if (protocol_6lowpan_rpl_root_dodag) { + rpl_control_delete_dodag_root(protocol_6lowpan_rpl_domain, protocol_6lowpan_rpl_root_dodag); + protocol_6lowpan_rpl_root_dodag = NULL; + } + memset(current_local_prefix, 0, 8); + memset(current_global_prefix, 0, 8); + memset(current_dodag_id, 0, 16); } -static void ws_bbr_ula_prefix_enable(uint8_t *dodag_id) -{ - tr_info("RPL ula prefix start"); - - uint8_t t_flags = PIO_A; - - rpl_control_update_dodag_prefix(protocol_6lowpan_rpl_root_dodag, dodag_id, 64, t_flags, 7200, 7200, false); - rpl_control_update_dodag_route(protocol_6lowpan_rpl_root_dodag, dodag_id, 64, 0x18, 7200, false); -} - - static int ws_border_router_proxy_validate(int8_t interface_id, uint8_t *address) { @@ -163,29 +158,24 @@ int ws_border_router_proxy_state_update(int8_t caller_interface_id, int8_t handl return -1; } - if (status) { - tr_debug("Border router Backhaul link ready"); - } else { - tr_debug("Border router Backhaul link down"); - } + tr_debug("Border router Backhaul link %s", status ? "ready" : "down"); return 0; } -static int ws_bbr_static_ula_create(protocol_interface_info_entry_t *cur) +static int ws_bbr_static_dodagid_create(protocol_interface_info_entry_t *cur) { - if (memcmp(static_ula_address, ADDR_UNSPECIFIED, 16) != 0) { + if (memcmp(current_dodag_id, ADDR_UNSPECIFIED, 16) != 0) { // address generated return 0; } - tr_info("BBR generate ula prefix"); - // This address is only used if no other address available. if_address_entry_t *add_entry = icmpv6_slaac_address_add(cur, static_dodag_prefix, 64, 0xffffffff, 0xffffffff, true, SLAAC_IID_FIXED); if (!add_entry) { + tr_err("dodagid create failed"); return -1; } - memcpy(static_ula_address, add_entry->address, 16); - tr_info("BBR generate ula prefix addr %s", trace_ipv6(static_ula_address)); + memcpy(current_dodag_id, add_entry->address, 16); + tr_info("BBR generate DODAGID %s", trace_ipv6(current_dodag_id)); addr_policy_table_add_entry(static_dodag_prefix, 64, 2, WS_NON_PREFFRED_LABEL); return 0; @@ -195,61 +185,53 @@ static int ws_bbr_static_ula_create(protocol_interface_info_entry_t *cur) * 0 static non rooted self generated own address * 1 static address with backbone connectivity */ -static int ws_bbr_static_dodag_get(protocol_interface_info_entry_t *cur, uint8_t *dodag_id_ptr) +static void ws_bbr_bb_static_prefix_get(uint8_t *dodag_id_ptr) { + /* Get static ULA prefix if we have configuration in backbone and there is address we use that. + * + * If there is no address we can use our own generated ULA as a backup ULA + */ + protocol_interface_info_entry_t *bb_interface = protocol_stack_interface_info_get_by_id(backbone_interface_id); if (bb_interface && bb_interface->ipv6_configure->ipv6_stack_mode == NET_IPV6_BOOTSTRAP_STATIC) { - // static configuration for ethernet available - ns_list_foreach(if_address_entry_t, add_entry, &cur->ip_addresses) { - if (memcmp(add_entry->address, bb_interface->ipv6_configure->static_prefix64, 8) == 0) { - //tr_info("BBR static config available"); - if (dodag_id_ptr) { - memcpy(dodag_id_ptr, add_entry->address, 16); - } - return 1; - } + if (protocol_address_prefix_cmp(bb_interface, bb_interface->ipv6_configure->static_prefix64, 64)) { + memcpy(dodag_id_ptr, bb_interface->ipv6_configure->static_prefix64, 8); } } - ws_bbr_static_ula_create(cur); - - // only own generated prefix available - if (dodag_id_ptr) { - memcpy(dodag_id_ptr, static_ula_address, 16); - } - - return 0; + return; } -static int ws_bbr_dodag_get(protocol_interface_info_entry_t *cur, uint8_t *static_dodag_id_ptr, uint8_t *dodag_id_ptr) +static void ws_bbr_dodag_get(uint8_t *local_prefix_ptr, uint8_t *global_prefix_ptr) { uint8_t global_address[16]; - if (static_dodag_id_ptr) { - memset(static_dodag_id_ptr, 0, 16); - } + memset(global_prefix_ptr, 0, 8); - if (dodag_id_ptr) { - memset(dodag_id_ptr, 0, 16); - } - - if (ws_bbr_static_dodag_get(cur, static_dodag_id_ptr) < 0) { - // no static configuration available - return -1; - } + // By default static dodagID prefix is used as local prefix + memcpy(local_prefix_ptr, current_dodag_id, 8); + ws_bbr_bb_static_prefix_get(local_prefix_ptr); if (arm_net_address_get(backbone_interface_id, ADDR_IPV6_GP, global_address) != 0) { // No global prefix available - return 0; + return; } - if (memcmp(global_address, dodag_id_ptr, 8) == 0) { - // static address is same - return 0; + protocol_interface_info_entry_t *bb_interface = protocol_stack_interface_info_get_by_id(backbone_interface_id); + if_address_entry_t *addr_entry = addr_get_entry(bb_interface, global_address); + + if (!addr_entry || addr_entry->preferred_lifetime == 0) { + return; } - memcpy(dodag_id_ptr, global_address, 16); - return 0; + //tr_debug("BBR address %s lifetime %d pref %d", trace_ipv6(addr_entry->address), addr_entry->valid_lifetime, addr_entry->preferred_lifetime); + + if (memcmp(global_address, local_prefix_ptr, 8) == 0) { + // static prefix is same + return; + } + memcpy(global_prefix_ptr, global_address, 8); + return; } static void wisun_bbr_na_send(int8_t interface_id, const uint8_t target[static 16]) { @@ -284,7 +266,7 @@ static void ws_bbr_dhcp_server_start(protocol_interface_info_entry_t *cur, uint8 memcpy(&ll[8], cur->mac, 8); ll[8] ^= 2; - tr_debug("DHCP server activate %s", trace_ipv6(global_id)); + tr_debug("DHCP server activate %s", trace_ipv6_prefix(global_id, 64)); if (DHCPv6_server_service_init(cur->id, global_id, cur->mac, DHCPV6_DUID_HARDWARE_IEEE_802_NETWORKS_TYPE) != 0) { tr_error("DHCPv6 Server create fail"); @@ -293,7 +275,7 @@ static void ws_bbr_dhcp_server_start(protocol_interface_info_entry_t *cur, uint8 DHCPv6_server_service_callback_set(cur->id, global_id, NULL, wisun_dhcp_address_add_cb); DHCPv6_server_service_set_address_autonous_flag(cur->id, global_id, true); - DHCPv6_server_service_set_address_validlifetime(cur->id, global_id, 7200); + DHCPv6_server_service_set_address_validlifetime(cur->id, global_id, WS_DHCP_ADDRESS_LIFETIME); ws_dhcp_client_address_request(cur, global_id, ll); } @@ -307,86 +289,136 @@ static void ws_bbr_dhcp_server_stop(protocol_interface_info_entry_t *cur, uint8_ static void ws_bbr_rpl_status_check(protocol_interface_info_entry_t *cur) { - uint8_t static_id[16] = {0}; - uint8_t global_id[16] = {0}; + uint8_t local_prefix[8] = {0}; + uint8_t global_prefix[8] = {0}; //tr_info("BBR status check"); - ws_bbr_dodag_get(cur, static_id, global_id); - - // Check if we need to wait for Global ID - if (configuration & BBR_GUA_WAIT) { - if (memcmp(global_dodag_id, ADDR_UNSPECIFIED, 16) == 0 && - memcmp(global_id, ADDR_UNSPECIFIED, 16) == 0) { - // We need to wait for Global connectivity to start anything - return; + /* + * Start RPL Root + */ + if (!protocol_6lowpan_rpl_root_dodag) { + // Generate DODAGID + if (ws_bbr_static_dodagid_create(cur) == 0) { + ws_bbr_rpl_root_start(current_dodag_id); } } - if (memcmp(static_dodag_id, static_id, 16) != 0) { - // Static id updated or first setup - ws_bbr_rpl_root_start(static_id); - if (configuration & BBR_ULA_C) { - // Start static ULA prefix and routing always - ws_bbr_ula_prefix_enable(static_id); + if (!protocol_6lowpan_rpl_root_dodag) { + // Failed to start + tr_info("BBR failed to start"); + return; + } + + /* + * Check that DODAGID is still valid + */ + if (protocol_interface_address_compare(current_dodag_id) != 0) { + //DODAGID is lost need to restart + tr_err("DODAGID lost restart RPL"); + memset(current_dodag_id, 0, 16); + ws_bbr_rpl_root_stop(); + return; + } + + ws_bbr_dodag_get(local_prefix, global_prefix); + tr_debug("BBR global %s, local %s", trace_ipv6_prefix(global_prefix, 64), trace_ipv6_prefix(local_prefix, 64)); + + /* + * Add default route to RPL + */ + rpl_control_update_dodag_route(protocol_6lowpan_rpl_root_dodag, NULL, 0, 0, WS_ROUTE_LIFETIME, false); + + /* + * Create static ULA configuration or modify if needed + */ + if ((configuration & BBR_ULA_C) && + memcmp(current_local_prefix, local_prefix, 8) != 0) { + // Generate Static ULA + // Start static ULA prefix and routing always + if (memcmp(current_local_prefix, ADDR_UNSPECIFIED, 8) != 0) { + // Remove Old ULA prefix + rpl_control_update_dodag_prefix(protocol_6lowpan_rpl_root_dodag, current_local_prefix, 64, PIO_A, 0, 0, true); + } + if (memcmp(local_prefix, ADDR_UNSPECIFIED, 8) != 0) { + tr_info("RPL Local prefix activate %s", trace_ipv6_prefix(local_prefix, 64)); + rpl_control_update_dodag_prefix(protocol_6lowpan_rpl_root_dodag, local_prefix, 64, PIO_A, WS_ULA_LIFETIME, WS_ULA_LIFETIME, false); + memcpy(current_local_prefix, local_prefix, 8); } } - if (memcmp(global_dodag_id, global_id, 16) != 0) { + /* + * Check if backup ULA prefix is needed + */ + if (memcmp(global_prefix, ADDR_UNSPECIFIED, 8) == 0) { + //Global prefix not available count if backup ULA should be created + global_prefix_unavailable_timer += BBR_CHECK_INTERVAL; + tr_debug("Check for backup prefix %"PRIu32"", global_prefix_unavailable_timer); + if (global_prefix_unavailable_timer >= BBR_BACKUP_ULA_DELAY) { + if (memcmp(current_global_prefix, ADDR_UNSPECIFIED, 8) == 0) { + tr_info("start using backup prefix %s", trace_ipv6_prefix(local_prefix, 64)); + } + memcpy(global_prefix, local_prefix, 8); + } + } else { + //Global connection OK + global_prefix_unavailable_timer = 0; + } + + /* + * Check for Global prefix + */ + if (memcmp(current_global_prefix, global_prefix, 8) != 0) { // Global prefix changed - if (memcmp(global_dodag_id, ADDR_UNSPECIFIED, 16) != 0) { + if (memcmp(current_global_prefix, ADDR_UNSPECIFIED, 8) != 0) { // TODO remove old global prefix - tr_info("RPL GUA deactivate %s", trace_ipv6(global_dodag_id)); + tr_info("RPL global prefix deactivate %s", trace_ipv6_prefix(current_global_prefix, 64)); // Old backbone information is deleted after 120 seconds - rpl_control_update_dodag_route(protocol_6lowpan_rpl_root_dodag, NULL, 0, 0, 0, true); - rpl_control_update_dodag_prefix(protocol_6lowpan_rpl_root_dodag, global_dodag_id, 64, 0, 0, 0, true); - rpl_control_update_dodag_route(protocol_6lowpan_rpl_root_dodag, global_dodag_id, 64, 0, 0, true); - ipv6_route_add_with_info(global_dodag_id, 64, backbone_interface_id, NULL, ROUTE_THREAD_BBR, NULL, 0, 120, 0); + rpl_control_update_dodag_prefix(protocol_6lowpan_rpl_root_dodag, current_global_prefix, 64, 0, 0, 0, true); + if (configuration & BBR_GUA_ROUTE) { + rpl_control_update_dodag_route(protocol_6lowpan_rpl_root_dodag, current_global_prefix, 64, 0, 0, true); + } + ipv6_route_add_with_info(current_global_prefix, 64, backbone_interface_id, NULL, ROUTE_THREAD_BBR, NULL, 0, 120, 0); - ws_bbr_dhcp_server_stop(cur, global_dodag_id); + ws_bbr_dhcp_server_stop(cur, current_global_prefix); } // TODO add global prefix - if (memcmp(global_id, ADDR_UNSPECIFIED, 16) != 0) { - //DHCPv6 Server flags set 0 by default - uint8_t t_flags = 0; + if (memcmp(global_prefix, ADDR_UNSPECIFIED, 8) != 0) { + tr_info("RPL global prefix activate %s", trace_ipv6_prefix(global_prefix, 64)); // Add default route to RPL - rpl_control_update_dodag_route(protocol_6lowpan_rpl_root_dodag, NULL, 0, 0, 7200, false); // Enable default routing to backbone - ipv6_route_add_with_info(global_id, 64, backbone_interface_id, NULL, ROUTE_THREAD_BBR, NULL, 0, 0xffffffff, 0); - - if (configuration & BBR_GUA_SLAAC) { - // GUA prefix is using SLAAC so no DHCP started and set correct flags for prefix - t_flags = PIO_A; - icmpv6_slaac_address_add(cur, global_id, 64, 0xffffffff, 0xffffffff, true, SLAAC_IID_FIXED); - } else { - ws_bbr_dhcp_server_start(cur, global_id); + if (ipv6_route_add_with_info(global_prefix, 64, backbone_interface_id, NULL, ROUTE_THREAD_BBR, NULL, 0, 0xffffffff, 0) == NULL) { + tr_err("global route add failed"); + return; } + ws_bbr_dhcp_server_start(cur, global_prefix); + rpl_control_update_dodag_prefix(protocol_6lowpan_rpl_root_dodag, global_prefix, 64, 0, 0, 0, false); + // no check for failure should have - if (configuration & BBR_GUA_C) { - // Add also global prefix and route to RPL - uint32_t valid_lifetime; - if (t_flags & PIO_A) { - valid_lifetime = 7200; - } else { - valid_lifetime = 0; - } - - rpl_control_update_dodag_prefix(protocol_6lowpan_rpl_root_dodag, global_id, 64, t_flags, valid_lifetime, valid_lifetime, false); - - } if (configuration & BBR_GUA_ROUTE) { // Add also global prefix and route to RPL - rpl_control_update_dodag_route(protocol_6lowpan_rpl_root_dodag, global_id, 64, 0, 7200, false); + rpl_control_update_dodag_route(protocol_6lowpan_rpl_root_dodag, global_prefix, 64, 0, WS_ROUTE_LIFETIME, false); } } - memcpy(global_dodag_id, global_id, 16); + memcpy(current_global_prefix, global_prefix, 8); rpl_control_increment_dodag_version(protocol_6lowpan_rpl_root_dodag); nd_proxy_downstream_interface_register(cur->id, ws_border_router_proxy_validate, ws_border_router_proxy_state_update); - } + } else if (memcmp(current_global_prefix, ADDR_UNSPECIFIED, 8) != 0) { + /* + * This is a keep alive validation RPL is updated to hold the real info. + * There is no status checks on prefix adds so this makes sure they are not lost + * DHCP validation should be done also + */ + rpl_control_update_dodag_prefix(protocol_6lowpan_rpl_root_dodag, current_global_prefix, 64, 0, 0, 0, false); + if (configuration & BBR_GUA_ROUTE) { + // Add also global prefix and route to RPL + rpl_control_update_dodag_route(protocol_6lowpan_rpl_root_dodag, current_global_prefix, 64, 0, WS_ROUTE_LIFETIME, false); + } + } } void ws_bbr_seconds_timer(protocol_interface_info_entry_t *cur, uint32_t seconds) @@ -408,7 +440,7 @@ void ws_bbr_seconds_timer(protocol_interface_info_entry_t *cur, uint32_t seconds if (bbr_delay_timer > seconds) { bbr_delay_timer -= seconds; } else { - bbr_delay_timer = 20; // 20 second interval between status checks + bbr_delay_timer = BBR_CHECK_INTERVAL; // 20 second interval between status checks // prequisists // Wi-SUN network configuration started without RPL @@ -425,16 +457,6 @@ void ws_bbr_seconds_timer(protocol_interface_info_entry_t *cur, uint32_t seconds // 2. if GUA prefix becomes available in backend add new prefix to DODAG // 3. if GUA prefix is removed remove the prefix. - if (protocol_6lowpan_rpl_root_dodag) { - // Border router is active - if (0 != protocol_interface_address_compare(static_dodag_id)) { - // Dodag has become invalid need to delete - tr_info("RPL static dodag not valid anymore %s", trace_ipv6(static_dodag_id)); - ws_bbr_rpl_root_stop(); - } else { - - } - } ws_bbr_rpl_status_check(cur); } @@ -445,7 +467,7 @@ void ws_bbr_seconds_timer(protocol_interface_info_entry_t *cur, uint32_t seconds } else { // Border router has timed out tr_debug("Border router version number update"); - cur->ws_info->pan_version_timer = PAN_VERSION_LIFETIME; + cur->ws_info->pan_version_timer = ws_common_version_lifetime_get(cur->ws_info->network_size_config); cur->ws_info->pan_information.pan_version++; // Inconsistent for border router to make information distribute faster ws_bootstrap_configuration_trickle_reset(cur); @@ -455,8 +477,8 @@ void ws_bbr_seconds_timer(protocol_interface_info_entry_t *cur, uint32_t seconds } // We update the RPL version in same time to allow nodes to reselect parent // As configuration is made so that devices cant move downward in dodag this allows it - // TODO think the correct rate for this - if (cur->ws_info->pan_information.pan_version && cur->ws_info->pan_information.pan_version % RPL_VERSION_LIFETIME / PAN_VERSION_LIFETIME == 0) { + // Version number update is only done if DoDAG MAX Rank Increase parameter is 0 + if (rpl_conf.dag_max_rank_increase == 0 && cur->ws_info->pan_information.pan_version && cur->ws_info->pan_information.pan_version % RPL_VERSION_LIFETIME / cur->ws_info->pan_version_timer == 0) { // Third the rate of configuration version change at default 5 hours rpl_control_increment_dodag_version(protocol_6lowpan_rpl_root_dodag); } @@ -476,13 +498,12 @@ uint16_t ws_bbr_pan_size(protocol_interface_info_entry_t *cur) } // const uint8_t *prefix_ptr; - if ((configuration & (BBR_ULA_C | BBR_GUA_C)) == BBR_GUA_C) { - //Use just GUA Prefix - prefix_ptr = global_dodag_id; - + if (memcmp(current_global_prefix, ADDR_UNSPECIFIED, 8) != 0) { + //Use GUA Prefix + prefix_ptr = current_global_prefix; } else { //Use ULA for indentifier - prefix_ptr = static_dodag_id; + prefix_ptr = current_local_prefix; } rpl_control_get_instance_dao_target_count(cur->rpl_domain, RPL_INSTANCE_ID, NULL, prefix_ptr, &result); @@ -598,3 +619,4 @@ int ws_bbr_node_access_revoke_start(int8_t interface_id) return -1; #endif } + diff --git a/source/6LoWPAN/ws/ws_bootstrap.c b/source/6LoWPAN/ws/ws_bootstrap.c index 2193e6eae8..6ab4c793bc 100644 --- a/source/6LoWPAN/ws/ws_bootstrap.c +++ b/source/6LoWPAN/ws/ws_bootstrap.c @@ -53,6 +53,7 @@ #include "6LoWPAN/ws/ws_llc.h" #include "6LoWPAN/ws/ws_neighbor_class.h" #include "6LoWPAN/ws/ws_ie_lib.h" +#include "6LoWPAN/ws/ws_stats.h" #include "6LoWPAN/lowpan_adaptation_interface.h" #include "Service_Libs/etx/etx.h" #include "Service_Libs/mac_neighbor_table/mac_neighbor_table.h" @@ -80,7 +81,7 @@ static void ws_bootstrap_state_change(protocol_interface_info_entry_t *cur, icmp static bool ws_bootstrap_state_discovery(struct protocol_interface_info_entry *cur); static int8_t ws_bootsrap_event_trig(ws_bootsrap_event_type_e event_type, int8_t interface_id, arm_library_event_priority_e priority, void *event_data); -static bool ws_bootstrap_neighbor_info_request(struct protocol_interface_info_entry *interface, const uint8_t *mac_64, llc_neighbour_req_t *neighbor_buffer, bool request_new); +static bool ws_bootstrap_neighbor_info_request(struct protocol_interface_info_entry *interface, const uint8_t *mac_64, llc_neighbour_req_t *neighbor_buffer, bool request_new, bool multicast); static uint16_t ws_bootstrap_routing_cost_calculate(protocol_interface_info_entry_t *cur); static uint16_t ws_bootstrap_rank_get(protocol_interface_info_entry_t *cur); static uint16_t ws_bootstrap_min_rank_inc_get(protocol_interface_info_entry_t *cur); @@ -90,10 +91,12 @@ static void ws_bootstrap_nw_key_set(protocol_interface_info_entry_t *cur, uint8_ static void ws_bootstrap_nw_key_clear(protocol_interface_info_entry_t *cur, uint8_t slot); static void ws_bootstrap_nw_key_index_set(protocol_interface_info_entry_t *cur, uint8_t index); static void ws_bootstrap_nw_frame_counter_set(protocol_interface_info_entry_t *cur, uint32_t counter); +static void ws_bootstrap_nw_frame_counter_read(protocol_interface_info_entry_t *cur, uint32_t *counter); static void ws_bootstrap_authentication_completed(protocol_interface_info_entry_t *cur, bool success); static void ws_bootstrap_pan_version_increment(protocol_interface_info_entry_t *cur); static ws_nud_table_entry_t *ws_nud_entry_discover(protocol_interface_info_entry_t *cur, void *neighbor); static void ws_nud_entry_remove(protocol_interface_info_entry_t *cur, mac_neighbor_table_entry_t *entry_ptr); +static bool ws_neighbor_entry_nud_notify(mac_neighbor_table_entry_t *entry_ptr, void *user_data); typedef enum { WS_PARENT_SOFT_SYNCH = 0, /**< let FHSS make decision if synchronization is needed*/ @@ -101,6 +104,13 @@ typedef enum { WS_EAPOL_PARENT_SYNCH, /**< Broadcast synch with EAPOL parent*/ } ws_parent_synch_e; +static void ws_bootsrap_create_ll_address(uint8_t *ll_address, const uint8_t *mac64) +{ + memcpy(ll_address, ADDR_LINK_LOCAL_PREFIX, 8); + memcpy(ll_address + 8, mac64, 8); + ll_address[8] ^= 2; +} + mac_neighbor_table_entry_t *ws_bootstrap_mac_neighbor_add(struct protocol_interface_info_entry *interface, const uint8_t *src64) { @@ -123,11 +133,11 @@ mac_neighbor_table_entry_t *ws_bootstrap_mac_neighbor_add(struct protocol_interf return neighbor; } -static void ws_bootstrap_neighbor_delete(struct protocol_interface_info_entry *interface, uint8_t attribute_index) +static void ws_bootstrap_neighbor_delete(struct protocol_interface_info_entry *interface, mac_neighbor_table_entry_t *entry_ptr) { - mac_helper_devicetable_remove(interface->mac_api, attribute_index); - etx_neighbor_remove(interface->id, attribute_index); - ws_neighbor_class_entry_remove(&interface->ws_info->neighbor_storage, attribute_index); + mac_helper_devicetable_remove(interface->mac_api, entry_ptr->index, entry_ptr->mac64); + etx_neighbor_remove(interface->id, entry_ptr->index); + ws_neighbor_class_entry_remove(&interface->ws_info->neighbor_storage, entry_ptr->index); } static void ws_bootstrap_neighbor_list_clean(struct protocol_interface_info_entry *interface) @@ -144,8 +154,9 @@ static void ws_bootstrap_address_notification_cb(struct protocol_interface_info_ } if (reason == ADDR_CALLBACK_DAD_COMPLETE) { //Trig Address Registartion only when Bootstrap is ready - if (interface->nwk_bootstrap_state == ER_BOOTSRAP_DONE || addr->source == ADDR_SOURCE_DHCP) { - ws_bootsrap_event_trig(WS_ADDRESS_ADDED, interface->bootStrapId, ARM_LIB_LOW_PRIORITY_EVENT, (void *)addr); + if (interface->nwk_bootstrap_state == ER_BOOTSRAP_DONE && addr->source != ADDR_SOURCE_DHCP) { + tr_debug("Address registration %s", trace_ipv6(addr->address)); + rpl_control_register_address(interface, addr->address); } if (addr_ipv6_scope(addr->address, interface) > IPV6_SCOPE_LINK_LOCAL) { // at least ula address available inside mesh. @@ -155,6 +166,12 @@ static void ws_bootstrap_address_notification_cb(struct protocol_interface_info_ } else if (reason == ADDR_CALLBACK_DELETED) { // What to do? // Go through address list and check if there is global address still available + if (addr->source == ADDR_SOURCE_DHCP) { + //Deprecate dhcpv address + uint8_t address[16]; + memcpy(address, addr->address, 16); + dhcp_client_global_address_delete(interface->id, NULL, address); + } //Discover prefix policy addr_policy_remove_by_label(WS_NON_PREFFRED_LABEL); @@ -167,12 +184,10 @@ static void ws_bootstrap_address_notification_cb(struct protocol_interface_info_ } } } else if (reason == ADDR_CALLBACK_TIMER) { - tr_debug("Address Re registration %s", trace_ipv6(addr->address)); - - if (!interface->ws_info->address_registration_event_active) { - interface->ws_info->address_registration_event_active = true; - tr_info("Register ARO"); - ws_bootsrap_event_trig(WS_ADDRESS_ADDED, interface->bootStrapId, ARM_LIB_LOW_PRIORITY_EVENT, NULL); + if (addr->source != ADDR_SOURCE_DHCP) { + tr_debug("Address Re registration %s", trace_ipv6(addr->address)); + //Register + rpl_control_register_address(interface, addr->address); } } } @@ -304,9 +319,7 @@ static bool ws_nud_message_build(protocol_interface_info_entry_t *cur, mac_neigh { //Send NS uint8_t ll_target[16]; - memcpy(ll_target, ADDR_LINK_LOCAL_PREFIX, 8); - memcpy(ll_target + 8, neighbor->mac64, 8); - ll_target[8] ^= 2; + ws_bootsrap_create_ll_address(ll_target, neighbor->mac64); tr_info("NUD generate NS %u", neighbor->index); buffer_t *buffer = icmpv6_build_ns(cur, ll_target, NULL, true, false, NULL); if (buffer) { @@ -321,6 +334,8 @@ void ws_nud_active_timer(protocol_interface_info_entry_t *cur, uint16_t ticks) //Convert TICKS to real milliseconds if (ticks > 0xffff / 100) { ticks = 0xffff; + } else if (ticks == 0) { + ticks = 1; } else { ticks *= 100; } @@ -649,10 +664,7 @@ uint16_t ws_etx_read(protocol_interface_info_entry_t *interface, addrtype_t addr if (!ws_neighbour || !etx_entry || etx_entry->etx_samples < 1 /*|| !ws_neighbour->candidate_parent*/) { // if RSL value is not good enough candidate parent flag is removed and device not accepted as parent - //tr_debug("ws_etx_read not valid parent"); - if (etx_entry && etx_entry->etx_samples) { - tr_debug("ws_etx_read not valid %u RSL IN(%u), %u RSL out(%u)", ws_neighbor_class_rsl_in_get(ws_neighbour), ws_neighbour->rsl_in, ws_neighbor_class_rsl_out_get(ws_neighbour), ws_neighbour->rsl_out); - } + tr_debug("ws_etx_read not valid params"); return 0xffff; } @@ -680,6 +692,21 @@ uint16_t ws_etx_read(protocol_interface_info_entry_t *interface, addrtype_t addr //tr_debug("ws_etx_read etx:%d", etx); return etx; } +bool ws_bootstrap_nd_ns_transmit(protocol_interface_info_entry_t *cur, ipv6_neighbour_t *entry, bool unicast, uint8_t seq) +{ + (void)cur; + (void)seq; + + if (unicast) { + // Unicast NS is OK + return false; + } + // Fail the resolution + tr_warn("Link address lost for %s", trace_ipv6(entry->ip_address)); + ipv6_neighbour_entry_remove(&cur->ipv6_neighbour_cache, entry); + // True means we skip the message sending + return true; +} static int8_t ws_bootstrap_up(protocol_interface_info_entry_t *cur) { @@ -698,8 +725,6 @@ static int8_t ws_bootstrap_up(protocol_interface_info_entry_t *cur) return -3; } - //Enable Power bootup timer setup - cur->ws_info->power_up_setup = true; // Save FHSS api cur->ws_info->fhss_api = ns_sw_mac_get_fhss_api(cur->mac_api); @@ -725,6 +750,9 @@ static int8_t ws_bootstrap_up(protocol_interface_info_entry_t *cur) /* Disable NUD Probes */ cur->ipv6_neighbour_cache.send_nud_probes = false; cur->ipv6_neighbour_cache.probe_avoided_routers = true; + /*Replace NS handler to disable multicast address queries */ + cur->if_ns_transmit = ws_bootstrap_nd_ns_transmit; + dhcp_client_init(cur->id); dhcp_client_configure(cur->id, true, true, true); //RENEW uses SOLICIT, Interface will use 1 instance for address get, IAID address hint is not used. dhcp_client_solicit_timeout_set(cur->id, WS_DHCP_SOLICIT_TIMEOUT, WS_DHCP_SOLICIT_MAX_RT, WS_DHCP_SOLICIT_MAX_RC); @@ -833,17 +861,18 @@ static void ws_bootstrap_pan_advertisement_analyse_active(struct protocol_interf * * A consistent transmission is defined as a PAN Advertisement received by a node with PAN ID and * NETNAME-IE / Network Name matching that of the receiving node, and with a PAN-IE / Routing Cost - * the same or better than (less than or equal to) that of the receiving node. + * the same or worse than (bigger than or equal to) that of the receiving node. * * Inconsistent: - * PAN Advertisement solicit + * + * Received Routing Cost is smaller than stored one * * A PAN Advertisement received by a node with PAN ID and NETNAME-IE / Network name matching - * that of the receiving node, and PAN-IE / Routing Cost worse than (greater than) that of the receiving node. + * that of the receiving node, and PAN-IE / Routing Cost better than (smaller than) that of the receiving node. * */ - if (pan_information->routing_cost <= cur->ws_info->pan_information.routing_cost) { + if (pan_information->routing_cost >= cur->ws_info->pan_information.routing_cost) { trickle_consistent_heard(&cur->ws_info->trickle_pan_advertisement); } else { trickle_inconsistent_heard(&cur->ws_info->trickle_pan_advertisement, &cur->ws_info->trickle_params_pan_discovery); @@ -897,7 +926,7 @@ static void ws_bootstrap_pan_advertisement_analyse(struct protocol_interface_inf // Save route cost for all neighbours llc_neighbour_req_t neighbor_info; neighbor_info.neighbor = NULL; - if (ws_bootstrap_neighbor_info_request(cur, data->SrcAddr, &neighbor_info, false)) { + if (ws_bootstrap_neighbor_info_request(cur, data->SrcAddr, &neighbor_info, false, false)) { neighbor_info.ws_neighbor->routing_cost = pan_information.routing_cost; } @@ -911,13 +940,13 @@ static void ws_bootstrap_pan_advertisement_analyse(struct protocol_interface_inf if (memcmp(cur->ws_info->parent_info.addr, ADDR_UNSPECIFIED, 8) != 0) { // if we dont have higher than threshold signal only signal level decides parent - if (ws_neighbor_class_rssi_from_dbm_calculate(cur->ws_info->parent_info.signal_dbm) < (CAND_PARENT_THRESHOLD + CAND_PARENT_HYSTERISIS) && - ws_neighbor_class_rssi_from_dbm_calculate(data->signal_dbm) > ws_neighbor_class_rssi_from_dbm_calculate(cur->ws_info->parent_info.signal_dbm)) { + if (ws_neighbor_class_rsl_from_dbm_calculate(cur->ws_info->parent_info.signal_dbm) < (DEVICE_MIN_SENS + CAND_PARENT_THRESHOLD + CAND_PARENT_HYSTERISIS) && + ws_neighbor_class_rsl_from_dbm_calculate(data->signal_dbm) > ws_neighbor_class_rsl_from_dbm_calculate(cur->ws_info->parent_info.signal_dbm)) { // automatically select the best quality link from the below threshold goto parent_selected; } // Drop if signal quality is not good enough - if (ws_neighbor_class_rssi_from_dbm_calculate(data->signal_dbm) < (CAND_PARENT_THRESHOLD + CAND_PARENT_HYSTERISIS)) { + if (ws_neighbor_class_rsl_from_dbm_calculate(data->signal_dbm) < (DEVICE_MIN_SENS + CAND_PARENT_THRESHOLD + CAND_PARENT_HYSTERISIS)) { tr_info("EAPOL target dropped Link quality too low"); return; } @@ -936,14 +965,6 @@ static void ws_bootstrap_pan_advertisement_analyse(struct protocol_interface_inf tr_info("EAPOL target dropped Lower link quality %u < %u current", data->signal_dbm, cur->ws_info->parent_info.signal_dbm); return; } - - } else { - // First advertise heard - - if (ws_neighbor_class_rssi_from_dbm_calculate(data->signal_dbm) < (CAND_PARENT_THRESHOLD + CAND_PARENT_HYSTERISIS)) { - // First neighbor is too low we need to wait one extra trickle - cur->bootsrap_state_machine_cnt += cur->ws_info->trickle_params_pan_discovery.Imin + randLIB_get_8bit() % 50; - } } parent_selected: @@ -974,8 +995,10 @@ parent_selected: // Learn latest network information if (cur->bootsrap_mode != ARM_NWK_BOOTSRAP_MODE_6LoWPAN_BORDER_ROUTER && neighbor_info.neighbor) { + uint8_t ll_address[16]; + ws_bootsrap_create_ll_address(ll_address, neighbor_info.neighbor->mac64); - if (neighbor_info.neighbor->link_role == PRIORITY_PARENT_NEIGHBOUR) { + if (rpl_control_is_dodag_parent(cur, ll_address, true)) { cur->ws_info->pan_information.pan_size = pan_information.pan_size; cur->ws_info->pan_information.routing_cost = pan_information.routing_cost; cur->ws_info->pan_information.rpl_routing_method = pan_information.rpl_routing_method; @@ -1055,23 +1078,34 @@ static void ws_bootstrap_pan_config_analyse(struct protocol_interface_info_entry return; } llc_neighbour_req_t neighbor_info; - if (!ws_bootstrap_neighbor_info_request(cur, data->SrcAddr, &neighbor_info, true)) { - return; + bool neighbour_pointer_valid; + + if (cur->ws_info->configuration_learned || cur->bootsrap_mode == ARM_NWK_BOOTSRAP_MODE_6LoWPAN_BORDER_ROUTER) { + //If we are border router or learned configuration we only update already learned neighbours. + neighbour_pointer_valid = ws_bootstrap_neighbor_info_request(cur, data->SrcAddr, &neighbor_info, false, true); + + } else { + neighbour_pointer_valid = ws_bootstrap_neighbor_info_request(cur, data->SrcAddr, &neighbor_info, true, true); + if (!neighbour_pointer_valid) { + return; + } } - etx_lqi_dbm_update(cur->id, data->mpduLinkQuality, data->signal_dbm, neighbor_info.neighbor->index); - //Update Neighbor Broadcast and Unicast Parameters - ws_neighbor_class_neighbor_unicast_time_info_update(neighbor_info.ws_neighbor, ws_utt, data->timestamp); - ws_neighbor_class_neighbor_unicast_schedule_set(neighbor_info.ws_neighbor, ws_us); - ws_neighbor_class_neighbor_broadcast_time_info_update(neighbor_info.ws_neighbor, &ws_bt_ie, data->timestamp); - ws_neighbor_class_neighbor_broadcast_schedule_set(neighbor_info.ws_neighbor, &ws_bs_ie); + if (neighbour_pointer_valid) { + etx_lqi_dbm_update(cur->id, data->mpduLinkQuality, data->signal_dbm, neighbor_info.neighbor->index); + //Update Neighbor Broadcast and Unicast Parameters + ws_neighbor_class_neighbor_unicast_time_info_update(neighbor_info.ws_neighbor, ws_utt, data->timestamp); + ws_neighbor_class_neighbor_unicast_schedule_set(neighbor_info.ws_neighbor, ws_us); + ws_neighbor_class_neighbor_broadcast_time_info_update(neighbor_info.ws_neighbor, &ws_bt_ie, data->timestamp); + ws_neighbor_class_neighbor_broadcast_schedule_set(neighbor_info.ws_neighbor, &ws_bs_ie); + } if (cur->ws_info->configuration_learned) { tr_info("PAN Config analyse own:%d, heard:%d", cur->ws_info->pan_information.pan_version, pan_version); if (cur->ws_info->pan_information.pan_version == pan_version) { // Same version heard so it is consistent trickle_consistent_heard(&cur->ws_info->trickle_pan_config); - if (neighbor_info.neighbor->link_role == PRIORITY_PARENT_NEIGHBOUR) { + if (neighbour_pointer_valid && neighbor_info.neighbor->link_role == PRIORITY_PARENT_NEIGHBOUR) { ws_bootstrap_primary_parent_set(cur, &neighbor_info, WS_PARENT_SOFT_SYNCH); } // no need to process more @@ -1079,7 +1113,7 @@ static void ws_bootstrap_pan_config_analyse(struct protocol_interface_info_entry } else { // received version is different so we need to reset the trickle trickle_inconsistent_heard(&cur->ws_info->trickle_pan_config, &cur->ws_info->trickle_params_pan_discovery); - if (neighbor_info.neighbor->link_role == PRIORITY_PARENT_NEIGHBOUR) { + if (neighbour_pointer_valid && neighbor_info.neighbor->link_role == PRIORITY_PARENT_NEIGHBOUR) { ws_bootstrap_primary_parent_set(cur, &neighbor_info, WS_PARENT_HARD_SYNCH); } if (common_serial_number_greater_16(cur->ws_info->pan_information.pan_version, pan_version)) { @@ -1100,7 +1134,7 @@ static void ws_bootstrap_pan_config_analyse(struct protocol_interface_info_entry tr_info("Updated PAN configuration own:%d, heard:%d", cur->ws_info->pan_information.pan_version, pan_version); // restart PAN version timer - cur->ws_info->pan_version_timeout_timer = PAN_VERSION_TIMEOUT; + cur->ws_info->pan_version_timeout_timer = ws_common_version_timeout_get(cur->ws_info->network_size_config); cur->ws_info->pan_information.pan_version = pan_version; ws_pae_controller_gtk_hash_update(cur, gtkhash_ptr); @@ -1138,7 +1172,7 @@ static void ws_bootstrap_pan_config_solicit_analyse(struct protocol_interface_in */ llc_neighbour_req_t neighbor_info; - if (ws_bootstrap_neighbor_info_request(cur, data->SrcAddr, &neighbor_info, false)) { + if (ws_bootstrap_neighbor_info_request(cur, data->SrcAddr, &neighbor_info, false, false)) { etx_lqi_dbm_update(cur->id, data->mpduLinkQuality, data->signal_dbm, neighbor_info.neighbor->index); ws_neighbor_class_neighbor_unicast_time_info_update(neighbor_info.ws_neighbor, ws_utt, data->timestamp); ws_neighbor_class_neighbor_unicast_schedule_set(neighbor_info.ws_neighbor, ws_us); @@ -1220,7 +1254,7 @@ static void ws_bootstrap_asynch_ind(struct protocol_interface_info_entry *cur, c default: return; } - + ws_stats_update(cur, STATS_WS_ASYNCH_RX, 1); //UTT-IE and US-IE are mandatory for all Asynch Messages ws_utt_ie_t ws_utt; if (!ws_wh_utt_read(ie_ext->headerIeList, ie_ext->headerIeListLength, &ws_utt)) { @@ -1273,9 +1307,21 @@ static void ws_bootstrap_asynch_ind(struct protocol_interface_info_entry *cur, c static void ws_bootstrap_asynch_confirm(struct protocol_interface_info_entry *interface, uint8_t asynch_message) { + ws_stats_update(interface, STATS_WS_ASYNCH_TX, 1); (void)interface; (void)asynch_message; } + +uint32_t ws_time_from_last_unicast_traffic(uint32_t current_time_stamp, ws_neighbor_class_entry_t *ws_neighbor) +{ + uint32_t time_from_last_unicast_shedule = current_time_stamp; + + //Time from last RX unicast in us + time_from_last_unicast_shedule -= ws_neighbor->fhss_data.uc_timing_info.utt_rx_timestamp; + time_from_last_unicast_shedule /= 1000000; //Convert to seconds + return time_from_last_unicast_shedule; +} + static void ws_bootstrap_neighbor_table_clean(struct protocol_interface_info_entry *interface) { uint8_t ll_target[16]; @@ -1286,14 +1332,22 @@ static void ws_bootstrap_neighbor_table_clean(struct protocol_interface_info_ent } memcpy(ll_target, ADDR_LINK_LOCAL_PREFIX, 8); + uint32_t current_time_stamp = ns_sw_mac_read_current_timestamp(interface->mac_api); + mac_neighbor_table_entry_t *neighbor_entry_ptr = NULL; ns_list_foreach_safe(mac_neighbor_table_entry_t, cur, &mac_neighbor_info(interface)->neighbour_list) { + ws_neighbor_class_entry_t *ws_neighbor = ws_neighbor_class_entry_get(&interface->ws_info->neighbor_storage, cur->index); if (cur->link_role == PRIORITY_PARENT_NEIGHBOUR) { //This is our primary parent we cannot delete continue; } + if (cur->nud_active || ws_neighbor->accelerated_etx_probe || ws_neighbor->negative_aro_send) { + //If NUD process is active do not trig + continue; + } + if (neighbor_entry_ptr && neighbor_entry_ptr->lifetime < cur->lifetime) { // We have already shorter link entry found this cannot replace it continue; @@ -1309,20 +1363,35 @@ static void ws_bootstrap_neighbor_table_clean(struct protocol_interface_info_ent memcpy(ll_target + 8, cur->mac64, 8); ll_target[8] ^= 2; - if (rpl_control_is_dodag_parent(interface, ll_target)) { + if (rpl_control_is_dodag_parent(interface, ll_target, true)) { // Possible parent is limited to 3 by default? continue; } } + uint32_t link_min_timeout; + //Read current timestamp + uint32_t time_from_last_unicast_shedule = ws_time_from_last_unicast_traffic(current_time_stamp, ws_neighbor); if (cur->trusted_device) { - neighbor_entry_ptr = cur; + link_min_timeout = WS_NEIGHBOR_TRUSTED_LINK_MIN_TIMEOUT; } else { - if (cur->link_lifetime - cur->lifetime > WS_NEIGHBOR_NOT_TRUSTED_LINK_TIMEOUT) { - //Accept only Enough Old not trusted Device + + link_min_timeout = WS_NEIGHBOR_NOT_TRUSTED_LINK_MIN_TIMEOUT; + } + + if (time_from_last_unicast_shedule > link_min_timeout || !ws_neighbor->unicast_data_rx) { + //Accept only Enough Old Device + if (!neighbor_entry_ptr) { + //Accept first compare neighbor_entry_ptr = cur; + } else { + uint32_t compare_neigh_time = ws_time_from_last_unicast_traffic(current_time_stamp, ws_neighbor_class_entry_get(&interface->ws_info->neighbor_storage, neighbor_entry_ptr->index)); + if (compare_neigh_time < time_from_last_unicast_shedule) { + //Accept older RX timeout allways + neighbor_entry_ptr = cur; + } } } } @@ -1333,7 +1402,7 @@ static void ws_bootstrap_neighbor_table_clean(struct protocol_interface_info_ent } -static bool ws_bootstrap_neighbor_info_request(struct protocol_interface_info_entry *interface, const uint8_t *mac_64, llc_neighbour_req_t *neighbor_buffer, bool request_new) +static bool ws_bootstrap_neighbor_info_request(struct protocol_interface_info_entry *interface, const uint8_t *mac_64, llc_neighbour_req_t *neighbor_buffer, bool request_new, bool multicast) { neighbor_buffer->neighbor = mac_neighbor_table_address_discover(mac_neighbor_info(interface), mac_64, ADDR_802_15_4_LONG); if (neighbor_buffer->neighbor) { @@ -1346,17 +1415,36 @@ static bool ws_bootstrap_neighbor_info_request(struct protocol_interface_info_en if (!request_new) { return false; } - uint8_t ll_target[16]; - memcpy(ll_target, ADDR_LINK_LOCAL_PREFIX, 8); - memcpy(ll_target + 8, mac_64, 8); - ll_target[8] ^= 2; + uint8_t ll_target[16]; + ws_bootsrap_create_ll_address(ll_target, mac_64); if (blacklist_reject(ll_target)) { // Rejected by blacklist return false; } + if (multicast) { + //for multicast neighbour we must limit if we have already enough information + if (interface->bootsrap_mode == ARM_NWK_BOOTSRAP_MODE_6LoWPAN_BORDER_ROUTER) { + //Border router never allocate neighbors by multicast + return false; + } + + uint16_t parent_candidate_size = rpl_control_parent_candidate_list_size(interface, false); + + //if we have enough candidates at list do not accept new multicast neighbours + if (parent_candidate_size >= 4) { + return false; + } + + parent_candidate_size = rpl_control_parent_candidate_list_size(interface, true); + //If we have already enough parent selected Candidates count is bigger tahn 4 + if (parent_candidate_size >= 2) { + return false; + } + } + ws_bootstrap_neighbor_table_clean(interface); neighbor_buffer->neighbor = ws_bootstrap_mac_neighbor_add(interface, mac_64); @@ -1394,7 +1482,7 @@ static void ws_neighbor_entry_remove_notify(mac_neighbor_table_entry_t *entry_pt //NUD Process Clear Here ws_nud_entry_remove(cur, entry_ptr); - ws_bootstrap_neighbor_delete(cur, entry_ptr->index); + ws_bootstrap_neighbor_delete(cur, entry_ptr); } static bool ws_neighbor_entry_nud_notify(mac_neighbor_table_entry_t *entry_ptr, void *user_data) @@ -1406,7 +1494,7 @@ static bool ws_neighbor_entry_nud_notify(mac_neighbor_table_entry_t *entry_ptr, ws_neighbor_class_entry_t *ws_neighbor = ws_neighbor_class_entry_get(&cur->ws_info->neighbor_storage, entry_ptr->index); etx_storage_t *etx_entry = etx_storage_entry_get(cur->id, entry_ptr->index); - if (!entry_ptr->trusted_device || !ws_neighbor || !etx_entry) { + if (!entry_ptr->trusted_device || !ws_neighbor || !etx_entry || ws_neighbor->negative_aro_send) { return false; } @@ -1426,17 +1514,37 @@ static bool ws_neighbor_entry_nud_notify(mac_neighbor_table_entry_t *entry_ptr, //ETX Sample 0: random 1-8 //ETX Sample 1: random 2-16 //ETX Sample 2: random 4-32 - uint32_t probe_period = WS_PROBE_INIT_BASE_SECONDS << etx_entry->etx_samples; - uint32_t time_block = 1 << etx_entry->etx_samples; - if (time_from_start >= probe_period) { - tr_debug("Link Probe test %u Sample trig", etx_entry->etx_samples); + if (etx_entry->etx_samples == 0 && ws_neighbor->accelerated_etx_probe) { + //Accept quick Probe for init ETX activate_nud = true; - } else if (time_from_start > time_block) { - uint16_t switch_prob = randLIB_get_random_in_range(0, probe_period - 1); - //Take Random from time WS_NEIGHBOR_NUD_TIMEOUT - WS_NEIGHBOR_NUD_TIMEOUT*1.5 - if (switch_prob < 2) { - tr_debug("Link Probe test with jitter %"PRIu32", sample %u", time_from_start, etx_entry->etx_samples); + } else { + if (cur->bootsrap_mode == ARM_NWK_BOOTSRAP_MODE_6LoWPAN_BORDER_ROUTER) { + if (etx_entry->etx_samples || !ws_neighbor->unicast_data_rx) { + //Border router just need 1 sample for ETX + return false; + } + } else { + uint8_t ll_address[16]; + ws_bootsrap_create_ll_address(ll_address, entry_ptr->mac64); + if (!rpl_control_is_dodag_parent(cur, ll_address, false)) { + if (etx_entry->etx_samples || !ws_neighbor->unicast_data_rx) { + return 0; + } + } + } + + uint32_t probe_period = WS_PROBE_INIT_BASE_SECONDS << etx_entry->etx_samples; + uint32_t time_block = 1 << etx_entry->etx_samples; + if (time_from_start >= probe_period) { + //tr_debug("Link Probe test %u Sample trig", etx_entry->etx_samples); activate_nud = true; + } else if (time_from_start > time_block) { + uint16_t switch_prob = randLIB_get_random_in_range(0, probe_period - 1); + //Take Random from time WS_NEIGHBOR_NUD_TIMEOUT - WS_NEIGHBOR_NUD_TIMEOUT*1.5 + if (switch_prob < 2) { + //tr_debug("Link Probe test with jitter %"PRIu32", sample %u", time_from_start, etx_entry->etx_samples); + activate_nud = true; + } } } } @@ -1450,6 +1558,10 @@ static bool ws_neighbor_entry_nud_notify(mac_neighbor_table_entry_t *entry_ptr, return false; } entry->neighbor_info = entry_ptr; + if (ws_neighbor->accelerated_etx_probe) { + ws_neighbor->accelerated_etx_probe = false; + entry->timer = 1; + } if (etx_entry->etx_samples >= WS_NEIGBOR_ETX_SAMPLE_MAX) { entry->nud_process = true; @@ -1554,7 +1666,7 @@ int ws_bootstrap_init(int8_t interface_id, net_6lowpan_mode_e bootstrap_mode) ret_val = -4; goto init_fail; } - if (ws_pae_controller_cb_register(cur, &ws_bootstrap_authentication_completed, &ws_bootstrap_nw_key_set, &ws_bootstrap_nw_key_clear, &ws_bootstrap_nw_key_index_set, &ws_bootstrap_nw_frame_counter_set, &ws_bootstrap_pan_version_increment) < 0) { + if (ws_pae_controller_cb_register(cur, &ws_bootstrap_authentication_completed, &ws_bootstrap_nw_key_set, &ws_bootstrap_nw_key_clear, &ws_bootstrap_nw_key_index_set, &ws_bootstrap_nw_frame_counter_set, &ws_bootstrap_nw_frame_counter_read, &ws_bootstrap_pan_version_increment) < 0) { ret_val = -4; goto init_fail; } @@ -1778,11 +1890,8 @@ static void ws_set_fhss_hop(protocol_interface_info_entry_t *cur) static void ws_address_registration_update(protocol_interface_info_entry_t *interface) { - if (!interface->ws_info->address_registration_event_active) { - interface->ws_info->address_registration_event_active = true; - tr_info("RPL parent update ... register ARO"); - ws_bootsrap_event_trig(WS_ADDRESS_ADDED, interface->bootStrapId, ARM_LIB_LOW_PRIORITY_EVENT, NULL); - } + rpl_control_register_address(interface, NULL); + tr_info("RPL parent update ... register ARO"); } static void ws_bootstrap_rpl_callback(rpl_event_t event, void *handle) @@ -1835,7 +1944,13 @@ static void ws_dhcp_client_global_adress_cb(int8_t interface, uint8_t dhcp_addr[ (void)prefix; (void)interface; //TODO add handler for negative status - tr_debug("DHCPv6 %s status %u", trace_ipv6(dhcp_addr), register_status); + tr_debug("DHCPv6 %s status %u with link %s", trace_ipv6(prefix), register_status, trace_ipv6(dhcp_addr)); + if (register_status) { + protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(interface); + if (cur) { + rpl_control_register_address(cur, prefix); + } + } } @@ -1907,6 +2022,7 @@ static void ws_bootstrap_rpl_activate(protocol_interface_info_entry_t *cur) rpl_control_set_callback(protocol_6lowpan_rpl_domain, ws_bootstrap_rpl_callback, ws_rpl_prefix_callback, cur); // If i am router I Do this rpl_control_force_leaf(protocol_6lowpan_rpl_domain, leaf); + rpl_control_request_parent_link_confirmation(true); cur->ws_info->rpl_state = 0xff; // Set invalid state and learn from event } @@ -1966,16 +2082,6 @@ static void ws_bootstrap_start_discovery(protocol_interface_info_entry_t *cur) // New network scan started old addresses not assumed valid anymore ws_bootstrap_ip_stack_addr_clear(cur); - // Reset advertisement solicit trickle to start discovering network - cur->ws_info->trickle_pas_running = true; - trickle_start(&cur->ws_info->trickle_pan_advertisement_solicit, &cur->ws_info->trickle_params_pan_discovery); - if (cur->ws_info->power_up_setup) { - cur->ws_info->power_up_setup = false; - tr_debug("PAS init I %u and t %u", cur->ws_info->trickle_pan_advertisement_solicit.I, cur->ws_info->trickle_pan_advertisement_solicit.t); - } else { - trickle_inconsistent_heard(&cur->ws_info->trickle_pan_advertisement_solicit, &cur->ws_info->trickle_params_pan_discovery); - } - if ((cur->lowpan_info & INTERFACE_NWK_BOOTSRAP_ACTIVE) != INTERFACE_NWK_BOOTSRAP_ACTIVE) { // we have sent bootstrap ready event and now // restarted discovery so bootstrap down event is sent @@ -1983,8 +2089,24 @@ static void ws_bootstrap_start_discovery(protocol_interface_info_entry_t *cur) ws_nwk_event_post(cur, ARM_NWK_NWK_CONNECTION_DOWN); } - // Discovery statemachine is checkked after two trickle interval - cur->bootsrap_state_machine_cnt = 2 * cur->ws_info->trickle_params_pan_discovery.Imin + randLIB_get_8bit() % 50; + // Start advertisement solicit trickle and calculate when we are checking the status + cur->ws_info->trickle_pas_running = true; + if (cur->ws_info->trickle_pan_advertisement_solicit.I != cur->ws_info->trickle_params_pan_discovery.Imin) { + // Trickle not reseted so starting a new interval + trickle_start(&cur->ws_info->trickle_pan_advertisement_solicit, &cur->ws_info->trickle_params_pan_discovery); + } + + // Discovery statemachine is checkked after we have sent the Solicit + uint16_t time_to_solicit = 0; + if (cur->ws_info->trickle_pan_advertisement_solicit.t > cur->ws_info->trickle_pan_advertisement_solicit.now) { + time_to_solicit = cur->ws_info->trickle_pan_advertisement_solicit.t - cur->ws_info->trickle_pan_advertisement_solicit.now; + } + + tr_debug("Disc params imin %u, imax %u, expirations %u, k %u PAS Trickle I %u t %u, now %u, c %u", + cur->ws_info->trickle_params_pan_discovery.Imin, cur->ws_info->trickle_params_pan_discovery.Imax, cur->ws_info->trickle_params_pan_discovery.TimerExpirations, cur->ws_info->trickle_params_pan_discovery.k, + cur->ws_info->trickle_pan_advertisement_solicit.I, cur->ws_info->trickle_pan_advertisement_solicit.t, cur->ws_info->trickle_pan_advertisement_solicit.now, cur->ws_info->trickle_pan_advertisement_solicit.c); + + cur->bootsrap_state_machine_cnt = time_to_solicit + cur->ws_info->trickle_params_pan_discovery.Imin + randLIB_get_8bit() % 50; } // Start authentication @@ -2024,6 +2146,12 @@ static void ws_bootstrap_nw_frame_counter_set(protocol_interface_info_entry_t *c mac_helper_link_frame_counter_set(cur->id, counter); } +static void ws_bootstrap_nw_frame_counter_read(protocol_interface_info_entry_t *cur, uint32_t *counter) +{ + // Read frame counter + mac_helper_link_frame_counter_read(cur->id, counter); +} + static void ws_bootstrap_authentication_completed(protocol_interface_info_entry_t *cur, bool success) { if (success) { @@ -2032,6 +2160,8 @@ static void ws_bootstrap_authentication_completed(protocol_interface_info_entry_ } else { tr_debug("authentication failed"); // What else to do to start over again... + // Trickle is reseted when entering to discovery from state 2 + trickle_inconsistent_heard(&cur->ws_info->trickle_pan_advertisement_solicit, &cur->ws_info->trickle_params_pan_discovery); ws_bootstrap_event_discovery_start(cur); } } @@ -2244,17 +2374,6 @@ static void ws_bootstrap_pan_config(protocol_interface_info_entry_t *cur) ws_llc_asynch_request(cur, &async_req); } -static bool ws_bootstrap_address_registration_ongoing(protocol_interface_info_entry_t *cur) -{ - ns_list_foreach(if_address_entry_t, addr, &cur->ip_addresses) { - if (addr->addr_reg_pend != 0) { - return true; - } - } - - return false; -} - static void ws_bootstrap_event_handler(arm_event_s *event) { ws_bootsrap_event_type_e event_type; @@ -2301,7 +2420,7 @@ static void ws_bootstrap_event_handler(arm_event_s *event) uint8_t *gtkhash = ws_pae_controller_gtk_hash_ptr_get(cur); ws_llc_set_gtkhash(cur, gtkhash); - cur->ws_info->pan_version_timer = PAN_VERSION_LIFETIME; + cur->ws_info->pan_version_timer = ws_common_version_lifetime_get(cur->ws_info->network_size_config); // Set default parameters for FHSS when starting a discovery ws_fhss_border_router_configure(cur); @@ -2378,12 +2497,7 @@ static void ws_bootstrap_event_handler(arm_event_s *event) ws_bootstrap_advertise_start(cur); ws_bootstrap_state_change(cur, ER_BOOTSRAP_DONE); break; - case WS_ADDRESS_ADDED: - cur->ws_info->address_registration_event_active = false; - if (!ws_bootstrap_address_registration_ongoing(cur)) { - rpl_control_register_address(cur, (if_address_entry_t *) event->data_ptr); - } - break; + default: tr_err("Invalid event received"); break; @@ -2407,7 +2521,7 @@ void ws_bootstrap_network_scan_process(protocol_interface_info_entry_t *cur) // Add EAPOL neighbour llc_neighbour_req_t neighbor_info; - if (!ws_bootstrap_neighbor_info_request(cur, cur->ws_info->parent_info.addr, &neighbor_info, true)) { + if (!ws_bootstrap_neighbor_info_request(cur, cur->ws_info->parent_info.addr, &neighbor_info, true, false)) { return; } @@ -2515,9 +2629,6 @@ void ws_bootstrap_state_machine(protocol_interface_info_entry_t *cur) break; case ER_PANA_AUTH: tr_info("authentication start"); - // only advert sol stopped as we might be doing re authentication - cur->ws_info->trickle_pas_running = false; - //Add Test ecurity key and security level's // Advertisements stopped during the EAPOL cur->ws_info->trickle_pa_running = false; cur->ws_info->trickle_pc_running = false; @@ -2557,6 +2668,8 @@ void ws_bootstrap_trickle_timer(protocol_interface_info_entry_t *cur, uint16_t t // Remove network keys from MAC ws_pae_controller_nw_keys_remove(cur); + // Trickle is reseted when entering to discovery from state 3 + trickle_inconsistent_heard(&cur->ws_info->trickle_pan_advertisement_solicit, &cur->ws_info->trickle_params_pan_discovery); ws_bootstrap_event_discovery_start(cur); return; } @@ -2601,9 +2714,7 @@ void ws_primary_parent_update(protocol_interface_info_entry_t *interface, mac_ne neighbor_info.ws_neighbor = ws_neighbor_class_entry_get(&interface->ws_info->neighbor_storage, neighbor->index); ws_bootstrap_primary_parent_set(interface, &neighbor_info, WS_PARENT_HARD_SYNCH); uint8_t link_local_address[16]; - memcpy(link_local_address, ADDR_LINK_LOCAL_PREFIX, 8); - memcpy(link_local_address + 8, neighbor->mac64, 8); - link_local_address[8] ^= 2; + ws_bootsrap_create_ll_address(link_local_address, neighbor->mac64); dhcp_client_server_address_update(interface->id, NULL, link_local_address); ws_secondary_parent_update(interface); @@ -2615,11 +2726,30 @@ void ws_secondary_parent_update(protocol_interface_info_entry_t *interface) if (interface->ws_info) { ns_list_foreach(if_address_entry_t, address, &interface->ip_addresses) { if (!addr_is_ipv6_link_local(address->address)) { - address->addr_reg_done = 0; ws_address_registration_update(interface); } } } } +void ws_bootstrap_etx_accelerate(protocol_interface_info_entry_t *interface, mac_neighbor_table_entry_t *neigh) +{ + ws_neighbor_class_entry_t *ws_neighbor = ws_neighbor_class_entry_get(&interface->ws_info->neighbor_storage, neigh->index); + //Enable Faster ETX probing + ws_neighbor->accelerated_etx_probe = true; + //Move Neighbor to first to for accelerate Process + mac_neighbor_table_t *table_class = mac_neighbor_info(interface); + ns_list_remove(&table_class->neighbour_list, neigh); + ns_list_add_to_start(&table_class->neighbour_list, neigh); + //Try to Generate Active NUD Immediately + if (!ws_neighbor_entry_nud_notify(neigh, interface)) { + return;//Return if NUD active is full + } + table_class->active_nud_process++; + neigh->nud_active = true; + //Push NS to send + ws_nud_active_timer(interface, 0); + +} + #endif //HAVE_WS diff --git a/source/6LoWPAN/ws/ws_bootstrap.h b/source/6LoWPAN/ws/ws_bootstrap.h index 789279e0fc..9d7f552465 100644 --- a/source/6LoWPAN/ws/ws_bootstrap.h +++ b/source/6LoWPAN/ws/ws_bootstrap.h @@ -24,8 +24,7 @@ typedef enum { WS_DISCOVERY_START, /**< discovery start*/ WS_CONFIGURATION_START, /**< configuration learn start*/ WS_OPERATION_START, /**< active operation start*/ - WS_ROUTING_READY, /**< RPL routing connected to BR*/ - WS_ADDRESS_ADDED /**< Address added to IF*/ + WS_ROUTING_READY /**< RPL routing connected to BR*/ } ws_bootsrap_event_type_e; #ifdef HAVE_WS @@ -77,6 +76,8 @@ bool ws_eapol_relay_state_active(protocol_interface_info_entry_t *cur); void ws_bootstrap_eapol_parent_synch(struct protocol_interface_info_entry *cur, struct llc_neighbour_req *neighbor_info); +void ws_bootstrap_etx_accelerate(struct protocol_interface_info_entry *cur, mac_neighbor_table_entry_t *neigh); + #else #define ws_bootstrap_init(interface_id, bootstrap_mode) (-1) @@ -86,6 +87,7 @@ void ws_bootstrap_eapol_parent_synch(struct protocol_interface_info_entry *cur, #define ws_bootstrap_aro_failure(cur, ll_address) #define ws_primary_parent_update(interface, neighbor) #define ws_secondary_parent_update(interface) +#define ws_bootstrap_etx_accelerate(cur, neigh) ((void) 0) #endif //HAVE_WS diff --git a/source/6LoWPAN/ws/ws_common.c b/source/6LoWPAN/ws/ws_common.c index 5478366ec5..e020bee7c6 100644 --- a/source/6LoWPAN/ws/ws_common.c +++ b/source/6LoWPAN/ws/ws_common.c @@ -27,6 +27,7 @@ #include "6LoWPAN/ws/ws_common.h" #include "6LoWPAN/ws/ws_bootstrap.h" #include "6LoWPAN/ws/ws_bbr_api_internal.h" +#include "Service_Libs/etx/etx.h" #include "Service_Libs/mac_neighbor_table/mac_neighbor_table.h" #include "Service_Libs/blacklist/blacklist.h" #include "ws_management_api.h" @@ -35,7 +36,9 @@ #ifdef HAVE_WS #define TRACE_GROUP "wscm" -int8_t DEVICE_MIN_SENS = -93; +// estimated sensitivity -93 dbm converted to Wi-SUN RSL range +// This provides a range of -174 (0) to +80 (254) dBm +uint8_t DEVICE_MIN_SENS = 174 - 93; #define TRICKLE_IMIN_60_SECS (60 * 10) #define TRICKLE_IMIN_30_SECS (30 * 10) @@ -50,7 +53,7 @@ static const trickle_params_t trickle_params_pan_discovery_large = { static const trickle_params_t trickle_params_pan_discovery_medium = { .Imin = TRICKLE_IMIN_30_SECS, /* 30 second; ticks are 1s */ - .Imax = TRICKLE_IMIN_30_SECS << 3, /* 240 seconds 4 min*/ + .Imax = TRICKLE_IMIN_30_SECS << 5, /* 960 seconds 16 min*/ .k = 1, /* 1 */ .TimerExpirations = TRICKLE_EXPIRATIONS_INFINITE }; @@ -274,8 +277,8 @@ int8_t ws_common_allocate_and_init(protocol_interface_info_entry_t *cur) cur->ws_info->hopping_schdule.operating_mode = OPERATING_MODE_3; cur->ws_info->hopping_schdule.operating_class = 2; ws_common_regulatory_domain_config(cur); - cur->ws_info->network_size_config = NETWORK_SIZE_AUTOMATIC; - ws_common_network_size_configure(cur, 10); // defaults to small network size + cur->ws_info->network_size_config = NETWORK_SIZE_MEDIUM; + ws_common_network_size_configure(cur, 200); // defaults to medium network size // Set defaults for the device. user can modify these. cur->ws_info->fhss_uc_fixed_channel = 0xffff; @@ -314,17 +317,17 @@ void ws_common_network_size_configure(protocol_interface_info_entry_t *cur, uint cur->ws_info->trickle_params_pan_discovery = trickle_params_pan_discovery_medium; // Something in between // imin: 15 (32s) - // doublings:3 (262s) - // redundancy; 7 - ws_bbr_rpl_config(15, 3, 7); + // doublings:5 (960s) + // redundancy; 10 + ws_bbr_rpl_config(15, 5, 10); } else { // Configure the Wi-SUN discovery trickle parameters cur->ws_info->trickle_params_pan_discovery = trickle_params_pan_discovery_large; // Wi-SUN Large network parameters // imin: 19 (524s, 9 min) // doublings:1 (1048s, 17 min) - // redundancy; 1 Really heavy redundancy - ws_bbr_rpl_config(19, 1, 1); + // redundancy; 10 May need some tuning still + ws_bbr_rpl_config(19, 1, 10); } return; } @@ -396,6 +399,58 @@ bool ws_common_allow_child_registration(protocol_interface_info_entry_t *interfa return true; } +bool ws_common_negative_aro_mark(protocol_interface_info_entry_t *interface, const uint8_t *eui64) +{ + mac_neighbor_table_entry_t *neighbour = mac_neighbor_table_address_discover(mac_neighbor_info(interface), eui64, ADDR_802_15_4_LONG); + if (!neighbour) { + return false; + } + ws_neighbor_class_entry_t *ws_neighbor = ws_neighbor_class_entry_get(&interface->ws_info->neighbor_storage, neighbour->index); + ws_neighbor->negative_aro_send = true; + neighbour->lifetime = WS_NEIGHBOR_NOT_TRUSTED_LINK_MIN_TIMEOUT; //Remove anyway if Packet is freed before MAC push + return true; +} + +void ws_common_etx_validate(protocol_interface_info_entry_t *interface, mac_neighbor_table_entry_t *neigh) +{ + etx_storage_t *etx_entry = etx_storage_entry_get(interface->id, neigh->index); + + if (neigh->nud_active || !neigh->trusted_device || !etx_entry || etx_entry->etx_samples) { + return; //Do not trig Second NS if Active NUD already, not trusted or ETX samples already done + } + + ws_bootstrap_etx_accelerate(interface, neigh); +} + +uint32_t ws_common_version_lifetime_get(uint8_t config) +{ + uint32_t lifetime; + if (config == NETWORK_SIZE_SMALL) { + lifetime = PAN_VERSION_SMALL_NETWORK_LIFETIME; + } else if (config == NETWORK_SIZE_MEDIUM) { + lifetime = PAN_VERSION_MEDIUM_NETWORK_LIFETIME; + } else { + lifetime = PAN_VERSION_LARGE_NETWORK_LIFETIME; + } + + return lifetime; + +} + +uint32_t ws_common_version_timeout_get(uint8_t config) +{ + uint32_t lifetime; + if (config == NETWORK_SIZE_SMALL) { + lifetime = PAN_VERSION_SMALL_NETWORK_TIMEOUT; + } else if (config == NETWORK_SIZE_MEDIUM) { + lifetime = PAN_VERSION_MEDIUM_NETWORK_TIMEOUT; + } else { + lifetime = PAN_VERSION_LARGE_NETWORK_TIMEOUT; + } + + return lifetime; +} + #endif // HAVE_WS diff --git a/source/6LoWPAN/ws/ws_common.h b/source/6LoWPAN/ws/ws_common.h index 3c1d220cc7..510f3d9681 100644 --- a/source/6LoWPAN/ws/ws_common.h +++ b/source/6LoWPAN/ws/ws_common.h @@ -73,13 +73,11 @@ typedef struct ws_info_s { uint32_t pan_version_timer; /**< border router version udate timeout */ uint32_t pan_version_timeout_timer; /**< routers will fallback to previous state after this */ uint8_t gtkhash[32]; - bool address_registration_event_active : 1; bool configuration_learned: 1; bool trickle_pas_running: 1; bool trickle_pa_running: 1; bool trickle_pcs_running: 1; bool trickle_pc_running: 1; - bool power_up_setup: 1; // default fhss parameters for this device uint8_t fhss_uc_dwell_interval; uint8_t fhss_bc_dwell_interval; @@ -94,6 +92,7 @@ typedef struct ws_info_s { ws_nud_table_list_t free_nud_entries; struct ws_pan_information_s pan_information; ws_hopping_schedule_t hopping_schdule; + struct ws_statistics *stored_stats_ptr; struct ws_neighbor_class_s neighbor_storage; struct fhss_timer *fhss_timer_ptr; // Platform adaptation for FHSS timers. struct fhss_api *fhss_api; @@ -123,6 +122,15 @@ void ws_common_neighbor_remove(protocol_interface_info_entry_t *cur, const uint8 bool ws_common_allow_child_registration(protocol_interface_info_entry_t *cur, const uint8_t *eui64); +void ws_common_etx_validate(protocol_interface_info_entry_t *interface, mac_neighbor_table_entry_t *neigh); + +bool ws_common_negative_aro_mark(protocol_interface_info_entry_t *interface, const uint8_t *eui64); + + +uint32_t ws_common_version_lifetime_get(uint8_t config); + +uint32_t ws_common_version_timeout_get(uint8_t config); + #define ws_info(cur) ((cur)->ws_info) #else #define ws_info(cur) ((ws_info_t *) NULL) @@ -132,6 +140,8 @@ bool ws_common_allow_child_registration(protocol_interface_info_entry_t *cur, co #define ws_common_neighbor_remove(cur, ll_address) #define ws_common_fast_timer(cur, ticks) ((void) 0) #define ws_common_allow_child_registration(cur, eui64) (false) +#define ws_common_etx_validate(interface, neigh) ((void) 0) +#define ws_common_negative_aro_mark(interface, eui64)(false) #endif //HAVE_WS diff --git a/source/6LoWPAN/ws/ws_common_defines.h b/source/6LoWPAN/ws/ws_common_defines.h index 4df0dd641f..4e796f4fd9 100644 --- a/source/6LoWPAN/ws/ws_common_defines.h +++ b/source/6LoWPAN/ws/ws_common_defines.h @@ -186,7 +186,8 @@ typedef struct ws_bs_ie { #define WS_FAN_VERSION_1_0 1 #define WS_NEIGHBOR_LINK_TIMEOUT 2200 -#define WS_NEIGHBOR_NOT_TRUSTED_LINK_TIMEOUT 60 +#define WS_NEIGHBOR_NOT_TRUSTED_LINK_MIN_TIMEOUT 60 +#define WS_NEIGHBOR_TRUSTED_LINK_MIN_TIMEOUT 15 #define WS_NEIGHBOR_NUD_TIMEOUT WS_NEIGHBOR_LINK_TIMEOUT / 2 #define WS_NEIGBOR_ETX_SAMPLE_MAX 3 diff --git a/source/6LoWPAN/ws/ws_config.h b/source/6LoWPAN/ws/ws_config.h index f7eecaa201..0d63c67c6b 100644 --- a/source/6LoWPAN/ws/ws_config.h +++ b/source/6LoWPAN/ws/ws_config.h @@ -37,7 +37,9 @@ * Minimum interval at which a Border Router shall increment its PAN Version value. */ -#define PAN_VERSION_LIFETIME 240 +#define PAN_VERSION_SMALL_NETWORK_LIFETIME 4*60 +#define PAN_VERSION_MEDIUM_NETWORK_LIFETIME 15*60 +#define PAN_VERSION_LARGE_NETWORK_LIFETIME 30*60 //30min #define RPL_VERSION_LIFETIME 5*3600 @@ -50,7 +52,11 @@ * */ -#define PAN_VERSION_TIMEOUT 1920 +#define PAN_VERSION_SMALL_NETWORK_TIMEOUT 32*60 + +#define PAN_VERSION_MEDIUM_NETWORK_TIMEOUT 64*60 + +#define PAN_VERSION_LARGE_NETWORK_TIMEOUT 90*60 /* Routing Cost Weighting factor */ @@ -68,7 +74,7 @@ * * Default value for us is -93 */ -extern int8_t DEVICE_MIN_SENS; +extern uint8_t DEVICE_MIN_SENS; /* Candidate parent Threshold */ @@ -96,7 +102,7 @@ extern int8_t DEVICE_MIN_SENS; * */ #define WS_DHCP_SOLICIT_TIMEOUT 60 -#define WS_DHCP_SOLICIT_MAX_RT 3600 +#define WS_DHCP_SOLICIT_MAX_RT 900 #define WS_DHCP_SOLICIT_MAX_RC 0 @@ -120,5 +126,11 @@ extern int8_t DEVICE_MIN_SENS; #define WS_BLACKLIST_PURGE_NBR 3 #define WS_BLACKLIST_PURGE_TIMER_TIMEOUT 60 +/* + * MAC frame counter NVM storing configuration + */ +#define FRAME_COUNTER_STORE_INTERVAL 60 // Time interval (on seconds) between frame counter store operations +#define FRAME_COUNTER_INCREMENT 1000 // How much frame counter is incremented on start up +#define FRAME_COUNTER_STORE_THRESHOLD 800 // How much frame counter must increment before it is stored #endif /* WS_CONFIG_H_ */ diff --git a/source/6LoWPAN/ws/ws_empty_functions.c b/source/6LoWPAN/ws/ws_empty_functions.c index 0881574e92..487af5e151 100644 --- a/source/6LoWPAN/ws/ws_empty_functions.c +++ b/source/6LoWPAN/ws/ws_empty_functions.c @@ -189,4 +189,17 @@ int ws_test_next_gtk_set(int8_t interface_id, uint8_t *gtk[4]) return -1; } +int ws_statistics_start(int8_t interface_id, ws_statistics_t *stats_ptr) +{ + (void) interface_id; + (void) stats_ptr; + return -1; +} + +int ws_statistics_stop(int8_t interface_id) +{ + (void) interface_id; + return -1; +} + #endif // no HAVE_WS diff --git a/source/6LoWPAN/ws/ws_ie_lib.c b/source/6LoWPAN/ws/ws_ie_lib.c index 92b95bce68..a3aa0d93a6 100644 --- a/source/6LoWPAN/ws/ws_ie_lib.c +++ b/source/6LoWPAN/ws/ws_ie_lib.c @@ -111,10 +111,10 @@ uint8_t *ws_wh_fc_write(uint8_t *ptr, uint8_t flow_ctrl) return ptr; } -uint8_t *ws_wh_rsl_write(uint8_t *ptr, int8_t rssi) +uint8_t *ws_wh_rsl_write(uint8_t *ptr, uint8_t rsl) { ptr = ws_wh_header_base_write(ptr, 1, WH_IE_RSL_TYPE); - *ptr++ = rssi; + *ptr++ = rsl; return ptr; } diff --git a/source/6LoWPAN/ws/ws_ie_lib.h b/source/6LoWPAN/ws/ws_ie_lib.h index e992b09fd2..1beadcd898 100644 --- a/source/6LoWPAN/ws/ws_ie_lib.h +++ b/source/6LoWPAN/ws/ws_ie_lib.h @@ -36,7 +36,7 @@ typedef struct ws_wp_network_name { uint8_t *ws_wh_utt_write(uint8_t *ptr, uint8_t message_type); uint8_t *ws_wh_bt_write(uint8_t *ptr); uint8_t *ws_wh_fc_write(uint8_t *ptr, uint8_t flow_ctrl); -uint8_t *ws_wh_rsl_write(uint8_t *ptr, int8_t rssi); +uint8_t *ws_wh_rsl_write(uint8_t *ptr, uint8_t rsl); uint8_t *ws_wh_vh_write(uint8_t *ptr, uint8_t *vendor_header, uint8_t vendor_header_length); uint8_t *ws_wh_ea_write(uint8_t *ptr, uint8_t *eui64); diff --git a/source/6LoWPAN/ws/ws_llc.h b/source/6LoWPAN/ws/ws_llc.h index a1dab61bff..1104431e70 100644 --- a/source/6LoWPAN/ws/ws_llc.h +++ b/source/6LoWPAN/ws/ws_llc.h @@ -99,11 +99,12 @@ typedef void ws_asynch_confirm(struct protocol_interface_info_entry *interface, * @param mac_64 Neighbor 64-bit address * @param neighbor_buffer Buffer where neighbor infor is buffered * @param request_new true if is possible to allocate new entry + * @param multicast true if packet is multicast * * @return true when neighbor info is available * @return false when no neighbor info */ -typedef bool ws_neighbor_info_request(struct protocol_interface_info_entry *interface, const uint8_t *mac_64, llc_neighbour_req_t *neighbor_buffer, bool request_new); +typedef bool ws_neighbor_info_request(struct protocol_interface_info_entry *interface, const uint8_t *mac_64, llc_neighbour_req_t *neighbor_buffer, bool request_new, bool multicast); /** * @brief ws_llc_create ws LLC module create diff --git a/source/6LoWPAN/ws/ws_llc_data_service.c b/source/6LoWPAN/ws/ws_llc_data_service.c index 9c9192bb1b..53b2a9e9e9 100644 --- a/source/6LoWPAN/ws/ws_llc_data_service.c +++ b/source/6LoWPAN/ws/ws_llc_data_service.c @@ -395,7 +395,7 @@ static void ws_llc_mac_confirm_cb(const mac_api_t *api, const mcps_data_conf_t * success = true; } - if (message->dst_address_type == MAC_ADDR_MODE_64_BIT && base->ws_neighbor_info_request_cb(interface, message->dst_address, &neighbor_info, false)) { + if (message->dst_address_type == MAC_ADDR_MODE_64_BIT && base->ws_neighbor_info_request_cb(interface, message->dst_address, &neighbor_info, false, false)) { etx_transm_attempts_update(interface->id, 1 + data->tx_retries, success, neighbor_info.neighbor->index); //TODO discover RSL from Enchanced ACK Header IE elements ws_utt_ie_t ws_utt; @@ -463,8 +463,7 @@ static void ws_llc_ack_data_req_ext(const mac_api_t *api, mcps_ack_data_payload_ //Write Data to block uint8_t *ptr = base->ws_enhanced_ack_elements; ptr = ws_wh_utt_write(ptr, WS_FT_ACK); - uint8_t rsl = ws_neighbor_class_rssi_from_dbm_calculate(rssi); - ws_wh_rsl_write(ptr, rsl); + ws_wh_rsl_write(ptr, ws_neighbor_class_rsl_from_dbm_calculate(rssi)); } /** WS LLC MAC data extension indication */ @@ -494,6 +493,7 @@ static void ws_llc_mac_indication_cb(const mac_api_t *api, const mcps_data_ind_t return; } + mpx_user_t *user_cb; mac_payload_IE_t mpx_ie; mpx_ie.id = MAC_PAYLOAD_MPX_IE_GROUP_ID; if (mac_ie_payload_discover(ie_ext->payloadIeList, ie_ext->payloadIeListLength, &mpx_ie) < 1) { @@ -522,12 +522,24 @@ static void ws_llc_mac_indication_cb(const mac_api_t *api, const mcps_data_ind_t } llc_neighbour_req_t neighbor_info; - - if (!base->ws_neighbor_info_request_cb(interface, data->SrcAddr, &neighbor_info, us_ie_inline)) { - tr_debug("Drop message no neighbor"); - return; + bool multicast; + if (data->DstAddrMode == ADDR_802_15_4_LONG) { + multicast = false; + } else { + multicast = true; } + if (!base->ws_neighbor_info_request_cb(interface, data->SrcAddr, &neighbor_info, us_ie_inline, multicast)) { + if (!multicast || ws_utt.message_type == WS_FT_EAPOL) { + tr_debug("Drop message no neighbor"); + return; + } else { + goto mpx_data_ind; + } + } + + multicast = false; + ws_neighbor_class_neighbor_unicast_time_info_update(neighbor_info.ws_neighbor, &ws_utt, data->timestamp); if (us_ie_inline) { ws_neighbor_class_neighbor_unicast_schedule_set(neighbor_info.ws_neighbor, &us_ie); @@ -557,9 +569,9 @@ static void ws_llc_mac_indication_cb(const mac_api_t *api, const mcps_data_ind_t } } - //Refresh Neighbor if unicast + //Refresh Neighbor ETX if unicast if (ws_utt.message_type == WS_FT_DATA && data->DstAddrMode == ADDR_802_15_4_LONG) { - neighbor_info.neighbor->lifetime = neighbor_info.neighbor->link_lifetime; + neighbor_info.ws_neighbor->unicast_data_rx = true; etx_lqi_dbm_update(interface->id, data->mpduLinkQuality, data->signal_dbm, neighbor_info.neighbor->index); } if (ws_utt.message_type == WS_FT_DATA) { @@ -572,10 +584,15 @@ static void ws_llc_mac_indication_cb(const mac_api_t *api, const mcps_data_ind_t } } + +mpx_data_ind: // Discover MPX - mpx_user_t *user_cb = ws_llc_mpx_user_discover(&base->mpx_data_base, mpx_frame.multiplex_id); + user_cb = ws_llc_mpx_user_discover(&base->mpx_data_base, mpx_frame.multiplex_id); if (user_cb && user_cb->data_ind) { mcps_data_ind_t data_ind = *data; + if (multicast) { + data_ind.Key.SecurityLevel = 0; //Mark unknow device + } data_ind.msdu_ptr = mpx_frame.frame_ptr; data_ind.msduLength = mpx_frame.frame_length; user_cb->data_ind(&base->mpx_data_base.mpx_api, &data_ind); @@ -618,7 +635,7 @@ static uint16_t ws_mpx_header_size_get(llc_data_base_t *base, uint16_t user_id) } //Dynamic length - header_size += 2 + WS_WP_SUB_IE_ELEMENT_HEADER_LENGTH + ws_wp_nested_hopping_schedule_length(base->ie_params.hopping_schedule, true); + header_size += 2 + WS_WP_SUB_IE_ELEMENT_HEADER_LENGTH + ws_wp_nested_hopping_schedule_length(base->ie_params.hopping_schedule, true) + ws_wp_nested_hopping_schedule_length(base->ie_params.hopping_schedule, false); } else if (MPX_KEY_MANAGEMENT_ENC_USER_ID) { header_size += 7 + 5 + 2; @@ -687,6 +704,11 @@ static void ws_llc_mpx_data_request(const mpx_api_t *api, const struct mcps_data if (base->ie_params.vendor_payload_length) { nested_wp_id.vp_ie = true; } + + if (!data->TxAckReq) { + nested_wp_id.bs_ie = true; + } + } else if (user_id == MPX_KEY_MANAGEMENT_ENC_USER_ID) { ie_header_mask.bt_ie = ws_eapol_relay_state_active(base->interface_ptr); ie_header_mask.ea_ie = ws_eapol_handshake_first_msg(data->msdu, data->msduLength, base->interface_ptr); diff --git a/source/6LoWPAN/ws/ws_management_api.c b/source/6LoWPAN/ws/ws_management_api.c index e733080d8d..e302b7bd7a 100644 --- a/source/6LoWPAN/ws/ws_management_api.c +++ b/source/6LoWPAN/ws/ws_management_api.c @@ -118,6 +118,8 @@ int ws_management_network_size_set( if (network_size == NETWORK_SIZE_LARGE) { ws_common_network_size_configure(cur, 5000); + } else if (network_size == NETWORK_SIZE_MEDIUM) { + ws_common_network_size_configure(cur, 200); } else { ws_common_network_size_configure(cur, 10); } diff --git a/source/6LoWPAN/ws/ws_neighbor_class.c b/source/6LoWPAN/ws/ws_neighbor_class.c index 79036b8375..8eda4fcc63 100644 --- a/source/6LoWPAN/ws/ws_neighbor_class.c +++ b/source/6LoWPAN/ws/ws_neighbor_class.c @@ -134,13 +134,22 @@ void ws_neighbor_class_neighbor_broadcast_schedule_set(ws_neighbor_class_entry_t ws_neighbor->fhss_data.bc_timing_info.broadcast_schedule_id = ws_bs_ie->broadcast_schedule_identifier; } -uint8_t ws_neighbor_class_rssi_from_dbm_calculate(int8_t dbm_heard) +void ws_neighbor_class_rf_sensitivity_calculate(uint8_t rsl_heard) { - if (DEVICE_MIN_SENS > dbm_heard) { + if (DEVICE_MIN_SENS > rsl_heard) { // We are hearing packet with lower than min_sens dynamically learn the sensitivity - DEVICE_MIN_SENS = dbm_heard; + DEVICE_MIN_SENS = rsl_heard; } - return dbm_heard - DEVICE_MIN_SENS; +} + +uint8_t ws_neighbor_class_rsl_from_dbm_calculate(int8_t dbm_heard) +{ + /* RSL MUST be calculated as the received signal level relative to standard + * thermal noise (290oK) at 1 Hz bandwidth or 174 dBm. + * This provides a range of -174 (0) to +80 (254) dBm. + */ + + return dbm_heard + 174; } static void ws_neighbor_class_parent_set_analyze(ws_neighbor_class_entry_t *ws_neighbor) @@ -151,24 +160,26 @@ static void ws_neighbor_class_parent_set_analyze(ws_neighbor_class_entry_t *ws_n return; } - if (ws_neighbor_class_rsl_in_get(ws_neighbor) < (CAND_PARENT_THRESHOLD - CAND_PARENT_HYSTERISIS) && - ws_neighbor_class_rsl_out_get(ws_neighbor) < (CAND_PARENT_THRESHOLD - CAND_PARENT_HYSTERISIS)) { + if (ws_neighbor_class_rsl_in_get(ws_neighbor) < (DEVICE_MIN_SENS + CAND_PARENT_THRESHOLD - CAND_PARENT_HYSTERISIS) && + ws_neighbor_class_rsl_out_get(ws_neighbor) < (DEVICE_MIN_SENS + CAND_PARENT_THRESHOLD - CAND_PARENT_HYSTERISIS)) { ws_neighbor->candidate_parent = false; } - if (ws_neighbor_class_rsl_in_get(ws_neighbor) > (CAND_PARENT_THRESHOLD + CAND_PARENT_HYSTERISIS) && - ws_neighbor_class_rsl_out_get(ws_neighbor) > (CAND_PARENT_THRESHOLD + CAND_PARENT_HYSTERISIS)) { + if (ws_neighbor_class_rsl_in_get(ws_neighbor) > (DEVICE_MIN_SENS + CAND_PARENT_THRESHOLD + CAND_PARENT_HYSTERISIS) && + ws_neighbor_class_rsl_out_get(ws_neighbor) > (DEVICE_MIN_SENS + CAND_PARENT_THRESHOLD + CAND_PARENT_HYSTERISIS)) { ws_neighbor->candidate_parent = true; } } void ws_neighbor_class_rsl_in_calculate(ws_neighbor_class_entry_t *ws_neighbor, int8_t dbm_heard) { - uint8_t rssi = ws_neighbor_class_rssi_from_dbm_calculate(dbm_heard); + uint8_t rsl = ws_neighbor_class_rsl_from_dbm_calculate(dbm_heard); + // Calculate minimum sensitivity from heard packets. + ws_neighbor_class_rf_sensitivity_calculate(rsl); if (ws_neighbor->rsl_in == RSL_UNITITIALIZED) { - ws_neighbor->rsl_in = rssi << WS_RSL_SCALING; + ws_neighbor->rsl_in = rsl << WS_RSL_SCALING; } - ws_neighbor->rsl_in = ws_neighbor->rsl_in + rssi - (ws_neighbor->rsl_in >> WS_RSL_SCALING); + ws_neighbor->rsl_in = ws_neighbor->rsl_in + rsl - (ws_neighbor->rsl_in >> WS_RSL_SCALING); ws_neighbor_class_parent_set_analyze(ws_neighbor); return; } diff --git a/source/6LoWPAN/ws/ws_neighbor_class.h b/source/6LoWPAN/ws/ws_neighbor_class.h index bc86ab70f8..7fa0c9b695 100644 --- a/source/6LoWPAN/ws/ws_neighbor_class.h +++ b/source/6LoWPAN/ws/ws_neighbor_class.h @@ -32,6 +32,9 @@ typedef struct ws_neighbor_class_entry { bool broadcast_timing_info_stored: 1; bool broadcast_shedule_info_stored: 1; bool synch_done : 1; + bool accelerated_etx_probe : 1; + bool negative_aro_send : 1; + bool unicast_data_rx : 1; } ws_neighbor_class_entry_t; /** @@ -134,15 +137,26 @@ void ws_neighbor_class_neighbor_broadcast_time_info_update(ws_neighbor_class_ent void ws_neighbor_class_neighbor_broadcast_schedule_set(ws_neighbor_class_entry_t *ws_neighbor, ws_bs_ie_t *ws_bs_ie); /** - * ws_neighbor_class_rssi_from_dbm_calculate + * ws_neighbor_class_rf_sensitivity_calculate * - * Calculates rssi value from dbm heard taking into account min sensitivity of radio - * dynamically adjusts min sensitivity if value is not properly set + * Calculates minimum heard RSL value from all packets. + * This will dynamically adjusts min sensitivity if value is not properly set + * + * \param rsl_heard; rsl_heard heard from Radio + * + */ +void ws_neighbor_class_rf_sensitivity_calculate(uint8_t rsl_heard); + +/** + * ws_neighbor_class_rsl_from_dbm_calculate + * + * Calculates rsl value from dbm heard. + * This provides a range of -174 (0) to +80 (254) dBm. * * \param dbm_heard; dbm heard from the neighbour * */ -uint8_t ws_neighbor_class_rssi_from_dbm_calculate(int8_t dbm_heard); +uint8_t ws_neighbor_class_rsl_from_dbm_calculate(int8_t dbm_heard); /** Helper macros to read RSL values from neighbour class. * diff --git a/source/6LoWPAN/ws/ws_pae_auth.c b/source/6LoWPAN/ws/ws_pae_auth.c index 78f559696f..ada6267090 100644 --- a/source/6LoWPAN/ws/ws_pae_auth.c +++ b/source/6LoWPAN/ws/ws_pae_auth.c @@ -332,7 +332,7 @@ int8_t ws_pae_auth_node_keys_remove(protocol_interface_info_entry_t *interface_p sec_prot_keys_pmk_delete(&supp->sec_keys); sec_prot_keys_ptk_delete(&supp->sec_keys); supp->access_revoked = true; - tr_info("Access revoked; keys removed, eui-64: %s", trace_array(kmp_address_eui_64_get(supp->addr), 8)); + tr_info("Access revoked; keys removed, eui-64: %s", trace_array(supp->addr.eui_64, 8)); return 0; } @@ -340,7 +340,7 @@ int8_t ws_pae_auth_node_keys_remove(protocol_interface_info_entry_t *interface_p supp = ws_pae_lib_supp_list_entry_eui_64_get(&pae_auth->inactive_supp_list, eui_64); if (supp) { // Deletes supplicant - tr_info("Access revoked; deleted, eui-64: %s", trace_array(kmp_address_eui_64_get(supp->addr), 8)); + tr_info("Access revoked; deleted, eui-64: %s", trace_array(supp->addr.eui_64, 8)); ws_pae_lib_supp_list_remove(&pae_auth->inactive_supp_list, supp); return 0; } @@ -720,8 +720,8 @@ static void ws_pae_auth_kmp_service_addr_get(kmp_service_t *service, kmp_api_t * // Get supplicant address supp_entry_t *entry = kmp_api_data_get(kmp); - if (entry && entry->addr) { - kmp_address_copy(remote_addr, entry->addr); + if (entry) { + kmp_address_copy(remote_addr, &entry->addr); } } @@ -767,7 +767,7 @@ static kmp_api_t *ws_pae_auth_kmp_incoming_ind(kmp_service_t *service, kmp_type_ sec_prot_keys_ptk_eui_64_write(&supp_entry->sec_keys, kmp_address_eui_64_get(addr)); } else { // Updates relay address - kmp_address_copy(supp_entry->addr, addr); + kmp_address_copy(&supp_entry->addr, addr); } // Increases waiting time for supplicant authentication @@ -788,7 +788,7 @@ static kmp_api_t *ws_pae_auth_kmp_incoming_ind(kmp_service_t *service, kmp_type_ kmp_api_data_set(kmp, supp_entry); // Sets address to KMP - kmp_api_addr_set(kmp, supp_entry->addr); + kmp_api_addr_set(kmp, &supp_entry->addr); // Sets security keys to KMP kmp_api_sec_keys_set(kmp, &supp_entry->sec_keys); @@ -862,6 +862,11 @@ static void ws_pae_auth_next_kmp_trigger(pae_auth_t *pae_auth, supp_entry_t *sup if (next_type == KMP_TYPE_NONE) { // All done return; + } else { + if (ws_pae_lib_kmp_list_type_get(&supp_entry->kmp_list, next_type) != NULL) { + tr_info("KMP already ongoing; ignored, eui-64: %s", trace_array(supp_entry->addr.eui_64, 8)); + return; + } } // Increases waiting time for supplicant authentication @@ -877,7 +882,7 @@ static void ws_pae_auth_next_kmp_trigger(pae_auth_t *pae_auth, supp_entry_t *sup uint16_t ongoing_eap_tls_cnt = ws_pae_lib_supp_list_kmp_count(&pae_auth->active_supp_list, IEEE_802_1X_MKA); if (ongoing_eap_tls_cnt >= MAX_SIMULTANEOUS_EAP_TLS_NEGOTIATIONS) { supp_entry->retry_ticks = EAP_TLS_NEGOTIATION_TRIGGER_TIMEOUT; - tr_info("EAP-TLS max ongoing reached, count %i, delayed: eui-64: %s", ongoing_eap_tls_cnt, trace_array(kmp_address_eui_64_get(supp_entry->addr), 8)); + tr_info("EAP-TLS max ongoing reached, count %i, delayed: eui-64: %s", ongoing_eap_tls_cnt, trace_array(supp_entry->addr.eui_64, 8)); return; } } @@ -902,7 +907,7 @@ static void ws_pae_auth_next_kmp_trigger(pae_auth_t *pae_auth, supp_entry_t *sup } } - kmp_api_create_request(new_kmp, next_type, supp_entry->addr, &supp_entry->sec_keys); + kmp_api_create_request(new_kmp, next_type, &supp_entry->addr, &supp_entry->sec_keys); } static kmp_type_e ws_pae_auth_next_protocol_get(supp_entry_t *supp_entry) @@ -915,11 +920,11 @@ static kmp_type_e ws_pae_auth_next_protocol_get(supp_entry_t *supp_entry) sec_keys->ptk_mismatch = true; // start EAP-TLS towards supplicant next_type = IEEE_802_1X_MKA; - tr_info("PAE start EAP-TLS, eui-64: %s", trace_array(kmp_address_eui_64_get(supp_entry->addr), 8)); + tr_info("PAE start EAP-TLS, eui-64: %s", trace_array(supp_entry->addr.eui_64, 8)); } else if (sec_keys->ptk_mismatch) { // start 4WH towards supplicant next_type = IEEE_802_11_4WH; - tr_info("PAE start 4WH, eui-64: %s", trace_array(kmp_address_eui_64_get(supp_entry->addr), 8)); + tr_info("PAE start 4WH, eui-64: %s", trace_array(supp_entry->addr.eui_64, 8)); } int8_t gtk_index = -1; @@ -937,14 +942,14 @@ static kmp_type_e ws_pae_auth_next_protocol_get(supp_entry_t *supp_entry) if (next_type == KMP_TYPE_NONE && gtk_index >= 0) { // Update just GTK next_type = IEEE_802_11_GKH; - tr_info("PAE start GKH, eui-64: %s", trace_array(kmp_address_eui_64_get(supp_entry->addr), 8)); + tr_info("PAE start GKH, eui-64: %s", trace_array(supp_entry->addr.eui_64, 8)); } - tr_info("PAE update GTK index: %i, eui-64: %s", gtk_index, trace_array(kmp_address_eui_64_get(supp_entry->addr), 8)); + tr_info("PAE update GTK index: %i, eui-64: %s", gtk_index, trace_array(supp_entry->addr.eui_64, 8)); } if (next_type == KMP_TYPE_NONE) { - tr_info("PAE authenticated, eui-64: %s", trace_array(kmp_address_eui_64_get(supp_entry->addr), 8)); + tr_info("PAE authenticated, eui-64: %s", trace_array(supp_entry->addr.eui_64, 8)); } return next_type; @@ -1004,7 +1009,7 @@ static void ws_pae_auth_kmp_api_finished(kmp_api_t *kmp) ws_pae_lib_kmp_list_delete(&supp_entry->kmp_list, kmp); if (retry_supp) { - tr_info("PAE next KMP trigger, eui-64: %s", trace_array(kmp_address_eui_64_get(retry_supp->addr), 8)); + tr_info("PAE next KMP trigger, eui-64: %s", trace_array(retry_supp->addr.eui_64, 8)); ws_pae_auth_next_kmp_trigger(pae_auth, retry_supp); } diff --git a/source/6LoWPAN/ws/ws_pae_controller.c b/source/6LoWPAN/ws/ws_pae_controller.c index a00dbd3b71..c001c2364a 100644 --- a/source/6LoWPAN/ws/ws_pae_controller.c +++ b/source/6LoWPAN/ws/ws_pae_controller.c @@ -31,6 +31,8 @@ #include "6LoWPAN/ws/ws_pae_timers.h" #include "6LoWPAN/ws/ws_pae_supp.h" #include "6LoWPAN/ws/ws_pae_auth.h" +#include "6LoWPAN/ws/ws_pae_nvm_store.h" +#include "6LoWPAN/ws/ws_pae_nvm_data.h" #include "mbedtls/sha256.h" #ifdef HAVE_WS @@ -51,6 +53,13 @@ typedef struct { bool fresh : 1; /**< Key is fresh i.e. not used on sending */ } nw_key_t; +typedef struct { + uint8_t hash[8]; /**< GTK hash for the frame counter */ + uint32_t frame_counter; /**< Frame counter */ + uint8_t index; /**< Index */ + bool set : 1; /**< Value has been set */ +} stored_frame_counter_t; + typedef struct { ns_list_link_t link; /**< Link */ uint8_t target_eui_64[8]; /**< EAPOL target */ @@ -63,6 +72,8 @@ typedef struct { sec_prot_certs_t certs; /**< Certificates */ nw_key_t nw_key[4]; /**< Currently active network keys (on MAC) */ char *network_name; /**< Network name for GAK generation */ + uint16_t frame_cnt_store_timer; /**< Timer for storing frame counter value */ + stored_frame_counter_t stored_frame_counter; /**< Stored frame counter */ timer_settings_t timer_settings; /**< Timer settings */ protocol_interface_info_entry_t *interface_ptr; /**< List link entry */ ws_pae_controller_auth_completed *auth_completed; /**< Authentication completed callback, continue bootstrap */ @@ -70,6 +81,7 @@ typedef struct { ws_pae_controller_nw_key_clear *nw_key_clear; /**< Key clear callback */ ws_pae_controller_nw_send_key_index_set *nw_send_key_index_set; /**< Send key index set callback */ ws_pae_controller_nw_frame_counter_set *nw_frame_counter_set; /**< Frame counter set callback */ + ws_pae_controller_nw_frame_counter_read *nw_frame_counter_read; /**< Frame counter read callback */ ws_pae_controller_pan_ver_increment *pan_ver_increment; /**< PAN version increment callback */ ws_pae_delete *pae_delete; /**< PAE delete callback */ ws_pae_timer *pae_fast_timer; /**< PAE fast timer callback */ @@ -79,12 +91,17 @@ typedef struct { ws_pae_gtks_updated *pae_gtks_updated; /**< PAE GTKs updated */ ws_pae_gtk_hash_update *pae_gtk_hash_update; /**< PAE GTK HASH update */ ws_pae_nw_key_index_update *pae_nw_key_index_update; /**< PAE NW key index update */ + nvm_tlv_entry_t *pae_nvm_buffer; /**< Buffer For PAE NVM write operation*/ bool gtks_set : 1; /**< GTKs are set */ bool gtkhash_set : 1; /**< GTK hashes are set */ bool key_index_set : 1; /**< NW key index is set */ } pae_controller_t; static pae_controller_t *ws_pae_controller_get(protocol_interface_info_entry_t *interface_ptr); +static void ws_pae_controller_frame_counter_timer(uint16_t seconds, pae_controller_t *entry); +static void ws_pae_controller_frame_counter_store(pae_controller_t *entry); +static void ws_pae_controller_nvm_frame_counter_write(nvm_tlv_entry_t *tlv_entry); +static int8_t ws_pae_controller_nvm_frame_counter_read(uint8_t *index, uint8_t *hash, uint32_t *frame_counter); static pae_controller_t *ws_pae_controller_get_or_create(int8_t interface_id); static void ws_pae_controller_gtk_hash_set(protocol_interface_info_entry_t *interface_ptr, uint8_t *gtkhash); static int8_t ws_pae_controller_nw_key_check_and_insert(protocol_interface_info_entry_t *interface_ptr, sec_prot_gtk_keys_t *gtks); @@ -93,6 +110,12 @@ static void ws_pae_controller_active_nw_key_set(protocol_interface_info_entry_t static int8_t ws_pae_controller_gak_from_gtk(uint8_t *gak, uint8_t *gtk, char *network_name); static void ws_pae_controller_nw_key_index_check_and_set(protocol_interface_info_entry_t *interface_ptr, uint8_t index); static void ws_pae_controller_data_init(pae_controller_t *controller); +static void ws_pae_controller_frame_counter_read(pae_controller_t *controller); +static void ws_pae_controller_frame_counter_reset(stored_frame_counter_t *counter); +static uint32_t ws_pae_controller_frame_counter_get(stored_frame_counter_t *counter, uint8_t index, uint8_t *key_hash); +static void ws_pae_controller_frame_counter_write(pae_controller_t *controller, uint8_t index, uint8_t *key_hash, uint32_t curr_counter); + +static const char *FRAME_COUNTER_FILE = FRAME_COUNTER_FILE_NAME; static NS_LIST_DEFINE(pae_controller_list, pae_controller_t, link); @@ -188,7 +211,7 @@ int8_t ws_pae_controller_authenticator_start(protocol_interface_info_entry_t *in return 0; } -int8_t ws_pae_controller_cb_register(protocol_interface_info_entry_t *interface_ptr, ws_pae_controller_auth_completed *completed, ws_pae_controller_nw_key_set *nw_key_set, ws_pae_controller_nw_key_clear *nw_key_clear, ws_pae_controller_nw_send_key_index_set *nw_send_key_index_set, ws_pae_controller_nw_frame_counter_set *nw_frame_counter_set, ws_pae_controller_pan_ver_increment *pan_ver_increment) +int8_t ws_pae_controller_cb_register(protocol_interface_info_entry_t *interface_ptr, ws_pae_controller_auth_completed *completed, ws_pae_controller_nw_key_set *nw_key_set, ws_pae_controller_nw_key_clear *nw_key_clear, ws_pae_controller_nw_send_key_index_set *nw_send_key_index_set, ws_pae_controller_nw_frame_counter_set *nw_frame_counter_set, ws_pae_controller_nw_frame_counter_read *nw_frame_counter_read, ws_pae_controller_pan_ver_increment *pan_ver_increment) { if (!interface_ptr) { return -1; @@ -204,6 +227,7 @@ int8_t ws_pae_controller_cb_register(protocol_interface_info_entry_t *interface_ controller->nw_key_clear = nw_key_clear; controller->nw_send_key_index_set = nw_send_key_index_set; controller->nw_frame_counter_set = nw_frame_counter_set; + controller->nw_frame_counter_read = nw_frame_counter_read; controller->pan_ver_increment = pan_ver_increment; return 0; @@ -422,7 +446,12 @@ static void ws_pae_controller_nw_key_index_check_and_set(protocol_interface_info if (controller->nw_send_key_index_set) { tr_info("NW send key index set: %i", index + 1); controller->nw_send_key_index_set(interface_ptr, index); - controller->nw_frame_counter_set(interface_ptr, 0); + controller->gtk_index = index; + + uint32_t frame_counter = ws_pae_controller_frame_counter_get(&controller->stored_frame_counter, index, controller->nw_key[index].hash); + controller->nw_frame_counter_set(interface_ptr, frame_counter); + tr_info("NW frame counter set: %"PRIu32"", frame_counter); + ws_pae_controller_frame_counter_write(controller, index, controller->nw_key[index].hash, frame_counter); } // Do not update PAN version for initial key index set @@ -444,10 +473,14 @@ static void ws_pae_controller_active_nw_key_set(protocol_interface_info_entry_t if (controller->nw_send_key_index_set) { controller->nw_send_key_index_set(controller->interface_ptr, index); + tr_info("NW send key index set: %i", index + 1); - // If index has changed and the key for the index is fresh reset frame counter + // If index has changed and the key for the index is fresh get frame counter if (controller->gtk_index != index && controller->nw_key[index].fresh) { - controller->nw_frame_counter_set(cur, 0); + uint32_t frame_counter = ws_pae_controller_frame_counter_get(&controller->stored_frame_counter, index, controller->nw_key[index].hash); + controller->nw_frame_counter_set(cur, frame_counter); + tr_info("NW frame counter set: %"PRIu32"", frame_counter); + ws_pae_controller_frame_counter_write(controller, index, controller->nw_key[index].hash, frame_counter); } controller->gtk_index = index; @@ -466,7 +499,11 @@ int8_t ws_pae_controller_init(protocol_interface_info_entry_t *interface_ptr) } pae_controller_t *controller = ns_dyn_mem_alloc(sizeof(pae_controller_t)); - if (!controller) { + void *pae_nvm_buffer = ws_pae_buffer_allocate(); + + if (!controller || !pae_nvm_buffer) { + ns_dyn_mem_free(controller); + ns_dyn_mem_free(pae_nvm_buffer); return -1; } @@ -477,6 +514,7 @@ int8_t ws_pae_controller_init(protocol_interface_info_entry_t *interface_ptr) controller->nw_send_key_index_set = NULL; controller->nw_frame_counter_set = NULL; controller->pan_ver_increment = NULL; + controller->pae_nvm_buffer = pae_nvm_buffer; ws_pae_controller_data_init(controller); @@ -510,12 +548,62 @@ static void ws_pae_controller_data_init(pae_controller_t *controller) controller->key_index_set = false; controller->gtk_index = -1; controller->network_name = NULL; + controller->frame_cnt_store_timer = FRAME_COUNTER_STORE_INTERVAL; + ws_pae_controller_frame_counter_reset(&controller->stored_frame_counter); sec_prot_keys_gtks_init(&controller->gtks); sec_prot_keys_gtks_init(&controller->next_gtks); sec_prot_certs_init(&controller->certs); ws_pae_timers_settings_init(&controller->timer_settings); } +static void ws_pae_controller_frame_counter_read(pae_controller_t *controller) +{ + stored_frame_counter_t *counter = &controller->stored_frame_counter; + // If not already, read frame counter and check if index and hash matches + if (!counter->set && ws_pae_controller_nvm_frame_counter_read(&counter->index, counter->hash, &counter->frame_counter) >= 0) { + counter->frame_counter += FRAME_COUNTER_INCREMENT; + counter->set = true; + tr_debug("Read frame counter: %"PRIu32", index %i, hash %s, system time: %"PRIu32"", counter->frame_counter, counter->index, trace_array(counter->hash, 8), protocol_core_monotonic_time / 10); + // Write incremented frame counter + ws_pae_nvm_store_frame_counter_tlv_create(controller->pae_nvm_buffer, counter->index, counter->hash, counter->frame_counter); + ws_pae_controller_nvm_frame_counter_write(controller->pae_nvm_buffer); + } +} + +static void ws_pae_controller_frame_counter_reset(stored_frame_counter_t *counter) +{ + memset(counter->hash, 0, GTK_HASH_LEN); + counter->frame_counter = 0; + counter->index = -1; + counter->set = false; +} + +static uint32_t ws_pae_controller_frame_counter_get(stored_frame_counter_t *counter, uint8_t index, uint8_t *key_hash) +{ + uint32_t frame_counter = 0; + // If both index and hash matches uses the stored frame counter + if (counter->set && counter->index == index && memcmp(counter->hash, key_hash, GTK_HASH_LEN) == 0) { + frame_counter = counter->frame_counter; + } + + return frame_counter; +} + +static void ws_pae_controller_frame_counter_write(pae_controller_t *controller, uint8_t index, uint8_t *key_hash, uint32_t curr_frame_counter) +{ + stored_frame_counter_t *counter = &controller->stored_frame_counter; + // If index or hash changes, or frame counter has been incremented by the threshold updates frame counter + if (!counter->set || counter->index != index || memcmp(key_hash, counter->hash, 8) != 0 || curr_frame_counter > counter->frame_counter + FRAME_COUNTER_STORE_THRESHOLD) { + ws_pae_nvm_store_frame_counter_tlv_create(controller->pae_nvm_buffer, index, key_hash, curr_frame_counter); + ws_pae_controller_nvm_frame_counter_write(controller->pae_nvm_buffer); + counter->index = index; + counter->frame_counter = curr_frame_counter; + memcpy(counter->hash, key_hash, GTK_HASH_LEN); + counter->set = true; + tr_debug("Stored frame counter: %"PRIu32", index %i, hash %s, system time: %"PRIu32"", curr_frame_counter, index, trace_array(key_hash, 8), protocol_core_monotonic_time / 10); + } +} + int8_t ws_pae_controller_supp_init(protocol_interface_info_entry_t *interface_ptr) { pae_controller_t *controller = ws_pae_controller_get(interface_ptr); @@ -537,6 +625,8 @@ int8_t ws_pae_controller_supp_init(protocol_interface_info_entry_t *interface_pt ws_pae_supp_cb_register(controller->interface_ptr, controller->auth_completed, ws_pae_controller_nw_key_check_and_insert, ws_pae_controller_active_nw_key_set); + ws_pae_controller_frame_counter_read(controller); + return 0; } @@ -557,8 +647,11 @@ int8_t ws_pae_controller_auth_init(protocol_interface_info_entry_t *interface_pt controller->pae_gtks_updated = ws_pae_auth_gtks_updated; controller->pae_nw_key_index_update = ws_pae_auth_nw_key_index_update; + ws_pae_controller_frame_counter_read(controller); + return 0; } + int8_t ws_pae_controller_stop(protocol_interface_info_entry_t *interface_ptr) { pae_controller_t *controller = ws_pae_controller_get(interface_ptr); @@ -566,6 +659,9 @@ int8_t ws_pae_controller_stop(protocol_interface_info_entry_t *interface_ptr) return -1; } + // Stores frame counter + ws_pae_controller_frame_counter_store(controller); + // If PAE has been initialized, deletes it if (controller->pae_delete) { controller->pae_delete(interface_ptr); @@ -594,6 +690,7 @@ int8_t ws_pae_controller_delete(protocol_interface_info_entry_t *interface_ptr) } ns_list_remove(&pae_controller_list, controller); + ns_dyn_mem_free(controller->pae_nvm_buffer); ns_dyn_mem_free(controller); return 0; @@ -959,9 +1056,58 @@ void ws_pae_controller_slow_timer(uint16_t seconds) if (entry->pae_slow_timer) { entry->pae_slow_timer(seconds); } + + ws_pae_controller_frame_counter_timer(seconds, entry); } } +static void ws_pae_controller_frame_counter_timer(uint16_t seconds, pae_controller_t *entry) +{ + if (entry->frame_cnt_store_timer > seconds) { + entry->frame_cnt_store_timer -= seconds; + } else { + entry->frame_cnt_store_timer = FRAME_COUNTER_STORE_INTERVAL; + ws_pae_controller_frame_counter_store(entry); + } +} + +static void ws_pae_controller_frame_counter_store(pae_controller_t *entry) +{ + // Gets index of active GTK + int8_t active_index = entry->gtk_index; + + if (active_index >= 0) { + // Gets hash of the key + uint8_t *hash = entry->nw_key[active_index].hash; + + uint32_t curr_frame_counter; + entry->nw_frame_counter_read(entry->interface_ptr, &curr_frame_counter); + ws_pae_controller_frame_counter_write(entry, active_index, hash, curr_frame_counter); + } +} + + +static int8_t ws_pae_controller_nvm_frame_counter_read(uint8_t *index, uint8_t *hash, uint32_t *frame_counter) +{ + nvm_tlv_list_t tlv_list; + ns_list_init(&tlv_list); + + if (ws_pae_nvm_store_tlv_file_read(FRAME_COUNTER_FILE, &tlv_list) < 0) { + return -1; + } + + int8_t result = -1; + ns_list_foreach_safe(nvm_tlv_entry_t, entry, &tlv_list) { + if (ws_pae_nvm_store_frame_counter_tlv_read(entry, index, hash, frame_counter) >= 0) { + result = 0; + } + ns_list_remove(&tlv_list, entry); + ns_dyn_mem_free(entry); + } + + return result; +} + static pae_controller_t *ws_pae_controller_get(protocol_interface_info_entry_t *interface_ptr) { ns_list_foreach(pae_controller_t, entry, &pae_controller_list) { @@ -992,5 +1138,24 @@ static pae_controller_t *ws_pae_controller_get_or_create(int8_t interface_id) return controller; } +nvm_tlv_entry_t *ws_pae_controller_nvm_tlv_get(protocol_interface_info_entry_t *interface_ptr) +{ + pae_controller_t *controller = ws_pae_controller_get(interface_ptr); + if (!controller) { + return NULL; + } + + return controller->pae_nvm_buffer; +} + +static void ws_pae_controller_nvm_frame_counter_write(nvm_tlv_entry_t *tlv_entry) +{ + nvm_tlv_list_t tlv_list; + ns_list_init(&tlv_list); + ns_list_add_to_end(&tlv_list, tlv_entry); + ws_pae_nvm_store_tlv_file_write(FRAME_COUNTER_FILE, &tlv_list); + +} + #endif /* HAVE_WS */ diff --git a/source/6LoWPAN/ws/ws_pae_controller.h b/source/6LoWPAN/ws/ws_pae_controller.h index c7d75d3610..2f1b6ce050 100644 --- a/source/6LoWPAN/ws/ws_pae_controller.h +++ b/source/6LoWPAN/ws/ws_pae_controller.h @@ -20,6 +20,7 @@ #ifdef HAVE_WS +struct nvm_tlv_entry; /** * ws_pae_controller_set_target sets EAPOL target for PAE supplicant * @@ -384,6 +385,15 @@ typedef void ws_pae_controller_nw_send_key_index_set(protocol_interface_info_ent */ typedef void ws_pae_controller_nw_frame_counter_set(protocol_interface_info_entry_t *interface_ptr, uint32_t counter); +/** + * ws_pae_controller_nw_frame_counter_read network frame counter read callback + * + * \param interface_ptr interface + * \param counter frame counter + * + */ +typedef void ws_pae_controller_nw_frame_counter_read(protocol_interface_info_entry_t *interface_ptr, uint32_t *counter); + /** * ws_pae_controller_auth_completed authentication completed callback * @@ -410,13 +420,14 @@ typedef void ws_pae_controller_pan_ver_increment(protocol_interface_info_entry_t * \param nw_key_clear network key clear callback * \param nw_send_key_index_set network send key index set callback * \param nw_frame_counter_set network frame counter set callback + * \param nw_frame_counter_read network frame counter read callback * \param pan_ver_increment PAN version increment callback * * \return < 0 failure * \return >= 0 success * */ -int8_t ws_pae_controller_cb_register(protocol_interface_info_entry_t *interface_ptr, ws_pae_controller_auth_completed *completed, ws_pae_controller_nw_key_set *nw_key_set, ws_pae_controller_nw_key_clear *nw_key_clear, ws_pae_controller_nw_send_key_index_set *nw_send_key_index_set, ws_pae_controller_nw_frame_counter_set *nw_frame_counter_set, ws_pae_controller_pan_ver_increment *pan_ver_increment); +int8_t ws_pae_controller_cb_register(protocol_interface_info_entry_t *interface_ptr, ws_pae_controller_auth_completed *completed, ws_pae_controller_nw_key_set *nw_key_set, ws_pae_controller_nw_key_clear *nw_key_clear, ws_pae_controller_nw_send_key_index_set *nw_send_key_index_set, ws_pae_controller_nw_frame_counter_set *nw_frame_counter_set, ws_pae_controller_nw_frame_counter_read *nw_frame_counter_read, ws_pae_controller_pan_ver_increment *pan_ver_increment); /** * ws_pae_controller_fast_timer PAE controller fast timer call @@ -435,6 +446,8 @@ void ws_pae_controller_fast_timer(uint16_t ticks); */ void ws_pae_controller_slow_timer(uint16_t seconds); +struct nvm_tlv_entry *ws_pae_controller_nvm_tlv_get(protocol_interface_info_entry_t *interface_ptr); + #else #define ws_pae_controller_set_target(interface_ptr, target_pan_id, target_dest_eui_64) @@ -455,6 +468,7 @@ void ws_pae_controller_slow_timer(uint16_t seconds); #define ws_pae_controller_stop(interface_ptr) #define ws_pae_controller_delete(interface_ptr) #define ws_pae_controller_cb_register(interface_ptr, completed, nw_key_set, nw_key_clear, nw_send_key_index_set, pan_ver_increment) 1 +#define ws_pae_controller_nvm_tlv_get(interface_ptr) NULL #endif diff --git a/source/6LoWPAN/ws/ws_pae_lib.c b/source/6LoWPAN/ws/ws_pae_lib.c index 13d311f8f4..6886a71408 100644 --- a/source/6LoWPAN/ws/ws_pae_lib.c +++ b/source/6LoWPAN/ws/ws_pae_lib.c @@ -156,9 +156,9 @@ supp_entry_t *ws_pae_lib_supp_list_add(supp_list_t *supp_list, const kmp_addr_t } ws_pae_lib_supp_init(entry); - - entry->addr = kmp_address_create(KMP_ADDR_EUI_64_AND_IP, 0); - kmp_address_copy(entry->addr, addr); + memset(&entry->addr, 0, sizeof(kmp_addr_t)); + entry->addr.type = KMP_ADDR_EUI_64_AND_IP; + kmp_address_copy(&entry->addr, addr); ns_list_add_to_end(supp_list, entry); @@ -178,7 +178,7 @@ int8_t ws_pae_lib_supp_list_remove(supp_list_t *supp_list, supp_entry_t *supp) supp_entry_t *ws_pae_lib_supp_list_entry_eui_64_get(const supp_list_t *supp_list, const uint8_t *eui_64) { ns_list_foreach(supp_entry_t, cur, supp_list) { - if (memcmp(kmp_address_eui_64_get(cur->addr), eui_64, 8) == 0) { + if (memcmp(cur->addr.eui_64, eui_64, 8) == 0) { return cur; } } @@ -213,10 +213,10 @@ void ws_pae_lib_supp_list_slow_timer_update(supp_list_t *supp_list, timer_settin { ns_list_foreach(supp_entry_t, entry, supp_list) { if (sec_prot_keys_pmk_lifetime_decrement(&entry->sec_keys, timer_settings->pmk_lifetime, seconds)) { - tr_info("PMK and PTK expired, eui-64: %s, system time: %"PRIu32"", trace_array(kmp_address_eui_64_get(entry->addr), 8), protocol_core_monotonic_time / 10); + tr_info("PMK and PTK expired, eui-64: %s, system time: %"PRIu32"", trace_array(entry->addr.eui_64, 8), protocol_core_monotonic_time / 10); } if (sec_prot_keys_ptk_lifetime_decrement(&entry->sec_keys, timer_settings->ptk_lifetime, seconds)) { - tr_info("PTK expired, eui-64: %s, system time: %"PRIu32"", trace_array(kmp_address_eui_64_get(entry->addr), 8), protocol_core_monotonic_time / 10); + tr_info("PTK expired, eui-64: %s, system time: %"PRIu32"", trace_array(entry->addr.eui_64, 8), protocol_core_monotonic_time / 10); } } @@ -225,7 +225,7 @@ void ws_pae_lib_supp_list_slow_timer_update(supp_list_t *supp_list, timer_settin void ws_pae_lib_supp_init(supp_entry_t *entry) { ws_pae_lib_kmp_list_init(&entry->kmp_list); - entry->addr = 0; + memset(&entry->addr, 0, sizeof(kmp_addr_t)); memset(&entry->sec_keys, 0, sizeof(sec_prot_keys_t)); entry->ticks = 0; entry->retry_ticks = 0; @@ -236,7 +236,6 @@ void ws_pae_lib_supp_init(supp_entry_t *entry) void ws_pae_lib_supp_delete(supp_entry_t *entry) { ws_pae_lib_kmp_list_free(&entry->kmp_list); - kmp_address_delete(entry->addr); } bool ws_pae_lib_supp_timer_update(supp_entry_t *entry, uint16_t ticks, ws_pae_lib_kmp_timer_timeout timeout) @@ -260,7 +259,7 @@ bool ws_pae_lib_supp_timer_update(supp_entry_t *entry, uint16_t ticks, ws_pae_li entry->retry_ticks -= ticks; } else { if (entry->retry_ticks > 0) { - tr_info("EAP-TLS max ongoing delay timeout eui-64: %s", trace_array(kmp_address_eui_64_get(entry->addr), 8)); + tr_info("EAP-TLS max ongoing delay timeout eui-64: %s", trace_array(entry->addr.eui_64, 8)); } entry->retry_ticks = 0; } @@ -279,7 +278,7 @@ void ws_pae_lib_supp_list_to_active(supp_list_t *active_supp_list, supp_list_t * return; } - tr_debug("PAE: to active, eui-64: %s", trace_array(kmp_address_eui_64_get(entry->addr), 8)); + tr_debug("PAE: to active, eui-64: %s", trace_array(entry->addr.eui_64, 8)); ns_list_remove(inactive_supp_list, entry); ns_list_add_to_start(active_supp_list, entry); @@ -288,9 +287,7 @@ void ws_pae_lib_supp_list_to_active(supp_list_t *active_supp_list, supp_list_t * entry->ticks = 0; // Adds relay address data - kmp_addr_t *addr = kmp_address_create(KMP_ADDR_EUI_64_AND_IP, kmp_address_eui_64_get(entry->addr)); - kmp_address_delete(entry->addr); - entry->addr = addr; + entry->addr.type = KMP_ADDR_EUI_64_AND_IP; } void ws_pae_lib_supp_list_to_inactive(supp_list_t *active_supp_list, supp_list_t *inactive_supp_list, supp_entry_t *entry) @@ -299,10 +296,10 @@ void ws_pae_lib_supp_list_to_inactive(supp_list_t *active_supp_list, supp_list_t return; } - tr_debug("PAE: to inactive, eui-64: %s", trace_array(kmp_address_eui_64_get(entry->addr), 8)); + tr_debug("PAE: to inactive, eui-64: %s", trace_array(entry->addr.eui_64, 8)); if (entry->access_revoked) { - tr_info("Access revoked; deleted, eui-64: %s", trace_array(kmp_address_eui_64_get(entry->addr), 8)); + tr_info("Access revoked; deleted, eui-64: %s", trace_array(entry->addr.eui_64, 8)); ws_pae_lib_supp_list_remove(active_supp_list, entry); return; } @@ -314,9 +311,9 @@ void ws_pae_lib_supp_list_to_inactive(supp_list_t *active_supp_list, supp_list_t entry->ticks = 0; // Removes relay address data - kmp_addr_t *addr = kmp_address_create(KMP_ADDR_EUI_64, kmp_address_eui_64_get(entry->addr)); - kmp_address_delete(entry->addr); - entry->addr = addr; + entry->addr.type = KMP_ADDR_EUI_64; + entry->addr.port = 0; + memset(entry->addr.relay_address, 0, 16); } uint16_t ws_pae_lib_supp_list_kmp_count(supp_list_t *supp_list, kmp_type_e type) diff --git a/source/6LoWPAN/ws/ws_pae_lib.h b/source/6LoWPAN/ws/ws_pae_lib.h index a9d239b950..2569637dee 100644 --- a/source/6LoWPAN/ws/ws_pae_lib.h +++ b/source/6LoWPAN/ws/ws_pae_lib.h @@ -33,7 +33,7 @@ typedef NS_LIST_HEAD(kmp_entry_t, link) kmp_list_t; typedef struct { kmp_list_t kmp_list; /**< Ongoing KMP negotiations */ - kmp_addr_t *addr; /**< EUI-64 (Relay IP address, Relay port) */ + kmp_addr_t addr; /**< EUI-64 (Relay IP address, Relay port) */ sec_prot_keys_t sec_keys; /**< Security keys */ uint32_t ticks; /**< Ticks */ uint16_t retry_ticks; /**< Retry ticks */ diff --git a/source/6LoWPAN/ws/ws_pae_nvm_data.c b/source/6LoWPAN/ws/ws_pae_nvm_data.c index bf07505771..7cb2f42af8 100644 --- a/source/6LoWPAN/ws/ws_pae_nvm_data.c +++ b/source/6LoWPAN/ws/ws_pae_nvm_data.c @@ -35,6 +35,7 @@ #define PAE_NVM_NW_INFO_TAG 1 #define PAE_NVM_KEYS_TAG 2 +#define PAE_NVM_FRAME_COUNTER_TAG 3 // pan_id (2) + network name (33) + (GTK set (1) + GTK lifetime (4) + GTK (16)) * 4 #define PAE_NVM_NW_INFO_LEN 2 + 33 + (1 + 4 + GTK_LEN) * GTK_NUM @@ -42,12 +43,17 @@ // PTK EUI-64 set (1) + PTK EUI-64 (8) + PMK set (1) + PMK (32) + PMK replay counter (8) + PTK set (1) + PTK (48) #define PAE_NVM_KEYS_LEN 1 + 8 + 1 + PMK_LEN + 8 + 1 + PTK_LEN -nvm_tlv_entry_t *ws_pae_nvm_store_nw_info_tlv_create(uint16_t pan_id, char *nw_name, sec_prot_gtk_keys_t *gtks) +// GTK hash (8), frame counter (4), index (1) +#define PAE_NVM_FRAME_COUNTER_LEN 8 + 4 + 1 + +nvm_tlv_entry_t *ws_pae_buffer_allocate(void) +{ + //Allocate worts case buffer + return ns_dyn_mem_temporary_alloc(sizeof(nvm_tlv_entry_t) + PAE_NVM_NW_INFO_LEN); +} + +void ws_pae_nvm_store_nw_info_tlv_create(nvm_tlv_entry_t *tlv_entry, uint16_t pan_id, char *nw_name, sec_prot_gtk_keys_t *gtks) { - nvm_tlv_entry_t *tlv_entry = ns_dyn_mem_temporary_alloc(sizeof(nvm_tlv_entry_t) + PAE_NVM_NW_INFO_LEN); - if (!tlv_entry) { - return NULL; - } tlv_entry->tag = PAE_NVM_NW_INFO_TAG; tlv_entry->len = PAE_NVM_NW_INFO_LEN; @@ -78,7 +84,6 @@ nvm_tlv_entry_t *ws_pae_nvm_store_nw_info_tlv_create(uint16_t pan_id, char *nw_n tr_debug("NVM NW_INFO write PAN ID %i name: %s", pan_id, nw_name); - return tlv_entry; } int8_t ws_pae_nvm_store_nw_info_tlv_read(nvm_tlv_entry_t *tlv_entry, uint16_t *pan_id, char *nw_name, sec_prot_gtk_keys_t *gtks) @@ -117,13 +122,8 @@ int8_t ws_pae_nvm_store_nw_info_tlv_read(nvm_tlv_entry_t *tlv_entry, uint16_t *p return 0; } -nvm_tlv_entry_t *ws_pae_nvm_store_keys_tlv_create(sec_prot_keys_t *sec_keys) +void ws_pae_nvm_store_keys_tlv_create(nvm_tlv_entry_t *tlv_entry, sec_prot_keys_t *sec_keys) { - nvm_tlv_entry_t *tlv_entry = ns_dyn_mem_temporary_alloc(sizeof(nvm_tlv_entry_t) + PAE_NVM_KEYS_LEN); - if (!tlv_entry) { - return NULL; - } - tlv_entry->tag = PAE_NVM_KEYS_TAG; tlv_entry->len = PAE_NVM_KEYS_LEN; @@ -164,7 +164,6 @@ nvm_tlv_entry_t *ws_pae_nvm_store_keys_tlv_create(sec_prot_keys_t *sec_keys) tr_debug("NVM KEYS write"); - return tlv_entry; } int8_t ws_pae_nvm_store_keys_tlv_read(nvm_tlv_entry_t *tlv_entry, sec_prot_keys_t *sec_keys) @@ -209,5 +208,44 @@ int8_t ws_pae_nvm_store_keys_tlv_read(nvm_tlv_entry_t *tlv_entry, sec_prot_keys_ return 0; } +void ws_pae_nvm_store_frame_counter_tlv_create(nvm_tlv_entry_t *tlv_entry, uint8_t index, uint8_t *hash, uint32_t frame_counter) +{ + + tlv_entry->tag = PAE_NVM_FRAME_COUNTER_TAG; + tlv_entry->len = PAE_NVM_FRAME_COUNTER_LEN; + + uint8_t *tlv = ((uint8_t *) &tlv_entry->tag) + NVM_TLV_FIXED_LEN; + + memcpy(tlv, hash, GTK_HASH_LEN); + tlv += GTK_HASH_LEN; + tlv = common_write_32_bit(frame_counter, tlv); + *tlv = index; + + tr_debug("NVM FRAME COUNTER write"); +} + +int8_t ws_pae_nvm_store_frame_counter_tlv_read(nvm_tlv_entry_t *tlv_entry, uint8_t *index, uint8_t *hash, uint32_t *frame_counter) +{ + if (!tlv_entry || !frame_counter) { + return -1; + } + + if (tlv_entry->tag != PAE_NVM_FRAME_COUNTER_TAG || tlv_entry->len != PAE_NVM_FRAME_COUNTER_LEN) { + return -1; + } + + uint8_t *tlv = ((uint8_t *) &tlv_entry->tag) + NVM_TLV_FIXED_LEN; + + memcpy(hash, tlv, GTK_HASH_LEN); + tlv += GTK_HASH_LEN; + *frame_counter = common_read_32_bit(tlv); + tlv += 4; + *index = *tlv; + + tr_debug("NVM FRAME COUNTER read"); + + return 0; +} + #endif /* HAVE_WS */ diff --git a/source/6LoWPAN/ws/ws_pae_nvm_data.h b/source/6LoWPAN/ws/ws_pae_nvm_data.h index 109017a700..ce763d7844 100644 --- a/source/6LoWPAN/ws/ws_pae_nvm_data.h +++ b/source/6LoWPAN/ws/ws_pae_nvm_data.h @@ -27,6 +27,7 @@ /** * ws_pae_nvm_store_nw_info_tlv_create create NVM network info TLV * + * \param tlv_entry TLV entry pointer * \param pan_id PAN ID * \param nw_name network name * \param gtks GTK keys @@ -34,7 +35,7 @@ * \return TLV entry or NULL * */ -nvm_tlv_entry_t *ws_pae_nvm_store_nw_info_tlv_create(uint16_t pan_id, char *nw_name, sec_prot_gtk_keys_t *gtks); +void ws_pae_nvm_store_nw_info_tlv_create(nvm_tlv_entry_t *tlv_entry, uint16_t pan_id, char *nw_name, sec_prot_gtk_keys_t *gtks); /** * ws_pae_nvm_store_nw_info_tlv_read read from NVM network info TLV @@ -53,12 +54,11 @@ int8_t ws_pae_nvm_store_nw_info_tlv_read(nvm_tlv_entry_t *tlv_entry, uint16_t *p /** * ws_pae_nvm_store_keys_tlv_create create NVM keys TLV * + * \param tlv_entry TLV entry buffer pointer * \param sec_keys security keys * - * \return TLV entry or NULL - * */ -nvm_tlv_entry_t *ws_pae_nvm_store_keys_tlv_create(sec_prot_keys_t *sec_keys); +void ws_pae_nvm_store_keys_tlv_create(nvm_tlv_entry_t *tlv_entry, sec_prot_keys_t *sec_keys); /** * ws_pae_nvm_store_nw_info_tlv_read read from NVM keys TLV @@ -72,4 +72,32 @@ nvm_tlv_entry_t *ws_pae_nvm_store_keys_tlv_create(sec_prot_keys_t *sec_keys); */ int8_t ws_pae_nvm_store_keys_tlv_read(nvm_tlv_entry_t *tlv_entry, sec_prot_keys_t *sec_keys); +/** + * ws_pae_nvm_store_frame_counter_tlv_create create NVM frame counter TLV + * + * \param tlv_entry TLV entry buffer pointer + * \param index index + * \param hash hash + * \param frame_counter frame counter + * + * + */ +void ws_pae_nvm_store_frame_counter_tlv_create(nvm_tlv_entry_t *tlv_entry, uint8_t index, uint8_t *hash, uint32_t frame_counter); + +/** + * ws_pae_nvm_store_frame_counter_tlv_read read from NVM frame counter TLV + * + * \param tlv_entry TLV entry + * \param index index + * \param hash hash + * \param frame_counter frame counter + * + * \return < 0 failure + * \return >= 0 success + * + */ +int8_t ws_pae_nvm_store_frame_counter_tlv_read(nvm_tlv_entry_t *tlv_entry, uint8_t *index, uint8_t *hash, uint32_t *frame_counter); + +nvm_tlv_entry_t *ws_pae_buffer_allocate(void); + #endif /* WS_PAE_NVM_DATA_H_ */ diff --git a/source/6LoWPAN/ws/ws_pae_nvm_store.c b/source/6LoWPAN/ws/ws_pae_nvm_store.c index 1c1b357af9..aa873bdf86 100644 --- a/source/6LoWPAN/ws/ws_pae_nvm_store.c +++ b/source/6LoWPAN/ws/ws_pae_nvm_store.c @@ -193,6 +193,10 @@ static int8_t ws_pae_nvm_store_read(const char *file_name, nvm_tlv_list_t *tlv_l fclose(fp); if (failure) { + ns_list_foreach_safe(nvm_tlv_entry_t, entry, tlv_list) { + ns_list_remove(tlv_list, entry); + ns_dyn_mem_free(entry); + } tr_error("NVM read error %s", file_name); return PAE_NVM_FILE_READ_ERROR; } else { diff --git a/source/6LoWPAN/ws/ws_pae_nvm_store.h b/source/6LoWPAN/ws/ws_pae_nvm_store.h index 130ae73f03..84838ef6f3 100644 --- a/source/6LoWPAN/ws/ws_pae_nvm_store.h +++ b/source/6LoWPAN/ws/ws_pae_nvm_store.h @@ -27,7 +27,12 @@ // tag + length #define NVM_TLV_FIXED_LEN 4 -typedef struct { +// file names +#define NW_INFO_FILE_NAME "pae_nw_info" +#define KEYS_FILE_NAME "pae_keys" +#define FRAME_COUNTER_FILE_NAME "pae_frame_counter" + +typedef struct nvm_tlv_entry { ns_list_link_t link; /**< Link */ uint16_t tag; /**< Unique tag */ uint16_t len; /**< Number of the bytes after the length field */ diff --git a/source/6LoWPAN/ws/ws_pae_supp.c b/source/6LoWPAN/ws/ws_pae_supp.c index fea7d9ce2b..4eea7843cb 100644 --- a/source/6LoWPAN/ws/ws_pae_supp.c +++ b/source/6LoWPAN/ws/ws_pae_supp.c @@ -73,9 +73,6 @@ #define INITIAL_KEY_TIMER_MIN 3 #define INITIAL_KEY_TIMER_MAX 30 -const char *NW_INFO_FILE = "pae_nw_info"; -const char *KEYS_FILE = "pae_keys"; - typedef struct { char network_name[33]; /**< Network name for keys */ sec_prot_gtk_keys_t *gtks; /**< Link to GTKs */ @@ -106,6 +103,7 @@ typedef struct { bool timer_running : 1; /**< Timer is running */ bool new_br_eui_64_set : 1; /**< Border router address has been set */ bool new_br_eui_64_fresh : 1; /**< Border router address is fresh (set during this authentication attempt) */ + bool entry_address_active: 1; } pae_supp_t; @@ -151,6 +149,9 @@ static const eapol_pdu_recv_cb_data_t eapol_pdu_recv_cb_data = { .receive = kmp_eapol_pdu_if_receive }; +static const char *NW_INFO_FILE = NW_INFO_FILE_NAME; +static const char *KEYS_FILE = KEYS_FILE_NAME; + static int8_t tasklet_id = -1; static NS_LIST_DEFINE(pae_supp_list, pae_supp_t, link); @@ -185,7 +186,8 @@ int8_t ws_pae_supp_authenticate(protocol_interface_info_entry_t *interface_ptr, // Stores target/parent address kmp_address_init(KMP_ADDR_EUI_64, &pae_supp->target_addr, dest_eui_64); // Sets target address in use - pae_supp->entry.addr = (kmp_addr_t *) &pae_supp->target_addr; + pae_supp->entry.addr = pae_supp->target_addr; + pae_supp->entry_address_active = true; pae_supp->auth_requested = true; @@ -326,7 +328,6 @@ int8_t ws_pae_supp_nw_key_index_update(protocol_interface_info_entry_t *interfac } if (sec_prot_keys_gtk_status_active_set(&pae_supp->gtks, index) >= 0) { - tr_info("NW send key index set: %i", index + 1); pae_supp->nw_key_index_set(interface_ptr, index); } else { tr_info("NW send key index: %i, no changes", index + 1); @@ -349,21 +350,26 @@ static void ws_pae_supp_nvm_update(pae_supp_t *pae_supp) ws_pae_supp_nvm_keys_write(pae_supp); sec_prot_keys_updated_reset(&pae_supp->entry.sec_keys); } + + } static int8_t ws_pae_supp_nvm_nw_info_write(pae_supp_t *pae_supp) { + nvm_tlv_entry_t *tlv_entry = ws_pae_controller_nvm_tlv_get(pae_supp->interface_ptr); + if (!tlv_entry) { + return -1; + } + nvm_tlv_list_t tlv_list; ns_list_init(&tlv_list); - nvm_tlv_entry_t *tlv_entry = ws_pae_nvm_store_nw_info_tlv_create(pae_supp->sec_keys_nw_info.key_pan_id, - pae_supp->sec_keys_nw_info.network_name, - &pae_supp->gtks); + ws_pae_nvm_store_nw_info_tlv_create(tlv_entry, pae_supp->sec_keys_nw_info.key_pan_id, + pae_supp->sec_keys_nw_info.network_name, + &pae_supp->gtks); ns_list_add_to_end(&tlv_list, tlv_entry); ws_pae_nvm_store_tlv_file_write(NW_INFO_FILE, &tlv_list); - ns_list_remove(&tlv_list, tlv_entry); - ns_dyn_mem_free(tlv_entry); return 0; } @@ -388,15 +394,18 @@ static int8_t ws_pae_supp_nvm_nw_info_read(pae_supp_t *pae_supp) static int8_t ws_pae_supp_nvm_keys_write(pae_supp_t *pae_supp) { + nvm_tlv_entry_t *tlv_entry = ws_pae_controller_nvm_tlv_get(pae_supp->interface_ptr); + if (!tlv_entry) { + return -1; + } + nvm_tlv_list_t tlv_list; ns_list_init(&tlv_list); - nvm_tlv_entry_t *tlv_entry = ws_pae_nvm_store_keys_tlv_create(&pae_supp->entry.sec_keys); + ws_pae_nvm_store_keys_tlv_create(tlv_entry, &pae_supp->entry.sec_keys); ns_list_add_to_end(&tlv_list, tlv_entry); ws_pae_nvm_store_tlv_file_write(KEYS_FILE, &tlv_list); - ns_list_remove(&tlv_list, tlv_entry); - ns_dyn_mem_free(tlv_entry); return 0; } @@ -438,7 +447,7 @@ static int8_t ws_pae_supp_initial_key_send(pae_supp_t *pae_supp) // Stores target/parent address kmp_address_init(KMP_ADDR_EUI_64, &pae_supp->target_addr, parent_eui_64); // Sets parent address in use - pae_supp->entry.addr = (kmp_addr_t *) &pae_supp->target_addr; + pae_supp->entry.addr = pae_supp->target_addr; ws_pae_lib_supp_timer_ticks_set(&pae_supp->entry, WAIT_FOR_REAUTHENTICATION_TICKS); tr_info("PAE wait for auth seconds: %i", WAIT_FOR_REAUTHENTICATION_TICKS / 10); @@ -449,9 +458,9 @@ static int8_t ws_pae_supp_initial_key_send(pae_supp_t *pae_supp) return -1; } - tr_info("EAPOL target: %s", trace_array(kmp_address_eui_64_get(pae_supp->entry.addr), 8)); + tr_info("EAPOL target: %s", trace_array(kmp_address_eui_64_get(&pae_supp->entry.addr), 8)); - kmp_api_create_request(kmp, IEEE_802_1X_MKA_KEY, pae_supp->entry.addr, &pae_supp->entry.sec_keys); + kmp_api_create_request(kmp, IEEE_802_1X_MKA_KEY, &pae_supp->entry.addr, &pae_supp->entry.sec_keys); return 0; } @@ -735,8 +744,7 @@ void ws_pae_supp_fast_timer(uint16_t ticks) tr_debug("PAE idle"); // Sets target/parent address to null - pae_supp->entry.addr = NULL; - + pae_supp->entry_address_active = false; // If not already completed, restart bootstrap ws_pae_supp_authenticate_response(pae_supp, false); @@ -846,8 +854,8 @@ static int8_t ws_pae_supp_eapol_pdu_address_check(protocol_interface_info_entry_ } // Message from EAPOL target node, route to self - if (pae_supp->entry.addr) { - if (memcmp(eui_64, kmp_address_eui_64_get(pae_supp->entry.addr), 8) == 0) { + if (pae_supp->entry_address_active) { + if (memcmp(eui_64, pae_supp->entry.addr.eui_64, 8) == 0) { return 0; } } @@ -945,7 +953,7 @@ static kmp_api_t *ws_pae_supp_kmp_incoming_ind(kmp_service_t *service, kmp_type_ return NULL; } - if (!pae_supp->entry.addr) { + if (!pae_supp->entry_address_active) { // Does no longer wait for authentication, ignores message return NULL; } @@ -954,7 +962,7 @@ static kmp_api_t *ws_pae_supp_kmp_incoming_ind(kmp_service_t *service, kmp_type_ pae_supp->auth_trickle_running = false; // Updates parent address - kmp_address_copy(pae_supp->entry.addr, addr); + kmp_address_copy(&pae_supp->entry.addr, addr); // Check if ongoing kmp_api_t *kmp = ws_pae_lib_kmp_list_type_get(&pae_supp->entry.kmp_list, type); @@ -991,7 +999,7 @@ static kmp_api_t *ws_pae_supp_kmp_create_and_start(kmp_service_t *service, kmp_t } // Updates parent address - kmp_api_addr_set(kmp, pae_supp->entry.addr); + kmp_api_addr_set(kmp, &pae_supp->entry.addr); // Sets security keys to KMP kmp_api_sec_keys_set(kmp, &pae_supp->entry.sec_keys); diff --git a/source/6LoWPAN/ws/ws_stats.c b/source/6LoWPAN/ws/ws_stats.c new file mode 100644 index 0000000000..85f2511221 --- /dev/null +++ b/source/6LoWPAN/ws/ws_stats.c @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2018-2019, Arm Limited and affiliates. + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "nsconfig.h" +#include "ns_types.h" +#include "ns_trace.h" +#include "NWK_INTERFACE/Include/protocol.h" +#include "6LoWPAN/ws/ws_stats.h" +#include "6LoWPAN/ws/ws_common.h" +#include "ws_management_api.h" + +#define TRACE_GROUP "wsst" + +#ifdef HAVE_WS + +int ws_statistics_start(int8_t interface_id, ws_statistics_t *stats_ptr) +{ + if (!stats_ptr) { + return -1; + } + protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(interface_id); + if (!cur || !ws_info(cur)) { + return -1; + } + cur->ws_info->stored_stats_ptr = stats_ptr; + return 0; +} + +int ws_statistics_stop(int8_t interface_id) +{ + protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(interface_id); + if (!cur || !ws_info(cur)) { + return -1; + } + cur->ws_info->stored_stats_ptr = NULL; + return 0; +} + +void ws_stats_update(protocol_interface_info_entry_t *cur, ws_stats_type_t type, uint32_t update_val) +{ + if (!cur || !ws_info(cur)) { + return; + } + ws_statistics_t *stored_stats = cur->ws_info->stored_stats_ptr; + + if (stored_stats) { + switch (type) { + case STATS_WS_ASYNCH_TX: + stored_stats->asynch_tx_count += update_val; + break; + case STATS_WS_ASYNCH_RX: + stored_stats->asynch_rx_count += update_val; + break; + } + } +} +#endif // HAVE_WS diff --git a/source/6LoWPAN/ws/ws_stats.h b/source/6LoWPAN/ws/ws_stats.h new file mode 100644 index 0000000000..8f7776d97d --- /dev/null +++ b/source/6LoWPAN/ws/ws_stats.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2018-2019, Arm Limited and affiliates. + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef WS_STATS_H_ +#define WS_STATS_H_ + +#ifdef HAVE_WS + +typedef enum { + STATS_WS_ASYNCH_TX, + STATS_WS_ASYNCH_RX +} ws_stats_type_t; + +void ws_stats_update(protocol_interface_info_entry_t *cur, ws_stats_type_t type, uint32_t update_val); + +#endif // HAVE_WS + +#endif // WS_STATS_H_ diff --git a/source/Common_Protocols/icmpv6.c b/source/Common_Protocols/icmpv6.c index 3dfac3c936..bcd659f9b9 100644 --- a/source/Common_Protocols/icmpv6.c +++ b/source/Common_Protocols/icmpv6.c @@ -1037,10 +1037,7 @@ buffer_t *icmpv6_up(buffer_t *buf) cur = buf->interface; - if (buf->options.ll_security_bypass_rx) { - tr_debug("ICMP: Drop by EP"); - goto drop; - } + if (data_len < 4) { //tr_debug("Ic1"); @@ -1051,6 +1048,13 @@ buffer_t *icmpv6_up(buffer_t *buf) buf->options.type = *dptr++; buf->options.code = *dptr++; + if (buf->options.ll_security_bypass_rx) { + if (!ws_info(buf->interface) || !(buf->options.type == ICMPV6_TYPE_INFO_RPL_CONTROL && buf->options.code == ICMPV6_CODE_RPL_DIS)) { + //tr_debug("ICMP: Drop by EP"); + goto drop; + } + } + /* Check FCS first */ if (buffer_ipv6_fcf(buf, IPV6_NH_ICMPV6)) { tr_warn("ICMP cksum error!"); @@ -1369,6 +1373,21 @@ void ack_remove_neighbour_cb(struct buffer *buffer_ptr, uint8_t status) } +static void icmpv6_aro_cb(buffer_t *buf, uint8_t status) +{ + uint8_t ll_address[16]; + if (buf->dst_sa.addr_type == ADDR_IPV6) { + /*Full IPv6 address*/ + memcpy(ll_address, buf->dst_sa.address, 16); + } else if (buf->dst_sa.addr_type == ADDR_802_15_4_LONG) { + // Build link local address from long MAC address + memcpy(ll_address, ADDR_LINK_LOCAL_PREFIX, 8); + memcpy(ll_address + 8, &buf->dst_sa.address[2], 8); + ll_address[8] ^= 2; + } + rpl_control_address_register_done(buf->interface, ll_address, status); +} + buffer_t *icmpv6_build_ns(protocol_interface_info_entry_t *cur, const uint8_t target_addr[16], const uint8_t *prompting_src_addr, bool unicast, bool unspecified_source, const aro_t *aro) { if (!cur || addr_is_ipv6_multicast(target_addr)) { @@ -1444,7 +1463,7 @@ buffer_t *icmpv6_build_ns(protocol_interface_info_entry_t *cur, const uint8_t ta /* If ARO Success sending is omitted, MAC ACK is used instead */ /* Setting callback for receiving ACK from adaptation layer */ if (aro && cur->ipv6_neighbour_cache.omit_na_aro_success) { - buf->ack_receive_cb = rpl_control_address_register_done; + buf->ack_receive_cb = icmpv6_aro_cb; } } if (unicast && (!aro && cur->ipv6_neighbour_cache.omit_na)) { @@ -1677,6 +1696,10 @@ buffer_t *icmpv6_build_na(protocol_interface_info_entry_t *cur, bool solicited, } if (ws_info(cur) && aro && aro->status != ARO_SUCCESS) { /*If Aro failed we will kill the neigbour after we have succeeded in sending message*/ + if (!ws_common_negative_aro_mark(cur, aro->eui64)) { + tr_debug("Neighbour removed for negative response send"); + return buffer_free(buf); + } buf->ack_receive_cb = ack_remove_neighbour_cb; } diff --git a/source/Core/include/ns_address_internal.h b/source/Core/include/ns_address_internal.h index 651d15cf2a..cce42c6447 100644 --- a/source/Core/include/ns_address_internal.h +++ b/source/Core/include/ns_address_internal.h @@ -96,8 +96,6 @@ typedef struct if_address_entry { bool temporary: 1; // RFC 4941 temporary address bool tentative: 1; // Tentative address (Duplicate Address Detection running) bool group_added: 1; // Solicited-Node group added - uint8_t addr_reg_pend; // Bitmask for pending address registrations. Based on RPL path control bits - uint8_t addr_reg_done; // Bitmask for address registration done. Based on RPL path control bits if_address_source_t source; // if_address_callback_fn *cb; // Address protocol callback function void *data; // Address protocol data diff --git a/source/Core/include/ns_monitor.h b/source/Core/include/ns_monitor.h new file mode 100644 index 0000000000..6ed6d3a9e4 --- /dev/null +++ b/source/Core/include/ns_monitor.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2019, Arm Limited and affiliates. + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * \file ns_monitor.h + * \brief Utility functions concerning IPv6 stack monitoring. + * + * Module can monitor nanostack heap usage and release memory if heap usage is too high. + * Mmeory monitoring can work if memory statistics are enabled in nsdynmemLIB. + * + */ + +#ifndef _NS_MONITOR_H +#define _NS_MONITOR_H + +int ns_monitor_init(void); + +int ns_monitor_clear(void); + +void ns_monitor_timer(uint16_t seconds); + +int ns_monitor_heap_gc_threshold_set(uint8_t percentage_high, uint8_t percentage_critical); + +#endif // _NS_MONITOR_H + diff --git a/source/Core/ns_address_internal.c b/source/Core/ns_address_internal.c index ec884a3907..ca998f361e 100644 --- a/source/Core/ns_address_internal.c +++ b/source/Core/ns_address_internal.c @@ -865,7 +865,6 @@ void addr_fast_timer(protocol_interface_info_entry_t *cur, uint_fast16_t ticks) } #endif } else { - addr->addr_reg_done = 0; addr_cb(cur, addr, ADDR_CALLBACK_TIMER); } diff --git a/source/Core/ns_monitor.c b/source/Core/ns_monitor.c new file mode 100644 index 0000000000..7b17edbad3 --- /dev/null +++ b/source/Core/ns_monitor.c @@ -0,0 +1,174 @@ +/* + * Copyright (c) 2019, Arm Limited and affiliates. + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * \file ns_monitor.c + * \brief Utility functions for nanostack maintenance + * + * This module tracks stack current heap usage and triggers GC if heap usage is too high. + * GC is triggered by: + * 1. Heap usage is above HEAP_USAGE_HIGH + * 2. Heap usage is above HEAP_USAGE_CRITICAL + * 3. If nsdynmemLIB memory allocation has failed since last check + */ + +#include "nsconfig.h" +#include "ns_types.h" +#define HAVE_DEBUG +#include "ns_trace.h" +#include "nsdynmemLIB.h" +#include "ipv6_stack/ipv6_routing_table.h" +#include "NWK_INTERFACE/Include/protocol.h" + +#define TRACE_GROUP "mntr" + +typedef enum { + NS_MONITOR_STATE_HEAP_GC_IDLE = 0, + NS_MONITOR_STATE_HEAP_GC_HIGH, + NS_MONITOR_STATE_GC_CRITICAL +} ns_monitor_state_e; + +#define HEAP_HIGH_WATERWARK (0.95) /* Heap usage HIGH threshold */ +#define HEAP_CRITICAL_WATERMARK (0.99) /* Heap usage CRITICAL threshold */ + +#define NS_MAINTENANCE_TIMER_INTERVAL 10 // Maintenance interval + +typedef struct ns_monitor__s { + ns_mem_heap_size_t heap_high_watermark; + ns_mem_heap_size_t heap_critical_watermark; + uint32_t prev_heap_alloc_fail_cnt; + ns_monitor_state_e ns_monitor_heap_gc_state; + const mem_stat_t *mem_stats; + uint16_t ns_maintenance_timer; +} ns_monitor_t; + +static ns_monitor_t *ns_monitor_ptr = NULL; + +typedef void (ns_maintenance_gc_cb)(bool full_gc); + +/* + * Garbage collection functions. + * Add more GC performing functions to the table + * + */ +static ns_maintenance_gc_cb *ns_maintenance_gc_functions[] = { + ipv6_destination_cache_forced_gc +}; + +static void ns_monitor_heap_gc(bool full_gc) +{ + (void) full_gc; + + for (unsigned int i = 0; i < sizeof(ns_maintenance_gc_functions) / sizeof(ns_maintenance_gc_functions[0]); i++) { + if (ns_maintenance_gc_functions[i]) { + (ns_maintenance_gc_functions[i])(full_gc); + } + } +} + +static void ns_monitor_periodic_heap_health_check(void) +{ + if (ns_monitor_ptr->mem_stats->heap_sector_allocated_bytes > ns_monitor_ptr->heap_critical_watermark) { + // Heap usage above CRITICAL + if (ns_monitor_ptr->ns_monitor_heap_gc_state != NS_MONITOR_STATE_GC_CRITICAL) { + ns_mem_heap_size_t prev_heap_sector_allocated_bytes = ns_monitor_ptr->mem_stats->heap_sector_allocated_bytes; + tr_debug("heap %lu/%lu", (unsigned long)ns_monitor_ptr->mem_stats->heap_sector_allocated_bytes, (unsigned long)ns_monitor_ptr->mem_stats->heap_sector_size); + ns_monitor_heap_gc(true); + ns_monitor_ptr->ns_monitor_heap_gc_state = NS_MONITOR_STATE_GC_CRITICAL; + tr_info("Stack GC critical: freed %lu bytes", (unsigned long)(prev_heap_sector_allocated_bytes - ns_monitor_ptr->mem_stats->heap_sector_allocated_bytes)); + } + } else if (ns_monitor_ptr->mem_stats->heap_sector_allocated_bytes > ns_monitor_ptr->heap_high_watermark) { + // Heap usage above HIGH + if (ns_monitor_ptr->ns_monitor_heap_gc_state == NS_MONITOR_STATE_HEAP_GC_IDLE) { + ns_mem_heap_size_t prev_heap_sector_allocated_bytes = ns_monitor_ptr->mem_stats->heap_sector_allocated_bytes; + tr_debug("heap %lu/%lu", (unsigned long)ns_monitor_ptr->mem_stats->heap_sector_allocated_bytes, (unsigned long)ns_monitor_ptr->mem_stats->heap_sector_size); + ns_monitor_heap_gc(false); + ns_monitor_ptr->ns_monitor_heap_gc_state = NS_MONITOR_STATE_HEAP_GC_HIGH; + tr_info("Stack GC high: freed %lu bytes", (unsigned long)(prev_heap_sector_allocated_bytes - ns_monitor_ptr->mem_stats->heap_sector_allocated_bytes)); + } + } else if (ns_monitor_ptr->mem_stats->heap_sector_allocated_bytes <= ns_monitor_ptr->heap_high_watermark) { + // Heap usage in normal range + ns_monitor_ptr->ns_monitor_heap_gc_state = NS_MONITOR_STATE_HEAP_GC_IDLE; + } +} + +void ns_monitor_timer(uint16_t seconds) +{ + if (ns_monitor_ptr) { + ns_monitor_ptr->ns_maintenance_timer += seconds; + + if (ns_monitor_ptr->mem_stats->heap_alloc_fail_cnt > ns_monitor_ptr->prev_heap_alloc_fail_cnt) { + // Heap allocation failure occurred since last check + ns_monitor_ptr->prev_heap_alloc_fail_cnt = ns_monitor_ptr->mem_stats->heap_alloc_fail_cnt; + if (ns_monitor_ptr->ns_monitor_heap_gc_state != NS_MONITOR_STATE_GC_CRITICAL) { + ns_monitor_ptr->ns_monitor_heap_gc_state = NS_MONITOR_STATE_GC_CRITICAL; + ns_monitor_heap_gc(true); + ns_monitor_ptr->ns_maintenance_timer = 0; + } + } + + if (ns_monitor_ptr->ns_maintenance_timer >= NS_MAINTENANCE_TIMER_INTERVAL) { + ns_monitor_ptr->ns_maintenance_timer -= NS_MAINTENANCE_TIMER_INTERVAL; + ns_monitor_periodic_heap_health_check(); + } + } +} + +int ns_monitor_init(void) +{ + if (ns_monitor_ptr || !ns_dyn_mem_get_mem_stat()) { + // already initialized or memory statistics not available + return -2; + } + + ns_monitor_ptr = ns_dyn_mem_alloc(sizeof(ns_monitor_t)); + + if (ns_monitor_ptr) { + ns_monitor_ptr->mem_stats = ns_dyn_mem_get_mem_stat(); + ns_monitor_ptr->heap_high_watermark = ns_monitor_ptr->mem_stats->heap_sector_size * HEAP_HIGH_WATERWARK; + ns_monitor_ptr->heap_critical_watermark = ns_monitor_ptr->mem_stats->heap_sector_size * HEAP_CRITICAL_WATERMARK; + ns_monitor_ptr->ns_monitor_heap_gc_state = NS_MONITOR_STATE_HEAP_GC_IDLE; + ns_monitor_ptr->ns_maintenance_timer = 0; + ns_monitor_ptr->prev_heap_alloc_fail_cnt = 0; + return 0; + } + + return -1; +} + +int ns_monitor_clear(void) +{ + if (ns_monitor_ptr) { + ns_dyn_mem_free(ns_monitor_ptr); + ns_monitor_ptr = NULL; + return 0; + } + + return -1; +} + +int ns_monitor_heap_gc_threshold_set(uint8_t percentage_high, uint8_t percentage_critical) +{ + if (ns_monitor_ptr && (percentage_critical <= 100) && (percentage_high < percentage_critical)) { + ns_monitor_ptr->heap_high_watermark = ns_monitor_ptr->mem_stats->heap_sector_size * percentage_high / 100; + ns_monitor_ptr->heap_critical_watermark = ns_monitor_ptr->mem_stats->heap_sector_size * percentage_critical / 100; + tr_debug("Monitor set high:%lu, critical:%lu total:%lu", (unsigned long)ns_monitor_ptr->heap_high_watermark, (unsigned long)ns_monitor_ptr->heap_critical_watermark, (unsigned long)ns_monitor_ptr->mem_stats->heap_sector_size); + return 0; + } + + return -1; +} diff --git a/source/DHCPv6_Server/DHCPv6_Server_service.c b/source/DHCPv6_Server/DHCPv6_Server_service.c index be3c6c927f..7e172f7fde 100644 --- a/source/DHCPv6_Server/DHCPv6_Server_service.c +++ b/source/DHCPv6_Server/DHCPv6_Server_service.c @@ -147,6 +147,11 @@ int DHCPV6_server_service_request_handler(uint16_t instance_id, uint32_t msg_tr_ replyPacket.T1 = dhcp_ia_non_temporal_params.T1; replyPacket.iaId = dhcp_ia_non_temporal_params.iaId; replyPacket.transaction_ID = msg_tr_id; + + uint16_t duid_length = libdhcpv6_duid_option_size(replyPacket.clientDUID.linkType); + duid_length -= 8; + tr_debug("Response dhcp sol %s clientDUID", trace_array(replyPacket.clientDUID.linkID, duid_length)); + //Check First Current list if (DHCPv6_server_respond_client(serverBase, &replyPacket, &dhcp_ia_non_temporal_params, &responseBuf, true) == 0) { //Respond diff --git a/source/DHCPv6_client/dhcpv6_client_api.h b/source/DHCPv6_client/dhcpv6_client_api.h index 472b9ff8f2..60c2ff7f52 100644 --- a/source/DHCPv6_client/dhcpv6_client_api.h +++ b/source/DHCPv6_client/dhcpv6_client_api.h @@ -100,7 +100,7 @@ void dhcp_client_global_address_delete(int8_t interface, uint8_t *dhcp_addr, uin void dhcp_relay_agent_enable(int8_t interface, uint8_t border_router_address[static 16]); -int dhcp_client_server_address_update(int8_t interface, uint8_t prefix[static 16], uint8_t server_address[static 16]); +int dhcp_client_server_address_update(int8_t interface, uint8_t *prefix, uint8_t server_address[static 16]); diff --git a/source/DHCPv6_client/dhcpv6_client_service.c b/source/DHCPv6_client/dhcpv6_client_service.c index 5ed5209893..511ac2affe 100644 --- a/source/DHCPv6_client/dhcpv6_client_service.c +++ b/source/DHCPv6_client/dhcpv6_client_service.c @@ -96,7 +96,7 @@ void dhcp_client_delete(int8_t interface) { protocol_interface_info_entry_t *cur = NULL; dhcpv6_client_server_data_t *srv_data_ptr; - + uint8_t temporary_address[16]; dhcp_service_delete(dhcp_client.service_instance); @@ -110,9 +110,11 @@ void dhcp_client_delete(int8_t interface) srv_data_ptr = libdhcpv6_nonTemporal_entry_get_by_instance(dhcp_client.libDhcp_instance); if (srv_data_ptr != NULL) { tr_debug("Free DHCPv6 Client\n"); + memcpy(temporary_address, srv_data_ptr->iaNontemporalAddress.addressPrefix, 16); dhcp_service_req_remove(srv_data_ptr->transActionId);// remove all pending retransmissions - addr_delete(cur, srv_data_ptr->iaNontemporalAddress.addressPrefix); libdhcvp6_nontemporalAddress_server_data_free(srv_data_ptr); + addr_delete(cur, temporary_address); + } } while (srv_data_ptr != NULL); dhcp_client.service_instance = 0; @@ -234,6 +236,9 @@ int dhcp_client_get_global_address(int8_t interface, uint8_t dhcp_addr[static 16 dhcpv6_renew(protocol_stack_interface_info_get_by_id(interface), NULL, ADDR_CALLBACK_TIMER); } return 0; + } else if (dhcp_client_server_address_update(interface, prefix, dhcp_addr) == 0) { + //DHCP server address OK + return 0; } } return -1; @@ -302,7 +307,7 @@ int dhcp_client_get_global_address(int8_t interface, uint8_t dhcp_addr[static 16 return 0; } -int dhcp_client_server_address_update(int8_t interface, uint8_t prefix[static 16], uint8_t server_address[static 16]) +int dhcp_client_server_address_update(int8_t interface, uint8_t *prefix, uint8_t server_address[static 16]) { dhcpv6_client_server_data_t *srv_data_ptr = NULL; @@ -446,6 +451,7 @@ void dhcpv6_renew(protocol_interface_info_entry_t *interface, if_address_entry_t // Default retry values are modified from specification update to message dhcp_service_set_retry_timers(srv_data_ptr->transActionId, dhcp_client.sol_timeout, dhcp_client.sol_max_rt, dhcp_client.sol_max_rc); } + tr_error("DHCP renew send OK"); } static bool dhcpv6_client_set_address(int8_t interface_id, dhcpv6_client_server_data_t *srv_data_ptr) diff --git a/source/MAC/IEEE802_15_4/mac_indirect_data.c b/source/MAC/IEEE802_15_4/mac_indirect_data.c index fcfdb26586..51af386bdd 100644 --- a/source/MAC/IEEE802_15_4/mac_indirect_data.c +++ b/source/MAC/IEEE802_15_4/mac_indirect_data.c @@ -148,7 +148,6 @@ uint8_t mac_indirect_data_req_handle(mac_pre_parsed_frame_t *buf, protocol_inter /* If the Ack we sent for the Data Request didn't have frame pending set, we shouldn't transmit - child may have slept */ if (!buf->ack_pendinfg_status) { - //tr_debug("Drop by pending"); if (mac_ptr->indirect_pd_data_request_queue) { tr_error("Wrongly dropped"); } diff --git a/source/MAC/IEEE802_15_4/mac_mcps_sap.c b/source/MAC/IEEE802_15_4/mac_mcps_sap.c index 4035ec7ddf..39609e4dac 100644 --- a/source/MAC/IEEE802_15_4/mac_mcps_sap.c +++ b/source/MAC/IEEE802_15_4/mac_mcps_sap.c @@ -74,6 +74,8 @@ static void mac_pd_data_confirm_failure_handle(protocol_interface_rf_mac_setup_s static int8_t mac_tasklet_event_handler = -1; +static uint32_t ns_dyn_mem_rate_limiting_threshold = 0xFFFFFFFF; + /** * Get PHY time stamp. * @@ -233,7 +235,6 @@ void mcps_sap_data_req_handler_ext(protocol_interface_rf_mac_setup_s *rf_mac_set if (!rf_mac_setup->macUpState || rf_mac_setup->scan_active) { status = MLME_TRX_OFF; - tr_debug("Drop MAC tx packet when mac disabled"); goto verify_status; } @@ -614,11 +615,6 @@ static uint8_t mac_data_interface_decrypt_packet(mac_pre_parsed_frame_t *b, mlme ccm_ptr.data_ptr = (mcps_mac_payload_pointer_get(b) + openPayloadLength); ccm_ptr.data_len = b->mac_payload_length - openPayloadLength; if (ccm_process_run(&ccm_ptr) != 0) { - tr_warning("MIC Fail adata %s", trace_array(ccm_ptr.adata_ptr, ccm_ptr.adata_len)); - tr_warning("Nonce %s", trace_array(ccm_ptr.exp_nonce, 13)); - if (openPayloadLength) { - tr_warning("%s", tr_array(ccm_ptr.data_ptr, ccm_ptr.data_len)); - } return MLME_SECURITY_FAIL; } @@ -660,7 +656,6 @@ static void mcps_comm_status_indication_generate(uint8_t status, mac_pre_parsed_ static int8_t mac_data_interface_host_accept_data(mcps_data_ind_t *data_ind, protocol_interface_rf_mac_setup_s *rf_mac_setup) { if ((data_ind->DstAddrMode == MAC_ADDR_MODE_16_BIT) && (data_ind->DstAddr[0] == 0xff && data_ind->DstAddr[1] == 0xff)) { - tr_debug("Drop Multicast packet"); return -1; } @@ -686,6 +681,7 @@ static int8_t mac_data_sap_rx_handler(mac_pre_parsed_frame_t *buf, protocol_inte { int8_t retval = -1; uint8_t status; + //allocate Data ind primitiv and parse packet to that mcps_data_ind_t *data_ind = ns_dyn_mem_temporary_alloc(sizeof(mcps_data_ind_t)); @@ -720,7 +716,6 @@ static int8_t mac_data_sap_rx_handler(mac_pre_parsed_frame_t *buf, protocol_inte } if (!mac_payload_information_elements_parse(buf)) { - tr_debug("Drop by Paylod IE"); goto DROP_PACKET; } data_ind->msduLength = buf->mac_payload_length; @@ -738,7 +733,6 @@ static int8_t mac_data_sap_rx_handler(mac_pre_parsed_frame_t *buf, protocol_inte if (buf->fcf_dsn.frameVersion == MAC_FRAME_VERSION_2015) { if (!rf_mac_setup->mac_extension_enabled) { - tr_debug("No Ext reg"); goto DROP_PACKET; } mcps_data_ie_list_t ie_list; @@ -900,7 +894,6 @@ static void mac_data_interface_parse_beacon(mac_pre_parsed_frame_t *buf, protoco } if (!mac_payload_information_elements_parse(buf)) { - tr_debug("Drop by Paylod IE"); return; } @@ -921,7 +914,6 @@ static void mac_data_interface_parse_beacon(mac_pre_parsed_frame_t *buf, protoco if (len < gts_field_length) { return; } -// gts_info = ptr; len -= gts_field_length; ptr += gts_field_length; } @@ -976,7 +968,6 @@ static void mac_data_interface_frame_handler(mac_pre_parsed_frame_t *buf) { protocol_interface_rf_mac_setup_s *rf_mac_setup = buf->mac_class_ptr; if (!rf_mac_setup) { - tr_debug("Drop by no mac class"); mcps_sap_pre_parsed_frame_buffer_free(buf); return; } @@ -1081,13 +1072,11 @@ static int8_t mac_ack_sap_rx_handler(mac_pre_parsed_frame_t *buf, protocol_inter if (buf->fcf_dsn.securityEnabled) { uint8_t status = mac_data_interface_decrypt_packet(buf, &key); if (status != MLME_SUCCESS) { - tr_debug("ACK Decrypt fail"); return -1; } } if (buf->mac_payload_length && !mac_payload_information_elements_parse(buf)) { - tr_debug("Drop ACK by Paylod IE"); return -1; } @@ -2068,6 +2057,12 @@ void mcps_sap_pre_parsed_frame_buffer_free(mac_pre_parsed_frame_t *buf) mac_pre_parsed_frame_t *mcps_sap_pre_parsed_frame_buffer_get(const uint8_t *data_ptr, uint16_t frame_length) { + // check that system has enough space to handle the new packet + const mem_stat_t *ns_dyn_mem_stat = ns_dyn_mem_get_mem_stat(); + if (ns_dyn_mem_stat && ns_dyn_mem_stat->heap_sector_allocated_bytes > ns_dyn_mem_rate_limiting_threshold) { + return NULL; + } + mac_pre_parsed_frame_t *buffer = ns_dyn_mem_temporary_alloc(sizeof(mac_pre_parsed_frame_t) + frame_length); if (buffer) { @@ -2075,6 +2070,7 @@ mac_pre_parsed_frame_t *mcps_sap_pre_parsed_frame_buffer_get(const uint8_t *data buffer->frameLength = frame_length; memcpy(mac_header_message_start_pointer(buffer), data_ptr, frame_length); } + return buffer; } @@ -2298,3 +2294,15 @@ uint8_t mcps_sap_purge_reg_handler(protocol_interface_rf_mac_setup_s *rf_mac_set return confirmation.status; } + +int mcps_packet_ingress_rate_limit_by_memory(uint8_t free_heap_percentage) +{ + const mem_stat_t *ns_dyn_mem_stat = ns_dyn_mem_get_mem_stat(); + + if (ns_dyn_mem_stat && free_heap_percentage < 100) { + ns_dyn_mem_rate_limiting_threshold = ns_dyn_mem_stat->heap_sector_size / 100 * (100 - free_heap_percentage); + return 0; + } + + return -1; +} diff --git a/source/MAC/IEEE802_15_4/mac_mcps_sap.h b/source/MAC/IEEE802_15_4/mac_mcps_sap.h index a4f4baeb73..b69ec96aa2 100644 --- a/source/MAC/IEEE802_15_4/mac_mcps_sap.h +++ b/source/MAC/IEEE802_15_4/mac_mcps_sap.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2018, Arm Limited and affiliates. + * Copyright (c) 2016-2019, Arm Limited and affiliates. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -216,4 +216,6 @@ int8_t mcps_pd_data_rebuild(struct protocol_interface_rf_mac_setup *rf_ptr, mac_ int8_t mcps_generic_ack_build(struct protocol_interface_rf_mac_setup *rf_ptr, const mac_fcf_sequence_t *fcf, const uint8_t *data_ptr, const mcps_ack_data_payload_t *ack_payload); +int mcps_packet_ingress_rate_limit_by_memory(uint8_t free_heap_percentage); + #endif /* MAC_IEEE802_15_4_MAC_MCPS_SAP_H_ */ diff --git a/source/MAC/IEEE802_15_4/mac_mlme.c b/source/MAC/IEEE802_15_4/mac_mlme.c index bea62f2676..c247f01b21 100644 --- a/source/MAC/IEEE802_15_4/mac_mlme.c +++ b/source/MAC/IEEE802_15_4/mac_mlme.c @@ -232,7 +232,6 @@ uint8_t mac_mlme_beacon_req_tx(protocol_interface_rf_mac_setup_s *rf_ptr) buf->fcf_dsn.DstPanPresents = true; buf->fcf_dsn.SrcPanPresents = false; - tr_debug("BEA REQ tx"); mcps_sap_pd_req_queue_write(rf_ptr, buf); return 1; } @@ -843,7 +842,6 @@ static void mlme_scan_operation(protocol_interface_rf_mac_setup_s *rf_mac_setup) channel = mlme_scan_analyze_next_channel(&rf_mac_setup->mac_channel_list, true); if (channel > 0xff || rf_mac_setup->mac_mlme_scan_resp->ResultListSize == MLME_MAC_RES_SIZE_MAX) { resp->status = MLME_SUCCESS; - tr_debug("Scan Complete..Halt MAC"); platform_enter_critical(); mac_mlme_mac_radio_disabled(rf_mac_setup); if (resp->ResultListSize == 0 && rf_mac_setup->scan_type == MAC_ACTIVE_SCAN) { @@ -855,7 +853,6 @@ static void mlme_scan_operation(protocol_interface_rf_mac_setup_s *rf_mac_setup) platform_exit_critical(); //Scan Confirmation mac_generic_event_trig(MAC_MLME_SCAN_CONFIRM_HANDLER, rf_mac_setup, false); - tr_debug("Trig confirm"); rf_mac_setup->scan_active = false; } else { mac_mlme_scan_init((uint8_t) channel, rf_mac_setup); @@ -987,7 +984,6 @@ static void mac_mlme_free_scan_temporary_data(protocol_interface_rf_mac_setup_s rf_mac_setup->scan_active = false; if (rf_mac_setup->mac_mlme_scan_resp) { mlme_scan_conf_t *r = rf_mac_setup->mac_mlme_scan_resp; - tr_debug("%02x", r->ResultListSize); if (r->ED_values) { ns_dyn_mem_free(r->ED_values); r->ED_values = NULL; @@ -995,12 +991,10 @@ static void mac_mlme_free_scan_temporary_data(protocol_interface_rf_mac_setup_s uint8_t i = 0; while (i < r->ResultListSize) { if (r->PAN_values[i]) { - tr_debug("Free PAN result"); ns_dyn_mem_free(r->PAN_values[i]); } i++; } - tr_debug("Free Response"); ns_dyn_mem_free(rf_mac_setup->mac_mlme_scan_resp); rf_mac_setup->mac_mlme_scan_resp = NULL; } @@ -1399,11 +1393,6 @@ static void mac_mlme_start_confirm_handler(protocol_interface_rf_mac_setup_s *rf static void mac_mlme_scan_confirm_handler(protocol_interface_rf_mac_setup_s *rf_ptr, const mlme_scan_conf_t *conf) { - if (conf->ScanType == MAC_ACTIVE_SCAN) { - tr_debug("Active Scan Result"); - } else if (conf->ScanType == MAC_ED_SCAN_TYPE) { - tr_debug("ED Scan Result"); - } if (rf_ptr->tun_extension_rf_driver) { virtual_data_req_t scan_conf; uint8_t buf_temp[2]; diff --git a/source/MAC/IEEE802_15_4/mac_pd_sap.c b/source/MAC/IEEE802_15_4/mac_pd_sap.c index 9157c44454..ae78961499 100644 --- a/source/MAC/IEEE802_15_4/mac_pd_sap.c +++ b/source/MAC/IEEE802_15_4/mac_pd_sap.c @@ -487,7 +487,8 @@ static int8_t mac_data_interface_tx_done_cb(protocol_interface_rf_mac_setup_s *r return 0; } else { // Do not update CCA count when Ack is received, it was already updated with PHY_LINK_TX_SUCCESS event - if ((status != PHY_LINK_TX_DONE) && (status != PHY_LINK_TX_DONE_PENDING)) { + // Do not update CCA count when CCA_OK is received, PHY_LINK_TX_SUCCESS will update it + if ((status != PHY_LINK_TX_DONE) && (status != PHY_LINK_TX_DONE_PENDING) && (status != PHY_LINK_CCA_OK)) { /* For PHY_LINK_TX_SUCCESS and PHY_LINK_CCA_FAIL cca_retry must always be > 0. * PHY_LINK_TX_FAIL either happened during transmission or when waiting Ack -> we must use the CCA count given by PHY. */ diff --git a/source/MAC/IEEE802_15_4/mac_security_mib.c b/source/MAC/IEEE802_15_4/mac_security_mib.c index 2fe2b8fbeb..e009d04256 100644 --- a/source/MAC/IEEE802_15_4/mac_security_mib.c +++ b/source/MAC/IEEE802_15_4/mac_security_mib.c @@ -126,7 +126,7 @@ static void mac_sec_mib_key_device_description_remove_from_list(mlme_key_descrip *prev = *cur; } else if (cur->DeviceDescriptorHandle == device_descriptor_handle) { removed_entry = true; - tr_debug("Remove user %u from key", device_descriptor_handle); + //tr_debug("Remove user %u from key", device_descriptor_handle); } prev = cur; cur++; @@ -244,10 +244,10 @@ int8_t mac_sec_mib_device_description_set(uint8_t atribute_index, mlme_device_de if (memcmp(device_ptr->ExtAddress, device_descriptor->ExtAddress, 8)) { //Remove last handles key user's mac_sec_mib_device_description_remove(rf_mac_setup, atribute_index); - tr_debug("Over write %u, mac16 %x mac64: %s, %"PRIu32, atribute_index, device_ptr->ShortAddress, trace_array(device_ptr->ExtAddress, 8), device_ptr->FrameCounter); + //tr_debug("Over write %u, mac16 %x mac64: %s, %"PRIu32, atribute_index, device_ptr->ShortAddress, trace_array(device_ptr->ExtAddress, 8), device_ptr->FrameCounter); } - tr_debug("Set %u, mac16 %x mac64: %s, %"PRIu32, atribute_index, device_descriptor->ShortAddress, trace_array(device_descriptor->ExtAddress, 8), device_descriptor->FrameCounter); + //tr_debug("Set %u, mac16 %x mac64: %s, %"PRIu32, atribute_index, device_descriptor->ShortAddress, trace_array(device_descriptor->ExtAddress, 8), device_descriptor->FrameCounter); *device_ptr = *device_descriptor; return 0; @@ -485,7 +485,7 @@ void mac_sec_mib_device_description_blacklist(protocol_interface_rf_mac_setup_s for (uint8_t i = 0; i < rf_mac_setup->key_description_table_size; i++) { descriptor = mac_sec_mib_key_device_description_discover_from_list(&rf_mac_setup->key_description_table[i], device_handle); if (descriptor) { - tr_debug("Black listed device %u lookup%s", device_handle, trace_array(rf_mac_setup->key_description_table[i].Key, 16)); + tr_debug("Black listed device %u", device_handle); descriptor->Blacklisted = true; } diff --git a/source/MAC/IEEE802_15_4/sw_mac.c b/source/MAC/IEEE802_15_4/sw_mac.c index 3650d7c794..ca31fe949d 100644 --- a/source/MAC/IEEE802_15_4/sw_mac.c +++ b/source/MAC/IEEE802_15_4/sw_mac.c @@ -699,3 +699,19 @@ void sw_mac_stats_update(protocol_interface_rf_mac_setup_s *setup, mac_stats_typ } } } + +uint32_t ns_sw_mac_read_current_timestamp(struct mac_api_s *mac_api) +{ + if (!mac_api) { + return 0; + } + + // Get a pointer to MAC setup structure + protocol_interface_rf_mac_setup_s *mac_setup = get_sw_mac_ptr_by_mac_api(mac_api); + if (!mac_setup) { + return 0; + } + uint32_t time_stamp_buffer; + mac_setup->dev_driver->phy_driver->extension(PHY_EXTENSION_GET_TIMESTAMP, (uint8_t *)&time_stamp_buffer); + return time_stamp_buffer; +} diff --git a/source/NWK_INTERFACE/Include/protocol.h b/source/NWK_INTERFACE/Include/protocol.h index 7a0ec03529..3bdba330b8 100644 --- a/source/NWK_INTERFACE/Include/protocol.h +++ b/source/NWK_INTERFACE/Include/protocol.h @@ -515,5 +515,6 @@ extern void protocol_core_dhcpv6_allocated_address_remove(protocol_interface_inf extern void nwk_bootsrap_state_update(arm_nwk_interface_status_type_e posted_event, protocol_interface_info_entry_t *cur); void bootsrap_next_state_kick(icmp_state_t new_state, protocol_interface_info_entry_t *cur); int8_t protocol_interface_address_compare(const uint8_t *addr); +bool protocol_address_prefix_cmp(protocol_interface_info_entry_t *cur, const uint8_t *prefix, uint8_t prefix_len); bool protocol_interface_any_address_match(const uint8_t *prefix, uint8_t prefix_len); #endif /* _NS_PROTOCOL_H */ diff --git a/source/NWK_INTERFACE/protocol_core.c b/source/NWK_INTERFACE/protocol_core.c index a05ac5f55e..1564cdf6a6 100644 --- a/source/NWK_INTERFACE/protocol_core.c +++ b/source/NWK_INTERFACE/protocol_core.c @@ -24,6 +24,7 @@ #include "ns_trace.h" #include "nsdynmemLIB.h" #include "Core/include/ns_socket.h" +#include "Core/include/ns_monitor.h" #include "NWK_INTERFACE/Include/protocol.h" #include "NWK_INTERFACE/Include/protocol_timer.h" #include "platform/arm_hal_interrupt.h" @@ -175,6 +176,7 @@ void protocol_root_tasklet(arm_event_t *event) switch (event_type) { case ARM_LIB_TASKLET_INIT_EVENT: tr_debug("NS Root task Init"); + ns_monitor_init(); break; case ARM_IN_PROTOCOL_TIMER_EVENT: { @@ -306,8 +308,7 @@ void core_timer_event_handle(uint16_t ticksUpdate) ws_pae_controller_slow_timer(seconds); #endif protocol_6lowpan_mle_timer(seconds); - /* This limit bad behaviour device's MLE link reject generation */ - + ns_monitor_timer(seconds); } else { protocol_core_seconds_timer -= ticksUpdate; } @@ -387,7 +388,6 @@ void protocol_core_init(void) protocol_core_timer_info.core_security_ticks_counter = SEC_LIB_X_100MS_COUNTER; protocol_timer_start(PROTOCOL_TIMER_STACK_TIM, protocol_core_cb, 100); - } void protocol_core_interface_info_reset(protocol_interface_info_entry_t *entry) @@ -1140,9 +1140,9 @@ int8_t protocol_interface_address_compare(const uint8_t *addr) return -1; } -static bool protocol_address_prefix_cmp(protocol_interface_info_entry_t *interface, const uint8_t *prefix, uint8_t prefix_len) +bool protocol_address_prefix_cmp(protocol_interface_info_entry_t *cur, const uint8_t *prefix, uint8_t prefix_len) { - ns_list_foreach(if_address_entry_t, adr, &interface->ip_addresses) { + ns_list_foreach(if_address_entry_t, adr, &cur->ip_addresses) { if (bitsequal(adr->address, prefix, prefix_len)) { /* Prefix stil used at list so stop checking */ return true; diff --git a/source/RPL/rpl_control.c b/source/RPL/rpl_control.c index 963b2f3c19..f54d1c2ad3 100644 --- a/source/RPL/rpl_control.c +++ b/source/RPL/rpl_control.c @@ -171,68 +171,85 @@ void rpl_control_unpublish_address(rpl_domain_t *domain, const uint8_t addr[16]) } } -static if_address_entry_t *rpl_instance_reg_addr_get(protocol_interface_info_entry_t *interface) +void rpl_control_request_parent_link_confirmation(bool requested) { - ns_list_foreach(if_address_entry_t, address, &interface->ip_addresses) { - if (!address->addr_reg_done && !addr_is_ipv6_link_local(address->address)) { - return address; - } - } - - return NULL; + rpl_policy_set_parent_confirmation_request(requested); } /* Send address registration to either specified address, or to non-registered address */ -void rpl_control_register_address(protocol_interface_info_entry_t *interface, if_address_entry_t *addr) +void rpl_control_register_address(protocol_interface_info_entry_t *interface, const uint8_t addr[16]) { - if_address_entry_t *reg_addr = addr; - - if (!reg_addr) { - reg_addr = rpl_instance_reg_addr_get(interface); - - if (!reg_addr) { - return; - } + if (!rpl_policy_parent_confirmation_requested()) { + return; } ns_list_foreach(struct rpl_instance, instance, &interface->rpl_domain->instances) { - rpl_instance_send_address_registration(interface, instance, reg_addr); + rpl_instance_send_address_registration(instance, addr); } } -void rpl_control_address_register_done(struct buffer *buf, uint8_t status) +void rpl_control_address_register_done(protocol_interface_info_entry_t *interface, const uint8_t ll_addr[16], uint8_t status) { - ns_list_foreach(if_address_entry_t, addr, &buf->interface->ip_addresses) { + if (!interface->rpl_domain) { + return; + } + if (!rpl_policy_parent_confirmation_requested()) { + return; + } - /* Optimize, ll addresses are not registered anyway.. */ - if (addr_is_ipv6_link_local(addr->address) || !addr->addr_reg_pend) { - continue; - } - - ns_list_foreach(struct rpl_instance, instance, &buf->interface->rpl_domain->instances) { - if (rpl_instance_address_registration_done(buf->interface, instance, addr, status)) { - return; - } + ns_list_foreach(struct rpl_instance, instance, &interface->rpl_domain->instances) { + rpl_neighbour_t *neighbour = rpl_lookup_neighbour_by_ll_address(instance, ll_addr, interface->id); + if (neighbour) { + rpl_instance_address_registration_done(interface, instance, neighbour, status); } } } -bool rpl_control_is_dodag_parent(protocol_interface_info_entry_t *interface, const uint8_t ll_addr[16]) +bool rpl_control_is_dodag_parent(protocol_interface_info_entry_t *interface, const uint8_t ll_addr[16], bool selected) { + if (!interface->rpl_domain) { + return false; + } // go through instances and parents and check if they match the address. ns_list_foreach(struct rpl_instance, instance, &interface->rpl_domain->instances) { - if (rpl_instance_address_is_parent(instance, ll_addr)) { + if (rpl_instance_address_is_parent(instance, ll_addr, selected)) { return true; } } return false; } + +uint16_t rpl_control_parent_candidate_list_size(protocol_interface_info_entry_t *interface, bool parent_list) +{ + if (!interface->rpl_domain) { + return 0; + } + + uint16_t parent_list_size = 0; + + // go through instances and parents and check if they match the address. + ns_list_foreach(struct rpl_instance, instance, &interface->rpl_domain->instances) { + uint16_t current_size = rpl_instance_address_candidate_count(instance, parent_list); + if (current_size > parent_list_size) { + parent_list_size = current_size; + } + } + return parent_list_size; +} + + void rpl_control_neighbor_delete(protocol_interface_info_entry_t *interface, const uint8_t ll_addr[16]) { + if (!interface->rpl_domain) { + return; + } // go through instances and delete address. ns_list_foreach(struct rpl_instance, instance, &interface->rpl_domain->instances) { - rpl_instance_neighbor_delete(instance, ll_addr); + + rpl_neighbour_t *neighbour = rpl_lookup_neighbour_by_ll_address(instance, ll_addr, interface->id); + if (neighbour) { + rpl_delete_neighbour(instance, neighbour); + } } - return; } /* Address changes need to trigger DAO target re-evaluation */ @@ -686,13 +703,12 @@ static void rpl_control_process_prefix_options(protocol_interface_info_entry_t * uint32_t preferred = common_read_32_bit(ptr + 8); const uint8_t *prefix = ptr + 16; - if (!pref_parent || neighbour == pref_parent) { + if (rpl_upward_accept_prefix_update(dodag, neighbour, pref_parent)) { /* Store prefixes for possible forwarding */ /* XXX if leaf - don't bother? Or do we want to remember them for * when we switch DODAG, as mentioned above? */ - prefix_entry_t *prefix_entry = rpl_dodag_update_dio_prefix(dodag, prefix, prefix_len, flags, valid, preferred, false, true); if (prefix_entry && pref_parent) { rpl_control_process_prefix_option(prefix_entry, cur); @@ -840,7 +856,6 @@ static void rpl_control_dao_trigger_request(rpl_instance_t *instance, rpl_dodag_ static buffer_t *rpl_control_dio_handler(protocol_interface_info_entry_t *cur, rpl_domain_t *domain, buffer_t *buf) { if (!rpl_control_options_well_formed_in_buffer(buf, 24)) { - tr_error("DIO format"); malformed: protocol_stats_update(STATS_RPL_MALFORMED_MESSAGE, 1); return buffer_free(buf); @@ -993,7 +1008,7 @@ malformed: rpl_control_process_prefix_options(cur, instance, dodag, neighbour, ptr, buffer_data_end(buf)); - rpl_dodag_update_implicit_system_routes(dodag, neighbour); + //rpl_dodag_update_implicit_system_routes(dodag, neighbour); rpl_control_process_route_options(instance, dodag, version, neighbour, rank, ptr, buffer_data_end(buf)); //rpl_control_process_metric_containers(neighbour, ptr, buffer_data_end(buf)) @@ -1137,7 +1152,7 @@ void rpl_control_transmit_dio(rpl_domain_t *domain, protocol_interface_info_entr } else { prefix->options &= ~ PIO_R; - if (rpl_dodag_mop(dodag) == RPL_MODE_NON_STORING && prefix->lifetime != 0) { + if (rpl_dodag_mop(dodag) == RPL_MODE_NON_STORING && (prefix->lifetime != 0 || !(prefix->options & PIO_A))) { continue; } } @@ -1175,7 +1190,7 @@ void rpl_control_transmit_dio(rpl_domain_t *domain, protocol_interface_info_entr ns_list_foreach_safe(prefix_entry_t, prefix, prefixes) { /* See equivalent checks in length calculation above */ if ((prefix->options & (PIO_L | RPL_PIO_PUBLISHED)) == PIO_L || - (!(prefix->options & PIO_R) && rpl_dodag_mop(dodag) == RPL_MODE_NON_STORING && prefix->lifetime != 0)) { + (!(prefix->options & PIO_R) && rpl_dodag_mop(dodag) == RPL_MODE_NON_STORING && (prefix->lifetime != 0 || !(prefix->options & PIO_A)))) { continue; } @@ -1252,7 +1267,6 @@ void rpl_control_transmit_dio(rpl_domain_t *domain, protocol_interface_info_entr static buffer_t *rpl_control_dis_handler(protocol_interface_info_entry_t *cur, rpl_domain_t *domain, buffer_t *buf, bool multicast) { if (!rpl_control_options_well_formed_in_buffer(buf, 2)) { - tr_error("DIS format"); protocol_stats_update(STATS_RPL_MALFORMED_MESSAGE, 1); return buffer_free(buf); } @@ -1380,7 +1394,6 @@ static buffer_t *rpl_control_dao_ack_handler(protocol_interface_info_entry_t *cu if (buffer_data_length(buf) < 4) { format_error: - tr_error("DAO-ACK format"); protocol_stats_update(STATS_RPL_MALFORMED_MESSAGE, 1); return buffer_free(buf); } @@ -1464,7 +1477,6 @@ static buffer_t *rpl_control_dao_handler(protocol_interface_info_entry_t *cur, r { if (buffer_data_length(buf) < 4) { format_error: - tr_error("DAO format"); protocol_stats_update(STATS_RPL_MALFORMED_MESSAGE, 1); return buffer_free(buf); } diff --git a/source/RPL/rpl_control.h b/source/RPL/rpl_control.h index 20b82351ce..cbe6cfd164 100644 --- a/source/RPL/rpl_control.h +++ b/source/RPL/rpl_control.h @@ -147,10 +147,13 @@ void rpl_control_set_callback(rpl_domain_t *domain, rpl_domain_callback_t callba /* Target publishing */ void rpl_control_publish_host_address(rpl_domain_t *domain, const uint8_t addr[16], uint32_t lifetime); void rpl_control_unpublish_address(rpl_domain_t *domain, const uint8_t addr[16]); -void rpl_control_register_address(struct protocol_interface_info_entry *interface, if_address_entry_t *addr); -void rpl_control_address_register_done(struct buffer *buf, uint8_t status); -bool rpl_control_is_dodag_parent(struct protocol_interface_info_entry *interface, const uint8_t ll_addr[16]); +bool rpl_control_is_dodag_parent(struct protocol_interface_info_entry *interface, const uint8_t ll_addr[16], bool selected); +uint16_t rpl_control_parent_candidate_list_size(struct protocol_interface_info_entry *interface, bool parent_list); void rpl_control_neighbor_delete(struct protocol_interface_info_entry *interface, const uint8_t ll_addr[16]); +/* Parent link confirmation API extension */ +void rpl_control_request_parent_link_confirmation(bool requested); +void rpl_control_register_address(struct protocol_interface_info_entry *interface, const uint8_t addr[16]); +void rpl_control_address_register_done(struct protocol_interface_info_entry *interface, const uint8_t ll_addr[16], uint8_t status); /* Configure and return the routing lookup predicate for a specified RPL instance ID */ ipv6_route_predicate_fn_t *rpl_control_get_route_predicate(rpl_domain_t *domain, uint8_t instance_id, const uint8_t src[16], const uint8_t dst[16]); @@ -172,7 +175,7 @@ uint16_t rpl_control_current_rank(const struct rpl_instance *instance); #define rpl_control_slow_timer(seconds) ((void) 0) #define rpl_control_remove_domain_from_interface(cur) ((void) 0) #define rpl_control_register_address(interface, addr) ((void) 0) -#define rpl_control_address_register_done NULL +#define rpl_control_address_register_done(interface, ll_addr, status) ((void) 0) #endif /* HAVE_RPL */ diff --git a/source/RPL/rpl_downward.c b/source/RPL/rpl_downward.c index a0359ecaea..3c6da959da 100644 --- a/source/RPL/rpl_downward.c +++ b/source/RPL/rpl_downward.c @@ -372,6 +372,12 @@ void rpl_instance_publish_dao_target(rpl_instance_t *instance, const uint8_t *pr target->descriptor_present = want_descriptor; target->descriptor = descriptor; target->path_control = 0xFF; /* Use as much path control as we can (PCS limits) */ + target->response_wait_time = 0; + target->active_confirmation_state = false; + target->trig_confirmation_state = true; + //Activate allways registration + instance->pending_neighbour_confirmation = rpl_policy_parent_confirmation_requested(); + tr_debug("New Target %s", trace_ipv6(target->prefix)); /* Path lifetime left as 0 for now - will be filled in on transmission, along with refresh timer */ rpl_instance_dao_trigger(instance, 0); } @@ -383,7 +389,7 @@ void rpl_instance_dao_trigger(rpl_instance_t *instance, uint16_t delay) } if (instance->delay_dao_timer == 0 || instance->delay_dao_timer > delay) { instance->delay_dao_timer = delay; - tr_debug("DAO trigger %" PRIu16, delay); + //tr_debug("DAO trigger %" PRIu16, delay); } } @@ -583,63 +589,63 @@ static void rpl_downward_reset_assigning(rpl_instance_t *instance, uint8_t pcs_m } } - -void rpl_instance_send_address_registration(protocol_interface_info_entry_t *interface, rpl_instance_t *instance, if_address_entry_t *addr) +static void rpl_instance_unconfirm_parent_info(rpl_instance_t *instance) { - aro_t aro; - buffer_t *buf; - - aro.status = ARO_SUCCESS; - aro.present = true; - aro.lifetime = (addr->valid_lifetime / 60) + 1; - memcpy(aro.eui64, interface->mac, 8); - - // go through neighbour list, and send to all assigned parents. - ns_list_foreach(rpl_neighbour_t, neighbour, &instance->candidate_neighbours) { - if (neighbour->dao_path_control) { - tr_debug("Send ARO %s to %s", trace_ipv6(addr->address), trace_ipv6(neighbour->ll_address)); - buf = icmpv6_build_ns(interface, neighbour->ll_address, addr->address, true, false, &aro); - addr->addr_reg_pend |= neighbour->dao_path_control; - protocol_push(buf); - } else { - tr_debug("Skip ARO to %s - no pc", trace_ipv6(neighbour->ll_address)); - } - } -} - -bool rpl_instance_address_registration_done(protocol_interface_info_entry_t *interface, rpl_instance_t *instance, if_address_entry_t *addr, uint8_t status) -{ - ns_list_foreach(rpl_neighbour_t, neighbour, &instance->candidate_neighbours) { - // Check path control mask - if (!(addr->addr_reg_pend & neighbour->dao_path_control)) { + ns_list_foreach_safe(rpl_neighbour_t, n, &instance->candidate_neighbours) { + if (n->dao_path_control == 0) { continue; } + n->confirmed = false; - tr_debug("Address %s register to %s", trace_ipv6(addr->address), trace_ipv6(neighbour->ll_address)); - - /* Clear pending flag */ - addr->addr_reg_pend &= ~neighbour->dao_path_control; - - if (status == SOCKET_TX_DONE) { - addr->addr_reg_done |= neighbour->dao_path_control; - /* State_timer is 1/10 s. Set renewal to 75-85% of lifetime */ - addr->state_timer = (addr->preferred_lifetime * randLIB_get_random_in_range(75, 85) / 10); - } else { - tr_error("Address registration failed"); - rpl_delete_neighbour(instance, neighbour); - } - - /* If that was last one to reply, send next one. */ - if (!addr->addr_reg_pend) { - rpl_control_register_address(interface, NULL); - } - - return true; } - - return false; } +static rpl_dao_target_t *rpl_instance_get_pending_target_confirmation_for_address(rpl_instance_t *instance, const uint8_t address[16]) +{ + ns_list_foreach_safe(rpl_dao_target_t, n, &instance->dao_targets) { + if (memcmp(n->prefix, address, 16) == 0) { + return n; + } + } + return NULL; +} + +static rpl_dao_target_t *rpl_instance_get_pending_target_confirmation(rpl_instance_t *instance) +{ + ns_list_foreach_safe(rpl_dao_target_t, n, &instance->dao_targets) { + if (!n->trig_confirmation_state) { + continue; + } + n->trig_confirmation_state = false; + n->active_confirmation_state = true; + instance->wait_response = NULL; + rpl_instance_unconfirm_parent_info(instance); + return n; + } + return NULL; +} + +void rpl_instance_send_address_registration(rpl_instance_t *instance, const uint8_t addr[16]) +{ + if (addr) { + rpl_dao_target_t *target = rpl_instance_get_pending_target_confirmation_for_address(instance, addr); + if (!target) { + return; + } + + if (instance->pending_neighbour_confirmation && (target->active_confirmation_state || target->trig_confirmation_state)) { + return; + } + target->trig_confirmation_state = true; + } else if (!instance->pending_neighbour_confirmation) { + ns_list_foreach_safe(rpl_dao_target_t, n, &instance->dao_targets) { + n->trig_confirmation_state = true; + } + } + instance->pending_neighbour_confirmation = true; +} + + /* We are optimised for sending updates to existing targets to current parents; * we track the state of what information DAO parents have, and manage the * updates together with message coalescing and ack tracking. @@ -673,6 +679,12 @@ void rpl_instance_send_dao_update(rpl_instance_t *instance) return; } + //Verify that no pending address registartion to parent + if (instance->pending_neighbour_confirmation) { + rpl_instance_dao_trigger(instance, 6 * 10); + return; + } + if (instance->dao_in_transit) { // Force current DAO timeout to be cut short, then // when it times out, it will re-evaluate the situation, @@ -1689,4 +1701,145 @@ void rpl_downward_print_instance(rpl_instance_t *instance, route_print_fn_t *pri } } +rpl_dao_target_t *rpl_instance_get_active_target_confirmation(rpl_instance_t *instance) +{ + ns_list_foreach_safe(rpl_dao_target_t, n, &instance->dao_targets) { + if (!n->active_confirmation_state) { + continue; + } + return n; + + } + return NULL; +} + +static rpl_neighbour_t *rpl_instance_get_unconfirmed_parent_info(rpl_instance_t *instance) +{ + ns_list_foreach_safe(rpl_neighbour_t, n, &instance->candidate_neighbours) { + if (n->dao_path_control != 0 && !n->confirmed) { + return n; + } + + } + return NULL; +} + +static bool rpl_instance_push_address_registration(protocol_interface_info_entry_t *interface, rpl_neighbour_t *neighbour, if_address_entry_t *addr) +{ + aro_t aro; + + aro.status = ARO_SUCCESS; + aro.present = true; + aro.lifetime = (addr->valid_lifetime / 60) + 1; + memcpy(aro.eui64, interface->mac, 8); + + buffer_t *buf = icmpv6_build_ns(interface, neighbour->ll_address, addr->address, true, false, &aro); + if (!buf) { + return false; + } + tr_debug("Send ARO %s to %s", trace_ipv6(addr->address), trace_ipv6(neighbour->ll_address)); + protocol_push(buf); + return true; +} +static if_address_entry_t *rpl_interface_addr_get(protocol_interface_info_entry_t *interface, const uint8_t addr[16]) +{ + ns_list_foreach(if_address_entry_t, entry, &interface->ip_addresses) { + if (memcmp(entry->address, addr, 16) == 0) { + return entry; + } + } + return NULL; +} + + + +void rpl_instance_parent_address_reg_timer_update(rpl_instance_t *instance, uint16_t seconds) +{ + if (!instance->pending_neighbour_confirmation) { + return; //No need validate any confirmation + } + + //Get Pendig active target + rpl_dao_target_t *dao_target = rpl_instance_get_active_target_confirmation(instance); + if (!dao_target) { + dao_target = rpl_instance_get_pending_target_confirmation(instance); + if (!dao_target) { + instance->pending_neighbour_confirmation = false; + return; + } + + tr_debug("Register Address to parent %s", trace_ipv6(dao_target->prefix)); + } + + if (instance->wait_response) { + uint16_t wait_time = dao_target->response_wait_time; + if (seconds < wait_time) { + //Must Wait response time untill finish + dao_target->response_wait_time -= seconds; + return; + } + dao_target->response_wait_time = 0; + instance->wait_response = NULL; + } + + //Get Next Parent for confirmation + rpl_neighbour_t *neighbour = rpl_instance_get_unconfirmed_parent_info(instance); + if (!neighbour) { + dao_target->active_confirmation_state = false; + return; + } + + //Get address and buffer + protocol_interface_info_entry_t *interface = protocol_stack_interface_info_get_by_id(neighbour->interface_id); + if (!interface) { + dao_target->response_wait_time = 0; + instance->wait_response = NULL; + dao_target->active_confirmation_state = false; + return; + } + + if_address_entry_t *address = rpl_interface_addr_get(interface, dao_target->prefix); + if (!address) { + dao_target->response_wait_time = 0; + instance->wait_response = NULL; + dao_target->active_confirmation_state = false; + return; + } + + + if (rpl_instance_push_address_registration(interface, neighbour, address)) { + instance->wait_response = neighbour; + dao_target->response_wait_time = 5; + } + +} + +void rpl_instance_address_registration_done(protocol_interface_info_entry_t *interface, rpl_instance_t *instance, rpl_neighbour_t *neighbour, uint8_t status) +{ + + if (!instance->pending_neighbour_confirmation) { + return; + } + + rpl_dao_target_t *dao_target = rpl_instance_get_active_target_confirmation(instance); + if (!dao_target || instance->wait_response != neighbour) { + return; + } + + tr_debug("Address %s register to %s", trace_ipv6(dao_target->prefix), trace_ipv6(neighbour->ll_address)); + + if (status == SOCKET_TX_DONE) { + /* State_timer is 1/10 s. Set renewal to 75-85% of lifetime */ + if_address_entry_t *address = rpl_interface_addr_get(interface, dao_target->prefix); + if (address) { + address->state_timer = (address->preferred_lifetime * randLIB_get_random_in_range(75, 85) / 10); + } + neighbour->confirmed = true; + dao_target->response_wait_time = 6; + } else { + tr_error("Address registration failed"); + rpl_delete_neighbour(instance, neighbour); + } +} + #endif /* HAVE_RPL */ diff --git a/source/RPL/rpl_downward.h b/source/RPL/rpl_downward.h index 15d40bae7a..a8c66a79b7 100644 --- a/source/RPL/rpl_downward.h +++ b/source/RPL/rpl_downward.h @@ -40,9 +40,10 @@ struct rpl_dao_target *rpl_instance_match_dao_target(struct rpl_instance *instan void rpl_instance_dao_request(struct rpl_instance *instance, struct rpl_neighbour *neighbour); void rpl_instance_dao_trigger(struct rpl_instance *instance, uint16_t delay); void rpl_instance_dao_acked(struct rpl_instance *instance, const uint8_t src[16], int8_t interface_id, uint8_t dao_sequence, uint8_t status); - -void rpl_instance_send_address_registration(protocol_interface_info_entry_t *interface, rpl_instance_t *instance, if_address_entry_t *addr); -bool rpl_instance_address_registration_done(protocol_interface_info_entry_t *interface, rpl_instance_t *instance, if_address_entry_t *addr, uint8_t status); +void rpl_instance_parent_address_reg_timer_update(struct rpl_instance *instance, uint16_t seconds); +void rpl_instance_send_address_registration(rpl_instance_t *instance, const uint8_t addr[16]); +void rpl_instance_address_registration_done(protocol_interface_info_entry_t *interface, rpl_instance_t *instance, rpl_neighbour_t *neighbour, uint8_t status); +struct rpl_dao_target *rpl_instance_get_active_target_confirmation(struct rpl_instance *instance); #ifdef HAVE_RPL_DAO_HANDLING bool rpl_instance_dao_received(struct rpl_instance *instance, const uint8_t src[16], int8_t interface_id, bool multicast, const uint8_t *opts, uint16_t opts_len, uint8_t *status_out); diff --git a/source/RPL/rpl_policy.c b/source/RPL/rpl_policy.c index f31a51ec13..3048898333 100644 --- a/source/RPL/rpl_policy.c +++ b/source/RPL/rpl_policy.c @@ -34,6 +34,8 @@ #define TRACE_GROUP "RPLy" +static bool rpl_policy_parent_confirmation_req = false; + /* TODO - application API to control when to join new instances / DODAGs * * Eg, allow application to ignore local DODAGs, or specify known instance IDs, @@ -318,6 +320,17 @@ uint16_t rpl_policy_mrhof_parent_switch_threshold(const rpl_domain_t *domain) return 192; } +void rpl_policy_set_parent_confirmation_request(bool confirmation_requested) +{ + rpl_policy_parent_confirmation_req = confirmation_requested; +} + + +bool rpl_policy_parent_confirmation_requested(void) +{ + return rpl_policy_parent_confirmation_req; +} + #ifdef RPL_STRUCTURES_H_ #error "rpl_structures.h should not be included by rpl_policy.c" diff --git a/source/RPL/rpl_policy.h b/source/RPL/rpl_policy.h index 469656f474..dc1094e5cd 100644 --- a/source/RPL/rpl_policy.h +++ b/source/RPL/rpl_policy.h @@ -54,5 +54,7 @@ uint_fast8_t rpl_policy_mrhof_parent_set_size(const rpl_domain_t *domain); uint16_t rpl_policy_mrhof_max_link_metric(const rpl_domain_t *domain); uint16_t rpl_policy_mrhof_parent_switch_threshold(const rpl_domain_t *domain); uint16_t rpl_policy_mrhof_max_rank_stretch_for_extra_parents(const rpl_domain_t *domain); +bool rpl_policy_parent_confirmation_requested(void); +void rpl_policy_set_parent_confirmation_request(bool confirmation_requested); #endif /* RPL_POLICY_H_ */ diff --git a/source/RPL/rpl_structures.h b/source/RPL/rpl_structures.h index fac901ccd4..107ff9b6eb 100644 --- a/source/RPL/rpl_structures.h +++ b/source/RPL/rpl_structures.h @@ -52,6 +52,7 @@ struct rpl_neighbour { bool was_dodag_parent: 1; // Was a DODAG parent (used only during parent selection) bool have_global_address: 1; // Global address known bool considered: 1; // Have considered at least once for parent selection + bool confirmed: 1; // Confirmed unsigned dodag_pref: 4; // Preference indication for DODAG parents (0=best) uint8_t dao_path_control; // Path control bit assignments for DAO parent uint8_t old_dao_path_control; @@ -136,6 +137,7 @@ struct rpl_dao_target { uint8_t prefix_len; uint8_t path_sequence; uint8_t path_control; + uint8_t response_wait_time; int8_t interface_id; uint32_t lifetime; /* Seconds */ uint32_t descriptor; /* Target descriptor */ @@ -146,6 +148,8 @@ struct rpl_dao_target { bool descriptor_present: 1; /* Target descriptor specified */ bool need_seq_inc: 1; bool connected: 1; /* We know this target has a path to the root */ + bool trig_confirmation_state: 1; /* Enable confirmation to parent's */ + bool active_confirmation_state: 1; union { #ifdef HAVE_RPL_ROOT rpl_dao_root_t root; /* Info specific to a non-storing root */ @@ -175,12 +179,14 @@ struct rpl_instance { bool dio_not_consistent: 1; /* Something changed - not consistent this period */ bool dao_in_transit: 1; /* If we have a DAO in transit */ bool requested_dao_ack: 1; /* If we requested an ACK (so we retry if no ACK, rather than assuming success) */ + bool pending_neighbour_confirmation: 1; /* if we have not finished address registration state to parent */ uint8_t poison_count; uint8_t repair_dis_count; uint16_t repair_dis_timer; uint32_t last_dao_trigger_time; uint16_t srh_error_count; /* SRH errors since last DAO trigger */ NS_LIST_HEAD(rpl_dodag_t, link) dodags; /* List of DODAGs */ + rpl_neighbour_t *wait_response; rpl_neighbour_list_t candidate_neighbours; /* Candidate neighbour set */ // rpl_neighbour_list_t old_neighbours; /* Old neighbours (without a live DODAG version) */ rpl_dodag_version_t *current_dodag_version; /* Pointer to DODAG version we are a member of (if any) */ diff --git a/source/RPL/rpl_upward.c b/source/RPL/rpl_upward.c index 1f18507dad..625e17ae8b 100644 --- a/source/RPL/rpl_upward.c +++ b/source/RPL/rpl_upward.c @@ -343,6 +343,8 @@ void rpl_instance_trigger_parent_selection(rpl_instance_t *instance, uint16_t de static void rpl_instance_parent_selection_timer(rpl_instance_t *instance, uint16_t seconds) { + + if (instance->parent_selection_timer > seconds) { instance->parent_selection_timer -= seconds; } else if (instance->parent_selection_timer != 0) { @@ -405,6 +407,7 @@ rpl_neighbour_t *rpl_create_neighbour(rpl_dodag_version_t *version, const uint8_ neighbour->g_mop_prf = g_mop_prf; neighbour->dtsn = dtsn; neighbour->dao_path_control = 0; + neighbour->confirmed = 0; /* Need to limit number of neighbours here - chucking worst neighbour */ @@ -423,6 +426,11 @@ rpl_neighbour_t *rpl_create_neighbour(rpl_dodag_version_t *version, const uint8_ void rpl_delete_neighbour(rpl_instance_t *instance, rpl_neighbour_t *neighbour) { + rpl_dao_target_t *dao_target = rpl_instance_get_active_target_confirmation(instance); + if (dao_target && instance->wait_response == neighbour) { + instance->wait_response = NULL; + } + rpl_downward_neighbour_gone(instance, neighbour); ns_list_remove(&instance->candidate_neighbours, neighbour); if (neighbour->dao_path_control) { @@ -1280,7 +1288,7 @@ static void rpl_instance_update_system_dio_route(rpl_instance_t *instance, rpl_n uint8_t metric = ipv6_route_pref_to_metric(pref) + parent->dodag_pref; - ipv6_route_add_metric(route->prefix, route->prefix_len, parent->interface_id, parent->ll_address, ROUTE_RPL_DIO, parent, instance->id, rpl_aged_lifetime(route->lifetime, parent->dio_timestamp), metric); + ipv6_route_add_metric(route->prefix, route->prefix_len, parent->interface_id, parent->ll_address, ROUTE_RPL_DIO, parent, instance->id, route->lifetime, metric); } /* Called when a DIO has been received */ @@ -1290,14 +1298,14 @@ void rpl_dodag_update_implicit_system_routes(rpl_dodag_t *dodag, rpl_neighbour_t return; } - uint32_t aged_default = rpl_aged_lifetime(rpl_default_lifetime(dodag), parent->dio_timestamp); + uint32_t default_lifetime = rpl_default_lifetime(dodag); uint8_t metric = IPV6_ROUTE_DEFAULT_METRIC + parent->dodag_pref; /* Always add the "root" default route - only used for per-instance lookup */ - ipv6_route_add_metric(NULL, 0, parent->interface_id, parent->ll_address, ROUTE_RPL_INSTANCE, parent, dodag->instance->id, aged_default, metric); + ipv6_route_add_metric(NULL, 0, parent->interface_id, parent->ll_address, ROUTE_RPL_INSTANCE, parent, dodag->instance->id, default_lifetime, metric); /* Also add a specific route to the DODAGID */ - ipv6_route_add_metric(dodag->id, 128, parent->interface_id, parent->ll_address, ROUTE_RPL_ROOT, parent, dodag->instance->id, aged_default, metric); + ipv6_route_add_metric(dodag->id, 128, parent->interface_id, parent->ll_address, ROUTE_RPL_ROOT, parent, dodag->instance->id, default_lifetime, metric); } @@ -1365,7 +1373,8 @@ void rpl_instance_run_parent_selection(rpl_instance_t *instance) } ns_list_foreach_safe(rpl_neighbour_t, n, &instance->candidate_neighbours) { - if (rpl_aged_lifetime(rpl_default_lifetime(n->dodag_version->dodag), n->dio_timestamp) == 0) { + //Remove a Parent candidates which are not heared a long time ago and not slected ones + if (!n->dodag_parent && (rpl_aged_lifetime(rpl_default_lifetime(n->dodag_version->dodag), n->dio_timestamp) == 0)) { rpl_delete_neighbour(instance, n); continue; } @@ -1406,6 +1415,9 @@ void rpl_instance_run_parent_selection(rpl_instance_t *instance) if (original_preferred != preferred_parent) { protocol_stats_update(STATS_RPL_PARENT_CHANGE, 1); + if (preferred_parent) { + tr_debug("New preferred parent %s", trace_array(preferred_parent->ll_address, 16)); + } } // Sets new preferred parent @@ -1605,19 +1617,48 @@ uint16_t rpl_instance_current_rank(const rpl_instance_t *instance) return instance->current_rank; } -bool rpl_instance_address_is_parent(rpl_instance_t *instance, const uint8_t *ipv6_addr) +bool rpl_instance_address_is_parent(rpl_instance_t *instance, const uint8_t *ipv6_addr, bool selected) { ns_list_foreach(rpl_neighbour_t, neighbour, &instance->candidate_neighbours) { - if (neighbour->dodag_parent && addr_ipv6_equal(neighbour->ll_address, ipv6_addr)) { - return true; - } - if (!neighbour->dodag_parent) { + if (selected && !neighbour->dodag_parent) { // list is ordered so first encounter of false means no more parents in list return false; } + + if (addr_ipv6_equal(neighbour->ll_address, ipv6_addr)) { + if (!selected) { + return true; + } + if (!neighbour->dodag_parent) { + return false; + } + + return true; + } + } return false; } + +uint16_t rpl_instance_address_candidate_count(rpl_instance_t *instance, bool selected_parents) +{ + uint16_t parent_list = 0; + + ns_list_foreach(rpl_neighbour_t, neighbour, &instance->candidate_neighbours) { + + + if (selected_parents) { + if (neighbour->dodag_parent) { + parent_list++; + } + } else { + parent_list++; + } + } + return parent_list; +} + + void rpl_instance_neighbor_delete(rpl_instance_t *instance, const uint8_t *ipv6_addr) { ns_list_foreach_safe(rpl_neighbour_t, neighbour, &instance->candidate_neighbours) { @@ -1633,6 +1674,8 @@ void rpl_instance_slow_timer(rpl_instance_t *instance, uint16_t seconds) ns_list_foreach(rpl_dodag_t, dodag, &instance->dodags) { rpl_dodag_slow_timer(dodag, seconds); } + + rpl_instance_parent_address_reg_timer_update(instance, seconds); rpl_instance_parent_selection_timer(instance, seconds); if (!rpl_instance_preferred_parent(instance)) { protocol_stats_update(STATS_RPL_TIME_NO_NEXT_HOP, 1); @@ -1665,6 +1708,10 @@ void rpl_upward_dio_timer(rpl_instance_t *instance, uint16_t ticks) if (rpl_dodag_am_leaf(dodag) && !instance->poison_count) { return; } + /* If we are waiting for DAO or DAO registration is needed we dont send periodic DIOs */ + if (instance->dao_in_transit || instance->delay_dao_timer > 0) { + return; + } if (trickle_timer(&instance->dio_timer, &dodag->dio_timer_params, ticks)) { instance->dio_not_consistent = false; rpl_instance_dio_trigger(instance, NULL, NULL); @@ -1845,4 +1892,26 @@ bool rpl_upward_read_dodag_info(const rpl_instance_t *instance, rpl_dodag_info_t return true; } +bool rpl_upward_accept_prefix_update(const rpl_dodag_t *dodag_info, const rpl_neighbour_t *neighbour, const rpl_neighbour_t *pref_parent) +{ + //Accept allways from Pref parent or before it is selected + if (!pref_parent || neighbour == pref_parent) { + return true; + } + + //Accept only same or higher version number + if (rpl_dodag_version_compare(neighbour->dodag_version, pref_parent->dodag_version) & (RPL_CMP_EQUAL | RPL_CMP_GREATER)) { + //Calculate Time between from last dio from parent and this neighbour + //neighbour dio_timestamp >= pref_parent's, because it's a newly-received message + uint32_t time_between_parent = neighbour->dio_timestamp - pref_parent->dio_timestamp; + uint32_t accepted_time = (uint32_t)dodag_info->dio_timer_params.Imax * 2; + //Accept prefix Update If Time from last DIO is more than 2 x Max + if (accepted_time < time_between_parent) { + return true; + } + } + + return false; +} + #endif /* HAVE_RPL */ diff --git a/source/RPL/rpl_upward.h b/source/RPL/rpl_upward.h index b34e15c9c5..3e1146a11e 100644 --- a/source/RPL/rpl_upward.h +++ b/source/RPL/rpl_upward.h @@ -83,7 +83,8 @@ void rpl_instance_dio_trigger(rpl_instance_t *instance, struct protocol_interfac void rpl_instance_set_local_repair(rpl_instance_t *instance, bool repair); bool rpl_instance_local_repair(const rpl_instance_t *instance); uint16_t rpl_instance_current_rank(const rpl_instance_t *instance); -bool rpl_instance_address_is_parent(rpl_instance_t *instance, const uint8_t *ipv6_addr); +bool rpl_instance_address_is_parent(rpl_instance_t *instance, const uint8_t *ipv6_addr, bool selected); +uint16_t rpl_instance_address_candidate_count(rpl_instance_t *instance, bool selected_parents); void rpl_instance_neighbor_delete(rpl_instance_t *instance, const uint8_t *ipv6_addr); void rpl_instance_slow_timer(rpl_instance_t *instance, uint16_t seconds); @@ -139,11 +140,14 @@ void rpl_neighbour_update_dodag_version(rpl_neighbour_t *neighbour, rpl_dodag_ve bool rpl_neighbour_update_dtsn(rpl_neighbour_t *neighbour, uint8_t dtsn); rpl_instance_t *rpl_neighbour_instance(const rpl_neighbour_t *neighbour); + void rpl_instance_neighbours_changed(rpl_instance_t *instance, const rpl_dodag_t *dodag); void rpl_instance_run_parent_selection(rpl_instance_t *instance); void rpl_upward_print_instance(rpl_instance_t *instance, route_print_fn_t *print_fn); bool rpl_upward_read_dodag_info(const rpl_instance_t *instance, struct rpl_dodag_info_t *dodag_info); +bool rpl_upward_accept_prefix_update(const rpl_dodag_t *dodag_info, const rpl_neighbour_t *neighbour, const rpl_neighbour_t *pref_parent); uint16_t rpl_upward_read_dao_target_list_size(const rpl_instance_t *instance, const uint8_t *target_prefix); + #endif /* RPL_UPWARD_H_ */ diff --git a/source/Security/TLS/tls_lib.c b/source/Security/TLS/tls_lib.c index 07146da65c..b4596c9f4a 100644 --- a/source/Security/TLS/tls_lib.c +++ b/source/Security/TLS/tls_lib.c @@ -989,6 +989,7 @@ void tls_server_finnish_handle_start(sec_suite_t *tls_suite) #ifdef PANA_SERVER_API static buffer_t *tls_verify_handler(uint8_t certi_rx, tls_header_t *tls_header_ptr, buffer_t *buf, sec_suite_t *tls_suite) { + (void) certi_rx; tls_heap_t *tls_heap = tls_suite->tls_session->tls_heap; tls_heap->client_verify_buf_len = tls_header_ptr->length; if (tls_heap->client_verify_buf) { diff --git a/source/Security/kmp/kmp_addr.c b/source/Security/kmp/kmp_addr.c index bbff7bdad8..a09ab4ea74 100644 --- a/source/Security/kmp/kmp_addr.c +++ b/source/Security/kmp/kmp_addr.c @@ -33,65 +33,15 @@ #define TRACE_GROUP "kmar" -#define KMP_ADDR_DYN_ALLOC 0x80 -#define KMP_ADDR_TYPE_MASK 0x0F - -typedef struct { - uint8_t type; - uint8_t eui_64[8]; - address_t ip_addr; - uint16_t port; -} kmp_eui_64_ip_addr_t; - -kmp_addr_t *kmp_address_create(kmp_addr_e type, const uint8_t *eui_64) -{ - uint8_t size; - if (type == KMP_ADDR_EUI_64) { - size = sizeof(kmp_addr_t); - } else if (type == KMP_ADDR_EUI_64_AND_IP) { - size = sizeof(kmp_eui_64_ip_addr_t); - } else { - return 0; - } - - kmp_addr_t *addr = ns_dyn_mem_alloc(size); - if (!addr) { - return 0; - } - - kmp_address_init(type, addr, eui_64); - - addr->type |= KMP_ADDR_DYN_ALLOC; - - return addr; -} - void kmp_address_init(kmp_addr_e type, kmp_addr_t *addr, const uint8_t *eui_64) { - uint8_t size; - if (type == KMP_ADDR_EUI_64) { - size = sizeof(kmp_addr_t); - } else if (type == KMP_ADDR_EUI_64_AND_IP) { - size = sizeof(kmp_eui_64_ip_addr_t); - } else { - return; - } - - kmp_addr_t *kmp_addr = addr; - - memset(addr, 0, size); - kmp_addr->type = type; + memset(addr, 0, sizeof(kmp_addr_t)); + addr->type = type; if (eui_64) { - memcpy(kmp_addr->eui_64, eui_64, 8); + memcpy(addr->eui_64, eui_64, 8); } } -void kmp_address_delete(kmp_addr_t *addr) -{ - if (addr && (addr->type & KMP_ADDR_DYN_ALLOC)) { - ns_dyn_mem_free(addr); - } -} const uint8_t *kmp_address_eui_64_get(const kmp_addr_t *addr) { @@ -104,20 +54,11 @@ const uint8_t *kmp_address_eui_64_get(const kmp_addr_t *addr) const uint8_t *kmp_address_ip_get(const kmp_addr_t *addr) { - if (!addr || (addr->type & KMP_ADDR_TYPE_MASK) != KMP_ADDR_EUI_64_AND_IP) { + if (!addr || addr->type != KMP_ADDR_EUI_64_AND_IP) { return NULL; } - return ((kmp_eui_64_ip_addr_t *)addr)->ip_addr; -} - -uint16_t kmp_address_port_get(const kmp_addr_t *addr) -{ - if (!addr || (addr->type & KMP_ADDR_TYPE_MASK) != KMP_ADDR_EUI_64_AND_IP) { - return 0; - } - - return ((kmp_eui_64_ip_addr_t *)addr)->port; + return addr->relay_address; } int8_t kmp_address_eui_64_set(kmp_addr_t *addr, const uint8_t *eui64) @@ -130,26 +71,6 @@ int8_t kmp_address_eui_64_set(kmp_addr_t *addr, const uint8_t *eui64) return 0; } -int8_t kmp_address_ip_set(kmp_addr_t *addr, const uint8_t *ip_addr) -{ - if (!addr || !ip_addr || (addr->type & KMP_ADDR_TYPE_MASK) != KMP_ADDR_EUI_64_AND_IP) { - return -1; - } - - memcpy(((kmp_eui_64_ip_addr_t *)addr)->ip_addr, ip_addr, sizeof(address_t)); - return 0; -} - -int8_t kmp_address_port_set(kmp_addr_t *addr, const uint16_t port) -{ - if (!addr || (addr->type & KMP_ADDR_TYPE_MASK) != KMP_ADDR_EUI_64_AND_IP) { - return -1; - } - - ((kmp_eui_64_ip_addr_t *)addr)->port = port; - return 0; -} - int8_t kmp_address_copy(kmp_addr_t *to_addr, const kmp_addr_t *from_addr) { if (!to_addr || !from_addr) { @@ -158,16 +79,13 @@ int8_t kmp_address_copy(kmp_addr_t *to_addr, const kmp_addr_t *from_addr) memcpy(to_addr->eui_64, from_addr->eui_64, 8); - kmp_eui_64_ip_addr_t *to_ip_addr = (kmp_eui_64_ip_addr_t *) to_addr; - kmp_eui_64_ip_addr_t *from_ip_addr = (kmp_eui_64_ip_addr_t *) from_addr; - - if ((to_ip_addr->type & KMP_ADDR_TYPE_MASK) == KMP_ADDR_EUI_64_AND_IP - && (from_ip_addr->type & KMP_ADDR_TYPE_MASK) == KMP_ADDR_EUI_64_AND_IP) { - memcpy(to_ip_addr->ip_addr, from_ip_addr->ip_addr, sizeof(address_t)); - to_ip_addr->port = from_ip_addr->port; - } else if ((to_ip_addr->type & KMP_ADDR_TYPE_MASK) == KMP_ADDR_EUI_64_AND_IP) { - memset(to_ip_addr->ip_addr, 0, sizeof(address_t)); - to_ip_addr->port = 0; + if (to_addr->type == KMP_ADDR_EUI_64_AND_IP + && from_addr->type == KMP_ADDR_EUI_64_AND_IP) { + memcpy(to_addr->relay_address, from_addr->relay_address, sizeof(address_t)); + to_addr->port = from_addr->port; + } else if (to_addr->type == KMP_ADDR_EUI_64_AND_IP) { + memset(to_addr->relay_address, 0, sizeof(address_t)); + to_addr->port = 0; } return 0; diff --git a/source/Security/kmp/kmp_addr.h b/source/Security/kmp/kmp_addr.h index 967839707c..43b549a77c 100644 --- a/source/Security/kmp/kmp_addr.h +++ b/source/Security/kmp/kmp_addr.h @@ -26,19 +26,10 @@ typedef enum { typedef struct { uint8_t type; uint8_t eui_64[8]; + address_t relay_address; + uint16_t port; } kmp_addr_t; -/** - * kmp_address_create creates address - * - * \param type address type - * \param eui_64 EUI-64 - * - * \return address - * - */ -kmp_addr_t *kmp_address_create(kmp_addr_e type, const uint8_t *eui_64); - /** * kmp_address_init initializes address * @@ -49,13 +40,6 @@ kmp_addr_t *kmp_address_create(kmp_addr_e type, const uint8_t *eui_64); */ void kmp_address_init(kmp_addr_e type, kmp_addr_t *addr, const uint8_t *eui_64); -/** - * kmp_address_delete deletes address - * - * \param addr address - * - */ -void kmp_address_delete(kmp_addr_t *addr); /** * kmp_address_eui_64_get get EUI-64 @@ -77,15 +61,6 @@ const uint8_t *kmp_address_eui_64_get(const kmp_addr_t *addr); */ const uint8_t *kmp_address_ip_get(const kmp_addr_t *addr); -/** - * kmp_address_port_get get port - * - * \param addr address - * - * \return port - * - */ -uint16_t kmp_address_port_get(const kmp_addr_t *addr); /** * kmp_address_eui_64_set set EUI-64 @@ -99,30 +74,6 @@ uint16_t kmp_address_port_get(const kmp_addr_t *addr); */ int8_t kmp_address_eui_64_set(kmp_addr_t *addr, const uint8_t *eui64); -/** - * kmp_address_ip_set set IP address - * - * \param addr address - * \param ip_addr IP address - * - * \return < 0 failure - * \return >= 0 success - * - */ -int8_t kmp_address_ip_set(kmp_addr_t *addr, const uint8_t *ip_addr); - -/** - * kmp_address_port_set set port address - * - * \param addr address - * \param port port - * - * \return < 0 failure - * \return >= 0 success - * - */ -int8_t kmp_address_port_set(kmp_addr_t *addr, const uint16_t port); - /** * kmp_address_copy copies address * diff --git a/source/Security/kmp/kmp_api.c b/source/Security/kmp/kmp_api.c index 479f0d15bb..35d541f156 100644 --- a/source/Security/kmp/kmp_api.c +++ b/source/Security/kmp/kmp_api.c @@ -251,10 +251,10 @@ static void kmp_sec_prot_eui64_addr_get(sec_prot_t *prot, uint8_t *local_eui64, kmp->service->addr_get(kmp->service, kmp, &local_addr, &remote_addr); if (local_eui64) { - memcpy(local_eui64, kmp_address_eui_64_get(&local_addr), 8); + memcpy(local_eui64, local_addr.eui_64, 8); } if (remote_eui64) { - memcpy(remote_eui64, kmp_address_eui_64_get(&remote_addr), 8); + memcpy(remote_eui64, remote_addr.eui_64, 8); } } diff --git a/source/Security/kmp/kmp_socket_if.c b/source/Security/kmp/kmp_socket_if.c index d4dc4a32a8..8bb7f262ba 100644 --- a/source/Security/kmp/kmp_socket_if.c +++ b/source/Security/kmp/kmp_socket_if.c @@ -129,9 +129,9 @@ static int8_t kmp_socket_if_send(kmp_service_t *service, kmp_type_e kmp_id, cons //Build UPD Relay uint8_t *ptr = pdu; - memcpy(ptr, kmp_address_ip_get(addr), 16); + memcpy(ptr, addr->relay_address, 16); ptr += 16; - ptr = common_write_16_bit(kmp_address_port_get(addr), ptr); + ptr = common_write_16_bit(addr->port, ptr); memcpy(ptr, kmp_address_eui_64_get(addr), 8); ptr += 8; *ptr = kmp_id; @@ -169,14 +169,15 @@ static void kmp_socket_if_socket_cb(void *ptr) ns_dyn_mem_free(pdu); return; } - uint8_t *relay_address, *euid64; - uint16_t relay_port; + kmp_addr_t addr; + addr.type = KMP_ADDR_EUI_64_AND_IP; + uint8_t *data_ptr = pdu; - relay_address = data_ptr; + memcpy(addr.relay_address, data_ptr, 16); data_ptr += 16; - relay_port = common_read_16_bit(data_ptr); + addr.port = common_read_16_bit(data_ptr); data_ptr += 2; - euid64 = data_ptr; + memcpy(addr.eui_64, data_ptr, 8); data_ptr += 8; kmp_type_e type = kmp_api_type_from_id_get(*data_ptr++); @@ -185,17 +186,8 @@ static void kmp_socket_if_socket_cb(void *ptr) return; } - kmp_addr_t *addr = kmp_address_create(KMP_ADDR_EUI_64_AND_IP, euid64); - if (!addr) { - ns_dyn_mem_free(pdu); - return; - } - kmp_address_ip_set(addr, relay_address); - kmp_address_port_set(addr, relay_port); - - kmp_service_msg_if_receive(socket_if->kmp_service, type, addr, data_ptr, cb_data->d_len - 27); - kmp_address_delete(addr); + kmp_service_msg_if_receive(socket_if->kmp_service, type, &addr, data_ptr, cb_data->d_len - 27); ns_dyn_mem_free(pdu); } diff --git a/source/Security/protocols/sec_prot_lib.c b/source/Security/protocols/sec_prot_lib.c index ff7d126a25..470d854639 100644 --- a/source/Security/protocols/sec_prot_lib.c +++ b/source/Security/protocols/sec_prot_lib.c @@ -272,7 +272,7 @@ int8_t sec_prot_lib_pmkid_calc(const uint8_t *pmk, const uint8_t *auth_eui64, co const uint8_t pmk_string_val[] = {"PMK Name"}; const uint8_t pmk_string_val_len = sizeof(pmk_string_val) - 1; - const uint8_t data_len = pmk_string_val_len + EUI64_LEN + EUI64_LEN; + uint8_t data_len = pmk_string_val_len + EUI64_LEN + EUI64_LEN; uint8_t data[data_len]; uint8_t *ptr = data; memcpy(ptr, pmk_string_val, pmk_string_val_len); @@ -294,7 +294,7 @@ int8_t sec_prot_lib_ptkid_calc(const uint8_t *ptk, const uint8_t *auth_eui64, co const uint8_t ptk_string_val[] = {"PTK Name"}; const uint8_t ptk_string_val_len = sizeof(ptk_string_val) - 1; - const uint8_t data_len = ptk_string_val_len + EUI64_LEN + EUI64_LEN; + uint8_t data_len = ptk_string_val_len + EUI64_LEN + EUI64_LEN; uint8_t data[data_len]; uint8_t *ptr = data; memcpy(ptr, ptk_string_val, ptk_string_val_len); diff --git a/source/Security/protocols/tls_sec_prot/tls_sec_prot_lib.c b/source/Security/protocols/tls_sec_prot/tls_sec_prot_lib.c index 56f02ab3fe..0232bc3178 100644 --- a/source/Security/protocols/tls_sec_prot/tls_sec_prot_lib.c +++ b/source/Security/protocols/tls_sec_prot/tls_sec_prot_lib.c @@ -97,6 +97,11 @@ static void tls_sec_prot_lib_debug(void *ctx, int level, const char *file, int l #endif #ifdef MBEDTLS_PLATFORM_MEMORY +// Disable for now +//#define TLS_SEC_PROT_LIB_USE_MBEDTLS_PLATFORM_MEMORY +#endif + +#ifdef TLS_SEC_PROT_LIB_USE_MBEDTLS_PLATFORM_MEMORY static void *tls_sec_prot_lib_mem_calloc(size_t count, size_t size); static void tls_sec_prot_lib_mem_free(void *ptr); #endif @@ -105,9 +110,8 @@ int8_t tls_sec_prot_lib_init(tls_security_t *sec) { const char *pers = "ws_tls"; -#ifdef MBEDTLS_PLATFORM_MEMORY - // Disable for now - //mbedtls_platform_set_calloc_free(tls_sec_prot_lib_mem_calloc, tls_sec_prot_lib_mem_free); +#ifdef TLS_SEC_PROT_LIB_USE_MBEDTLS_PLATFORM_MEMORY + mbedtls_platform_set_calloc_free(tls_sec_prot_lib_mem_calloc, tls_sec_prot_lib_mem_free); #endif @@ -497,7 +501,7 @@ static int tls_sec_lib_entropy_poll(void *ctx, unsigned char *output, size_t len return (0); } -#ifdef MBEDTLS_PLATFORM_MEMORY +#ifdef TLS_SEC_PROT_LIB_USE_MBEDTLS_PLATFORM_MEMORY static void *tls_sec_prot_lib_mem_calloc(size_t count, size_t size) { void *mem_ptr = ns_dyn_mem_temporary_alloc(count * size); diff --git a/source/Service_Libs/blacklist/blacklist.c b/source/Service_Libs/blacklist/blacklist.c index a614ed12c1..25d0666638 100644 --- a/source/Service_Libs/blacklist/blacklist.c +++ b/source/Service_Libs/blacklist/blacklist.c @@ -100,7 +100,6 @@ bool blacklist_reject(const uint8_t *ll64_address) tr_debug("blacklist full reject"); return true; } else { - tr_debug("blacklist not found %s", trace_array(ll64_address + 8, 8)); return false; } } @@ -144,7 +143,6 @@ void blacklist_update(const uint8_t *ll64_address, bool success) } /* TTL is blacklist entry lifetime + from 1.0 to 1.5 * interval */ blacklist_entry->ttl = blacklist_data->blacklist_entry_lifetime + randLIB_randomise_base(blacklist_entry->interval, 0x8000, 0xC000); - tr_debug("Blacklist updated, ttl=%"PRIu16, blacklist_entry->ttl); } else { tr_debug("Blacklist add"); blacklist_entry_add(ll64_address + 8); diff --git a/source/Service_Libs/etx/etx.c b/source/Service_Libs/etx/etx.c index 802b85dccd..2e8dcc1cdd 100644 --- a/source/Service_Libs/etx/etx.c +++ b/source/Service_Libs/etx/etx.c @@ -157,7 +157,7 @@ static bool etx_update_possible(etx_sample_storage_t *storage, etx_storage_t *en } } - tr_debug("ETX update possible %u attempts, %u rx ack", storage->attempts_count, storage->received_acks); + //tr_debug("ETX update possible %u attempts, %u rx ack", storage->attempts_count, storage->received_acks); return true; @@ -318,9 +318,6 @@ uint16_t etx_read(int8_t interface_id, addrtype_t addr_type, const uint8_t *addr } attribute_index = mac_neighbor->index; - - //tr_debug("Etx Read from atribute %u", attribute_index); - etx_storage_t *entry = etx_storage_entry_get(interface_id, attribute_index); if (!entry) { @@ -330,8 +327,6 @@ uint16_t etx_read(int8_t interface_id, addrtype_t addr_type, const uint8_t *addr uint16_t etx = etx_current_calc(entry->etx, entry->accumulated_failures); etx >>= 4; - //tr_debug("Etx value %u", etx); - return etx; } @@ -632,7 +627,6 @@ void etx_max_update_set(uint16_t etx_max_update) etx_storage_t *etx_storage_entry_get(int8_t interface_id, uint8_t attribute_index) { if (etx_info.interface_id != interface_id || !etx_info.etx_storage_list || attribute_index >= etx_info.ext_storage_list_size) { - tr_debug("Unknow ID or un initilized ETX %u", attribute_index); return NULL; } @@ -745,7 +739,7 @@ static void etx_accum_failures_callback_needed_check(etx_storage_t *entry, uint8 void etx_neighbor_remove(int8_t interface_id, uint8_t attribute_index) { - tr_debug("Remove attribute %u", attribute_index); + //tr_debug("Remove attribute %u", attribute_index); uint16_t stored_diff_etx; etx_storage_t *entry = etx_storage_entry_get(interface_id, attribute_index); if (entry && etx_info.callback_ptr) { @@ -780,7 +774,7 @@ void etx_neighbor_remove(int8_t interface_id, uint8_t attribute_index) void etx_neighbor_add(int8_t interface_id, uint8_t attribute_index) { - tr_debug("Add attribute %u", attribute_index); + //tr_debug("Add attribute %u", attribute_index); uint16_t stored_diff_etx; etx_storage_t *entry = etx_storage_entry_get(interface_id, attribute_index); if (entry && etx_info.callback_ptr) { @@ -804,12 +798,7 @@ void etx_cache_timer(int8_t interface_id, uint16_t seconds_update) } protocol_interface_info_entry_t *interface = protocol_stack_interface_info_get_by_id(interface_id); - if (!interface) { - return; - } - - - if (!mac_neighbor_info(interface)) { + if (!interface || !mac_neighbor_info(interface)) { return; } diff --git a/source/Service_Libs/fhss/fhss.c b/source/Service_Libs/fhss/fhss.c index 350c9e0e07..511c07aa98 100644 --- a/source/Service_Libs/fhss/fhss.c +++ b/source/Service_Libs/fhss/fhss.c @@ -71,7 +71,7 @@ fhss_structure_t *fhss_enable(fhss_api_t *fhss_api, const fhss_configuration_t * fhss_struct->fhss_event_timer = eventOS_callback_timer_register(fhss_event_timer_cb); fhss_struct->bs->fhss_configuration = *fhss_configuration; - fhss_struct->bs->fhss_stats_ptr = fhss_statistics; + fhss_struct->fhss_stats_ptr = fhss_statistics; fhss_struct->number_of_channels = channel_count; // set a invalid id to tasklet_id, so we know that one is not started yet diff --git a/source/Service_Libs/fhss/fhss.h b/source/Service_Libs/fhss/fhss.h index baf89e6b20..1f09840cbd 100644 --- a/source/Service_Libs/fhss/fhss.h +++ b/source/Service_Libs/fhss/fhss.h @@ -97,7 +97,6 @@ struct fhss_bs { uint16_t channel_list_counter; uint16_t synch_panid; uint32_t synch_interval; - struct fhss_statistics *fhss_stats_ptr; struct fhss_beacon_info *fhss_beacon_info_store; struct fhss_configuration fhss_configuration; struct fhss_synch_configuration synch_configuration; diff --git a/source/Service_Libs/fhss/fhss_common.h b/source/Service_Libs/fhss/fhss_common.h index 1c9dbceb7a..35e1d0cc46 100644 --- a/source/Service_Libs/fhss/fhss_common.h +++ b/source/Service_Libs/fhss/fhss_common.h @@ -48,6 +48,7 @@ struct fhss_structure { struct fhss_ws *ws; struct fhss_timer platform_functions; struct fhss_callback callbacks; + struct fhss_statistics *fhss_stats_ptr; fhss_failed_tx_list_t fhss_failed_tx_list; uint8_t synch_parent[8]; }; diff --git a/source/Service_Libs/fhss/fhss_configuration_interface.c b/source/Service_Libs/fhss/fhss_configuration_interface.c index c1acfc38ac..5ac0f81a4e 100644 --- a/source/Service_Libs/fhss/fhss_configuration_interface.c +++ b/source/Service_Libs/fhss/fhss_configuration_interface.c @@ -24,6 +24,7 @@ #include "Service_Libs/fhss/fhss.h" #include "Service_Libs/fhss/fhss_common.h" #include "Service_Libs/fhss/fhss_ws.h" +#include "Service_Libs/fhss/fhss_statistics.h" #include "ns_trace.h" #define TRACE_GROUP "fhss" @@ -138,3 +139,12 @@ int ns_fhss_ws_set_hop_count(const fhss_api_t *fhss_api, const uint8_t hop_count } return fhss_ws_set_hop_count(fhss_structure, hop_count); } + +int ns_fhss_statistics_start(const fhss_api_t *fhss_api, fhss_statistics_t *fhss_statistics) +{ + fhss_structure_t *fhss_structure = fhss_get_object_with_api(fhss_api); + if (!fhss_structure) { + return -1; + } + return fhss_statistics_start(fhss_structure, fhss_statistics); +} diff --git a/source/Service_Libs/fhss/fhss_statistics.c b/source/Service_Libs/fhss/fhss_statistics.c index 2ab1702ed5..b4ee75c48f 100644 --- a/source/Service_Libs/fhss/fhss_statistics.c +++ b/source/Service_Libs/fhss/fhss_statistics.c @@ -24,23 +24,35 @@ void fhss_stats_update(fhss_structure_t *fhss_structure, fhss_stats_type_t type, uint32_t update_val) { - if (fhss_structure->bs->fhss_stats_ptr) { + if (fhss_structure->fhss_stats_ptr) { switch (type) { case STATS_FHSS_DRIFT_COMP: - fhss_structure->bs->fhss_stats_ptr->fhss_drift_compensation = update_val; + fhss_structure->fhss_stats_ptr->fhss_drift_compensation = update_val; break; case STATS_FHSS_HOP_COUNT: - fhss_structure->bs->fhss_stats_ptr->fhss_hop_count = update_val; + fhss_structure->fhss_stats_ptr->fhss_hop_count = update_val; break; case STATS_FHSS_SYNCH_INTERVAL: - fhss_structure->bs->fhss_stats_ptr->fhss_synch_interval = update_val; + fhss_structure->fhss_stats_ptr->fhss_synch_interval = update_val; break; case STATS_FHSS_AVG_SYNCH_FIX: - fhss_structure->bs->fhss_stats_ptr->fhss_prev_avg_synch_fix = update_val; + fhss_structure->fhss_stats_ptr->fhss_prev_avg_synch_fix = update_val; break; case STATS_FHSS_SYNCH_LOST: - fhss_structure->bs->fhss_stats_ptr->fhss_synch_lost += update_val; + fhss_structure->fhss_stats_ptr->fhss_synch_lost += update_val; + break; + case STATS_FHSS_UNKNOWN_NEIGHBOR: + fhss_structure->fhss_stats_ptr->fhss_unknown_neighbor += update_val; + break; + case STATS_FHSS_CHANNEL_RETRY: + fhss_structure->fhss_stats_ptr->fhss_channel_retry += update_val; break; } } } + +int fhss_statistics_start(fhss_structure_t *fhss_structure, fhss_statistics_t *fhss_statistics) +{ + fhss_structure->fhss_stats_ptr = fhss_statistics; + return 0; +} diff --git a/source/Service_Libs/fhss/fhss_statistics.h b/source/Service_Libs/fhss/fhss_statistics.h index 42ddaa0af1..bd2f81eaef 100644 --- a/source/Service_Libs/fhss/fhss_statistics.h +++ b/source/Service_Libs/fhss/fhss_statistics.h @@ -23,8 +23,11 @@ typedef enum { STATS_FHSS_SYNCH_INTERVAL, STATS_FHSS_AVG_SYNCH_FIX, STATS_FHSS_SYNCH_LOST, + STATS_FHSS_UNKNOWN_NEIGHBOR, + STATS_FHSS_CHANNEL_RETRY } fhss_stats_type_t; void fhss_stats_update(fhss_structure_t *fhss_structure, fhss_stats_type_t type, uint32_t update_val); +int fhss_statistics_start(fhss_structure_t *fhss_structure, fhss_statistics_t *fhss_statistics); #endif /* FHSS_STATISTICS_H_ */ diff --git a/source/Service_Libs/fhss/fhss_ws.c b/source/Service_Libs/fhss/fhss_ws.c index 7cf0cd9473..8d4f159ee4 100644 --- a/source/Service_Libs/fhss/fhss_ws.c +++ b/source/Service_Libs/fhss/fhss_ws.c @@ -20,6 +20,7 @@ #include "fhss_config.h" #include "fhss.h" #include "fhss_common.h" +#include "fhss_statistics.h" #include "channel_list.h" #include "channel_functions.h" #include "fhss_ws.h" @@ -143,7 +144,7 @@ fhss_structure_t *fhss_ws_enable(fhss_api_t *fhss_api, const fhss_ws_configurati fhss_struct->fhss_event_timer = eventOS_callback_timer_register(fhss_event_timer_cb); fhss_struct->ws->fhss_configuration = *fhss_configuration; fhss_struct->number_of_channels = channel_count; - fhss_struct->own_hop = 0xff; + fhss_ws_set_hop_count(fhss_struct, 0xff); fhss_struct->rx_channel = fhss_configuration->unicast_fixed_channel; fhss_struct->ws->min_synch_interval = DEFAULT_MIN_SYNCH_INTERVAL; fhss_set_txrx_slot_length(fhss_struct); @@ -472,6 +473,7 @@ static int fhss_ws_tx_handle_callback(const fhss_api_t *api, bool is_broadcast_a if (fhss_structure->fhss_state == FHSS_SYNCHRONIZED) { fhss_ws_neighbor_timing_info_t *neighbor_timing_info = fhss_structure->ws->get_neighbor_info(api, destination_address); if (!neighbor_timing_info) { + fhss_stats_update(fhss_structure, STATS_FHSS_UNKNOWN_NEIGHBOR, 1); return -2; } // TODO: WS bootstrap has to store neighbors number of channels @@ -687,6 +689,7 @@ static bool fhss_ws_data_tx_fail_callback(const fhss_api_t *api, uint8_t handle, // Create new failure handle and return true to retransmit fhss_failed_handle_add(fhss_structure, handle, fhss_structure->rx_channel); } + fhss_stats_update(fhss_structure, STATS_FHSS_CHANNEL_RETRY, 1); return true; } @@ -858,9 +861,11 @@ int fhss_ws_set_parent(fhss_structure_t *fhss_structure, const uint8_t eui64[8], drift_per_ms_tmp = -MAX_DRIFT_COMPENSATION_STEP; } fhss_structure->ws->drift_per_millisecond_ns += drift_per_ms_tmp; + fhss_stats_update(fhss_structure, STATS_FHSS_DRIFT_COMP, NS_TO_US(fhss_structure->ws->drift_per_millisecond_ns * bc_timing_info->broadcast_dwell_interval)); } tr_debug("synch to parent: %s, drift: %"PRIi32"ms in %"PRIu32" seconds, compensation: %"PRIi32"ns per ms", trace_array(eui64, 8), true_bc_interval_offset - own_bc_interval_offset + ((int32_t)(fhss_structure->ws->bc_slot - own_bc_slot) * bc_timing_info->broadcast_interval), US_TO_S(time_since_last_synch_us), fhss_structure->ws->drift_per_millisecond_ns); } + fhss_stats_update(fhss_structure, STATS_FHSS_SYNCH_INTERVAL, US_TO_S(time_since_last_synch_us)); return 0; } @@ -915,6 +920,8 @@ int fhss_ws_configuration_set(fhss_structure_t *fhss_structure, const fhss_ws_co int fhss_ws_set_hop_count(fhss_structure_t *fhss_structure, const uint8_t hop_count) { fhss_structure->own_hop = hop_count; + fhss_stats_update(fhss_structure, STATS_FHSS_HOP_COUNT, fhss_structure->own_hop); return 0; } + #endif // HAVE_WS diff --git a/source/Service_Libs/mac_neighbor_table/mac_neighbor_table.c b/source/Service_Libs/mac_neighbor_table/mac_neighbor_table.c index 89ebcce39e..3f1960fb5b 100644 --- a/source/Service_Libs/mac_neighbor_table/mac_neighbor_table.c +++ b/source/Service_Libs/mac_neighbor_table/mac_neighbor_table.c @@ -26,8 +26,6 @@ #include "Core/include/ns_address_internal.h" #include "platform/topo_trace.h" -#define TRACE_GROUP "mnei" - mac_neighbor_table_t *mac_neighbor_table_create(uint8_t table_size, neighbor_entry_remove_notify *remove_cb, neighbor_entry_nud_notify *nud_cb, void *user_indentifier) { mac_neighbor_table_t *table_class = ns_dyn_mem_alloc(sizeof(mac_neighbor_table_t) + sizeof(mac_neighbor_table_entry_t) * table_size); @@ -111,11 +109,9 @@ void mac_neighbor_table_neighbor_timeout_update(mac_neighbor_table_t *table_clas if (table_class->user_nud_notify_cb(cur, table_class->table_user_identifier)) { table_class->active_nud_process++; cur->nud_active = true; - tr_debug("Nud started index %u : %"PRIu32" time ", cur->index, cur->lifetime); } } else { - tr_debug("Node index %u time out ", cur->index); neighbor_table_class_remove_entry(table_class, cur); } } @@ -176,7 +172,6 @@ void mac_neighbor_table_neighbor_refresh(mac_neighbor_table_t *table_class, mac_ neighbor_entry->lifetime = life_time; neighbor_entry->link_lifetime = life_time; if (neighbor_entry->nud_active) { - tr_debug("Node index NUD response %u : %"PRIu32" time ", neighbor_entry->index, neighbor_entry->lifetime); neighbor_entry->nud_active = false; table_class->active_nud_process--; } diff --git a/source/Service_Libs/utils/ns_conf.c b/source/Service_Libs/utils/ns_conf.c new file mode 100644 index 0000000000..54ebbbe8a8 --- /dev/null +++ b/source/Service_Libs/utils/ns_conf.c @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2017-2018, Arm Limited and affiliates. + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "nsconfig.h" +#include "ns_types.h" + +#include "Core/include/ns_monitor.h" +#include "mac_api.h" // for mcps_packet_ingress_rate_limit_by_memory +#include "MAC/IEEE802_15_4/mac_mcps_sap.h" // for mcps_packet_ingress_rate_limit_by_memory + +int ns_conf_gc_threshold_set(uint8_t percentage_high, uint8_t percentage_critical) +{ + return ns_monitor_heap_gc_threshold_set(percentage_high, percentage_critical); +} + +int ns_conf_packet_ingress_rate_limit_by_mem(uint8_t free_heap_percentage) +{ + return mcps_packet_ingress_rate_limit_by_memory(free_heap_percentage); +} diff --git a/source/ipv6_stack/ipv6_routing_table.c b/source/ipv6_stack/ipv6_routing_table.c index d51eb029d3..711159c4d5 100644 --- a/source/ipv6_stack/ipv6_routing_table.c +++ b/source/ipv6_stack/ipv6_routing_table.c @@ -303,9 +303,15 @@ ipv6_neighbour_t *ipv6_neighbour_lookup_or_create(ipv6_neighbour_cache_t *cache, { uint_fast16_t count = 0; ipv6_neighbour_t *entry = NULL; + ipv6_neighbour_t *garbage_possible_entry = NULL; ns_list_foreach(ipv6_neighbour_t, cur, &cache->list) { - count++; + + if (cur->type == IP_NEIGHBOUR_GARBAGE_COLLECTIBLE) { + garbage_possible_entry = cur; + count++; + } + if (addr_ipv6_equal(cur->ip_address, address)) { if (cur != ns_list_get_first(&cache->list)) { ns_list_remove(&cache->list, cur); @@ -315,9 +321,9 @@ ipv6_neighbour_t *ipv6_neighbour_lookup_or_create(ipv6_neighbour_cache_t *cache, } } - if (count >= neighbour_cache_config.max_entries) { - entry = ns_list_get_last(&cache->list); - ipv6_neighbour_entry_remove(cache, entry); + if (count >= neighbour_cache_config.max_entries && garbage_possible_entry) { + //Remove Last storaged IP_NEIGHBOUR_GARBAGE_COLLECTIBLE type entry + ipv6_neighbour_entry_remove(cache, garbage_possible_entry); } // Allocate new - note we have a basic size, plus enough for the LL address, @@ -1066,6 +1072,23 @@ void ipv6_destination_redirect(const uint8_t *dest_addr, const uint8_t *sender_a } #endif +void ipv6_destination_cache_forced_gc(bool full_gc) +{ + int gc_count = ns_list_count(&ipv6_destination_cache); + + /* Minimize size of destination cache: + * - keep absolutely minimum number of entries if not full gc + * - clear all entries in case of full gc + **/ + ns_list_foreach_reverse_safe(ipv6_destination_t, entry, &ipv6_destination_cache) { + if (entry->lifetime == 0 || gc_count > destination_cache_config.long_term_entries || full_gc) { + ns_list_remove(&ipv6_destination_cache, entry); + ipv6_destination_release(entry); + gc_count--; + } + } +} + static void ipv6_destination_release(ipv6_destination_t *dest) { if (--dest->refcount == 0) { diff --git a/source/ipv6_stack/ipv6_routing_table.h b/source/ipv6_stack/ipv6_routing_table.h index 291077527b..944439843e 100644 --- a/source/ipv6_stack/ipv6_routing_table.h +++ b/source/ipv6_stack/ipv6_routing_table.h @@ -73,7 +73,7 @@ typedef enum ipv6_route_src { ROUTE_RPL_DAO, /* Explicitly advertised in DAO, Storing mode */ ROUTE_RPL_DAO_SR, /* Explicitly advertised in DAO, Root Source Routes in Non-Storing mode */ ROUTE_RPL_SRH, /* Not in routing table - used in buffers to represent on-link inferred from SRH */ - ROUTE_RPL_ROOT, /* Implicit route to DODAG route */ + ROUTE_RPL_ROOT, /* Implicit route to DODAG root */ ROUTE_RPL_INSTANCE, /* Implicit instance-specific default upward route (not for general search) */ ROUTE_RPL_FWD_ERROR, /* Not in routing table - used in buffers to represent Forwarding-Error bounce */ ROUTE_MULTICAST, /* Not in routing table - used to represent multicast interface selection */ @@ -222,6 +222,7 @@ void ipv6_destination_cache_timer(uint8_t ticks); #ifdef HAVE_IPV6_ND void ipv6_destination_redirect(const uint8_t *dest_addr, const uint8_t *sender_addr, const uint8_t *redirect_addr, int8_t interface_id, addrtype_t ll_type, const uint8_t *ll_address); #endif +void ipv6_destination_cache_forced_gc(bool full_gc); /* Combined Routing Table (RFC 4191) and Prefix List (RFC 4861) */ /* On-link prefixes have the on_link flag set and next_hop is unset */ diff --git a/source/libDHCPv6/dhcp_service_api.c b/source/libDHCPv6/dhcp_service_api.c index b784904dd8..5356eda2fb 100644 --- a/source/libDHCPv6/dhcp_service_api.c +++ b/source/libDHCPv6/dhcp_service_api.c @@ -828,6 +828,8 @@ void dhcp_service_send_message(msg_tr_t *msg_tr_ptr) } if (retval != 0) { tr_warn("dhcp service socket_sendto fails: %i", retval); + } else { + tr_warn("dhcp service socket_sendto %s", trace_ipv6(msg_tr_ptr->addr.address)); } } bool dhcp_service_timer_tick(uint16_t ticks) diff --git a/source/libDHCPv6/libDHCPv6.c b/source/libDHCPv6/libDHCPv6.c index 53beaaadc3..5b7b3ffb8b 100644 --- a/source/libDHCPv6/libDHCPv6.c +++ b/source/libDHCPv6/libDHCPv6.c @@ -208,7 +208,7 @@ dhcpv6_client_server_data_t *libdhcpv6_nonTemporal_entry_get_by_transactionId(ui dhcpv6_client_server_data_t *libdhcpv6_nonTemporal_entry_get_by_prefix(int8_t interfaceId, uint8_t *prefix) { ns_list_foreach(dhcpv6_client_server_data_t, cur, &dhcpv6_client_nonTemporal_list) { - if ((cur->interfaceId == interfaceId)) { + if (cur->interfaceId == interfaceId) { if (memcmp(cur->iaNontemporalAddress.addressPrefix, prefix, 8) == 0) { return cur; } diff --git a/sources.mk b/sources.mk index f71f088bdf..40c75cbe0b 100644 --- a/sources.mk +++ b/sources.mk @@ -39,6 +39,7 @@ SRCS += \ source/6LoWPAN/ws/ws_eapol_auth_relay.c \ source/6LoWPAN/ws/ws_eapol_relay_lib.c \ source/6LoWPAN/ws/ws_eapol_pdu.c \ + source/6LoWPAN/ws/ws_stats.c \ source/BorderRouter/border_router.c \ source/Common_Protocols/icmpv6.c \ source/Common_Protocols/icmpv6_prefix.c \ @@ -51,6 +52,7 @@ SRCS += \ source/Common_Protocols/tcp.c \ source/Common_Protocols/udp.c \ source/Core/ns_address_internal.c \ + source/Core/ns_monitor.c \ source/Core/buffer_dyn.c \ source/Core/sockbuf.c \ source/Core/ns_socket.c \ @@ -195,6 +197,7 @@ SRCS += \ source/Service_Libs/utils/ns_crc.c \ source/Service_Libs/utils/isqrt.c \ source/Service_Libs/utils/ns_file_system.c \ + source/Service_Libs/utils/ns_conf.c \ source/Service_Libs/mdns/ns_mdns_api.c \ source/Service_Libs/mdns/ns_fnet_port.c \ source/Service_Libs/mdns/ns_fnet_events.c \