static bool rpl_data_handle_fwd_error(buffer_t *buf, protocol_interface_info_entry_t *cur, uint8_t *opt, const sockaddr_t *ll_src) { if (!ll_src) { tr_warn("Forwarding-Error - dst=%s, neighbour unknown", trace_ipv6(buf->dst_sa.address)); return false; } else { tr_warn("Forwarding-Error - dst=%s, neighbour=%s", trace_ipv6(buf->dst_sa.address), trace_sockaddr(ll_src, true)); } rpl_instance_t *instance = rpl_lookup_instance(cur->rpl_domain, opt[1], rpl_data_get_dodagid(buf)); if (!instance) { return false; } #if 1 return false; #else /* Work needed */ if (rpl_instance_am_root(instance)) { /* We are looking for a target that has us as its transit */ } bool deleted = ipv6_route_delete_by_info_and_ll(buf->dst_sa.address, ROUTE_RPL_DAO, ll_src); deleted |= ipv6_route_delete_by_info_and_ll(buf->dst_sa.address, ROUTE_RPL_DAO_SR, ll_src); opt[0] &=~ RPL_OPT_FWD_ERROR; return true; #endif }
int8_t thread_management_get_request_full_nwk_data(int8_t interface_id, bool *full_nwk_data) { #ifdef HAVE_THREAD const protocol_interface_info_entry_t *cur; if (!full_nwk_data) { tr_warn("Invalid input ptr"); return -3; } cur = protocol_stack_interface_info_get_by_id(interface_id); if (!cur) { tr_warn("Invalid interface id"); return -1; } if (!cur->thread_info) { tr_warn("Thread not active"); return -2; } *full_nwk_data = cur->thread_info->requestFullNetworkData; return 0; #else (void) interface_id; (void) full_nwk_data; return -1; #endif }
int thread_management_max_child_count( int8_t interface_id, uint8_t maxChildCount) { #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; } if (!cur->thread_info) { tr_warn("Not Thread specific interface"); return -1; } mac_description_storage_size_t buffer; if (!cur->mac_api || !cur->mac_api->mac_storage_sizes_get || cur->mac_api->mac_storage_sizes_get(cur->mac_api, &buffer) != 0) { return -1; } if (maxChildCount > buffer.device_decription_table_size) { tr_error("Accept values are between 0-%d for max Child count", buffer.device_decription_table_size); return -1; } cur->thread_info->maxChildCount = maxChildCount; return 0; #else (void) interface_id; (void) maxChildCount; return -1; #endif }
int8_t thread_management_get_link_timeout(int8_t interface_id, uint32_t *link_timeout) { #ifdef HAVE_THREAD const protocol_interface_info_entry_t *cur; if (!link_timeout) { tr_warn("Invalid input ptr"); return -3; } cur = protocol_stack_interface_info_get_by_id(interface_id); if (!cur) { tr_warn("Invalid interface id"); return -1; } const thread_info_t *thread = cur->thread_info; if (!thread) { tr_warn("Thread not active"); return -2; } *link_timeout = thread->host_link_timeout; return 0; #else (void) interface_id; (void) link_timeout; return -1; #endif }
int8_t thread_management_set_link_timeout(int8_t interface_id, uint32_t link_timeout) { #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; } thread_info_t *thread = cur->thread_info; if (!thread) { tr_warn("Thread not active"); return -2; } tr_info("set new link timeout %"PRIu32" , old value %"PRIu32"", link_timeout, thread->host_link_timeout); thread->host_link_timeout = link_timeout; thread_bootstrap_child_update_trig(cur); return 0; #else (void) interface_id; (void) link_timeout; return -1; #endif }
int thread_management_device_type_set(int8_t interface_id, thread_device_type_e device_type) { #ifdef HAVE_THREAD protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(interface_id); if (!cur || !cur->thread_info) { tr_warn("Not Thread specific interface"); return -1; } if (device_type == THREAD_DEVICE_REED) { // Change mode to router cur->bootsrap_mode = ARM_NWK_BOOTSRAP_MODE_6LoWPAN_ROUTER; } else if (device_type == THREAD_DEVICE_FED) { //FED devices makes links and makes address resolutions cur->bootsrap_mode = ARM_NWK_BOOTSRAP_MODE_6LoWPAN_HOST; cur->thread_info->end_device_link_synch = true; } else if (device_type == THREAD_DEVICE_MED) { cur->bootsrap_mode = ARM_NWK_BOOTSRAP_MODE_6LoWPAN_HOST; cur->thread_info->end_device_link_synch = false; } else if (device_type == THREAD_DEVICE_SED) { cur->bootsrap_mode = ARM_NWK_BOOTSRAP_MODE_6LoWPAN_SLEEPY_HOST; cur->thread_info->end_device_link_synch = false; } if (cur->lowpan_info & INTERFACE_NWK_ACTIVE) { // bootstrap active need to restart thread_bootstrap_reset_restart(interface_id); } return 0; #else (void) interface_id; (void) device_type; return -1; #endif }
bool rpl_data_remember_outer(buffer_t *buf) { /* We're stripping the IP header - need the HBH header for future reference */ uint8_t *hbh; rpl_data_locate_info(buf, &hbh, NULL); if (hbh) { uint8_t instance_id = hbh[3]; /* For local instances, also need to extract the DODAG ID from src/dst */ bool local = rpl_instance_id_is_local(instance_id); /* Copy the length byte and the option data (and optionally DODAG ID) */ buf->rpl_option = ns_dyn_mem_temporary_alloc(hbh[1] + 1 + (local ? 16 : 0)); if (buf->rpl_option) { memcpy(buf->rpl_option, hbh + 1, hbh[1] + 1); if (local) { uint8_t *dodagid = instance_id & RPL_INSTANCE_DEST ? buf->dst_sa.address : buf->src_sa.address; memcpy(buf->rpl_option + hbh[1] + 1, dodagid, 16); } } } if ((buf->options.ip_extflags & IPEXT_HBH_RPL) && !buf->rpl_option) { tr_warn("RPL tunnel exit HbH fail"); return false; } return true; }
void pana_event_handler(arm_event_s *event) { switch (event->event_type) { case ARM_PANA_INIT: tr_debug("Pana Tasklet Init"); break; case ARM_PANA_TLS_CB: if (event->data_ptr) { buffer_t *buf = event->data_ptr; sec_suite_t *tls_suite = buf->session_ptr; buf->session_ptr = NULL; tls_suite = sec_suite_verify(tls_suite); if (tls_suite && pana_tls_handler_cb) { buf = pana_tls_handler_cb(buf, tls_suite); } else { tr_warn("Pana/TLS er"); } if (buf) { buffer_free(buf); } } break; default: break; } }
static void thread_nd_coap_notification_callback(int8_t interface_id, const uint8_t ip_addr[16], uint16_t loc_addr, const uint8_t ml_eid[8]) { protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(interface_id); if (!cur) { return; } /* First check to see if we have an existing entry with different RLOC - we need to unicast error * notification to that old entry if so. */ ipv6_neighbour_t *entry = ipv6_neighbour_lookup(&cur->ipv6_neighbour_cache, ip_addr); if (entry && entry->ll_type == ADDR_802_15_4_SHORT) { uint16_t old_entry_rloc = common_read_16_bit(entry->ll_address + 2); if (old_entry_rloc != loc_addr) { uint8_t old_entry_ip[16]; thread_addr_write_mesh_local_16(old_entry_ip, common_read_16_bit(entry->ll_address + 2), cur->thread_info); tr_warn("Proactive address change %s %04x->%04x", trace_ipv6(ip_addr), old_entry_rloc, loc_addr); thread_resolution_client_address_error(interface_id, old_entry_ip, ip_addr, ml_eid); } } /* Now treat as an unsolicited update (by address, because entry may be NULL) */ uint8_t ll_addr[4]; common_write_16_bit(cur->mac_parameters->pan_id, ll_addr + 0); common_write_16_bit(loc_addr, ll_addr + 2); ipv6_neighbour_update_unsolicited(&cur->ipv6_neighbour_cache, ip_addr, ADDR_802_15_4_SHORT, ll_addr); if (nd_proxy_enabled_for_upstream(cur->id)) { ipv6_route_add(ip_addr, 128, cur->id, NULL, ROUTE_THREAD_PROXIED_HOST, 3600, 0); } }
/** * \brief Network state event handler. * \param event show network start response or current network state. * * - ARM_NWK_BOOTSTRAP_READY: Save NVK persistent data to NVM and Net role * - ARM_NWK_NWK_SCAN_FAIL: Link Layer Active Scan Fail, Stack is Already at Idle state * - ARM_NWK_IP_ADDRESS_ALLOCATION_FAIL: No ND Router at current Channel Stack is Already at Idle state * - ARM_NWK_NWK_CONNECTION_DOWN: Connection to Access point is lost wait for Scan Result * - ARM_NWK_NWK_PARENT_POLL_FAIL: Host should run net start without any PAN-id filter and all channels * - ARM_NWK_AUHTENTICATION_FAIL: Pana Authentication fail, Stack is Already at Idle state */ void nd_tasklet_parse_network_event(arm_event_s *event) { arm_nwk_interface_status_type_e status = (arm_nwk_interface_status_type_e) event->event_data; tr_debug("app_parse_network_event() %d", status); switch (status) { case ARM_NWK_BOOTSTRAP_READY: /* Network is ready and node is connected to Access Point */ if (tasklet_data_ptr->tasklet_state != TASKLET_STATE_BOOTSTRAP_READY) { tr_info("6LoWPAN ND bootstrap ready"); tasklet_data_ptr->tasklet_state = TASKLET_STATE_BOOTSTRAP_READY; nd_tasklet_trace_bootstrap_info(); nd_tasklet_network_state_changed(MESH_CONNECTED); } break; case ARM_NWK_NWK_SCAN_FAIL: /* Link Layer Active Scan Fail, Stack is Already at Idle state */ tr_debug("Link Layer Scan Fail: No Beacons"); tasklet_data_ptr->tasklet_state = TASKLET_STATE_BOOTSTRAP_FAILED; nd_tasklet_network_state_changed(MESH_DISCONNECTED); break; case ARM_NWK_IP_ADDRESS_ALLOCATION_FAIL: /* No ND Router at current Channel Stack is Already at Idle state */ tr_debug("ND Scan/ GP REG fail"); tasklet_data_ptr->tasklet_state = TASKLET_STATE_BOOTSTRAP_FAILED; nd_tasklet_network_state_changed(MESH_DISCONNECTED); break; case ARM_NWK_NWK_CONNECTION_DOWN: /* Connection to Access point is lost wait for Scan Result */ tr_debug("ND/RPL scan new network"); tasklet_data_ptr->tasklet_state = TASKLET_STATE_BOOTSTRAP_FAILED; nd_tasklet_network_state_changed(MESH_DISCONNECTED); break; case ARM_NWK_NWK_PARENT_POLL_FAIL: tasklet_data_ptr->tasklet_state = TASKLET_STATE_BOOTSTRAP_FAILED; nd_tasklet_network_state_changed(MESH_DISCONNECTED); break; case ARM_NWK_AUHTENTICATION_FAIL: tr_debug("Network authentication fail"); tasklet_data_ptr->tasklet_state = TASKLET_STATE_BOOTSTRAP_FAILED; nd_tasklet_network_state_changed(MESH_DISCONNECTED); break; default: tr_warn("Unknown event %d", status); break; } if (tasklet_data_ptr->tasklet_state != TASKLET_STATE_BOOTSTRAP_READY && tasklet_data_ptr->network_interface_id != INVALID_INTERFACE_ID) { // Set 5s timer for new network scan eventOS_event_timer_request(TIMER_EVENT_START_BOOTSTRAP, ARM_LIB_SYSTEM_TIMER_EVENT, tasklet_data_ptr->tasklet, 5000); } }
/** * Set DHCPV6 server for Thread GP data purpose * * \param interface_id Network Interface * \param prefix_ptr pointer DHCPv6 Server Given Prefix * * return 0, Set OK * return <0 Set Not OK */ int thread_dhcpv6_server_add(int8_t interface_id, uint8_t *prefix_ptr, uint32_t max_client_cnt, bool stableData) { #if defined(HAVE_THREAD) && defined(HAVE_DHCPV6_SERVER) protocol_interface_info_entry_t *cur; thread_prefix_tlv_t prefixTlv; thread_border_router_tlv_entry_t service; uint8_t temp[16]; uint8_t *ptr = temp; cur = protocol_stack_interface_info_get_by_id(interface_id); if (!cur) { return -1; } if (!cur->thread_info) { return -1; } if (thread_dhcp6_server_init(interface_id, prefix_ptr, cur->mac, THREAD_MIN_PREFIX_LIFETIME) != 0) { tr_warn("SerVER alloc fail"); return -1; } prefixTlv.domainId = 0; prefixTlv.Prefix = prefix_ptr; prefixTlv.PrefixLen = 64; memset(&service, 0, sizeof(thread_border_router_tlv_entry_t)); service.Prf = 1; service.P_dhcp = true; service.P_on_mesh = true; service.stableData = stableData; // SET maximum number of accepted clients DHCPv6_server_service_set_max_clients_accepts_count(interface_id, prefix_ptr, max_client_cnt); tr_debug("GUA server Generate OK"); memcpy(ptr, prefix_ptr, 8); memset(ptr + 8, 0, 8); //Network Data if (thread_local_server_list_add_on_mesh_server(&cur->thread_info->localServerDataBase, &prefixTlv, &service) != 0) { return -1; } return 0; #else (void) interface_id; (void) prefix_ptr; (void) max_client_cnt; (void) stableData; return -1; #endif }
buffer_t *pana_auth_message_handler(buffer_t *buf, pana_header_t *header, sec_suite_t *suite) { if (!buf) { return NULL; } protocol_interface_info_entry_t *cur = buf->interface; if (!cur) { return buffer_free(buf); } uint16_t length = buffer_data_length(buf); uint8_t *ptr = buffer_data_pointer(buf); pana_avp_t avp_temp; if (suite->pana_session.session_ready) { return buffer_free(buf); } if (sec_check_suite_ptrs(suite) == 0) { tr_warn("SEC Lib Fail"); return buffer_free(buf); } avp_temp.code = AVP_NONCE_CODE; if (pana_avp_discover(ptr, length, &avp_temp)) { if (avp_temp.len == 16) { if ((header->flags & PANA_FLAGS_REQUEST) == PANA_FLAGS_RESPONSE) { memcpy(suite->pana_session.pana_heap->client_nonce, avp_temp.avp_ptr, 16); } else { memcpy(suite->pana_session.pana_heap->agent_nonce, avp_temp.avp_ptr, 16); } //tr_debug("Pana:A_NONCE OK"); } else { tr_debug("A_NONCE length fail, Len: %x", avp_temp.len); } } avp_temp.code = AVP_EAP_PAYLOAD_CODE; if (pana_avp_discover(ptr, length, &avp_temp)) { ptr = avp_temp.avp_ptr; if (avp_temp.len > 4) { buf->buf_ptr = 0; buf->buf_end = avp_temp.len; memmove(buf->buf, ptr, avp_temp.len); return buf; } } return buffer_free(buf); }
int8_t thread_management_set_request_full_nwk_data(int8_t interface_id, bool full_nwk_data) { #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; } if (!cur->thread_info) { tr_warn("Thread not active"); return -2; } if (cur->thread_info->requestFullNetworkData != full_nwk_data) { cur->thread_info->requestFullNetworkData = full_nwk_data; thread_bootstrap_child_update_trig(cur); } return 0; #else (void) interface_id; (void) full_nwk_data; return -1; #endif }
int thread_management_device_certificate_set(int8_t interface_id, const unsigned char *device_certificate_ptr, uint16_t device_certificate_len, const unsigned char *priv_key_ptr, uint16_t priv_key_len) { #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; } return thread_extension_bootstrap_device_certificate_set(cur, device_certificate_ptr, device_certificate_len, priv_key_ptr, priv_key_len); #else (void) interface_id; (void) device_certificate_ptr; (void) device_certificate_len; (void) priv_key_ptr; (void) priv_key_len; return -1; #endif }
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; }
buffer_t *nwk_udp_rx_security_check(buffer_t *buf) { protocol_interface_info_entry_t *cur = buf->interface; uint8_t drop_unsecured = 0; // Hack for PANA and MLE. PANA socket is not unsecured, need to allow unsecured link local traffic. // MLE need to allow joiner request, that is not secured. // TODO: Check if there is better fix for these. if (buf->src_sa.port == UDP_PORT_PANA || buf->dst_sa.port == UDP_PORT_PANA) { if ((buf->dst_sa.address[0] != 0xfe) && (buf->options.ll_security_bypass_rx)) { drop_unsecured = 1; } } else if (buf->dst_sa.port == UDP_PORT_MLE) { // OK } else if (buf->options.ll_security_bypass_rx) { if (addr_ipv6_scope(buf->src_sa.address, cur) > IPV6_SCOPE_LINK_LOCAL) { drop_unsecured = 1; } else { if (!buf->socket) { buffer_socket_set(buf, socket_lookup_ipv6(IPV6_NH_UDP, &buf->dst_sa, &buf->src_sa, true)); } if (buf->socket && buf->socket->inet_pcb->link_layer_security == 0) { // non-secure okay if it's for a socket whose security flag is clear. } else { drop_unsecured = 1; } } } if (drop_unsecured) { tr_warn("Drop UDP Unsecured"); buf = buffer_free(buf); } return buf; }
int thread_management_node_init( int8_t interface_id, channel_list_s *channel_list, device_configuration_s *device_configuration, link_configuration_s *static_configuration) { #ifdef HAVE_THREAD protocol_interface_info_entry_t *cur; nwk_scan_params_t *scan_params; if (!device_configuration) { return -1; } cur = protocol_stack_interface_info_get_by_id(interface_id); if (!cur) { tr_warn("Invalid interface id"); return -1; } if (!cur->thread_info) { tr_warn("Not Thread specific interface"); return -1; } if ((cur->lowpan_info & INTERFACE_NWK_ACTIVE) != 0) { return -1; } if (cur->bootsrap_mode == ARM_NWK_BOOTSRAP_MODE_6LoWPAN_BORDER_ROUTER || cur->border_router_setup) { return -1; } if (thread_init(cur) < 0) { thread_nd_service_delete(cur->id); tr_warn("Thread Boostarp Init Fail"); return -1; } if (thread_management_server_init(cur->id) != 0) { tr_warn("Thread management server init fail"); return -1; } if (thread_diagnostic_init(cur->id) != 0) { tr_warn("Thread diagnostic init fail"); return -1; } //Store setup to application Joiner Application if (thread_joiner_application_init(cur->id, device_configuration, static_configuration) != 0) { tr_error("mandatory device configuration missing"); return -2; } // Joiner application copies and massages the device configuration - switch to massaged version device_configuration = thread_joiner_application_get_device_config(cur->id); if (!device_configuration) { return -1; } cur->if_lowpan_security_params->nwk_security_mode = NET_SEC_MODE_NO_LINK_SECURITY; cur->mac_parameters->mac_configured_sec_level = 0; // If no-one has already set a secret key, use the EUI-64 - Thread // wants RFC 7217 IIDs. Also ensure they're on for the Thread interface. // (Note that this will likely enable opaque IIDs on Ethernet too). if (!addr_opaque_iid_key_is_set()) { // Could we include some private key here? arm_nwk_ipv6_opaque_iid_key(device_configuration->eui64, 8); arm_nwk_ipv6_opaque_iid_enable(cur->id, true); } // Copy the channel list memset(&cur->mac_parameters->mac_channel_list, 0, sizeof(channel_list_s)); if (channel_list) { // Application has given limited set of channels cur->mac_parameters->mac_channel_list = *channel_list; } else { cur->mac_parameters->mac_channel_list.channel_page = CHANNEL_PAGE_0; cur->mac_parameters->mac_channel_list.channel_mask[0] = 0x07FFF800; } scan_params = &cur->mac_parameters->nwk_scan_params; memset(&scan_params->stack_chan_list, 0, sizeof(channel_list_s)); if (channel_list) { // Application has given limited set of channels scan_params->stack_chan_list = *channel_list; } else { scan_params->stack_chan_list.channel_page = CHANNEL_PAGE_0; scan_params->stack_chan_list.channel_mask[0] = 0x07FFF800; } scan_params->scan_duration = 5; cur->thread_info->masterSecretMaterial.valid_Info = false; thread_key_guard_timer_calculate(cur, static_configuration, true); cur->thread_info->maxChildCount = THREAD_MAX_CHILD_COUNT; cur->thread_info->rfc6775 = false; cur->thread_info->host_link_timeout = THREAD_END_DEVICE_DEFAULT_TIMEOUT; /* 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; lowpan_adaptation_indirect_queue_params_set(cur, THREAD_INDIRECT_BIG_PACKET_THRESHOLD, THREAD_INDIRECT_BIG_PACKETS_TOTAL, THREAD_INDIRECT_SMALL_PACKETS_PER_CHILD); if (cur->bootsrap_mode == ARM_NWK_BOOTSRAP_MODE_6LoWPAN_SLEEPY_HOST) { cur->thread_info->requestFullNetworkData = false; } else { cur->thread_info->requestFullNetworkData = true; } cur->lowpan_info &= ~INTERFACE_NWK_BOOTSRAP_PANA_AUTHENTICATION; cur->configure_flags |= INTERFACE_SECURITY_DEFINED; cur->comm_status_ind_cb = thread_comm_status_indication_cb; return 0; #else (void) interface_id; (void) channel_list; (void) device_configuration; (void) static_configuration; return -1; #endif }
/* Public functions */ void thread_general_mle_receive_cb(int8_t interface_id, mle_message_t *mle_msg, mle_security_header_t *security_headers) { /* TODO's: * - Any incoming link configuration or advertisement message, or an incoming update sent to a * link-local address, whose IP Hop Limit is not 255, may have been forwarded by a Router * and MUST be discarded. */ protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(interface_id); if (!cur) { return; } /* Check that message is from link-local scope */ if(!addr_is_ipv6_link_local(mle_msg->packet_src_address)) { return; } uint8_t linkMargin = thread_compute_link_margin(mle_msg->dbm); // Always save lowpower queries thread_lowpower_process_request(mle_msg); switch (mle_msg->message_type) { case MLE_COMMAND_ACCEPT: { thread_parse_accept(cur, mle_msg, security_headers, linkMargin); break; } case MLE_COMMAND_METRIC_MANAGEMENT_REQUEST: { thread_lowpower_metrics_management_query_request_process(cur, mle_msg, security_headers, linkMargin); break; } 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); if (entry_temp) { mle_class_remove_entry(cur->id, entry_temp); } break; } case MLE_COMMAND_DATASET_ANNOUNCE: { thread_parse_annoucement(cur, mle_msg); break; } case MLE_COMMAND_ADVERTISEMENT: { thread_parse_advertisement(cur, mle_msg, security_headers, linkMargin); break; } case MLE_COMMAND_DATA_RESPONSE: { thread_parse_data_response(cur, mle_msg, linkMargin); break; } case MLE_COMMAND_CHILD_UPDATE_RESPONSE: { thread_parse_child_update_response(cur, mle_msg, security_headers, linkMargin); break; } case MLE_COMMAND_PARENT_RESPONSE: { tr_debug("MLE parent response received"); thread_mle_parent_discover_receive_cb(interface_id, mle_msg, security_headers); break; } default: if ((thread_am_host(cur) || thread_am_reed(cur)) && mle_msg->message_type == MLE_COMMAND_CHILD_UPDATE_REQUEST){ // Thread host and router in REED mode answer the message same way. Routers only process messages from child thread_host_child_update_request_process(cur, mle_msg, linkMargin); } else if (cur->thread_info->thread_device_mode == THREAD_DEVICE_MODE_ROUTER) { thread_router_bootstrap_mle_receive_cb(interface_id, mle_msg, security_headers); } else { tr_warn("Not supported MLE message for host %d", mle_msg->message_type); } } }
static void thread_host_child_update_request_process(protocol_interface_info_entry_t *cur, mle_message_t *mle_msg, uint8_t linkMargin) { thread_leader_data_t leaderData; mle_tlv_info_t networkDataTlv; mle_tlv_info_t ConfigurationTlv; mle_tlv_info_t challengeTlv; mle_tlv_info_t tlv_req; uint64_t active_timestamp = 0; uint64_t pending_timestamp = 0;// means no pending timestamp mle_neigh_table_entry_t *entry_temp; 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); if (!thread_leader_data_parse(mle_msg->data_ptr, mle_msg->data_length, &leaderData) || !entry_temp || !thread_check_is_this_my_parent(cur, entry_temp)) { // Dropped if no leader data or not from parent tr_warn("invalid message"); return; } mle_tlv_read_tlv(MLE_TYPE_CHALLENGE, mle_msg->data_ptr, mle_msg->data_length, &challengeTlv); mle_tlv_read_tlv(MLE_TYPE_TLV_REQUEST, mle_msg->data_ptr, mle_msg->data_length, &tlv_req); // Check if partition changed if (thread_info(cur)->thread_leader_data->partitionId != leaderData.partitionId) { thread_info(cur)->thread_leader_data->leaderRouterId = leaderData.leaderRouterId; thread_info(cur)->thread_leader_data->partitionId = leaderData.partitionId; thread_old_partition_data_purge(cur); } //Check Network Data TLV if (mle_tlv_read_tlv(MLE_TYPE_NETWORK_DATA, mle_msg->data_ptr, mle_msg->data_length, &networkDataTlv)) { thread_bootstrap_network_data_save(cur, &leaderData, networkDataTlv.dataPtr, networkDataTlv.tlvLen); thread_bootstrap_network_data_update(cur); } if (thread_info(cur)->thread_leader_data->stableDataVersion != leaderData.stableDataVersion || thread_info(cur)->thread_leader_data->dataVersion != leaderData.dataVersion) { // version numbers not in sync need to send data request data_request_needed = true; } // update operational datasets mle_tlv_read_tlv(MLE_TYPE_OPERATIONAL_DATASET, mle_msg->data_ptr, mle_msg->data_length, &ConfigurationTlv); if (mle_tlv_read_64_bit_tlv(MLE_TYPE_ACTIVE_TIMESTAMP, mle_msg->data_ptr, mle_msg->data_length, &active_timestamp)) { thread_active_operational_dataset_process(cur,ConfigurationTlv.dataPtr, ConfigurationTlv.tlvLen, active_timestamp); } mle_tlv_read_tlv(MLE_TYPE_PENDING_OPERATIONAL_DATASET, mle_msg->data_ptr, mle_msg->data_length, &ConfigurationTlv); if (mle_tlv_read_64_bit_tlv(MLE_TYPE_PENDING_TIMESTAMP, mle_msg->data_ptr, mle_msg->data_length, &pending_timestamp)) { thread_pending_operational_dataset_process(cur, pending_timestamp, ConfigurationTlv.dataPtr, ConfigurationTlv.tlvLen); } // Check if operational datasets are in sync if (thread_joiner_application_active_timestamp_get(cur->id) < active_timestamp || thread_joiner_application_pending_config_timestamp_get(cur->id) < pending_timestamp) { tr_debug("Request new network data with configurations active %"PRIX64", %"PRIX64" Pending %"PRIX64", %"PRIX64, active_timestamp, thread_joiner_application_active_timestamp_get(cur->id), pending_timestamp, thread_joiner_application_pending_config_timestamp_get(cur->id)); data_request_needed = true; } thread_host_child_update_response_send(cur, mle_msg->packet_src_address, &challengeTlv, &tlv_req); if (data_request_needed) { thread_network_data_request_send(cur, mle_msg->packet_src_address, true); } }
static void thread_parse_data_response(protocol_interface_info_entry_t *cur, mle_message_t *mle_msg, uint8_t linkMargin) { thread_leader_data_t leaderData; mle_tlv_info_t networkDataTlv; mle_tlv_info_t ConfigurationTlv; uint64_t active_timestamp = 0; uint64_t pending_timestamp = 0;// means no pending timestamp mle_neigh_table_entry_t *entry_temp; bool accept_new_data = false; bool leaderDataReceived; tr_debug("Data Response"); if (thread_leader_data_parse(mle_msg->data_ptr, mle_msg->data_length, &leaderData)) { leaderDataReceived = true; } else { leaderDataReceived = false; } if (!leaderDataReceived) { tr_warn("no leader TLV"); return; } entry_temp = mle_class_get_entry_by_ll64(cur->id, linkMargin, mle_msg->packet_src_address, false); if(cur->thread_info->thread_device_mode == THREAD_DEVICE_MODE_ROUTER || cur->thread_info->thread_device_mode == THREAD_DEVICE_MODE_FULL_END_DEVICE) { if (thread_info(cur)->thread_attached_state == THREAD_STATE_CONNECTED) { // We are attached as child and just learn new data if (!thread_check_is_this_my_parent(cur, entry_temp)) { return; } } else { if (thread_info(cur)->thread_leader_data->partitionId != leaderData.partitionId) { // if receiving data response from different partition it is dropped return; } } } else if (thread_info(cur)->thread_device_mode == THREAD_DEVICE_MODE_END_DEVICE || thread_info(cur)->thread_device_mode == THREAD_DEVICE_MODE_SLEEPY_END_DEVICE) { if (!entry_temp) { tr_debug("Unknown neighbor"); return; } } if (thread_info(cur)->thread_leader_data->partitionId != leaderData.partitionId) { thread_info(cur)->thread_leader_data->leaderRouterId = leaderData.leaderRouterId; thread_info(cur)->thread_leader_data->partitionId = leaderData.partitionId; thread_old_partition_data_purge(cur); accept_new_data = true; } //check response is for link metrics query thread_lowpower_process_response(mle_msg->packet_src_address, cur->id, mle_msg->data_ptr, mle_msg->data_length); if (cur->thread_info->networkDataRequested) { tr_debug("Requested network data received"); cur->thread_info->networkDataRequested = false; accept_new_data = true; } if (1 == thread_leader_data_validation(cur, &leaderData, NULL)) { tr_debug("Network data updated"); accept_new_data = true; } // update operational datasets mle_tlv_read_tlv(MLE_TYPE_OPERATIONAL_DATASET, mle_msg->data_ptr, mle_msg->data_length, &ConfigurationTlv); if (mle_tlv_read_64_bit_tlv(MLE_TYPE_ACTIVE_TIMESTAMP, mle_msg->data_ptr, mle_msg->data_length, &active_timestamp)) { thread_active_operational_dataset_process(cur,ConfigurationTlv.dataPtr, ConfigurationTlv.tlvLen, active_timestamp); } // TODO check if result is true then need to update all configurations mle_tlv_read_tlv(MLE_TYPE_PENDING_OPERATIONAL_DATASET, mle_msg->data_ptr, mle_msg->data_length, &ConfigurationTlv); if (mle_tlv_read_64_bit_tlv(MLE_TYPE_PENDING_TIMESTAMP, mle_msg->data_ptr, mle_msg->data_length, &pending_timestamp)) { thread_pending_operational_dataset_process(cur, pending_timestamp, ConfigurationTlv.dataPtr, ConfigurationTlv.tlvLen); } // Check if we are now in sync // if not matching must send data request again if (thread_joiner_application_active_timestamp_get(cur->id) < active_timestamp || thread_joiner_application_pending_config_timestamp_get(cur->id) < pending_timestamp) { tr_debug("Request new network data with configurations active %"PRIX64", %"PRIX64" Pending %"PRIX64", %"PRIX64, active_timestamp, thread_joiner_application_active_timestamp_get(cur->id), pending_timestamp, thread_joiner_application_pending_config_timestamp_get(cur->id)); thread_network_data_request_send(cur, mle_msg->packet_src_address, true); return; } //Check Network Data TLV if (accept_new_data) { if (mle_tlv_read_tlv(MLE_TYPE_NETWORK_DATA, mle_msg->data_ptr, mle_msg->data_length, &networkDataTlv)) { thread_bootstrap_network_data_save(cur, &leaderData, networkDataTlv.dataPtr, networkDataTlv.tlvLen); thread_bootstrap_network_data_update(cur); } else { tr_debug("SET NWK data Request state"); } } // leader has finished synching network data after reset/restart if (cur->thread_info->leader_synced) { cur->thread_info->leader_synced = false; thread_leader_service_network_data_changed(cur, true, true); } }
/* Input: Final IP packet for transmission on link. * Buffer destination = final destination * Buffer source undefined. * Route next hop address set. * Output: Buffer destination+source = link-layer addresses * Sent to mesh, LowPAN fragmentation or MAC layers */ buffer_t *lowpan_down(buffer_t *buf) { protocol_interface_info_entry_t *cur = buf->interface; buf->options.type = 0; if (!buf->route) { tr_debug("lowpan_down route"); return buffer_free(buf); } const uint8_t *ip_src = buffer_data_pointer(buf) + 8; const uint8_t *next_hop = buf->route->route_info.next_hop_addr; bool link_local = addr_is_ipv6_link_local(next_hop); bool stable_only = false; /* We have IP next hop - figure out the MAC address */ if (addr_is_ipv6_multicast(next_hop)) { buf->dst_sa.addr_type = ADDR_BROADCAST; common_write_16_bit(cur->mac_parameters->pan_id, buf->dst_sa.address); buf->dst_sa.address[2] = 0x80 | (next_hop[14] & 0x1f); buf->dst_sa.address[3] = next_hop[15]; stable_only = true; } else { /* unicast */ ipv6_neighbour_t *n = ipv6_interface_resolve_new(cur, buf); if (!n) { return NULL; } if (thread_info(cur)) { stable_only = thread_stable_context_check(cur, buf); } } if (!buf->link_specific.ieee802_15_4.useDefaultPanId) { /* Override dest PAN ID (from multicast map above, or neighbour cache) */ common_write_16_bit(buf->link_specific.ieee802_15_4.dstPanId, buf->dst_sa.address); } /* Figure out which source MAC address to use. Usually try to match the * source, for best compression, and to ensure if the layer above uses LL64 * (like MLE), it forces us to use our MAC64. */ if (thread_info(cur) && !(link_local && thread_insist_that_mesh_isnt_a_link(cur)) && buf->dst_sa.addr_type == ADDR_802_15_4_SHORT) { /* For Thread, we want to always use short source address for unicast * to non-link-local 16-bit addresses, which is the case where we want * to use mesh headers. */ buf->src_sa.addr_type = ADDR_802_15_4_SHORT; } else if (addr_iid_matches_eui64(ip_src + 8, cur->mac)) { buf->src_sa.addr_type = ADDR_802_15_4_LONG; } else if (cur->mac_parameters->mac_short_address < 0xfffe && addr_iid_matches_lowpan_short(ip_src + 8, cur->mac_parameters->mac_short_address)) { buf->src_sa.addr_type = ADDR_802_15_4_SHORT; } else { /* This lets mac_mlme_write_our_addr choose based on address mode */ buf->src_sa.addr_type = ADDR_NONE; } if (!mac_helper_write_our_addr(cur, &buf->src_sa)) { return buffer_free(buf); } /* Clear Link Layer Re Transmission Counter */ //buf->fhss_channel_retries_left = 1+ cur->mac_parameters->number_of_fhss_channel_retries; if (buf->dst_sa.addr_type != ADDR_802_15_4_LONG && buf->dst_sa.addr_type != ADDR_802_15_4_SHORT && buf->dst_sa.addr_type != ADDR_BROADCAST) { tr_debug("IP:Dest Pro. addr_type: %02x", buf->dst_sa.addr_type); return buffer_free(buf); } uint_fast8_t mesh_size; if (link_local && thread_insist_that_mesh_isnt_a_link(cur)) { mesh_size = 0; } else { /* Allow the link-layer destination addresses passed from upper layers * to be remapped - used to implement Thread anycast. * * Mapping function can change address and type - if it returns false, * packet is dropped. * * Note that this mapping has to be done before IPHC compression, which * is why it moved from mesh.c. */ if (!mesh_address_map(cur, &buf->dst_sa.addr_type, buf->dst_sa.address)) { tr_debug("mesh_address_map fail"); return buffer_free(buf); } /* After mapping, compute final mesh header size (which depends on * the final address). */ mesh_size = mesh_header_size(buf); } if (mesh_size == 0) { if (buf->dst_sa.addr_type == ADDR_BROADCAST) { /* Thread says multicasts other than MLE are sent to our parent, if we're an end device */ if (cur->ip_multicast_as_mac_unicast_to_parent && !buf->options.ll_broadcast_tx) { if (protocol_6lowpan_interface_get_mac_coordinator_address(cur, &buf->dst_sa) < 0) { tr_warn("IP: No parent for multicast as unicast"); return buffer_free(buf); } } else { /* * Not using a mesh header, so have to "purify" RFC 4944 multicast - we * set a 100xxxxxxxxxxxxx RFC 4944 multicast address above, but * IEEE 802.15.4 only supports broadcast in the real MAC header. */ common_write_16_bit(0xFFFF, buf->dst_sa.address + 2); } } } /* RFC 6282+4944 require that we limit compression to the first fragment. * This check is slightly conservative - always allow 4 for first-fragment header */ uint_fast16_t overhead = mac_helper_frame_overhead(cur, buf); uint_fast16_t max_iphc_size = mac_helper_max_payload_size(cur, overhead) - mesh_size - 4; buf = iphc_compress(&cur->lowpan_contexts, buf, max_iphc_size, stable_only); if (!buf) { return NULL; } if (mesh_size != 0) { buf->info = (buffer_info_t)(B_FROM_IPV6_TXRX | B_TO_MESH_ROUTING | B_DIR_DOWN); return buf; } buf->info = (buffer_info_t)(B_FROM_IPV6_TXRX | B_TO_MAC | B_DIR_DOWN); return buf; }