diff --git a/README.md b/README.md index f614033fa7e..ddddf390c72 100644 --- a/README.md +++ b/README.md @@ -3,37 +3,29 @@ ARM Mesh networking stack This repository contains the ARM mesh networking stack that provides support for the following mesh protocols: - * 6LoWPAN with Neighbor Discovery (ND) and Mesh Link Establishment (MLE) - * Thread - * Wi-SUN +* 6LoWPAN with Neighbor Discovery (ND) and Mesh Link Establishment (MLE) +* Wi-SUN - All networking stacks are using IEEE 802.15.4 based radios. +All networking stacks are using IEEE 802.15.4 based radios. The full documentation is hosted in [Mbed OS documentation](https://os.mbed.com/docs/mbed-os/latest/reference/mesh-tech.html). -On mbed OS, mesh networking stacks can be used through [Mbed Mesh API](https://os.mbed.com/docs/mbed-os/latest/apis/mesh-api.html) and [Network Socket API](https://os.mbed.com/docs/mbed-os/v5.11/apis/network-socket.html). +On mbed OS, mesh networking stacks can be used through [Mbed Mesh API](https://os.mbed.com/docs/mbed-os/latest/apis/mesh-api.html) and [Network Socket API](https://os.mbed.com/docs/mbed-os/latest/apis/network-socket.html). To see, how the mesh networking stack works, check the example application [mbed-os-example-mesh-minimal](https://github.com/ARMmbed/mbed-os-example-mesh-minimal). - -##6LoWPAN with ND and MLE + +## 6LoWPAN with ND and MLE This networking stack is using standard 6LoWPAN and uses: * Neighbor Discovery Protocol ([RFC4861](https://tools.ietf.org/html/rfc4861)) to locate other devices in the mesh network. * Mesh-Link-Establishment ([draft-kelsey-intarea-mesh-link-establishment-06](https://tools.ietf.org/html/draft-kelsey-intarea-mesh-link-establishment-06)) is used for establishing and configuring secure radio links. - -##Thread -Thread is standardized by [Thread group](https://www.threadgroup.org/). - -![](docs/img/thread_certified.png) -mbed OS is now a Thread Certified Component. Using IPv6 with 6LoWPAN as the foundation, Thread technology provides a low-power, self-healing mesh network designed for the home. -##Wi-SUN +## Wi-SUN Wi-SUN (Smart Utility Networks) specification is standardized by [Wi-SUN Alliance](https://www.wi-sun.org/). -Mbed OS release 5.12 contains the initial Mbed Wi-SUN FAN implementation. Functionality of the Mbed Wi-SUN network stack will be updated when the Wi-SUN protocol is specified further. ## License diff --git a/docs/img/thread_certified.png b/docs/img/thread_certified.png deleted file mode 100644 index c86ee53a7e8..00000000000 Binary files a/docs/img/thread_certified.png and /dev/null differ diff --git a/mbed_lib.json b/mbed_lib.json index 6640b5e3ef5..1fddbd2cbac 100644 --- a/mbed_lib.json +++ b/mbed_lib.json @@ -9,12 +9,6 @@ }, "macros": ["NS_USE_EXTERNAL_MBED_TLS"], "target_overrides": { - "KW24D": { - "nanostack.configuration": "lowpan_router" - }, - "NCS36510": { - "nanostack.configuration": "lowpan_router" - }, "TB_SENSE_12": { "nanostack.configuration": "lowpan_router" }, diff --git a/nanostack/fhss_config.h b/nanostack/fhss_config.h index 9a286128acf..5c55965733f 100644 --- a/nanostack/fhss_config.h +++ b/nanostack/fhss_config.h @@ -88,6 +88,16 @@ typedef struct fhss_configuration { */ typedef int32_t fhss_vendor_defined_cf(const fhss_api_t *api, uint16_t slot, uint8_t eui64[8], uint16_t bsi, uint16_t number_of_channels); +/** + * \brief Struct fhss_config_parameters defines FHSS configuration parameters. + * + */ +typedef struct fhss_config_parameters { + /** Number of channel retries defines how many consecutive channels are used when retransmitting a frame after initial transmission channel. */ + uint8_t number_of_channel_retries; +} fhss_config_parameters_t; + + /** * \brief Struct fhss_ws_configuration defines configuration of WS FHSS. */ @@ -125,6 +135,9 @@ typedef struct fhss_ws_configuration { /** Vendor defined channel function. */ fhss_vendor_defined_cf *vendor_defined_cf; + /** Configuration parameters. */ + fhss_config_parameters_t config_parameters; + } fhss_ws_configuration_t; /** diff --git a/nanostack/fhss_test_api.h b/nanostack/fhss_test_api.h index 270c5a27a31..e6a93cc2c0b 100644 --- a/nanostack/fhss_test_api.h +++ b/nanostack/fhss_test_api.h @@ -39,6 +39,17 @@ extern "C" { */ int8_t fhss_set_optimal_packet_length(const fhss_api_t *fhss_api, uint16_t packet_length); +/** + * \brief Set number of channel retries + * + * \param fhss_api FHSS instance. + * \param number_of_channel_retries Number of channel retries + * + * \return 0 Success + * \return -1 Failure + */ +int8_t fhss_set_number_of_channel_retries(const fhss_api_t *fhss_api, uint8_t number_of_channel_retries); + #ifdef __cplusplus } #endif diff --git a/nanostack/mlme.h b/nanostack/mlme.h index 233e349ba0d..841f097cb66 100644 --- a/nanostack/mlme.h +++ b/nanostack/mlme.h @@ -264,6 +264,8 @@ typedef enum { macAutoRequestKeyIndex = 0x7b, /*= 0 success + * + */ +int ws_bbr_key_storage_memory_set(int8_t interface_id, uint8_t key_storages_number, const uint16_t *key_storage_size, void **key_storages); + +/** + * ws_bbr_key_storage_settings_set sets key storage settings + * + * This functions can be used to set the settings of EAPOL key storage. + * Allocation max number and allocation size sets the settings that are used when key storage + * memory is allocated dynamically from heap. These settings must be set before (first) interface + * up and shall not be set if key storage memory is set by ws_pae_key_storage_memory_set() call. + * + * \param interface_id Network interface ID. + * \param alloc_max_number maximum number of allocation made to dynamic memory. + * \param alloc_size size of each allocation. + * \param storing_interval interval in which the check to store to NVM is made. + * + * \return < 0 failure + * \return >= 0 success + * + */ +int ws_bbr_key_storage_settings_set(int8_t interface_id, uint8_t alloc_max_number, uint16_t alloc_size, uint16_t storing_interval); + #endif /* WS_BBR_API_H_ */ diff --git a/nanostack/ws_management_api.h b/nanostack/ws_management_api.h index 99092ba5f58..37e66999ab7 100644 --- a/nanostack/ws_management_api.h +++ b/nanostack/ws_management_api.h @@ -75,10 +75,16 @@ extern "C" { #define CHANNEL_SPACING_100 0x03 // 100 khz #define CHANNEL_SPACING_250 0x04 // 250 khz -#define NETWORK_SIZE_CERTIFICATE 0x00 -#define NETWORK_SIZE_SMALL 0x01 -#define NETWORK_SIZE_MEDIUM 0x08 -#define NETWORK_SIZE_LARGE 0x10 +/* + * 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 + */ + +#define NETWORK_SIZE_CERTIFICATE 0x00 // Network configuration used in Wi-SUN certification +#define NETWORK_SIZE_SMALL 0x01 // Small networks +#define NETWORK_SIZE_MEDIUM 0x08 // 100 - 800 device networks are medium sized +#define NETWORK_SIZE_LARGE 0x0F // 800 - 1500 device networks are large +#define NETWORK_SIZE_XLARGE 0x19 // 2500+ devices #define NETWORK_SIZE_AUTOMATIC 0xFF /** Temporary API change flag. this will be removed when new version of API is implemented on applications @@ -229,9 +235,9 @@ int ws_management_regulatory_domain_validate( * * timing parameters follows the specification example from Wi-SUN specification * - * Default value: medium - * small network size: hundreds of devices - * Large network size: thousands of devices + * Default value: medium 100 - 800 device + * small network size: less than 100 devices + * Large network size: 800 - 1500 devices * automatic: when discovering the network network size is learned * from advertisements and timings adjusted accordingly * diff --git a/source/6LoWPAN/Bootstraps/Generic/protocol_6lowpan.c b/source/6LoWPAN/Bootstraps/Generic/protocol_6lowpan.c index bacac2e6a59..b89117b7c79 100644 --- a/source/6LoWPAN/Bootstraps/Generic/protocol_6lowpan.c +++ b/source/6LoWPAN/Bootstraps/Generic/protocol_6lowpan.c @@ -83,6 +83,9 @@ #define TRACE_GROUP_LOWPAN "6lo" #define TRACE_GROUP "6lo" +/* Data rate for application used in Stagger calculation */ +#define STAGGER_DATARATE_FOR_APPL(n) ((n)*25/100) + #ifdef HAVE_RPL rpl_domain_t *protocol_6lowpan_rpl_domain; /* Having to sidestep old rpl_dodag_t type for the moment */ @@ -800,7 +803,7 @@ bool protocol_6lowpan_latency_estimate_get(int8_t interface_id, uint32_t *latenc latency_estimate = 100; } else if (thread_info(cur_interface)) { // thread network - latency_estimate = 1000; + latency_estimate = 2000; } else if (ws_info(cur_interface)) { latency_estimate = ws_common_latency_estimate_get(cur_interface); } else { @@ -820,14 +823,13 @@ bool protocol_6lowpan_stagger_estimate_get(int8_t interface_id, uint32_t data_am { size_t network_size; uint32_t datarate; + uint32_t stagger_value; protocol_interface_info_entry_t *cur_interface = protocol_stack_interface_info_get_by_id(interface_id); if (!cur_interface) { return false; } - *stagger_min = 1; - if (cur_interface->eth_mac_api) { // either PPP or Ethernet interface. network_size = 1; @@ -849,16 +851,25 @@ bool protocol_6lowpan_stagger_estimate_get(int8_t interface_id, uint32_t data_am // If no data amount given, use 1kB data_amount = 1; } - /**Example: - * Maximum stagger value to send 1kB on 50 devices network using datarate 50000 kb/: - * (1 * 1024 * 8 * 50) / (50000/4)) = ~ 32s - * - * devices: 50, datarate: 250kbps => stagger ~ 6s - * devices: 1000, datarate: 50kbps => stagger ~ 655s + + /* + * Do not occupy whole bandwidth, leave space for network formation etc... + */ + datarate = STAGGER_DATARATE_FOR_APPL(datarate); + stagger_value = 1 + ((data_amount * 1024 * 8 * network_size) / datarate); + /** + * Example: + * Maximum stagger value to send 1kB to 100 device network using data rate of 50kbs: + * 1 + (1 * 1024 * 8 * 100) / (50000*0.25) = 66s */ - /* Do not occupy whole bandwidth, halve the theoretical datarate and reserve room for other channel usage */ - datarate = datarate / 4; - *stagger_max = (uint16_t) * stagger_min + ((data_amount * 1024 * 8 * network_size) / datarate); + + *stagger_min = stagger_value / 5; // Minimum stagger value is 1/5 of the max + + if (stagger_value > 0xFFFF) { + *stagger_max = 0xFFFF; + } else { + *stagger_max = (uint16_t)stagger_value; + } // Randomize stagger value *stagger_rand = randLIB_get_random_in_range(*stagger_min, *stagger_max); diff --git a/source/6LoWPAN/Bootstraps/Generic/protocol_6lowpan_bootstrap.c b/source/6LoWPAN/Bootstraps/Generic/protocol_6lowpan_bootstrap.c index cbe3e12c67e..0a21788cc26 100644 --- a/source/6LoWPAN/Bootstraps/Generic/protocol_6lowpan_bootstrap.c +++ b/source/6LoWPAN/Bootstraps/Generic/protocol_6lowpan_bootstrap.c @@ -588,7 +588,7 @@ static void mle_neigh_entry_update_by_mle_tlv_list(int8_t interface_id, mac_neig uint8_t link_idr; uint8_t iop_flags; if (mle_link_quality_tlv_parse(mac64, short_address, mle_tlv_info.dataPtr, mle_tlv_info.tlvLen, &iop_flags, &link_idr)) { - etx_remote_incoming_idr_update(interface_id, link_idr, entry_temp->index); + etx_remote_incoming_idr_update(interface_id, link_idr, entry_temp->index, entry_temp->mac64); if ((iop_flags & MLE_NEIGHBOR_PRIORITY_LINK) == MLE_NEIGHBOR_PRIORITY_LINK) { entry_temp->link_role = CHILD_NEIGHBOUR; @@ -965,9 +965,9 @@ int protocol_6lowpan_router_synch_to_new_router(protocol_interface_info_entry_t static uint8_t mle_calculate_idr(int8_t interface_id, mle_message_t *mle_msg, mac_neighbor_table_entry_t *entry_temp) { if (!entry_temp) { - return etx_lqi_dbm_update(-2, mle_msg->lqi, mle_msg->dbm, 0) >> 3; + return etx_lqi_dbm_update(-2, mle_msg->lqi, mle_msg->dbm, 0, NULL) >> 3; } - return etx_lqi_dbm_update(interface_id, mle_msg->lqi, mle_msg->dbm, entry_temp->index) >> 3; + return etx_lqi_dbm_update(interface_id, mle_msg->lqi, mle_msg->dbm, entry_temp->index, entry_temp->mac64) >> 3; } @@ -1609,7 +1609,7 @@ static void lowpan_neighbor_entry_remove_notify(mac_neighbor_table_entry_t *entr } mac_helper_devicetable_remove(cur_interface->mac_api, entry_ptr->index, entry_ptr->mac64); //Removes ETX neighbor - etx_neighbor_remove(cur_interface->id, entry_ptr->index); + etx_neighbor_remove(cur_interface->id, entry_ptr->index, entry_ptr->mac64); //Remove MLE frame counter info mle_service_frame_counter_entry_delete(cur_interface->id, entry_ptr->index); diff --git a/source/6LoWPAN/MAC/mac_helper.c b/source/6LoWPAN/MAC/mac_helper.c index e33c7fe6f95..9e9b5a266c6 100644 --- a/source/6LoWPAN/MAC/mac_helper.c +++ b/source/6LoWPAN/MAC/mac_helper.c @@ -900,11 +900,13 @@ void mac_helper_devicetable_remove(mac_api_t *mac_api, uint8_t attribute_index, set_req.attr_index = attribute_index; set_req.value_pointer = (void *)&device_desc; set_req.value_size = sizeof(mlme_device_descriptor_t); - tr_debug("Unregister Device %u, mac64: %s", attribute_index, trace_array(mac64, 8)); + if (mac64) { + tr_debug("Unregister Device %u, mac64: %s", attribute_index, trace_array(mac64, 8)); + } mac_api->mlme_req(mac_api, MLME_SET, &set_req); } -void mac_helper_device_description_write(protocol_interface_info_entry_t *cur, mlme_device_descriptor_t *device_desc, uint8_t *mac64, uint16_t mac16, uint32_t frame_counter, bool exempt) +void mac_helper_device_description_write(protocol_interface_info_entry_t *cur, mlme_device_descriptor_t *device_desc, const uint8_t *mac64, uint16_t mac16, uint32_t frame_counter, bool exempt) { memcpy(device_desc->ExtAddress, mac64, 8); device_desc->ShortAddress = mac16; @@ -914,14 +916,19 @@ void mac_helper_device_description_write(protocol_interface_info_entry_t *cur, m } void mac_helper_devicetable_set(const mlme_device_descriptor_t *device_desc, protocol_interface_info_entry_t *cur, uint8_t attribute_index, uint8_t keyID, bool force_set) - { - if (!cur->mac_api) { + if (!force_set && cur->mac_parameters->SecurityEnabled && cur->mac_parameters->mac_default_key_index != keyID) { + tr_debug("Do not set counter by index %u != %u", cur->mac_parameters->mac_default_key_index, keyID); return; } - if (!force_set && cur->mac_parameters->SecurityEnabled && cur->mac_parameters->mac_default_key_index != keyID) { - tr_debug("Do not set counter by index %u != %u", cur->mac_parameters->mac_default_key_index, keyID); + tr_debug("Register Device %u, mac16 %x mac64: %s, %"PRIu32, attribute_index, device_desc->ShortAddress, trace_array(device_desc->ExtAddress, 8), device_desc->FrameCounter); + mac_helper_devicetable_direct_set(cur->mac_api, device_desc, attribute_index); +} + +void mac_helper_devicetable_direct_set(struct mac_api_s *mac_api, const mlme_device_descriptor_t *device_desc, uint8_t attribute_index) +{ + if (!mac_api) { return; } @@ -930,7 +937,20 @@ void mac_helper_devicetable_set(const mlme_device_descriptor_t *device_desc, pro set_req.attr_index = attribute_index; set_req.value_pointer = (void *)device_desc; set_req.value_size = sizeof(mlme_device_descriptor_t); - tr_debug("Register Device %u, mac16 %x mac64: %s, %"PRIu32, attribute_index, device_desc->ShortAddress, trace_array(device_desc->ExtAddress, 8), device_desc->FrameCounter); + mac_api->mlme_req(mac_api, MLME_SET, &set_req); +} + +void mac_helper_devicetable_ack_trig(const mlme_device_descriptor_t *device_desc, protocol_interface_info_entry_t *cur) +{ + if (!cur->mac_api) { + return; + } + + mlme_set_t set_req; + set_req.attr = macDevicePendingAckTrig; + set_req.attr_index = 0; + set_req.value_pointer = (void *)device_desc; + set_req.value_size = sizeof(mlme_device_descriptor_t); cur->mac_api->mlme_req(cur->mac_api, MLME_SET, &set_req); } diff --git a/source/6LoWPAN/MAC/mac_helper.h b/source/6LoWPAN/MAC/mac_helper.h index 3e6ac27897e..6c68c6dc2f0 100644 --- a/source/6LoWPAN/MAC/mac_helper.h +++ b/source/6LoWPAN/MAC/mac_helper.h @@ -121,9 +121,14 @@ int8_t mac_helper_key_link_frame_counter_set(int8_t interface_id, uint32_t seq_p void mac_helper_devicetable_remove(struct mac_api_s *mac_api, uint8_t attribute_index, uint8_t *mac64); -void mac_helper_device_description_write(struct protocol_interface_info_entry *cur, mlme_device_descriptor_t *device_desc, uint8_t *mac64, uint16_t mac16, uint32_t frame_counter, bool exempt); +void mac_helper_device_description_write(struct protocol_interface_info_entry *cur, mlme_device_descriptor_t *device_desc, const uint8_t *mac64, uint16_t mac16, uint32_t frame_counter, bool exempt); void mac_helper_devicetable_set(const mlme_device_descriptor_t *device_dec, struct protocol_interface_info_entry *cur, uint8_t attribute_index, uint8_t keyID, bool force_set); + +void mac_helper_devicetable_direct_set(struct mac_api_s *mac_api, const mlme_device_descriptor_t *device_desc, uint8_t attribute_index); + +void mac_helper_devicetable_ack_trig(const mlme_device_descriptor_t *device_desc, struct protocol_interface_info_entry *cur); + int8_t mac_helper_mac_mlme_max_retry_set(int8_t interface_id, uint8_t mac_retry_set); int8_t mac_helper_mac_device_description_pan_id_update(int8_t interface_id, uint16_t pan_id); diff --git a/source/6LoWPAN/Thread/thread_bootstrap.c b/source/6LoWPAN/Thread/thread_bootstrap.c index 07e231c8643..1d0537d3438 100644 --- a/source/6LoWPAN/Thread/thread_bootstrap.c +++ b/source/6LoWPAN/Thread/thread_bootstrap.c @@ -141,7 +141,7 @@ static void thread_neighbor_remove(mac_neighbor_table_entry_t *entry_ptr, void * thread_reset_neighbour_info(cur, entry_ptr); //Removes ETX neighbor - etx_neighbor_remove(cur->id, entry_ptr->index); + etx_neighbor_remove(cur->id, entry_ptr->index, entry_ptr->mac64); //Remove MLE frame counter info mle_service_frame_counter_entry_delete(cur->id, entry_ptr->index); } diff --git a/source/6LoWPAN/Thread/thread_nvm_store.c b/source/6LoWPAN/Thread/thread_nvm_store.c index 683d2f07cbb..876639933c5 100644 --- a/source/6LoWPAN/Thread/thread_nvm_store.c +++ b/source/6LoWPAN/Thread/thread_nvm_store.c @@ -34,7 +34,7 @@ #include "nsconfig.h" #include -#include +#include "Service_Libs/utils/ns_file.h" #include "Core/include/ns_address_internal.h" #include "ns_file_system.h" #include "thread_config.h" @@ -44,16 +44,13 @@ #define TRACE_GROUP "tnvm" const char *FAST_DATA_FILE = "f_d"; -#define FAST_DATA_VERSION 1 #define LINK_INFO_WRITE_DELAY 2 #define LINK_INFO_SHORT_ADDR_NOT_SET 0xffff #define LINK_INFO_WRITE_DONE 0xffff const char *LINK_INFO_FILE = "l_i"; -#define LINK_INFO_DATA_VERSION 1 const char *LEADER_INFO_FILE = "ld_i"; -#define LEADER_INFO_DATA_VERSION 1 typedef struct { uint8_t mac[8]; @@ -67,18 +64,15 @@ typedef struct { } thread_nvm_store_link_info_t; const char *THREAD_NVM_ACTIVE_CONF_FILE = "a_c"; -#define ACTIVE_CONF_DATA_VERSION 1 const char *DEVICE_CONF_FILE = "s_d"; -#define DEVICE_CONF_VERSION 1 const char *THREAD_NVM_PENDING_CONF_FILE = "p_c"; -#define PENDING_CONF_DATA_VERSION 1 static const char *thread_nvm_store_get_root_path(void); static int root_path_valid(void); -static int thread_nvm_store_read(const char *file_name, void *data, uint32_t data_size, uint32_t *version); -static int thread_nvm_store_write(const char *file_name, void *data, uint32_t data_size, uint32_t version); +static int thread_nvm_store_read(const char *file_name, void *data, uint32_t data_size); +static int thread_nvm_store_write(const char *file_name, void *data, uint32_t data_size); static void thread_nvm_store_create_path(char *fast_data_path, const char *file_name); static int thread_nvm_store_fast_data_save(thread_nvm_fast_data_t *fast_data_to_set); static int thread_nvm_store_all_counters_store(uint32_t mac_frame_counter, uint32_t mle_frame_counter, uint32_t seq_counter); @@ -131,13 +125,12 @@ int thread_nvm_store_mleid_rloc_map_write(thread_nvm_mleid_rloc_map *mleid_rloc_ } thread_nvm_store_create_path(lc_data_path, LEADER_INFO_FILE); tr_debug("writing to store rloc mapping info"); - return thread_nvm_store_write(lc_data_path, mleid_rloc_map, sizeof(thread_nvm_mleid_rloc_map), LEADER_INFO_DATA_VERSION); + return thread_nvm_store_write(lc_data_path, mleid_rloc_map, sizeof(thread_nvm_mleid_rloc_map)); } int thread_nvm_store_mleid_rloc_map_read(thread_nvm_mleid_rloc_map *mleid_rloc_map) { char lc_data_path[LEADER_INFO_STRING_LEN]; - uint32_t version; if (NULL == mleid_rloc_map) { return THREAD_NVM_FILE_PARAMETER_INVALID; } @@ -146,7 +139,7 @@ int thread_nvm_store_mleid_rloc_map_read(thread_nvm_mleid_rloc_map *mleid_rloc_m } thread_nvm_store_create_path(lc_data_path, LEADER_INFO_FILE); - int ret = thread_nvm_store_read(lc_data_path, mleid_rloc_map, sizeof(thread_nvm_mleid_rloc_map), &version); + int ret = thread_nvm_store_read(lc_data_path, mleid_rloc_map, sizeof(thread_nvm_mleid_rloc_map)); if (THREAD_NVM_FILE_SUCCESS != ret) { tr_info("Leader data map read failed"); @@ -154,12 +147,6 @@ int thread_nvm_store_mleid_rloc_map_read(thread_nvm_mleid_rloc_map *mleid_rloc_m return ret; } - if (LEADER_INFO_DATA_VERSION != version) { - tr_info("Leader data map version mismatch %"PRIu32, version); - thread_nvm_store_mleid_rloc_map_remove(); - return THREAD_NVM_FILE_VERSION_WRONG; - } - return ret; } @@ -191,7 +178,7 @@ int thread_nvm_store_device_configuration_write(uint8_t *mac_ptr, uint8_t *mleid memcpy(d_c.mle_id, mleid_ptr, sizeof(d_c.mle_id)); char device_conf_path[DEVICE_CONF_STRING_LEN]; thread_nvm_store_create_path(device_conf_path, DEVICE_CONF_FILE); - return thread_nvm_store_write(device_conf_path, &d_c, sizeof(thread_nvm_device_conf_t), DEVICE_CONF_VERSION); + return thread_nvm_store_write(device_conf_path, &d_c, sizeof(thread_nvm_device_conf_t)); } int thread_nvm_store_device_configuration_read(uint8_t *mac_ptr, uint8_t *mleid_ptr) @@ -202,18 +189,12 @@ int thread_nvm_store_device_configuration_read(uint8_t *mac_ptr, uint8_t *mleid_ } char device_conf_path[DEVICE_CONF_STRING_LEN]; thread_nvm_store_create_path(device_conf_path, DEVICE_CONF_FILE); - uint32_t version; thread_nvm_device_conf_t d_c; - ret = thread_nvm_store_read(device_conf_path, &d_c, sizeof(thread_nvm_device_conf_t), &version); + ret = thread_nvm_store_read(device_conf_path, &d_c, sizeof(thread_nvm_device_conf_t)); if (THREAD_NVM_FILE_SUCCESS == ret) { - if (THREAD_NVM_FILE_SUCCESS == ret && DEVICE_CONF_VERSION != version) { - tr_info("fast data version mismatch %"PRIu32, version); - ret = THREAD_NVM_FILE_VERSION_WRONG; - } else { - memcpy(mac_ptr, d_c.mac, sizeof(d_c.mac)); - memcpy(mleid_ptr, d_c.mle_id, sizeof(d_c.mle_id)); - } + memcpy(mac_ptr, d_c.mac, sizeof(d_c.mac)); + memcpy(mleid_ptr, d_c.mle_id, sizeof(d_c.mle_id)); } return ret; } @@ -228,13 +209,12 @@ int thread_nvm_store_pending_configuration_write(void *data, uint16_t size) return THREAD_NVM_FILE_ROOT_PATH_INVALID; } thread_nvm_store_create_path(pc_data_path, THREAD_NVM_PENDING_CONF_FILE); - return thread_nvm_store_write(pc_data_path, data, size, PENDING_CONF_DATA_VERSION); + return thread_nvm_store_write(pc_data_path, data, size); } int thread_nvm_store_pending_configuration_read(void *data, uint16_t size) { char pc_data_path[PENDING_CONF_STRING_LEN]; - uint32_t version; if (NULL == data) { return THREAD_NVM_FILE_PARAMETER_INVALID; } @@ -243,11 +223,7 @@ int thread_nvm_store_pending_configuration_read(void *data, uint16_t size) } thread_nvm_store_create_path(pc_data_path, THREAD_NVM_PENDING_CONF_FILE); - int ret = thread_nvm_store_read(pc_data_path, data, size, &version); - if (THREAD_NVM_FILE_SUCCESS == ret && PENDING_CONF_DATA_VERSION != version) { - tr_info("Pending configuration version mismatch %"PRIu32, version); - return THREAD_NVM_FILE_VERSION_WRONG; - } + int ret = thread_nvm_store_read(pc_data_path, data, size); return ret; } @@ -262,13 +238,12 @@ int thread_nvm_store_active_configuration_write(void *data, uint16_t data_size) } thread_nvm_store_create_path(ac_data_path, THREAD_NVM_ACTIVE_CONF_FILE); - return thread_nvm_store_write(ac_data_path, data, data_size, ACTIVE_CONF_DATA_VERSION); + return thread_nvm_store_write(ac_data_path, data, data_size); } int thread_nvm_store_active_configuration_read(void *data, uint16_t data_size) { char ac_data_path[ACTIVE_CONF_STRING_LEN]; - uint32_t version; if (NULL == data) { return THREAD_NVM_FILE_PARAMETER_INVALID; } @@ -277,11 +252,7 @@ int thread_nvm_store_active_configuration_read(void *data, uint16_t data_size) } thread_nvm_store_create_path(ac_data_path, THREAD_NVM_ACTIVE_CONF_FILE); - int ret = thread_nvm_store_read(ac_data_path, data, data_size, &version); - if (THREAD_NVM_FILE_SUCCESS == ret && ACTIVE_CONF_DATA_VERSION != version) { - tr_info("active configuration version mismatch %"PRIu32, version); - return THREAD_NVM_FILE_VERSION_WRONG; - } + int ret = thread_nvm_store_read(ac_data_path, data, data_size); return ret; } @@ -399,12 +370,7 @@ int thread_nvm_store_fast_data_read(thread_nvm_fast_data_t *fast_data) if (root_path_valid()) { char fast_data_path[FAST_DATA_STRING_LEN]; thread_nvm_store_create_path(fast_data_path, FAST_DATA_FILE); - uint32_t version; - ret = thread_nvm_store_read(fast_data_path, fast_data, sizeof(thread_nvm_fast_data_t), &version); - if (THREAD_NVM_FILE_SUCCESS == ret && FAST_DATA_VERSION != version) { - tr_info("fast data version mismatch %"PRIu32, version); - return THREAD_NVM_FILE_VERSION_WRONG; - } + ret = thread_nvm_store_read(fast_data_path, fast_data, sizeof(thread_nvm_fast_data_t)); } else { fast_data->mac_frame_counter = cached_fast_data.mac_frame_counter; fast_data->mle_frame_counter = cached_fast_data.mle_frame_counter; @@ -417,26 +383,19 @@ static int thread_nvm_store_fast_data_save(thread_nvm_fast_data_t *fast_data_to_ { char fast_data_path[FAST_DATA_STRING_LEN]; thread_nvm_store_create_path(fast_data_path, FAST_DATA_FILE); - return thread_nvm_store_write(fast_data_path, fast_data_to_set, sizeof(thread_nvm_fast_data_t), FAST_DATA_VERSION); + return thread_nvm_store_write(fast_data_path, fast_data_to_set, sizeof(thread_nvm_fast_data_t)); } -static int thread_nvm_store_write(const char *file_name, void *data, uint32_t data_size, uint32_t version) +static int thread_nvm_store_write(const char *file_name, void *data, uint32_t data_size) { - FILE *fp = fopen(file_name, "w"); + NS_FILE *fp = ns_fopen(file_name, "w"); if (fp == NULL) { tr_error("NVM open error: %s", file_name); return THREAD_NVM_FILE_CANNOT_OPEN; } - size_t n_bytes = fwrite(&version, 1, sizeof(uint32_t), fp); - if (n_bytes != sizeof(uint32_t)) { - tr_warning("NVM version write error"); - fclose(fp); - return THREAD_NVM_FILE_WRITE_ERROR; - } - - n_bytes = fwrite(data, 1, data_size, fp); - fclose(fp); + size_t n_bytes = ns_fwrite(fp, data, data_size); + ns_fclose(fp); if (n_bytes != data_size) { tr_error("NVM write error %s", file_name); return THREAD_NVM_FILE_WRITE_ERROR; @@ -446,23 +405,16 @@ static int thread_nvm_store_write(const char *file_name, void *data, uint32_t da } // returns 0 when ok -static int thread_nvm_store_read(const char *file_name, void *data, uint32_t data_size, uint32_t *version) +static int thread_nvm_store_read(const char *file_name, void *data, uint32_t data_size) { - FILE *fp = fopen(file_name, "r"); + NS_FILE *fp = ns_fopen(file_name, "r"); if (fp == NULL) { tr_warning("File not found: %s", file_name); return THREAD_NVM_FILE_CANNOT_OPEN; } - size_t n_bytes = fread(version, 1, sizeof(uint32_t), fp); - if (n_bytes != sizeof(uint32_t)) { - tr_warning("NVM version read error %s", file_name); - fclose(fp); - return THREAD_NVM_FILE_READ_ERROR; - } - - n_bytes = fread(data, 1, data_size, fp); - fclose(fp); + size_t n_bytes = ns_fread(fp, data, data_size); + ns_fclose(fp); if (n_bytes != data_size) { tr_error("NVM read error %s", file_name); return THREAD_NVM_FILE_READ_ERROR; @@ -488,8 +440,7 @@ int thread_nvm_store_link_info_read(void) strcpy(link_info_path, thread_nvm_store_get_root_path()); strcat(link_info_path, LINK_INFO_FILE); - uint32_t version = 0; - status = thread_nvm_store_read(link_info_path, &nvm_link_info_tmp, sizeof(nvm_link_info_t), &version); + status = thread_nvm_store_read(link_info_path, &nvm_link_info_tmp, sizeof(nvm_link_info_t)); if (status != THREAD_NVM_FILE_SUCCESS) { if (!memcmp(cached_link_info.nvm_link_info.mac, ADDR_UNSPECIFIED, 8) && @@ -499,9 +450,6 @@ int thread_nvm_store_link_info_read(void) return THREAD_NVM_FILE_READ_ERROR; } return status; - } else if (ACTIVE_CONF_DATA_VERSION != version) { - tr_info("link info version mismatch %"PRIu32, version); - return THREAD_NVM_FILE_VERSION_WRONG; } memcpy(cached_link_info.nvm_link_info.mac, nvm_link_info_tmp.mac, 8); cached_link_info.nvm_link_info.short_addr = nvm_link_info_tmp.short_addr; @@ -597,7 +545,7 @@ static void thread_nvm_store_link_info_delayed_write(uint32_t seconds) strcpy(link_info_path, thread_nvm_store_get_root_path()); strcat(link_info_path, LINK_INFO_FILE); tr_info("link info write parent mac: %s parent short addr: %"PRIu16, trace_array(cached_link_info.nvm_link_info.mac, 8), cached_link_info.nvm_link_info.short_addr); - thread_nvm_store_write(link_info_path, &cached_link_info.nvm_link_info, sizeof(nvm_link_info_t), LINK_INFO_DATA_VERSION); + thread_nvm_store_write(link_info_path, &cached_link_info.nvm_link_info, sizeof(nvm_link_info_t)); } void thread_nvm_store_seconds_timer(uint32_t seconds) diff --git a/source/6LoWPAN/adaptation_interface.c b/source/6LoWPAN/adaptation_interface.c index 99636719d9d..87d66577359 100644 --- a/source/6LoWPAN/adaptation_interface.c +++ b/source/6LoWPAN/adaptation_interface.c @@ -155,7 +155,7 @@ static void lowpan_adaptation_etx_update_cb(protocol_interface_info_entry_t *cur // Gets table entry mac_neighbor_table_entry_t *neigh_table_ptr = mac_neighbor_table_address_discover(mac_neighbor_info(cur), buf->dst_sa.address + PAN_ID_LEN, buf->dst_sa.addr_type); if (neigh_table_ptr) { - etx_transm_attempts_update(cur->id, 1 + confirm->tx_retries, success, neigh_table_ptr->index); + etx_transm_attempts_update(cur->id, 1 + confirm->tx_retries, success, neigh_table_ptr->index, neigh_table_ptr->mac64); // Updates ETX statistics etx_storage_t *etx_entry = etx_storage_entry_get(cur->id, neigh_table_ptr->index); if (etx_entry) { diff --git a/source/6LoWPAN/ws/ws_bbr_api.c b/source/6LoWPAN/ws/ws_bbr_api.c index d180102e4a9..f841be8144a 100644 --- a/source/6LoWPAN/ws/ws_bbr_api.c +++ b/source/6LoWPAN/ws/ws_bbr_api.c @@ -20,6 +20,7 @@ #include "ns_types.h" #include "ns_trace.h" #include "net_interface.h" +#include "socket_api.h" #include "eventOS_event.h" #include "NWK_INTERFACE/Include/protocol.h" #include "6LoWPAN/Bootstraps/protocol_6lowpan.h" @@ -28,6 +29,7 @@ #include "6LoWPAN/ws/ws_common.h" #include "6LoWPAN/ws/ws_bootstrap.h" #include "6LoWPAN/ws/ws_cfg_settings.h" +#include "6LoWPAN/ws/ws_pae_key_storage.h" #include "RPL/rpl_control.h" #include "RPL/rpl_data.h" #include "Common_Protocols/icmpv6.h" @@ -52,7 +54,6 @@ static uint8_t current_instance_id = RPL_INSTANCE_ID; #define WS_ULA_LIFETIME 24*3600 #define WS_ROUTE_LIFETIME WS_ULA_LIFETIME -#define WS_DHCP_ADDRESS_LIFETIME 2*3600 #define BBR_CHECK_INTERVAL 60 #define BBR_BACKUP_ULA_DELAY 300 @@ -68,7 +69,7 @@ static uint8_t static_dodag_prefix[8] = {0xfd, 0x00, 0x72, 0x83, 0x7e}; static uint8_t static_dodag_id_prefix[8] = {0xfd, 0x00, 0x61, 0x72, 0x6d}; static uint8_t current_dodag_id[16] = {0}; static uint8_t current_local_prefix[8] = {0}; -static uint8_t current_global_prefix[8] = {0}; +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. @@ -94,7 +95,16 @@ static void ws_bbr_rpl_version_timer_start(protocol_interface_info_entry_t *cur, //stable version for RPL so slow timer update is ok cur->ws_info->rpl_version_timer = RPL_VERSION_LIFETIME; } else { - cur->ws_info->rpl_version_timer = RPL_VERSION_LIFETIME_RESTART; + if (cur->ws_info->cfg->gen.network_size <= NETWORK_SIZE_SMALL) { + // handles also NETWORK_SIZE_CERTIFICATE + cur->ws_info->rpl_version_timer = RPL_VERSION_LIFETIME_RESTART_SMALL; + } else if (cur->ws_info->cfg->gen.network_size <= NETWORK_SIZE_MEDIUM) { + cur->ws_info->rpl_version_timer = RPL_VERSION_LIFETIME_RESTART_MEDIUM; + } else if (cur->ws_info->cfg->gen.network_size <= NETWORK_SIZE_LARGE) { + cur->ws_info->rpl_version_timer = RPL_VERSION_LIFETIME_RESTART_LARGE; + } else { + cur->ws_info->rpl_version_timer = RPL_VERSION_LIFETIME_RESTART_EXTRA_LARGE; + } } } @@ -137,6 +147,15 @@ void ws_bbr_rpl_config(protocol_interface_info_entry_t *cur, uint8_t imin, uint8 } } +void ws_bbr_dhcp_address_lifetime_set(protocol_interface_info_entry_t *cur, uint32_t dhcp_address_lifetime) +{ + if (!cur) { + return; + } + // Change the setting if the border router is active + DHCPv6_server_service_set_address_validlifetime(cur->id, current_global_prefix, dhcp_address_lifetime); +} + static void ws_bbr_rpl_root_start(protocol_interface_info_entry_t *cur, uint8_t *dodag_id) { tr_info("RPL root start"); @@ -223,7 +242,10 @@ static if_address_entry_t *ws_bbr_slaac_generate(protocol_interface_info_entry_t static void ws_bbr_slaac_remove(protocol_interface_info_entry_t *cur, uint8_t *ula_prefix) { - icmpv6_slaac_prefix_update(cur, ula_prefix, 64, 0, 0); + if (cur) { + icmpv6_slaac_prefix_update(cur, ula_prefix, 64, 0, 0); + } + addr_policy_table_delete_entry(ula_prefix, 64); } @@ -328,7 +350,7 @@ static bool wisun_dhcp_address_add_cb(int8_t interfaceId, dhcp_address_cache_upd return true; } -static void ws_bbr_dhcp_server_start(protocol_interface_info_entry_t *cur, uint8_t *global_id) +static void ws_bbr_dhcp_server_start(protocol_interface_info_entry_t *cur, uint8_t *global_id, uint32_t dhcp_address_lifetime) { uint8_t ll[16]; memcpy(ll, ADDR_LINK_LOCAL_PREFIX, 8); @@ -344,7 +366,7 @@ static void ws_bbr_dhcp_server_start(protocol_interface_info_entry_t *cur, uint8 DHCPv6_server_service_callback_set(cur->id, global_id, NULL, wisun_dhcp_address_add_cb); //Enable SLAAC mode to border router DHCPv6_server_service_set_address_autonous_flag(cur->id, global_id, true, false); - DHCPv6_server_service_set_address_validlifetime(cur->id, global_id, WS_DHCP_ADDRESS_LIFETIME); + DHCPv6_server_service_set_address_validlifetime(cur->id, global_id, dhcp_address_lifetime); //SEt max value for not limiting address allocation DHCPv6_server_service_set_max_clients_accepts_count(cur->id, global_id, MAX_SUPPORTED_ADDRESS_LIST_SIZE); @@ -352,6 +374,9 @@ static void ws_bbr_dhcp_server_start(protocol_interface_info_entry_t *cur, uint8 } static void ws_bbr_dhcp_server_stop(protocol_interface_info_entry_t *cur, uint8_t *global_id) { + if (!cur) { + return; + } uint8_t temp_address[16]; memcpy(temp_address, global_id, 8); memset(temp_address + 8, 0, 8); @@ -359,7 +384,6 @@ static void ws_bbr_dhcp_server_stop(protocol_interface_info_entry_t *cur, uint8_ DHCPv6_server_service_delete(cur->id, global_id, false); //Delete Client dhcp_client_global_address_delete(cur->id, NULL, temp_address); - } static void ws_bbr_routing_stop(protocol_interface_info_entry_t *cur) @@ -506,7 +530,7 @@ static void ws_bbr_rpl_status_check(protocol_interface_info_entry_t *cur) return; } } - ws_bbr_dhcp_server_start(cur, global_prefix); + ws_bbr_dhcp_server_start(cur, global_prefix, cur->ws_info->cfg->bbr.dhcp_address_lifetime); rpl_control_update_dodag_prefix(protocol_6lowpan_rpl_root_dodag, global_prefix, 64, 0, 0, 0, false); // no check for failure should have @@ -623,6 +647,11 @@ uint16_t test_pan_size_override = 0xffff; uint16_t ws_bbr_pan_size(protocol_interface_info_entry_t *cur) { uint16_t result = 0; + + if (!cur || !cur->rpl_domain) { + return 0; + } + if (test_pan_size_override != 0xffff) { return test_pan_size_override; } @@ -701,7 +730,6 @@ void ws_bbr_stop(int8_t interface_id) protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(interface_id); ws_bbr_routing_stop(cur); - backbone_interface_id = -1; current_instance_id++; @@ -728,6 +756,86 @@ int ws_bbr_configure(int8_t interface_id, uint16_t options) return -1; #endif } +int ws_bbr_info_get(int8_t interface_id, bbr_information_t *info_ptr) +{ +#ifdef HAVE_WS_BORDER_ROUTER + + protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(interface_id); + rpl_dodag_info_t dodag_info; + + if (!info_ptr) { + return -1; + } + if (!cur || !protocol_6lowpan_rpl_root_dodag) { + tr_warn("bbr not started"); + return -1; + } + struct rpl_instance *instance = rpl_control_lookup_instance(protocol_6lowpan_rpl_domain, current_instance_id, current_dodag_id); + if (!instance) { + tr_warn("bbr instance not found"); + return -2; + } + // Zero the structure + memset(info_ptr, 0, sizeof(bbr_information_t)); + + rpl_control_read_dodag_info(instance, &dodag_info); + + memcpy(info_ptr->dodag_id, current_dodag_id, 16); + memcpy(info_ptr->prefix, current_global_prefix, 8); + + // Get the Wi-SUN interface generated address that is used in the RF interface. + const uint8_t *wisun_if_addr = addr_select_with_prefix(cur, current_global_prefix, 64, SOCKET_IPV6_PREFER_SRC_PUBLIC); + + if (wisun_if_addr) { + memcpy(info_ptr->IID, wisun_if_addr + 8, 8); + } + + info_ptr->devices_in_network = ws_bbr_pan_size(cur); + info_ptr->instance_id = current_instance_id; + info_ptr->version = dodag_info.version_num; + info_ptr->timestamp = protocol_core_monotonic_time; // TODO switch to second timer + // consider DTSN included It can also be added for getting device information + // Consider own device API to get DTSN, DHCP lifetime values + return 0; + +#else + (void) interface_id; + (void) info_ptr; + + return -1; +#endif +} + +int ws_bbr_routing_table_get(int8_t interface_id, bbr_route_info_t *table_ptr, uint16_t table_len) +{ +#ifdef HAVE_WS_BORDER_ROUTER + protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(interface_id); + int length; + if (!cur || !protocol_6lowpan_rpl_root_dodag) { + return -1; + } + + struct rpl_instance *instance = rpl_control_lookup_instance(protocol_6lowpan_rpl_domain, current_instance_id, current_dodag_id); + if (!instance) { + tr_warn("bbr instance not found"); + return -2; + } + memset(table_ptr, 0, table_len); + + /* RPL structure must match the external structure so we dont need to make conversion. + * + */ + length = rpl_control_route_table_get(instance, current_global_prefix, (rpl_route_info_t *)table_ptr, table_len); + + return length; +#else + (void) interface_id; + (void) table_ptr; + (void) table_len; + + return -1; +#endif +} int ws_bbr_node_keys_remove(int8_t interface_id, uint8_t *eui64) { @@ -782,8 +890,8 @@ int ws_bbr_rpl_parameters_set(int8_t interface_id, uint8_t dio_interval_min, uin #ifdef HAVE_WS_BORDER_ROUTER protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(interface_id); - ws_rpl_cfg_t cfg; - if (ws_cfg_rpl_get(&cfg, NULL) < 0) { + ws_bbr_cfg_t cfg; + if (ws_cfg_bbr_get(&cfg, NULL) < 0) { return -1; } @@ -797,7 +905,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_rpl_set(cur, NULL, &cfg, 0) < 0) { + if (ws_cfg_bbr_set(cur, NULL, &cfg, 0) < 0) { return -2; } @@ -818,8 +926,8 @@ int ws_bbr_rpl_parameters_get(int8_t interface_id, uint8_t *dio_interval_min, ui return -1; } - ws_rpl_cfg_t cfg; - if (ws_cfg_rpl_get(&cfg, NULL) < 0) { + ws_bbr_cfg_t cfg; + if (ws_cfg_bbr_get(&cfg, NULL) < 0) { return -2; } @@ -840,8 +948,8 @@ int ws_bbr_rpl_parameters_validate(int8_t interface_id, uint8_t dio_interval_min { (void) interface_id; #ifdef HAVE_WS_BORDER_ROUTER - ws_rpl_cfg_t cfg; - if (ws_cfg_rpl_get(&cfg, NULL) < 0) { + ws_bbr_cfg_t cfg; + if (ws_cfg_bbr_get(&cfg, NULL) < 0) { return -2; } @@ -855,7 +963,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_rpl_validate(NULL, &cfg) < 0) { + if (ws_cfg_bbr_validate(NULL, &cfg) < 0) { return -3; } @@ -935,3 +1043,29 @@ int ws_bbr_pan_configuration_validate(int8_t interface_id, uint16_t pan_id) return -1; #endif } + +int ws_bbr_key_storage_memory_set(int8_t interface_id, uint8_t key_storages_number, const uint16_t *key_storage_size, void **key_storages) +{ + (void) interface_id; +#ifdef HAVE_WS_BORDER_ROUTER + return ws_pae_key_storage_memory_set(key_storages_number, key_storage_size, key_storages); +#else + (void) key_storages_number; + (void) key_storage_size; + (void) key_storages; + return -1; +#endif +} + +int ws_bbr_key_storage_settings_set(int8_t interface_id, uint8_t alloc_max_number, uint16_t alloc_size, uint16_t storing_interval) +{ + (void) interface_id; +#ifdef HAVE_WS_BORDER_ROUTER + return ws_pae_key_storage_settings_set(alloc_max_number, alloc_size, storing_interval); +#else + (void) alloc_max_number; + (void) alloc_size; + (void) storing_interval; + return -1; +#endif +} diff --git a/source/6LoWPAN/ws/ws_bbr_api_internal.h b/source/6LoWPAN/ws/ws_bbr_api_internal.h index ee465916afd..249790feac3 100644 --- a/source/6LoWPAN/ws/ws_bbr_api_internal.h +++ b/source/6LoWPAN/ws/ws_bbr_api_internal.h @@ -31,6 +31,8 @@ uint16_t ws_bbr_pan_size(protocol_interface_info_entry_t *cur); void ws_bbr_rpl_config(protocol_interface_info_entry_t *cur, uint8_t imin, uint8_t doubling, uint8_t redundancy, uint16_t dag_max_rank_increase, uint16_t min_hop_rank_increase); +void ws_bbr_dhcp_address_lifetime_set(protocol_interface_info_entry_t *cur, uint32_t dhcp_address_lifetime); + bool ws_bbr_ready_to_start(protocol_interface_info_entry_t *cur); @@ -40,6 +42,7 @@ bool ws_bbr_ready_to_start(protocol_interface_info_entry_t *cur); #define ws_bbr_pan_version_increase(cur) #define ws_bbr_pan_size(cur) 0 #define ws_bbr_rpl_config( cur, imin, doubling, redundancy, dag_max_rank_increase, min_hop_rank_increase) +#define ws_bbr_dhcp_address_lifetime_set(cur, dhcp_address_lifetime) #define ws_bbr_ready_to_start(cur) true #endif //HAVE_WS_BORDER_ROUTER diff --git a/source/6LoWPAN/ws/ws_bootstrap.c b/source/6LoWPAN/ws/ws_bootstrap.c index 6a6079acfa8..0d02498a5dc 100644 --- a/source/6LoWPAN/ws/ws_bootstrap.c +++ b/source/6LoWPAN/ws/ws_bootstrap.c @@ -95,14 +95,16 @@ static void ws_bootstrap_nw_key_clear(protocol_interface_info_entry_t *cur, uint static void ws_bootstrap_nw_key_index_set(protocol_interface_info_entry_t *cur, uint8_t index); static void ws_bootstrap_nw_frame_counter_set(protocol_interface_info_entry_t *cur, uint32_t counter, uint8_t slot); static void ws_bootstrap_nw_frame_counter_read(protocol_interface_info_entry_t *cur, uint32_t *counter, uint8_t slot); +static void ws_bootstrap_nw_info_updated(protocol_interface_info_entry_t *interface_ptr, uint16_t pan_id, char *network_name); static void ws_bootstrap_authentication_completed(protocol_interface_info_entry_t *cur, auth_result_e result, uint8_t *target_eui_64); +static const uint8_t *ws_bootstrap_authentication_next_target(protocol_interface_info_entry_t *cur, const uint8_t *previous_eui_64, uint16_t *pan_id); static void ws_bootstrap_pan_version_increment(protocol_interface_info_entry_t *cur); static ws_nud_table_entry_t *ws_nud_entry_discover(protocol_interface_info_entry_t *cur, void *neighbor); static void ws_nud_entry_remove(protocol_interface_info_entry_t *cur, mac_neighbor_table_entry_t *entry_ptr); static bool ws_neighbor_entry_nud_notify(mac_neighbor_table_entry_t *entry_ptr, void *user_data); static void ws_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_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); @@ -146,14 +148,68 @@ mac_neighbor_table_entry_t *ws_bootstrap_mac_neighbor_add(struct protocol_interf static void ws_bootstrap_neighbor_delete(struct protocol_interface_info_entry *interface, mac_neighbor_table_entry_t *entry_ptr) { mac_helper_devicetable_remove(interface->mac_api, entry_ptr->index, entry_ptr->mac64); - etx_neighbor_remove(interface->id, entry_ptr->index); + etx_neighbor_remove(interface->id, entry_ptr->index, entry_ptr->mac64); ws_neighbor_class_entry_remove(&interface->ws_info->neighbor_storage, entry_ptr->index); } +static void ws_bootstap_eapol_neigh_entry_allocate(struct protocol_interface_info_entry *interface) +{ + uint8_t mac_64[8]; + memset(mac_64, 0, sizeof(mac_64)); + + mac_neighbor_table_entry_t *mac_entry = ws_bootstrap_mac_neighbor_add(interface, mac_64); + + if (!mac_entry) { + return; + } + mac_entry->lifetime = 0xffffffff; + mac_entry->link_lifetime = 0xffffffff; + ws_neighbor_class_entry_t *ws_neigh = ws_neighbor_class_entry_get(&interface->ws_info->neighbor_storage, mac_entry->index); + if (!ws_neigh) { + return; + } + interface->ws_info->eapol_tx_index = mac_entry->index; +} + +void ws_bootstrap_eapol_rx_temporary_set(struct protocol_interface_info_entry *interface, const uint8_t *src64) +{ + mlme_device_descriptor_t device_desc; + + mac_helper_device_description_write(interface, &device_desc, src64, 0xffff, 0, false); + mac_helper_devicetable_ack_trig(&device_desc, interface); +} + +ws_neighbor_class_entry_t *ws_bootstrap_eapol_tx_temporary_set(struct protocol_interface_info_entry *interface, const uint8_t *src64) +{ + mlme_device_descriptor_t device_desc; + mac_neighbor_table_entry_t *mac_entry = mac_neighbor_table_attribute_discover(mac_neighbor_info(interface), interface->ws_info->eapol_tx_index); + if (!mac_entry) { + return NULL; + } + + memcpy(mac_entry->mac64, src64, 8); + mac_helper_device_description_write(interface, &device_desc, src64, 0xffff, 0, false); + mac_helper_devicetable_direct_set(interface->mac_api, &device_desc, interface->ws_info->eapol_tx_index); + return ws_neighbor_class_entry_get(&interface->ws_info->neighbor_storage, mac_entry->index); +} + +void ws_bootstrap_eapol_tx_temporary_clear(struct protocol_interface_info_entry *interface) +{ + mac_neighbor_table_entry_t *mac_entry = mac_neighbor_table_attribute_discover(mac_neighbor_info(interface), interface->ws_info->eapol_tx_index); + if (!mac_entry) { + return; + } + + memset(mac_entry->mac64, 0xff, 8); + mac_helper_devicetable_remove(interface->mac_api, interface->ws_info->eapol_tx_index, NULL); +} + static void ws_bootstrap_neighbor_list_clean(struct protocol_interface_info_entry *interface) { mac_neighbor_table_neighbor_list_clean(mac_neighbor_info(interface)); + //Allocate EAPOL TX temporary neigh entry + ws_bootstap_eapol_neigh_entry_allocate(interface); } static void ws_address_reregister_trig(struct protocol_interface_info_entry *interface) @@ -486,8 +542,8 @@ static uint8_t ws_generate_exluded_channel_list_from_active_channels(ws_excluded static void ws_fhss_configure_channel_masks(protocol_interface_info_entry_t *cur, fhss_ws_configuration_t *fhss_configuration) { - ws_generate_channel_list(fhss_configuration->channel_mask, cur->ws_info->hopping_schdule.number_of_channels, cur->ws_info->hopping_schdule.regulatory_domain); - ws_generate_channel_list(fhss_configuration->unicast_channel_mask, cur->ws_info->hopping_schdule.number_of_channels, cur->ws_info->hopping_schdule.regulatory_domain); + 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); + 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); // 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]; @@ -510,6 +566,7 @@ static int8_t ws_fhss_initialize(protocol_interface_info_entry_t *cur) fhss_configuration.ws_bc_channel_function = (fhss_ws_channel_functions)cur->ws_info->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; + fhss_configuration.config_parameters.number_of_channel_retries = WS_NUMBER_OF_CHANNEL_RETRIES; fhss_api = ns_fhss_ws_create(&fhss_configuration, cur->ws_info->fhss_timer_ptr); if (!fhss_api) { @@ -1069,7 +1126,7 @@ static parent_info_t *ws_bootstrap_candidate_parent_allocate(protocol_interface_ return entry; } -static void ws_bootstrap_candidate_parent_free(protocol_interface_info_entry_t *cur, uint8_t *addr) +static void ws_bootstrap_candidate_parent_free(protocol_interface_info_entry_t *cur, const uint8_t *addr) { ns_list_foreach_safe(parent_info_t, entry, &cur->ws_info->parent_list_reserved) { if (memcmp(entry->addr, addr, 8) == 0) { @@ -1286,14 +1343,15 @@ static void ws_bootstrap_pan_advertisement_solicit_analyse(struct protocol_inter * 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 faster the parent if we hear solicit from someone else */ - if (ws_bootstrap_state_discovery(cur) && - cur->bootsrap_state_machine_cnt > cur->ws_info->trickle_params_pan_discovery.Imin + 50) { - cur->bootsrap_state_machine_cnt = cur->ws_info->trickle_params_pan_discovery.Imin + randLIB_get_8bit() % 50; + if (ws_bootstrap_state_discovery(cur) && cur->ws_info->cfg->gen.network_size <= NETWORK_SIZE_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)); } } @@ -1347,6 +1405,7 @@ static void ws_bootstrap_pan_config_analyse(struct protocol_interface_info_entry tr_error("No broadcast schedule"); return; } + llc_neighbour_req_t neighbor_info; bool neighbour_pointer_valid; @@ -1362,7 +1421,7 @@ static void ws_bootstrap_pan_config_analyse(struct protocol_interface_info_entry } if (neighbour_pointer_valid) { - etx_lqi_dbm_update(cur->id, data->mpduLinkQuality, data->signal_dbm, neighbor_info.neighbor->index); + etx_lqi_dbm_update(cur->id, data->mpduLinkQuality, data->signal_dbm, neighbor_info.neighbor->index, neighbor_info.neighbor->mac64); //Update Neighbor Broadcast and Unicast Parameters ws_neighbor_class_neighbor_unicast_time_info_update(neighbor_info.ws_neighbor, ws_utt, data->timestamp); ws_neighbor_class_neighbor_unicast_schedule_set(neighbor_info.ws_neighbor, ws_us); @@ -1447,7 +1506,7 @@ static void ws_bootstrap_pan_config_solicit_analyse(struct protocol_interface_in llc_neighbour_req_t neighbor_info; if (ws_bootstrap_neighbor_info_request(cur, data->SrcAddr, &neighbor_info, false)) { - etx_lqi_dbm_update(cur->id, data->mpduLinkQuality, data->signal_dbm, neighbor_info.neighbor->index); + etx_lqi_dbm_update(cur->id, data->mpduLinkQuality, data->signal_dbm, neighbor_info.neighbor->index, neighbor_info.neighbor->mac64); ws_neighbor_class_neighbor_unicast_time_info_update(neighbor_info.ws_neighbor, ws_utt, data->timestamp); ws_neighbor_class_neighbor_unicast_schedule_set(neighbor_info.ws_neighbor, ws_us); } @@ -1607,6 +1666,10 @@ static void ws_bootstrap_neighbor_table_clean(struct protocol_interface_info_ent 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 (cur->index == interface->ws_info->eapol_tx_index) { + continue; + } + if (cur->link_role == PRIORITY_PARENT_NEIGHBOUR) { //This is our primary parent we cannot delete continue; @@ -1758,7 +1821,7 @@ static bool ws_neighbor_entry_nud_notify(mac_neighbor_table_entry_t *entry_ptr, return false; } - if (!rpl_control_is_dodag_parent_candidate(cur, ll_address, WS_NEIGHBOUR_MAX_CANDIDATE_PROBE)) { + if (!rpl_control_is_dodag_parent_candidate(cur, ll_address, cur->ws_info->cfg->gen.rpl_parent_candidate_max)) { //NUD Not needed for if neighbour is not parent candidate return false; } @@ -1921,7 +1984,7 @@ int ws_bootstrap_init(int8_t interface_id, net_6lowpan_mode_e bootstrap_mode) ret_val = -4; goto init_fail; } - if (ws_pae_controller_cb_register(cur, &ws_bootstrap_authentication_completed, &ws_bootstrap_nw_key_set, &ws_bootstrap_nw_key_clear, &ws_bootstrap_nw_key_index_set, &ws_bootstrap_nw_frame_counter_set, &ws_bootstrap_nw_frame_counter_read, &ws_bootstrap_pan_version_increment) < 0) { + if (ws_pae_controller_cb_register(cur, &ws_bootstrap_authentication_completed, &ws_bootstrap_authentication_next_target, &ws_bootstrap_nw_key_set, &ws_bootstrap_nw_key_clear, &ws_bootstrap_nw_key_index_set, &ws_bootstrap_nw_frame_counter_set, &ws_bootstrap_nw_frame_counter_read, &ws_bootstrap_pan_version_increment, &ws_bootstrap_nw_info_updated) < 0) { ret_val = -4; goto init_fail; } @@ -1957,6 +2020,8 @@ int ws_bootstrap_init(int8_t interface_id, net_6lowpan_mode_e bootstrap_mode) set_req.value_size = sizeof(bool); cur->mac_api->mlme_req(cur->mac_api, MLME_SET, &set_req); + mac_helper_mac_mlme_max_retry_set(cur->id, WS_MAX_FRAME_RETRIES); + // Set the default parameters for MPL cur->mpl_proactive_forwarding = true; @@ -2032,6 +2097,12 @@ int ws_bootstrap_set_rf_config(protocol_interface_info_entry_t *cur, phy_rf_chan set_request.value_pointer = &multi_csma_params; set_request.value_size = sizeof(mlme_multi_csma_ca_param_t); cur->mac_api->mlme_req(cur->mac_api, MLME_SET, &set_request); + // Start automatic CCA threshold + uint8_t start_cca_thr[4] = {cur->ws_info->hopping_schdule.number_of_channels, CCA_DEFAULT_DBM, CCA_HIGH_LIMIT, CCA_LOW_LIMIT}; + set_request.attr = macCCAThresholdStart; + set_request.value_pointer = &start_cca_thr; + set_request.value_size = sizeof(start_cca_thr); + cur->mac_api->mlme_req(cur->mac_api, MLME_SET, &set_request); return 0; } @@ -2205,8 +2276,8 @@ static void ws_bootstrap_rpl_callback(rpl_event_t event, void *handle) ws_eapol_relay_start(cur, EAPOL_RELAY_SOCKET_PORT, dodag_info.dodag_id, EAPOL_RELAY_SOCKET_PORT); // Set network information to PAE ws_pae_controller_nw_info_set(cur, cur->ws_info->network_pan_id, cur->ws_info->cfg->gen.network_name); - // Network key is valid - ws_pae_controller_nw_key_valid(cur); + // Network key is valid, indicate border router IID to controller + ws_pae_controller_nw_key_valid(cur, &dodag_info.dodag_id[8]); // After successful DAO ACK connection to border router is verified cur->ws_info->pan_timeout_timer = cur->ws_info->cfg->timing.pan_timeout; @@ -2308,19 +2379,21 @@ static void ws_rpl_prefix_callback(prefix_entry_t *prefix, void *handle, uint8_t static bool ws_rpl_candidate_soft_filtering(protocol_interface_info_entry_t *cur, struct rpl_instance *instance) { - //If bootstrap active we not need any candidate filtering - if ((cur->lowpan_info & INTERFACE_NWK_BOOTSRAP_ACTIVE) && (ws_info(cur)->cfg->gen.network_size == NETWORK_SIZE_CERTIFICATE)) { - return true; - } - //Already many candidates - if (rpl_control_candidate_list_size(cur, instance) > cur->ws_info->cfg->rpl.rpl_parent_candidate_max) { + uint16_t candidate_list_size = rpl_control_candidate_list_size(cur, instance); + if (candidate_list_size >= cur->ws_info->cfg->gen.rpl_parent_candidate_max) { return false; } + uint16_t selected_parents = rpl_control_selected_parent_count(cur, instance); + //Already enough selected candidates - if (rpl_control_selected_parent_count(cur, instance) >= cur->ws_info->cfg->rpl.rpl_selected_parent_max) { - return false; + if (selected_parents >= cur->ws_info->cfg->gen.rpl_selected_parent_max) { + candidate_list_size -= selected_parents; + if (candidate_list_size >= 2) { + //We have more candidates than selected + return false; + } } return true; @@ -2354,6 +2427,19 @@ static bool ws_rpl_new_parent_callback(uint8_t *ll_parent_address, void *handle, ws_neighbor_temp_class_t *entry = ws_llc_get_multicast_temp_entry(cur, mac64); if (!ws_rpl_candidate_soft_filtering(cur, instance)) { + + //Acept only better than own rank here + if (candidate_rank >= rpl_control_current_rank(instance)) { + //Do not accept no more siblings + return false; + } + + uint16_t candidate_list_size = rpl_control_candidate_list_size(cur, instance); + if (candidate_list_size > cur->ws_info->cfg->gen.rpl_parent_candidate_max + 1) { + //Accept only 1 better 1 time + return false; + } + if (!neigh_buffer.neighbor) { //Do not accept any new in that Place return false; @@ -2386,42 +2472,6 @@ static bool ws_rpl_new_parent_callback(uint8_t *ll_parent_address, void *handle, if (neigh_buffer.neighbor) { return true; } -#if 0 - if (!rpl_control_find_worst_neighbor(cur, instance, replacing)) { - return false; - } - - // +2 Is for PAN ID space - memcpy(mac64 + 2, replacing + 8, 8); - mac64[2] ^= 2; - - if (ws_etx_read(cur, ADDR_802_15_4_LONG, mac64) == 0xffff) { - //Not proped yet because ETX is 0xffff - return false; - } - - uint16_t etx = 0; - if (neigh_buffer.neighbor) { - etx = etx_local_etx_read(cur->id, neigh_buffer.neighbor->index); - } - - // Accept now only better one's when max candidates selected and max candidate list size is reached - if (!rpl_possible_better_candidate(cur, instance, replacing, candidate_rank, etx)) { - return false; - } - //TODO if replacing has poor ETX, put it in blacklist as "poor ETX" to prevent reselection - //Mark That We can try remove replaced link - replace_ok = true; - -neigh_create: - - - if (neigh_buffer.neighbor) { - //Use Already discovered entry - create_ok = true; - goto neigh_create_ok; - } -#endif if (!entry) { //No Multicast Entry Available @@ -2435,7 +2485,7 @@ static bool ws_rpl_new_parent_callback(uint8_t *ll_parent_address, void *handle, //Copy fhss temporary data *ws_neigh = entry->neigh_info_list; //ETX Create here - etx_lqi_dbm_update(cur->id, entry->mpduLinkQuality, entry->signal_dbm, neigh_buffer.neighbor->index); + etx_lqi_dbm_update(cur->id, entry->mpduLinkQuality, entry->signal_dbm, neigh_buffer.neighbor->index, neigh_buffer.neighbor->mac64); mac_neighbor_table_trusted_neighbor(mac_neighbor_info(cur), neigh_buffer.neighbor, true); } ws_llc_free_multicast_temp_entry(cur, entry); @@ -2562,7 +2612,7 @@ static void ws_bootstrap_start_discovery(protocol_interface_info_entry_t *cur) } // Discovery statemachine is checkked after we have sent the Solicit - uint16_t time_to_solicit = 0; + 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; } @@ -2571,7 +2621,13 @@ static void ws_bootstrap_start_discovery(protocol_interface_info_entry_t *cur) 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); - cur->bootsrap_state_machine_cnt = time_to_solicit + cur->ws_info->trickle_params_pan_discovery.Imin + randLIB_get_8bit() % 50; + 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)); } @@ -2627,6 +2683,32 @@ static void ws_bootstrap_nw_frame_counter_read(protocol_interface_info_entry_t * mac_helper_key_link_frame_counter_read(cur->id, counter, slot); } +static void ws_bootstrap_nw_info_updated(protocol_interface_info_entry_t *cur, uint16_t pan_id, char *network_name) +{ + /* For border router, the PAE controller reads pan_id and network name from storage. + * If they are set, takes them into use here. + */ + if (cur->bootsrap_mode == ARM_NWK_BOOTSRAP_MODE_6LoWPAN_BORDER_ROUTER) { + // Get pad_id and network name + ws_gen_cfg_t gen_cfg; + if (ws_cfg_gen_get(&gen_cfg, NULL) < 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 network name has not been set, set it + if (strlen(gen_cfg.network_name) == 0) { + strncpy(gen_cfg.network_name, network_name, 32); + } + + // Stores the settings + ws_cfg_gen_set(cur, NULL, &gen_cfg, 0); + } +} + static void ws_bootstrap_authentication_completed(protocol_interface_info_entry_t *cur, auth_result_e result, uint8_t *target_eui_64) { (void) target_eui_64; @@ -2658,6 +2740,24 @@ static void ws_bootstrap_authentication_completed(protocol_interface_info_entry_ } } +static const uint8_t *ws_bootstrap_authentication_next_target(protocol_interface_info_entry_t *cur, const uint8_t *previous_eui_64, uint16_t *pan_id) +{ + ws_bootstrap_candidate_parent_free(cur, previous_eui_64); + + // Gets best target + parent_info_t *parent_info = ws_bootstrap_candidate_parent_get_best(cur); + if (parent_info) { + /* On failure still continues with the new parent, and on next call, + will try to set the neighbor again */ + ws_bootstrap_neighbor_set(cur, parent_info, true); + *pan_id = parent_info->pan_id; + return parent_info->addr; + } + + // If no targets found, retries the last one + return previous_eui_64; +} + // Start configuration learning static void ws_bootstrap_start_configuration_learn(protocol_interface_info_entry_t *cur) { @@ -2731,7 +2831,7 @@ static void ws_set_asynch_channel_list(protocol_interface_info_entry_t *cur, asy 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)); } 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); + 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); } async_req->channel_list.channel_page = CHANNEL_PAGE_10; @@ -3047,6 +3147,36 @@ static void ws_bootstrap_event_handler(arm_event_s *event) } } +static 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_version = 0; // This is learned from actual configuration + + // If PAN ID changes, clear learned neighbors and activate FHSS + if (pan_id != cur->ws_info->network_pan_id) { + if (clear_list) { + ws_bootstrap_neighbor_list_clean(cur); + } + ws_bootstrap_fhss_activate(cur); + } + + llc_neighbour_req_t neighbor_info; + if (!ws_bootstrap_neighbor_info_request(cur, parent_ptr->addr, &neighbor_info, true)) { + //Remove Neighbour and set Link setup back + ns_list_remove(&cur->ws_info->parent_list_reserved, parent_ptr); + ns_list_add_to_end(&cur->ws_info->parent_list_free, parent_ptr); + return -1; + } + + ws_neighbor_class_neighbor_unicast_time_info_update(neighbor_info.ws_neighbor, &parent_ptr->ws_utt, parent_ptr->timestamp); + ws_neighbor_class_neighbor_unicast_schedule_set(neighbor_info.ws_neighbor, &parent_ptr->ws_us); + return 0; +} + /* * State machine * @@ -3067,29 +3197,21 @@ void ws_bootstrap_network_scan_process(protocol_interface_info_entry_t *cur) // randomize new channel and start MAC ws_bootstrap_fhss_activate(cur); // Next check will be after one trickle - cur->bootsrap_state_machine_cnt += cur->ws_info->trickle_params_pan_discovery.Imin + randLIB_get_8bit() % 50; + 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); - // Add EAPOL neighbour - cur->ws_info->network_pan_id = selected_parent_ptr->pan_id; - cur->ws_info->pan_information = selected_parent_ptr->pan_information; - cur->ws_info->pan_information.pan_version = 0; // This is learned from actual configuration - - ws_bootstrap_fhss_activate(cur); - llc_neighbour_req_t neighbor_info; - if (!ws_bootstrap_neighbor_info_request(cur, selected_parent_ptr->addr, &neighbor_info, true)) { - //Remove Neighbour and set Link setup back - ns_list_remove(&cur->ws_info->parent_list_reserved, selected_parent_ptr); - ns_list_add_to_end(&cur->ws_info->parent_list_free, selected_parent_ptr); + if (ws_bootstrap_neighbor_set(cur, selected_parent_ptr, false) < 0) { goto select_best_candidate; } - ws_neighbor_class_neighbor_unicast_time_info_update(neighbor_info.ws_neighbor, &selected_parent_ptr->ws_utt, selected_parent_ptr->timestamp); - ws_neighbor_class_neighbor_unicast_schedule_set(neighbor_info.ws_neighbor, &selected_parent_ptr->ws_us); - 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; @@ -3305,6 +3427,8 @@ void ws_bootstrap_seconds_timer(protocol_interface_info_entry_t *cur, uint32_t s } } + ws_llc_timer_seconds(cur, seconds); + } void ws_primary_parent_update(protocol_interface_info_entry_t *interface, mac_neighbor_table_entry_t *neighbor) diff --git a/source/6LoWPAN/ws/ws_bootstrap.h b/source/6LoWPAN/ws/ws_bootstrap.h index 949eac4a99d..c9cdcd46b4d 100644 --- a/source/6LoWPAN/ws/ws_bootstrap.h +++ b/source/6LoWPAN/ws/ws_bootstrap.h @@ -31,6 +31,7 @@ typedef enum { struct llc_neighbour_req; struct ws_us_ie; +struct ws_neighbor_class_entry; int ws_bootstrap_init(int8_t interface_id, net_6lowpan_mode_e bootstrap_mode); @@ -81,6 +82,12 @@ void ws_bootstrap_eapol_parent_synch(struct protocol_interface_info_entry *cur, bool ws_bootstrap_validate_channel_plan(struct ws_us_ie *ws_us, struct protocol_interface_info_entry *cur); +void ws_bootstrap_eapol_rx_temporary_set(struct protocol_interface_info_entry *interface, const uint8_t *src64); + +struct ws_neighbor_class_entry *ws_bootstrap_eapol_tx_temporary_set(struct protocol_interface_info_entry *interface, const uint8_t *src64); + +void ws_bootstrap_eapol_tx_temporary_clear(struct protocol_interface_info_entry *interface); + #else #define ws_bootstrap_init(interface_id, bootstrap_mode) (-1) diff --git a/source/6LoWPAN/ws/ws_cfg_settings.c b/source/6LoWPAN/ws/ws_cfg_settings.c index bebe6627d75..8eacf4802d4 100644 --- a/source/6LoWPAN/ws/ws_cfg_settings.c +++ b/source/6LoWPAN/ws/ws_cfg_settings.c @@ -49,8 +49,9 @@ #define TRICKLE_IMIN_15_SECS 15 typedef struct ws_cfg_nw_size_s { + ws_gen_cfg_t gen; /**< General configuration */ ws_timing_cfg_t timing; /**< Timing configuration */ - ws_rpl_cfg_t rpl; /**< RPL configuration */ + ws_bbr_cfg_t bbr; /**< RPL configuration */ ws_sec_prot_cfg_t sec_prot; /**< Security protocols configuration */ } ws_cfg_nw_size_t; @@ -69,7 +70,7 @@ typedef union { ws_gen_cfg_t gen; ws_phy_cfg_t phy; ws_timing_cfg_t timing; - ws_rpl_cfg_t rpl; + ws_bbr_cfg_t bbr; ws_fhss_cfg_t fhss; ws_mpl_cfg_t mpl; ws_sec_timer_cfg_t sec_timer; @@ -81,12 +82,13 @@ static int8_t ws_cfg_to_get(ws_cfgs_t **cfg, ws_cfgs_t *new_cfg, ws_cfg_validate 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); +static void ws_cfg_network_size_config_set_xlarge(ws_cfg_nw_size_t *cfg); static void ws_cfg_network_size_config_set_certificate(ws_cfg_nw_size_t *cfg); static int8_t ws_cfg_network_size_default_set(ws_gen_cfg_t *cfg); static int8_t ws_cfg_gen_default_set(ws_gen_cfg_t *cfg); static int8_t ws_cfg_phy_default_set(ws_phy_cfg_t *cfg); static int8_t ws_cfg_timing_default_set(ws_timing_cfg_t *cfg); -static int8_t ws_cfg_rpl_default_set(ws_rpl_cfg_t *cfg); +static int8_t ws_cfg_bbr_default_set(ws_bbr_cfg_t *cfg); static int8_t ws_cfg_mpl_default_set(ws_mpl_cfg_t *cfg); static int8_t ws_cfg_fhss_default_set(ws_fhss_cfg_t *cfg); static int8_t ws_cfg_sec_timer_default_set(ws_sec_timer_cfg_t *cfg); @@ -107,7 +109,7 @@ static const ws_cfg_cb_t cfg_cb[] = { CFG_CB(ws_cfg_gen_default_set, ws_cfg_gen_validate, ws_cfg_gen_set, offsetof(ws_cfg_t, gen)), CFG_CB(ws_cfg_phy_default_set, ws_cfg_phy_validate, ws_cfg_phy_set, offsetof(ws_cfg_t, phy)), CFG_CB(ws_cfg_timing_default_set, ws_cfg_timing_validate, ws_cfg_timing_set, offsetof(ws_cfg_t, timing)), - CFG_CB(ws_cfg_rpl_default_set, ws_cfg_rpl_validate, ws_cfg_rpl_set, offsetof(ws_cfg_t, rpl)), + CFG_CB(ws_cfg_bbr_default_set, ws_cfg_bbr_validate, ws_cfg_bbr_set, offsetof(ws_cfg_t, bbr)), CFG_CB(ws_cfg_mpl_default_set, ws_cfg_mpl_validate, ws_cfg_mpl_set, offsetof(ws_cfg_t, mpl)), CFG_CB(ws_cfg_fhss_default_set, ws_cfg_fhss_validate, ws_cfg_fhss_set, offsetof(ws_cfg_t, fhss)), CFG_CB(ws_cfg_sec_timer_default_set, ws_cfg_sec_timer_validate, ws_cfg_sec_timer_set, offsetof(ws_cfg_t, sec_timer)), @@ -128,10 +130,12 @@ static int8_t ws_cfg_to_get(ws_cfgs_t **cfg, ws_cfgs_t *new_cfg, ws_cfg_validate 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.timing) { + 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.rpl) { - *cfg = (ws_cfgs_t *) &nw_size_external_cfg->rpl; + } 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 { @@ -245,8 +249,9 @@ int8_t ws_cfg_network_size_set(protocol_interface_info_entry_t *cur, ws_gen_cfg_ 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_rpl_get(&nw_size_cfg.rpl, NULL); + ws_cfg_bbr_get(&nw_size_cfg.bbr, NULL); ws_cfg_sec_prot_get(&nw_size_cfg.sec_prot, NULL); ws_cfg_network_size_config_set_size set_function = NULL; @@ -257,8 +262,10 @@ int8_t ws_cfg_network_size_set(protocol_interface_info_entry_t *cur, ws_gen_cfg_ set_function = ws_cfg_network_size_config_set_small; } else if (cfg->network_size <= NETWORK_SIZE_MEDIUM) { set_function = ws_cfg_network_size_config_set_medium; - } else { + } else if (cfg->network_size <= NETWORK_SIZE_LARGE) { set_function = ws_cfg_network_size_config_set_large; + } else { + set_function = ws_cfg_network_size_config_set_xlarge; } // Overrides the values on the new configuration @@ -279,13 +286,17 @@ int8_t ws_cfg_network_size_set(protocol_interface_info_entry_t *cur, ws_gen_cfg_ } /* 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_rpl_validate(&ws_cfg.rpl, &nw_size_cfg.rpl) == CFG_SETTINGS_CHANGED || + if (ws_cfg_bbr_validate(&ws_cfg.bbr, &nw_size_cfg.bbr) == CFG_SETTINGS_CHANGED || old_network_size == NETWORK_SIZE_AUTOMATIC) { - ws_cfg_rpl_set(cur, &ws_cfg.rpl, &nw_size_cfg.rpl, &set_flags); + 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) { @@ -305,8 +316,10 @@ int8_t ws_cfg_network_size_configure(protocol_interface_info_entry_t *cur, uint1 // 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_rpl_get(&new_nw_size_cfg.rpl, &flags); + ws_cfg_bbr_get(&new_nw_size_cfg.bbr, &flags); ws_cfg_sec_prot_get(&new_nw_size_cfg.sec_prot, &flags); if (!nw_size_external_cfg) { @@ -321,16 +334,20 @@ int8_t ws_cfg_network_size_configure(protocol_interface_info_entry_t *cur, uint1 if (network_size < 100) { // Automatic ws_cfg_network_size_config_set_small(&new_nw_size_cfg); - } else if (network_size < 300) { + } else if (network_size < 800) { // Medium ws_cfg_network_size_config_set_medium(&new_nw_size_cfg); + } else if (network_size < 1500) { + // Medium + ws_cfg_network_size_config_set_large(&new_nw_size_cfg); } else { // Large - ws_cfg_network_size_config_set_large(&new_nw_size_cfg); + 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_rpl_set(cur, NULL, &new_nw_size_cfg.rpl, &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); return CFG_SETTINGS_OK; @@ -338,112 +355,190 @@ int8_t ws_cfg_network_size_configure(protocol_interface_info_entry_t *cur, uint1 static void ws_cfg_network_size_config_set_small(ws_cfg_nw_size_t *cfg) { + // Configure the Wi-SUN parent configuration + cfg->gen.rpl_parent_candidate_max = WS_RPL_PARENT_CANDIDATE_MAX; + cfg->gen.rpl_selected_parent_max = WS_RPL_SELECTED_PARENT_MAX; + // Configure the Wi-SUN timing trickle parameter cfg->timing.disc_trickle_imin = TRICKLE_IMIN_15_SECS; // 15 seconds cfg->timing.disc_trickle_imax = TRICKLE_IMIN_15_SECS << 2; // 60 seconds cfg->timing.disc_trickle_k = 1; cfg->timing.pan_timeout = PAN_VERSION_SMALL_NETWORK_TIMEOUT; cfg->timing.temp_link_min_timeout = WS_NEIGHBOR_TEMPORARY_LINK_MIN_TIMEOUT_SMALL; + cfg->timing.temp_eapol_min_timeout = WS_EAPOL_TEMPORARY_ENTRY_SMALL_TIMEOUT; // RPL configuration - cfg->rpl.dio_interval_min = WS_RPL_DIO_IMIN_SMALL; // 15; 32s seconds - cfg->rpl.dio_interval_doublings = WS_RPL_DIO_DOUBLING_SMALL; // 2; 128 - cfg->rpl.dio_redundancy_constant = WS_RPL_DIO_REDUNDANCY_SMALL; // Disabled - cfg->rpl.dag_max_rank_increase = WS_RPL_MAX_HOP_RANK_INCREASE; - cfg->rpl.min_hop_rank_increase = WS_RPL_MIN_HOP_RANK_INCREASE; - cfg->rpl.rpl_parent_candidate_max = WS_RPL_PARENT_CANDIDATE_MAX; - cfg->rpl.rpl_selected_parent_max = WS_RPL_SELECTED_PARENT_MAX; + cfg->bbr.dio_interval_min = WS_RPL_DIO_IMIN_SMALL; // 15; 32s seconds + cfg->bbr.dio_interval_doublings = WS_RPL_DIO_DOUBLING_SMALL; // 2; 128 + cfg->bbr.dio_redundancy_constant = WS_RPL_DIO_REDUNDANCY_SMALL; // Disabled + cfg->bbr.dag_max_rank_increase = WS_RPL_MAX_HOP_RANK_INCREASE; + cfg->bbr.min_hop_rank_increase = WS_RPL_MIN_HOP_RANK_INCREASE; + cfg->bbr.dhcp_address_lifetime = WS_DHCP_ADDRESS_LIFETIME_SMALL; // EAPOL configuration cfg->sec_prot.sec_prot_trickle_imin = SEC_PROT_SMALL_IMIN; cfg->sec_prot.sec_prot_trickle_imax = SEC_PROT_SMALL_IMAX; cfg->sec_prot.sec_prot_trickle_timer_exp = SEC_PROT_TIMER_EXPIRATIONS; cfg->sec_prot.sec_prot_retry_timeout = SEC_PROT_RETRY_TIMEOUT_SMALL; - cfg->sec_prot.sec_max_ongoing_authentication = MAX_SIMULTANEOUS_EAP_TLS_NEGOTIATIONS_SMALL; + + cfg->sec_prot.sec_max_ongoing_authentication = MAX_SIMULTANEOUS_SECURITY_NEGOTIATIONS_SMALL; + + cfg->sec_prot.initial_key_retry_delay = DEFAULT_INITIAL_KEY_RETRY_TIMER; + cfg->sec_prot.initial_key_imin = SMALL_NW_INITIAL_KEY_TRICKLE_IMIN_SECS; + cfg->sec_prot.initial_key_imax = SMALL_NW_INITIAL_KEY_TRICKLE_IMAX_SECS; + cfg->sec_prot.initial_key_retry_cnt = DEFAULT_INITIAL_KEY_RETRY_COUNT; } static void ws_cfg_network_size_config_set_medium(ws_cfg_nw_size_t *cfg) { + // Configure the Wi-SUN parent configuration + cfg->gen.rpl_parent_candidate_max = WS_RPL_PARENT_CANDIDATE_MAX; + cfg->gen.rpl_selected_parent_max = WS_RPL_SELECTED_PARENT_MAX; + // Configure the Wi-SUN timing trickle parameters - cfg->timing.disc_trickle_imin = TRICKLE_IMIN_30_SECS; // 30 seconds - cfg->timing.disc_trickle_imax = TRICKLE_IMIN_30_SECS << 5; // 960 seconds; 16 minutes + cfg->timing.disc_trickle_imin = TRICKLE_IMIN_60_SECS; // 60 seconds + cfg->timing.disc_trickle_imax = TRICKLE_IMIN_60_SECS << 4; // 960 seconds; 16 minutes cfg->timing.disc_trickle_k = 1; cfg->timing.pan_timeout = PAN_VERSION_MEDIUM_NETWORK_TIMEOUT; cfg->timing.temp_link_min_timeout = WS_NEIGHBOR_TEMPORARY_LINK_MIN_TIMEOUT_SMALL; + cfg->timing.temp_eapol_min_timeout = WS_EAPOL_TEMPORARY_ENTRY_MEDIUM_TIMEOUT; // RPL configuration - cfg->rpl.dio_interval_min = WS_RPL_DIO_IMIN_MEDIUM; // 15; 32s - cfg->rpl.dio_interval_doublings = WS_RPL_DIO_DOUBLING_MEDIUM; // 2; 1024s - cfg->rpl.dio_redundancy_constant = WS_RPL_DIO_REDUNDANCY_MEDIUM; // 10 - cfg->rpl.dag_max_rank_increase = WS_RPL_MAX_HOP_RANK_INCREASE; - cfg->rpl.min_hop_rank_increase = WS_RPL_MIN_HOP_RANK_INCREASE; - cfg->rpl.rpl_parent_candidate_max = WS_RPL_PARENT_CANDIDATE_MAX; - cfg->rpl.rpl_selected_parent_max = WS_RPL_SELECTED_PARENT_MAX; + cfg->bbr.dio_interval_min = WS_RPL_DIO_IMIN_MEDIUM; // 17; 128s + cfg->bbr.dio_interval_doublings = WS_RPL_DIO_DOUBLING_MEDIUM; // 3; 1024s + cfg->bbr.dio_redundancy_constant = WS_RPL_DIO_REDUNDANCY_MEDIUM; // 10 + cfg->bbr.dag_max_rank_increase = WS_RPL_MAX_HOP_RANK_INCREASE; + cfg->bbr.min_hop_rank_increase = WS_RPL_MIN_HOP_RANK_INCREASE; + cfg->bbr.dhcp_address_lifetime = WS_DHCP_ADDRESS_LIFETIME_MEDIUM; // EAPOL configuration cfg->sec_prot.sec_prot_trickle_imin = SEC_PROT_SMALL_IMIN; cfg->sec_prot.sec_prot_trickle_imax = SEC_PROT_SMALL_IMAX; cfg->sec_prot.sec_prot_trickle_timer_exp = SEC_PROT_TIMER_EXPIRATIONS; cfg->sec_prot.sec_prot_retry_timeout = SEC_PROT_RETRY_TIMEOUT_SMALL; - cfg->sec_prot.sec_max_ongoing_authentication = MAX_SIMULTANEOUS_EAP_TLS_NEGOTIATIONS_MEDIUM; + + cfg->sec_prot.sec_max_ongoing_authentication = MAX_SIMULTANEOUS_SECURITY_NEGOTIATIONS_MEDIUM; + + cfg->sec_prot.initial_key_retry_delay = DEFAULT_INITIAL_KEY_RETRY_TIMER; + cfg->sec_prot.initial_key_imin = MEDIUM_NW_INITIAL_KEY_TRICKLE_IMIN_SECS; + cfg->sec_prot.initial_key_imax = MEDIUM_NW_INITIAL_KEY_TRICKLE_IMAX_SECS; + cfg->sec_prot.initial_key_retry_cnt = DEFAULT_INITIAL_KEY_RETRY_COUNT; } static void ws_cfg_network_size_config_set_large(ws_cfg_nw_size_t *cfg) { + // Configure the Wi-SUN parent configuration + cfg->gen.rpl_parent_candidate_max = WS_RPL_PARENT_CANDIDATE_MAX; + cfg->gen.rpl_selected_parent_max = WS_RPL_SELECTED_PARENT_MAX; + // Configure the Wi-SUN timing trickle parameters - cfg->timing.disc_trickle_imin = TRICKLE_IMIN_60_SECS; // 60 seconds - cfg->timing.disc_trickle_imax = TRICKLE_IMIN_60_SECS << 4; // 960 seconds; 16 minutes + cfg->timing.disc_trickle_imin = TRICKLE_IMIN_60_SECS << 2; // 240 seconds + cfg->timing.disc_trickle_imax = 1536; // 1536 seconds; 25 minutes cfg->timing.disc_trickle_k = 1; cfg->timing.pan_timeout = PAN_VERSION_LARGE_NETWORK_TIMEOUT; cfg->timing.temp_link_min_timeout = WS_NEIGHBOR_TEMPORARY_LINK_MIN_TIMEOUT_LARGE; + cfg->timing.temp_eapol_min_timeout = WS_EAPOL_TEMPORARY_ENTRY_LARGE_TIMEOUT; + + // RPL configuration + cfg->bbr.dio_interval_min = WS_RPL_DIO_IMIN_LARGE; // 18; 262s, 4.5min + cfg->bbr.dio_interval_doublings = WS_RPL_DIO_DOUBLING_LARGE; // 3; 2048s, 34min + cfg->bbr.dio_redundancy_constant = WS_RPL_DIO_REDUNDANCY_LARGE; // 10 + cfg->bbr.dag_max_rank_increase = WS_RPL_MAX_HOP_RANK_INCREASE; + cfg->bbr.min_hop_rank_increase = WS_RPL_MIN_HOP_RANK_INCREASE; + cfg->bbr.dhcp_address_lifetime = WS_DHCP_ADDRESS_LIFETIME_LARGE; + + // EAPOL configuration + cfg->sec_prot.sec_prot_trickle_imin = SEC_PROT_LARGE_IMIN; + cfg->sec_prot.sec_prot_trickle_imax = SEC_PROT_LARGE_IMAX; + cfg->sec_prot.sec_prot_trickle_timer_exp = SEC_PROT_TIMER_EXPIRATIONS; + cfg->sec_prot.sec_prot_retry_timeout = SEC_PROT_RETRY_TIMEOUT_LARGE; + + cfg->sec_prot.sec_max_ongoing_authentication = MAX_SIMULTANEOUS_SECURITY_NEGOTIATIONS_LARGE; + + cfg->sec_prot.initial_key_retry_delay = NONE_INITIAL_KEY_RETRY_TIMER; + cfg->sec_prot.initial_key_imin = LARGE_NW_INITIAL_KEY_TRICKLE_IMIN_SECS; + cfg->sec_prot.initial_key_imax = LARGE_NW_INITIAL_KEY_TRICKLE_IMAX_SECS; + cfg->sec_prot.initial_key_retry_cnt = LARGE_NW_INITIAL_KEY_RETRY_COUNT; +} + +static void ws_cfg_network_size_config_set_xlarge(ws_cfg_nw_size_t *cfg) +{ + // Configure the Wi-SUN parent configuration + cfg->gen.rpl_parent_candidate_max = WS_RPL_PARENT_CANDIDATE_MAX; + cfg->gen.rpl_selected_parent_max = WS_RPL_SELECTED_PARENT_MAX; + + // Configure the Wi-SUN timing trickle parameters + cfg->timing.disc_trickle_imin = TRICKLE_IMIN_60_SECS << 2; // 240 seconds + cfg->timing.disc_trickle_imax = 1920; // 1920 seconds; 32 minutes + cfg->timing.disc_trickle_k = 1; + cfg->timing.pan_timeout = PAN_VERSION_XLARGE_NETWORK_TIMEOUT; + cfg->timing.temp_link_min_timeout = WS_NEIGHBOR_TEMPORARY_LINK_MIN_TIMEOUT_LARGE; + cfg->timing.temp_eapol_min_timeout = WS_EAPOL_TEMPORARY_ENTRY_LARGE_TIMEOUT; // RPL configuration - cfg->rpl.dio_interval_min = WS_RPL_DIO_IMIN_LARGE; // 19; 524s, 9min - cfg->rpl.dio_interval_doublings = WS_RPL_DIO_DOUBLING_LARGE; // 1; 1024s, 17min - cfg->rpl.dio_redundancy_constant = WS_RPL_DIO_REDUNDANCY_LARGE; // 10 - cfg->rpl.dag_max_rank_increase = WS_RPL_MAX_HOP_RANK_INCREASE; - cfg->rpl.min_hop_rank_increase = WS_RPL_MIN_HOP_RANK_INCREASE; - cfg->rpl.rpl_parent_candidate_max = WS_RPL_PARENT_CANDIDATE_MAX; - cfg->rpl.rpl_selected_parent_max = WS_RPL_SELECTED_PARENT_MAX; + cfg->bbr.dio_interval_min = WS_RPL_DIO_IMIN_XLARGE; // 18; 262s, 4.5min + cfg->bbr.dio_interval_doublings = WS_RPL_DIO_DOUBLING_XLARGE; // 4; 2048s, 34min + cfg->bbr.dio_redundancy_constant = WS_RPL_DIO_REDUNDANCY_XLARGE; // 10 + cfg->bbr.dag_max_rank_increase = WS_RPL_MAX_HOP_RANK_INCREASE; + cfg->bbr.min_hop_rank_increase = WS_RPL_MIN_HOP_RANK_INCREASE; + cfg->bbr.dhcp_address_lifetime = WS_DHCP_ADDRESS_LIFETIME_LARGE; // EAPOL configuration cfg->sec_prot.sec_prot_trickle_imin = SEC_PROT_LARGE_IMIN; cfg->sec_prot.sec_prot_trickle_imax = SEC_PROT_LARGE_IMAX; cfg->sec_prot.sec_prot_trickle_timer_exp = SEC_PROT_TIMER_EXPIRATIONS; cfg->sec_prot.sec_prot_retry_timeout = SEC_PROT_RETRY_TIMEOUT_LARGE; - cfg->sec_prot.sec_max_ongoing_authentication = MAX_SIMULTANEOUS_EAP_TLS_NEGOTIATIONS_LARGE; + + cfg->sec_prot.sec_max_ongoing_authentication = MAX_SIMULTANEOUS_SECURITY_NEGOTIATIONS_LARGE; + + cfg->sec_prot.initial_key_retry_delay = NONE_INITIAL_KEY_RETRY_TIMER; + cfg->sec_prot.initial_key_imin = EXTRA_LARGE_NW_INITIAL_KEY_TRICKLE_IMIN_SECS; + cfg->sec_prot.initial_key_imax = EXTRA_LARGE_NW_INITIAL_KEY_TRICKLE_IMAX_SECS; + cfg->sec_prot.initial_key_retry_cnt = EXTRA_LARGE_NW_INITIAL_KEY_RETRY_COUNT; } static void ws_cfg_network_size_config_set_certificate(ws_cfg_nw_size_t *cfg) { + // Configure the Wi-SUN parent configuration + cfg->gen.rpl_parent_candidate_max = WS_CERTIFICATE_RPL_PARENT_CANDIDATE_MAX; + cfg->gen.rpl_selected_parent_max = WS_CERTIFICATE_RPL_SELECTED_PARENT_MAX; + // Configure the Wi-SUN timing trickle parameters cfg->timing.disc_trickle_imin = TRICKLE_IMIN_15_SECS; // 15 seconds cfg->timing.disc_trickle_imax = TRICKLE_IMIN_15_SECS << 2; // 60 seconds cfg->timing.disc_trickle_k = 1; cfg->timing.pan_timeout = PAN_VERSION_SMALL_NETWORK_TIMEOUT; cfg->timing.temp_link_min_timeout = WS_NEIGHBOR_TEMPORARY_LINK_MIN_TIMEOUT_SMALL; + cfg->timing.temp_eapol_min_timeout = WS_EAPOL_TEMPORARY_ENTRY_SMALL_TIMEOUT; // RPL configuration (small) - cfg->rpl.dio_interval_min = WS_RPL_DIO_IMIN_SMALL; // 15; 32s seconds - cfg->rpl.dio_interval_doublings = WS_RPL_DIO_DOUBLING_SMALL; // 2; 128 - cfg->rpl.dio_redundancy_constant = WS_RPL_DIO_REDUNDANCY_SMALL; // Disabled - cfg->rpl.dag_max_rank_increase = WS_CERTIFICATE_RPL_MAX_HOP_RANK_INCREASE; - cfg->rpl.min_hop_rank_increase = WS_CERTIFICATE_RPL_MIN_HOP_RANK_INCREASE; - cfg->rpl.rpl_parent_candidate_max = WS_CERTIFICATE_RPL_PARENT_CANDIDATE_MAX; - cfg->rpl.rpl_selected_parent_max = WS_CERTIFICATE_RPL_SELECTED_PARENT_MAX; + cfg->bbr.dio_interval_min = WS_RPL_DIO_IMIN_SMALL; // 15; 32s seconds + cfg->bbr.dio_interval_doublings = WS_RPL_DIO_DOUBLING_SMALL; // 2; 128 + cfg->bbr.dio_redundancy_constant = WS_RPL_DIO_REDUNDANCY_SMALL; // Disabled + cfg->bbr.dag_max_rank_increase = WS_CERTIFICATE_RPL_MAX_HOP_RANK_INCREASE; + cfg->bbr.min_hop_rank_increase = WS_CERTIFICATE_RPL_MIN_HOP_RANK_INCREASE; + cfg->bbr.dhcp_address_lifetime = WS_DHCP_ADDRESS_LIFETIME_SMALL; // EAPOL configuration cfg->sec_prot.sec_prot_trickle_imin = SEC_PROT_SMALL_IMIN; cfg->sec_prot.sec_prot_trickle_imax = SEC_PROT_SMALL_IMAX; cfg->sec_prot.sec_prot_trickle_timer_exp = SEC_PROT_TIMER_EXPIRATIONS; cfg->sec_prot.sec_prot_retry_timeout = SEC_PROT_RETRY_TIMEOUT_SMALL; - cfg->sec_prot.sec_max_ongoing_authentication = MAX_SIMULTANEOUS_EAP_TLS_NEGOTIATIONS_SMALL; + + cfg->sec_prot.sec_max_ongoing_authentication = MAX_SIMULTANEOUS_SECURITY_NEGOTIATIONS_SMALL; + + cfg->sec_prot.initial_key_retry_delay = DEFAULT_INITIAL_KEY_RETRY_TIMER; + cfg->sec_prot.initial_key_imin = SMALL_NW_INITIAL_KEY_TRICKLE_IMIN_SECS; + cfg->sec_prot.initial_key_imax = SMALL_NW_INITIAL_KEY_TRICKLE_IMAX_SECS; + cfg->sec_prot.initial_key_retry_cnt = DEFAULT_INITIAL_KEY_RETRY_COUNT; } 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; } @@ -467,7 +562,9 @@ 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->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; } @@ -493,6 +590,8 @@ int8_t ws_cfg_gen_set(protocol_interface_info_entry_t *cur, ws_gen_cfg_t *cfg, w 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)) { ws_bootstrap_restart_delayed(cur->id); @@ -584,11 +683,12 @@ int8_t ws_cfg_phy_set(protocol_interface_info_entry_t *cur, ws_phy_cfg_t *cfg, w static int8_t ws_cfg_timing_default_set(ws_timing_cfg_t *cfg) { // Configure the Wi-SUN timing trickle parameters - cfg->disc_trickle_imin = TRICKLE_IMIN_30_SECS; // 30 seconds - cfg->disc_trickle_imax = TRICKLE_IMIN_30_SECS << 5; // 960 seconds; 16 minutes + cfg->disc_trickle_imin = TRICKLE_IMIN_60_SECS; // 60 seconds + cfg->disc_trickle_imax = TRICKLE_IMIN_60_SECS << 4; // 960 seconds; 16 minutes cfg->disc_trickle_k = 1; cfg->pan_timeout = PAN_VERSION_MEDIUM_NETWORK_TIMEOUT; cfg->temp_link_min_timeout = WS_NEIGHBOR_TEMPORARY_LINK_MIN_TIMEOUT_SMALL; + cfg->temp_eapol_min_timeout = WS_EAPOL_TEMPORARY_ENTRY_MEDIUM_TIMEOUT; return CFG_SETTINGS_OK; } @@ -658,58 +758,56 @@ int8_t ws_cfg_timing_set(protocol_interface_info_entry_t *cur, ws_timing_cfg_t * return CFG_SETTINGS_OK; } -static int8_t ws_cfg_rpl_default_set(ws_rpl_cfg_t *cfg) +static int8_t ws_cfg_bbr_default_set(ws_bbr_cfg_t *cfg) { // Something in between - // imin: 15 (32s) - // doublings:5 (960s) + // imin: 17 (128s) + // doublings:3 (1024s) // redundancy; 10 - //ws_bbr_rpl_config(cur, 15, 5, 10, WS_RPL_MAX_HOP_RANK_INCREASE, WS_RPL_MIN_HOP_RANK_INCREASE); + //ws_bbr_rpl_config(cur, 17, 3, 10, WS_RPL_MAX_HOP_RANK_INCREASE, WS_RPL_MIN_HOP_RANK_INCREASE); - cfg->dio_interval_min = 15; // 32s - cfg->dio_interval_doublings = 5; // 1024s + cfg->dio_interval_min = WS_RPL_DIO_IMIN_MEDIUM; // 128s + cfg->dio_interval_doublings = WS_RPL_DIO_DOUBLING_MEDIUM; // 1024s cfg->dio_redundancy_constant = 10; cfg->dag_max_rank_increase = WS_RPL_MAX_HOP_RANK_INCREASE; cfg->min_hop_rank_increase = WS_RPL_MIN_HOP_RANK_INCREASE; - cfg->rpl_parent_candidate_max = WS_RPL_PARENT_CANDIDATE_MAX; - cfg->rpl_selected_parent_max = WS_RPL_SELECTED_PARENT_MAX; + cfg->dhcp_address_lifetime = WS_DHCP_ADDRESS_LIFETIME_MEDIUM; return CFG_SETTINGS_OK; } -int8_t ws_cfg_rpl_get(ws_rpl_cfg_t *cfg, uint8_t *flags) +int8_t ws_cfg_bbr_get(ws_bbr_cfg_t *cfg, uint8_t *flags) { - ws_rpl_cfg_t *get_cfg = NULL; - ws_cfg_to_get((ws_cfgs_t **) &get_cfg, NULL, NULL, (ws_cfgs_t *) &ws_cfg.rpl, 0, flags); + 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; return CFG_SETTINGS_OK; } -int8_t ws_cfg_rpl_validate(ws_rpl_cfg_t *cfg, ws_rpl_cfg_t *new_cfg) +int8_t ws_cfg_bbr_validate(ws_bbr_cfg_t *cfg, 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.rpl, 0, 0); + ws_cfg_to_get((ws_cfgs_t **) &cfg, (ws_cfgs_t *) new_cfg, NULL, (ws_cfgs_t *) &ws_cfg.bbr, 0, 0); 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 || cfg->dag_max_rank_increase != new_cfg->dag_max_rank_increase || cfg->min_hop_rank_increase != new_cfg->min_hop_rank_increase || - cfg->rpl_parent_candidate_max != new_cfg->rpl_parent_candidate_max || - cfg->rpl_selected_parent_max != new_cfg->rpl_selected_parent_max) { + cfg->dhcp_address_lifetime != new_cfg->dhcp_address_lifetime) { return CFG_SETTINGS_CHANGED; } return CFG_SETTINGS_OK; } -int8_t ws_cfg_rpl_set(protocol_interface_info_entry_t *cur, ws_rpl_cfg_t *cfg, ws_rpl_cfg_t *new_cfg, uint8_t *flags) +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) { (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_rpl_validate, (ws_cfgs_t *) &ws_cfg.rpl, &cfg_flags, 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) { return ret; } @@ -719,13 +817,14 @@ int8_t ws_cfg_rpl_set(protocol_interface_info_entry_t *cur, ws_rpl_cfg_t *cfg, w 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, new_cfg->min_hop_rank_increase); + ws_bbr_dhcp_address_lifetime_set(cur, new_cfg->dhcp_address_lifetime); } if (cfg == new_cfg) { return CFG_SETTINGS_OK; } - ws_cfg_trace((ws_cfgs_t *) cfg, (ws_cfgs_t *) new_cfg, sizeof(ws_rpl_cfg_t), "rpl"); + ws_cfg_trace((ws_cfgs_t *) cfg, (ws_cfgs_t *) new_cfg, sizeof(ws_bbr_cfg_t), "rpl"); *cfg = *new_cfg; @@ -978,7 +1077,12 @@ static int8_t ws_cfg_sec_prot_default_set(ws_sec_prot_cfg_t *cfg) cfg->sec_prot_trickle_imax = SEC_PROT_SMALL_IMAX; cfg->sec_prot_trickle_timer_exp = 2; cfg->sec_prot_retry_timeout = SEC_PROT_RETRY_TIMEOUT_SMALL; - cfg->sec_max_ongoing_authentication = MAX_SIMULTANEOUS_EAP_TLS_NEGOTIATIONS_MEDIUM; + cfg->sec_max_ongoing_authentication = MAX_SIMULTANEOUS_SECURITY_NEGOTIATIONS_MEDIUM; + cfg->initial_key_retry_delay = DEFAULT_INITIAL_KEY_RETRY_TIMER; + cfg->initial_key_imin = MEDIUM_NW_INITIAL_KEY_TRICKLE_IMIN_SECS; + cfg->initial_key_imax = MEDIUM_NW_INITIAL_KEY_TRICKLE_IMAX_SECS; + cfg->initial_key_retry_cnt = DEFAULT_INITIAL_KEY_RETRY_COUNT; + return CFG_SETTINGS_OK; } @@ -999,7 +1103,11 @@ int8_t ws_cfg_sec_prot_validate(ws_sec_prot_cfg_t *cfg, ws_sec_prot_cfg_t *new_c cfg->sec_prot_trickle_imax != new_cfg->sec_prot_trickle_imax || cfg->sec_prot_trickle_timer_exp != new_cfg->sec_prot_trickle_timer_exp || cfg->sec_prot_retry_timeout != new_cfg->sec_prot_retry_timeout || - cfg->sec_max_ongoing_authentication != new_cfg->sec_max_ongoing_authentication) { + cfg->sec_max_ongoing_authentication != new_cfg->sec_max_ongoing_authentication || + cfg->initial_key_retry_delay != new_cfg->initial_key_retry_delay || + cfg->initial_key_imin != new_cfg->initial_key_retry_delay || + cfg->initial_key_imax != new_cfg->initial_key_retry_delay || + cfg->initial_key_retry_cnt != new_cfg->initial_key_retry_delay) { return CFG_SETTINGS_CHANGED; } @@ -1095,8 +1203,9 @@ int8_t ws_cfg_settings_get(protocol_interface_info_entry_t *cur, ws_cfg_t *cfg) *cfg = ws_cfg; + ws_cfg_gen_get(&cfg->gen, NULL); ws_cfg_timing_get(&cfg->timing, NULL); - ws_cfg_rpl_get(&cfg->rpl, NULL); + ws_cfg_bbr_get(&cfg->bbr, NULL); ws_cfg_sec_prot_get(&cfg->sec_prot, NULL); return CFG_SETTINGS_OK; diff --git a/source/6LoWPAN/ws/ws_cfg_settings.h b/source/6LoWPAN/ws/ws_cfg_settings.h index 334489d5137..bc46336229d 100644 --- a/source/6LoWPAN/ws/ws_cfg_settings.h +++ b/source/6LoWPAN/ws/ws_cfg_settings.h @@ -27,6 +27,8 @@ typedef struct ws_gen_cfg_s { 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; /** @@ -47,20 +49,20 @@ typedef struct ws_timing_cfg_s { uint8_t disc_trickle_k; /**< Discovery trickle k; DISC_K; default 1 */ uint16_t pan_timeout; /**< PAN timeout; PAN_TIMEOUT; seconds; range 60-15300; default 3840 */ uint16_t temp_link_min_timeout; /**< Temporary neighbor link minimum timeout; seconds; default 260 */ + uint16_t temp_eapol_min_timeout; /**< Temporary neighbor link minimum timeout; seconds; default 330 */ } ws_timing_cfg_t; /** * \brief Struct ws_rpl_cfg_t RPL configuration */ -typedef struct ws_rpl_cfg_s { +typedef struct ws_bbr_cfg_s { uint8_t dio_interval_min; /**> DIO interval min; DEFAULT_DIO_INTERVAL_MIN; 2^value in milliseconds; range 1-255; default */ uint8_t dio_interval_doublings; /**> DIO interval doublings; DEFAULT_DIO_INTERVAL_DOUBLINGS; range 1-8; default */ uint8_t dio_redundancy_constant; /**> DIO redundancy constant; DEFAULT_DIO_REDUNDANCY_CONSTANT; range 0-10; default */ uint16_t dag_max_rank_increase; uint16_t min_hop_rank_increase; - 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_rpl_cfg_t; + uint32_t dhcp_address_lifetime; /**> DHCP address lifetime in seconds minimum 2 hours and maximum as days hours*/ +} ws_bbr_cfg_t; /** * \brief Struct ws_fhss_cfg_t Frequency hopping configuration @@ -106,11 +108,15 @@ typedef struct ws_sec_timer_cfg_s { * \brief Struct ws_sec_prot_cfg_t Security protocols configuration */ typedef struct ws_sec_prot_cfg_s { - uint16_t sec_prot_retry_timeout; /**< Security protocol retry timeout; seconds; default 330 */ - uint16_t sec_prot_trickle_imin; /**< Security protocol trickle parameters Imin; seconds; default 30 */ - uint16_t sec_prot_trickle_imax; /**< Security protocol trickle parameters Imax; seconds; default 90 */ - uint8_t sec_prot_trickle_timer_exp; /**< Security protocol trickle timer expirations; default 2 */ - uint16_t sec_max_ongoing_authentication; /**< Pae authenticator max Accept ongoing authentication count */ + uint16_t sec_prot_retry_timeout; /**< Security protocol retry timeout; seconds; default 330 */ + uint16_t sec_prot_trickle_imin; /**< Security protocol trickle parameters Imin; seconds; default 30 */ + uint16_t sec_prot_trickle_imax; /**< Security protocol trickle parameters Imax; seconds; default 90 */ + uint8_t sec_prot_trickle_timer_exp; /**< Security protocol trickle timer expirations; default 2 */ + uint16_t sec_max_ongoing_authentication; /**< Pae authenticator max Accept ongoing authentication count */ + uint16_t initial_key_retry_delay; /**< Delay before starting initial key trickle; seconds; default 120 */ + uint16_t initial_key_imin; /**< Initial key trickle Imin; seconds; default 360 */ + uint16_t initial_key_imax; /**< Initial key trickle Imax; seconds; default 720 */ + uint8_t initial_key_retry_cnt; /**< Number of initial key retries; default 2 */ } ws_sec_prot_cfg_t; /** @@ -120,7 +126,7 @@ typedef struct ws_cfg_s { ws_gen_cfg_t gen; /**< General configuration */ ws_phy_cfg_t phy; /**< Physical layer configuration */ ws_timing_cfg_t timing; /**< Timing configuration */ - ws_rpl_cfg_t rpl; /**< RPL configuration */ + ws_bbr_cfg_t bbr; /**< RPL configuration */ ws_fhss_cfg_t fhss; /**< Frequency hopping configuration */ ws_mpl_cfg_t mpl; /**< Multicast configuration */ ws_sec_timer_cfg_t sec_timer; /**< Security timers configuration */ @@ -161,9 +167,9 @@ 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_rpl_get(ws_rpl_cfg_t *cfg, uint8_t *flags); -int8_t ws_cfg_rpl_validate(ws_rpl_cfg_t *cfg, ws_rpl_cfg_t *new_cfg); -int8_t ws_cfg_rpl_set(protocol_interface_info_entry_t *cur, ws_rpl_cfg_t *cfg, ws_rpl_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_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); diff --git a/source/6LoWPAN/ws/ws_common.c b/source/6LoWPAN/ws/ws_common.c index 7bfb66df4ed..010f6c14ac3 100644 --- a/source/6LoWPAN/ws/ws_common.c +++ b/source/6LoWPAN/ws/ws_common.c @@ -49,12 +49,34 @@ uint8_t DEVICE_MIN_SENS = 174 - 93; uint16_t test_max_child_count_override = 0xffff; - -int8_t ws_generate_channel_list(uint32_t *channel_mask, uint16_t number_of_channels, uint8_t regulatory_domain) +int8_t ws_generate_channel_list(uint32_t *channel_mask, uint16_t number_of_channels, uint8_t regulatory_domain, uint8_t operating_class) { - (void)regulatory_domain; - for (uint8_t i = 0; i < number_of_channels; i++) { - channel_mask[0 + (i / 32)] |= (1 << (i % 32)); + uint32_t excluded_start_channel = 0xFFFFFFFF; + uint32_t excluded_end_channel = 0xFFFFFFFF; + + if (regulatory_domain == REG_DOMAIN_BZ) { + if (operating_class == 1) { + excluded_start_channel = 26; + excluded_end_channel = 64; + } else if (operating_class == 2) { + excluded_start_channel = 12; + excluded_end_channel = 32; + } else if (operating_class == 3) { + excluded_start_channel = 7; + excluded_end_channel = 21; + } + } + + // Clear channel mask + for (uint8_t i = 0; i < 8; i++) { + channel_mask[i] = 0; + } + + // Set channel maks outside excluded channels + for (uint16_t i = 0; i < number_of_channels; i++) { + if (i < excluded_start_channel || i > excluded_end_channel) { + channel_mask[0 + (i / 32)] |= (1 << (i % 32)); + } } return 0; } @@ -159,6 +181,19 @@ int8_t ws_common_regulatory_domain_config(protocol_interface_info_entry_t *cur, } else { return -1; } + } else if (hopping_schdule->regulatory_domain == REG_DOMAIN_BZ) { + if (hopping_schdule->operating_class == 1) { + hopping_schdule->ch0_freq = 9022; + hopping_schdule->channel_spacing = CHANNEL_SPACING_200; + } else if (hopping_schdule->operating_class == 2) { + hopping_schdule->ch0_freq = 9024; + hopping_schdule->channel_spacing = CHANNEL_SPACING_400; + } else if (hopping_schdule->operating_class == 3) { + hopping_schdule->ch0_freq = 9026; + hopping_schdule->channel_spacing = CHANNEL_SPACING_600; + } else { + return -1; + } } else if (hopping_schdule->regulatory_domain == REG_DOMAIN_JP) { if (hopping_schdule->operating_class == 1) { hopping_schdule->ch0_freq = 9206; @@ -189,6 +224,7 @@ int8_t ws_common_regulatory_domain_config(protocol_interface_info_entry_t *cur, if (!hopping_schdule->number_of_channels) { return -1; } + return 0; } @@ -232,6 +268,14 @@ uint16_t ws_common_channel_number_calc(uint8_t regulatory_domain, uint8_t operat } else if (operating_class == 3) { return 12; } + } else if (regulatory_domain == REG_DOMAIN_BZ) { + if (operating_class == 1) { + return 129; + } else if (operating_class == 2) { + return 64; + } else if (operating_class == 3) { + return 42; + } } else if (regulatory_domain == REG_DOMAIN_WW) { if (operating_class == 1) { // TODO we dont support this yet, but it is used as test value @@ -388,11 +432,13 @@ uint32_t ws_common_latency_estimate_get(protocol_interface_info_entry_t *cur) if (network_size <= NETWORK_SIZE_SMALL) { // handles also NETWORK_SIZE_CERTIFICATE - latency = 8000; + latency = 4000; } else if (network_size <= NETWORK_SIZE_MEDIUM) { + latency = 8000; + } else if (network_size <= NETWORK_SIZE_LARGE) { latency = 16000; } else { - latency = 32000; + latency = 24000; } return latency; @@ -405,22 +451,11 @@ uint32_t ws_common_datarate_get(protocol_interface_info_entry_t *cur) uint32_t ws_common_network_size_estimate_get(protocol_interface_info_entry_t *cur) { - uint32_t network_size_estimate = 0; - uint8_t network_size = cur->ws_info->cfg->gen.network_size; - - if (network_size == NETWORK_SIZE_AUTOMATIC) { - network_size = cur->ws_info->pan_information.pan_size / 100; - } + uint32_t network_size_estimate = 100; - if (network_size <= NETWORK_SIZE_SMALL) { - // tens of devices (now 30), handles also NETWORK_SIZE_CERTIFICATE - network_size_estimate = 30; - } else if (network_size <= NETWORK_SIZE_MEDIUM) { - // hundreds of devices (now 300) - network_size_estimate = 300; - } else { - // huge amount of devices (now 1000) - network_size_estimate = 1000; + if ((cur->ws_info->cfg->gen.network_size != NETWORK_SIZE_AUTOMATIC) && + (cur->ws_info->cfg->gen.network_size != NETWORK_SIZE_CERTIFICATE)) { + network_size_estimate = cur->ws_info->cfg->gen.network_size * 100; } return network_size_estimate; diff --git a/source/6LoWPAN/ws/ws_common.h b/source/6LoWPAN/ws/ws_common.h index 3aa154c0527..08d726ee6b1 100644 --- a/source/6LoWPAN/ws/ws_common.h +++ b/source/6LoWPAN/ws/ws_common.h @@ -82,6 +82,7 @@ typedef struct ws_info_s { trickle_params_t trickle_params_pan_discovery; uint8_t rpl_state; // state from rpl_event_t uint8_t pas_requests; // Amount of PAN solicits sent + uint8_t eapol_tx_index; parent_info_t parent_info[WS_PARENT_LIST_SIZE]; parent_info_list_t parent_list_free; parent_info_list_t parent_list_reserved; @@ -112,7 +113,7 @@ 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); +int8_t ws_generate_channel_list(uint32_t *channel_mask, uint16_t number_of_channels, uint8_t regulatory_domain, uint8_t operating_class); uint32_t ws_decode_channel_spacing(uint8_t channel_spacing); diff --git a/source/6LoWPAN/ws/ws_common_defines.h b/source/6LoWPAN/ws/ws_common_defines.h index d2797f8e803..749a5aa1fa3 100644 --- a/source/6LoWPAN/ws/ws_common_defines.h +++ b/source/6LoWPAN/ws/ws_common_defines.h @@ -236,9 +236,12 @@ typedef struct ws_bs_ie { #define WS_NEIGHBOR_TEMPORARY_LINK_MIN_TIMEOUT_SMALL 260 #define WS_NEIGHBOR_NUD_TIMEOUT WS_NEIGHBOR_LINK_TIMEOUT / 2 +#define WS_EAPOL_TEMPORARY_ENTRY_SMALL_TIMEOUT 330 +#define WS_EAPOL_TEMPORARY_ENTRY_MEDIUM_TIMEOUT WS_EAPOL_TEMPORARY_ENTRY_SMALL_TIMEOUT +#define WS_EAPOL_TEMPORARY_ENTRY_LARGE_TIMEOUT 750 + #define WS_NEIGHBOR_ETX_SAMPLE_MAX 3 #define WS_NEIGHBOR_FIRST_ETX_SAMPLE_MIN_COUNT 3 //This can't be bigger than WS_NEIGHBOR_ETX_SAMPLE_MAX -#define WS_NEIGHBOUR_MAX_CANDIDATE_PROBE 5 #define WS_PROBE_INIT_BASE_SECONDS 8 @@ -295,6 +298,34 @@ typedef struct ws_bs_ie { */ #define WS_TACK_MAX_MS 5 + +/* WS requires at least 19 MAC retransmissions (total 1+19=20 attempts). Default 802.15.4 macMaxFrameRetries is 3 (total 1+3=4 attempts). + * At least 4 channel retries must be used: (Initial channel + WS_NUMBER_OF_CHANNEL_RETRIES) * MAC attempts = (1+4)*4=20 attempts + * + * Valid settings could be for example: + * WS_MAX_FRAME_RETRIES WS_NUMBER_OF_CHANNEL_RETRIES Total attempts + * 0 19 1+0*1+19=20 + * 1 9 1+1*1+9=20 + * 2 6 1+2*1+6=21 + * 3 4 1+3*1+4=20 + * + */ +#define WS_MAX_FRAME_RETRIES 3 +#define WS_NUMBER_OF_CHANNEL_RETRIES 4 + + +#if (1 + WS_MAX_FRAME_RETRIES) * (1 + WS_NUMBER_OF_CHANNEL_RETRIES) < 20 +#warning "MAX frame retries set too low" +#endif + +/* + * Automatic CCA threshold: default threshold and range in dBm. + */ +#define CCA_DEFAULT_DBM -60 +#define CCA_HIGH_LIMIT -60 +#define CCA_LOW_LIMIT -100 + + /* * Config new version consistent filter period in 100ms periods */ diff --git a/source/6LoWPAN/ws/ws_config.h b/source/6LoWPAN/ws/ws_config.h index b2a9bd18c9f..6b00d6004c7 100644 --- a/source/6LoWPAN/ws/ws_config.h +++ b/source/6LoWPAN/ws/ws_config.h @@ -31,14 +31,18 @@ #define WS_RPL_DIO_DOUBLING_SMALL 2 #define WS_RPL_DIO_REDUNDANCY_SMALL 0 -#define WS_RPL_DIO_IMIN_MEDIUM 15 -#define WS_RPL_DIO_DOUBLING_MEDIUM 5 +#define WS_RPL_DIO_IMIN_MEDIUM 17 +#define WS_RPL_DIO_DOUBLING_MEDIUM 3 #define WS_RPL_DIO_REDUNDANCY_MEDIUM 10 -#define WS_RPL_DIO_IMIN_LARGE 19 -#define WS_RPL_DIO_DOUBLING_LARGE 1 +#define WS_RPL_DIO_IMIN_LARGE 18 +#define WS_RPL_DIO_DOUBLING_LARGE 3 #define WS_RPL_DIO_REDUNDANCY_LARGE 10 // May need some tuning still +#define WS_RPL_DIO_IMIN_XLARGE 18 +#define WS_RPL_DIO_DOUBLING_XLARGE 4 +#define WS_RPL_DIO_REDUNDANCY_XLARGE 10 // May need some tuning still + #define WS_RPL_DIO_IMIN_AUTOMATIC 14 #define WS_RPL_DIO_DOUBLING_AUTOMATIC 3 #define WS_RPL_DIO_REDUNDANCY_AUTOMATIC 0 @@ -46,6 +50,10 @@ #define WS_RPL_MIN_HOP_RANK_INCREASE 196 #define WS_RPL_MAX_HOP_RANK_INCREASE 2048 +#define WS_DHCP_ADDRESS_LIFETIME_SMALL 2*3600 // small networks less than devices 100 +#define WS_DHCP_ADDRESS_LIFETIME_MEDIUM 12*3600 // Medium size networks from 100 - 1000 device networks +#define WS_DHCP_ADDRESS_LIFETIME_LARGE 24*3600 // Large size networks 1000 + device networks + #define WS_CERTIFICATE_RPL_MIN_HOP_RANK_INCREASE 128 #define WS_CERTIFICATE_RPL_MAX_HOP_RANK_INCREASE 0 @@ -64,7 +72,10 @@ // RPL version number update intervall // after restart version numbers are increased faster and then slowed down when network is stable #define RPL_VERSION_LIFETIME 12*3600 -#define RPL_VERSION_LIFETIME_RESTART 3600 +#define RPL_VERSION_LIFETIME_RESTART_SMALL 3600 +#define RPL_VERSION_LIFETIME_RESTART_MEDIUM 2*3600 +#define RPL_VERSION_LIFETIME_RESTART_LARGE 4*3600 +#define RPL_VERSION_LIFETIME_RESTART_EXTRA_LARGE 8*3600 /* Border router connection lost timeout * @@ -81,6 +92,8 @@ #define PAN_VERSION_LARGE_NETWORK_TIMEOUT 90*60 +#define PAN_VERSION_XLARGE_NETWORK_TIMEOUT 120*60 + /* Routing Cost Weighting factor */ #define PRC_WEIGHT_FACTOR 256 @@ -153,10 +166,11 @@ extern uint8_t DEVICE_MIN_SENS; /* * MAC frame counter NVM storing configuration */ -#define FRAME_COUNTER_STORE_INTERVAL 60 // Time interval (on seconds) between frame counter store operations -#define FRAME_COUNTER_STORE_TRIGGER 5 // Delay (on seconds) before storing, when storing of frame counters is triggered -#define FRAME_COUNTER_INCREMENT 1000 // How much frame counter is incremented on start up -#define FRAME_COUNTER_STORE_THRESHOLD 800 // How much frame counter must increment before it is stored +#define FRAME_COUNTER_STORE_INTERVAL 60 // Time interval (on seconds) between checking if frame counter storing is needed +#define FRAME_COUNTER_STORE_FORCE_INTERVAL (3600 * 20) // Time interval (on seconds) before frame counter storing is forced (if no other storing operations triggered) +#define FRAME_COUNTER_STORE_TRIGGER 5 // Delay (on seconds) before storing, when storing of frame counters is triggered +#define FRAME_COUNTER_INCREMENT 1000 // How much frame counter is incremented on start up +#define FRAME_COUNTER_STORE_THRESHOLD 800 // How much frame counter must increment before it is stored /* @@ -199,10 +213,10 @@ extern uint8_t DEVICE_MIN_SENS; #define SEC_PROT_TIMER_EXPIRATIONS 2 // Number of retries -// Maximum number of simultaneous EAP-TLS negotiations -#define MAX_SIMULTANEOUS_EAP_TLS_NEGOTIATIONS_SMALL 3 -#define MAX_SIMULTANEOUS_EAP_TLS_NEGOTIATIONS_MEDIUM 20 -#define MAX_SIMULTANEOUS_EAP_TLS_NEGOTIATIONS_LARGE 50 +// Maximum number of simultaneous security negotiations +#define MAX_SIMULTANEOUS_SECURITY_NEGOTIATIONS_SMALL 3 +#define MAX_SIMULTANEOUS_SECURITY_NEGOTIATIONS_MEDIUM 20 +#define MAX_SIMULTANEOUS_SECURITY_NEGOTIATIONS_LARGE 50 /* * Security protocol timer configuration parameters @@ -218,4 +232,33 @@ extern uint8_t DEVICE_MIN_SENS; #define DEFAULT_GTK_MAX_MISMATCH 64 // 64 minutes #define DEFAULT_GTK_NEW_INSTALL_REQUIRED 80 // 80 percent of GTK lifetime --> 24 days +/* + * Security protocol initial EAPOL-key parameters + */ + +// How long the wait is before the first initial EAPOL-key retry +#define DEFAULT_INITIAL_KEY_RETRY_TIMER 120 +#define NONE_INITIAL_KEY_RETRY_TIMER 0 + +// Small network Default trickle values for sending of initial EAPOL-key +#define SMALL_NW_INITIAL_KEY_TRICKLE_IMIN_SECS 360 /* 6 to 8.3 minutes */ +#define SMALL_NW_INITIAL_KEY_TRICKLE_IMAX_SECS 500 + +// Small network Default trickle values for sending of initial EAPOL-key +#define MEDIUM_NW_INITIAL_KEY_TRICKLE_IMIN_SECS 360 /* 6 to 12 minutes */ +#define MEDIUM_NW_INITIAL_KEY_TRICKLE_IMAX_SECS 720 + +// Large network trickle values for sending of initial EAPOL-key +#define LARGE_NW_INITIAL_KEY_TRICKLE_IMIN_SECS 600 /* 10 to 20 minutes */ +#define LARGE_NW_INITIAL_KEY_TRICKLE_IMAX_SECS 1200 +#define LARGE_NW_INITIAL_KEY_RETRY_COUNT 4 + +// Very slow network values for sending of initial EAPOL-key +#define EXTRA_LARGE_NW_INITIAL_KEY_TRICKLE_IMIN_SECS 600 /* 10 to 20 minutes */ +#define EXTRA_LARGE_NW_INITIAL_KEY_TRICKLE_IMAX_SECS 1200 +#define EXTRA_LARGE_NW_INITIAL_KEY_RETRY_COUNT 4 + +// How many times sending of initial EAPOL-key is retried +#define DEFAULT_INITIAL_KEY_RETRY_COUNT 2 + #endif /* WS_CONFIG_H_ */ diff --git a/source/6LoWPAN/ws/ws_eapol_pdu.c b/source/6LoWPAN/ws/ws_eapol_pdu.c index ffe83c4a48d..f20530d4662 100644 --- a/source/6LoWPAN/ws/ws_eapol_pdu.c +++ b/source/6LoWPAN/ws/ws_eapol_pdu.c @@ -31,6 +31,7 @@ #include "6LoWPAN/MAC/mpx_api.h" #include "6LoWPAN/ws/ws_config.h" #include "6LoWPAN/ws/ws_eapol_pdu.h" +#include "6LoWPAN/ws/ws_llc.h" #ifdef HAVE_WS @@ -49,6 +50,7 @@ typedef NS_LIST_HEAD(eapol_pdu_msdu_t, link) eapol_pdu_msdu_list_t; typedef struct { uint8_t priority; + bool filter_requsted: 1; ws_eapol_pdu_address_check *addr_check; ws_eapol_pdu_receive *receive; ns_list_link_t link; @@ -147,6 +149,7 @@ int8_t ws_eapol_pdu_cb_register(protocol_interface_info_entry_t *interface_ptr, new_cb->priority = cb_data->priority; new_cb->addr_check = cb_data->addr_check; new_cb->receive = cb_data->receive; + new_cb->filter_requsted = cb_data->filter_requsted; ns_list_foreach(eapol_pdu_recv_cb_t, entry, &eapol_pdu_data->recv_cb_list) { if (new_cb->priority <= entry->priority) { @@ -307,6 +310,11 @@ static void ws_eapol_pdu_mpx_data_indication(const mpx_api_t *api, const struct ns_list_foreach(eapol_pdu_recv_cb_t, entry, &eapol_pdu_data->recv_cb_list) { if (entry->addr_check(eapol_pdu_data->interface_ptr, data->SrcAddr) >= 0) { + if (entry->filter_requsted && !ws_llc_eapol_relay_forward_filter(eapol_pdu_data->interface_ptr, data->SrcAddr, data->DSN, data->timestamp)) { + tr_info("EAPOL relay filter drop"); + return; + } + entry->receive(eapol_pdu_data->interface_ptr, data->SrcAddr, data->msdu_ptr, data->msduLength); break; } diff --git a/source/6LoWPAN/ws/ws_eapol_pdu.h b/source/6LoWPAN/ws/ws_eapol_pdu.h index 75f4ef40745..c385e9313c9 100644 --- a/source/6LoWPAN/ws/ws_eapol_pdu.h +++ b/source/6LoWPAN/ws/ws_eapol_pdu.h @@ -99,6 +99,7 @@ typedef enum { typedef struct { eapol_pdu_recv_prior_t priority; /**< Priority: high, medium or low */ + bool filter_requsted: 1; /**< True when EAPOL temporary filter requsted, false for normal functionality */ ws_eapol_pdu_address_check *addr_check; /**< Address check callback */ ws_eapol_pdu_receive *receive; /**< PDU receive callback */ } eapol_pdu_recv_cb_data_t; diff --git a/source/6LoWPAN/ws/ws_eapol_relay.c b/source/6LoWPAN/ws/ws_eapol_relay.c index 367181bfcc6..a5a83c3ec3e 100644 --- a/source/6LoWPAN/ws/ws_eapol_relay.c +++ b/source/6LoWPAN/ws/ws_eapol_relay.c @@ -53,6 +53,7 @@ static void ws_eapol_relay_socket_cb(void *cb); static const eapol_pdu_recv_cb_data_t eapol_pdu_recv_cb_data = { .priority = EAPOL_PDU_RECV_LOW_PRIORITY, + .filter_requsted = true, .addr_check = ws_eapol_relay_eapol_pdu_address_check, .receive = ws_eapol_relay_eapol_pdu_receive }; diff --git a/source/6LoWPAN/ws/ws_empty_functions.c b/source/6LoWPAN/ws/ws_empty_functions.c index e03e811d634..f9e4e971955 100644 --- a/source/6LoWPAN/ws/ws_empty_functions.c +++ b/source/6LoWPAN/ws/ws_empty_functions.c @@ -25,6 +25,7 @@ #include "6LoWPAN/ws/ws_common.h" #include "ws_management_api.h" +#include "ns_time_api.h" #ifndef HAVE_WS int ws_management_node_init( @@ -392,4 +393,9 @@ int ws_statistics_stop(int8_t interface_id) return -1; } +void ns_time_api_system_time_callback_set(ns_time_api_system_time_callback callback) +{ + (void) callback; +} + #endif // no HAVE_WS diff --git a/source/6LoWPAN/ws/ws_llc.h b/source/6LoWPAN/ws/ws_llc.h index 33891f05a38..fd3b0105014 100644 --- a/source/6LoWPAN/ws/ws_llc.h +++ b/source/6LoWPAN/ws/ws_llc.h @@ -78,11 +78,18 @@ typedef struct llc_neighbour_req { struct ws_neighbor_class_entry *ws_neighbor; /**< Wi-sun Neighbor information entry. */ } llc_neighbour_req_t; +typedef struct eapol_temporary_info_s { + uint8_t eapol_rx_relay_filter; /*!< seconds for dropping duplicate id */ + uint8_t last_rx_mac_sequency; /*!< Only compared when Timer is active */ + uint16_t eapol_timeout; /*!< EAPOL relay Temporary entry lifetime */ +} eapol_temporary_info_t; + /** * Neighbor temporary structure for storage FHSS data before create a real Neighbour info */ typedef struct ws_neighbor_temp_class_s { struct ws_neighbor_class_entry neigh_info_list; /*!< Allocated hopping info array*/ + eapol_temporary_info_t eapol_temp_info; uint8_t mac64[8]; uint8_t mpduLinkQuality; int8_t signal_dbm; @@ -217,6 +224,10 @@ void ws_llc_set_pan_information_pointer(struct protocol_interface_info_entry *in */ void ws_llc_hopping_schedule_config(struct protocol_interface_info_entry *interface, struct ws_hopping_schedule_s *hopping_schedule); +void ws_llc_timer_seconds(struct protocol_interface_info_entry *interface, uint16_t seconds_update); + +bool ws_llc_eapol_relay_forward_filter(struct protocol_interface_info_entry *interface, const uint8_t *joiner_eui64, uint8_t mac_sequency, uint32_t rx_timestamp); + ws_neighbor_temp_class_t *ws_llc_get_multicast_temp_entry(struct protocol_interface_info_entry *interface, const uint8_t *mac64); void ws_llc_free_multicast_temp_entry(struct protocol_interface_info_entry *interface, ws_neighbor_temp_class_t *neighbor); diff --git a/source/6LoWPAN/ws/ws_llc_data_service.c b/source/6LoWPAN/ws/ws_llc_data_service.c index adef723d0cf..73f468a27ca 100644 --- a/source/6LoWPAN/ws/ws_llc_data_service.c +++ b/source/6LoWPAN/ws/ws_llc_data_service.c @@ -36,6 +36,7 @@ #include "6LoWPAN/ws/ws_llc.h" #include "6LoWPAN/ws/ws_mpx_header.h" #include "6LoWPAN/ws/ws_pae_controller.h" +#include "6LoWPAN/ws/ws_cfg_settings.h" #include "Security/PANA/pana_eap_header.h" #include "Security/eapol/eapol_helper.h" #include "Service_Libs/etx/etx.h" @@ -78,10 +79,13 @@ typedef struct { typedef struct { uint8_t dst_address[8]; /**< Destination address */ + uint16_t pan_id; /**< Destination Pan-Id */ unsigned messsage_type: 3; /**< Frame type to UTT */ unsigned mpx_id: 5; /**< MPX sequence */ bool ack_requested: 1; /**< ACK requested */ + bool eapol_temporary: 1; /**< EAPOL TX entry index used */ unsigned dst_address_type: 2; /**< Destination address type */ + unsigned src_address_type: 2; /**< Source address type */ uint8_t msg_handle; /**< LLC genetaed unique MAC handle */ uint8_t mpx_user_handle; /**< This MPX user defined handle */ ns_ie_iovec_t ie_vector_list[3]; /**< IE vectors: 1 for Header's, 1 for Payload and for MPX payload */ @@ -95,12 +99,17 @@ typedef struct { typedef NS_LIST_HEAD(llc_message_t, link) llc_message_list_t; -#define MAX_NEIGH_TEMPORRY_MULTICAST_SIZE 5 +#define MAX_NEIGH_TEMPORARY_MULTICAST_SIZE 5 +#define MAX_NEIGH_TEMPORRY_EAPOL_SIZE 30 +#define MAX_NEIGH_TEMPORAY_LIST_SIZE (MAX_NEIGH_TEMPORARY_MULTICAST_SIZE + MAX_NEIGH_TEMPORRY_EAPOL_SIZE) typedef struct { - ws_neighbor_temp_class_t neighbour_temporary_table[MAX_NEIGH_TEMPORRY_MULTICAST_SIZE]; - ws_neighbor_temp_list_t active_temp_neigh; + ws_neighbor_temp_class_t neighbour_temporary_table[MAX_NEIGH_TEMPORAY_LIST_SIZE]; + ws_neighbor_temp_list_t active_multicast_temp_neigh; + ws_neighbor_temp_list_t active_eapol_temp_neigh; ws_neighbor_temp_list_t free_temp_neigh; + llc_message_list_t llc_eap_pending_list; /**< Active Message list */ + bool active_eapol_session: 1; /**< Indicating active EAPOL message */ } temp_entriest_t; typedef struct { @@ -131,7 +140,8 @@ static llc_message_t *llc_message_discover_by_mac_handle(uint8_t handle, llc_mes static llc_message_t *llc_message_discover_by_mpx_id(uint8_t handle, llc_message_list_t *list); static llc_message_t *llc_message_discover_mpx_user_id(uint8_t handle, uint16_t user_id, llc_message_list_t *list); static void llc_message_free(llc_message_t *message, llc_data_base_t *llc_base); -static llc_message_t *llc_message_allocate(uint16_t ie_buffer_size, llc_data_base_t *llc_base, bool mpx_user); +static void llc_message_id_allocate(llc_message_t *message, llc_data_base_t *llc_base, bool mpx_user); +static llc_message_t *llc_message_allocate(uint16_t ie_buffer_size, llc_data_base_t *llc_base); /** LLC interface sepesific local functions */ static llc_data_base_t *ws_llc_discover_by_interface(struct protocol_interface_info_entry *interface); @@ -151,6 +161,11 @@ static void ws_llc_mpx_init(mpx_class_t *mpx_class); static void ws_llc_temp_neigh_info_table_reset(temp_entriest_t *base); static ws_neighbor_temp_class_t *ws_allocate_multicast_temp_entry(temp_entriest_t *base, const uint8_t *mac64); +static ws_neighbor_temp_class_t *ws_llc_discover_eapol_temp_entry(temp_entriest_t *base, const uint8_t *mac64); +static void ws_llc_release_eapol_temp_entry(temp_entriest_t *base, const uint8_t *mac64); +static ws_neighbor_temp_class_t *ws_allocate_eapol_temp_entry(temp_entriest_t *base, const uint8_t *mac64); + +static void ws_llc_mpx_eapol_send(llc_data_base_t *base, llc_message_t *message); /** Discover Message by message handle id */ static llc_message_t *llc_message_discover_by_mac_handle(uint8_t handle, llc_message_list_t *list) @@ -202,18 +217,8 @@ static void llc_message_free(llc_message_t *message, llc_data_base_t *llc_base) llc_base->llc_message_list_size--; } -static llc_message_t *llc_message_allocate(uint16_t ie_buffer_size, llc_data_base_t *llc_base, bool mpx_user) +static void llc_message_id_allocate(llc_message_t *message, llc_data_base_t *llc_base, bool mpx_user) { - if (llc_base->llc_message_list_size >= LLC_MESSAGE_QUEUE_LIST_SIZE_MAX) { - return NULL; - } - - llc_message_t *message = ns_dyn_mem_temporary_alloc(sizeof(llc_message_t) + ie_buffer_size); - if (!message) { - return NULL; - } - message->ack_requested = false; - //Guarantee while (1) { if (llc_message_discover_by_mac_handle(llc_base->mac_handle_base, &llc_base->llc_message_list)) { @@ -237,8 +242,20 @@ static llc_message_t *llc_message_allocate(uint16_t ie_buffer_size, llc_data_bas if (mpx_user) { message->mpx_id = llc_base->mpx_data_base.mpx_id++; } - llc_base->llc_message_list_size++; - ns_list_add_to_end(&llc_base->llc_message_list, message); +} + +static llc_message_t *llc_message_allocate(uint16_t ie_buffer_size, llc_data_base_t *llc_base) +{ + if (llc_base->llc_message_list_size >= LLC_MESSAGE_QUEUE_LIST_SIZE_MAX) { + return NULL; + } + + llc_message_t *message = ns_dyn_mem_temporary_alloc(sizeof(llc_message_t) + ie_buffer_size); + if (!message) { + return NULL; + } + message->ack_requested = false; + message->eapol_temporary = false; return message; } @@ -375,12 +392,14 @@ static llc_data_base_t *ws_llc_base_allocate(void) } memset(base, 0, sizeof(llc_data_base_t)); memset(temp_entries, 0, sizeof(temp_entriest_t)); - ns_list_init(&temp_entries->active_temp_neigh); + ns_list_init(&temp_entries->active_multicast_temp_neigh); + ns_list_init(&temp_entries->active_eapol_temp_neigh); ns_list_init(&temp_entries->free_temp_neigh); - + ns_list_init(&temp_entries->llc_eap_pending_list); base->temp_entries = temp_entries; ns_list_init(&base->llc_message_list); + ns_list_add_to_end(&llc_data_base_list, base); return base; } @@ -403,6 +422,19 @@ static void ws_llc_mac_confirm_cb(const mac_api_t *api, const mcps_data_conf_t * uint8_t messsage_type = message->messsage_type; uint8_t mpx_user_handle = message->mpx_user_handle; + if (message->eapol_temporary) { + //Clear + ws_bootstrap_eapol_tx_temporary_clear(interface); + + if (data->status == MLME_SUCCESS || data->status == MLME_NO_DATA) { + //Update timeout + ws_neighbor_temp_class_t *temp_entry = ws_llc_discover_eapol_temp_entry(base->temp_entries, message->dst_address); + if (temp_entry) { + //Update Temporary Lifetime + temp_entry->eapol_temp_info.eapol_timeout = interface->ws_info->cfg->timing.temp_eapol_min_timeout + 1; + } + } + } //ETX update if (message->ack_requested && messsage_type == WS_FT_DATA) { llc_neighbour_req_t neighbor_info; @@ -417,7 +449,7 @@ static void ws_llc_mac_confirm_cb(const mac_api_t *api, const mcps_data_conf_t * } if (message->dst_address_type == MAC_ADDR_MODE_64_BIT && base->ws_neighbor_info_request_cb(interface, message->dst_address, &neighbor_info, false)) { - etx_transm_attempts_update(interface->id, 1 + data->tx_retries, success, neighbor_info.neighbor->index); + etx_transm_attempts_update(interface->id, 1 + data->tx_retries, success, neighbor_info.neighbor->index, neighbor_info.neighbor->mac64); //TODO discover RSL from Enchanced ACK Header IE elements ws_utt_ie_t ws_utt; if (ws_wh_utt_read(conf_data->headerIeList, conf_data->headerIeListLength, &ws_utt)) { @@ -450,6 +482,7 @@ static void ws_llc_mac_confirm_cb(const mac_api_t *api, const mcps_data_conf_t * mpx_user_id = MPX_LOWPAN_ENC_USER_ID; } else { mpx_user_id = MPX_KEY_MANAGEMENT_ENC_USER_ID; + base->temp_entries->active_eapol_session = false; } user_cb = ws_llc_mpx_user_discover(&base->mpx_data_base, mpx_user_id); @@ -459,6 +492,16 @@ static void ws_llc_mac_confirm_cb(const mac_api_t *api, const mcps_data_conf_t * data_conf.msduHandle = mpx_user_handle; user_cb->data_confirm(&base->mpx_data_base.mpx_api, &data_conf); } + + if (messsage_type == WS_FT_EAPOL) { + message = ns_list_get_first(&base->temp_entries->llc_eap_pending_list); + if (message) { + //Start A pending EAPOL + ns_list_remove(&base->temp_entries->llc_eap_pending_list, message); + ws_llc_mpx_eapol_send(base, message); + } + } + return; } //Async message Confirmation @@ -487,181 +530,320 @@ static void ws_llc_ack_data_req_ext(const mac_api_t *api, mcps_ack_data_payload_ ws_wh_rsl_write(ptr, ws_neighbor_class_rsl_from_dbm_calculate(rssi)); } -/** WS LLC MAC data extension indication */ -static void ws_llc_mac_indication_cb(const mac_api_t *api, const mcps_data_ind_t *data, const mcps_data_ie_list_t *ie_ext) + +static llc_data_base_t *ws_llc_mpx_frame_common_validates(const mac_api_t *api, const mcps_data_ind_t *data, ws_utt_ie_t ws_utt) { llc_data_base_t *base = ws_llc_discover_by_mac(api); + if (!base) { + return NULL; + } + + if (!base->ie_params.gtkhash && ws_utt.message_type == WS_FT_DATA) { + return NULL; + } + + if (data->SrcAddrMode != ADDR_802_15_4_LONG) { + return NULL; + } + + protocol_interface_info_entry_t *interface = base->interface_ptr; + + if (interface->mac_parameters->pan_id != 0xffff && data->SrcPANId != interface->mac_parameters->pan_id) { + //Drop wrong PAN-id messages in this phase. + return NULL; + } + + return base; + +} + +static mpx_user_t *ws_llc_mpx_header_parse(llc_data_base_t *base, const mcps_data_ie_list_t *ie_ext, mpx_msg_t *mpx_frame, mac_payload_IE_t *mpx_ie) +{ + + mpx_ie->id = MAC_PAYLOAD_MPX_IE_GROUP_ID; + if (mac_ie_payload_discover(ie_ext->payloadIeList, ie_ext->payloadIeListLength, mpx_ie) < 1) { + // NO MPX + return NULL; + } + //Validate MPX header + if (!ws_llc_mpx_header_frame_parse(mpx_ie->content_ptr, mpx_ie->length, mpx_frame)) { + return NULL; + } + + if (mpx_frame->transfer_type != MPX_FT_FULL_FRAME) { + return NULL; //Support only FULL Frame's + } + + // Discover MPX handler + mpx_user_t *user_cb = ws_llc_mpx_user_discover(&base->mpx_data_base, mpx_frame->multiplex_id); + if (!user_cb || !user_cb->data_ind) { + return NULL; + } + + return user_cb; +} + + +static void ws_llc_data_indication_cb(const mac_api_t *api, const mcps_data_ind_t *data, const mcps_data_ie_list_t *ie_ext, ws_utt_ie_t ws_utt) +{ + llc_data_base_t *base = ws_llc_mpx_frame_common_validates(api, data, ws_utt); if (!base) { return; } - //Discover Header WH_IE_UTT_TYPE - ws_utt_ie_t ws_utt; - if (!ws_wh_utt_read(ie_ext->headerIeList, ie_ext->headerIeListLength, &ws_utt)) { - // NO UTT header + //Discover MPX header and handler + mac_payload_IE_t mpx_ie; + mpx_msg_t mpx_frame; + mpx_user_t *user_cb = ws_llc_mpx_header_parse(base, ie_ext, &mpx_frame, &mpx_ie); + if (!user_cb) { return; } + mac_payload_IE_t ws_wp_nested; + ws_us_ie_t us_ie; + bool us_ie_inline = false; + bool bs_ie_inline = false; + ws_wp_nested.id = WS_WP_NESTED_IE; + ws_bs_ie_t ws_bs_ie; + if (mac_ie_payload_discover(ie_ext->payloadIeList, ie_ext->payloadIeListLength, &ws_wp_nested) > 2) { + us_ie_inline = ws_wp_nested_us_read(ws_wp_nested.content_ptr, ws_wp_nested.length, &us_ie); + bs_ie_inline = ws_wp_nested_bs_read(ws_wp_nested.content_ptr, ws_wp_nested.length, &ws_bs_ie); + } + protocol_interface_info_entry_t *interface = base->interface_ptr; - if (!base->ie_params.gtkhash && ws_utt.message_type == WS_FT_DATA) { + + //Validate Unicast shedule Channel Plan + if (us_ie_inline && !ws_bootstrap_validate_channel_plan(&us_ie, interface)) { + //Channel plan configuration mismatch return; } - //Discover 2 Payload Heder - if (ws_utt.message_type == WS_FT_DATA || ws_utt.message_type == WS_FT_EAPOL) { + //Free Old temporary entry + if (data->Key.SecurityLevel) { + ws_llc_release_eapol_temp_entry(base->temp_entries, data->SrcAddr); + } - if (data->SrcAddrMode != ADDR_802_15_4_LONG) { - return; - } + llc_neighbour_req_t neighbor_info; + bool multicast; + bool request_new_entry; + if (data->DstAddrMode == ADDR_802_15_4_LONG) { + multicast = false; + request_new_entry = us_ie_inline; + } else { + multicast = true; + request_new_entry = false; + } - if (interface->mac_parameters->pan_id != 0xffff && data->SrcPANId != interface->mac_parameters->pan_id) { - //Drop wrong PAN-id messages in this phase. + if (!base->ws_neighbor_info_request_cb(interface, data->SrcAddr, &neighbor_info, request_new_entry)) { + if (!multicast) { + //tr_debug("Drop message no neighbor"); return; + } else { + //Allocate temporary entry + ws_neighbor_temp_class_t *temp_entry = ws_allocate_multicast_temp_entry(base->temp_entries, data->SrcAddr); + neighbor_info.ws_neighbor = &temp_entry->neigh_info_list; + //Storage Signal info for future ETX update possibility + temp_entry->mpduLinkQuality = data->mpduLinkQuality; + temp_entry->signal_dbm = data->signal_dbm; } + } - mpx_user_t *user_cb; - mac_payload_IE_t mpx_ie; - mpx_ie.id = MAC_PAYLOAD_MPX_IE_GROUP_ID; - if (mac_ie_payload_discover(ie_ext->payloadIeList, ie_ext->payloadIeListLength, &mpx_ie) < 1) { - // NO MPX - return; - } - //Validate MPX header - mpx_msg_t mpx_frame; - if (!ws_llc_mpx_header_frame_parse(mpx_ie.content_ptr, mpx_ie.length, &mpx_frame)) { - return; - } + if (!multicast && !ws_neighbor_class_neighbor_duplicate_packet_check(neighbor_info.ws_neighbor, data->DSN, data->timestamp)) { + tr_info("Drop duplicate message"); + return; + } - if (mpx_frame.transfer_type != MPX_FT_FULL_FRAME) { - return; //Support only FULL Frame's - } + ws_neighbor_class_neighbor_unicast_time_info_update(neighbor_info.ws_neighbor, &ws_utt, data->timestamp); + if (us_ie_inline) { + ws_neighbor_class_neighbor_unicast_schedule_set(neighbor_info.ws_neighbor, &us_ie); + } + //Update BS if it is part of message + if (bs_ie_inline) { + ws_neighbor_class_neighbor_broadcast_schedule_set(neighbor_info.ws_neighbor, &ws_bs_ie); + } - mac_payload_IE_t ws_wp_nested; - ws_us_ie_t us_ie; - bool us_ie_inline = false; - bool bs_ie_inline = false; - ws_wp_nested.id = WS_WP_NESTED_IE; - ws_bs_ie_t ws_bs_ie; - if (mac_ie_payload_discover(ie_ext->payloadIeList, ie_ext->payloadIeListLength, &ws_wp_nested) > 2) { - us_ie_inline = ws_wp_nested_us_read(ws_wp_nested.content_ptr, ws_wp_nested.length, &us_ie); - bs_ie_inline = ws_wp_nested_bs_read(ws_wp_nested.content_ptr, ws_wp_nested.length, &ws_bs_ie); + //Update BT if it is part of message + ws_bt_ie_t ws_bt; + if (ws_wh_bt_read(ie_ext->headerIeList, ie_ext->headerIeListLength, &ws_bt)) { + ws_neighbor_class_neighbor_broadcast_time_info_update(neighbor_info.ws_neighbor, &ws_bt, data->timestamp); + if (neighbor_info.neighbor && neighbor_info.neighbor->link_role == PRIORITY_PARENT_NEIGHBOUR) { + ns_fhss_ws_set_parent(interface->ws_info->fhss_api, neighbor_info.neighbor->mac64, &neighbor_info.ws_neighbor->fhss_data.bc_timing_info, false); } + } - //Validate Unicast shedule Channel Plan - if (us_ie_inline && !ws_bootstrap_validate_channel_plan(&us_ie, interface)) { - //Channel plan configuration mismatch - return; - } + if (data->DstAddrMode == ADDR_802_15_4_LONG) { + neighbor_info.ws_neighbor->unicast_data_rx = true; + } - llc_neighbour_req_t neighbor_info; - bool multicast; - bool request_new_entry; - if (data->DstAddrMode == ADDR_802_15_4_LONG) { - multicast = false; - request_new_entry = us_ie_inline; - } else { - multicast = true; - request_new_entry = false; - } + // Calculate RSL for all UDATA packages heard + ws_neighbor_class_rsl_in_calculate(neighbor_info.ws_neighbor, data->signal_dbm); - if (!base->ws_neighbor_info_request_cb(interface, data->SrcAddr, &neighbor_info, request_new_entry)) { - if (!multicast || ws_utt.message_type == WS_FT_EAPOL) { - //tr_debug("Drop message no neighbor"); - return; - } else { - //Allocate temporary entry - ws_neighbor_temp_class_t *temp_entry = ws_allocate_multicast_temp_entry(base->temp_entries, data->SrcAddr); - neighbor_info.ws_neighbor = &temp_entry->neigh_info_list; - //Storage Signal info for future ETX update possibility - temp_entry->mpduLinkQuality = data->mpduLinkQuality; - temp_entry->signal_dbm = data->signal_dbm; - } + if (neighbor_info.neighbor) { + //Refresh ETX dbm + etx_lqi_dbm_update(interface->id, data->mpduLinkQuality, data->signal_dbm, neighbor_info.neighbor->index, neighbor_info.neighbor->mac64); + if (data->Key.SecurityLevel) { + //SET trusted state + mac_neighbor_table_trusted_neighbor(mac_neighbor_info(interface), neighbor_info.neighbor, true); } + } - ws_neighbor_class_neighbor_unicast_time_info_update(neighbor_info.ws_neighbor, &ws_utt, data->timestamp); - if (us_ie_inline) { - ws_neighbor_class_neighbor_unicast_schedule_set(neighbor_info.ws_neighbor, &us_ie); - } - //Update BS if it is part of message - if (bs_ie_inline) { - ws_neighbor_class_neighbor_broadcast_schedule_set(neighbor_info.ws_neighbor, &ws_bs_ie); - } + mcps_data_ind_t data_ind = *data; + if (!neighbor_info.neighbor) { + data_ind.Key.SecurityLevel = 0; //Mark unknow device + } + data_ind.msdu_ptr = mpx_frame.frame_ptr; + data_ind.msduLength = mpx_frame.frame_length; + user_cb->data_ind(&base->mpx_data_base.mpx_api, &data_ind); - if (ws_utt.message_type == WS_FT_EAPOL) { - uint8_t auth_eui64[8]; - //Discover and write Auhtenticator EUI-64 - if (ws_wh_ea_read(ie_ext->headerIeList, ie_ext->headerIeListLength, auth_eui64)) { - ws_pae_controller_border_router_addr_write(base->interface_ptr, auth_eui64); - } - } +} +static void ws_llc_eapol_indication_cb(const mac_api_t *api, const mcps_data_ind_t *data, const mcps_data_ie_list_t *ie_ext, ws_utt_ie_t ws_utt) +{ + llc_data_base_t *base = ws_llc_mpx_frame_common_validates(api, data, ws_utt); + if (!base) { + return; + } - //Update BT if it is part of message - ws_bt_ie_t ws_bt; - if (ws_wh_bt_read(ie_ext->headerIeList, ie_ext->headerIeListLength, &ws_bt)) { - ws_neighbor_class_neighbor_broadcast_time_info_update(neighbor_info.ws_neighbor, &ws_bt, data->timestamp); - if (neighbor_info.neighbor) { - if (neighbor_info.neighbor->link_role == PRIORITY_PARENT_NEIGHBOUR) { - // We have broadcast schedule set up set the broadcast parent schedule - ns_fhss_ws_set_parent(interface->ws_info->fhss_api, neighbor_info.neighbor->mac64, &neighbor_info.ws_neighbor->fhss_data.bc_timing_info, false); - } else if (ws_utt.message_type == WS_FT_EAPOL) { - ws_bootstrap_eapol_parent_synch(interface, &neighbor_info); - } - } - } + if (data->DstAddrMode != ADDR_802_15_4_LONG) { + return; + } - if (ws_utt.message_type == WS_FT_DATA) { + //Discover MPX header and handler + mac_payload_IE_t mpx_ie; + mpx_msg_t mpx_frame; + mpx_user_t *user_cb = ws_llc_mpx_header_parse(base, ie_ext, &mpx_frame, &mpx_ie); + if (!user_cb) { + return; + } - if (data->DstAddrMode == ADDR_802_15_4_LONG) { - neighbor_info.ws_neighbor->unicast_data_rx = true; - } + mac_payload_IE_t ws_wp_nested; + ws_us_ie_t us_ie; + bool us_ie_inline = false; + bool bs_ie_inline = false; + ws_wp_nested.id = WS_WP_NESTED_IE; + ws_bs_ie_t ws_bs_ie; + if (mac_ie_payload_discover(ie_ext->payloadIeList, ie_ext->payloadIeListLength, &ws_wp_nested) > 2) { + us_ie_inline = ws_wp_nested_us_read(ws_wp_nested.content_ptr, ws_wp_nested.length, &us_ie); + bs_ie_inline = ws_wp_nested_bs_read(ws_wp_nested.content_ptr, ws_wp_nested.length, &ws_bs_ie); + } - // Calculate RSL for all UDATA packages heard - ws_neighbor_class_rsl_in_calculate(neighbor_info.ws_neighbor, data->signal_dbm); + protocol_interface_info_entry_t *interface = base->interface_ptr; - if (neighbor_info.neighbor) { - //Refresh ETX dbm - etx_lqi_dbm_update(interface->id, data->mpduLinkQuality, data->signal_dbm, neighbor_info.neighbor->index); - if (data->Key.SecurityLevel) { - //SET trusted state - mac_neighbor_table_trusted_neighbor(mac_neighbor_info(interface), neighbor_info.neighbor, true); - } - } + //Validate Unicast shedule Channel Plan + if (us_ie_inline && !ws_bootstrap_validate_channel_plan(&us_ie, interface)) { + //Channel plan configuration mismatch + return; + } + + llc_neighbour_req_t neighbor_info; + + if (!base->ws_neighbor_info_request_cb(interface, data->SrcAddr, &neighbor_info, false)) { + //Allocate temporary entry + ws_neighbor_temp_class_t *temp_entry = ws_allocate_eapol_temp_entry(base->temp_entries, data->SrcAddr); + if (!temp_entry) { + tr_warn("EAPOL temp pool empty"); + return; } + //Update Temporary Lifetime + temp_entry->eapol_temp_info.eapol_timeout = interface->ws_info->cfg->timing.temp_eapol_min_timeout + 1; + neighbor_info.ws_neighbor = &temp_entry->neigh_info_list; + //Storage Signal info for future ETX update possibility + temp_entry->mpduLinkQuality = data->mpduLinkQuality; + temp_entry->signal_dbm = data->signal_dbm; + } + uint8_t auth_eui64[8]; + ws_neighbor_class_neighbor_unicast_time_info_update(neighbor_info.ws_neighbor, &ws_utt, data->timestamp); + if (us_ie_inline) { + ws_neighbor_class_neighbor_unicast_schedule_set(neighbor_info.ws_neighbor, &us_ie); + } + //Update BS if it is part of message + if (bs_ie_inline) { + ws_neighbor_class_neighbor_broadcast_schedule_set(neighbor_info.ws_neighbor, &ws_bs_ie); + } - // Discover MPX - user_cb = ws_llc_mpx_user_discover(&base->mpx_data_base, mpx_frame.multiplex_id); - if (user_cb && user_cb->data_ind) { - mcps_data_ind_t data_ind = *data; - if (!neighbor_info.neighbor) { - data_ind.Key.SecurityLevel = 0; //Mark unknow device - } - data_ind.msdu_ptr = mpx_frame.frame_ptr; - data_ind.msduLength = mpx_frame.frame_length; - user_cb->data_ind(&base->mpx_data_base.mpx_api, &data_ind); + //Discover and write Auhtenticator EUI-64 + if (ws_wh_ea_read(ie_ext->headerIeList, ie_ext->headerIeListLength, auth_eui64)) { + ws_pae_controller_border_router_addr_write(base->interface_ptr, auth_eui64); + } + + //Update BT if it is part of message + ws_bt_ie_t ws_bt; + if (ws_wh_bt_read(ie_ext->headerIeList, ie_ext->headerIeListLength, &ws_bt)) { + ws_neighbor_class_neighbor_broadcast_time_info_update(neighbor_info.ws_neighbor, &ws_bt, data->timestamp); + if (neighbor_info.neighbor) { + ws_bootstrap_eapol_parent_synch(interface, &neighbor_info); } + } + + + mcps_data_ind_t data_ind = *data; + data_ind.msdu_ptr = mpx_frame.frame_ptr; + data_ind.msduLength = mpx_frame.frame_length; + user_cb->data_ind(&base->mpx_data_base.mpx_api, &data_ind); +} + +static void ws_llc_asynch_indication(const mac_api_t *api, const mcps_data_ind_t *data, const mcps_data_ie_list_t *ie_ext, ws_utt_ie_t ws_utt) +{ + llc_data_base_t *base = ws_llc_discover_by_mac(api); + if (!base || !base->asynch_ind) { return; } //Asynch Message - if (ws_utt.message_type < WS_FT_DATA && base->asynch_ind) { - mac_payload_IE_t ws_wp_nested; - ws_wp_nested.id = WS_WP_NESTED_IE; - if (mac_ie_payload_discover(ie_ext->payloadIeList, ie_ext->payloadIeListLength, &ws_wp_nested) < 2) { - // NO WS_WP_NESTED_IE Payload - return; - } + mac_payload_IE_t ws_wp_nested; + + ws_wp_nested.id = WS_WP_NESTED_IE; + if (mac_ie_payload_discover(ie_ext->payloadIeList, ie_ext->payloadIeListLength, &ws_wp_nested) < 2) { + // NO WS_WP_NESTED_IE Payload + return; + } + + switch (ws_utt.message_type) { + case WS_FT_PAN_ADVERT: + case WS_FT_PAN_CONF: + case WS_FT_PAN_CONF_SOL: + ws_llc_release_eapol_temp_entry(base->temp_entries, data->SrcAddr); + break; + default: + break; + } + + mcps_data_ie_list_t asynch_ie_list; + asynch_ie_list.headerIeList = ie_ext->headerIeList, + asynch_ie_list.headerIeListLength = ie_ext->headerIeListLength; + asynch_ie_list.payloadIeList = ws_wp_nested.content_ptr; + asynch_ie_list.payloadIeListLength = ws_wp_nested.length; + base->asynch_ind(base->interface_ptr, data, &asynch_ie_list, ws_utt.message_type); +} + +/** WS LLC MAC data extension indication */ +static void ws_llc_mac_indication_cb(const mac_api_t *api, const mcps_data_ind_t *data, const mcps_data_ie_list_t *ie_ext) +{ + + + //Discover Header WH_IE_UTT_TYPE + ws_utt_ie_t ws_utt; + if (!ws_wh_utt_read(ie_ext->headerIeList, ie_ext->headerIeListLength, &ws_utt)) { + // NO UTT header + return; + } - mcps_data_ie_list_t asynch_ie_list; - asynch_ie_list.headerIeList = ie_ext->headerIeList, - asynch_ie_list.headerIeListLength = ie_ext->headerIeListLength; - asynch_ie_list.payloadIeList = ws_wp_nested.content_ptr; - asynch_ie_list.payloadIeListLength = ws_wp_nested.length; - base->asynch_ind(interface, data, &asynch_ie_list, ws_utt.message_type); + if (ws_utt.message_type < WS_FT_DATA) { + ws_llc_asynch_indication(api, data, ie_ext, ws_utt); + return; } + if (ws_utt.message_type == WS_FT_DATA) { + ws_llc_data_indication_cb(api, data, ie_ext, ws_utt); + return; + } + + if (ws_utt.message_type == WS_FT_EAPOL) { + ws_llc_eapol_indication_cb(api, data, ie_ext, ws_utt); + return; + } } static uint16_t ws_mpx_header_size_get(llc_data_base_t *base, uint16_t user_id) @@ -720,18 +902,21 @@ static bool ws_eapol_handshake_first_msg(uint8_t *pdu, uint16_t length, protocol return false; } -static void ws_llc_mpx_data_request(const mpx_api_t *api, const struct mcps_data_req_s *data, uint16_t user_id) +static void ws_llc_lowpan_mpx_header_set(llc_message_t *message, uint16_t user_id) { - llc_data_base_t *base = ws_llc_discover_by_mpx(api); - if (!base) { - return; - } - - mpx_user_t *user_cb = ws_llc_mpx_user_discover(&base->mpx_data_base, user_id); - if (!user_cb || !user_cb->data_confirm || !user_cb->data_ind) { - return; - } + uint8_t *ptr = (uint8_t *)message->ie_vector_list[1].ieBase; + ptr += message->ie_vector_list[1].iovLen; + ptr = mac_ie_payload_base_write(ptr, MAC_PAYLOAD_MPX_IE_GROUP_ID, message->ie_vector_list[2].iovLen + 3); + mpx_msg_t mpx_header; + mpx_header.transfer_type = MPX_FT_FULL_FRAME; + mpx_header.transaction_id = message->mpx_id; + mpx_header.multiplex_id = user_id; + ptr = ws_llc_mpx_header_write(ptr, &mpx_header); + message->ie_vector_list[1].iovLen = ptr - (uint8_t *)message->ie_vector_list[1].ieBase; +} +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) +{ wh_ie_sub_list_t ie_header_mask; memset(&ie_header_mask, 0, sizeof(wh_ie_sub_list_t)); @@ -739,25 +924,17 @@ static void ws_llc_mpx_data_request(const mpx_api_t *api, const struct mcps_data memset(&nested_wp_id, 0, sizeof(wp_nested_ie_sub_list_t)); ie_header_mask.utt_ie = true; - if (user_id == MPX_LOWPAN_ENC_USER_ID) { - ie_header_mask.bt_ie = true; - if (base->ie_params.vendor_header_length) { - ie_header_mask.vh_ie = true; - } - - if (base->ie_params.vendor_payload_length) { - nested_wp_id.vp_ie = true; - } - - if (!data->TxAckReq) { - nested_wp_id.bs_ie = true; - } + ie_header_mask.bt_ie = true; + if (base->ie_params.vendor_header_length) { + ie_header_mask.vh_ie = true; + } - } else if (user_id == MPX_KEY_MANAGEMENT_ENC_USER_ID) { - ie_header_mask.bt_ie = ws_eapol_relay_state_active(base->interface_ptr); - ie_header_mask.ea_ie = ws_eapol_handshake_first_msg(data->msdu, data->msduLength, base->interface_ptr); - nested_wp_id.bs_ie = ie_header_mask.ea_ie; + if (base->ie_params.vendor_payload_length) { + nested_wp_id.vp_ie = true; + } + if (!data->TxAckReq) { + nested_wp_id.bs_ie = true; } nested_wp_id.us_ie = true; @@ -773,7 +950,7 @@ static void ws_llc_mpx_data_request(const mpx_api_t *api, const struct mcps_data over_head_size += 5; //MPX FuLL frame 3 bytes + IE header 2 bytes //Allocate Message - llc_message_t *message = llc_message_allocate(over_head_size, base, true); + llc_message_t *message = llc_message_allocate(over_head_size, base); if (!message) { mcps_data_conf_t data_conf; memset(&data_conf, 0, sizeof(mcps_data_conf_t)); @@ -782,6 +959,12 @@ static void ws_llc_mpx_data_request(const mpx_api_t *api, const struct mcps_data user_cb->data_confirm(&base->mpx_data_base.mpx_api, &data_conf); return; } + + //Add To active list + llc_message_id_allocate(message, base, true); + base->llc_message_list_size++; + ns_list_add_to_end(&base->llc_message_list, message); + mcps_data_req_t data_req; message->mpx_user_handle = data->msduHandle; message->ack_requested = data->TxAckReq; @@ -802,11 +985,7 @@ static void ws_llc_mpx_data_request(const mpx_api_t *api, const struct mcps_data } uint8_t *ptr = ws_message_buffer_ptr_get(message); - if (user_id == MPX_LOWPAN_ENC_USER_ID) { - message->messsage_type = WS_FT_DATA; - } else { - message->messsage_type = WS_FT_EAPOL; - } + message->messsage_type = WS_FT_DATA; message->ie_vector_list[0].ieBase = ptr; //Write UTT @@ -816,19 +995,149 @@ static void ws_llc_mpx_data_request(const mpx_api_t *api, const struct mcps_data ptr = ws_wh_bt_write(ptr); } - if (user_id == MPX_LOWPAN_ENC_USER_ID) { - if (ie_header_mask.vh_ie) { - ptr = ws_wh_vh_write(ptr, base->ie_params.vendor_header_data, base->ie_params.vendor_header_length); - } - } else if (user_id == MPX_KEY_MANAGEMENT_ENC_USER_ID) { - if (ie_header_mask.ea_ie) { - uint8_t eapol_auth_eui64[8]; - ws_pae_controller_border_router_addr_read(base->interface_ptr, eapol_auth_eui64); - ptr = ws_wh_ea_write(ptr, eapol_auth_eui64); + if (ie_header_mask.vh_ie) { + ptr = ws_wh_vh_write(ptr, base->ie_params.vendor_header_data, base->ie_params.vendor_header_length); + } + + message->ie_vector_list[0].iovLen = ie_header_length; + message->ie_ext.headerIeVectorList = &message->ie_vector_list[0]; + message->ie_ext.headerIovLength = 1; + message->ie_ext.payloadIeVectorList = &message->ie_vector_list[1]; + message->ie_ext.payloadIovLength = 2; + message->ie_vector_list[1].ieBase = ptr; + + if (nested_ie_length) { + ptr = ws_wp_base_write(ptr, nested_ie_length); + //Write unicast schedule + ptr = ws_wp_nested_hopping_schedule_write(ptr, base->ie_params.hopping_schedule, true); + + if (nested_wp_id.bs_ie) { + //Write Broadcastcast schedule + ptr = ws_wp_nested_hopping_schedule_write(ptr, base->ie_params.hopping_schedule, false); } } + // SET Payload IE Length + message->ie_vector_list[1].iovLen = ptr - (uint8_t *)message->ie_vector_list[1].ieBase; + message->ie_vector_list[2].ieBase = data->msdu; + message->ie_vector_list[2].iovLen = data->msduLength; + + ws_llc_lowpan_mpx_header_set(message, MPX_LOWPAN_ENC_USER_ID); + + base->interface_ptr->mac_api->mcps_data_req_ext(base->interface_ptr->mac_api, &data_req, &message->ie_ext, NULL); +} + +static bool ws_llc_eapol_temp_entry_set(llc_data_base_t *base, const uint8_t *mac64) +{ + //Discover Temporary entry + ws_neighbor_temp_class_t *temp_neigh = ws_llc_discover_eapol_temp_entry(base->temp_entries, mac64); + + if (!temp_neigh) { + return false; + } + ws_neighbor_class_entry_t *entry = ws_bootstrap_eapol_tx_temporary_set(base->interface_ptr, mac64); + if (!entry) { + return false; + } + *entry = temp_neigh->neigh_info_list; + return true; + +} + + +static void ws_llc_eapol_data_req_init(mcps_data_req_t *data_req, llc_message_t *message) +{ + memset(data_req, 0, sizeof(mcps_data_req_t)); + data_req->TxAckReq = message->ack_requested; + data_req->DstPANId = message->pan_id; + data_req->SrcAddrMode = message->src_address_type; + if (!data_req->TxAckReq) { + data_req->PanIdSuppressed = false; + data_req->DstAddrMode = MAC_ADDR_MODE_NONE; + } else { + data_req->PanIdSuppressed = true; + data_req->DstAddrMode = message->dst_address_type; + memcpy(data_req->DstAddr, message->dst_address, 8); + } + + + data_req->msdu = NULL; + data_req->msduLength = 0; + data_req->msduHandle = message->msg_handle; + + ws_llc_lowpan_mpx_header_set(message, MPX_KEY_MANAGEMENT_ENC_USER_ID); +} + +static void ws_llc_mpx_eapol_send(llc_data_base_t *base, llc_message_t *message) +{ + mcps_data_req_t data_req; + llc_message_id_allocate(message, base, true); + base->llc_message_list_size++; + ns_list_add_to_end(&base->llc_message_list, message); + message->eapol_temporary = ws_llc_eapol_temp_entry_set(base, message->dst_address); + 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); +} + + +static void ws_llc_mpx_eapol_request(llc_data_base_t *base, mpx_user_t *user_cb, const struct mcps_data_req_s *data) +{ + wh_ie_sub_list_t ie_header_mask; + memset(&ie_header_mask, 0, sizeof(wh_ie_sub_list_t)); + + wp_nested_ie_sub_list_t nested_wp_id; + memset(&nested_wp_id, 0, sizeof(wp_nested_ie_sub_list_t)); + ie_header_mask.utt_ie = true; + ie_header_mask.bt_ie = ws_eapol_relay_state_active(base->interface_ptr); + ie_header_mask.ea_ie = ws_eapol_handshake_first_msg(data->msdu, data->msduLength, base->interface_ptr); + nested_wp_id.bs_ie = ie_header_mask.ea_ie; + + + 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 over_head_size = ie_header_length; + if (nested_ie_length) { + over_head_size += nested_ie_length + 2; + } + //Mpx header size + over_head_size += 5; //MPX FuLL frame 3 bytes + IE header 2 bytes + //Allocate Message + llc_message_t *message = llc_message_allocate(over_head_size, base); + if (!message) { + mcps_data_conf_t data_conf; + memset(&data_conf, 0, sizeof(mcps_data_conf_t)); + data_conf.msduHandle = data->msduHandle; + data_conf.status = MLME_TRANSACTION_OVERFLOW; + user_cb->data_confirm(&base->mpx_data_base.mpx_api, &data_conf); + return; + } + message->mpx_user_handle = data->msduHandle; + message->ack_requested = data->TxAckReq; + + message->src_address_type = data->SrcAddrMode; + memcpy(message->dst_address, data->DstAddr, 8); + message->dst_address_type = data->DstAddrMode; + message->pan_id = data->DstPANId; + message->messsage_type = WS_FT_EAPOL; + uint8_t *ptr = ws_message_buffer_ptr_get(message); + + message->ie_vector_list[0].ieBase = ptr; + //Write UTT + ptr = ws_wh_utt_write(ptr, message->messsage_type); + if (ie_header_mask.bt_ie) { + ptr = ws_wh_bt_write(ptr); + } + + if (ie_header_mask.ea_ie) { + uint8_t eapol_auth_eui64[8]; + ws_pae_controller_border_router_addr_read(base->interface_ptr, eapol_auth_eui64); + ptr = ws_wh_ea_write(ptr, eapol_auth_eui64); + } message->ie_vector_list[0].iovLen = ie_header_length; message->ie_ext.headerIeVectorList = &message->ie_vector_list[0]; @@ -848,18 +1157,38 @@ static void ws_llc_mpx_data_request(const mpx_api_t *api, const struct mcps_data } } - - ptr = mac_ie_payload_base_write(ptr, MAC_PAYLOAD_MPX_IE_GROUP_ID, data->msduLength + 3); - mpx_msg_t mpx_header; - mpx_header.transfer_type = MPX_FT_FULL_FRAME; - mpx_header.transaction_id = message->mpx_id; - mpx_header.multiplex_id = user_id; - ptr = ws_llc_mpx_header_write(ptr, &mpx_header); + // SET Payload IE Length message->ie_vector_list[1].iovLen = ptr - (uint8_t *)message->ie_vector_list[1].ieBase; message->ie_vector_list[2].ieBase = data->msdu; message->ie_vector_list[2].iovLen = data->msduLength; - base->interface_ptr->mac_api->mcps_data_req_ext(base->interface_ptr->mac_api, &data_req, &message->ie_ext, NULL); + if (base->temp_entries->active_eapol_session) { + //Move to pending list + ns_list_add_to_end(&base->temp_entries->llc_eap_pending_list, message); + } else { + ws_llc_mpx_eapol_send(base, message); + } + +} + + +static void ws_llc_mpx_data_request(const mpx_api_t *api, const struct mcps_data_req_s *data, uint16_t user_id) +{ + llc_data_base_t *base = ws_llc_discover_by_mpx(api); + if (!base) { + return; + } + + mpx_user_t *user_cb = ws_llc_mpx_user_discover(&base->mpx_data_base, user_id); + if (!user_cb || !user_cb->data_confirm || !user_cb->data_ind) { + return; + } + + if (user_id == MPX_KEY_MANAGEMENT_ENC_USER_ID) { + ws_llc_mpx_eapol_request(base, user_cb, data); + } else if (user_id == MPX_LOWPAN_ENC_USER_ID) { + ws_llc_lowpan_mpx_data_request(base, user_cb, data); + } } @@ -932,6 +1261,12 @@ static void ws_llc_clean(llc_data_base_t *base) base->interface_ptr->mac_api->mcps_purge_req(base->interface_ptr->mac_api, &purge_req); } + + ns_list_foreach_safe(llc_message_t, message, &base->temp_entries->llc_eap_pending_list) { + ns_list_remove(&base->temp_entries->llc_eap_pending_list, message); + ns_dyn_mem_free(message); + } + base->temp_entries->active_eapol_session = false; memset(&base->ie_params, 0, sizeof(llc_ie_params_t)); ws_llc_temp_neigh_info_table_reset(base->temp_entries); @@ -940,18 +1275,19 @@ static void ws_llc_clean(llc_data_base_t *base) static void ws_llc_temp_neigh_info_table_reset(temp_entriest_t *base) { //Empty active list - ns_list_init(&base->active_temp_neigh); + ns_list_init(&base->active_multicast_temp_neigh); + ns_list_init(&base->active_eapol_temp_neigh); ns_list_init(&base->free_temp_neigh); //Add to free list to full - for (int i = 0; i < MAX_NEIGH_TEMPORRY_MULTICAST_SIZE; i++) { + for (int i = 0; i < MAX_NEIGH_TEMPORAY_LIST_SIZE; i++) { ns_list_add_to_end(&base->free_temp_neigh, &base->neighbour_temporary_table[i]); } } -static ws_neighbor_temp_class_t *ws_llc_discover_temp_entry(temp_entriest_t *base, const uint8_t *mac64) +static ws_neighbor_temp_class_t *ws_llc_discover_mc_temp_entry(temp_entriest_t *base, const uint8_t *mac64) { - ns_list_foreach_safe(ws_neighbor_temp_class_t, entry, &base->active_temp_neigh) { + ns_list_foreach(ws_neighbor_temp_class_t, entry, &base->active_multicast_temp_neigh) { if (memcmp(entry->mac64, mac64, 8) == 0) { return entry; } @@ -959,6 +1295,27 @@ static ws_neighbor_temp_class_t *ws_llc_discover_temp_entry(temp_entriest_t *bas return NULL; } +static ws_neighbor_temp_class_t *ws_llc_discover_eapol_temp_entry(temp_entriest_t *base, const uint8_t *mac64) +{ + ns_list_foreach(ws_neighbor_temp_class_t, entry, &base->active_eapol_temp_neigh) { + if (memcmp(entry->mac64, mac64, 8) == 0) { + return entry; + } + } + return NULL; +} + +static void ws_llc_release_eapol_temp_entry(temp_entriest_t *base, const uint8_t *mac64) +{ + ws_neighbor_temp_class_t *neighbor = ws_llc_discover_eapol_temp_entry(base, mac64); + if (!neighbor) { + return; + } + + ns_list_remove(&base->active_eapol_temp_neigh, neighbor); + ns_list_add_to_end(&base->free_temp_neigh, neighbor); +} + ws_neighbor_temp_class_t *ws_llc_get_multicast_temp_entry(protocol_interface_info_entry_t *interface, const uint8_t *mac64) { llc_data_base_t *base = ws_llc_discover_by_interface(interface); @@ -966,38 +1323,72 @@ ws_neighbor_temp_class_t *ws_llc_get_multicast_temp_entry(protocol_interface_inf return NULL; } - return ws_llc_discover_temp_entry(base->temp_entries, mac64); + return ws_llc_discover_mc_temp_entry(base->temp_entries, mac64); } +static void ws_init_temporary_neigh_data(ws_neighbor_temp_class_t *entry, const uint8_t *mac64) +{ + //Clear Old data + memset(&entry->neigh_info_list, 0, sizeof(ws_neighbor_class_entry_t)); + entry->neigh_info_list.rsl_in = RSL_UNITITIALIZED; + entry->neigh_info_list.rsl_out = RSL_UNITITIALIZED; + memcpy(entry->mac64, mac64, 8); + entry->eapol_temp_info.eapol_rx_relay_filter = 0; +} + static ws_neighbor_temp_class_t *ws_allocate_multicast_temp_entry(temp_entriest_t *base, const uint8_t *mac64) { - ws_neighbor_temp_class_t *entry = ws_llc_discover_temp_entry(base, mac64); + ws_neighbor_temp_class_t *entry = ws_llc_discover_mc_temp_entry(base, mac64); if (entry) { - ns_list_remove(&base->active_temp_neigh, entry); - ns_list_add_to_start(&base->active_temp_neigh, entry); + ns_list_remove(&base->active_multicast_temp_neigh, entry); + ns_list_add_to_start(&base->active_multicast_temp_neigh, entry); return entry; } - entry = ns_list_get_first(&base->free_temp_neigh); + if (ns_list_count(&base->active_multicast_temp_neigh) < MAX_NEIGH_TEMPORARY_MULTICAST_SIZE) { + entry = ns_list_get_first(&base->free_temp_neigh); + } if (entry) { ns_list_remove(&base->free_temp_neigh, entry); } else { //Replace last entry and put it to first - entry = ns_list_get_last(&base->active_temp_neigh); - ns_list_remove(&base->active_temp_neigh, entry); + entry = ns_list_get_last(&base->active_multicast_temp_neigh); + ns_list_remove(&base->active_multicast_temp_neigh, entry); } //Add to list - ns_list_add_to_start(&base->active_temp_neigh, entry); + ns_list_add_to_start(&base->active_multicast_temp_neigh, entry); //Clear Old data - memset(&entry->neigh_info_list, 0, sizeof(ws_neighbor_class_entry_t)); - entry->neigh_info_list.rsl_in = RSL_UNITITIALIZED; - entry->neigh_info_list.rsl_out = RSL_UNITITIALIZED; - memcpy(entry->mac64, mac64, 8); + ws_init_temporary_neigh_data(entry, mac64); + return entry; +} + +static ws_neighbor_temp_class_t *ws_allocate_eapol_temp_entry(temp_entriest_t *base, const uint8_t *mac64) +{ + + ws_neighbor_temp_class_t *entry = ws_llc_discover_eapol_temp_entry(base, mac64); + if (entry) { + //TODO referesh Timer here + return entry; + } + + if (ns_list_count(&base->active_eapol_temp_neigh) < MAX_NEIGH_TEMPORRY_EAPOL_SIZE) { + entry = ns_list_get_first(&base->free_temp_neigh); + } + + if (!entry) { + return NULL; + } + + ns_list_remove(&base->free_temp_neigh, entry); + //Add to list + ns_list_add_to_start(&base->active_eapol_temp_neigh, entry); + //Clear Old data + ws_init_temporary_neigh_data(entry, mac64); return entry; } @@ -1007,7 +1398,7 @@ void ws_llc_free_multicast_temp_entry(protocol_interface_info_entry_t *cur, ws_n if (!base) { return; } - ns_list_remove(&base->temp_entries->active_temp_neigh, neighbor); + ns_list_remove(&base->temp_entries->active_multicast_temp_neigh, neighbor); ns_list_add_to_end(&base->temp_entries->free_temp_neigh, neighbor); } @@ -1096,15 +1487,21 @@ int8_t ws_llc_asynch_request(struct protocol_interface_info_entry *interface, as } //Allocate LLC message pointer - llc_message_t *message = llc_message_allocate(total_length, base, false); + llc_message_t *message = llc_message_allocate(total_length, base); if (!message) { if (base->asynch_confirm) { base->asynch_confirm(interface, request->message_type); } return 0; } + + //Add To active list + llc_message_id_allocate(message, base, false); + base->llc_message_list_size++; + ns_list_add_to_end(&base->llc_message_list, message); message->messsage_type = request->message_type; + mcps_data_req_t data_req; memset(&data_req, 0, sizeof(mcps_data_req_t)); data_req.SeqNumSuppressed = true; @@ -1253,4 +1650,60 @@ void ws_llc_hopping_schedule_config(struct protocol_interface_info_entry *interf } base->ie_params.hopping_schedule = hopping_schedule; } + +void ws_llc_timer_seconds(struct protocol_interface_info_entry *interface, uint16_t seconds_update) +{ + llc_data_base_t *base = ws_llc_discover_by_interface(interface); + if (!base) { + return; + } + + ns_list_foreach_safe(ws_neighbor_temp_class_t, entry, &base->temp_entries->active_eapol_temp_neigh) { + if (entry->eapol_temp_info.eapol_timeout <= seconds_update) { + ns_list_remove(&base->temp_entries->active_eapol_temp_neigh, entry); + ns_list_add_to_end(&base->temp_entries->free_temp_neigh, entry); + } else { + entry->eapol_temp_info.eapol_timeout -= seconds_update; + if (entry->eapol_temp_info.eapol_rx_relay_filter == 0) { + //No active filter period + continue; + } + + //Update filter time + if (entry->eapol_temp_info.eapol_rx_relay_filter <= seconds_update) { + entry->eapol_temp_info.eapol_rx_relay_filter = 0; + } else { + entry->eapol_temp_info.eapol_rx_relay_filter -= seconds_update; + } + } + } +} + +bool ws_llc_eapol_relay_forward_filter(struct protocol_interface_info_entry *interface, const uint8_t *joiner_eui64, uint8_t mac_sequency, uint32_t rx_timestamp) +{ + llc_data_base_t *base = ws_llc_discover_by_interface(interface); + if (!base) { + return false; + } + + ws_neighbor_temp_class_t *neighbor = ws_llc_discover_eapol_temp_entry(base->temp_entries, joiner_eui64); + if (!neighbor) { + llc_neighbour_req_t neighbor_info; + //Discover here Normal Neighbour + if (!base->ws_neighbor_info_request_cb(interface, joiner_eui64, &neighbor_info, false)) { + return false; + } + return ws_neighbor_class_neighbor_duplicate_packet_check(neighbor_info.ws_neighbor, mac_sequency, rx_timestamp); + } + + if (neighbor->eapol_temp_info.eapol_rx_relay_filter && neighbor->eapol_temp_info.last_rx_mac_sequency == mac_sequency) { + return false; + } + neighbor->eapol_temp_info.last_rx_mac_sequency = mac_sequency; + neighbor->eapol_temp_info.eapol_rx_relay_filter = 6; //Activate 5-5.99 seconds filter time + return true; + +} + + #endif diff --git a/source/6LoWPAN/ws/ws_management_api.c b/source/6LoWPAN/ws/ws_management_api.c index cd4ce0cd80c..ef9e9cffbd0 100644 --- a/source/6LoWPAN/ws/ws_management_api.c +++ b/source/6LoWPAN/ws/ws_management_api.c @@ -41,9 +41,11 @@ int ws_management_node_init( protocol_interface_info_entry_t *cur; cur = protocol_stack_interface_info_get_by_id(interface_id); + if (interface_id >= 0 && (!cur || !ws_info(cur))) { return -1; } + if (!network_name_ptr || !fhss_timer_ptr) { return -2; } @@ -70,7 +72,9 @@ int ws_management_node_init( return -4; } - cur->ws_info->fhss_timer_ptr = fhss_timer_ptr; + if (cur && ws_info(cur)) { + cur->ws_info->fhss_timer_ptr = fhss_timer_ptr; + } return 0; } @@ -398,7 +402,7 @@ int ws_management_channel_plan_set( protocol_interface_info_entry_t *cur; cur = protocol_stack_interface_info_get_by_id(interface_id); - if (interface_id >= 0 && (!cur || !ws_info(cur))) { + if (!cur || !ws_info(cur)) { return -1; } cur->ws_info->hopping_schdule.channel_plan = channel_plan; diff --git a/source/6LoWPAN/ws/ws_neighbor_class.c b/source/6LoWPAN/ws/ws_neighbor_class.c index 7e4e7eedc02..214c46f871f 100644 --- a/source/6LoWPAN/ws/ws_neighbor_class.c +++ b/source/6LoWPAN/ws/ws_neighbor_class.c @@ -322,5 +322,32 @@ void ws_neighbor_class_rsl_out_calculate(ws_neighbor_class_entry_t *ws_neighbor, return; } + +bool ws_neighbor_class_neighbor_duplicate_packet_check(ws_neighbor_class_entry_t *ws_neighbor, uint8_t mac_dsn, uint32_t rx_timestamp) +{ + if (ws_neighbor->last_DSN != mac_dsn) { + // New packet allways accepted + ws_neighbor->last_DSN = mac_dsn; + return true; + } + + if (!ws_neighbor->unicast_data_rx) { + // No unicast info stored always accepted + return true; + } + + rx_timestamp -= ws_neighbor->fhss_data.uc_timing_info.utt_rx_timestamp; + rx_timestamp /= 1000000; //Convert to s + + //Compare only when last rx timestamp is less than 5 seconds + if (rx_timestamp < 5) { + //Packet is sent too fast filter it out + return false; + } + + return true; +} + + #endif /* HAVE_WS */ diff --git a/source/6LoWPAN/ws/ws_neighbor_class.h b/source/6LoWPAN/ws/ws_neighbor_class.h index c381b43f50e..f470a25a8b0 100644 --- a/source/6LoWPAN/ws/ws_neighbor_class.h +++ b/source/6LoWPAN/ws/ws_neighbor_class.h @@ -28,6 +28,7 @@ typedef struct ws_neighbor_class_entry { uint16_t rsl_in; /*!< RSL EWMA heard from neighbour*/ uint16_t rsl_out; /*!< RSL EWMA heard by neighbour*/ uint16_t routing_cost; /*!< ETX to border Router. */ + uint8_t last_DSN; bool candidate_parent: 1; bool broadcast_timing_info_stored: 1; bool broadcast_shedule_info_stored: 1; @@ -181,4 +182,6 @@ 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); + #endif /* WS_NEIGHBOR_CLASS_H_ */ diff --git a/source/6LoWPAN/ws/ws_pae_auth.c b/source/6LoWPAN/ws/ws_pae_auth.c index df50aea726f..077c3ae5806 100644 --- a/source/6LoWPAN/ws/ws_pae_auth.c +++ b/source/6LoWPAN/ws/ws_pae_auth.c @@ -28,6 +28,7 @@ #include "eventOS_scheduler.h" #include "eventOS_event_timer.h" #include "ns_address.h" +#include "Service_Libs/utils/ns_file.h" #include "NWK_INTERFACE/Include/protocol.h" #include "6LoWPAN/ws/ws_config.h" #include "Security/protocols/sec_prot_cfg.h" @@ -46,6 +47,8 @@ #include "6LoWPAN/ws/ws_pae_timers.h" #include "6LoWPAN/ws/ws_pae_auth.h" #include "6LoWPAN/ws/ws_pae_lib.h" +#include "6LoWPAN/ws/ws_pae_time.h" +#include "6LoWPAN/ws/ws_pae_key_storage.h" #ifdef HAVE_WS #ifdef HAVE_PAE_AUTH @@ -56,16 +59,18 @@ #define PAE_TASKLET_EVENT 2 #define PAE_TASKLET_TIMER 3 -// Wait for for supplicant to indicate activity (e.g. to send a message) -#define WAIT_FOR_AUTHENTICATION_TICKS 5 * 60 * 10 // 5 minutes - +/* Wait for supplicant to indicate activity (e.g. to send a message) when + authentication is ongoing */ +#define WAIT_FOR_AUTHENTICATION_TICKS 2 * 60 * 10 // 2 minutes +// Wait after authentication has completed before supplicant entry goes inactive +#define WAIT_AFTER_AUTHENTICATION_TICKS 15 * 10 // 15 seconds /* If EAP-TLS is delayed due to simultaneous negotiations limit, defines how long to wait for previous negotiation to complete */ #define EAP_TLS_NEGOTIATION_TRIGGER_TIMEOUT 60 * 10 // 60 seconds // Default for maximum number of supplicants -#define SUPPLICANT_MAX_NUMBER 1000 +#define SUPPLICANT_MAX_NUMBER 5000 /* Default for number of supplicants to purge per garbage collect call from nanostack monitor */ @@ -76,21 +81,23 @@ typedef struct { ns_list_link_t link; /**< Link */ + uint16_t pan_id; /**< PAN ID */ + char network_name[33]; /**< Network name */ kmp_service_t *kmp_service; /**< KMP service */ protocol_interface_info_entry_t *interface_ptr; /**< Interface pointer */ ws_pae_auth_gtk_hash_set *hash_set; /**< GTK hash set callback */ ws_pae_auth_nw_key_insert *nw_key_insert; /**< Key insert callback */ + ws_pae_auth_nw_keys_remove *nw_keys_remove; /**< Network keys remove callback */ ws_pae_auth_nw_key_index_set *nw_key_index_set; /**< Key index set callback */ + ws_pae_auth_nw_info_updated *nw_info_updated; /**< Security keys network info updated callback */ supp_list_t active_supp_list; /**< List of active supplicants */ - supp_list_t inactive_supp_list; /**< List of inactive supplicants */ arm_event_storage_t *timer; /**< Timer */ - sec_prot_gtk_keys_t *gtks; /**< GTKs */ sec_prot_gtk_keys_t *next_gtks; /**< Next GTKs */ const sec_prot_certs_t *certs; /**< Certificates */ + sec_prot_keys_nw_info_t *sec_keys_nw_info; /**< Security keys network information */ sec_timer_cfg_t *sec_timer_cfg; /**< Timer configuration */ sec_prot_cfg_t *sec_prot_cfg; /**< Protocol Configuration */ uint16_t supp_max_number; /**< Max number of stored supplicants */ - uint16_t slow_timer_seconds; /**< Slow timer seconds */ 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 */ @@ -119,15 +126,15 @@ static void ws_pae_auth_kmp_api_create_indication(kmp_api_t *kmp, kmp_type_e typ static void ws_pae_auth_kmp_api_finished_indication(kmp_api_t *kmp, kmp_result_e result, kmp_sec_keys_t *sec_keys); static void ws_pae_auth_next_kmp_trigger(pae_auth_t *pae_auth, supp_entry_t *supp_entry); static kmp_type_e ws_pae_auth_next_protocol_get(pae_auth_t *pae_auth, supp_entry_t *supp_entry); -static kmp_api_t *ws_pae_auth_kmp_create_and_start(kmp_service_t *service, kmp_type_e type, supp_entry_t *supp_entry, sec_prot_cfg_t *cfg); +static kmp_api_t *ws_pae_auth_kmp_create_and_start(kmp_service_t *service, kmp_type_e type, supp_entry_t *supp_entry, sec_prot_cfg_t *prot_cfg, sec_timer_cfg_t *timer_cfg); static void ws_pae_auth_kmp_api_finished(kmp_api_t *kmp); 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 *gtks, sec_prot_gtk_keys_t *next_gtks, const sec_prot_certs_t *certs, sec_timer_cfg_t *sec_timer_cfg, sec_prot_cfg_t *sec_prot_cfg) +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_timer_cfg_t *sec_timer_cfg, sec_prot_cfg_t *sec_prot_cfg, sec_prot_keys_nw_info_t *sec_keys_nw_info) { - if (!interface_ptr || !gtks || !certs) { + if (!interface_ptr || !next_gtks || !certs || !sec_timer_cfg || !sec_prot_cfg || !sec_keys_nw_info) { return -1; } @@ -140,23 +147,25 @@ int8_t ws_pae_auth_init(protocol_interface_info_entry_t *interface_ptr, sec_prot return -1; } + + memset(&pae_auth->network_name, 0, 33); + pae_auth->pan_id = 0xffff; pae_auth->interface_ptr = interface_ptr; ws_pae_lib_supp_list_init(&pae_auth->active_supp_list); - ws_pae_lib_supp_list_init(&pae_auth->inactive_supp_list); pae_auth->timer = NULL; pae_auth->hash_set = NULL; pae_auth->nw_key_insert = NULL; + pae_auth->nw_keys_remove = NULL; pae_auth->nw_key_index_set = NULL; - pae_auth->gtks = gtks; pae_auth->next_gtks = next_gtks; pae_auth->certs = certs; + pae_auth->sec_keys_nw_info = sec_keys_nw_info; pae_auth->sec_timer_cfg = sec_timer_cfg; pae_auth->sec_prot_cfg = sec_prot_cfg; pae_auth->supp_max_number = SUPPLICANT_MAX_NUMBER; - pae_auth->slow_timer_seconds = 0; pae_auth->gtk_new_inst_req_exp = false; pae_auth->gtk_new_act_time_exp = false; @@ -254,7 +263,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) +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) { if (!interface_ptr) { return; @@ -268,6 +277,7 @@ void ws_pae_auth_cb_register(protocol_interface_info_entry_t *interface_ptr, ws_ pae_auth->hash_set = hash_set; pae_auth->nw_key_insert = nw_key_insert; pae_auth->nw_key_index_set = nw_key_index_set; + pae_auth->nw_info_updated = nw_info_updated; } void ws_pae_auth_start(protocol_interface_info_entry_t *interface_ptr) @@ -282,15 +292,17 @@ void ws_pae_auth_start(protocol_interface_info_entry_t *interface_ptr) } // Checks if there is predefined active key - int8_t index = sec_prot_keys_gtk_status_active_get(pae_auth->gtks); + int8_t index = sec_prot_keys_gtk_status_active_get(pae_auth->sec_keys_nw_info->gtks); if (index < 0) { // If there is no key, inserts a new one ws_pae_auth_gtk_key_insert(pae_auth); - index = sec_prot_keys_gtk_install_order_first_index_get(pae_auth->gtks); + index = sec_prot_keys_gtk_install_order_first_index_get(pae_auth->sec_keys_nw_info->gtks); ws_pae_auth_active_gtk_set(pae_auth, index); } else { ws_pae_auth_active_gtk_set(pae_auth, index); } + // Update keys to NVM as needed + pae_auth->nw_info_updated(pae_auth->interface_ptr); // Inserts keys and updates GTK hash on stack ws_pae_auth_network_keys_from_gtks_set(pae_auth); @@ -331,13 +343,15 @@ int8_t ws_pae_auth_nw_key_index_update(protocol_interface_info_entry_t *interfac int8_t ws_pae_auth_node_keys_remove(protocol_interface_info_entry_t *interface_ptr, uint8_t *eui_64) { + int8_t ret_value = -1; + if (!interface_ptr) { - return -1; + return ret_value; } pae_auth_t *pae_auth = ws_pae_auth_get(interface_ptr); if (!pae_auth) { - return -1; + return ret_value; } // Checks if supplicant is active @@ -348,20 +362,16 @@ int8_t ws_pae_auth_node_keys_remove(protocol_interface_info_entry_t *interface_p sec_prot_keys_pmk_delete(&supp->sec_keys); sec_prot_keys_ptk_delete(&supp->sec_keys); supp->access_revoked = true; - tr_info("Access revoked; keys removed, eui-64: %s", trace_array(supp->addr.eui_64, 8)); - return 0; + tr_info("Access revoked; keys removed, eui-64: %s", trace_array(eui_64, 8)); + ret_value = 0; } - // Checks if supplicant is inactive - supp = ws_pae_lib_supp_list_entry_eui_64_get(&pae_auth->inactive_supp_list, eui_64); - if (supp) { - // Deletes supplicant - tr_info("Access revoked; deleted, eui-64: %s", trace_array(supp->addr.eui_64, 8)); - ws_pae_lib_supp_list_remove(&pae_auth->inactive_supp_list, supp); - return 0; + if (ws_pae_key_storage_supp_delete(pae_auth, eui_64)) { + tr_info("Access revoked; key store deleted, eui-64: %s", trace_array(eui_64, 8)); + ret_value = 0; } - return -1; + return ret_value; } int8_t ws_pae_auth_node_access_revoke_start(protocol_interface_info_entry_t *interface_ptr) @@ -376,7 +386,7 @@ int8_t ws_pae_auth_node_access_revoke_start(protocol_interface_info_entry_t *int } // Gets active GTK - int8_t active_index = sec_prot_keys_gtk_status_active_get(pae_auth->gtks); + int8_t active_index = sec_prot_keys_gtk_status_active_get(pae_auth->sec_keys_nw_info->gtks); if (active_index >= 0) { // As default removes other keys than active @@ -384,22 +394,24 @@ int8_t ws_pae_auth_node_access_revoke_start(protocol_interface_info_entry_t *int uint32_t revocation_lifetime = ws_pae_timers_gtk_revocation_lifetime_get(pae_auth->sec_timer_cfg); - uint32_t active_lifetime = sec_prot_keys_gtk_lifetime_get(pae_auth->gtks, active_index); + uint32_t active_lifetime = sec_prot_keys_gtk_lifetime_get(pae_auth->sec_keys_nw_info->gtks, active_index); + + uint64_t current_time = ws_pae_current_time_get(); // If active GTK lifetime is larger than revocation lifetime decrements active GTK lifetime if (active_lifetime > revocation_lifetime) { - sec_prot_keys_gtk_lifetime_decrement(pae_auth->gtks, active_index, active_lifetime - revocation_lifetime); + sec_prot_keys_gtk_lifetime_decrement(pae_auth->sec_keys_nw_info->gtks, active_index, current_time, active_lifetime - revocation_lifetime); tr_info("Access revocation start, GTK active index: %i, revoked lifetime: %"PRIu32"", active_index, revocation_lifetime); } else { // Otherwise decrements lifetime of the GTK to be installed after the active one - int8_t second_index = sec_prot_keys_gtk_install_order_second_index_get(pae_auth->gtks); + int8_t second_index = sec_prot_keys_gtk_install_order_second_index_get(pae_auth->sec_keys_nw_info->gtks); if (second_index >= 0) { // Second GTK revocation lifetime is the active GTK lifetime added with revocation time uint32_t second_revocation_lifetime = active_lifetime + revocation_lifetime; - uint32_t second_lifetime = sec_prot_keys_gtk_lifetime_get(pae_auth->gtks, second_index); + uint32_t second_lifetime = sec_prot_keys_gtk_lifetime_get(pae_auth->sec_keys_nw_info->gtks, second_index); if (second_lifetime > second_revocation_lifetime) { - sec_prot_keys_gtk_lifetime_decrement(pae_auth->gtks, second_index, second_lifetime - second_revocation_lifetime); + sec_prot_keys_gtk_lifetime_decrement(pae_auth->sec_keys_nw_info->gtks, second_index, current_time, second_lifetime - second_revocation_lifetime); tr_info("Access revocation start, GTK second active index: %i, revoked lifetime: %"PRIu32"", second_index, second_revocation_lifetime); } // Removes other keys than active and GTK to be installed next @@ -408,11 +420,11 @@ int8_t ws_pae_auth_node_access_revoke_start(protocol_interface_info_entry_t *int } // Deletes other GTKs - int8_t last_index = sec_prot_keys_gtk_install_order_last_index_get(pae_auth->gtks); + int8_t last_index = sec_prot_keys_gtk_install_order_last_index_get(pae_auth->sec_keys_nw_info->gtks); while (last_index >= 0 && last_index != not_removed_index) { tr_info("Access revocation GTK clear index: %i", last_index); - sec_prot_keys_gtk_clear(pae_auth->gtks, last_index); - last_index = sec_prot_keys_gtk_install_order_last_index_get(pae_auth->gtks); + sec_prot_keys_gtk_clear(pae_auth->sec_keys_nw_info->gtks, last_index); + last_index = sec_prot_keys_gtk_install_order_last_index_get(pae_auth->sec_keys_nw_info->gtks); } } @@ -420,6 +432,9 @@ int8_t ws_pae_auth_node_access_revoke_start(protocol_interface_info_entry_t *int ws_pae_auth_gtk_key_insert(pae_auth); ws_pae_auth_network_keys_from_gtks_set(pae_auth); + // Update keys to NVM as needed + pae_auth->nw_info_updated(pae_auth->interface_ptr); + return 0; } @@ -452,22 +467,69 @@ void ws_pae_auth_forced_gc(protocol_interface_info_entry_t *interface_ptr) /* Purge in maximum five entries from supplicant list (starting from oldest one) per call to the function (called by nanostack monitor) */ - ws_pae_lib_supp_list_purge(&pae_auth->active_supp_list, &pae_auth->inactive_supp_list, 0, SUPPLICANT_NUMBER_TO_PURGE); + ws_pae_lib_supp_list_purge(&pae_auth->active_supp_list, 0, SUPPLICANT_NUMBER_TO_PURGE); +} + +int8_t ws_pae_auth_nw_info_set(protocol_interface_info_entry_t *interface_ptr, uint16_t pan_id, char *network_name) +{ + if (!interface_ptr || !network_name) { + return -1; + } + + pae_auth_t *pae_auth = ws_pae_auth_get(interface_ptr); + if (!pae_auth) { + return -1; + } + + // On authenticator pan_id is always selected locally and is always valid for keys + if (pae_auth->sec_keys_nw_info->key_pan_id != pan_id) { + pae_auth->sec_keys_nw_info->key_pan_id = pan_id; + pae_auth->sec_keys_nw_info->updated = true; + } + + bool update_keys = false; + if (pae_auth->pan_id != 0xffff && pae_auth->pan_id != pan_id) { + update_keys = true; + } + pae_auth->pan_id = pan_id; + + if (strlen((char *) &pae_auth->network_name) > 0 && strcmp((char *) &pae_auth->network_name, network_name) != 0) { + update_keys = true; + } + strcpy((char *) &pae_auth->network_name, network_name); + + if (!update_keys) { + return 0; + } + + if (pae_auth->nw_keys_remove) { + pae_auth->nw_keys_remove(pae_auth->interface_ptr); + } + + ws_pae_auth_network_keys_from_gtks_set(pae_auth); + + int8_t index = sec_prot_keys_gtk_status_active_get(pae_auth->sec_keys_nw_info->gtks); + if (index >= 0) { + // Sets active key index + ws_pae_auth_network_key_index_set(pae_auth, index); + } + + return 0; } static int8_t ws_pae_auth_network_keys_from_gtks_set(pae_auth_t *pae_auth) { // Authenticator keys are always fresh - sec_prot_keys_gtk_status_all_fresh_set(pae_auth->gtks); + sec_prot_keys_gtk_status_all_fresh_set(pae_auth->sec_keys_nw_info->gtks); if (pae_auth->hash_set) { uint8_t gtk_hash[32]; - sec_prot_keys_gtks_hash_generate(pae_auth->gtks, gtk_hash); + sec_prot_keys_gtks_hash_generate(pae_auth->sec_keys_nw_info->gtks, gtk_hash); pae_auth->hash_set(pae_auth->interface_ptr, gtk_hash); } if (pae_auth->nw_key_insert) { - pae_auth->nw_key_insert(pae_auth->interface_ptr, pae_auth->gtks); + pae_auth->nw_key_insert(pae_auth->interface_ptr, pae_auth->sec_keys_nw_info->gtks); } return 0; @@ -475,12 +537,12 @@ static int8_t ws_pae_auth_network_keys_from_gtks_set(pae_auth_t *pae_auth) static int8_t ws_pae_auth_active_gtk_set(pae_auth_t *pae_auth, uint8_t index) { - return sec_prot_keys_gtk_status_active_set(pae_auth->gtks, index); + return sec_prot_keys_gtk_status_active_set(pae_auth->sec_keys_nw_info->gtks, index); } static int8_t ws_pae_auth_gtk_clear(pae_auth_t *pae_auth, uint8_t index) { - return sec_prot_keys_gtk_clear(pae_auth->gtks, index); + return sec_prot_keys_gtk_clear(pae_auth->sec_keys_nw_info->gtks, index); } static int8_t ws_pae_auth_network_key_index_set(pae_auth_t *pae_auth, uint8_t index) @@ -499,7 +561,6 @@ static void ws_pae_auth_free(pae_auth_t *pae_auth) } ws_pae_lib_supp_list_delete(&pae_auth->active_supp_list); - ws_pae_lib_supp_list_delete(&pae_auth->inactive_supp_list); kmp_socket_if_unregister(pae_auth->kmp_service); @@ -582,7 +643,7 @@ void ws_pae_auth_fast_timer(uint16_t ticks) } // Updates KMP timers - bool running = ws_pae_lib_supp_list_timer_update(&pae_auth->active_supp_list, &pae_auth->inactive_supp_list, ticks, kmp_service_timer_if_timeout); + bool running = ws_pae_lib_supp_list_timer_update(pae_auth, &pae_auth->active_supp_list, ticks, kmp_service_timer_if_timeout); if (!running) { ws_pae_auth_timer_stop(pae_auth); } @@ -594,22 +655,26 @@ void ws_pae_auth_slow_timer(uint16_t seconds) ns_list_foreach(pae_auth_t, pae_auth, &pae_auth_list) { // Gets index of currently active GTK - int8_t active_index = sec_prot_keys_gtk_status_active_get(pae_auth->gtks); + int8_t active_index = sec_prot_keys_gtk_status_active_get(pae_auth->sec_keys_nw_info->gtks); + + uint64_t current_time = ws_pae_current_time_get(); for (uint8_t i = 0; i < GTK_NUM; i++) { - if (!sec_prot_keys_gtk_is_set(pae_auth->gtks, i)) { + 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->gtks, i, seconds); + uint32_t timer_seconds = sec_prot_keys_gtk_lifetime_decrement(pae_auth->sec_keys_nw_info->gtks, i, current_time, seconds); 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_timer_cfg, timer_seconds); if (pae_auth->gtk_new_inst_req_exp) { - int8_t second_index = sec_prot_keys_gtk_install_order_second_index_get(pae_auth->gtks); + int8_t second_index = sec_prot_keys_gtk_install_order_second_index_get(pae_auth->sec_keys_nw_info->gtks); if (second_index < 0) { tr_info("GTK new install required active index: %i, time: %"PRIu32", system time: %"PRIu32"", active_index, timer_seconds, protocol_core_monotonic_time / 10); ws_pae_auth_gtk_key_insert(pae_auth); ws_pae_auth_network_keys_from_gtks_set(pae_auth); + // Update keys to NVM as needed + pae_auth->nw_info_updated(pae_auth->interface_ptr); } else { tr_info("GTK new install already done; second index: %i, time: %"PRIu32", system time: %"PRIu32"", second_index, timer_seconds, protocol_core_monotonic_time / 10); } @@ -626,6 +691,8 @@ void ws_pae_auth_slow_timer(uint16_t seconds) } pae_auth->gtk_new_inst_req_exp = false; pae_auth->gtk_new_act_time_exp = false; + // Update keys to NVM as needed + pae_auth->nw_info_updated(pae_auth->interface_ptr); } } } @@ -634,22 +701,22 @@ void ws_pae_auth_slow_timer(uint16_t seconds) tr_info("GTK expired index: %i, system time: %"PRIu32"", i, protocol_core_monotonic_time / 10); ws_pae_auth_gtk_clear(pae_auth, i); ws_pae_auth_network_keys_from_gtks_set(pae_auth); + // Update keys to NVM as needed + pae_auth->nw_info_updated(pae_auth->interface_ptr); } } - pae_auth->slow_timer_seconds += seconds; - if (pae_auth->slow_timer_seconds > 60) { - ws_pae_lib_supp_list_slow_timer_update(&pae_auth->active_supp_list, pae_auth->sec_timer_cfg, pae_auth->slow_timer_seconds); - ws_pae_lib_supp_list_slow_timer_update(&pae_auth->inactive_supp_list, pae_auth->sec_timer_cfg, pae_auth->slow_timer_seconds); - pae_auth->slow_timer_seconds = 0; - } + ws_pae_lib_supp_list_slow_timer_update(&pae_auth->active_supp_list, seconds); } + + // Update key storage timer + ws_pae_key_storage_timer(seconds); } static void ws_pae_auth_gtk_key_insert(pae_auth_t *pae_auth) { // Gets index to install the key - uint8_t install_index = sec_prot_keys_gtk_install_index_get(pae_auth->gtks); + uint8_t install_index = sec_prot_keys_gtk_install_index_get(pae_auth->sec_keys_nw_info->gtks); // Key to install uint8_t gtk_value[GTK_LEN]; @@ -671,24 +738,24 @@ static void ws_pae_auth_gtk_key_insert(pae_auth_t *pae_auth) // Gets latest installed key lifetime and adds GTK expire offset to it uint32_t lifetime = pae_auth->sec_timer_cfg->gtk_expire_offset; - int8_t last_index = sec_prot_keys_gtk_install_order_last_index_get(pae_auth->gtks); + int8_t last_index = sec_prot_keys_gtk_install_order_last_index_get(pae_auth->sec_keys_nw_info->gtks); if (last_index >= 0) { - lifetime += sec_prot_keys_gtk_lifetime_get(pae_auth->gtks, last_index); + lifetime += sec_prot_keys_gtk_lifetime_get(pae_auth->sec_keys_nw_info->gtks, last_index); } // Installs the new key - sec_prot_keys_gtk_clear(pae_auth->gtks, install_index); - sec_prot_keys_gtk_set(pae_auth->gtks, install_index, gtk_value, lifetime); + sec_prot_keys_gtk_clear(pae_auth->sec_keys_nw_info->gtks, install_index); + sec_prot_keys_gtk_set(pae_auth->sec_keys_nw_info->gtks, install_index, gtk_value, lifetime); // Authenticator keys are always fresh - sec_prot_keys_gtk_status_all_fresh_set(pae_auth->gtks); + sec_prot_keys_gtk_status_all_fresh_set(pae_auth->sec_keys_nw_info->gtks); tr_info("GTK install new index: %i, lifetime: %"PRIu32" system time: %"PRIu32"", install_index, lifetime, protocol_core_monotonic_time / 10); } static int8_t ws_pae_auth_new_gtk_activate(pae_auth_t *pae_auth) { - int8_t new_active_index = sec_prot_keys_gtk_install_order_second_index_get(pae_auth->gtks); + int8_t new_active_index = sec_prot_keys_gtk_install_order_second_index_get(pae_auth->sec_keys_nw_info->gtks); if (new_active_index >= 0) { ws_pae_auth_active_gtk_set(pae_auth, new_active_index); } @@ -717,8 +784,6 @@ static int8_t ws_pae_auth_timer_if_start(kmp_service_t *service, kmp_api_t *kmp) return -1; } - ws_pae_lib_supp_list_to_active(&pae_auth->active_supp_list, &pae_auth->inactive_supp_list, supp_entry); - ws_pae_lib_kmp_timer_start(&supp_entry->kmp_list, entry); return 0; } @@ -798,26 +863,27 @@ static kmp_api_t *ws_pae_auth_kmp_incoming_ind(kmp_service_t *service, kmp_type_ supp_entry_t *supp_entry = ws_pae_lib_supp_list_entry_eui_64_get(&pae_auth->active_supp_list, kmp_address_eui_64_get(addr)); if (!supp_entry) { - // Find supplicant from list of inactive supplicants - supp_entry = ws_pae_lib_supp_list_entry_eui_64_get(&pae_auth->inactive_supp_list, kmp_address_eui_64_get(addr)); + // Checks if active supplicant list has space for new supplicants + if (ws_pae_lib_supp_list_active_limit_reached(&pae_auth->active_supp_list, pae_auth->sec_prot_cfg->sec_max_ongoing_authentication)) { + tr_debug("PAE: active limit reached, eui-64: %s", trace_array(kmp_address_eui_64_get(addr), 8)); + return NULL; + } + // Find supplicant from key storage + supp_entry = ws_pae_key_storage_supp_read(pae_auth, kmp_address_eui_64_get(addr), pae_auth->sec_keys_nw_info->gtks, pae_auth->certs); if (supp_entry) { // Move supplicant to active list - ws_pae_lib_supp_list_to_active(&pae_auth->active_supp_list, &pae_auth->inactive_supp_list, supp_entry); + tr_debug("PAE: to active, eui-64: %s", trace_array(supp_entry->addr.eui_64, 8)); + ns_list_add_to_start(&pae_auth->active_supp_list, supp_entry); } } // If does not exists add it to list if (!supp_entry) { - // Checks if maximum number of supplicants is reached and purge supplicant list (starting from oldest one) - ws_pae_lib_supp_list_purge(&pae_auth->active_supp_list, &pae_auth->inactive_supp_list, pae_auth->supp_max_number, 0); - supp_entry = ws_pae_lib_supp_list_add(&pae_auth->active_supp_list, addr); if (!supp_entry) { return 0; } - sec_prot_keys_init(&supp_entry->sec_keys, pae_auth->gtks, pae_auth->certs); - // Fixes the address of the supplicant to keys - sec_prot_keys_ptk_eui_64_write(&supp_entry->sec_keys, kmp_address_eui_64_get(addr)); + sec_prot_keys_init(&supp_entry->sec_keys, pae_auth->sec_keys_nw_info->gtks, pae_auth->certs); } else { // Updates relay address kmp_address_copy(&supp_entry->addr, addr); @@ -833,7 +899,7 @@ static kmp_api_t *ws_pae_auth_kmp_incoming_ind(kmp_service_t *service, kmp_type_ } // Create a new KMP for initial eapol-key - kmp = kmp_api_create(service, type + IEEE_802_1X_INITIAL_KEY, pae_auth->sec_prot_cfg); + kmp = kmp_api_create(service, type + IEEE_802_1X_INITIAL_KEY, pae_auth->sec_prot_cfg, pae_auth->sec_timer_cfg); if (!kmp) { return 0; @@ -913,10 +979,11 @@ static void ws_pae_auth_next_kmp_trigger(pae_auth_t *pae_auth, supp_entry_t *sup kmp_type_e next_type = ws_pae_auth_next_protocol_get(pae_auth, supp_entry); if (next_type == KMP_TYPE_NONE) { + // Supplicant goes inactive after 15 seconds + ws_pae_lib_supp_timer_ticks_set(supp_entry, WAIT_AFTER_AUTHENTICATION_TICKS); // All done return; } else { - kmp_api_t *api = ws_pae_lib_kmp_list_type_get(&supp_entry->kmp_list, next_type); if (api != NULL) { /* For other types than GTK, only one ongoing negotiation at the same time, @@ -947,7 +1014,7 @@ static void ws_pae_auth_next_kmp_trigger(pae_auth_t *pae_auth, supp_entry_t *sup } // Create new instance - kmp_api_t *new_kmp = ws_pae_auth_kmp_create_and_start(pae_auth->kmp_service, next_type, supp_entry, pae_auth->sec_prot_cfg); + kmp_api_t *new_kmp = ws_pae_auth_kmp_create_and_start(pae_auth->kmp_service, next_type, supp_entry, pae_auth->sec_prot_cfg, pae_auth->sec_timer_cfg); if (!new_kmp) { return; } @@ -960,7 +1027,7 @@ static void ws_pae_auth_next_kmp_trigger(pae_auth_t *pae_auth, supp_entry_t *sup return; } // Create TLS instance */ - if (ws_pae_auth_kmp_create_and_start(pae_auth->kmp_service, TLS_PROT, supp_entry, pae_auth->sec_prot_cfg) == NULL) { + if (ws_pae_auth_kmp_create_and_start(pae_auth->kmp_service, TLS_PROT, supp_entry, pae_auth->sec_prot_cfg, pae_auth->sec_timer_cfg) == NULL) { ws_pae_lib_kmp_list_delete(&supp_entry->kmp_list, new_kmp); return; } @@ -1027,11 +1094,10 @@ static kmp_type_e ws_pae_auth_next_protocol_get(pae_auth_t *pae_auth, supp_entry return next_type; } - -static kmp_api_t *ws_pae_auth_kmp_create_and_start(kmp_service_t *service, kmp_type_e type, supp_entry_t *supp_entry, sec_prot_cfg_t *cfg) +static kmp_api_t *ws_pae_auth_kmp_create_and_start(kmp_service_t *service, kmp_type_e type, supp_entry_t *supp_entry, sec_prot_cfg_t *prot_cfg, sec_timer_cfg_t *timer_cfg) { // Create KMP instance for new authentication - kmp_api_t *kmp = kmp_api_create(service, type, cfg); + kmp_api_t *kmp = kmp_api_create(service, type, prot_cfg, timer_cfg); if (!kmp) { return NULL; @@ -1084,7 +1150,6 @@ static void ws_pae_auth_kmp_api_finished(kmp_api_t *kmp) tr_info("PAE next KMP trigger, eui-64: %s", trace_array(retry_supp->addr.eui_64, 8)); ws_pae_auth_next_kmp_trigger(pae_auth, retry_supp); } - } #endif /* HAVE_PAE_AUTH */ diff --git a/source/6LoWPAN/ws/ws_pae_auth.h b/source/6LoWPAN/ws/ws_pae_auth.h index 5bf680f4abe..db84db0656e 100644 --- a/source/6LoWPAN/ws/ws_pae_auth.h +++ b/source/6LoWPAN/ws/ws_pae_auth.h @@ -43,18 +43,18 @@ * \param local_port local port * \param remote_addr remote address * \param remote_port remote port - * \param gtks group keys * \param next_gtks next group keys to be used * \param cert_chain certificate chain * \param timer_settings timer settings * \param sec_timer_cfg timer configuration * \param sec_prot_cfg protocol configuration + * \param sec_keys_nw_info security keys network information * * \return < 0 failure * \return >= 0 success * */ -int8_t ws_pae_auth_init(protocol_interface_info_entry_t *interface_ptr, sec_prot_gtk_keys_t *gtks, sec_prot_gtk_keys_t *next_gtks, const sec_prot_certs_t *certs, sec_timer_cfg_t *sec_timer_cfg, sec_prot_cfg_t *sec_prot_cfg); +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_timer_cfg_t *sec_timer_cfg, sec_prot_cfg_t *sec_prot_cfg, sec_prot_keys_nw_info_t *sec_keys_nw_info); /** * ws_pae_auth_addresses_set set relay addresses @@ -168,6 +168,19 @@ int8_t ws_pae_auth_node_limit_set(protocol_interface_info_entry_t *interface_ptr */ void ws_pae_auth_forced_gc(protocol_interface_info_entry_t *interface_ptr); +/** + * ws_pae_auth_nw_info_set set network information + * + * \param interface_ptr interface + * \param pan_id PAD ID + * \param network_name network name + * + * \return < 0 failure + * \return >= 0 success + * + */ +int8_t ws_pae_auth_nw_info_set(protocol_interface_info_entry_t *interface_ptr, uint16_t pan_id, char *network_name); + /** * ws_pae_auth_gtk_hash_set GTK hash set callback * @@ -189,6 +202,14 @@ typedef void ws_pae_auth_gtk_hash_set(protocol_interface_info_entry_t *interface */ typedef int8_t ws_pae_auth_nw_key_insert(protocol_interface_info_entry_t *interface_ptr, sec_prot_gtk_keys_t *gtks); +/** + * ws_pae_auth_nw_keys_remove remove network keys callback + * + * \param interface_ptr interface + * + */ +typedef void ws_pae_auth_nw_keys_remove(protocol_interface_info_entry_t *interface_ptr); + /** * ws_pae_auth_nw_key_index_set network send key index set callback * @@ -198,6 +219,14 @@ typedef int8_t ws_pae_auth_nw_key_insert(protocol_interface_info_entry_t *interf */ typedef void ws_pae_auth_nw_key_index_set(protocol_interface_info_entry_t *interface_ptr, uint8_t index); +/** + * ws_pae_auth_nw_info_updated security keys network information updated + * + * \param interface_ptr interface + * + */ +typedef void ws_pae_auth_nw_info_updated(protocol_interface_info_entry_t *interface_ptr); + /** * ws_pae_auth_cb_register register PAE authenticator callbacks * @@ -205,9 +234,10 @@ typedef void ws_pae_auth_nw_key_index_set(protocol_interface_info_entry_t *inter * \param hash_set GTK hash set callback * \param nw_key_insert network key index callback * \param nw_key_index_set network send key index callback + * \param nw_info_updated network keys updated 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); +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); #else @@ -215,10 +245,11 @@ void ws_pae_auth_cb_register(protocol_interface_info_entry_t *interface_ptr, ws_ #define ws_pae_auth_timing_adjust(timing) #define ws_pae_auth_addresses_set(interface_ptr, local_port, remote_addr, remote_port) 1 #define ws_pae_auth_delete NULL -#define ws_pae_auth_cb_register(interface_ptr, hash_set, nw_key_insert, nw_key_index_set) {(void) hash_set;} +#define ws_pae_auth_cb_register(interface_ptr, hash_set, nw_key_insert, nw_key_index_set, nw_info_updated) {(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 +#define ws_pae_auth_nw_info_set NULL #define ws_pae_auth_node_keys_remove(interface_ptr, eui64) -1 #define ws_pae_auth_node_access_revoke_start(interface_ptr) #define ws_pae_auth_node_limit_set(interface_ptr, limit) diff --git a/source/6LoWPAN/ws/ws_pae_controller.c b/source/6LoWPAN/ws/ws_pae_controller.c index cf73b0a9da3..05eb06983b6 100644 --- a/source/6LoWPAN/ws/ws_pae_controller.c +++ b/source/6LoWPAN/ws/ws_pae_controller.c @@ -24,6 +24,7 @@ #include "fhss_config.h" #include "ns_address.h" #include "ws_management_api.h" +#include "Service_Libs/utils/ns_file.h" #include "NWK_INTERFACE/Include/protocol.h" #include "6LoWPAN/ws/ws_config.h" #include "6LoWPAN/ws/ws_cfg_settings.h" @@ -36,6 +37,8 @@ #include "6LoWPAN/ws/ws_pae_auth.h" #include "6LoWPAN/ws/ws_pae_nvm_store.h" #include "6LoWPAN/ws/ws_pae_nvm_data.h" +#include "6LoWPAN/ws/ws_pae_time.h" +#include "6LoWPAN/ws/ws_pae_key_storage.h" #include "mbedtls/sha256.h" #ifdef HAVE_WS @@ -49,6 +52,7 @@ typedef int8_t ws_pae_br_addr_read(protocol_interface_info_entry_t *interface_pt 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_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); typedef struct { uint8_t gtk[GTK_LEN]; /**< GTK key */ @@ -63,15 +67,17 @@ typedef struct { uint8_t br_eui_64[8]; /**< Border router EUI-64 */ sec_prot_gtk_keys_t gtks; /**< GTKs */ sec_prot_gtk_keys_t next_gtks; /**< Next GTKs */ + sec_prot_keys_nw_info_t sec_keys_nw_info; /**< Security keys network information */ int8_t gtk_index; /**< GTK index */ uint8_t gtkhash[32]; /**< GTK hashes */ sec_prot_certs_t certs; /**< Certificates */ nw_key_t nw_key[GTK_NUM]; /**< Currently active network keys (on MAC) */ - char *network_name; /**< Network name for GAK generation */ - uint16_t frame_cnt_store_timer; /**< Timer for storing frame counter value */ + uint16_t frame_cnt_store_timer; /**< Timer to check if storing of frame counter value is needed */ + uint32_t frame_cnt_store_force_timer; /**< Timer to force storing of frame counter, if no other updates */ frame_counters_t frame_counters; /**< Frame counters */ sec_timer_cfg_t sec_timer_cfg; /**< Timer configuration (configuration set values) */ sec_prot_cfg_t sec_prot_cfg; /**< Configuration */ + uint32_t restart_cnt; /**< Re-start counter */ protocol_interface_info_entry_t *interface_ptr; /**< List link entry */ ws_pae_controller_auth_completed *auth_completed; /**< Authentication completed callback, continue bootstrap */ ws_pae_controller_nw_key_set *nw_key_set; /**< Key set callback */ @@ -80,6 +86,8 @@ typedef struct { ws_pae_controller_nw_frame_counter_set *nw_frame_counter_set; /**< Frame counter set callback */ ws_pae_controller_nw_frame_counter_read *nw_frame_counter_read; /**< Frame counter read callback */ ws_pae_controller_pan_ver_increment *pan_ver_increment; /**< PAN version increment callback */ + ws_pae_controller_nw_info_updated *nw_info_updated; /**< Network information updated callback */ + ws_pae_controller_auth_next_target *auth_next_target; /**< Authentication next target callback */ ws_pae_delete *pae_delete; /**< PAE delete callback */ ws_pae_timer *pae_fast_timer; /**< PAE fast timer callback */ ws_pae_timer *pae_slow_timer; /**< PAE slow timer callback */ @@ -88,7 +96,8 @@ typedef struct { ws_pae_gtks_updated *pae_gtks_updated; /**< PAE GTKs updated */ ws_pae_gtk_hash_update *pae_gtk_hash_update; /**< PAE GTK HASH update */ ws_pae_nw_key_index_update *pae_nw_key_index_update; /**< PAE NW key index update */ - nvm_tlv_entry_t *pae_nvm_buffer; /**< Buffer For PAE NVM write operation*/ + ws_pae_nw_info_set *pae_nw_info_set; /**< PAE security key network info set */ + uint8_t pae_nvm_buffer[PAE_NVM_DEFAULT_BUFFER_SIZE]; /**< Buffer for PAE NVM read and write operations */ bool gtks_set : 1; /**< GTKs are set */ bool gtkhash_set : 1; /**< GTK hashes are set */ bool key_index_set : 1; /**< NW key index is set */ @@ -101,12 +110,14 @@ typedef struct { bool ext_cert_valid_enabled : 1; /**< Extended certificate validation enabled */ } pae_controller_config_t; +static void ws_pae_controller_keys_nw_info_init(sec_prot_keys_nw_info_t *sec_keys_nw_info, sec_prot_gtk_keys_t *gtks); +static void ws_pae_controller_nw_info_updated_check(protocol_interface_info_entry_t *interface_ptr); 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); static void ws_pae_controller_frame_counter_timer_trigger(uint16_t seconds, pae_controller_t *entry); static void ws_pae_controller_frame_counter_store(pae_controller_t *entry, bool use_threshold); -static void ws_pae_controller_nvm_frame_counter_write(nvm_tlv_entry_t *tlv_entry); -static int8_t ws_pae_controller_nvm_frame_counter_read(frame_counters_t *counters); +static void ws_pae_controller_nvm_frame_counter_write(nvm_tlv_t *tlv_entry); +static int8_t ws_pae_controller_nvm_frame_counter_read(uint32_t *restart_cnt, uint64_t *stored_time, frame_counters_t *counters); static pae_controller_t *ws_pae_controller_get_or_create(int8_t interface_id); static void ws_pae_controller_gtk_hash_set(protocol_interface_info_entry_t *interface_ptr, uint8_t *gtkhash); static int8_t ws_pae_controller_nw_key_check_and_insert(protocol_interface_info_entry_t *interface_ptr, sec_prot_gtk_keys_t *gtks); @@ -114,12 +125,19 @@ static void ws_pae_controller_active_nw_key_clear(nw_key_t *nw_key); static void ws_pae_controller_active_nw_key_set(protocol_interface_info_entry_t *cur, uint8_t index); static int8_t ws_pae_controller_gak_from_gtk(uint8_t *gak, uint8_t *gtk, char *network_name); static void ws_pae_controller_frame_counter_store_and_nw_keys_remove(protocol_interface_info_entry_t *interface_ptr, pae_controller_t *controller, bool use_threshold); +#ifdef HAVE_PAE_AUTH static void ws_pae_controller_nw_key_index_check_and_set(protocol_interface_info_entry_t *interface_ptr, uint8_t index); +#endif static void ws_pae_controller_data_init(pae_controller_t *controller); -static void ws_pae_controller_frame_counter_read(pae_controller_t *controller); +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 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, 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, sec_prot_gtk_keys_t *gtks); + static const char *FRAME_COUNTER_FILE = FRAME_COUNTER_FILE_NAME; +static const char *NW_INFO_FILE = NW_INFO_FILE_NAME; static NS_LIST_DEFINE(pae_controller_list, pae_controller_t, link); @@ -129,26 +147,6 @@ pae_controller_config_t pae_controller_config = { .ext_cert_valid_enabled = false }; -#if !defined(HAVE_PAE_SUPP) && !defined(HAVE_PAE_AUTH) - -static void ws_pae_controller_test_keys_set(sec_prot_gtk_keys_t *gtks) -{ - uint8_t gtk[GTK_LEN]; - - // Test data - for (int i = 0; i < GTK_LEN; i++) { - gtk[i] = 0xcf - i; - } - - sec_prot_keys_gtk_set(gtks, 0, gtk, GTK_DEFAULT_LIFETIME); -} - -#else - -#define ws_pae_controller_test_keys_set(gtks); - -#endif - int8_t ws_pae_controller_authenticate(protocol_interface_info_entry_t *interface_ptr) { pae_controller_t *controller = ws_pae_controller_get(interface_ptr); @@ -168,16 +166,9 @@ int8_t ws_pae_controller_authenticate(protocol_interface_info_entry_t *interface return 0; } - if (ws_pae_supp_authenticate(controller->interface_ptr, controller->target_pan_id, controller->target_eui_64) < 0) { + if (ws_pae_supp_authenticate(controller->interface_ptr, controller->target_pan_id, controller->target_eui_64, controller->sec_keys_nw_info.network_name) < 0) { controller->auth_completed(interface_ptr, AUTH_RESULT_ERR_UNSPEC, controller->target_eui_64); } - -#else - ws_pae_controller_test_keys_set(&controller->gtks); - ws_pae_controller_nw_key_check_and_insert(interface_ptr, &controller->gtks); - ws_pae_controller_nw_key_index_check_and_set(interface_ptr, 0); - - controller->auth_completed(interface_ptr, AUTH_RESULT_OK); #endif return 0; @@ -216,20 +207,6 @@ int8_t ws_pae_controller_authenticator_start(protocol_interface_info_entry_t *in return -1; } -#ifdef HAVE_PAE_AUTH - if (sec_prot_keys_gtks_are_updated(&controller->gtks)) { - ws_pae_auth_gtks_updated(interface_ptr); - if (controller->gtk_index >= 0) { - controller->pae_nw_key_index_update(interface_ptr, controller->gtk_index); - } - sec_prot_keys_gtks_updated_reset(&controller->gtks); - } -#else - ws_pae_controller_test_keys_set(&controller->gtks); - ws_pae_controller_nw_key_check_and_insert(interface_ptr, &controller->gtks); - ws_pae_controller_nw_key_index_check_and_set(interface_ptr, 0); -#endif - if (ws_pae_auth_addresses_set(interface_ptr, local_port, remote_addr, remote_port) < 0) { return -1; } @@ -238,14 +215,14 @@ 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_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_auth_start(interface_ptr); return 0; } -int8_t ws_pae_controller_cb_register(protocol_interface_info_entry_t *interface_ptr, ws_pae_controller_auth_completed *completed, ws_pae_controller_nw_key_set *nw_key_set, ws_pae_controller_nw_key_clear *nw_key_clear, ws_pae_controller_nw_send_key_index_set *nw_send_key_index_set, ws_pae_controller_nw_frame_counter_set *nw_frame_counter_set, ws_pae_controller_nw_frame_counter_read *nw_frame_counter_read, ws_pae_controller_pan_ver_increment *pan_ver_increment) +int8_t ws_pae_controller_cb_register(protocol_interface_info_entry_t *interface_ptr, ws_pae_controller_auth_completed *completed, ws_pae_controller_auth_next_target *auth_next_target, ws_pae_controller_nw_key_set *nw_key_set, ws_pae_controller_nw_key_clear *nw_key_clear, ws_pae_controller_nw_send_key_index_set *nw_send_key_index_set, ws_pae_controller_nw_frame_counter_set *nw_frame_counter_set, ws_pae_controller_nw_frame_counter_read *nw_frame_counter_read, ws_pae_controller_pan_ver_increment *pan_ver_increment, ws_pae_controller_nw_info_updated *nw_info_updated) { if (!interface_ptr) { return -1; @@ -263,7 +240,8 @@ int8_t ws_pae_controller_cb_register(protocol_interface_info_entry_t *interface_ controller->nw_frame_counter_set = nw_frame_counter_set; controller->nw_frame_counter_read = nw_frame_counter_read; controller->pan_ver_increment = pan_ver_increment; - + controller->nw_info_updated = nw_info_updated; + controller->auth_next_target = auth_next_target; return 0; } @@ -284,6 +262,20 @@ int8_t ws_pae_controller_set_target(protocol_interface_info_entry_t *interface_p return 0; } +static void ws_pae_controller_keys_nw_info_init(sec_prot_keys_nw_info_t *sec_keys_nw_info, sec_prot_gtk_keys_t *gtks) +{ + if (!sec_keys_nw_info) { + return; + } + + memset(sec_keys_nw_info, 0, sizeof(sec_prot_keys_nw_info_t)); + + sec_keys_nw_info->gtks = gtks; + sec_keys_nw_info->new_pan_id = 0xFFFF; + sec_keys_nw_info->key_pan_id = 0xFFFF; + sec_keys_nw_info->updated = false; +} + int8_t ws_pae_controller_nw_info_set(protocol_interface_info_entry_t *interface_ptr, uint16_t pan_id, char *network_name) { (void) pan_id; @@ -298,12 +290,44 @@ int8_t ws_pae_controller_nw_info_set(protocol_interface_info_entry_t *interface_ return -1; } - controller->network_name = network_name; + // Network name has been modified + if (network_name && strncmp(controller->sec_keys_nw_info.network_name, network_name, 33) != 0) { + strncpy(controller->sec_keys_nw_info.network_name, network_name, 32); + controller->sec_keys_nw_info.updated = true; + } - return ws_pae_supp_nw_info_set(interface_ptr, pan_id, network_name); + // PAN ID has been modified + if (pan_id != 0xffff && pan_id != controller->sec_keys_nw_info.new_pan_id) { + controller->sec_keys_nw_info.new_pan_id = pan_id; + controller->sec_keys_nw_info.updated = true; + } + + if (controller->pae_nw_info_set) { + controller->pae_nw_info_set(interface_ptr, pan_id, network_name); + } + + return 0; } -int8_t ws_pae_controller_nw_key_valid(protocol_interface_info_entry_t *interface_ptr) +static void ws_pae_controller_nw_info_updated_check(protocol_interface_info_entry_t *interface_ptr) +{ + if (!interface_ptr) { + return; + } + + pae_controller_t *controller = ws_pae_controller_get(interface_ptr); + if (!controller) { + return; + } + + if (controller->sec_keys_nw_info.updated || sec_prot_keys_gtks_are_updated(controller->sec_keys_nw_info.gtks)) { + ws_pae_controller_nvm_nw_info_write(interface_ptr, controller->sec_keys_nw_info.key_pan_id, controller->sec_keys_nw_info.network_name, controller->sec_keys_nw_info.gtks); + controller->sec_keys_nw_info.updated = false; + sec_prot_keys_gtks_updated_reset(controller->sec_keys_nw_info.gtks); + } +} + +int8_t ws_pae_controller_nw_key_valid(protocol_interface_info_entry_t *interface_ptr, uint8_t *br_iid) { if (!interface_ptr) { return -1; @@ -314,7 +338,7 @@ int8_t ws_pae_controller_nw_key_valid(protocol_interface_info_entry_t *interface return -1; } - return ws_pae_supp_nw_key_valid(interface_ptr); + return ws_pae_supp_nw_key_valid(interface_ptr, br_iid); } static int8_t ws_pae_controller_nw_key_check_and_insert(protocol_interface_info_entry_t *interface_ptr, sec_prot_gtk_keys_t *gtks) @@ -366,21 +390,21 @@ static int8_t ws_pae_controller_nw_key_check_and_insert(protocol_interface_info_ sec_prot_keys_gtk_hash_generate(gtk, gtkhash); tr_info("NW key set: %i, hash: %s", i, trace_array(gtkhash, 8)); uint8_t gak[GTK_LEN]; - if (ws_pae_controller_gak_from_gtk(gak, gtk, controller->network_name) >= 0) { + if (ws_pae_controller_gak_from_gtk(gak, gtk, controller->sec_keys_nw_info.network_name) >= 0) { // Install the new network key derived from GTK and network name (GAK) to MAC controller->nw_key_set(interface_ptr, i, i, gak); nw_key[i].installed = true; ret = 0; #ifdef EXTRA_DEBUG_INFO - tr_info("NW name: %s", controller->network_name); - size_t nw_name_len = strlen(controller->network_name); - tr_info("NW name: %s", trace_array((uint8_t *)controller->network_name, nw_name_len)); + tr_info("NW name: %s", controller->sec_keys_nw_info.network_name); + size_t nw_name_len = strlen(controller->sec_keys_nw_info.network_name); + tr_info("NW name: %s", trace_array((uint8_t *)controller->sec_keys_nw_info.network_name, nw_name_len)); tr_info("GTK: %s", trace_array(gtk, 16)); tr_info("GAK: %s", trace_array(gak, 16)); #endif } else { - tr_error("GAK generation failed network name: %s", controller->network_name); + tr_error("GAK generation failed network name: %s", controller->sec_keys_nw_info.network_name); continue; } @@ -512,6 +536,7 @@ static void ws_pae_controller_frame_counter_store_and_nw_keys_remove(protocol_in } } +#ifdef HAVE_PAE_AUTH static void ws_pae_controller_nw_key_index_check_and_set(protocol_interface_info_entry_t *interface_ptr, uint8_t index) { pae_controller_t *controller = ws_pae_controller_get(interface_ptr); @@ -534,6 +559,7 @@ static void ws_pae_controller_nw_key_index_check_and_set(protocol_interface_info controller->key_index_set = true; } } +#endif static void ws_pae_controller_active_nw_key_set(protocol_interface_info_entry_t *cur, uint8_t index) { @@ -564,11 +590,9 @@ int8_t ws_pae_controller_init(protocol_interface_info_entry_t *interface_ptr) } pae_controller_t *controller = ns_dyn_mem_alloc(sizeof(pae_controller_t)); - void *pae_nvm_buffer = ws_pae_buffer_allocate(); - if (!controller || !pae_nvm_buffer) { + if (!controller) { ns_dyn_mem_free(controller); - ns_dyn_mem_free(pae_nvm_buffer); return -1; } @@ -579,7 +603,9 @@ int8_t ws_pae_controller_init(protocol_interface_info_entry_t *interface_ptr) controller->nw_send_key_index_set = NULL; controller->nw_frame_counter_set = NULL; controller->pan_ver_increment = NULL; - controller->pae_nvm_buffer = pae_nvm_buffer; + controller->nw_info_updated = NULL; + controller->auth_next_target = NULL; + memset(&controller->sec_timer_cfg, 0, sizeof(ws_sec_timer_cfg_t)); memset(&controller->sec_prot_cfg, 0, sizeof(sec_prot_cfg_t)); @@ -603,7 +629,15 @@ int8_t ws_pae_controller_configure(protocol_interface_info_entry_t *interface_pt controller->sec_prot_cfg.sec_prot_trickle_params.k = 0; controller->sec_prot_cfg.sec_prot_trickle_params.TimerExpirations = sec_prot_cfg->sec_prot_trickle_timer_exp; controller->sec_prot_cfg.sec_prot_retry_timeout = sec_prot_cfg->sec_prot_retry_timeout * 10; + controller->sec_prot_cfg.sec_max_ongoing_authentication = sec_prot_cfg->sec_max_ongoing_authentication; + + controller->sec_prot_cfg.initial_key_retry_delay = sec_prot_cfg->initial_key_retry_delay; + controller->sec_prot_cfg.initial_key_trickle_params.Imin = sec_prot_cfg->initial_key_imin; + controller->sec_prot_cfg.initial_key_trickle_params.Imax = sec_prot_cfg->initial_key_imax; + controller->sec_prot_cfg.initial_key_trickle_params.k = 0; + controller->sec_prot_cfg.initial_key_trickle_params.TimerExpirations = 2; + controller->sec_prot_cfg.initial_key_retry_cnt = sec_prot_cfg->initial_key_retry_cnt; } if (sec_timer_cfg) { @@ -613,7 +647,6 @@ int8_t ws_pae_controller_configure(protocol_interface_info_entry_t *interface_pt return 0; } - static void ws_pae_controller_data_init(pae_controller_t *controller) { memset(controller->target_eui_64, 0, 8); @@ -634,29 +667,43 @@ static void ws_pae_controller_data_init(pae_controller_t *controller) controller->pae_gtks_updated = NULL; controller->pae_gtk_hash_update = NULL; controller->pae_nw_key_index_update = NULL; + controller->pae_nw_info_set = NULL; controller->gtks_set = false; controller->gtkhash_set = false; controller->key_index_set = false; controller->frame_counter_read = false; controller->gtk_index = -1; - controller->network_name = NULL; controller->frame_cnt_store_timer = FRAME_COUNTER_STORE_INTERVAL; + controller->frame_cnt_store_force_timer = FRAME_COUNTER_STORE_FORCE_INTERVAL; + controller->restart_cnt = 0; ws_pae_controller_frame_counter_reset(&controller->frame_counters); sec_prot_keys_gtks_init(&controller->gtks); sec_prot_keys_gtks_init(&controller->next_gtks); sec_prot_certs_init(&controller->certs); sec_prot_certs_ext_certificate_validation_set(&controller->certs, pae_controller_config.ext_cert_valid_enabled); + ws_pae_controller_keys_nw_info_init(&controller->sec_keys_nw_info, &controller->gtks); } -static void ws_pae_controller_frame_counter_read(pae_controller_t *controller) +static int8_t ws_pae_controller_frame_counter_read(pae_controller_t *controller) { + int8_t ret_value = 0; + if (controller->frame_counter_read) { - return; + return ret_value; } controller->frame_counter_read = true; + uint64_t stored_time = 0; + // Read frame counters - if (ws_pae_controller_nvm_frame_counter_read(&controller->frame_counters) >= 0) { + if (ws_pae_controller_nvm_frame_counter_read(&controller->restart_cnt, &stored_time, &controller->frame_counters) >= 0) { + // Current time is not valid + if (ws_pae_current_time_set(stored_time) < 0) { + ret_value = -1; + } + // This is used to ensure that PMK replay counters are fresh after each re-start. + controller->restart_cnt++; + bool updated = false; // Checks frame counters for (uint8_t index = 0; index < GTK_NUM; index++) { @@ -673,10 +720,12 @@ static void ws_pae_controller_frame_counter_read(pae_controller_t *controller) } if (updated) { // Writes incremented frame counters - ws_pae_nvm_store_frame_counter_tlv_create(controller->pae_nvm_buffer, &controller->frame_counters); - ws_pae_controller_nvm_frame_counter_write(controller->pae_nvm_buffer); + ws_pae_nvm_store_frame_counter_tlv_create((nvm_tlv_t *) &controller->pae_nvm_buffer, controller->restart_cnt, &controller->frame_counters); + ws_pae_controller_nvm_frame_counter_write((nvm_tlv_t *) &controller->pae_nvm_buffer); } } + + return ret_value; } static void ws_pae_controller_frame_counter_reset(frame_counters_t *frame_counters) @@ -689,6 +738,53 @@ static void ws_pae_controller_frame_counter_reset(frame_counters_t *frame_counte } } +static int8_t ws_pae_controller_nw_info_read(pae_controller_t *controller, sec_prot_gtk_keys_t *gtks) +{ + 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, gtks) < 0) { + // If no stored GTKs and network info (pan_id and network name) exits + return -1; + } + + // Sets also new pan_id used for pan_id set by bootstrap + controller->sec_keys_nw_info.new_pan_id = controller->sec_keys_nw_info.key_pan_id; + + 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, sec_prot_gtk_keys_t *gtks) +{ + nvm_tlv_t *tlv = 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, gtks); + + ws_pae_nvm_store_tlv_file_write(NW_INFO_FILE, 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, sec_prot_gtk_keys_t *gtks) +{ + nvm_tlv_t *tlv_entry = ws_pae_controller_nvm_tlv_get(interface_ptr); + if (!tlv_entry) { + return -1; + } + + ws_pae_nvm_store_generic_tlv_create(tlv_entry, PAE_NVM_NW_INFO_TAG, PAE_NVM_NW_INFO_LEN); + + if (ws_pae_nvm_store_tlv_file_read(NW_INFO_FILE, tlv_entry) < 0) { + return -1; + } + + if (ws_pae_nvm_store_nw_info_tlv_read(tlv_entry, pan_id, network_name, gtks) < 0) { + return -1; + } + + return 0; +} + int8_t ws_pae_controller_supp_init(protocol_interface_info_entry_t *interface_ptr) { pae_controller_t *controller = ws_pae_controller_get(interface_ptr); @@ -696,7 +792,7 @@ int8_t ws_pae_controller_supp_init(protocol_interface_info_entry_t *interface_pt return -1; } - if (ws_pae_supp_init(controller->interface_ptr, &controller->certs, &controller->sec_timer_cfg, &controller->sec_prot_cfg) < 0) { + if (ws_pae_supp_init(controller->interface_ptr, &controller->certs, &controller->sec_timer_cfg, &controller->sec_prot_cfg, &controller->sec_keys_nw_info) < 0) { return -1; } @@ -707,10 +803,14 @@ int8_t ws_pae_controller_supp_init(protocol_interface_info_entry_t *interface_pt controller->pae_br_addr_read = ws_pae_supp_border_router_addr_read; controller->pae_gtk_hash_update = ws_pae_supp_gtk_hash_update; controller->pae_nw_key_index_update = ws_pae_supp_nw_key_index_update; + controller->pae_nw_info_set = NULL; - ws_pae_supp_cb_register(controller->interface_ptr, controller->auth_completed, ws_pae_controller_nw_key_check_and_insert, ws_pae_controller_active_nw_key_set, ws_pae_controller_gtk_hash_ptr_get); + ws_pae_supp_cb_register(controller->interface_ptr, controller->auth_completed, controller->auth_next_target, ws_pae_controller_nw_key_check_and_insert, ws_pae_controller_active_nw_key_set, ws_pae_controller_gtk_hash_ptr_get, ws_pae_controller_nw_info_updated_check); ws_pae_controller_frame_counter_read(controller); + ws_pae_controller_nw_info_read(controller, controller->sec_keys_nw_info.gtks); + // Set active key back to fresh so that it can be used again after re-start + sec_prot_keys_gtk_status_active_to_fresh_set(&controller->gtks); return 0; } @@ -722,7 +822,7 @@ 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->gtks, &controller->next_gtks, &controller->certs, &controller->sec_timer_cfg, &controller->sec_prot_cfg) < 0) { + if (ws_pae_auth_init(controller->interface_ptr, &controller->next_gtks, &controller->certs, &controller->sec_timer_cfg, &controller->sec_prot_cfg, &controller->sec_keys_nw_info) < 0) { return -1; } @@ -731,8 +831,45 @@ int8_t ws_pae_controller_auth_init(protocol_interface_info_entry_t *interface_pt controller->pae_slow_timer = ws_pae_auth_slow_timer; controller->pae_gtks_updated = ws_pae_auth_gtks_updated; controller->pae_nw_key_index_update = ws_pae_auth_nw_key_index_update; + controller->pae_nw_info_set = ws_pae_auth_nw_info_set; - ws_pae_controller_frame_counter_read(controller); + sec_prot_gtk_keys_t *read_gtks_to = controller->sec_keys_nw_info.gtks; + if (ws_pae_controller_frame_counter_read(controller) < 0) { + tr_error("Stored key material invalid"); + // Key material invalid, do not read GTKs or any other security data + read_gtks_to = NULL; + } + +#ifdef HAVE_PAE_AUTH + if (sec_prot_keys_gtks_are_updated(&controller->gtks)) { + // If application has set GTK keys prepare those for use + ws_pae_auth_gtks_updated(interface_ptr); + if (controller->gtk_index >= 0) { + controller->pae_nw_key_index_update(interface_ptr, controller->gtk_index); + } + sec_prot_keys_gtks_updated_reset(&controller->gtks); + } +#endif + + if (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.network_name); + } + if (!read_gtks_to || sec_prot_keys_gtk_count(read_gtks_to) == 0) { + // Key material invalid or GTKs are expired, delete GTKs from NVM + 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, NULL); + } + } + + ws_pae_key_storage_init(); + if (read_gtks_to) { + ws_pae_key_storage_read(controller->restart_cnt); + } else { + // Key material invalid, delete key storage + ws_pae_key_storage_remove(); + } return 0; } @@ -747,6 +884,15 @@ int8_t ws_pae_controller_stop(protocol_interface_info_entry_t *interface_ptr) // Stores frame counters and removes network keys from PAE controller and MAC ws_pae_controller_frame_counter_store_and_nw_keys_remove(interface_ptr, controller, false); + // Store security key network info if it has been modified + ws_pae_controller_nw_info_updated_check(interface_ptr); + + // Store key storage if it has been modified + ws_pae_key_storage_store(); + + // Delete key storage + ws_pae_key_storage_delete(); + // If PAE has been initialized, deletes it if (controller->pae_delete) { controller->pae_delete(interface_ptr); @@ -775,7 +921,6 @@ int8_t ws_pae_controller_delete(protocol_interface_info_entry_t *interface_ptr) } ns_list_remove(&pae_controller_list, controller); - ns_dyn_mem_free(controller->pae_nvm_buffer); ns_dyn_mem_free(controller); return 0; @@ -1028,6 +1173,10 @@ int8_t ws_pae_controller_gtk_update(int8_t interface_id, uint8_t *gtk[GTK_NUM]) } } + // Sets active key + int8_t index = sec_prot_keys_gtk_install_order_first_index_get(&controller->gtks); + sec_prot_keys_gtk_status_active_set(&controller->gtks, index); + // Notifies PAE authenticator that GTKs have been updated */ if (controller->pae_gtks_updated) { controller->pae_gtks_updated(controller->interface_ptr); @@ -1234,6 +1383,13 @@ static void ws_pae_controller_frame_counter_timer(uint16_t seconds, pae_controll entry->frame_cnt_store_timer = FRAME_COUNTER_STORE_INTERVAL; ws_pae_controller_frame_counter_store(entry, true); } + + if (entry->frame_cnt_store_force_timer > seconds) { + entry->frame_cnt_store_force_timer -= seconds; + } else { + entry->frame_cnt_store_force_timer = 0; + ws_pae_controller_frame_counter_store(entry, true); + } } static void ws_pae_controller_frame_counter_timer_trigger(uint16_t seconds, pae_controller_t *entry) @@ -1287,33 +1443,38 @@ static void ws_pae_controller_frame_counter_store(pae_controller_t *entry, bool } } - if (update_needed) { + if (update_needed || entry->frame_cnt_store_force_timer == 0) { tr_debug("Write frame counters: system time %"PRIu32"", protocol_core_monotonic_time / 10); // Writes modified frame counters - ws_pae_nvm_store_frame_counter_tlv_create(entry->pae_nvm_buffer, &entry->frame_counters); - ws_pae_controller_nvm_frame_counter_write(entry->pae_nvm_buffer); + ws_pae_nvm_store_frame_counter_tlv_create((nvm_tlv_t *) &entry->pae_nvm_buffer, entry->restart_cnt, &entry->frame_counters); + ws_pae_controller_nvm_frame_counter_write((nvm_tlv_t *) &entry->pae_nvm_buffer); + + // Reset force interval when ever values are stored + entry->frame_cnt_store_force_timer = FRAME_COUNTER_STORE_FORCE_INTERVAL; } } -static int8_t ws_pae_controller_nvm_frame_counter_read(frame_counters_t *counters) +static int8_t ws_pae_controller_nvm_frame_counter_read(uint32_t *restart_cnt, uint64_t *stored_time, frame_counters_t *counters) { - nvm_tlv_list_t tlv_list; - ns_list_init(&tlv_list); + nvm_tlv_t *tlv = ws_pae_nvm_store_generic_tlv_allocate_and_create( + PAE_NVM_FRAME_COUNTER_TAG, PAE_NVM_FRAME_COUNTER_LEN); + if (!tlv) { + return -1; + } - if (ws_pae_nvm_store_tlv_file_read(FRAME_COUNTER_FILE, &tlv_list) < 0) { + if (ws_pae_nvm_store_tlv_file_read(FRAME_COUNTER_FILE, tlv) < 0) { + ws_pae_nvm_store_generic_tlv_free(tlv); return -1; } - int8_t result = -1; - ns_list_foreach_safe(nvm_tlv_entry_t, entry, &tlv_list) { - if (ws_pae_nvm_store_frame_counter_tlv_read(entry, counters) >= 0) { - result = 0; - } - ns_list_remove(&tlv_list, entry); - ns_dyn_mem_free(entry); + if (ws_pae_nvm_store_frame_counter_tlv_read(tlv, restart_cnt, stored_time, counters) < 0) { + ws_pae_nvm_store_generic_tlv_free(tlv); + return -1; } - return result; + ws_pae_nvm_store_generic_tlv_free(tlv); + + return 0; } static pae_controller_t *ws_pae_controller_get(protocol_interface_info_entry_t *interface_ptr) @@ -1346,22 +1507,19 @@ static pae_controller_t *ws_pae_controller_get_or_create(int8_t interface_id) return controller; } -nvm_tlv_entry_t *ws_pae_controller_nvm_tlv_get(protocol_interface_info_entry_t *interface_ptr) +nvm_tlv_t *ws_pae_controller_nvm_tlv_get(protocol_interface_info_entry_t *interface_ptr) { pae_controller_t *controller = ws_pae_controller_get(interface_ptr); if (!controller) { return NULL; } - return controller->pae_nvm_buffer; + return (nvm_tlv_t *) &controller->pae_nvm_buffer; } -static void ws_pae_controller_nvm_frame_counter_write(nvm_tlv_entry_t *tlv_entry) +static void ws_pae_controller_nvm_frame_counter_write(nvm_tlv_t *tlv_entry) { - nvm_tlv_list_t tlv_list; - ns_list_init(&tlv_list); - ns_list_add_to_end(&tlv_list, tlv_entry); - ws_pae_nvm_store_tlv_file_write(FRAME_COUNTER_FILE, &tlv_list); + ws_pae_nvm_store_tlv_file_write(FRAME_COUNTER_FILE, tlv_entry); } diff --git a/source/6LoWPAN/ws/ws_pae_controller.h b/source/6LoWPAN/ws/ws_pae_controller.h index 9a16b769d1f..2f7e01e6dff 100644 --- a/source/6LoWPAN/ws/ws_pae_controller.h +++ b/source/6LoWPAN/ws/ws_pae_controller.h @@ -249,12 +249,13 @@ int8_t ws_pae_controller_nw_info_set(protocol_interface_info_entry_t *interface_ * ws_pae_controller_nw_key_valid network key is valid i.e. used successfully on bootstrap * * \param interface_ptr interface + * \param br_iid border router IID for which the keys are valid * * \return < 0 failure * \return >= 0 success * */ -int8_t ws_pae_controller_nw_key_valid(protocol_interface_info_entry_t *interface_ptr); +int8_t ws_pae_controller_nw_key_valid(protocol_interface_info_entry_t *interface_ptr, uint8_t *br_iid); /** * ws_pae_controller_border_router_addr_write write border router address @@ -278,7 +279,7 @@ int8_t ws_pae_controller_border_router_addr_write(protocol_interface_info_entry_ * \return >= 0 success * */ -int8_t ws_pae_controller_border_router_addr_read(protocol_interface_info_entry_t *interface_ptr, uint8_t *eui_64); +int8_t ws_pae_controller_border_router_addr_read(protocol_interface_info_entry_t *interface_ptr, uint8_t *iid); /** * ws_pae_controller_gtk_update update GTKs (test interface) @@ -492,6 +493,18 @@ typedef void ws_pae_controller_nw_frame_counter_read(protocol_interface_info_ent */ typedef void ws_pae_controller_auth_completed(protocol_interface_info_entry_t *interface_ptr, auth_result_e result, uint8_t *target_eui_64); +/** + * ws_pae_controller_auth_next_target get next target to attempt authentication + * + * \param interface_ptr interface + * \param previous_eui_64 EUI-64 of previous target + * \param pan_id pan id + * + * \return EUI-64 of the next target or previous target if new one not available + * + */ +typedef const uint8_t *ws_pae_controller_auth_next_target(protocol_interface_info_entry_t *interface_ptr, const uint8_t *previous_eui_64, uint16_t *pan_id); + /** * ws_pae_controller_pan_ver_increment PAN version increment callback * @@ -500,23 +513,35 @@ typedef void ws_pae_controller_auth_completed(protocol_interface_info_entry_t *i */ typedef void ws_pae_controller_pan_ver_increment(protocol_interface_info_entry_t *interface_ptr); +/** + * ws_pae_controller_nw_info_updated network information is updated (read from memory) + * + * \param interface_ptr interface + * \param pan_id PAN ID + * \param network_name network name + * + */ +typedef void ws_pae_controller_nw_info_updated(protocol_interface_info_entry_t *interface_ptr, uint16_t pan_id, char *network_name); + /** * ws_pae_controller_cb_register register PEA controller callbacks * * \param interface_ptr interface * \param completed authentication completed callback + * \param next_target authentication next target callback * \param nw_key_set network key set callback * \param nw_key_clear network key clear callback * \param nw_send_key_index_set network send key index set callback * \param nw_frame_counter_set network frame counter set callback * \param nw_frame_counter_read network frame counter read callback * \param pan_ver_increment PAN version increment callback + * \param nw_info_updated network information updated callback * * \return < 0 failure * \return >= 0 success * */ -int8_t ws_pae_controller_cb_register(protocol_interface_info_entry_t *interface_ptr, ws_pae_controller_auth_completed *completed, ws_pae_controller_nw_key_set *nw_key_set, ws_pae_controller_nw_key_clear *nw_key_clear, ws_pae_controller_nw_send_key_index_set *nw_send_key_index_set, ws_pae_controller_nw_frame_counter_set *nw_frame_counter_set, ws_pae_controller_nw_frame_counter_read *nw_frame_counter_read, ws_pae_controller_pan_ver_increment *pan_ver_increment); +int8_t ws_pae_controller_cb_register(protocol_interface_info_entry_t *interface_ptr, ws_pae_controller_auth_completed *completed, ws_pae_controller_auth_next_target *auth_next_target, ws_pae_controller_nw_key_set *nw_key_set, ws_pae_controller_nw_key_clear *nw_key_clear, ws_pae_controller_nw_send_key_index_set *nw_send_key_index_set, ws_pae_controller_nw_frame_counter_set *nw_frame_counter_set, ws_pae_controller_nw_frame_counter_read *nw_frame_counter_read, ws_pae_controller_pan_ver_increment *pan_ver_increment, ws_pae_controller_nw_info_updated *nw_info_updated); /** * ws_pae_controller_fast_timer PAE controller fast timer call @@ -534,7 +559,7 @@ void ws_pae_controller_fast_timer(uint16_t ticks); */ void ws_pae_controller_slow_timer(uint16_t seconds); -struct nvm_tlv_entry *ws_pae_controller_nvm_tlv_get(protocol_interface_info_entry_t *interface_ptr); +struct nvm_tlv *ws_pae_controller_nvm_tlv_get(protocol_interface_info_entry_t *interface_ptr); /** * ws_pae_controller_forced_gc PAE controller garbage cleanup callback diff --git a/source/6LoWPAN/ws/ws_pae_key_storage.c b/source/6LoWPAN/ws/ws_pae_key_storage.c new file mode 100644 index 00000000000..b50dfb03027 --- /dev/null +++ b/source/6LoWPAN/ws/ws_pae_key_storage.c @@ -0,0 +1,1002 @@ +/* + * Copyright (c) 2020, Arm Limited and affiliates. + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "nsconfig.h" +#include +#include "ns_types.h" +#include "ns_list.h" +#include "ns_trace.h" +#include "nsdynmemLIB.h" +#include "fhss_config.h" +#include "NWK_INTERFACE/Include/protocol.h" +#include "6LoWPAN/ws/ws_config.h" +#include "Security/protocols/sec_prot_cfg.h" +#include "Security/kmp/kmp_addr.h" +#include "Security/kmp/kmp_api.h" +#include "Security/kmp/kmp_socket_if.h" +#include "Security/protocols/sec_prot_certs.h" +#include "Security/protocols/sec_prot_keys.h" +#include "6LoWPAN/ws/ws_cfg_settings.h" +#include "6LoWPAN/ws/ws_pae_controller.h" +#include "6LoWPAN/ws/ws_pae_timers.h" +#include "6LoWPAN/ws/ws_pae_auth.h" +#include "6LoWPAN/ws/ws_pae_lib.h" +#include "6LoWPAN/ws/ws_pae_nvm_store.h" +#include "6LoWPAN/ws/ws_pae_nvm_data.h" +#include "6LoWPAN/ws/ws_pae_time.h" +#include "6LoWPAN/ws/ws_pae_key_storage.h" + +#ifdef HAVE_WS + +#define TRACE_GROUP "wsks" + +#define KEY_STORAGE_INDEX_FILE "key_storage_index" +#define KEY_STORAGE_FILE "key_storage_00" +#define KEY_STORAGE_FILE_LEN sizeof(KEY_STORAGE_FILE) + +// Storage array header size +#define STORAGE_ARRAY_HEADER_LEN sizeof(key_storage_nvm_tlv_entry_t) + +// Update the key storage reference time on write operations, if entry reference time differs more than a day +#define KEY_STORAGE_REF_TIME_UPDATE_THRESHOLD 86400 + +/* Force key storage reference time update, if reference time differs more 31 days */ +#define KEY_STORAGE_REF_TIME_UPDATE_FORCE_THRESHOLD GTK_DEFAULT_LIFETIME + 86400 + +typedef enum { + WRITE_SET = 0, + TIME_SET, + PMK_CNT_SET, + PMK_SET, + PTK_SET, + EUI64_SET, + PTKEUI64_SET, + GTKHASH_SET, + GTKHASH4WH_SET, + PMKLTIME_SET, + PTKLTIME_SET, +} field_set_t; + +#define FIELD_SET(field) (field_set | (1 << field)) +#define FIELD_IS_SET(field) (field_set & (1 << field)) + +typedef struct { + ns_list_link_t link; /**< Link */ + const void *instance; /**< Instance; for support of multiple authenticators */ + key_storage_nvm_tlv_entry_t *storage_array_handle; /**< Key storage array handle (NVM header + array) */ + sec_prot_keys_storage_t *storage_array; /**< Key storage array */ + uint16_t size; /**< Array size in bytes */ + uint16_t entries; /**< Entries in array */ + uint16_t free_entries; /**< Free entries in array */ + bool allocated : 1; /**< Allocated */ + bool modified : 1; /**< Array modified */ +} key_storage_array_t; + +typedef struct { + uint8_t settings_set; /**< Settings set, do not use defaults */ + uint8_t storages_empty; /**< Number of empty i.e. to be allocated storages */ + uint16_t storage_default_size; /**< Default size for storages */ + uint16_t replace_index; /**< Index to replace when storages are full */ + uint64_t store_bitfield; /**< Bitfield of stored files */ + uint16_t store_timer_timeout; /**< Storing timing timeout */ + uint16_t store_timer; /**< Storing timer */ + uint32_t restart_cnt; /**< Re-start counter */ +} key_storage_params_t; + +static key_storage_params_t key_storage_params; + +static NS_LIST_DEFINE(key_storage_array_list, key_storage_array_t, link); + +static int8_t ws_pae_key_storage_allocate(const void *instance, uint16_t key_storage_size, void *storage); +static void ws_pae_key_storage_clear(key_storage_array_t *key_storage_array); +static void ws_pae_key_storage_list_all_free(void); +static sec_prot_keys_storage_t *ws_pae_key_storage_get(const void *instance, const uint8_t *eui64, key_storage_array_t **key_storage_array, bool return_free); +static sec_prot_keys_storage_t *ws_pae_key_storage_replace(const void *instance, key_storage_array_t **key_storage_array); +static void ws_pae_key_storage_trace(uint16_t field_set, sec_prot_keys_storage_t *key_storage, key_storage_array_t *key_storage_array); +static void ws_pae_key_storage_timer_expiry_set(void); +static int8_t ws_pae_key_storage_array_time_update_entry(uint64_t time_difference, sec_prot_keys_storage_t *storage_array_entry); +static int8_t ws_pae_key_storage_array_time_check_and_update_all(key_storage_array_t *key_storage_array, bool modified); +static int8_t ws_pae_key_storage_array_counters_check_and_update_all(key_storage_array_t *key_storage_array); +static int8_t ws_pae_key_storage_array_lifetime_update(uint32_t time_difference, uint16_t *lifetime); +static int8_t ws_pae_key_storage_array_lifetime_get(uint32_t time_difference, uint16_t short_lifetime, uint32_t *lifetime); +static void ws_pae_key_storage_array_pmk_invalid(sec_prot_keys_storage_t *storage_array); +static void ws_pae_key_storage_array_ptk_invalid(sec_prot_keys_storage_t *storage_array); + +static void ws_pae_key_storage_filename_set(char *file_name, uint8_t file_number) +{ + // Name is "key_storage_00" where 00 is replaced by file number + strcpy(file_name, KEY_STORAGE_FILE); + file_name[12] = (file_number / 10) + 'A'; // 0 is ASCII 'A', 1='B',..., F='P' + file_name[13] = (file_number % 10) + 'A'; // same as above +} + +int8_t ws_pae_key_storage_memory_set(uint8_t key_storages_number, const uint16_t *key_storage_size, void **key_storages) +{ + for (uint8_t index = 0; index < key_storages_number; index++) { + if (ws_pae_key_storage_allocate(NULL, key_storage_size[index], (sec_prot_keys_storage_t *) key_storages[index]) < 0) { + return -1; + } + } + + key_storage_params.storages_empty = 0; + + return 0; +} + +int8_t ws_pae_key_storage_settings_set(uint8_t alloc_max_number, uint16_t alloc_size, uint16_t storing_interval) +{ + key_storage_params.settings_set = true; + key_storage_params.storages_empty = alloc_max_number; + key_storage_params.storage_default_size = alloc_size; + key_storage_params.store_timer = storing_interval; + key_storage_params.store_timer_timeout = storing_interval; + + return 0; +} + +void ws_pae_key_storage_init(void) +{ + if (!key_storage_params.settings_set) { + key_storage_params.storages_empty = DEFAULT_NUMBER_OF_STORAGES; + key_storage_params.storage_default_size = STORAGE_ARRAY_HEADER_LEN + (sizeof(sec_prot_keys_storage_t) * DEFAULT_NUMBER_OF_ENTRIES_IN_ONE_STORAGE); + key_storage_params.store_timer = DEFAULT_STORING_INTERVAL; + key_storage_params.store_timer_timeout = DEFAULT_STORING_INTERVAL; + } + key_storage_params.replace_index = 0; + key_storage_params.store_bitfield = 0, + key_storage_params.restart_cnt = 0; +} + +void ws_pae_key_storage_delete(void) +{ + ws_pae_key_storage_list_all_free(); +} + +static int8_t ws_pae_key_storage_allocate(const void *instance, uint16_t key_storage_size, void *new_storage_array) +{ + key_storage_array_t *key_storage_array = ns_dyn_mem_alloc(sizeof(key_storage_array_t)); + if (!key_storage_array) { + return -1; + } + + if (new_storage_array == NULL) { + key_storage_array->storage_array_handle = ns_dyn_mem_alloc(key_storage_size); + if (!key_storage_array->storage_array_handle) { + return -1; + } + key_storage_array->allocated = true; + } else { + key_storage_array->storage_array_handle = new_storage_array; + key_storage_array->allocated = false; + } + key_storage_array->storage_array = (sec_prot_keys_storage_t *)(((uint8_t *)key_storage_array->storage_array_handle) + STORAGE_ARRAY_HEADER_LEN); + key_storage_array->size = key_storage_size; + key_storage_array->entries = (key_storage_size - STORAGE_ARRAY_HEADER_LEN) / sizeof(sec_prot_keys_storage_t); + key_storage_array->free_entries = key_storage_array->entries; + key_storage_array->instance = instance; + key_storage_array->modified = false; + + ws_pae_nvm_store_key_storage_tlv_create((nvm_tlv_t *) key_storage_array->storage_array_handle, key_storage_array->size); + + ws_pae_key_storage_clear(key_storage_array); + + ns_list_add_to_end(&key_storage_array_list, key_storage_array); + + tr_info("KeyS new %s, array: %p entries: %i", key_storage_array->allocated ? "allocated" : "static", (void *) key_storage_array->storage_array, key_storage_array->entries); + + return 0; +} + +static void ws_pae_key_storage_clear(key_storage_array_t *key_storage_array) +{ + key_storage_array->storage_array_handle->reference_time = ws_pae_current_time_get(); + key_storage_array->storage_array_handle->reference_restart_cnt = key_storage_params.restart_cnt; + + sec_prot_keys_storage_t *storage_array = (sec_prot_keys_storage_t *) key_storage_array->storage_array; + // Set all entries empty + for (uint16_t index = 0; index < key_storage_array->entries; index++) { + if (key_storage_array->allocated) { + memset(&storage_array[index], 0, sizeof(sec_prot_keys_storage_t)); + } + storage_array[index].eui_64_set = false; + } +} + +static void ws_pae_key_storage_list_all_free(void) +{ + ns_list_foreach_safe(key_storage_array_t, entry, &key_storage_array_list) { + if (entry->allocated) { + ns_dyn_mem_free(entry->storage_array_handle); + } + ns_list_remove(&key_storage_array_list, entry); + ns_dyn_mem_free(entry); + } +} + +static sec_prot_keys_storage_t *ws_pae_key_storage_get(const void *instance, const uint8_t *eui64, key_storage_array_t **key_storage_array, bool return_free) +{ + sec_prot_keys_storage_t *free_key_storage = NULL; + *key_storage_array = NULL; + uint16_t free_index = 0; + + ns_list_foreach(key_storage_array_t, entry, &key_storage_array_list) { + // Checks whether storage is for this authenticator + if (entry->instance != NULL && entry->instance != instance) { + tr_info("KeyS get instance other"); + continue; + } + // Checks entries in storage array + sec_prot_keys_storage_t *storage_array = (sec_prot_keys_storage_t *) entry->storage_array; + for (uint16_t index = 0; index < entry->entries; index++) { + if (!storage_array[index].eui_64_set) { + // Stores free array entry and initiates data on it to zero + if (return_free && free_key_storage == NULL) { + *key_storage_array = entry; + free_key_storage = &storage_array[index]; + memset(&storage_array[index], 0, sizeof(sec_prot_keys_storage_t)); + free_index = index; + } + continue; + } + // Searches for matching entry + if (memcmp(&storage_array[index].ptk_eui_64, eui64, 8) == 0) { + *key_storage_array = entry; + // If not already reserved for authenticator instance, reserve array for it + entry->instance = instance; + tr_info("KeyS get array: %p i: %i eui64: %s", (void *) entry->storage_array, index, tr_array(eui64, 8)); + return &storage_array[index]; + } + } + } + + // If not already reserved for authenticator instance, reserve array for it + if (free_key_storage != NULL && (*key_storage_array)->instance == NULL) { + (*key_storage_array)->instance = instance; + } + + tr_info("KeyS get array %s: %p i: %i free: %p eui64: %s", *key_storage_array ? "" : "(not alloc)", *key_storage_array ? (void *)(*key_storage_array)->storage_array : NULL, *key_storage_array ? free_index : 0, (void *)free_key_storage, tr_array(eui64, 8)); + // If matching entry is not found, returns free entry + return free_key_storage; +} + +bool ws_pae_key_storage_supp_delete(const void *instance, const uint8_t *eui64) +{ + (void) instance; + + bool deleted = false; + + ns_list_foreach(key_storage_array_t, entry, &key_storage_array_list) { + // Checks entries in storage array + sec_prot_keys_storage_t *storage_array = (sec_prot_keys_storage_t *) entry->storage_array; + for (uint16_t index = 0; index < entry->entries; index++) { + if (!storage_array[index].eui_64_set) { + continue; + } + // Searches for matching entry + if (memcmp(&storage_array[index].ptk_eui_64, eui64, 8) == 0) { + memset(&storage_array[index], 0, sizeof(sec_prot_keys_storage_t)); + tr_info("KeyS delete array: %p i: %i eui64: %s", (void *) entry->storage_array, index, tr_array(eui64, 8)); + entry->modified = true; + deleted = true; + } + } + } + + if (deleted) { + // Trigger storing to NVM right away to keep the stored data in sync + ws_pae_key_storage_timer_expiry_set(); + } + + return deleted; +} + +static sec_prot_keys_storage_t *ws_pae_key_storage_replace(const void *instance, key_storage_array_t **key_storage_array) +{ + uint16_t replace_index = key_storage_params.replace_index; + sec_prot_keys_storage_t *storage_array = NULL; + uint16_t storage_array_index = 0; + + ns_list_foreach(key_storage_array_t, entry, &key_storage_array_list) { + // Checks whether storage is for this authenticator + if (entry->instance != instance) { + continue; + } + // Finds correct key storage array + if (replace_index >= entry->entries) { + replace_index -= entry->entries; + continue; + } + if (key_storage_array) { + *key_storage_array = entry; + } + // Sets array and index and sets replace index to next + storage_array = (sec_prot_keys_storage_t *) entry->storage_array; + storage_array_index = replace_index; + key_storage_params.replace_index++; + + tr_info("KeyS replace array: %p i: %i eui64: %s", (void *) entry->storage_array, replace_index, tr_array(storage_array[replace_index].ptk_eui_64, 8)); + } + + // If replace index is not found it means that index has gone past the last entry + if (storage_array == NULL) { + /* Gets first key storage array and sets the array and sets index to zero and sets + (next) replace index to first */ + key_storage_array_t *key_storage_array_entry = ns_list_get_first(&key_storage_array_list); + if (key_storage_array_entry == NULL) { + return NULL; + } + if (key_storage_array) { + *key_storage_array = key_storage_array_entry; + } + storage_array = (sec_prot_keys_storage_t *) key_storage_array_entry->storage_array; + storage_array_index = 0; + key_storage_params.replace_index = 1; + + tr_info("KeyS replace array: %p i: %i eui64: %s", (void *) key_storage_array_entry->storage_array, storage_array_index, tr_array(key_storage_array_entry->storage_array[storage_array_index].ptk_eui_64, 8)); + } + + // Deletes any previous data + memset(&storage_array[storage_array_index], 0, sizeof(sec_prot_keys_storage_t)); + + return &storage_array[storage_array_index]; +} + +int8_t ws_pae_key_storage_supp_write(const void *instance, supp_entry_t *pae_supp) +{ + uint8_t *eui_64 = pae_supp->addr.eui_64; + + key_storage_array_t *key_storage_array; + sec_prot_keys_storage_t *key_storage = ws_pae_key_storage_get(instance, eui_64, &key_storage_array, true); + + // If cannot find existing or empty storage and there is room for storages tries to allocate more storage + if (key_storage == NULL && key_storage_params.storages_empty > 0) { + if (ws_pae_key_storage_allocate(instance, key_storage_params.storage_default_size, NULL) >= 0) { + key_storage_params.storages_empty--; + key_storage = ws_pae_key_storage_get(instance, eui_64, &key_storage_array, true); + } + } + + // If still cannot find empty storage, replaces old one + if (key_storage == NULL) { + key_storage = ws_pae_key_storage_replace(instance, &key_storage_array); + } + + // On failure exit + if (key_storage == NULL) { + return -1; + } + + // Calculate time difference between storage array reference time and current time + uint32_t time_difference; + if (ws_pae_time_diff_calc(ws_pae_current_time_get(), key_storage_array->storage_array_handle->reference_time, &time_difference, false) < 0) { + tr_error("KeyS write time err: %"PRIi64", ref: %"PRIi64", diff: %"PRIi32, ws_pae_current_time_get(), key_storage_array->storage_array_handle->reference_time, time_difference); + return -1; + } + + sec_prot_keys_t *sec_keys = &pae_supp->sec_keys; + + // If replay counter is near to exhaust delete PMK and PTK to refresh the counter + if (sec_keys->pmk_key_replay_cnt_set && (sec_keys->pmk_key_replay_cnt & PMK_KEY_REPLAY_CNT_LIMIT_MASK) >= PMK_KEY_REPLAY_CNT_LIMIT) { + tr_error("KeyS write PMK cnt limit eui64: %s", tr_array(eui_64, 8)); + sec_prot_keys_ptk_delete(&pae_supp->sec_keys); + sec_prot_keys_pmk_delete(&pae_supp->sec_keys); + } + + uint16_t field_set = 1 << WRITE_SET; + + if (key_storage->pmk_key_replay_cnt_set != sec_keys->pmk_key_replay_cnt_set || + key_storage->pmk_key_replay_cnt != sec_keys->pmk_key_replay_cnt) { + /* Does not set modified variable since counter updates are never stored to NVM. + Instead counter is increased on re-start. */ + key_storage->pmk_key_replay_cnt = sec_keys->pmk_key_replay_cnt & PMK_KEY_REPLAY_CNT_LIMIT_MASK; + key_storage->pmk_key_replay_cnt_set = sec_keys->pmk_key_replay_cnt_set; + field_set |= 1 << PMK_CNT_SET; + } + + if (key_storage->pmk_set != sec_keys->pmk_set || + memcmp(key_storage->pmk, sec_keys->pmk, PMK_LEN) != 0) { + key_storage_array->modified = true; + key_storage->pmk_set = sec_keys->pmk_set; + memcpy(key_storage->pmk, sec_keys->pmk, PMK_LEN); + field_set |= 1 << PMK_SET; + } + + if (key_storage->ptk_set != sec_keys->ptk_set || + memcmp(key_storage->ptk, sec_keys->ptk, PTK_LEN) != 0) { + key_storage_array->modified = true; + key_storage->ptk_set = sec_keys->ptk_set; + memcpy(key_storage->ptk, sec_keys->ptk, PTK_LEN); + field_set |= 1 << PTK_SET; + } + + if (key_storage->eui_64_set != true || + memcmp(key_storage->ptk_eui_64, eui_64, 8) != 0) { + key_storage_array->modified = true; + key_storage->eui_64_set = true; + memcpy(key_storage->ptk_eui_64, eui_64, 8); + field_set |= 1 << EUI64_SET; + } + + if (key_storage->ptk_eui_64_set != sec_keys->ptk_eui_64_set) { + key_storage_array->modified = true; + key_storage->ptk_eui_64_set = sec_keys->ptk_eui_64_set; + field_set |= 1 << PTKEUI64_SET; + } + + if (key_storage->ins_gtk_hash_set != sec_keys->ins_gtk_hash_set || + memcmp(key_storage->ins_gtk_hash, sec_keys->ins_gtk_hash, sizeof(sec_keys->ins_gtk_hash)) != 0) { + key_storage_array->modified = true; + key_storage->ins_gtk_hash_set = sec_keys->ins_gtk_hash_set; + memcpy(key_storage->ins_gtk_hash, sec_keys->ins_gtk_hash, sizeof(sec_keys->ins_gtk_hash)); + field_set |= 1 << GTKHASH_SET; + } + if (key_storage->ins_gtk_4wh_hash_set != sec_keys->ins_gtk_hash_set) { + key_storage->ins_gtk_4wh_hash_set = sec_keys->ins_gtk_hash_set; + field_set |= 1 << GTKHASH4WH_SET; + } + + if (sec_keys->pmk_set) { + // PMK lifetime is: time difference between reference and current time + lifetime + uint64_t pmk_lifetime = time_difference + sec_keys->pmk_lifetime; + if (pmk_lifetime > SEC_MAXIMUM_LIFETIME) { + pmk_lifetime = 0; + } + uint16_t short_time = ws_pae_time_to_short_convert(pmk_lifetime); + // Compares the time from active supplicant entry to stored one, and if time + if (!key_storage->pmk_lifetime_set || !ws_pae_time_from_short_time_compare(key_storage->pmk_lifetime, short_time)) { + key_storage_array->modified = true; + key_storage->pmk_lifetime_set = true; + key_storage->pmk_lifetime = short_time; + field_set |= 1 << PMKLTIME_SET; + } + } else { + key_storage->pmk_lifetime_set = false; + key_storage->pmk_lifetime = 0; + field_set |= 1 << PMKLTIME_SET; + } + + if (sec_keys->ptk_set) { + // PTK lifetime is: time difference between reference and current time + lifetime + uint64_t ptk_lifetime = time_difference + sec_keys->ptk_lifetime; + if (ptk_lifetime > SEC_MAXIMUM_LIFETIME) { + ptk_lifetime = 0; + } + uint16_t short_time = ws_pae_time_to_short_convert(ptk_lifetime); + if (!key_storage->ptk_lifetime_set || !ws_pae_time_from_short_time_compare(key_storage->ptk_lifetime, short_time)) { + key_storage_array->modified = true; + key_storage->ptk_lifetime_set = true; + key_storage->ptk_lifetime = short_time; + field_set |= 1 << PTKLTIME_SET; + } + } else { + key_storage->ptk_lifetime_set = false; + key_storage->ptk_lifetime = 0; + field_set |= 1 << PTKLTIME_SET; + } + + ws_pae_key_storage_trace(field_set, key_storage, key_storage_array); + + return 0; +} + +supp_entry_t *ws_pae_key_storage_supp_read(const void *instance, const uint8_t *eui_64, sec_prot_gtk_keys_t *gtks, const sec_prot_certs_t *certs) +{ + key_storage_array_t *key_storage_array; + sec_prot_keys_storage_t *key_storage = ws_pae_key_storage_get(instance, eui_64, &key_storage_array, false); + if (key_storage == NULL) { + return NULL; + } + + uint8_t pmk_invalid = false; + uint8_t ptk_invalid = false; + + uint16_t field_set = 0; + + // Calculate time difference between storage array reference time and current time + uint32_t time_difference; + if (ws_pae_time_diff_calc(ws_pae_current_time_get(), key_storage_array->storage_array_handle->reference_time, &time_difference, false) < 0) { + tr_error("KeyS read time err"); + pmk_invalid = true; + field_set |= 1 << TIME_SET; + } + + uint32_t pmk_lifetime = 0; + uint32_t ptk_lifetime = 0; + + if (!pmk_invalid) { + // Calculate PMK lifetime + if (ws_pae_key_storage_array_lifetime_get(time_difference, key_storage->pmk_lifetime, &pmk_lifetime) < 0) { + // PMK expired, all keys are invalid + pmk_invalid = true; + ptk_invalid = true; + field_set |= 1 << TIME_SET; + } + field_set |= 1 << PMKLTIME_SET; + } + + if (!pmk_invalid) { + // Calculate PTK lifetime + if (ws_pae_key_storage_array_lifetime_get(time_difference, key_storage->ptk_lifetime, &ptk_lifetime) < 0) { + // PMK expired, invalidate PTK related fields, PMK is still valid + ptk_invalid = true; + field_set |= 1 << TIME_SET; + } + field_set |= 1 << PTKLTIME_SET; + } + + supp_entry_t *pae_supp = ns_dyn_mem_temporary_alloc(sizeof(supp_entry_t)); + if (!pae_supp) { + return NULL; + } + ws_pae_lib_supp_init(pae_supp); + + // Adds relay address data + kmp_address_init(KMP_ADDR_EUI_64_AND_IP, &pae_supp->addr, key_storage->ptk_eui_64); + + sec_prot_keys_t *sec_keys = &pae_supp->sec_keys; + sec_prot_keys_init(sec_keys, gtks, certs); + + // PMK is invalid, do not retrieve any security key data + if (pmk_invalid) { + ws_pae_key_storage_trace(field_set, key_storage, key_storage_array); + return pae_supp; + } + + // Set PMK security key data + if (key_storage->pmk_key_replay_cnt_set) { + // LSB 16 bits is the replay counter + sec_keys->pmk_key_replay_cnt = key_storage->pmk_key_replay_cnt; + + uint32_t restart_cnt_diff; + if (key_storage_params.restart_cnt >= key_storage_array->storage_array_handle->reference_restart_cnt) { + restart_cnt_diff = key_storage_params.restart_cnt - key_storage_array->storage_array_handle->reference_restart_cnt; + } else { + restart_cnt_diff = key_storage_params.restart_cnt; + } + // MSB 32 bits is the restart count + sec_keys->pmk_key_replay_cnt |= ((uint64_t) restart_cnt_diff) << 32; + field_set |= 1 << PMK_CNT_SET; + } else { + sec_keys->pmk_key_replay_cnt = 0; + } + sec_keys->pmk_key_replay_cnt_set = key_storage->pmk_key_replay_cnt_set; + + memcpy(sec_keys->pmk, key_storage->pmk, PMK_LEN); + sec_keys->pmk_set = key_storage->pmk_set; + + field_set |= ((uint16_t)sec_keys->pmk_set) << PMK_SET; + + sec_keys->pmk_lifetime = pmk_lifetime; + + field_set |= 1 << PMKLTIME_SET; + + // PTK is invalid, do not retrieve any PTK security key data + if (ptk_invalid) { + ws_pae_key_storage_trace(field_set, key_storage, key_storage_array); + return pae_supp; + } + + // Set PTK security key data + memcpy(sec_keys->ptk, key_storage->ptk, PTK_LEN); + sec_keys->ptk_set = key_storage->ptk_set; + + field_set |= ((uint16_t)sec_keys->ptk_set) << PTK_SET; + + memcpy(sec_keys->ptk_eui_64, key_storage->ptk_eui_64, 8); + sec_keys->ptk_eui_64_set = key_storage->ptk_eui_64_set; + + field_set |= ((uint16_t) sec_keys->ptk_eui_64_set) << PTKEUI64_SET; + + memcpy(sec_keys->ins_gtk_hash, key_storage->ins_gtk_hash, sizeof(sec_keys->ins_gtk_hash)); + sec_keys->ins_gtk_hash_set = key_storage->ins_gtk_hash_set; + sec_keys->ins_gtk_4wh_hash_set = sec_keys->ins_gtk_hash_set; + + field_set |= ((uint16_t) sec_keys->ins_gtk_hash_set) << GTKHASH_SET; + field_set |= ((uint16_t) sec_keys->ins_gtk_4wh_hash_set) << GTKHASH4WH_SET; + + sec_keys->ptk_lifetime = ptk_lifetime; + + field_set |= 1 << PTKLTIME_SET; + + ws_pae_key_storage_trace(field_set, key_storage, key_storage_array); + + return pae_supp; +} + +static void ws_pae_key_storage_trace(uint16_t field_set, sec_prot_keys_storage_t *key_storage, key_storage_array_t *key_storage_array) +{ + tr_info("KeyS %s %s%"PRIi64" %"PRIi64" %s%s%i %s%s%s%s%s %s%s%i %i %s%i %i", + FIELD_IS_SET(WRITE_SET) ? "write" : "read", + FIELD_IS_SET(TIME_SET) ? "TIME " : "", FIELD_IS_SET(TIME_SET) ? ws_pae_current_time_get() : 0, FIELD_IS_SET(TIME_SET) ? key_storage_array->storage_array_handle->reference_time : 0, + FIELD_IS_SET(PMK_SET) ? "PMK " : "", + FIELD_IS_SET(PMK_CNT_SET) ? "PMK CNT " : "", key_storage->pmk_key_replay_cnt, + FIELD_IS_SET(PTK_SET) ? "PTK " : "", + FIELD_IS_SET(EUI64_SET) ? "EUI64 " : "", + FIELD_IS_SET(PTKEUI64_SET) ? "PTKEUI64 " : "", + FIELD_IS_SET(GTKHASH_SET) ? "GTKHASH " : "", tr_array((uint8_t *)key_storage->ins_gtk_hash, 8), + FIELD_IS_SET(GTKHASH4WH_SET) ? "GTKHASH4WH " : "", + FIELD_IS_SET(PMKLTIME_SET) ? "PMKLTIME " : "", STIME_TIME_GET(key_storage->pmk_lifetime), STIME_FORMAT_GET(key_storage->pmk_lifetime), + FIELD_IS_SET(PTKLTIME_SET) ? "PTKLTIME " : "", STIME_TIME_GET(key_storage->ptk_lifetime), STIME_FORMAT_GET(key_storage->ptk_lifetime) + ); +} + +int8_t ws_pae_key_storage_store(void) +{ + uint8_t entry_offset = 0; + uint64_t store_bitfield = 0; + + ns_list_foreach(key_storage_array_t, entry, &key_storage_array_list) { + // Bitfield is set for all entries (also that are non-modified in this write) + store_bitfield |= ((uint64_t) 1) << entry_offset; + + /* Checks whether array reference time needs to be updated */ + int8_t ret_value = ws_pae_key_storage_array_time_check_and_update_all(entry, entry->modified); + if (ret_value == 1) { + entry->modified = true; + } else if (ret_value < 0) { + // On error clears the whole array + ws_pae_key_storage_clear(entry); + entry->modified = true; + } + + /* On large network there could be different time thresholds for entries full / all updated + and half empty entries/not all updated where it is likely that data will still be modified */ + if (!entry->modified) { + entry_offset++; + // If not pending for storing; skips file write + continue; + } + + char filename[KEY_STORAGE_FILE_LEN]; + ws_pae_key_storage_filename_set(filename, entry_offset); + tr_info("KeyS write array: %p file: %s", (void *) entry->storage_array, filename); + nvm_tlv_t *tlv = (nvm_tlv_t *) entry->storage_array_handle; + ws_pae_nvm_store_tlv_file_write(filename, tlv); + + // No longer pending for storing + entry->modified = false; + entry_offset++; + } + + if (key_storage_params.store_bitfield != store_bitfield) { + key_storage_params.store_bitfield = store_bitfield; + nvm_tlv_t *tlv = ws_pae_nvm_store_generic_tlv_allocate_and_create( + PAE_NVM_KEY_STORAGE_INDEX_TAG, PAE_NVM_KEY_STORAGE_INDEX_LEN); + ws_pae_nvm_store_key_storage_index_tlv_create(tlv, key_storage_params.store_bitfield); + ws_pae_nvm_store_tlv_file_write(KEY_STORAGE_INDEX_FILE, tlv); + ws_pae_nvm_store_generic_tlv_free(tlv); + } + + return 0; +} + +void ws_pae_key_storage_read(uint32_t restart_cnt) +{ + key_storage_params.store_bitfield = 0; + key_storage_params.restart_cnt = restart_cnt; + + nvm_tlv_t *tlv = ws_pae_nvm_store_generic_tlv_allocate_and_create( + PAE_NVM_KEY_STORAGE_INDEX_TAG, PAE_NVM_KEY_STORAGE_INDEX_LEN); + + if (ws_pae_nvm_store_tlv_file_read(KEY_STORAGE_INDEX_FILE, tlv) < 0) { + ws_pae_nvm_store_generic_tlv_free(tlv); + return; + } + + uint64_t store_bitfield; + if (ws_pae_nvm_store_key_storage_index_tlv_read(tlv, &store_bitfield) >= 0) { + key_storage_params.store_bitfield = store_bitfield; + } + + ws_pae_nvm_store_generic_tlv_free(tlv); + + if (key_storage_params.store_bitfield == 0) { + return; + } + + tr_info("KeyS init store bitf: %"PRIx64, store_bitfield); + + key_storage_array_t *key_storage_array = ns_list_get_first(&key_storage_array_list); + key_storage_array_t *key_storage_array_prev = NULL; + + for (uint8_t entry_offset = 0; entry_offset < 64; entry_offset++) { + // There are no more fields + if (store_bitfield == 0) { + break; + } + + if (key_storage_array == NULL && key_storage_params.storages_empty > 0) { + if (ws_pae_key_storage_allocate(NULL, key_storage_params.storage_default_size, NULL) >= 0) { + key_storage_params.storages_empty--; + } + } + + if (key_storage_array_prev != NULL) { + key_storage_array = ns_list_get_next(&key_storage_array_list, key_storage_array_prev); + } else if (key_storage_array == NULL) { + key_storage_array = ns_list_get_first(&key_storage_array_list); + } + + if (key_storage_array == NULL) { + break; + } + key_storage_array_prev = key_storage_array; + + // If set on bitfield read + if ((store_bitfield & (((uint64_t) 1) << entry_offset)) == 0) { + continue; + } + store_bitfield &= ~(((uint64_t) 1) << entry_offset); + + tlv = (nvm_tlv_t *) key_storage_array->storage_array_handle; + ws_pae_nvm_store_key_storage_tlv_create(tlv, key_storage_array->size); + + char filename[KEY_STORAGE_FILE_LEN]; + ws_pae_key_storage_filename_set(filename, entry_offset); + + tr_info("KeyS init read array: %p file: %s", (void *) key_storage_array->storage_array, filename); + if (ws_pae_nvm_store_tlv_file_read(filename, tlv) < 0) { + ws_pae_key_storage_clear(key_storage_array); + // On error, re-use current one + key_storage_array_prev = NULL; + continue; + } + + bool read_error = false; + if (ws_pae_nvm_store_key_storage_tlv_read(tlv, key_storage_array->size) < 0) { + ws_pae_key_storage_clear(key_storage_array); + read_error = true; + } + + if (read_error) { + // On error, re-use current one + key_storage_array_prev = NULL; + continue; + } + + // Calculate time difference between storage array reference time and current time + uint32_t time_difference; + if (ws_pae_time_diff_calc(ws_pae_current_time_get(), key_storage_array->storage_array_handle->reference_time, &time_difference, false) < 0) { + tr_error("KeyS read array time err: %"PRIi64", ref: %"PRIi64", diff: %"PRIi32, ws_pae_current_time_get(), key_storage_array->storage_array_handle->reference_time, time_difference); + ws_pae_key_storage_clear(key_storage_array); + } + + // Checks and updates PMK counters + if (ws_pae_key_storage_array_counters_check_and_update_all(key_storage_array) < 0) { + tr_error("KeyS read array cnt err"); + // On error clears the whole array + ws_pae_key_storage_clear(key_storage_array); + } + + // Entry set, go to next + key_storage_array = NULL; + } +} + +void ws_pae_key_storage_remove(void) +{ + nvm_tlv_t *tlv = ws_pae_nvm_store_generic_tlv_allocate_and_create( + PAE_NVM_KEY_STORAGE_INDEX_TAG, PAE_NVM_KEY_STORAGE_INDEX_LEN); + + uint64_t store_bitfield = 0; + if (ws_pae_nvm_store_tlv_file_read(KEY_STORAGE_INDEX_FILE, tlv) >= 0) { + ws_pae_nvm_store_key_storage_index_tlv_read(tlv, &store_bitfield); + } + ws_pae_nvm_store_generic_tlv_free(tlv); + + ws_pae_nvm_store_tlv_file_remove(KEY_STORAGE_INDEX_FILE); + + tr_info("KeyS remove store bitf: %"PRIx64, store_bitfield); + + if (store_bitfield == 0) { + return; + } + + for (uint8_t entry_offset = 0; entry_offset < 64; entry_offset++) { + // If set on bitfield delete + if ((store_bitfield & (((uint64_t) 1) << entry_offset)) == 0) { + continue; + } + + char filename[KEY_STORAGE_FILE_LEN]; + ws_pae_key_storage_filename_set(filename, entry_offset); + + tr_info("KeyS remove file: %s", filename); + ws_pae_nvm_store_tlv_file_remove(filename); + } +} + +void ws_pae_key_storage_timer(uint16_t seconds) +{ + if (key_storage_params.store_timer > seconds) { + key_storage_params.store_timer -= seconds; + } else { + key_storage_params.store_timer = key_storage_params.store_timer_timeout; + ws_pae_key_storage_store(); + } + + ws_pae_current_time_update(seconds); +} + +static void ws_pae_key_storage_timer_expiry_set(void) +{ + // Expire in 30 seconds + key_storage_params.store_timer = 30; +} + +uint16_t ws_pae_key_storage_storing_interval_get(void) +{ + return key_storage_params.store_timer_timeout; +} + +static int8_t ws_pae_key_storage_array_time_update_entry(uint64_t time_difference, sec_prot_keys_storage_t *storage_array_entry) +{ + if (storage_array_entry->pmk_lifetime_set) { +#ifdef EXTRA_DEBUG_INFO + tr_debug("KeyS time update diff: %"PRIi64" PMK OLD t: %i %i eui64: %s", time_difference, STIME_TIME_GET(storage_array_entry->pmk_lifetime), STIME_FORMAT_GET(storage_array_entry->pmk_lifetime), tr_array(storage_array_entry->ptk_eui_64, 8)); +#endif + // Calculate new PMK lifetime + if (ws_pae_key_storage_array_lifetime_update(time_difference, &storage_array_entry->pmk_lifetime) < 0) { + tr_info("KeyS time update PMK expired diff: %"PRIi64" t: %i %i eui64: %s", time_difference, STIME_TIME_GET(storage_array_entry->pmk_lifetime), STIME_FORMAT_GET(storage_array_entry->pmk_lifetime), tr_array(storage_array_entry->ptk_eui_64, 8)); + // PMK expired, whole entry is invalid + ws_pae_key_storage_array_pmk_invalid(storage_array_entry); + return -1; + } +#ifdef EXTRA_DEBUG_INFO + tr_debug("KeyS time update PMK NEW t: %i %i", STIME_TIME_GET(storage_array_entry->pmk_lifetime), STIME_FORMAT_GET(storage_array_entry->pmk_lifetime)); +#endif + } + + if (storage_array_entry->pmk_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 + // Calculate new PTK lifetime + if (ws_pae_key_storage_array_lifetime_update(time_difference, &storage_array_entry->ptk_lifetime) < 0) { + tr_info("KeyS time update PTK expired diff: %"PRIi64" 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)); + // PTK is invalid, invalidate PTK related fields + ws_pae_key_storage_array_ptk_invalid(storage_array_entry); + // PMK is still valid + return 0; + } +#ifdef EXTRA_DEBUG_INFO + tr_debug("KeyS time update PTK NEW t: %i %i", STIME_TIME_GET(storage_array_entry->ptk_lifetime), STIME_FORMAT_GET(storage_array_entry->ptk_lifetime)); +#endif + } + return 0; +} + +static int8_t ws_pae_key_storage_array_time_check_and_update_all(key_storage_array_t *key_storage_array, bool modified) +{ + uint64_t reference_time = key_storage_array->storage_array_handle->reference_time; + uint64_t current_time = ws_pae_current_time_get(); + + uint32_t time_difference; + if (ws_pae_time_diff_calc(current_time, reference_time, &time_difference, false) < 0) { + tr_error("KeyS array time all err: %"PRIi64", ref: %"PRIi64", diff: %"PRIi32, ws_pae_current_time_get(), reference_time, time_difference); + return -1; + } + + if (modified) { + // Updates once a day on write + if (time_difference < KEY_STORAGE_REF_TIME_UPDATE_THRESHOLD) { + return 0; + } + } else if (time_difference < KEY_STORAGE_REF_TIME_UPDATE_FORCE_THRESHOLD) { + // Or every 31 days also when no other writes triggered + return 0; + } + + // Checks entries in storage array + sec_prot_keys_storage_t *storage_array = (sec_prot_keys_storage_t *) key_storage_array->storage_array; + for (uint16_t index = 0; index < key_storage_array->entries; index++) { + if (!storage_array[index].eui_64_set) { + continue; + } + // Updates lifetimes on the entry + ws_pae_key_storage_array_time_update_entry(time_difference, &storage_array[index]); + } + + // Entries are now on current time; update reference time + key_storage_array->storage_array_handle->reference_time = current_time; + return 1; +} + +static int8_t ws_pae_key_storage_array_counters_check_and_update_all(key_storage_array_t *key_storage_array) +{ + // Checks entries in storage array + sec_prot_keys_storage_t *storage_array = (sec_prot_keys_storage_t *) key_storage_array->storage_array; + for (uint16_t index = 0; index < key_storage_array->entries; index++) { + if (!storage_array[index].eui_64_set) { + continue; + } + + // GTK 4WH hash information is not stored to NVM and might be obsolete (changing it does not trigger NVM write) + storage_array[index].ins_gtk_4wh_hash_set = 0; + + if (!storage_array[index].pmk_key_replay_cnt_set) { + continue; + } + + // Sanity check for replay counter + if (storage_array[index].pmk_key_replay_cnt >= PMK_KEY_REPLAY_CNT_LIMIT) { + ws_pae_key_storage_array_pmk_invalid(&storage_array[index]); + ws_pae_key_storage_array_ptk_invalid(&storage_array[index]); + continue; + } + + /* Resets replay counter (lower part). When generating 64bit replay counter used on EAPOL, + re-start count is set to replay counter MSB 32bits. So the lower part of the counter + is always fresh after re-start. Thus, each power cycle of device has LSB 32bits of replay + counter space to use. In practice uses only LSB 16bits since counter is limited to 60000, + before generating new PMK. */ + storage_array[index].pmk_key_replay_cnt = 0; + } + + return 0; +} + +static int8_t ws_pae_key_storage_array_lifetime_update(uint32_t time_difference, uint16_t *lifetime) +{ + uint32_t entry_lifetime = ws_pae_time_from_short_convert(*lifetime); + *lifetime = 0; + + // If lifetime has expired, return failure + if (time_difference >= entry_lifetime) { + return -1; + } + entry_lifetime -= time_difference; + *lifetime = ws_pae_time_to_short_convert(entry_lifetime); + // If conversion results zero lifetime return failure + if (*lifetime == 0) { + return -1; + } + + // Lifetime is valid + return 0; +} + +static int8_t ws_pae_key_storage_array_lifetime_get(uint32_t time_difference, uint16_t short_lifetime, uint32_t *lifetime) +{ + *lifetime = ws_pae_time_from_short_convert(short_lifetime); + + // If lifetime has expired, return failure + if (time_difference >= *lifetime) { + return -1; + } + *lifetime -= time_difference; + + return 0; +} + +static void ws_pae_key_storage_array_pmk_invalid(sec_prot_keys_storage_t *storage_array) +{ + memset(storage_array, 0, sizeof(sec_prot_keys_storage_t)); +} + +static void ws_pae_key_storage_array_ptk_invalid(sec_prot_keys_storage_t *storage_array) +{ + memset(storage_array->ptk, 0, PTK_LEN); + storage_array->ptk_set = false; + storage_array->ptk_eui_64_set = false; + memset(storage_array->ins_gtk_hash, 0, sizeof(storage_array->ins_gtk_hash)); + storage_array->ins_gtk_hash_set = false; + storage_array->ptk_lifetime = 0; +} + +#endif /* HAVE_WS */ + diff --git a/source/6LoWPAN/ws/ws_pae_key_storage.h b/source/6LoWPAN/ws/ws_pae_key_storage.h new file mode 100644 index 00000000000..b4116200180 --- /dev/null +++ b/source/6LoWPAN/ws/ws_pae_key_storage.h @@ -0,0 +1,164 @@ +/* + * Copyright (c) 2020, Arm Limited and affiliates. + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef WS_PAE_KEY_STORAGE_H_ +#define WS_PAE_KEY_STORAGE_H_ + +/* + * Port access entity key storage functions. + * + */ + +// Number of storages i.e. records in NVM +#define DEFAULT_NUMBER_OF_STORAGES 50 + +// Number of entries stored in a storage i.e. one record in NVM +#define DEFAULT_NUMBER_OF_ENTRIES_IN_ONE_STORAGE 100 + +// Interval to check if storage has been modified and needs to be updated to NVM +#define DEFAULT_STORING_INTERVAL 3600 + +struct supp_entry_s; +struct sec_prot_gtk_keys_s; +struct sec_prot_certs_s; + +/** + * ws_pae_key_storage_memory_set sets memory used for key storages + * + * This functions can be used to set memory used by key storage. When memory areas + * are set, module does not allocate memory internally from heap. + * + * \param key_storages_number number of memory areas + * \param key_storage_size array of memory area sizes + * \param key_storages array of memory area start pointers + * + * \return < 0 failure + * \return >= 0 success + * + */ +int8_t ws_pae_key_storage_memory_set(uint8_t key_storages_number, const uint16_t *key_storage_size, void **key_storages); + +/** + * ws_pae_key_storage_memory_set sets key storage settings + * + * Allocation max number and allocation size sets the settings that are used when key storage + * memory is allocated dynamically from heap. These settings must be set before (first) interface + * up and shall not be set if key storage memory is set by ws_pae_key_storage_memory_set() call. + * + * \param alloc_max_number maximum number of allocation made to dynamic memory + * \param alloc_size size of each allocation + * \param storing_interval interval in which the check to store to NVM is made + * + * \return < 0 failure + * \return >= 0 success + * + */ +int8_t ws_pae_key_storage_settings_set(uint8_t alloc_max_number, uint16_t alloc_size, uint16_t storing_interval); + +/** + * ws_pae_key_storage_init init key storage + * + */ +void ws_pae_key_storage_init(void); + +/** + * ws_pae_key_storage_init delete key storage + * + */ +void ws_pae_key_storage_delete(void); + +/** + * ws_pae_key_storage_store store to NVM + * + * Checks whether key storage data has been updated and stores to NVM. + * + * \return < 0 failure + * \return >= 0 success + * + */ +int8_t ws_pae_key_storage_store(void); + +/** + * ws_pae_key_storage_read read from NVM + * + * Reads key storage data from NVM. + * + */ +void ws_pae_key_storage_read(uint32_t restart_cnt); + +/** + * ws_pae_key_storage_remove remove storage from NVM + * + * Removes key storage data from NVM. + * + */ +void ws_pae_key_storage_remove(void); + +/** + * ws_pae_key_storage_supp_write writes supplicant entry to key storage + * + * \param instance instance + * \param pae_supp supplicant entry + * + * \return < 0 failure + * \return >= 0 success + * + */ +int8_t ws_pae_key_storage_supp_write(const void *instance, struct supp_entry_s *pae_supp); + +/** + * ws_pae_key_storage_supp_read reads supplicant entry from key storage + * + * \param instance instance + * \param eui_64 EUI-64 of the supplicant + * \param gtks GTK keys + * \param cert_chain certificates + * + * \return supplicant entry or NULL if supplicant entry does not exits + * + */ +struct supp_entry_s *ws_pae_key_storage_supp_read(const void *instance, const uint8_t *eui_64, struct sec_prot_gtk_keys_s *gtks, const struct sec_prot_certs_s *certs); + +/** + * ws_pae_key_storage_supp_delete delete supplicant entry from key storage + * + * \param instance instance + * \param eui_64 EUI-64 of the supplicant + * + * \return true entry was deleted + * \return false entry was not deleted + * + */ +bool ws_pae_key_storage_supp_delete(const void *instance, const uint8_t *eui64); + +/** + * ws_pae_key_storage_timer key storage timers + * + * \param seconds Seconds passed + * + */ +void ws_pae_key_storage_timer(uint16_t seconds); + +/** + * ws_pae_key_storage_storing_interval_get gets key storage storing interval + * + * \return storing interval in seconds + * + */ +uint16_t ws_pae_key_storage_storing_interval_get(void); + +#endif /* WS_PAE_KEY_STORAGE_H_ */ diff --git a/source/6LoWPAN/ws/ws_pae_lib.c b/source/6LoWPAN/ws/ws_pae_lib.c index 4394ee1dc87..d47aff8a8fe 100644 --- a/source/6LoWPAN/ws/ws_pae_lib.c +++ b/source/6LoWPAN/ws/ws_pae_lib.c @@ -26,13 +26,14 @@ #include "NWK_INTERFACE/Include/protocol.h" #include "6LoWPAN/ws/ws_cfg_settings.h" #include "6LoWPAN/ws/ws_config.h" -#include "6LoWPAN/ws/ws_pae_timers.h" #include "Security/protocols/sec_prot_cfg.h" +#include "6LoWPAN/ws/ws_pae_timers.h" #include "Security/kmp/kmp_addr.h" #include "Security/kmp/kmp_api.h" #include "Security/protocols/sec_prot_certs.h" #include "Security/protocols/sec_prot_keys.h" #include "6LoWPAN/ws/ws_pae_lib.h" +#include "6LoWPAN/ws/ws_pae_key_storage.h" #ifdef HAVE_WS @@ -126,6 +127,16 @@ kmp_entry_t *ws_pae_lib_kmp_list_entry_get(kmp_list_t *kmp_list, kmp_api_t *kmp) return 0; } +bool ws_pae_lib_kmp_list_empty(kmp_list_t *kmp_list) +{ + return ns_list_is_empty(kmp_list); +} + +uint8_t ws_pae_lib_kmp_list_count(kmp_list_t *kmp_list) +{ + return ns_list_count(kmp_list); +} + void ws_pae_lib_kmp_timer_start(kmp_list_t *kmp_list, kmp_entry_t *entry) { if (ns_list_get_first(kmp_list) != entry) { @@ -171,7 +182,7 @@ void ws_pae_lib_supp_list_init(supp_list_t *supp_list) supp_entry_t *ws_pae_lib_supp_list_add(supp_list_t *supp_list, const kmp_addr_t *addr) { - supp_entry_t *entry = ns_dyn_mem_alloc(sizeof(supp_entry_t)); + supp_entry_t *entry = ns_dyn_mem_temporary_alloc(sizeof(supp_entry_t)); if (!entry) { return NULL; @@ -215,33 +226,32 @@ void ws_pae_lib_supp_list_delete(supp_list_t *supp_list) } } -bool ws_pae_lib_supp_list_timer_update(supp_list_t *active_supp_list, supp_list_t *inactive_supp_list, uint16_t ticks, ws_pae_lib_kmp_timer_timeout timeout) +bool ws_pae_lib_supp_list_timer_update(void *instance, supp_list_t *active_supp_list, uint16_t ticks, ws_pae_lib_kmp_timer_timeout timeout) { bool timer_running = false; ns_list_foreach_safe(supp_entry_t, entry, active_supp_list) { - bool running = ws_pae_lib_supp_timer_update(entry, ticks, timeout); + bool running = ws_pae_lib_supp_timer_update(instance, entry, ticks, timeout); if (running) { timer_running = true; } else { - ws_pae_lib_supp_list_to_inactive(active_supp_list, inactive_supp_list, entry); + ws_pae_lib_supp_list_to_inactive(instance, active_supp_list, entry); } } return timer_running; } -void ws_pae_lib_supp_list_slow_timer_update(supp_list_t *supp_list, sec_timer_cfg_t *timer_settings, uint16_t seconds) +void ws_pae_lib_supp_list_slow_timer_update(supp_list_t *supp_list, uint16_t seconds) { ns_list_foreach(supp_entry_t, entry, supp_list) { - if (sec_prot_keys_pmk_lifetime_decrement(&entry->sec_keys, timer_settings->pmk_lifetime, seconds)) { + if (sec_prot_keys_pmk_lifetime_decrement(&entry->sec_keys, seconds)) { tr_info("PMK and PTK expired, eui-64: %s, system time: %"PRIu32"", trace_array(entry->addr.eui_64, 8), protocol_core_monotonic_time / 10); } - if (sec_prot_keys_ptk_lifetime_decrement(&entry->sec_keys, timer_settings->ptk_lifetime, seconds)) { + if (sec_prot_keys_ptk_lifetime_decrement(&entry->sec_keys, seconds)) { tr_info("PTK expired, eui-64: %s, system time: %"PRIu32"", trace_array(entry->addr.eui_64, 8), protocol_core_monotonic_time / 10); } } - } void ws_pae_lib_supp_init(supp_entry_t *entry) @@ -251,6 +261,7 @@ void ws_pae_lib_supp_init(supp_entry_t *entry) memset(&entry->sec_keys, 0, sizeof(sec_prot_keys_t)); entry->ticks = 0; entry->retry_ticks = 0; + entry->store_ticks = ws_pae_key_storage_storing_interval_get() * 1000; entry->active = true; entry->access_revoked = false; } @@ -260,7 +271,7 @@ void ws_pae_lib_supp_delete(supp_entry_t *entry) ws_pae_lib_kmp_list_free(&entry->kmp_list); } -bool ws_pae_lib_supp_timer_update(supp_entry_t *entry, uint16_t ticks, ws_pae_lib_kmp_timer_timeout timeout) +bool ws_pae_lib_supp_timer_update(void *instance, supp_entry_t *entry, uint16_t ticks, ws_pae_lib_kmp_timer_timeout timeout) { // Updates KMP timers and calls timeout callback bool keep_timer_running = ws_pae_lib_kmp_timer_update(&entry->kmp_list, ticks, timeout); @@ -286,6 +297,19 @@ bool ws_pae_lib_supp_timer_update(supp_entry_t *entry, uint16_t ticks, ws_pae_li entry->retry_ticks = 0; } + if (!instance) { + return keep_timer_running; + } + + // Updates retry timer + if (entry->store_ticks > ticks) { + entry->store_ticks -= ticks; + } else { + tr_info("PAE active entry key storage update timeout"); + ws_pae_key_storage_supp_write(instance, entry); + entry->store_ticks = ws_pae_key_storage_storing_interval_get() * 1000; + } + return keep_timer_running; } @@ -326,7 +350,7 @@ void ws_pae_lib_supp_list_to_active(supp_list_t *active_supp_list, supp_list_t * entry->addr.type = KMP_ADDR_EUI_64_AND_IP; } -void ws_pae_lib_supp_list_to_inactive(supp_list_t *active_supp_list, supp_list_t *inactive_supp_list, supp_entry_t *entry) +void ws_pae_lib_supp_list_to_inactive(void *instance, supp_list_t *active_supp_list, supp_entry_t *entry) { if (!entry->active) { return; @@ -340,34 +364,28 @@ void ws_pae_lib_supp_list_to_inactive(supp_list_t *active_supp_list, supp_list_t return; } - ns_list_remove(active_supp_list, entry); - ns_list_add_to_start(inactive_supp_list, entry); + // Store to key storage + ws_pae_key_storage_supp_write(instance, entry); - entry->active = false; - entry->ticks = 0; - - // Removes relay address data - entry->addr.type = KMP_ADDR_EUI_64; - entry->addr.port = 0; - memset(entry->addr.relay_address, 0, 16); + // Remove supplicant entry + ws_pae_lib_supp_list_remove(active_supp_list, entry); } -void ws_pae_lib_supp_list_purge(supp_list_t *active_supp_list, supp_list_t *inactive_supp_list, uint16_t max_number, uint8_t max_purge) +void ws_pae_lib_supp_list_purge(supp_list_t *active_supp_list, uint16_t max_number, uint8_t max_purge) { uint16_t active_supp = ns_list_count(active_supp_list); - uint16_t inactive_supp = ns_list_count(inactive_supp_list); - if (active_supp + inactive_supp > max_number) { - uint16_t remove_count = active_supp + inactive_supp - max_number; + if (active_supp > max_number) { + uint16_t remove_count = active_supp - max_number; if (max_purge > 0 && remove_count > max_purge) { remove_count = max_purge; } - // Remove entries from inactive list - ns_list_foreach_safe(supp_entry_t, entry, inactive_supp_list) { - if (remove_count > 0) { - tr_info("Inactive supplicant removed, eui-64: %s", trace_array(kmp_address_eui_64_get(&entry->addr), 8)); - ws_pae_lib_supp_list_remove(inactive_supp_list, entry); + // Remove entries from active list if there are no active KMPs ongoing for the entry + ns_list_foreach_safe(supp_entry_t, entry, active_supp_list) { + if (remove_count > 0 && ws_pae_lib_kmp_list_empty(&entry->kmp_list)) { + tr_info("Active supplicant removed, eui-64: %s", trace_array(kmp_address_eui_64_get(&entry->addr), 8)); + ws_pae_lib_supp_list_remove(active_supp_list, entry); remove_count--; } else { break; @@ -376,6 +394,16 @@ void ws_pae_lib_supp_list_purge(supp_list_t *active_supp_list, supp_list_t *inac } } +bool ws_pae_lib_supp_list_active_limit_reached(supp_list_t *active_supp_list, uint16_t max_number) +{ + uint16_t active_supp = ns_list_count(active_supp_list); + if (active_supp > max_number) { + return true; + } + + return false; +} + uint16_t ws_pae_lib_supp_list_kmp_count(supp_list_t *supp_list, kmp_type_e type) { uint16_t kmp_count = 0; diff --git a/source/6LoWPAN/ws/ws_pae_lib.h b/source/6LoWPAN/ws/ws_pae_lib.h index b045fd00fd6..eed138e74c9 100644 --- a/source/6LoWPAN/ws/ws_pae_lib.h +++ b/source/6LoWPAN/ws/ws_pae_lib.h @@ -31,12 +31,13 @@ typedef struct { typedef NS_LIST_HEAD(kmp_entry_t, link) kmp_list_t; -typedef struct { +typedef struct supp_entry_s { kmp_list_t kmp_list; /**< Ongoing KMP negotiations */ kmp_addr_t addr; /**< EUI-64 (Relay IP address, Relay port) */ sec_prot_keys_t sec_keys; /**< Security keys */ uint32_t ticks; /**< Ticks */ uint16_t retry_ticks; /**< Retry ticks */ + uint16_t store_ticks; /**< NVM store ticks */ bool active : 1; /**< Is active */ bool access_revoked : 1; /**< Nodes access is revoked */ ns_list_link_t link; /**< Link */ @@ -123,6 +124,27 @@ kmp_api_t *ws_pae_lib_kmp_list_instance_id_get(kmp_list_t *kmp_list, uint8_t ins */ kmp_entry_t *ws_pae_lib_kmp_list_entry_get(kmp_list_t *kmp_list, kmp_api_t *kmp); +/** + * ws_pae_lib_kmp_list_empty checks whether KMP list is empty + * + * \param kmp_list KMP list + * + * \return true list is empty + * \return false list is not empty + * + */ +bool ws_pae_lib_kmp_list_empty(kmp_list_t *kmp_list); + +/** + * ws_pae_lib_kmp_list_count counts entries on KMP list + * + * \param kmp_list KMP list + * + * \return count of entries on the list + * + */ +uint8_t ws_pae_lib_kmp_list_count(kmp_list_t *kmp_list); + /** * ws_pae_lib_kmp_timer_start starts KMP timer * @@ -215,6 +237,7 @@ void ws_pae_lib_supp_list_delete(supp_list_t *supp_list); /** * ws_pae_lib_supp_list_timer_update updates timers on supplicant list * + * \param instance Instance * \param active_supp_list list of active supplicants * \param inactive_supp_list list of inactive supplicants * \param ticks timer ticks @@ -223,17 +246,16 @@ void ws_pae_lib_supp_list_delete(supp_list_t *supp_list); * \return true timer needs still to be running * \return false timer can be stopped */ -bool ws_pae_lib_supp_list_timer_update(supp_list_t *active_supp_list, supp_list_t *inactive_supp_list, uint16_t ticks, ws_pae_lib_kmp_timer_timeout timeout); +bool ws_pae_lib_supp_list_timer_update(void *instance, supp_list_t *active_supp_list, uint16_t ticks, ws_pae_lib_kmp_timer_timeout timeout); /** * ws_pae_lib_supp_list_slow_timer_update updates slow timer on supplicant list * * \param supp_list list of supplicants - * \param timer_settings timer settings * \param seconds seconds * */ -void ws_pae_lib_supp_list_slow_timer_update(supp_list_t *supp_list, sec_timer_cfg_t *timer_settings, uint16_t seconds); +void ws_pae_lib_supp_list_slow_timer_update(supp_list_t *supp_list, uint16_t seconds); /** * ws_pae_lib_supp_list_timer_update updates supplicant timers @@ -245,7 +267,7 @@ void ws_pae_lib_supp_list_slow_timer_update(supp_list_t *supp_list, sec_timer_cf * \return true timer needs still to be running * \return false timer can be stopped */ -bool ws_pae_lib_supp_timer_update(supp_entry_t *entry, uint16_t ticks, ws_pae_lib_kmp_timer_timeout timeout); +bool ws_pae_lib_supp_timer_update(void *instance, supp_entry_t *entry, uint16_t ticks, ws_pae_lib_kmp_timer_timeout timeout); /** * ws_pae_lib_supp_init initiates supplicant entry @@ -304,24 +326,34 @@ void ws_pae_lib_supp_list_to_active(supp_list_t *active_supp_list, supp_list_t * /** * ws_pae_lib_supp_list_to_inactive move supplicant to inactive supplicants list * + * \param instance Instance * \param active_supp_list list of active supplicants - * \param inactive_supp_list list of inactive supplicants * \param entry supplicant entry * */ -void ws_pae_lib_supp_list_to_inactive(supp_list_t *active_supp_list, supp_list_t *inactive_supp_list, supp_entry_t *entry); +void ws_pae_lib_supp_list_to_inactive(void *instance, supp_list_t *active_supp_list, supp_entry_t *entry); /** * ws_pae_lib_supp_list_purge purge inactive supplicants list * * \param active_supp_list list of active supplicants - * \param inactive_supp_list list of inactive supplicants * \param max_number maximum number of supplicant entries, can be set to 0 in combination with max_purge * to free list entries even when maximum number supplicant entries has not been reached * \param max_purge maximum number of supplicants to purge in one call, 0 means not limited * */ -void ws_pae_lib_supp_list_purge(supp_list_t *active_supp_list, supp_list_t *inactive_supp_list, uint16_t max_number, uint8_t max_purge); +void ws_pae_lib_supp_list_purge(supp_list_t *active_supp_list, uint16_t max_number, uint8_t max_purge); + +/** + * ws_pae_lib_supp_list_limit_reached_check check if active supplicant list limit has been reached + * + * \param active_supp_list list of active supplicants + * \param max_number maximum number of supplicant entries + * + * \return true limit has been reached + * \return false limit has not been reached + */ +bool ws_pae_lib_supp_list_active_limit_reached(supp_list_t *active_supp_list, uint16_t max_number); /** * ws_pae_lib_supp_list_kmp_count counts the number of KMPs of a certain type in a list of supplicants diff --git a/source/6LoWPAN/ws/ws_pae_nvm_data.c b/source/6LoWPAN/ws/ws_pae_nvm_data.c index 7f833430a61..3212240af83 100644 --- a/source/6LoWPAN/ws/ws_pae_nvm_data.c +++ b/source/6LoWPAN/ws/ws_pae_nvm_data.c @@ -24,38 +24,50 @@ #include "common_functions.h" #include "6LoWPAN/ws/ws_config.h" #include "ns_file_system.h" +#include "NWK_INTERFACE/Include/protocol.h" +#include "Service_Libs/utils/ns_file.h" #include "Security/protocols/sec_prot_certs.h" #include "Security/protocols/sec_prot_keys.h" #include "6LoWPAN/ws/ws_pae_nvm_store.h" #include "6LoWPAN/ws/ws_pae_nvm_data.h" +#include "6LoWPAN/ws/ws_pae_controller.h" +#include "6LoWPAN/ws/ws_pae_time.h" #ifdef HAVE_WS #define TRACE_GROUP "wsnv" -#define PAE_NVM_NW_INFO_TAG 1 -#define PAE_NVM_KEYS_TAG 2 -#define PAE_NVM_FRAME_COUNTER_TAG 3 - -// pan_id (2) + network name (33) + (GTK set (1) + GTK lifetime (4) + GTK (16)) * 4 -#define PAE_NVM_NW_INFO_LEN 2 + 33 + (1 + 4 + GTK_LEN) * GTK_NUM +#define PAE_NVM_FIELD_NOT_SET 0 // Field is not present +#define PAE_NVM_FIELD_SET 1 // Field is present -// PTK EUI-64 set (1) + PTK EUI-64 (8) + PMK set (1) + PMK (32) + PMK replay counter (8) + PTK set (1) + PTK (48) -#define PAE_NVM_KEYS_LEN 1 + 8 + 1 + PMK_LEN + 8 + 1 + PTK_LEN +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; +} -// (frame counter set (1) + GTK (16) + frame counter (4)) * 4 -#define PAE_NVM_FRAME_COUNTER_LEN (1 + GTK_LEN + 4) * GTK_NUM +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; -#define PAE_NVM_FIELD_NOT_SET 0 // Field is not present -#define PAE_NVM_FIELD_SET 1 // Field is present + return tlv_entry; +} -nvm_tlv_entry_t *ws_pae_buffer_allocate(void) +void ws_pae_nvm_store_generic_tlv_free(nvm_tlv_t *tlv_entry) { - //Allocate worts case buffer - return ns_dyn_mem_temporary_alloc(sizeof(nvm_tlv_entry_t) + PAE_NVM_NW_INFO_LEN); + if (!tlv_entry) { + return; + } + + ns_dyn_mem_free(tlv_entry); } -void ws_pae_nvm_store_nw_info_tlv_create(nvm_tlv_entry_t *tlv_entry, uint16_t pan_id, char *nw_name, sec_prot_gtk_keys_t *gtks) +void ws_pae_nvm_store_nw_info_tlv_create(nvm_tlv_t *tlv_entry, uint16_t pan_id, char *nw_name, sec_prot_gtk_keys_t *gtks) { int len; tlv_entry->tag = PAE_NVM_NW_INFO_TAG; @@ -75,19 +87,31 @@ void ws_pae_nvm_store_nw_info_tlv_create(nvm_tlv_entry_t *tlv_entry, uint16_t pa memcpy((char *)tlv, nw_name, len); tlv += 33; + uint64_t current_time = ws_pae_current_time_get(); + for (uint8_t i = 0; i < GTK_NUM; i++) { - if (sec_prot_keys_gtk_is_set(gtks, i)) { + if (gtks && sec_prot_keys_gtk_is_set(gtks, i)) { *tlv++ = PAE_NVM_FIELD_SET; // GTK is set - uint32_t lifetime = sec_prot_keys_gtk_lifetime_get(gtks, i); - tlv = common_write_32_bit(lifetime, tlv); + + uint64_t expirytime = sec_prot_keys_gtk_exptime_from_lifetime_get(gtks, i, current_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); + + tlv = common_write_64_bit(expirytime, tlv); + + uint8_t status = sec_prot_keys_gtk_status_get(gtks, i); + *tlv++ = status; + + uint8_t install_order = sec_prot_keys_gtk_install_order_get(gtks, i); + *tlv++ = install_order; uint8_t *gtk = sec_prot_keys_gtk_get(gtks, i); memcpy(tlv, gtk, GTK_LEN); tlv += GTK_LEN; } else { *tlv++ = PAE_NVM_FIELD_NOT_SET; // GTK is not set - memset(tlv, 0, 4 + GTK_LEN); - tlv += 4 + GTK_LEN; + memset(tlv, 0, 8 + 1 + 1 + GTK_LEN); + tlv += 8 + 1 + 1 + GTK_LEN; } } @@ -95,9 +119,9 @@ void ws_pae_nvm_store_nw_info_tlv_create(nvm_tlv_entry_t *tlv_entry, uint16_t pa } -int8_t ws_pae_nvm_store_nw_info_tlv_read(nvm_tlv_entry_t *tlv_entry, uint16_t *pan_id, char *nw_name, sec_prot_gtk_keys_t *gtks) +int8_t ws_pae_nvm_store_nw_info_tlv_read(nvm_tlv_t *tlv_entry, uint16_t *pan_id, char *nw_name, sec_prot_gtk_keys_t *gtks) { - if (!tlv_entry || !pan_id || !nw_name || !gtks) { + if (!tlv_entry || !pan_id || !nw_name) { return -1; } @@ -107,31 +131,60 @@ int8_t ws_pae_nvm_store_nw_info_tlv_read(nvm_tlv_entry_t *tlv_entry, uint16_t *p uint8_t *tlv = ((uint8_t *) &tlv_entry->tag) + NVM_TLV_FIXED_LEN; - *pan_id = common_read_16_bit(tlv); + if (*pan_id == 0xffff) { + // If application has not set pan_id read it from NVM + *pan_id = common_read_16_bit(tlv); + } tlv += 2; - memset(nw_name, 0, 33); - strncpy(nw_name, (char *) tlv, 32); + if (strlen(nw_name) == 0) { + // If application has not set network name read it from NVM + memset(nw_name, 0, 33); + strncpy(nw_name, (char *) tlv, 32); + } tlv += 33; - for (uint8_t i = 0; i < GTK_NUM; i++) { - if (*tlv++ == PAE_NVM_FIELD_SET) { /* GTK is set */ - uint32_t lifetime = common_read_32_bit(tlv); - tlv += 4; - sec_prot_keys_gtk_set(gtks, i, tlv, lifetime); - tlv += GTK_LEN; - } else { - tlv += 4 + GTK_LEN; + uint64_t current_time = ws_pae_current_time_get(); + + tr_debug("NVM NW_INFO current time: %"PRIi64, current_time); + + if (gtks && sec_prot_keys_gtk_count(gtks) == 0) { + // If application has not set GTKs read them from NVM + for (uint8_t i = 0; i < GTK_NUM; i++) { + if (*tlv++ == PAE_NVM_FIELD_SET) { /* GTK is set */ + uint64_t expirytime = common_read_64_bit(tlv); + uint32_t lifetime = 0; + 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); + continue; + } + tlv += 8; + + uint8_t status = *tlv++; + + 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); + + sec_prot_keys_gtk_set(gtks, i, tlv, lifetime); + sec_prot_keys_gtk_expirytime_set(gtks, i, expirytime); + tlv += GTK_LEN; + sec_prot_keys_gtk_status_set(gtks, i, status); + sec_prot_keys_gtk_install_order_set(gtks, i, install_order); + } else { + tlv += 8 + 1 + 1 + GTK_LEN; + } } + sec_prot_keys_gtks_updated_reset(gtks); } - sec_prot_keys_gtks_updated_reset(gtks); tr_debug("NVM NW_INFO read PAN ID %i name: %s", *pan_id, nw_name); return 0; } -void ws_pae_nvm_store_keys_tlv_create(nvm_tlv_entry_t *tlv_entry, sec_prot_keys_t *sec_keys) +void ws_pae_nvm_store_keys_tlv_create(nvm_tlv_t *tlv_entry, sec_prot_keys_t *sec_keys) { tlv_entry->tag = PAE_NVM_KEYS_TAG; tlv_entry->len = PAE_NVM_KEYS_LEN; @@ -151,10 +204,12 @@ void ws_pae_nvm_store_keys_tlv_create(nvm_tlv_entry_t *tlv_entry, sec_prot_keys_ uint8_t *pmk = sec_prot_keys_pmk_get(sec_keys); if (pmk) { *tlv++ = PAE_NVM_FIELD_SET; + uint32_t lifetime = sec_prot_keys_pmk_lifetime_get(sec_keys); + tlv = common_write_32_bit(lifetime, tlv); memcpy(tlv, pmk, PMK_LEN); } else { *tlv++ = PAE_NVM_FIELD_NOT_SET; - memset(tlv, 0, PMK_LEN); + memset(tlv, 0, 4 + PMK_LEN); } tlv += PMK_LEN; @@ -164,18 +219,19 @@ void ws_pae_nvm_store_keys_tlv_create(nvm_tlv_entry_t *tlv_entry, sec_prot_keys_ uint8_t *ptk = sec_prot_keys_ptk_get(sec_keys); if (ptk) { *tlv++ = PAE_NVM_FIELD_SET; + uint32_t lifetime = sec_prot_keys_ptk_lifetime_get(sec_keys); + tlv = common_write_32_bit(lifetime, tlv); memcpy(tlv, ptk, PTK_LEN); } else { *tlv++ = PAE_NVM_FIELD_NOT_SET; - memset(tlv, 0, PTK_LEN); + memset(tlv, 0, 4 + PTK_LEN); } tlv += PTK_LEN; tr_debug("NVM KEYS write"); - } -int8_t ws_pae_nvm_store_keys_tlv_read(nvm_tlv_entry_t *tlv_entry, sec_prot_keys_t *sec_keys) +int8_t ws_pae_nvm_store_keys_tlv_read(nvm_tlv_t *tlv_entry, sec_prot_keys_t *sec_keys) { if (!tlv_entry || !sec_keys) { return -1; @@ -195,7 +251,11 @@ int8_t ws_pae_nvm_store_keys_tlv_read(nvm_tlv_entry_t *tlv_entry, sec_prot_keys_ // PMK set if (*tlv++ == PAE_NVM_FIELD_SET) { - sec_prot_keys_pmk_write(sec_keys, tlv); + uint32_t lifetime = common_read_32_bit(tlv); + tlv += 4; + sec_prot_keys_pmk_write(sec_keys, tlv, lifetime); + } else { + tlv += 4; } tlv += PMK_LEN; @@ -205,7 +265,11 @@ int8_t ws_pae_nvm_store_keys_tlv_read(nvm_tlv_entry_t *tlv_entry, sec_prot_keys_ // PTK set if (*tlv++ == PAE_NVM_FIELD_SET) { - sec_prot_keys_ptk_write(sec_keys, tlv); + uint32_t lifetime = common_read_32_bit(tlv); + tlv += 4; + sec_prot_keys_ptk_write(sec_keys, tlv, lifetime); + } else { + tlv += 4; } tlv += PTK_LEN; @@ -217,13 +281,18 @@ int8_t ws_pae_nvm_store_keys_tlv_read(nvm_tlv_entry_t *tlv_entry, sec_prot_keys_ return 0; } -void ws_pae_nvm_store_frame_counter_tlv_create(nvm_tlv_entry_t *tlv_entry, frame_counters_t *counters) +void ws_pae_nvm_store_frame_counter_tlv_create(nvm_tlv_t *tlv_entry, uint32_t restart_cnt, frame_counters_t *counters) { tlv_entry->tag = PAE_NVM_FRAME_COUNTER_TAG; tlv_entry->len = PAE_NVM_FRAME_COUNTER_LEN; uint8_t *tlv = ((uint8_t *) &tlv_entry->tag) + NVM_TLV_FIXED_LEN; + 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); + for (uint8_t index = 0; index < GTK_NUM; index++) { if (!counters->counter[index].set) { *tlv++ = PAE_NVM_FIELD_NOT_SET; @@ -240,7 +309,7 @@ void ws_pae_nvm_store_frame_counter_tlv_create(nvm_tlv_entry_t *tlv_entry, frame tr_debug("NVM FRAME COUNTER write"); } -int8_t ws_pae_nvm_store_frame_counter_tlv_read(nvm_tlv_entry_t *tlv_entry, frame_counters_t *counters) +int8_t ws_pae_nvm_store_frame_counter_tlv_read(nvm_tlv_t *tlv_entry, uint32_t *restart_cnt, uint64_t *stored_time, frame_counters_t *counters) { if (!tlv_entry || !counters) { return -1; @@ -252,6 +321,12 @@ int8_t ws_pae_nvm_store_frame_counter_tlv_read(nvm_tlv_entry_t *tlv_entry, frame uint8_t *tlv = ((uint8_t *) &tlv_entry->tag) + NVM_TLV_FIXED_LEN; + *restart_cnt = common_read_32_bit(tlv); + tlv += 4; + + *stored_time = common_read_64_bit(tlv); + tlv += 8; + for (uint8_t index = 0; index < GTK_NUM; index++) { // Frame counter not set if (*tlv++ == PAE_NVM_FIELD_NOT_SET) { @@ -272,5 +347,61 @@ int8_t ws_pae_nvm_store_frame_counter_tlv_read(nvm_tlv_entry_t *tlv_entry, frame return 0; } +void ws_pae_nvm_store_key_storage_index_tlv_create(nvm_tlv_t *tlv_entry, uint64_t bitfield) +{ + tlv_entry->tag = PAE_NVM_KEY_STORAGE_INDEX_TAG; + tlv_entry->len = PAE_NVM_KEY_STORAGE_INDEX_LEN; + + uint8_t *tlv = ((uint8_t *) &tlv_entry->tag) + NVM_TLV_FIXED_LEN; + + tlv = common_write_64_bit(bitfield, tlv); + + tr_debug("NVM KEY STORAGE INDEX write"); +} + +int8_t ws_pae_nvm_store_key_storage_index_tlv_read(nvm_tlv_t *tlv_entry, uint64_t *bitfield) +{ + if (!tlv_entry || !bitfield) { + return -1; + } + + if (tlv_entry->tag != PAE_NVM_KEY_STORAGE_INDEX_TAG || tlv_entry->len != PAE_NVM_KEY_STORAGE_INDEX_LEN) { + return -1; + } + + uint8_t *tlv = ((uint8_t *) &tlv_entry->tag) + NVM_TLV_FIXED_LEN; + *bitfield = common_read_64_bit(tlv); + tlv += 8; + + tr_debug("NVM KEY STORAGE INDEX read"); + + return 0; +} + +void ws_pae_nvm_store_key_storage_tlv_create(nvm_tlv_t *tlv_entry, uint16_t length) +{ + memset(tlv_entry, 0, sizeof(key_storage_nvm_tlv_entry_t)); + + tlv_entry->tag = PAE_NVM_KEY_STORAGE_TAG; + tlv_entry->len = length - sizeof(nvm_tlv_t); + + tr_debug("NVM KEY STORAGE create"); +} + +int8_t ws_pae_nvm_store_key_storage_tlv_read(nvm_tlv_t *tlv_entry, uint16_t length) +{ + if (!tlv_entry || !length) { + return -1; + } + + if (tlv_entry->tag != PAE_NVM_KEY_STORAGE_TAG || tlv_entry->len != length - sizeof(nvm_tlv_t)) { + return -1; + } + + tr_debug("NVM KEY STORAGE read"); + + return 0; +} + #endif /* HAVE_WS */ diff --git a/source/6LoWPAN/ws/ws_pae_nvm_data.h b/source/6LoWPAN/ws/ws_pae_nvm_data.h index 86ebedad806..c55d56412b0 100644 --- a/source/6LoWPAN/ws/ws_pae_nvm_data.h +++ b/source/6LoWPAN/ws/ws_pae_nvm_data.h @@ -24,10 +24,52 @@ * */ +// file names +#define NW_INFO_FILE_NAME "pae_nw_info" +#define KEYS_FILE_NAME "pae_keys" +#define FRAME_COUNTER_FILE_NAME "pae_frame_counter" + +#define PAE_NVM_NW_INFO_TAG 1 +#define PAE_NVM_KEYS_TAG 2 +#define PAE_NVM_FRAME_COUNTER_TAG 3 +#define PAE_NVM_KEY_STORAGE_INDEX_TAG 4 +#define PAE_NVM_KEY_STORAGE_TAG 5 + +// pan_id (2) + network name (33) + (GTK set (1) + GTK expiry timestamp (8) + status (1) + install order (1) + GTK (16)) * 4 +#define PAE_NVM_NW_INFO_LEN 2 + 33 + (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 + (frame counter set (1) + GTK (16) + frame counter (4)) * 4 +#define PAE_NVM_FRAME_COUNTER_LEN 4 + 8 + (1 + GTK_LEN + 4) * GTK_NUM + +#define PAE_NVM_DEFAULT_BUFFER_SIZE sizeof(nvm_tlv_t) + PAE_NVM_NW_INFO_LEN + +// key storage index bitfield (8) +#define PAE_NVM_KEY_STORAGE_INDEX_LEN 8 + +/** + * 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); + +nvm_tlv_t *ws_pae_nvm_store_generic_tlv_allocate_and_create(uint16_t tag, uint16_t length); + +void ws_pae_nvm_store_generic_tlv_free(nvm_tlv_t *tlv_entry); + /** * ws_pae_nvm_store_nw_info_tlv_create create NVM network info TLV * - * \param tlv_entry TLV entry pointer + * \param tlv_entry TLV * \param pan_id PAN ID * \param nw_name network name * \param gtks GTK keys @@ -35,12 +77,12 @@ * \return TLV entry or NULL * */ -void ws_pae_nvm_store_nw_info_tlv_create(nvm_tlv_entry_t *tlv_entry, uint16_t pan_id, char *nw_name, sec_prot_gtk_keys_t *gtks); +void ws_pae_nvm_store_nw_info_tlv_create(nvm_tlv_t *tlv_entry, uint16_t pan_id, char *nw_name, sec_prot_gtk_keys_t *gtks); /** * ws_pae_nvm_store_nw_info_tlv_read read from NVM network info TLV * - * \param tlv_entry TLV entry + * \param tlv_entry TLV * \param pan_id PAN ID * \param nw_name network name * \param gtks GTK keys @@ -49,50 +91,101 @@ void ws_pae_nvm_store_nw_info_tlv_create(nvm_tlv_entry_t *tlv_entry, uint16_t pa * \return >= 0 success * */ -int8_t ws_pae_nvm_store_nw_info_tlv_read(nvm_tlv_entry_t *tlv_entry, uint16_t *pan_id, char *nw_name, sec_prot_gtk_keys_t *gtks); +int8_t ws_pae_nvm_store_nw_info_tlv_read(nvm_tlv_t *tlv_entry, uint16_t *pan_id, char *nw_name, sec_prot_gtk_keys_t *gtks); /** * ws_pae_nvm_store_keys_tlv_create create NVM keys TLV * - * \param tlv_entry TLV entry buffer pointer + * \param tlv_entry TLV * \param sec_keys security keys * */ -void ws_pae_nvm_store_keys_tlv_create(nvm_tlv_entry_t *tlv_entry, sec_prot_keys_t *sec_keys); +void ws_pae_nvm_store_keys_tlv_create(nvm_tlv_t *tlv_entry, sec_prot_keys_t *sec_keys); /** * ws_pae_nvm_store_nw_info_tlv_read read from NVM keys TLV * - * \param tlv_entry TLV entry + * \param tlv_entry TLV * \param sec_keys security keys * * \return < 0 failure * \return >= 0 success * */ -int8_t ws_pae_nvm_store_keys_tlv_read(nvm_tlv_entry_t *tlv_entry, sec_prot_keys_t *sec_keys); +int8_t ws_pae_nvm_store_keys_tlv_read(nvm_tlv_t *tlv_entry, sec_prot_keys_t *sec_keys); /** * ws_pae_nvm_store_frame_counter_tlv_create create NVM frame counter TLV * - * \param tlv_entry TLV entry buffer pointer + * \param tlv_entry TLV buffer pointer + * \param restart_cnt re-start counter * \param counters frame counters * */ -void ws_pae_nvm_store_frame_counter_tlv_create(nvm_tlv_entry_t *tlv_entry, frame_counters_t *counters); +void ws_pae_nvm_store_frame_counter_tlv_create(nvm_tlv_t *tlv_entry, uint32_t restart_cnt, frame_counters_t *counters); /** * ws_pae_nvm_store_frame_counter_tlv_read read from NVM frame counter TLV * - * \param tlv_entry TLV entry + * \param tlv_entry TLV + * \param restart_cnt re-start counter + * \param stored_time stored timestampt * \param counters frame counters * * \return < 0 failure * \return >= 0 success * */ -int8_t ws_pae_nvm_store_frame_counter_tlv_read(nvm_tlv_entry_t *tlv_entry, frame_counters_t *counters); +int8_t ws_pae_nvm_store_frame_counter_tlv_read(nvm_tlv_t *tlv_entry, uint32_t *restart_cnt, uint64_t *stored_time, frame_counters_t *counters); + +/** + * ws_pae_nvm_store_key_storage_index_tlv_create create NVM key storage index TLV + * + * \param tlv_entry TLV entry + * \param bitfield index of filenames + * + * \return < 0 failure + * \return >= 0 success + * + */ +void ws_pae_nvm_store_key_storage_index_tlv_create(nvm_tlv_t *tlv_entry, uint64_t bitfield); + +/** + * ws_pae_nvm_store_key_storage_index_tlv_read read NVM key storage index TLV + * + * \param tlv_entry TLV entry + * \param bitfield index of filenames + * + * \return < 0 failure + * \return >= 0 success + * + */ +int8_t ws_pae_nvm_store_key_storage_index_tlv_read(nvm_tlv_t *tlv_entry, uint64_t *bitfield); + +/** + * ws_pae_nvm_store_key_storage_tlv_create create NVM key storage TLV + * + * \param tlv_entry TLV entry + * \param length length of the (whole) entry + * + * \return < 0 failure + * \return >= 0 success + * + */ +void ws_pae_nvm_store_key_storage_tlv_create(nvm_tlv_t *tlv_entry, uint16_t length); + +/** + * ws_pae_nvm_store_key_storage_tlv_read read NVM key storage TLV + * + * \param tlv_entry TLV entry + * \param length length of the (whole) entry + * + * \return < 0 failure + * \return >= 0 success + * + */ +int8_t ws_pae_nvm_store_key_storage_tlv_read(nvm_tlv_t *tlv_entry, uint16_t length); -nvm_tlv_entry_t *ws_pae_buffer_allocate(void); +nvm_tlv_t *ws_pae_buffer_allocate(void); #endif /* WS_PAE_NVM_DATA_H_ */ diff --git a/source/6LoWPAN/ws/ws_pae_nvm_store.c b/source/6LoWPAN/ws/ws_pae_nvm_store.c index aa873bdf865..b4a9108bcad 100644 --- a/source/6LoWPAN/ws/ws_pae_nvm_store.c +++ b/source/6LoWPAN/ws/ws_pae_nvm_store.c @@ -17,7 +17,6 @@ #include "nsconfig.h" #include -#include #include "ns_types.h" #include "ns_list.h" #include "ns_trace.h" @@ -25,9 +24,11 @@ #include "common_functions.h" #include "6LoWPAN/ws/ws_config.h" #include "ns_file_system.h" +#include "Service_Libs/utils/ns_file.h" #include "Security/protocols/sec_prot_certs.h" #include "Security/protocols/sec_prot_keys.h" #include "6LoWPAN/ws/ws_pae_nvm_store.h" +#include "ns_file_system.h" #ifdef HAVE_WS @@ -39,10 +40,10 @@ static uint16_t ws_pae_nvm_store_path_len_get(const char *file_name); static const char *ws_pae_nvm_store_get_root_path(void); static int8_t ws_pae_nvm_store_root_path_valid(void); static int8_t ws_pae_nvm_store_create_path(char *fast_data_path, const char *file_name); -static int8_t ws_pae_nvm_store_write(const char *file_name, nvm_tlv_list_t *tlv_list); -static int8_t ws_pae_nvm_store_read(const char *file_name, nvm_tlv_list_t *tlv_list); +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); -int8_t ws_pae_nvm_store_tlv_file_write(const char *file, nvm_tlv_list_t *tlv_list) +int8_t ws_pae_nvm_store_tlv_file_write(const char *file, nvm_tlv_t *tlv) { if (!ws_pae_nvm_store_root_path_valid()) { return PAE_NVM_FILE_ROOT_PATH_INVALID; @@ -54,10 +55,10 @@ int8_t ws_pae_nvm_store_tlv_file_write(const char *file, nvm_tlv_list_t *tlv_lis ws_pae_nvm_store_create_path(nw_info_path, file); - return ws_pae_nvm_store_write(nw_info_path, tlv_list); + return ws_pae_nvm_store_write(nw_info_path, tlv); } -int8_t ws_pae_nvm_store_tlv_file_read(const char *file, nvm_tlv_list_t *tlv_list) +int8_t ws_pae_nvm_store_tlv_file_read(const char *file, nvm_tlv_t *tlv) { if (!ws_pae_nvm_store_root_path_valid()) { return PAE_NVM_FILE_ROOT_PATH_INVALID; @@ -69,7 +70,27 @@ int8_t ws_pae_nvm_store_tlv_file_read(const char *file, nvm_tlv_list_t *tlv_list ws_pae_nvm_store_create_path(nw_info_path, file); - return ws_pae_nvm_store_read(nw_info_path, tlv_list); + return ws_pae_nvm_store_read(nw_info_path, tlv); +} + +int8_t ws_pae_nvm_store_tlv_file_remove(const char *file) +{ + if (!ws_pae_nvm_store_root_path_valid()) { + return PAE_NVM_FILE_ROOT_PATH_INVALID; + } + + uint16_t path_len = ws_pae_nvm_store_path_len_get(file); + + char nw_info_path[path_len]; + + ws_pae_nvm_store_create_path(nw_info_path, file); + + int ret = ns_fremove(nw_info_path); + if (ret < 0) { + return -1; + } + + return 0; } static const char *ws_pae_nvm_store_get_root_path(void) @@ -106,104 +127,49 @@ static int8_t ws_pae_nvm_store_create_path(char *data_path, const char *file_nam return 0; } -static int8_t ws_pae_nvm_store_write(const char *file_name, nvm_tlv_list_t *tlv_list) +static int8_t ws_pae_nvm_store_write(const char *file_name, nvm_tlv_t *tlv) { - FILE *fp = fopen(file_name, "w"); + if (!file_name || !tlv) { + return -1; + } + + NS_FILE *fp = ns_fopen(file_name, "w"); if (fp == NULL) { tr_error("NVM open error: %s", file_name); return PAE_NVM_FILE_CANNOT_OPEN; } - uint16_t list_count = ns_list_count(tlv_list); - size_t n_bytes = fwrite(&list_count, 1, sizeof(uint16_t), fp); - if (n_bytes != sizeof(uint16_t)) { - tr_warning("NVM TLV list count write error"); - fclose(fp); - return PAE_NVM_FILE_WRITE_ERROR; - } - - bool failure = false; - - ns_list_foreach(nvm_tlv_entry_t, entry, tlv_list) { - n_bytes = fwrite(&entry->tag, 1, entry->len + NVM_TLV_FIXED_LEN, fp); - if (n_bytes != (size_t) entry->len + NVM_TLV_FIXED_LEN) { - failure = true; - break; - } - } - - fclose(fp); - if (failure) { + size_t n_bytes = ns_fwrite(fp, tlv, tlv->len + sizeof(nvm_tlv_t)); + ns_fclose(fp); + if (n_bytes != tlv->len + sizeof(nvm_tlv_t)) { tr_error("NVM write error %s", file_name); return PAE_NVM_FILE_WRITE_ERROR; - } else { - return PAE_NVM_FILE_SUCCESS; } + + return PAE_NVM_FILE_SUCCESS; } -static int8_t ws_pae_nvm_store_read(const char *file_name, nvm_tlv_list_t *tlv_list) +static int8_t ws_pae_nvm_store_read(const char *file_name, nvm_tlv_t *tlv) { - FILE *fp = fopen(file_name, "r"); + if (!file_name || !tlv) { + return -1; + } + + NS_FILE *fp = ns_fopen(file_name, "r"); if (fp == NULL) { tr_warning("File not found: %s", file_name); return PAE_NVM_FILE_CANNOT_OPEN; } - uint16_t list_count; - size_t n_bytes = fread(&list_count, 1, sizeof(uint16_t), fp); - if (n_bytes != sizeof(uint16_t)) { - tr_warning("NVM TLV list count read error %s", file_name); - fclose(fp); + size_t n_bytes = ns_fread(fp, tlv, tlv->len + sizeof(nvm_tlv_t)); + ns_fclose(fp); + if (n_bytes != tlv->len + sizeof(nvm_tlv_t)) { + tr_warning("File not found or cannot be read: %s", file_name); return PAE_NVM_FILE_READ_ERROR; } - bool failure = false; - - while (list_count-- > 0) { - nvm_tlv_entry_t entry_header; - memset(&entry_header, 0, sizeof(nvm_tlv_entry_t)); - n_bytes = fread(&entry_header.tag, 1, NVM_TLV_FIXED_LEN, fp); - if (n_bytes != NVM_TLV_FIXED_LEN) { - failure = true; - break; - } - uint16_t len = entry_header.len; - - nvm_tlv_entry_t *entry = ns_dyn_mem_temporary_alloc(sizeof(nvm_tlv_entry_t) + len); - if (!entry) { - failure = true; - break; - } - - memcpy(&entry->tag, &entry_header.tag, NVM_TLV_FIXED_LEN); - - if (len > 0) { - uint8_t *data_ptr = ((uint8_t *)&entry->tag) + NVM_TLV_FIXED_LEN; - n_bytes = fread(data_ptr, 1, len, fp); - if (n_bytes != len) { - ns_dyn_mem_free(entry); - failure = true; - break; - } - } - - ns_list_add_to_end(tlv_list, entry); - } - - fclose(fp); - - if (failure) { - ns_list_foreach_safe(nvm_tlv_entry_t, entry, tlv_list) { - ns_list_remove(tlv_list, entry); - ns_dyn_mem_free(entry); - } - tr_error("NVM read error %s", file_name); - return PAE_NVM_FILE_READ_ERROR; - } else { - return PAE_NVM_FILE_SUCCESS; // return how many bytes was written. - } + return PAE_NVM_FILE_SUCCESS; } - #endif /* HAVE_WS */ diff --git a/source/6LoWPAN/ws/ws_pae_nvm_store.h b/source/6LoWPAN/ws/ws_pae_nvm_store.h index 84838ef6f37..fb741da8331 100644 --- a/source/6LoWPAN/ws/ws_pae_nvm_store.h +++ b/source/6LoWPAN/ws/ws_pae_nvm_store.h @@ -24,22 +24,6 @@ * */ -// tag + length -#define NVM_TLV_FIXED_LEN 4 - -// file names -#define NW_INFO_FILE_NAME "pae_nw_info" -#define KEYS_FILE_NAME "pae_keys" -#define FRAME_COUNTER_FILE_NAME "pae_frame_counter" - -typedef struct nvm_tlv_entry { - ns_list_link_t link; /**< Link */ - uint16_t tag; /**< Unique tag */ - uint16_t len; /**< Number of the bytes after the length field */ -} nvm_tlv_entry_t; - -typedef NS_LIST_HEAD(nvm_tlv_entry_t, link) nvm_tlv_list_t; - #define PAE_NVM_FILE_SUCCESS 0 #define PAE_NVM_FILE_READ_ERROR -1 #define PAE_NVM_FILE_WRITE_ERROR -2 @@ -49,28 +33,53 @@ typedef NS_LIST_HEAD(nvm_tlv_entry_t, link) nvm_tlv_list_t; #define PAE_NVM_FILE_PARAMETER_INVALID -6 #define PAE_NVM_FILE_REMOVE_ERROR -7 +typedef struct nvm_tlv { + uint16_t tag; /**< Unique tag */ + uint16_t len; /**< Number of the bytes after the length field */ +} nvm_tlv_t; + +typedef struct { + nvm_tlv_t nvm_tlv; /**< NVM TLV */ + uint64_t reference_time; /**< Reference time used for timers (set when file is created) */ + uint32_t reference_restart_cnt; /**< Reference re-start counter set when file is created) */ +} key_storage_nvm_tlv_entry_t; + +// tag + length +#define NVM_TLV_FIXED_LEN sizeof(nvm_tlv_t) + /** * ws_pae_nvm_store_tlv_file_write write a list of TLVs to file * * \param file file name - * \param tlv_list TLV list + * \param tlv TLV * * \return < 0 failure * \return >= 0 success * */ -int8_t ws_pae_nvm_store_tlv_file_write(const char *file, nvm_tlv_list_t *tlv_list); +int8_t ws_pae_nvm_store_tlv_file_write(const char *file, nvm_tlv_t *tlv); /** * ws_pae_nvm_store_tlv_file_read read a list of TLVs from file * * \param file file name - * \param tlv_list TLV list + * \param tlv TLV + * + * \return < 0 failure + * \return >= 0 success + * + */ +int8_t ws_pae_nvm_store_tlv_file_read(const char *file, nvm_tlv_t *tlv); + +/** + * ws_pae_nvm_store_tlv_file_remove delete a file + * + * \param file file name * * \return < 0 failure * \return >= 0 success * */ -int8_t ws_pae_nvm_store_tlv_file_read(const char *file, nvm_tlv_list_t *tlv_list); +int8_t ws_pae_nvm_store_tlv_file_remove(const char *file); #endif /* WS_PAE_NVM_STORE_H_ */ diff --git a/source/6LoWPAN/ws/ws_pae_supp.c b/source/6LoWPAN/ws/ws_pae_supp.c index a9e955366ea..7954010d508 100644 --- a/source/6LoWPAN/ws/ws_pae_supp.c +++ b/source/6LoWPAN/ws/ws_pae_supp.c @@ -28,6 +28,7 @@ #include "eventOS_scheduler.h" #include "eventOS_event_timer.h" #include "ns_address.h" +#include "Service_Libs/utils/ns_file.h" #include "NWK_INTERFACE/Include/protocol.h" #include "RPL/rpl_protocol.h" #include "RPL/rpl_control.h" @@ -48,6 +49,7 @@ #include "6LoWPAN/ws/ws_pae_timers.h" #include "6LoWPAN/ws/ws_pae_supp.h" #include "6LoWPAN/ws/ws_pae_lib.h" +#include "6LoWPAN/ws/ws_pae_time.h" #include "6LoWPAN/ws/ws_pae_nvm_store.h" #include "6LoWPAN/ws/ws_pae_nvm_data.h" #include "6LoWPAN/MAC/mpx_api.h" @@ -79,31 +81,25 @@ #define INITIAL_KEY_TIMER_MIN 3 #define INITIAL_KEY_TIMER_MAX 30 -typedef struct { - char network_name[33]; /**< Network name for keys */ - sec_prot_gtk_keys_t *gtks; /**< Link to GTKs */ - uint16_t new_pan_id; /**< new PAN ID indicated by bootstrap */ - uint16_t key_pan_id; /**< PAN ID for keys */ - bool updated : 1; /**< Network info has been updated */ -} sec_prot_keys_nw_info_t; - typedef struct { ns_list_link_t link; /**< Link */ kmp_service_t *kmp_service; /**< KMP service */ protocol_interface_info_entry_t *interface_ptr; /**< Interface */ ws_pae_supp_auth_completed *auth_completed; /**< Authentication completed callback, continue bootstrap */ + ws_pae_supp_auth_next_target *auth_next_target; /**< Authentication next target callback */ ws_pae_supp_nw_key_insert *nw_key_insert; /**< Key insert callback */ ws_pae_supp_nw_key_index_set *nw_key_index_set; /**< Key index set callback */ ws_pae_supp_gtk_hash_ptr_get *gtk_hash_ptr_get; /**< Get pointer to GTK hash storage callback */ + ws_pae_supp_nw_info_updated *nw_info_updated; /**< Security keys network info updated callback */ supp_entry_t entry; /**< Supplicant data */ kmp_addr_t target_addr; /**< EAPOL target (parent) address */ uint16_t initial_key_timer; /**< Timer to trigger initial EAPOL-Key */ uint16_t initial_key_retry_timer; /**< Timer to trigger initial EAPOL-Key 1st retry */ trickle_t auth_trickle_timer; /**< Trickle timer for re-sending initial EAPOL-key or for GTK mismatch */ trickle_params_t auth_trickle_params; /**< Trickle parameters for initial EAPOL-key or for GTK mismatch */ - sec_prot_gtk_keys_t gtks; /**< GTKs */ - uint8_t new_br_eui_64[8]; /**< Border router EUI-64 indicated by bootstrap */ - sec_prot_keys_nw_info_t sec_keys_nw_info; /**< Security keys network information */ + uint8_t new_br_eui_64[8]; /**< Border router EUI-64 indicated by bootstrap after bootstrap start */ + uint8_t comp_br_eui_64[8]; /**< Border router EUI-64 indicated by bootstrap after bootstrap completed */ + sec_prot_keys_nw_info_t *sec_keys_nw_info; /**< Security keys network information */ sec_timer_cfg_t *sec_timer_cfg; /**< Timer configuration */ sec_prot_cfg_t *sec_prot_cfg; /**< Protocol Configuration */ uint8_t nw_keys_used_cnt; /**< How many times bootstrap has been tried with current keys */ @@ -111,47 +107,26 @@ typedef struct { bool auth_trickle_running : 1; /**< Initial EAPOL-Key Trickle timer running */ bool auth_requested : 1; /**< Authentication has been requested by the bootstrap */ bool timer_running : 1; /**< Timer is running */ - bool new_br_eui_64_set : 1; /**< Border router address has been set */ + bool new_br_eui_64_set : 1; /**< Border router address has been set after bootstrap start */ bool new_br_eui_64_fresh : 1; /**< Border router address is fresh (set during this authentication attempt) */ - bool entry_address_active: 1; + bool comp_br_eui_64_set : 1; /**< Border router address has been set after bootstrap completed */ + bool entry_address_active: 1; /**< EAPOL target address is set */ + bool tx_failure_on_initial_key: 1; /**< TX failure has happened on initial EAPOL-key sequence */ } pae_supp_t; -// How many times sending of initial EAPOL-key is retried -#define INITIAL_KEY_RETRY_COUNT 2 - // How many times sending of initial EAPOL-key is initiated on key update #define KEY_UPDATE_RETRY_COUNT 3 #define LIFETIME_MISMATCH_RETRY_COUNT 1 /* No retries */ -// How long the wait is before the first initial EAPOL-key retry -#define DEFAULT_INITIAL_KEY_RETRY_TIMER 120 -#define NONE_INITIAL_KEY_RETRY_TIMER 0 - -// Default trickle values for sending of initial EAPOL-key -#define DEFAULT_TRICKLE_IMIN_SECS 360 /* 6 to 12 minutes */ -#define DEFAULT_TRICKLE_IMAX_SECS 720 - -// Very slow network values for sending of initial EAPOL-key -#define VERY_SLOW_NW_TRICKLE_IMIN_SECS 600 /* 10 to 60 minutes */ -#define VERY_SLOW_NW_TRICKLE_IMAX_SECS 3600 - // Trickle timer on how long to wait response after last retry before failing authentication #define LAST_INTERVAL_TRICKLE_IMIN_SECS 240 /* 4 minutes */ #define LAST_INTERVAL_TRICKLE_IMAX_SECS 240 -static trickle_params_t initial_eapol_key_trickle_params = { - .Imin = DEFAULT_TRICKLE_IMIN_SECS, /* 360 second; ticks are 1 second */ - .Imax = DEFAULT_TRICKLE_IMAX_SECS, /* 720 second */ - .k = 0, /* infinity - no consistency checking */ - .TimerExpirations = 2 -}; - static void ws_pae_supp_free(pae_supp_t *pae_supp); static void ws_pae_supp_authenticate_response(pae_supp_t *pae_supp, auth_result_e result); static int8_t ws_pae_supp_initial_key_send(pae_supp_t *pae_supp); static void ws_pae_supp_nvm_update(pae_supp_t *pae_supp); -static int8_t ws_pae_supp_nw_keys_valid_check(pae_supp_t *pae_supp, uint16_t pan_id); -static int8_t ws_pae_supp_nvm_nw_info_write(pae_supp_t *pae_supp); +static int8_t ws_pae_supp_nw_keys_valid_check(pae_supp_t *pae_supp, uint16_t pan_id, char *dest_network_name); static int8_t ws_pae_supp_nvm_keys_write(pae_supp_t *pae_supp); static pae_supp_t *ws_pae_supp_get(protocol_interface_info_entry_t *interface_ptr); static int8_t ws_pae_supp_event_send(kmp_service_t *service, void *data); @@ -182,16 +157,15 @@ static void ws_pae_supp_kmp_api_finished(kmp_api_t *kmp); static const eapol_pdu_recv_cb_data_t eapol_pdu_recv_cb_data = { .priority = EAPOL_PDU_RECV_HIGH_PRIORITY, + .filter_requsted = false, .addr_check = ws_pae_supp_eapol_pdu_address_check, .receive = kmp_eapol_pdu_if_receive }; -static const char *NW_INFO_FILE = NW_INFO_FILE_NAME; static const char *KEYS_FILE = KEYS_FILE_NAME; static int8_t tasklet_id = -1; static NS_LIST_DEFINE(pae_supp_list, pae_supp_t, link); -static uint8_t timing_value = 0; // Timing value set based e.g. on network size static void ws_pae_supp_address_set(pae_supp_t *pae_supp, kmp_addr_t *address) { @@ -209,33 +183,35 @@ static bool ws_pae_supp_address_is_set(pae_supp_t *pae_supp) return pae_supp->entry_address_active; } -int8_t ws_pae_supp_authenticate(protocol_interface_info_entry_t *interface_ptr, uint16_t dest_pan_id, uint8_t *dest_eui_64) +int8_t ws_pae_supp_authenticate(protocol_interface_info_entry_t *interface_ptr, uint16_t dest_pan_id, uint8_t *dest_eui_64, char *dest_network_name) { pae_supp_t *pae_supp = ws_pae_supp_get(interface_ptr); if (!pae_supp) { return -1; } - if (ws_pae_supp_nw_keys_valid_check(pae_supp, dest_pan_id) >= 0) { + if (ws_pae_supp_nw_keys_valid_check(pae_supp, dest_pan_id, dest_network_name) >= 0) { pae_supp->auth_completed(interface_ptr, AUTH_RESULT_OK, NULL); return 0; } // Delete GTKs - sec_prot_keys_gtks_init(pae_supp->sec_keys_nw_info.gtks); + sec_prot_keys_gtks_init(pae_supp->sec_keys_nw_info->gtks); - /* PAN ID has changed, delete key data associated with border router + /* Network name or PAN ID has changed, delete key data associated with border router i.e PMK, PTK, EA-IE data (border router EUI-64) */ - if (pae_supp->sec_keys_nw_info.key_pan_id != 0xFFFF && pae_supp->sec_keys_nw_info.key_pan_id != dest_pan_id) { + if (strcmp(pae_supp->sec_keys_nw_info->network_name, dest_network_name) != 0 || + (pae_supp->sec_keys_nw_info->key_pan_id != 0xFFFF && pae_supp->sec_keys_nw_info->key_pan_id != dest_pan_id)) { sec_prot_keys_pmk_delete(&pae_supp->entry.sec_keys); sec_prot_keys_ptk_delete(&pae_supp->entry.sec_keys); sec_prot_keys_ptk_eui_64_delete(&pae_supp->entry.sec_keys); } - pae_supp->sec_keys_nw_info.key_pan_id = dest_pan_id; + pae_supp->sec_keys_nw_info->key_pan_id = dest_pan_id; // Prepare to receive new border router address pae_supp->new_br_eui_64_fresh = false; + pae_supp->comp_br_eui_64_set = false; // Stores target/parent address kmp_address_init(KMP_ADDR_EUI_64, &pae_supp->target_addr, dest_eui_64); @@ -255,29 +231,6 @@ int8_t ws_pae_supp_authenticate(protocol_interface_info_entry_t *interface_ptr, return 1; } -int8_t ws_pae_supp_nw_info_set(protocol_interface_info_entry_t *interface_ptr, uint16_t pan_id, char *network_name) -{ - pae_supp_t *pae_supp = ws_pae_supp_get(interface_ptr); - if (!pae_supp) { - return -1; - } - - // PAN ID has been modified - if (pan_id != 0xffff && pan_id != pae_supp->sec_keys_nw_info.new_pan_id) { - pae_supp->sec_keys_nw_info.new_pan_id = pan_id; - pae_supp->sec_keys_nw_info.updated = true; - } - - // Network name has been modified - if (network_name && strncmp(pae_supp->sec_keys_nw_info.network_name, network_name, 33) != 0) { - strncpy(pae_supp->sec_keys_nw_info.network_name, network_name, 32); - pae_supp->sec_keys_nw_info.updated = true; - } - - - return 0; -} - int8_t ws_pae_supp_border_router_addr_write(protocol_interface_info_entry_t *interface_ptr, const uint8_t *eui_64) { pae_supp_t *pae_supp = ws_pae_supp_get(interface_ptr); @@ -299,9 +252,14 @@ int8_t ws_pae_supp_border_router_addr_read(protocol_interface_info_entry_t *inte return -1; } + // Check if there is border router EUI-64 on used on 4WH PTK generation uint8_t *br_eui_64 = sec_prot_keys_ptk_eui_64_get(&pae_supp->entry.sec_keys); if (!br_eui_64) { - return -1; + // Check if there is border router EUI-64 indicated by the bootstrap when bootstrap completed + if (!pae_supp->comp_br_eui_64_set) { + return -1; + } + br_eui_64 = pae_supp->comp_br_eui_64; } memcpy(eui_64, br_eui_64, 8); @@ -309,14 +267,31 @@ int8_t ws_pae_supp_border_router_addr_read(protocol_interface_info_entry_t *inte return 0; } -int8_t ws_pae_supp_nw_key_valid(protocol_interface_info_entry_t *interface_ptr) +int8_t ws_pae_supp_nw_key_valid(protocol_interface_info_entry_t *interface_ptr, uint8_t *br_iid) { pae_supp_t *pae_supp = ws_pae_supp_get(interface_ptr); if (!pae_supp) { return -1; } - tr_info("NW key valid"); + tr_info("NW key valid indication"); + + // Store border router EUI-64 received on bootstrap complete + memcpy(pae_supp->comp_br_eui_64, br_iid, 8); + pae_supp->comp_br_eui_64[0] ^= 0x02; + pae_supp->comp_br_eui_64_set = true; + + // Get the EUI-64 used on 4WH handshake PTK generation + uint8_t *ptk_eui_64 = sec_prot_keys_ptk_eui_64_get(&pae_supp->entry.sec_keys); + + /* If border router EUI-64 received on bootstrap complete does not match to + EUI-64 stored with keys, delete keys */ + if (memcmp(ptk_eui_64, pae_supp->comp_br_eui_64, 8) != 0) { + tr_warn("Delete keys: PTK EUI-64 %s does not match to BR EUI-64 %s", tr_array(ptk_eui_64, 8), tr_array(pae_supp->comp_br_eui_64, 8)); + sec_prot_keys_pmk_delete(&pae_supp->entry.sec_keys); + sec_prot_keys_ptk_delete(&pae_supp->entry.sec_keys); + sec_prot_keys_ptk_eui_64_delete(&pae_supp->entry.sec_keys); + } // Stored keys are valid pae_supp->nw_keys_used_cnt = 0; @@ -335,7 +310,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->gtks, gtkhash); + gtk_mismatch_e mismatch = sec_prot_keys_gtks_hash_update(pae_supp->sec_keys_nw_info->gtks, gtkhash); if (mismatch != GTK_NO_MISMATCH) { return -1; } @@ -352,7 +327,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->gtks, gtkhash); + gtk_mismatch_e mismatch = sec_prot_keys_gtks_hash_update(pae_supp->sec_keys_nw_info->gtks, gtkhash); if (mismatch > GTK_NO_MISMATCH) { tr_info("GTK hash update %s %s %s %s", trace_array(>khash[0], 8), @@ -379,7 +354,7 @@ int8_t ws_pae_supp_gtk_hash_update(protocol_interface_info_entry_t *interface_pt } // Modify keys - pae_supp->nw_key_insert(pae_supp->interface_ptr, pae_supp->sec_keys_nw_info.gtks); + pae_supp->nw_key_insert(pae_supp->interface_ptr, pae_supp->sec_keys_nw_info->gtks); return 0; } @@ -391,7 +366,7 @@ int8_t ws_pae_supp_nw_key_index_update(protocol_interface_info_entry_t *interfac return -1; } - if (sec_prot_keys_gtk_status_active_set(&pae_supp->gtks, index) >= 0) { + if (sec_prot_keys_gtk_status_active_set(pae_supp->sec_keys_nw_info->gtks, index) >= 0) { pae_supp->nw_key_index_set(interface_ptr, index); } else { tr_info("NW send key index: %i, no changes", index + 1); @@ -407,7 +382,7 @@ int8_t ws_pae_supp_gtks_set(protocol_interface_info_entry_t *interface_ptr, sec_ return -1; } - pae_supp->gtks = *gtks; + *pae_supp->sec_keys_nw_info->gtks = *gtks; return 0; } @@ -427,12 +402,8 @@ int8_t ws_pae_supp_eapol_target_remove(protocol_interface_info_entry_t *interfac static void ws_pae_supp_nvm_update(pae_supp_t *pae_supp) { - // Check if NW info or GTKs have been changed - if (pae_supp->sec_keys_nw_info.updated || sec_prot_keys_gtks_are_updated(pae_supp->sec_keys_nw_info.gtks)) { - ws_pae_supp_nvm_nw_info_write(pae_supp); - pae_supp->sec_keys_nw_info.updated = false; - sec_prot_keys_gtks_updated_reset(pae_supp->sec_keys_nw_info.gtks); - } + // Indicate to PAE controller that NW info or GTKs may have been changed + pae_supp->nw_info_updated(pae_supp->interface_ptr); // Check if pairwise security keys have been changed if (sec_prot_keys_are_updated(&pae_supp->entry.sec_keys)) { @@ -441,75 +412,30 @@ static void ws_pae_supp_nvm_update(pae_supp_t *pae_supp) } } -static int8_t ws_pae_supp_nvm_nw_info_write(pae_supp_t *pae_supp) -{ - nvm_tlv_entry_t *tlv_entry = ws_pae_controller_nvm_tlv_get(pae_supp->interface_ptr); - if (!tlv_entry) { - return -1; - } - - nvm_tlv_list_t tlv_list; - ns_list_init(&tlv_list); - - ws_pae_nvm_store_nw_info_tlv_create(tlv_entry, pae_supp->sec_keys_nw_info.key_pan_id, - pae_supp->sec_keys_nw_info.network_name, - &pae_supp->gtks); - ns_list_add_to_end(&tlv_list, tlv_entry); - - ws_pae_nvm_store_tlv_file_write(NW_INFO_FILE, &tlv_list); - - return 0; -} - -static int8_t ws_pae_supp_nvm_nw_info_read(pae_supp_t *pae_supp) -{ - nvm_tlv_list_t tlv_list; - ns_list_init(&tlv_list); - - ws_pae_nvm_store_tlv_file_read(NW_INFO_FILE, &tlv_list); - - ns_list_foreach_safe(nvm_tlv_entry_t, entry, &tlv_list) { - ws_pae_nvm_store_nw_info_tlv_read(entry, &pae_supp->sec_keys_nw_info.key_pan_id, - pae_supp->sec_keys_nw_info.network_name, - &pae_supp->gtks); - ns_list_remove(&tlv_list, entry); - ns_dyn_mem_free(entry); - } - - return 0; -} - static int8_t ws_pae_supp_nvm_keys_write(pae_supp_t *pae_supp) { - nvm_tlv_entry_t *tlv_entry = ws_pae_controller_nvm_tlv_get(pae_supp->interface_ptr); - if (!tlv_entry) { + nvm_tlv_t *tlv = ws_pae_controller_nvm_tlv_get(pae_supp->interface_ptr); + if (!tlv) { return -1; } - nvm_tlv_list_t tlv_list; - ns_list_init(&tlv_list); - - ws_pae_nvm_store_keys_tlv_create(tlv_entry, &pae_supp->entry.sec_keys); - ns_list_add_to_end(&tlv_list, tlv_entry); - - ws_pae_nvm_store_tlv_file_write(KEYS_FILE, &tlv_list); + ws_pae_nvm_store_keys_tlv_create(tlv, &pae_supp->entry.sec_keys); + ws_pae_nvm_store_tlv_file_write(KEYS_FILE, tlv); return 0; } static int8_t ws_pae_supp_nvm_keys_read(pae_supp_t *pae_supp) { - nvm_tlv_list_t tlv_list; - ns_list_init(&tlv_list); - - ws_pae_nvm_store_tlv_file_read(KEYS_FILE, &tlv_list); - - ns_list_foreach_safe(nvm_tlv_entry_t, entry, &tlv_list) { - ws_pae_nvm_store_keys_tlv_read(entry, &pae_supp->entry.sec_keys); - ns_list_remove(&tlv_list, entry); - ns_dyn_mem_free(entry); + nvm_tlv_t *tlv = ws_pae_controller_nvm_tlv_get(pae_supp->interface_ptr); + if (!tlv) { + return -1; } - + ws_pae_nvm_store_generic_tlv_create(tlv, PAE_NVM_KEYS_TAG, PAE_NVM_KEYS_LEN); + if (ws_pae_nvm_store_tlv_file_read(KEYS_FILE_NAME, tlv) < 0) { + return -1; + } + ws_pae_nvm_store_keys_tlv_read(tlv, &pae_supp->entry.sec_keys); return 0; } @@ -562,29 +488,31 @@ static int8_t ws_pae_supp_initial_key_send(pae_supp_t *pae_supp) return 0; } -static int8_t ws_pae_supp_nw_keys_valid_check(pae_supp_t *pae_supp, uint16_t pan_id) +static int8_t ws_pae_supp_nw_keys_valid_check(pae_supp_t *pae_supp, uint16_t pan_id, char *dest_network_name) { // Checks how many times authentication has been tried with current network keys if (pae_supp->nw_keys_used_cnt >= STORED_KEYS_MAXIMUM_USE_COUNT) { tr_debug("Keys not valid, delete GTKs"); // Delete GTKs - sec_prot_keys_gtks_init(pae_supp->sec_keys_nw_info.gtks); - sec_prot_keys_gtks_updated_set(pae_supp->sec_keys_nw_info.gtks); + sec_prot_keys_gtks_init(pae_supp->sec_keys_nw_info->gtks); + sec_prot_keys_gtks_updated_set(pae_supp->sec_keys_nw_info->gtks); ws_pae_supp_nvm_update(pae_supp); pae_supp->nw_keys_used_cnt = 0; return -1; } - /* Checks if keys match to PAN ID and that needed keys exists (PMK, PTK and a GTK), - and calls inserts function that will update the network keys as needed */ - if ((pan_id == pae_supp->sec_keys_nw_info.key_pan_id) && - (sec_prot_keys_gtk_count(pae_supp->sec_keys_nw_info.gtks) > 0) && + /* Checks if keys match to network name and PAN ID and that needed keys exists (PMK, + PTK and a GTK), and calls inserts function that will update the network keys as + needed */ + if ((strcmp(dest_network_name, pae_supp->sec_keys_nw_info->network_name) == 0 && + pan_id == pae_supp->sec_keys_nw_info->key_pan_id) && + (sec_prot_keys_gtk_count(pae_supp->sec_keys_nw_info->gtks) > 0) && (sec_prot_keys_pmk_get(&pae_supp->entry.sec_keys) != NULL) && (sec_prot_keys_ptk_get(&pae_supp->entry.sec_keys) != NULL)) { tr_debug("Existing keys used, counter %i", pae_supp->nw_keys_used_cnt); - if (pae_supp->nw_key_insert(pae_supp->interface_ptr, pae_supp->sec_keys_nw_info.gtks) >= 0) { + if (pae_supp->nw_key_insert(pae_supp->interface_ptr, pae_supp->sec_keys_nw_info->gtks) >= 0) { tr_debug("Keys inserted"); } pae_supp->nw_keys_used_cnt++; @@ -595,21 +523,7 @@ static int8_t ws_pae_supp_nw_keys_valid_check(pae_supp_t *pae_supp, uint16_t pan } } -static void ws_pae_supp_keys_nw_info_init(sec_prot_keys_nw_info_t *sec_keys_nw_info, sec_prot_gtk_keys_t *gtks) -{ - if (!sec_keys_nw_info) { - return; - } - - memset(sec_keys_nw_info, 0, sizeof(sec_prot_keys_nw_info_t)); - - sec_keys_nw_info->gtks = gtks; - sec_keys_nw_info->new_pan_id = 0xFFFF; - sec_keys_nw_info->key_pan_id = 0xFFFF; - sec_keys_nw_info->updated = false; -} - -void ws_pae_supp_cb_register(protocol_interface_info_entry_t *interface_ptr, ws_pae_supp_auth_completed *completed, ws_pae_supp_nw_key_insert *nw_key_insert, ws_pae_supp_nw_key_index_set *nw_key_index_set, ws_pae_supp_gtk_hash_ptr_get *gtk_hash_ptr_get) +void ws_pae_supp_cb_register(protocol_interface_info_entry_t *interface_ptr, ws_pae_supp_auth_completed *completed, ws_pae_supp_auth_next_target *auth_next_target, ws_pae_supp_nw_key_insert *nw_key_insert, ws_pae_supp_nw_key_index_set *nw_key_index_set, ws_pae_supp_gtk_hash_ptr_get *gtk_hash_ptr_get, ws_pae_supp_nw_info_updated *nw_info_updated) { pae_supp_t *pae_supp = ws_pae_supp_get(interface_ptr); if (!pae_supp) { @@ -617,12 +531,14 @@ void ws_pae_supp_cb_register(protocol_interface_info_entry_t *interface_ptr, ws_ } pae_supp->auth_completed = completed; + pae_supp->auth_next_target = auth_next_target; pae_supp->nw_key_insert = nw_key_insert; pae_supp->nw_key_index_set = nw_key_index_set; pae_supp->gtk_hash_ptr_get = gtk_hash_ptr_get; + pae_supp->nw_info_updated = nw_info_updated; } -int8_t ws_pae_supp_init(protocol_interface_info_entry_t *interface_ptr, const sec_prot_certs_t *certs, sec_timer_cfg_t *sec_timer_cfg, sec_prot_cfg_t *sec_prot_cfg) +int8_t ws_pae_supp_init(protocol_interface_info_entry_t *interface_ptr, const sec_prot_certs_t *certs, sec_timer_cfg_t *sec_timer_cfg, sec_prot_cfg_t *sec_prot_cfg, sec_prot_keys_nw_info_t *sec_keys_nw_info) { if (!interface_ptr) { return -1; @@ -639,13 +555,15 @@ int8_t ws_pae_supp_init(protocol_interface_info_entry_t *interface_ptr, const se pae_supp->interface_ptr = interface_ptr; pae_supp->auth_completed = NULL; + pae_supp->auth_next_target = NULL; pae_supp->nw_key_insert = NULL; pae_supp->nw_key_index_set = NULL; pae_supp->gtk_hash_ptr_get = NULL; pae_supp->initial_key_timer = 0; pae_supp->initial_key_retry_timer = 0; pae_supp->nw_keys_used_cnt = 0; - pae_supp->initial_key_retry_cnt = INITIAL_KEY_RETRY_COUNT; + pae_supp->initial_key_retry_cnt = DEFAULT_INITIAL_KEY_RETRY_COUNT; + pae_supp->sec_keys_nw_info = sec_keys_nw_info; pae_supp->sec_timer_cfg = sec_timer_cfg; pae_supp->sec_prot_cfg = sec_prot_cfg; pae_supp->auth_trickle_running = false; @@ -653,16 +571,15 @@ int8_t ws_pae_supp_init(protocol_interface_info_entry_t *interface_ptr, const se pae_supp->timer_running = false; pae_supp->new_br_eui_64_set = false; pae_supp->new_br_eui_64_fresh = false; + pae_supp->comp_br_eui_64_set = false; pae_supp->entry_address_active = false; ws_pae_lib_supp_init(&pae_supp->entry); - ws_pae_supp_keys_nw_info_init(&pae_supp->sec_keys_nw_info, &pae_supp->gtks); - kmp_address_init(KMP_ADDR_EUI_64, &pae_supp->target_addr, 0); - sec_prot_keys_gtks_init(&pae_supp->gtks); - sec_prot_keys_init(&pae_supp->entry.sec_keys, &pae_supp->gtks, certs); + sec_prot_keys_gtks_init(pae_supp->sec_keys_nw_info->gtks); + sec_prot_keys_init(&pae_supp->entry.sec_keys, pae_supp->sec_keys_nw_info->gtks, certs); memset(pae_supp->new_br_eui_64, 0, 8); pae_supp->kmp_service = kmp_service_create(); @@ -721,7 +638,6 @@ int8_t ws_pae_supp_init(protocol_interface_info_entry_t *interface_ptr, const se goto error; } - ws_pae_supp_nvm_nw_info_read(pae_supp); ws_pae_supp_nvm_keys_read(pae_supp); ns_list_add_to_end(&pae_supp_list, pae_supp); @@ -840,7 +756,7 @@ void ws_pae_supp_fast_timer(uint16_t ticks) } // Updates KMP timers and supplicant authentication ongoing timer - bool running = ws_pae_lib_supp_timer_update(&pae_supp->entry, ticks, kmp_service_timer_if_timeout); + bool running = ws_pae_lib_supp_timer_update(NULL, &pae_supp->entry, ticks, kmp_service_timer_if_timeout); // Checks whether timer needs to be active if (!ws_pae_supp_authentication_ongoing(pae_supp) && !running) { @@ -881,6 +797,15 @@ void ws_pae_supp_slow_timer(uint16_t seconds) // Checks if trickle timer expires if (trickle_timer(&pae_supp->auth_trickle_timer, &pae_supp->auth_trickle_params, seconds)) { if (pae_supp->initial_key_retry_cnt > 0) { + // On initial EAPOL-key TX failure, check for other parents + if (pae_supp->auth_requested && pae_supp->tx_failure_on_initial_key) { + // Returns same target if no other valid targets found + const uint8_t *next_target = pae_supp->auth_next_target(pae_supp->interface_ptr, kmp_address_eui_64_get(&pae_supp->target_addr), &pae_supp->sec_keys_nw_info->key_pan_id); + kmp_address_eui_64_set(&pae_supp->target_addr, next_target); + ws_pae_supp_address_set(pae_supp, &pae_supp->target_addr); + } + pae_supp->tx_failure_on_initial_key = false; + // Sends initial EAPOL-key if (ws_pae_supp_initial_key_send(pae_supp) < 0) { tr_info("EAPOL-Key send failed"); } @@ -895,7 +820,12 @@ void ws_pae_supp_slow_timer(uint16_t seconds) tr_info("GTKs do not match to GTK hash"); retry = true; } - ws_pae_supp_authenticate_response(pae_supp, AUTH_RESULT_ERR_UNSPEC); + auth_result_e result = AUTH_RESULT_ERR_UNSPEC; + if (pae_supp->tx_failure_on_initial_key) { + result = AUTH_RESULT_ERR_TX_NO_ACK; + pae_supp->tx_failure_on_initial_key = false; + } + ws_pae_supp_authenticate_response(pae_supp, result); if (retry) { // Start trickle timer to try re-authentication ws_pae_supp_initial_key_update_trickle_timer_start(pae_supp, KEY_UPDATE_RETRY_COUNT); @@ -921,10 +851,11 @@ void ws_pae_supp_slow_timer(uint16_t seconds) // Decrements GTK lifetimes for (uint8_t i = 0; i < GTK_NUM; i++) { - if (!sec_prot_keys_gtk_is_set(&pae_supp->gtks, i)) { + if (!sec_prot_keys_gtk_is_set(pae_supp->sec_keys_nw_info->gtks, i)) { continue; } - sec_prot_keys_gtk_lifetime_decrement(&pae_supp->gtks, i, seconds); + uint64_t current_time = ws_pae_current_time_get(); + sec_prot_keys_gtk_lifetime_decrement(pae_supp->sec_keys_nw_info->gtks, i, current_time, seconds); } if (pae_supp->initial_key_timer > 0) { @@ -932,7 +863,7 @@ void ws_pae_supp_slow_timer(uint16_t seconds) pae_supp->initial_key_timer -= seconds; } else { pae_supp->initial_key_timer = 0; - + pae_supp->tx_failure_on_initial_key = false; // Sends initial EAPOL-Key message if (ws_pae_supp_initial_key_send(pae_supp) < 0) { tr_info("EAPOL-Key send failed"); @@ -946,46 +877,40 @@ void ws_pae_supp_slow_timer(uint16_t seconds) static void ws_pae_supp_initial_trickle_timer_start(pae_supp_t *pae_supp) { - pae_supp->auth_trickle_params = initial_eapol_key_trickle_params; - - // Very fast, medium and slow network - if (timing_value < 25) { - /* Starts trickle for initial EAPOL-key. Sequence has fixed delay of 2 minutes, - * one re-transmit interval, last re-transmit interval transmit time and a wait time - * for the authenticator to answer the last re-transmit. - * - * Interval I [6,12] minutes. Sequence: - * - * fixed 2 minutes delay + I + last I transmit time t + wait for answer [2,4] minutes - * - * There are two retries. Minimum time that sequence takes before authentication failure - * is 16 minutes and maximum is 30 minutes. - */ - pae_supp->initial_key_retry_timer = DEFAULT_INITIAL_KEY_RETRY_TIMER; // 2 minutes - } else { - /* Extremely slow network - * - * Starts trickle for initial EAPOL-key, Interval I [10,60] minutes. Sequence: - * I + last I transmit time t + wait for answer [2,4] minutes - * There are two retries. Minimum time that sequence takes before authentication failure - * is 22 minutes and maximum is 124 minutes. - */ - pae_supp->auth_trickle_params.Imin = VERY_SLOW_NW_TRICKLE_IMIN_SECS; - pae_supp->auth_trickle_params.Imax = VERY_SLOW_NW_TRICKLE_IMAX_SECS; - pae_supp->initial_key_retry_timer = NONE_INITIAL_KEY_RETRY_TIMER; // 0 seconds - } + /* Starts trickle for initial EAPOL-key. Default sequence has fixed delay of 2 minutes, + * one re-transmit interval, last re-transmit interval transmit time and a wait time + * for the authenticator to answer the last re-transmit. + * + * Interval I [6,12] minutes. Sequence: + * + * fixed 2 minutes delay + I + last I transmit time t + wait for answer [2,4] minutes + * + * There are two retries. Minimum time that sequence takes before authentication failure + * is 16 minutes and maximum is 30 minutes. + * + * + * Extremely slow network + * + * Starts trickle for initial EAPOL-key, Interval I [10,60] minutes. Sequence: + * I + last I transmit time t + wait for answer [2,4] minutes + * There are two retries. Minimum time that sequence takes before authentication failure + * is 22 minutes and maximum is 124 minutes. + */ + pae_supp->auth_trickle_params = pae_supp->sec_prot_cfg->initial_key_trickle_params; + pae_supp->initial_key_retry_timer = pae_supp->sec_prot_cfg->initial_key_retry_delay; + trickle_start(&pae_supp->auth_trickle_timer, &pae_supp->auth_trickle_params); tr_info("Initial EAPOL-Key trickle I: [%i,%i] %i, t: %i", pae_supp->auth_trickle_params.Imin, pae_supp->auth_trickle_params.Imax, pae_supp->auth_trickle_timer.I, pae_supp->auth_trickle_timer.t); pae_supp->auth_trickle_running = true; - pae_supp->initial_key_retry_cnt = INITIAL_KEY_RETRY_COUNT; + pae_supp->initial_key_retry_cnt = pae_supp->sec_prot_cfg->initial_key_retry_cnt; } static void ws_pae_supp_initial_last_interval_trickle_timer_start(pae_supp_t *pae_supp) { // Starts trickle last to wait response after last retry before failing authentication - pae_supp->auth_trickle_params = initial_eapol_key_trickle_params; pae_supp->auth_trickle_params.Imin = LAST_INTERVAL_TRICKLE_IMIN_SECS; pae_supp->auth_trickle_params.Imax = LAST_INTERVAL_TRICKLE_IMAX_SECS; + pae_supp->auth_trickle_params.k = 0; pae_supp->auth_trickle_params.TimerExpirations = 1; // Set I to [iMin,iMax] (4 to 4 minutes) -> t is [I/2 - I] (2 minutes to 4 minutes) trickle_start(&pae_supp->auth_trickle_timer, &pae_supp->auth_trickle_params); @@ -1213,7 +1138,7 @@ static kmp_api_t *ws_pae_supp_kmp_incoming_ind(kmp_service_t *service, kmp_type_ static kmp_api_t *ws_pae_supp_kmp_create_and_start(kmp_service_t *service, kmp_type_e type, pae_supp_t *pae_supp) { // Create new instance - kmp_api_t *kmp = kmp_api_create(service, type, pae_supp->sec_prot_cfg); + kmp_api_t *kmp = kmp_api_create(service, type, pae_supp->sec_prot_cfg, pae_supp->sec_timer_cfg); if (!kmp) { return NULL; } @@ -1308,7 +1233,12 @@ static void ws_pae_supp_kmp_api_finished_indication(kmp_api_t *kmp, kmp_result_e that bootstrap can decide if EAPOL target should be changed */ else if (type > IEEE_802_1X_INITIAL_KEY && result == KMP_RESULT_ERR_TX_NO_ACK) { tr_info("Initial EAPOL-Key TX failure, target: %s", trace_array(kmp_address_eui_64_get(&pae_supp->entry.addr), 8)); - ws_pae_supp_authenticate_response(pae_supp, AUTH_RESULT_ERR_TX_NO_ACK); + /* Fails authentication only if other authentication protocols are not yet + started by authenticator */ + if (ws_pae_lib_kmp_list_count(&pae_supp->entry.kmp_list) <= 1) { + // Continues with trickle but selects different parent + pae_supp->tx_failure_on_initial_key = true; + } } } diff --git a/source/6LoWPAN/ws/ws_pae_supp.h b/source/6LoWPAN/ws/ws_pae_supp.h index 3bfbc095c5c..7bd20170616 100644 --- a/source/6LoWPAN/ws/ws_pae_supp.h +++ b/source/6LoWPAN/ws/ws_pae_supp.h @@ -40,12 +40,13 @@ * \param cert_chain certificate chain * \param sec_timer_cfg timer configuration * \param sec_prot_cfg protocol configuration + * \param sec_keys_nw_info security keys network information * * \return < 0 failure * \return >= 0 success * */ -int8_t ws_pae_supp_init(protocol_interface_info_entry_t *interface_ptr, const sec_prot_certs_t *certs, sec_timer_cfg_t *sec_timer_cfg, sec_prot_cfg_t *sec_prot_cfg); +int8_t ws_pae_supp_init(protocol_interface_info_entry_t *interface_ptr, const sec_prot_certs_t *certs, sec_timer_cfg_t *sec_timer_cfg, sec_prot_cfg_t *sec_prot_cfg, sec_prot_keys_nw_info_t *sec_keys_nw_info); /** * ws_pae_supp_delete deletes PAE supplicant @@ -80,26 +81,14 @@ void ws_pae_supp_slow_timer(uint16_t seconds); * \param interface_ptr interface * \param dest_pan_id EAPOL target PAN ID * \param dest_eui_64 EAPOL target + * \param dest_network_name EAPOL target network name * * \return < 0 failure * \return 0 authentication done, continue * \return > 0 authentication started * */ -int8_t ws_pae_supp_authenticate(protocol_interface_info_entry_t *interface_ptr, uint16_t dest_pan_id, uint8_t *dest_eui_64); - -/** - * ws_pae_supp_nw_info_set set network information - * - * \param interface_ptr interface - * \param pan_id PAD ID - * \param network_name network name - * - * \return < 0 failure - * \return >= 0 success - * - */ -int8_t ws_pae_supp_nw_info_set(protocol_interface_info_entry_t *interface_ptr, uint16_t pan_id, char *network_name); +int8_t ws_pae_supp_authenticate(protocol_interface_info_entry_t *interface_ptr, uint16_t dest_pan_id, uint8_t *dest_eui_64, char *dest_network_name); /** * ws_pae_supp_border_router_addr_write write border router address @@ -129,12 +118,13 @@ int8_t ws_pae_supp_border_router_addr_read(protocol_interface_info_entry_t *inte * ws_pae_supp_nw_key_valid network key is valid i.e. used successfully on bootstrap * * \param interface_ptr interface + * \param br_iid border router IID for which the keys are valid * * \return < 0 failure * \return >= 0 success * */ -int8_t ws_pae_supp_nw_key_valid(protocol_interface_info_entry_t *interface_ptr); +int8_t ws_pae_supp_nw_key_valid(protocol_interface_info_entry_t *interface_ptr, uint8_t *br_iid); /** * ws_pae_supp_gtk_hash_update GTK hash has been updated (on PAN configuration) @@ -202,6 +192,17 @@ typedef void ws_pae_supp_nw_key_index_set(protocol_interface_info_entry_t *inter */ typedef void ws_pae_supp_auth_completed(protocol_interface_info_entry_t *interface_ptr, auth_result_e result, uint8_t *target_eui_64); +/** + * ws_pae_supp_auth_next_target get next target to attempt authentication + * + * \param interface_ptr interface + * \param previous_eui_64 EUI-64 of previous target + * + * \return EUI-64 of the next target or previous target if new one not available + * + */ +typedef const uint8_t *ws_pae_supp_auth_next_target(protocol_interface_info_entry_t *interface_ptr, const uint8_t *previous_eui_64, uint16_t *pan_id); + /** * ws_pae_supp_nw_key_insert network key insert callback * @@ -224,6 +225,14 @@ typedef int8_t ws_pae_supp_nw_key_insert(protocol_interface_info_entry_t *interf */ typedef uint8_t *ws_pae_supp_gtk_hash_ptr_get(protocol_interface_info_entry_t *interface_ptr); +/** + * ws_pae_supp_nw_info_updated security keys network information updated + * + * \param interface_ptr interface + * + */ +typedef void ws_pae_supp_nw_info_updated(protocol_interface_info_entry_t *interface_ptr); + /** * ws_pae_supp_cb_register register PEA supplicant callbacks * @@ -231,9 +240,10 @@ typedef uint8_t *ws_pae_supp_gtk_hash_ptr_get(protocol_interface_info_entry_t *i * \param completed authentication completed callback * \param nw_key_insert network key index callback * \param nw_key_index_set network send key index callback + * \param nw_info_updated security keys network information updated callback * */ -void ws_pae_supp_cb_register(protocol_interface_info_entry_t *interface_ptr, ws_pae_supp_auth_completed *completed, ws_pae_supp_nw_key_insert *nw_key_insert, ws_pae_supp_nw_key_index_set *nw_key_index_set, ws_pae_supp_gtk_hash_ptr_get *gtk_hash_ptr_get); +void ws_pae_supp_cb_register(protocol_interface_info_entry_t *interface_ptr, ws_pae_supp_auth_completed *completed, ws_pae_supp_auth_next_target *auth_next_target, ws_pae_supp_nw_key_insert *nw_key_insert, ws_pae_supp_nw_key_index_set *nw_key_index_set, ws_pae_supp_gtk_hash_ptr_get *gtk_hash_ptr_get, ws_pae_supp_nw_info_updated *nw_info_updated); #else @@ -241,7 +251,6 @@ void ws_pae_supp_cb_register(protocol_interface_info_entry_t *interface_ptr, ws_ #define ws_pae_supp_delete NULL #define ws_pae_supp_timing_adjust(timing) 1 #define ws_pae_supp_cb_register(interface_ptr, completed, nw_key_insert, nw_key_index_set) -#define ws_pae_supp_nw_info_set(interface_ptr, pan_id, network_name) -1 #define ws_pae_supp_nw_key_valid(interface_ptr) -1 #define ws_pae_supp_fast_timer NULL #define ws_pae_supp_slow_timer NULL diff --git a/source/6LoWPAN/ws/ws_pae_time.c b/source/6LoWPAN/ws/ws_pae_time.c new file mode 100644 index 00000000000..ad60f3d0e2f --- /dev/null +++ b/source/6LoWPAN/ws/ws_pae_time.c @@ -0,0 +1,190 @@ +/* + * Copyright (c) 2020, Arm Limited and affiliates. + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "nsconfig.h" +#include +#include "ns_types.h" +#include "ns_list.h" +#include "ns_trace.h" +#include "ns_time_api.h" +#include "6LoWPAN/ws/ws_config.h" +#include "6LoWPAN/ws/ws_pae_time.h" +#include "Security/protocols/sec_prot_certs.h" +#include "Security/protocols/sec_prot_keys.h" + +#ifdef HAVE_WS + +#define TRACE_GROUP "wst" + +// Wednesday, January 1, 2020 0:00:00 GMT +#define CURRENT_TIME_INIT_VALUE 1577836800 + +// Increment two hours in addition to maximum storing interval +#define CURRENT_TIME_INCREMENT_VALUE (2 * 3600) + +static uint64_t current_time = CURRENT_TIME_INIT_VALUE; +static ns_time_api_system_time_callback *system_time_callback = NULL; + +uint16_t ws_pae_time_to_short_convert(uint32_t time) +{ + uint16_t short_time; + time_format_t format; + + if (time < STIME_TIME_MAX) { + short_time = time; + format = TIME_FORMAT_SECONDS; + } else if (time < (STIME_TIME_MAX * 60)) { + short_time = time / 60; + format = TIME_FORMAT_MINUTES; + } else if (time < (STIME_TIME_MAX * 3600)) { + short_time = time / 3600; + format = TIME_FORMAT_HOURS; + } else { + short_time = time / 86400; + format = TIME_FORMAT_DAYS; + } + + short_time |= ((uint16_t) format) << STIME_TIME_BITS; + + return short_time; +} + +uint32_t ws_pae_time_from_short_convert(uint16_t short_time) +{ + uint32_t time; + + time_format_t format = short_time >> STIME_TIME_BITS; + + short_time &= STIME_TIME_MASK; + + if (format == TIME_FORMAT_SECONDS) { + time = short_time; + } else if (format == TIME_FORMAT_MINUTES) { + time = short_time * 60; + } else if (format == TIME_FORMAT_HOURS) { + time = short_time * 3600; + } else { + time = short_time * 86400; + } + + return time; +} + +bool ws_pae_time_from_short_time_compare(uint16_t short_time1, uint16_t short_time2) +{ + uint32_t time1 = ws_pae_time_from_short_convert(short_time1); + uint32_t time2 = ws_pae_time_from_short_convert(short_time2); + + // Calculate difference + uint32_t difference; + if (time1 > time2) { + difference = time1 - time2; + } else { + difference = time2 - time1; + } + + // Allow variable difference to be regarded as same based on format + if (STIME_FORMAT_GET(short_time1) == TIME_FORMAT_DAYS || STIME_FORMAT_GET(short_time2) == TIME_FORMAT_DAYS) { + if (difference > 2 * 24 * 3600) { // Two days + return false; + } + } else if (STIME_FORMAT_GET(short_time1) == TIME_FORMAT_HOURS || STIME_FORMAT_GET(short_time2) == TIME_FORMAT_HOURS) { + if (difference > 2 * 3600) { // Two hours + return false; + } + } else if (STIME_FORMAT_GET(short_time1) == TIME_FORMAT_MINUTES || STIME_FORMAT_GET(short_time2) == TIME_FORMAT_MINUTES) { + if (difference > 5 * 60) { // 5 minutes + return false; + } + } else { + if (difference > 10) { // 10 seconds + return false; + } + } + + return true; +} + +int8_t ws_pae_time_diff_calc(uint64_t curr_time, uint64_t comp_time, uint32_t *time_diff, bool future) +{ + int32_t difference; + *time_diff = 0; + // Comparison time is in future + if (curr_time < comp_time) { + if (!future) { + // Do not allow times in future + return -1; + } + difference = comp_time - curr_time; + } else { + // Comparison time is in past + if (future) { + // Do not allow times in past + return -1; + } + difference = curr_time - comp_time; + } + + // If difference is more two years time is invalid + if (difference > SEC_MAXIMUM_LIFETIME) { + return -1; + } + + *time_diff = difference; + + return 0; +} + +uint64_t ws_pae_current_time_get(void) +{ + if (system_time_callback) { + return system_time_callback(); + } + + return current_time; +} + +void ws_pae_current_time_update(uint16_t seconds) +{ + current_time += seconds; +} + +int8_t ws_pae_current_time_set(uint64_t time) +{ + current_time = time; + + if (system_time_callback) { + uint64_t system_time = system_time_callback(); + // System time has gone backwards + if (system_time < current_time || 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, system_time, current_time); + return -1; + } + } else { + current_time += FRAME_COUNTER_STORE_FORCE_INTERVAL + CURRENT_TIME_INCREMENT_VALUE; + } + + return 0; +} + +void ns_time_api_system_time_callback_set(ns_time_api_system_time_callback callback) +{ + system_time_callback = callback; +} + +#endif /* HAVE_WS */ + diff --git a/source/6LoWPAN/ws/ws_pae_time.h b/source/6LoWPAN/ws/ws_pae_time.h new file mode 100644 index 00000000000..12655e2c2a5 --- /dev/null +++ b/source/6LoWPAN/ws/ws_pae_time.h @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2020, Arm Limited and affiliates. + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef WS_PAE_TIME_H_ +#define WS_PAE_TIME_H_ + +/* + * Port access entity time functions. + * + */ + +typedef enum { + TIME_FORMAT_SECONDS = 0, + TIME_FORMAT_MINUTES, + TIME_FORMAT_HOURS, + TIME_FORMAT_DAYS, +} time_format_t; + +#define STIME_TIME_BITS 14 +#define STIME_TIME_MAX 0x3FFF +#define STIME_TIME_MASK STIME_TIME_MAX + +#define STIME_FORMAT_GET(stime) (stime >> STIME_TIME_BITS) +#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) + +/** + * ws_pae_time_to_short_convert convert time to short format + * + * \param time time in seconds to convert + * + * \return < 0 failure + * \return >= 0 success + * + */ +uint16_t ws_pae_time_to_short_convert(uint32_t time); + +/** + * ws_pae_time_from_short_convert convert short time to time format + * + * \param short_time short_time to convert + * + * \return time in seconds + * + */ +uint32_t ws_pae_time_from_short_convert(uint16_t short_time); + +/** + * ws_pae_time_from_short_time_compare compare two times in short format + * + * \param short_time1 time 1 to compare + * \param short_time1 time 2 to compare + * + * \return true times are equal + * \return false times are not equal + * + */ +bool ws_pae_time_from_short_time_compare(uint16_t short_time1, uint16_t short_time2); + +/** + * ws_pae_time_diff_calc calculates difference between two times + * + * \param curr_time current time + * \param comp_time time which is compared + * \param time_diff returns time difference + * \param future compared time should in future + * + * \return < 0 failure + * \return >= 0 success + * + */ +int8_t ws_pae_time_diff_calc(uint64_t curr_time, uint64_t comp_time, uint32_t *time_diff, bool future); + +/** + * ws_pae_current_time_get gets current time + * + * \return current time in seconds after 1970 + * + */ +uint64_t ws_pae_current_time_get(void); + +/** + * ws_pae_current_time_get updates current time + * + * \param seconds seconds to be added to current time + * + */ +void ws_pae_current_time_update(uint16_t seconds); + +/** + * ws_pae_current_time_set sets current time + * + * \param time new time + * + * \return < 0 failure + * \return >= 0 success + */ +int8_t ws_pae_current_time_set(uint64_t time); + +#endif /* WS_PAE_KEY_STORAGE_H_ */ diff --git a/source/6LoWPAN/ws/ws_pae_timers.c b/source/6LoWPAN/ws/ws_pae_timers.c index fd3f02e621e..a07d0e6debc 100644 --- a/source/6LoWPAN/ws/ws_pae_timers.c +++ b/source/6LoWPAN/ws/ws_pae_timers.c @@ -26,6 +26,7 @@ #include "NWK_INTERFACE/Include/protocol.h" #include "6LoWPAN/ws/ws_config.h" #include "6LoWPAN/ws/ws_cfg_settings.h" +#include "Security/protocols/sec_prot_cfg.h" #include "6LoWPAN/ws/ws_pae_timers.h" #ifdef HAVE_WS diff --git a/source/6LoWPAN/ws/ws_pae_timers.h b/source/6LoWPAN/ws/ws_pae_timers.h index ec792996a01..7b8f58052d6 100644 --- a/source/6LoWPAN/ws/ws_pae_timers.h +++ b/source/6LoWPAN/ws/ws_pae_timers.h @@ -18,18 +18,6 @@ #ifndef WS_PAE_TIMERS_H_ #define WS_PAE_TIMERS_H_ -typedef struct sec_timer_cfg_s { - uint32_t gtk_expire_offset; /* GTK lifetime; GTK_EXPIRE_OFFSET (seconds) */ - uint32_t pmk_lifetime; /* PMK lifetime (seconds) */ - uint32_t ptk_lifetime; /* PTK lifetime (seconds) */ - uint16_t gtk_new_act_time; /* GTK_NEW_ACTIVATION_TIME (1/X of expire offset) */ - uint16_t revocat_lifetime_reduct; /* REVOCATION_LIFETIME_REDUCTION (reduction of lifetime) */ - uint16_t gtk_request_imin; /* GTK_REQUEST_IMIN (seconds) */ - uint16_t gtk_request_imax; /* GTK_REQUEST_IMAX (seconds) */ - uint16_t gtk_max_mismatch; /* GTK_MAX_MISMATCH (seconds) */ - uint8_t gtk_new_install_req; /* GTK_NEW_INSTALL_REQUIRED (percent of GTK lifetime) */ -} sec_timer_cfg_t; - /** * ws_pae_timers_settings_init initializes timer settings structure * diff --git a/source/6LoWPAN/ws/ws_test_api.c b/source/6LoWPAN/ws/ws_test_api.c index f7ea71de086..16f9c5926a3 100644 --- a/source/6LoWPAN/ws/ws_test_api.c +++ b/source/6LoWPAN/ws/ws_test_api.c @@ -23,7 +23,9 @@ #include #include "fhss_config.h" #include "ws_management_api.h" +#include "mac_api.h" #include "NWK_INTERFACE/Include/protocol.h" +#include "6LoWPAN/MAC/mac_helper.h" #include "6LoWPAN/ws/ws_config.h" #include "6LoWPAN/ws/ws_common.h" #include "6LoWPAN/ws/ws_bbr_api_internal.h" diff --git a/source/Common_Protocols/icmpv6.c b/source/Common_Protocols/icmpv6.c index b94b55d52ab..c6d3efd81c9 100644 --- a/source/Common_Protocols/icmpv6.c +++ b/source/Common_Protocols/icmpv6.c @@ -1714,7 +1714,11 @@ buffer_t *icmpv6_build_na(protocol_interface_info_entry_t *cur, bool solicited, buf->info = (buffer_info_t)(B_DIR_DOWN | B_FROM_ICMP | B_TO_ICMP); buf->interface = cur; - tr_info("Build NA"); + if (aro) { + tr_info("Build NA ARO"); + } else { + tr_info("Build NA"); + } return (buf); } diff --git a/source/Core/include/ns_monitor.h b/source/Core/include/ns_monitor.h index 6ed6d3a9e4f..2d98feb2def 100644 --- a/source/Core/include/ns_monitor.h +++ b/source/Core/include/ns_monitor.h @@ -35,5 +35,10 @@ void ns_monitor_timer(uint16_t seconds); int ns_monitor_heap_gc_threshold_set(uint8_t percentage_high, uint8_t percentage_critical); +int ns_monitor_packet_ingress_rate_limit_by_memory(uint8_t free_heap_percentage); + +bool ns_monitor_packet_allocation_allowed(void); + + #endif // _NS_MONITOR_H diff --git a/source/Core/ns_monitor.c b/source/Core/ns_monitor.c index 54d6ecaceac..17a46eb6233 100644 --- a/source/Core/ns_monitor.c +++ b/source/Core/ns_monitor.c @@ -62,6 +62,8 @@ typedef struct ns_monitor__s { static ns_monitor_t *ns_monitor_ptr = NULL; +static uint8_t ns_dyn_mem_rate_limiting_threshold_percentage = 0; // Percentage of free memory required to allow routing + typedef void (ns_maintenance_gc_cb)(bool full_gc); /* @@ -189,3 +191,31 @@ int ns_monitor_heap_gc_threshold_set(uint8_t percentage_high, uint8_t percentage return -1; } + +int ns_monitor_packet_ingress_rate_limit_by_memory(uint8_t free_heap_percentage) +{ + if (free_heap_percentage < 100) { + ns_dyn_mem_rate_limiting_threshold_percentage = free_heap_percentage; + return 0; + } + + return -1; +} + +bool ns_monitor_packet_allocation_allowed(void) +{ + // If there is no packets to forward this should not be blocked. + // There should be cleanup routine enabled that will remove unneeded memory to prevent locks + // this could trigger a function to clean packets from routing and allow newest packets + + const mem_stat_t *ns_dyn_mem_stat = ns_dyn_mem_get_mem_stat(); + + if (ns_dyn_mem_stat && ns_dyn_mem_rate_limiting_threshold_percentage) { + if (ns_dyn_mem_stat->heap_sector_allocated_bytes > ns_dyn_mem_stat->heap_sector_size / 100 * (100 - ns_dyn_mem_rate_limiting_threshold_percentage)) { + // Packet allocation not allowed as memory is running low. + return false; + } + } + return true; +} + diff --git a/source/MAC/IEEE802_15_4/mac_cca_threshold.c b/source/MAC/IEEE802_15_4/mac_cca_threshold.c new file mode 100644 index 00000000000..33b9b274107 --- /dev/null +++ b/source/MAC/IEEE802_15_4/mac_cca_threshold.c @@ -0,0 +1,142 @@ +/* + * Copyright (c) 2020, Arm Limited and affiliates. + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "string.h" +#include "nsconfig.h" +#include "ns_types.h" +#include "ns_trace.h" +#include "nsdynmemLIB.h" +#include "MAC/IEEE802_15_4/mac_defines.h" +#include "MAC/IEEE802_15_4/mac_cca_threshold.h" + +#define TRACE_GROUP "mcth" + +int8_t mac_cca_thr_init(protocol_interface_rf_mac_setup_s *rf_ptr, uint8_t number_of_channels, int8_t default_dbm, int8_t high_limit, int8_t low_limit) +{ + // No changes + if (rf_ptr->cca_threshold && + (number_of_channels == rf_ptr->cca_threshold->number_of_channels) && + (default_dbm == rf_ptr->cca_threshold->default_dbm) && + (high_limit == rf_ptr->cca_threshold->high_limit) && + (low_limit == rf_ptr->cca_threshold->low_limit)) { + return -1; + } + // Validate given dBm range. Default must be in between high and low limit. + if ((default_dbm > high_limit) || (default_dbm < low_limit)) { + return -1; + } + mac_cca_thr_deinit(rf_ptr); + rf_ptr->cca_threshold = ns_dyn_mem_alloc(sizeof(mac_cca_threshold_s)); + if (!rf_ptr->cca_threshold) { + return -1; + } + rf_ptr->cca_threshold->ch_thresholds = ns_dyn_mem_alloc(number_of_channels); + if (!rf_ptr->cca_threshold->ch_thresholds) { + ns_dyn_mem_free(rf_ptr->cca_threshold); + rf_ptr->cca_threshold = 0; + return -1; + } + memset(rf_ptr->cca_threshold->ch_thresholds, default_dbm, number_of_channels); + rf_ptr->cca_threshold->high_limit = high_limit; + rf_ptr->cca_threshold->low_limit = low_limit; + rf_ptr->cca_threshold->default_dbm = default_dbm; + rf_ptr->cca_threshold->number_of_channels = number_of_channels; + tr_info("Initialized CCA threshold: %u, %i, %i, %i", number_of_channels, default_dbm, high_limit, low_limit); + return 0; +} + +int8_t mac_cca_thr_deinit(protocol_interface_rf_mac_setup_s *rf_ptr) +{ + if (!rf_ptr->cca_threshold) { + return -1; + } + ns_dyn_mem_free(rf_ptr->cca_threshold->ch_thresholds); + ns_dyn_mem_free(rf_ptr->cca_threshold); + rf_ptr->cca_threshold = 0; + return 0; +} + +int8_t mac_cca_thr_get_dbm(protocol_interface_rf_mac_setup_s *rf_ptr, uint8_t channel) +{ + if (!rf_ptr->cca_threshold) { + return CCA_FAILED_DBM; + } + // If channel is unknown, use default threshold + if (channel > (rf_ptr->cca_threshold->number_of_channels - 1)) { + return rf_ptr->cca_threshold->default_dbm; + } + return rf_ptr->cca_threshold->ch_thresholds[channel]; +} + +static int8_t mac_cca_thr_set_dbm(protocol_interface_rf_mac_setup_s *rf_ptr, uint8_t channel, int8_t dbm) +{ + if (rf_ptr->cca_threshold->ch_thresholds[channel] != dbm) { + rf_ptr->cca_threshold->ch_thresholds[channel] = dbm; + return 0; + } + return -1; +} + +static int8_t mac_cca_thr_update_channel_threshold(protocol_interface_rf_mac_setup_s *rf_ptr, uint8_t channel, int8_t dbm) +{ + // Already on low limit + if (rf_ptr->cca_threshold->ch_thresholds[channel] == rf_ptr->cca_threshold->low_limit) { + return -1; + } + // Already using lower threshold + if (rf_ptr->cca_threshold->ch_thresholds[channel] <= (dbm - CCA_THRESHOLD_STEP)) { + return -1; + } + // Do not set below configured low limit + if ((dbm - CCA_THRESHOLD_STEP) < rf_ptr->cca_threshold->low_limit) { + return mac_cca_thr_set_dbm(rf_ptr, channel, rf_ptr->cca_threshold->low_limit); + } + return mac_cca_thr_set_dbm(rf_ptr, channel, dbm - CCA_THRESHOLD_STEP); +} + +static int8_t mac_cca_thr_channel_failed(protocol_interface_rf_mac_setup_s *rf_ptr, uint8_t channel) +{ + // Already on high limit + if (rf_ptr->cca_threshold->ch_thresholds[channel] == rf_ptr->cca_threshold->high_limit) { + return -1; + } + // Do not set above configured high limit + if ((rf_ptr->cca_threshold->ch_thresholds[channel] + CCA_THRESHOLD_STEP) > rf_ptr->cca_threshold->high_limit) { + return mac_cca_thr_set_dbm(rf_ptr, channel, rf_ptr->cca_threshold->high_limit); + } + return mac_cca_thr_set_dbm(rf_ptr, channel, rf_ptr->cca_threshold->ch_thresholds[channel] + CCA_THRESHOLD_STEP); +} + +int8_t mac_cca_threshold_update(protocol_interface_rf_mac_setup_s *rf_ptr, uint8_t channel, int8_t dbm) +{ + if (!rf_ptr->cca_threshold) { + return -1; + } + if (channel > (rf_ptr->cca_threshold->number_of_channels - 1)) { + return -1; + } + if (dbm == CCA_FAILED_DBM) { + if (mac_cca_thr_channel_failed(rf_ptr, channel)) { + return -1; + } + } else { + if (mac_cca_thr_update_channel_threshold(rf_ptr, channel, dbm)) { + return -1; + } + } + tr_debug("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_cca_threshold.h b/source/MAC/IEEE802_15_4/mac_cca_threshold.h new file mode 100644 index 00000000000..a2081ba5883 --- /dev/null +++ b/source/MAC/IEEE802_15_4/mac_cca_threshold.h @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2020, Arm Limited and affiliates. + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef MAC_CCA_THRESHOLD_H_ +#define MAC_CCA_THRESHOLD_H_ + +#define CCA_THRESHOLD_STEP 1 +#define CCA_FAILED_DBM 0x7F + +typedef struct mac_cca_threshold { + int8_t *ch_thresholds; + int8_t high_limit; + int8_t low_limit; + int8_t default_dbm; + uint8_t number_of_channels; +} mac_cca_threshold_s; + +/** + * @brief Initialize automatic CCA threshold. + * @param rf_ptr Pointer to MAC instance. + * @param number_of_channels Number of MAC channels. + * @param default_dbm Default threshold. + * @param high_limit Highest allowed CCA threshold. + * @param low_limit Lowest allowed CCA threshold. + * @return 0 Success, negative Failed. + */ +int8_t mac_cca_thr_init(protocol_interface_rf_mac_setup_s *rf_ptr, uint8_t number_of_channels, int8_t default_dbm, int8_t high_limit, int8_t low_limit); + +/** + * @brief Deinitialize automatic CCA threshold. + * @param rf_ptr Pointer to MAC instance. + * @return 0 Success, negative Not found. + */ +int8_t mac_cca_thr_deinit(protocol_interface_rf_mac_setup_s *rf_ptr); + +/** + * @brief Read CCA threshold of specific channel. + * @param channel Channel. + * @return CCA threshold (dBm), CCA_FAILED_DBM Feature not enabled. + */ +int8_t mac_cca_thr_get_dbm(protocol_interface_rf_mac_setup_s *rf_ptr, uint8_t channel); + +/** + * @brief Update CCA threshold of specific channel. + * @param channel Channel. + * @param dbm CCA threshold (dBm). + * @return 0 Updated, negative Already using this value. + */ +int8_t mac_cca_threshold_update(protocol_interface_rf_mac_setup_s *rf_ptr, uint8_t channel, int8_t dbm); + +#endif /* MAC_CCA_THRESHOLD_H_ */ diff --git a/source/MAC/IEEE802_15_4/mac_data_buffer.h b/source/MAC/IEEE802_15_4/mac_data_buffer.h index a7de899bbba..4888cc816d5 100644 --- a/source/MAC/IEEE802_15_4/mac_data_buffer.h +++ b/source/MAC/IEEE802_15_4/mac_data_buffer.h @@ -91,11 +91,13 @@ typedef struct mac_pre_build_frame { uint8_t csma_periods_left; uint8_t fhss_retry_count; uint8_t fhss_cca_retry_count; + uint16_t initial_tx_channel; uint32_t tx_time; bool upper_layer_request: 1; bool mac_allocated_payload_ptr: 1; bool asynch_request: 1; bool message_builded: 1; + bool DSN_allocated: 1; unsigned security_mic_len: 5; //Max possible lengths 0, 4, 8, 16 bytes unsigned priority: 2; struct mac_pre_build_frame *next; //Pointer for queue purpose diff --git a/source/MAC/IEEE802_15_4/mac_defines.h b/source/MAC/IEEE802_15_4/mac_defines.h index 28c2e62cfe3..ff676169905 100644 --- a/source/MAC/IEEE802_15_4/mac_defines.h +++ b/source/MAC/IEEE802_15_4/mac_defines.h @@ -276,6 +276,7 @@ typedef struct protocol_interface_rf_mac_setup { struct arm_device_driver_list *tun_extension_rf_driver; /* End of API Control */ struct mlme_scan_conf_s *mac_mlme_scan_resp; + struct mac_cca_threshold *cca_threshold; //beacon_join_priority_tx_cb *beacon_join_priority_tx_cb_ptr; struct mac_statistics_s *mac_statistics; /* FHSS API*/ diff --git a/source/MAC/IEEE802_15_4/mac_mcps_sap.c b/source/MAC/IEEE802_15_4/mac_mcps_sap.c index d7c9aa9ef87..ee16dc86700 100644 --- a/source/MAC/IEEE802_15_4/mac_mcps_sap.c +++ b/source/MAC/IEEE802_15_4/mac_mcps_sap.c @@ -34,6 +34,7 @@ #include "fhss_api.h" #include "platform/arm_hal_interrupt.h" #include "common_functions.h" +#include "Core/include/ns_monitor.h" #include "MAC/IEEE802_15_4/sw_mac_internal.h" #include "MAC/IEEE802_15_4/mac_defines.h" @@ -45,6 +46,7 @@ #include "MAC/IEEE802_15_4/mac_mcps_sap.h" #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/rf_driver_storage.h" #include "sw_mac.h" @@ -74,8 +76,6 @@ static void mac_pd_data_confirm_failure_handle(protocol_interface_rf_mac_setup_s static int8_t mac_tasklet_event_handler = -1; -static ns_mem_heap_size_t ns_dyn_mem_rate_limiting_threshold = 0xFFFFFFFF; - /** * Get PHY time stamp. * @@ -1196,6 +1196,9 @@ static void mac_mcps_sap_data_tasklet(arm_event_s *event) case MAC_MLME_SCAN_CONFIRM_HANDLER: mac_mlme_scan_confirmation_handle((protocol_interface_rf_mac_setup_s *) event->data_ptr); break; + case MAC_CCA_THR_UPDATE: + mac_cca_threshold_update((protocol_interface_rf_mac_setup_s *) event->data_ptr, event->event_data >> 8, (int8_t) event->event_data); + break; case MAC_SAP_TRIG_TX: mac_clear_active_event((protocol_interface_rf_mac_setup_s *) event->data_ptr, MAC_SAP_TRIG_TX); mac_mcps_trig_buffer_from_queue((protocol_interface_rf_mac_setup_s *) event->data_ptr); @@ -1221,7 +1224,9 @@ mac_pre_build_frame_t *mcps_sap_prebuild_frame_buffer_get(uint16_t payload_size) return NULL; } memset(buffer, 0, sizeof(mac_pre_build_frame_t)); + buffer->initial_tx_channel = 0xffff; buffer->aux_header.frameCounter = 0xffffffff; + buffer->DSN_allocated = false; if (payload_size) { //Mac interlnal payload allocate buffer->mac_payload = ns_dyn_mem_temporary_alloc(payload_size); @@ -1498,7 +1503,10 @@ static void mcps_generic_sequence_number_allocate(protocol_interface_rf_mac_setu switch (buffer->fcf_dsn.frametype) { case MAC_FRAME_CMD: case MAC_FRAME_DATA: - buffer->fcf_dsn.DSN = mac_mlme_set_new_sqn(rf_ptr); + if (!buffer->DSN_allocated) { + buffer->fcf_dsn.DSN = mac_mlme_set_new_sqn(rf_ptr); + buffer->DSN_allocated = true; + } break; case MAC_FRAME_BEACON: buffer->fcf_dsn.DSN = mac_mlme_set_new_beacon_sqn(rf_ptr); @@ -2126,8 +2134,8 @@ void mcps_sap_pre_parsed_frame_buffer_free(mac_pre_parsed_frame_t *buf) mac_pre_parsed_frame_t *mcps_sap_pre_parsed_frame_buffer_get(const uint8_t *data_ptr, uint16_t frame_length) { // check that system has enough space to handle the new packet - const mem_stat_t *ns_dyn_mem_stat = ns_dyn_mem_get_mem_stat(); - if (ns_dyn_mem_stat && ns_dyn_mem_stat->heap_sector_allocated_bytes > ns_dyn_mem_rate_limiting_threshold) { + if (!ns_monitor_packet_allocation_allowed()) { + // stack can not handle new packets for routing return NULL; } @@ -2251,6 +2259,25 @@ void mcps_sap_trig_tx(void *mac_ptr) } } +void mac_cca_threshold_event_send(protocol_interface_rf_mac_setup_s *rf_ptr, uint8_t channel, int16_t dbm) +{ + // Return if feature is not initialized + if (!rf_ptr->cca_threshold) { + return; + } + uint16_t data = channel << 8 | (uint8_t) dbm; + arm_event_s event = { + .receiver = mac_tasklet_event_handler, + .sender = 0, + .event_id = 0, + .event_data = data, + .data_ptr = rf_ptr, + .event_type = MAC_CCA_THR_UPDATE, + .priority = ARM_LIB_LOW_PRIORITY_EVENT, + }; + + eventOS_event_send(&event); +} void mac_generic_event_trig(uint8_t event_type, void *mac_ptr, bool low_latency) { @@ -2363,18 +2390,6 @@ uint8_t mcps_sap_purge_reg_handler(protocol_interface_rf_mac_setup_s *rf_mac_set return confirmation.status; } -int mcps_packet_ingress_rate_limit_by_memory(uint8_t free_heap_percentage) -{ - const mem_stat_t *ns_dyn_mem_stat = ns_dyn_mem_get_mem_stat(); - - if (ns_dyn_mem_stat && free_heap_percentage < 100) { - ns_dyn_mem_rate_limiting_threshold = ns_dyn_mem_stat->heap_sector_size / 100 * (100 - free_heap_percentage); - return 0; - } - - return -1; -} - void mcps_pending_packet_counter_update_check(protocol_interface_rf_mac_setup_s *rf_mac_setup, mac_pre_build_frame_t *buffer) { if (buffer->fcf_dsn.securityEnabled) { diff --git a/source/MAC/IEEE802_15_4/mac_mcps_sap.h b/source/MAC/IEEE802_15_4/mac_mcps_sap.h index de61fe8b91b..1a840041412 100644 --- a/source/MAC/IEEE802_15_4/mac_mcps_sap.h +++ b/source/MAC/IEEE802_15_4/mac_mcps_sap.h @@ -56,6 +56,7 @@ typedef enum { #define MAC_MLME_SCAN_CONFIRM_HANDLER 6 #define MAC_SAP_TRIG_TX 7 #define MCPS_SAP_DATA_ACK_CNF_EVENT 8 +#define MAC_CCA_THR_UPDATE 9 // Default number of CSMA-CA periods #define MAC_DEFAULT_NUMBER_OF_CSMA_PERIODS 1 @@ -142,4 +143,6 @@ uint32_t mac_mcps_sap_get_phy_timestamp(struct protocol_interface_rf_mac_setup * void mcps_pending_packet_counter_update_check(struct protocol_interface_rf_mac_setup *rf_mac_setup, mac_pre_build_frame_t *buffer); +void mac_cca_threshold_event_send(struct protocol_interface_rf_mac_setup *rf_mac_setup, uint8_t channel, int16_t dbm); + #endif /* MAC_IEEE802_15_4_MAC_MCPS_SAP_H_ */ diff --git a/source/MAC/IEEE802_15_4/mac_mlme.c b/source/MAC/IEEE802_15_4/mac_mlme.c index 8ea8f3355ce..901ef010714 100644 --- a/source/MAC/IEEE802_15_4/mac_mlme.c +++ b/source/MAC/IEEE802_15_4/mac_mlme.c @@ -48,6 +48,7 @@ #include "MAC/IEEE802_15_4/mac_timer.h" #include "MAC/IEEE802_15_4/mac_pd_sap.h" #include "MAC/IEEE802_15_4/mac_mcps_sap.h" +#include "MAC/IEEE802_15_4/mac_cca_threshold.h" #include "MAC/virtual_rf/virtual_rf_defines.h" #include "MAC/rf_driver_storage.h" @@ -668,14 +669,50 @@ static int8_t mac_mlme_set_ack_wait_duration(protocol_interface_rf_mac_setup_s * return 0; } +static void mac_mlme_trig_pending_ack(protocol_interface_rf_mac_setup_s *rf_mac_setup, mlme_device_descriptor_t *device_ptr) +{ + platform_enter_critical(); + if (rf_mac_setup->mac_ack_tx_active && !rf_mac_setup->ack_tx_possible && + device_ptr->PANId == rf_mac_setup->enhanced_ack_buffer.DstPANId) { + + //Compare address for pending neigbour add + if (rf_mac_setup->enhanced_ack_buffer.fcf_dsn.DstAddrMode == MAC_ADDR_MODE_16_BIT) { + uint16_t short_id = common_read_16_bit(rf_mac_setup->enhanced_ack_buffer.DstAddr); + if (short_id == device_ptr->ShortAddress) { + rf_mac_setup->ack_tx_possible = true; + } + } else if (rf_mac_setup->enhanced_ack_buffer.fcf_dsn.DstAddrMode == MAC_ADDR_MODE_64_BIT) { + if (memcmp(device_ptr->ExtAddress, rf_mac_setup->enhanced_ack_buffer.DstAddr, 8) == 0) { + rf_mac_setup->ack_tx_possible = true; + } + } + } + platform_exit_critical(); +} + static int8_t mac_mlme_device_description_set(protocol_interface_rf_mac_setup_s *rf_mac_setup, const mlme_set_t *set_req) { if (set_req->value_size != sizeof(mlme_device_descriptor_t)) { return -1; } + if (mac_sec_mib_device_description_set(set_req->attr_index, (mlme_device_descriptor_t *) set_req->value_pointer, rf_mac_setup) != 0) { + return -1; + } - return mac_sec_mib_device_description_set(set_req->attr_index, (mlme_device_descriptor_t *) set_req->value_pointer, rf_mac_setup); + mac_mlme_trig_pending_ack(rf_mac_setup, (mlme_device_descriptor_t *) set_req->value_pointer); + return 0; +} + +static int8_t mac_mlme_device_pending_ack_trig(protocol_interface_rf_mac_setup_s *rf_mac_setup, const mlme_set_t *set_req) +{ + + if (set_req->value_size != sizeof(mlme_device_descriptor_t)) { + return -1; + } + mac_mlme_trig_pending_ack(rf_mac_setup, (mlme_device_descriptor_t *) set_req->value_pointer); + + return 0; } static int8_t mac_mlme_key_description_set(protocol_interface_rf_mac_setup_s *rf_mac_setup, const mlme_set_t *set_req) @@ -754,6 +791,8 @@ int8_t mac_mlme_set_req(protocol_interface_rf_mac_setup_s *rf_mac_setup, const m return mac_mlme_set_ack_wait_duration(rf_mac_setup, set_req); case macDeviceTable: return mac_mlme_device_description_set(rf_mac_setup, set_req); + case macDevicePendingAckTrig: + return mac_mlme_device_pending_ack_trig(rf_mac_setup, set_req); case macKeyTable: return mac_mlme_key_description_set(rf_mac_setup, set_req); case macDefaultKeySource: @@ -768,6 +807,10 @@ int8_t mac_mlme_set_req(protocol_interface_rf_mac_setup_s *rf_mac_setup, const m memcpy(rf_mac_setup->coord_long_address, set_req->value_pointer, 8); } return 0; + case macCCAThresholdStart: + pu8 = (uint8_t *) set_req->value_pointer; + mac_cca_thr_init(rf_mac_setup, *pu8, *((int8_t *)pu8 + 1), *((int8_t *)pu8 + 2), *((int8_t *)pu8 + 3)); + return 0; case mac802_15_4Mode: pu8 = (uint8_t *) set_req->value_pointer; if (rf_mac_setup->current_mac_mode == *pu8) { @@ -1059,6 +1102,7 @@ void mac_mlme_data_base_deallocate(struct protocol_interface_rf_mac_setup *rf_ma ns_dyn_mem_free(rf_mac->mac_beacon_payload); mac_sec_mib_deinit(rf_mac); + mac_cca_thr_deinit(rf_mac); ns_dyn_mem_free(rf_mac); } } diff --git a/source/MAC/IEEE802_15_4/mac_pd_sap.c b/source/MAC/IEEE802_15_4/mac_pd_sap.c index 09952b9b108..ec34ef77aea 100644 --- a/source/MAC/IEEE802_15_4/mac_pd_sap.c +++ b/source/MAC/IEEE802_15_4/mac_pd_sap.c @@ -34,6 +34,7 @@ #include "MAC/IEEE802_15_4/mac_mlme.h" #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/rf_driver_storage.h" /* Define TX Timeot Period */ @@ -45,7 +46,7 @@ #define MIN_FHSS_CSMA_PERIOD_US 5000 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); +static void mac_sap_cca_fail_cb(protocol_interface_rf_mac_setup_s *rf_ptr, uint16_t failed_channel); void mac_csma_param_init(protocol_interface_rf_mac_setup_s *rf_mac_setup) { @@ -273,7 +274,7 @@ void mac_pd_sap_state_machine(protocol_interface_rf_mac_setup_s *rf_mac_setup) if (rf_mac_setup->mac_tx_result == MAC_TIMER_CCA) { if (rf_mac_setup->rf_csma_extension_supported) { - mac_sap_cca_fail_cb(rf_mac_setup); + mac_sap_cca_fail_cb(rf_mac_setup, 0xffff); return; } @@ -328,7 +329,7 @@ void mac_pd_sap_state_machine(protocol_interface_rf_mac_setup_s *rf_mac_setup) } } -static void mac_sap_cca_fail_cb(protocol_interface_rf_mac_setup_s *rf_ptr) +static void mac_sap_cca_fail_cb(protocol_interface_rf_mac_setup_s *rf_ptr, uint16_t failed_channel) { if (rf_ptr->mac_ack_tx_active) { if (rf_ptr->active_pd_data_request) { @@ -340,6 +341,11 @@ static void mac_sap_cca_fail_cb(protocol_interface_rf_mac_setup_s *rf_ptr) if (rf_ptr->mac_cca_retry > rf_ptr->macMaxCSMABackoffs || (rf_ptr->active_pd_data_request && rf_ptr->active_pd_data_request->asynch_request)) { //Send MAC_CCA_FAIL mac_tx_done_state_set(rf_ptr, MAC_CCA_FAIL); + if (failed_channel != 0xffff && rf_ptr->active_pd_data_request) { + if (failed_channel == rf_ptr->active_pd_data_request->initial_tx_channel) { + mac_cca_threshold_event_send(rf_ptr, failed_channel, CCA_FAILED_DBM); + } + } } else { timer_mac_stop(rf_ptr); mac_csma_BE_update(rf_ptr); @@ -414,7 +420,7 @@ static void mac_data_ack_tx_finish(protocol_interface_rf_mac_setup_s *rf_ptr) mcps_pending_packet_counter_update_check(rf_ptr, rf_ptr->active_pd_data_request); //GEN TX failure - mac_sap_cca_fail_cb(rf_ptr); + mac_sap_cca_fail_cb(rf_ptr, 0xffff); } } @@ -442,6 +448,11 @@ static int8_t mac_data_interface_tx_done_cb(protocol_interface_rf_mac_setup_s *r } if (mac_data_asynch_channel_switch(rf_ptr, rf_ptr->active_pd_data_request)) { + rf_ptr->active_pd_data_request->initial_tx_channel = rf_ptr->mac_channel; + int8_t channel_cca_threshold = mac_cca_thr_get_dbm(rf_ptr, rf_ptr->mac_channel); + if (CCA_FAILED_DBM != channel_cca_threshold) { + rf_ptr->dev_driver->phy_driver->extension(PHY_EXTENSION_SET_CHANNEL_CCA_THRESHOLD, (uint8_t *)&channel_cca_threshold); + } return PHY_TX_ALLOWED; } @@ -458,7 +469,7 @@ static int8_t mac_data_interface_tx_done_cb(protocol_interface_rf_mac_setup_s *r rf_ptr->dev_driver->phy_driver->phy_tail_length, active_buf->tx_time); // When FHSS TX handle returns -1, transmission of the packet is currently not allowed -> restart CCA timer if (tx_handle_retval == -1) { - mac_sap_cca_fail_cb(rf_ptr); + mac_sap_cca_fail_cb(rf_ptr, 0xffff); return PHY_TX_NOT_ALLOWED; } // When FHSS TX handle returns -3, we are trying to transmit broadcast packet on unicast channel -> push back @@ -470,6 +481,13 @@ static int8_t mac_data_interface_tx_done_cb(protocol_interface_rf_mac_setup_s *r mac_tx_done_state_set(rf_ptr, MAC_UNKNOWN_DESTINATION); return PHY_TX_NOT_ALLOWED; } + if (rf_ptr->mac_cca_retry == 0 && rf_ptr->active_pd_data_request) { + rf_ptr->active_pd_data_request->initial_tx_channel = rf_ptr->mac_channel; + } + int8_t channel_cca_threshold = mac_cca_thr_get_dbm(rf_ptr, rf_ptr->mac_channel); + if (CCA_FAILED_DBM != channel_cca_threshold) { + rf_ptr->dev_driver->phy_driver->extension(PHY_EXTENSION_SET_CHANNEL_CCA_THRESHOLD, (uint8_t *)&channel_cca_threshold); + } if (active_buf->csma_periods_left > 0) { active_buf->csma_periods_left--; active_buf->tx_time += rf_ptr->multi_cca_interval; @@ -501,7 +519,7 @@ static int8_t mac_data_interface_tx_done_cb(protocol_interface_rf_mac_setup_s *r rf_ptr->mac_tx_retry += tx_retry; 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) { /* waiting_ack == false allows FHSS to change back to RX channel after transmission * tx_completed == true allows FHSS to delete stored failure handles @@ -543,7 +561,7 @@ static int8_t mac_data_interface_tx_done_cb(protocol_interface_rf_mac_setup_s *r break; case PHY_LINK_CCA_FAIL: - mac_sap_cca_fail_cb(rf_ptr); + mac_sap_cca_fail_cb(rf_ptr, failed_channel); break; case PHY_LINK_CCA_OK: @@ -788,10 +806,16 @@ static int8_t mac_pd_sap_generate_ack(protocol_interface_rf_mac_setup_s *rf_ptr, return -1; } - if (mac_sec_mib_device_description_get(rf_ptr, rf_ptr->enhanced_ack_buffer.DstAddr, rf_ptr->enhanced_ack_buffer.fcf_dsn.DstAddrMode, rf_ptr->enhanced_ack_buffer.DstPANId)) { + + if (rf_ptr->enhanced_ack_buffer.fcf_dsn.securityEnabled == 0 || rf_ptr->enhanced_ack_buffer.aux_header.securityLevel == 0) { + //Unsecured data will be acked immediately rf_ptr->ack_tx_possible = true; } else { - rf_ptr->ack_tx_possible = false; + if (mac_sec_mib_device_description_get(rf_ptr, rf_ptr->enhanced_ack_buffer.DstAddr, rf_ptr->enhanced_ack_buffer.fcf_dsn.DstAddrMode, rf_ptr->enhanced_ack_buffer.DstPANId)) { + rf_ptr->ack_tx_possible = true; + } else { + rf_ptr->ack_tx_possible = false; + } } return mcps_generic_ack_build(rf_ptr, true); @@ -898,7 +922,7 @@ int8_t mac_pd_sap_data_cb(void *identifier, arm_phy_sap_msg_t *message) 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); diff --git a/source/MAC/IEEE802_15_4/mac_security_mib.c b/source/MAC/IEEE802_15_4/mac_security_mib.c index abe65d668bc..0897b78bb9e 100644 --- a/source/MAC/IEEE802_15_4/mac_security_mib.c +++ b/source/MAC/IEEE802_15_4/mac_security_mib.c @@ -295,21 +295,6 @@ int8_t mac_sec_mib_device_description_set(uint8_t atribute_index, mlme_device_de *device_ptr = *device_descriptor; - if (rf_mac_setup->mac_ack_tx_active && !rf_mac_setup->ack_tx_possible && - device_ptr->PANId == rf_mac_setup->enhanced_ack_buffer.DstPANId) { - - //Compare address for pending neigbour add - if (rf_mac_setup->enhanced_ack_buffer.fcf_dsn.DstAddrMode == MAC_ADDR_MODE_16_BIT) { - uint16_t short_id = common_read_16_bit(rf_mac_setup->enhanced_ack_buffer.DstAddr); - if (short_id == device_ptr->ShortAddress) { - rf_mac_setup->ack_tx_possible = true; - } - } else if (rf_mac_setup->enhanced_ack_buffer.fcf_dsn.DstAddrMode == MAC_ADDR_MODE_64_BIT) { - if (memcmp(device_ptr->ExtAddress, rf_mac_setup->enhanced_ack_buffer.DstAddr, 8) == 0) { - rf_mac_setup->ack_tx_possible = true; - } - } - } platform_exit_critical(); return 0; diff --git a/source/MAC/ethernet/ethernet_mac_api.c b/source/MAC/ethernet/ethernet_mac_api.c index 228ad7b5535..fb4d9d21769 100644 --- a/source/MAC/ethernet/ethernet_mac_api.c +++ b/source/MAC/ethernet/ethernet_mac_api.c @@ -22,6 +22,7 @@ #include "nsdynmemLIB.h" #include "common_functions.h" #include "MAC/rf_driver_storage.h" +#include "Core/include/ns_monitor.h" typedef struct eth_mac_internal_s { eth_mac_api_t *mac_api; @@ -269,6 +270,11 @@ static int8_t eth_mac_net_phy_rx(const uint8_t *data_ptr, uint16_t data_len, uin return -1; } + if (!ns_monitor_packet_allocation_allowed()) { + // stack can not handle new packets for routing + return -1; + } + eth_data_ind_t *data_ind = ns_dyn_mem_temporary_alloc(sizeof(eth_data_ind_t)); if (!data_ind) { return -1; diff --git a/source/MAC/serial/serial_mac_api.c b/source/MAC/serial/serial_mac_api.c index 469635208c2..b3ffa24bea3 100644 --- a/source/MAC/serial/serial_mac_api.c +++ b/source/MAC/serial/serial_mac_api.c @@ -23,6 +23,7 @@ #include "common_functions.h" #include "ns_trace.h" #include "MAC/rf_driver_storage.h" +#include "Core/include/ns_monitor.h" #define TRACE_GROUP "seMa" @@ -317,10 +318,16 @@ static int8_t serial_mac_net_phy_rx(const uint8_t *data_ptr, uint16_t data_len, (void)link_quality; (void) dbm; + if (!ns_monitor_packet_allocation_allowed()) { + // stack can not handle new packets for routing + return -1; + } + serial_data_ind_t *data_ind = ns_dyn_mem_temporary_alloc(sizeof(serial_data_ind_t)); if (!data_ind) { return -1; } + data_ind->msdu = ns_dyn_mem_temporary_alloc(data_len); if (!data_ind->msdu) { ns_dyn_mem_free(data_ind); diff --git a/source/RPL/rpl_control.c b/source/RPL/rpl_control.c index d555eb8124b..37eacc43452 100644 --- a/source/RPL/rpl_control.c +++ b/source/RPL/rpl_control.c @@ -391,7 +391,7 @@ static void rpl_control_addr_notifier(struct protocol_interface_info_entry *inte } } -static void rpl_control_etx_change_callback(int8_t nwk_id, uint16_t previous_etx, uint16_t current_etx, uint8_t attribute_index) +static void rpl_control_etx_change_callback(int8_t nwk_id, uint16_t previous_etx, uint16_t current_etx, uint8_t attribute_index, const uint8_t *mac64) { protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(nwk_id); @@ -405,14 +405,29 @@ static void rpl_control_etx_change_callback(int8_t nwk_id, uint16_t previous_et uint16_t delay = rpl_policy_etx_change_parent_selection_delay(domain); tr_debug("Triggering parent selection due to ETX %s on neigh index %u, etx %u", better ? "better" : "worse", attribute_index, current_etx); rpl_dodag_t *dodag = NULL; + //Define Link Local Address + uint8_t ll_parent_address[16]; + memcpy(ll_parent_address, ADDR_LINK_LOCAL_PREFIX, 8); + memcpy(ll_parent_address + 8, mac64, 8); + ll_parent_address[8] ^= 2; ns_list_foreach(rpl_instance_t, instance, &domain->instances) { - if (better) { - dodag = rpl_instance_current_dodag(instance); - } - rpl_instance_trigger_parent_selection(instance, delay, dodag); + if (rpl_instance_am_root(instance)) { rpl_downward_paths_invalidate(instance); + } else { + if (better) { + //Only react here for candidate updates and when DODAG version is configured + if (rpl_instance_address_is_candidate(instance, ll_parent_address, 0)) { + dodag = rpl_instance_current_dodag(instance); + if (dodag) { + rpl_instance_trigger_parent_selection(instance, delay, dodag); + } + } + } else if (rpl_instance_address_is_parent(instance, ll_parent_address)) { + //Quick reaction for selected parent only + rpl_instance_trigger_parent_selection(instance, delay, NULL); + } } } } @@ -1886,6 +1901,11 @@ static void rpl_domain_print(const rpl_domain_t *domain, route_print_fn_t *print } } +uint16_t rpl_control_route_table_get(struct rpl_instance *instance, uint8_t *prefix, rpl_route_info_t *output_table, uint16_t output_table_len) +{ + return rpl_downward_route_table_get(instance, prefix, output_table, output_table_len); +} + void rpl_control_print(route_print_fn_t *print_fn) { unsigned t = protocol_core_monotonic_time % 10; diff --git a/source/RPL/rpl_control.h b/source/RPL/rpl_control.h index 613d47eb054..5b9f6c26cf9 100644 --- a/source/RPL/rpl_control.h +++ b/source/RPL/rpl_control.h @@ -44,6 +44,10 @@ typedef void rpl_prefix_callback_t(struct prefix_entry_t *prefix, void *handle, typedef bool rpl_new_parent_callback_t(uint8_t *ll_parent_address, void *handle, struct rpl_instance *instance, uint16_t candidate_rank); +typedef struct rpl_route_info { + uint8_t node[8]; /* IID of parent in parent child relation table */ + uint8_t parent[8]; /* IID of child in parent child relation table */ +} rpl_route_info_t; typedef struct rpl_domain { NS_LIST_HEAD_INCOMPLETE(struct rpl_instance) instances; @@ -186,6 +190,7 @@ ipv6_route_predicate_fn_t *rpl_control_get_route_predicate(rpl_domain_t *domain, /* Diagnostic APIs */ void rpl_control_print(route_print_fn_t *print_fn); +uint16_t rpl_control_route_table_get(struct rpl_instance *instance, uint8_t *prefix, rpl_route_info_t *output_table, uint16_t output_table_len); struct rpl_instance *rpl_control_enumerate_instances(rpl_domain_t *domain, struct rpl_instance *instance); struct rpl_instance *rpl_control_lookup_instance(rpl_domain_t *domain, uint8_t instance_id, const uint8_t *dodagid); diff --git a/source/RPL/rpl_downward.c b/source/RPL/rpl_downward.c index 34ca3cf6b73..e97416c752f 100644 --- a/source/RPL/rpl_downward.c +++ b/source/RPL/rpl_downward.c @@ -1754,6 +1754,52 @@ void rpl_downward_print_instance(rpl_instance_t *instance, route_print_fn_t *pri } } +uint16_t rpl_downward_route_table_get(rpl_instance_t *instance, uint8_t *prefix, rpl_route_info_t *output_table, uint16_t output_table_len) +{ + uint16_t index = 0; + + if (!prefix || !output_table || !output_table_len) { + return 0; + } + if (ns_list_is_empty(&instance->dao_targets)) { + return 0; + } + if (!rpl_instance_am_root(instance)) { + // Question should this be available also for non roots in storing mode + return 0; + } + +#ifdef HAVE_RPL_ROOT + rpl_downward_compute_paths(instance); + + ns_list_foreach(rpl_dao_target_t, target, &instance->dao_targets) { + if (memcmp(target->prefix, prefix, 8) != 0) { + continue; + } + + if (target->root) { + /* Target has root structure + * We take the first transit only from table as simple topology is needed + */ + rpl_dao_root_transit_t *transit = ns_list_get_first(&target->info.root.transits); + if (transit) { + memcpy(output_table->node, &target->prefix[8], 8); + memcpy(output_table->parent, &transit->transit[8], 8); + + index++; + if (index == output_table_len) { + //table is full + return index; + } + output_table++; + } + } + /* We dont put non roots to list so border router is not visible as a node in list*/ + } +#endif + return index; +} + rpl_dao_target_t *rpl_instance_get_active_target_confirmation(rpl_instance_t *instance) { ns_list_foreach_safe(rpl_dao_target_t, n, &instance->dao_targets) { diff --git a/source/RPL/rpl_downward.h b/source/RPL/rpl_downward.h index b2b8faa5c84..c7cd66f27f1 100644 --- a/source/RPL/rpl_downward.h +++ b/source/RPL/rpl_downward.h @@ -27,6 +27,7 @@ struct rpl_dao_root_transit; void rpl_downward_dao_slow_timer(struct rpl_instance *instance, uint16_t seconds); void rpl_downward_dao_timer(struct rpl_instance *instance, uint16_t ticks); void rpl_downward_print_instance(struct rpl_instance *instance, route_print_fn_t *print_fn); +uint16_t rpl_downward_route_table_get(rpl_instance_t *instance, uint8_t *prefix, rpl_route_info_t *output_table, uint16_t output_table_len); void rpl_downward_convert_dodag_preferences_to_dao_path_control(struct rpl_dodag *dodag); void rpl_downward_process_dao_parent_changes(struct rpl_instance *instance); diff --git a/source/Security/kmp/kmp_api.c b/source/Security/kmp/kmp_api.c index 345e9ba9fc7..d3a61fe867d 100644 --- a/source/Security/kmp/kmp_api.c +++ b/source/Security/kmp/kmp_api.c @@ -99,7 +99,7 @@ static void kmp_sec_prot_receive_disable(sec_prot_t *prot); #define kmp_api_get_from_prot(prot) (kmp_api_t *)(((uint8_t *)prot) - offsetof(kmp_api_t, sec_prot)); -kmp_api_t *kmp_api_create(kmp_service_t *service, kmp_type_e type, sec_prot_cfg_t *cfg) +kmp_api_t *kmp_api_create(kmp_service_t *service, kmp_type_e type, sec_prot_cfg_t *prot_cfg, sec_timer_cfg_t *timer_cfg) { if (!service) { return 0; @@ -151,7 +151,8 @@ kmp_api_t *kmp_api_create(kmp_service_t *service, kmp_type_e type, sec_prot_cfg_ kmp->sec_prot.addr_get = kmp_sec_prot_eui64_addr_get; kmp->sec_prot.type_get = kmp_sec_prot_by_type_get; kmp->sec_prot.receive_disable = kmp_sec_prot_receive_disable; - kmp->sec_prot.cfg = cfg; + kmp->sec_prot.prot_cfg = prot_cfg; + kmp->sec_prot.timer_cfg = timer_cfg; if (sec_prot->init(&kmp->sec_prot) < 0) { ns_dyn_mem_free(kmp); diff --git a/source/Security/kmp/kmp_api.h b/source/Security/kmp/kmp_api.h index 062b36b4ad5..10f36528bdd 100644 --- a/source/Security/kmp/kmp_api.h +++ b/source/Security/kmp/kmp_api.h @@ -125,12 +125,13 @@ typedef void kmp_api_finished(kmp_api_t *kmp); * * \param service KMP service * \param type KMP type - * \param cfg configuration + * \param prot_cfg protocol configuration + * \param timer_cfg timer configuration * * \return KMP instance or NULL * */ -kmp_api_t *kmp_api_create(kmp_service_t *service, kmp_type_e type, sec_prot_cfg_t *cfg); +kmp_api_t *kmp_api_create(kmp_service_t *service, kmp_type_e type, sec_prot_cfg_t *prot_cfg, sec_timer_cfg_t *timer_cfg); /** * kmp_api_start start KMP api diff --git a/source/Security/protocols/eap_tls_sec_prot/auth_eap_tls_sec_prot.c b/source/Security/protocols/eap_tls_sec_prot/auth_eap_tls_sec_prot.c index e8118585ad5..2fd7d96b65b 100644 --- a/source/Security/protocols/eap_tls_sec_prot/auth_eap_tls_sec_prot.c +++ b/source/Security/protocols/eap_tls_sec_prot/auth_eap_tls_sec_prot.c @@ -189,7 +189,7 @@ static int8_t auth_eap_tls_sec_prot_receive(sec_prot_t *prot, void *pdu, uint16_ // Call state machine prot->state_machine(prot); // Resets trickle timer to give time for supplicant to answer - sec_prot_timer_trickle_start(&data->common, &prot->cfg->sec_prot_trickle_params); + sec_prot_timer_trickle_start(&data->common, &prot->prot_cfg->sec_prot_trickle_params); data->init_key_cnt++; } // Filters repeated initial EAPOL-key messages @@ -297,7 +297,7 @@ static void auth_eap_tls_sec_prot_timer_timeout(sec_prot_t *prot, uint16_t ticks } sec_prot_timer_timeout_handle(prot, &data->common, - &prot->cfg->sec_prot_trickle_params, ticks); + &prot->prot_cfg->sec_prot_trickle_params, ticks); } static void auth_eap_tls_sec_prot_tls_create_indication(sec_prot_t *tls_prot) @@ -421,7 +421,7 @@ static void auth_eap_tls_sec_prot_state_machine(sec_prot_t *prot) auth_eap_tls_sec_prot_message_send(prot, EAP_REQ, EAP_IDENTITY, EAP_TLS_EXCHANGE_NONE); // Start trickle timer to re-send if no response - sec_prot_timer_trickle_start(&data->common, &prot->cfg->sec_prot_trickle_params); + sec_prot_timer_trickle_start(&data->common, &prot->prot_cfg->sec_prot_trickle_params); sec_prot_state_set(prot, &data->common, EAP_TLS_STATE_RESPONSE_ID); break; @@ -445,7 +445,7 @@ static void auth_eap_tls_sec_prot_state_machine(sec_prot_t *prot) auth_eap_tls_sec_prot_message_send(prot, EAP_REQ, EAP_TLS, EAP_TLS_EXCHANGE_START); // Start trickle timer to re-send if no response - sec_prot_timer_trickle_start(&data->common, &prot->cfg->sec_prot_trickle_params); + sec_prot_timer_trickle_start(&data->common, &prot->prot_cfg->sec_prot_trickle_params); sec_prot_state_set(prot, &data->common, EAP_TLS_STATE_RESPONSE_START); break; @@ -527,7 +527,7 @@ static void auth_eap_tls_sec_prot_state_machine(sec_prot_t *prot) auth_eap_tls_sec_prot_message_send(prot, EAP_REQ, EAP_TLS, EAP_TLS_EXCHANGE_ONGOING); // Start trickle timer to re-send if no response - sec_prot_timer_trickle_start(&data->common, &prot->cfg->sec_prot_trickle_params); + sec_prot_timer_trickle_start(&data->common, &prot->prot_cfg->sec_prot_trickle_params); } else { // TLS done, indicate success to peer if (data->tls_result == EAP_TLS_RESULT_HANDSHAKE_OVER) { diff --git a/source/Security/protocols/eap_tls_sec_prot/supp_eap_tls_sec_prot.c b/source/Security/protocols/eap_tls_sec_prot/supp_eap_tls_sec_prot.c index c7c935242d7..b7df2d6eb6f 100644 --- a/source/Security/protocols/eap_tls_sec_prot/supp_eap_tls_sec_prot.c +++ b/source/Security/protocols/eap_tls_sec_prot/supp_eap_tls_sec_prot.c @@ -404,7 +404,7 @@ static void supp_eap_tls_sec_prot_state_machine(sec_prot_t *prot) } // Set retry timeout based on network size - data->common.ticks = prot->cfg->sec_prot_retry_timeout; + data->common.ticks = prot->prot_cfg->sec_prot_retry_timeout; // Store sequence ID supp_eap_tls_sec_prot_seq_id_update(prot); @@ -449,7 +449,7 @@ static void supp_eap_tls_sec_prot_state_machine(sec_prot_t *prot) supp_eap_tls_sec_prot_seq_id_update(prot); sec_prot_state_set(prot, &data->common, EAP_TLS_STATE_REQUEST); - data->common.ticks = prot->cfg->sec_prot_retry_timeout; + data->common.ticks = prot->prot_cfg->sec_prot_retry_timeout; // Initialize TLS protocol if (supp_eap_tls_sec_prot_init_tls(prot) < 0) { @@ -483,7 +483,7 @@ static void supp_eap_tls_sec_prot_state_machine(sec_prot_t *prot) // Store sequence ID if (supp_eap_tls_sec_prot_seq_id_update(prot)) { // When receiving a new sequence number, adds more time for re-send if no response - data->common.ticks = prot->cfg->sec_prot_retry_timeout; + data->common.ticks = prot->prot_cfg->sec_prot_retry_timeout; } // All fragments received for a message diff --git a/source/Security/protocols/fwh_sec_prot/auth_fwh_sec_prot.c b/source/Security/protocols/fwh_sec_prot/auth_fwh_sec_prot.c index b43ca5e58f4..285a75db8e3 100644 --- a/source/Security/protocols/fwh_sec_prot/auth_fwh_sec_prot.c +++ b/source/Security/protocols/fwh_sec_prot/auth_fwh_sec_prot.c @@ -66,6 +66,7 @@ typedef struct { fwh_sec_prot_msg_e recv_msg; /**< Received message */ uint8_t nonce[EAPOL_KEY_NONCE_LEN]; /**< Authenticator nonce */ uint8_t new_ptk[PTK_LEN]; /**< PTK (384 bits) */ + uint8_t remote_eui64[8]; /**< Remote EUI-64 used to calculate PTK */ void *recv_pdu; /**< received pdu */ uint16_t recv_size; /**< received pdu size */ } fwh_sec_prot_int_t; @@ -265,14 +266,20 @@ static int8_t auth_fwh_sec_prot_message_send(sec_prot_t *prot, fwh_sec_prot_msg_ switch (msg) { case FWH_MESSAGE_1: - sec_prot_keys_pmk_replay_cnt_increment(prot->sec_keys); + if (!sec_prot_keys_pmk_replay_cnt_increment(prot->sec_keys)) { + ns_dyn_mem_free(kde_start); + return 1; + } eapol_pdu.msg.key.replay_counter = sec_prot_keys_pmk_replay_cnt_get(prot->sec_keys); eapol_pdu.msg.key.key_information.key_ack = true; eapol_pdu.msg.key.key_length = EAPOL_KEY_LEN; eapol_pdu.msg.key.key_nonce = data->nonce; break; case FWH_MESSAGE_3: - sec_prot_keys_pmk_replay_cnt_increment(prot->sec_keys); + if (!sec_prot_keys_pmk_replay_cnt_increment(prot->sec_keys)) { + ns_dyn_mem_free(kde_start); + return -1; + } eapol_pdu.msg.key.replay_counter = sec_prot_keys_pmk_replay_cnt_get(prot->sec_keys); eapol_pdu.msg.key.key_information.install = true; eapol_pdu.msg.key.key_information.key_ack = true; @@ -306,7 +313,7 @@ static int8_t auth_fwh_sec_prot_message_send(sec_prot_t *prot, fwh_sec_prot_msg_ static void auth_fwh_sec_prot_timer_timeout(sec_prot_t *prot, uint16_t ticks) { fwh_sec_prot_int_t *data = fwh_sec_prot_get(prot); - sec_prot_timer_timeout_handle(prot, &data->common, &prot->cfg->sec_prot_trickle_params, ticks); + sec_prot_timer_timeout_handle(prot, &data->common, &prot->prot_cfg->sec_prot_trickle_params, ticks); } static void auth_fwh_sec_prot_state_machine(sec_prot_t *prot) @@ -343,7 +350,7 @@ static void auth_fwh_sec_prot_state_machine(sec_prot_t *prot) auth_fwh_sec_prot_message_send(prot, FWH_MESSAGE_1); // Start trickle timer to re-send if no response - sec_prot_timer_trickle_start(&data->common, &prot->cfg->sec_prot_trickle_params); + sec_prot_timer_trickle_start(&data->common, &prot->prot_cfg->sec_prot_trickle_params); sec_prot_state_set(prot, &data->common, FWH_STATE_MESSAGE_2); break; @@ -371,7 +378,7 @@ static void auth_fwh_sec_prot_state_machine(sec_prot_t *prot) auth_fwh_sec_prot_message_send(prot, FWH_MESSAGE_3); // Start trickle timer to re-send if no response - sec_prot_timer_trickle_start(&data->common, &prot->cfg->sec_prot_trickle_params); + sec_prot_timer_trickle_start(&data->common, &prot->prot_cfg->sec_prot_trickle_params); sec_prot_state_set(prot, &data->common, FWH_STATE_MESSAGE_4); } @@ -391,12 +398,16 @@ static void auth_fwh_sec_prot_state_machine(sec_prot_t *prot) } // PTK is fresh for installing any GTKs sec_prot_keys_ptk_installed_gtk_hash_clear_all(prot->sec_keys); + /* Store the hash for to-be installed GTK as used for the PTK, on 4WH + this stores only the hash in NVM and does not affect otherwise */ + sec_prot_keys_ptk_installed_gtk_hash_set(prot->sec_keys, true); // If GTK was inserted set it valid sec_prot_keys_gtkl_from_gtk_insert_index_set(prot->sec_keys); // Reset PTK mismatch sec_prot_keys_ptk_mismatch_reset(prot->sec_keys); // Update PTK - sec_prot_keys_ptk_write(prot->sec_keys, data->new_ptk); + sec_prot_keys_ptk_write(prot->sec_keys, data->new_ptk, prot->timer_cfg->ptk_lifetime); + sec_prot_keys_ptk_eui_64_write(prot->sec_keys, data->remote_eui64); sec_prot_state_set(prot, &data->common, FWH_STATE_FINISH); } break; @@ -427,9 +438,7 @@ static int8_t auth_fwh_sec_prot_ptk_generate(sec_prot_t *prot, sec_prot_keys_t * fwh_sec_prot_int_t *data = fwh_sec_prot_get(prot); uint8_t local_eui64[8]; - uint8_t remote_eui64[8]; - - prot->addr_get(prot, local_eui64, remote_eui64); + prot->addr_get(prot, local_eui64, data->remote_eui64); uint8_t *remote_nonce = data->recv_eapol_pdu.msg.key.key_nonce; if (!remote_nonce) { @@ -438,7 +447,7 @@ static int8_t auth_fwh_sec_prot_ptk_generate(sec_prot_t *prot, sec_prot_keys_t * } uint8_t *pmk = sec_prot_keys_pmk_get(sec_keys); - sec_prot_lib_ptk_calc(pmk, local_eui64, remote_eui64, data->nonce, remote_nonce, data->new_ptk); + sec_prot_lib_ptk_calc(pmk, local_eui64, data->remote_eui64, data->nonce, remote_nonce, data->new_ptk); return 0; } diff --git a/source/Security/protocols/fwh_sec_prot/supp_fwh_sec_prot.c b/source/Security/protocols/fwh_sec_prot/supp_fwh_sec_prot.c index e5a44e18b8d..ef3e9bd9915 100644 --- a/source/Security/protocols/fwh_sec_prot/supp_fwh_sec_prot.c +++ b/source/Security/protocols/fwh_sec_prot/supp_fwh_sec_prot.c @@ -139,7 +139,7 @@ static int8_t supp_fwh_sec_prot_init(sec_prot_t *prot) sec_prot_init(&data->common); sec_prot_state_set(prot, &data->common, FWH_STATE_INIT); - data->common.ticks = prot->cfg->sec_prot_retry_timeout; + data->common.ticks = prot->prot_cfg->sec_prot_retry_timeout; data->msg3_received = false; data->msg3_retry_wait = false; data->recv_replay_cnt = 0; @@ -337,7 +337,7 @@ static void supp_fwh_sec_prot_state_machine(sec_prot_t *prot) if (sec_prot_result_ok_check(&data->common)) { // Send 4WH message 2 supp_fwh_sec_prot_message_send(prot, FWH_MESSAGE_2); - data->common.ticks = prot->cfg->sec_prot_retry_timeout; + data->common.ticks = prot->prot_cfg->sec_prot_retry_timeout; sec_prot_state_set(prot, &data->common, FWH_STATE_MESSAGE_3); } else { // Ready to be deleted @@ -365,7 +365,7 @@ static void supp_fwh_sec_prot_state_machine(sec_prot_t *prot) // Send 4WH message 2 supp_fwh_sec_prot_message_send(prot, FWH_MESSAGE_2); - data->common.ticks = prot->cfg->sec_prot_retry_timeout; + data->common.ticks = prot->prot_cfg->sec_prot_retry_timeout; return; } else if (data->recv_msg != FWH_MESSAGE_3) { return; @@ -392,7 +392,7 @@ static void supp_fwh_sec_prot_state_machine(sec_prot_t *prot) // Sends 4WH Message 4 supp_fwh_sec_prot_message_send(prot, FWH_MESSAGE_4); - data->common.ticks = prot->cfg->sec_prot_retry_timeout; + data->common.ticks = prot->prot_cfg->sec_prot_retry_timeout; sec_prot_state_set(prot, &data->common, FWH_STATE_FINISH); break; @@ -409,7 +409,7 @@ static void supp_fwh_sec_prot_state_machine(sec_prot_t *prot) tr_info("4WH: finish, wait Message 3 retry"); - sec_prot_keys_ptk_write(prot->sec_keys, data->new_ptk); + sec_prot_keys_ptk_write(prot->sec_keys, data->new_ptk, prot->timer_cfg->ptk_lifetime); sec_prot_keys_ptk_eui_64_write(prot->sec_keys, data->remote_eui64); data->common.ticks = 60 * 10; // 60 seconds diff --git a/source/Security/protocols/gkh_sec_prot/auth_gkh_sec_prot.c b/source/Security/protocols/gkh_sec_prot/auth_gkh_sec_prot.c index 9c1b47d01df..7d736ae95b7 100644 --- a/source/Security/protocols/gkh_sec_prot/auth_gkh_sec_prot.c +++ b/source/Security/protocols/gkh_sec_prot/auth_gkh_sec_prot.c @@ -226,7 +226,10 @@ static int8_t auth_gkh_sec_prot_message_send(sec_prot_t *prot, gkh_sec_prot_msg_ switch (msg) { case GKH_MESSAGE_1: - sec_prot_keys_pmk_replay_cnt_increment(prot->sec_keys); + if (!sec_prot_keys_pmk_replay_cnt_increment(prot->sec_keys)) { + ns_dyn_mem_free(kde_start); + return -1; + } eapol_pdu.msg.key.replay_counter = sec_prot_keys_pmk_replay_cnt_get(prot->sec_keys); eapol_pdu.msg.key.key_information.key_ack = true; eapol_pdu.msg.key.key_information.key_mic = true; @@ -258,7 +261,7 @@ static int8_t auth_gkh_sec_prot_message_send(sec_prot_t *prot, gkh_sec_prot_msg_ static void auth_gkh_sec_prot_timer_timeout(sec_prot_t *prot, uint16_t ticks) { gkh_sec_prot_int_t *data = gkh_sec_prot_get(prot); - sec_prot_timer_timeout_handle(prot, &data->common, &prot->cfg->sec_prot_trickle_params, ticks); + sec_prot_timer_timeout_handle(prot, &data->common, &prot->prot_cfg->sec_prot_trickle_params, ticks); } static void auth_gkh_sec_prot_state_machine(sec_prot_t *prot) @@ -283,16 +286,16 @@ static void auth_gkh_sec_prot_state_machine(sec_prot_t *prot) // KMP-CREATE.confirm prot->create_conf(prot, SEC_RESULT_OK); - // Sends 4WH Message 1 + // Sends GKH Message 1 auth_gkh_sec_prot_message_send(prot, GKH_MESSAGE_1); // Start trickle timer to re-send if no response - sec_prot_timer_trickle_start(&data->common, &prot->cfg->sec_prot_trickle_params); + sec_prot_timer_trickle_start(&data->common, &prot->prot_cfg->sec_prot_trickle_params); sec_prot_state_set(prot, &data->common, GKH_STATE_MESSAGE_2); // Store the hash for to-be installed GTK as used for the PTK - sec_prot_keys_ptk_installed_gtk_hash_set(prot->sec_keys); + sec_prot_keys_ptk_installed_gtk_hash_set(prot->sec_keys, false); break; // Wait GKH message 2 diff --git a/source/Security/protocols/key_sec_prot/key_sec_prot.c b/source/Security/protocols/key_sec_prot/key_sec_prot.c index daa07af371f..ad75cf5853e 100644 --- a/source/Security/protocols/key_sec_prot/key_sec_prot.c +++ b/source/Security/protocols/key_sec_prot/key_sec_prot.c @@ -268,6 +268,7 @@ static int8_t key_sec_prot_receive(sec_prot_t *prot, void *pdu, uint16_t size) // Checks if supplicant indicates that it has valid PMK uint8_t remote_keyid[KEYID_LEN]; if (kde_pmkid_read(kde, kde_len, remote_keyid) >= 0) { + tr_debug("recv PMKID: %s", trace_array(remote_keyid, 16)); uint8_t pmkid[PMKID_LEN]; if (sec_prot_lib_pmkid_generate(prot, pmkid, true) >= 0) { if (memcmp(remote_keyid, pmkid, PMKID_LEN) == 0) { @@ -278,6 +279,7 @@ static int8_t key_sec_prot_receive(sec_prot_t *prot, void *pdu, uint16_t size) // Checks if supplicant indicates that it has valid PTK if (kde_ptkid_read(kde, kde_len, remote_keyid) >= 0) { + tr_debug("recv PTKID: %s", trace_array(remote_keyid, 16)); uint8_t ptkid[PTKID_LEN]; if (sec_prot_lib_ptkid_generate(prot, ptkid, true) >= 0) { if (memcmp(remote_keyid, ptkid, PTKID_LEN) == 0) { diff --git a/source/Security/protocols/sec_prot.h b/source/Security/protocols/sec_prot.h index 556d769f6bb..c6ebae78a95 100644 --- a/source/Security/protocols/sec_prot.h +++ b/source/Security/protocols/sec_prot.h @@ -268,7 +268,8 @@ struct sec_prot_s { sec_prot_receive_disable *receive_disable; /**< Disable receiving of messages */ sec_prot_keys_t *sec_keys; /**< Security keys storage pointer */ - sec_prot_cfg_t *cfg; /**< Configuration pointer */ + sec_prot_cfg_t *prot_cfg; /**< Security protocol configuration pointer */ + sec_timer_cfg_t *timer_cfg; /**< Security timer configuration pointer */ uint8_t header_size; /**< Header size */ sec_prot_int_data_t *data; /**< Protocol internal data */ }; diff --git a/source/Security/protocols/sec_prot_certs.h b/source/Security/protocols/sec_prot_certs.h index e9a25ece847..9a204aaa099 100644 --- a/source/Security/protocols/sec_prot_certs.h +++ b/source/Security/protocols/sec_prot_certs.h @@ -54,7 +54,7 @@ typedef struct { typedef NS_LIST_HEAD(cert_chain_entry_t, link) cert_chain_list_t; typedef NS_LIST_HEAD(cert_revocat_list_entry_t, link) cert_revocat_lists_t; -typedef struct { +typedef struct sec_prot_certs_s { cert_chain_entry_t own_cert_chain; /**< Own certificate chain */ cert_chain_list_t trusted_cert_chain_list; /**< Trusted certificate chain lists */ cert_revocat_lists_t cert_revocat_lists; /**< Certificate Revocation Lists */ diff --git a/source/Security/protocols/sec_prot_cfg.h b/source/Security/protocols/sec_prot_cfg.h index fa2a88dafb9..f0a118b7c1d 100644 --- a/source/Security/protocols/sec_prot_cfg.h +++ b/source/Security/protocols/sec_prot_cfg.h @@ -24,6 +24,23 @@ typedef struct sec_prot_cfg_s { trickle_params_t sec_prot_trickle_params; uint16_t sec_prot_retry_timeout; uint16_t sec_max_ongoing_authentication; + uint16_t initial_key_retry_delay; + trickle_params_t initial_key_trickle_params; + uint8_t initial_key_retry_cnt; } sec_prot_cfg_t; +/* Security timer configuration settings */ + +typedef struct sec_timer_cfg_s { + uint32_t gtk_expire_offset; /* GTK lifetime; GTK_EXPIRE_OFFSET (seconds) */ + uint32_t pmk_lifetime; /* PMK lifetime (seconds) */ + uint32_t ptk_lifetime; /* PTK lifetime (seconds) */ + uint16_t gtk_new_act_time; /* GTK_NEW_ACTIVATION_TIME (1/X of expire offset) */ + uint16_t revocat_lifetime_reduct; /* REVOCATION_LIFETIME_REDUCTION (reduction of lifetime) */ + uint16_t gtk_request_imin; /* GTK_REQUEST_IMIN (seconds) */ + uint16_t gtk_request_imax; /* GTK_REQUEST_IMAX (seconds) */ + uint16_t gtk_max_mismatch; /* GTK_MAX_MISMATCH (seconds) */ + uint8_t gtk_new_install_req; /* GTK_NEW_INSTALL_REQUIRED (percent of GTK lifetime) */ +} sec_timer_cfg_t; + #endif /* SEC_PROT_CONF_H_ */ diff --git a/source/Security/protocols/sec_prot_keys.c b/source/Security/protocols/sec_prot_keys.c index c420a5823f0..d7071e93237 100644 --- a/source/Security/protocols/sec_prot_keys.c +++ b/source/Security/protocols/sec_prot_keys.c @@ -56,8 +56,8 @@ sec_prot_keys_t *sec_prot_keys_create(sec_prot_gtk_keys_t *gtks, const sec_prot_ void sec_prot_keys_init(sec_prot_keys_t *sec_keys, sec_prot_gtk_keys_t *gtks, const sec_prot_certs_t *certs) { memset(sec_keys, 0, sizeof(sec_prot_keys_t)); - sec_keys->pmk_lifetime = PMK_LIFETIME_INSTALL; - sec_keys->ptk_lifetime = PTK_LIFETIME_INSTALL; + sec_keys->pmk_lifetime = 0; + sec_keys->ptk_lifetime = 0; sec_keys->pmk_key_replay_cnt = 0; sec_keys->gtks = gtks; sec_keys->certs = certs; @@ -101,12 +101,12 @@ void sec_prot_keys_gtks_delete(sec_prot_gtk_keys_t *gtks) ns_dyn_mem_free(gtks); } -void sec_prot_keys_pmk_write(sec_prot_keys_t *sec_keys, uint8_t *pmk) +void sec_prot_keys_pmk_write(sec_prot_keys_t *sec_keys, uint8_t *pmk, uint32_t pmk_lifetime) { memcpy(sec_keys->pmk, pmk, PMK_LEN); sec_keys->pmk_key_replay_cnt = 0; sec_keys->pmk_key_replay_cnt_set = false; - sec_keys->pmk_lifetime = PMK_LIFETIME_INSTALL; + sec_keys->pmk_lifetime = pmk_lifetime; sec_keys->pmk_set = true; sec_keys->updated = true; } @@ -116,7 +116,7 @@ void sec_prot_keys_pmk_delete(sec_prot_keys_t *sec_keys) memset(sec_keys->pmk, 0, PMK_LEN); sec_keys->pmk_key_replay_cnt = 0; sec_keys->pmk_key_replay_cnt_set = false; - sec_keys->pmk_lifetime = PMK_LIFETIME_INSTALL; + sec_keys->pmk_lifetime = 0; sec_keys->pmk_set = false; sec_keys->updated = true; } @@ -130,6 +130,15 @@ uint8_t *sec_prot_keys_pmk_get(sec_prot_keys_t *sec_keys) return sec_keys->pmk; } +uint32_t sec_prot_keys_pmk_lifetime_get(sec_prot_keys_t *sec_keys) +{ + if (!sec_keys->pmk_set) { + return 0; + } + + return sec_keys->pmk_lifetime; +} + uint64_t sec_prot_keys_pmk_replay_cnt_get(sec_prot_keys_t *sec_keys) { return sec_keys->pmk_key_replay_cnt; @@ -140,15 +149,20 @@ void sec_prot_keys_pmk_replay_cnt_set(sec_prot_keys_t *sec_keys, uint64_t counte sec_keys->pmk_key_replay_cnt_set = true; sec_keys->pmk_key_replay_cnt = counter; } - -void sec_prot_keys_pmk_replay_cnt_increment(sec_prot_keys_t *sec_keys) +bool sec_prot_keys_pmk_replay_cnt_increment(sec_prot_keys_t *sec_keys) { // Start from zero i.e. does not increment on first call if (!sec_keys->pmk_key_replay_cnt_set) { sec_keys->pmk_key_replay_cnt_set = true; - return; + return true; + } + // If counter is near to exhaust return error (ignores MSB 32bits which are re-start counter) + if ((sec_keys->pmk_key_replay_cnt & PMK_KEY_REPLAY_CNT_LIMIT_MASK) > PMK_KEY_REPLAY_CNT_LIMIT) { + sec_keys->pmk_key_replay_cnt |= 0xFFFF; // Invalidate counter; will result removal of keys + return false; } sec_keys->pmk_key_replay_cnt++; + return true; } bool sec_prot_keys_pmk_replay_cnt_compare(uint64_t received_counter, sec_prot_keys_t *sec_keys) @@ -179,16 +193,12 @@ bool sec_prot_keys_pmk_mismatch_is_set(sec_prot_keys_t *sec_keys) return sec_keys->pmk_mismatch; } -bool sec_prot_keys_pmk_lifetime_decrement(sec_prot_keys_t *sec_keys, uint32_t default_lifetime, uint8_t seconds) +bool sec_prot_keys_pmk_lifetime_decrement(sec_prot_keys_t *sec_keys, uint8_t seconds) { if (!sec_keys->pmk_set) { return false; } - if (sec_keys->pmk_lifetime == PMK_LIFETIME_INSTALL) { - sec_keys->pmk_lifetime = default_lifetime; - } - if (sec_keys->pmk_lifetime > seconds) { sec_keys->pmk_lifetime -= seconds; } else { @@ -202,10 +212,10 @@ bool sec_prot_keys_pmk_lifetime_decrement(sec_prot_keys_t *sec_keys, uint32_t de return false; } -void sec_prot_keys_ptk_write(sec_prot_keys_t *sec_keys, uint8_t *ptk) +void sec_prot_keys_ptk_write(sec_prot_keys_t *sec_keys, uint8_t *ptk, uint32_t ptk_lifetime) { memcpy(sec_keys->ptk, ptk, PTK_LEN); - sec_keys->ptk_lifetime = PTK_LIFETIME_INSTALL; + sec_keys->ptk_lifetime = ptk_lifetime; sec_keys->ptk_set = true; sec_keys->updated = true; } @@ -213,7 +223,7 @@ void sec_prot_keys_ptk_write(sec_prot_keys_t *sec_keys, uint8_t *ptk) void sec_prot_keys_ptk_delete(sec_prot_keys_t *sec_keys) { memset(sec_keys->ptk, 0, PTK_LEN); - sec_keys->ptk_lifetime = PTK_LIFETIME_INSTALL; + sec_keys->ptk_lifetime = 0; sec_keys->ptk_set = false; sec_keys->updated = true; } @@ -227,6 +237,15 @@ uint8_t *sec_prot_keys_ptk_get(sec_prot_keys_t *sec_keys) return sec_keys->ptk; } +uint32_t sec_prot_keys_ptk_lifetime_get(sec_prot_keys_t *sec_keys) +{ + if (!sec_keys->ptk_set) { + return 0; + } + + return sec_keys->ptk_lifetime; +} + void sec_prot_keys_ptk_mismatch_set(sec_prot_keys_t *sec_keys) { sec_keys->ptk_mismatch = true; @@ -265,16 +284,12 @@ void sec_prot_keys_ptk_eui_64_delete(sec_prot_keys_t *sec_keys) sec_keys->updated = true; } -bool sec_prot_keys_ptk_lifetime_decrement(sec_prot_keys_t *sec_keys, uint32_t default_lifetime, uint8_t seconds) +bool sec_prot_keys_ptk_lifetime_decrement(sec_prot_keys_t *sec_keys, uint8_t seconds) { if (!sec_keys->ptk_set) { return false; } - if (sec_keys->ptk_lifetime == PTK_LIFETIME_INSTALL) { - sec_keys->ptk_lifetime = default_lifetime; - } - if (sec_keys->ptk_lifetime > seconds) { sec_keys->ptk_lifetime -= seconds; } else { @@ -380,8 +395,11 @@ int8_t sec_prot_keys_gtk_insert_index_from_gtkl_get(sec_prot_keys_t *sec_keys) // Checks all keys for (uint8_t i = 0; i < GTK_NUM; i++) { - if (sec_prot_keys_gtk_status_is_live(sec_keys->gtks, i)) { - // If key is live, but not indicated on GTKL inserts it + if (sec_prot_keys_gtk_status_is_live(sec_keys->gtks, i) || + sec_prot_keys_gtk_status_get(sec_keys->gtks, i) == GTK_STATUS_OLD) { + /* If key is live, but not indicated on GTKL inserts it. Also old keys indicated + still on GTK hash are inserted, since supplicants do not know the status of the + key and might need the key for receive (only) from not updated neighbors */ if (!sec_prot_keys_gtkl_gtk_is_live(sec_keys, i)) { sec_prot_keys_gtk_insert_index_set(sec_keys, i); return i; @@ -438,6 +456,8 @@ int8_t sec_prot_keys_gtk_clear(sec_prot_gtk_keys_t *gtks, uint8_t index) gtks->gtk[index].status = GTK_STATUS_NEW; memset(gtks->gtk[index].key, 0, GTK_LEN); + gtks->updated = true; + sec_prot_keys_gtk_install_order_update(gtks); return 0; @@ -470,7 +490,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, uint16_t seconds) +uint32_t sec_prot_keys_gtk_lifetime_decrement(sec_prot_gtk_keys_t *gtks, uint8_t index, uint64_t current_time, uint16_t seconds) { if (gtks->gtk[index].lifetime > seconds) { gtks->gtk[index].lifetime -= seconds; @@ -478,9 +498,44 @@ uint32_t sec_prot_keys_gtk_lifetime_decrement(sec_prot_gtk_keys_t *gtks, uint8_t gtks->gtk[index].lifetime = 0; } + // Calculates expiration timestamp for GTK from current time and lifetime + uint64_t expirytime = current_time + gtks->gtk[index].lifetime; + uint64_t diff; + // Compares calculated timestamp to stored one + if (gtks->gtk[index].expirytime >= expirytime) { + diff = gtks->gtk[index].expirytime - expirytime; + } else { + diff = expirytime - gtks->gtk[index].expirytime; + } + // If timestamps differ for more than 5 minutes marks field as updated (and stores to NVM) + if (diff > 300) { + gtks->updated = true; + } + return gtks->gtk[index].lifetime; } +uint64_t sec_prot_keys_gtk_exptime_from_lifetime_get(sec_prot_gtk_keys_t *gtks, uint8_t index, uint64_t current_time) +{ + if (index >= GTK_NUM || !gtks->gtk[index].set) { + return 0; + } + + uint32_t lifetime = gtks->gtk[index].lifetime; + return current_time + lifetime; +} + +int8_t sec_prot_keys_gtk_expirytime_set(sec_prot_gtk_keys_t *gtks, uint8_t index, uint64_t expirytime) +{ + if (index >= GTK_NUM || !gtks->gtk[index].set) { + return -1; + } + + gtks->gtk[index].expirytime = expirytime; + + return 0; +} + bool sec_prot_keys_gtks_are_updated(sec_prot_gtk_keys_t *gtks) { return gtks->updated; @@ -505,6 +560,7 @@ void sec_prot_keys_gtk_status_fresh_set(sec_prot_gtk_keys_t *gtks, uint8_t index // Active key remains as active, old keys are never reused if (gtks->gtk[index].status < GTK_STATUS_FRESH) { gtks->gtk[index].status = GTK_STATUS_FRESH; + gtks->updated = true; } } @@ -528,9 +584,11 @@ int8_t sec_prot_keys_gtk_status_active_set(sec_prot_gtk_keys_t *gtks, uint8_t in // Sets previously active key old if (gtks->gtk[i].status == GTK_STATUS_ACTIVE) { gtks->gtk[i].status = GTK_STATUS_OLD; + gtks->updated = true; } } gtks->gtk[index].status = GTK_STATUS_ACTIVE; + gtks->updated = true; return 0; } @@ -548,6 +606,16 @@ int8_t sec_prot_keys_gtk_status_active_get(sec_prot_gtk_keys_t *gtks) return -1; } +int8_t sec_prot_keys_gtk_status_active_to_fresh_set(sec_prot_gtk_keys_t *gtks) +{ + int8_t index = sec_prot_keys_gtk_status_active_get(gtks); + if (index < 0) { + return -1; + } + + return sec_prot_keys_gtk_status_set(gtks, index, GTK_STATUS_FRESH); +} + bool sec_prot_keys_gtk_status_is_live(sec_prot_gtk_keys_t *gtks, uint8_t index) { if (index >= GTK_NUM || !gtks->gtk[index].set) { @@ -567,9 +635,36 @@ void sec_prot_keys_gtk_status_new_set(sec_prot_gtk_keys_t *gtks, uint8_t index) return; } + if (gtks->gtk[index].status != GTK_STATUS_NEW) { + gtks->updated = true; + } + gtks->gtk[index].status = GTK_STATUS_NEW; } +uint8_t sec_prot_keys_gtk_status_get(sec_prot_gtk_keys_t *gtks, uint8_t index) +{ + if (index >= GTK_NUM || !gtks->gtk[index].set) { + return 0; + } + + return gtks->gtk[index].status; +} + +int8_t sec_prot_keys_gtk_status_set(sec_prot_gtk_keys_t *gtks, uint8_t index, uint8_t status) +{ + if (index >= GTK_NUM || !gtks->gtk[index].set) { + return -1; + } + + if (gtks->gtk[index].status != status) { + gtks->updated = true; + } + + gtks->gtk[index].status = status; + return 0; +} + void sec_prot_keys_gtks_hash_generate(sec_prot_gtk_keys_t *gtks, uint8_t *gtkhash) { memset(gtkhash, 0, GTK_ALL_HASHES_LEN); @@ -758,6 +853,9 @@ void sec_prot_keys_gtk_install_order_update(sec_prot_gtk_keys_t *gtks) uint8_t new_install_order = 0; for (uint8_t i = 0; i < GTK_NUM; i++) { if (ordered_indexes[i] >= 0) { + if (gtks->gtk[ordered_indexes[i]].install_order != new_install_order) { + gtks->updated = true; + } gtks->gtk[ordered_indexes[i]].install_order = new_install_order++; } } @@ -786,6 +884,29 @@ int8_t sec_prot_keys_gtk_install_index_get(sec_prot_gtk_keys_t *gtks) return install_index; } +uint8_t sec_prot_keys_gtk_install_order_get(sec_prot_gtk_keys_t *gtks, uint8_t index) +{ + if (index >= GTK_NUM || !gtks->gtk[index].set) { + return 0; + } + + return gtks->gtk[index].install_order; +} + +int8_t sec_prot_keys_gtk_install_order_set(sec_prot_gtk_keys_t *gtks, uint8_t index, uint8_t install_order) +{ + if (index >= GTK_NUM || !gtks->gtk[index].set) { + return -1; + } + if (gtks->gtk[index].install_order != install_order) { + gtks->updated = true; + } + + gtks->gtk[index].install_order = install_order; + return 0; +} + + uint8_t sec_prot_keys_gtk_count(sec_prot_gtk_keys_t *gtks) { uint8_t count = 0; @@ -802,12 +923,13 @@ uint8_t sec_prot_keys_gtk_count(sec_prot_gtk_keys_t *gtks) void sec_prot_keys_ptk_installed_gtk_hash_clear_all(sec_prot_keys_t *sec_keys) { for (uint8_t index = 0; index < GTK_NUM; index++) { - memset(sec_keys->ins_gtk_hash[sec_keys->gtk_set_index].hash, 0, INS_GTK_HASH_LEN); + memset(sec_keys->ins_gtk_hash[index].hash, 0, INS_GTK_HASH_LEN); } sec_keys->ins_gtk_hash_set = 0; + sec_keys->ins_gtk_4wh_hash_set = 0; } -void sec_prot_keys_ptk_installed_gtk_hash_set(sec_prot_keys_t *sec_keys) +void sec_prot_keys_ptk_installed_gtk_hash_set(sec_prot_keys_t *sec_keys, bool is_4wh) { if (sec_keys->gtk_set_index >= 0) { uint8_t *gtk = sec_prot_keys_gtk_get(sec_keys->gtks, sec_keys->gtk_set_index); @@ -824,12 +946,22 @@ void sec_prot_keys_ptk_installed_gtk_hash_set(sec_prot_keys_t *sec_keys) */ memcpy(sec_keys->ins_gtk_hash[sec_keys->gtk_set_index].hash, gtk_hash, INS_GTK_HASH_LEN); sec_keys->ins_gtk_hash_set |= (1 << sec_keys->gtk_set_index); + /* If used on 4WH will store the hash in case GKH is initiated later for the + * same index as 4WH (likely to happen if just GTK update is made). This allows + * that NVM storage does not need to be updated since hash is already stored. */ + if (is_4wh) { + sec_keys->ins_gtk_4wh_hash_set |= (1 << sec_keys->gtk_set_index); + } else { + sec_keys->ins_gtk_4wh_hash_set &= ~(1 << sec_keys->gtk_set_index); + } } } bool sec_prot_keys_ptk_installed_gtk_hash_mismatch_check(sec_prot_keys_t *sec_keys, uint8_t gtk_index) { - if ((sec_keys->ins_gtk_hash_set & (1 << sec_keys->gtk_set_index)) == 0) { + // If not set or the key has been inserted by 4WH then there is no mismatch + if ((sec_keys->ins_gtk_hash_set & (1 << sec_keys->gtk_set_index)) == 0 || + (sec_keys->ins_gtk_hash_set & (1 << sec_keys->gtk_set_index)) == 1) { return false; } diff --git a/source/Security/protocols/sec_prot_keys.h b/source/Security/protocols/sec_prot_keys.h index 9df422934b9..06302519d27 100644 --- a/source/Security/protocols/sec_prot_keys.h +++ b/source/Security/protocols/sec_prot_keys.h @@ -41,7 +41,7 @@ #define PTKID_LEN 16 #define KEYID_LEN 16 -#define GTK_DEFAULT_LIFETIME 60 * 60 * 24 * 30 // 30 days +#define GTK_DEFAULT_LIFETIME (60 * 60 * 24 * 30) // 30 days #define GTK_EXPIRE_MISMATCH_TIME 60 // Supplicant GTK expire time mismatch occurs if GTK expires before this time #define GTK_STATUS_NEW 0 // New GTK, can transition to fresh @@ -56,18 +56,22 @@ #define GTK_ALL_HASHES_LEN GTK_HASH_LEN * GTK_NUM #define INS_GTK_HASH_LEN 2 -#define PMK_LIFETIME_INSTALL 0xFFFFF -#define PTK_LIFETIME_INSTALL 0xFFFFF +// Limit is 60000 (of 65536) +#define PMK_KEY_REPLAY_CNT_LIMIT 60000 // Upper limit for PMK replay counter +#define PMK_KEY_REPLAY_CNT_LIMIT_MASK 0xFFFF // Upper limit mask + +#define SEC_MAXIMUM_LIFETIME (60 * 60 * 24 * 30 * 24) // Maximum life time for PMK, PTK, GTKs etc. is two years typedef struct { uint8_t key[GTK_LEN]; /**< Group Transient Key (128 bits) */ + uint64_t expirytime; /**< GTK expiry time on storage */ uint32_t lifetime; /**< GTK lifetime in seconds */ unsigned status : 2; /**< Group Transient Key status */ unsigned install_order : 2; /**< Order in which GTK keys are added */ bool set: 1; /**< Group Transient Key set (valid value) */ } gtk_key_t; -typedef struct { +typedef struct sec_prot_gtk_keys_s { gtk_key_t gtk[GTK_NUM]; /**< 4 Group Transient Keys */ bool updated: 1; /**< Group Transient Keys has been updated */ } sec_prot_gtk_keys_t; @@ -90,6 +94,7 @@ typedef struct { uint8_t gtkl; /**< Remote GTKL information */ int8_t gtk_set_index; /**< Index of GTK to set */ unsigned ins_gtk_hash_set: 4; /**< Hash for inserted GTKs for a PTK set */ + unsigned ins_gtk_4wh_hash_set: 4; /**< Hash for inserted GTKs for a PTK set for a 4WH */ bool pmk_set: 1; /**< Pairwise Master Key set */ bool ptk_set: 1; /**< Pairwise Transient Key set */ bool pmk_key_replay_cnt_set: 1; /**< Pairwise Master Key replay counter set */ @@ -111,6 +116,35 @@ typedef struct { frame_counter_t counter[GTK_NUM]; /**< Frame counter for each GTK key */ } frame_counters_t; +// Authenticator supplicant security key data +typedef struct { + uint8_t pmk[PMK_LEN]; /**< Pairwise Master Key (256 bits) */ + uint8_t ptk[PTK_LEN]; /**< Pairwise Transient Key (384 bits) */ + uint8_t ptk_eui_64[8]; /**< Remote EUI-64 used to derive PTK or NULL */ + sec_prot_gtk_hash_t ins_gtk_hash[GTK_NUM]; /**< Hashes for inserted GTKs for a PTK */ + uint16_t pmk_key_replay_cnt; /**< Pairwise Master Key replay counter */ + uint16_t pmk_lifetime; /**< PMK lifetime (short time format) */ + uint16_t ptk_lifetime; /**< PTK lifetime (short time format) */ + unsigned ins_gtk_hash_set: 4; /**< Hash for inserted GTKs for a PTK set */ + unsigned ins_gtk_4wh_hash_set: 4; /**< Hash for inserted GTKs for a PTK set for a 4WH */ + bool pmk_set: 1; /**< Pairwise Master Key set */ + bool ptk_set: 1; /**< Pairwise Transient Key set */ + bool pmk_lifetime_set: 1; /**< PMK lifetime (short time format) */ + bool ptk_lifetime_set: 1; /**< PTK lifetime (short time format) */ + bool pmk_key_replay_cnt_set: 1; /**< Pairwise Master Key replay counter set */ + bool ptk_eui_64_set: 1; /**< Remote EUI-64 used to derive PTK is set */ + bool eui_64_set: 1; /**< Remote EUI-64 is set */ +} sec_prot_keys_storage_t; + +// Security keys (GTKs) and needed network information +typedef struct { + char network_name[33]; /**< Network name for keys */ + sec_prot_gtk_keys_t *gtks; /**< Link to GTKs */ + uint16_t new_pan_id; /**< new PAN ID indicated by bootstrap */ + uint16_t key_pan_id; /**< PAN ID for keys */ + bool updated : 1; /**< Network info has been updated */ +} sec_prot_keys_nw_info_t; + /* * GTK mismatch types, list is ordered according to priority of mismatch i.e. if there * are both hash and lifetime mismatch, hash has greater priority @@ -178,9 +212,10 @@ void sec_prot_keys_gtks_delete(sec_prot_gtk_keys_t *gtks); * * \param sec_keys security keys * \param pmk Pairwise Master Key + * \param pmk_lifetime PMK lifetime * */ -void sec_prot_keys_pmk_write(sec_prot_keys_t *sec_keys, uint8_t *pmk); +void sec_prot_keys_pmk_write(sec_prot_keys_t *sec_keys, uint8_t *pmk, uint32_t pmk_lifetime); /** * sec_prot_keys_pmk_delete deletes PMK @@ -200,6 +235,16 @@ void sec_prot_keys_pmk_delete(sec_prot_keys_t *sec_keys); */ uint8_t *sec_prot_keys_pmk_get(sec_prot_keys_t *sec_keys); +/** + * sec_prot_keys_pmk_lifetime_get Pairwise Master Key lifetime + * + * \param sec_keys security keys + * + * \return PMK lifetime + * + */ +uint32_t sec_prot_keys_pmk_lifetime_get(sec_prot_keys_t *sec_keys); + /** * sec_prot_keys_pmk_replay_cnt_get gets PMK replay counter value * @@ -224,8 +269,11 @@ void sec_prot_keys_pmk_replay_cnt_set(sec_prot_keys_t *sec_keys, uint64_t counte * * \param sec_keys security keys * + * \return TRUE counter was incremented + * \return FALSE counter increment failed + * */ -void sec_prot_keys_pmk_replay_cnt_increment(sec_prot_keys_t *sec_keys); +bool sec_prot_keys_pmk_replay_cnt_increment(sec_prot_keys_t *sec_keys); /** * sec_prot_keys_pmk_replay_cnt_compare compares received replay counter value to PMK replay counter @@ -269,23 +317,23 @@ bool sec_prot_keys_pmk_mismatch_is_set(sec_prot_keys_t *sec_keys); * sec_prot_keys_pmk_lifetime_decrement decrements PMK lifetime * * \param sec_keys security keys - * \param default_lifetime default lifetime for PMK * \param seconds elapsed seconds * * \return true PMK expired and deleted both PMK and PTK * \return false PMK not expired * */ -bool sec_prot_keys_pmk_lifetime_decrement(sec_prot_keys_t *sec_keys, uint32_t default_lifetime, uint8_t seconds); +bool sec_prot_keys_pmk_lifetime_decrement(sec_prot_keys_t *sec_keys, uint8_t seconds); /** * sec_prot_keys_ptk_write writes Pairwise Transient Key * * \param sec_keys security keys * \param ptk Pairwise Transient Key + * \param ptk_lifetime PTK lifetime * */ -void sec_prot_keys_ptk_write(sec_prot_keys_t *sec_keys, uint8_t *ptk); +void sec_prot_keys_ptk_write(sec_prot_keys_t *sec_keys, uint8_t *ptk, uint32_t ptk_lifetime); /** * sec_prot_keys_ptk_delete deletes PTK @@ -305,6 +353,16 @@ void sec_prot_keys_ptk_delete(sec_prot_keys_t *sec_keys); */ uint8_t *sec_prot_keys_ptk_get(sec_prot_keys_t *sec_keys); +/** + * sec_prot_keys_ptk_lifetime_get gets Pairwise Transient Key lifetime + * + * \param sec_keys security keys + * + * \return PTK lifetime + * + */ +uint32_t sec_prot_keys_ptk_lifetime_get(sec_prot_keys_t *sec_keys); + /** * sec_prot_keys_ptk_mismatch_set set PTK mismatch * @@ -362,14 +420,13 @@ void sec_prot_keys_ptk_eui_64_delete(sec_prot_keys_t *sec_keys); * sec_prot_keys_ptk_lifetime_decrement decrements PTK lifetime * * \param sec_keys security keys - * \param default_lifetime default lifetime for PTK * \param seconds elapsed seconds * * \return true PTK expired and deleted * \return false PTK not expired * */ -bool sec_prot_keys_ptk_lifetime_decrement(sec_prot_keys_t *sec_keys, uint32_t default_lifetime, uint8_t seconds); +bool sec_prot_keys_ptk_lifetime_decrement(sec_prot_keys_t *sec_keys, uint8_t seconds); /** * sec_prot_keys_are_updated returns security keys have been updated flag @@ -556,12 +613,38 @@ uint32_t sec_prot_keys_gtk_lifetime_get(sec_prot_gtk_keys_t *gtks, uint8_t index * * \param gtks GTK keys * \param index index for GTK + * \param current_time current timestamp * \param seconds elapsed seconds * * \return new GTK lifetime * */ -uint32_t sec_prot_keys_gtk_lifetime_decrement(sec_prot_gtk_keys_t *gtks, uint8_t index, uint16_t seconds); +uint32_t sec_prot_keys_gtk_lifetime_decrement(sec_prot_gtk_keys_t *gtks, uint8_t index, uint64_t current_time, uint16_t seconds); + +/** + * sec_prot_keys_gtk_exptime_from_lifetime_get converts GTK lifetime to expiry time. + * + * \param gtks GTK keys + * \param index index for GTK + * \param current_time current time + * + * \return expiry time + * + */ +uint64_t sec_prot_keys_gtk_exptime_from_lifetime_get(sec_prot_gtk_keys_t *gtks, uint8_t index, uint64_t current_time); + +/** + * sec_prot_keys_gtk_expirytime_set sets GTK expiry time + * + * \param gtks GTK keys + * \param index index for GTK + * \param expirytime expiry time + * + * \return < 0 failure + * \return >= 0 success + * + */ +int8_t sec_prot_keys_gtk_expirytime_set(sec_prot_gtk_keys_t *gtks, uint8_t index, uint64_t expirytime); /** * sec_prot_keys_gtks_are_updated returns GTKs have been updated flag @@ -631,6 +714,17 @@ int8_t sec_prot_keys_gtk_status_active_set(sec_prot_gtk_keys_t *gtks, uint8_t in */ int8_t sec_prot_keys_gtk_status_active_get(sec_prot_gtk_keys_t *gtks); +/** + * sec_prot_keys_gtk_status_active_to_fresh_set sets active GTK to fresh GTK + * + * \param gtks GTK keys + * + * \return < 0 failure + * \return >= 0 success + * + */ +int8_t sec_prot_keys_gtk_status_active_to_fresh_set(sec_prot_gtk_keys_t *gtks); + /** * sec_prot_keys_gtk_status_is_live checks whether GTK is active * @@ -642,6 +736,30 @@ int8_t sec_prot_keys_gtk_status_active_get(sec_prot_gtk_keys_t *gtks); */ bool sec_prot_keys_gtk_status_is_live(sec_prot_gtk_keys_t *gtks, uint8_t index); +/** + * sec_prot_keys_gtk_status_get gets GTK status + * + * \param gtks GTK keys + * \param index index + * + * \return GTK status + * + */ +uint8_t sec_prot_keys_gtk_status_get(sec_prot_gtk_keys_t *gtks, uint8_t index); + +/** + * sec_prot_keys_gtk_status_get sets GTK status + * + * \param gtks GTK keys + * \param index index + * \param status status + * + * \return < 0 failure + * \return >= 0 success + * + */ +int8_t sec_prot_keys_gtk_status_set(sec_prot_gtk_keys_t *gtks, uint8_t index, uint8_t status); + /** * sec_prot_keys_gtks_hash_generate generate GTK hash based on all GTKs * @@ -761,6 +879,30 @@ void sec_prot_keys_gtk_install_order_update(sec_prot_gtk_keys_t *gtks); */ int8_t sec_prot_keys_gtk_install_index_get(sec_prot_gtk_keys_t *gtks); +/** + * sec_prot_keys_gtk_install_order_get gets GTK install order + * + * \param gtks GTK keys + * \param index index + * + * \return GTK install order + * + */ +uint8_t sec_prot_keys_gtk_install_order_get(sec_prot_gtk_keys_t *gtks, uint8_t gtk_index); + +/** + * sec_prot_keys_gtk_install_order_set sets GTK install order + * + * \param gtks GTK keys + * \param index index + * \param install_order GTK install order + * + * \return < 0 failure + * \return >= 0 success + * + */ +int8_t sec_prot_keys_gtk_install_order_set(sec_prot_gtk_keys_t *gtks, uint8_t gtk_index, uint8_t install_order); + /** * sec_prot_keys_gtk_count counts GTK keys * @@ -784,9 +926,10 @@ void sec_prot_keys_ptk_installed_gtk_hash_clear_all(sec_prot_keys_t *sec_keys); * to supplicant using the current PTK * * \param sec_keys security keys + * \param is_4wh set by 4WH * */ -void sec_prot_keys_ptk_installed_gtk_hash_set(sec_prot_keys_t *sec_keys); +void sec_prot_keys_ptk_installed_gtk_hash_set(sec_prot_keys_t *sec_keys, bool is_4wh); /** * sec_prot_keys_ptk_installed_gtk_hash_set check if PTK is being used to store new GTK for the index diff --git a/source/Security/protocols/sec_prot_lib.c b/source/Security/protocols/sec_prot_lib.c index 0987054d6bc..1df7d5dac33 100644 --- a/source/Security/protocols/sec_prot_lib.c +++ b/source/Security/protocols/sec_prot_lib.c @@ -274,6 +274,12 @@ int8_t sec_prot_lib_ptk_calc(const uint8_t *pmk, const uint8_t *eui64_1, const u memcpy(ptk, result, PTK_LEN); +#ifdef EXTRA_DEBUG_INFO + tr_debug("PTK EUI: %s %s", trace_array(eui64_1, 8), trace_array(eui64_2, 8)); + tr_debug("PTK NONCE: %s %s", trace_array(nonce1, 32), trace_array(nonce2, 32)); + tr_debug("PTK: %s:%s", trace_array(ptk, PTK_LEN / 2), trace_array(ptk + PTK_LEN / 2, PTK_LEN / 2)); +#endif + return 0; } @@ -469,7 +475,7 @@ int8_t sec_prot_lib_ptkid_generate(sec_prot_t *prot, uint8_t *ptkid, bool is_aut { uint8_t local_eui64[8]; prot->addr_get(prot, local_eui64, NULL); - uint8_t *ptk = sec_prot_keys_pmk_get(prot->sec_keys); + uint8_t *ptk = sec_prot_keys_ptk_get(prot->sec_keys); if (!ptk) { return -1; } @@ -524,7 +530,10 @@ uint8_t *sec_prot_remote_eui_64_addr_get(sec_prot_t *prot) if (prot->sec_keys && prot->sec_keys->ptk_eui_64_set) { return prot->sec_keys->ptk_eui_64; } else { - return NULL; + static uint8_t remote_eui64[8]; + memset(remote_eui64, 0, 8); + prot->addr_get(prot, NULL, (uint8_t *) &remote_eui64); + return remote_eui64; } } 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 ad07fd1ca17..d4b8c549ae8 100644 --- a/source/Security/protocols/tls_sec_prot/tls_sec_prot.c +++ b/source/Security/protocols/tls_sec_prot/tls_sec_prot.c @@ -69,15 +69,20 @@ typedef struct { bool timer_running : 1; /**< TLS timer running */ bool finished : 1; /**< TLS finished */ bool calculating : 1; /**< TLS is calculating */ +#ifdef SERVER_TLS_EC_CALC_QUEUE bool queued : 1; /**< TLS is queued */ +#endif bool library_init : 1; /**< TLS library has been initialized */ tls_sec_prot_lib_int_t *tls_sec_inst; /**< TLS security library storage, SHALL BE THE LAST FIELD */ } tls_sec_prot_int_t; +// TLS server EC queue is currently disabled, since EC calculation is made on server in one go +#ifdef SERVER_TLS_EC_CALC_QUEUE typedef struct { ns_list_link_t link; /**< Link */ sec_prot_t *prot; /**< Protocol instance */ } tls_sec_prot_queue_t; +#endif static uint16_t tls_sec_prot_size(void); static int8_t client_tls_sec_prot_init(sec_prot_t *prot); @@ -102,15 +107,22 @@ static int8_t tls_sec_prot_tls_get_timer(void *handle); static int8_t tls_sec_prot_tls_configure_and_connect(sec_prot_t *prot, bool is_server); +#ifdef SERVER_TLS_EC_CALC_QUEUE static bool tls_sec_prot_queue_check(sec_prot_t *prot); static bool tls_sec_prot_queue_process(sec_prot_t *prot); static void tls_sec_prot_queue_remove(sec_prot_t *prot); +#else +#define tls_sec_prot_queue_process(prot) true +#define tls_sec_prot_queue_remove(prot) +#endif /* SERVER_TLS_EC_CALC_QUEUE */ static uint16_t tls_sec_prot_send_buffer_size_get(sec_prot_t *prot); #define tls_sec_prot_get(prot) (tls_sec_prot_int_t *) &prot->data +#ifdef SERVER_TLS_EC_CALC_QUEUE static NS_LIST_DEFINE(tls_sec_prot_queue, tls_sec_prot_queue_t, link); +#endif int8_t client_tls_sec_prot_register(kmp_service_t *service) { @@ -168,7 +180,9 @@ static int8_t client_tls_sec_prot_init(sec_prot_t *prot) data->fin_timer_timeout = false; data->timer_running = false; data->calculating = false; +#ifdef SERVER_TLS_EC_CALC_QUEUE data->queued = false; +#endif data->library_init = false; return 0; } @@ -198,7 +212,9 @@ static int8_t server_tls_sec_prot_init(sec_prot_t *prot) data->fin_timer_timeout = false; data->timer_running = false; data->calculating = false; +#ifdef SERVER_TLS_EC_CALC_QUEUE data->queued = false; +#endif data->library_init = false; return 0; } @@ -281,7 +297,11 @@ static void tls_sec_prot_timer_timeout(sec_prot_t *prot, uint16_t ticks) if (data->fin_timer_timeout) { data->fin_timer_timeout = false; prot->state_machine(prot); - } else if (data->calculating || data->queued) { + } else if (data->calculating +#ifdef SERVER_TLS_EC_CALC_QUEUE + || data->queued +#endif + ) { prot->state_machine(prot); } } @@ -355,7 +375,7 @@ static void client_tls_sec_prot_state_machine(sec_prot_t *prot) data->calculating = false; if (sec_prot_result_ok_check(&data->common)) { - sec_prot_keys_pmk_write(prot->sec_keys, data->new_pmk); + sec_prot_keys_pmk_write(prot->sec_keys, data->new_pmk, prot->timer_cfg->pmk_lifetime); } // KMP-FINISHED.indication, @@ -385,7 +405,9 @@ static void server_tls_sec_prot_state_machine(sec_prot_t *prot) { tls_sec_prot_int_t *data = tls_sec_prot_get(prot); int8_t result; +#ifdef SERVER_TLS_EC_CALC_QUEUE bool client_hello = false; +#endif switch (sec_prot_state_get(&data->common)) { case TLS_STATE_INIT: @@ -400,7 +422,9 @@ static void server_tls_sec_prot_state_machine(sec_prot_t *prot) case TLS_STATE_CLIENT_HELLO: tr_debug("TLS: start, eui-64: %s", trace_array(sec_prot_remote_eui_64_addr_get(prot), 8)); +#ifdef SERVER_TLS_EC_CALC_QUEUE client_hello = true; +#endif sec_prot_state_set(prot, &data->common, TLS_STATE_CREATE_RESP); @@ -430,6 +454,7 @@ static void server_tls_sec_prot_state_machine(sec_prot_t *prot) break; case TLS_STATE_PROCESS: +#ifdef SERVER_TLS_EC_CALC_QUEUE // If not client hello, reserves slot on TLS queue if (!client_hello && !tls_sec_prot_queue_check(prot)) { data->queued = true; @@ -437,6 +462,7 @@ static void server_tls_sec_prot_state_machine(sec_prot_t *prot) } else { data->queued = false; } +#endif result = tls_sec_prot_lib_process((tls_security_t *) &data->tls_sec_inst); @@ -468,7 +494,7 @@ static void server_tls_sec_prot_state_machine(sec_prot_t *prot) data->calculating = false; if (sec_prot_result_ok_check(&data->common)) { - sec_prot_keys_pmk_write(prot->sec_keys, data->new_pmk); + sec_prot_keys_pmk_write(prot->sec_keys, data->new_pmk, prot->timer_cfg->pmk_lifetime); } // KMP-FINISHED.indication, @@ -636,6 +662,7 @@ static int8_t tls_sec_prot_tls_configure_and_connect(sec_prot_t *prot, bool is_s return 0; } +#ifdef SERVER_TLS_EC_CALC_QUEUE static bool tls_sec_prot_queue_check(sec_prot_t *prot) { bool queue_add = true; @@ -703,6 +730,7 @@ static void tls_sec_prot_queue_remove(sec_prot_t *prot) } } } +#endif static uint16_t tls_sec_prot_send_buffer_size_get(sec_prot_t *prot) { diff --git a/source/Service_Libs/etx/etx.c b/source/Service_Libs/etx/etx.c index 639490981a6..76b7c7d2034 100644 --- a/source/Service_Libs/etx/etx.c +++ b/source/Service_Libs/etx/etx.c @@ -37,9 +37,14 @@ #define TRACE_GROUP "etx" +typedef struct { + uint8_t attribute_index; + const uint8_t *mac64; +} ext_neigh_info_t; + static uint16_t etx_current_calc(uint16_t etx, uint8_t accumulated_failures); static uint16_t etx_dbm_lqi_calc(uint8_t lqi, int8_t dbm); -static void etx_value_change_callback_needed_check(uint16_t etx, uint16_t *stored_diff_etx, uint8_t accumulated_failures, uint8_t attribute_index); +static void etx_value_change_callback_needed_check(uint16_t etx, uint16_t *stored_diff_etx, uint8_t accumulated_failures, ext_neigh_info_t *etx_neigh_info); static void etx_accum_failures_callback_needed_check(etx_storage_t *entry, uint8_t attribute_index); static void etx_cache_entry_init(uint8_t attribute_index); @@ -90,7 +95,7 @@ static ext_info_t etx_info = { .interface_id = -1 }; -static void etx_calculation(etx_storage_t *entry, uint16_t attempts, uint8_t acks_rx, uint8_t attribute_index) +static void etx_calculation(etx_storage_t *entry, uint16_t attempts, uint8_t acks_rx, ext_neigh_info_t *etx_neigh_info) { if (etx_info.hysteresis && !entry->stored_diff_etx) { if (entry->etx_samples >= etx_info.init_etx_sample_count) { @@ -130,9 +135,9 @@ static void etx_calculation(etx_storage_t *entry, uint16_t attempts, uint8_t ack entry->etx = etx; if (entry->etx_samples >= etx_info.init_etx_sample_count) { - etx_cache_entry_init(attribute_index); + etx_cache_entry_init(etx_neigh_info->attribute_index); // Checks if ETX value change callback is needed - etx_value_change_callback_needed_check(entry->etx, &(entry->stored_diff_etx), entry->accumulated_failures, attribute_index); + etx_value_change_callback_needed_check(entry->etx, &(entry->stored_diff_etx), entry->accumulated_failures, etx_neigh_info); } } @@ -203,7 +208,7 @@ static etx_sample_storage_t *etx_cache_sample_update(uint8_t attribute_index, ui * \param addr_type address type, ADDR_802_15_4_SHORT or ADDR_802_15_4_LONG * \param addr_ptr PAN ID with 802.15.4 address */ -void etx_transm_attempts_update(int8_t interface_id, uint8_t attempts, bool success, uint8_t attribute_index) +void etx_transm_attempts_update(int8_t interface_id, uint8_t attempts, bool success, uint8_t attribute_index, const uint8_t *mac64_addr_ptr) { uint8_t accumulated_failures; // Gets table entry @@ -212,6 +217,10 @@ void etx_transm_attempts_update(int8_t interface_id, uint8_t attempts, bool succ return; } + ext_neigh_info_t etx_neigh_info; + etx_neigh_info.attribute_index = attribute_index; + etx_neigh_info.mac64 = mac64_addr_ptr; + if (entry->etx_samples < 7) { entry->etx_samples++; } @@ -225,7 +234,7 @@ void etx_transm_attempts_update(int8_t interface_id, uint8_t attempts, bool succ return; } - etx_calculation(entry, storage->attempts_count, storage->received_acks, attribute_index); + etx_calculation(entry, storage->attempts_count, storage->received_acks, &etx_neigh_info); if (entry->etx_samples < 7 && !success) { entry->etx_samples = 7; //Stop Probing to failure @@ -254,7 +263,7 @@ void etx_transm_attempts_update(int8_t interface_id, uint8_t attempts, bool succ if (entry->etx) { if (success) { - etx_calculation(entry, attempts + accumulated_failures, 1, attribute_index); + etx_calculation(entry, attempts + accumulated_failures, 1, &etx_neigh_info); } } } @@ -268,35 +277,42 @@ void etx_transm_attempts_update(int8_t interface_id, uint8_t attempts, bool succ * \param remote_incoming_idr Remote incoming IDR * \param mac64_addr_ptr long MAC address */ -void etx_remote_incoming_idr_update(int8_t interface_id, uint8_t remote_incoming_idr, uint8_t attribute_index) +void etx_remote_incoming_idr_update(int8_t interface_id, uint8_t remote_incoming_idr, uint8_t attribute_index, const uint8_t *mac64_addr_ptr) { etx_storage_t *entry = etx_storage_entry_get(interface_id, attribute_index); + if (!entry) { + return; + } - if (entry) { - // If ETX has been set - if (entry->etx) { - // If hysteresis is set stores ETX value to enable comparison - if (etx_info.hysteresis && !entry->stored_diff_etx) { - entry->stored_diff_etx = entry->etx; - } - // remote EXT = remote incoming IDR^2 (12 bit fraction) - uint32_t remote_ext = ((uint32_t)remote_incoming_idr * remote_incoming_idr) << 2; + ext_neigh_info_t etx_neigh_info; + etx_neigh_info.attribute_index = attribute_index; + etx_neigh_info.mac64 = mac64_addr_ptr; - // ETX = 7/8 * current ETX + 1/8 * remote ETX */ - uint32_t etx = entry->etx - (entry->etx >> ETX_MOVING_AVERAGE_FRACTION); - etx += remote_ext >> ETX_MOVING_AVERAGE_FRACTION; - if (etx > 0xffff) { - entry->etx = 0xffff; - } else { - entry->etx = etx; - } + // If ETX has been set + if (entry->etx) { + // If hysteresis is set stores ETX value to enable comparison + if (etx_info.hysteresis && !entry->stored_diff_etx) { + entry->stored_diff_etx = entry->etx; + } + // remote EXT = remote incoming IDR^2 (12 bit fraction) + uint32_t remote_ext = ((uint32_t)remote_incoming_idr * remote_incoming_idr) << 2; - // Checks if ETX value change callback is needed - etx_value_change_callback_needed_check(entry->etx, &(entry->stored_diff_etx), entry->accumulated_failures, attribute_index); + // ETX = 7/8 * current ETX + 1/8 * remote ETX */ + uint32_t etx = entry->etx - (entry->etx >> ETX_MOVING_AVERAGE_FRACTION); + etx += remote_ext >> ETX_MOVING_AVERAGE_FRACTION; + + if (etx > 0xffff) { + entry->etx = 0xffff; + } else { + entry->etx = etx; } - entry->remote_incoming_idr = remote_incoming_idr; + + // Checks if ETX value change callback is needed + etx_value_change_callback_needed_check(entry->etx, &(entry->stored_diff_etx), entry->accumulated_failures, &etx_neigh_info); } + entry->remote_incoming_idr = remote_incoming_idr; + } /** @@ -442,14 +458,18 @@ static uint16_t etx_current_calc(uint16_t etx, uint8_t accumulated_failures) * * \return 0x0100 to 0xFFFF local incoming IDR value (8 bit fraction) */ -uint16_t etx_lqi_dbm_update(int8_t interface_id, uint8_t lqi, int8_t dbm, uint8_t attribute_index) +uint16_t etx_lqi_dbm_update(int8_t interface_id, uint8_t lqi, int8_t dbm, uint8_t attribute_index, const uint8_t *mac64_addr_ptr) { uint32_t local_incoming_idr = 0; uint32_t etx = 0; etx_storage_t *entry = etx_storage_entry_get(interface_id, attribute_index); + if (entry) { + ext_neigh_info_t etx_neigh_info; + etx_neigh_info.attribute_index = attribute_index; + etx_neigh_info.mac64 = mac64_addr_ptr; // If local ETX is not set calculate it based on LQI and dBm if (!entry->etx) { etx = etx_dbm_lqi_calc(lqi, dbm); @@ -458,7 +478,7 @@ uint16_t etx_lqi_dbm_update(int8_t interface_id, uint8_t lqi, int8_t dbm, uint8_ entry->tmp_etx = true; if (etx_info.callback_ptr) { etx_info.callback_ptr(etx_info.interface_id, 0, entry->etx >> 4, - attribute_index); + attribute_index, mac64_addr_ptr); } } // If local ETX has been calculated without remote incoming IDR and @@ -474,7 +494,7 @@ uint16_t etx_lqi_dbm_update(int8_t interface_id, uint8_t lqi, int8_t dbm, uint8_ entry->etx = etx >> 12; local_incoming_idr >>= 4; - etx_value_change_callback_needed_check(entry->etx, &(entry->stored_diff_etx), entry->accumulated_failures, attribute_index); + etx_value_change_callback_needed_check(entry->etx, &(entry->stored_diff_etx), entry->accumulated_failures, &etx_neigh_info); } } @@ -721,7 +741,7 @@ uint8_t etx_accum_failures_callback_register(nwk_interface_id nwk_id, int8_t int * * \return ETX value (12 bit fraction) */ -static void etx_value_change_callback_needed_check(uint16_t etx, uint16_t *stored_diff_etx, uint8_t accumulated_failures, uint8_t attribute_index) +static void etx_value_change_callback_needed_check(uint16_t etx, uint16_t *stored_diff_etx, uint8_t accumulated_failures, ext_neigh_info_t *etx_neigh_info) { uint16_t current_etx; bool callback = false; @@ -747,7 +767,7 @@ static void etx_value_change_callback_needed_check(uint16_t etx, uint16_t *store // Calls callback function if (callback) { - etx_info.callback_ptr(etx_info.interface_id, (*stored_diff_etx) >> 4, current_etx >> 4, attribute_index); + etx_info.callback_ptr(etx_info.interface_id, (*stored_diff_etx) >> 4, current_etx >> 4, etx_neigh_info->attribute_index, etx_neigh_info->mac64); *stored_diff_etx = current_etx; } } @@ -782,7 +802,7 @@ static void etx_accum_failures_callback_needed_check(etx_storage_t *entry, uint8 * \param mac64_addr_ptr long MAC address * */ -void etx_neighbor_remove(int8_t interface_id, uint8_t attribute_index) +void etx_neighbor_remove(int8_t interface_id, uint8_t attribute_index, const uint8_t *mac64_addr_ptr) { //tr_debug("Remove attribute %u", attribute_index); @@ -795,7 +815,8 @@ void etx_neighbor_remove(int8_t interface_id, uint8_t attribute_index) if (!stored_diff_etx) { stored_diff_etx = 0xffff; } - etx_info.callback_ptr(etx_info.interface_id, stored_diff_etx, 0xffff, attribute_index); + + etx_info.callback_ptr(etx_info.interface_id, stored_diff_etx, 0xffff, attribute_index, mac64_addr_ptr); } if (etx_info.cache_sample_requested) { @@ -829,7 +850,10 @@ void etx_cache_timer(int8_t interface_id, uint16_t seconds_update) etx_sample_storage_t *storage = etx_info.etx_cache_storage_list + neighbour->index; if (etx_update_possible(storage, etx_entry, seconds_update)) { - etx_calculation(etx_entry, storage->attempts_count, storage->received_acks, neighbour->index); + ext_neigh_info_t etx_neigh_info; + etx_neigh_info.attribute_index = neighbour->index; + etx_neigh_info.mac64 = neighbour->mac64; + etx_calculation(etx_entry, storage->attempts_count, storage->received_acks, &etx_neigh_info); } } diff --git a/source/Service_Libs/etx/etx.h b/source/Service_Libs/etx/etx.h index c785cc5c983..a1c40b2694d 100644 --- a/source/Service_Libs/etx/etx.h +++ b/source/Service_Libs/etx/etx.h @@ -76,8 +76,9 @@ typedef struct etx_sample_storage_s { * \param attempts number of attempts to send message * \param success was message sending successful * \param attribute_index Neighbour attribute index + * \param mac64_addr_ptr Neighbour MAC64 */ -void etx_transm_attempts_update(int8_t interface_id, uint8_t attempts, bool success, uint8_t attribute_index); +void etx_transm_attempts_update(int8_t interface_id, uint8_t attempts, bool success, uint8_t attribute_index, const uint8_t *mac64_addr_ptr); /** * \brief A function to update ETX value based on remote incoming IDR @@ -88,8 +89,9 @@ void etx_transm_attempts_update(int8_t interface_id, uint8_t attempts, bool succ * \param interface_id Interface identifier * \param remote_incoming_idr Remote incoming IDR * \param attribute_index Neighbour attribute index + * \param mac64_addr_ptr Neighbour MAC64 */ -void etx_remote_incoming_idr_update(int8_t interface_id, uint8_t remote_incoming_idr, uint8_t attribute_index); +void etx_remote_incoming_idr_update(int8_t interface_id, uint8_t remote_incoming_idr, uint8_t attribute_index, const uint8_t *mac64_addr_ptr); /** * \brief A function to read ETX value @@ -139,10 +141,11 @@ uint16_t etx_local_etx_read(int8_t interface_id, uint8_t attribute_index); * \param lqi link quality indicator * \param dbm measured dBm * \param attribute_index Neighbour attribute index + * \param mac64_addr_ptr Neighbour MAC64 * * \return 0x0100 to 0xFFFF local incoming IDR value (8 bit fraction) */ -uint16_t etx_lqi_dbm_update(int8_t interface_id, uint8_t lqi, int8_t dbm, uint8_t attribute_index); +uint16_t etx_lqi_dbm_update(int8_t interface_id, uint8_t lqi, int8_t dbm, uint8_t attribute_index, const uint8_t *mac64_addr_ptr); /** * \brief A function callback that indicates ETX value change @@ -154,9 +157,10 @@ uint16_t etx_lqi_dbm_update(int8_t interface_id, uint8_t lqi, int8_t dbm, uint8_ * \param previous_etx ETX value to what the current ETX was compared (8 bit fraction) * \param current_etx current ETX value (8 bit fraction) * \param attribute_index Neighbour attribute index + * \param mac64_addr_ptr Pointer to MAC64 for given etx update * */ -typedef void (etx_value_change_handler_t)(int8_t nwk_id, uint16_t previous_etx, uint16_t current_etx, uint8_t attribute_index); +typedef void (etx_value_change_handler_t)(int8_t nwk_id, uint16_t previous_etx, uint16_t current_etx, uint8_t attribute_index, const uint8_t *mac64_addr_ptr); /** * \brief A function callback that indicates the number of accumulated TX failures @@ -232,9 +236,10 @@ uint8_t etx_accum_failures_callback_register(nwk_interface_id nwk_id, int8_t int * if that is set. * * \param attribute_index Neighbour attribute index + * \param mac64_addr_ptr Neighbour MAC64 * */ -void etx_neighbor_remove(int8_t interface_id, uint8_t attribute_index); +void etx_neighbor_remove(int8_t interface_id, uint8_t attribute_index, const uint8_t *mac64_addr_ptr); /** * \brief A function for update cached ETX calculation diff --git a/source/Service_Libs/fhss/fhss_test_api.c b/source/Service_Libs/fhss/fhss_test_api.c index 7b1e696ea04..02e63af682c 100644 --- a/source/Service_Libs/fhss/fhss_test_api.c +++ b/source/Service_Libs/fhss/fhss_test_api.c @@ -44,3 +44,18 @@ int8_t fhss_set_optimal_packet_length(const fhss_api_t *fhss_api, uint16_t packe #endif return 0; } + +int8_t fhss_set_number_of_channel_retries(const fhss_api_t *fhss_api, uint8_t number_of_channel_retries) +{ + (void) fhss_api; + (void) number_of_channel_retries; +#ifdef HAVE_WS + fhss_structure_t *fhss_structure = fhss_get_object_with_api(fhss_api); + if (!fhss_structure || !fhss_structure->ws) { + return -1; + } + fhss_structure->ws->fhss_configuration.config_parameters.number_of_channel_retries = number_of_channel_retries; + tr_debug("Setting number of channel retries to: %u", number_of_channel_retries); +#endif + return 0; +} diff --git a/source/Service_Libs/fhss/fhss_ws.c b/source/Service_Libs/fhss/fhss_ws.c index 1d29e70c2af..80c3f90d149 100644 --- a/source/Service_Libs/fhss/fhss_ws.c +++ b/source/Service_Libs/fhss/fhss_ws.c @@ -750,16 +750,18 @@ static bool fhss_ws_data_tx_fail_callback(const fhss_api_t *api, uint8_t handle, if (fhss_structure->fhss_state == FHSS_UNSYNCHRONIZED) { return false; } - // Use channel retries only for data frames if (FHSS_DATA_FRAME != frame_type) { return false; } - + // Channel retries are disabled + if (!fhss_structure->ws->fhss_configuration.config_parameters.number_of_channel_retries) { + return false; + } fhss_failed_tx_t *fhss_failed_tx = fhss_failed_handle_find(fhss_structure, handle); if (fhss_failed_tx) { fhss_failed_tx->retries_done++; - if (fhss_failed_tx->retries_done >= WS_NUMBER_OF_CHANNEL_RETRIES) { + if (fhss_failed_tx->retries_done >= fhss_structure->ws->fhss_configuration.config_parameters.number_of_channel_retries) { // No more retries. Return false to stop retransmitting. fhss_failed_handle_remove(fhss_structure, handle); return false; @@ -966,6 +968,19 @@ int fhss_ws_configuration_set(fhss_structure_t *fhss_structure, const fhss_ws_co if (channel_count <= 0) { return -1; } + + if (fhss_structure->number_of_channels < channel_count || + (channel_count_uc && fhss_structure->number_of_uc_channels < channel_count_uc)) { + // Channel amount changed to largeneed to reallocate channel table + ns_dyn_mem_free(fhss_structure->ws->tr51_channel_table); + fhss_structure->ws->tr51_channel_table = NULL; + ns_dyn_mem_free(fhss_structure->ws->tr51_output_table); + fhss_structure->ws->tr51_output_table = NULL; + + if (fhss_ws_manage_channel_table_allocation(fhss_structure, channel_count_uc > channel_count ? channel_count_uc : channel_count)) { + return -1; + } + } platform_enter_critical(); if (fhss_configuration->ws_uc_channel_function == WS_FIXED_CHANNEL || fhss_configuration->fhss_uc_dwell_interval == 0) { fhss_stop_timer(fhss_structure, fhss_unicast_handler); diff --git a/source/Service_Libs/fhss/fhss_ws.h b/source/Service_Libs/fhss/fhss_ws.h index c3d31fa67ef..f4d27c1bff0 100644 --- a/source/Service_Libs/fhss/fhss_ws.h +++ b/source/Service_Libs/fhss/fhss_ws.h @@ -17,10 +17,6 @@ #ifndef FHSS_WS_H_ #define FHSS_WS_H_ -/* WS requires at least 19 MAC retransmissions (total 1+19=20 attempts). 802.15.4 macMaxFrameRetries is 3 (total 1+3=4 attempts). - * At least 4 channel retries must be used: (Initial channel + WS_NUMBER_OF_CHANNEL_RETRIES) * MAC attempts = (1+4)*4=20 attempts - */ -#define WS_NUMBER_OF_CHANNEL_RETRIES 4 // TX slot length is optimised to this packet length #define OPTIMAL_PACKET_LENGTH 500 // Default TX/RX slot length in milliseconds. Is used when datarate is not given by PHY. diff --git a/source/Service_Libs/mac_neighbor_table/mac_neighbor_table.c b/source/Service_Libs/mac_neighbor_table/mac_neighbor_table.c index 3f1960fb5bc..19691592777 100644 --- a/source/Service_Libs/mac_neighbor_table/mac_neighbor_table.c +++ b/source/Service_Libs/mac_neighbor_table/mac_neighbor_table.c @@ -101,6 +101,10 @@ void mac_neighbor_table_neighbor_timeout_update(mac_neighbor_table_t *table_clas ns_list_foreach_safe(mac_neighbor_table_entry_t, cur, &table_class->neighbour_list) { if (cur->lifetime > time_update) { + if (cur->lifetime == 0xffffffff && cur->link_lifetime == 0xffffffff) { + continue; //Infinite Lifetime too not touch + } + cur->lifetime -= time_update; if (!table_class->user_nud_notify_cb || table_class->active_nud_process > ACTIVE_NUD_PROCESS_MAX || cur->nud_active || !cur->rx_on_idle) { continue; diff --git a/source/Service_Libs/mdns/fnet/fnet_stack/port/compiler/fnet_comp_config.h b/source/Service_Libs/mdns/fnet/fnet_stack/port/compiler/fnet_comp_config.h index cf878c5aa18..81732fbf62b 100644 --- a/source/Service_Libs/mdns/fnet/fnet_stack/port/compiler/fnet_comp_config.h +++ b/source/Service_Libs/mdns/fnet/fnet_stack/port/compiler/fnet_comp_config.h @@ -94,10 +94,6 @@ #elif defined(__clang__) #define FNET_CFG_COMP_CLANG (1) #define FNET_COMP_STR "CLANG" - /* Keil uVision compiler using armcc. */ - #elif defined(__CC_ARM) - #define FNET_CFG_COMP_UV (1) - #define FNET_COMP_STR "UV" /* GNU GCC */ #elif defined(__GNUC__) #define FNET_CFG_COMP_GNUC (1) diff --git a/source/Service_Libs/utils/ns_conf.c b/source/Service_Libs/utils/ns_conf.c index 54ebbbe8a8f..93de03ce43b 100644 --- a/source/Service_Libs/utils/ns_conf.c +++ b/source/Service_Libs/utils/ns_conf.c @@ -29,5 +29,5 @@ int ns_conf_gc_threshold_set(uint8_t percentage_high, uint8_t percentage_critica int ns_conf_packet_ingress_rate_limit_by_mem(uint8_t free_heap_percentage) { - return mcps_packet_ingress_rate_limit_by_memory(free_heap_percentage); + return ns_monitor_packet_ingress_rate_limit_by_memory(free_heap_percentage); } diff --git a/source/Service_Libs/utils/ns_file.h b/source/Service_Libs/utils/ns_file.h new file mode 100644 index 00000000000..8ba32133a64 --- /dev/null +++ b/source/Service_Libs/utils/ns_file.h @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2017, Arm Limited and affiliates. + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _NS_FILE_H_ +#define _NS_FILE_H_ + +/** + * \file ns_file.h + * \brief Nanostack file handling API. + */ + +#include "ns_file_system.h" + +/** + * File open + * + * Depending on underlying file system file open for read for non-existing + * files can return success. In that case file read will fail. + * + * \param filename filename + * \param mode can be either "r" or "w" + * + * \return file handle + * \return NULL on error + * + */ +NS_FILE ns_fopen(const char *filename, const char *mode); + +/** + * File close + * + * \param handle file handle + * + * \return 0 on success + * \return < 0 in case of errors + * + */ +int ns_fclose(NS_FILE *ns_handle); + +/** + * File remove + * + * \param filename filename + * + * \return 0 on success + * \return < 0 in case of errors + * + */ +int ns_fremove(const char *filename); + +/** + * File write + * + * Write is not stream write. The whole file is written from start to end + * and if function is called again, previous file content is replaced with + * new content. + * + * \param handle file handle + * \param buffer buffer + * \param buffer buffer size + * + * \return bytes written + * + */ +size_t ns_fwrite(NS_FILE *ns_handle, const void *buffer, size_t size); + +/** + * File read + * + * Read is not stream read. The whole file is read from start to end + * and if function is called again, read is started from start again. + * + * \param handle file handle + * \param buffer buffer + * \param size buffer size + * + * \return bytes written + * + */ +size_t ns_fread(NS_FILE *ns_handle, void *buffer, size_t size); + +/** + * File size callback + * + * Reads file size. + * + * \param handle file handle + * \param size file size + * + * \return 0 on success + * \return < 0 in case of reading file size is not supported + * + */ +int ns_fsize(NS_FILE *ns_handle, size_t *size); + +#endif /* _NS_FILE_SYSTEM_H_ */ diff --git a/source/Service_Libs/utils/ns_file_system.c b/source/Service_Libs/utils/ns_file_system.c index 5ea3cca5fd1..a7202ccdd02 100644 --- a/source/Service_Libs/utils/ns_file_system.c +++ b/source/Service_Libs/utils/ns_file_system.c @@ -16,12 +16,21 @@ */ #include +#include #include "ns_types.h" #include "nsdynmemLIB.h" #include "ns_file_system.h" +#include "ns_file.h" static char *file_system_root; +static ns_file_open file_open_cb = NULL; +static ns_file_close file_close_cb = NULL; +static ns_file_remove file_remove_cb = NULL; +static ns_file_write file_write_cb = NULL; +static ns_file_read file_read_cb = NULL; +static ns_file_size file_size_cb = NULL; + int ns_file_system_set_root_path(const char *root_path) { char *new_root_path; @@ -50,3 +59,99 @@ char *ns_file_system_get_root_path(void) { return file_system_root; } + +void ns_file_system_callbacks_set(ns_file_open open, ns_file_close close, ns_file_remove remove, ns_file_write write, ns_file_read read, ns_file_size size) +{ + file_open_cb = open; + file_close_cb = close; + file_remove_cb = remove; + file_write_cb = write; + file_read_cb = read; + file_size_cb = size; +} + +NS_FILE ns_fopen(const char *file_name, const char *mode) +{ + if (!file_name || !mode || (*mode != 'r' && *mode != 'w')) { + return NULL; + } + + if (file_open_cb) { + return file_open_cb(file_name, mode); + } + + FILE *file = fopen(file_name, mode); + if (file == NULL) { + return NULL; + } + + return (NS_FILE) file; +} + +int ns_fclose(NS_FILE *ns_handle) +{ + if (!ns_handle) { + return -1; + } + + if (file_close_cb) { + return file_close_cb(ns_handle); + } + fclose((FILE *) ns_handle); + return 0; +} + +int ns_fremove(const char *file_name) +{ + if (file_remove_cb) { + return file_remove_cb(file_name); + } + + if (!file_name) { + return -1; + } + + return remove(file_name); +} + +size_t ns_fwrite(NS_FILE *ns_handle, const void *buffer, size_t size) +{ + if (!ns_handle || !buffer || size == 0) { + return 0; + } + + if (file_write_cb) { + return file_write_cb(ns_handle, buffer, size); + } + + rewind((FILE *) ns_handle); + return fwrite(buffer, 1, size, (FILE *) ns_handle); +} + +size_t ns_fread(NS_FILE *ns_handle, void *buffer, size_t size) +{ + if (!ns_handle || !buffer || size == 0) { + return 0; + } + + if (file_read_cb) { + return file_read_cb(ns_handle, buffer, size); + } + + rewind((FILE *) ns_handle); + return fread(buffer, 1, size, (FILE *) ns_handle); +} + +int ns_fsize(NS_FILE *ns_handle, size_t *size) +{ + if (!ns_handle || !size) { + return 0; + } + + if (file_size_cb) { + return file_size_cb(ns_handle, size); + } + + fseek((FILE *) ns_handle, 0L, SEEK_END); + return ftell((FILE *) ns_handle); +} diff --git a/source/nsconfig.h b/source/nsconfig.h index 9a6db864a20..dff8a5622d4 100644 --- a/source/nsconfig.h +++ b/source/nsconfig.h @@ -24,10 +24,6 @@ #include "ns_types.h" -#ifdef __CC_ARM -#pragma diag_suppress 546 // transfer of control bypasses initialization -#endif - #define __ns_cfg_header(x) #x #define _ns_cfg_header(x) __ns_cfg_header(configs/cfg_##x.h) #define ns_cfg_header(x) _ns_cfg_header(x) diff --git a/sources.mk b/sources.mk index 3998833c3be..e364c49b840 100644 --- a/sources.mk +++ b/sources.mk @@ -34,7 +34,9 @@ SRCS += \ source/6LoWPAN/ws/ws_pae_lib.c \ source/6LoWPAN/ws/ws_pae_nvm_data.c \ source/6LoWPAN/ws/ws_pae_nvm_store.c \ + source/6LoWPAN/ws/ws_pae_time.c \ source/6LoWPAN/ws/ws_pae_timers.c \ + source/6LoWPAN/ws/ws_pae_key_storage.c \ source/6LoWPAN/ws/ws_eapol_relay.c \ source/6LoWPAN/ws/ws_eapol_auth_relay.c \ source/6LoWPAN/ws/ws_eapol_relay_lib.c \ @@ -79,6 +81,7 @@ SRCS += \ source/MAC/IEEE802_15_4/mac_timer.c \ 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/ethernet/ethernet_mac_api.c \ source/MAC/serial/serial_mac_api.c \ source/MAC/virtual_rf/virtual_rf_client.c \