mbed-os/source/libNET/src/ns_net.c

1612 lines
49 KiB
C

/*
* Copyright (c) 2014-2021, Pelion and affiliates.
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* \file net.c
* \brief Network API for library model
*
* The network API functions for library model
*/
#include "nsconfig.h"
#include "ns_types.h"
#include "eventOS_scheduler.h"
#include "string.h"
#include "ns_trace.h"
#include "socket_api.h"
#include "nsdynmemLIB.h"
#include "NWK_INTERFACE/Include/protocol.h"
#include "Core/include/ns_socket.h"
#ifdef HAVE_RPL
#include "RPL/rpl_of0.h"
#include "RPL/rpl_mrhof.h"
#include "RPL/rpl_control.h"
#include "RPL/rpl_data.h"
#endif
#include "ccmLIB.h"
#include "6LoWPAN/lowpan_adaptation_interface.h"
#include "6LoWPAN/Bootstraps/network_lib.h"
#include "6LoWPAN/Bootstraps/protocol_6lowpan.h"
#include "6LoWPAN/Bootstraps/protocol_6lowpan_bootstrap.h"
#include "6LoWPAN/ND/nd_router_object.h"
#include "6LoWPAN/MAC/mac_helper.h"
#include "6LoWPAN/MAC/beacon_handler.h"
#ifndef NO_MLE
#include "MLE/mle.h"
#endif
#include "platform/arm_hal_interrupt.h"
#include "common_functions.h"
#include "Service_Libs/whiteboard/whiteboard.h"
#include "net_pana_parameters_api.h"
#ifdef ECC
#include "libX509_V3.h"
#include "ecc.h"
#endif
#include "Security/PANA/pana.h"
#include "Security/PANA/pana_internal_api.h"
#include "nwk_stats_api.h"
#include "NWK_INTERFACE/Include/protocol_stats.h"
#include "Security/Common/sec_lib_definitions.h"
#include "ipv6_stack/protocol_ipv6.h"
#include "ipv6_stack/ipv6_routing_table.h"
#include "libNET/src/net_dns_internal.h"
#include "net_thread_test.h"
#include "6LoWPAN/Thread/thread_common.h"
#include "6LoWPAN/Thread/thread_routing.h"
#include "6LoWPAN/Thread/thread_bootstrap.h"
#include "6LoWPAN/Thread/thread_management_internal.h"
#include "6LoWPAN/ws/ws_common.h"
#ifdef HAVE_WS
#include "6LoWPAN/ws/ws_pae_controller.h"
#endif
#include "BorderRouter/border_router.h"
#include "Service_Libs/mle_service/mle_service_api.h"
#include "6LoWPAN/MAC/mac_data_poll.h"
#include "sw_mac.h"
#include "mac_api.h"
#include "ethernet_mac_api.h"
#include <stdarg.h>
#define TRACE_GROUP "lNet"
/**
* \brief A function checks that the channel list is not empty. Channel pages 9 and 10 can have eight 32-bit channel masks.
* \param scan_list is a pointer to the channel list structure given by the application.
* \return 0 on success.
* \return -1 if channel list is empty.
*/
static int arm_channel_list_validation(const channel_list_s *scan_list)
{
uint8_t i = 1;
if (scan_list) {
if (scan_list->channel_page == CHANNEL_PAGE_9 || scan_list->channel_page == CHANNEL_PAGE_10) {
i = 8;
}
while (i--)
if (scan_list->channel_mask[i]) {
return 0;
}
}
return -1;
}
/* Energy & Active Scan API */
int8_t arm_net_energy_scan(int8_t interface_id, channel_list_s *scan_list, void (*passed_fptr)(int8_t if_id, const mlme_scan_conf_t *conf), uint8_t energy_tresshold)
{
(void)interface_id;
(void)scan_list;
(void)passed_fptr;
(void)energy_tresshold;
int8_t ret_val = -3;
#ifdef HAVE_RF_TUNNEL
(void)interface_id;
(void)scan_list;
(void)passed_fptr;
(void)energy_tresshold;
#else
protocol_interface_info_entry_t *cur = 0;
cur = protocol_stack_interface_info_get_by_id(interface_id);
if (cur) {
if (cur->lowpan_info & INTERFACE_NWK_ACTIVE) {
ret_val = -1;
} else {
nwk_scan_params_t *scan_params = 0;
if (cur->mac_parameters) {
scan_params = &cur->mac_parameters->nwk_scan_params;
scan_params->stack_chan_list = *scan_list;
scan_params->energy_treshold = energy_tresshold;
mlme_scan_t req;
mac_create_scan_request(MAC_ED_SCAN_TYPE, &cur->mac_parameters->nwk_scan_params.stack_chan_list, 5, &req);
if (cur->mac_api) {
cur->scan_cb = passed_fptr;
cur->mac_api->mlme_req(cur->mac_api, MLME_SCAN, &req);
ret_val = 0;
}
}
}
}
#endif
return ret_val;
}
int8_t arm_net_nwk_scan(int8_t interface_id, channel_list_s *scan_list, void (*passed_fptr)(int8_t if_id, const mlme_scan_conf_t *conf), uint8_t scan_level)
{
(void)interface_id;
(void)scan_list;
(void)passed_fptr;
(void)scan_level;
int8_t ret_val = -3;
#ifdef HAVE_RF_TUNNEL
(void)interface_id;
(void)scan_list;
(void)passed_fptr;
(void)scan_level;
#else
protocol_interface_info_entry_t *cur = 0;
cur = protocol_stack_interface_info_get_by_id(interface_id);
if (cur) {
cur->scan_cb = passed_fptr;
if (cur->mac_parameters) {
nwk_filter_params_s *filter = &(cur->mac_parameters->nwk_filter_params);
if (cur->lowpan_info & INTERFACE_NWK_ACTIVE) {
ret_val = -1;
} else if (arm_channel_list_validation(scan_list)) {
tr_debug("Given channel mask is empty!");
ret_val = -2;
} else {
nwk_scan_params_t *scan_params = &cur->mac_parameters->nwk_scan_params;
scan_params->stack_chan_list = *scan_list;
mlme_scan_t req;
mac_create_scan_request(MAC_ACTIVE_SCAN, &scan_params->stack_chan_list, 5, &req);
if (cur->mac_api) {
cur->scan_cb = passed_fptr;
scan_params->active_scan_active = true;
cur->mac_api->mlme_req(cur->mac_api, MLME_SCAN, &req);
}
filter->nwk_active_scan_level = scan_level;
mac_helper_nwk_id_filter_set(0, filter);
mac_helper_mac16_address_set(cur, 0xffff);
protocol_6lowpan_register_handlers(cur);
ret_val = 0;
}
}
}
#endif
return ret_val;
}
nwk_pan_descriptor_t *arm_net_get_scanned_nwk_list(int8_t interface_id)
{
nwk_pan_descriptor_t *ret_val = 0;
protocol_interface_info_entry_t *cur = 0;
cur = protocol_stack_interface_info_get_by_id(interface_id);
if (cur) {
if (cur->mac_parameters) {
ret_val = cur->mac_parameters->nwk_scan_params.nwk_response_info;
}
}
return ret_val;
}
/**
* \brief A function to read pan ID filter.
* \return 16-bit value indicating a pan ID filter.
*/
uint16_t arm_net_get_nwk_pan_id_filter(int8_t interface_id)
{
protocol_interface_info_entry_t *cur = 0;
cur = protocol_stack_interface_info_get_by_id(interface_id);
if (cur) {
if (cur->mac_parameters) {
nwk_filter_params_s *filter = &(cur->mac_parameters->nwk_filter_params);
return filter->net_pan_id_filter;
}
}
return 0;
}
/**
* \brief A function to read network layer configurations.
* \param network_params is a pointer to the structure to where the network layer configs are written to.
* \return 0 on success.
* \return Negative value if interface id or PAN coordinator is not known.
*/
int8_t arm_nwk_param_read(int8_t interface_id, link_layer_setups_s *network_params)
{
protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(interface_id);
addrtype_t addrType = mac_helper_coordinator_address_get(cur, network_params->address);
if (addrType == ADDR_NONE) {
return -2;
}
network_params->PANId = mac_helper_panid_get(cur);
if (addrType == ADDR_802_15_4_SHORT) {
network_params->addr_mode = ADDR_MAC_SHORT16;
} else {
network_params->addr_mode = ADDR_MAC_LONG64;
}
network_params->LogicalChannel = cur->mac_parameters->mac_channel;
network_params->sf = 0xff;
return 0;
}
/**
* \brief A function to read MAC PAN-ID, Short address & EUID64
* \param mac_params is a pointer to the structure to where the mac address are written to.
* \return 0 on success.
* \return Negative value if interface id is not known.
*/
int8_t arm_nwk_mac_address_read(int8_t interface_id, link_layer_address_s *mac_params)
{
int8_t ret_val = -2;
protocol_interface_info_entry_t *cur = 0;
cur = protocol_stack_interface_info_get_by_id(interface_id);
if (cur) {
ret_val = 0;
memcpy(mac_params->mac_long, cur->mac, 8);
memcpy(mac_params->iid_eui64, cur->iid_eui64, 8);
if (cur->mac_parameters) {
mac_params->PANId = cur->mac_parameters->pan_id;
mac_params->mac_short = cur->mac_parameters->mac_short_address;
} else {
mac_params->PANId = 0xffff;
mac_params->mac_short = 0xffff;
}
}
return ret_val;
}
/**
* \brief A function to read 6LoWPAN ND border router address and NWK prefix
* \param mac_params is a pointer to the structure to where the mac address are written to.
* \return 0 on success.
* \return -1 .
*/
int8_t arm_nwk_nd_address_read(int8_t interface_id, network_layer_address_s *nd_addr_info)
{
(void)interface_id;
(void)nd_addr_info;
int8_t ret_val = -2;
#ifdef HAVE_6LOWPAN_ND
protocol_interface_info_entry_t *cur = 0;
cur = protocol_stack_interface_info_get_by_id(interface_id);
if (cur) {
if ((cur->lowpan_info & (INTERFACE_NWK_ACTIVE | INTERFACE_NWK_BOOTSRAP_ADDRESS_REGISTER_READY)) == (INTERFACE_NWK_ACTIVE | INTERFACE_NWK_BOOTSRAP_ADDRESS_REGISTER_READY)) {
uint8_t *adr_ptr = protocol_6lowpan_nd_border_router_address_get(cur->nwk_id);
if (adr_ptr) {
ret_val = 0;
memcpy(nd_addr_info->border_router, adr_ptr, 16);
memcpy(nd_addr_info->prefix, adr_ptr, 8);
}
}
}
#else
(void)interface_id;
(void)nd_addr_info;
#endif
return ret_val;
}
/**
* \brief Get current used channel.
*
* \return Active channel
* \return -1 if invalid network interface ID is given
*/
int16_t arm_net_get_current_channel(int8_t interface_id)
{
int16_t ret_val = -1;
protocol_interface_info_entry_t *cur = 0;
cur = protocol_stack_interface_info_get_by_id(interface_id);
if (cur) {
if (cur->lowpan_info & INTERFACE_NWK_ACTIVE) {
ret_val = cur->mac_parameters->mac_channel;
}
}
return ret_val;
}
/**
* \brief A function to set sleep mode of a host.
* \param state equals to 1 if the sleep mode is to be enabled, 0 if the sleep mode is to be disabled.
*/
void arm_net_host_enter_sleep_state_set(int8_t interface_id, uint8_t state)
{
protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(interface_id);
if (cur && cur->rfd_poll_info) {
if (state) {
cur->rfd_poll_info->macDeepSleepEnabled = true;
} else {
cur->rfd_poll_info->macDeepSleepEnabled = false;
}
}
}
/**
* \brief A function to read library version information.
* \param ptr is a pointer to an array to where the version information is read to.
*/
void net_get_version_information(uint8_t *ptr)
{
(void)ptr;
}
/**
* \brief Set configured network interface Global address mode (Border router bootstrap mode can't set this).
*
* \param interface_id Network interface ID
* \param mode efine 6LoWPAN Global Address register mode::
* * NET_6LOWPAN_GP64_ADDRESS, Interface register only GP64
* * NET_6LOWPAN_GP16_ADDRESS, Interface register only GP16
* * NET_6LOWPAN_MULTI_GP_ADDRESS, Interface register GP16 and GP64 addresses. GP16 is primary address and GP64 is secondary.
*
* \param short_address_base Short address base. If application defines value 0-0xfffd 6LoWPAN try to register GP16 address using that address. 0xfffe and 0xffff will generate random 16-bit short address.
*
* \param define_new_short_address_at_DAD This parameter is only checked when mode is not NET_6LOWPAN_GP64_ADDRESS and short_address_base is 0-0xfffd. Recommend value is 1 that will enable automatic new address definition at Duplicate Address Detection(DAD). Value 0 will generate Duplicate Adreress Detection error for interface bootstrap.
Border Router Device will not check that part.
*
* \return >=0 Bootstrap mode set OK.
* \return -1 Unknown network ID.
* \return -2 Illegal for Border Router
* \return -3 Bootsrap not defined yet.
*/
int8_t arm_nwk_6lowpan_gp_address_mode(int8_t interface_id, net_6lowpan_gp_address_mode_e mode, uint16_t short_address_base, uint8_t define_new_short_address_at_DAD)
{
#ifdef HAVE_6LOWPAN_ND
protocol_interface_info_entry_t *cur;
cur = protocol_stack_interface_info_get_by_id(interface_id);
if (!cur) {
return -1;
}
if (cur->bootsrap_mode == ARM_NWK_BOOTSRAP_MODE_6LoWPAN_BORDER_ROUTER) {
return -2;
}
if (!(cur->configure_flags & INTERFACE_BOOTSTRAP_DEFINED)) {
return -3;
}
if (thread_info(cur)) {
return -2;
}
if (short_address_base < 0xfffe) {
cur->lowpan_desired_short_address = short_address_base;
} else {
protocol_6lowpan_allocate_mac16(cur); //Allocate Random init value
}
cur->reallocate_short_address_if_duplicate = define_new_short_address_at_DAD;
cur->lowpan_address_mode = mode;
return 0;
#else
(void) interface_id;
(void) mode;
(void) short_address_base;
(void) define_new_short_address_at_DAD;
return -2;
#endif
}
/**
* \brief A function to read networking address informations.
* \param addr_id identifies the address information type to be read.
* \param address is a pointer to a buffer to where the address information is written to.
* \return zero on success, -1 on errors.
*/
int8_t arm_net_address_get(int8_t interface_id, net_address_t addr_id, uint8_t *address)
{
int8_t ret_val = -1;
protocol_interface_info_entry_t *cur;
const uint8_t *addr;
cur = protocol_stack_interface_info_get_by_id(interface_id);
if (!cur) {
return -1;
}
if (!cur->global_address_available && addr_id != ADDR_IPV6_LL) {
//Should also check Check Bootstrap state
return -1;
}
switch (addr_id) {
case ADDR_IPV6_LL:
ret_val = addr_interface_get_ll_address(cur, address, 0);
break;
case ADDR_IPV6_GP:
addr = addr_select_with_prefix(cur, NULL, 0, SOCKET_IPV6_PREFER_SRC_PUBLIC | SOCKET_IPV6_PREFER_SRC_6LOWPAN_SHORT);
if (addr) {
memcpy(address, addr, 16);
ret_val = 0;
}
break;
case ADDR_IPV6_GP_SEC:
addr = addr_select_with_prefix(cur, NULL, 0, SOCKET_IPV6_PREFER_SRC_PUBLIC | SOCKET_IPV6_PREFER_SRC_6LOWPAN_LONG);
/* Return if the "prefer long" gives a different answer to the default "prefer short". Pointer comparison is
* sufficient as addr_select returns a pointer into the address list. */
if (addr && addr != addr_select_with_prefix(cur, NULL, 0, SOCKET_IPV6_PREFER_SRC_PUBLIC | SOCKET_IPV6_PREFER_SRC_6LOWPAN_SHORT)) {
memcpy(address, addr, 16);
ret_val = 0;
}
break;
}
return ret_val;
}
/**
* \brief A function to read network Interface address count.
* \param interface_id Id to interface.
* \param address_count Pointer where address count will be saved.
* \return zero on success, -1 on errors.
*/
int8_t arm_net_interface_address_list_size(int8_t interface_id, uint16_t *address_count)
{
int8_t ret_val = -1;
protocol_interface_info_entry_t *cur;
*address_count = 0;
cur = protocol_stack_interface_info_get_by_id(interface_id);
if (cur) {
ns_list_foreach(if_address_entry_t, addr, &cur->ip_addresses) {
if (!addr->tentative) {
(*address_count)++;
}
}
ret_val = 0;
}
return ret_val;
}
/**
* \brief A function to set interface metric.
* \param interface_id Network interface ID.
* \param metric Used to rank otherwise-equivalent routes. Lower is preferred and default is 0. The metric value is added to metric provided by the arm_net_route_add() function.
* \return 0 On success, -1 on errors.
*/
int8_t arm_net_interface_set_metric(int8_t interface_id, uint16_t metric)
{
int8_t ret_val = -1;
protocol_interface_info_entry_t *cur;
cur = protocol_stack_interface_info_get_by_id(interface_id);
if (cur) {
cur->ipv6_neighbour_cache.route_if_info.metric = metric;
ret_val = 0;
}
return ret_val;
}
/**
* \brief A function to read the interface metric value on an interface.
* \param interface_id Network interface ID.
* \param metric A pointer to the variable where the interface metric value is saved.
* \return 0 On success, -1 on errors.
*/
int8_t arm_net_interface_get_metric(int8_t interface_id, uint16_t *metric)
{
int8_t ret_val = -1;
protocol_interface_info_entry_t *cur;
cur = protocol_stack_interface_info_get_by_id(interface_id);
if (cur) {
*metric = cur->ipv6_neighbour_cache.route_if_info.metric;
ret_val = 0;
}
return ret_val;
}
/**
* \brief A function to read network Interface.
* \param interface_id Id to interface.
* \param address_buf_size Indicate buffer size in bytes minimal is 16 bytes.
* \param address_buffer pointer where stack save address one by one.
* \param writed_address_count pointer where stack save how many address is writed behind address_buffer.
*
* \return zero on success, -1 on errors.
*/
int8_t arm_net_address_list_get(int8_t interface_id, uint8_t address_buf_size, uint8_t *address_buffer, int *writed_address_count)
{
int8_t ret_val = -1;
protocol_interface_info_entry_t *cur;
int address_count = 0;
cur = protocol_stack_interface_info_get_by_id(interface_id);
if (!cur) {
return -1;
}
if (address_buf_size >= 16) {
int loop_counter = 0;
bool save_address;
while (loop_counter < 2) {
ns_list_foreach(if_address_entry_t, e, &cur->ip_addresses) {
if (e->tentative) {
continue;
}
save_address = false;
if (loop_counter) {
if (!addr_is_ipv6_link_local(e->address)) {
save_address = true;
}
} else {
if (addr_is_ipv6_link_local(e->address)) {
save_address = true;
}
}
if (save_address) {
memcpy(address_buffer, e->address, 16);
address_buf_size -= 16;
ret_val = 0;
address_count++;
if (address_buf_size >= 16) {
address_buffer += 16;
} else {
*writed_address_count = address_count;
return ret_val;
}
}
}
loop_counter++;
}
//Save writed address count to Pointer
*writed_address_count = address_count;
}
return ret_val;
}
int8_t arm_net_address_list_get_next(int8_t interface_id, int *n, uint8_t address_buffer[16])
{
int8_t ret_val = -1;
protocol_interface_info_entry_t *cur;
int address_count = 0;
cur = protocol_stack_interface_info_get_by_id(interface_id);
if (!cur) {
return -1;
}
int loop_counter = 0;
bool save_address;
while (loop_counter < 2) {
ns_list_foreach(if_address_entry_t, e, &cur->ip_addresses) {
if (e->tentative) {
continue;
}
save_address = false;
if (loop_counter) {
if (!addr_is_ipv6_link_local(e->address)) {
save_address = true;
}
} else {
if (addr_is_ipv6_link_local(e->address)) {
save_address = true;
}
}
if (save_address) {
if (*n == address_count) {
memcpy(address_buffer, e->address, 16);
*n = *n + 1;
return 0;
}
address_count++;
}
}
loop_counter++;
}
return ret_val;
}
int8_t arm_net_address_add_to_interface(int8_t interface_id, const uint8_t address[16], uint8_t prefix_len, uint32_t valid_lifetime, uint32_t preferred_lifetime)
{
protocol_interface_info_entry_t *cur;
if_address_entry_t *entry;
cur = protocol_stack_interface_info_get_by_id(interface_id);
if (!cur) {
return -1;
}
entry = addr_add(cur, address, prefix_len, ADDR_SOURCE_STATIC, valid_lifetime, preferred_lifetime, false);
if (!entry) {
return -1;
}
return 0;
}
int8_t arm_net_address_delete_from_interface(int8_t interface_id, const uint8_t address[16])
{
protocol_interface_info_entry_t *cur;
cur = protocol_stack_interface_info_get_by_id(interface_id);
if (!cur) {
return -1;
}
return addr_delete(cur, address);
}
/* DNS cache functions
*/
int8_t arm_net_dns_server_get(int8_t interface_id, uint8_t address[16], uint8_t **dns_search_list_ptr, uint8_t *dns_search_list_len, uint8_t index)
{
return net_dns_server_get(interface_id, address, dns_search_list_ptr, dns_search_list_len, index);
}
int8_t arm_net_dns_query_result_set(int8_t interface_id, const uint8_t address[16], const char *domain_name_ptr, uint32_t lifetime)
{
return net_dns_query_result_set(interface_id, address, domain_name_ptr, lifetime);
}
int8_t arm_net_dns_query_result_get(int8_t interface_id, uint8_t address[16], char *domain_name_ptr)
{
return net_dns_query_result_get(interface_id, address, domain_name_ptr);
}
int8_t arm_net_route_add(const uint8_t *prefix, uint8_t prefix_len, const uint8_t *next_hop, uint32_t lifetime, uint8_t metric, int8_t interface_id)
{
ipv6_route_t *entry;
if (prefix_len > 128 || (prefix == NULL && prefix_len != 0)) {
return -2;
}
entry = ipv6_route_add_metric(prefix, prefix_len, interface_id, next_hop, ROUTE_USER, NULL, 0, lifetime, metric);
if (!entry) {
return -1;
}
return 0;
}
int8_t arm_net_route_delete(const uint8_t *prefix, uint8_t prefix_len, const uint8_t *next_hop, int8_t interface_id)
{
if (prefix_len > 128 || (prefix == NULL && prefix_len != 0)) {
return -2;
}
return ipv6_route_delete(prefix, prefix_len, interface_id, next_hop, ROUTE_USER);
}
int8_t arm_nwk_interface_ethernet_init(eth_mac_api_t *api, const char *interface_name_ptr)
{
#ifdef HAVE_ETHERNET
if (!api) {
return -1;
}
protocol_interface_info_entry_t *cur = protocol_stack_interface_generate_ethernet(api);
if (!cur) {
return -3;
}
cur->if_up = ipv6_interface_up;
cur->if_down = ipv6_interface_down;
cur->interface_name = interface_name_ptr;
return cur->id;
#else
(void)api;
(void)interface_name_ptr;
return -2;
#endif
}
extern int8_t arm_nwk_interface_ppp_init(struct eth_mac_api_s *api, const char *interface_name_ptr)
{
#ifdef HAVE_ETHERNET
if (!api) {
return -1;
}
protocol_interface_info_entry_t *cur = protocol_stack_interface_generate_ppp(api);
if (!cur) {
return -3;
}
cur->if_up = ipv6_interface_up;
cur->if_down = ipv6_interface_down;
cur->interface_name = interface_name_ptr;
return cur->id;
#else
(void)api;
(void)interface_name_ptr;
return -2;
#endif
}
int8_t arm_nwk_interface_lowpan_init(mac_api_t *api, char *interface_name_ptr)
{
if (!api) {
return -1;
}
protocol_interface_info_entry_t *cur = protocol_stack_interface_generate_lowpan(api);
if (!cur) {
return -3;
}
protocol_6lowpan_configure_core(cur);
cur->interface_name = interface_name_ptr;
return cur->id;
}
static int arm_net_channel_bit_mask_to_number(const uint32_t *channel_mask)
{
int i, j;
for (j = 0; j < 8; j++) {
for (i = 0; i < 32; i++) {
if (channel_mask[j] & (1U << i)) {
break;
}
}
if (i < 32) {
break;
}
}
if (j > 7) {
return -1;
}
return i + (j * 32);
}
/**
* \brief Set network interface link layer parameters.
*
* \param interface_id Network interface ID
* \param tun_driver_id Driver id FOR PHY data IN & OUT
* \param channel define network link channel
* \param link_setup Link layer parameters for NET_6LOWPAN_NETWORK_DRIVER defines NetworkID, PAN-ID Short Address
*
* \return >=0 Config set OK.
* \return -1 Unknown network ID or tun driver.
* \return -2 Interface is active, Bootsrap mode not selected or is not NET_6LOWPAN_NETWORK_DRIVER or NET_6LOWPAN_SNIFFER.
* \return -3 No Memory for 6LoWPAN stack.
* \return -4 Null pointer parameter
* \return -5 Channel list empty
*/
int8_t arm_nwk_interface_network_driver_set(int8_t interface_id, const channel_list_s *nwk_channel_list, network_driver_setup_s *link_setup)
{
int8_t ret_val = -1;
protocol_interface_info_entry_t *cur = 0;
if (arm_channel_list_validation(nwk_channel_list)) {
tr_debug("Given channel mask is empty!");
return -5;
}
cur = protocol_stack_interface_info_get_by_id(interface_id);
if (!cur || !cur->mac_api) {
return -1;
}
if (cur->lowpan_info & INTERFACE_NWK_ACTIVE) {
ret_val = -2;
} else if ((cur->configure_flags & INTERFACE_BOOTSTRAP_DEFINED) == 0) {
ret_val = -2;
} else if (link_setup && (link_setup->beacon_payload_tlv_length && link_setup->beacon_payload_tlv_ptr == NULL)) {
ret_val = -4;
} else if (link_setup && (cur->bootsrap_mode == ARM_NWK_BOOTSRAP_MODE_6LoWPAN_RF_ACCESPOINT || cur->bootsrap_mode == ARM_NWK_BOOTSRAP_MODE_6LoWPAN_RF_SNIFFER)) {
ret_val = 0;
if (cur->bootsrap_mode == ARM_NWK_BOOTSRAP_MODE_6LoWPAN_RF_ACCESPOINT) {
//Configure setup
uint8_t *beaon_payload = mac_helper_beacon_payload_reallocate(cur, 18);
if (beaon_payload) {
*beaon_payload++ = link_setup->beacon_protocol_id;
*beaon_payload++ = 7; //Accept Join / Host & Router
memcpy(beaon_payload, link_setup->network_id, 16);
ret_val = mac_helper_beacon_payload_register(cur);
} else {
ret_val = -3;
}
cur->mac_parameters->mac_channel_list = *nwk_channel_list;
} else {
}
if (ret_val == 0) {
if (link_setup->mac_short_adr < 0xfffe) {
cur->lowpan_address_mode = NET_6LOWPAN_GP16_ADDRESS;
} else {
cur->lowpan_address_mode = NET_6LOWPAN_GP64_ADDRESS;
}
mac_helper_panid_set(cur, link_setup->mac_panid);
mac_helper_mac16_address_set(cur, link_setup->mac_short_adr);
int channel_number = arm_net_channel_bit_mask_to_number(nwk_channel_list->channel_mask);
if (channel_number >= 0) {
// copy the channel list information, which is needed by FHSS
//Set Channel
mac_helper_mac_channel_set(cur, channel_number);
cur->configure_flags |= INTERFACE_NETWORK_DRIVER_SETUP_DEFINED;
}
} else {
mac_helper_beacon_payload_reallocate(cur, 0);
}
} else {
ret_val = -2;
}
return ret_val;
}
int8_t arm_nwk_interface_up(int8_t interface_id)
{
int8_t ret_val = -1;
protocol_interface_info_entry_t *cur = 0;
cur = protocol_stack_interface_info_get_by_id(interface_id);
if (!cur) {
return -1;
}
if ((cur->lowpan_info & INTERFACE_NWK_ACTIVE) && cur->bootsrap_mode != ARM_NWK_BOOTSRAP_MODE_6LoWPAN_BORDER_ROUTER) {
return -4;
}
if (!cur->if_up || !cur->if_down) {
return -5;
}
cur->net_start_tasklet = eventOS_scheduler_get_active_tasklet();
ret_val = cur->if_up(cur);
return ret_val;
}
int8_t arm_nwk_interface_down(int8_t interface_id)
{
int8_t ret_val = -1;
protocol_interface_info_entry_t *cur = 0;
cur = protocol_stack_interface_info_get_by_id(interface_id);
if (cur) {
if (!(cur->lowpan_info & INTERFACE_NWK_ACTIVE)) {
ret_val = -4;
} else if (!cur->if_up || !cur->if_down) {
return -5;
} else {
ret_val = cur->if_down(cur);
}
}
return ret_val;
}
int8_t arm_pana_client_key_pull(int8_t interface_id)
{
#ifndef PANA
(void)interface_id;
#endif
return pana_client_key_pull(interface_id);
}
int8_t arm_nwk_link_layer_security_mode(int8_t interface_id, net_6lowpan_link_layer_sec_mode_e mode, uint8_t sec_level, const net_link_layer_psk_security_info_s *psk_key_info)
{
protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(interface_id);
if (!cur || thread_info(cur) || !cur->mac_parameters || (cur->configure_flags & INTERFACE_BOOTSTRAP_DEFINED) == 0) {
return -1;
}
#ifndef HAVE_6LOWPAN_ND
(void) mode;
(void) sec_level;
(void) psk_key_info;
return -1;
#else
if (cur->lowpan_info & INTERFACE_NWK_ACTIVE) {
return -4;
}
//Verify MLE Service
if (arm_6lowpan_mle_service_ready_for_security_init(cur) != 0) {
return -1;
}
cur->if_lowpan_security_params->nwk_security_mode = mode;
mac_helper_link_frame_counter_set(cur->id, 0); //This is maybe mistake
if (mode == NET_SEC_MODE_NO_LINK_SECURITY) {
cur->mac_parameters->mac_configured_sec_level = 0;
cur->if_lowpan_security_params->security_level = 0;
cur->configure_flags |= INTERFACE_SECURITY_DEFINED;
cur->lowpan_info &= ~INTERFACE_NWK_BOOTSRAP_PANA_AUTHENTICATION;
} else {
if (sec_level == 0 || sec_level > 7) {
return -2;
}
cur->mac_parameters->mac_configured_sec_level = sec_level;
cur->if_lowpan_security_params->security_level = sec_level;
if (mode == NET_SEC_MODE_PSK_LINK_SECURITY) {
if (!psk_key_info) {
return -2;
}
//SET PSK KEY
cur->if_lowpan_security_params->psk_key_info = *psk_key_info;
cur->lowpan_info &= ~INTERFACE_NWK_BOOTSRAP_PANA_AUTHENTICATION;
cur->configure_flags |= INTERFACE_SECURITY_DEFINED;
} else {
if (!cur->if_lowpan_security_params->pana_params) {
cur->if_lowpan_security_params->pana_params = pana_client_parameter_allocate();
}
if (!cur->if_lowpan_security_params->pana_params) {
return -2;
}
cur->lowpan_info |= (INTERFACE_NWK_BOOTSRAP_PANA_AUTHENTICATION);
}
}
return 0;
#endif
}
int8_t arm_network_certificate_chain_set(const arm_certificate_chain_entry_s *chain_info)
{
int8_t ret = -2;
#if !defined(PANA) && !defined(HAVE_WS)
(void)chain_info;
#endif
#ifdef HAVE_WS
ret = ws_pae_controller_certificate_chain_set(chain_info);
#endif
#ifdef PANA
ret = pana_interface_certificate_chain_set(chain_info);
#endif
return ret;
}
int8_t arm_network_trusted_certificate_add(const arm_certificate_entry_s *cert)
{
#ifdef HAVE_WS
return ws_pae_controller_trusted_certificate_add(cert);
#else
(void) cert;
return -1;
#endif
}
int8_t arm_network_trusted_certificate_remove(const arm_certificate_entry_s *cert)
{
#ifdef HAVE_WS
return ws_pae_controller_trusted_certificate_remove(cert);
#else
(void) cert;
return -1;
#endif
}
int8_t arm_network_trusted_certificates_remove(void)
{
#ifdef HAVE_WS
return ws_pae_controller_trusted_certificates_remove();
#else
return -1;
#endif
}
int8_t arm_network_own_certificate_add(const arm_certificate_entry_s *cert)
{
#ifdef HAVE_WS
return ws_pae_controller_own_certificate_add(cert);
#else
(void) cert;
return -1;
#endif
}
extern int8_t arm_network_own_certificates_remove(void)
{
#ifdef HAVE_WS
return ws_pae_controller_own_certificates_remove();
#else
return -1;
#endif
}
int8_t arm_network_certificate_revocation_list_add(const arm_cert_revocation_list_entry_s *crl)
{
#ifdef HAVE_WS
return ws_pae_controller_certificate_revocation_list_add(crl);
#else
(void) crl;
return -1;
#endif
}
int8_t arm_network_certificate_revocation_list_remove(const arm_cert_revocation_list_entry_s *crl)
{
#ifdef HAVE_WS
return ws_pae_controller_certificate_revocation_list_remove(crl);
#else
(void) crl;
return -1;
#endif
}
/**
* \brief Read Pana server security key material
*
* previous_active_network_key is information is only valid when current_active_key_index is bigger than 1.
*
*\param key pointer for store keymaterial information.
*
* \return 0 Key Read OK
* \return -1 Pana server key material not available
*/
int8_t arm_network_key_get(int8_t interface_id, ns_keys_t *key)
{
#ifndef PANA_SERVER
(void)interface_id;
(void)key;
#endif
return pana_network_key_get(interface_id, key);
}
int8_t arm_pana_server_library_init(int8_t interface_id, net_tls_cipher_e cipher_mode, const uint8_t *key_material, uint32_t time_period_before_activate_key)
{
#ifndef PANA_SERVER
(void)interface_id;
(void)cipher_mode;
(void)key_material;
(void)time_period_before_activate_key;
#endif
return pana_server_interface_init(interface_id, cipher_mode, key_material, time_period_before_activate_key);
}
int8_t arm_pana_activate_new_key(int8_t interface_id)
{
#ifndef PANA_SERVER
(void)interface_id;
#endif
return pana_server_trig_new_key(interface_id);
}
int8_t arm_pana_server_key_update(int8_t interface_id, const uint8_t *network_key_material)
{
#ifndef PANA_SERVER
(void)interface_id;
(void)network_key_material;
#endif
return pana_server_key_update(interface_id, network_key_material);
}
int8_t net_pana_parameter_set(const pana_lib_parameters_s *parameter_ptr)
{
#ifndef PANA
(void)parameter_ptr;
#endif
return pana_set_params(parameter_ptr);
}
/**
* \brief API to read PANA library parameters.
*
* \param parameter_ptr Output pointer for Pana parameters
*
*/
int8_t net_pana_parameter_read(pana_lib_parameters_s *parameter_ptr)
{
#ifndef PANA
(void)parameter_ptr;
#endif
return pana_get_params(parameter_ptr);
}
int8_t arm_pana_client_library_init(int8_t interface_id, net_tls_cipher_e cipher_mode, uint32_t psk_key_id)
{
#ifndef PANA
(void)interface_id;
(void)cipher_mode;
(void)psk_key_id;
#endif
return pana_client_interface_init(interface_id, cipher_mode, psk_key_id);
}
int8_t arm_nwk_interface_configure_ipv6_bootstrap_set(int8_t interface_id, net_ipv6_mode_e bootstrap_mode, const uint8_t *ipv6_prefix_pointer)
{
#ifndef HAVE_ETHERNET
(void)interface_id;
(void)bootstrap_mode;
(void)ipv6_prefix_pointer;
#endif
return ipv6_interface_configure_ipv6_bootstrap_set(interface_id, bootstrap_mode, ipv6_prefix_pointer);
}
int8_t arm_nwk_interface_accept_ipv6_ra(int8_t interface_id, net_ipv6_accept_ra_e accept_ra)
{
#ifndef HAVE_ETHERNET
(void)interface_id;
(void)accept_ra;
#endif
return ipv6_interface_accept_ra(interface_id, accept_ra);
}
int8_t arm_6lowpan_bootsrap_set_for_selected_interface(int8_t interface_id)
{
protocol_interface_info_entry_t *cur;
cur = protocol_stack_interface_info_get_by_id(interface_id);
if (!cur) {
return -1;
}
if (cur->lowpan_info & INTERFACE_NWK_ACTIVE || cur->interface_mode == INTERFACE_UP) {
return -4;
}
if (cur->nwk_id != IF_6LoWPAN) {
return -1;
}
return 0;
}
/**
* \brief Set network interface bootstrap setup.
*
* \param interface_id Network interface ID
* \param bootstrap_mode Selected Bootstrap mode:
* * NET_6LOWPAN_BORDER_ROUTER, Initialise Border router basic setup
* * NET_6LOWPAN_ROUTER, Enable normal 6LoWPAN ND and RPL to bootstrap
* * NET_6LOWPAN_HOST, Enable normal 6LoWPAN ND only to bootstrap
* * NET_6LOWPAN_SLEEPY_HOST, Enable normal 6LoWPAN ND only to bootstrap
*
* \param net_6lowpan_mode_extension Define MLE protocol use and 6LoWPAN mode
*
* \return >=0 Bootstrap mode set OK.
* \return -1 Unknown network ID.
* \return -2 Unsupported bootstrap type or extension in this library.
* \return -3 No Memory for 6LoWPAN stack.
* \return -4 Null pointer parameter
*/
int8_t arm_nwk_interface_configure_6lowpan_bootstrap_set(int8_t interface_id, net_6lowpan_mode_e bootstrap_mode, net_6lowpan_mode_extension_e net_6lowpan_mode_extension)
{
int8_t ret_val;
(void)bootstrap_mode;
ret_val = arm_6lowpan_bootsrap_set_for_selected_interface(interface_id);
if (ret_val == 0) {
if (net_6lowpan_mode_extension == NET_6LOWPAN_THREAD) {
ret_val = thread_node_bootstrap_init(interface_id, bootstrap_mode);
} else if (net_6lowpan_mode_extension == NET_6LOWPAN_WS) {
ret_val = ws_common_init(interface_id, bootstrap_mode);
} else {
ret_val = arm_6lowpan_bootstarp_bootstrap_set(interface_id, bootstrap_mode, net_6lowpan_mode_extension);
}
}
return ret_val;
}
int8_t arm_nwk_set_channel_list(int8_t interface_id, const channel_list_s *nwk_channel_list)
{
int8_t ret_val = -1;
protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(interface_id);
if (!cur || !cur->mac_parameters) {
return -1;
}
if (arm_channel_list_validation(nwk_channel_list)) {
tr_debug("Given channel mask is empty!");
return -2;
}
//CHECK Value
if (cur->lowpan_info & INTERFACE_NWK_ACTIVE) {
return -4;
}
if (cur->bootsrap_mode == ARM_NWK_BOOTSRAP_MODE_6LoWPAN_BORDER_ROUTER) {
if (!cur->border_router_setup) {
return -2;
}
const int channel_number = arm_net_channel_bit_mask_to_number(nwk_channel_list->channel_mask);
if (channel_number < 0) {
return -3;
}
cur->mac_parameters->mac_channel_list = *nwk_channel_list;
cur->mac_parameters->mac_channel = channel_number;
cur->border_router_setup->chanlist = &cur->mac_parameters->mac_channel_list;
ret_val = 0;
} else {
// copy the channel information and store one internal pointer to it
cur->mac_parameters->mac_channel_list = *nwk_channel_list;
ret_val = 0;
}
return ret_val;
}
int8_t arm_nwk_6lowpan_link_scan_parameter_set(int8_t interface_id, uint8_t scan_time)
{
int8_t ret_val = -1;
protocol_interface_info_entry_t *cur = 0;
cur = protocol_stack_interface_info_get_by_id(interface_id);
if (cur) {
if (cur->lowpan_info & INTERFACE_NWK_ACTIVE) {
return -4;
}
if (cur->mac_parameters) {
if (scan_time > 14) {
ret_val = -5;
} else {
nwk_scan_params_t *scan_params = 0;
scan_params = &cur->mac_parameters->nwk_scan_params;
scan_params->scan_duration = scan_time;
ret_val = 0;
}
}
}
return ret_val;
}
int8_t arm_nwk_6lowpan_link_panid_filter_for_nwk_scan(int8_t interface_id, uint16_t pan_id_filter)
{
int8_t ret_val = -1;
protocol_interface_info_entry_t *cur = 0;
cur = protocol_stack_interface_info_get_by_id(interface_id);
if (cur) {
if (cur->lowpan_info & INTERFACE_NWK_ACTIVE) {
ret_val = -2;
} else if (cur->mac_parameters) {
nwk_filter_params_s *filter = &(cur->mac_parameters->nwk_filter_params);
filter->net_pan_id_filter = pan_id_filter;
ret_val = 0;
}
}
return ret_val;
}
int8_t arm_nwk_6lowpan_link_nwk_id_filter_for_nwk_scan(int8_t interface_id, const uint8_t *nwk_id_filter)
{
int8_t ret_val = -1;
protocol_interface_info_entry_t *cur = 0;
cur = protocol_stack_interface_info_get_by_id(interface_id);
if (cur) {
if (cur->lowpan_info & INTERFACE_NWK_ACTIVE) {
ret_val = -2;
} else if (cur->mac_parameters) {
nwk_filter_params_s *filter = &(cur->mac_parameters->nwk_filter_params);
ret_val = mac_helper_nwk_id_filter_set(nwk_id_filter, filter);
}
}
return ret_val;
}
int8_t arm_nwk_6lowpan_link_protocol_id_filter_for_nwk_scan(int8_t interface_id, uint8_t protocol_ID)
{
int8_t ret_val = -1;
protocol_interface_info_entry_t *cur = 0;
cur = protocol_stack_interface_info_get_by_id(interface_id);
if (cur) {
if (cur->lowpan_info & INTERFACE_NWK_ACTIVE) {
ret_val = -4;
} else if (cur->mac_parameters) {
nwk_filter_params_s *filter = &(cur->mac_parameters->nwk_filter_params);
filter->beacon_protocol_id_filter = protocol_ID;
ret_val = 0;
}
}
return ret_val;
}
/* Don't have a loopback interface we can optimise for, but we do still need a route so we
* can talk to ourself at all, in case our address isn't in an on-link prefix.
*/
static void net_automatic_loopback_route_update(protocol_interface_info_entry_t *interface, const if_address_entry_t *addr, if_address_callback_t reason)
{
/* Don't care about link-local addresses - we know they're on-link */
if (addr_is_ipv6_link_local(addr->address)) {
return;
}
/* TODO: When/if we have a real loopback interface, these routes would use it instead of interface->id */
switch (reason) {
case ADDR_CALLBACK_DAD_COMPLETE:
ipv6_route_add(addr->address, 128, interface->id, NULL, ROUTE_LOOPBACK, 0xFFFFFFFF, 0);
break;
case ADDR_CALLBACK_DELETED:
ipv6_route_delete(addr->address, 128, interface->id, NULL, ROUTE_LOOPBACK);
break;
default:
break;
}
}
int8_t arm_nwk_6lowpan_beacon_join_priority_tx_callback_set(int8_t interface_id,
beacon_join_priority_tx_cb *beacon_join_priority_tx_cb_ptr)
{
return (mac_beacon_link_beacon_join_priority_tx_callback_set(interface_id, beacon_join_priority_tx_cb_ptr));
}
int8_t arm_nwk_6lowpan_beacon_compare_rx_callback_set(int8_t interface_id,
beacon_compare_rx_cb *beacon_compare_rx_cb_ptr)
{
return (mac_beacon_link_beacon_compare_rx_callback_set(interface_id, beacon_compare_rx_cb_ptr));
}
/**
* \brief A function to initialize core elements of NanoStack library.
*
* \param core_idle is a function pointer to a function that is called whenever NanoStack is idle.
* \return 0 on success.
* \return -1 if a null pointer is given.
*/
int8_t net_init_core(void)
{
/* Reset Protocol_stats */
protocol_stats_init();
protocol_core_init();
#ifdef HAVE_RPL
rpl_data_init();
// XXX application should call these!
rpl_of0_init();
rpl_mrhof_init();
#endif
network_library_init();
addr_notification_register(net_automatic_loopback_route_update);
return 0;
}
static int8_t mac_data_poll_host_polling_state_change_check(protocol_interface_info_entry_t *cur)
{
int8_t ret_val = 0;
if (cur->lowpan_info & INTERFACE_NWK_ROUTER_DEVICE) {
tr_warn("Host Control not accepted for Router");
ret_val = -1;
} else if (nwk_bootsrap_ready(cur) == 0) {
tr_debug("Bootsrap Active");
ret_val = -2;
}
return ret_val;
}
/**
* \brief Set new Host state.
*
* \param mode new host state
* \param poll_time poll time in seconds only handled when NET_HOST_SLOW_POLL_MODE is enabled
*
* Valid poll time for NET_HOST_SLOW_POLL_MODE is 0 < poll_time poll_time < 864001 (1 Day)
*
* \return 0, State update OK
* \return -1, unknown state
* \return -2, invalid time
* \return -3 MLE handshake trig Fail
*
*/
int8_t arm_nwk_host_mode_set(int8_t interface_id, net_host_mode_t mode, uint32_t poll_time)
{
protocol_interface_info_entry_t *cur;
cur = protocol_stack_interface_info_get_by_id(interface_id);
if (!cur) {
return -1;
}
if (mac_data_poll_host_polling_state_change_check(cur) != 0) {
return -3;
}
net_host_mode_t old_mode;
if (mac_data_poll_host_mode_get(cur, &old_mode) != 0) {
return -1;
}
if (thread_info(cur)) {
//save polltime for later use, polltime is zero for fast poll mode
thread_info(cur)->sleepy_host_poll_time = 0;
if (mode == NET_HOST_SLOW_POLL_MODE) {
thread_info(cur)->sleepy_host_poll_time = poll_time;
}
if (old_mode == NET_HOST_RX_ON_IDLE && mode != old_mode
&& thread_info(cur)->thread_device_mode == THREAD_DEVICE_MODE_END_DEVICE) {
tr_debug("End device changing to SED");
thread_management_device_type_set(cur->id, THREAD_DEVICE_SED);
return 0;
}
}
return mac_data_poll_host_mode_set(cur, mode, poll_time);
}
/**
* \brief Read Current Host State.
*
* \param mode pointer where host state will be saved
* \return 0, State Read update OK
* \return -1, Net Role is Router or stack is idle
*
*/
int8_t arm_nwk_host_mode_get(int8_t interface_id, net_host_mode_t *mode)
{
protocol_interface_info_entry_t *cur;
cur = protocol_stack_interface_info_get_by_id(interface_id);
if (!cur || !(cur->lowpan_info & INTERFACE_NWK_ACTIVE)) {
return -1;
}
return mac_data_poll_host_mode_get(cur, mode);
}
int8_t net_nvm_data_clean(int8_t interface_id)
{
int8_t ret_val = -2; // Not ative
protocol_interface_info_entry_t *cur = 0;
cur = protocol_stack_interface_info_get_by_id(interface_id);
if (cur) {
if (cur->mac_parameters) {
nwk_filter_params_s *filter = &(cur->mac_parameters->nwk_filter_params);
if ((cur->lowpan_info & INTERFACE_NWK_ACTIVE) == 0) {
mac_helper_nwk_id_filter_set(0, filter);
mac_helper_panid_set(cur, 0xffff);
mac_helper_mac16_address_set(cur, 0xffff);
pana_reset_client_session();
ret_val = 0;
} else {
ret_val = 0;
}
}
}
return ret_val;
}
static void trace_cmd_print(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
vtracef(TRACE_LEVEL_CMD, TRACE_GROUP, fmt, ap);
va_end(ap);
}
void arm_print_routing_table(void)
{
arm_print_routing_table2(trace_cmd_print);
}
void arm_print_routing_table2(void (*print_fn)(const char *fmt, ...))
{
ipv6_destination_cache_print(print_fn);
ipv6_route_table_print(print_fn);
#ifdef HAVE_RPL
rpl_control_print(print_fn);
#endif
}
void arm_print_neigh_cache(void)
{
arm_print_neigh_cache2(trace_cmd_print);
}
void arm_print_neigh_cache2(void (*print_fn)(const char *fmt, ...))
{
nwk_interface_print_neigh_cache(print_fn);
}
void arm_print_protocols(void)
{
arm_print_protocols2(trace_cmd_print, ' ');
}
void arm_print_protocols2(void (*print_fn)(const char *fmt, ...), char sep)
{
socket_list_print(print_fn, sep);
}
void arm_ncache_flush(void)
{
nwk_interface_flush_neigh_cache();
}
int arm_nwk_sleepy_device_parent_buffer_size_set(int8_t interface_id, uint16_t big_packet_threshold, uint16_t small_packets_per_child_count, uint16_t big_packets_total_count)
{
protocol_interface_info_entry_t *cur;
cur = protocol_stack_interface_info_get_by_id(interface_id);
if (cur) {
return lowpan_adaptation_indirect_queue_params_set(cur, big_packet_threshold,
big_packets_total_count, small_packets_per_child_count);
}
return -1;
}
int8_t arm_nwk_set_cca_threshold(int8_t interface_id, uint8_t cca_threshold)
{
protocol_interface_info_entry_t *cur;
cur = protocol_stack_interface_info_get_by_id(interface_id);
if (!cur || !cur->mac_api || (cca_threshold > 100)) {
return -1;
}
mlme_set_t set_req;
set_req.attr = macCCAThreshold;
set_req.attr_index = 0;
set_req.value_pointer = &cca_threshold;
set_req.value_size = sizeof(cca_threshold);
cur->mac_api->mlme_req(cur->mac_api, MLME_SET, &set_req);
return 0;
}
int8_t arm_nwk_set_tx_output_power(int8_t interface_id, uint8_t tx_power)
{
protocol_interface_info_entry_t *cur;
cur = protocol_stack_interface_info_get_by_id(interface_id);
if (!cur || !cur->mac_api || (tx_power > 100)) {
return -1;
}
mlme_set_t set_req;
set_req.attr = macTXPower;
set_req.attr_index = 0;
set_req.value_pointer = &tx_power;
set_req.value_size = sizeof(tx_power);
cur->mac_api->mlme_req(cur->mac_api, MLME_SET, &set_req);
return 0;
}
const cca_threshold_table_s *arm_nwk_get_cca_threshold_table(int8_t interface_id)
{
protocol_interface_info_entry_t *cur;
cur = protocol_stack_interface_info_get_by_id(interface_id);
// Interface or MAC parameters not initialized
if (!cur || !cur->mac_parameters) {
return NULL;
}
// Automatic CCA threshold not initialized
if (!cur->mac_parameters->cca_thr_table.cca_threshold_table || !cur->mac_parameters->cca_thr_table.number_of_channels) {
return NULL;
}
return &cur->mac_parameters->cca_thr_table;
}