static void thread_parse_child_update_response(protocol_interface_info_entry_t *cur, mle_message_t *mle_msg, mle_security_header_t *security_headers, uint8_t linkMargin) { uint8_t mode; uint32_t timeout; mle_neigh_table_entry_t *entry_temp; thread_leader_data_t leaderData = {0}; uint8_t status; bool leader_data_received; tr_debug("Child Update Response"); 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); 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)) { tr_debug("parent has connection error"); thread_bootstrap_connection_error(cur->id, CON_PARENT_CONNECT_DOWN, NULL); return; } if (!entry_temp) { tr_debug("Not Neighbor"); mle_tlv_info_t challengeTlv; mle_tlv_read_tlv(MLE_TYPE_CHALLENGE, mle_msg->data_ptr, mle_msg->data_length, &challengeTlv); thread_host_bootstrap_child_update_negative_response(cur, mle_msg->packet_src_address, &challengeTlv); return; } if ((security_headers->KeyIdMode == MAC_KEY_ID_MODE_SRC4_IDX) && (thread_instance_id_matches(cur, &leaderData))) { thread_management_key_synch_req(cur->id, common_read_32_bit(security_headers->Keysource)); } else { tr_debug("Key ID Mode 2 not used; dropped."); return; } if (!mle_tlv_read_8_bit_tlv(MLE_TYPE_MODE, mle_msg->data_ptr, mle_msg->data_length, &mode)) { tr_debug("No Mode"); return; } 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); //Save possible new Leader Data if (leader_data_received) { thread_save_leader_data(cur, &leaderData); } mac_data_poll_protocol_poll_mode_decrement(cur); }
void nwk_parent_poll_fail_cb(int8_t id) { protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(id); if (!cur) { tr_error("Data Poll Fail Event: No interface"); return; } if (thread_info(cur)) { //Initialize Bootsrap thread_bootstrap_connection_error(cur->id, CON_ERROR_POLL, NULL); } else { nwk_bootsrap_state_update(ARM_NWK_NWK_PARENT_POLL_FAIL, cur); } }
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; } 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; } // 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_leader_data_process(protocol_interface_info_entry_t *cur, uint8_t *src_address, thread_leader_data_t *leaderData, mle_tlv_info_t *routeTlv, mle_neigh_table_entry_t *neighbor) { int leaderDataUpdate = thread_leader_data_validation(cur, leaderData, routeTlv); if (leaderDataUpdate == 1) { if (neighbor && neighbor->handshakeReady == 1) { // 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"); thread_bootstrap_connection_error(cur->id, CON_ERROR_PARTITION_MERGE, NULL); return false; } else if (leaderDataUpdate < 0) { tr_warn("Leader data failure"); 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; // Check device mode & bootstrap state if ((thread_info(cur)->thread_device_mode == THREAD_DEVICE_MODE_SLEEPY_END_DEVICE) || (cur->nwk_bootstrap_state != ER_BOOTSRAP_DONE && cur->nwk_bootstrap_state != ER_MLE_ATTACH_READY)) { return; } tr_debug("Received Advertisement"); // Validate and parse TLV's if (!thread_router_advertiment_tlv_analyze(mle_msg->data_ptr, mle_msg->data_length, &leaderData, &shortAddress, &routeTlv)) { return; } // Get MLE entry entry_temp = mle_class_get_entry_by_ll64(cur->id, linkMargin, mle_msg->packet_src_address, false); if ((security_headers->KeyIdMode == MAC_KEY_ID_MODE_SRC4_IDX) && (thread_instance_id_matches(cur, &leaderData))) { 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; } } } // Update MLE entry thread_update_mle_entry(cur, mle_msg, security_headers, entry_temp, shortAddress); // Process advertisement if (thread_info(cur)->thread_device_mode != THREAD_DEVICE_MODE_END_DEVICE) { 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)) { // 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 return; } } // process REED advertisement from higher partition if (thread_reed_partitions_merge(cur, shortAddress, leaderData)) { return; } } else { //Router if (!thread_router_leader_data_process(cur, mle_msg->packet_src_address, &leaderData, &routeTlv, entry_temp) ) { return; } thread_router_bootstrap_advertiment_analyze(cur, mle_msg->packet_src_address, entry_temp, shortAddress); } } // Process route TLV if ((entry_temp && routeTlv.dataPtr && routeTlv.tlvLen) && (thread_info(cur)->thread_leader_data->partitionId == leaderData.partitionId)){ tr_debug("Update Route TLV %x", entry_temp->short_adr); thread_router_bootstrap_route_tlv_push(cur, routeTlv.dataPtr, routeTlv.tlvLen , linkMargin, entry_temp); } }