From ca1f4fea7ae25ae4a11c54821309bc12e104c45f Mon Sep 17 00:00:00 2001 From: Arto Kinnunen Date: Thu, 23 Sep 2021 11:44:04 +0300 Subject: [PATCH] Squashed 'features/nanostack/sal-stack-nanostack/' changes from 4a3c5c525b..225a4af94f 225a4af94f Remove files from tests folder 58d2c8fa82 Merge remote-tracking branch 'origin/release_internal' into release_external 921b4b3273 Wi-SUN FAN 1.1 dynamic MDR data request enabler b8722e81b1 Corrected BR removing of waiting list entry when supplicant is in key storage 0d54d7ab39 Adjust trace levels (#2692) 681d9eae8d Added reset for pan id and version to BR network start 30d4fb2ed9 Renaming and cleaning ws bootstrap (#2688) e0da19dbf0 Add Wi-SUN host configuration (#2690) 50ecc3d0f0 Refactoring Wi-SUN stack (#2686) 9d2386d484 Renamed operation mode to operating mode. 2f755bcfdb RF config resolver and some refactoring (#2683) 86c6d19e06 Fixed WS IE PCAP read operation wrong length usage. cd3a4c2a62 Config: Remove additional HAVE_WS_ROUTER (#2684) cdd7f2d868 Added API for configure supported Phy capability. a00a3c0a02 Wi-SUN FAN 1.1 PCAP IE update 2d063d3b4a Moved State machine and timer functions to own files edb8bec609 Corrected system time check function return values 85358a635b Moved Wi-SUN Bootstrap Event handling to separate device handlers 61cbdde485 MAC to support mode switch on single channel (#2678) 1006d29e4d Added storing of PAN ID to NVM in BBR 7bf0028c66 Corrected system time jump detection on BR startup e60974d815 Split Wi-SUN bootstrap to device types a3f341266e MAC data req: API to support mode switch (#2674) cad5122a90 Removed automatic network size configuration (#2673) 35d313224a MAC: Callback set to resolve PHY mode ID (#2672) 0c5faca469 Added support for large system time changes (e.g. due to NTP) (#2670) c94b306431 LFN version and LGTK Hash IE advertisment and learn 8e075119f6 Use FAN version constant instead of pure number a5566b22b2 Channel Plan 2 validation and FAN 1.0 reject 42dba4151e Wi-Sun IE FAN 1.1 update 1d56070c24 EU channel plan ids (FAN 1.1) supported (#2668) fc4f41fb30 Add test API empty function 37efc7ec25 Add version 1.1 basic support e1558fbb1a Implemented mode switch PHR build and parse (#2665) cbd8a15d31 Corrected frame counter storing threshold check 37f7ae95eb Time configuration distribution using DHCPv6 vendor data 7415bc724b Added checks for Border Router frame counter space exhaustion (#2660) f1a65ecbe8 Mode switch PHY API (#2663) e54231b5d4 Do not check buffer age when virtual RF driver used (#2662) cc8c7bd38f arm_network_certificate_chain_set() returns -2 when PANA is disabled 319dd91bce Fix dubious semicolon in #define 2ff51abeca Remove extra '\n' in traces 19376c8837 Simplify array indexes c808661836 Fix ASAN warnings about overflows in bit shifts f998008f60 Fix use-after-free in mac_helper_coordinator_address_set() 4d04541d70 Wi-SUN header and Paylod IE element lenght future proof update. 935898badf Medium network PAN_TIMEOUT changed to 30 minutes 1af7cfeb24 Updated nanostack to be compatible with mbed TLS 3.0 (#2657) 29744e0e46 If Router Solicitation creation fails no longer tries to retry the RS right away (#2655) 2b889e92b0 Added automatic test procedure triggering during bootstrap ed9eb0503f GTKs are removed only when fresh GTK hash is received 81ecdc24f8 Added empty function for test procedure trigger 14439b4aa9 Added support for triggering test procedures b8a67a9e36 Update CHANGELOG.md for Nanostack 14.0.0 (#2649) git-subtree-dir: features/nanostack/sal-stack-nanostack git-subtree-split: 225a4af94f3faf5ca3726e86bc96cdda4c99a469 --- nanostack/mac_api.h | 67 +- nanostack/net_ws_test.h | 17 + nanostack/net_ws_test_ext.h | 119 + nanostack/ns_sha256.h | 32 + nanostack/ns_time_api.h | 45 + nanostack/platform/arm_hal_phy.h | 1 + nanostack/ws_bbr_api.h | 32 + nanostack/ws_management_api.h | 47 + .../Bootstraps/Generic/protocol_6lowpan.c | 8 +- .../Generic/protocol_6lowpan_bootstrap.c | 4 +- source/6LoWPAN/MAC/mac_helper.c | 3 +- source/6LoWPAN/MAC/mac_ie_lib.c | 27 + source/6LoWPAN/MAC/mac_ie_lib.h | 3 + source/6LoWPAN/Thread/thread_bootstrap.c | 2 +- .../6LoWPAN/Thread/thread_commissioning_api.c | 2 +- source/6LoWPAN/Thread/thread_common.c | 8 +- source/6LoWPAN/adaptation_interface.c | 2 +- source/6LoWPAN/ws/ws_bbr_api.c | 179 +- source/6LoWPAN/ws/ws_bbr_api_internal.h | 2 + source/6LoWPAN/ws/ws_bootstrap.c | 2256 ++++++----------- source/6LoWPAN/ws/ws_bootstrap.h | 138 +- source/6LoWPAN/ws/ws_bootstrap_6lbr.c | 479 ++++ source/6LoWPAN/ws/ws_bootstrap_6lbr.h | 43 + source/6LoWPAN/ws/ws_bootstrap_ffn.c | 1027 ++++++++ source/6LoWPAN/ws/ws_bootstrap_ffn.h | 43 + source/6LoWPAN/ws/ws_bootstrap_lfn.c | 172 ++ source/6LoWPAN/ws/ws_bootstrap_lfn.h | 43 + source/6LoWPAN/ws/ws_cfg_settings.c | 432 +--- source/6LoWPAN/ws/ws_cfg_settings.h | 59 +- source/6LoWPAN/ws/ws_common.c | 308 +-- source/6LoWPAN/ws/ws_common.h | 76 +- source/6LoWPAN/ws/ws_common_defines.h | 210 +- source/6LoWPAN/ws/ws_config.h | 2 +- source/6LoWPAN/ws/ws_empty_functions.c | 24 + source/6LoWPAN/ws/ws_ie_lib.c | 1032 +++++++- source/6LoWPAN/ws/ws_ie_lib.h | 55 + source/6LoWPAN/ws/ws_llc.h | 18 +- source/6LoWPAN/ws/ws_llc_data_service.c | 116 +- source/6LoWPAN/ws/ws_management_api.c | 121 +- source/6LoWPAN/ws/ws_neighbor_class.c | 27 +- source/6LoWPAN/ws/ws_neighbor_class.h | 11 + source/6LoWPAN/ws/ws_pae_auth.c | 234 +- source/6LoWPAN/ws/ws_pae_auth.h | 23 +- source/6LoWPAN/ws/ws_pae_controller.c | 92 +- source/6LoWPAN/ws/ws_pae_key_storage.c | 2 +- source/6LoWPAN/ws/ws_pae_nvm_data.c | 84 +- source/6LoWPAN/ws/ws_pae_nvm_data.h | 29 +- source/6LoWPAN/ws/ws_pae_nvm_store.c | 27 + source/6LoWPAN/ws/ws_pae_nvm_store.h | 32 + source/6LoWPAN/ws/ws_pae_supp.c | 6 +- source/6LoWPAN/ws/ws_pae_supp.h | 3 +- source/6LoWPAN/ws/ws_pae_time.c | 66 +- source/6LoWPAN/ws/ws_pae_time.h | 32 +- source/6LoWPAN/ws/ws_phy.c | 353 +++ source/6LoWPAN/ws/ws_phy.h | 51 + source/6LoWPAN/ws/ws_test_api.c | 52 +- source/BorderRouter/border_router.c | 2 +- source/Core/ns_address_internal.c | 2 +- source/Core/ns_socket.c | 4 +- source/DHCPv6_client/dhcpv6_client_service.c | 2 +- source/MAC/IEEE802_15_4/mac_cca_threshold.c | 2 +- source/MAC/IEEE802_15_4/mac_data_buffer.h | 1 + source/MAC/IEEE802_15_4/mac_defines.h | 16 +- source/MAC/IEEE802_15_4/mac_mcps_sap.c | 26 +- source/MAC/IEEE802_15_4/mac_mcps_sap.h | 2 +- source/MAC/IEEE802_15_4/mac_mlme.c | 2 +- source/MAC/IEEE802_15_4/mac_mode_switch.c | 240 ++ source/MAC/IEEE802_15_4/mac_mode_switch.h | 56 + source/MAC/IEEE802_15_4/mac_pd_sap.c | 71 +- source/MAC/IEEE802_15_4/mac_pd_sap.h | 2 +- source/MAC/IEEE802_15_4/mac_timer.c | 2 +- source/MAC/IEEE802_15_4/sw_mac.c | 23 +- source/MPL/mpl.c | 2 +- .../NWK_INTERFACE/Include/protocol_abstract.h | 1 + source/NWK_INTERFACE/protocol_core.c | 15 +- source/NWK_INTERFACE/protocol_timer.c | 2 +- source/RPL/rpl_control.c | 14 + source/RPL/rpl_control.h | 5 + .../radius_sec_prot/radius_client_sec_prot.c | 52 + source/Security/protocols/sec_prot_keys.c | 18 +- source/Security/protocols/sec_prot_keys.h | 13 +- source/Security/protocols/sec_prot_lib.c | 12 + .../protocols/tls_sec_prot/tls_sec_prot.c | 2 +- .../protocols/tls_sec_prot/tls_sec_prot_lib.c | 67 +- source/Service_Libs/fhss/channel_list.c | 6 +- source/Service_Libs/fhss/fhss_ws.c | 2 +- source/Service_Libs/hmac/hmac_md.c | 6 +- source/Service_Libs/nd_proxy/nd_proxy.c | 4 +- source/Service_Libs/nist_aes_kw/nist_aes_kw.c | 12 +- source/Service_Libs/utils/ns_time.c | 29 + source/Service_Libs/utils/ns_time.h | 28 + source/configs/base/cfg_ws_host.h | 26 + source/configs/base/cfg_ws_router.h | 11 +- source/configs/cfg_generic.h | 1 + source/configs/cfg_ws_host.h | 23 + source/ipv6_stack/protocol_ipv6.c | 10 +- source/libDHCPv6/libDHCPv6_vendordata.c | 63 +- source/libDHCPv6/libDHCPv6_vendordata.h | 14 + source/libNET/src/ns_net.c | 22 +- sources.mk | 5 + 100 files changed, 6779 insertions(+), 2517 deletions(-) create mode 100644 nanostack/net_ws_test_ext.h create mode 100644 source/6LoWPAN/ws/ws_bootstrap_6lbr.c create mode 100644 source/6LoWPAN/ws/ws_bootstrap_6lbr.h create mode 100644 source/6LoWPAN/ws/ws_bootstrap_ffn.c create mode 100644 source/6LoWPAN/ws/ws_bootstrap_ffn.h create mode 100644 source/6LoWPAN/ws/ws_bootstrap_lfn.c create mode 100644 source/6LoWPAN/ws/ws_bootstrap_lfn.h create mode 100644 source/6LoWPAN/ws/ws_phy.c create mode 100644 source/6LoWPAN/ws/ws_phy.h create mode 100644 source/MAC/IEEE802_15_4/mac_mode_switch.c create mode 100644 source/MAC/IEEE802_15_4/mac_mode_switch.h create mode 100644 source/configs/base/cfg_ws_host.h create mode 100644 source/configs/cfg_ws_host.h diff --git a/nanostack/mac_api.h b/nanostack/mac_api.h index 8cc4da258e..897d04078f 100644 --- a/nanostack/mac_api.h +++ b/nanostack/mac_api.h @@ -129,10 +129,11 @@ typedef void mcps_data_request(const mac_api_t *api, const mcps_data_req_t *data * @param ie_ext Information element list to MCPS-DATA.request * @param asynch_channel_list Optional channel list to asynch data request. Give NULL when normal data request. * @param priority Data request priority level + * @param phy_mode_id Use mode switch if given phy_mode_id > 0 * * Asynch data request is mac standard extension. asynch_channel_list include channel mask which channel message is requested to send. */ -typedef void mcps_data_request_ext(const mac_api_t *api, const mcps_data_req_t *data, const mcps_data_req_ie_list_t *ie_ext, const struct channel_list_s *asynch_channel_list, mac_data_priority_t priority); +typedef void mcps_data_request_ext(const mac_api_t *api, const mcps_data_req_t *data, const mcps_data_req_ie_list_t *ie_ext, const struct channel_list_s *asynch_channel_list, mac_data_priority_t priority, uint8_t phy_mode_id); /** * @brief mcps_purge_request MCPS_PURGE request call @@ -192,6 +193,16 @@ typedef void mcps_ack_data_req_ext(const mac_api_t *api, mcps_ack_data_payload_t typedef void mcps_edfe_handler(const mac_api_t *api, mcps_edfe_response_t *response_message); +/** + * @brief mode_switch_resolver Callback to resolve configuration behind received PHY mode ID + * @param api The API which handled the response + * @param phy_mode_id PHY mode ID to be resolved + * @param rf_config Resolved configuration + * @return 0 in case of success, negative otherwise + */ +typedef int8_t mode_switch_resolver(const mac_api_t *api, uint8_t phy_mode_id, phy_rf_channel_configuration_s *rf_config); + + /** * @brief mcps_purge_confirm MCPS-PURGE confirm is called as a response to MCPS-PURGE request * @param api The API which handled the request @@ -272,6 +283,16 @@ typedef int8_t mac_api_enable_mcps_ext(mac_api_t *api, typedef int8_t mac_api_enable_mcps_edfe_ext(mac_api_t *api, mcps_edfe_handler *edfe_ind_cb); +/** + * @brief mac_api_mode_switch_resolver_ext Initialises mode switch resolver callback. Upper layer must configure function when mode switch is used. + * @param api mac_api_t pointer, which is created by application. + * @param mode_resolver_cb Upper layer function to resolve received PHY mode ID + * @param base_phy_mode Base PHY mode, device returns to this mode after mode switch transmission or reception + * @return -1 if error, 0 otherwise + */ +typedef int8_t mac_api_mode_switch_resolver_ext(mac_api_t *api, + mode_switch_resolver *mode_resolver_cb, uint8_t base_phy_mode); + /** * \brief Struct mac_api_s defines functions for two-way communications between external MAC and Upper layer. * Application creates mac_api_t object by calling external MAC's creator function. @@ -279,30 +300,32 @@ typedef int8_t mac_api_enable_mcps_edfe_ext(mac_api_t *api, * Then MAC is operated by Upper layer by calling MLME or MCPS primitive functions. */ struct mac_api_s { - mac_api_initialize *mac_initialize; /**< MAC initialize function to use */ - mac_api_enable_mcps_ext *mac_mcps_extension_enable; /**< MAC MCPS IE extension enable function, optional feature */ - mac_api_enable_mcps_edfe_ext *mac_mcps_edfe_enable; /**< MAC MCPS MCPS EDFE frame extension enable function, optional feature */ + mac_api_initialize *mac_initialize; /**< MAC initialize function to use */ + mac_api_enable_mcps_ext *mac_mcps_extension_enable; /**< MAC MCPS IE extension enable function, optional feature */ + mac_api_enable_mcps_edfe_ext *mac_mcps_edfe_enable; /**< MAC MCPS MCPS EDFE frame extension enable function, optional feature */ + mac_api_mode_switch_resolver_ext *mac_mode_switch_resolver_set; /**< MAC Mode switch resolver function set, optional feature */ //External MAC callbacks - mlme_request *mlme_req; /**< MAC MLME request function to use */ - mcps_data_request *mcps_data_req; /**< MAC MCPS data request function to use */ - mcps_data_request_ext *mcps_data_req_ext; /**< MAC MCPS data request with Information element extension function to use */ - mcps_purge_request *mcps_purge_req; /**< MAC MCPS purge request function to use */ + mlme_request *mlme_req; /**< MAC MLME request function to use */ + mcps_data_request *mcps_data_req; /**< MAC MCPS data request function to use */ + mcps_data_request_ext *mcps_data_req_ext; /**< MAC MCPS data request with Information element extension function to use */ + mcps_purge_request *mcps_purge_req; /**< MAC MCPS purge request function to use */ //Upper layer callbacksMLME_ASSOCIATE - mcps_data_confirm *data_conf_cb; /**< MAC MCPS data confirm callback function */ - mcps_data_confirm_ext *data_conf_ext_cb; /**< MAC MCPS data confirm with payload callback function */ - mcps_data_indication *data_ind_cb; /**< MAC MCPS data indication callback function */ - mcps_data_indication_ext *data_ind_ext_cb; /**< MAC MCPS data indication with IE extension's callback function */ - mcps_edfe_handler *edfe_ind_cb; /**< MAC MCPS EDFE detection extension's callback function */ - mcps_ack_data_req_ext *enhanced_ack_data_req_cb; /**< Enhanced ACK IE element and payload request from MAC user */ - mcps_purge_confirm *purge_conf_cb; /**< MAC MCPS purge confirm callback function */ - mlme_confirm *mlme_conf_cb; /**< MAC MLME confirm callback function */ - mlme_indication *mlme_ind_cb; /**< MAC MLME indication callback function */ - mac_ext_mac64_address_set *mac64_set; /**< MAC extension function to set mac64 address */ - mac_ext_mac64_address_get *mac64_get; /**< MAC extension function to get mac64 address */ - mac_storage_decription_sizes_get *mac_storage_sizes_get; /**< Getter function to query data storage sizes from MAC */ + mcps_data_confirm *data_conf_cb; /**< MAC MCPS data confirm callback function */ + mcps_data_confirm_ext *data_conf_ext_cb; /**< MAC MCPS data confirm with payload callback function */ + mcps_data_indication *data_ind_cb; /**< MAC MCPS data indication callback function */ + mcps_data_indication_ext *data_ind_ext_cb; /**< MAC MCPS data indication with IE extension's callback function */ + mcps_edfe_handler *edfe_ind_cb; /**< MAC MCPS EDFE detection extension's callback function */ + mode_switch_resolver *mode_resolver_cb; /**< MAC Mode switch resolver callback function */ + mcps_ack_data_req_ext *enhanced_ack_data_req_cb; /**< Enhanced ACK IE element and payload request from MAC user */ + mcps_purge_confirm *purge_conf_cb; /**< MAC MCPS purge confirm callback function */ + mlme_confirm *mlme_conf_cb; /**< MAC MLME confirm callback function */ + mlme_indication *mlme_ind_cb; /**< MAC MLME indication callback function */ + mac_ext_mac64_address_set *mac64_set; /**< MAC extension function to set mac64 address */ + mac_ext_mac64_address_get *mac64_get; /**< MAC extension function to get mac64 address */ + mac_storage_decription_sizes_get *mac_storage_sizes_get; /**< Getter function to query data storage sizes from MAC */ - int8_t parent_id; /**< Upper layer id */ - uint16_t phyMTU; /**< Maximum Transmission Unit(MTU) used by MAC*/ + int8_t parent_id; /**< Upper layer id */ + uint16_t phyMTU; /**< Maximum Transmission Unit(MTU) used by MAC*/ }; /** diff --git a/nanostack/net_ws_test.h b/nanostack/net_ws_test.h index 234c12e0b1..76ded833f1 100644 --- a/nanostack/net_ws_test.h +++ b/nanostack/net_ws_test.h @@ -39,6 +39,23 @@ extern "C" { #include "ns_types.h" +/** + * \brief Set Wi-SUN version number + * + * Sets the Wi-SUN protocol version. + * 1 = Wi-SUN FAN 1.0 + * 2 = Wi-SUN FAN 1.1 + * + * Set version to 0 to stop override and use stack default + * + * \param interface_id Network Interface + * \param version Wi-SUN version + * + * \return 0 OK + * \return <0 Failure + */ + +int ws_test_version_set(int8_t interface_id, uint8_t version); /** * \brief Set Pan size. * diff --git a/nanostack/net_ws_test_ext.h b/nanostack/net_ws_test_ext.h new file mode 100644 index 0000000000..137f0e8c46 --- /dev/null +++ b/nanostack/net_ws_test_ext.h @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2021, Pelion and affiliates. + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef NET_WS_TEST_EXT_H_ +#define NET_WS_TEST_EXT_H_ + +/** + * \file net_ws_test_ext.h + * \brief Wi-SUN Library External Test API. + * + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "ns_types.h" + +/* Test procedure triggers + * + * Example about using the triggers during bootstrap to trigger + * messages and state transitions. + * + * Border Router Node + * + * Join state 1 (select PAN) + * + * PROC_PA + * ------- PAN Advertisement------------> + * + * PROC_EAPOL + * Select EAPOL target + * Join state 2 (authenticate) + * <------ EAPOL authentication --------> + * Join State 3 (acquire PAN configuration) + * + * PROC_PC + * ------- PAN Configuration -----------> + * Join state 4 (configure routing) + * + * PROC_DIO + * ------- DIO -------------------------> + * Neighbor discovery (NS probing for ETX) + * Create RPL candidate parent set + * + * PROC_RPL + * Select RPL parent + * <------ DHCP ------------------------> + * + * PROC_DAO + * <------ DAO -------------------------- + * ------- DAO acknowledge -------------> + * + * Join state 5 (operational) + * + * + * On automatic mode the PROC_PAS, PROC_EAPOL, PROC_PCS, PROC_DIS and PROC_RPL + * will be triggered automatically by the node during the bootstrap. + * + */ + +/** + * @brief Test procedure triggers. + */ +typedef enum { + PROC_DIS, /* trigger DODAG information object solicit (node) */ + PROC_DIO, /* trigger DODAG information object (BR, node) */ + PROC_DAO, /* trigger Destination advertisement object (node) */ + + PROC_PAS, /* trigger PAN Advertisement Solicit (node) */ + PROC_PA, /* trigger PAN Advertisement (BR, node) */ + PROC_PCS, /* trigger PAN Configuration Solicit (node) */ + PROC_PC, /* trigger PAN Configuration (BR, node) */ + + PROC_EAPOL, /* trigger EAPOL target selection (initiates authentication, node) */ + PROC_RPL, /* trigger RPL parent selection (node) */ + + PROC_AUTO_ON, /* trigger bootstrap test procedures automatically */ + PROC_AUTO_OFF, /* disable automatic bootstrap test procedure triggering */ + + MSG_NONE +} ws_test_proc_t; + +/** + * Trigger a test procedure + * + * Can be used to trigger a test procedure, e.g. to send a message (DIS, + * DIO, DAO, PAS, PS, PCS and PC) or to trigger bootstrap state change + * on node e.g. EAPOL target selection. + * + * \param interface_id Network Interface ID >= 0 or -1 for Wi-SUN mesh interface + * Default value is -1 + * \param procedure Triggered procedure + * \param parameters Parameters for future extensions, shall be set to NULL + * + * \return 0 Success + * \return <0 Failure + */ +int ws_test_procedure_trigger(int8_t interface_id, ws_test_proc_t procedure, void *parameters); + +#ifdef __cplusplus +} +#endif + +#endif /* NET_WS_TEST_EXT_H_ */ diff --git a/nanostack/ns_sha256.h b/nanostack/ns_sha256.h index fccded2cfa..f550430e66 100644 --- a/nanostack/ns_sha256.h +++ b/nanostack/ns_sha256.h @@ -61,23 +61,39 @@ static inline void ns_sha256_clone(ns_sha256_context *dst, static inline void ns_sha256_starts(ns_sha256_context *ctx) { +#if (MBEDTLS_VERSION_MAJOR >= 3) + (void)mbedtls_sha256_starts(ctx, 0); +#else (void)mbedtls_sha256_starts_ret(ctx, 0); +#endif } static inline void ns_sha256_update(ns_sha256_context *ctx, const void *input, size_t ilen) { +#if (MBEDTLS_VERSION_MAJOR >= 3) + (void)mbedtls_sha256_update(ctx, input, ilen); +#else (void)mbedtls_sha256_update_ret(ctx, input, ilen); +#endif } static inline void ns_sha256_finish(ns_sha256_context *ctx, void *output) { +#if (MBEDTLS_VERSION_MAJOR >= 3) + (void)mbedtls_sha256_finish(ctx, output); +#else (void)mbedtls_sha256_finish_ret(ctx, output); +#endif } static inline void ns_sha256(const void *input, size_t ilen, void *output) { +#if (MBEDTLS_VERSION_MAJOR >= 3) + (void)mbedtls_sha256(input, ilen, output, 0); +#else (void)mbedtls_sha256_ret(input, ilen, output, 0); +#endif } /* Extensions to standard mbed TLS - output the first bits of a hash only */ @@ -85,10 +101,18 @@ static inline void ns_sha256(const void *input, size_t ilen, void *output) static inline void ns_sha256_finish_nbits(ns_sha256_context *ctx, void *output, unsigned obits) { if (obits == 256) { +#if (MBEDTLS_VERSION_MAJOR >= 3) + (void)mbedtls_sha256_finish(ctx, output); +#else (void)mbedtls_sha256_finish_ret(ctx, output); +#endif } else { uint8_t sha256[32]; +#if (MBEDTLS_VERSION_MAJOR >= 3) + (void)mbedtls_sha256_finish(ctx, sha256); +#else (void)mbedtls_sha256_finish_ret(ctx, sha256); +#endif memcpy(output, sha256, obits / 8); } } @@ -96,10 +120,18 @@ static inline void ns_sha256_finish_nbits(ns_sha256_context *ctx, void *output, static inline void ns_sha256_nbits(const void *input, size_t ilen, void *output, unsigned obits) { if (obits == 256) { +#if (MBEDTLS_VERSION_MAJOR >= 3) + (void)mbedtls_sha256(input, ilen, output, 0); +#else (void)mbedtls_sha256_ret(input, ilen, output, 0); +#endif } else { uint8_t sha256[32]; +#if (MBEDTLS_VERSION_MAJOR >= 3) + (void)mbedtls_sha256(input, ilen, sha256, 0); +#else (void)mbedtls_sha256_ret(input, ilen, sha256, 0); +#endif memcpy(output, sha256, obits / 8); } } diff --git a/nanostack/ns_time_api.h b/nanostack/ns_time_api.h index 4b1907cfc9..14be92dd94 100644 --- a/nanostack/ns_time_api.h +++ b/nanostack/ns_time_api.h @@ -28,6 +28,24 @@ #include "ns_types.h" +/** + * Time zone information structure. + * + * Daylight saving time and time zone information learned by network stack + * + */ +typedef struct timezone_info { + /** Timestamp of the Daylight saving time change*/ + uint64_t timestamp; + /** Time zone information in minutes*/ + int16_t timezone; + /** Change that is applied when timestamp is reached*/ + int16_t deviation; + /** Time configuration status bit field + * "bit xxxxxxxxxxxxxxxS" 0 = false 1 = true Daylight saving time status*/ + uint16_t status; +} timezone_info_t; + /** * System time read callback. * @@ -48,6 +66,22 @@ typedef uint64_t ns_time_api_system_time_callback(void); */ typedef void ns_time_api_system_time_write_callback(uint64_t write_time); +/** + * New time zone and daylight saving time information learned from stack. + * + * Called when network stack learns the time zone and daylights saving time information. + * + * In Wi-SUN Border router can distribute this information to synchronize all nodes in network. + * This information is updated roughly once a day using DHCPv6 protocol + * + * If network stack does not have the information this is not called and can be called when information becomes available. + * This can be called multiple times with same information. + * + * \param info_ptr time zone and daylight saving time configuration. + * + */ +typedef void ns_time_api_time_configuration_notify_callback(timezone_info_t *info_ptr); + /** * System time read callback set. * @@ -68,4 +102,15 @@ void ns_time_api_system_time_callback_set(ns_time_api_system_time_callback callb */ void ns_time_api_system_time_write_callback_set(ns_time_api_system_time_write_callback callback_wr); +/** + * Set system time configuration notify callback. + * + * Sets system time configuration notify callback that is called if network stack + * learns time information from other devices in the network. + * + * \param callback_wr system time write callback. + * + */ +void ns_time_api_time_configuration_notify_callback_set(ns_time_api_time_configuration_notify_callback callback_wr); + #endif /* NS_TIME_API_H_ */ diff --git a/nanostack/platform/arm_hal_phy.h b/nanostack/platform/arm_hal_phy.h index b4a1913742..05b34be236 100644 --- a/nanostack/platform/arm_hal_phy.h +++ b/nanostack/platform/arm_hal_phy.h @@ -143,6 +143,7 @@ typedef struct phy_signal_info_s { typedef struct phy_csma_params { uint32_t backoff_time; /**< CSMA Backoff us time before start CCA & TX. 0 should disable current backoff*/ bool cca_enabled; /**< True will affect CCA check false start TX direct after backoff */ + bool mode_switch_phr; /**< True - Frame is a mode switch PHR. In this case PHY driver should skip FCS and send two byte PHR as it is given by TX callback */ } phy_csma_params_t; /** PHY modulation scheme */ diff --git a/nanostack/ws_bbr_api.h b/nanostack/ws_bbr_api.h index a1c15aa061..00e8623c65 100644 --- a/nanostack/ws_bbr_api.h +++ b/nanostack/ws_bbr_api.h @@ -74,6 +74,20 @@ typedef struct bbr_radius_timing { uint8_t radius_retry_count; } bbr_radius_timing_t; +/** + * \brief Daylights saving time parameters. + */ +typedef struct bbr_timezone_configuration { + /** Timestamp of the Daylight saving time change*/ + uint64_t timestamp; + /** Time zone information in minutes*/ + int16_t timezone; + /** Change that is applied when timestamp is reached*/ + int16_t deviation; + /** Time configuration status bit field + * "bit xxxxxxxxxxxxxxxS" 0 = false 1 = true Daylight saving time status*/ + uint16_t status; +} bbr_timezone_configuration_t; /** * Start backbone border router service. * @@ -521,4 +535,22 @@ int ws_bbr_radius_timing_validate(int8_t interface_id, bbr_radius_timing_t *timi */ int ws_bbr_dns_query_result_set(int8_t interface_id, const uint8_t address[16], char *domain_name_ptr); +/** + * \brief A function to set time zone and daylights saving time configuration + * + * Border router distributes this information in DHCP Reply messages to + * all the devices joining to the Wi-SUN mesh network. + * + * Border router keeps this information until reboot and continues to distribute the information. + * If the information is changed the updates are sent to devices in network when they + * renew their address. This can take time from 1 to 24 hours + * + * \param interface_id Network interface ID. + * \param daylight_saving_time_ptr daylights saving time configuration. NULL if you want to remove the configuration. + * + * \return < 0 failure + * \return >= 0 success + */ +int ws_bbr_timezone_configuration_set(int8_t interface_id, bbr_timezone_configuration_t *daylight_saving_time_ptr); + #endif /* WS_BBR_API_H_ */ diff --git a/nanostack/ws_management_api.h b/nanostack/ws_management_api.h index ddab5d40e5..b436bf24ab 100644 --- a/nanostack/ws_management_api.h +++ b/nanostack/ws_management_api.h @@ -78,6 +78,17 @@ extern "C" { #define CHANNEL_SPACING_800 0x05 /**< 800 khz */ #define CHANNEL_SPACING_1200 0x06 /**< 1200 khz */ +/* + * Wi-SUN FAN 1.1 Phy capability types. + * + */ +#define WS_PHY_TYPE_ID_FSK 0 /**< FSK phy type */ +#define WS_PHY_TYPE_ID_FSK_FEC 1 /**< FSK with FEC phy type */ +#define WS_PHY_TYPE_ID_OFDM1 2 /**< OFDM1 phy type */ +#define WS_PHY_TYPE_ID_OFDM2 3 /**< OFDM2 phy type */ +#define WS_PHY_TYPE_ID_OFDM3 4 /**< OFDM3 phy type */ +#define WS_PHY_TYPE_ID_OFDM4 5 /**< OFDM4 phy type */ + /* * Network Size definitions are device amount in hundreds of devices. * These definitions are meant to give some estimates of sizes. Any value can be given as parameter @@ -225,6 +236,28 @@ typedef struct ws_neighbour_info { ws_management_neighbor_type_e type; } ws_neighbour_info_t; + +/** + * @brief ws_management_pcap_t Wi-SUN FAN 1.1 Phy Capability type and operating mode + */ +typedef struct ws_management_pcap { + /** Phy type */ + uint8_t phy_type; + /** Phy operating mode */ + uint16_t operating_mode; +} ws_management_pcap_t; + +/** + * @brief ws_management_pcap_info_t Wi-SUN FAN 1.1 Phy Capability list for MDR support + */ +typedef struct ws_management_pcap_info { + /** Length of the capability */ + uint8_t length_of_list: 3; + /** Capability information */ + ws_management_pcap_t pcap[7]; +} ws_management_pcap_info_t; + + /** * Initialize Wi-SUN stack. * @@ -875,6 +908,20 @@ int ws_device_min_sens_set( int8_t interface_id, uint8_t device_min_sens); +/** + * Set Phy Capability support for MDR, FAN 1.1 feature + * + * + * \param interface_id Network interface ID. + * \param pcap_list pointer to supported list + * + * \return 0 Success. + * \return <0 Failure. + */ +int ws_management_phy_capability_set( + int8_t interface_id, + ws_management_pcap_info_t *pcap_list); + #ifdef __cplusplus } #endif diff --git a/source/6LoWPAN/Bootstraps/Generic/protocol_6lowpan.c b/source/6LoWPAN/Bootstraps/Generic/protocol_6lowpan.c index 3069e00a56..4f730e4763 100644 --- a/source/6LoWPAN/Bootstraps/Generic/protocol_6lowpan.c +++ b/source/6LoWPAN/Bootstraps/Generic/protocol_6lowpan.c @@ -118,7 +118,7 @@ static uint8_t protocol_buffer_valid(buffer_t *b, protocol_interface_info_entry_ void protocol_init(void) { - tr_debug("P.Init\n"); + tr_debug("P.Init"); #ifdef PANA sec_libray_init(); #endif @@ -134,7 +134,7 @@ void protocol_6lowpan_stack(buffer_t *b) { protocol_interface_info_entry_t *cur = b->interface; if (protocol_buffer_valid(b, cur) == 0) { - tr_debug("Drop Packets\n"); + tr_debug("Drop Packets"); buffer_free(b); return; } @@ -230,7 +230,7 @@ void protocol_6lowpan_stack(buffer_t *b) b = tcp_up(b); break; default: - tr_debug("LLL\n"); + tr_debug("LLL"); b = buffer_free(b); break; } @@ -871,7 +871,7 @@ bool protocol_6lowpan_stagger_estimate_get(int8_t interface_id, uint32_t data_am } // For small networks sets 10 seconds stagger - if (network_size <= 100 && ws_info(cur_interface)) { + if (ws_info(cur_interface) && (network_size <= 100 || ws_test_proc_auto_trg(cur_interface))) { stagger_value = 10; } else { stagger_value = 1 + ((data_amount * 1024 * 8 * network_size) / datarate); diff --git a/source/6LoWPAN/Bootstraps/Generic/protocol_6lowpan_bootstrap.c b/source/6LoWPAN/Bootstraps/Generic/protocol_6lowpan_bootstrap.c index fa7ecae8b1..80b53382f1 100644 --- a/source/6LoWPAN/Bootstraps/Generic/protocol_6lowpan_bootstrap.c +++ b/source/6LoWPAN/Bootstraps/Generic/protocol_6lowpan_bootstrap.c @@ -1548,7 +1548,7 @@ int8_t arm_network_processor_up(protocol_interface_info_entry_t *cur) { int8_t ret_val = -1; if ((cur->configure_flags & INTERFACE_SETUP_NETWORK_DRIVER_MASK) != INTERFACE_SETUP_NETWORK_DRIVER_READY) { - tr_debug("Interface not yet fully configured\n"); + tr_debug("Interface not yet fully configured"); ret_val = -5; } else { protocol_6lowpan_register_handlers(cur); @@ -2123,7 +2123,7 @@ static void nwk_rpl_dio_scan(protocol_interface_info_entry_t *cur) if (nwk_bootstrap_icmp_rpl_dis_msg_tx(cur)) { cur->bootsrap_state_machine_cnt = 45 << cur->nwk_rpl_scan_counter; cur->nwk_rpl_scan_counter++; - tr_debug("MC_DIS\n"); + tr_debug("MC_DIS"); cur->nwk_bootstrap_state = ER_RPL_SCAN; } else { cur->bootsrap_state_machine_cnt = 3; diff --git a/source/6LoWPAN/MAC/mac_helper.c b/source/6LoWPAN/MAC/mac_helper.c index 515c16ce18..dbea21add5 100644 --- a/source/6LoWPAN/MAC/mac_helper.c +++ b/source/6LoWPAN/MAC/mac_helper.c @@ -476,13 +476,14 @@ void mac_helper_security_key_clean(protocol_interface_info_entry_t *interface) void mac_helper_coordinator_address_set(protocol_interface_info_entry_t *interface, addrtype_t adr_type, uint8_t *adr_ptr) { + uint16_t short_addr; mlme_set_t set_req; set_req.attr_index = 0; if (adr_type == ADDR_802_15_4_SHORT) { memcpy(interface->mac_parameters->mac_cordinator_info.mac_mlme_coord_address, adr_ptr, 2); interface->mac_parameters->mac_cordinator_info.cord_adr_mode = MAC_ADDR_MODE_16_BIT; - uint16_t short_addr = common_read_16_bit(interface->mac_parameters->mac_cordinator_info.mac_mlme_coord_address); + short_addr = common_read_16_bit(interface->mac_parameters->mac_cordinator_info.mac_mlme_coord_address); set_req.attr = macCoordShortAddress; set_req.value_pointer = &short_addr; set_req.value_size = 2; diff --git a/source/6LoWPAN/MAC/mac_ie_lib.c b/source/6LoWPAN/MAC/mac_ie_lib.c index e6329bfbca..5c054b99f5 100644 --- a/source/6LoWPAN/MAC/mac_ie_lib.c +++ b/source/6LoWPAN/MAC/mac_ie_lib.c @@ -144,6 +144,33 @@ uint16_t mac_ie_nested_discover(uint8_t *payload_ptr, uint16_t length, mac_neste return 0; } +uint16_t mac_ie_nested_tagged_discover(uint8_t *payload_ptr, uint16_t length, mac_nested_payload_IE_t *nested_ie, uint8_t sub_tag_id) +{ + mac_nested_payload_IE_t ie_element; + uint8_t *sub_tag_ptr; + while (length >= 2) { + mac_ie_nested_id_parse(&ie_element, payload_ptr); + + if (length < ie_element.length + 2) { + return 0; + } + + sub_tag_ptr = ie_element.content_ptr; + if (ie_element.length > 1 && nested_ie->id == ie_element.id && *sub_tag_ptr == sub_tag_id) { + sub_tag_ptr++; + ie_element.length--; + nested_ie->content_ptr = sub_tag_ptr; + nested_ie->length = ie_element.length; + return ie_element.length; + } + + length -= ie_element.length + 2; + + payload_ptr += ie_element.length + 2; + } + return 0; +} + uint8_t mac_ie_header_discover(uint8_t *header_ptr, uint16_t length, mac_header_IE_t *header_ie) { mac_header_IE_t ie_element; diff --git a/source/6LoWPAN/MAC/mac_ie_lib.h b/source/6LoWPAN/MAC/mac_ie_lib.h index 6cd0f5f82e..0b6a36630f 100644 --- a/source/6LoWPAN/MAC/mac_ie_lib.h +++ b/source/6LoWPAN/MAC/mac_ie_lib.h @@ -49,6 +49,9 @@ uint16_t mac_ie_payload_discover(uint8_t *payload_ptr, uint16_t length, struct m /** Nested IE element discover inside parsed payload element */ uint16_t mac_ie_nested_discover(uint8_t *payload_ptr, uint16_t length, mac_nested_payload_IE_t *nested_ie); +/** Nested IE element discover with Sub Tag ID inside parsed payload element */ +uint16_t mac_ie_nested_tagged_discover(uint8_t *payload_ptr, uint16_t length, mac_nested_payload_IE_t *nested_ie, uint8_t sub_tag_id); + /** Header IE elemnt discover */ uint8_t mac_ie_header_discover(uint8_t *header_ptr, uint16_t length, struct mac_header_IE_s *header_ie); diff --git a/source/6LoWPAN/Thread/thread_bootstrap.c b/source/6LoWPAN/Thread/thread_bootstrap.c index af16058f13..38665c343d 100644 --- a/source/6LoWPAN/Thread/thread_bootstrap.c +++ b/source/6LoWPAN/Thread/thread_bootstrap.c @@ -2308,7 +2308,7 @@ void thread_bootstrap_state_machine(protocol_interface_info_entry_t *cur) break; case ER_BOOTSRAP_DONE: - tr_debug("Thread SM:Bootstrap Done"); + tr_info("Thread SM:Bootstrap Done"); cur->nwk_nd_re_scan_count = 0; break; case ER_BOOTSTRAP_SCAN_FAIL: diff --git a/source/6LoWPAN/Thread/thread_commissioning_api.c b/source/6LoWPAN/Thread/thread_commissioning_api.c index f9939a1cc2..fb69e2f087 100644 --- a/source/6LoWPAN/Thread/thread_commissioning_api.c +++ b/source/6LoWPAN/Thread/thread_commissioning_api.c @@ -262,7 +262,7 @@ static int thread_commissioning_active_get_cb(int8_t service_id, uint8_t source_ if ((len = thread_meshcop_tlv_find(response_ptr->payload_ptr, response_ptr->payload_len, MESHCOP_TLV_NETWORK_MESH_LOCAL_ULA, &ptr)) > 0) { state = COMMISSIONING_STATE_ACCEPT; - tr_debug(" TLV ml prefix=%s\r\n", trace_array(ptr, len)); + tr_debug(" TLV ml prefix=%s", trace_array(ptr, len)); memcpy(this->leader_address, ptr, 8); memcpy(this->leader_address + 8, ADDR_SHORT_ADR_SUFFIC, 6); common_write_16_bit(0xfc00, this->leader_address + 14); diff --git a/source/6LoWPAN/Thread/thread_common.c b/source/6LoWPAN/Thread/thread_common.c index a5146cc29b..67fc029be8 100644 --- a/source/6LoWPAN/Thread/thread_common.c +++ b/source/6LoWPAN/Thread/thread_common.c @@ -2006,7 +2006,7 @@ void thread_reset_neighbour_info(protocol_interface_info_entry_t *cur, mac_neigh if (!thread_i_am_router(cur) && thread_endnode_parent && thread_endnode_parent->shortAddress == neighbour->mac16) { if (cur->nwk_bootstrap_state != ER_CHILD_ID_REQ) { - tr_warn("End device lost parent, reset!\n"); + tr_warn("End device lost parent, reset!"); thread_bootstrap_connection_error(cur->id, CON_PARENT_CONNECT_DOWN, NULL); } } @@ -2238,18 +2238,18 @@ int thread_common_primary_bbr_get(struct protocol_interface_info_entry *cur, uin (service_tlv_ptr[0] & 0x80) && // THREAD_ENTERPRISE_NUMBER service_tlv_ptr[1] == 1 && // length 1 service_tlv_ptr[2] == THREAD_SERVICE_DATA_BBR) { - //tr_info("BBR service TLV: %s\r\n", trace_array(service_tlv_ptr, service_tlv_len)); + //tr_info("BBR service TLV: %s", trace_array(service_tlv_ptr, service_tlv_len)); // try to parse SUB-TLVs // network_data_server_tlv_parse(service_tlv_ptr, tlv_length); uint16_t server_tlv_len = 0; uint8_t *server_tlv_ptr = thread_common_server_tlv_list_get(service_tlv_ptr, service_tlv_len, &server_tlv_len); uint16_t found_tlv_len; uint8_t *found_tlv = NULL; - //tr_info("BBR server TLV: %s\r\n", trace_array(server_tlv_ptr, server_tlv_len)); + //tr_info("BBR server TLV: %s", trace_array(server_tlv_ptr, server_tlv_len)); do { found_tlv_len = thread_meshcop_tlv_find_next(server_tlv_ptr, server_tlv_len, THREAD_NWK_DATA_TYPE_SERVER_DATA | THREAD_NWK_STABLE_DATA, &found_tlv); if (found_tlv && found_tlv_len > 8) { - //tr_info("BBR server TLV: %s\r\n", trace_array(found_tlv, found_tlv_len)); + //tr_info("BBR server TLV: %s", trace_array(found_tlv, found_tlv_len)); if (addr_ptr) { thread_addr_write_mesh_local_16(addr_ptr, common_read_16_bit(found_tlv), cur->thread_info); } diff --git a/source/6LoWPAN/adaptation_interface.c b/source/6LoWPAN/adaptation_interface.c index 4423636e03..6e0b296b1b 100644 --- a/source/6LoWPAN/adaptation_interface.c +++ b/source/6LoWPAN/adaptation_interface.c @@ -1137,7 +1137,7 @@ static void lowpan_data_request_to_mac(protocol_interface_info_entry_t *cur, buf } else { mcps_data_req_ie_list_t ie_list; memset(&ie_list, 0, sizeof(mcps_data_req_ie_list_t)); - cur->mac_api->mcps_data_req_ext(cur->mac_api, &dataReq, &ie_list, NULL, data_priority); + cur->mac_api->mcps_data_req_ext(cur->mac_api, &dataReq, &ie_list, NULL, data_priority, 0); } } diff --git a/source/6LoWPAN/ws/ws_bbr_api.c b/source/6LoWPAN/ws/ws_bbr_api.c index 051fca51ad..0e9fe10b8b 100644 --- a/source/6LoWPAN/ws/ws_bbr_api.c +++ b/source/6LoWPAN/ws/ws_bbr_api.c @@ -70,7 +70,7 @@ static uint8_t current_instance_id = RPL_INSTANCE_ID; //TAG ID This must be update if NVM_BBR_INFO_LEN or data structure #define NVM_BBR_INFO_TAG 1 // BSI 2 bytes -#define NVM_BBR_INFO_LEN 2 +#define NVM_BBR_INFO_LEN 4 typedef struct bbr_info_nvm_tlv { uint16_t tag; /**< Unique tag */ @@ -97,6 +97,9 @@ static uint8_t current_global_prefix[16] = {0}; // DHCP requires 16 bytes prefix static uint32_t bbr_delay_timer = BBR_CHECK_INTERVAL; // initial delay. static uint32_t global_prefix_unavailable_timer = 0; // initial delay. +static bbr_timezone_configuration_t *bbr_time_config = NULL; + + static rpl_dodag_conf_t rpl_conf = { // Lifetime values .default_lifetime = 120, @@ -132,41 +135,57 @@ static bbr_info_nvm_tlv_t bbr_info_nvm_tlv = { }; static uint16_t ws_bbr_fhss_bsi = 0; +static uint16_t ws_bbr_pan_id = 0xffff; -static int8_t ws_bbr_nvm_info_read(bbr_info_nvm_tlv_t *tlv_entry) +static int8_t ws_bbr_info_tlv_read(bbr_info_nvm_tlv_t *tlv_entry, uint16_t *bsi, uint16_t *pan_id) { - tlv_entry->tag = NVM_BBR_INFO_TAG; - tlv_entry->len = NVM_BBR_INFO_LEN; - - int8_t ret_val = ws_pae_nvm_store_tlv_file_read(BBR_INFO_FILE, (nvm_tlv_t *) &bbr_info_nvm_tlv); - - if (ret_val < 0 || tlv_entry->tag != NVM_BBR_INFO_TAG || tlv_entry->len != NVM_BBR_INFO_LEN) { - ws_pae_nvm_store_tlv_file_remove(BBR_INFO_FILE); - tlv_entry->len = 0; + if (tlv_entry->tag != NVM_BBR_INFO_TAG || tlv_entry->len != NVM_BBR_INFO_LEN) { return -1; } + + uint8_t *tlv = (uint8_t *) &tlv_entry->data[0]; + + *bsi = common_read_16_bit(tlv); + tlv += 2; + *pan_id = common_read_16_bit(tlv); + return 0; } -static void ws_bbr_nvm_info_write(bbr_info_nvm_tlv_t *tlv_entry) +static void ws_bbr_info_tlv_write(bbr_info_nvm_tlv_t *tlv_entry, uint16_t bsi, uint16_t pan_id) { tlv_entry->tag = NVM_BBR_INFO_TAG; tlv_entry->len = NVM_BBR_INFO_LEN; - ws_pae_nvm_store_tlv_file_write(BBR_INFO_FILE, (nvm_tlv_t *) tlv_entry); - tr_debug("BBR info NVM update"); + + uint8_t *tlv = (uint8_t *) &tlv_entry->data[0]; + + tlv = common_write_16_bit(bsi, tlv); + common_write_16_bit(pan_id, tlv); } -static uint16_t ws_bbr_bsi_read(bbr_info_nvm_tlv_t *tlv_entry) +static int8_t ws_bbr_nvm_info_read(uint16_t *bsi, uint16_t *pan_id) { - if (tlv_entry->tag != NVM_BBR_INFO_TAG || tlv_entry->len != NVM_BBR_INFO_LEN) { - return 0; + ws_pae_nvm_store_generic_tlv_create((nvm_tlv_t *) &bbr_info_nvm_tlv, NVM_BBR_INFO_TAG, NVM_BBR_INFO_LEN); + + if (ws_pae_nvm_store_tlv_file_read(BBR_INFO_FILE, (nvm_tlv_t *) &bbr_info_nvm_tlv) < 0) { + ws_pae_nvm_store_tlv_file_remove(BBR_INFO_FILE); + return -1; } - return common_read_16_bit(tlv_entry->data + BBR_NVM_BSI_OFFSET); + + if (ws_bbr_info_tlv_read(&bbr_info_nvm_tlv, bsi, pan_id) < 0) { + ws_pae_nvm_store_tlv_file_remove(BBR_INFO_FILE); + return -1; + } + + return 0; } -static void ws_bbr_bsi_write(bbr_info_nvm_tlv_t *tlv_entry, uint16_t bsi) +static void ws_bbr_nvm_info_write(uint16_t bsi, uint16_t pan_id) { - common_write_16_bit(bsi, tlv_entry->data + BBR_NVM_BSI_OFFSET); + ws_bbr_info_tlv_write(&bbr_info_nvm_tlv, bsi, pan_id); + + ws_pae_nvm_store_tlv_file_write(BBR_INFO_FILE, (nvm_tlv_t *) &bbr_info_nvm_tlv); + tr_debug("BBR info NVM update"); } static void ws_bbr_rpl_version_timer_start(protocol_interface_info_entry_t *cur, uint8_t version) @@ -488,24 +507,32 @@ static uint8_t *ws_bbr_dhcp_server_dynamic_vendor_data_write(int8_t interfaceId, // If local time is not available vendor data is not written and data_len is not modified (void)interfaceId; - uint64_t time_read; + uint64_t time_read = 0; - if (0 != ns_time_system_time_read(&time_read)) { - return ptr; - } + ns_time_system_time_read(&time_read); if (data_len) { - *data_len += net_vendor_option_current_time_length(); + if (time_read) { + *data_len += net_vendor_option_current_time_length(); + } + if (bbr_time_config) { + *data_len += net_vendor_option_time_configuration_length(); + } } if (!ptr) { return ptr; } - time_read += 2208988800; // Time starts now from the 0 era instead of First day of Unix (1 Jan 1970) + if (time_read) { + time_read += 2208988800; // Time starts now from the 0 era instead of First day of Unix (1 Jan 1970) - uint32_t era = time_read / (uint64_t)(4294967296); - uint32_t timestamp = time_read - (era * (uint64_t)(4294967296)); - ptr = net_vendor_option_current_time_write(ptr, era, timestamp, 0); + uint32_t era = time_read / (uint64_t)(4294967296); + uint32_t timestamp = time_read - (era * (uint64_t)(4294967296)); + ptr = net_vendor_option_current_time_write(ptr, era, timestamp, 0); + } + if (bbr_time_config) { + ptr = net_vendor_option_time_configuration_write(ptr, bbr_time_config->timestamp, bbr_time_config->timezone, bbr_time_config->deviation, bbr_time_config->status); + } return ptr; } @@ -953,24 +980,21 @@ static void ws_bbr_forwarding_cb(protocol_interface_info_entry_t *interface, buf } } - - void ws_bbr_init(protocol_interface_info_entry_t *interface) { (void) interface; //Read From NVM - if (ws_bbr_nvm_info_read(&bbr_info_nvm_tlv) < 0) { + if (ws_bbr_nvm_info_read(&ws_bbr_fhss_bsi, &ws_bbr_pan_id) < 0) { //NVM value not available Randomize Value Here by first time ws_bbr_fhss_bsi = randLIB_get_16bit(); tr_debug("Randomized init value BSI %u", ws_bbr_fhss_bsi); } else { - ws_bbr_fhss_bsi = ws_bbr_bsi_read(&bbr_info_nvm_tlv); tr_debug("Read BSI %u from NVM", ws_bbr_fhss_bsi); + tr_debug("Read PAN ID %u from NVM", ws_bbr_pan_id); } interface->if_common_forwarding_out_cb = &ws_bbr_forwarding_cb; } - uint16_t ws_bbr_bsi_generate(protocol_interface_info_entry_t *interface) { (void) interface; @@ -979,11 +1003,16 @@ uint16_t ws_bbr_bsi_generate(protocol_interface_info_entry_t *interface) //Update value for next round ws_bbr_fhss_bsi++; //Store To NVN - ws_bbr_bsi_write(&bbr_info_nvm_tlv, ws_bbr_fhss_bsi); - ws_bbr_nvm_info_write(&bbr_info_nvm_tlv); + ws_bbr_nvm_info_write(ws_bbr_fhss_bsi, ws_bbr_pan_id); return bsi; } +uint16_t ws_bbr_pan_id_get(protocol_interface_info_entry_t *interface) +{ + (void) interface; + return ws_bbr_pan_id; +} + #endif //HAVE_WS_BORDER_ROUTER /* Public APIs @@ -1188,7 +1217,7 @@ int ws_bbr_rpl_parameters_set(int8_t interface_id, uint8_t dio_interval_min, uin protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(interface_id); ws_bbr_cfg_t cfg; - if (ws_cfg_bbr_get(&cfg, NULL) < 0) { + if (ws_cfg_bbr_get(&cfg) < 0) { return -1; } @@ -1202,7 +1231,7 @@ int ws_bbr_rpl_parameters_set(int8_t interface_id, uint8_t dio_interval_min, uin cfg.dio_redundancy_constant = dio_redundancy_constant; } - if (ws_cfg_bbr_set(cur, NULL, &cfg, 0) < 0) { + if (ws_cfg_bbr_set(cur, &cfg, 0) < 0) { return -2; } @@ -1224,7 +1253,7 @@ int ws_bbr_rpl_parameters_get(int8_t interface_id, uint8_t *dio_interval_min, ui } ws_bbr_cfg_t cfg; - if (ws_cfg_bbr_get(&cfg, NULL) < 0) { + if (ws_cfg_bbr_get(&cfg) < 0) { return -2; } @@ -1246,7 +1275,7 @@ int ws_bbr_rpl_parameters_validate(int8_t interface_id, uint8_t dio_interval_min (void) interface_id; #ifdef HAVE_WS_BORDER_ROUTER ws_bbr_cfg_t cfg; - if (ws_cfg_bbr_get(&cfg, NULL) < 0) { + if (ws_cfg_bbr_get(&cfg) < 0) { return -2; } @@ -1260,7 +1289,7 @@ int ws_bbr_rpl_parameters_validate(int8_t interface_id, uint8_t dio_interval_min cfg.dio_redundancy_constant = dio_redundancy_constant; } - if (ws_cfg_bbr_validate(NULL, &cfg) < 0) { + if (ws_cfg_bbr_validate(&cfg) < 0) { return -3; } @@ -1289,8 +1318,7 @@ int ws_bbr_bsi_set(int8_t interface_id, uint16_t new_bsi) ws_bootstrap_restart_delayed(cur->id); } - ws_bbr_bsi_write(&bbr_info_nvm_tlv, new_bsi); - ws_bbr_nvm_info_write(&bbr_info_nvm_tlv); + ws_bbr_nvm_info_write(ws_bbr_fhss_bsi, ws_bbr_pan_id); ws_bbr_fhss_bsi = new_bsi; return 0; #else @@ -1299,24 +1327,16 @@ int ws_bbr_bsi_set(int8_t interface_id, uint16_t new_bsi) #endif } - int ws_bbr_pan_configuration_set(int8_t interface_id, uint16_t pan_id) { (void) interface_id; #ifdef HAVE_WS_BORDER_ROUTER - protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(interface_id); - - ws_gen_cfg_t cfg; - if (ws_cfg_gen_get(&cfg, NULL) < 0) { - return -1; + if (ws_bbr_pan_id != pan_id) { + ws_bbr_pan_id = pan_id; + // Store to NVM and restart bootstrap + ws_bbr_nvm_info_write(ws_bbr_fhss_bsi, ws_bbr_pan_id); + ws_bootstrap_restart_delayed(interface_id); } - - cfg.network_pan_id = pan_id; - - if (ws_cfg_gen_set(cur, NULL, &cfg, 0) < 0) { - return -2; - } - return 0; #else (void) pan_id; @@ -1332,12 +1352,7 @@ int ws_bbr_pan_configuration_get(int8_t interface_id, uint16_t *pan_id) return -1; } - ws_gen_cfg_t cfg; - if (ws_cfg_gen_get(&cfg, NULL) < 0) { - return -2; - } - - *pan_id = cfg.network_pan_id; + *pan_id = ws_bbr_pan_id; return 0; #else @@ -1349,21 +1364,10 @@ int ws_bbr_pan_configuration_get(int8_t interface_id, uint16_t *pan_id) int ws_bbr_pan_configuration_validate(int8_t interface_id, uint16_t pan_id) { (void) interface_id; + (void) pan_id; #ifdef HAVE_WS_BORDER_ROUTER - ws_gen_cfg_t cfg; - if (ws_cfg_gen_get(&cfg, NULL) < 0) { - return -1; - } - - cfg.network_pan_id = pan_id; - - if (ws_cfg_gen_validate(NULL, &cfg) < 0) { - return -2; - } - return 0; #else - (void) pan_id; return -1; #endif } @@ -1553,3 +1557,32 @@ update_information: return -1; #endif } + +int ws_bbr_timezone_configuration_set(int8_t interface_id, bbr_timezone_configuration_t *daylight_saving_time_ptr) +{ +#ifdef HAVE_WS_BORDER_ROUTER + (void) interface_id; + + if (!daylight_saving_time_ptr) { + // Delete configuration + ns_dyn_mem_free(bbr_time_config); + bbr_time_config = NULL; + return 0; + } + + if (!bbr_time_config) { + bbr_time_config = ns_dyn_mem_alloc(sizeof(bbr_timezone_configuration_t)); + } + + if (!bbr_time_config) { + return -2; + } + *bbr_time_config = *daylight_saving_time_ptr; + + return 0; +#else + (void) interface_id; + (void) daylight_saving_time_ptr; + return -1; +#endif +} diff --git a/source/6LoWPAN/ws/ws_bbr_api_internal.h b/source/6LoWPAN/ws/ws_bbr_api_internal.h index dab05547eb..0ab7c1dda3 100644 --- a/source/6LoWPAN/ws/ws_bbr_api_internal.h +++ b/source/6LoWPAN/ws/ws_bbr_api_internal.h @@ -38,6 +38,7 @@ bool ws_bbr_ready_to_start(protocol_interface_info_entry_t *cur); bool ws_bbr_backbone_address_get(uint8_t *address); uint16_t ws_bbr_bsi_generate(protocol_interface_info_entry_t *interface); +uint16_t ws_bbr_pan_id_get(protocol_interface_info_entry_t *interface); void ws_bbr_init(protocol_interface_info_entry_t *interface); #else @@ -50,6 +51,7 @@ void ws_bbr_init(protocol_interface_info_entry_t *interface); #define ws_bbr_ready_to_start(cur) true #define ws_bbr_backbone_address_get(address) 0 #define ws_bbr_bsi_generate(interface) 0 +#define ws_bbr_pan_id_get(interface) 0 #define ws_bbr_init(interface) (void) 0 #endif //HAVE_WS_BORDER_ROUTER diff --git a/source/6LoWPAN/ws/ws_bootstrap.c b/source/6LoWPAN/ws/ws_bootstrap.c index b3f97518c3..253ec1d228 100644 --- a/source/6LoWPAN/ws/ws_bootstrap.c +++ b/source/6LoWPAN/ws/ws_bootstrap.c @@ -62,6 +62,10 @@ #include "6LoWPAN/ws/ws_ie_lib.h" #include "6LoWPAN/ws/ws_stats.h" #include "6LoWPAN/ws/ws_cfg_settings.h" +#include "6LoWPAN/ws/ws_bootstrap_6lbr.h" +#include "6LoWPAN/ws/ws_bootstrap_ffn.h" +#include "6LoWPAN/ws/ws_bootstrap_lfn.h" +#include "6LoWPAN/ws/ws_phy.h" #include "6LoWPAN/lowpan_adaptation_interface.h" #include "Service_Libs/etx/etx.h" #include "Service_Libs/mac_neighbor_table/mac_neighbor_table.h" @@ -84,19 +88,11 @@ #define TRACE_GROUP "wsbs" - static void ws_bootstrap_event_handler(arm_event_s *event); -static void ws_bootstrap_state_change(protocol_interface_info_entry_t *cur, icmp_state_t nwk_bootstrap_state); -static bool ws_bootstrap_state_discovery(struct protocol_interface_info_entry *cur); -static bool ws_bootstrap_state_active(struct protocol_interface_info_entry *cur); -static bool ws_bootstrap_state_wait_rpl(struct protocol_interface_info_entry *cur); static int8_t ws_bootsrap_event_trig(ws_bootsrap_event_type_e event_type, int8_t interface_id, arm_library_event_priority_e priority, void *event_data); - -static bool ws_bootstrap_neighbor_info_request(struct protocol_interface_info_entry *interface, const uint8_t *mac_64, llc_neighbour_req_t *neighbor_buffer, bool request_new); static uint16_t ws_bootstrap_routing_cost_calculate(protocol_interface_info_entry_t *cur); static uint16_t ws_bootstrap_rank_get(protocol_interface_info_entry_t *cur); static uint16_t ws_bootstrap_min_rank_inc_get(protocol_interface_info_entry_t *cur); - static void ws_bootstrap_mac_security_enable(protocol_interface_info_entry_t *cur); static void ws_bootstrap_nw_key_set(protocol_interface_info_entry_t *cur, uint8_t operation, uint8_t index, uint8_t *key); static void ws_bootstrap_nw_key_clear(protocol_interface_info_entry_t *cur, uint8_t slot); @@ -111,37 +107,11 @@ 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 void ws_bootstrap_dhcp_neighbour_update_cb(int8_t interface_id, uint8_t ll_addr[static 16]); +static void ws_bootstrap_dhcp_info_notify_cb(int8_t interface, dhcp_option_notify_t *options, dhcp_server_notify_info_t *server_info); +static void ws_bootstrap_test_procedure_trigger_timer(protocol_interface_info_entry_t *cur, uint32_t seconds); -static void ws_address_registration_update(protocol_interface_info_entry_t *interface, const uint8_t addr[16]); -static int8_t ws_bootstrap_neighbor_set(protocol_interface_info_entry_t *cur, parent_info_t *parent_ptr, bool clear_list); -static void ws_bootstrap_parent_confirm(protocol_interface_info_entry_t *cur, struct rpl_instance *instance); - -static void ws_bootstrap_candidate_table_reset(protocol_interface_info_entry_t *cur); -static parent_info_t *ws_bootstrap_candidate_parent_get(struct protocol_interface_info_entry *cur, const uint8_t *addr, bool create); -static void ws_bootstrap_candidate_parent_sort(struct protocol_interface_info_entry *cur, parent_info_t *new_entry); -static void ws_bootstrap_packet_congestion_init(protocol_interface_info_entry_t *cur); - -static void ws_bootstrap_asynch_trickle_stop(protocol_interface_info_entry_t *cur); -static void ws_bootstrap_advertise_start(protocol_interface_info_entry_t *cur); -static void ws_bootstrap_rpl_scan_start(protocol_interface_info_entry_t *cur); - -static uint16_t ws_randomize_fixed_channel(uint16_t configured_fixed_channel, uint8_t number_of_channels, uint32_t *channel_mask); - -typedef enum { - WS_PARENT_SOFT_SYNCH = 0, /**< let FHSS make decision if synchronization is needed*/ - WS_PARENT_HARD_SYNCH, /**< Synch FHSS with latest synch information*/ - WS_EAPOL_PARENT_SYNCH, /**< Broadcast synch with EAPOL parent*/ -} ws_parent_synch_e; - - -static void ws_bootsrap_create_ll_address(uint8_t *ll_address, const uint8_t *mac64) -{ - memcpy(ll_address, ADDR_LINK_LOCAL_PREFIX, 8); - memcpy(ll_address + 8, mac64, 8); - ll_address[8] ^= 2; -} - - +uint16_t test_pan_version = 1; static mac_neighbor_table_entry_t *ws_bootstrap_mac_neighbor_allocate(struct protocol_interface_info_entry *interface, const uint8_t *src64) { @@ -160,7 +130,6 @@ static mac_neighbor_table_entry_t *ws_bootstrap_mac_neighbor_allocate(struct pro } mac_neighbor_table_entry_t *ws_bootstrap_mac_neighbor_add(struct protocol_interface_info_entry *interface, const uint8_t *src64) - { mac_neighbor_table_entry_t *neighbor = mac_neighbor_table_address_discover(mac_neighbor_info(interface), src64, MAC_ADDR_MODE_64_BIT); if (neighbor) { @@ -200,7 +169,7 @@ static void ws_bootstrap_neighbor_delete(struct protocol_interface_info_entry *i ws_neighbor_class_entry_remove(&interface->ws_info->neighbor_storage, entry_ptr->index); } -static void ws_bootstrap_neighbor_list_clean(struct protocol_interface_info_entry *interface) +void ws_bootstrap_neighbor_list_clean(struct protocol_interface_info_entry *interface) { mac_neighbor_table_neighbor_list_clean(mac_neighbor_info(interface)); @@ -264,19 +233,87 @@ static void ws_bootstrap_address_notification_cb(struct protocol_interface_info_ } } } +#ifdef HAVE_WS_VERSION_1_1 -static void ws_bootstrap_configure_max_retries(protocol_interface_info_entry_t *cur, uint8_t max_mac_retries) +static ws_pcap_ie_t ws_neighbour_phy_cap_list_compare(ws_phy_cap_info_t *prefered_mode, ws_phy_cap_info_t *neighbour_cap_list) +{ + ws_pcap_ie_t pref_setup; + + ws_pcap_ie_t *prefered_setup = prefered_mode->pcap; + int length_of_list = prefered_mode->length_of_list; + while (length_of_list) { + for (int i = 0; i < neighbour_cap_list->length_of_list; i++) { + //Check first phy type is matching + if (neighbour_cap_list->pcap[i].phy_type != prefered_setup->phy_type) { + continue; + } + //Validate supported + if (neighbour_cap_list->pcap[i].operating_mode & prefered_setup->operating_mode) { + + //Take only matched opeating modes + pref_setup.operating_mode = neighbour_cap_list->pcap[i].operating_mode & prefered_setup->operating_mode; + pref_setup.phy_type = prefered_setup->phy_type; + return pref_setup; + } + break; + } + prefered_setup++; + length_of_list--; + } + //Mark zero operating modes + pref_setup.operating_mode = 0; + return pref_setup; +} + +static void ws_neighbour_mdr_mode_analyze(struct protocol_interface_info_entry *interface) +{ + if (!ws_version_1_1(interface)) { + return; + } + + if (!interface->ws_info->uptime || (interface->ws_info->uptime % 10)) { + return; + } + + if (!interface->ws_info->phy_cap_info.length_of_list) { + //No Preferred Cap modes + return; + } + + ns_list_foreach_safe(mac_neighbor_table_entry_t, cur, &mac_neighbor_info(interface)->neighbour_list) { + + ws_neighbor_class_entry_t *ws_neighbor = ws_neighbor_class_entry_get(&interface->ws_info->neighbor_storage, cur->index); + + if (!ws_neighbor || ws_neighbor->phy_mode_id || !ws_neighbor->pcap_info.length_of_list) { + continue; + } + + ws_pcap_ie_t preferred = ws_neighbour_phy_cap_list_compare(&interface->ws_info->phy_cap_info, ws_neighbour_cap_pointer(ws_neighbor)); + uint8_t phy_mode_id = ws_ie_lib_phy_mode_id_get_from_phy_cap(&preferred); + if (ws_neighbor->phy_mode_id != phy_mode_id) { + tr_debug("Updated Neigh %u MDR phy mode id %u -> %u", cur->index, ws_neighbor->phy_mode_id, phy_mode_id); + ws_neighbor->phy_mode_id = phy_mode_id; + } + + } +} +#else +#define ws_neighbour_mdr_mode_analyze(interface) ((void)0) +#endif + + +void ws_bootstrap_configure_max_retries(protocol_interface_info_entry_t *cur, uint8_t max_mac_retries) { mac_helper_mac_mlme_max_retry_set(cur->id, max_mac_retries); } -static void ws_bootstrap_configure_csma_ca_backoffs(protocol_interface_info_entry_t *cur, uint8_t max_backoffs, uint8_t min_be, uint8_t max_be) +void ws_bootstrap_configure_csma_ca_backoffs(protocol_interface_info_entry_t *cur, uint8_t max_backoffs, uint8_t min_be, uint8_t max_be) { mac_helper_mac_mlme_max_csma_backoffs_set(cur->id, max_backoffs); mac_helper_mac_mlme_be_set(cur->id, min_be, max_be); } -static void ws_bootstrap_configure_data_request_restart(protocol_interface_info_entry_t *cur, uint8_t cca_failure_restart_max, uint8_t tx_failure_restart_max, uint16_t blacklist_min_ms, uint16_t blacklist_max_ms) +void ws_bootstrap_configure_data_request_restart(protocol_interface_info_entry_t *cur, uint8_t cca_failure_restart_max, uint8_t tx_failure_restart_max, uint16_t blacklist_min_ms, uint16_t blacklist_max_ms) { mlme_request_restart_config_t request_restart_config; request_restart_config.cca_failure_restart_max = cca_failure_restart_max; @@ -301,6 +338,7 @@ static int ws_bootstrap_tasklet_init(protocol_interface_info_entry_t *cur) return 0; } + static void ws_nwk_event_post(protocol_interface_info_entry_t *cur, arm_nwk_interface_status_type_e posted_event) { arm_event_s event = { @@ -329,7 +367,7 @@ static int8_t ws_bootsrap_event_trig(ws_bootsrap_event_type_e event_type, int8_t return eventOS_event_send(&event); } -static void ws_nud_table_reset(protocol_interface_info_entry_t *cur) +void ws_nud_table_reset(protocol_interface_info_entry_t *cur) { //Empty active list ns_list_foreach_safe(ws_nud_table_entry_t, entry, &cur->ws_info->active_nud_process) { @@ -361,7 +399,6 @@ static ws_nud_table_entry_t *ws_nud_entry_get_free(protocol_interface_info_entry return entry; } - void ws_nud_entry_remove_active(protocol_interface_info_entry_t *cur, void *neighbor) { ws_nud_table_entry_t *entry = ws_nud_entry_discover(cur, neighbor); @@ -378,7 +415,6 @@ void ws_nud_entry_remove_active(protocol_interface_info_entry_t *cur, void *neig } } - static ws_nud_table_entry_t *ws_nud_entry_discover(protocol_interface_info_entry_t *cur, void *neighbor) { ns_list_foreach(ws_nud_table_entry_t, entry, &cur->ws_info->active_nud_process) { @@ -389,7 +425,6 @@ static ws_nud_table_entry_t *ws_nud_entry_discover(protocol_interface_info_entry return NULL; } - static void ws_nud_state_clean(protocol_interface_info_entry_t *cur, ws_nud_table_entry_t *entry) { mac_neighbor_table_entry_t *neighbor = entry->neighbor_info; @@ -408,6 +443,7 @@ static void ws_nud_entry_remove(protocol_interface_info_entry_t *cur, mac_neighb ws_nud_state_clean(cur, nud_entry); } } + if_address_entry_t *ws_probe_aro_address(protocol_interface_info_entry_t *interface) { if (interface->global_address_available) { @@ -420,7 +456,6 @@ if_address_entry_t *ws_probe_aro_address(protocol_interface_info_entry_t *interf return NULL; } - static bool ws_nud_message_build(protocol_interface_info_entry_t *cur, mac_neighbor_table_entry_t *neighbor, bool nud_process) { //Send NS @@ -430,7 +465,7 @@ static bool ws_nud_message_build(protocol_interface_info_entry_t *cur, mac_neigh aro_t *aro_ptr = NULL; uint8_t *src_address_ptr = NULL; - ws_bootsrap_create_ll_address(ll_target, neighbor->mac64); + ws_common_create_ll_address(ll_target, neighbor->mac64); if (nud_process) { tr_info("NUD generate NS %u", neighbor->index); } else { @@ -508,7 +543,7 @@ void ws_nud_active_timer(protocol_interface_info_entry_t *cur, uint16_t ticks) } } -static fhss_ws_neighbor_timing_info_t *ws_get_neighbor_info(const fhss_api_t *api, uint8_t eui64[8]) +static fhss_ws_neighbor_timing_info_t *ws_bootstrap_get_neighbor_info(const fhss_api_t *api, uint8_t eui64[8]) { protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_fhss_api(api); if (!cur || !cur->mac_parameters || !mac_neighbor_info(cur)) { @@ -529,7 +564,8 @@ static fhss_ws_neighbor_timing_info_t *ws_get_neighbor_info(const fhss_api_t *ap } return &temp_entry->neigh_info_list.fhss_data; } -static void ws_bootstrap_llc_hopping_update(struct protocol_interface_info_entry *cur, const fhss_ws_configuration_t *fhss_configuration) + +void ws_bootstrap_llc_hopping_update(struct protocol_interface_info_entry *cur, const fhss_ws_configuration_t *fhss_configuration) { 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; @@ -542,7 +578,7 @@ static void ws_bootstrap_llc_hopping_update(struct protocol_interface_info_entry cur->ws_info->hopping_schdule.fhss_bsi = fhss_configuration->bsi; } -static uint8_t ws_generate_exluded_channel_list_from_active_channels(ws_excluded_channel_data_t *excluded_data, const uint32_t *selected_channel_mask, const uint32_t *global_channel_mask, uint16_t number_of_channels) +static uint8_t ws_bootstrap_generate_exluded_channel_list_from_active_channels(ws_excluded_channel_data_t *excluded_data, const uint32_t *selected_channel_mask, const uint32_t *global_channel_mask, uint16_t number_of_channels) { bool active_range = false; @@ -550,7 +586,7 @@ static uint8_t ws_generate_exluded_channel_list_from_active_channels(ws_excluded memset(excluded_data, 0, sizeof(ws_excluded_channel_data_t)); for (uint8_t i = 0; i < number_of_channels; i++) { - if (!(global_channel_mask[0 + (i / 32)] & (1 << (i % 32)))) { + if (!(global_channel_mask[i / 32] & (1U << (i % 32)))) { //Global exluded channel if (active_range) { //Mark range stop here @@ -559,7 +595,7 @@ static uint8_t ws_generate_exluded_channel_list_from_active_channels(ws_excluded continue; } - if (selected_channel_mask[0 + (i / 32)] & (1 << (i % 32))) { + if (selected_channel_mask[i / 32] & (1U << (i % 32))) { if (active_range) { //Mark range stop here active_range = false; @@ -567,7 +603,7 @@ static uint8_t ws_generate_exluded_channel_list_from_active_channels(ws_excluded } else { //Mark excluded channel //Swap Order already here - excluded_data->channel_mask[0 + (i / 32)] |= 1 << (31 - (i % 32)); + excluded_data->channel_mask[i / 32] |= 1U << (31 - (i % 32)); excluded_data->excluded_channel_count++; if (excluded_data->excluded_range_length < WS_EXCLUDED_MAX_RANGE_TO_SEND) { @@ -605,33 +641,28 @@ static uint8_t ws_generate_exluded_channel_list_from_active_channels(ws_excluded return channel_plan; } -static void ws_fhss_configure_channel_masks(protocol_interface_info_entry_t *cur, fhss_ws_configuration_t *fhss_configuration) +void ws_bootstrap_fhss_configure_channel_masks(protocol_interface_info_entry_t *cur, fhss_ws_configuration_t *fhss_configuration) { fhss_configuration->channel_mask_size = cur->ws_info->hopping_schdule.number_of_channels; - ws_generate_channel_list(fhss_configuration->channel_mask, cur->ws_info->hopping_schdule.number_of_channels, cur->ws_info->hopping_schdule.regulatory_domain, cur->ws_info->hopping_schdule.operating_class, cur->ws_info->hopping_schdule.channel_plan_id); - ws_generate_channel_list(fhss_configuration->unicast_channel_mask, cur->ws_info->hopping_schdule.number_of_channels, cur->ws_info->hopping_schdule.regulatory_domain, cur->ws_info->hopping_schdule.operating_class, cur->ws_info->hopping_schdule.channel_plan_id); + ws_common_generate_channel_list(fhss_configuration->channel_mask, cur->ws_info->hopping_schdule.number_of_channels, cur->ws_info->hopping_schdule.regulatory_domain, cur->ws_info->hopping_schdule.operating_class, cur->ws_info->hopping_schdule.channel_plan_id); + ws_common_generate_channel_list(fhss_configuration->unicast_channel_mask, cur->ws_info->hopping_schdule.number_of_channels, cur->ws_info->hopping_schdule.regulatory_domain, cur->ws_info->hopping_schdule.operating_class, cur->ws_info->hopping_schdule.channel_plan_id); // using bitwise AND operation for user set channel mask to remove channels not allowed in this device for (uint8_t n = 0; n < 8; n++) { fhss_configuration->unicast_channel_mask[n] &= cur->ws_info->cfg->fhss.fhss_channel_mask[n]; } //Update Exluded channels - cur->ws_info->hopping_schdule.channel_plan = ws_generate_exluded_channel_list_from_active_channels(&cur->ws_info->hopping_schdule.excluded_channels, fhss_configuration->unicast_channel_mask, fhss_configuration->channel_mask, cur->ws_info->hopping_schdule.number_of_channels); + cur->ws_info->hopping_schdule.channel_plan = ws_bootstrap_generate_exluded_channel_list_from_active_channels(&cur->ws_info->hopping_schdule.excluded_channels, fhss_configuration->unicast_channel_mask, fhss_configuration->channel_mask, cur->ws_info->hopping_schdule.number_of_channels); } -static int8_t ws_fhss_initialize(protocol_interface_info_entry_t *cur) +static int8_t ws_bootstrap_fhss_initialize(protocol_interface_info_entry_t *cur) { fhss_api_t *fhss_api = ns_sw_mac_get_fhss_api(cur->mac_api); fhss_ws_configuration_t fhss_configuration; memset(&fhss_configuration, 0, sizeof(fhss_ws_configuration_t)); if (!fhss_api) { // When FHSS doesn't exist yet, create one - ws_fhss_configure_channel_masks(cur, &fhss_configuration); - - fhss_configuration.fhss_uc_dwell_interval = cur->ws_info->cfg->fhss.fhss_uc_dwell_interval; - fhss_configuration.ws_uc_channel_function = (fhss_ws_channel_functions)cur->ws_info->cfg->fhss.fhss_uc_channel_function; - fhss_configuration.ws_bc_channel_function = (fhss_ws_channel_functions)cur->ws_info->cfg->fhss.fhss_bc_channel_function; - fhss_configuration.fhss_bc_dwell_interval = cur->ws_info->cfg->fhss.fhss_bc_dwell_interval; - fhss_configuration.fhss_broadcast_interval = cur->ws_info->cfg->fhss.fhss_bc_interval; + ws_bootstrap_fhss_configure_channel_masks(cur, &fhss_configuration); + ws_bootstrap_fhss_set_defaults(cur, &fhss_configuration); fhss_api = ns_fhss_ws_create(&fhss_configuration, cur->ws_info->fhss_timer_ptr); if (!fhss_api) { @@ -641,32 +672,13 @@ static int8_t ws_fhss_initialize(protocol_interface_info_entry_t *cur) // Allow transmitting unicast frames only on TX slots in normal and expedited forwarding mode ns_fhss_ws_set_tx_allowance_level(fhss_api, WS_TX_SLOT, WS_TX_SLOT); } else { - // Read defaults from the configuration to help FHSS testing - const fhss_ws_configuration_t *fhss_configuration_copy = ns_fhss_ws_configuration_get(fhss_api); - if (!fhss_configuration_copy) { - // no configuration set yet - return 0; - } - fhss_configuration = *fhss_configuration_copy; - //Overwrite domain channel setup this will over write a default 35 channel - int num_of_channels = channel_list_count_channels(fhss_configuration_copy->unicast_channel_mask); - cur->ws_info->hopping_schdule.number_of_channels = (uint8_t) num_of_channels; - memcpy(cur->ws_info->cfg->fhss.fhss_channel_mask, fhss_configuration_copy->unicast_channel_mask, sizeof(uint32_t) * 8); - cur->ws_info->cfg->fhss.fhss_uc_channel_function = fhss_configuration_copy->ws_uc_channel_function; - cur->ws_info->cfg->fhss.fhss_bc_channel_function = fhss_configuration_copy->ws_bc_channel_function; - cur->ws_info->cfg->fhss.fhss_bc_dwell_interval = fhss_configuration_copy->fhss_bc_dwell_interval; - cur->ws_info->cfg->fhss.fhss_bc_interval = fhss_configuration_copy->fhss_broadcast_interval; - cur->ws_info->cfg->fhss.fhss_uc_dwell_interval = fhss_configuration_copy->fhss_uc_dwell_interval; - cur->ws_info->cfg->fhss.fhss_bc_fixed_channel = fhss_configuration_copy->broadcast_fixed_channel; - cur->ws_info->cfg->fhss.fhss_uc_fixed_channel = fhss_configuration_copy->unicast_fixed_channel; - ws_fhss_configure_channel_masks(cur, &fhss_configuration); - ns_fhss_ws_configuration_set(fhss_api, &fhss_configuration); + return -1; } return 0; } -static int8_t ws_fhss_set_defaults(protocol_interface_info_entry_t *cur, fhss_ws_configuration_t *fhss_configuration) +int8_t ws_bootstrap_fhss_set_defaults(protocol_interface_info_entry_t *cur, fhss_ws_configuration_t *fhss_configuration) { fhss_configuration->fhss_uc_dwell_interval = cur->ws_info->cfg->fhss.fhss_uc_dwell_interval; fhss_configuration->ws_uc_channel_function = (fhss_ws_channel_functions)cur->ws_info->cfg->fhss.fhss_uc_channel_function; @@ -679,42 +691,20 @@ static int8_t ws_fhss_set_defaults(protocol_interface_info_entry_t *cur, fhss_ws fhss_configuration->broadcast_fixed_channel = cur->ws_info->cfg->fhss.fhss_bc_fixed_channel; return 0; } -static int8_t ws_fhss_border_router_configure(protocol_interface_info_entry_t *cur) + +static bool ws_bootstrap_channel_allowed(uint8_t channel, uint32_t *channel_mask) { - // Read configuration of existing FHSS and start using the default values for any network - fhss_ws_configuration_t fhss_configuration; - memset(&fhss_configuration, 0, sizeof(fhss_ws_configuration_t)); - - 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)); - } - - //GET BSI from BBR module - fhss_configuration.bsi = ws_bbr_bsi_generate(cur); - ws_fhss_configure_channel_masks(cur, &fhss_configuration); - // Randomize fixed channels. Only used if channel plan is fixed. - cur->ws_info->cfg->fhss.fhss_uc_fixed_channel = ws_randomize_fixed_channel(cur->ws_info->cfg->fhss.fhss_uc_fixed_channel, cur->ws_info->hopping_schdule.number_of_channels, fhss_configuration.channel_mask); - cur->ws_info->cfg->fhss.fhss_bc_fixed_channel = ws_randomize_fixed_channel(cur->ws_info->cfg->fhss.fhss_bc_fixed_channel, cur->ws_info->hopping_schdule.number_of_channels, fhss_configuration.channel_mask); - ws_fhss_set_defaults(cur, &fhss_configuration); - ns_fhss_ws_configuration_set(cur->ws_info->fhss_api, &fhss_configuration); - ws_bootstrap_llc_hopping_update(cur, &fhss_configuration); - - return 0; -} - -static bool ws_channel_allowed(uint8_t channel, uint32_t *channel_mask) -{ - if ((1 << (channel % 32)) & (channel_mask[channel / 32])) { + if ((1U << (channel % 32)) & (channel_mask[channel / 32])) { return true; } return false; } -static uint16_t ws_randomize_fixed_channel(uint16_t configured_fixed_channel, uint8_t number_of_channels, uint32_t *channel_mask) +uint16_t ws_bootstrap_randomize_fixed_channel(uint16_t configured_fixed_channel, uint8_t number_of_channels, uint32_t *channel_mask) { if (configured_fixed_channel == 0xFFFF) { uint16_t random_channel = randLIB_get_random_in_range(0, number_of_channels - 1); - while (ws_channel_allowed(random_channel, channel_mask) == false) { + while (ws_bootstrap_channel_allowed(random_channel, channel_mask) == false) { random_channel = randLIB_get_random_in_range(0, number_of_channels - 1); } return random_channel; @@ -723,74 +713,37 @@ static uint16_t ws_randomize_fixed_channel(uint16_t configured_fixed_channel, ui } } -static int8_t ws_fhss_configure(protocol_interface_info_entry_t *cur, bool discovery) +static int8_t ws_bootstrap_fhss_enable(protocol_interface_info_entry_t *cur) { - // Read configuration of existing FHSS and start using the default values for any network - fhss_ws_configuration_t fhss_configuration; - memset(&fhss_configuration, 0, sizeof(fhss_ws_configuration_t)); + fhss_ws_configuration_t fhss_configuration = ws_common_get_current_fhss_configuration(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)); - ws_fhss_set_defaults(cur, &fhss_configuration); - ws_fhss_configure_channel_masks(cur, &fhss_configuration); - } - // Discovery is done using fixed channel - if (discovery) { - fhss_configuration.ws_uc_channel_function = WS_FIXED_CHANNEL; - } else { - fhss_configuration.ws_uc_channel_function = (fhss_ws_channel_functions)cur->ws_info->cfg->fhss.fhss_uc_channel_function; - } - fhss_configuration.ws_bc_channel_function = WS_FIXED_CHANNEL; - fhss_configuration.fhss_broadcast_interval = 0; - uint8_t tmp_uc_fixed_channel = ws_randomize_fixed_channel(cur->ws_info->cfg->fhss.fhss_uc_fixed_channel, cur->ws_info->hopping_schdule.number_of_channels, fhss_configuration.channel_mask); - uint8_t tmp_bc_fixed_channel = ws_randomize_fixed_channel(cur->ws_info->cfg->fhss.fhss_bc_fixed_channel, cur->ws_info->hopping_schdule.number_of_channels, fhss_configuration.channel_mask); - fhss_configuration.unicast_fixed_channel = tmp_uc_fixed_channel; - fhss_configuration.broadcast_fixed_channel = tmp_bc_fixed_channel; - ns_fhss_ws_configuration_set(cur->ws_info->fhss_api, &fhss_configuration); - ns_fhss_ws_set_hop_count(cur->ws_info->fhss_api, 0xff); + // Set the LLC information to follow the actual fhss settings ws_bootstrap_llc_hopping_update(cur, &fhss_configuration); - return 0; -} - -static int8_t ws_fhss_enable(protocol_interface_info_entry_t *cur) -{ - const fhss_ws_configuration_t *fhss_configuration = ns_fhss_ws_configuration_get(cur->ws_info->fhss_api); - - if (!cur->ws_info->fhss_api || !fhss_configuration) { - return -1; - } - // Set the LLC information to follow the actual fhss settings - ws_bootstrap_llc_hopping_update(cur, fhss_configuration); - // Set neighbor info callback - if (ns_fhss_set_neighbor_info_fp(cur->ws_info->fhss_api, &ws_get_neighbor_info)) { + if (ns_fhss_set_neighbor_info_fp(cur->ws_info->fhss_api, &ws_bootstrap_get_neighbor_info)) { return -1; } - if (cur->bootsrap_mode == ARM_NWK_BOOTSRAP_MODE_6LoWPAN_BORDER_ROUTER) { - ns_fhss_ws_set_hop_count(cur->ws_info->fhss_api, 0); - } + return 0; } /* Sets the parent and broadcast schedule we are following * */ -static void ws_bootstrap_primary_parent_set(struct protocol_interface_info_entry *cur, llc_neighbour_req_t *neighbor_info, ws_parent_synch_e synch_req) +void ws_bootstrap_primary_parent_set(struct protocol_interface_info_entry *cur, llc_neighbour_req_t *neighbor_info, ws_parent_synch_e synch_req) { - - fhss_ws_configuration_t fhss_configuration; if (!neighbor_info->ws_neighbor->broadcast_timing_info_stored) { tr_error("No BC timing info for set new parent"); return; } - memcpy(&fhss_configuration, ns_fhss_ws_configuration_get(cur->ws_info->fhss_api), sizeof(fhss_ws_configuration_t)); + fhss_ws_configuration_t fhss_configuration = ws_common_get_current_fhss_configuration(cur); // Learning broadcast network configuration if (neighbor_info->ws_neighbor->broadcast_shedule_info_stored) { if (synch_req != WS_EAPOL_PARENT_SYNCH) { - ws_fhss_set_defaults(cur, &fhss_configuration); + ws_bootstrap_fhss_set_defaults(cur, &fhss_configuration); } fhss_configuration.ws_bc_channel_function = (fhss_ws_channel_functions)neighbor_info->ws_neighbor->fhss_data.bc_timing_info.broadcast_channel_function; if (fhss_configuration.ws_bc_channel_function == WS_FIXED_CHANNEL) { @@ -931,133 +884,6 @@ bool ws_bootstrap_nd_ns_transmit(protocol_interface_info_entry_t *cur, ipv6_neig // True means we skip the message sending return true; } - -static void ws_bootstrap_dhcp_neighbour_update_cb(int8_t interface_id, uint8_t ll_addr[static 16]) -{ - if (memcmp(ll_addr, ADDR_LINK_LOCAL_PREFIX, 8)) { - return; - } - - protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(interface_id); - if (!cur) { - return; - } - - uint8_t mac64[8]; - memcpy(mac64, ll_addr + 8, 8); - mac64[0] ^= 2; - ws_bootstrap_mac_neighbor_short_time_set(cur, mac64, WS_NEIGHBOUR_DHCP_ENTRY_LIFETIME); -} - -static void ws_bootstrap_dhcp_info_notify_cb(int8_t interface, dhcp_option_notify_t *options, dhcp_server_notify_info_t *server_info) -{ - protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(interface); - if (!cur) { - return; - } - uint8_t server_ll64[16]; - memcpy(server_ll64, ADDR_LINK_LOCAL_PREFIX, 8); - - if (server_info->duid_length == 8) { - memcpy(server_ll64 + 8, server_info->duid, 8); - } else { - server_ll64[8] = server_info->duid[0]; - server_ll64[9] = server_info->duid[1]; - server_ll64[10] = server_info->duid[2]; - server_ll64[11] = 0xff; - server_ll64[12] = 0xfe; - server_ll64[13] = server_info->duid[3]; - server_ll64[14] = server_info->duid[4]; - server_ll64[15] = server_info->duid[5]; - } - server_ll64[8] ^= 2; - - switch (options->option_type) { - case DHCPV6_OPTION_VENDOR_SPECIFIC_INFO: - if (options->option.vendor_spesific.enterprise_number != ARM_ENTERPRISE_NUMBER) { - break; - } - while (options->option.vendor_spesific.data_length) { - uint16_t option_type; - char *domain; - uint8_t *address; - uint16_t option_len; - option_len = net_dns_option_vendor_option_data_get_next(options->option.vendor_spesific.data, options->option.vendor_spesific.data_length, &option_type); - tr_debug("DHCP vendor specific data type:%u length %d", option_type, option_len); - //tr_debug("DHCP vendor specific data %s", trace_array(options->option.vendor_spesific.data, options->option.vendor_spesific.data_length)); - - if (option_len == 0) { - // Option fields were corrupted - break; - } - if (option_type == ARM_DHCP_VENDOR_DATA_DNS_QUERY_RESULT) { - // Process ARM DNS query result - domain = NULL; - address = NULL; - if (net_dns_option_vendor_option_data_dns_query_read(options->option.vendor_spesific.data, options->option.vendor_spesific.data_length, &address, &domain) > 0 || - domain || address) { - // Valid ARM DNS query entry - net_dns_query_result_set(interface, address, domain, server_info->life_time); - } - } - if (option_type == ARM_DHCP_VENDOR_DATA_NETWORK_TIME) { - // Process ARM Network Time - // Get Current time - // Get Round trip time of the DHCP request - // Estimated error is elapsed time of request - // If current time difference is larger than estimated error update current time - // set the time for server time + *.5 RTT - int32_t era; - uint32_t offset; - if (net_vendor_option_current_time_read(options->option.vendor_spesific.data, options->option.vendor_spesific.data_length, &era, &offset, NULL)) { - uint64_t current_time; - uint64_t network_time = (era * (uint64_t)(4294967296)) + offset - 2208988800; //Convert to First day of Unix (1 Jan 1970) - - tr_debug("Network Time option Era:%"PRId32" Offset:%"PRIu32" rtt: %"PRId32" time: %"PRIu64, era, offset, server_info->rtt, network_time); - if (0 == ns_time_system_time_read(¤t_time)) { - uint64_t difference; - // We only adjust clock if time has drifted more than 10 seconds to avoid constant changing of time - // If Round trip time is very high the accuracy is reduced. - uint32_t estimated_error = 10 + server_info->rtt / 10; - // Take into account the round trip time it took the response to arrive from the time server Write the time. - network_time += server_info->rtt / 20; - - if (current_time > network_time) { - difference = current_time - network_time; - } else { - difference = network_time - current_time; - } - if (difference > estimated_error) { - // Larger than 10 second difference update the time - int ret = ns_time_system_time_write(network_time); - tr_info("Network Time %s: Era:%"PRId32" Offset:%"PRIu32" old time: %"PRIu64" time: %"PRIu64, ret == 0 ? "updated" : "update FAILED", era, offset, current_time, network_time); - } - } - } - } - - options->option.vendor_spesific.data_length -= option_len; - options->option.vendor_spesific.data += option_len; - } - break; - - case DHCPV6_OPTION_DNS_SERVERS: - while (options->option.generic.data_length && options->option.generic.data_length >= 16 && options->option.generic.data_length % 16 == 0) { - // Validate payload to have full 16 byte length addresses without any extra bytes - net_dns_server_address_set(interface, server_ll64, options->option.generic.data, server_info->life_time); - options->option.generic.data_length -= 16; - options->option.generic.data += 16; - } - break; - case DHCPV6_OPTION_DOMAIN_LIST: - net_dns_server_search_list_set(interface, server_ll64, options->option.generic.data, options->option.generic.data_length, server_info->life_time); - break; - default: - break; - } - -} - static void ws_bootstrap_memory_configuration() { /* Configure memory limits for garbage collection based on total memory size @@ -1095,7 +921,7 @@ static int8_t ws_bootstrap_up(protocol_interface_info_entry_t *cur) tr_error("Interface not yet fully configured"); return -2; } - if (ws_fhss_initialize(cur) != 0) { + if (ws_bootstrap_fhss_initialize(cur) != 0) { tr_error("fhss initialization failed"); return -3; } @@ -1164,43 +990,6 @@ cleanup: return ret_val; } -void ws_bootstrap_disconnect(protocol_interface_info_entry_t *cur, ws_bootsrap_event_type_e event_type) -{ - if (cur->nwk_bootstrap_state == ER_RPL_NETWORK_LEAVING) { - //Already moved to leaving state. - return; - } - // We are no longer connected - cur->ws_info->connected_time = 0; - - if (cur->rpl_domain && cur->nwk_bootstrap_state == ER_BOOTSRAP_DONE) { - //Stop Asych Timer - ws_bootstrap_asynch_trickle_stop(cur); - tr_debug("Start Network soft leaving"); - if (event_type == WS_FAST_DISCONNECT) { - rpl_control_instant_poison(cur, cur->rpl_domain); - cur->bootsrap_state_machine_cnt = 80; //Give 8 seconds time to send Poison - } else { - rpl_control_poison(cur->rpl_domain, 1); - cur->bootsrap_state_machine_cnt = 6000; //Give 10 minutes time for poison if RPL is not report - } - - } else { - ws_bootstrap_event_discovery_start(cur); - } - cur->nwk_bootstrap_state = ER_RPL_NETWORK_LEAVING; -} - - -static void ws_bootstrap_asynch_trickle_stop(protocol_interface_info_entry_t *cur) -{ - cur->ws_info->trickle_pas_running = false; - cur->ws_info->trickle_pa_running = false; - cur->ws_info->trickle_pcs_running = false; - cur->ws_info->trickle_pc_running = false; - cur->ws_info->trickle_pc_consistency_block_period = 0; -} - static int8_t ws_bootstrap_down(protocol_interface_info_entry_t *cur) { if (!cur || !(cur->lowpan_info & INTERFACE_NWK_ACTIVE)) { @@ -1266,7 +1055,7 @@ void ws_bootstrap_configuration_reset(protocol_interface_info_entry_t *cur) return; } -static bool ws_bootstrap_network_name_matches(const struct mcps_data_ie_list *ie_ext, const char *network_name_ptr) +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; @@ -1291,50 +1080,6 @@ static bool ws_bootstrap_network_name_matches(const struct mcps_data_ie_list *ie return true; } -static void ws_bootstrap_pan_advertisement_analyse_active(struct protocol_interface_info_entry *cur, ws_pan_information_t *pan_information) -{ - /* In Active state - * - * A consistent transmission is defined as a PAN Advertisement received by a node with PAN ID and - * NETNAME-IE / Network Name matching that of the receiving node, and with a PAN-IE / Routing Cost - * the same or worse than (bigger than or equal to) that of the receiving node. - * - * Inconsistent: - * - * Received Routing Cost is smaller than stored one - * - * A PAN Advertisement received by a node with PAN ID and NETNAME-IE / Network name matching - * that of the receiving node, and PAN-IE / Routing Cost better than (smaller than) that of the receiving node. - * - */ - if (cur->bootsrap_mode == ARM_NWK_BOOTSRAP_MODE_6LoWPAN_BORDER_ROUTER) { - //Border router never set consistent that will guarantee that BR will send advertisment - return; - } -#ifdef WISUN_1_0_ERRATA_FIX - if (pan_information->pan_size == cur->ws_info->pan_information.pan_size) { - //If same pan size information then set consistent value - trickle_consistent_heard(&cur->ws_info->trickle_pan_advertisement); - } -#else - // Wi-SUN 1.0 specified functionality, causes extra inconsistencies when we hear higher rank advertisements - if (pan_information->routing_cost >= ws_bootstrap_routing_cost_calculate(cur)) { - trickle_consistent_heard(&cur->ws_info->trickle_pan_advertisement); - } else { - trickle_inconsistent_heard(&cur->ws_info->trickle_pan_advertisement, &cur->ws_info->trickle_params_pan_discovery); - } -#endif -} - -static parent_info_t *ws_bootstrap_candidate_parent_get_best(protocol_interface_info_entry_t *cur) -{ - ns_list_foreach_safe(parent_info_t, entry, &cur->ws_info->parent_list_reserved) { - tr_info("candidate list a:%s panid:%x cost:%d size:%d rssi:%d txFailure:%u age:%"PRIu32, trace_array(entry->addr, 8), entry->pan_id, entry->pan_information.routing_cost, entry->pan_information.pan_size, entry->signal_dbm, entry->tx_fail, protocol_core_monotonic_time - entry->age); - } - - return ns_list_get_first(&cur->ws_info->parent_list_reserved); -} - static void ws_bootstrap_decode_exclude_range_to_mask_by_range(void *mask_buffer, ws_excluded_channel_range_t *range_info, uint16_t number_of_channels) { uint16_t range_start, range_stop; @@ -1355,8 +1100,8 @@ static void ws_bootstrap_decode_exclude_range_to_mask_by_range(void *mask_buffer //channel_index = 0; } if (channel >= range_start && channel <= range_stop) { - //mask_ptr[mask_index] |= 1 << (31 - channel_index); - mask_ptr[0 + (channel / 32)] |= 1 << (31 - (channel % 32)); + //mask_ptr[mask_index] |= 1U << (31 - channel_index); + mask_ptr[channel / 32] |= 1U << (31 - (channel % 32)); } else if (channel > range_stop) { break; } @@ -1364,7 +1109,7 @@ static void ws_bootstrap_decode_exclude_range_to_mask_by_range(void *mask_buffer } } -static void ws_bootstrap_candidate_parent_store(parent_info_t *parent, const struct mcps_data_ind_s *data, ws_utt_ie_t *ws_utt, ws_us_ie_t *ws_us, ws_pan_information_t *pan_information) +void ws_bootstrap_candidate_parent_store(parent_info_t *parent, const struct mcps_data_ind_s *data, ws_utt_ie_t *ws_utt, ws_us_ie_t *ws_us, ws_pan_information_t *pan_information) { parent->ws_utt = *ws_utt; // Saved from unicast IE @@ -1406,7 +1151,16 @@ static void ws_bootstrap_candidate_parent_store(parent_info_t *parent, const str parent->age = protocol_core_monotonic_time; } -static void ws_bootstrap_candidate_table_reset(protocol_interface_info_entry_t *cur) +parent_info_t *ws_bootstrap_candidate_parent_get_best(protocol_interface_info_entry_t *cur) +{ + ns_list_foreach_safe(parent_info_t, entry, &cur->ws_info->parent_list_reserved) { + tr_info("candidate list a:%s panid:%x cost:%d size:%d rssi:%d txFailure:%u age:%"PRIu32, trace_array(entry->addr, 8), entry->pan_id, entry->pan_information.routing_cost, entry->pan_information.pan_size, entry->signal_dbm, entry->tx_fail, protocol_core_monotonic_time - entry->age); + } + + return ns_list_get_first(&cur->ws_info->parent_list_reserved); +} + +void ws_bootstrap_candidate_table_reset(protocol_interface_info_entry_t *cur) { //Empty active list ns_list_foreach_safe(parent_info_t, entry, &cur->ws_info->parent_list_free) { @@ -1442,7 +1196,7 @@ static parent_info_t *ws_bootstrap_candidate_parent_allocate(protocol_interface_ return entry; } -static parent_info_t *ws_bootstrap_candidate_parent_get(struct protocol_interface_info_entry *cur, const uint8_t *addr, bool create) +parent_info_t *ws_bootstrap_candidate_parent_get(struct protocol_interface_info_entry *cur, const uint8_t *addr, bool create) { ns_list_foreach_safe(parent_info_t, entry, &cur->ws_info->parent_list_reserved) { if (memcmp(entry->addr, addr, 8) == 0) { @@ -1510,7 +1264,7 @@ static bool ws_bootstrap_candidate_parent_compare(parent_info_t *p1, parent_info return false; } -static void ws_bootstrap_candidate_list_clean(struct protocol_interface_info_entry *cur, uint8_t pan_max, uint32_t current_time, uint16_t pan_id) +void ws_bootstrap_candidate_list_clean(struct protocol_interface_info_entry *cur, uint8_t pan_max, uint32_t current_time, uint16_t pan_id) { int pan_count = 0; @@ -1533,7 +1287,7 @@ static void ws_bootstrap_candidate_list_clean(struct protocol_interface_info_ent } } -static void ws_bootstrap_candidate_parent_sort(struct protocol_interface_info_entry *cur, parent_info_t *new_entry) +void ws_bootstrap_candidate_parent_sort(struct protocol_interface_info_entry *cur, parent_info_t *new_entry) { //Remove from the list @@ -1557,352 +1311,6 @@ static void ws_bootstrap_candidate_parent_sort(struct protocol_interface_info_en ns_list_add_to_end(&cur->ws_info->parent_list_reserved, new_entry); } -static void ws_bootstrap_pan_information_store(struct protocol_interface_info_entry *cur, const struct mcps_data_ind_s *data, ws_utt_ie_t *ws_utt, ws_us_ie_t *ws_us, ws_pan_information_t *pan_information) -{ - - parent_info_t *new_entry; - /* Have List of 20 heard neighbours - * Order those as best based on pan cost - * In single pan order based on signal quality - * in single PAN limit the amount of devices to 5 - * If there is no advertisement heard for last hour Clear the neigbour. - */ - - // Discovery state processing - //tr_info("neighbour: addr:%s panid:%x signal:%d", trace_array(data->SrcAddr, 8), data->SrcPANId, data->signal_dbm); - - // Clean old entries - ws_bootstrap_candidate_list_clean(cur, WS_PARENT_LIST_MAX_PAN_IN_DISCOVERY, protocol_core_monotonic_time, data->SrcPANId); - - new_entry = ws_bootstrap_candidate_parent_get(cur, data->SrcAddr, true); - if (!new_entry) { - tr_warn("neighbour creation fail"); - return; - } - // Safe the information - ws_bootstrap_candidate_parent_store(new_entry, data, ws_utt, ws_us, pan_information); - if (!new_entry->link_acceptable) { - // This entry is either poor quality or changed to poor quality link so we will remove this - // Todo in future possibility to try poor link parents if we have not found any good link parents - tr_info("neighbour not accepted: addr:%s panid:%x rsl:%d device_min_sens: %d", trace_array(new_entry->addr, 8), new_entry->pan_id, ws_neighbor_class_rsl_from_dbm_calculate(new_entry->signal_dbm), DEVICE_MIN_SENS); - ns_list_remove(&cur->ws_info->parent_list_reserved, new_entry); - ns_list_add_to_end(&cur->ws_info->parent_list_free, new_entry); - return; - } - // set to the correct place in list - ws_bootstrap_candidate_parent_sort(cur, new_entry); - - return; -} - -static void ws_bootstrap_pan_advertisement_analyse(struct protocol_interface_info_entry *cur, const struct mcps_data_ind_s *data, const struct mcps_data_ie_list *ie_ext, ws_utt_ie_t *ws_utt, ws_us_ie_t *ws_us) -{ - - //Validate Pan Conrfirmation is at packet - ws_pan_information_t pan_information; - if (!ws_wp_nested_pan_read(ie_ext->payloadIeList, ie_ext->payloadIeListLength, &pan_information)) { - // Corrupted - tr_error("No pan information"); - return; - } - - if (ws_us->excluded_channel_ctrl) { - //Validate that we can storage data - if (ws_us->excluded_channel_ctrl == WS_EXC_CHAN_CTRL_BITMASK && ws_us->excluded_channels.mask.mask_len_inline > 32) { - return; - } - } - - // Check pan flags so that it is valid - if (!pan_information.rpl_routing_method) { - // NOT RPL routing - //tr_warn("Not supported routing"); - return; - } - - // Store heard pans and possible candidate parents - ws_bootstrap_pan_information_store(cur, data, ws_utt, ws_us, &pan_information); - - if (!(ws_bootstrap_state_active(cur) || - ws_bootstrap_state_wait_rpl(cur))) { - // During discovery/eapol/config learn we dont do further processing for advertisements - return; - } - // Active state processing - //tr_debug("Advertisement active"); - - // In active operation less neighbours per pan is allowed - ws_bootstrap_candidate_list_clean(cur, WS_PARENT_LIST_MAX_PAN_IN_ACTIVE, protocol_core_monotonic_time, data->SrcPANId); - - // Check if valid PAN - if (data->SrcPANId != cur->ws_info->network_pan_id) { - return; - } - - // Save route cost for all known neighbors - llc_neighbour_req_t neighbor_info; - neighbor_info.neighbor = NULL; - if (ws_bootstrap_neighbor_info_request(cur, data->SrcAddr, &neighbor_info, false)) { - neighbor_info.ws_neighbor->routing_cost = pan_information.routing_cost; - } - - ws_bootstrap_pan_advertisement_analyse_active(cur, &pan_information); - - // Learn latest network information - if (cur->bootsrap_mode != ARM_NWK_BOOTSRAP_MODE_6LoWPAN_BORDER_ROUTER && neighbor_info.neighbor) { - uint8_t ll_address[16]; - ws_bootsrap_create_ll_address(ll_address, neighbor_info.neighbor->mac64); - - if (rpl_control_is_dodag_parent(cur, ll_address)) { - cur->ws_info->pan_information.pan_size = pan_information.pan_size; - cur->ws_info->pan_information.routing_cost = pan_information.routing_cost; - cur->ws_info->pan_information.rpl_routing_method = pan_information.rpl_routing_method; - cur->ws_info->pan_information.use_parent_bs = pan_information.use_parent_bs; - cur->ws_info->pan_information.version = pan_information.version; - } - } -} - -static void ws_bootstrap_pan_advertisement_solicit_analyse(struct protocol_interface_info_entry *cur, const struct mcps_data_ind_s *data, ws_utt_ie_t *ws_utt, ws_us_ie_t *ws_us) -{ - - (void)data; - (void)ws_utt; - (void)ws_us; - /* - * An inconsistent transmission is defined as: - * A PAN Advertisement Solicit with NETNAME-IE matching that of the receiving node. - */ - trickle_inconsistent_heard(&cur->ws_info->trickle_pan_advertisement, &cur->ws_info->trickle_params_pan_discovery); - /* - * A consistent transmission is defined as - * a PAN Advertisement Solicit with NETNAME-IE / Network Name matching that configured on the receiving node. - */ - trickle_consistent_heard(&cur->ws_info->trickle_pan_advertisement_solicit); - /* - * Optimized PAN discovery to select the parent faster if we hear solicit from someone else - */ - - if (ws_bootstrap_state_discovery(cur) && ws_cfg_network_config_get(cur) <= CONFIG_MEDIUM && - cur->bootsrap_state_machine_cnt > cur->ws_info->trickle_params_pan_discovery.Imin * 2) { - - cur->bootsrap_state_machine_cnt = cur->ws_info->trickle_params_pan_discovery.Imin + randLIB_get_random_in_range(0, cur->ws_info->trickle_params_pan_discovery.Imin); - - tr_info("Making parent selection in %u s", (cur->bootsrap_state_machine_cnt / 10)); - } - - if (ws_bootstrap_state_active(cur) && cur->bootsrap_mode != ARM_NWK_BOOTSRAP_MODE_6LoWPAN_BORDER_ROUTER) { - mac_neighbor_table_entry_t *neighbor = mac_neighbor_table_address_discover(mac_neighbor_info(cur), data->SrcAddr, ADDR_802_15_4_LONG); - if (neighbor && neighbor->link_role == PRIORITY_PARENT_NEIGHBOUR) { - ws_bootstrap_parent_confirm(cur, NULL); - } - } -} - - -static void ws_bootstrap_pan_config_analyse(struct protocol_interface_info_entry *cur, const struct mcps_data_ind_s *data, const struct mcps_data_ie_list *ie_ext, ws_utt_ie_t *ws_utt, ws_us_ie_t *ws_us) -{ - - uint16_t pan_version; - ws_bs_ie_t ws_bs_ie; - uint8_t *gtkhash_ptr; - - if (data->SrcPANId != cur->ws_info->network_pan_id) { - return; - } - ws_bt_ie_t ws_bt_ie; - if (!ws_wh_bt_read(ie_ext->headerIeList, ie_ext->headerIeListLength, &ws_bt_ie)) { - tr_warn("BT-IE"); - return; - } - - /* - * A consistent transmission is defined as a PAN Configuration with a PAN-ID matching that of the receiving node and - * a PANVER-IE / PAN Version greater than or equal to the receiving node’s current PAN version. - * - * A inconsistent transmission is defined as: - * - * A PAN Configuration with PAN-ID matching that of the receiving node and a - * PANVER-IE / PAN Version that is less than the receiving node’s current PAN version. - */ - - // TODO Add this to neighbor table - // TODO save all information from config message if version number has changed - - if (!ws_wp_nested_pan_version_read(ie_ext->payloadIeList, ie_ext->payloadIeListLength, &pan_version)) { - // Corrupted - tr_warn("no version"); - return; - } - - gtkhash_ptr = ws_wp_nested_gtkhash_read(ie_ext->payloadIeList, ie_ext->payloadIeListLength); - - if (!gtkhash_ptr) { - // Corrupted - tr_error("No gtk hash"); - return; - } - - if (!ws_wp_nested_bs_read(ie_ext->payloadIeList, ie_ext->payloadIeListLength, &ws_bs_ie)) { - // Corrupted - tr_error("No broadcast schedule"); - return; - } - - llc_neighbour_req_t neighbor_info; - bool neighbour_pointer_valid; - - //Validate BSI - if (cur->bootsrap_mode != ARM_NWK_BOOTSRAP_MODE_6LoWPAN_BORDER_ROUTER) { - - if (cur->ws_info->ws_bsi_block.block_time && cur->ws_info->ws_bsi_block.old_bsi == ws_bs_ie.broadcast_schedule_identifier) { - tr_debug("Do not accept a old BSI: %u in time %"PRIu32, cur->ws_info->ws_bsi_block.old_bsi, cur->ws_info->ws_bsi_block.block_time); - //Refresh Block time when hear a old BSI - cur->ws_info->ws_bsi_block.block_time = cur->ws_info->cfg->timing.pan_timeout; - return; - } - - //When Config is learned and USE Parent BS is enabled compare is this new BSI - if (cur->ws_info->configuration_learned && cur->ws_info->pan_information.use_parent_bs && ws_bs_ie.broadcast_schedule_identifier != cur->ws_info->hopping_schdule.fhss_bsi) { - //Accept only next possible BSI number - if ((cur->ws_info->hopping_schdule.fhss_bsi + 1) != ws_bs_ie.broadcast_schedule_identifier) { - tr_debug("Do not accept a unknown BSI: %u", ws_bs_ie.broadcast_schedule_identifier); - } else { - tr_debug("NEW Brodcast Schedule %u...BR rebooted", ws_bs_ie.broadcast_schedule_identifier); - cur->ws_info->ws_bsi_block.block_time = cur->ws_info->cfg->timing.pan_timeout; - cur->ws_info->ws_bsi_block.old_bsi = cur->ws_info->hopping_schdule.fhss_bsi; - ws_bootstrap_event_disconnect(cur, WS_NORMAL_DISCONNECT); - } - return; - } - } - - - if (cur->ws_info->configuration_learned || cur->bootsrap_mode == ARM_NWK_BOOTSRAP_MODE_6LoWPAN_BORDER_ROUTER) { - //If we are border router or learned configuration we only update already learned neighbours. - neighbour_pointer_valid = ws_bootstrap_neighbor_info_request(cur, data->SrcAddr, &neighbor_info, false); - - } else { - neighbour_pointer_valid = ws_bootstrap_neighbor_info_request(cur, data->SrcAddr, &neighbor_info, true); - if (!neighbour_pointer_valid) { - return; - } - ws_bootstrap_neighbor_set_stable(cur, data->SrcAddr); - } - - if (neighbour_pointer_valid) { - //Update Neighbor Broadcast and Unicast Parameters - ws_neighbor_class_neighbor_unicast_time_info_update(neighbor_info.ws_neighbor, ws_utt, data->timestamp, (uint8_t *) data->SrcAddr); - ws_neighbor_class_neighbor_unicast_schedule_set(neighbor_info.ws_neighbor, ws_us, &cur->ws_info->hopping_schdule); - ws_neighbor_class_neighbor_broadcast_time_info_update(neighbor_info.ws_neighbor, &ws_bt_ie, data->timestamp); - ws_neighbor_class_neighbor_broadcast_schedule_set(neighbor_info.ws_neighbor, &ws_bs_ie); - } - - if (cur->ws_info->configuration_learned) { - tr_info("PAN Config analyse own:%d, heard:%d", cur->ws_info->pan_information.pan_version, pan_version); - if (cur->ws_info->pan_information.pan_version == pan_version) { - //Check if Trgigle have been resetted in short time skip this then - if (cur->ws_info->trickle_pc_consistency_block_period == 0) { - // Same version heard so it is consistent - trickle_consistent_heard(&cur->ws_info->trickle_pan_config); - } - - if (neighbour_pointer_valid && neighbor_info.neighbor->link_role == PRIORITY_PARENT_NEIGHBOUR) { - ws_bootstrap_primary_parent_set(cur, &neighbor_info, WS_PARENT_SOFT_SYNCH); - } - // no need to process more - return; - } else { - // received version is different so we need to reset the trickle - trickle_inconsistent_heard(&cur->ws_info->trickle_pan_config, &cur->ws_info->trickle_params_pan_discovery); - if (neighbour_pointer_valid && neighbor_info.neighbor->link_role == PRIORITY_PARENT_NEIGHBOUR) { - ws_bootstrap_primary_parent_set(cur, &neighbor_info, WS_PARENT_HARD_SYNCH); - } - if (common_serial_number_greater_16(cur->ws_info->pan_information.pan_version, pan_version)) { - // older version heard ignoring the message - return; - } - cur->ws_info->trickle_pc_consistency_block_period = WS_CONFIG_CONSISTENT_FILTER_PERIOD; - } - } - - if (cur->bootsrap_mode == ARM_NWK_BOOTSRAP_MODE_6LoWPAN_BORDER_ROUTER) { - //Border router does not learn network information - return; - } - - /* - * Learn new information from neighbor - */ - tr_info("Updated PAN configuration own:%d, heard:%d", cur->ws_info->pan_information.pan_version, pan_version); - - // restart PAN version timer - //Check Here Do we have a selected Primary parent - if (!cur->ws_info->configuration_learned || cur->ws_info->rpl_state == RPL_EVENT_DAO_DONE) { - ws_common_border_router_alive_update(cur); - } - - cur->ws_info->pan_information.pan_version = pan_version; - - ws_pae_controller_gtk_hash_update(cur, gtkhash_ptr); - - ws_pae_controller_nw_key_index_update(cur, data->Key.KeyIndex - 1); - - if (!cur->ws_info->configuration_learned) { - // Generate own hopping schedules Follow first parent broadcast and plans and also use same unicast dwell - tr_info("learn network configuration"); - cur->ws_info->configuration_learned = true; - // return to state machine after 1-2 s - cur->bootsrap_state_machine_cnt = randLIB_get_random_in_range(10, 20); - // enable frequency hopping for unicast channel and start listening first neighbour - ws_bootstrap_primary_parent_set(cur, &neighbor_info, WS_PARENT_HARD_SYNCH); - // set neighbor as priority parent clear if there is others - protocol_6lowpan_neighbor_priority_clear_all(cur->id, PRIORITY_1ST); - neighbor_info.neighbor->link_role = PRIORITY_PARENT_NEIGHBOUR; - } -} - -static void ws_bootstrap_pan_config_solicit_analyse(struct protocol_interface_info_entry *cur, const struct mcps_data_ind_s *data, ws_utt_ie_t *ws_utt, ws_us_ie_t *ws_us) -{ - if (data->SrcPANId != cur->ws_info->network_pan_id) { - return; - } - - /* TODO smart neighbour process - * - * Unsecure packet we cant trust the device? - * - * Question mark in specification also present, now we create neighbour. - * this is moved in future to NS/ND processing triggered by RPL - * - */ - - llc_neighbour_req_t neighbor_info; - if (ws_bootstrap_neighbor_info_request(cur, data->SrcAddr, &neighbor_info, false)) { - ws_neighbor_class_neighbor_unicast_time_info_update(neighbor_info.ws_neighbor, ws_utt, data->timestamp, (uint8_t *) data->SrcAddr); - ws_neighbor_class_neighbor_unicast_schedule_set(neighbor_info.ws_neighbor, ws_us, &cur->ws_info->hopping_schdule); - } - - if (ws_bootstrap_state_active(cur) && cur->bootsrap_mode != ARM_NWK_BOOTSRAP_MODE_6LoWPAN_BORDER_ROUTER) { - mac_neighbor_table_entry_t *neighbor = mac_neighbor_table_address_discover(mac_neighbor_info(cur), data->SrcAddr, ADDR_802_15_4_LONG); - if (neighbor && neighbor->link_role == PRIORITY_PARENT_NEIGHBOUR) { - ws_bootstrap_parent_confirm(cur, NULL); - } - } - - /* - * A consistent transmission is defined as a PAN Configuration Solicit with - * a PAN-ID matching that of the receiving node and a NETNAME-IE / Network Name - * matching that configured on the receiving node. - */ - trickle_consistent_heard(&cur->ws_info->trickle_pan_config_solicit); - /* - * inconsistent transmission is defined as either: - * A PAN Configuration Solicit with a PAN-ID matching that of the receiving node and - * a NETNAME-IE / Network Name matching the network name configured on the receiving - */ - trickle_inconsistent_heard(&cur->ws_info->trickle_pan_config, &cur->ws_info->trickle_params_pan_discovery); -} static bool ws_channel_plan_zero_compare(ws_channel_plan_zero_t *rx_plan, ws_hopping_schedule_t *hopping_schdule) { if (rx_plan->operation_class != hopping_schdule->operating_class) { @@ -1926,6 +1334,16 @@ static bool ws_channel_plan_one_compare(ws_channel_plan_one_t *rx_plan, ws_hoppi return true; } +static bool ws_channel_plan_two_compare(ws_channel_plan_two_t *rx_plan, ws_hopping_schedule_t *hopping_schdule) +{ + if (rx_plan->channel_plan_id != hopping_schdule->channel_plan_id) { + return false; + } else if (rx_plan->regulator_domain != hopping_schdule->regulatory_domain) { + return false; + } + return true; +} + bool ws_bootstrap_validate_channel_plan(ws_us_ie_t *ws_us, struct protocol_interface_info_entry *cur) { if (ws_us->channel_plan == 0) { @@ -1936,6 +1354,15 @@ bool ws_bootstrap_validate_channel_plan(ws_us_ie_t *ws_us, struct protocol_inter if (!ws_channel_plan_one_compare(&ws_us->plan.one, &cur->ws_info->hopping_schdule)) { return false; } + } else if (ws_us->channel_plan == 2) { + if (!ws_version_1_1(cur)) { + return false; + } + if (!ws_channel_plan_two_compare(&ws_us->plan.two, &cur->ws_info->hopping_schdule)) { + return false; + } + } else { + return false; } return true; @@ -1962,92 +1389,6 @@ bool ws_bootstrap_validate_channel_function(ws_us_ie_t *ws_us, ws_bs_ie_t *ws_bs return true; } -static void ws_bootstrap_asynch_ind(struct protocol_interface_info_entry *cur, const struct mcps_data_ind_s *data, const struct mcps_data_ie_list *ie_ext, uint8_t message_type) -{ - // Store weakest heard packet RSSI - if (cur->ws_info->weakest_received_rssi > data->signal_dbm) { - cur->ws_info->weakest_received_rssi = data->signal_dbm; - } - - if (data->SrcAddrMode != MAC_ADDR_MODE_64_BIT) { - // Not from long address - return; - } - ws_stats_update(cur, STATS_WS_ASYNCH_RX, 1); - //Validate network name - switch (message_type) { - case WS_FT_PAN_ADVERT: - case WS_FT_PAN_ADVERT_SOL: - case WS_FT_PAN_CONF_SOL: - //Check Network Name - if (!ws_bootstrap_network_name_matches(ie_ext, cur->ws_info->cfg->gen.network_name)) { - // Not in our network - return; - } - break; - case WS_FT_PAN_CONF: - break; - default: - return; - } - //UTT-IE and US-IE are mandatory for all Asynch Messages - ws_utt_ie_t ws_utt; - if (!ws_wh_utt_read(ie_ext->headerIeList, ie_ext->headerIeListLength, &ws_utt)) { - // Corrupted - return; - } - - ws_us_ie_t ws_us; - if (!ws_wp_nested_us_read(ie_ext->payloadIeList, ie_ext->payloadIeListLength, &ws_us)) { - // Corrupted - return; - } - - if (!ws_bootstrap_validate_channel_plan(&ws_us, cur) || - !ws_bootstrap_validate_channel_function(&ws_us, NULL)) { - return; - } - - //Handle Message's - switch (message_type) { - case WS_FT_PAN_ADVERT: - // Analyse Advertisement - ws_stats_update(cur, STATS_WS_ASYNCH_RX_PA, 1); - tr_info("received ADVERT Src:%s panid:%x rssi:%d", trace_array(data->SrcAddr, 8), data->SrcPANId, data->signal_dbm); - ws_bootstrap_pan_advertisement_analyse(cur, data, ie_ext, &ws_utt, &ws_us); - break; - case WS_FT_PAN_ADVERT_SOL: - ws_stats_update(cur, STATS_WS_ASYNCH_RX_PAS, 1); - tr_info("received ADVERT SOL Src:%s rssi:%d", trace_array(data->SrcAddr, 8), data->signal_dbm); - ws_bootstrap_pan_advertisement_solicit_analyse(cur, data, &ws_utt, &ws_us); - break; - case WS_FT_PAN_CONF: - ws_stats_update(cur, STATS_WS_ASYNCH_RX_PC, 1); - tr_info("received CONFIG Src:%s rssi:%d", trace_array(data->SrcAddr, 8), data->signal_dbm); - ws_bootstrap_pan_config_analyse(cur, data, ie_ext, &ws_utt, &ws_us); - break; - case WS_FT_PAN_CONF_SOL: - ws_stats_update(cur, STATS_WS_ASYNCH_RX_PCS, 1); - tr_info("received CONFIG SOL Src:%s rssi:%d", trace_array(data->SrcAddr, 8), data->signal_dbm); - ws_bootstrap_pan_config_solicit_analyse(cur, data, &ws_utt, &ws_us); - default: - // Unknown message do not process - break; - } -} - -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); - 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) { uint32_t time_from_last_unicast_shedule = current_time_stamp; @@ -2141,7 +1482,7 @@ static void ws_bootstrap_neighbor_table_clean(struct protocol_interface_info_ent } -static bool ws_bootstrap_neighbor_info_request(struct protocol_interface_info_entry *interface, const uint8_t *mac_64, llc_neighbour_req_t *neighbor_buffer, bool request_new) +bool ws_bootstrap_neighbor_info_request(struct protocol_interface_info_entry *interface, const uint8_t *mac_64, llc_neighbour_req_t *neighbor_buffer, bool request_new) { neighbor_buffer->ws_neighbor = NULL; neighbor_buffer->neighbor = mac_neighbor_table_address_discover(mac_neighbor_info(interface), mac_64, ADDR_802_15_4_LONG); @@ -2234,7 +1575,7 @@ static bool ws_neighbor_entry_nud_notify(mac_neighbor_table_entry_t *entry_ptr, return false; } - ws_bootsrap_create_ll_address(ll_address, entry_ptr->mac64); + ws_common_create_ll_address(ll_address, entry_ptr->mac64); if (time_from_start > WS_NEIGHBOR_NUD_TIMEOUT) { @@ -2280,7 +1621,7 @@ static bool ws_neighbor_entry_nud_notify(mac_neighbor_table_entry_t *entry_ptr, //ETX Sample 1: random 2-16 //ETX Sample 2: random 4-32 - ws_bootsrap_create_ll_address(ll_address, entry_ptr->mac64); + ws_common_create_ll_address(ll_address, entry_ptr->mac64); if (!rpl_control_probe_parent_candidate(cur, ll_address)) { return false; } @@ -2394,7 +1735,22 @@ int ws_bootstrap_init(int8_t interface_id, net_6lowpan_mode_e bootstrap_mode) goto init_fail; } - ws_llc_create(cur, &ws_bootstrap_asynch_ind, &ws_bootstrap_asynch_confirm, &ws_bootstrap_neighbor_info_request); + if (wisun_mode_host(cur)) { + // Configure for LFN device +#if defined(HAVE_WS) && defined(HAVE_WS_HOST) + ws_llc_create(cur, &ws_bootstrap_lfn_asynch_ind, &ws_bootstrap_lfn_asynch_confirm, &ws_bootstrap_neighbor_info_request); +#endif + } else if (wisun_mode_router(cur)) { + // Configure FFN device +#if defined(HAVE_WS) && defined(HAVE_WS_ROUTER) + ws_llc_create(cur, &ws_bootstrap_ffn_asynch_ind, &ws_bootstrap_ffn_asynch_confirm, &ws_bootstrap_neighbor_info_request); +#endif + } else if (wisun_mode_border_router(cur)) { + // Configure as Border router +#if defined(HAVE_WS) && defined(HAVE_WS_BORDER_ROUTER) + ws_llc_create(cur, &ws_bootstrap_6lbr_asynch_ind, &ws_bootstrap_6lbr_asynch_confirm, &ws_bootstrap_neighbor_info_request); +#endif + } mpx_api_t *mpx_api = ws_llc_mpx_api_get(cur); if (!mpx_api) { @@ -2515,7 +1871,45 @@ int ws_bootstrap_restart_delayed(int8_t interface_id) return 0; } -int ws_bootstrap_set_rf_config(protocol_interface_info_entry_t *cur, phy_rf_channel_configuration_s rf_configs) +static int8_t ws_bootstrap_phy_mode_resolver(const mac_api_t *api, uint8_t phy_mode_id, phy_rf_channel_configuration_s *rf_config) +{ + rf_config->modulation = ws_phy_get_modulation_using_phy_mode_id(phy_mode_id); + if (rf_config->modulation == M_UNDEFINED) { + return -1; + } + protocol_interface_info_entry_t *interface = protocol_stack_interface_info_get_by_id(api->parent_id); + if (!interface) { + return -1; + } + uint8_t regulatory_domain = interface->ws_info->hopping_schdule.regulatory_domain; + uint8_t base_channel_plan_id = interface->ws_info->hopping_schdule.channel_plan_id; + if (base_channel_plan_id == 255) { + base_channel_plan_id = ws_phy_convert_operating_class_to_channel_plan_id(interface->ws_info->hopping_schdule.operating_class, regulatory_domain); + } + if (!base_channel_plan_id) { + return -1; + } + // Function returns base channel plan ID, if it matches the PHY mode ID. Otherwise, nearest matching channel plan ID where PHY mode ID is allowed will be returned. + uint8_t channel_plan_id = ws_phy_get_channel_plan_id_using_phy_mode_id(phy_mode_id, regulatory_domain, base_channel_plan_id); + if (!channel_plan_id) { + return -1; + } + + rf_config->channel_0_center_frequency = ws_phy_get_channel_0_frequency_using_channel_plan_id(channel_plan_id); + rf_config->channel_spacing = ws_phy_get_channel_spacing_using_channel_plan_id(channel_plan_id); + rf_config->number_of_channels = ws_phy_get_number_of_channels_using_channel_plan_id(channel_plan_id); + rf_config->datarate = ws_phy_get_datarate_using_phy_mode_id(phy_mode_id); + if (!rf_config->channel_0_center_frequency || !rf_config->channel_spacing || !rf_config->number_of_channels || !rf_config->datarate) { + return -1; + } + rf_config->ofdm_option = ws_phy_get_ofdm_option_using_phy_mode_id(phy_mode_id); + rf_config->ofdm_mcs = ws_phy_get_ofdm_mcs_using_phy_mode_id(phy_mode_id); + rf_config->fec = ws_phy_get_fsk_fec_enabled_using_phy_mode_id(phy_mode_id); + rf_config->modulation_index = ws_phy_get_modulation_index_using_phy_mode_id(phy_mode_id); + return 0; +} + +static int ws_bootstrap_set_rf_config(protocol_interface_info_entry_t *cur, phy_rf_channel_configuration_s rf_configs) { mlme_set_t set_request; // Set MAC mode @@ -2547,6 +1941,16 @@ int ws_bootstrap_set_rf_config(protocol_interface_info_entry_t *cur, phy_rf_chan cur->mac_api->mlme_req(cur->mac_api, MLME_SET, &set_request); // Start automatic CCA threshold mac_helper_start_auto_cca_threshold(cur->id, cur->ws_info->hopping_schdule.number_of_channels, CCA_DEFAULT_DBM, CCA_HIGH_LIMIT, CCA_LOW_LIMIT); + // Enable MAC mode switch when base PHY mode ID could be found, otherwise disable the feature + uint8_t phy_mode_id = cur->ws_info->hopping_schdule.phy_mode_id; + if (phy_mode_id == 255) { + phy_mode_id = ws_phy_convert_operating_mode_to_phy_mode_id(cur->ws_info->hopping_schdule.operating_mode); + } + if (!phy_mode_id) { + cur->mac_api->mac_mode_switch_resolver_set(cur->mac_api, NULL, phy_mode_id); + } else { + cur->mac_api->mac_mode_switch_resolver_set(cur->mac_api, &ws_bootstrap_phy_mode_resolver, phy_mode_id); + } return 0; } @@ -2567,35 +1971,35 @@ int ws_bootstrap_aro_failure(protocol_interface_info_entry_t *cur, const uint8_t return 0; } -static int ws_bootstrap_set_domain_rf_config(protocol_interface_info_entry_t *cur) +static int ws_bootstrap_operating_mode_resolver(protocol_interface_info_entry_t *cur, phy_rf_channel_configuration_s *rf_config) { - phy_rf_channel_configuration_s rf_configs; - memset(&rf_configs, 0, sizeof(phy_rf_channel_configuration_s)); + memset(rf_config, 0, sizeof(phy_rf_channel_configuration_s)); + rf_config->fec = false; + rf_config->modulation = M_2FSK; + rf_config->datarate = ws_phy_get_datarate_using_operating_mode(cur->ws_info->hopping_schdule.operating_mode); + rf_config->modulation_index = ws_phy_get_modulation_index_using_operating_mode(cur->ws_info->hopping_schdule.operating_mode); + rf_config->channel_0_center_frequency = (uint32_t)cur->ws_info->hopping_schdule.ch0_freq * 100000; + rf_config->channel_spacing = ws_phy_decode_channel_spacing(cur->ws_info->hopping_schdule.channel_spacing); + rf_config->number_of_channels = cur->ws_info->hopping_schdule.number_of_channels; + return 0; +} + +int ws_bootstrap_set_domain_rf_config(protocol_interface_info_entry_t *cur) +{ + phy_rf_channel_configuration_s rf_config; + memset(&rf_config, 0, sizeof(phy_rf_channel_configuration_s)); uint8_t phy_mode_id = cur->ws_info->hopping_schdule.phy_mode_id; - if (((phy_mode_id >= 34) && (phy_mode_id <= 38)) || - ((phy_mode_id >= 51) && (phy_mode_id <= 54)) || - ((phy_mode_id >= 68) && (phy_mode_id <= 70)) || - ((phy_mode_id >= 84) && (phy_mode_id <= 86))) { - rf_configs.modulation = M_OFDM; - rf_configs.datarate = ws_get_datarate_using_phy_mode_id(cur->ws_info->hopping_schdule.phy_mode_id); - rf_configs.ofdm_option = ws_get_ofdm_option_using_phy_mode_id(cur->ws_info->hopping_schdule.phy_mode_id); - rf_configs.ofdm_mcs = ws_get_ofdm_mcs_using_phy_mode_id(cur->ws_info->hopping_schdule.phy_mode_id); - } else { - if ((phy_mode_id >= 17) && (phy_mode_id <= 24)) { - rf_configs.fec = true; - } else { - rf_configs.fec = false; - } - rf_configs.modulation = M_2FSK; - rf_configs.datarate = ws_get_datarate_using_operating_mode(cur->ws_info->hopping_schdule.operating_mode); - rf_configs.modulation_index = ws_get_modulation_index_using_operating_mode(cur->ws_info->hopping_schdule.operating_mode); + if (phy_mode_id == 255) { + phy_mode_id = ws_phy_convert_operating_mode_to_phy_mode_id(cur->ws_info->hopping_schdule.operating_mode); } - rf_configs.channel_0_center_frequency = (uint32_t)cur->ws_info->hopping_schdule.ch0_freq * 100000; - rf_configs.channel_spacing = ws_decode_channel_spacing(cur->ws_info->hopping_schdule.channel_spacing); - rf_configs.number_of_channels = cur->ws_info->hopping_schdule.number_of_channels; - ws_bootstrap_set_rf_config(cur, rf_configs); + if (!phy_mode_id || ws_bootstrap_phy_mode_resolver(cur->mac_api, phy_mode_id, &rf_config)) { + // Cannot resolve RF configuration using PHY mode ID, try with operating mode + ws_bootstrap_operating_mode_resolver(cur, &rf_config); + } + + ws_bootstrap_set_rf_config(cur, rf_config); return 0; } @@ -2618,10 +2022,10 @@ static void ws_bootstrap_mac_activate(protocol_interface_info_entry_t *cur, uint } } -static void ws_bootstrap_fhss_activate(protocol_interface_info_entry_t *cur) +void ws_bootstrap_fhss_activate(protocol_interface_info_entry_t *cur) { tr_debug("FHSS activate"); - ws_fhss_enable(cur); + ws_bootstrap_fhss_enable(cur); ws_llc_hopping_schedule_config(cur, &cur->ws_info->hopping_schdule); // Only supporting fixed channel @@ -2633,32 +2037,7 @@ static void ws_bootstrap_fhss_activate(protocol_interface_info_entry_t *cur) return; } -static void ws_bootstrap_network_configuration_learn(protocol_interface_info_entry_t *cur) -{ - tr_debug("Start using PAN configuration"); - - // Timing information can be modified here - ws_llc_set_pan_information_pointer(cur, &cur->ws_info->pan_information); - uint8_t *gtkhash = ws_pae_controller_gtk_hash_ptr_get(cur); - ws_llc_set_gtkhash(cur, gtkhash); - // TODO update own fhss schedules we are starting to follow first parent - - return; -} - -static void ws_bootstrap_ip_stack_addr_clear(protocol_interface_info_entry_t *cur) -{ - tr_debug("ip stack address clear"); - ns_list_foreach_safe(if_address_entry_t, addr, &cur->ip_addresses) { - if (addr->source != ADDR_SOURCE_STATIC && - addr_ipv6_scope(addr->address, cur) > IPV6_SCOPE_LINK_LOCAL) { - // Remove all exept User set address - addr_delete_entry(cur, addr); - } - } -} - -static void ws_bootstrap_ip_stack_reset(protocol_interface_info_entry_t *cur) +void ws_bootstrap_ip_stack_reset(protocol_interface_info_entry_t *cur) { tr_debug("ip stack reset"); // Delete all temporary cached information @@ -2666,7 +2045,7 @@ static void ws_bootstrap_ip_stack_reset(protocol_interface_info_entry_t *cur) lowpan_context_list_free(&cur->lowpan_contexts); } -static void ws_bootstrap_ip_stack_activate(protocol_interface_info_entry_t *cur) +void ws_bootstrap_ip_stack_activate(protocol_interface_info_entry_t *cur) { tr_debug("ip stack init"); clear_power_state(ICMP_ACTIVE); @@ -2674,7 +2053,7 @@ static void ws_bootstrap_ip_stack_activate(protocol_interface_info_entry_t *cur) ws_bootstrap_ip_stack_reset(cur); } -static void ws_set_fhss_hop(protocol_interface_info_entry_t *cur) +static void ws_bootstrap_set_fhss_hop(protocol_interface_info_entry_t *cur) { uint16_t own_rank = ws_bootstrap_rank_get(cur); uint16_t rank_inc = ws_bootstrap_min_rank_inc_get(cur); @@ -2694,7 +2073,172 @@ static void ws_set_fhss_hop(protocol_interface_info_entry_t *cur) tr_debug("own hop: %u, own rank: %u, rank inc: %u", own_hop, own_rank, rank_inc); } -static void ws_address_registration_update(protocol_interface_info_entry_t *interface, const uint8_t addr[16]) +static void ws_bootstrap_dhcp_neighbour_update_cb(int8_t interface_id, uint8_t ll_addr[static 16]) +{ + if (memcmp(ll_addr, ADDR_LINK_LOCAL_PREFIX, 8)) { + return; + } + + protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(interface_id); + if (!cur) { + return; + } + + uint8_t mac64[8]; + memcpy(mac64, ll_addr + 8, 8); + mac64[0] ^= 2; + ws_bootstrap_mac_neighbor_short_time_set(cur, mac64, WS_NEIGHBOUR_DHCP_ENTRY_LIFETIME); +} + +static void ws_bootstrap_dhcp_info_notify_cb(int8_t interface, dhcp_option_notify_t *options, dhcp_server_notify_info_t *server_info) +{ + protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(interface); + if (!cur) { + return; + } + uint8_t server_ll64[16]; + memcpy(server_ll64, ADDR_LINK_LOCAL_PREFIX, 8); + + if (server_info->duid_length == 8) { + memcpy(server_ll64 + 8, server_info->duid, 8); + } else { + server_ll64[8] = server_info->duid[0]; + server_ll64[9] = server_info->duid[1]; + server_ll64[10] = server_info->duid[2]; + server_ll64[11] = 0xff; + server_ll64[12] = 0xfe; + server_ll64[13] = server_info->duid[3]; + server_ll64[14] = server_info->duid[4]; + server_ll64[15] = server_info->duid[5]; + } + server_ll64[8] ^= 2; + + switch (options->option_type) { + case DHCPV6_OPTION_VENDOR_SPECIFIC_INFO: + if (options->option.vendor_spesific.enterprise_number != ARM_ENTERPRISE_NUMBER) { + break; + } + while (options->option.vendor_spesific.data_length) { + uint16_t option_type; + char *domain; + uint8_t *address; + uint16_t option_len; + option_len = net_dns_option_vendor_option_data_get_next(options->option.vendor_spesific.data, options->option.vendor_spesific.data_length, &option_type); + tr_debug("DHCP vendor specific data type:%u length %d", option_type, option_len); + //tr_debug("DHCP vendor specific data %s", trace_array(options->option.vendor_spesific.data, options->option.vendor_spesific.data_length)); + + if (option_len == 0) { + // Option fields were corrupted + break; + } + if (option_type == ARM_DHCP_VENDOR_DATA_DNS_QUERY_RESULT) { + // Process ARM DNS query result + domain = NULL; + address = NULL; + if (net_dns_option_vendor_option_data_dns_query_read(options->option.vendor_spesific.data, options->option.vendor_spesific.data_length, &address, &domain) > 0 || + domain || address) { + // Valid ARM DNS query entry + net_dns_query_result_set(interface, address, domain, server_info->life_time); + } + } + if (option_type == ARM_DHCP_VENDOR_DATA_TIME_CONFIGURATION) { + timezone_info_t time_configuration; + if (net_vendor_option_time_configuration_read(options->option.vendor_spesific.data, options->option.vendor_spesific.data_length, &time_configuration.timestamp, &time_configuration.timezone, &time_configuration.deviation, &time_configuration.status)) { + int ret = ns_time_system_timezone_info_notify(&time_configuration); + tr_info("Network Time configuration %s status:%"PRIu16" time stamp: %"PRIu64" deviation: %"PRId16" Time Zone: %"PRId16, ret == 0 ? "notified" : "notify FAILED", time_configuration.status, time_configuration.timestamp, time_configuration.deviation, time_configuration.timezone); + } + } + if (option_type == ARM_DHCP_VENDOR_DATA_NETWORK_TIME) { + // Process ARM Network Time + // Get Current time + // Get Round trip time of the DHCP request + // Estimated error is elapsed time of request + // If current time difference is larger than estimated error update current time + // set the time for server time + *.5 RTT + int32_t era; + uint32_t offset; + if (net_vendor_option_current_time_read(options->option.vendor_spesific.data, options->option.vendor_spesific.data_length, &era, &offset, NULL)) { + uint64_t current_time; + uint64_t network_time = (era * (uint64_t)(4294967296)) + offset - 2208988800; //Convert to First day of Unix (1 Jan 1970) + + tr_debug("Network Time option Era:%"PRId32" Offset:%"PRIu32" rtt: %"PRId32" time: %"PRIu64, era, offset, server_info->rtt, network_time); + if (0 == ns_time_system_time_read(¤t_time)) { + uint64_t difference; + // We only adjust clock if time has drifted more than 10 seconds to avoid constant changing of time + // If Round trip time is very high the accuracy is reduced. + uint32_t estimated_error = 10 + server_info->rtt / 10; + // Take into account the round trip time it took the response to arrive from the time server Write the time. + network_time += server_info->rtt / 20; + + if (current_time > network_time) { + difference = current_time - network_time; + } else { + difference = network_time - current_time; + } + if (difference > estimated_error) { + // Larger than 10 second difference update the time + int ret = ns_time_system_time_write(network_time); + tr_info("Network Time %s: Era:%"PRId32" Offset:%"PRIu32" old time: %"PRIu64" time: %"PRIu64, ret == 0 ? "updated" : "update FAILED", era, offset, current_time, network_time); + } + // System time has been acquired + ns_time_system_time_acquired_set(); + } + } + } + + options->option.vendor_spesific.data_length -= option_len; + options->option.vendor_spesific.data += option_len; + } + break; + + case DHCPV6_OPTION_DNS_SERVERS: + while (options->option.generic.data_length && options->option.generic.data_length >= 16 && options->option.generic.data_length % 16 == 0) { + // Validate payload to have full 16 byte length addresses without any extra bytes + net_dns_server_address_set(interface, server_ll64, options->option.generic.data, server_info->life_time); + options->option.generic.data_length -= 16; + options->option.generic.data += 16; + } + break; + case DHCPV6_OPTION_DOMAIN_LIST: + net_dns_server_search_list_set(interface, server_ll64, options->option.generic.data, options->option.generic.data_length, server_info->life_time); + break; + default: + break; + } + +} + +static void ws_dhcp_client_global_adress_cb(int8_t interface, uint8_t dhcp_addr[static 16], uint8_t prefix[static 16], bool register_status) +{ + (void)prefix; + (void)interface; + //TODO add handler for negative status + tr_debug("DHCPv6 %s status %u with link %s", trace_ipv6(prefix), register_status, trace_ipv6(dhcp_addr)); + if (register_status) { + protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(interface); + if (cur) { + ws_address_reregister_trig(cur); + } + } else { + //Delete dhcpv6 client + dhcp_client_global_address_delete(interface, dhcp_addr, prefix); + } +} + + +void ws_dhcp_client_address_request(protocol_interface_info_entry_t *cur, uint8_t *prefix, uint8_t *parent_link_local) +{ + if (dhcp_client_get_global_address(cur->id, parent_link_local, prefix, ws_dhcp_client_global_adress_cb) != 0) { + tr_error("DHCPp client request fail"); + } +} + +void ws_dhcp_client_address_delete(protocol_interface_info_entry_t *cur, uint8_t *prefix) +{ + dhcp_client_global_address_delete(cur->id, NULL, prefix); +} + +void ws_address_registration_update(protocol_interface_info_entry_t *interface, const uint8_t addr[16]) { rpl_control_register_address(interface, addr); // Timer is used only to track full registrations @@ -2723,7 +2267,7 @@ static void ws_address_parent_update(protocol_interface_info_entry_t *interface) ws_address_registration_update(interface, NULL); } -static void ws_bootstrap_parent_confirm(protocol_interface_info_entry_t *cur, struct rpl_instance *instance) +void ws_bootstrap_parent_confirm(protocol_interface_info_entry_t *cur, struct rpl_instance *instance) { /* Possible problem with the parent connection * Give some time for parent to rejoin and confirm the connection with ARO and DAO @@ -2831,7 +2375,7 @@ static void ws_bootstrap_rpl_callback(rpl_event_t event, void *handle) ws_bootstrap_advertise_start(cur); } - ws_set_fhss_hop(cur); + ws_bootstrap_set_fhss_hop(cur); // Set retry configuration for bootstrap ready state ws_bootstrap_configure_max_retries(cur, WS_MAX_FRAME_RETRIES); // Set TX failure request restart configuration @@ -2853,7 +2397,7 @@ static void ws_bootstrap_rpl_callback(rpl_event_t event, void *handle) if (ws_bootstrap_state_active(cur)) { tr_info("Move state 4 to wait parent connection confirmation"); ws_bootstrap_rpl_scan_start(cur); - ws_nwk_event_post(cur, ARM_NWK_NWK_CONNECTION_DOWN); + ws_bootstrap_network_down(cur); } } else if (event == RPL_EVENT_DAO_PARENT_ADD) { ws_address_parent_update(cur); @@ -2862,36 +2406,6 @@ static void ws_bootstrap_rpl_callback(rpl_event_t event, void *handle) tr_info("RPL event %d", event); } -static void ws_dhcp_client_global_adress_cb(int8_t interface, uint8_t dhcp_addr[static 16], uint8_t prefix[static 16], bool register_status) -{ - (void)prefix; - (void)interface; - //TODO add handler for negative status - tr_debug("DHCPv6 %s status %u with link %s", trace_ipv6(prefix), register_status, trace_ipv6(dhcp_addr)); - if (register_status) { - protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(interface); - if (cur) { - ws_address_reregister_trig(cur); - } - } else { - //Delete dhcpv6 client - dhcp_client_global_address_delete(interface, dhcp_addr, prefix); - } -} - - -void ws_dhcp_client_address_request(protocol_interface_info_entry_t *cur, uint8_t *prefix, uint8_t *parent_link_local) -{ - if (dhcp_client_get_global_address(cur->id, parent_link_local, prefix, ws_dhcp_client_global_adress_cb) != 0) { - tr_error("DHCPp client request fail"); - } -} - -void ws_dhcp_client_address_delete(protocol_interface_info_entry_t *cur, uint8_t *prefix) -{ - dhcp_client_global_address_delete(cur->id, NULL, prefix); -} - bool ws_eapol_relay_state_active(protocol_interface_info_entry_t *cur) { if (cur->bootsrap_mode == ARM_NWK_BOOTSRAP_MODE_6LoWPAN_BORDER_ROUTER || cur->nwk_bootstrap_state == ER_BOOTSRAP_DONE) { @@ -3060,8 +2574,86 @@ neigh_create_ok: #endif return create_ok; } +static uint16_t ws_bootstrap_routing_cost_calculate(protocol_interface_info_entry_t *cur) +{ + mac_neighbor_table_entry_t *mac_neighbor = mac_neighbor_entry_get_priority(mac_neighbor_info(cur)); + if (!mac_neighbor) { + return 0xffff; + } + ws_neighbor_class_entry_t *ws_neighbor = ws_neighbor_class_entry_get(&cur->ws_info->neighbor_storage, mac_neighbor->index); + if (!ws_neighbor) { + return 0xffff; + } -static void ws_bootstrap_rpl_activate(protocol_interface_info_entry_t *cur) + uint16_t etx = ws_local_etx_read(cur, ADDR_802_15_4_LONG, mac_neighbor->mac64); + if (etx == 0) { + etx = WS_ETX_MAX; //SET maximum value here if ETX is unknown + } else { + //Scale to 128 based ETX (local read return 0x100 - 0xffff + etx = etx >> 1; + } + // Make the 0xffff as maximum value + if (ws_neighbor->routing_cost + etx > 0xffff) { + return 0xffff; + } + + return ws_neighbor->routing_cost + etx; +} + +static struct rpl_instance *ws_bootstrap_get_rpl_instance(protocol_interface_info_entry_t *cur) +{ + if (!cur || !cur->rpl_domain) { + return NULL; + } + struct rpl_instance *best_instance = NULL; + ns_list_foreach(struct rpl_instance, instance, &cur->rpl_domain->instances) { + best_instance = instance; + // Select best grounded and lowest rank? But there should be only one really + } + return best_instance; +} + +static uint16_t ws_bootstrap_rank_get(protocol_interface_info_entry_t *cur) +{ + struct rpl_instance *rpl_instance = ws_bootstrap_get_rpl_instance(cur); + if (!rpl_instance) { + return 0xffff; + } + return rpl_control_current_rank(rpl_instance); +} + + +static uint16_t ws_bootstrap_min_rank_inc_get(protocol_interface_info_entry_t *cur) +{ + struct rpl_instance *rpl_instance = ws_bootstrap_get_rpl_instance(cur); + if (!rpl_instance) { + return 0xffff; + } + struct rpl_dodag_info_t dodag_info; + if (!rpl_control_read_dodag_info(rpl_instance, &dodag_info)) { + return 0xffff; + } + return dodag_info.dag_min_hop_rank_inc; +} + +void ws_bootstrap_rpl_scan_start(protocol_interface_info_entry_t *cur) +{ + tr_debug("Start RPL learn"); + // Stop Trickle timers + ws_bootstrap_asynch_trickle_stop(cur); + + // routers wait until RPL root is contacted + ws_bootstrap_state_change(cur, ER_RPL_SCAN); + // Change state as the state is checked in state machine + cur->ws_info->rpl_state = RPL_EVENT_LOCAL_REPAIR_START; + //For Large network and medium should do passive scan + if (ws_cfg_network_config_get(cur) > CONFIG_SMALL) { + // Set timeout for check to 30 - 60 seconds + cur->bootsrap_state_machine_cnt = randLIB_get_random_in_range(WS_RPL_DIS_INITIAL_TIMEOUT / 2, WS_RPL_DIS_INITIAL_TIMEOUT); + } +} + +void ws_bootstrap_rpl_activate(protocol_interface_info_entry_t *cur) { tr_debug("RPL Activate"); bool downstream = true; @@ -3094,28 +2686,14 @@ static void ws_bootstrap_rpl_activate(protocol_interface_info_entry_t *cur) cur->ws_info->rpl_state = 0xff; // Set invalid state and learn from event } -static void ws_bootstrap_network_start(protocol_interface_info_entry_t *cur) +void ws_bootstrap_network_start(protocol_interface_info_entry_t *cur) { //Set Network names, Pan information configure, hopping schedule & GTKHash ws_llc_set_network_name(cur, (uint8_t *)cur->ws_info->cfg->gen.network_name, strlen(cur->ws_info->cfg->gen.network_name)); ws_llc_set_pan_information_pointer(cur, &cur->ws_info->pan_information); } -static void ws_bootstrap_network_discovery_configure(protocol_interface_info_entry_t *cur) -{ - // Reset information to defaults - cur->ws_info->network_pan_id = 0xffff; - - ws_common_regulatory_domain_config(cur, &cur->ws_info->hopping_schdule); - ws_bootstrap_set_domain_rf_config(cur); - ws_fhss_configure(cur, true); - - //Set Network names, Pan information configure, hopping schedule & GTKHash - ws_llc_set_network_name(cur, (uint8_t *)cur->ws_info->cfg->gen.network_name, strlen(cur->ws_info->cfg->gen.network_name)); -} - - -static void ws_bootstrap_advertise_start(protocol_interface_info_entry_t *cur) +void ws_bootstrap_advertise_start(protocol_interface_info_entry_t *cur) { cur->ws_info->trickle_pa_running = true; trickle_start(&cur->ws_info->trickle_pan_advertisement, &cur->ws_info->trickle_params_pan_discovery); @@ -3130,67 +2708,8 @@ static void ws_bootstrap_pan_version_increment(protocol_interface_info_entry_t * ws_bbr_pan_version_increase(cur); } -// Start network scan -static void ws_bootstrap_start_discovery(protocol_interface_info_entry_t *cur) -{ - tr_debug("router discovery start"); - // Remove network keys from MAC - ws_pae_controller_nw_keys_remove(cur); - ws_bootstrap_state_change(cur, ER_ACTIVE_SCAN); - cur->nwk_nd_re_scan_count = 0; - cur->ws_info->configuration_learned = false; - cur->ws_info->pan_timeout_timer = 0; - cur->ws_info->weakest_received_rssi = 0; - - // Clear learned candidate parents - ws_bootstrap_candidate_table_reset(cur); - - // Clear RPL information - rpl_control_free_domain_instances_from_interface(cur); - // Clear EAPOL relay address - ws_eapol_relay_delete(cur); - - // Clear ip stack from old information - ws_bootstrap_ip_stack_reset(cur); - // New network scan started old addresses not assumed valid anymore - ws_bootstrap_ip_stack_addr_clear(cur); - - if ((cur->lowpan_info & INTERFACE_NWK_BOOTSRAP_ACTIVE) != INTERFACE_NWK_BOOTSRAP_ACTIVE) { - // we have sent bootstrap ready event and now - // restarted discovery so bootstrap down event is sent - cur->lowpan_info |= INTERFACE_NWK_BOOTSRAP_ACTIVE; - ws_nwk_event_post(cur, ARM_NWK_NWK_CONNECTION_DOWN); - } - - // Start advertisement solicit trickle and calculate when we are checking the status - cur->ws_info->trickle_pas_running = true; - if (cur->ws_info->trickle_pan_advertisement_solicit.I != cur->ws_info->trickle_params_pan_discovery.Imin) { - // Trickle not reseted so starting a new interval - trickle_start(&cur->ws_info->trickle_pan_advertisement_solicit, &cur->ws_info->trickle_params_pan_discovery); - } - - // Discovery statemachine is checkked after we have sent the Solicit - uint32_t time_to_solicit = 0; - if (cur->ws_info->trickle_pan_advertisement_solicit.t > cur->ws_info->trickle_pan_advertisement_solicit.now) { - time_to_solicit = cur->ws_info->trickle_pan_advertisement_solicit.t - cur->ws_info->trickle_pan_advertisement_solicit.now; - } - - tr_debug("Disc params imin %u, imax %u, expirations %u, k %u PAS Trickle I %u t %u, now %u, c %u", - cur->ws_info->trickle_params_pan_discovery.Imin, cur->ws_info->trickle_params_pan_discovery.Imax, cur->ws_info->trickle_params_pan_discovery.TimerExpirations, cur->ws_info->trickle_params_pan_discovery.k, - cur->ws_info->trickle_pan_advertisement_solicit.I, cur->ws_info->trickle_pan_advertisement_solicit.t, cur->ws_info->trickle_pan_advertisement_solicit.now, cur->ws_info->trickle_pan_advertisement_solicit.c); - - time_to_solicit += cur->ws_info->trickle_params_pan_discovery.Imin + randLIB_get_random_in_range(0, cur->ws_info->trickle_params_pan_discovery.Imin); - - if (time_to_solicit > 0xffff) { - time_to_solicit = 0xffff; - } - cur->bootsrap_state_machine_cnt = time_to_solicit; - - tr_info("Making parent selection in %u s", (cur->bootsrap_state_machine_cnt / 10)); -} - // Start authentication -static void ws_bootstrap_start_authentication(protocol_interface_info_entry_t *cur) +void ws_bootstrap_start_authentication(protocol_interface_info_entry_t *cur) { // Set PAN ID and network name to controller ws_pae_controller_nw_info_set(cur, cur->ws_info->network_pan_id, cur->ws_info->pan_information.pan_version, cur->ws_info->cfg->gen.network_name); @@ -3247,15 +2766,15 @@ static void ws_bootstrap_nw_info_updated(protocol_interface_info_entry_t *cur, u * If they are set, takes them into use here. */ if (cur->bootsrap_mode == ARM_NWK_BOOTSRAP_MODE_6LoWPAN_BORDER_ROUTER) { - // Get PAN ID and network name + // Get network name ws_gen_cfg_t gen_cfg; - if (ws_cfg_gen_get(&gen_cfg, NULL) < 0) { + if (ws_cfg_gen_get(&gen_cfg) < 0) { return; } // If PAN ID has not been set, set it - if (gen_cfg.network_pan_id == 0xffff) { - gen_cfg.network_pan_id = pan_id; + if (cur->ws_info->network_pan_id == 0xffff) { + cur->ws_info->network_pan_id = pan_id; // Sets PAN version cur->ws_info->pan_information.pan_version = pan_version; cur->ws_info->pan_information.pan_version_set = true; @@ -3267,14 +2786,14 @@ static void ws_bootstrap_nw_info_updated(protocol_interface_info_entry_t *cur, u } // Stores the settings - ws_cfg_gen_set(cur, NULL, &gen_cfg, 0); + ws_cfg_gen_set(cur, &gen_cfg, 0); } } static void ws_bootstrap_authentication_completed(protocol_interface_info_entry_t *cur, auth_result_e result, uint8_t *target_eui_64) { if (result == AUTH_RESULT_OK) { - tr_debug("authentication success eui64:%s", trace_array(target_eui_64, 8)); + tr_info("authentication success eui64:%s", trace_array(target_eui_64, 8)); if (target_eui_64) { // Authentication was made contacting the authenticator cur->ws_info->authentication_time = cur->ws_info->uptime; @@ -3322,29 +2841,6 @@ static const uint8_t *ws_bootstrap_authentication_next_target(protocol_interface return previous_eui_64; } -static void ws_bootstrap_eapol_congestion_init(protocol_interface_info_entry_t *cur) -{ - random_early_detection_free(cur->llc_random_early_detection); - cur->llc_random_early_detection = NULL; - - if (cur->llc_random_early_detection == NULL) { - cur->llc_random_early_detection = random_early_detection_create( - cur->ws_info->cfg->sec_prot.max_simult_sec_neg_tx_queue_min, - cur->ws_info->cfg->sec_prot.max_simult_sec_neg_tx_queue_max, - 100, RED_AVERAGE_WEIGHT_EIGHTH); - } - - random_early_detection_free(cur->llc_eapol_random_early_detection); - cur->llc_eapol_random_early_detection = NULL; - - if (cur->llc_eapol_random_early_detection == NULL) { - cur->llc_eapol_random_early_detection = random_early_detection_create( - cur->ws_info->cfg->sec_prot.max_simult_sec_neg_tx_queue_min, - cur->ws_info->cfg->sec_prot.max_simult_sec_neg_tx_queue_max, - 100, RED_AVERAGE_WEIGHT_EIGHTH); - } -} - static bool ws_bootstrap_eapol_congestion_get(protocol_interface_info_entry_t *cur, uint16_t active_supp) { if (cur == NULL || cur->random_early_detection == NULL || cur->llc_random_early_detection == NULL || cur->llc_eapol_random_early_detection == NULL) { @@ -3419,42 +2915,6 @@ congestion_get_end: return return_value; } -// Start configuration learning -static void ws_bootstrap_start_configuration_learn(protocol_interface_info_entry_t *cur) -{ - tr_debug("router configuration learn start"); - ws_bootstrap_state_change(cur, ER_SCAN); - - cur->ws_info->configuration_learned = false; - - // Clear all temporary information - ws_bootstrap_ip_stack_reset(cur); - - cur->ws_info->pas_requests = 0; - //Calculate max time for config learn state - cur->ws_info->pan_config_sol_max_timeout = trickle_timer_max(&cur->ws_info->trickle_params_pan_discovery, PCS_MAX); - // Reset advertisement solicit trickle to start discovering network - cur->ws_info->trickle_pcs_running = true; - trickle_start(&cur->ws_info->trickle_pan_config_solicit, &cur->ws_info->trickle_params_pan_discovery); - trickle_inconsistent_heard(&cur->ws_info->trickle_pan_config_solicit, &cur->ws_info->trickle_params_pan_discovery); -} -static void ws_bootstrap_rpl_scan_start(protocol_interface_info_entry_t *cur) -{ - tr_debug("Start RPL learn"); - // Stop Trickle timers - ws_bootstrap_asynch_trickle_stop(cur); - - // routers wait until RPL root is contacted - ws_bootstrap_state_change(cur, ER_RPL_SCAN); - // Change state as the state is checked in state machine - cur->ws_info->rpl_state = RPL_EVENT_LOCAL_REPAIR_START; - //For Large network and medium should do passive scan - if (ws_cfg_network_config_get(cur) > CONFIG_SMALL) { - // Set timeout for check to 30 - 60 seconds - cur->bootsrap_state_machine_cnt = randLIB_get_random_in_range(WS_RPL_DIS_INITIAL_TIMEOUT / 2, WS_RPL_DIS_INITIAL_TIMEOUT); - } -} - /* * Event transitions * @@ -3484,21 +2944,28 @@ void ws_bootstrap_event_disconnect(protocol_interface_info_entry_t *cur, ws_boot { ws_bootsrap_event_trig(event_type, cur->bootStrapId, ARM_LIB_LOW_PRIORITY_EVENT, NULL); } +void ws_bootstrap_event_test_procedure_trigger(protocol_interface_info_entry_t *cur, ws_bootsrap_procedure_t procedure) +{ + if (cur->bootStrapId < 0) { + return; + } + ws_bootsrap_event_trig(WS_TEST_PROC_TRIGGER, cur->bootStrapId, ARM_LIB_LOW_PRIORITY_EVENT, (void *) procedure); +} void ws_bootstrap_configuration_trickle_reset(protocol_interface_info_entry_t *cur) { trickle_inconsistent_heard(&cur->ws_info->trickle_pan_config, &cur->ws_info->trickle_params_pan_discovery); } -static void ws_set_asynch_channel_list(protocol_interface_info_entry_t *cur, asynch_request_t *async_req) +static void ws_bootstrap_set_asynch_channel_list(protocol_interface_info_entry_t *cur, asynch_request_t *async_req) { memset(&async_req->channel_list, 0, sizeof(channel_list_s)); if (cur->ws_info->cfg->fhss.fhss_uc_channel_function == WS_FIXED_CHANNEL) { //SET 1 Channel only uint16_t channel_number = cur->ws_info->cfg->fhss.fhss_uc_fixed_channel; - async_req->channel_list.channel_mask[0 + (channel_number / 32)] = (1 << (channel_number % 32)); + async_req->channel_list.channel_mask[channel_number / 32] = 1U << (channel_number % 32); } else { - ws_generate_channel_list(async_req->channel_list.channel_mask, cur->ws_info->hopping_schdule.number_of_channels, cur->ws_info->hopping_schdule.regulatory_domain, cur->ws_info->hopping_schdule.operating_class, cur->ws_info->hopping_schdule.channel_plan_id); + ws_common_generate_channel_list(async_req->channel_list.channel_mask, cur->ws_info->hopping_schdule.number_of_channels, cur->ws_info->hopping_schdule.regulatory_domain, cur->ws_info->hopping_schdule.operating_class, cur->ws_info->hopping_schdule.channel_plan_id); } async_req->channel_list.channel_page = CHANNEL_PAGE_10; @@ -3514,7 +2981,7 @@ static void ws_bootstrap_pan_advert_solicit(protocol_interface_info_entry_t *cur async_req.wp_requested_nested_ie_list.us_ie = true; async_req.wp_requested_nested_ie_list.net_name_ie = true; - ws_set_asynch_channel_list(cur, &async_req); + ws_bootstrap_set_asynch_channel_list(cur, &async_req); async_req.security.SecurityLevel = 0; @@ -3533,75 +3000,13 @@ static void ws_bootstrap_pan_config_solicit(protocol_interface_info_entry_t *cur async_req.wp_requested_nested_ie_list.us_ie = true; async_req.wp_requested_nested_ie_list.net_name_ie = true; - ws_set_asynch_channel_list(cur, &async_req); + ws_bootstrap_set_asynch_channel_list(cur, &async_req); async_req.security.SecurityLevel = 0; ws_stats_update(cur, STATS_WS_ASYNCH_TX_PCS, 1); ws_llc_asynch_request(cur, &async_req); } -static struct rpl_instance *ws_get_rpl_instance(protocol_interface_info_entry_t *cur) -{ - if (!cur || !cur->rpl_domain) { - return NULL; - } - struct rpl_instance *best_instance = NULL; - ns_list_foreach(struct rpl_instance, instance, &cur->rpl_domain->instances) { - best_instance = instance; - // Select best grounded and lowest rank? But there should be only one really - } - return best_instance; -} - -static uint16_t ws_bootstrap_routing_cost_calculate(protocol_interface_info_entry_t *cur) -{ - mac_neighbor_table_entry_t *mac_neighbor = mac_neighbor_entry_get_priority(mac_neighbor_info(cur)); - if (!mac_neighbor) { - return 0xffff; - } - ws_neighbor_class_entry_t *ws_neighbor = ws_neighbor_class_entry_get(&cur->ws_info->neighbor_storage, mac_neighbor->index); - if (!ws_neighbor) { - return 0xffff; - } - - uint16_t etx = ws_local_etx_read(cur, ADDR_802_15_4_LONG, mac_neighbor->mac64); - if (etx == 0) { - etx = WS_ETX_MAX; //SET maximum value here if ETX is unknown - } else { - //Scale to 128 based ETX (local read return 0x100 - 0xffff - etx = etx >> 1; - } - // Make the 0xffff as maximum value - if (ws_neighbor->routing_cost + etx > 0xffff) { - return 0xffff; - } - - return ws_neighbor->routing_cost + etx; -} - -static uint16_t ws_bootstrap_rank_get(protocol_interface_info_entry_t *cur) -{ - struct rpl_instance *rpl_instance = ws_get_rpl_instance(cur); - if (!rpl_instance) { - return 0xffff; - } - return rpl_control_current_rank(rpl_instance); -} - - -static uint16_t ws_bootstrap_min_rank_inc_get(protocol_interface_info_entry_t *cur) -{ - struct rpl_instance *rpl_instance = ws_get_rpl_instance(cur); - if (!rpl_instance) { - return 0xffff; - } - struct rpl_dodag_info_t dodag_info; - if (!rpl_control_read_dodag_info(rpl_instance, &dodag_info)) { - return 0xffff; - } - return dodag_info.dag_min_hop_rank_inc; -} - static void ws_bootstrap_pan_advert(protocol_interface_info_entry_t *cur) { asynch_request_t async_req; @@ -3612,8 +3017,11 @@ static void ws_bootstrap_pan_advert(protocol_interface_info_entry_t *cur) async_req.wp_requested_nested_ie_list.us_ie = true; async_req.wp_requested_nested_ie_list.pan_ie = true; async_req.wp_requested_nested_ie_list.net_name_ie = true; + if (ws_version_1_1(cur)) { + async_req.wp_requested_nested_ie_list.phy_cap_ie = true; + } - ws_set_asynch_channel_list(cur, &async_req); + ws_bootstrap_set_asynch_channel_list(cur, &async_req); async_req.security.SecurityLevel = 0; if (cur->bootsrap_mode == ARM_NWK_BOOTSRAP_MODE_6LoWPAN_BORDER_ROUTER) { @@ -3643,8 +3051,11 @@ static void ws_bootstrap_pan_config(protocol_interface_info_entry_t *cur) async_req.wp_requested_nested_ie_list.pan_version_ie = true; async_req.wp_requested_nested_ie_list.gtkhash_ie = true; async_req.wp_requested_nested_ie_list.vp_ie = true; + if (ws_version_1_1(cur)) { + async_req.wp_requested_nested_ie_list.lfn_gtk_version_ie = ws_lfn_version_learned(cur); + } - ws_set_asynch_channel_list(cur, &async_req); + ws_bootstrap_set_asynch_channel_list(cur, &async_req); async_req.security.SecurityLevel = mac_helper_default_security_level_get(cur); async_req.security.KeyIdMode = mac_helper_default_security_key_id_mode_get(cur); @@ -3659,207 +3070,32 @@ static void ws_bootstrap_pan_config(protocol_interface_info_entry_t *cur) ws_llc_asynch_request(cur, &async_req); } -static int8_t ws_bootstrap_backbone_ip_addr_get(protocol_interface_info_entry_t *interface_ptr, uint8_t *address) -{ - (void) interface_ptr; - (void) address; - - if (ws_bbr_backbone_address_get(address)) { - return 0; - } - - return -1; -} - - static void ws_bootstrap_event_handler(arm_event_s *event) { - ws_bootsrap_event_type_e event_type; - event_type = (ws_bootsrap_event_type_e)event->event_type; protocol_interface_info_entry_t *cur; cur = protocol_stack_interface_info_get_by_bootstrap_id(event->receiver); if (!cur) { return; } - switch (event_type) { - case WS_INIT_EVENT: - tr_debug("tasklet init"); - break; - case WS_DISCOVERY_START: - tr_info("Discovery start"); - protocol_mac_reset(cur); - ws_llc_reset(cur); - lowpan_adaptation_interface_reset(cur->id); - //Clear Pending Key Index State - cur->ws_info->pending_key_index_info.state = NO_PENDING_PROCESS; - cur->mac_parameters->mac_default_key_index = 0; - - ipv6_destination_cache_clean(cur->id); - - // Clear parent blacklist - blacklist_clear(); - - // All trickle timers stopped to allow entry from any state - ws_bootstrap_asynch_trickle_stop(cur); - //Init Packet congestion - ws_bootstrap_packet_congestion_init(cur); - - if (cur->bootsrap_mode == ARM_NWK_BOOTSRAP_MODE_6LoWPAN_BORDER_ROUTER) { - tr_info("Border router start network"); - - - if (!ws_bbr_ready_to_start(cur)) { - // Wi-SUN not started yet we wait for Border router permission - ws_bootstrap_state_change(cur, ER_WAIT_RESTART); - cur->nwk_nd_re_scan_count = randLIB_get_random_in_range(40, 100); - return; - } - // Clear Old information from stack - - ws_nud_table_reset(cur); - ws_bootstrap_neighbor_list_clean(cur); - ws_bootstrap_ip_stack_reset(cur); - ws_pae_controller_auth_init(cur); - - if (cur->ws_info->cfg->gen.network_pan_id == 0xffff) { - cur->ws_info->network_pan_id = randLIB_get_random_in_range(0, 0xfffd); - } else { - cur->ws_info->network_pan_id = cur->ws_info->cfg->gen.network_pan_id; - } - if (!cur->ws_info->pan_information.pan_version_set) { - cur->ws_info->pan_information.pan_version = randLIB_get_random_in_range(0, 0xffff); - cur->ws_info->pan_information.pan_version_set = true; - } - cur->ws_info->pan_information.pan_size = 0; - cur->ws_info->pan_information.routing_cost = 0; - cur->ws_info->pan_information.rpl_routing_method = true; - cur->ws_info->pan_information.use_parent_bs = true; - cur->ws_info->pan_information.version = WS_FAN_VERSION_1_0; - - uint8_t *gtkhash = ws_pae_controller_gtk_hash_ptr_get(cur); - ws_llc_set_gtkhash(cur, gtkhash); - ws_bbr_pan_version_increase(cur); - - // Set default parameters for FHSS when starting a discovery - ws_common_regulatory_domain_config(cur, &cur->ws_info->hopping_schdule); - ws_fhss_border_router_configure(cur); - ws_bootstrap_set_domain_rf_config(cur); - ws_bootstrap_fhss_activate(cur); - - uint8_t ll_addr[16]; - addr_interface_get_ll_address(cur, ll_addr, 1); - - //SET EAPOL authenticator EUI64 - ws_pae_controller_border_router_addr_write(cur, cur->mac); - - // Set EAPOL relay to port 10255 and authenticator relay to 10253 (and to own ll address) - ws_eapol_relay_start(cur, BR_EAPOL_RELAY_SOCKET_PORT, ll_addr, EAPOL_RELAY_SOCKET_PORT); - - // Set authenticator relay to port 10253 and PAE to 10254 (and to own ll address) - ws_eapol_auth_relay_start(cur, EAPOL_RELAY_SOCKET_PORT, ll_addr, PAE_AUTH_SOCKET_PORT); - - // Set PAN ID and network name to controller - ws_pae_controller_nw_info_set(cur, cur->ws_info->network_pan_id, cur->ws_info->pan_information.pan_version, cur->ws_info->cfg->gen.network_name); - - // Set backbone IP address get callback - ws_pae_controller_auth_cb_register(cur, ws_bootstrap_backbone_ip_addr_get); - - // Set PAE port to 10254 and authenticator relay to 10253 (and to own ll address) - ws_pae_controller_authenticator_start(cur, PAE_AUTH_SOCKET_PORT, ll_addr, EAPOL_RELAY_SOCKET_PORT); - - // Initialize eapol congestion tracking - ws_bootstrap_eapol_congestion_init(cur); - - // Set retry configuration for bootstrap ready state - ws_bootstrap_configure_max_retries(cur, WS_MAX_FRAME_RETRIES); - - // Set TX failure request restart configuration - ws_bootstrap_configure_data_request_restart(cur, WS_CCA_REQUEST_RESTART_MAX, WS_TX_REQUEST_RESTART_MAX, WS_REQUEST_RESTART_BLACKLIST_MIN, WS_REQUEST_RESTART_BLACKLIST_MAX); - - // Set CSMA-CA backoff configuration - ws_bootstrap_configure_csma_ca_backoffs(cur, WS_MAX_CSMA_BACKOFFS, WS_MAC_MIN_BE, WS_MAC_MAX_BE); - - ws_bootstrap_event_operation_start(cur); - break; - } - ws_pae_controller_supp_init(cur); - // Clear learned neighbours - ws_bootstrap_neighbor_list_clean(cur); - // Configure LLC for network discovery - ws_bootstrap_network_discovery_configure(cur); - ws_bootstrap_fhss_activate(cur); - // Set retry configuration for discovery state - ws_bootstrap_configure_max_retries(cur, WS_MAX_FRAME_RETRIES_BOOTSTRAP); - // Set TX failure request restart configuration for discovery state - ws_bootstrap_configure_data_request_restart(cur, WS_CCA_REQUEST_RESTART_MAX, WS_TX_REQUEST_RESTART_MAX_BOOTSTRAP, WS_REQUEST_RESTART_BLACKLIST_MIN, WS_REQUEST_RESTART_BLACKLIST_MAX); - // Set CSMA-CA backoff configuration - ws_bootstrap_configure_csma_ca_backoffs(cur, WS_MAX_CSMA_BACKOFFS, WS_MAC_MIN_BE, WS_MAC_MAX_BE); - // Start network scan - ws_bootstrap_start_discovery(cur); - break; - - case WS_CONFIGURATION_START: - tr_info("Configuration start"); - // Old configuration is considered invalid stopping all - ws_bootstrap_asynch_trickle_stop(cur); - - // Build list of possible neighbours and learn first broadcast schedule - - ws_bootstrap_start_configuration_learn(cur); - break; - case WS_OPERATION_START: - tr_info("operation start"); - // Advertisements stopped during the RPL scan - ws_bootstrap_asynch_trickle_stop(cur); - // Activate RPL - // Activate IPv6 stack - ws_bootstrap_ip_stack_activate(cur); - ws_bootstrap_rpl_activate(cur); - ws_bootstrap_network_start(cur); - // Wait for RPL start - if (cur->bootsrap_mode == ARM_NWK_BOOTSRAP_MODE_6LoWPAN_BORDER_ROUTER) { - ws_bootstrap_event_routing_ready(cur); - } else { - ws_bootstrap_rpl_scan_start(cur); - /* While in Join State 4, if a non Border Router determines it has been unable to communicate with the PAN Border - * Router for an interval of PAN_TIMEOUT, a node MUST assume failure of the PAN Border Router and MUST - * Transition to Join State 1 - */ - ws_common_border_router_alive_update(cur); - } - break; - case WS_ROUTING_READY: - tr_info("Routing ready"); - // stopped all to make sure we can enter here from any state - ws_bootstrap_asynch_trickle_stop(cur); - - // Indicate PAE controller that bootstrap is ready - ws_pae_controller_bootstrap_done(cur); - - ws_bootstrap_advertise_start(cur); - ws_bootstrap_state_change(cur, ER_BOOTSRAP_DONE); - break; - case WS_FAST_DISCONNECT: - ws_bootstrap_disconnect(cur, WS_FAST_DISCONNECT); - break; - case WS_NORMAL_DISCONNECT: - ws_bootstrap_disconnect(cur, WS_NORMAL_DISCONNECT); - break; - - default: - tr_err("Invalid event received"); - break; + if (wisun_mode_host(cur)) { + ws_bootstrap_lfn_event_handler(cur, event); + } else if (wisun_mode_router(cur)) { + ws_bootstrap_ffn_event_handler(cur, event); + } else if (wisun_mode_border_router(cur)) { + ws_bootstrap_6lbr_event_handler(cur, event); } } -static int8_t ws_bootstrap_neighbor_set(protocol_interface_info_entry_t *cur, parent_info_t *parent_ptr, bool clear_list) +int8_t ws_bootstrap_neighbor_set(protocol_interface_info_entry_t *cur, parent_info_t *parent_ptr, bool clear_list) { uint16_t pan_id = cur->ws_info->network_pan_id; // Add EAPOL neighbor cur->ws_info->network_pan_id = parent_ptr->pan_id; - cur->ws_info->pan_information = parent_ptr->pan_information; + cur->ws_info->pan_information.pan_size = parent_ptr->pan_information.pan_size; + cur->ws_info->pan_information.routing_cost = parent_ptr->pan_information.routing_cost; + cur->ws_info->pan_information.use_parent_bs = parent_ptr->pan_information.use_parent_bs; cur->ws_info->pan_information.pan_version = 0; // This is learned from actual configuration // If PAN ID changes, clear learned neighbors and activate FHSS @@ -3887,72 +3123,34 @@ static int8_t ws_bootstrap_neighbor_set(protocol_interface_info_entry_t *cur, pa * State machine * * */ -void ws_bootstrap_network_scan_process(protocol_interface_info_entry_t *cur) +void ws_bootstrap_state_disconnect(protocol_interface_info_entry_t *cur, ws_bootsrap_event_type_e event_type) { - - parent_info_t *selected_parent_ptr; - - tr_debug("analyze network discovery result"); - -select_best_candidate: - selected_parent_ptr = ws_bootstrap_candidate_parent_get_best(cur); - - if (!selected_parent_ptr) { - // Configure LLC for network discovery - ws_bootstrap_network_discovery_configure(cur); - // randomize new channel and start MAC - ws_bootstrap_fhss_activate(cur); - // Next check will be after one trickle - uint32_t random_start = cur->ws_info->trickle_params_pan_discovery.Imin + randLIB_get_random_in_range(0, cur->ws_info->trickle_params_pan_discovery.Imin); - if (random_start > 0xffff) { - random_start = 0xffff; - } - cur->bootsrap_state_machine_cnt = random_start; - - tr_info("Making parent selection in %u s", (cur->bootsrap_state_machine_cnt / 10)); + if (cur->nwk_bootstrap_state == ER_RPL_NETWORK_LEAVING) { + //Already moved to leaving state. return; } - tr_info("selected parent:%s panid %u", trace_array(selected_parent_ptr->addr, 8), selected_parent_ptr->pan_id); + // We are no longer connected + cur->ws_info->connected_time = 0; - if (ws_bootstrap_neighbor_set(cur, selected_parent_ptr, false) < 0) { - goto select_best_candidate; - } - - ws_pae_controller_set_target(cur, selected_parent_ptr->pan_id, selected_parent_ptr->addr); // temporary!!! store since auth - ws_bootstrap_event_authentication_start(cur); - return; -} - -void ws_bootstrap_configure_process(protocol_interface_info_entry_t *cur) -{ - - if (cur->ws_info->configuration_learned) { - ws_bootstrap_network_configuration_learn(cur); - ws_bootstrap_event_operation_start(cur); - return; - } - return; -} -void ws_bootstrap_rpl_wait_process(protocol_interface_info_entry_t *cur) -{ - - if (cur->ws_info->rpl_state == RPL_EVENT_DAO_DONE) { - // RPL routing is ready - cur->ws_info->connected_time = cur->ws_info->uptime; - ws_bootstrap_event_routing_ready(cur); - } else if (!rpl_control_have_dodag(cur->rpl_domain)) { - // RPL not ready send DIS message if possible - if (cur->bootsrap_mode == ARM_NWK_BOOTSRAP_MODE_6LoWPAN_ROUTER) { - // TODO Multicast DIS should be sent only if no DIO heard for some time - rpl_control_transmit_dis(cur->rpl_domain, cur, 0, 0, NULL, 0, ADDR_LINK_LOCAL_ALL_RPL_NODES); + if (cur->rpl_domain && cur->nwk_bootstrap_state == ER_BOOTSRAP_DONE) { + //Stop Asych Timer + ws_bootstrap_asynch_trickle_stop(cur); + tr_debug("Start Network soft leaving"); + if (event_type == WS_FAST_DISCONNECT) { + rpl_control_instant_poison(cur, cur->rpl_domain); + cur->bootsrap_state_machine_cnt = 80; //Give 8 seconds time to send Poison + } else { + rpl_control_poison(cur->rpl_domain, 1); + cur->bootsrap_state_machine_cnt = 6000; //Give 10 minutes time for poison if RPL is not report } - // set timer for next DIS - cur->bootsrap_state_machine_cnt = randLIB_get_random_in_range(WS_RPL_DIS_TIMEOUT / 2, WS_RPL_DIS_TIMEOUT); + + } else { + ws_bootstrap_event_discovery_start(cur); } - return; + cur->nwk_bootstrap_state = ER_RPL_NETWORK_LEAVING; } -static bool ws_bootstrap_state_discovery(struct protocol_interface_info_entry *cur) +bool ws_bootstrap_state_discovery(struct protocol_interface_info_entry *cur) { if (cur->nwk_bootstrap_state == ER_ACTIVE_SCAN) { return true; @@ -3960,7 +3158,7 @@ static bool ws_bootstrap_state_discovery(struct protocol_interface_info_entry *c return false; } -static bool ws_bootstrap_state_authenticate(struct protocol_interface_info_entry *cur) +bool ws_bootstrap_state_authenticate(struct protocol_interface_info_entry *cur) { // Think about the state value if (cur->nwk_bootstrap_state == ER_PANA_AUTH) { @@ -3969,7 +3167,7 @@ static bool ws_bootstrap_state_authenticate(struct protocol_interface_info_entry return false; } -static bool ws_bootstrap_state_configure(struct protocol_interface_info_entry *cur) +bool ws_bootstrap_state_configure(struct protocol_interface_info_entry *cur) { // Think about the state value if (cur->nwk_bootstrap_state == ER_SCAN) { @@ -3978,7 +3176,7 @@ static bool ws_bootstrap_state_configure(struct protocol_interface_info_entry *c return false; } -static bool ws_bootstrap_state_wait_rpl(struct protocol_interface_info_entry *cur) +bool ws_bootstrap_state_wait_rpl(struct protocol_interface_info_entry *cur) { // Think about the state value if (cur->nwk_bootstrap_state == ER_RPL_SCAN) { @@ -3987,7 +3185,7 @@ static bool ws_bootstrap_state_wait_rpl(struct protocol_interface_info_entry *cu return false; } -static bool ws_bootstrap_state_active(struct protocol_interface_info_entry *cur) +bool ws_bootstrap_state_active(struct protocol_interface_info_entry *cur) { if (cur->nwk_bootstrap_state == ER_BOOTSRAP_DONE) { return true; @@ -3995,56 +3193,15 @@ static bool ws_bootstrap_state_active(struct protocol_interface_info_entry *cur) return false; } -static void ws_bootstrap_state_change(protocol_interface_info_entry_t *cur, icmp_state_t nwk_bootstrap_state) +void ws_bootstrap_state_change(protocol_interface_info_entry_t *cur, icmp_state_t nwk_bootstrap_state) { cur->bootsrap_state_machine_cnt = 1; cur->nwk_bootstrap_state = nwk_bootstrap_state; } -void ws_bootstrap_state_machine(protocol_interface_info_entry_t *cur) +void ws_bootstrap_network_down(protocol_interface_info_entry_t *cur) { - - switch (cur->nwk_bootstrap_state) { - case ER_WAIT_RESTART: - tr_debug("WS SM:Wait for startup"); - ws_bootstrap_event_discovery_start(cur); - break; - case ER_ACTIVE_SCAN: - tr_debug("WS SM:Active Scan"); - ws_bootstrap_network_scan_process(cur); - break; - case ER_SCAN: - tr_debug("WS SM:configuration Scan"); - ws_bootstrap_configure_process(cur); - break; - case ER_PANA_AUTH: - tr_info("authentication start"); - // Advertisements stopped during the EAPOL - ws_bootstrap_asynch_trickle_stop(cur); - ws_fhss_configure(cur, false); - int8_t new_default = cur->ws_info->weakest_received_rssi - 1; - if ((new_default < CCA_DEFAULT_DBM) && (new_default >= CCA_LOW_LIMIT) && (new_default <= CCA_HIGH_LIMIT)) { - // Restart automatic CCA threshold using weakest received RSSI as new default - mac_helper_start_auto_cca_threshold(cur->id, cur->ws_info->hopping_schdule.number_of_channels, cur->ws_info->weakest_received_rssi - 1, CCA_HIGH_LIMIT, CCA_LOW_LIMIT); - } - ws_bootstrap_start_authentication(cur); - break; - case ER_RPL_SCAN: - tr_debug("WS SM:Wait RPL to contact DODAG root"); - ws_bootstrap_rpl_wait_process(cur); - break; - case ER_BOOTSRAP_DONE: - tr_debug("WS SM:Bootstrap Done"); - // Bootstrap_done event to application - nwk_bootsrap_state_update(ARM_NWK_BOOTSTRAP_READY, cur); - break; - case ER_RPL_NETWORK_LEAVING: - tr_debug("WS SM:RPL Leaving ready trigger discovery"); - ws_bootstrap_event_discovery_start(cur); - break; - default: - tr_warn("WS SM:Invalid state %d", cur->nwk_bootstrap_state); - } + ws_nwk_event_post(cur, ARM_NWK_NWK_CONNECTION_DOWN); } void ws_bootstrap_trickle_timer(protocol_interface_info_entry_t *cur, uint16_t ticks) @@ -4108,50 +3265,18 @@ void ws_bootstrap_trickle_timer(protocol_interface_info_entry_t *cur, uint16_t t } } +void ws_bootstrap_asynch_trickle_stop(protocol_interface_info_entry_t *cur) +{ + cur->ws_info->trickle_pas_running = false; + cur->ws_info->trickle_pa_running = false; + cur->ws_info->trickle_pcs_running = false; + cur->ws_info->trickle_pc_running = false; + cur->ws_info->trickle_pc_consistency_block_period = 0; +} + void ws_bootstrap_seconds_timer(protocol_interface_info_entry_t *cur, uint32_t seconds) { - /* Border router keep alive check - */ - if (cur->ws_info->pan_timeout_timer) { - // PAN version timer running - if (cur->ws_info->pan_timeout_timer > seconds) { - cur->ws_info->pan_timeout_timer -= seconds; - if (cur->ws_info->pan_timeout_timer < cur->ws_info->cfg->timing.pan_timeout / 10) { - /* pan timeout is closing need to verify that DAO is tested before the pan times out. - This will give some extra time for RPL to find better parents. - Border router liveliness can be checked from version number change or from successful DAO registrations - in this case there has not been any version number changes during this PAN lifetime. - */ - rpl_control_dao_timeout(cur->rpl_domain, 20); - } - } else { - // Border router has timed out - //Clear Timeout timer - cur->ws_info->pan_timeout_timer = 0; - tr_warn("Border router has timed out"); - ws_bootstrap_event_disconnect(cur, WS_FAST_DISCONNECT); - } - } - if (cur->ws_info->aro_registration_timer) { - if (cur->ws_info->aro_registration_timer > seconds) { - cur->ws_info->aro_registration_timer -= seconds; - } else { - // Update all addressess. This function will update the timer value if needed - cur->ws_info->aro_registration_timer = 0; - ws_address_registration_update(cur, NULL); - } - } - - if (cur->ws_info->ws_bsi_block.block_time) { - if (cur->ws_info->ws_bsi_block.block_time > seconds) { - cur->ws_info->ws_bsi_block.block_time -= seconds; - } else { - //Clear A BSI blokker - cur->ws_info->ws_bsi_block.block_time = 0; - cur->ws_info->ws_bsi_block.old_bsi = 0; - } - } /*Update join state statistics*/ if (ws_bootstrap_state_discovery(cur)) { ws_stats_update(cur, STATS_WS_STATE_1, 1); @@ -4163,11 +3288,14 @@ void ws_bootstrap_seconds_timer(protocol_interface_info_entry_t *cur, uint32_t s ws_stats_update(cur, STATS_WS_STATE_4, 1); } else if (ws_bootstrap_state_active(cur)) { ws_stats_update(cur, STATS_WS_STATE_5, 1); + //Update neighbour MDR phy capability mode id + ws_neighbour_mdr_mode_analyze(cur); } cur->ws_info->uptime++; ws_llc_timer_seconds(cur, seconds); + ws_bootstrap_test_procedure_trigger_timer(cur, seconds); } void ws_bootstrap_primary_parent_update(protocol_interface_info_entry_t *interface, mac_neighbor_table_entry_t *neighbor) @@ -4178,7 +3306,7 @@ void ws_bootstrap_primary_parent_update(protocol_interface_info_entry_t *interfa neighbor_info.ws_neighbor = ws_neighbor_class_entry_get(&interface->ws_info->neighbor_storage, neighbor->index); ws_bootstrap_primary_parent_set(interface, &neighbor_info, WS_PARENT_HARD_SYNCH); uint8_t link_local_address[16]; - ws_bootsrap_create_ll_address(link_local_address, neighbor->mac64); + ws_common_create_ll_address(link_local_address, neighbor->mac64); dhcp_client_server_address_update(interface->id, NULL, link_local_address); ws_bootstrap_secondary_parent_update(interface); @@ -4206,7 +3334,7 @@ int ws_bootstrap_stack_info_get(protocol_interface_info_entry_t *cur, struct ws_ if (mac_parent) { ws_neighbour = ws_neighbor_class_entry_get(&cur->ws_info->neighbor_storage, mac_parent->index); - ws_bootsrap_create_ll_address(info_ptr->parent, mac_parent->mac64); + ws_common_create_ll_address(info_ptr->parent, mac_parent->mac64); } if (ws_neighbour) { info_ptr->rsl_in = ws_neighbor_class_rsl_in_get(ws_neighbour); @@ -4268,7 +3396,7 @@ int ws_bootstrap_neighbor_info_get(protocol_interface_info_entry_t *cur, ws_neig if (neighbor_ptr[count].etx != 0xffff) { neighbor_ptr[count].etx = neighbor_ptr[count].etx >> 1; } - ws_bootsrap_create_ll_address(ll_address, mac_entry->mac64); + ws_common_create_ll_address(ll_address, mac_entry->mac64); memcpy(neighbor_ptr[count].link_local_address, ll_address, 16); if (rpl_control_is_dodag_parent_candidate(cur, ll_address, cur->ws_info->cfg->gen.rpl_parent_candidate_max)) { @@ -4344,9 +3472,7 @@ static uint16_t ws_bootstrap_packet_per_seconds(protocol_interface_info_entry_t return data_rate / 5; } - - -static void ws_bootstrap_packet_congestion_init(protocol_interface_info_entry_t *cur) +void ws_bootstrap_packet_congestion_init(protocol_interface_info_entry_t *cur) { random_early_detection_free(cur->random_early_detection); cur->random_early_detection = NULL; @@ -4376,4 +3502,232 @@ static void ws_bootstrap_packet_congestion_init(protocol_interface_info_entry_t } +static bool auto_test_proc_trg_enabled = false; + +int ws_bootstrap_test_procedure_trigger(protocol_interface_info_entry_t *cur, ws_bootsrap_procedure_t procedure) +{ + switch (procedure) { + case PROCEDURE_AUTO_ON: + tr_info("Trigger bootstrap test procedures automatically"); + auto_test_proc_trg_enabled = true; + return 0; + case PROCEDURE_AUTO_OFF: + tr_info("Disable automatic bootstrap test procedure triggering"); + auto_test_proc_trg_enabled = false; + return 0; + default: + break; + } + + if (!cur) { + return -1; + } + + switch (procedure) { + case PROCEDURE_DIS: + case PROCEDURE_DAO: + case PROCEDURE_PAS: + case PROCEDURE_PCS: + case PROCEDURE_EAPOL: + case PROCEDURE_RPL: + if (cur->bootsrap_mode == ARM_NWK_BOOTSRAP_MODE_6LoWPAN_BORDER_ROUTER) { + tr_info("Not allowed on Border Router"); + return -1; + } + break; + default: + break; + } + + if (cur->interface_mode != INTERFACE_UP) { + tr_info("Interface is not up"); + return -1; + } + + ws_bootstrap_event_test_procedure_trigger(cur, procedure); + return 0; +} + +void ws_bootstrap_test_procedure_trigger_exec(protocol_interface_info_entry_t *cur, ws_bootsrap_procedure_t procedure) +{ + switch (procedure) { + case PROCEDURE_DIS: + if (cur->nwk_bootstrap_state == ER_RPL_SCAN || ws_bootstrap_state_active(cur)) { + tr_info("trigger DODAG information object solicit"); + rpl_control_transmit_dis(cur->rpl_domain, cur, 0, 0, NULL, 0, ADDR_LINK_LOCAL_ALL_RPL_NODES); + } else { + tr_info("wrong state: DODAG information object solicit not triggered"); + } + break; + case PROCEDURE_DIO: + if (ws_bootstrap_state_active(cur)) { + tr_info("trigger DODAG information object"); + rpl_control_transmit_dio_trigger(cur, cur->rpl_domain); + } else { + tr_info("wrong state: DODAG information object not triggered"); + } + break; + case PROCEDURE_DAO: + // Can be triggered if in correct state and there is selected RPL parent + if ((cur->nwk_bootstrap_state == ER_RPL_SCAN || ws_bootstrap_state_active(cur)) + && rpl_control_parent_candidate_list_size(cur, true) > 0) { + tr_info("trigger Destination advertisement object"); + rpl_control_dao_timeout(cur->rpl_domain, 2); + } else { + tr_info("wrong state: Destination advertisement object not triggered"); + } + break; + case PROCEDURE_PAS: + case PROCEDURE_PAS_TRICKLE_INCON: + tr_info("trigger PAN advertisement Solicit"); + if (procedure != PROCEDURE_PAS_TRICKLE_INCON) { + tr_info("send PAN advertisement Solicit"); + ws_bootstrap_pan_advert_solicit(cur); + } + if (cur->ws_info->trickle_pas_running) { + trickle_inconsistent_heard(&cur->ws_info->trickle_pan_advertisement_solicit, &cur->ws_info->trickle_params_pan_discovery); + } + break; + case PROCEDURE_PA: + if (cur->ws_info->trickle_pa_running) { + tr_info("trigger PAN advertisement"); + ws_bootstrap_pan_advert(cur); + trickle_inconsistent_heard(&cur->ws_info->trickle_pan_advertisement, &cur->ws_info->trickle_params_pan_discovery); + } else { + tr_info("wrong state: PAN advertisement not triggered"); + } + break; + case PROCEDURE_PCS: + case PROCEDURE_PCS_TRICKLE_INCON: + if (cur->ws_info->trickle_pcs_running || ws_bootstrap_state_active(cur)) { + tr_info("trigger PAN configuration Solicit"); + if (procedure != PROCEDURE_PCS_TRICKLE_INCON) { + tr_info("send PAN configuration Solicit"); + ws_bootstrap_pan_config_solicit(cur); + } + if (cur->ws_info->trickle_pcs_running) { + trickle_inconsistent_heard(&cur->ws_info->trickle_pan_config_solicit, &cur->ws_info->trickle_params_pan_discovery); + } + } else { + tr_info("wrong state: PAN configuration Solicit not triggered"); + } + break; + case PROCEDURE_PC: + if (cur->ws_info->trickle_pc_running) { + tr_info("trigger PAN configuration"); + ws_bootstrap_pan_config(cur); + trickle_inconsistent_heard(&cur->ws_info->trickle_pan_config, &cur->ws_info->trickle_params_pan_discovery); + } else { + tr_info("wrong state: PAN configuration not triggered"); + } + break; + case PROCEDURE_EAPOL: + if (cur->nwk_bootstrap_state == ER_ACTIVE_SCAN) { + tr_info("trigger EAPOL target selection"); + if (cur->bootsrap_state_machine_cnt > 3) { + cur->bootsrap_state_machine_cnt = 3; + } + } else { + tr_info("wrong state: EAPOL target selection not triggered"); + } + break; + case PROCEDURE_RPL: { + bool neigth_has_ext = false; + for (int n = 0; n < mac_neighbor_info(cur)->list_total_size; n++) { + mac_neighbor_table_entry_t *mac_entry = mac_neighbor_table_attribute_discover(mac_neighbor_info(cur), n); + if (mac_entry) { + uint16_t etx = ws_local_etx_read(cur, ADDR_802_15_4_LONG, mac_entry->mac64); + if (etx != 0xFFFF) { + neigth_has_ext = true; + } + } + } + /* If selecting RPL parent, there is some RPL candidates and neighbors with ETX try + the RPL parent selection procedure */ + if (cur->nwk_bootstrap_state == ER_RPL_SCAN && neigth_has_ext && + rpl_control_parent_candidate_list_size(cur, false) > 0) { + tr_info("trigger RPL parent selection"); + rpl_control_parent_selection_trigger(cur->rpl_domain); + } else { + tr_info("wrong state: RPL parent selection not triggered"); + } + break; + } + default: + break; + } +} + +static void ws_bootstrap_test_procedure_trigger_timer(protocol_interface_info_entry_t *cur, uint32_t seconds) +{ + if (!auto_test_proc_trg_enabled) { + cur->ws_info->test_proc_trg.auto_trg_enabled = false; + return; + } + + cur->ws_info->test_proc_trg.auto_trg_enabled = true; + + if (cur->nwk_bootstrap_state == ER_ACTIVE_SCAN) { + if (cur->ws_info->trickle_pas_running) { + if (cur->ws_info->test_proc_trg.pas_trigger_timer > seconds) { + cur->ws_info->test_proc_trg.pas_trigger_timer -= seconds; + } else { + if (cur->ws_info->test_proc_trg.pas_trigger_count > 2) { + ws_bootstrap_test_procedure_trigger_exec(cur, PROCEDURE_PAS_TRICKLE_INCON); + } else { + cur->ws_info->test_proc_trg.pas_trigger_count++; + ws_bootstrap_test_procedure_trigger_exec(cur, PROCEDURE_PAS); + } + cur->ws_info->test_proc_trg.pas_trigger_timer = (cur->ws_info->trickle_params_pan_discovery.Imin / 10); + } + if (cur->ws_info->test_proc_trg.eapol_trigger_timer > seconds) { + cur->ws_info->test_proc_trg.eapol_trigger_timer -= seconds; + } else { + ws_bootstrap_test_procedure_trigger_exec(cur, PROCEDURE_EAPOL); + cur->ws_info->test_proc_trg.eapol_trigger_timer = (cur->ws_info->trickle_params_pan_discovery.Imin / 10) / 2; + } + } + } else if (cur->nwk_bootstrap_state == ER_SCAN) { + if (cur->ws_info->trickle_pcs_running) { + if (cur->ws_info->test_proc_trg.pcs_trigger_timer > seconds) { + cur->ws_info->test_proc_trg.pcs_trigger_timer -= seconds; + } else { + if (cur->ws_info->test_proc_trg.pcs_trigger_count > 2) { + ws_bootstrap_test_procedure_trigger_exec(cur, PROCEDURE_PCS_TRICKLE_INCON); + } else { + cur->ws_info->test_proc_trg.pcs_trigger_count++; + ws_bootstrap_test_procedure_trigger_exec(cur, PROCEDURE_PCS); + } + cur->ws_info->test_proc_trg.pcs_trigger_timer = (cur->ws_info->trickle_params_pan_discovery.Imin / 10); + } + } + } else if (cur->nwk_bootstrap_state == ER_RPL_SCAN) { + if (cur->ws_info->test_proc_trg.dis_trigger_timer > seconds) { + cur->ws_info->test_proc_trg.dis_trigger_timer -= seconds; + } else { + ws_bootstrap_test_procedure_trigger_exec(cur, PROCEDURE_DIS); + cur->ws_info->test_proc_trg.dis_trigger_timer_val *= 2; + if (cur->ws_info->test_proc_trg.dis_trigger_timer_val > (WS_RPL_DIS_INITIAL_TIMEOUT / 10) * 4) { + cur->ws_info->test_proc_trg.dis_trigger_timer_val = (WS_RPL_DIS_INITIAL_TIMEOUT / 10) * 4; + } + cur->ws_info->test_proc_trg.dis_trigger_timer = cur->ws_info->test_proc_trg.dis_trigger_timer_val; + } + if (cur->ws_info->test_proc_trg.rpl_trigger_timer > seconds) { + cur->ws_info->test_proc_trg.rpl_trigger_timer -= seconds; + } else { + ws_bootstrap_test_procedure_trigger_exec(cur, PROCEDURE_RPL); + cur->ws_info->test_proc_trg.rpl_trigger_timer_val *= 2; + if (cur->ws_info->test_proc_trg.rpl_trigger_timer_val > (WS_RPL_DIS_INITIAL_TIMEOUT / 10) * 2) { + cur->ws_info->test_proc_trg.rpl_trigger_timer_val = (WS_RPL_DIS_INITIAL_TIMEOUT / 10) * 2; + } + cur->ws_info->test_proc_trg.rpl_trigger_timer = cur->ws_info->test_proc_trg.rpl_trigger_timer_val; + } + } else { + cur->ws_info->test_proc_trg.dis_trigger_timer_val = (WS_RPL_DIS_INITIAL_TIMEOUT / 10) / 2; + cur->ws_info->test_proc_trg.rpl_trigger_timer_val = (WS_RPL_DIS_INITIAL_TIMEOUT / 10) / 2; + cur->ws_info->test_proc_trg.pas_trigger_count = 0; + cur->ws_info->test_proc_trg.pcs_trigger_count = 0; + } +} + #endif //HAVE_WS diff --git a/source/6LoWPAN/ws/ws_bootstrap.h b/source/6LoWPAN/ws/ws_bootstrap.h index 1d41c80a75..8c08a43978 100644 --- a/source/6LoWPAN/ws/ws_bootstrap.h +++ b/source/6LoWPAN/ws/ws_bootstrap.h @@ -26,17 +26,53 @@ typedef enum { WS_OPERATION_START, /**< active operation start*/ WS_ROUTING_READY, /**< RPL routing connected to BR*/ WS_FAST_DISCONNECT, /**< Do fast timeout after Border router timeout*/ - WS_NORMAL_DISCONNECT /**< Border have been rebooted so Slow poison Process*/ + WS_NORMAL_DISCONNECT, /**< Border have been rebooted so Slow poison Process*/ + WS_TEST_PROC_TRIGGER /**< Trigger test procedure */ } ws_bootsrap_event_type_e; +/* Bootstrap internal test procedures, these must match to ws_test_proc_t + on net_ws_test_ext.h */ +typedef enum { + PROCEDURE_DIS, + PROCEDURE_DIO, + PROCEDURE_DAO, + + PROCEDURE_PAS, + PROCEDURE_PA, + PROCEDURE_PCS, + PROCEDURE_PC, + + PROCEDURE_EAPOL, + PROCEDURE_RPL, + PROCEDURE_AUTO_ON, + PROCEDURE_AUTO_OFF, + + /* Above must match to ws_test_proc_t */ + + PROCEDURE_PAS_TRICKLE_INCON, + PROCEDURE_PCS_TRICKLE_INCON + +} ws_bootsrap_procedure_t; + +typedef enum { + WS_PARENT_SOFT_SYNCH = 0, /**< let FHSS make decision if synchronization is needed*/ + WS_PARENT_HARD_SYNCH, /**< Synch FHSS with latest synch information*/ + WS_EAPOL_PARENT_SYNCH, /**< Broadcast synch with EAPOL parent*/ +} ws_parent_synch_e; + #ifdef HAVE_WS +//#include "6LoWPAN/ws/ws_llc.h" +#include "6LoWPAN/ws/ws_common_defines.h" + +struct rpl_instance; struct llc_neighbour_req; -struct ws_us_ie; -struct ws_bs_ie; -struct ws_neighbor_class_entry; struct ws_stack_info; struct ws_neighbour_info; +struct mcps_data_ie_list; +struct mcps_data_ind_s; + +extern uint16_t test_pan_version; int ws_bootstrap_init(int8_t interface_id, net_6lowpan_mode_e bootstrap_mode); @@ -46,25 +82,10 @@ int ws_bootstrap_restart(int8_t interface_id); int ws_bootstrap_restart_delayed(int8_t interface_id); -int ws_bootstrap_set_rf_config(protocol_interface_info_entry_t *cur, phy_rf_channel_configuration_s rf_configs); - int ws_bootstrap_neighbor_remove(protocol_interface_info_entry_t *cur, const uint8_t *ll_address); int ws_bootstrap_aro_failure(protocol_interface_info_entry_t *cur, const uint8_t *ll_address); -/*State machine transactions*/ -void ws_bootstrap_event_discovery_start(protocol_interface_info_entry_t *cur); - -void ws_bootstrap_event_configuration_start(protocol_interface_info_entry_t *cur); - -void ws_bootstrap_event_authentication_start(protocol_interface_info_entry_t *cur); - -void ws_bootstrap_event_operation_start(protocol_interface_info_entry_t *cur); - -void ws_bootstrap_event_routing_ready(protocol_interface_info_entry_t *cur); - -void ws_bootstrap_event_disconnect(protocol_interface_info_entry_t *cur, ws_bootsrap_event_type_e event_type); - void ws_bootstrap_configuration_trickle_reset(protocol_interface_info_entry_t *cur); void ws_bootstrap_seconds_timer(protocol_interface_info_entry_t *cur, uint32_t seconds); @@ -99,6 +120,84 @@ int ws_bootstrap_neighbor_info_get(protocol_interface_info_entry_t *cur, struct void ws_bootstrap_mac_neighbor_short_time_set(struct protocol_interface_info_entry *interface, const uint8_t *src64, uint32_t valid_time); +int ws_bootstrap_test_procedure_trigger(protocol_interface_info_entry_t *cur, ws_bootsrap_procedure_t procedure); + +/* + * Functions shared with different bootstrap modes + */ + +bool ws_bootstrap_network_name_matches(const struct mcps_data_ie_list *ie_ext, const char *network_name_ptr); + +/*State machine transactions*/ +void ws_bootstrap_event_discovery_start(protocol_interface_info_entry_t *cur); + +void ws_bootstrap_event_configuration_start(protocol_interface_info_entry_t *cur); + +void ws_bootstrap_event_authentication_start(protocol_interface_info_entry_t *cur); + +void ws_bootstrap_event_operation_start(protocol_interface_info_entry_t *cur); + +void ws_bootstrap_event_routing_ready(protocol_interface_info_entry_t *cur); + +void ws_bootstrap_event_disconnect(protocol_interface_info_entry_t *cur, ws_bootsrap_event_type_e event_type); + +void ws_bootstrap_test_procedure_trigger_exec(protocol_interface_info_entry_t *cur, ws_bootsrap_procedure_t procedure); + +void ws_bootstrap_network_down(protocol_interface_info_entry_t *cur); + +// Bootstrap functions +void ws_bootstrap_start_authentication(protocol_interface_info_entry_t *cur); + + +// Bootstrap state machine state Functions +bool ws_bootstrap_state_discovery(struct protocol_interface_info_entry *cur); +bool ws_bootstrap_state_authenticate(struct protocol_interface_info_entry *cur); +bool ws_bootstrap_state_configure(struct protocol_interface_info_entry *cur); +bool ws_bootstrap_state_wait_rpl(struct protocol_interface_info_entry *cur); +bool ws_bootstrap_state_active(struct protocol_interface_info_entry *cur); +void ws_bootstrap_state_disconnect(protocol_interface_info_entry_t *cur, ws_bootsrap_event_type_e event_type); +void ws_bootstrap_state_change(protocol_interface_info_entry_t *cur, icmp_state_t nwk_bootstrap_state); + +void ws_bootstrap_candidate_list_clean(struct protocol_interface_info_entry *cur, uint8_t pan_max, uint32_t current_time, uint16_t pan_id); +void ws_bootstrap_candidate_parent_store(parent_info_t *parent, const struct mcps_data_ind_s *data, ws_utt_ie_t *ws_utt, ws_us_ie_t *ws_us, ws_pan_information_t *pan_information); +void ws_bootstrap_candidate_table_reset(protocol_interface_info_entry_t *cur); +parent_info_t *ws_bootstrap_candidate_parent_get(struct protocol_interface_info_entry *cur, const uint8_t *addr, bool create); +void ws_bootstrap_candidate_parent_sort(struct protocol_interface_info_entry *cur, parent_info_t *new_entry); +parent_info_t *ws_bootstrap_candidate_parent_get_best(protocol_interface_info_entry_t *cur); + +void ws_bootstrap_primary_parent_set(struct protocol_interface_info_entry *cur, struct llc_neighbour_req *neighbor_info, ws_parent_synch_e synch_req); +void ws_bootstrap_parent_confirm(protocol_interface_info_entry_t *cur, struct rpl_instance *instance); +bool ws_bootstrap_neighbor_info_request(struct protocol_interface_info_entry *interface, const uint8_t *mac_64, struct llc_neighbour_req *neighbor_buffer, bool request_new); +void ws_bootstrap_neighbor_list_clean(struct protocol_interface_info_entry *interface); +int8_t ws_bootstrap_neighbor_set(protocol_interface_info_entry_t *cur, parent_info_t *parent_ptr, bool clear_list); +void ws_nud_table_reset(protocol_interface_info_entry_t *cur); +void ws_address_registration_update(protocol_interface_info_entry_t *interface, const uint8_t addr[16]); + + +void ws_bootstrap_configure_csma_ca_backoffs(protocol_interface_info_entry_t *cur, uint8_t max_backoffs, uint8_t min_be, uint8_t max_be); +void ws_bootstrap_fhss_configure_channel_masks(protocol_interface_info_entry_t *cur, fhss_ws_configuration_t *fhss_configuration); +int8_t ws_bootstrap_fhss_set_defaults(protocol_interface_info_entry_t *cur, fhss_ws_configuration_t *fhss_configuration); +void ws_bootstrap_fhss_activate(protocol_interface_info_entry_t *cur); +uint16_t ws_bootstrap_randomize_fixed_channel(uint16_t configured_fixed_channel, uint8_t number_of_channels, uint32_t *channel_mask); +int ws_bootstrap_set_domain_rf_config(protocol_interface_info_entry_t *cur); +void ws_bootstrap_configure_max_retries(protocol_interface_info_entry_t *cur, uint8_t max_mac_retries); +void ws_bootstrap_configure_data_request_restart(protocol_interface_info_entry_t *cur, uint8_t cca_failure_restart_max, uint8_t tx_failure_restart_max, uint16_t blacklist_min_ms, uint16_t blacklist_max_ms); + + +void ws_bootstrap_llc_hopping_update(struct protocol_interface_info_entry *cur, const fhss_ws_configuration_t *fhss_configuration); + +void ws_bootstrap_rpl_activate(protocol_interface_info_entry_t *cur); +void ws_bootstrap_rpl_scan_start(protocol_interface_info_entry_t *cur); + +void ws_bootstrap_ip_stack_reset(protocol_interface_info_entry_t *cur); +void ws_bootstrap_ip_stack_activate(protocol_interface_info_entry_t *cur); + +void ws_bootstrap_packet_congestion_init(protocol_interface_info_entry_t *cur); + +void ws_bootstrap_asynch_trickle_stop(protocol_interface_info_entry_t *cur); +void ws_bootstrap_advertise_start(protocol_interface_info_entry_t *cur); + +void ws_bootstrap_network_start(protocol_interface_info_entry_t *cur); #else #define ws_bootstrap_init(interface_id, bootstrap_mode) (-1) @@ -111,6 +210,7 @@ void ws_bootstrap_mac_neighbor_short_time_set(struct protocol_interface_info_ent #define ws_bootstrap_secondary_parent_update(interface) #define ws_bootstrap_stack_info_get(cur, info_ptr) #define ws_bootstrap_neighbor_info_get(cur, neighbor_ptr, count) +#define ws_bootstrap_test_procedure_trigger(cur, procedure); #endif //HAVE_WS diff --git a/source/6LoWPAN/ws/ws_bootstrap_6lbr.c b/source/6LoWPAN/ws/ws_bootstrap_6lbr.c new file mode 100644 index 0000000000..a5e9ac3037 --- /dev/null +++ b/source/6LoWPAN/ws/ws_bootstrap_6lbr.c @@ -0,0 +1,479 @@ +/* + * Copyright (c) 2021, Pelion and affiliates. + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include "nsconfig.h" +#if defined(HAVE_WS) && defined(HAVE_WS_BORDER_ROUTER) +#include "ns_types.h" +#include "ns_trace.h" +#include "nsdynmemLIB.h" +#include "net_interface.h" +#include "eventOS_event.h" +#include "randLIB.h" +#include "common_functions.h" +#include "mac_common_defines.h" +#include "sw_mac.h" +#include "ccmLIB.h" +#include "Core/include/ns_monitor.h" +#include "NWK_INTERFACE/Include/protocol.h" +#include "6LoWPAN/Bootstraps/protocol_6lowpan.h" +#include "6LoWPAN/Bootstraps/protocol_6lowpan_interface.h" +#include "ipv6_stack/protocol_ipv6.h" +#include "ipv6_stack/ipv6_routing_table.h" +#include "6LoWPAN/MAC/mac_helper.h" +#include "6LoWPAN/MAC/mac_data_poll.h" +#include "6LoWPAN/MAC/mpx_api.h" +#include "6LoWPAN/MAC/mac_ie_lib.h" +#include "MPL/mpl.h" +#include "RPL/rpl_protocol.h" +#include "RPL/rpl_control.h" +#include "RPL/rpl_data.h" +#include "RPL/rpl_policy.h" +#include "Common_Protocols/icmpv6.h" +#include "Common_Protocols/icmpv6_radv.h" +#include "Common_Protocols/ipv6_constants.h" +#include "Common_Protocols/ip.h" +#include "Service_Libs/Trickle/trickle.h" +#include "Service_Libs/fhss/channel_list.h" +#include "Service_Libs/utils/ns_time.h" +#include "6LoWPAN/ws/ws_common_defines.h" +#include "6LoWPAN/ws/ws_common_defines.h" +#include "6LoWPAN/ws/ws_config.h" +#include "6LoWPAN/ws/ws_common.h" +#include "6LoWPAN/ws/ws_bootstrap.h" +#include "6LoWPAN/ws/ws_bbr_api_internal.h" +#include "6LoWPAN/ws/ws_common_defines.h" +#include "6LoWPAN/ws/ws_llc.h" +#include "6LoWPAN/ws/ws_neighbor_class.h" +#include "6LoWPAN/ws/ws_ie_lib.h" +#include "6LoWPAN/ws/ws_stats.h" +#include "6LoWPAN/ws/ws_cfg_settings.h" +#include "6LoWPAN/lowpan_adaptation_interface.h" +#include "Service_Libs/etx/etx.h" +#include "Service_Libs/mac_neighbor_table/mac_neighbor_table.h" +#include "Service_Libs/nd_proxy/nd_proxy.h" +#include "Service_Libs/blacklist/blacklist.h" +#include "platform/topo_trace.h" +#include "dhcp_service_api.h" +#include "libDHCPv6/libDHCPv6.h" +#include "libDHCPv6/libDHCPv6_vendordata.h" +#include "DHCPv6_client/dhcpv6_client_api.h" +#include "ws_management_api.h" +#include "net_rpl.h" +#include "mac_api.h" +#include "6LoWPAN/ws/ws_pae_controller.h" +#include "6LoWPAN/ws/ws_eapol_pdu.h" +#include "6LoWPAN/ws/ws_eapol_auth_relay.h" +#include "6LoWPAN/ws/ws_eapol_relay.h" +#include "libNET/src/net_dns_internal.h" +#include "Service_Libs/random_early_detection/random_early_detection_api.h" + + +#define TRACE_GROUP "wsbs" + +static int8_t ws_bootstrap_6lbr_fhss_configure(protocol_interface_info_entry_t *cur) +{ + // Read configuration of existing FHSS and start using the default values for any network + fhss_ws_configuration_t fhss_configuration = ws_common_get_current_fhss_configuration(cur); + //GET BSI from BBR module + fhss_configuration.bsi = ws_bbr_bsi_generate(cur); + ws_bootstrap_fhss_configure_channel_masks(cur, &fhss_configuration); + // Randomize fixed channels. Only used if channel plan is fixed. + cur->ws_info->cfg->fhss.fhss_uc_fixed_channel = ws_bootstrap_randomize_fixed_channel(cur->ws_info->cfg->fhss.fhss_uc_fixed_channel, cur->ws_info->hopping_schdule.number_of_channels, fhss_configuration.channel_mask); + cur->ws_info->cfg->fhss.fhss_bc_fixed_channel = ws_bootstrap_randomize_fixed_channel(cur->ws_info->cfg->fhss.fhss_bc_fixed_channel, cur->ws_info->hopping_schdule.number_of_channels, fhss_configuration.channel_mask); + ws_bootstrap_fhss_set_defaults(cur, &fhss_configuration); + ns_fhss_ws_configuration_set(cur->ws_info->fhss_api, &fhss_configuration); + ws_bootstrap_llc_hopping_update(cur, &fhss_configuration); + + return 0; +} + +static int8_t ws_bootstrap_6lbr_backbone_ip_addr_get(protocol_interface_info_entry_t *interface_ptr, uint8_t *address) +{ + (void) interface_ptr; + (void) address; + + if (ws_bbr_backbone_address_get(address)) { + return 0; + } + + return -1; +} + +static void ws_bootstrap_6lbr_eapol_congestion_init(protocol_interface_info_entry_t *cur) +{ + random_early_detection_free(cur->llc_random_early_detection); + cur->llc_random_early_detection = NULL; + + if (cur->llc_random_early_detection == NULL) { + cur->llc_random_early_detection = random_early_detection_create( + cur->ws_info->cfg->sec_prot.max_simult_sec_neg_tx_queue_min, + cur->ws_info->cfg->sec_prot.max_simult_sec_neg_tx_queue_max, + 100, RED_AVERAGE_WEIGHT_EIGHTH); + } + + random_early_detection_free(cur->llc_eapol_random_early_detection); + cur->llc_eapol_random_early_detection = NULL; + + if (cur->llc_eapol_random_early_detection == NULL) { + cur->llc_eapol_random_early_detection = random_early_detection_create( + cur->ws_info->cfg->sec_prot.max_simult_sec_neg_tx_queue_min, + cur->ws_info->cfg->sec_prot.max_simult_sec_neg_tx_queue_max, + 100, RED_AVERAGE_WEIGHT_EIGHTH); + } +} + +static void ws_bootstrap_6lbr_pan_config_analyse(struct protocol_interface_info_entry *cur, const struct mcps_data_ind_s *data, const struct mcps_data_ie_list *ie_ext, ws_utt_ie_t *ws_utt, ws_us_ie_t *ws_us) +{ + ws_bs_ie_t ws_bs_ie; + ws_bt_ie_t ws_bt_ie; + llc_neighbour_req_t neighbor_info; + + if (data->SrcPANId != cur->ws_info->network_pan_id) { + return; + } + if (!ws_wh_bt_read(ie_ext->headerIeList, ie_ext->headerIeListLength, &ws_bt_ie)) { + tr_warn("BT-IE"); + return; + } + + if (!ws_wp_nested_bs_read(ie_ext->payloadIeList, ie_ext->payloadIeListLength, &ws_bs_ie)) { + // Corrupted + tr_error("No broadcast schedule"); + return; + } + + //If we are border router or learned configuration we only update already learned neighbours. + + if (ws_bootstrap_neighbor_info_request(cur, data->SrcAddr, &neighbor_info, false)) { + //Update Neighbor Broadcast and Unicast Parameters + ws_neighbor_class_neighbor_unicast_time_info_update(neighbor_info.ws_neighbor, ws_utt, data->timestamp, (uint8_t *) data->SrcAddr); + ws_neighbor_class_neighbor_unicast_schedule_set(neighbor_info.ws_neighbor, ws_us, &cur->ws_info->hopping_schdule); + ws_neighbor_class_neighbor_broadcast_time_info_update(neighbor_info.ws_neighbor, &ws_bt_ie, data->timestamp); + ws_neighbor_class_neighbor_broadcast_schedule_set(neighbor_info.ws_neighbor, &ws_bs_ie); + } +} + +static void ws_bootstrap_6lbr_pan_config_solicit_analyse(struct protocol_interface_info_entry *cur, const struct mcps_data_ind_s *data, ws_utt_ie_t *ws_utt, ws_us_ie_t *ws_us) +{ + llc_neighbour_req_t neighbor_info; + + if (data->SrcPANId != cur->ws_info->network_pan_id) { + return; + } + + if (ws_bootstrap_neighbor_info_request(cur, data->SrcAddr, &neighbor_info, false)) { + ws_neighbor_class_neighbor_unicast_time_info_update(neighbor_info.ws_neighbor, ws_utt, data->timestamp, (uint8_t *) data->SrcAddr); + ws_neighbor_class_neighbor_unicast_schedule_set(neighbor_info.ws_neighbor, ws_us, &cur->ws_info->hopping_schdule); + } +} + +void ws_bootstrap_6lbr_asynch_ind(struct protocol_interface_info_entry *cur, const struct mcps_data_ind_s *data, const struct mcps_data_ie_list *ie_ext, uint8_t message_type) +{ + // Store weakest heard packet RSSI + if (cur->ws_info->weakest_received_rssi > data->signal_dbm) { + cur->ws_info->weakest_received_rssi = data->signal_dbm; + } + + if (data->SrcAddrMode != MAC_ADDR_MODE_64_BIT) { + // Not from long address + return; + } + ws_stats_update(cur, STATS_WS_ASYNCH_RX, 1); + //Validate network name + switch (message_type) { + case WS_FT_PAN_ADVERT: + case WS_FT_PAN_ADVERT_SOL: + case WS_FT_PAN_CONF_SOL: + //Check Network Name + if (!ws_bootstrap_network_name_matches(ie_ext, cur->ws_info->cfg->gen.network_name)) { + // Not in our network + return; + } + break; + case WS_FT_PAN_CONF: + break; + default: + return; + } + //UTT-IE and US-IE are mandatory for all Asynch Messages + ws_utt_ie_t ws_utt; + if (!ws_wh_utt_read(ie_ext->headerIeList, ie_ext->headerIeListLength, &ws_utt)) { + // Corrupted + return; + } + + ws_us_ie_t ws_us; + if (!ws_wp_nested_us_read(ie_ext->payloadIeList, ie_ext->payloadIeListLength, &ws_us)) { + // Corrupted + return; + } + + if (!ws_bootstrap_validate_channel_plan(&ws_us, cur) || + !ws_bootstrap_validate_channel_function(&ws_us, NULL)) { + return; + } + + //Handle Message's + switch (message_type) { + case WS_FT_PAN_ADVERT: + // Analyse Advertisement + ws_stats_update(cur, STATS_WS_ASYNCH_RX_PA, 1); + tr_info("received ADVERT Src:%s panid:%x rssi:%d", trace_array(data->SrcAddr, 8), data->SrcPANId, data->signal_dbm); + // Border routers do not do any analysing on the Advertisements heard from others + // in future if we need PANID conflict detection we could use this + break; + case WS_FT_PAN_ADVERT_SOL: + ws_stats_update(cur, STATS_WS_ASYNCH_RX_PAS, 1); + tr_info("received ADVERT SOL Src:%s rssi:%d", trace_array(data->SrcAddr, 8), data->signal_dbm); + trickle_inconsistent_heard(&cur->ws_info->trickle_pan_advertisement, &cur->ws_info->trickle_params_pan_discovery); + + break; + case WS_FT_PAN_CONF: + ws_stats_update(cur, STATS_WS_ASYNCH_RX_PC, 1); + tr_info("received CONFIG Src:%s rssi:%d", trace_array(data->SrcAddr, 8), data->signal_dbm); + ws_bootstrap_6lbr_pan_config_analyse(cur, data, ie_ext, &ws_utt, &ws_us); + break; + case WS_FT_PAN_CONF_SOL: + ws_stats_update(cur, STATS_WS_ASYNCH_RX_PCS, 1); + tr_info("received CONFIG SOL Src:%s rssi:%d", trace_array(data->SrcAddr, 8), data->signal_dbm); + trickle_inconsistent_heard(&cur->ws_info->trickle_pan_config, &cur->ws_info->trickle_params_pan_discovery); + ws_bootstrap_6lbr_pan_config_solicit_analyse(cur, data, &ws_utt, &ws_us); + default: + // Unknown message do not process + break; + } +} + +void ws_bootstrap_6lbr_asynch_confirm(struct protocol_interface_info_entry *interface, uint8_t asynch_message) +{ + ws_stats_update(interface, STATS_WS_ASYNCH_TX, 1); + if (interface->bootsrap_mode == ARM_NWK_BOOTSRAP_MODE_6LoWPAN_BORDER_ROUTER) { + if (asynch_message == WS_FT_PAN_CONF && interface->ws_info->pending_key_index_info.state == PENDING_KEY_INDEX_ACTIVATE) { + interface->ws_info->pending_key_index_info.state = NO_PENDING_PROCESS; + tr_info("Activate new default key %u", interface->ws_info->pending_key_index_info.index + 1); + mac_helper_security_auto_request_key_index_set(interface, interface->ws_info->pending_key_index_info.index, interface->ws_info->pending_key_index_info.index + 1); + } + } +} + +void ws_bootstrap_6lbr_event_handler(protocol_interface_info_entry_t *cur, arm_event_s *event) +{ + ws_bootsrap_event_type_e event_type; + event_type = (ws_bootsrap_event_type_e)event->event_type; + + switch (event_type) { + case WS_INIT_EVENT: + tr_debug("tasklet init"); + break; + case WS_DISCOVERY_START: + tr_info("Discovery start"); + protocol_mac_reset(cur); + ws_llc_reset(cur); + lowpan_adaptation_interface_reset(cur->id); + //Clear Pending Key Index State + cur->ws_info->pending_key_index_info.state = NO_PENDING_PROCESS; + cur->mac_parameters->mac_default_key_index = 0; + + ipv6_destination_cache_clean(cur->id); + + // Clear parent blacklist + blacklist_clear(); + + // All trickle timers stopped to allow entry from any state + ws_bootstrap_asynch_trickle_stop(cur); + //Init Packet congestion + ws_bootstrap_packet_congestion_init(cur); + + tr_info("Border router start network"); + + + if (!ws_bbr_ready_to_start(cur)) { + // Wi-SUN not started yet we wait for Border router permission + ws_bootstrap_state_change(cur, ER_WAIT_RESTART); + cur->nwk_nd_re_scan_count = randLIB_get_random_in_range(40, 100); + return; + } + // Clear Old information from stack + cur->ws_info->network_pan_id = 0xffff; + cur->ws_info->pan_information.pan_version_set = false; + ws_nud_table_reset(cur); + ws_bootstrap_neighbor_list_clean(cur); + ws_bootstrap_ip_stack_reset(cur); + ws_pae_controller_auth_init(cur); + + uint16_t pan_id = ws_bbr_pan_id_get(cur); + if (pan_id != 0xffff) { + cur->ws_info->network_pan_id = pan_id; + } else { + if (cur->ws_info->network_pan_id == 0xffff) { + cur->ws_info->network_pan_id = randLIB_get_random_in_range(0, 0xfffd); + } + } + if (!cur->ws_info->pan_information.pan_version_set) { + cur->ws_info->pan_information.pan_version = randLIB_get_random_in_range(0, 0xffff); + cur->ws_info->pan_information.pan_version_set = true; + } + cur->ws_info->pan_information.pan_size = 0; + cur->ws_info->pan_information.routing_cost = 0; + cur->ws_info->pan_information.rpl_routing_method = true; + cur->ws_info->pan_information.use_parent_bs = true; + cur->ws_info->pan_information.version = WS_FAN_VERSION_1_0; + // initialize for FAN 1.1 defaults + if (ws_version_1_1(cur)) { + cur->ws_info->pan_information.version = WS_FAN_VERSION_1_1; +#ifdef HAVE_WS_VERSION_1_1 + if (!cur->ws_info->lfngtk.lfn_version_learned) { + //Randomize LFN version + cur->ws_info->lfngtk.lfn_version = randLIB_get_random_in_range(0, 0xffff); + cur->ws_info->lfngtk.lfn_version_learned = true; + } +#endif + } + + uint8_t *gtkhash = ws_pae_controller_gtk_hash_ptr_get(cur); + ws_llc_set_gtkhash(cur, gtkhash); + ws_bbr_pan_version_increase(cur); + + // Set default parameters for FHSS when starting a discovery + ws_common_regulatory_domain_config(cur, &cur->ws_info->hopping_schdule); + ws_bootstrap_6lbr_fhss_configure(cur); + ws_bootstrap_set_domain_rf_config(cur); + ws_bootstrap_fhss_activate(cur); + ns_fhss_ws_set_hop_count(cur->ws_info->fhss_api, 0); + + uint8_t ll_addr[16]; + addr_interface_get_ll_address(cur, ll_addr, 1); + + //SET EAPOL authenticator EUI64 + ws_pae_controller_border_router_addr_write(cur, cur->mac); + + // Set EAPOL relay to port 10255 and authenticator relay to 10253 (and to own ll address) + ws_eapol_relay_start(cur, BR_EAPOL_RELAY_SOCKET_PORT, ll_addr, EAPOL_RELAY_SOCKET_PORT); + + // Set authenticator relay to port 10253 and PAE to 10254 (and to own ll address) + ws_eapol_auth_relay_start(cur, EAPOL_RELAY_SOCKET_PORT, ll_addr, PAE_AUTH_SOCKET_PORT); + + // Set PAN ID and network name to controller + ws_pae_controller_nw_info_set(cur, cur->ws_info->network_pan_id, cur->ws_info->pan_information.pan_version, cur->ws_info->cfg->gen.network_name); + + // Set backbone IP address get callback + ws_pae_controller_auth_cb_register(cur, ws_bootstrap_6lbr_backbone_ip_addr_get); + + // Set PAE port to 10254 and authenticator relay to 10253 (and to own ll address) + ws_pae_controller_authenticator_start(cur, PAE_AUTH_SOCKET_PORT, ll_addr, EAPOL_RELAY_SOCKET_PORT); + + // Initialize eapol congestion tracking + ws_bootstrap_6lbr_eapol_congestion_init(cur); + + // Set retry configuration for bootstrap ready state + ws_bootstrap_configure_max_retries(cur, WS_MAX_FRAME_RETRIES); + + // Set TX failure request restart configuration + ws_bootstrap_configure_data_request_restart(cur, WS_CCA_REQUEST_RESTART_MAX, WS_TX_REQUEST_RESTART_MAX, WS_REQUEST_RESTART_BLACKLIST_MIN, WS_REQUEST_RESTART_BLACKLIST_MAX); + + // Set CSMA-CA backoff configuration + ws_bootstrap_configure_csma_ca_backoffs(cur, WS_MAX_CSMA_BACKOFFS, WS_MAC_MIN_BE, WS_MAC_MAX_BE); + + ws_bootstrap_event_operation_start(cur); + break; + + case WS_CONFIGURATION_START: + tr_info("6LBR Configuration start"); + break; + case WS_OPERATION_START: + tr_info("operation start"); + // Advertisements stopped during the RPL scan + ws_bootstrap_asynch_trickle_stop(cur); + // Activate RPL + // Activate IPv6 stack + ws_bootstrap_ip_stack_activate(cur); + ws_bootstrap_rpl_activate(cur); + ws_bootstrap_network_start(cur); + // Wait for RPL start + ws_bootstrap_event_routing_ready(cur); + break; + case WS_ROUTING_READY: + tr_info("Routing ready"); + // stopped all to make sure we can enter here from any state + ws_bootstrap_asynch_trickle_stop(cur); + + // Indicate PAE controller that bootstrap is ready + ws_pae_controller_bootstrap_done(cur); + + ws_bootstrap_advertise_start(cur); + ws_bootstrap_state_change(cur, ER_BOOTSRAP_DONE); + break; + case WS_FAST_DISCONNECT: + ws_bootstrap_state_disconnect(cur, WS_FAST_DISCONNECT); + break; + case WS_NORMAL_DISCONNECT: + ws_bootstrap_state_disconnect(cur, WS_NORMAL_DISCONNECT); + break; + + case WS_TEST_PROC_TRIGGER: + ws_bootstrap_test_procedure_trigger_exec(cur, (ws_bootsrap_procedure_t) event->data_ptr); + break; + + default: + tr_err("Invalid event received"); + break; + } +} + +void ws_bootstrap_6lbr_state_machine(protocol_interface_info_entry_t *cur) +{ + + switch (cur->nwk_bootstrap_state) { + case ER_WAIT_RESTART: + tr_debug("WS SM:Wait for startup"); + ws_bootstrap_event_discovery_start(cur); + break; + case ER_ACTIVE_SCAN: + tr_debug("WS SM:Active Scan"); + break; + case ER_SCAN: + tr_debug("WS SM:configuration Scan"); + break; + case ER_PANA_AUTH: + tr_info("authentication start"); + break; + case ER_RPL_SCAN: + tr_debug("WS SM:Wait RPL to contact DODAG root"); + break; + case ER_BOOTSRAP_DONE: + tr_info("WS SM:Bootstrap Done"); + // Bootstrap_done event to application + nwk_bootsrap_state_update(ARM_NWK_BOOTSTRAP_READY, cur); + break; + case ER_RPL_NETWORK_LEAVING: + tr_debug("WS SM:RPL Leaving ready trigger discovery"); + ws_bootstrap_event_discovery_start(cur); + break; + default: + tr_warn("WS SM:Invalid state %d", cur->nwk_bootstrap_state); + } +} + +void ws_bootstrap_6lbr_seconds_timer(protocol_interface_info_entry_t *cur, uint32_t seconds) +{ + (void)cur; + (void)seconds; +} + + +#endif //HAVE_WS_BORDER_ROUTER && HAVE_WS diff --git a/source/6LoWPAN/ws/ws_bootstrap_6lbr.h b/source/6LoWPAN/ws/ws_bootstrap_6lbr.h new file mode 100644 index 0000000000..5517793fb5 --- /dev/null +++ b/source/6LoWPAN/ws/ws_bootstrap_6lbr.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2021, Pelion and affiliates. + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef WS_BOOTSTRAP_6LBR_H_ +#define WS_BOOTSTRAP_6LBR_H_ + +#if defined(HAVE_WS) && defined(HAVE_WS_BORDER_ROUTER) + +void ws_bootstrap_6lbr_asynch_ind(struct protocol_interface_info_entry *cur, const struct mcps_data_ind_s *data, const struct mcps_data_ie_list *ie_ext, uint8_t message_type); +void ws_bootstrap_6lbr_asynch_confirm(struct protocol_interface_info_entry *interface, uint8_t asynch_message); +void ws_bootstrap_6lbr_event_handler(protocol_interface_info_entry_t *cur, arm_event_s *event); +void ws_bootstrap_6lbr_state_machine(protocol_interface_info_entry_t *cur); +void ws_bootstrap_6lbr_seconds_timer(protocol_interface_info_entry_t *cur, uint32_t seconds); + +#define wisun_mode_border_router(cur) (cur->bootsrap_mode == ARM_NWK_BOOTSRAP_MODE_6LoWPAN_BORDER_ROUTER) + +#else + +#define ws_bootstrap_6lbr_asynch_ind(cur, data, ie_ext, message_type) ((void) 0) +#define ws_bootstrap_6lbr_asynch_confirm(interface, asynch_message) ((void) 0) +#define ws_bootstrap_6lbr_event_handler(cur, event) ((void) 0) +#define ws_bootstrap_6lbr_state_machine(cur) ((void) 0) +#define ws_bootstrap_6lbr_seconds_timer(cur, seconds) ((void) 0) + +#define wisun_mode_border_router(cur) (false) + +#endif //HAVE_WS + +#endif /* WS_BOOTSTRAP_H_ */ diff --git a/source/6LoWPAN/ws/ws_bootstrap_ffn.c b/source/6LoWPAN/ws/ws_bootstrap_ffn.c new file mode 100644 index 0000000000..489039abff --- /dev/null +++ b/source/6LoWPAN/ws/ws_bootstrap_ffn.c @@ -0,0 +1,1027 @@ +/* + * Copyright (c) 2021, Pelion and affiliates. + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include "nsconfig.h" +#if defined(HAVE_WS) && defined(HAVE_WS_ROUTER) +#include "ns_types.h" +#include "ns_trace.h" +#include "nsdynmemLIB.h" +#include "net_interface.h" +#include "eventOS_event.h" +#include "randLIB.h" +#include "common_functions.h" +#include "mac_common_defines.h" +#include "sw_mac.h" +#include "ccmLIB.h" +#include "Core/include/ns_monitor.h" +#include "NWK_INTERFACE/Include/protocol.h" +#include "6LoWPAN/Bootstraps/protocol_6lowpan.h" +#include "6LoWPAN/Bootstraps/protocol_6lowpan_interface.h" +#include "ipv6_stack/protocol_ipv6.h" +#include "ipv6_stack/ipv6_routing_table.h" +#include "6LoWPAN/MAC/mac_helper.h" +#include "6LoWPAN/MAC/mac_data_poll.h" +#include "6LoWPAN/MAC/mpx_api.h" +#include "6LoWPAN/MAC/mac_ie_lib.h" +#include "MPL/mpl.h" +#include "RPL/rpl_protocol.h" +#include "RPL/rpl_control.h" +#include "RPL/rpl_data.h" +#include "RPL/rpl_policy.h" +#include "Common_Protocols/icmpv6.h" +#include "Common_Protocols/icmpv6_radv.h" +#include "Common_Protocols/ipv6_constants.h" +#include "Common_Protocols/ip.h" +#include "Service_Libs/Trickle/trickle.h" +#include "Service_Libs/fhss/channel_list.h" +#include "Service_Libs/utils/ns_time.h" +#include "6LoWPAN/ws/ws_common_defines.h" +#include "6LoWPAN/ws/ws_common_defines.h" +#include "6LoWPAN/ws/ws_config.h" +#include "6LoWPAN/ws/ws_common.h" +#include "6LoWPAN/ws/ws_bootstrap.h" +#include "6LoWPAN/ws/ws_bbr_api_internal.h" +#include "6LoWPAN/ws/ws_common_defines.h" +#include "6LoWPAN/ws/ws_llc.h" +#include "6LoWPAN/ws/ws_neighbor_class.h" +#include "6LoWPAN/ws/ws_ie_lib.h" +#include "6LoWPAN/ws/ws_stats.h" +#include "6LoWPAN/ws/ws_cfg_settings.h" +#include "6LoWPAN/lowpan_adaptation_interface.h" +#include "Service_Libs/etx/etx.h" +#include "Service_Libs/mac_neighbor_table/mac_neighbor_table.h" +#include "Service_Libs/nd_proxy/nd_proxy.h" +#include "Service_Libs/blacklist/blacklist.h" +#include "platform/topo_trace.h" +#include "dhcp_service_api.h" +#include "libDHCPv6/libDHCPv6.h" +#include "libDHCPv6/libDHCPv6_vendordata.h" +#include "DHCPv6_client/dhcpv6_client_api.h" +#include "ws_management_api.h" +#include "net_rpl.h" +#include "mac_api.h" +#include "6LoWPAN/ws/ws_pae_controller.h" +#include "6LoWPAN/ws/ws_eapol_pdu.h" +#include "6LoWPAN/ws/ws_eapol_auth_relay.h" +#include "6LoWPAN/ws/ws_eapol_relay.h" +#include "libNET/src/net_dns_internal.h" +#include "Service_Libs/random_early_detection/random_early_detection_api.h" + +#define TRACE_GROUP "wsbs" + +static void ws_bootstrap_ffn_ip_stack_addr_clear(protocol_interface_info_entry_t *cur) +{ + tr_debug("ip stack address clear"); + ns_list_foreach_safe(if_address_entry_t, addr, &cur->ip_addresses) { + if (addr->source != ADDR_SOURCE_STATIC && + addr_ipv6_scope(addr->address, cur) > IPV6_SCOPE_LINK_LOCAL) { + // Remove all exept User set address + addr_delete_entry(cur, addr); + } + } +} + +static void ws_bootstrap_ffn_pan_information_store(struct protocol_interface_info_entry *cur, const struct mcps_data_ind_s *data, ws_utt_ie_t *ws_utt, ws_us_ie_t *ws_us, ws_pan_information_t *pan_information) +{ + + parent_info_t *new_entry; + /* Have List of 20 heard neighbours + * Order those as best based on pan cost + * In single pan order based on signal quality + * in single PAN limit the amount of devices to 5 + * If there is no advertisement heard for last hour Clear the neigbour. + */ + + // Discovery state processing + //tr_info("neighbour: addr:%s panid:%x signal:%d", trace_array(data->SrcAddr, 8), data->SrcPANId, data->signal_dbm); + + // Clean old entries + ws_bootstrap_candidate_list_clean(cur, WS_PARENT_LIST_MAX_PAN_IN_DISCOVERY, protocol_core_monotonic_time, data->SrcPANId); + + new_entry = ws_bootstrap_candidate_parent_get(cur, data->SrcAddr, true); + if (!new_entry) { + tr_warn("neighbour creation fail"); + return; + } + // Safe the information + ws_bootstrap_candidate_parent_store(new_entry, data, ws_utt, ws_us, pan_information); + if (!new_entry->link_acceptable) { + // This entry is either poor quality or changed to poor quality link so we will remove this + // Todo in future possibility to try poor link parents if we have not found any good link parents + tr_info("neighbour not accepted: addr:%s panid:%x rsl:%d device_min_sens: %d", trace_array(new_entry->addr, 8), new_entry->pan_id, ws_neighbor_class_rsl_from_dbm_calculate(new_entry->signal_dbm), DEVICE_MIN_SENS); + ns_list_remove(&cur->ws_info->parent_list_reserved, new_entry); + ns_list_add_to_end(&cur->ws_info->parent_list_free, new_entry); + return; + } + // set to the correct place in list + ws_bootstrap_candidate_parent_sort(cur, new_entry); + + return; +} + +static int8_t ws_bootstrap_ffn_fhss_configure(protocol_interface_info_entry_t *cur, bool discovery) +{ + // Read configuration of existing FHSS and start using the default values for any network + fhss_ws_configuration_t fhss_configuration = ws_common_get_current_fhss_configuration(cur); + ws_bootstrap_fhss_set_defaults(cur, &fhss_configuration); + ws_bootstrap_fhss_configure_channel_masks(cur, &fhss_configuration); + + // Discovery is done using fixed channel + if (discovery) { + fhss_configuration.ws_uc_channel_function = WS_FIXED_CHANNEL; + } else { + fhss_configuration.ws_uc_channel_function = (fhss_ws_channel_functions)cur->ws_info->cfg->fhss.fhss_uc_channel_function; + } + fhss_configuration.ws_bc_channel_function = WS_FIXED_CHANNEL; + fhss_configuration.fhss_broadcast_interval = 0; + uint8_t tmp_uc_fixed_channel = ws_bootstrap_randomize_fixed_channel(cur->ws_info->cfg->fhss.fhss_uc_fixed_channel, cur->ws_info->hopping_schdule.number_of_channels, fhss_configuration.channel_mask); + uint8_t tmp_bc_fixed_channel = ws_bootstrap_randomize_fixed_channel(cur->ws_info->cfg->fhss.fhss_bc_fixed_channel, cur->ws_info->hopping_schdule.number_of_channels, fhss_configuration.channel_mask); + fhss_configuration.unicast_fixed_channel = tmp_uc_fixed_channel; + fhss_configuration.broadcast_fixed_channel = tmp_bc_fixed_channel; + ns_fhss_ws_configuration_set(cur->ws_info->fhss_api, &fhss_configuration); + ns_fhss_ws_set_hop_count(cur->ws_info->fhss_api, 0xff); + ws_bootstrap_llc_hopping_update(cur, &fhss_configuration); + + return 0; +} + +void ws_bootstrap_ffn_network_discovery_configure(protocol_interface_info_entry_t *cur) +{ + // Reset information to defaults + cur->ws_info->network_pan_id = 0xffff; + + ws_common_regulatory_domain_config(cur, &cur->ws_info->hopping_schdule); + ws_bootstrap_set_domain_rf_config(cur); + ws_bootstrap_ffn_fhss_configure(cur, true); + + //Set Network names, Pan information configure, hopping schedule & GTKHash + ws_llc_set_network_name(cur, (uint8_t *)cur->ws_info->cfg->gen.network_name, strlen(cur->ws_info->cfg->gen.network_name)); +} + +// Start network scan +static void ws_bootstrap_ffn_start_discovery(protocol_interface_info_entry_t *cur) +{ + tr_debug("router discovery start"); + // Remove network keys from MAC + ws_pae_controller_nw_keys_remove(cur); + ws_bootstrap_state_change(cur, ER_ACTIVE_SCAN); + cur->nwk_nd_re_scan_count = 0; + cur->ws_info->configuration_learned = false; + cur->ws_info->pan_timeout_timer = 0; + cur->ws_info->weakest_received_rssi = 0; + + // Clear learned candidate parents + ws_bootstrap_candidate_table_reset(cur); + + // Clear RPL information + rpl_control_free_domain_instances_from_interface(cur); + // Clear EAPOL relay address + ws_eapol_relay_delete(cur); + + // Clear ip stack from old information + ws_bootstrap_ip_stack_reset(cur); + // New network scan started old addresses not assumed valid anymore + ws_bootstrap_ffn_ip_stack_addr_clear(cur); + + if ((cur->lowpan_info & INTERFACE_NWK_BOOTSRAP_ACTIVE) != INTERFACE_NWK_BOOTSRAP_ACTIVE) { + // we have sent bootstrap ready event and now + // restarted discovery so bootstrap down event is sent + cur->lowpan_info |= INTERFACE_NWK_BOOTSRAP_ACTIVE; + ws_bootstrap_network_down(cur); + } + + // Start advertisement solicit trickle and calculate when we are checking the status + cur->ws_info->trickle_pas_running = true; + if (cur->ws_info->trickle_pan_advertisement_solicit.I != cur->ws_info->trickle_params_pan_discovery.Imin) { + // Trickle not reseted so starting a new interval + trickle_start(&cur->ws_info->trickle_pan_advertisement_solicit, &cur->ws_info->trickle_params_pan_discovery); + } + + // Discovery statemachine is checkked after we have sent the Solicit + uint32_t time_to_solicit = 0; + if (cur->ws_info->trickle_pan_advertisement_solicit.t > cur->ws_info->trickle_pan_advertisement_solicit.now) { + time_to_solicit = cur->ws_info->trickle_pan_advertisement_solicit.t - cur->ws_info->trickle_pan_advertisement_solicit.now; + } + + tr_debug("Disc params imin %u, imax %u, expirations %u, k %u PAS Trickle I %u t %u, now %u, c %u", + cur->ws_info->trickle_params_pan_discovery.Imin, cur->ws_info->trickle_params_pan_discovery.Imax, cur->ws_info->trickle_params_pan_discovery.TimerExpirations, cur->ws_info->trickle_params_pan_discovery.k, + cur->ws_info->trickle_pan_advertisement_solicit.I, cur->ws_info->trickle_pan_advertisement_solicit.t, cur->ws_info->trickle_pan_advertisement_solicit.now, cur->ws_info->trickle_pan_advertisement_solicit.c); + + time_to_solicit += cur->ws_info->trickle_params_pan_discovery.Imin + randLIB_get_random_in_range(0, cur->ws_info->trickle_params_pan_discovery.Imin); + + if (time_to_solicit > 0xffff) { + time_to_solicit = 0xffff; + } + cur->bootsrap_state_machine_cnt = time_to_solicit; + + tr_info("Making parent selection in %u s", (cur->bootsrap_state_machine_cnt / 10)); +} + +// Start configuration learning +static void ws_bootstrap_ffn_start_configuration_learn(protocol_interface_info_entry_t *cur) +{ + tr_debug("router configuration learn start"); + ws_bootstrap_state_change(cur, ER_SCAN); + + cur->ws_info->configuration_learned = false; + + // Clear all temporary information + ws_bootstrap_ip_stack_reset(cur); + + cur->ws_info->pas_requests = 0; + //Calculate max time for config learn state + cur->ws_info->pan_config_sol_max_timeout = trickle_timer_max(&cur->ws_info->trickle_params_pan_discovery, PCS_MAX); + // Reset advertisement solicit trickle to start discovering network + cur->ws_info->trickle_pcs_running = true; + trickle_start(&cur->ws_info->trickle_pan_config_solicit, &cur->ws_info->trickle_params_pan_discovery); + trickle_inconsistent_heard(&cur->ws_info->trickle_pan_config_solicit, &cur->ws_info->trickle_params_pan_discovery); +} + +static void ws_bootstrap_ffn_network_configuration_learn(protocol_interface_info_entry_t *cur) +{ + tr_debug("Start using PAN configuration"); + + // Timing information can be modified here + ws_llc_set_pan_information_pointer(cur, &cur->ws_info->pan_information); + uint8_t *gtkhash = ws_pae_controller_gtk_hash_ptr_get(cur); + ws_llc_set_gtkhash(cur, gtkhash); + // TODO update own fhss schedules we are starting to follow first parent + + return; +} + +static void ws_bootstrap_ffn_pan_advertisement_analyse_active(struct protocol_interface_info_entry *cur, ws_pan_information_t *pan_information) +{ + /* In Active state + * + * A consistent transmission is defined as a PAN Advertisement received by a node with PAN ID and + * NETNAME-IE / Network Name matching that of the receiving node, and with a PAN-IE / Routing Cost + * the same or worse than (bigger than or equal to) that of the receiving node. + * + * Inconsistent: + * + * Received Routing Cost is smaller than stored one + * + * A PAN Advertisement received by a node with PAN ID and NETNAME-IE / Network name matching + * that of the receiving node, and PAN-IE / Routing Cost better than (smaller than) that of the receiving node. + * + */ + if (cur->bootsrap_mode == ARM_NWK_BOOTSRAP_MODE_6LoWPAN_BORDER_ROUTER) { + //Border router never set consistent that will guarantee that BR will send advertisment + return; + } +#ifdef WISUN_1_0_ERRATA_FIX + if (pan_information->pan_size == cur->ws_info->pan_information.pan_size) { + //If same pan size information then set consistent value + trickle_consistent_heard(&cur->ws_info->trickle_pan_advertisement); + } +#else + // Wi-SUN 1.0 specified functionality, causes extra inconsistencies when we hear higher rank advertisements + if (pan_information->routing_cost >= ws_bootstrap_routing_cost_calculate(cur)) { + trickle_consistent_heard(&cur->ws_info->trickle_pan_advertisement); + } else { + trickle_inconsistent_heard(&cur->ws_info->trickle_pan_advertisement, &cur->ws_info->trickle_params_pan_discovery); + } +#endif +} + +static void ws_bootstrap_ffn_pan_advertisement_analyse(struct protocol_interface_info_entry *cur, const struct mcps_data_ind_s *data, const struct mcps_data_ie_list *ie_ext, ws_utt_ie_t *ws_utt, ws_us_ie_t *ws_us) +{ + + //Validate Pan Conrfirmation is at packet + ws_pan_information_t pan_information; + if (!ws_wp_nested_pan_read(ie_ext->payloadIeList, ie_ext->payloadIeListLength, &pan_information)) { + // Corrupted + tr_error("No pan information"); + return; + } + + if (ws_us->excluded_channel_ctrl) { + //Validate that we can storage data + if (ws_us->excluded_channel_ctrl == WS_EXC_CHAN_CTRL_BITMASK && ws_us->excluded_channels.mask.mask_len_inline > 32) { + return; + } + } + + // Check pan flags so that it is valid + if (!pan_information.rpl_routing_method) { + // NOT RPL routing + //tr_warn("Not supported routing"); + return; + } + + // Store heard pans and possible candidate parents + ws_bootstrap_ffn_pan_information_store(cur, data, ws_utt, ws_us, &pan_information); + + if (!(ws_bootstrap_state_active(cur) || + ws_bootstrap_state_wait_rpl(cur))) { + // During discovery/eapol/config learn we dont do further processing for advertisements + return; + } + // Active state processing + //tr_debug("Advertisement active"); + + // In active operation less neighbours per pan is allowed + ws_bootstrap_candidate_list_clean(cur, WS_PARENT_LIST_MAX_PAN_IN_ACTIVE, protocol_core_monotonic_time, data->SrcPANId); + + // Check if valid PAN + if (data->SrcPANId != cur->ws_info->network_pan_id) { + return; + } + + // Save route cost for all known neighbors + llc_neighbour_req_t neighbor_info; + neighbor_info.neighbor = NULL; + if (ws_bootstrap_neighbor_info_request(cur, data->SrcAddr, &neighbor_info, false)) { + neighbor_info.ws_neighbor->routing_cost = pan_information.routing_cost; + //Store and search neighbour PCAP info + if (ws_version_1_1(cur)) { + ws_neighbor_class_pcap_ie_store(neighbor_info.ws_neighbor, ie_ext); + } + } + + ws_bootstrap_ffn_pan_advertisement_analyse_active(cur, &pan_information); + + // Learn latest network information + if (cur->bootsrap_mode != ARM_NWK_BOOTSRAP_MODE_6LoWPAN_BORDER_ROUTER && neighbor_info.neighbor) { + uint8_t ll_address[16]; + ws_common_create_ll_address(ll_address, neighbor_info.neighbor->mac64); + + if (rpl_control_is_dodag_parent(cur, ll_address)) { + cur->ws_info->pan_information.pan_size = pan_information.pan_size; + cur->ws_info->pan_information.routing_cost = pan_information.routing_cost; + cur->ws_info->pan_information.rpl_routing_method = pan_information.rpl_routing_method; + cur->ws_info->pan_information.use_parent_bs = pan_information.use_parent_bs; + } + } +} + +static void ws_bootstrap_ffn_pan_advertisement_solicit_analyse(struct protocol_interface_info_entry *cur, const struct mcps_data_ind_s *data, ws_utt_ie_t *ws_utt, ws_us_ie_t *ws_us) +{ + + (void)data; + (void)ws_utt; + (void)ws_us; + /* + * An inconsistent transmission is defined as: + * A PAN Advertisement Solicit with NETNAME-IE matching that of the receiving node. + */ + trickle_inconsistent_heard(&cur->ws_info->trickle_pan_advertisement, &cur->ws_info->trickle_params_pan_discovery); + /* + * A consistent transmission is defined as + * a PAN Advertisement Solicit with NETNAME-IE / Network Name matching that configured on the receiving node. + */ + trickle_consistent_heard(&cur->ws_info->trickle_pan_advertisement_solicit); + /* + * Optimized PAN discovery to select the parent faster if we hear solicit from someone else + */ + + if (ws_bootstrap_state_discovery(cur) && ws_cfg_network_config_get(cur) <= CONFIG_MEDIUM && + cur->bootsrap_state_machine_cnt > cur->ws_info->trickle_params_pan_discovery.Imin * 2) { + + cur->bootsrap_state_machine_cnt = cur->ws_info->trickle_params_pan_discovery.Imin + randLIB_get_random_in_range(0, cur->ws_info->trickle_params_pan_discovery.Imin); + + tr_info("Making parent selection in %u s", (cur->bootsrap_state_machine_cnt / 10)); + } + + if (ws_bootstrap_state_active(cur) && cur->bootsrap_mode != ARM_NWK_BOOTSRAP_MODE_6LoWPAN_BORDER_ROUTER) { + mac_neighbor_table_entry_t *neighbor = mac_neighbor_table_address_discover(mac_neighbor_info(cur), data->SrcAddr, ADDR_802_15_4_LONG); + if (neighbor && neighbor->link_role == PRIORITY_PARENT_NEIGHBOUR) { + ws_bootstrap_parent_confirm(cur, NULL); + } + } +} +#ifdef HAVE_WS_VERSION_1_1 +static void ws_bootstrap_ffn_pan_config_lfn_analyze(struct protocol_interface_info_entry *cur, const struct mcps_data_ie_list *ie_ext) +{ + if (!ws_version_1_1(cur) || cur->bootsrap_mode == ARM_NWK_BOOTSRAP_MODE_6LoWPAN_BORDER_ROUTER) { + return; + } + + ws_lfnver_ie_t lfn_version; + if (!ws_wp_nested_lfn_version_read(ie_ext->payloadIeList, ie_ext->payloadIeListLength, &lfn_version)) { + return; // LFN version + } + + //Read LFNGTKHASH + ws_lgtkhash_ie_t ws_lgtkhash; + if (!ws_wp_nested_lgtk_hash_read(ie_ext->payloadIeList, ie_ext->payloadIeListLength, &ws_lgtkhash)) { + return; + } + + if (!cur->ws_info->lfngtk.lfn_version_learned) { + if (!cur->ws_info->configuration_learned) { + trickle_inconsistent_heard(&cur->ws_info->trickle_pan_config, &cur->ws_info->trickle_params_pan_discovery); + } + } else { + if (cur->ws_info->lfngtk.lfn_version == lfn_version.lfn_version) { + return; + } + + if (common_serial_number_greater_16(cur->ws_info->lfngtk.lfn_version, lfn_version.lfn_version)) { + // older version heard ignoring the message + return; + } + } + + cur->ws_info->lfngtk.lfn_version = lfn_version.lfn_version; + + //Clear HASH allways at new first or for first leaned one's + memset(cur->ws_info->lfngtk.lgtkhash, 0, 24); + cur->ws_info->lfngtk.lfn_version_learned = true; + + //Set Active key index and hash inline bits + cur->ws_info->lfngtk.active_key_index = ws_lgtkhash.active_lgtk_index; + cur->ws_info->lfngtk.active_hash_1 = ws_lgtkhash.lgtk0; + cur->ws_info->lfngtk.active_hash_2 = ws_lgtkhash.lgtk1; + cur->ws_info->lfngtk.active_hash_3 = ws_lgtkhash.lgtk2; + + if (cur->ws_info->lfngtk.active_hash_1) { + memcpy(cur->ws_info->lfngtk.lgtkhash, ws_lgtkhash.lgtk0_hash, 8); + } + + if (cur->ws_info->lfngtk.active_hash_2) { + memcpy(cur->ws_info->lfngtk.lgtkhash + 8, ws_lgtkhash.lgtk1_hash, 8); + } + + if (cur->ws_info->lfngtk.active_hash_3) { + memcpy(cur->ws_info->lfngtk.lgtkhash + 16, ws_lgtkhash.lgtk2_hash, 8); + } + //TODO Analyze HASH's and set LFN group key index +} +#endif + + +static void ws_bootstrap_ffn_pan_config_analyse(struct protocol_interface_info_entry *cur, const struct mcps_data_ind_s *data, const struct mcps_data_ie_list *ie_ext, ws_utt_ie_t *ws_utt, ws_us_ie_t *ws_us) +{ + + uint16_t pan_version; + ws_bs_ie_t ws_bs_ie; + uint8_t *gtkhash_ptr; + + if (data->SrcPANId != cur->ws_info->network_pan_id) { + return; + } + ws_bt_ie_t ws_bt_ie; + if (!ws_wh_bt_read(ie_ext->headerIeList, ie_ext->headerIeListLength, &ws_bt_ie)) { + tr_warn("BT-IE"); + return; + } + + /* + * A consistent transmission is defined as a PAN Configuration with a PAN-ID matching that of the receiving node and + * a PANVER-IE / PAN Version greater than or equal to the receiving node’s current PAN version. + * + * A inconsistent transmission is defined as: + * + * A PAN Configuration with PAN-ID matching that of the receiving node and a + * PANVER-IE / PAN Version that is less than the receiving node’s current PAN version. + */ + + // TODO Add this to neighbor table + // TODO save all information from config message if version number has changed + + if (!ws_wp_nested_pan_version_read(ie_ext->payloadIeList, ie_ext->payloadIeListLength, &pan_version)) { + // Corrupted + tr_warn("no version"); + return; + } + + gtkhash_ptr = ws_wp_nested_gtkhash_read(ie_ext->payloadIeList, ie_ext->payloadIeListLength); + + if (!gtkhash_ptr) { + // Corrupted + tr_error("No gtk hash"); + return; + } + + if (!ws_wp_nested_bs_read(ie_ext->payloadIeList, ie_ext->payloadIeListLength, &ws_bs_ie)) { + // Corrupted + tr_error("No broadcast schedule"); + return; + } + + llc_neighbour_req_t neighbor_info; + bool neighbour_pointer_valid; + + //Validate BSI + if (cur->bootsrap_mode != ARM_NWK_BOOTSRAP_MODE_6LoWPAN_BORDER_ROUTER) { + + if (cur->ws_info->ws_bsi_block.block_time && cur->ws_info->ws_bsi_block.old_bsi == ws_bs_ie.broadcast_schedule_identifier) { + tr_debug("Do not accept a old BSI: %u in time %"PRIu32, cur->ws_info->ws_bsi_block.old_bsi, cur->ws_info->ws_bsi_block.block_time); + //Refresh Block time when hear a old BSI + cur->ws_info->ws_bsi_block.block_time = cur->ws_info->cfg->timing.pan_timeout; + return; + } + + //When Config is learned and USE Parent BS is enabled compare is this new BSI + if (cur->ws_info->configuration_learned && cur->ws_info->pan_information.use_parent_bs && ws_bs_ie.broadcast_schedule_identifier != cur->ws_info->hopping_schdule.fhss_bsi) { + //Accept only next possible BSI number + if ((cur->ws_info->hopping_schdule.fhss_bsi + 1) != ws_bs_ie.broadcast_schedule_identifier) { + tr_debug("Do not accept a unknown BSI: %u", ws_bs_ie.broadcast_schedule_identifier); + } else { + tr_debug("NEW Brodcast Schedule %u...BR rebooted", ws_bs_ie.broadcast_schedule_identifier); + cur->ws_info->ws_bsi_block.block_time = cur->ws_info->cfg->timing.pan_timeout; + cur->ws_info->ws_bsi_block.old_bsi = cur->ws_info->hopping_schdule.fhss_bsi; + ws_bootstrap_event_disconnect(cur, WS_NORMAL_DISCONNECT); + } + return; + } + } + + + if (cur->ws_info->configuration_learned || cur->bootsrap_mode == ARM_NWK_BOOTSRAP_MODE_6LoWPAN_BORDER_ROUTER) { + //If we are border router or learned configuration we only update already learned neighbours. + neighbour_pointer_valid = ws_bootstrap_neighbor_info_request(cur, data->SrcAddr, &neighbor_info, false); + + } else { + neighbour_pointer_valid = ws_bootstrap_neighbor_info_request(cur, data->SrcAddr, &neighbor_info, true); + if (!neighbour_pointer_valid) { + return; + } + ws_bootstrap_neighbor_set_stable(cur, data->SrcAddr); + } + + if (neighbour_pointer_valid) { + //Update Neighbor Broadcast and Unicast Parameters + ws_neighbor_class_neighbor_unicast_time_info_update(neighbor_info.ws_neighbor, ws_utt, data->timestamp, (uint8_t *) data->SrcAddr); + ws_neighbor_class_neighbor_unicast_schedule_set(neighbor_info.ws_neighbor, ws_us, &cur->ws_info->hopping_schdule); + ws_neighbor_class_neighbor_broadcast_time_info_update(neighbor_info.ws_neighbor, &ws_bt_ie, data->timestamp); + ws_neighbor_class_neighbor_broadcast_schedule_set(neighbor_info.ws_neighbor, &ws_bs_ie); + } + + if (cur->ws_info->configuration_learned) { + tr_info("PAN Config analyse own:%d, heard:%d", cur->ws_info->pan_information.pan_version, pan_version); + if (cur->ws_info->pan_information.pan_version == pan_version) { + //Check if Trgigle have been resetted in short time skip this then + if (cur->ws_info->trickle_pc_consistency_block_period == 0) { + // Same version heard so it is consistent + trickle_consistent_heard(&cur->ws_info->trickle_pan_config); + } + + if (neighbour_pointer_valid && neighbor_info.neighbor->link_role == PRIORITY_PARENT_NEIGHBOUR) { + ws_bootstrap_primary_parent_set(cur, &neighbor_info, WS_PARENT_SOFT_SYNCH); + } + // no need to process more +#ifdef HAVE_WS_VERSION_1_1 + ws_bootstrap_ffn_pan_config_lfn_analyze(cur, ie_ext); +#endif + return; + } else { + // received version is different so we need to reset the trickle + trickle_inconsistent_heard(&cur->ws_info->trickle_pan_config, &cur->ws_info->trickle_params_pan_discovery); + if (neighbour_pointer_valid && neighbor_info.neighbor->link_role == PRIORITY_PARENT_NEIGHBOUR) { + ws_bootstrap_primary_parent_set(cur, &neighbor_info, WS_PARENT_HARD_SYNCH); + } + if (common_serial_number_greater_16(cur->ws_info->pan_information.pan_version, pan_version)) { + // older version heard ignoring the message + return; + } + cur->ws_info->trickle_pc_consistency_block_period = WS_CONFIG_CONSISTENT_FILTER_PERIOD; + } + } + + if (cur->bootsrap_mode == ARM_NWK_BOOTSRAP_MODE_6LoWPAN_BORDER_ROUTER) { + //Border router does not learn network information + return; + } + + /* + * Learn new information from neighbor + */ + tr_info("Updated PAN configuration own:%d, heard:%d", cur->ws_info->pan_information.pan_version, pan_version); + + // restart PAN version timer + //Check Here Do we have a selected Primary parent + if (!cur->ws_info->configuration_learned || cur->ws_info->rpl_state == RPL_EVENT_DAO_DONE) { + ws_common_border_router_alive_update(cur); + } + + cur->ws_info->pan_information.pan_version = pan_version; + + ws_pae_controller_gtk_hash_update(cur, gtkhash_ptr); + + ws_pae_controller_nw_key_index_update(cur, data->Key.KeyIndex - 1); + +#ifdef HAVE_WS_VERSION_1_1 + ws_bootstrap_ffn_pan_config_lfn_analyze(cur, ie_ext); +#endif + + if (!cur->ws_info->configuration_learned) { + // Generate own hopping schedules Follow first parent broadcast and plans and also use same unicast dwell + tr_info("learn network configuration"); + cur->ws_info->configuration_learned = true; + // return to state machine after 1-2 s + cur->bootsrap_state_machine_cnt = randLIB_get_random_in_range(10, 20); + // enable frequency hopping for unicast channel and start listening first neighbour + ws_bootstrap_primary_parent_set(cur, &neighbor_info, WS_PARENT_HARD_SYNCH); + // set neighbor as priority parent clear if there is others + protocol_6lowpan_neighbor_priority_clear_all(cur->id, PRIORITY_1ST); + neighbor_info.neighbor->link_role = PRIORITY_PARENT_NEIGHBOUR; + } +} + +static void ws_bootstrap_ffn_pan_config_solicit_analyse(struct protocol_interface_info_entry *cur, const struct mcps_data_ind_s *data, ws_utt_ie_t *ws_utt, ws_us_ie_t *ws_us) +{ + if (data->SrcPANId != cur->ws_info->network_pan_id) { + return; + } + + /* TODO smart neighbour process + * + * Unsecure packet we cant trust the device? + * + * Question mark in specification also present, now we create neighbour. + * this is moved in future to NS/ND processing triggered by RPL + * + */ + + llc_neighbour_req_t neighbor_info; + if (ws_bootstrap_neighbor_info_request(cur, data->SrcAddr, &neighbor_info, false)) { + ws_neighbor_class_neighbor_unicast_time_info_update(neighbor_info.ws_neighbor, ws_utt, data->timestamp, (uint8_t *) data->SrcAddr); + ws_neighbor_class_neighbor_unicast_schedule_set(neighbor_info.ws_neighbor, ws_us, &cur->ws_info->hopping_schdule); + } + + if (ws_bootstrap_state_active(cur) && cur->bootsrap_mode != ARM_NWK_BOOTSRAP_MODE_6LoWPAN_BORDER_ROUTER) { + mac_neighbor_table_entry_t *neighbor = mac_neighbor_table_address_discover(mac_neighbor_info(cur), data->SrcAddr, ADDR_802_15_4_LONG); + if (neighbor && neighbor->link_role == PRIORITY_PARENT_NEIGHBOUR) { + ws_bootstrap_parent_confirm(cur, NULL); + } + } + + /* + * A consistent transmission is defined as a PAN Configuration Solicit with + * a PAN-ID matching that of the receiving node and a NETNAME-IE / Network Name + * matching that configured on the receiving node. + */ + trickle_consistent_heard(&cur->ws_info->trickle_pan_config_solicit); + /* + * inconsistent transmission is defined as either: + * A PAN Configuration Solicit with a PAN-ID matching that of the receiving node and + * a NETNAME-IE / Network Name matching the network name configured on the receiving + */ + trickle_inconsistent_heard(&cur->ws_info->trickle_pan_config, &cur->ws_info->trickle_params_pan_discovery); +} + + +void ws_bootstrap_ffn_asynch_ind(struct protocol_interface_info_entry *cur, const struct mcps_data_ind_s *data, const struct mcps_data_ie_list *ie_ext, uint8_t message_type) +{ + // Store weakest heard packet RSSI + if (cur->ws_info->weakest_received_rssi > data->signal_dbm) { + cur->ws_info->weakest_received_rssi = data->signal_dbm; + } + + if (data->SrcAddrMode != MAC_ADDR_MODE_64_BIT) { + // Not from long address + return; + } + ws_stats_update(cur, STATS_WS_ASYNCH_RX, 1); + //Validate network name + switch (message_type) { + case WS_FT_PAN_ADVERT: + case WS_FT_PAN_ADVERT_SOL: + case WS_FT_PAN_CONF_SOL: + //Check Network Name + if (!ws_bootstrap_network_name_matches(ie_ext, cur->ws_info->cfg->gen.network_name)) { + // Not in our network + return; + } + break; + case WS_FT_PAN_CONF: + break; + default: + return; + } + //UTT-IE and US-IE are mandatory for all Asynch Messages + ws_utt_ie_t ws_utt; + if (!ws_wh_utt_read(ie_ext->headerIeList, ie_ext->headerIeListLength, &ws_utt)) { + // Corrupted + return; + } + + ws_us_ie_t ws_us; + if (!ws_wp_nested_us_read(ie_ext->payloadIeList, ie_ext->payloadIeListLength, &ws_us)) { + // Corrupted + return; + } + + if (!ws_bootstrap_validate_channel_plan(&ws_us, cur) || + !ws_bootstrap_validate_channel_function(&ws_us, NULL)) { + return; + } + + //Handle Message's + switch (message_type) { + case WS_FT_PAN_ADVERT: + // Analyse Advertisement + ws_stats_update(cur, STATS_WS_ASYNCH_RX_PA, 1); + tr_info("received ADVERT Src:%s panid:%x rssi:%d", trace_array(data->SrcAddr, 8), data->SrcPANId, data->signal_dbm); + ws_bootstrap_ffn_pan_advertisement_analyse(cur, data, ie_ext, &ws_utt, &ws_us); + break; + case WS_FT_PAN_ADVERT_SOL: + ws_stats_update(cur, STATS_WS_ASYNCH_RX_PAS, 1); + tr_info("received ADVERT SOL Src:%s rssi:%d", trace_array(data->SrcAddr, 8), data->signal_dbm); + ws_bootstrap_ffn_pan_advertisement_solicit_analyse(cur, data, &ws_utt, &ws_us); + break; + case WS_FT_PAN_CONF: + ws_stats_update(cur, STATS_WS_ASYNCH_RX_PC, 1); + tr_info("received CONFIG Src:%s rssi:%d", trace_array(data->SrcAddr, 8), data->signal_dbm); + ws_bootstrap_ffn_pan_config_analyse(cur, data, ie_ext, &ws_utt, &ws_us); + break; + case WS_FT_PAN_CONF_SOL: + ws_stats_update(cur, STATS_WS_ASYNCH_RX_PCS, 1); + tr_info("received CONFIG SOL Src:%s rssi:%d", trace_array(data->SrcAddr, 8), data->signal_dbm); + ws_bootstrap_ffn_pan_config_solicit_analyse(cur, data, &ws_utt, &ws_us); + default: + // Unknown message do not process + break; + } +} + +void ws_bootstrap_ffn_asynch_confirm(struct protocol_interface_info_entry *interface, uint8_t asynch_message) +{ + (void)asynch_message; + ws_stats_update(interface, STATS_WS_ASYNCH_TX, 1); +} + +void ws_bootstrap_ffn_event_handler(protocol_interface_info_entry_t *cur, arm_event_s *event) +{ + ws_bootsrap_event_type_e event_type; + event_type = (ws_bootsrap_event_type_e)event->event_type; + + switch (event_type) { + case WS_INIT_EVENT: + tr_debug("tasklet init"); + break; + case WS_DISCOVERY_START: + tr_info("Discovery start"); + protocol_mac_reset(cur); + ws_llc_reset(cur); + lowpan_adaptation_interface_reset(cur->id); + //Clear Pending Key Index State + cur->ws_info->pending_key_index_info.state = NO_PENDING_PROCESS; + cur->mac_parameters->mac_default_key_index = 0; + + ipv6_destination_cache_clean(cur->id); + + // Clear parent blacklist + blacklist_clear(); + + // All trickle timers stopped to allow entry from any state + ws_bootstrap_asynch_trickle_stop(cur); + //Init Packet congestion + ws_bootstrap_packet_congestion_init(cur); + + ws_pae_controller_supp_init(cur); + // Clear learned neighbours + ws_bootstrap_neighbor_list_clean(cur); + // Configure LLC for network discovery + ws_bootstrap_ffn_network_discovery_configure(cur); + ws_bootstrap_fhss_activate(cur); + // Set retry configuration for discovery state + ws_bootstrap_configure_max_retries(cur, WS_MAX_FRAME_RETRIES_BOOTSTRAP); + // Set TX failure request restart configuration for discovery state + ws_bootstrap_configure_data_request_restart(cur, WS_CCA_REQUEST_RESTART_MAX, WS_TX_REQUEST_RESTART_MAX_BOOTSTRAP, WS_REQUEST_RESTART_BLACKLIST_MIN, WS_REQUEST_RESTART_BLACKLIST_MAX); + // Set CSMA-CA backoff configuration + ws_bootstrap_configure_csma_ca_backoffs(cur, WS_MAX_CSMA_BACKOFFS, WS_MAC_MIN_BE, WS_MAC_MAX_BE); + // Start network scan + ws_bootstrap_ffn_start_discovery(cur); + break; + + case WS_CONFIGURATION_START: + tr_info("Configuration start"); + // Old configuration is considered invalid stopping all + ws_bootstrap_asynch_trickle_stop(cur); + + // Build list of possible neighbours and learn first broadcast schedule + + ws_bootstrap_ffn_start_configuration_learn(cur); + break; + case WS_OPERATION_START: + tr_info("operation start"); + // Advertisements stopped during the RPL scan + ws_bootstrap_asynch_trickle_stop(cur); + // Activate RPL + // Activate IPv6 stack + ws_bootstrap_ip_stack_activate(cur); + ws_bootstrap_rpl_activate(cur); + ws_bootstrap_network_start(cur); + // Wait for RPL start + ws_bootstrap_rpl_scan_start(cur); + /* While in Join State 4, if a non Border Router determines it has been unable to communicate with the PAN Border + * Router for an interval of PAN_TIMEOUT, a node MUST assume failure of the PAN Border Router and MUST + * Transition to Join State 1 + */ + ws_common_border_router_alive_update(cur); + break; + case WS_ROUTING_READY: + tr_info("Routing ready"); + // stopped all to make sure we can enter here from any state + ws_bootstrap_asynch_trickle_stop(cur); + + // Indicate PAE controller that bootstrap is ready + ws_pae_controller_bootstrap_done(cur); + + ws_bootstrap_advertise_start(cur); + ws_bootstrap_state_change(cur, ER_BOOTSRAP_DONE); + break; + case WS_FAST_DISCONNECT: + ws_bootstrap_state_disconnect(cur, WS_FAST_DISCONNECT); + break; + case WS_NORMAL_DISCONNECT: + ws_bootstrap_state_disconnect(cur, WS_NORMAL_DISCONNECT); + break; + + case WS_TEST_PROC_TRIGGER: + ws_bootstrap_test_procedure_trigger_exec(cur, (ws_bootsrap_procedure_t) event->data_ptr); + break; + + default: + tr_err("Invalid event received"); + break; + } +} + +/* + * Statemachine state functions + * */ + +static void ws_bootstrap_ffn_network_scan_process(protocol_interface_info_entry_t *cur) +{ + + parent_info_t *selected_parent_ptr; + + tr_debug("analyze network discovery result"); + +select_best_candidate: + selected_parent_ptr = ws_bootstrap_candidate_parent_get_best(cur); + + if (!selected_parent_ptr) { + // Configure LLC for network discovery + ws_bootstrap_ffn_network_discovery_configure(cur); + // randomize new channel and start MAC + ws_bootstrap_fhss_activate(cur); + // Next check will be after one trickle + uint32_t random_start = cur->ws_info->trickle_params_pan_discovery.Imin + randLIB_get_random_in_range(0, cur->ws_info->trickle_params_pan_discovery.Imin); + if (random_start > 0xffff) { + random_start = 0xffff; + } + cur->bootsrap_state_machine_cnt = random_start; + + tr_info("Making parent selection in %u s", (cur->bootsrap_state_machine_cnt / 10)); + return; + } + tr_info("selected parent:%s panid %u", trace_array(selected_parent_ptr->addr, 8), selected_parent_ptr->pan_id); + + if (ws_bootstrap_neighbor_set(cur, selected_parent_ptr, false) < 0) { + goto select_best_candidate; + } + + ws_pae_controller_set_target(cur, selected_parent_ptr->pan_id, selected_parent_ptr->addr); // temporary!!! store since auth + ws_bootstrap_event_authentication_start(cur); + return; +} + +static void ws_bootstrap_ffn_configure_process(protocol_interface_info_entry_t *cur) +{ + + if (cur->ws_info->configuration_learned) { + ws_bootstrap_ffn_network_configuration_learn(cur); + ws_bootstrap_event_operation_start(cur); + return; + } + return; +} + +void ws_bootstrap_ffn_rpl_wait_process(protocol_interface_info_entry_t *cur) +{ + + if (cur->ws_info->rpl_state == RPL_EVENT_DAO_DONE) { + // RPL routing is ready + cur->ws_info->connected_time = cur->ws_info->uptime; + ws_bootstrap_event_routing_ready(cur); + } else if (!rpl_control_have_dodag(cur->rpl_domain)) { + // RPL not ready send DIS message if possible + if (cur->bootsrap_mode == ARM_NWK_BOOTSRAP_MODE_6LoWPAN_ROUTER) { + // TODO Multicast DIS should be sent only if no DIO heard for some time + rpl_control_transmit_dis(cur->rpl_domain, cur, 0, 0, NULL, 0, ADDR_LINK_LOCAL_ALL_RPL_NODES); + } + // set timer for next DIS + cur->bootsrap_state_machine_cnt = randLIB_get_random_in_range(WS_RPL_DIS_TIMEOUT / 2, WS_RPL_DIS_TIMEOUT); + } + return; +} + + +/* + * State machine + */ + +void ws_bootstrap_ffn_state_machine(protocol_interface_info_entry_t *cur) +{ + + switch (cur->nwk_bootstrap_state) { + case ER_WAIT_RESTART: + tr_debug("WS SM:Wait for startup"); + ws_bootstrap_event_discovery_start(cur); + break; + case ER_ACTIVE_SCAN: + tr_debug("WS SM:Active Scan"); + ws_bootstrap_ffn_network_scan_process(cur); + break; + case ER_SCAN: + tr_debug("WS SM:configuration Scan"); + ws_bootstrap_ffn_configure_process(cur); + break; + case ER_PANA_AUTH: + tr_info("authentication start"); + // Advertisements stopped during the EAPOL + ws_bootstrap_asynch_trickle_stop(cur); + ws_bootstrap_ffn_fhss_configure(cur, false); + int8_t new_default = cur->ws_info->weakest_received_rssi - 1; + if ((new_default < CCA_DEFAULT_DBM) && (new_default >= CCA_LOW_LIMIT) && (new_default <= CCA_HIGH_LIMIT)) { + // Restart automatic CCA threshold using weakest received RSSI as new default + mac_helper_start_auto_cca_threshold(cur->id, cur->ws_info->hopping_schdule.number_of_channels, cur->ws_info->weakest_received_rssi - 1, CCA_HIGH_LIMIT, CCA_LOW_LIMIT); + } + ws_bootstrap_start_authentication(cur); + break; + case ER_RPL_SCAN: + tr_debug("WS SM:Wait RPL to contact DODAG root"); + ws_bootstrap_ffn_rpl_wait_process(cur); + break; + case ER_BOOTSRAP_DONE: + tr_info("WS SM:Bootstrap Done"); + // Bootstrap_done event to application + nwk_bootsrap_state_update(ARM_NWK_BOOTSTRAP_READY, cur); + break; + case ER_RPL_NETWORK_LEAVING: + tr_debug("WS SM:RPL Leaving ready trigger discovery"); + ws_bootstrap_event_discovery_start(cur); + break; + default: + tr_warn("WS SM:Invalid state %d", cur->nwk_bootstrap_state); + } +} + +void ws_bootstrap_ffn_seconds_timer(protocol_interface_info_entry_t *cur, uint32_t seconds) +{ + /* Border router keep alive check + */ + if (cur->ws_info->pan_timeout_timer) { + // PAN version timer running + if (cur->ws_info->pan_timeout_timer > seconds) { + cur->ws_info->pan_timeout_timer -= seconds; + if (cur->ws_info->pan_timeout_timer < cur->ws_info->cfg->timing.pan_timeout / 10) { + /* pan timeout is closing need to verify that DAO is tested before the pan times out. + This will give some extra time for RPL to find better parents. + Border router liveliness can be checked from version number change or from successful DAO registrations + in this case there has not been any version number changes during this PAN lifetime. + */ + rpl_control_dao_timeout(cur->rpl_domain, 20); + } + } else { + // Border router has timed out + //Clear Timeout timer + cur->ws_info->pan_timeout_timer = 0; + tr_warn("Border router has timed out"); + ws_bootstrap_event_disconnect(cur, WS_FAST_DISCONNECT); + } + } + if (cur->ws_info->aro_registration_timer) { + if (cur->ws_info->aro_registration_timer > seconds) { + cur->ws_info->aro_registration_timer -= seconds; + } else { + // Update all addressess. This function will update the timer value if needed + cur->ws_info->aro_registration_timer = 0; + ws_address_registration_update(cur, NULL); + } + } + + if (cur->ws_info->ws_bsi_block.block_time) { + if (cur->ws_info->ws_bsi_block.block_time > seconds) { + cur->ws_info->ws_bsi_block.block_time -= seconds; + } else { + //Clear A BSI blokker + cur->ws_info->ws_bsi_block.block_time = 0; + cur->ws_info->ws_bsi_block.old_bsi = 0; + } + } +} + + +#endif //HAVE_WS_BORDER_ROUTER && HAVE_WS diff --git a/source/6LoWPAN/ws/ws_bootstrap_ffn.h b/source/6LoWPAN/ws/ws_bootstrap_ffn.h new file mode 100644 index 0000000000..fcc9dd25d6 --- /dev/null +++ b/source/6LoWPAN/ws/ws_bootstrap_ffn.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2021, Pelion and affiliates. + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef WS_BOOTSTRAP_FFN_H_ +#define WS_BOOTSTRAP_FFN_H_ + +#if defined(HAVE_WS) && defined(HAVE_WS_ROUTER) + +void ws_bootstrap_ffn_asynch_ind(struct protocol_interface_info_entry *cur, const struct mcps_data_ind_s *data, const struct mcps_data_ie_list *ie_ext, uint8_t message_type); +void ws_bootstrap_ffn_asynch_confirm(struct protocol_interface_info_entry *interface, uint8_t asynch_message); +void ws_bootstrap_ffn_event_handler(protocol_interface_info_entry_t *cur, arm_event_s *event); +void ws_bootstrap_ffn_state_machine(protocol_interface_info_entry_t *cur); +void ws_bootstrap_ffn_seconds_timer(protocol_interface_info_entry_t *cur, uint32_t seconds); + +#define wisun_mode_router(cur) (cur->bootsrap_mode == ARM_NWK_BOOTSRAP_MODE_6LoWPAN_ROUTER) + +#else + +#define ws_bootstrap_ffn_asynch_ind(cur, data, ie_ext, message_type) ((void) 0) +#define ws_bootstrap_ffn_asynch_confirm(interface, asynch_message) ((void) 0) +#define ws_bootstrap_ffn_event_handler(cur, event) ((void) 0) +#define ws_bootstrap_ffn_state_machine(cur) ((void) 0) +#define ws_bootstrap_ffn_seconds_timer(cur, seconds) ((void) 0) + +#define wisun_mode_router(cur) (false) + +#endif //HAVE_WS + +#endif /* WS_BOOTSTRAP_H_ */ diff --git a/source/6LoWPAN/ws/ws_bootstrap_lfn.c b/source/6LoWPAN/ws/ws_bootstrap_lfn.c new file mode 100644 index 0000000000..7e0a46cc49 --- /dev/null +++ b/source/6LoWPAN/ws/ws_bootstrap_lfn.c @@ -0,0 +1,172 @@ +/* + * Copyright (c) 2021, Pelion and affiliates. + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include "nsconfig.h" +#if defined(HAVE_WS) && defined(HAVE_WS_HOST) +#include "ns_types.h" +#include "ns_trace.h" +#include "nsdynmemLIB.h" +#include "net_interface.h" +#include "eventOS_event.h" +#include "randLIB.h" +#include "common_functions.h" +#include "mac_common_defines.h" +#include "sw_mac.h" +#include "ccmLIB.h" +#include "Core/include/ns_monitor.h" +#include "NWK_INTERFACE/Include/protocol.h" +#include "6LoWPAN/Bootstraps/protocol_6lowpan.h" +#include "6LoWPAN/Bootstraps/protocol_6lowpan_interface.h" +#include "ipv6_stack/protocol_ipv6.h" +#include "ipv6_stack/ipv6_routing_table.h" +#include "6LoWPAN/MAC/mac_helper.h" +#include "6LoWPAN/MAC/mac_data_poll.h" +#include "6LoWPAN/MAC/mpx_api.h" +#include "6LoWPAN/MAC/mac_ie_lib.h" +#include "MPL/mpl.h" +#include "RPL/rpl_protocol.h" +#include "RPL/rpl_control.h" +#include "RPL/rpl_data.h" +#include "RPL/rpl_policy.h" +#include "Common_Protocols/icmpv6.h" +#include "Common_Protocols/icmpv6_radv.h" +#include "Common_Protocols/ipv6_constants.h" +#include "Common_Protocols/ip.h" +#include "Service_Libs/Trickle/trickle.h" +#include "Service_Libs/fhss/channel_list.h" +#include "Service_Libs/utils/ns_time.h" +#include "6LoWPAN/ws/ws_common_defines.h" +#include "6LoWPAN/ws/ws_common_defines.h" +#include "6LoWPAN/ws/ws_config.h" +#include "6LoWPAN/ws/ws_common.h" +#include "6LoWPAN/ws/ws_bootstrap.h" +#include "6LoWPAN/ws/ws_bbr_api_internal.h" +#include "6LoWPAN/ws/ws_common_defines.h" +#include "6LoWPAN/ws/ws_llc.h" +#include "6LoWPAN/ws/ws_neighbor_class.h" +#include "6LoWPAN/ws/ws_ie_lib.h" +#include "6LoWPAN/ws/ws_stats.h" +#include "6LoWPAN/ws/ws_cfg_settings.h" +#include "6LoWPAN/lowpan_adaptation_interface.h" +#include "Service_Libs/etx/etx.h" +#include "Service_Libs/mac_neighbor_table/mac_neighbor_table.h" +#include "Service_Libs/nd_proxy/nd_proxy.h" +#include "Service_Libs/blacklist/blacklist.h" +#include "platform/topo_trace.h" +#include "dhcp_service_api.h" +#include "libDHCPv6/libDHCPv6.h" +#include "libDHCPv6/libDHCPv6_vendordata.h" +#include "DHCPv6_client/dhcpv6_client_api.h" +#include "ws_management_api.h" +#include "net_rpl.h" +#include "mac_api.h" +#include "6LoWPAN/ws/ws_pae_controller.h" +#include "6LoWPAN/ws/ws_eapol_pdu.h" +#include "6LoWPAN/ws/ws_eapol_auth_relay.h" +#include "6LoWPAN/ws/ws_eapol_relay.h" +#include "libNET/src/net_dns_internal.h" +#include "Service_Libs/random_early_detection/random_early_detection_api.h" + +#define TRACE_GROUP "wsbs" + + +void ws_bootstrap_lfn_asynch_ind(struct protocol_interface_info_entry *cur, const struct mcps_data_ind_s *data, const struct mcps_data_ie_list *ie_ext, uint8_t message_type) +{ + (void)ie_ext; + // Store weakest heard packet RSSI + if (cur->ws_info->weakest_received_rssi > data->signal_dbm) { + cur->ws_info->weakest_received_rssi = data->signal_dbm; + } + + if (data->SrcAddrMode != MAC_ADDR_MODE_64_BIT) { + // Not from long address + return; + } + ws_stats_update(cur, STATS_WS_ASYNCH_RX, 1); + tr_warn("Wi-SUN LFN Mode received message id: %x", message_type); +} + +void ws_bootstrap_lfn_asynch_confirm(struct protocol_interface_info_entry *interface, uint8_t asynch_message) +{ + (void)asynch_message; + ws_stats_update(interface, STATS_WS_ASYNCH_TX, 1); +} + +void ws_bootstrap_lfn_event_handler(protocol_interface_info_entry_t *cur, arm_event_s *event) +{ + (void)cur; + ws_bootsrap_event_type_e event_type; + event_type = (ws_bootsrap_event_type_e)event->event_type; + + switch (event_type) { + case WS_INIT_EVENT: + tr_debug("tasklet init"); + break; + /* case WS_DISCOVERY_START: + case WS_CONFIGURATION_START: + case WS_OPERATION_START: + case WS_ROUTING_READY: + case WS_FAST_DISCONNECT: + case WS_NORMAL_DISCONNECT: + */ + default: + tr_err("Invalid event received"); + break; + } +} + +void ws_bootstrap_lfn_state_machine(protocol_interface_info_entry_t *cur) +{ + + switch (cur->nwk_bootstrap_state) { + case ER_WAIT_RESTART: + tr_debug("WS SM:Wait for startup"); + break; + case ER_ACTIVE_SCAN: + tr_debug("WS SM:Active Scan"); + break; + case ER_SCAN: + tr_debug("WS SM:configuration Scan"); + break; + case ER_PANA_AUTH: + tr_info("authentication start"); + // Advertisements stopped during the EAPOL + break; + case ER_RPL_SCAN: + tr_debug("WS SM:Wait RPL to contact DODAG root"); + break; + case ER_BOOTSRAP_DONE: + tr_info("WS SM:Bootstrap Done"); + // Bootstrap_done event to application + break; + case ER_RPL_NETWORK_LEAVING: + tr_debug("WS SM:RPL Leaving ready trigger discovery"); + break; + default: + tr_warn("WS SM:Invalid state %d", cur->nwk_bootstrap_state); + } +} + +void ws_bootstrap_lfn_seconds_timer(protocol_interface_info_entry_t *cur, uint32_t seconds) +{ + (void)cur; + (void)seconds; +} + + +#endif //HAVE_WS_BORDER_ROUTER && HAVE_WS diff --git a/source/6LoWPAN/ws/ws_bootstrap_lfn.h b/source/6LoWPAN/ws/ws_bootstrap_lfn.h new file mode 100644 index 0000000000..84a0cf8101 --- /dev/null +++ b/source/6LoWPAN/ws/ws_bootstrap_lfn.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2021, Pelion and affiliates. + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef WS_BOOTSTRAP_LFN_H_ +#define WS_BOOTSTRAP_LFN_H_ + +#if defined(HAVE_WS) && defined(HAVE_WS_HOST) + +void ws_bootstrap_lfn_asynch_ind(struct protocol_interface_info_entry *cur, const struct mcps_data_ind_s *data, const struct mcps_data_ie_list *ie_ext, uint8_t message_type); +void ws_bootstrap_lfn_asynch_confirm(struct protocol_interface_info_entry *interface, uint8_t asynch_message); +void ws_bootstrap_lfn_event_handler(protocol_interface_info_entry_t *cur, arm_event_s *event); +void ws_bootstrap_lfn_state_machine(protocol_interface_info_entry_t *cur); +void ws_bootstrap_lfn_seconds_timer(protocol_interface_info_entry_t *cur, uint32_t seconds); + +#define wisun_mode_host(cur) (cur->bootsrap_mode == ARM_NWK_BOOTSRAP_MODE_6LoWPAN_HOST) + +#else + +#define ws_bootstrap_ffn_asynch_ind(cur, data, ie_ext, message_type) ((void) 0) +#define ws_bootstrap_ffn_asynch_confirm(interface, asynch_message) ((void) 0) +#define ws_bootstrap_ffn_event_handler(cur, event) ((void) 0) +#define ws_bootstrap_lfn_state_machine(cur) ((void) 0) +#define ws_bootstrap_lfn_seconds_timer(cur, seconds) ((void) 0) + +#define wisun_mode_host(cur) (false) + +#endif //HAVE_WS + +#endif /* WS_BOOTSTRAP_H_ */ diff --git a/source/6LoWPAN/ws/ws_cfg_settings.c b/source/6LoWPAN/ws/ws_cfg_settings.c index d01601da20..2d70df180a 100644 --- a/source/6LoWPAN/ws/ws_cfg_settings.c +++ b/source/6LoWPAN/ws/ws_cfg_settings.c @@ -39,10 +39,8 @@ #define CFG_SETTINGS_OK 0 #define CFG_SETTINGS_CHANGED 1 -#define CFG_FLAGS_DISABLE_VAL_SET 0x01 -#define CFG_FLAGS_OVERRIDE_DISABLE_VAL_SET 0x02 -#define CFG_FLAGS_FORCE_INTERNAL_CONFIG 0x04 -#define CFG_FLAGS_BOOTSTRAP_RESTART_DISABLE 0x08 +#define CFG_FLAGS_BOOTSTRAP_RESTART_DISABLE 0x01 +#define CFG_FLAGS_BOOTSTRAP_SET_VALUES 0x02 #define TRICKLE_IMIN_60_SECS 60 #define TRICKLE_IMIN_30_SECS 30 @@ -58,8 +56,8 @@ typedef struct ws_cfg_nw_size_s { static uint32_t ws_test_temporary_entry_lifetime = 0; typedef int8_t (*ws_cfg_default_set)(void *cfg); -typedef int8_t (*ws_cfg_validate)(void *cfg, void *new_cfg); -typedef int8_t (*ws_cfg_set)(protocol_interface_info_entry_t *cur, void *cfg, void *new_cfg, uint8_t *flags); +typedef int8_t (*ws_cfg_validate)(void *new_cfg); +typedef int8_t (*ws_cfg_set)(protocol_interface_info_entry_t *cur, void *new_cfg, uint8_t flags); typedef struct { ws_cfg_default_set default_set; @@ -104,9 +102,6 @@ const cfg_devices_in_config_t devices_by_datarate[] = { { 2, 20, 50, 100}, // Configuration for 600kbs - 2400kbs }; - -static int8_t ws_cfg_to_get(ws_cfgs_t **cfg, ws_cfgs_t *new_cfg, ws_cfg_validate valid_cb, ws_cfgs_t *external_cfg, uint8_t *cfg_flags, uint8_t *flags); - static void ws_cfg_network_size_config_set_small(ws_cfg_nw_size_t *cfg); static void ws_cfg_network_size_config_set_medium(ws_cfg_nw_size_t *cfg); static void ws_cfg_network_size_config_set_large(ws_cfg_nw_size_t *cfg); @@ -146,55 +141,6 @@ static const ws_cfg_cb_t cfg_cb[] = { // Wisun configuration storage ws_cfg_t ws_cfg; -// If automatic network size mode; external configuration shown to towards users of external APIs -ws_cfg_nw_size_t *nw_size_external_cfg = NULL; - -static int8_t ws_cfg_to_get(ws_cfgs_t **cfg, ws_cfgs_t *new_cfg, ws_cfg_validate valid_cb, ws_cfgs_t *ws_cfg_ptr, uint8_t *cfg_flags, uint8_t *flags) -{ - // In case target configuration is not set, uses ws_cfg storage - if (*cfg == NULL) { - // In case external configuration is not same as internal - if (nw_size_external_cfg && (!flags || !(*flags & CFG_FLAGS_FORCE_INTERNAL_CONFIG))) { - if (ws_cfg_ptr == (ws_cfgs_t *) &ws_cfg.gen) { - *cfg = (ws_cfgs_t *) &nw_size_external_cfg->gen; - } else if (ws_cfg_ptr == (ws_cfgs_t *) &ws_cfg.timing) { - *cfg = (ws_cfgs_t *) &nw_size_external_cfg->timing; - } else if (ws_cfg_ptr == (ws_cfgs_t *) &ws_cfg.bbr) { - *cfg = (ws_cfgs_t *) &nw_size_external_cfg->bbr; - } else if (ws_cfg_ptr == (ws_cfgs_t *) &ws_cfg.sec_prot) { - *cfg = (ws_cfgs_t *) &nw_size_external_cfg->sec_prot; - } else if (ws_cfg_ptr == (ws_cfgs_t *) &ws_cfg.mpl) { - *cfg = (ws_cfgs_t *) &nw_size_external_cfg->mpl; - } else { - *cfg = ws_cfg_ptr; - } - } else { - *cfg = ws_cfg_ptr; - } - - if (valid_cb) { - int8_t ret = valid_cb(*cfg, new_cfg); - // On failure and if nothing is changed, returns - if (ret != CFG_SETTINGS_CHANGED) { - return ret; - } - } - } - - if (!cfg_flags) { - return CFG_SETTINGS_CHANGED; - } - *cfg_flags = 0; - if (flags) { - *cfg_flags |= *flags; - } - if (nw_size_external_cfg && !(*cfg_flags & CFG_FLAGS_OVERRIDE_DISABLE_VAL_SET)) { - *cfg_flags |= CFG_FLAGS_DISABLE_VAL_SET; - } - - return CFG_SETTINGS_CHANGED; -} - #ifdef FEA_TRACE_SUPPORT static void ws_cfg_trace(ws_cfgs_t *cfg, ws_cfgs_t *new_cfg, uint8_t size, char *name) { @@ -236,19 +182,15 @@ static int8_t ws_cfg_network_size_default_set(ws_gen_cfg_t *cfg) return CFG_SETTINGS_OK; } -int8_t ws_cfg_network_size_get(ws_gen_cfg_t *cfg, uint8_t *flags) +int8_t ws_cfg_network_size_get(ws_gen_cfg_t *cfg) { - ws_gen_cfg_t *get_cfg = NULL; - ws_cfg_to_get((ws_cfgs_t **) &get_cfg, NULL, NULL, (ws_cfgs_t *) &ws_cfg.gen, 0, flags); - *cfg = *get_cfg; - + *cfg = ws_cfg.gen; return CFG_SETTINGS_OK; } -int8_t ws_cfg_network_size_validate(ws_gen_cfg_t *cfg, ws_gen_cfg_t *new_cfg) +int8_t ws_cfg_network_size_validate(ws_gen_cfg_t *new_cfg) { - ws_cfg_to_get((ws_cfgs_t **) &cfg, (ws_cfgs_t *) new_cfg, NULL, (ws_cfgs_t *) &ws_cfg.gen, 0, 0); - + ws_gen_cfg_t *cfg = &ws_cfg.gen; if (cfg->network_size != new_cfg->network_size) { return CFG_SETTINGS_CHANGED; } @@ -258,29 +200,24 @@ int8_t ws_cfg_network_size_validate(ws_gen_cfg_t *cfg, ws_gen_cfg_t *new_cfg) typedef void (*ws_cfg_network_size_config_set_size)(ws_cfg_nw_size_t *cfg); -int8_t ws_cfg_network_size_set(protocol_interface_info_entry_t *cur, ws_gen_cfg_t *cfg, ws_gen_cfg_t *new_cfg, uint8_t *flags) +int8_t ws_cfg_network_size_set(protocol_interface_info_entry_t *cur, ws_gen_cfg_t *new_cfg, uint8_t flags) { - uint8_t cfg_flags; - int8_t ret = ws_cfg_to_get((ws_cfgs_t **) &cfg, (ws_cfgs_t *) new_cfg, (ws_cfg_validate) ws_cfg_network_size_validate, (ws_cfgs_t *) &ws_cfg.gen, &cfg_flags, flags); - if (ret != CFG_SETTINGS_CHANGED) { - return ret; - } + (void) flags; - uint8_t old_network_size = cfg->network_size; - - // If network size configuration has not changed, returns - if (cfg->network_size == new_cfg->network_size) { + if (ws_cfg_network_size_validate(new_cfg) != CFG_SETTINGS_CHANGED) { return CFG_SETTINGS_OK; } + ws_gen_cfg_t *cfg = &ws_cfg.gen; + cfg->network_size = new_cfg->network_size; ws_cfg_nw_size_t nw_size_cfg; - ws_cfg_gen_get(&nw_size_cfg.gen, NULL); - ws_cfg_timing_get(&nw_size_cfg.timing, NULL); - ws_cfg_bbr_get(&nw_size_cfg.bbr, NULL); - ws_cfg_sec_prot_get(&nw_size_cfg.sec_prot, NULL); - ws_cfg_mpl_get(&nw_size_cfg.mpl, NULL); + ws_cfg_gen_get(&nw_size_cfg.gen); + ws_cfg_timing_get(&nw_size_cfg.timing); + ws_cfg_bbr_get(&nw_size_cfg.bbr); + ws_cfg_sec_prot_get(&nw_size_cfg.sec_prot); + ws_cfg_mpl_get(&nw_size_cfg.mpl); ws_cfg_network_size_config_set_size set_function = NULL; @@ -301,46 +238,13 @@ int8_t ws_cfg_network_size_set(protocol_interface_info_entry_t *cur, ws_gen_cfg_ set_function(&nw_size_cfg); } - uint8_t cfg_network_size = cfg->network_size; + /* Sets values if changed */ + ws_cfg_gen_set(cur, &nw_size_cfg.gen, 0x00); + ws_cfg_timing_set(cur, &nw_size_cfg.timing, 0x00); + ws_cfg_bbr_set(cur, &nw_size_cfg.bbr, 0x00); + ws_cfg_sec_prot_set(cur, &nw_size_cfg.sec_prot, 0x00); + ws_cfg_mpl_set(cur, &nw_size_cfg.mpl, 0x00); - /* If no longer in an automatic network size mode, frees automatic configuration, - so that new configuration is set */ - if (nw_size_external_cfg && old_network_size == NETWORK_SIZE_AUTOMATIC) { - ns_dyn_mem_free(nw_size_external_cfg); - nw_size_external_cfg = NULL; - } - - uint8_t set_flags = 0; - if (cfg_network_size == NETWORK_SIZE_AUTOMATIC) { - set_flags = CFG_FLAGS_DISABLE_VAL_SET; - } - /* Sets values if changed or network size has been previously automatic (to make sure - the settings are in sync */ - if (ws_cfg_gen_validate(&ws_cfg.gen, &nw_size_cfg.gen) == CFG_SETTINGS_CHANGED || - old_network_size == NETWORK_SIZE_AUTOMATIC) { - ws_cfg_gen_set(cur, &ws_cfg.gen, &nw_size_cfg.gen, &set_flags); - } - if (ws_cfg_timing_validate(&ws_cfg.timing, &nw_size_cfg.timing) == CFG_SETTINGS_CHANGED || - old_network_size == NETWORK_SIZE_AUTOMATIC) { - ws_cfg_timing_set(cur, &ws_cfg.timing, &nw_size_cfg.timing, &set_flags); - } - if (ws_cfg_bbr_validate(&ws_cfg.bbr, &nw_size_cfg.bbr) == CFG_SETTINGS_CHANGED || - old_network_size == NETWORK_SIZE_AUTOMATIC) { - ws_cfg_bbr_set(cur, &ws_cfg.bbr, &nw_size_cfg.bbr, &set_flags); - } - if (ws_cfg_sec_prot_validate(&ws_cfg.sec_prot, &nw_size_cfg.sec_prot) == CFG_SETTINGS_CHANGED || - old_network_size == NETWORK_SIZE_AUTOMATIC) { - ws_cfg_sec_prot_set(cur, &ws_cfg.sec_prot, &nw_size_cfg.sec_prot, &set_flags); - } - if (ws_cfg_mpl_validate(&ws_cfg.mpl, &nw_size_cfg.mpl) == CFG_SETTINGS_CHANGED || - old_network_size == NETWORK_SIZE_AUTOMATIC) { - ws_cfg_mpl_set(cur, &ws_cfg.mpl, &nw_size_cfg.mpl, &set_flags); - } - - // If is in an automatic network size mode, updates automatic configuration - if (cfg_network_size == NETWORK_SIZE_AUTOMATIC && cur) { - ws_cfg_network_size_configure(cur, cur->ws_info->pan_information.pan_size); - } return CFG_SETTINGS_OK; } @@ -349,7 +253,7 @@ static uint8_t ws_cfg_config_get_by_size(protocol_interface_info_entry_t *cur, u (void)cur; ws_phy_cfg_t phy_cfg; - if (ws_cfg_phy_get(&phy_cfg, NULL) < 0) { + if (ws_cfg_phy_get(&phy_cfg) < 0) { return CONFIG_SMALL; } uint32_t data_rate = ws_common_datarate_get_from_phy_mode(phy_cfg.phy_mode_id, phy_cfg.operating_mode); @@ -377,50 +281,6 @@ static uint8_t ws_cfg_config_get_by_size(protocol_interface_info_entry_t *cur, u return CONFIG_XLARGE; } -int8_t ws_cfg_network_size_configure(protocol_interface_info_entry_t *cur, uint16_t network_size) -{ - // Read settings that are affected by network size - ws_cfg_nw_size_t new_nw_size_cfg; - uint8_t flags = CFG_FLAGS_OVERRIDE_DISABLE_VAL_SET | CFG_FLAGS_FORCE_INTERNAL_CONFIG; - - ws_cfg_gen_get(&new_nw_size_cfg.gen, &flags); - ws_cfg_timing_get(&new_nw_size_cfg.timing, &flags); - ws_cfg_bbr_get(&new_nw_size_cfg.bbr, &flags); - ws_cfg_sec_prot_get(&new_nw_size_cfg.sec_prot, &flags); - ws_cfg_mpl_get(&new_nw_size_cfg.mpl, &flags); - - if (!nw_size_external_cfg) { - nw_size_external_cfg = ns_dyn_mem_alloc(sizeof(ws_cfg_nw_size_t)); - if (!nw_size_external_cfg) { - return -1; - } - memcpy(nw_size_external_cfg, &new_nw_size_cfg, sizeof(ws_cfg_nw_size_t)); - } - - network_size = network_size / 100; - if (network_size == 0) { - network_size = 1; - } - - if (ws_cfg_config_get_by_size(cur, network_size) == CONFIG_SMALL) { - ws_cfg_network_size_config_set_small(&new_nw_size_cfg); - } else if (ws_cfg_config_get_by_size(cur, network_size) == CONFIG_MEDIUM) { - ws_cfg_network_size_config_set_medium(&new_nw_size_cfg); - } else if (ws_cfg_config_get_by_size(cur, network_size) == CONFIG_LARGE) { - ws_cfg_network_size_config_set_large(&new_nw_size_cfg); - } else { - ws_cfg_network_size_config_set_xlarge(&new_nw_size_cfg); - } - - ws_cfg_gen_set(cur, NULL, &new_nw_size_cfg.gen, &flags); - ws_cfg_timing_set(cur, NULL, &new_nw_size_cfg.timing, &flags); - ws_cfg_bbr_set(cur, NULL, &new_nw_size_cfg.bbr, &flags); - ws_cfg_sec_prot_set(cur, NULL, &new_nw_size_cfg.sec_prot, &flags); - ws_cfg_mpl_set(cur, &ws_cfg.mpl, &new_nw_size_cfg.mpl, &flags); - - return CFG_SETTINGS_OK; -} - cfg_network_size_type_e ws_cfg_network_config_get(protocol_interface_info_entry_t *cur) { // Get size of the network Amount of devices in the network @@ -430,7 +290,7 @@ cfg_network_size_type_e ws_cfg_network_config_get(protocol_interface_info_entry_ (void)cur; ws_gen_cfg_t cfg; - if (ws_cfg_gen_get(&cfg, NULL) < 0) { + if (ws_cfg_gen_get(&cfg) < 0) { return CONFIG_SMALL; } @@ -563,7 +423,6 @@ static void ws_cfg_network_size_config_set_large(ws_cfg_nw_size_t *cfg) cfg->mpl.mpl_trickle_k = MPL_LARGE_K; cfg->mpl.mpl_trickle_timer_exp = MPL_LARGE_EXPIRATIONS; cfg->mpl.seed_set_entry_lifetime = MPL_LARGE_SEED_LIFETIME; - } static void ws_cfg_network_size_config_set_xlarge(ws_cfg_nw_size_t *cfg) @@ -653,25 +512,21 @@ static void ws_cfg_network_size_config_set_certificate(ws_cfg_nw_size_t *cfg) static int8_t ws_cfg_gen_default_set(ws_gen_cfg_t *cfg) { memset(cfg->network_name, 0, sizeof(cfg->network_name)); - cfg->network_pan_id = 0xffff; cfg->rpl_parent_candidate_max = WS_RPL_PARENT_CANDIDATE_MAX; cfg->rpl_selected_parent_max = WS_RPL_SELECTED_PARENT_MAX; return CFG_SETTINGS_OK; } -int8_t ws_cfg_gen_get(ws_gen_cfg_t *cfg, uint8_t *flags) +int8_t ws_cfg_gen_get(ws_gen_cfg_t *cfg) { - ws_gen_cfg_t *get_cfg = NULL; - ws_cfg_to_get((ws_cfgs_t **) &get_cfg, NULL, NULL, (ws_cfgs_t *) &ws_cfg.gen, 0, flags); - *cfg = *get_cfg; - + *cfg = ws_cfg.gen; return CFG_SETTINGS_OK; } -int8_t ws_cfg_gen_validate(ws_gen_cfg_t *cfg, ws_gen_cfg_t *new_cfg) +int8_t ws_cfg_gen_validate(ws_gen_cfg_t *new_cfg) { - ws_cfg_to_get((ws_cfgs_t **) &cfg, (ws_cfgs_t *) new_cfg, NULL, (ws_cfgs_t *) &ws_cfg.gen, 0, 0); + ws_gen_cfg_t *cfg = &ws_cfg.gen; if (strlen(new_cfg->network_name) > 32) { return CFG_SETTINGS_ERROR_GEN_CONF; @@ -679,7 +534,6 @@ int8_t ws_cfg_gen_validate(ws_gen_cfg_t *cfg, ws_gen_cfg_t *new_cfg) // Regulator domain, operating mode or class has changed if (strcmp(cfg->network_name, new_cfg->network_name) != 0 || - cfg->network_pan_id != new_cfg->network_pan_id || cfg->rpl_parent_candidate_max != new_cfg->rpl_parent_candidate_max || cfg->rpl_selected_parent_max != new_cfg->rpl_selected_parent_max) { return CFG_SETTINGS_CHANGED; @@ -688,30 +542,29 @@ int8_t ws_cfg_gen_validate(ws_gen_cfg_t *cfg, ws_gen_cfg_t *new_cfg) return CFG_SETTINGS_OK; } -int8_t ws_cfg_gen_set(protocol_interface_info_entry_t *cur, ws_gen_cfg_t *cfg, ws_gen_cfg_t *new_cfg, uint8_t *flags) +int8_t ws_cfg_gen_set(protocol_interface_info_entry_t *cur, ws_gen_cfg_t *new_cfg, uint8_t flags) { - (void) cur; - (void) flags; - - uint8_t cfg_flags; - int8_t ret = ws_cfg_to_get((ws_cfgs_t **) &cfg, (ws_cfgs_t *) new_cfg, (ws_cfg_validate) ws_cfg_gen_validate, (ws_cfgs_t *) &ws_cfg.gen, &cfg_flags, flags); - if (ret != CFG_SETTINGS_CHANGED) { + int8_t ret = ws_cfg_gen_validate(new_cfg); + if (!(flags & CFG_FLAGS_BOOTSTRAP_SET_VALUES) && ret != CFG_SETTINGS_CHANGED) { return ret; } - if (cfg == new_cfg) { + + if (flags & CFG_FLAGS_BOOTSTRAP_SET_VALUES) { return CFG_SETTINGS_OK; } + + ws_gen_cfg_t *cfg = &ws_cfg.gen; + ws_cfg_trace((ws_cfgs_t *) cfg, (ws_cfgs_t *) new_cfg, sizeof(ws_gen_cfg_t), "gen"); cfg->network_size = new_cfg->network_size; if (&cfg->network_name != &new_cfg->network_name) { strncpy(cfg->network_name, new_cfg->network_name, 32); } - cfg->network_pan_id = new_cfg->network_pan_id; cfg->rpl_parent_candidate_max = new_cfg->rpl_parent_candidate_max; cfg->rpl_selected_parent_max = new_cfg->rpl_selected_parent_max; - if (cur && !(cfg_flags & CFG_FLAGS_BOOTSTRAP_RESTART_DISABLE)) { + if (cur && !(flags & CFG_FLAGS_BOOTSTRAP_RESTART_DISABLE)) { ws_bootstrap_restart_delayed(cur->id); } @@ -730,18 +583,15 @@ int8_t ws_cfg_phy_default_set(ws_phy_cfg_t *cfg) return CFG_SETTINGS_OK; } -int8_t ws_cfg_phy_get(ws_phy_cfg_t *cfg, uint8_t *flags) +int8_t ws_cfg_phy_get(ws_phy_cfg_t *cfg) { - ws_phy_cfg_t *get_cfg = NULL; - ws_cfg_to_get((ws_cfgs_t **) &get_cfg, NULL, NULL, (ws_cfgs_t *) &ws_cfg.phy, 0, flags); - *cfg = *get_cfg; - + *cfg = ws_cfg.phy; return CFG_SETTINGS_OK; } -int8_t ws_cfg_phy_validate(ws_phy_cfg_t *cfg, ws_phy_cfg_t *new_cfg) +int8_t ws_cfg_phy_validate(ws_phy_cfg_t *new_cfg) { - ws_cfg_to_get((ws_cfgs_t **) &cfg, (ws_cfgs_t *) new_cfg, NULL, (ws_cfgs_t *) &ws_cfg.phy, 0, 0); + ws_phy_cfg_t *cfg = &ws_cfg.phy; // Regulator domain, operating mode or class has changed if (cfg->regulatory_domain != new_cfg->regulatory_domain || @@ -770,15 +620,14 @@ int8_t ws_cfg_phy_validate(ws_phy_cfg_t *cfg, ws_phy_cfg_t *new_cfg) return CFG_SETTINGS_OK; } -int8_t ws_cfg_phy_set(protocol_interface_info_entry_t *cur, ws_phy_cfg_t *cfg, ws_phy_cfg_t *new_cfg, uint8_t *flags) +int8_t ws_cfg_phy_set(protocol_interface_info_entry_t *cur, ws_phy_cfg_t *new_cfg, uint8_t flags) { - uint8_t cfg_flags; - int8_t ret = ws_cfg_to_get((ws_cfgs_t **) &cfg, (ws_cfgs_t *) new_cfg, (ws_cfg_validate) ws_cfg_phy_validate, (ws_cfgs_t *) &ws_cfg.phy, &cfg_flags, flags); - if (ret != CFG_SETTINGS_CHANGED) { + int8_t ret = ws_cfg_phy_validate(new_cfg); + if (!(flags & CFG_FLAGS_BOOTSTRAP_SET_VALUES) && ret != CFG_SETTINGS_CHANGED) { return ret; } // Check settings and configure interface - if (cur && !(cfg_flags & CFG_FLAGS_DISABLE_VAL_SET)) { + if (cur) { // Set operating mode for FSK if given with PHY mode ID if ((new_cfg->phy_mode_id == 1) || (new_cfg->phy_mode_id == 17)) { cur->ws_info->hopping_schdule.operating_mode = OPERATING_MODE_1a; @@ -809,15 +658,17 @@ int8_t ws_cfg_phy_set(protocol_interface_info_entry_t *cur, ws_phy_cfg_t *cfg, w } } - if (cfg == new_cfg) { + if (flags & CFG_FLAGS_BOOTSTRAP_SET_VALUES) { return CFG_SETTINGS_OK; } + ws_phy_cfg_t *cfg = &ws_cfg.phy; + ws_cfg_trace((ws_cfgs_t *) cfg, (ws_cfgs_t *) new_cfg, sizeof(ws_phy_cfg_t), "phy"); *cfg = *new_cfg; - if (cur && !(cfg_flags & CFG_FLAGS_BOOTSTRAP_RESTART_DISABLE)) { + if (cur && !(flags & CFG_FLAGS_BOOTSTRAP_RESTART_DISABLE)) { ws_bootstrap_restart_delayed(cur->id); } @@ -837,18 +688,15 @@ int8_t ws_cfg_timing_default_set(ws_timing_cfg_t *cfg) return CFG_SETTINGS_OK; } -int8_t ws_cfg_timing_get(ws_timing_cfg_t *cfg, uint8_t *flags) +int8_t ws_cfg_timing_get(ws_timing_cfg_t *cfg) { - ws_timing_cfg_t *get_cfg = NULL; - ws_cfg_to_get((ws_cfgs_t **) &get_cfg, NULL, NULL, (ws_cfgs_t *) &ws_cfg.timing, 0, flags); - *cfg = *get_cfg; - + *cfg = ws_cfg.timing; return CFG_SETTINGS_OK; } -int8_t ws_cfg_timing_validate(ws_timing_cfg_t *cfg, ws_timing_cfg_t *new_cfg) +int8_t ws_cfg_timing_validate(ws_timing_cfg_t *new_cfg) { - ws_cfg_to_get((ws_cfgs_t **) &cfg, (ws_cfgs_t *) new_cfg, NULL, (ws_cfgs_t *) &ws_cfg.timing, 0, 0); + ws_timing_cfg_t *cfg = &ws_cfg.timing; if (cfg->disc_trickle_imin != new_cfg->disc_trickle_imin || cfg->disc_trickle_imax != new_cfg->disc_trickle_imax || @@ -876,15 +724,16 @@ int8_t ws_cfg_timing_validate(ws_timing_cfg_t *cfg, ws_timing_cfg_t *new_cfg) return CFG_SETTINGS_OK; } -int8_t ws_cfg_timing_set(protocol_interface_info_entry_t *cur, ws_timing_cfg_t *cfg, ws_timing_cfg_t *new_cfg, uint8_t *flags) +int8_t ws_cfg_timing_set(protocol_interface_info_entry_t *cur, ws_timing_cfg_t *new_cfg, uint8_t flags) { - uint8_t cfg_flags; - int8_t ret = ws_cfg_to_get((ws_cfgs_t **) &cfg, (ws_cfgs_t *) new_cfg, (ws_cfg_validate) ws_cfg_timing_validate, (ws_cfgs_t *) &ws_cfg.timing, &cfg_flags, flags); - if (ret != CFG_SETTINGS_CHANGED) { + (void) flags; + + int8_t ret = ws_cfg_timing_validate(new_cfg); + if (!(flags & CFG_FLAGS_BOOTSTRAP_SET_VALUES) && ret != CFG_SETTINGS_CHANGED) { return ret; } - if (cur && !(cfg_flags & CFG_FLAGS_DISABLE_VAL_SET)) { + if (cur) { cur->ws_info->trickle_params_pan_discovery.Imin = new_cfg->disc_trickle_imin * 10; cur->ws_info->trickle_params_pan_discovery.Imax = new_cfg->disc_trickle_imax * 10; cur->ws_info->trickle_params_pan_discovery.k = new_cfg->disc_trickle_k; @@ -892,10 +741,12 @@ int8_t ws_cfg_timing_set(protocol_interface_info_entry_t *cur, ws_timing_cfg_t * ws_pae_controller_configure(cur, NULL, NULL, new_cfg); } - if (cfg == new_cfg) { + if (flags & CFG_FLAGS_BOOTSTRAP_SET_VALUES) { return CFG_SETTINGS_OK; } + ws_timing_cfg_t *cfg = &ws_cfg.timing; + ws_cfg_trace((ws_cfgs_t *) cfg, (ws_cfgs_t *) new_cfg, sizeof(ws_timing_cfg_t), "timing"); *cfg = *new_cfg; @@ -922,19 +773,15 @@ static int8_t ws_cfg_bbr_default_set(ws_bbr_cfg_t *cfg) return CFG_SETTINGS_OK; } -int8_t ws_cfg_bbr_get(ws_bbr_cfg_t *cfg, uint8_t *flags) +int8_t ws_cfg_bbr_get(ws_bbr_cfg_t *cfg) { - ws_bbr_cfg_t *get_cfg = NULL; - ws_cfg_to_get((ws_cfgs_t **) &get_cfg, NULL, NULL, (ws_cfgs_t *) &ws_cfg.bbr, 0, flags); - *cfg = *get_cfg; - + *cfg = ws_cfg.bbr; return CFG_SETTINGS_OK; } -int8_t ws_cfg_bbr_validate(ws_bbr_cfg_t *cfg, ws_bbr_cfg_t *new_cfg) +int8_t ws_cfg_bbr_validate(ws_bbr_cfg_t *new_cfg) { - ws_cfg_to_get((ws_cfgs_t **) &cfg, (ws_cfgs_t *) new_cfg, NULL, (ws_cfgs_t *) &ws_cfg.bbr, 0, 0); - + ws_bbr_cfg_t *cfg = &ws_cfg.bbr; if (cfg->dio_interval_min != new_cfg->dio_interval_min || cfg->dio_interval_doublings != new_cfg->dio_interval_doublings || cfg->dio_redundancy_constant != new_cfg->dio_redundancy_constant || @@ -948,18 +795,16 @@ int8_t ws_cfg_bbr_validate(ws_bbr_cfg_t *cfg, ws_bbr_cfg_t *new_cfg) return CFG_SETTINGS_OK; } -int8_t ws_cfg_bbr_set(protocol_interface_info_entry_t *cur, ws_bbr_cfg_t *cfg, ws_bbr_cfg_t *new_cfg, uint8_t *flags) +int8_t ws_cfg_bbr_set(protocol_interface_info_entry_t *cur, ws_bbr_cfg_t *new_cfg, uint8_t flags) { - (void) cur; (void) flags; - uint8_t cfg_flags; - int8_t ret = ws_cfg_to_get((ws_cfgs_t **) &cfg, (ws_cfgs_t *) new_cfg, (ws_cfg_validate) ws_cfg_bbr_validate, (ws_cfgs_t *) &ws_cfg.bbr, &cfg_flags, flags); - if (ret != CFG_SETTINGS_CHANGED) { + int8_t ret = ws_cfg_bbr_validate(new_cfg); + if (!(flags & CFG_FLAGS_BOOTSTRAP_SET_VALUES) && ret != CFG_SETTINGS_CHANGED) { return ret; } - if (!(cfg_flags & CFG_FLAGS_DISABLE_VAL_SET)) { + if (cur) { // cur is optional, default values are for Wi-SUN small network parameters, ws_bbr_rpl_config(cur, new_cfg->dio_interval_min, new_cfg->dio_interval_doublings, new_cfg->dio_redundancy_constant, new_cfg->dag_max_rank_increase, @@ -967,10 +812,12 @@ int8_t ws_cfg_bbr_set(protocol_interface_info_entry_t *cur, ws_bbr_cfg_t *cfg, w ws_bbr_dhcp_address_lifetime_set(cur, new_cfg->dhcp_address_lifetime); } - if (cfg == new_cfg) { + if (flags & CFG_FLAGS_BOOTSTRAP_SET_VALUES) { return CFG_SETTINGS_OK; } + ws_bbr_cfg_t *cfg = &ws_cfg.bbr; + ws_cfg_trace((ws_cfgs_t *) cfg, (ws_cfgs_t *) new_cfg, sizeof(ws_bbr_cfg_t), "rpl"); *cfg = *new_cfg; @@ -990,18 +837,15 @@ static int8_t ws_cfg_mpl_default_set(ws_mpl_cfg_t *cfg) return CFG_SETTINGS_OK; } -int8_t ws_cfg_mpl_get(ws_mpl_cfg_t *cfg, uint8_t *flags) +int8_t ws_cfg_mpl_get(ws_mpl_cfg_t *cfg) { - ws_mpl_cfg_t *get_cfg = NULL; - ws_cfg_to_get((ws_cfgs_t **) &get_cfg, NULL, NULL, (ws_cfgs_t *) &ws_cfg.mpl, 0, flags); - *cfg = *get_cfg; - + *cfg = ws_cfg.mpl; return CFG_SETTINGS_OK; } -int8_t ws_cfg_mpl_validate(ws_mpl_cfg_t *cfg, ws_mpl_cfg_t *new_cfg) +int8_t ws_cfg_mpl_validate(ws_mpl_cfg_t *new_cfg) { - ws_cfg_to_get((ws_cfgs_t **) &cfg, (ws_cfgs_t *) new_cfg, NULL, (ws_cfgs_t *) &ws_cfg.mpl, 0, 0); + ws_mpl_cfg_t *cfg = &ws_cfg.mpl; // MPL configuration has changed if (cfg->mpl_trickle_imin != new_cfg->mpl_trickle_imin || @@ -1015,9 +859,9 @@ int8_t ws_cfg_mpl_validate(ws_mpl_cfg_t *cfg, ws_mpl_cfg_t *new_cfg) return CFG_SETTINGS_OK; } -int8_t ws_cfg_mpl_set(protocol_interface_info_entry_t *cur, ws_mpl_cfg_t *cfg, ws_mpl_cfg_t *new_cfg, uint8_t *flags) +int8_t ws_cfg_mpl_set(protocol_interface_info_entry_t *cur, ws_mpl_cfg_t *new_cfg, uint8_t flags) { - uint8_t cfg_flags; + (void) flags; // In Wi-SUN Border router will have modified settings to improve reliability if (cur && cur->bootsrap_mode == ARM_NWK_BOOTSRAP_MODE_6LoWPAN_BORDER_ROUTER) { @@ -1033,12 +877,12 @@ int8_t ws_cfg_mpl_set(protocol_interface_info_entry_t *cur, ws_mpl_cfg_t *cfg, w } } - int8_t ret = ws_cfg_to_get((ws_cfgs_t **) &cfg, (ws_cfgs_t *) new_cfg, (ws_cfg_validate) ws_cfg_mpl_validate, (ws_cfgs_t *) &ws_cfg.mpl, &cfg_flags, flags); - if (ret != CFG_SETTINGS_CHANGED) { + int8_t ret = ws_cfg_mpl_validate(new_cfg); + if (!(flags & CFG_FLAGS_BOOTSTRAP_SET_VALUES) && ret != CFG_SETTINGS_CHANGED) { return ret; } - if (cur && !(cfg_flags & CFG_FLAGS_DISABLE_VAL_SET)) { + if (cur) { cur->mpl_data_trickle_params.Imin = MPL_MS_TO_TICKS(new_cfg->mpl_trickle_imin * 1000); cur->mpl_data_trickle_params.Imax = MPL_MS_TO_TICKS(new_cfg->mpl_trickle_imax * 1000); cur->mpl_data_trickle_params.k = new_cfg->mpl_trickle_k; @@ -1051,10 +895,12 @@ int8_t ws_cfg_mpl_set(protocol_interface_info_entry_t *cur, ws_mpl_cfg_t *cfg, w } } - if (cfg == new_cfg) { + if (flags & CFG_FLAGS_BOOTSTRAP_SET_VALUES) { return CFG_SETTINGS_OK; } + ws_mpl_cfg_t *cfg = &ws_cfg.mpl; + ws_cfg_trace((ws_cfgs_t *) cfg, (ws_cfgs_t *) new_cfg, sizeof(ws_mpl_cfg_t), "mpl"); *cfg = *new_cfg; @@ -1080,18 +926,15 @@ int8_t ws_cfg_fhss_default_set(ws_fhss_cfg_t *cfg) return CFG_SETTINGS_OK; } -int8_t ws_cfg_fhss_get(ws_fhss_cfg_t *cfg, uint8_t *flags) +int8_t ws_cfg_fhss_get(ws_fhss_cfg_t *cfg) { - ws_fhss_cfg_t *get_cfg = NULL; - ws_cfg_to_get((ws_cfgs_t **) &get_cfg, NULL, NULL, (ws_cfgs_t *) &ws_cfg.fhss, 0, flags); - *cfg = *get_cfg; - + *cfg = ws_cfg.fhss; return CFG_SETTINGS_OK; } -int8_t ws_cfg_fhss_validate(ws_fhss_cfg_t *cfg, ws_fhss_cfg_t *new_cfg) +int8_t ws_cfg_fhss_validate(ws_fhss_cfg_t *new_cfg) { - ws_cfg_to_get((ws_cfgs_t **) &cfg, (ws_cfgs_t *) new_cfg, NULL, (ws_cfgs_t *) &ws_cfg.fhss, 0, 0); + ws_fhss_cfg_t *cfg = &ws_cfg.fhss; if (memcmp(cfg->fhss_channel_mask, new_cfg->fhss_channel_mask, sizeof(uint32_t) * 8) != 0 || cfg->fhss_uc_dwell_interval != new_cfg->fhss_uc_dwell_interval || @@ -1123,20 +966,21 @@ int8_t ws_cfg_fhss_validate(ws_fhss_cfg_t *cfg, ws_fhss_cfg_t *new_cfg) return CFG_SETTINGS_OK; } -int8_t ws_cfg_fhss_set(protocol_interface_info_entry_t *cur, ws_fhss_cfg_t *cfg, ws_fhss_cfg_t *new_cfg, uint8_t *flags) +int8_t ws_cfg_fhss_set(protocol_interface_info_entry_t *cur, ws_fhss_cfg_t *new_cfg, uint8_t flags) { (void) cur; - uint8_t cfg_flags; - int8_t ret = ws_cfg_to_get((ws_cfgs_t **) &cfg, (ws_cfgs_t *) new_cfg, (ws_cfg_validate) ws_cfg_fhss_validate, (ws_cfgs_t *) &ws_cfg.fhss, &cfg_flags, flags); - if (ret != CFG_SETTINGS_CHANGED) { + int8_t ret = ws_cfg_fhss_validate(new_cfg); + if (!(flags & CFG_FLAGS_BOOTSTRAP_SET_VALUES) && ret != CFG_SETTINGS_CHANGED) { return ret; } - if (cfg == new_cfg) { + if (flags & CFG_FLAGS_BOOTSTRAP_SET_VALUES) { return CFG_SETTINGS_OK; } + ws_fhss_cfg_t *cfg = &ws_cfg.fhss; + ws_cfg_trace((ws_cfgs_t *) cfg, (ws_cfgs_t *) new_cfg, sizeof(ws_fhss_cfg_t), "fhss"); *cfg = *new_cfg; @@ -1159,7 +1003,7 @@ int8_t ws_cfg_fhss_set(protocol_interface_info_entry_t *cur, ws_fhss_cfg_t *cfg, cfg->fhss_bc_fixed_channel = 0xffff; } - if (cur && !(cfg_flags & CFG_FLAGS_BOOTSTRAP_RESTART_DISABLE)) { + if (cur && !(flags & CFG_FLAGS_BOOTSTRAP_RESTART_DISABLE)) { ws_bootstrap_restart_delayed(cur->id); } @@ -1181,18 +1025,15 @@ static int8_t ws_cfg_sec_timer_default_set(ws_sec_timer_cfg_t *cfg) return CFG_SETTINGS_OK; } -int8_t ws_cfg_sec_timer_get(ws_sec_timer_cfg_t *cfg, uint8_t *flags) +int8_t ws_cfg_sec_timer_get(ws_sec_timer_cfg_t *cfg) { - ws_sec_timer_cfg_t *get_cfg = NULL; - ws_cfg_to_get((ws_cfgs_t **) &get_cfg, NULL, NULL, (ws_cfgs_t *) &ws_cfg.sec_timer, 0, flags); - *cfg = *get_cfg; - + *cfg = ws_cfg.sec_timer; return CFG_SETTINGS_OK; } -int8_t ws_cfg_sec_timer_validate(ws_sec_timer_cfg_t *cfg, ws_sec_timer_cfg_t *new_cfg) +int8_t ws_cfg_sec_timer_validate(ws_sec_timer_cfg_t *new_cfg) { - ws_cfg_to_get((ws_cfgs_t **) &cfg, (ws_cfgs_t *) new_cfg, NULL, (ws_cfgs_t *) &ws_cfg.sec_timer, 0, 0); + ws_sec_timer_cfg_t *cfg = &ws_cfg.sec_timer; if (cfg->gtk_expire_offset != new_cfg->gtk_expire_offset || cfg->pmk_lifetime != new_cfg->pmk_lifetime || @@ -1210,22 +1051,25 @@ int8_t ws_cfg_sec_timer_validate(ws_sec_timer_cfg_t *cfg, ws_sec_timer_cfg_t *ne return CFG_SETTINGS_OK; } -int8_t ws_cfg_sec_timer_set(protocol_interface_info_entry_t *cur, ws_sec_timer_cfg_t *cfg, ws_sec_timer_cfg_t *new_cfg, uint8_t *flags) +int8_t ws_cfg_sec_timer_set(protocol_interface_info_entry_t *cur, ws_sec_timer_cfg_t *new_cfg, uint8_t flags) { - uint8_t cfg_flags; - int8_t ret = ws_cfg_to_get((ws_cfgs_t **) &cfg, (ws_cfgs_t *) new_cfg, (ws_cfg_validate) ws_cfg_sec_timer_validate, (ws_cfgs_t *) &ws_cfg.sec_timer, &cfg_flags, flags); - if (ret != CFG_SETTINGS_CHANGED) { + (void) flags; + + int8_t ret = ws_cfg_sec_timer_validate(new_cfg); + if (!(flags & CFG_FLAGS_BOOTSTRAP_SET_VALUES) && ret != CFG_SETTINGS_CHANGED) { return ret; } - if (cur && !(cfg_flags & CFG_FLAGS_DISABLE_VAL_SET)) { + if (cur) { ws_pae_controller_configure(cur, new_cfg, NULL, NULL); } - if (cfg == new_cfg) { + if (flags & CFG_FLAGS_BOOTSTRAP_SET_VALUES) { return CFG_SETTINGS_OK; } + ws_sec_timer_cfg_t *cfg = &ws_cfg.sec_timer; + ws_cfg_trace((ws_cfgs_t *) cfg, (ws_cfgs_t *) new_cfg, sizeof(ws_sec_timer_cfg_t), "sec_timer"); *cfg = *new_cfg; @@ -1249,18 +1093,15 @@ static int8_t ws_cfg_sec_prot_default_set(ws_sec_prot_cfg_t *cfg) return CFG_SETTINGS_OK; } -int8_t ws_cfg_sec_prot_get(ws_sec_prot_cfg_t *cfg, uint8_t *flags) +int8_t ws_cfg_sec_prot_get(ws_sec_prot_cfg_t *cfg) { - ws_sec_prot_cfg_t *get_cfg = NULL; - ws_cfg_to_get((ws_cfgs_t **) &get_cfg, NULL, NULL, (ws_cfgs_t *) &ws_cfg.sec_prot, 0, flags); - *cfg = *get_cfg; - + *cfg = ws_cfg.sec_prot; return CFG_SETTINGS_OK; } -int8_t ws_cfg_sec_prot_validate(ws_sec_prot_cfg_t *cfg, ws_sec_prot_cfg_t *new_cfg) +int8_t ws_cfg_sec_prot_validate(ws_sec_prot_cfg_t *new_cfg) { - ws_cfg_to_get((ws_cfgs_t **) &cfg, (ws_cfgs_t *) new_cfg, NULL, (ws_cfgs_t *) &ws_cfg.sec_prot, 0, 0); + ws_sec_prot_cfg_t *cfg = &ws_cfg.sec_prot; if (cfg->sec_prot_trickle_imin != new_cfg->sec_prot_trickle_imin || cfg->sec_prot_trickle_imax != new_cfg->sec_prot_trickle_imax || @@ -1279,22 +1120,25 @@ int8_t ws_cfg_sec_prot_validate(ws_sec_prot_cfg_t *cfg, ws_sec_prot_cfg_t *new_c return CFG_SETTINGS_OK; } -int8_t ws_cfg_sec_prot_set(protocol_interface_info_entry_t *cur, ws_sec_prot_cfg_t *cfg, ws_sec_prot_cfg_t *new_cfg, uint8_t *flags) +int8_t ws_cfg_sec_prot_set(protocol_interface_info_entry_t *cur, ws_sec_prot_cfg_t *new_cfg, uint8_t flags) { - uint8_t cfg_flags; - int8_t ret = ws_cfg_to_get((ws_cfgs_t **) &cfg, (ws_cfgs_t *) new_cfg, (ws_cfg_validate) ws_cfg_sec_prot_validate, (ws_cfgs_t *) &ws_cfg.sec_prot, &cfg_flags, flags); - if (ret != CFG_SETTINGS_CHANGED) { + (void) flags; + + int8_t ret = ws_cfg_sec_prot_validate(new_cfg); + if (!(flags & CFG_FLAGS_BOOTSTRAP_SET_VALUES) && ret != CFG_SETTINGS_CHANGED) { return ret; } - if (cur && !(cfg_flags & CFG_FLAGS_DISABLE_VAL_SET)) { + if (cur) { ws_pae_controller_configure(cur, NULL, new_cfg, NULL); } - if (cfg == new_cfg) { + if (flags & CFG_FLAGS_BOOTSTRAP_SET_VALUES) { return CFG_SETTINGS_OK; } + ws_sec_prot_cfg_t *cfg = &ws_cfg.sec_prot; + ws_cfg_trace((ws_cfgs_t *) cfg, (ws_cfgs_t *) new_cfg, sizeof(ws_sec_prot_cfg_t), "sec_prot"); *cfg = *new_cfg; @@ -1324,11 +1168,9 @@ int8_t ws_cfg_settings_default_set(void) // Set new configuration values for (uint8_t index = 0; index < CFG_CB_NUM; index++) { - uint8_t flags = 0; if (cfg_cb[index].set(NULL, ((uint8_t *)&ws_cfg) + cfg_cb[index].setting_offset, - ((uint8_t *)&ws_cfg) + cfg_cb[index].setting_offset, - &flags) < 0) { + 0x00) < 0) { tr_info("FATAL CONFIG FAILURE"); ret_value = CFG_SETTINGS_OTHER_ERROR; } @@ -1345,13 +1187,11 @@ int8_t ws_cfg_settings_interface_set(protocol_interface_info_entry_t *cur) // Set new configuration values for (uint8_t index = 0; index < CFG_CB_NUM; index++) { - uint8_t flags = CFG_FLAGS_BOOTSTRAP_RESTART_DISABLE; // Validation if (cfg_cb[index].set) { if (cfg_cb[index].set(cur, ((uint8_t *)&ws_cfg) + cfg_cb[index].setting_offset, - ((uint8_t *)&ws_cfg) + cfg_cb[index].setting_offset, - &flags) < 0) { + CFG_FLAGS_BOOTSTRAP_RESTART_DISABLE | CFG_FLAGS_BOOTSTRAP_SET_VALUES) < 0) { tr_info("FATAL CONFIG FAILURE"); ret_value = CFG_SETTINGS_OTHER_ERROR; } @@ -1361,30 +1201,19 @@ int8_t ws_cfg_settings_interface_set(protocol_interface_info_entry_t *cur) return ret_value; } -int8_t ws_cfg_settings_get(protocol_interface_info_entry_t *cur, ws_cfg_t *cfg) +int8_t ws_cfg_settings_get(ws_cfg_t *cfg) { - (void) cur; - *cfg = ws_cfg; - ws_cfg_gen_get(&cfg->gen, NULL); - ws_cfg_timing_get(&cfg->timing, NULL); - ws_cfg_bbr_get(&cfg->bbr, NULL); - ws_cfg_sec_prot_get(&cfg->sec_prot, NULL); - ws_cfg_mpl_get(&cfg->mpl, NULL); - return CFG_SETTINGS_OK; } -int8_t ws_cfg_settings_validate(protocol_interface_info_entry_t *cur, struct ws_cfg_s *new_cfg) +int8_t ws_cfg_settings_validate(struct ws_cfg_s *new_cfg) { - (void) cur; - // Validate new configuration values for (uint8_t index = 0; index < CFG_CB_NUM; index++) { if (cfg_cb[index].validate) { int8_t ret = cfg_cb[index].validate( - ((uint8_t *)&ws_cfg) + cfg_cb[index].setting_offset, ((uint8_t *)new_cfg) + cfg_cb[index].setting_offset); if (ret < 0) { // Validation failed @@ -1406,7 +1235,6 @@ int8_t ws_cfg_settings_set(protocol_interface_info_entry_t *cur, ws_cfg_t *new_c for (uint8_t index = 0; index < CFG_CB_NUM; index++) { if (cfg_cb[index].validate) { int8_t ret = cfg_cb[index].validate( - ((uint8_t *)&ws_cfg) + cfg_cb[index].setting_offset, ((uint8_t *)new_cfg) + cfg_cb[index].setting_offset); if (ret < 0) { @@ -1425,12 +1253,10 @@ int8_t ws_cfg_settings_set(protocol_interface_info_entry_t *cur, ws_cfg_t *new_c // Set new configuration values for (uint8_t index = 0; index < CFG_CB_NUM; index++) { - uint8_t flags = 0; // Validation if (call_cfg_set[index]) { if (cfg_cb[index].set(cur, - ((uint8_t *)&ws_cfg) + cfg_cb[index].setting_offset, - ((uint8_t *)new_cfg) + cfg_cb[index].setting_offset, &flags) < 0) { + ((uint8_t *)new_cfg) + cfg_cb[index].setting_offset, 0x00) < 0) { tr_info("FATAL CONFIG FAILURE"); ret_value = CFG_SETTINGS_OTHER_ERROR; } diff --git a/source/6LoWPAN/ws/ws_cfg_settings.h b/source/6LoWPAN/ws/ws_cfg_settings.h index 827b45aeff..98f7b15905 100644 --- a/source/6LoWPAN/ws/ws_cfg_settings.h +++ b/source/6LoWPAN/ws/ws_cfg_settings.h @@ -26,7 +26,6 @@ typedef struct ws_gen_cfg_s { default values */ uint8_t network_size; /**< Network size selection; default medium (= 8) */ char network_name[33]; /**< Network name; max 32 octets + terminating 0 */ - uint16_t network_pan_id; /**< PAN identifier; PAN_ID; default 0xffff */ uint16_t rpl_parent_candidate_max; /**< RPL parent candidate maximum value; default 5 */ uint16_t rpl_selected_parent_max; /**< RPL selected parent maximum value; default 2 */ } ws_gen_cfg_t; @@ -163,48 +162,50 @@ typedef enum { int8_t ws_cfg_settings_init(void); int8_t ws_cfg_settings_default_set(void); int8_t ws_cfg_settings_interface_set(protocol_interface_info_entry_t *cur); -int8_t ws_cfg_network_size_configure(protocol_interface_info_entry_t *cur, uint16_t network_size); +int8_t ws_cfg_settings_get(ws_cfg_t *cfg); +int8_t ws_cfg_settings_validate(struct ws_cfg_s *new_cfg); +int8_t ws_cfg_settings_set(protocol_interface_info_entry_t *cur, ws_cfg_t *new_cfg); cfg_network_size_type_e ws_cfg_network_config_get(protocol_interface_info_entry_t *cur); -int8_t ws_cfg_network_size_get(ws_gen_cfg_t *cfg, uint8_t *flags); -int8_t ws_cfg_network_size_validate(ws_gen_cfg_t *cfg, ws_gen_cfg_t *new_cfg); -int8_t ws_cfg_network_size_set(protocol_interface_info_entry_t *cur, ws_gen_cfg_t *cfg, ws_gen_cfg_t *new_cfg, uint8_t *flags); +int8_t ws_cfg_network_size_get(ws_gen_cfg_t *cfg); +int8_t ws_cfg_network_size_validate(ws_gen_cfg_t *new_cfg); +int8_t ws_cfg_network_size_set(protocol_interface_info_entry_t *cur, ws_gen_cfg_t *new_cfg, uint8_t flags); -int8_t ws_cfg_gen_get(ws_gen_cfg_t *cfg, uint8_t *flags); -int8_t ws_cfg_gen_validate(ws_gen_cfg_t *cfg, ws_gen_cfg_t *new_cfg); -int8_t ws_cfg_gen_set(protocol_interface_info_entry_t *cur, ws_gen_cfg_t *cfg, ws_gen_cfg_t *new_cfg, uint8_t *flags); +int8_t ws_cfg_gen_get(ws_gen_cfg_t *cfg); +int8_t ws_cfg_gen_validate(ws_gen_cfg_t *new_cfg); +int8_t ws_cfg_gen_set(protocol_interface_info_entry_t *cur, ws_gen_cfg_t *new_cfg, uint8_t flags); int8_t ws_cfg_phy_default_set(ws_phy_cfg_t *cfg); -int8_t ws_cfg_phy_get(ws_phy_cfg_t *cfg, uint8_t *flags); -int8_t ws_cfg_phy_validate(ws_phy_cfg_t *cfg, ws_phy_cfg_t *new_cfg); -int8_t ws_cfg_phy_set(protocol_interface_info_entry_t *cur, ws_phy_cfg_t *cfg, ws_phy_cfg_t *new_cfg, uint8_t *flags); +int8_t ws_cfg_phy_get(ws_phy_cfg_t *cfg); +int8_t ws_cfg_phy_validate(ws_phy_cfg_t *new_cfg); +int8_t ws_cfg_phy_set(protocol_interface_info_entry_t *cur, ws_phy_cfg_t *new_cfg, uint8_t flags); int8_t ws_cfg_timing_default_set(ws_timing_cfg_t *cfg); -int8_t ws_cfg_timing_get(ws_timing_cfg_t *cfg, uint8_t *flags); -int8_t ws_cfg_timing_validate(ws_timing_cfg_t *cfg, ws_timing_cfg_t *new_cfg); -int8_t ws_cfg_timing_set(protocol_interface_info_entry_t *cur, ws_timing_cfg_t *cfg, ws_timing_cfg_t *new_cfg, uint8_t *flags); +int8_t ws_cfg_timing_get(ws_timing_cfg_t *cfg); +int8_t ws_cfg_timing_validate(ws_timing_cfg_t *new_cfg); +int8_t ws_cfg_timing_set(protocol_interface_info_entry_t *cur, ws_timing_cfg_t *new_cfg, uint8_t flags); -int8_t ws_cfg_bbr_get(ws_bbr_cfg_t *cfg, uint8_t *flags); -int8_t ws_cfg_bbr_validate(ws_bbr_cfg_t *cfg, ws_bbr_cfg_t *new_cfg); -int8_t ws_cfg_bbr_set(protocol_interface_info_entry_t *cur, ws_bbr_cfg_t *cfg, ws_bbr_cfg_t *new_cfg, uint8_t *flags); +int8_t ws_cfg_bbr_get(ws_bbr_cfg_t *cfg); +int8_t ws_cfg_bbr_validate(ws_bbr_cfg_t *new_cfg); +int8_t ws_cfg_bbr_set(protocol_interface_info_entry_t *cur, ws_bbr_cfg_t *new_cfg, uint8_t flags); -int8_t ws_cfg_mpl_get(ws_mpl_cfg_t *cfg, uint8_t *flags); -int8_t ws_cfg_mpl_validate(ws_mpl_cfg_t *cfg, ws_mpl_cfg_t *new_cfg); -int8_t ws_cfg_mpl_set(protocol_interface_info_entry_t *cur, ws_mpl_cfg_t *cfg, ws_mpl_cfg_t *new_cfg, uint8_t *flags); +int8_t ws_cfg_mpl_get(ws_mpl_cfg_t *cfg); +int8_t ws_cfg_mpl_validate(ws_mpl_cfg_t *new_cfg); +int8_t ws_cfg_mpl_set(protocol_interface_info_entry_t *cur, ws_mpl_cfg_t *new_cfg, uint8_t flags); int8_t ws_cfg_fhss_default_set(ws_fhss_cfg_t *cfg); -int8_t ws_cfg_fhss_get(ws_fhss_cfg_t *cfg, uint8_t *flags); -int8_t ws_cfg_fhss_validate(ws_fhss_cfg_t *cfg, ws_fhss_cfg_t *new_cfg); -int8_t ws_cfg_fhss_set(protocol_interface_info_entry_t *cur, ws_fhss_cfg_t *cfg, ws_fhss_cfg_t *new_cfg, uint8_t *flags); +int8_t ws_cfg_fhss_get(ws_fhss_cfg_t *cfg); +int8_t ws_cfg_fhss_validate(ws_fhss_cfg_t *new_cfg); +int8_t ws_cfg_fhss_set(protocol_interface_info_entry_t *cur, ws_fhss_cfg_t *new_cfg, uint8_t flags); -int8_t ws_cfg_sec_timer_get(ws_sec_timer_cfg_t *cfg, uint8_t *flags); -int8_t ws_cfg_sec_timer_validate(ws_sec_timer_cfg_t *cfg, ws_sec_timer_cfg_t *new_cfg); -int8_t ws_cfg_sec_timer_set(protocol_interface_info_entry_t *cur, ws_sec_timer_cfg_t *cfg, ws_sec_timer_cfg_t *new_cfg, uint8_t *flags); +int8_t ws_cfg_sec_timer_get(ws_sec_timer_cfg_t *cfg); +int8_t ws_cfg_sec_timer_validate(ws_sec_timer_cfg_t *new_cfg); +int8_t ws_cfg_sec_timer_set(protocol_interface_info_entry_t *cur, ws_sec_timer_cfg_t *new_cfg, uint8_t flags); -int8_t ws_cfg_sec_prot_get(ws_sec_prot_cfg_t *cfg, uint8_t *flags); -int8_t ws_cfg_sec_prot_validate(ws_sec_prot_cfg_t *cfg, ws_sec_prot_cfg_t *new_cfg); -int8_t ws_cfg_sec_prot_set(protocol_interface_info_entry_t *cur, ws_sec_prot_cfg_t *cfg, ws_sec_prot_cfg_t *new_cfg, uint8_t *flags); +int8_t ws_cfg_sec_prot_get(ws_sec_prot_cfg_t *cfg); +int8_t ws_cfg_sec_prot_validate(ws_sec_prot_cfg_t *new_cfg); +int8_t ws_cfg_sec_prot_set(protocol_interface_info_entry_t *cur, ws_sec_prot_cfg_t *new_cfg, uint8_t flags); uint32_t ws_cfg_neighbour_temporary_lifetime_get(void); void ws_cfg_neighbour_temporary_lifetime_set(uint32_t lifetime); diff --git a/source/6LoWPAN/ws/ws_common.c b/source/6LoWPAN/ws/ws_common.c index 42a9ceb764..e6274c2e4f 100644 --- a/source/6LoWPAN/ws/ws_common.c +++ b/source/6LoWPAN/ws/ws_common.c @@ -20,21 +20,28 @@ #include "ns_types.h" #include "ns_trace.h" #include "randLIB.h" +#include "common_functions.h" #include #include #include "Common_Protocols/icmpv6.h" #include "mac_common_defines.h" #include "net_interface.h" +#include "eventOS_event.h" #include "6LoWPAN/MAC/mpx_api.h" #include "6LoWPAN/ws/ws_config.h" #include "6LoWPAN/ws/ws_common_defines.h" #include "6LoWPAN/ws/ws_llc.h" #include "6LoWPAN/ws/ws_common.h" #include "6LoWPAN/ws/ws_bootstrap.h" +#include "6LoWPAN/ws/ws_bootstrap_6lbr.h" +#include "6LoWPAN/ws/ws_bootstrap_ffn.h" +#include "6LoWPAN/ws/ws_bootstrap_lfn.h" #include "6LoWPAN/ws/ws_bbr_api_internal.h" #include "6LoWPAN/ws/ws_pae_controller.h" #include "6LoWPAN/ws/ws_cfg_settings.h" #include "6LoWPAN/ws/ws_stats.h" +#include "6LoWPAN/ws/ws_ie_lib.h" +#include "6LoWPAN/ws/ws_phy.h" #include "Service_Libs/etx/etx.h" #include "Service_Libs/mac_neighbor_table/mac_neighbor_table.h" #include "Service_Libs/blacklist/blacklist.h" @@ -58,13 +65,13 @@ static int8_t ws_disable_channels_in_range(uint32_t *channel_mask, uint16_t numb { for (uint16_t i = 0; i < number_of_channels; i++) { if (i >= range_start && i <= range_stop) { - channel_mask[0 + (i / 32)] &= ~(1 << (i % 32)); + channel_mask[i / 32] &= ~(1U << (i % 32)); } } return 0; } -int8_t ws_generate_channel_list(uint32_t *channel_mask, uint16_t number_of_channels, uint8_t regulatory_domain, uint8_t operating_class, uint8_t channel_plan_id) +int8_t ws_common_generate_channel_list(uint32_t *channel_mask, uint16_t number_of_channels, uint8_t regulatory_domain, uint8_t operating_class, uint8_t channel_plan_id) { // Clear channel mask for (uint8_t i = 0; i < 8; i++) { @@ -72,7 +79,7 @@ int8_t ws_generate_channel_list(uint32_t *channel_mask, uint16_t number_of_chann } // Enable all channels for (uint16_t i = 0; i < number_of_channels; i++) { - channel_mask[0 + (i / 32)] |= (1 << (i % 32)); + channel_mask[i / 32] |= 1U << (i % 32); } // Disable unsupported channels per regional frequency bands if (regulatory_domain == REG_DOMAIN_BZ) { @@ -93,121 +100,38 @@ int8_t ws_generate_channel_list(uint32_t *channel_mask, uint16_t number_of_chann ws_disable_channels_in_range(channel_mask, number_of_channels, 3, 10); } } + } else if (regulatory_domain == REG_DOMAIN_EU) { + if (channel_plan_id == 32) { + ws_disable_channels_in_range(channel_mask, number_of_channels, 55, 56); + ws_disable_channels_in_range(channel_mask, number_of_channels, 61, 63); + ws_disable_channels_in_range(channel_mask, number_of_channels, 65, 66); + } else if (channel_plan_id == 33) { + ws_disable_channels_in_range(channel_mask, number_of_channels, 27, 28); + ws_disable_channels_in_range(channel_mask, number_of_channels, 30, 33); + } else if (channel_plan_id == 36) { + ws_disable_channels_in_range(channel_mask, number_of_channels, 55, 56); + ws_disable_channels_in_range(channel_mask, number_of_channels, 61, 63); + ws_disable_channels_in_range(channel_mask, number_of_channels, 65, 66); + } else if (channel_plan_id == 37) { + ws_disable_channels_in_range(channel_mask, number_of_channels, 27, 28); + ws_disable_channels_in_range(channel_mask, number_of_channels, 30, 33); + } } return 0; } -uint16_t ws_active_channel_count(uint32_t *channel_mask, uint16_t number_of_channels) +uint16_t ws_common_active_channel_count(uint32_t *channel_mask, uint16_t number_of_channels) { uint16_t active_channels = 0; // Set channel maks outside excluded channels for (uint16_t i = 0; i < number_of_channels; i++) { - if (channel_mask[0 + (i / 32)] & (1 << (i % 32))) { + if (channel_mask[i / 32] & (1U << (i % 32))) { active_channels++; } } return active_channels; } -uint32_t ws_decode_channel_spacing(uint8_t channel_spacing) -{ - if (CHANNEL_SPACING_100 == channel_spacing) { - return 100000; - } else if (CHANNEL_SPACING_200 == channel_spacing) { - return 200000; - } else if (CHANNEL_SPACING_250 == channel_spacing) { - return 250000; - } else if (CHANNEL_SPACING_400 == channel_spacing) { - return 400000; - } else if (CHANNEL_SPACING_600 == channel_spacing) { - return 600000; - } else if (CHANNEL_SPACING_800 == channel_spacing) { - return 800000; - } else if (CHANNEL_SPACING_1200 == channel_spacing) { - return 1200000; - } - return 0; -} - -uint32_t ws_get_datarate_using_operating_mode(uint8_t operating_mode) -{ - if ((OPERATING_MODE_1a == operating_mode) || (OPERATING_MODE_1b == operating_mode)) { - return 50000; - } else if ((OPERATING_MODE_2a == operating_mode) || (OPERATING_MODE_2b == operating_mode)) { - return 100000; - } else if (OPERATING_MODE_3 == operating_mode) { - return 150000; - } else if ((OPERATING_MODE_4a == operating_mode) || (OPERATING_MODE_4b == operating_mode)) { - return 200000; - } else if (OPERATING_MODE_5 == operating_mode) { - return 300000; - } - return 0; -} - -uint32_t ws_get_datarate_using_phy_mode_id(uint8_t phy_mode_id) -{ - if (84 == phy_mode_id) { - return 150000; - } else if (85 == phy_mode_id) { - return 200000; - } else if ((68 == phy_mode_id) || (86 == phy_mode_id)) { - return 300000; - } else if ((34 == phy_mode_id) || (51 == phy_mode_id) || (69 == phy_mode_id)) { - return 400000; - } else if ((52 == phy_mode_id) || (70 == phy_mode_id)) { - return 600000; - } else if ((35 == phy_mode_id) || (53 == phy_mode_id)) { - return 800000; - } else if ((36 == phy_mode_id) || (54 == phy_mode_id)) { - return 1200000; - } else if (37 == phy_mode_id) { - return 1600000; - } else if (38 == phy_mode_id) { - return 2400000; - } - return 0; -} - -uint8_t ws_get_ofdm_option_using_phy_mode_id(uint8_t phy_mode_id) -{ - if ((phy_mode_id >= 34) && (phy_mode_id <= 38)) { - return OFDM_OPTION_1; - } else if ((phy_mode_id >= 51) && (phy_mode_id <= 54)) { - return OFDM_OPTION_2; - } else if ((phy_mode_id >= 68) && (phy_mode_id <= 70)) { - return OFDM_OPTION_3; - } else if ((phy_mode_id >= 84) && (phy_mode_id <= 86)) { - return OFDM_OPTION_4; - } - return 0; -} - -uint8_t ws_get_ofdm_mcs_using_phy_mode_id(uint8_t phy_mode_id) -{ - if (34 == phy_mode_id) { - return OFDM_MCS_2; - } else if ((35 == phy_mode_id) || (51 == phy_mode_id)) { - return OFDM_MCS_3; - } else if ((36 == phy_mode_id) || (52 == phy_mode_id) || (68 == phy_mode_id) || (84 == phy_mode_id)) { - return OFDM_MCS_4; - } else if ((37 == phy_mode_id) || (53 == phy_mode_id) || (69 == phy_mode_id) || (85 == phy_mode_id)) { - return OFDM_MCS_5; - } else if ((38 == phy_mode_id) || (54 == phy_mode_id) || (70 == phy_mode_id) || (86 == phy_mode_id)) { - return OFDM_MCS_6; - } - return 0; -} - -phy_modulation_index_e ws_get_modulation_index_using_operating_mode(uint8_t operating_mode) -{ - if ((OPERATING_MODE_1b == operating_mode) || (OPERATING_MODE_2b == operating_mode) || (OPERATING_MODE_4b == operating_mode)) { - return MODULATION_INDEX_1_0; - } else { - return MODULATION_INDEX_0_5; - } -} - int8_t ws_common_regulatory_domain_config(protocol_interface_info_entry_t *cur, ws_hopping_schedule_t *hopping_schdule) { (void)cur; @@ -229,23 +153,18 @@ int8_t ws_common_regulatory_domain_config(protocol_interface_info_entry_t *cur, if (phy_type >= 2 && phy_mode > 6) { return -1; } - // Skip if PHY mode is for FSK modulation - if (!phy_mode_id || ((phy_mode_id > 8) && (phy_mode_id < 17)) || phy_mode_id > 24) { + + if (M_OFDM == ws_phy_get_modulation_using_phy_mode_id(phy_mode_id)) { // Validate OFDM configurations - if (((phy_mode_id >= 34) && (phy_mode_id <= 38)) || - ((phy_mode_id >= 51) && (phy_mode_id <= 54)) || - ((phy_mode_id >= 68) && (phy_mode_id <= 70)) || - ((phy_mode_id >= 84) && (phy_mode_id <= 86))) { - if (ws_get_datarate_using_phy_mode_id(phy_mode_id) == 0 || - ws_get_ofdm_option_using_phy_mode_id(phy_mode_id) == 0 || - ws_get_ofdm_mcs_using_phy_mode_id(phy_mode_id) == 0) { - //Unsupported PHY mode - return -1; - } - } else { - // Invalid PHY mode ID + if (!ws_phy_get_datarate_using_phy_mode_id(phy_mode_id) || + !ws_phy_get_ofdm_option_using_phy_mode_id(phy_mode_id) || + !ws_phy_get_ofdm_mcs_using_phy_mode_id(phy_mode_id)) { + //Unsupported PHY mode return -1; } + } else if (M_UNDEFINED == ws_phy_get_modulation_using_phy_mode_id(phy_mode_id)) { + // Invalid PHY mode ID + return -1; } } hopping_schdule->channel_plan = 0; @@ -261,20 +180,44 @@ int8_t ws_common_regulatory_domain_config(protocol_interface_info_entry_t *cur, return -1; } } else if (hopping_schdule->regulatory_domain == REG_DOMAIN_EU) { - if (hopping_schdule->operating_class == 1) { - hopping_schdule->ch0_freq = 8631; - hopping_schdule->channel_spacing = CHANNEL_SPACING_100; - } else if (hopping_schdule->operating_class == 2) { - hopping_schdule->ch0_freq = 8631; - hopping_schdule->channel_spacing = CHANNEL_SPACING_200; - } else if (hopping_schdule->operating_class == 3) { - hopping_schdule->ch0_freq = 8701; - hopping_schdule->channel_spacing = CHANNEL_SPACING_100; - } else if (hopping_schdule->operating_class == 4) { - hopping_schdule->ch0_freq = 8702; - hopping_schdule->channel_spacing = CHANNEL_SPACING_200; + if (hopping_schdule->channel_plan_id == 255) { + if (hopping_schdule->operating_class == 1) { + hopping_schdule->ch0_freq = 8631; + hopping_schdule->channel_spacing = CHANNEL_SPACING_100; + } else if (hopping_schdule->operating_class == 2) { + hopping_schdule->ch0_freq = 8631; + hopping_schdule->channel_spacing = CHANNEL_SPACING_200; + } else if (hopping_schdule->operating_class == 3) { + hopping_schdule->ch0_freq = 8701; + hopping_schdule->channel_spacing = CHANNEL_SPACING_100; + } else if (hopping_schdule->operating_class == 4) { + hopping_schdule->ch0_freq = 8702; + hopping_schdule->channel_spacing = CHANNEL_SPACING_200; + } else { + return -1; + } } else { - return -1; + if (hopping_schdule->channel_plan_id == 32) { + hopping_schdule->ch0_freq = 8631; + hopping_schdule->channel_spacing = CHANNEL_SPACING_100; + } else if (hopping_schdule->channel_plan_id == 33) { + hopping_schdule->ch0_freq = 8631; + hopping_schdule->channel_spacing = CHANNEL_SPACING_200; + } else if (hopping_schdule->channel_plan_id == 34) { + hopping_schdule->ch0_freq = 8701; + hopping_schdule->channel_spacing = CHANNEL_SPACING_100; + } else if (hopping_schdule->channel_plan_id == 35) { + hopping_schdule->ch0_freq = 8702; + hopping_schdule->channel_spacing = CHANNEL_SPACING_200; + } else if (hopping_schdule->channel_plan_id == 36) { + hopping_schdule->ch0_freq = 8631; + hopping_schdule->channel_spacing = CHANNEL_SPACING_100; + } else if (hopping_schdule->channel_plan_id == 37) { + hopping_schdule->ch0_freq = 8631; + hopping_schdule->channel_spacing = CHANNEL_SPACING_200; + } else { + return -1; + } } } else if (hopping_schdule->regulatory_domain == REG_DOMAIN_IN) { if (hopping_schdule->operating_class == 1) { @@ -385,15 +328,10 @@ uint16_t ws_common_channel_number_calc(uint8_t regulatory_domain, uint8_t operat return 16; } } else if (regulatory_domain == REG_DOMAIN_EU) { - if (operating_class == 1) { - return 69; - } else if (operating_class == 2) { - return 35; - } else if (operating_class == 3) { - return 55; - } else if (operating_class == 4) { - return 27; + if (channel_plan_id == 255) { + channel_plan_id = ws_phy_convert_operating_class_to_channel_plan_id(operating_class, regulatory_domain); } + return ws_phy_get_number_of_channels_using_channel_plan_id(channel_plan_id); } else if (regulatory_domain == REG_DOMAIN_IN) { if (operating_class == 1) { return 19; @@ -402,22 +340,9 @@ uint16_t ws_common_channel_number_calc(uint8_t regulatory_domain, uint8_t operat } } else if (regulatory_domain == REG_DOMAIN_NA) { if (channel_plan_id == 255) { - if (operating_class == 1) { - return 129; - } else if (operating_class == 2) { - return 64; - } else if (operating_class == 3) { - return 42; - } - } else { - if (channel_plan_id == 1) { - return 129; - } else if (channel_plan_id == 2) { - return 64; - } else if (channel_plan_id == 5) { - return 21; - } + channel_plan_id = ws_phy_convert_operating_class_to_channel_plan_id(operating_class, regulatory_domain); } + return ws_phy_get_number_of_channels_using_channel_plan_id(channel_plan_id); } else if (regulatory_domain == REG_DOMAIN_JP) { if (operating_class == 1) { return 38; @@ -428,22 +353,9 @@ uint16_t ws_common_channel_number_calc(uint8_t regulatory_domain, uint8_t operat } } else if (regulatory_domain == REG_DOMAIN_BZ) { if (channel_plan_id == 255) { - if (operating_class == 1) { - return 129; - } else if (operating_class == 2) { - return 64; - } else if (operating_class == 3) { - return 42; - } - } else { - if (channel_plan_id == 1) { - return 129; - } else if (channel_plan_id == 2) { - return 64; - } else if (channel_plan_id == 5) { - return 21; - } + channel_plan_id = ws_phy_convert_operating_class_to_channel_plan_id(operating_class, regulatory_domain); } + return ws_phy_get_number_of_channels_using_channel_plan_id(channel_plan_id); } else if (regulatory_domain == REG_DOMAIN_WW) { if (operating_class == 1) { // TODO we dont support this yet, but it is used as test value @@ -472,12 +384,13 @@ int8_t ws_common_allocate_and_init(protocol_interface_info_entry_t *cur) ns_list_init(&cur->ws_info->parent_list_free); ns_list_init(&cur->ws_info->parent_list_reserved); + cur->ws_info->version = test_pan_version; + cur->ws_info->network_pan_id = 0xffff; cur->ws_info->pan_information.use_parent_bs = true; cur->ws_info->pan_information.rpl_routing_method = true; cur->ws_info->pan_information.pan_version_set = false; cur->ws_info->pan_information.version = WS_FAN_VERSION_1_0; - cur->ws_info->pending_key_index_info.state = NO_PENDING_PROCESS; cur->ws_info->hopping_schdule.regulatory_domain = REG_DOMAIN_EU; @@ -490,14 +403,40 @@ int8_t ws_common_allocate_and_init(protocol_interface_info_entry_t *cur) ws_common_regulatory_domain_config(cur, &cur->ws_info->hopping_schdule); cur->ws_info->pending_key_index_info.state = NO_PENDING_PROCESS; - + // initialize for FAN 1.1 defaults + if (ws_version_1_1(cur)) { + cur->ws_info->pan_information.version = WS_FAN_VERSION_1_1; + } return 0; } +int ws_common_init(int8_t interface_id, net_6lowpan_mode_e bootstrap_mode) +{ + return ws_bootstrap_init(interface_id, bootstrap_mode); +} + +void ws_common_state_machine(protocol_interface_info_entry_t *cur) +{ + if (wisun_mode_host(cur)) { + // Configure for LFN device + ws_bootstrap_lfn_state_machine(cur); + } else if (wisun_mode_router(cur)) { + // Configure FFN device + ws_bootstrap_ffn_state_machine(cur); + } else if (wisun_mode_border_router(cur)) { + // Configure as Border router + ws_bootstrap_6lbr_state_machine(cur); + } + +} + void ws_common_seconds_timer(protocol_interface_info_entry_t *cur, uint32_t seconds) { ws_bbr_seconds_timer(cur, seconds); ws_bootstrap_seconds_timer(cur, seconds); + ws_bootstrap_6lbr_seconds_timer(cur, seconds); + ws_bootstrap_ffn_seconds_timer(cur, seconds); + ws_bootstrap_lfn_seconds_timer(cur, seconds); blacklist_ttl_update(seconds); } @@ -508,6 +447,12 @@ void ws_common_fast_timer(protocol_interface_info_entry_t *cur, uint16_t ticks) ws_llc_fast_timer(cur, ticks); } +void ws_common_create_ll_address(uint8_t *ll_address, const uint8_t *mac64) +{ + memcpy(ll_address, ADDR_LINK_LOCAL_PREFIX, 8); + memcpy(ll_address + 8, mac64, 8); + ll_address[8] ^= 2; +} void ws_common_neighbor_update(protocol_interface_info_entry_t *cur, const uint8_t *ll_address) { @@ -652,13 +597,10 @@ uint32_t ws_common_latency_estimate_get(protocol_interface_info_entry_t *cur) uint32_t ws_common_datarate_get_from_phy_mode(uint8_t phy_mode_id, uint8_t operating_mode) { - if (((phy_mode_id >= 34) && (phy_mode_id <= 38)) || - ((phy_mode_id >= 51) && (phy_mode_id <= 54)) || - ((phy_mode_id >= 68) && (phy_mode_id <= 70)) || - ((phy_mode_id >= 84) && (phy_mode_id <= 86))) { - return ws_get_datarate_using_phy_mode_id(phy_mode_id); + if (phy_mode_id == 255) { + phy_mode_id = ws_phy_convert_operating_mode_to_phy_mode_id(operating_mode); } - return ws_get_datarate_using_operating_mode(operating_mode); + return ws_phy_get_datarate_using_phy_mode_id(phy_mode_id); } uint32_t ws_common_datarate_get(protocol_interface_info_entry_t *cur) @@ -737,4 +679,16 @@ void ws_common_border_router_alive_update(protocol_interface_info_entry_t *inter interface->ws_info->pan_timeout_timer = interface->ws_info->cfg->timing.pan_timeout; } +fhss_ws_configuration_t ws_common_get_current_fhss_configuration(protocol_interface_info_entry_t *cur) +{ + fhss_ws_configuration_t fhss_configuration; + memset(&fhss_configuration, 0, sizeof(fhss_ws_configuration_t)); + 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)); + } else { + tr_error("FHSS configuration could not be read"); + } + return fhss_configuration; +} + #endif // HAVE_WS diff --git a/source/6LoWPAN/ws/ws_common.h b/source/6LoWPAN/ws/ws_common.h index 40fbd0a16d..c7fb453e14 100644 --- a/source/6LoWPAN/ws/ws_common.h +++ b/source/6LoWPAN/ws/ws_common.h @@ -37,6 +37,8 @@ struct ws_pan_information_s; struct ws_neighbor_class_s; struct ws_excluded_channel_data_s; struct ws_cfg_s; +struct ws_neighbor_class_entry; +struct mcps_data_ie_list; typedef struct parent_info_s { uint16_t pan_id; /**< PAN ID */ @@ -79,6 +81,30 @@ typedef struct { uint16_t old_bsi; } ws_bsi_block_t; +typedef struct { + uint16_t eapol_trigger_timer; + uint16_t pas_trigger_timer; + uint16_t pcs_trigger_timer; + uint16_t dis_trigger_timer; + uint16_t dis_trigger_timer_val; + uint16_t rpl_trigger_timer; + uint16_t rpl_trigger_timer_val; + uint8_t pas_trigger_count; + uint8_t pcs_trigger_count; + bool auto_trg_enabled; +} ws_test_proc_trg_t; + +typedef struct { + uint16_t lfn_version; + bool lfn_version_learned: 1; + bool active_hash_1: 1; + bool active_hash_2: 1; + bool active_hash_3: 1; + unsigned active_key_index: 2; + uint8_t lgtkhash[24]; +} ws_lfn_lgtk_t; + + typedef NS_LIST_HEAD(ws_nud_table_entry_t, link) ws_nud_table_list_t; typedef struct ws_info_s { @@ -87,6 +113,7 @@ typedef struct ws_info_s { trickle_t trickle_pan_advertisement_solicit; trickle_t trickle_pan_advertisement; trickle_params_t trickle_params_pan_discovery; + uint8_t version; // Wi-SUN version information 1 = 1.0 2 = 1.x uint8_t rpl_state; // state from rpl_event_t uint8_t pas_requests; // Amount of PAN solicits sent uint8_t device_min_sens; // Device min sensitivity set by the application @@ -114,6 +141,11 @@ typedef struct ws_info_s { ws_nud_table_entry_t nud_table_entrys[ACTIVE_NUD_PROCESS_MAX]; ws_nud_table_list_t active_nud_process; ws_nud_table_list_t free_nud_entries; + ws_test_proc_trg_t test_proc_trg; +#ifdef HAVE_WS_VERSION_1_1 + ws_lfn_lgtk_t lfngtk; + ws_phy_cap_info_t phy_cap_info; +#endif struct ws_cfg_s *cfg; /**< Wi-SUN configuration */ struct ws_pan_information_s pan_information; ws_hopping_schedule_t hopping_schdule; @@ -125,21 +157,9 @@ typedef struct ws_info_s { #ifdef HAVE_WS -int8_t ws_generate_channel_list(uint32_t *channel_mask, uint16_t number_of_channels, uint8_t regulatory_domain, uint8_t operating_class, uint8_t channel_plan_id); +int8_t ws_common_generate_channel_list(uint32_t *channel_mask, uint16_t number_of_channels, uint8_t regulatory_domain, uint8_t operating_class, uint8_t channel_plan_id); -uint16_t ws_active_channel_count(uint32_t *channel_mask, uint16_t number_of_channels); - -uint32_t ws_decode_channel_spacing(uint8_t channel_spacing); - -uint32_t ws_get_datarate_using_operating_mode(uint8_t operating_mode); - -uint32_t ws_get_datarate_using_phy_mode_id(uint8_t phy_mode_id); - -uint8_t ws_get_ofdm_option_using_phy_mode_id(uint8_t phy_mode_id); - -uint8_t ws_get_ofdm_mcs_using_phy_mode_id(uint8_t phy_mode_id); - -phy_modulation_index_e ws_get_modulation_index_using_operating_mode(uint8_t operating_mode); +uint16_t ws_common_active_channel_count(uint32_t *channel_mask, uint16_t number_of_channels); int8_t ws_common_regulatory_domain_config(protocol_interface_info_entry_t *cur, ws_hopping_schedule_t *hopping_schdule); @@ -151,6 +171,8 @@ void ws_common_seconds_timer(protocol_interface_info_entry_t *cur, uint32_t seco void ws_common_fast_timer(protocol_interface_info_entry_t *cur, uint16_t ticks); +void ws_common_create_ll_address(uint8_t *ll_address, const uint8_t *mac64); + void ws_common_neighbor_update(protocol_interface_info_entry_t *cur, const uint8_t *ll_address); void ws_common_black_list_neighbour(const uint8_t *ll_address, uint8_t nd_status); @@ -184,11 +206,35 @@ void ws_common_primary_parent_update(protocol_interface_info_entry_t *interface, void ws_common_secondary_parent_update(protocol_interface_info_entry_t *interface); uint8_t ws_common_temporary_entry_size(uint8_t mac_table_size); + void ws_common_border_router_alive_update(protocol_interface_info_entry_t *interface); +int ws_common_init(int8_t interface_id, net_6lowpan_mode_e bootstrap_mode); + +void ws_common_state_machine(protocol_interface_info_entry_t *cur); + +fhss_ws_configuration_t ws_common_get_current_fhss_configuration(protocol_interface_info_entry_t *cur); + #define ws_info(cur) ((cur)->ws_info) +#ifdef HAVE_WS_VERSION_1_1 +#define ws_version_1_0(cur) (((cur)->ws_info) && ((cur)->ws_info)->version == 1) +#define ws_version_1_1(cur) (((cur)->ws_info) && ((cur)->ws_info)->version > 1) +#define ws_lfn_version_learned(cur) ((cur)->ws_info->lfngtk.lfn_version_learned == true) +#define ws_neighbour_cap_pointer(neighbour) (&neighbour->pcap_info) +#else +#define ws_version_1_1(cur) (false) +#define ws_version_1_0(cur) ((cur)->ws_info) +#define ws_lfn_version_learned(cur) (false) +#define ws_neighbour_cap_pointer(neighbour) NULL +#endif +#define ws_test_proc_auto_trg(cur) ((cur)->ws_info->test_proc_trg.auto_trg_enabled == true) #else #define ws_info(cur) ((ws_info_t *) NULL) +#define ws_version_1_1(cur) (false) +#define ws_version_1_0(cur) (false) +#define ws_lfn_version_learned(cur) (false) +#define ws_neighbour_cap_pointer(neighbour) NULL +#define ws_test_proc_auto_trg(cur) (false) #define ws_common_seconds_timer(cur, seconds) #define ws_common_neighbor_update(cur, ll_address) ((void) 0) #define ws_common_black_list_neighbour(ll_address, nd_status) ((void) 0) @@ -207,6 +253,8 @@ void ws_common_border_router_alive_update(protocol_interface_info_entry_t *inter #define ws_common_primary_parent_update(interface, neighbor) #define ws_common_secondary_parent_update(interface) #define ws_common_border_router_alive_update(interface) ((void) 0) +#define ws_common_init(interface_id, bootstrap_mode) 0 +#define ws_common_state_machine(cur) #endif //HAVE_WS diff --git a/source/6LoWPAN/ws/ws_common_defines.h b/source/6LoWPAN/ws/ws_common_defines.h index 8ea6ab3f06..fa73a96ef6 100644 --- a/source/6LoWPAN/ws/ws_common_defines.h +++ b/source/6LoWPAN/ws/ws_common_defines.h @@ -28,19 +28,40 @@ #define WH_IE_MHDS_TYPE 5 /**< MHDS information for mesh routing */ #define WH_IE_VH_TYPE 6 /**< Vendor header information */ #define WH_IE_EA_TYPE 9 /**< Eapol Auhtenticator EUI-64 header information */ +/* Wi-SUN FAN dfinition 1.1 */ +#define WH_IE_LUTT_TYPE 10 /**< LFN Unicast Timing and Frame Type information */ +#define WH_IE_LBT_TYPE 11 /**< LFN Broadcast Timing information */ +#define WH_IE_NR_TYPE 12 /**< Node Role IE information */ +#define WH_IE_LUS_TYPE 13 /**< LFN Unicast Schedule information */ +#define WH_IE_FLUS_TYPE 14 /**< FFN for LFN unicast Schedule information */ +#define WH_IE_LBS_TYPE 15 /**< LFN Broadcast Schedule information */ +#define WH_IE_LND_TYPE 16 /**< LFN Network Discovery information */ +#define WH_IE_LTO_TYPE 17 /**< LFN Timing information */ +#define WH_IE_PANID_TYPE 18 /**< PAN Identifier information */ + #define WS_WP_NESTED_IE 4 /**< WS nested Payload IE element'selement could include mltiple sub payload IE */ #define WS_WP_SUB_IE_ELEMENT_HEADER_LENGTH 2 /* Payload IE sub elements in side WS_WP_NESTED_IE */ -#define WP_PAYLOAD_IE_US_TYPE 1 /**< Unicast Schedule information */ -#define WP_PAYLOAD_IE_BS_TYPE 2 /**< Broadcast Schedule information */ -#define WP_PAYLOAD_IE_VP_TYPE 3 /**< Vendor Payload information */ +/* Long form subID's */ +#define WP_PAYLOAD_IE_US_TYPE 1 /**< Unicast Schedule information */ +#define WP_PAYLOAD_IE_BS_TYPE 2 /**< Broadcast Schedule information */ +#define WP_PAYLOAD_IE_VP_TYPE 3 /**< Vendor Payload information */ +/* Wi-SUN FAN definition 1.1 */ +#define WP_PAYLOAD_IE_LFN_CHANNEL_PLAN_TYPE 4 /**< LFN Channel Plan information*/ + +/* Short form subID's */ #define WP_PAYLOAD_IE_PAN_TYPE 4 /**< PAN Information */ #define WP_PAYLOAD_IE_NETNAME_TYPE 5 /**< Network Name information */ #define WP_PAYLOAD_IE_PAN_VER_TYPE 6 /**< Pan configuration version */ #define WP_PAYLOAD_IE_GTKHASH_TYPE 7 /**< GTK Hash information */ +/* Wi-SUN FAN definition 1.1 */ +#define WP_PAYLOAD_IE_PCAP_TYPE 8 /**< PHY Capability information */ +#define WP_PAYLOAD_IE_LFNVER_TYPE 9 /**< LFN Version information */ +#define WP_PAYLOAD_IE_LGTKHASH_TYPE 10 /**< LFN GTK Hash Information */ + /* WS frame types to WH_IE_UTT_TYPE */ #define WS_FT_PAN_ADVERT 0 /**< PAN Advert */ @@ -50,14 +71,25 @@ #define WS_FT_DATA 4 /**< data type inside MPX */ #define WS_FT_ACK 5 /**< Enhanced ACK */ #define WS_FT_EAPOL 6 /**< EAPOL message inside MPX */ +/* Wi-SUN FAN 1.1 */ +#define WS_FT_LPA 9 /**< LFN PAN Advert */ +#define WS_FT_LPAS 10 /**< LFN PAN Advert Solicit */ +#define WS_FT_LPC 11 /**< LFN PAN Config */ +#define WS_FT_LPCS 12 /**< LFN PAN Config Solicit */ + /* WS exluded channel Control */ #define WS_EXC_CHAN_CTRL_NONE 0 /**< No excluded channels */ #define WS_EXC_CHAN_CTRL_RANGE 1 /**< Excluded channels are in 1 or multiple channel range */ -#define WS_EXC_CHAN_CTRL_BITMASK 2 /**< Excluded channels are marked to bitmask which length based on configured channels */ +#define WS_EXC_CHAN_CTRL_BITMASK 2 /**< Excluded channels are marked to bitmask which length based on configured channels */ #define WS_EXCLUDED_MAX_RANGE_TO_SEND 3 + +#define WS_NR_ROLE_BR 0 +#define WS_NR_ROLE_ROUTER 1 +#define WS_NR_ROLE_LFN 2 + /** * @brief ws_pan_information_t PAN information */ @@ -68,6 +100,7 @@ typedef struct ws_pan_information_s { bool use_parent_bs: 1; /**< 1 for force to follow parent broadcast schedule. 0 node may define own schedule. */ bool rpl_routing_method: 1; /**< 1 when RPL routing is selected and 0 when L2 routing. */ bool pan_version_set: 1; /**< 1 PAN version is set. */ + bool lfn_window_style: 1; /**< 1 FFN management trasmission. */ unsigned version: 3; /**< Pan version support. */ } ws_pan_information_t; @@ -125,6 +158,101 @@ typedef struct ws_utt_ie { uint_fast24_t ufsi; } ws_utt_ie_t; +/** + * @brief ws_utt_ie_t WS LUTT-IE + */ +typedef struct ws_lutt_ie { + uint8_t message_type; + uint16_t slot_number; + uint_fast24_t interval_offset; +} ws_lutt_ie_t; + +/** + * @brief ws_lbt_ie_t WS LBT-IE + */ +typedef struct ws_lbt_ie { + uint16_t slot_number; + uint_fast24_t interval_offset; +} ws_lbt_ie_t; + + +/** + * @brief ws_nr_ie_t WS NR-IE + */ +typedef struct ws_nr_ie { + unsigned node_role: 3; + uint8_t clock_drift; + uint8_t timing_accurancy; + uint_fast24_t listen_interval_min; + uint_fast24_t listen_interval_max; +} ws_nr_ie_t; + + +/** + * @brief ws_lus_ie_t WS LUS-IE + */ +typedef struct ws_lus_ie { + uint8_t channel_plan_tag; + uint_fast24_t listen_interval; +} ws_lus_ie_t; + +/** + * @brief ws_lus_ie_t WS FLUS-IE + */ +typedef struct ws_flus_ie { + uint8_t channel_plan_tag; + uint8_t dwell_interval; +} ws_flus_ie_t; + +/** + * @brief ws_lnd_ie_t WS LND-IE + */ +typedef struct ws_lnd_ie { + uint8_t response_threshold; + uint8_t discovery_slot_time; + uint8_t discovery_slots; + uint16_t discovery_first_slot; + uint_fast24_t response_delay; +} ws_lnd_ie_t; + +/** + * @brief ws_lto_ie_t WS LTO-IE + */ +typedef struct ws_lto_ie { + uint_fast24_t offset; + uint_fast24_t adjusted_listening_interval; +} ws_lto_ie_t; + +/** + * @brief ws_lbs_ie_t WS LBS-IE + */ +typedef struct ws_lbs_ie { + uint8_t channel_plan_tag; + uint16_t broadcast_secheduler_id; + uint_fast24_t broadcast_interval; +} ws_lbs_ie_t; + + +/** + * @brief ws_panid_ie_t WS PANID-IE + */ +typedef struct ws_panid_ie { + uint16_t panid; +} ws_panid_ie_t; + +/** + * @brief ws_pcap_ie_t WS PCAB-IE + */ +typedef struct ws_pcap_ie { + unsigned phy_type: 3; + uint16_t operating_mode; +} ws_pcap_ie_t; + +typedef struct ws_phy_cap_info { + unsigned length_of_list: 3; + ws_pcap_ie_t pcap[7]; +} ws_phy_cap_info_t; + /** * @brief ws_bt_ie_t WS BT-IE read */ @@ -141,6 +269,26 @@ typedef struct ws_fc_ie { uint8_t rx_flow_ctrl; } ws_fc_ie_t; +/** + * @brief ws_lfnver_ie_t WS LFNVER-IE element + */ +typedef struct ws_lfnver_ie { + uint16_t lfn_version; +} ws_lfnver_ie_t; + +/** + * @brief ws_lgtkhash_ie_t WS LGTKHASH-IE element + */ +typedef struct ws_lgtkhash_ie { + bool lgtk0: 1; /**< 1= LGTK0 in line 0 = elided */ + bool lgtk1: 1; /**< 1= LGTK1 in line 0 = elided */ + bool lgtk2: 1; /**< 1= LGTK2 in line 0 = elided */ + unsigned active_lgtk_index: 2; /**< Indicate Active LGTK index 0-2 */ + uint8_t *lgtk0_hash; /**< LGTK0 64-bit Hash if lgtk0=1*/ + uint8_t *lgtk1_hash; /**< LGTK1 64-bit Hash if lgtk1=1*/ + uint8_t *lgtk2_hash; /**< LGTK2 64-bit Hash if lgtk2=1*/ +} ws_lgtkhash_ie_t; + /** * @brief ws_channel_plan_zero_t WS channel plan 0 define domain and class */ @@ -158,6 +306,14 @@ typedef struct ws_channel_plan_one { uint16_t number_of_channel; } ws_channel_plan_one_t; +/** + * @brief ws_channel_plan_two_t WS channel plan 2 define regulator domain and chanel plan 1 + */ +typedef struct ws_channel_plan_two { + uint8_t regulator_domain; + uint8_t channel_plan_id; +} ws_channel_plan_two_t; + /** * @brief ws_channel_function_zero_t WS function 0 fixed channel */ @@ -189,6 +345,43 @@ typedef struct ws_excluded_channel_mask { uint8_t mask_len_inline; } ws_excluded_channel_mask_t; + +typedef struct ws_excluded_channel_range_out { + unsigned excluded_range_length: 3; + ws_excluded_channel_range_data_t *exluded_range; +} ws_excluded_channel_range_out_t; + + +typedef struct ws_excluded_channel_mask_out { + uint16_t excluded_channel_count; + uint8_t channel_mask_bytes_inline; + uint32_t *channel_mask; +} ws_excluded_channel_mask_out_t; + +/** + * @brief ws_generic_channel_info_t Generic Channel Info + */ +typedef struct ws_generic_channel_info { + unsigned channel_plan: 3; + unsigned channel_function: 3; + unsigned excluded_channel_ctrl: 2; + union { + ws_channel_plan_zero_t zero; + ws_channel_plan_one_t one; + ws_channel_plan_two_t two; + } plan; + union { + ws_channel_function_zero_t zero; + ws_channel_function_three_t three; + } function; + union { + ws_excluded_channel_range_out_t range; + ws_excluded_channel_mask_out_t mask; + ws_excluded_channel_range_t range_in; + ws_excluded_channel_mask_t mask_in; + } excluded_channels; +} ws_generic_channel_info_t; + /** * @brief ws_us_ie_t WS US-IE read */ @@ -202,6 +395,7 @@ typedef struct ws_us_ie { union { ws_channel_plan_zero_t zero; ws_channel_plan_one_t one; + ws_channel_plan_two_t two; } plan; union { ws_channel_function_zero_t zero; @@ -228,6 +422,7 @@ typedef struct ws_bs_ie { union { ws_channel_plan_zero_t zero; ws_channel_plan_one_t one; + ws_channel_plan_two_t two; } plan; union { ws_channel_function_zero_t zero; @@ -247,6 +442,7 @@ typedef struct ws_bs_ie { #define WS_MPX_MAX_MTU 1576 #define WS_FAN_VERSION_1_0 1 +#define WS_FAN_VERSION_1_1 2 #define WS_NEIGHBOR_LINK_TIMEOUT 2200 @@ -381,9 +577,9 @@ typedef struct ws_bs_ie { /* Default FHSS timing information * */ -#define WS_FHSS_UC_DWELL_INTERVAL 255; -#define WS_FHSS_BC_INTERVAL 1020; -#define WS_FHSS_BC_DWELL_INTERVAL 255; +#define WS_FHSS_UC_DWELL_INTERVAL 255 +#define WS_FHSS_BC_INTERVAL 1020 +#define WS_FHSS_BC_DWELL_INTERVAL 255 /* * EAPOL relay and PAE authenticator socket settings diff --git a/source/6LoWPAN/ws/ws_config.h b/source/6LoWPAN/ws/ws_config.h index 49723f009b..9af23615d8 100644 --- a/source/6LoWPAN/ws/ws_config.h +++ b/source/6LoWPAN/ws/ws_config.h @@ -97,7 +97,7 @@ #define PAN_VERSION_SMALL_NETWORK_TIMEOUT 30*60 -#define PAN_VERSION_MEDIUM_NETWORK_TIMEOUT 60*60 +#define PAN_VERSION_MEDIUM_NETWORK_TIMEOUT 30*60 #define PAN_VERSION_LARGE_NETWORK_TIMEOUT 90*60 diff --git a/source/6LoWPAN/ws/ws_empty_functions.c b/source/6LoWPAN/ws/ws_empty_functions.c index f7e14fdb79..f070e20ac5 100644 --- a/source/6LoWPAN/ws/ws_empty_functions.c +++ b/source/6LoWPAN/ws/ws_empty_functions.c @@ -26,6 +26,7 @@ #include "ws_management_api.h" #include "ns_time_api.h" +#include "net_ws_test_ext.h" #ifndef HAVE_WS int ws_management_node_init( @@ -362,6 +363,12 @@ int ws_management_timing_parameters_validate( } /* ### test api ### */ +int ws_test_version_set(int8_t interface_id, uint8_t version) +{ + (void) interface_id; + (void) version; + return -1; +} int ws_test_pan_size_set(int8_t interface_id, uint16_t pan_size) { (void) interface_id; @@ -488,5 +495,22 @@ int8_t ws_test_drop_edfe_data_frames(int8_t interface_id, uint8_t number_of_dro return -1; } +int ws_test_procedure_trigger(int8_t interface_id, ws_test_proc_t procedure, void *parameters) +{ + (void) interface_id; + (void) procedure; + (void) parameters; + return -1; +} + +int ws_management_phy_capability_set( + int8_t interface_id, + ws_management_pcap_info_t *pcap_list) +{ + (void)interface_id; + (void)pcap_list; + return -1; +} + #endif // no HAVE_WS diff --git a/source/6LoWPAN/ws/ws_ie_lib.c b/source/6LoWPAN/ws/ws_ie_lib.c index 5edd436dbc..820ff86ed7 100644 --- a/source/6LoWPAN/ws/ws_ie_lib.c +++ b/source/6LoWPAN/ws/ws_ie_lib.c @@ -25,6 +25,7 @@ #include "6LoWPAN/MAC/mac_ie_lib.h" #include "6LoWPAN/ws/ws_common_defines.h" #include "6LoWPAN/ws/ws_ie_lib.h" +#include "ws_management_api.h" static uint8_t *ws_wh_header_base_write(uint8_t *ptr, uint16_t length, uint8_t type) { @@ -42,6 +43,9 @@ static uint16_t ws_channel_plan_length(uint8_t channel_plan) case 1: //CHo, Channel spasing and number of channel's inline return 6; + case 2: + //Regulator domain and channel plan ID inline + return 2; default: return 0; @@ -66,29 +70,120 @@ static uint16_t ws_channel_function_length(uint8_t channel_function, uint16_t ho } } -uint16_t ws_wp_nested_hopping_schedule_length(struct ws_hopping_schedule_s *hopping_schedule, bool unicast_schedule) +static uint16_t ws_excluded_channel_length(ws_generic_channel_info_t *generic_channel_info) { uint16_t length; - uint8_t channel_function; - if (unicast_schedule) { - length = 4; - channel_function = hopping_schedule->uc_channel_function; + if (generic_channel_info->excluded_channel_ctrl == WS_EXC_CHAN_CTRL_RANGE) { + length = (generic_channel_info->excluded_channels.range.excluded_range_length * 4) + 1; + } else if (generic_channel_info->excluded_channel_ctrl == WS_EXC_CHAN_CTRL_BITMASK) { + length = generic_channel_info->excluded_channels.mask.channel_mask_bytes_inline; } else { - length = 10; - channel_function = hopping_schedule->bc_channel_function; + length = 0; } + return length; +} - length += ws_channel_plan_length(hopping_schedule->channel_plan); - - length += ws_channel_function_length(channel_function, 1); - - if (unicast_schedule && hopping_schedule->excluded_channels.excuded_channel_ctrl) { - if (hopping_schedule->excluded_channels.excuded_channel_ctrl == WS_EXC_CHAN_CTRL_RANGE) { - length += (hopping_schedule->excluded_channels.excluded_range_length * 4) + 1; - } else { - length += hopping_schedule->excluded_channels.channel_mask_bytes_inline; +static void ws_generic_channel_info_init(struct ws_hopping_schedule_s *hopping_schedule, ws_generic_channel_info_t *generic_channel_info, bool unicast_schedule) +{ + generic_channel_info->channel_plan = hopping_schedule->channel_plan; + if (unicast_schedule) { + generic_channel_info->channel_function = hopping_schedule->uc_channel_function; + generic_channel_info->excluded_channel_ctrl = hopping_schedule->excluded_channels.excuded_channel_ctrl; + if (generic_channel_info->excluded_channel_ctrl == WS_EXC_CHAN_CTRL_RANGE) { + generic_channel_info->excluded_channels.range.excluded_range_length = hopping_schedule->excluded_channels.excluded_range_length; + generic_channel_info->excluded_channels.range.exluded_range = hopping_schedule->excluded_channels.exluded_range; + } else if (generic_channel_info->excluded_channel_ctrl == WS_EXC_CHAN_CTRL_BITMASK) { + generic_channel_info->excluded_channels.mask.channel_mask_bytes_inline = hopping_schedule->excluded_channels.channel_mask_bytes_inline; + generic_channel_info->excluded_channels.mask.excluded_channel_count = hopping_schedule->excluded_channels.excluded_channel_count; + generic_channel_info->excluded_channels.mask.channel_mask = hopping_schedule->excluded_channels.channel_mask; } + } else { + generic_channel_info->channel_function = hopping_schedule->bc_channel_function; + generic_channel_info->excluded_channel_ctrl = WS_EXC_CHAN_CTRL_NONE; } +} + +static void ws_wp_channel_plan_set(ws_generic_channel_info_t *generic_channel_info, struct ws_hopping_schedule_s *hopping_schedule) +{ + switch (generic_channel_info->channel_plan) { + case 0: + //Regulator domain and operationg class inline + generic_channel_info->plan.zero.regulator_domain = hopping_schedule->regulatory_domain; + generic_channel_info->plan.zero.operation_class = hopping_schedule->operating_class; + break; + case 1: + //CHo, Channel spasing and number of channel's inline + generic_channel_info->plan.one.ch0 = hopping_schedule->ch0_freq; + generic_channel_info->plan.one.channel_spacing = hopping_schedule->channel_spacing; + generic_channel_info->plan.one.number_of_channel = hopping_schedule->number_of_channels; + break; + case 2: + generic_channel_info->plan.two.regulator_domain = hopping_schedule->regulatory_domain; + generic_channel_info->plan.two.channel_plan_id = hopping_schedule->channel_plan_id; + break; + default: + break; + } +} + +static void ws_wp_channel_function_set(ws_generic_channel_info_t *generic_channel_info, struct ws_hopping_schedule_s *hopping_schedule, bool unicast_schedule) +{ + switch (generic_channel_info->channel_function) { + case 0: + //Fixed channel inline + if (unicast_schedule) { + generic_channel_info->function.zero.fixed_channel = hopping_schedule->uc_fixed_channel; + } else { + generic_channel_info->function.zero.fixed_channel = hopping_schedule->bc_fixed_channel; + } + break; + case 1: + case 2: + //No Inline + break; + case 3: + //TODO add list to possible to set + //Force 1 channel 0 + generic_channel_info->function.three.channel_hop_count = 1; + generic_channel_info->function.three.channel_list = NULL; + break; + default: + break; + + } +} + +static uint16_t ws_wp_generic_shedule_length_get(ws_generic_channel_info_t *generic_channel_info) +{ + uint16_t length = 1; + + length += ws_channel_plan_length(generic_channel_info->channel_plan); + uint16_t number_of_channels = 1; + if (generic_channel_info->channel_plan == 3) { + number_of_channels = generic_channel_info->function.three.channel_hop_count; + } else { + number_of_channels = 1; + } + length += ws_channel_function_length(generic_channel_info->channel_function, number_of_channels); + + length += ws_excluded_channel_length(generic_channel_info); + + return length; +} + +uint16_t ws_wp_nested_hopping_schedule_length(struct ws_hopping_schedule_s *hopping_schedule, bool unicast_schedule) +{ + ws_generic_channel_info_t generic_channel_info; + + ws_generic_channel_info_init(hopping_schedule, &generic_channel_info, unicast_schedule); + ws_wp_channel_function_set(&generic_channel_info, hopping_schedule, unicast_schedule); + uint16_t length; + if (unicast_schedule) { + length = 3; + } else { + length = 9; + } + length += ws_wp_generic_shedule_length_get(&generic_channel_info); return length; } @@ -143,15 +238,233 @@ uint8_t *ws_wh_vh_write(uint8_t *ptr, uint8_t *vendor_header, uint8_t vendor_hea return ptr; } +uint8_t *ws_wh_lutt_write(uint8_t *ptr, uint8_t message_type) +{ + ptr = ws_wh_header_base_write(ptr, ws_wh_lutt_length(), WH_IE_LUTT_TYPE); + *ptr++ = message_type; + //Set 0 for next 5 bytes which will be initializwed by FHSS + memset(ptr, 0, 5); /* Unicast Slot Number 2 bytes, UFSI 3 bytes */ + ptr += 5; + return ptr; +} + +uint8_t *ws_wh_lus_write(uint8_t *ptr, struct ws_lus_ie *lus_ptr) +{ + ptr = ws_wh_header_base_write(ptr, ws_wh_lus_length(), WH_IE_LUS_TYPE); + ptr = common_write_24_bit_inverse(lus_ptr->listen_interval, ptr); + *ptr++ = lus_ptr->channel_plan_tag; + return ptr; +} + +uint8_t *ws_wh_flus_write(uint8_t *ptr, struct ws_flus_ie *flus_ptr) +{ + ptr = ws_wh_header_base_write(ptr, ws_wh_flus_length(), WH_IE_FLUS_TYPE); + *ptr++ = flus_ptr->dwell_interval; + *ptr++ = flus_ptr->channel_plan_tag; + return ptr; +} + +uint8_t *ws_wh_lbt_write(uint8_t *ptr) +{ + ptr = ws_wh_header_base_write(ptr, ws_wh_lbt_length(), WH_IE_LBT_TYPE); + //Set 0 for next 5 bytes which will be initializwed by FHSS + memset(ptr, 0, ws_wh_lbt_length()); /* LFN Broadcast Slot Number 2 bytes, LFN Broadcast Interval Offset 3 bytes */ + ptr += ws_wh_lbt_length(); + return ptr; + +} + +uint8_t *ws_wh_lbs_write(uint8_t *ptr, struct ws_lbs_ie *lbs_ptr) +{ + ptr = ws_wh_header_base_write(ptr, ws_wh_lbs_length(), WH_IE_LBS_TYPE); + ptr = common_write_24_bit_inverse(lbs_ptr->broadcast_interval, ptr); + ptr = common_write_16_bit_inverse(lbs_ptr->broadcast_secheduler_id, ptr); + *ptr++ = lbs_ptr->channel_plan_tag; + return ptr; +} + +uint16_t ws_wh_nr_length(struct ws_nr_ie *nr_ptr) +{ + uint16_t length; + if (nr_ptr->node_role == WS_NR_ROLE_LFN) { + length = 9; + } else { + length = 3; + } + return length; +} + + +uint8_t *ws_wh_nr_write(uint8_t *ptr, struct ws_nr_ie *nr_ptr) +{ + ptr = ws_wh_header_base_write(ptr, ws_wh_nr_length(nr_ptr), WH_IE_NR_TYPE); + *ptr++ = nr_ptr->node_role; + *ptr++ = nr_ptr->clock_drift; + *ptr++ = nr_ptr->timing_accurancy; + if (nr_ptr->node_role == WS_NR_ROLE_LFN) { + ptr = common_write_24_bit_inverse(nr_ptr->listen_interval_min, ptr); + ptr = common_write_24_bit_inverse(nr_ptr->listen_interval_max, ptr); + } + return ptr; +} + +uint8_t *ws_wh_lnd_write(uint8_t *ptr, struct ws_lnd_ie *lnd_ptr) +{ + ptr = ws_wh_header_base_write(ptr, ws_wh_lnd_length(), WH_IE_LND_TYPE); + *ptr++ = lnd_ptr->response_threshold; + ptr = common_write_24_bit_inverse(lnd_ptr->response_delay, ptr); + *ptr++ = lnd_ptr->discovery_slot_time; + *ptr++ = lnd_ptr->discovery_slots; + ptr = common_write_16_bit_inverse(lnd_ptr->discovery_first_slot, ptr); + return ptr; +} + +uint8_t *ws_wh_lto_write(uint8_t *ptr, struct ws_lto_ie *lto_ptr) +{ + ptr = ws_wh_header_base_write(ptr, ws_wh_lto_length(), WH_IE_LTO_TYPE); + ptr = common_write_24_bit_inverse(lto_ptr->offset, ptr); + ptr = common_write_24_bit_inverse(lto_ptr->adjusted_listening_interval, ptr); + return ptr; +} + + +uint8_t *ws_wh_panid_write(uint8_t *ptr, uint16_t pana_id) +{ + ptr = ws_wh_header_base_write(ptr, ws_wh_panid_length(), WH_IE_PANID_TYPE); + //TODO need to be check byte order + ptr = common_write_16_bit_inverse(pana_id, ptr); + return ptr; +} + + + uint8_t *ws_wp_base_write(uint8_t *ptr, uint16_t length) { return mac_ie_payload_base_write(ptr, WS_WP_NESTED_IE, length); } +static uint8_t ws_wp_channel_info_base_get(ws_generic_channel_info_t *generic_channel_info) +{ + uint8_t channel_info_base = 0; + channel_info_base = generic_channel_info->channel_plan; + channel_info_base |= (generic_channel_info->channel_function << 3); + //Set Excluded Channel control part + channel_info_base |= (generic_channel_info->excluded_channel_ctrl << 6); + + return channel_info_base; +} + +static uint8_t *ws_wp_channel_plan_write(uint8_t *ptr, ws_generic_channel_info_t *generic_channel_info) +{ + switch (generic_channel_info->channel_plan) { + case 0: + //Regulator domain and operationg class inline + *ptr++ = generic_channel_info->plan.zero.regulator_domain; + *ptr++ = generic_channel_info->plan.zero.operation_class; + break; + case 1: + //CHo, Channel spasing and number of channel's inline + ptr = common_write_24_bit_inverse(generic_channel_info->plan.one.ch0 * 100, ptr); + *ptr++ = generic_channel_info->plan.one.channel_spacing; + ptr = common_write_16_bit_inverse(generic_channel_info->plan.one.number_of_channel, ptr); + break; + case 2: + *ptr++ = generic_channel_info->plan.two.regulator_domain; + *ptr++ = generic_channel_info->plan.two.channel_plan_id; + break; + default: + break; + } + return ptr; +} + +static uint8_t *ws_wp_channel_function_write(uint8_t *ptr, ws_generic_channel_info_t *generic_channel_info) +{ + switch (generic_channel_info->channel_function) { + case 0: + //Fixed channel inline + ptr = common_write_16_bit_inverse(generic_channel_info->function.zero.fixed_channel, ptr); + break; + case 1: + case 2: + //No Inline + break; + case 3: + //TODO do this properly + //Hop count + channel hop list + if (generic_channel_info->function.three.channel_list && generic_channel_info->function.three.channel_hop_count) { + *ptr++ = generic_channel_info->function.three.channel_hop_count; + memcpy(ptr, generic_channel_info->function.three.channel_list, generic_channel_info->function.three.channel_hop_count); + ptr += generic_channel_info->function.three.channel_hop_count; + } else { + *ptr++ = 1; + *ptr++ = 0; + } + + break; + default: + break; + + } + return ptr; +} + +static uint8_t *ws_wp_nested_excluded_channel_write(uint8_t *ptr, ws_generic_channel_info_t *generic_channel_info) +{ + if (generic_channel_info->excluded_channel_ctrl == WS_EXC_CHAN_CTRL_RANGE) { + uint8_t range_length = generic_channel_info->excluded_channels.range.excluded_range_length; + ws_excluded_channel_range_data_t *range_ptr = generic_channel_info->excluded_channels.range.exluded_range; + *ptr++ = range_length; + while (range_length) { + ptr = common_write_16_bit_inverse(range_ptr->range_start, ptr); + ptr = common_write_16_bit_inverse(range_ptr->range_end, ptr); + range_length--; + range_ptr++; + } + } else if (generic_channel_info->excluded_channel_ctrl == WS_EXC_CHAN_CTRL_BITMASK) { + //Set Mask + uint16_t channel_mask_length = generic_channel_info->excluded_channels.mask.channel_mask_bytes_inline * 8; + + for (uint8_t i = 0; i < 8; i++) { + uint32_t mask_value = generic_channel_info->excluded_channels.mask.channel_mask[i]; + if (channel_mask_length >= 32) { + ptr = common_write_32_bit(mask_value, ptr); + channel_mask_length -= 32; + } else { + //Write MSB Bits from mask 24-8 top bits + uint8_t move_mask = 0; + while (channel_mask_length) { + *ptr++ = (uint8_t)(mask_value >> (24 - move_mask)); + channel_mask_length -= 8; + move_mask += 8; + } + } + + if (channel_mask_length == 0) { + break; + } + } + } + return ptr; +} + uint8_t *ws_wp_nested_hopping_schedule_write(uint8_t *ptr, struct ws_hopping_schedule_s *hopping_schedule, bool unicast_schedule) { //Calculate length - uint16_t length = ws_wp_nested_hopping_schedule_length(hopping_schedule, unicast_schedule); + ws_generic_channel_info_t generic_channel_info; + + ws_generic_channel_info_init(hopping_schedule, &generic_channel_info, unicast_schedule); + ws_wp_channel_plan_set(&generic_channel_info, hopping_schedule); + ws_wp_channel_function_set(&generic_channel_info, hopping_schedule, unicast_schedule); + + uint16_t length; + if (unicast_schedule) { + length = 3; + } else { + length = 9; + } + length += ws_wp_generic_shedule_length_get(&generic_channel_info); + if (!unicast_schedule) { ptr = mac_ie_nested_ie_long_base_write(ptr, WP_PAYLOAD_IE_BS_TYPE, length); ptr = common_write_32_bit_inverse(hopping_schedule->fhss_broadcast_interval, ptr); @@ -164,97 +477,12 @@ uint8_t *ws_wp_nested_hopping_schedule_write(uint8_t *ptr, struct ws_hopping_sch *ptr++ = hopping_schedule->clock_drift; *ptr++ = hopping_schedule->timing_accurancy; - uint8_t channel_info_base = 0; - channel_info_base = (hopping_schedule->channel_plan); - if (unicast_schedule) { - channel_info_base |= (hopping_schedule->uc_channel_function << 3); - //Set Excluded Channel control part - channel_info_base |= (hopping_schedule->excluded_channels.excuded_channel_ctrl << 6); - } else { - channel_info_base |= (hopping_schedule->bc_channel_function << 3); - } - *ptr++ = channel_info_base; - - switch (hopping_schedule->channel_plan) { - case 0: - //Regulator domain and operationg class inline - *ptr++ = hopping_schedule->regulatory_domain; - *ptr++ = hopping_schedule->operating_class; - break; - case 1: - //CHo, Channel spasing and number of channel's inline - ptr = common_write_24_bit_inverse(hopping_schedule->ch0_freq * 100, ptr); - *ptr++ = hopping_schedule->channel_spacing; - ptr = common_write_16_bit_inverse(hopping_schedule->number_of_channels, ptr); - break; - default: - break; - } - uint8_t cf = hopping_schedule->uc_channel_function; - uint16_t fixed_channel = hopping_schedule->uc_fixed_channel; - if (!unicast_schedule) { - cf = hopping_schedule->bc_channel_function; - } - switch (cf) { - case 0: - //Fixed channel inline - if (!unicast_schedule) { - fixed_channel = hopping_schedule->bc_fixed_channel; - } - ptr = common_write_16_bit_inverse(fixed_channel, ptr); - break; - case 1: - case 2: - //No Inline - break; - case 3: - //TODO do this properly - //Hop count + channel hop list - *ptr++ = 1; - *ptr++ = 0; - break; - default: - break; - - } - - if (unicast_schedule && hopping_schedule->excluded_channels.excuded_channel_ctrl) { - if (hopping_schedule->excluded_channels.excuded_channel_ctrl == WS_EXC_CHAN_CTRL_RANGE) { - uint8_t range_length = hopping_schedule->excluded_channels.excluded_range_length; - ws_excluded_channel_range_data_t *range_ptr = hopping_schedule->excluded_channels.exluded_range; - *ptr++ = range_length; - while (range_length) { - ptr = common_write_16_bit_inverse(range_ptr->range_start, ptr); - ptr = common_write_16_bit_inverse(range_ptr->range_end, ptr); - range_length--; - range_ptr++; - } - } else if (hopping_schedule->excluded_channels.excuded_channel_ctrl == WS_EXC_CHAN_CTRL_BITMASK) { - //Set Mask - uint16_t channel_mask_length = hopping_schedule->excluded_channels.channel_mask_bytes_inline * 8; - - for (uint8_t i = 0; i < 8; i++) { - uint32_t mask_value = hopping_schedule->excluded_channels.channel_mask[i]; - if (channel_mask_length >= 32) { - ptr = common_write_32_bit(mask_value, ptr); - channel_mask_length -= 32; - } else { - //Write MSB Bits from mask 24-8 top bits - uint8_t move_mask = 0; - while (channel_mask_length) { - *ptr++ = (uint8_t)(mask_value >> (24 - move_mask)); - channel_mask_length -= 8; - move_mask += 8; - } - } - - if (channel_mask_length == 0) { - break; - } - } - } - } + // Write a generic part of shedule + *ptr++ = ws_wp_channel_info_base_get(&generic_channel_info); + ptr = ws_wp_channel_plan_write(ptr, &generic_channel_info); + ptr = ws_wp_channel_function_write(ptr, &generic_channel_info); + ptr = ws_wp_nested_excluded_channel_write(ptr, &generic_channel_info); return ptr; } @@ -280,7 +508,12 @@ uint8_t *ws_wp_nested_pan_info_write(uint8_t *ptr, struct ws_pan_information_s * uint8_t temp8 = 0; temp8 |= (pan_congiguration->use_parent_bs << 0); temp8 |= (pan_congiguration->rpl_routing_method << 1); + /* FAN 1.1 specific write */ + if (pan_congiguration->version > WS_FAN_VERSION_1_0) { + temp8 |= (pan_congiguration->lfn_window_style << 2); + } temp8 |= pan_congiguration->version << 5; + *ptr++ = temp8; return ptr; } @@ -315,11 +548,202 @@ uint8_t *ws_wp_nested_gtkhash_write(uint8_t *ptr, uint8_t *gtkhash, uint8_t gtkh return ptr; } +uint16_t ws_wp_nested_pcap_length(uint8_t list_length) +{ + uint16_t lenght = (list_length * 3) + 1; + return lenght; +} + +void ws_ie_lib_phy_cap_list_update(struct ws_phy_cap_info *phy_pap, struct ws_pcap_ie *pcap) +{ + for (int i = 0; i < phy_pap->length_of_list; i++) { + if (phy_pap->pcap[i].phy_type == pcap->phy_type) { + phy_pap->pcap[i].operating_mode |= pcap->operating_mode; + return; + } + } + + if (phy_pap->length_of_list == 7) { + return; + } + + phy_pap->pcap[phy_pap->length_of_list].phy_type = pcap->phy_type; + phy_pap->pcap[phy_pap->length_of_list].operating_mode |= pcap->operating_mode; + phy_pap->length_of_list++; +} + + +ws_pcap_ie_t ws_ie_lib_generate_phy_cap_from_phy_mode_id(uint8_t phy_mode_id) +{ + ws_pcap_ie_t pcap; + if (phy_mode_id > 96) { + pcap.operating_mode = 0; + return pcap; + } + + if (phy_mode_id < 16) { + pcap.phy_type = WS_PHY_TYPE_ID_FSK; + } else if (phy_mode_id < 32) { + phy_mode_id -= 16; + pcap.phy_type = WS_PHY_TYPE_ID_FSK_FEC; + } else if (phy_mode_id < 48) { + phy_mode_id -= 32; + pcap.phy_type = WS_PHY_TYPE_ID_OFDM1; + } else if (phy_mode_id < 64) { + phy_mode_id -= 48; + pcap.phy_type = WS_PHY_TYPE_ID_OFDM2; + } else if (phy_mode_id < 80) { + phy_mode_id -= 64; + pcap.phy_type = WS_PHY_TYPE_ID_OFDM3; + } else { + phy_mode_id -= 80; + pcap.phy_type = WS_PHY_TYPE_ID_OFDM4; + } + pcap.operating_mode = 1 << phy_mode_id; + return pcap; +} + +uint8_t ws_ie_lib_phy_mode_id_get_from_phy_cap(ws_pcap_ie_t *phy_cap) +{ + if (!phy_cap->operating_mode) { + return 0; + } + + uint8_t phy_mode_id = 0; + for (uint8_t i = 0; i < 16; i++) { + if (phy_cap->operating_mode & (1 << (15 - i))) { + phy_mode_id = 15 - i; + break; + } + } + + switch (phy_cap->phy_type) { + case WS_PHY_TYPE_ID_FSK: + break; + case WS_PHY_TYPE_ID_FSK_FEC: + phy_mode_id += 16; + break; + case WS_PHY_TYPE_ID_OFDM1: + phy_mode_id += 32; + break; + case WS_PHY_TYPE_ID_OFDM2: + phy_mode_id += 48; + break; + case WS_PHY_TYPE_ID_OFDM3: + phy_mode_id += 64; + break; + case WS_PHY_TYPE_ID_OFDM4: + phy_mode_id += 80; + break; + default: + break; + } + + return phy_mode_id; + +} + +uint8_t *ws_wp_nested_pcap_write(uint8_t *ptr, struct ws_phy_cap_info *pcap_list) +{ + uint16_t lenght = ws_wp_nested_pcap_length(pcap_list->length_of_list); + + ptr = mac_ie_nested_ie_short_base_write(ptr, WP_PAYLOAD_IE_PCAP_TYPE, lenght); + *ptr++ = pcap_list->length_of_list; + for (int i = 0; i < pcap_list->length_of_list; i++) { + *ptr++ = pcap_list->pcap[i].phy_type; + ptr = common_write_16_bit_inverse(pcap_list->pcap[i].operating_mode, ptr); + } + return ptr; +} + + +uint8_t *ws_wp_nested_lfn_version_write(uint8_t *ptr, struct ws_lfnver_ie *ws_lfnver) +{ + ptr = mac_ie_nested_ie_short_base_write(ptr, WP_PAYLOAD_IE_LFNVER_TYPE, ws_wp_nested_lfn_version_length()); + ptr = common_write_16_bit_inverse(ws_lfnver->lfn_version, ptr); + + return ptr; +} + + +uint16_t ws_wp_lgtk_hash_length(struct ws_lgtkhash_ie *ws_lgtkhash) +{ + uint16_t length = 1; + + if (ws_lgtkhash->lgtk0) { + length += 8; + } + + if (ws_lgtkhash->lgtk1) { + length += 8; + } + + if (ws_lgtkhash->lgtk2) { + length += 8; + } + return length; +} + +uint8_t *ws_wp_nested_lgtk_hash_write(uint8_t *ptr, struct ws_lgtkhash_ie *ws_lgtkhash) +{ + uint16_t length = ws_wp_lgtk_hash_length(ws_lgtkhash); + + ptr = mac_ie_nested_ie_short_base_write(ptr, WP_PAYLOAD_IE_LGTKHASH_TYPE, length); + + uint8_t temp8 = 0; + temp8 |= (ws_lgtkhash->lgtk0 << 0); + temp8 |= (ws_lgtkhash->lgtk1 << 1); + temp8 |= (ws_lgtkhash->lgtk2 << 2); + temp8 |= (ws_lgtkhash->active_lgtk_index << 3); + + *ptr++ = temp8; + if (ws_lgtkhash->lgtk0) { + memcpy(ptr, ws_lgtkhash->lgtk0_hash, 8); + ptr += 8; + } + + if (ws_lgtkhash->lgtk1) { + memcpy(ptr, ws_lgtkhash->lgtk1_hash, 8); + ptr += 8; + } + + if (ws_lgtkhash->lgtk2) { + memcpy(ptr, ws_lgtkhash->lgtk2_hash, 8); + ptr += 8; + } + + return ptr; +} + +uint16_t ws_wp_nested_lfn_channel_plan_length(ws_generic_channel_info_t *ws_lcp) +{ + uint16_t length = 1; //Channel Plan Tag + + length += ws_wp_generic_shedule_length_get(ws_lcp); + return length; +} + +uint8_t *ws_wp_nested_lfn_channel_plan_write(uint8_t *ptr, ws_generic_channel_info_t *ws_lcp, uint8_t plan_tag_id) +{ + uint16_t length = ws_wp_nested_lfn_channel_plan_length(ws_lcp); + + ptr = mac_ie_nested_ie_long_base_write(ptr, WP_PAYLOAD_IE_LFN_CHANNEL_PLAN_TYPE, length); + *ptr++ = plan_tag_id; + *ptr++ = ws_wp_channel_info_base_get(ws_lcp); + ptr = ws_wp_channel_plan_write(ptr, ws_lcp); + ptr = ws_wp_channel_function_write(ptr, ws_lcp); + ptr = ws_wp_nested_excluded_channel_write(ptr, ws_lcp); + return ptr; + +} + + + bool ws_wh_utt_read(uint8_t *data, uint16_t length, struct ws_utt_ie *utt_ie) { mac_header_IE_t utt_ie_data; utt_ie_data.id = MAC_HEADER_ASSIGNED_EXTERNAL_ORG_IE_ID; - if (4 != mac_ie_header_sub_id_discover(data, length, &utt_ie_data, WH_IE_UTT_TYPE)) { + if (4 > mac_ie_header_sub_id_discover(data, length, &utt_ie_data, WH_IE_UTT_TYPE)) { // NO UTT header return false; } @@ -333,7 +757,7 @@ bool ws_wh_bt_read(uint8_t *data, uint16_t length, struct ws_bt_ie *bt_ie) { mac_header_IE_t btt_ie_data; btt_ie_data.id = MAC_HEADER_ASSIGNED_EXTERNAL_ORG_IE_ID; - if (5 != mac_ie_header_sub_id_discover(data, length, &btt_ie_data, WH_IE_BT_TYPE)) { + if (5 > mac_ie_header_sub_id_discover(data, length, &btt_ie_data, WH_IE_BT_TYPE)) { return false; } data = btt_ie_data.content_ptr; @@ -346,7 +770,7 @@ bool ws_wh_fc_read(uint8_t *data, uint16_t length, struct ws_fc_ie *fc_ie) { mac_header_IE_t fc_ie_data; fc_ie_data.id = MAC_HEADER_ASSIGNED_EXTERNAL_ORG_IE_ID; - if (2 != mac_ie_header_sub_id_discover(data, length, &fc_ie_data, WH_IE_FC_TYPE)) { + if (2 > mac_ie_header_sub_id_discover(data, length, &fc_ie_data, WH_IE_FC_TYPE)) { return false; } data = fc_ie_data.content_ptr; @@ -359,7 +783,7 @@ bool ws_wh_rsl_read(uint8_t *data, uint16_t length, int8_t *rsl) { mac_header_IE_t rsl_ie_data; rsl_ie_data.id = MAC_HEADER_ASSIGNED_EXTERNAL_ORG_IE_ID; - if (1 != mac_ie_header_sub_id_discover(data, length, &rsl_ie_data, WH_IE_RSL_TYPE)) { + if (1 > mac_ie_header_sub_id_discover(data, length, &rsl_ie_data, WH_IE_RSL_TYPE)) { return false; } *rsl = *rsl_ie_data.content_ptr; @@ -371,7 +795,7 @@ bool ws_wh_ea_read(uint8_t *data, uint16_t length, uint8_t *eui64) { mac_header_IE_t rsl_ie_data; rsl_ie_data.id = MAC_HEADER_ASSIGNED_EXTERNAL_ORG_IE_ID; - if (8 != mac_ie_header_sub_id_discover(data, length, &rsl_ie_data, WH_IE_EA_TYPE)) { + if (8 > mac_ie_header_sub_id_discover(data, length, &rsl_ie_data, WH_IE_EA_TYPE)) { return false; } memcpy(eui64, rsl_ie_data.content_ptr, 8); @@ -379,6 +803,162 @@ bool ws_wh_ea_read(uint8_t *data, uint16_t length, uint8_t *eui64) return true; } +bool ws_wh_lutt_read(uint8_t *data, uint16_t length, struct ws_lutt_ie *ws_lutt) +{ + + mac_header_IE_t lutt_ie_data; + lutt_ie_data.id = MAC_HEADER_ASSIGNED_EXTERNAL_ORG_IE_ID; + if (ws_wh_lutt_length() > mac_ie_header_sub_id_discover(data, length, &lutt_ie_data, WH_IE_LUTT_TYPE)) { + return false; + } + data = lutt_ie_data.content_ptr; + ws_lutt->message_type = *data++; + ws_lutt->slot_number = common_read_16_bit_inverse(data); + ws_lutt->interval_offset = common_read_24_bit_inverse(data + 2); + + return true; +} + +bool ws_wh_lus_read(uint8_t *data, uint16_t length, struct ws_lus_ie *lus_ptr) +{ + mac_header_IE_t lus_ie_data; + lus_ie_data.id = MAC_HEADER_ASSIGNED_EXTERNAL_ORG_IE_ID; + if (ws_wh_lus_length() > mac_ie_header_sub_id_discover(data, length, &lus_ie_data, WH_IE_LUS_TYPE)) { + return false; + } + data = lus_ie_data.content_ptr; + lus_ptr->listen_interval = common_read_24_bit_inverse(data); + data += 3; + lus_ptr->channel_plan_tag = *data; + + return true; +} + +bool ws_wh_flus_read(uint8_t *data, uint16_t length, struct ws_flus_ie *flus_ptr) +{ + mac_header_IE_t flus_ie_data; + flus_ie_data.id = MAC_HEADER_ASSIGNED_EXTERNAL_ORG_IE_ID; + if (ws_wh_flus_length() > mac_ie_header_sub_id_discover(data, length, &flus_ie_data, WH_IE_FLUS_TYPE)) { + return false; + } + data = flus_ie_data.content_ptr; + flus_ptr->dwell_interval = *data++; + flus_ptr->channel_plan_tag = *data; + + return true; +} + +bool ws_wh_lbt_read(uint8_t *data, uint16_t length, struct ws_lbt_ie *ws_lbt) +{ + mac_header_IE_t lbt_ie_data; + lbt_ie_data.id = MAC_HEADER_ASSIGNED_EXTERNAL_ORG_IE_ID; + if (ws_wh_lbt_length() > mac_ie_header_sub_id_discover(data, length, &lbt_ie_data, WH_IE_LBT_TYPE)) { + return false; + } + data = lbt_ie_data.content_ptr; + ws_lbt->slot_number = common_read_16_bit_inverse(data); + ws_lbt->interval_offset = common_read_24_bit_inverse(data + 2); + + return true; +} + +bool ws_wh_lbs_read(uint8_t *data, uint16_t length, struct ws_lbs_ie *lbs_ptr) +{ + mac_header_IE_t lbs_ie_data; + lbs_ie_data.id = MAC_HEADER_ASSIGNED_EXTERNAL_ORG_IE_ID; + if (ws_wh_lbs_length() > mac_ie_header_sub_id_discover(data, length, &lbs_ie_data, WH_IE_LBS_TYPE)) { + return false; + } + + data = lbs_ie_data.content_ptr; + lbs_ptr->broadcast_interval = common_read_24_bit_inverse(data); + data += 3; + lbs_ptr->broadcast_secheduler_id = common_read_16_bit_inverse(data); + data += 2; + lbs_ptr->channel_plan_tag = *data; + + return true; +} + +bool ws_wh_nr_read(uint8_t *data, uint16_t length, struct ws_nr_ie *nr_ptr) +{ + mac_header_IE_t nr_ie_data; + nr_ie_data.id = MAC_HEADER_ASSIGNED_EXTERNAL_ORG_IE_ID; + if (3 > mac_ie_header_sub_id_discover(data, length, &nr_ie_data, WH_IE_NR_TYPE)) { + return false; + } + data = nr_ie_data.content_ptr; + nr_ptr->node_role = *data++ & 7; + nr_ptr->clock_drift = *data++; + nr_ptr->timing_accurancy = *data++; + switch (nr_ptr->node_role) { + case WS_NR_ROLE_BR: + break; + case WS_NR_ROLE_ROUTER: + break; + case WS_NR_ROLE_LFN: + if (9 > nr_ie_data.length) { + return false; + } + nr_ptr->listen_interval_min = common_read_24_bit_inverse(data); + nr_ptr->listen_interval_max = common_read_24_bit_inverse(data + 3); + break; + default: + return false; + } + + return true; +} + +bool ws_wh_lnd_read(uint8_t *data, uint16_t length, struct ws_lnd_ie *lnd_ptr) +{ + mac_header_IE_t lnd_ie_data; + lnd_ie_data.id = MAC_HEADER_ASSIGNED_EXTERNAL_ORG_IE_ID; + if (ws_wh_lnd_length() > mac_ie_header_sub_id_discover(data, length, &lnd_ie_data, WH_IE_LND_TYPE)) { + return false; + } + + data = lnd_ie_data.content_ptr; + lnd_ptr->response_threshold = *data++; + lnd_ptr->response_delay = common_read_24_bit_inverse(data); + data += 3; + lnd_ptr->discovery_slot_time = *data++; + lnd_ptr->discovery_slots = *data++; + lnd_ptr->discovery_first_slot = common_read_16_bit_inverse(data); + + return true; +} + +bool ws_wh_lto_read(uint8_t *data, uint16_t length, struct ws_lto_ie *lto_ptr) +{ + mac_header_IE_t lto_ie_data; + lto_ie_data.id = MAC_HEADER_ASSIGNED_EXTERNAL_ORG_IE_ID; + if (ws_wh_lto_length() > mac_ie_header_sub_id_discover(data, length, <o_ie_data, WH_IE_LTO_TYPE)) { + return false; + } + data = lto_ie_data.content_ptr; + + lto_ptr->offset = common_read_24_bit_inverse(data); + lto_ptr->adjusted_listening_interval = common_read_24_bit_inverse(data + 3); + + return true; +} + +bool ws_wh_panid_read(uint8_t *data, uint16_t length, struct ws_panid_ie *ws_panid) +{ + mac_header_IE_t panid_ie_data; + panid_ie_data.id = MAC_HEADER_ASSIGNED_EXTERNAL_ORG_IE_ID; + if (ws_wh_panid_length() > mac_ie_header_sub_id_discover(data, length, &panid_ie_data, WH_IE_PANID_TYPE)) { + return false; + } + + ws_panid->panid = common_read_16_bit_inverse(panid_ie_data.content_ptr); + + return true; +} + + + static uint8_t *ws_channel_plan_zero_read(uint8_t *ptr, ws_channel_plan_zero_t *plan) { plan->regulator_domain = *ptr++; @@ -397,6 +977,13 @@ static uint8_t *ws_channel_plan_one_read(uint8_t *ptr, ws_channel_plan_one_t *pl return ptr; } +static uint8_t *ws_channel_plan_two_read(uint8_t *ptr, ws_channel_plan_two_t *plan) +{ + plan->regulator_domain = *ptr++; + plan->channel_plan_id = *ptr++; + return ptr; +} + static uint8_t *ws_channel_function_zero_read(uint8_t *ptr, ws_channel_function_zero_t *plan) { plan->fixed_channel = common_read_16_bit_inverse(ptr); @@ -415,7 +1002,7 @@ bool ws_wp_nested_us_read(uint8_t *data, uint16_t length, struct ws_us_ie *us_ie mac_nested_payload_IE_t nested_payload_ie; nested_payload_ie.id = WP_PAYLOAD_IE_US_TYPE; nested_payload_ie.type_long = true; - if (mac_ie_nested_discover(data, length, &nested_payload_ie) < 4) { + if (4 > mac_ie_nested_discover(data, length, &nested_payload_ie)) { return false; } @@ -443,6 +1030,9 @@ bool ws_wp_nested_us_read(uint8_t *data, uint16_t length, struct ws_us_ie *us_ie case 1: data = ws_channel_plan_one_read(data, &us_ie->plan.one); break; + case 2: + data = ws_channel_plan_two_read(data, &us_ie->plan.two); + break; default: return false; @@ -517,7 +1107,7 @@ bool ws_wp_nested_bs_read(uint8_t *data, uint16_t length, struct ws_bs_ie *bs_ie mac_nested_payload_IE_t nested_payload_ie; nested_payload_ie.id = WP_PAYLOAD_IE_BS_TYPE; nested_payload_ie.type_long = true; - if (mac_ie_nested_discover(data, length, &nested_payload_ie) < 10) { + if (10 > mac_ie_nested_discover(data, length, &nested_payload_ie)) { return false; } data = nested_payload_ie.content_ptr; @@ -548,6 +1138,9 @@ bool ws_wp_nested_bs_read(uint8_t *data, uint16_t length, struct ws_bs_ie *bs_ie case 1: data = ws_channel_plan_one_read(data, &bs_ie->plan.one); break; + case 2: + data = ws_channel_plan_two_read(data, &bs_ie->plan.two); + break; default: return false; @@ -590,7 +1183,7 @@ bool ws_wp_nested_pan_read(uint8_t *data, uint16_t length, struct ws_pan_informa mac_nested_payload_IE_t nested_payload_ie; nested_payload_ie.id = WP_PAYLOAD_IE_PAN_TYPE; nested_payload_ie.type_long = false; - if (mac_ie_nested_discover(data, length, &nested_payload_ie) != 5) { + if (5 > mac_ie_nested_discover(data, length, &nested_payload_ie)) { return false; } @@ -599,6 +1192,12 @@ bool ws_wp_nested_pan_read(uint8_t *data, uint16_t length, struct ws_pan_informa pan_congiguration->use_parent_bs = (nested_payload_ie.content_ptr[4] & 0x01) == 0x01; pan_congiguration->rpl_routing_method = (nested_payload_ie.content_ptr[4] & 0x02) == 0x02; pan_congiguration->version = (nested_payload_ie.content_ptr[4] & 0xe0) >> 5; + if (pan_congiguration->version > WS_FAN_VERSION_1_0) { + /* FAN 1.1 specific read */ + pan_congiguration->lfn_window_style = (nested_payload_ie.content_ptr[4] & 0x04) == 0x04; + } else { + pan_congiguration->lfn_window_style = false; //Set false for FAN 1.0 + } return true; } @@ -608,7 +1207,7 @@ bool ws_wp_nested_pan_version_read(uint8_t *data, uint16_t length, uint16_t *pan mac_nested_payload_IE_t nested_payload_ie; nested_payload_ie.id = WP_PAYLOAD_IE_PAN_VER_TYPE; nested_payload_ie.type_long = false; - if (mac_ie_nested_discover(data, length, &nested_payload_ie) != 2) { + if (2 > mac_ie_nested_discover(data, length, &nested_payload_ie)) { return false; } *pan_version = common_read_16_bit_inverse(nested_payload_ie.content_ptr); @@ -646,3 +1245,204 @@ bool ws_wp_nested_network_name_read(uint8_t *data, uint16_t length, ws_wp_networ return true; } +bool ws_wp_nested_pcap_read(uint8_t *data, uint16_t length, struct ws_phy_cap_info *ws_pcap_list) +{ +#ifdef HAVE_WS_VERSION_1_1 + mac_nested_payload_IE_t nested_payload_ie; + nested_payload_ie.id = WP_PAYLOAD_IE_PCAP_TYPE; + nested_payload_ie.type_long = false; + if (4 > mac_ie_nested_discover(data, length, &nested_payload_ie)) { + return false; + } + //Read & Validate length + data = nested_payload_ie.content_ptr; + uint8_t length_of_cap = *data++ & 0x07; + + if (nested_payload_ie.length < length_of_cap * 3) { + return false; + } + ws_pcap_list->length_of_list = length_of_cap; + + for (uint8_t i = 0; i < length_of_cap; i++) { + ws_pcap_list->pcap[i].phy_type = *data++ & 7; + ws_pcap_list->pcap[i].operating_mode = common_read_16_bit_inverse(data); + data += 2; + } + + + return true; +#else + (void) data; + (void) length; + (void) ws_pcap_list; + return false; +#endif +} + + +bool ws_wp_nested_lfn_version_read(uint8_t *data, uint16_t length, struct ws_lfnver_ie *ws_lfnver) +{ + mac_nested_payload_IE_t nested_payload_ie; + nested_payload_ie.id = WP_PAYLOAD_IE_LFNVER_TYPE; + nested_payload_ie.type_long = false; + if (ws_wp_nested_lfn_version_length() > mac_ie_nested_discover(data, length, &nested_payload_ie)) { + return false; + } + + ws_lfnver->lfn_version = common_read_16_bit_inverse(nested_payload_ie.content_ptr); + return true; +} + + +bool ws_wp_nested_lgtk_hash_read(uint8_t *data, uint16_t length, struct ws_lgtkhash_ie *ws_lgtkhash) +{ + mac_nested_payload_IE_t nested_payload_ie; + nested_payload_ie.id = WP_PAYLOAD_IE_LGTKHASH_TYPE; + nested_payload_ie.type_long = false; + if (1 > mac_ie_nested_discover(data, length, &nested_payload_ie)) { + return false; + } + data = nested_payload_ie.content_ptr; + + ws_lgtkhash->lgtk0 = (*data & 0x01) == 0x01; + ws_lgtkhash->lgtk1 = (*data & 0x02) == 0x02; + ws_lgtkhash->lgtk2 = (*data & 0x04) == 0x04; + ws_lgtkhash->active_lgtk_index = (*data & 0x18) >> 3; + + if (ws_wp_lgtk_hash_length(ws_lgtkhash) > nested_payload_ie.length) { + return false; + } + + data++; + if (ws_lgtkhash->lgtk0) { + ws_lgtkhash->lgtk0_hash = data; + data += 8; + } else { + ws_lgtkhash->lgtk0_hash = NULL; + } + + if (ws_lgtkhash->lgtk1) { + ws_lgtkhash->lgtk1_hash = data; + data += 8; + } else { + ws_lgtkhash->lgtk1_hash = NULL; + } + + if (ws_lgtkhash->lgtk2) { + ws_lgtkhash->lgtk2_hash = data; + } else { + ws_lgtkhash->lgtk2_hash = NULL; + } + + return true; + +} + + + +bool ws_wp_nested_lfn_channel_plan_read(uint8_t *data, uint16_t length, ws_generic_channel_info_t *ws_lcp, uint8_t plan_tag_id) +{ + mac_nested_payload_IE_t nested_payload_ie; + nested_payload_ie.id = WP_PAYLOAD_IE_LFN_CHANNEL_PLAN_TYPE; + nested_payload_ie.type_long = true; + + if (1 < mac_ie_nested_tagged_discover(data, length, &nested_payload_ie, plan_tag_id)) { + return false; + } + //Parse Channel Plan, function and excluded channel + data = nested_payload_ie.content_ptr; + ws_lcp->channel_plan = (*data & 3); + ws_lcp->channel_function = (*data & 0x38) >> 3; + ws_lcp->excluded_channel_ctrl = (*data & 0xc0) >> 6; + data++; + nested_payload_ie.length--; + + uint16_t info_length = 0; + info_length = ws_channel_plan_length(ws_lcp->channel_plan); + if (nested_payload_ie.length < info_length) { + return false; + } + + nested_payload_ie.length -= info_length; + switch (ws_lcp->channel_plan) { + case 0: + data = ws_channel_plan_zero_read(data, &ws_lcp->plan.zero); + break; + + case 1: + data = ws_channel_plan_one_read(data, &ws_lcp->plan.one); + break; + case 2: + data = ws_channel_plan_two_read(data, &ws_lcp->plan.two); + break; + default: + return false; + + } + + info_length = ws_channel_function_length(ws_lcp->channel_function, 0); + + if (nested_payload_ie.length < info_length) { + return false; + } + nested_payload_ie.length -= info_length; + + + switch (ws_lcp->channel_function) { + case 0: + data = ws_channel_function_zero_read(data, &ws_lcp->function.zero); + break; + + case 1: + case 2: + break; + + case 3: + + data = ws_channel_function_three_read(data, &ws_lcp->function.three); + info_length = ws_lcp->function.three.channel_hop_count; + if (nested_payload_ie.length < info_length) { + return false; + } + nested_payload_ie.length -= info_length; + data += info_length; + break; + default: + return false; + + } + + switch (ws_lcp->excluded_channel_ctrl) { + case WS_EXC_CHAN_CTRL_NONE: + + break; + case WS_EXC_CHAN_CTRL_RANGE: + ws_lcp->excluded_channels.range_in.number_of_range = *data; + if (nested_payload_ie.length < (ws_lcp->excluded_channels.range_in.number_of_range * 4) + 1) { + return false; + } + //Set Range start after validation + ws_lcp->excluded_channels.range_in.range_start = data + 1; + break; + + case WS_EXC_CHAN_CTRL_BITMASK: + if (ws_lcp->channel_plan == 1) { + ws_lcp->excluded_channels.mask_in.mask_len_inline = ((ws_lcp->plan.one.number_of_channel + 7) / 8); + if (ws_lcp->excluded_channels.mask_in.mask_len_inline != nested_payload_ie.length) { + //Channel mask length is not correct + return false; + } + } else { + ws_lcp->excluded_channels.mask_in.mask_len_inline = nested_payload_ie.length; + } + + ws_lcp->excluded_channels.mask_in.channel_mask = data; + break; + default: + return false; + } + + return true; + +} + diff --git a/source/6LoWPAN/ws/ws_ie_lib.h b/source/6LoWPAN/ws/ws_ie_lib.h index 3198763c07..d6fb4907ab 100644 --- a/source/6LoWPAN/ws/ws_ie_lib.h +++ b/source/6LoWPAN/ws/ws_ie_lib.h @@ -24,6 +24,8 @@ struct ws_bt_ie; struct ws_us_ie; struct ws_hopping_schedule_s; struct ws_fc_ie; +struct ws_phy_cap_info; +struct ws_pcap_ie; /** * @brief ws_wp_network_name_t WS nested payload network name @@ -33,6 +35,16 @@ typedef struct ws_wp_network_name { uint8_t *network_name; } ws_wp_network_name_t; +#define ws_wp_nested_lfn_version_length() 2 +#define ws_wh_lutt_length() 6 +#define ws_wh_lus_length() 4 +#define ws_wh_flus_length() 2 +#define ws_wh_lbt_length() 5 +#define ws_wh_lbs_length() 6 +#define ws_wh_lnd_length() 8 +#define ws_wh_lto_length() 6 +#define ws_wh_panid_length() 2 + /* WS_WH HEADER IE */ uint8_t *ws_wh_utt_write(uint8_t *ptr, uint8_t message_type); uint8_t *ws_wh_bt_write(uint8_t *ptr); @@ -40,12 +52,34 @@ uint8_t *ws_wh_fc_write(uint8_t *ptr, struct ws_fc_ie *fc_ie); uint8_t *ws_wh_rsl_write(uint8_t *ptr, uint8_t rsl); uint8_t *ws_wh_vh_write(uint8_t *ptr, uint8_t *vendor_header, uint8_t vendor_header_length); uint8_t *ws_wh_ea_write(uint8_t *ptr, uint8_t *eui64); +/* Wi-SUN FAN 1.1 */ +uint8_t *ws_wh_lutt_write(uint8_t *ptr, uint8_t message_type); +uint8_t *ws_wh_lus_write(uint8_t *ptr, struct ws_lus_ie *lus_ptr); +uint8_t *ws_wh_flus_write(uint8_t *ptr, struct ws_flus_ie *flus_ptr); +uint8_t *ws_wh_lbt_write(uint8_t *ptr); +uint8_t *ws_wh_lbs_write(uint8_t *ptr, struct ws_lbs_ie *lbs_ptr); +uint8_t *ws_wh_nr_write(uint8_t *ptr, struct ws_nr_ie *nr_ptr); +uint16_t ws_wh_nr_length(struct ws_nr_ie *nr_ptr); +uint8_t *ws_wh_lnd_write(uint8_t *ptr, struct ws_lnd_ie *lnd_ptr); +uint8_t *ws_wh_lto_write(uint8_t *ptr, struct ws_lto_ie *lto_ptr); +uint8_t *ws_wh_panid_write(uint8_t *ptr, uint16_t pana_id); + bool ws_wh_utt_read(uint8_t *data, uint16_t length, struct ws_utt_ie *utt_ie); bool ws_wh_bt_read(uint8_t *data, uint16_t length, struct ws_bt_ie *bt_ie); bool ws_wh_fc_read(uint8_t *data, uint16_t length, struct ws_fc_ie *fc_ie); bool ws_wh_rsl_read(uint8_t *data, uint16_t length, int8_t *rsl); bool ws_wh_ea_read(uint8_t *data, uint16_t length, uint8_t *eui64); +/*Wi-SUN FAN 1.1 */ +bool ws_wh_lutt_read(uint8_t *data, uint16_t length, struct ws_lutt_ie *ws_lutt); +bool ws_wh_lus_read(uint8_t *data, uint16_t length, struct ws_lus_ie *lus_ptr); +bool ws_wh_flus_read(uint8_t *data, uint16_t length, struct ws_flus_ie *flus_ptr); +bool ws_wh_lbt_read(uint8_t *data, uint16_t length, struct ws_lbt_ie *ws_lbt); +bool ws_wh_lbs_read(uint8_t *data, uint16_t length, struct ws_lbs_ie *lbs_ptr); +bool ws_wh_nr_read(uint8_t *data, uint16_t length, struct ws_nr_ie *nr_ptr); +bool ws_wh_lnd_read(uint8_t *data, uint16_t length, struct ws_lnd_ie *lnd_ptr); +bool ws_wh_lto_read(uint8_t *data, uint16_t length, struct ws_lto_ie *lto_ptr); +bool ws_wh_panid_read(uint8_t *data, uint16_t length, struct ws_panid_ie *ws_panid); /* WS_WP_NESTED PAYLOD IE */ uint8_t *ws_wp_base_write(uint8_t *ptr, uint16_t length); @@ -56,6 +90,22 @@ uint8_t *ws_wp_nested_netname_write(uint8_t *ptr, uint8_t *network_name, uint8_t uint8_t *ws_wp_nested_pan_ver_write(uint8_t *ptr, struct ws_pan_information_s *pan_congiguration); uint8_t *ws_wp_nested_gtkhash_write(uint8_t *ptr, uint8_t *gtkhash, uint8_t gtkhash_length); uint16_t ws_wp_nested_hopping_schedule_length(struct ws_hopping_schedule_s *hopping_schedule, bool unicast_schedule); +/* Wi-SUN FAN 1.1 */ +/* WS PCAP */ +uint8_t *ws_wp_nested_pcap_write(uint8_t *ptr, struct ws_phy_cap_info *pcap_list); +uint16_t ws_wp_nested_pcap_length(uint8_t list_length); +struct ws_pcap_ie ws_ie_lib_generate_phy_cap_from_phy_mode_id(uint8_t phy_mode_id); +uint8_t ws_ie_lib_phy_mode_id_get_from_phy_cap(struct ws_pcap_ie *phy_cap); +void ws_ie_lib_phy_cap_list_update(struct ws_phy_cap_info *phy_pap, struct ws_pcap_ie *pcap); +/* WS LFN version */ +uint8_t *ws_wp_nested_lfn_version_write(uint8_t *ptr, struct ws_lfnver_ie *ws_lfnver); +/* WS LFN GTK HAS */ +uint8_t *ws_wp_nested_lgtk_hash_write(uint8_t *ptr, struct ws_lgtkhash_ie *ws_lgtkhash); +uint16_t ws_wp_lgtk_hash_length(struct ws_lgtkhash_ie *ws_lgtkhash); +/* WS LFN Channel plan */ +uint8_t *ws_wp_nested_lfn_channel_plan_write(uint8_t *ptr, struct ws_generic_channel_info *ws_lcp, uint8_t plan_tag_id); +uint16_t ws_wp_nested_lfn_channel_plan_length(struct ws_generic_channel_info *ws_lcp); + bool ws_wp_nested_us_read(uint8_t *data, uint16_t length, struct ws_us_ie *us_ie); bool ws_wp_nested_bs_read(uint8_t *data, uint16_t length, struct ws_bs_ie *bs_ie); @@ -63,6 +113,11 @@ bool ws_wp_nested_pan_read(uint8_t *data, uint16_t length, struct ws_pan_informa bool ws_wp_nested_pan_version_read(uint8_t *data, uint16_t length, uint16_t *pan_version); bool ws_wp_nested_network_name_read(uint8_t *data, uint16_t length, ws_wp_network_name_t *network_name); uint8_t *ws_wp_nested_gtkhash_read(uint8_t *data, uint16_t length); +/* Wi-SUN FAN 1.1 */ +bool ws_wp_nested_pcap_read(uint8_t *data, uint16_t length, struct ws_phy_cap_info *ws_pcap_list); +bool ws_wp_nested_lfn_version_read(uint8_t *data, uint16_t length, struct ws_lfnver_ie *ws_lfnver); +bool ws_wp_nested_lgtk_hash_read(uint8_t *data, uint16_t length, struct ws_lgtkhash_ie *ws_lgtkhash); +bool ws_wp_nested_lfn_channel_plan_read(uint8_t *data, uint16_t length, struct ws_generic_channel_info *ws_lcp, uint8_t plan_tag_id); #endif /* WS_IE_LIB_H_ */ diff --git a/source/6LoWPAN/ws/ws_llc.h b/source/6LoWPAN/ws/ws_llc.h index 9e905b7bbc..da89a34959 100644 --- a/source/6LoWPAN/ws/ws_llc.h +++ b/source/6LoWPAN/ws/ws_llc.h @@ -49,13 +49,15 @@ typedef struct wh_ie_sub_list_s { * @brief wp_nested_ie_sub_list_t ws asynch Nested Payload sub IE element request list */ typedef struct wp_nested_ie_sub_list_s { - bool us_ie: 1; /**< Unicast Schedule information */ - bool bs_ie: 1; /**< Broadcast Schedule information */ - bool vp_ie: 1; /**< Vendor Payload information */ - bool pan_ie: 1; /**< PAN Information */ - bool net_name_ie: 1; /**< Network Name information */ - bool pan_version_ie: 1; /**< Pan configuration version */ - bool gtkhash_ie: 1; /**< GTK Hash information */ + bool us_ie: 1; /**< Unicast Schedule information */ + bool bs_ie: 1; /**< Broadcast Schedule information */ + bool vp_ie: 1; /**< Vendor Payload information */ + bool pan_ie: 1; /**< PAN Information */ + bool net_name_ie: 1; /**< Network Name information */ + bool pan_version_ie: 1; /**< Pan configuration version */ + bool gtkhash_ie: 1; /**< GTK Hash information */ + bool lfn_gtk_version_ie: 1; /**< LFN Version & GTK Hash */ + bool phy_cap_ie: 1; /** < Phy Cap information for MDR */ } wp_nested_ie_sub_list_t; /** @@ -124,7 +126,7 @@ typedef void ws_asynch_confirm(struct protocol_interface_info_entry *interface, * @return true when neighbor info is available * @return false when no neighbor info */ -typedef bool ws_neighbor_info_request(struct protocol_interface_info_entry *interface, const uint8_t *mac_64, llc_neighbour_req_t *neighbor_buffer, bool request_new); +typedef bool ws_neighbor_info_request(struct protocol_interface_info_entry *interface, const uint8_t *mac_64, struct llc_neighbour_req *neighbor_buffer, bool request_new); /** * @brief ws_llc_create ws LLC module create diff --git a/source/6LoWPAN/ws/ws_llc_data_service.c b/source/6LoWPAN/ws/ws_llc_data_service.c index 35e87582e7..43794ba776 100644 --- a/source/6LoWPAN/ws/ws_llc_data_service.c +++ b/source/6LoWPAN/ws/ws_llc_data_service.c @@ -34,6 +34,8 @@ #include "6LoWPAN/ws/ws_bootstrap.h" #include "6LoWPAN/ws/ws_ie_lib.h" #include "6LoWPAN/ws/ws_llc.h" +#include "6LoWPAN/ws/ws_neighbor_class.h" +#include "6LoWPAN/ws/ws_ie_lib.h" #include "6LoWPAN/ws/ws_mpx_header.h" #include "6LoWPAN/ws/ws_pae_controller.h" #include "6LoWPAN/ws/ws_cfg_settings.h" @@ -42,6 +44,7 @@ #include "Service_Libs/etx/etx.h" #include "fhss_ws_extension.h" #include "Service_Libs/random_early_detection/random_early_detection_api.h" +#include "ws_management_api.h" #ifdef HAVE_WS @@ -158,7 +161,7 @@ typedef struct { static NS_LIST_DEFINE(llc_data_base_list, llc_data_base_t, link); -static uint16_t ws_wp_nested_message_length(wp_nested_ie_sub_list_t requested_list, llc_ie_params_t *params); +static uint16_t ws_wp_nested_message_length(wp_nested_ie_sub_list_t requested_list, llc_data_base_t *llc_base); static uint16_t ws_wh_headers_length(wh_ie_sub_list_t requested_list, llc_ie_params_t *params); /** LLC message local functions */ @@ -378,9 +381,10 @@ static uint16_t ws_wh_headers_length(wh_ie_sub_list_t requested_list, llc_ie_par return length; } -static uint16_t ws_wp_nested_message_length(wp_nested_ie_sub_list_t requested_list, llc_ie_params_t *params) +static uint16_t ws_wp_nested_message_length(wp_nested_ie_sub_list_t requested_list, llc_data_base_t *llc_base) { uint16_t length = 0; + llc_ie_params_t *params = &llc_base->ie_params; if (requested_list.gtkhash_ie) { //Static 32 bytes allways length += WS_WP_SUB_IE_ELEMENT_HEADER_LENGTH + params->gtkhash_length; @@ -411,6 +415,23 @@ static uint16_t ws_wp_nested_message_length(wp_nested_ie_sub_list_t requested_li length += 2; } } +#ifdef HAVE_WS_VERSION_1_1 + if (ws_version_1_1(llc_base->interface_ptr)) { + if (requested_list.lfn_gtk_version_ie) { + + length += WS_WP_SUB_IE_ELEMENT_HEADER_LENGTH + ws_wp_nested_lfn_version_length(); + ws_lgtkhash_ie_t ws_lgtkhash; + ws_lgtkhash.lgtk0 = llc_base->interface_ptr->ws_info->lfngtk.active_hash_1; + ws_lgtkhash.lgtk1 = llc_base->interface_ptr->ws_info->lfngtk.active_hash_2; + ws_lgtkhash.lgtk2 = llc_base->interface_ptr->ws_info->lfngtk.active_hash_3; + length += WS_WP_SUB_IE_ELEMENT_HEADER_LENGTH + ws_wp_lgtk_hash_length(&ws_lgtkhash); + } + + if (requested_list.phy_cap_ie) { + length += WS_WP_SUB_IE_ELEMENT_HEADER_LENGTH + ws_wp_nested_pcap_length(llc_base->interface_ptr->ws_info->phy_cap_info.length_of_list); + } + } +#endif if (requested_list.bs_ie) { ///Dynamic length @@ -774,6 +795,11 @@ static void ws_llc_data_indication_cb(const mac_api_t *api, const mcps_data_ind_ //SET trusted state mac_neighbor_table_trusted_neighbor(mac_neighbor_info(interface), neighbor_info.neighbor, true); } + // + //Phy CAP info read and store + if (ws_version_1_1(interface)) { + ws_neighbor_class_pcap_ie_store(neighbor_info.ws_neighbor, ie_ext); + } } mcps_data_ind_t data_ind = *data; @@ -1010,6 +1036,26 @@ static void ws_llc_lowpan_mpx_header_set(llc_message_t *message, uint16_t user_i message->ie_vector_list[1].iovLen = ptr - (uint8_t *)message->ie_vector_list[1].ieBase; } +#ifdef HAVE_WS_VERSION_1_1 +uint8_t ws_llc_mdr_phy_mode_get(llc_data_base_t *base, const struct mcps_data_req_s *data) +{ + + if (!ws_version_1_1(base->interface_ptr) || !data->TxAckReq || data->msduLength < 500) { + return 0; + } + + llc_neighbour_req_t neighbor_info; + + if (!base->ws_neighbor_info_request_cb(base->interface_ptr, data->DstAddr, &neighbor_info, false)) { + return 0; + } + + return neighbor_info.ws_neighbor->phy_mode_id; +} +#else +#define ws_llc_mdr_phy_mode_get(base, data) 0 +#endif + static void ws_llc_lowpan_mpx_data_request(llc_data_base_t *base, mpx_user_t *user_cb, const struct mcps_data_req_s *data, mac_data_priority_t priority) { wh_ie_sub_list_t ie_header_mask; @@ -1038,7 +1084,7 @@ static void ws_llc_lowpan_mpx_data_request(llc_data_base_t *base, mpx_user_t *us nested_wp_id.us_ie = true; uint16_t ie_header_length = ws_wh_headers_length(ie_header_mask, &base->ie_params); - uint16_t nested_ie_length = ws_wp_nested_message_length(nested_wp_id, &base->ie_params); + uint16_t nested_ie_length = ws_wp_nested_message_length(nested_wp_id, base); uint16_t over_head_size = ie_header_length; if (nested_ie_length) { @@ -1066,6 +1112,7 @@ static void ws_llc_lowpan_mpx_data_request(llc_data_base_t *base, mpx_user_t *us ns_list_add_to_end(&base->llc_message_list, message); mcps_data_req_t data_req; + uint8_t phy_mode_id = ws_llc_mdr_phy_mode_get(base, data); message->mpx_user_handle = data->msduHandle; message->ack_requested = data->TxAckReq; if (data->TxAckReq) { @@ -1140,7 +1187,7 @@ static void ws_llc_lowpan_mpx_data_request(llc_data_base_t *base, mpx_user_t *us message->ie_ext.payloadIovLength = 0; //Set Back 2 at response handler } - base->interface_ptr->mac_api->mcps_data_req_ext(base->interface_ptr->mac_api, &data_req, &message->ie_ext, NULL, message->priority); + base->interface_ptr->mac_api->mcps_data_req_ext(base->interface_ptr->mac_api, &data_req, &message->ie_ext, NULL, message->priority, phy_mode_id); } static void ws_llc_eapol_data_req_init(mcps_data_req_t *data_req, llc_message_t *message) @@ -1187,7 +1234,7 @@ static void ws_llc_mpx_eapol_send(llc_data_base_t *base, llc_message_t *message) ns_list_add_to_end(&base->llc_message_list, message); ws_llc_eapol_data_req_init(&data_req, message); base->temp_entries->active_eapol_session = true; - base->interface_ptr->mac_api->mcps_data_req_ext(base->interface_ptr->mac_api, &data_req, &message->ie_ext, NULL, message->priority); + base->interface_ptr->mac_api->mcps_data_req_ext(base->interface_ptr->mac_api, &data_req, &message->ie_ext, NULL, message->priority, 0); } @@ -1207,7 +1254,7 @@ static void ws_llc_mpx_eapol_request(llc_data_base_t *base, mpx_user_t *user_cb, nested_wp_id.us_ie = true; uint16_t ie_header_length = ws_wh_headers_length(ie_header_mask, &base->ie_params); - uint16_t nested_ie_length = ws_wp_nested_message_length(nested_wp_id, &base->ie_params); + uint16_t nested_ie_length = ws_wp_nested_message_length(nested_wp_id, base); uint16_t over_head_size = ie_header_length; if (nested_ie_length) { @@ -1764,6 +1811,31 @@ mpx_api_t *ws_llc_mpx_api_get(struct protocol_interface_info_entry *interface) } return &base->mpx_data_base.mpx_api; } +#ifdef HAVE_WS_VERSION_1_1 + +static void ws_llc_phy_cab_list_generate(struct protocol_interface_info_entry *interface, ws_phy_cap_info_t *phy_cap) +{ + + memset(phy_cap, 0, sizeof(ws_phy_cap_info_t)); + + ws_phy_cap_info_t *prefedd_list = &interface->ws_info->phy_cap_info; + + if (!prefedd_list->length_of_list) { + return; + } + + + for (int i = 0; i < prefedd_list->length_of_list; i++) { + ws_ie_lib_phy_cap_list_update(phy_cap, &prefedd_list->pcap[i]); + } + + //Add base support + ws_pcap_ie_t base_cap = ws_ie_lib_generate_phy_cap_from_phy_mode_id(interface->ws_info->hopping_schdule.phy_mode_id); + if (base_cap.operating_mode) { + ws_ie_lib_phy_cap_list_update(phy_cap, &base_cap); + } +} +#endif int8_t ws_llc_asynch_request(struct protocol_interface_info_entry *interface, asynch_request_t *request) { @@ -1783,7 +1855,7 @@ int8_t ws_llc_asynch_request(struct protocol_interface_info_entry *interface, as request->wh_requested_ie_list.rsl_ie = false; //Never should not be a part Asynch message request->wh_requested_ie_list.vh_ie = false; uint16_t header_buffer_length = ws_wh_headers_length(request->wh_requested_ie_list, &base->ie_params); - uint16_t wp_nested_payload_length = ws_wp_nested_message_length(request->wp_requested_nested_ie_list, &base->ie_params); + uint16_t wp_nested_payload_length = ws_wp_nested_message_length(request->wp_requested_nested_ie_list, base); //Allocated uint16_t total_length = header_buffer_length; @@ -1880,9 +1952,37 @@ int8_t ws_llc_asynch_request(struct protocol_interface_info_entry *interface, as //Write Vendor spesific payload ptr = ws_wp_nested_vp_write(ptr, base->ie_params.vendor_payload, base->ie_params.vendor_payload_length); } + +#ifdef HAVE_WS_VERSION_1_1 + if (ws_version_1_1(interface)) { + if (request->wp_requested_nested_ie_list.lfn_gtk_version_ie) { + ws_lfnver_ie_t lfn_ver; + ws_lgtkhash_ie_t ws_lgtkhash; + //Write LFN Version + lfn_ver.lfn_version = interface->ws_info->lfngtk.lfn_version; + ptr = ws_wp_nested_lfn_version_write(ptr, &lfn_ver); + //Write LFN GTK Hash info + ws_lgtkhash.lgtk0 = base->interface_ptr->ws_info->lfngtk.active_hash_1; + ws_lgtkhash.lgtk1 = base->interface_ptr->ws_info->lfngtk.active_hash_2; + ws_lgtkhash.lgtk2 = base->interface_ptr->ws_info->lfngtk.active_hash_3; + ws_lgtkhash.active_lgtk_index = base->interface_ptr->ws_info->lfngtk.active_key_index; + ws_lgtkhash.lgtk0_hash = base->interface_ptr->ws_info->lfngtk.lgtkhash; + ws_lgtkhash.lgtk1_hash = base->interface_ptr->ws_info->lfngtk.lgtkhash + 8; + ws_lgtkhash.lgtk2_hash = base->interface_ptr->ws_info->lfngtk.lgtkhash + 16; + ptr = ws_wp_nested_lgtk_hash_write(ptr, &ws_lgtkhash); + } + + if (request->wp_requested_nested_ie_list.phy_cap_ie) { + ws_phy_cap_info_t phy_cap; + ws_llc_phy_cab_list_generate(base->interface_ptr, &phy_cap); + ptr = ws_wp_nested_pcap_write(ptr, &phy_cap); + } + } +#endif + } - base->interface_ptr->mac_api->mcps_data_req_ext(base->interface_ptr->mac_api, &data_req, &message->ie_ext, &request->channel_list, message->priority); + base->interface_ptr->mac_api->mcps_data_req_ext(base->interface_ptr->mac_api, &data_req, &message->ie_ext, &request->channel_list, message->priority, 0); return 0; } diff --git a/source/6LoWPAN/ws/ws_management_api.c b/source/6LoWPAN/ws/ws_management_api.c index 61c9e4b6e5..c39f6bced0 100644 --- a/source/6LoWPAN/ws/ws_management_api.c +++ b/source/6LoWPAN/ws/ws_management_api.c @@ -51,24 +51,24 @@ int ws_management_node_init( } ws_phy_cfg_t phy_cfg; - if (ws_cfg_phy_get(&phy_cfg, NULL) < 0) { + if (ws_cfg_phy_get(&phy_cfg) < 0) { return -3; } phy_cfg.regulatory_domain = regulatory_domain; - if (ws_cfg_phy_set(cur, NULL, &phy_cfg, 0) < 0) { + if (ws_cfg_phy_set(cur, &phy_cfg, 0) < 0) { return -4; } ws_gen_cfg_t gen_cfg; - if (ws_cfg_gen_get(&gen_cfg, NULL) < 0) { + if (ws_cfg_gen_get(&gen_cfg) < 0) { return -3; } strncpy(gen_cfg.network_name, network_name_ptr, 32); - if (ws_cfg_gen_set(cur, NULL, &gen_cfg, 0) < 0) { + if (ws_cfg_gen_set(cur, &gen_cfg, 0) < 0) { return -4; } @@ -93,13 +93,13 @@ int ws_management_network_name_set( } ws_gen_cfg_t cfg; - if (ws_cfg_gen_get(&cfg, NULL) < 0) { + if (ws_cfg_gen_get(&cfg) < 0) { return -3; } strncpy(cfg.network_name, network_name_ptr, 32); - if (ws_cfg_gen_set(cur, NULL, &cfg, 0) < 0) { + if (ws_cfg_gen_set(cur, &cfg, 0) < 0) { return -4; } @@ -120,7 +120,7 @@ int ws_management_network_name_get( } ws_gen_cfg_t cfg; - if (ws_cfg_gen_get(&cfg, NULL) < 0) { + if (ws_cfg_gen_get(&cfg) < 0) { return -3; } @@ -143,13 +143,13 @@ int ws_management_network_name_validate( } ws_gen_cfg_t cfg; - if (ws_cfg_gen_get(&cfg, NULL) < 0) { + if (ws_cfg_gen_get(&cfg) < 0) { return -3; } strncpy(cfg.network_name, network_name_ptr, 32); - if (ws_cfg_gen_validate(NULL, &cfg) < 0) { + if (ws_cfg_gen_validate(&cfg) < 0) { return -4; } @@ -170,7 +170,7 @@ int ws_management_domain_configuration_set( ws_phy_cfg_t cfg; ws_phy_cfg_t cfg_default; - if (ws_cfg_phy_get(&cfg, NULL) < 0) { + if (ws_cfg_phy_get(&cfg) < 0) { return -3; } @@ -196,7 +196,7 @@ int ws_management_domain_configuration_set( cfg.channel_plan_id = channel_plan_id; } - if (ws_cfg_phy_set(cur, NULL, &cfg, 0) < 0) { + if (ws_cfg_phy_set(cur, &cfg, 0) < 0) { return -4; } @@ -216,7 +216,7 @@ int ws_management_domain_configuration_get( } ws_phy_cfg_t cfg; - if (ws_cfg_phy_get(&cfg, NULL) < 0) { + if (ws_cfg_phy_get(&cfg) < 0) { return -2; } @@ -246,7 +246,7 @@ int ws_management_domain_configuration_validate( } ws_phy_cfg_t cfg; - if (ws_cfg_phy_get(&cfg, NULL) < 0) { + if (ws_cfg_phy_get(&cfg) < 0) { return -3; } @@ -254,7 +254,7 @@ int ws_management_domain_configuration_validate( cfg.phy_mode_id = phy_mode_id; cfg.channel_plan_id = channel_plan_id; - if (ws_cfg_phy_validate(NULL, &cfg) < 0) { + if (ws_cfg_phy_validate(&cfg) < 0) { return -4; } @@ -276,7 +276,7 @@ int ws_management_regulatory_domain_set( ws_phy_cfg_t cfg; ws_phy_cfg_t cfg_default; - if (ws_cfg_phy_get(&cfg, NULL) < 0) { + if (ws_cfg_phy_get(&cfg) < 0) { return -3; } @@ -300,7 +300,7 @@ int ws_management_regulatory_domain_set( cfg.operating_class = cfg_default.operating_class; } - if (ws_cfg_phy_set(cur, NULL, &cfg, 0) < 0) { + if (ws_cfg_phy_set(cur, &cfg, 0) < 0) { return -4; } @@ -323,7 +323,7 @@ int ws_management_regulatory_domain_get( } ws_phy_cfg_t cfg; - if (ws_cfg_phy_get(&cfg, NULL) < 0) { + if (ws_cfg_phy_get(&cfg) < 0) { return -3; } @@ -347,7 +347,7 @@ int ws_management_regulatory_domain_validate( } ws_phy_cfg_t cfg; - if (ws_cfg_phy_get(&cfg, NULL) < 0) { + if (ws_cfg_phy_get(&cfg) < 0) { return -3; } @@ -355,7 +355,7 @@ int ws_management_regulatory_domain_validate( cfg.operating_class = operating_class; cfg.operating_mode = operating_mode; - if (ws_cfg_phy_validate(NULL, &cfg) < 0) { + if (ws_cfg_phy_validate(&cfg) < 0) { return -4; } @@ -374,13 +374,13 @@ int ws_management_network_size_set( } ws_gen_cfg_t cfg; - if (ws_cfg_network_size_get(&cfg, NULL) < 0) { + if (ws_cfg_network_size_get(&cfg) < 0) { return -3; } cfg.network_size = network_size; - if (ws_cfg_network_size_set(cur, NULL, &cfg, 0) < 0) { + if (ws_cfg_network_size_set(cur, &cfg, 0) < 0) { return -3; } @@ -401,7 +401,7 @@ int ws_management_network_size_get( } ws_gen_cfg_t cfg; - if (ws_cfg_network_size_get(&cfg, NULL) < 0) { + if (ws_cfg_network_size_get(&cfg) < 0) { return -3; } @@ -421,13 +421,13 @@ int ws_management_network_size_validate( } ws_gen_cfg_t cfg; - if (ws_cfg_network_size_get(&cfg, NULL) < 0) { + if (ws_cfg_network_size_get(&cfg) < 0) { return -3; } cfg.network_size = network_size; - if (ws_cfg_network_size_validate(NULL, &cfg) < 0) { + if (ws_cfg_network_size_validate(&cfg) < 0) { return -4; } @@ -446,7 +446,7 @@ int ws_management_channel_mask_set( } ws_fhss_cfg_t cfg; - if (ws_cfg_fhss_get(&cfg, NULL) < 0) { + if (ws_cfg_fhss_get(&cfg) < 0) { return -2; } @@ -463,7 +463,7 @@ int ws_management_channel_mask_set( } - if (ws_cfg_fhss_set(cur, NULL, &cfg, 0) < 0) { + if (ws_cfg_fhss_set(cur, &cfg, 0) < 0) { return -3; } @@ -484,7 +484,7 @@ int ws_management_channel_mask_get( } ws_fhss_cfg_t cfg; - if (ws_cfg_fhss_get(&cfg, NULL) < 0) { + if (ws_cfg_fhss_get(&cfg) < 0) { return -2; } @@ -504,13 +504,13 @@ int ws_management_channel_mask_validate( } ws_fhss_cfg_t cfg; - if (ws_cfg_fhss_get(&cfg, NULL) < 0) { + if (ws_cfg_fhss_get(&cfg) < 0) { return -2; } memcpy(cfg.fhss_channel_mask, channel_mask, sizeof(uint32_t) * 8); - if (ws_cfg_fhss_validate(NULL, &cfg) < 0) { + if (ws_cfg_fhss_validate(&cfg) < 0) { return -4; } @@ -557,7 +557,7 @@ int ws_management_fhss_timing_configure( } ws_fhss_cfg_t cfg; - if (ws_cfg_fhss_get(&cfg, NULL) < 0) { + if (ws_cfg_fhss_get(&cfg) < 0) { return -2; } @@ -584,7 +584,7 @@ int ws_management_fhss_timing_configure( cfg.fhss_bc_dwell_interval = fhss_bc_dwell_interval; } - if (ws_cfg_fhss_set(cur, NULL, &cfg, 0) < 0) { + if (ws_cfg_fhss_set(cur, &cfg, 0) < 0) { return -3; } @@ -605,7 +605,7 @@ int ws_management_fhss_unicast_channel_function_configure( } ws_fhss_cfg_t cfg; - if (ws_cfg_fhss_get(&cfg, NULL) < 0) { + if (ws_cfg_fhss_get(&cfg) < 0) { return -2; } @@ -631,7 +631,7 @@ int ws_management_fhss_unicast_channel_function_configure( cfg.fhss_uc_fixed_channel = cfg_default.fhss_uc_fixed_channel; } - if (ws_cfg_fhss_set(cur, NULL, &cfg, 0) < 0) { + if (ws_cfg_fhss_set(cur, &cfg, 0) < 0) { return -3; } @@ -654,7 +654,7 @@ int ws_management_fhss_unicast_channel_function_get( } ws_fhss_cfg_t cfg; - if (ws_cfg_fhss_get(&cfg, NULL) < 0) { + if (ws_cfg_fhss_get(&cfg) < 0) { return -2; } @@ -678,7 +678,7 @@ int ws_management_fhss_unicast_channel_function_validate( } ws_fhss_cfg_t cfg; - if (ws_cfg_fhss_get(&cfg, NULL) < 0) { + if (ws_cfg_fhss_get(&cfg) < 0) { return -2; } @@ -686,7 +686,7 @@ int ws_management_fhss_unicast_channel_function_validate( cfg.fhss_uc_channel_function = channel_function; cfg.fhss_uc_fixed_channel = fixed_channel; - if (ws_cfg_fhss_validate(NULL, &cfg) < 0) { + if (ws_cfg_fhss_validate(&cfg) < 0) { return -4; } @@ -708,7 +708,7 @@ int ws_management_fhss_broadcast_channel_function_configure( } ws_fhss_cfg_t cfg; - if (ws_cfg_fhss_get(&cfg, NULL) < 0) { + if (ws_cfg_fhss_get(&cfg) < 0) { return -2; } ws_fhss_cfg_t cfg_default; @@ -740,7 +740,7 @@ int ws_management_fhss_broadcast_channel_function_configure( cfg.fhss_bc_fixed_channel = cfg_default.fhss_bc_fixed_channel; } - if (ws_cfg_fhss_set(cur, NULL, &cfg, 0) < 0) { + if (ws_cfg_fhss_set(cur, &cfg, 0) < 0) { return -3; } @@ -764,7 +764,7 @@ int ws_management_fhss_broadcast_channel_function_get( } ws_fhss_cfg_t cfg; - if (ws_cfg_fhss_get(&cfg, NULL) < 0) { + if (ws_cfg_fhss_get(&cfg) < 0) { return -2; } @@ -790,7 +790,7 @@ int ws_management_fhss_broadcast_channel_function_validate( } ws_fhss_cfg_t cfg; - if (ws_cfg_fhss_get(&cfg, NULL) < 0) { + if (ws_cfg_fhss_get(&cfg) < 0) { return -2; } @@ -799,7 +799,7 @@ int ws_management_fhss_broadcast_channel_function_validate( cfg.fhss_bc_channel_function = channel_function; cfg.fhss_bc_fixed_channel = fixed_channel; - if (ws_cfg_fhss_validate(NULL, &cfg) < 0) { + if (ws_cfg_fhss_validate(&cfg) < 0) { return -4; } @@ -821,7 +821,7 @@ int ws_management_timing_parameters_set( } ws_timing_cfg_t cfg; - if (ws_cfg_timing_get(&cfg, NULL) < 0) { + if (ws_cfg_timing_get(&cfg) < 0) { return -2; } @@ -854,7 +854,7 @@ int ws_management_timing_parameters_set( cfg.pan_timeout = cfg_default.pan_timeout;; } - if (ws_cfg_timing_set(cur, NULL, &cfg, 0) < 0) { + if (ws_cfg_timing_set(cur, &cfg, 0) < 0) { return -3; } @@ -878,7 +878,7 @@ int ws_management_timing_parameters_get( } ws_timing_cfg_t cfg; - if (ws_cfg_timing_get(&cfg, NULL) < 0) { + if (ws_cfg_timing_get(&cfg) < 0) { return -2; } @@ -904,7 +904,7 @@ int ws_management_timing_parameters_validate( } ws_timing_cfg_t cfg; - if (ws_cfg_timing_get(&cfg, NULL) < 0) { + if (ws_cfg_timing_get(&cfg) < 0) { return -2; } @@ -913,7 +913,7 @@ int ws_management_timing_parameters_validate( cfg.disc_trickle_k = disc_trickle_k; cfg.pan_timeout = pan_timeout; - if (ws_cfg_timing_validate(NULL, &cfg) < 0) { + if (ws_cfg_timing_validate(&cfg) < 0) { return -4; } @@ -957,4 +957,33 @@ int ws_device_min_sens_set( return 0; } +int ws_management_phy_capability_set( + int8_t interface_id, + ws_management_pcap_info_t *pcap_list) +{ +#ifdef HAVE_WS_VERSION_1_1 + protocol_interface_info_entry_t *cur; + cur = protocol_stack_interface_info_get_by_id(interface_id); + if (!cur || !ws_info(cur) || pcap_list->length_of_list > 7) { + return -1; + } + + //Set supported configure for MDR + //TODO add validation for Phy_type and operation modes + cur->ws_info->phy_cap_info.length_of_list = pcap_list->length_of_list; + for (int i = 0; i < pcap_list->length_of_list; i++) { + cur->ws_info->phy_cap_info.pcap[i].phy_type = pcap_list->pcap[i].phy_type; + cur->ws_info->phy_cap_info.pcap[i].operating_mode = pcap_list->pcap[i].operating_mode; + } + + return 0; + +#else + (void)interface_id; + (void)pcap_list; + return -1; +#endif +} + + #endif // HAVE_WS diff --git a/source/6LoWPAN/ws/ws_neighbor_class.c b/source/6LoWPAN/ws/ws_neighbor_class.c index 20d29cbc4d..3cd07e5e5f 100644 --- a/source/6LoWPAN/ws/ws_neighbor_class.c +++ b/source/6LoWPAN/ws/ws_neighbor_class.c @@ -26,7 +26,9 @@ #include "6LoWPAN/ws/ws_config.h" #include "6LoWPAN/ws/ws_neighbor_class.h" #include "6LoWPAN/ws/ws_common.h" +#include "6LoWPAN/ws/ws_ie_lib.h" #include "ws_management_api.h" +#include "mac_api.h" #ifdef HAVE_WS @@ -168,7 +170,7 @@ static void ws_neighbour_excluded_mask_by_range(ws_channel_mask_t *channel_info, if (channel >= range_start && channel <= range_stop) { //Cut channel - compare_mask_bit = 1 << (channel % 32); + compare_mask_bit = 1U << (channel % 32); mask_index = 0 + (channel / 32); if (channel_info->channel_mask[mask_index] & compare_mask_bit) { @@ -187,7 +189,7 @@ static uint32_t ws_reserve_order_32_bit(uint32_t value) uint32_t ret_val = 0; for (uint8_t i = 0; i < 32; i++) { if ((value & (1 << i))) { - ret_val |= 1 << ((32 - 1) - i); + ret_val |= 1U << ((32 - 1) - i); } } return ret_val; @@ -258,21 +260,23 @@ void ws_neighbor_class_neighbor_unicast_schedule_set(ws_neighbor_class_entry_t * } else if (ws_us->channel_plan == 1) { ws_neighbor->fhss_data.uc_timing_info.unicast_number_of_channels = ws_us->plan.one.number_of_channel; + } else if (ws_us->channel_plan == 2) { + //TODO add Channel plan 2 channel count function call here } //Handle excluded channel and generate activate channel list if (ws_us->excluded_channel_ctrl == WS_EXC_CHAN_CTRL_RANGE) { - ws_generate_channel_list(ws_neighbor->fhss_data.uc_channel_list.channel_mask, ws_neighbor->fhss_data.uc_timing_info.unicast_number_of_channels, own_shedule->regulatory_domain, own_shedule->operating_class, own_shedule->channel_plan_id); - ws_neighbor->fhss_data.uc_channel_list.channel_count = ws_active_channel_count(ws_neighbor->fhss_data.uc_channel_list.channel_mask, ws_neighbor->fhss_data.uc_timing_info.unicast_number_of_channels); + ws_common_generate_channel_list(ws_neighbor->fhss_data.uc_channel_list.channel_mask, ws_neighbor->fhss_data.uc_timing_info.unicast_number_of_channels, own_shedule->regulatory_domain, own_shedule->operating_class, own_shedule->channel_plan_id); + ws_neighbor->fhss_data.uc_channel_list.channel_count = ws_common_active_channel_count(ws_neighbor->fhss_data.uc_channel_list.channel_mask, ws_neighbor->fhss_data.uc_timing_info.unicast_number_of_channels); ws_neighbour_excluded_mask_by_range(&ws_neighbor->fhss_data.uc_channel_list, &ws_us->excluded_channels.range, ws_neighbor->fhss_data.uc_timing_info.unicast_number_of_channels); } else if (ws_us->excluded_channel_ctrl == WS_EXC_CHAN_CTRL_BITMASK) { - ws_generate_channel_list(ws_neighbor->fhss_data.uc_channel_list.channel_mask, ws_neighbor->fhss_data.uc_timing_info.unicast_number_of_channels, own_shedule->regulatory_domain, own_shedule->operating_class, own_shedule->channel_plan_id); - ws_neighbor->fhss_data.uc_channel_list.channel_count = ws_active_channel_count(ws_neighbor->fhss_data.uc_channel_list.channel_mask, ws_neighbor->fhss_data.uc_timing_info.unicast_number_of_channels); + ws_common_generate_channel_list(ws_neighbor->fhss_data.uc_channel_list.channel_mask, ws_neighbor->fhss_data.uc_timing_info.unicast_number_of_channels, own_shedule->regulatory_domain, own_shedule->operating_class, own_shedule->channel_plan_id); + ws_neighbor->fhss_data.uc_channel_list.channel_count = ws_common_active_channel_count(ws_neighbor->fhss_data.uc_channel_list.channel_mask, ws_neighbor->fhss_data.uc_timing_info.unicast_number_of_channels); ws_neighbour_excluded_mask_by_mask(&ws_neighbor->fhss_data.uc_channel_list, &ws_us->excluded_channels.mask, ws_neighbor->fhss_data.uc_timing_info.unicast_number_of_channels); } else if (ws_us->excluded_channel_ctrl == WS_EXC_CHAN_CTRL_NONE) { if (ws_neighbor->fhss_data.uc_timing_info.unicast_number_of_channels != ws_neighbor->fhss_data.uc_channel_list.channel_count) { - ws_generate_channel_list(ws_neighbor->fhss_data.uc_channel_list.channel_mask, ws_neighbor->fhss_data.uc_timing_info.unicast_number_of_channels, own_shedule->regulatory_domain, own_shedule->operating_class, own_shedule->channel_plan_id); - ws_neighbor->fhss_data.uc_channel_list.channel_count = ws_active_channel_count(ws_neighbor->fhss_data.uc_channel_list.channel_mask, ws_neighbor->fhss_data.uc_timing_info.unicast_number_of_channels); + ws_common_generate_channel_list(ws_neighbor->fhss_data.uc_channel_list.channel_mask, ws_neighbor->fhss_data.uc_timing_info.unicast_number_of_channels, own_shedule->regulatory_domain, own_shedule->operating_class, own_shedule->channel_plan_id); + ws_neighbor->fhss_data.uc_channel_list.channel_count = ws_common_active_channel_count(ws_neighbor->fhss_data.uc_channel_list.channel_mask, ws_neighbor->fhss_data.uc_timing_info.unicast_number_of_channels); } } @@ -391,6 +395,13 @@ bool ws_neighbor_class_neighbor_duplicate_packet_check(ws_neighbor_class_entry_t return true; } +#ifdef HAVE_WS_VERSION_1_1 +void ws_neighbor_class_pcap_ie_store(struct ws_neighbor_class_entry *ws_neighbor, const struct mcps_data_ie_list *ie_ext) +{ + ws_wp_nested_pcap_read(ie_ext->payloadIeList, ie_ext->payloadIeListLength, &ws_neighbor->pcap_info); +} +#endif + #endif /* HAVE_WS */ diff --git a/source/6LoWPAN/ws/ws_neighbor_class.h b/source/6LoWPAN/ws/ws_neighbor_class.h index 1bb82adb28..5fe7c19b67 100644 --- a/source/6LoWPAN/ws/ws_neighbor_class.h +++ b/source/6LoWPAN/ws/ws_neighbor_class.h @@ -21,6 +21,8 @@ #include "fhss_ws_extension.h" #include "6LoWPAN/ws/ws_common_defines.h" +struct mcps_data_ie_list; + #define RSL_UNITITIALIZED 0x7fff typedef struct ws_neighbor_class_entry { @@ -34,6 +36,10 @@ typedef struct ws_neighbor_class_entry { bool broadcast_shedule_info_stored: 1; bool synch_done : 1; bool unicast_data_rx : 1; +#ifdef HAVE_WS_VERSION_1_1 + uint8_t phy_mode_id; /*!< Bootstrap configured Preference Phy mode for MDR */ + ws_phy_cap_info_t pcap_info; +#endif } ws_neighbor_class_entry_t; /** @@ -182,5 +188,10 @@ void ws_neighbor_class_rsl_in_calculate(ws_neighbor_class_entry_t *ws_neighbor, void ws_neighbor_class_rsl_out_calculate(ws_neighbor_class_entry_t *ws_neighbor, uint8_t rsl_reported); bool ws_neighbor_class_neighbor_duplicate_packet_check(ws_neighbor_class_entry_t *ws_neighbor, uint8_t mac_dsn, uint32_t rx_timestamp); +#ifdef HAVE_WS_VERSION_1_1 +void ws_neighbor_class_pcap_ie_store(ws_neighbor_class_entry_t *ws_neighbor, const struct mcps_data_ie_list *ie_ext); +#else +#define ws_neighbor_class_pcap_ie_store(ws_neighbor, ie_ext) ((void)0) +#endif #endif /* WS_NEIGHBOR_CLASS_H_ */ diff --git a/source/6LoWPAN/ws/ws_pae_auth.c b/source/6LoWPAN/ws/ws_pae_auth.c index da2c3cf104..fa6b66da4b 100644 --- a/source/6LoWPAN/ws/ws_pae_auth.c +++ b/source/6LoWPAN/ws/ws_pae_auth.c @@ -80,6 +80,13 @@ // Short GTK lifetime value, for GTK install check #define SHORT_GTK_LIFETIME 10 * 3600 // 10 hours +// Frame counter exhaust check timer +#define FRAME_CNT_TIMER 3600 + +#define SECONDS_IN_DAY (3600 * 24) +#define TIME_MINIMUM_DIFFERENCE 5 +#define TIME_DIFFERENCE_THRESHOLD 3600 + typedef struct { ns_list_link_t link; /**< Link */ uint16_t pan_id; /**< PAN ID */ @@ -93,6 +100,7 @@ typedef struct { ws_pae_auth_nw_info_updated *nw_info_updated; /**< Security keys network info updated callback */ ws_pae_auth_ip_addr_get *ip_addr_get; /**< IP address get callback */ ws_pae_auth_congestion_get *congestion_get; /**< Congestion get callback */ + ws_pae_auth_nw_frame_counter_read *nw_frame_cnt_read; /**< Network frame counter read callback */ supp_list_t active_supp_list; /**< List of active supplicants */ supp_list_t waiting_supp_list; /**< List of waiting supplicants */ shared_comp_list_t shared_comp_list; /**< Shared component list */ @@ -101,13 +109,20 @@ typedef struct { const sec_prot_certs_t *certs; /**< Certificates */ sec_prot_keys_nw_info_t *sec_keys_nw_info; /**< Security keys network information */ sec_cfg_t *sec_cfg; /**< Security configuration */ + frame_counters_t *frame_counters; /**< Frame counters */ + uint64_t prev_system_time; /**< Previous system time */ + uint64_t system_time_diff; /**< System time diffence */ + uint32_t prev_frame_cnt; /**< Previous frame counter */ + uint16_t prev_frame_cnt_timer; /**< Previous frame counter timer */ uint16_t supp_max_number; /**< Max number of stored supplicants */ uint16_t waiting_supp_list_size; /**< Waiting supplicants list size */ uint8_t relay_socked_msg_if_instance_id; /**< Relay socket message interface instance identifier */ uint8_t radius_socked_msg_if_instance_id; /**< Radius socket message interface instance identifier */ bool timer_running : 1; /**< Timer is running */ bool gtk_new_inst_req_exp : 1; /**< GTK new install required timer expired */ - bool gtk_new_act_time_exp: 1; /**< GTK new activation time expired */ + bool gtk_new_act_time_exp : 1; /**< GTK new activation time expired */ + bool prev_system_time_set : 1; /**< Previous system time set */ + bool prev_frame_cnt_set : 1; /**< Previous frame counter set */ } pae_auth_t; static int8_t ws_pae_auth_network_keys_from_gtks_set(pae_auth_t *pae_auth, bool force_install); @@ -118,6 +133,8 @@ static pae_auth_t *ws_pae_auth_get(protocol_interface_info_entry_t *interface_pt static pae_auth_t *ws_pae_auth_by_kmp_service_get(kmp_service_t *service); static int8_t ws_pae_auth_event_send(kmp_service_t *service, void *data); static void ws_pae_auth_tasklet_handler(arm_event_s *event); +static uint32_t ws_pae_auth_lifetime_key_frame_cnt_check(pae_auth_t *pae_auth, uint8_t gtk_index, uint16_t seconds); +static uint32_t ws_pae_auth_lifetime_system_time_check(pae_auth_t *pae_auth, int8_t gtk_index, uint16_t seconds, uint32_t dec_extra_seconds); static void ws_pae_auth_gtk_key_insert(pae_auth_t *pae_auth); static int8_t ws_pae_auth_new_gtk_activate(pae_auth_t *pae_auth); static int8_t ws_pae_auth_timer_if_start(kmp_service_t *service, kmp_api_t *kmp); @@ -145,9 +162,9 @@ static void ws_pae_auth_waiting_supp_deleted(void *pae_auth); static int8_t tasklet_id = -1; static NS_LIST_DEFINE(pae_auth_list, pae_auth_t, link); -int8_t ws_pae_auth_init(protocol_interface_info_entry_t *interface_ptr, sec_prot_gtk_keys_t *next_gtks, const sec_prot_certs_t *certs, sec_cfg_t *sec_cfg, sec_prot_keys_nw_info_t *sec_keys_nw_info) +int8_t ws_pae_auth_init(protocol_interface_info_entry_t *interface_ptr, sec_prot_gtk_keys_t *next_gtks, const sec_prot_certs_t *certs, sec_cfg_t *sec_cfg, sec_prot_keys_nw_info_t *sec_keys_nw_info, frame_counters_t *frame_counters) { - if (!interface_ptr || !next_gtks || !certs || !sec_cfg || !sec_keys_nw_info) { + if (!interface_ptr || !next_gtks || !certs || !sec_cfg || !sec_keys_nw_info || !frame_counters) { return -1; } @@ -175,16 +192,24 @@ int8_t ws_pae_auth_init(protocol_interface_info_entry_t *interface_ptr, sec_prot pae_auth->nw_info_updated = NULL; pae_auth->ip_addr_get = NULL; pae_auth->congestion_get = NULL; + pae_auth->nw_frame_cnt_read = NULL; pae_auth->next_gtks = next_gtks; pae_auth->certs = certs; pae_auth->sec_keys_nw_info = sec_keys_nw_info; pae_auth->sec_cfg = sec_cfg; + pae_auth->frame_counters = frame_counters; + pae_auth->prev_system_time = 0; + pae_auth->system_time_diff = 0; + pae_auth->prev_frame_cnt = 0; + pae_auth->prev_frame_cnt_timer = FRAME_CNT_TIMER; pae_auth->supp_max_number = SUPPLICANT_MAX_NUMBER; pae_auth->waiting_supp_list_size = 0; pae_auth->gtk_new_inst_req_exp = false; pae_auth->gtk_new_act_time_exp = false; + pae_auth->prev_frame_cnt_set = false; + pae_auth->prev_system_time_set = false; pae_auth->relay_socked_msg_if_instance_id = 0; pae_auth->radius_socked_msg_if_instance_id = 0; @@ -316,7 +341,7 @@ int8_t ws_pae_auth_delete(protocol_interface_info_entry_t *interface_ptr) return 0; } -void ws_pae_auth_cb_register(protocol_interface_info_entry_t *interface_ptr, ws_pae_auth_gtk_hash_set *hash_set, ws_pae_auth_nw_key_insert *nw_key_insert, ws_pae_auth_nw_key_index_set *nw_key_index_set, ws_pae_auth_nw_info_updated *nw_info_updated, ws_pae_auth_ip_addr_get *ip_addr_get, ws_pae_auth_congestion_get *congestion_get) +void ws_pae_auth_cb_register(protocol_interface_info_entry_t *interface_ptr, ws_pae_auth_gtk_hash_set *hash_set, ws_pae_auth_nw_key_insert *nw_key_insert, ws_pae_auth_nw_key_index_set *nw_key_index_set, ws_pae_auth_nw_info_updated *nw_info_updated, ws_pae_auth_ip_addr_get *ip_addr_get, ws_pae_auth_congestion_get *congestion_get, ws_pae_auth_nw_frame_counter_read *nw_frame_cnt_read) { if (!interface_ptr) { return; @@ -333,6 +358,7 @@ void ws_pae_auth_cb_register(protocol_interface_info_entry_t *interface_ptr, ws_ pae_auth->nw_info_updated = nw_info_updated; pae_auth->ip_addr_get = ip_addr_get; pae_auth->congestion_get = congestion_get; + pae_auth->nw_frame_cnt_read = nw_frame_cnt_read; } void ws_pae_auth_start(protocol_interface_info_entry_t *interface_ptr) @@ -364,6 +390,9 @@ void ws_pae_auth_start(protocol_interface_info_entry_t *interface_ptr) // Sets active key index ws_pae_auth_network_key_index_set(pae_auth, index); + + pae_auth->prev_system_time = ws_pae_current_time_get(); + pae_auth->prev_system_time_set = true; } void ws_pae_auth_gtks_updated(protocol_interface_info_entry_t *interface_ptr) @@ -734,7 +763,12 @@ void ws_pae_auth_slow_timer(uint16_t seconds) if (!sec_prot_keys_gtk_is_set(pae_auth->sec_keys_nw_info->gtks, i)) { continue; } - uint32_t timer_seconds = sec_prot_keys_gtk_lifetime_decrement(pae_auth->sec_keys_nw_info->gtks, i, current_time, seconds, true); + uint32_t gtk_lifetime_dec_extra_seconds = 0; + if (active_index == i) { + gtk_lifetime_dec_extra_seconds = ws_pae_auth_lifetime_key_frame_cnt_check(pae_auth, i, seconds); + gtk_lifetime_dec_extra_seconds = ws_pae_auth_lifetime_system_time_check(pae_auth, i, seconds, gtk_lifetime_dec_extra_seconds); + } + uint32_t timer_seconds = sec_prot_keys_gtk_lifetime_decrement(pae_auth->sec_keys_nw_info->gtks, i, current_time, seconds + gtk_lifetime_dec_extra_seconds, true); if (active_index == i) { if (!pae_auth->gtk_new_inst_req_exp) { pae_auth->gtk_new_inst_req_exp = ws_pae_timers_gtk_new_install_required(pae_auth->sec_cfg, timer_seconds); @@ -766,6 +800,10 @@ void ws_pae_auth_slow_timer(uint16_t seconds) pae_auth->nw_info_updated(pae_auth->interface_ptr); } } + if (gtk_lifetime_dec_extra_seconds != 0) { + // Update keys to NVM as needed + pae_auth->nw_info_updated(pae_auth->interface_ptr); + } } if (timer_seconds == 0) { @@ -786,6 +824,159 @@ void ws_pae_auth_slow_timer(uint16_t seconds) ws_pae_key_storage_timer(seconds); } +static uint32_t ws_pae_auth_lifetime_key_frame_cnt_check(pae_auth_t *pae_auth, uint8_t gtk_index, uint16_t seconds) +{ + uint32_t decrement_seconds = 0; + + if (pae_auth->prev_frame_cnt_timer > seconds) { + pae_auth->prev_frame_cnt_timer -= seconds; + return 0; + } + pae_auth->prev_frame_cnt_timer = FRAME_CNT_TIMER; + + uint32_t frame_cnt = 0; + if (pae_auth->nw_frame_cnt_read(pae_auth->interface_ptr, &frame_cnt, gtk_index) < 0) { + return 0; + } + + sec_timer_cfg_t *timer_cfg = &pae_auth->sec_cfg->timer_cfg; + + // For GTK lifetime and frame counter space calculate the percent that has been used + uint32_t gtk_lifetime_left = sec_prot_keys_gtk_lifetime_get(pae_auth->sec_keys_nw_info->gtks, gtk_index); + uint32_t gtk_lifetime = timer_cfg->gtk_expire_offset; + uint32_t gtk_lifetime_left_percent = gtk_lifetime_left * 100 / gtk_lifetime; + + uint32_t frame_cnt_left_percent = ((uint64_t)((UINT32_MAX - frame_cnt))) * 100 / UINT32_MAX; + + tr_info("Active GTK lifetime %"PRIu32", frame counter %"PRIu32" percent, counter %"PRIu32, gtk_lifetime_left_percent, frame_cnt_left_percent, frame_cnt); + + /* If frame counter space has been exhausted faster than should be based on GTK lifetime + * decrements GTK lifetime. Do not check until 20% of the frame counter space has been used + * so that we have data from longer time period. As sanity check, validate that GTK lifetime + * is not more than 105% of the GTK lifetime. + */ + uint32_t gtk_new_install_req_seconds = timer_cfg->gtk_expire_offset - timer_cfg->gtk_new_install_req * timer_cfg->gtk_expire_offset / 100; + if ((frame_cnt_left_percent < gtk_lifetime_left_percent && frame_cnt_left_percent < 80) || + gtk_lifetime_left_percent > 105) { + // If not yet on GTK update period + if (gtk_lifetime_left > (gtk_new_install_req_seconds + SECONDS_IN_DAY)) { + uint32_t diff = gtk_lifetime_left_percent - frame_cnt_left_percent; + decrement_seconds = gtk_lifetime * diff / 100 + SECONDS_IN_DAY; + if (decrement_seconds > gtk_lifetime_left - gtk_new_install_req_seconds) { + decrement_seconds = gtk_lifetime_left - gtk_new_install_req_seconds; + } + tr_info("Decrement GTK lifetime percent, seconds %"PRIu32, decrement_seconds); + } + } + + // Calculate how much frame counters have changed and store maximum if larger than previous maximum + uint32_t frame_cnt_diff = 0; + if (pae_auth->prev_frame_cnt_set && frame_cnt > pae_auth->prev_frame_cnt) { + frame_cnt_diff = frame_cnt - pae_auth->prev_frame_cnt; + if (frame_cnt_diff > pae_auth->frame_counters->counter[gtk_index].max_frame_counter_chg) { + pae_auth->frame_counters->counter[gtk_index].max_frame_counter_chg = frame_cnt_diff; + } + } + + tr_info("Frame counter change %"PRIu32", max %"PRIu32, frame_cnt_diff, pae_auth->frame_counters->counter[gtk_index].max_frame_counter_chg); + + /* Calculates an estimate for how much free frame counter space is needed for the GTK update and + * initiates it faster if needed (default length of GTK update is 6 days). + */ + uint32_t max_needed_frame_counters = + pae_auth->frame_counters->counter[gtk_index].max_frame_counter_chg * gtk_new_install_req_seconds / 3600; + // Adds 20% to calculated value + max_needed_frame_counters = max_needed_frame_counters * 120 / 100; + // If estimated value is more than is left starts GTK update right away (if not already started) + if (max_needed_frame_counters >= (UINT32_MAX - frame_cnt)) { + if (gtk_lifetime_left > gtk_new_install_req_seconds) { + decrement_seconds = gtk_lifetime_left - gtk_new_install_req_seconds; + tr_info("Decrement GTK lifetime update, seconds %"PRIu32, decrement_seconds); + } + } + + /* Calculates an estimate for how much free frame counter space is needed for the GTK activation and + * initiates it faster if needed (default length of GTK activation is 60 minutes). + */ + uint32_t gtk_new_activation_time_seconds = timer_cfg->gtk_expire_offset / timer_cfg->gtk_new_act_time; + // Calculates the estimated maximum value for frame counter during GTK update + max_needed_frame_counters = + pae_auth->frame_counters->counter[gtk_index].max_frame_counter_chg * gtk_new_activation_time_seconds / 3600; + // Adds 200% to calculated value + max_needed_frame_counters = max_needed_frame_counters * 300 / 100; + // If estimated value is more than is left starts GTK update right away (if not already started) + if (max_needed_frame_counters >= (UINT32_MAX - frame_cnt)) { + if (gtk_lifetime_left > gtk_new_activation_time_seconds) { + decrement_seconds = gtk_lifetime_left - gtk_new_activation_time_seconds; + tr_info("Decrement GTK lifetime activation, seconds %"PRIu32, decrement_seconds); + } + } + + pae_auth->prev_frame_cnt = frame_cnt; + pae_auth->prev_frame_cnt_set = true; + + return decrement_seconds; +} + +static uint32_t ws_pae_auth_lifetime_system_time_check(pae_auth_t *pae_auth, int8_t gtk_index, uint16_t seconds, uint32_t dec_extra_seconds) +{ + // Read current system time and compare it to previous time + uint64_t current_time = ws_pae_current_time_get(); + if (pae_auth->prev_system_time_set) { + if (current_time > pae_auth->prev_system_time + TIME_MINIMUM_DIFFERENCE) { + pae_auth->system_time_diff += current_time - pae_auth->prev_system_time; + } + } + pae_auth->prev_system_time = current_time; + pae_auth->prev_system_time_set = true; + + uint64_t time_diff = 0; + // Update lifetimes only if time difference is more than hour + if (pae_auth->system_time_diff > TIME_DIFFERENCE_THRESHOLD + seconds + dec_extra_seconds) { + time_diff = pae_auth->system_time_diff - seconds - dec_extra_seconds; + } else { + return dec_extra_seconds; + } + pae_auth->system_time_diff = 0; + + uint32_t new_dec_extra_seconds = dec_extra_seconds; + + if (time_diff > 0) { + /* If the system time has made a large jump then use the stored time to calculate the lifetime + (this implies e.g. that new time has been received from NTP and old time was not valid) */ + if (!ws_pae_time_old_and_new_validate(current_time, current_time + time_diff)) { + // Allow one jump without invalidating active GTK + if (pae_auth->sec_keys_nw_info->system_time_changed == SYSTEM_TIME_NOT_CHANGED) { + pae_auth->sec_keys_nw_info->system_time_changed = SYSTEM_TIME_CHANGED; + tr_info("System time large change ignored; difference: %"PRIu64, time_diff); + time_diff = 0; + } + } + + uint32_t gtk_lifetime_left = sec_prot_keys_gtk_lifetime_get(pae_auth->sec_keys_nw_info->gtks, gtk_index); + sec_timer_cfg_t *timer_cfg = &pae_auth->sec_cfg->timer_cfg; + uint32_t gtk_new_activation_time_seconds = timer_cfg->gtk_expire_offset / timer_cfg->gtk_new_act_time; + + // If there is GTK lifetime left + if (gtk_lifetime_left > (seconds + dec_extra_seconds + time_diff)) { + // If GTK lifetime would be less than new activation time sets decrements time to activation time + if (gtk_lifetime_left - seconds - dec_extra_seconds - time_diff < gtk_new_activation_time_seconds) { + new_dec_extra_seconds = gtk_lifetime_left - gtk_new_activation_time_seconds; + } else { + // Decrements GTK lifetime + new_dec_extra_seconds = dec_extra_seconds + time_diff; + } + } else { + // If there is no GTK lifetime left decrements time to activation time + new_dec_extra_seconds = gtk_lifetime_left - gtk_new_activation_time_seconds; + } + + tr_info("System change difference: %"PRIu64" decrement extra: %"PRIu32" (seconds: %"PRIu16" previous extra %"PRIu32")", time_diff, new_dec_extra_seconds, seconds, dec_extra_seconds); + } + + return new_dec_extra_seconds; +} + static void ws_pae_auth_gtk_key_insert(pae_auth_t *pae_auth) { // Gets index to install the key @@ -962,27 +1153,36 @@ static bool ws_pae_auth_active_limit_reached(uint16_t active_supp, pae_auth_t *p return pae_auth->congestion_get(pae_auth->interface_ptr, active_supp); } +static void ws_pae_auth_waiting_supp_remove_oldest(pae_auth_t *pae_auth, const kmp_addr_t *addr) +{ + supp_entry_t *delete_supp = ns_list_get_last(&pae_auth->waiting_supp_list); + if (!delete_supp) { + return; + } + tr_info("PAE: waiting list full, eui-64: %s, deleted eui-64: %s", trace_array(addr->eui_64, 8), trace_array(delete_supp->addr.eui_64, 8)); + // Create new instance + kmp_api_t *new_kmp = ws_pae_auth_kmp_create_and_start(pae_auth->kmp_service, MSG_PROT, pae_auth->relay_socked_msg_if_instance_id, delete_supp, pae_auth->sec_cfg); + if (!new_kmp) { + return; + } + kmp_api_create_request(new_kmp, MSG_PROT, &delete_supp->addr, &delete_supp->sec_keys); + (void) ws_pae_lib_supp_list_remove(pae_auth, &pae_auth->waiting_supp_list, delete_supp, ws_pae_auth_waiting_supp_deleted); +} + static supp_entry_t *ws_pae_auth_waiting_supp_list_add(pae_auth_t *pae_auth, supp_entry_t *supp_entry, const kmp_addr_t *addr) { // Entry is already allocated if (supp_entry) { + // If the waiting list if full removes the oldest entry from the list + if (pae_auth->waiting_supp_list_size >= WAITING_SUPPLICANT_LIST_MAX_SIZE) { + ws_pae_auth_waiting_supp_remove_oldest(pae_auth, addr); + } ns_list_add_to_start(&pae_auth->waiting_supp_list, supp_entry); pae_auth->waiting_supp_list_size++; } else { // If the waiting list if full removes the oldest entry from the list if (pae_auth->waiting_supp_list_size >= WAITING_SUPPLICANT_LIST_MAX_SIZE) { - supp_entry_t *delete_supp = ns_list_get_last(&pae_auth->waiting_supp_list); - if (!delete_supp) { - return NULL; - } - tr_info("PAE: waiting list full, eui-64: %s, deleted eui-64: %s", trace_array(addr->eui_64, 8), trace_array(delete_supp->addr.eui_64, 8)); - // Create new instance - kmp_api_t *new_kmp = ws_pae_auth_kmp_create_and_start(pae_auth->kmp_service, MSG_PROT, pae_auth->relay_socked_msg_if_instance_id, delete_supp, pae_auth->sec_cfg); - if (!new_kmp) { - return NULL; - } - kmp_api_create_request(new_kmp, MSG_PROT, &delete_supp->addr, &delete_supp->sec_keys); - (void) ws_pae_lib_supp_list_remove(pae_auth, &pae_auth->waiting_supp_list, delete_supp, ws_pae_auth_waiting_supp_deleted); + ws_pae_auth_waiting_supp_remove_oldest(pae_auth, addr); } supp_entry = ws_pae_lib_supp_list_add(&pae_auth->waiting_supp_list, addr); if (!supp_entry) { diff --git a/source/6LoWPAN/ws/ws_pae_auth.h b/source/6LoWPAN/ws/ws_pae_auth.h index 4b6dd07432..8abfe1e970 100644 --- a/source/6LoWPAN/ws/ws_pae_auth.h +++ b/source/6LoWPAN/ws/ws_pae_auth.h @@ -48,12 +48,13 @@ * \param timer_settings timer settings * \param sec_cfg security configuration * \param sec_keys_nw_info security keys network information + * \param frame_counters frame counters * * \return < 0 failure * \return >= 0 success * */ -int8_t ws_pae_auth_init(protocol_interface_info_entry_t *interface_ptr, sec_prot_gtk_keys_t *next_gtks, const sec_prot_certs_t *certs, sec_cfg_t *sec_cfg, sec_prot_keys_nw_info_t *sec_keys_nw_info); +int8_t ws_pae_auth_init(protocol_interface_info_entry_t *interface_ptr, sec_prot_gtk_keys_t *next_gtks, const sec_prot_certs_t *certs, sec_cfg_t *sec_cfg, sec_prot_keys_nw_info_t *sec_keys_nw_info, frame_counters_t *frame_counters); /** * ws_pae_auth_addresses_set set relay addresses @@ -260,6 +261,19 @@ typedef void ws_pae_auth_ip_addr_get(protocol_interface_info_entry_t *interface_ */ typedef bool ws_pae_auth_congestion_get(protocol_interface_info_entry_t *interface_ptr, uint16_t active_supp); +/** + * ws_pae_auth_nw_frame_counter_read network frame counter read callback + * + * \param interface_ptr interface + * \param counter frame counter + * \param gtk_index GTK index + * + * \return < 0 failure + * \return >= 0 success + * + */ +typedef int8_t ws_pae_auth_nw_frame_counter_read(protocol_interface_info_entry_t *interface_ptr, uint32_t *counter, uint8_t gtk_index); + /** * ws_pae_auth_cb_register register PAE authenticator callbacks * @@ -270,17 +284,18 @@ typedef bool ws_pae_auth_congestion_get(protocol_interface_info_entry_t *interfa * \param nw_info_updated network keys updated callback * \param ip_addr_get IP addressing information callback * \param congestion_get congestion get callback + * \param nw_frame_cnt_read network frame counter read callback * */ -void ws_pae_auth_cb_register(protocol_interface_info_entry_t *interface_ptr, ws_pae_auth_gtk_hash_set *hash_set, ws_pae_auth_nw_key_insert *nw_key_insert, ws_pae_auth_nw_key_index_set *nw_key_index_set, ws_pae_auth_nw_info_updated *nw_info_updated, ws_pae_auth_ip_addr_get *ip_addr_get, ws_pae_auth_congestion_get *congestion_get); +void ws_pae_auth_cb_register(protocol_interface_info_entry_t *interface_ptr, ws_pae_auth_gtk_hash_set *hash_set, ws_pae_auth_nw_key_insert *nw_key_insert, ws_pae_auth_nw_key_index_set *nw_key_index_set, ws_pae_auth_nw_info_updated *nw_info_updated, ws_pae_auth_ip_addr_get *ip_addr_get, ws_pae_auth_congestion_get *congestion_get, ws_pae_auth_nw_frame_counter_read *nw_frame_cnt_read); #else -#define ws_pae_auth_init(interface_ptr, next_gtks, certs, sec_cfg, sec_keys_nw_info) 1 +#define ws_pae_auth_init(interface_ptr, next_gtks, certs, sec_cfg, sec_keys_nw_info, frame_counters) 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, nw_info_updated, ip_addr_get, congestion_get) {(void) hash_set;} +#define ws_pae_auth_cb_register(interface_ptr, hash_set, nw_key_insert, nw_key_index_set, nw_info_updated, ip_addr_get, congestion_get, nw_frame_cnt_read) {(void) hash_set;} #define ws_pae_auth_start(interface_ptr) #define ws_pae_auth_gtks_updated NULL #define ws_pae_auth_nw_key_index_update NULL diff --git a/source/6LoWPAN/ws/ws_pae_controller.c b/source/6LoWPAN/ws/ws_pae_controller.c index 805cb07d8b..6511616540 100644 --- a/source/6LoWPAN/ws/ws_pae_controller.c +++ b/source/6LoWPAN/ws/ws_pae_controller.c @@ -26,6 +26,7 @@ #include "ws_management_api.h" #include "ws_bbr_api.h" #include "Service_Libs/utils/ns_file.h" +#include "Service_Libs/utils/ns_time.h" #include "NWK_INTERFACE/Include/protocol.h" #include "6LoWPAN/ws/ws_config.h" #include "6LoWPAN/ws/ws_cfg_settings.h" @@ -51,7 +52,7 @@ typedef void ws_pae_timer(uint16_t ticks); typedef int8_t ws_pae_br_addr_write(protocol_interface_info_entry_t *interface_ptr, const uint8_t *eui_64); typedef int8_t ws_pae_br_addr_read(protocol_interface_info_entry_t *interface_ptr, uint8_t *eui_64); typedef void ws_pae_gtks_updated(protocol_interface_info_entry_t *interface_ptr); -typedef int8_t ws_pae_gtk_hash_update(protocol_interface_info_entry_t *interface_ptr, uint8_t *gtkhash); +typedef int8_t ws_pae_gtk_hash_update(protocol_interface_info_entry_t *interface_ptr, uint8_t *gtkhash, bool del_gtk_on_mismatch); typedef int8_t ws_pae_nw_key_index_update(protocol_interface_info_entry_t *interface_ptr, uint8_t index); typedef int8_t ws_pae_nw_info_set(protocol_interface_info_entry_t *interface_ptr, uint16_t pan_id, char *network_name, bool updated); @@ -119,6 +120,7 @@ static void ws_pae_controller_nw_info_updated_check(protocol_interface_info_entr #ifdef HAVE_PAE_AUTH static void ws_pae_controller_auth_ip_addr_get(protocol_interface_info_entry_t *interface_ptr, uint8_t *address); static bool ws_pae_controller_auth_congestion_get(protocol_interface_info_entry_t *interface_ptr, uint16_t active_supp); +static int8_t ws_pae_controller_auth_nw_frame_counter_read(protocol_interface_info_entry_t *interface_ptr, uint32_t *counter, uint8_t gtk_index); #endif static pae_controller_t *ws_pae_controller_get(protocol_interface_info_entry_t *interface_ptr); static void ws_pae_controller_frame_counter_timer(uint16_t seconds, pae_controller_t *entry); @@ -140,8 +142,8 @@ static int8_t ws_pae_controller_frame_counter_read(pae_controller_t *controller) static void ws_pae_controller_frame_counter_reset(frame_counters_t *frame_counters); static void ws_pae_controller_frame_counter_index_reset(frame_counters_t *frame_counters, uint8_t index); static int8_t ws_pae_controller_nw_info_read(pae_controller_t *controller, sec_prot_gtk_keys_t *gtks); -static int8_t ws_pae_controller_nvm_nw_info_write(protocol_interface_info_entry_t *interface_ptr, uint16_t pan_id, char *network_name, uint8_t *gtk_eui64, sec_prot_gtk_keys_t *gtks); -static int8_t ws_pae_controller_nvm_nw_info_read(protocol_interface_info_entry_t *interface_ptr, uint16_t *pan_id, char *network_name, uint8_t *gtk_eui64, sec_prot_gtk_keys_t *gtks); +static int8_t ws_pae_controller_nvm_nw_info_write(protocol_interface_info_entry_t *interface_ptr, uint16_t pan_id, char *network_name, uint8_t *gtk_eui64, sec_prot_gtk_keys_t *gtks, uint64_t stored_time, uint8_t time_changed); +static int8_t ws_pae_controller_nvm_nw_info_read(protocol_interface_info_entry_t *interface_ptr, uint16_t *pan_id, char *network_name, uint8_t *gtk_eui64, sec_prot_gtk_keys_t *gtks, uint64_t current_time, uint8_t *time_changed); static const char *FRAME_COUNTER_FILE = FRAME_COUNTER_FILE_NAME; @@ -196,7 +198,7 @@ int8_t ws_pae_controller_bootstrap_done(protocol_interface_info_entry_t *interfa /* Trigger GTK hash update to supplicant, so it can check whether keys have been updated during bootstrap. Does nothing if GTKs are up to date. */ - ws_pae_supp_gtk_hash_update(interface_ptr, controller->gtkhash); + ws_pae_supp_gtk_hash_update(interface_ptr, controller->gtkhash, false); #endif return 0; @@ -239,7 +241,7 @@ int8_t ws_pae_controller_authenticator_start(protocol_interface_info_entry_t *in ws_pae_auth_node_limit_set(controller->interface_ptr, pae_controller_config.node_limit); } - ws_pae_auth_cb_register(interface_ptr, ws_pae_controller_gtk_hash_set, ws_pae_controller_nw_key_check_and_insert, ws_pae_controller_nw_key_index_check_and_set, ws_pae_controller_nw_info_updated_check, ws_pae_controller_auth_ip_addr_get, ws_pae_controller_auth_congestion_get); + ws_pae_auth_cb_register(interface_ptr, ws_pae_controller_gtk_hash_set, ws_pae_controller_nw_key_check_and_insert, ws_pae_controller_nw_key_index_check_and_set, ws_pae_controller_nw_info_updated_check, ws_pae_controller_auth_ip_addr_get, ws_pae_controller_auth_congestion_get, ws_pae_controller_auth_nw_frame_counter_read); controller->auth_started = true; @@ -376,7 +378,8 @@ static void ws_pae_controller_nw_info_updated_check(protocol_interface_info_entr if (arm_nwk_mac_address_read(interface_ptr->id, &mac_params) >= 0) { memcpy(gtk_eui64, mac_params.mac_long, 8); } - ws_pae_controller_nvm_nw_info_write(interface_ptr, controller->sec_keys_nw_info.key_pan_id, controller->sec_keys_nw_info.network_name, gtk_eui64, controller->sec_keys_nw_info.gtks); + uint64_t system_time = ws_pae_current_time_get(); + ws_pae_controller_nvm_nw_info_write(interface_ptr, controller->sec_keys_nw_info.key_pan_id, controller->sec_keys_nw_info.network_name, gtk_eui64, controller->sec_keys_nw_info.gtks, system_time, controller->sec_keys_nw_info.system_time_changed); controller->sec_keys_nw_info.updated = false; sec_prot_keys_gtks_updated_reset(controller->sec_keys_nw_info.gtks); } @@ -410,6 +413,21 @@ static bool ws_pae_controller_auth_congestion_get(protocol_interface_info_entry_ return controller->congestion_get(interface_ptr, active_supp); } + +static int8_t ws_pae_controller_auth_nw_frame_counter_read(protocol_interface_info_entry_t *interface_ptr, uint32_t *counter, uint8_t gtk_index) +{ + if (!interface_ptr) { + return -1; + } + + pae_controller_t *controller = ws_pae_controller_get(interface_ptr); + if (!controller) { + return -1; + } + + controller->nw_frame_counter_read(interface_ptr, counter, gtk_index); + return 0; +} #endif int8_t ws_pae_controller_nw_key_valid(protocol_interface_info_entry_t *interface_ptr, uint8_t *br_iid) @@ -546,19 +564,31 @@ static int8_t ws_pae_controller_gak_from_gtk(uint8_t *gak, uint8_t *gtk, char *n mbedtls_sha256_init(&ctx); +#if (MBEDTLS_VERSION_MAJOR >= 3) + if (mbedtls_sha256_starts(&ctx, 0) != 0) { +#else if (mbedtls_sha256_starts_ret(&ctx, 0) != 0) { +#endif ret_val = -1; goto error; } +#if (MBEDTLS_VERSION_MAJOR >= 3) + if (mbedtls_sha256_update(&ctx, input, network_name_len + GTK_LEN) != 0) { +#else if (mbedtls_sha256_update_ret(&ctx, input, network_name_len + GTK_LEN) != 0) { +#endif ret_val = -1; goto error; } uint8_t output[32]; +#if (MBEDTLS_VERSION_MAJOR >= 3) + if (mbedtls_sha256_finish(&ctx, output) != 0) { +#else if (mbedtls_sha256_finish_ret(&ctx, output) != 0) { +#endif ret_val = -1; goto error; } @@ -792,8 +822,8 @@ static int8_t ws_pae_controller_frame_counter_read(pae_controller_t *controller) // Read frame counters if (ws_pae_controller_nvm_frame_counter_read(&controller->restart_cnt, &stored_time, &controller->sec_keys_nw_info.pan_version, &controller->frame_counters) >= 0) { - // Current time is not valid - if (ws_pae_current_time_set(stored_time) < 0) { + // Check if stored time is not valid + if (ws_pae_stored_time_check_and_set(stored_time) < 0) { ret_value = -1; } // This is used to ensure that PMK replay counters are fresh after each re-start. @@ -837,16 +867,23 @@ static void ws_pae_controller_frame_counter_index_reset(frame_counters_t *frame_ 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].max_frame_counter_chg = 0; frame_counters->counter[index].set = false; } static int8_t ws_pae_controller_nw_info_read(pae_controller_t *controller, sec_prot_gtk_keys_t *gtks) { uint8_t nvm_gtk_eui64[8]; - if (ws_pae_controller_nvm_nw_info_read(controller->interface_ptr, &controller->sec_keys_nw_info.key_pan_id, controller->sec_keys_nw_info.network_name, nvm_gtk_eui64, gtks) < 0) { + uint64_t system_time = ws_pae_current_time_get(); + + uint8_t system_time_changed = controller->sec_keys_nw_info.system_time_changed; + if (ws_pae_controller_nvm_nw_info_read(controller->interface_ptr, &controller->sec_keys_nw_info.key_pan_id, controller->sec_keys_nw_info.network_name, nvm_gtk_eui64, gtks, system_time, &controller->sec_keys_nw_info.system_time_changed) < 0) { // If no stored GTKs and network info (pan_id and network name) exits return -1; } + if (system_time_changed != controller->sec_keys_nw_info.system_time_changed) { + controller->sec_keys_nw_info.updated = true; + } /* Get own EUI-64 and compare to the one read from the NVM. In case of mismatch delete GTKs and make full authentication to update keys with new EUI-64 and in case of authenticator to update new @@ -867,21 +904,21 @@ static int8_t ws_pae_controller_nw_info_read(pae_controller_t *controller, sec_p return 0; } -static int8_t ws_pae_controller_nvm_nw_info_write(protocol_interface_info_entry_t *interface_ptr, uint16_t pan_id, char *network_name, uint8_t *gtk_eui64, sec_prot_gtk_keys_t *gtks) +static int8_t ws_pae_controller_nvm_nw_info_write(protocol_interface_info_entry_t *interface_ptr, uint16_t pan_id, char *network_name, uint8_t *gtk_eui64, sec_prot_gtk_keys_t *gtks, uint64_t stored_time, uint8_t time_changed) { nw_info_nvm_tlv_t *tlv = (nw_info_nvm_tlv_t *) ws_pae_controller_nvm_tlv_get(interface_ptr); if (!tlv) { return -1; } - ws_pae_nvm_store_nw_info_tlv_create(tlv, pan_id, network_name, gtk_eui64, gtks); + ws_pae_nvm_store_nw_info_tlv_create(tlv, pan_id, network_name, gtk_eui64, gtks, stored_time, time_changed); ws_pae_nvm_store_tlv_file_write(NW_INFO_FILE, (nvm_tlv_t *) tlv); return 0; } -static int8_t ws_pae_controller_nvm_nw_info_read(protocol_interface_info_entry_t *interface_ptr, uint16_t *pan_id, char *network_name, uint8_t *gtk_eui64, sec_prot_gtk_keys_t *gtks) +static int8_t ws_pae_controller_nvm_nw_info_read(protocol_interface_info_entry_t *interface_ptr, uint16_t *pan_id, char *network_name, uint8_t *gtk_eui64, sec_prot_gtk_keys_t *gtks, uint64_t current_time, uint8_t *time_changed) { nw_info_nvm_tlv_t *tlv_entry = (nw_info_nvm_tlv_t *) ws_pae_controller_nvm_tlv_get(interface_ptr); if (!tlv_entry) { @@ -894,7 +931,7 @@ static int8_t ws_pae_controller_nvm_nw_info_read(protocol_interface_info_entry_t return -1; } - if (ws_pae_nvm_store_nw_info_tlv_read(tlv_entry, pan_id, network_name, gtk_eui64, gtks) < 0) { + if (ws_pae_nvm_store_nw_info_tlv_read(tlv_entry, pan_id, network_name, gtk_eui64, gtks, current_time, time_changed) < 0) { return -1; } @@ -939,10 +976,13 @@ int8_t ws_pae_controller_auth_init(protocol_interface_info_entry_t *interface_pt return -1; } - if (ws_pae_auth_init(controller->interface_ptr, &controller->next_gtks, &controller->certs, &controller->sec_cfg, &controller->sec_keys_nw_info) < 0) { + if (ws_pae_auth_init(controller->interface_ptr, &controller->next_gtks, &controller->certs, &controller->sec_cfg, &controller->sec_keys_nw_info, &controller->frame_counters) < 0) { return -1; } + // For Border Router enable the time acquired as default + ns_time_system_time_acquired_set(); + controller->pae_delete = ws_pae_auth_delete; controller->pae_fast_timer = ws_pae_auth_fast_timer; controller->pae_slow_timer = ws_pae_auth_slow_timer; @@ -967,21 +1007,21 @@ int8_t ws_pae_controller_auth_init(protocol_interface_info_entry_t *interface_pt sec_prot_keys_gtks_updated_reset(&controller->gtks); } #endif - - if (ws_pae_controller_nw_info_read(controller, read_gtks_to) >= 0) { + if (read_gtks_to && ws_pae_controller_nw_info_read(controller, read_gtks_to) >= 0) { /* If network information i.e pan_id and network name exists updates bootstrap with it, (in case already configured by application then no changes are made) */ if (controller->nw_info_updated) { controller->nw_info_updated(interface_ptr, controller->sec_keys_nw_info.key_pan_id, controller->sec_keys_nw_info.pan_version, controller->sec_keys_nw_info.network_name); } - if (!read_gtks_to || sec_prot_keys_gtk_count(read_gtks_to) == 0) { + if (sec_prot_keys_gtk_count(read_gtks_to) == 0) { // Key material invalid or GTKs are expired, delete GTKs from NVM uint8_t gtk_eui64[8] = {0}; // Set GTK EUI-64 to zero - ws_pae_controller_nvm_nw_info_write(controller->interface_ptr, controller->sec_keys_nw_info.key_pan_id, controller->sec_keys_nw_info.network_name, gtk_eui64, NULL); + uint64_t system_time = ws_pae_current_time_get(); + ws_pae_controller_nvm_nw_info_write(controller->interface_ptr, controller->sec_keys_nw_info.key_pan_id, controller->sec_keys_nw_info.network_name, gtk_eui64, NULL, system_time, controller->sec_keys_nw_info.system_time_changed); } } - ws_pae_key_storage_init(); + if (read_gtks_to) { ws_pae_key_storage_read(controller->restart_cnt); } else { @@ -1662,7 +1702,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, controller->gtkhash); + return controller->pae_gtk_hash_update(interface_ptr, controller->gtkhash, true); } return 0; @@ -1731,9 +1771,12 @@ static void ws_pae_controller_frame_counter_store(pae_controller_t *entry, bool } 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 || - frame_counter > entry->frame_counters.counter[i].stored_frame_counter + FRAME_COUNTER_STORE_THRESHOLD) { + /* If threshold check is disabled or frame counter has advanced for the threshold value, stores the new value. + If frame counter is at maximum at storage, do not initiate storing */ + if (!use_threshold || ( + (frame_counter > entry->frame_counters.counter[i].stored_frame_counter + FRAME_COUNTER_STORE_THRESHOLD) && + !(entry->frame_counters.counter[i].stored_frame_counter == UINT32_MAX && + frame_counter >= UINT32_MAX - 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, frame_counter); @@ -1761,8 +1804,9 @@ static void ws_pae_controller_frame_counter_store(pae_controller_t *entry, bool if (update_needed || entry->frame_cnt_store_force_timer == 0) { tr_debug("Write frame counters: system time %"PRIu32"", protocol_core_monotonic_time / 10); + uint64_t system_time = ws_pae_current_time_get(); // Writes modified frame counters - ws_pae_nvm_store_frame_counter_tlv_create((frame_cnt_nvm_tlv_t *) &entry->pae_nvm_buffer, entry->restart_cnt, entry->sec_keys_nw_info.pan_version, &entry->frame_counters); + ws_pae_nvm_store_frame_counter_tlv_create((frame_cnt_nvm_tlv_t *) &entry->pae_nvm_buffer, entry->restart_cnt, entry->sec_keys_nw_info.pan_version, &entry->frame_counters, system_time); ws_pae_controller_nvm_frame_counter_write((frame_cnt_nvm_tlv_t *) &entry->pae_nvm_buffer); // Reset force interval when ever values are stored diff --git a/source/6LoWPAN/ws/ws_pae_key_storage.c b/source/6LoWPAN/ws/ws_pae_key_storage.c index 373f2c0619..398c9ac0cd 100644 --- a/source/6LoWPAN/ws/ws_pae_key_storage.c +++ b/source/6LoWPAN/ws/ws_pae_key_storage.c @@ -944,7 +944,7 @@ static int8_t ws_pae_key_storage_array_time_update_entry(uint64_t time_differenc #endif } - if (storage_array_entry->pmk_lifetime_set) { + if (storage_array_entry->ptk_lifetime_set) { #ifdef EXTRA_DEBUG_INFO tr_debug("KeyS time update diff: %"PRIi64" PTK OLD t: %i %i eui64: %s", time_difference, STIME_TIME_GET(storage_array_entry->ptk_lifetime), STIME_FORMAT_GET(storage_array_entry->ptk_lifetime), tr_array(storage_array_entry->ptk_eui_64, 8)); #endif diff --git a/source/6LoWPAN/ws/ws_pae_nvm_data.c b/source/6LoWPAN/ws/ws_pae_nvm_data.c index 27eacbc45f..fe5e00d09e 100644 --- a/source/6LoWPAN/ws/ws_pae_nvm_data.c +++ b/source/6LoWPAN/ws/ws_pae_nvm_data.c @@ -40,34 +40,7 @@ #define PAE_NVM_FIELD_NOT_SET 0 // Field is not present #define PAE_NVM_FIELD_SET 1 // Field is present -void ws_pae_nvm_store_generic_tlv_create(nvm_tlv_t *tlv_entry, uint16_t tag, uint16_t length) -{ - tlv_entry->tag = tag; - tlv_entry->len = length; -} - -nvm_tlv_t *ws_pae_nvm_store_generic_tlv_allocate_and_create(uint16_t tag, uint16_t length) -{ - nvm_tlv_t *tlv_entry = ns_dyn_mem_alloc(length + sizeof(nvm_tlv_t)); - if (!tlv_entry) { - return NULL; - } - tlv_entry->tag = tag; - tlv_entry->len = length; - - return tlv_entry; -} - -void ws_pae_nvm_store_generic_tlv_free(nvm_tlv_t *tlv_entry) -{ - if (!tlv_entry) { - return; - } - - ns_dyn_mem_free(tlv_entry); -} - -void ws_pae_nvm_store_nw_info_tlv_create(nw_info_nvm_tlv_t *tlv_entry, uint16_t pan_id, char *nw_name, uint8_t *gtk_eui64, sec_prot_gtk_keys_t *gtks) +void ws_pae_nvm_store_nw_info_tlv_create(nw_info_nvm_tlv_t *tlv_entry, uint16_t pan_id, char *nw_name, uint8_t *gtk_eui64, sec_prot_gtk_keys_t *gtks, uint64_t stored_time, uint8_t time_changed) { int len; tlv_entry->tag = PAE_NVM_NW_INFO_TAG; @@ -90,13 +63,14 @@ void ws_pae_nvm_store_nw_info_tlv_create(nw_info_nvm_tlv_t *tlv_entry, uint16_t memcpy((char *)tlv, gtk_eui64, 8); tlv += 8; - uint64_t current_time = ws_pae_current_time_get(); + *tlv++ = time_changed; + tlv = common_write_64_bit(stored_time, tlv); for (uint8_t i = 0; i < GTK_NUM; i++) { if (gtks && sec_prot_keys_gtk_is_set(gtks, i)) { *tlv++ = PAE_NVM_FIELD_SET; // GTK is set - uint64_t expirytime = sec_prot_keys_gtk_exptime_from_lifetime_get(gtks, i, current_time); + uint64_t expirytime = sec_prot_keys_gtk_exptime_from_lifetime_get(gtks, i, stored_time); // Sets stored expiration time to GTKs; no need to update anymore to NVM if not changed sec_prot_keys_gtk_expirytime_set(gtks, i, expirytime); @@ -118,11 +92,11 @@ void ws_pae_nvm_store_nw_info_tlv_create(nw_info_nvm_tlv_t *tlv_entry, uint16_t } } - tr_debug("NVM NW_INFO write PAN ID %i name: %s", pan_id, nw_name); + tr_info("NVM NW_INFO write PAN ID: %i name: %s stored time: %"PRIu64, pan_id, nw_name, stored_time); } -int8_t ws_pae_nvm_store_nw_info_tlv_read(nw_info_nvm_tlv_t *tlv_entry, uint16_t *pan_id, char *nw_name, uint8_t *gtk_eui64, sec_prot_gtk_keys_t *gtks) +int8_t ws_pae_nvm_store_nw_info_tlv_read(nw_info_nvm_tlv_t *tlv_entry, uint16_t *pan_id, char *nw_name, uint8_t *gtk_eui64, sec_prot_gtk_keys_t *gtks, uint64_t current_time, uint8_t *time_changed) { if (!tlv_entry || !pan_id || !nw_name) { return -1; @@ -150,9 +124,20 @@ int8_t ws_pae_nvm_store_nw_info_tlv_read(nw_info_nvm_tlv_t *tlv_entry, uint16_t memcpy(gtk_eui64, (char *)tlv, 8); tlv += 8; - uint64_t current_time = ws_pae_current_time_get(); + *time_changed = *tlv++; + uint64_t stored_time = common_read_64_bit(tlv); + tlv += 8; + // Use either stored time or current time as reference when calculating lifetimes + current_time = ws_pae_time_old_or_new_select(stored_time, current_time); + /* If the selected time has made a large jump then use the stored time to calculate the lifetime + (this implies e.g. that new time has been received from NTP and old time was not valid) */ + if (*time_changed == SYSTEM_TIME_NOT_CHANGED && !ws_pae_time_old_and_new_validate(stored_time, current_time)) { + *time_changed = SYSTEM_TIME_CHANGED; + current_time = stored_time; + tr_info("NVM NW_INFO system time change"); + } - tr_debug("NVM NW_INFO current time: %"PRIi64, current_time); + tr_info("NVM NW_INFO current time: %"PRIi64" stored time: %"PRIi64, current_time, stored_time); if (gtks && sec_prot_keys_gtk_count(gtks) == 0) { // If application has not set GTKs read them from NVM @@ -160,9 +145,10 @@ int8_t ws_pae_nvm_store_nw_info_tlv_read(nw_info_nvm_tlv_t *tlv_entry, uint16_t if (*tlv++ == PAE_NVM_FIELD_SET) { /* GTK is set */ uint64_t expirytime = common_read_64_bit(tlv); uint32_t lifetime = 0; + // Calculate lifetime if (ws_pae_time_diff_calc(current_time, expirytime, &lifetime, true) < 0) { tlv += 8 + 1 + 1 + GTK_LEN; - tr_debug("GTK index %i, expired expiry time: %"PRIi64", lifetime: %"PRIi32, i, expirytime, lifetime); + tr_info("GTK index %i, expired expiry time: %"PRIi64", lifetime: %"PRIi32, i, expirytime, lifetime); continue; } tlv += 8; @@ -171,7 +157,7 @@ int8_t ws_pae_nvm_store_nw_info_tlv_read(nw_info_nvm_tlv_t *tlv_entry, uint16_t uint8_t install_order = *tlv++; - tr_debug("GTK index: %i, status: %i, install order %i, expiry time: %"PRIi64", lifetime: %"PRIi32, i, status, install_order, expirytime, lifetime); + tr_info("GTK index: %i, status: %i, install order %i, expiry time: %"PRIi64", lifetime: %"PRIi32, i, status, install_order, expirytime, lifetime); sec_prot_keys_gtk_set(gtks, i, tlv, lifetime); sec_prot_keys_gtk_expirytime_set(gtks, i, expirytime); @@ -185,7 +171,7 @@ int8_t ws_pae_nvm_store_nw_info_tlv_read(nw_info_nvm_tlv_t *tlv_entry, uint16_t sec_prot_keys_gtks_updated_reset(gtks); } - tr_debug("NVM NW_INFO read PAN ID %i name: %s", *pan_id, nw_name); + tr_info("NVM NW_INFO read PAN ID %i name: %s", *pan_id, nw_name); return 0; } @@ -234,7 +220,7 @@ void ws_pae_nvm_store_keys_tlv_create(keys_nvm_tlv_t *tlv_entry, sec_prot_keys_t } tlv += PTK_LEN; - tr_debug("NVM KEYS write"); + tr_info("NVM KEYS write"); } int8_t ws_pae_nvm_store_keys_tlv_read(keys_nvm_tlv_t *tlv_entry, sec_prot_keys_t *sec_keys) @@ -282,12 +268,12 @@ int8_t ws_pae_nvm_store_keys_tlv_read(keys_nvm_tlv_t *tlv_entry, sec_prot_keys_t sec_prot_keys_updated_reset(sec_keys); - tr_debug("NVM KEYS read"); + tr_info("NVM KEYS read"); return 0; } -void ws_pae_nvm_store_frame_counter_tlv_create(frame_cnt_nvm_tlv_t *tlv_entry, uint32_t restart_cnt, uint16_t pan_version, frame_counters_t *counters) +void ws_pae_nvm_store_frame_counter_tlv_create(frame_cnt_nvm_tlv_t *tlv_entry, uint32_t restart_cnt, uint16_t pan_version, frame_counters_t *counters, uint64_t stored_time) { tlv_entry->tag = PAE_NVM_FRAME_COUNTER_TAG; tlv_entry->len = PAE_NVM_FRAME_COUNTER_LEN; @@ -296,7 +282,6 @@ void ws_pae_nvm_store_frame_counter_tlv_create(frame_cnt_nvm_tlv_t *tlv_entry, u tlv = common_write_32_bit(restart_cnt, tlv); - uint64_t stored_time = ws_pae_current_time_get(); tlv = common_write_64_bit(stored_time, tlv); tlv = common_write_16_bit(pan_version, tlv); @@ -304,17 +289,18 @@ void ws_pae_nvm_store_frame_counter_tlv_create(frame_cnt_nvm_tlv_t *tlv_entry, u for (uint8_t index = 0; index < GTK_NUM; index++) { if (!counters->counter[index].set) { *tlv++ = PAE_NVM_FIELD_NOT_SET; - memset(tlv, 0, GTK_LEN + 4); - tlv += GTK_LEN + 4; + memset(tlv, 0, GTK_LEN + 4 + 4); + tlv += GTK_LEN + 4 + 4; continue; } *tlv++ = PAE_NVM_FIELD_SET; memcpy(tlv, counters->counter[index].gtk, GTK_LEN); tlv += GTK_LEN; tlv = common_write_32_bit(counters->counter[index].frame_counter, tlv); + tlv = common_write_32_bit(counters->counter[index].max_frame_counter_chg, tlv); } - tr_debug("NVM FRAME COUNTER write"); + tr_info("NVM FRAME COUNTER write; stored time: %"PRIu64, stored_time); } int8_t ws_pae_nvm_store_frame_counter_tlv_read(frame_cnt_nvm_tlv_t *tlv_entry, uint32_t *restart_cnt, uint64_t *stored_time, uint16_t *pan_version, frame_counters_t *counters) @@ -342,7 +328,7 @@ int8_t ws_pae_nvm_store_frame_counter_tlv_read(frame_cnt_nvm_tlv_t *tlv_entry, u // Frame counter not set if (*tlv++ == PAE_NVM_FIELD_NOT_SET) { counters->counter[index].set = false; - tlv += GTK_LEN + 4; + tlv += GTK_LEN + 4 + 4; continue; } // Frame counter is set, read GTK key and counter values @@ -351,9 +337,11 @@ int8_t ws_pae_nvm_store_frame_counter_tlv_read(frame_cnt_nvm_tlv_t *tlv_entry, u tlv += GTK_LEN; counters->counter[index].frame_counter = common_read_32_bit(tlv); tlv += 4; + counters->counter[index].max_frame_counter_chg = common_read_32_bit(tlv); + tlv += 4; } - tr_debug("NVM FRAME COUNTER read"); + tr_info("NVM FRAME COUNTER read; stored time: %"PRIu64, *stored_time); return 0; } @@ -367,7 +355,7 @@ void ws_pae_nvm_store_key_storage_index_tlv_create(nvm_tlv_t *tlv_entry, uint64_ tlv = common_write_64_bit(bitfield, tlv); - tr_debug("NVM KEY STORAGE INDEX write"); + tr_info("NVM KEY STORAGE INDEX write"); } int8_t ws_pae_nvm_store_key_storage_index_tlv_read(nvm_tlv_t *tlv_entry, uint64_t *bitfield) @@ -384,7 +372,7 @@ int8_t ws_pae_nvm_store_key_storage_index_tlv_read(nvm_tlv_t *tlv_entry, uint64_ *bitfield = common_read_64_bit(tlv); tlv += 8; - tr_debug("NVM KEY STORAGE INDEX read"); + tr_info("NVM KEY STORAGE INDEX read"); return 0; } diff --git a/source/6LoWPAN/ws/ws_pae_nvm_data.h b/source/6LoWPAN/ws/ws_pae_nvm_data.h index 9194e2b5b9..1e0f0f3214 100644 --- a/source/6LoWPAN/ws/ws_pae_nvm_data.h +++ b/source/6LoWPAN/ws/ws_pae_nvm_data.h @@ -35,16 +35,24 @@ #define PAE_NVM_KEY_STORAGE_INDEX_TAG 4 #define PAE_NVM_KEY_STORAGE_TAG 5 -// pan_id (2) + network name (33) + GTK EUI-64 (own EUI-64) (8) + (GTK set (1) + GTK expiry timestamp (8) + status (1) + install order (1) + GTK (16)) * 4 -#define PAE_NVM_NW_INFO_LEN 2 + 33 + 8 + (1 + 8 + 1 + 1 + GTK_LEN) * GTK_NUM +// pan_id (2) + network name (33) + GTK EUI-64 (own EUI-64) (8) + stored time (8) + time changed (1) + (GTK set (1) + GTK expiry timestamp (8) + status (1) + install order (1) + GTK (16)) * 4 +#define PAE_NVM_NW_INFO_LEN 2 + 33 + 8 + 8 + 1 + (1 + 8 + 1 + 1 + GTK_LEN) * GTK_NUM // PTK EUI-64 set (1) + PTK EUI-64 (8) + PMK set (1) + PMK lifetime (4) + PMK (32) + PMK replay counter (8) + PTK set (1) + PTK lifetime (4) + PTK (48) #define PAE_NVM_KEYS_LEN 1 + 8 + 1 + 4 + PMK_LEN + 8 + 1 + 4 + PTK_LEN -// restart counter + stored time + pan version + (frame counter set (1) + GTK (16) + frame counter (4)) * 4 -#define PAE_NVM_FRAME_COUNTER_LEN 4 + 8 + 2 + (1 + GTK_LEN + 4) * GTK_NUM +// restart counter + stored time + pan version + (frame counter set (1) + GTK (16) + frame counter (4) + max frame counter change (4)) * 4 +#define PAE_NVM_FRAME_COUNTER_LEN 4 + 8 + 2 + (1 + GTK_LEN + 4 + 4) * GTK_NUM -#define PAE_NVM_DEFAULT_BUFFER_SIZE sizeof(nvm_tlv_t) + PAE_NVM_NW_INFO_LEN +#if (PAE_NVM_NW_INFO_LEN >= PAE_NVM_KEYS_LEN) && (PAE_NVM_NW_INFO_LEN >= PAE_NVM_FRAME_COUNTER_LEN) +#define PAE_NVM_LARGEST_FILE PAE_NVM_NW_INFO_LEN +#elif (PAE_NVM_KEYS_LEN >= PAE_NVM_NW_INFO_LEN) && (PAE_NVM_KEYS_LEN >= PAE_NVM_FRAME_COUNTER_LEN) +#define PAE_NVM_LARGEST_FILE PAE_NVM_KEYS_LEN +#else +#define PAE_NVM_LARGEST_FILE PAE_NVM_FRAME_COUNTER_LEN +#endif + +#define PAE_NVM_DEFAULT_BUFFER_SIZE sizeof(nvm_tlv_t) + PAE_NVM_LARGEST_FILE // key storage index bitfield (8) #define PAE_NVM_KEY_STORAGE_INDEX_LEN 8 @@ -91,11 +99,13 @@ void ws_pae_nvm_store_generic_tlv_free(nvm_tlv_t *tlv_entry); * \param pan_id PAN ID * \param nw_name network name * \param gtks GTK keys + * \param stored_time stored timestampt + * \param time_changed stored time has changed * * \return TLV entry or NULL * */ -void ws_pae_nvm_store_nw_info_tlv_create(nw_info_nvm_tlv_t *tlv_entry, uint16_t pan_id, char *nw_name, uint8_t *gtk_eui64, sec_prot_gtk_keys_t *gtks); +void ws_pae_nvm_store_nw_info_tlv_create(nw_info_nvm_tlv_t *tlv_entry, uint16_t pan_id, char *nw_name, uint8_t *gtk_eui64, sec_prot_gtk_keys_t *gtks, uint64_t stored_time, uint8_t time_changed); /** * ws_pae_nvm_store_nw_info_tlv_read read from NVM network info TLV @@ -104,12 +114,14 @@ void ws_pae_nvm_store_nw_info_tlv_create(nw_info_nvm_tlv_t *tlv_entry, uint16_t * \param pan_id PAN ID * \param nw_name network name * \param gtks GTK keys + * \param current_time current timestampt + * \param time_changed stored time has changed * * \return < 0 failure * \return >= 0 success * */ -int8_t ws_pae_nvm_store_nw_info_tlv_read(nw_info_nvm_tlv_t *tlv_entry, uint16_t *pan_id, char *nw_name, uint8_t *gtk_eui64, sec_prot_gtk_keys_t *gtks); +int8_t ws_pae_nvm_store_nw_info_tlv_read(nw_info_nvm_tlv_t *tlv_entry, uint16_t *pan_id, char *nw_name, uint8_t *gtk_eui64, sec_prot_gtk_keys_t *gtks, uint64_t current_time, uint8_t *time_changed); /** * ws_pae_nvm_store_keys_tlv_create create NVM keys TLV @@ -139,9 +151,10 @@ int8_t ws_pae_nvm_store_keys_tlv_read(keys_nvm_tlv_t *tlv_entry, sec_prot_keys_t * \param restart_cnt re-start counter * \param pan_version PAN version * \param counters frame counters + * \param stored_time stored timestampt * */ -void ws_pae_nvm_store_frame_counter_tlv_create(frame_cnt_nvm_tlv_t *tlv_entry, uint32_t restart_cnt, uint16_t pan_version, frame_counters_t *counters); +void ws_pae_nvm_store_frame_counter_tlv_create(frame_cnt_nvm_tlv_t *tlv_entry, uint32_t restart_cnt, uint16_t pan_version, frame_counters_t *counters, uint64_t stored_time); /** * ws_pae_nvm_store_frame_counter_tlv_read read from NVM frame counter TLV diff --git a/source/6LoWPAN/ws/ws_pae_nvm_store.c b/source/6LoWPAN/ws/ws_pae_nvm_store.c index 065d9d0598..e30a1caad7 100644 --- a/source/6LoWPAN/ws/ws_pae_nvm_store.c +++ b/source/6LoWPAN/ws/ws_pae_nvm_store.c @@ -43,6 +43,33 @@ static int8_t ws_pae_nvm_store_create_path(char *fast_data_path, const char *fil static int8_t ws_pae_nvm_store_write(const char *file_name, nvm_tlv_t *tlv); static int8_t ws_pae_nvm_store_read(const char *file_name, nvm_tlv_t *tlv); +void ws_pae_nvm_store_generic_tlv_create(nvm_tlv_t *tlv_entry, uint16_t tag, uint16_t length) +{ + tlv_entry->tag = tag; + tlv_entry->len = length; +} + +nvm_tlv_t *ws_pae_nvm_store_generic_tlv_allocate_and_create(uint16_t tag, uint16_t length) +{ + nvm_tlv_t *tlv_entry = ns_dyn_mem_alloc(length + sizeof(nvm_tlv_t)); + if (!tlv_entry) { + return NULL; + } + tlv_entry->tag = tag; + tlv_entry->len = length; + + return tlv_entry; +} + +void ws_pae_nvm_store_generic_tlv_free(nvm_tlv_t *tlv_entry) +{ + if (!tlv_entry) { + return; + } + + ns_dyn_mem_free(tlv_entry); +} + int8_t ws_pae_nvm_store_tlv_file_write(const char *file, nvm_tlv_t *tlv) { if (!ws_pae_nvm_store_root_path_valid()) { diff --git a/source/6LoWPAN/ws/ws_pae_nvm_store.h b/source/6LoWPAN/ws/ws_pae_nvm_store.h index 32fd0bafde..412c57a6df 100644 --- a/source/6LoWPAN/ws/ws_pae_nvm_store.h +++ b/source/6LoWPAN/ws/ws_pae_nvm_store.h @@ -47,6 +47,38 @@ typedef struct { // tag + length #define NVM_TLV_FIXED_LEN sizeof(nvm_tlv_t) +/** + * ws_pae_nvm_store_generic_tlv_create create NVM generic storage TLV + * + * \param tlv_entry TLV entry + * \param tag tag + * \param length length of the (whole) entry + * + * \return < 0 failure + * \return >= 0 success + * + */ +void ws_pae_nvm_store_generic_tlv_create(nvm_tlv_t *tlv_entry, uint16_t tag, uint16_t length); + +/** + * ws_pae_nvm_store_generic_tlv_allocate_and_create allocate and create NVM generic storage TLV + * + * \param tag tag + * \param length length of the (whole) entry + * + * \return TLV entry or NULL + * + */ +nvm_tlv_t *ws_pae_nvm_store_generic_tlv_allocate_and_create(uint16_t tag, uint16_t length); + +/** + * ws_pae_nvm_store_generic_tlv_free free NVM generic storage TLV + * + * \param tlv_entry TLV entry + * + */ +void ws_pae_nvm_store_generic_tlv_free(nvm_tlv_t *tlv_entry); + /** * ws_pae_nvm_store_tlv_file_write write a list of TLVs to file * diff --git a/source/6LoWPAN/ws/ws_pae_supp.c b/source/6LoWPAN/ws/ws_pae_supp.c index 6aab0d9cae..7e518c465b 100644 --- a/source/6LoWPAN/ws/ws_pae_supp.c +++ b/source/6LoWPAN/ws/ws_pae_supp.c @@ -294,7 +294,7 @@ static int8_t ws_pae_supp_gtk_hash_mismatch_check(pae_supp_t *pae_supp) } // Check GTK hashes and initiate EAPOL procedure if mismatch is detected */ - gtk_mismatch_e mismatch = sec_prot_keys_gtks_hash_update(pae_supp->sec_keys_nw_info->gtks, gtkhash); + gtk_mismatch_e mismatch = sec_prot_keys_gtks_hash_update(pae_supp->sec_keys_nw_info->gtks, gtkhash, false); if (mismatch != GTK_NO_MISMATCH) { return -1; } @@ -303,7 +303,7 @@ static int8_t ws_pae_supp_gtk_hash_mismatch_check(pae_supp_t *pae_supp) return 0; } -int8_t ws_pae_supp_gtk_hash_update(protocol_interface_info_entry_t *interface_ptr, uint8_t *gtkhash) +int8_t ws_pae_supp_gtk_hash_update(protocol_interface_info_entry_t *interface_ptr, uint8_t *gtkhash, bool del_gtk_on_mismatch) { pae_supp_t *pae_supp = ws_pae_supp_get(interface_ptr); if (!pae_supp) { @@ -311,7 +311,7 @@ int8_t ws_pae_supp_gtk_hash_update(protocol_interface_info_entry_t *interface_pt } // Check GTK hashes and initiate EAPOL procedure if mismatch is detected */ - gtk_mismatch_e mismatch = sec_prot_keys_gtks_hash_update(pae_supp->sec_keys_nw_info->gtks, gtkhash); + gtk_mismatch_e mismatch = sec_prot_keys_gtks_hash_update(pae_supp->sec_keys_nw_info->gtks, gtkhash, del_gtk_on_mismatch); if (mismatch > GTK_NO_MISMATCH) { tr_info("GTK hash update %s %s %s %s", trace_array(>khash[0], 8), diff --git a/source/6LoWPAN/ws/ws_pae_supp.h b/source/6LoWPAN/ws/ws_pae_supp.h index 1ccd78c21e..c991d65062 100644 --- a/source/6LoWPAN/ws/ws_pae_supp.h +++ b/source/6LoWPAN/ws/ws_pae_supp.h @@ -130,12 +130,13 @@ int8_t ws_pae_supp_nw_key_valid(protocol_interface_info_entry_t *interface_ptr, * * \param interface_ptr interface * \param gtkhash GTK hash, 32 bytes + * \param del_gtk_on_mismatch Delete GTK in case of mismatch * * \return < 0 failure * \return >= 0 success * */ -int8_t ws_pae_supp_gtk_hash_update(protocol_interface_info_entry_t *interface_ptr, uint8_t *gtkhash); +int8_t ws_pae_supp_gtk_hash_update(protocol_interface_info_entry_t *interface_ptr, uint8_t *gtkhash, bool del_gtk_on_mismatch); /** * ws_pae_supp_nw_key_index_update key index been updated (on PAN configuration) diff --git a/source/6LoWPAN/ws/ws_pae_time.c b/source/6LoWPAN/ws/ws_pae_time.c index 55a3e8b5c6..be7bf77597 100644 --- a/source/6LoWPAN/ws/ws_pae_time.c +++ b/source/6LoWPAN/ws/ws_pae_time.c @@ -34,7 +34,9 @@ // Wednesday, January 1, 2020 0:00:00 GMT #define CURRENT_TIME_INIT_VALUE 1577836800 -static uint64_t current_time = CURRENT_TIME_INIT_VALUE; +#define SECONDS_IN_WEEK (7 * 24 * 60 * 60) + +static uint64_t ws_pae_current_time = CURRENT_TIME_INIT_VALUE; uint16_t ws_pae_time_to_short_convert(uint32_t time) { @@ -146,36 +148,76 @@ int8_t ws_pae_time_diff_calc(uint64_t curr_time, uint64_t comp_time, uint32_t *t return 0; } +uint64_t ws_pae_time_old_or_new_select(uint64_t old_time, uint64_t new_time) +{ + // If current time is more than one week in the past use the stored time + if (old_time > SECONDS_IN_WEEK && new_time < old_time - SECONDS_IN_WEEK) { + return old_time; + } + + return new_time; +} + +bool ws_pae_time_old_and_new_validate(uint64_t old_time, uint64_t new_time) +{ + /* If new time is more than one week in the past or more than a month in the + future the old time is not valid */ + if ((old_time > SECONDS_IN_WEEK && new_time < old_time - SECONDS_IN_WEEK) || + new_time > (old_time + SYSTEM_TIME_MAXIMUM_DIFF)) { + return false; + } + + return true; +} + uint64_t ws_pae_current_time_get(void) { + if (!ns_time_system_time_acquired_get()) { + return ws_pae_current_time; + } + uint64_t new_time; if (ns_time_system_time_read(&new_time) == 0) { + new_time = ws_pae_time_old_or_new_select(ws_pae_current_time, new_time); return new_time; } - return current_time; + return ws_pae_current_time; } void ws_pae_current_time_update(uint16_t seconds) { - current_time += seconds; + ws_pae_current_time += seconds; } -int8_t ws_pae_current_time_set(uint64_t time) +int8_t ws_pae_stored_time_check_and_set(uint64_t stored_time) { uint64_t new_system_time; - current_time = time; - tr_debug("Current time set: %"PRIi64, time); + tr_debug("Stored time check and set: %"PRIi64, stored_time); - if (ns_time_system_time_read(&new_system_time) == 0) { - // System time has gone backwards - if (new_system_time < current_time || new_system_time > current_time + SYSTEM_TIME_MAXIMUM_DIFF) { - tr_error("FATAL: system time less than reference time or more than 12 months in future: %"PRIi64" reference time: %"PRIi64, new_system_time, current_time); - return -1; - } + if (!ns_time_system_time_acquired_get()) { + ws_pae_current_time = stored_time; + return stored_time; } + if (ns_time_system_time_read(&new_system_time) == 0) { + // Use either stored time or current time as reference when calculating lifetimes + ws_pae_current_time = ws_pae_time_old_or_new_select(stored_time, new_system_time); + } + return 0; +} + +int8_t ws_pae_current_time_check_and_set(uint64_t current_time) +{ + uint64_t new_system_time; + + tr_debug("Current time check and set: %"PRIi64, current_time); + + if (ns_time_system_time_read(&new_system_time) == 0) { + // Use either stored time or current time as reference when calculating lifetimes + ws_pae_current_time = ws_pae_time_old_or_new_select(current_time, new_system_time); + } return 0; } diff --git a/source/6LoWPAN/ws/ws_pae_time.h b/source/6LoWPAN/ws/ws_pae_time.h index 41f77ef9fe..4fb6181ef5 100644 --- a/source/6LoWPAN/ws/ws_pae_time.h +++ b/source/6LoWPAN/ws/ws_pae_time.h @@ -38,7 +38,7 @@ typedef enum { #define STIME_TIME_GET(stime) (stime & STIME_TIME_MASK) // Maximum difference in stored and indicated system time -#define SYSTEM_TIME_MAXIMUM_DIFF (60 * 60 * 24 * 30 * 12) +#define SYSTEM_TIME_MAXIMUM_DIFF (60 * 60 * 24 * 30) // One month /** * ws_pae_time_to_short_convert convert time to short format @@ -87,6 +87,28 @@ bool ws_pae_time_from_short_time_compare(uint16_t short_time1, uint16_t short_ti */ int8_t ws_pae_time_diff_calc(uint64_t curr_time, uint64_t comp_time, uint32_t *time_diff, bool future); +/** + * ws_pae_time_old_or_new_select selected old or new time (based on difference) + * + * \param old_time old time + * \param new_time new time + * + * \return old or new time + * + */ +uint64_t ws_pae_time_old_or_new_select(uint64_t old_time, uint64_t new_time); + +/** + * ws_pae_time_old_and_new_validate validate old and new time (based on difference) + * + * \param old_time old time + * \param new_time new time + * + * \return TRUE old time is valid, FALSE old time is not valid + * + */ +bool ws_pae_time_old_and_new_validate(uint64_t old_time, uint64_t new_time); + /** * ws_pae_current_time_get gets current time * @@ -96,7 +118,7 @@ int8_t ws_pae_time_diff_calc(uint64_t curr_time, uint64_t comp_time, uint32_t *t uint64_t ws_pae_current_time_get(void); /** - * ws_pae_current_time_get updates current time + * ws_pae_current_time_update updates current time * * \param seconds seconds to be added to current time * @@ -104,13 +126,13 @@ uint64_t ws_pae_current_time_get(void); void ws_pae_current_time_update(uint16_t seconds); /** - * ws_pae_current_time_set sets current time + * ws_pae_stored_time_check_and_set stored time check and set current time * - * \param time new time + * \param stored_time stored time * * \return < 0 failure * \return >= 0 success */ -int8_t ws_pae_current_time_set(uint64_t time); +int8_t ws_pae_stored_time_check_and_set(uint64_t stored_time); #endif /* WS_PAE_KEY_STORAGE_H_ */ diff --git a/source/6LoWPAN/ws/ws_phy.c b/source/6LoWPAN/ws/ws_phy.c new file mode 100644 index 0000000000..d6d84709a7 --- /dev/null +++ b/source/6LoWPAN/ws/ws_phy.c @@ -0,0 +1,353 @@ +/* + * Copyright (c) 2021, Pelion and affiliates. + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include "nsconfig.h" +#include "ns_types.h" +#include "ns_trace.h" +#include "ws_management_api.h" + +#ifdef HAVE_WS +#define TRACE_GROUP "wsph" + +uint32_t ws_phy_decode_channel_spacing(uint8_t channel_spacing) +{ + if (CHANNEL_SPACING_100 == channel_spacing) { + return 100000; + } else if (CHANNEL_SPACING_200 == channel_spacing) { + return 200000; + } else if (CHANNEL_SPACING_250 == channel_spacing) { + return 250000; + } else if (CHANNEL_SPACING_400 == channel_spacing) { + return 400000; + } else if (CHANNEL_SPACING_600 == channel_spacing) { + return 600000; + } else if (CHANNEL_SPACING_800 == channel_spacing) { + return 800000; + } else if (CHANNEL_SPACING_1200 == channel_spacing) { + return 1200000; + } + return 0; +} + +uint32_t ws_phy_get_datarate_using_operating_mode(uint8_t operating_mode) +{ + if ((OPERATING_MODE_1a == operating_mode) || (OPERATING_MODE_1b == operating_mode)) { + return 50000; + } else if ((OPERATING_MODE_2a == operating_mode) || (OPERATING_MODE_2b == operating_mode)) { + return 100000; + } else if (OPERATING_MODE_3 == operating_mode) { + return 150000; + } else if ((OPERATING_MODE_4a == operating_mode) || (OPERATING_MODE_4b == operating_mode)) { + return 200000; + } else if (OPERATING_MODE_5 == operating_mode) { + return 300000; + } + return 0; +} + +uint8_t ws_phy_convert_operating_class_to_channel_plan_id(uint8_t operating_class, uint8_t regulatory_domain) +{ + if (regulatory_domain == REG_DOMAIN_KR) { + + } else if (regulatory_domain == REG_DOMAIN_EU) { + if ((operating_class == 1) || (operating_class == 2) || (operating_class == 3) || (operating_class == 4)) { + return operating_class + 31; + } + } else if (regulatory_domain == REG_DOMAIN_IN) { + + } else if ((regulatory_domain == REG_DOMAIN_NA) || (regulatory_domain == REG_DOMAIN_BZ)) { + if ((operating_class == 1) || (operating_class == 2) || (operating_class == 3)) { + return operating_class; + } + } else if (regulatory_domain == REG_DOMAIN_JP) { + + } else if (regulatory_domain == REG_DOMAIN_WW) { + + } + + return 0; +} + +uint8_t ws_phy_convert_operating_mode_to_phy_mode_id(uint8_t operating_mode) +{ + if (OPERATING_MODE_1a == operating_mode) { + return 1; + } else if (OPERATING_MODE_1b == operating_mode) { + return 2; + } else if (OPERATING_MODE_2a == operating_mode) { + return 3; + } else if (OPERATING_MODE_2b == operating_mode) { + return 4; + } else if (OPERATING_MODE_3 == operating_mode) { + return 5; + } else if (OPERATING_MODE_4a == operating_mode) { + return 6; + } else if (OPERATING_MODE_4b == operating_mode) { + return 7; + } else if (OPERATING_MODE_5 == operating_mode) { + return 8; + } + return 0; +} + +uint32_t ws_phy_get_datarate_using_phy_mode_id(uint8_t phy_mode_id) +{ + if (84 == phy_mode_id) { + return 150000; + } else if (85 == phy_mode_id) { + return 200000; + } else if ((68 == phy_mode_id) || (86 == phy_mode_id)) { + return 300000; + } else if ((34 == phy_mode_id) || (51 == phy_mode_id) || (69 == phy_mode_id)) { + return 400000; + } else if ((52 == phy_mode_id) || (70 == phy_mode_id)) { + return 600000; + } else if ((35 == phy_mode_id) || (53 == phy_mode_id)) { + return 800000; + } else if ((36 == phy_mode_id) || (54 == phy_mode_id)) { + return 1200000; + } else if (37 == phy_mode_id) { + return 1600000; + } else if (38 == phy_mode_id) { + return 2400000; + } else if ((1 == phy_mode_id) || (2 == phy_mode_id) || (17 == phy_mode_id) || (18 == phy_mode_id)) { + return 50000; + } else if ((3 == phy_mode_id) || (4 == phy_mode_id) || (19 == phy_mode_id) || (20 == phy_mode_id)) { + return 100000; + } else if ((5 == phy_mode_id) || (21 == phy_mode_id)) { + return 150000; + } else if ((6 == phy_mode_id) || (7 == phy_mode_id) || (22 == phy_mode_id) || (23 == phy_mode_id)) { + return 200000; + } else if ((8 == phy_mode_id) || (24 == phy_mode_id)) { + return 300000; + } + return 0; +} + +uint8_t ws_phy_get_ofdm_option_using_phy_mode_id(uint8_t phy_mode_id) +{ + if ((phy_mode_id >= 34) && (phy_mode_id <= 38)) { + return OFDM_OPTION_1; + } else if ((phy_mode_id >= 51) && (phy_mode_id <= 54)) { + return OFDM_OPTION_2; + } else if ((phy_mode_id >= 68) && (phy_mode_id <= 70)) { + return OFDM_OPTION_3; + } else if ((phy_mode_id >= 84) && (phy_mode_id <= 86)) { + return OFDM_OPTION_4; + } + return 0; +} + +uint8_t ws_phy_get_ofdm_mcs_using_phy_mode_id(uint8_t phy_mode_id) +{ + if (34 == phy_mode_id) { + return OFDM_MCS_2; + } else if ((35 == phy_mode_id) || (51 == phy_mode_id)) { + return OFDM_MCS_3; + } else if ((36 == phy_mode_id) || (52 == phy_mode_id) || (68 == phy_mode_id) || (84 == phy_mode_id)) { + return OFDM_MCS_4; + } else if ((37 == phy_mode_id) || (53 == phy_mode_id) || (69 == phy_mode_id) || (85 == phy_mode_id)) { + return OFDM_MCS_5; + } else if ((38 == phy_mode_id) || (54 == phy_mode_id) || (70 == phy_mode_id) || (86 == phy_mode_id)) { + return OFDM_MCS_6; + } + return 0; +} + +uint8_t ws_phy_get_channel_plan_id_using_phy_mode_id(uint8_t phy_mode_id, uint8_t regulatory_domain, uint8_t base_channel_plan_id) +{ + if (regulatory_domain == REG_DOMAIN_KR) { + + } else if (regulatory_domain == REG_DOMAIN_EU) { + // As on EU domain the PHY mode ID cannot unambiguously define the used channel plan id, use the one which best matches to the base channel plan id + if ((base_channel_plan_id == 32) || (base_channel_plan_id == 33)) { + if ((phy_mode_id == 1) || (phy_mode_id == 17)) { + return 32; + } else if ((phy_mode_id == 3) || (phy_mode_id == 5) || (phy_mode_id == 19) || (phy_mode_id == 21) || ((phy_mode_id >= 84) && (phy_mode_id <= 86))) { + return 33; + } + } else if ((base_channel_plan_id == 36) || (base_channel_plan_id == 37)) { + if ((phy_mode_id == 1) || (phy_mode_id == 17)) { + return 36; + } else if ((phy_mode_id == 3) || (phy_mode_id == 5) || (phy_mode_id == 19) || (phy_mode_id == 21) || ((phy_mode_id >= 84) && (phy_mode_id <= 86))) { + return 37; + } + } else if ((base_channel_plan_id == 34) || (base_channel_plan_id == 35)) { + if ((phy_mode_id == 1) || (phy_mode_id == 17)) { + return 34; + } else if ((phy_mode_id == 3) || (phy_mode_id == 5) || (phy_mode_id == 19) || (phy_mode_id == 21) || ((phy_mode_id >= 84) && (phy_mode_id <= 86))) { + return 35; + } + } + } else if (regulatory_domain == REG_DOMAIN_IN) { + + } else if ((regulatory_domain == REG_DOMAIN_NA) || (regulatory_domain == REG_DOMAIN_BZ)) { + if ((phy_mode_id == 2) || (phy_mode_id == 3) || (phy_mode_id == 18) || (phy_mode_id == 19) || ((phy_mode_id >= 84) && (phy_mode_id <= 86))) { + return 1; + } else if ((phy_mode_id == 5) || (phy_mode_id == 6) || (phy_mode_id == 21) || (phy_mode_id == 22) || ((phy_mode_id >= 68) && (phy_mode_id <= 70))) { + return 2; + } else if ((phy_mode_id == 8) || (phy_mode_id == 24)) { + return 3; + } else if ((phy_mode_id >= 51) && (phy_mode_id <= 54)) { + return 4; + } else if ((phy_mode_id >= 34) && (phy_mode_id <= 38)) { + return 5; + } + } else if (regulatory_domain == REG_DOMAIN_JP) { + + } else if (regulatory_domain == REG_DOMAIN_WW) { + + } + + return 0; +} + +uint16_t ws_phy_get_number_of_channels_using_channel_plan_id(uint8_t channel_plan_id) +{ + if (channel_plan_id == 1) { + return 129; + } else if (channel_plan_id == 2) { + return 64; + } else if (channel_plan_id == 3) { + return 42; + } else if (channel_plan_id == 4) { + return 32; + } else if (channel_plan_id == 5) { + return 21; + } else if (channel_plan_id == 32) { + return 69; + } else if (channel_plan_id == 33) { + return 35; + } else if (channel_plan_id == 34) { + return 55; + } else if (channel_plan_id == 35) { + return 27; + } else if (channel_plan_id == 36) { + return 125; + } else if (channel_plan_id == 37) { + return 62; + } + + return 0; +} + +uint32_t ws_phy_get_channel_spacing_using_channel_plan_id(uint8_t channel_plan_id) +{ + if (channel_plan_id == 1) { + return 200000; + } else if (channel_plan_id == 2) { + return 400000; + } else if (channel_plan_id == 3) { + return 600000; + } else if (channel_plan_id == 4) { + return 800000; + } else if (channel_plan_id == 5) { + return 1200000; + } else if (channel_plan_id == 32) { + return 100000; + } else if (channel_plan_id == 33) { + return 200000; + } else if (channel_plan_id == 34) { + return 100000; + } else if (channel_plan_id == 35) { + return 200000; + } else if (channel_plan_id == 36) { + return 100000; + } else if (channel_plan_id == 37) { + return 200000; + } + + return 0; +} + +uint32_t ws_phy_get_channel_0_frequency_using_channel_plan_id(uint8_t channel_plan_id) +{ + if (channel_plan_id == 1) { + return 902200000; + } else if (channel_plan_id == 2) { + return 902400000; + } else if (channel_plan_id == 3) { + return 902600000; + } else if (channel_plan_id == 4) { + return 902800000; + } else if (channel_plan_id == 5) { + return 903200000; + } else if (channel_plan_id == 32) { + return 863100000; + } else if (channel_plan_id == 33) { + return 863100000; + } else if (channel_plan_id == 34) { + return 870100000; + } else if (channel_plan_id == 35) { + return 870200000; + } else if (channel_plan_id == 36) { + return 863100000; + } else if (channel_plan_id == 37) { + return 863100000; + } + + return 0; +} + +bool ws_phy_get_fsk_fec_enabled_using_phy_mode_id(uint8_t phy_mode_id) +{ + if ((phy_mode_id >= 17) && (phy_mode_id <= 24)) { + return true; + } + return false; +} + +phy_modulation_e ws_phy_get_modulation_using_phy_mode_id(uint8_t phy_mode_id) +{ + if (((phy_mode_id >= 34) && (phy_mode_id <= 38)) || + ((phy_mode_id >= 51) && (phy_mode_id <= 54)) || + ((phy_mode_id >= 68) && (phy_mode_id <= 70)) || + ((phy_mode_id >= 84) && (phy_mode_id <= 86))) { + return M_OFDM; + } else if (((phy_mode_id >= 1) && (phy_mode_id <= 8)) || ((phy_mode_id >= 17) && (phy_mode_id <= 24))) { + return M_2FSK; + } else { + return M_UNDEFINED; + } +} + +phy_modulation_index_e ws_phy_get_modulation_index_using_phy_mode_id(uint8_t phy_mode_id) +{ + if (ws_phy_get_modulation_using_phy_mode_id(phy_mode_id) != M_2FSK) { + return MODULATION_INDEX_UNDEFINED; + } + + if ((2 == phy_mode_id) || (18 == phy_mode_id) || + (4 == phy_mode_id) || (20 == phy_mode_id) || + (7 == phy_mode_id) || (23 == phy_mode_id)) { + return MODULATION_INDEX_1_0; + } + return MODULATION_INDEX_0_5; +} + +phy_modulation_index_e ws_phy_get_modulation_index_using_operating_mode(uint8_t operating_mode) +{ + if ((OPERATING_MODE_1b == operating_mode) || (OPERATING_MODE_2b == operating_mode) || (OPERATING_MODE_4b == operating_mode)) { + return MODULATION_INDEX_1_0; + } else { + return MODULATION_INDEX_0_5; + } +} + + +#endif //HAVE_WS diff --git a/source/6LoWPAN/ws/ws_phy.h b/source/6LoWPAN/ws/ws_phy.h new file mode 100644 index 0000000000..5b4603e720 --- /dev/null +++ b/source/6LoWPAN/ws/ws_phy.h @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2021, Pelion and affiliates. + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef WS_PHY_H_ +#define WS_PHY_H_ + +uint32_t ws_phy_decode_channel_spacing(uint8_t channel_spacing); + +uint32_t ws_phy_get_datarate_using_operating_mode(uint8_t operating_mode); + +uint8_t ws_phy_convert_operating_class_to_channel_plan_id(uint8_t operating_class, uint8_t regulatory_domain); + +uint8_t ws_phy_convert_operating_mode_to_phy_mode_id(uint8_t operating_mode); + +uint8_t ws_phy_get_channel_plan_id_using_phy_mode_id(uint8_t phy_mode_id, uint8_t regulatory_domain, uint8_t base_channel_plan_id); + +uint32_t ws_phy_get_datarate_using_phy_mode_id(uint8_t phy_mode_id); + +uint8_t ws_phy_get_ofdm_option_using_phy_mode_id(uint8_t phy_mode_id); + +uint8_t ws_phy_get_ofdm_mcs_using_phy_mode_id(uint8_t phy_mode_id); + +uint16_t ws_phy_get_number_of_channels_using_channel_plan_id(uint8_t channel_plan_id); + +uint32_t ws_phy_get_channel_spacing_using_channel_plan_id(uint8_t channel_plan_id); + +uint32_t ws_phy_get_channel_0_frequency_using_channel_plan_id(uint8_t channel_plan_id); + +bool ws_phy_get_fsk_fec_enabled_using_phy_mode_id(uint8_t phy_mode_id); + +phy_modulation_e ws_phy_get_modulation_using_phy_mode_id(uint8_t phy_mode_id); + +phy_modulation_index_e ws_phy_get_modulation_index_using_phy_mode_id(uint8_t phy_mode_id); + +phy_modulation_index_e ws_phy_get_modulation_index_using_operating_mode(uint8_t operating_mode); + +#endif //WS_PHY_H_ diff --git a/source/6LoWPAN/ws/ws_test_api.c b/source/6LoWPAN/ws/ws_test_api.c index 9dd322a752..4dc5d394b1 100644 --- a/source/6LoWPAN/ws/ws_test_api.c +++ b/source/6LoWPAN/ws/ws_test_api.c @@ -21,6 +21,7 @@ #include "ns_list.h" #include "nsdynmemLIB.h" #include "net_ws_test.h" +#include "net_ws_test_ext.h" #include "fhss_config.h" #include "ws_management_api.h" #include "mac_api.h" @@ -32,6 +33,7 @@ #include "6LoWPAN/ws/ws_bbr_api_internal.h" #include "6LoWPAN/ws/ws_pae_controller.h" #include "6LoWPAN/ws/ws_cfg_settings.h" +#include "6LoWPAN/ws/ws_bootstrap.h" #include "randLIB.h" #include "ns_trace.h" @@ -41,6 +43,25 @@ #ifdef HAVE_WS +int ws_test_version_set(int8_t interface_id, uint8_t version) +{ + test_pan_version = version; + + protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(interface_id); + if (cur) { + if (!ws_info(cur)) { + return -1; + } + cur->ws_info->version = version; + if (ws_version_1_0(cur)) { + cur->ws_info->pan_information.version = WS_FAN_VERSION_1_0; + } else if (ws_version_1_1(cur)) { + cur->ws_info->pan_information.version = WS_FAN_VERSION_1_1; + } + } + return 0; +} + int ws_test_pan_size_set(int8_t interface_id, uint16_t pan_size) { @@ -88,7 +109,7 @@ int ws_test_key_lifetime_set(int8_t interface_id, uint32_t gtk_lifetime, uint32_ } ws_sec_timer_cfg_t cfg; - if (ws_cfg_sec_timer_get(&cfg, NULL) < 0) { + if (ws_cfg_sec_timer_get(&cfg) < 0) { return -2; } @@ -102,7 +123,7 @@ int ws_test_key_lifetime_set(int8_t interface_id, uint32_t gtk_lifetime, uint32_ cfg.ptk_lifetime = ptk_lifetime; } - if (ws_cfg_sec_timer_set(cur, NULL, &cfg, NULL) < 0) { + if (ws_cfg_sec_timer_set(cur, &cfg, 0x00) < 0) { return -3; } @@ -119,7 +140,7 @@ int ws_test_gtk_time_settings_set(int8_t interface_id, uint8_t revocat_lifetime_ } ws_sec_timer_cfg_t cfg; - if (ws_cfg_sec_timer_get(&cfg, NULL) < 0) { + if (ws_cfg_sec_timer_get(&cfg) < 0) { return -2; } @@ -136,7 +157,7 @@ int ws_test_gtk_time_settings_set(int8_t interface_id, uint8_t revocat_lifetime_ cfg.gtk_max_mismatch = max_mismatch; } - if (ws_cfg_sec_timer_set(cur, NULL, &cfg, NULL) < 0) { + if (ws_cfg_sec_timer_set(cur, &cfg, 0x00) < 0) { return -3; } @@ -177,4 +198,27 @@ int ws_test_neighbour_temporary_lifetime_set(int8_t interface_id, uint32_t tempo return 0; } +int ws_test_procedure_trigger(int8_t interface_id, ws_test_proc_t procedure, void *parameters) +{ + (void) parameters; + + protocol_interface_info_entry_t *cur = NULL;; + + if (interface_id > 0) { + cur = protocol_stack_interface_info_get_by_id(interface_id); + if (!cur || !ws_info(cur)) { + return -1; + } + } else { + cur = protocol_stack_interface_info_get_wisun_mesh(); + if (!cur) { + if (procedure != PROC_AUTO_ON && procedure != PROC_AUTO_OFF) { + return -1; + } + } + } + + return ws_bootstrap_test_procedure_trigger(cur, procedure); +} + #endif // HAVE_WS diff --git a/source/BorderRouter/border_router.c b/source/BorderRouter/border_router.c index 02836da0d8..00964f3a19 100644 --- a/source/BorderRouter/border_router.c +++ b/source/BorderRouter/border_router.c @@ -114,7 +114,7 @@ void nd_border_router_setup_refresh(nwk_interface_id id, bool fresh_abro) nd_router_object->life_time = nd_configure->life_time; if (!ns_list_is_empty(&nd_router_object->prefix_list)) { - tr_debug("Release Prefix\n"); + tr_debug("Release Prefix"); icmpv6_prefix_list_free(&nd_router_object->prefix_list); } diff --git a/source/Core/ns_address_internal.c b/source/Core/ns_address_internal.c index c7c69d2d39..023ce2880e 100644 --- a/source/Core/ns_address_internal.c +++ b/source/Core/ns_address_internal.c @@ -371,7 +371,7 @@ void addr_policy_table_print(void) ns_list_foreach(addr_policy_table_entry_t, entry, &addr_policy_table) { char addr[40]; ip6tos(entry->prefix, addr); - tr_debug("%3d %3d %s/%u\n", entry->precedence, entry->label, addr, entry->prefix_len); + tr_debug("%3d %3d %s/%u", entry->precedence, entry->label, addr, entry->prefix_len); } } diff --git a/source/Core/ns_socket.c b/source/Core/ns_socket.c index 77dade5ccf..d91c03d0d3 100644 --- a/source/Core/ns_socket.c +++ b/source/Core/ns_socket.c @@ -834,12 +834,12 @@ void socket_list_print(route_print_fn_t *print_fn, char sep) /* Chuck in a consistency check */ for (int i = 0; i < SOCKETS_MAX; i++) { if (socket_instance[i] && socket_instance[i]->id != i) { - tr_err("ID %d points to %p with id %d\n", i, (void *)socket_instance[i], socket_instance[i]->id); + tr_err("ID %d points to %p with id %d", i, (void *)socket_instance[i], socket_instance[i]->id); } } ns_list_foreach(socket_t, socket, &socket_list) { if (socket->id != -1 && socket_pointer_get(socket->id) != socket) { - tr_err("Socket %p has invalid ID %d\n", (void *)socket, socket->id); + tr_err("Socket %p has invalid ID %d", (void *)socket, socket->id); } sockbuf_check(&socket->rcvq); sockbuf_check(&socket->sndq); diff --git a/source/DHCPv6_client/dhcpv6_client_service.c b/source/DHCPv6_client/dhcpv6_client_service.c index 15b2dbe4cc..6000e85445 100644 --- a/source/DHCPv6_client/dhcpv6_client_service.c +++ b/source/DHCPv6_client/dhcpv6_client_service.c @@ -212,7 +212,7 @@ void dhcp_client_delete(int8_t interface) do { srv_data_ptr = libdhcpv6_nonTemporal_entry_get_by_instance(dhcp_client->libDhcp_instance); if (srv_data_ptr != NULL) { - tr_debug("Free DHCPv6 Client\n"); + tr_debug("Free DHCPv6 Client"); memcpy(temporary_address, srv_data_ptr->iaNontemporalAddress.addressPrefix, 16); dhcp_service_req_remove_all(srv_data_ptr);// remove all pending retransmissions libdhcvp6_nontemporalAddress_server_data_free(srv_data_ptr); diff --git a/source/MAC/IEEE802_15_4/mac_cca_threshold.c b/source/MAC/IEEE802_15_4/mac_cca_threshold.c index 1b3a94253b..f4ce92fbe4 100644 --- a/source/MAC/IEEE802_15_4/mac_cca_threshold.c +++ b/source/MAC/IEEE802_15_4/mac_cca_threshold.c @@ -137,7 +137,7 @@ int8_t mac_cca_threshold_update(protocol_interface_rf_mac_setup_s *rf_ptr, uint8 return -1; } } - tr_debug("Channel %u CCA threshold to %i", channel, rf_ptr->cca_threshold->ch_thresholds[channel]); + tr_info("Channel %u CCA threshold to %i", channel, rf_ptr->cca_threshold->ch_thresholds[channel]); return 0; } diff --git a/source/MAC/IEEE802_15_4/mac_data_buffer.h b/source/MAC/IEEE802_15_4/mac_data_buffer.h index a76016cb4d..f3d97a04a0 100644 --- a/source/MAC/IEEE802_15_4/mac_data_buffer.h +++ b/source/MAC/IEEE802_15_4/mac_data_buffer.h @@ -96,6 +96,7 @@ typedef struct mac_pre_build_frame { uint8_t cca_request_restart_cnt; uint8_t tx_request_restart_cnt; uint8_t priority; + uint8_t phy_mode_id; uint32_t blacklist_start_time_us; uint16_t blacklist_period_ms; uint16_t initial_tx_channel; diff --git a/source/MAC/IEEE802_15_4/mac_defines.h b/source/MAC/IEEE802_15_4/mac_defines.h index c55b5085f4..ee76ad67ad 100644 --- a/source/MAC/IEEE802_15_4/mac_defines.h +++ b/source/MAC/IEEE802_15_4/mac_defines.h @@ -43,7 +43,8 @@ typedef enum mac_event_t { MAC_ACK_SECURITY_FAIL, MAC_UNKNOWN_DESTINATION, MAC_TX_PRECOND_FAIL, - MAC_RETURN_TO_QUEUE + MAC_RETURN_TO_QUEUE, + MAC_MODE_SWITCH_TIMEOUT } mac_event_t; typedef enum mac_tx_status_type_t { @@ -95,11 +96,21 @@ typedef enum arm_nwk_mlme_event_type { ARM_NWK_MAC_MLME_INDIRECT_DATA_POLL_AFTER_DATA = 5, } arm_nwk_mlme_event_type_e; +typedef enum mac_mode_switch_states { + MAC_MS_IDLE = 0, + MAC_MS_PHR_SEND_READY, + MAC_MS_DATA_SEND_READY, + MAC_MS_PHR_RECEIVED, + MAC_MS_DATA_RECEIVED, + MAC_MS_TIMEOUT +} mac_mode_switch_states_e; + #define ENHANCED_ACK_MAX_LENGTH 255 typedef struct dev_driver_tx_buffer { uint8_t *buf; uint8_t *enhanced_ack_buf; + uint8_t mode_switch_phr_buf[2]; uint16_t ack_len; uint16_t len; unsigned priority: 2; @@ -180,6 +191,7 @@ typedef struct protocol_interface_rf_mac_setup { bool mac_ack_tx_active: 1; bool mac_edfe_tx_active: 1; bool mac_edfe_response_tx_active: 1; + bool mac_mode_switch_phr_tx_active: 1; bool mac_frame_pending: 1; /* MAC Capability Information */ bool macCapRxOnIdle: 1; @@ -228,6 +240,8 @@ typedef struct protocol_interface_rf_mac_setup { uint8_t mac_channel; uint8_t mac_tx_start_channel; + uint8_t base_phy_mode; + mac_mode_switch_states_e mode_switch_state; //uint8_t cca_failure; /* MAC TX Queue */ diff --git a/source/MAC/IEEE802_15_4/mac_mcps_sap.c b/source/MAC/IEEE802_15_4/mac_mcps_sap.c index 6e952174f4..145d43bf10 100644 --- a/source/MAC/IEEE802_15_4/mac_mcps_sap.c +++ b/source/MAC/IEEE802_15_4/mac_mcps_sap.c @@ -48,6 +48,7 @@ #include "MAC/IEEE802_15_4/mac_header_helper_functions.h" #include "MAC/IEEE802_15_4/mac_indirect_data.h" #include "MAC/IEEE802_15_4/mac_cca_threshold.h" +#include "MAC/IEEE802_15_4/mac_mode_switch.h" #include "MAC/rf_driver_storage.h" #include "sw_mac.h" @@ -156,7 +157,7 @@ void mcps_sap_data_req_handler(protocol_interface_rf_mac_setup_s *rf_mac_setup, { mcps_data_req_ie_list_t ie_list; memset(&ie_list, 0, sizeof(mcps_data_req_ie_list_t)); - mcps_sap_data_req_handler_ext(rf_mac_setup, data_req, &ie_list, NULL, MAC_DATA_NORMAL_PRIORITY); + mcps_sap_data_req_handler_ext(rf_mac_setup, data_req, &ie_list, NULL, MAC_DATA_NORMAL_PRIORITY, 0); } static bool mac_ie_vector_length_validate(ns_ie_iovec_t *ie_vector, uint16_t iov_length, uint16_t *length_out) @@ -195,8 +196,9 @@ static bool mac_ie_vector_length_validate(ns_ie_iovec_t *ie_vector, uint16_t iov } -void mcps_sap_data_req_handler_ext(protocol_interface_rf_mac_setup_s *rf_mac_setup, const mcps_data_req_t *data_req, const mcps_data_req_ie_list_t *ie_list, const channel_list_s *asynch_channel_list, mac_data_priority_t priority) +void mcps_sap_data_req_handler_ext(protocol_interface_rf_mac_setup_s *rf_mac_setup, const mcps_data_req_t *data_req, const mcps_data_req_ie_list_t *ie_list, const channel_list_s *asynch_channel_list, mac_data_priority_t priority, uint8_t phy_mode_id) { + (void) phy_mode_id; uint8_t status = MLME_SUCCESS; mac_pre_build_frame_t *buffer = NULL; @@ -292,6 +294,7 @@ void mcps_sap_data_req_handler_ext(protocol_interface_rf_mac_setup_s *rf_mac_set buffer->fcf_dsn.frametype = FC_DATA_FRAME; buffer->ExtendedFrameExchange = data_req->ExtendedFrameExchange; buffer->WaitResponse = data_req->TxAckReq; + buffer->phy_mode_id = phy_mode_id; if (data_req->ExtendedFrameExchange) { buffer->fcf_dsn.ackRequested = false; } else { @@ -1106,6 +1109,10 @@ static void mac_mcps_asynch_finish(protocol_interface_rf_mac_setup_s *rf_mac_set static bool mcps_sap_check_buffer_timeout(protocol_interface_rf_mac_setup_s *rf_mac_setup, mac_pre_build_frame_t *buffer) { + // Timestamp is not implemented by virtual RF driver. Do not check buffer age. + if (rf_mac_setup->dev_driver->phy_driver->arm_net_virtual_tx_cb) { + return false; + } // Convert from 1us slots to seconds uint32_t buffer_age_s = (mac_mcps_sap_get_phy_timestamp(rf_mac_setup) - buffer->request_start_time_us) / 1000000; // Do not timeout broadcast frames. Broadcast interval could be very long. @@ -1834,6 +1841,12 @@ static int8_t mcps_generic_packet_build(protocol_interface_rf_mac_setup_s *rf_pt mac_security_authentication_data_params_set(&ccm_ptr, mhr_start, (buffer->mac_header_length_with_security + open_payload)); ccm_process_run(&ccm_ptr); } + // Packet is sent using mode switch. Build mode switch PHR + if (buffer->phy_mode_id) { + if (mac_build_mode_switch_phr(rf_ptr, tx_buf->mode_switch_phr_buf, buffer->phy_mode_id)) { + return -1; + } + } return 0; } @@ -2083,6 +2096,7 @@ int8_t mcps_generic_ack_build(protocol_interface_rf_mac_setup_s *rf_ptr, bool in phy_csma_params_t csma_params; csma_params.backoff_time = 0; csma_params.cca_enabled = false; + csma_params.mode_switch_phr = false; rf_ptr->dev_driver->phy_driver->extension(PHY_EXTENSION_SET_CSMA_PARAMETERS, (uint8_t *) &csma_params); if (rf_ptr->active_pd_data_request) { timer_mac_stop(rf_ptr); @@ -2197,8 +2211,10 @@ static int8_t mcps_pd_data_cca_trig(protocol_interface_rf_mac_setup_s *rf_ptr, m rf_ptr->mac_edfe_tx_active = true; } + } else if (buffer->phy_mode_id) { + rf_ptr->mac_mode_switch_phr_tx_active = true; + cca_enabled = true; } else { - if (rf_ptr->mac_ack_tx_active) { mac_csma_backoff_start(rf_ptr); platform_exit_critical(); @@ -2209,13 +2225,13 @@ static int8_t mcps_pd_data_cca_trig(protocol_interface_rf_mac_setup_s *rf_ptr, m } // Use double CCA check with FHSS for data packets only - if (rf_ptr->fhss_api && !rf_ptr->mac_ack_tx_active && !rf_ptr->mac_edfe_tx_active && !rf_ptr->active_pd_data_request->asynch_request) { + if (rf_ptr->fhss_api && !rf_ptr->mac_ack_tx_active && !rf_ptr->mac_edfe_tx_active && !rf_ptr->active_pd_data_request->asynch_request && !rf_ptr->mac_mode_switch_phr_tx_active) { if ((buffer->tx_time - (rf_ptr->multi_cca_interval * (rf_ptr->number_of_csma_ca_periods - 1))) > mac_mcps_sap_get_phy_timestamp(rf_ptr)) { buffer->csma_periods_left = rf_ptr->number_of_csma_ca_periods - 1; buffer->tx_time -= (rf_ptr->multi_cca_interval * (rf_ptr->number_of_csma_ca_periods - 1)); } } - mac_pd_sap_set_phy_tx_time(rf_ptr, buffer->tx_time, cca_enabled); + mac_pd_sap_set_phy_tx_time(rf_ptr, buffer->tx_time, cca_enabled, rf_ptr->mac_mode_switch_phr_tx_active); if (mac_plme_cca_req(rf_ptr) != 0) { if (buffer->fcf_dsn.frametype == MAC_FRAME_ACK || (buffer->ExtendedFrameExchange && rf_ptr->mac_edfe_response_tx_active)) { //ACK or EFDE Response diff --git a/source/MAC/IEEE802_15_4/mac_mcps_sap.h b/source/MAC/IEEE802_15_4/mac_mcps_sap.h index 94247d58b8..db986d26ee 100644 --- a/source/MAC/IEEE802_15_4/mac_mcps_sap.h +++ b/source/MAC/IEEE802_15_4/mac_mcps_sap.h @@ -123,7 +123,7 @@ int8_t mac_virtual_sap_data_cb(void *identifier, struct arm_phy_sap_msg_s *messa void mcps_sap_data_req_handler(struct protocol_interface_rf_mac_setup *rf_mac_setup, const struct mcps_data_req_s *data_req); -void mcps_sap_data_req_handler_ext(struct protocol_interface_rf_mac_setup *rf_mac_setup, const struct mcps_data_req_s *data_req, const struct mcps_data_req_ie_list *ie_list, const channel_list_s *asynch_channel_list, mac_data_priority_t priority); +void mcps_sap_data_req_handler_ext(struct protocol_interface_rf_mac_setup *rf_mac_setup, const struct mcps_data_req_s *data_req, const struct mcps_data_req_ie_list *ie_list, const channel_list_s *asynch_channel_list, mac_data_priority_t priority, uint8_t phy_mode_id); void mac_mcps_trig_buffer_from_queue(struct protocol_interface_rf_mac_setup *rf_mac_setup); diff --git a/source/MAC/IEEE802_15_4/mac_mlme.c b/source/MAC/IEEE802_15_4/mac_mlme.c index 9d39b35202..cbc6682020 100644 --- a/source/MAC/IEEE802_15_4/mac_mlme.c +++ b/source/MAC/IEEE802_15_4/mac_mlme.c @@ -826,7 +826,7 @@ int8_t mac_mlme_set_req(protocol_interface_rf_mac_setup_s *rf_mac_setup, const m case macCCAThreshold: pu8 = (uint8_t *) set_req->value_pointer; rf_mac_setup->dev_driver->phy_driver->extension(PHY_EXTENSION_SET_CCA_THRESHOLD, pu8); - tr_debug("Set CCA threshold to %u%%", *pu8); + tr_info("Set CCA threshold to %u%%", *pu8); return 0; case macMultiCSMAParameters: return mac_mlme_set_multi_csma_parameters(rf_mac_setup, set_req); diff --git a/source/MAC/IEEE802_15_4/mac_mode_switch.c b/source/MAC/IEEE802_15_4/mac_mode_switch.c new file mode 100644 index 0000000000..4fe0963702 --- /dev/null +++ b/source/MAC/IEEE802_15_4/mac_mode_switch.c @@ -0,0 +1,240 @@ +/* + * Copyright (c) 2021, Pelion and affiliates. + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "string.h" +#include "nsconfig.h" +#include "ns_types.h" +#include "ns_trace.h" +#include "common_functions.h" +#include "mac_api.h" +#include "MAC/IEEE802_15_4/sw_mac_internal.h" +#include "MAC/IEEE802_15_4/mac_defines.h" +#include "MAC/IEEE802_15_4/mac_mode_switch.h" +#include "MAC/IEEE802_15_4/mac_mcps_sap.h" +#include "MAC/IEEE802_15_4/mac_timer.h" +#include "MAC/rf_driver_storage.h" + +#define TRACE_GROUP "mswc" + +static uint8_t mac_calculate_mode_switch_parity(uint16_t mode_switch_phr) +{ + uint8_t counter = 0; + // Calculate number of 1-bits in (15-bit) input and return modulo-2 of the sum + for (int i = 0; i < 15; i++) { + if (mode_switch_phr & (1 << i)) { + counter++; + } + } + return counter % 2; +} +/* + * 11-bit input must be padded with 4 leading zeroes. + * Reverse the 15-bit result and divide with polynomial X⁴ + X + 1 -> 10011 + * Return remainder as checksum + * + * Example: + * Input: xxxxx01000000001 + * Padded input: x000001000000001 + * Reversed and padded input: 100000000100000x + * Calculated checksum: 0x0f (00001111) + * + * Division: + * + * 10011010101 <- Result + * ----------------- + * 10011 | 100000000100000 <- Highest bit (10000) is 1, add 1 in result + * 10011 <- 10011 * 1 + * ----- + * 00110 <- Highest bit (00110) is 0, add 0 in result + * 00000 <- 10011 * 0 + * ----- + * . + * . + * . + * ----- + * 11100 + * 10011 + * ---- + * 1111 <- Remainder + * + */ +static uint8_t mac_calculate_mode_switch_checksum(uint16_t mode_switch_phr) +{ + // X⁴ + X + 1 -> 0b10011 -> 0x13 + uint8_t polynomial = 0x13; + // Pad input with four leading zeroes + mode_switch_phr &= ~0x7800; + // Reverse input + uint16_t phr_reversed = 0; + for (int i = 0; i < 16; i++) { + if (mode_switch_phr & (1 << i)) { + phr_reversed |= 1 << (15 - i); + } + } + // Divide 15-bit padded and reversed input, use polynomial 10011 as the divider + uint8_t shift = 11; + uint8_t remainder = phr_reversed >> shift; + for (int i = 0; i < 11; i++) { + // Check highest bit + if (remainder & (1 << 4)) { + remainder ^= polynomial; + } else { + remainder ^= 0; + } + // Division ready, return remainder as checksum + if (!(--shift)) { + return remainder; + } + remainder <<= 1; + if (phr_reversed & (1 << shift)) { + remainder |= 1; + } + } + // Shouldn't go here + return 0; +} + +/* + * Mode switch PHR format: + * + * | 0 | 1-2 | 3-10 | 11-14 | 15 | + * |Mode Switch|Reserved|New Phy Mode ID|Checksum|Parity| + * + */ +int8_t mac_build_mode_switch_phr(protocol_interface_rf_mac_setup_s *rf_ptr, uint8_t *data_ptr, uint8_t phy_mode_id) +{ + (void) rf_ptr; + if (!data_ptr) { + return -1; + } + // - Write mode switch and PHY mode id fields + uint16_t mode_switch_phr = 1 << SHIFT_MODE_SWITCH; + mode_switch_phr |= phy_mode_id << SHIFT_MODE_SWITCH_PHY_MODE; + // - Calculate checksum + mode_switch_phr |= mac_calculate_mode_switch_checksum(mode_switch_phr) << SHIFT_MODE_SWITCH_CHECKSUM; + // - Calculate parity + mode_switch_phr |= mac_calculate_mode_switch_parity(mode_switch_phr) << SHIFT_MODE_SWITCH_PARITY; + + common_write_16_bit_inverse(mode_switch_phr, data_ptr); + + // - With successful return value, MAC should start CSMA-CA for a mode switch PHR + return 0; +} + +static int8_t mac_change_mode_switch_configuration(protocol_interface_rf_mac_setup_s *rf_ptr, uint8_t phy_mode_id, mac_mode_switch_states_e new_state) +{ + mac_api_t *mac_api = get_sw_mac_api(rf_ptr); + if (mac_api->mode_resolver_cb) { + phy_rf_channel_configuration_s rf_config; + memset(&rf_config, 0, sizeof(phy_rf_channel_configuration_s)); + if (!mac_api->mode_resolver_cb(mac_api, phy_mode_id, &rf_config)) { + rf_ptr->dev_driver->phy_driver->extension(PHY_EXTENSION_SET_RF_CONFIGURATION, (uint8_t *) &rf_config); + rf_ptr->mode_switch_state = new_state; + return 0; + } else { + tr_error("Mode switch could not resolve PHY mode ID %u", phy_mode_id); + } + } + return -1; +} + +static uint32_t mac_calculate_timeout(protocol_interface_rf_mac_setup_s *rf_ptr, uint8_t phy_mode_id) +{ + mac_api_t *mac_api = get_sw_mac_api(rf_ptr); + if (mac_api->mode_resolver_cb) { + phy_rf_channel_configuration_s rf_config; + memset(&rf_config, 0, sizeof(phy_rf_channel_configuration_s)); + if (!mac_api->mode_resolver_cb(mac_api, phy_mode_id, &rf_config)) { + // Calculate transmission time of max size packet + Ack size + max settling time + Tack + return ((uint64_t)(1200 + 100) * 8000000 / rf_config.datarate + 1500 + 5000); + } + } + // If could not resolve configuration, use 300ms as default timeout + return 300000; +} + +int8_t mac_parse_mode_switch_phr(protocol_interface_rf_mac_setup_s *rf_ptr, const uint8_t *data_ptr, uint16_t data_len) +{ + if (data_len != PHR_LEN) { + return -1; + } + if (!data_ptr) { + return -1; + } + + uint16_t mode_switch_phr = common_read_16_bit_inverse(data_ptr); + if (!(mode_switch_phr & MASK_MODE_SWITCH)) { + // Mode switch not enabled + return -1; + } + + // - Validate checksum + if (mac_calculate_mode_switch_checksum(mode_switch_phr) != ((mode_switch_phr & MASK_MODE_SWITCH_CHECKSUM) >> SHIFT_MODE_SWITCH_CHECKSUM)) { + // Invalid checksum, TODO: error correction + return -1; + } + // - Validate parity + if (mac_calculate_mode_switch_parity(mode_switch_phr) != (mode_switch_phr & MASK_MODE_SWITCH_PARITY) >> SHIFT_MODE_SWITCH_PARITY) { + // Invalid parity + return -1; + } + // - Read PHY mode id + uint8_t phy_mode_id = (mode_switch_phr & MASK_MODE_SWITCH_PHY_MODE) >> SHIFT_MODE_SWITCH_PHY_MODE; + + // When mode switch PHR was received, change new configuration here to wait data packet and set mode switch state machine to 'PHR received' + if (mac_change_mode_switch_configuration(rf_ptr, phy_mode_id, MAC_MS_PHR_RECEIVED)) { + return -1; + } + // Backup timer, if reception of data packet fails + timer_mac_start(rf_ptr, MAC_MODE_SWITCH_TIMEOUT, mac_calculate_timeout(rf_ptr, phy_mode_id) / 50); + return 0; +} + +int8_t mac_update_mode_switch_state(protocol_interface_rf_mac_setup_s *rf_ptr, mac_mode_switch_states_e state, uint8_t phy_mode_id) +{ + switch (state) { + case MAC_MS_PHR_SEND_READY: + // When mode switch PHR was sent, change new configuration here before transmitting data packet and set mode switch state machine to 'PHR send ready' + if (!mac_change_mode_switch_configuration(rf_ptr, phy_mode_id, MAC_MS_PHR_SEND_READY)) { + return 0; + } + break; + case MAC_MS_DATA_SEND_READY: + // When data packet was sent, switch back to base configuration and set mode switch state machine to 'idle' + if ((rf_ptr->mode_switch_state == MAC_MS_PHR_SEND_READY) && !mac_change_mode_switch_configuration(rf_ptr, phy_mode_id, MAC_MS_IDLE)) { + return 0; + } + break; + case MAC_MS_DATA_RECEIVED: + // When packet was received in new configuration, switch back to base configuration and set mode switch state machine to 'idle' + if ((rf_ptr->mode_switch_state == MAC_MS_PHR_RECEIVED) && !mac_change_mode_switch_configuration(rf_ptr, phy_mode_id, MAC_MS_IDLE)) { + // Packet was received, stop backup timer to not cause timeout event + timer_mac_stop(rf_ptr); + return 0; + } + break; + case MAC_MS_TIMEOUT: + // When reception timeout occurs, switch back to base configuration and set mode switch state machine to 'idle' + if ((rf_ptr->mode_switch_state == MAC_MS_PHR_RECEIVED) && !mac_change_mode_switch_configuration(rf_ptr, phy_mode_id, MAC_MS_IDLE)) { + return 0; + } + break; + default: + break; + } + return -1; +} diff --git a/source/MAC/IEEE802_15_4/mac_mode_switch.h b/source/MAC/IEEE802_15_4/mac_mode_switch.h new file mode 100644 index 0000000000..8efa146cf0 --- /dev/null +++ b/source/MAC/IEEE802_15_4/mac_mode_switch.h @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2021, Pelion and affiliates. + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef MAC_MODE_SWITCH_H_ +#define MAC_MODE_SWITCH_H_ + +#define PHR_LEN 2 + +#define SHIFT_MODE_SWITCH_PARITY (15) +#define SHIFT_MODE_SWITCH_CHECKSUM (11) +#define SHIFT_MODE_SWITCH_PHY_MODE (3) +#define SHIFT_MODE_SWITCH (0) +#define MASK_MODE_SWITCH_PARITY (0x8000) +#define MASK_MODE_SWITCH_CHECKSUM (0x7800) +#define MASK_MODE_SWITCH_PHY_MODE (0x07F8) +#define MASK_MODE_SWITCH (0x0001) + +/** + * @brief Build mode switch PHR. + * @param rf_ptr Pointer to MAC instance. + * @param data_ptr Pointer to data buffer. + * @param phy_mode_id Used PHY mode id. + * @return 0 - success, -1 - failure. + */ +int8_t mac_build_mode_switch_phr(protocol_interface_rf_mac_setup_s *rf_ptr, uint8_t *data_ptr, uint8_t phy_mode_id); + +/** + * @brief Parse mode switch PHR. + * @param rf_ptr Pointer to MAC instance. + * @param data_ptr Pointer to data buffer. + * @param data_len Data length. + * @return 0 - mode switch PHR found, -1 - mode switch PHR not found. + */ +int8_t mac_parse_mode_switch_phr(protocol_interface_rf_mac_setup_s *rf_ptr, const uint8_t *data_ptr, uint16_t data_len); + +/** + * @brief Update mode switch state. + * @param rf_ptr Pointer to MAC instance. + */ +int8_t mac_update_mode_switch_state(protocol_interface_rf_mac_setup_s *rf_ptr, mac_mode_switch_states_e state, uint8_t phy_mode_id); + +#endif /* MAC_MODE_SWITCH_H_ */ diff --git a/source/MAC/IEEE802_15_4/mac_pd_sap.c b/source/MAC/IEEE802_15_4/mac_pd_sap.c index da3b6b7a53..f4956b896c 100644 --- a/source/MAC/IEEE802_15_4/mac_pd_sap.c +++ b/source/MAC/IEEE802_15_4/mac_pd_sap.c @@ -35,6 +35,7 @@ #include "MAC/IEEE802_15_4/mac_filter.h" #include "MAC/IEEE802_15_4/mac_mcps_sap.h" #include "MAC/IEEE802_15_4/mac_cca_threshold.h" +#include "MAC/IEEE802_15_4/mac_mode_switch.h" #include "MAC/rf_driver_storage.h" #include "Core/include/ns_monitor.h" #include "ns_trace.h" @@ -49,6 +50,10 @@ // MAC should learn and make this dynamic by sending first few packets with predefined CSMA period. #define MIN_FHSS_CSMA_PERIOD_US 5000 +// Add extra CSMA-CA delay for packets using mode switch. The delay between mode switch PHR and data packet equals to MDR_SETTLING_TIME_US +// Must be between 510 and 1500 us +#define MDR_SETTLING_TIME_US 510 + static int8_t mac_data_interface_tx_done_cb(protocol_interface_rf_mac_setup_s *rf_ptr, phy_link_tx_status_e status, uint8_t cca_retry, uint8_t tx_retry); static void mac_sap_cca_fail_cb(protocol_interface_rf_mac_setup_s *rf_ptr, uint16_t failed_channel); @@ -106,6 +111,9 @@ uint32_t mac_csma_backoff_get(protocol_interface_rf_mac_setup_s *rf_mac_setup) backoff_in_us = 1; } if (rf_mac_setup->fhss_api) { + if (rf_mac_setup->active_pd_data_request->phy_mode_id) { + backoff_in_us += MDR_SETTLING_TIME_US; + } // Synchronization error when backoff time is shorter than allowed. // TODO: Make this dynamic. if (backoff_in_us < MIN_FHSS_CSMA_PERIOD_US) { @@ -184,6 +192,9 @@ int8_t mac_plme_cca_req(protocol_interface_rf_mac_setup_s *rf_mac_setup) if (rf_mac_setup->mac_ack_tx_active || (rf_mac_setup->mac_edfe_tx_active && rf_mac_setup->mac_edfe_response_tx_active)) { buffer = tx_buf->enhanced_ack_buf; length = tx_buf->ack_len; + } else if (rf_mac_setup->mac_mode_switch_phr_tx_active) { + buffer = tx_buf->mode_switch_phr_buf; + length = sizeof(tx_buf->mode_switch_phr_buf); } else { buffer = tx_buf->buf; length = tx_buf->len; @@ -232,6 +243,7 @@ void mac_pd_abort_active_tx(protocol_interface_rf_mac_setup_s *rf_mac_setup) phy_csma_params_t csma_params; // Set TX time to 0 to abort current transmission csma_params.backoff_time = 0; + csma_params.mode_switch_phr = false; rf_mac_setup->dev_driver->phy_driver->extension(PHY_EXTENSION_SET_CSMA_PARAMETERS, (uint8_t *) &csma_params); } @@ -242,8 +254,12 @@ void mac_pd_abort_active_tx(protocol_interface_rf_mac_setup_s *rf_mac_setup) * \param tx_time TX timestamp to be set. * */ -void mac_pd_sap_set_phy_tx_time(protocol_interface_rf_mac_setup_s *rf_mac_setup, uint32_t tx_time, bool cca_enabled) +void mac_pd_sap_set_phy_tx_time(protocol_interface_rf_mac_setup_s *rf_mac_setup, uint32_t tx_time, bool cca_enabled, bool mode_switch) { + // Given tx_time is for the actual data packet. Mode switch PHR must be sent with the offset of MDR settling time. + if (mode_switch) { + tx_time -= MDR_SETTLING_TIME_US; + } // With TX time set to zero, PHY sends immediately if (!tx_time) { tx_time++; @@ -251,6 +267,7 @@ void mac_pd_sap_set_phy_tx_time(protocol_interface_rf_mac_setup_s *rf_mac_setup, phy_csma_params_t csma_params; csma_params.backoff_time = tx_time; csma_params.cca_enabled = cca_enabled; + csma_params.mode_switch_phr = mode_switch; rf_mac_setup->dev_driver->phy_driver->extension(PHY_EXTENSION_SET_CSMA_PARAMETERS, (uint8_t *) &csma_params); } @@ -300,7 +317,7 @@ void mac_pd_sap_state_machine(protocol_interface_rf_mac_setup_s *rf_mac_setup) cca_enabled = true; } - mac_pd_sap_set_phy_tx_time(rf_mac_setup, active_buf->tx_time, cca_enabled); + mac_pd_sap_set_phy_tx_time(rf_mac_setup, active_buf->tx_time, cca_enabled, rf_mac_setup->mac_mode_switch_phr_tx_active); if (active_buf->fcf_dsn.frametype == FC_BEACON_FRAME) { // FHSS synchronization info is written in the end of transmitted (Beacon) buffer dev_driver_tx_buffer_s *tx_buf = &rf_mac_setup->dev_driver_tx_buffer; @@ -335,6 +352,10 @@ void mac_pd_sap_state_machine(protocol_interface_rf_mac_setup_s *rf_mac_setup) } else if (rf_mac_setup->mac_tx_result == MAC_TIMER_ACK) { mac_data_interface_tx_done_cb(rf_mac_setup, PHY_LINK_TX_FAIL, 0, 0); } + } else { + if (rf_mac_setup->mac_tx_result == MAC_MODE_SWITCH_TIMEOUT) { + mac_update_mode_switch_state(rf_mac_setup, MAC_MS_TIMEOUT, rf_mac_setup->base_phy_mode); + } } } @@ -424,6 +445,7 @@ static bool mac_data_asynch_channel_switch(protocol_interface_rf_mac_setup_s *rf static void mac_data_ack_tx_finish(protocol_interface_rf_mac_setup_s *rf_ptr) { rf_ptr->mac_ack_tx_active = false; + mac_update_mode_switch_state(rf_ptr, MAC_MS_DATA_RECEIVED, rf_ptr->base_phy_mode); if (rf_ptr->fhss_api) { //SET tx completed false because ack isnot never queued rf_ptr->fhss_api->data_tx_done(rf_ptr->fhss_api, false, false, 0xff); @@ -449,7 +471,6 @@ int8_t mac_data_edfe_force_stop(protocol_interface_rf_mac_setup_s *rf_ptr) static int8_t mac_data_interface_tx_done_cb(protocol_interface_rf_mac_setup_s *rf_ptr, phy_link_tx_status_e status, uint8_t cca_retry, uint8_t tx_retry) { - if (!rf_ptr->macRfRadioTxActive) { return -1; } @@ -513,7 +534,7 @@ static int8_t mac_data_interface_tx_done_cb(protocol_interface_rf_mac_setup_s *r if (active_buf->csma_periods_left > 0) { active_buf->csma_periods_left--; active_buf->tx_time += rf_ptr->multi_cca_interval; - mac_pd_sap_set_phy_tx_time(rf_ptr, active_buf->tx_time, true); + mac_pd_sap_set_phy_tx_time(rf_ptr, active_buf->tx_time, true, false); #ifdef TIMING_TOOL_TRACES tr_info("%u CSMA_start", mac_mcps_sap_get_phy_timestamp(rf_ptr)); #endif @@ -555,6 +576,23 @@ VALIDATE_TX_TIME: mac_data_ack_tx_finish(rf_ptr); return 0; } + } else if (rf_ptr->mac_mode_switch_phr_tx_active) { +#ifdef TIMING_TOOL_TRACES + tr_info("%u TX_done", mac_mcps_sap_get_phy_timestamp(rf_ptr)); +#endif + rf_ptr->mac_mode_switch_phr_tx_active = false; + if (rf_ptr->fhss_api) { + rf_ptr->fhss_api->data_tx_done(rf_ptr->fhss_api, false, true, rf_ptr->active_pd_data_request->msduHandle); + } + if (!mac_update_mode_switch_state(rf_ptr, MAC_MS_PHR_SEND_READY, rf_ptr->active_pd_data_request->phy_mode_id)) { + mac_pd_sap_set_phy_tx_time(rf_ptr, rf_ptr->active_pd_data_request->tx_time, true, rf_ptr->mac_mode_switch_phr_tx_active); + if (mac_plme_cca_req(rf_ptr) != 0) { + mac_sap_no_ack_cb(rf_ptr); + } + return 0; + } + // Failed to start data transmission after mode switch PHR was sent + status = PHY_LINK_TX_FAIL; } // Do not update CCA count when Ack is received, it was already updated with PHY_LINK_TX_SUCCESS event @@ -580,7 +618,7 @@ VALIDATE_TX_TIME: timer_mac_stop(rf_ptr); } uint16_t failed_channel = rf_ptr->mac_channel; - if (rf_ptr->fhss_api && rf_ptr->active_pd_data_request->asynch_request == false) { + if (rf_ptr->active_pd_data_request && 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 */ @@ -610,7 +648,12 @@ VALIDATE_TX_TIME: 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); + if (waiting_ack == false) { + mac_update_mode_switch_state(rf_ptr, MAC_MS_DATA_SEND_READY, rf_ptr->base_phy_mode); + } + if (rf_ptr->fhss_api) { + rf_ptr->fhss_api->data_tx_done(rf_ptr->fhss_api, waiting_ack, tx_completed, rf_ptr->active_pd_data_request->msduHandle); + } } switch (status) { @@ -674,7 +717,7 @@ static int8_t mac_data_interface_tx_done_by_ack_cb(protocol_interface_rf_mac_set if (mcps_sap_pd_ack(rf_ptr, buf) != 0) { mcps_sap_pre_parsed_frame_buffer_free(buf); } - + mac_update_mode_switch_state(rf_ptr, MAC_MS_DATA_SEND_READY, rf_ptr->base_phy_mode); if (rf_ptr->fhss_api) { rf_ptr->fhss_api->data_tx_done(rf_ptr->fhss_api, false, true, rf_ptr->active_pd_data_request->msduHandle); } @@ -1040,19 +1083,27 @@ int8_t mac_pd_sap_data_cb(void *identifier, arm_phy_sap_msg_t *message) goto ERROR_HANDLER; } - if (pd_data_ind->data_len < 3) { - return -1; - } #ifdef TIMING_TOOL_TRACES tr_info("%u RX_start", mac_pd_sap_get_phy_rx_time(rf_ptr)); tr_info("%u RX_done", mac_mcps_sap_get_phy_timestamp(rf_ptr)); #endif + + if (!mac_parse_mode_switch_phr(rf_ptr, pd_data_ind->data_ptr, pd_data_ind->data_len)) { + // TODO: mode switch returned 0, needs some logic to wait frame with new mode + goto ERROR_HANDLER; + } + + if (pd_data_ind->data_len < 3) { + return -1; + } + mac_cca_threshold_event_send(rf_ptr, rf_ptr->mac_channel, pd_data_ind->dbm); mac_fcf_sequence_t fcf_read; const uint8_t *ptr = mac_header_parse_fcf_dsn(&fcf_read, pd_data_ind->data_ptr); // No need to send Ack - Check if RX channel needs to be updated if (fcf_read.ackRequested == false) { + mac_update_mode_switch_state(rf_ptr, MAC_MS_DATA_RECEIVED, rf_ptr->base_phy_mode); if (rf_ptr->fhss_api) { rf_ptr->fhss_api->data_tx_done(rf_ptr->fhss_api, false, false, 0); } diff --git a/source/MAC/IEEE802_15_4/mac_pd_sap.h b/source/MAC/IEEE802_15_4/mac_pd_sap.h index 730c9b0e3e..79b959312d 100644 --- a/source/MAC/IEEE802_15_4/mac_pd_sap.h +++ b/source/MAC/IEEE802_15_4/mac_pd_sap.h @@ -43,7 +43,7 @@ int8_t mac_plme_cca_req(struct protocol_interface_rf_mac_setup *rf_mac_setup); void mac_pd_abort_active_tx(struct protocol_interface_rf_mac_setup *rf_mac_setup); -void mac_pd_sap_set_phy_tx_time(struct protocol_interface_rf_mac_setup *rf_mac_setup, uint32_t tx_time, bool cca_enabled); +void mac_pd_sap_set_phy_tx_time(struct protocol_interface_rf_mac_setup *rf_mac_setup, uint32_t tx_time, bool cca_enabled, bool mode_switch); void mac_pd_sap_rf_low_level_function_set(void *mac_ptr, void *driver); diff --git a/source/MAC/IEEE802_15_4/mac_timer.c b/source/MAC/IEEE802_15_4/mac_timer.c index 764cd25a73..187ae44c1c 100644 --- a/source/MAC/IEEE802_15_4/mac_timer.c +++ b/source/MAC/IEEE802_15_4/mac_timer.c @@ -23,7 +23,7 @@ #include "MAC/IEEE802_15_4/mac_pd_sap.h" #include "MAC/IEEE802_15_4/mac_timer.h" #include "sw_mac.h" - +#define TRACE_GROUP "mTim" /*-------------------MAC TIMER FUNCTIONS--------------------------*/ diff --git a/source/MAC/IEEE802_15_4/sw_mac.c b/source/MAC/IEEE802_15_4/sw_mac.c index 675eda3b5c..1decacba21 100644 --- a/source/MAC/IEEE802_15_4/sw_mac.c +++ b/source/MAC/IEEE802_15_4/sw_mac.c @@ -55,10 +55,11 @@ static int8_t ns_sw_mac_initialize(mac_api_t *api, mcps_data_confirm *mcps_data_ mlme_confirm *mlme_conf_callback, mlme_indication *mlme_ind_callback, int8_t parent_id); static int8_t ns_sw_mac_api_enable_mcps_ext(mac_api_t *api, mcps_data_indication_ext *data_ind_cb, mcps_data_confirm_ext *data_cnf_cb, mcps_ack_data_req_ext *ack_data_req_cb); static int8_t ns_sw_mac_api_enable_edfe_ext(mac_api_t *api, mcps_edfe_handler *edfe_ind_cb); +static int8_t ns_sw_mac_api_mode_switch_resolver_set(mac_api_t *api, mode_switch_resolver *mode_resolver_cb, uint8_t base_phy_mode); static void mlme_req(const mac_api_t *api, mlme_primitive id, const void *data); static void mcps_req(const mac_api_t *api, const mcps_data_req_t *data); -static void mcps_req_ext(const mac_api_t *api, const mcps_data_req_t *data, const mcps_data_req_ie_list_t *ie_ext, const channel_list_s *asynch_channel_list, mac_data_priority_t priority); +static void mcps_req_ext(const mac_api_t *api, const mcps_data_req_t *data, const mcps_data_req_ie_list_t *ie_ext, const channel_list_s *asynch_channel_list, mac_data_priority_t priority, uint8_t phy_mode_id); static uint8_t purge_req(const mac_api_t *api, const mcps_purge_t *data); static int8_t macext_mac64_address_set(const mac_api_t *api, const uint8_t *mac64); static int8_t macext_mac64_address_get(const mac_api_t *api, mac_extended_address_type type, uint8_t *mac64_buf); @@ -130,6 +131,7 @@ mac_api_t *ns_sw_mac_create(int8_t rf_driver_id, mac_description_storage_size_t this->mac_initialize = &ns_sw_mac_initialize; this->mac_mcps_extension_enable = &ns_sw_mac_api_enable_mcps_ext; this->mac_mcps_edfe_enable = &ns_sw_mac_api_enable_edfe_ext; + this->mac_mode_switch_resolver_set = &ns_sw_mac_api_mode_switch_resolver_set; this->mlme_req = &mlme_req; this->mcps_data_req = &mcps_req; this->mcps_data_req_ext = &mcps_req_ext; @@ -344,6 +346,19 @@ static int8_t ns_sw_mac_api_enable_edfe_ext(mac_api_t *api, mcps_edfe_handler *e return 0; } +static int8_t ns_sw_mac_api_mode_switch_resolver_set(mac_api_t *api, mode_switch_resolver *mode_resolver_cb, uint8_t base_phy_mode) +{ + if (api != mac_store.mac_api) { + return -1; + } + if (!mac_store.setup->mac_extension_enabled) { + return -1; + } + mac_store.setup->base_phy_mode = base_phy_mode; + mac_store.mac_api->mode_resolver_cb = mode_resolver_cb; + return 0; +} + mac_api_t *get_sw_mac_api(protocol_interface_rf_mac_setup_s *setup) { if (!mac_store.mac_api || mac_store.mac_api->parent_id == -1 || mac_store.setup != setup) { @@ -582,15 +597,15 @@ static void mcps_req(const mac_api_t *api, const mcps_data_req_t *data) /* Call direct new API but without IE extensions */ mcps_data_req_ie_list_t ie_list; memset(&ie_list, 0, sizeof(mcps_data_req_ie_list_t)); - mcps_sap_data_req_handler_ext(mac_store.setup, data, &ie_list, NULL, MAC_DATA_NORMAL_PRIORITY); + mcps_sap_data_req_handler_ext(mac_store.setup, data, &ie_list, NULL, MAC_DATA_NORMAL_PRIORITY, 0); } } -static void mcps_req_ext(const mac_api_t *api, const mcps_data_req_t *data, const mcps_data_req_ie_list_t *ie_ext, const channel_list_s *asynch_channel_list, mac_data_priority_t priority) +static void mcps_req_ext(const mac_api_t *api, const mcps_data_req_t *data, const mcps_data_req_ie_list_t *ie_ext, const channel_list_s *asynch_channel_list, mac_data_priority_t priority, uint8_t phy_mode_id) { //TODO: Populate linked list when present if (mac_store.mac_api == api) { - mcps_sap_data_req_handler_ext(mac_store.setup, data, ie_ext, asynch_channel_list, priority); + mcps_sap_data_req_handler_ext(mac_store.setup, data, ie_ext, asynch_channel_list, priority, phy_mode_id); } } diff --git a/source/MPL/mpl.c b/source/MPL/mpl.c index face25a0f3..52453fbd06 100644 --- a/source/MPL/mpl.c +++ b/source/MPL/mpl.c @@ -501,7 +501,7 @@ static void mpl_buffer_transmit(mpl_domain_t *domain, mpl_buffered_message_t *me memcpy(buf->src_sa.address, message->message + IPV6_HDROFF_SRC_ADDR, 16); ipv6_transmit_multicast_on_interface(buf, domain->interface); - tr_debug("MPL transmit %u", mpl_buffer_sequence(message)); + tr_info("MPL transmit %u", mpl_buffer_sequence(message)); } static void mpl_buffer_inconsistent(const mpl_domain_t *domain, mpl_buffered_message_t *message) diff --git a/source/NWK_INTERFACE/Include/protocol_abstract.h b/source/NWK_INTERFACE/Include/protocol_abstract.h index f59ca2bf9e..87452877a5 100644 --- a/source/NWK_INTERFACE/Include/protocol_abstract.h +++ b/source/NWK_INTERFACE/Include/protocol_abstract.h @@ -45,5 +45,6 @@ protocol_interface_info_entry_t *protocol_stack_interface_info_get_by_id(int8_t protocol_interface_info_entry_t *protocol_stack_interface_info_get_by_bootstrap_id(int8_t id); protocol_interface_info_entry_t *protocol_stack_interface_info_get_by_rpl_domain(const struct rpl_domain *domain, int8_t last_id); protocol_interface_info_entry_t *protocol_stack_interface_info_get_by_fhss_api(const struct fhss_api *fhss_api); +protocol_interface_info_entry_t *protocol_stack_interface_info_get_wisun_mesh(void); #endif /* NWK_INTERFACE_INCLUDE_PROTOCOL_ABSTRACT_H_ */ diff --git a/source/NWK_INTERFACE/protocol_core.c b/source/NWK_INTERFACE/protocol_core.c index cab954193b..3a46c05b4a 100644 --- a/source/NWK_INTERFACE/protocol_core.c +++ b/source/NWK_INTERFACE/protocol_core.c @@ -65,7 +65,6 @@ #include "6LoWPAN/Thread/thread_bootstrap.h" #include "6LoWPAN/Thread/thread_routing.h" #include "6LoWPAN/Thread/thread_management_internal.h" -#include "6LoWPAN/ws/ws_bootstrap.h" #include "6LoWPAN/ws/ws_common.h" #ifdef HAVE_WS #include "6LoWPAN/ws/ws_pae_controller.h" @@ -806,6 +805,18 @@ protocol_interface_info_entry_t *protocol_stack_interface_info_get_by_fhss_api(c return NULL; } +protocol_interface_info_entry_t *protocol_stack_interface_info_get_wisun_mesh(void) +{ +#ifdef HAVE_WS + ns_list_foreach(protocol_interface_info_entry_t, cur, &protocol_interface_info_list) { + if (cur->ws_info) { + return cur; + } + } +#endif //HAVE_WS + return NULL; +} + protocol_interface_info_entry_t *protocol_stack_interface_sleep_possibility(void) { ns_list_foreach(protocol_interface_info_entry_t, cur, &protocol_interface_info_list) { @@ -1148,7 +1159,7 @@ void net_bootsrap_cb_run(uint8_t event) if (thread_info(cur)) { thread_bootstrap_state_machine(cur); } else if (ws_info(cur)) { - ws_bootstrap_state_machine(cur); + ws_common_state_machine(cur); } else { protocol_6lowpan_bootstrap(cur); } diff --git a/source/NWK_INTERFACE/protocol_timer.c b/source/NWK_INTERFACE/protocol_timer.c index 0c518ecf5d..15c2869adf 100644 --- a/source/NWK_INTERFACE/protocol_timer.c +++ b/source/NWK_INTERFACE/protocol_timer.c @@ -70,7 +70,7 @@ void protocol_timer_start(protocol_timer_id_t id, void (*passed_fptr)(uint16_t), protocol_timer[id].fptr = passed_fptr; platform_exit_critical(); } else { - tr_debug("Do Not use Null pointer for fptr!!!\n"); + tr_debug("Do Not use Null pointer for fptr!!!"); } } diff --git a/source/RPL/rpl_control.c b/source/RPL/rpl_control.c index 282eea4f6e..fb77ea064e 100644 --- a/source/RPL/rpl_control.c +++ b/source/RPL/rpl_control.c @@ -1549,6 +1549,20 @@ static buffer_t *rpl_control_dis_handler(protocol_interface_info_entry_t *cur, r return buffer_free(buf); } +void rpl_control_transmit_dio_trigger(protocol_interface_info_entry_t *cur, struct rpl_domain *domain) +{ + ns_list_foreach(rpl_instance_t, instance, &domain->instances) { + rpl_instance_dio_trigger(instance, cur, NULL); + } +} + +void rpl_control_parent_selection_trigger(struct rpl_domain *domain) +{ + ns_list_foreach(rpl_instance_t, instance, &domain->instances) { + rpl_instance_run_parent_selection(instance); + } +} + void rpl_control_transmit_dis(rpl_domain_t *domain, protocol_interface_info_entry_t *cur, uint8_t pred, uint8_t instance_id, const uint8_t *dodagid, const uint8_t version, const uint8_t *dst) { uint16_t length = 2; diff --git a/source/RPL/rpl_control.h b/source/RPL/rpl_control.h index e5381afefd..c1cd578828 100644 --- a/source/RPL/rpl_control.h +++ b/source/RPL/rpl_control.h @@ -133,6 +133,11 @@ struct buffer *rpl_control_source_route_error_handler(struct buffer *buf, struct /* Manually send DIS packets for bootstrap */ void rpl_control_transmit_dis(struct rpl_domain *domain, struct protocol_interface_info_entry *cur, uint8_t pred, uint8_t instance_id, const uint8_t *dodagid, const uint8_t version, const uint8_t *dst); +/* Manually send DIO packets for bootstrap */ +void rpl_control_transmit_dio_trigger(struct protocol_interface_info_entry *cur, struct rpl_domain *domain); +/* Manually trigger RPL parent selection */ +void rpl_control_parent_selection_trigger(struct rpl_domain *domain); + bool rpl_control_have_dodag(struct rpl_domain *domain); /* APIs used to manipulate configuration at the root */ diff --git a/source/Security/protocols/radius_sec_prot/radius_client_sec_prot.c b/source/Security/protocols/radius_sec_prot/radius_client_sec_prot.c index 21dc0bf7e0..8f3371f621 100644 --- a/source/Security/protocols/radius_sec_prot/radius_client_sec_prot.c +++ b/source/Security/protocols/radius_sec_prot/radius_client_sec_prot.c @@ -786,19 +786,31 @@ static int8_t radius_client_sec_prot_eui_64_hash_generate(uint8_t *eui_64, uint8 mbedtls_sha256_init(&ctx); +#if (MBEDTLS_VERSION_MAJOR >= 3) + if (mbedtls_sha256_starts(&ctx, 0) != 0) { +#else if (mbedtls_sha256_starts_ret(&ctx, 0) != 0) { +#endif ret_val = -1; goto error; } +#if (MBEDTLS_VERSION_MAJOR >= 3) + if (mbedtls_sha256_update(&ctx, hashed_string, 24) != 0) { +#else if (mbedtls_sha256_update_ret(&ctx, hashed_string, 24) != 0) { +#endif ret_val = -1; goto error; } uint8_t output[32]; +#if (MBEDTLS_VERSION_MAJOR >= 3) + if (mbedtls_sha256_finish(&ctx, output) != 0) { +#else if (mbedtls_sha256_finish_ret(&ctx, output) != 0) { +#endif ret_val = -1; goto error; } @@ -872,19 +884,35 @@ static int8_t radius_client_sec_prot_response_authenticator_calc(sec_prot_t *pro mbedtls_md5_init(&ctx); +#if (MBEDTLS_VERSION_MAJOR >= 3) + if (mbedtls_md5_starts(&ctx) != 0) { +#else if (mbedtls_md5_starts_ret(&ctx) != 0) { +#endif goto end; } +#if (MBEDTLS_VERSION_MAJOR >= 3) + if (mbedtls_md5_update(&ctx, msg_ptr, msg_len) != 0) { +#else if (mbedtls_md5_update_ret(&ctx, msg_ptr, msg_len) != 0) { +#endif goto end; } +#if (MBEDTLS_VERSION_MAJOR >= 3) + if (mbedtls_md5_update(&ctx, key, key_len) != 0) { +#else if (mbedtls_md5_update_ret(&ctx, key, key_len) != 0) { +#endif goto end; } +#if (MBEDTLS_VERSION_MAJOR >= 3) + if (mbedtls_md5_finish(&ctx, auth_ptr) != 0) { +#else if (mbedtls_md5_finish_ret(&ctx, auth_ptr) != 0) { +#endif goto end; } @@ -940,35 +968,59 @@ static int8_t radius_client_sec_prot_ms_mppe_recv_key_pmk_decrypt(sec_prot_t *pr while (cipher_text_len >= MS_MPPE_RECV_KEY_BLOCK_LEN) { mbedtls_md5_init(&ctx); +#if (MBEDTLS_VERSION_MAJOR >= 3) + if (mbedtls_md5_starts(&ctx) != 0) { +#else if (mbedtls_md5_starts_ret(&ctx) != 0) { +#endif md5_failed = true; break; } +#if (MBEDTLS_VERSION_MAJOR >= 3) + if (mbedtls_md5_update(&ctx, key, key_len) != 0) { +#else if (mbedtls_md5_update_ret(&ctx, key, key_len) != 0) { +#endif md5_failed = true; break; } if (first_interm_b_value) { // b(1) = MD5(secret + request-authenticator + salt) +#if (MBEDTLS_VERSION_MAJOR >= 3) + if (mbedtls_md5_update(&ctx, request_authenticator, MS_MPPE_RECV_KEY_BLOCK_LEN) != 0) { +#else if (mbedtls_md5_update_ret(&ctx, request_authenticator, MS_MPPE_RECV_KEY_BLOCK_LEN) != 0) { +#endif md5_failed = true; break; } +#if (MBEDTLS_VERSION_MAJOR >= 3) + if (mbedtls_md5_update(&ctx, salt_ptr, MS_MPPE_RECV_KEY_SALT_LEN) != 0) { +#else if (mbedtls_md5_update_ret(&ctx, salt_ptr, MS_MPPE_RECV_KEY_SALT_LEN) != 0) { +#endif md5_failed = true; break; } } else { // b(i) = MD5(secret + cipher_text(i - 1)) +#if (MBEDTLS_VERSION_MAJOR >= 3) + if (mbedtls_md5_update(&ctx, cipher_text_ptr - MS_MPPE_RECV_KEY_BLOCK_LEN, MS_MPPE_RECV_KEY_BLOCK_LEN) != 0) { +#else if (mbedtls_md5_update_ret(&ctx, cipher_text_ptr - MS_MPPE_RECV_KEY_BLOCK_LEN, MS_MPPE_RECV_KEY_BLOCK_LEN) != 0) { +#endif md5_failed = true; break; } } +#if (MBEDTLS_VERSION_MAJOR >= 3) + if (mbedtls_md5_finish(&ctx, interm_b_val) != 0) { +#else if (mbedtls_md5_finish_ret(&ctx, interm_b_val) != 0) { +#endif md5_failed = true; break; } diff --git a/source/Security/protocols/sec_prot_keys.c b/source/Security/protocols/sec_prot_keys.c index 02748f08fc..ebe5f6ab05 100644 --- a/source/Security/protocols/sec_prot_keys.c +++ b/source/Security/protocols/sec_prot_keys.c @@ -507,7 +507,7 @@ uint32_t sec_prot_keys_gtk_lifetime_get(sec_prot_gtk_keys_t *gtks, uint8_t index return gtks->gtk[index].lifetime; } -uint32_t sec_prot_keys_gtk_lifetime_decrement(sec_prot_gtk_keys_t *gtks, uint8_t index, uint64_t current_time, uint16_t seconds, bool gtk_update_enable) +uint32_t sec_prot_keys_gtk_lifetime_decrement(sec_prot_gtk_keys_t *gtks, uint8_t index, uint64_t current_time, uint32_t seconds, bool gtk_update_enable) { if (gtks->gtk[index].lifetime > seconds) { gtks->gtk[index].lifetime -= seconds; @@ -527,6 +527,7 @@ uint32_t sec_prot_keys_gtk_lifetime_decrement(sec_prot_gtk_keys_t *gtks, uint8_t // If timestamps differ for more than 5 minutes marks field as updated (and stores to NVM) if (diff > 300 && gtk_update_enable) { gtks->updated = true; + sec_prot_keys_gtk_expirytime_set(gtks, index, expirytime); } return gtks->gtk[index].lifetime; @@ -716,7 +717,7 @@ int8_t sec_prot_keys_gtk_valid_check(uint8_t *gtk) return 0; } -gtk_mismatch_e sec_prot_keys_gtks_hash_update(sec_prot_gtk_keys_t *gtks, uint8_t *gtkhash) +gtk_mismatch_e sec_prot_keys_gtks_hash_update(sec_prot_gtk_keys_t *gtks, uint8_t *gtkhash, bool del_gtk_on_mismatch) { uint8_t *gtk_hash_ptr = gtkhash; @@ -729,11 +730,15 @@ gtk_mismatch_e sec_prot_keys_gtks_hash_update(sec_prot_gtk_keys_t *gtks, uint8_t uint32_t lifetime = sec_prot_keys_gtk_lifetime_get(gtks, i); if (lifetime > GTK_EXPIRE_MISMATCH_TIME) { tr_info("GTK mismatch %i expired time, lifetime: %"PRIu32"", i, lifetime); - if (mismatch < GTK_LIFETIME_MISMATCH) { + // Only indicate mismatch in case fresh hash is received + if (mismatch < GTK_LIFETIME_MISMATCH && del_gtk_on_mismatch) { mismatch = GTK_LIFETIME_MISMATCH; } } - sec_prot_keys_gtk_clear(gtks, i); + // Only delete in case fresh hash is received + if (del_gtk_on_mismatch) { + sec_prot_keys_gtk_clear(gtks, i); + } } } else { // Check is hash matches to existing key @@ -759,7 +764,10 @@ gtk_mismatch_e sec_prot_keys_gtks_hash_update(sec_prot_gtk_keys_t *gtks, uint8_t if (mismatch < GTK_HASH_MISMATCH) { mismatch = GTK_HASH_MISMATCH; } - sec_prot_keys_gtk_clear(gtks, i); + // Only delete in case fresh hash is received + if (del_gtk_on_mismatch) { + sec_prot_keys_gtk_clear(gtks, i); + } } } } diff --git a/source/Security/protocols/sec_prot_keys.h b/source/Security/protocols/sec_prot_keys.h index 6215bdc759..242618bd36 100644 --- a/source/Security/protocols/sec_prot_keys.h +++ b/source/Security/protocols/sec_prot_keys.h @@ -62,6 +62,10 @@ #define SEC_MAXIMUM_LIFETIME (60 * 60 * 24 * 30 * 24) // Maximum life time for PMK, PTK, GTKs etc. is two years +// System time changed +#define SYSTEM_TIME_NOT_CHANGED 0 +#define SYSTEM_TIME_CHANGED 1 + typedef struct { uint8_t key[GTK_LEN]; /**< Group Transient Key (128 bits) */ uint64_t expirytime; /**< GTK expiry time on storage */ @@ -108,7 +112,8 @@ typedef struct { typedef struct { uint8_t gtk[GTK_LEN]; /**< GTK of the frame counter */ uint32_t frame_counter; /**< Current frame counter */ - uint32_t stored_frame_counter; /**< Stored Frame counter */ + uint32_t stored_frame_counter; /**< Stored frame counter */ + uint32_t max_frame_counter_chg; /**< Maximum frame counter change */ bool set : 1; /**< Value has been set */ } frame_counter_t; @@ -144,6 +149,7 @@ typedef struct { uint16_t new_pan_id; /**< new PAN ID indicated by bootstrap */ uint16_t key_pan_id; /**< PAN ID for keys */ uint16_t pan_version; /**< PAN version for keys */ + uint8_t system_time_changed; /**< System time changed */ bool updated : 1; /**< Network info has been updated */ } sec_prot_keys_nw_info_t; @@ -630,7 +636,7 @@ uint32_t sec_prot_keys_gtk_lifetime_get(sec_prot_gtk_keys_t *gtks, uint8_t index * \return new GTK lifetime * */ -uint32_t sec_prot_keys_gtk_lifetime_decrement(sec_prot_gtk_keys_t *gtks, uint8_t index, uint64_t current_time, uint16_t seconds, bool gtk_update_enable); +uint32_t sec_prot_keys_gtk_lifetime_decrement(sec_prot_gtk_keys_t *gtks, uint8_t index, uint64_t current_time, uint32_t seconds, bool gtk_update_enable); /** * sec_prot_keys_gtk_exptime_from_lifetime_get converts GTK lifetime to expiry time. @@ -806,11 +812,12 @@ int8_t sec_prot_keys_gtk_valid_check(uint8_t *gtk); * * \param gtks GTK keys * \param gtk_hash GTK hash + * \param del_gtk_on_mismatch Delete GTK in case of mismatch * * \return GTK mismatch type or no mismatch * */ -gtk_mismatch_e sec_prot_keys_gtks_hash_update(sec_prot_gtk_keys_t *gtks, uint8_t *gtkhash); +gtk_mismatch_e sec_prot_keys_gtks_hash_update(sec_prot_gtk_keys_t *gtks, uint8_t *gtkhash, bool del_gtk_on_mismatch); /** * sec_prot_keys_gtk_hash_empty checks if GTK hash field is empty diff --git a/source/Security/protocols/sec_prot_lib.c b/source/Security/protocols/sec_prot_lib.c index 7789020660..88577b3157 100644 --- a/source/Security/protocols/sec_prot_lib.c +++ b/source/Security/protocols/sec_prot_lib.c @@ -514,19 +514,31 @@ int8_t sec_prot_lib_gtkhash_generate(uint8_t *gtk, uint8_t *gtk_hash) mbedtls_sha256_init(&ctx); +#if (MBEDTLS_VERSION_MAJOR >= 3) + if (mbedtls_sha256_starts(&ctx, 0) != 0) { +#else if (mbedtls_sha256_starts_ret(&ctx, 0) != 0) { +#endif ret_val = -1; goto error; } +#if (MBEDTLS_VERSION_MAJOR >= 3) + if (mbedtls_sha256_update(&ctx, gtk, 16) != 0) { +#else if (mbedtls_sha256_update_ret(&ctx, gtk, 16) != 0) { +#endif ret_val = -1; goto error; } uint8_t output[32]; +#if (MBEDTLS_VERSION_MAJOR >= 3) + if (mbedtls_sha256_finish(&ctx, output) != 0) { +#else if (mbedtls_sha256_finish_ret(&ctx, output) != 0) { +#endif ret_val = -1; goto error; } diff --git a/source/Security/protocols/tls_sec_prot/tls_sec_prot.c b/source/Security/protocols/tls_sec_prot/tls_sec_prot.c index 545dbbcb87..e194301e4d 100644 --- a/source/Security/protocols/tls_sec_prot/tls_sec_prot.c +++ b/source/Security/protocols/tls_sec_prot/tls_sec_prot.c @@ -595,7 +595,7 @@ static void tls_sec_prot_tls_export_keys(void *handle, const uint8_t *master_sec const uint8_t *print_data = eap_tls_key_material; uint16_t print_data_len = 128; while (true) { - tr_debug("EAP-TLS key material %s\n", trace_array(print_data, print_data_len > 32 ? 32 : print_data_len)); + tr_debug("EAP-TLS key material %s", trace_array(print_data, print_data_len > 32 ? 32 : print_data_len)); if (print_data_len > 32) { print_data_len -= 32; print_data += 32; diff --git a/source/Security/protocols/tls_sec_prot/tls_sec_prot_lib.c b/source/Security/protocols/tls_sec_prot/tls_sec_prot_lib.c index 36f50a8b09..fa3df55593 100644 --- a/source/Security/protocols/tls_sec_prot/tls_sec_prot_lib.c +++ b/source/Security/protocols/tls_sec_prot/tls_sec_prot_lib.c @@ -18,12 +18,8 @@ #include "nsconfig.h" #ifdef HAVE_WS -#if !defined(MBEDTLS_CONFIG_FILE) -#include "mbedtls/config.h" -#else -#include MBEDTLS_CONFIG_FILE -#endif +#include "mbedtls/version.h" #if defined(MBEDTLS_SSL_TLS_C) && defined(MBEDTLS_X509_CRT_PARSE_C) && defined(MBEDTLS_SSL_EXPORT_KEYS) /* EXPORT_KEYS not supported by mbedtls baremetal yet */ #define WS_MBEDTLS_SECURITY_ENABLED #endif @@ -49,7 +45,6 @@ #include "mbedtls/platform.h" #include "mbedtls/ssl_cookie.h" #include "mbedtls/entropy.h" -#include "mbedtls/entropy_poll.h" #include "mbedtls/ctr_drbg.h" #include "mbedtls/ssl_ciphersuites.h" #include "mbedtls/debug.h" @@ -77,7 +72,9 @@ struct tls_security_s { mbedtls_pk_context pkey; /**< Private key for own certificate */ void *handle; /**< Handle provided in callbacks (defined by library user) */ bool ext_cert_valid : 1; /**< Extended certificate validation enabled */ +#if (MBEDTLS_VERSION_MAJOR < 3) tls_sec_prot_lib_crt_verify_cb *crt_verify; /**< Verify function for client/server certificate */ +#endif tls_sec_prot_lib_send *send; /**< Send callback */ tls_sec_prot_lib_receive *receive; /**< Receive callback */ tls_sec_prot_lib_export_keys *export_keys; /**< Export keys callback */ @@ -90,12 +87,22 @@ static int tls_sec_prot_lib_ssl_get_timer(void *ctx); static int tls_sec_lib_entropy_poll(void *data, unsigned char *output, size_t len, size_t *olen); static int tls_sec_prot_lib_ssl_send(void *ctx, const unsigned char *buf, size_t len); static int tls_sec_prot_lib_ssl_recv(void *ctx, unsigned char *buf, size_t len); -static int tls_sec_prot_lib_ssl_export_keys(void *p_expkey, const unsigned char *ms, +#if (MBEDTLS_VERSION_MAJOR >= 3) +static void tls_sec_prot_lib_ssl_export_keys(void *p_expkey, mbedtls_ssl_key_export_type type, + const unsigned char *secret, + size_t secret_len, + const unsigned char client_random[32], + const unsigned char server_random[32], + mbedtls_tls_prf_types tls_prf_type); +#else +static int tls_sec_prot_lib_ssl_export_keys(void *p_expkey, const unsigned char *secret, const unsigned char *kb, size_t maclen, size_t keylen, size_t ivlen, const unsigned char client_random[32], const unsigned char server_random[32], mbedtls_tls_prf_types tls_prf_type); +#endif +#if (MBEDTLS_VERSION_MAJOR < 3) static int tls_sec_prot_lib_x509_crt_verify(void *ctx, mbedtls_x509_crt *crt, int certificate_depth, uint32_t *flags); static int8_t tls_sec_prot_lib_subject_alternative_name_validate(mbedtls_x509_crt *crt); static int8_t tls_sec_prot_lib_extended_key_usage_validate(mbedtls_x509_crt *crt); @@ -105,6 +112,7 @@ static int tls_sec_prot_lib_x509_crt_idevid_ldevid_verify(tls_security_t *sec, m #ifdef HAVE_PAE_SUPP static int tls_sec_prot_lib_x509_crt_server_verify(tls_security_t *sec, mbedtls_x509_crt *crt, uint32_t *flags); #endif +#endif #ifdef TLS_SEC_PROT_LIB_TLS_DEBUG static void tls_sec_prot_lib_debug(void *ctx, int level, const char *file, int line, const char *string); #endif @@ -234,7 +242,11 @@ static int tls_sec_prot_lib_configure_certificates(tls_security_t *sec, const se return -1; } +#if (MBEDTLS_VERSION_MAJOR >= 3) + if (mbedtls_pk_parse_key(&sec->pkey, key, key_len, NULL, 0, mbedtls_ctr_drbg_random, &sec->ctr_drbg) < 0) { +#else if (mbedtls_pk_parse_key(&sec->pkey, key, key_len, NULL, 0) < 0) { +#endif tr_error("Private key parse error"); return -1; } @@ -310,6 +322,7 @@ int8_t tls_sec_prot_lib_connect(tls_security_t *sec, bool is_server, const sec_p return -1; } +#if (MBEDTLS_VERSION_MAJOR < 3) #ifdef HAVE_PAE_SUPP if (is_server_is_not_set) { sec->crt_verify = tls_sec_prot_lib_x509_crt_server_verify; @@ -320,7 +333,7 @@ int8_t tls_sec_prot_lib_connect(tls_security_t *sec, bool is_server, const sec_p sec->crt_verify = tls_sec_prot_lib_x509_crt_idevid_ldevid_verify; } #endif - +#endif if ((mbedtls_ssl_config_defaults(&sec->conf, is_server_is_set ? MBEDTLS_SSL_IS_SERVER : MBEDTLS_SSL_IS_CLIENT, @@ -384,7 +397,11 @@ int8_t tls_sec_prot_lib_connect(tls_security_t *sec, bool is_server, const sec_p #endif // Export keys callback +#if (MBEDTLS_VERSION_MAJOR >= 3) + mbedtls_ssl_set_export_keys_cb(&sec->ssl, tls_sec_prot_lib_ssl_export_keys, sec); +#else mbedtls_ssl_conf_export_keys_ext_cb(&sec->conf, tls_sec_prot_lib_ssl_export_keys, sec); +#endif #if !defined(MBEDTLS_SSL_CONF_MIN_MINOR_VER) || !defined(MBEDTLS_SSL_CONF_MIN_MAJOR_VER) mbedtls_ssl_conf_min_version(&sec->conf, MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MAJOR_VERSION_3); @@ -395,7 +412,9 @@ int8_t tls_sec_prot_lib_connect(tls_security_t *sec, bool is_server, const sec_p #endif /* !defined(MBEDTLS_SSL_CONF_MAX_MINOR_VER) || !defined(MBEDTLS_SSL_CONF_MAX_MAJOR_VER) */ // Set certificate verify callback +#if (MBEDTLS_VERSION_MAJOR < 3) mbedtls_ssl_set_verify(&sec->ssl, tls_sec_prot_lib_x509_crt_verify, sec); +#endif /* Currently assuming we are running fast enough HW that ECC calculations are not blocking any normal operation. * @@ -432,7 +451,11 @@ int8_t tls_sec_prot_lib_process(tls_security_t *sec) return TLS_SEC_PROT_LIB_ERROR; } +#if (MBEDTLS_VERSION_MAJOR >= 3) + if (sec->ssl.private_state == MBEDTLS_SSL_HANDSHAKE_OVER) { +#else if (sec->ssl.state == MBEDTLS_SSL_HANDSHAKE_OVER) { +#endif return TLS_SEC_PROT_LIB_HANDSHAKE_OVER; } } @@ -469,16 +492,31 @@ static int tls_sec_prot_lib_ssl_recv(void *ctx, unsigned char *buf, size_t len) return ret; } -static int tls_sec_prot_lib_ssl_export_keys(void *p_expkey, const unsigned char *ms, +#if (MBEDTLS_VERSION_MAJOR >= 3) +static void tls_sec_prot_lib_ssl_export_keys(void *p_expkey, mbedtls_ssl_key_export_type type, + const unsigned char *secret, + size_t secret_len, + const unsigned char client_random[32], + const unsigned char server_random[32], + mbedtls_tls_prf_types tls_prf_type) +#else +static int tls_sec_prot_lib_ssl_export_keys(void *p_expkey, const unsigned char *secret, const unsigned char *kb, size_t maclen, size_t keylen, size_t ivlen, const unsigned char client_random[32], const unsigned char server_random[32], mbedtls_tls_prf_types tls_prf_type) +#endif { +#if (MBEDTLS_VERSION_MAJOR >= 3) + if (type != MBEDTLS_SSL_KEY_EXPORT_TLS12_MASTER_SECRET || secret_len < 48) { + return; + } +#else (void) kb; (void) maclen; (void) keylen; (void) ivlen; +#endif tls_security_t *sec = (tls_security_t *)p_expkey; @@ -487,18 +525,24 @@ static int tls_sec_prot_lib_ssl_export_keys(void *p_expkey, const unsigned char memcpy(random, client_random, 32); memcpy(&random[32], server_random, 32); - int ret = mbedtls_ssl_tls_prf(tls_prf_type, ms, 48, "client EAP encryption", + int ret = mbedtls_ssl_tls_prf(tls_prf_type, secret, 48, "client EAP encryption", random, 64, eap_tls_key_material, 128); if (ret != 0) { tr_error("key material PRF error"); +#if (MBEDTLS_VERSION_MAJOR < 3) return 0; +#endif } - sec->export_keys(sec->handle, ms, eap_tls_key_material); + sec->export_keys(sec->handle, secret, eap_tls_key_material); + +#if (MBEDTLS_VERSION_MAJOR < 3) return 0; +#endif } +#if (MBEDTLS_VERSION_MAJOR < 3) static int tls_sec_prot_lib_x509_crt_verify(void *ctx, mbedtls_x509_crt *crt, int certificate_depth, uint32_t *flags) { tls_security_t *sec = (tls_security_t *) ctx; @@ -605,6 +649,7 @@ static int tls_sec_prot_lib_x509_crt_server_verify(tls_security_t *sec, mbedtls_ return 0; } #endif +#endif static int tls_sec_lib_entropy_poll(void *ctx, unsigned char *output, size_t len, size_t *olen) { diff --git a/source/Service_Libs/fhss/channel_list.c b/source/Service_Libs/fhss/channel_list.c index a25ffe12b4..9af436a7ca 100644 --- a/source/Service_Libs/fhss/channel_list.c +++ b/source/Service_Libs/fhss/channel_list.c @@ -35,7 +35,7 @@ static bool channel_list_bit_test32(uint32_t word, int_fast8_t bit_number) { bool bitSet; - if (word & ((uint32_t) 1 << bit_number)) { + if (word & (1U << bit_number)) { bitSet = true; } else { bitSet = false; @@ -92,9 +92,9 @@ void channel_list_set_channel(uint32_t *list, int channel, bool active) return; } if (active) { - list[channel / 32] |= (1 << channel % 32); + list[channel / 32] |= (1U << channel % 32); } else { - list[channel / 32] &= ~(1 << channel % 32); + list[channel / 32] &= ~(1U << channel % 32); } return; } diff --git a/source/Service_Libs/fhss/fhss_ws.c b/source/Service_Libs/fhss/fhss_ws.c index 090520570b..061337395c 100644 --- a/source/Service_Libs/fhss/fhss_ws.c +++ b/source/Service_Libs/fhss/fhss_ws.c @@ -292,7 +292,7 @@ static int32_t fhss_channel_index_from_mask(const uint32_t *channel_mask, int32_ int32_t active_channels = 0; // Set channel maks outside excluded channels for (int32_t i = 0; i < number_of_channels; i++) { - if (channel_mask[0 + (i / 32)] & (1 << (i % 32))) { + if (channel_mask[i / 32] & (1U << (i % 32))) { if (channel_index == active_channels) { return i; } diff --git a/source/Service_Libs/hmac/hmac_md.c b/source/Service_Libs/hmac/hmac_md.c index 0ef22158e1..affc569b3e 100644 --- a/source/Service_Libs/hmac/hmac_md.c +++ b/source/Service_Libs/hmac/hmac_md.c @@ -29,12 +29,12 @@ int8_t hmac_md_calc(const alg_hmac_md_e md, const uint8_t *key, uint16_t key_len { #ifdef EXTRA_DEBUG_INFO // Extensive debug for now, to be disabled later - tr_debug("hmac_md key %s\n", trace_array(key, key_len)); + tr_debug("hmac_md key %s", trace_array(key, key_len)); const uint8_t *print_data = data; uint16_t print_data_len = data_len; while (true) { - tr_debug("hmac_md data %s\n", trace_array(print_data, print_data_len > 32 ? 32 : print_data_len)); + tr_debug("hmac_md data %s", trace_array(print_data, print_data_len > 32 ? 32 : print_data_len)); if (print_data_len > 32) { print_data_len -= 32; print_data += 32; @@ -81,7 +81,7 @@ int8_t hmac_md_calc(const alg_hmac_md_e md, const uint8_t *key, uint16_t key_len memcpy(result, result_value, result_len); #ifdef EXTRA_DEBUG_INFO - tr_debug("hmac_md result %s\n", trace_array(result_value, 20)); + tr_debug("hmac_md result %s", trace_array(result_value, 20)); #endif return 0; diff --git a/source/Service_Libs/nd_proxy/nd_proxy.c b/source/Service_Libs/nd_proxy/nd_proxy.c index 6d75180313..5a9dd6f748 100644 --- a/source/Service_Libs/nd_proxy/nd_proxy.c +++ b/source/Service_Libs/nd_proxy/nd_proxy.c @@ -349,7 +349,7 @@ int nd_proxy_downstream_interface_register(int8_t interface_id, nd_proxy_req_cb ns_list_foreach(nd_proxy_upstream_list_s, e, &upstream_interface_list) { if (proxy_cache_interface_enable_proxy(e->id, interface_id) == 0) { - tr_debug("Proxy bridge enabled for interface %i to %i\n", e->id, interface_id); + tr_debug("Proxy bridge enabled for interface %i to %i", e->id, interface_id); } } @@ -391,7 +391,7 @@ int nd_proxy_upstream_interface_register(int8_t interface_id, nd_proxy_req_cb *r ns_list_foreach(nd_proxy_downstream_list_s, e, &downstream_interface_list) { if (proxy_cache_interface_enable_proxy(interface_id, e->id) == 0) { - tr_debug("Proxy bridge enabled for interface %i to %i \n", interface_id, e->id); + tr_debug("Proxy bridge enabled for interface %i to %i", interface_id, e->id); } } return 0; diff --git a/source/Service_Libs/nist_aes_kw/nist_aes_kw.c b/source/Service_Libs/nist_aes_kw/nist_aes_kw.c index 98f6a69812..282d9e46ba 100644 --- a/source/Service_Libs/nist_aes_kw/nist_aes_kw.c +++ b/source/Service_Libs/nist_aes_kw/nist_aes_kw.c @@ -21,11 +21,7 @@ #include "ns_list.h" #include "ns_trace.h" -#if !defined(MBEDTLS_CONFIG_FILE) -#include "mbedtls/config.h" -#else -#include MBEDTLS_CONFIG_FILE -#endif +#include "mbedtls/version.h" #if defined(MBEDTLS_NIST_KW_C) && defined(HAVE_WS) && (defined(HAVE_PAE_SUPP) || defined(HAVE_PAE_AUTH)) #include "mbedtls/nist_kw.h" @@ -48,7 +44,7 @@ int8_t nist_aes_key_wrap(uint8_t is_wrap, const uint8_t *key, int16_t key_bits, const uint8_t *print_data = key; uint16_t print_data_len = key_bits / 8; while (true) { - tr_debug("nist_aes_key_wrap key %s\n", trace_array(print_data, print_data_len > 32 ? 32 : print_data_len)); + tr_debug("nist_aes_key_wrap key %s", trace_array(print_data, print_data_len > 32 ? 32 : print_data_len)); if (print_data_len > 32) { print_data_len -= 32; print_data += 32; @@ -60,7 +56,7 @@ int8_t nist_aes_key_wrap(uint8_t is_wrap, const uint8_t *key, int16_t key_bits, print_data = input; print_data_len = input_len; while (true) { - tr_debug("nist_aes_key_wrap in %s\n", trace_array(print_data, print_data_len > 32 ? 32 : print_data_len)); + tr_debug("nist_aes_key_wrap in %s", trace_array(print_data, print_data_len > 32 ? 32 : print_data_len)); if (print_data_len > 32) { print_data_len -= 32; print_data += 32; @@ -95,7 +91,7 @@ int8_t nist_aes_key_wrap(uint8_t is_wrap, const uint8_t *key, int16_t key_bits, print_data = output; print_data_len = *output_len; while (true) { - tr_debug("nist_aes_key_wrap out %s\n", trace_array(print_data, print_data_len > 32 ? 32 : print_data_len)); + tr_debug("nist_aes_key_wrap out %s", trace_array(print_data, print_data_len > 32 ? 32 : print_data_len)); if (print_data_len > 32) { print_data_len -= 32; print_data += 32; diff --git a/source/Service_Libs/utils/ns_time.c b/source/Service_Libs/utils/ns_time.c index 9e8bf761b3..e0aabe979e 100644 --- a/source/Service_Libs/utils/ns_time.c +++ b/source/Service_Libs/utils/ns_time.c @@ -22,6 +22,9 @@ static ns_time_api_system_time_callback *system_time_read_callback = NULL; static ns_time_api_system_time_write_callback *system_time_write_callback = NULL; +static ns_time_api_time_configuration_notify_callback *system_time_configuration_notify_callback = NULL; + +static bool system_time_acquired = false; void ns_time_api_system_time_callback_set(ns_time_api_system_time_callback callback_rd) { @@ -33,10 +36,16 @@ void ns_time_api_system_time_write_callback_set(ns_time_api_system_time_write_ca system_time_write_callback = callback_wr; } +void ns_time_api_time_configuration_notify_callback_set(ns_time_api_time_configuration_notify_callback callback_wr) +{ + system_time_configuration_notify_callback = callback_wr; +} + int ns_time_system_time_write(uint64_t time_write) { if (system_time_write_callback) { system_time_write_callback(time_write); + system_time_acquired = true; return 0; } @@ -53,3 +62,23 @@ int ns_time_system_time_read(uint64_t *time_read) return -1; } + +int ns_time_system_timezone_info_notify(timezone_info_t *info_ptr) +{ + if (system_time_configuration_notify_callback && info_ptr) { + system_time_configuration_notify_callback(info_ptr); + return 0; + } + + return -1; +} + +void ns_time_system_time_acquired_set(void) +{ + system_time_acquired = true; +} + +bool ns_time_system_time_acquired_get(void) +{ + return system_time_acquired; +} diff --git a/source/Service_Libs/utils/ns_time.h b/source/Service_Libs/utils/ns_time.h index 27299ce0bb..34256af055 100644 --- a/source/Service_Libs/utils/ns_time.h +++ b/source/Service_Libs/utils/ns_time.h @@ -22,6 +22,7 @@ * \file ns_time.h * \brief Nanostack internal time handling API. */ +#include "ns_time_api.h" /** * Write new time as a platform time @@ -51,6 +52,33 @@ int ns_time_system_time_write(uint64_t time_write); */ int ns_time_system_time_read(uint64_t *time_read); +/** + * Notify Time zone and daylight saving time information + * + * \param info_ptr time zone information pointer. + * + * \return 0 in success. + * \return <0 in case of errors. + * + */ +int ns_time_system_timezone_info_notify(timezone_info_t *info_ptr); +/** + * Set system time acquired + * + * Sets system time acquired (e.g. has been acquired from network) + * + */ +void ns_time_system_time_acquired_set(void); + +/** + * Get system time acquired + * + * Checks whether system time has been acquired (e.g. has been written) + * + * \return TRUE system time has been acquired, FALSE system time has not been acquired + * + */ +bool ns_time_system_time_acquired_get(void); #endif /* _NS_TIME_H_ */ diff --git a/source/configs/base/cfg_ws_host.h b/source/configs/base/cfg_ws_host.h new file mode 100644 index 0000000000..49122b9da6 --- /dev/null +++ b/source/configs/base/cfg_ws_host.h @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2021, Pelion and affiliates. + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define HAVE_WS +#define HAVE_WS_HOST +#define HAVE_WS_VERSION_1_1 +#define HAVE_RPL +#define HAVE_MPL +#define HAVE_6LOWPAN_ND +#define HAVE_IPV6_ND +#define HAVE_PAE_SUPP +#define HAVE_6LOWPAN_ROUTER \ No newline at end of file diff --git a/source/configs/base/cfg_ws_router.h b/source/configs/base/cfg_ws_router.h index a8a07c5700..78f3537941 100644 --- a/source/configs/base/cfg_ws_router.h +++ b/source/configs/base/cfg_ws_router.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Pelion and affiliates. + * Copyright (c) 2019-2021, Pelion and affiliates. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -15,12 +15,7 @@ * limitations under the License. */ -#define HAVE_6LOWPAN_ROUTER +#include "cfg_ws_host.h" + #define HAVE_WS_ROUTER -#define HAVE_RPL -#define HAVE_IPV6_ND -#define HAVE_6LOWPAN_ND -#define HAVE_MPL -#define HAVE_WS -#define HAVE_PAE_SUPP #define HAVE_EAPOL_RELAY diff --git a/source/configs/cfg_generic.h b/source/configs/cfg_generic.h index d17b137850..c7a27d4c2d 100644 --- a/source/configs/cfg_generic.h +++ b/source/configs/cfg_generic.h @@ -32,4 +32,5 @@ #define TCP_TEST #define THREAD_THCI_SUPPORT #define HAVE_WS +#define HAVE_WS_VERSION_1_1 #define MLE_TEST diff --git a/source/configs/cfg_ws_host.h b/source/configs/cfg_ws_host.h new file mode 100644 index 0000000000..74b3113c48 --- /dev/null +++ b/source/configs/cfg_ws_host.h @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2021, Pelion and affiliates. + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#include "base/cfg_ws_host.h" + +#define FEA_TRACE_SUPPORT +#define EXTRA_CONSISTENCY_CHECKS + diff --git a/source/ipv6_stack/protocol_ipv6.c b/source/ipv6_stack/protocol_ipv6.c index 6041ac623a..982405b034 100644 --- a/source/ipv6_stack/protocol_ipv6.c +++ b/source/ipv6_stack/protocol_ipv6.c @@ -323,16 +323,16 @@ static void ipv6_nd_bootstrap(protocol_interface_info_entry_t *cur) break; case IPV6_ROUTER_SOLICATION: - tr_debug("Waiting for ICMPv6 Router Advertisement"); if (ipv6_nd_rs(cur)) { + tr_debug("Waiting for ICMPv6 Router Advertisement"); if (cur->ipv6_configure->routerSolicationRetryCounter != ROUTER_SOL_MAX_COUNTER) { cur->ipv6_configure->routerSolicationRetryCounter++; } - cur->ipv6_configure->ND_TIMER = (cur->ipv6_configure->routerSolicationRetryCounter * 25); - - } else { - cur->ipv6_configure->ND_TIMER = 1; } + if (cur->ipv6_configure->routerSolicationRetryCounter == 0) { + cur->ipv6_configure->routerSolicationRetryCounter++; + } + cur->ipv6_configure->ND_TIMER = (cur->ipv6_configure->routerSolicationRetryCounter * 25); break; case IPV6_GP_GEN: diff --git a/source/libDHCPv6/libDHCPv6_vendordata.c b/source/libDHCPv6/libDHCPv6_vendordata.c index fb6b909c7c..0eda579b32 100644 --- a/source/libDHCPv6/libDHCPv6_vendordata.c +++ b/source/libDHCPv6/libDHCPv6_vendordata.c @@ -137,7 +137,7 @@ uint8_t *net_vendor_option_current_time_read(uint8_t *ptr, uint16_t length, int3 } option_len = common_read_16_bit(ptr + 2); - ptr += 4; + ptr += 2 * sizeof(uint16_t); if (option_len < 3 * sizeof(uint32_t)) { // Corrupted as not enough room for fields @@ -147,11 +147,70 @@ uint8_t *net_vendor_option_current_time_read(uint8_t *ptr, uint16_t length, int3 if (era) { *era = (int32_t)common_read_32_bit(ptr); } + if (offset) { *offset = common_read_32_bit(ptr + sizeof(uint32_t)); } + if (fraction) { - *fraction = common_read_32_bit(ptr + 2 * sizeof(uint32_t)); + *fraction = common_read_32_bit(ptr + sizeof(uint32_t) + sizeof(uint32_t)); + } + + return ptr; +} + +uint16_t net_vendor_option_time_configuration_length(void) +{ + return 4 + 1 * sizeof(uint64_t) + 2 * sizeof(int16_t) + 1 * sizeof(uint16_t); +} + +uint8_t *net_vendor_option_time_configuration_write(uint8_t *ptr, uint64_t timestamp, int16_t timezone, int16_t deviation, uint16_t status) +{ + + ptr = common_write_16_bit(ARM_DHCP_VENDOR_DATA_TIME_CONFIGURATION, ptr); + ptr = common_write_16_bit(1 * sizeof(uint64_t) + 2 * sizeof(int16_t) + 1 * sizeof(uint16_t), ptr); + ptr = common_write_16_bit(status, ptr); + ptr = common_write_64_bit(timestamp, ptr); + ptr = common_write_16_bit((uint16_t)deviation, ptr); + ptr = common_write_16_bit((uint16_t)timezone, ptr); + return ptr; +} + +uint8_t *net_vendor_option_time_configuration_read(uint8_t *ptr, uint16_t length, uint64_t *timestamp, int16_t *timezone, int16_t *deviation, uint16_t *status) +{ + uint16_t option_len; + + if (length < net_vendor_option_time_configuration_length()) { + // Corrupted as there is no room for all fields + return 0; + } + + if (common_read_16_bit(ptr) != ARM_DHCP_VENDOR_DATA_TIME_CONFIGURATION) { + return 0; + } + + option_len = common_read_16_bit(ptr + sizeof(uint16_t)); + ptr += 2 * sizeof(uint16_t); + + if (option_len < 1 * sizeof(uint64_t) + 2 * sizeof(int16_t) + 1 * sizeof(uint16_t)) { + // Corrupted as not enough room for fields + return 0; + } + + if (status) { + *status = (uint16_t)common_read_16_bit(ptr); + } + + if (timestamp) { + *timestamp = common_read_64_bit(ptr + sizeof(uint16_t)); + } + + if (deviation) { + *deviation = (int16_t)common_read_16_bit(ptr + sizeof(uint16_t) + sizeof(uint64_t)); + } + + if (timezone) { + *timezone = (int16_t)common_read_16_bit(ptr + sizeof(uint16_t) + sizeof(uint64_t) + sizeof(uint16_t)); } return ptr; diff --git a/source/libDHCPv6/libDHCPv6_vendordata.h b/source/libDHCPv6/libDHCPv6_vendordata.h index a9974e8862..1fc33d0d44 100644 --- a/source/libDHCPv6/libDHCPv6_vendordata.h +++ b/source/libDHCPv6/libDHCPv6_vendordata.h @@ -66,6 +66,17 @@ * */ #define ARM_DHCP_VENDOR_DATA_NETWORK_TIME 298 +/* ARM Defined vendor data option to distribute Time configuration + * + * uint16_t status Bit field for status + * bit 1 Daylight saving time status 0 = false 1 = true + * Additional bits reserved for future and are ignored on receive + * uint64_t timestamp Time stamp of the Daylight saving time change + * int16_t deviation Change that is applied when time stamp is reached + * int16_t timezone Time zone information in minutes compared to UTC time + */ +#define ARM_DHCP_VENDOR_DATA_TIME_CONFIGURATION 299 + /* DHCPv6 vendor options to distribute ARM vendor data*/ uint16_t net_dns_option_vendor_option_data_dns_query_length(char *domain); @@ -78,5 +89,8 @@ uint16_t net_vendor_option_current_time_length(void); uint8_t *net_vendor_option_current_time_write(uint8_t *ptr, int32_t era, uint32_t offset, uint32_t fraction); uint8_t *net_vendor_option_current_time_read(uint8_t *ptr, uint16_t length, int32_t *era, uint32_t *offset, uint32_t *fraction); +uint16_t net_vendor_option_time_configuration_length(void); +uint8_t *net_vendor_option_time_configuration_write(uint8_t *ptr, uint64_t timestamp, int16_t timezone, int16_t deviation, uint16_t status); +uint8_t *net_vendor_option_time_configuration_read(uint8_t *ptr, uint16_t length, uint64_t *timestamp, int16_t *timezone, int16_t *deviation, uint16_t *status); #endif /* LIBDHCPV6_VENDOR_DATA_H_ */ diff --git a/source/libNET/src/ns_net.c b/source/libNET/src/ns_net.c index dd3883c6ef..eecd38f772 100644 --- a/source/libNET/src/ns_net.c +++ b/source/libNET/src/ns_net.c @@ -67,7 +67,7 @@ #include "6LoWPAN/Thread/thread_routing.h" #include "6LoWPAN/Thread/thread_bootstrap.h" #include "6LoWPAN/Thread/thread_management_internal.h" -#include "6LoWPAN/ws/ws_bootstrap.h" +#include "6LoWPAN/ws/ws_common.h" #ifdef HAVE_WS #include "6LoWPAN/ws/ws_pae_controller.h" #endif @@ -168,7 +168,7 @@ int8_t arm_net_nwk_scan(int8_t interface_id, channel_list_s *scan_list, void (*p if (cur->lowpan_info & INTERFACE_NWK_ACTIVE) { ret_val = -1; } else if (arm_channel_list_validation(scan_list)) { - tr_debug("Given channel mask is empty!\n"); + tr_debug("Given channel mask is empty!"); ret_val = -2; } else { nwk_scan_params_t *scan_params = &cur->mac_parameters->nwk_scan_params; @@ -768,7 +768,7 @@ static int arm_net_channel_bit_mask_to_number(const uint32_t *channel_mask) for (j = 0; j < 8; j++) { for (i = 0; i < 32; i++) { - if (channel_mask[j] & ((uint32_t)1 << i)) { + if (channel_mask[j] & (1U << i)) { break; } } @@ -804,7 +804,7 @@ int8_t arm_nwk_interface_network_driver_set(int8_t interface_id, const channel_l protocol_interface_info_entry_t *cur = 0; if (arm_channel_list_validation(nwk_channel_list)) { - tr_debug("Given channel mask is empty!\n"); + tr_debug("Given channel mask is empty!"); return -5; } @@ -981,15 +981,21 @@ int8_t arm_nwk_link_layer_security_mode(int8_t interface_id, net_6lowpan_link_la int8_t arm_network_certificate_chain_set(const arm_certificate_chain_entry_s *chain_info) { + int8_t ret = -2; + #if !defined(PANA) && !defined(HAVE_WS) (void)chain_info; #endif #ifdef HAVE_WS - ws_pae_controller_certificate_chain_set(chain_info); + ret = ws_pae_controller_certificate_chain_set(chain_info); #endif - return pana_interface_certificate_chain_set(chain_info); +#ifdef PANA + ret = pana_interface_certificate_chain_set(chain_info); +#endif + + return ret; } int8_t arm_network_trusted_certificate_add(const arm_certificate_entry_s *cert) @@ -1207,7 +1213,7 @@ int8_t arm_nwk_interface_configure_6lowpan_bootstrap_set(int8_t interface_id, ne if (net_6lowpan_mode_extension == NET_6LOWPAN_THREAD) { ret_val = thread_node_bootstrap_init(interface_id, bootstrap_mode); } else if (net_6lowpan_mode_extension == NET_6LOWPAN_WS) { - ret_val = ws_bootstrap_init(interface_id, bootstrap_mode); + ret_val = ws_common_init(interface_id, bootstrap_mode); } else { ret_val = arm_6lowpan_bootstarp_bootstrap_set(interface_id, bootstrap_mode, net_6lowpan_mode_extension); } @@ -1226,7 +1232,7 @@ int8_t arm_nwk_set_channel_list(int8_t interface_id, const channel_list_s *nwk_c } if (arm_channel_list_validation(nwk_channel_list)) { - tr_debug("Given channel mask is empty!\n"); + tr_debug("Given channel mask is empty!"); return -2; } diff --git a/sources.mk b/sources.mk index 7c5af85feb..1b6916f4b7 100644 --- a/sources.mk +++ b/sources.mk @@ -23,6 +23,9 @@ SRCS += \ source/6LoWPAN/ws/ws_mpx_header.c \ source/6LoWPAN/ws/ws_neighbor_class.c \ source/6LoWPAN/ws/ws_bootstrap.c \ + source/6LoWPAN/ws/ws_bootstrap_6lbr.c \ + source/6LoWPAN/ws/ws_bootstrap_ffn.c \ + source/6LoWPAN/ws/ws_bootstrap_lfn.c \ source/6LoWPAN/ws/ws_common.c \ source/6LoWPAN/ws/ws_management_api.c \ source/6LoWPAN/ws/ws_bbr_api.c \ @@ -43,6 +46,7 @@ SRCS += \ source/6LoWPAN/ws/ws_eapol_pdu.c \ source/6LoWPAN/ws/ws_stats.c \ source/6LoWPAN/ws/ws_cfg_settings.c \ + source/6LoWPAN/ws/ws_phy.c \ source/BorderRouter/border_router.c \ source/Common_Protocols/icmpv6.c \ source/Common_Protocols/icmpv6_prefix.c \ @@ -83,6 +87,7 @@ SRCS += \ source/MAC/IEEE802_15_4/sw_mac.c \ source/MAC/IEEE802_15_4/mac_fhss_callbacks.c \ source/MAC/IEEE802_15_4/mac_cca_threshold.c \ + source/MAC/IEEE802_15_4/mac_mode_switch.c \ source/MAC/ethernet/ethernet_mac_api.c \ source/MAC/serial/serial_mac_api.c \ source/MAC/virtual_rf/virtual_rf_client.c \