mbed-os/features/nanostack/sal-stack-nanostack/source/6LoWPAN/Thread/thread_management_if.c

1433 lines
44 KiB
C

/*
* 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 <string.h>
#include "ns_types.h"
#include "mlme.h"
#include "NWK_INTERFACE/Include/protocol.h"
#include "thread_management_if.h"
#include <nsdynmemLIB.h>
#include "eventOS_event.h"
#include <ns_list.h>
#include <net_thread_test.h>
#include <net_ipv6_api.h>
#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
}