diff --git a/nanostack/net_interface.h b/nanostack/net_interface.h index e4b07583a04..ac3a48c4c66 100644 --- a/nanostack/net_interface.h +++ b/nanostack/net_interface.h @@ -995,6 +995,7 @@ extern void net_get_version_information(uint8_t *ptr); * * Note! In Thread mode parent buffer size is automatically set during Thread initialization. * + * \param interface_id Network interface ID. * \param big_packet_threshold Indicate how long packets are considered big. For Thread, must be 106 bytes. * \param small_packets_per_child_count Number of small packets stored for each sleepy children. For Thread, must be at least 1. * \param big_packets_total_count Total number of big packets parent can store for all sleepy children. For Thread, must be at least 1. diff --git a/nanostack/net_test_api.h b/nanostack/net_test_api.h index 8b797df305b..78b2898da23 100644 --- a/nanostack/net_test_api.h +++ b/nanostack/net_test_api.h @@ -24,6 +24,7 @@ #define NET_TEST_API_H_ #include "ns_types.h" +#include "Service_Libs/mle_service/mle_service_api.h" /** * \brief Makes TCP protocol drop given number of packets from a particular state (TX side). @@ -56,4 +57,11 @@ int8_t arm_nwk_test_tcp_drop_rx(int state, uint8_t count); */ void arm_nwk_test_tcp_drop_reset(void); +/** + * \brief Set callback for MLE message receiving filter. + * + * Testing API for setting MLE receive callback for message filtering purposes. + */ +void arm_nwk_test_mle_receive_filter_set(mle_service_filter_cb *response_filter_cb); + #endif //NET_TEST_API_H_ diff --git a/nanostack/net_thread_test.h b/nanostack/net_thread_test.h index 1751be8ad77..648fb79a3d7 100644 --- a/nanostack/net_thread_test.h +++ b/nanostack/net_thread_test.h @@ -274,6 +274,19 @@ int thread_test_increment_key_sequence_counter(int8_t interface_id); */ int thread_test_key_sequence_counter_update(int8_t interface_id, uint32_t thrKeySequenceCounter); +/** + * \brief Resets cached values from stack + * + Resets link configuration from cache and from NVM. + * + * + * \param interface_id Network Interface + * + * \return 0, OK + * \return <0 Error + */ +int thread_test_stack_cache_reset(int8_t interface_id); + /** * \brief Set new Thread key rotation value * diff --git a/source/6LoWPAN/Bootstraps/Generic/protocol_6lowpan_bootstrap.c b/source/6LoWPAN/Bootstraps/Generic/protocol_6lowpan_bootstrap.c index 06dbf49f417..4be6abcc281 100644 --- a/source/6LoWPAN/Bootstraps/Generic/protocol_6lowpan_bootstrap.c +++ b/source/6LoWPAN/Bootstraps/Generic/protocol_6lowpan_bootstrap.c @@ -758,7 +758,7 @@ static int mle_router_accept_request_build(protocol_interface_info_entry_t *cur, static void protocol_6lowpan_link_reject_handler(protocol_interface_info_entry_t *cur, uint8_t *ll64) { - mle_neigh_table_entry_t *entry_temp = mle_class_get_entry_by_ll64(cur->id, 0, ll64, false); + mle_neigh_table_entry_t *entry_temp = mle_class_get_entry_by_ll64(cur->id, 0, ll64, false, NULL); tr_debug("MLE link reject"); if (entry_temp) { mle_class_remove_entry(cur->id, entry_temp); @@ -1081,7 +1081,7 @@ void mle_6lowpan_message_handler(int8_t interface_id, mle_message_t *mle_msg, ml mle_6lowpan_data->link_req_token_bucket--; } else { //Update only old information based on link request - entry_temp = mle_class_get_entry_by_ll64(interface_id, linkMargin, mle_msg->packet_src_address, false); + entry_temp = mle_class_get_entry_by_ll64(interface_id, linkMargin, mle_msg->packet_src_address, false, NULL); if (entry_temp) { mle_neigh_time_and_mode_update(entry_temp,mle_msg->data_ptr, mle_msg->data_length); mle_neigh_entry_update_by_mle_tlv_list(interface_id, entry_temp, mle_msg->data_ptr, mle_msg->data_length, cur->mac, own_mac16); @@ -1118,12 +1118,12 @@ void mle_6lowpan_message_handler(int8_t interface_id, mle_message_t *mle_msg, ml tr_debug("Accept & Request"); - entry_temp = mle_class_get_entry_by_ll64(interface_id, linkMargin, mle_msg->packet_src_address, false); + entry_temp = mle_class_get_entry_by_ll64(interface_id, linkMargin, mle_msg->packet_src_address, false, NULL); if (!entry_temp) { // If there is space for neighbors try to allocate new entry if (mle_6lowpan_neighbor_limit_check(interface_id, mle_msg, true)) { - entry_temp = mle_class_get_entry_by_ll64(interface_id, linkMargin, mle_msg->packet_src_address, true); + entry_temp = mle_class_get_entry_by_ll64(interface_id, linkMargin, mle_msg->packet_src_address, true, NULL); } } @@ -1185,7 +1185,7 @@ void mle_6lowpan_message_handler(int8_t interface_id, mle_message_t *mle_msg, ml mode = *t_ptr; } - entry_temp = mle_class_get_entry_by_ll64(interface_id, linkMargin, mle_msg->packet_src_address, false); + entry_temp = mle_class_get_entry_by_ll64(interface_id, linkMargin, mle_msg->packet_src_address, false, NULL); if (!entry_temp) { if ((mode & MLE_DEV_MASK) == MLE_FFD_DEV) { // If there is space for neighbors synchronizes to new router @@ -2787,7 +2787,7 @@ bool lowpan_neighbour_data_clean(int8_t interface_id, const uint8_t *link_local_ { bool return_value = false; #ifndef NO_MLE - mle_neigh_table_entry_t * neigh_entry = mle_class_get_entry_by_ll64(interface_id, 0, link_local_address, false); + mle_neigh_table_entry_t * neigh_entry = mle_class_get_entry_by_ll64(interface_id, 0, link_local_address, false, NULL); if (neigh_entry) { //Remove entry if (neigh_entry->priorityFlag) { diff --git a/source/6LoWPAN/Bootstraps/Generic/protocol_6lowpan_interface.c b/source/6LoWPAN/Bootstraps/Generic/protocol_6lowpan_interface.c index 854f11b0017..478d86ecafb 100644 --- a/source/6LoWPAN/Bootstraps/Generic/protocol_6lowpan_interface.c +++ b/source/6LoWPAN/Bootstraps/Generic/protocol_6lowpan_interface.c @@ -87,7 +87,10 @@ static int8_t set_6lowpan_nwk_down(protocol_interface_info_entry_t *cur) #endif } } - uint16_t pan_id = cur->mac_parameters->pan_id; + if (cur->lowpan_info & INTERFACE_NWK_BOOTSRAP_PANA_AUTHENTICATION) { + pana_reset_values(cur->mac_parameters->pan_id); + } + if (cur->interface_mode == INTERFACE_UP) { if (cur->mac_api) { mlme_reset_t reset; @@ -105,9 +108,6 @@ static int8_t set_6lowpan_nwk_down(protocol_interface_info_entry_t *cur) reassembly_interface_reset(cur->id); icmp_nd_routers_init(); - if (cur->lowpan_info & INTERFACE_NWK_BOOTSRAP_PANA_AUTHENTICATION) { - pana_reset_values(pan_id); - } if (cur->pana_sec_info_temp) { ns_dyn_mem_free(cur->pana_sec_info_temp); diff --git a/source/6LoWPAN/MAC/mac_helper.c b/source/6LoWPAN/MAC/mac_helper.c index d26140937b1..faf954010d1 100644 --- a/source/6LoWPAN/MAC/mac_helper.c +++ b/source/6LoWPAN/MAC/mac_helper.c @@ -433,8 +433,9 @@ void mac_helper_coordinator_address_set(protocol_interface_info_entry_t *interfa if (adr_type == ADDR_802_15_4_SHORT) { memcpy(interface->mac_parameters->mac_cordinator_info.mac_mlme_coord_address, adr_ptr, 2); interface->mac_parameters->mac_cordinator_info.cord_adr_mode = MAC_ADDR_MODE_16_BIT; + uint16_t short_addr = common_read_16_bit(interface->mac_parameters->mac_cordinator_info.mac_mlme_coord_address); set_req.attr = macCoordShortAddress; - set_req.value_pointer = &interface->mac_parameters->mac_cordinator_info.mac_mlme_coord_address; + set_req.value_pointer = &short_addr; set_req.value_size = 2; } else if (adr_type == ADDR_802_15_4_LONG) { memcpy(interface->mac_parameters->mac_cordinator_info.mac_mlme_coord_address, adr_ptr, 8); @@ -767,8 +768,10 @@ static uint8_t mac_helper_header_security_aux_header_length(uint8_t keyIdmode) { switch (keyIdmode) { case MAC_KEY_ID_MODE_SRC8_IDX: header_length += 4; //64-bit key source first part + /* fall through */ case MAC_KEY_ID_MODE_SRC4_IDX: header_length += 4; //32-bit key source inline + /* fall through */ case MAC_KEY_ID_MODE_IDX: header_length += 1; break; @@ -830,13 +833,13 @@ void mac_helper_devicetable_remove(mac_api_t *mac_api, uint8_t attribute_index) mac_api->mlme_req(mac_api,MLME_SET , &set_req); } -void mac_helper_devicetable_set(mle_neigh_table_entry_t *entry_temp, protocol_interface_info_entry_t *cur, uint32_t frame_counter, uint8_t keyID) +void mac_helper_devicetable_set(mle_neigh_table_entry_t *entry_temp, protocol_interface_info_entry_t *cur, uint32_t frame_counter, uint8_t keyID, bool force_set) { if (!cur->mac_api) { return; } - if (cur->mac_parameters->SecurityEnabled && cur->mac_parameters->mac_default_key_index != keyID) { + if (!force_set && cur->mac_parameters->SecurityEnabled && cur->mac_parameters->mac_default_key_index != keyID) { tr_debug("Do not set counter by index %u != %u", cur->mac_parameters->mac_default_key_index, keyID); return; } diff --git a/source/6LoWPAN/MAC/mac_helper.h b/source/6LoWPAN/MAC/mac_helper.h index 28ea5331c3d..a1fe37cd681 100644 --- a/source/6LoWPAN/MAC/mac_helper.h +++ b/source/6LoWPAN/MAC/mac_helper.h @@ -110,7 +110,7 @@ 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_set(struct mle_neigh_table_entry_t *entry_temp, struct protocol_interface_info_entry *cur, uint32_t frame_counter, uint8_t keyID); +void mac_helper_devicetable_set(struct mle_neigh_table_entry_t *entry_temp, struct protocol_interface_info_entry *cur, uint32_t frame_counter, uint8_t keyID, bool force_set); int8_t mac_helper_mac_mlme_max_retry_set(int8_t interface_id, uint8_t mac_retry_set); diff --git a/source/6LoWPAN/MAC/mac_pairwise_key.c b/source/6LoWPAN/MAC/mac_pairwise_key.c index 8a53457fac9..bb37e137fd6 100644 --- a/source/6LoWPAN/MAC/mac_pairwise_key.c +++ b/source/6LoWPAN/MAC/mac_pairwise_key.c @@ -252,6 +252,8 @@ int mac_pairwise_key_interface_unregister(int8_t interface_id) int mac_pairwise_key_add(int8_t interface_id, uint32_t valid_life_time, const uint8_t eui64[static 8], const uint8_t key[static 16]) { protocol_interface_info_entry_t *interface = protocol_stack_interface_info_get_by_id(interface_id); + bool new_entry_created; + if (!interface || !interface->mac_api) { return -1; } @@ -264,7 +266,7 @@ int mac_pairwise_key_add(int8_t interface_id, uint32_t valid_life_time, const ui } //Allocate mle entry - mle_neigh_table_entry_t *mle_entry = mle_class_get_entry_by_mac64(interface_id, 0, eui64, true); + mle_neigh_table_entry_t *mle_entry = mle_class_get_entry_by_mac64(interface_id, 0, eui64, true, &new_entry_created); if (!mle_entry) { return -1; } @@ -282,7 +284,7 @@ int mac_pairwise_key_add(int8_t interface_id, uint32_t valid_life_time, const ui } //Set device descriptor - mac_helper_devicetable_set(mle_entry, interface, 0, interface->mac_parameters->mac_default_key_index); + mac_helper_devicetable_set(mle_entry, interface, 0, interface->mac_parameters->mac_default_key_index, new_entry_created); //set key descriptor if (mac_helper_security_pairwisekey_set(interface, key, eui64, key_desc->key_decriptor_attribute) != 0) { @@ -308,7 +310,7 @@ int mac_pairwise_key_del(int8_t interface_id, const uint8_t eui64[static 8]) return -1; } //Get from mle - mle_neigh_table_entry_t *mle_entry = mle_class_get_entry_by_mac64(interface_id, 0, eui64, true); + mle_neigh_table_entry_t *mle_entry = mle_class_get_entry_by_mac64(interface_id, 0, eui64, true, NULL); if (!mle_entry) { return -1; } diff --git a/source/6LoWPAN/Thread/thread_bbr_api.c b/source/6LoWPAN/Thread/thread_bbr_api.c index acdaa2c4536..0e0fc04d116 100644 --- a/source/6LoWPAN/Thread/thread_bbr_api.c +++ b/source/6LoWPAN/Thread/thread_bbr_api.c @@ -738,7 +738,7 @@ static bool thread_bbr_activated(thread_bbr_t *this, uint32_t seconds) return true; } // We will try to become router. This is done only in 120 seconds intervals if failed - thread_router_bootstrap_router_id_request(cur, 0); + thread_router_bootstrap_router_id_request(cur, THREAD_BBR_ROUTER_ID_REQUEST_STATUS); this->router_upgrade_delay_timer = 120; return false; } @@ -755,8 +755,8 @@ bool thread_bbr_routing_enabled(protocol_interface_info_entry_t *cur) void thread_bbr_network_data_update_notify(protocol_interface_info_entry_t *cur) { - (void) cur; thread_mdns_network_data_update_notify(); + thread_extension_bbr_route_update(cur); } #endif /* HAVE_THREAD_BORDER_ROUTER*/ diff --git a/source/6LoWPAN/Thread/thread_bootstrap.c b/source/6LoWPAN/Thread/thread_bootstrap.c index 20953819364..3f746d20d1a 100644 --- a/source/6LoWPAN/Thread/thread_bootstrap.c +++ b/source/6LoWPAN/Thread/thread_bootstrap.c @@ -63,6 +63,7 @@ #include "6LoWPAN/Thread/thread_network_synch.h" #include "6LoWPAN/Thread/thread_joiner_application.h" #include "6LoWPAN/Thread/thread_extension.h" +#include "6LoWPAN/Thread/thread_extension_bbr.h" #include "6LoWPAN/Thread/thread_management_client.h" #include "6LoWPAN/Thread/thread_address_registration_client.h" #include "6LoWPAN/Thread/thread_joiner_application.h" @@ -112,7 +113,6 @@ static void thread_bootsrap_network_discovery_failure(int8_t interface_id); static void thread_neighbor_remove(int8_t interface_id, mle_neigh_table_entry_t *cur); static void thread_bootsrap_network_join_start(struct protocol_interface_info_entry *cur_interface, discovery_response_list_t *nwk_info); -static int8_t thread_child_keep_alive(int8_t interface_id, const uint8_t *mac64); @@ -134,37 +134,6 @@ static void thread_neighbor_remove(int8_t interface_id, mle_neigh_table_entry_t thread_reset_neighbour_info(cur_interface, cur); } - -static bool thread_child_keep_alive_callback(int8_t interface_id, uint16_t msgId, bool usedAllRetries) -{ - uint8_t mac64[8]; - uint8_t *ll64_ptr = mle_service_get_msg_destination_address_pointer(msgId); - - memcpy(mac64, ll64_ptr + 8, 8); - mac64[0] ^= 2; - - mle_neigh_table_entry_t *neig_info = mle_class_get_by_link_address(interface_id, mac64, ADDR_802_15_4_LONG); - - if (!neig_info) { - return false;//Why entry is removed before timeout?? - } - - - if (neig_info->ttl > MLE_TABLE_CHALLENGE_TIMER) { - return false; - } - - - if (usedAllRetries) { - - //GET entry - mle_class_remove_entry(interface_id, neig_info); - return false; - } - - return true; -} - int8_t thread_mle_class_init(int8_t interface_id) { protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(interface_id); @@ -182,7 +151,7 @@ int8_t thread_mle_class_init(int8_t interface_id) return -1; } - if (mle_class_init(interface_id, buffer.device_decription_table_size - 1, &thread_neighbor_remove, &thread_child_keep_alive, &thread_interface_is_active) != 0) { + if (mle_class_init(interface_id, buffer.device_decription_table_size - 1, &thread_neighbor_remove, &thread_host_bootstrap_child_update, &thread_interface_is_active) != 0) { return -1; } @@ -231,68 +200,6 @@ uint8_t thread_mode_get_by_interface_ptr(protocol_interface_info_entry_t *cur) return mle_mode; } -static int8_t thread_child_keep_alive(int8_t interface_id, const uint8_t *mac64) -{ - mle_message_timeout_params_t timeout; - uint8_t ll64[16]; - protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(interface_id); - uint32_t keySequence; - uint16_t bufId; - uint8_t mode; - if (!cur) { - return -1; - } - - if (!thread_info(cur)) { - return -1; - } - - //routers do not send keep alive - if (thread_i_am_router(cur)){ - return -1; - } - - tr_debug("Child Keep Alive"); - bufId = mle_service_msg_allocate(cur->id, 150 + 3 + 6 + 10, false,MLE_COMMAND_CHILD_UPDATE_REQUEST); - if (bufId == 0) { - return -1; - } - - thread_management_get_current_keysequence(cur->id, &keySequence); - mle_service_msg_update_security_params(bufId, 5, 2, keySequence); - mode = thread_mode_get_by_interface_ptr(cur); - - uint8_t *ptr = mle_service_get_data_pointer(bufId); - ptr = mle_general_write_source_address(ptr, cur); - ptr = mle_tlv_write_mode(ptr, mode); - - ptr = thread_leader_data_tlv_write(ptr, cur); - - //Set Addresss TLV - if ((mode & MLE_FFD_DEV) == 0) { - ptr = thread_address_registration_tlv_write(ptr, cur); - } - - memcpy(ll64, ADDR_LINK_LOCAL_PREFIX, 8); - memcpy(&ll64[8], mac64, 8); - ll64[8] ^= 2; - if (mle_service_update_length_by_ptr(bufId,ptr)!= 0) { - tr_debug("Buffer overflow at message write"); - } - timeout.retrans_max = 3; - timeout.timeout_init = 1; - timeout.timeout_max = 4; - timeout.delay = MLE_NO_DELAY; - - //SET Destination address - mle_service_set_msg_destination_address(bufId, ll64); - //Set Callback - mle_service_set_packet_callback(bufId, thread_child_keep_alive_callback); - mle_service_set_msg_timeout_parameters(bufId, &timeout); - mle_service_send_message(bufId); - return 0; -} - /** * Return lower (worse) of the two margins. */ @@ -419,17 +326,24 @@ int thread_bootstrap_partition_process(protocol_interface_info_entry_t *cur, uin tr_debug("Dropping advertisement from old partition without sequence number increase"); return -2; } - if (heard_partition_routers == 0 && active_routers == 1) { - //heard a REED and I am in a singleton partition so merge - tr_debug("Heard a REED and I am a singleton - merge"); - return 2; - } + /*Rule 0: If we are going to form Higher partition than heard we dont try to attach to lower ones */ if (thread_extension_enabled(cur) && - thread_info(cur)->thread_device_mode == THREAD_DEVICE_MODE_ROUTER && - heard_partition_leader_data->weighting < thread_info(cur)->partition_weighting) { - return -2; + thread_info(cur)->thread_device_mode == THREAD_DEVICE_MODE_ROUTER) { + if (heard_partition_leader_data->weighting < thread_info(cur)->partition_weighting) { + tr_debug("Heard a lower weight partition"); + return -2; + } + if (heard_partition_leader_data->weighting > thread_info(cur)->partition_weighting) { + return 2; + } + } + + if ((heard_partition_routers == 0 && active_routers == 1) && thread_am_router(cur)) { + //heard a REED and I am a lonely router in a singleton partition, so merge + tr_debug("Heard a REED and I am a singleton - merge"); + return 2; } //Rule 1: A non-singleton Thread Network Partition always has higher priority than a singleton Thread Network Partition @@ -768,6 +682,8 @@ int thread_configuration_thread_activate(protocol_interface_info_entry_t *cur, l thread_extension_activate(cur); + thread_extension_bbr_route_update(cur); + blacklist_clear(); blacklist_params_set( @@ -1014,6 +930,7 @@ static void thread_interface_bootsrap_mode_init(protocol_interface_info_entry_t cur->thread_info->thread_device_mode = THREAD_DEVICE_MODE_SLEEPY_END_DEVICE; //SET Sleepy Host To RX on Idle mode for bootsrap nwk_thread_host_control(cur, NET_HOST_RX_ON_IDLE, 0); + cur->thread_info->childUpdateReqTimer = 0.8 * cur->thread_info->host_link_timeout; } else { tr_debug("Set End node Mode"); cur->thread_info->thread_device_mode = THREAD_DEVICE_MODE_END_DEVICE; @@ -1134,7 +1051,9 @@ void thread_tasklet(arm_event_s *event) case THREAD_CHILD_UPDATE: tr_debug_extra("Thread SM THREAD_CHILD_UPDATE"); - thread_bootstrap_child_update(cur); + if (thread_info(cur)->thread_endnode_parent) { + thread_host_bootstrap_child_update(cur->id, cur->thread_info->thread_endnode_parent->mac64); + } break; case THREAD_ANNOUNCE_ACTIVE: { tr_debug_extra("Thread SM THREAD_ANNOUNCE_ACTIVE"); @@ -1245,14 +1164,14 @@ void thread_bootstrap_ready(protocol_interface_info_entry_t *cur) mac_data_poll_protocol_poll_mode_decrement(cur); } -void thread_clean_all_routers_from_neighbor_list(int8_t interface_id) +void thread_neighbor_list_clean(struct protocol_interface_info_entry *cur) { - mle_neigh_table_list_t *neig_list = mle_class_active_list_get(interface_id); - /* Init Double linked Routing Table */ - ns_list_foreach_safe(mle_neigh_table_entry_t, cur, neig_list) { - if (thread_is_router_addr(cur->short_adr)) { - tr_debug("Free Router %x", cur->short_adr); - mle_class_remove_entry(interface_id, cur); + mle_neigh_table_list_t *neig_list = mle_class_active_list_get(cur->id); + + ns_list_foreach_safe(mle_neigh_table_entry_t, cur_entry, neig_list) { + if (!thread_addr_is_equal_or_child(cur->thread_info->routerShortAddress, cur_entry->short_adr)) { + tr_debug("Free ID %x", cur_entry->short_adr); + mle_class_remove_entry(cur->id, cur_entry); } } } @@ -1751,6 +1670,23 @@ bool thread_network_data_timeout(int8_t interface_id, uint16_t msgId, bool usedA return true; } + if(cur->thread_info->leader_synced) { + if(usedAllRetries) { + // could not learn network data from neighbour, everyone must reregister + cur->thread_info->leader_synced = false; + thread_leader_service_network_data_changed(cur,true,true); + return false; + } else { + tr_debug("retrying as leader data not yet synced"); + return true; + } + } + + // if REED fails to get updated network data, it reattaches + if (thread_info(cur)->networkDataRequested && !thread_attach_active_router(cur) && usedAllRetries) { + thread_bootstrap_reset_restart(interface_id); + } + thread_info(cur)->networkDataRequested = false; mac_data_poll_protocol_poll_mode_decrement(cur); return false; @@ -1876,7 +1812,7 @@ static void thread_dhcp_client_gua_error_cb(int8_t interface, uint8_t dhcp_addr[ } } -static bool thread_dhcpv6_address_valid(uint8_t *prefixPtr, if_address_list_t *list) +bool thread_dhcpv6_address_entry_available(uint8_t *prefixPtr, if_address_list_t *list) { bool addressReady = false; ns_list_foreach(if_address_entry_t, entry, list) { @@ -2333,21 +2269,7 @@ void thread_bootstrap_stop(protocol_interface_info_entry_t *cur) void thread_bootstrap_child_update_trig(protocol_interface_info_entry_t *cur) { - if (cur->thread_info->thread_attached_state == THREAD_STATE_CONNECTED) { - if (cur->thread_info->thread_endnode_parent == NULL) { - return; - } - - if (cur->thread_info->thread_endnode_parent->childUpdateProcessActive) { - //Set Pending if earlier proces is already started - cur->thread_info->thread_endnode_parent->childUpdatePending = true; - return; - } - //Trig event - cur->thread_info->thread_endnode_parent->childUpdatePending = false; - cur->thread_info->thread_endnode_parent->childUpdateProcessActive = true; - cur->thread_info->thread_endnode_parent->childUpdateProcessStatus = false; - + if (cur->thread_info->thread_attached_state == THREAD_STATE_CONNECTED && cur->thread_info->thread_endnode_parent) { thread_bootsrap_event_trig(THREAD_CHILD_UPDATE, cur->bootStrapId, ARM_LIB_HIGH_PRIORITY_EVENT); } } @@ -2584,8 +2506,8 @@ int thread_bootstrap_network_data_process(protocol_interface_info_entry_t *cur, memcpy(addr, cur->thread_info->threadPrivatePrefixInfo.ulaPrefix, 8); memcpy(&addr[8], ADDR_SHORT_ADR_SUFFIC, 6); common_write_16_bit(genericService.routerID, &addr[14]); - thread_dhcp_client_global_address_delete(cur->id, addr, prefixTlv.Prefix); tr_debug("Delete DHCPv6 given address"); + thread_dhcp_client_global_address_delete(cur->id, addr, prefixTlv.Prefix); } } @@ -2812,7 +2734,7 @@ void thread_bootstrap_network_prefixes_process(protocol_interface_info_entry_t * bool validToLearnRoutes, validToLearOnMeshRoute; thread_network_server_data_entry_t *weHostService = NULL; uint16_t routerId; - tr_debug("Network Data:"); + tr_debug("Network Data process:"); routerId = cur->mac_parameters->mac_short_address; thread_network_data_cache_entry_t *networkData; networkData = &cur->thread_info->networkDataStorage; @@ -2875,14 +2797,14 @@ void thread_bootstrap_network_prefixes_process(protocol_interface_info_entry_t * } } - if (!thread_dhcpv6_address_valid(curPrefix->servicesPrefix, &cur->ip_addresses)) { + if (!thread_dhcpv6_address_entry_available(curPrefix->servicesPrefix, &cur->ip_addresses)) { thread_addr_write_mesh_local_16(addr, curBorderRouter->routerID, cur->thread_info); - + /* Do not allow multiple DHCP solicits from one prefix => delete previous */ + thread_dhcp_client_global_address_delete(cur->id, NULL, curPrefix->servicesPrefix); if (thread_dhcp_client_get_global_address(cur->id, addr, curPrefix->servicesPrefix, cur->mac, thread_dhcp_client_gua_error_cb) == 0) { tr_debug("GP Address Requested"); } } - } else { /* All end device types perform RLOC16 -> 0xfffe replacement if stable network data was requested. */ @@ -2895,7 +2817,7 @@ void thread_bootstrap_network_prefixes_process(protocol_interface_info_entry_t * } if (curBorderRouter->P_preferred) { - if (!thread_dhcpv6_address_valid(curPrefix->servicesPrefix, &cur->ip_addresses)) { + if (!thread_dhcpv6_address_entry_available(curPrefix->servicesPrefix, &cur->ip_addresses)) { icmpv6_slaac_address_add(cur, curPrefix->servicesPrefix, curPrefix->servicesPrefixLen, 0xffffffff, 0xffffffff, true, SLAAC_IID_DEFAULT); } } diff --git a/source/6LoWPAN/Thread/thread_bootstrap.h b/source/6LoWPAN/Thread/thread_bootstrap.h index 09b07918521..517321704b0 100644 --- a/source/6LoWPAN/Thread/thread_bootstrap.h +++ b/source/6LoWPAN/Thread/thread_bootstrap.h @@ -106,7 +106,7 @@ void thread_general_mle_receive_cb(int8_t interface_id, mle_message_t *mle_msg, int thread_bootstrap_reset_child_info(protocol_interface_info_entry_t *cur, struct mle_neigh_table_entry_t *child); void thread_bootstrap_ready(struct protocol_interface_info_entry *cur); int thread_bootstrap_reset(struct protocol_interface_info_entry *cur); -void thread_clean_all_routers_from_neighbor_list(int8_t interface_id); +void thread_neighbor_list_clean(struct protocol_interface_info_entry *cur); bool thread_bootstrap_request_network_data(struct protocol_interface_info_entry *cur, struct thread_leader_data_s *leaderData, uint16_t short_address); bool thread_check_is_this_my_parent(struct protocol_interface_info_entry *cur, struct mle_neigh_table_entry_t *entry_temp); void thread_clean_old_16_bit_address_based_addresses(struct protocol_interface_info_entry *cur); diff --git a/source/6LoWPAN/Thread/thread_border_router_api.c b/source/6LoWPAN/Thread/thread_border_router_api.c index 00bdc848410..acad9e474cf 100644 --- a/source/6LoWPAN/Thread/thread_border_router_api.c +++ b/source/6LoWPAN/Thread/thread_border_router_api.c @@ -884,9 +884,20 @@ int thread_border_router_publish(int8_t interface_id) tr_debug("Border router old: %x, new: %x", cur->thread_info->localServerDataBase.registered_rloc16, rloc16); if (cur->thread_info->localServerDataBase.publish_active) { - cur->thread_info->localServerDataBase.publish_pending = true; - tr_debug("Activate pending status for publish"); - return 0; + if (rloc16 != cur->thread_info->localServerDataBase.registered_rloc16) { + /* + * Device short address has changed, cancel previous a/sd and a/as requests + * and start resubmit timer + * */ + tr_debug("address changed, kill pending reuqests"); + thread_management_client_pending_coap_request_kill(cur->id); + thread_border_router_resubmit_timer_set(interface_id, 5); + return 0; + } else { + cur->thread_info->localServerDataBase.publish_pending = true; + tr_debug("Activate pending status for publish"); + return 0; + } } //Allocate Memory for Data diff --git a/source/6LoWPAN/Thread/thread_common.c b/source/6LoWPAN/Thread/thread_common.c index 1ef5e4e60d9..db166f84cec 100644 --- a/source/6LoWPAN/Thread/thread_common.c +++ b/source/6LoWPAN/Thread/thread_common.c @@ -233,8 +233,8 @@ int8_t thread_bootstrap_down(protocol_interface_info_entry_t *cur) tr_debug("SET thread Idle"); //stop polling mac_data_poll_disable(cur); - //Clean routers from mle table - thread_clean_all_routers_from_neighbor_list(cur->id); + //Clean mle table + thread_neighbor_list_clean(cur); // store frame counters if (cur->thread_info) { thread_nvm_fast_data_t fast_data; @@ -249,6 +249,7 @@ int8_t thread_bootstrap_down(protocol_interface_info_entry_t *cur) thread_joiner_application_configuration_nvm_save(cur->id); mac_pairwise_key_flush_list(cur->id); thread_discovery_reset(cur->id); + thread_leader_mleid_rloc_map_to_nvm_write(cur); thread_bootstrap_stop(cur); mle_service_interface_unregister(cur->id); thread_management_server_delete(cur->id); @@ -524,6 +525,7 @@ thread_leader_info_t *thread_allocate_and_init_leader_private_data(void) thread_leader_info_t *leader_info = ns_dyn_mem_alloc(sizeof(thread_leader_info_t)); if (leader_info) { leader_info->leader_id_seq_timer = ID_SEQUENCE_PERIOD; + leader_info->leader_nvm_sync_timer = 0; } return leader_info; } @@ -717,6 +719,7 @@ void thread_child_id_request_info_init(thread_pending_child_id_req_t *child_info thread_pending_child_id_req_t *thread_child_id_request_allocate(void) { thread_pending_child_id_req_t *req = ns_dyn_mem_alloc(sizeof(thread_pending_child_id_req_t)); + memset(req->eiid, 0 , 8); thread_child_id_request_info_init(req); return req; } @@ -880,7 +883,6 @@ static void thread_child_update_req_timer(protocol_interface_info_entry_t *cur, if (cur->thread_info->childUpdateReqTimer == -1) { return; } - if (cur->thread_info->childUpdateReqTimer > seconds) { cur->thread_info->childUpdateReqTimer -= seconds; } else { @@ -1712,7 +1714,8 @@ uint8_t *thread_address_registration_tlv_write(uint8_t *ptr, protocol_interface_ // Maximum length of address registrations continue; } - if (addr_ipv6_scope(e->address, cur) == IPV6_SCOPE_GLOBAL) { + if (addr_ipv6_scope(e->address, cur) == IPV6_SCOPE_GLOBAL || (addr_ipv6_scope(e->address, cur) == IPV6_SCOPE_REALM_LOCAL + && !thread_addr_is_mesh_local_16(e->address, cur))) { ctx = lowpan_context_get_by_address(&cur->lowpan_contexts, e->address); if (ctx) { //Write TLV to list @@ -1725,7 +1728,6 @@ uint8_t *thread_address_registration_tlv_write(uint8_t *ptr, protocol_interface_ memcpy(ptr, e->address, 16); ptr += 16; *address_len_ptr += 17; - } } } @@ -1838,7 +1840,7 @@ static void thread_tx_failure_handler(int8_t nwk_id, uint8_t accumulated_failure } if (accumulated_failures >= THREAD_MAC_TRANSMISSIONS*THREAD_FAILED_CHILD_TRANSMISSIONS) { - thread_reset_neighbour_info(cur, neighbor); + mle_class_remove_entry(cur->id, neighbor); } } @@ -1848,8 +1850,8 @@ void thread_reset_neighbour_info(protocol_interface_info_entry_t *cur, mle_neigh thread_parent_info_t *thread_endnode_parent = thread_info(cur)->thread_endnode_parent; if (!thread_i_am_router(cur) && thread_endnode_parent && thread_endnode_parent->shortAddress == neighbour->short_adr) { - tr_warn("End device lost Parent!\n"); if(cur->nwk_bootstrap_state != ER_CHILD_ID_REQ) { + tr_warn("End device lost parent, reset!\n"); thread_bootstrap_connection_error(cur->id, CON_PARENT_CONNECT_DOWN, NULL); } } diff --git a/source/6LoWPAN/Thread/thread_common.h b/source/6LoWPAN/Thread/thread_common.h index 9cadc1b5ed3..b06b9454e44 100644 --- a/source/6LoWPAN/Thread/thread_common.h +++ b/source/6LoWPAN/Thread/thread_common.h @@ -48,6 +48,8 @@ */ #define ROUTER_ID_REUSE_DELAY 100 //Seconds +#define LEADER_NVM_SYNC_DELAY 30 // Leader router ids write delay to NVM + #define ROUTER_ID_INFINITY_DELAY 90 //Seconds #define NETWORK_ID_TIMEOUT 120 //seconds @@ -145,6 +147,7 @@ typedef struct thread_leader_info_s { uint8_t leader_id_seq_timer; uint8_t master_router_id_mask[8]; uint8_t maskSeq; + uint8_t leader_nvm_sync_timer; } thread_leader_info_t; typedef struct thread_leader_data_s { @@ -174,7 +177,6 @@ typedef struct thread_parent_info_s { uint8_t pathCostToLeader; bool childUpdatePending: 1; bool childUpdateProcessActive: 1; - bool childUpdateProcessStatus: 1; } thread_parent_info_t; @@ -287,8 +289,10 @@ typedef struct thread_info_s { uint16_t native_commissioner_port; uint16_t routerShortAddress; uint16_t reedJitterTimer; + uint16_t reedMergeAdvTimer; uint16_t routerIdReqCoapID; // COAP msg id of RouterID request int16_t childUpdateReqTimer; + uint16_t childUpdateReqMsgId; uint16_t proactive_an_timer; //uint8_t lastValidRouteMask[8]; int8_t interface_id; //Thread Interface ID diff --git a/source/6LoWPAN/Thread/thread_config.h b/source/6LoWPAN/Thread/thread_config.h index 55243dc4a83..ca689a004f2 100644 --- a/source/6LoWPAN/Thread/thread_config.h +++ b/source/6LoWPAN/Thread/thread_config.h @@ -31,6 +31,10 @@ #ifndef THREAD_CONFIG_H_ #define THREAD_CONFIG_H_ +/** + * Thread stack configuration values. All constants that are specified in Thread specification can be found from thread_constants.h + */ + #include "thread_constants.h" /** @@ -307,6 +311,21 @@ */ #define THREAD_PROACTIVE_AN_SEND_DELAY 2 +/* + * Parent response wait time (in 100ms) when "R" bit is set in scan mask TLV (rounded up from 0.75 seconds) + */ +#define THREAD_PARENT_REQ_SCANMASK_R_TIMEOUT 9 + +/* + * Parent response wait time (in 100ms) when both "R" and "E" bit is set in scan mask TLV (rounded up from 1.25 seconds) + */ +#define THREAD_PARENT_REQ_SCANMASK_RE_TIMEOUT 15 + +/* + * When BBR is started, router address is requested from leader with following status + */ +#define THREAD_BBR_ROUTER_ID_REQUEST_STATUS THREAD_COAP_STATUS_TLV_HAVE_CHILD_ID_REQUEST + /** * Build time flag to enable THCI special traces for test harness purposes */ diff --git a/source/6LoWPAN/Thread/thread_constants.h b/source/6LoWPAN/Thread/thread_constants.h index a854791ffa7..978606b360b 100644 --- a/source/6LoWPAN/Thread/thread_constants.h +++ b/source/6LoWPAN/Thread/thread_constants.h @@ -31,7 +31,7 @@ #define THREAD_CONSTANTS_H_ /** - * Constants defined in Thread specifications + * Constants defined in Thread specifications. All configured values are defined in thread_config.h */ /** @@ -164,7 +164,7 @@ #define THREAD_ENTERPRISE_NUMBER 44970 -#define THREAD_ADDR_REG_TIMEOUT_BASE 300 +#define THREAD_ADDR_REG_RETRY_INTERVAL 300 #define THREAD_PROACTIVE_AN_INTERVAL 3600 // Router defines @@ -174,6 +174,10 @@ #define MIN_DOWNGRADE_NEIGHBORS 7 #define THREAD_REED_ADVERTISEMENT_DELAY 5000 +// Interval after which REED can send an advertisement to help others merge to higher partition. +// This is not related to default REED advertisements. +#define THREAD_REED_MERGE_ADVERTISEMENT_INTERVAL 120 + /** Default Threshold for router Selection */ #define ROUTER_DOWNGRADE_THRESHOLD 23 // Define downGrade Threshold when active router is higher than this #define ROUTER_UPGRADE_THRESHOLD 16 // Define upgrade Threshold fort REED when Active Router Count is smaller than this upgrade is possible diff --git a/source/6LoWPAN/Thread/thread_dhcpv6_client.c b/source/6LoWPAN/Thread/thread_dhcpv6_client.c index 7005b52336c..642857bdd70 100644 --- a/source/6LoWPAN/Thread/thread_dhcpv6_client.c +++ b/source/6LoWPAN/Thread/thread_dhcpv6_client.c @@ -135,6 +135,13 @@ int dhcp_solicit_resp_cb(uint16_t instance_id, void *ptr, uint8_t msg_name, uin tr_error("Sol Not include all Options"); goto error_exit; } + + if (libdhcpv6_nonTemporal_entry_get_by_iaid(dhcp_ia_non_temporal_params.iaId) != srv_data_ptr) { + /* Validate server data availability */ + tr_error("Valid instance not found"); + goto error_exit; + } + if (srv_data_ptr->IAID != dhcp_ia_non_temporal_params.iaId) { tr_error("Wrong IAID"); goto error_exit; @@ -181,7 +188,9 @@ int thread_dhcp_client_get_global_address(int8_t interface, uint8_t dhcp_addr[st tr_error("Invalid parameters"); return -1; } + srv_data_ptr = libdhcvp6_nontemporalAddress_server_data_allocate(interface, dhcp_client.libDhcp_instance, mac64, DHCPV6_DUID_HARDWARE_EUI64_TYPE, prefix, dhcp_addr); + payload_len = libdhcpv6_solication_message_length(DHCPV6_DUID_HARDWARE_EUI64_TYPE, true, 0); payload_ptr = ns_dyn_mem_temporary_alloc(payload_len); @@ -207,6 +216,7 @@ int thread_dhcp_client_get_global_address(int8_t interface, uint8_t dhcp_addr[st srv_data_ptr->transActionId = dhcp_service_send_req(dhcp_client.service_instance, 0, srv_data_ptr , dhcp_addr, payload_ptr, payload_len, dhcp_solicit_resp_cb); return srv_data_ptr->transActionId ? 0 : -1; } + void thread_dhcp_client_global_address_renew(int8_t interface) { // only prepared for changes in thread specifications @@ -219,15 +229,23 @@ void thread_dhcp_client_global_address_delete(int8_t interface, uint8_t dhcp_add protocol_interface_info_entry_t *cur; dhcpv6_client_server_data_t *srv_data_ptr; (void) dhcp_addr; + srv_data_ptr = libdhcpv6_nonTemporal_entry_get_by_prefix(interface, prefix); cur = protocol_stack_interface_info_get_by_id(interface); - if (cur == NULL || srv_data_ptr == NULL) { - tr_error("Not valid prefix"); - return; - } - 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); + + do { + if (cur == NULL || srv_data_ptr == NULL) { + return; + } + dhcp_service_req_remove(srv_data_ptr->transActionId);// remove all pending retransmissions + tr_debug("Deleting address: %s", trace_ipv6(srv_data_ptr->iaNontemporalAddress.addressPrefix)); + + addr_delete(cur, srv_data_ptr->iaNontemporalAddress.addressPrefix); + + libdhcvp6_nontemporalAddress_server_data_free(srv_data_ptr); + srv_data_ptr = libdhcpv6_nonTemporal_entry_get_by_prefix(interface, prefix); + } while (srv_data_ptr); + return; } @@ -306,7 +324,7 @@ void thread_dhcpv6_client_set_address(int8_t interface_id, dhcpv6_client_server_ if (address_entry == NULL) { tr_error("Address add failed"); - return ; + return; } if (renewTimer) { // translate seconds to 100ms ticks @@ -316,7 +334,6 @@ void thread_dhcpv6_client_set_address(int8_t interface_id, dhcpv6_client_server_ renewTimer = 0xfffffffe; } } - tr_debug("Added new address"); address_entry->state_timer = renewTimer; address_entry->cb = thread_dhcpv6_renew; } diff --git a/source/6LoWPAN/Thread/thread_discovery.c b/source/6LoWPAN/Thread/thread_discovery.c index ab552ccd17e..b9e484f341a 100644 --- a/source/6LoWPAN/Thread/thread_discovery.c +++ b/source/6LoWPAN/Thread/thread_discovery.c @@ -817,6 +817,12 @@ static void thread_discovery_request_msg_handler(thread_discovery_class_t * disc } tr_debug("Thread discovery request message RX"); + // Check if we have room for new neighbor + if (mle_class_free_entry_count_get(discovery_class->interface_id) < 1) { + tr_debug("MLE table full, skip request"); + return; + } + //validate message mle_tlv_info_t discovery_tlv; //Parse Message diff --git a/source/6LoWPAN/Thread/thread_extension_bbr.h b/source/6LoWPAN/Thread/thread_extension_bbr.h index 7f973799054..5e4ac8f8c15 100644 --- a/source/6LoWPAN/Thread/thread_extension_bbr.h +++ b/source/6LoWPAN/Thread/thread_extension_bbr.h @@ -38,15 +38,30 @@ extern "C" { #endif +#if defined(HAVE_THREAD_V2) && defined(HAVE_THREAD_BORDER_ROUTER) + +int8_t thread_extension_bbr_init(int8_t interface_id, int8_t backbone_interface_id); +void thread_extension_bbr_delete(int8_t interface_id); +bool thread_extension_bbr_nd_query_process(protocol_interface_info_entry_t *cur, const uint8_t *target_addr, uint16_t rloc); +void thread_extension_bbr_seconds_timer(int8_t interface_id, uint32_t seconds); +int thread_extension_bbr_timeout_set(int8_t interface_id, uint32_t timeout_a, uint32_t timeout_b, uint32_t delay); +int thread_extension_bbr_address_set(int8_t interface_id, const uint8_t *addr_ptr, uint16_t port); +void thread_extension_bbr_route_update(protocol_interface_info_entry_t *cur); + + +#else + #define thread_extension_bbr_init(interface_id, backbone_interface_id) #define thread_extension_bbr_delete(interface_id) -#define thread_extension_bbr_nd_query_process(cur, target_addr) false +#define thread_extension_bbr_nd_query_process(cur, target_addr, rloc) false #define thread_extension_bbr_seconds_timer(interface_id, seconds) #define thread_extension_bbr_timeout_set(interface_id, timeout_a, timeout_b, delay) #define thread_extension_bbr_address_set(interface_id, addr_ptr, port) (-1) +#define thread_extension_bbr_route_update(cur) +#endif #ifdef __cplusplus } #endif -#endif /* THREAD_EXTENSION_BBR_H_ */ +#endif //HAVE_THREAD_BORDER_ROUTER && HAVE_THREAD_V2 diff --git a/source/6LoWPAN/Thread/thread_host_bootstrap.c b/source/6LoWPAN/Thread/thread_host_bootstrap.c index 9f5e5bd5dc1..b1cf6441477 100644 --- a/source/6LoWPAN/Thread/thread_host_bootstrap.c +++ b/source/6LoWPAN/Thread/thread_host_bootstrap.c @@ -88,7 +88,6 @@ static int thread_parent_request_build(protocol_interface_info_entry_t *cur); static int thread_attach_child_id_request_build(protocol_interface_info_entry_t *cur); static int thread_end_device_synch_response_validate(protocol_interface_info_entry_t *cur, uint8_t *ptr, uint16_t data_length, uint8_t linkMargin, uint8_t *src_address, mle_security_header_t *securityHeader); -static uint8_t *thread_single_address_registration_tlv_write(uint8_t *ptr, lowpan_context_t *ctx, uint8_t *addressPtr); static int8_t thread_end_device_synch_start(protocol_interface_info_entry_t *cur); @@ -122,18 +121,17 @@ static void thread_merge_prepare(protocol_interface_info_entry_t *cur) { thread_clean_old_16_bit_address_based_addresses(cur); mpl_clear_realm_scope_seeds(cur); - ipv6_neighbour_cache_flush(&cur->ipv6_neighbour_cache); ipv6_route_table_remove_info(cur->id, ROUTE_THREAD_PROXIED_HOST, NULL); - thread_routing_deactivate(&cur->thread_info->routing); - thread_routing_init(&cur->thread_info->routing); - cur->nwk_mode = ARM_NWK_GP_IP_MODE; + thread_old_partition_data_purge(cur); thread_network_data_clean(cur); + cur->nwk_mode = ARM_NWK_GP_IP_MODE; } //This function is for Thread Parent scan callback static bool thread_parent_discover_timeout_cb(int8_t interface_id, uint16_t msgId, bool usedAllRetries) { protocol_interface_info_entry_t *cur; + bool new_entry_created; cur = protocol_stack_interface_info_get_by_id(interface_id); if (!cur) { @@ -159,7 +157,7 @@ static bool thread_parent_discover_timeout_cb(int8_t interface_id, uint16_t msgI memcpy(&ll64[8], parent->mac64 , 8); ll64[8] ^= 2; - entry_temp = mle_class_get_entry_by_ll64(interface_id, parent->linkMarginToParent,ll64, true); + entry_temp = mle_class_get_entry_by_ll64(interface_id, parent->linkMarginToParent,ll64, true, &new_entry_created); if (entry_temp == NULL) { return false; } @@ -172,7 +170,7 @@ static bool thread_parent_discover_timeout_cb(int8_t interface_id, uint16_t msgI thread_management_key_sets_calc(cur, linkConfiguration, cur->thread_info->thread_attach_scanned_parent->keySequence); thread_calculate_key_guard_timer(cur, linkConfiguration, true); - mac_helper_devicetable_set(entry_temp, cur, parent->linLayerFrameCounter, mac_helper_default_key_index_get(cur)); + mac_helper_devicetable_set(entry_temp, cur, parent->linLayerFrameCounter, mac_helper_default_key_index_get(cur), new_entry_created); mle_entry_timeout_update(entry_temp, THREAD_DEFAULT_LINK_LIFETIME); if (cur->thread_info->thread_device_mode == THREAD_DEVICE_MODE_SLEEPY_END_DEVICE) { @@ -229,13 +227,20 @@ static int thread_parent_request_build(protocol_interface_info_entry_t *cur) return -1; } + timeout.retrans_max = THREAD_PARENT_REQUEST_MAX_RETRY_CNT; + timeout.timeout_init = THREAD_PARENT_REQ_SCANMASK_R_TIMEOUT; + timeout.timeout_max = THREAD_PARENT_REQ_SCANMASK_RE_TIMEOUT; + timeout.delay = MLE_STANDARD_RESPONSE_DELAY; + if (cur->thread_info->thread_attached_state == THREAD_STATE_REATTACH || cur->thread_info->thread_attached_state == THREAD_STATE_REATTACH_RETRY || cur->thread_info->thread_attached_state == THREAD_STATE_CONNECTED || cur->thread_info->thread_attached_state == THREAD_STATE_CONNECTED_ROUTER) { // When doing re-attach End devices are immediately accepted as parents scanMask |= 0x40; + timeout.timeout_init = THREAD_PARENT_REQ_SCANMASK_RE_TIMEOUT; } + thread_management_get_current_keysequence(cur->id, &keySequence); mle_service_msg_update_security_params(buf_id, 5, 2, keySequence); @@ -258,11 +263,9 @@ static int thread_parent_request_build(protocol_interface_info_entry_t *cur) if (mle_service_update_length_by_ptr(buf_id,ptr)!= 0) { tr_debug("Buffer overflow at message write"); } - timeout.retrans_max = THREAD_PARENT_REQUEST_MAX_RETRY_CNT; - timeout.timeout_init = 1; - timeout.timeout_max = 2; - timeout.delay = MLE_NO_DELAY; + cur->nwk_nd_re_scan_count = 1; + mle_service_set_packet_callback(buf_id, thread_parent_discover_timeout_cb); if (cur->thread_info->thread_attached_state == THREAD_STATE_NETWORK_DISCOVER) { mle_service_interface_receiver_handler_update(cur->id, thread_mle_parent_discover_receive_cb); @@ -270,7 +273,7 @@ static int thread_parent_request_build(protocol_interface_info_entry_t *cur) mle_service_interface_receiver_handler_update(cur->id, thread_general_mle_receive_cb); } - mle_service_set_msg_timeout_parameters(buf_id, &timeout); + mle_service_set_msg_timeout_parameters_fast(buf_id, &timeout); mle_service_send_message(buf_id); return 0; } @@ -295,6 +298,7 @@ static int thread_end_device_synch_response_validate(protocol_interface_info_ent uint32_t llFrameCounter; thread_leader_data_t leaderData; mle_neigh_table_entry_t *entry_temp; + bool new_entry_created; tr_debug("Validate Link Synch Response"); //Check First Status @@ -325,7 +329,7 @@ static int thread_end_device_synch_response_validate(protocol_interface_info_ent } //Update parent link information - entry_temp = mle_class_get_entry_by_ll64(cur->id, linkMargin, src_address, true); + entry_temp = mle_class_get_entry_by_ll64(cur->id, linkMargin, src_address, true, &new_entry_created); if (!entry_temp) { tr_debug("Neighbor allocate fail"); @@ -343,7 +347,7 @@ static int thread_end_device_synch_response_validate(protocol_interface_info_ent mac_helper_coordinator_address_set(cur, ADDR_802_15_4_SHORT, shortAddress); mle_entry_timeout_update(entry_temp, thread_info(cur)->host_link_timeout); - mac_helper_devicetable_set(entry_temp, cur, llFrameCounter, securityHeader->KeyIndex); + mac_helper_devicetable_set(entry_temp, cur, llFrameCounter, securityHeader->KeyIndex, new_entry_created); thread_info(cur)->thread_attached_state = THREAD_STATE_CONNECTED; thread_bootstrap_update_ml16_address(cur, address16); @@ -394,7 +398,7 @@ static void thread_child_synch_receive_cb(int8_t interface_id, mle_message_t *ml messageId = mle_tlv_validate_response(mle_msg->data_ptr, mle_msg->data_length); if (messageId == 0) { - tr_debug("Not for me"); + tr_debug("No matching challenge"); return; } @@ -472,7 +476,7 @@ void thread_mle_parent_discover_receive_cb(int8_t interface_id, mle_message_t *m return; } - tr_debug("Thread MLE Parent request response Handler"); + tr_debug("MLE Parent response handler"); //State machine What packet should accept in this case switch (mle_msg->message_type) { case MLE_COMMAND_PARENT_RESPONSE: { @@ -497,7 +501,7 @@ void thread_mle_parent_discover_receive_cb(int8_t interface_id, mle_message_t *m messageId = mle_tlv_validate_response(mle_msg->data_ptr, mle_msg->data_length); if (messageId == 0) { - tr_debug("Not for me"); + tr_debug("No matching challenge"); return; } @@ -748,11 +752,12 @@ static void thread_mle_child_request_receive_cb(int8_t interface_id, mle_message return; } - tr_debug("Thread MLE Child request response Handler"); + tr_debug("Thread MLE Child ID response handler"); switch (mle_msg->message_type) { case MLE_COMMAND_CHILD_ID_RESPONSE: { + uint8_t src_mac64[8]; uint8_t shortAddress[2]; uint16_t childId; mle_tlv_info_t routeTlv, addressRegisteredTlv, networkDataTlv; @@ -760,22 +765,32 @@ static void thread_mle_child_request_receive_cb(int8_t interface_id, mle_message uint64_t pending_timestamp = 0; uint64_t active_timestamp; thread_scanned_parent_t *scan_result = thread_info(cur)->thread_attach_scanned_parent; + bool new_entry_created; - tr_info("Received Child ID Response"); + tr_info("Recv Child ID Response"); + + // Validate that response is coming from the scanned parent candidate + memcpy(src_mac64, (mle_msg->packet_src_address + 8), 8); + src_mac64[0] ^= 2; + if (memcmp(src_mac64, scan_result->mac64, 8) != 0) { + tr_debug("Drop Child ID response from previous request"); + return; + } // Clear old data if (cur->thread_info->releaseRouterId) { thread_bootstrap_clear_neighbor_entries(cur); - cur->thread_info->localServerDataBase.release_old_address = true; } - thread_clean_all_routers_from_neighbor_list(cur->id); + cur->thread_info->localServerDataBase.release_old_address = true; + + thread_neighbor_list_clean(cur); thread_leader_service_stop(interface_id); thread_leader_service_leader_data_free(cur->thread_info); thread_merge_prepare(cur); // Create entry for new parent - entry_temp = mle_class_get_entry_by_ll64(cur->id, thread_compute_link_margin(mle_msg->dbm), mle_msg->packet_src_address, true); + entry_temp = mle_class_get_entry_by_ll64(cur->id, thread_compute_link_margin(mle_msg->dbm), mle_msg->packet_src_address, true, &new_entry_created); if (entry_temp == NULL) { // todo: what to do here? return; @@ -832,7 +847,14 @@ static void thread_mle_child_request_receive_cb(int8_t interface_id, mle_message mac_helper_coordinator_address_set(cur, ADDR_802_15_4_SHORT, shortAddress); mle_entry_timeout_update(entry_temp, thread_info(cur)->host_link_timeout); - mac_helper_devicetable_set(entry_temp, cur, scan_result->linLayerFrameCounter, security_headers->KeyIndex); + + if (scan_result->security_key_index != security_headers->KeyIndex) { + // KeyIndex has been changed between parent_response and child_id_response, reset link layer frame counter + scan_result->linLayerFrameCounter = 0; + scan_result->security_key_index = security_headers->KeyIndex; + } + + mac_helper_devicetable_set(entry_temp, cur, scan_result->linLayerFrameCounter, security_headers->KeyIndex, new_entry_created); thread_info(cur)->thread_attached_state = THREAD_STATE_CONNECTED; @@ -868,7 +890,7 @@ static void thread_mle_child_request_receive_cb(int8_t interface_id, mle_message break; } default: - tr_debug("Unsupported TLV %d", mle_msg->message_type); + tr_debug("Skip msg type %d", mle_msg->message_type); break; } @@ -927,9 +949,10 @@ void thread_endevice_synch_start(protocol_interface_info_entry_t *cur) { if (cur->thread_info->thread_endnode_parent) { mle_neigh_table_entry_t *entry_temp; + bool new_entry_created; // Add the parent to the MLE neighbor table - entry_temp = mle_class_get_entry_by_mac64(cur->id, 64, cur->thread_info->thread_endnode_parent->mac64, true); + entry_temp = mle_class_get_entry_by_mac64(cur->id, 64, cur->thread_info->thread_endnode_parent->mac64, true, &new_entry_created); if (entry_temp) { entry_temp->short_adr = cur->thread_info->thread_endnode_parent->shortAddress; @@ -941,7 +964,7 @@ void thread_endevice_synch_start(protocol_interface_info_entry_t *cur) mle_entry_timeout_update(entry_temp, 20); // Add the parent to the MAC table (for e.g. secured/fragmented Child Update Response) - mac_helper_devicetable_set(entry_temp, cur, 0, cur->mac_parameters->mac_default_key_index); + mac_helper_devicetable_set(entry_temp, cur, 0, cur->mac_parameters->mac_default_key_index, new_entry_created); } } @@ -975,7 +998,7 @@ static bool thread_child_id_req_timeout(int8_t interface_id, uint16_t msgId, boo cur->thread_info->thread_attach_scanned_parent->child_id_request_id = 0; uint8_t *addr = mle_service_get_msg_destination_address_pointer(msgId); - tr_debug("Child ID Request timed out, address: %s", trace_ipv6(addr)); + tr_debug("Child ID Request timed out: %s", trace_ipv6(addr)); blacklist_update(addr, false); @@ -999,8 +1022,9 @@ static bool thread_child_id_req_timeout(int8_t interface_id, uint16_t msgId, boo memcpy(&ll64[8], scanned_parent->mac64 , 8); ll64[8] ^= 2; - entry_temp = mle_class_get_entry_by_ll64(cur->id, scanned_parent->linkMarginToParent, ll64, false); - if (entry_temp) { + entry_temp = mle_class_get_entry_by_ll64(cur->id, scanned_parent->linkMarginToParent, ll64, false, NULL); + if (entry_temp && !thread_check_is_this_my_parent(cur, entry_temp)) { + // remove scanned_parent entry only if it is not my parent mle_class_remove_entry(cur->id, entry_temp); } } @@ -1017,36 +1041,19 @@ static bool thread_child_id_req_timeout(int8_t interface_id, uint16_t msgId, boo cur->thread_info->localServerDataBase.release_old_address = false; cur->thread_info->releaseRouterId = false; + cur->thread_info->networkDataRequested = false; cur->nwk_bootstrap_state = ER_BOOTSRAP_DONE; - mle_service_interface_receiver_handler_update(cur->id, thread_general_mle_receive_cb); exit: + mle_service_interface_receiver_handler_update(cur->id, thread_general_mle_receive_cb); + ns_dyn_mem_free(cur->thread_info->thread_attach_scanned_parent); cur->thread_info->thread_attach_scanned_parent = NULL; return false; } -static uint8_t *thread_single_address_registration_tlv_write(uint8_t *ptr, lowpan_context_t *ctx, uint8_t *addressPtr) -{ - *ptr++ = MLE_TYPE_ADDRESS_REGISTRATION; - if (ctx) { - *ptr++ = 9; - //Write TLV to list - *ptr++ = (ctx->cid | 0x80); - memcpy(ptr, addressPtr + 8, 8); - ptr += 8; - } else { - *ptr++ = 17; - //Write TLV to list - *ptr++ = 0; - memcpy(ptr, addressPtr, 16); - ptr += 16; - } - return ptr; -} - static int thread_attach_child_id_request_build(protocol_interface_info_entry_t *cur) { uint8_t *ptr, *address_ptr; @@ -1069,8 +1076,6 @@ static int thread_attach_child_id_request_build(protocol_interface_info_entry_t thread_management_get_current_keysequence(cur->id, &keySequence); mle_service_msg_update_security_params(buf_id, 5, 2, keySequence); - lowpan_context_t *ctx; - uint8_t ml64[16]; uint8_t request_tlv_list[3]; uint8_t macShort[2]; uint8_t reqTlvCnt; @@ -1088,15 +1093,10 @@ static int thread_attach_child_id_request_build(protocol_interface_info_entry_t ptr = mle_tlv_write_response(ptr, scan_parent->challengeData, scan_parent->chal_len); //Add ML-EID - memcpy(ml64, thread_info(cur)->threadPrivatePrefixInfo.ulaPrefix, 8); - memcpy(&ml64[8], cur->iid_slaac, 8); if ((mode & MLE_FFD_DEV) == 0) { - ctx = lowpan_context_get_by_address(&cur->lowpan_contexts, ml64); - if (ctx) { - //Write TLV to list - ptr = thread_single_address_registration_tlv_write(ptr, ctx, ml64); - } + ptr = thread_address_registration_tlv_write(ptr, cur); } + reqTlvCnt = 2; request_tlv_list[0] = MLE_TYPE_NETWORK_DATA; @@ -1133,53 +1133,54 @@ static int thread_attach_child_id_request_build(protocol_interface_info_entry_t static bool thread_child_update_timeout_cb(int8_t interface_id, uint16_t msgId, bool usedAllRerties) { protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(interface_id); - (void)msgId; if (!cur || !cur->thread_info->thread_endnode_parent) { return false; } - tr_debug("Child Update CB"); - if (cur->thread_info->thread_endnode_parent->childUpdateProcessStatus) { - //This process is ready - cur->thread_info->thread_endnode_parent->childUpdateProcessStatus = false; - if (!cur->thread_info->thread_endnode_parent->childUpdatePending) { - - cur->thread_info->thread_endnode_parent->childUpdateProcessActive = false; - //Disable Poll - mac_data_poll_protocol_poll_mode_decrement(cur); - tr_debug("Child Update ready"); - } else { - cur->thread_info->thread_endnode_parent->childUpdatePending = false; - tr_debug("Child Update Pending"); - thread_bootsrap_event_trig(THREAD_CHILD_UPDATE, cur->bootStrapId, ARM_LIB_HIGH_PRIORITY_EVENT); - } + if (msgId != cur->thread_info->childUpdateReqMsgId) { + //Wrong message id return false; } if (usedAllRerties) { - + tr_debug("Child Update timed out"); cur->thread_info->thread_endnode_parent->childUpdatePending = false; cur->thread_info->thread_endnode_parent->childUpdateProcessActive = false; - cur->thread_info->thread_endnode_parent->childUpdateProcessStatus = false; mac_data_poll_protocol_poll_mode_decrement(cur); thread_bootstrap_reset_restart(cur->id); tr_debug("Restart attachment"); return false; } + if (cur->thread_info->thread_endnode_parent->childUpdateProcessActive) { + // we have not received response so re-send + return true; + } - return true; + return false; } -int8_t thread_bootstrap_child_update(protocol_interface_info_entry_t *cur) +int8_t thread_host_bootstrap_child_update(int8_t interface_id, const uint8_t *mac64) { + protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(interface_id); mle_message_timeout_params_t timeout; uint8_t mode; uint32_t keySequence; + if (!cur->thread_info->thread_endnode_parent) { return -1; } + if (cur->thread_info->thread_endnode_parent->childUpdateProcessActive) { + //Set Pending if earlier process is already started + cur->thread_info->thread_endnode_parent->childUpdatePending = true; + return -1; + } + //Trig event + cur->thread_info->thread_endnode_parent->childUpdatePending = false; + cur->thread_info->thread_endnode_parent->childUpdateProcessActive = true; + + tr_debug("Child Update Request"); mode = thread_mode_get_by_interface_ptr(cur); @@ -1196,11 +1197,12 @@ int8_t thread_bootstrap_child_update(protocol_interface_info_entry_t *cur) uint8_t *address_ptr = mle_service_get_msg_destination_address_pointer(bufId); memcpy(address_ptr, ADDR_LINK_LOCAL_PREFIX, 8); - memcpy(address_ptr + 8, cur->thread_info->thread_endnode_parent->mac64, 8); + memcpy(address_ptr + 8, mac64, 8); address_ptr[8] ^= 2; uint8_t *ptr = mle_service_get_data_pointer(bufId); ptr = mle_tlv_write_mode(ptr, mode); + ptr = mle_general_write_source_address(ptr, cur); ptr = mle_tlv_write_timeout(ptr, cur->thread_info->host_link_timeout); ptr = thread_leader_data_tlv_write(ptr, cur); @@ -1221,9 +1223,11 @@ int8_t thread_bootstrap_child_update(protocol_interface_info_entry_t *cur) thread_end_device_mode_set(cur, false); } mac_data_poll_init_protocol_poll(cur); + cur->thread_info->childUpdateReqMsgId = bufId; mle_service_set_packet_callback(bufId, thread_child_update_timeout_cb); mle_service_set_msg_timeout_parameters(bufId, &timeout); mle_service_send_message(bufId); + return 0; } int thread_host_bootstrap_child_update_negative_response(protocol_interface_info_entry_t *cur, uint8_t *dstAddress, mle_tlv_info_t *challenge) diff --git a/source/6LoWPAN/Thread/thread_host_bootstrap.h b/source/6LoWPAN/Thread/thread_host_bootstrap.h index 89b73f1abb4..e154208540d 100644 --- a/source/6LoWPAN/Thread/thread_host_bootstrap.h +++ b/source/6LoWPAN/Thread/thread_host_bootstrap.h @@ -42,7 +42,7 @@ struct protocol_interface_info_entry; struct mle_security_header; void thread_network_attach_start(struct protocol_interface_info_entry *cur); -int8_t thread_bootstrap_child_update(struct protocol_interface_info_entry *cur); +int8_t thread_host_bootstrap_child_update(int8_t interface_id, const uint8_t *mac64); int thread_host_bootstrap_child_update_negative_response(protocol_interface_info_entry_t *cur, uint8_t *dstAddress, mle_tlv_info_t *challenge); void thread_child_set_default_route(struct protocol_interface_info_entry *cur); diff --git a/source/6LoWPAN/Thread/thread_joiner_application.c b/source/6LoWPAN/Thread/thread_joiner_application.c index 231502f0581..91400d7e401 100644 --- a/source/6LoWPAN/Thread/thread_joiner_application.c +++ b/source/6LoWPAN/Thread/thread_joiner_application.c @@ -917,6 +917,15 @@ link_configuration_s *thread_joiner_application_get_config(int8_t interface_id) return this->configuration_ptr; } +uint8_t *thread_joiner_application_network_name_get(int8_t interface_id) +{ + thread_joiner_t *this = thread_joiner_find(interface_id); + if (!this) { + return NULL; + } + return this->configuration_ptr->name; +} + static int thread_joiner_application_nvm_link_config_read(thread_joiner_t *this) { // read config from NVM, in case of failure current settings are unchanged. diff --git a/source/6LoWPAN/Thread/thread_joiner_application.h b/source/6LoWPAN/Thread/thread_joiner_application.h index 3939b5de525..21258690ee2 100644 --- a/source/6LoWPAN/Thread/thread_joiner_application.h +++ b/source/6LoWPAN/Thread/thread_joiner_application.h @@ -69,6 +69,7 @@ struct link_configuration *thread_joiner_application_get_config(int8_t interface uint64_t thread_joiner_application_active_timestamp_get(int8_t interface_id); uint8_t thread_joiner_application_security_policy_get(int8_t interface_id); void thread_joiner_application_active_timestamp_set(int8_t interface_id, uint64_t timestamp); +uint8_t *thread_joiner_application_network_name_get(int8_t interface_id); uint8_t *thread_joiner_application_active_config_tlv_list_get(uint8_t interface_id, uint16_t *length); uint8_t *thread_joiner_application_active_config_params_get(uint8_t interface_id, uint16_t *length); diff --git a/source/6LoWPAN/Thread/thread_leader_service.c b/source/6LoWPAN/Thread/thread_leader_service.c index 622f9de18e8..d1e21e7f6d6 100644 --- a/source/6LoWPAN/Thread/thread_leader_service.c +++ b/source/6LoWPAN/Thread/thread_leader_service.c @@ -733,6 +733,32 @@ static void thread_leader_allocate_router_id_by_allocated_id(thread_leader_info_ info->thread_router_id_list[router_id].reUsePossible = false; } +void thread_leader_mleid_rloc_map_populate(thread_nvm_mleid_rloc_map *mleid_rloc_map, thread_leader_info_t *leader_private_info) +{ + for (uint8_t i = 0; i < 64; i++) { + if (bit_test(leader_private_info->master_router_id_mask, i)) { + memcpy(mleid_rloc_map->mleid_rloc_map[i].mle_id, leader_private_info->thread_router_id_list[i].eui64, 8); + } + } +} + +int thread_leader_mleid_rloc_map_to_nvm_write(protocol_interface_info_entry_t *cur) +{ + if (!cur->thread_info->leader_private_data) { + return -1; + } + + thread_nvm_mleid_rloc_map *mleid_rloc_map = ns_dyn_mem_temporary_alloc(sizeof(thread_nvm_mleid_rloc_map)); + if (!mleid_rloc_map) { + return -2; + } + memset(mleid_rloc_map, 0, sizeof(thread_nvm_mleid_rloc_map)); + thread_leader_mleid_rloc_map_populate(mleid_rloc_map, cur->thread_info->leader_private_data); + thread_nvm_store_mleid_rloc_map_write(mleid_rloc_map); + ns_dyn_mem_free(mleid_rloc_map); + return 0; +} + static int thread_leader_service_router_id_allocate(const uint8_t *eui64, protocol_interface_info_entry_t *cur, thread_leader_service_router_id_resp_t *reponse) { int ret_val = -1; @@ -793,6 +819,8 @@ static int thread_leader_service_router_id_allocate(const uint8_t *eui64, protoc if (!bit_test(leader_private_ptr->master_router_id_mask, id)) { if (leader_private_ptr->thread_router_id_list[id].reUsePossible) { allocated_id = id; + // new id allocated save to nvm after delay + leader_private_ptr->leader_nvm_sync_timer = LEADER_NVM_SYNC_DELAY; break; } } @@ -847,6 +875,7 @@ static int thread_leader_service_router_id_deallocate(const uint8_t *eui64, prot //Active ID if (memcmp(eui64, leader_private_ptr->thread_router_id_list[i].eui64, 8) == 0) { tr_debug("Release Router Id %d", i); + leader_private_ptr->leader_nvm_sync_timer = LEADER_NVM_SYNC_DELAY; thread_leader_service_route_mask_bit_clear(leader_private_ptr, i); leader_private_ptr->thread_router_id_list[i].reUsePossible = true; leader_private_ptr->thread_router_id_list[i].validLifeTime = 0; @@ -1270,7 +1299,7 @@ static int thread_leader_service_leader_init(protocol_interface_info_entry_t *cu thread_nd_service_delete(cur->id); mpl_clear_realm_scope_seeds(cur); ipv6_neighbour_cache_flush(&cur->ipv6_neighbour_cache); - thread_clean_all_routers_from_neighbor_list(cur->id); + thread_neighbor_list_clean(cur); cur->mesh_callbacks = NULL; cur->lowpan_info &= ~INTERFACE_NWK_CONF_MAC_RX_OFF_IDLE; @@ -1318,6 +1347,8 @@ static void thread_leader_service_interface_setup_activate(protocol_interface_in //SET Router ID thread_leader_allocate_router_id_by_allocated_id(private, routerId, cur->mac); thread_old_partition_data_purge(cur); + // remove any existing rloc mapping in nvm + thread_nvm_store_mleid_rloc_map_remove(); cur->lowpan_address_mode = NET_6LOWPAN_GP16_ADDRESS; thread_bootstrap_update_ml16_address(cur, cur->thread_info->routerShortAddress); thread_generate_ml64_address(cur); @@ -1483,6 +1514,7 @@ void thread_leader_service_timer(protocol_interface_info_entry_t *cur, uint32_t thread_bootstrap_network_data_update(cur); } } + if (cur->thread_info->leader_private_data->leader_id_seq_timer) { if (cur->thread_info->leader_private_data->leader_id_seq_timer > ticks) { cur->thread_info->leader_private_data->leader_id_seq_timer -= ticks; @@ -1499,6 +1531,16 @@ void thread_leader_service_timer(protocol_interface_info_entry_t *cur, uint32_t thread_leader_service_network_data_changed(cur, false, false); } + if (cur->thread_info->leader_private_data->leader_nvm_sync_timer) { + if ((cur->thread_info->leader_private_data->leader_nvm_sync_timer) > ticks) { + cur->thread_info->leader_private_data->leader_nvm_sync_timer -= ticks; + } + else { + cur->thread_info->leader_private_data->leader_nvm_sync_timer = 0; + thread_leader_mleid_rloc_map_to_nvm_write(cur); + } + } + thread_leader_service_router_id_valid_lifetime_update(cur, ticks); } @@ -1618,25 +1660,39 @@ int thread_leader_service_thread_partitition_restart(int8_t interface_id, mle_tl } //Learn network data, we remove own data from here it should be re given by application //thread_management_network_data_register(cur->id, networkData.dataPtr, networkData.tlvLen, address16 ); - + thread_nvm_mleid_rloc_map *mleid_rloc_map = ns_dyn_mem_temporary_alloc(sizeof(thread_nvm_mleid_rloc_map)); + if (!mleid_rloc_map) { + return -1; + } + if (thread_nvm_store_mleid_rloc_map_read(mleid_rloc_map) != THREAD_NVM_FILE_SUCCESS) { + memset(mleid_rloc_map, 0, sizeof(thread_nvm_mleid_rloc_map)); + } // initialize private data thread_info(cur)->leader_private_data->maskSeq = *routing->dataPtr; - memcpy(thread_info(cur)->leader_private_data->master_router_id_mask,routing->dataPtr + 1,8); + memcpy(thread_info(cur)->leader_private_data->master_router_id_mask,routing->dataPtr + 1, 8); for (int i = 0; i < 64; i++) { - memset(thread_info(cur)->leader_private_data->thread_router_id_list[i].eui64,0,8); if (bit_test(thread_info(cur)->leader_private_data->master_router_id_mask, i)) { //Active ID thread_info(cur)->leader_private_data->thread_router_id_list[i].reUsePossible = false; - + memcpy(thread_info(cur)->leader_private_data->thread_router_id_list[i].eui64, mleid_rloc_map->mleid_rloc_map[i].mle_id, 8); } else { // Free id thread_info(cur)->leader_private_data->thread_router_id_list[i].reUsePossible = true; + // clear the mleid in both local router id list and nvm + memset(thread_info(cur)->leader_private_data->thread_router_id_list[i].eui64, 0, 8); + memset(mleid_rloc_map->mleid_rloc_map[i].mle_id, 0, 8); } thread_info(cur)->leader_private_data->thread_router_id_list[i].validLifeTime = 0xffffffff; } + // write back updated map to store + thread_nvm_store_mleid_rloc_map_write(mleid_rloc_map); + ns_dyn_mem_free(mleid_rloc_map); // Clear network data (if exists) and propagate new empty network data thread_network_data_free_and_clean(&cur->thread_info->networkDataStorage); thread_network_data_base_init(&cur->thread_info->networkDataStorage); + // Update router sequence id to prevent network fragmentation in case of Leader was temporarily down + // and routers were not able to get new sequence id for NETWORK_ID_TIMEOUT duration. + thread_leader_service_update_id_set(cur); return 0; } diff --git a/source/6LoWPAN/Thread/thread_leader_service.h b/source/6LoWPAN/Thread/thread_leader_service.h index 465a027ce23..7eabcb30283 100644 --- a/source/6LoWPAN/Thread/thread_leader_service.h +++ b/source/6LoWPAN/Thread/thread_leader_service.h @@ -118,6 +118,8 @@ void thread_leader_service_network_data_changed(protocol_interface_info_entry_t void thread_leader_service_timer(protocol_interface_info_entry_t *cur, uint32_t ticks); +int thread_leader_mleid_rloc_map_to_nvm_write(protocol_interface_info_entry_t *cur); + /** Get first child ID from network data based on parent ID * * \param thread_info @@ -161,6 +163,8 @@ void thread_leader_service_router_state_changed(thread_info_t *thread_info, uint #define thread_leader_service_router_state_changed(thread_info, router_id, available, interface_id) +#define thread_leader_mleid_rloc_map_to_nvm_write(cur) (0) + #endif /*HAVE_THREAD_LEADER_SERVICE*/ #endif /* _THREAD_LEADER_SERVICE_H_ */ diff --git a/source/6LoWPAN/Thread/thread_mle_message_handler.c b/source/6LoWPAN/Thread/thread_mle_message_handler.c index e5647527914..fee1e223503 100644 --- a/source/6LoWPAN/Thread/thread_mle_message_handler.c +++ b/source/6LoWPAN/Thread/thread_mle_message_handler.c @@ -102,7 +102,7 @@ void thread_general_mle_receive_cb(int8_t interface_id, mle_message_t *mle_msg, case MLE_COMMAND_REJECT: { mle_neigh_table_entry_t *entry_temp; tr_warn("Reject Link"); - entry_temp = mle_class_get_entry_by_ll64(cur->id, linkMargin, mle_msg->packet_src_address, false); + entry_temp = mle_class_get_entry_by_ll64(cur->id, linkMargin, mle_msg->packet_src_address, false, NULL); if (entry_temp) { mle_class_remove_entry(cur->id, entry_temp); } @@ -224,8 +224,6 @@ static bool thread_router_leader_data_process(protocol_interface_info_entry_t *c // Request network data if we have a 2-way link tr_debug("Request New Network Data from %s", trace_ipv6(src_address)); thread_network_data_request_send(cur, src_address, true); - } else { - } } else if (leaderDataUpdate == 2) { tr_debug("Start Merge"); @@ -239,27 +237,16 @@ static bool thread_router_leader_data_process(protocol_interface_info_entry_t *c return true; } -static bool thread_reed_partitions_merge(protocol_interface_info_entry_t *cur, uint16_t shortAddress, thread_leader_data_t heard_partition_leader_data) +static bool thread_heard_lower_partition(protocol_interface_info_entry_t *cur, thread_leader_data_t heard_partition_leader_data) { - if (thread_is_router_addr(shortAddress)) { - return false; + if (heard_partition_leader_data.weighting < thread_info(cur)->thread_leader_data->weighting) { + return true; } - if (thread_extension_version_check(thread_info(cur)->version)) { - // lower weighting heard - if (thread_info(cur)->thread_leader_data->weighting > heard_partition_leader_data.weighting) { - return false; - } - // lower/same partition id heard - if (thread_info(cur)->thread_leader_data->weighting == heard_partition_leader_data.weighting && - thread_info(cur)->thread_leader_data->partitionId >= heard_partition_leader_data.partitionId ) { - return false; - } - } else if (thread_info(cur)->thread_leader_data->partitionId >= heard_partition_leader_data.partitionId){ - return false; + if (heard_partition_leader_data.weighting == thread_info(cur)->thread_leader_data->weighting && + heard_partition_leader_data.partitionId < thread_info(cur)->thread_leader_data->partitionId) { + return true; } - // can merge to a higher weighting/partition id - thread_bootstrap_connection_error(cur->id, CON_ERROR_PARTITION_MERGE, NULL); - return true; + return false; } static bool thread_router_advertiment_tlv_analyze(uint8_t *ptr, uint16_t data_length, thread_leader_data_t *leaderData, uint16_t *shortAddress, mle_tlv_info_t *routeTlv) @@ -315,12 +302,31 @@ static void thread_update_mle_entry(protocol_interface_info_entry_t *cur, mle_me return; } +static bool thread_parse_advertisement_from_parent(protocol_interface_info_entry_t *cur, thread_leader_data_t *leader_data, uint16_t short_address) +{ + if ((thread_info(cur)->thread_leader_data->partitionId != leader_data->partitionId) || + (thread_info(cur)->thread_leader_data->weighting != leader_data->weighting)) { + //parent changed partition/weight - reset own routing information + thread_old_partition_data_purge(cur); + } + //check if network data needs to be requested + if (!thread_bootstrap_request_network_data(cur, leader_data, short_address)) { + tr_debug("Parent short address changed - re-attach"); + thread_bootstrap_connection_error(cur->id, CON_PARENT_CONNECT_DOWN, NULL); + return false; + } + + return true; +} + static void thread_parse_advertisement(protocol_interface_info_entry_t *cur, mle_message_t *mle_msg, mle_security_header_t *security_headers, uint8_t linkMargin) { mle_tlv_info_t routeTlv; thread_leader_data_t leaderData; - uint16_t shortAddress; mle_neigh_table_entry_t *entry_temp; + uint16_t shortAddress; + bool adv_from_my_partition; + bool my_parent; // Check device mode & bootstrap state if ((thread_info(cur)->thread_device_mode == THREAD_DEVICE_MODE_SLEEPY_END_DEVICE) || @@ -336,29 +342,27 @@ static void thread_parse_advertisement(protocol_interface_info_entry_t *cur, mle } // Get MLE entry - entry_temp = mle_class_get_entry_by_ll64(cur->id, linkMargin, mle_msg->packet_src_address, false); + entry_temp = mle_class_get_entry_by_ll64(cur->id, linkMargin, mle_msg->packet_src_address, false, NULL); + + // Check if this is from my parent + my_parent = thread_check_is_this_my_parent(cur, entry_temp); + + adv_from_my_partition = thread_instance_id_matches(cur, &leaderData); - if ((security_headers->KeyIdMode == MAC_KEY_ID_MODE_SRC4_IDX) - && (thread_instance_id_matches(cur, &leaderData))) { + if ((security_headers->KeyIdMode == MAC_KEY_ID_MODE_SRC4_IDX) && adv_from_my_partition) { thread_management_key_synch_req(cur->id, common_read_32_bit(security_headers->Keysource)); } - // Check parent status - if (!thread_attach_active_router(cur)) { - //processing for non routers - if (thread_check_is_this_my_parent(cur, entry_temp)) { - //advertisement from parent - if ((thread_info(cur)->thread_leader_data->partitionId != leaderData.partitionId) || - (thread_info(cur)->thread_leader_data->weighting != leaderData.weighting)) { - //parent changed partition/weight - reset own routing information - thread_old_partition_data_purge(cur); - } - //check if network data needs to be requested - if (!thread_bootstrap_request_network_data(cur, &leaderData, shortAddress)) { - tr_debug("Parent short address changed - re-attach"); - thread_bootstrap_connection_error(cur->id, CON_PARENT_CONNECT_DOWN, NULL); - return; - } + if (entry_temp && !adv_from_my_partition && !my_parent ) { + // Remove MLE entry that are located in other partition and is not my parent + mle_class_remove_entry(cur->id, entry_temp); + entry_temp = NULL; + } + + /* Check parent status */ + if (!thread_attach_active_router(cur) && my_parent) { + if (!thread_parse_advertisement_from_parent(cur, &leaderData, shortAddress)) { + return; } } @@ -367,26 +371,31 @@ static void thread_parse_advertisement(protocol_interface_info_entry_t *cur, mle // Process advertisement if (thread_info(cur)->thread_device_mode != THREAD_DEVICE_MODE_END_DEVICE) { + /* REED and FED */ if (!thread_attach_active_router(cur)) { - // REED and FED - if (!entry_temp && thread_bootstrap_link_create_check(cur, shortAddress) && thread_bootstrap_link_create_allowed(cur, shortAddress, mle_msg->packet_src_address)) { - if ((thread_info(cur)->thread_leader_data->partitionId == leaderData.partitionId) && - (thread_info(cur)->thread_leader_data->weighting == leaderData.weighting)) { + /* Check if advertisement is from same partition */ + if (thread_info(cur)->thread_leader_data->weighting == leaderData.weighting && thread_info(cur)->thread_leader_data->partitionId == leaderData.partitionId ) { + if (!entry_temp && thread_bootstrap_link_create_check(cur, shortAddress) && thread_bootstrap_link_create_allowed(cur, shortAddress, mle_msg->packet_src_address)) { // Create link to new neighbor no other processing allowed thread_link_request_start(cur, mle_msg->packet_src_address); return; } - if (!thread_router_leader_data_process(cur, mle_msg->packet_src_address, &leaderData, &routeTlv, entry_temp)) { - // better partition found or new network data learn started + /* Advertisement from higher / lower partition */ + } else { + // Check if better partition is heard + if (thread_bootstrap_partition_process(cur, thread_get_router_count_from_route_tlv(&routeTlv), &leaderData, &routeTlv) > 0) { + tr_debug("Start Merge"); + thread_bootstrap_connection_error(cur->id, CON_ERROR_PARTITION_MERGE, NULL); return; } + + // REED advertisement to lower partition to help merge faster + if (thread_heard_lower_partition(cur,leaderData)) { + thread_router_bootstrap_reed_merge_advertisement(cur); + } } - // process REED advertisement from higher partition - if (thread_reed_partitions_merge(cur, shortAddress, leaderData)) { - return; - } + /* ROUTER */ } else { - //Router if (!thread_router_leader_data_process(cur, mle_msg->packet_src_address, &leaderData, &routeTlv, entry_temp) ) { return; } @@ -409,14 +418,14 @@ static void thread_parse_accept(protocol_interface_info_entry_t *cur, mle_messag uint16_t messageId; uint8_t linkMarginfronNeigh; mle_neigh_table_entry_t *entry_temp; - bool createNew; + bool createNew, new_entry_created; tr_info("MLE LINK ACCEPT"); messageId = mle_tlv_validate_response(mle_msg->data_ptr, mle_msg->data_length); if (messageId == 0) { - tr_debug("Not for me"); + tr_debug("No matching challenge"); return; } @@ -435,7 +444,7 @@ static void thread_parse_accept(protocol_interface_info_entry_t *cur, mle_messag /* Call to determine whether or not we should create a new link */ createNew = thread_bootstrap_link_create_check(cur, shortAddress); - entry_temp = mle_class_get_entry_by_ll64(cur->id, linkMargin, mle_msg->packet_src_address, createNew); + entry_temp = mle_class_get_entry_by_ll64(cur->id, linkMargin, mle_msg->packet_src_address, createNew, &new_entry_created); if (!entry_temp) { thread_link_reject_send(cur, mle_msg->packet_src_address); @@ -457,7 +466,7 @@ static void thread_parse_accept(protocol_interface_info_entry_t *cur, mle_messag // Set full data as REED needs full data and SED will not make links entry_temp->mode |= MLE_THREAD_REQ_FULL_DATA_SET; - mac_helper_devicetable_set(entry_temp, cur, llFrameCounter, security_headers->KeyIndex); + mac_helper_devicetable_set(entry_temp, cur, llFrameCounter, security_headers->KeyIndex, new_entry_created); if (entry_temp->timeout_rx) { mle_entry_timeout_refresh(entry_temp); @@ -551,7 +560,7 @@ static void thread_parse_data_response(protocol_interface_info_entry_t *cur, mle return; } - entry_temp = mle_class_get_entry_by_ll64(cur->id, linkMargin, mle_msg->packet_src_address, false); + entry_temp = mle_class_get_entry_by_ll64(cur->id, linkMargin, mle_msg->packet_src_address, false, NULL); if(cur->thread_info->thread_device_mode == THREAD_DEVICE_MODE_ROUTER || cur->thread_info->thread_device_mode == THREAD_DEVICE_MODE_FULL_END_DEVICE) { @@ -700,7 +709,7 @@ static void thread_host_child_update_request_process(protocol_interface_info_ent bool data_request_needed = false; tr_debug("Child update request"); - entry_temp = mle_class_get_entry_by_ll64(cur->id, linkMargin, mle_msg->packet_src_address, false); + entry_temp = mle_class_get_entry_by_ll64(cur->id, linkMargin, mle_msg->packet_src_address, false, NULL); if (!thread_leader_data_parse(mle_msg->data_ptr, mle_msg->data_length, &leaderData) || !entry_temp || @@ -763,10 +772,15 @@ static void thread_parse_child_update_response(protocol_interface_info_entry_t * uint8_t status; bool leader_data_received; + if (cur->thread_info->thread_endnode_parent == NULL) { + return; + } + tr_debug("Child Update Response"); + //mle_service_buffer_find leader_data_received = thread_leader_data_parse(mle_msg->data_ptr, mle_msg->data_length, &leaderData); - entry_temp = mle_class_get_entry_by_ll64(cur->id, linkMargin, mle_msg->packet_src_address, false); + entry_temp = mle_class_get_entry_by_ll64(cur->id, linkMargin, mle_msg->packet_src_address, false, NULL); if (mle_tlv_read_8_bit_tlv(MLE_TYPE_STATUS, mle_msg->data_ptr, mle_msg->data_length, &status) && status == 1 && thread_check_is_this_my_parent(cur, entry_temp)) { @@ -783,8 +797,7 @@ static void thread_parse_child_update_response(protocol_interface_info_entry_t * return; } - if ((security_headers->KeyIdMode == MAC_KEY_ID_MODE_SRC4_IDX) - && (thread_instance_id_matches(cur, &leaderData))) { + if (security_headers->KeyIdMode == MAC_KEY_ID_MODE_SRC4_IDX) { thread_management_key_synch_req(cur->id, common_read_32_bit(security_headers->Keysource)); } else { tr_debug("Key ID Mode 2 not used; dropped."); @@ -796,12 +809,13 @@ static void thread_parse_child_update_response(protocol_interface_info_entry_t * return; } + timeout = cur->thread_info->host_link_timeout; if (mle_tlv_read_32_bit_tlv(MLE_TYPE_TIMEOUT, mle_msg->data_ptr, mle_msg->data_length, &timeout)) { entry_temp->holdTime = 90; tr_debug("Setting child timeout, value=%"PRIu32, timeout); mle_entry_timeout_update(entry_temp, timeout); - thread_info(cur)->thread_endnode_parent->childUpdateProcessStatus = true; } + tr_debug("Keep-Alive -->Respond from Parent"); mle_entry_timeout_refresh(entry_temp); @@ -809,7 +823,22 @@ static void thread_parse_child_update_response(protocol_interface_info_entry_t * if (leader_data_received) { thread_save_leader_data(cur, &leaderData); } + + if (cur->thread_info->thread_device_mode == THREAD_DEVICE_MODE_SLEEPY_END_DEVICE) { + if (cur->thread_info->childUpdateReqTimer < 1) { + cur->thread_info->childUpdateReqTimer = 0.8 * timeout; + } + } + //This process is ready + cur->thread_info->thread_endnode_parent->childUpdateProcessActive = false; + if (cur->thread_info->thread_endnode_parent->childUpdatePending) { + tr_debug("Child Update Pending"); + thread_bootsrap_event_trig(THREAD_CHILD_UPDATE, cur->bootStrapId, ARM_LIB_HIGH_PRIORITY_EVENT); + return; + } + mac_data_poll_protocol_poll_mode_decrement(cur); + } #endif diff --git a/source/6LoWPAN/Thread/thread_nd.c b/source/6LoWPAN/Thread/thread_nd.c index 0ce0d26aa56..4c9a5af3918 100644 --- a/source/6LoWPAN/Thread/thread_nd.c +++ b/source/6LoWPAN/Thread/thread_nd.c @@ -209,7 +209,7 @@ static mle_neigh_table_entry_t *thread_nd_child_mleid_get(int8_t interface_id, u return NULL; } -static int thread_nd_address_query_lookup(int8_t interface_id, const uint8_t target_addr[static 16], uint16_t *addr_out, bool *proxy, uint32_t *last_transaction_time, uint8_t *mleid_ptr) +static int thread_nd_address_query_lookup(int8_t interface_id, const uint8_t target_addr[static 16], uint16_t *rloc, uint16_t *addr_out, bool *proxy, uint32_t *last_transaction_time, uint8_t *mleid_ptr) { protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(interface_id); if (!cur) { @@ -260,8 +260,8 @@ static int thread_nd_address_query_lookup(int8_t interface_id, const uint8_t tar can_route_of_mesh = true; } - if (thread_extension_bbr_nd_query_process(cur,target_addr)) { - can_route_of_mesh = true; + if (thread_extension_bbr_nd_query_process(cur,target_addr, *rloc)){ + return -1; } if (can_route_of_mesh) { diff --git a/source/6LoWPAN/Thread/thread_network_data_storage.h b/source/6LoWPAN/Thread/thread_network_data_storage.h index a4d2bf01763..33671a74cf3 100644 --- a/source/6LoWPAN/Thread/thread_network_data_storage.h +++ b/source/6LoWPAN/Thread/thread_network_data_storage.h @@ -184,7 +184,7 @@ typedef struct thread_network_local_data_cache_entry_s { thread_network_data_prefix_list_t prefix_list; /*!< Local parsed or generated service list */ thread_network_data_service_list_t service_list; uint16_t registered_rloc16;/*!< Address used for latest registration */ - bool release_old_address:1;/*!< true if release of old address is needed */ + bool release_old_address:1;/*!< true if network data can be released from old address */ bool publish_active:1;/*!< true when publish is active */ bool publish_pending:1;/*!< true when publish attempt made during active publish */ } thread_network_local_data_cache_entry_t; diff --git a/source/6LoWPAN/Thread/thread_network_synch.c b/source/6LoWPAN/Thread/thread_network_synch.c index 58676276033..8528d0c8b87 100644 --- a/source/6LoWPAN/Thread/thread_network_synch.c +++ b/source/6LoWPAN/Thread/thread_network_synch.c @@ -238,6 +238,7 @@ void thread_dynamic_storage_build_mle_table(int8_t interface_id) tr_debug("Dynamic storage: building MLE table."); thread_network_dynamic_data_entry_t *storeEntry = thread_network_synch_find(interface_id); + bool new_entry_created; if (!storeEntry) { storeEntry = thread_network_synch_create(interface_id); @@ -261,7 +262,7 @@ void thread_dynamic_storage_build_mle_table(int8_t interface_id) } uint8_t *mac64 = storeEntry->networ_dynamic_data_parameters.children[i].long_addr; tr_debug("Child: %04x, %s", storeEntry->networ_dynamic_data_parameters.children[i].short_addr, trace_array(mac64, 8)); - mle_neigh_table_entry_t *entry = mle_class_get_entry_by_mac64(interface_id, 64, mac64, true); + mle_neigh_table_entry_t *entry = mle_class_get_entry_by_mac64(interface_id, 64, mac64, true, &new_entry_created); if (entry) { entry->short_adr = storeEntry->networ_dynamic_data_parameters.children[i].short_addr; entry->mle_frame_counter = storeEntry->networ_dynamic_data_parameters.children[i].mle_frame_counter; @@ -272,7 +273,7 @@ void thread_dynamic_storage_build_mle_table(int8_t interface_id) if (cur && cur->mac_parameters) { // Set MAC layer frame counter for the child - mac_helper_devicetable_set(entry, cur, storeEntry->networ_dynamic_data_parameters.children[i].mac_frame_counter, cur->mac_parameters->mac_default_key_index); + mac_helper_devicetable_set(entry, cur, storeEntry->networ_dynamic_data_parameters.children[i].mac_frame_counter, cur->mac_parameters->mac_default_key_index, new_entry_created); } } } diff --git a/source/6LoWPAN/Thread/thread_nvm_store.c b/source/6LoWPAN/Thread/thread_nvm_store.c index fdd644e846e..e0c7c9224c9 100644 --- a/source/6LoWPAN/Thread/thread_nvm_store.c +++ b/source/6LoWPAN/Thread/thread_nvm_store.c @@ -52,6 +52,9 @@ const char *FAST_DATA_FILE = "f_d"; const char *LINK_INFO_FILE = "l_i"; #define LINK_INFO_DATA_VERSION 1 +const char *LEADER_INFO_FILE = "ld_i"; +#define LEADER_INFO_DATA_VERSION 1 + typedef struct { uint8_t mac[8]; uint16_t short_addr; @@ -88,6 +91,7 @@ static void thread_nvm_store_link_info_delayed_write(uint32_t seconds); #define DEVICE_CONF_STRING_LEN (strlen(DEVICE_CONF_FILE)+strlen(thread_nvm_store_get_root_path())+1) #define PENDING_CONF_STRING_LEN (strlen(THREAD_NVM_PENDING_CONF_FILE)+strlen(thread_nvm_store_get_root_path())+1) #define LINK_INFO_STRING_LEN (strlen(LINK_INFO_FILE)+strlen(thread_nvm_store_get_root_path())+1) +#define LEADER_INFO_STRING_LEN (strlen(LEADER_INFO_FILE)+strlen(thread_nvm_store_get_root_path())+1) thread_nvm_fast_data_t cached_fast_data; @@ -117,6 +121,65 @@ static int root_path_valid(void) } return 1; } + +int thread_nvm_store_mleid_rloc_map_write(thread_nvm_mleid_rloc_map *mleid_rloc_map) +{ + char lc_data_path[LEADER_INFO_STRING_LEN]; + if (!root_path_valid()) { + return THREAD_NVM_FILE_ROOT_PATH_INVALID; + } + thread_nvm_store_create_path(lc_data_path, LEADER_INFO_FILE); + tr_debug("writing to store rloc mapping info"); + return thread_nvm_store_write(lc_data_path, mleid_rloc_map, sizeof(thread_nvm_mleid_rloc_map), LEADER_INFO_DATA_VERSION); +} + +int thread_nvm_store_mleid_rloc_map_read(thread_nvm_mleid_rloc_map *mleid_rloc_map) +{ + char lc_data_path[LEADER_INFO_STRING_LEN]; + uint32_t version; + if (NULL==mleid_rloc_map) { + return THREAD_NVM_FILE_PARAMETER_INVALID; + } + if (!root_path_valid()) { + return THREAD_NVM_FILE_ROOT_PATH_INVALID; + } + thread_nvm_store_create_path(lc_data_path, LEADER_INFO_FILE); + + int ret = thread_nvm_store_read(lc_data_path, mleid_rloc_map, sizeof(thread_nvm_mleid_rloc_map), &version); + + if (THREAD_NVM_FILE_SUCCESS!=ret) { + tr_info("Leader data map read failed"); + thread_nvm_store_mleid_rloc_map_remove(); + return ret; + } + + if (LEADER_INFO_DATA_VERSION!=version) { + tr_info("Leader data map version mismatch %"PRIu32, version); + thread_nvm_store_mleid_rloc_map_remove(); + return THREAD_NVM_FILE_VERSION_WRONG; + } + + return ret; +} + +int thread_nvm_store_mleid_rloc_map_remove(void) +{ + int status; + tr_info("thread_nvm_store_leader_info_remove"); + + if (!ns_file_system_get_root_path()) { + return THREAD_NVM_FILE_ROOT_PATH_INVALID; + } + + char lc_data_path[LEADER_INFO_STRING_LEN]; + thread_nvm_store_create_path(lc_data_path, LEADER_INFO_FILE); + status = remove(lc_data_path); + if (status != 0) { + return THREAD_NVM_FILE_REMOVE_ERROR; + } + return THREAD_NVM_FILE_SUCCESS; +} + int thread_nvm_store_device_configuration_write(uint8_t *mac_ptr, uint8_t *mleid_ptr) { thread_nvm_device_conf_t d_c; diff --git a/source/6LoWPAN/Thread/thread_nvm_store.h b/source/6LoWPAN/Thread/thread_nvm_store.h index d01a1719f2e..cd160590add 100644 --- a/source/6LoWPAN/Thread/thread_nvm_store.h +++ b/source/6LoWPAN/Thread/thread_nvm_store.h @@ -67,6 +67,15 @@ typedef struct { uint8_t mle_id[8]; } thread_nvm_device_conf_t; +typedef struct { + uint8_t mle_id[8]; +} thread_nvm_rloc_map_entry_t; + +typedef struct { + // mapping is in order from 0 to 63 + thread_nvm_rloc_map_entry_t mleid_rloc_map[64]; +} thread_nvm_mleid_rloc_map; + /* reads all fast data from nvm, if the return values is THREAD_NVM_FILE_ROOT_PATH_INVALID, the cached values are returned. */ int thread_nvm_store_fast_data_read(thread_nvm_fast_data_t* fast_data); /* stores all fast data to nvm */ @@ -87,6 +96,9 @@ int thread_nvm_store_active_configuration_remove(void); int thread_nvm_store_device_configuration_write(uint8_t *mac_ptr, uint8_t *mleid_ptr); int thread_nvm_store_device_configuration_read(uint8_t *mac_ptr, uint8_t *mleid_ptr); +int thread_nvm_store_mleid_rloc_map_write(thread_nvm_mleid_rloc_map *mleid_rloc_map); +int thread_nvm_store_mleid_rloc_map_read(thread_nvm_mleid_rloc_map *mleid_rloc_map); +int thread_nvm_store_mleid_rloc_map_remove(void); int thread_nvm_store_pending_configuration_write(void *data, uint16_t size); int thread_nvm_store_pending_configuration_read(void *data, uint16_t size); int thread_nvm_store_pending_configuration_remove(void); diff --git a/source/6LoWPAN/Thread/thread_resolution_server.c b/source/6LoWPAN/Thread/thread_resolution_server.c index 1440c48a5e6..292b7ca8436 100644 --- a/source/6LoWPAN/Thread/thread_resolution_server.c +++ b/source/6LoWPAN/Thread/thread_resolution_server.c @@ -91,6 +91,7 @@ static int thread_resolution_server_query_cb(int8_t service_id, uint8_t source_a uint8_t mlEID[8]; bool proxy; uint16_t rloc16; + uint16_t requestor_rloc; uint32_t last_transaction_time = 0; uint8_t *ptr; (void)source_port; @@ -118,9 +119,11 @@ static int thread_resolution_server_query_cb(int8_t service_id, uint8_t source_a return -1; } + requestor_rloc = common_read_16_bit(source_address + 14); + tr_debug("Thread address query %s", trace_ipv6(target_ip_ptr)); - int ret = this->query_cb_ptr(this->interface_id, target_ip_ptr, &rloc16, &proxy, &last_transaction_time, mlEID); + int ret = this->query_cb_ptr(this->interface_id, target_ip_ptr, &requestor_rloc, &rloc16, &proxy, &last_transaction_time, mlEID); if (ret < 0) { /* XXX "Forbidden" response? */ return -1; diff --git a/source/6LoWPAN/Thread/thread_resolution_server.h b/source/6LoWPAN/Thread/thread_resolution_server.h index 047538aa3f1..a3795a1867c 100644 --- a/source/6LoWPAN/Thread/thread_resolution_server.h +++ b/source/6LoWPAN/Thread/thread_resolution_server.h @@ -58,7 +58,7 @@ extern "C" { * * /return return 0 for success, negative if unable to respond. */ -typedef int thread_resolution_server_addr_query_cb(int8_t interface_id, const uint8_t target_addr[static 16], uint16_t *addr_out, bool *proxy, uint32_t *last_transaction_time, uint8_t *mleid_ptr); +typedef int thread_resolution_server_addr_query_cb(int8_t interface_id, const uint8_t target_addr[static 16], uint16_t *rloc, uint16_t *addr_out, bool *proxy, uint32_t *last_transaction_time, uint8_t *mleid_ptr); #ifdef HAVE_THREAD_NEIGHBOR_DISCOVERY diff --git a/source/6LoWPAN/Thread/thread_router_bootstrap.c b/source/6LoWPAN/Thread/thread_router_bootstrap.c index c6e8cd185f0..ced6b84281c 100644 --- a/source/6LoWPAN/Thread/thread_router_bootstrap.c +++ b/source/6LoWPAN/Thread/thread_router_bootstrap.c @@ -336,10 +336,11 @@ static void thread_router_synch_receive_cb(int8_t interface_id, mle_message_t *m case MLE_COMMAND_ACCEPT: { tr_info("Accept (ROUTER handler)"); uint32_t mleFrameCounter; + bool new_neigbour; uint16_t messageId = mle_tlv_validate_response(mle_msg->data_ptr, mle_msg->data_length); if (messageId == 0) { - tr_debug("Not for me"); + tr_debug("No matching challenge"); return; } /*Link accept command has an optional MLE Frame counter TLV, if this is not present use link layer frame counter TLV @@ -353,7 +354,7 @@ static void thread_router_synch_receive_cb(int8_t interface_id, mle_message_t *m } //Allocate neighbor entry - entry_temp = mle_class_get_entry_by_ll64(cur->id, linkMargin, mle_msg->packet_src_address, true); + entry_temp = mle_class_get_entry_by_ll64(cur->id, linkMargin, mle_msg->packet_src_address, true, &new_neigbour); if (!entry_temp) { return; } @@ -361,7 +362,6 @@ static void thread_router_synch_receive_cb(int8_t interface_id, mle_message_t *m //Free Response mle_service_msg_free(messageId); entry_temp->threadNeighbor = true; - mac_helper_devicetable_set(entry_temp, cur, llFrameCounter, security_headers->KeyIndex); entry_temp->short_adr = shortAddress; //when allocating neighbour entry, use MLE Frame counter if present to validate further advertisements from the neighbour entry_temp->mle_frame_counter = mleFrameCounter; @@ -388,7 +388,7 @@ static void thread_router_synch_receive_cb(int8_t interface_id, mle_message_t *m thread_routing_update_link_margin(cur, entry_temp->short_adr, linkMargin, linkMarginfronNeigh); } - mac_helper_devicetable_set(entry_temp, cur, llFrameCounter, security_headers->KeyIndex); + mac_helper_devicetable_set(entry_temp, cur, llFrameCounter, security_headers->KeyIndex, new_neigbour); //Copy Leader Data *cur->thread_info->thread_leader_data = leaderData; @@ -410,6 +410,8 @@ static void thread_router_synch_receive_cb(int8_t interface_id, mle_message_t *m cur->thread_info->thread_leader_data->dataVersion--; cur->thread_info->thread_leader_data->stableDataVersion--; thread_network_data_request_send(cur, mle_msg->packet_src_address, true); + // remove any existing rloc mapping in nvm + thread_nvm_store_mleid_rloc_map_remove(); tr_info("Router synch OK as Router"); } @@ -894,7 +896,7 @@ static int thread_attach_parent_response_build(protocol_interface_info_entry_t * if (bufId == 0) { return -1; } - tr_debug("MLE ATTACHED 2. Packet"); + tr_debug("Build MLE Parent response"); uint32_t keySequence; uint8_t *ptr = mle_service_get_data_pointer(bufId); @@ -1309,12 +1311,8 @@ void thread_router_bootstrap_child_id_handler(protocol_interface_info_entry_t *c memcpy(&ll64[8], req->euid64 , 8); ll64[8] ^= 2; //Allocate entry - mle_neigh_table_entry_t *entry_temp = mle_class_get_entry_by_ll64(cur->id, req->linkMargin, ll64, false); + mle_neigh_table_entry_t *entry_temp = mle_class_get_entry_by_ll64(cur->id, req->linkMargin, ll64, true, &new_neigbour); - if (!entry_temp) { - entry_temp = mle_class_get_entry_by_ll64(cur->id, req->linkMargin, ll64, true); - new_neigbour = true; - } if (!entry_temp) { //Send link reject thread_link_reject_send(cur, ll64); @@ -1340,7 +1338,7 @@ void thread_router_bootstrap_child_id_handler(protocol_interface_info_entry_t *c } } if (new_neigbour) { - mac_helper_devicetable_set(entry_temp, cur, req->frameCounter, req->keyId); + mac_helper_devicetable_set(entry_temp, cur, req->frameCounter, req->keyId, new_neigbour); } else { // in get response handler this will update the short address from MLE table mlme_get_t get_req; @@ -1361,7 +1359,6 @@ void thread_router_bootstrap_child_id_handler(protocol_interface_info_entry_t *c thread_nd_address_registration(cur, tempIPv6Address, entry_temp->short_adr, cur->mac_parameters->pan_id, entry_temp->mac64); } - tr_debug("Response Child Id Request"); mle_attach_child_id_response_build(cur,ll64,req, entry_temp); free_request: @@ -1474,7 +1471,7 @@ void thread_router_bootstrap_mle_receive_cb(int8_t interface_id, mle_message_t * } // parent request received - entry_temp = mle_class_get_entry_by_ll64(cur->id, linkMargin, mle_msg->packet_src_address, false); + entry_temp = mle_class_get_entry_by_ll64(cur->id, linkMargin, mle_msg->packet_src_address, false, NULL); if (entry_temp) { entry_temp->mode = (MLE_FFD_DEV | MLE_RX_ON_IDLE | MLE_THREAD_REQ_FULL_DATA_SET); } @@ -1595,7 +1592,7 @@ void thread_router_bootstrap_mle_receive_cb(int8_t interface_id, mle_message_t * uint16_t messageId = mle_tlv_validate_response(mle_msg->data_ptr, mle_msg->data_length); if (messageId == 0) { - tr_debug("Not for me"); + tr_debug("No matching challenge"); return; } @@ -1610,6 +1607,7 @@ void thread_router_bootstrap_mle_receive_cb(int8_t interface_id, mle_message_t * mle_msg->packet_src_address[8] ^= 2; if (!id_req) { + tr_debug("No room for child id req"); return; } @@ -1631,6 +1629,7 @@ void thread_router_bootstrap_mle_receive_cb(int8_t interface_id, mle_message_t * (!mle_tlv_read_32_bit_tlv(MLE_TYPE_LL_FRAME_COUNTER, mle_msg->data_ptr, mle_msg->data_length, &id_req->frameCounter)) || (!mle_tlv_read_tlv(MLE_TYPE_TLV_REQUEST, mle_msg->data_ptr, mle_msg->data_length, &tlvRequest))) { thread_child_id_request_entry_remove(cur, id_req); + tr_debug("Illegal child id req"); return; } //If MLE MLE_TYPE_MLE_FRAME_COUNTER TLV is present then use it for validating further messages else use link layer frame counter @@ -1727,7 +1726,7 @@ void thread_router_bootstrap_mle_receive_cb(int8_t interface_id, mle_message_t * return; } - entry_temp = mle_class_get_entry_by_ll64(cur->id, linkMargin, mle_msg->packet_src_address, false); + entry_temp = mle_class_get_entry_by_ll64(cur->id, linkMargin, mle_msg->packet_src_address, false, NULL); if (!mle_tlv_read_16_bit_tlv(MLE_TYPE_SRC_ADDRESS, mle_msg->data_ptr, mle_msg->data_length, &shortAddress)) { @@ -1826,12 +1825,12 @@ void thread_router_bootstrap_mle_receive_cb(int8_t interface_id, mle_message_t * uint16_t version, shortAddress; uint32_t llFrameCounter; mle_tlv_info_t requestTlv, challengeTlv; - bool createNew; + bool createNew, new_entry; tr_info("Recv Router Accept & Request"); uint16_t messageId = mle_tlv_validate_response(mle_msg->data_ptr, mle_msg->data_length); if (messageId == 0) { - tr_debug("Not for me"); + tr_debug("No matching challenge"); return; } @@ -1854,7 +1853,7 @@ void thread_router_bootstrap_mle_receive_cb(int8_t interface_id, mle_message_t * createNew = thread_bootstrap_link_create_check(cur, shortAddress); //Send Response - entry_temp = mle_class_get_entry_by_ll64(cur->id, linkMargin, mle_msg->packet_src_address, createNew); + entry_temp = mle_class_get_entry_by_ll64(cur->id, linkMargin, mle_msg->packet_src_address, createNew, &new_entry); if (entry_temp) { if (security_headers->KeyIdMode == MAC_KEY_ID_MODE_SRC4_IDX) { @@ -1863,7 +1862,7 @@ void thread_router_bootstrap_mle_receive_cb(int8_t interface_id, mle_message_t * entry_temp->threadNeighbor = true; entry_temp->short_adr = shortAddress; - mac_helper_devicetable_set(entry_temp, cur, llFrameCounter, security_headers->KeyIndex); + mac_helper_devicetable_set(entry_temp, cur, llFrameCounter, security_headers->KeyIndex, new_entry); if (entry_temp->timeout_rx) { mle_entry_timeout_refresh(entry_temp); } else { @@ -1900,7 +1899,7 @@ void thread_router_bootstrap_mle_receive_cb(int8_t interface_id, mle_message_t * mle_tlv_info_t addressRegisterTlv = {0}; mle_tlv_info_t challengeTlv = {0}; mle_tlv_info_t tlv_req = {0}; - entry_temp = mle_class_get_entry_by_ll64(cur->id, linkMargin, mle_msg->packet_src_address, false); + entry_temp = mle_class_get_entry_by_ll64(cur->id, linkMargin, mle_msg->packet_src_address, false, NULL); if (mle_tlv_read_8_bit_tlv(MLE_TYPE_STATUS, mle_msg->data_ptr, mle_msg->data_length, &status)) { if (1 == status && thread_check_is_this_my_parent(cur, entry_temp)) { @@ -1970,7 +1969,7 @@ void thread_router_bootstrap_mle_receive_cb(int8_t interface_id, mle_message_t * case MLE_COMMAND_DATA_REQUEST: { mle_tlv_info_t requestTlv; tr_info("Recv Router Data Request"); - entry_temp = mle_class_get_entry_by_ll64(cur->id, linkMargin, mle_msg->packet_src_address, false); + entry_temp = mle_class_get_entry_by_ll64(cur->id, linkMargin, mle_msg->packet_src_address, false, NULL); if (!entry_temp || !mle_tlv_read_tlv(MLE_TYPE_TLV_REQUEST, mle_msg->data_ptr, mle_msg->data_length, &requestTlv)) { return; } @@ -2372,6 +2371,16 @@ void thread_router_bootstrap_reed_advertisements_start(protocol_interface_info_e cur->thread_info->routerSelectParameters.reedAdvertisementTimeout = eventOS_timeout_ms(thread_reed_advertisements_cb,timeout, cur); } +void thread_router_bootstrap_reed_merge_advertisement(protocol_interface_info_entry_t *cur) +{ + if (cur->thread_info->reedMergeAdvTimer > 1) { + return; + } + thread_reed_advertise(cur); + // 120s second timer reinitialised before next merge advertisement + cur->thread_info->reedMergeAdvTimer = THREAD_REED_MERGE_ADVERTISEMENT_INTERVAL; + +} void thread_router_bootstrap_router_id_release(protocol_interface_info_entry_t *cur) { tr_debug("Router ID Release"); @@ -2421,6 +2430,12 @@ void thread_router_bootstrap_timer(protocol_interface_info_entry_t *cur, uint32_ } } + if (cur->thread_info->reedMergeAdvTimer > ticks) { + cur->thread_info->reedMergeAdvTimer -= ticks; + } else { + cur->thread_info->reedMergeAdvTimer = 0; + } + if (!thread_info->leader_private_data && thread_info->thread_attached_state == THREAD_STATE_CONNECTED_ROUTER) { // Non leader router checks if (thread_info->routing.activated) { diff --git a/source/6LoWPAN/Thread/thread_router_bootstrap.h b/source/6LoWPAN/Thread/thread_router_bootstrap.h index 823655879d4..faf2f7db0d6 100644 --- a/source/6LoWPAN/Thread/thread_router_bootstrap.h +++ b/source/6LoWPAN/Thread/thread_router_bootstrap.h @@ -45,6 +45,7 @@ struct mle_security_header; struct buffer; void thread_router_bootstrap_reed_advertisements_start(protocol_interface_info_entry_t *cur); +void thread_router_bootstrap_reed_merge_advertisement(protocol_interface_info_entry_t *cur); int thread_router_bootstrap_mle_advertise(struct protocol_interface_info_entry *cur); void thread_router_bootstrap_child_information_clear(protocol_interface_info_entry_t *cur); @@ -101,6 +102,7 @@ void thread_router_bootstrap_address_change_notify_send(protocol_interface_info_ #define thread_router_bootstrap_network_data_distribute(cur) #define thread_router_bootstrap_routing_allowed(cur) false #define thread_router_bootstrap_address_change_notify_send(cur) +#define thread_router_bootstrap_reed_merge_advertisement(cur) #endif/*HAVE_THREAD_ROUTER*/ diff --git a/source/6LoWPAN/Thread/thread_routing.c b/source/6LoWPAN/Thread/thread_routing.c index ec672ae26aa..8fdf01da7b6 100644 --- a/source/6LoWPAN/Thread/thread_routing.c +++ b/source/6LoWPAN/Thread/thread_routing.c @@ -768,6 +768,8 @@ static void delete_link(thread_info_t *thread, thread_router_link_t *link) thread_router_id_t id = link->router_id; thread_routing_info_t *routing = &thread->routing; + tr_debug("delete_link: router: %x", thread_router_addr_from_id(link->router_id)); + /* Remove entry from the link set */ ns_list_remove(&routing->link_set, link); ns_dyn_mem_free(link); @@ -779,7 +781,6 @@ static void delete_link(thread_info_t *thread, thread_router_link_t *link) ns_dyn_mem_free(route_entry); } } - thread_update_fast_route_table(thread); } @@ -879,7 +880,6 @@ void thread_routing_init(thread_routing_info_t *routing) { ns_list_init(&routing->route_set); ns_list_init(&routing->link_set); - routing->networkIdTimeout = NETWORK_ID_TIMEOUT; thread_routing_reset(routing); } @@ -887,6 +887,7 @@ void thread_routing_reset(thread_routing_info_t *routing) { thread_routing_free(routing); routing->router_id_sequence_valid = false; + routing->networkIdTimeout = NETWORK_ID_TIMEOUT; memset(routing->fast_route_table, FAST_ROUTE_INVALID_ID, sizeof routing->fast_route_table); trickle_start(&routing->mle_advert_timer, &thread_mle_advert_trickle_params); } diff --git a/source/6LoWPAN/Thread/thread_test_api.c b/source/6LoWPAN/Thread/thread_test_api.c index be81d1736c8..c6504beee84 100644 --- a/source/6LoWPAN/Thread/thread_test_api.c +++ b/source/6LoWPAN/Thread/thread_test_api.c @@ -47,6 +47,7 @@ #include "6LoWPAN/Thread/thread_bootstrap.h" #include "6LoWPAN/Thread/thread_router_bootstrap.h" #include "6LoWPAN/Thread/thread_discovery.h" +#include "6LoWPAN/Thread/thread_nvm_store.h" #include "6LoWPAN/Thread/thread_extension_bootstrap.h" #include "MLE/mle.h" #include "thread_meshcop_lib.h" @@ -413,6 +414,27 @@ int thread_test_key_sequence_counter_update(int8_t interface_id, uint32_t thrKey #endif } +int thread_test_stack_cache_reset(int8_t interface_id) +{ +#ifdef HAVE_THREAD + protocol_interface_info_entry_t *cur; + + cur = protocol_stack_interface_info_get_by_id(interface_id); + if (!cur) { + tr_warn("Invalid interface id"); + return -1; + } + + // Reset link information + (void) thread_nvm_store_link_info_clear(); + + return 0; +#else + (void)interface_id; + return -1; +#endif +} + int thread_test_key_rotation_update(int8_t interface_id, uint32_t thrKeyRotation) { #ifdef HAVE_THREAD diff --git a/source/6LoWPAN/adaptation_interface.c b/source/6LoWPAN/adaptation_interface.c index 3cb43a30a22..230a21893c0 100644 --- a/source/6LoWPAN/adaptation_interface.c +++ b/source/6LoWPAN/adaptation_interface.c @@ -1014,6 +1014,12 @@ int8_t lowpan_adaptation_interface_tx_confirm(protocol_interface_info_entry_t *c case MLME_TRANSACTION_EXPIRED: default: tr_error("MCPS Data fail by status %u", confirm->status); + if (buf->dst_sa.addr_type == ADDR_802_15_4_SHORT) { + tr_info("Dest addr: %x", common_read_16_bit(buf->dst_sa.address+2)); + } else if (buf->dst_sa.addr_type == ADDR_802_15_4_LONG) { + tr_info("Dest addr: %s", trace_array(buf->dst_sa.address+2, 8)); + } + #ifdef HAVE_RPL if (confirm->status == MLME_TX_NO_ACK) { if (buf->route && rpl_data_is_rpl_parent_route(buf->route->route_info.source)) { diff --git a/source/Common_Protocols/icmpv6.c b/source/Common_Protocols/icmpv6.c index dec3f280be2..6c4240b65de 100644 --- a/source/Common_Protocols/icmpv6.c +++ b/source/Common_Protocols/icmpv6.c @@ -48,7 +48,6 @@ #define TRACE_GROUP "icmp" static buffer_t *icmpv6_echo_request_handler(struct buffer *buf); -static buffer_t *icmpv6_na_handler(struct buffer *buf); /* Check to see if a message is recognisable ICMPv6, and if so, fill in code/type */ /* This used ONLY for the e.1 + e.2 tests in RFC 4443, to try to avoid ICMPv6 error loops */ @@ -280,6 +279,11 @@ buffer_t *icmpv6_packet_too_big_handler(buffer_t *buf) const uint8_t *ptr = buffer_data_pointer(buf); uint32_t mtu = common_read_32_bit(ptr); + /* RFC 8201 - ignore MTU smaller than minimum */ + if (mtu < IPV6_MIN_LINK_MTU) { + return buffer_free(buf); + } + ptr = buffer_data_strip_header(buf, 4); /* Check source is us */ @@ -481,7 +485,6 @@ static buffer_t *icmpv6_ns_handler(buffer_t *buf) * interface, which we should only do in the whiteboard case. */ if (addr_interface_address_compare(cur, target) != 0) { - int8_t mesh_id = -1; //tr_debug("Received NS for proxy %s", trace_ipv6(target)); proxy = true; @@ -490,7 +493,7 @@ static buffer_t *icmpv6_ns_handler(buffer_t *buf) goto drop; } - if (!nd_proxy_enabled_for_downstream(cur->id) || !nd_proxy_target_address_validation(cur->id, target, &mesh_id)) { + if (!nd_proxy_enabled_for_downstream(cur->id) || !nd_proxy_target_address_validation(cur->id, target)) { goto drop; } } @@ -917,6 +920,80 @@ static buffer_t *icmpv6_redirect_handler(buffer_t *buf, protocol_interface_info_ tr_warn("Redirect drop"); return buffer_free(buf); } + +static buffer_t *icmpv6_na_handler(buffer_t *buf) +{ + protocol_interface_info_entry_t *cur; + uint8_t *dptr = buffer_data_pointer(buf); + uint8_t flags; + const uint8_t *target; + const uint8_t *tllao; + if_address_entry_t *addr_entry; + ipv6_neighbour_t *neighbour_entry; + + //"Parse NA at IPv6\n"); + + if (buf->options.code != 0 || buf->options.hop_limit != 255) { + goto drop; + } + + if (!icmpv6_options_well_formed_in_buffer(buf, 20)) { + goto drop; + } + + // Skip the 4 reserved bytes + flags = *dptr; + dptr += 4; + + // Note the target IPv6 address + target = dptr; + + if (addr_is_ipv6_multicast(target)) { + goto drop; + } + + /* Solicited flag must be clear if sent to a multicast address */ + if (addr_is_ipv6_multicast(buf->dst_sa.address) && (flags & NA_S)) { + goto drop; + } + + cur = buf->interface; + + /* RFC 4862 5.4.4 DAD checks */ + addr_entry = addr_get_entry(cur, target); + if (addr_entry) { + if (addr_entry->tentative) { + tr_debug("Received NA for our tentative address"); + addr_duplicate_detected(cur, target); + } else { + tr_debug("NA received for our own address: %s", trace_ipv6(target)); + } + goto drop; + } + + if (cur->ipv6_neighbour_cache.recv_na_aro) { + const uint8_t *aro = icmpv6_find_option_in_buffer(buf, 20, ICMPV6_OPT_ADDR_REGISTRATION, 2); + if (aro) { + icmpv6_na_aro_handler(cur, aro, buf->dst_sa.address); + } + } + + /* No need to create a neighbour cache entry if one doesn't already exist */ + neighbour_entry = ipv6_neighbour_lookup(&cur->ipv6_neighbour_cache, target); + if (!neighbour_entry) { + goto drop; + } + + tllao = icmpv6_find_option_in_buffer(buf, 20, ICMPV6_OPT_TGT_LL_ADDR, 0); + if (!tllao || !cur->if_llao_parse(cur, tllao, &buf->dst_sa)) { + buf->dst_sa.addr_type = ADDR_NONE; + } + + ipv6_neighbour_update_from_na(&cur->ipv6_neighbour_cache, neighbour_entry, flags, buf->dst_sa.addr_type, buf->dst_sa.address); + +drop: + return buffer_free(buf); +} #endif // HAVE_IPV6_ND buffer_t *icmpv6_up(buffer_t *buf) @@ -989,7 +1066,7 @@ buffer_t *icmpv6_up(buffer_t *buf) case ICMPV6_TYPE_INFO_ECHO_REPLY: ipv6_neighbour_reachability_confirmation(buf->src_sa.address, buf->interface->id); - /* no break */ + /* fall through */ case ICMPV6_TYPE_ERROR_DESTINATION_UNREACH: #ifdef HAVE_RPL_ROOT @@ -1494,79 +1571,6 @@ buffer_t *icmpv6_build_na(protocol_interface_info_entry_t *cur, bool solicited, return (buf); } -static buffer_t *icmpv6_na_handler(buffer_t *buf) -{ - protocol_interface_info_entry_t *cur; - uint8_t *dptr = buffer_data_pointer(buf); - uint8_t flags; - const uint8_t *target; - const uint8_t *tllao; - if_address_entry_t *addr_entry; - ipv6_neighbour_t *neighbour_entry; - - //"Parse NA at IPv6\n"); - - if (buf->options.code != 0 || buf->options.hop_limit != 255) { - goto drop; - } - - if (!icmpv6_options_well_formed_in_buffer(buf, 20)) { - goto drop; - } - - // Skip the 4 reserved bytes - flags = *dptr; - dptr += 4; - - // Note the target IPv6 address - target = dptr; - - if (addr_is_ipv6_multicast(target)) { - goto drop; - } - - /* Solicited flag must be clear if sent to a multicast address */ - if (addr_is_ipv6_multicast(buf->dst_sa.address) && (flags & NA_S)) { - goto drop; - } - - cur = buf->interface; - - /* RFC 4862 5.4.4 DAD checks */ - addr_entry = addr_get_entry(cur, target); - if (addr_entry) { - if (addr_entry->tentative) { - tr_debug("Received NA for our tentative address"); - addr_duplicate_detected(cur, target); - } else { - tr_debug("NA received for our own address: %s", trace_ipv6(target)); - } - goto drop; - } - - if (cur->ipv6_neighbour_cache.recv_na_aro) { - const uint8_t *aro = icmpv6_find_option_in_buffer(buf, 20, ICMPV6_OPT_ADDR_REGISTRATION, 2); - if (aro) { - icmpv6_na_aro_handler(cur, aro, buf->dst_sa.address); - } - } - - /* No need to create a neighbour cache entry if one doesn't already exist */ - neighbour_entry = ipv6_neighbour_lookup(&cur->ipv6_neighbour_cache, target); - if (!neighbour_entry) { - goto drop; - } - - tllao = icmpv6_find_option_in_buffer(buf, 20, ICMPV6_OPT_TGT_LL_ADDR, 0); - if (!tllao || !cur->if_llao_parse(cur, tllao, &buf->dst_sa)) { - buf->dst_sa.addr_type = ADDR_NONE; - } - - ipv6_neighbour_update_from_na(&cur->ipv6_neighbour_cache, neighbour_entry, flags, buf->dst_sa.addr_type, buf->dst_sa.address); - -drop: - return buffer_free(buf); -} #endif // HAVE_IPV6_ND #ifdef HAVE_IPV6_ND diff --git a/source/Common_Protocols/ipv6_fragmentation.c b/source/Common_Protocols/ipv6_fragmentation.c index bc265b1ba99..13169a0c191 100644 --- a/source/Common_Protocols/ipv6_fragmentation.c +++ b/source/Common_Protocols/ipv6_fragmentation.c @@ -21,15 +21,12 @@ * References: * * RFC 815 IP Datagram Reassembly Algorithms - * RFC 2460 Internet Protocol. Version 6 (IPv6) Specification * RFC 3168 The Addition of Explicit Congestion Notification (ECN) to IP - * RFC 5722 Handling of Overlapping IPv6 Fragments * RFC 6040 Tunnelling of Explicit Congestion Notification - * RFC 6145 IP/ICMP Translation Algorithm [sections on Path MTU] * RFC 6660 Encoding Three Pre-Congestion Notification (PCN) States in the * IP Header Using a Single Diffserv Codepoint (DSCP) - * RFC 6946 Processing of IPv6 "Atomic" Fragments - * RFC 7112 Implications of Oversized IPv6 Header Chains + * RFC 8200 Internet Protocol, Version 6 (IPv6) Specification + * RFC 8201 Path MTU Discovery for IP version 6 */ #include "nsconfig.h" #include "ns_types.h" @@ -656,35 +653,6 @@ buffer_t *ipv6_frag_down(buffer_t *dgram_buf) *nh_ptr = IPV6_NH_FRAGMENT; - /* Special case for atomic fragments (caused by a small PMTU) */ - /* Note that we DO have the option of actually fragmenting and obeying - * a small PMTU, which would avoid this special case. - */ - if (buffer_data_length(dgram_buf) <= IPV6_MIN_LINK_MTU - 8) { - dgram_buf = buffer_headroom(dgram_buf, 8); - if (!dgram_buf) { - return NULL; - } - - /* Move unfragmentable section back 8 bytes; increase IP length field */ - ip_ptr = buffer_data_reserve_header(dgram_buf, 8); - memmove(ip_ptr, ip_ptr + 8, unfrag_len); - common_write_16_bit(common_read_16_bit(ip_ptr + 4) + 8, ip_ptr + 4); - - /* Write atomic fragment header into the gap */ - frag_hdr = ip_ptr + unfrag_len; - frag_hdr[0] = nh; - frag_hdr[1] = 0; - common_write_16_bit(0, frag_hdr + 2); - common_write_32_bit(++dest->fragment_id, frag_hdr + 4); - return dgram_buf; - } - - /* We won't fragment below minimum MTU. (Although we could...) */ - if (pmtu < IPV6_MIN_LINK_MTU) { - pmtu = IPV6_MIN_LINK_MTU; - } - /* Check for silly situation - can't fit any fragment data (8 for fragment * header, 8 for minimum fragment payload) */ if (unfrag_len + 8 + 8 > pmtu) { diff --git a/source/Common_Protocols/tcp.c b/source/Common_Protocols/tcp.c index d492f563004..5fb61554ede 100644 --- a/source/Common_Protocols/tcp.c +++ b/source/Common_Protocols/tcp.c @@ -559,7 +559,7 @@ tcp_error tcp_session_abort(tcp_session_t *tcp_session) case TCP_STATE_FIN_WAIT_2: case TCP_STATE_CLOSE_WAIT: tcp_session_send_reset_to_abort_connection(tcp_session); - /* no break */ + /* fall through */ case TCP_STATE_LISTEN: case TCP_STATE_SYN_SENT: tcp_session_delete_with_error(tcp_session, SOCKET_CONNECTION_RESET); diff --git a/source/Core/address.c b/source/Core/address.c index 395a0e4be70..31b4434e75f 100644 --- a/source/Core/address.c +++ b/source/Core/address.c @@ -1354,14 +1354,23 @@ int8_t addr_interface_address_compare(protocol_interface_info_entry_t *cur, cons return 0; } - /* If link-local, that's it */ - if (addr_is_ipv6_link_local(addr)) { - return -1; + /* Then check other interfaces, enforcing scope zones */ + uint_fast8_t scope = addr_ipv6_scope(addr, cur); + ns_list_foreach(protocol_interface_info_entry_t, other, &protocol_interface_info_list) { + if (other != cur && + other->zone_index[scope] == cur->zone_index[scope] && + addr_is_assigned_to_interface(other, addr)) { + // special handling for Thread - external global-scope ULA coming in, + // which would match, but we need to restrict if that ULA is mesh-local + // on the Thread side. + if (thread_info(other) && addr_ipv6_scope(addr, other) <= IPV6_SCOPE_REALM_LOCAL) { + continue; + } + return 0; + } } - /* Now check other interfaces */ - /* TODO: should only do this if both current and other interface have forwarding enabled */ - return protcol_interface_address_compare(cur, addr); + return -1; } int8_t addr_interface_select_source(protocol_interface_info_entry_t *cur, uint8_t *src_ptr, const uint8_t *dest, uint32_t addr_preferences) diff --git a/source/Core/include/ns_buffer.h b/source/Core/include/ns_buffer.h index 5e4681bbeb9..60e5f22bff4 100644 --- a/source/Core/include/ns_buffer.h +++ b/source/Core/include/ns_buffer.h @@ -340,12 +340,20 @@ struct socket *buffer_socket_set(buffer_t *buf, struct socket *socket); /** Removes z amount of bytes from the begining of buffer * uint8_t *buffer_data_strip_header(buffer_t *x, uint16_t z) * */ -#define buffer_data_strip_header(x,z) ((x)->buf_ptr += (z), buffer_data_pointer_after_adjustment(x)) +static inline uint8_t *buffer_data_strip_header(buffer_t *x, uint16_t z) +{ + x->buf_ptr += z; + return buffer_data_pointer_after_adjustment(x); +} /** Adds z amount of bytes to the begining of buffer check if this is allowed using buffer_headroom method. * uint8_t *buffer_data_reserve_header(buffer_t *x, uint16_t z) * */ -#define buffer_data_reserve_header(x,z) ((x)->buf_ptr -= (z), buffer_data_pointer_after_adjustment(x)) +static inline uint8_t *buffer_data_reserve_header(buffer_t *x, uint16_t z) +{ + x->buf_ptr -= z; + return buffer_data_pointer_after_adjustment(x); +} /** append 1 byte to data*/ #define buffer_push_uint8(x, z) do {\ diff --git a/source/Core/ns_socket.c b/source/Core/ns_socket.c index 08f5fd4173d..01f7fe2360e 100644 --- a/source/Core/ns_socket.c +++ b/source/Core/ns_socket.c @@ -1301,7 +1301,7 @@ int16_t socket_buffer_sendmsg(int8_t sid, buffer_t *buf, const struct ns_msghdr * address is valid in one of the available interfaces * */ if (buf->src_sa.addr_type == ADDR_IPV6 && - protcol_interface_address_compare(NULL, buf->src_sa.address) != 0) { + protocol_interface_address_compare(buf->src_sa.address) != 0) { tr_warn("Specified source address %s is not valid",trace_ipv6(buf->src_sa.address)); ret_val = -3; goto fail; diff --git a/source/MAC/IEEE802_15_4/mac_header_helper_functions.c b/source/MAC/IEEE802_15_4/mac_header_helper_functions.c index 1a23d00b38b..e5ed44e63e5 100644 --- a/source/MAC/IEEE802_15_4/mac_header_helper_functions.c +++ b/source/MAC/IEEE802_15_4/mac_header_helper_functions.c @@ -58,8 +58,10 @@ uint8_t mac_header_security_aux_header_length(uint8_t security_level, uint8_t ke switch (keyIdmode) { case MAC_KEY_ID_MODE_SRC8_IDX: header_length += 4; //64-bit key source first part + /* fall through */ case MAC_KEY_ID_MODE_SRC4_IDX: header_length += 4; //32-bit key source inline + /* fall through */ case MAC_KEY_ID_MODE_IDX: header_length += 1; break; @@ -128,8 +130,10 @@ void mac_header_security_parameter_set(mac_aux_security_header_t *header, const case MAC_KEY_ID_MODE_SRC8_IDX: keysource_len += 4; //64-bit key source first part + /* fall through */ case MAC_KEY_ID_MODE_SRC4_IDX: keysource_len += 4; //32-bit key source inline + /* fall through */ case MAC_KEY_ID_MODE_IDX: //Security header + 32-bit security counter + Key index header->KeyIndex = frame_setup->KeyIndex; @@ -198,10 +202,12 @@ void mac_header_security_components_read(mac_pre_parsed_frame_t *buffer, mlme_se break; case MAC_KEY_ID_MODE_SRC8_IDX: key_source_len += 4; + /* fall through */ case MAC_KEY_ID_MODE_SRC4_IDX: key_source_len += 4; memcpy(security_params->Keysource, ptr, key_source_len); ptr += key_source_len; + /* fall through */ case MAC_KEY_ID_MODE_IDX: security_params->KeyIndex = *ptr; break; diff --git a/source/MLE/mle.c b/source/MLE/mle.c index b70eb607999..39177b1537d 100644 --- a/source/MLE/mle.c +++ b/source/MLE/mle.c @@ -386,9 +386,8 @@ int16_t mle_class_rfd_entry_count_get(int8_t interface_id) return count; } -mle_neigh_table_entry_t *mle_class_get_entry_by_ll64(int8_t interface_id, uint8_t linkMargin, const uint8_t *ipv6Address, bool allocateNew) +mle_neigh_table_entry_t *mle_class_get_entry_by_ll64(int8_t interface_id, uint8_t linkMargin, const uint8_t *ipv6Address, bool allocateNew, bool *new_entry_allocated) { - // Check it really is LL64 (not LL16) if (memcmp(ipv6Address, ADDR_LINK_LOCAL_PREFIX , 8) != 0) { @@ -403,10 +402,9 @@ mle_neigh_table_entry_t *mle_class_get_entry_by_ll64(int8_t interface_id, uint8_ memcpy(temporary_mac64, (ipv6Address + 8), 8); temporary_mac64[0] ^= 2; - return mle_class_get_entry_by_mac64(interface_id, linkMargin, temporary_mac64,allocateNew); + return mle_class_get_entry_by_mac64(interface_id, linkMargin, temporary_mac64, allocateNew, new_entry_allocated); } - mle_neigh_table_entry_t *mle_class_discover_entry_by_ll64(int8_t interface_id, const uint8_t *ipv6Address) { @@ -428,7 +426,7 @@ mle_neigh_table_entry_t *mle_class_discover_entry_by_ll64(int8_t interface_id, c } -mle_neigh_table_entry_t *mle_class_get_entry_by_mac64(int8_t interface_id, uint8_t linkMargin, const uint8_t *mac64, bool allocateNew) +mle_neigh_table_entry_t *mle_class_get_entry_by_mac64(int8_t interface_id, uint8_t linkMargin, const uint8_t *mac64, bool allocateNew, bool *new_entry_allocated) { mle_table_class_t *mle_class_ptr = mle_table_class_discover(interface_id); //Clean list and set function pointer call backs @@ -436,6 +434,10 @@ mle_neigh_table_entry_t *mle_class_get_entry_by_mac64(int8_t interface_id, uint8 return NULL; } + if (new_entry_allocated) { + *new_entry_allocated = false; + } + mle_neigh_table_entry_t *ret_val = mle_class_neighbor_get(&mle_class_ptr->mle_table, mac64, ADDR_802_15_4_LONG); @@ -454,6 +456,9 @@ mle_neigh_table_entry_t *mle_class_get_entry_by_mac64(int8_t interface_id, uint8 topo_trace(TOPOLOGY_MLE, mac64, TOPO_ADD); ret_val->link_margin = linkMargin << THREAD_LINK_MARGIN_SCALING; memcpy(ret_val->mac64, mac64, 8); + if (new_entry_allocated) { + *new_entry_allocated = true; + } } } return ret_val; @@ -788,7 +793,7 @@ bool mle_neigh_entry_frame_counter_update(mle_neigh_table_entry_t *entry_temp, u frame_counter = common_read_32_bit(mle_tlv_info.dataPtr); } - mac_helper_devicetable_set(entry_temp, cur, frame_counter, key_id); + mac_helper_devicetable_set(entry_temp, cur, frame_counter, key_id, false); return true; } diff --git a/source/MLE/mle.h b/source/MLE/mle.h index 59600b5f0d5..3d16cdec405 100644 --- a/source/MLE/mle.h +++ b/source/MLE/mle.h @@ -211,11 +211,11 @@ int8_t mle_class_set_new_key_pending(int8_t interface_id); int16_t mle_class_free_entry_count_get(int8_t interface_id); -mle_neigh_table_entry_t *mle_class_get_entry_by_ll64(int8_t interface_id, uint8_t linkMargin, const uint8_t *ipv6Address, bool allocateNew); +mle_neigh_table_entry_t *mle_class_get_entry_by_ll64(int8_t interface_id, uint8_t linkMargin, const uint8_t *ipv6Address, bool allocateNew, bool *new_entry_allocated); mle_neigh_table_entry_t *mle_class_discover_entry_by_ll64(int8_t interface_id, const uint8_t *ipv6Address); -mle_neigh_table_entry_t *mle_class_get_entry_by_mac64(int8_t interface_id, uint8_t linkMargin, const uint8_t *mac64, bool allocateNew); +mle_neigh_table_entry_t *mle_class_get_entry_by_mac64(int8_t interface_id, uint8_t linkMargin, const uint8_t *mac64, bool allocateNew, bool *new_entry_allocated); mle_neigh_table_entry_t *mle_class_get_by_link_address(int8_t interface_id, const uint8_t *address, addrtype_t type); diff --git a/source/MPL/mpl.c b/source/MPL/mpl.c index b72600da69f..9ad06d49d3b 100644 --- a/source/MPL/mpl.c +++ b/source/MPL/mpl.c @@ -685,7 +685,8 @@ buffer_t *mpl_control_handler(buffer_t *buf, protocol_interface_info_entry_t *cu // by its colour not being flipped. // This is equivalent to having a "mentioned" flag, except we don't have // to have a separate "reset" loop. - bool new_colour = --domain->colour; // smart-alec binary flip + domain->colour = !domain->colour; + bool new_colour = domain->colour; while (ptr < end) { if (end - ptr < 2) { diff --git a/source/NWK_INTERFACE/Include/protocol.h b/source/NWK_INTERFACE/Include/protocol.h index c2bb96fabd7..1e7290c1184 100644 --- a/source/NWK_INTERFACE/Include/protocol.h +++ b/source/NWK_INTERFACE/Include/protocol.h @@ -507,5 +507,5 @@ 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 protcol_interface_address_compare(protocol_interface_info_entry_t *cur, const uint8_t *addr); +int8_t protocol_interface_address_compare(const uint8_t *addr); #endif /* _NS_PROTOCOL_H */ diff --git a/source/NWK_INTERFACE/protocol_core.c b/source/NWK_INTERFACE/protocol_core.c index 4590ef324e4..2950b79964e 100644 --- a/source/NWK_INTERFACE/protocol_core.c +++ b/source/NWK_INTERFACE/protocol_core.c @@ -1085,10 +1085,12 @@ void protocol_core_dhcpv6_allocated_address_remove(protocol_interface_info_entry } } -int8_t protcol_interface_address_compare(protocol_interface_info_entry_t *cur, const uint8_t *addr) +/* XXX note that this does not perform any scope checks, so will for example match + * link local addresses on any interface - you may want addr_interface_address_compare */ +int8_t protocol_interface_address_compare(const uint8_t *addr) { - ns_list_foreach(protocol_interface_info_entry_t, other, &protocol_interface_info_list) { - if (other != cur && addr_is_assigned_to_interface(other, addr)) { + ns_list_foreach(protocol_interface_info_entry_t, cur, &protocol_interface_info_list) { + if (addr_is_assigned_to_interface(cur, addr)) { return 0; } } diff --git a/source/RPL/rpl_control.c b/source/RPL/rpl_control.c index 229eade4bc6..703f81c261f 100644 --- a/source/RPL/rpl_control.c +++ b/source/RPL/rpl_control.c @@ -855,7 +855,7 @@ static buffer_t *rpl_control_dio_handler(protocol_interface_info_entry_t *cur, r } /* Even if we're not currently rooting - what if it's our address? Ignore stale info on network */ - if (protcol_interface_address_compare(NULL, dodagid) == 0) { + if (addr_interface_address_compare(cur, dodagid) == 0) { tr_info("DIO our DODAGID %s", trace_ipv6(dodagid)); /* Should we transmit poison? */ goto invalid_parent; diff --git a/source/RPL/rpl_downward.c b/source/RPL/rpl_downward.c index 2f7d9c95d46..d9c98dc63d8 100644 --- a/source/RPL/rpl_downward.c +++ b/source/RPL/rpl_downward.c @@ -1059,7 +1059,7 @@ static bool rpl_downward_process_targets_for_transit(rpl_dodag_t *dodag, bool st /* In Non-Storing mode, add the transit to the target, and we'll re-evaluate system routes later */ ipv6_route_table_remove_info(-1, ROUTE_RPL_DAO_SR, target); if (transit_opt) { - if (protcol_interface_address_compare(NULL, parent) == 0) { + if (protocol_interface_address_compare(parent) == 0) { /* If we're transit, it's on-link */ ipv6_route_add_with_info(prefix, prefix_len, interface_id, NULL, ROUTE_RPL_DAO_SR, target, 0, target->lifetime, 0); } else { @@ -1122,7 +1122,7 @@ static void rpl_downward_link_transits_to_targets(rpl_instance_t *instance) } ns_list_foreach(rpl_dao_target_t, target, &instance->dao_targets) { ns_list_foreach(rpl_dao_root_transit_t, transit, &target->info.root.transits) { - if (protcol_interface_address_compare(NULL, transit->transit) == 0) { + if (protocol_interface_address_compare(transit->transit) == 0) { /* It points to us (the DODAG root) - mark this with NULL */ transit->parent = NULL; target->connected = true; diff --git a/source/Service_Libs/fhss/fhss_beacon_tasklet.c b/source/Service_Libs/fhss/fhss_beacon_tasklet.c index 2ba416cf909..7c54b6d2b0f 100644 --- a/source/Service_Libs/fhss/fhss_beacon_tasklet.c +++ b/source/Service_Libs/fhss/fhss_beacon_tasklet.c @@ -68,7 +68,9 @@ static void fhss_beacon_tasklet_func(arm_event_s* event) if (!fhss_structure) { return; } +#ifdef FEA_TRACE_SUPPORT uint8_t parent_address[8]; +#endif fhss_clear_active_event(fhss_structure, event->event_type); // skip the init event as there will be a timer event after if (event->event_type == FHSS_TIMER_EVENT) { diff --git a/source/Service_Libs/mle_service/mle_service.c b/source/Service_Libs/mle_service/mle_service.c index 9bded4cb8db..45c5c081d3e 100644 --- a/source/Service_Libs/mle_service/mle_service.c +++ b/source/Service_Libs/mle_service/mle_service.c @@ -68,6 +68,10 @@ typedef struct { mle_service_class_t *mle_service = NULL; +#ifdef MLE_TEST +static mle_service_filter_cb *receive_filter_cb = NULL; +#endif + static uint8_t *mle_security_aux_header_write(uint8_t *ptr, const mle_security_header_t *auxHeader); static void mle_security_aux_ccm_nonce_set(uint8_t *noncePtr, uint8_t *mac64, uint32_t securityFrameCounter, uint8_t securityLevel); static uint8_t mle_security_aux_header_size(uint8_t keyIdMode); @@ -802,6 +806,13 @@ static void mle_service_socket_callback(void *cb) mle_msg.dbm = buf->options.dbm; mle_msg.lqi = buf->options.lqi; +#ifdef MLE_TEST + if (receive_filter_cb) { + if (!receive_filter_cb(service_handler->interface_id, &mle_msg, &securityHeader)) { + goto error_handler; + } + } +#endif if (security_bypass) { /* Security by pass message handler call */ service_handler->recv_security_bypass_cb(service_handler->interface_id, &mle_msg); @@ -812,7 +823,7 @@ static void mle_service_socket_callback(void *cb) } } - error_handler: +error_handler: if (buf) { buffer_free(buf); } @@ -1199,7 +1210,7 @@ int mle_service_message_tail_get(uint16_t msgId, uint16_t tail_length) return mle_service_buffer_tail_get(msgId,tail_length); } -int mle_service_set_msg_timeout_parameters(uint16_t msgId, mle_message_timeout_params_t *timeout_params) +static int mle_service_timeout_fill(uint16_t msgId, mle_message_timeout_params_t *timeout_params, bool timeout_in_seconds) { mle_service_msg_buf_t *buffer = mle_service_buffer_find(msgId); @@ -1207,14 +1218,33 @@ int mle_service_set_msg_timeout_parameters(uint16_t msgId, mle_message_timeout_p return -1; } - buffer->timeout_init = randLIB_randomise_base(timeout_params->timeout_init * 10, MLE_RAND_LOW, MLE_RAND_HIGH); - buffer->timeout = buffer->timeout_init; - buffer->timeout_max = timeout_params->timeout_max * 10; + buffer->timeout_max = timeout_params->timeout_max; buffer->retrans_max = timeout_params->retrans_max; buffer->delayed_response = timeout_params->delay; + buffer->timeout_init = timeout_params->timeout_init; + + if (timeout_in_seconds) { + buffer->timeout_max = buffer->timeout_max * 10; + buffer->timeout_init = buffer->timeout_init * 10; + } + + buffer->timeout_init = randLIB_randomise_base(buffer->timeout_init, MLE_RAND_LOW, MLE_RAND_HIGH); + + buffer->timeout = buffer->timeout_init; + return 0; } +int mle_service_set_msg_timeout_parameters(uint16_t msgId, mle_message_timeout_params_t *timeout_params) +{ + return mle_service_timeout_fill(msgId, timeout_params, true); +} + +int mle_service_set_msg_timeout_parameters_fast(uint16_t msgId, mle_message_timeout_params_t *timeout_params) +{ + return mle_service_timeout_fill(msgId, timeout_params, false); +} + int mle_service_set_msg_token_bucket_priority(uint16_t msgId) { mle_service_msg_buf_t *buffer = mle_service_buffer_find(msgId); @@ -1497,3 +1527,10 @@ void mle_service_set_accept_invalid_frame_counter(bool value) } } +#ifdef MLE_TEST +void mle_service_receive_filter_cb_set(mle_service_filter_cb *filter_cb) +{ + receive_filter_cb = filter_cb; +} + +#endif diff --git a/source/Service_Libs/mle_service/mle_service_api.h b/source/Service_Libs/mle_service/mle_service_api.h index 97417663856..2efcf8e6013 100644 --- a/source/Service_Libs/mle_service/mle_service_api.h +++ b/source/Service_Libs/mle_service/mle_service_api.h @@ -126,8 +126,8 @@ typedef struct { * */ typedef struct { -uint16_t timeout_init; /*!< Define start timeout in seconds */ -uint16_t timeout_max; /*!< Define max timeout time in seconds */ +uint16_t timeout_init; /*!< Define start timeout */ +uint16_t timeout_max; /*!< Define max timeout time */ uint8_t retrans_max; /*!< Define max packet TX count */ uint8_t delay; /*!< 100ms Ticks for random delay */ } mle_message_timeout_params_t; @@ -189,6 +189,21 @@ typedef uint8_t * (mle_service_security_notify_cb)(int8_t interface_id, mle_secu */ typedef bool (mle_service_message_timeout_cb)(int8_t interface_id, uint16_t msgId, bool usedAllRetries); +/** + * A callback for receive MLE message filtering + * + * This function will be called when MLE message is received. Only for testing purposes. + * + * \param interface_id define interface id for receiver + * \param mle_msg received MLE message + * \param security_headers messages security parameters + * + * \return true continue MLE packet processing + * \return false drop MLE packet + * + */ +typedef bool (mle_service_filter_cb)(int8_t interface_id, mle_message_t *mle_msg, mle_security_header_t *security_headers); + /* * Initialise server instance. * Creates and shares socket for other mle services. @@ -568,7 +583,7 @@ int mle_service_set_msg_panid(uint16_t msgId, uint16_t panid); /** * Set messages timeout parameters. * -* Messages timeout parameters define messages TX count and init timeout and max timeout values is messages delayed. +* Struct timeout_params defines messages retransmission times in seconds, retransmission count and sending delay. * Delayed message will affect random time between 100-900ms * * \param msgId Message Id. @@ -576,6 +591,17 @@ int mle_service_set_msg_panid(uint16_t msgId, uint16_t panid); */ int mle_service_set_msg_timeout_parameters(uint16_t msgId, mle_message_timeout_params_t *timeout_params); +/** +* Set messages timeout parameters. +* +* Struct timeout_params defines messages retransmission times in 100ms, retransmission count and sending delay. +* Delayed message will affect random time between 100-900ms +* +* \param msgId Message Id. +* \param timeout_params messages transmission parameters +*/ +int mle_service_set_msg_timeout_parameters_fast(uint16_t msgId, mle_message_timeout_params_t *timeout_params); + int mle_service_set_msg_rf_channel(uint16_t msgId, uint8_t channel); int mle_service_set_msg_link_layer_security_mode(uint16_t msgId, bool use_key_id_mode_2); @@ -704,4 +730,14 @@ void mle_service_set_fragmented_msg_ll_security(bool value); */ void mle_service_set_accept_invalid_frame_counter(bool value); +#ifdef MLE_TEST +/** + * Set callback for MLE receiving packet filtering. + * + * If this is set, all received MLE messages will be passed to given callback. + */ +void mle_service_receive_filter_cb_set(mle_service_filter_cb *filter_cb); +#else +#define mle_service_receive_filter_cb_set(filter_cb) ((void) 0) +#endif /* MLE_TEST */ #endif /* MLE_SERVICE_API_H_ */ diff --git a/source/Service_Libs/nd_proxy/nd_proxy.c b/source/Service_Libs/nd_proxy/nd_proxy.c index 72a841343fd..51b96b20794 100644 --- a/source/Service_Libs/nd_proxy/nd_proxy.c +++ b/source/Service_Libs/nd_proxy/nd_proxy.c @@ -434,11 +434,11 @@ bool nd_proxy_enabled_for_upstream(int8_t interface_id) return false; } -bool nd_proxy_target_address_validation(int8_t upstream_id, uint8_t *address, int8_t *downstream_id_ptr) +bool nd_proxy_target_address_validation(int8_t upstream_id, uint8_t *address) { nd_proxy_downstream_list_s *downstream; nd_proxy_connected_list_s *upstream = proxy_upstream_conection_get(upstream_id); - *downstream_id_ptr = -1; + if (!upstream) { return false; } @@ -447,7 +447,6 @@ bool nd_proxy_target_address_validation(int8_t upstream_id, uint8_t *address, in downstream = proxy_cache_downstream_interface_get(downstream_entry->id, &downstream_interface_list); if (downstream) { if (downstream->nd_proxy_validation(downstream_entry->id, address) == 0) { - *downstream_id_ptr = downstream_entry->id; return true; } } diff --git a/source/Service_Libs/nd_proxy/nd_proxy.h b/source/Service_Libs/nd_proxy/nd_proxy.h index 0059d6de958..4ab48e23e5a 100644 --- a/source/Service_Libs/nd_proxy/nd_proxy.h +++ b/source/Service_Libs/nd_proxy/nd_proxy.h @@ -125,7 +125,7 @@ bool nd_proxy_enabled_for_upstream(int8_t interface_id); *\return true Address validated behind downstream_id_ptr interface *\return false Unknown address for this proxy */ -bool nd_proxy_target_address_validation(int8_t upstream_id, uint8_t *address, int8_t *downstream_id_ptr); +bool nd_proxy_target_address_validation(int8_t upstream_id, uint8_t *address); /** * Downstream interface validate prefix route on Link status from connected Upstream interface * @@ -147,9 +147,9 @@ NS_DUMMY_DEFINITIONS_OK #define nd_proxy_upstream_interface_unregister(interface_id) -1 #define nd_proxy_enabled_for_downstream(interface_id) false #define nd_proxy_enabled_for_upstream(interface_id) false -#define nd_proxy_target_address_validation(upstream_id, address, downstream_id_ptr) false +#define nd_proxy_target_address_validation(upstream_id, address) false #define nd_proxy_upstream_route_onlink(downstream_id, address) false -#define nd_proxy_target_address_validation(upstream_id, address, downstream_id_ptr) false + #endif /* HAVE_ND_PROXY */ #endif /* ND_PROXY_H_ */ diff --git a/source/configs/generic.cfg b/source/configs/generic.cfg index 85018d8fe59..ea8216f7b76 100644 --- a/source/configs/generic.cfg +++ b/source/configs/generic.cfg @@ -30,3 +30,4 @@ #define HAVE_DHCPV6_SERVER #define TCP_TEST #define THREAD_THCI_SUPPORT +#define MLE_TEST diff --git a/source/ipv6_stack/ipv6_routing_table.c b/source/ipv6_stack/ipv6_routing_table.c index 4c30a332099..9e36a43a2a2 100644 --- a/source/ipv6_stack/ipv6_routing_table.c +++ b/source/ipv6_stack/ipv6_routing_table.c @@ -73,7 +73,6 @@ static void ipv6_destination_cache_forget_neighbour(const ipv6_neighbour_t *neig static void ipv6_destination_release(ipv6_destination_t *dest); static void ipv6_route_table_remove_router(int8_t interface_id, const uint8_t *addr, ipv6_route_src_t source); static uint16_t total_metric(const ipv6_route_t *route); -static void trace_debug_print(const char *fmt, ...); static uint8_t ipv6_route_table_count_source(int8_t interface_id, ipv6_route_src_t source); static void ipv6_route_table_remove_last_one_from_source(int8_t interface_id, ipv6_route_src_t source); static uint8_t ipv6_route_table_get_max_entries(int8_t interface_id, ipv6_route_src_t source); @@ -758,7 +757,7 @@ void ipv6_neighbour_cache_fast_timer(ipv6_neighbour_cache_t *cache, uint16_t tic ipv6_neighbour_set_state(cache, cur, IP_NEIGHBOUR_UNREACHABLE); } } - /* no break */ + /* fall through */ case IP_NEIGHBOUR_UNREACHABLE: if (cur->retrans_count < 0xFF) { cur->retrans_count++; diff --git a/source/ipv6_stack/ipv6_routing_table.h b/source/ipv6_stack/ipv6_routing_table.h index 86d08569e7a..5d39a1cfa83 100644 --- a/source/ipv6_stack/ipv6_routing_table.h +++ b/source/ipv6_stack/ipv6_routing_table.h @@ -82,6 +82,7 @@ typedef enum ipv6_route_src { ROUTE_THREAD, ROUTE_THREAD_BORDER_ROUTER, ROUTE_THREAD_PROXIED_HOST, + ROUTE_THREAD_BBR, ROUTE_REDIRECT, /* Only occurs in destination cache */ ROUTE_MAX, } ipv6_route_src_t; diff --git a/source/libNET/src/net_test.c b/source/libNET/src/net_test.c index 51c1408a056..668ba809e4b 100644 --- a/source/libNET/src/net_test.c +++ b/source/libNET/src/net_test.c @@ -20,6 +20,7 @@ #include #include "nsdynmemLIB.h" #include "NWK_INTERFACE/Include/protocol.h" +#include "Service_Libs/mle_service/mle_service_api.h" #include "net_test_api.h" #include "Common_Protocols/tcp.h" @@ -76,3 +77,8 @@ int8_t arm_nwk_test_tcp_drop_rx(int state, uint8_t count) void arm_nwk_test_tcp_drop_reset() { tcp_test_drop_reset(); } + +void arm_nwk_test_mle_receive_filter_set(mle_service_filter_cb *response_filter_cb) +{ + mle_service_receive_filter_cb_set(response_filter_cb); +} diff --git a/source/libNET/src/socket_api.c b/source/libNET/src/socket_api.c index f0989a4525f..84d5383ba09 100644 --- a/source/libNET/src/socket_api.c +++ b/source/libNET/src/socket_api.c @@ -656,7 +656,7 @@ int8_t socket_bind(int8_t socket, const ns_address_t *address) return -4; } - if (protcol_interface_address_compare(NULL, address->address) != 0) { + if (protocol_interface_address_compare(address->address) != 0) { return -3; }