/* * Copyright (c) 2014-2018, Arm Limited and affiliates. * SPDX-License-Identifier: BSD-3-Clause * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holder nor the * names of its contributors may be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include "nsconfig.h" #include #include "ns_types.h" #include "mlme.h" #include "NWK_INTERFACE/Include/protocol.h" #include "thread_management_if.h" #include #include "eventOS_event.h" #include #include #include #include "ns_trace.h" #include "Core/include/ns_buffer.h" #include "common_functions.h" #include "6LoWPAN/Thread/thread_config.h" #include "6LoWPAN/Thread/thread_common.h" #include "6LoWPAN/Thread/thread_bootstrap.h" #include "6LoWPAN/Thread/thread_border_router_api_internal.h" #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 "DHCPv6_client/dhcpv6_client_api.h" #include "6LoWPAN/Thread/thread_discovery.h" #include "6LoWPAN/Thread/thread_network_synch.h" #include "6LoWPAN/Thread/thread_management_internal.h" #include "6LoWPAN/Thread/thread_management_server.h" #include "6LoWPAN/Thread/thread_joiner_application.h" #include "6LoWPAN/Thread/thread_management_client.h" #include "6LoWPAN/Thread/thread_nvm_store.h" #include "Service_Libs/mle_service/mle_service_security.h" #include "6LoWPAN/Thread/thread_tmfcop_lib.h" #include "6LoWPAN/Thread/thread_constants.h" #include "6LoWPAN/Thread/thread_extension_bootstrap.h" #include "6LoWPAN/Thread/thread_extension.h" #include "6LoWPAN/Thread/thread_bbr_api_internal.h" #include "6LoWPAN/Bootstraps/protocol_6lowpan.h" #include "RPL/rpl_control.h" // insanity - bootstraps shouldn't be doing each others' clean-up #include "MLE/mle.h" #include "MLE/mle_tlv.h" #include "thread_meshcop_lib.h" #include "thread_commissioning_if.h" #include "shalib.h" #include "Common_Protocols/icmpv6.h" #include "DHCPv6_Server/DHCPv6_server_service.h" #include "6LoWPAN/Thread/thread_dhcpv6_server.h" #include "Service_Libs/mle_service/mle_service_api.h" #include "Service_Libs/blacklist/blacklist.h" #include "6LoWPAN/MAC/mac_helper.h" #include "6LoWPAN/MAC/mac_pairwise_key.h" #include "6LoWPAN/MAC/mpx_api.h" #include "6LoWPAN/lowpan_adaptation_interface.h" #include "Service_Libs/mac_neighbor_table/mac_neighbor_table.h" #include "mac_common_defines.h" #include "mlme.h" #include "mac_api.h" #ifdef HAVE_THREAD #define TRACE_GROUP "thrm" static const uint8_t thread_discovery_key[16] = {0x78, 0x58, 0x16, 0x86, 0xfd, 0xb4, 0x58, 0x0f, 0xb0, 0x92, 0x54, 0x6a, 0xec, 0xbd, 0x15, 0x66}; static const uint8_t thread_discovery_extented_address[8] = {0x35, 0x06, 0xfe, 0xb8, 0x23, 0xd4, 0x87, 0x12}; uint32_t thread_delay_timer_default = THREAD_DELAY_TIMER_DEFAULT_SECONDS; uint32_t thread_router_selection_jitter = THREAD_ROUTER_SELECTION_JITTER; uint16_t thread_joiner_port = THREAD_DEFAULT_JOINER_PORT; /* * Prototypes */ static void thread_discover_key_descriptor_set(struct mac_api_s *api, const uint8_t *key, uint8_t id, uint32_t key32_bit_src, uint8_t attribute_index) { mlme_set_t set_req; mlme_key_id_lookup_descriptor_t lookup_description; mlme_key_descriptor_entry_t key_description; mlme_key_device_descriptor_t dev_descriptor; if (key) { memset(lookup_description.LookupData, 0, 9); common_write_32_bit(key32_bit_src, lookup_description.LookupData); lookup_description.LookupData[4] = id; lookup_description.LookupDataSize = 0; memset(&key_description, 0, sizeof(mlme_key_descriptor_entry_t)); memcpy(key_description.Key, key, 16); key_description.KeyIdLookupList = &lookup_description; key_description.KeyIdLookupListEntries = 1; dev_descriptor.Blacklisted = false; dev_descriptor.DeviceDescriptorHandle = attribute_index; dev_descriptor.UniqueDevice = true; key_description.KeyDeviceList = &dev_descriptor; key_description.KeyDeviceListEntries = 1; } else { memset(&key_description, 0, sizeof(mlme_key_descriptor_entry_t)); } set_req.attr = macKeyTable; set_req.attr_index = 3; //Allwayd firth key set_req.value_pointer = &key_description; set_req.value_size = sizeof(mlme_key_descriptor_entry_t); api->mlme_req(api, MLME_SET, &set_req); } static void thread_discover_device_descriptor_set(struct mac_api_s *api, const uint8_t *device_extended_address, uint8_t attribute_index) { if (!api) { return; } mlme_device_descriptor_t device_desc; mlme_set_t set_req; device_desc.FrameCounter = 0; device_desc.Exempt = false; device_desc.ShortAddress = 0xffff; memcpy(device_desc.ExtAddress, device_extended_address, 8); device_desc.PANId = 0xffff; set_req.attr = macDeviceTable; set_req.attr_index = attribute_index; set_req.value_pointer = (void *)&device_desc; set_req.value_size = sizeof(mlme_device_descriptor_t); tr_debug("Register Discovery device descriptor"); api->mlme_req(api, MLME_SET, &set_req); } static void thread_discover_security_material_update(protocol_interface_info_entry_t *cur, const mlme_security_t *security_params) { if (!security_params || !cur) { return; } if (security_params->SecurityLevel != SEC_ENC_MIC32 || security_params->KeyIdMode != MAC_KEY_ID_MODE_SRC4_IDX || security_params->KeyIndex != THREAD_DISCOVERY_SECURITY_KEY_INDEX) { return; } mac_description_storage_size_t buffer; if (common_read_32_bit(security_params->Keysource) != THREAD_DISCOVERY_SECURITY_KEY_SOURCE) { return; } if (!cur->mac_api || !cur->mac_api->mac_storage_sizes_get || cur->mac_api->mac_storage_sizes_get(cur->mac_api, &buffer) != 0) { return; } thread_discover_device_descriptor_set(cur->mac_api, thread_discovery_extented_address, buffer.device_decription_table_size - 1); } static void thread_security_trig_pending_key(protocol_interface_info_entry_t *cur) { if (cur->mac_parameters->mac_next_key_index) { //Call MAC Key Update uint8_t key_id = cur->mac_parameters->mac_next_key_index; mac_helper_security_key_swap_next_to_default(cur); if (mle_service_security_key_trig(cur->id, key_id)) { thread_security_update_from_mac(cur); } } } static void thread_mac_security_key_update_cb(protocol_interface_info_entry_t *cur, const mlme_security_t *security_params) { if (!cur->thread_info || !cur->mac_parameters) { return; } if (cur->mac_parameters->mac_next_key_index && (security_params->KeyIndex == cur->mac_parameters->mac_next_key_index)) { if (cur->thread_info->masterSecretMaterial.keySwitchGuardTimer == 0) { tr_debug("Trig Next Key"); thread_security_trig_pending_key(cur); } } else { thread_discover_security_material_update(cur, security_params); } } int8_t thread_node_bootstrap_init(int8_t interface_id, net_6lowpan_mode_e bootstrap_mode) { protocol_interface_info_entry_t *cur; uint8_t table_size = 4; cur = protocol_stack_interface_info_get_by_id(interface_id); if (!cur) { return -1; } //Read MAC device table sizes 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; } cur->configure_flags &= ~INTERFACE_BOOTSTRAP_DEFINED; mac_pairwise_key_interface_unregister(cur->id); if (buffer.key_description_table_size < 4) { tr_error("MAC key_description_table_size too short %d<4", buffer.key_description_table_size); return -1; } switch (bootstrap_mode) { case NET_6LOWPAN_HOST: case NET_6LOWPAN_SLEEPY_HOST: protocol_6lowpan_host_init(cur, bootstrap_mode == NET_6LOWPAN_SLEEPY_HOST); break; case NET_6LOWPAN_ROUTER: protocol_6lowpan_router_init(cur); table_size = buffer.key_description_table_size; break; default: return -3; } if (mac_pairwise_key_interface_register(cur->id, table_size, 4) < 0) { tr_error("MAC pairwise key in registration failed"); return -1; } if (blacklist_init() != 0) { tr_debug("6LoWPAN MLE blacklist init failed."); return -1; } blacklist_params_set( THREAD_BLACKLIST_ENTRY_LIFETIME, THREAD_BLACKLIST_TIMER_MAX_TIMEOUT, THREAD_BLACKLIST_TIMER_TIMEOUT, THREAD_BLACKLIST_ENTRY_MAX_NBR, THREAD_BLACKLIST_PURGE_NBR, THREAD_BLACKLIST_PURGE_TIMER_TIMEOUT); if (thread_info_allocate_and_init(cur) < 0) { mac_pairwise_key_interface_unregister(cur->id); return -3; } if (thread_discovery_init(cur->id, cur, thread_info(cur)->version, bootstrap_mode == NET_6LOWPAN_ROUTER) != 0) { tr_error("Discovery init fail"); mac_pairwise_key_interface_unregister(cur->id); return -3; } cur->configure_flags |= INTERFACE_BOOTSTRAP_DEFINED; cur->lowpan_info |= INTERFACE_NWK_BOOTSRAP_MLE; rpl_control_remove_domain_from_interface(cur); //SET MAC key id mode 2 key and device thread_discover_key_descriptor_set(cur->mac_api, thread_discovery_key, THREAD_DISCOVERY_SECURITY_KEY_INDEX, THREAD_DISCOVERY_SECURITY_KEY_SOURCE, buffer.device_decription_table_size - 1); thread_discover_device_descriptor_set(cur->mac_api, thread_discovery_extented_address, buffer.device_decription_table_size - 1); cur->mac_security_key_usage_update_cb = thread_mac_security_key_update_cb; return 0; } void arm_thread_private_ula_prefix_set(protocol_interface_info_entry_t *cur, const uint8_t *ula_prefix) { //Define Local Thread memcpy(cur->thread_info->threadPrivatePrefixInfo.ulaPrefix, ula_prefix, 8); cur->thread_info->threadPrivatePrefixInfo.ulaValid = true; } /** * Calculate New Key Material by given security key material and sequency number * * \param key Thread Master key pointer * \param key_material_buf Buffer for calculated MAC & MLE key: first 128-bit for MLE and rest 128-bit for MAC * \param threadSequency Key material key index. * */ void thread_key_get(uint8_t *key, uint8_t *key_material_buf, uint32_t key_sequence_counter) { static uint8_t key_seed[6] = {'T', 'h', 'r', 'e', 'a', 'd'}; static uint8_t temp32_buf[4]; common_write_32_bit(key_sequence_counter, temp32_buf); SHALIB_init_HMAC(key, 16); SHALIB_push_data_HMAC(temp32_buf, 4); SHALIB_push_data_HMAC(key_seed, 6); SHALIB_finish_HMAC(key_material_buf, 8); } /** * Thread key sequence & key synch * */ void thread_management_key_synch_req(int8_t interface_id, uint32_t keySequnce) { protocol_interface_info_entry_t *cur; link_configuration_s *linkConfiguration; linkConfiguration = thread_joiner_application_get_config(interface_id); if (!linkConfiguration) { return; } cur = protocol_stack_interface_info_get_by_id(interface_id); if (!cur || !cur->thread_info) { return; } if (!cur->thread_info->masterSecretMaterial.valid_Info) { return; } //tr_debug("Sync key material by %"PRIu32, keySequnce); if (keySequnce <= linkConfiguration->key_sequence) { // Smaller or equal request ignored //tr_debug("Sync key material no change"); return; } if ((cur->thread_info->masterSecretMaterial.keySwitchGuardTimer > 0)) { // Guard time prevent the change //tr_debug("Sync key material guard blocked"); return; } // Calculate new keys tr_debug("Sync key material by %"PRIu32, keySequnce); thread_management_key_sets_calc(cur, linkConfiguration, keySequnce); thread_key_guard_timer_calculate(cur, linkConfiguration, false); } static void thread_history_key_material_push(thread_info_t *thread_info, uint8_t *mleKeyPtr, uint8_t keyId) { thread_info->masterSecretMaterial.historyKeyValid = true; thread_info->masterSecretMaterial.historyKeyId = keyId; memcpy(thread_info->masterSecretMaterial.historyKey, mleKeyPtr, 16); } void thread_security_update_from_mac(protocol_interface_info_entry_t *cur) { uint8_t *mleKey; uint8_t historyKeyId; link_configuration_s *linkConfiguration; linkConfiguration = thread_joiner_application_get_config(cur->id); if (!linkConfiguration) { return; } mleKey = mle_service_security_next_key_get(cur->id); if (!mleKey) { return; } historyKeyId = mle_service_security_next_key_id_get(cur->id); /* Set old secondary to history */ thread_history_key_material_push(cur->thread_info, mleKey, historyKeyId); linkConfiguration->key_sequence++; mac_helper_link_frame_counter_set(cur->id, 0); thread_security_next_key_generate(cur, linkConfiguration->master_key, linkConfiguration->key_sequence); thread_key_guard_timer_calculate(cur, linkConfiguration, false); } void thread_security_key_generate(protocol_interface_info_entry_t *cur, uint8_t *masterKey, uint32_t keySequence) { uint8_t key_material[32]; uint8_t key_index; //primary key is generated from the current value of sequence counter uint32_t thrKeySequenceCounter = keySequence; /* Produced keys from Thread security material: MAC key | MLE key */ thread_key_get(masterKey, key_material, thrKeySequenceCounter); /* Update keys as primary keys */ key_index = THREAD_KEY_INDEX(thrKeySequenceCounter); tr_debug("Set current key Id: %u", key_index); mac_helper_security_default_key_set(cur, &key_material[16], key_index, MAC_KEY_ID_MODE_IDX); mle_service_security_set_security_key(cur->id, key_material, key_index, true); } void thread_security_prev_key_generate(protocol_interface_info_entry_t *cur, uint8_t *masterKey, uint32_t keySequence) { uint8_t key_material[32]; uint8_t key_index; uint32_t thrKeySequenceCounter; if (keySequence == 0) { // in initial value there is no prev available return; } thrKeySequenceCounter = keySequence - 1; /* Produced keys from Thread security material: MAC key | MLE key */ thread_key_get(masterKey, key_material, thrKeySequenceCounter); /* Update keys as primary keys */ key_index = THREAD_KEY_INDEX(thrKeySequenceCounter); tr_debug("Set previous key Id: %u", key_index); mac_helper_security_prev_key_set(cur, &key_material[16], key_index, MAC_KEY_ID_MODE_IDX); mle_service_security_set_security_key(cur->id, key_material, key_index, false); //copy master secret material to history thread_history_key_material_push(cur->thread_info, key_material, key_index); } void thread_security_next_key_generate(protocol_interface_info_entry_t *cur, uint8_t *masterKey, uint32_t keySequence) { uint8_t key_material[32]; uint8_t key_index; uint32_t thrKeySequenceCounter; /* Will wrap modulo 32 bits */ thrKeySequenceCounter = keySequence + 1; /* Produced keys from Thread security material: MAC key | MLE key */ thread_key_get(masterKey, key_material, thrKeySequenceCounter); /* Update keys as non-primary keys */ key_index = THREAD_KEY_INDEX(thrKeySequenceCounter); tr_debug("Set next key Id: %u", key_index); mac_helper_security_next_key_set(cur, &key_material[16], key_index, MAC_KEY_ID_MODE_IDX); /* Auth counter not relevant for Thread */ mle_service_security_set_security_key(cur->id, key_material, key_index, false); } int thread_management_key_sets_calc(protocol_interface_info_entry_t *cur, link_configuration_s *linkConfiguration, uint32_t thrKeySequenceCounter) { int ret_val = -1; if (thrKeySequenceCounter == linkConfiguration->key_sequence) { /* Same key - do not change */ ret_val = 0; } else if (thrKeySequenceCounter == (linkConfiguration->key_sequence + 1)) { /* Next key - trig pending key */ thread_security_trig_pending_key(cur); ret_val = 0; } else { /* Generate new key set */ //Clean All Keys mac_helper_security_key_clean(cur); // Update key sequence linkConfiguration->key_sequence = thrKeySequenceCounter; // Zero all frame counters. MLE does it automatically mac_helper_link_frame_counter_set(cur->id, 0); // Store all frame counters as zero and update the sequence counter thread_nvm_store_fast_data_write_all(0, 0, thrKeySequenceCounter); thread_security_prev_key_generate(cur, linkConfiguration->master_key, linkConfiguration->key_sequence); thread_security_key_generate(cur, linkConfiguration->master_key, linkConfiguration->key_sequence); thread_security_next_key_generate(cur, linkConfiguration->master_key, linkConfiguration->key_sequence); ret_val = 0; } return ret_val; } int thread_management_get_my_iid16(int8_t interface_id, uint8_t *iidPtr) { protocol_interface_info_entry_t *cur; cur = protocol_stack_interface_info_get_by_id(interface_id); if (!cur) { return -1; } if (!cur->thread_info) { return -1; } if (thread_attach_ready(cur) != 0) { return -1; } if (!cur->thread_info->threadPrivatePrefixInfo.ulaValid) { return -1; } memcpy(iidPtr, ADDR_SHORT_ADR_SUFFIC, 6); common_write_16_bit(mac_helper_mac16_address_get(cur), (iidPtr + 6)); return 0; } int thread_management_get_current_keysequence(int8_t interface_id, uint32_t *sequencePtr) { link_configuration_s *linkConfiguration; linkConfiguration = thread_joiner_application_get_config(interface_id); if (!linkConfiguration) { return -1; } protocol_interface_info_entry_t *cur; cur = protocol_stack_interface_info_get_by_id(interface_id); if (!cur) { return -1; } if (!cur->thread_info) { return -1; } if (!cur->thread_info->masterSecretMaterial.valid_Info) { return -1; } *sequencePtr = linkConfiguration->key_sequence; return 0; } int thread_management_increment_key_sequence_counter(int8_t interface_id) { protocol_interface_info_entry_t *cur; cur = protocol_stack_interface_info_get_by_id(interface_id); if (cur && cur->thread_info) { /* Not sure if this check is needed - not sure exactly what the flag means! */ if ((cur->lowpan_info & INTERFACE_NWK_ACTIVE) == 0) { return -1; } if ((cur->configure_flags & INTERFACE_BOOTSTRAP_DEFINED) == 0) { return -1; } //Trig Pending Key thread_security_trig_pending_key(cur); return 0; } return -1; } int thread_management_get_ml_prefix(int8_t interface_id, uint8_t *prefix_ptr) { // TODO get from static configuration protocol_interface_info_entry_t *cur; cur = protocol_stack_interface_info_get_by_id(interface_id); if (!cur || !prefix_ptr) { return -1; } if (!cur->thread_info) { return -1; } if (thread_attach_ready(cur) != 0) { return -1; } if (!cur->thread_info->threadPrivatePrefixInfo.ulaValid) { return -1; } memcpy(prefix_ptr, cur->thread_info->threadPrivatePrefixInfo.ulaPrefix, 8); return 0; } /* Get my mesh local prefix /112 */ int thread_management_get_ml_prefix_112(int8_t interface_id, uint8_t *prefix_ptr) { protocol_interface_info_entry_t *cur; cur = protocol_stack_interface_info_get_by_id(interface_id); if (!cur || !prefix_ptr) { return -1; } if (!cur->thread_info) { return -1; } if (thread_attach_ready(cur) != 0) { return -1; } if (!cur->thread_info->threadPrivatePrefixInfo.ulaValid) { return -1; } memcpy(prefix_ptr, cur->thread_info->threadPrivatePrefixInfo.ulaPrefix, 8); memcpy(prefix_ptr + 8, ADDR_SHORT_ADR_SUFFIC, 6); return 0; } #endif /** * Public interface functions. */ /** * 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 } int thread_dhcpv6_server_set_lifetime(int8_t interface_id, uint8_t *prefix_ptr, uint32_t valid_lifetime) { #if defined(HAVE_THREAD) && defined(HAVE_DHCPV6_SERVER) if (!prefix_ptr) { return -1; } return DHCPv6_server_service_set_address_validlifetime(interface_id, prefix_ptr, valid_lifetime); #else (void) interface_id; (void) prefix_ptr; (void) valid_lifetime; return -1; #endif } int thread_dhcpv6_server_set_max_client(int8_t interface_id, uint8_t *prefix_ptr, uint32_t max_client_count) { #if defined(HAVE_THREAD) && defined(HAVE_DHCPV6_SERVER) if (!prefix_ptr) { return -1; } return DHCPv6_server_service_set_max_clients_accepts_count(interface_id, prefix_ptr, max_client_count); #else (void) interface_id; (void) prefix_ptr; (void) max_client_count; return -1; #endif } int thread_dhcpv6_server_set_anonymous_addressing(int8_t interface_id, uint8_t *prefix_ptr, bool anonymous) { #if defined(HAVE_THREAD) && defined(HAVE_DHCPV6_SERVER) if (!prefix_ptr) { return -1; } return DHCPv6_server_service_set_address_autonous_flag(interface_id, prefix_ptr, anonymous); #else (void) interface_id; (void) prefix_ptr; (void) anonymous; return -1; #endif } int thread_dhcpv6_server_delete(int8_t interface_id, uint8_t *prefix_ptr) { #if defined(HAVE_THREAD) && defined(HAVE_DHCPV6_SERVER) uint8_t temp[16]; protocol_interface_info_entry_t *cur; thread_prefix_tlv_t prefixTlv; tr_debug("GUA server Delete"); cur = protocol_stack_interface_info_get_by_id(interface_id); if (!cur) { return -1; } if (!cur->thread_info) { return -1; } memcpy(temp, prefix_ptr, 8); memset(temp + 8, 0, 8); prefixTlv.domainId = 0; prefixTlv.Prefix = prefix_ptr; prefixTlv.PrefixLen = 64; //Delete dhcp service DHCPv6_server_service_delete(interface_id, prefix_ptr, false); ipv6_route_delete(temp, 64, cur->id, NULL, ROUTE_THREAD); thread_local_server_list_del_on_mesh_server(&cur->thread_info->localServerDataBase, &prefixTlv); return 0; #else (void) interface_id; (void) prefix_ptr; return -1; #endif } #ifdef HAVE_THREAD static mac_neighbor_table_entry_t *neighbor_data_poll_referesh(protocol_interface_info_entry_t *cur, const uint8_t *address, addrtype_t type) { mac_neighbor_table_entry_t *entry = mac_neighbor_table_address_discover(mac_neighbor_info(cur), address, type); if (!entry || !entry->connected_device) { return NULL; } entry->lifetime = entry->link_lifetime; return entry; } void thread_comm_status_indication_cb(int8_t if_id, const mlme_comm_status_t *status) { protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(if_id); if (!cur) { return; } mac_neighbor_table_entry_t *entry; switch (status->status) { case MLME_SECURITY_FAIL: break; case MLME_COUNTER_ERROR: break; case MLME_DATA_POLL_NOTIFICATION: entry = neighbor_data_poll_referesh(cur, status->SrcAddr, (addrtype_t)status->SrcAddrMode); if (entry) { thread_neighbor_communication_update(cur, entry->index); } break; default: break; } } #endif 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 } 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 } 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 } link_configuration_s *thread_management_configuration_get(int8_t interface_id) { #ifdef HAVE_THREAD return thread_joiner_application_get_config(interface_id); #else (void) interface_id; return NULL; #endif } device_configuration_s *thread_management_device_configuration_get(int8_t interface_id) { #ifdef HAVE_THREAD return thread_joiner_application_get_device_config(interface_id); #else (void) interface_id; return NULL; #endif } int thread_management_link_configuration_store(int8_t interface_id, link_configuration_s *link_config) { #ifdef HAVE_THREAD int ret = thread_joiner_application_link_configuration_store(interface_id, link_config); if (interface_id == -1) { return ret; } if (ret >= 0) { protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(interface_id); if (!link_config || !cur || !cur->thread_info) { return -2; } if ((cur->lowpan_info & INTERFACE_NWK_ACTIVE) != 0) { // take new settings into use after restart thread_bootstrap_reset_restart(interface_id); } } return ret; #else (void) interface_id; (void) link_config; return -1; #endif } int thread_management_link_configuration_add(int8_t interface_id, uint8_t *additional_ptr, uint8_t additional_len) { #ifdef HAVE_THREAD if (interface_id < 0) { return -1; } int ret = thread_joiner_application_update_configuration(interface_id, additional_ptr, additional_len, true); if (ret != 0) { return ret; } protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(interface_id); if (!cur || !cur->thread_info) { return -2; } if ((cur->lowpan_info & INTERFACE_NWK_ACTIVE) != 0) { // take new settings into use after restart thread_bootstrap_reset_restart(interface_id); } return ret; #else (void) interface_id; (void) additional_ptr; (void) additional_len; return -1; #endif } int thread_management_link_configuration_delete(int8_t interface_id) { #ifdef HAVE_THREAD int ret = thread_joiner_application_link_configuration_delete(interface_id); if (interface_id == -1) { return ret; } if (ret >= 0) { protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(interface_id); if (!cur || !cur->thread_info) { return -2; } if ((cur->lowpan_info & INTERFACE_NWK_ACTIVE) != 0) { thread_bootstrap_reset_restart(interface_id); } } return ret; #else (void) interface_id; return -1; #endif } int thread_management_get_leader_address(int8_t interface_id, uint8_t *address_buffer) { #ifdef HAVE_THREAD protocol_interface_info_entry_t *cur; cur = protocol_stack_interface_info_get_by_id(interface_id); if (cur) { if ((cur->thread_info) && (thread_attach_ready(cur) == 0) && (cur->thread_info->threadPrivatePrefixInfo.ulaValid)) { thread_addr_write_mesh_local_16(address_buffer, thread_router_addr_from_id(cur->thread_info->thread_leader_data->leaderRouterId), cur->thread_info); return 0; } } return -1; #else (void) interface_id; (void) address_buffer; return -1; #endif } int thread_management_get_leader_aloc(int8_t interface_id, uint8_t *address_buffer) { #ifdef HAVE_THREAD protocol_interface_info_entry_t *cur; cur = protocol_stack_interface_info_get_by_id(interface_id); if (cur) { if ((cur->thread_info) && (thread_attach_ready(cur) == 0) && (cur->thread_info->threadPrivatePrefixInfo.ulaValid)) { thread_addr_write_mesh_local_16(address_buffer, 0xfc00, cur->thread_info); return 0; } } return -1; #else (void) interface_id; (void) address_buffer; return -1; #endif } int thread_management_get_ml64_address(int8_t interface_id, uint8_t *address_ptr) { #ifdef HAVE_THREAD protocol_interface_info_entry_t *cur; cur = protocol_stack_interface_info_get_by_id(interface_id); if (!cur) { return -1; } if (!address_ptr) { return -1; } if (0 != thread_management_get_ml_prefix(interface_id, address_ptr)) { return -2; } memcpy(&address_ptr[8], cur->iid_slaac, 8); return 0; #else (void) interface_id; (void) address_ptr; return -1; #endif } int thread_management_get_ml16_address(int8_t interface_id, uint8_t *address_ptr) { #ifdef HAVE_THREAD if (!address_ptr) { return -1; } if (0 != thread_management_get_ml_prefix(interface_id, address_ptr)) { return -2; } if (0 != thread_management_get_my_iid16(interface_id, address_ptr + 8)) { return -2; } return 0; #else (void) interface_id; (void) address_ptr; return -1; #endif } int thread_management_get_parent_address(int8_t interface_id, uint8_t *address_ptr) { #ifdef HAVE_THREAD protocol_interface_info_entry_t *cur; cur = protocol_stack_interface_info_get_by_id(interface_id); if (!cur || !cur->thread_info || !address_ptr) { return -1; } memset(address_ptr, 0, 16); if (cur->thread_info->thread_endnode_parent) { memcpy(address_ptr, ADDR_LINK_LOCAL_PREFIX, 8); address_ptr += 8; memcpy(address_ptr, cur->thread_info->thread_endnode_parent->mac64, 8); *address_ptr ^= 2; } return 0; #else (void) interface_id; (void) address_ptr; return -1; #endif } int thread_management_get_commissioner_address(int8_t interface_id, uint8_t *address_ptr, uint16_t *port_ptr) { #ifdef HAVE_THREAD protocol_interface_info_entry_t *cur; cur = protocol_stack_interface_info_get_by_id(interface_id); if (!cur || !cur->thread_info || !address_ptr) { return -1; } if (!cur->thread_info->registered_commissioner.commissioner_valid) { return -2; } memcpy(address_ptr, cur->thread_info->threadPrivatePrefixInfo.ulaPrefix, 8); memcpy(address_ptr + 8, ADDR_SHORT_ADR_SUFFIC, 6); common_write_16_bit(0xfc30 + (cur->thread_info->registered_commissioner.session_id % 8), address_ptr + 14); if (port_ptr) { *port_ptr = THREAD_MANAGEMENT_PORT;// Default commissioner port } return 0; #else (void) interface_id; (void) address_ptr; (void) port_ptr; 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 } 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_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 } 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_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 } 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) { #ifdef HAVE_THREAD protocol_interface_info_entry_t *cur; cur = protocol_stack_interface_info_get_by_id(interface_id); if (!cur) { tr_debug("invalid interface id"); return -1; } if (0 > thread_extension_bootstrap_network_certificate_set(cur, network_certificate_ptr, network_certificate_len)) { return -1; } return thread_extension_bootstrap_network_private_key_set(cur, priv_key_ptr, priv_key_len); #else (void) interface_id; (void) network_certificate_ptr; (void) network_certificate_len; (void) priv_key_ptr; (void) priv_key_len; return -1; #endif } int thread_management_partition_weighting_set(int8_t interface_id, uint8_t 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; } bool trig_network_scan = false; if (cur->thread_info->thread_leader_data) { if (cur->thread_info->thread_leader_data->weighting < partition_weighting) { trig_network_scan = true; } } cur->thread_info->partition_weighting = partition_weighting; if (cur->lowpan_info & INTERFACE_NWK_ACTIVE) { if (trig_network_scan && thread_extension_enabled(cur)) { thread_nvm_store_link_info_clear(); // bootstrap active and weighting has changed thread_bootstrap_reset_restart(interface_id); } } return 0; #else (void) interface_id; (void) partition_weighting; return -1; #endif }