From e7914df2fc0d604e27f5c26c935d05181f6be72d Mon Sep 17 00:00:00 2001 From: Arto Kinnunen Date: Thu, 20 Feb 2020 16:27:48 +0200 Subject: [PATCH] Squashed 'features/nanostack/sal-stack-nanostack/' changes from 9b3e144f5b..fb7413b846 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit fb7413b846 Merge branch 'release_internal' into release_external a9f6e88978 Merge branch 'master' into release_internal c536960fb0 DHCPv6 Server feature update 01e7e820d5 Merge pull request #2314 from ARMmbed/update_from_mbedos c906c43a8a Fixed typo: 'lenght' in ns_crc.h 2bd05584fe Wi-sun border router DHCPv6 server address alocation update 63e4680ca3 Allow buffer_dyn to handle more data (#2311) 9b82abff03 Copy IE unicast channel function from WS info instead of FHSS configu… (#2310) 18247d546f Wi-sun RPL memory soft and hard limit update c8560dbe01 Updated RPL default memory sof and hard limit to 2/4 from 1/2. 05aa54c464 Update MPL parameters to follow Specification f728d55920 Support for handle CRC error which will automatically change a channel. 6b6f535828 Corrected EUI-64 address bit flip on supplicant 015f3fe60e Corrected bitfield definition 7717ef8c60 Improved initial EAPOL-key send stop logic on supplicant 4185734223 Improved EAPOL key update retry logic 8bda176445 Wi-sun boot fix 6283dfd643 DIO advertisment fix 1acec7cdcc Aro Registation and Dao update 6cde17ad9c Iotthd 3963 2 (#2301) b9187daa62 Randomize fixed channel when making new parent selection 34d0339a4d Wi-sun address registartion update 5b3055904a Allow unicast TX to overlap with MC (#2298) d40b1c7d01 MAC: Updated calling FHSS TX done (#2295) aeb93a16ae Add support for bbr configuration that removes default route from DIO 9b941af4b5 Use default UC channel function in discovery, fixed BC schedule (#2284) d65fcc6bf2 Fix Wi-SUN network name comparison (#2294) f085132543 Made parent set size configuraple in RPL fd11ffae1a Added HAVE_WS flag to FHSS api (#2296) 4f275005fb Implemented optimal packet size test api (#2292) 87ee16a22b Call channel change after filtered out packet d196ffc4c5 Refactor Wi-SUN BBR stop function 35970d7ea9 Revert "Disabled temporarily tx slot check for testing purposes (#2287)" (#2289) 8cc0ff508b Disabled temporarily tx slot check for testing purposes (#2287) e306dc5adb Removed extra ";" 5642a4fe74 Free TX failed list when FHSS deleted (#2285) 9fcf718d22 Updated FHSS optimal packet length to 300 bytes (#2282) 427743f718 ETX and Source route validation update 7b6bcca842 Added TX/RX bytes in PHY statistics (#2281) a043f8dc30 Wi-sun FHSS Management update 2ff90e6c0f Configure TXRX slot length using given datarate (#2275) a126cb750d ETX sampling rule update d5cf8d52e2 Clean ARMC6/GCC compiler warnings (#2278) 807632dd94 DHCP server freed next free allocated id fd6ce049a3 Thread Child ml16 update clear old address queue's and registered address. 99e6efac6c Neighbour remove operation update 5cd094cd1d Corrected GTK update initial EAPOL-key trickle timer 7606ee87a9 Wi-sun NS Aro registration blacklisting update e3e5a00c55 Timed parent selection timer trigger update 71441212ea RPL DIO Multicast message update 588f202a51 Wi-Sun RPL bootstrap update 20289f675d Added periodic RPL version number increase d8dd18d89b Added ignoring of incoming security messages and improved EAP-TLS startup 73506346ca Corrected initial EAPOL-key trickle retries ac33518493 Wi-sun ETX and proping update 11c486f391 Implemented unregistering FHSS from MAC. FHSS deleted in ifdown call. (#2266) eabca172af Wi-Sun Border router DHCPV server SLAAC mode enabled by default. 1d6ce9c0a4 DHCPv6 Server feature update 46aa46042d Fixed unit test's. c65292e9eb Mac enhanced ACK pending update 11a1e1d2de Store TX start channel and black list if TX failed (#2261) 04946065e4 Adapatation layer unicast list entry free update 4481e8635a Updated trace level to info. c9e3d8ef74 Interface down update 1f77ad6964 Updated trace levels (#2258) 1d82fd5a5d Wi-sun BBR route update fix 33c48eb647 Removed NUD messages from registered children ec2ea92b71 Added RX and TX active times in PHY statistics (#2255) 49686ccb3c Wi-sun certification test setup update 1090430622 Trickle API update and Wi-SUN config sol state timeout update 38df5768c5 Wi-sun advertisment consistent update 81740b8b1d Wi-sun bootstarp update nad balck list trace level update 6919ba1301 Wi-sun New key index activate. 0aead9305a Wi-sun Probe functionality revert operation 4ff02f9770 Stop sending normal ACK if neighbour is Unknown. c387fda238 NS Probe limiter accept only 2 probe at 16 seconds period. a58c71b96b Trace level updates (#2247) 6867dd7b27 Suplicant EAP-TLS timeout is not incremented from retries 1f1c2a24fa Test purpose change. 1b99fe18df Added ETX to rpl_possible_better_candidate 3441594157 RPL parent candidate list update 96ffe92744 Adaptation layer to support multiple simultaneous unicast transmissions (#2243) 45f851997f On stop (ifdown) stores frame counters regardless of threshold 5c2fc55f0e Corrected frame counter handling on re-discovery 930741617f Added check to prevent installing new GTK to used index using GKH 385ae14284 WS bootstrap: print MAC address 2b1dfb90ed Slaac address can be recreated after root stop 74ff3cc503 Merge branch 'release_internal' into release_external 66bfd985fb Fixed trace printing warnings. 21d9c24acd DHCP server address allocated pointer init fix. e659a01241 Fixed compile warning for may uninitialized usage. cee8502783 Fixed trace printing warnings. bc9f07bd49 DHCP server address allocated pointer init fix. e3fddadccf Fixed compile warning for may uninitialized usage. bf909d29d3 Modified bbr restart mechanism when dodagid was lost git-subtree-dir: features/nanostack/sal-stack-nanostack git-subtree-split: fb7413b846f0052d72c506ebab2534bcafdfff60 --- nanostack/fhss_api.h | 3 +- nanostack/fhss_test_api.h | 46 ++ nanostack/platform/arm_hal_phy.h | 7 +- nanostack/sw_mac.h | 7 + nanostack/ws_bbr_api.h | 12 +- .../Generic/protocol_6lowpan_bootstrap.c | 4 +- .../Generic/protocol_6lowpan_interface.c | 23 +- .../Bootstraps/protocol_6lowpan_interface.h | 2 + source/6LoWPAN/MAC/mac_helper.c | 1 + source/6LoWPAN/MAC/mac_response_handler.c | 1 + source/6LoWPAN/ND/nd_router_object.c | 17 +- source/6LoWPAN/Thread/thread_bootstrap.c | 2 +- source/6LoWPAN/Thread/thread_common.c | 2 + source/6LoWPAN/Thread/thread_management_if.c | 2 +- .../Thread/thread_mle_message_handler.c | 2 +- source/6LoWPAN/Thread/thread_network_synch.c | 19 +- .../6LoWPAN/Thread/thread_router_bootstrap.c | 8 - source/6LoWPAN/Thread/thread_test_api.c | 3 +- source/6LoWPAN/adaptation_interface.c | 158 ++++-- source/6LoWPAN/lowpan_adaptation_interface.h | 4 +- source/6LoWPAN/ws/ws_bbr_api.c | 139 ++++-- source/6LoWPAN/ws/ws_bbr_api_internal.h | 4 +- source/6LoWPAN/ws/ws_bootstrap.c | 458 +++++++++++------- source/6LoWPAN/ws/ws_bootstrap.h | 3 - source/6LoWPAN/ws/ws_common.c | 42 +- source/6LoWPAN/ws/ws_common.h | 26 +- source/6LoWPAN/ws/ws_common_defines.h | 6 +- source/6LoWPAN/ws/ws_config.h | 13 +- source/6LoWPAN/ws/ws_llc_data_service.c | 2 +- source/6LoWPAN/ws/ws_management_api.c | 77 ++- source/6LoWPAN/ws/ws_neighbor_class.h | 1 - source/6LoWPAN/ws/ws_pae_auth.c | 32 +- source/6LoWPAN/ws/ws_pae_auth.h | 2 +- source/6LoWPAN/ws/ws_pae_controller.c | 62 ++- source/6LoWPAN/ws/ws_pae_lib.c | 14 + source/6LoWPAN/ws/ws_pae_lib.h | 19 + source/6LoWPAN/ws/ws_pae_nvm_data.c | 10 +- source/6LoWPAN/ws/ws_pae_supp.c | 246 ++++++++-- source/6LoWPAN/ws/ws_pae_supp.h | 12 +- source/Common_Protocols/icmpv6.c | 8 +- source/Common_Protocols/icmpv6.h | 1 + source/Common_Protocols/icmpv6_radv.c | 3 + source/Common_Protocols/ipv6.c | 6 + source/Core/buffer_dyn.c | 43 +- source/Core/include/ns_buffer.h | 2 +- source/Core/ns_socket.c | 8 +- source/DHCPv6_Server/DHCPv6_Server_service.c | 67 +-- source/DHCPv6_Server/DHCPv6_server_service.h | 3 +- source/MAC/IEEE802_15_4/mac_defines.h | 2 + source/MAC/IEEE802_15_4/mac_fhss_callbacks.c | 9 +- source/MAC/IEEE802_15_4/mac_mcps_sap.c | 15 +- source/MAC/IEEE802_15_4/mac_mlme.c | 2 + source/MAC/IEEE802_15_4/mac_pd_sap.c | 62 ++- source/MAC/IEEE802_15_4/mac_security_mib.c | 19 + source/MAC/IEEE802_15_4/sw_mac.c | 14 + source/NWK_INTERFACE/protocol_core.c | 5 +- source/RPL/rpl_control.c | 155 +++++- source/RPL/rpl_control.h | 24 +- source/RPL/rpl_downward.c | 16 +- source/RPL/rpl_mrhof.c | 22 + source/RPL/rpl_objective.h | 5 +- source/RPL/rpl_of0.c | 10 + source/RPL/rpl_policy.c | 11 +- source/RPL/rpl_policy.h | 1 + source/RPL/rpl_structures.h | 9 +- source/RPL/rpl_upward.c | 156 ++++-- source/RPL/rpl_upward.h | 11 +- source/Security/TLS/tls_lib.c | 1 + .../eap_tls_sec_prot/auth_eap_tls_sec_prot.c | 39 +- .../eap_tls_sec_prot/supp_eap_tls_sec_prot.c | 29 +- .../fwh_sec_prot/auth_fwh_sec_prot.c | 3 +- .../gkh_sec_prot/auth_gkh_sec_prot.c | 3 + .../protocols/key_sec_prot/key_sec_prot.c | 4 +- source/Security/protocols/sec_prot_keys.c | 72 ++- source/Security/protocols/sec_prot_keys.h | 50 +- source/Service_Libs/Trickle/trickle.c | 20 + source/Service_Libs/Trickle/trickle.h | 5 + source/Service_Libs/blacklist/blacklist.c | 8 +- source/Service_Libs/etx/etx.c | 133 ++--- source/Service_Libs/etx/etx.h | 27 +- source/Service_Libs/fhss/fhss.c | 5 +- source/Service_Libs/fhss/fhss_common.c | 3 + source/Service_Libs/fhss/fhss_common.h | 1 + source/Service_Libs/fhss/fhss_test_api.c | 46 ++ source/Service_Libs/fhss/fhss_ws.c | 92 +++- source/Service_Libs/fhss/fhss_ws.h | 7 +- source/Service_Libs/utils/ns_crc.h | 2 +- source/libDHCPv6/dhcp_service_api.c | 2 +- source/libDHCPv6/libDHCPv6_server.c | 330 ++++++++++--- source/libDHCPv6/libDHCPv6_server.h | 49 +- source/libNET/src/net_6lowpan_parameter_api.c | 5 + source/libNET/src/net_load_balance.c | 16 +- source/libNET/src/ns_net.c | 9 +- source/libNET/src/socket_api.c | 9 +- sources.mk | 1 + 95 files changed, 2324 insertions(+), 827 deletions(-) create mode 100644 nanostack/fhss_test_api.h create mode 100644 source/Service_Libs/fhss/fhss_test_api.c diff --git a/nanostack/fhss_api.h b/nanostack/fhss_api.h index 84c0c17c326..be5a90c1d21 100644 --- a/nanostack/fhss_api.h +++ b/nanostack/fhss_api.h @@ -122,9 +122,10 @@ typedef void fhss_data_tx_done(const fhss_api_t *api, bool waiting_ack, bool tx_ * @param api FHSS instance. * @param handle Handle of the data request. * @param frame_type Frame type of packet (Frames types are defined by FHSS api). + * @param channel Channel wanted to black list temporarily. * @return true if frame has to be queued for retransmission, false otherwise. */ -typedef bool fhss_data_tx_fail(const fhss_api_t *api, uint8_t handle, int frame_type); +typedef bool fhss_data_tx_fail(const fhss_api_t *api, uint8_t handle, int frame_type, uint8_t channel); /** * @brief Change synchronization state. diff --git a/nanostack/fhss_test_api.h b/nanostack/fhss_test_api.h new file mode 100644 index 00000000000..270c5a27a31 --- /dev/null +++ b/nanostack/fhss_test_api.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2020, Arm Limited and affiliates. + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * \file fhss_test_api.h + * \brief + */ + +#ifndef FHSS_TEST_API_H +#define FHSS_TEST_API_H + + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Set optimal packet length + * + * \param fhss_api FHSS instance. + * \param packet_length Optimal packet length + * + * \return 0 Success + * \return -1 Failure + */ +int8_t fhss_set_optimal_packet_length(const fhss_api_t *fhss_api, uint16_t packet_length); + +#ifdef __cplusplus +} +#endif + +#endif // FHSS_TEST_API_H diff --git a/nanostack/platform/arm_hal_phy.h b/nanostack/platform/arm_hal_phy.h index 9f4e09937db..ab53b5942cb 100644 --- a/nanostack/platform/arm_hal_phy.h +++ b/nanostack/platform/arm_hal_phy.h @@ -161,7 +161,8 @@ typedef enum { CHANNEL_PAGE_5 = 5, ///< Page 5 CHANNEL_PAGE_6 = 6, ///< Page 6 CHANNEL_PAGE_9 = 9, ///< Page 9 - CHANNEL_PAGE_10 = 10 ///< Page 10 + CHANNEL_PAGE_10 = 10, ///< Page 10 + CHANNEL_PAGE_UNDEFINED ///< Undefined } channel_page_e; /** Modulation index */ @@ -192,6 +193,10 @@ typedef struct phy_rf_statistics_s { uint32_t crc_fails; ///< CRC failures uint32_t tx_timeouts; ///< transmission timeouts uint32_t rx_timeouts; ///< reception timeouts + uint64_t tx_active_time; ///< transmission active time + uint64_t rx_active_time; ///< reception active time + uint32_t tx_bytes; ///< transmitted bytes + uint32_t rx_bytes; ///< received bytes } phy_rf_statistics_s; /** Virtual data request */ diff --git a/nanostack/sw_mac.h b/nanostack/sw_mac.h index e4a018fc4e9..894b8b75c4b 100644 --- a/nanostack/sw_mac.h +++ b/nanostack/sw_mac.h @@ -67,6 +67,13 @@ extern int8_t ns_sw_mac_virtual_client_unregister(struct mac_api_s *api); */ extern int ns_sw_mac_fhss_register(struct mac_api_s *mac_api, struct fhss_api *fhss_api); +/** + * @brief Unregister FHSS API instance from given software MAC instance. + * @param mac_api MAC instance. + * @return 0 on success, -1 on fail. + */ +extern int ns_sw_mac_fhss_unregister(struct mac_api_s *mac_api); + /** * @brief Request registered FHSS API instance from software MAC instance. * @param mac_api MAC instance. diff --git a/nanostack/ws_bbr_api.h b/nanostack/ws_bbr_api.h index a4d4d460e8f..1559f433d55 100644 --- a/nanostack/ws_bbr_api.h +++ b/nanostack/ws_bbr_api.h @@ -48,14 +48,10 @@ int ws_bbr_start(int8_t interface_id, int8_t backbone_interface_id); /** * Border router configuration options */ -#define BBR_ULA_C 0x0001 /**< Static ULA prefix created automatically */ -#define BBR_GUA_ROUTE 0x0002 /**< More specific route is added for GUA prefix */ -#define BBR_BB_WAIT 0x0004 /**< Wait backbone availability before starting Wi-SUN network */ - -/*Deprecated configuration values */ -#define BBR_GUA_C 0x0000 /**< Routable prefix is learned from the backbone */ -#define BBR_GUA_SLAAC 0x0000 /**< Use SLAAC addressing in routable prefix */ -#define BBR_GUA_WAIT 0x0000 /**< Wait backbone availability before startingRPL dodag */ +#define BBR_ULA_C 0x0001 /**< Static ULA prefix created automatically */ +#define BBR_GUA_ROUTE 0x0002 /**< More specific route is added for GUA prefix */ +#define BBR_BB_WAIT 0x0004 /**< Wait backbone availability before starting Wi-SUN network */ +#define BBR_DEFAULT_ROUTE 0x0008 /**< Add default route parameter to DIO */ /** * Configure border router features. diff --git a/source/6LoWPAN/Bootstraps/Generic/protocol_6lowpan_bootstrap.c b/source/6LoWPAN/Bootstraps/Generic/protocol_6lowpan_bootstrap.c index e78b91c088a..cbe3e12c67e 100644 --- a/source/6LoWPAN/Bootstraps/Generic/protocol_6lowpan_bootstrap.c +++ b/source/6LoWPAN/Bootstraps/Generic/protocol_6lowpan_bootstrap.c @@ -1379,6 +1379,8 @@ static int8_t arm_6lowpan_bootstrap_down(protocol_interface_info_entry_t *cur) } cur->if_lowpan_security_params->mle_security_frame_counter = mle_service_security_get_frame_counter(cur->id); mle_service_interface_receiver_handler_update(cur->id, mle_6lowpan_message_handler); + // Reset MAC for safe upper layer memory free + protocol_mac_reset(cur); return nwk_6lowpan_down(cur); } #ifdef HAVE_6LOWPAN_ND @@ -1593,7 +1595,7 @@ static void lowpan_neighbor_entry_remove_notify(mac_neighbor_table_entry_t *entr { protocol_interface_info_entry_t *cur_interface = user_data; - lowpan_adaptation_remove_free_indirect_table(cur_interface, entry_ptr); + lowpan_adaptation_neigh_remove_free_tx_tables(cur_interface, entry_ptr); // Sleepy host if (cur_interface->lowpan_info & INTERFACE_NWK_CONF_MAC_RX_OFF_IDLE) { mac_data_poll_protocol_poll_mode_decrement(cur_interface); diff --git a/source/6LoWPAN/Bootstraps/Generic/protocol_6lowpan_interface.c b/source/6LoWPAN/Bootstraps/Generic/protocol_6lowpan_interface.c index d3b0d16520b..92ea3ce7382 100644 --- a/source/6LoWPAN/Bootstraps/Generic/protocol_6lowpan_interface.c +++ b/source/6LoWPAN/Bootstraps/Generic/protocol_6lowpan_interface.c @@ -72,6 +72,15 @@ #include "6LoWPAN/Fragmentation/cipv6_fragmenter.h" #include "libNET/src/net_load_balance_internal.h" +void protocol_mac_reset(protocol_interface_info_entry_t *cur) +{ + if (cur->mac_api) { + mlme_reset_t reset; + reset.SetDefaultPIB = true; + cur->mac_api->mlme_req(cur->mac_api, MLME_RESET, &reset); + } +} + static int8_t set_6lowpan_nwk_down(protocol_interface_info_entry_t *cur) @@ -96,15 +105,11 @@ static int8_t set_6lowpan_nwk_down(protocol_interface_info_entry_t *cur) } if (cur->interface_mode == INTERFACE_UP) { - if (cur->mac_api) { - mlme_reset_t reset; - reset.SetDefaultPIB = true; - cur->mac_parameters->pan_id = 0xffff; - cur->mac_parameters->SecurityEnabled = false; - cur->mac_parameters->security_frame_counter = 0; - cur->mac_parameters->mac_security_level = 0; - cur->mac_api->mlme_req(cur->mac_api, MLME_RESET, &reset); - } + cur->mac_parameters->pan_id = 0xffff; + cur->mac_parameters->SecurityEnabled = false; + cur->mac_parameters->security_frame_counter = 0; + cur->mac_parameters->mac_security_level = 0; + protocol_mac_reset(cur); cur->interface_mode = INTERFACE_IDLE; net_load_balance_internal_state_activate(cur, false); } diff --git a/source/6LoWPAN/Bootstraps/protocol_6lowpan_interface.h b/source/6LoWPAN/Bootstraps/protocol_6lowpan_interface.h index bd7875c5146..017805735ca 100644 --- a/source/6LoWPAN/Bootstraps/protocol_6lowpan_interface.h +++ b/source/6LoWPAN/Bootstraps/protocol_6lowpan_interface.h @@ -31,5 +31,7 @@ extern int8_t nwk_6lowpan_up(struct protocol_interface_info_entry *cur); */ extern int8_t nwk_6lowpan_down(struct protocol_interface_info_entry *cur); +extern void protocol_mac_reset(struct protocol_interface_info_entry *cur); + #endif /* PROTOCOL_6LOWPAN_INTERFACE_H_ */ diff --git a/source/6LoWPAN/MAC/mac_helper.c b/source/6LoWPAN/MAC/mac_helper.c index 1f7de87fc7d..e33c7fe6f95 100644 --- a/source/6LoWPAN/MAC/mac_helper.c +++ b/source/6LoWPAN/MAC/mac_helper.c @@ -887,6 +887,7 @@ int8_t mac_helper_key_link_frame_counter_set(int8_t interface_id, uint32_t seq_p void mac_helper_devicetable_remove(mac_api_t *mac_api, uint8_t attribute_index, uint8_t *mac64) { + (void) mac64; if (!mac_api) { return; } diff --git a/source/6LoWPAN/MAC/mac_response_handler.c b/source/6LoWPAN/MAC/mac_response_handler.c index 1c89a92578c..87d3003bbc6 100644 --- a/source/6LoWPAN/MAC/mac_response_handler.c +++ b/source/6LoWPAN/MAC/mac_response_handler.c @@ -120,6 +120,7 @@ void mcps_data_indication_handler(const mac_api_t *api, const mcps_data_ind_t *d void mcps_purge_confirm_handler(const mac_api_t *api, mcps_purge_conf_t *data) { (void)api; + (void)data; tr_info("MCPS Data Purge confirm status %u, for handle %u", data->status, data->msduHandle); } diff --git a/source/6LoWPAN/ND/nd_router_object.c b/source/6LoWPAN/ND/nd_router_object.c index c397bfa66c8..53ff5ac59f1 100644 --- a/source/6LoWPAN/ND/nd_router_object.c +++ b/source/6LoWPAN/ND/nd_router_object.c @@ -856,9 +856,6 @@ static void nd_update_registration(protocol_interface_info_entry_t *cur_interfac mac_neighbor_table_entry_t *entry = mac_neighbor_table_address_discover(mac_neighbor_info(cur_interface), ipv6_neighbour_eui64(&cur_interface->ipv6_neighbour_cache, neigh), ADDR_802_15_4_LONG); if (entry) { - if (ws_info(cur_interface)) { - ws_common_etx_validate(cur_interface, entry); - } if (!entry->ffd_device) { rpl_control_publish_host_address(protocol_6lowpan_rpl_domain, neigh->ip_address, neigh->lifetime); @@ -931,11 +928,13 @@ bool nd_ns_aro_handler(protocol_interface_info_entry_t *cur_interface, const uin } /* TODO - check hard upper limit on registrations? */ - if (ws_info(cur_interface) && - !ws_common_allow_child_registration(cur_interface, aro_out->eui64)) { - aro_out->present = true; - aro_out->status = ARO_FULL; - return true; + if (ws_info(cur_interface)) { + + aro_out->status = ws_common_allow_child_registration(cur_interface, aro_out->eui64); + if (aro_out->status != ARO_SUCCESS) { + aro_out->present = true; + return true; + } } /* We need to have entry in the Neighbour Cache */ @@ -1757,6 +1756,8 @@ void nd_6lowpan_set_radv_params(protocol_interface_info_entry_t *cur_interface) cur_interface->adv_retrans_timer = nd_params.ra_retrans_timer; cur_interface->max_initial_rtr_adv_interval = nd_params.ra_interval_min; cur_interface->max_initial_rtr_advertisements = nd_params.ra_transmits; +#else + (void) cur_interface; #endif } #endif // HAVE_6LOWPAN_ND diff --git a/source/6LoWPAN/Thread/thread_bootstrap.c b/source/6LoWPAN/Thread/thread_bootstrap.c index 84d0609fb28..483932b5781 100644 --- a/source/6LoWPAN/Thread/thread_bootstrap.c +++ b/source/6LoWPAN/Thread/thread_bootstrap.c @@ -137,7 +137,7 @@ static void thread_bootstrap_pbbr_update_done(struct protocol_interface_info_ent static void thread_neighbor_remove(mac_neighbor_table_entry_t *entry_ptr, void *user_data) { protocol_interface_info_entry_t *cur = user_data; - lowpan_adaptation_remove_free_indirect_table(cur, entry_ptr); + lowpan_adaptation_neigh_remove_free_tx_tables(cur, entry_ptr); thread_reset_neighbour_info(cur, entry_ptr); //Removes ETX neighbor diff --git a/source/6LoWPAN/Thread/thread_common.c b/source/6LoWPAN/Thread/thread_common.c index 7bbfb739617..bfea2ba7a9e 100644 --- a/source/6LoWPAN/Thread/thread_common.c +++ b/source/6LoWPAN/Thread/thread_common.c @@ -240,6 +240,8 @@ int8_t thread_bootstrap_down(protocol_interface_info_entry_t *cur) tr_debug("SET thread Idle"); //stop polling mac_data_poll_disable(cur); + // Reset MAC for safe upper layer memory free + protocol_mac_reset(cur); //Clean mle table thread_neighbor_list_clean(cur); // store frame counters diff --git a/source/6LoWPAN/Thread/thread_management_if.c b/source/6LoWPAN/Thread/thread_management_if.c index 435ab513345..7409f53a907 100644 --- a/source/6LoWPAN/Thread/thread_management_if.c +++ b/source/6LoWPAN/Thread/thread_management_if.c @@ -699,7 +699,7 @@ int thread_dhcpv6_server_set_anonymous_addressing(int8_t interface_id, uint8_t * return -1; } - return DHCPv6_server_service_set_address_autonous_flag(interface_id, prefix_ptr, anonymous); + return DHCPv6_server_service_set_address_autonous_flag(interface_id, prefix_ptr, anonymous, false); #else (void) interface_id; (void) prefix_ptr; diff --git a/source/6LoWPAN/Thread/thread_mle_message_handler.c b/source/6LoWPAN/Thread/thread_mle_message_handler.c index a8253c5f8eb..31e2f3416ca 100644 --- a/source/6LoWPAN/Thread/thread_mle_message_handler.c +++ b/source/6LoWPAN/Thread/thread_mle_message_handler.c @@ -285,7 +285,7 @@ static void thread_update_mle_entry(protocol_interface_info_entry_t *cur, mle_me if (short_address != entry_temp->mac16) { if (thread_router_addr_from_addr(entry_temp->mac16) == cur->thread_info->routerShortAddress) { thread_dynamic_storage_child_info_clear(cur->id, entry_temp); - protocol_6lowpan_release_short_link_address_from_neighcache(cur, entry_temp->mac16); + } entry_temp->mac16 = short_address; /* throw MLME_GET request, short address is changed automatically in get request callback */ diff --git a/source/6LoWPAN/Thread/thread_network_synch.c b/source/6LoWPAN/Thread/thread_network_synch.c index 0ef70d38f18..1ffbdc8da97 100644 --- a/source/6LoWPAN/Thread/thread_network_synch.c +++ b/source/6LoWPAN/Thread/thread_network_synch.c @@ -64,6 +64,7 @@ #include "Common_Protocols/icmpv6_radv.h" #include "MLE/mle.h" #include "Service_Libs/mac_neighbor_table/mac_neighbor_table.h" +#include "6LoWPAN/lowpan_adaptation_interface.h" #include "6LoWPAN/MAC/mac_helper.h" #define TRACE_GROUP "tsyn" @@ -192,15 +193,29 @@ void thread_dynamic_storage_child_info_store(protocol_interface_info_entry_t *cu void thread_dynamic_storage_child_info_clear(int8_t interface_id, struct mac_neighbor_table_entry *child) { + protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(interface_id); + if (!cur) { + return; + } thread_sync_child_info_t *child_info = thread_dynamic_storage_child_info_find(interface_id, child); + if (child_info) { // Clear child information memset(child_info, 0, sizeof(thread_sync_child_info_t)); tr_debug("Dynamic storage: cleared child; mac16=%04x", child->mac16); - return; } - return; + uint8_t temp_address[2]; + common_write_16_bit(child->mac16, temp_address); + //Release Old short address entries + lowpan_adaptation_free_messages_from_queues_by_address(cur, temp_address, ADDR_802_15_4_SHORT); + /* As we are losing a link to a child address, we can assume that if we have an IP neighbour cache + * mapping to that address, it is no longer valid. We must have been their parent, and they must be + * finding a new parent, and hence a new 16-bit address. (Losing a link to a router address would not + * invalidate our IP->16-bit mapping.) + */ + protocol_6lowpan_release_short_link_address_from_neighcache(cur, child->mac16); + } static thread_sync_child_info_t *thread_dynamic_storage_child_info_find(int8_t interface_id, mac_neighbor_table_entry_t *child) diff --git a/source/6LoWPAN/Thread/thread_router_bootstrap.c b/source/6LoWPAN/Thread/thread_router_bootstrap.c index 1f17c7e5696..81d54494475 100644 --- a/source/6LoWPAN/Thread/thread_router_bootstrap.c +++ b/source/6LoWPAN/Thread/thread_router_bootstrap.c @@ -969,13 +969,6 @@ int thread_router_bootstrap_reset_child_info(protocol_interface_info_entry_t *cu tr_debug("Child free %x", child->mac16); thread_dynamic_storage_child_info_clear(cur->id, child); - /* As we are losing a link to a child address, we can assume that if we have an IP neighbour cache - * mapping to that address, it is no longer valid. We must have been their parent, and they must be - * finding a new parent, and hence a new 16-bit address. (Losing a link to a router address would not - * invalidate our IP->16-bit mapping.) - */ - protocol_6lowpan_release_short_link_address_from_neighcache(cur, child->mac16); - // If Child's RLOC16 appears in the Network Data send the RLOC16 to the Leader if (thread_network_data_services_registered(&cur->thread_info->networkDataStorage, child->mac16)) { tr_debug("Remove references to Child's RLOC16 from the Network Data"); @@ -1824,7 +1817,6 @@ void thread_router_bootstrap_mle_receive_cb(int8_t interface_id, mle_message_t * // Was this previously our child? If yes, update. if ((entry_temp->mac16 & THREAD_CHILD_MASK) && thread_router_addr_from_addr(entry_temp->mac16) == cur->thread_info->routerShortAddress) { thread_dynamic_storage_child_info_clear(cur->id, entry_temp); - protocol_6lowpan_release_short_link_address_from_neighcache(cur, entry_temp->mac16); } update_mac_mib = true; entry_temp->mac16 = shortAddress; // short address refreshed diff --git a/source/6LoWPAN/Thread/thread_test_api.c b/source/6LoWPAN/Thread/thread_test_api.c index 26b7dd9250a..bc137b1a9f0 100644 --- a/source/6LoWPAN/Thread/thread_test_api.c +++ b/source/6LoWPAN/Thread/thread_test_api.c @@ -643,11 +643,10 @@ int thread_test_version_set(int8_t interface_id, uint8_t version) int thread_test_pbbr_response_override_set(int8_t interface_id, uint8_t dua_status, uint8_t dua_count, uint8_t ba_failure_count) { -#ifdef HAVE_THREAD +#if defined(HAVE_THREAD) && defined(HAVE_THREAD_V2) && defined(HAVE_THREAD_BORDER_ROUTER) (void)interface_id; thread_bbr_commercial_status_override_set(dua_status, dua_count, ba_failure_count); return 0; - #else (void)interface_id; (void)dua_status; diff --git a/source/6LoWPAN/adaptation_interface.c b/source/6LoWPAN/adaptation_interface.c index 0758ed4d123..99636719d9d 100644 --- a/source/6LoWPAN/adaptation_interface.c +++ b/source/6LoWPAN/adaptation_interface.c @@ -89,8 +89,8 @@ typedef struct { fragmenter_tx_list_t indirect_tx_queue; uint8_t *fragment_indirect_tx_buffer; //Used for write fragmentation header uint16_t mtu_size; - fragmenter_tx_entry_t active_unicast_tx_buf; //Current active direct unicast tx process fragmenter_tx_entry_t active_broadcast_tx_buf; //Current active direct broadcast tx process + fragmenter_tx_list_t activeUnicastList; //Unicast packets waiting data confirmation from MAC buffer_list_t directTxQueue; //Waiting free tx process uint16_t directTxQueue_size; uint16_t indirect_big_packet_threshold; @@ -110,7 +110,7 @@ static fragmenter_interface_t *lowpan_adaptation_interface_discover(int8_t inter /* Interface direct message pending queue functions */ static void lowpan_adaptation_tx_queue_write(fragmenter_interface_t *interface_ptr, buffer_t *buf); -static buffer_t *lowpan_adaptation_tx_queue_read(fragmenter_interface_t *interface_ptr, protocol_interface_info_entry_t *cur); +static buffer_t *lowpan_adaptation_tx_queue_read(fragmenter_interface_t *interface_ptr); /* Data direction and message length validation */ static bool lowpan_adaptation_indirect_data_request(mac_neighbor_table_entry_t *mle_entry); @@ -126,7 +126,7 @@ static void lowpan_data_request_to_mac(protocol_interface_info_entry_t *cur, buf /* Tx confirmation local functions */ static bool lowpan_active_tx_handle_verify(uint8_t handle, buffer_t *buf); -static fragmenter_tx_entry_t *lowpan_indirect_tx_handle_verify(uint8_t handle, fragmenter_tx_list_t *indirect_tx_queue); +static fragmenter_tx_entry_t *lowpan_listed_tx_handle_verify(uint8_t handle, fragmenter_tx_list_t *indirect_tx_queue); static void lowpan_adaptation_data_process_clean(fragmenter_interface_t *interface_ptr, fragmenter_tx_entry_t *tx_ptr, uint8_t socket_event); static uint8_t map_mlme_status_to_socket_event(uint8_t mlme_status); static bool lowpan_adaptation_tx_process_ready(fragmenter_tx_entry_t *tx_ptr); @@ -138,6 +138,8 @@ static bool lowpan_adaptation_indirect_queue_free_message(struct protocol_interf static fragmenter_tx_entry_t *lowpan_adaptation_indirect_mac_data_request_active(fragmenter_interface_t *interface_ptr, fragmenter_tx_entry_t *tx_ptr); +static bool lowpan_buffer_tx_allowed(fragmenter_interface_t *interface_ptr, buffer_t *buf); + static void lowpan_adaptation_etx_update_cb(protocol_interface_info_entry_t *cur, buffer_t *buf, const mcps_data_conf_t *confirm) { switch (confirm->status) { @@ -221,18 +223,14 @@ static void lowpan_adaptation_tx_queue_write(fragmenter_interface_t *interface_p protocol_stats_update(STATS_AL_TX_QUEUE_SIZE, interface_ptr->directTxQueue_size); } -static buffer_t *lowpan_adaptation_tx_queue_read(fragmenter_interface_t *interface_ptr, protocol_interface_info_entry_t *cur) +static buffer_t *lowpan_adaptation_tx_queue_read(fragmenter_interface_t *interface_ptr) { - /* Currently this function is called only when data confirm is received for previously sent packet. - * Data confirm has freed the corresponding "active buffer" and this function will look for new buffer to be set as active buffer. - */ + // Currently this function is called only when data confirm is received for previously sent packet. + if (!interface_ptr->directTxQueue_size) { + return NULL; + } ns_list_foreach_safe(buffer_t, buf, &interface_ptr->directTxQueue) { - bool fragmented_needed = lowpan_adaptation_request_longer_than_mtu(cur, buf, interface_ptr); - //Check that we not trig second active fragmentation process - if (fragmented_needed && interface_ptr->fragmenter_active) { - tr_debug("Do not trig Second active fragmentation"); - } else if ((buf->link_specific.ieee802_15_4.requestAck && !interface_ptr->active_unicast_tx_buf.buf) - || (!buf->link_specific.ieee802_15_4.requestAck && !interface_ptr->active_broadcast_tx_buf.buf)) { + if (lowpan_buffer_tx_allowed(interface_ptr, buf)) { ns_list_remove(&interface_ptr->directTxQueue, buf); interface_ptr->directTxQueue_size--; protocol_stats_update(STATS_AL_TX_QUEUE_SIZE, interface_ptr->directTxQueue_size); @@ -292,7 +290,7 @@ static bool lowpan_active_tx_handle_verify(uint8_t handle, buffer_t *buf) -static fragmenter_tx_entry_t *lowpan_indirect_tx_handle_verify(uint8_t handle, fragmenter_tx_list_t *indirect_tx_queue) +static fragmenter_tx_entry_t *lowpan_listed_tx_handle_verify(uint8_t handle, fragmenter_tx_list_t *indirect_tx_queue) { ns_list_foreach(fragmenter_tx_entry_t, entry, indirect_tx_queue) { if (entry->buf->seq == handle) { @@ -310,9 +308,9 @@ static uint8_t lowpan_data_request_unique_handle_get(fragmenter_interface_t *int uint8_t handle; while (!valid_info) { handle = interface_ptr->msduHandle++; - if (!lowpan_active_tx_handle_verify(handle, interface_ptr->active_unicast_tx_buf.buf) + if (!lowpan_listed_tx_handle_verify(handle, &interface_ptr->activeUnicastList) && !lowpan_active_tx_handle_verify(handle, interface_ptr->active_broadcast_tx_buf.buf) - && !lowpan_indirect_tx_handle_verify(handle, &interface_ptr->indirect_tx_queue)) { + && !lowpan_listed_tx_handle_verify(handle, &interface_ptr->indirect_tx_queue)) { valid_info = true; } } @@ -320,7 +318,7 @@ static uint8_t lowpan_data_request_unique_handle_get(fragmenter_interface_t *int } -static void lowpan_indirect_entry_free(fragmenter_tx_list_t *list, fragmenter_tx_entry_t *entry) +static void lowpan_list_entry_free(fragmenter_tx_list_t *list, fragmenter_tx_entry_t *entry) { ns_list_remove(list, entry); if (entry->buf) { @@ -330,11 +328,15 @@ static void lowpan_indirect_entry_free(fragmenter_tx_list_t *list, fragmenter_tx ns_dyn_mem_free(entry); } -static void lowpan_indirect_queue_free(fragmenter_tx_list_t *list) +static void lowpan_list_free(fragmenter_tx_list_t *list, bool fragment_buf_free) { while (!ns_list_is_empty(list)) { fragmenter_tx_entry_t *entry = ns_list_get_first(list); - lowpan_indirect_entry_free(list, entry); + if (!fragment_buf_free) { + //We can't free this pointer becuase it must be until interface is deleted + entry->fragmenter_buf = NULL; + } + lowpan_list_entry_free(list, entry); } } @@ -365,6 +367,7 @@ int8_t lowpan_adaptation_interface_init(int8_t interface_id, uint16_t mac_mtu_si ns_list_init(&interface_ptr->indirect_tx_queue); ns_list_init(&interface_ptr->directTxQueue); + ns_list_init(&interface_ptr->activeUnicastList); ns_list_add_to_end(&fragmenter_interface_list, interface_ptr); @@ -389,11 +392,11 @@ int8_t lowpan_adaptation_interface_free(int8_t interface_id) ns_list_remove(&fragmenter_interface_list, interface_ptr); //free active tx process - lowpan_active_buffer_state_reset(&interface_ptr->active_unicast_tx_buf); + lowpan_list_free(&interface_ptr->activeUnicastList, false); lowpan_active_buffer_state_reset(&interface_ptr->active_broadcast_tx_buf); //Free Indirect entry - lowpan_indirect_queue_free(&interface_ptr->indirect_tx_queue); + lowpan_list_free(&interface_ptr->indirect_tx_queue, true); buffer_free_list(&interface_ptr->directTxQueue); @@ -414,13 +417,13 @@ int8_t lowpan_adaptation_interface_reset(int8_t interface_id) } //free active tx process - lowpan_active_buffer_state_reset(&interface_ptr->active_unicast_tx_buf); + lowpan_list_free(&interface_ptr->activeUnicastList, false); lowpan_active_buffer_state_reset(&interface_ptr->active_broadcast_tx_buf); //Clean fragmented message flag interface_ptr->fragmenter_active = false; //Free Indirect entry - lowpan_indirect_queue_free(&interface_ptr->indirect_tx_queue); + lowpan_list_free(&interface_ptr->indirect_tx_queue, true); buffer_free_list(&interface_ptr->directTxQueue); @@ -588,10 +591,15 @@ static bool lowpan_message_fragmentation_message_write(const fragmenter_tx_entry static fragmenter_tx_entry_t *lowpan_adaptation_tx_process_init(fragmenter_interface_t *interface_ptr, bool indirect, bool fragmented, bool is_unicast) { + // For broadcast, the active TX queue is only 1 entry. For unicast, using a list. fragmenter_tx_entry_t *tx_entry; if (!indirect) { if (is_unicast) { - tx_entry = &interface_ptr->active_unicast_tx_buf; + tx_entry = lowpan_indirect_entry_allocate(0); + if (!tx_entry) { + return NULL; + } + ns_list_add_to_end(&interface_ptr->activeUnicastList, tx_entry); } else { tx_entry = &interface_ptr->active_broadcast_tx_buf; } @@ -936,6 +944,40 @@ static void lowpan_data_request_to_mac(protocol_interface_info_entry_t *cur, buf } } +static bool lowpan_adaptation_is_destination_tx_active(fragmenter_tx_list_t *list, buffer_t *buf) +{ + ns_list_foreach(fragmenter_tx_entry_t, entry, list) { + if (entry->buf) { + if (!memcmp(&entry->buf->dst_sa.address[2], &buf->dst_sa.address[2], 8)) { + return true; + } + } + } + return false; +} + +static bool lowpan_buffer_tx_allowed(fragmenter_interface_t *interface_ptr, buffer_t *buf) +{ + bool is_unicast = buf->link_specific.ieee802_15_4.requestAck; + // Indirect allowed always + if (buf->link_specific.ieee802_15_4.indirectTxProcess) { + return true; + } + // Do not accept any other TX when fragmented TX active. Prevents other frames to be sent in between two fragments. + if (interface_ptr->fragmenter_active) { + return false; + } + // Do not accept more than one active broadcast TX + if (!is_unicast && interface_ptr->active_broadcast_tx_buf.buf) { + return false; + } + // Do not accept more than one active unicast TX per destination + if (is_unicast && lowpan_adaptation_is_destination_tx_active(&interface_ptr->activeUnicastList, buf)) { + return false; + } + return true; +} + int8_t lowpan_adaptation_interface_tx(protocol_interface_info_entry_t *cur, buffer_t *buf) { bool is_room_for_new_message; @@ -956,11 +998,10 @@ int8_t lowpan_adaptation_interface_tx(protocol_interface_info_entry_t *cur, buff bool fragmented_needed = lowpan_adaptation_request_longer_than_mtu(cur, buf, interface_ptr); bool is_unicast = buf->link_specific.ieee802_15_4.requestAck; bool indirect = buf->link_specific.ieee802_15_4.indirectTxProcess; - if (!indirect) { - if (((is_unicast && interface_ptr->active_unicast_tx_buf.buf) || (!is_unicast && interface_ptr->active_broadcast_tx_buf.buf)) || (fragmented_needed && interface_ptr->fragmenter_active)) { - lowpan_adaptation_tx_queue_write(interface_ptr, buf); - return 0; //Return here - } + + if (!lowpan_buffer_tx_allowed(interface_ptr, buf)) { + lowpan_adaptation_tx_queue_write(interface_ptr, buf); + return 0; } //Allocate Handle @@ -1107,10 +1148,14 @@ static bool lowpan_adaptation_tx_process_ready(fragmenter_tx_entry_t *tx_ptr) static void lowpan_adaptation_data_process_clean(fragmenter_interface_t *interface_ptr, fragmenter_tx_entry_t *tx_ptr, uint8_t socket_event) { buffer_t *buf = tx_ptr->buf; + tx_ptr->buf = NULL; if (buf->link_specific.ieee802_15_4.indirectTxProcess) { //release from list and free entry - lowpan_indirect_entry_free(&interface_ptr->indirect_tx_queue, tx_ptr); + lowpan_list_entry_free(&interface_ptr->indirect_tx_queue, tx_ptr); + } else if (buf->link_specific.ieee802_15_4.requestAck) { + ns_list_remove(&interface_ptr->activeUnicastList, tx_ptr); + ns_dyn_mem_free(tx_ptr); } socket_tx_buffer_event_and_free(buf, socket_event); @@ -1131,18 +1176,19 @@ int8_t lowpan_adaptation_interface_tx_confirm(protocol_interface_info_entry_t *c //Check first fragmenter_tx_entry_t *tx_ptr; bool active_direct_confirm; - bool is_unicast = true; - - if (lowpan_active_tx_handle_verify(confirm->msduHandle, interface_ptr->active_unicast_tx_buf.buf)) { - active_direct_confirm = true; - tx_ptr = &interface_ptr->active_unicast_tx_buf; - } else if (lowpan_active_tx_handle_verify(confirm->msduHandle, interface_ptr->active_broadcast_tx_buf.buf)) { + if (lowpan_active_tx_handle_verify(confirm->msduHandle, interface_ptr->active_broadcast_tx_buf.buf)) { active_direct_confirm = true; tx_ptr = &interface_ptr->active_broadcast_tx_buf; - is_unicast = false; } else { - active_direct_confirm = false; - tx_ptr = lowpan_indirect_tx_handle_verify(confirm->msduHandle, &interface_ptr->indirect_tx_queue); + tx_ptr = lowpan_listed_tx_handle_verify(confirm->msduHandle, &interface_ptr->activeUnicastList); + if (tx_ptr) { + active_direct_confirm = true; + } else { + tx_ptr = lowpan_listed_tx_handle_verify(confirm->msduHandle, &interface_ptr->indirect_tx_queue); + if (tx_ptr) { + active_direct_confirm = false; + } + } } if (!tx_ptr) { @@ -1214,7 +1260,7 @@ int8_t lowpan_adaptation_interface_tx_confirm(protocol_interface_info_entry_t *c } #ifdef HAVE_RPL - if (confirm->status == MLME_TX_NO_ACK) { + if (confirm->status == MLME_TX_NO_ACK || confirm->status == MLME_UNAVAILABLE_KEY) { if (buf->route && rpl_data_is_rpl_parent_route(buf->route->route_info.source)) { protocol_stats_update(STATS_RPL_PARENT_TX_FAIL, 1); } @@ -1232,14 +1278,15 @@ int8_t lowpan_adaptation_interface_tx_confirm(protocol_interface_info_entry_t *c break; } - - if ((is_unicast && !interface_ptr->active_unicast_tx_buf.buf) || (!is_unicast && !interface_ptr->active_broadcast_tx_buf.buf)) { - //Read Buffer and trig next direct request - lowpan_adaptation_interface_tx(cur, lowpan_adaptation_tx_queue_read(interface_ptr, cur)); + // When confirmation is for direct transmission, push all allowed buffers to MAC + if (active_direct_confirm == true) { + buffer_t *buf_from_queue = lowpan_adaptation_tx_queue_read(interface_ptr); + while (buf_from_queue) { + lowpan_adaptation_interface_tx(cur, buf_from_queue); + buf_from_queue = lowpan_adaptation_tx_queue_read(interface_ptr); + } } - return 0; - } static bool mac_data_is_broadcast_addr(const sockaddr_t *addr) @@ -1332,7 +1379,7 @@ bool lowpan_adaptation_tx_active(int8_t interface_id) { fragmenter_interface_t *interface_ptr = lowpan_adaptation_interface_discover(interface_id); - if (!interface_ptr || (!interface_ptr->active_unicast_tx_buf.buf && !interface_ptr->active_broadcast_tx_buf.buf)) { + if (!interface_ptr || (!ns_list_count(&interface_ptr->activeUnicastList) && !interface_ptr->active_broadcast_tx_buf.buf)) { return false; } return true; @@ -1399,19 +1446,19 @@ static bool lowpan_adaptation_indirect_queue_free_message(struct protocol_interf return true; } -void lowpan_adaptation_remove_free_indirect_table(protocol_interface_info_entry_t *cur_interface, mac_neighbor_table_entry_t *entry_ptr) +void lowpan_adaptation_neigh_remove_free_tx_tables(protocol_interface_info_entry_t *cur_interface, mac_neighbor_table_entry_t *entry_ptr) { //Free first by defined short address if (entry_ptr->mac16 < 0xfffe) { uint8_t temp_address[2]; common_write_16_bit(entry_ptr->mac16, temp_address); - lowpan_adaptation_indirect_free_messages_from_queues_by_address(cur_interface, temp_address, ADDR_802_15_4_SHORT); + lowpan_adaptation_free_messages_from_queues_by_address(cur_interface, temp_address, ADDR_802_15_4_SHORT); } - lowpan_adaptation_indirect_free_messages_from_queues_by_address(cur_interface, entry_ptr->mac64, ADDR_802_15_4_LONG); + lowpan_adaptation_free_messages_from_queues_by_address(cur_interface, entry_ptr->mac64, ADDR_802_15_4_LONG); } -int8_t lowpan_adaptation_indirect_free_messages_from_queues_by_address(struct protocol_interface_info_entry *cur, uint8_t *address_ptr, addrtype_t adr_type) +int8_t lowpan_adaptation_free_messages_from_queues_by_address(struct protocol_interface_info_entry *cur, uint8_t *address_ptr, addrtype_t adr_type) { fragmenter_interface_t *interface_ptr = lowpan_adaptation_interface_discover(cur->id); @@ -1427,9 +1474,18 @@ int8_t lowpan_adaptation_indirect_free_messages_from_queues_by_address(struct pr } } + //Check next direct queue + ns_list_foreach_safe(fragmenter_tx_entry_t, entry, &interface_ptr->activeUnicastList) { + if (lowpan_tx_buffer_address_compare(&entry->buf->dst_sa, address_ptr, adr_type)) { + //Purge from mac + lowpan_adaptation_indirect_queue_free_message(cur, interface_ptr, entry); + } + } + return 0; } + int8_t lowpan_adaptation_indirect_queue_params_set(struct protocol_interface_info_entry *cur, uint16_t indirect_big_packet_threshold, uint16_t max_indirect_big_packets_total, uint16_t max_indirect_small_packets_per_child) { fragmenter_interface_t *interface_ptr = lowpan_adaptation_interface_discover(cur->id); diff --git a/source/6LoWPAN/lowpan_adaptation_interface.h b/source/6LoWPAN/lowpan_adaptation_interface.h index 562e4820340..307dd9917be 100644 --- a/source/6LoWPAN/lowpan_adaptation_interface.h +++ b/source/6LoWPAN/lowpan_adaptation_interface.h @@ -51,9 +51,9 @@ struct buffer *lowpan_adaptation_reassembly(struct protocol_interface_info_entry bool lowpan_adaptation_tx_active(int8_t interface_id); -void lowpan_adaptation_remove_free_indirect_table(struct protocol_interface_info_entry *cur_interface, struct mac_neighbor_table_entry *entry_ptr); +void lowpan_adaptation_neigh_remove_free_tx_tables(struct protocol_interface_info_entry *cur_interface, struct mac_neighbor_table_entry *entry_ptr); -int8_t lowpan_adaptation_indirect_free_messages_from_queues_by_address(struct protocol_interface_info_entry *cur, uint8_t *address_ptr, addrtype_t adr_type); +int8_t lowpan_adaptation_free_messages_from_queues_by_address(struct protocol_interface_info_entry *cur, uint8_t *address_ptr, addrtype_t adr_type); int8_t lowpan_adaptation_indirect_queue_params_set(struct protocol_interface_info_entry *cur, uint16_t indirect_big_packet_threshold, uint16_t max_indirect_big_packets_total, uint16_t max_indirect_small_packets_per_child); diff --git a/source/6LoWPAN/ws/ws_bbr_api.c b/source/6LoWPAN/ws/ws_bbr_api.c index 390de439329..7961f10cc95 100644 --- a/source/6LoWPAN/ws/ws_bbr_api.c +++ b/source/6LoWPAN/ws/ws_bbr_api.c @@ -45,10 +45,10 @@ #define RPL_INSTANCE_ID 1 -static uint8_t current_instance_id = RPL_INSTANCE_ID; - #ifdef HAVE_WS_BORDER_ROUTER +static uint8_t current_instance_id = RPL_INSTANCE_ID; + #define WS_ULA_LIFETIME 24*3600 #define WS_ROUTE_LIFETIME WS_ULA_LIFETIME #define WS_DHCP_ADDRESS_LIFETIME 2*3600 @@ -85,7 +85,27 @@ static rpl_dodag_conf_t rpl_conf = { .dio_redundancy_constant = WS_RPL_DIO_REDUNDANCY }; -void ws_bbr_rpl_config(uint8_t imin, uint8_t doubling, uint8_t redundancy, uint16_t dag_max_rank_increase, uint16_t min_hop_rank_increase) +static void ws_bbr_rpl_version_timer_start(protocol_interface_info_entry_t *cur, uint8_t version) +{ + // Set the next timeout value for version update + if (version < 128) { + //stable version for RPL so slow timer update is ok + cur->ws_info->rpl_version_timer = RPL_VERSION_LIFETIME; + } else { + cur->ws_info->rpl_version_timer = RPL_VERSION_LIFETIME_RESTART; + } +} + +static void ws_bbr_rpl_version_increase(protocol_interface_info_entry_t *cur) +{ + if (!protocol_6lowpan_rpl_root_dodag) { + return; + } + ws_bbr_rpl_version_timer_start(cur, rpl_control_increment_dodag_version(protocol_6lowpan_rpl_root_dodag)); +} + + +void ws_bbr_rpl_config(protocol_interface_info_entry_t *cur, uint8_t imin, uint8_t doubling, uint8_t redundancy, uint16_t dag_max_rank_increase, uint16_t min_hop_rank_increase) { if (imin == 0 || doubling == 0) { // use default values @@ -111,11 +131,11 @@ void ws_bbr_rpl_config(uint8_t imin, uint8_t doubling, uint8_t redundancy, uint1 if (protocol_6lowpan_rpl_root_dodag) { rpl_control_update_dodag_config(protocol_6lowpan_rpl_root_dodag, &rpl_conf); - rpl_control_increment_dodag_version(protocol_6lowpan_rpl_root_dodag); + ws_bbr_rpl_version_increase(cur); } } -static void ws_bbr_rpl_root_start(uint8_t *dodag_id) +static void ws_bbr_rpl_root_start(protocol_interface_info_entry_t *cur, uint8_t *dodag_id) { tr_info("RPL root start"); rpl_data_init_root(); @@ -123,7 +143,6 @@ static void ws_bbr_rpl_root_start(uint8_t *dodag_id) if (protocol_6lowpan_rpl_root_dodag) { rpl_control_delete_dodag_root(protocol_6lowpan_rpl_domain, protocol_6lowpan_rpl_root_dodag); protocol_6lowpan_rpl_root_dodag = NULL; - current_instance_id++; } protocol_6lowpan_rpl_root_dodag = rpl_control_create_dodag_root(protocol_6lowpan_rpl_domain, current_instance_id, dodag_id, &rpl_conf, rpl_conf.min_hop_rank_increase, RPL_GROUNDED | RPL_MODE_NON_STORING | RPL_DODAG_PREF(0)); @@ -133,19 +152,20 @@ static void ws_bbr_rpl_root_start(uint8_t *dodag_id) } // RPL memory limits set larger for Border router rpl_control_set_memory_limits(64 * 1024, 0); + + // Initial version number for RPL start is 240 from RPL RFC + ws_bbr_rpl_version_timer_start(cur, 240); + } + static void ws_bbr_rpl_root_stop(void) { tr_info("RPL root stop"); if (protocol_6lowpan_rpl_root_dodag) { rpl_control_delete_dodag_root(protocol_6lowpan_rpl_domain, protocol_6lowpan_rpl_root_dodag); protocol_6lowpan_rpl_root_dodag = NULL; - current_instance_id++; } - memset(current_local_prefix, 0, 8); - memset(current_global_prefix, 0, 8); - memset(current_dodag_id, 0, 16); } static int ws_border_router_proxy_validate(int8_t interface_id, uint8_t *address) @@ -177,11 +197,24 @@ int ws_border_router_proxy_state_update(int8_t caller_interface_id, int8_t handl static if_address_entry_t *ws_bbr_slaac_generate(protocol_interface_info_entry_t *cur, uint8_t *ula_prefix) { - if_address_entry_t *add_entry = icmpv6_slaac_address_add(cur, ula_prefix, 64, 0xffffffff, 0xffffffff, true, SLAAC_IID_FIXED); + if_address_entry_t *add_entry = NULL; + const uint8_t *address; + + address = addr_select_with_prefix(cur, ula_prefix, 64, 0); + if (address) { + // Address already exists for this prefix find the entry + add_entry = addr_get_entry(cur, address); + } + + if (!add_entry) { + add_entry = icmpv6_slaac_address_add(cur, ula_prefix, 64, 0xffffffff, 0xffffffff, true, SLAAC_IID_FIXED); + } if (!add_entry) { tr_err("ula create failed"); return NULL; } + // Set the timeouts for this address and policy + icmpv6_slaac_prefix_update(cur, ula_prefix, 64, 0xffffffff, 0xffffffff); addr_policy_table_add_entry(ula_prefix, 64, 2, WS_NON_PREFFRED_LABEL); return add_entry; } @@ -307,9 +340,11 @@ static void ws_bbr_dhcp_server_start(protocol_interface_info_entry_t *cur, uint8 return; } DHCPv6_server_service_callback_set(cur->id, global_id, NULL, wisun_dhcp_address_add_cb); - - DHCPv6_server_service_set_address_autonous_flag(cur->id, global_id, true); + //Enable SLAAC mode to border router + DHCPv6_server_service_set_address_autonous_flag(cur->id, global_id, true, false); DHCPv6_server_service_set_address_validlifetime(cur->id, global_id, WS_DHCP_ADDRESS_LIFETIME); + //SEt max value for not limiting address allocation + DHCPv6_server_service_set_max_clients_accepts_count(cur->id, global_id, MAX_SUPPORTED_ADDRESS_LIST_SIZE); ws_dhcp_client_address_request(cur, global_id, ll); } @@ -325,6 +360,31 @@ static void ws_bbr_dhcp_server_stop(protocol_interface_info_entry_t *cur, uint8_ } +static void ws_bbr_routing_stop(protocol_interface_info_entry_t *cur) +{ + tr_info("BBR routing stop"); + if (memcmp(current_local_prefix, ADDR_UNSPECIFIED, 8) != 0) { + ws_bbr_slaac_remove(cur, current_local_prefix); + memset(current_local_prefix, 0, 8); + } + + if (memcmp(current_global_prefix, ADDR_UNSPECIFIED, 8) != 0) { + ws_bbr_dhcp_server_stop(cur, current_global_prefix); + if (backbone_interface_id >= 0) { + // Delete route to backbone if it exists + ipv6_route_add_with_info(current_global_prefix, 64, backbone_interface_id, NULL, ROUTE_THREAD_BBR, NULL, 0, 0, 0); + } + memset(current_global_prefix, 0, 8); + } + + if (memcmp(current_dodag_id, ADDR_UNSPECIFIED, 8) != 0) { + ws_bbr_slaac_remove(cur, current_dodag_id); + memset(current_dodag_id, 0, 16); + } + + ws_bbr_rpl_root_stop(); +} + static void ws_bbr_rpl_status_check(protocol_interface_info_entry_t *cur) { @@ -339,7 +399,7 @@ static void ws_bbr_rpl_status_check(protocol_interface_info_entry_t *cur) if (!protocol_6lowpan_rpl_root_dodag) { // Generate DODAGID if (ws_bbr_static_dodagid_create(cur) == 0) { - ws_bbr_rpl_root_start(current_dodag_id); + ws_bbr_rpl_root_start(cur, current_dodag_id); } } @@ -354,9 +414,8 @@ static void ws_bbr_rpl_status_check(protocol_interface_info_entry_t *cur) */ if (protocol_interface_address_compare(current_dodag_id) != 0) { //DODAGID is lost need to restart - tr_warn("DODAGID lost restart RPL"); - memset(current_dodag_id, 0, 16); - ws_bbr_rpl_root_stop(); + tr_warn("DODAGID lost restart BBR"); + ws_bbr_routing_stop(cur); return; } @@ -366,7 +425,9 @@ static void ws_bbr_rpl_status_check(protocol_interface_info_entry_t *cur) /* * Add default route to RPL */ - rpl_control_update_dodag_route(protocol_6lowpan_rpl_root_dodag, NULL, 0, 0, WS_ROUTE_LIFETIME, false); + if (configuration & BBR_DEFAULT_ROUTE) { + rpl_control_update_dodag_route(protocol_6lowpan_rpl_root_dodag, NULL, 0, 0, WS_ROUTE_LIFETIME, false); + } /* * Create static ULA configuration or modify if needed @@ -384,6 +445,7 @@ static void ws_bbr_rpl_status_check(protocol_interface_info_entry_t *cur) if (memcmp(local_prefix, ADDR_UNSPECIFIED, 8) != 0) { if (!ws_bbr_slaac_generate(cur, local_prefix)) { + // Address creation failed return; } @@ -425,8 +487,9 @@ static void ws_bbr_rpl_status_check(protocol_interface_info_entry_t *cur) if (configuration & BBR_GUA_ROUTE) { rpl_control_update_dodag_route(protocol_6lowpan_rpl_root_dodag, current_global_prefix, 64, 0, 0, true); } - ipv6_route_add_with_info(current_global_prefix, 64, backbone_interface_id, NULL, ROUTE_THREAD_BBR, NULL, 0, 120, 0); - + if (backbone_interface_id >= 0) { + ipv6_route_add_with_info(current_global_prefix, 64, backbone_interface_id, NULL, ROUTE_THREAD_BBR, NULL, 0, 120, 0); + } ws_bbr_dhcp_server_stop(cur, current_global_prefix); } // TODO add global prefix @@ -435,9 +498,11 @@ static void ws_bbr_rpl_status_check(protocol_interface_info_entry_t *cur) tr_info("RPL global prefix activate %s", trace_ipv6_prefix(global_prefix, 64)); // Add default route to RPL // Enable default routing to backbone - if (ipv6_route_add_with_info(global_prefix, 64, backbone_interface_id, NULL, ROUTE_THREAD_BBR, NULL, 0, 0xffffffff, 0) == NULL) { - tr_err("global route add failed"); - return; + if (backbone_interface_id >= 0) { + if (ipv6_route_add_with_info(global_prefix, 64, backbone_interface_id, NULL, ROUTE_THREAD_BBR, NULL, 0, 0xffffffff, 0) == NULL) { + tr_err("global route add failed"); + return; + } } ws_bbr_dhcp_server_start(cur, global_prefix); rpl_control_update_dodag_prefix(protocol_6lowpan_rpl_root_dodag, global_prefix, 64, 0, 0, 0, false); @@ -450,7 +515,8 @@ static void ws_bbr_rpl_status_check(protocol_interface_info_entry_t *cur) } memcpy(current_global_prefix, global_prefix, 8); - rpl_control_increment_dodag_version(protocol_6lowpan_rpl_root_dodag); + ws_bbr_rpl_version_increase(cur); + nd_proxy_downstream_interface_register(cur->id, ws_border_router_proxy_validate, ws_border_router_proxy_state_update); } else if (memcmp(current_global_prefix, ADDR_UNSPECIFIED, 8) != 0) { /* @@ -511,7 +577,7 @@ void ws_bbr_seconds_timer(protocol_interface_info_entry_t *cur, uint32_t seconds if (cur->ws_info->pan_version_timer > seconds) { cur->ws_info->pan_version_timer -= seconds; } else { - // Border router has timed out + // PAN version number update tr_debug("Border router version number update"); cur->ws_info->pan_version_timer = ws_common_version_lifetime_get(cur->ws_info->network_size_config); cur->ws_info->pan_information.pan_version++; @@ -522,9 +588,13 @@ void ws_bbr_seconds_timer(protocol_interface_info_entry_t *cur, uint32_t seconds ws_common_network_size_configure(cur, cur->ws_info->pan_information.pan_size); } } - + if (cur->ws_info->rpl_version_timer > seconds) { + cur->ws_info->rpl_version_timer -= seconds; + } else { + // RPL version update needed + ws_bbr_rpl_version_increase(cur); + } } - } uint16_t test_pan_size_override = 0xffff; @@ -607,15 +677,11 @@ void ws_bbr_stop(int8_t interface_id) { #ifdef HAVE_WS_BORDER_ROUTER - (void)interface_id; - backbone_interface_id = -1; + protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(interface_id); - if (!protocol_6lowpan_rpl_domain) { - return; - } + ws_bbr_routing_stop(cur); - rpl_control_delete_dodag_root(protocol_6lowpan_rpl_domain, protocol_6lowpan_rpl_root_dodag); - protocol_6lowpan_rpl_root_dodag = NULL; + backbone_interface_id = -1; current_instance_id++; #else @@ -626,11 +692,12 @@ int ws_bbr_configure(int8_t interface_id, uint16_t options) { #ifdef HAVE_WS_BORDER_ROUTER - (void)interface_id; + protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(interface_id); + if (protocol_6lowpan_rpl_root_dodag && options != configuration) { //Configuration changed delete previous setup - ws_bbr_rpl_root_stop(); + ws_bbr_routing_stop(cur); } configuration = options; return 0; diff --git a/source/6LoWPAN/ws/ws_bbr_api_internal.h b/source/6LoWPAN/ws/ws_bbr_api_internal.h index 5da59eabcfb..b07565a96c2 100644 --- a/source/6LoWPAN/ws/ws_bbr_api_internal.h +++ b/source/6LoWPAN/ws/ws_bbr_api_internal.h @@ -27,7 +27,7 @@ void ws_bbr_seconds_timer(protocol_interface_info_entry_t *cur, uint32_t seconds uint16_t ws_bbr_pan_size(protocol_interface_info_entry_t *cur); -void ws_bbr_rpl_config(uint8_t imin, uint8_t doubling, uint8_t redundancy, uint16_t dag_max_rank_increase, uint16_t min_hop_rank_increase); +void ws_bbr_rpl_config(protocol_interface_info_entry_t *cur, uint8_t imin, uint8_t doubling, uint8_t redundancy, uint16_t dag_max_rank_increase, uint16_t min_hop_rank_increase); bool ws_bbr_ready_to_start(protocol_interface_info_entry_t *cur); @@ -36,7 +36,7 @@ bool ws_bbr_ready_to_start(protocol_interface_info_entry_t *cur); #define ws_bbr_seconds_timer( cur, seconds) #define ws_bbr_pan_size(cur) 0 -#define ws_bbr_rpl_config( imin, doubling, redundancy, dag_max_rank_increase, min_hop_rank_increase) +#define ws_bbr_rpl_config( cur, imin, doubling, redundancy, dag_max_rank_increase, min_hop_rank_increase) #define ws_bbr_ready_to_start(cur) true #endif //HAVE_WS_BORDER_ROUTER diff --git a/source/6LoWPAN/ws/ws_bootstrap.c b/source/6LoWPAN/ws/ws_bootstrap.c index f620e4d574a..6aaffc1a8ec 100644 --- a/source/6LoWPAN/ws/ws_bootstrap.c +++ b/source/6LoWPAN/ws/ws_bootstrap.c @@ -97,7 +97,6 @@ static void ws_bootstrap_pan_version_increment(protocol_interface_info_entry_t * 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 bool ws_rpl_dio_new_parent_accept(struct protocol_interface_info_entry *interface); static void ws_bootstrap_candidate_table_reset(protocol_interface_info_entry_t *cur); @@ -202,7 +201,7 @@ static int ws_bootstrap_tasklet_init(protocol_interface_info_entry_t *cur) { if (cur->bootStrapId < 0) { cur->bootStrapId = eventOS_event_handler_create(&ws_bootstrap_event_handler, WS_INIT_EVENT); - tr_debug("WS tasklet init"); + tr_info("WS tasklet init"); } if (cur->bootStrapId < 0) { @@ -321,12 +320,16 @@ static void ws_nud_entry_remove(protocol_interface_info_entry_t *cur, mac_neighb } } -static bool ws_nud_message_build(protocol_interface_info_entry_t *cur, mac_neighbor_table_entry_t *neighbor) +static bool ws_nud_message_build(protocol_interface_info_entry_t *cur, mac_neighbor_table_entry_t *neighbor, bool nud_process) { //Send NS uint8_t ll_target[16]; ws_bootsrap_create_ll_address(ll_target, neighbor->mac64); - tr_info("NUD generate NS %u", neighbor->index); + if (nud_process) { + tr_info("NUD generate NS %u", neighbor->index); + } else { + tr_info("Probe generate NS %u", neighbor->index); + } buffer_t *buffer = icmpv6_build_ns(cur, ll_target, NULL, true, false, NULL); if (buffer) { protocol_push(buffer); @@ -368,7 +371,7 @@ void ws_nud_active_timer(protocol_interface_info_entry_t *cur, uint16_t ticks) } else { //Random TX wait period is over - entry->wait_response = ws_nud_message_build(cur, entry->neighbor_info); + entry->wait_response = ws_nud_message_build(cur, entry->neighbor_info, entry->nud_process); if (!entry->wait_response) { if (entry->nud_process && entry->retry_count < 2) { entry->timer = randLIB_get_random_in_range(1, 900); @@ -409,7 +412,8 @@ static void ws_bootstrap_llc_hopping_update(struct protocol_interface_info_entry memcpy(cur->ws_info->hopping_schdule.channel_mask, fhss_configuration->channel_mask, sizeof(uint32_t) * 8); cur->ws_info->hopping_schdule.uc_fixed_channel = fhss_configuration->unicast_fixed_channel; cur->ws_info->hopping_schdule.bc_fixed_channel = fhss_configuration->broadcast_fixed_channel; - cur->ws_info->hopping_schdule.uc_channel_function = fhss_configuration->ws_uc_channel_function; + // Read UC channel function from WS info because FHSS might be temporarily configured to fixed channel during discovery. + cur->ws_info->hopping_schdule.uc_channel_function = cur->ws_info->fhss_uc_channel_function; cur->ws_info->hopping_schdule.bc_channel_function = fhss_configuration->ws_bc_channel_function; cur->ws_info->hopping_schdule.fhss_bc_dwell_interval = fhss_configuration->fhss_bc_dwell_interval; cur->ws_info->hopping_schdule.fhss_broadcast_interval = fhss_configuration->fhss_broadcast_interval; @@ -420,8 +424,7 @@ static void ws_bootstrap_llc_hopping_update(struct protocol_interface_info_entry static int8_t ws_fhss_initialize(protocol_interface_info_entry_t *cur) { fhss_api_t *fhss_api = ns_sw_mac_get_fhss_api(cur->mac_api); - - if (!fhss_api || (fhss_api && cur->ws_info->fhss_owner)) { + if (!fhss_api) { // When FHSS doesn't exist yet, create one fhss_ws_configuration_t fhss_configuration; memset(&fhss_configuration, 0, sizeof(fhss_ws_configuration_t)); @@ -437,26 +440,11 @@ static int8_t ws_fhss_initialize(protocol_interface_info_entry_t *cur) fhss_configuration.ws_bc_channel_function = (fhss_ws_channel_functions)cur->ws_info->fhss_bc_channel_function; fhss_configuration.fhss_bc_dwell_interval = cur->ws_info->fhss_bc_dwell_interval; fhss_configuration.fhss_broadcast_interval = cur->ws_info->fhss_bc_interval; - + fhss_api = ns_fhss_ws_create(&fhss_configuration, cur->ws_info->fhss_timer_ptr); if (!fhss_api) { - fhss_api = ns_fhss_ws_create(&fhss_configuration, cur->ws_info->fhss_timer_ptr); - if (!fhss_api) { - tr_error("fhss create failed"); - return -1; - } - ns_sw_mac_fhss_register(cur->mac_api, fhss_api); - cur->ws_info->fhss_owner = true; - } else { - //Configuration set - ns_fhss_ws_configuration_set(cur->ws_info->fhss_api, &fhss_configuration); - - if (cur->bootsrap_mode == ARM_NWK_BOOTSRAP_MODE_6LoWPAN_BORDER_ROUTER) { - ns_fhss_ws_set_hop_count(cur->ws_info->fhss_api, 0); - } else { - //Clear OWN HOP - ns_fhss_ws_set_hop_count(cur->ws_info->fhss_api, 0xff); - } + return -1; } + ns_sw_mac_fhss_register(cur->mac_api, fhss_api); } else { // Read defaults from the configuration to help FHSS testing const fhss_ws_configuration_t *fhss_configuration = ns_fhss_ws_configuration_get(fhss_api); @@ -519,7 +507,7 @@ static uint16_t ws_randomize_fixed_channel(uint16_t configured_fixed_channel, ui } } -static int8_t ws_fhss_discovery_configure(protocol_interface_info_entry_t *cur) +static int8_t ws_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; @@ -528,8 +516,12 @@ static int8_t ws_fhss_discovery_configure(protocol_interface_info_entry_t *cur) if (ns_fhss_ws_configuration_get(cur->ws_info->fhss_api)) { memcpy(&fhss_configuration, ns_fhss_ws_configuration_get(cur->ws_info->fhss_api), sizeof(fhss_ws_configuration_t)); } - - fhss_configuration.ws_uc_channel_function = WS_FIXED_CHANNEL; + // 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->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_randomize_fixed_channel(cur->ws_info->fhss_uc_fixed_channel, cur->ws_info->hopping_schdule.number_of_channels); @@ -641,8 +633,9 @@ static void ws_bootstrap_ll_address_validate(struct protocol_interface_info_entr mac64[0] |= 2; //Set Local Bit mac64[0] &= ~1; //Clear multicast bit - tr_info("Generated random MAC %s", trace_array(mac64, 8)); + tr_info("Generated random MAC address"); } + tr_info("MAC address: %s", trace_array(mac64, 8)); mac_helper_mac64_set(cur, mac64); memcpy(cur->iid_eui64, mac64, 8); @@ -660,7 +653,6 @@ static void ws_bootstrap_ll_address_validate(struct protocol_interface_info_entr uint16_t ws_etx_read(protocol_interface_info_entry_t *interface, addrtype_t addr_type, const uint8_t *addr_ptr) { - uint16_t etx; if (!addr_ptr || !interface) { return 0; } @@ -675,42 +667,11 @@ uint16_t ws_etx_read(protocol_interface_info_entry_t *interface, addrtype_t addr ws_neighbor_class_entry_t *ws_neighbour = ws_neighbor_class_entry_get(&interface->ws_info->neighbor_storage, attribute_index); etx_storage_t *etx_entry = etx_storage_entry_get(interface->id, attribute_index); - if (interface->bootsrap_mode == ARM_NWK_BOOTSRAP_MODE_6LoWPAN_BORDER_ROUTER) { - if (!ws_neighbour || !etx_entry) { - return 0xffff; - } - } else { - - if (!ws_neighbour || !etx_entry || etx_entry->etx_samples < 1 /*|| - !ws_neighbour->candidate_parent*/) { - // if RSL value is not good enough candidate parent flag is removed and device not accepted as parent - //tr_debug("ws_etx_read not valid params"); - return 0xffff; - } - - //If we are not following gbobal Broadcast synch - if (!interface->ws_info->pan_information.use_parent_bs) { - //We must know both information's here - if (!ws_neighbour->broadcast_shedule_info_stored || - !ws_neighbour->broadcast_timing_info_stored) { - return 0xffff; - } - } else { - if (!ws_neighbour->broadcast_timing_info_stored) { - //Global shedule is stored already - tr_debug("ws_etx_read not valid NO BTI"); - return 0xffff; - } - } - } - - etx = etx_local_etx_read(interface->id, attribute_index); - if (etx == 0) { + if (!ws_neighbour || !etx_entry) { return 0xffff; } - //tr_debug("ws_etx_read etx:%d", etx); - return etx; + return etx_local_etx_read(interface->id, attribute_index); } bool ws_bootstrap_nd_ns_transmit(protocol_interface_info_entry_t *cur, ipv6_neighbour_t *entry, bool unicast, uint8_t seq) { @@ -759,6 +720,8 @@ static int8_t ws_bootstrap_up(protocol_interface_info_entry_t *cur) 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 */ @@ -803,8 +766,12 @@ static int8_t ws_bootstrap_down(protocol_interface_info_entry_t *cur) return -1; } - tr_debug("Wi-SUN ifdown"); - + 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_common_reset(cur) ws_llc_reset(cur); @@ -862,19 +829,26 @@ void ws_bootstrap_configuration_reset(protocol_interface_info_entry_t *cur) static bool ws_bootstrap_network_name_matches(const struct mcps_data_ie_list *ie_ext, const char *network_name_ptr) { + ws_wp_network_name_t network_name; + if (!network_name_ptr || !ie_ext) { return false; } - ws_wp_network_name_t network_name; if (!ws_wp_nested_network_name_read(ie_ext->payloadIeList, ie_ext->payloadIeListLength, &network_name)) { tr_warn("No network name IE"); return false; } - if (network_name_ptr == NULL || strncmp(network_name_ptr, (char *)network_name.network_name, network_name.network_name_length) != 0) { + if (network_name.network_name_length != strlen(network_name_ptr)) { return false; } + + if (strncmp(network_name_ptr, (char *)network_name.network_name, network_name.network_name_length) != 0) { + return false; + } + + // names have equal length and same characters return true; } @@ -894,10 +868,15 @@ static void ws_bootstrap_pan_advertisement_analyse_active(struct protocol_interf * 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 - // All messages are considered as consistent only Solicit will cause inconsistent - trickle_consistent_heard(&cur->ws_info->trickle_pan_advertisement); + 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)) { @@ -1189,7 +1168,7 @@ static void ws_bootstrap_pan_advertisement_solicit_analyse(struct protocol_inter if (ws_bootstrap_state_discovery(cur) && cur->bootsrap_state_machine_cnt > cur->ws_info->trickle_params_pan_discovery.Imin + 50) { cur->bootsrap_state_machine_cnt = cur->ws_info->trickle_params_pan_discovery.Imin + randLIB_get_8bit() % 50; - tr_info("Making parent selection in %d s", (uint32_t)(cur->bootsrap_state_machine_cnt / 10)); + tr_info("Making parent selection in %u s", (cur->bootsrap_state_machine_cnt / 10)); } } @@ -1460,8 +1439,13 @@ static void ws_bootstrap_asynch_ind(struct protocol_interface_info_entry *cur, c static void ws_bootstrap_asynch_confirm(struct protocol_interface_info_entry *interface, uint8_t asynch_message) { ws_stats_update(interface, STATS_WS_ASYNCH_TX, 1); - (void)interface; - (void)asynch_message; + if (interface->bootsrap_mode == ARM_NWK_BOOTSRAP_MODE_6LoWPAN_BORDER_ROUTER) { + if (asynch_message == WS_FT_PAN_CONF && interface->ws_info->pending_key_index_info.state == PENDING_KEY_INDEX_ACTIVATE) { + interface->ws_info->pending_key_index_info.state = NO_PENDING_PROCESS; + tr_info("Activate new default key %u", interface->ws_info->pending_key_index_info.index + 1); + mac_helper_security_auto_request_key_index_set(interface, interface->ws_info->pending_key_index_info.index, interface->ws_info->pending_key_index_info.index + 1); + } + } } uint32_t ws_time_from_last_unicast_traffic(uint32_t current_time_stamp, ws_neighbor_class_entry_t *ws_neighbor) @@ -1495,7 +1479,7 @@ static void ws_bootstrap_neighbor_table_clean(struct protocol_interface_info_ent continue; } - if (cur->nud_active || ws_neighbor->accelerated_etx_probe || ws_neighbor->negative_aro_send) { + if (cur->nud_active || ws_neighbor->negative_aro_send) { //If NUD process is active do not trig continue; } @@ -1589,30 +1573,11 @@ static bool ws_bootstrap_neighbor_info_request(struct protocol_interface_info_en return true; } -static bool ws_rpl_dio_new_parent_accept(struct protocol_interface_info_entry *interface) -{ - uint16_t parent_candidate_size = rpl_control_parent_candidate_list_size(interface, false); - //TODO check bootstarap state for review - //if we have enough candidates at list do not accept new multicast neighbours - if (parent_candidate_size > interface->ws_info->rpl_parent_candidate_max) { - return false; - } - - parent_candidate_size = rpl_control_parent_candidate_list_size(interface, true); - //If we have already enough parent selected Candidates count is bigger than configured - if (parent_candidate_size >= interface->ws_info->rpl_selected_parent_max) { - return false; - } - - return true; -} - - static void ws_neighbor_entry_remove_notify(mac_neighbor_table_entry_t *entry_ptr, void *user_data) { protocol_interface_info_entry_t *cur = user_data; - lowpan_adaptation_remove_free_indirect_table(cur, entry_ptr); + lowpan_adaptation_neigh_remove_free_tx_tables(cur, entry_ptr); // Sleepy host if (cur->lowpan_info & INTERFACE_NWK_CONF_MAC_RX_OFF_IDLE) { mac_data_poll_protocol_poll_mode_decrement(cur); @@ -1634,6 +1599,8 @@ static void ws_neighbor_entry_remove_notify(mac_neighbor_table_entry_t *entry_pt static bool ws_neighbor_entry_nud_notify(mac_neighbor_table_entry_t *entry_ptr, void *user_data) { uint32_t time_from_start = entry_ptr->link_lifetime - entry_ptr->lifetime; + uint8_t ll_address[16]; + bool nud_proces = false; bool activate_nud = false; protocol_interface_info_entry_t *cur = user_data; @@ -1644,17 +1611,22 @@ static bool ws_neighbor_entry_nud_notify(mac_neighbor_table_entry_t *entry_ptr, return false; } - uint8_t ll_address[16]; + ws_bootsrap_create_ll_address(ll_address, entry_ptr->mac64); if (time_from_start > WS_NEIGHBOR_NUD_TIMEOUT) { - ws_bootsrap_create_ll_address(ll_address, entry_ptr->mac64); + if (ipv6_neighbour_has_registered_by_eui64(&cur->ipv6_neighbour_cache, entry_ptr->mac64)) { + // This is our child with valid ARO registration Change link timeout to future we check at 2 minute intervals + entry_ptr->lifetime = entry_ptr->lifetime + 120; + if (entry_ptr->lifetime > entry_ptr->link_lifetime) { + entry_ptr->lifetime = entry_ptr->link_lifetime; + } + return false; + } if (!rpl_control_is_dodag_parent_candidate(cur, ll_address, WS_NEIGHBOUR_MAX_CANDIDATE_PROBE)) { - if (!ipv6_neighbour_has_registered_by_eui64(&cur->ipv6_neighbour_cache, entry_ptr->mac64)) { - //NUD Not needed for if neighbour is not child or parent candidate - return false; - } + //NUD Not needed for if neighbour is not parent candidate + return false; } if (time_from_start > WS_NEIGHBOR_NUD_TIMEOUT * 1.5) { @@ -1666,33 +1638,29 @@ static bool ws_neighbor_entry_nud_notify(mac_neighbor_table_entry_t *entry_ptr, activate_nud = true; } } - } else if (etx_entry->etx_samples < WS_NEIGBOR_ETX_SAMPLE_MAX) { + nud_proces = activate_nud; + } else if (etx_entry->etx_samples < WS_NEIGHBOR_ETX_SAMPLE_MAX) { //Take Random number for trig a prope. //ETX Sample 0: random 1-8 //ETX Sample 1: random 2-16 //ETX Sample 2: random 4-32 - if (etx_entry->etx_samples == 0 && ws_neighbor->accelerated_etx_probe) { - //Accept quick Probe for init ETX - activate_nud = true; - } else { + ws_bootsrap_create_ll_address(ll_address, entry_ptr->mac64); + if (!rpl_control_probe_parent_candidate(cur, ll_address)) { + return false; + } - ws_bootsrap_create_ll_address(ll_address, entry_ptr->mac64); - if (!rpl_control_is_dodag_parent_candidate(cur, ll_address, WS_NEIGHBOUR_MAX_CANDIDATE_PROBE)) { - return false; - } - uint32_t probe_period = WS_PROBE_INIT_BASE_SECONDS << etx_entry->etx_samples; - uint32_t time_block = 1 << etx_entry->etx_samples; - if (time_from_start >= probe_period) { - //tr_debug("Link Probe test %u Sample trig", etx_entry->etx_samples); + uint32_t probe_period = WS_PROBE_INIT_BASE_SECONDS << etx_entry->etx_samples; + uint32_t time_block = 1 << etx_entry->etx_samples; + if (time_from_start >= probe_period) { + //tr_debug("Link Probe test %u Sample trig", etx_entry->etx_samples); + activate_nud = true; + } else if (time_from_start > time_block) { + uint16_t switch_prob = randLIB_get_random_in_range(0, probe_period - 1); + //Take Random from time WS_NEIGHBOR_NUD_TIMEOUT - WS_NEIGHBOR_NUD_TIMEOUT*1.5 + if (switch_prob < 2) { + //tr_debug("Link Probe test with jitter %"PRIu32", sample %u", time_from_start, etx_entry->etx_samples); activate_nud = true; - } else if (time_from_start > time_block) { - uint16_t switch_prob = randLIB_get_random_in_range(0, probe_period - 1); - //Take Random from time WS_NEIGHBOR_NUD_TIMEOUT - WS_NEIGHBOR_NUD_TIMEOUT*1.5 - if (switch_prob < 2) { - //tr_debug("Link Probe test with jitter %"PRIu32", sample %u", time_from_start, etx_entry->etx_samples); - activate_nud = true; - } } } } @@ -1706,14 +1674,9 @@ static bool ws_neighbor_entry_nud_notify(mac_neighbor_table_entry_t *entry_ptr, return false; } entry->neighbor_info = entry_ptr; - if (ws_neighbor->accelerated_etx_probe) { - ws_neighbor->accelerated_etx_probe = false; - entry->timer = 1; - } - if (etx_entry->etx_samples >= WS_NEIGBOR_ETX_SAMPLE_MAX) { - entry->nud_process = true; - } + entry->nud_process = nud_proces; + return true; } @@ -1746,12 +1709,13 @@ int ws_bootstrap_init(int8_t interface_id, net_6lowpan_mode_e bootstrap_mode) if (!etx_storage_list_allocate(cur->id, buffer.device_decription_table_size)) { return -1; } - if (!etx_cached_etx_parameter_set(WS_ETX_MIN_WAIT_TIME, WS_ETX_MIN_SAMPLE_COUNT)) { + if (!etx_cached_etx_parameter_set(WS_ETX_MIN_WAIT_TIME, WS_ETX_MIN_SAMPLE_COUNT, WS_NEIGHBOR_FIRST_ETX_SAMPLE_MIN_COUNT)) { etx_storage_list_allocate(cur->id, 0); return -1; } etx_max_update_set(WS_ETX_MAX_UPDATE); + etx_max_set(WS_ETX_MAX); if (blacklist_init() != 0) { tr_err("MLE blacklist init failed."); @@ -2148,7 +2112,22 @@ static void ws_rpl_prefix_callback(prefix_entry_t *prefix, void *handle, uint8_t } } -static bool ws_rpl_new_parent_callback_t(uint8_t *ll_parent_address, void *handle) +static bool ws_rpl_candidate_soft_filtering(protocol_interface_info_entry_t *cur, struct rpl_instance *instance) +{ + //Already many candidates + if (rpl_control_candidate_list_size(cur, instance) > cur->ws_info->rpl_parent_candidate_max) { + return false; + } + + //Already enough selected candidates + if (rpl_control_selected_parent_count(cur, instance) >= cur->ws_info->rpl_selected_parent_max) { + 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; @@ -2156,26 +2135,102 @@ static bool ws_rpl_new_parent_callback_t(uint8_t *ll_parent_address, void *handl return false; } - uint8_t mac64[8]; + 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; - llc_neighbour_req_t neigh_buffer; - if (ws_bootstrap_neighbor_info_request(cur, mac64, &neigh_buffer, false)) { + + + 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)) { + 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 + 2, replacing + 8, 8); + mac64[2] ^= 2; + + if (ws_etx_read(cur, ADDR_802_15_4_LONG, mac64) == 0xffff) { + //Not proped yet because ETX is 0xffff + return false; + } + + uint16_t etx = 0; + if (neigh_buffer.neighbor) { + etx = etx_local_etx_read(cur->id, neigh_buffer.neighbor->index); + } + + // 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 0 + if (!rpl_control_find_worst_neighbor(cur, instance, replacing)) { + return false; + } + + // +2 Is for PAN ID space + memcpy(mac64 + 2, replacing + 8, 8); + mac64[2] ^= 2; - if (!ws_rpl_dio_new_parent_accept(cur)) { + if (ws_etx_read(cur, ADDR_802_15_4_LONG, mac64) == 0xffff) { + //Not proped yet because ETX is 0xffff return false; } - //Discover Multicast temporary entry + uint16_t etx = 0; + if (neigh_buffer.neighbor) { + etx = etx_local_etx_read(cur->id, neigh_buffer.neighbor->index); + } + + // Accept now only better one's when max candidates selected and max candidate list size is reached + if (!rpl_possible_better_candidate(cur, instance, replacing, candidate_rank, etx)) { + return false; + } + //TODO if replacing has poor ETX, put it in blacklist as "poor ETX" to prevent reselection + //Mark That We can try remove replaced link + replace_ok = true; + +neigh_create: + + + if (neigh_buffer.neighbor) { + //Use Already discovered entry + create_ok = true; + goto neigh_create_ok; + } +#endif - ws_neighbor_temp_class_t *entry = ws_llc_get_multicast_temp_entry(cur, mac64); if (!entry) { + //No Multicast Entry Available return false; } + //Create entry - bool create_ok = ws_bootstrap_neighbor_info_request(cur, mac64, &neigh_buffer, true); + 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; //Copy fhss temporary data @@ -2186,7 +2241,15 @@ static bool ws_rpl_new_parent_callback_t(uint8_t *ll_parent_address, void *handl } 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; } @@ -2198,13 +2261,18 @@ static void ws_bootstrap_rpl_activate(protocol_interface_info_entry_t *cur) 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_t, cur); + rpl_control_set_callback(protocol_6lowpan_rpl_domain, ws_bootstrap_rpl_callback, ws_rpl_prefix_callback, ws_rpl_new_parent_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_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); + 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); + } cur->ws_info->rpl_state = 0xff; // Set invalid state and learn from event } @@ -2222,7 +2290,7 @@ static void ws_bootstrap_network_discovery_configure(protocol_interface_info_ent cur->ws_info->network_pan_id = 0xffff; ws_common_regulatory_domain_config(cur); - ws_fhss_discovery_configure(cur); + ws_fhss_configure(cur, true); //Set Network names, Pan information configure, hopping schedule & GTKHash ws_llc_set_network_name(cur, (uint8_t *)cur->ws_info->network_name, strlen(cur->ws_info->network_name)); @@ -2294,7 +2362,7 @@ static void ws_bootstrap_start_discovery(protocol_interface_info_entry_t *cur) 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); cur->bootsrap_state_machine_cnt = time_to_solicit + cur->ws_info->trickle_params_pan_discovery.Imin + randLIB_get_8bit() % 50; - tr_info("Making parent selection in %d s", (uint32_t)(cur->bootsrap_state_machine_cnt / 10)); + tr_info("Making parent selection in %u s", (cur->bootsrap_state_machine_cnt / 10)); } // Start authentication @@ -2324,7 +2392,16 @@ static void ws_bootstrap_nw_key_clear(protocol_interface_info_entry_t *cur, uint static void ws_bootstrap_nw_key_index_set(protocol_interface_info_entry_t *cur, uint8_t index) { - // Set send key + + if (cur->bootsrap_mode == ARM_NWK_BOOTSRAP_MODE_6LoWPAN_BORDER_ROUTER) { + if (cur->mac_parameters->mac_default_key_index != 0 && cur->mac_parameters->mac_default_key_index != index + 1) { + tr_info("New Pending key Request %u", index + 1); + cur->ws_info->pending_key_index_info.state = PENDING_KEY_INDEX_ADVERTISMENT; + cur->ws_info->pending_key_index_info.index = index; + return; + } + } + mac_helper_security_auto_request_key_index_set(cur, index, index + 1); } @@ -2355,7 +2432,7 @@ static void ws_bootstrap_authentication_completed(protocol_interface_info_entry_ // Go back for network scanning ws_bootstrap_state_change(cur, ER_ACTIVE_SCAN); cur->bootsrap_state_machine_cnt = randLIB_get_random_in_range(10, cur->ws_info->trickle_params_pan_discovery.Imin >> 1); - tr_info("Making parent selection in %d s", (uint32_t)(cur->bootsrap_state_machine_cnt / 10)); + tr_info("Making parent selection in %u s", (cur->bootsrap_state_machine_cnt / 10)); } else { tr_debug("authentication failed"); // What else to do to start over again... @@ -2377,6 +2454,8 @@ static void ws_bootstrap_start_configuration_learn(protocol_interface_info_entry 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); @@ -2387,8 +2466,11 @@ static void ws_bootstrap_rpl_scan_start(protocol_interface_info_entry_t *cur) tr_debug("Start RPL learn"); // routers wait until RPL root is contacted ws_bootstrap_state_change(cur, ER_RPL_SCAN); - // 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); + //For Large network and medium shuold do passive scan + if (cur->ws_info->network_size_config == NETWORK_SIZE_LARGE || cur->ws_info->network_size_config == NETWORK_SIZE_MEDIUM) { + // 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); + } } /* @@ -2494,13 +2576,11 @@ static uint16_t ws_bootstrap_routing_cost_calculate(protocol_interface_info_entr uint16_t etx = etx_local_etx_read(cur->id, mac_neighbor->index); if (etx == 0) { - etx = 0xffff; - } - if (etx > 0x800) { - // Wi-SUN section 6.2.3.1.6.1 says ETX can only be maximum of 1024 (8*128) in RPL units, ie 8.0. - etx = 0x800; + etx = WS_ETX_MAX; //SET maxium value here if ETX is unknown + } else { + //Scale to 128 based ETX (local read retur 0x100 - 0xffff + etx = etx >> 1; } - etx = etx >> 1; return ws_neighbor->routing_cost + etx; } @@ -2574,7 +2654,13 @@ static void ws_bootstrap_pan_config(protocol_interface_info_entry_t *cur) async_req.security.SecurityLevel = mac_helper_default_security_level_get(cur); async_req.security.KeyIdMode = mac_helper_default_security_key_id_mode_get(cur); - async_req.security.KeyIndex = mac_helper_default_key_index_get(cur); + if (cur->bootsrap_mode == ARM_NWK_BOOTSRAP_MODE_6LoWPAN_BORDER_ROUTER && cur->ws_info->pending_key_index_info.state == PENDING_KEY_INDEX_ADVERTISMENT) { + async_req.security.KeyIndex = cur->ws_info->pending_key_index_info.index + 1; + cur->ws_info->pending_key_index_info.state = PENDING_KEY_INDEX_ACTIVATE; + } else { + async_req.security.KeyIndex = mac_helper_default_key_index_get(cur); + } + ws_llc_asynch_request(cur, &async_req); } @@ -2594,6 +2680,11 @@ static void ws_bootstrap_event_handler(arm_event_s *event) break; case WS_DISCOVERY_START: tr_info("Discovery start"); + + //Clear Pending Key Index State + cur->ws_info->pending_key_index_info.state = NO_PENDING_PROCESS; + cur->mac_parameters->mac_default_key_index = 0; + // All trickle timers stopped to allow entry from any state cur->ws_info->trickle_pa_running = false; cur->ws_info->trickle_pc_running = false; @@ -2601,7 +2692,7 @@ static void ws_bootstrap_event_handler(arm_event_s *event) cur->ws_info->trickle_pcs_running = false; if (cur->bootsrap_mode == ARM_NWK_BOOTSRAP_MODE_6LoWPAN_BORDER_ROUTER) { - tr_debug("Border router start network"); + tr_info("Border router start network"); if (!ws_bbr_ready_to_start(cur)) { // Wi-SUN not started yet we wait for Border router permission @@ -2722,12 +2813,17 @@ void ws_bootstrap_network_scan_process(protocol_interface_info_entry_t *cur) 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_network_discovery_configure(cur); + // randomize new channel and start MAC + ws_bootstrap_fhss_activate(cur); // Next check will be after one trickle cur->bootsrap_state_machine_cnt += cur->ws_info->trickle_params_pan_discovery.Imin + randLIB_get_8bit() % 50; - tr_info("Making parent selection in %d s", (uint32_t)(cur->bootsrap_state_machine_cnt / 10)); + 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); @@ -2740,7 +2836,10 @@ void ws_bootstrap_network_scan_process(protocol_interface_info_entry_t *cur) ws_bootstrap_fhss_activate(cur); llc_neighbour_req_t neighbor_info; if (!ws_bootstrap_neighbor_info_request(cur, selected_parent_ptr->addr, &neighbor_info, true)) { - return; + //Remove Neighbour and set Link setup back + ns_list_remove(&cur->ws_info->parent_list_reserved, selected_parent_ptr); + ns_list_add_to_end(&cur->ws_info->parent_list_free, selected_parent_ptr); + goto select_best_candidate; } ws_neighbor_class_neighbor_unicast_time_info_update(neighbor_info.ws_neighbor, &selected_parent_ptr->ws_utt, selected_parent_ptr->timestamp); @@ -2848,7 +2947,7 @@ void ws_bootstrap_state_machine(protocol_interface_info_entry_t *cur) cur->ws_info->trickle_pc_running = false; cur->ws_info->trickle_pas_running = false; cur->ws_info->trickle_pcs_running = false; - + ws_fhss_configure(cur, false); ws_bootstrap_start_authentication(cur); break; case ER_RPL_SCAN: @@ -2873,20 +2972,34 @@ void ws_bootstrap_trickle_timer(protocol_interface_info_entry_t *cur, uint16_t t tr_info("Send PAN advertisement Solicit"); ws_bootstrap_pan_advert_solicit(cur); } - if (cur->ws_info->trickle_pcs_running && - trickle_timer(&cur->ws_info->trickle_pan_config_solicit, &cur->ws_info->trickle_params_pan_discovery, ticks)) { - // send PAN Configuration solicit - if (cur->ws_info->pas_requests >= PCS_MAX) { - // if MAX PCS sent restart discovery + if (cur->ws_info->trickle_pcs_running) { + //Update MAX config sol timeout timer + if (cur->ws_info->pan_config_sol_max_timeout > ticks) { + cur->ws_info->pan_config_sol_max_timeout -= ticks; + } else { + //Config sol state timeout + cur->ws_info->pan_config_sol_max_timeout = 0; + } + + if (trickle_timer(&cur->ws_info->trickle_pan_config_solicit, &cur->ws_info->trickle_params_pan_discovery, ticks)) { + if (cur->ws_info->pas_requests < PCS_MAX) { + // send PAN Configuration solicit + tr_info("Send PAN configuration Solicit"); + ws_bootstrap_pan_config_solicit(cur); + } + //Update counter every time reason that we detect PCS_MAX higher state + cur->ws_info->pas_requests++; + } + + if (cur->ws_info->pas_requests > PCS_MAX || cur->ws_info->pan_config_sol_max_timeout == 0) { + // if MAX PCS sent or max waited timeout restart discovery // Trickle is reseted when entering to discovery from state 3 + tr_info("PAN configuration Solicit timeout"); trickle_inconsistent_heard(&cur->ws_info->trickle_pan_advertisement_solicit, &cur->ws_info->trickle_params_pan_discovery); ws_bootstrap_event_discovery_start(cur); return; } - tr_info("Send PAN configuration Solicit"); - cur->ws_info->pas_requests++; - ws_bootstrap_pan_config_solicit(cur); } if (cur->ws_info->trickle_pa_running && trickle_timer(&cur->ws_info->trickle_pan_advertisement, &cur->ws_info->trickle_params_pan_discovery, ticks)) { @@ -2943,23 +3056,4 @@ void ws_secondary_parent_update(protocol_interface_info_entry_t *interface) } } -void ws_bootstrap_etx_accelerate(protocol_interface_info_entry_t *interface, mac_neighbor_table_entry_t *neigh) -{ - ws_neighbor_class_entry_t *ws_neighbor = ws_neighbor_class_entry_get(&interface->ws_info->neighbor_storage, neigh->index); - //Enable Faster ETX probing - ws_neighbor->accelerated_etx_probe = true; - //Move Neighbor to first to for accelerate Process - mac_neighbor_table_t *table_class = mac_neighbor_info(interface); - ns_list_remove(&table_class->neighbour_list, neigh); - ns_list_add_to_start(&table_class->neighbour_list, neigh); - //Try to Generate Active NUD Immediately - if (!ws_neighbor_entry_nud_notify(neigh, interface)) { - return;//Return if NUD active is full - } - table_class->active_nud_process++; - neigh->nud_active = true; - //Push NS to send - ws_nud_active_timer(interface, 0); -} - #endif //HAVE_WS diff --git a/source/6LoWPAN/ws/ws_bootstrap.h b/source/6LoWPAN/ws/ws_bootstrap.h index 9d7f5524659..062dc767a3b 100644 --- a/source/6LoWPAN/ws/ws_bootstrap.h +++ b/source/6LoWPAN/ws/ws_bootstrap.h @@ -76,8 +76,6 @@ 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_etx_accelerate(struct protocol_interface_info_entry *cur, mac_neighbor_table_entry_t *neigh); - #else #define ws_bootstrap_init(interface_id, bootstrap_mode) (-1) @@ -87,7 +85,6 @@ void ws_bootstrap_etx_accelerate(struct protocol_interface_info_entry *cur, mac_ #define ws_bootstrap_aro_failure(cur, ll_address) #define ws_primary_parent_update(interface, neighbor) #define ws_secondary_parent_update(interface) -#define ws_bootstrap_etx_accelerate(cur, neigh) ((void) 0) #endif //HAVE_WS diff --git a/source/6LoWPAN/ws/ws_common.c b/source/6LoWPAN/ws/ws_common.c index 449a4d8e0d8..f89fbaa7483 100644 --- a/source/6LoWPAN/ws/ws_common.c +++ b/source/6LoWPAN/ws/ws_common.c @@ -22,6 +22,7 @@ #include "randLIB.h" #include #include +#include "Common_Protocols/icmpv6.h" #include "6LoWPAN/ws/ws_config.h" #include "6LoWPAN/ws/ws_common_defines.h" #include "6LoWPAN/ws/ws_common.h" @@ -316,6 +317,9 @@ int8_t ws_common_allocate_and_init(protocol_interface_info_entry_t *cur) cur->ws_info->fhss_bc_dwell_interval = WS_FHSS_BC_DWELL_INTERVAL; cur->ws_info->fhss_uc_channel_function = WS_DH1CF; cur->ws_info->fhss_bc_channel_function = WS_DH1CF; + + cur->ws_info->pending_key_index_info.state = NO_PENDING_PROCESS; + for (uint8_t n = 0; n < 8; n++) { cur->ws_info->fhss_channel_mask[n] = 0xffffffff; } @@ -335,11 +339,11 @@ void ws_common_network_size_configure(protocol_interface_info_entry_t *cur, uint // doublings:3 (128s) // redundancy; 0 Disabled if (cur->ws_info->network_size_config == NETWORK_SIZE_AUTOMATIC) { - ws_bbr_rpl_config(14, 3, 0, WS_RPL_MAX_HOP_RANK_INCREASE, WS_RPL_MIN_HOP_RANK_INCREASE); + ws_bbr_rpl_config(cur, 14, 3, 0, WS_RPL_MAX_HOP_RANK_INCREASE, WS_RPL_MIN_HOP_RANK_INCREASE); } else if (cur->ws_info->network_size_config == NETWORK_SIZE_CERTIFICATE) { - ws_bbr_rpl_config(0, 0, 0, WS_CERTIFICATE_RPL_MAX_HOP_RANK_INCREASE, WS_CERTIFICATE_RPL_MIN_HOP_RANK_INCREASE); + ws_bbr_rpl_config(cur, 0, 0, 0, WS_CERTIFICATE_RPL_MAX_HOP_RANK_INCREASE, WS_CERTIFICATE_RPL_MIN_HOP_RANK_INCREASE); } else { - ws_bbr_rpl_config(0, 0, 0, WS_RPL_MAX_HOP_RANK_INCREASE, WS_RPL_MIN_HOP_RANK_INCREASE); + ws_bbr_rpl_config(cur, 0, 0, 0, WS_RPL_MAX_HOP_RANK_INCREASE, WS_RPL_MIN_HOP_RANK_INCREASE); } ws_pae_controller_timing_adjust(1); // Fast and reactive network } else if (network_size < 300) { @@ -349,7 +353,7 @@ void ws_common_network_size_configure(protocol_interface_info_entry_t *cur, uint // imin: 15 (32s) // doublings:5 (960s) // redundancy; 10 - ws_bbr_rpl_config(15, 5, 10, WS_RPL_MAX_HOP_RANK_INCREASE, WS_RPL_MIN_HOP_RANK_INCREASE); + ws_bbr_rpl_config(cur, 15, 5, 10, WS_RPL_MAX_HOP_RANK_INCREASE, WS_RPL_MIN_HOP_RANK_INCREASE); ws_pae_controller_timing_adjust(9); // medium limited network } else { // Configure the Wi-SUN discovery trickle parameters @@ -358,7 +362,7 @@ void ws_common_network_size_configure(protocol_interface_info_entry_t *cur, uint // imin: 19 (524s, 9 min) // doublings:1 (1048s, 17 min) // redundancy; 10 May need some tuning still - ws_bbr_rpl_config(19, 1, 10, WS_RPL_MAX_HOP_RANK_INCREASE, WS_RPL_MIN_HOP_RANK_INCREASE); + ws_bbr_rpl_config(cur, 19, 1, 10, WS_RPL_MAX_HOP_RANK_INCREASE, WS_RPL_MIN_HOP_RANK_INCREASE); ws_pae_controller_timing_adjust(24); // Very slow and high latency network } return; @@ -387,12 +391,10 @@ void ws_common_neighbor_update(protocol_interface_info_entry_t *cur, const uint8 } } -void ws_common_aro_failure(protocol_interface_info_entry_t *cur, const uint8_t *ll_address, bool cache_full) +void ws_common_aro_failure(protocol_interface_info_entry_t *cur, const uint8_t *ll_address) { tr_warn("ARO registration Failure %s", trace_ipv6(ll_address)); - if (cache_full) { - blacklist_update(ll_address, false); - } + blacklist_update(ll_address, false); ws_bootstrap_aro_failure(cur, ll_address); } @@ -404,7 +406,7 @@ void ws_common_neighbor_remove(protocol_interface_info_entry_t *cur, const uint8 -bool ws_common_allow_child_registration(protocol_interface_info_entry_t *interface, const uint8_t *eui64) +uint8_t ws_common_allow_child_registration(protocol_interface_info_entry_t *interface, const uint8_t *eui64) { uint8_t child_count = 0; uint8_t max_child_count = mac_neighbor_info(interface)->list_total_size - WS_NON_CHILD_NEIGHBOUR_COUNT; @@ -417,13 +419,13 @@ bool ws_common_allow_child_registration(protocol_interface_info_entry_t *interfa //Validate Is EUI64 already allocated for any address if (ipv6_neighbour_has_registered_by_eui64(&interface->ipv6_neighbour_cache, eui64)) { tr_info("Child registration from old child"); - return true; + return ARO_SUCCESS; } //Verify that we have Selected Parent if (interface->bootsrap_mode != ARM_NWK_BOOTSRAP_MODE_6LoWPAN_BORDER_ROUTER && !rpl_control_parent_candidate_list_size(interface, true)) { tr_info("Do not accept new ARO child: no selected parent"); - return false; + return ARO_TOPOLOGICALLY_INCORRECT; } @@ -435,10 +437,10 @@ bool ws_common_allow_child_registration(protocol_interface_info_entry_t *interfa } if (child_count >= max_child_count) { tr_warn("Child registration not allowed %d/%d, max:%d", child_count, max_child_count, mac_neighbor_info(interface)->list_total_size); - return false; + return ARO_FULL; } tr_info("Child registration allowed %d/%d, max:%d", child_count, max_child_count, mac_neighbor_info(interface)->list_total_size); - return true; + return ARO_SUCCESS; } bool ws_common_negative_aro_mark(protocol_interface_info_entry_t *interface, const uint8_t *eui64) @@ -447,23 +449,13 @@ bool ws_common_negative_aro_mark(protocol_interface_info_entry_t *interface, con if (!neighbour) { return false; } + ws_neighbor_class_entry_t *ws_neighbor = ws_neighbor_class_entry_get(&interface->ws_info->neighbor_storage, neighbour->index); ws_neighbor->negative_aro_send = true; neighbour->lifetime = WS_NEIGHBOR_TEMPORARY_LINK_MIN_TIMEOUT_SMALL; //Remove anyway if Packet is freed before MAC push return true; } -void ws_common_etx_validate(protocol_interface_info_entry_t *interface, mac_neighbor_table_entry_t *neigh) -{ - etx_storage_t *etx_entry = etx_storage_entry_get(interface->id, neigh->index); - - if (neigh->nud_active || !neigh->trusted_device || !etx_entry || etx_entry->etx_samples) { - return; //Do not trig Second NS if Active NUD already, not trusted or ETX samples already done - } - - ws_bootstrap_etx_accelerate(interface, neigh); -} - uint32_t ws_common_version_lifetime_get(uint8_t config) { uint32_t lifetime; diff --git a/source/6LoWPAN/ws/ws_common.h b/source/6LoWPAN/ws/ws_common.h index a901d08b27d..588902753ff 100644 --- a/source/6LoWPAN/ws/ws_common.h +++ b/source/6LoWPAN/ws/ws_common.h @@ -60,6 +60,15 @@ typedef struct ws_nud_table_entry { ns_list_link_t link; } ws_nud_table_entry_t; +#define NO_PENDING_PROCESS 0 +#define PENDING_KEY_INDEX_ADVERTISMENT 1 +#define PENDING_KEY_INDEX_ACTIVATE 2 + +typedef struct { + unsigned state: 2; + uint8_t index; +} ws_pending_key_index_t; + typedef NS_LIST_HEAD(ws_nud_table_entry_t, link) ws_nud_table_list_t; typedef struct ws_info_s { @@ -79,15 +88,17 @@ typedef struct ws_info_s { parent_info_t parent_info[WS_PARENT_LIST_SIZE]; parent_info_list_t parent_list_free; parent_info_list_t parent_list_reserved; - uint32_t pan_version_timer; /**< border router version udate timeout */ + uint16_t rpl_version_timer; /**< RPL version update timeout */ + uint32_t pan_version_timer; /**< border router version update timeout */ uint32_t pan_version_timeout_timer; /**< routers will fallback to previous state after this */ + uint32_t pan_config_sol_max_timeout; uint8_t gtkhash[32]; bool configuration_learned: 1; bool trickle_pas_running: 1; bool trickle_pa_running: 1; bool trickle_pcs_running: 1; bool trickle_pc_running: 1; - bool fhss_owner: 1; + ws_pending_key_index_t pending_key_index_info; // default fhss parameters for this device uint8_t fhss_uc_dwell_interval; uint8_t fhss_bc_dwell_interval; @@ -126,13 +137,11 @@ void ws_common_fast_timer(protocol_interface_info_entry_t *cur, uint16_t ticks); void ws_common_neighbor_update(protocol_interface_info_entry_t *cur, const uint8_t *ll_address); -void ws_common_aro_failure(protocol_interface_info_entry_t *cur, const uint8_t *ll_address, bool cache_full); +void ws_common_aro_failure(protocol_interface_info_entry_t *cur, const uint8_t *ll_address); void ws_common_neighbor_remove(protocol_interface_info_entry_t *cur, const uint8_t *ll_address); -bool ws_common_allow_child_registration(protocol_interface_info_entry_t *cur, const uint8_t *eui64); - -void ws_common_etx_validate(protocol_interface_info_entry_t *interface, mac_neighbor_table_entry_t *neigh); +uint8_t ws_common_allow_child_registration(protocol_interface_info_entry_t *cur, const uint8_t *eui64); bool ws_common_negative_aro_mark(protocol_interface_info_entry_t *interface, const uint8_t *eui64); @@ -146,11 +155,10 @@ uint32_t ws_common_version_timeout_get(uint8_t config); #define ws_info(cur) ((ws_info_t *) NULL) #define ws_common_seconds_timer(cur, seconds) #define ws_common_neighbor_update(cur, ll_address) ((void) 0) -#define ws_common_aro_failure(cur, ll_address, cache_full) +#define ws_common_aro_failure(cur, ll_address) #define ws_common_neighbor_remove(cur, ll_address) #define ws_common_fast_timer(cur, ticks) ((void) 0) -#define ws_common_allow_child_registration(cur, eui64) (false) -#define ws_common_etx_validate(interface, neigh) ((void) 0) +#define ws_common_allow_child_registration(cur, eui64) (2) #define ws_common_negative_aro_mark(interface, eui64)(false) #endif //HAVE_WS diff --git a/source/6LoWPAN/ws/ws_common_defines.h b/source/6LoWPAN/ws/ws_common_defines.h index f9f07fe7011..92f7da38eb4 100644 --- a/source/6LoWPAN/ws/ws_common_defines.h +++ b/source/6LoWPAN/ws/ws_common_defines.h @@ -190,7 +190,8 @@ typedef struct ws_bs_ie { #define WS_NEIGHBOR_TEMPORARY_LINK_MIN_TIMEOUT_SMALL 260 #define WS_NEIGHBOR_NUD_TIMEOUT WS_NEIGHBOR_LINK_TIMEOUT / 2 -#define WS_NEIGBOR_ETX_SAMPLE_MAX 3 +#define WS_NEIGHBOR_ETX_SAMPLE_MAX 3 +#define WS_NEIGHBOR_FIRST_ETX_SAMPLE_MIN_COUNT 3 //This can't be bigger than WS_NEIGHBOR_ETX_SAMPLE_MAX #define WS_NEIGHBOUR_MAX_CANDIDATE_PROBE 5 #define WS_PROBE_INIT_BASE_SECONDS 8 @@ -204,6 +205,7 @@ typedef struct ws_bs_ie { #define WS_ETX_MIN_SAMPLE_COUNT 4 #define WS_ETX_MAX_UPDATE 1024 +#define WS_ETX_MAX 1024 #define WS_ETX_MIN_WAIT_TIME 60 @@ -211,7 +213,7 @@ typedef struct ws_bs_ie { #define WS_RPL_SELECTED_PARENT_MAX 2 #define WS_CERTIFICATE_RPL_PARENT_CANDIDATE_MAX 8 -#define WS_CERTIFICATE_RPL_SELECTED_PARENT_MAX 3 +#define WS_CERTIFICATE_RPL_SELECTED_PARENT_MAX 4 /** * Wi-sun spesific non-preferred prefix policy label diff --git a/source/6LoWPAN/ws/ws_config.h b/source/6LoWPAN/ws/ws_config.h index 9ff0007021b..e7afc90d982 100644 --- a/source/6LoWPAN/ws/ws_config.h +++ b/source/6LoWPAN/ws/ws_config.h @@ -46,7 +46,10 @@ #define PAN_VERSION_MEDIUM_NETWORK_LIFETIME 15*60 #define PAN_VERSION_LARGE_NETWORK_LIFETIME 30*60 //30min -#define RPL_VERSION_LIFETIME 5*3600 +// RPL version number update intervall +// after restart version numbers are increased faster and then slowed down when network is stable +#define RPL_VERSION_LIFETIME 12*3600 +#define RPL_VERSION_LIFETIME_RESTART 3600 /* Border router connection lost timeout * @@ -100,7 +103,7 @@ extern uint8_t DEVICE_MIN_SENS; #define DATA_MESSAGE_IMIN (10 * 1000) #define DATA_MESSAGE_TIMER_EXPIRATIONS 3 -#define DATA_MESSAGE_IMAX (DATA_MESSAGE_IMIN) +#define DATA_MESSAGE_IMAX (80 * 1000) #define MPL_SEED_SET_ENTRY_TIMEOUT (DATA_MESSAGE_IMAX * 24 * 4 / 1000) // 10 seconds per hop making this 240 seconds /* DHCP client timeout configuration values @@ -145,7 +148,11 @@ extern uint8_t DEVICE_MIN_SENS; */ #define WS_MAX_DAO_RETRIES 3 // With 40s, 80s, 160s, 320s, 640s #define WS_MAX_DAO_INITIAL_TIMEOUT 400 // With 40s initial value exponentially increasing -#define WS_MIN_DIO_MULTICAST_CONFIG_ADVERTISMENT_COUNT 10 // Define 10 multicast advertisment when learn config or learn config update +#define WS_MIN_DIO_MULTICAST_CONFIG_ADVERTISMENT_COUNT 0xff // Advertisment config at every MC DIO +#define WS_MAX_PARENT_SET_COUNT 2 // maximum amount of parents selected by node + +#define WS_NODE_RPL_SOFT_MEM_LIMIT 4*1024 // Limit when RPL start purge unused data +#define WS_NODE_RPL_HARD_MEM_LIMIT 6*1024 // Limit when RPL memory allocation start limit allocation /* * Candidate parent list parameters diff --git a/source/6LoWPAN/ws/ws_llc_data_service.c b/source/6LoWPAN/ws/ws_llc_data_service.c index 00523518eb0..9e94dbbe4cb 100644 --- a/source/6LoWPAN/ws/ws_llc_data_service.c +++ b/source/6LoWPAN/ws/ws_llc_data_service.c @@ -560,7 +560,7 @@ static void ws_llc_mac_indication_cb(const mac_api_t *api, const mcps_data_ind_t if (!base->ws_neighbor_info_request_cb(interface, data->SrcAddr, &neighbor_info, request_new_entry)) { if (!multicast || ws_utt.message_type == WS_FT_EAPOL) { - tr_debug("Drop message no neighbor"); + //tr_debug("Drop message no neighbor"); return; } else { //Allocate temporary entry diff --git a/source/6LoWPAN/ws/ws_management_api.c b/source/6LoWPAN/ws/ws_management_api.c index e8be8dac519..63f7322326a 100644 --- a/source/6LoWPAN/ws/ws_management_api.c +++ b/source/6LoWPAN/ws/ws_management_api.c @@ -220,20 +220,32 @@ int ws_management_fhss_timing_configure( if (!cur || !ws_info(cur)) { return -1; } - if (fhss_uc_dwell_interval > 0) { + + if (fhss_uc_dwell_interval && fhss_uc_dwell_interval < 15) { + return -2; + } + + if (fhss_bc_dwell_interval && fhss_bc_dwell_interval < 15) { + return -2; + } + + bool updated_configure = false; + + if (fhss_uc_dwell_interval > 0 && cur->ws_info->fhss_uc_dwell_interval != fhss_uc_dwell_interval) { cur->ws_info->fhss_uc_dwell_interval = fhss_uc_dwell_interval; + updated_configure = true; } - if (fhss_broadcast_interval > 0) { + if (fhss_broadcast_interval > 0 && cur->ws_info->fhss_bc_interval != fhss_broadcast_interval) { cur->ws_info->fhss_bc_interval = fhss_broadcast_interval; - + updated_configure = true; } - if (fhss_bc_dwell_interval > 0) { + if (fhss_bc_dwell_interval > 0 && cur->ws_info->fhss_bc_dwell_interval != fhss_bc_dwell_interval) { cur->ws_info->fhss_bc_dwell_interval = fhss_bc_dwell_interval; - + updated_configure = true; } // if settings change reset_restart for the settings needed - if (cur->lowpan_info & INTERFACE_NWK_ACTIVE) { + if (updated_configure && (cur->lowpan_info & INTERFACE_NWK_ACTIVE)) { // bootstrap active need to restart ws_bootstrap_restart(interface_id); } @@ -259,23 +271,38 @@ int ws_management_fhss_unicast_channel_function_configure( return -2; } + if (dwell_interval && dwell_interval < 15) { + return -2; + } + if (channel_function == WS_FIXED_CHANNEL && fixed_channel == 0xffff) { fixed_channel = 0; tr_warn("Fixed channel not configured. Set to 0"); } + bool updated_config = false; + + if (cur->ws_info->fhss_uc_channel_function != channel_function) { + cur->ws_info->fhss_uc_channel_function = channel_function; + updated_config = true; + } - cur->ws_info->fhss_uc_channel_function = channel_function; if (cur->ws_info->fhss_uc_channel_function == WS_FIXED_CHANNEL) { - cur->ws_info->fhss_uc_fixed_channel = fixed_channel; + if (cur->ws_info->fhss_uc_fixed_channel != fixed_channel) { + cur->ws_info->fhss_uc_fixed_channel = fixed_channel; + updated_config = true; + } } else { cur->ws_info->fhss_uc_fixed_channel = 0xffff; } - cur->ws_info->fhss_uc_dwell_interval = dwell_interval; + if (dwell_interval && cur->ws_info->fhss_uc_dwell_interval != dwell_interval) { + cur->ws_info->fhss_uc_dwell_interval = dwell_interval; + updated_config = true; + } // if settings change reset_restart for the settings needed - if (cur->lowpan_info & INTERFACE_NWK_ACTIVE) { + if (updated_config && (cur->lowpan_info & INTERFACE_NWK_ACTIVE)) { // bootstrap active need to restart ws_bootstrap_restart(interface_id); } @@ -303,23 +330,43 @@ int ws_management_fhss_broadcast_channel_function_configure( return -2; } + if (dwell_interval && dwell_interval < 15) { + return -2; + } + if (channel_function == WS_FIXED_CHANNEL && fixed_channel == 0xffff) { fixed_channel = 0; tr_warn("Fixed channel not configured. Set to 0"); } - cur->ws_info->fhss_bc_channel_function = channel_function; + bool updated_config = false; + + if (cur->ws_info->fhss_bc_channel_function != channel_function) { + cur->ws_info->fhss_bc_channel_function = channel_function; + updated_config = true; + } + if (cur->ws_info->fhss_bc_channel_function == WS_FIXED_CHANNEL) { - cur->ws_info->fhss_bc_fixed_channel = fixed_channel; + if (cur->ws_info->fhss_bc_fixed_channel != fixed_channel) { + cur->ws_info->fhss_bc_fixed_channel = fixed_channel; + updated_config = true; + } } else { cur->ws_info->fhss_bc_fixed_channel = 0xffff; } - cur->ws_info->fhss_bc_dwell_interval = dwell_interval; - cur->ws_info->fhss_bc_interval = broadcast_interval; + if (dwell_interval > 0 && cur->ws_info->fhss_bc_dwell_interval != dwell_interval) { + cur->ws_info->fhss_bc_dwell_interval = dwell_interval; + updated_config = true; + } + + if (broadcast_interval > 0 && cur->ws_info->fhss_bc_interval != broadcast_interval) { + cur->ws_info->fhss_bc_interval = broadcast_interval; + updated_config = true; + } // if settings change reset_restart for the settings needed - if (cur->lowpan_info & INTERFACE_NWK_ACTIVE) { + if (updated_config && (cur->lowpan_info & INTERFACE_NWK_ACTIVE)) { // bootstrap active need to restart ws_bootstrap_restart(interface_id); } diff --git a/source/6LoWPAN/ws/ws_neighbor_class.h b/source/6LoWPAN/ws/ws_neighbor_class.h index 2a0cbe2c122..c381b43f50e 100644 --- a/source/6LoWPAN/ws/ws_neighbor_class.h +++ b/source/6LoWPAN/ws/ws_neighbor_class.h @@ -32,7 +32,6 @@ typedef struct ws_neighbor_class_entry { bool broadcast_timing_info_stored: 1; bool broadcast_shedule_info_stored: 1; bool synch_done : 1; - bool accelerated_etx_probe : 1; bool negative_aro_send : 1; bool unicast_data_rx : 1; } ws_neighbor_class_entry_t; diff --git a/source/6LoWPAN/ws/ws_pae_auth.c b/source/6LoWPAN/ws/ws_pae_auth.c index aeac1065314..01ffea56039 100644 --- a/source/6LoWPAN/ws/ws_pae_auth.c +++ b/source/6LoWPAN/ws/ws_pae_auth.c @@ -70,6 +70,9 @@ nanostack monitor */ #define SUPPLICANT_NUMBER_TO_PURGE 5 +// Short GTK lifetime value, for GTK install check +#define SHORT_GTK_LIFETIME 10 * 3600 // 10 hours + typedef struct { ns_list_link_t link; /**< Link */ kmp_service_t *kmp_service; /**< KMP service */ @@ -113,7 +116,7 @@ static void ws_pae_auth_kmp_api_create_confirm(kmp_api_t *kmp, kmp_result_e resu static void ws_pae_auth_kmp_api_create_indication(kmp_api_t *kmp, kmp_type_e type, kmp_addr_t *addr); static void ws_pae_auth_kmp_api_finished_indication(kmp_api_t *kmp, kmp_result_e result, kmp_sec_keys_t *sec_keys); static void ws_pae_auth_next_kmp_trigger(pae_auth_t *pae_auth, supp_entry_t *supp_entry); -static kmp_type_e ws_pae_auth_next_protocol_get(supp_entry_t *supp_entry); +static kmp_type_e ws_pae_auth_next_protocol_get(pae_auth_t *pae_auth, supp_entry_t *supp_entry); static kmp_api_t *ws_pae_auth_kmp_create_and_start(kmp_service_t *service, kmp_type_e type, supp_entry_t *supp_entry); static void ws_pae_auth_kmp_api_finished(kmp_api_t *kmp); @@ -666,7 +669,9 @@ static void ws_pae_auth_gtk_key_insert(pae_auth_t *pae_auth) sec_prot_keys_gtk_clear(pae_auth->next_gtks, next_gtk_index); sec_prot_keys_gtk_set(pae_auth->next_gtks, next_gtk_index, gtk_value, 0); } else { - randLIB_get_n_bytes_random(gtk_value, GTK_LEN); + do { + randLIB_get_n_bytes_random(gtk_value, GTK_LEN); + } while (sec_prot_keys_gtk_valid_check(gtk_value) < 0); } // Gets latest installed key lifetime and adds GTK expire offset to it @@ -910,7 +915,7 @@ static void ws_pae_auth_next_kmp_trigger(pae_auth_t *pae_auth, supp_entry_t *sup supp_entry->retry_ticks = 0; // Get next protocol based on what keys supplicant has - kmp_type_e next_type = ws_pae_auth_next_protocol_get(supp_entry); + kmp_type_e next_type = ws_pae_auth_next_protocol_get(pae_auth, supp_entry); if (next_type == KMP_TYPE_NONE) { // All done @@ -969,7 +974,7 @@ static void ws_pae_auth_next_kmp_trigger(pae_auth_t *pae_auth, supp_entry_t *sup kmp_api_create_request(new_kmp, next_type, &supp_entry->addr, &supp_entry->sec_keys); } -static kmp_type_e ws_pae_auth_next_protocol_get(supp_entry_t *supp_entry) +static kmp_type_e ws_pae_auth_next_protocol_get(pae_auth_t *pae_auth, supp_entry_t *supp_entry) { kmp_type_e next_type = KMP_TYPE_NONE; sec_prot_keys_t *sec_keys = &supp_entry->sec_keys; @@ -999,9 +1004,22 @@ static kmp_type_e ws_pae_auth_next_protocol_get(supp_entry_t *supp_entry) if (gtk_index >= 0) { if (next_type == KMP_TYPE_NONE && gtk_index >= 0) { - // Update just GTK - next_type = IEEE_802_11_GKH; - tr_info("PAE start GKH, eui-64: %s", trace_array(supp_entry->addr.eui_64, 8)); + + /* Check if the PTK has been already used to install GTK to specific index and if it + * has been, trigger 4WH to update also the PTK. This prevents writing multiple + * GTK keys to same index using same PTK. + */ + if (pae_auth->timer_settings->gtk_expire_offset > SHORT_GTK_LIFETIME && + sec_prot_keys_ptk_installed_gtk_hash_mismatch_check(sec_keys, gtk_index)) { + // start 4WH towards supplicant + next_type = IEEE_802_11_4WH; + sec_keys->ptk_mismatch = true; + tr_info("PAE start 4WH due to GTK index re-use, eui-64: %s", trace_array(supp_entry->addr.eui_64, 8)); + } else { + // Update just GTK + next_type = IEEE_802_11_GKH; + tr_info("PAE start GKH, eui-64: %s", trace_array(supp_entry->addr.eui_64, 8)); + } } tr_info("PAE update GTK index: %i, eui-64: %s", gtk_index, trace_array(supp_entry->addr.eui_64, 8)); diff --git a/source/6LoWPAN/ws/ws_pae_auth.h b/source/6LoWPAN/ws/ws_pae_auth.h index 5c0f35d9609..04bd157d789 100644 --- a/source/6LoWPAN/ws/ws_pae_auth.h +++ b/source/6LoWPAN/ws/ws_pae_auth.h @@ -232,7 +232,7 @@ void ws_pae_auth_cb_register(protocol_interface_info_entry_t *interface_ptr, ws_ #else #define ws_pae_auth_init(interface_ptr, gtks, next_gtks, certs, timer_settings) 1 -#define ws_pae_auth_timing_adjust(timing) 1 +#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) {(void) hash_set;} diff --git a/source/6LoWPAN/ws/ws_pae_controller.c b/source/6LoWPAN/ws/ws_pae_controller.c index 6db0877be7f..f5bc4dba922 100644 --- a/source/6LoWPAN/ws/ws_pae_controller.c +++ b/source/6LoWPAN/ws/ws_pae_controller.c @@ -88,6 +88,7 @@ typedef struct { bool gtks_set : 1; /**< GTKs are set */ bool gtkhash_set : 1; /**< GTK hashes are set */ bool key_index_set : 1; /**< NW key index is set */ + bool frame_counter_read : 1; /**< Frame counters has been read */ } pae_controller_t; typedef struct { @@ -108,6 +109,7 @@ static int8_t ws_pae_controller_nw_key_check_and_insert(protocol_interface_info_ static void ws_pae_controller_active_nw_key_clear(nw_key_t *nw_key); static void ws_pae_controller_active_nw_key_set(protocol_interface_info_entry_t *cur, uint8_t index); 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); static void ws_pae_controller_nw_key_index_check_and_set(protocol_interface_info_entry_t *interface_ptr, uint8_t index); static void ws_pae_controller_data_init(pae_controller_t *controller); static void ws_pae_controller_frame_counter_read(pae_controller_t *controller); @@ -363,12 +365,16 @@ static int8_t ws_pae_controller_nw_key_check_and_insert(protocol_interface_info_ if (ws_pae_controller_gak_from_gtk(gak, gtk, controller->network_name) >= 0) { // Install the new network key derived from GTK and network name (GAK) to MAC controller->nw_key_set(interface_ptr, i, i, gak); - tr_info("NW: %s", controller->network_name); - tr_info("NW: %s", trace_array((uint8_t *)controller->network_name, 20)); - tr_info("GTK: %s", trace_array(gtk, 16)); - tr_info("GAK: %s", trace_array(gak, 16)); nw_key[i].installed = true; ret = 0; +#ifdef EXTRA_DEBUG_INFO + tr_info("NW name: %s", controller->network_name); + size_t nw_name_len = strlen(controller->network_name); + tr_info("NW name: %s", trace_array((uint8_t *)controller->network_name, nw_name_len)); + tr_info("GTK: %s", trace_array(gtk, 16)); + tr_info("GAK: %s", trace_array(gak, 16)); +#endif + } else { tr_error("GAK generation failed network name: %s", controller->network_name); continue; @@ -380,9 +386,11 @@ static int8_t ws_pae_controller_nw_key_check_and_insert(protocol_interface_info_ // Read current counter from MAC uint32_t curr_frame_counter; controller->nw_frame_counter_read(controller->interface_ptr, &curr_frame_counter, i); + // If stored frame counter is greater than MAC counter if (controller->frame_counters.counter[i].frame_counter > curr_frame_counter) { - tr_debug("Frame counter set: %i, stored %"PRIu32" current: %"PRIu32"", i, controller->frame_counters.counter[i].frame_counter, curr_frame_counter); + tr_debug("Frame counter set: %i, stored %"PRIu32" current: %"PRIu32"", i, + controller->frame_counters.counter[i].frame_counter, curr_frame_counter); curr_frame_counter = controller->frame_counters.counter[i].frame_counter; // Updates MAC frame counter controller->nw_frame_counter_set(controller->interface_ptr, curr_frame_counter, i); @@ -474,6 +482,16 @@ void ws_pae_controller_nw_keys_remove(protocol_interface_info_entry_t *interface return; } + /* Stores frame counters if incremented by threshold and removes network keys from PAE + controller and MAC */ + ws_pae_controller_frame_counter_store_and_nw_keys_remove(interface_ptr, controller, true); +} + +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) +{ + /* Checks if frame counters needs to be stored when keys are removed */ + ws_pae_controller_frame_counter_store(controller, use_threshold); + tr_info("NW keys remove"); nw_key_t *nw_key = controller->nw_key; @@ -589,6 +607,7 @@ static void ws_pae_controller_data_init(pae_controller_t *controller) controller->gtks_set = false; controller->gtkhash_set = false; controller->key_index_set = false; + controller->frame_counter_read = false; controller->gtk_index = -1; controller->network_name = NULL; controller->frame_cnt_store_timer = FRAME_COUNTER_STORE_INTERVAL; @@ -602,6 +621,11 @@ static void ws_pae_controller_data_init(pae_controller_t *controller) static void ws_pae_controller_frame_counter_read(pae_controller_t *controller) { + if (controller->frame_counter_read) { + return; + } + controller->frame_counter_read = true; + // Read frame counters if (ws_pae_controller_nvm_frame_counter_read(&controller->frame_counters) >= 0) { bool updated = false; @@ -610,6 +634,8 @@ static void ws_pae_controller_frame_counter_read(pae_controller_t *controller) if (controller->frame_counters.counter[index].set) { // Increments frame counters controller->frame_counters.counter[index].frame_counter += FRAME_COUNTER_INCREMENT; + controller->frame_counters.counter[index].stored_frame_counter = + controller->frame_counters.counter[index].frame_counter; tr_info("Read frame counter: index %i value %"PRIu32"", index, controller->frame_counters.counter[index].frame_counter); @@ -620,7 +646,6 @@ static void ws_pae_controller_frame_counter_read(pae_controller_t *controller) // Writes incremented frame counters ws_pae_nvm_store_frame_counter_tlv_create(controller->pae_nvm_buffer, &controller->frame_counters); ws_pae_controller_nvm_frame_counter_write(controller->pae_nvm_buffer); - //ws_pae_controller_frame_counter_write(controller, &controller->frame_counters); } } } @@ -630,6 +655,7 @@ static void ws_pae_controller_frame_counter_reset(frame_counters_t *frame_counte for (uint8_t index = 0; index < GTK_NUM; index++) { memset(frame_counters->counter[index].gtk, 0, GTK_LEN); frame_counters->counter[index].frame_counter = 0; + frame_counters->counter[index].stored_frame_counter = 0; frame_counters->counter[index].set = false; } } @@ -653,7 +679,7 @@ int8_t ws_pae_controller_supp_init(protocol_interface_info_entry_t *interface_pt controller->pae_gtk_hash_update = ws_pae_supp_gtk_hash_update; controller->pae_nw_key_index_update = ws_pae_supp_nw_key_index_update; - ws_pae_supp_cb_register(controller->interface_ptr, controller->auth_completed, ws_pae_controller_nw_key_check_and_insert, ws_pae_controller_active_nw_key_set); + ws_pae_supp_cb_register(controller->interface_ptr, controller->auth_completed, ws_pae_controller_nw_key_check_and_insert, ws_pae_controller_active_nw_key_set, ws_pae_controller_gtk_hash_ptr_get); ws_pae_controller_frame_counter_read(controller); @@ -689,11 +715,8 @@ int8_t ws_pae_controller_stop(protocol_interface_info_entry_t *interface_ptr) return -1; } - // Stores frame counter - ws_pae_controller_frame_counter_store(controller, false); - - // Removes network keys from PAE controller and MAC - ws_pae_controller_nw_keys_remove(interface_ptr); + // Stores frame counters and removes network keys from PAE controller and MAC + ws_pae_controller_frame_counter_store_and_nw_keys_remove(interface_ptr, controller, false); // If PAE has been initialized, deletes it if (controller->pae_delete) { @@ -1180,7 +1203,7 @@ int8_t ws_pae_controller_gtk_hash_update(protocol_interface_info_entry_t *interf memcpy(controller->gtkhash, gtkhash, 32); if (controller->pae_gtk_hash_update) { - return controller->pae_gtk_hash_update(interface_ptr, gtkhash); + return controller->pae_gtk_hash_update(interface_ptr, controller->gtkhash); } return 0; @@ -1241,18 +1264,25 @@ static void ws_pae_controller_frame_counter_store(pae_controller_t *entry, bool // If frame counter for the network key has already been stored if (entry->frame_counters.counter[i].set && memcmp(entry->nw_key[i].gtk, entry->frame_counters.counter[i].gtk, GTK_LEN) == 0) { + + if (curr_frame_counter > entry->frame_counters.counter[i].frame_counter) { + entry->frame_counters.counter[i].frame_counter = curr_frame_counter; + } + uint32_t frame_counter = entry->frame_counters.counter[i].frame_counter; + // If threshold check is disabled or frame counter has advanced for the threshold value, stores the new value if (!use_threshold || - curr_frame_counter > entry->frame_counters.counter[i].frame_counter + FRAME_COUNTER_STORE_THRESHOLD) { - entry->frame_counters.counter[i].frame_counter = curr_frame_counter; + frame_counter > entry->frame_counters.counter[i].stored_frame_counter + FRAME_COUNTER_STORE_THRESHOLD) { + entry->frame_counters.counter[i].stored_frame_counter = frame_counter; update_needed = true; - tr_debug("Stored updated frame counter: index %i value %"PRIu32"", i, curr_frame_counter); + tr_debug("Stored updated frame counter: index %i value %"PRIu32"", i, frame_counter); } } else { // For new or modified network keys, stores the frame counter value entry->frame_counters.counter[i].set = true; memcpy(entry->frame_counters.counter[i].gtk, entry->nw_key[i].gtk, GTK_LEN); entry->frame_counters.counter[i].frame_counter = curr_frame_counter; + entry->frame_counters.counter[i].stored_frame_counter = curr_frame_counter; update_needed = true; tr_debug("Stored new frame counter: index %i value %"PRIu32"", i, curr_frame_counter); } diff --git a/source/6LoWPAN/ws/ws_pae_lib.c b/source/6LoWPAN/ws/ws_pae_lib.c index 22d95b8086d..455ba76f64b 100644 --- a/source/6LoWPAN/ws/ws_pae_lib.c +++ b/source/6LoWPAN/ws/ws_pae_lib.c @@ -291,6 +291,20 @@ void ws_pae_lib_supp_timer_ticks_set(supp_entry_t *entry, uint32_t ticks) entry->ticks = ticks; } +void ws_pae_lib_supp_timer_ticks_add(supp_entry_t *entry, uint32_t ticks) +{ + entry->ticks += ticks; +} + +bool ws_pae_lib_supp_timer_is_running(supp_entry_t *entry) +{ + if (entry->ticks == 0) { + return false; + } + + return true; +} + void ws_pae_lib_supp_list_to_active(supp_list_t *active_supp_list, supp_list_t *inactive_supp_list, supp_entry_t *entry) { if (entry->active) { diff --git a/source/6LoWPAN/ws/ws_pae_lib.h b/source/6LoWPAN/ws/ws_pae_lib.h index 90ba1481266..3ee6f10d0f3 100644 --- a/source/6LoWPAN/ws/ws_pae_lib.h +++ b/source/6LoWPAN/ws/ws_pae_lib.h @@ -272,6 +272,25 @@ void ws_pae_lib_supp_delete(supp_entry_t *entry); */ void ws_pae_lib_supp_timer_ticks_set(supp_entry_t *entry, uint32_t ticks); +/** + * ws_pae_lib_supp_timer_ticks_add adds supplicant timer ticks + * + * \param entry supplicant entry + * \param ticks ticks + * + */ +void ws_pae_lib_supp_timer_ticks_add(supp_entry_t *entry, uint32_t ticks); + +/** + * ws_pae_lib_supp_timer_is_running checks whether supplicant timer is running + * + * \param entry supplicant entry + * + * \return TRUE timer is running, FALSE timer is not running + * + */ +bool ws_pae_lib_supp_timer_is_running(supp_entry_t *entry); + /** * ws_pae_lib_supp_list_to_active move supplicant to active supplicants list * diff --git a/source/6LoWPAN/ws/ws_pae_nvm_data.c b/source/6LoWPAN/ws/ws_pae_nvm_data.c index d7f2d23861a..7f833430a61 100644 --- a/source/6LoWPAN/ws/ws_pae_nvm_data.c +++ b/source/6LoWPAN/ws/ws_pae_nvm_data.c @@ -57,7 +57,7 @@ nvm_tlv_entry_t *ws_pae_buffer_allocate(void) void ws_pae_nvm_store_nw_info_tlv_create(nvm_tlv_entry_t *tlv_entry, uint16_t pan_id, char *nw_name, sec_prot_gtk_keys_t *gtks) { - + int len; tlv_entry->tag = PAE_NVM_NW_INFO_TAG; tlv_entry->len = PAE_NVM_NW_INFO_LEN; @@ -66,7 +66,13 @@ void ws_pae_nvm_store_nw_info_tlv_create(nvm_tlv_entry_t *tlv_entry, uint16_t pa tlv = common_write_16_bit(pan_id, tlv); memset(tlv, 0, 33); - strncpy((char *)tlv, nw_name, 32); + // use strnlen & memset instead of strncpy to avoid gcc warning: + // call to __builtin___strncpy_chk will always overflow destination buffer [-Werror] + len = strlen(nw_name); + if (len > 32) { + len = 32; + } + memcpy((char *)tlv, nw_name, len); tlv += 33; for (uint8_t i = 0; i < GTK_NUM; i++) { diff --git a/source/6LoWPAN/ws/ws_pae_supp.c b/source/6LoWPAN/ws/ws_pae_supp.c index 452f5993aef..db891dc6e4a 100644 --- a/source/6LoWPAN/ws/ws_pae_supp.c +++ b/source/6LoWPAN/ws/ws_pae_supp.c @@ -66,6 +66,9 @@ // Wait for re-authentication after GTK update #define WAIT_FOR_REAUTHENTICATION_TICKS 120 * 10 // 120 seconds +// Ticks added to wait for authenticator timer when authentication protocol is started (e.g. EAP-TLS) +#define START_AUTHENTICATION_TICKS 5 * 10 // 10 seconds + // How many times in maximum stored keys are used for authentication #define STORED_KEYS_MAXIMUM_USE_COUNT 1 @@ -88,9 +91,11 @@ typedef struct { ws_pae_supp_auth_completed *auth_completed; /**< Authentication completed callback, continue bootstrap */ ws_pae_supp_nw_key_insert *nw_key_insert; /**< Key insert callback */ ws_pae_supp_nw_key_index_set *nw_key_index_set; /**< Key index set callback */ + ws_pae_supp_gtk_hash_ptr_get *gtk_hash_ptr_get; /**< Get pointer to GTK hash storage callback */ supp_entry_t entry; /**< Supplicant data */ kmp_addr_t target_addr; /**< EAPOL target (parent) address */ uint16_t initial_key_timer; /**< Timer to trigger initial EAPOL-Key */ + uint16_t initial_key_retry_timer; /**< Timer to trigger initial EAPOL-Key 1st retry */ trickle_t auth_trickle_timer; /**< Trickle timer for re-sending initial EAPOL-key or for GTK mismatch */ trickle_params_t auth_trickle_params; /**< Trickle parameters for initial EAPOL-key or for GTK mismatch */ sec_prot_gtk_keys_t gtks; /**< GTKs */ @@ -98,6 +103,7 @@ typedef struct { sec_prot_keys_nw_info_t sec_keys_nw_info; /**< Security keys network information */ timer_settings_t *timer_settings; /**< Timer settings */ uint8_t nw_keys_used_cnt; /**< How many times bootstrap has been tried with current keys */ + uint8_t initial_key_retry_cnt; /**< initial EAPOL-Key retry counter */ bool auth_trickle_running : 1; /**< Initial EAPOL-Key Trickle timer running */ bool auth_requested : 1; /**< Authentication has been requested by the bootstrap */ bool timer_running : 1; /**< Timer is running */ @@ -106,14 +112,34 @@ typedef struct { bool entry_address_active: 1; } pae_supp_t; +// How many times sending of initial EAPOL-key is retried +#define INITIAL_KEY_RETRY_COUNT 2 + +// How many times sending of initial EAPOL-key is initiated on key update +#define KEY_UPDATE_RETRY_COUNT 3 +#define LIFETIME_MISMATCH_RETRY_COUNT 1 /* No retries */ + +// How long the wait is before the first initial EAPOL-key retry +#define DEFAULT_INITIAL_KEY_RETRY_TIMER 120 +#define NONE_INITIAL_KEY_RETRY_TIMER 0 + +// Default trickle values for sending of initial EAPOL-key +#define DEFAULT_TRICKLE_IMIN_SECS 360 /* 6 to 12 minutes */ +#define DEFAULT_TRICKLE_IMAX_SECS 720 -#define TRICKLE_IMIN_180_SECS 180 +// Very slow network values for sending of initial EAPOL-key +#define VERY_SLOW_NW_TRICKLE_IMIN_SECS 600 /* 10 to 60 minutes */ +#define VERY_SLOW_NW_TRICKLE_IMAX_SECS 3600 + +// Trickle timer on how long to wait response after last retry before failing authentication +#define LAST_INTERVAL_TRICKLE_IMIN_SECS 240 /* 4 minutes */ +#define LAST_INTERVAL_TRICKLE_IMAX_SECS 240 static trickle_params_t initial_eapol_key_trickle_params = { - .Imin = TRICKLE_IMIN_180_SECS, /* 180 second; ticks are 1 second */ - .Imax = TRICKLE_IMIN_180_SECS << 1, /* 360 second */ - .k = 0, /* infinity - no consistency checking */ - .TimerExpirations = 3 + .Imin = DEFAULT_TRICKLE_IMIN_SECS, /* 360 second; ticks are 1 second */ + .Imax = DEFAULT_TRICKLE_IMAX_SECS, /* 720 second */ + .k = 0, /* infinity - no consistency checking */ + .TimerExpirations = 2 }; static void ws_pae_supp_free(pae_supp_t *pae_supp); @@ -126,6 +152,10 @@ static int8_t ws_pae_supp_nvm_keys_write(pae_supp_t *pae_supp); static pae_supp_t *ws_pae_supp_get(protocol_interface_info_entry_t *interface_ptr); static int8_t ws_pae_supp_event_send(kmp_service_t *service, void *data); static void ws_pae_supp_tasklet_handler(arm_event_s *event); +static void ws_pae_supp_initial_trickle_timer_start(pae_supp_t *pae_supp); +static void ws_pae_supp_initial_last_interval_trickle_timer_start(pae_supp_t *pae_supp); +static void ws_pae_supp_initial_key_update_trickle_timer_start(pae_supp_t *pae_supp, uint8_t timer_expirations); +static bool ws_pae_supp_authentication_ongoing(pae_supp_t *pae_supp); static int8_t ws_pae_supp_timer_if_start(kmp_service_t *service, kmp_api_t *kmp); static int8_t ws_pae_supp_timer_if_stop(kmp_service_t *service, kmp_api_t *kmp); static int8_t ws_pae_supp_timer_start(pae_supp_t *pae_supp); @@ -138,6 +168,7 @@ static kmp_api_t *ws_pae_supp_kmp_tx_status_ind(kmp_service_t *service, uint8_t static kmp_api_t *ws_pae_supp_kmp_create_and_start(kmp_service_t *service, kmp_type_e type, pae_supp_t *pae_supp); static int8_t ws_pae_supp_eapol_pdu_address_check(protocol_interface_info_entry_t *interface_ptr, const uint8_t *eui_64); static int8_t ws_pae_supp_parent_eui_64_get(protocol_interface_info_entry_t *interface_ptr, uint8_t *eui_64); +static int8_t ws_pae_supp_gtk_hash_mismatch_check(pae_supp_t *pae_supp); static void ws_pae_supp_kmp_api_create_confirm(kmp_api_t *kmp, kmp_result_e result); static void ws_pae_supp_kmp_api_create_indication(kmp_api_t *kmp, kmp_type_e type, kmp_addr_t *addr); @@ -156,6 +187,7 @@ static const char *KEYS_FILE = KEYS_FILE_NAME; static int8_t tasklet_id = -1; static NS_LIST_DEFINE(pae_supp_list, pae_supp_t, link); +static uint8_t timing_value = 0; // Timing value set based e.g. on network size static void ws_pae_supp_address_set(pae_supp_t *pae_supp, kmp_addr_t *address) { @@ -291,6 +323,23 @@ int8_t ws_pae_supp_nw_key_valid(protocol_interface_info_entry_t *interface_ptr) return 0; } +static int8_t ws_pae_supp_gtk_hash_mismatch_check(pae_supp_t *pae_supp) +{ + uint8_t *gtkhash = pae_supp->gtk_hash_ptr_get(pae_supp->interface_ptr); + if (!gtkhash) { + return -1; + } + + // Check GTK hashes and initiate EAPOL procedure if mismatch is detected */ + gtk_mismatch_e mismatch = sec_prot_keys_gtks_hash_update(&pae_supp->gtks, gtkhash); + if (mismatch != GTK_NO_MISMATCH) { + return -1; + } + + tr_info("GTKs match to GTK hash"); + return 0; +} + int8_t ws_pae_supp_gtk_hash_update(protocol_interface_info_entry_t *interface_ptr, uint8_t *gtkhash) { pae_supp_t *pae_supp = ws_pae_supp_get(interface_ptr); @@ -307,30 +356,21 @@ int8_t ws_pae_supp_gtk_hash_update(protocol_interface_info_entry_t *interface_pt trace_array(>khash[16], 8), trace_array(>khash[24], 8)); - // Mismatch, initiate EAPOL - if (!pae_supp->auth_trickle_running) { - uint8_t timer_expirations = 3; + /* Mismatch, initiate EAPOL (if authentication not already ongoing or if not on + wait time for the authenticator to answer) */ + if (!pae_supp->auth_trickle_running || pae_supp->initial_key_retry_cnt == 0) { + uint8_t timer_expirations = KEY_UPDATE_RETRY_COUNT; // For GTK lifetime mismatch send only once if (mismatch == GTK_LIFETIME_MISMATCH) { - timer_expirations = 1; + timer_expirations = LIFETIME_MISMATCH_RETRY_COUNT; } - - pae_supp->auth_trickle_params.Imin = pae_supp->timer_settings->gtk_request_imin; - pae_supp->auth_trickle_params.Imax = pae_supp->timer_settings->gtk_request_imax; - pae_supp->auth_trickle_params.k = 0; - pae_supp->auth_trickle_params.TimerExpirations = timer_expirations; - - // Starts trickle - trickle_start(&pae_supp->auth_trickle_timer, &pae_supp->auth_trickle_params); - pae_supp->auth_trickle_running = true; + // Start trickle timer + ws_pae_supp_initial_key_update_trickle_timer_start(pae_supp, timer_expirations); // Starts supplicant timer ws_pae_supp_timer_start(pae_supp); tr_info("GTK update start imin: %i, imax: %i, max mismatch: %i, tr time: %i", pae_supp->timer_settings->gtk_request_imin, pae_supp->timer_settings->gtk_request_imax, pae_supp->timer_settings->gtk_max_mismatch, pae_supp->auth_trickle_timer.t); - } else { - // If trickle is already running, set inconsistent heard to speed up the trickle - trickle_inconsistent_heard(&pae_supp->auth_trickle_timer, &pae_supp->auth_trickle_params); } } @@ -565,7 +605,7 @@ static void ws_pae_supp_keys_nw_info_init(sec_prot_keys_nw_info_t *sec_keys_nw_i sec_keys_nw_info->updated = false; } -void ws_pae_supp_cb_register(protocol_interface_info_entry_t *interface_ptr, ws_pae_supp_auth_completed *completed, ws_pae_supp_nw_key_insert *nw_key_insert, ws_pae_supp_nw_key_index_set *nw_key_index_set) +void ws_pae_supp_cb_register(protocol_interface_info_entry_t *interface_ptr, ws_pae_supp_auth_completed *completed, ws_pae_supp_nw_key_insert *nw_key_insert, ws_pae_supp_nw_key_index_set *nw_key_index_set, ws_pae_supp_gtk_hash_ptr_get *gtk_hash_ptr_get) { pae_supp_t *pae_supp = ws_pae_supp_get(interface_ptr); if (!pae_supp) { @@ -575,6 +615,7 @@ void ws_pae_supp_cb_register(protocol_interface_info_entry_t *interface_ptr, ws_ pae_supp->auth_completed = completed; pae_supp->nw_key_insert = nw_key_insert; pae_supp->nw_key_index_set = nw_key_index_set; + pae_supp->gtk_hash_ptr_get = gtk_hash_ptr_get; } int8_t ws_pae_supp_init(protocol_interface_info_entry_t *interface_ptr, const sec_prot_certs_t *certs, timer_settings_t *timer_settings) @@ -596,9 +637,12 @@ int8_t ws_pae_supp_init(protocol_interface_info_entry_t *interface_ptr, const se pae_supp->auth_completed = NULL; pae_supp->nw_key_insert = NULL; pae_supp->nw_key_index_set = NULL; + pae_supp->gtk_hash_ptr_get = NULL; pae_supp->initial_key_timer = 0; + pae_supp->initial_key_retry_timer = 0; pae_supp->nw_keys_used_cnt = 0; pae_supp->timer_settings = timer_settings; + pae_supp->initial_key_retry_cnt = INITIAL_KEY_RETRY_COUNT; pae_supp->auth_trickle_running = false; pae_supp->auth_requested = false; pae_supp->timer_running = false; @@ -702,6 +746,7 @@ int8_t ws_pae_supp_delete(protocol_interface_info_entry_t *interface_ptr) int8_t ws_pae_supp_timing_adjust(uint8_t timing) { + timing_value = timing; supp_fwh_sec_prot_timing_adjust(timing); supp_eap_sec_prot_timing_adjust(timing); return 0; @@ -801,7 +846,7 @@ void ws_pae_supp_fast_timer(uint16_t ticks) bool running = ws_pae_lib_supp_timer_update(&pae_supp->entry, ticks, kmp_service_timer_if_timeout); // Checks whether timer needs to be active - if (!pae_supp->initial_key_timer && !pae_supp->auth_trickle_running && !running) { + if (!ws_pae_supp_authentication_ongoing(pae_supp) && !running) { tr_debug("PAE idle"); // If not already completed, restart bootstrap ws_pae_supp_authenticate_response(pae_supp, AUTH_RESULT_ERR_UNSPEC); @@ -811,20 +856,69 @@ void ws_pae_supp_fast_timer(uint16_t ticks) } } +static bool ws_pae_supp_authentication_ongoing(pae_supp_t *pae_supp) +{ + /* When either bootstrap initial authentication or re-authentication is ongoing */ + if (pae_supp->initial_key_timer || pae_supp->auth_trickle_running || + ws_pae_lib_supp_timer_is_running(&pae_supp->entry)) { + return true; + } + + return false; +} + void ws_pae_supp_slow_timer(uint16_t seconds) { ns_list_foreach(pae_supp_t, pae_supp, &pae_supp_list) { // Checks whether initial EAPOL-Key message needs to be re-send or new GTK request to be sent if (pae_supp->auth_trickle_running) { - if (trickle_timer(&pae_supp->auth_trickle_timer, &pae_supp->auth_trickle_params, seconds)) { - if (ws_pae_supp_initial_key_send(pae_supp) < 0) { - tr_info("EAPOL-Key send failed"); + if (pae_supp->initial_key_retry_timer > 0) { + if (pae_supp->initial_key_retry_timer > seconds) { + pae_supp->initial_key_retry_timer -= seconds; + } else { + pae_supp->initial_key_retry_timer = 0; + tr_info("initial key retry timer expired"); + } + } else { + // Checks if trickle timer expires + if (trickle_timer(&pae_supp->auth_trickle_timer, &pae_supp->auth_trickle_params, seconds)) { + if (pae_supp->initial_key_retry_cnt > 0) { + if (ws_pae_supp_initial_key_send(pae_supp) < 0) { + tr_info("EAPOL-Key send failed"); + } + } + + /* Wait time for the authenticator to answer the last re-transmit expires; + fails authentication */ + if (pae_supp->initial_key_retry_cnt == 0) { + bool retry = false; + // If making key update and GTKs do not match to GTK hash + if (!pae_supp->auth_requested && ws_pae_supp_gtk_hash_mismatch_check(pae_supp) < 0) { + tr_info("GTKs do not match to GTK hash"); + retry = true; + } + ws_pae_supp_authenticate_response(pae_supp, AUTH_RESULT_ERR_UNSPEC); + if (retry) { + // Start trickle timer to try re-authentication + ws_pae_supp_initial_key_update_trickle_timer_start(pae_supp, KEY_UPDATE_RETRY_COUNT); + } + } else { + if (pae_supp->initial_key_retry_cnt > 0) { + pae_supp->initial_key_retry_cnt--; + } + if (pae_supp->initial_key_retry_cnt == 0) { + // Starts wait time for the authenticator to answer + tr_info("Initial EAPOL-Key wait for last re-transmit answer"); + ws_pae_supp_initial_last_interval_trickle_timer_start(pae_supp); + } + } + } + + // Sanity check, should be running until authentication failure + if (!trickle_running(&pae_supp->auth_trickle_timer, &pae_supp->auth_trickle_params)) { + ws_pae_supp_authenticate_response(pae_supp, AUTH_RESULT_ERR_UNSPEC); } - } - // Maximum number of trickle expires, authentication fails - if (!trickle_running(&pae_supp->auth_trickle_timer, &pae_supp->auth_trickle_params)) { - ws_pae_supp_authenticate_response(pae_supp, AUTH_RESULT_ERR_UNSPEC); } } @@ -846,16 +940,76 @@ void ws_pae_supp_slow_timer(uint16_t seconds) if (ws_pae_supp_initial_key_send(pae_supp) < 0) { tr_info("EAPOL-Key send failed"); } - - // Starts trickle - pae_supp->auth_trickle_params = initial_eapol_key_trickle_params; - trickle_start(&pae_supp->auth_trickle_timer, &pae_supp->auth_trickle_params); - pae_supp->auth_trickle_running = true; + // Start trickle timer + ws_pae_supp_initial_trickle_timer_start(pae_supp); } } } } +static void ws_pae_supp_initial_trickle_timer_start(pae_supp_t *pae_supp) +{ + pae_supp->auth_trickle_params = initial_eapol_key_trickle_params; + + // Very fast, medium and slow network + if (timing_value < 25) { + /* Starts trickle for initial EAPOL-key. Sequence has fixed delay of 2 minutes, + * one re-transmit interval, last re-transmit interval transmit time and a wait time + * for the authenticator to answer the last re-transmit. + * + * Interval I [6,12] minutes. Sequence: + * + * fixed 2 minutes delay + I + last I transmit time t + wait for answer [2,4] minutes + * + * There are two retries. Minimum time that sequence takes before authentication failure + * is 16 minutes and maximum is 30 minutes. + */ + pae_supp->initial_key_retry_timer = DEFAULT_INITIAL_KEY_RETRY_TIMER; // 2 minutes + } else { + /* Extremely slow network + * + * Starts trickle for initial EAPOL-key, Interval I [10,60] minutes. Sequence: + * I + last I transmit time t + wait for answer [2,4] minutes + * There are two retries. Minimum time that sequence takes before authentication failure + * is 22 minutes and maximum is 124 minutes. + */ + pae_supp->auth_trickle_params.Imin = VERY_SLOW_NW_TRICKLE_IMIN_SECS; + pae_supp->auth_trickle_params.Imax = VERY_SLOW_NW_TRICKLE_IMAX_SECS; + pae_supp->initial_key_retry_timer = NONE_INITIAL_KEY_RETRY_TIMER; // 0 seconds + } + trickle_start(&pae_supp->auth_trickle_timer, &pae_supp->auth_trickle_params); + tr_info("Initial EAPOL-Key trickle I: [%i,%i] %i, t: %i", pae_supp->auth_trickle_params.Imin, pae_supp->auth_trickle_params.Imax, pae_supp->auth_trickle_timer.I, pae_supp->auth_trickle_timer.t); + pae_supp->auth_trickle_running = true; + pae_supp->initial_key_retry_cnt = INITIAL_KEY_RETRY_COUNT; +} + +static void ws_pae_supp_initial_last_interval_trickle_timer_start(pae_supp_t *pae_supp) +{ + // Starts trickle last to wait response after last retry before failing authentication + pae_supp->auth_trickle_params = initial_eapol_key_trickle_params; + pae_supp->auth_trickle_params.Imin = LAST_INTERVAL_TRICKLE_IMIN_SECS; + pae_supp->auth_trickle_params.Imax = LAST_INTERVAL_TRICKLE_IMAX_SECS; + pae_supp->auth_trickle_params.TimerExpirations = 1; + // Set I to [iMin,iMax] (4 to 4 minutes) -> t is [I/2 - I] (2 minutes to 4 minutes) + trickle_start(&pae_supp->auth_trickle_timer, &pae_supp->auth_trickle_params); + tr_info("Initial EAPOL-Key trickle I: [%i,%i] %i, t: %i", pae_supp->auth_trickle_params.Imin, pae_supp->auth_trickle_params.Imax, pae_supp->auth_trickle_timer.I, pae_supp->auth_trickle_timer.t); +} + +static void ws_pae_supp_initial_key_update_trickle_timer_start(pae_supp_t *pae_supp, uint8_t timer_expirations) +{ + // Starts trickle for the key update + pae_supp->auth_trickle_params.Imin = pae_supp->timer_settings->gtk_request_imin; + pae_supp->auth_trickle_params.Imax = pae_supp->timer_settings->gtk_request_imax; + pae_supp->auth_trickle_params.k = 0; + pae_supp->auth_trickle_params.TimerExpirations = timer_expirations; + + trickle_start(&pae_supp->auth_trickle_timer, &pae_supp->auth_trickle_params); + tr_info("Initial EAPOL-Key trickle I: [%i,%i] %i, t: %i", pae_supp->auth_trickle_params.Imin, pae_supp->auth_trickle_params.Imax, pae_supp->auth_trickle_timer.I, pae_supp->auth_trickle_timer.t); + pae_supp->initial_key_retry_timer = NONE_INITIAL_KEY_RETRY_TIMER; // 0 seconds + pae_supp->auth_trickle_running = true; + pae_supp->initial_key_retry_cnt = timer_expirations; +} + static int8_t ws_pae_supp_timer_if_start(kmp_service_t *service, kmp_api_t *kmp) { pae_supp_t *pae_supp = ws_pae_supp_by_kmp_service_get(service); @@ -947,7 +1101,7 @@ static int8_t ws_pae_supp_parent_eui_64_get(protocol_interface_info_entry_t *int const uint8_t *parent_ll_addr = rpl_control_preferred_parent_addr(instance, false); if (parent_ll_addr) { memcpy(eui_64, &parent_ll_addr[8], 8); - eui_64[0] |= 0x02; + eui_64[0] ^= 0x02; return 0; } } @@ -1014,14 +1168,13 @@ static kmp_api_t *ws_pae_supp_kmp_incoming_ind(kmp_service_t *service, kmp_type_ return NULL; } - if (!pae_supp->entry_address_active) { + // If target address is not set or authentication is not ongoing + if (!pae_supp->entry_address_active || !ws_pae_supp_authentication_ongoing(pae_supp)) { + tr_info("Incoming KMP rejected, auth not ongoing, type: %i ", type); // Does no longer wait for authentication, ignores message return NULL; } - // No longer runs trickle timer for re-sending initial EAPOL-key - pae_supp->auth_trickle_running = false; - // Updates parent address kmp_address_copy(&pae_supp->entry.addr, addr); @@ -1040,6 +1193,9 @@ static kmp_api_t *ws_pae_supp_kmp_incoming_ind(kmp_service_t *service, kmp_type_ // Create new instance kmp = ws_pae_supp_kmp_create_and_start(service, type, pae_supp); + // Adds ticks to wait for authenticator to continue timer + ws_pae_lib_supp_timer_ticks_add(&pae_supp->entry, START_AUTHENTICATION_TICKS); + // For EAP-TLS create also TLS in addition to EAP-TLS if (type == IEEE_802_1X_MKA) { if (ws_pae_lib_kmp_list_type_get(&pae_supp->entry.kmp_list, TLS_PROT) != NULL) { @@ -1112,6 +1268,15 @@ static void ws_pae_supp_kmp_api_create_indication(kmp_api_t *kmp, kmp_type_e typ (void) addr; (void) type; + kmp_service_t *service = kmp_api_service_get(kmp); + pae_supp_t *pae_supp = ws_pae_supp_by_kmp_service_get(service); + if (!pae_supp) { + return; + } + + // Incoming KMP protocol has started, no longer runs trickle timer for re-sending EAPOL-key message + pae_supp->auth_trickle_running = false; + // For now, accept every KMP-CREATE.indication kmp_api_create_response(kmp, KMP_RESULT_OK); } @@ -1148,7 +1313,6 @@ static void ws_pae_supp_kmp_api_finished_indication(kmp_api_t *kmp, kmp_result_e tr_info("Initial EAPOL-Key TX failure, target: %s", trace_array(kmp_address_eui_64_get(&pae_supp->entry.addr), 8)); ws_pae_supp_authenticate_response(pae_supp, AUTH_RESULT_ERR_TX_NO_ACK); } - } static void ws_pae_supp_kmp_api_finished(kmp_api_t *kmp) diff --git a/source/6LoWPAN/ws/ws_pae_supp.h b/source/6LoWPAN/ws/ws_pae_supp.h index bc8fc0f0110..458ed7bf9ea 100644 --- a/source/6LoWPAN/ws/ws_pae_supp.h +++ b/source/6LoWPAN/ws/ws_pae_supp.h @@ -236,6 +236,16 @@ typedef void ws_pae_supp_auth_completed(protocol_interface_info_entry_t *interfa */ typedef int8_t ws_pae_supp_nw_key_insert(protocol_interface_info_entry_t *interface_ptr, sec_prot_gtk_keys_t *gtks); +/** + * ws_pae_supp_gtk_hash_ptr_get get pointer to GTK hash storage callback + * + * \param interface_ptr interface + * + * \return pointer to GTK has storage or NULL + * + */ +typedef uint8_t *ws_pae_supp_gtk_hash_ptr_get(protocol_interface_info_entry_t *interface_ptr); + /** * ws_pae_supp_cb_register register PEA supplicant callbacks * @@ -245,7 +255,7 @@ typedef int8_t ws_pae_supp_nw_key_insert(protocol_interface_info_entry_t *interf * \param nw_key_index_set network send key index callback * */ -void ws_pae_supp_cb_register(protocol_interface_info_entry_t *interface_ptr, ws_pae_supp_auth_completed *completed, ws_pae_supp_nw_key_insert *nw_key_insert, ws_pae_supp_nw_key_index_set *nw_key_index_set); +void ws_pae_supp_cb_register(protocol_interface_info_entry_t *interface_ptr, ws_pae_supp_auth_completed *completed, ws_pae_supp_nw_key_insert *nw_key_insert, ws_pae_supp_nw_key_index_set *nw_key_index_set, ws_pae_supp_gtk_hash_ptr_get *gtk_hash_ptr_get); #else diff --git a/source/Common_Protocols/icmpv6.c b/source/Common_Protocols/icmpv6.c index 5222fde7689..f0b3dc59eab 100644 --- a/source/Common_Protocols/icmpv6.c +++ b/source/Common_Protocols/icmpv6.c @@ -356,7 +356,7 @@ static void icmpv6_na_wisun_aro_handler(protocol_interface_info_entry_t *cur_int (void)life_time; if (nd_status != ARO_SUCCESS) { - ws_common_aro_failure(cur_interface, src_addr, true); + ws_common_aro_failure(cur_interface, src_addr); } } @@ -1389,7 +1389,7 @@ static void icmpv6_aro_cb(buffer_t *buf, uint8_t status) } rpl_control_address_register_done(buf->interface, ll_address, status); if (status != SOCKET_TX_DONE) { - ws_common_aro_failure(buf->interface, ll_address, false); + ws_common_aro_failure(buf->interface, ll_address); } } @@ -1697,7 +1697,7 @@ buffer_t *icmpv6_build_na(protocol_interface_info_entry_t *cur, bool solicited, memcpy(ptr, aro->eui64, 8); ptr += 8; } - if (ws_info(cur) && aro && aro->status != ARO_SUCCESS) { + if (ws_info(cur) && aro && (aro->status != ARO_SUCCESS && aro->status != ARO_TOPOLOGICALLY_INCORRECT)) { /*If Aro failed we will kill the neigbour after we have succeeded in sending message*/ if (!ws_common_negative_aro_mark(cur, aro->eui64)) { tr_debug("Neighbour removed for negative response send"); @@ -1713,7 +1713,7 @@ buffer_t *icmpv6_build_na(protocol_interface_info_entry_t *cur, bool solicited, buf->info = (buffer_info_t)(B_DIR_DOWN | B_FROM_ICMP | B_TO_ICMP); buf->interface = cur; - tr_debug("Build NA"); + tr_info("Build NA"); return (buf); } diff --git a/source/Common_Protocols/icmpv6.h b/source/Common_Protocols/icmpv6.h index c209e2af427..3ae2aa14edf 100644 --- a/source/Common_Protocols/icmpv6.h +++ b/source/Common_Protocols/icmpv6.h @@ -117,6 +117,7 @@ typedef enum slaac_src { #define ARO_SUCCESS 0 #define ARO_DUPLICATE 1 #define ARO_FULL 2 +#define ARO_TOPOLOGICALLY_INCORRECT 8 extern void icmpv6_init(void); extern struct buffer *icmpv6_down(struct buffer *buf); diff --git a/source/Common_Protocols/icmpv6_radv.c b/source/Common_Protocols/icmpv6_radv.c index fff4edec989..446d05f38ec 100644 --- a/source/Common_Protocols/icmpv6_radv.c +++ b/source/Common_Protocols/icmpv6_radv.c @@ -325,6 +325,9 @@ 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) abro; +#endif if (cur->nwk_id == IF_6LoWPAN) { nd_ra_build_by_abro(abro, dest, cur); } else { diff --git a/source/Common_Protocols/ipv6.c b/source/Common_Protocols/ipv6.c index fe3102591d7..11df4aafa45 100644 --- a/source/Common_Protocols/ipv6.c +++ b/source/Common_Protocols/ipv6.c @@ -773,6 +773,9 @@ static buffer_t *ipv6_tunnel_exit(buffer_t *buf, uint8_t *payload) static buffer_t *ipv6_handle_options(buffer_t *buf, protocol_interface_info_entry_t *cur, uint8_t *ptr, uint8_t nh, uint16_t payload_length, uint16_t *hdrlen_out, const sockaddr_t *ll_src, bool pre_fragment) { (void) nh; +#ifndef HAVE_RPL + (void) ll_src; +#endif if (payload_length < 2) { return icmpv6_error(buf, cur, ICMPV6_TYPE_ERROR_PARAMETER_PROBLEM, ICMPV6_CODE_PARAM_PRB_HDR_ERR, 4); } @@ -853,6 +856,9 @@ static buffer_t *ipv6_handle_options(buffer_t *buf, protocol_interface_info_entr static buffer_t *ipv6_handle_routing_header(buffer_t *buf, protocol_interface_info_entry_t *cur, uint8_t *ptr, uint16_t payload_length, uint16_t *hdrlen_out, bool *forward_out, bool pre_fragment) { +#ifndef HAVE_RPL + (void) forward_out; +#endif if (buf->options.ll_security_bypass_rx) { tr_warn("Routing header: Security check fail"); protocol_stats_update(STATS_IP_RX_DROP, 1); diff --git a/source/Core/buffer_dyn.c b/source/Core/buffer_dyn.c index 1b34e649973..268ee815ab9 100644 --- a/source/Core/buffer_dyn.c +++ b/source/Core/buffer_dyn.c @@ -16,7 +16,8 @@ */ #include "nsconfig.h" -#include "string.h" +#include +#include #include "ns_types.h" #include "nsdynmemLIB.h" #include "Core/include/ns_address_internal.h" @@ -30,6 +31,13 @@ #define TRACE_GROUP "buff" +// Get module working also on 16-bit platform +#if INT_MAX < 0xFFFF +#define BUFFER_MAX_SIZE ((size_t)INT_MAX) +#else +#define BUFFER_MAX_SIZE ((size_t)0xFFFF) +#endif + volatile unsigned int buffer_count = 0; uint8_t *(buffer_corrupt_check)(buffer_t *buf) @@ -38,15 +46,12 @@ uint8_t *(buffer_corrupt_check)(buffer_t *buf) return NULL; } - if (buf->buf_ptr > buf->buf_end) { - tr_error("Buffer pointer end not set"); - } else if (buffer_data_length(buf) < 0) { - tr_error("Buffer length overflow"); - while (1); - } else if (buf->buf_end > buf->size || buf->buf_ptr > buf->size) { - tr_error("buffer pointer overridden"); + if (buf->buf_ptr > buf->buf_end || buf->buf_end > buf->size) { + tr_error("Invalid buffer, size=%"PRIu16", buf_ptr=%"PRIu16", buf_end=%"PRIu16"", buf->size, buf->buf_ptr, buf->buf_end); + tr_error("Data: %s", tr_array(buffer_data_pointer(buf), 56)); while (1); } + return buffer_data_pointer(buf); } @@ -71,8 +76,8 @@ buffer_t *buffer_get_minimal(uint16_t size) */ buffer_t *buffer_get_specific(uint16_t headroom, uint16_t size, uint16_t minspace) { - buffer_t *buf; - uint16_t total_size; + buffer_t *buf = NULL; + uint32_t total_size; total_size = headroom + size; if (total_size < minspace) { @@ -83,10 +88,12 @@ buffer_t *buffer_get_specific(uint16_t headroom, uint16_t size, uint16_t minspac * anyway be this much aligned. */ total_size = (total_size + 3) & ~ 3; - // Note - as well as this alloc+init, buffers can also be "realloced" - // in buffer_headroom() + if (total_size <= BUFFER_MAX_SIZE) { + // Note - as well as this alloc+init, buffers can also be "realloced" + // in buffer_headroom() + buf = ns_dyn_mem_temporary_alloc(sizeof(buffer_t) + total_size); + } - buf = ns_dyn_mem_temporary_alloc(sizeof(buffer_t) + total_size); if (buf) { platform_enter_critical(); buffer_count++; @@ -110,7 +117,7 @@ buffer_t *buffer_get_specific(uint16_t headroom, uint16_t size, uint16_t minspac #endif buf->size = total_size; } else { - tr_error("buffer_get failed: alloc(%d)", (int) sizeof(buffer_t) + total_size); + tr_error("buffer_get failed: alloc(%"PRIu32")", (uint32_t)(sizeof(buffer_t) + total_size)); } protocol_stats_update(STATS_BUFFER_ALLOC, 1); @@ -130,10 +137,14 @@ buffer_t *buffer_headroom(buffer_t *buf, uint16_t size) uint16_t curr_len = buffer_data_length(buf); if (buf->size < (curr_len + size)) { + buffer_t *restrict new_buf = NULL; /* This buffer isn't big enough at all - allocate a new block */ // TODO - should we be giving them extra? probably - uint16_t new_total = (curr_len + size + 3) & ~ 3; - buffer_t *restrict new_buf = ns_dyn_mem_temporary_alloc(sizeof(buffer_t) + new_total); + uint32_t new_total = (curr_len + size + 3) & ~ 3; + if (new_total <= BUFFER_MAX_SIZE) { + new_buf = ns_dyn_mem_temporary_alloc(sizeof(buffer_t) + new_total); + } + if (new_buf) { // Copy the buffer_t header *new_buf = *buf; diff --git a/source/Core/include/ns_buffer.h b/source/Core/include/ns_buffer.h index 7ebb6e05454..b33148a14d1 100644 --- a/source/Core/include/ns_buffer.h +++ b/source/Core/include/ns_buffer.h @@ -322,7 +322,7 @@ struct socket *buffer_socket_set(buffer_t *buf, struct socket *socket); } while(0) /** get data length*/ -#define buffer_data_length(x) (int16_t)(x->buf_end - x->buf_ptr) +#define buffer_data_length(x) (int)(x->buf_end - x->buf_ptr) /** get data length Set*/ #define buffer_data_length_set(x,z) ((x)->buf_end = (x)->buf_ptr + (z)) diff --git a/source/Core/ns_socket.c b/source/Core/ns_socket.c index 24f7738c6fa..05961ccb5b1 100644 --- a/source/Core/ns_socket.c +++ b/source/Core/ns_socket.c @@ -287,14 +287,16 @@ void socket_release(socket_t *socket) if (tcp_info(socket->inet_pcb)) { /* This may trigger a reset if pending data. Do it first so you * get just the reset, rather than a FIN. */ - tcp_session_shutdown_read(tcp_info(socket->inet_pcb)); + tcp_error sock_status = tcp_session_shutdown_read(tcp_info(socket->inet_pcb)); /* This can also cause TCP deletion */ if (tcp_info(socket->inet_pcb)) { - tcp_session_close(tcp_info(socket->inet_pcb)); + sock_status = tcp_session_close(tcp_info(socket->inet_pcb)); } if (tcp_info(socket->inet_pcb)) { tcp_socket_released(tcp_info(socket->inet_pcb)); } + // prevent warning "statement with no effect" when TCP is disabled + (void) sock_status; } else { /* Unbind the internet control block - ensures users are not prevented * from binding a new socket to the same port if the socket lingers @@ -1362,8 +1364,10 @@ int16_t socket_buffer_sendmsg(int8_t sid, buffer_t *buf, const struct ns_msghdr protocol_push(buf); +#ifndef NO_TCP /* TCP jumps back to here */ success: +#endif if (flags & NS_MSG_LEGACY0) { return 0; } else { diff --git a/source/DHCPv6_Server/DHCPv6_Server_service.c b/source/DHCPv6_Server/DHCPv6_Server_service.c index bd606db11fe..a7755034a9d 100644 --- a/source/DHCPv6_Server/DHCPv6_Server_service.c +++ b/source/DHCPv6_Server/DHCPv6_Server_service.c @@ -87,7 +87,7 @@ static void DHCP_server_service_timer_stop(void) int DHCPv6_server_respond_client(dhcpv6_gua_server_entry_s *serverBase, dhcpv6_reply_packet_s *replyPacket, dhcp_ia_non_temporal_params_t *dhcp_ia_non_temporal_params, dhcpv6_gua_response_t *response, bool allocateNew) { - dhcpv6_alloacted_address_entry_t *dhcp_allocated_address; + dhcpv6_allocated_address_t *dhcp_allocated_address = NULL; dhcpv6_ia_non_temporal_address_s nonTemporalAddress; bool address_allocated = false; //Validate Client DUID @@ -279,12 +279,15 @@ void DHCPv6_server_service_delete(int8_t interface, uint8_t guaPrefix[static 8], { dhcpv6_gua_server_entry_s *serverInfo = libdhcpv6_server_data_get_by_prefix_and_interfaceid(interface, guaPrefix); if (serverInfo) { - ns_list_foreach_safe(dhcpv6_alloacted_address_entry_t, cur, &serverInfo->allocatedAddressList) { + ns_list_foreach_safe(dhcpv6_allocated_address_entry_t, cur, &serverInfo->allocatedAddressList) { //Delete Server data base if (serverInfo->removeCb) { - serverInfo->removeCb(interface, cur->nonTemporalAddress, NULL); + uint8_t allocated_address[16]; + libdhcpv6_allocated_address_write(allocated_address, cur, serverInfo); + serverInfo->removeCb(interface, allocated_address, NULL); } } + if (serverInfo->removeCb) { // Clean all /128 'Thread Proxy' routes to self and others added when acting as a DHCP server serverInfo->removeCb(interface, NULL, serverInfo->guaPrefix); @@ -312,18 +315,22 @@ void DHCPv6_server_service_delete(int8_t interface, uint8_t guaPrefix[static 8], * /param guaPrefix Prefix which will be removed * /param mode true trig autonous mode, false define address by default suffics + client id */ -int DHCPv6_server_service_set_address_autonous_flag(int8_t interface, uint8_t guaPrefix[static 16], bool mode) +int DHCPv6_server_service_set_address_autonous_flag(int8_t interface, uint8_t guaPrefix[static 16], bool mode, bool autonomous_skip_list) { - int retVal = -1; - dhcpv6_gua_server_entry_s *serverInfo; + dhcpv6_gua_server_entry_s *serverInfo = libdhcpv6_server_data_get_by_prefix_and_interfaceid(interface, guaPrefix); + if (!serverInfo) { + return -1; - serverInfo = libdhcpv6_server_data_get_by_prefix_and_interfaceid(interface, guaPrefix); - if (serverInfo) { - serverInfo->enableAddressAutonous = mode; - retVal = 0; } - return retVal; + serverInfo->enableAddressAutonous = mode; + if (mode) { + serverInfo->disableAddressListAllocation = autonomous_skip_list; + } else { + serverInfo->disableAddressListAllocation = false; + } + + return 0; } void DHCPv6_server_service_callback_set(int8_t interface, uint8_t guaPrefix[static 16], dhcp_address_prefer_remove_cb *remove_cb, dhcp_address_add_notify_cb *add_cb) @@ -365,18 +372,18 @@ int DHCPv6_server_service_duid_update(int8_t interface, uint8_t guaPrefix[static */ int DHCPv6_server_service_set_max_clients_accepts_count(int8_t interface, uint8_t guaPrefix[static 16], uint32_t maxClientCount) { - int retVal = -1; dhcpv6_gua_server_entry_s *serverInfo; - if (maxClientCount == 0) { + if (maxClientCount == 0 || maxClientCount > MAX_SUPPORTED_ADDRESS_LIST_SIZE) { return -2; - } else { - serverInfo = libdhcpv6_server_data_get_by_prefix_and_interfaceid(interface, guaPrefix); - if (serverInfo) { - serverInfo->maxSuppertedClients = maxClientCount; - retVal = 0; - } } - return retVal; + serverInfo = libdhcpv6_server_data_get_by_prefix_and_interfaceid(interface, guaPrefix); + if (!serverInfo) { + return -1; + } + + serverInfo->maxSupportedClients = maxClientCount; + + return 0; } /** SET Address Valid Lifetime parameter for allocated address, Default is 7200 seconds @@ -388,18 +395,17 @@ int DHCPv6_server_service_set_max_clients_accepts_count(int8_t interface, uint8_ */ int DHCPv6_server_service_set_address_validlifetime(int8_t interface, uint8_t guaPrefix[static 16], uint32_t validLifeTimne) { - int retVal = -1; dhcpv6_gua_server_entry_s *serverInfo; if (validLifeTimne < 120) { - retVal = -2; - } else { - serverInfo = libdhcpv6_server_data_get_by_prefix_and_interfaceid(interface, guaPrefix); - if (serverInfo) { - serverInfo->validLifetime = validLifeTimne; - retVal = 0; - } + return -2; } - return retVal; + serverInfo = libdhcpv6_server_data_get_by_prefix_and_interfaceid(interface, guaPrefix); + if (!serverInfo) { + return -1; + } + serverInfo->validLifetime = validLifeTimne; + + return 0; } #else @@ -422,11 +428,12 @@ void DHCPv6_server_service_timeout_cb(uint32_t timeUpdateInSeconds) { (void) timeUpdateInSeconds; } -int DHCPv6_server_service_set_address_autonous_flag(int8_t interface, uint8_t guaPrefix[static 16], bool mode) +int DHCPv6_server_service_set_address_autonous_flag(int8_t interface, uint8_t guaPrefix[static 16], bool mode, bool autonomous_skip_list) { (void) interface; (void) guaPrefix; (void) mode; + (void) autonomous_skip_list; return -1; } diff --git a/source/DHCPv6_Server/DHCPv6_server_service.h b/source/DHCPv6_Server/DHCPv6_server_service.h index 2a236ad2542..8f8616f4f41 100644 --- a/source/DHCPv6_Server/DHCPv6_server_service.h +++ b/source/DHCPv6_Server/DHCPv6_server_service.h @@ -66,8 +66,9 @@ void DHCPv6_server_service_timeout_cb(uint32_t timeUpdateInSeconds); * /param interface interface id of this thread instance. * /param guaPrefix Prefix which will be removed * /param mode true trig autonous mode, false define address by default suffics + client id + * /param autonomous_skip_list true skip address list allocation when autonous mode is selected */ -int DHCPv6_server_service_set_address_autonous_flag(int8_t interface, uint8_t guaPrefix[static 16], bool mode); +int DHCPv6_server_service_set_address_autonous_flag(int8_t interface, uint8_t guaPrefix[static 16], bool mode, bool autonomous_skip_list); /* SET max accepted clients to server, Default is 200 diff --git a/source/MAC/IEEE802_15_4/mac_defines.h b/source/MAC/IEEE802_15_4/mac_defines.h index 7d534595458..acc45a67880 100644 --- a/source/MAC/IEEE802_15_4/mac_defines.h +++ b/source/MAC/IEEE802_15_4/mac_defines.h @@ -202,6 +202,7 @@ typedef struct protocol_interface_rf_mac_setup { mac_scan_type_t scan_type; uint8_t mac_channel; + uint8_t mac_tx_start_channel; //uint8_t cca_failure; /* MAC TX Queue */ @@ -244,6 +245,7 @@ typedef struct protocol_interface_rf_mac_setup { uint32_t mlme_tick_count; uint32_t symbol_rate; uint32_t symbol_time_us; + uint32_t datarate; uint8_t max_ED; uint16_t mlme_ED_counter; mac_tx_status_t mac_tx_status; diff --git a/source/MAC/IEEE802_15_4/mac_fhss_callbacks.c b/source/MAC/IEEE802_15_4/mac_fhss_callbacks.c index 3f09ca01baf..fd56ecbd74a 100644 --- a/source/MAC/IEEE802_15_4/mac_fhss_callbacks.c +++ b/source/MAC/IEEE802_15_4/mac_fhss_callbacks.c @@ -57,8 +57,13 @@ uint32_t mac_read_phy_datarate(const fhss_api_t *fhss_api) if (!mac_setup) { return 0; } - uint32_t datarate = dev_get_phy_datarate(mac_setup->dev_driver->phy_driver, mac_setup->mac_channel_list.channel_page); - // If datarate is not set, use default 250kbit/s. + uint32_t datarate = 0; + // When channel page is set, ask data rate directly from PHY driver, otherwise use data rate configured to MAC. Ultimately, use default value instead 0. + if (mac_setup->mac_channel_list.channel_page != CHANNEL_PAGE_UNDEFINED) { + datarate = dev_get_phy_datarate(mac_setup->dev_driver->phy_driver, mac_setup->mac_channel_list.channel_page); + } else if (mac_setup->datarate) { + datarate = mac_setup->datarate; + } if (!datarate) { datarate = 250000; } diff --git a/source/MAC/IEEE802_15_4/mac_mcps_sap.c b/source/MAC/IEEE802_15_4/mac_mcps_sap.c index a97570675a6..6442290a48e 100644 --- a/source/MAC/IEEE802_15_4/mac_mcps_sap.c +++ b/source/MAC/IEEE802_15_4/mac_mcps_sap.c @@ -1321,7 +1321,7 @@ static void mac_common_data_confirmation_handle(protocol_interface_rf_mac_setup_ timer_mac_stop(rf_mac_setup); if (m_event == MAC_CCA_FAIL) { sw_mac_stats_update(rf_mac_setup, STAT_MAC_TX_CCA_FAIL, 0); - tr_debug("MAC CCA fail"); + tr_info("MAC CCA fail"); /* CCA fail */ //rf_mac_setup->cca_failure++; buf->status = MLME_BUSY_CHAN; @@ -1329,7 +1329,7 @@ static void mac_common_data_confirmation_handle(protocol_interface_rf_mac_setup_ sw_mac_stats_update(rf_mac_setup, STAT_MAC_TX_COUNT, buf->mac_payload_length); if (m_event == MAC_TX_FAIL) { sw_mac_stats_update(rf_mac_setup, STAT_MAC_TX_FAIL, 0); - tr_debug("MAC tx fail"); + tr_info("MAC tx fail"); buf->status = MLME_TX_NO_ACK; } else if (m_event == MAC_TX_DONE) { if (mac_is_ack_request_set(buf) == false) { @@ -1430,7 +1430,7 @@ static void mcps_data_confirm_handle(protocol_interface_rf_mac_setup_s *rf_ptr, if (rf_ptr->fhss_api && !buffer->asynch_request) { // FHSS checks if this failed buffer needs to be pushed back to TX queue and retransmitted if ((rf_ptr->mac_tx_result == MAC_TX_FAIL) || (rf_ptr->mac_tx_result == MAC_CCA_FAIL)) { - if (rf_ptr->fhss_api->data_tx_fail(rf_ptr->fhss_api, buffer->msduHandle, mac_convert_frame_type_to_fhss(buffer->fcf_dsn.frametype)) == true) { + if (rf_ptr->fhss_api->data_tx_fail(rf_ptr->fhss_api, buffer->msduHandle, mac_convert_frame_type_to_fhss(buffer->fcf_dsn.frametype), rf_ptr->mac_tx_start_channel) == true) { if (rf_ptr->mac_tx_result == MAC_TX_FAIL) { buffer->fhss_retry_count += 1 + rf_ptr->mac_tx_status.retry; @@ -1543,7 +1543,7 @@ static int8_t mcps_generic_packet_build(protocol_interface_rf_mac_setup_s *rf_pt mac_header_information_elements_preparation(buffer); mcps_generic_sequence_number_allocate(rf_ptr, buffer); - mlme_key_descriptor_t *key_desc; + mlme_key_descriptor_t *key_desc = NULL; if (buffer->fcf_dsn.securityEnabled) { bool increment_framecounter = false; //Remember to update security counter here! @@ -1600,7 +1600,7 @@ static int8_t mcps_generic_packet_build(protocol_interface_rf_mac_setup_s *rf_pt tr_debug("Too Long %u, %u pa %u header %u mic %u", frame_length, mac_payload_length, buffer->mac_header_length_with_security, buffer->security_mic_len, dev_driver->phy_MTU); buffer->status = MLME_FRAME_TOO_LONG; //decrement security counter - if (buffer->fcf_dsn.securityEnabled) { + if (key_desc) { mac_sec_mib_key_outgoing_frame_counter_decrement(rf_ptr, key_desc); } return -1; @@ -1716,7 +1716,7 @@ int8_t mcps_generic_ack_build(protocol_interface_rf_mac_setup_s *rf_ptr, bool in ccm_globals_t ccm_ptr; mac_pre_build_frame_t *buffer = &rf_ptr->enhanced_ack_buffer; - mlme_key_descriptor_t *key_desc; + mlme_key_descriptor_t *key_desc = NULL; if (buffer->fcf_dsn.securityEnabled) { //Remember to update security counter here! @@ -1755,7 +1755,7 @@ int8_t mcps_generic_ack_build(protocol_interface_rf_mac_setup_s *rf_ptr, bool in if ((frame_length) > ack_mtu_size - 2) { buffer->status = MLME_FRAME_TOO_LONG; - if (buffer->fcf_dsn.securityEnabled) { + if (key_desc) { //decrement security counter mac_sec_mib_key_outgoing_frame_counter_decrement(rf_ptr, key_desc); ccm_free(&ccm_ptr); @@ -1921,6 +1921,7 @@ static int8_t mcps_pd_data_request(protocol_interface_rf_mac_setup_s *rf_ptr, ma memset(&(rf_ptr->mac_tx_status), 0, sizeof(mac_tx_status_t)); rf_ptr->mac_cca_retry = 0; rf_ptr->mac_tx_retry = 0; + rf_ptr->mac_tx_start_channel = rf_ptr->mac_channel; mac_csma_param_init(rf_ptr); if (mcps_generic_packet_build(rf_ptr, buffer) != 0) { return -1; diff --git a/source/MAC/IEEE802_15_4/mac_mlme.c b/source/MAC/IEEE802_15_4/mac_mlme.c index 5d1f5e48c92..b091da2a85f 100644 --- a/source/MAC/IEEE802_15_4/mac_mlme.c +++ b/source/MAC/IEEE802_15_4/mac_mlme.c @@ -783,6 +783,7 @@ int8_t mac_mlme_set_req(protocol_interface_rf_mac_setup_s *rf_mac_setup, const m rf_mac_setup->dev_driver->phy_driver->extension(PHY_EXTENSION_SET_RF_CONFIGURATION, (uint8_t *) set_req->value_pointer); mac_mlme_set_symbol_rate(rf_mac_setup); phy_rf_channel_configuration_s *config_params = (phy_rf_channel_configuration_s *)set_req->value_pointer; + rf_mac_setup->datarate = config_params->datarate; tr_info("RF config update:"); tr_info("Frequency(ch0): %"PRIu32"Hz", config_params->channel_0_center_frequency); tr_info("Channel spacing: %"PRIu32"Hz", config_params->channel_spacing); @@ -1090,6 +1091,7 @@ protocol_interface_rf_mac_setup_s *mac_mlme_data_base_allocate(uint8_t *mac64, a entry->aUnitBackoffPeriod = 20; //This can be different in some Platform 20 comes from 12-symbol turnaround and 8 symbol CCA read entry->number_of_csma_ca_periods = MAC_DEFAULT_NUMBER_OF_CSMA_PERIODS; entry->multi_cca_interval = MAC_DEFAULT_CSMA_MULTI_CCA_INTERVAL; + entry->mac_channel_list.channel_page = CHANNEL_PAGE_UNDEFINED; if (mac_sec_mib_init(entry, storage_sizes) != 0) { mac_mlme_data_base_deallocate(entry); diff --git a/source/MAC/IEEE802_15_4/mac_pd_sap.c b/source/MAC/IEEE802_15_4/mac_pd_sap.c index a7a5cc2a89d..1b8eda12291 100644 --- a/source/MAC/IEEE802_15_4/mac_pd_sap.c +++ b/source/MAC/IEEE802_15_4/mac_pd_sap.c @@ -429,7 +429,7 @@ static int8_t mac_data_interface_tx_done_cb(protocol_interface_rf_mac_setup_s *r if (rf_ptr->mac_ack_tx_active) { //Accept direct non crypted acks and crypted only if neighbor is at list - if (rf_ptr->ack_tx_possible || mac_sec_mib_device_description_get(rf_ptr, rf_ptr->enhanced_ack_buffer.DstAddr, rf_ptr->enhanced_ack_buffer.fcf_dsn.DstAddrMode, rf_ptr->enhanced_ack_buffer.DstPANId)) { + if (rf_ptr->ack_tx_possible) { return PHY_TX_ALLOWED; } @@ -481,10 +481,6 @@ static int8_t mac_data_interface_tx_done_cb(protocol_interface_rf_mac_setup_s *r return 0; } - // - bool waiting_ack = false; - - if (rf_ptr->mac_ack_tx_active) { mac_data_ack_tx_finish(rf_ptr); return 0; @@ -506,11 +502,40 @@ static int8_t mac_data_interface_tx_done_cb(protocol_interface_rf_mac_setup_s *r timer_mac_stop(rf_ptr); } + if (rf_ptr->fhss_api && rf_ptr->active_pd_data_request->asynch_request == false) { + /* waiting_ack == false allows FHSS to change back to RX channel after transmission + * tx_completed == true allows FHSS to delete stored failure handles + */ + bool waiting_ack = false, tx_completed = false; + if (status == PHY_LINK_TX_SUCCESS && !rf_ptr->macTxRequestAck) { + waiting_ack = false; + tx_completed = true; + } else if (status == PHY_LINK_TX_SUCCESS && rf_ptr->macTxRequestAck) { + waiting_ack = true; + tx_completed = false; + } else if (status == PHY_LINK_CCA_FAIL) { + waiting_ack = false; + tx_completed = false; + } else if (status == PHY_LINK_CCA_OK) { + waiting_ack = false; + tx_completed = false; + } else if (status == PHY_LINK_TX_FAIL) { + waiting_ack = false; + tx_completed = false; + } else if (status == PHY_LINK_TX_DONE) { + waiting_ack = false; + tx_completed = true; + } else if (status == PHY_LINK_TX_DONE_PENDING) { + waiting_ack = false; + tx_completed = true; + } + rf_ptr->fhss_api->data_tx_done(rf_ptr->fhss_api, waiting_ack, tx_completed, rf_ptr->active_pd_data_request->msduHandle); + } + switch (status) { case PHY_LINK_TX_SUCCESS: if (rf_ptr->macTxRequestAck) { timer_mac_start(rf_ptr, MAC_TIMER_ACK, rf_ptr->mac_ack_wait_duration); /*wait for ACK 1 ms*/ - waiting_ack = true; } else { //TODO CHECK this is MAC_TX_ PERMIT OK mac_tx_done_state_set(rf_ptr, MAC_TX_DONE); @@ -540,15 +565,6 @@ static int8_t mac_data_interface_tx_done_cb(protocol_interface_rf_mac_setup_s *r default: break; } - if (rf_ptr->fhss_api) { - bool tx_is_done = false; - if (rf_ptr->mac_tx_result == MAC_TX_DONE) { - tx_is_done = true; - } - if (rf_ptr->active_pd_data_request->asynch_request == false) { - rf_ptr->fhss_api->data_tx_done(rf_ptr->fhss_api, waiting_ack, tx_is_done, rf_ptr->active_pd_data_request->msduHandle); - } - } return 0; } @@ -772,7 +788,7 @@ static int8_t mac_pd_sap_generate_ack(protocol_interface_rf_mac_setup_s *rf_ptr, return -1; } - if (rf_ptr->enhanced_ack_buffer.aux_header.securityLevel == 0 || mac_sec_mib_device_description_get(rf_ptr, rf_ptr->enhanced_ack_buffer.DstAddr, rf_ptr->enhanced_ack_buffer.fcf_dsn.DstAddrMode, rf_ptr->enhanced_ack_buffer.DstPANId)) { + if (mac_sec_mib_device_description_get(rf_ptr, rf_ptr->enhanced_ack_buffer.DstAddr, rf_ptr->enhanced_ack_buffer.fcf_dsn.DstAddrMode, rf_ptr->enhanced_ack_buffer.DstPANId)) { rf_ptr->ack_tx_possible = true; } else { rf_ptr->ack_tx_possible = false; @@ -874,6 +890,11 @@ int8_t mac_pd_sap_data_cb(void *identifier, arm_phy_sap_msg_t *message) if (message->id == MAC15_4_PD_SAP_DATA_IND) { arm_pd_sap_generic_ind_t *pd_data_ind = &(message->message.generic_data_ind); + mac_pre_parsed_frame_t *buffer = NULL; + if (pd_data_ind->data_len == 0) { + goto ERROR_HANDLER; + } + if (pd_data_ind->data_len < 3) { return -1; } @@ -881,7 +902,7 @@ int8_t mac_pd_sap_data_cb(void *identifier, arm_phy_sap_msg_t *message) mac_fcf_sequence_t fcf_read; const uint8_t *ptr = mac_header_parse_fcf_dsn(&fcf_read, pd_data_ind->data_ptr); - mac_pre_parsed_frame_t *buffer = mac_pd_sap_allocate_receive_buffer(rf_ptr, &fcf_read, pd_data_ind); + buffer = mac_pd_sap_allocate_receive_buffer(rf_ptr, &fcf_read, pd_data_ind); if (buffer && mac_filter_modify_link_quality(rf_ptr->mac_interface_id, buffer) == 1) { goto ERROR_HANDLER; } @@ -919,7 +940,12 @@ int8_t mac_pd_sap_data_cb(void *identifier, arm_phy_sap_msg_t *message) } ERROR_HANDLER: mcps_sap_pre_parsed_frame_buffer_free(buffer); - sw_mac_stats_update(rf_ptr, STAT_MAC_RX_DROP, 0); + if (pd_data_ind->data_len >= 3) { + sw_mac_stats_update(rf_ptr, STAT_MAC_RX_DROP, 0); + } + if (rf_ptr->fhss_api) { + rf_ptr->fhss_api->data_tx_done(rf_ptr->fhss_api, false, false, 0); + } return -1; } else if (message->id == MAC15_4_PD_SAP_DATA_TX_CONFIRM) { diff --git a/source/MAC/IEEE802_15_4/mac_security_mib.c b/source/MAC/IEEE802_15_4/mac_security_mib.c index 8b22875a96d..27de7e89cbe 100644 --- a/source/MAC/IEEE802_15_4/mac_security_mib.c +++ b/source/MAC/IEEE802_15_4/mac_security_mib.c @@ -281,6 +281,7 @@ int8_t mac_sec_mib_device_description_set(uint8_t atribute_index, mlme_device_de return -1; } + platform_enter_critical(); mlme_device_descriptor_t *device_ptr = rf_mac_setup->device_description_table + atribute_index; //Copy description @@ -293,6 +294,24 @@ int8_t mac_sec_mib_device_description_set(uint8_t atribute_index, mlme_device_de //tr_debug("Set %u, mac16 %x mac64: %s, %"PRIu32, atribute_index, device_descriptor->ShortAddress, trace_array(device_descriptor->ExtAddress, 8), device_descriptor->FrameCounter); *device_ptr = *device_descriptor; + + if (rf_mac_setup->mac_ack_tx_active && !rf_mac_setup->ack_tx_possible && + device_ptr->PANId == rf_mac_setup->enhanced_ack_buffer.DstPANId) { + + //Compare address for pending neigbour add + if (rf_mac_setup->enhanced_ack_buffer.fcf_dsn.DstAddrMode == MAC_ADDR_MODE_16_BIT) { + uint16_t short_id = common_read_16_bit(rf_mac_setup->enhanced_ack_buffer.DstAddr); + if (short_id == device_ptr->ShortAddress) { + rf_mac_setup->ack_tx_possible = true; + } + } else if (rf_mac_setup->enhanced_ack_buffer.fcf_dsn.DstAddrMode == MAC_ADDR_MODE_64_BIT) { + if (memcmp(device_ptr->ExtAddress, rf_mac_setup->enhanced_ack_buffer.DstAddr, 8) == 0) { + rf_mac_setup->ack_tx_possible = true; + } + } + } + platform_exit_critical(); + return 0; } diff --git a/source/MAC/IEEE802_15_4/sw_mac.c b/source/MAC/IEEE802_15_4/sw_mac.c index ca52231bac2..a5b679eb284 100644 --- a/source/MAC/IEEE802_15_4/sw_mac.c +++ b/source/MAC/IEEE802_15_4/sw_mac.c @@ -197,6 +197,20 @@ int ns_sw_mac_fhss_register(mac_api_t *mac_api, fhss_api_t *fhss_api) return 0; } +int ns_sw_mac_fhss_unregister(mac_api_t *mac_api) +{ + if (!mac_api) { + return -1; + } + // Get a pointer to MAC setup structure + protocol_interface_rf_mac_setup_s *mac_setup = get_sw_mac_ptr_by_mac_api(mac_api); + if (!mac_setup) { + return -1; + } + mac_setup->fhss_api = NULL; + return 0; +} + struct fhss_api *ns_sw_mac_get_fhss_api(struct mac_api_s *mac_api) { if (!mac_api) { diff --git a/source/NWK_INTERFACE/protocol_core.c b/source/NWK_INTERFACE/protocol_core.c index 2d8c99f4c13..279bc7f0df6 100644 --- a/source/NWK_INTERFACE/protocol_core.c +++ b/source/NWK_INTERFACE/protocol_core.c @@ -603,6 +603,7 @@ static protocol_interface_info_entry_t *protocol_core_interface_6lowpan_entry_ge entry->mac_parameters->mac_prev_key_attribute_id = 0; entry->mac_parameters->mac_default_key_attribute_id = 1; entry->mac_parameters->mac_next_key_attribute_id = 2; + entry->mac_parameters->mac_default_key_index = 0; entry->beacon_cb = beacon_received; @@ -1116,10 +1117,10 @@ void nwk_bootsrap_state_update(arm_nwk_interface_status_type_e posted_event, pro default: mac_data_poll_protocol_poll_mode_disable(cur); if (!cur->rpl_domain) { - tr_debug("NON RPL Ready"); + tr_info("NON RPL Ready"); //nwk_protocol_poll_mode_disable(cur->nwk_id, 0); } else { - tr_debug("RPL Ready"); + tr_info("RPL Ready"); } } } else { diff --git a/source/RPL/rpl_control.c b/source/RPL/rpl_control.c index c6854e3f4e0..b17dce381e9 100644 --- a/source/RPL/rpl_control.c +++ b/source/RPL/rpl_control.c @@ -60,8 +60,8 @@ const uint8_t ADDR_LINK_LOCAL_ALL_RPL_NODES[16] = { 0xff, 0x02, [15] = 0x1a }; /* Sensible default limits for a 6LoWPAN-ND node */ -static size_t rpl_purge_threshold = 1 * 1024; -static size_t rpl_alloc_limit = 2 * 1024; // 0 means no limit +static size_t rpl_purge_threshold = 2 * 1024; +static size_t rpl_alloc_limit = 4 * 1024; // 0 means no limit static size_t rpl_alloc_total; #define RPL_ALLOC_OVERHEAD 8 @@ -190,6 +190,10 @@ void rpl_control_set_initial_dao_ack_wait(uint16_t timeout_in_ms) { rpl_policy_set_initial_dao_ack_wait(timeout_in_ms); } +void rpl_control_set_mrhof_parent_set_size(uint16_t parent_set_size) +{ + rpl_policy_set_mrhof_parent_set_size(parent_set_size); +} /* Send address registration to either specified address, or to non-registered address */ void rpl_control_register_address(protocol_interface_info_entry_t *interface, const uint8_t addr[16]) @@ -247,6 +251,56 @@ bool rpl_control_is_dodag_parent_candidate(protocol_interface_info_entry_t *inte return false; } +uint16_t rpl_control_candidate_list_size(protocol_interface_info_entry_t *interface, rpl_instance_t *rpl_instance) +{ + if (!interface->rpl_domain) { + return 0; + } + + return rpl_instance_address_candidate_count(rpl_instance, false); + +} + +uint16_t rpl_control_selected_parent_count(protocol_interface_info_entry_t *interface, rpl_instance_t *rpl_instance) +{ + if (!interface->rpl_domain) { + return 0; + } + + return rpl_instance_address_candidate_count(rpl_instance, true); + +} + + +bool rpl_control_probe_parent_candidate(protocol_interface_info_entry_t *interface, const uint8_t ll_addr[16]) +{ + if (!interface->rpl_domain) { + return false; + } + // go through instances and parents and check if they match the address. + ns_list_foreach(struct rpl_instance, instance, &interface->rpl_domain->instances) { + if (rpl_lookup_neighbour_by_ll_address(instance, ll_addr, interface->id)) { + return true; + } + } + return false; +} + +bool rpl_possible_better_candidate(struct protocol_interface_info_entry *interface, rpl_instance_t *rpl_instance, const uint8_t ll_addr[16], uint16_t candidate_rank, uint16_t etx) +{ + if (!interface->rpl_domain) { + return false; + } + + rpl_neighbour_t *neighbour = rpl_lookup_neighbour_by_ll_address(rpl_instance, ll_addr, interface->id); + if (!neighbour) { + return false; + } + + return rpl_instance_possible_better_candidate(rpl_instance, neighbour, candidate_rank, etx); + +} + uint16_t rpl_control_parent_candidate_list_size(protocol_interface_info_entry_t *interface, bool parent_list) { @@ -266,6 +320,13 @@ uint16_t rpl_control_parent_candidate_list_size(protocol_interface_info_entry_t return parent_list_size; } +void rpl_control_neighbor_delete_from_instance(protocol_interface_info_entry_t *interface, rpl_instance_t *instance, const uint8_t ll_addr[16]) +{ + rpl_neighbour_t *neighbour = rpl_lookup_neighbour_by_ll_address(instance, ll_addr, interface->id); + if (neighbour) { + rpl_delete_neighbour(instance, neighbour); + } +} void rpl_control_neighbor_delete(protocol_interface_info_entry_t *interface, const uint8_t ll_addr[16]) { @@ -274,14 +335,26 @@ void rpl_control_neighbor_delete(protocol_interface_info_entry_t *interface, con } // go through instances and delete address. ns_list_foreach(struct rpl_instance, instance, &interface->rpl_domain->instances) { + rpl_control_neighbor_delete_from_instance(interface, instance, ll_addr); + } +} - rpl_neighbour_t *neighbour = rpl_lookup_neighbour_by_ll_address(instance, ll_addr, interface->id); - if (neighbour) { - rpl_delete_neighbour(instance, neighbour); - } +bool rpl_control_find_worst_neighbor(protocol_interface_info_entry_t *interface, rpl_instance_t *rpl_instance, uint8_t ll_addr[static 16]) +{ + if (!interface->rpl_domain) { + return false; + } + + rpl_neighbour_t *neighbour = rpl_lookup_last_candidate_from_list(rpl_instance); + if (neighbour) { + memcpy(ll_addr, rpl_neighbour_ll_address(neighbour), 16); + return true; } + + return false; } + /* Address changes need to trigger DAO target re-evaluation */ static void rpl_control_addr_notifier(struct protocol_interface_info_entry *interface, const if_address_entry_t *addr, if_address_callback_t reason) { @@ -307,19 +380,24 @@ static void rpl_control_addr_notifier(struct protocol_interface_info_entry *inte static void rpl_control_etx_change_callback(int8_t nwk_id, uint16_t previous_etx, uint16_t current_etx, uint8_t attribute_index) { - (void)previous_etx; - (void)current_etx; protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(nwk_id); if (!cur || !cur->rpl_domain) { return; } + // ETX is "better" if now lower, or previous was "unknown" and new isn't infinite + bool better = current_etx < previous_etx || (previous_etx == 0 && current_etx != 0xffff); + rpl_domain_t *domain = cur->rpl_domain; uint16_t delay = rpl_policy_etx_change_parent_selection_delay(domain); - tr_debug("Triggering parent selection due to ETX change on neigh index %u, etx %u", attribute_index, current_etx); + tr_debug("Triggering parent selection due to ETX %s on neigh index %u, etx %u", better ? "better" : "worse", attribute_index, current_etx); + rpl_dodag_t *dodag = NULL; ns_list_foreach(rpl_instance_t, instance, &domain->instances) { - rpl_instance_trigger_parent_selection(instance, delay); + if (better) { + dodag = rpl_instance_current_dodag(instance); + } + rpl_instance_trigger_parent_selection(instance, delay, dodag); if (rpl_instance_am_root(instance)) { rpl_downward_paths_invalidate(instance); } @@ -339,6 +417,7 @@ rpl_domain_t *rpl_control_create_domain(void) domain->callback = NULL; domain->cb_handle = NULL; domain->force_leaf = false; + domain->process_routes = true; ns_list_add_to_start(&rpl_domains, domain); addr_notification_register(rpl_control_addr_notifier); @@ -495,8 +574,13 @@ rpl_dodag_t *rpl_control_create_dodag_root(rpl_domain_t *domain, uint8_t instanc rpl_dodag_t *dodag = rpl_lookup_dodag(instance, dodagid); if (dodag) { - tr_error("Root DODAG already exists"); - return NULL; + if (rpl_dodag_am_root(dodag)) { + tr_error("Root DODAG already exists"); + return NULL; + } + + // Delete non root information and recreate dodag + rpl_delete_dodag(dodag); } dodag = rpl_create_dodag(instance, dodagid, g_mop_prf); if (!dodag) { @@ -547,13 +631,16 @@ void rpl_control_increment_dtsn(rpl_dodag_t *dodag) //rpl_dodag_inconsistency(dodag); currently implied by rpl_dodag_increment_dtsn } -void rpl_control_increment_dodag_version(rpl_dodag_t *dodag) +uint8_t rpl_control_increment_dodag_version(rpl_dodag_t *dodag) { + uint8_t new_version = 240; if (rpl_dodag_am_root(dodag)) { - uint8_t new_version = rpl_seq_inc(rpl_dodag_get_version_number_as_root(dodag)); + new_version = rpl_seq_inc(rpl_dodag_get_version_number_as_root(dodag)); rpl_dodag_set_version_number_as_root(dodag, new_version); } + return new_version; } + void rpl_control_update_dodag_config(struct rpl_dodag *dodag, const rpl_dodag_conf_t *conf) { @@ -586,6 +673,10 @@ void rpl_control_force_leaf(rpl_domain_t *domain, bool leaf) } } } +void rpl_control_process_routes(rpl_domain_t *domain, bool process_routes) +{ + domain->process_routes = process_routes; +} /* Check whether the options section of a RPL control message is well-formed */ static bool rpl_control_options_well_formed(const uint8_t *dptr, uint_fast16_t dlen) @@ -855,7 +946,6 @@ static void rpl_control_process_route_options(rpl_instance_t *instance, rpl_doda } rpl_dodag_update_dio_route(dodag, prefix, prefix_len, flags, lifetime, true); } - /* We do not purge unadvertised routes. Thus if the root wants to purge * a route before its lifetime is up, stopping advertising it is not * sufficient, it has to advertise it with low or zero lifetime. This fits @@ -975,8 +1065,9 @@ static buffer_t *rpl_control_dio_handler(protocol_interface_info_entry_t *cur, r } } - /* Never listen to nodes in a DODAG we're rooting */ - if (rpl_dodag_am_root(dodag)) { + /* Never listen to nodes in a DODAG we're rooting or were root*/ + if (rpl_dodag_am_root(dodag) || + rpl_dodag_was_root(dodag)) { /* TODO - if version is newer or unordered, increment our version to be higher? */ /* Old code had this trick - actually, would need to go further. Want to listen first, then use a higher * than existing. */ @@ -1009,7 +1100,7 @@ static buffer_t *rpl_control_dio_handler(protocol_interface_info_entry_t *cur, r const rpl_dodag_conf_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)) { + if (domain->new_parent_add && !domain->new_parent_add(buf->src_sa.address, domain->cb_handle, instance, rank)) { goto invalid_parent; } rpl_control_transmit_dis(domain, cur, RPL_SOLINFO_PRED_DODAGID | RPL_SOLINFO_PRED_INSTANCEID, instance_id, dodagid, 0, buf->src_sa.address); @@ -1043,15 +1134,21 @@ static buffer_t *rpl_control_dio_handler(protocol_interface_info_entry_t *cur, r /* Now we create the neighbour, if we don't already have a record */ if (!neighbour) { + + if (domain->new_parent_add) { + + if (!domain->new_parent_add(buf->src_sa.address, domain->cb_handle, instance, rank)) { + goto invalid_parent; + } + } + neighbour = rpl_create_neighbour(version, buf->src_sa.address, cur->id, g_mop_prf, dtsn); //Call Here new parent create if (!neighbour) { goto invalid_parent; } - if (domain->new_parent_add && !domain->new_parent_add(buf->src_sa.address, domain->cb_handle)) { - goto invalid_parent; - } + } @@ -1182,7 +1279,7 @@ void rpl_control_transmit_dio(rpl_domain_t *domain, protocol_interface_info_entr const rpl_dio_route_list_t *routes = rpl_dodag_get_route_list(dodag); const prefix_list_t *prefixes = rpl_dodag_get_prefix_list(dodag); - tr_debug("transmit dio, rank: %x", rank); + tr_info("transmit dio, rank: %x", rank); protocol_interface_info_entry_t *downstream_if = protocol_stack_interface_info_get_by_id(domain->non_storing_downstream_interface); length = 24; if (conf) { @@ -1770,12 +1867,24 @@ static void rpl_domain_print(const rpl_domain_t *domain, route_print_fn_t *print void rpl_control_print(route_print_fn_t *print_fn) { - print_fn("RPL memory usage %zu", rpl_alloc_total); + unsigned t = protocol_core_monotonic_time % 10; + unsigned s_full = protocol_core_monotonic_time / 10; + unsigned m = s_full / 60; + unsigned s = s_full % 60; + unsigned h = m / 60; + m %= 60; + // %zu doesn't work on some Mbed toolchains + print_fn("Time %02u:%02u:%02u.%u (%u.%u) RPL memory usage %" PRIu32, h, m, s, t, s_full, t, (uint32_t) rpl_alloc_total); ns_list_foreach(rpl_domain_t, domain, &rpl_domains) { rpl_domain_print(domain, print_fn); } } +uint8_t rpl_policy_mrhof_parent_set_size_get(const rpl_domain_t *domain) +{ + return rpl_policy_mrhof_parent_set_size(domain); +} + #ifdef RPL_STRUCTURES_H_ #error "rpl_structures.h should not be included by rpl_control.c" #endif diff --git a/source/RPL/rpl_control.h b/source/RPL/rpl_control.h index 7569bac9449..464e5c2a832 100644 --- a/source/RPL/rpl_control.h +++ b/source/RPL/rpl_control.h @@ -42,7 +42,8 @@ typedef void rpl_domain_callback_t(rpl_event_t event, void *handle); typedef void rpl_prefix_callback_t(struct prefix_entry_t *prefix, void *handle, uint8_t *parent_link_local); -typedef bool rpl_new_parent_callback_t(uint8_t *ll_parent_address, void *handle); +typedef bool rpl_new_parent_callback_t(uint8_t *ll_parent_address, void *handle, struct rpl_instance *instance, uint16_t candidate_rank); + typedef struct rpl_domain { NS_LIST_HEAD_INCOMPLETE(struct rpl_instance) instances; @@ -54,6 +55,8 @@ typedef struct rpl_domain { int8_t non_storing_downstream_interface; /* As part of shutdown, we can force entering leaf mode */ bool force_leaf; + /* if false routes are not set to routing table, instead default route is added for DODAGID */ + bool process_routes; rpl_domain_callback_t *callback; rpl_prefix_callback_t *prefix_cb; rpl_new_parent_callback_t *new_parent_add; @@ -129,13 +132,15 @@ struct rpl_dodag *rpl_control_create_dodag_root(rpl_domain_t *domain, uint8_t in void rpl_control_delete_dodag_root(rpl_domain_t *domain, struct rpl_dodag *dodag); void rpl_control_update_dodag_route(struct rpl_dodag *dodag, const uint8_t *prefix, uint8_t prefix_len, uint8_t flags, uint32_t lifetime, bool age); void rpl_control_update_dodag_prefix(struct rpl_dodag *dodag, const uint8_t *prefix, uint8_t prefix_len, uint8_t flags, uint32_t lifetime, uint32_t preftime, bool age); -void rpl_control_increment_dodag_version(struct rpl_dodag *dodag); +uint8_t rpl_control_increment_dodag_version(struct rpl_dodag *dodag); void rpl_control_update_dodag_config(struct rpl_dodag *dodag, const rpl_dodag_conf_t *conf); void rpl_control_set_dodag_pref(struct rpl_dodag *dodag, uint8_t pref); void rpl_control_increment_dtsn(struct rpl_dodag *dodag); /* Force leaf behaviour on a domain - useful before shutdown, and in conjunction with poison */ void rpl_control_force_leaf(rpl_domain_t *domain, bool leaf); +/*Process routes from DIOs and add those as real routes. if routes are not processed assume DODAGID as default route*/ +void rpl_control_process_routes(rpl_domain_t *domain, bool process_routes); /* Manually send poison on all existing instances a few times */ void rpl_control_poison(rpl_domain_t *domain, uint8_t poison_count); @@ -146,20 +151,28 @@ void rpl_control_delete_domain(rpl_domain_t *domain); void rpl_control_set_domain_on_interface(struct protocol_interface_info_entry *cur, rpl_domain_t *domain, bool downstream); void rpl_control_remove_domain_from_interface(struct protocol_interface_info_entry *cur); void rpl_control_free_domain_instances_from_interface(struct protocol_interface_info_entry *cur); -void rpl_control_set_callback(rpl_domain_t *domain, rpl_domain_callback_t callback, rpl_prefix_callback_t prefix_learn_cb, rpl_new_parent_callback_t new_parent_add, void *cb_handle); +void rpl_control_set_callback(rpl_domain_t *domain, rpl_domain_callback_t callback, rpl_prefix_callback_t prefix_learn_cb, rpl_new_parent_callback_t new_parent_add, void *cb_handle); /* Target publishing */ void rpl_control_publish_host_address(rpl_domain_t *domain, const uint8_t addr[16], uint32_t lifetime); void rpl_control_unpublish_address(rpl_domain_t *domain, const uint8_t addr[16]); bool rpl_control_is_dodag_parent(struct protocol_interface_info_entry *interface, const uint8_t ll_addr[16]); bool rpl_control_is_dodag_parent_candidate(struct protocol_interface_info_entry *interface, const uint8_t ll_addr[16], uint16_t candidate_cmp_limiter); -uint16_t rpl_control_parent_candidate_list_size(struct protocol_interface_info_entry *interface, bool parent_list); +bool rpl_control_probe_parent_candidate(struct protocol_interface_info_entry *interface, const uint8_t ll_addr[16]); +bool rpl_possible_better_candidate(struct protocol_interface_info_entry *interface, struct rpl_instance *rpl_instance, const uint8_t ll_addr[16], uint16_t candidate_rank, uint16_t etx); +uint16_t rpl_control_parent_candidate_list_size(struct protocol_interface_info_entry *interface, bool parent_list); +uint16_t rpl_control_candidate_list_size(struct protocol_interface_info_entry *interface, struct rpl_instance *rpl_instance); +uint16_t rpl_control_selected_parent_count(struct protocol_interface_info_entry *interface, struct rpl_instance *rpl_instance); void rpl_control_neighbor_delete(struct protocol_interface_info_entry *interface, const uint8_t ll_addr[16]); +void rpl_control_neighbor_delete_from_instance(struct protocol_interface_info_entry *interface, struct rpl_instance *rpl_instance, const uint8_t ll_addr[16]); +bool rpl_control_find_worst_neighbor(struct protocol_interface_info_entry *interface, struct rpl_instance *rpl_instance, uint8_t ll_addr[16]); + /* Parent link confirmation API extension */ void rpl_control_request_parent_link_confirmation(bool requested); void rpl_control_set_dio_multicast_min_config_advertisment_count(uint8_t min_count); void rpl_control_set_dao_retry_count(uint8_t count); void rpl_control_set_initial_dao_ack_wait(uint16_t timeout_in_ms); +void rpl_control_set_mrhof_parent_set_size(uint16_t parent_set_size); void rpl_control_register_address(struct protocol_interface_info_entry *interface, const uint8_t addr[16]); void rpl_control_address_register_done(struct protocol_interface_info_entry *interface, const uint8_t ll_addr[16], uint8_t status); @@ -176,6 +189,7 @@ bool rpl_control_read_dodag_info(const struct rpl_instance *instance, struct rpl const rpl_dodag_conf_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); #else /* HAVE_RPL */ @@ -185,6 +199,8 @@ uint16_t rpl_control_current_rank(const struct rpl_instance *instance); #define rpl_control_free_domain_instances_from_interface(cur) ((void) 0) #define rpl_control_register_address(interface, addr) ((void) 0) #define rpl_control_address_register_done(interface, ll_addr, status) ((void) 0) +#define rpl_policy_mrhof_parent_set_size_get(domain) (0) +#define rpl_control_set_mrhof_parent_set_size(parent_set_size) #endif /* HAVE_RPL */ diff --git a/source/RPL/rpl_downward.c b/source/RPL/rpl_downward.c index 607cca6168a..6f7a5dbfcb5 100644 --- a/source/RPL/rpl_downward.c +++ b/source/RPL/rpl_downward.c @@ -545,8 +545,7 @@ static rpl_dao_target_t *rpl_instance_choose_target_to_assign(rpl_instance_t *in */ ns_list_foreach(rpl_neighbour_t, neighbour, &instance->candidate_neighbours) { if (neighbour->dao_path_control & unassigned_pc) { - unassigned_pc &= neighbour->dao_path_control; - *path_control = unassigned_pc; + *path_control = neighbour->dao_path_control; *parent = neighbour; return target; } @@ -561,14 +560,7 @@ static rpl_dao_target_t *rpl_instance_choose_target_to_assign(rpl_instance_t *in } } - /* If looking for a follow-up target, final path control must match */ - if (t1) { - if (unassigned_pc != *path_control) { - continue; - } - } else { - *path_control = unassigned_pc; - } + *path_control = target->path_control; return target; } @@ -1786,7 +1778,7 @@ static bool rpl_instance_push_address_registration(protocol_interface_info_entry if (!buf) { return false; } - tr_debug("Send ARO %s to %s", trace_ipv6(addr->address), trace_ipv6(neighbour->ll_address)); + tr_info("Send ARO %s to %s", trace_ipv6(addr->address), trace_ipv6(neighbour->ll_address)); protocol_push(buf); return true; } @@ -1811,6 +1803,8 @@ static void rpl_instance_address_registration_cancel(rpl_instance_t *instance) instance->wait_response = NULL; instance->pending_neighbour_confirmation = false; instance->delay_dao_timer = 0; + instance->dao_in_transit = false; + instance->dao_retry_timer = 0; } void rpl_instance_parent_address_reg_timer_update(rpl_instance_t *instance, uint16_t seconds) diff --git a/source/RPL/rpl_mrhof.c b/source/RPL/rpl_mrhof.c index bfff5aa0004..be3fd9a8229 100644 --- a/source/RPL/rpl_mrhof.c +++ b/source/RPL/rpl_mrhof.c @@ -45,12 +45,14 @@ static void rpl_mrhof_parent_selection(rpl_instance_t *instance); static uint16_t rpl_mrhof_path_cost_through_neighbour(const rpl_neighbour_t *neighbour); static bool rpl_mrhof_neighbour_acceptable(const rpl_instance_t *instance, const rpl_neighbour_t *neighbour); +static bool rpl_mrhof_possible_better_candidate(const rpl_instance_t *instance, const rpl_neighbour_t *existing, uint16_t rank, uint16_t etx); static rpl_objective_t rpl_mrhof = { .ocp = RPL_OCP_MRHOF, .parent_selection = rpl_mrhof_parent_selection, .path_cost = rpl_mrhof_path_cost_through_neighbour, .neighbour_acceptable = rpl_mrhof_neighbour_acceptable, + .possible_better_candidate = rpl_mrhof_possible_better_candidate, }; typedef struct rpl_of0_params { @@ -94,6 +96,26 @@ static bool rpl_mrhof_neighbour_acceptable(const rpl_instance_t *instance, const return rpl_mrhof_link_metric_to_neighbour(neighbour) <= rpl_policy_mrhof_max_link_metric(instance->domain); } +static bool rpl_mrhof_possible_better_candidate(const rpl_instance_t *instance, const rpl_neighbour_t *existing, uint16_t rank, uint16_t etx) +{ + uint16_t existing_path = rpl_mrhof_path_cost_through_neighbour(existing); + // Optimistically assume we could get a perfect link to this new person + // But add hysteresis to avoid switching unless potentially worthwhile + // (Compare rpl_mrhof_etx which assumes poor for unknown as a sort of hysteresis) + // Think: could actually use rpl_mrhof_etx here to get an existing ETX estimate + // (except that gives infinite if no current link, would want a variant that checks + // blacklist records for remembered poor ETX) + uint16_t threshold = rpl_policy_mrhof_parent_switch_threshold(instance->domain); + if (etx == 0) { + etx = 128; + } else if (etx >= (0xffff - threshold)) { + return false; + } + + etx += threshold; + uint16_t potential_path_with_hysteresis = rpl_rank_add(rank, etx); + return potential_path_with_hysteresis <= existing_path; +} /* Given a preferred parent, we are only permitted to stretch our above the * path cost through that parent by a certain (policy) amount to accommodate a diff --git a/source/RPL/rpl_objective.h b/source/RPL/rpl_objective.h index 67c35fd7c80..7e8293a396a 100644 --- a/source/RPL/rpl_objective.h +++ b/source/RPL/rpl_objective.h @@ -28,9 +28,12 @@ typedef struct rpl_objective { uint16_t ocp; /* Run the parent selection algorithm - see rpl_of0.c for detailed info */ void (*parent_selection)(struct rpl_instance *); - /* Return the path cost of a neighbour (for debug prints only) */ + /* Return the path cost of a neighbour */ uint16_t (*path_cost)(const struct rpl_neighbour *); bool (*neighbour_acceptable)(const struct rpl_instance *, const struct rpl_neighbour *); + /* Could someone with specified rank be a significantly better candidate than the existing one? */ + /* (In future, this API could be extended to pass a metric pointer as well as rank) */ + bool (*possible_better_candidate)(const struct rpl_instance *, const struct rpl_neighbour *existing, uint16_t rank, uint16_t etx); ns_list_link_t link; } rpl_objective_t; diff --git a/source/RPL/rpl_of0.c b/source/RPL/rpl_of0.c index aa6927c1f16..bfdee2a4962 100644 --- a/source/RPL/rpl_of0.c +++ b/source/RPL/rpl_of0.c @@ -42,12 +42,14 @@ static void rpl_of0_parent_selection(rpl_instance_t *instance); static uint16_t rpl_of0_rank_through_neighbour(const rpl_neighbour_t *neighbour); static bool rpl_of0_neighbour_acceptable(const rpl_instance_t *instance, const rpl_neighbour_t *neighbour); +static bool rpl_of0_possible_better_candidate(const rpl_instance_t *instance, const rpl_neighbour_t *existing, uint16_t rank, uint16_t etx); static rpl_objective_t rpl_of0 = { .ocp = RPL_OCP_OF0, .parent_selection = rpl_of0_parent_selection, .path_cost = rpl_of0_rank_through_neighbour, .neighbour_acceptable = rpl_of0_neighbour_acceptable, + .possible_better_candidate = rpl_of0_possible_better_candidate, }; #define DEFAULT_STEP_OF_RANK 3 @@ -115,6 +117,14 @@ static uint16_t rpl_of0_rank_through_neighbour(const rpl_neighbour_t *neighbour) return rpl_rank_add(neighbour->rank, rpl_of0_rank_increase(neighbour)); } +static bool rpl_of0_possible_better_candidate(const rpl_instance_t *instance, const rpl_neighbour_t *existing, uint16_t rank, uint16_t etx) +{ + (void)etx; + uint16_t existing_path = rpl_of0_rank_through_neighbour(existing); + uint16_t potential_path_with_hysteresis = rpl_rank_add(rank, 2 * rpl_policy_of0_rank_factor(instance->domain) * existing->dodag_version->dodag->config.min_hop_rank_increase); + return potential_path_with_hysteresis <= existing_path; +} + /* Given a preferred parent, we are only permitted to stretch our above the * path cost through that parent by a certain (policy) amount to accommodate a * bigger parent set. diff --git a/source/RPL/rpl_policy.c b/source/RPL/rpl_policy.c index ec581c8bb42..f8b25d86f19 100644 --- a/source/RPL/rpl_policy.c +++ b/source/RPL/rpl_policy.c @@ -39,7 +39,7 @@ static int8_t rpl_policy_dao_retry_count_conf = 0; static int16_t rpl_policy_dao_initial_timeout_conf = 20; // Default is 2 seconds 100ms ticks static uint16_t rpl_policy_dio_validity_period_hysteresis = 0x0180; //Fixed Point 1.5 static uint8_t rpl_policy_multicast_config_min_advertisment_count = 0; - +static uint8_t rpl_policy_mrhof_parent_set_size_conf = 3; // default parent set size /* TODO - application API to control when to join new instances / DODAGs * @@ -147,7 +147,7 @@ int8_t rpl_policy_dao_retry_count() /* Given the next-hop address from a source routing header, which interface, * if any, should we assume that next hop is on? */ -#define ETX_SRH_THRESHOLD 0x800 /* 8.8 fixed-point, so 4 */ +#define ETX_SRH_THRESHOLD 0x400 /* 8.8 fixed-point, so 4 */ int8_t rpl_policy_srh_next_hop_interface(rpl_domain_t *domain, int8_t if_id, const uint8_t *next_hop) { if (domain->non_storing_downstream_interface != -1) { @@ -326,11 +326,16 @@ uint_fast8_t rpl_policy_of0_max_backup_successors(const rpl_domain_t *domain) return 1; } +void rpl_policy_set_mrhof_parent_set_size(uint8_t parent_set_size) +{ + rpl_policy_mrhof_parent_set_size_conf = parent_set_size; +} + uint_fast8_t rpl_policy_mrhof_parent_set_size(const rpl_domain_t *domain) { (void)domain; - return 3; + return rpl_policy_mrhof_parent_set_size_conf; } uint16_t rpl_policy_mrhof_max_rank_stretch_for_extra_parents(const rpl_domain_t *domain) diff --git a/source/RPL/rpl_policy.h b/source/RPL/rpl_policy.h index c51adc81cd1..13e25c492ca 100644 --- a/source/RPL/rpl_policy.h +++ b/source/RPL/rpl_policy.h @@ -59,6 +59,7 @@ uint_fast8_t rpl_policy_of0_rank_factor(const rpl_domain_t *domain); bool rpl_policy_of0_dodag_preference_supersedes_grounded(const rpl_domain_t *domain); uint_fast8_t rpl_policy_of0_max_backup_successors(const rpl_domain_t *domain); +void rpl_policy_set_mrhof_parent_set_size(uint8_t parent_set_size); uint_fast8_t rpl_policy_mrhof_parent_set_size(const rpl_domain_t *domain); uint16_t rpl_policy_mrhof_max_link_metric(const rpl_domain_t *domain); uint16_t rpl_policy_mrhof_parent_switch_threshold(const rpl_domain_t *domain); diff --git a/source/RPL/rpl_structures.h b/source/RPL/rpl_structures.h index 1d4dcc0c377..aadbc60c28e 100644 --- a/source/RPL/rpl_structures.h +++ b/source/RPL/rpl_structures.h @@ -32,10 +32,6 @@ struct rpl_objective; /* Descriptor for a RPL neighbour within a DODAG - * - * The neighbour is normally associated with a DODAG Version, but may not be, - * if the version has been retired, and we haven't since heard from that - * neighbour. In that case dodag_version is NULL. * * Note that global address is only needed with downward routes, but I don't * think it's worth optimising for an "upward-only" build. (Unless to be a RPL @@ -45,7 +41,7 @@ struct rpl_objective; * first in the instance candidate_neighbour list, in order of preference. */ struct rpl_neighbour { - rpl_dodag_version_t *dodag_version; // Back pointer to DODAG Version (may be NULL, if not dodag_parent) + rpl_dodag_version_t *dodag_version; // Back pointer to DODAG Version uint8_t ll_address[16]; // Link-local address (source of DIO) uint8_t global_address[16]; // Global address (from DIO RIO) bool dodag_parent: 1; // This is a DODAG parent (if true, dodag_version may not be NULL) @@ -87,10 +83,11 @@ struct rpl_dodag { rpl_dodag_conf_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 */ bool leaf: 1; /* We are a leaf in this DODAG (by policy) */ bool have_config: 1; /* We have the config */ bool used: 1; /* We have ever been a member of this DODAG? */ - uint8_t new_config_advertisment_count; /* We have advertiment new config at multicasti DIO */ + uint8_t new_config_advertisment_count; /* We have advertiment new config at multicasti DIO max updated value is 0xfe*/ NS_LIST_HEAD(rpl_dodag_version_t, link) versions; /* List of DODAG versions (newest first) */ prefix_list_t prefixes; /* Prefixes advertised in DIO PIOs */ rpl_dio_route_list_t routes; /* Routes advertised in DIO RIOs*/ diff --git a/source/RPL/rpl_upward.c b/source/RPL/rpl_upward.c index d3e4720b041..99377e6150c 100644 --- a/source/RPL/rpl_upward.c +++ b/source/RPL/rpl_upward.c @@ -74,6 +74,8 @@ static NS_LIST_DEFINE(rpl_candidate_neighbour_set, rpl_neighbour_t, candidate_ne static void rpl_instance_remove_parents(rpl_instance_t *instance); static void rpl_instance_remove_system_routes_through_parent(rpl_instance_t *instance, rpl_neighbour_t *parent); static void rpl_dodag_update_system_route(rpl_dodag_t *dodag, rpl_dio_route_t *route); +static rpl_neighbour_t *rpl_instance_choose_worst_neighbour(const rpl_instance_t *instance); +static uint32_t rpl_dio_imax_time_calculate(uint16_t Imax, uint16_t fixed_point); /* Rank comparison, and DAGRank(rank) */ uint16_t nrpl_dag_rank(const rpl_dodag_t *dodag, uint16_t rank) @@ -283,6 +285,16 @@ rpl_neighbour_t *rpl_instance_preferred_parent(const rpl_instance_t *instance) return neighbour; } +uint16_t rpl_instance_candidate_rank(const rpl_neighbour_t *candidate) +{ + return candidate->rank; +} + +bool rpl_instance_possible_better_candidate(const rpl_instance_t *instance, rpl_neighbour_t *replacing, uint16_t candidate_rank, uint16_t etx) +{ + return instance->of->possible_better_candidate(instance, replacing, candidate_rank, etx); +} + /* If we're a member of a DODAG Version matching the predicate in this instance, * return it. Mainly used for handling DODAG Information Solicitations. */ @@ -340,10 +352,19 @@ void rpl_instance_force_leaf(rpl_instance_t *instance) instance->current_rank = RPL_RANK_INFINITE; } -void rpl_instance_trigger_parent_selection(rpl_instance_t *instance, uint16_t delay) +void rpl_instance_trigger_parent_selection(rpl_instance_t *instance, uint16_t delay, rpl_dodag_t *dodag) { + /* When "improving", let us have a minimum trigger time based on Imin, for large networks */ + if (dodag) { + //Convert imin 100ms tick to seconds + uint16_t i_min_delay = dodag->dio_timer_params.Imin / 10; + if (i_min_delay > delay) { + delay = i_min_delay; + } + } if (instance->parent_selection_timer == 0 || instance->parent_selection_timer > delay) { - instance->parent_selection_timer = randLIB_randomise_base(delay, 0x7333, 0x8CCD) /* +/- 10% */; + instance->parent_selection_timer = randLIB_randomise_base(delay, 0x8000, 0x999A) /* Random between delay * 1.0-1.2 */; + tr_debug("Timed parent triggered %u", instance->parent_selection_timer); } } @@ -390,6 +411,15 @@ rpl_neighbour_t *rpl_lookup_neighbour_by_ll_address(const rpl_instance_t *instan return NULL; } +rpl_neighbour_t *rpl_lookup_last_candidate_from_list(const rpl_instance_t *instance) +{ + rpl_neighbour_t *neighbour = rpl_instance_choose_worst_neighbour(instance); + if (neighbour && neighbour->considered && !neighbour->dodag_parent) { + return neighbour; + } + return NULL; +} + rpl_neighbour_t *rpl_create_neighbour(rpl_dodag_version_t *version, const uint8_t *addr, int8_t if_id, uint8_t g_mop_prf, uint8_t dtsn) { /* Should gate higher-rank neighbours here - ignore higher-rank neighbours @@ -563,7 +593,7 @@ void rpl_delete_dodag_version(rpl_dodag_version_t *version) // triggering poison immediately. // Give parent selection a chance to select another version (but will it have any info on-hand?) instance->current_dodag_version = NULL; - rpl_instance_trigger_parent_selection(instance, 5); + rpl_instance_trigger_parent_selection(instance, 5, NULL); } ns_list_foreach_safe(rpl_neighbour_t, neighbour, &instance->candidate_neighbours) { @@ -638,6 +668,7 @@ rpl_dodag_t *rpl_create_dodag(rpl_instance_t *instance, const uint8_t *dodagid, memcpy(dodag->id, dodagid, 16); dodag->leaf = false; dodag->root = false; + dodag->was_root = false; dodag->have_config = false; dodag->used = false; dodag->g_mop_prf = g_mop_prf; @@ -678,15 +709,9 @@ void rpl_delete_dodag_root(rpl_dodag_t *dodag) { // This should trigger immediate poison rpl_instance_set_dodag_version(dodag->instance, NULL, RPL_RANK_INFINITE); - // Deleting DODAG is not ideal - we will just pick up adverts from our - // former children, and recreate, possibly violating the MaxRankIncrease. - // Should retain DODAG version info and just unset root flag, which will - // limit what happens when we hear adverts. - // Problem is rpl_control_create_dodag_root which can't handle the - // case where DODAG already exists. This would always be a problem if - // we'd heard adverts in between delete and create, but would be an instant - // problem without this delete. Need to fix. - rpl_delete_dodag(dodag); + // Retain DODAG version info and just unset root flag + // We have was_root still set which will drop adverts for this dodag. + dodag->root = false; } /* Convert RPL configuration to generic trickle parameters. Returns true if @@ -792,6 +817,7 @@ void rpl_dodag_set_root(rpl_dodag_t *dodag, bool root) dodag->root = root; if (root) { rpl_instance_remove_parents(dodag->instance); + dodag->was_root = true; } else { rpl_instance_run_parent_selection(dodag->instance); } @@ -803,6 +829,11 @@ bool rpl_dodag_am_root(const rpl_dodag_t *dodag) { return dodag->root; } + +bool rpl_dodag_was_root(const rpl_dodag_t *dodag) +{ + return dodag->was_root; +} #endif void rpl_dodag_set_leaf(rpl_dodag_t *dodag, bool leaf) @@ -1163,10 +1194,20 @@ static rpl_neighbour_t *rpl_instance_choose_worst_neighbour(const rpl_instance_t { rpl_neighbour_t *worst = NULL; bool worst_acceptable = false; + bool worst_old = false; /* Parents will be first - loop backwards so we take non-parents first */ ns_list_foreach_reverse(rpl_neighbour_t, neighbour, &instance->candidate_neighbours) { bool acceptable = instance->of->neighbour_acceptable(instance, neighbour); + bool old; + if (!neighbour->dodag_version) { + old = true; + } else { + uint32_t age = protocol_core_monotonic_time - neighbour->dio_timestamp; + uint32_t age_threshold = rpl_dio_imax_time_calculate(neighbour->dodag_version->dodag->dio_timer_params.Imax, + rpl_policy_dio_validity_period(instance->domain)); + old = age > age_threshold; + } if (!worst) { goto new_worst; } @@ -1176,6 +1217,13 @@ static rpl_neighbour_t *rpl_instance_choose_worst_neighbour(const rpl_instance_t break; } + /* Prefer neighbours with DODAG version */ + if (neighbour->dodag_version && !worst->dodag_version) { + continue; + } else if (!neighbour->dodag_version && worst->dodag_version) { + goto new_worst; + } + /* Prefer to purge "unacceptable" neighbours according to OF */ if (acceptable && !worst_acceptable) { continue; @@ -1183,18 +1231,24 @@ static rpl_neighbour_t *rpl_instance_choose_worst_neighbour(const rpl_instance_t goto new_worst; } - /* Prefer to purge least-recently-heard-from */ - uint32_t neighbour_age = protocol_core_monotonic_time - neighbour->dio_timestamp; - uint32_t worst_age = protocol_core_monotonic_time - worst->dio_timestamp; - if (neighbour_age <= worst_age) { + /* Prefer to purge old neighbours */ + if (old && !worst_old) { continue; - } else { + } else if (!old && worst_old) { goto new_worst; } + /* Tiebreak by path cost, assuming we have dodag_version */ + if (neighbour->dodag_version && instance->of) { + /* worst must also have version to reach this tiebreak */ + if (instance->of->path_cost(neighbour) <= instance->of->path_cost(worst)) { + continue; + } + } new_worst: worst = neighbour; worst_acceptable = acceptable; + worst_old = old; } return worst; @@ -1225,24 +1279,19 @@ bool rpl_instance_purge(rpl_instance_t *instance) */ rpl_neighbour_t *neighbour = rpl_instance_choose_worst_neighbour(instance); if (neighbour && neighbour->considered && !neighbour->dodag_parent && neighbour->dao_path_control == 0) { + tr_debug("Candidate Purge: Remove %s", trace_ipv6(neighbour->ll_address)); rpl_delete_neighbour(instance, neighbour); return true; } return false; } -void rpl_instance_neighbours_changed(rpl_instance_t *instance, const rpl_dodag_t *dodag) +void rpl_instance_neighbours_changed(rpl_instance_t *instance, rpl_dodag_t *dodag) { instance->neighbours_changed = true; uint16_t delay = rpl_policy_dio_parent_selection_delay(instance->domain); - if (dodag) { - //Convert imin 100ms tick to seconds - uint16_t i_min_delay = dodag->dio_timer_params.Imin / 10; - if (i_min_delay > delay) { - delay = i_min_delay; - } - } - rpl_instance_trigger_parent_selection(instance, delay); + + rpl_instance_trigger_parent_selection(instance, delay, dodag); } static void rpl_instance_remove_parents(rpl_instance_t *instance) @@ -1315,6 +1364,10 @@ void rpl_dodag_update_implicit_system_routes(rpl_dodag_t *dodag, rpl_neighbour_t /* Also add a specific route to the DODAGID */ ipv6_route_add_metric(dodag->id, 128, parent->interface_id, parent->ll_address, ROUTE_RPL_ROOT, parent, dodag->instance->id, default_lifetime, metric); + /* Check if we assume default route to DODAGID */ + if (!dodag->instance->domain->process_routes) { + ipv6_route_add_metric(NULL, 0, parent->interface_id, parent->ll_address, ROUTE_RPL_ROOT, parent, dodag->instance->id, default_lifetime, metric); + } } /* Called when a DIO RIO route has been updated (but not the parent list) */ @@ -1323,9 +1376,13 @@ static void rpl_dodag_update_system_route(rpl_dodag_t *dodag, rpl_dio_route_t *r if (!rpl_dodag_is_current(dodag)) { return; } - rpl_instance_t *instance = dodag->instance; + if (!instance->domain->process_routes) { + // We dont add actual routes and only create default route throuh DODAGID + return; + } + ns_list_foreach(rpl_neighbour_t, neighbour, &instance->candidate_neighbours) { if (neighbour->dodag_parent) { rpl_instance_update_system_dio_route(instance, neighbour, route); @@ -1340,6 +1397,11 @@ static void rpl_instance_update_system_routes_through_parent(rpl_instance_t *ins rpl_dodag_update_implicit_system_routes(dodag, parent); + if (!instance->domain->process_routes) { + // We dont add actual routes and only create default route through DODAGID + return; + } + /* Then add the specific routes listed in the DIO as ROUTE_RPL_DIO */ ns_list_foreach(rpl_dio_route_t, route, &dodag->routes) { rpl_instance_update_system_dio_route(instance, parent, route); @@ -1381,13 +1443,15 @@ void rpl_instance_run_parent_selection(rpl_instance_t *instance) return; } - if (instance->current_dodag_version && instance->current_dodag_version->dodag->root) { + if (instance->current_dodag_version && + (instance->current_dodag_version->dodag->root || instance->current_dodag_version->dodag->was_root)) { return; } ns_list_foreach_safe(rpl_neighbour_t, n, &instance->candidate_neighbours) { //Remove a Parent candidates which are not heared a long time ago and not slected ones if (!n->dodag_parent && (rpl_aged_lifetime(rpl_default_lifetime(n->dodag_version->dodag), n->dio_timestamp) == 0)) { + tr_debug("Candidate timeout: Remove %s", trace_ipv6(n->ll_address)); rpl_delete_neighbour(instance, n); continue; } @@ -1429,7 +1493,7 @@ void rpl_instance_run_parent_selection(rpl_instance_t *instance) if (original_preferred != preferred_parent) { protocol_stats_update(STATS_RPL_PARENT_CHANGE, 1); if (preferred_parent) { - tr_debug("New preferred parent %s", trace_array(preferred_parent->ll_address, 16)); + tr_info("New preferred parent %s", trace_array(preferred_parent->ll_address, 16)); } } @@ -1479,6 +1543,7 @@ void rpl_instance_run_parent_selection(rpl_instance_t *instance) continue; } if (!instance->of->neighbour_acceptable(instance, n)) { + tr_debug("Candidate not acceptable: Remove %s", trace_ipv6(n->ll_address)); rpl_delete_neighbour(instance, n); } } @@ -1560,7 +1625,9 @@ void rpl_instance_dio_trigger(rpl_instance_t *instance, protocol_interface_info_ conf = &dodag->config; } else if (dodag->new_config_advertisment_count < rpl_policy_dio_multicast_config_advertisment_min_count()) { conf = &dodag->config; - dodag->new_config_advertisment_count++; + if (dodag->new_config_advertisment_count < 0xfe) { + dodag->new_config_advertisment_count++; + } } else { conf = NULL; } @@ -1699,7 +1766,7 @@ bool rpl_instance_address_is_candidate(rpl_instance_t *instance, const uint8_t * return false; } -uint16_t rpl_instance_address_candidate_count(rpl_instance_t *instance, bool selected_parents) +uint16_t rpl_instance_address_candidate_count(const rpl_instance_t *instance, bool selected_parents) { uint16_t parent_list = 0; @@ -1717,7 +1784,6 @@ uint16_t rpl_instance_address_candidate_count(rpl_instance_t *instance, bool sel return parent_list; } - void rpl_instance_neighbor_delete(rpl_instance_t *instance, const uint8_t *ipv6_addr) { ns_list_foreach_safe(rpl_neighbour_t, neighbour, &instance->candidate_neighbours) { @@ -1767,17 +1833,21 @@ void rpl_upward_dio_timer(rpl_instance_t *instance, uint16_t ticks) if (rpl_dodag_am_leaf(dodag) && !instance->poison_count) { return; } - // We dont have any valid address in interface - if (ns_list_count(&instance->dao_targets) == 0) { - return; - } - /* Address registrations for parent ongoing*/ - if (rpl_policy_parent_confirmation_requested() && instance->pending_neighbour_confirmation) { - return; - } - /* If we are waiting for DAO or DAO registration is needed we dont send periodic DIOs */ - if (instance->dao_in_transit || instance->delay_dao_timer > 0) { - return; + /* Delay sending first DIO if we are still potentially gathering info */ + /* Important to always send DIOs if we ever have sent any, so we can indicate problems to others */ + if (!instance->last_advertised_dodag_version && rpl_policy_parent_confirmation_requested()) { + // We dont have any valid address in interface + if (ns_list_count(&instance->dao_targets) == 0) { + return; + } + /* Address registrations for parent ongoing*/ + if (instance->pending_neighbour_confirmation) { + return; + } + /* If we are waiting for DAO or DAO registration is needed we dont send periodic DIOs */ + if (instance->dao_in_transit || instance->delay_dao_timer > 0) { + return; + } } if (trickle_timer(&instance->dio_timer, &dodag->dio_timer_params, ticks)) { instance->dio_not_consistent = false; diff --git a/source/RPL/rpl_upward.h b/source/RPL/rpl_upward.h index 2780f6729a9..b3b51b38bc6 100644 --- a/source/RPL/rpl_upward.h +++ b/source/RPL/rpl_upward.h @@ -70,6 +70,7 @@ bool rpl_instance_am_root(const rpl_instance_t *instance); uint8_t rpl_instance_mop(const rpl_instance_t *instance); rpl_dodag_version_t *rpl_instance_current_dodag_version(const rpl_instance_t *instance); rpl_neighbour_t *rpl_instance_preferred_parent(const rpl_instance_t *instance); +bool rpl_instance_possible_better_candidate(const rpl_instance_t *instance, rpl_neighbour_t *replacing, uint16_t candidate_rank, uint16_t etx); rpl_dodag_version_t *rpl_instance_predicate_match(rpl_instance_t *instance, uint8_t pred, uint8_t instance_id, const uint8_t *dodagid, uint8_t version_num); void rpl_instance_inconsistency(rpl_instance_t *instance); void rpl_instance_consistent_rx(rpl_instance_t *instance); @@ -77,15 +78,16 @@ void rpl_instance_increment_dtsn(rpl_instance_t *instance); void rpl_dodag_set_pref(rpl_dodag_t *dodag, uint8_t pref); void rpl_instance_poison(rpl_instance_t *instance, uint8_t count); void rpl_instance_force_leaf(rpl_instance_t *instance); -void rpl_instance_trigger_parent_selection(rpl_instance_t *instance, uint16_t delay); +void rpl_instance_trigger_parent_selection(rpl_instance_t *instance, uint16_t delay, rpl_dodag_t *dodag); void rpl_instance_remove_interface(rpl_instance_t *instance, int8_t if_id); void rpl_instance_dio_trigger(rpl_instance_t *instance, struct protocol_interface_info_entry *cur, const uint8_t *addr); void rpl_instance_set_local_repair(rpl_instance_t *instance, bool repair); bool rpl_instance_local_repair(const rpl_instance_t *instance); uint16_t rpl_instance_current_rank(const rpl_instance_t *instance); +uint16_t rpl_instance_candidate_rank(const rpl_neighbour_t *candidate); bool rpl_instance_address_is_parent(rpl_instance_t *instance, const uint8_t *ipv6_addr); bool rpl_instance_address_is_candidate(rpl_instance_t *instance, const uint8_t *ipv6_addr, uint16_t candidate_amount); -uint16_t rpl_instance_address_candidate_count(rpl_instance_t *instance, bool selected_parents); +uint16_t rpl_instance_address_candidate_count(const rpl_instance_t *instance, bool selected_parents); void rpl_instance_neighbor_delete(rpl_instance_t *instance, const uint8_t *ipv6_addr); void rpl_instance_slow_timer(rpl_instance_t *instance, uint16_t seconds); @@ -97,8 +99,10 @@ uint8_t rpl_dodag_mop(const rpl_dodag_t *dodag); void rpl_dodag_set_root(rpl_dodag_t *dodag, bool root); #ifdef HAVE_RPL_ROOT bool rpl_dodag_am_root(const rpl_dodag_t *dodag); +bool rpl_dodag_was_root(const rpl_dodag_t *dodag); #else #define rpl_dodag_am_root(dodag) false +#define rpl_dodag_was_root(dodag) false #endif 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); @@ -131,6 +135,7 @@ void rpl_dodag_version_raise_greediness(rpl_dodag_version_t *version, uint16_t p bool rpl_dodag_version_rank_indicates_possible_sub_dodag(const rpl_dodag_version_t *version, uint16_t rank); rpl_neighbour_t *rpl_lookup_neighbour_by_ll_address(const rpl_instance_t *instance, const uint8_t *addr, int8_t if_id); +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); @@ -142,7 +147,7 @@ bool rpl_neighbour_update_dtsn(rpl_neighbour_t *neighbour, uint8_t dtsn); rpl_instance_t *rpl_neighbour_instance(const rpl_neighbour_t *neighbour); -void rpl_instance_neighbours_changed(rpl_instance_t *instance, const rpl_dodag_t *dodag); +void rpl_instance_neighbours_changed(rpl_instance_t *instance, rpl_dodag_t *dodag); void rpl_instance_run_parent_selection(rpl_instance_t *instance); void rpl_upward_print_instance(rpl_instance_t *instance, route_print_fn_t *print_fn); diff --git a/source/Security/TLS/tls_lib.c b/source/Security/TLS/tls_lib.c index b4596c9f4af..f23517a62c0 100644 --- a/source/Security/TLS/tls_lib.c +++ b/source/Security/TLS/tls_lib.c @@ -229,6 +229,7 @@ uint8_t tls_parse_client_hello(uint8_t *ptr, uint16_t len, sec_suite_t *tls_suit case TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8: thep->client_knows_standard_ecc_ciphersuite = true; /* no break */ + /* fall through */ case TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8_COMPAT: tr_debug("Client Sup ECC"); ret_val |= SEC_CIPHERSUITE_ECC; 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 40a5c2eccda..bc61ab1ac60 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 @@ -53,16 +53,24 @@ typedef enum { EAP_TLS_STATE_FINISHED = SEC_STATE_FINISHED } eap_tls_sec_prot_state_e; +// Filters initial EAPOL-key re-transmission bursts +#define BURST_FILTER_TIMER_TIMEOUT 5 * 10 + +// How many times initial EAPOL-key is accepted on wait for identity response state +#define INITIAL_EAPOL_KEY_MAX_COUNT 2 + typedef struct { sec_prot_common_t common; /**< Common data */ sec_prot_t *tls_prot; /**< TLS security protocol */ eapol_pdu_t recv_eapol_pdu; /**< Received EAPOL PDU */ tls_data_t tls_send; /**< EAP-TLS send buffer */ tls_data_t tls_recv; /**< EAP-TLS receive buffer */ + uint16_t burst_filt_timer; /**< Burst filter timer */ uint8_t eap_id_seq; /**< EAP sequence */ uint8_t recv_eap_id_seq; /**< Last received EAP sequence */ uint8_t eap_code; /**< Received EAP code */ uint8_t eap_type; /**< Received EAP type */ + uint8_t init_key_cnt; /**< How many time initial EAPOL-key has been received */ int8_t tls_result; /**< Result of TLS operation */ bool wait_tls: 1; /**< Wait TLS (ECC calculation) before sending EAP-TLS message */ bool tls_ongoing: 1; /**< TLS handshake is ongoing */ @@ -151,13 +159,15 @@ static int8_t auth_eap_tls_sec_prot_init(sec_prot_t *prot) sec_prot_state_set(prot, &data->common, EAP_TLS_STATE_INIT); data->tls_prot = NULL; + data->burst_filt_timer = BURST_FILTER_TIMER_TIMEOUT; data->eap_id_seq = 0; data->recv_eap_id_seq = 0; data->eap_code = 0; data->eap_type = 0; eap_tls_sec_prot_lib_message_init(&data->tls_recv); eap_tls_sec_prot_lib_message_init(&data->tls_send); - data->tls_result = EAP_TLS_RESULT_ERROR; + data->tls_result = EAP_TLS_RESULT_ERROR; + data->init_key_cnt = 0; data->wait_tls = false; data->tls_ongoing = false; data->send_pending = false; @@ -186,13 +196,31 @@ static int8_t auth_eap_tls_sec_prot_receive(sec_prot_t *prot, void *pdu, uint16_ // Decoding is successful if (eapol_parse_pdu_header(pdu, size, &data->recv_eapol_pdu)) { - // Handle only EAP messages (ignore initial EAPOL-key retransmissions) + // Handle EAP messages if (data->recv_eapol_pdu.packet_type == EAPOL_EAP_TYPE) { data->eap_code = data->recv_eapol_pdu.msg.eap.eap_code; data->eap_type = data->recv_eapol_pdu.msg.eap.type; // Call state machine prot->state_machine(prot); + } else if (data->recv_eapol_pdu.packet_type == EAPOL_KEY_TYPE && + sec_prot_state_get(&data->common) == EAP_TLS_STATE_RESPONSE_ID) { + /* If initial EAPOL-key transmission arrives to first EAP-TLS wait state i.e. + * when waiting for identity response, triggers re-transmission of identity + * request. This allows the supplicant to start EAP-TLS right away, if it has + * missed the original identity request. + */ + if (data->burst_filt_timer == 0 && data->init_key_cnt < INITIAL_EAPOL_KEY_MAX_COUNT) { + tr_info("EAP-TLS: initial EAPOL-key recv, eui-64: %s", trace_array(sec_prot_remote_eui_64_addr_get(prot), 8)); + sec_prot_result_set(&data->common, SEC_RESULT_TIMEOUT); + // Call state machine + prot->state_machine(prot); + // Resets trickle timer to give time for supplicant to answer + sec_prot_timer_trickle_start(&data->common, &eap_tls_trickle_params); + data->init_key_cnt++; + } + // Filters repeated initial EAPOL-key messages + data->burst_filt_timer = BURST_FILTER_TIMER_TIMEOUT; } ret_val = 0; } @@ -288,6 +316,13 @@ static int8_t auth_eap_tls_sec_prot_message_send(sec_prot_t *prot, uint8_t eap_c static void auth_eap_tls_sec_prot_timer_timeout(sec_prot_t *prot, uint16_t ticks) { eap_tls_sec_prot_int_t *data = eap_tls_sec_prot_get(prot); + + if (data->burst_filt_timer > ticks) { + data->burst_filt_timer -= ticks; + } else { + data->burst_filt_timer = 0; + } + sec_prot_timer_timeout_handle(prot, &data->common, &eap_tls_trickle_params, ticks); } 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 b80a43cc404..bac7ecceb4a 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 @@ -72,10 +72,10 @@ typedef struct { bool send_pending: 1; /**< TLS data is not yet send to network */ } eap_tls_sec_prot_int_t; -#define FWH_RETRY_TIMEOUT_SMALL 330*10 // retry timeout for small network additional 30 seconds for authenticator delay -#define FWH_RETRY_TIMEOUT_LARGE 750*10 // retry timeout for large network additional 30 seconds for authenticator delay +#define EAP_TLS_RETRY_TIMEOUT_SMALL 330*10 // retry timeout for small network additional 30 seconds for authenticator delay +#define EAP_TLS_RETRY_TIMEOUT_LARGE 750*10 // retry timeout for large network additional 30 seconds for authenticator delay -static uint16_t retry_timeout = FWH_RETRY_TIMEOUT_SMALL; +static uint16_t retry_timeout = EAP_TLS_RETRY_TIMEOUT_SMALL; static uint16_t supp_eap_tls_sec_prot_size(void); static int8_t supp_eap_tls_sec_prot_init(sec_prot_t *prot); @@ -93,7 +93,7 @@ static void supp_eap_tls_sec_prot_timer_timeout(sec_prot_t *prot, uint16_t ticks static int8_t supp_eap_tls_sec_prot_init_tls(sec_prot_t *prot); static void supp_eap_tls_sec_prot_delete_tls(sec_prot_t *prot); -static void supp_eap_tls_sec_prot_seq_id_update(sec_prot_t *prot); +static bool supp_eap_tls_sec_prot_seq_id_update(sec_prot_t *prot); #define eap_tls_sec_prot_get(prot) (eap_tls_sec_prot_int_t *) &prot->data @@ -113,9 +113,9 @@ int8_t supp_eap_tls_sec_prot_register(kmp_service_t *service) int8_t supp_eap_sec_prot_timing_adjust(uint8_t timing) { if (timing < 16) { - retry_timeout = FWH_RETRY_TIMEOUT_SMALL; + retry_timeout = EAP_TLS_RETRY_TIMEOUT_SMALL; } else { - retry_timeout = FWH_RETRY_TIMEOUT_LARGE; + retry_timeout = EAP_TLS_RETRY_TIMEOUT_LARGE; } return 0; } @@ -493,7 +493,10 @@ static void supp_eap_tls_sec_prot_state_machine(sec_prot_t *prot) } // Store sequence ID - supp_eap_tls_sec_prot_seq_id_update(prot); + 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 = retry_timeout; + } // All fragments received for a message if (result == EAP_TLS_MSG_RECEIVE_DONE && data->tls_ongoing) { @@ -524,10 +527,6 @@ static void supp_eap_tls_sec_prot_state_machine(sec_prot_t *prot) // Send EAP response supp_eap_tls_sec_prot_message_send(prot, EAP_RESPONSE, EAP_TLS, EAP_TLS_EXCHANGE_ONGOING); data->send_pending = false; - - // Add more time for re-send if no response - data->common.ticks = retry_timeout; - break; case EAP_TLS_STATE_FINISH: @@ -550,10 +549,16 @@ static void supp_eap_tls_sec_prot_state_machine(sec_prot_t *prot) } } -static void supp_eap_tls_sec_prot_seq_id_update(sec_prot_t *prot) +static bool supp_eap_tls_sec_prot_seq_id_update(sec_prot_t *prot) { eap_tls_sec_prot_int_t *data = eap_tls_sec_prot_get(prot); + bool new_seq_id = false; + + if (data->recv_eapol_pdu.msg.eap.id_seq > data->eap_id_seq) { + new_seq_id = true; + } data->eap_id_seq = data->recv_eapol_pdu.msg.eap.id_seq; + return new_seq_id; } #endif /* HAVE_WS */ 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 5c0a48393d1..02b32b729f2 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 @@ -414,7 +414,8 @@ static void auth_fwh_sec_prot_state_machine(sec_prot_t *prot) if (auth_fwh_sec_prot_mic_validate(prot) < 0) { return; } - + // PTK is fresh for installing any GTKs + sec_prot_keys_ptk_installed_gtk_hash_clear_all(prot->sec_keys); // If GTK was inserted set it valid sec_prot_keys_gtkl_from_gtk_insert_index_set(prot->sec_keys); // Reset PTK mismatch 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 50a9691b33b..b4206f69b4f 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 @@ -315,6 +315,9 @@ static void auth_gkh_sec_prot_state_machine(sec_prot_t *prot) sec_prot_timer_trickle_start(&data->common, &gkh_trickle_params); sec_prot_state_set(prot, &data->common, GKH_STATE_MESSAGE_2); + + // Store the hash for to-be installed GTK as used for the PTK + sec_prot_keys_ptk_installed_gtk_hash_set(prot->sec_keys); break; // Wait GKH message 2 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 ba56a7566c6..409546c3dc2 100644 --- a/source/Security/protocols/key_sec_prot/key_sec_prot.c +++ b/source/Security/protocols/key_sec_prot/key_sec_prot.c @@ -318,10 +318,10 @@ static int8_t key_sec_prot_tx_status_ind(sec_prot_t *prot, sec_prot_tx_status_e // Indicates TX failure if (tx_status == SEC_PROT_TX_ERR_TX_NO_ACK) { - sec_prot_result_set(&data->common, KMP_RESULT_ERR_TX_NO_ACK); + sec_prot_result_set(&data->common, SEC_RESULT_ERR_TX_NO_ACK); } else if (tx_status != SEC_PROT_TX_OK) { // Indicates other failure - sec_prot_result_set(&data->common, KMP_RESULT_ERR_UNSPEC); + sec_prot_result_set(&data->common, SEC_RESULT_ERR_UNSPEC); } prot->state_machine_call(prot); return 0; diff --git a/source/Security/protocols/sec_prot_keys.c b/source/Security/protocols/sec_prot_keys.c index 9a0d4c8a434..cdcc31de326 100644 --- a/source/Security/protocols/sec_prot_keys.c +++ b/source/Security/protocols/sec_prot_keys.c @@ -38,6 +38,8 @@ #define TRACE_GROUP "spke" +static const uint8_t empty_hash[GTK_HASH_LEN] = {0}; + sec_prot_keys_t *sec_prot_keys_create(sec_prot_gtk_keys_t *gtks, const sec_prot_certs_t *certs) { sec_prot_keys_t *sec_keys = ns_dyn_mem_alloc(sizeof(sec_prot_keys_t)); @@ -67,6 +69,7 @@ void sec_prot_keys_init(sec_prot_keys_t *sec_keys, sec_prot_gtk_keys_t *gtks, co sec_keys->ptk_eui_64_set = false; sec_keys->pmk_mismatch = false; sec_keys->ptk_mismatch = false; + sec_prot_keys_ptk_installed_gtk_hash_clear_all(sec_keys); } void sec_prot_keys_delete(sec_prot_keys_t *sec_keys) @@ -581,9 +584,22 @@ void sec_prot_keys_gtks_hash_generate(sec_prot_gtk_keys_t *gtks, uint8_t *gtkhas } } -void sec_prot_keys_gtk_hash_generate(uint8_t *gtk, uint8_t *gtk_hash) +int8_t sec_prot_keys_gtk_hash_generate(uint8_t *gtk, uint8_t *gtk_hash) { + return sec_prot_lib_gtkhash_generate(gtk, gtk_hash); +} + +int8_t sec_prot_keys_gtk_valid_check(uint8_t *gtk) +{ + uint8_t gtk_hash[8]; sec_prot_lib_gtkhash_generate(gtk, gtk_hash); + + // Checks if GTK hash for the GTK would be all zero + if (memcmp(gtk_hash, empty_hash, GTK_HASH_LEN) == 0) { + return -1; + } + + return 0; } gtk_mismatch_e sec_prot_keys_gtks_hash_update(sec_prot_gtk_keys_t *gtks, uint8_t *gtkhash) @@ -639,7 +655,6 @@ gtk_mismatch_e sec_prot_keys_gtks_hash_update(sec_prot_gtk_keys_t *gtks, uint8_t bool sec_prot_keys_gtk_hash_empty(uint8_t *gtkhash) { - const uint8_t empty_hash[GTK_HASH_LEN] = {0}; if (memcmp(gtkhash, empty_hash, GTK_HASH_LEN) == 0) { return true; } else { @@ -783,4 +798,57 @@ uint8_t sec_prot_keys_gtk_count(sec_prot_gtk_keys_t *gtks) return count; } +void sec_prot_keys_ptk_installed_gtk_hash_clear_all(sec_prot_keys_t *sec_keys) +{ + for (uint8_t index = 0; index < GTK_NUM; index++) { + memset(sec_keys->ins_gtk_hash[sec_keys->gtk_set_index].hash, 0, INS_GTK_HASH_LEN); + } + sec_keys->ins_gtk_hash_set = 0; +} + +void sec_prot_keys_ptk_installed_gtk_hash_set(sec_prot_keys_t *sec_keys) +{ + if (sec_keys->gtk_set_index >= 0) { + uint8_t *gtk = sec_prot_keys_gtk_get(sec_keys->gtks, sec_keys->gtk_set_index); + if (!gtk) { + return; + } + uint8_t gtk_hash[GTK_HASH_LEN]; + if (sec_prot_keys_gtk_hash_generate(gtk, gtk_hash) < 0) { + return; + } + /* Store two byte hash. This is long enough for the GTK installed check, since + * possible conflict between hashes causes only that 4WH is initiated/is not + * initiated instead of GKH. + */ + memcpy(sec_keys->ins_gtk_hash[sec_keys->gtk_set_index].hash, gtk_hash, INS_GTK_HASH_LEN); + sec_keys->ins_gtk_hash_set |= (1 << sec_keys->gtk_set_index); + } +} + +bool sec_prot_keys_ptk_installed_gtk_hash_mismatch_check(sec_prot_keys_t *sec_keys, uint8_t gtk_index) +{ + if ((sec_keys->ins_gtk_hash_set & (1 << sec_keys->gtk_set_index)) == 0) { + return false; + } + + uint8_t *gtk = sec_prot_keys_gtk_get(sec_keys->gtks, gtk_index); + if (!gtk) { + return false; + } + + // Calculated GTK hash for the current GTK on the defined index + uint8_t gtk_hash[GTK_HASH_LEN]; + if (sec_prot_keys_gtk_hash_generate(gtk, gtk_hash) < 0) { + return false; + } + + // If PTK has been used to install different GTK to index than the current one, trigger mismatch + if (memcmp(sec_keys->ins_gtk_hash[sec_keys->gtk_set_index].hash, gtk_hash, INS_GTK_HASH_LEN) != 0) { + return true; + } + + return false; +} + #endif /* HAVE_WS */ diff --git a/source/Security/protocols/sec_prot_keys.h b/source/Security/protocols/sec_prot_keys.h index 4a14fc2b6ff..9df422934b9 100644 --- a/source/Security/protocols/sec_prot_keys.h +++ b/source/Security/protocols/sec_prot_keys.h @@ -54,6 +54,7 @@ #define GTK_HASH_LEN 8 #define GTK_ALL_HASHES_LEN GTK_HASH_LEN * GTK_NUM +#define INS_GTK_HASH_LEN 2 #define PMK_LIFETIME_INSTALL 0xFFFFF #define PTK_LIFETIME_INSTALL 0xFFFFF @@ -71,18 +72,24 @@ typedef struct { bool updated: 1; /**< Group Transient Keys has been updated */ } sec_prot_gtk_keys_t; +typedef struct { + uint8_t hash[INS_GTK_HASH_LEN]; /**< Inserted GTKs for a PTK hash */ +} sec_prot_gtk_hash_t; + // Security key data typedef struct { uint64_t pmk_key_replay_cnt; /**< Pairwise Master Key replay counter */ uint8_t pmk[PMK_LEN]; /**< Pairwise Master Key (256 bits) */ uint8_t ptk[PTK_LEN]; /**< Pairwise Transient Key (384 bits) */ uint8_t ptk_eui_64[8]; /**< Remote EUI-64 used to derive PTK or NULL */ + sec_prot_gtk_hash_t ins_gtk_hash[GTK_NUM]; /**< Hashes for inserted GTKs for a PTK */ sec_prot_gtk_keys_t *gtks; /**< Group Transient Keys */ const sec_prot_certs_t *certs; /**< Certificates */ uint32_t pmk_lifetime; /**< PMK lifetime in seconds */ uint32_t ptk_lifetime; /**< PTK lifetime in seconds */ uint8_t gtkl; /**< Remote GTKL information */ int8_t gtk_set_index; /**< Index of GTK to set */ + unsigned ins_gtk_hash_set: 4; /**< Hash for inserted GTKs for a PTK set */ bool pmk_set: 1; /**< Pairwise Master Key set */ bool ptk_set: 1; /**< Pairwise Transient Key set */ bool pmk_key_replay_cnt_set: 1; /**< Pairwise Master Key replay counter set */ @@ -95,7 +102,8 @@ typedef struct { // Frame counter data typedef struct { uint8_t gtk[GTK_LEN]; /**< GTK of the frame counter */ - uint32_t frame_counter; /**< Frame counter */ + uint32_t frame_counter; /**< Current frame counter */ + uint32_t stored_frame_counter; /**< Stored Frame counter */ bool set : 1; /**< Value has been set */ } frame_counter_t; @@ -649,8 +657,20 @@ void sec_prot_keys_gtks_hash_generate(sec_prot_gtk_keys_t *gtks, uint8_t *gtk_ha * \param gtk GTK key * \param gtk_hash GTK hash for a GTK * + * \return < 0 failure + * \return >= 0 success */ -void sec_prot_keys_gtk_hash_generate(uint8_t *gtk, uint8_t *gtk_hash); +int8_t sec_prot_keys_gtk_hash_generate(uint8_t *gtk, uint8_t *gtk_hash); + +/** + * sec_prot_keys_gtk_valid_check check if GTK is valid + * + * \param gtk GTK key + * + * \return < 0 failure + * \return >= 0 success + */ +int8_t sec_prot_keys_gtk_valid_check(uint8_t *gtk); /** * sec_prot_keys_gtks_hash_update update GTKs based on GTK hash @@ -751,4 +771,30 @@ int8_t sec_prot_keys_gtk_install_index_get(sec_prot_gtk_keys_t *gtks); */ uint8_t sec_prot_keys_gtk_count(sec_prot_gtk_keys_t *gtks); +/** + * sec_prot_keys_ptk_installed_gtk_hash_clear_all clear GTK hashes of the GTKs that has been installed + * to supplicant using the PTK + * \param sec_keys security keys + * + */ +void sec_prot_keys_ptk_installed_gtk_hash_clear_all(sec_prot_keys_t *sec_keys); + +/** + * sec_prot_keys_ptk_installed_gtk_hash_set set GTK hash of the GTK that has been installed + * to supplicant using the current PTK + * + * \param sec_keys security keys + * + */ +void sec_prot_keys_ptk_installed_gtk_hash_set(sec_prot_keys_t *sec_keys); + +/** + * sec_prot_keys_ptk_installed_gtk_hash_set check if PTK is being used to store new GTK for the index + * for the supplicant i.e. GTK hash would change + * + * \param sec_keys security keys + * + */ +bool sec_prot_keys_ptk_installed_gtk_hash_mismatch_check(sec_prot_keys_t *sec_keys, uint8_t gtk_index); + #endif /* SEC_PROT_KEYS_H_ */ diff --git a/source/Service_Libs/Trickle/trickle.c b/source/Service_Libs/Trickle/trickle.c index 5eaa8a1fa69..77e58d09ad6 100644 --- a/source/Service_Libs/Trickle/trickle.c +++ b/source/Service_Libs/Trickle/trickle.c @@ -49,6 +49,26 @@ void trickle_start(trickle_t *t, const trickle_params_t *params) trickle_begin_interval(t); } +uint32_t trickle_timer_max(const trickle_params_t *params, uint8_t trickle_timer_expiration) +{ + trickle_time_t time_I = params->Imin - 1; + uint32_t total_time = time_I; + while (trickle_timer_expiration) { + if (time_I <= TRICKLE_TIME_MAX / 2) { + time_I *= 2; + } else { + time_I = TRICKLE_TIME_MAX; + } + + if (time_I > params->Imax) { + time_I = params->Imax; + } + total_time += time_I; + trickle_timer_expiration--; + } + return total_time; +} + /* We don't expose the raw reset as API; users should use "inconsistent_heard". * This avoids repeated resets stopping transmission by restarting the interval. */ diff --git a/source/Service_Libs/Trickle/trickle.h b/source/Service_Libs/Trickle/trickle.h index 60ffa25f81e..a6c957826c9 100644 --- a/source/Service_Libs/Trickle/trickle.h +++ b/source/Service_Libs/Trickle/trickle.h @@ -76,5 +76,10 @@ bool trickle_running(const trickle_t *t, const trickle_params_t *params); /* Stop the timer (by setting e to infinite) */ void trickle_stop(trickle_t *t); +/* + * Call return max time after n count expiration period 0 return 1 Imin - 1 period + * + */ +uint32_t trickle_timer_max(const trickle_params_t *params, uint8_t trickle_timer_expiration); #endif /* TRICKLE_H_ */ diff --git a/source/Service_Libs/blacklist/blacklist.c b/source/Service_Libs/blacklist/blacklist.c index 25d06666389..f47b2097bff 100644 --- a/source/Service_Libs/blacklist/blacklist.c +++ b/source/Service_Libs/blacklist/blacklist.c @@ -87,7 +87,7 @@ bool blacklist_reject(const uint8_t *ll64_address) if (blacklist_entry) { // If address is blacklisted rejects if (blacklist_entry->ttl > blacklist_data->blacklist_entry_lifetime) { - tr_debug("blacklist reject: %s", trace_array(ll64_address + 8, 8)); + tr_info("blacklist reject: %s", trace_array(ll64_address + 8, 8)); return true; // Neighbor heard; updates blacklist entry TTL to full lifetime } else { @@ -131,7 +131,7 @@ void blacklist_update(const uint8_t *ll64_address, bool success) // On successful link establishment remove address from blacklist if (success) { if (blacklist_entry) { - tr_debug("Blacklist removed"); + tr_info("Blacklist removed"); blacklist_entry_free(blacklist_entry); } // On failure add address to blacklist or update timeout @@ -144,7 +144,7 @@ void blacklist_update(const uint8_t *ll64_address, bool success) /* TTL is blacklist entry lifetime + from 1.0 to 1.5 * interval */ blacklist_entry->ttl = blacklist_data->blacklist_entry_lifetime + randLIB_randomise_base(blacklist_entry->interval, 0x8000, 0xC000); } else { - tr_debug("Blacklist add"); + tr_info("Blacklist add"); blacklist_entry_add(ll64_address + 8); } } @@ -209,7 +209,7 @@ void blacklist_ttl_update(uint16_t ticks) if (blacklist_entry->ttl > ticks) { blacklist_entry->ttl -= ticks; } else { - tr_debug("Blacklist remove entry: %s", trace_array(blacklist_entry->eui64, 8)); + tr_info("Blacklist remove entry: %s", trace_array(blacklist_entry->eui64, 8)); blacklist_entry_free(blacklist_entry); } } diff --git a/source/Service_Libs/etx/etx.c b/source/Service_Libs/etx/etx.c index 60dc5a91fce..639490981a6 100644 --- a/source/Service_Libs/etx/etx.c +++ b/source/Service_Libs/etx/etx.c @@ -62,11 +62,13 @@ typedef struct { etx_storage_t *etx_storage_list; etx_sample_storage_t *etx_cache_storage_list; uint32_t max_etx_update; + uint32_t max_etx; uint16_t hysteresis; // 12 bit fraction + uint16_t init_etx_sample_count; uint8_t accum_threshold; uint8_t etx_min_sampling_time; uint8_t ext_storage_list_size; - uint8_t min_sample_count; + uint8_t min_attempts_count; bool cache_sample_requested; int8_t interface_id; } ext_info_t; @@ -79,8 +81,10 @@ static ext_info_t etx_info = { .etx_storage_list = NULL, .etx_cache_storage_list = NULL, .ext_storage_list_size = 0, - .min_sample_count = 0, + .min_attempts_count = 0, .max_etx_update = 0, + .max_etx = 0xffff, + .init_etx_sample_count = 1, .cache_sample_requested = false, .etx_min_sampling_time = 0, .interface_id = -1 @@ -89,7 +93,9 @@ static ext_info_t etx_info = { static void etx_calculation(etx_storage_t *entry, uint16_t attempts, uint8_t acks_rx, uint8_t attribute_index) { if (etx_info.hysteresis && !entry->stored_diff_etx) { - entry->stored_diff_etx = entry->etx; + if (entry->etx_samples >= etx_info.init_etx_sample_count) { + entry->stored_diff_etx = entry->etx; + } } uint32_t etx = attempts << (12 - ETX_MOVING_AVERAGE_FRACTION); @@ -99,11 +105,14 @@ static void etx_calculation(etx_storage_t *entry, uint16_t attempts, uint8_t ack } else { etx = 0xffff; } + if ((etx_info.max_etx_update) && etx > etx_info.max_etx_update) { etx = etx_info.max_etx_update; } - if (etx_info.cache_sample_requested && entry->etx_samples == 1) { + //tr_debug("Attempts %u ACK %u 1/8 update %u", attempts, acks_rx, etx); + + if (etx_info.cache_sample_requested && entry->etx_samples <= etx_info.init_etx_sample_count) { // skip the initial value as RSSI generated ETX is not valid etx = etx << 3; } else { @@ -111,18 +120,20 @@ static void etx_calculation(etx_storage_t *entry, uint16_t attempts, uint8_t ack etx += entry->etx - (entry->etx >> ETX_MOVING_AVERAGE_FRACTION); } - if (etx > 0xffff) { - etx = 0xffff; + if (etx > etx_info.max_etx) { + etx = etx_info.max_etx; } // If real ETX value has been received do not update based on LQI or dBm entry->tmp_etx = false; - entry->etx = etx; - etx_cache_entry_init(attribute_index); + entry->etx = etx; - // Checks if ETX value change callback is needed - etx_value_change_callback_needed_check(entry->etx, &(entry->stored_diff_etx), entry->accumulated_failures, attribute_index); + if (entry->etx_samples >= etx_info.init_etx_sample_count) { + etx_cache_entry_init(attribute_index); + // Checks if ETX value change callback is needed + etx_value_change_callback_needed_check(entry->etx, &(entry->stored_diff_etx), entry->accumulated_failures, attribute_index); + } } static void etx_cache_entry_init(uint8_t attribute_index) @@ -135,7 +146,6 @@ static void etx_cache_entry_init(uint8_t attribute_index) storage->attempts_count = 0; storage->etx_timer = etx_info.etx_min_sampling_time; storage->received_acks = 0; - storage->sample_count = 0; } static bool etx_update_possible(etx_sample_storage_t *storage, etx_storage_t *entry, uint16_t time_update) @@ -148,23 +158,23 @@ static bool etx_update_possible(etx_sample_storage_t *storage, etx_storage_t *en } } - if (entry->etx_samples > ETX_ACCELERATED_SAMPLE_COUNT) { + if (entry->etx_samples > etx_info.init_etx_sample_count) { //Slower ETX update phase - if (storage->sample_count < etx_info.min_sample_count || storage->etx_timer) { - if (storage->sample_count < 0xff) { - return false; + if (storage->attempts_count >= etx_info.min_attempts_count) { + + if (storage->etx_timer == 0 || storage->attempts_count == 0xffff || storage->received_acks == 0xff) { + //Got least min sample in requested time or max possible sample + return true; } } - } else { - //Accelerated ETX at for new neighbor - if (storage->sample_count < ETX_ACCELERATED_INTERVAL) { - return false; - } + return false; } - //tr_debug("ETX update possible %u attempts, %u rx ack", storage->attempts_count, storage->received_acks); + if (time_update == 0) { + return true; + } - return true; + return false; } @@ -176,7 +186,6 @@ static etx_sample_storage_t *etx_cache_sample_update(uint8_t attribute_index, ui if (ack_rx) { storage->received_acks++; } - storage->sample_count++; return storage; } @@ -202,6 +211,7 @@ void etx_transm_attempts_update(int8_t interface_id, uint8_t attempts, bool succ if (!entry) { return; } + if (entry->etx_samples < 7) { entry->etx_samples++; } @@ -211,11 +221,15 @@ void etx_transm_attempts_update(int8_t interface_id, uint8_t attempts, bool succ etx_sample_storage_t *storage = etx_cache_sample_update(attribute_index, attempts, success); entry->accumulated_failures = 0; - if (!entry->etx || (entry->etx_samples > 1 && !etx_update_possible(storage, entry, 0))) { + if (!etx_update_possible(storage, entry, 0)) { return; } etx_calculation(entry, storage->attempts_count, storage->received_acks, attribute_index); + + if (entry->etx_samples < 7 && !success) { + entry->etx_samples = 7; //Stop Probing to failure + } return; } @@ -377,6 +391,13 @@ uint16_t etx_local_etx_read(int8_t interface_id, uint8_t attribute_index) if (!entry) { return 0; } + + if (etx_info.cache_sample_requested && entry->etx_samples < etx_info.init_etx_sample_count) { + if (!entry->etx_samples) { + return 0; + } + } + return etx_current_calc(entry->etx, entry->accumulated_failures) >> 4; } @@ -433,7 +454,12 @@ uint16_t etx_lqi_dbm_update(int8_t interface_id, uint8_t lqi, int8_t dbm, uint8_ if (!entry->etx) { etx = etx_dbm_lqi_calc(lqi, dbm); entry->etx = etx; + entry->stored_diff_etx = etx; entry->tmp_etx = true; + if (etx_info.callback_ptr) { + etx_info.callback_ptr(etx_info.interface_id, 0, entry->etx >> 4, + attribute_index); + } } // If local ETX has been calculated without remote incoming IDR and // remote incoming IDR is available update it by remote incoming IDR value @@ -448,11 +474,7 @@ uint16_t etx_lqi_dbm_update(int8_t interface_id, uint8_t lqi, int8_t dbm, uint8_ entry->etx = etx >> 12; local_incoming_idr >>= 4; - } - - // If local ETX has been calculated indicates new neighbor - if (etx) { - etx_neighbor_add(interface_id, attribute_index); + etx_value_change_callback_needed_check(entry->etx, &(entry->stored_diff_etx), entry->accumulated_failures, attribute_index); } } @@ -585,14 +607,18 @@ bool etx_storage_list_allocate(int8_t interface_id, uint8_t etx_storage_size) } -bool etx_cached_etx_parameter_set(uint8_t min_wait_time, uint8_t etx_min_sample_count) +bool etx_cached_etx_parameter_set(uint8_t min_wait_time, uint8_t etx_min_attempts_count, uint8_t init_etx_sample_count) { //No ini ETX allocation done yet if (etx_info.ext_storage_list_size == 0) { return false; } - if (min_wait_time || etx_min_sample_count) { + if (min_wait_time || etx_min_attempts_count) { + if (init_etx_sample_count == 0) { + return false; + } + if (!etx_info.etx_cache_storage_list) { //allocate etx_info.etx_cache_storage_list = ns_dyn_mem_alloc(sizeof(etx_sample_storage_t) * etx_info.ext_storage_list_size); @@ -615,8 +641,9 @@ bool etx_cached_etx_parameter_set(uint8_t min_wait_time, uint8_t etx_min_sample_ etx_info.etx_cache_storage_list = NULL; } - etx_info.min_sample_count = etx_min_sample_count; + etx_info.min_attempts_count = etx_min_attempts_count; etx_info.etx_min_sampling_time = min_wait_time; + etx_info.init_etx_sample_count = init_etx_sample_count; return true; } @@ -624,12 +651,23 @@ bool etx_cached_etx_parameter_set(uint8_t min_wait_time, uint8_t etx_min_sample_ void etx_max_update_set(uint16_t etx_max_update) { if (etx_max_update) { + //Define MAX ETX UPDATE etx_info.max_etx_update = (etx_max_update / 128) << (12 - ETX_MOVING_AVERAGE_FRACTION); } else { etx_info.max_etx_update = 0; } } +void etx_max_set(uint16_t etx_max) +{ + if (etx_max) { + //Define MAX ETX possible value + etx_info.max_etx = (etx_max / 128) << 12; + } else { + etx_info.max_etx = 0xffff; + } +} + etx_storage_t *etx_storage_entry_get(int8_t interface_id, uint8_t attribute_index) { if (etx_info.interface_id != interface_id || !etx_info.etx_storage_list || attribute_index >= etx_info.ext_storage_list_size) { @@ -698,6 +736,8 @@ static void etx_value_change_callback_needed_check(uint16_t etx, uint16_t *store if (current_etx > *stored_diff_etx) { if (current_etx - *stored_diff_etx >= etx_info.hysteresis) { callback = true; + } else if (current_etx == etx_info.max_etx && *stored_diff_etx != etx_info.max_etx) { + callback = true; } } else if (current_etx < *stored_diff_etx) { if (*stored_diff_etx - current_etx >= etx_info.hysteresis) { @@ -768,35 +808,6 @@ void etx_neighbor_remove(int8_t interface_id, uint8_t attribute_index) } } -/** - * \brief A function to add ETX neighbor - * - * Notifies ETX module that neighbor has been added. Calls ETX value change callback - * if that is set. - * - * \param mac64_addr_ptr long MAC address - * - */ -void etx_neighbor_add(int8_t interface_id, uint8_t attribute_index) -{ - - //tr_debug("Add attribute %u", attribute_index); - uint16_t stored_diff_etx; - etx_storage_t *entry = etx_storage_entry_get(interface_id, attribute_index); - if (entry && etx_info.callback_ptr) { - // Gets table entry - - if (entry->etx) { - stored_diff_etx = entry->stored_diff_etx; - if (!stored_diff_etx) { - stored_diff_etx = entry->etx; - } - etx_info.callback_ptr(etx_info.interface_id, stored_diff_etx >> 4, entry->etx >> 4, - attribute_index); - } - } -} - void etx_cache_timer(int8_t interface_id, uint16_t seconds_update) { if (!etx_info.cache_sample_requested) { diff --git a/source/Service_Libs/etx/etx.h b/source/Service_Libs/etx/etx.h index 55c125456d1..c785cc5c983 100644 --- a/source/Service_Libs/etx/etx.h +++ b/source/Service_Libs/etx/etx.h @@ -64,7 +64,6 @@ typedef struct etx_sample_storage_s { uint16_t attempts_count; /*!< TX attempt count */ uint8_t etx_timer; /*!< Count down from configured value 0 means that ETX Update is possible done again*/ uint8_t received_acks; /*!< Received ACK's */ - uint8_t sample_count; /*!< Finished TX count */ } etx_sample_storage_t; /** @@ -237,17 +236,6 @@ uint8_t etx_accum_failures_callback_register(nwk_interface_id nwk_id, int8_t int */ void etx_neighbor_remove(int8_t interface_id, uint8_t attribute_index); -/** - * \brief A function to add ETX neighbor - * - * Notifies ETX module that neighbor has been added. Calls ETX value change callback - * if that is set. - * - * \param attribute_index Neighbour attribute index - * - */ -void etx_neighbor_add(int8_t interface_id, uint8_t attribute_index); - /** * \brief A function for update cached ETX calculation * @@ -266,13 +254,14 @@ void etx_cache_timer(int8_t interface_id, uint16_t seconds_update); * ETX update will happen when min wait time is reached and also reached min etx sample count. * * \param min_wait_time how many seconds must wait before do new ETX - * \param etx_min_sample_count define how many completed TX process must be done for new ETX. Min accepted value is 4. + * \param etx_min_attempts_count define how many TX attempts process must be done for new ETX. Min accepted value is 4. + * \param init_etx_sample_count How Many sample is need to init etx calculate * * \return true Enable is OK * \return false Memory allocation fail * */ -bool etx_cached_etx_parameter_set(uint8_t min_wait_time, uint8_t etx_min_sample_count); +bool etx_cached_etx_parameter_set(uint8_t min_wait_time, uint8_t etx_min_attempts_count, uint8_t init_etx_sample_count); /** @@ -285,4 +274,14 @@ bool etx_cached_etx_parameter_set(uint8_t min_wait_time, uint8_t etx_min_sample_ */ void etx_max_update_set(uint16_t etx_max_update); +/** + * \brief A function for set Maxium ETX value + * + * ETX RFC define that that Max value is 0xffff but this API cuold make that Poor link start go down slowly. + * + * \param etx_max 0 No limit for higher value means. This pameter will change normal ETX which could be 0xffff. + * + */ +void etx_max_set(uint16_t etx_max); + #endif /* ETX_H_ */ diff --git a/source/Service_Libs/fhss/fhss.c b/source/Service_Libs/fhss/fhss.c index 511c07aa985..ae960bc8d07 100644 --- a/source/Service_Libs/fhss/fhss.c +++ b/source/Service_Libs/fhss/fhss.c @@ -1123,8 +1123,9 @@ static void fhss_data_tx_done_callback(const fhss_api_t *api, bool waiting_ack, } } -static bool fhss_data_tx_fail_callback(const fhss_api_t *api, uint8_t handle, int frame_type) +static bool fhss_data_tx_fail_callback(const fhss_api_t *api, uint8_t handle, int frame_type, uint8_t channel) { + (void) channel; fhss_structure_t *fhss_structure = fhss_get_object_with_api(api); if (!fhss_structure) { return false; @@ -1384,7 +1385,9 @@ static void fhss_beacon_tasklet_func(arm_event_s *event) if (!fhss_structure) { return; } +#ifdef FEA_TRACE_SUPPORT uint8_t parent_address[8]; +#endif fhss_clear_active_event(fhss_structure, event->event_type); // skip the init event as there will be a timer event after if (event->event_type == FHSS_TIMER_EVENT) { diff --git a/source/Service_Libs/fhss/fhss_common.c b/source/Service_Libs/fhss/fhss_common.c index d2826ca7e85..0d9dc7c505b 100644 --- a/source/Service_Libs/fhss/fhss_common.c +++ b/source/Service_Libs/fhss/fhss_common.c @@ -113,7 +113,10 @@ int8_t fhss_disable(fhss_structure_t *fhss_structure) } fhss_structure->fhss_api->synch_state_set(fhss_structure->fhss_api, FHSS_UNSYNCHRONIZED, 0); ns_dyn_mem_free(fhss_structure->bs); + ns_dyn_mem_free(fhss_structure->ws->tr51_channel_table); + ns_dyn_mem_free(fhss_structure->ws->tr51_output_table); ns_dyn_mem_free(fhss_structure->ws); + fhss_failed_list_free(fhss_structure); ns_dyn_mem_free(fhss_structure); fhss_struct = 0; return 0; diff --git a/source/Service_Libs/fhss/fhss_common.h b/source/Service_Libs/fhss/fhss_common.h index 35e1d0cc461..4d10667924a 100644 --- a/source/Service_Libs/fhss/fhss_common.h +++ b/source/Service_Libs/fhss/fhss_common.h @@ -40,6 +40,7 @@ struct fhss_structure { int8_t fhss_event_timer; uint8_t active_fhss_events; uint16_t number_of_channels; + uint16_t optimal_packet_length; fhss_states fhss_state; uint32_t fhss_timeout; uint32_t fhss_timer; diff --git a/source/Service_Libs/fhss/fhss_test_api.c b/source/Service_Libs/fhss/fhss_test_api.c new file mode 100644 index 00000000000..7b1e696ea04 --- /dev/null +++ b/source/Service_Libs/fhss/fhss_test_api.c @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2020, Arm Limited and affiliates. + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "nsconfig.h" +#include "ns_types.h" +#include "ns_trace.h" +#include "fhss_api.h" +#include "fhss_config.h" +#include "fhss.h" +#include "fhss_common.h" +#include "fhss_ws.h" +#include "fhss_statistics.h" +#include "fhss_channel.h" +#include "channel_list.h" +#include + +#define TRACE_GROUP "fhta" + +int8_t fhss_set_optimal_packet_length(const fhss_api_t *fhss_api, uint16_t packet_length) +{ + (void) fhss_api; + (void) packet_length; +#ifdef HAVE_WS + fhss_structure_t *fhss_structure = fhss_get_object_with_api(fhss_api); + if (!fhss_structure) { + return -1; + } + fhss_structure->optimal_packet_length = packet_length; + fhss_set_txrx_slot_length(fhss_structure); + tr_debug("Setting FHSS optimal packet length to: %u", fhss_structure->optimal_packet_length); +#endif + return 0; +} diff --git a/source/Service_Libs/fhss/fhss_ws.c b/source/Service_Libs/fhss/fhss_ws.c index 452c6e177bf..d5272250f83 100644 --- a/source/Service_Libs/fhss/fhss_ws.c +++ b/source/Service_Libs/fhss/fhss_ws.c @@ -83,7 +83,6 @@ static void fhss_event_timer_cb(int8_t timer_id, uint16_t slots); static void fhss_ws_update_uc_channel_callback(fhss_structure_t *fhss_structure); static void fhss_unicast_handler(const fhss_api_t *fhss_api, uint16_t delay); static bool fhss_ws_check_tx_allowed(fhss_structure_t *fhss_structure); -static uint32_t fhss_set_txrx_slot_length(fhss_structure_t *fhss_structure); // This function supports rounding up static int64_t divide_integer(int64_t dividend, int32_t divisor) @@ -147,10 +146,10 @@ fhss_structure_t *fhss_ws_enable(fhss_api_t *fhss_api, const fhss_ws_configurati fhss_struct->fhss_event_timer = eventOS_callback_timer_register(fhss_event_timer_cb); fhss_struct->ws->fhss_configuration = *fhss_configuration; fhss_struct->number_of_channels = channel_count; + fhss_struct->optimal_packet_length = OPTIMAL_PACKET_LENGTH; fhss_ws_set_hop_count(fhss_struct, 0xff); fhss_struct->rx_channel = fhss_configuration->unicast_fixed_channel; fhss_struct->ws->min_synch_interval = DEFAULT_MIN_SYNCH_INTERVAL; - fhss_set_txrx_slot_length(fhss_struct); ns_list_init(&fhss_struct->fhss_failed_tx_list); return fhss_struct; } @@ -173,14 +172,51 @@ static int fhss_ws_manage_channel_table_allocation(fhss_structure_t *fhss_struct return 0; } -static uint32_t fhss_set_txrx_slot_length(fhss_structure_t *fhss_structure) +void fhss_set_txrx_slot_length(fhss_structure_t *fhss_structure) { - uint32_t number_of_tx_slots = ((fhss_structure->ws->fhss_configuration.fhss_broadcast_interval - fhss_structure->ws->fhss_configuration.fhss_bc_dwell_interval) / WS_MAX_TXRX_SLOT_LEN_MS) / 2; + // No broadcast schedule, no TX slots + if (fhss_structure->ws->fhss_configuration.fhss_broadcast_interval == 0 || fhss_structure->ws->fhss_configuration.fhss_bc_dwell_interval == 0) { + return; + } + uint32_t txrx_slot_length_ms_tmp = WS_TXRX_SLOT_LEN_MS; + if (fhss_structure->callbacks.read_datarate) { + /* Calculate minimum TX slot length which can fit optimal packet length twice. + * Twice, because 0, 1, 4, 5... hop starts transmission at the beginning of TX slot and 2, 3, 6, 7... hop at the middle of TX slot + * + * hop 0 + * tx'ing | | | | | | + * | BC | RX | TX | RX | TX | RX | TX | BC | + * hop 1 + * tx'ing | | | | | | + * | BC | TX | RX | TX | RX | TX | RX | BC | + * hop 2 + * tx'ing | | | | | | + * | BC | RX | TX | RX | TX | RX | TX | BC | + * hop 3 + * tx'ing | | | | | | + * | BC | TX | RX | TX | RX | TX | RX | BC | + */ + uint32_t datarate = fhss_structure->callbacks.read_datarate(fhss_structure->fhss_api); + if (datarate) { + txrx_slot_length_ms_tmp = ((fhss_structure->optimal_packet_length * 2) * (8000000 / datarate)) / 1000; + // Do not allow using too high TX slot length. + if (txrx_slot_length_ms_tmp > WS_TXRX_SLOT_LEN_MS) { + tr_debug("TX slot length setting too high %"PRIu32"ms, using %"PRIu32"ms", txrx_slot_length_ms_tmp, (uint32_t)WS_TXRX_SLOT_LEN_MS); + txrx_slot_length_ms_tmp = WS_TXRX_SLOT_LEN_MS; + } + } + } + uint32_t number_of_tx_slots = ((fhss_structure->ws->fhss_configuration.fhss_broadcast_interval - fhss_structure->ws->fhss_configuration.fhss_bc_dwell_interval) / txrx_slot_length_ms_tmp) / 2; if (!number_of_tx_slots) { - return 0; + return; } fhss_structure->ws->txrx_slot_length_ms = (fhss_structure->ws->fhss_configuration.fhss_broadcast_interval - fhss_structure->ws->fhss_configuration.fhss_bc_dwell_interval) / (number_of_tx_slots * 2); - return number_of_tx_slots; + tr_info("TX slot length: %"PRIu32"ms", fhss_structure->ws->txrx_slot_length_ms); +} + +static uint32_t fhss_get_number_of_tx_slots(fhss_structure_t *fhss_structure) +{ + return ((fhss_structure->ws->fhss_configuration.fhss_broadcast_interval - fhss_structure->ws->fhss_configuration.fhss_bc_dwell_interval) / fhss_structure->ws->txrx_slot_length_ms) / 2; } static int32_t fhss_ws_calc_bc_channel(fhss_structure_t *fhss_structure) @@ -193,8 +229,8 @@ static int32_t fhss_ws_calc_bc_channel(fhss_structure_t *fhss_structure) fhss_structure->ws->bc_slot = 0; } } else if (fhss_structure->ws->fhss_configuration.ws_bc_channel_function == WS_DH1CF) { - next_channel = dh1cf_get_bc_channel_index(fhss_structure->ws->bc_slot, fhss_structure->ws->fhss_configuration.bsi, fhss_structure->number_of_channels); fhss_structure->ws->bc_slot++; + next_channel = dh1cf_get_bc_channel_index(fhss_structure->ws->bc_slot, fhss_structure->ws->fhss_configuration.bsi, fhss_structure->number_of_channels); } else if (fhss_structure->ws->fhss_configuration.ws_bc_channel_function == WS_VENDOR_DEF_CF) { if (fhss_structure->ws->fhss_configuration.vendor_defined_cf) { next_channel = fhss_structure->ws->fhss_configuration.vendor_defined_cf(fhss_structure->fhss_api, fhss_structure->ws->bc_slot, NULL, fhss_structure->ws->fhss_configuration.bsi, fhss_structure->number_of_channels); @@ -305,8 +341,11 @@ static void fhss_event_timer_cb(int8_t timer_id, uint16_t slots) { (void) slots; uint16_t queue_size = 0; - fhss_structure_t *fhss_structure = fhss_get_object_with_timer_id(timer_id); + fhss_structure_t *fhss_structure = fhss_get_object_with_timer_id(timer_id); + if (!fhss_structure) { + return; + } if (fhss_structure->ws->is_on_bc_channel == true) { queue_size = fhss_structure->callbacks.read_tx_queue_size(fhss_structure->fhss_api, true); @@ -394,7 +433,7 @@ static int16_t fhss_ws_synch_state_set_callback(const fhss_api_t *api, fhss_stat if (fhss_state == FHSS_SYNCHRONIZED) { uint32_t fhss_broadcast_interval = fhss_structure->ws->fhss_configuration.fhss_broadcast_interval; uint8_t fhss_bc_dwell_interval = fhss_structure->ws->fhss_configuration.fhss_bc_dwell_interval; - + fhss_set_txrx_slot_length(fhss_structure); // Start broadcast schedule when BC intervals are known if (fhss_broadcast_interval && fhss_bc_dwell_interval) { fhss_broadcast_handler(fhss_structure->fhss_api, 0); @@ -407,6 +446,9 @@ static int16_t fhss_ws_synch_state_set_callback(const fhss_api_t *api, fhss_stat } } else if (fhss_state == FHSS_UNSYNCHRONIZED) { fhss_structure->ws->synchronization_time = 0; + eventOS_callback_timer_stop(fhss_structure->fhss_event_timer); + fhss_stop_timer(fhss_structure, fhss_unicast_handler); + fhss_stop_timer(fhss_structure, fhss_broadcast_handler); } fhss_structure->fhss_state = fhss_state; @@ -531,7 +573,7 @@ static bool fhss_ws_check_tx_allowed(fhss_structure_t *fhss_structure) if (fhss_structure->ws->is_on_bc_channel == true) { return true; } - uint32_t number_of_tx_slots = fhss_set_txrx_slot_length(fhss_structure); + uint32_t number_of_tx_slots = fhss_get_number_of_tx_slots(fhss_structure); // Allow transmission when broadcast interval is very short comparing to MAX slot length if (!number_of_tx_slots) { return true; @@ -539,9 +581,22 @@ static bool fhss_ws_check_tx_allowed(fhss_structure_t *fhss_structure) uint32_t remaining_time_ms = get_remaining_slots_us(fhss_structure, fhss_broadcast_handler, MS_TO_US(fhss_structure->ws->fhss_configuration.fhss_broadcast_interval)) / 1000; uint32_t tx_slot_begin_ms = (fhss_structure->ws->fhss_configuration.fhss_broadcast_interval - fhss_structure->ws->fhss_configuration.fhss_bc_dwell_interval) - (fhss_structure->ws->txrx_slot_length_ms * (fhss_structure->own_hop & 1)); + /* Return false when our first TX slot has not yet started + * |------remaining_time_ms---| + * | + * v + * | BC | RX | TX | RX | TX | RX | TX | BC | + */ + if (tx_slot_begin_ms < remaining_time_ms) { + return false; + } tx_slot_begin_ms = tx_slot_begin_ms - (((tx_slot_begin_ms - remaining_time_ms) / (2 * fhss_structure->ws->txrx_slot_length_ms)) * (2 * fhss_structure->ws->txrx_slot_length_ms)); uint32_t rx_slot_begin_ms = tx_slot_begin_ms - fhss_structure->ws->txrx_slot_length_ms; - // Check if we are currently on TX slot. + /* Check if we are currently on TX slot. + * | | | + * v v v + * | BC | RX | TX | RX | TX | RX | TX | BC | + */ if ((remaining_time_ms <= tx_slot_begin_ms) && (remaining_time_ms > rx_slot_begin_ms)) { return true; } @@ -551,6 +606,10 @@ static bool fhss_ws_check_tx_allowed(fhss_structure_t *fhss_structure) static bool fhss_ws_check_tx_time(fhss_structure_t *fhss_structure, uint16_t tx_length, uint8_t phy_header_length, uint8_t phy_tail_length) { + /* + * Check if there is enough time for transmitting before the next multicast slot. + */ +#ifdef FHSS_WS_PROTECT_MC_SLOTS if (!fhss_structure->ws->fhss_configuration.fhss_broadcast_interval || !fhss_structure->ws->fhss_configuration.fhss_bc_dwell_interval) { return true; } @@ -560,6 +619,13 @@ static bool fhss_ws_check_tx_time(fhss_structure_t *fhss_structure, uint16_t tx_ return false; } return true; +#else + (void) fhss_structure; + (void) tx_length; + (void) phy_header_length; + (void) phy_tail_length; + return true; +#endif } static bool fhss_ws_check_tx_conditions_callback(const fhss_api_t *api, bool is_broadcast_addr, uint8_t handle, int frame_type, uint16_t frame_length, uint8_t phy_header_length, uint8_t phy_tail_length) @@ -663,7 +729,7 @@ static void fhss_ws_data_tx_done_callback(const fhss_api_t *api, bool waiting_ac } } -static bool fhss_ws_data_tx_fail_callback(const fhss_api_t *api, uint8_t handle, int frame_type) +static bool fhss_ws_data_tx_fail_callback(const fhss_api_t *api, uint8_t handle, int frame_type, uint8_t channel) { fhss_structure_t *fhss_structure = fhss_get_object_with_api(api); if (!fhss_structure) { @@ -687,7 +753,7 @@ static bool fhss_ws_data_tx_fail_callback(const fhss_api_t *api, uint8_t handle, fhss_failed_handle_remove(fhss_structure, handle); return false; } - fhss_failed_tx->bad_channel = fhss_structure->rx_channel; + fhss_failed_tx->bad_channel = channel; } else { // Create new failure handle and return true to retransmit fhss_failed_handle_add(fhss_structure, handle, fhss_structure->rx_channel); diff --git a/source/Service_Libs/fhss/fhss_ws.h b/source/Service_Libs/fhss/fhss_ws.h index 917b599878f..c3d31fa67ef 100644 --- a/source/Service_Libs/fhss/fhss_ws.h +++ b/source/Service_Libs/fhss/fhss_ws.h @@ -21,8 +21,10 @@ * At least 4 channel retries must be used: (Initial channel + WS_NUMBER_OF_CHANNEL_RETRIES) * MAC attempts = (1+4)*4=20 attempts */ #define WS_NUMBER_OF_CHANNEL_RETRIES 4 -//TX/RX slot length in milliseconds -#define WS_MAX_TXRX_SLOT_LEN_MS 100 +// TX slot length is optimised to this packet length +#define OPTIMAL_PACKET_LENGTH 500 +// Default TX/RX slot length in milliseconds. Is used when datarate is not given by PHY. +#define WS_TXRX_SLOT_LEN_MS 100 // Default minimum broadcast synchronization interval in seconds #define DEFAULT_MIN_SYNCH_INTERVAL 60 // Drift compensation allowed if at least SYNCH_COMPENSATION_MIN_INTERVAL (seconds) since last synchronization @@ -55,5 +57,6 @@ int fhss_ws_set_parent(fhss_structure_t *fhss_structure, const uint8_t eui64[8], int fhss_ws_remove_parent(fhss_structure_t *fhss_structure, const uint8_t eui64[8]); int fhss_ws_configuration_set(fhss_structure_t *fhss_structure, const fhss_ws_configuration_t *fhss_configuration); int fhss_ws_set_hop_count(fhss_structure_t *fhss_structure, const uint8_t hop_count); +void fhss_set_txrx_slot_length(fhss_structure_t *fhss_structure); #endif /*FHSS_WS_H_*/ diff --git a/source/Service_Libs/utils/ns_crc.h b/source/Service_Libs/utils/ns_crc.h index f229b97e67e..92fad32272f 100644 --- a/source/Service_Libs/utils/ns_crc.h +++ b/source/Service_Libs/utils/ns_crc.h @@ -31,7 +31,7 @@ uint16_t crc16_ccitt(uint8_t *message, int nBytes); /** * @param data data which crc will be calculate - * @param data_length Lenght of data pointer + * @param data_length Length of data pointer * @param polynomial Polynomial which will be used to calculate CRC, POLYNOMIAL_CRC15_CCIT, POLYNOMIAL_CRC15_ANSI * @return Calculated 16bit CRC value */ diff --git a/source/libDHCPv6/dhcp_service_api.c b/source/libDHCPv6/dhcp_service_api.c index 8e321a9468f..47c09ec5e26 100644 --- a/source/libDHCPv6/dhcp_service_api.c +++ b/source/libDHCPv6/dhcp_service_api.c @@ -842,7 +842,7 @@ void dhcp_service_send_message(msg_tr_t *msg_tr_ptr) if (retval != 0) { tr_warn("dhcp service socket_sendto fails: %i", retval); } else { - tr_debug("dhcp service socket_sendto %s", trace_ipv6(msg_tr_ptr->addr.address)); + tr_info("dhcp service socket_sendto %s", trace_ipv6(msg_tr_ptr->addr.address)); } } bool dhcp_service_timer_tick(uint16_t ticks) diff --git a/source/libDHCPv6/libDHCPv6_server.c b/source/libDHCPv6/libDHCPv6_server.c index 2f19eb70a4e..f3c0ccba8c6 100644 --- a/source/libDHCPv6/libDHCPv6_server.c +++ b/source/libDHCPv6/libDHCPv6_server.c @@ -49,17 +49,81 @@ static dhcpv6_gua_server_entry_s *libdhcpv6_server_entry_allocate(void) } entry->serverDynamic_DUID = server_duid_ptr; entry->serverDynamic_DUID_length = 16; - entry->clientIdSequence = 0; + entry->firstFreedId = 0; + entry->firstUnusedId = DHCP_ADDRESS_ID_START; entry->enableAddressAutonous = true; - entry->clientIdDefaultSuffics = 0x0000000; - entry->maxSuppertedClients = 200; + entry->disableAddressListAllocation = false; + entry->maxSupportedClients = 200; entry->validLifetime = 7200; entry->removeCb = NULL; entry->addCb = NULL; ns_list_init(&entry->allocatedAddressList); return entry; } -static void libdhcpv6_address_generate(dhcpv6_gua_server_entry_s *serverInfo, dhcpv6_alloacted_address_entry_t *entry) + +static uint16_t libdhcpv6_get_next_freed_id(dhcpv6_gua_server_entry_s *serverInfo) +{ + uint16_t last_allocated_id = DHCP_ADDRESS_ID_START - 1; + ns_list_foreach(dhcpv6_allocated_address_entry_t, cur, &serverInfo->allocatedAddressList) { + + if (last_allocated_id + 1 == cur->allocatedID) { + //Last and current plus 1 so normal order + last_allocated_id = cur->allocatedID; + continue; + } + + if ((cur->allocatedID - last_allocated_id) == 2) { + //one missing sequence between last and current + if (last_allocated_id + 1 == serverInfo->firstFreedId) { + //Skip Current freedID this will update after this call to new one + last_allocated_id = cur->allocatedID; + continue; + } + } else if (last_allocated_id + 1 == serverInfo->firstFreedId) { + //Skip first if it is last freedId + return last_allocated_id + 2; + } + + return last_allocated_id + 1; + } + //No more freed ID so return 0 + return 0; +} + +static uint16_t libdhcpv6_address_id_allocate(dhcpv6_gua_server_entry_s *serverInfo) +{ + uint16_t address_id; + if (serverInfo->firstFreedId) { + address_id = serverInfo->firstFreedId; + //Discover next free freed possible value + serverInfo->firstFreedId = libdhcpv6_get_next_freed_id(serverInfo); + } else { + //Allocated new ID + address_id = serverInfo->firstUnusedId++; + } + return address_id; +} + +static void libdhcpv6_gen_suffics_from_eui48(uint8_t *ptr, uint8_t *eui48) +{ + *ptr++ = *eui48++ ^ 2; + *ptr++ = *eui48++; + *ptr++ = *eui48++; + *ptr++ = 0xff; + *ptr++ = 0xfe; + *ptr++ = *eui48++; + *ptr++ = *eui48++; + *ptr = *eui48++; +} + +static void libdhcpv6_gen_suffics_from_allocated_id(uint8_t *ptr, uint8_t *server_unique_48_bit_id, uint16_t allocated_id) +{ + memcpy(ptr, server_unique_48_bit_id, 6); + common_write_16_bit(allocated_id, ptr + 6); +} + + +static uint16_t libdhcpv6_address_generate(dhcpv6_gua_server_entry_s *serverInfo, dhcpv6_allocated_address_t *entry) { //GENERATE ADDRESS uint8_t *ptr = entry->nonTemporalAddress; @@ -70,25 +134,78 @@ static void libdhcpv6_address_generate(dhcpv6_gua_server_entry_s *serverInfo, dh entry->linkType == DHCPV6_DUID_HARDWARE_IEEE_802_NETWORKS_TYPE) { memcpy(ptr, entry->linkId, 8); *ptr ^= 2; - } else if (entry->linkType == DHCPV6_DUID_HARDWARE_EUI48_TYPE) { - *ptr++ = entry->linkId[0] ^ 2; - *ptr++ = entry->linkId[1]; - *ptr++ = entry->linkId[2]; - *ptr++ = 0xff; - *ptr++ = 0xfe; - *ptr++ = entry->linkId[3]; - *ptr++ = entry->linkId[4]; - *ptr = entry->linkId[5]; - } else { - ptr = common_write_32_bit((serverInfo->clientIdDefaultSuffics | 02000000), ptr); - ptr = common_write_32_bit((serverInfo->clientIdSequence + 2), ptr); + return 0; } - } else { - ptr = common_write_32_bit((serverInfo->clientIdDefaultSuffics | 02000000), ptr); - ptr = common_write_32_bit((serverInfo->clientIdSequence + 2), ptr); + if (entry->linkType == DHCPV6_DUID_HARDWARE_EUI48_TYPE) { + libdhcpv6_gen_suffics_from_eui48(ptr, entry->linkId); + return 0; + } + } + + uint16_t allocated_id = libdhcpv6_address_id_allocate(serverInfo); + libdhcpv6_gen_suffics_from_allocated_id(ptr, serverInfo->clientIdDefaultSuffics, allocated_id); + return allocated_id; +} + +static void libdhcpv6_address_free(dhcpv6_gua_server_entry_s *server_info, dhcpv6_allocated_address_entry_t *entry) +{ + ns_list_remove(&server_info->allocatedAddressList, entry); + if (!server_info->enableAddressAutonous) { + if (entry->allocatedID + 1 == server_info->firstUnusedId) { + server_info->firstUnusedId--; + } else if (server_info->firstFreedId == 0 || server_info->firstFreedId > entry->allocatedID) { + server_info->firstFreedId = entry->allocatedID; + } + } + ns_dyn_mem_free(entry); +} + +void libdhcpv6_allocated_address_write(uint8_t *ptr, dhcpv6_allocated_address_entry_t *address, dhcpv6_gua_server_entry_s *serverInfo) +{ + memcpy(ptr, serverInfo->guaPrefix, 8); + ptr += 8; + if (serverInfo->enableAddressAutonous) { + //Generate address from link layer address + if (address->linkType == DHCPV6_DUID_HARDWARE_EUI64_TYPE || + address->linkType == DHCPV6_DUID_HARDWARE_IEEE_802_NETWORKS_TYPE) { + memcpy(ptr, address->linkId, 8); + *ptr ^= 2; + return; + } else if (address->linkType == DHCPV6_DUID_HARDWARE_EUI48_TYPE) { + libdhcpv6_gen_suffics_from_eui48(ptr, address->linkId); + return; + } } - serverInfo->clientIdSequence++; + //Generate from 16-bit allocate and default suffic's + libdhcpv6_gen_suffics_from_allocated_id(ptr, serverInfo->clientIdDefaultSuffics, address->allocatedID); +} + +static bool libdhcpv6_address_suffics_compare(const uint8_t *suffics, dhcpv6_allocated_address_entry_t *address, dhcpv6_gua_server_entry_s *serverInfo) +{ + uint8_t allocated_suffics[8]; + if (serverInfo->enableAddressAutonous) { + //Generate address from link layer address + if (address->linkType == DHCPV6_DUID_HARDWARE_EUI64_TYPE || + address->linkType == DHCPV6_DUID_HARDWARE_IEEE_802_NETWORKS_TYPE) { + memcpy(allocated_suffics, address->linkId, 8); + allocated_suffics[0] ^= 2; + goto compare_suffics; + } else if (address->linkType == DHCPV6_DUID_HARDWARE_EUI48_TYPE) { + libdhcpv6_gen_suffics_from_eui48(allocated_suffics, address->linkId); + goto compare_suffics; + } + } + //Generate from 16-bit allocate and default suffic's + libdhcpv6_gen_suffics_from_allocated_id(allocated_suffics, serverInfo->clientIdDefaultSuffics, address->allocatedID); + +compare_suffics: + if (memcmp(allocated_suffics, suffics, 8)) { + return false; + } + + return true; + } @@ -97,15 +214,16 @@ void libdhcpv6_gua_servers_time_update(uint32_t timeUpdateInSeconds) //Check All allocated server inside this loop ns_list_foreach(dhcpv6_gua_server_entry_s, cur, &dhcpv6_gua_server_list) { //Check All allocated address in this module - ns_list_foreach_safe(dhcpv6_alloacted_address_entry_t, address, &cur->allocatedAddressList) { + ns_list_foreach_safe(dhcpv6_allocated_address_entry_t, address, &cur->allocatedAddressList) { //Update if (address->preferredLifetime) { if (address->preferredLifetime <= timeUpdateInSeconds) { //Stop use this address for leasequery and delete Route or address map - address->preferredLifetime = 0; if (cur->removeCb) { - cur->removeCb(cur->interfaceId, address->nonTemporalAddress, cur->guaPrefix); + uint8_t allocated_address[16]; + libdhcpv6_allocated_address_write(allocated_address, address, cur); + cur->removeCb(cur->interfaceId, allocated_address, cur->guaPrefix); } } else { address->preferredLifetime -= timeUpdateInSeconds; @@ -113,8 +231,7 @@ void libdhcpv6_gua_servers_time_update(uint32_t timeUpdateInSeconds) } if (address->lifetime <= timeUpdateInSeconds) { - ns_list_remove(&cur->allocatedAddressList, address); - ns_dyn_mem_free(address); + libdhcpv6_address_free(cur, address); } else { address->lifetime -= timeUpdateInSeconds; } @@ -187,6 +304,15 @@ dhcpv6_gua_server_entry_s *libdhcpv6_gua_server_allocate(uint8_t *prefix, int8_t duid_length = libdhcpv6_duid_linktype_size(serverDUIDType) + 2; ptr = common_write_16_bit(serverDUIDType, ptr); memcpy(ptr, serverDUID, libdhcpv6_duid_linktype_size(serverDUIDType)); + //SET Defaultsuffics + if (libdhcpv6_duid_linktype_size(serverDUIDType) == 8) { + memcpy(entry->clientIdDefaultSuffics, serverDUID, 3); + memcpy(entry->clientIdDefaultSuffics + 3, serverDUID + 5, 3); + } else { + memcpy(entry->clientIdDefaultSuffics, serverDUID, 6); + } + + entry->clientIdDefaultSuffics[0] ^= 0x02; //SET DUID if (libdhcpv6_server_duid_set(entry, duid_ll, DHCPV6_DUID_LINK_LAYER_TYPE, duid_length) != 0) { @@ -208,7 +334,7 @@ void libdhcpv6_gua_server_free_by_prefix_and_interfaceid(uint8_t *prefix, int8_t dhcpv6_gua_server_entry_s *serverInfo = libdhcpv6_server_data_get_by_prefix_and_interfaceid(interfaceId, prefix); if (serverInfo) { if ((serverInfo->interfaceId == interfaceId) && (memcmp(serverInfo->guaPrefix, prefix, 8) == 0)) { - ns_list_foreach_safe(dhcpv6_alloacted_address_entry_t, cur, &serverInfo->allocatedAddressList) { + ns_list_foreach_safe(dhcpv6_allocated_address_entry_t, cur, &serverInfo->allocatedAddressList) { ns_list_remove(&serverInfo->allocatedAddressList, cur); ns_dyn_mem_free(cur); } @@ -219,26 +345,52 @@ void libdhcpv6_gua_server_free_by_prefix_and_interfaceid(uint8_t *prefix, int8_t } } -static dhcpv6_alloacted_address_entry_t *libdhcpv6_address_entry_allocate(uint32_t validLifetime) +static void libdhcpv6_address_entry_lifetime_set(dhcpv6_allocated_address_entry_t *entry, uint32_t validLifetime) { - dhcpv6_alloacted_address_entry_t *entry = ns_dyn_mem_alloc(sizeof(dhcpv6_alloacted_address_entry_t)); - if (entry) { - if (validLifetime != 0xffffffff) { - entry->lifetime = validLifetime; - entry->preferredLifetime = (validLifetime >> 1); - } else { - entry->lifetime = 0xffffffff; - entry->preferredLifetime = 0xffffffff; - } + if (validLifetime != 0xffffffff) { + entry->lifetime = validLifetime; + entry->preferredLifetime = (validLifetime >> 1); + } else { + entry->lifetime = 0xffffffff; + entry->preferredLifetime = 0xffffffff; } - return entry; } -dhcpv6_alloacted_address_entry_t *libdhcpv6_address_get_from_allocated_list(dhcpv6_gua_server_entry_s *serverInfo, const uint8_t *address) +static void libdhcpv6_copy_allocated_entry_to_temp(dhcpv6_allocated_address_entry_t *cur, dhcpv6_allocated_address_t *address, dhcpv6_gua_server_entry_s *serverInfo) +{ + libdhcpv6_allocated_address_write(address->nonTemporalAddress, cur, serverInfo); + memcpy(address->linkId, cur->linkId, 8); + address->T0 = cur->T0; + address->T1 = cur->T1; + address->iaID = cur->iaID; + address->lifetime = cur->lifetime; + address->preferredLifetime = cur->preferredLifetime; + address->linkType = cur->linkType; +} + + +static void libdhcpv6_copy_temp_to_allocated_entry(dhcpv6_allocated_address_entry_t *cur, dhcpv6_allocated_address_t *address, uint16_t allocated_id) +{ + memcpy(cur->linkId, address->linkId, 8); + cur->allocatedID = allocated_id; + cur->T0 = address->T0; + cur->T1 = address->T1; + cur->iaID = address->iaID; + cur->lifetime = address->lifetime; + cur->preferredLifetime = address->preferredLifetime; + cur->linkType = address->linkType; +} + +dhcpv6_allocated_address_t *libdhcpv6_address_get_from_allocated_list(dhcpv6_gua_server_entry_s *serverInfo, const uint8_t *address) { - ns_list_foreach(dhcpv6_alloacted_address_entry_t, cur, &serverInfo->allocatedAddressList) { - if (memcmp(cur->nonTemporalAddress, address, 16) == 0) { - return cur; + if (memcmp(serverInfo->guaPrefix, address, 8)) { + return NULL; + } + + ns_list_foreach(dhcpv6_allocated_address_entry_t, cur, &serverInfo->allocatedAddressList) { + if (libdhcpv6_address_suffics_compare(address + 8, cur, serverInfo) == 0) { + libdhcpv6_copy_allocated_entry_to_temp(cur, &serverInfo->tempAddressEntry, serverInfo); + return &serverInfo->tempAddressEntry; } } return NULL; @@ -246,49 +398,95 @@ dhcpv6_alloacted_address_entry_t *libdhcpv6_address_get_from_allocated_list(dhcp void libdhcpv6_address_rm_from_allocated_list(dhcpv6_gua_server_entry_s *serverInfo, const uint8_t *address) { - ns_list_foreach_safe(dhcpv6_alloacted_address_entry_t, cur, &serverInfo->allocatedAddressList) { - if (memcmp(cur->nonTemporalAddress, address, 16) == 0) { - ns_list_remove(&serverInfo->allocatedAddressList, cur); - ns_dyn_mem_free(cur); + if (memcmp(serverInfo->guaPrefix, address, 8)) { + return; + } + + ns_list_foreach_safe(dhcpv6_allocated_address_entry_t, cur, &serverInfo->allocatedAddressList) { + if (libdhcpv6_address_suffics_compare(address + 8, cur, serverInfo) == 0) { + libdhcpv6_address_free(serverInfo, cur); return; } } } -dhcpv6_alloacted_address_entry_t *libdhcpv6_address_allocated_list_scan(dhcpv6_gua_server_entry_s *serverInfo, uint8_t *linkId, uint16_t linkType, uint32_t iaID, uint32_t T0, uint32_t T1, bool allocateNew) + +static void libdhcpv6_address_id_add_to_list(dhcpv6_gua_server_entry_s *serverInfo, dhcpv6_allocated_address_entry_t *allocated) +{ + if (serverInfo->firstUnusedId != allocated->allocatedID + 1) { + ns_list_foreach_safe(dhcpv6_allocated_address_entry_t, cur, &serverInfo->allocatedAddressList) { + if (cur->allocatedID > allocated->allocatedID) { + //Add before new allocated + if (cur->link.prev) { + ns_list_add_before(&serverInfo->allocatedAddressList, cur, allocated); + } else { + //New first + ns_list_add_to_start(&serverInfo->allocatedAddressList, allocated); + } + return; + } + } + } + ns_list_add_to_end(&serverInfo->allocatedAddressList, allocated); +} + + +dhcpv6_allocated_address_t *libdhcpv6_address_allocated_list_scan(dhcpv6_gua_server_entry_s *serverInfo, uint8_t *linkId, uint16_t linkType, uint32_t iaID, uint32_t T0, uint32_t T1, bool allocateNew) { - dhcpv6_alloacted_address_entry_t *newEntry = NULL; + dhcpv6_allocated_address_t *newEntry = NULL; + dhcpv6_allocated_address_entry_t *allocatedEntry = NULL; uint16_t duiLength = 6; if (linkType == DHCPV6_DUID_HARDWARE_EUI64_TYPE || linkType == DHCPV6_DUID_HARDWARE_IEEE_802_NETWORKS_TYPE) { duiLength = 8; } - ns_list_foreach(dhcpv6_alloacted_address_entry_t, cur, &serverInfo->allocatedAddressList) { + + if (serverInfo->enableAddressAutonous && serverInfo->disableAddressListAllocation) { + //Accept allways when autonous + newEntry = &serverInfo->tempAddressEntry; + allocateNew = false; + } + + ns_list_foreach(dhcpv6_allocated_address_entry_t, cur, &serverInfo->allocatedAddressList) { if (cur->linkType == linkType) { if (memcmp(cur->linkId, linkId, duiLength) == 0) { cur->iaID = iaID; - if (serverInfo->validLifetime != 0xffffffff) { - cur->lifetime = serverInfo->validLifetime ; - cur->preferredLifetime = (serverInfo->validLifetime >> 1); - } else { - cur->lifetime = 0xffffffff; - cur->preferredLifetime = 0xffffffff; - } - return cur; + libdhcpv6_address_entry_lifetime_set(cur, serverInfo->validLifetime); + libdhcpv6_copy_allocated_entry_to_temp(cur, &serverInfo->tempAddressEntry, serverInfo); + return &serverInfo->tempAddressEntry; } } } if (allocateNew) { - if (ns_list_count(&serverInfo->allocatedAddressList) < serverInfo->maxSuppertedClients) { - newEntry = libdhcpv6_address_entry_allocate(serverInfo->validLifetime); - if (newEntry) { - memcpy(newEntry->linkId, linkId, duiLength); - newEntry->linkType = linkType; - newEntry->iaID = iaID; - newEntry->T0 = T0; - newEntry->T1 = T1; - libdhcpv6_address_generate(serverInfo, newEntry); - ns_list_add_to_end(&serverInfo->allocatedAddressList, newEntry); + if (ns_list_count(&serverInfo->allocatedAddressList) < serverInfo->maxSupportedClients) { + allocatedEntry = ns_dyn_mem_alloc(sizeof(dhcpv6_allocated_address_entry_t)); + if (allocatedEntry) { + newEntry = &serverInfo->tempAddressEntry; + } + } + } + if (newEntry) { + + if (serverInfo->validLifetime != 0xffffffff) { + newEntry->lifetime = serverInfo->validLifetime; + newEntry->preferredLifetime = (serverInfo->validLifetime >> 1); + } else { + newEntry->lifetime = 0xffffffff; + newEntry->preferredLifetime = 0xffffffff; + } + memcpy(newEntry->linkId, linkId, duiLength); + newEntry->linkType = linkType; + newEntry->iaID = iaID; + newEntry->T0 = T0; + newEntry->T1 = T1; + uint16_t allocated_id = libdhcpv6_address_generate(serverInfo, newEntry); + if (!serverInfo->disableAddressListAllocation) { + libdhcpv6_copy_temp_to_allocated_entry(allocatedEntry, newEntry, allocated_id); + if (serverInfo->enableAddressAutonous) { + ns_list_add_to_end(&serverInfo->allocatedAddressList, allocatedEntry); + } else { + //Add to list to proper order + libdhcpv6_address_id_add_to_list(serverInfo, allocatedEntry); } } } diff --git a/source/libDHCPv6/libDHCPv6_server.h b/source/libDHCPv6/libDHCPv6_server.h index ba17b340f5d..3b4c0643e2e 100644 --- a/source/libDHCPv6/libDHCPv6_server.h +++ b/source/libDHCPv6/libDHCPv6_server.h @@ -28,29 +28,36 @@ #include "libDHCPv6/libDHCPv6.h" +#define MAX_SUPPORTED_ADDRESS_LIST_SIZE 0x0000fffd +#define DHCP_ADDRESS_ID_START 2 + typedef void (dhcp_address_prefer_remove_cb)(int8_t interfaceId, uint8_t *targetAddress, void *prefix_info); -typedef struct dhcpv6_alloacted_address_entry_s { - uint8_t nonTemporalAddress[16]; +typedef struct dhcpv6_allocated_address_entry_s { uint8_t linkId[8]; /*!< Services UL64 */ - uint16_t linkType; uint32_t iaID; uint32_t T0; uint32_t T1; uint32_t preferredLifetime; uint32_t lifetime; + uint16_t linkType; + uint16_t allocatedID; ns_list_link_t link; /*!< List link entry */ -} dhcpv6_alloacted_address_entry_t; +} dhcpv6_allocated_address_entry_t; -typedef NS_LIST_HEAD(dhcpv6_alloacted_address_entry_t, link) dhcpv6_alloacted_address_list_t; -typedef struct thread_dhcpv6_server_data_s { - uint8_t prefix[8]; /*!< Services Prefix */ - uint16_t maxSuppertedClients; - uint32_t clientIdSequence; /*!< Define */ - dhcpv6_alloacted_address_list_t allocatedAddressList; - ns_list_link_t link; /*!< List link entry */ -} dhcpv6_server_data_entry_t; +typedef struct dhcpv6_allocated_address_s { + uint8_t nonTemporalAddress[16]; + uint8_t linkId[8]; /*!< Services UL64 */ + uint16_t linkType; + uint32_t iaID; + uint32_t T0; + uint32_t T1; + uint32_t preferredLifetime; + uint32_t lifetime; +} dhcpv6_allocated_address_t; + +typedef NS_LIST_HEAD(dhcpv6_allocated_address_entry_t, link) dhcpv6_allocated_address_list_t; typedef struct dhcp_address_cache_update { uint8_t *allocatedAddress; @@ -62,19 +69,22 @@ typedef bool (dhcp_address_add_notify_cb)(int8_t interfaceId, dhcp_address_cache typedef struct dhcpv6_gua_server_entry_s { int8_t interfaceId; - bool enableAddressAutonous; + bool enableAddressAutonous: 1; + bool disableAddressListAllocation: 1; uint16_t socketInstance_id; uint8_t guaPrefix[8]; uint8_t serverDynamic_DUID_length; - uint32_t maxSuppertedClients; - uint32_t clientIdDefaultSuffics; - uint32_t clientIdSequence; /*!< Define */ + uint32_t maxSupportedClients; + uint8_t clientIdDefaultSuffics[6]; + uint16_t firstFreedId; + uint16_t firstUnusedId; /*!< This is first unused Id */ uint32_t validLifetime; dhcp_duid_options_params_t serverDUID; uint8_t *serverDynamic_DUID; dhcp_address_prefer_remove_cb *removeCb; dhcp_address_add_notify_cb *addCb; - dhcpv6_alloacted_address_list_t allocatedAddressList; + dhcpv6_allocated_address_list_t allocatedAddressList; + dhcpv6_allocated_address_t tempAddressEntry; ns_list_link_t link; /*!< List link entry */ } dhcpv6_gua_server_entry_s; @@ -84,10 +94,11 @@ int libdhcpv6_server_duid_set(dhcpv6_gua_server_entry_s *server_info, uint8_t *d void libdhcpv6_gua_server_free_by_prefix_and_interfaceid(uint8_t *prefix, int8_t interfaceId); void libdhcpv6_gua_servers_time_update(uint32_t timeUpdateInSeconds); void libdhcpv6_address_rm_from_allocated_list(dhcpv6_gua_server_entry_s *serverInfo, const uint8_t *address); -dhcpv6_alloacted_address_entry_t *libdhcpv6_address_get_from_allocated_list(dhcpv6_gua_server_entry_s *serverInfo, const uint8_t *address); +dhcpv6_allocated_address_t *libdhcpv6_address_get_from_allocated_list(dhcpv6_gua_server_entry_s *serverInfo, const uint8_t *address); dhcpv6_gua_server_entry_s *libdhcpv6_server_data_get_by_prefix_and_interfaceid(int8_t interfaceId, const uint8_t *prefixPtr); dhcpv6_gua_server_entry_s *libdhcpv6_server_data_get_by_prefix_and_socketinstance(uint16_t socketInstance, uint8_t *prefixPtr); -dhcpv6_alloacted_address_entry_t *libdhcpv6_address_allocated_list_scan(dhcpv6_gua_server_entry_s *serverInfo, uint8_t *euid64, uint16_t linkType, uint32_t iaID, uint32_t T0, uint32_t T1, bool allocateNew); +dhcpv6_allocated_address_t *libdhcpv6_address_allocated_list_scan(dhcpv6_gua_server_entry_s *serverInfo, uint8_t *euid64, uint16_t linkType, uint32_t iaID, uint32_t T0, uint32_t T1, bool allocateNew); +void libdhcpv6_allocated_address_write(uint8_t *ptr, dhcpv6_allocated_address_entry_t *address, dhcpv6_gua_server_entry_s *serverInfo); #else #define libdhcpv6_gua_server_list_empty() true #define libdhcpv6_server_data_get_by_prefix_and_interfaceid(interfaceId, prefixPtr) NULL diff --git a/source/libNET/src/net_6lowpan_parameter_api.c b/source/libNET/src/net_6lowpan_parameter_api.c index 59bea2198aa..cd1649df3c8 100644 --- a/source/libNET/src/net_6lowpan_parameter_api.c +++ b/source/libNET/src/net_6lowpan_parameter_api.c @@ -65,6 +65,7 @@ int8_t net_6lowpan_nd_parameter_set(const nd_parameters_s *p) return 0; #else + (void) p; return -2; #endif } @@ -89,6 +90,8 @@ int8_t net_6lowpan_nd_timer_base_tick_set(uint8_t base_tick_x_100ms) } nd_base_tick = base_tick_x_100ms; +#else + (void) base_tick_x_100ms; #endif return 0; } @@ -103,5 +106,7 @@ void net_6lowpan_nd_parameter_read(nd_parameters_s *p) { #ifdef HAVE_6LOWPAN_ND *p = nd_params; +#else + (void) p; #endif } diff --git a/source/libNET/src/net_load_balance.c b/source/libNET/src/net_load_balance.c index 90f4960dffd..a643d90fde3 100644 --- a/source/libNET/src/net_load_balance.c +++ b/source/libNET/src/net_load_balance.c @@ -146,12 +146,14 @@ int8_t net_load_balance_network_switch_cb_set(int8_t interface_id, net_load_bala return load_balance_network_switch_cb_set(interface_ptr->lb_api, network_switch_notify); #else + (void) interface_id; + (void) network_switch_notify; return -1; #endif } -int8_t net_load_balance_create(int8_t interface_id, bool enable_periodic_beacon_interval) +int8_t net_load_balance_create(int8_t interface_id, bool enable_periodic_beacon_interval) { #ifdef HAVE_6LOWPAN_ND protocol_interface_info_entry_t *interface_ptr = protocol_stack_interface_info_get_by_id(interface_id); @@ -188,6 +190,8 @@ int8_t net_load_balance_create(int8_t interface_id, bool enable_periodic_beacon return 0; #else + (void) interface_id; + (void) enable_periodic_beacon_interval; return -1; #endif } @@ -205,6 +209,7 @@ int8_t net_load_balance_delete(int8_t interface_id) return load_balance_delete(lb_api); #else + (void) interface_id; return -1; #endif } @@ -223,6 +228,9 @@ int8_t net_load_balance_threshold_set(int8_t interface_id, uint8_t threshold_min return load_balance_network_threshold_set(interface_ptr->lb_api, threshold_min, threshold_max); #else + (void) interface_id; + (void) threshold_min; + (void) threshold_max; return -1; #endif } @@ -259,8 +267,10 @@ void net_load_balance_internal_state_activate(protocol_interface_info_entry_t *i set_req.value_pointer = &state; set_req.value_size = sizeof(bool); interface_ptr->mac_api->mlme_req(interface_ptr->mac_api, MLME_SET, &set_req); +#else + (void) interface_ptr; + (void) state; #endif - } #ifdef HAVE_RPL @@ -361,6 +371,8 @@ int8_t net_load_balance_set_max_probability(int8_t interface_id, uint8_t max_p) return load_balance_set_max_probability(interface_ptr->lb_api, max_p); #else + (void) interface_id; + (void) max_p; return -1; #endif } diff --git a/source/libNET/src/ns_net.c b/source/libNET/src/ns_net.c index 5ee8a60dc66..e369f6c3758 100644 --- a/source/libNET/src/ns_net.c +++ b/source/libNET/src/ns_net.c @@ -400,6 +400,10 @@ int8_t arm_nwk_6lowpan_gp_address_mode(int8_t interface_id, net_6lowpan_gp_addre return 0; #else + (void) interface_id; + (void) mode; + (void) short_address_base; + (void) define_new_short_address_at_DAD; return -2; #endif } @@ -895,7 +899,7 @@ int8_t arm_pana_client_key_pull(int8_t interface_id) return pana_client_key_pull(interface_id); } -int8_t arm_nwk_link_layer_security_mode(int8_t interface_id, net_6lowpan_link_layer_sec_mode_e mode, uint8_t sec_level, const net_link_layer_psk_security_info_s *psk_key_info) +int8_t arm_nwk_link_layer_security_mode(int8_t interface_id, net_6lowpan_link_layer_sec_mode_e mode, uint8_t sec_level, const net_link_layer_psk_security_info_s *psk_key_info) { protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(interface_id); if (!cur || thread_info(cur) || !cur->mac_parameters || (cur->configure_flags & INTERFACE_BOOTSTRAP_DEFINED) == 0) { @@ -903,6 +907,9 @@ int8_t arm_nwk_link_layer_security_mode(int8_t interface_id, net_6lowpan_link_la } #ifndef HAVE_6LOWPAN_ND + (void) mode; + (void) sec_level; + (void) psk_key_info; return -1; #else if (cur->lowpan_info & INTERFACE_NWK_ACTIVE) { diff --git a/source/libNET/src/socket_api.c b/source/libNET/src/socket_api.c index 65b192145dd..2cf27829c5e 100644 --- a/source/libNET/src/socket_api.c +++ b/source/libNET/src/socket_api.c @@ -108,6 +108,8 @@ int8_t socket_close(int8_t sid) int8_t socket_listen(int8_t socket, uint8_t backlog) { #ifdef NO_TCP + (void) socket; + (void) backlog; return -1; #else socket_t *socket_ptr = socket_pointer_get(socket); @@ -141,6 +143,9 @@ int8_t socket_listen(int8_t socket, uint8_t backlog) int8_t socket_accept(int8_t listen_socket_id, ns_address_t *addr, void (*passed_fptr)(void *)) { #ifdef NO_TCP + (void) listen_socket_id; + (void) addr; + (void) passed_fptr; return -1; #else socket_t *socket_ptr = socket_pointer_get(listen_socket_id); @@ -189,6 +194,8 @@ int8_t socket_accept(int8_t listen_socket_id, ns_address_t *addr, void (*passed_ int8_t socket_shutdown(int8_t socket, uint8_t how) { #ifdef NO_TCP + (void) socket; + (void) how; return -1; #else socket_t *socket_ptr = socket_pointer_get(socket); @@ -608,8 +615,8 @@ int8_t socket_connect(int8_t socket, ns_address_t *address, uint8_t randomly_tak socket_ptr->flags |= SOCKET_FLAG_CONNECTING; } -#endif exit: +#endif if (status != 0) { memcpy(inet_pcb->remote_address, ns_in6addr_any, 16); inet_pcb->remote_port = 0; diff --git a/sources.mk b/sources.mk index 1cc99981bd2..840c51105d3 100644 --- a/sources.mk +++ b/sources.mk @@ -136,6 +136,7 @@ SRCS += \ source/Service_Libs/fhss/fhss_common.c \ source/Service_Libs/fhss/channel_functions.c \ source/Service_Libs/fhss/channel_list.c \ + source/Service_Libs/fhss/fhss_test_api.c \ source/Service_Libs/fnv_hash/fnv_hash.c \ source/Service_Libs/hmac/hmac_sha1.c \ source/Service_Libs/ieee_802_11/ieee_802_11.c \