mbed-os/features/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_bootstrap_6lbr.c

480 lines
20 KiB
C

/*
* Copyright (c) 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.
*/
#include <string.h>
#include "nsconfig.h"
#if defined(HAVE_WS) && defined(HAVE_WS_BORDER_ROUTER)
#include "ns_types.h"
#include "ns_trace.h"
#include "nsdynmemLIB.h"
#include "net_interface.h"
#include "eventOS_event.h"
#include "randLIB.h"
#include "common_functions.h"
#include "mac_common_defines.h"
#include "sw_mac.h"
#include "ccmLIB.h"
#include "Core/include/ns_monitor.h"
#include "NWK_INTERFACE/Include/protocol.h"
#include "6LoWPAN/Bootstraps/protocol_6lowpan.h"
#include "6LoWPAN/Bootstraps/protocol_6lowpan_interface.h"
#include "ipv6_stack/protocol_ipv6.h"
#include "ipv6_stack/ipv6_routing_table.h"
#include "6LoWPAN/MAC/mac_helper.h"
#include "6LoWPAN/MAC/mac_data_poll.h"
#include "6LoWPAN/MAC/mpx_api.h"
#include "6LoWPAN/MAC/mac_ie_lib.h"
#include "MPL/mpl.h"
#include "RPL/rpl_protocol.h"
#include "RPL/rpl_control.h"
#include "RPL/rpl_data.h"
#include "RPL/rpl_policy.h"
#include "Common_Protocols/icmpv6.h"
#include "Common_Protocols/icmpv6_radv.h"
#include "Common_Protocols/ipv6_constants.h"
#include "Common_Protocols/ip.h"
#include "Service_Libs/Trickle/trickle.h"
#include "Service_Libs/fhss/channel_list.h"
#include "Service_Libs/utils/ns_time.h"
#include "6LoWPAN/ws/ws_common_defines.h"
#include "6LoWPAN/ws/ws_common_defines.h"
#include "6LoWPAN/ws/ws_config.h"
#include "6LoWPAN/ws/ws_common.h"
#include "6LoWPAN/ws/ws_bootstrap.h"
#include "6LoWPAN/ws/ws_bbr_api_internal.h"
#include "6LoWPAN/ws/ws_common_defines.h"
#include "6LoWPAN/ws/ws_llc.h"
#include "6LoWPAN/ws/ws_neighbor_class.h"
#include "6LoWPAN/ws/ws_ie_lib.h"
#include "6LoWPAN/ws/ws_stats.h"
#include "6LoWPAN/ws/ws_cfg_settings.h"
#include "6LoWPAN/lowpan_adaptation_interface.h"
#include "Service_Libs/etx/etx.h"
#include "Service_Libs/mac_neighbor_table/mac_neighbor_table.h"
#include "Service_Libs/nd_proxy/nd_proxy.h"
#include "Service_Libs/blacklist/blacklist.h"
#include "platform/topo_trace.h"
#include "dhcp_service_api.h"
#include "libDHCPv6/libDHCPv6.h"
#include "libDHCPv6/libDHCPv6_vendordata.h"
#include "DHCPv6_client/dhcpv6_client_api.h"
#include "ws_management_api.h"
#include "net_rpl.h"
#include "mac_api.h"
#include "6LoWPAN/ws/ws_pae_controller.h"
#include "6LoWPAN/ws/ws_eapol_pdu.h"
#include "6LoWPAN/ws/ws_eapol_auth_relay.h"
#include "6LoWPAN/ws/ws_eapol_relay.h"
#include "libNET/src/net_dns_internal.h"
#include "Service_Libs/random_early_detection/random_early_detection_api.h"
#define TRACE_GROUP "wsbs"
static int8_t ws_bootstrap_6lbr_fhss_configure(protocol_interface_info_entry_t *cur)
{
// Read configuration of existing FHSS and start using the default values for any network
fhss_ws_configuration_t fhss_configuration = ws_common_get_current_fhss_configuration(cur);
//GET BSI from BBR module
fhss_configuration.bsi = ws_bbr_bsi_generate(cur);
ws_bootstrap_fhss_configure_channel_masks(cur, &fhss_configuration);
// Randomize fixed channels. Only used if channel plan is fixed.
cur->ws_info->cfg->fhss.fhss_uc_fixed_channel = ws_bootstrap_randomize_fixed_channel(cur->ws_info->cfg->fhss.fhss_uc_fixed_channel, cur->ws_info->hopping_schdule.number_of_channels, fhss_configuration.channel_mask);
cur->ws_info->cfg->fhss.fhss_bc_fixed_channel = ws_bootstrap_randomize_fixed_channel(cur->ws_info->cfg->fhss.fhss_bc_fixed_channel, cur->ws_info->hopping_schdule.number_of_channels, fhss_configuration.channel_mask);
ws_bootstrap_fhss_set_defaults(cur, &fhss_configuration);
ns_fhss_ws_configuration_set(cur->ws_info->fhss_api, &fhss_configuration);
ws_bootstrap_llc_hopping_update(cur, &fhss_configuration);
return 0;
}
static int8_t ws_bootstrap_6lbr_backbone_ip_addr_get(protocol_interface_info_entry_t *interface_ptr, uint8_t *address)
{
(void) interface_ptr;
(void) address;
if (ws_bbr_backbone_address_get(address)) {
return 0;
}
return -1;
}
static void ws_bootstrap_6lbr_eapol_congestion_init(protocol_interface_info_entry_t *cur)
{
random_early_detection_free(cur->llc_random_early_detection);
cur->llc_random_early_detection = NULL;
if (cur->llc_random_early_detection == NULL) {
cur->llc_random_early_detection = random_early_detection_create(
cur->ws_info->cfg->sec_prot.max_simult_sec_neg_tx_queue_min,
cur->ws_info->cfg->sec_prot.max_simult_sec_neg_tx_queue_max,
100, RED_AVERAGE_WEIGHT_EIGHTH);
}
random_early_detection_free(cur->llc_eapol_random_early_detection);
cur->llc_eapol_random_early_detection = NULL;
if (cur->llc_eapol_random_early_detection == NULL) {
cur->llc_eapol_random_early_detection = random_early_detection_create(
cur->ws_info->cfg->sec_prot.max_simult_sec_neg_tx_queue_min,
cur->ws_info->cfg->sec_prot.max_simult_sec_neg_tx_queue_max,
100, RED_AVERAGE_WEIGHT_EIGHTH);
}
}
static void ws_bootstrap_6lbr_pan_config_analyse(struct protocol_interface_info_entry *cur, const struct mcps_data_ind_s *data, const struct mcps_data_ie_list *ie_ext, ws_utt_ie_t *ws_utt, ws_us_ie_t *ws_us)
{
ws_bs_ie_t ws_bs_ie;
ws_bt_ie_t ws_bt_ie;
llc_neighbour_req_t neighbor_info;
if (data->SrcPANId != cur->ws_info->network_pan_id) {
return;
}
if (!ws_wh_bt_read(ie_ext->headerIeList, ie_ext->headerIeListLength, &ws_bt_ie)) {
tr_warn("BT-IE");
return;
}
if (!ws_wp_nested_bs_read(ie_ext->payloadIeList, ie_ext->payloadIeListLength, &ws_bs_ie)) {
// Corrupted
tr_error("No broadcast schedule");
return;
}
//If we are border router or learned configuration we only update already learned neighbours.
if (ws_bootstrap_neighbor_info_request(cur, data->SrcAddr, &neighbor_info, false)) {
//Update Neighbor Broadcast and Unicast Parameters
ws_neighbor_class_neighbor_unicast_time_info_update(neighbor_info.ws_neighbor, ws_utt, data->timestamp, (uint8_t *) data->SrcAddr);
ws_neighbor_class_neighbor_unicast_schedule_set(neighbor_info.ws_neighbor, ws_us, &cur->ws_info->hopping_schdule);
ws_neighbor_class_neighbor_broadcast_time_info_update(neighbor_info.ws_neighbor, &ws_bt_ie, data->timestamp);
ws_neighbor_class_neighbor_broadcast_schedule_set(neighbor_info.ws_neighbor, &ws_bs_ie);
}
}
static void ws_bootstrap_6lbr_pan_config_solicit_analyse(struct protocol_interface_info_entry *cur, const struct mcps_data_ind_s *data, ws_utt_ie_t *ws_utt, ws_us_ie_t *ws_us)
{
llc_neighbour_req_t neighbor_info;
if (data->SrcPANId != cur->ws_info->network_pan_id) {
return;
}
if (ws_bootstrap_neighbor_info_request(cur, data->SrcAddr, &neighbor_info, false)) {
ws_neighbor_class_neighbor_unicast_time_info_update(neighbor_info.ws_neighbor, ws_utt, data->timestamp, (uint8_t *) data->SrcAddr);
ws_neighbor_class_neighbor_unicast_schedule_set(neighbor_info.ws_neighbor, ws_us, &cur->ws_info->hopping_schdule);
}
}
void ws_bootstrap_6lbr_asynch_ind(struct protocol_interface_info_entry *cur, const struct mcps_data_ind_s *data, const struct mcps_data_ie_list *ie_ext, uint8_t message_type)
{
// Store weakest heard packet RSSI
if (cur->ws_info->weakest_received_rssi > data->signal_dbm) {
cur->ws_info->weakest_received_rssi = data->signal_dbm;
}
if (data->SrcAddrMode != MAC_ADDR_MODE_64_BIT) {
// Not from long address
return;
}
ws_stats_update(cur, STATS_WS_ASYNCH_RX, 1);
//Validate network name
switch (message_type) {
case WS_FT_PAN_ADVERT:
case WS_FT_PAN_ADVERT_SOL:
case WS_FT_PAN_CONF_SOL:
//Check Network Name
if (!ws_bootstrap_network_name_matches(ie_ext, cur->ws_info->cfg->gen.network_name)) {
// Not in our network
return;
}
break;
case WS_FT_PAN_CONF:
break;
default:
return;
}
//UTT-IE and US-IE are mandatory for all Asynch Messages
ws_utt_ie_t ws_utt;
if (!ws_wh_utt_read(ie_ext->headerIeList, ie_ext->headerIeListLength, &ws_utt)) {
// Corrupted
return;
}
ws_us_ie_t ws_us;
if (!ws_wp_nested_us_read(ie_ext->payloadIeList, ie_ext->payloadIeListLength, &ws_us)) {
// Corrupted
return;
}
if (!ws_bootstrap_validate_channel_plan(&ws_us, cur) ||
!ws_bootstrap_validate_channel_function(&ws_us, NULL)) {
return;
}
//Handle Message's
switch (message_type) {
case WS_FT_PAN_ADVERT:
// Analyse Advertisement
ws_stats_update(cur, STATS_WS_ASYNCH_RX_PA, 1);
tr_info("received ADVERT Src:%s panid:%x rssi:%d", trace_array(data->SrcAddr, 8), data->SrcPANId, data->signal_dbm);
// Border routers do not do any analysing on the Advertisements heard from others
// in future if we need PANID conflict detection we could use this
break;
case WS_FT_PAN_ADVERT_SOL:
ws_stats_update(cur, STATS_WS_ASYNCH_RX_PAS, 1);
tr_info("received ADVERT SOL Src:%s rssi:%d", trace_array(data->SrcAddr, 8), data->signal_dbm);
trickle_inconsistent_heard(&cur->ws_info->trickle_pan_advertisement, &cur->ws_info->trickle_params_pan_discovery);
break;
case WS_FT_PAN_CONF:
ws_stats_update(cur, STATS_WS_ASYNCH_RX_PC, 1);
tr_info("received CONFIG Src:%s rssi:%d", trace_array(data->SrcAddr, 8), data->signal_dbm);
ws_bootstrap_6lbr_pan_config_analyse(cur, data, ie_ext, &ws_utt, &ws_us);
break;
case WS_FT_PAN_CONF_SOL:
ws_stats_update(cur, STATS_WS_ASYNCH_RX_PCS, 1);
tr_info("received CONFIG SOL Src:%s rssi:%d", trace_array(data->SrcAddr, 8), data->signal_dbm);
trickle_inconsistent_heard(&cur->ws_info->trickle_pan_config, &cur->ws_info->trickle_params_pan_discovery);
ws_bootstrap_6lbr_pan_config_solicit_analyse(cur, data, &ws_utt, &ws_us);
default:
// Unknown message do not process
break;
}
}
void ws_bootstrap_6lbr_asynch_confirm(struct protocol_interface_info_entry *interface, uint8_t asynch_message)
{
ws_stats_update(interface, STATS_WS_ASYNCH_TX, 1);
if (interface->bootsrap_mode == ARM_NWK_BOOTSRAP_MODE_6LoWPAN_BORDER_ROUTER) {
if (asynch_message == WS_FT_PAN_CONF && interface->ws_info->pending_key_index_info.state == PENDING_KEY_INDEX_ACTIVATE) {
interface->ws_info->pending_key_index_info.state = NO_PENDING_PROCESS;
tr_info("Activate new default key %u", interface->ws_info->pending_key_index_info.index + 1);
mac_helper_security_auto_request_key_index_set(interface, interface->ws_info->pending_key_index_info.index, interface->ws_info->pending_key_index_info.index + 1);
}
}
}
void ws_bootstrap_6lbr_event_handler(protocol_interface_info_entry_t *cur, arm_event_s *event)
{
ws_bootsrap_event_type_e event_type;
event_type = (ws_bootsrap_event_type_e)event->event_type;
switch (event_type) {
case WS_INIT_EVENT:
tr_debug("tasklet init");
break;
case WS_DISCOVERY_START:
tr_info("Discovery start");
protocol_mac_reset(cur);
ws_llc_reset(cur);
lowpan_adaptation_interface_reset(cur->id);
//Clear Pending Key Index State
cur->ws_info->pending_key_index_info.state = NO_PENDING_PROCESS;
cur->mac_parameters->mac_default_key_index = 0;
ipv6_destination_cache_clean(cur->id);
// Clear parent blacklist
blacklist_clear();
// All trickle timers stopped to allow entry from any state
ws_bootstrap_asynch_trickle_stop(cur);
//Init Packet congestion
ws_bootstrap_packet_congestion_init(cur);
tr_info("Border router start network");
if (!ws_bbr_ready_to_start(cur)) {
// Wi-SUN not started yet we wait for Border router permission
ws_bootstrap_state_change(cur, ER_WAIT_RESTART);
cur->nwk_nd_re_scan_count = randLIB_get_random_in_range(40, 100);
return;
}
// Clear Old information from stack
cur->ws_info->network_pan_id = 0xffff;
cur->ws_info->pan_information.pan_version_set = false;
ws_nud_table_reset(cur);
ws_bootstrap_neighbor_list_clean(cur);
ws_bootstrap_ip_stack_reset(cur);
ws_pae_controller_auth_init(cur);
uint16_t pan_id = ws_bbr_pan_id_get(cur);
if (pan_id != 0xffff) {
cur->ws_info->network_pan_id = pan_id;
} else {
if (cur->ws_info->network_pan_id == 0xffff) {
cur->ws_info->network_pan_id = randLIB_get_random_in_range(0, 0xfffd);
}
}
if (!cur->ws_info->pan_information.pan_version_set) {
cur->ws_info->pan_information.pan_version = randLIB_get_random_in_range(0, 0xffff);
cur->ws_info->pan_information.pan_version_set = true;
}
cur->ws_info->pan_information.pan_size = 0;
cur->ws_info->pan_information.routing_cost = 0;
cur->ws_info->pan_information.rpl_routing_method = true;
cur->ws_info->pan_information.use_parent_bs = true;
cur->ws_info->pan_information.version = WS_FAN_VERSION_1_0;
// initialize for FAN 1.1 defaults
if (ws_version_1_1(cur)) {
cur->ws_info->pan_information.version = WS_FAN_VERSION_1_1;
#ifdef HAVE_WS_VERSION_1_1
if (!cur->ws_info->lfngtk.lfn_version_learned) {
//Randomize LFN version
cur->ws_info->lfngtk.lfn_version = randLIB_get_random_in_range(0, 0xffff);
cur->ws_info->lfngtk.lfn_version_learned = true;
}
#endif
}
uint8_t *gtkhash = ws_pae_controller_gtk_hash_ptr_get(cur);
ws_llc_set_gtkhash(cur, gtkhash);
ws_bbr_pan_version_increase(cur);
// Set default parameters for FHSS when starting a discovery
ws_common_regulatory_domain_config(cur, &cur->ws_info->hopping_schdule);
ws_bootstrap_6lbr_fhss_configure(cur);
ws_bootstrap_set_domain_rf_config(cur);
ws_bootstrap_fhss_activate(cur);
ns_fhss_ws_set_hop_count(cur->ws_info->fhss_api, 0);
uint8_t ll_addr[16];
addr_interface_get_ll_address(cur, ll_addr, 1);
//SET EAPOL authenticator EUI64
ws_pae_controller_border_router_addr_write(cur, cur->mac);
// Set EAPOL relay to port 10255 and authenticator relay to 10253 (and to own ll address)
ws_eapol_relay_start(cur, BR_EAPOL_RELAY_SOCKET_PORT, ll_addr, EAPOL_RELAY_SOCKET_PORT);
// Set authenticator relay to port 10253 and PAE to 10254 (and to own ll address)
ws_eapol_auth_relay_start(cur, EAPOL_RELAY_SOCKET_PORT, ll_addr, PAE_AUTH_SOCKET_PORT);
// Set PAN ID and network name to controller
ws_pae_controller_nw_info_set(cur, cur->ws_info->network_pan_id, cur->ws_info->pan_information.pan_version, cur->ws_info->cfg->gen.network_name);
// Set backbone IP address get callback
ws_pae_controller_auth_cb_register(cur, ws_bootstrap_6lbr_backbone_ip_addr_get);
// Set PAE port to 10254 and authenticator relay to 10253 (and to own ll address)
ws_pae_controller_authenticator_start(cur, PAE_AUTH_SOCKET_PORT, ll_addr, EAPOL_RELAY_SOCKET_PORT);
// Initialize eapol congestion tracking
ws_bootstrap_6lbr_eapol_congestion_init(cur);
// Set retry configuration for bootstrap ready state
ws_bootstrap_configure_max_retries(cur, WS_MAX_FRAME_RETRIES);
// Set TX failure request restart configuration
ws_bootstrap_configure_data_request_restart(cur, WS_CCA_REQUEST_RESTART_MAX, WS_TX_REQUEST_RESTART_MAX, WS_REQUEST_RESTART_BLACKLIST_MIN, WS_REQUEST_RESTART_BLACKLIST_MAX);
// Set CSMA-CA backoff configuration
ws_bootstrap_configure_csma_ca_backoffs(cur, WS_MAX_CSMA_BACKOFFS, WS_MAC_MIN_BE, WS_MAC_MAX_BE);
ws_bootstrap_event_operation_start(cur);
break;
case WS_CONFIGURATION_START:
tr_info("6LBR Configuration start");
break;
case WS_OPERATION_START:
tr_info("operation start");
// Advertisements stopped during the RPL scan
ws_bootstrap_asynch_trickle_stop(cur);
// Activate RPL
// Activate IPv6 stack
ws_bootstrap_ip_stack_activate(cur);
ws_bootstrap_rpl_activate(cur);
ws_bootstrap_network_start(cur);
// Wait for RPL start
ws_bootstrap_event_routing_ready(cur);
break;
case WS_ROUTING_READY:
tr_info("Routing ready");
// stopped all to make sure we can enter here from any state
ws_bootstrap_asynch_trickle_stop(cur);
// Indicate PAE controller that bootstrap is ready
ws_pae_controller_bootstrap_done(cur);
ws_bootstrap_advertise_start(cur);
ws_bootstrap_state_change(cur, ER_BOOTSRAP_DONE);
break;
case WS_FAST_DISCONNECT:
ws_bootstrap_state_disconnect(cur, WS_FAST_DISCONNECT);
break;
case WS_NORMAL_DISCONNECT:
ws_bootstrap_state_disconnect(cur, WS_NORMAL_DISCONNECT);
break;
case WS_TEST_PROC_TRIGGER:
ws_bootstrap_test_procedure_trigger_exec(cur, (ws_bootsrap_procedure_t) event->data_ptr);
break;
default:
tr_err("Invalid event received");
break;
}
}
void ws_bootstrap_6lbr_state_machine(protocol_interface_info_entry_t *cur)
{
switch (cur->nwk_bootstrap_state) {
case ER_WAIT_RESTART:
tr_debug("WS SM:Wait for startup");
ws_bootstrap_event_discovery_start(cur);
break;
case ER_ACTIVE_SCAN:
tr_debug("WS SM:Active Scan");
break;
case ER_SCAN:
tr_debug("WS SM:configuration Scan");
break;
case ER_PANA_AUTH:
tr_info("authentication start");
break;
case ER_RPL_SCAN:
tr_debug("WS SM:Wait RPL to contact DODAG root");
break;
case ER_BOOTSRAP_DONE:
tr_info("WS SM:Bootstrap Done");
// Bootstrap_done event to application
nwk_bootsrap_state_update(ARM_NWK_BOOTSTRAP_READY, cur);
break;
case ER_RPL_NETWORK_LEAVING:
tr_debug("WS SM:RPL Leaving ready trigger discovery");
ws_bootstrap_event_discovery_start(cur);
break;
default:
tr_warn("WS SM:Invalid state %d", cur->nwk_bootstrap_state);
}
}
void ws_bootstrap_6lbr_seconds_timer(protocol_interface_info_entry_t *cur, uint32_t seconds)
{
(void)cur;
(void)seconds;
}
#endif //HAVE_WS_BORDER_ROUTER && HAVE_WS