diff --git a/source/6LoWPAN/Thread/thread_bootstrap.c b/source/6LoWPAN/Thread/thread_bootstrap.c index 2e0b643b9d9..991ccdd01d4 100644 --- a/source/6LoWPAN/Thread/thread_bootstrap.c +++ b/source/6LoWPAN/Thread/thread_bootstrap.c @@ -333,11 +333,7 @@ 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) && @@ -351,6 +347,12 @@ int thread_bootstrap_partition_process(protocol_interface_info_entry_t *cur, uin } } + 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 if (heard_partition_routers > 1 && active_routers == 1) { tr_debug("Heard a nonsingleton and i am a singleton"); @@ -1815,7 +1817,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) { @@ -2509,8 +2511,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); } } @@ -2737,7 +2739,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; @@ -2800,14 +2802,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. */ @@ -2820,7 +2822,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_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_extension_bbr.c b/source/6LoWPAN/Thread/thread_extension_bbr.c index a2f402d0784..9e912270299 100644 --- a/source/6LoWPAN/Thread/thread_extension_bbr.c +++ b/source/6LoWPAN/Thread/thread_extension_bbr.c @@ -229,7 +229,7 @@ static void thread_border_router_bb_ans_send(thread_pbbr_t *this, uint8_t *desti return; } -static void thread_border_router_bb_qry_send(thread_pbbr_t *this, uint8_t *target_eid_ptr, uint16_t *rloc_ptr) +static void thread_border_router_bb_qry_send(thread_pbbr_t *this, const uint8_t *target_eid_ptr, uint16_t *rloc_ptr) { uint8_t *ptr; uint8_t payload[22]; @@ -446,7 +446,7 @@ static int thread_pbbr_bb_qry_cb(int8_t service_id, uint8_t source_address[16], if (!link_configuration_ptr || !cur) { return -1; } - if (addr_is_assigned_to_interface(cur,source_address)) { + if (addr_interface_address_compare(cur, source_address) == 0) { // Received from own address no need to process return 0; } @@ -473,15 +473,57 @@ static int thread_pbbr_bb_qry_cb(int8_t service_id, uint8_t source_address[16], return 0; } + +static int thread_pbbr_dua_duplicate_address_detection(int8_t service_id, uint8_t *addr_data_ptr, uint8_t *ml_eid_ptr) +{ + thread_pbbr_t *this = thread_border_router_find_by_service(service_id); + + if (!this) { + return -1; + } + + protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(this->interface_id); + duplicate_dua_tr_t *tr_ptr = thread_border_router_dup_tr_find(this->interface_id,addr_data_ptr); + + if (!tr_ptr) { + return -1; + } + + ipv6_route_t *route = ipv6_route_choose_next_hop(addr_data_ptr, this->interface_id, NULL); + if (!route || route->prefix_len != 128 || !route->on_link || route->info.source != ROUTE_THREAD_PROXIED_HOST) { + // Not found + tr_debug("route not found"); + return 0; + } + + // We have pending request and received answer + if (memcmp(ml_eid_ptr,tr_ptr->ml_eid, 8) != 0){ + // Different ml_eid but same address means duplicate address detected + thread_resolution_client_address_error(this->interface_id, tr_ptr->source_address, tr_ptr->target_eid, tr_ptr->ml_eid); + ipv6_neighbour_t *neighbour_entry; + neighbour_entry = ipv6_neighbour_lookup(&cur->ipv6_neighbour_cache, tr_ptr->target_eid); + if (neighbour_entry) { + tr_debug("Remove from neigh Cache: %s", tr_ipv6(tr_ptr->target_eid)); + ipv6_neighbour_entry_remove(&cur->ipv6_neighbour_cache, neighbour_entry); + } + ipv6_route_delete(route->prefix, route->prefix_len, this->interface_id, route->info.next_hop_addr, ROUTE_THREAD_PROXIED_HOST); + } + return 0; + + // TODO check last transaction time for migrated device if this answer is newer delete entry + // ipv6_route_delete(route->prefix, route->prefix_len, this->interface_id, route->info.next_hop_addr, ROUTE_THREAD_PROXIED_HOST); +} + static int thread_pbbr_bb_ans_cb(int8_t service_id, uint8_t source_address[16], uint16_t source_port, sn_coap_hdr_s *request_ptr) { (void)service_id; (void)source_port; (void)request_ptr; - uint16_t addr_len, ml_eid_len, last_transaction_time_len, network_name_len; + uint16_t addr_len, ml_eid_len, last_transaction_time_len; uint8_t *addr_data_ptr; + uint16_t rloc16; + uint8_t destination_address[16] = {0}; uint8_t *ml_eid_ptr; - uint8_t *network_name_ptr; uint32_t last_transaction_time; tr_info("Thread BBR BB_ANS.ntf receive"); thread_pbbr_t *this = thread_border_router_find_by_service(service_id); @@ -495,7 +537,7 @@ static int thread_pbbr_bb_ans_cb(int8_t service_id, uint8_t source_address[16], if (!link_configuration_ptr || !cur) { return -1; } - if (addr_is_assigned_to_interface(cur,source_address)) { + if (addr_interface_address_compare(cur, source_address) == 0) { // Received from own address no need to process return 0; } @@ -503,46 +545,43 @@ static int thread_pbbr_bb_ans_cb(int8_t service_id, uint8_t source_address[16], addr_len = thread_meshcop_tlv_find(request_ptr->payload_ptr, request_ptr->payload_len, TMFCOP_TLV_TARGET_EID, &addr_data_ptr); ml_eid_len = thread_meshcop_tlv_find(request_ptr->payload_ptr, request_ptr->payload_len, TMFCOP_TLV_ML_EID, &ml_eid_ptr); last_transaction_time_len = thread_meshcop_tlv_data_get_uint32(request_ptr->payload_ptr, request_ptr->payload_len, TMFCOP_TLV_LAST_TRANSACTION_TIME, &last_transaction_time); - network_name_len = thread_meshcop_tlv_find(request_ptr->payload_ptr, request_ptr->payload_len, TMFCOP_TLV_LAST_TRANSACTION_TIME, &network_name_ptr); if ( addr_len < 16|| ml_eid_len < 8 || last_transaction_time_len < 4 ) { tr_err("Invalid message"); return 0; } - // Network name must match - if(stringlen((char *)link_configuration_ptr->name,16) != network_name_len || memcmp(link_configuration_ptr->name,network_name_ptr,network_name_len) != 0) { + if ((thread_pbbr_dua_duplicate_address_detection(service_id, addr_data_ptr, ml_eid_ptr) == 0)) { return 0; } - ipv6_route_t *route = ipv6_route_choose_next_hop(addr_data_ptr, this->interface_id, NULL); - if (!route || route->prefix_len != 128 || !route->on_link || route->info.source != ROUTE_THREAD_PROXIED_HOST) { - // Not found + // If rloc16 is present then a/an is sent to the thread device with the rloc + if (thread_tmfcop_tlv_data_get_uint16(request_ptr->payload_ptr, request_ptr->payload_len, TMFCOP_TLV_RLOC16, &rloc16) != 2) { return 0; } - duplicate_dua_tr_t *tr_ptr = thread_border_router_dup_tr_find(this->interface_id,addr_data_ptr); - if (tr_ptr) { - // We have pending request and received answer - if (memcmp(ml_eid_ptr,tr_ptr->ml_eid, 8) != 0){ - // Different ml_eid but same address means duplicate address detected - thread_resolution_client_address_error(this->interface_id, tr_ptr->source_address, tr_ptr->target_eid, tr_ptr->ml_eid); - ipv6_neighbour_t *neighbour_entry; - neighbour_entry = ipv6_neighbour_lookup(&cur->ipv6_neighbour_cache, tr_ptr->target_eid); - if (neighbour_entry) { - tr_debug("Remove from neigh Cache: %s", tr_ipv6(tr_ptr->target_eid)); - ipv6_neighbour_entry_remove(&cur->ipv6_neighbour_cache, neighbour_entry); - } - ipv6_route_delete(route->prefix, route->prefix_len, this->interface_id, route->info.next_hop_addr, ROUTE_THREAD_PROXIED_HOST); - } else { - // Roaming case lets inform other pbbr that we have newest - thread_border_router_bb_ans_send(this, source_address, tr_ptr->target_eid, tr_ptr->ml_eid, 0, link_configuration_ptr->name, NULL); - } - } else { - ipv6_route_delete(route->prefix, route->prefix_len, this->interface_id, route->info.next_hop_addr, ROUTE_THREAD_PROXIED_HOST); - } + // form the destination address to which the a/an is sent + thread_addr_write_mesh_local_16(destination_address, rloc16, cur->thread_info); - // If delayed DUA registration entry is present send duplicate error code to DUA.response + // Address query pending send address notification, include tlvs: target eid, rloc16 tlv of bbr, mleid, and last transaction time + uint8_t payload[16 + 2 + 8 + 4]; // Target eid + Rloc16 + MLEID + transaction time + uint8_t *ptr; + ptr = payload; + ptr = thread_tmfcop_tlv_data_write(ptr, TMFCOP_TLV_TARGET_EID, 16, addr_data_ptr); + ptr = thread_tmfcop_tlv_data_write_uint16(ptr, TMFCOP_TLV_RLOC16, cur->thread_info->routerShortAddress); + ptr = thread_tmfcop_tlv_data_write(ptr, TMFCOP_TLV_ML_EID, 8, ml_eid_ptr); + ptr = thread_tmfcop_tlv_data_write_uint32(ptr, TMFCOP_TLV_LAST_TRANSACTION_TIME, last_transaction_time); + + // XXX "Accepted" response? + + /* We don't require a response, so we don't specify a callback. Library + * should retry itself until it gets an ACK. + */ + coap_service_request_send(this->coap_service_id, COAP_REQUEST_OPTIONS_ADDRESS_SHORT, + destination_address, THREAD_MANAGEMENT_PORT, + COAP_MSG_TYPE_CONFIRMABLE, COAP_MSG_CODE_REQUEST_POST, + THREAD_URI_ADDRESS_NOTIFICATION, COAP_CT_OCTET_STREAM, + payload, ptr - payload, NULL); return 0; } static int thread_extension_bbr_bmlr_req_send(int8_t service_id, const uint8_t br_addr[16], const uint8_t *address_ptr, uint8_t addr_len, uint32_t timeout) @@ -737,13 +776,13 @@ static int thread_extension_bbr_dua_cb(int8_t service_id, uint8_t source_address tr_debug("DUA.req addr:%s ml_eid:%s", trace_array(addr_data_ptr, addr_len), trace_array(ml_eid_ptr, ml_eid_len)); - entry_keep_alive = true; + entry_keep_alive = false; // TODO add ml_eid to structure saved in info pointer to detect duplicates if (thread_bbr_nd_entry_find(this->interface_id, addr_data_ptr) == 0) { - entry_keep_alive = false; + entry_keep_alive = true; } - if (thread_bbr_nd_entry_add(this->interface_id, addr_data_ptr, 0xFFFFFFFF, NULL, ml_eid_ptr) == -1) { + if (thread_bbr_nd_entry_add(this->interface_id, addr_data_ptr, 0xFFFFFFFF, NULL, ml_eid_ptr) != 0) { bbr_status = THREAD_BBR_STATUS_RESOURCE_SHORTAGE; goto send_response; } @@ -891,14 +930,17 @@ static int thread_extension_bbr_pbbr_start(thread_pbbr_t *this) //If started only refresh network data return 0; } + // Register to backbone CoAP service + this->br_bb_service_id = coap_service_initialize(this->backbone_interface_id, this->pbbr_port, COAP_SERVICE_OPTIONS_SELECT_SOCKET_IF, NULL, NULL); + if(this->br_bb_service_id < 0) { + tr_error("pBBR Commercial service start failed"); + thread_extension_bbr_pbbr_stop(this); + return -1; + } // Allow only filtered addresses to be forwarded multicast_fwd_full_for_scope(this->interface_id, 0x10); multicast_fwd_full_for_scope(this->backbone_interface_id, 0); - //Register baseline 1.2 features - coap_service_register_uri(this->coap_service_id, THREAD_URI_BBR_MCAST_LISTENER_REPORT, COAP_SERVICE_ACCESS_POST_ALLOWED, thread_extension_bbr_mlr_cb); - this->pbbr_started = true; - // Generate pbbr multicast address memset(this->pbbr_multicast_address, 0, 16); this->pbbr_multicast_address[0] = 0xff; @@ -906,31 +948,21 @@ static int thread_extension_bbr_pbbr_start(thread_pbbr_t *this) this->pbbr_multicast_address[2] = 0x00; //Reserved this->pbbr_multicast_address[3] = 0x40; //Prefix length 64 bits this->pbbr_multicast_address[15] = 2; - if (0 != thread_extension_network_prefix_get(this->interface_id, NULL, &this->pbbr_multicast_address[4], NULL)) { - //No domain prefix in settings DUA handling not used - tr_info("pBBR service started (Home network)"); - return 0; - } + tr_info("pBBR service started (Commercial network)"); - // Start commercial mode features + // Register Primary BBR backbone multicast address multicast_add_address(this->pbbr_multicast_address, false); - // Register to backbone CoAP service - this->br_bb_service_id = coap_service_initialize(this->backbone_interface_id, this->pbbr_port, COAP_SERVICE_OPTIONS_SELECT_SOCKET_IF, NULL, NULL); - if(this->br_bb_service_id < 0) { - tr_error("pBBR Commercial service start failed"); - thread_extension_bbr_pbbr_stop(this); - return -1; - } - // Register Primary BBR backbone multicast address + this->pbbr_started = true; - // Register commercial features + // Register Backbone commercial features coap_service_register_uri(this->br_bb_service_id, THREAD_URI_BBR_BB_QRY_NTF, COAP_SERVICE_ACCESS_POST_ALLOWED, thread_pbbr_bb_qry_cb); coap_service_register_uri(this->br_bb_service_id, THREAD_URI_BBR_BB_ANS_NTF, COAP_SERVICE_ACCESS_POST_ALLOWED, thread_pbbr_bb_ans_cb); coap_service_register_uri(this->br_bb_service_id, THREAD_URI_TRI_TX_NTF, COAP_SERVICE_ACCESS_POST_ALLOWED, thread_pbbr_relay_from_tri_cb); coap_service_register_uri(this->br_bb_service_id, THREAD_URI_BBR_BMLR_NTF, COAP_SERVICE_ACCESS_POST_ALLOWED, thread_extension_bbr_bmlr_cb); // Register Mesh address registration URI + coap_service_register_uri(this->coap_service_id, THREAD_URI_BBR_MCAST_LISTENER_REPORT, COAP_SERVICE_ACCESS_POST_ALLOWED, thread_extension_bbr_mlr_cb); coap_service_register_uri(this->coap_service_id, THREAD_URI_BBR_DOMAIN_ADDRESS_REGISTRATION, COAP_SERVICE_ACCESS_POST_ALLOWED, thread_extension_bbr_dua_cb); // Register Mesh side relay URI coap_service_register_uri(this->coap_service_id, THREAD_URI_BBR_TRI_RX_NTF, COAP_SERVICE_ACCESS_POST_ALLOWED, thread_pbbr_relay_to_tri_cb); @@ -942,7 +974,7 @@ static int thread_extension_bbr_pbbr_start(thread_pbbr_t *this) thread_extension_bootstrap_network_certificate_enable(cur, this->coap_nmkp_virtual_service_id); coap_service_register_uri(this->coap_nmkp_virtual_service_id, THREAD_URI_BBR_NMKP_REQ, COAP_SERVICE_ACCESS_POST_ALLOWED, thread_pbbr_nmkp_req_recv_cb); coap_service_virtual_socket_set_cb(this->coap_nmkp_virtual_service_id, thread_pbbr_nmkp_virtual_socket_send_cb); - // Set the partition weight to be 72 + return 0; } @@ -986,6 +1018,8 @@ int8_t thread_extension_bbr_init(int8_t interface_id, int8_t backbone_interface_ } ns_list_add_to_start(&pbbr_instance_list, this); + // Set the partition weight to be 72 + thread_management_partition_weighting_set(this->interface_id, 72); return 0; } @@ -1002,7 +1036,7 @@ void thread_extension_bbr_delete(int8_t interface_id) ns_dyn_mem_free(this); } -bool thread_extension_bbr_nd_query_process(protocol_interface_info_entry_t *cur, const uint8_t *target_addr) +bool thread_extension_bbr_nd_query_process(protocol_interface_info_entry_t *cur, const uint8_t *target_addr, uint16_t rloc) { uint8_t domain_prefix[8]; if (thread_version < THREAD_VERSION_1_2) { @@ -1015,12 +1049,17 @@ bool thread_extension_bbr_nd_query_process(protocol_interface_info_entry_t *cur, if (!this->pbbr_started) { return false; } - // if we have DUA addressing enabled - if ( thread_extension_network_prefix_get(cur->id, NULL, domain_prefix, NULL) == 0 && - bitsequal(domain_prefix,target_addr,64) ) { - return true; + // if we do not have DUA addressing enabled + if ( !thread_extension_network_prefix_get(cur->id, NULL, domain_prefix, NULL) == 0 || + !bitsequal(domain_prefix,target_addr,64) ) { + return false; + } - return false; + + // SEND BB_QRY + thread_border_router_bb_qry_send(this,target_addr,&rloc); + return true; + } @@ -1066,12 +1105,6 @@ void thread_extension_bbr_seconds_timer(int8_t interface_id, uint32_t seconds) thread_extension_bbr_pbbr_start(this); } else { - if(this->br_bb_service_id < 0 && - thread_extension_network_prefix_get(cur->id, NULL, NULL, NULL) == 0) { - // Settings changed to commercial - thread_extension_bbr_pbbr_stop(this); - thread_extension_bbr_pbbr_start(this); - } if (thread_extension_bbr_downgrade_to_secondary(cur)) { tr_info("pbbr downgraded"); thread_extension_bbr_pbbr_stop(this); diff --git a/source/6LoWPAN/Thread/thread_extension_bbr.h b/source/6LoWPAN/Thread/thread_extension_bbr.h index 879e7a569c1..114d9fad9a4 100644 --- a/source/6LoWPAN/Thread/thread_extension_bbr.h +++ b/source/6LoWPAN/Thread/thread_extension_bbr.h @@ -41,7 +41,7 @@ extern "C" { #ifdef HAVE_THREAD_V2 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); +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); @@ -51,7 +51,7 @@ int thread_extension_bbr_address_set(int8_t interface_id, const uint8_t *addr_pt #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) diff --git a/source/6LoWPAN/Thread/thread_host_bootstrap.c b/source/6LoWPAN/Thread/thread_host_bootstrap.c index 3da9c1c5ce3..69cf292b6b7 100644 --- a/source/6LoWPAN/Thread/thread_host_bootstrap.c +++ b/source/6LoWPAN/Thread/thread_host_bootstrap.c @@ -1043,6 +1043,7 @@ 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; diff --git a/source/6LoWPAN/Thread/thread_mle_message_handler.c b/source/6LoWPAN/Thread/thread_mle_message_handler.c index d865db3bb8d..e785c88cdd1 100644 --- a/source/6LoWPAN/Thread/thread_mle_message_handler.c +++ b/source/6LoWPAN/Thread/thread_mle_message_handler.c @@ -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"); @@ -251,25 +249,6 @@ static bool thread_heard_lower_partition(protocol_interface_info_entry_t *cur, t return false; } -static bool thread_reed_partitions_merge(protocol_interface_info_entry_t *cur, uint16_t shortAddress, thread_leader_data_t heard_partition_leader_data) -{ - if (thread_is_router_addr(shortAddress)) { - return false; - } - // 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; - } - // can merge to a higher weighting/partition id - thread_bootstrap_connection_error(cur->id, CON_ERROR_PARTITION_MERGE, NULL); - return true; -} - 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) { //Read Leader Data and verify connectivity @@ -323,14 +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; mle_neigh_table_entry_t *entry_temp; uint16_t shortAddress; - bool my_parent; 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) || @@ -348,7 +344,9 @@ 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, 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) && adv_from_my_partition) { @@ -361,22 +359,10 @@ static void thread_parse_advertisement(protocol_interface_info_entry_t *cur, mle entry_temp = NULL; } - // Check parent status - if (!thread_attach_active_router(cur)) { - //processing for non routers - if (my_parent) { - //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; - } + /* Check parent status */ + if (!thread_attach_active_router(cur) && my_parent) { + if (!thread_parse_advertisement_from_parent(cur, &leaderData, shortAddress)) { + return; } } @@ -385,30 +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; - } - // REED advertisement to lower partition to help merge faster - if (thread_heard_lower_partition(cur,leaderData)) { - thread_router_bootstrap_reed_merge_advertisement(cur); - } + /* ROUTER */ } else { - //Router if (!thread_router_leader_data_process(cur, mle_msg->packet_src_address, &leaderData, &routeTlv, entry_temp) ) { return; } 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_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/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/ns_socket.c b/source/Core/ns_socket.c index a11db6c91e2..1adf83d2d3c 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/NWK_INTERFACE/Include/protocol.h b/source/NWK_INTERFACE/Include/protocol.h index fe06de7b6e4..4e415438753 100644 --- a/source/NWK_INTERFACE/Include/protocol.h +++ b/source/NWK_INTERFACE/Include/protocol.h @@ -513,5 +513,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 e659621090f..5c622360052 100644 --- a/source/NWK_INTERFACE/protocol_core.c +++ b/source/NWK_INTERFACE/protocol_core.c @@ -1107,10 +1107,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 df94fc6931c..eb6769d2cf1 100644 --- a/source/RPL/rpl_control.c +++ b/source/RPL/rpl_control.c @@ -910,7 +910,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 b743fec2e9e..1c7c03d7d09 100644 --- a/source/RPL/rpl_downward.c +++ b/source/RPL/rpl_downward.c @@ -1115,7 +1115,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 { @@ -1178,7 +1178,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/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; } diff --git a/test/nanostack/unittest/stub/protocol_core_stub.c b/test/nanostack/unittest/stub/protocol_core_stub.c index af42ce01f4a..ba2c1e9a927 100644 --- a/test/nanostack/unittest/stub/protocol_core_stub.c +++ b/test/nanostack/unittest/stub/protocol_core_stub.c @@ -234,7 +234,7 @@ 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) +int8_t protocol_interface_address_compare(const uint8_t *addr) { return protocol_core_stub.int8_value; }