diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000000..2cab979e90 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,33 @@ +# Copyright (c) 2020-2021, Pelion and affiliates. +# SPDX-License-Identifier: Apache-2.0 + +add_subdirectory(source/6LoWPAN) +add_subdirectory(source/BorderRouter) +add_subdirectory(source/Common_Protocols) +add_subdirectory(source/Core) +add_subdirectory(source/DHCPv6_Server) +add_subdirectory(source/DHCPv6_client) +add_subdirectory(source/MAC) +add_subdirectory(source/MLE) +add_subdirectory(source/MPL) +add_subdirectory(source/NWK_INTERFACE) +add_subdirectory(source/RPL) +add_subdirectory(source/Security) +add_subdirectory(source/Service_Libs) +add_subdirectory(source/configs) +add_subdirectory(source/ipv6_stack) +add_subdirectory(source/libDHCPv6) +add_subdirectory(source/libNET) + +target_include_directories(mbed-nanostack-sal_stack + INTERFACE + . + ./nanostack + ./nanostack/platform + ./source +) + +target_link_libraries(mbed-nanostack + INTERFACE + mbed-nanostack-coap_service +) diff --git a/nanostack/net_interface.h b/nanostack/net_interface.h index eb87675af5..6be75ae8fe 100644 --- a/nanostack/net_interface.h +++ b/nanostack/net_interface.h @@ -99,6 +99,8 @@ typedef enum arm_library_event_type_e { #define SOCKET_NO_RAM (10 << 4) /** TCP connection problem indication (RFC 1122 R1) */ #define SOCKET_CONNECTION_PROBLEM (11 << 4) +/** Socket is busy or Radio is returning CCA failure */ +#define SOCKET_BUSY (12 << 4) #define SOCKET_BIND_DONE SOCKET_CONNECT_DONE /**< Backward compatibility */ #define SOCKET_BIND_FAIL SOCKET_CONNECT_FAIL /**< Backward compatibility */ diff --git a/nanostack/socket_api.h b/nanostack/socket_api.h index 7cf8b57748..fe19acd75e 100644 --- a/nanostack/socket_api.h +++ b/nanostack/socket_api.h @@ -115,6 +115,7 @@ extern "C" { * | | | TCP: some data acknowledged (d_len = data remaining in send queue) | * | SOCKET_NO_RAM | 0xA0 | No RAM available. | * | SOCKET_CONNECTION_PROBLEM | 0xB0 | TCP connection is retrying. | + * | SOCKET_BUSY | 0xC0 | Socket is busy or Radio channel is returning CCA failure. | * * * \section socket-tcp How to use TCP sockets: diff --git a/nanostack/ws_bbr_api.h b/nanostack/ws_bbr_api.h index 00e8623c65..2450de8546 100644 --- a/nanostack/ws_bbr_api.h +++ b/nanostack/ws_bbr_api.h @@ -88,6 +88,22 @@ typedef struct bbr_timezone_configuration { * "bit xxxxxxxxxxxxxxxS" 0 = false 1 = true Daylight saving time status*/ uint16_t status; } bbr_timezone_configuration_t; + + +/** + * \brief Border router configuration. + */ +typedef struct bbr_configuration_s { + uint32_t dhcp_address_lifetime; /**< DHCP address lifetime in seconds minimum 2 hours and maximum few days*/ + uint32_t rpl_default_lifetime; /**< RPL default lifetime value from 30 minutes to 16 hours*/ + uint16_t dag_max_rank_increase; /**< DIO Max rank increase. Range 0-2048 */ + uint16_t min_hop_rank_increase; /**< DIO Min hop rank increase. range 32-256 */ + uint16_t options; /**< Border router configuration options */ + uint8_t dio_interval_min; /**< DIO interval min. range 1-255 */ + uint8_t dio_interval_doublings; /**< DIO interval doublings. range 1-8 */ + uint8_t dio_redundancy_constant; /**< DIO redundancy constant. Range 0-10 */ +} bbr_configuration_t; + /** * Start backbone border router service. * @@ -270,7 +286,52 @@ int ws_bbr_eapol_node_limit_set(int8_t interface_id, uint16_t limit); int ws_bbr_ext_certificate_validation_set(int8_t interface_id, uint8_t validation); /** - * Sets RPL parameters + * Sets Border router configuration + * + * Sets the configuration to the border router. Use ws_configuration_get to get + * the settings and modify wanted parameters. + * + * Minor validation is done to parameters, but full validation must be done + * at application level + * + * \param interface_id Network interface ID. + * \param configuration_ptr Configuration structure. + * + * \return 0, Configuration parameters set. + * \return <0 Parameter set failed. + */ +int ws_bbr_configuration_set(int8_t interface_id, bbr_configuration_t *configuration_ptr); + +/** + * Get Border router configuration + * + * Gets the current configuration to the border router. + * + * \param interface_id Network interface ID. + * \param configuration_ptr Configuration structure. + * + * \return 0, Configuration parameters set. + * \return <0 Parameter set failed. + */ +int ws_bbr_configuration_get(int8_t interface_id, bbr_configuration_t *configuration_ptr); + +/** + * validate Border router configuration + * + * Minor validation is done to parameters. + * Full validation must be done at application level. + * + * \param interface_id Network interface ID. + * \param configuration_ptr Configuration structure. + * + * \return 0, Configuration parameters set. + * \return <0 Parameter set failed. + */ +int ws_bbr_configuration_validate(int8_t interface_id, bbr_configuration_t *configuration_ptr); + +/** + * Sets RPL parameters (DEPRECATED) + * Use ws_bbr_configuration_set instead. * * Sets RPL DIO trickle parameters. * @@ -285,7 +346,8 @@ int ws_bbr_ext_certificate_validation_set(int8_t interface_id, uint8_t validatio int ws_bbr_rpl_parameters_set(int8_t interface_id, uint8_t dio_interval_min, uint8_t dio_interval_doublings, uint8_t dio_redundancy_constant); /** - * Gets RPL parameters + * Gets RPL parameters (DEPRECATED) + * Use ws_bbr_configuration_get instead. * * Gets RPL DIO trickle parameters. * @@ -300,7 +362,8 @@ int ws_bbr_rpl_parameters_set(int8_t interface_id, uint8_t dio_interval_min, uin int ws_bbr_rpl_parameters_get(int8_t interface_id, uint8_t *dio_interval_min, uint8_t *dio_interval_doublings, uint8_t *dio_redundancy_constant); /** - * Validate RPL parameters + * Validate RPL parameters (DEPRECATED) + * Use ws_bbr_configuration_validate instead. * * Validates RPL DIO trickle parameters. * diff --git a/source/6LoWPAN/CMakeLists.txt b/source/6LoWPAN/CMakeLists.txt new file mode 100644 index 0000000000..ef3b50ce2c --- /dev/null +++ b/source/6LoWPAN/CMakeLists.txt @@ -0,0 +1,114 @@ +# Copyright (c) 2020-2021, Pelion and affiliates. +# SPDX-License-Identifier: Apache-2.0 + +target_include_directories(mbed-nanostack-sal_stack + INTERFACE + . + ./Bootstraps + ./Fragmentation + ./IPHC_Decode + ./MAC + ./Mesh + ./ND + ./NVM + ./Thread + ./ws +) + +target_sources(mbed-nanostack-sal_stack + INTERFACE + adaptation_interface.c + + Bootstraps/Generic/network_lib.c + Bootstraps/Generic/protocol_6lowpan.c + Bootstraps/Generic/protocol_6lowpan_bootstrap.c + Bootstraps/Generic/protocol_6lowpan_interface.c + + Fragmentation/cipv6_fragmenter.c + + IPHC_Decode/6lowpan_iphc.c + IPHC_Decode/iphc_compress.c + IPHC_Decode/iphc_decompress.c + IPHC_Decode/lowpan_context.c + + MAC/beacon_handler.c + MAC/mac_data_poll.c + MAC/mac_helper.c + MAC/mac_ie_lib.c + MAC/mac_pairwise_key.c + MAC/mac_response_handler.c + + Mesh/mesh.c + + ND/nd_router_object.c + + NVM/nwk_nvm.c + + Thread/thread_bbr_api.c + Thread/thread_bbr_commercial.c + Thread/thread_beacon.c + Thread/thread_bootstrap.c + Thread/thread_border_router_api.c + Thread/thread_ccm.c + Thread/thread_commissioning_api.c + Thread/thread_commissioning_if.c + Thread/thread_common.c + Thread/thread_dhcpv6_server.c + Thread/thread_diagnostic.c + Thread/thread_discovery.c + Thread/thread_host_bootstrap.c + Thread/thread_joiner_application.c + Thread/thread_leader_service.c + Thread/thread_lowpower_api.c + Thread/thread_lowpower_private_api.c + Thread/thread_management_api.c + Thread/thread_management_client.c + Thread/thread_management_if.c + Thread/thread_management_server.c + Thread/thread_mdns.c + Thread/thread_meshcop_lib.c + Thread/thread_mle_message_handler.c + Thread/thread_nd.c + Thread/thread_neighbor_class.c + Thread/thread_net_config_api.c + Thread/thread_network_data_lib.c + Thread/thread_network_data_storage.c + Thread/thread_network_synch.c + Thread/thread_nvm_store.c + Thread/thread_resolution_client.c + Thread/thread_resolution_server.c + Thread/thread_router_bootstrap.c + Thread/thread_routing.c + Thread/thread_test_api.c + + ws/ws_bbr_api.c + ws/ws_bootstrap.c + ws/ws_bootstrap_6lbr.c + ws/ws_bootstrap_6ln.c + ws/ws_bootstrap_6lr.c + ws/ws_bootstrap_ffn.c + ws/ws_cfg_settings.c + ws/ws_common.c + ws/ws_eapol_auth_relay.c + ws/ws_eapol_pdu.c + ws/ws_eapol_relay.c + ws/ws_eapol_relay_lib.c + ws/ws_empty_functions.c + ws/ws_ie_lib.c + ws/ws_llc_data_service.c + ws/ws_management_api.c + ws/ws_mpx_header.c + ws/ws_neighbor_class.c + ws/ws_pae_auth.c + ws/ws_pae_controller.c + ws/ws_pae_key_storage.c + ws/ws_pae_lib.c + ws/ws_pae_nvm_data.c + ws/ws_pae_nvm_store.c + ws/ws_pae_supp.c + ws/ws_pae_time.c + ws/ws_pae_timers.c + ws/ws_phy.c + ws/ws_stats.c + ws/ws_test_api.c +) diff --git a/source/6LoWPAN/ND/nd_router_object.c b/source/6LoWPAN/ND/nd_router_object.c index 40aa092de5..380a2413b1 100644 --- a/source/6LoWPAN/ND/nd_router_object.c +++ b/source/6LoWPAN/ND/nd_router_object.c @@ -849,6 +849,7 @@ static void nd_update_registration(protocol_interface_info_entry_t *cur_interfac /* Register with 2 seconds off the lifetime - don't want the NCE to expire before the route */ ipv6_route_add_metric(neigh->ip_address, 128, cur_interface->id, neigh->ip_address, ROUTE_ARO, NULL, 0, neigh->lifetime - 2, 32); +#ifdef HAVE_RPL /* We need to know peer is a host before publishing - this needs MLE. Not yet established * what to do without MLE - might need special external/non-external prioritisation at root. * This "publish for RFD" rule comes from ZigBee IP. @@ -861,6 +862,7 @@ static void nd_update_registration(protocol_interface_info_entry_t *cur_interfac rpl_control_publish_host_address(protocol_6lowpan_rpl_domain, neigh->ip_address, neigh->lifetime); } } +#endif // HAVE_RPL protocol_6lowpan_neighbor_address_state_synch(cur_interface, aro->eui64, neigh->ip_address + 8); } else { @@ -870,10 +872,13 @@ static void nd_update_registration(protocol_interface_info_entry_t *cur_interfac neigh->lifetime = 2; ipv6_neighbour_set_state(&cur_interface->ipv6_neighbour_cache, neigh, IP_NEIGHBOUR_STALE); ipv6_route_add_metric(neigh->ip_address, 128, cur_interface->id, neigh->ip_address, ROUTE_ARO, NULL, 0, 4, 32); +#ifdef HAVE_RPL rpl_control_unpublish_address(protocol_6lowpan_rpl_domain, neigh->ip_address); +#endif } } +#ifdef HAVE_RPL void nd_remove_registration(protocol_interface_info_entry_t *cur_interface, addrtype_t ll_type, const uint8_t *ll_address) { ns_list_foreach_safe(ipv6_neighbour_t, cur, &cur_interface->ipv6_neighbour_cache.list) { @@ -888,7 +893,9 @@ void nd_remove_registration(protocol_interface_info_entry_t *cur_interface, addr } } } +#endif // HAVE_RPL +#ifdef HAVE_RPL /* Process ICMP Neighbor Solicitation (RFC 4861 + RFC 6775) ARO. */ bool nd_ns_aro_handler(protocol_interface_info_entry_t *cur_interface, const uint8_t *aro_opt, const uint8_t *slla_opt, const uint8_t *src_addr, aro_t *aro_out) { @@ -1032,6 +1039,7 @@ RESPONSE: return false; /* Tell ns_handler to not transmit now */ } } +#endif //HAVE_RPL buffer_t *nd_dac_handler(buffer_t *buf, protocol_interface_info_entry_t *cur) { @@ -1304,6 +1312,7 @@ void nd_ra_process_lowpan_context_option(protocol_interface_info_entry_t *cur, c lowpan_context_update(&cur->lowpan_contexts, cid_flags, lifetime, opt + 8, ctx_len, true); } #ifdef HAVE_6LOWPAN_ROUTER +#ifdef HAVE_RPL static void nd_ra_build(nd_router_t *cur, const uint8_t *address, protocol_interface_info_entry_t *cur_interface) { if (!(cur_interface->lowpan_info & INTERFACE_NWK_BOOTSRAP_ADDRESS_REGISTER_READY) || !icmp_nd_router_prefix_valid(cur)) { @@ -1393,7 +1402,6 @@ void nd_ra_build_by_abro(const uint8_t *abro, const uint8_t *dest, protocol_inte } } - void nd_trigger_ras_from_rs(const uint8_t *unicast_adr, protocol_interface_info_entry_t *cur_interface) { ns_list_foreach(nd_router_t, cur, &nd_router_list) { @@ -1470,7 +1478,7 @@ static nd_router_t *nd_router_object_scan_by_prefix(const uint8_t *ptr, nwk_inte return NULL; } - +#endif //HAVE_RPL #endif void gp_address_add_to_end(gp_ipv6_address_list_t *list, const uint8_t address[static 16]) diff --git a/source/6LoWPAN/adaptation_interface.c b/source/6LoWPAN/adaptation_interface.c index 6e0b296b1b..55904778f0 100644 --- a/source/6LoWPAN/adaptation_interface.c +++ b/source/6LoWPAN/adaptation_interface.c @@ -1747,6 +1747,9 @@ static uint8_t map_mlme_status_to_socket_event(uint8_t mlme_status) case MLME_SUCCESS: socket_event = SOCKET_TX_DONE; break; + case MLME_BUSY_CHAN: + socket_event = SOCKET_BUSY; + break; case MLME_TX_NO_ACK: case MLME_SECURITY_FAIL: case MLME_TRANSACTION_EXPIRED: diff --git a/source/6LoWPAN/ws/ws_bbr_api.c b/source/6LoWPAN/ws/ws_bbr_api.c index 0e9fe10b8b..db4bf5e2de 100644 --- a/source/6LoWPAN/ws/ws_bbr_api.c +++ b/source/6LoWPAN/ws/ws_bbr_api.c @@ -31,6 +31,7 @@ #include "6LoWPAN/ws/ws_config.h" #include "6LoWPAN/ws/ws_common.h" #include "6LoWPAN/ws/ws_bootstrap.h" +#include "6LoWPAN/ws/ws_bootstrap_ffn.h" #include "6LoWPAN/ws/ws_cfg_settings.h" #include "6LoWPAN/ws/ws_pae_key_storage.h" #include "6LoWPAN/ws/ws_pae_nvm_store.h" @@ -1209,6 +1210,94 @@ int ws_bbr_ext_certificate_validation_set(int8_t interface_id, uint8_t validatio return -1; #endif } +int ws_bbr_configuration_set(int8_t interface_id, bbr_configuration_t *configuration_ptr) +{ +#ifdef HAVE_WS_BORDER_ROUTER + protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(interface_id); + + ws_bbr_cfg_t cfg; + if (!configuration_ptr || ws_cfg_bbr_get(&cfg) < 0) { + return -1; + } + + cfg.dio_interval_min = configuration_ptr->dio_interval_min; + cfg.dio_interval_doublings = configuration_ptr->dio_interval_doublings; + cfg.dio_redundancy_constant = configuration_ptr->dio_redundancy_constant; + cfg.dag_max_rank_increase = configuration_ptr->dag_max_rank_increase; + cfg.min_hop_rank_increase = configuration_ptr->min_hop_rank_increase; + cfg.dhcp_address_lifetime = configuration_ptr->dhcp_address_lifetime; + cfg.rpl_default_lifetime = configuration_ptr->rpl_default_lifetime; + + /* Configuration change is different from settings change as it changes + * PAN version instead of RPL version. + */ + ws_bbr_configure(interface_id, configuration_ptr->options); + + if (ws_cfg_bbr_set(cur, &cfg, 0) < 0) { + return -2; + } + + return 0; +#else + (void) interface_id; + (void) configuration_ptr; + return -1; +#endif +} + +int ws_bbr_configuration_get(int8_t interface_id, bbr_configuration_t *configuration_ptr) +{ +#ifdef HAVE_WS_BORDER_ROUTER + (void) interface_id; + ws_bbr_cfg_t cfg; + if (!configuration_ptr || ws_cfg_bbr_get(&cfg) < 0) { + return -1; + } + + configuration_ptr->dio_interval_min = cfg.dio_interval_min; + configuration_ptr->dio_interval_doublings = cfg.dio_interval_doublings; + configuration_ptr->dio_redundancy_constant = cfg.dio_redundancy_constant; + configuration_ptr->dag_max_rank_increase = cfg.dag_max_rank_increase; + configuration_ptr->min_hop_rank_increase = cfg.min_hop_rank_increase; + configuration_ptr->dhcp_address_lifetime = cfg.dhcp_address_lifetime; + configuration_ptr->rpl_default_lifetime = cfg.rpl_default_lifetime; + configuration_ptr->options = configuration; + return 0; +#else + (void) interface_id; + (void) configuration_ptr; + return -1; +#endif +} + +int ws_bbr_configuration_validate(int8_t interface_id, bbr_configuration_t *configuration_ptr) +{ +#ifdef HAVE_WS_BORDER_ROUTER + (void) interface_id; + ws_bbr_cfg_t cfg; + if (!configuration_ptr || ws_cfg_bbr_get(&cfg) < 0) { + return -1; + } + + cfg.dio_interval_min = configuration_ptr->dio_interval_min; + cfg.dio_interval_doublings = configuration_ptr->dio_interval_doublings; + cfg.dio_redundancy_constant = configuration_ptr->dio_redundancy_constant; + cfg.dag_max_rank_increase = configuration_ptr->dag_max_rank_increase; + cfg.min_hop_rank_increase = configuration_ptr->min_hop_rank_increase; + cfg.dhcp_address_lifetime = configuration_ptr->dhcp_address_lifetime; + cfg.rpl_default_lifetime = configuration_ptr->rpl_default_lifetime; + + if (ws_cfg_bbr_validate(&cfg) < 0) { + return -3; + } + + return 0; +#else + (void) interface_id; + (void) configuration_ptr; + return -1; +#endif +} int ws_bbr_rpl_parameters_set(int8_t interface_id, uint8_t dio_interval_min, uint8_t dio_interval_doublings, uint8_t dio_redundancy_constant) { diff --git a/source/6LoWPAN/ws/ws_bootstrap.c b/source/6LoWPAN/ws/ws_bootstrap.c index 253ec1d228..73473fe588 100644 --- a/source/6LoWPAN/ws/ws_bootstrap.c +++ b/source/6LoWPAN/ws/ws_bootstrap.c @@ -63,8 +63,9 @@ #include "6LoWPAN/ws/ws_stats.h" #include "6LoWPAN/ws/ws_cfg_settings.h" #include "6LoWPAN/ws/ws_bootstrap_6lbr.h" +#include "6LoWPAN/ws/ws_bootstrap_6lr.h" #include "6LoWPAN/ws/ws_bootstrap_ffn.h" -#include "6LoWPAN/ws/ws_bootstrap_lfn.h" +#include "6LoWPAN/ws/ws_bootstrap_6ln.h" #include "6LoWPAN/ws/ws_phy.h" #include "6LoWPAN/lowpan_adaptation_interface.h" #include "Service_Libs/etx/etx.h" @@ -91,24 +92,17 @@ static void ws_bootstrap_event_handler(arm_event_s *event); static int8_t ws_bootsrap_event_trig(ws_bootsrap_event_type_e event_type, int8_t interface_id, arm_library_event_priority_e priority, void *event_data); static uint16_t ws_bootstrap_routing_cost_calculate(protocol_interface_info_entry_t *cur); -static uint16_t ws_bootstrap_rank_get(protocol_interface_info_entry_t *cur); -static uint16_t ws_bootstrap_min_rank_inc_get(protocol_interface_info_entry_t *cur); static void ws_bootstrap_mac_security_enable(protocol_interface_info_entry_t *cur); static void ws_bootstrap_nw_key_set(protocol_interface_info_entry_t *cur, uint8_t operation, uint8_t index, uint8_t *key); static void ws_bootstrap_nw_key_clear(protocol_interface_info_entry_t *cur, uint8_t slot); static void ws_bootstrap_nw_key_index_set(protocol_interface_info_entry_t *cur, uint8_t index); static void ws_bootstrap_nw_frame_counter_set(protocol_interface_info_entry_t *cur, uint32_t counter, uint8_t slot); static void ws_bootstrap_nw_frame_counter_read(protocol_interface_info_entry_t *cur, uint32_t *counter, uint8_t slot); -static void ws_bootstrap_nw_info_updated(protocol_interface_info_entry_t *interface_ptr, uint16_t pan_id, uint16_t pan_version, char *network_name); static void ws_bootstrap_authentication_completed(protocol_interface_info_entry_t *cur, auth_result_e result, uint8_t *target_eui_64); static const uint8_t *ws_bootstrap_authentication_next_target(protocol_interface_info_entry_t *cur, const uint8_t *previous_eui_64, uint16_t *pan_id); -static bool ws_bootstrap_eapol_congestion_get(protocol_interface_info_entry_t *interface_ptr, uint16_t active_supp); -static void ws_bootstrap_pan_version_increment(protocol_interface_info_entry_t *cur); static ws_nud_table_entry_t *ws_nud_entry_discover(protocol_interface_info_entry_t *cur, void *neighbor); static void ws_nud_entry_remove(protocol_interface_info_entry_t *cur, mac_neighbor_table_entry_t *entry_ptr); static bool ws_neighbor_entry_nud_notify(mac_neighbor_table_entry_t *entry_ptr, void *user_data); -static void ws_bootstrap_dhcp_neighbour_update_cb(int8_t interface_id, uint8_t ll_addr[static 16]); -static void ws_bootstrap_dhcp_info_notify_cb(int8_t interface, dhcp_option_notify_t *options, dhcp_server_notify_info_t *server_info); static void ws_bootstrap_test_procedure_trigger_timer(protocol_interface_info_entry_t *cur, uint32_t seconds); uint16_t test_pan_version = 1; @@ -175,7 +169,7 @@ void ws_bootstrap_neighbor_list_clean(struct protocol_interface_info_entry *inte mac_neighbor_table_neighbor_list_clean(mac_neighbor_info(interface)); } -static void ws_address_reregister_trig(struct protocol_interface_info_entry *interface) +void ws_address_reregister_trig(struct protocol_interface_info_entry *interface) { if (interface->ws_info->aro_registration_timer == 0) { interface->ws_info->aro_registration_timer = WS_NEIGHBOR_NUD_TIMEOUT; @@ -195,7 +189,7 @@ static void ws_bootstrap_address_notification_cb(struct protocol_interface_info_ //Trigger Address Registration only when Bootstrap is ready if (interface->nwk_bootstrap_state == ER_BOOTSRAP_DONE) { tr_debug("Address registration %s", trace_ipv6(addr->address)); - ws_address_registration_update(interface, addr->address); + ws_bootstrap_6lr_address_registration_update(interface, addr->address); } ws_address_reregister_trig(interface); } @@ -654,7 +648,7 @@ void ws_bootstrap_fhss_configure_channel_masks(protocol_interface_info_entry_t * cur->ws_info->hopping_schdule.channel_plan = ws_bootstrap_generate_exluded_channel_list_from_active_channels(&cur->ws_info->hopping_schdule.excluded_channels, fhss_configuration->unicast_channel_mask, fhss_configuration->channel_mask, cur->ws_info->hopping_schdule.number_of_channels); } -static int8_t ws_bootstrap_fhss_initialize(protocol_interface_info_entry_t *cur) +int8_t ws_bootstrap_fhss_initialize(protocol_interface_info_entry_t *cur) { fhss_api_t *fhss_api = ns_sw_mac_get_fhss_api(cur->mac_api); fhss_ws_configuration_t fhss_configuration; @@ -784,7 +778,7 @@ void ws_bootstrap_eapol_parent_synch(struct protocol_interface_info_entry *cur, } } -static void ws_bootstrap_ll_address_validate(struct protocol_interface_info_entry *cur) +void ws_bootstrap_ll_address_validate(struct protocol_interface_info_entry *cur) { // Configure EUI64 for MAC if missing uint8_t mac64[8]; @@ -884,7 +878,7 @@ bool ws_bootstrap_nd_ns_transmit(protocol_interface_info_entry_t *cur, ipv6_neig // True means we skip the message sending return true; } -static void ws_bootstrap_memory_configuration() +void ws_bootstrap_memory_configuration() { /* Configure memory limits for garbage collection based on total memory size * Starting from these values @@ -908,118 +902,6 @@ static void ws_bootstrap_memory_configuration() return; } - -static int8_t ws_bootstrap_up(protocol_interface_info_entry_t *cur) -{ - int8_t ret_val = -1; - - if (!cur) { - return -1; - } - - if ((cur->configure_flags & INTERFACE_SETUP_MASK) != INTERFACE_SETUP_READY) { - tr_error("Interface not yet fully configured"); - return -2; - } - if (ws_bootstrap_fhss_initialize(cur) != 0) { - tr_error("fhss initialization failed"); - return -3; - } - if (cur->bootsrap_mode == ARM_NWK_BOOTSRAP_MODE_6LoWPAN_BORDER_ROUTER) { - //BBR init like NVM read - ws_bbr_init(cur); - } - // Save FHSS api - cur->ws_info->fhss_api = ns_sw_mac_get_fhss_api(cur->mac_api); - - ws_bootstrap_ll_address_validate(cur); - - addr_interface_set_ll64(cur, NULL); - cur->nwk_nd_re_scan_count = 0; - // Trigger discovery for bootstrap - ret_val = nwk_6lowpan_up(cur); - if (ret_val) { - goto cleanup; - } - - /* Wi-sun will trig event for stamechine this timer must be zero on init */ - cur->bootsrap_state_machine_cnt = 0; - /* Disable SLLAO send/mandatory receive with the ARO */ - cur->ipv6_neighbour_cache.use_eui64_as_slla_in_aro = true; - /* Omit sending of NA if ARO SUCCESS */ - cur->ipv6_neighbour_cache.omit_na_aro_success = true; - /* Omit sending of NA and consider ACK to be success */ - cur->ipv6_neighbour_cache.omit_na = true; - // do not process AROs from NA. This is overriden by Wi-SUN specific failure handling - cur->ipv6_neighbour_cache.recv_na_aro = false; - /* Disable NUD Probes */ - cur->ipv6_neighbour_cache.send_nud_probes = false; - cur->ipv6_neighbour_cache.probe_avoided_routers = true; - /*Replace NS handler to disable multicast address queries */ - cur->if_ns_transmit = ws_bootstrap_nd_ns_transmit; - - dhcp_client_init(cur->id, DHCPV6_DUID_HARDWARE_IEEE_802_NETWORKS_TYPE); - dhcp_service_link_local_rx_cb_set(cur->id, ws_bootstrap_dhcp_neighbour_update_cb); - dhcp_client_configure(cur->id, true, true, true); //RENEW uses SOLICIT, Interface will use 1 instance for address get, IAID address hint is not used. - - dhcp_client_solicit_timeout_set(cur->id, WS_DHCP_SOLICIT_TIMEOUT, WS_DHCP_SOLICIT_MAX_RT, WS_DHCP_SOLICIT_MAX_RC, WS_DHCP_SOLICIT_MAX_DELAY); - dhcp_client_option_notification_cb_set(cur->id, ws_bootstrap_dhcp_info_notify_cb); - - // Configure memory limits and garbage collection values; - ws_bootstrap_memory_configuration(); - ws_nud_table_reset(cur); - - ws_bootstrap_candidate_table_reset(cur); - // Zero uptime counters - cur->ws_info->uptime = 0; - cur->ws_info->authentication_time = 0; - cur->ws_info->connected_time = 0; - - blacklist_params_set( - WS_BLACKLIST_ENTRY_LIFETIME, - WS_BLACKLIST_TIMER_MAX_TIMEOUT, - WS_BLACKLIST_TIMER_TIMEOUT, - WS_BLACKLIST_ENTRY_MAX_NBR, - WS_BLACKLIST_PURGE_NBR, - WS_BLACKLIST_PURGE_TIMER_TIMEOUT); - - ws_bootstrap_event_discovery_start(cur); - - return 0; -cleanup: - return ret_val; -} - -static int8_t ws_bootstrap_down(protocol_interface_info_entry_t *cur) -{ - if (!cur || !(cur->lowpan_info & INTERFACE_NWK_ACTIVE)) { - return -1; - } - - tr_info("Wi-SUN ifdown"); - // Reset MAC for safe upper layer memory free - protocol_mac_reset(cur); - ns_sw_mac_fhss_unregister(cur->mac_api); - ns_fhss_delete(cur->ws_info->fhss_api); - cur->ws_info->fhss_api = NULL; - // Reset WS information - ws_bootstrap_asynch_trickle_stop(cur); - ws_llc_reset(cur); - if (nd_proxy_downstream_interface_unregister(cur->id) != 0) { - tr_warn("nd proxy unregister failed"); - } - ws_nud_table_reset(cur); - dhcp_client_delete(cur->id); - ws_eapol_relay_delete(cur); - ws_eapol_auth_relay_delete(cur); - ws_pae_controller_stop(cur); - ws_bootstrap_candidate_table_reset(cur); - blacklist_clear(); - cur->if_common_forwarding_out_cb = NULL; - - return nwk_6lowpan_down(cur); -} - void ws_bootstrap_configuration_reset(protocol_interface_info_entry_t *cur) { // Configure IP stack to operate as Wi-SUN node @@ -1738,17 +1620,17 @@ int ws_bootstrap_init(int8_t interface_id, net_6lowpan_mode_e bootstrap_mode) if (wisun_mode_host(cur)) { // Configure for LFN device #if defined(HAVE_WS) && defined(HAVE_WS_HOST) - ws_llc_create(cur, &ws_bootstrap_lfn_asynch_ind, &ws_bootstrap_lfn_asynch_confirm, &ws_bootstrap_neighbor_info_request); + ws_llc_create(cur, & ws_bootstrap_6ln_asynch_ind, & ws_bootstrap_6ln_asynch_confirm, &ws_bootstrap_neighbor_info_request, &ws_bootstrap_6ln_eapol_relay_state_active); #endif } else if (wisun_mode_router(cur)) { // Configure FFN device #if defined(HAVE_WS) && defined(HAVE_WS_ROUTER) - ws_llc_create(cur, &ws_bootstrap_ffn_asynch_ind, &ws_bootstrap_ffn_asynch_confirm, &ws_bootstrap_neighbor_info_request); + ws_llc_create(cur, &ws_bootstrap_6lr_asynch_ind, &ws_bootstrap_6lr_asynch_confirm, &ws_bootstrap_neighbor_info_request, &ws_bootstrap_6lr_eapol_relay_state_active); #endif } else if (wisun_mode_border_router(cur)) { // Configure as Border router #if defined(HAVE_WS) && defined(HAVE_WS_BORDER_ROUTER) - ws_llc_create(cur, &ws_bootstrap_6lbr_asynch_ind, &ws_bootstrap_6lbr_asynch_confirm, &ws_bootstrap_neighbor_info_request); + ws_llc_create(cur, &ws_bootstrap_6lbr_asynch_ind, &ws_bootstrap_6lbr_asynch_confirm, &ws_bootstrap_neighbor_info_request, &ws_bootstrap_6lbr_eapol_relay_state_active); #endif } @@ -1784,7 +1666,11 @@ int ws_bootstrap_init(int8_t interface_id, net_6lowpan_mode_e bootstrap_mode) ret_val = -4; goto init_fail; } - if (ws_pae_controller_cb_register(cur, &ws_bootstrap_authentication_completed, &ws_bootstrap_authentication_next_target, &ws_bootstrap_nw_key_set, &ws_bootstrap_nw_key_clear, &ws_bootstrap_nw_key_index_set, &ws_bootstrap_nw_frame_counter_set, &ws_bootstrap_nw_frame_counter_read, &ws_bootstrap_pan_version_increment, &ws_bootstrap_nw_info_updated, &ws_bootstrap_eapol_congestion_get) < 0) { + if (ws_pae_controller_nw_key_cb_register(cur, &ws_bootstrap_nw_key_set, &ws_bootstrap_nw_key_clear, &ws_bootstrap_nw_key_index_set, &ws_bootstrap_nw_frame_counter_set, &ws_bootstrap_nw_frame_counter_read) < 0) { + ret_val = -4; + goto init_fail; + } + if (ws_pae_controller_authentication_cb_register(cur, &ws_bootstrap_authentication_completed, &ws_bootstrap_authentication_next_target) < 0) { ret_val = -4; goto init_fail; } @@ -1806,8 +1692,21 @@ int ws_bootstrap_init(int8_t interface_id, net_6lowpan_mode_e bootstrap_mode) cur->ipv6_neighbour_cache.link_mtu = cur->max_link_mtu = WS_MPX_MAX_MTU; - cur->if_up = ws_bootstrap_up; - cur->if_down = ws_bootstrap_down; + switch (bootstrap_mode) { + // case NET_6LOWPAN_SLEEPY_HOST: + case NET_6LOWPAN_HOST: + cur->if_up = ws_bootstrap_6ln_up; + cur->if_down = ws_bootstrap_6ln_down; + break; + case NET_6LOWPAN_ROUTER: + case NET_6LOWPAN_BORDER_ROUTER: + cur->if_up = ws_bootstrap_ffn_up; + cur->if_down = ws_bootstrap_ffn_down; + break; + default: + break; + } + cur->ws_info->neighbor_storage = neigh_info; cur->etx_read_override = ws_etx_read; @@ -1939,8 +1838,13 @@ static int ws_bootstrap_set_rf_config(protocol_interface_info_entry_t *cur, phy_ set_request.value_pointer = &multi_csma_params; set_request.value_size = sizeof(mlme_multi_csma_ca_param_t); cur->mac_api->mlme_req(cur->mac_api, MLME_SET, &set_request); - // Start automatic CCA threshold - mac_helper_start_auto_cca_threshold(cur->id, cur->ws_info->hopping_schdule.number_of_channels, CCA_DEFAULT_DBM, CCA_HIGH_LIMIT, CCA_LOW_LIMIT); + if (cur->ws_info->hopping_schdule.regulatory_domain == REG_DOMAIN_JP) { + // For Japan regulatory domain, use static CCA threshold -80dBm as defined by Wi-SUN FAN specification + mac_helper_start_auto_cca_threshold(cur->id, cur->ws_info->hopping_schdule.number_of_channels, -80, -80, -80); + } else { + // Start automatic CCA threshold + mac_helper_start_auto_cca_threshold(cur->id, cur->ws_info->hopping_schdule.number_of_channels, CCA_DEFAULT_DBM, CCA_HIGH_LIMIT, CCA_LOW_LIMIT); + } // Enable MAC mode switch when base PHY mode ID could be found, otherwise disable the feature uint8_t phy_mode_id = cur->ws_info->hopping_schdule.phy_mode_id; if (phy_mode_id == 255) { @@ -2053,527 +1957,6 @@ void ws_bootstrap_ip_stack_activate(protocol_interface_info_entry_t *cur) ws_bootstrap_ip_stack_reset(cur); } -static void ws_bootstrap_set_fhss_hop(protocol_interface_info_entry_t *cur) -{ - uint16_t own_rank = ws_bootstrap_rank_get(cur); - uint16_t rank_inc = ws_bootstrap_min_rank_inc_get(cur); - if (own_rank == 0xffff || rank_inc == 0xffff) { - return; - } - // Calculate own hop count. This method gets inaccurate when hop count increases. - uint8_t own_hop = (own_rank - rank_inc) / rank_inc; - ns_fhss_ws_set_hop_count(cur->ws_info->fhss_api, own_hop); - if (own_hop == 1) { - // Allow transmitting unicast frames only on TX slots in normal mode and always in expedited forwarding mode for first hop - ns_fhss_ws_set_tx_allowance_level(cur->ws_info->fhss_api, WS_TX_SLOT, WS_TX_ALWAYS); - } else { - // Allow transmitting unicast frames only on TX slots in normal and expedited forwarding mode for other hops - ns_fhss_ws_set_tx_allowance_level(cur->ws_info->fhss_api, WS_TX_SLOT, WS_TX_SLOT); - } - tr_debug("own hop: %u, own rank: %u, rank inc: %u", own_hop, own_rank, rank_inc); -} - -static void ws_bootstrap_dhcp_neighbour_update_cb(int8_t interface_id, uint8_t ll_addr[static 16]) -{ - if (memcmp(ll_addr, ADDR_LINK_LOCAL_PREFIX, 8)) { - return; - } - - protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(interface_id); - if (!cur) { - return; - } - - uint8_t mac64[8]; - memcpy(mac64, ll_addr + 8, 8); - mac64[0] ^= 2; - ws_bootstrap_mac_neighbor_short_time_set(cur, mac64, WS_NEIGHBOUR_DHCP_ENTRY_LIFETIME); -} - -static void ws_bootstrap_dhcp_info_notify_cb(int8_t interface, dhcp_option_notify_t *options, dhcp_server_notify_info_t *server_info) -{ - protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(interface); - if (!cur) { - return; - } - uint8_t server_ll64[16]; - memcpy(server_ll64, ADDR_LINK_LOCAL_PREFIX, 8); - - if (server_info->duid_length == 8) { - memcpy(server_ll64 + 8, server_info->duid, 8); - } else { - server_ll64[8] = server_info->duid[0]; - server_ll64[9] = server_info->duid[1]; - server_ll64[10] = server_info->duid[2]; - server_ll64[11] = 0xff; - server_ll64[12] = 0xfe; - server_ll64[13] = server_info->duid[3]; - server_ll64[14] = server_info->duid[4]; - server_ll64[15] = server_info->duid[5]; - } - server_ll64[8] ^= 2; - - switch (options->option_type) { - case DHCPV6_OPTION_VENDOR_SPECIFIC_INFO: - if (options->option.vendor_spesific.enterprise_number != ARM_ENTERPRISE_NUMBER) { - break; - } - while (options->option.vendor_spesific.data_length) { - uint16_t option_type; - char *domain; - uint8_t *address; - uint16_t option_len; - option_len = net_dns_option_vendor_option_data_get_next(options->option.vendor_spesific.data, options->option.vendor_spesific.data_length, &option_type); - tr_debug("DHCP vendor specific data type:%u length %d", option_type, option_len); - //tr_debug("DHCP vendor specific data %s", trace_array(options->option.vendor_spesific.data, options->option.vendor_spesific.data_length)); - - if (option_len == 0) { - // Option fields were corrupted - break; - } - if (option_type == ARM_DHCP_VENDOR_DATA_DNS_QUERY_RESULT) { - // Process ARM DNS query result - domain = NULL; - address = NULL; - if (net_dns_option_vendor_option_data_dns_query_read(options->option.vendor_spesific.data, options->option.vendor_spesific.data_length, &address, &domain) > 0 || - domain || address) { - // Valid ARM DNS query entry - net_dns_query_result_set(interface, address, domain, server_info->life_time); - } - } - if (option_type == ARM_DHCP_VENDOR_DATA_TIME_CONFIGURATION) { - timezone_info_t time_configuration; - if (net_vendor_option_time_configuration_read(options->option.vendor_spesific.data, options->option.vendor_spesific.data_length, &time_configuration.timestamp, &time_configuration.timezone, &time_configuration.deviation, &time_configuration.status)) { - int ret = ns_time_system_timezone_info_notify(&time_configuration); - tr_info("Network Time configuration %s status:%"PRIu16" time stamp: %"PRIu64" deviation: %"PRId16" Time Zone: %"PRId16, ret == 0 ? "notified" : "notify FAILED", time_configuration.status, time_configuration.timestamp, time_configuration.deviation, time_configuration.timezone); - } - } - if (option_type == ARM_DHCP_VENDOR_DATA_NETWORK_TIME) { - // Process ARM Network Time - // Get Current time - // Get Round trip time of the DHCP request - // Estimated error is elapsed time of request - // If current time difference is larger than estimated error update current time - // set the time for server time + *.5 RTT - int32_t era; - uint32_t offset; - if (net_vendor_option_current_time_read(options->option.vendor_spesific.data, options->option.vendor_spesific.data_length, &era, &offset, NULL)) { - uint64_t current_time; - uint64_t network_time = (era * (uint64_t)(4294967296)) + offset - 2208988800; //Convert to First day of Unix (1 Jan 1970) - - tr_debug("Network Time option Era:%"PRId32" Offset:%"PRIu32" rtt: %"PRId32" time: %"PRIu64, era, offset, server_info->rtt, network_time); - if (0 == ns_time_system_time_read(¤t_time)) { - uint64_t difference; - // We only adjust clock if time has drifted more than 10 seconds to avoid constant changing of time - // If Round trip time is very high the accuracy is reduced. - uint32_t estimated_error = 10 + server_info->rtt / 10; - // Take into account the round trip time it took the response to arrive from the time server Write the time. - network_time += server_info->rtt / 20; - - if (current_time > network_time) { - difference = current_time - network_time; - } else { - difference = network_time - current_time; - } - if (difference > estimated_error) { - // Larger than 10 second difference update the time - int ret = ns_time_system_time_write(network_time); - tr_info("Network Time %s: Era:%"PRId32" Offset:%"PRIu32" old time: %"PRIu64" time: %"PRIu64, ret == 0 ? "updated" : "update FAILED", era, offset, current_time, network_time); - } - // System time has been acquired - ns_time_system_time_acquired_set(); - } - } - } - - options->option.vendor_spesific.data_length -= option_len; - options->option.vendor_spesific.data += option_len; - } - break; - - case DHCPV6_OPTION_DNS_SERVERS: - while (options->option.generic.data_length && options->option.generic.data_length >= 16 && options->option.generic.data_length % 16 == 0) { - // Validate payload to have full 16 byte length addresses without any extra bytes - net_dns_server_address_set(interface, server_ll64, options->option.generic.data, server_info->life_time); - options->option.generic.data_length -= 16; - options->option.generic.data += 16; - } - break; - case DHCPV6_OPTION_DOMAIN_LIST: - net_dns_server_search_list_set(interface, server_ll64, options->option.generic.data, options->option.generic.data_length, server_info->life_time); - break; - default: - break; - } - -} - -static void ws_dhcp_client_global_adress_cb(int8_t interface, uint8_t dhcp_addr[static 16], uint8_t prefix[static 16], bool register_status) -{ - (void)prefix; - (void)interface; - //TODO add handler for negative status - tr_debug("DHCPv6 %s status %u with link %s", trace_ipv6(prefix), register_status, trace_ipv6(dhcp_addr)); - if (register_status) { - protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(interface); - if (cur) { - ws_address_reregister_trig(cur); - } - } else { - //Delete dhcpv6 client - dhcp_client_global_address_delete(interface, dhcp_addr, prefix); - } -} - - -void ws_dhcp_client_address_request(protocol_interface_info_entry_t *cur, uint8_t *prefix, uint8_t *parent_link_local) -{ - if (dhcp_client_get_global_address(cur->id, parent_link_local, prefix, ws_dhcp_client_global_adress_cb) != 0) { - tr_error("DHCPp client request fail"); - } -} - -void ws_dhcp_client_address_delete(protocol_interface_info_entry_t *cur, uint8_t *prefix) -{ - dhcp_client_global_address_delete(cur->id, NULL, prefix); -} - -void ws_address_registration_update(protocol_interface_info_entry_t *interface, const uint8_t addr[16]) -{ - rpl_control_register_address(interface, addr); - // Timer is used only to track full registrations - - if (addr != NULL && interface->ws_info->aro_registration_timer) { - // Single address update and timer is running - return; - } - - if (interface->ws_info->aro_registration_timer == 0) { - // Timer expired and check if we have valid address to register - ns_list_foreach(if_address_entry_t, address, &interface->ip_addresses) { - if (!addr_is_ipv6_link_local(address->address)) { - // We have still valid addresses let the timer run for next period - tr_info("ARO registration timer start"); - interface->ws_info->aro_registration_timer = WS_NEIGHBOR_NUD_TIMEOUT; - return; - } - } - } -} - -static void ws_address_parent_update(protocol_interface_info_entry_t *interface) -{ - tr_info("RPL parent update ... register ARO"); - ws_address_registration_update(interface, NULL); -} - -void ws_bootstrap_parent_confirm(protocol_interface_info_entry_t *cur, struct rpl_instance *instance) -{ - /* Possible problem with the parent connection - * Give some time for parent to rejoin and confirm the connection with ARO and DAO - */ - const rpl_dodag_conf_t *config = NULL; - uint32_t Imin_secs = 0; - - if (!ws_bootstrap_state_active(cur)) { - // If we are not in Active state no need to confirm parent - return; - } - - tr_info("RPL parent confirm"); - - if (!instance) { - // If we dont have instance we take any available to get reference - instance = rpl_control_enumerate_instances(cur->rpl_domain, NULL); - } - - if (instance) { - config = rpl_control_get_dodag_config(instance); - } - - if (config) { - //dio imin Period caluclate in seconds - uint32_t Imin_ms = config->dio_interval_min < 32 ? (1ul << config->dio_interval_min) : 0xfffffffful; - //Covert to seconds and multiple by 2 so we give time to recovery so divide by 500 do that operation - Imin_secs = (Imin_ms + 499) / 500; - - if (Imin_secs > 0xffff) { - Imin_secs = 0xffff; - } - } - if (Imin_secs == 0) { - // If we dont have RPL configuration we assume conservative value - Imin_secs = 60; - } - - /*Speed up the ARO registration*/ - if (cur->ws_info->aro_registration_timer > Imin_secs) { - cur->ws_info->aro_registration_timer = Imin_secs; - } -} - -static void ws_rpl_parent_dis_callback(const uint8_t *ll_parent_address, void *handle, struct rpl_instance *instance) -{ - (void) ll_parent_address; - protocol_interface_info_entry_t *cur = handle; - if (!cur->rpl_domain || cur->interface_mode != INTERFACE_UP) { - return; - } - //Multicast DIS from parent indicate that Parent is not valid in short time window possible - ws_bootstrap_parent_confirm(cur, instance); -} - - -static void ws_bootstrap_rpl_callback(rpl_event_t event, void *handle) -{ - - protocol_interface_info_entry_t *cur = handle; - if (!cur->rpl_domain || cur->interface_mode != INTERFACE_UP) { - return; - } - - if (event == RPL_EVENT_POISON_FINISHED) { - //If we are waiting poison we will trig Discovery after couple seconds - if (cur->nwk_bootstrap_state == ER_RPL_NETWORK_LEAVING) { - cur->bootsrap_state_machine_cnt = 80; //Give 8 seconds time to send Poison - } - return; - } - - // if waiting for RPL and - if (event == RPL_EVENT_DAO_DONE) { - // Trigger statemachine check - cur->bootsrap_state_machine_cnt = 1; - rpl_dodag_info_t dodag_info; - struct rpl_instance *instance = rpl_control_enumerate_instances(cur->rpl_domain, NULL); - - if (instance && rpl_control_read_dodag_info(instance, &dodag_info)) { - tr_debug("Enable DHCPv6 relay"); - dhcp_relay_agent_enable(cur->id, dodag_info.dodag_id); - - tr_debug("Start EAPOL relay"); - // Set both own port and border router port to 10253 - ws_eapol_relay_start(cur, EAPOL_RELAY_SOCKET_PORT, dodag_info.dodag_id, EAPOL_RELAY_SOCKET_PORT); - // Set network information to PAE - 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); - // Network key is valid, indicate border router IID to controller - ws_pae_controller_nw_key_valid(cur, &dodag_info.dodag_id[8]); - //Update here Suplikant target by validated Primary Parent - if (cur->bootsrap_mode != ARM_NWK_BOOTSRAP_MODE_6LoWPAN_BORDER_ROUTER) { - mac_neighbor_table_entry_t *mac_neighbor = mac_neighbor_entry_get_priority(mac_neighbor_info(cur)); - if (mac_neighbor) { - ws_pae_controller_set_target(cur, cur->ws_info->network_pan_id, mac_neighbor->mac64); - } - } - - // After successful DAO ACK connection to border router is verified - ws_common_border_router_alive_update(cur); - } - - if (!cur->ws_info->trickle_pa_running || !cur->ws_info->trickle_pc_running) { - //Enable wi-sun asynch adverisment - ws_bootstrap_advertise_start(cur); - } - - ws_bootstrap_set_fhss_hop(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); - } else if (event == RPL_EVENT_LOCAL_REPAIR_NO_MORE_DIS) { - /* - * RPL goes to passive mode, but does not require any extra changed - * - * We could remove our current addresses learned from RPL - * We could send solicit for configuration and then select new parent when those arrive - * - */ - - } else if (event == RPL_EVENT_LOCAL_REPAIR_START) { - tr_debug("RPL local repair start"); - //Disable Async and go to state 4 to confirm parent connection - ws_bootstrap_parent_confirm(cur, NULL); - // Move to state 4 if we see issues with primary parent - if (ws_bootstrap_state_active(cur)) { - tr_info("Move state 4 to wait parent connection confirmation"); - ws_bootstrap_rpl_scan_start(cur); - ws_bootstrap_network_down(cur); - } - } else if (event == RPL_EVENT_DAO_PARENT_ADD) { - ws_address_parent_update(cur); - } - cur->ws_info->rpl_state = event; - tr_info("RPL event %d", event); -} - -bool ws_eapol_relay_state_active(protocol_interface_info_entry_t *cur) -{ - if (cur->bootsrap_mode == ARM_NWK_BOOTSRAP_MODE_6LoWPAN_BORDER_ROUTER || cur->nwk_bootstrap_state == ER_BOOTSRAP_DONE) { - return true; - } - - return false; -} - -static void ws_rpl_prefix_callback(prefix_entry_t *prefix, void *handle, uint8_t *parent_link_local) -{ - protocol_interface_info_entry_t *cur = (protocol_interface_info_entry_t *) handle; - /* Check if A-Flag. - * A RPL node may use this option for the purpose of Stateless Address Autoconfiguration (SLAAC) - * from a prefix advertised by a parent. - */ - if (prefix->options & PIO_A) { - - if (parent_link_local) { - if (icmpv6_slaac_prefix_update(cur, prefix->prefix, prefix->prefix_len, prefix->lifetime, prefix->preftime) != 0) { - ipv6_interface_slaac_handler(cur, prefix->prefix, prefix->prefix_len, prefix->lifetime, prefix->preftime); - /* - * Give SLAAC addresses a different label and low precedence to indicate that - * they probably shouldn't be used for external traffic. SLAAC use in Wi-SUN is non-standard, - * and we use it for mesh-local traffic we should prefer any DHCP-assigned addresses - * for talking to the outside world - * - */ - addr_policy_table_add_entry(prefix->prefix, prefix->prefix_len, 2, WS_NON_PREFFRED_LABEL); - } - } else { - icmpv6_slaac_prefix_update(cur, prefix->prefix, prefix->prefix_len, 0, 0); - } - } else if (prefix->prefix_len) { - // Create new address using DHCP - if (parent_link_local) { - ws_dhcp_client_address_request(cur, prefix->prefix, parent_link_local); - } else { - /* Deprecate address and remove client */ - tr_debug("Prefix invalidation %s", trace_ipv6(prefix->prefix)); - dhcp_client_global_address_delete(cur->id, NULL, prefix->prefix); - } - } -} - -static bool ws_rpl_candidate_soft_filtering(protocol_interface_info_entry_t *cur, struct rpl_instance *instance) -{ - //Already many candidates - uint16_t candidate_list_size = rpl_control_candidate_list_size(cur, instance); - if (candidate_list_size >= cur->ws_info->cfg->gen.rpl_parent_candidate_max) { - return false; - } - - uint16_t selected_parents = rpl_control_selected_parent_count(cur, instance); - - //Already enough selected candidates - if (selected_parents >= cur->ws_info->cfg->gen.rpl_selected_parent_max) { - candidate_list_size -= selected_parents; - if (candidate_list_size >= 2) { - //We have more candidates than selected - return false; - } - } - - return true; -} - -static bool ws_rpl_new_parent_callback(uint8_t *ll_parent_address, void *handle, struct rpl_instance *instance, uint16_t candidate_rank) -{ - - protocol_interface_info_entry_t *cur = handle; - if (!cur->rpl_domain || cur->interface_mode != INTERFACE_UP) { - return false; - } - - if (blacklist_reject(ll_parent_address)) { - // Rejected by blacklist - return false; - } - - uint8_t mac64[10]; - //bool replace_ok = false; - //bool create_ok = false; - llc_neighbour_req_t neigh_buffer; - - //Discover neigh ready here for possible ETX validate - memcpy(mac64, ll_parent_address + 8, 8); - mac64[0] ^= 2; - - - ws_bootstrap_neighbor_info_request(cur, mac64, &neigh_buffer, false); - //Discover Multicast temporary entry for create neighbour table entry for new candidate - ws_neighbor_temp_class_t *entry = ws_llc_get_multicast_temp_entry(cur, mac64); - - if (!ws_rpl_candidate_soft_filtering(cur, instance)) { - - //Acept only better than own rank here - if (candidate_rank >= rpl_control_current_rank(instance)) { - //Do not accept no more siblings - return false; - } - - uint16_t candidate_list_size = rpl_control_candidate_list_size(cur, instance); - if (candidate_list_size > cur->ws_info->cfg->gen.rpl_parent_candidate_max + 1) { - //Accept only 1 better 1 time - return false; - } - - if (!neigh_buffer.neighbor) { - //Do not accept any new in that Place - return false; - } - - uint8_t replacing[16]; - //Accept Know neighbour if it is enough good - if (!rpl_control_find_worst_neighbor(cur, instance, replacing)) { - return false; - } - // +2 Is for PAN ID space - memcpy(mac64, replacing + 8, 8); - mac64[0] ^= 2; - - if (ws_local_etx_read(cur, ADDR_802_15_4_LONG, mac64) == 0xffff) { - //Not probed yet because ETX is 0xffff - return false; - } - - uint16_t etx = 0; - if (neigh_buffer.neighbor) { - etx = ws_local_etx_read(cur, ADDR_802_15_4_LONG, neigh_buffer.neighbor->mac64); - } - - // Accept now only better one's when max candidates selected and max candidate list size is reached - return rpl_possible_better_candidate(cur, instance, replacing, candidate_rank, etx); - } - - //Neighbour allready - if (neigh_buffer.neighbor) { - return true; - } - - if (!entry) { - //No Multicast Entry Available - return false; - } - - //Create entry - bool create_ok = ws_bootstrap_neighbor_info_request(cur, entry->mac64, &neigh_buffer, true); - if (create_ok) { - ws_neighbor_class_entry_t *ws_neigh = neigh_buffer.ws_neighbor; - ws_bootstrap_neighbor_set_stable(cur, entry->mac64); - //Copy fhss temporary data - *ws_neigh = entry->neigh_info_list; - mac_neighbor_table_trusted_neighbor(mac_neighbor_info(cur), neigh_buffer.neighbor, true); - } - ws_llc_free_multicast_temp_entry(cur, entry); - -#if 0 -neigh_create_ok: - - if (create_ok && replace_ok) { - //Try remove here when accepted new better one possible - tr_debug("Remove %s by %s", trace_ipv6(replacing), trace_ipv6(ll_parent_address)); - rpl_control_neighbor_delete_from_instance(cur, instance, replacing); - } -#endif - return create_ok; -} static uint16_t ws_bootstrap_routing_cost_calculate(protocol_interface_info_entry_t *cur) { mac_neighbor_table_entry_t *mac_neighbor = mac_neighbor_entry_get_priority(mac_neighbor_info(cur)); @@ -2600,92 +1983,6 @@ static uint16_t ws_bootstrap_routing_cost_calculate(protocol_interface_info_entr return ws_neighbor->routing_cost + etx; } -static struct rpl_instance *ws_bootstrap_get_rpl_instance(protocol_interface_info_entry_t *cur) -{ - if (!cur || !cur->rpl_domain) { - return NULL; - } - struct rpl_instance *best_instance = NULL; - ns_list_foreach(struct rpl_instance, instance, &cur->rpl_domain->instances) { - best_instance = instance; - // Select best grounded and lowest rank? But there should be only one really - } - return best_instance; -} - -static uint16_t ws_bootstrap_rank_get(protocol_interface_info_entry_t *cur) -{ - struct rpl_instance *rpl_instance = ws_bootstrap_get_rpl_instance(cur); - if (!rpl_instance) { - return 0xffff; - } - return rpl_control_current_rank(rpl_instance); -} - - -static uint16_t ws_bootstrap_min_rank_inc_get(protocol_interface_info_entry_t *cur) -{ - struct rpl_instance *rpl_instance = ws_bootstrap_get_rpl_instance(cur); - if (!rpl_instance) { - return 0xffff; - } - struct rpl_dodag_info_t dodag_info; - if (!rpl_control_read_dodag_info(rpl_instance, &dodag_info)) { - return 0xffff; - } - return dodag_info.dag_min_hop_rank_inc; -} - -void ws_bootstrap_rpl_scan_start(protocol_interface_info_entry_t *cur) -{ - tr_debug("Start RPL learn"); - // Stop Trickle timers - ws_bootstrap_asynch_trickle_stop(cur); - - // routers wait until RPL root is contacted - ws_bootstrap_state_change(cur, ER_RPL_SCAN); - // Change state as the state is checked in state machine - cur->ws_info->rpl_state = RPL_EVENT_LOCAL_REPAIR_START; - //For Large network and medium should do passive scan - if (ws_cfg_network_config_get(cur) > CONFIG_SMALL) { - // Set timeout for check to 30 - 60 seconds - cur->bootsrap_state_machine_cnt = randLIB_get_random_in_range(WS_RPL_DIS_INITIAL_TIMEOUT / 2, WS_RPL_DIS_INITIAL_TIMEOUT); - } -} - -void ws_bootstrap_rpl_activate(protocol_interface_info_entry_t *cur) -{ - tr_debug("RPL Activate"); - bool downstream = true; - bool leaf = false; - - addr_add_router_groups(cur); - rpl_control_set_domain_on_interface(cur, protocol_6lowpan_rpl_domain, downstream); - rpl_control_set_callback(protocol_6lowpan_rpl_domain, ws_bootstrap_rpl_callback, ws_rpl_prefix_callback, ws_rpl_new_parent_callback, ws_rpl_parent_dis_callback, cur); - // If i am router I Do this - rpl_control_force_leaf(protocol_6lowpan_rpl_domain, leaf); - rpl_control_process_routes(protocol_6lowpan_rpl_domain, false); // Wi-SUN assumes that no default route needed - rpl_control_request_parent_link_confirmation(true); - rpl_control_set_dio_multicast_min_config_advertisment_count(WS_MIN_DIO_MULTICAST_CONFIG_ADVERTISMENT_COUNT); - rpl_control_set_address_registration_timeout((WS_NEIGHBOR_LINK_TIMEOUT / 60) + 1); - rpl_control_set_dao_retry_count(WS_MAX_DAO_RETRIES); - rpl_control_set_initial_dao_ack_wait(WS_MAX_DAO_INITIAL_TIMEOUT); - rpl_control_set_mrhof_parent_set_size(WS_MAX_PARENT_SET_COUNT); - rpl_control_set_force_tunnel(true); - if (cur->bootsrap_mode != ARM_NWK_BOOTSRAP_MODE_6LoWPAN_BORDER_ROUTER) { - rpl_control_set_memory_limits(WS_NODE_RPL_SOFT_MEM_LIMIT, WS_NODE_RPL_HARD_MEM_LIMIT); - } - // Set RPL Link ETX Validation Threshold to 2.5 - 33.0 - // This setup will set ETX 0x800 to report ICMP error 18% probability - // When ETX start go over 0x280 forward dropping probability start increase linear to 100% at 0x2100 - rpl_policy_forward_link_etx_threshold_set(0x280, 0x2100); - - // Set the minimum target refresh to sen DAO registrations before pan timeout - rpl_control_set_minimum_dao_target_refresh(WS_RPL_DAO_MAX_TIMOUT); - - cur->ws_info->rpl_state = 0xff; // Set invalid state and learn from event -} - void ws_bootstrap_network_start(protocol_interface_info_entry_t *cur) { //Set Network names, Pan information configure, hopping schedule & GTKHash @@ -2702,12 +1999,6 @@ void ws_bootstrap_advertise_start(protocol_interface_info_entry_t *cur) trickle_start(&cur->ws_info->trickle_pan_config, &cur->ws_info->trickle_params_pan_discovery); } -static void ws_bootstrap_pan_version_increment(protocol_interface_info_entry_t *cur) -{ - (void)cur; - ws_bbr_pan_version_increase(cur); -} - // Start authentication void ws_bootstrap_start_authentication(protocol_interface_info_entry_t *cur) { @@ -2760,36 +2051,6 @@ static void ws_bootstrap_nw_frame_counter_read(protocol_interface_info_entry_t * mac_helper_key_link_frame_counter_read(cur->id, counter, slot); } -static void ws_bootstrap_nw_info_updated(protocol_interface_info_entry_t *cur, uint16_t pan_id, uint16_t pan_version, char *network_name) -{ - /* For border router, the PAE controller reads PAN ID, PAN version and network name from storage. - * If they are set, takes them into use here. - */ - if (cur->bootsrap_mode == ARM_NWK_BOOTSRAP_MODE_6LoWPAN_BORDER_ROUTER) { - // Get network name - ws_gen_cfg_t gen_cfg; - if (ws_cfg_gen_get(&gen_cfg) < 0) { - return; - } - - // If PAN ID has not been set, set it - if (cur->ws_info->network_pan_id == 0xffff) { - cur->ws_info->network_pan_id = pan_id; - // Sets PAN version - cur->ws_info->pan_information.pan_version = pan_version; - cur->ws_info->pan_information.pan_version_set = true; - } - - // If network name has not been set, set it - if (strlen(gen_cfg.network_name) == 0) { - strncpy(gen_cfg.network_name, network_name, 32); - } - - // Stores the settings - ws_cfg_gen_set(cur, &gen_cfg, 0); - } -} - static void ws_bootstrap_authentication_completed(protocol_interface_info_entry_t *cur, auth_result_e result, uint8_t *target_eui_64) { if (result == AUTH_RESULT_OK) { @@ -2841,79 +2102,6 @@ static const uint8_t *ws_bootstrap_authentication_next_target(protocol_interface return previous_eui_64; } -static bool ws_bootstrap_eapol_congestion_get(protocol_interface_info_entry_t *cur, uint16_t active_supp) -{ - if (cur == NULL || cur->random_early_detection == NULL || cur->llc_random_early_detection == NULL || cur->llc_eapol_random_early_detection == NULL) { - return false; - } - - bool return_value = false; - static struct red_info_s *red_info = NULL; - uint16_t adaptation_average = 0; - uint16_t llc_average = 0; - uint16_t llc_eapol_average = 0; - uint16_t average_sum = 0; - uint8_t active_max = 0; - - //TODO implement API for HEAP info request - uint32_t heap_size; - const mem_stat_t *mem_stats = ns_dyn_mem_get_mem_stat(); - if (mem_stats) { - heap_size = mem_stats->heap_sector_size; - } else { - heap_size = 0; - } - - /* - * For different memory sizes the max simultaneous authentications will be - * 32k: (32k / 50k) * 2 + 1 = 1 - * 65k: (65k / 50k) * 2 + 1 = 3 - * 250k: (250k / 50k) * 2 + 1 = 11 - * 1000k: (1000k / 50k) * 2 + 1 = 41 - * 2000k: (2000k / 50k) * 2 + 1 = 50 (upper limit) - */ - active_max = (heap_size / 50000) * 2 + 1; - if (active_max > 50) { - active_max = 50; - } - - // Read the values for adaptation and LLC queues - adaptation_average = random_early_detetction_aq_read(cur->random_early_detection); - llc_average = random_early_detetction_aq_read(cur->llc_random_early_detection); - llc_eapol_average = random_early_detetction_aq_read(cur->llc_eapol_random_early_detection); - // Calculate combined average - average_sum = adaptation_average + llc_average + llc_eapol_average; - - // Maximum for active supplicants based on memory reached, fail - if (active_supp >= active_max) { - return_value = true; - goto congestion_get_end; - } - - // Always allow at least five negotiations (if memory does not limit) - if (active_supp < 5) { - goto congestion_get_end; - } - - if (red_info == NULL) { - red_info = 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_DISABLED); - } - if (red_info == NULL) { - goto congestion_get_end; - } - - // Check drop probability - average_sum = random_early_detetction_aq_calc(red_info, average_sum); - return_value = random_early_detection_congestion_check(red_info); - -congestion_get_end: - tr_info("Active supplicant limit, active: %i max: %i summed averageQ: %i adapt averageQ: %i LLC averageQ: %i LLC EAPOL averageQ: %i drop: %s", active_supp, active_max, average_sum, adaptation_average, llc_average, llc_eapol_average, return_value ? "T" : "F"); - - return return_value; -} /* * Event transitions @@ -3079,9 +2267,9 @@ static void ws_bootstrap_event_handler(arm_event_s *event) } if (wisun_mode_host(cur)) { - ws_bootstrap_lfn_event_handler(cur, event); + ws_bootstrap_6ln_event_handler(cur, event); } else if (wisun_mode_router(cur)) { - ws_bootstrap_ffn_event_handler(cur, event); + ws_bootstrap_6lr_event_handler(cur, event); } else if (wisun_mode_border_router(cur)) { ws_bootstrap_6lbr_event_handler(cur, event); } @@ -3298,32 +2486,6 @@ void ws_bootstrap_seconds_timer(protocol_interface_info_entry_t *cur, uint32_t s ws_bootstrap_test_procedure_trigger_timer(cur, seconds); } -void ws_bootstrap_primary_parent_update(protocol_interface_info_entry_t *interface, mac_neighbor_table_entry_t *neighbor) -{ - if (interface->ws_info) { - llc_neighbour_req_t neighbor_info; - neighbor_info.neighbor = neighbor; - neighbor_info.ws_neighbor = ws_neighbor_class_entry_get(&interface->ws_info->neighbor_storage, neighbor->index); - ws_bootstrap_primary_parent_set(interface, &neighbor_info, WS_PARENT_HARD_SYNCH); - uint8_t link_local_address[16]; - ws_common_create_ll_address(link_local_address, neighbor->mac64); - dhcp_client_server_address_update(interface->id, NULL, link_local_address); - - ws_bootstrap_secondary_parent_update(interface); - } -} - -void ws_bootstrap_secondary_parent_update(protocol_interface_info_entry_t *interface) -{ - if (interface->ws_info) { - ns_list_foreach(if_address_entry_t, address, &interface->ip_addresses) { - if (!addr_is_ipv6_link_local(address->address)) { - ws_address_parent_update(interface); - } - } - } -} - int ws_bootstrap_stack_info_get(protocol_interface_info_entry_t *cur, struct ws_stack_info *info_ptr) { diff --git a/source/6LoWPAN/ws/ws_bootstrap.h b/source/6LoWPAN/ws/ws_bootstrap.h index 8c08a43978..b114ee9146 100644 --- a/source/6LoWPAN/ws/ws_bootstrap.h +++ b/source/6LoWPAN/ws/ws_bootstrap.h @@ -18,7 +18,6 @@ #ifndef WS_BOOTSTRAP_H_ #define WS_BOOTSTRAP_H_ - typedef enum { WS_INIT_EVENT = 0, /**< tasklet initializion event*/ WS_DISCOVERY_START, /**< discovery start*/ @@ -76,8 +75,6 @@ extern uint16_t test_pan_version; int ws_bootstrap_init(int8_t interface_id, net_6lowpan_mode_e bootstrap_mode); -void ws_bootstrap_state_machine(protocol_interface_info_entry_t *cur); - int ws_bootstrap_restart(int8_t interface_id); int ws_bootstrap_restart_delayed(int8_t interface_id); @@ -92,22 +89,20 @@ void ws_bootstrap_seconds_timer(protocol_interface_info_entry_t *cur, uint32_t s void ws_bootstrap_trickle_timer(protocol_interface_info_entry_t *cur, uint16_t ticks); -void ws_bootstrap_primary_parent_update(protocol_interface_info_entry_t *interface, mac_neighbor_table_entry_t *neighbor); - -void ws_bootstrap_secondary_parent_update(protocol_interface_info_entry_t *interface); - void ws_nud_entry_remove_active(protocol_interface_info_entry_t *cur, void *neighbor); void ws_nud_active_timer(protocol_interface_info_entry_t *cur, uint16_t ticks); -void ws_dhcp_client_address_request(protocol_interface_info_entry_t *cur, uint8_t *prefix, uint8_t *parent_link_local); - -void ws_dhcp_client_address_delete(protocol_interface_info_entry_t *cur, uint8_t *prefix); - -bool ws_eapol_relay_state_active(protocol_interface_info_entry_t *cur); - void ws_bootstrap_eapol_parent_synch(struct protocol_interface_info_entry *cur, struct llc_neighbour_req *neighbor_info); +void ws_bootstrap_ll_address_validate(struct protocol_interface_info_entry *cur); + +uint16_t ws_local_etx_read(protocol_interface_info_entry_t *interface, addrtype_t addr_type, const uint8_t *mac_adddress); + +bool ws_bootstrap_nd_ns_transmit(protocol_interface_info_entry_t *cur, ipv6_neighbour_t *entry, bool unicast, uint8_t seq); + +void ws_bootstrap_memory_configuration(); + bool ws_bootstrap_validate_channel_plan(struct ws_us_ie *ws_us, struct protocol_interface_info_entry *cur); bool ws_bootstrap_validate_channel_function(struct ws_us_ie *ws_us, struct ws_bs_ie *ws_bs); @@ -166,16 +161,15 @@ void ws_bootstrap_candidate_parent_sort(struct protocol_interface_info_entry *cu parent_info_t *ws_bootstrap_candidate_parent_get_best(protocol_interface_info_entry_t *cur); void ws_bootstrap_primary_parent_set(struct protocol_interface_info_entry *cur, struct llc_neighbour_req *neighbor_info, ws_parent_synch_e synch_req); -void ws_bootstrap_parent_confirm(protocol_interface_info_entry_t *cur, struct rpl_instance *instance); bool ws_bootstrap_neighbor_info_request(struct protocol_interface_info_entry *interface, const uint8_t *mac_64, struct llc_neighbour_req *neighbor_buffer, bool request_new); void ws_bootstrap_neighbor_list_clean(struct protocol_interface_info_entry *interface); int8_t ws_bootstrap_neighbor_set(protocol_interface_info_entry_t *cur, parent_info_t *parent_ptr, bool clear_list); +void ws_address_reregister_trig(struct protocol_interface_info_entry *interface); void ws_nud_table_reset(protocol_interface_info_entry_t *cur); -void ws_address_registration_update(protocol_interface_info_entry_t *interface, const uint8_t addr[16]); - void ws_bootstrap_configure_csma_ca_backoffs(protocol_interface_info_entry_t *cur, uint8_t max_backoffs, uint8_t min_be, uint8_t max_be); void ws_bootstrap_fhss_configure_channel_masks(protocol_interface_info_entry_t *cur, fhss_ws_configuration_t *fhss_configuration); +int8_t ws_bootstrap_fhss_initialize(protocol_interface_info_entry_t *cur); int8_t ws_bootstrap_fhss_set_defaults(protocol_interface_info_entry_t *cur, fhss_ws_configuration_t *fhss_configuration); void ws_bootstrap_fhss_activate(protocol_interface_info_entry_t *cur); uint16_t ws_bootstrap_randomize_fixed_channel(uint16_t configured_fixed_channel, uint8_t number_of_channels, uint32_t *channel_mask); @@ -186,9 +180,6 @@ void ws_bootstrap_configure_data_request_restart(protocol_interface_info_entry_t void ws_bootstrap_llc_hopping_update(struct protocol_interface_info_entry *cur, const fhss_ws_configuration_t *fhss_configuration); -void ws_bootstrap_rpl_activate(protocol_interface_info_entry_t *cur); -void ws_bootstrap_rpl_scan_start(protocol_interface_info_entry_t *cur); - void ws_bootstrap_ip_stack_reset(protocol_interface_info_entry_t *cur); void ws_bootstrap_ip_stack_activate(protocol_interface_info_entry_t *cur); @@ -201,13 +192,10 @@ void ws_bootstrap_network_start(protocol_interface_info_entry_t *cur); #else #define ws_bootstrap_init(interface_id, bootstrap_mode) (-1) -#define ws_bootstrap_state_machine(cur) #define ws_bootstrap_restart(cur) #define ws_bootstrap_neighbor_remove(cur, ll_address) #define ws_bootstrap_aro_failure(cur, ll_address) #define ws_bootstrap_neighbor_set_stable(interface, src64) -#define ws_bootstrap_primary_parent_update(interface, neighbor) -#define ws_bootstrap_secondary_parent_update(interface) #define ws_bootstrap_stack_info_get(cur, info_ptr) #define ws_bootstrap_neighbor_info_get(cur, neighbor_ptr, count) #define ws_bootstrap_test_procedure_trigger(cur, procedure); diff --git a/source/6LoWPAN/ws/ws_bootstrap_6lbr.c b/source/6LoWPAN/ws/ws_bootstrap_6lbr.c index a5e9ac3037..34139e44a4 100644 --- a/source/6LoWPAN/ws/ws_bootstrap_6lbr.c +++ b/source/6LoWPAN/ws/ws_bootstrap_6lbr.c @@ -54,6 +54,7 @@ #include "6LoWPAN/ws/ws_common_defines.h" #include "6LoWPAN/ws/ws_config.h" #include "6LoWPAN/ws/ws_common.h" +#include "6LoWPAN/ws/ws_bootstrap_ffn.h" #include "6LoWPAN/ws/ws_bootstrap.h" #include "6LoWPAN/ws/ws_bbr_api_internal.h" #include "6LoWPAN/ws/ws_common_defines.h" @@ -271,6 +272,123 @@ void ws_bootstrap_6lbr_asynch_confirm(struct protocol_interface_info_entry *inte } } +bool ws_bootstrap_6lbr_eapol_relay_state_active(protocol_interface_info_entry_t *cur) +{ + (void) cur; + + return true; +} + +static void ws_bootstrap_6lbr_pan_version_increment(protocol_interface_info_entry_t *cur) +{ + (void)cur; + ws_bbr_pan_version_increase(cur); +} + +static void ws_bootstrap_6lbr_nw_info_updated(protocol_interface_info_entry_t *cur, uint16_t pan_id, uint16_t pan_version, char *network_name) +{ + /* For border router, the PAE controller reads PAN ID, PAN version and network name from storage. + * If they are set, takes them into use here. + */ + if (cur->bootsrap_mode == ARM_NWK_BOOTSRAP_MODE_6LoWPAN_BORDER_ROUTER) { + // Get network name + ws_gen_cfg_t gen_cfg; + if (ws_cfg_gen_get(&gen_cfg) < 0) { + return; + } + + // If PAN ID has not been set, set it + if (cur->ws_info->network_pan_id == 0xffff) { + cur->ws_info->network_pan_id = pan_id; + // Sets PAN version + cur->ws_info->pan_information.pan_version = pan_version; + cur->ws_info->pan_information.pan_version_set = true; + } + + // If network name has not been set, set it + if (strlen(gen_cfg.network_name) == 0) { + strncpy(gen_cfg.network_name, network_name, 32); + } + + // Stores the settings + ws_cfg_gen_set(cur, &gen_cfg, 0); + } +} + +static bool ws_bootstrap_6lbr_eapol_congestion_get(protocol_interface_info_entry_t *cur, uint16_t active_supp) +{ + if (cur == NULL || cur->random_early_detection == NULL || cur->llc_random_early_detection == NULL || cur->llc_eapol_random_early_detection == NULL) { + return false; + } + + bool return_value = false; + static struct red_info_s *red_info = NULL; + uint16_t adaptation_average = 0; + uint16_t llc_average = 0; + uint16_t llc_eapol_average = 0; + uint16_t average_sum = 0; + uint8_t active_max = 0; + + //TODO implement API for HEAP info request + uint32_t heap_size; + const mem_stat_t *mem_stats = ns_dyn_mem_get_mem_stat(); + if (mem_stats) { + heap_size = mem_stats->heap_sector_size; + } else { + heap_size = 0; + } + + /* + * For different memory sizes the max simultaneous authentications will be + * 32k: (32k / 50k) * 2 + 1 = 1 + * 65k: (65k / 50k) * 2 + 1 = 3 + * 250k: (250k / 50k) * 2 + 1 = 11 + * 1000k: (1000k / 50k) * 2 + 1 = 41 + * 2000k: (2000k / 50k) * 2 + 1 = 50 (upper limit) + */ + active_max = (heap_size / 50000) * 2 + 1; + if (active_max > 50) { + active_max = 50; + } + + // Read the values for adaptation and LLC queues + adaptation_average = random_early_detetction_aq_read(cur->random_early_detection); + llc_average = random_early_detetction_aq_read(cur->llc_random_early_detection); + llc_eapol_average = random_early_detetction_aq_read(cur->llc_eapol_random_early_detection); + // Calculate combined average + average_sum = adaptation_average + llc_average + llc_eapol_average; + + // Maximum for active supplicants based on memory reached, fail + if (active_supp >= active_max) { + return_value = true; + goto congestion_get_end; + } + + // Always allow at least five negotiations (if memory does not limit) + if (active_supp < 5) { + goto congestion_get_end; + } + + if (red_info == NULL) { + red_info = 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_DISABLED); + } + if (red_info == NULL) { + goto congestion_get_end; + } + + // Check drop probability + average_sum = random_early_detetction_aq_calc(red_info, average_sum); + return_value = random_early_detection_congestion_check(red_info); + +congestion_get_end: + tr_info("Active supplicant limit, active: %i max: %i summed averageQ: %i adapt averageQ: %i LLC averageQ: %i LLC EAPOL averageQ: %i drop: %s", active_supp, active_max, average_sum, adaptation_average, llc_average, llc_eapol_average, return_value ? "T" : "F"); + + return return_value; +} + void ws_bootstrap_6lbr_event_handler(protocol_interface_info_entry_t *cur, arm_event_s *event) { ws_bootsrap_event_type_e event_type; @@ -371,8 +489,11 @@ void ws_bootstrap_6lbr_event_handler(protocol_interface_info_entry_t *cur, arm_e // 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 information callbacks (backbone IP address get callback, network information, congestion) + ws_pae_controller_information_cb_register(cur, ws_bootstrap_6lbr_backbone_ip_addr_get, &ws_bootstrap_6lbr_nw_info_updated, &ws_bootstrap_6lbr_eapol_congestion_get); + + // Set PAN version control callbacks + ws_pae_controller_pan_version_cb_register(cur, &ws_bootstrap_6lbr_pan_version_increment); // 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); @@ -402,7 +523,7 @@ void ws_bootstrap_6lbr_event_handler(protocol_interface_info_entry_t *cur, arm_e // Activate RPL // Activate IPv6 stack ws_bootstrap_ip_stack_activate(cur); - ws_bootstrap_rpl_activate(cur); + ws_bootstrap_ffn_rpl_configure(cur); ws_bootstrap_network_start(cur); // Wait for RPL start ws_bootstrap_event_routing_ready(cur); diff --git a/source/6LoWPAN/ws/ws_bootstrap_6lbr.h b/source/6LoWPAN/ws/ws_bootstrap_6lbr.h index 5517793fb5..716454484e 100644 --- a/source/6LoWPAN/ws/ws_bootstrap_6lbr.h +++ b/source/6LoWPAN/ws/ws_bootstrap_6lbr.h @@ -22,6 +22,7 @@ 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); void ws_bootstrap_6lbr_asynch_confirm(struct protocol_interface_info_entry *interface, uint8_t asynch_message); +bool ws_bootstrap_6lbr_eapol_relay_state_active(protocol_interface_info_entry_t *cur); void ws_bootstrap_6lbr_event_handler(protocol_interface_info_entry_t *cur, arm_event_s *event); void ws_bootstrap_6lbr_state_machine(protocol_interface_info_entry_t *cur); void ws_bootstrap_6lbr_seconds_timer(protocol_interface_info_entry_t *cur, uint32_t seconds); @@ -32,6 +33,7 @@ void ws_bootstrap_6lbr_seconds_timer(protocol_interface_info_entry_t *cur, uint3 #define ws_bootstrap_6lbr_asynch_ind(cur, data, ie_ext, message_type) ((void) 0) #define ws_bootstrap_6lbr_asynch_confirm(interface, asynch_message) ((void) 0) +#define ws_bootstrap_6lbr_eapol_relay_state_active(cur) false #define ws_bootstrap_6lbr_event_handler(cur, event) ((void) 0) #define ws_bootstrap_6lbr_state_machine(cur) ((void) 0) #define ws_bootstrap_6lbr_seconds_timer(cur, seconds) ((void) 0) diff --git a/source/6LoWPAN/ws/ws_bootstrap_lfn.c b/source/6LoWPAN/ws/ws_bootstrap_6ln.c similarity index 57% rename from source/6LoWPAN/ws/ws_bootstrap_lfn.c rename to source/6LoWPAN/ws/ws_bootstrap_6ln.c index 7e0a46cc49..824cb19646 100644 --- a/source/6LoWPAN/ws/ws_bootstrap_lfn.c +++ b/source/6LoWPAN/ws/ws_bootstrap_6ln.c @@ -85,7 +85,7 @@ #define TRACE_GROUP "wsbs" -void ws_bootstrap_lfn_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) +void ws_bootstrap_6ln_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) { (void)ie_ext; // Store weakest heard packet RSSI @@ -101,13 +101,20 @@ void ws_bootstrap_lfn_asynch_ind(struct protocol_interface_info_entry *cur, cons tr_warn("Wi-SUN LFN Mode received message id: %x", message_type); } -void ws_bootstrap_lfn_asynch_confirm(struct protocol_interface_info_entry *interface, uint8_t asynch_message) +void ws_bootstrap_6ln_asynch_confirm(struct protocol_interface_info_entry *interface, uint8_t asynch_message) { (void)asynch_message; ws_stats_update(interface, STATS_WS_ASYNCH_TX, 1); } -void ws_bootstrap_lfn_event_handler(protocol_interface_info_entry_t *cur, arm_event_s *event) +bool ws_bootstrap_6ln_eapol_relay_state_active(protocol_interface_info_entry_t *cur) +{ + (void) cur; + + return false; +} + +void ws_bootstrap_6ln_event_handler(protocol_interface_info_entry_t *cur, arm_event_s *event) { (void)cur; ws_bootsrap_event_type_e event_type; @@ -130,7 +137,7 @@ void ws_bootstrap_lfn_event_handler(protocol_interface_info_entry_t *cur, arm_ev } } -void ws_bootstrap_lfn_state_machine(protocol_interface_info_entry_t *cur) +void ws_bootstrap_6ln_state_machine(protocol_interface_info_entry_t *cur) { switch (cur->nwk_bootstrap_state) { @@ -162,11 +169,111 @@ void ws_bootstrap_lfn_state_machine(protocol_interface_info_entry_t *cur) } } -void ws_bootstrap_lfn_seconds_timer(protocol_interface_info_entry_t *cur, uint32_t seconds) +void ws_bootstrap_6ln_seconds_timer(protocol_interface_info_entry_t *cur, uint32_t seconds) { (void)cur; (void)seconds; } +int8_t ws_bootstrap_6ln_up(protocol_interface_info_entry_t *cur) +{ + int8_t ret_val = -1; + + if (!cur) { + return -1; + } + + if ((cur->configure_flags & INTERFACE_SETUP_MASK) != INTERFACE_SETUP_READY) { + tr_error("Interface not yet fully configured"); + return -2; + } + if (ws_bootstrap_fhss_initialize(cur) != 0) { + tr_error("fhss initialization failed"); + return -3; + } + if (cur->bootsrap_mode == ARM_NWK_BOOTSRAP_MODE_6LoWPAN_BORDER_ROUTER) { + //BBR init like NVM read + ws_bbr_init(cur); + } + // Save FHSS api + cur->ws_info->fhss_api = ns_sw_mac_get_fhss_api(cur->mac_api); + + ws_bootstrap_ll_address_validate(cur); + + addr_interface_set_ll64(cur, NULL); + cur->nwk_nd_re_scan_count = 0; + // Trigger discovery for bootstrap + ret_val = nwk_6lowpan_up(cur); + if (ret_val) { + goto cleanup; + } + + /* Wi-sun will trig event for stamechine this timer must be zero on init */ + cur->bootsrap_state_machine_cnt = 0; + /* Disable SLLAO send/mandatory receive with the ARO */ + cur->ipv6_neighbour_cache.use_eui64_as_slla_in_aro = true; + /* Omit sending of NA if ARO SUCCESS */ + cur->ipv6_neighbour_cache.omit_na_aro_success = true; + /* Omit sending of NA and consider ACK to be success */ + cur->ipv6_neighbour_cache.omit_na = true; + // do not process AROs from NA. This is overriden by Wi-SUN specific failure handling + cur->ipv6_neighbour_cache.recv_na_aro = false; + /* Disable NUD Probes */ + cur->ipv6_neighbour_cache.send_nud_probes = false; + cur->ipv6_neighbour_cache.probe_avoided_routers = true; + /*Replace NS handler to disable multicast address queries */ + cur->if_ns_transmit = ws_bootstrap_nd_ns_transmit; + + // Configure memory limits and garbage collection values; + ws_bootstrap_memory_configuration(); + ws_nud_table_reset(cur); + + ws_bootstrap_candidate_table_reset(cur); + // Zero uptime counters + cur->ws_info->uptime = 0; + cur->ws_info->authentication_time = 0; + cur->ws_info->connected_time = 0; + + blacklist_params_set( + WS_BLACKLIST_ENTRY_LIFETIME, + WS_BLACKLIST_TIMER_MAX_TIMEOUT, + WS_BLACKLIST_TIMER_TIMEOUT, + WS_BLACKLIST_ENTRY_MAX_NBR, + WS_BLACKLIST_PURGE_NBR, + WS_BLACKLIST_PURGE_TIMER_TIMEOUT); + + ws_bootstrap_event_discovery_start(cur); + + return 0; +cleanup: + return ret_val; +} + +int8_t ws_bootstrap_6ln_down(protocol_interface_info_entry_t *cur) +{ + if (!cur || !(cur->lowpan_info & INTERFACE_NWK_ACTIVE)) { + return -1; + } + + tr_info("Wi-SUN ifdown"); + // Reset MAC for safe upper layer memory free + protocol_mac_reset(cur); + ns_sw_mac_fhss_unregister(cur->mac_api); + ns_fhss_delete(cur->ws_info->fhss_api); + cur->ws_info->fhss_api = NULL; + // Reset WS information + ws_bootstrap_asynch_trickle_stop(cur); + ws_llc_reset(cur); + if (nd_proxy_downstream_interface_unregister(cur->id) != 0) { + tr_warn("nd proxy unregister failed"); + } + ws_nud_table_reset(cur); + ws_pae_controller_stop(cur); + ws_bootstrap_candidate_table_reset(cur); + blacklist_clear(); + cur->if_common_forwarding_out_cb = NULL; + + return nwk_6lowpan_down(cur); +} #endif //HAVE_WS_BORDER_ROUTER && HAVE_WS diff --git a/source/6LoWPAN/ws/ws_bootstrap_6ln.h b/source/6LoWPAN/ws/ws_bootstrap_6ln.h new file mode 100644 index 0000000000..0b9edeffdc --- /dev/null +++ b/source/6LoWPAN/ws/ws_bootstrap_6ln.h @@ -0,0 +1,51 @@ +/* + * 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. + */ + +#ifndef WS_BOOTSTRAP_6LN_H_ +#define WS_BOOTSTRAP_6LN_H_ + +#if defined(HAVE_WS) && defined(HAVE_WS_HOST) + +void ws_bootstrap_6ln_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); +void ws_bootstrap_6ln_asynch_confirm(struct protocol_interface_info_entry *interface, uint8_t asynch_message); +bool ws_bootstrap_6ln_eapol_relay_state_active(protocol_interface_info_entry_t *cur); +void ws_bootstrap_6ln_event_handler(protocol_interface_info_entry_t *cur, arm_event_s *event); +void ws_bootstrap_6ln_state_machine(protocol_interface_info_entry_t *cur); +void ws_bootstrap_6ln_seconds_timer(protocol_interface_info_entry_t *cur, uint32_t seconds); + +int8_t ws_bootstrap_6ln_up(protocol_interface_info_entry_t *cur); +int8_t ws_bootstrap_6ln_down(protocol_interface_info_entry_t *cur); + +#define wisun_mode_host(cur) (cur->bootsrap_mode == ARM_NWK_BOOTSRAP_MODE_6LoWPAN_HOST) + +#else + +#define ws_bootstrap_6lr_asynch_ind(cur, data, ie_ext, message_type) ((void) 0) +#define ws_bootstrap_6lr_asynch_confirm(interface, asynch_message) ((void) 0) +#define ws_bootstrap_6ln_eapol_relay_state_active(false) false +#define ws_bootstrap_6lr_event_handler(cur, event) ((void) 0) +#define ws_bootstrap_6ln_state_machine(cur) ((void) 0) +#define ws_bootstrap_6ln_seconds_timer(cur, seconds) ((void) 0) + +#define ws_bootstrap_6ln_up(cur) +#define ws_bootstrap_6ln_down(cur) + +#define wisun_mode_host(cur) (false) + +#endif //HAVE_WS + +#endif /* WS_BOOTSTRAP_6LN_H_ */ diff --git a/source/6LoWPAN/ws/ws_bootstrap_6lr.c b/source/6LoWPAN/ws/ws_bootstrap_6lr.c new file mode 100644 index 0000000000..d7a5cf8d81 --- /dev/null +++ b/source/6LoWPAN/ws/ws_bootstrap_6lr.c @@ -0,0 +1,1477 @@ +/* + * 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 +#include "nsconfig.h" +#if defined(HAVE_WS) && defined(HAVE_WS_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_bootstrap_6lr.h" +#include "6LoWPAN/ws/ws_bootstrap_ffn.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 void ws_bootstrap_6lr_address_update(protocol_interface_info_entry_t *interface); +static void ws_bootstrap_6lr_parent_confirm(protocol_interface_info_entry_t *cur, struct rpl_instance *instance); +static struct rpl_instance *ws_bootstrap_6lr_get_rpl_instance(protocol_interface_info_entry_t *cur); +static uint16_t ws_bootstrap_6lr_rank_get(protocol_interface_info_entry_t *cur); +static uint16_t ws_bootstrap_6lr_min_rank_inc_get(protocol_interface_info_entry_t *cur); + + +static void ws_bootstrap_6lr_set_fhss_hop(protocol_interface_info_entry_t *cur) +{ + uint16_t own_rank = ws_bootstrap_6lr_rank_get(cur); + uint16_t rank_inc = ws_bootstrap_6lr_min_rank_inc_get(cur); + if (own_rank == 0xffff || rank_inc == 0xffff) { + return; + } + // Calculate own hop count. This method gets inaccurate when hop count increases. + uint8_t own_hop = (own_rank - rank_inc) / rank_inc; + ns_fhss_ws_set_hop_count(cur->ws_info->fhss_api, own_hop); + if (own_hop == 1) { + // Allow transmitting unicast frames only on TX slots in normal mode and always in expedited forwarding mode for first hop + ns_fhss_ws_set_tx_allowance_level(cur->ws_info->fhss_api, WS_TX_SLOT, WS_TX_ALWAYS); + } else { + // Allow transmitting unicast frames only on TX slots in normal and expedited forwarding mode for other hops + ns_fhss_ws_set_tx_allowance_level(cur->ws_info->fhss_api, WS_TX_SLOT, WS_TX_SLOT); + } + tr_debug("own hop: %u, own rank: %u, rank inc: %u", own_hop, own_rank, rank_inc); +} + +static void ws_bootstrap_6lr_ip_stack_addr_clear(protocol_interface_info_entry_t *cur) +{ + tr_debug("ip stack address clear"); + ns_list_foreach_safe(if_address_entry_t, addr, &cur->ip_addresses) { + if (addr->source != ADDR_SOURCE_STATIC && + addr_ipv6_scope(addr->address, cur) > IPV6_SCOPE_LINK_LOCAL) { + // Remove all exept User set address + addr_delete_entry(cur, addr); + } + } +} + +static void ws_bootstrap_6lr_pan_information_store(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, ws_pan_information_t *pan_information) +{ + + parent_info_t *new_entry; + /* Have List of 20 heard neighbours + * Order those as best based on pan cost + * In single pan order based on signal quality + * in single PAN limit the amount of devices to 5 + * If there is no advertisement heard for last hour Clear the neigbour. + */ + + // Discovery state processing + //tr_info("neighbour: addr:%s panid:%x signal:%d", trace_array(data->SrcAddr, 8), data->SrcPANId, data->signal_dbm); + + // Clean old entries + ws_bootstrap_candidate_list_clean(cur, WS_PARENT_LIST_MAX_PAN_IN_DISCOVERY, protocol_core_monotonic_time, data->SrcPANId); + + new_entry = ws_bootstrap_candidate_parent_get(cur, data->SrcAddr, true); + if (!new_entry) { + tr_warn("neighbour creation fail"); + return; + } + // Safe the information + ws_bootstrap_candidate_parent_store(new_entry, data, ws_utt, ws_us, pan_information); + if (!new_entry->link_acceptable) { + // This entry is either poor quality or changed to poor quality link so we will remove this + // Todo in future possibility to try poor link parents if we have not found any good link parents + tr_info("neighbour not accepted: addr:%s panid:%x rsl:%d device_min_sens: %d", trace_array(new_entry->addr, 8), new_entry->pan_id, ws_neighbor_class_rsl_from_dbm_calculate(new_entry->signal_dbm), DEVICE_MIN_SENS); + ns_list_remove(&cur->ws_info->parent_list_reserved, new_entry); + ns_list_add_to_end(&cur->ws_info->parent_list_free, new_entry); + return; + } + // set to the correct place in list + ws_bootstrap_candidate_parent_sort(cur, new_entry); + + return; +} + +static int8_t ws_bootstrap_6lr_fhss_configure(protocol_interface_info_entry_t *cur, bool discovery) +{ + // 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); + ws_bootstrap_fhss_set_defaults(cur, &fhss_configuration); + ws_bootstrap_fhss_configure_channel_masks(cur, &fhss_configuration); + + // Discovery is done using fixed channel + if (discovery) { + fhss_configuration.ws_uc_channel_function = WS_FIXED_CHANNEL; + } else { + fhss_configuration.ws_uc_channel_function = (fhss_ws_channel_functions)cur->ws_info->cfg->fhss.fhss_uc_channel_function; + } + fhss_configuration.ws_bc_channel_function = WS_FIXED_CHANNEL; + fhss_configuration.fhss_broadcast_interval = 0; + uint8_t tmp_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); + uint8_t tmp_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); + fhss_configuration.unicast_fixed_channel = tmp_uc_fixed_channel; + fhss_configuration.broadcast_fixed_channel = tmp_bc_fixed_channel; + ns_fhss_ws_configuration_set(cur->ws_info->fhss_api, &fhss_configuration); + ns_fhss_ws_set_hop_count(cur->ws_info->fhss_api, 0xff); + ws_bootstrap_llc_hopping_update(cur, &fhss_configuration); + + return 0; +} + +void ws_bootstrap_6lr_network_discovery_configure(protocol_interface_info_entry_t *cur) +{ + // Reset information to defaults + cur->ws_info->network_pan_id = 0xffff; + + ws_common_regulatory_domain_config(cur, &cur->ws_info->hopping_schdule); + ws_bootstrap_set_domain_rf_config(cur); + ws_bootstrap_6lr_fhss_configure(cur, true); + + //Set Network names, Pan information configure, hopping schedule & GTKHash + ws_llc_set_network_name(cur, (uint8_t *)cur->ws_info->cfg->gen.network_name, strlen(cur->ws_info->cfg->gen.network_name)); +} + +// Start network scan +static void ws_bootstrap_6lr_start_discovery(protocol_interface_info_entry_t *cur) +{ + tr_debug("router discovery start"); + // Remove network keys from MAC + ws_pae_controller_nw_keys_remove(cur); + ws_bootstrap_state_change(cur, ER_ACTIVE_SCAN); + cur->nwk_nd_re_scan_count = 0; + cur->ws_info->configuration_learned = false; + cur->ws_info->pan_timeout_timer = 0; + cur->ws_info->weakest_received_rssi = 0; + + // Clear learned candidate parents + ws_bootstrap_candidate_table_reset(cur); + + // Clear RPL information + rpl_control_free_domain_instances_from_interface(cur); + // Clear EAPOL relay address + ws_eapol_relay_delete(cur); + + // Clear ip stack from old information + ws_bootstrap_ip_stack_reset(cur); + // New network scan started old addresses not assumed valid anymore + ws_bootstrap_6lr_ip_stack_addr_clear(cur); + + if ((cur->lowpan_info & INTERFACE_NWK_BOOTSRAP_ACTIVE) != INTERFACE_NWK_BOOTSRAP_ACTIVE) { + // we have sent bootstrap ready event and now + // restarted discovery so bootstrap down event is sent + cur->lowpan_info |= INTERFACE_NWK_BOOTSRAP_ACTIVE; + ws_bootstrap_network_down(cur); + } + + // Start advertisement solicit trickle and calculate when we are checking the status + cur->ws_info->trickle_pas_running = true; + if (cur->ws_info->trickle_pan_advertisement_solicit.I != cur->ws_info->trickle_params_pan_discovery.Imin) { + // Trickle not reseted so starting a new interval + trickle_start(&cur->ws_info->trickle_pan_advertisement_solicit, &cur->ws_info->trickle_params_pan_discovery); + } + + // Discovery statemachine is checkked after we have sent the Solicit + uint32_t time_to_solicit = 0; + if (cur->ws_info->trickle_pan_advertisement_solicit.t > cur->ws_info->trickle_pan_advertisement_solicit.now) { + time_to_solicit = cur->ws_info->trickle_pan_advertisement_solicit.t - cur->ws_info->trickle_pan_advertisement_solicit.now; + } + + tr_debug("Disc params imin %u, imax %u, expirations %u, k %u PAS Trickle I %u t %u, now %u, c %u", + cur->ws_info->trickle_params_pan_discovery.Imin, cur->ws_info->trickle_params_pan_discovery.Imax, cur->ws_info->trickle_params_pan_discovery.TimerExpirations, cur->ws_info->trickle_params_pan_discovery.k, + cur->ws_info->trickle_pan_advertisement_solicit.I, cur->ws_info->trickle_pan_advertisement_solicit.t, cur->ws_info->trickle_pan_advertisement_solicit.now, cur->ws_info->trickle_pan_advertisement_solicit.c); + + time_to_solicit += cur->ws_info->trickle_params_pan_discovery.Imin + randLIB_get_random_in_range(0, cur->ws_info->trickle_params_pan_discovery.Imin); + + if (time_to_solicit > 0xffff) { + time_to_solicit = 0xffff; + } + cur->bootsrap_state_machine_cnt = time_to_solicit; + + tr_info("Making parent selection in %u s", (cur->bootsrap_state_machine_cnt / 10)); +} + +// Start configuration learning +static void ws_bootstrap_6lr_start_configuration_learn(protocol_interface_info_entry_t *cur) +{ + tr_debug("router configuration learn start"); + ws_bootstrap_state_change(cur, ER_SCAN); + + cur->ws_info->configuration_learned = false; + + // Clear all temporary information + ws_bootstrap_ip_stack_reset(cur); + + cur->ws_info->pas_requests = 0; + //Calculate max time for config learn state + cur->ws_info->pan_config_sol_max_timeout = trickle_timer_max(&cur->ws_info->trickle_params_pan_discovery, PCS_MAX); + // Reset advertisement solicit trickle to start discovering network + cur->ws_info->trickle_pcs_running = true; + trickle_start(&cur->ws_info->trickle_pan_config_solicit, &cur->ws_info->trickle_params_pan_discovery); + trickle_inconsistent_heard(&cur->ws_info->trickle_pan_config_solicit, &cur->ws_info->trickle_params_pan_discovery); +} + +static void ws_bootstrap_6lr_network_configuration_learn(protocol_interface_info_entry_t *cur) +{ + tr_debug("Start using PAN configuration"); + + // Timing information can be modified here + ws_llc_set_pan_information_pointer(cur, &cur->ws_info->pan_information); + uint8_t *gtkhash = ws_pae_controller_gtk_hash_ptr_get(cur); + ws_llc_set_gtkhash(cur, gtkhash); + // TODO update own fhss schedules we are starting to follow first parent + + return; +} + +static void ws_bootstrap_6lr_pan_advertisement_analyse_active(struct protocol_interface_info_entry *cur, ws_pan_information_t *pan_information) +{ + /* In Active state + * + * A consistent transmission is defined as a PAN Advertisement received by a node with PAN ID and + * NETNAME-IE / Network Name matching that of the receiving node, and with a PAN-IE / Routing Cost + * the same or worse than (bigger than or equal to) that of the receiving node. + * + * Inconsistent: + * + * Received Routing Cost is smaller than stored one + * + * A PAN Advertisement received by a node with PAN ID and NETNAME-IE / Network name matching + * that of the receiving node, and PAN-IE / Routing Cost better than (smaller than) that of the receiving node. + * + */ + if (cur->bootsrap_mode == ARM_NWK_BOOTSRAP_MODE_6LoWPAN_BORDER_ROUTER) { + //Border router never set consistent that will guarantee that BR will send advertisment + return; + } +#ifdef WISUN_1_0_ERRATA_FIX + if (pan_information->pan_size == cur->ws_info->pan_information.pan_size) { + //If same pan size information then set consistent value + trickle_consistent_heard(&cur->ws_info->trickle_pan_advertisement); + } +#else + // Wi-SUN 1.0 specified functionality, causes extra inconsistencies when we hear higher rank advertisements + if (pan_information->routing_cost >= ws_bootstrap_routing_cost_calculate(cur)) { + trickle_consistent_heard(&cur->ws_info->trickle_pan_advertisement); + } else { + trickle_inconsistent_heard(&cur->ws_info->trickle_pan_advertisement, &cur->ws_info->trickle_params_pan_discovery); + } +#endif +} + +static void ws_bootstrap_6lr_pan_advertisement_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) +{ + + //Validate Pan Conrfirmation is at packet + ws_pan_information_t pan_information; + if (!ws_wp_nested_pan_read(ie_ext->payloadIeList, ie_ext->payloadIeListLength, &pan_information)) { + // Corrupted + tr_error("No pan information"); + return; + } + + if (ws_us->excluded_channel_ctrl) { + //Validate that we can storage data + if (ws_us->excluded_channel_ctrl == WS_EXC_CHAN_CTRL_BITMASK && ws_us->excluded_channels.mask.mask_len_inline > 32) { + return; + } + } + + // Check pan flags so that it is valid + if (!pan_information.rpl_routing_method) { + // NOT RPL routing + //tr_warn("Not supported routing"); + return; + } + + // Store heard pans and possible candidate parents + ws_bootstrap_6lr_pan_information_store(cur, data, ws_utt, ws_us, &pan_information); + + if (!(ws_bootstrap_state_active(cur) || + ws_bootstrap_state_wait_rpl(cur))) { + // During discovery/eapol/config learn we dont do further processing for advertisements + return; + } + // Active state processing + //tr_debug("Advertisement active"); + + // In active operation less neighbours per pan is allowed + ws_bootstrap_candidate_list_clean(cur, WS_PARENT_LIST_MAX_PAN_IN_ACTIVE, protocol_core_monotonic_time, data->SrcPANId); + + // Check if valid PAN + if (data->SrcPANId != cur->ws_info->network_pan_id) { + return; + } + + // Save route cost for all known neighbors + llc_neighbour_req_t neighbor_info; + neighbor_info.neighbor = NULL; + if (ws_bootstrap_neighbor_info_request(cur, data->SrcAddr, &neighbor_info, false)) { + neighbor_info.ws_neighbor->routing_cost = pan_information.routing_cost; + //Store and search neighbour PCAP info + if (ws_version_1_1(cur)) { + ws_neighbor_class_pcap_ie_store(neighbor_info.ws_neighbor, ie_ext); + } + } + + ws_bootstrap_6lr_pan_advertisement_analyse_active(cur, &pan_information); + + // Learn latest network information + if (cur->bootsrap_mode != ARM_NWK_BOOTSRAP_MODE_6LoWPAN_BORDER_ROUTER && neighbor_info.neighbor) { + uint8_t ll_address[16]; + ws_common_create_ll_address(ll_address, neighbor_info.neighbor->mac64); + + if (rpl_control_is_dodag_parent(cur, ll_address)) { + cur->ws_info->pan_information.pan_size = pan_information.pan_size; + cur->ws_info->pan_information.routing_cost = pan_information.routing_cost; + cur->ws_info->pan_information.rpl_routing_method = pan_information.rpl_routing_method; + cur->ws_info->pan_information.use_parent_bs = pan_information.use_parent_bs; + } + } +} + +static void ws_bootstrap_6lr_pan_advertisement_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) +{ + + (void)data; + (void)ws_utt; + (void)ws_us; + /* + * An inconsistent transmission is defined as: + * A PAN Advertisement Solicit with NETNAME-IE matching that of the receiving node. + */ + trickle_inconsistent_heard(&cur->ws_info->trickle_pan_advertisement, &cur->ws_info->trickle_params_pan_discovery); + /* + * A consistent transmission is defined as + * a PAN Advertisement Solicit with NETNAME-IE / Network Name matching that configured on the receiving node. + */ + trickle_consistent_heard(&cur->ws_info->trickle_pan_advertisement_solicit); + /* + * Optimized PAN discovery to select the parent faster if we hear solicit from someone else + */ + + if (ws_bootstrap_state_discovery(cur) && ws_cfg_network_config_get(cur) <= CONFIG_MEDIUM && + cur->bootsrap_state_machine_cnt > cur->ws_info->trickle_params_pan_discovery.Imin * 2) { + + cur->bootsrap_state_machine_cnt = cur->ws_info->trickle_params_pan_discovery.Imin + randLIB_get_random_in_range(0, cur->ws_info->trickle_params_pan_discovery.Imin); + + tr_info("Making parent selection in %u s", (cur->bootsrap_state_machine_cnt / 10)); + } + + if (ws_bootstrap_state_active(cur) && cur->bootsrap_mode != ARM_NWK_BOOTSRAP_MODE_6LoWPAN_BORDER_ROUTER) { + mac_neighbor_table_entry_t *neighbor = mac_neighbor_table_address_discover(mac_neighbor_info(cur), data->SrcAddr, ADDR_802_15_4_LONG); + if (neighbor && neighbor->link_role == PRIORITY_PARENT_NEIGHBOUR) { + ws_bootstrap_6lr_parent_confirm(cur, NULL); + } + } +} +#ifdef HAVE_WS_VERSION_1_1 +static void ws_bootstrap_6lr_pan_config_lfn_analyze(struct protocol_interface_info_entry *cur, const struct mcps_data_ie_list *ie_ext) +{ + if (!ws_version_1_1(cur) || cur->bootsrap_mode == ARM_NWK_BOOTSRAP_MODE_6LoWPAN_BORDER_ROUTER) { + return; + } + + ws_lfnver_ie_t lfn_version; + if (!ws_wp_nested_lfn_version_read(ie_ext->payloadIeList, ie_ext->payloadIeListLength, &lfn_version)) { + return; // LFN version + } + + //Read LFNGTKHASH + ws_lgtkhash_ie_t ws_lgtkhash; + if (!ws_wp_nested_lgtk_hash_read(ie_ext->payloadIeList, ie_ext->payloadIeListLength, &ws_lgtkhash)) { + return; + } + + if (!cur->ws_info->lfngtk.lfn_version_learned) { + if (!cur->ws_info->configuration_learned) { + trickle_inconsistent_heard(&cur->ws_info->trickle_pan_config, &cur->ws_info->trickle_params_pan_discovery); + } + } else { + if (cur->ws_info->lfngtk.lfn_version == lfn_version.lfn_version) { + return; + } + + if (common_serial_number_greater_16(cur->ws_info->lfngtk.lfn_version, lfn_version.lfn_version)) { + // older version heard ignoring the message + return; + } + } + + cur->ws_info->lfngtk.lfn_version = lfn_version.lfn_version; + + //Clear HASH allways at new first or for first leaned one's + memset(cur->ws_info->lfngtk.lgtkhash, 0, 24); + cur->ws_info->lfngtk.lfn_version_learned = true; + + //Set Active key index and hash inline bits + cur->ws_info->lfngtk.active_key_index = ws_lgtkhash.active_lgtk_index; + cur->ws_info->lfngtk.active_hash_1 = ws_lgtkhash.lgtk0; + cur->ws_info->lfngtk.active_hash_2 = ws_lgtkhash.lgtk1; + cur->ws_info->lfngtk.active_hash_3 = ws_lgtkhash.lgtk2; + + if (cur->ws_info->lfngtk.active_hash_1) { + memcpy(cur->ws_info->lfngtk.lgtkhash, ws_lgtkhash.lgtk0_hash, 8); + } + + if (cur->ws_info->lfngtk.active_hash_2) { + memcpy(cur->ws_info->lfngtk.lgtkhash + 8, ws_lgtkhash.lgtk1_hash, 8); + } + + if (cur->ws_info->lfngtk.active_hash_3) { + memcpy(cur->ws_info->lfngtk.lgtkhash + 16, ws_lgtkhash.lgtk2_hash, 8); + } + //TODO Analyze HASH's and set LFN group key index +} +#endif + + +static void ws_bootstrap_6lr_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) +{ + + uint16_t pan_version; + ws_bs_ie_t ws_bs_ie; + uint8_t *gtkhash_ptr; + + if (data->SrcPANId != cur->ws_info->network_pan_id) { + return; + } + ws_bt_ie_t ws_bt_ie; + if (!ws_wh_bt_read(ie_ext->headerIeList, ie_ext->headerIeListLength, &ws_bt_ie)) { + tr_warn("BT-IE"); + return; + } + + /* + * A consistent transmission is defined as a PAN Configuration with a PAN-ID matching that of the receiving node and + * a PANVER-IE / PAN Version greater than or equal to the receiving node’s current PAN version. + * + * A inconsistent transmission is defined as: + * + * A PAN Configuration with PAN-ID matching that of the receiving node and a + * PANVER-IE / PAN Version that is less than the receiving node’s current PAN version. + */ + + // TODO Add this to neighbor table + // TODO save all information from config message if version number has changed + + if (!ws_wp_nested_pan_version_read(ie_ext->payloadIeList, ie_ext->payloadIeListLength, &pan_version)) { + // Corrupted + tr_warn("no version"); + return; + } + + gtkhash_ptr = ws_wp_nested_gtkhash_read(ie_ext->payloadIeList, ie_ext->payloadIeListLength); + + if (!gtkhash_ptr) { + // Corrupted + tr_error("No gtk hash"); + return; + } + + if (!ws_wp_nested_bs_read(ie_ext->payloadIeList, ie_ext->payloadIeListLength, &ws_bs_ie)) { + // Corrupted + tr_error("No broadcast schedule"); + return; + } + + llc_neighbour_req_t neighbor_info; + bool neighbour_pointer_valid; + + //Validate BSI + if (cur->bootsrap_mode != ARM_NWK_BOOTSRAP_MODE_6LoWPAN_BORDER_ROUTER) { + + if (cur->ws_info->ws_bsi_block.block_time && cur->ws_info->ws_bsi_block.old_bsi == ws_bs_ie.broadcast_schedule_identifier) { + tr_debug("Do not accept a old BSI: %u in time %"PRIu32, cur->ws_info->ws_bsi_block.old_bsi, cur->ws_info->ws_bsi_block.block_time); + //Refresh Block time when hear a old BSI + cur->ws_info->ws_bsi_block.block_time = cur->ws_info->cfg->timing.pan_timeout; + return; + } + + //When Config is learned and USE Parent BS is enabled compare is this new BSI + if (cur->ws_info->configuration_learned && cur->ws_info->pan_information.use_parent_bs && ws_bs_ie.broadcast_schedule_identifier != cur->ws_info->hopping_schdule.fhss_bsi) { + //Accept only next possible BSI number + if ((cur->ws_info->hopping_schdule.fhss_bsi + 1) != ws_bs_ie.broadcast_schedule_identifier) { + tr_debug("Do not accept a unknown BSI: %u", ws_bs_ie.broadcast_schedule_identifier); + } else { + tr_debug("NEW Brodcast Schedule %u...BR rebooted", ws_bs_ie.broadcast_schedule_identifier); + cur->ws_info->ws_bsi_block.block_time = cur->ws_info->cfg->timing.pan_timeout; + cur->ws_info->ws_bsi_block.old_bsi = cur->ws_info->hopping_schdule.fhss_bsi; + ws_bootstrap_event_disconnect(cur, WS_NORMAL_DISCONNECT); + } + return; + } + } + + + if (cur->ws_info->configuration_learned || cur->bootsrap_mode == ARM_NWK_BOOTSRAP_MODE_6LoWPAN_BORDER_ROUTER) { + //If we are border router or learned configuration we only update already learned neighbours. + neighbour_pointer_valid = ws_bootstrap_neighbor_info_request(cur, data->SrcAddr, &neighbor_info, false); + + } else { + neighbour_pointer_valid = ws_bootstrap_neighbor_info_request(cur, data->SrcAddr, &neighbor_info, true); + if (!neighbour_pointer_valid) { + return; + } + ws_bootstrap_neighbor_set_stable(cur, data->SrcAddr); + } + + if (neighbour_pointer_valid) { + //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); + } + + if (cur->ws_info->configuration_learned) { + tr_info("PAN Config analyse own:%d, heard:%d", cur->ws_info->pan_information.pan_version, pan_version); + if (cur->ws_info->pan_information.pan_version == pan_version) { + //Check if Trgigle have been resetted in short time skip this then + if (cur->ws_info->trickle_pc_consistency_block_period == 0) { + // Same version heard so it is consistent + trickle_consistent_heard(&cur->ws_info->trickle_pan_config); + } + + if (neighbour_pointer_valid && neighbor_info.neighbor->link_role == PRIORITY_PARENT_NEIGHBOUR) { + ws_bootstrap_primary_parent_set(cur, &neighbor_info, WS_PARENT_SOFT_SYNCH); + } + // no need to process more +#ifdef HAVE_WS_VERSION_1_1 + ws_bootstrap_6lr_pan_config_lfn_analyze(cur, ie_ext); +#endif + return; + } else { + // received version is different so we need to reset the trickle + trickle_inconsistent_heard(&cur->ws_info->trickle_pan_config, &cur->ws_info->trickle_params_pan_discovery); + if (neighbour_pointer_valid && neighbor_info.neighbor->link_role == PRIORITY_PARENT_NEIGHBOUR) { + ws_bootstrap_primary_parent_set(cur, &neighbor_info, WS_PARENT_HARD_SYNCH); + } + if (common_serial_number_greater_16(cur->ws_info->pan_information.pan_version, pan_version)) { + // older version heard ignoring the message + return; + } + cur->ws_info->trickle_pc_consistency_block_period = WS_CONFIG_CONSISTENT_FILTER_PERIOD; + } + } + + if (cur->bootsrap_mode == ARM_NWK_BOOTSRAP_MODE_6LoWPAN_BORDER_ROUTER) { + //Border router does not learn network information + return; + } + + /* + * Learn new information from neighbor + */ + tr_info("Updated PAN configuration own:%d, heard:%d", cur->ws_info->pan_information.pan_version, pan_version); + + // restart PAN version timer + //Check Here Do we have a selected Primary parent + if (!cur->ws_info->configuration_learned || cur->ws_info->rpl_state == RPL_EVENT_DAO_DONE) { + ws_common_border_router_alive_update(cur); + } + + cur->ws_info->pan_information.pan_version = pan_version; + + ws_pae_controller_gtk_hash_update(cur, gtkhash_ptr); + + ws_pae_controller_nw_key_index_update(cur, data->Key.KeyIndex - 1); + +#ifdef HAVE_WS_VERSION_1_1 + ws_bootstrap_6lr_pan_config_lfn_analyze(cur, ie_ext); +#endif + + if (!cur->ws_info->configuration_learned) { + // Generate own hopping schedules Follow first parent broadcast and plans and also use same unicast dwell + tr_info("learn network configuration"); + cur->ws_info->configuration_learned = true; + // return to state machine after 1-2 s + cur->bootsrap_state_machine_cnt = randLIB_get_random_in_range(10, 20); + // enable frequency hopping for unicast channel and start listening first neighbour + ws_bootstrap_primary_parent_set(cur, &neighbor_info, WS_PARENT_HARD_SYNCH); + // set neighbor as priority parent clear if there is others + protocol_6lowpan_neighbor_priority_clear_all(cur->id, PRIORITY_1ST); + neighbor_info.neighbor->link_role = PRIORITY_PARENT_NEIGHBOUR; + } +} + +static void ws_bootstrap_6lr_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) +{ + if (data->SrcPANId != cur->ws_info->network_pan_id) { + return; + } + + /* TODO smart neighbour process + * + * Unsecure packet we cant trust the device? + * + * Question mark in specification also present, now we create neighbour. + * this is moved in future to NS/ND processing triggered by RPL + * + */ + + llc_neighbour_req_t neighbor_info; + 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); + } + + if (ws_bootstrap_state_active(cur) && cur->bootsrap_mode != ARM_NWK_BOOTSRAP_MODE_6LoWPAN_BORDER_ROUTER) { + mac_neighbor_table_entry_t *neighbor = mac_neighbor_table_address_discover(mac_neighbor_info(cur), data->SrcAddr, ADDR_802_15_4_LONG); + if (neighbor && neighbor->link_role == PRIORITY_PARENT_NEIGHBOUR) { + ws_bootstrap_6lr_parent_confirm(cur, NULL); + } + } + + /* + * A consistent transmission is defined as a PAN Configuration Solicit with + * a PAN-ID matching that of the receiving node and a NETNAME-IE / Network Name + * matching that configured on the receiving node. + */ + trickle_consistent_heard(&cur->ws_info->trickle_pan_config_solicit); + /* + * inconsistent transmission is defined as either: + * A PAN Configuration Solicit with a PAN-ID matching that of the receiving node and + * a NETNAME-IE / Network Name matching the network name configured on the receiving + */ + trickle_inconsistent_heard(&cur->ws_info->trickle_pan_config, &cur->ws_info->trickle_params_pan_discovery); +} + + +void ws_bootstrap_6lr_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); + ws_bootstrap_6lr_pan_advertisement_analyse(cur, data, ie_ext, &ws_utt, &ws_us); + 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); + ws_bootstrap_6lr_pan_advertisement_solicit_analyse(cur, data, &ws_utt, &ws_us); + 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_6lr_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); + ws_bootstrap_6lr_pan_config_solicit_analyse(cur, data, &ws_utt, &ws_us); + default: + // Unknown message do not process + break; + } +} + +void ws_bootstrap_6lr_asynch_confirm(struct protocol_interface_info_entry *interface, uint8_t asynch_message) +{ + (void)asynch_message; + ws_stats_update(interface, STATS_WS_ASYNCH_TX, 1); +} + +bool ws_bootstrap_6lr_eapol_relay_state_active(protocol_interface_info_entry_t *cur) +{ + if (cur->nwk_bootstrap_state == ER_BOOTSRAP_DONE) { + return true; + } + + return false; +} + +static struct rpl_instance *ws_bootstrap_6lr_get_rpl_instance(protocol_interface_info_entry_t *cur) +{ + if (!cur || !cur->rpl_domain) { + return NULL; + } + struct rpl_instance *best_instance = NULL; + ns_list_foreach(struct rpl_instance, instance, &cur->rpl_domain->instances) { + best_instance = instance; + // Select best grounded and lowest rank? But there should be only one really + } + return best_instance; +} + +static uint16_t ws_bootstrap_6lr_rank_get(protocol_interface_info_entry_t *cur) +{ + struct rpl_instance *rpl_instance = ws_bootstrap_6lr_get_rpl_instance(cur); + if (!rpl_instance) { + return 0xffff; + } + return rpl_control_current_rank(rpl_instance); +} + +static uint16_t ws_bootstrap_6lr_min_rank_inc_get(protocol_interface_info_entry_t *cur) +{ + struct rpl_instance *rpl_instance = ws_bootstrap_6lr_get_rpl_instance(cur); + if (!rpl_instance) { + return 0xffff; + } + struct rpl_dodag_info_t dodag_info; + if (!rpl_control_read_dodag_info(rpl_instance, &dodag_info)) { + return 0xffff; + } + return dodag_info.dag_min_hop_rank_inc; +} + +void ws_bootstrap_6lr_address_registration_update(protocol_interface_info_entry_t *interface, const uint8_t addr[16]) +{ + rpl_control_register_address(interface, addr); + // Timer is used only to track full registrations + + if (addr != NULL && interface->ws_info->aro_registration_timer) { + // Single address update and timer is running + return; + } + + if (interface->ws_info->aro_registration_timer == 0) { + // Timer expired and check if we have valid address to register + ns_list_foreach(if_address_entry_t, address, &interface->ip_addresses) { + if (!addr_is_ipv6_link_local(address->address)) { + // We have still valid addresses let the timer run for next period + tr_info("ARO registration timer start"); + interface->ws_info->aro_registration_timer = WS_NEIGHBOR_NUD_TIMEOUT; + return; + } + } + } +} + +static void ws_bootstrap_6lr_address_update(protocol_interface_info_entry_t *interface) +{ + tr_info("RPL parent update ... register ARO"); + ws_bootstrap_6lr_address_registration_update(interface, NULL); +} + +static void ws_bootstrap_6lr_parent_confirm(protocol_interface_info_entry_t *cur, struct rpl_instance *instance) +{ + /* Possible problem with the parent connection + * Give some time for parent to rejoin and confirm the connection with ARO and DAO + */ + const rpl_dodag_conf_int_t *config = NULL; + uint32_t Imin_secs = 0; + + if (!ws_bootstrap_state_active(cur)) { + // If we are not in Active state no need to confirm parent + return; + } + + tr_info("RPL parent confirm"); + + if (!instance) { + // If we dont have instance we take any available to get reference + instance = rpl_control_enumerate_instances(cur->rpl_domain, NULL); + } + + if (instance) { + config = rpl_control_get_dodag_config(instance); + } + + if (config) { + //dio imin Period caluclate in seconds + uint32_t Imin_ms = config->dio_interval_min < 32 ? (1ul << config->dio_interval_min) : 0xfffffffful; + //Covert to seconds and multiple by 2 so we give time to recovery so divide by 500 do that operation + Imin_secs = (Imin_ms + 499) / 500; + + if (Imin_secs > 0xffff) { + Imin_secs = 0xffff; + } + } + if (Imin_secs == 0) { + // If we dont have RPL configuration we assume conservative value + Imin_secs = 60; + } + + /*Speed up the ARO registration*/ + if (cur->ws_info->aro_registration_timer > Imin_secs) { + cur->ws_info->aro_registration_timer = Imin_secs; + } +} + + +void ws_bootstrap_6lr_primary_parent_update(protocol_interface_info_entry_t *interface, mac_neighbor_table_entry_t *neighbor) +{ + if (interface->ws_info) { + llc_neighbour_req_t neighbor_info; + neighbor_info.neighbor = neighbor; + neighbor_info.ws_neighbor = ws_neighbor_class_entry_get(&interface->ws_info->neighbor_storage, neighbor->index); + ws_bootstrap_primary_parent_set(interface, &neighbor_info, WS_PARENT_HARD_SYNCH); + uint8_t link_local_address[16]; + ws_common_create_ll_address(link_local_address, neighbor->mac64); + dhcp_client_server_address_update(interface->id, NULL, link_local_address); + + ws_bootstrap_6lr_secondary_parent_update(interface); + } +} + +void ws_bootstrap_6lr_secondary_parent_update(protocol_interface_info_entry_t *interface) +{ + if (interface->ws_info) { + ns_list_foreach(if_address_entry_t, address, &interface->ip_addresses) { + if (!addr_is_ipv6_link_local(address->address)) { + ws_bootstrap_6lr_address_update(interface); + } + } + } +} + +static void ws_bootstrap_6lr_rpl_scan_start(protocol_interface_info_entry_t *cur) +{ + tr_debug("Start RPL learn"); + // Stop Trickle timers + ws_bootstrap_asynch_trickle_stop(cur); + + // routers wait until RPL root is contacted + ws_bootstrap_state_change(cur, ER_RPL_SCAN); + // Change state as the state is checked in state machine + cur->ws_info->rpl_state = RPL_EVENT_LOCAL_REPAIR_START; + //For Large network and medium should do passive scan + if (ws_cfg_network_config_get(cur) > CONFIG_SMALL) { + // Set timeout for check to 30 - 60 seconds + cur->bootsrap_state_machine_cnt = randLIB_get_random_in_range(WS_RPL_DIS_INITIAL_TIMEOUT / 2, WS_RPL_DIS_INITIAL_TIMEOUT); + } +} + + +static void ws_bootstrap_6lr_rpl_callback(rpl_event_t event, void *handle) +{ + + protocol_interface_info_entry_t *cur = handle; + if (!cur->rpl_domain || cur->interface_mode != INTERFACE_UP) { + return; + } + + if (event == RPL_EVENT_POISON_FINISHED) { + //If we are waiting poison we will trig Discovery after couple seconds + if (cur->nwk_bootstrap_state == ER_RPL_NETWORK_LEAVING) { + cur->bootsrap_state_machine_cnt = 80; //Give 8 seconds time to send Poison + } + return; + } + + // if waiting for RPL and + if (event == RPL_EVENT_DAO_DONE) { + // Trigger statemachine check + cur->bootsrap_state_machine_cnt = 1; + rpl_dodag_info_t dodag_info; + struct rpl_instance *instance = rpl_control_enumerate_instances(cur->rpl_domain, NULL); + + if (instance && rpl_control_read_dodag_info(instance, &dodag_info)) { + tr_debug("Enable DHCPv6 relay"); + dhcp_relay_agent_enable(cur->id, dodag_info.dodag_id); + + tr_debug("Start EAPOL relay"); + // Set both own port and border router port to 10253 + ws_eapol_relay_start(cur, EAPOL_RELAY_SOCKET_PORT, dodag_info.dodag_id, EAPOL_RELAY_SOCKET_PORT); + // Set network information to PAE + 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); + // Network key is valid, indicate border router IID to controller + ws_pae_controller_nw_key_valid(cur, &dodag_info.dodag_id[8]); + //Update here Suplikant target by validated Primary Parent + if (cur->bootsrap_mode != ARM_NWK_BOOTSRAP_MODE_6LoWPAN_BORDER_ROUTER) { + mac_neighbor_table_entry_t *mac_neighbor = mac_neighbor_entry_get_priority(mac_neighbor_info(cur)); + if (mac_neighbor) { + ws_pae_controller_set_target(cur, cur->ws_info->network_pan_id, mac_neighbor->mac64); + } + } + + // After successful DAO ACK connection to border router is verified + ws_common_border_router_alive_update(cur); + } + + if (!cur->ws_info->trickle_pa_running || !cur->ws_info->trickle_pc_running) { + //Enable wi-sun asynch adverisment + ws_bootstrap_advertise_start(cur); + } + + ws_bootstrap_6lr_set_fhss_hop(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); + } else if (event == RPL_EVENT_LOCAL_REPAIR_NO_MORE_DIS) { + /* + * RPL goes to passive mode, but does not require any extra changed + * + * We could remove our current addresses learned from RPL + * We could send solicit for configuration and then select new parent when those arrive + * + */ + + } else if (event == RPL_EVENT_LOCAL_REPAIR_START) { + tr_debug("RPL local repair start"); + //Disable Async and go to state 4 to confirm parent connection + ws_bootstrap_6lr_parent_confirm(cur, NULL); + // Move to state 4 if we see issues with primary parent + if (ws_bootstrap_state_active(cur)) { + tr_info("Move state 4 to wait parent connection confirmation"); + ws_bootstrap_6lr_rpl_scan_start(cur); + ws_bootstrap_network_down(cur); + } + } else if (event == RPL_EVENT_DAO_PARENT_ADD) { + ws_bootstrap_6lr_address_update(cur); + } + cur->ws_info->rpl_state = event; + tr_info("RPL event %d", event); +} + +static void ws_bootstrap_6lr_rpl_prefix_callback(prefix_entry_t *prefix, void *handle, uint8_t *parent_link_local) +{ + protocol_interface_info_entry_t *cur = (protocol_interface_info_entry_t *) handle; + /* Check if A-Flag. + * A RPL node may use this option for the purpose of Stateless Address Autoconfiguration (SLAAC) + * from a prefix advertised by a parent. + */ + if (prefix->options & PIO_A) { + + if (parent_link_local) { + if (icmpv6_slaac_prefix_update(cur, prefix->prefix, prefix->prefix_len, prefix->lifetime, prefix->preftime) != 0) { + ipv6_interface_slaac_handler(cur, prefix->prefix, prefix->prefix_len, prefix->lifetime, prefix->preftime); + /* + * Give SLAAC addresses a different label and low precedence to indicate that + * they probably shouldn't be used for external traffic. SLAAC use in Wi-SUN is non-standard, + * and we use it for mesh-local traffic we should prefer any DHCP-assigned addresses + * for talking to the outside world + * + */ + addr_policy_table_add_entry(prefix->prefix, prefix->prefix_len, 2, WS_NON_PREFFRED_LABEL); + } + } else { + icmpv6_slaac_prefix_update(cur, prefix->prefix, prefix->prefix_len, 0, 0); + } + } else if (prefix->prefix_len) { + // Create new address using DHCP + if (parent_link_local) { + ws_dhcp_client_address_request(cur, prefix->prefix, parent_link_local); + } else { + /* Deprecate address and remove client */ + tr_debug("Prefix invalidation %s", trace_ipv6(prefix->prefix)); + dhcp_client_global_address_delete(cur->id, NULL, prefix->prefix); + } + } +} + +static bool ws_bootstrap_6lr_rpl_candidate_soft_filtering(protocol_interface_info_entry_t *cur, struct rpl_instance *instance) +{ + //Already many candidates + uint16_t candidate_list_size = rpl_control_candidate_list_size(cur, instance); + if (candidate_list_size >= cur->ws_info->cfg->gen.rpl_parent_candidate_max) { + return false; + } + + uint16_t selected_parents = rpl_control_selected_parent_count(cur, instance); + + //Already enough selected candidates + if (selected_parents >= cur->ws_info->cfg->gen.rpl_selected_parent_max) { + candidate_list_size -= selected_parents; + if (candidate_list_size >= 2) { + //We have more candidates than selected + return false; + } + } + + return true; +} + +static bool ws_bootstrap_6lr_rpl_new_parent_callback(uint8_t *ll_parent_address, void *handle, struct rpl_instance *instance, uint16_t candidate_rank) +{ + + protocol_interface_info_entry_t *cur = handle; + if (!cur->rpl_domain || cur->interface_mode != INTERFACE_UP) { + return false; + } + + if (blacklist_reject(ll_parent_address)) { + // Rejected by blacklist + return false; + } + + uint8_t mac64[10]; + //bool replace_ok = false; + //bool create_ok = false; + llc_neighbour_req_t neigh_buffer; + + //Discover neigh ready here for possible ETX validate + memcpy(mac64, ll_parent_address + 8, 8); + mac64[0] ^= 2; + + + ws_bootstrap_neighbor_info_request(cur, mac64, &neigh_buffer, false); + //Discover Multicast temporary entry for create neighbour table entry for new candidate + ws_neighbor_temp_class_t *entry = ws_llc_get_multicast_temp_entry(cur, mac64); + + if (!ws_bootstrap_6lr_rpl_candidate_soft_filtering(cur, instance)) { + + //Acept only better than own rank here + if (candidate_rank >= rpl_control_current_rank(instance)) { + //Do not accept no more siblings + return false; + } + + uint16_t candidate_list_size = rpl_control_candidate_list_size(cur, instance); + if (candidate_list_size > cur->ws_info->cfg->gen.rpl_parent_candidate_max + 1) { + //Accept only 1 better 1 time + return false; + } + + if (!neigh_buffer.neighbor) { + //Do not accept any new in that Place + return false; + } + + uint8_t replacing[16]; + //Accept Know neighbour if it is enough good + if (!rpl_control_find_worst_neighbor(cur, instance, replacing)) { + return false; + } + // +2 Is for PAN ID space + memcpy(mac64, replacing + 8, 8); + mac64[0] ^= 2; + + if (ws_local_etx_read(cur, ADDR_802_15_4_LONG, mac64) == 0xffff) { + //Not probed yet because ETX is 0xffff + return false; + } + + uint16_t etx = 0; + if (neigh_buffer.neighbor) { + etx = ws_local_etx_read(cur, ADDR_802_15_4_LONG, neigh_buffer.neighbor->mac64); + } + + // Accept now only better one's when max candidates selected and max candidate list size is reached + return rpl_possible_better_candidate(cur, instance, replacing, candidate_rank, etx); + } + + //Neighbour allready + if (neigh_buffer.neighbor) { + return true; + } + + if (!entry) { + //No Multicast Entry Available + return false; + } + + //Create entry + bool create_ok = ws_bootstrap_neighbor_info_request(cur, entry->mac64, &neigh_buffer, true); + if (create_ok) { + ws_neighbor_class_entry_t *ws_neigh = neigh_buffer.ws_neighbor; + ws_bootstrap_neighbor_set_stable(cur, entry->mac64); + //Copy fhss temporary data + *ws_neigh = entry->neigh_info_list; + mac_neighbor_table_trusted_neighbor(mac_neighbor_info(cur), neigh_buffer.neighbor, true); + } + ws_llc_free_multicast_temp_entry(cur, entry); + +#if 0 +neigh_create_ok: + + if (create_ok && replace_ok) { + //Try remove here when accepted new better one possible + tr_debug("Remove %s by %s", trace_ipv6(replacing), trace_ipv6(ll_parent_address)); + rpl_control_neighbor_delete_from_instance(cur, instance, replacing); + } +#endif + return create_ok; +} + +static void ws_bootstrap_6lr_rpl_parent_dis_callback(const uint8_t *ll_parent_address, void *handle, struct rpl_instance *instance) +{ + (void) ll_parent_address; + protocol_interface_info_entry_t *cur = handle; + if (!cur->rpl_domain || cur->interface_mode != INTERFACE_UP) { + return; + } + //Multicast DIS from parent indicate that Parent is not valid in short time window possible + ws_bootstrap_6lr_parent_confirm(cur, instance); +} + + +void ws_bootstrap_6lr_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); + + ws_pae_controller_supp_init(cur); + // Clear learned neighbours + ws_bootstrap_neighbor_list_clean(cur); + // Configure LLC for network discovery + ws_bootstrap_6lr_network_discovery_configure(cur); + ws_bootstrap_fhss_activate(cur); + // Set retry configuration for discovery state + ws_bootstrap_configure_max_retries(cur, WS_MAX_FRAME_RETRIES_BOOTSTRAP); + // Set TX failure request restart configuration for discovery state + ws_bootstrap_configure_data_request_restart(cur, WS_CCA_REQUEST_RESTART_MAX, WS_TX_REQUEST_RESTART_MAX_BOOTSTRAP, 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); + // Start network scan + ws_bootstrap_6lr_start_discovery(cur); + break; + + case WS_CONFIGURATION_START: + tr_info("Configuration start"); + // Old configuration is considered invalid stopping all + ws_bootstrap_asynch_trickle_stop(cur); + + // Build list of possible neighbours and learn first broadcast schedule + + ws_bootstrap_6lr_start_configuration_learn(cur); + 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_ffn_rpl_configure(cur); + // Configure RPL for Node. + rpl_control_set_callback(protocol_6lowpan_rpl_domain, ws_bootstrap_6lr_rpl_callback, ws_bootstrap_6lr_rpl_prefix_callback, ws_bootstrap_6lr_rpl_new_parent_callback, ws_bootstrap_6lr_rpl_parent_dis_callback, cur); + rpl_control_set_memory_limits(WS_NODE_RPL_SOFT_MEM_LIMIT, WS_NODE_RPL_HARD_MEM_LIMIT); + + ws_bootstrap_network_start(cur); + // Wait for RPL start + ws_bootstrap_6lr_rpl_scan_start(cur); + /* While in Join State 4, if a non Border Router determines it has been unable to communicate with the PAN Border + * Router for an interval of PAN_TIMEOUT, a node MUST assume failure of the PAN Border Router and MUST + * Transition to Join State 1 + */ + ws_common_border_router_alive_update(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; + } +} + +/* + * Statemachine state functions + * */ + +static void ws_bootstrap_6lr_network_scan_process(protocol_interface_info_entry_t *cur) +{ + + parent_info_t *selected_parent_ptr; + + tr_debug("analyze network discovery result"); + +select_best_candidate: + selected_parent_ptr = ws_bootstrap_candidate_parent_get_best(cur); + + if (!selected_parent_ptr) { + // Configure LLC for network discovery + ws_bootstrap_6lr_network_discovery_configure(cur); + // randomize new channel and start MAC + ws_bootstrap_fhss_activate(cur); + // Next check will be after one trickle + uint32_t random_start = cur->ws_info->trickle_params_pan_discovery.Imin + randLIB_get_random_in_range(0, cur->ws_info->trickle_params_pan_discovery.Imin); + if (random_start > 0xffff) { + random_start = 0xffff; + } + cur->bootsrap_state_machine_cnt = random_start; + + tr_info("Making parent selection in %u s", (cur->bootsrap_state_machine_cnt / 10)); + return; + } + tr_info("selected parent:%s panid %u", trace_array(selected_parent_ptr->addr, 8), selected_parent_ptr->pan_id); + + if (ws_bootstrap_neighbor_set(cur, selected_parent_ptr, false) < 0) { + goto select_best_candidate; + } + + ws_pae_controller_set_target(cur, selected_parent_ptr->pan_id, selected_parent_ptr->addr); // temporary!!! store since auth + ws_bootstrap_event_authentication_start(cur); + return; +} + +static void ws_bootstrap_6lr_configure_process(protocol_interface_info_entry_t *cur) +{ + + if (cur->ws_info->configuration_learned) { + ws_bootstrap_6lr_network_configuration_learn(cur); + ws_bootstrap_event_operation_start(cur); + return; + } + return; +} + +void ws_bootstrap_6lr_rpl_wait_process(protocol_interface_info_entry_t *cur) +{ + + if (cur->ws_info->rpl_state == RPL_EVENT_DAO_DONE) { + // RPL routing is ready + cur->ws_info->connected_time = cur->ws_info->uptime; + ws_bootstrap_event_routing_ready(cur); + } else if (!rpl_control_have_dodag(cur->rpl_domain)) { + // RPL not ready send DIS message if possible + if (cur->bootsrap_mode == ARM_NWK_BOOTSRAP_MODE_6LoWPAN_ROUTER) { + // TODO Multicast DIS should be sent only if no DIO heard for some time + rpl_control_transmit_dis(cur->rpl_domain, cur, 0, 0, NULL, 0, ADDR_LINK_LOCAL_ALL_RPL_NODES); + } + // set timer for next DIS + cur->bootsrap_state_machine_cnt = randLIB_get_random_in_range(WS_RPL_DIS_TIMEOUT / 2, WS_RPL_DIS_TIMEOUT); + } + return; +} + + +/* + * State machine + */ + +void ws_bootstrap_6lr_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"); + ws_bootstrap_6lr_network_scan_process(cur); + break; + case ER_SCAN: + tr_debug("WS SM:configuration Scan"); + ws_bootstrap_6lr_configure_process(cur); + break; + case ER_PANA_AUTH: + tr_info("authentication start"); + // Advertisements stopped during the EAPOL + ws_bootstrap_asynch_trickle_stop(cur); + ws_bootstrap_6lr_fhss_configure(cur, false); + int8_t new_default = cur->ws_info->weakest_received_rssi - 1; + if ((new_default < CCA_DEFAULT_DBM) && (new_default >= CCA_LOW_LIMIT) && (new_default <= CCA_HIGH_LIMIT)) { + // Restart automatic CCA threshold using weakest received RSSI as new default + mac_helper_start_auto_cca_threshold(cur->id, cur->ws_info->hopping_schdule.number_of_channels, cur->ws_info->weakest_received_rssi - 1, CCA_HIGH_LIMIT, CCA_LOW_LIMIT); + } + ws_bootstrap_start_authentication(cur); + break; + case ER_RPL_SCAN: + tr_debug("WS SM:Wait RPL to contact DODAG root"); + ws_bootstrap_6lr_rpl_wait_process(cur); + 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_6lr_seconds_timer(protocol_interface_info_entry_t *cur, uint32_t seconds) +{ + /* Border router keep alive check + */ + if (cur->ws_info->pan_timeout_timer) { + // PAN version timer running + if (cur->ws_info->pan_timeout_timer > seconds) { + cur->ws_info->pan_timeout_timer -= seconds; + if (cur->ws_info->pan_timeout_timer < cur->ws_info->cfg->timing.pan_timeout / 10) { + /* pan timeout is closing need to verify that DAO is tested before the pan times out. + This will give some extra time for RPL to find better parents. + Border router liveliness can be checked from version number change or from successful DAO registrations + in this case there has not been any version number changes during this PAN lifetime. + */ + rpl_control_dao_timeout(cur->rpl_domain, 20); + } + } else { + // Border router has timed out + //Clear Timeout timer + cur->ws_info->pan_timeout_timer = 0; + tr_warn("Border router has timed out"); + ws_bootstrap_event_disconnect(cur, WS_FAST_DISCONNECT); + } + } + if (cur->ws_info->aro_registration_timer) { + if (cur->ws_info->aro_registration_timer > seconds) { + cur->ws_info->aro_registration_timer -= seconds; + } else { + // Update all addressess. This function will update the timer value if needed + cur->ws_info->aro_registration_timer = 0; + ws_bootstrap_6lr_address_registration_update(cur, NULL); + } + } + + if (cur->ws_info->ws_bsi_block.block_time) { + if (cur->ws_info->ws_bsi_block.block_time > seconds) { + cur->ws_info->ws_bsi_block.block_time -= seconds; + } else { + //Clear A BSI blokker + cur->ws_info->ws_bsi_block.block_time = 0; + cur->ws_info->ws_bsi_block.old_bsi = 0; + } + } +} + + +#endif //HAVE_WS_BORDER_ROUTER && HAVE_WS diff --git a/source/6LoWPAN/ws/ws_bootstrap_6lr.h b/source/6LoWPAN/ws/ws_bootstrap_6lr.h new file mode 100644 index 0000000000..0facfa3d35 --- /dev/null +++ b/source/6LoWPAN/ws/ws_bootstrap_6lr.h @@ -0,0 +1,52 @@ +/* + * 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. + */ + +#ifndef WS_BOOTSTRAP_6LR_H_ +#define WS_BOOTSTRAP_6LR_H_ + +#if defined(HAVE_WS) && defined(HAVE_WS_ROUTER) + +void ws_bootstrap_6lr_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); +void ws_bootstrap_6lr_asynch_confirm(struct protocol_interface_info_entry *interface, uint8_t asynch_message); +bool ws_bootstrap_6lr_eapol_relay_state_active(protocol_interface_info_entry_t *cur); +void ws_bootstrap_6lr_event_handler(protocol_interface_info_entry_t *cur, arm_event_s *event); +void ws_bootstrap_6lr_state_machine(protocol_interface_info_entry_t *cur); +void ws_bootstrap_6lr_seconds_timer(protocol_interface_info_entry_t *cur, uint32_t seconds); + +void ws_bootstrap_6lr_primary_parent_update(protocol_interface_info_entry_t *interface, mac_neighbor_table_entry_t *neighbor); +void ws_bootstrap_6lr_secondary_parent_update(protocol_interface_info_entry_t *interface); +void ws_bootstrap_6lr_address_registration_update(protocol_interface_info_entry_t *interface, const uint8_t addr[16]); + +#define wisun_mode_router(cur) (cur->bootsrap_mode == ARM_NWK_BOOTSRAP_MODE_6LoWPAN_ROUTER) + +#else + +#define ws_bootstrap_6lr_asynch_ind(cur, data, ie_ext, message_type) ((void) 0) +#define ws_bootstrap_6lr_asynch_confirm(interface, asynch_message) ((void) 0) +#define ws_bootstrap_6lr_eapol_relay_state_active false +#define ws_bootstrap_6lr_event_handler(cur, event) ((void) 0) +#define ws_bootstrap_6lr_state_machine(cur) ((void) 0) +#define ws_bootstrap_6lr_seconds_timer(cur, seconds) ((void) 0) +#define ws_bootstrap_6lr_primary_parent_update(interface, neighbor) ((void) 0) +#define ws_bootstrap_6lr_secondary_parent_update(interface) ((void) 0) +#define ws_bootstrap_6lr_address_registration_update(interface, addr) ((void) 0) + +#define wisun_mode_router(cur) (false) + +#endif //HAVE_WS + +#endif /* WS_BOOTSTRAP_6LR_H_ */ diff --git a/source/6LoWPAN/ws/ws_bootstrap_ffn.c b/source/6LoWPAN/ws/ws_bootstrap_ffn.c index 489039abff..ae9dd1315f 100644 --- a/source/6LoWPAN/ws/ws_bootstrap_ffn.c +++ b/source/6LoWPAN/ws/ws_bootstrap_ffn.c @@ -17,7 +17,7 @@ #include #include "nsconfig.h" -#if defined(HAVE_WS) && defined(HAVE_WS_ROUTER) +#ifdef HAVE_WS #include "ns_types.h" #include "ns_trace.h" #include "nsdynmemLIB.h" @@ -62,6 +62,11 @@ #include "6LoWPAN/ws/ws_ie_lib.h" #include "6LoWPAN/ws/ws_stats.h" #include "6LoWPAN/ws/ws_cfg_settings.h" +#include "6LoWPAN/ws/ws_bootstrap_ffn.h" +#include "6LoWPAN/ws/ws_bootstrap_6lbr.h" +#include "6LoWPAN/ws/ws_bootstrap_6lr.h" +#include "6LoWPAN/ws/ws_bootstrap_6ln.h" +#include "6LoWPAN/ws/ws_phy.h" #include "6LoWPAN/lowpan_adaptation_interface.h" #include "Service_Libs/etx/etx.h" #include "Service_Libs/mac_neighbor_table/mac_neighbor_table.h" @@ -84,944 +89,315 @@ #define TRACE_GROUP "wsbs" -static void ws_bootstrap_ffn_ip_stack_addr_clear(protocol_interface_info_entry_t *cur) +static void ws_bootstrap_ffn_dhcp_neighbour_update_cb(int8_t interface_id, uint8_t ll_addr[static 16]); +static void ws_bootstrap_ffn_dhcp_info_notify_cb(int8_t interface, dhcp_option_notify_t *options, dhcp_server_notify_info_t *server_info); + +int8_t ws_bootstrap_ffn_up(protocol_interface_info_entry_t *cur) { - tr_debug("ip stack address clear"); - ns_list_foreach_safe(if_address_entry_t, addr, &cur->ip_addresses) { - if (addr->source != ADDR_SOURCE_STATIC && - addr_ipv6_scope(addr->address, cur) > IPV6_SCOPE_LINK_LOCAL) { - // Remove all exept User set address - addr_delete_entry(cur, addr); - } + int8_t ret_val = -1; + + if (!cur) { + return -1; } -} -static void ws_bootstrap_ffn_pan_information_store(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, ws_pan_information_t *pan_information) -{ - - parent_info_t *new_entry; - /* Have List of 20 heard neighbours - * Order those as best based on pan cost - * In single pan order based on signal quality - * in single PAN limit the amount of devices to 5 - * If there is no advertisement heard for last hour Clear the neigbour. - */ - - // Discovery state processing - //tr_info("neighbour: addr:%s panid:%x signal:%d", trace_array(data->SrcAddr, 8), data->SrcPANId, data->signal_dbm); - - // Clean old entries - ws_bootstrap_candidate_list_clean(cur, WS_PARENT_LIST_MAX_PAN_IN_DISCOVERY, protocol_core_monotonic_time, data->SrcPANId); - - new_entry = ws_bootstrap_candidate_parent_get(cur, data->SrcAddr, true); - if (!new_entry) { - tr_warn("neighbour creation fail"); - return; + if ((cur->configure_flags & INTERFACE_SETUP_MASK) != INTERFACE_SETUP_READY) { + tr_error("Interface not yet fully configured"); + return -2; } - // Safe the information - ws_bootstrap_candidate_parent_store(new_entry, data, ws_utt, ws_us, pan_information); - if (!new_entry->link_acceptable) { - // This entry is either poor quality or changed to poor quality link so we will remove this - // Todo in future possibility to try poor link parents if we have not found any good link parents - tr_info("neighbour not accepted: addr:%s panid:%x rsl:%d device_min_sens: %d", trace_array(new_entry->addr, 8), new_entry->pan_id, ws_neighbor_class_rsl_from_dbm_calculate(new_entry->signal_dbm), DEVICE_MIN_SENS); - ns_list_remove(&cur->ws_info->parent_list_reserved, new_entry); - ns_list_add_to_end(&cur->ws_info->parent_list_free, new_entry); - return; + if (ws_bootstrap_fhss_initialize(cur) != 0) { + tr_error("fhss initialization failed"); + return -3; } - // set to the correct place in list - ws_bootstrap_candidate_parent_sort(cur, new_entry); - - return; -} - -static int8_t ws_bootstrap_ffn_fhss_configure(protocol_interface_info_entry_t *cur, bool discovery) -{ - // 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); - ws_bootstrap_fhss_set_defaults(cur, &fhss_configuration); - ws_bootstrap_fhss_configure_channel_masks(cur, &fhss_configuration); - - // Discovery is done using fixed channel - if (discovery) { - fhss_configuration.ws_uc_channel_function = WS_FIXED_CHANNEL; - } else { - fhss_configuration.ws_uc_channel_function = (fhss_ws_channel_functions)cur->ws_info->cfg->fhss.fhss_uc_channel_function; + if (cur->bootsrap_mode == ARM_NWK_BOOTSRAP_MODE_6LoWPAN_BORDER_ROUTER) { + //BBR init like NVM read + ws_bbr_init(cur); } - fhss_configuration.ws_bc_channel_function = WS_FIXED_CHANNEL; - fhss_configuration.fhss_broadcast_interval = 0; - uint8_t tmp_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); - uint8_t tmp_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); - fhss_configuration.unicast_fixed_channel = tmp_uc_fixed_channel; - fhss_configuration.broadcast_fixed_channel = tmp_bc_fixed_channel; - ns_fhss_ws_configuration_set(cur->ws_info->fhss_api, &fhss_configuration); - ns_fhss_ws_set_hop_count(cur->ws_info->fhss_api, 0xff); - ws_bootstrap_llc_hopping_update(cur, &fhss_configuration); + // Save FHSS api + cur->ws_info->fhss_api = ns_sw_mac_get_fhss_api(cur->mac_api); + + ws_bootstrap_ll_address_validate(cur); + + addr_interface_set_ll64(cur, NULL); + cur->nwk_nd_re_scan_count = 0; + // Trigger discovery for bootstrap + ret_val = nwk_6lowpan_up(cur); + if (ret_val) { + goto cleanup; + } + + /* Wi-sun will trig event for stamechine this timer must be zero on init */ + cur->bootsrap_state_machine_cnt = 0; + /* Disable SLLAO send/mandatory receive with the ARO */ + cur->ipv6_neighbour_cache.use_eui64_as_slla_in_aro = true; + /* Omit sending of NA if ARO SUCCESS */ + cur->ipv6_neighbour_cache.omit_na_aro_success = true; + /* Omit sending of NA and consider ACK to be success */ + cur->ipv6_neighbour_cache.omit_na = true; + // do not process AROs from NA. This is overriden by Wi-SUN specific failure handling + cur->ipv6_neighbour_cache.recv_na_aro = false; + /* Disable NUD Probes */ + cur->ipv6_neighbour_cache.send_nud_probes = false; + cur->ipv6_neighbour_cache.probe_avoided_routers = true; + /*Replace NS handler to disable multicast address queries */ + cur->if_ns_transmit = ws_bootstrap_nd_ns_transmit; + + dhcp_client_init(cur->id, DHCPV6_DUID_HARDWARE_IEEE_802_NETWORKS_TYPE); + dhcp_service_link_local_rx_cb_set(cur->id, ws_bootstrap_ffn_dhcp_neighbour_update_cb); + dhcp_client_configure(cur->id, true, true, true); //RENEW uses SOLICIT, Interface will use 1 instance for address get, IAID address hint is not used. + + dhcp_client_solicit_timeout_set(cur->id, WS_DHCP_SOLICIT_TIMEOUT, WS_DHCP_SOLICIT_MAX_RT, WS_DHCP_SOLICIT_MAX_RC, WS_DHCP_SOLICIT_MAX_DELAY); + dhcp_client_option_notification_cb_set(cur->id, ws_bootstrap_ffn_dhcp_info_notify_cb); + + // Configure memory limits and garbage collection values; + ws_bootstrap_memory_configuration(); + ws_nud_table_reset(cur); + + ws_bootstrap_candidate_table_reset(cur); + // Zero uptime counters + cur->ws_info->uptime = 0; + cur->ws_info->authentication_time = 0; + cur->ws_info->connected_time = 0; + + blacklist_params_set( + WS_BLACKLIST_ENTRY_LIFETIME, + WS_BLACKLIST_TIMER_MAX_TIMEOUT, + WS_BLACKLIST_TIMER_TIMEOUT, + WS_BLACKLIST_ENTRY_MAX_NBR, + WS_BLACKLIST_PURGE_NBR, + WS_BLACKLIST_PURGE_TIMER_TIMEOUT); + + ws_bootstrap_event_discovery_start(cur); return 0; +cleanup: + return ret_val; } -void ws_bootstrap_ffn_network_discovery_configure(protocol_interface_info_entry_t *cur) +int8_t ws_bootstrap_ffn_down(protocol_interface_info_entry_t *cur) { - // Reset information to defaults - cur->ws_info->network_pan_id = 0xffff; + if (!cur || !(cur->lowpan_info & INTERFACE_NWK_ACTIVE)) { + return -1; + } - ws_common_regulatory_domain_config(cur, &cur->ws_info->hopping_schdule); - ws_bootstrap_set_domain_rf_config(cur); - ws_bootstrap_ffn_fhss_configure(cur, true); - - //Set Network names, Pan information configure, hopping schedule & GTKHash - ws_llc_set_network_name(cur, (uint8_t *)cur->ws_info->cfg->gen.network_name, strlen(cur->ws_info->cfg->gen.network_name)); -} - -// Start network scan -static void ws_bootstrap_ffn_start_discovery(protocol_interface_info_entry_t *cur) -{ - tr_debug("router discovery start"); - // Remove network keys from MAC - ws_pae_controller_nw_keys_remove(cur); - ws_bootstrap_state_change(cur, ER_ACTIVE_SCAN); - cur->nwk_nd_re_scan_count = 0; - cur->ws_info->configuration_learned = false; - cur->ws_info->pan_timeout_timer = 0; - cur->ws_info->weakest_received_rssi = 0; - - // Clear learned candidate parents - ws_bootstrap_candidate_table_reset(cur); - - // Clear RPL information - rpl_control_free_domain_instances_from_interface(cur); - // Clear EAPOL relay address + tr_info("Wi-SUN ifdown"); + // Reset MAC for safe upper layer memory free + protocol_mac_reset(cur); + ns_sw_mac_fhss_unregister(cur->mac_api); + ns_fhss_delete(cur->ws_info->fhss_api); + cur->ws_info->fhss_api = NULL; + // Reset WS information + ws_bootstrap_asynch_trickle_stop(cur); + ws_llc_reset(cur); + if (nd_proxy_downstream_interface_unregister(cur->id) != 0) { + tr_warn("nd proxy unregister failed"); + } + ws_nud_table_reset(cur); + dhcp_client_delete(cur->id); ws_eapol_relay_delete(cur); + ws_eapol_auth_relay_delete(cur); + ws_pae_controller_stop(cur); + ws_bootstrap_candidate_table_reset(cur); + blacklist_clear(); + cur->if_common_forwarding_out_cb = NULL; - // Clear ip stack from old information - ws_bootstrap_ip_stack_reset(cur); - // New network scan started old addresses not assumed valid anymore - ws_bootstrap_ffn_ip_stack_addr_clear(cur); - - if ((cur->lowpan_info & INTERFACE_NWK_BOOTSRAP_ACTIVE) != INTERFACE_NWK_BOOTSRAP_ACTIVE) { - // we have sent bootstrap ready event and now - // restarted discovery so bootstrap down event is sent - cur->lowpan_info |= INTERFACE_NWK_BOOTSRAP_ACTIVE; - ws_bootstrap_network_down(cur); - } - - // Start advertisement solicit trickle and calculate when we are checking the status - cur->ws_info->trickle_pas_running = true; - if (cur->ws_info->trickle_pan_advertisement_solicit.I != cur->ws_info->trickle_params_pan_discovery.Imin) { - // Trickle not reseted so starting a new interval - trickle_start(&cur->ws_info->trickle_pan_advertisement_solicit, &cur->ws_info->trickle_params_pan_discovery); - } - - // Discovery statemachine is checkked after we have sent the Solicit - uint32_t time_to_solicit = 0; - if (cur->ws_info->trickle_pan_advertisement_solicit.t > cur->ws_info->trickle_pan_advertisement_solicit.now) { - time_to_solicit = cur->ws_info->trickle_pan_advertisement_solicit.t - cur->ws_info->trickle_pan_advertisement_solicit.now; - } - - tr_debug("Disc params imin %u, imax %u, expirations %u, k %u PAS Trickle I %u t %u, now %u, c %u", - cur->ws_info->trickle_params_pan_discovery.Imin, cur->ws_info->trickle_params_pan_discovery.Imax, cur->ws_info->trickle_params_pan_discovery.TimerExpirations, cur->ws_info->trickle_params_pan_discovery.k, - cur->ws_info->trickle_pan_advertisement_solicit.I, cur->ws_info->trickle_pan_advertisement_solicit.t, cur->ws_info->trickle_pan_advertisement_solicit.now, cur->ws_info->trickle_pan_advertisement_solicit.c); - - time_to_solicit += cur->ws_info->trickle_params_pan_discovery.Imin + randLIB_get_random_in_range(0, cur->ws_info->trickle_params_pan_discovery.Imin); - - if (time_to_solicit > 0xffff) { - time_to_solicit = 0xffff; - } - cur->bootsrap_state_machine_cnt = time_to_solicit; - - tr_info("Making parent selection in %u s", (cur->bootsrap_state_machine_cnt / 10)); + return nwk_6lowpan_down(cur); } -// Start configuration learning -static void ws_bootstrap_ffn_start_configuration_learn(protocol_interface_info_entry_t *cur) +static void ws_bootstrap_ffn_dhcp_neighbour_update_cb(int8_t interface_id, uint8_t ll_addr[static 16]) { - tr_debug("router configuration learn start"); - ws_bootstrap_state_change(cur, ER_SCAN); - - cur->ws_info->configuration_learned = false; - - // Clear all temporary information - ws_bootstrap_ip_stack_reset(cur); - - cur->ws_info->pas_requests = 0; - //Calculate max time for config learn state - cur->ws_info->pan_config_sol_max_timeout = trickle_timer_max(&cur->ws_info->trickle_params_pan_discovery, PCS_MAX); - // Reset advertisement solicit trickle to start discovering network - cur->ws_info->trickle_pcs_running = true; - trickle_start(&cur->ws_info->trickle_pan_config_solicit, &cur->ws_info->trickle_params_pan_discovery); - trickle_inconsistent_heard(&cur->ws_info->trickle_pan_config_solicit, &cur->ws_info->trickle_params_pan_discovery); -} - -static void ws_bootstrap_ffn_network_configuration_learn(protocol_interface_info_entry_t *cur) -{ - tr_debug("Start using PAN configuration"); - - // Timing information can be modified here - ws_llc_set_pan_information_pointer(cur, &cur->ws_info->pan_information); - uint8_t *gtkhash = ws_pae_controller_gtk_hash_ptr_get(cur); - ws_llc_set_gtkhash(cur, gtkhash); - // TODO update own fhss schedules we are starting to follow first parent - - return; -} - -static void ws_bootstrap_ffn_pan_advertisement_analyse_active(struct protocol_interface_info_entry *cur, ws_pan_information_t *pan_information) -{ - /* In Active state - * - * A consistent transmission is defined as a PAN Advertisement received by a node with PAN ID and - * NETNAME-IE / Network Name matching that of the receiving node, and with a PAN-IE / Routing Cost - * the same or worse than (bigger than or equal to) that of the receiving node. - * - * Inconsistent: - * - * Received Routing Cost is smaller than stored one - * - * A PAN Advertisement received by a node with PAN ID and NETNAME-IE / Network name matching - * that of the receiving node, and PAN-IE / Routing Cost better than (smaller than) that of the receiving node. - * - */ - if (cur->bootsrap_mode == ARM_NWK_BOOTSRAP_MODE_6LoWPAN_BORDER_ROUTER) { - //Border router never set consistent that will guarantee that BR will send advertisment + if (memcmp(ll_addr, ADDR_LINK_LOCAL_PREFIX, 8)) { return; } -#ifdef WISUN_1_0_ERRATA_FIX - if (pan_information->pan_size == cur->ws_info->pan_information.pan_size) { - //If same pan size information then set consistent value - trickle_consistent_heard(&cur->ws_info->trickle_pan_advertisement); + + protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(interface_id); + if (!cur) { + return; } -#else - // Wi-SUN 1.0 specified functionality, causes extra inconsistencies when we hear higher rank advertisements - if (pan_information->routing_cost >= ws_bootstrap_routing_cost_calculate(cur)) { - trickle_consistent_heard(&cur->ws_info->trickle_pan_advertisement); + + uint8_t mac64[8]; + memcpy(mac64, ll_addr + 8, 8); + mac64[0] ^= 2; + ws_bootstrap_mac_neighbor_short_time_set(cur, mac64, WS_NEIGHBOUR_DHCP_ENTRY_LIFETIME); +} + +static void ws_bootstrap_ffn_dhcp_info_notify_cb(int8_t interface, dhcp_option_notify_t *options, dhcp_server_notify_info_t *server_info) +{ + protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(interface); + if (!cur) { + return; + } + uint8_t server_ll64[16]; + memcpy(server_ll64, ADDR_LINK_LOCAL_PREFIX, 8); + + if (server_info->duid_length == 8) { + memcpy(server_ll64 + 8, server_info->duid, 8); } else { - trickle_inconsistent_heard(&cur->ws_info->trickle_pan_advertisement, &cur->ws_info->trickle_params_pan_discovery); + server_ll64[8] = server_info->duid[0]; + server_ll64[9] = server_info->duid[1]; + server_ll64[10] = server_info->duid[2]; + server_ll64[11] = 0xff; + server_ll64[12] = 0xfe; + server_ll64[13] = server_info->duid[3]; + server_ll64[14] = server_info->duid[4]; + server_ll64[15] = server_info->duid[5]; } -#endif + server_ll64[8] ^= 2; + + switch (options->option_type) { + case DHCPV6_OPTION_VENDOR_SPECIFIC_INFO: + if (options->option.vendor_spesific.enterprise_number != ARM_ENTERPRISE_NUMBER) { + break; + } + while (options->option.vendor_spesific.data_length) { + uint16_t option_type; + char *domain; + uint8_t *address; + uint16_t option_len; + option_len = net_dns_option_vendor_option_data_get_next(options->option.vendor_spesific.data, options->option.vendor_spesific.data_length, &option_type); + tr_debug("DHCP vendor specific data type:%u length %d", option_type, option_len); + //tr_debug("DHCP vendor specific data %s", trace_array(options->option.vendor_spesific.data, options->option.vendor_spesific.data_length)); + + if (option_len == 0) { + // Option fields were corrupted + break; + } + if (option_type == ARM_DHCP_VENDOR_DATA_DNS_QUERY_RESULT) { + // Process ARM DNS query result + domain = NULL; + address = NULL; + if (net_dns_option_vendor_option_data_dns_query_read(options->option.vendor_spesific.data, options->option.vendor_spesific.data_length, &address, &domain) > 0 || + domain || address) { + // Valid ARM DNS query entry + net_dns_query_result_set(interface, address, domain, server_info->life_time); + } + } + if (option_type == ARM_DHCP_VENDOR_DATA_TIME_CONFIGURATION) { + timezone_info_t time_configuration; + if (net_vendor_option_time_configuration_read(options->option.vendor_spesific.data, options->option.vendor_spesific.data_length, &time_configuration.timestamp, &time_configuration.timezone, &time_configuration.deviation, &time_configuration.status)) { + int ret = ns_time_system_timezone_info_notify(&time_configuration); + tr_info("Network Time configuration %s status:%"PRIu16" time stamp: %"PRIu64" deviation: %"PRId16" Time Zone: %"PRId16, ret == 0 ? "notified" : "notify FAILED", time_configuration.status, time_configuration.timestamp, time_configuration.deviation, time_configuration.timezone); + } + } + if (option_type == ARM_DHCP_VENDOR_DATA_NETWORK_TIME) { + // Process ARM Network Time + // Get Current time + // Get Round trip time of the DHCP request + // Estimated error is elapsed time of request + // If current time difference is larger than estimated error update current time + // set the time for server time + *.5 RTT + int32_t era; + uint32_t offset; + if (net_vendor_option_current_time_read(options->option.vendor_spesific.data, options->option.vendor_spesific.data_length, &era, &offset, NULL)) { + uint64_t current_time; + uint64_t network_time = (era * (uint64_t)(4294967296)) + offset - 2208988800; //Convert to First day of Unix (1 Jan 1970) + + tr_debug("Network Time option Era:%"PRId32" Offset:%"PRIu32" rtt: %"PRId32" time: %"PRIu64, era, offset, server_info->rtt, network_time); + if (0 == ns_time_system_time_read(¤t_time)) { + uint64_t difference; + // We only adjust clock if time has drifted more than 10 seconds to avoid constant changing of time + // If Round trip time is very high the accuracy is reduced. + uint32_t estimated_error = 10 + server_info->rtt / 10; + // Take into account the round trip time it took the response to arrive from the time server Write the time. + network_time += server_info->rtt / 20; + + if (current_time > network_time) { + difference = current_time - network_time; + } else { + difference = network_time - current_time; + } + if (difference > estimated_error) { + // Larger than 10 second difference update the time + int ret = ns_time_system_time_write(network_time); + tr_info("Network Time %s: Era:%"PRId32" Offset:%"PRIu32" old time: %"PRIu64" time: %"PRIu64, ret == 0 ? "updated" : "update FAILED", era, offset, current_time, network_time); + } + // System time has been acquired + ns_time_system_time_acquired_set(); + } + } + } + + options->option.vendor_spesific.data_length -= option_len; + options->option.vendor_spesific.data += option_len; + } + break; + + case DHCPV6_OPTION_DNS_SERVERS: + while (options->option.generic.data_length && options->option.generic.data_length >= 16 && options->option.generic.data_length % 16 == 0) { + // Validate payload to have full 16 byte length addresses without any extra bytes + net_dns_server_address_set(interface, server_ll64, options->option.generic.data, server_info->life_time); + options->option.generic.data_length -= 16; + options->option.generic.data += 16; + } + break; + case DHCPV6_OPTION_DOMAIN_LIST: + net_dns_server_search_list_set(interface, server_ll64, options->option.generic.data, options->option.generic.data_length, server_info->life_time); + break; + default: + break; + } + } -static void ws_bootstrap_ffn_pan_advertisement_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) +static void ws_dhcp_client_global_adress_cb(int8_t interface, uint8_t dhcp_addr[static 16], uint8_t prefix[static 16], bool register_status) { - - //Validate Pan Conrfirmation is at packet - ws_pan_information_t pan_information; - if (!ws_wp_nested_pan_read(ie_ext->payloadIeList, ie_ext->payloadIeListLength, &pan_information)) { - // Corrupted - tr_error("No pan information"); - return; - } - - if (ws_us->excluded_channel_ctrl) { - //Validate that we can storage data - if (ws_us->excluded_channel_ctrl == WS_EXC_CHAN_CTRL_BITMASK && ws_us->excluded_channels.mask.mask_len_inline > 32) { - return; - } - } - - // Check pan flags so that it is valid - if (!pan_information.rpl_routing_method) { - // NOT RPL routing - //tr_warn("Not supported routing"); - return; - } - - // Store heard pans and possible candidate parents - ws_bootstrap_ffn_pan_information_store(cur, data, ws_utt, ws_us, &pan_information); - - if (!(ws_bootstrap_state_active(cur) || - ws_bootstrap_state_wait_rpl(cur))) { - // During discovery/eapol/config learn we dont do further processing for advertisements - return; - } - // Active state processing - //tr_debug("Advertisement active"); - - // In active operation less neighbours per pan is allowed - ws_bootstrap_candidate_list_clean(cur, WS_PARENT_LIST_MAX_PAN_IN_ACTIVE, protocol_core_monotonic_time, data->SrcPANId); - - // Check if valid PAN - if (data->SrcPANId != cur->ws_info->network_pan_id) { - return; - } - - // Save route cost for all known neighbors - llc_neighbour_req_t neighbor_info; - neighbor_info.neighbor = NULL; - if (ws_bootstrap_neighbor_info_request(cur, data->SrcAddr, &neighbor_info, false)) { - neighbor_info.ws_neighbor->routing_cost = pan_information.routing_cost; - //Store and search neighbour PCAP info - if (ws_version_1_1(cur)) { - ws_neighbor_class_pcap_ie_store(neighbor_info.ws_neighbor, ie_ext); - } - } - - ws_bootstrap_ffn_pan_advertisement_analyse_active(cur, &pan_information); - - // Learn latest network information - if (cur->bootsrap_mode != ARM_NWK_BOOTSRAP_MODE_6LoWPAN_BORDER_ROUTER && neighbor_info.neighbor) { - uint8_t ll_address[16]; - ws_common_create_ll_address(ll_address, neighbor_info.neighbor->mac64); - - if (rpl_control_is_dodag_parent(cur, ll_address)) { - cur->ws_info->pan_information.pan_size = pan_information.pan_size; - cur->ws_info->pan_information.routing_cost = pan_information.routing_cost; - cur->ws_info->pan_information.rpl_routing_method = pan_information.rpl_routing_method; - cur->ws_info->pan_information.use_parent_bs = pan_information.use_parent_bs; - } - } -} - -static void ws_bootstrap_ffn_pan_advertisement_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) -{ - - (void)data; - (void)ws_utt; - (void)ws_us; - /* - * An inconsistent transmission is defined as: - * A PAN Advertisement Solicit with NETNAME-IE matching that of the receiving node. - */ - trickle_inconsistent_heard(&cur->ws_info->trickle_pan_advertisement, &cur->ws_info->trickle_params_pan_discovery); - /* - * A consistent transmission is defined as - * a PAN Advertisement Solicit with NETNAME-IE / Network Name matching that configured on the receiving node. - */ - trickle_consistent_heard(&cur->ws_info->trickle_pan_advertisement_solicit); - /* - * Optimized PAN discovery to select the parent faster if we hear solicit from someone else - */ - - if (ws_bootstrap_state_discovery(cur) && ws_cfg_network_config_get(cur) <= CONFIG_MEDIUM && - cur->bootsrap_state_machine_cnt > cur->ws_info->trickle_params_pan_discovery.Imin * 2) { - - cur->bootsrap_state_machine_cnt = cur->ws_info->trickle_params_pan_discovery.Imin + randLIB_get_random_in_range(0, cur->ws_info->trickle_params_pan_discovery.Imin); - - tr_info("Making parent selection in %u s", (cur->bootsrap_state_machine_cnt / 10)); - } - - if (ws_bootstrap_state_active(cur) && cur->bootsrap_mode != ARM_NWK_BOOTSRAP_MODE_6LoWPAN_BORDER_ROUTER) { - mac_neighbor_table_entry_t *neighbor = mac_neighbor_table_address_discover(mac_neighbor_info(cur), data->SrcAddr, ADDR_802_15_4_LONG); - if (neighbor && neighbor->link_role == PRIORITY_PARENT_NEIGHBOUR) { - ws_bootstrap_parent_confirm(cur, NULL); - } - } -} -#ifdef HAVE_WS_VERSION_1_1 -static void ws_bootstrap_ffn_pan_config_lfn_analyze(struct protocol_interface_info_entry *cur, const struct mcps_data_ie_list *ie_ext) -{ - if (!ws_version_1_1(cur) || cur->bootsrap_mode == ARM_NWK_BOOTSRAP_MODE_6LoWPAN_BORDER_ROUTER) { - return; - } - - ws_lfnver_ie_t lfn_version; - if (!ws_wp_nested_lfn_version_read(ie_ext->payloadIeList, ie_ext->payloadIeListLength, &lfn_version)) { - return; // LFN version - } - - //Read LFNGTKHASH - ws_lgtkhash_ie_t ws_lgtkhash; - if (!ws_wp_nested_lgtk_hash_read(ie_ext->payloadIeList, ie_ext->payloadIeListLength, &ws_lgtkhash)) { - return; - } - - if (!cur->ws_info->lfngtk.lfn_version_learned) { - if (!cur->ws_info->configuration_learned) { - trickle_inconsistent_heard(&cur->ws_info->trickle_pan_config, &cur->ws_info->trickle_params_pan_discovery); + (void)prefix; + (void)interface; + //TODO add handler for negative status + tr_debug("DHCPv6 %s status %u with link %s", trace_ipv6(prefix), register_status, trace_ipv6(dhcp_addr)); + if (register_status) { + protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(interface); + if (cur) { + ws_address_reregister_trig(cur); } } else { - if (cur->ws_info->lfngtk.lfn_version == lfn_version.lfn_version) { - return; - } - - if (common_serial_number_greater_16(cur->ws_info->lfngtk.lfn_version, lfn_version.lfn_version)) { - // older version heard ignoring the message - return; - } + //Delete dhcpv6 client + dhcp_client_global_address_delete(interface, dhcp_addr, prefix); } - - cur->ws_info->lfngtk.lfn_version = lfn_version.lfn_version; - - //Clear HASH allways at new first or for first leaned one's - memset(cur->ws_info->lfngtk.lgtkhash, 0, 24); - cur->ws_info->lfngtk.lfn_version_learned = true; - - //Set Active key index and hash inline bits - cur->ws_info->lfngtk.active_key_index = ws_lgtkhash.active_lgtk_index; - cur->ws_info->lfngtk.active_hash_1 = ws_lgtkhash.lgtk0; - cur->ws_info->lfngtk.active_hash_2 = ws_lgtkhash.lgtk1; - cur->ws_info->lfngtk.active_hash_3 = ws_lgtkhash.lgtk2; - - if (cur->ws_info->lfngtk.active_hash_1) { - memcpy(cur->ws_info->lfngtk.lgtkhash, ws_lgtkhash.lgtk0_hash, 8); - } - - if (cur->ws_info->lfngtk.active_hash_2) { - memcpy(cur->ws_info->lfngtk.lgtkhash + 8, ws_lgtkhash.lgtk1_hash, 8); - } - - if (cur->ws_info->lfngtk.active_hash_3) { - memcpy(cur->ws_info->lfngtk.lgtkhash + 16, ws_lgtkhash.lgtk2_hash, 8); - } - //TODO Analyze HASH's and set LFN group key index } + + +void ws_dhcp_client_address_request(protocol_interface_info_entry_t *cur, uint8_t *prefix, uint8_t *parent_link_local) +{ + if (dhcp_client_get_global_address(cur->id, parent_link_local, prefix, ws_dhcp_client_global_adress_cb) != 0) { + tr_error("DHCPp client request fail"); + } +} + +void ws_dhcp_client_address_delete(protocol_interface_info_entry_t *cur, uint8_t *prefix) +{ + dhcp_client_global_address_delete(cur->id, NULL, prefix); +} + +void ws_bootstrap_ffn_rpl_configure(protocol_interface_info_entry_t *cur) +{ + tr_debug("RPL Activate"); +#ifdef HAVE_RPL + bool downstream = true; + bool leaf = false; #endif + addr_add_router_groups(cur); +#ifdef HAVE_RPL + rpl_control_set_domain_on_interface(cur, protocol_6lowpan_rpl_domain, downstream); + // If i am router I Do this + rpl_control_force_leaf(protocol_6lowpan_rpl_domain, leaf); + rpl_control_process_routes(protocol_6lowpan_rpl_domain, false); // Wi-SUN assumes that no default route needed + rpl_control_request_parent_link_confirmation(true); + rpl_control_set_dio_multicast_min_config_advertisment_count(WS_MIN_DIO_MULTICAST_CONFIG_ADVERTISMENT_COUNT); + rpl_control_set_address_registration_timeout((WS_NEIGHBOR_LINK_TIMEOUT / 60) + 1); + rpl_control_set_dao_retry_count(WS_MAX_DAO_RETRIES); + rpl_control_set_initial_dao_ack_wait(WS_MAX_DAO_INITIAL_TIMEOUT); + rpl_control_set_mrhof_parent_set_size(WS_MAX_PARENT_SET_COUNT); + rpl_control_set_force_tunnel(true); + // Set RPL Link ETX Validation Threshold to 2.5 - 33.0 + // This setup will set ETX 0x800 to report ICMP error 18% probability + // When ETX start go over 0x280 forward dropping probability start increase linear to 100% at 0x2100 + rpl_policy_forward_link_etx_threshold_set(0x280, 0x2100); -static void ws_bootstrap_ffn_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) -{ + // Set the minimum target refresh to sen DAO registrations before pan timeout + rpl_control_set_minimum_dao_target_refresh(WS_RPL_DAO_MAX_TIMOUT); +#endif // HAVE_RPL - uint16_t pan_version; - ws_bs_ie_t ws_bs_ie; - uint8_t *gtkhash_ptr; - - if (data->SrcPANId != cur->ws_info->network_pan_id) { - return; - } - ws_bt_ie_t ws_bt_ie; - if (!ws_wh_bt_read(ie_ext->headerIeList, ie_ext->headerIeListLength, &ws_bt_ie)) { - tr_warn("BT-IE"); - return; - } - - /* - * A consistent transmission is defined as a PAN Configuration with a PAN-ID matching that of the receiving node and - * a PANVER-IE / PAN Version greater than or equal to the receiving node’s current PAN version. - * - * A inconsistent transmission is defined as: - * - * A PAN Configuration with PAN-ID matching that of the receiving node and a - * PANVER-IE / PAN Version that is less than the receiving node’s current PAN version. - */ - - // TODO Add this to neighbor table - // TODO save all information from config message if version number has changed - - if (!ws_wp_nested_pan_version_read(ie_ext->payloadIeList, ie_ext->payloadIeListLength, &pan_version)) { - // Corrupted - tr_warn("no version"); - return; - } - - gtkhash_ptr = ws_wp_nested_gtkhash_read(ie_ext->payloadIeList, ie_ext->payloadIeListLength); - - if (!gtkhash_ptr) { - // Corrupted - tr_error("No gtk hash"); - return; - } - - if (!ws_wp_nested_bs_read(ie_ext->payloadIeList, ie_ext->payloadIeListLength, &ws_bs_ie)) { - // Corrupted - tr_error("No broadcast schedule"); - return; - } - - llc_neighbour_req_t neighbor_info; - bool neighbour_pointer_valid; - - //Validate BSI - if (cur->bootsrap_mode != ARM_NWK_BOOTSRAP_MODE_6LoWPAN_BORDER_ROUTER) { - - if (cur->ws_info->ws_bsi_block.block_time && cur->ws_info->ws_bsi_block.old_bsi == ws_bs_ie.broadcast_schedule_identifier) { - tr_debug("Do not accept a old BSI: %u in time %"PRIu32, cur->ws_info->ws_bsi_block.old_bsi, cur->ws_info->ws_bsi_block.block_time); - //Refresh Block time when hear a old BSI - cur->ws_info->ws_bsi_block.block_time = cur->ws_info->cfg->timing.pan_timeout; - return; - } - - //When Config is learned and USE Parent BS is enabled compare is this new BSI - if (cur->ws_info->configuration_learned && cur->ws_info->pan_information.use_parent_bs && ws_bs_ie.broadcast_schedule_identifier != cur->ws_info->hopping_schdule.fhss_bsi) { - //Accept only next possible BSI number - if ((cur->ws_info->hopping_schdule.fhss_bsi + 1) != ws_bs_ie.broadcast_schedule_identifier) { - tr_debug("Do not accept a unknown BSI: %u", ws_bs_ie.broadcast_schedule_identifier); - } else { - tr_debug("NEW Brodcast Schedule %u...BR rebooted", ws_bs_ie.broadcast_schedule_identifier); - cur->ws_info->ws_bsi_block.block_time = cur->ws_info->cfg->timing.pan_timeout; - cur->ws_info->ws_bsi_block.old_bsi = cur->ws_info->hopping_schdule.fhss_bsi; - ws_bootstrap_event_disconnect(cur, WS_NORMAL_DISCONNECT); - } - return; - } - } - - - if (cur->ws_info->configuration_learned || cur->bootsrap_mode == ARM_NWK_BOOTSRAP_MODE_6LoWPAN_BORDER_ROUTER) { - //If we are border router or learned configuration we only update already learned neighbours. - neighbour_pointer_valid = ws_bootstrap_neighbor_info_request(cur, data->SrcAddr, &neighbor_info, false); - - } else { - neighbour_pointer_valid = ws_bootstrap_neighbor_info_request(cur, data->SrcAddr, &neighbor_info, true); - if (!neighbour_pointer_valid) { - return; - } - ws_bootstrap_neighbor_set_stable(cur, data->SrcAddr); - } - - if (neighbour_pointer_valid) { - //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); - } - - if (cur->ws_info->configuration_learned) { - tr_info("PAN Config analyse own:%d, heard:%d", cur->ws_info->pan_information.pan_version, pan_version); - if (cur->ws_info->pan_information.pan_version == pan_version) { - //Check if Trgigle have been resetted in short time skip this then - if (cur->ws_info->trickle_pc_consistency_block_period == 0) { - // Same version heard so it is consistent - trickle_consistent_heard(&cur->ws_info->trickle_pan_config); - } - - if (neighbour_pointer_valid && neighbor_info.neighbor->link_role == PRIORITY_PARENT_NEIGHBOUR) { - ws_bootstrap_primary_parent_set(cur, &neighbor_info, WS_PARENT_SOFT_SYNCH); - } - // no need to process more -#ifdef HAVE_WS_VERSION_1_1 - ws_bootstrap_ffn_pan_config_lfn_analyze(cur, ie_ext); -#endif - return; - } else { - // received version is different so we need to reset the trickle - trickle_inconsistent_heard(&cur->ws_info->trickle_pan_config, &cur->ws_info->trickle_params_pan_discovery); - if (neighbour_pointer_valid && neighbor_info.neighbor->link_role == PRIORITY_PARENT_NEIGHBOUR) { - ws_bootstrap_primary_parent_set(cur, &neighbor_info, WS_PARENT_HARD_SYNCH); - } - if (common_serial_number_greater_16(cur->ws_info->pan_information.pan_version, pan_version)) { - // older version heard ignoring the message - return; - } - cur->ws_info->trickle_pc_consistency_block_period = WS_CONFIG_CONSISTENT_FILTER_PERIOD; - } - } - - if (cur->bootsrap_mode == ARM_NWK_BOOTSRAP_MODE_6LoWPAN_BORDER_ROUTER) { - //Border router does not learn network information - return; - } - - /* - * Learn new information from neighbor - */ - tr_info("Updated PAN configuration own:%d, heard:%d", cur->ws_info->pan_information.pan_version, pan_version); - - // restart PAN version timer - //Check Here Do we have a selected Primary parent - if (!cur->ws_info->configuration_learned || cur->ws_info->rpl_state == RPL_EVENT_DAO_DONE) { - ws_common_border_router_alive_update(cur); - } - - cur->ws_info->pan_information.pan_version = pan_version; - - ws_pae_controller_gtk_hash_update(cur, gtkhash_ptr); - - ws_pae_controller_nw_key_index_update(cur, data->Key.KeyIndex - 1); - -#ifdef HAVE_WS_VERSION_1_1 - ws_bootstrap_ffn_pan_config_lfn_analyze(cur, ie_ext); -#endif - - if (!cur->ws_info->configuration_learned) { - // Generate own hopping schedules Follow first parent broadcast and plans and also use same unicast dwell - tr_info("learn network configuration"); - cur->ws_info->configuration_learned = true; - // return to state machine after 1-2 s - cur->bootsrap_state_machine_cnt = randLIB_get_random_in_range(10, 20); - // enable frequency hopping for unicast channel and start listening first neighbour - ws_bootstrap_primary_parent_set(cur, &neighbor_info, WS_PARENT_HARD_SYNCH); - // set neighbor as priority parent clear if there is others - protocol_6lowpan_neighbor_priority_clear_all(cur->id, PRIORITY_1ST); - neighbor_info.neighbor->link_role = PRIORITY_PARENT_NEIGHBOUR; - } + cur->ws_info->rpl_state = 0xff; // Set invalid state and learn from event } - -static void ws_bootstrap_ffn_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) -{ - if (data->SrcPANId != cur->ws_info->network_pan_id) { - return; - } - - /* TODO smart neighbour process - * - * Unsecure packet we cant trust the device? - * - * Question mark in specification also present, now we create neighbour. - * this is moved in future to NS/ND processing triggered by RPL - * - */ - - llc_neighbour_req_t neighbor_info; - 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); - } - - if (ws_bootstrap_state_active(cur) && cur->bootsrap_mode != ARM_NWK_BOOTSRAP_MODE_6LoWPAN_BORDER_ROUTER) { - mac_neighbor_table_entry_t *neighbor = mac_neighbor_table_address_discover(mac_neighbor_info(cur), data->SrcAddr, ADDR_802_15_4_LONG); - if (neighbor && neighbor->link_role == PRIORITY_PARENT_NEIGHBOUR) { - ws_bootstrap_parent_confirm(cur, NULL); - } - } - - /* - * A consistent transmission is defined as a PAN Configuration Solicit with - * a PAN-ID matching that of the receiving node and a NETNAME-IE / Network Name - * matching that configured on the receiving node. - */ - trickle_consistent_heard(&cur->ws_info->trickle_pan_config_solicit); - /* - * inconsistent transmission is defined as either: - * A PAN Configuration Solicit with a PAN-ID matching that of the receiving node and - * a NETNAME-IE / Network Name matching the network name configured on the receiving - */ - trickle_inconsistent_heard(&cur->ws_info->trickle_pan_config, &cur->ws_info->trickle_params_pan_discovery); -} - - -void ws_bootstrap_ffn_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); - ws_bootstrap_ffn_pan_advertisement_analyse(cur, data, ie_ext, &ws_utt, &ws_us); - 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); - ws_bootstrap_ffn_pan_advertisement_solicit_analyse(cur, data, &ws_utt, &ws_us); - 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_ffn_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); - ws_bootstrap_ffn_pan_config_solicit_analyse(cur, data, &ws_utt, &ws_us); - default: - // Unknown message do not process - break; - } -} - -void ws_bootstrap_ffn_asynch_confirm(struct protocol_interface_info_entry *interface, uint8_t asynch_message) -{ - (void)asynch_message; - ws_stats_update(interface, STATS_WS_ASYNCH_TX, 1); -} - -void ws_bootstrap_ffn_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); - - ws_pae_controller_supp_init(cur); - // Clear learned neighbours - ws_bootstrap_neighbor_list_clean(cur); - // Configure LLC for network discovery - ws_bootstrap_ffn_network_discovery_configure(cur); - ws_bootstrap_fhss_activate(cur); - // Set retry configuration for discovery state - ws_bootstrap_configure_max_retries(cur, WS_MAX_FRAME_RETRIES_BOOTSTRAP); - // Set TX failure request restart configuration for discovery state - ws_bootstrap_configure_data_request_restart(cur, WS_CCA_REQUEST_RESTART_MAX, WS_TX_REQUEST_RESTART_MAX_BOOTSTRAP, 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); - // Start network scan - ws_bootstrap_ffn_start_discovery(cur); - break; - - case WS_CONFIGURATION_START: - tr_info("Configuration start"); - // Old configuration is considered invalid stopping all - ws_bootstrap_asynch_trickle_stop(cur); - - // Build list of possible neighbours and learn first broadcast schedule - - ws_bootstrap_ffn_start_configuration_learn(cur); - 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_rpl_scan_start(cur); - /* While in Join State 4, if a non Border Router determines it has been unable to communicate with the PAN Border - * Router for an interval of PAN_TIMEOUT, a node MUST assume failure of the PAN Border Router and MUST - * Transition to Join State 1 - */ - ws_common_border_router_alive_update(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; - } -} - -/* - * Statemachine state functions - * */ - -static void ws_bootstrap_ffn_network_scan_process(protocol_interface_info_entry_t *cur) -{ - - parent_info_t *selected_parent_ptr; - - tr_debug("analyze network discovery result"); - -select_best_candidate: - selected_parent_ptr = ws_bootstrap_candidate_parent_get_best(cur); - - if (!selected_parent_ptr) { - // Configure LLC for network discovery - ws_bootstrap_ffn_network_discovery_configure(cur); - // randomize new channel and start MAC - ws_bootstrap_fhss_activate(cur); - // Next check will be after one trickle - uint32_t random_start = cur->ws_info->trickle_params_pan_discovery.Imin + randLIB_get_random_in_range(0, cur->ws_info->trickle_params_pan_discovery.Imin); - if (random_start > 0xffff) { - random_start = 0xffff; - } - cur->bootsrap_state_machine_cnt = random_start; - - tr_info("Making parent selection in %u s", (cur->bootsrap_state_machine_cnt / 10)); - return; - } - tr_info("selected parent:%s panid %u", trace_array(selected_parent_ptr->addr, 8), selected_parent_ptr->pan_id); - - if (ws_bootstrap_neighbor_set(cur, selected_parent_ptr, false) < 0) { - goto select_best_candidate; - } - - ws_pae_controller_set_target(cur, selected_parent_ptr->pan_id, selected_parent_ptr->addr); // temporary!!! store since auth - ws_bootstrap_event_authentication_start(cur); - return; -} - -static void ws_bootstrap_ffn_configure_process(protocol_interface_info_entry_t *cur) -{ - - if (cur->ws_info->configuration_learned) { - ws_bootstrap_ffn_network_configuration_learn(cur); - ws_bootstrap_event_operation_start(cur); - return; - } - return; -} - -void ws_bootstrap_ffn_rpl_wait_process(protocol_interface_info_entry_t *cur) -{ - - if (cur->ws_info->rpl_state == RPL_EVENT_DAO_DONE) { - // RPL routing is ready - cur->ws_info->connected_time = cur->ws_info->uptime; - ws_bootstrap_event_routing_ready(cur); - } else if (!rpl_control_have_dodag(cur->rpl_domain)) { - // RPL not ready send DIS message if possible - if (cur->bootsrap_mode == ARM_NWK_BOOTSRAP_MODE_6LoWPAN_ROUTER) { - // TODO Multicast DIS should be sent only if no DIO heard for some time - rpl_control_transmit_dis(cur->rpl_domain, cur, 0, 0, NULL, 0, ADDR_LINK_LOCAL_ALL_RPL_NODES); - } - // set timer for next DIS - cur->bootsrap_state_machine_cnt = randLIB_get_random_in_range(WS_RPL_DIS_TIMEOUT / 2, WS_RPL_DIS_TIMEOUT); - } - return; -} - - -/* - * State machine - */ - -void ws_bootstrap_ffn_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"); - ws_bootstrap_ffn_network_scan_process(cur); - break; - case ER_SCAN: - tr_debug("WS SM:configuration Scan"); - ws_bootstrap_ffn_configure_process(cur); - break; - case ER_PANA_AUTH: - tr_info("authentication start"); - // Advertisements stopped during the EAPOL - ws_bootstrap_asynch_trickle_stop(cur); - ws_bootstrap_ffn_fhss_configure(cur, false); - int8_t new_default = cur->ws_info->weakest_received_rssi - 1; - if ((new_default < CCA_DEFAULT_DBM) && (new_default >= CCA_LOW_LIMIT) && (new_default <= CCA_HIGH_LIMIT)) { - // Restart automatic CCA threshold using weakest received RSSI as new default - mac_helper_start_auto_cca_threshold(cur->id, cur->ws_info->hopping_schdule.number_of_channels, cur->ws_info->weakest_received_rssi - 1, CCA_HIGH_LIMIT, CCA_LOW_LIMIT); - } - ws_bootstrap_start_authentication(cur); - break; - case ER_RPL_SCAN: - tr_debug("WS SM:Wait RPL to contact DODAG root"); - ws_bootstrap_ffn_rpl_wait_process(cur); - 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_ffn_seconds_timer(protocol_interface_info_entry_t *cur, uint32_t seconds) -{ - /* Border router keep alive check - */ - if (cur->ws_info->pan_timeout_timer) { - // PAN version timer running - if (cur->ws_info->pan_timeout_timer > seconds) { - cur->ws_info->pan_timeout_timer -= seconds; - if (cur->ws_info->pan_timeout_timer < cur->ws_info->cfg->timing.pan_timeout / 10) { - /* pan timeout is closing need to verify that DAO is tested before the pan times out. - This will give some extra time for RPL to find better parents. - Border router liveliness can be checked from version number change or from successful DAO registrations - in this case there has not been any version number changes during this PAN lifetime. - */ - rpl_control_dao_timeout(cur->rpl_domain, 20); - } - } else { - // Border router has timed out - //Clear Timeout timer - cur->ws_info->pan_timeout_timer = 0; - tr_warn("Border router has timed out"); - ws_bootstrap_event_disconnect(cur, WS_FAST_DISCONNECT); - } - } - if (cur->ws_info->aro_registration_timer) { - if (cur->ws_info->aro_registration_timer > seconds) { - cur->ws_info->aro_registration_timer -= seconds; - } else { - // Update all addressess. This function will update the timer value if needed - cur->ws_info->aro_registration_timer = 0; - ws_address_registration_update(cur, NULL); - } - } - - if (cur->ws_info->ws_bsi_block.block_time) { - if (cur->ws_info->ws_bsi_block.block_time > seconds) { - cur->ws_info->ws_bsi_block.block_time -= seconds; - } else { - //Clear A BSI blokker - cur->ws_info->ws_bsi_block.block_time = 0; - cur->ws_info->ws_bsi_block.old_bsi = 0; - } - } -} - - -#endif //HAVE_WS_BORDER_ROUTER && HAVE_WS +#endif //HAVE_WS diff --git a/source/6LoWPAN/ws/ws_bootstrap_ffn.h b/source/6LoWPAN/ws/ws_bootstrap_ffn.h index fcc9dd25d6..b598b81479 100644 --- a/source/6LoWPAN/ws/ws_bootstrap_ffn.h +++ b/source/6LoWPAN/ws/ws_bootstrap_ffn.h @@ -18,26 +18,15 @@ #ifndef WS_BOOTSTRAP_FFN_H_ #define WS_BOOTSTRAP_FFN_H_ -#if defined(HAVE_WS) && defined(HAVE_WS_ROUTER) +#ifdef HAVE_WS -void ws_bootstrap_ffn_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); -void ws_bootstrap_ffn_asynch_confirm(struct protocol_interface_info_entry *interface, uint8_t asynch_message); -void ws_bootstrap_ffn_event_handler(protocol_interface_info_entry_t *cur, arm_event_s *event); -void ws_bootstrap_ffn_state_machine(protocol_interface_info_entry_t *cur); -void ws_bootstrap_ffn_seconds_timer(protocol_interface_info_entry_t *cur, uint32_t seconds); +int8_t ws_bootstrap_ffn_up(protocol_interface_info_entry_t *cur); +int8_t ws_bootstrap_ffn_down(protocol_interface_info_entry_t *cur); -#define wisun_mode_router(cur) (cur->bootsrap_mode == ARM_NWK_BOOTSRAP_MODE_6LoWPAN_ROUTER) +void ws_dhcp_client_address_request(protocol_interface_info_entry_t *cur, uint8_t *prefix, uint8_t *parent_link_local); -#else +void ws_bootstrap_ffn_rpl_configure(protocol_interface_info_entry_t *cur); -#define ws_bootstrap_ffn_asynch_ind(cur, data, ie_ext, message_type) ((void) 0) -#define ws_bootstrap_ffn_asynch_confirm(interface, asynch_message) ((void) 0) -#define ws_bootstrap_ffn_event_handler(cur, event) ((void) 0) -#define ws_bootstrap_ffn_state_machine(cur) ((void) 0) -#define ws_bootstrap_ffn_seconds_timer(cur, seconds) ((void) 0) +#endif -#define wisun_mode_router(cur) (false) - -#endif //HAVE_WS - -#endif /* WS_BOOTSTRAP_H_ */ +#endif /* WS_BOOTSTRAP_FFN_H_ */ diff --git a/source/6LoWPAN/ws/ws_bootstrap_lfn.h b/source/6LoWPAN/ws/ws_bootstrap_lfn.h deleted file mode 100644 index 84a0cf8101..0000000000 --- a/source/6LoWPAN/ws/ws_bootstrap_lfn.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - * 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. - */ - -#ifndef WS_BOOTSTRAP_LFN_H_ -#define WS_BOOTSTRAP_LFN_H_ - -#if defined(HAVE_WS) && defined(HAVE_WS_HOST) - -void ws_bootstrap_lfn_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); -void ws_bootstrap_lfn_asynch_confirm(struct protocol_interface_info_entry *interface, uint8_t asynch_message); -void ws_bootstrap_lfn_event_handler(protocol_interface_info_entry_t *cur, arm_event_s *event); -void ws_bootstrap_lfn_state_machine(protocol_interface_info_entry_t *cur); -void ws_bootstrap_lfn_seconds_timer(protocol_interface_info_entry_t *cur, uint32_t seconds); - -#define wisun_mode_host(cur) (cur->bootsrap_mode == ARM_NWK_BOOTSRAP_MODE_6LoWPAN_HOST) - -#else - -#define ws_bootstrap_ffn_asynch_ind(cur, data, ie_ext, message_type) ((void) 0) -#define ws_bootstrap_ffn_asynch_confirm(interface, asynch_message) ((void) 0) -#define ws_bootstrap_ffn_event_handler(cur, event) ((void) 0) -#define ws_bootstrap_lfn_state_machine(cur) ((void) 0) -#define ws_bootstrap_lfn_seconds_timer(cur, seconds) ((void) 0) - -#define wisun_mode_host(cur) (false) - -#endif //HAVE_WS - -#endif /* WS_BOOTSTRAP_H_ */ diff --git a/source/6LoWPAN/ws/ws_cfg_settings.c b/source/6LoWPAN/ws/ws_cfg_settings.c index 2d70df180a..312d41263a 100644 --- a/source/6LoWPAN/ws/ws_cfg_settings.c +++ b/source/6LoWPAN/ws/ws_cfg_settings.c @@ -792,6 +792,13 @@ int8_t ws_cfg_bbr_validate(ws_bbr_cfg_t *new_cfg) return CFG_SETTINGS_CHANGED; } + if (cfg->dio_interval_min == 0 || + cfg->min_hop_rank_increase < 32 || + cfg->dhcp_address_lifetime < 60 || + cfg->rpl_default_lifetime < 60) { + return CFG_SETTINGS_ERROR_GEN_CONF; + } + return CFG_SETTINGS_OK; } diff --git a/source/6LoWPAN/ws/ws_common.c b/source/6LoWPAN/ws/ws_common.c index e6274c2e4f..f9c258aefd 100644 --- a/source/6LoWPAN/ws/ws_common.c +++ b/source/6LoWPAN/ws/ws_common.c @@ -33,9 +33,10 @@ #include "6LoWPAN/ws/ws_llc.h" #include "6LoWPAN/ws/ws_common.h" #include "6LoWPAN/ws/ws_bootstrap.h" +#include "6LoWPAN/ws/ws_bootstrap_6ln.h" +#include "6LoWPAN/ws/ws_bootstrap_6lr.h" #include "6LoWPAN/ws/ws_bootstrap_6lbr.h" #include "6LoWPAN/ws/ws_bootstrap_ffn.h" -#include "6LoWPAN/ws/ws_bootstrap_lfn.h" #include "6LoWPAN/ws/ws_bbr_api_internal.h" #include "6LoWPAN/ws/ws_pae_controller.h" #include "6LoWPAN/ws/ws_cfg_settings.h" @@ -419,10 +420,10 @@ void ws_common_state_machine(protocol_interface_info_entry_t *cur) { if (wisun_mode_host(cur)) { // Configure for LFN device - ws_bootstrap_lfn_state_machine(cur); + ws_bootstrap_6ln_state_machine(cur); } else if (wisun_mode_router(cur)) { // Configure FFN device - ws_bootstrap_ffn_state_machine(cur); + ws_bootstrap_6lr_state_machine(cur); } else if (wisun_mode_border_router(cur)) { // Configure as Border router ws_bootstrap_6lbr_state_machine(cur); @@ -435,8 +436,8 @@ void ws_common_seconds_timer(protocol_interface_info_entry_t *cur, uint32_t seco ws_bbr_seconds_timer(cur, seconds); ws_bootstrap_seconds_timer(cur, seconds); ws_bootstrap_6lbr_seconds_timer(cur, seconds); - ws_bootstrap_ffn_seconds_timer(cur, seconds); - ws_bootstrap_lfn_seconds_timer(cur, seconds); + ws_bootstrap_6lr_seconds_timer(cur, seconds); + ws_bootstrap_6ln_seconds_timer(cur, seconds); blacklist_ttl_update(seconds); } @@ -661,12 +662,12 @@ uint32_t ws_common_authentication_time_get(protocol_interface_info_entry_t *cur) void ws_common_primary_parent_update(protocol_interface_info_entry_t *interface, mac_neighbor_table_entry_t *neighbor) { - ws_bootstrap_primary_parent_update(interface, neighbor); + ws_bootstrap_6lr_primary_parent_update(interface, neighbor); } void ws_common_secondary_parent_update(protocol_interface_info_entry_t *interface) { - ws_bootstrap_secondary_parent_update(interface); + ws_bootstrap_6lr_secondary_parent_update(interface); } void ws_common_border_router_alive_update(protocol_interface_info_entry_t *interface) diff --git a/source/6LoWPAN/ws/ws_config.h b/source/6LoWPAN/ws/ws_config.h index 9af23615d8..d2715783a3 100644 --- a/source/6LoWPAN/ws/ws_config.h +++ b/source/6LoWPAN/ws/ws_config.h @@ -246,15 +246,21 @@ extern uint8_t DEVICE_MIN_SENS; * * Trickle is reset on start (inconsistent heard is set) */ +#define SEC_PROT_TIMER_EXPIRATIONS 4 // Number of retries +#define SEC_PROT_END_DELAY 30 // 30 seconds delay + #define SEC_PROT_SMALL_IMIN 60 // Retries done in 60 seconds #define SEC_PROT_SMALL_IMAX 120 // Largest value 120 seconds -#define SEC_PROT_RETRY_TIMEOUT_SMALL 450 // Retry timeout for small network additional 30 seconds for authenticator delay +// Retry timeout for small network; additional 30 seconds for authenticator delay +#define SEC_PROT_RETRY_TIMEOUT_SMALL (SEC_PROT_SMALL_IMAX * SEC_PROT_TIMER_EXPIRATIONS + SEC_PROT_END_DELAY) #define SEC_PROT_LARGE_IMIN 60 // Retries done in 60 seconds #define SEC_PROT_LARGE_IMAX 240 // Largest value 240 seconds -#define SEC_PROT_RETRY_TIMEOUT_LARGE 750 // Retry timeout for large network additional 30 seconds for authenticator delay +// Retry timeout for large network; additional 30 seconds for authenticator delay +#define SEC_PROT_RETRY_TIMEOUT_LARGE (SEC_PROT_LARGE_IMAX * SEC_PROT_TIMER_EXPIRATIONS + SEC_PROT_END_DELAY) -#define SEC_PROT_TIMER_EXPIRATIONS 4 // Number of retries +// Timeout for retrying side of the protocol (runs when trickle not running) +#define SEC_PROT_RETRYING_PROTOCOL_TIMEOUT (5 * 60 * 10) // 5 minutes in ticks // Maximum number of simultaneous security negotiations #define MAX_SIMULTANEOUS_SECURITY_NEGOTIATIONS_TX_QUEUE_MIN 64 diff --git a/source/6LoWPAN/ws/ws_llc.h b/source/6LoWPAN/ws/ws_llc.h index da89a34959..9b8e55f380 100644 --- a/source/6LoWPAN/ws/ws_llc.h +++ b/source/6LoWPAN/ws/ws_llc.h @@ -117,7 +117,7 @@ typedef void ws_asynch_ind(struct protocol_interface_info_entry *interface, cons typedef void ws_asynch_confirm(struct protocol_interface_info_entry *interface, uint8_t asynch_message); /** - * @brief ws_asynch_confirm ws asynch data confirmation to asynch message request + * @brief ws_neighbor_info_request neighbor info request * @param interface The interface pointer * @param mac_64 Neighbor 64-bit address * @param neighbor_buffer Buffer where neighbor infor is buffered @@ -128,15 +128,31 @@ typedef void ws_asynch_confirm(struct protocol_interface_info_entry *interface, */ typedef bool ws_neighbor_info_request(struct protocol_interface_info_entry *interface, const uint8_t *mac_64, struct llc_neighbour_req *neighbor_buffer, bool request_new); +/** + * @brief ws_eapol_relay_active_check check if eapol relay is active + * @param interface The interface pointer + * + * @return true eapol relay is active + * @return false eapol relay is not active + */ +typedef bool ws_eapol_relay_active_check(struct protocol_interface_info_entry *cur); + /** * @brief ws_llc_create ws LLC module create * @param interface Interface pointer * @param asynch_ind_cb Asynch indication + * @param asynch_cnf_cb Asynch confirm + * @param ws_neighbor_info_request_cb neighbor info request + * @param eapol_relay_active_cb check if eapol relay is active + * * @param ie_ext Information element list * * Function allocate and init LLC class and init it 2 supported 2 API: ws asynch and MPX user are internally registered. + * + * @return 0 on success + * @return < 0 on failure */ -int8_t ws_llc_create(struct protocol_interface_info_entry *interface, ws_asynch_ind *asynch_ind_cb, ws_asynch_confirm *asynch_cnf_cb, ws_neighbor_info_request *ws_neighbor_info_request_cb); +int8_t ws_llc_create(struct protocol_interface_info_entry *interface, ws_asynch_ind *asynch_ind_cb, ws_asynch_confirm *asynch_cnf_cb, ws_neighbor_info_request *ws_neighbor_info_request_cb, ws_eapol_relay_active_check *eapol_relay_active_cb); /** * @brief ws_llc_reset Reset ws LLC parametrs and clean messages diff --git a/source/6LoWPAN/ws/ws_llc_data_service.c b/source/6LoWPAN/ws/ws_llc_data_service.c index 43794ba776..665a16b8c8 100644 --- a/source/6LoWPAN/ws/ws_llc_data_service.c +++ b/source/6LoWPAN/ws/ws_llc_data_service.c @@ -32,6 +32,7 @@ #include "6LoWPAN/ws/ws_common_defines.h" #include "6LoWPAN/ws/ws_common.h" #include "6LoWPAN/ws/ws_bootstrap.h" +#include "6LoWPAN/ws/ws_bootstrap_ffn.h" #include "6LoWPAN/ws/ws_ie_lib.h" #include "6LoWPAN/ws/ws_llc.h" #include "6LoWPAN/ws/ws_neighbor_class.h" @@ -153,6 +154,7 @@ typedef struct { ws_asynch_ind *asynch_ind; /**< LLC Asynch data indication call back configured by user */ ws_asynch_confirm *asynch_confirm; /**< LLC Asynch data confirmation call back configured by user */ ws_neighbor_info_request *ws_neighbor_info_request_cb; /**< LLC Neighbour discover API*/ + ws_eapol_relay_active_check *eapol_relay_active_cb; /**< EAPOL relay active check callback */ uint8_t ws_enhanced_response_elements[ENHANCED_FRAME_RESPONSE]; ns_ie_iovec_t ws_header_vector; bool high_priority_mode; @@ -992,9 +994,9 @@ static uint16_t ws_mpx_header_size_get(llc_data_base_t *base, uint16_t user_id) return header_size; } -static bool ws_eapol_handshake_first_msg(uint8_t *pdu, uint16_t length, protocol_interface_info_entry_t *cur) +static bool ws_eapol_handshake_first_msg(llc_data_base_t *base, uint8_t *pdu, uint16_t length, protocol_interface_info_entry_t *cur) { - if (!ws_eapol_relay_state_active(cur)) { + if (!base->eapol_relay_active_cb(cur)) { return false; } @@ -1246,8 +1248,8 @@ static void ws_llc_mpx_eapol_request(llc_data_base_t *base, mpx_user_t *user_cb, wp_nested_ie_sub_list_t nested_wp_id; memset(&nested_wp_id, 0, sizeof(wp_nested_ie_sub_list_t)); ie_header_mask.utt_ie = true; - ie_header_mask.bt_ie = ws_eapol_relay_state_active(base->interface_ptr); - ie_header_mask.ea_ie = ws_eapol_handshake_first_msg(data->msdu, data->msduLength, base->interface_ptr); + ie_header_mask.bt_ie = base->eapol_relay_active_cb(base->interface_ptr); /* Broadcast timing information */ + ie_header_mask.ea_ie = ws_eapol_handshake_first_msg(base, data->msdu, data->msduLength, base->interface_ptr); nested_wp_id.bs_ie = ie_header_mask.ea_ie; @@ -1746,7 +1748,7 @@ static uint16_t ws_llc_calculate_dynamic_entries_max(uint16_t min_entry, uint16_ } -int8_t ws_llc_create(struct protocol_interface_info_entry *interface, ws_asynch_ind *asynch_ind_cb, ws_asynch_confirm *asynch_cnf_cb, ws_neighbor_info_request *ws_neighbor_info_request_cb) +int8_t ws_llc_create(struct protocol_interface_info_entry *interface, ws_asynch_ind *asynch_ind_cb, ws_asynch_confirm *asynch_cnf_cb, ws_neighbor_info_request *ws_neighbor_info_request_cb, ws_eapol_relay_active_check eapol_relay_active_cb) { llc_data_base_t *base = ws_llc_discover_by_interface(interface); if (base) { @@ -1765,6 +1767,7 @@ int8_t ws_llc_create(struct protocol_interface_info_entry *interface, ws_asynch_ base->asynch_ind = asynch_ind_cb; base->asynch_confirm = asynch_cnf_cb; base->ws_neighbor_info_request_cb = ws_neighbor_info_request_cb; + base->eapol_relay_active_cb = eapol_relay_active_cb; //Register MAC Extensions base->interface_ptr->mac_api->mac_mcps_extension_enable(base->interface_ptr->mac_api, &ws_llc_mac_indication_cb, &ws_llc_mac_confirm_cb, &ws_llc_ack_data_req_ext); base->interface_ptr->mac_api->mac_mcps_edfe_enable(base->interface_ptr->mac_api, &ws_llc_mcps_edfe_handler); diff --git a/source/6LoWPAN/ws/ws_management_api.c b/source/6LoWPAN/ws/ws_management_api.c index c39f6bced0..92e280d1b1 100644 --- a/source/6LoWPAN/ws/ws_management_api.c +++ b/source/6LoWPAN/ws/ws_management_api.c @@ -327,9 +327,26 @@ int ws_management_regulatory_domain_get( return -3; } - *regulatory_domain = cfg.regulatory_domain; - *operating_class = cfg.operating_class; - *operating_mode = cfg.operating_mode; + if (regulatory_domain) { + *regulatory_domain = cfg.regulatory_domain; + } + + // If phy_mode_id is set the new configuration mode is used and class and mode return invalid value + if (operating_class) { + if (cfg.phy_mode_id == 0xff) { + *operating_class = cfg.operating_class; + } else { + *operating_class = 0xff; + } + } + + if (operating_mode) { + if (cfg.phy_mode_id == 0xff) { + *operating_mode = cfg.operating_mode; + } else { + *operating_mode = 0xff; + } + } return 0; } diff --git a/source/6LoWPAN/ws/ws_pae_auth.h b/source/6LoWPAN/ws/ws_pae_auth.h index 8abfe1e970..79df031586 100644 --- a/source/6LoWPAN/ws/ws_pae_auth.h +++ b/source/6LoWPAN/ws/ws_pae_auth.h @@ -295,7 +295,7 @@ void ws_pae_auth_cb_register(protocol_interface_info_entry_t *interface_ptr, ws_ #define ws_pae_auth_timing_adjust(timing) #define ws_pae_auth_addresses_set(interface_ptr, local_port, remote_addr, remote_port) 1 #define ws_pae_auth_delete NULL -#define ws_pae_auth_cb_register(interface_ptr, hash_set, nw_key_insert, nw_key_index_set, nw_info_updated, ip_addr_get, congestion_get, nw_frame_cnt_read) {(void) hash_set;} +#define ws_pae_auth_cb_register(interface_ptr, hash_set, nw_key_insert, nw_key_index_set, nw_info_updated, ip_addr_get, congestion_get, nw_frame_cnt_read) #define ws_pae_auth_start(interface_ptr) #define ws_pae_auth_gtks_updated NULL #define ws_pae_auth_nw_key_index_update NULL diff --git a/source/6LoWPAN/ws/ws_pae_controller.c b/source/6LoWPAN/ws/ws_pae_controller.c index 6511616540..fdc0dbfd0a 100644 --- a/source/6LoWPAN/ws/ws_pae_controller.c +++ b/source/6LoWPAN/ws/ws_pae_controller.c @@ -64,11 +64,15 @@ typedef struct { typedef struct { ns_list_link_t link; /**< Link */ +#ifdef HAVE_PAE_SUPP uint8_t target_eui_64[8]; /**< EAPOL target */ uint16_t target_pan_id; /**< EAPOL target PAN ID */ +#endif uint8_t br_eui_64[8]; /**< Border router EUI-64 */ sec_prot_gtk_keys_t gtks; /**< GTKs */ +#ifdef HAVE_PAE_AUTH sec_prot_gtk_keys_t next_gtks; /**< Next GTKs */ +#endif sec_prot_keys_nw_info_t sec_keys_nw_info; /**< Security keys network information */ int8_t gtk_index; /**< GTK index */ uint8_t gtkhash[32]; /**< GTK hashes */ @@ -80,17 +84,21 @@ typedef struct { sec_cfg_t sec_cfg; /**< Security configuration (configuration set values) */ uint32_t restart_cnt; /**< Re-start counter */ protocol_interface_info_entry_t *interface_ptr; /**< List link entry */ - ws_pae_controller_auth_completed *auth_completed; /**< Authentication completed callback, continue bootstrap */ ws_pae_controller_nw_key_set *nw_key_set; /**< Key set callback */ ws_pae_controller_nw_key_clear *nw_key_clear; /**< Key clear callback */ ws_pae_controller_nw_send_key_index_set *nw_send_key_index_set; /**< Send key index set callback */ ws_pae_controller_nw_frame_counter_set *nw_frame_counter_set; /**< Frame counter set callback */ ws_pae_controller_nw_frame_counter_read *nw_frame_counter_read; /**< Frame counter read callback */ +#ifdef HAVE_PAE_SUPP + ws_pae_controller_auth_completed *auth_completed; /**< Authentication completed callback, continue bootstrap */ + ws_pae_controller_auth_next_target *auth_next_target; /**< Authentication next target callback */ +#endif +#ifdef HAVE_PAE_AUTH ws_pae_controller_pan_ver_increment *pan_ver_increment; /**< PAN version increment callback */ ws_pae_controller_nw_info_updated *nw_info_updated; /**< Network information updated callback */ - ws_pae_controller_auth_next_target *auth_next_target; /**< Authentication next target callback */ ws_pae_controller_congestion_get *congestion_get; /**< Congestion get callback */ ws_pae_controller_ip_addr_get *ip_addr_get; /**< IP address get callback */ +#endif ws_pae_delete *pae_delete; /**< PAE delete callback */ ws_pae_timer *pae_fast_timer; /**< PAE fast timer callback */ ws_pae_timer *pae_slow_timer; /**< PAE slow timer callback */ @@ -128,10 +136,14 @@ static void ws_pae_controller_frame_counter_store(pae_controller_t *entry, bool static void ws_pae_controller_nvm_frame_counter_write(frame_cnt_nvm_tlv_t *tlv_entry); static int8_t ws_pae_controller_nvm_frame_counter_read(uint32_t *restart_cnt, uint64_t *stored_time, uint16_t *pan_version, frame_counters_t *counters); static pae_controller_t *ws_pae_controller_get_or_create(int8_t interface_id); +#ifdef HAVE_PAE_AUTH static void ws_pae_controller_gtk_hash_set(protocol_interface_info_entry_t *interface_ptr, uint8_t *gtkhash); +#endif static int8_t ws_pae_controller_nw_key_check_and_insert(protocol_interface_info_entry_t *interface_ptr, sec_prot_gtk_keys_t *gtks, bool force_install); static void ws_pae_controller_active_nw_key_clear(nw_key_t *nw_key); +#ifdef HAVE_PAE_SUPP static void ws_pae_controller_active_nw_key_set(protocol_interface_info_entry_t *cur, uint8_t index); +#endif static int8_t ws_pae_controller_gak_from_gtk(uint8_t *gak, uint8_t *gtk, char *network_name); static void ws_pae_controller_frame_counter_store_and_nw_keys_remove(protocol_interface_info_entry_t *interface_ptr, pae_controller_t *controller, bool use_threshold); #ifdef HAVE_PAE_AUTH @@ -250,7 +262,7 @@ int8_t ws_pae_controller_authenticator_start(protocol_interface_info_entry_t *in return 0; } -int8_t ws_pae_controller_cb_register(protocol_interface_info_entry_t *interface_ptr, ws_pae_controller_auth_completed *completed, ws_pae_controller_auth_next_target *auth_next_target, ws_pae_controller_nw_key_set *nw_key_set, ws_pae_controller_nw_key_clear *nw_key_clear, ws_pae_controller_nw_send_key_index_set *nw_send_key_index_set, ws_pae_controller_nw_frame_counter_set *nw_frame_counter_set, ws_pae_controller_nw_frame_counter_read *nw_frame_counter_read, ws_pae_controller_pan_ver_increment *pan_ver_increment, ws_pae_controller_nw_info_updated *nw_info_updated, ws_pae_controller_congestion_get *congestion_get) +int8_t ws_pae_controller_nw_key_cb_register(protocol_interface_info_entry_t *interface_ptr, ws_pae_controller_nw_key_set *nw_key_set, ws_pae_controller_nw_key_clear *nw_key_clear, ws_pae_controller_nw_send_key_index_set *nw_send_key_index_set, ws_pae_controller_nw_frame_counter_set *nw_frame_counter_set, ws_pae_controller_nw_frame_counter_read *nw_frame_counter_read) { if (!interface_ptr) { return -1; @@ -261,21 +273,40 @@ int8_t ws_pae_controller_cb_register(protocol_interface_info_entry_t *interface_ return -1; } + controller->nw_key_set = nw_key_set; + controller->nw_key_clear = nw_key_clear; + controller->nw_send_key_index_set = nw_send_key_index_set; + controller->nw_frame_counter_set = nw_frame_counter_set; + controller->nw_frame_counter_read = nw_frame_counter_read; + return 0; +} + +int8_t ws_pae_controller_authentication_cb_register(protocol_interface_info_entry_t *interface_ptr, ws_pae_controller_auth_completed *completed, ws_pae_controller_auth_next_target *auth_next_target) +{ +#ifdef HAVE_PAE_SUPP + if (!interface_ptr) { + return -1; + } + + pae_controller_t *controller = ws_pae_controller_get(interface_ptr); + if (!controller) { + return -1; + } + controller->auth_completed = completed; - controller->nw_key_set = nw_key_set; - controller->nw_key_clear = nw_key_clear; - controller->nw_send_key_index_set = nw_send_key_index_set; - controller->nw_frame_counter_set = nw_frame_counter_set; - controller->nw_frame_counter_read = nw_frame_counter_read; - controller->pan_ver_increment = pan_ver_increment; - controller->nw_info_updated = nw_info_updated; controller->auth_next_target = auth_next_target; - controller->congestion_get = congestion_get; return 0; +#else + (void) interface_ptr; + (void) completed; + (void) auth_next_target; + return 0; +#endif } -int8_t ws_pae_controller_auth_cb_register(protocol_interface_info_entry_t *interface_ptr, ws_pae_controller_ip_addr_get *ip_addr_get) +int8_t ws_pae_controller_information_cb_register(protocol_interface_info_entry_t *interface_ptr, ws_pae_controller_ip_addr_get *ip_addr_get, ws_pae_controller_nw_info_updated *nw_info_updated, ws_pae_controller_congestion_get *congestion_get) { +#ifdef HAVE_PAE_AUTH if (!interface_ptr) { return -1; } @@ -286,11 +317,42 @@ int8_t ws_pae_controller_auth_cb_register(protocol_interface_info_entry_t *inter } controller->ip_addr_get = ip_addr_get; + controller->nw_info_updated = nw_info_updated; + controller->congestion_get = congestion_get; return 0; +#else + (void) interface_ptr; + (void) ip_addr_get; + (void) nw_info_updated; + (void) congestion_get; + return 0; +#endif +} + +int8_t ws_pae_controller_pan_version_cb_register(protocol_interface_info_entry_t *interface_ptr, ws_pae_controller_pan_ver_increment *pan_ver_increment) +{ +#ifdef HAVE_PAE_AUTH + if (!interface_ptr) { + return -1; + } + + pae_controller_t *controller = ws_pae_controller_get(interface_ptr); + if (!controller) { + return -1; + } + + controller->pan_ver_increment = pan_ver_increment; + return 0; +#else + (void) interface_ptr; + (void) pan_ver_increment; + return 0; +#endif } int8_t ws_pae_controller_set_target(protocol_interface_info_entry_t *interface_ptr, uint16_t target_pan_id, uint8_t *target_eui_64) { +#ifdef HAVE_PAE_SUPP if (!interface_ptr) { return -1; } @@ -304,6 +366,12 @@ int8_t ws_pae_controller_set_target(protocol_interface_info_entry_t *interface_p memcpy(controller->target_eui_64, target_eui_64, 8); return 0; +#else + (void) interface_ptr; + (void) target_pan_id; + (void) target_eui_64; + return -1; +#endif } static void ws_pae_controller_keys_nw_info_init(sec_prot_keys_nw_info_t *sec_keys_nw_info, sec_prot_gtk_keys_t *gtks) @@ -432,6 +500,8 @@ static int8_t ws_pae_controller_auth_nw_frame_counter_read(protocol_interface_in int8_t ws_pae_controller_nw_key_valid(protocol_interface_info_entry_t *interface_ptr, uint8_t *br_iid) { + (void) br_iid; + if (!interface_ptr) { return -1; } @@ -683,6 +753,7 @@ static void ws_pae_controller_nw_key_index_check_and_set(protocol_interface_info } #endif +#ifdef HAVE_PAE_SUPP static void ws_pae_controller_active_nw_key_set(protocol_interface_info_entry_t *cur, uint8_t index) { pae_controller_t *controller = ws_pae_controller_get(cur); @@ -701,6 +772,7 @@ static void ws_pae_controller_active_nw_key_set(protocol_interface_info_entry_t } } +#endif int8_t ws_pae_controller_init(protocol_interface_info_entry_t *interface_ptr) { @@ -720,15 +792,21 @@ int8_t ws_pae_controller_init(protocol_interface_info_entry_t *interface_ptr) } controller->interface_ptr = interface_ptr; - controller->auth_completed = NULL; controller->nw_key_set = NULL; controller->nw_key_clear = NULL; controller->nw_send_key_index_set = NULL; controller->nw_frame_counter_set = NULL; + controller->nw_frame_counter_read = NULL; +#ifdef HAVE_PAE_SUPP + controller->auth_completed = NULL; + controller->auth_next_target = NULL; +#endif +#ifdef HAVE_PAE_AUTH controller->pan_ver_increment = NULL; controller->nw_info_updated = NULL; - controller->auth_next_target = NULL; controller->congestion_get = NULL; + controller->ip_addr_get = NULL; +#endif memset(&controller->sec_cfg, 0, sizeof(sec_cfg_t)); @@ -773,7 +851,9 @@ int8_t ws_pae_controller_configure(protocol_interface_info_entry_t *interface_pt static void ws_pae_controller_data_init(pae_controller_t *controller) { +#ifdef HAVE_PAE_SUPP memset(controller->target_eui_64, 0, 8); +#endif memset(controller->br_eui_64, 0, 8); memset(controller->gtkhash, 0, 32); @@ -782,7 +862,9 @@ static void ws_pae_controller_data_init(pae_controller_t *controller) ws_pae_controller_active_nw_key_clear(&controller->nw_key[2]); ws_pae_controller_active_nw_key_clear(&controller->nw_key[3]); +#ifdef HAVE_PAE_SUPP controller->target_pan_id = 0xffff; +#endif controller->pae_delete = NULL; controller->pae_fast_timer = NULL; controller->pae_slow_timer = NULL; @@ -803,7 +885,9 @@ static void ws_pae_controller_data_init(pae_controller_t *controller) controller->auth_started = false; ws_pae_controller_frame_counter_reset(&controller->frame_counters); sec_prot_keys_gtks_init(&controller->gtks); +#ifdef HAVE_PAE_AUTH sec_prot_keys_gtks_init(&controller->next_gtks); +#endif sec_prot_certs_init(&controller->certs); sec_prot_certs_ext_certificate_validation_set(&controller->certs, pae_controller_config.ext_cert_valid_enabled); ws_pae_controller_keys_nw_info_init(&controller->sec_keys_nw_info, &controller->gtks); @@ -1006,7 +1090,6 @@ int8_t ws_pae_controller_auth_init(protocol_interface_info_entry_t *interface_pt } sec_prot_keys_gtks_updated_reset(&controller->gtks); } -#endif if (read_gtks_to && ws_pae_controller_nw_info_read(controller, read_gtks_to) >= 0) { /* If network information i.e pan_id and network name exists updates bootstrap with it, (in case already configured by application then no changes are made) */ @@ -1020,6 +1103,7 @@ int8_t ws_pae_controller_auth_init(protocol_interface_info_entry_t *interface_pt ws_pae_controller_nvm_nw_info_write(controller->interface_ptr, controller->sec_keys_nw_info.key_pan_id, controller->sec_keys_nw_info.network_name, gtk_eui64, NULL, system_time, controller->sec_keys_nw_info.system_time_changed); } } +#endif ws_pae_key_storage_init(); if (read_gtks_to) { @@ -1539,6 +1623,7 @@ int8_t ws_pae_controller_gtk_update(int8_t interface_id, uint8_t *gtk[GTK_NUM]) int8_t ws_pae_controller_next_gtk_update(int8_t interface_id, uint8_t *gtk[GTK_NUM]) { +#ifdef HAVE_PAE_AUTH if (!gtk) { return -1; } @@ -1558,6 +1643,11 @@ int8_t ws_pae_controller_next_gtk_update(int8_t interface_id, uint8_t *gtk[GTK_N } return 0; +#else + (void) interface_id; + (void) gtk; + return -1; +#endif } int8_t ws_pae_controller_active_key_update(int8_t interface_id, uint8_t index) @@ -1657,6 +1747,7 @@ void ws_pae_controller_forced_gc(bool full_gc) } } +#ifdef HAVE_PAE_AUTH static void ws_pae_controller_gtk_hash_set(protocol_interface_info_entry_t *interface_ptr, uint8_t *gtkhash) { pae_controller_t *controller = ws_pae_controller_get(interface_ptr); @@ -1681,6 +1772,7 @@ static void ws_pae_controller_gtk_hash_set(protocol_interface_info_entry_t *inte controller->gtkhash_set = true; } } +#endif uint8_t *ws_pae_controller_gtk_hash_ptr_get(protocol_interface_info_entry_t *interface_ptr) { diff --git a/source/6LoWPAN/ws/ws_pae_controller.h b/source/6LoWPAN/ws/ws_pae_controller.h index 40cd01fb0b..ab31a7c75a 100644 --- a/source/6LoWPAN/ws/ws_pae_controller.h +++ b/source/6LoWPAN/ws/ws_pae_controller.h @@ -573,6 +573,22 @@ typedef void ws_pae_controller_nw_frame_counter_set(protocol_interface_info_entr */ typedef void ws_pae_controller_nw_frame_counter_read(protocol_interface_info_entry_t *interface_ptr, uint32_t *counter, uint8_t slot); +/** + * ws_pae_controller_nw_key_cb_register register network key control callbacks + * + * \param interface_ptr interface + * \param nw_key_set network key set callback + * \param nw_key_clear network key clear callback + * \param nw_send_key_index_set network send key index set callback + * \param nw_frame_counter_set network frame counter set callback + * \param nw_frame_counter_read network frame counter read callback + * + * \return < 0 failure + * \return >= 0 success + * + */ +int8_t ws_pae_controller_nw_key_cb_register(protocol_interface_info_entry_t *interface_ptr, ws_pae_controller_nw_key_set *nw_key_set, ws_pae_controller_nw_key_clear *nw_key_clear, ws_pae_controller_nw_send_key_index_set *nw_send_key_index_set, ws_pae_controller_nw_frame_counter_set *nw_frame_counter_set, ws_pae_controller_nw_frame_counter_read *nw_frame_counter_read); + /** * ws_pae_controller_auth_completed authentication completed callback * @@ -596,12 +612,29 @@ typedef void ws_pae_controller_auth_completed(protocol_interface_info_entry_t *i typedef const uint8_t *ws_pae_controller_auth_next_target(protocol_interface_info_entry_t *interface_ptr, const uint8_t *previous_eui_64, uint16_t *pan_id); /** - * ws_pae_controller_pan_ver_increment PAN version increment callback + * ws_pae_controller_authentication_cb_register register supplicant authentication control callbacks * * \param interface_ptr interface + * \param completed authentication completed callback + * \param next_target authentication next target callback + * + * \return < 0 failure + * \return >= 0 success * */ -typedef void ws_pae_controller_pan_ver_increment(protocol_interface_info_entry_t *interface_ptr); +int8_t ws_pae_controller_authentication_cb_register(protocol_interface_info_entry_t *interface_ptr, ws_pae_controller_auth_completed *completed, ws_pae_controller_auth_next_target *auth_next_target); + +/** + * ws_pae_controller_ip_addr_get gets IP addressing information + * + * \param interface_ptr interface + * \param address IP address + * + * \return < 0 failure + * \return >= 0 success + * + */ +typedef int8_t ws_pae_controller_ip_addr_get(protocol_interface_info_entry_t *interface_ptr, uint8_t *address); /** * ws_pae_controller_nw_info_updated network information is updated (read from memory) @@ -626,17 +659,10 @@ typedef void ws_pae_controller_nw_info_updated(protocol_interface_info_entry_t * typedef bool ws_pae_controller_congestion_get(protocol_interface_info_entry_t *interface_ptr, uint16_t active_supp); /** - * ws_pae_controller_cb_register register controller callbacks + * ws_pae_controller_information_cb_register register information callbacks * * \param interface_ptr interface - * \param completed authentication completed callback - * \param next_target authentication next target callback - * \param nw_key_set network key set callback - * \param nw_key_clear network key clear callback - * \param nw_send_key_index_set network send key index set callback - * \param nw_frame_counter_set network frame counter set callback - * \param nw_frame_counter_read network frame counter read callback - * \param pan_ver_increment PAN version increment callback + * \param ip_addr_get IP address get callback * \param nw_info_updated network information updated callback * \param congestion_get congestion get callback * @@ -644,31 +670,27 @@ typedef bool ws_pae_controller_congestion_get(protocol_interface_info_entry_t *i * \return >= 0 success * */ -int8_t ws_pae_controller_cb_register(protocol_interface_info_entry_t *interface_ptr, ws_pae_controller_auth_completed *completed, ws_pae_controller_auth_next_target *auth_next_target, ws_pae_controller_nw_key_set *nw_key_set, ws_pae_controller_nw_key_clear *nw_key_clear, ws_pae_controller_nw_send_key_index_set *nw_send_key_index_set, ws_pae_controller_nw_frame_counter_set *nw_frame_counter_set, ws_pae_controller_nw_frame_counter_read *nw_frame_counter_read, ws_pae_controller_pan_ver_increment *pan_ver_increment, ws_pae_controller_nw_info_updated *nw_info_updated, ws_pae_controller_congestion_get *congestion_get); +int8_t ws_pae_controller_information_cb_register(protocol_interface_info_entry_t *interface_ptr, ws_pae_controller_ip_addr_get *ip_addr_get, ws_pae_controller_nw_info_updated *nw_info_updated, ws_pae_controller_congestion_get *congestion_get); /** - * ws_pae_controller_ip_addr_get gets IP addressing information + * ws_pae_controller_pan_ver_increment PAN version increment callback * * \param interface_ptr interface - * \param address IP address + * + */ +typedef void ws_pae_controller_pan_ver_increment(protocol_interface_info_entry_t *interface_ptr); + +/** + * ws_pae_controller_bbr_control_cb_register register PAN version control callbacks + * + * \param interface_ptr interface + * \param pan_ver_increment PAN version increment callback * * \return < 0 failure * \return >= 0 success * */ -typedef int8_t ws_pae_controller_ip_addr_get(protocol_interface_info_entry_t *interface_ptr, uint8_t *address); - -/** - * ws_pae_controller_auth_cb_register register authenticator callbacks - * - * \param interface_ptr interface - * \param ip_addr_get IP address get callback - * - * \return < 0 failure - * \return >= 0 success - * - */ -int8_t ws_pae_controller_auth_cb_register(protocol_interface_info_entry_t *interface_ptr, ws_pae_controller_ip_addr_get *ip_addr_get); +int8_t ws_pae_controller_pan_version_cb_register(protocol_interface_info_entry_t *interface_ptr, ws_pae_controller_pan_ver_increment *pan_ver_increment); /** * ws_pae_controller_fast_timer PAE controller fast timer call diff --git a/source/6LoWPAN/ws/ws_pae_key_storage.c b/source/6LoWPAN/ws/ws_pae_key_storage.c index 398c9ac0cd..04fd4d4757 100644 --- a/source/6LoWPAN/ws/ws_pae_key_storage.c +++ b/source/6LoWPAN/ws/ws_pae_key_storage.c @@ -42,6 +42,7 @@ #include "6LoWPAN/ws/ws_pae_key_storage.h" #ifdef HAVE_WS +#ifdef HAVE_PAE_AUTH #define TRACE_GROUP "wsks" @@ -1081,5 +1082,6 @@ static void ws_pae_key_storage_array_ptk_invalid(sec_prot_keys_storage_t *storag storage_array->ptk_lifetime = 0; } +#endif /* HAVE_PAE_AUTH */ #endif /* HAVE_WS */ diff --git a/source/6LoWPAN/ws/ws_pae_key_storage.h b/source/6LoWPAN/ws/ws_pae_key_storage.h index 39e6df60e0..7c170b6331 100644 --- a/source/6LoWPAN/ws/ws_pae_key_storage.h +++ b/source/6LoWPAN/ws/ws_pae_key_storage.h @@ -18,6 +18,8 @@ #ifndef WS_PAE_KEY_STORAGE_H_ #define WS_PAE_KEY_STORAGE_H_ +#ifdef HAVE_PAE_AUTH + /* * Port access entity key storage functions. * @@ -169,4 +171,22 @@ void ws_pae_key_storage_fast_timer(uint16_t ticks); */ uint16_t ws_pae_key_storage_storing_interval_get(void); +#else + +#define ws_pae_key_storage_memory_set(key_storages_number, key_storage_size, key_storages) +#define ws_pae_key_storage_settings_set(alloc_max_number, alloc_size, storing_interval) +#define ws_pae_key_storage_init() +#define ws_pae_key_storage_delete() +#define ws_pae_key_storage_store() +#define ws_pae_key_storage_read(restart_cnt) +#define ws_pae_key_storage_remove() +#define ws_pae_key_storage_supp_write(instance, pae_supp) +#define ws_pae_key_storage_supp_read(instance, eui_64, gtks, certs) +#define ws_pae_key_storage_supp_delete(instance, eui64) +#define ws_pae_key_storage_timer(seconds) +#define ws_pae_key_storage_fast_timer(ticks) +#define ws_pae_key_storage_storing_interval_get() 0 + +#endif + #endif /* WS_PAE_KEY_STORAGE_H_ */ diff --git a/source/6LoWPAN/ws/ws_pae_lib.c b/source/6LoWPAN/ws/ws_pae_lib.c index bc14ba93ab..e833dc3019 100644 --- a/source/6LoWPAN/ws/ws_pae_lib.c +++ b/source/6LoWPAN/ws/ws_pae_lib.c @@ -374,9 +374,6 @@ void ws_pae_lib_supp_list_to_inactive(void *instance, supp_list_t *active_supp_l // Remove supplicant entry ws_pae_lib_supp_list_remove(instance, active_supp_list, entry, supp_deleted); - if (supp_deleted) { - supp_deleted(instance); - } } void ws_pae_lib_supp_list_purge(void *instance, supp_list_t *active_supp_list, uint16_t max_number, uint8_t max_purge, ws_pae_lib_supp_deleted supp_deleted) diff --git a/source/6LoWPAN/ws/ws_pae_supp.c b/source/6LoWPAN/ws/ws_pae_supp.c index 7e518c465b..8c6cefdb78 100644 --- a/source/6LoWPAN/ws/ws_pae_supp.c +++ b/source/6LoWPAN/ws/ws_pae_supp.c @@ -1007,6 +1007,7 @@ static int8_t ws_pae_supp_eapol_pdu_address_check(protocol_interface_info_entry_ static int8_t ws_pae_supp_parent_eui_64_get(protocol_interface_info_entry_t *interface_ptr, uint8_t *eui_64) { rpl_dodag_info_t dodag_info; + (void) dodag_info; // avoid unused warning in ws_host mode if (!interface_ptr->rpl_domain) { return -1; } diff --git a/source/6LoWPAN/ws/ws_pae_supp.h b/source/6LoWPAN/ws/ws_pae_supp.h index c991d65062..377c78ec76 100644 --- a/source/6LoWPAN/ws/ws_pae_supp.h +++ b/source/6LoWPAN/ws/ws_pae_supp.h @@ -265,8 +265,8 @@ void ws_pae_supp_cb_register(protocol_interface_info_entry_t *interface_ptr, ws_ #define ws_pae_supp_init(interface_ptr, certs, sec_timer_cfg, sec_prot_cfg) 1 #define ws_pae_supp_delete NULL #define ws_pae_supp_timing_adjust(timing) 1 -#define ws_pae_supp_cb_register(interface_ptr, completed, nw_key_insert, nw_key_index_set) -#define ws_pae_supp_nw_key_valid(interface_ptr) -1 +#define ws_pae_supp_cb_register(interface_ptr, completed, auth_next_target,nw_key_insert, nw_key_index_set, gtk_hash_ptr_get, nw_info_updated) +#define ws_pae_supp_nw_key_valid(interface_ptr, br_iid) -1 #define ws_pae_supp_fast_timer NULL #define ws_pae_supp_slow_timer NULL #define ws_pae_supp_authenticate(interface_ptr, dest_pan_id, dest_eui_64) PAE_SUPP_NOT_ENABLED @@ -276,6 +276,7 @@ void ws_pae_supp_cb_register(protocol_interface_info_entry_t *interface_ptr, ws_ #define ws_pae_supp_nw_key_index_update NULL #define ws_pae_supp_gtks_set(interface_ptr, gtks) #define ws_pae_supp_eapol_target_remove(interface_ptr) +#define ws_pae_supp_nw_info_set NULL #endif diff --git a/source/6LoWPAN/ws/ws_test_api.c b/source/6LoWPAN/ws/ws_test_api.c index 4dc5d394b1..902cc352b6 100644 --- a/source/6LoWPAN/ws/ws_test_api.c +++ b/source/6LoWPAN/ws/ws_test_api.c @@ -218,7 +218,7 @@ int ws_test_procedure_trigger(int8_t interface_id, ws_test_proc_t procedure, voi } } - return ws_bootstrap_test_procedure_trigger(cur, procedure); + return ws_bootstrap_test_procedure_trigger(cur, (ws_bootsrap_procedure_t) procedure); } #endif // HAVE_WS diff --git a/source/BorderRouter/CMakeLists.txt b/source/BorderRouter/CMakeLists.txt new file mode 100644 index 0000000000..3f0d5fafce --- /dev/null +++ b/source/BorderRouter/CMakeLists.txt @@ -0,0 +1,12 @@ +# Copyright (c) 2020-2021, Pelion and affiliates. +# SPDX-License-Identifier: Apache-2.0 + +target_include_directories(mbed-nanostack-sal_stack + INTERFACE + . +) + +target_sources(mbed-nanostack-sal_stack + INTERFACE + border_router.c +) diff --git a/source/Common_Protocols/CMakeLists.txt b/source/Common_Protocols/CMakeLists.txt new file mode 100644 index 0000000000..31bcdffc22 --- /dev/null +++ b/source/Common_Protocols/CMakeLists.txt @@ -0,0 +1,21 @@ +# Copyright (c) 2020-2021, Pelion and affiliates. +# SPDX-License-Identifier: Apache-2.0 + +target_include_directories(mbed-nanostack-sal_stack + INTERFACE + . +) + +target_sources(mbed-nanostack-sal_stack + INTERFACE + icmpv6.c + icmpv6_prefix.c + icmpv6_radv.c + ipv6.c + ipv6_flow.c + ipv6_fragmentation.c + ipv6_resolution.c + mld.c + tcp.c + udp.c +) diff --git a/source/Common_Protocols/icmpv6_radv.c b/source/Common_Protocols/icmpv6_radv.c index 9ad0544322..f49f7303bb 100644 --- a/source/Common_Protocols/icmpv6_radv.c +++ b/source/Common_Protocols/icmpv6_radv.c @@ -326,6 +326,7 @@ void icmpv6_stop_router_advertisements(protocol_interface_info_entry_t *cur, con static void icmpv6_send_ra(protocol_interface_info_entry_t *cur, const uint8_t *dest, const uint8_t *abro) { #ifndef HAVE_RPL + (void) dest; (void) abro; #endif if (cur->nwk_id == IF_6LoWPAN) { diff --git a/source/Core/CMakeLists.txt b/source/Core/CMakeLists.txt new file mode 100644 index 0000000000..ae8903fe3f --- /dev/null +++ b/source/Core/CMakeLists.txt @@ -0,0 +1,17 @@ +# Copyright (c) 2020-2021, Pelion and affiliates. +# SPDX-License-Identifier: Apache-2.0 + +target_include_directories(mbed-nanostack-sal_stack + INTERFACE + . + ./include +) + +target_sources(mbed-nanostack-sal_stack + INTERFACE + buffer_dyn.c + ns_address_internal.c + ns_monitor.c + ns_socket.c + sockbuf.c +) diff --git a/source/Core/ns_socket.c b/source/Core/ns_socket.c index d91c03d0d3..c520c20279 100644 --- a/source/Core/ns_socket.c +++ b/source/Core/ns_socket.c @@ -1438,6 +1438,10 @@ buffer_t *socket_tx_buffer_event(buffer_t *buf, uint8_t status) if (buf->ack_receive_cb) { buf->ack_receive_cb(buf, status); } + if (status == SOCKET_BUSY) { + //SOCKET_BUSY shuold not be forward further and switched back orginal behaviour + status = SOCKET_TX_FAIL; + } /* Suppress events once socket orphaned */ if (!buf->socket || (buf->socket->flags & (SOCKET_FLAG_PENDING | SOCKET_FLAG_CLOSED))) { diff --git a/source/DHCPv6_Server/CMakeLists.txt b/source/DHCPv6_Server/CMakeLists.txt new file mode 100644 index 0000000000..f62037f121 --- /dev/null +++ b/source/DHCPv6_Server/CMakeLists.txt @@ -0,0 +1,12 @@ +# Copyright (c) 2020-2021, Pelion and affiliates. +# SPDX-License-Identifier: Apache-2.0 + +target_include_directories(mbed-nanostack-sal_stack + INTERFACE + . +) + +target_sources(mbed-nanostack-sal_stack + INTERFACE + DHCPv6_Server_service.c +) diff --git a/source/DHCPv6_client/CMakeLists.txt b/source/DHCPv6_client/CMakeLists.txt new file mode 100644 index 0000000000..1838ab0153 --- /dev/null +++ b/source/DHCPv6_client/CMakeLists.txt @@ -0,0 +1,12 @@ +# Copyright (c) 2020-2021, Pelion and affiliates. +# SPDX-License-Identifier: Apache-2.0 + +target_include_directories(mbed-nanostack-sal_stack + INTERFACE + . +) + +target_sources(mbed-nanostack-sal_stack + INTERFACE + dhcpv6_client_service.c +) diff --git a/source/MAC/CMakeLists.txt b/source/MAC/CMakeLists.txt new file mode 100644 index 0000000000..6dec6f74a7 --- /dev/null +++ b/source/MAC/CMakeLists.txt @@ -0,0 +1,34 @@ +# Copyright (c) 2020-2021, Pelion and affiliates. +# SPDX-License-Identifier: Apache-2.0 + +target_include_directories(mbed-nanostack-sal_stack + INTERFACE + . + ./IEEE802_15_4 + ./virtual_rf +) + +target_sources(mbed-nanostack-sal_stack + INTERFACE + rf_driver_storage.c + + IEEE802_15_4/mac_cca_threshold.c + IEEE802_15_4/mac_fhss_callbacks.c + IEEE802_15_4/mac_filter.c + IEEE802_15_4/mac_header_helper_functions.c + IEEE802_15_4/mac_indirect_data.c + IEEE802_15_4/mac_mcps_sap.c + IEEE802_15_4/mac_mlme.c + IEEE802_15_4/mac_mode_switch.c + IEEE802_15_4/mac_pd_sap.c + IEEE802_15_4/mac_security_mib.c + IEEE802_15_4/mac_timer.c + IEEE802_15_4/sw_mac.c + + ethernet/ethernet_mac_api.c + + serial/serial_mac_api.c + + virtual_rf/virtual_rf_client.c + virtual_rf/virtual_rf_driver.c +) diff --git a/source/MAC/IEEE802_15_4/mac_mlme.c b/source/MAC/IEEE802_15_4/mac_mlme.c index cbc6682020..0e6e7c6c50 100644 --- a/source/MAC/IEEE802_15_4/mac_mlme.c +++ b/source/MAC/IEEE802_15_4/mac_mlme.c @@ -71,6 +71,7 @@ static void mac_mlme_start_confirm_handler(protocol_interface_rf_mac_setup_s *rf static void mac_mlme_scan_confirm_handler(protocol_interface_rf_mac_setup_s *rf_ptr, const mlme_scan_conf_t *conf); static int mac_mlme_set_symbol_rate(protocol_interface_rf_mac_setup_s *rf_mac_setup); static int mac_mlme_allocate_tx_buffers(protocol_interface_rf_mac_setup_s *rf_mac_setup, arm_device_driver_list_s *dev_driver, uint16_t mtu_size); +static int mac_mlme_allocate_beacon_payload_buffer(protocol_interface_rf_mac_setup_s *rf_mac_setup, uint16_t mtu_size); static void mac_mlme_energy_scan_start(protocol_interface_rf_mac_setup_s *rf_mac_setup, uint8_t channel) { @@ -1133,7 +1134,6 @@ static int mac_mlme_set_symbol_rate(protocol_interface_rf_mac_setup_s *rf_mac_se static int mac_mlme_allocate_tx_buffers(protocol_interface_rf_mac_setup_s *rf_mac_setup, arm_device_driver_list_s *dev_driver, uint16_t mtu_size) { ns_dyn_mem_free(rf_mac_setup->dev_driver_tx_buffer.buf); - ns_dyn_mem_free(rf_mac_setup->mac_beacon_payload); uint16_t total_length = 0; //Allocate tx buffer by given MTU + header + tail total_length = mtu_size; @@ -1142,15 +1142,26 @@ static int mac_mlme_allocate_tx_buffers(protocol_interface_rf_mac_setup_s *rf_ma if (!rf_mac_setup->dev_driver_tx_buffer.buf) { return -1; } - //allocate Beacon Payload buffer - rf_mac_setup->max_beacon_payload_length = mtu_size - MAC_IEEE_802_15_4_MAX_BEACON_OVERHEAD; - rf_mac_setup->mac_beacon_payload = ns_dyn_mem_alloc(rf_mac_setup->max_beacon_payload_length); + + return 0; +} + +static int mac_mlme_allocate_beacon_payload_buffer(protocol_interface_rf_mac_setup_s *rf_mac_setup, uint16_t mtu_size) +{ + + rf_mac_setup->mac_beacon_payload = ns_dyn_mem_alloc(mtu_size); if (!rf_mac_setup->mac_beacon_payload) { return -1; } + + rf_mac_setup->max_beacon_payload_length = mtu_size; + rf_mac_setup->mac_beacon_payload_size = 0; + memset(rf_mac_setup->mac_beacon_payload, 0, rf_mac_setup->max_beacon_payload_length); return 0; } + + protocol_interface_rf_mac_setup_s *mac_mlme_data_base_allocate(uint8_t *mac64, arm_device_driver_list_s *dev_driver, mac_description_storage_size_t *storage_sizes, uint16_t mtu_size) { //allocate security @@ -1191,6 +1202,11 @@ protocol_interface_rf_mac_setup_s *mac_mlme_data_base_allocate(uint8_t *mac64, a mac_mlme_data_base_deallocate(entry); return NULL; } + //Allocate Default Beacon pyload data + if (mac_mlme_allocate_beacon_payload_buffer(entry, MAC_IEEE_802_15_4_MAX_BEACON_PAYLOAD_LENGTH)) { + mac_mlme_data_base_deallocate(entry); + return NULL; + } entry->mac_tasklet_id = mac_mcps_sap_tasklet_init(); if (entry->mac_tasklet_id < 0) { @@ -1213,7 +1229,6 @@ protocol_interface_rf_mac_setup_s *mac_mlme_data_base_allocate(uint8_t *mac64, a entry->mac_mlme_retry_max = MAC_DEFAULT_MAX_FRAME_RETRIES; memset(entry->mac_default_key_source, 0xff, 8); memset(entry->mac_auto_request.Keysource, 0xff, 8); - memset(entry->mac_beacon_payload, 0, entry->max_beacon_payload_length); entry->mac_auto_request.SecurityLevel = 6; entry->mac_auto_request.KeyIndex = 0xff; mac_pd_sap_rf_low_level_function_set(entry, entry->dev_driver); diff --git a/source/MLE/CMakeLists.txt b/source/MLE/CMakeLists.txt new file mode 100644 index 0000000000..da8a5f3d37 --- /dev/null +++ b/source/MLE/CMakeLists.txt @@ -0,0 +1,13 @@ +# Copyright (c) 2020-2021, Pelion and affiliates. +# SPDX-License-Identifier: Apache-2.0 + +target_include_directories(mbed-nanostack-sal_stack + INTERFACE + . +) + +target_sources(mbed-nanostack-sal_stack + INTERFACE + mle.c + mle_tlv.c +) diff --git a/source/MPL/CMakeLists.txt b/source/MPL/CMakeLists.txt new file mode 100644 index 0000000000..805ae78d20 --- /dev/null +++ b/source/MPL/CMakeLists.txt @@ -0,0 +1,12 @@ +# Copyright (c) 2020-2021, Pelion and affiliates. +# SPDX-License-Identifier: Apache-2.0 + +target_include_directories(mbed-nanostack-sal_stack + INTERFACE + . +) + +target_sources(mbed-nanostack-sal_stack + INTERFACE + mpl.c +) diff --git a/source/NWK_INTERFACE/CMakeLists.txt b/source/NWK_INTERFACE/CMakeLists.txt new file mode 100644 index 0000000000..50445aeffe --- /dev/null +++ b/source/NWK_INTERFACE/CMakeLists.txt @@ -0,0 +1,16 @@ +# Copyright (c) 2020-2021, Pelion and affiliates. +# SPDX-License-Identifier: Apache-2.0 + +target_include_directories(mbed-nanostack-sal_stack + INTERFACE + . + ./Include +) + +target_sources(mbed-nanostack-sal_stack + INTERFACE + protocol_core.c + protocol_core_sleep.c + protocol_stats.c + protocol_timer.c +) diff --git a/source/NWK_INTERFACE/Include/protocol.h b/source/NWK_INTERFACE/Include/protocol.h index a3a845ffba..e2a71fee20 100644 --- a/source/NWK_INTERFACE/Include/protocol.h +++ b/source/NWK_INTERFACE/Include/protocol.h @@ -91,12 +91,10 @@ typedef enum icmp_state { ER_SCAN = 2, ER_ADDRESS_REQ = 3, ER_BIND_COMP = 4, -#ifdef HAVE_RPL ER_RPL_MC = 5, ER_RPL_SCAN = 6, ER_RPL_UNICAST = 7, ER_DAO_TX = 8, -#endif ER_PANA_AUTH = 9, ER_PANA_AUTH_DONE = 10, ER_PANA_AUTH_ERROR = 11, @@ -104,9 +102,7 @@ typedef enum icmp_state { ER_MLE_LINK_REQ = 13, ER_MLE_LINK_SHORT_SYNCH = 14, ER_MLE_LINK_ADDRESS_SYNCH = 15, -#ifdef HAVE_RPL ER_ROUTER_SYNCH = 17, -#endif ER_PANA_PING = 18, ER_PARENT_SYNCH_LOST = 19, ER_MLE_SCAN = 20, diff --git a/source/RPL/CMakeLists.txt b/source/RPL/CMakeLists.txt new file mode 100644 index 0000000000..98616d90be --- /dev/null +++ b/source/RPL/CMakeLists.txt @@ -0,0 +1,19 @@ +# Copyright (c) 2020-2021, Pelion and affiliates. +# SPDX-License-Identifier: Apache-2.0 + +target_include_directories(mbed-nanostack-sal_stack + INTERFACE + . +) + +target_sources(mbed-nanostack-sal_stack + INTERFACE + rpl_control.c + rpl_data.c + rpl_downward.c + rpl_mrhof.c + rpl_objective.c + rpl_of0.c + rpl_policy.c + rpl_upward.c +) diff --git a/source/RPL/rpl_control.c b/source/RPL/rpl_control.c index fb77ea064e..59f573a087 100644 --- a/source/RPL/rpl_control.c +++ b/source/RPL/rpl_control.c @@ -132,6 +132,19 @@ void rpl_control_event(struct rpl_domain *domain, rpl_event_t event) } } +static void rpl_control_convert_internal_config(rpl_dodag_conf_int_t *conf, const rpl_dodag_conf_t *external_conf) +{ + conf->dio_interval_min = external_conf->dio_interval_min; + conf->dio_interval_doublings = external_conf->dio_interval_doublings; + conf->dio_redundancy_constant = external_conf->dio_redundancy_constant; + conf->default_lifetime = external_conf->default_lifetime; + conf->dag_max_rank_increase = external_conf->dag_max_rank_increase; + conf->min_hop_rank_increase = external_conf->min_hop_rank_increase; + conf->objective_code_point = external_conf->objective_code_point; + conf->lifetime_unit = external_conf->lifetime_unit; + conf->options = rpl_conf_options(external_conf->authentication, external_conf->path_control_size); + conf->reserved = 0; +} /* When we join a new instance, we need to publish existing addresses. * Later addresses additions/removals are handled by rpl_control_addr_notifier. @@ -660,7 +673,9 @@ rpl_dodag_t *rpl_control_create_dodag_root(rpl_domain_t *domain, uint8_t instanc return NULL; } - rpl_dodag_update_config(dodag, conf, NULL, NULL); + rpl_dodag_conf_int_t internal_conf; + rpl_control_convert_internal_config(&internal_conf, conf); + rpl_dodag_update_config(dodag, &internal_conf, NULL, NULL); rpl_dodag_set_root(dodag, true); rpl_dodag_version_t *version = rpl_create_dodag_version(dodag, rpl_seq_init()); if (!version) { @@ -717,11 +732,12 @@ void rpl_control_update_dodag_config(struct rpl_dodag *dodag, const rpl_dodag_co { if (rpl_dodag_am_root(dodag)) { - rpl_dodag_update_config(dodag, conf, NULL, NULL); + rpl_dodag_conf_int_t internal_conf; + rpl_control_convert_internal_config(&internal_conf, conf); + rpl_dodag_update_config(dodag, &internal_conf, NULL, NULL); } } - void rpl_control_set_dodag_pref(rpl_dodag_t *dodag, uint8_t pref) { if (rpl_dodag_am_root(dodag)) { @@ -839,34 +855,33 @@ static const uint8_t *rpl_control_find_option_in_buffer(const buffer_t *buf, uin * * Figure 24: Format of the DODAG Configuration Option */ -static const uint8_t *rpl_control_read_conf(rpl_dodag_conf_t *conf_out, const uint8_t *opt) +static const uint8_t *rpl_control_read_conf(rpl_dodag_conf_int_t *conf_out, const uint8_t *opt) { - conf_out->authentication = opt[2] & 0x08; - conf_out->path_control_size = opt[2] & 0x07; + conf_out->options = opt[2]; conf_out->dio_interval_doublings = opt[3]; conf_out->dio_interval_min = opt[4]; conf_out->dio_redundancy_constant = opt[5]; conf_out->dag_max_rank_increase = common_read_16_bit(opt + 6); conf_out->min_hop_rank_increase = common_read_16_bit(opt + 8); conf_out->objective_code_point = common_read_16_bit(opt + 10); + conf_out->reserved = opt[12]; conf_out->default_lifetime = opt[13]; conf_out->lifetime_unit = common_read_16_bit(opt + 14); return opt + 16; } -static uint8_t *rpl_control_write_conf(uint8_t *opt_out, const rpl_dodag_conf_t *conf) +static uint8_t *rpl_control_write_conf(uint8_t *opt_out, const rpl_dodag_conf_int_t *conf) { opt_out[0] = RPL_DODAG_CONF_OPTION; opt_out[1] = 14; - opt_out[2] = conf->authentication ? RPL_CONF_FLAG_AUTH : 0; - opt_out[2] |= conf->path_control_size; + opt_out[2] = conf->options; opt_out[3] = conf->dio_interval_doublings; opt_out[4] = conf->dio_interval_min; opt_out[5] = conf->dio_redundancy_constant; common_write_16_bit(conf->dag_max_rank_increase, opt_out + 6); common_write_16_bit(conf->min_hop_rank_increase, opt_out + 8); common_write_16_bit(conf->objective_code_point, opt_out + 10); - opt_out[12] = 0; // reserved + opt_out[12] = conf->reserved; opt_out[13] = conf->default_lifetime; common_write_16_bit(conf->lifetime_unit, opt_out + 14); return opt_out + 16; @@ -1174,7 +1189,7 @@ malformed: /* Update DODAG config information, if option present, and either we don't have it or version is newer */ const uint8_t *dodag_conf_ptr = rpl_control_find_option_in_buffer(buf, 24, RPL_DODAG_CONF_OPTION, 14); if (dodag_conf_ptr) { - rpl_dodag_conf_t conf_buf; + rpl_dodag_conf_int_t conf_buf; rpl_control_read_conf(&conf_buf, dodag_conf_ptr); if (!rpl_dodag_update_config(dodag, &conf_buf, buf->src_sa.address, &become_leaf)) { goto invalid_parent; @@ -1182,7 +1197,7 @@ malformed: } /* If we don't have any DODAG config information, ask by unicast DIS */ - const rpl_dodag_conf_t *conf = rpl_dodag_get_config(dodag); + const rpl_dodag_conf_int_t *conf = rpl_dodag_get_config(dodag); if (!conf) { /* TODO - rate limit DIS? */ if (domain->new_parent_add && !domain->new_parent_add(buf->src_sa.address, domain->cb_handle, instance, rank)) { @@ -1361,7 +1376,7 @@ void rpl_control_transmit(rpl_domain_t *domain, protocol_interface_info_entry_t /* Transmit a DIO (unicast or multicast); cur may be NULL if multicast */ -void rpl_control_transmit_dio(rpl_domain_t *domain, protocol_interface_info_entry_t *cur, uint8_t instance_id, uint8_t dodag_version, uint16_t rank, uint8_t g_mop_prf, uint8_t dtsn, rpl_dodag_t *dodag, const uint8_t dodagid[16], const rpl_dodag_conf_t *conf, const uint8_t *dst) +void rpl_control_transmit_dio(rpl_domain_t *domain, protocol_interface_info_entry_t *cur, uint8_t instance_id, uint8_t dodag_version, uint16_t rank, uint8_t g_mop_prf, uint8_t dtsn, rpl_dodag_t *dodag, const uint8_t dodagid[16], const rpl_dodag_conf_int_t *conf, const uint8_t *dst) { uint16_t length; @@ -1931,7 +1946,7 @@ bool rpl_control_read_dodag_info(const rpl_instance_t *instance, rpl_dodag_info_ return rpl_upward_read_dodag_info(instance, dodag_info); } -const rpl_dodag_conf_t *rpl_control_get_dodag_config(const rpl_instance_t *instance) +const rpl_dodag_conf_int_t *rpl_control_get_dodag_config(const rpl_instance_t *instance) { rpl_dodag_t *dodag = rpl_instance_current_dodag(instance); if (!dodag) { diff --git a/source/RPL/rpl_control.h b/source/RPL/rpl_control.h index c1cd578828..ce8a1d1665 100644 --- a/source/RPL/rpl_control.h +++ b/source/RPL/rpl_control.h @@ -18,8 +18,6 @@ #ifndef RPL_CONTROL_H_ #define RPL_CONTROL_H_ -#ifdef HAVE_RPL - #include "ns_list.h" #include "ipv6_stack/ipv6_routing_table.h" @@ -85,6 +83,29 @@ typedef struct rpl_dodag_conf { uint16_t lifetime_unit; /* seconds */ } rpl_dodag_conf_t; +/* Internally used configuration parameters for a DODAG, obtained through DIO DODAG Configuration options + * + * This structure has all the fields that are in the configuration + * to allow forwarding new bits that are added in future specifications. + */ +typedef struct rpl_dodag_conf_int { + uint8_t options; /* Flags|A|PCS */ + uint8_t reserved; /* Reserved fields in options (byte 12)*/ + uint8_t dio_interval_min; /* log2 milliseconds */ + uint8_t dio_interval_doublings; + uint8_t dio_redundancy_constant; + uint8_t default_lifetime; /* lifetime units */ + uint16_t dag_max_rank_increase; + uint16_t min_hop_rank_increase; + uint16_t objective_code_point; + uint16_t lifetime_unit; /* seconds */ +} rpl_dodag_conf_int_t; + +/* Helpers to handle configuration option bits*/ +#define rpl_conf_options(security, path_control_size) ((security ? 1:0) << 4) | (path_control_size & 0x07) +#define rpl_conf_option_security(conf) (bool)((conf)->options & 0x08) +#define rpl_conf_option_path_control_size(conf) ((conf)->options & 0x07) + /* Descriptor for a route from a DIO Route Information option. * Used to hold the "master copy" in the DODAG structure - the table for the * current DODAG is used to populate routes in our system routing table, and to @@ -104,6 +125,8 @@ typedef struct rpl_dio_route { uint8_t prefix[]; /* Variable-length prefix */ } rpl_dio_route_t; +#ifdef HAVE_RPL + typedef NS_LIST_HEAD(rpl_dio_route_t, link) rpl_dio_route_list_t; /******************************* RPL internal API ****************************/ @@ -112,7 +135,7 @@ void *rpl_realloc(void *p, uint16_t old_size, uint16_t new_size); void rpl_free(void *p, uint16_t size); void rpl_control_transmit(struct rpl_domain *domain, struct protocol_interface_info_entry *cur, uint8_t code, struct buffer *buf, const uint8_t *dst); void rpl_control_transmit_multicast_dio(struct rpl_domain *domain, struct rpl_instance *instance, uint8_t instance_id, uint8_t dodag_version, uint16_t rank, uint8_t g_mop_prf, uint8_t dtsn, const uint8_t dodagid[16], const struct rpl_dodag_conf *conf); -void rpl_control_transmit_dio(struct rpl_domain *domain, struct protocol_interface_info_entry *cur, uint8_t instance_id, uint8_t dodag_version, uint16_t rank, uint8_t g_mop_prf, uint8_t dtsn, struct rpl_dodag *dodag, const uint8_t dodagid[16], const struct rpl_dodag_conf *conf, const uint8_t *dst); +void rpl_control_transmit_dio(struct rpl_domain *domain, struct protocol_interface_info_entry *cur, uint8_t instance_id, uint8_t dodag_version, uint16_t rank, uint8_t g_mop_prf, uint8_t dtsn, struct rpl_dodag *dodag, const uint8_t dodagid[16], const struct rpl_dodag_conf_int *conf, const uint8_t *dst); bool rpl_control_transmit_dao(struct rpl_domain *domain, struct protocol_interface_info_entry *cur, struct rpl_instance *instance, uint8_t instance_id, uint8_t dao_sequence, const uint8_t dodagid[16], const uint8_t *opts, uint16_t opts_size, const uint8_t *dst); void rpl_control_disable_ra_routes(struct rpl_domain *domain); void rpl_control_event(struct rpl_domain *domain, rpl_event_t event); @@ -207,7 +230,7 @@ struct rpl_instance *rpl_control_enumerate_instances(rpl_domain_t *domain, struc struct rpl_instance *rpl_control_lookup_instance(rpl_domain_t *domain, uint8_t instance_id, const uint8_t *dodagid); bool rpl_control_get_instance_dao_target_count(rpl_domain_t *domain, uint8_t instance_id, const uint8_t *dodagid, const uint8_t *prefix, uint16_t *target_count); bool rpl_control_read_dodag_info(const struct rpl_instance *instance, struct rpl_dodag_info_t *dodag_info); -const rpl_dodag_conf_t *rpl_control_get_dodag_config(const struct rpl_instance *instance); +const rpl_dodag_conf_int_t *rpl_control_get_dodag_config(const struct rpl_instance *instance); const uint8_t *rpl_control_preferred_parent_addr(const struct rpl_instance *instance, bool global); uint16_t rpl_control_current_rank(const struct rpl_instance *instance); uint8_t rpl_policy_mrhof_parent_set_size_get(const rpl_domain_t *domain); @@ -215,15 +238,39 @@ void rpl_control_instant_poison(struct protocol_interface_info_entry *cur, rpl_d #else /* HAVE_RPL */ +#define rpl_control_set_memory_limits(soft_limit, hard_limit) #define rpl_control_fast_timer(ticks) ((void) 0) #define rpl_control_slow_timer(seconds) ((void) 0) +#define rpl_control_transmit_dis(domain, cur, pred, instance_id, dodagid, version, dst) ((void) 0) +#define rpl_control_transmit_dio_trigger(cur, domain) ((void) 0) +#define rpl_control_parent_selection_trigger(domain) ((void) 0) +#define rpl_control_force_leaf(domain, leaf) ((void) 0) +#define rpl_control_poison(domain, poison_count) ((void) 0) +#define rpl_control_dao_timeout(domain, seconds) ((void) 0) +#define rpl_control_set_domain_on_interface(cur, domain, downstream) ((void) 0) #define rpl_control_remove_domain_from_interface(cur) ((void) 0) #define rpl_control_free_domain_instances_from_interface(cur) ((void) 0) +#define rpl_control_set_callback(domain, callback, prefix_learn_cb, new_parent_add, parent_dis, cb_handle) ((void) 0) +#define rpl_control_is_dodag_parent(interface, ll_addr) (false) +#define rpl_control_is_dodag_parent_candidate(interface, ll_addr, candidate_cmp_limiter) (false) +#define rpl_control_probe_parent_candidate(interface, ll_addr) (false) +#define rpl_control_neighbor_info_get(interface, ll_addr, global_address) (0xffff) +#define rpl_possible_better_candidate(interface, rpl_instance, ll_addr, candidate_rank, etx) (false) +#define rpl_control_parent_candidate_list_size(interface, parent_list) (0) +#define rpl_control_candidate_list_size(interface, rpl_instance) (0) +#define rpl_control_selected_parent_count(interface, rpl_instance) (0) +#define rpl_control_neighbor_delete(interface, ll_addr) ((void) 0) +#define rpl_control_find_worst_neighbor(interface, rpl_instance, ll_addr) (false) #define rpl_control_register_address(interface, addr) ((void) 0) #define rpl_control_address_register_done(interface, ll_addr, status) (false) +#define rpl_control_enumerate_instances(domain, instance) (NULL) +#define rpl_control_read_dodag_info(instance, dodag_info) (false) +#define rpl_control_get_dodag_config(instance) (NULL) +#define rpl_control_preferred_parent_addr(instance, global) (NULL) +#define rpl_control_current_rank(instance) (RPL_RANK_INFINITE) #define rpl_policy_mrhof_parent_set_size_get(domain) (0) -#define rpl_control_set_mrhof_parent_set_size(parent_set_size) #define rpl_control_instant_poison(cur, domain) ((void) 0) + #endif /* HAVE_RPL */ #endif /* RPL_CONTROL_H_ */ diff --git a/source/RPL/rpl_downward.c b/source/RPL/rpl_downward.c index 984c24953e..628b344052 100644 --- a/source/RPL/rpl_downward.c +++ b/source/RPL/rpl_downward.c @@ -134,7 +134,7 @@ void rpl_downward_convert_dodag_preferences_to_dao_path_control(rpl_dodag_t *dod } rpl_instance_t *instance = dodag->instance; - uint8_t pcs = dodag->config.path_control_size; + uint8_t pcs = rpl_conf_option_path_control_size(&dodag->config); uint_fast8_t bit = 0; rpl_neighbour_t *last = NULL; @@ -477,14 +477,14 @@ static uint8_t *rpl_downward_write_target(uint8_t *ptr, rpl_dao_target_t *target * Figure 26: Format of the Transit Information Option * */ -static uint8_t *rpl_downward_write_transit(uint8_t *ptr, rpl_dao_target_t *target, uint8_t path_control, const uint8_t *parent, bool no_path) +static uint8_t *rpl_downward_write_transit(uint8_t *ptr, rpl_dao_target_t *target, uint8_t path_control, const uint8_t *parent, uint8_t path_lifetime) { *ptr++ = RPL_TRANSIT_OPTION; *ptr++ = parent ? 16 + 4 : 4; *ptr++ = target->external ? TRANSIT_FLAG_EXTERNAL : 0; *ptr++ = path_control; *ptr++ = target->path_sequence; - *ptr++ = no_path ? 0 : target->info.non_root.path_lifetime; + *ptr++ = path_lifetime; if (parent) { ptr = (uint8_t *) memcpy(ptr, parent, 16) + 16; } @@ -770,7 +770,11 @@ void rpl_instance_send_dao_update(rpl_instance_t *instance) * (^ Repeat if more targets with different transit info/parents) */ - + const rpl_dodag_conf_int_t *conf = rpl_dodag_get_config(dodag); + if (!conf) { + rpl_instance_dao_trigger(instance, 0); + return; + } uint8_t *opts = ns_dyn_mem_temporary_alloc(1280); if (!opts) { rpl_instance_dao_trigger(instance, 0); @@ -778,13 +782,13 @@ void rpl_instance_send_dao_update(rpl_instance_t *instance) } uint8_t *ptr = opts; - rpl_downward_reset_assigning(instance, PCSMASK(dodag->config.path_control_size)); + rpl_downward_reset_assigning(instance, PCSMASK(rpl_conf_option_path_control_size(&dodag->config))); ns_list_foreach(rpl_dao_target_t, t, &instance->dao_targets) { /* Self-published targets can defer path lifetime choice */ if (t->info.non_root.path_lifetime == 0) { uint32_t lifetime = t->lifetime; - const rpl_dodag_conf_t *conf = rpl_dodag_get_config(dodag); + uint16_t unit = conf->lifetime_unit; uint8_t def = conf->default_lifetime; if (lifetime != 0xFFFFFFFF) { @@ -835,20 +839,31 @@ void rpl_instance_send_dao_update(rpl_instance_t *instance) ptr = rpl_downward_write_target(ptr, t2); } + + uint8_t path_lifetime; + uint8_t path_life_adjust_t_default = conf->default_lifetime - (conf->default_lifetime / 8); + if (target->info.non_root.path_lifetime < path_life_adjust_t_default || target->info.non_root.path_lifetime >= conf->default_lifetime) { + path_lifetime = target->info.non_root.path_lifetime; + } else { + //Adjust from 7/8-0.99 to 1*default + //to pass conformance tests that expect to see exactly the default lifetime in a smoothly-running system + path_lifetime = conf->default_lifetime; + } + /* Then output the transit information for the original target */ if (storing) { /* Just one transit info */ - ptr = rpl_downward_write_transit(ptr, target, path_control, NULL, false); + ptr = rpl_downward_write_transit(ptr, target, path_control, NULL, path_lifetime); } else if (target->own) { /* One transit info for each DAO parent */ ns_list_foreach(rpl_neighbour_t, neighbour, &instance->candidate_neighbours) { if (neighbour->dao_path_control & path_control) { - ptr = rpl_downward_write_transit(ptr, target, neighbour->dao_path_control & path_control, neighbour->global_address, false); + ptr = rpl_downward_write_transit(ptr, target, neighbour->dao_path_control & path_control, neighbour->global_address, path_lifetime); } } } else { /* Attached host - single transit is us */ - ptr = rpl_downward_write_transit(ptr, target, path_control, our_addr, false); + ptr = rpl_downward_write_transit(ptr, target, path_control, our_addr, path_lifetime); } } @@ -1601,7 +1616,7 @@ void rpl_instance_dao_acked(rpl_instance_t *instance, const uint8_t src[16], int } rpl_dodag_t *dodag = rpl_instance_current_dodag(instance); - const rpl_dodag_conf_t *conf = dodag ? rpl_dodag_get_config(dodag) : NULL; + const rpl_dodag_conf_int_t *conf = dodag ? rpl_dodag_get_config(dodag) : NULL; instance->dao_in_transit = false; instance->dao_retry_timer = 0; if (!retry) { @@ -1917,11 +1932,11 @@ static void rpl_instance_address_registration_cancel(rpl_instance_t *instance) instance->pending_neighbour_confirmation = false; } -static void rpl_instance_address_registration_retry(rpl_dao_target_t *dao_target) +static void rpl_instance_address_registration_retry(rpl_dao_target_t *dao_target, uint8_t response_wait_time) { dao_target->active_confirmation_state = true; // Active timer is set true so the response_wait_time runs out dao_target->trig_confirmation_state = true; - dao_target->response_wait_time = 20; // Wait 20 seconds before retry + dao_target->response_wait_time = response_wait_time; // Wait 20 seconds before retry } void rpl_instance_parent_address_reg_timer_update(rpl_instance_t *instance, uint16_t seconds) @@ -2003,28 +2018,36 @@ bool rpl_instance_address_registration_done(protocol_interface_info_entry_t *int tr_debug("Address %s register to %s", trace_ipv6(dao_target->prefix), trace_ipv6(neighbour->ll_address)); - if (status != SOCKET_TX_DONE) { - if (neighbour->addr_reg_failures > 0) { - // Neighbor should be blacklisted after this. - tr_error("Address registration failed delete neighbor"); - rpl_instance_address_registration_cancel(instance); - rpl_delete_neighbour(instance, neighbour); - return true; + if (status == SOCKET_TX_DONE) { + /* State_timer is 1/10 s. Set renewal to 75-85% of lifetime */ + if_address_entry_t *address = rpl_interface_addr_get(interface, dao_target->prefix); + if (address && address->source != ADDR_SOURCE_DHCP) { + address->state_timer = (address->preferred_lifetime * randLIB_get_random_in_range(75, 85) / 10); } - tr_warn("Address registration ACK fail retry selection"); - neighbour->addr_reg_failures++; - rpl_instance_address_registration_retry(dao_target); + neighbour->addr_reg_failures = 0; + neighbour->confirmed = true; + dao_target->response_wait_time = 6; return false; } - /* State_timer is 1/10 s. Set renewal to 75-85% of lifetime */ - if_address_entry_t *address = rpl_interface_addr_get(interface, dao_target->prefix); - if (address && address->source != ADDR_SOURCE_DHCP) { - address->state_timer = (address->preferred_lifetime * randLIB_get_random_in_range(75, 85) / 10); + + if (status == SOCKET_BUSY) { + tr_warn("Address registration CCA fail retry selection"); + rpl_instance_address_registration_retry(dao_target, 4); + return false; } - neighbour->addr_reg_failures = 0; - neighbour->confirmed = true; - dao_target->response_wait_time = 6; + + if (neighbour->addr_reg_failures > 0) { + // Neighbor should be blacklisted after this. + tr_error("Address registration failed delete neighbor"); + rpl_instance_address_registration_cancel(instance); + rpl_delete_neighbour(instance, neighbour); + return true; + } + tr_warn("Address registration ACK fail retry selection"); + neighbour->addr_reg_failures++; + rpl_instance_address_registration_retry(dao_target, 20); return false; + } #endif /* HAVE_RPL */ diff --git a/source/RPL/rpl_policy.c b/source/RPL/rpl_policy.c index 5f669c591c..c0ee117117 100644 --- a/source/RPL/rpl_policy.c +++ b/source/RPL/rpl_policy.c @@ -87,7 +87,7 @@ bool rpl_policy_join_dodag(rpl_domain_t *domain, uint8_t g_mop_prf, uint8_t inst return true; } -bool rpl_policy_join_config(rpl_domain_t *domain, const rpl_dodag_conf_t *conf, bool *leaf_only) +bool rpl_policy_join_config(rpl_domain_t *domain, const rpl_dodag_conf_int_t *conf, bool *leaf_only) { (void)domain; (void)conf; @@ -99,7 +99,7 @@ bool rpl_policy_join_config(rpl_domain_t *domain, const rpl_dodag_conf_t *conf, } /* We don't support authentication */ - if (conf->authentication) { + if (rpl_conf_option_security(conf)) { return false; } diff --git a/source/RPL/rpl_policy.h b/source/RPL/rpl_policy.h index b80e0e9f2a..4b59432595 100644 --- a/source/RPL/rpl_policy.h +++ b/source/RPL/rpl_policy.h @@ -26,7 +26,7 @@ void rpl_policy_force_tunnel_set(bool enable); bool rpl_policy_join_instance(rpl_domain_t *domain, uint8_t instance_id, const uint8_t *dodagid); bool rpl_policy_join_dodag(rpl_domain_t *domain, uint8_t g_mop_prf, uint8_t instance_id, const uint8_t *dodagid); -bool rpl_policy_join_config(rpl_domain_t *domain, const rpl_dodag_conf_t *conf, bool *leaf_only); +bool rpl_policy_join_config(rpl_domain_t *domain, const rpl_dodag_conf_int_t *conf, bool *leaf_only); bool rpl_policy_request_dao_acks(const rpl_domain_t *domain, uint8_t mop); uint16_t rpl_policy_initial_dao_ack_wait(const rpl_domain_t *domain, uint8_t mop); diff --git a/source/RPL/rpl_structures.h b/source/RPL/rpl_structures.h index 0adeaacbf9..d43dea4a20 100644 --- a/source/RPL/rpl_structures.h +++ b/source/RPL/rpl_structures.h @@ -81,7 +81,7 @@ struct rpl_dodag { uint32_t timestamp; /* How long since we heard a DIO */ uint8_t id[16]; /* Root identifier */ uint8_t g_mop_prf; /* Grounded, Mode, Preference */ - rpl_dodag_conf_t config; /* Configuration from DIO */ + rpl_dodag_conf_int_t config; /* Configuration from DIO */ uint8_t info_version; /* Version for g_mop_prf and config */ bool root: 1; /* We are the root of this DODAG */ bool was_root: 1; /* If we have ever been a root in this DODAG */ diff --git a/source/RPL/rpl_upward.c b/source/RPL/rpl_upward.c index 283dff2b9c..c4347fc76d 100644 --- a/source/RPL/rpl_upward.c +++ b/source/RPL/rpl_upward.c @@ -729,7 +729,7 @@ void rpl_delete_dodag_root(rpl_dodag_t *dodag) /* Convert RPL configuration to generic trickle parameters. Returns true if * the value in the generic object has changed. */ -static bool rpl_dodag_conf_convert_trickle_parameters(trickle_params_t *params_out, const rpl_dodag_conf_t *conf) +static bool rpl_dodag_conf_convert_trickle_parameters(trickle_params_t *params_out, const rpl_dodag_conf_int_t *conf) { /* Convert trickle parameters into 100ms ticks */ uint32_t Imin_ms = conf->dio_interval_min < 32 ? (1ul << conf->dio_interval_min) : 0xfffffffful; @@ -756,7 +756,7 @@ uint8_t rpl_dodag_mop(const rpl_dodag_t *dodag) return dodag->g_mop_prf & RPL_MODE_MASK; } -bool rpl_dodag_update_config(rpl_dodag_t *dodag, const rpl_dodag_conf_t *conf, const uint8_t *src, bool *become_leaf) +bool rpl_dodag_update_config(rpl_dodag_t *dodag, const rpl_dodag_conf_int_t *conf, const uint8_t *src, bool *become_leaf) { /* If already have config, don't update unless it's coming from preferred parent */ if (dodag->have_config) { @@ -863,7 +863,7 @@ bool rpl_dodag_is_current(const rpl_dodag_t *dodag) return dodag->instance->current_dodag_version && dodag->instance->current_dodag_version->dodag == dodag; } -const rpl_dodag_conf_t *rpl_dodag_get_config(const rpl_dodag_t *dodag) +const rpl_dodag_conf_int_t *rpl_dodag_get_config(const rpl_dodag_t *dodag) { return dodag->have_config ? &dodag->config : NULL; } @@ -1677,7 +1677,7 @@ void rpl_instance_dio_trigger(rpl_instance_t *instance, protocol_interface_info_ } // Always send config in unicasts (as required), never in multicasts (optional) - rpl_dodag_conf_t *conf; + rpl_dodag_conf_int_t *conf; if (addr) { conf = &dodag->config; //Unicast diff --git a/source/RPL/rpl_upward.h b/source/RPL/rpl_upward.h index 3a3cb183c2..b15e65f438 100644 --- a/source/RPL/rpl_upward.h +++ b/source/RPL/rpl_upward.h @@ -108,7 +108,7 @@ uint8_t rpl_dodag_get_version_number_as_root(const rpl_dodag_t *dodag); void rpl_dodag_set_version_number_as_root(rpl_dodag_t *dodag, uint8_t number); void rpl_dodag_set_leaf(rpl_dodag_t *dodag, bool leaf); bool rpl_dodag_am_leaf(const rpl_dodag_t *dodag); -const rpl_dodag_conf_t *rpl_dodag_get_config(const rpl_dodag_t *dodag); +const rpl_dodag_conf_int_t *rpl_dodag_get_config(const rpl_dodag_t *dodag); void rpl_dodag_inconsistency(rpl_dodag_t *dodag); void rpl_dodag_increment_dtsn(rpl_dodag_t *dodag); rpl_cmp_t rpl_dodag_pref_compare(const rpl_dodag_t *a, const rpl_dodag_t *b); @@ -138,7 +138,7 @@ rpl_neighbour_t *rpl_lookup_neighbour_by_ll_address(const rpl_instance_t *instan rpl_neighbour_t *rpl_lookup_last_candidate_from_list(const rpl_instance_t *instance); rpl_neighbour_t *rpl_create_neighbour(rpl_dodag_version_t *instance, const uint8_t *ll_addr, int8_t if_id, uint8_t g_mop_prf, uint8_t dtsn); void rpl_delete_neighbour(rpl_instance_t *instance, rpl_neighbour_t *neighbour); -bool rpl_dodag_update_config(rpl_dodag_t *dodag, const rpl_dodag_conf_t *conf, const uint8_t *src, bool *become_leaf); +bool rpl_dodag_update_config(rpl_dodag_t *dodag, const rpl_dodag_conf_int_t *conf, const uint8_t *src, bool *become_leaf); const uint8_t *rpl_neighbour_ll_address(const rpl_neighbour_t *neighbour); const uint8_t *rpl_neighbour_global_address(const rpl_neighbour_t *neighbour); void rpl_neighbour_update_global_address(rpl_neighbour_t *neighbour, const uint8_t *addr); diff --git a/source/Security/CMakeLists.txt b/source/Security/CMakeLists.txt new file mode 100644 index 0000000000..63aaf0653a --- /dev/null +++ b/source/Security/CMakeLists.txt @@ -0,0 +1,69 @@ +# Copyright (c) 2020-2021, Pelion and affiliates. +# SPDX-License-Identifier: Apache-2.0 + +target_include_directories(mbed-nanostack-sal_stack + INTERFACE + . + ./Common + ./PANA + ./TLS + ./eapol + ./kmp + ./protocols + ./protocols/eap_tls_sec_prot + ./protocols/fwh_sec_prot + ./protocols/gkh_sec_prot + ./protocols/key_sec_prot + ./protocols/radius_sec_prot + ./protocols/tls_sec_prot +) + +target_sources(mbed-nanostack-sal_stack + INTERFACE + Common/security_lib.c + + PANA/eap_protocol.c + PANA/pana.c + PANA/pana_avp.c + PANA/pana_client.c + PANA/pana_eap_header.c + PANA/pana_header.c + PANA/pana_relay_table.c + PANA/pana_server.c + + TLS/tls_ccm_crypt.c + TLS/tls_lib.c + + eapol/eapol_helper.c + eapol/kde_helper.c + + kmp/kmp_addr.c + kmp/kmp_api.c + kmp/kmp_eapol_pdu_if.c + kmp/kmp_socket_if.c + + protocols/sec_prot_certs.c + protocols/sec_prot_keys.c + protocols/sec_prot_lib.c + + protocols/eap_tls_sec_prot/auth_eap_tls_sec_prot.c + protocols/eap_tls_sec_prot/eap_tls_sec_prot_lib.c + protocols/eap_tls_sec_prot/radius_eap_tls_sec_prot.c + protocols/eap_tls_sec_prot/supp_eap_tls_sec_prot.c + + protocols/fwh_sec_prot/auth_fwh_sec_prot.c + protocols/fwh_sec_prot/supp_fwh_sec_prot.c + + protocols/gkh_sec_prot/auth_gkh_sec_prot.c + protocols/gkh_sec_prot/supp_gkh_sec_prot.c + + protocols/key_sec_prot/key_sec_prot.c + + protocols/msg_sec_prot/msg_sec_prot.c + + protocols/radius_sec_prot/avp_helper.c + protocols/radius_sec_prot/radius_client_sec_prot.c + + protocols/tls_sec_prot/tls_sec_prot.c + protocols/tls_sec_prot/tls_sec_prot_lib.c +) diff --git a/source/Security/protocols/eap_tls_sec_prot/auth_eap_tls_sec_prot.c b/source/Security/protocols/eap_tls_sec_prot/auth_eap_tls_sec_prot.c index 4f1d3a725b..d4a7c476e8 100644 --- a/source/Security/protocols/eap_tls_sec_prot/auth_eap_tls_sec_prot.c +++ b/source/Security/protocols/eap_tls_sec_prot/auth_eap_tls_sec_prot.c @@ -411,7 +411,7 @@ static void auth_eap_tls_sec_prot_state_machine(sec_prot_t *prot) tr_info("EAP-TLS start, eui-64: %s", trace_array(sec_prot_remote_eui_64_addr_get(prot), 8)); // Set default timeout for the total maximum length of the negotiation - sec_prot_default_timeout_set(&data->common); + sec_prot_timeout_set(&data->common, SEC_PROT_RETRYING_PROTOCOL_TIMEOUT); // KMP-CREATE.confirm prot->create_conf(prot, SEC_RESULT_OK); diff --git a/source/Security/protocols/eap_tls_sec_prot/radius_eap_tls_sec_prot.c b/source/Security/protocols/eap_tls_sec_prot/radius_eap_tls_sec_prot.c index 09944249d9..1591df9cac 100644 --- a/source/Security/protocols/eap_tls_sec_prot/radius_eap_tls_sec_prot.c +++ b/source/Security/protocols/eap_tls_sec_prot/radius_eap_tls_sec_prot.c @@ -436,7 +436,7 @@ static void radius_eap_tls_sec_prot_state_machine(sec_prot_t *prot) tr_info("EAP-TLS: start, eui-64: %s", trace_array(sec_prot_remote_eui_64_addr_get(prot), 8)); // Set default timeout for the total maximum length of the negotiation - sec_prot_default_timeout_set(&data->common); + sec_prot_timeout_set(&data->common, SEC_PROT_RETRYING_PROTOCOL_TIMEOUT); // KMP-CREATE.confirm prot->create_conf(prot, SEC_RESULT_OK); @@ -482,7 +482,7 @@ static void radius_eap_tls_sec_prot_state_machine(sec_prot_t *prot) sec_prot_timer_trickle_stop(&data->common); // Set timeout to wait for RADIUS client to continue - data->common.ticks = RADIUS_EAP_TLS_CLIENT_TIMEOUT; + sec_prot_timeout_set(&data->common, RADIUS_EAP_TLS_CLIENT_TIMEOUT); // Send to radius client data->radius_client_send(data->radius_client_prot, (void *) &data->recv_eapol_pdu, length); @@ -547,7 +547,7 @@ static void radius_eap_tls_sec_prot_state_machine(sec_prot_t *prot) sec_prot_timer_trickle_stop(&data->common); // Set timeout to wait for RADIUS client to continue - data->common.ticks = RADIUS_EAP_TLS_CLIENT_TIMEOUT; + sec_prot_timeout_set(&data->common, RADIUS_EAP_TLS_CLIENT_TIMEOUT); // Send to radius client data->radius_client_send(data->radius_client_prot, (void *) &data->recv_eapol_pdu, length); diff --git a/source/Security/protocols/eap_tls_sec_prot/supp_eap_tls_sec_prot.c b/source/Security/protocols/eap_tls_sec_prot/supp_eap_tls_sec_prot.c index aa296c39d1..a80a3ea258 100644 --- a/source/Security/protocols/eap_tls_sec_prot/supp_eap_tls_sec_prot.c +++ b/source/Security/protocols/eap_tls_sec_prot/supp_eap_tls_sec_prot.c @@ -406,7 +406,7 @@ static void supp_eap_tls_sec_prot_state_machine(sec_prot_t *prot) } // Set retry timeout based on network size - data->common.ticks = prot->sec_cfg->prot_cfg.sec_prot_retry_timeout; + sec_prot_timeout_set(&data->common, prot->sec_cfg->prot_cfg.sec_prot_retry_timeout); // Store sequence ID supp_eap_tls_sec_prot_seq_id_update(prot); @@ -451,7 +451,7 @@ static void supp_eap_tls_sec_prot_state_machine(sec_prot_t *prot) supp_eap_tls_sec_prot_seq_id_update(prot); sec_prot_state_set(prot, &data->common, EAP_TLS_STATE_REQUEST); - data->common.ticks = prot->sec_cfg->prot_cfg.sec_prot_retry_timeout; + sec_prot_timeout_set(&data->common, prot->sec_cfg->prot_cfg.sec_prot_retry_timeout); // Initialize TLS protocol if (supp_eap_tls_sec_prot_init_tls(prot) < 0) { @@ -485,7 +485,7 @@ static void supp_eap_tls_sec_prot_state_machine(sec_prot_t *prot) // Store sequence ID if (supp_eap_tls_sec_prot_seq_id_update(prot)) { // When receiving a new sequence number, adds more time for re-send if no response - data->common.ticks = prot->sec_cfg->prot_cfg.sec_prot_retry_timeout; + sec_prot_timeout_set(&data->common, prot->sec_cfg->prot_cfg.sec_prot_retry_timeout); } // All fragments received for a message diff --git a/source/Security/protocols/fwh_sec_prot/auth_fwh_sec_prot.c b/source/Security/protocols/fwh_sec_prot/auth_fwh_sec_prot.c index 8138fe8ed4..cae5869127 100644 --- a/source/Security/protocols/fwh_sec_prot/auth_fwh_sec_prot.c +++ b/source/Security/protocols/fwh_sec_prot/auth_fwh_sec_prot.c @@ -120,7 +120,7 @@ static int8_t auth_fwh_sec_prot_init(sec_prot_t *prot) sec_prot_init(&data->common); sec_prot_state_set(prot, &data->common, FWH_STATE_INIT); - data->common.ticks = 15 * 10; // 15 seconds + sec_prot_timeout_set(&data->common, 15 * 10); // 15 seconds uint8_t eui64[8] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}; sec_prot_lib_nonce_init(data->nonce, eui64, 1000); @@ -348,7 +348,7 @@ static void auth_fwh_sec_prot_state_machine(sec_prot_t *prot) tr_info("4WH: start, eui-64: %s", trace_array(sec_prot_remote_eui_64_addr_get(prot), 8)); // Set default timeout for the total maximum length of the negotiation - sec_prot_default_timeout_set(&data->common); + sec_prot_timeout_set(&data->common, SEC_PROT_RETRYING_PROTOCOL_TIMEOUT); uint8_t *pmk = sec_prot_keys_pmk_get(prot->sec_keys); if (!pmk) { // If PMK is not set fails diff --git a/source/Security/protocols/fwh_sec_prot/supp_fwh_sec_prot.c b/source/Security/protocols/fwh_sec_prot/supp_fwh_sec_prot.c index 84e91e61ca..1f98e8c92f 100644 --- a/source/Security/protocols/fwh_sec_prot/supp_fwh_sec_prot.c +++ b/source/Security/protocols/fwh_sec_prot/supp_fwh_sec_prot.c @@ -139,7 +139,7 @@ static int8_t supp_fwh_sec_prot_init(sec_prot_t *prot) sec_prot_init(&data->common); sec_prot_state_set(prot, &data->common, FWH_STATE_INIT); - data->common.ticks = prot->sec_cfg->prot_cfg.sec_prot_retry_timeout; + sec_prot_timeout_set(&data->common, prot->sec_cfg->prot_cfg.sec_prot_retry_timeout); data->msg3_received = false; data->msg3_retry_wait = false; data->recv_replay_cnt = 0; @@ -314,7 +314,7 @@ static void supp_fwh_sec_prot_state_machine(sec_prot_t *prot) } // Set default timeout for the total maximum length of the negotiation - sec_prot_default_timeout_set(&data->common); + sec_prot_timeout_set(&data->common, prot->sec_cfg->prot_cfg.sec_prot_retry_timeout); tr_info("4WH: start"); @@ -337,7 +337,7 @@ static void supp_fwh_sec_prot_state_machine(sec_prot_t *prot) if (sec_prot_result_ok_check(&data->common)) { // Send 4WH message 2 supp_fwh_sec_prot_message_send(prot, FWH_MESSAGE_2); - data->common.ticks = prot->sec_cfg->prot_cfg.sec_prot_retry_timeout; + sec_prot_timeout_set(&data->common, prot->sec_cfg->prot_cfg.sec_prot_retry_timeout); sec_prot_state_set(prot, &data->common, FWH_STATE_MESSAGE_3); } else { // Ready to be deleted @@ -365,7 +365,7 @@ static void supp_fwh_sec_prot_state_machine(sec_prot_t *prot) // Send 4WH message 2 supp_fwh_sec_prot_message_send(prot, FWH_MESSAGE_2); - data->common.ticks = prot->sec_cfg->prot_cfg.sec_prot_retry_timeout; + sec_prot_timeout_set(&data->common, prot->sec_cfg->prot_cfg.sec_prot_retry_timeout); return; } else if (data->recv_msg != FWH_MESSAGE_3) { return; @@ -392,7 +392,7 @@ static void supp_fwh_sec_prot_state_machine(sec_prot_t *prot) // Sends 4WH Message 4 supp_fwh_sec_prot_message_send(prot, FWH_MESSAGE_4); - data->common.ticks = prot->sec_cfg->prot_cfg.sec_prot_retry_timeout; + sec_prot_timeout_set(&data->common, prot->sec_cfg->prot_cfg.sec_prot_retry_timeout); sec_prot_state_set(prot, &data->common, FWH_STATE_FINISH); break; @@ -412,7 +412,7 @@ static void supp_fwh_sec_prot_state_machine(sec_prot_t *prot) sec_prot_keys_ptk_write(prot->sec_keys, data->new_ptk, prot->sec_cfg->timer_cfg.ptk_lifetime); sec_prot_keys_ptk_eui_64_write(prot->sec_keys, data->remote_eui64); - data->common.ticks = 60 * 10; // 60 seconds + sec_prot_timeout_set(&data->common, 60 * 10); // 60 seconds // KMP-FINISHED.indication prot->finished_ind(prot, sec_prot_result_get(&data->common), prot->sec_keys); sec_prot_state_set(prot, &data->common, FWH_STATE_MESSAGE_3_RETRY_WAIT); diff --git a/source/Security/protocols/gkh_sec_prot/auth_gkh_sec_prot.c b/source/Security/protocols/gkh_sec_prot/auth_gkh_sec_prot.c index b01d60c824..416a0797b1 100644 --- a/source/Security/protocols/gkh_sec_prot/auth_gkh_sec_prot.c +++ b/source/Security/protocols/gkh_sec_prot/auth_gkh_sec_prot.c @@ -295,7 +295,7 @@ static void auth_gkh_sec_prot_state_machine(sec_prot_t *prot) tr_info("GKH start, eui-64: %s", trace_array(sec_prot_remote_eui_64_addr_get(prot), 8)); // Set default timeout for the total maximum length of the negotiation - sec_prot_default_timeout_set(&data->common); + sec_prot_timeout_set(&data->common, SEC_PROT_RETRYING_PROTOCOL_TIMEOUT); // KMP-CREATE.confirm prot->create_conf(prot, SEC_RESULT_OK); diff --git a/source/Security/protocols/gkh_sec_prot/supp_gkh_sec_prot.c b/source/Security/protocols/gkh_sec_prot/supp_gkh_sec_prot.c index a836e5870b..cffe5f704e 100644 --- a/source/Security/protocols/gkh_sec_prot/supp_gkh_sec_prot.c +++ b/source/Security/protocols/gkh_sec_prot/supp_gkh_sec_prot.c @@ -247,7 +247,7 @@ static void supp_gkh_sec_prot_state_machine(sec_prot_t *prot) } // Set default timeout for the total maximum length of the negotiation - sec_prot_default_timeout_set(&data->common); + sec_prot_timeout_set(&data->common, prot->sec_cfg->prot_cfg.sec_prot_retry_timeout); supp_gkh_sec_prot_security_replay_counter_update(prot); diff --git a/source/Security/protocols/key_sec_prot/key_sec_prot.c b/source/Security/protocols/key_sec_prot/key_sec_prot.c index 540ed35c71..817f3c43e9 100644 --- a/source/Security/protocols/key_sec_prot/key_sec_prot.c +++ b/source/Security/protocols/key_sec_prot/key_sec_prot.c @@ -370,7 +370,7 @@ static void supp_key_sec_prot_state_machine(sec_prot_t *prot) // KMP-FINISHED.indication, prot->finished_ind(prot, sec_prot_result_get(&data->common), 0); sec_prot_state_set(prot, &data->common, KEY_STATE_FINISHED); - data->common.ticks = KEY_SEC_FINISHED_TIMEOUT; + sec_prot_timeout_set(&data->common, KEY_SEC_FINISHED_TIMEOUT); break; case KEY_STATE_FINISHED: @@ -416,7 +416,7 @@ static void auth_key_sec_prot_state_machine(sec_prot_t *prot) // KMP-FINISHED.indication, prot->finished_ind(prot, sec_prot_result_get(&data->common), 0); sec_prot_state_set(prot, &data->common, KEY_STATE_FINISHED); - data->common.ticks = KEY_SEC_FINISHED_TIMEOUT; + sec_prot_timeout_set(&data->common, KEY_SEC_FINISHED_TIMEOUT); break; case KEY_STATE_FINISHED: { diff --git a/source/Security/protocols/radius_sec_prot/radius_client_sec_prot.c b/source/Security/protocols/radius_sec_prot/radius_client_sec_prot.c index 8f3371f621..c646b24cd2 100644 --- a/source/Security/protocols/radius_sec_prot/radius_client_sec_prot.c +++ b/source/Security/protocols/radius_sec_prot/radius_client_sec_prot.c @@ -1089,7 +1089,7 @@ static void radius_client_sec_prot_state_machine(sec_prot_t *prot) tr_info("Radius: start, eui-64: %s", trace_array(sec_prot_remote_eui_64_addr_get(prot), 8)); // Set default timeout for the total maximum length of the negotiation - sec_prot_default_timeout_set(&data->common); + sec_prot_timeout_set(&data->common, SEC_PROT_RETRYING_PROTOCOL_TIMEOUT); sec_prot_state_set(prot, &data->common, RADIUS_STATE_CREATE_RESP); @@ -1148,7 +1148,7 @@ static void radius_client_sec_prot_state_machine(sec_prot_t *prot) sec_prot_timer_trickle_stop(&data->common); // Set timeout to wait for EAP-TLS to continue - data->common.ticks = prot->sec_cfg->prot_cfg.sec_prot_retry_timeout; + sec_prot_timeout_set(&data->common, prot->sec_cfg->prot_cfg.sec_prot_retry_timeout); // Send to radius EAP-TLS if (data->radius_eap_tls_send && data->radius_eap_tls_prot && data->recv_eap_msg && data->recv_eap_msg_len > 0) { diff --git a/source/Security/protocols/sec_prot_lib.c b/source/Security/protocols/sec_prot_lib.c index 88577b3157..09495a817c 100644 --- a/source/Security/protocols/sec_prot_lib.c +++ b/source/Security/protocols/sec_prot_lib.c @@ -174,9 +174,9 @@ bool sec_prot_result_ok_check(sec_prot_common_t *data) return false; } -void sec_prot_default_timeout_set(sec_prot_common_t *data) +void sec_prot_timeout_set(sec_prot_common_t *data, uint16_t ticks) { - data->ticks = SEC_TOTAL_TIMEOUT; + data->ticks = ticks; } void sec_prot_lib_nonce_generate(uint8_t *nonce) diff --git a/source/Security/protocols/sec_prot_lib.h b/source/Security/protocols/sec_prot_lib.h index 83a01879c2..cc04b141a7 100644 --- a/source/Security/protocols/sec_prot_lib.h +++ b/source/Security/protocols/sec_prot_lib.h @@ -26,7 +26,6 @@ */ #define EUI64_LEN 8 -#define SEC_TOTAL_TIMEOUT 30 * 60 * 10 // 30 minutes #define SEC_FINISHED_TIMEOUT 5 * 10 // 5 seconds #define FWH_NONCE_LENGTH 32 @@ -299,11 +298,12 @@ bool sec_prot_result_timeout_check(sec_prot_common_t *data); bool sec_prot_result_ok_check(sec_prot_common_t *data); /** - * sec_prot_default_timeout_set sets default timeout for protocol + * sec_prot_timeout_set sets timeout for protocol * * \param data common data + * \param ticks ticks * */ -void sec_prot_default_timeout_set(sec_prot_common_t *data); +void sec_prot_timeout_set(sec_prot_common_t *data, uint16_t ticks); #endif /* SEC_PROT_LIB_H_ */ diff --git a/source/Security/protocols/tls_sec_prot/tls_sec_prot.c b/source/Security/protocols/tls_sec_prot/tls_sec_prot.c index e194301e4d..a7cb9b163f 100644 --- a/source/Security/protocols/tls_sec_prot/tls_sec_prot.c +++ b/source/Security/protocols/tls_sec_prot/tls_sec_prot.c @@ -320,7 +320,7 @@ static void client_tls_sec_prot_state_machine(sec_prot_t *prot) sec_prot_state_set(prot, &data->common, TLS_STATE_CREATE_REQ); prot->timer_start(prot); // Set default timeout for the total maximum length of the negotiation - sec_prot_default_timeout_set(&data->common); + sec_prot_timeout_set(&data->common, prot->sec_cfg->prot_cfg.sec_prot_retry_timeout); break; // Wait KMP-CREATE.request @@ -355,6 +355,8 @@ static void client_tls_sec_prot_state_machine(sec_prot_t *prot) data->calculating = false; } + sec_prot_timeout_set(&data->common, prot->sec_cfg->prot_cfg.sec_prot_retry_timeout); + if (data->tls_send.data) { prot->send(prot, data->tls_send.data, data->tls_send.handled_len); eap_tls_sec_prot_lib_message_init(&data->tls_send); @@ -415,7 +417,7 @@ static void server_tls_sec_prot_state_machine(sec_prot_t *prot) sec_prot_state_set(prot, &data->common, TLS_STATE_CLIENT_HELLO); prot->timer_start(prot); // Set default timeout for the total maximum length of the negotiation - sec_prot_default_timeout_set(&data->common); + sec_prot_timeout_set(&data->common, prot->sec_cfg->prot_cfg.sec_prot_retry_timeout); break; // Wait EAP request, Identity (starts handshake on supplicant) @@ -474,6 +476,8 @@ static void server_tls_sec_prot_state_machine(sec_prot_t *prot) data->calculating = false; } + sec_prot_timeout_set(&data->common, prot->sec_cfg->prot_cfg.sec_prot_retry_timeout); + if (data->tls_send.data) { prot->send(prot, data->tls_send.data, data->tls_send.handled_len); eap_tls_sec_prot_lib_message_init(&data->tls_send); diff --git a/source/Service_Libs/CMakeLists.txt b/source/Service_Libs/CMakeLists.txt new file mode 100644 index 0000000000..846fc8cb05 --- /dev/null +++ b/source/Service_Libs/CMakeLists.txt @@ -0,0 +1,107 @@ +# Copyright (c) 2020-2021, Pelion and affiliates. +# SPDX-License-Identifier: Apache-2.0 + +target_include_directories(mbed-nanostack-sal_stack + INTERFACE + . + ./Neighbor_cache + ./Trickle + ./blacklist + ./etx + ./fhss + ./fnv_hash + ./hmac + ./ieee_802_11 + ./load_balance + ./mac_neighbor_table + ./mdns + ./mdns/fnet + ./mdns/fnet/fnet_stack + ./mdns/fnet/fnet_stack/port + ./mdns/fnet/fnet_stack/port/compiler + ./mdns/fnet/fnet_stack/port/cpu + ./mdns/fnet/fnet_stack/services + ./mdns/fnet/fnet_stack/services/dns + ./mdns/fnet/fnet_stack/services/mdns + ./mdns/fnet/fnet_stack/services/poll + ./mdns/fnet/fnet_stack/services/serial + ./mdns/fnet/fnet_stack/stack + ./mle_service + ./nd_proxy + ./nist_aes_kw + ./pan_blacklist + ./random_early_detection + ./utils + ./whiteboard +) + +target_sources(mbed-nanostack-sal_stack + INTERFACE + CCM_lib/ccm_security.c + + CCM_lib/mbedOS/aes_mbedtls_adapter.c + + Neighbor_cache/neighbor_cache.c + + SHA256_Lib/ns_sha256.c + SHA256_Lib/shalib.c + + Trickle/trickle.c + + blacklist/blacklist.c + + etx/etx.c + + fhss/channel_functions.c + fhss/channel_list.c + fhss/fhss.c + fhss/fhss_channel.c + fhss/fhss_common.c + fhss/fhss_configuration_interface.c + fhss/fhss_statistics.c + fhss/fhss_test_api.c + fhss/fhss_ws.c + fhss/fhss_ws_empty_functions.c + + fnv_hash/fnv_hash.c + + hmac/hmac_md.c + + ieee_802_11/ieee_802_11.c + + load_balance/load_balance.c + + mac_neighbor_table/mac_neighbor_table.c + + mdns/ns_fnet_events.c + mdns/ns_fnet_port.c + mdns/ns_mdns_api.c + + mdns/fnet/fnet_stack/services/mdns/fnet_mdns.c + + mdns/fnet/fnet_stack/services/poll/fnet_poll.c + + mdns/fnet/fnet_stack/stack/fnet_stdlib.c + + mle_service/mle_service.c + mle_service/mle_service_buffer.c + mle_service/mle_service_frame_counter_table.c + mle_service/mle_service_interface.c + mle_service/mle_service_security.c + + nd_proxy/nd_proxy.c + + nist_aes_kw/nist_aes_kw.c + + pan_blacklist/pan_blacklist.c + + random_early_detection/random_early_detection.c + + utils/isqrt.c + utils/ns_conf.c + utils/ns_crc.c + utils/ns_file_system.c + utils/ns_time.c + + whiteboard/whiteboard.c +) diff --git a/source/configs/CMakeLists.txt b/source/configs/CMakeLists.txt new file mode 100644 index 0000000000..232128a026 --- /dev/null +++ b/source/configs/CMakeLists.txt @@ -0,0 +1,8 @@ +# Copyright (c) 2020-2021, Pelion and affiliates. +# SPDX-License-Identifier: Apache-2.0 + +target_include_directories(mbed-nanostack-sal_stack + INTERFACE + . + ./base +) diff --git a/source/configs/base/cfg_ws_full.h b/source/configs/base/cfg_ws_full.h new file mode 100644 index 0000000000..798f3c88a0 --- /dev/null +++ b/source/configs/base/cfg_ws_full.h @@ -0,0 +1,20 @@ +/* + * 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 "cfg_ws_border_router.h" + +#define HAVE_PAE_SUPP diff --git a/source/configs/base/cfg_ws_host.h b/source/configs/base/cfg_ws_host.h index 49122b9da6..aec86edcd3 100644 --- a/source/configs/base/cfg_ws_host.h +++ b/source/configs/base/cfg_ws_host.h @@ -18,9 +18,7 @@ #define HAVE_WS #define HAVE_WS_HOST #define HAVE_WS_VERSION_1_1 -#define HAVE_RPL #define HAVE_MPL #define HAVE_6LOWPAN_ND #define HAVE_IPV6_ND -#define HAVE_PAE_SUPP -#define HAVE_6LOWPAN_ROUTER \ No newline at end of file +#define HAVE_6LOWPAN_ROUTER diff --git a/source/configs/base/cfg_ws_router.h b/source/configs/base/cfg_ws_router.h index 78f3537941..5e36562036 100644 --- a/source/configs/base/cfg_ws_router.h +++ b/source/configs/base/cfg_ws_router.h @@ -17,5 +17,6 @@ #include "cfg_ws_host.h" +#define HAVE_RPL #define HAVE_WS_ROUTER #define HAVE_EAPOL_RELAY diff --git a/source/configs/cfg_generic.h b/source/configs/cfg_generic.h index c7a27d4c2d..49ccb5ee99 100644 --- a/source/configs/cfg_generic.h +++ b/source/configs/cfg_generic.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2016-2019, Pelion and affiliates. + * Copyright (c) 2014, 2016-2021, Pelion and affiliates. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -20,7 +20,7 @@ #include "base/cfg_lowpan_border_router.h" #include "base/cfg_local_socket.h" #include "base/cfg_rf_tunnel.h" -#include "base/cfg_ws_border_router.h" +#include "base/cfg_ws_full.h" #define FEA_TRACE_SUPPORT #define EXTRA_CONSISTENCY_CHECKS diff --git a/source/configs/cfg_ws_full.h b/source/configs/cfg_ws_full.h new file mode 100644 index 0000000000..798f3c88a0 --- /dev/null +++ b/source/configs/cfg_ws_full.h @@ -0,0 +1,20 @@ +/* + * 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 "cfg_ws_border_router.h" + +#define HAVE_PAE_SUPP diff --git a/source/configs/cfg_ws_host.h b/source/configs/cfg_ws_host.h index 74b3113c48..debfeb2c87 100644 --- a/source/configs/cfg_ws_host.h +++ b/source/configs/cfg_ws_host.h @@ -20,4 +20,5 @@ #define FEA_TRACE_SUPPORT #define EXTRA_CONSISTENCY_CHECKS +#define HAVE_PAE_SUPP diff --git a/source/configs/cfg_ws_router.h b/source/configs/cfg_ws_router.h index a4cf952501..da740e5c69 100644 --- a/source/configs/cfg_ws_router.h +++ b/source/configs/cfg_ws_router.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Pelion and affiliates. + * Copyright (c) 2019-2021, Pelion and affiliates. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -20,4 +20,5 @@ #define FEA_TRACE_SUPPORT #define EXTRA_CONSISTENCY_CHECKS +#define HAVE_PAE_SUPP diff --git a/source/ipv6_stack/CMakeLists.txt b/source/ipv6_stack/CMakeLists.txt new file mode 100644 index 0000000000..6ef7fbb31c --- /dev/null +++ b/source/ipv6_stack/CMakeLists.txt @@ -0,0 +1,13 @@ +# Copyright (c) 2020-2021, Pelion and affiliates. +# SPDX-License-Identifier: Apache-2.0 + +target_include_directories(mbed-nanostack-sal_stack + INTERFACE + . +) + +target_sources(mbed-nanostack-sal_stack + INTERFACE + ipv6_routing_table.c + protocol_ipv6.c +) diff --git a/source/libDHCPv6/CMakeLists.txt b/source/libDHCPv6/CMakeLists.txt new file mode 100644 index 0000000000..f922d6e437 --- /dev/null +++ b/source/libDHCPv6/CMakeLists.txt @@ -0,0 +1,15 @@ +# Copyright (c) 2020-2021, Pelion and affiliates. +# SPDX-License-Identifier: Apache-2.0 + +target_include_directories(mbed-nanostack-sal_stack + INTERFACE + . +) + +target_sources(mbed-nanostack-sal_stack + INTERFACE + dhcp_service_api.c + libDHCPv6.c + libDHCPv6_server.c + libDHCPv6_vendordata.c +) diff --git a/source/libNET/CMakeLists.txt b/source/libNET/CMakeLists.txt new file mode 100644 index 0000000000..8d2a977d72 --- /dev/null +++ b/source/libNET/CMakeLists.txt @@ -0,0 +1,25 @@ +# Copyright (c) 2020-2021, Pelion and affiliates. +# SPDX-License-Identifier: Apache-2.0 + +target_include_directories(mbed-nanostack-sal_stack + INTERFACE + . + ./src +) + +target_sources(mbed-nanostack-sal_stack + INTERFACE + src/multicast_api.c + src/net_6lowpan_parameter_api.c + src/net_dns.c + src/net_dns_internal.h + src/net_ipv6.c + src/net_load_balance.c + src/net_load_balance_internal.h + src/net_mle.c + src/net_rpl.c + src/net_short_address_extension.c + src/net_test.c + src/ns_net.c + src/socket_api.c +) diff --git a/source/libNET/src/net_load_balance.c b/source/libNET/src/net_load_balance.c index 7dbbe1ae29..34fb9bf32d 100644 --- a/source/libNET/src/net_load_balance.c +++ b/source/libNET/src/net_load_balance.c @@ -248,7 +248,7 @@ void net_load_balance_internal_state_activate(protocol_interface_info_entry_t *i 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); + const rpl_dodag_conf_int_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 ? diff --git a/sources.mk b/sources.mk index 1b6916f4b7..417d2d63f4 100644 --- a/sources.mk +++ b/sources.mk @@ -24,8 +24,9 @@ SRCS += \ source/6LoWPAN/ws/ws_neighbor_class.c \ source/6LoWPAN/ws/ws_bootstrap.c \ source/6LoWPAN/ws/ws_bootstrap_6lbr.c \ + source/6LoWPAN/ws/ws_bootstrap_6lr.c \ + source/6LoWPAN/ws/ws_bootstrap_6ln.c \ source/6LoWPAN/ws/ws_bootstrap_ffn.c \ - source/6LoWPAN/ws/ws_bootstrap_lfn.c \ source/6LoWPAN/ws/ws_common.c \ source/6LoWPAN/ws/ws_management_api.c \ source/6LoWPAN/ws/ws_bbr_api.c \