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 \