mirror of https://github.com/ARMmbed/mbed-os.git
367 lines
11 KiB
C
367 lines
11 KiB
C
/*
|
|
* Copyright (c) 2016-2019, Arm Limited 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.
|
|
*/
|
|
|
|
#include "nsconfig.h"
|
|
#include "ns_types.h"
|
|
#include "ns_trace.h"
|
|
#include <string.h>
|
|
#include "net_load_balance_api.h"
|
|
#include "net_interface.h"
|
|
#include "NWK_INTERFACE/Include/protocol.h"
|
|
#ifdef HAVE_6LOWPAN_ND
|
|
#include "net_rpl.h"
|
|
#include "Service_Libs/load_balance/load_balance_api.h"
|
|
#include "Service_Libs/mle_service/mle_service_api.h"
|
|
#include "nsdynmemLIB.h"
|
|
#include "ns_list.h"
|
|
#include "6LoWPAN/Bootstraps/protocol_6lowpan.h"
|
|
#include "mlme.h"
|
|
#include "mac_api.h"
|
|
#include "sw_mac.h"
|
|
#include "6LoWPAN/MAC/mac_helper.h"
|
|
#include "6LoWPAN/MAC/mac_data_poll.h"
|
|
#include "libNET/src/net_load_balance_internal.h"
|
|
#ifdef ECC
|
|
#include "libX509_V3.h"
|
|
#include "ecc.h"
|
|
#endif
|
|
#ifdef PANA
|
|
#include "Security/PANA/pana.h"
|
|
#include "Security/PANA/pana_internal_api.h"
|
|
#endif
|
|
#include "6LoWPAN/ND/nd_router_object.h"
|
|
#ifdef HAVE_RPL
|
|
#include "RPL/rpl_control.h"
|
|
#endif
|
|
|
|
#define TRACE_GROUP "6lb"
|
|
|
|
static uint8_t net_load_balance_priority_get(const void *load_balance_user)
|
|
{
|
|
const protocol_interface_info_entry_t *cur = load_balance_user;
|
|
if (!cur->rpl_domain) {
|
|
return 0;
|
|
}
|
|
int16_t priority = protocol_6lowpan_rpl_global_priority_get();
|
|
if (priority < 0) {
|
|
priority = 0;
|
|
} else if (priority > 255) {
|
|
priority = 255;
|
|
}
|
|
|
|
return priority;
|
|
}
|
|
|
|
static void net_load_balance_beacon_tx(const void *load_balance_user)
|
|
{
|
|
const protocol_interface_info_entry_t *cur = load_balance_user;
|
|
mlme_set_t set_req;
|
|
set_req.attr = macLoadBalancingBeaconTx;
|
|
set_req.attr_index = 0;
|
|
set_req.value_pointer = NULL;
|
|
set_req.value_size = 0;
|
|
cur->mac_api->mlme_req(cur->mac_api, MLME_SET, &set_req);
|
|
|
|
}
|
|
|
|
static bool net_load_balance_network_switch_req(void *load_balance_user, struct mlme_pan_descriptor_s *PANDescriptor, const uint8_t *beacon_payload, uint16_t beacon_payload_length)
|
|
{
|
|
protocol_interface_info_entry_t *interface = load_balance_user;
|
|
//Run down current interface setup and do start
|
|
if (interface->if_down(interface) != 0) {
|
|
return false;
|
|
}
|
|
#ifdef PANA
|
|
pana_reset_client_session();
|
|
#endif
|
|
if (interface->if_up(interface) != 0) {
|
|
return false;
|
|
}
|
|
|
|
if (!protocol_6lowpan_bootsrap_link_set(interface, PANDescriptor, beacon_payload, beacon_payload_length)) {
|
|
return false;
|
|
}
|
|
|
|
//Start configured bootstrap
|
|
return protocol_6lowpan_bootsrap_start(interface);
|
|
}
|
|
|
|
static void net_load_balance_link_reject(const protocol_interface_info_entry_t *cur)
|
|
{
|
|
uint8_t ll_all_nodes[16];
|
|
memcpy(ll_all_nodes, ADDR_LINK_LOCAL_ALL_NODES, 16);
|
|
mle_service_interface_receiver_handler_update(cur->id, NULL);
|
|
mle_service_reject_message_build(cur->id, ll_all_nodes, false);
|
|
|
|
nd_router_t *nd_router = nd_get_object_by_nwk_id(cur->nwk_id);
|
|
if (nd_router) {
|
|
nd_router->nd_timer = 0;
|
|
nd_router->ns_forward_timer = 0;
|
|
nd_router->mle_advert_timer = 0;
|
|
}
|
|
}
|
|
|
|
static bool net_load_balance_network_switch_notify_cb(const void *load_balance_user, load_balance_nwk_switch_operation operation, uint16_t *timeout)
|
|
{
|
|
const protocol_interface_info_entry_t *cur = load_balance_user;
|
|
switch (operation) {
|
|
case LB_ROUTER_LEAVE:
|
|
if (arm_nwk_6lowpan_rpl_dodag_poison(cur->id) == 0) {
|
|
*timeout = 8;
|
|
} else {
|
|
*timeout = 0;
|
|
}
|
|
break;
|
|
|
|
case LB_NEIGHBOUR_LEAVE:
|
|
net_load_balance_link_reject(cur);
|
|
*timeout = 4;
|
|
break;
|
|
}
|
|
return true;
|
|
}
|
|
#endif
|
|
|
|
int8_t net_load_balance_network_switch_cb_set(int8_t interface_id, net_load_balance_network_switch_notify *network_switch_notify)
|
|
{
|
|
#ifdef HAVE_6LOWPAN_ND
|
|
protocol_interface_info_entry_t *interface_ptr = protocol_stack_interface_info_get_by_id(interface_id);
|
|
if (!interface_ptr) {
|
|
return -1;
|
|
}
|
|
|
|
return load_balance_network_switch_cb_set(interface_ptr->lb_api, network_switch_notify);
|
|
#else
|
|
return -1;
|
|
#endif
|
|
}
|
|
|
|
|
|
int8_t net_load_balance_create(int8_t interface_id, bool enable_periodic_beacon_interval)
|
|
{
|
|
#ifdef HAVE_6LOWPAN_ND
|
|
protocol_interface_info_entry_t *interface_ptr = protocol_stack_interface_info_get_by_id(interface_id);
|
|
if (!interface_ptr || !interface_ptr->mac_api) {
|
|
return -1;
|
|
} else if (interface_ptr->lb_api) {
|
|
return -3;
|
|
}
|
|
//Allocate load balance user class
|
|
load_balance_api_t *lb_api = load_balance_create(net_load_balance_network_switch_notify_cb, enable_periodic_beacon_interval);
|
|
if (!lb_api) {
|
|
return -2;
|
|
}
|
|
//Here initialize load balance based on current mac max beacon data size
|
|
uint16_t beacon_payload_size;
|
|
if (interface_ptr->mac_api->phyMTU > MAC_IEEE_802_15_4_MAX_PHY_PACKET_SIZE) {
|
|
beacon_payload_size = MAC_IEEE_802_15_4_MAX_PHY_PACKET_SIZE - MAC_IEEE_802_15_4_MAX_BEACON_OVERHEAD;
|
|
} else {
|
|
beacon_payload_size = interface_ptr->mac_api->phyMTU - MAC_IEEE_802_15_4_MAX_BEACON_OVERHEAD;
|
|
}
|
|
|
|
if (lb_api->lb_initialize(lb_api, net_load_balance_beacon_tx, net_load_balance_priority_get, net_load_balance_network_switch_req, beacon_payload_size, interface_ptr) != 0) {
|
|
load_balance_delete(lb_api);
|
|
return -2;
|
|
}
|
|
|
|
//Store here load balance class pointer pointer
|
|
interface_ptr->lb_api = lb_api;
|
|
|
|
//Enable if
|
|
if ((interface_ptr->lowpan_info & (INTERFACE_NWK_ACTIVE | INTERFACE_NWK_BOOTSRAP_ADDRESS_REGISTER_READY)) == (INTERFACE_NWK_ACTIVE | INTERFACE_NWK_BOOTSRAP_ADDRESS_REGISTER_READY)) {
|
|
net_load_balance_internal_state_activate(interface_ptr, true);
|
|
}
|
|
|
|
return 0;
|
|
#else
|
|
return -1;
|
|
#endif
|
|
}
|
|
|
|
|
|
int8_t net_load_balance_delete(int8_t interface_id)
|
|
{
|
|
#ifdef HAVE_6LOWPAN_ND
|
|
protocol_interface_info_entry_t *interface_ptr = protocol_stack_interface_info_get_by_id(interface_id);
|
|
if (!interface_ptr) {
|
|
return -1;
|
|
}
|
|
load_balance_api_t *lb_api = interface_ptr->lb_api;
|
|
interface_ptr->lb_api = NULL;
|
|
|
|
return load_balance_delete(lb_api);
|
|
#else
|
|
return -1;
|
|
#endif
|
|
}
|
|
|
|
int8_t net_load_balance_threshold_set(int8_t interface_id, uint8_t threshold_min, uint8_t threshold_max)
|
|
{
|
|
#ifdef HAVE_6LOWPAN_ND
|
|
protocol_interface_info_entry_t *interface_ptr = protocol_stack_interface_info_get_by_id(interface_id);
|
|
if (!interface_ptr) {
|
|
return -1;
|
|
}
|
|
|
|
if (threshold_min > threshold_max) {
|
|
return -1;
|
|
}
|
|
|
|
return load_balance_network_threshold_set(interface_ptr->lb_api, threshold_min, threshold_max);
|
|
#else
|
|
return -1;
|
|
#endif
|
|
}
|
|
|
|
void net_load_balance_internal_state_activate(protocol_interface_info_entry_t *interface_ptr, bool state)
|
|
{
|
|
#ifdef HAVE_6LOWPAN_ND
|
|
if (!interface_ptr || !interface_ptr->lb_api || !interface_ptr->mac_api) {
|
|
return;
|
|
}
|
|
uint32_t trigle_period = 3600;
|
|
uint32_t route_lifetime_period = 3600;
|
|
//Enable Load Balance
|
|
#ifdef HAVE_RPL
|
|
if (state && interface_ptr->rpl_domain) {
|
|
struct rpl_instance *instance = rpl_control_lookup_instance(interface_ptr->rpl_domain, 1, NULL);
|
|
if (instance) {
|
|
const rpl_dodag_conf_t *dodag_config = rpl_control_get_dodag_config(instance);
|
|
if (dodag_config) {
|
|
//dio max Period caluclate in seconds
|
|
uint32_t Imax_ms = (dodag_config->dio_interval_min + dodag_config->dio_interval_doublings) < 32 ?
|
|
(1ul << (dodag_config->dio_interval_min + dodag_config->dio_interval_doublings)) : 0xfffffffful;
|
|
trigle_period = Imax_ms / 1000;
|
|
route_lifetime_period = (uint32_t)dodag_config->default_lifetime * dodag_config->lifetime_unit;
|
|
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
interface_ptr->lb_api->lb_enable(interface_ptr->lb_api, state, trigle_period, route_lifetime_period);
|
|
mlme_set_t set_req;
|
|
set_req.attr = macLoadBalancingAcceptAnyBeacon;
|
|
set_req.attr_index = 0;
|
|
set_req.value_pointer = &state;
|
|
set_req.value_size = sizeof(bool);
|
|
interface_ptr->mac_api->mlme_req(interface_ptr->mac_api, MLME_SET, &set_req);
|
|
#endif
|
|
|
|
}
|
|
|
|
#ifdef HAVE_RPL
|
|
#ifdef HAVE_6LOWPAN_BORDER_ROUTER
|
|
static int8_t net_load_balance_api_get_node_count_cb(void *lb_user, uint16_t *node_count)
|
|
{
|
|
protocol_interface_info_entry_t *interface_ptr = lb_user;
|
|
if (rpl_control_get_instance_dao_target_count(interface_ptr->rpl_domain, 1, NULL, node_count)) {
|
|
return 0;
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
#ifdef HAVE_RPL
|
|
#ifdef HAVE_6LOWPAN_BORDER_ROUTER
|
|
static int8_t net_load_balance_api_get_set_load_level_cb(void *lb_user, uint8_t load_level)
|
|
{
|
|
//Call DODAG preference
|
|
protocol_interface_info_entry_t *interface_ptr = lb_user;
|
|
if (!interface_ptr->rpl_domain || interface_ptr->rpl_domain != protocol_6lowpan_rpl_domain || !protocol_6lowpan_rpl_root_dodag) {
|
|
return -1;
|
|
}
|
|
|
|
if (load_level > RPL_DODAG_PREF_MASK) {
|
|
load_level = RPL_DODAG_PREF_MASK;
|
|
}
|
|
|
|
rpl_control_set_dodag_pref(protocol_6lowpan_rpl_root_dodag, RPL_DODAG_PREF_MASK - load_level);
|
|
return 0;
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
int8_t net_load_balance_load_level_update_enable(int8_t interface_id, uint16_t expected_device_count)
|
|
{
|
|
#ifdef HAVE_RPL
|
|
#ifdef HAVE_6LOWPAN_BORDER_ROUTER
|
|
protocol_interface_info_entry_t *interface_ptr = protocol_stack_interface_info_get_by_id(interface_id);
|
|
if (!interface_ptr) {
|
|
return -1;
|
|
}
|
|
|
|
uint16_t temp16 = expected_device_count % 8;
|
|
if (temp16) {
|
|
expected_device_count += (8 - temp16);
|
|
}
|
|
|
|
return load_balance_network_load_monitor_enable(interface_ptr->lb_api, expected_device_count, RPL_DODAG_PREF_MASK + 1, net_load_balance_api_get_node_count_cb, net_load_balance_api_get_set_load_level_cb);
|
|
#else
|
|
(void)interface_id;
|
|
(void)expected_device_count;
|
|
return -1;
|
|
#endif
|
|
#else
|
|
(void)interface_id;
|
|
(void)expected_device_count;
|
|
return -1;
|
|
#endif
|
|
}
|
|
|
|
/**
|
|
* \brief Disable automatic network load level update
|
|
*
|
|
* \param interface_id interface id
|
|
*
|
|
* \return 0 process ok -1 Unknown interface id
|
|
*/
|
|
int8_t net_load_balance_load_level_update_disable(int8_t interface_id)
|
|
{
|
|
#ifdef HAVE_RPL
|
|
#ifdef HAVE_6LOWPAN_BORDER_ROUTER
|
|
protocol_interface_info_entry_t *interface_ptr = protocol_stack_interface_info_get_by_id(interface_id);
|
|
if (!interface_ptr) {
|
|
return -1;
|
|
}
|
|
|
|
return load_balance_network_load_monitor_disable(interface_ptr->lb_api);
|
|
#else
|
|
(void)interface_id;
|
|
return -1;
|
|
#endif
|
|
#else
|
|
(void)interface_id;
|
|
return -1;
|
|
#endif
|
|
}
|
|
|
|
int8_t net_load_balance_set_max_probability(int8_t interface_id, uint8_t max_p)
|
|
{
|
|
#ifdef HAVE_6LOWPAN_ND
|
|
protocol_interface_info_entry_t *interface_ptr = protocol_stack_interface_info_get_by_id(interface_id);
|
|
if (!interface_ptr) {
|
|
return -1;
|
|
}
|
|
|
|
return load_balance_set_max_probability(interface_ptr->lb_api, max_p);
|
|
#else
|
|
return -1;
|
|
#endif
|
|
}
|