mbed-os/source/6LoWPAN/Thread/thread_network_synch.c

289 lines
11 KiB
C

/*
* Copyright (c) 2015-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.
*/
/*
* \file thread_network_synch.c
*
*/
#include "nsconfig.h"
#ifdef HAVE_THREAD
#include <string.h>
#include <ns_types.h>
#include <nsdynmemLIB.h>
#include "eventOS_event.h"
#include "eventOS_event_timer.h"
#include "randLIB.h"
#include "common_functions.h"
#include "NWK_INTERFACE/Include/protocol.h"
#include "net_thread_test.h"
#include "libDHCPv6/libDHCPv6.h"
#include "libDHCPv6/libDHCPv6_server.h"
#include "ns_trace.h"
#include "6LoWPAN/Bootstraps/protocol_6lowpan.h"
#include "6LoWPAN/Thread/thread_common.h"
#include "6LoWPAN/Thread/thread_routing.h"
#include "6LoWPAN/Thread/thread_nd.h"
#include "6LoWPAN/Thread/thread_bootstrap.h"
#include "6LoWPAN/Thread/thread_host_bootstrap.h"
#include "6LoWPAN/Thread/thread_router_bootstrap.h"
#include "6LoWPAN/Thread/thread_management_internal.h"
#include "6LoWPAN/Thread/thread_joiner_application.h"
#include "6LoWPAN/Thread/thread_management_client.h"
#include "6LoWPAN/Thread/thread_network_synch.h"
#include "6LoWPAN/Thread/thread_neighbor_class.h"
#include "thread_management_if.h"
#include "thread_config.h"
#include "Common_Protocols/ipv6.h"
#include "Common_Protocols/icmpv6.h"
#include "Common_Protocols/icmpv6_radv.h"
#include "MLE/mle.h"
#include "Service_Libs/mac_neighbor_table/mac_neighbor_table.h"
#include "6LoWPAN/MAC/mac_helper.h"
#define TRACE_GROUP "tsyn"
typedef struct thread_sync_child_info {
uint32_t mle_frame_counter;
uint32_t mac_frame_counter;
uint8_t long_addr[8];
uint16_t short_addr;
uint8_t mode;
} thread_sync_child_info_t;
typedef struct thread_network_dynamic_data_store {
thread_leader_info_t *leader_private_data;
thread_parent_info_t *thread_endnode_parent;
thread_attach_state_e thread_attached_state;
uint16_t shortAddress;
thread_sync_child_info_t children[THREAD_MAX_CHILD_COUNT];
} thread_network_dynamic_data_store_t;
typedef struct thread_network_dynamic_data_entry {
int8_t interfaceId;
ns_list_link_t link; /*!< List link entry */
thread_network_dynamic_data_store_t networ_dynamic_data_parameters;
} thread_network_dynamic_data_entry_t;
static thread_sync_child_info_t *thread_dynamic_storage_free_child_find(int8_t interface_id);
static thread_sync_child_info_t *thread_dynamic_storage_child_info_find(int8_t interface_id, mac_neighbor_table_entry_t *child);
static NS_LIST_DEFINE(thread_network_dynamic_data_info, thread_network_dynamic_data_entry_t, link);
thread_network_dynamic_data_entry_t *thread_network_synch_create(int8_t interfaceId)
{
thread_network_dynamic_data_entry_t *newEntry = ns_dyn_mem_alloc(sizeof(thread_network_dynamic_data_entry_t));
if (newEntry) {
tr_debug("Allocate New Store");
newEntry->interfaceId = interfaceId;
newEntry->networ_dynamic_data_parameters.thread_attached_state = THREAD_STATE_NETWORK_DISCOVER;
newEntry->networ_dynamic_data_parameters.shortAddress = 0xfffe;
newEntry->networ_dynamic_data_parameters.leader_private_data = NULL;
newEntry->networ_dynamic_data_parameters.thread_endnode_parent = NULL;
for (int i = 0; i < THREAD_MAX_CHILD_COUNT; ++i) {
memset(&newEntry->networ_dynamic_data_parameters.children[i], 0, sizeof(thread_sync_child_info_t));
}
ns_list_add_to_end(&thread_network_dynamic_data_info, newEntry);
}
return newEntry;
}
thread_network_dynamic_data_entry_t *thread_network_synch_find(int8_t interfaceId)
{
//Check current List
ns_list_foreach(thread_network_dynamic_data_entry_t, cur, &thread_network_dynamic_data_info) {
if (interfaceId == cur->interfaceId) {
return cur;
}
}
return NULL;
}
int thread_network_synch_delete(int8_t interfaceId)
{
thread_network_dynamic_data_entry_t *newEntry = thread_network_synch_find(interfaceId);
if (newEntry) {
//Free
if (newEntry->networ_dynamic_data_parameters.leader_private_data) {
ns_dyn_mem_free(newEntry->networ_dynamic_data_parameters.leader_private_data);
}
if (newEntry->networ_dynamic_data_parameters.thread_endnode_parent) {
ns_dyn_mem_free(newEntry->networ_dynamic_data_parameters.thread_endnode_parent);
}
newEntry->networ_dynamic_data_parameters.thread_attached_state = THREAD_STATE_NETWORK_DISCOVER;
newEntry->networ_dynamic_data_parameters.shortAddress = 0xfffe;
newEntry->networ_dynamic_data_parameters.leader_private_data = NULL;
newEntry->networ_dynamic_data_parameters.thread_endnode_parent = NULL;
return 0;
}
return -1;
}
//Call This when clean synched networkdata
int thread_network_synch_data_free(int8_t interface_id)
{
return thread_network_synch_delete(interface_id);
}
/*
* Dynamic network data storage.
*/
void thread_dynamic_storage_child_info_store(protocol_interface_info_entry_t *cur_interface, mac_neighbor_table_entry_t *child)
{
thread_network_dynamic_data_entry_t *storeEntry = thread_network_synch_find(cur_interface->id);
if (!storeEntry) {
storeEntry = thread_network_synch_create(cur_interface->id);
}
if (!storeEntry) {
return;
}
uint32_t mle_frame_counter = mle_service_neighbor_frame_counter_get(cur_interface->id, child->index);
thread_sync_child_info_t *child_info = thread_dynamic_storage_child_info_find(cur_interface->id, child);
if (!child_info) {
child_info = thread_dynamic_storage_free_child_find(cur_interface->id);
}
if (child_info) {
uint8_t mode = mle_mode_write_from_mac_entry(child);
mode |= thread_neighbor_class_mode_write_from_entry(&cur_interface->thread_info->neighbor_class, child->index);
child_info->mode = mode;
child_info->short_addr = child->mac16;
child_info->mle_frame_counter = mle_frame_counter;
child_info->mac_frame_counter = 0;
memcpy(child_info->long_addr, child->mac64, 8);
return;
}
return;
}
void thread_dynamic_storage_child_info_clear(int8_t interface_id, struct mac_neighbor_table_entry *child)
{
thread_sync_child_info_t *child_info = thread_dynamic_storage_child_info_find(interface_id, child);
if (child_info) {
// Clear child information
memset(child_info, 0, sizeof(thread_sync_child_info_t));
tr_debug("Dynamic storage: cleared child; mac16=%04x", child->mac16);
return;
}
return;
}
static thread_sync_child_info_t *thread_dynamic_storage_child_info_find(int8_t interface_id, mac_neighbor_table_entry_t *child)
{
thread_network_dynamic_data_entry_t *storeEntry = thread_network_synch_find(interface_id);
if (!storeEntry) {
return NULL;
}
for (uint16_t i = 0; i < THREAD_MAX_CHILD_COUNT; ++i) {
uint8_t *mac64 = storeEntry->networ_dynamic_data_parameters.children[i].long_addr;
if (memcmp(mac64, child->mac64, 8) == 0) {
return &storeEntry->networ_dynamic_data_parameters.children[i];
}
}
return NULL;
}
static thread_sync_child_info_t *thread_dynamic_storage_free_child_find(int8_t interface_id)
{
thread_network_dynamic_data_entry_t *storeEntry = thread_network_synch_find(interface_id);
if (!storeEntry) {
return NULL;
}
for (int i = 0; i < THREAD_MAX_CHILD_COUNT; ++i) {
if (storeEntry->networ_dynamic_data_parameters.children[i].short_addr == 0) {
return &storeEntry->networ_dynamic_data_parameters.children[i];
}
}
return NULL;
}
void thread_dynamic_storage_build_mle_table(int8_t interface_id)
{
tr_debug("Dynamic storage: building MLE table.");
protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(interface_id);
if (!cur || !cur->mac_parameters) {
return;
}
thread_network_dynamic_data_entry_t *storeEntry = thread_network_synch_find(interface_id);
bool new_entry_created;
if (!storeEntry) {
storeEntry = thread_network_synch_create(interface_id);
}
if (!storeEntry) {
return;
}
mac_neighbor_table_list_t *mac_table_list = &mac_neighbor_info(cur)->neighbour_list;
if (!mac_table_list) {
return;
}
int i;
for (i = 0; i < THREAD_MAX_CHILD_COUNT; ++i) {
if (storeEntry->networ_dynamic_data_parameters.children[i].short_addr == 0) {
// Skip empty child entry
continue;
}
uint8_t *mac64 = storeEntry->networ_dynamic_data_parameters.children[i].long_addr;
tr_debug("Child: %04x, %s", storeEntry->networ_dynamic_data_parameters.children[i].short_addr, trace_array(mac64, 8));
mac_neighbor_table_entry_t *mac_entry = mac_neighbor_entry_get_by_mac64(mac_neighbor_info(cur), mac64, true, &new_entry_created);
if (mac_entry) {
mac_entry->mac16 = storeEntry->networ_dynamic_data_parameters.children[i].short_addr;
mle_service_frame_counter_entry_add(interface_id, mac_entry->index, storeEntry->networ_dynamic_data_parameters.children[i].mle_frame_counter);
mle_mode_parse_to_mac_entry(mac_entry, storeEntry->networ_dynamic_data_parameters.children[i].mode);
// Set MAC layer frame counter for the child
mlme_device_descriptor_t device_desc;
thread_neighbor_class_update_link(&cur->thread_info->neighbor_class, mac_entry->index, 64, new_entry_created);
thread_neighbor_class_mode_parse_to_entry(&cur->thread_info->neighbor_class, mac_entry->index, storeEntry->networ_dynamic_data_parameters.children[i].mode);
thread_neighbor_last_communication_time_update(&cur->thread_info->neighbor_class, mac_entry->index);
mac_helper_device_description_write(cur, &device_desc, mac_entry->mac64, mac_entry->mac16, storeEntry->networ_dynamic_data_parameters.children[i].mac_frame_counter, false);
mac_helper_devicetable_set(&device_desc, cur, mac_entry->index, cur->mac_parameters->mac_default_key_index, new_entry_created);
}
}
}
#endif