diff --git a/nanostack/thread_management_if.h b/nanostack/thread_management_if.h index db5b2e7b264..fe51870f183 100644 --- a/nanostack/thread_management_if.h +++ b/nanostack/thread_management_if.h @@ -399,6 +399,20 @@ int thread_management_device_certificate_set(int8_t interface_id, const unsigned */ int thread_management_network_certificate_set(int8_t interface_id, const unsigned char *network_certificate_ptr, uint16_t network_certificate_len, const unsigned char *priv_key_ptr, uint16_t priv_key_len); +/** + * Set Thread partition weighting. + * + * This function sets weighting value for Thread network partition. Interface will be restarted if interface is active and + * new weighting value is different than previous weighting value. + * + * \param interface_id Network interface ID. + * \param partition_weighting New weighting value for Thread partition + * + * \return 0, OK. + * \return <0 fail. + */ +int thread_management_partition_weighting_set(int8_t interface_id, uint8_t partition_weighting); + #ifdef __cplusplus } #endif diff --git a/source/6LoWPAN/Thread/thread_bootstrap.c b/source/6LoWPAN/Thread/thread_bootstrap.c index 4cc9f2d7c94..6a33cc73cac 100644 --- a/source/6LoWPAN/Thread/thread_bootstrap.c +++ b/source/6LoWPAN/Thread/thread_bootstrap.c @@ -448,8 +448,10 @@ static int thread_router_check_previous_partition_info(protocol_interface_info_e //check for parameters return -1; } - if ((leaderData->partitionId == cur->thread_info->previous_partition_info.partitionId) && (routeTlv->dataPtr[0] == cur->thread_info->previous_partition_info.idSequence)) { - //drop the advertisement + if ((leaderData->partitionId == cur->thread_info->previous_partition_info.partitionId) && + (leaderData->weighting == cur->thread_info->previous_partition_info.weighting) && + (routeTlv->dataPtr[0] == cur->thread_info->previous_partition_info.idSequence)) { + //drop the advertisement from previuos partition return 1; } else { @@ -499,6 +501,7 @@ int thread_bootstrap_partition_process(protocol_interface_info_entry_t *cur, uin /*Rule 2: When comparing two singleton or two non-singleton Thread Network Partitions, the one with the higher 8-bit weight value has higher priority. */ if (heard_partition_leader_data->weighting > current_leader_data->weighting) { + tr_debug("Heard a greater weighting"); return 2; } @@ -526,7 +529,8 @@ int thread_leader_data_validation(protocol_interface_info_entry_t *cur, thread_l if (!thread_info(cur)->thread_leader_data) { return -1; } - if (thread_info(cur)->thread_leader_data->partitionId != leaderData->partitionId) { + if ((thread_info(cur)->thread_leader_data->partitionId != leaderData->partitionId) || + (thread_info(cur)->thread_leader_data->weighting != leaderData->weighting)) { uint8_t routers_in_route_tlv = thread_get_router_count_from_route_tlv(routeTlv); //partition checks return thread_bootstrap_partition_process(cur,routers_in_route_tlv,leaderData, routeTlv); @@ -535,10 +539,10 @@ int thread_leader_data_validation(protocol_interface_info_entry_t *cur, thread_l //Should check is there new version numbers if (common_serial_number_greater_8(leaderData->dataVersion, thread_info(cur)->thread_leader_data->dataVersion) || common_serial_number_greater_8(leaderData->stableDataVersion, thread_info(cur)->thread_leader_data->stableDataVersion)) { - // Version number increased + // Version number increased by some-one else -> there is leader in the network if (thread_info(cur)->leader_private_data) { - tr_error("SEq synch error"); - // MUST restart partition + tr_error("Another leader detected -> bootstrap"); + thread_bootstrap_reset_restart(cur->id); return -1; } tr_debug("NEW Network Data available"); @@ -1344,6 +1348,7 @@ static int thread_bootstrap_attach_start(int8_t interface_id, thread_bootsrap_st tr_debug("Thread ReAttach"); //save the current partition id and sequence number before trying reattach cur->thread_info->previous_partition_info.partitionId = cur->thread_info->thread_leader_data->partitionId; + cur->thread_info->previous_partition_info.weighting = cur->thread_info->thread_leader_data->weighting; cur->thread_info->previous_partition_info.idSequence = cur->thread_info->routing.router_id_sequence; cur->thread_info->routerShortAddress = mac_helper_mac16_address_get(cur); if(cur->thread_info->thread_attached_state != THREAD_STATE_REATTACH_RETRY){ diff --git a/source/6LoWPAN/Thread/thread_common.h b/source/6LoWPAN/Thread/thread_common.h index 86cdc1a6ebe..3da5ff7aeba 100644 --- a/source/6LoWPAN/Thread/thread_common.h +++ b/source/6LoWPAN/Thread/thread_common.h @@ -253,6 +253,7 @@ struct thread_extension_credentials; typedef struct thread_previous_partition_info_s { uint32_t partitionId; //partition ID of the previous partition uint8_t idSequence; //idSequence last heard from the previous partition + uint8_t weighting; //weighting last heard from the previous partition } thread_previous_partition_t; @@ -294,6 +295,7 @@ typedef struct thread_info_s { uint8_t version; uint8_t testMaxActiveRouterIdLimit; //Default for this is 32 uint8_t maxChildCount; //Default for this is 24 + uint8_t partition_weighting; bool rfc6775: 1; bool requestFullNetworkData: 1; bool leaderCab: 1; diff --git a/source/6LoWPAN/Thread/thread_host_bootstrap.c b/source/6LoWPAN/Thread/thread_host_bootstrap.c index 0a2d03d4e5c..122839848eb 100644 --- a/source/6LoWPAN/Thread/thread_host_bootstrap.c +++ b/source/6LoWPAN/Thread/thread_host_bootstrap.c @@ -532,7 +532,9 @@ void thread_mle_parent_discover_receive_cb(int8_t interface_id, mle_message_t *m if (thread_info(cur)->thread_attached_state == THREAD_STATE_REATTACH || thread_info(cur)->thread_attached_state == THREAD_STATE_REATTACH_RETRY) { tr_debug("Reattach"); if (thread_info(cur)->thread_leader_data) { - if (thread_info(cur)->thread_leader_data->partitionId != leaderData.partitionId) { //accept only same ID at reattach phase + if ((thread_info(cur)->thread_leader_data->partitionId != leaderData.partitionId) || + (thread_info(cur)->thread_leader_data->weighting != leaderData.weighting)) { + //accept only same ID at reattach phase return; } //Compare ID - when downgrading, accept all @@ -549,7 +551,9 @@ void thread_mle_parent_discover_receive_cb(int8_t interface_id, mle_message_t *m thread_info(cur)->thread_attached_state == THREAD_STATE_CONNECTED || thread_info(cur)->thread_attached_state == THREAD_STATE_CONNECTED_ROUTER) { if (thread_info(cur)->thread_leader_data) { - if (thread_info(cur)->thread_leader_data->partitionId == leaderData.partitionId) { //accept only different ID at anyattach phase + if ((thread_info(cur)->thread_leader_data->partitionId == leaderData.partitionId) && + (thread_info(cur)->thread_leader_data->weighting == leaderData.weighting)) { + //accept only different ID at anyattach phase tr_debug("Drop old partition"); return; } @@ -584,6 +588,10 @@ void thread_mle_parent_discover_receive_cb(int8_t interface_id, mle_message_t *m } } + if (leaderData.weighting < thread_info(cur)->partition_weighting) { + tr_debug("Drop parent due weighting %d<%d", leaderData.weighting, thread_info(cur)->partition_weighting); + return; + } if (accept_response) { if (thread_info(cur)->thread_attach_scanned_parent == NULL) { @@ -596,12 +604,16 @@ void thread_mle_parent_discover_receive_cb(int8_t interface_id, mle_message_t *m tr_debug("Partition %"PRIu32, leaderData.partitionId); } else { uint32_t currentPartitionId = thread_info(cur)->thread_attach_scanned_parent->leader_data.partitionId; - tr_debug("Current %"PRIu32" RX %"PRIu32, currentPartitionId, leaderData.partitionId); + uint8_t currentWeighting = thread_info(cur)->thread_attach_scanned_parent->leader_data.weighting; + tr_debug("Current partition %"PRIu32" old:%"PRIu32" weighting %"PRIu8" old:%"PRIu8, + currentPartitionId, leaderData.partitionId, currentWeighting, leaderData.weighting); - if (leaderData.partitionId != currentPartitionId) { + if ((leaderData.partitionId != currentPartitionId) || + (leaderData.weighting != currentWeighting)) { int retVal = thread_bootstrap_partition_process(cur, connectivityTlv.activeRouters, &leaderData,NULL); - if (retVal > 0) + if (retVal > 0) { scan_result = thread_info(cur)->thread_attach_scanned_parent; + } } else if (leaderData.partitionId == currentPartitionId) { thread_link_quality_e currentLqi; diff --git a/source/6LoWPAN/Thread/thread_leader_service.c b/source/6LoWPAN/Thread/thread_leader_service.c index 3b50953e3a6..ad905d7f2ad 100644 --- a/source/6LoWPAN/Thread/thread_leader_service.c +++ b/source/6LoWPAN/Thread/thread_leader_service.c @@ -1274,14 +1274,16 @@ static int thread_leader_service_leader_init(protocol_interface_info_entry_t *cu return thread_leader_service_leader_start(cur); } -static void thread_leader_service_leader_data_initialize(thread_leader_data_t *leader_data, uint8_t routerId) +static void thread_leader_service_leader_data_initialize(protocol_interface_info_entry_t *cur, uint8_t routerId) { - if (leader_data) { + thread_leader_data_t *leader_data = cur->thread_info->thread_leader_data; + + if (cur->thread_info->thread_leader_data) { leader_data->partitionId = randLIB_get_32bit(); //Generate Random Instance leader_data->leaderRouterId = routerId; //Set leader data to zero by Default leader_data->dataVersion = randLIB_get_8bit(); leader_data->stableDataVersion = randLIB_get_8bit(); - leader_data->weighting = THREAD_DEFAULT_WEIGHTING; + leader_data->weighting = cur->thread_info->partition_weighting; } } @@ -1303,7 +1305,7 @@ static void thread_leader_service_interface_setup_activate(protocol_interface_in routerId = thread_router_id_from_addr(cur->thread_info->routerShortAddress); - thread_leader_service_leader_data_initialize(cur->thread_info->thread_leader_data, routerId); + thread_leader_service_leader_data_initialize(cur, routerId); // Test code if(cur->thread_info->testRandomPartitionId != 0){ cur->thread_info->thread_leader_data->partitionId = cur->thread_info->testRandomPartitionId; @@ -1810,5 +1812,4 @@ void thread_leader_service_router_state_changed(thread_info_t *thread_info, uint } } - #endif // HAVE_THREAD_LEADER_SERVICE */ diff --git a/source/6LoWPAN/Thread/thread_management_if.c b/source/6LoWPAN/Thread/thread_management_if.c index 6b094a6677f..d7631a4bf9b 100644 --- a/source/6LoWPAN/Thread/thread_management_if.c +++ b/source/6LoWPAN/Thread/thread_management_if.c @@ -47,6 +47,7 @@ #include "6LoWPAN/Thread/thread_routing.h" #include "6LoWPAN/Thread/thread_network_data_lib.h" #include "6LoWPAN/Thread/thread_network_data_storage.h" +#include "6LoWPAN/Thread/thread_leader_service.h" #include "6LoWPAN/Thread/thread_nd.h" #include "thread_diagnostic.h" #include "6LoWPAN/Thread/thread_dhcpv6_client.h" @@ -915,6 +916,9 @@ int thread_management_node_init( /* Thread will manage the address query timing, and report negatives. Set this high so as not to interfere. */ cur->ipv6_neighbour_cache.retrans_timer = 10000; + // Set default partition weighting + cur->thread_info->partition_weighting = THREAD_DEFAULT_WEIGHTING; + /* IP forwarding is off by default */ cur->ip_forwarding = false; @@ -1390,3 +1394,31 @@ int thread_management_network_certificate_set(int8_t interface_id, const unsigne #endif } +int thread_management_partition_weighting_set(int8_t interface_id, uint8_t partition_weighting) +{ + (void) interface_id; + (void) partition_weighting; +#ifdef HAVE_THREAD + protocol_interface_info_entry_t *cur; + + cur = protocol_stack_interface_info_get_by_id(interface_id); + if (!cur || !cur->thread_info) { + tr_debug("Invalid interface id"); + return -1; + } + + if (cur->thread_info->partition_weighting == partition_weighting) { + return 0; + } + + cur->thread_info->partition_weighting = partition_weighting; + if (cur->lowpan_info & INTERFACE_NWK_ACTIVE) { + // bootstrap active and weighting has changed + thread_bootstrap_reset_restart(interface_id); + } + + return 0; +#else + return -1; +#endif +} diff --git a/source/6LoWPAN/Thread/thread_mle_message_handler.c b/source/6LoWPAN/Thread/thread_mle_message_handler.c index a8783cfba8c..e38cef4312c 100644 --- a/source/6LoWPAN/Thread/thread_mle_message_handler.c +++ b/source/6LoWPAN/Thread/thread_mle_message_handler.c @@ -323,8 +323,9 @@ static void thread_parse_advertisement(protocol_interface_info_entry_t *cur, mle //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) { - //parent changed partition - reset own routing information + 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->thread_info); } //check if network data needs to be requested @@ -333,7 +334,6 @@ static void thread_parse_advertisement(protocol_interface_info_entry_t *cur, mle thread_bootstrap_connection_error(cur->id, CON_PARENT_CONNECT_DOWN, NULL); return; } - } } @@ -345,7 +345,8 @@ static void thread_parse_advertisement(protocol_interface_info_entry_t *cur, mle 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) { + if ((thread_info(cur)->thread_leader_data->partitionId == leaderData.partitionId) && + (thread_info(cur)->thread_leader_data->weighting == leaderData.weighting)) { // Create link to new neighbor no other processing allowed thread_link_request_start(cur, mle_msg->packet_src_address); return;