From 843254a510d02d2ed80581c7511ae11cd26513fa Mon Sep 17 00:00:00 2001 From: Jarkko Paso Date: Wed, 10 Jun 2020 15:11:27 +0300 Subject: [PATCH 01/30] MPL: traces for transmit and receive message (#2387) --- source/MPL/mpl.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/source/MPL/mpl.c b/source/MPL/mpl.c index 1474c89187fc..f8e0b93dc194 100644 --- a/source/MPL/mpl.c +++ b/source/MPL/mpl.c @@ -498,6 +498,7 @@ static void mpl_buffer_transmit(mpl_domain_t *domain, mpl_buffered_message_t *me memcpy(buf->src_sa.address, message->message + IPV6_HDROFF_SRC_ADDR, 16); ipv6_transmit_multicast_on_interface(buf, domain->interface); + tr_debug("MPL transmit %u", mpl_buffer_sequence(message)); } static void mpl_buffer_inconsistent(const mpl_domain_t *domain, mpl_buffered_message_t *message) @@ -853,6 +854,7 @@ bool mpl_forwarder_process_message(buffer_t *buf, mpl_domain_t *domain, bool see const uint8_t *seed_id = opt_data + 2; uint8_t seed_id_len = mpl_seed_id_len(seed_id_type); + tr_debug("MPL %s %"PRIu8, seeding ? "transmit" : "received", sequence); /* Special handling - just ignore the MPL option if receiving loopback copy. * (MPL gets to process the outgoing message, and with seeding true - when * looping back, we want to accept it without MPL getting in the way). From 2174374df3283b6fe7492f9c447cb8242211eaef Mon Sep 17 00:00:00 2001 From: Arto Kinnunen Date: Mon, 15 Jun 2020 15:53:26 +0300 Subject: [PATCH 02/30] Fix error found by coverity (#2389) Fix error found by coverity CID 682646: Dereference null return value --- source/6LoWPAN/ws/ws_pae_supp.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/source/6LoWPAN/ws/ws_pae_supp.c b/source/6LoWPAN/ws/ws_pae_supp.c index 7954010d508f..a2cc896408d1 100644 --- a/source/6LoWPAN/ws/ws_pae_supp.c +++ b/source/6LoWPAN/ws/ws_pae_supp.c @@ -286,8 +286,9 @@ int8_t ws_pae_supp_nw_key_valid(protocol_interface_info_entry_t *interface_ptr, /* 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)); + if (!ptk_eui_64 || 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", + ptk_eui_64 ? 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); From e4630a4916a0ed6e3c544b525f3b36c022292c51 Mon Sep 17 00:00:00 2001 From: Mika Tervonen Date: Thu, 11 Jun 2020 14:36:02 +0300 Subject: [PATCH 03/30] Wi-SUN interface now informs address changes as interface events When addressing changes in Border router Wi-SUN interface it also informs the application which can then check the available addresses and act accordingly if address is changed Allow arm_net_address_get function to return Link Local address even if the interface does not have global address available --- source/6LoWPAN/ws/ws_bootstrap.c | 35 ++++++++++++++++---------------- source/libNET/src/ns_net.c | 3 ++- 2 files changed, 20 insertions(+), 18 deletions(-) diff --git a/source/6LoWPAN/ws/ws_bootstrap.c b/source/6LoWPAN/ws/ws_bootstrap.c index 0d02498a5dcc..9e2d23146a9e 100644 --- a/source/6LoWPAN/ws/ws_bootstrap.c +++ b/source/6LoWPAN/ws/ws_bootstrap.c @@ -221,13 +221,15 @@ static void ws_address_reregister_trig(struct protocol_interface_info_entry *int static void ws_bootstrap_address_notification_cb(struct protocol_interface_info_entry *interface, const struct if_address_entry *addr, if_address_callback_t reason) { + /* No need for LL address registration */ if (addr->source == ADDR_SOURCE_UNKNOWN || !interface->ws_info) { return; } if (reason == ADDR_CALLBACK_DAD_COMPLETE) { - //Trig Address Registartion only when Bootstrap is ready + //If address is generated manually we need to force registration if (addr->source != ADDR_SOURCE_DHCP) { + //Trigger Address Registration only when Bootstrap is ready if (interface->nwk_bootstrap_state == ER_BOOTSRAP_DONE) { tr_debug("Address registration %s", trace_ipv6(addr->address)); ws_address_registration_update(interface, addr->address); @@ -235,11 +237,6 @@ static void ws_bootstrap_address_notification_cb(struct protocol_interface_info_ ws_address_reregister_trig(interface); } - if (addr_ipv6_scope(addr->address, interface) > IPV6_SCOPE_LINK_LOCAL) { - // at least ula address available inside mesh. - interface->global_address_available = true; - } - } else if (reason == ADDR_CALLBACK_DELETED) { // What to do? // Go through address list and check if there is global address still available @@ -251,14 +248,22 @@ static void ws_bootstrap_address_notification_cb(struct protocol_interface_info_ } //Discover prefix policy addr_policy_remove_by_label(WS_NON_PREFFRED_LABEL); + } - interface->global_address_available = false; - ns_list_foreach(if_address_entry_t, addr_str, &interface->ip_addresses) { - if (addr_ipv6_scope(addr_str->address, interface) > IPV6_SCOPE_LINK_LOCAL) { - // at least ula address available inside mesh. - interface->global_address_available = true; - break; - } + // Check the Address status if we have global address available. + interface->global_address_available = false; + ns_list_foreach(if_address_entry_t, addr_str, &interface->ip_addresses) { + if (addr_ipv6_scope(addr_str->address, interface) > IPV6_SCOPE_LINK_LOCAL) { + // at least ula address available inside mesh. + interface->global_address_available = true; + break; + } + } + // Addressing in Wi-SUN interface was changed for Border router send new event so Application can update the state + if (interface->bootsrap_mode == ARM_NWK_BOOTSRAP_MODE_6LoWPAN_BORDER_ROUTER && + interface->nwk_bootstrap_state == ER_BOOTSRAP_DONE) { + if (interface->bootsrap_state_machine_cnt == 0) { + interface->bootsrap_state_machine_cnt = 10; //Re trigger state check } } } @@ -3222,11 +3227,7 @@ void ws_bootstrap_configure_process(protocol_interface_info_entry_t *cur) if (cur->ws_info->configuration_learned) { ws_bootstrap_network_configuration_learn(cur); - - ws_bootstrap_event_operation_start(cur); - - return; } return; diff --git a/source/libNET/src/ns_net.c b/source/libNET/src/ns_net.c index e369f6c37588..caf446493f1b 100644 --- a/source/libNET/src/ns_net.c +++ b/source/libNET/src/ns_net.c @@ -425,7 +425,8 @@ int8_t arm_net_address_get(int8_t interface_id, net_address_t addr_id, uint8_t * return -1; } - if (!cur->global_address_available) { //Should also check Check Bootstrap state + if (!cur->global_address_available && addr_id != ADDR_IPV6_LL) { + //Should also check Check Bootstrap state return -1; } From bcce0ed0ef825b5aa81e6d4fe9b07a0e492d083b Mon Sep 17 00:00:00 2001 From: Mika Tervonen Date: Mon, 22 Jun 2020 10:19:32 +0300 Subject: [PATCH 04/30] Clarified border router routing table API description Fixed description to use entry counts instead of data amount --- nanostack/ws_bbr_api.h | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/nanostack/ws_bbr_api.h b/nanostack/ws_bbr_api.h index 9182ea74fdfc..c07b98225ff5 100644 --- a/nanostack/ws_bbr_api.h +++ b/nanostack/ws_bbr_api.h @@ -130,9 +130,9 @@ int ws_bbr_info_get(int8_t interface_id, bbr_information_t *info_ptr); * * Table is Parent child relation using the Global address IID of the devices * To get the full IPv6 address of the device. - * IPv6 = Global Prefix + IID. + * IPv6 = Global Prefix + IID. * - * Routing table is in the format: 18 bytes per entry + * Routing table is in the format: 16 bytes per entry * | Node IID 8 bytes | parent IID 8 bytes | * | 1122112211221122 | 1111111111111111 | * | 1133113311331133 | 1111111111111111 | @@ -142,15 +142,18 @@ int ws_bbr_info_get(int8_t interface_id, bbr_information_t *info_ptr); * | 1177117711771177 | 1155115511551155 | * | 1188118811881188 | 1177117711771177 | * - * Order is not assured only parent child link is given in random order + * Order is not assured only parent child link is given in random order, * - * Return value is device amount in network divided by 16 bytes per route entry + * When preparing to call this function ws_bbr_info_get function should be called to get the amount of devices in the network. + * Memory for table is allocated based on the size of network and needs to be sizeof(bbr_route_info_t) * amount of entries. * - * \param interface_id interface ID of the Wi-SUN network - * \param table_ptr Application allocated memory block where routing table is written. + * Return value is amount of route entries written to the table. + * + * \param interface_id interface ID of the Wi-SUN network. + * \param table_ptr Application allocated memory where routing table is written. * \param table_len Length of the table allocated by application given as amount of entries. * - * \return 0 - x on success indicates amount of bytes written to the table_ptr + * \return 0 - x on success indicates amount of Route entries written to the table_ptr * \return <0 in case of errors * */ From f27fe86a2447a94b1f64af9ff6ef05cc2206e084 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mika=20Lepp=C3=A4nen?= Date: Mon, 22 Jun 2020 23:27:03 +0300 Subject: [PATCH 05/30] Corrected network name and PAN ID change on auth start PAE supplicant did not detect correctly that network name or PAN ID was changed on authentication start. This causes the supplicant to use old keys and old BR EUI-64 during authentication, which resulted to BR EUI-64 mismatch on 4WH. --- source/6LoWPAN/ws/ws_pae_auth.c | 4 +++- source/6LoWPAN/ws/ws_pae_auth.h | 3 ++- source/6LoWPAN/ws/ws_pae_controller.c | 12 ++++++++---- source/6LoWPAN/ws/ws_pae_supp.c | 25 +++++++++++++++++++++++++ source/6LoWPAN/ws/ws_pae_supp.h | 14 ++++++++++++++ 5 files changed, 52 insertions(+), 6 deletions(-) diff --git a/source/6LoWPAN/ws/ws_pae_auth.c b/source/6LoWPAN/ws/ws_pae_auth.c index 077c3ae5806d..8db7f28fe4f4 100644 --- a/source/6LoWPAN/ws/ws_pae_auth.c +++ b/source/6LoWPAN/ws/ws_pae_auth.c @@ -470,8 +470,10 @@ void ws_pae_auth_forced_gc(protocol_interface_info_entry_t *interface_ptr) 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) +int8_t ws_pae_auth_nw_info_set(protocol_interface_info_entry_t *interface_ptr, uint16_t pan_id, char *network_name, bool updated) { + (void) updated; + if (!interface_ptr || !network_name) { return -1; } diff --git a/source/6LoWPAN/ws/ws_pae_auth.h b/source/6LoWPAN/ws/ws_pae_auth.h index db84db0656e1..6b2719df910a 100644 --- a/source/6LoWPAN/ws/ws_pae_auth.h +++ b/source/6LoWPAN/ws/ws_pae_auth.h @@ -174,12 +174,13 @@ void ws_pae_auth_forced_gc(protocol_interface_info_entry_t *interface_ptr); * \param interface_ptr interface * \param pan_id PAD ID * \param network_name network name + * \param updated data has been updated * * \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); +int8_t ws_pae_auth_nw_info_set(protocol_interface_info_entry_t *interface_ptr, uint16_t pan_id, char *network_name, bool updated); /** * ws_pae_auth_gtk_hash_set GTK hash set callback diff --git a/source/6LoWPAN/ws/ws_pae_controller.c b/source/6LoWPAN/ws/ws_pae_controller.c index 05eb06983b61..f033d1579269 100644 --- a/source/6LoWPAN/ws/ws_pae_controller.c +++ b/source/6LoWPAN/ws/ws_pae_controller.c @@ -52,7 +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 int8_t ws_pae_nw_info_set(protocol_interface_info_entry_t *interface_ptr, uint16_t pan_id, char *network_name, bool updated); typedef struct { uint8_t gtk[GTK_LEN]; /**< GTK key */ @@ -290,20 +290,24 @@ int8_t ws_pae_controller_nw_info_set(protocol_interface_info_entry_t *interface_ return -1; } + bool updated = false; + // Network name has been modified - if (network_name && strncmp(controller->sec_keys_nw_info.network_name, network_name, 33) != 0) { + if (network_name && strcmp(controller->sec_keys_nw_info.network_name, network_name) != 0) { strncpy(controller->sec_keys_nw_info.network_name, network_name, 32); controller->sec_keys_nw_info.updated = true; + updated = true; } // 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; + updated = true; } if (controller->pae_nw_info_set) { - controller->pae_nw_info_set(interface_ptr, pan_id, network_name); + controller->pae_nw_info_set(interface_ptr, pan_id, network_name, updated); } return 0; @@ -803,7 +807,7 @@ 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; + controller->pae_nw_info_set = ws_pae_supp_nw_info_set; 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); diff --git a/source/6LoWPAN/ws/ws_pae_supp.c b/source/6LoWPAN/ws/ws_pae_supp.c index a2cc896408d1..676e9de74f53 100644 --- a/source/6LoWPAN/ws/ws_pae_supp.c +++ b/source/6LoWPAN/ws/ws_pae_supp.c @@ -524,6 +524,31 @@ static int8_t ws_pae_supp_nw_keys_valid_check(pae_supp_t *pae_supp, uint16_t pan } } +int8_t ws_pae_supp_nw_info_set(protocol_interface_info_entry_t *interface_ptr, uint16_t pan_id, char *network_name, bool updated) +{ + (void) pan_id; + (void) network_name; + + pae_supp_t *pae_supp = ws_pae_supp_get(interface_ptr); + if (!pae_supp) { + return -1; + } + + if (updated) { + tr_info("Delete old keys, new PAN ID: %i network name: %s", pan_id, network_name); + // Delete pair wise keys + 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); + // 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); + ws_pae_supp_nvm_update(pae_supp); + } + + return 0; +} + 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); diff --git a/source/6LoWPAN/ws/ws_pae_supp.h b/source/6LoWPAN/ws/ws_pae_supp.h index 7bd20170616a..33174954a77a 100644 --- a/source/6LoWPAN/ws/ws_pae_supp.h +++ b/source/6LoWPAN/ws/ws_pae_supp.h @@ -173,6 +173,20 @@ int8_t ws_pae_supp_gtks_set(protocol_interface_info_entry_t *interface_ptr, sec_ */ int8_t ws_pae_supp_eapol_target_remove(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 + * \param updated data has been updated + * + * \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, bool updated); + /** * ws_pae_supp_nw_key_index_set network send key index set callback * From 9a10d66add88ffcf3b7da234afaebc1c100d9dd3 Mon Sep 17 00:00:00 2001 From: Arto Kinnunen Date: Wed, 24 Jun 2020 15:11:53 +0300 Subject: [PATCH 06/30] Fix global address detection (#2392) Detect global address availability when DAD is completed. The new address is not yet in the ip_addresses list and therefore detecting address scope by looping the IP addresses does not work here. --- source/6LoWPAN/ws/ws_bootstrap.c | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/source/6LoWPAN/ws/ws_bootstrap.c b/source/6LoWPAN/ws/ws_bootstrap.c index 9e2d23146a9e..741914ab703b 100644 --- a/source/6LoWPAN/ws/ws_bootstrap.c +++ b/source/6LoWPAN/ws/ws_bootstrap.c @@ -76,7 +76,6 @@ #define TRACE_GROUP "wsbs" - static void ws_bootstrap_event_handler(arm_event_s *event); static void ws_bootstrap_state_change(protocol_interface_info_entry_t *cur, icmp_state_t nwk_bootstrap_state); static bool ws_bootstrap_state_discovery(struct protocol_interface_info_entry *cur); @@ -221,11 +220,11 @@ static void ws_address_reregister_trig(struct protocol_interface_info_entry *int static void ws_bootstrap_address_notification_cb(struct protocol_interface_info_entry *interface, const struct if_address_entry *addr, if_address_callback_t reason) { - /* No need for LL address registration */ if (addr->source == ADDR_SOURCE_UNKNOWN || !interface->ws_info) { return; } + if (reason == ADDR_CALLBACK_DAD_COMPLETE) { //If address is generated manually we need to force registration if (addr->source != ADDR_SOURCE_DHCP) { @@ -235,7 +234,10 @@ static void ws_bootstrap_address_notification_cb(struct protocol_interface_info_ ws_address_registration_update(interface, addr->address); } ws_address_reregister_trig(interface); - + } + if (addr_ipv6_scope(addr->address, interface) > IPV6_SCOPE_LINK_LOCAL) { + // at least ula address available inside mesh. + interface->global_address_available = true; } } else if (reason == ADDR_CALLBACK_DELETED) { // What to do? @@ -248,17 +250,17 @@ static void ws_bootstrap_address_notification_cb(struct protocol_interface_info_ } //Discover prefix policy addr_policy_remove_by_label(WS_NON_PREFFRED_LABEL); - } - // Check the Address status if we have global address available. - interface->global_address_available = false; - ns_list_foreach(if_address_entry_t, addr_str, &interface->ip_addresses) { - if (addr_ipv6_scope(addr_str->address, interface) > IPV6_SCOPE_LINK_LOCAL) { - // at least ula address available inside mesh. - interface->global_address_available = true; - break; + interface->global_address_available = false; + ns_list_foreach(if_address_entry_t, addr_str, &interface->ip_addresses) { + if (addr_ipv6_scope(addr_str->address, interface) > IPV6_SCOPE_LINK_LOCAL) { + // at least ula address available inside mesh. + interface->global_address_available = true; + break; + } } } + // Addressing in Wi-SUN interface was changed for Border router send new event so Application can update the state if (interface->bootsrap_mode == ARM_NWK_BOOTSRAP_MODE_6LoWPAN_BORDER_ROUTER && interface->nwk_bootstrap_state == ER_BOOTSRAP_DONE) { From 841dcbeccb7dc845647e6d4752612f3e3a2b8dcd Mon Sep 17 00:00:00 2001 From: Jarkko Paso Date: Fri, 26 Jun 2020 09:54:42 +0300 Subject: [PATCH 07/30] MAC: Configurable data whitening (#2393) --- nanostack/mlme.h | 1 + nanostack/platform/arm_hal_phy.h | 1 + source/MAC/IEEE802_15_4/mac_mlme.c | 5 +++++ 3 files changed, 7 insertions(+) diff --git a/nanostack/mlme.h b/nanostack/mlme.h index 841f097cb663..3a4e02d57949 100644 --- a/nanostack/mlme.h +++ b/nanostack/mlme.h @@ -264,6 +264,7 @@ typedef enum { macAutoRequestKeyIndex = 0x7b, /*coord_long_address, set_req->value_pointer, 8); } return 0; + case macSetDataWhitening: + pu8 = (uint8_t *) set_req->value_pointer; + rf_mac_setup->dev_driver->phy_driver->extension(PHY_EXTENSION_SET_DATA_WHITENING, pu8); + tr_debug("%s data whitening", *pu8 == (bool) true ? "Enable" : "Disable"); + 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)); From 1c263fd54eb43287bec1b643570c207d249a8daf Mon Sep 17 00:00:00 2001 From: Juha Heiskanen Date: Wed, 8 Jul 2020 17:26:39 +0300 Subject: [PATCH 08/30] FHSS exclude channel usage from mask and Brazilian Domain support Add support for regulator domain based exluded channel to Brazil. Fix Barzilian domain that it not advertise excluded channels. FHHS system select active channel from list add support for excluded channel usage in real network. --- source/6LoWPAN/ws/ws_bootstrap.c | 19 +++++++--- source/6LoWPAN/ws/ws_common.c | 12 +++++++ source/6LoWPAN/ws/ws_common.h | 2 ++ source/6LoWPAN/ws/ws_llc_data_service.c | 4 +-- source/6LoWPAN/ws/ws_neighbor_class.c | 35 +++++-------------- source/6LoWPAN/ws/ws_neighbor_class.h | 2 +- source/Service_Libs/fhss/fhss_ws.c | 27 ++++++++++++-- test/nanostack/unittest/stub/ws_common_stub.c | 4 +++ .../unittest/stub/ws_neighbour_class_stub.c | 2 +- 9 files changed, 70 insertions(+), 37 deletions(-) diff --git a/source/6LoWPAN/ws/ws_bootstrap.c b/source/6LoWPAN/ws/ws_bootstrap.c index 741914ab703b..3be7465c747a 100644 --- a/source/6LoWPAN/ws/ws_bootstrap.c +++ b/source/6LoWPAN/ws/ws_bootstrap.c @@ -493,7 +493,7 @@ static void ws_bootstrap_llc_hopping_update(struct protocol_interface_info_entry cur->ws_info->hopping_schdule.fhss_bsi = fhss_configuration->bsi; } -static uint8_t ws_generate_exluded_channel_list_from_active_channels(ws_excluded_channel_data_t *excluded_data, const uint32_t *selected_channel_mask, uint16_t number_of_channels) +static uint8_t ws_generate_exluded_channel_list_from_active_channels(ws_excluded_channel_data_t *excluded_data, const uint32_t *selected_channel_mask, const uint32_t *global_channel_mask, uint16_t number_of_channels) { bool active_range = false; @@ -501,6 +501,15 @@ static uint8_t ws_generate_exluded_channel_list_from_active_channels(ws_excluded memset(excluded_data, 0, sizeof(ws_excluded_channel_data_t)); for (uint8_t i = 0; i < number_of_channels; i++) { + if (!(global_channel_mask[0 + (i / 32)] & (1 << (i % 32)))) { + //Global exluded channel + if (active_range) { + //Mark range stop here + active_range = false; + } + continue; + } + if (selected_channel_mask[0 + (i / 32)] & (1 << (i % 32))) { if (active_range) { //Mark range stop here @@ -556,7 +565,7 @@ static void ws_fhss_configure_channel_masks(protocol_interface_info_entry_t *cur fhss_configuration->unicast_channel_mask[n] &= cur->ws_info->cfg->fhss.fhss_channel_mask[n]; } //Update Exluded channels - cur->ws_info->hopping_schdule.channel_plan = ws_generate_exluded_channel_list_from_active_channels(&cur->ws_info->hopping_schdule.excluded_channels, fhss_configuration->unicast_channel_mask, cur->ws_info->hopping_schdule.number_of_channels); + cur->ws_info->hopping_schdule.channel_plan = ws_generate_exluded_channel_list_from_active_channels(&cur->ws_info->hopping_schdule.excluded_channels, fhss_configuration->unicast_channel_mask, fhss_configuration->channel_mask, cur->ws_info->hopping_schdule.number_of_channels); } static int8_t ws_fhss_initialize(protocol_interface_info_entry_t *cur) @@ -1431,7 +1440,7 @@ static void ws_bootstrap_pan_config_analyse(struct protocol_interface_info_entry 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); + ws_neighbor_class_neighbor_unicast_schedule_set(neighbor_info.ws_neighbor, ws_us, &cur->ws_info->hopping_schdule); ws_neighbor_class_neighbor_broadcast_time_info_update(neighbor_info.ws_neighbor, &ws_bt_ie, data->timestamp); ws_neighbor_class_neighbor_broadcast_schedule_set(neighbor_info.ws_neighbor, &ws_bs_ie); } @@ -1515,7 +1524,7 @@ static void ws_bootstrap_pan_config_solicit_analyse(struct protocol_interface_in 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, 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); + ws_neighbor_class_neighbor_unicast_schedule_set(neighbor_info.ws_neighbor, ws_us, &cur->ws_info->hopping_schdule); } @@ -3180,7 +3189,7 @@ static int8_t ws_bootstrap_neighbor_set(protocol_interface_info_entry_t *cur, pa } 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); + ws_neighbor_class_neighbor_unicast_schedule_set(neighbor_info.ws_neighbor, &parent_ptr->ws_us, &cur->ws_info->hopping_schdule); return 0; } diff --git a/source/6LoWPAN/ws/ws_common.c b/source/6LoWPAN/ws/ws_common.c index 010f6c14ac37..02b54ff6b092 100644 --- a/source/6LoWPAN/ws/ws_common.c +++ b/source/6LoWPAN/ws/ws_common.c @@ -81,6 +81,18 @@ int8_t ws_generate_channel_list(uint32_t *channel_mask, uint16_t number_of_chann return 0; } +uint16_t ws_active_channel_count(uint32_t *channel_mask, uint16_t number_of_channels) +{ + uint16_t active_channels = 0; + // Set channel maks outside excluded channels + for (uint16_t i = 0; i < number_of_channels; i++) { + if (channel_mask[0 + (i / 32)] & (1 << (i % 32))) { + active_channels++; + } + } + return active_channels; +} + uint32_t ws_decode_channel_spacing(uint8_t channel_spacing) { if (CHANNEL_SPACING_100 == channel_spacing) { diff --git a/source/6LoWPAN/ws/ws_common.h b/source/6LoWPAN/ws/ws_common.h index 08d726ee6b14..a3d1eae85f8d 100644 --- a/source/6LoWPAN/ws/ws_common.h +++ b/source/6LoWPAN/ws/ws_common.h @@ -115,6 +115,8 @@ typedef struct ws_info_s { int8_t ws_generate_channel_list(uint32_t *channel_mask, uint16_t number_of_channels, uint8_t regulatory_domain, uint8_t operating_class); +uint16_t ws_active_channel_count(uint32_t *channel_mask, uint16_t number_of_channels); + uint32_t ws_decode_channel_spacing(uint8_t channel_spacing); uint32_t ws_get_datarate_using_operating_mode(uint8_t operating_mode); diff --git a/source/6LoWPAN/ws/ws_llc_data_service.c b/source/6LoWPAN/ws/ws_llc_data_service.c index 73f468a27ca2..1b1b530f0983 100644 --- a/source/6LoWPAN/ws/ws_llc_data_service.c +++ b/source/6LoWPAN/ws/ws_llc_data_service.c @@ -655,7 +655,7 @@ static void ws_llc_data_indication_cb(const mac_api_t *api, const mcps_data_ind_ 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); + ws_neighbor_class_neighbor_unicast_schedule_set(neighbor_info.ws_neighbor, &us_ie, &interface->ws_info->hopping_schdule); } //Update BS if it is part of message if (bs_ie_inline) { @@ -755,7 +755,7 @@ static void ws_llc_eapol_indication_cb(const mac_api_t *api, const mcps_data_ind 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); + ws_neighbor_class_neighbor_unicast_schedule_set(neighbor_info.ws_neighbor, &us_ie, &interface->ws_info->hopping_schdule); } //Update BS if it is part of message if (bs_ie_inline) { diff --git a/source/6LoWPAN/ws/ws_neighbor_class.c b/source/6LoWPAN/ws/ws_neighbor_class.c index 214c46f871f0..eedb016240d1 100644 --- a/source/6LoWPAN/ws/ws_neighbor_class.c +++ b/source/6LoWPAN/ws/ws_neighbor_class.c @@ -95,28 +95,6 @@ void ws_neighbor_class_neighbor_unicast_time_info_update(ws_neighbor_class_entry ws_neighbor->fhss_data.uc_timing_info.ufsi = ws_utt->ufsi; } -static void ws_neighbour_channel_list_enable_all(ws_channel_mask_t *channel_info, uint16_t number_of_channels) -{ - uint32_t mask; - channel_info->channel_count = number_of_channels; - for (uint8_t n = 0; n < 8; n++) { - if (number_of_channels >= 32) { - mask = 0xffffffff; - number_of_channels -= 32; - } else if (number_of_channels) { - mask = 0; - //Start bit enable to MSB - for (uint16_t i = 0; i < (number_of_channels % 32); i++) { - mask |= 1 << i; - } - number_of_channels = 0; - } else { - mask = 0; - } - channel_info->channel_mask[n] = mask; - } -} - static void ws_neighbour_excluded_mask_by_range(ws_channel_mask_t *channel_info, ws_excluded_channel_range_t *range_info, uint16_t number_of_channels) { uint16_t range_start, range_stop; @@ -210,29 +188,34 @@ static void ws_neighbour_excluded_mask_by_mask(ws_channel_mask_t *channel_info, } } -void ws_neighbor_class_neighbor_unicast_schedule_set(ws_neighbor_class_entry_t *ws_neighbor, ws_us_ie_t *ws_us) +void ws_neighbor_class_neighbor_unicast_schedule_set(ws_neighbor_class_entry_t *ws_neighbor, ws_us_ie_t *ws_us, ws_hopping_schedule_t *own_shedule) { ws_neighbor->fhss_data.uc_timing_info.unicast_channel_function = ws_us->channel_function; if (ws_us->channel_function == WS_FIXED_CHANNEL) { ws_neighbor->fhss_data.uc_timing_info.fixed_channel = ws_us->function.zero.fixed_channel; ws_neighbor->fhss_data.uc_timing_info.unicast_number_of_channels = 1; } else { + if (ws_us->channel_plan == 0) { ws_neighbor->fhss_data.uc_timing_info.unicast_number_of_channels = ws_common_channel_number_calc(ws_us->plan.zero.regulator_domain, ws_us->plan.zero.operation_class); } else if (ws_us->channel_plan == 1) { ws_neighbor->fhss_data.uc_timing_info.unicast_number_of_channels = ws_us->plan.one.number_of_channel; + } //Handle excluded channel and generate activate channel list if (ws_us->excluded_channel_ctrl == WS_EXC_CHAN_CTRL_RANGE) { - ws_neighbour_channel_list_enable_all(&ws_neighbor->fhss_data.uc_channel_list, ws_neighbor->fhss_data.uc_timing_info.unicast_number_of_channels); + ws_generate_channel_list(ws_neighbor->fhss_data.uc_channel_list.channel_mask, ws_neighbor->fhss_data.uc_timing_info.unicast_number_of_channels, own_shedule->regulatory_domain, own_shedule->operating_class); + ws_neighbor->fhss_data.uc_channel_list.channel_count = ws_active_channel_count(ws_neighbor->fhss_data.uc_channel_list.channel_mask, ws_neighbor->fhss_data.uc_timing_info.unicast_number_of_channels); ws_neighbour_excluded_mask_by_range(&ws_neighbor->fhss_data.uc_channel_list, &ws_us->excluded_channels.range, ws_neighbor->fhss_data.uc_timing_info.unicast_number_of_channels); } else if (ws_us->excluded_channel_ctrl == WS_EXC_CHAN_CTRL_BITMASK) { - ws_neighbour_channel_list_enable_all(&ws_neighbor->fhss_data.uc_channel_list, ws_neighbor->fhss_data.uc_timing_info.unicast_number_of_channels); + ws_generate_channel_list(ws_neighbor->fhss_data.uc_channel_list.channel_mask, ws_neighbor->fhss_data.uc_timing_info.unicast_number_of_channels, own_shedule->regulatory_domain, own_shedule->operating_class); + ws_neighbor->fhss_data.uc_channel_list.channel_count = ws_active_channel_count(ws_neighbor->fhss_data.uc_channel_list.channel_mask, ws_neighbor->fhss_data.uc_timing_info.unicast_number_of_channels); ws_neighbour_excluded_mask_by_mask(&ws_neighbor->fhss_data.uc_channel_list, &ws_us->excluded_channels.mask, ws_neighbor->fhss_data.uc_timing_info.unicast_number_of_channels); } else if (ws_us->excluded_channel_ctrl == WS_EXC_CHAN_CTRL_NONE) { if (ws_neighbor->fhss_data.uc_timing_info.unicast_number_of_channels != ws_neighbor->fhss_data.uc_channel_list.channel_count) { - ws_neighbour_channel_list_enable_all(&ws_neighbor->fhss_data.uc_channel_list, ws_neighbor->fhss_data.uc_timing_info.unicast_number_of_channels); + ws_generate_channel_list(ws_neighbor->fhss_data.uc_channel_list.channel_mask, ws_neighbor->fhss_data.uc_timing_info.unicast_number_of_channels, own_shedule->regulatory_domain, own_shedule->operating_class); + ws_neighbor->fhss_data.uc_channel_list.channel_count = ws_active_channel_count(ws_neighbor->fhss_data.uc_channel_list.channel_mask, ws_neighbor->fhss_data.uc_timing_info.unicast_number_of_channels); } } diff --git a/source/6LoWPAN/ws/ws_neighbor_class.h b/source/6LoWPAN/ws/ws_neighbor_class.h index f470a25a8b07..e1ebf0482327 100644 --- a/source/6LoWPAN/ws/ws_neighbor_class.h +++ b/source/6LoWPAN/ws/ws_neighbor_class.h @@ -115,7 +115,7 @@ void ws_neighbor_class_neighbor_unicast_time_info_update(ws_neighbor_class_entry * \param ws_us Unicast schedule IE data * */ -void ws_neighbor_class_neighbor_unicast_schedule_set(ws_neighbor_class_entry_t *ws_neighbor, ws_us_ie_t *ws_us); +void ws_neighbor_class_neighbor_unicast_schedule_set(ws_neighbor_class_entry_t *ws_neighbor, ws_us_ie_t *ws_us, ws_hopping_schedule_t *own_shedule); /** diff --git a/source/Service_Libs/fhss/fhss_ws.c b/source/Service_Libs/fhss/fhss_ws.c index 80c3f90d149a..5ccaa6ce6500 100644 --- a/source/Service_Libs/fhss/fhss_ws.c +++ b/source/Service_Libs/fhss/fhss_ws.c @@ -83,6 +83,7 @@ static void fhss_event_timer_cb(int8_t timer_id, uint16_t slots); static void fhss_ws_update_uc_channel_callback(fhss_structure_t *fhss_structure); static void fhss_unicast_handler(const fhss_api_t *fhss_api, uint16_t delay); static bool fhss_ws_check_tx_allowed(fhss_structure_t *fhss_structure); +static int32_t fhss_channel_index_from_mask(const uint32_t *channel_mask, int32_t channel_index, uint16_t number_of_channels); // This function supports rounding up static int64_t divide_integer(int64_t dividend, int32_t divisor) @@ -235,12 +236,14 @@ static int32_t fhss_ws_calc_bc_channel(fhss_structure_t *fhss_structure) if (fhss_structure->ws->fhss_configuration.ws_bc_channel_function == WS_TR51CF) { next_channel = tr51_get_bc_channel_index(fhss_structure->ws->tr51_channel_table, fhss_structure->ws->tr51_output_table, fhss_structure->ws->bc_slot, fhss_structure->ws->fhss_configuration.bsi, fhss_structure->number_of_channels, NULL); + next_channel = fhss_channel_index_from_mask(fhss_structure->ws->fhss_configuration.channel_mask, next_channel, fhss_structure->number_of_channels); if (++fhss_structure->ws->bc_slot == fhss_structure->number_of_channels) { fhss_structure->ws->bc_slot = 0; } } else if (fhss_structure->ws->fhss_configuration.ws_bc_channel_function == WS_DH1CF) { fhss_structure->ws->bc_slot++; next_channel = dh1cf_get_bc_channel_index(fhss_structure->ws->bc_slot, fhss_structure->ws->fhss_configuration.bsi, fhss_structure->number_of_channels); + next_channel = fhss_channel_index_from_mask(fhss_structure->ws->fhss_configuration.channel_mask, next_channel, fhss_structure->number_of_channels); } else if (fhss_structure->ws->fhss_configuration.ws_bc_channel_function == WS_VENDOR_DEF_CF) { if (fhss_structure->ws->fhss_configuration.vendor_defined_cf) { next_channel = fhss_structure->ws->fhss_configuration.vendor_defined_cf(fhss_structure->fhss_api, fhss_structure->ws->bc_slot, NULL, fhss_structure->ws->fhss_configuration.bsi, fhss_structure->number_of_channels); @@ -264,6 +267,22 @@ static uint8_t calc_own_tx_trig_slot(uint8_t own_hop) return (own_hop & 1); } +static int32_t fhss_channel_index_from_mask(const uint32_t *channel_mask, int32_t channel_index, uint16_t number_of_channels) +{ + //Function will return real active channel index at list + int32_t active_channels = 0; + // Set channel maks outside excluded channels + for (int32_t i = 0; i < number_of_channels; i++) { + if (channel_mask[0 + (i / 32)] & (1 << (i % 32))) { + if (channel_index == active_channels) { + return i; + } + active_channels++; + } + } + return 0; +} + static void fhss_broadcast_handler(const fhss_api_t *fhss_api, uint16_t delay) { int32_t next_channel; @@ -477,12 +496,14 @@ static void fhss_ws_update_uc_channel_callback(fhss_structure_t *fhss_structure) if (fhss_structure->ws->fhss_configuration.ws_uc_channel_function == WS_FIXED_CHANNEL) { return; } else if (fhss_structure->ws->fhss_configuration.ws_uc_channel_function == WS_TR51CF) { - next_channel = fhss_structure->rx_channel = tr51_get_uc_channel_index(fhss_structure->ws->tr51_channel_table, fhss_structure->ws->tr51_output_table, fhss_structure->ws->uc_slot, mac_address, fhss_structure->number_of_uc_channels, NULL); + next_channel = tr51_get_uc_channel_index(fhss_structure->ws->tr51_channel_table, fhss_structure->ws->tr51_output_table, fhss_structure->ws->uc_slot, mac_address, fhss_structure->number_of_uc_channels, NULL); + next_channel = fhss_structure->rx_channel = fhss_channel_index_from_mask(fhss_structure->ws->fhss_configuration.unicast_channel_mask, next_channel, fhss_structure->number_of_channels); if (++fhss_structure->ws->uc_slot == fhss_structure->number_of_uc_channels) { fhss_structure->ws->uc_slot = 0; } } else if (fhss_structure->ws->fhss_configuration.ws_uc_channel_function == WS_DH1CF) { - next_channel = fhss_structure->rx_channel = dh1cf_get_uc_channel_index(fhss_structure->ws->uc_slot, mac_address, fhss_structure->number_of_uc_channels); + next_channel = dh1cf_get_uc_channel_index(fhss_structure->ws->uc_slot, mac_address, fhss_structure->number_of_uc_channels); + next_channel = fhss_structure->rx_channel = fhss_channel_index_from_mask(fhss_structure->ws->fhss_configuration.unicast_channel_mask, next_channel, fhss_structure->number_of_channels); fhss_structure->ws->uc_slot++; } else if (fhss_structure->ws->fhss_configuration.ws_uc_channel_function == WS_VENDOR_DEF_CF) { if (fhss_structure->ws->fhss_configuration.vendor_defined_cf) { @@ -540,8 +561,10 @@ static int fhss_ws_tx_handle_callback(const fhss_api_t *api, bool is_broadcast_a int32_t tx_channel = neighbor_timing_info->uc_timing_info.fixed_channel; if (neighbor_timing_info->uc_timing_info.unicast_channel_function == WS_TR51CF) { tx_channel = tr51_get_uc_channel_index(fhss_structure->ws->tr51_channel_table, fhss_structure->ws->tr51_output_table, destination_slot, destination_address, neighbor_timing_info->uc_timing_info.unicast_number_of_channels, NULL); + tx_channel = fhss_channel_index_from_mask(neighbor_timing_info->uc_channel_list.channel_mask, tx_channel, fhss_structure->number_of_channels); } else if (neighbor_timing_info->uc_timing_info.unicast_channel_function == WS_DH1CF) { tx_channel = dh1cf_get_uc_channel_index(destination_slot, destination_address, neighbor_timing_info->uc_channel_list.channel_count); + tx_channel = fhss_channel_index_from_mask(neighbor_timing_info->uc_channel_list.channel_mask, tx_channel, fhss_structure->number_of_channels); } else if (neighbor_timing_info->uc_timing_info.unicast_channel_function == WS_VENDOR_DEF_CF) { if (fhss_structure->ws->fhss_configuration.vendor_defined_cf) { tx_channel = fhss_structure->ws->fhss_configuration.vendor_defined_cf(fhss_structure->fhss_api, fhss_structure->ws->bc_slot, destination_address, fhss_structure->ws->fhss_configuration.bsi, neighbor_timing_info->uc_timing_info.unicast_number_of_channels); diff --git a/test/nanostack/unittest/stub/ws_common_stub.c b/test/nanostack/unittest/stub/ws_common_stub.c index d974bbf8e0eb..e5cf8f5aa291 100644 --- a/test/nanostack/unittest/stub/ws_common_stub.c +++ b/test/nanostack/unittest/stub/ws_common_stub.c @@ -98,3 +98,7 @@ uint32_t ws_common_network_size_estimate_get(protocol_interface_info_entry_t *cu return 0; } +uint16_t ws_active_channel_count(uint32_t *channel_mask, uint16_t number_of_channels) +{ + return 35; +} diff --git a/test/nanostack/unittest/stub/ws_neighbour_class_stub.c b/test/nanostack/unittest/stub/ws_neighbour_class_stub.c index 1ed3135e384b..3425f78b4f32 100644 --- a/test/nanostack/unittest/stub/ws_neighbour_class_stub.c +++ b/test/nanostack/unittest/stub/ws_neighbour_class_stub.c @@ -74,7 +74,7 @@ void ws_neighbor_class_neighbor_unicast_time_info_update(ws_neighbor_class_entry } -void ws_neighbor_class_neighbor_unicast_schedule_set(ws_neighbor_class_entry_t *ws_neighbor, ws_us_ie_t *ws_us) +void ws_neighbor_class_neighbor_unicast_schedule_set(ws_neighbor_class_entry_t *ws_neighbor, ws_us_ie_t *ws_us, ws_hopping_schedule_t *own_shedule) { } From bf8e89e0b765188bb16ffc01776630841bc9fa6a Mon Sep 17 00:00:00 2001 From: Arto Kinnunen Date: Tue, 14 Jul 2020 09:11:07 +0300 Subject: [PATCH 09/30] Ignore neighbors using unsupported channel function (#2395) Nodes do not support Vendor specific channel function. Ignore potential neighbors which do not support node's channel function. --- source/6LoWPAN/ws/ws_bootstrap.c | 25 +++++++++++++++++-- source/6LoWPAN/ws/ws_bootstrap.h | 3 +++ source/6LoWPAN/ws/ws_llc_data_service.c | 20 ++++++++++++--- .../unittest/stub/ws_bootstrap_stub.c | 5 ++++ 4 files changed, 47 insertions(+), 6 deletions(-) diff --git a/source/6LoWPAN/ws/ws_bootstrap.c b/source/6LoWPAN/ws/ws_bootstrap.c index 3be7465c747a..e14746fe738c 100644 --- a/source/6LoWPAN/ws/ws_bootstrap.c +++ b/source/6LoWPAN/ws/ws_bootstrap.c @@ -156,7 +156,7 @@ static void ws_bootstap_eapol_neigh_entry_allocate(struct protocol_interface_inf 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); + mac_neighbor_table_entry_t *mac_entry = ws_bootstrap_mac_neighbor_add(interface, mac_64); if (!mac_entry) { return; @@ -1580,6 +1580,26 @@ bool ws_bootstrap_validate_channel_plan(ws_us_ie_t *ws_us, struct protocol_inter return true; } +bool ws_bootstrap_validate_channel_function(ws_us_ie_t *ws_us, ws_bs_ie_t *ws_bs) +{ + if (ws_us) { + if (ws_us->channel_function != WS_FIXED_CHANNEL && + ws_us->channel_function != WS_TR51CF && + ws_us->channel_function != WS_DH1CF) { + return false; + } + } + + if (ws_bs) { + if (ws_bs->channel_function != WS_FIXED_CHANNEL && + ws_bs->channel_function != WS_TR51CF && + ws_bs->channel_function != WS_DH1CF) { + return false; + } + } + + return true; +} static void ws_bootstrap_asynch_ind(struct protocol_interface_info_entry *cur, const struct mcps_data_ind_s *data, const struct mcps_data_ie_list *ie_ext, uint8_t message_type) { @@ -1618,7 +1638,8 @@ static void ws_bootstrap_asynch_ind(struct protocol_interface_info_entry *cur, c return; } - if (!ws_bootstrap_validate_channel_plan(&ws_us, cur)) { + if (!ws_bootstrap_validate_channel_plan(&ws_us, cur) || + !ws_bootstrap_validate_channel_function(&ws_us, NULL)) { return; } diff --git a/source/6LoWPAN/ws/ws_bootstrap.h b/source/6LoWPAN/ws/ws_bootstrap.h index c9cdcd46b4d6..1a85e8150d13 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_bs_ie; struct ws_neighbor_class_entry; int ws_bootstrap_init(int8_t interface_id, net_6lowpan_mode_e bootstrap_mode); @@ -82,6 +83,8 @@ 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); +bool ws_bootstrap_validate_channel_function(struct ws_us_ie *ws_us, struct ws_bs_ie *ws_bs); + 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); diff --git a/source/6LoWPAN/ws/ws_llc_data_service.c b/source/6LoWPAN/ws/ws_llc_data_service.c index 1b1b530f0983..d5fbbe359c67 100644 --- a/source/6LoWPAN/ws/ws_llc_data_service.c +++ b/source/6LoWPAN/ws/ws_llc_data_service.c @@ -613,8 +613,14 @@ static void ws_llc_data_indication_cb(const mac_api_t *api, const mcps_data_ind_ protocol_interface_info_entry_t *interface = base->interface_ptr; //Validate Unicast shedule Channel Plan - if (us_ie_inline && !ws_bootstrap_validate_channel_plan(&us_ie, interface)) { - //Channel plan configuration mismatch + if (us_ie_inline && + (!ws_bootstrap_validate_channel_plan(&us_ie, interface) || + !ws_bootstrap_validate_channel_function(&us_ie, NULL))) { + //Channel plan or channel function configuration mismatch + return; + } + + if (bs_ie_inline && !ws_bootstrap_validate_channel_function(NULL, &ws_bs_ie)) { return; } @@ -730,8 +736,14 @@ static void ws_llc_eapol_indication_cb(const mac_api_t *api, const mcps_data_ind protocol_interface_info_entry_t *interface = base->interface_ptr; //Validate Unicast shedule Channel Plan - if (us_ie_inline && !ws_bootstrap_validate_channel_plan(&us_ie, interface)) { - //Channel plan configuration mismatch + if (us_ie_inline && + (!ws_bootstrap_validate_channel_plan(&us_ie, interface) || + !ws_bootstrap_validate_channel_function(&us_ie, NULL))) { + //Channel plan or channel function configuration mismatch + return; + } + + if (bs_ie_inline && !ws_bootstrap_validate_channel_function(NULL, &ws_bs_ie)) { return; } diff --git a/test/nanostack/unittest/stub/ws_bootstrap_stub.c b/test/nanostack/unittest/stub/ws_bootstrap_stub.c index eb8dfaa1ed1e..47bc15ee2721 100644 --- a/test/nanostack/unittest/stub/ws_bootstrap_stub.c +++ b/test/nanostack/unittest/stub/ws_bootstrap_stub.c @@ -131,6 +131,11 @@ bool ws_bootstrap_validate_channel_plan(ws_us_ie_t *ws_us, struct protocol_inter return true; } +bool ws_bootstrap_validate_channel_function(ws_us_ie_t *ws_us, ws_bs_ie_t *ws_bs) +{ + return true; +} + struct ws_neighbor_class_entry *ws_bootstrap_eapol_tx_temporary_set(struct protocol_interface_info_entry *interface, const uint8_t *src64) { return NULL; From e78787442486c39ae98af5c81a42c8dfd9957498 Mon Sep 17 00:00:00 2001 From: Arto Kinnunen Date: Wed, 15 Jul 2020 12:57:35 +0300 Subject: [PATCH 10/30] Init MAC MTU size based on driver MTU size (#2397) Initialise MAC MTU size based on driver MTU size. In simulator MTU size was not properly updated to adaptation_interface by using `mac802_15_4Mode` change as adaptation_interface was already created in `arm_nwk_interface_lowpan_init`. --- source/MAC/IEEE802_15_4/sw_mac.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/MAC/IEEE802_15_4/sw_mac.c b/source/MAC/IEEE802_15_4/sw_mac.c index 67e5884227f1..25e6e9fa508a 100644 --- a/source/MAC/IEEE802_15_4/sw_mac.c +++ b/source/MAC/IEEE802_15_4/sw_mac.c @@ -102,9 +102,9 @@ mac_api_t *ns_sw_mac_create(int8_t rf_driver_id, mac_description_storage_size_t // Set default MTU size to 127 unless it is too much for PHY driver if (driver->phy_driver->phy_MTU > MAC_IEEE_802_15_4_MAX_PHY_PACKET_SIZE) { - this->phyMTU = MAC_IEEE_802_15_4_MAX_PHY_PACKET_SIZE; - } else { this->phyMTU = driver->phy_driver->phy_MTU; + } else { + this->phyMTU = MAC_IEEE_802_15_4_MAX_PHY_PACKET_SIZE; } mac_store.setup = mac_mlme_data_base_allocate(mac_store.dev_driver->phy_driver->PHY_MAC, mac_store.dev_driver, storage_sizes, this->phyMTU); From 12830770e6e246e561938c8affc131f3447756f6 Mon Sep 17 00:00:00 2001 From: Arto Kinnunen Date: Wed, 15 Jul 2020 13:37:04 +0300 Subject: [PATCH 11/30] Test API to adjust 6LoWPAN fragmentation MTU size (#2398) Add test API to allow testing of 6LoWPAN fragmentation. --- nanostack/net_ws_test.h | 11 +++++++++++ source/6LoWPAN/MAC/mac_helper.c | 9 ++++++++- source/6LoWPAN/MAC/mac_helper.h | 1 + source/6LoWPAN/ws/ws_test_api.c | 20 +++++++++++++++++--- 4 files changed, 37 insertions(+), 4 deletions(-) diff --git a/nanostack/net_ws_test.h b/nanostack/net_ws_test.h index 186bb05efe43..088caaad75c7 100644 --- a/nanostack/net_ws_test.h +++ b/nanostack/net_ws_test.h @@ -167,6 +167,17 @@ int ws_test_gtk_time_settings_set( */ int ws_test_next_gtk_set(int8_t interface_id, uint8_t *gtk[4]); +/** + * Sets 6LoWPAN fragmentation MTU size to test fragmentation + * + * \param interface_id Network interface ID. + * \param mtu_size Size of 6LoWPAN MTU when fragmentation occurs. + * + * \return 0 Success + * \return <0 Failure + */ +int ws_test_6lowpan_fragmentation_mtu_size_set(int8_t interface_id, uint16_t mtu_size); + #ifdef __cplusplus } #endif diff --git a/source/6LoWPAN/MAC/mac_helper.c b/source/6LoWPAN/MAC/mac_helper.c index 9e9b5a266c69..3475f87df387 100644 --- a/source/6LoWPAN/MAC/mac_helper.c +++ b/source/6LoWPAN/MAC/mac_helper.c @@ -31,6 +31,8 @@ static const uint8_t mac_helper_default_key_source[8] = {0xff, 0, 0, 0, 0, 0, 0, 0}; +uint16_t test_6lowpan_fragmentation_mtu_size_override = 0; + static uint8_t mac_helper_header_security_aux_header_length(uint8_t keyIdmode); static uint8_t mac_helper_security_mic_length_get(uint8_t security_level); static void mac_helper_keytable_pairwise_descriptor_set(struct mac_api_s *api, const uint8_t *key, const uint8_t *mac64, uint8_t attribute_id); @@ -736,7 +738,11 @@ uint_fast16_t mac_helper_max_payload_size(protocol_interface_info_entry_t *cur, { uint16_t max; - max = cur->mac_api->phyMTU - frame_overhead; + if (test_6lowpan_fragmentation_mtu_size_override == 0) { + max = cur->mac_api->phyMTU - frame_overhead; + } else { + max = test_6lowpan_fragmentation_mtu_size_override - frame_overhead; + } /* But if we want IEEE 802.15.4-2003 compatibility (and it looks like a * standard PHY), limit ourselves to the 2003 maximum */ @@ -744,6 +750,7 @@ uint_fast16_t mac_helper_max_payload_size(protocol_interface_info_entry_t *cur, cur->mac_api->phyMTU == MAC_IEEE_802_15_4_MAX_PHY_PACKET_SIZE) { max = MAC_IEEE_802_15_4_MAX_MAC_SAFE_PAYLOAD_SIZE; } + return max; } diff --git a/source/6LoWPAN/MAC/mac_helper.h b/source/6LoWPAN/MAC/mac_helper.h index 6c68c6dc2f08..dbd5b13d647f 100644 --- a/source/6LoWPAN/MAC/mac_helper.h +++ b/source/6LoWPAN/MAC/mac_helper.h @@ -30,6 +30,7 @@ struct ns_sockaddr; struct buffer; struct mac_api_s; +extern uint16_t test_6lowpan_fragmentation_mtu_size_override; void mac_create_scan_request(mac_scan_type_t type, struct channel_list_s *chanlist, uint8_t scan_duration, struct mlme_scan_s *request); diff --git a/source/6LoWPAN/ws/ws_test_api.c b/source/6LoWPAN/ws/ws_test_api.c index 16f9c5926a35..2e7cc97259a5 100644 --- a/source/6LoWPAN/ws/ws_test_api.c +++ b/source/6LoWPAN/ws/ws_test_api.c @@ -18,12 +18,13 @@ #include "nsconfig.h" #include -#include -#include -#include +#include "ns_list.h" +#include "nsdynmemLIB.h" +#include "net_ws_test.h" #include "fhss_config.h" #include "ws_management_api.h" #include "mac_api.h" +#include "6LoWPAN/MAC/mac_helper.h" #include "NWK_INTERFACE/Include/protocol.h" #include "6LoWPAN/MAC/mac_helper.h" #include "6LoWPAN/ws/ws_config.h" @@ -150,4 +151,17 @@ int ws_test_next_gtk_set(int8_t interface_id, uint8_t *gtk[4]) return ws_pae_controller_next_gtk_update(interface_id, gtk); } +int ws_test_6lowpan_fragmentation_mtu_size_set(int8_t interface_id, uint16_t mtu_size) +{ + protocol_interface_info_entry_t *cur; + + cur = protocol_stack_interface_info_get_by_id(interface_id); + if (!cur || !ws_info(cur)) { + return -1; + } + + test_6lowpan_fragmentation_mtu_size_override = mtu_size; + return 0; +} + #endif // HAVE_WS From 6b58e26c302c8a4e095f4882b7d84512c756c79a Mon Sep 17 00:00:00 2001 From: Arto Kinnunen Date: Thu, 16 Jul 2020 10:41:47 +0300 Subject: [PATCH 12/30] Add EDFE mode to Socket API setsockopt Add option to enable/disable EDFE (Extended Directed Frame Exchange) frame exchange pattern to Socket API. Option name is SOCKET_EDFE_MODE and it is available in setsockopt method. --- nanostack/socket_api.h | 12 ++++++------ source/Core/include/ns_buffer.h | 1 + source/Core/include/ns_socket.h | 1 + source/Core/ns_socket.c | 3 +++ source/libNET/src/socket_api.c | 7 +++++++ 5 files changed, 18 insertions(+), 6 deletions(-) diff --git a/nanostack/socket_api.h b/nanostack/socket_api.h index 2fa9732522d5..aef48b3d1665 100644 --- a/nanostack/socket_api.h +++ b/nanostack/socket_api.h @@ -712,11 +712,12 @@ static inline int8_t socket_read_session_address(int8_t socket, ns_address_t *ad * | SOCKET_IPV6_MULTICAST_LOOP | bool | Yes | Yes | No | * | SOCKET_IPV6_JOIN_GROUP | ns_ipv6_mreq_t | Set only | No | No | * | SOCKET_IPV6_LEAVE_GROUP | ns_ipv6_mreq_t | Set only | No | No | + * | SOCKET_LATENCY | ns_ipv6_latency_t | Get only | No | No | + * | SOCKET_STAGGER | ns_ipv6_stagger_t | Get only | No | No | + * | SOCKET_EDFE_MODE | bool | Set only | No | No | * | SOCKET_BROADCAST_PAN | int8_t | Yes | No | No | * | SOCKET_LINK_LAYER_SECURITY | int8_t | Yes | No | No | * | SOCKET_INTERFACE_SELECT | int8_t | Yes | No | No | - * | SOCKET_LATENCY | ns_ipv6_latency_t | Get only | No | No | - * | SOCKET_STAGGER | ns_ipv6_stagger_t | Get only | No | No | * */ @@ -755,11 +756,10 @@ static inline int8_t socket_read_session_address(int8_t socket, ns_address_t *ad #define SOCKET_IPV6_JOIN_GROUP 15 /** Leave a multicast group, using ns_ipv6_mreq_t */ #define SOCKET_IPV6_LEAVE_GROUP 16 -/** Read estimated latency to reach destination */ -#define SOCKET_LATENCY 17 -/** Read estimated stagger value that can be used as initial delay after bootstrap or firmware update. */ -#define SOCKET_STAGGER 18 +#define SOCKET_LATENCY 0xf9 /**< Not standard, read estimated latency to reach destination */ +#define SOCKET_STAGGER 0xfa /**< Not standard, read estimated stagger value that can be used as initial delay after bootstrap or firmware update. */ +#define SOCKET_EDFE_MODE 0xfb /**< Not standard, Extended Directed Frame Exchange mode enabled/disabled in MAC layer */ #define SOCKET_BROADCAST_PAN 0xfc /**< Internal use - transmit with IEEE 802.15.4 broadcast PAN ID */ #define SOCKET_LINK_LAYER_SECURITY 0xfd /**< Not standard enable or disable socket security at link layer (For 802.15.4). */ #define SOCKET_INTERFACE_SELECT 0xfe /**< Not standard socket interface ID. */ diff --git a/source/Core/include/ns_buffer.h b/source/Core/include/ns_buffer.h index b33148a14d18..0168495ff2d9 100644 --- a/source/Core/include/ns_buffer.h +++ b/source/Core/include/ns_buffer.h @@ -124,6 +124,7 @@ typedef struct buffer_options { bool need_predecessor: 1; /*!< Used as an indicator that predecessor address needed */ bool multicast_loop: 1; /*!< We want loopback if we're a group member (TX), or this IS the loopback if RX */ bool mpl_permitted: 1; /*!< MPL will be used if enabled on interface and scope >=3 */ + bool edfe_mode: 1; /*!< Use Extended Directed Frame Exchange pattern in MAC layer */ #ifndef NO_IP_FRAGMENT_TX bool ipv6_dontfrag: 1; /*!< Don't IPv6 fragment (RFC 3542) */ #endif diff --git a/source/Core/include/ns_socket.h b/source/Core/include/ns_socket.h index 941c7403da0f..c4e6e638c27b 100644 --- a/source/Core/include/ns_socket.h +++ b/source/Core/include/ns_socket.h @@ -177,6 +177,7 @@ typedef struct inet_pcb_s { bool recvpktinfo: 1; bool recvhoplimit: 1; bool recvtclass: 1; + bool edfe_mode: 1; int_least24_t flow_label; NS_LIST_HEAD(inet_group_t, link) mc_groups; } inet_pcb_t; diff --git a/source/Core/ns_socket.c b/source/Core/ns_socket.c index e0fbffd724ef..bd919a99af82 100644 --- a/source/Core/ns_socket.c +++ b/source/Core/ns_socket.c @@ -401,6 +401,8 @@ inet_pcb_t *socket_inet_pcb_allocate(void) inet_pcb->recvhoplimit = false; inet_pcb->recvpktinfo = false; inet_pcb->recvtclass = false; + inet_pcb->edfe_mode = false; + inet_pcb->link_layer_security = -1; #ifndef NO_IPV6_PMTUD inet_pcb->use_min_mtu = -1; @@ -1134,6 +1136,7 @@ int16_t socket_buffer_sendmsg(int8_t sid, buffer_t *buf, const struct ns_msghdr buf->options.ipv6_use_min_mtu = inet_pcb->use_min_mtu; buf->options.ipv6_dontfrag = inet_pcb->dontfrag; buf->options.multicast_loop = inet_pcb->multicast_loop; + buf->options.edfe_mode = inet_pcb->edfe_mode; /* Set default remote address from PCB */ if (inet_pcb->remote_port != 0 && !addr_ipv6_equal(inet_pcb->remote_address, ns_in6addr_any)) { diff --git a/source/libNET/src/socket_api.c b/source/libNET/src/socket_api.c index 105c8579aa6d..d02df10121d0 100644 --- a/source/libNET/src/socket_api.c +++ b/source/libNET/src/socket_api.c @@ -960,6 +960,13 @@ static int8_t ipv6_setsockopt(socket_t *socket_ptr, uint8_t opt_name, const void inet_pcb->recvtclass = *(const bool *) opt_value; return 0; } + case SOCKET_EDFE_MODE: { + if (opt_len != sizeof(bool)) { + return -3; + } + inet_pcb->edfe_mode = *(const bool *) opt_value; + return 0; + } default: return -2; } From fed69e04d7238d9d4657aded10d7113d87863303 Mon Sep 17 00:00:00 2001 From: Arto Kinnunen Date: Thu, 16 Jul 2020 11:38:09 +0300 Subject: [PATCH 13/30] Add missing test method to ws_empty_functions Add ws_test_6lowpan_fragmentation_mtu_size_set to ws_empty_functions to get other configurations compiled. --- source/6LoWPAN/ws/ws_empty_functions.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/source/6LoWPAN/ws/ws_empty_functions.c b/source/6LoWPAN/ws/ws_empty_functions.c index f9e4e971955f..59c9a1650c9d 100644 --- a/source/6LoWPAN/ws/ws_empty_functions.c +++ b/source/6LoWPAN/ws/ws_empty_functions.c @@ -380,6 +380,14 @@ int ws_test_next_gtk_set(int8_t interface_id, uint8_t *gtk[4]) return -1; } +int ws_test_6lowpan_fragmentation_mtu_size_set(int8_t interface_id, uint16_t mtu_size) +{ + (void) interface_id; + (void) mtu_size; + + return -1; +} + int ws_statistics_start(int8_t interface_id, ws_statistics_t *stats_ptr) { (void) interface_id; From 85ab8fd3e19a36495e1c2d5a880fbf1544d1c8ca Mon Sep 17 00:00:00 2001 From: Juha Heiskanen Date: Wed, 15 Jul 2020 15:39:40 +0300 Subject: [PATCH 14/30] Extented Frame exchange support Added support send Extented frame exchange when MAC ack functionality is disabled and mac user handle those. MAC-API have new API for enable new feature and add Callback for detect Extented Data flow packet and send responses. MAC support only 1 active EDFE Data request. Wi-sun DSN duplicate check is disabled for EFDE frames. Wi-sun EFDE TX process do allways full handshake which not add data to initial frame. Fix unit test's. --- nanostack/mac_api.h | 20 +- nanostack/mac_mcps.h | 28 +++ source/6LoWPAN/adaptation_interface.c | 1 + source/6LoWPAN/ws/ws_common_defines.h | 7 + source/6LoWPAN/ws/ws_ie_lib.c | 20 +- source/6LoWPAN/ws/ws_ie_lib.h | 4 +- source/6LoWPAN/ws/ws_llc_data_service.c | 132 +++++++++- source/MAC/IEEE802_15_4/mac_data_buffer.h | 2 + source/MAC/IEEE802_15_4/mac_defines.h | 23 ++ source/MAC/IEEE802_15_4/mac_fhss_callbacks.c | 7 + source/MAC/IEEE802_15_4/mac_mcps_sap.c | 235 ++++++++++++++++-- source/MAC/IEEE802_15_4/mac_mcps_sap.h | 5 + source/MAC/IEEE802_15_4/mac_mlme.c | 1 + source/MAC/IEEE802_15_4/mac_pd_sap.c | 123 ++++++++- source/MAC/IEEE802_15_4/sw_mac.c | 30 +++ .../6LoWPAN/ws_ie_lib/test_ws_ie_lib.c | 7 +- .../test_ws_llc_data_service.c | 10 + .../unittest/mac/mac_pd_sap/Makefile | 3 +- .../unittest/stub/6lowpan_mesh_stub.c | 2 + .../unittest/stub/mac_mcps_sap_stub.c | 10 + test/nanostack/unittest/stub/ws_ie_lib_stub.c | 9 +- 21 files changed, 635 insertions(+), 44 deletions(-) diff --git a/nanostack/mac_api.h b/nanostack/mac_api.h index 1de9dbc27658..a972554b92b9 100644 --- a/nanostack/mac_api.h +++ b/nanostack/mac_api.h @@ -183,6 +183,14 @@ typedef void mcps_data_indication_ext(const mac_api_t *api, const mcps_data_ind_ typedef void mcps_ack_data_req_ext(const mac_api_t *api, mcps_ack_data_payload_t *data, int8_t rssi, uint8_t lqi); +/** + * @brief mcps_edfe_handler Callback for handle and detect edfe frame + * @param api The API which handled the response + * @param response_message Enhanced message response data and status + */ +typedef void mcps_edfe_handler(const mac_api_t *api, mcps_edfe_response_t *response_message); + + /** * @brief mcps_purge_confirm MCPS-PURGE confirm is called as a response to MCPS-PURGE request * @param api The API which handled the request @@ -254,6 +262,15 @@ typedef int8_t mac_api_enable_mcps_ext(mac_api_t *api, mcps_data_confirm_ext *data_cnf_cb, mcps_ack_data_req_ext *ack_data_req_cb); +/** + * @brief mac_api_enable_mcps_edfe_ext Initialises MAC 2015 extension for EDFE handler callbacks must be non-NULL. + * @param api mac_api_t pointer, which is created by application. + * @param edfe_ind_cb Upper layer function to handle and detect EDFE's + * @return -1 if error, -2 if OOM, 0 otherwise + */ +typedef int8_t mac_api_enable_mcps_edfe_ext(mac_api_t *api, + mcps_edfe_handler *edfe_ind_cb); + /** * \brief Struct mac_api_s defines functions for two-way communications between external MAC and Upper layer. * Application creates mac_api_t object by calling external MAC's creator function. @@ -263,17 +280,18 @@ typedef int8_t mac_api_enable_mcps_ext(mac_api_t *api, struct mac_api_s { mac_api_initialize *mac_initialize; /**< MAC initialize function to use */ mac_api_enable_mcps_ext *mac_mcps_extension_enable; /**< MAC MCPS IE extension enable function, optional feature */ + mac_api_enable_mcps_edfe_ext *mac_mcps_edfe_enable; /**< MAC MCPS MCPS EDFE frame extension enable function, optional feature */ //External MAC callbacks mlme_request *mlme_req; /**< MAC MLME request function to use */ mcps_data_request *mcps_data_req; /**< MAC MCPS data request function to use */ mcps_data_request_ext *mcps_data_req_ext; /**< MAC MCPS data request with Information element extension function to use */ mcps_purge_request *mcps_purge_req; /**< MAC MCPS purge request function to use */ - //Upper layer callbacksMLME_ASSOCIATE mcps_data_confirm *data_conf_cb; /**< MAC MCPS data confirm callback function */ mcps_data_confirm_ext *data_conf_ext_cb; /**< MAC MCPS data confirm with payload callback function */ mcps_data_indication *data_ind_cb; /**< MAC MCPS data indication callback function */ mcps_data_indication_ext *data_ind_ext_cb; /**< MAC MCPS data indication with IE extension's callback function */ + mcps_edfe_handler *edfe_ind_cb; /**< MAC MCPS EDFE detection extension's callback function */ mcps_ack_data_req_ext *enhanced_ack_data_req_cb; /**< Enhanced ACK IE element and payload request from MAC user */ mcps_purge_confirm *purge_conf_cb; /**< MAC MCPS purge confirm callback function */ mlme_confirm *mlme_conf_cb; /**< MAC MLME confirm callback function */ diff --git a/nanostack/mac_mcps.h b/nanostack/mac_mcps.h index 05fbec040b3a..614a01e326cb 100644 --- a/nanostack/mac_mcps.h +++ b/nanostack/mac_mcps.h @@ -44,6 +44,7 @@ typedef struct mcps_data_req_s { bool PendingBit: 1; /**< Specifies whether more fragments are to be sent or not */ bool SeqNumSuppressed: 1; /**< True suppress sequence number from frame. This will be only checked when 2015 extension is enabled */ bool PanIdSuppressed: 1; /**< True suppress PAN-id is done when possible from frame. This will be only checked when 2015 extension is enabled */ + bool ExtendedFrameExchange: 1; /**< True for Extended Frame change. This will be only checked when 2015 extension and enhanced frame is enabled */ mlme_security_t Key; /**< Security key */ } mcps_data_req_t; @@ -86,6 +87,7 @@ typedef struct mcps_data_ind_s { uint16_t SrcPANId; /**< Source PAN ID */ uint8_t SrcAddr[8]; /**< Source address */ unsigned DstAddrMode: 2; /**< Destination address mode */ + bool DSN_suppressed: 1; /**< Indicate when DSN not include valid sequency id */ uint16_t DstPANId; /**< Destination PAN ID */ uint8_t DstAddr[8]; /**< Destination address */ uint8_t mpduLinkQuality; /**< LQI value measured during reception of the MPDU */ @@ -164,5 +166,31 @@ typedef struct mcps_purge_conf_s { uint8_t status; /**< Status of the purge performed */ } mcps_purge_conf_t; +#define MCPS_EDFE_NORMAL_FRAME 0 /**< Normal Data message normal behaviour */ +#define MCPS_EDFE_MALFORMED_FRAME 1 /**< Drop whole packet */ +#define MCPS_EDFE_TX_FRAME 2 /**< Tx message send data if pending in 1ms -5ms time window */ +#define MCPS_EDFE_RESPONSE_FRAME 3 /**< Response message send data if pending in 1ms -5ms time window */ +#define MCPS_EDFE_FINAL_FRAME_TX 4 /**< Final response message send in 1ms -5ms time window */ +#define MCPS_EDFE_FINAL_FRAME_RX 5 /**< EDFE session can be close at MAC side and drop this packet */ + +/** + * @brief struct mcps_edfe_response_t EDFE detetction and response structure + * + */ +typedef struct mcps_edfe_response_s { + struct mcps_data_ie_list ie_elements; /**< IE hader and payload's elements from Packet */ + struct mcps_data_req_ie_list ie_response; /**< IE hader and payload's elements for Response Packet */ + uint8_t edfe_message_status; /**< Indicate Packet handler status */ + uint8_t message_handle; /**< EDFE Data request message ID for detect pending data at LLC layer*/ + int8_t rssi; /**< Received packet signal streng in dbm */ + unsigned SrcAddrMode: 2; /**< Source address mode: used for RX validation and TX purpose */ + unsigned DstAddrMode: 2; /**< Destination address mode: used for RX validation and TX purpose */ + uint8_t Address[8]; /**< RX: Packet Address Src & TX Response Destination address */ + bool SeqNumSuppressed: 1; /**< True suppress sequence number from frame. This will be only checked when 2015 extension is enabled */ + bool PanIdSuppressed: 1; /**< True suppress PAN-id is done when possible from frame. */ + bool wait_response: 1; /**< True enable response wait timer and re-send operation. */ + bool use_message_handle_to_discover: 1; /**< EDFE Data request message ID is valid at message_handle. */ +} mcps_edfe_response_t; + #endif // MAC_MCPS_H diff --git a/source/6LoWPAN/adaptation_interface.c b/source/6LoWPAN/adaptation_interface.c index 87d66577359a..79e294745524 100644 --- a/source/6LoWPAN/adaptation_interface.c +++ b/source/6LoWPAN/adaptation_interface.c @@ -938,6 +938,7 @@ static void lowpan_data_request_to_mac(protocol_interface_info_entry_t *cur, buf } if (interface_ptr->mpx_api) { + dataReq.ExtendedFrameExchange = buf->options.edfe_mode; interface_ptr->mpx_api->mpx_data_request(interface_ptr->mpx_api, &dataReq, interface_ptr->mpx_user_id); } else { cur->mac_api->mcps_data_req(cur->mac_api, &dataReq); diff --git a/source/6LoWPAN/ws/ws_common_defines.h b/source/6LoWPAN/ws/ws_common_defines.h index 749a5aa1fa3b..423d183bda71 100644 --- a/source/6LoWPAN/ws/ws_common_defines.h +++ b/source/6LoWPAN/ws/ws_common_defines.h @@ -130,6 +130,13 @@ typedef struct ws_bt_ie { uint_fast24_t broadcast_interval_offset; } ws_bt_ie_t; +/** + * @brief ws_fc_ie_t WS FC-IE element + */ +typedef struct ws_fc_ie { + uint8_t tx_flow_ctrl; + uint8_t rx_flow_ctrl; +} ws_fc_ie_t; /** * @brief ws_channel_plan_zero_t WS channel plan 0 define domain and class diff --git a/source/6LoWPAN/ws/ws_ie_lib.c b/source/6LoWPAN/ws/ws_ie_lib.c index 0dfdc8b5ac13..633b01c60ede 100644 --- a/source/6LoWPAN/ws/ws_ie_lib.c +++ b/source/6LoWPAN/ws/ws_ie_lib.c @@ -110,10 +110,11 @@ uint8_t *ws_wh_bt_write(uint8_t *ptr) } -uint8_t *ws_wh_fc_write(uint8_t *ptr, uint8_t flow_ctrl) +uint8_t *ws_wh_fc_write(uint8_t *ptr, ws_fc_ie_t *fc_ie) { - ptr = ws_wh_header_base_write(ptr, 1, WH_IE_FC_TYPE); - *ptr++ = flow_ctrl; + ptr = ws_wh_header_base_write(ptr, 2, WH_IE_FC_TYPE); + *ptr++ = fc_ie->tx_flow_ctrl; + *ptr++ = fc_ie->rx_flow_ctrl; return ptr; } @@ -341,6 +342,19 @@ bool ws_wh_bt_read(uint8_t *data, uint16_t length, struct ws_bt_ie *bt_ie) return true; } +bool ws_wh_fc_read(uint8_t *data, uint16_t length, struct ws_fc_ie *fc_ie) +{ + mac_header_IE_t fc_ie_data; + fc_ie_data.id = MAC_HEADER_ASSIGNED_EXTERNAL_ORG_IE_ID; + if (2 != mac_ie_header_sub_id_discover(data, length, &fc_ie_data, WH_IE_FC_TYPE)) { + return false; + } + data = fc_ie_data.content_ptr; + fc_ie->tx_flow_ctrl = *data++; + fc_ie->rx_flow_ctrl = *data; + return true; +} + bool ws_wh_rsl_read(uint8_t *data, uint16_t length, int8_t *rsl) { mac_header_IE_t rsl_ie_data; diff --git a/source/6LoWPAN/ws/ws_ie_lib.h b/source/6LoWPAN/ws/ws_ie_lib.h index 1beadcd898b7..3be8bff8b5a1 100644 --- a/source/6LoWPAN/ws/ws_ie_lib.h +++ b/source/6LoWPAN/ws/ws_ie_lib.h @@ -23,6 +23,7 @@ struct ws_utt_ie; struct ws_bt_ie; struct ws_us_ie; struct ws_hopping_schedule_s; +struct ws_fc_ie; /** * @brief ws_wp_network_name_t WS nested payload network name @@ -35,13 +36,14 @@ typedef struct ws_wp_network_name { /* WS_WH HEADER IE */ uint8_t *ws_wh_utt_write(uint8_t *ptr, uint8_t message_type); uint8_t *ws_wh_bt_write(uint8_t *ptr); -uint8_t *ws_wh_fc_write(uint8_t *ptr, uint8_t flow_ctrl); +uint8_t *ws_wh_fc_write(uint8_t *ptr, struct ws_fc_ie *fc_ie); uint8_t *ws_wh_rsl_write(uint8_t *ptr, uint8_t rsl); uint8_t *ws_wh_vh_write(uint8_t *ptr, uint8_t *vendor_header, uint8_t vendor_header_length); uint8_t *ws_wh_ea_write(uint8_t *ptr, uint8_t *eui64); bool ws_wh_utt_read(uint8_t *data, uint16_t length, struct ws_utt_ie *utt_ie); bool ws_wh_bt_read(uint8_t *data, uint16_t length, struct ws_bt_ie *bt_ie); +bool ws_wh_fc_read(uint8_t *data, uint16_t length, struct ws_fc_ie *fc_ie); bool ws_wh_rsl_read(uint8_t *data, uint16_t length, int8_t *rsl); bool ws_wh_ea_read(uint8_t *data, uint16_t length, uint8_t *eui64); diff --git a/source/6LoWPAN/ws/ws_llc_data_service.c b/source/6LoWPAN/ws/ws_llc_data_service.c index d5fbbe359c67..89b48c4202d4 100644 --- a/source/6LoWPAN/ws/ws_llc_data_service.c +++ b/source/6LoWPAN/ws/ws_llc_data_service.c @@ -112,6 +112,10 @@ typedef struct { bool active_eapol_session: 1; /**< Indicating active EAPOL message */ } temp_entriest_t; +/** EDFE response and Enhanced ACK data length */ + +#define ENHANCED_FRAME_RESPONSE (WH_IE_ELEMENT_HEADER_LENGTH + 2 + WH_IE_ELEMENT_HEADER_LENGTH + 4 + WH_IE_ELEMENT_HEADER_LENGTH + 1 + WH_IE_ELEMENT_HEADER_LENGTH + 5) + typedef struct { uint8_t mac_handle_base; /**< Mac handle id base this will be updated by 1 after use */ uint8_t llc_message_list_size; /**< llc_message_list list size */ @@ -123,7 +127,7 @@ typedef struct { ws_asynch_ind *asynch_ind; /**< LLC Asynch data indication call back configured by user */ ws_asynch_confirm *asynch_confirm; /**< LLC Asynch data confirmation call back configured by user */ ws_neighbor_info_request *ws_neighbor_info_request_cb; /**< LLC Neighbour discover API*/ - uint8_t ws_enhanced_ack_elements[WH_IE_ELEMENT_HEADER_LENGTH + 4 + WH_IE_ELEMENT_HEADER_LENGTH + 1]; + uint8_t ws_enhanced_response_elements[ENHANCED_FRAME_RESPONSE]; ns_ie_iovec_t ws_header_vector; protocol_interface_info_entry_t *interface_ptr; /**< List link entry */ @@ -304,7 +308,7 @@ static uint16_t ws_wh_headers_length(wh_ie_sub_list_t requested_list, llc_ie_par if (requested_list.fc_ie) { //Static 1 bytes allways - length += WH_IE_ELEMENT_HEADER_LENGTH + 1; + length += WH_IE_ELEMENT_HEADER_LENGTH + 2; } if (requested_list.rsl_ie) { @@ -414,7 +418,6 @@ static void ws_llc_mac_confirm_cb(const mac_api_t *api, const mcps_data_conf_t * } protocol_interface_info_entry_t *interface = base->interface_ptr; - llc_message_t *message = llc_message_discover_by_mac_handle(data->msduHandle, &base->llc_message_list); if (!message) { return; @@ -520,14 +523,15 @@ static void ws_llc_ack_data_req_ext(const mac_api_t *api, mcps_ack_data_payload_ memset(data, 0, sizeof(mcps_ack_data_payload_t)); //Add just 2 header elements to inside 1 block data->ie_elements.headerIeVectorList = &base->ws_header_vector; - base->ws_header_vector.ieBase = base->ws_enhanced_ack_elements; - base->ws_header_vector.iovLen = sizeof(base->ws_enhanced_ack_elements); + base->ws_header_vector.ieBase = base->ws_enhanced_response_elements; + data->ie_elements.headerIovLength = 1; //Write Data to block - uint8_t *ptr = base->ws_enhanced_ack_elements; + uint8_t *ptr = base->ws_enhanced_response_elements; ptr = ws_wh_utt_write(ptr, WS_FT_ACK); - ws_wh_rsl_write(ptr, ws_neighbor_class_rsl_from_dbm_calculate(rssi)); + ptr = ws_wh_rsl_write(ptr, ws_neighbor_class_rsl_from_dbm_calculate(rssi)); + base->ws_header_vector.iovLen = ptr - base->ws_enhanced_response_elements; } @@ -654,7 +658,7 @@ static void ws_llc_data_indication_cb(const mac_api_t *api, const mcps_data_ind_ } } - if (!multicast && !ws_neighbor_class_neighbor_duplicate_packet_check(neighbor_info.ws_neighbor, data->DSN, data->timestamp)) { + if (!multicast && !data->DSN_suppressed && !ws_neighbor_class_neighbor_duplicate_packet_check(neighbor_info.ws_neighbor, data->DSN, data->timestamp)) { tr_info("Drop duplicate message"); return; } @@ -945,6 +949,9 @@ static void ws_llc_lowpan_mpx_data_request(llc_data_base_t *base, mpx_user_t *us nested_wp_id.vp_ie = true; } + if (data->ExtendedFrameExchange) { + ie_header_mask.fc_ie = true; + } if (!data->TxAckReq) { nested_wp_id.bs_ie = true; } @@ -989,17 +996,30 @@ static void ws_llc_lowpan_mpx_data_request(llc_data_base_t *base, mpx_user_t *us data_req.msduLength = 0; data_req.msduHandle = message->msg_handle; - if (!data->TxAckReq) { - data_req.PanIdSuppressed = false; - data_req.DstAddrMode = MAC_ADDR_MODE_NONE; - } else { + if (data->ExtendedFrameExchange) { + data_req.SeqNumSuppressed = true; data_req.PanIdSuppressed = true; + data_req.TxAckReq = true; // This will be changed inside MAC + } else { + if (!data->TxAckReq) { + data_req.PanIdSuppressed = false; + data_req.DstAddrMode = MAC_ADDR_MODE_NONE; + } else { + data_req.PanIdSuppressed = true; + } } uint8_t *ptr = ws_message_buffer_ptr_get(message); message->messsage_type = WS_FT_DATA; message->ie_vector_list[0].ieBase = ptr; + if (ie_header_mask.fc_ie) { + ws_fc_ie_t fc_ie; + fc_ie.tx_flow_ctrl = 50;//No data at initial frame + fc_ie.rx_flow_ctrl = 255; + //Write Flow control for 1 packet send this will be modified at real data send + ptr = ws_wh_fc_write(ptr, &fc_ie); + } //Write UTT ptr = ws_wh_utt_write(ptr, message->messsage_type); @@ -1034,6 +1054,9 @@ static void ws_llc_lowpan_mpx_data_request(llc_data_base_t *base, mpx_user_t *us message->ie_vector_list[2].iovLen = data->msduLength; ws_llc_lowpan_mpx_header_set(message, MPX_LOWPAN_ENC_USER_ID); + if (data->ExtendedFrameExchange) { + message->ie_ext.payloadIovLength = 0; //Set Back 2 at response handler + } base->interface_ptr->mac_api->mcps_data_req_ext(base->interface_ptr->mac_api, &data_req, &message->ie_ext, NULL); } @@ -1062,6 +1085,7 @@ static void ws_llc_eapol_data_req_init(mcps_data_req_t *data_req, llc_message_t data_req->TxAckReq = message->ack_requested; data_req->DstPANId = message->pan_id; data_req->SrcAddrMode = message->src_address_type; + data_req->ExtendedFrameExchange = false; if (!data_req->TxAckReq) { data_req->PanIdSuppressed = false; data_req->DstAddrMode = MAC_ADDR_MODE_NONE; @@ -1415,6 +1439,88 @@ void ws_llc_free_multicast_temp_entry(protocol_interface_info_entry_t *cur, ws_n } +static void ws_llc_build_edfe_response(llc_data_base_t *base, mcps_edfe_response_t *response_message, ws_fc_ie_t fc_ie) +{ + memset(&response_message->ie_response, 0, sizeof(mcps_data_req_ie_list_t)); + response_message->ie_response.headerIeVectorList = &base->ws_header_vector; + base->ws_header_vector.ieBase = base->ws_enhanced_response_elements; + response_message->ie_response.headerIovLength = 1; + + //Write Data to block + uint8_t *ptr = base->ws_header_vector.ieBase; + ptr = ws_wh_fc_write(ptr, &fc_ie); + ptr = ws_wh_utt_write(ptr, WS_FT_DATA); + ptr = ws_wh_bt_write(ptr); + ptr = ws_wh_rsl_write(ptr, ws_neighbor_class_rsl_from_dbm_calculate(response_message->rssi)); + base->ws_header_vector.iovLen = ptr - base->ws_enhanced_response_elements; + response_message->SrcAddrMode = MAC_ADDR_MODE_NONE; + response_message->wait_response = false; + response_message->PanIdSuppressed = true; +} + +static void ws_llc_build_edfe_frame(llc_message_t *message, mcps_edfe_response_t *response_message, ws_fc_ie_t fc_ie) +{ + memset(&response_message->ie_response, 0, sizeof(mcps_data_req_ie_list_t)); + uint8_t *ptr = message->ie_vector_list[0].ieBase; + fc_ie.tx_flow_ctrl = 0;//Put Data with Handshake + fc_ie.rx_flow_ctrl = 255; + //Write Flow control for 1 packet send this will be modified at real data send + ptr = ws_wh_fc_write(ptr, &fc_ie); + response_message->ie_response.headerIeVectorList = &message->ie_vector_list[0]; + response_message->ie_response.headerIovLength = 1; + response_message->ie_response.payloadIeVectorList = &message->ie_vector_list[1]; + response_message->ie_response.payloadIovLength = 2; + response_message->SrcAddrMode = MAC_ADDR_MODE_NONE; + response_message->wait_response = true; + response_message->PanIdSuppressed = true; + //tr_debug("FC:Send Data frame"); + response_message->edfe_message_status = MCPS_EDFE_TX_FRAME; +} + +static void ws_llc_mcps_edfe_handler(const mac_api_t *api, mcps_edfe_response_t *response_message) +{ + // INSIDE this shuold not print anything + response_message->edfe_message_status = MCPS_EDFE_NORMAL_FRAME; + llc_data_base_t *base = ws_llc_discover_by_mac(api); + if (!base) { + return; + } + //Discover Here header FC-IE element + ws_fc_ie_t fc_ie; + if (!ws_wh_fc_read(response_message->ie_elements.headerIeList, response_message->ie_elements.headerIeListLength, &fc_ie)) { + return; + } + //tr_debug("Flow ctrl(%u TX,%u RX)", fc_ie.tx_flow_ctrl, fc_ie.rx_flow_ctrl); + if (fc_ie.tx_flow_ctrl == 0 && fc_ie.rx_flow_ctrl) { + + llc_message_t *message = NULL; + if (response_message->use_message_handle_to_discover) { + message = llc_message_discover_by_mac_handle(response_message->message_handle, &base->llc_message_list); + } + + if (!message) { + //tr_debug("FC:Send a Final Frame"); + fc_ie.rx_flow_ctrl = 0; + ws_llc_build_edfe_response(base, response_message, fc_ie); + response_message->edfe_message_status = MCPS_EDFE_FINAL_FRAME_TX; + } else { + ws_llc_build_edfe_frame(message, response_message, fc_ie); + } + + } else if (fc_ie.tx_flow_ctrl == 0 && fc_ie.rx_flow_ctrl == 0) { + //tr_debug("FC:Received a Final Frame"); + response_message->edfe_message_status = MCPS_EDFE_FINAL_FRAME_RX; + } else if (fc_ie.tx_flow_ctrl && fc_ie.rx_flow_ctrl) { + fc_ie.tx_flow_ctrl = 0; + fc_ie.rx_flow_ctrl = 255; + //tr_debug("FC:Send a response"); + ws_llc_build_edfe_response(base, response_message, fc_ie); + response_message->edfe_message_status = MCPS_EDFE_RESPONSE_FRAME; + } +} + + + int8_t ws_llc_create(struct protocol_interface_info_entry *interface, ws_asynch_ind *asynch_ind_cb, ws_asynch_confirm *asynch_cnf_cb, ws_neighbor_info_request *ws_neighbor_info_request_cb) { llc_data_base_t *base = ws_llc_discover_by_interface(interface); @@ -1435,6 +1541,7 @@ int8_t ws_llc_create(struct protocol_interface_info_entry *interface, ws_asynch_ base->ws_neighbor_info_request_cb = ws_neighbor_info_request_cb; //Register MAC Extensions base->interface_ptr->mac_api->mac_mcps_extension_enable(base->interface_ptr->mac_api, &ws_llc_mac_indication_cb, &ws_llc_mac_confirm_cb, &ws_llc_ack_data_req_ext); + base->interface_ptr->mac_api->mac_mcps_edfe_enable(base->interface_ptr->mac_api, &ws_llc_mcps_edfe_handler); //Init MPX class ws_llc_mpx_init(&base->mpx_data_base); ws_llc_temp_neigh_info_table_reset(base->temp_entries); @@ -1520,6 +1627,7 @@ int8_t ws_llc_asynch_request(struct protocol_interface_info_entry *interface, as data_req.SrcAddrMode = MAC_ADDR_MODE_64_BIT; data_req.Key = request->security; data_req.msduHandle = message->msg_handle; + data_req.ExtendedFrameExchange = false; if (request->message_type == WS_FT_PAN_ADVERT_SOL) { // PANID not know yet must be supressed data_req.PanIdSuppressed = true; diff --git a/source/MAC/IEEE802_15_4/mac_data_buffer.h b/source/MAC/IEEE802_15_4/mac_data_buffer.h index 4888cc816d5d..e01ee3a0400c 100644 --- a/source/MAC/IEEE802_15_4/mac_data_buffer.h +++ b/source/MAC/IEEE802_15_4/mac_data_buffer.h @@ -98,6 +98,8 @@ typedef struct mac_pre_build_frame { bool asynch_request: 1; bool message_builded: 1; bool DSN_allocated: 1; + bool ExtendedFrameExchange: 1; + bool WaitResponse: 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 ff6761699052..5052ad5d4ea6 100644 --- a/source/MAC/IEEE802_15_4/mac_defines.h +++ b/source/MAC/IEEE802_15_4/mac_defines.h @@ -147,6 +147,25 @@ typedef struct mac_mcps_data_conf_fail_s { uint8_t status; /**< Status of the failing MSDU transmission */ } mac_mcps_data_conf_fail_t; + +typedef enum mac_edfe_frame_state { + MAC_EDFE_FRAME_IDLE = 0, + MAC_EDFE_FRAME_CONNECTING, + MAC_EDFE_FRAME_CONNECTED, + MAC_EDFE_FRAME_TX_RESPONSE, + MAC_EDFE_FRAME_TX_FINAL_FRAME, + MAC_EDFE_FRAME_WAIT_DATA, + MAC_EDFE_FRAME_WAIT_RESPONSE +} mac_edfe_frame_state_e; + + +typedef struct mac_mcps_edfe_info_s { + mac_edfe_frame_state_e state; + uint8_t PeerAddr[8]; + struct mac_pre_build_frame edfe_response_buffer; +} mac_mcps_edfe_frame_info_t; + + typedef struct protocol_interface_rf_mac_setup { int8_t mac_interface_id; bool macUpState: 1; @@ -154,7 +173,10 @@ typedef struct protocol_interface_rf_mac_setup { bool beaconSrcAddressModeLong: 1; //This force beacon src to mac64 otherwise shortAdressValid will define type bool secFrameCounterPerKey: 1; bool mac_extension_enabled: 1; + bool mac_edfe_enabled: 1; // Indicate when EFDE exchange is possible bool mac_ack_tx_active: 1; + bool mac_edfe_tx_active: 1; + bool mac_edfe_response_tx_active: 1; bool mac_frame_pending: 1; /* MAC Capability Information */ bool macCapRxOnIdle: 1; @@ -279,6 +301,7 @@ typedef struct protocol_interface_rf_mac_setup { struct mac_cca_threshold *cca_threshold; //beacon_join_priority_tx_cb *beacon_join_priority_tx_cb_ptr; struct mac_statistics_s *mac_statistics; + mac_mcps_edfe_frame_info_t *mac_edfe_info; /* FHSS API*/ struct fhss_api *fhss_api; } protocol_interface_rf_mac_setup_s; diff --git a/source/MAC/IEEE802_15_4/mac_fhss_callbacks.c b/source/MAC/IEEE802_15_4/mac_fhss_callbacks.c index fd56ecbd74a7..8925c5ae4a6f 100644 --- a/source/MAC/IEEE802_15_4/mac_fhss_callbacks.c +++ b/source/MAC/IEEE802_15_4/mac_fhss_callbacks.c @@ -87,9 +87,16 @@ int mac_set_channel(const fhss_api_t *fhss_api, uint8_t channel_number) if (!mac_setup) { return -1; } + if (mac_setup->mac_ack_tx_active || (mac_setup->active_pd_data_request && (mac_setup->active_pd_data_request->asynch_request || mac_setup->timer_mac_event == MAC_TIMER_ACK))) { return -1; } + + //EDFE packet check if active tx or frame change session open for example wait data + if (mac_setup->mac_edfe_enabled && (mac_setup->mac_edfe_tx_active || mac_setup->mac_edfe_info->state > MAC_EDFE_FRAME_CONNECTING)) { + return -1; + } + return mac_mlme_rf_channel_change(mac_setup, channel_number); } diff --git a/source/MAC/IEEE802_15_4/mac_mcps_sap.c b/source/MAC/IEEE802_15_4/mac_mcps_sap.c index ee16dc86700c..b464020b4552 100644 --- a/source/MAC/IEEE802_15_4/mac_mcps_sap.c +++ b/source/MAC/IEEE802_15_4/mac_mcps_sap.c @@ -197,6 +197,18 @@ void mcps_sap_data_req_handler_ext(protocol_interface_rf_mac_setup_s *rf_mac_set uint8_t status = MLME_SUCCESS; mac_pre_build_frame_t *buffer = NULL; + if (rf_mac_setup->mac_edfe_enabled && data_req->ExtendedFrameExchange) { + if (rf_mac_setup->mac_edfe_info->state != MAC_EDFE_FRAME_IDLE) { + tr_debug("Accept only 1 active Efde Data request push"); + status = MLME_UNSUPPORTED_LEGACY; + goto verify_status; + } + + if (data_req->DstAddrMode != MAC_ADDR_MODE_64_BIT) { + status = MLME_INVALID_PARAMETER; + goto verify_status; + } + } if (!rf_mac_setup->mac_security_enabled) { if (data_req->Key.SecurityLevel) { @@ -254,7 +266,13 @@ void mcps_sap_data_req_handler_ext(protocol_interface_rf_mac_setup_s *rf_mac_set buffer->upper_layer_request = true; buffer->fcf_dsn.frametype = FC_DATA_FRAME; - buffer->fcf_dsn.ackRequested = data_req->TxAckReq; + buffer->ExtendedFrameExchange = data_req->ExtendedFrameExchange; + buffer->WaitResponse = data_req->TxAckReq; + if (data_req->ExtendedFrameExchange) { + buffer->fcf_dsn.ackRequested = false; + } else { + buffer->fcf_dsn.ackRequested = data_req->TxAckReq; + } buffer->mac_header_length_with_security = 3; mac_header_security_parameter_set(&buffer->aux_header, &data_req->Key); @@ -336,6 +354,7 @@ void mcps_sap_data_req_handler_ext(protocol_interface_rf_mac_setup_s *rf_mac_set buffer->mac_payload = data_req->msdu; buffer->mac_payload_length = data_req->msduLength; //check that header + payload length is not bigger than MAC MTU + if (data_req->InDirectTx) { mac_indirect_queue_write(rf_mac_setup, buffer); } else { @@ -550,8 +569,14 @@ static uint8_t mac_data_interface_decrypt_packet(mac_pre_parsed_frame_t *b, mlme //READ SRC Address uint16_t SrcPANId = mac_header_get_src_panid(&b->fcf_dsn, mac_header_message_start_pointer(b), rf_mac_setup->pan_id); - mac_header_get_src_address(&b->fcf_dsn, mac_header_message_start_pointer(b), neighbour_validation.address); - neighbour_validation.addr_type = b->fcf_dsn.SrcAddrMode; + + if (b->fcf_dsn.SrcAddrMode == MAC_ADDR_MODE_NONE && rf_mac_setup->mac_edfe_enabled && rf_mac_setup->mac_edfe_info->state > MAC_EDFE_FRAME_CONNECTING) { + memcpy(neighbour_validation.address, rf_mac_setup->mac_edfe_info->PeerAddr, 8); + neighbour_validation.addr_type = MAC_ADDR_MODE_64_BIT; + } else { + mac_header_get_src_address(&b->fcf_dsn, mac_header_message_start_pointer(b), neighbour_validation.address); + neighbour_validation.addr_type = b->fcf_dsn.SrcAddrMode; + } neighbour_validation.keyId = security_params->KeyIndex; // Get A Key description @@ -708,6 +733,7 @@ static int8_t mac_data_sap_rx_handler(mac_pre_parsed_frame_t *buf, protocol_inte memset(data_ind, 0, sizeof(mcps_data_ind_t)); //Parse data data_ind->DSN = buf->fcf_dsn.DSN; + data_ind->DSN_suppressed = buf->fcf_dsn.sequenceNumberSuppress; data_ind->DstAddrMode = buf->fcf_dsn.DstAddrMode; mac_header_get_dst_address(&buf->fcf_dsn, mac_header_message_start_pointer(buf), data_ind->DstAddr); data_ind->SrcAddrMode = buf->fcf_dsn.SrcAddrMode; @@ -722,6 +748,10 @@ static int8_t mac_data_sap_rx_handler(mac_pre_parsed_frame_t *buf, protocol_inte data_ind->timestamp = buf->timestamp; /* Parse security part */ mac_header_security_components_read(buf, &data_ind->Key); + if (data_ind->SrcAddrMode == MAC_ADDR_MODE_NONE && rf_mac_setup->mac_edfe_enabled && rf_mac_setup->mac_edfe_info->state > MAC_EDFE_FRAME_CONNECTING) { + memcpy(data_ind->SrcAddr, rf_mac_setup->mac_edfe_info->PeerAddr, 8); + data_ind->SrcAddrMode = MAC_ADDR_MODE_64_BIT; + } buf->neigh_info = mac_sec_mib_device_description_get(rf_mac_setup, data_ind->SrcAddr, data_ind->SrcAddrMode, data_ind->SrcPANId); if (buf->fcf_dsn.securityEnabled) { @@ -795,7 +825,7 @@ static void mac_lib_res_no_data_to_req(mac_pre_parsed_frame_t *buffer, protocol_ buf->fcf_dsn.securityEnabled = buffer->fcf_dsn.securityEnabled; buf->fcf_dsn.intraPan = true; - buf->fcf_dsn.ackRequested = true; + buf->WaitResponse = buf->fcf_dsn.ackRequested = true; buf->mac_header_length_with_security = 3; //Check PanID presents at header buf->fcf_dsn.DstPanPresents = mac_dst_panid_present(&buf->fcf_dsn); @@ -1061,8 +1091,17 @@ void mac_mcps_trig_buffer_from_queue(protocol_interface_rf_mac_setup_s *rf_mac_s buffer = mcps_sap_pd_req_queue_read(rf_mac_setup, is_bc_queue, false); if (buffer) { + //Here + if (buffer->ExtendedFrameExchange) { + //Update here state and store peer + memcpy(rf_mac_setup->mac_edfe_info->PeerAddr, buffer->DstAddr, 8); + rf_mac_setup->mac_edfe_info->state = MAC_EDFE_FRAME_CONNECTING; + } rf_mac_setup->active_pd_data_request = buffer; if (mcps_pd_data_request(rf_mac_setup, buffer) != 0) { + if (buffer->ExtendedFrameExchange) { + rf_mac_setup->mac_edfe_info->state = MAC_EDFE_FRAME_IDLE; + } rf_mac_setup->active_pd_data_request = NULL; mac_mcps_asynch_finish(rf_mac_setup, buffer); mcps_data_confirm_handle(rf_mac_setup, buffer, NULL); @@ -1079,15 +1118,24 @@ static int8_t mac_ack_sap_rx_handler(mac_pre_parsed_frame_t *buf, protocol_inter { //allocate Data ind primitiv and parse packet to that mlme_security_t key; + uint8_t srcAddressMode; uint8_t SrcAddr[8]; /**< Source address */ memset(SrcAddr, 0, 8); memset(&key, 0, sizeof(mlme_security_t)); - mac_header_get_src_address(&buf->fcf_dsn, mac_header_message_start_pointer(buf), SrcAddr); + srcAddressMode = buf->fcf_dsn.SrcAddrMode; + if (buf->fcf_dsn.SrcAddrMode) { + mac_header_get_src_address(&buf->fcf_dsn, mac_header_message_start_pointer(buf), SrcAddr); + } else { + if (rf_mac_setup->mac_edfe_enabled && (buf->fcf_dsn.frametype == FC_DATA_FRAME && !buf->fcf_dsn.ackRequested)) { + memcpy(SrcAddr, rf_mac_setup->mac_edfe_info->PeerAddr, 8); + srcAddressMode = MAC_ADDR_MODE_64_BIT; + } + } uint16_t pan_id = mac_header_get_src_panid(&buf->fcf_dsn, mac_header_message_start_pointer(buf), rf_mac_setup->pan_id); /* Parse security part */ mac_header_security_components_read(buf, &key); - buf->neigh_info = mac_sec_mib_device_description_get(rf_mac_setup, SrcAddr, buf->fcf_dsn.SrcAddrMode, pan_id); + buf->neigh_info = mac_sec_mib_device_description_get(rf_mac_setup, SrcAddr, srcAddressMode, pan_id); if (buf->fcf_dsn.securityEnabled) { uint8_t status = mac_data_interface_decrypt_packet(buf, &key); if (status != MLME_SUCCESS) { @@ -1622,7 +1670,11 @@ static int8_t mcps_generic_packet_build(protocol_interface_rf_mac_setup_s *rf_pt tx_buf->len = frame_length; uint8_t *mhr_start = ptr; - buffer->tx_time = mcps_generic_backoff_calc(rf_ptr); + if (buffer->ExtendedFrameExchange && buffer->fcf_dsn.SrcAddrMode == MAC_ADDR_MODE_NONE) { + buffer->tx_time = mac_mcps_sap_get_phy_timestamp(rf_ptr) + 300; //Send 300 us later + } else { + buffer->tx_time = mcps_generic_backoff_calc(rf_ptr); + } ptr = mac_generic_packet_write(rf_ptr, ptr, buffer); @@ -1716,6 +1768,86 @@ int8_t mcps_generic_ack_data_request_init(protocol_interface_rf_mac_setup_s *rf_ return 0; } +int8_t mcps_generic_edfe_frame_init(protocol_interface_rf_mac_setup_s *rf_ptr, const mac_fcf_sequence_t *fcf, const uint8_t *data_ptr, const mcps_edfe_response_t *response) +{ + //Data Here + mac_pre_build_frame_t *buffer; + if (response->wait_response) { + buffer = rf_ptr->active_pd_data_request; + buffer->message_builded = false; + } else { + buffer = &rf_ptr->enhanced_ack_buffer; + memset(buffer, 0, sizeof(mac_pre_build_frame_t)); + buffer->fcf_dsn.frametype = FC_DATA_FRAME; + buffer->fcf_dsn.frameVersion = fcf->frameVersion; + buffer->fcf_dsn.DstPanPresents = fcf->DstPanPresents; + buffer->fcf_dsn.DstAddrMode = response->DstAddrMode; + buffer->DstPANId = mac_header_get_src_panid(fcf, data_ptr, rf_ptr->pan_id); + buffer->SrcPANId = mac_header_get_dst_panid(fcf, data_ptr, rf_ptr->pan_id); + memcpy(buffer->DstAddr, response->Address, 8); + } + buffer->fcf_dsn.intraPan = response->PanIdSuppressed; + buffer->fcf_dsn.SrcAddrMode = response->SrcAddrMode; + buffer->fcf_dsn.SrcPanPresents = response->SrcAddrMode; + buffer->fcf_dsn.framePending = false; + buffer->fcf_dsn.sequenceNumberSuppress = fcf->sequenceNumberSuppress; + + buffer->WaitResponse = response->wait_response; + buffer->ExtendedFrameExchange = true; + + if (buffer->fcf_dsn.sequenceNumberSuppress) { + buffer->mac_header_length_with_security = 2; + } else { + buffer->mac_header_length_with_security = 3; + } + + buffer->mac_header_length_with_security += mac_header_address_length(&buffer->fcf_dsn); + + //Security + buffer->fcf_dsn.securityEnabled = fcf->securityEnabled; + if (buffer->fcf_dsn.securityEnabled) { + //Read Security AUX headers + const uint8_t *ptr = data_ptr; + ptr += mac_header_off_set_to_aux_header(fcf); + //Start parsing AUX header + mlme_security_t aux_parse; + mac_header_security_aux_header_parse(ptr, &aux_parse); + buffer->aux_header.KeyIdMode = aux_parse.KeyIdMode; + buffer->aux_header.KeyIndex = aux_parse.KeyIndex; + buffer->aux_header.securityLevel = aux_parse.SecurityLevel; + memcpy(buffer->aux_header.Keysource, aux_parse.Keysource, 8); + + buffer->security_mic_len = mac_security_mic_length_get(buffer->aux_header.securityLevel); + buffer->fcf_dsn.frameVersion = MAC_FRAME_VERSION_2006; + buffer->mac_header_length_with_security += mac_header_security_aux_header_length(buffer->aux_header.securityLevel, buffer->aux_header.KeyIdMode); + + } + + uint16_t ie_header_length = 0; + uint16_t ie_payload_length = 0; + + if (!mac_ie_vector_length_validate(response->ie_response.headerIeVectorList, response->ie_response.headerIovLength, &ie_header_length)) { + return -1; + } + + if (!mac_ie_vector_length_validate(response->ie_response.payloadIeVectorList, response->ie_response.payloadIovLength, &ie_payload_length)) { + return -1; + } + + buffer->ie_elements.headerIeVectorList = response->ie_response.headerIeVectorList; + buffer->ie_elements.headerIovLength = response->ie_response.headerIovLength; + buffer->ie_elements.payloadIeVectorList = response->ie_response.payloadIeVectorList; + buffer->ie_elements.payloadIovLength = response->ie_response.payloadIovLength; + buffer->headerIeLength = ie_header_length; + buffer->payloadsIeLength = ie_payload_length; + buffer->mac_payload = NULL; + buffer->mac_payload_length = 0; + + //This will prepare MHR length with Header IE + mac_header_information_elements_preparation(buffer); + return 0; +} + int8_t mcps_generic_ack_build(protocol_interface_rf_mac_setup_s *rf_ptr, bool init_build) { @@ -1854,8 +1986,11 @@ static int8_t mcps_generic_packet_rebuild(protocol_interface_rf_mac_setup_s *rf_ tx_buf->len = frame_length; uint8_t *mhr_start = ptr; - - buffer->tx_time = mcps_generic_backoff_calc(rf_ptr); + if (buffer->ExtendedFrameExchange && buffer->fcf_dsn.SrcAddrMode == MAC_ADDR_MODE_NONE) { + buffer->tx_time = mac_mcps_sap_get_phy_timestamp(rf_ptr) + 300; //Send 300 us later + } else { + buffer->tx_time = mcps_generic_backoff_calc(rf_ptr); + } ptr = mac_generic_packet_write(rf_ptr, ptr, buffer); @@ -1884,15 +2019,39 @@ static int8_t mcps_pd_data_cca_trig(protocol_interface_rf_mac_setup_s *rf_ptr, m cca_enabled = false; rf_ptr->mac_ack_tx_active = true; } else { - if (rf_ptr->mac_ack_tx_active) { - mac_csma_backoff_start(rf_ptr); - platform_exit_critical(); - return -1; + if (buffer->ExtendedFrameExchange) { + if (buffer->fcf_dsn.SrcAddrMode) { + cca_enabled = true; + } else { + //Response + if (!buffer->WaitResponse) { + //Response + if (rf_ptr->mac_ack_tx_active) { + mac_csma_backoff_start(rf_ptr); + platform_exit_critical(); + return -1; + } + rf_ptr->mac_edfe_response_tx_active = true; + } else { + rf_ptr->mac_edfe_response_tx_active = false; + } + cca_enabled = false; + rf_ptr->mac_edfe_tx_active = true; + } + + } else { + + if (rf_ptr->mac_ack_tx_active) { + mac_csma_backoff_start(rf_ptr); + platform_exit_critical(); + return -1; + } + cca_enabled = true; } - cca_enabled = true; + } // Use double CCA check with FHSS for data packets only - if (rf_ptr->fhss_api && !rf_ptr->mac_ack_tx_active && !rf_ptr->active_pd_data_request->asynch_request) { + if (rf_ptr->fhss_api && !rf_ptr->mac_ack_tx_active && !rf_ptr->mac_edfe_tx_active && !rf_ptr->active_pd_data_request->asynch_request) { if ((buffer->tx_time - (rf_ptr->multi_cca_interval * (rf_ptr->number_of_csma_ca_periods - 1))) > mac_mcps_sap_get_phy_timestamp(rf_ptr)) { buffer->csma_periods_left = rf_ptr->number_of_csma_ca_periods - 1; buffer->tx_time -= (rf_ptr->multi_cca_interval * (rf_ptr->number_of_csma_ca_periods - 1)); @@ -1900,10 +2059,13 @@ static int8_t mcps_pd_data_cca_trig(protocol_interface_rf_mac_setup_s *rf_ptr, m } mac_pd_sap_set_phy_tx_time(rf_ptr, buffer->tx_time, cca_enabled); if (mac_plme_cca_req(rf_ptr) != 0) { - if (buffer->fcf_dsn.frametype == MAC_FRAME_ACK) { + if (buffer->fcf_dsn.frametype == MAC_FRAME_ACK || (buffer->ExtendedFrameExchange && rf_ptr->mac_edfe_response_tx_active)) { + //ACK or EFDE Response rf_ptr->mac_ack_tx_active = false; // For Ack, stop the active TX process rf_ptr->macTxProcessActive = false; + rf_ptr->mac_edfe_tx_active = false; + rf_ptr->mac_edfe_response_tx_active = false; // If MAC had TX process active before Ack transmission, // the TX process has to be restarted in case the Ack transmission failed. if (rf_ptr->active_pd_data_request) { @@ -1925,7 +2087,6 @@ static int8_t mcps_pd_data_request(protocol_interface_rf_mac_setup_s *rf_ptr, ma { rf_ptr->macTxRequestAck = false; - memset(&(rf_ptr->mac_tx_status), 0, sizeof(mac_tx_status_t)); rf_ptr->mac_cca_retry = 0; rf_ptr->mac_tx_retry = 0; @@ -1934,7 +2095,7 @@ static int8_t mcps_pd_data_request(protocol_interface_rf_mac_setup_s *rf_ptr, ma if (mcps_generic_packet_build(rf_ptr, buffer) != 0) { return -1; } - rf_ptr->macTxRequestAck = buffer->fcf_dsn.ackRequested; + rf_ptr->macTxRequestAck = buffer->WaitResponse; if (!rf_ptr->mac_ack_tx_active) { return mcps_pd_data_cca_trig(rf_ptr, buffer); } else { @@ -1943,6 +2104,24 @@ static int8_t mcps_pd_data_request(protocol_interface_rf_mac_setup_s *rf_ptr, ma } +int8_t mcps_edfe_data_request(protocol_interface_rf_mac_setup_s *rf_ptr, mac_pre_build_frame_t *buffer) +{ + rf_ptr->macTxRequestAck = false; + memset(&(rf_ptr->mac_tx_status), 0, sizeof(mac_tx_status_t)); + rf_ptr->mac_cca_retry = 0; + rf_ptr->mac_tx_retry = 0; + rf_ptr->mac_tx_start_channel = rf_ptr->mac_channel; + buffer->aux_header.frameCounter = 0xffffffff; + mac_csma_param_init(rf_ptr); + if (mcps_generic_packet_build(rf_ptr, buffer) != 0) { + return -1; + } + rf_ptr->macTxRequestAck = buffer->WaitResponse;//buffer->fcf_dsn.ackRequested; + + return mcps_pd_data_cca_trig(rf_ptr, buffer); + +} + int8_t mcps_pd_data_rebuild(protocol_interface_rf_mac_setup_s *rf_ptr, mac_pre_build_frame_t *buffer) { if (mcps_generic_packet_rebuild(rf_ptr, buffer) != 0) { @@ -1955,7 +2134,10 @@ int8_t mcps_pd_data_rebuild(protocol_interface_rf_mac_setup_s *rf_ptr, mac_pre_b bool mac_is_ack_request_set(mac_pre_build_frame_t *buffer) { - return buffer->fcf_dsn.ackRequested; + if (buffer->fcf_dsn.ackRequested || buffer->WaitResponse) { + return true; + } + return false; } int mac_convert_frame_type_to_fhss(uint8_t frame_type) @@ -1979,11 +2161,20 @@ void mcps_sap_pd_req_queue_write(protocol_interface_rf_mac_setup_s *rf_mac_setup if ((rf_mac_setup->macBroadcastDisabled == true) && !mac_is_ack_request_set(buffer)) { goto push_to_queue; } + + if (buffer->ExtendedFrameExchange) { + //Update here state and store peer + memcpy(rf_mac_setup->mac_edfe_info->PeerAddr, buffer->DstAddr, 8); + rf_mac_setup->mac_edfe_info->state = MAC_EDFE_FRAME_CONNECTING; + } if (rf_mac_setup->fhss_api && (buffer->asynch_request == false)) { uint16_t frame_length = buffer->mac_payload_length + buffer->headerIeLength + buffer->payloadsIeLength; if (rf_mac_setup->fhss_api->check_tx_conditions(rf_mac_setup->fhss_api, !mac_is_ack_request_set(buffer), buffer->msduHandle, mac_convert_frame_type_to_fhss(buffer->fcf_dsn.frametype), frame_length, rf_mac_setup->dev_driver->phy_driver->phy_header_length, rf_mac_setup->dev_driver->phy_driver->phy_tail_length) == false) { + if (buffer->ExtendedFrameExchange) { + rf_mac_setup->mac_edfe_info->state = MAC_EDFE_FRAME_IDLE; + } goto push_to_queue; } } @@ -1992,10 +2183,16 @@ void mcps_sap_pd_req_queue_write(protocol_interface_rf_mac_setup_s *rf_mac_setup if (mcps_pd_data_request(rf_mac_setup, buffer) != 0) { rf_mac_setup->mac_tx_result = MAC_TX_PRECOND_FAIL; rf_mac_setup->macTxRequestAck = false; + if (buffer->ExtendedFrameExchange) { + rf_mac_setup->mac_edfe_info->state = MAC_EDFE_FRAME_IDLE; + } if (mcps_sap_pd_confirm(rf_mac_setup) != 0) { // can't send event, try calling error handler directly rf_mac_setup->mac_mcps_data_conf_fail.msduHandle = buffer->msduHandle; rf_mac_setup->mac_mcps_data_conf_fail.status = buffer->status; + if (buffer->ExtendedFrameExchange) { + rf_mac_setup->mac_edfe_info->state = MAC_EDFE_FRAME_IDLE; + } mcps_sap_prebuild_frame_buffer_free(buffer); rf_mac_setup->active_pd_data_request = NULL; mac_pd_data_confirm_failure_handle(rf_mac_setup); diff --git a/source/MAC/IEEE802_15_4/mac_mcps_sap.h b/source/MAC/IEEE802_15_4/mac_mcps_sap.h index 1a8400414127..fb212e20a26e 100644 --- a/source/MAC/IEEE802_15_4/mac_mcps_sap.h +++ b/source/MAC/IEEE802_15_4/mac_mcps_sap.h @@ -35,6 +35,7 @@ struct arm_phy_sap_msg_s; struct mcps_purge_s; struct mcps_data_req_ie_list; struct channel_list_s; +struct mcps_enhanced_frame_response_s; /** Address types */ typedef enum { @@ -133,8 +134,12 @@ uint8_t mcps_sap_purge_reg_handler(struct protocol_interface_rf_mac_setup *rf_ma int8_t mcps_pd_data_rebuild(struct protocol_interface_rf_mac_setup *rf_ptr, mac_pre_build_frame_t *buffer); +int8_t mcps_edfe_data_request(struct protocol_interface_rf_mac_setup *rf_ptr, mac_pre_build_frame_t *buffer); + int8_t mcps_generic_ack_data_request_init(struct protocol_interface_rf_mac_setup *rf_ptr, const mac_fcf_sequence_t *fcf, const uint8_t *data_ptr, const mcps_ack_data_payload_t *ack_payload); +int8_t mcps_generic_edfe_frame_init(struct protocol_interface_rf_mac_setup *rf_ptr, const mac_fcf_sequence_t *fcf, const uint8_t *data_ptr, const struct mcps_edfe_response_s *response); + int8_t mcps_generic_ack_build(struct protocol_interface_rf_mac_setup *rf_ptr, bool init_build); int mcps_packet_ingress_rate_limit_by_memory(uint8_t free_heap_percentage); diff --git a/source/MAC/IEEE802_15_4/mac_mlme.c b/source/MAC/IEEE802_15_4/mac_mlme.c index fe8d264bda5d..c49178e2a3ef 100644 --- a/source/MAC/IEEE802_15_4/mac_mlme.c +++ b/source/MAC/IEEE802_15_4/mac_mlme.c @@ -1711,6 +1711,7 @@ void mac_mlme_poll_req(protocol_interface_rf_mac_setup_s *cur, const mlme_poll_t } buf->fcf_dsn.frametype = FC_CMD_FRAME; + buf->WaitResponse = true; buf->fcf_dsn.ackRequested = true; buf->fcf_dsn.intraPan = true; diff --git a/source/MAC/IEEE802_15_4/mac_pd_sap.c b/source/MAC/IEEE802_15_4/mac_pd_sap.c index ec34ef77aea0..459474384607 100644 --- a/source/MAC/IEEE802_15_4/mac_pd_sap.c +++ b/source/MAC/IEEE802_15_4/mac_pd_sap.c @@ -148,6 +148,8 @@ static void mac_tx_done_state_set(protocol_interface_rf_mac_setup_s *rf_ptr, mac } rf_ptr->macRfRadioTxActive = false; rf_ptr->macTxProcessActive = false; + rf_ptr->mac_edfe_response_tx_active = false; + rf_ptr->mac_edfe_tx_active = false; mcps_sap_pd_confirm(rf_ptr); } @@ -175,7 +177,7 @@ int8_t mac_plme_cca_req(protocol_interface_rf_mac_setup_s *rf_mac_setup) uint8_t *buffer; uint16_t length; - if (rf_mac_setup->mac_ack_tx_active) { + if (rf_mac_setup->mac_ack_tx_active || (rf_mac_setup->mac_edfe_tx_active && rf_mac_setup->mac_edfe_response_tx_active)) { buffer = tx_buf->enhanced_ack_buf; length = tx_buf->ack_len; } else { @@ -447,6 +449,10 @@ static int8_t mac_data_interface_tx_done_cb(protocol_interface_rf_mac_setup_s *r return PHY_TX_NOT_ALLOWED; } + if (rf_ptr->mac_edfe_tx_active) { + return PHY_TX_ALLOWED; + } + 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); @@ -503,6 +509,21 @@ static int8_t mac_data_interface_tx_done_cb(protocol_interface_rf_mac_setup_s *r mac_data_ack_tx_finish(rf_ptr); return 0; } else { + + if (rf_ptr->mac_edfe_tx_active) { + if (rf_ptr->mac_edfe_response_tx_active) { + //Stop process here + rf_ptr->mac_edfe_response_tx_active = false; + rf_ptr->mac_edfe_tx_active = false; + if ((status == PHY_LINK_TX_DONE || status == PHY_LINK_TX_SUCCESS) && rf_ptr->mac_edfe_info->state == MAC_EDFE_FRAME_TX_FINAL_FRAME) { + //Set to idle + rf_ptr->mac_edfe_info->state = MAC_EDFE_FRAME_IDLE; + } + mac_data_ack_tx_finish(rf_ptr); + return 0; + } + } + // Do not update CCA count when Ack is received, it was already updated with PHY_LINK_TX_SUCCESS event // Do not update CCA count when CCA_OK is received, PHY_LINK_TX_SUCCESS will update it if ((status != PHY_LINK_TX_DONE) && (status != PHY_LINK_TX_DONE_PENDING) && (status != PHY_LINK_CCA_OK)) { @@ -671,7 +692,9 @@ static int8_t mac_pd_sap_validate_fcf(protocol_interface_rf_mac_setup_s *rf_ptr, switch (fcf_read->frametype) { case FC_DATA_FRAME: if (fcf_read->SrcAddrMode == MAC_ADDR_MODE_NONE) { - return -1; + if (fcf_read->DstAddrMode == MAC_ADDR_MODE_NONE || fcf_read->frameVersion != MAC_FRAME_VERSION_2015) { + return -1; + } } else if (fcf_read->DstAddrMode == MAC_ADDR_MODE_NONE && fcf_read->frameVersion != MAC_FRAME_VERSION_2015) { return -1; } @@ -821,6 +844,31 @@ static int8_t mac_pd_sap_generate_ack(protocol_interface_rf_mac_setup_s *rf_ptr, return mcps_generic_ack_build(rf_ptr, true); } +static int8_t mac_pd_sap_generate_edfe_response(protocol_interface_rf_mac_setup_s *rf_ptr, const mac_fcf_sequence_t *fcf_read, arm_pd_sap_generic_ind_t *pd_data_ind, mcps_edfe_response_t *response) +{ + + if (rf_ptr->mac_ack_tx_active) { + return -1; + } + + if (rf_ptr->mac_edfe_info->state == MAC_EDFE_FRAME_CONNECTED && rf_ptr->macRfRadioTxActive && rf_ptr->active_pd_data_request) { + timer_mac_stop(rf_ptr); + rf_ptr->macRfRadioTxActive = false; + rf_ptr->macTxProcessActive = false; + } + + if (mcps_generic_edfe_frame_init(rf_ptr, fcf_read, pd_data_ind->data_ptr, response)) { + return -1; + } + + if (response->wait_response) { + return mcps_edfe_data_request(rf_ptr, rf_ptr->active_pd_data_request); + } + + return mcps_generic_ack_build(rf_ptr, true); +} + + static mac_pre_parsed_frame_t *mac_pd_sap_allocate_receive_buffer(protocol_interface_rf_mac_setup_s *rf_ptr, const mac_fcf_sequence_t *fcf_read, arm_pd_sap_generic_ind_t *pd_data_ind) { mac_pre_parsed_frame_t *buffer = mcps_sap_pre_parsed_frame_buffer_get(pd_data_ind->data_ptr, pd_data_ind->data_len); @@ -953,6 +1001,77 @@ int8_t mac_pd_sap_data_cb(void *identifier, arm_phy_sap_msg_t *message) } return 0; } + if (rf_ptr->mac_edfe_enabled && !fcf_read.ackRequested && fcf_read.frameVersion == MAC_FRAME_VERSION_2015 && buffer->fcf_dsn.frametype == FC_DATA_FRAME) { + mcps_edfe_response_t response; + mac_api_t *mac_api = get_sw_mac_api(rf_ptr); + response.ie_elements.payloadIeList = buffer->payloadsIePtr; + response.ie_elements.payloadIeListLength = buffer->payloadsIeLength; + response.ie_elements.headerIeList = buffer->headerIePtr; + response.ie_elements.headerIeListLength = buffer->headerIeLength; + response.DstAddrMode = buffer->fcf_dsn.DstAddrMode; + response.SrcAddrMode = buffer->fcf_dsn.SrcAddrMode; + response.rssi = pd_data_ind->dbm; + if (buffer->fcf_dsn.SrcAddrMode == MAC_ADDR_MODE_64_BIT) { + mac_header_get_src_address(&fcf_read, pd_data_ind->data_ptr, response.Address); + } else { + memcpy(response.Address, rf_ptr->mac_edfe_info->PeerAddr, 8); + } + if (rf_ptr->mac_edfe_info->state == MAC_EDFE_FRAME_CONNECTING && rf_ptr->active_pd_data_request) { + response.message_handle = rf_ptr->active_pd_data_request->msduHandle; + response.use_message_handle_to_discover = true; + } else { + response.use_message_handle_to_discover = false; + } + + mac_api->edfe_ind_cb(mac_api, &response); + + response.DstAddrMode = MAC_ADDR_MODE_64_BIT; + switch (response.edfe_message_status) { + + case MCPS_EDFE_RESPONSE_FRAME: + if (buffer->fcf_dsn.SrcAddrMode == MAC_ADDR_MODE_64_BIT) { + memcpy(rf_ptr->mac_edfe_info->PeerAddr, response.Address, 8); + } + rf_ptr->mac_edfe_info->state = MAC_EDFE_FRAME_WAIT_DATA; + if (mac_pd_sap_generate_edfe_response(rf_ptr, &fcf_read, pd_data_ind, &response)) { + goto ERROR_HANDLER; + } + break; + + case MCPS_EDFE_TX_FRAME: + rf_ptr->mac_edfe_info->state = MAC_EDFE_FRAME_CONNECTED; + if (mac_pd_sap_generate_edfe_response(rf_ptr, &fcf_read, pd_data_ind, &response)) { + goto ERROR_HANDLER; + } + break; + + case MCPS_EDFE_FINAL_FRAME_TX: + if (mac_pd_sap_generate_edfe_response(rf_ptr, &fcf_read, pd_data_ind, &response)) { + goto ERROR_HANDLER; + } + rf_ptr->mac_edfe_info->state = MAC_EDFE_FRAME_TX_FINAL_FRAME; + break; + + case MCPS_EDFE_FINAL_FRAME_RX: + //Mark session closed + rf_ptr->mac_edfe_info->state = MAC_EDFE_FRAME_IDLE; + rf_ptr->mac_edfe_tx_active = false; + if (mac_data_interface_tx_done_by_ack_cb(rf_ptr, buffer)) { + mcps_sap_pre_parsed_frame_buffer_free(buffer); + } + return 0; + + case MCPS_EDFE_MALFORMED_FRAME: + goto ERROR_HANDLER; + + case MCPS_EDFE_NORMAL_FRAME: + default: + break; + } + + } + + } } if (!buffer) { diff --git a/source/MAC/IEEE802_15_4/sw_mac.c b/source/MAC/IEEE802_15_4/sw_mac.c index 25e6e9fa508a..02d2b79cddba 100644 --- a/source/MAC/IEEE802_15_4/sw_mac.c +++ b/source/MAC/IEEE802_15_4/sw_mac.c @@ -54,6 +54,7 @@ static int8_t ns_sw_mac_initialize(mac_api_t *api, mcps_data_confirm *mcps_data_ mcps_data_indication *mcps_data_ind_cb, mcps_purge_confirm *purge_conf_cb, mlme_confirm *mlme_conf_callback, mlme_indication *mlme_ind_callback, int8_t parent_id); static int8_t ns_sw_mac_api_enable_mcps_ext(mac_api_t *api, mcps_data_indication_ext *data_ind_cb, mcps_data_confirm_ext *data_cnf_cb, mcps_ack_data_req_ext *ack_data_req_cb); +static int8_t ns_sw_mac_api_enable_edfe_ext(mac_api_t *api, mcps_edfe_handler *edfe_ind_cb); static void mlme_req(const mac_api_t *api, mlme_primitive id, const void *data); static void mcps_req(const mac_api_t *api, const mcps_data_req_t *data); @@ -67,6 +68,7 @@ static int8_t sw_mac_net_phy_tx_done(int8_t driver_id, uint8_t tx_handle, phy_li static int8_t sw_mac_net_phy_config_parser(int8_t driver_id, const uint8_t *data, uint16_t length); static int8_t sw_mac_storage_decription_sizes_get(const mac_api_t *api, mac_description_storage_size_t *buffer); + static int8_t sw_mac_storage_decription_sizes_get(const mac_api_t *api, mac_description_storage_size_t *buffer) { if (!api || !buffer || api != mac_store.mac_api) { @@ -127,6 +129,7 @@ mac_api_t *ns_sw_mac_create(int8_t rf_driver_id, mac_description_storage_size_t this->mac_initialize = &ns_sw_mac_initialize; this->mac_mcps_extension_enable = &ns_sw_mac_api_enable_mcps_ext; + this->mac_mcps_edfe_enable = &ns_sw_mac_api_enable_edfe_ext; this->mlme_req = &mlme_req; this->mcps_data_req = &mcps_req; this->mcps_data_req_ext = &mcps_req_ext; @@ -314,6 +317,33 @@ static int8_t ns_sw_mac_api_enable_mcps_ext(mac_api_t *api, mcps_data_indication return 0; } +static int8_t ns_sw_mac_api_enable_edfe_ext(mac_api_t *api, mcps_edfe_handler *edfe_ind_cb) +{ + //TODO: Find from linked list instead + if (api != mac_store.mac_api) { + return -1; + } + + mac_api_t *cur = mac_store.mac_api; + + if (!mac_store.setup->mac_extension_enabled) { + return -1; + } + cur->edfe_ind_cb = edfe_ind_cb; + if (edfe_ind_cb) { + ns_dyn_mem_free(mac_store.setup->mac_edfe_info); + mac_store.setup->mac_edfe_info = ns_dyn_mem_alloc(sizeof(mac_mcps_edfe_frame_info_t)); + if (!mac_store.setup->mac_edfe_info) { + return -2; + } + mac_store.setup->mac_edfe_info->state = MAC_EDFE_FRAME_IDLE; + mac_store.setup->mac_edfe_enabled = true; + } else { + mac_store.setup->mac_edfe_enabled = false; + } + return 0; +} + mac_api_t *get_sw_mac_api(protocol_interface_rf_mac_setup_s *setup) { if (!mac_store.mac_api || mac_store.mac_api->parent_id == -1 || mac_store.setup != setup) { diff --git a/test/nanostack/unittest/6LoWPAN/ws_ie_lib/test_ws_ie_lib.c b/test/nanostack/unittest/6LoWPAN/ws_ie_lib/test_ws_ie_lib.c index 3b772cc676fa..a2976b99b55f 100644 --- a/test/nanostack/unittest/6LoWPAN/ws_ie_lib/test_ws_ie_lib.c +++ b/test/nanostack/unittest/6LoWPAN/ws_ie_lib/test_ws_ie_lib.c @@ -44,8 +44,11 @@ bool test_ws_ie_lib_header() return false; } - ptr = ws_wh_fc_write(test_buf, 10); - if (ptr != &test_buf[4] || test_buf[3] != 10 || test_buf[2] != WH_IE_FC_TYPE) { + ws_fc_ie_t fc_ie; + fc_ie.tx_flow_ctrl = 50; + fc_ie.rx_flow_ctrl = 255; + ptr = ws_wh_fc_write(test_buf, &fc_ie); + if (ptr != &test_buf[5] || test_buf[4] != 255 || test_buf[3] != 50 || test_buf[2] != WH_IE_FC_TYPE) { return false; } diff --git a/test/nanostack/unittest/6LoWPAN/ws_llc_data_service/test_ws_llc_data_service.c b/test/nanostack/unittest/6LoWPAN/ws_llc_data_service/test_ws_llc_data_service.c index 50c1afbe9256..9c98cdbd9f63 100644 --- a/test/nanostack/unittest/6LoWPAN/ws_llc_data_service/test_ws_llc_data_service.c +++ b/test/nanostack/unittest/6LoWPAN/ws_llc_data_service/test_ws_llc_data_service.c @@ -46,6 +46,8 @@ static mcps_data_indication_ext *data_indication_cb; +static mcps_edfe_response_t *data_enhanced_cb; + static mcps_data_confirm_ext *data_confirmation_cb; static protocol_interface_info_entry_t interface; @@ -111,6 +113,13 @@ static int8_t test_mac_api_enable_mcps_ext(mac_api_t *api, return 0; } +static int8_t test_mac_api_enable_mcps_edfe_ext(mac_api_t *api, + mcps_edfe_handler *enhanced_ind_cb) +{ + data_enhanced_cb = enhanced_ind_cb; + return 0; +} + static void register_mpx_user(mpx_api_t *mpx_api) { mpx_api->mpx_user_registration(mpx_api, &test_mpx_data_confirm, &test_mpx_data_indication, 0xA0ED); @@ -138,6 +147,7 @@ static void interface_api_init(mac_api_t *api) api->mcps_purge_req = &test_mcps_purge_request; api->mcps_data_req_ext = &test_mcps_data_request_ext; api->mac_mcps_extension_enable = &test_mac_api_enable_mcps_ext; + api->mac_mcps_edfe_enable = &test_mac_api_enable_mcps_edfe_ext; } diff --git a/test/nanostack/unittest/mac/mac_pd_sap/Makefile b/test/nanostack/unittest/mac/mac_pd_sap/Makefile index 344ba7e2e374..41e17bb44cba 100644 --- a/test/nanostack/unittest/mac/mac_pd_sap/Makefile +++ b/test/nanostack/unittest/mac/mac_pd_sap/Makefile @@ -12,7 +12,7 @@ TEST_SRC_FILES = \ test_mac_pd_sap.c \ ../../stub/mbed_trace_stub.c \ ../../stub/nsdynmemLIB_stub.c \ - ../../stub/common_functions_stub.c \ + ../../stub/6lowpan_mesh_stub.c \ ../../stub/event_stub.c \ ../../stub/ns_timer_stub.c \ ../../stub/platform_stub.c \ @@ -22,7 +22,6 @@ TEST_SRC_FILES = \ ../../stub/mac_timer_stub.c \ ../../stub/mac_filter_stub.c \ ../../stub/mac_cca_threshold_stub.c \ - ../../stub/protocol_core_stub.c \ ../../stub/randLIB_stub.c \ ../../stub/mac_mlme_stub.c \ ../../stub/buffer_dyn_stub.c \ diff --git a/test/nanostack/unittest/stub/6lowpan_mesh_stub.c b/test/nanostack/unittest/stub/6lowpan_mesh_stub.c index 4ef2a0f1bc02..ee36e018365b 100644 --- a/test/nanostack/unittest/stub/6lowpan_mesh_stub.c +++ b/test/nanostack/unittest/stub/6lowpan_mesh_stub.c @@ -39,6 +39,8 @@ protocol_interface_info_entry_t *protocol_stack_interface_info_get(nwk_interface extern COMMON_FUNCTIONS_FN uint16_t common_read_16_bit(const uint8_t data_buf[__static 2]); extern COMMON_FUNCTIONS_FN uint8_t *common_write_16_bit(uint16_t value, uint8_t ptr[__static 2]); extern COMMON_FUNCTIONS_FN uint8_t *common_write_16_bit_inverse(uint16_t value, uint8_t ptr[__static 2]); +extern COMMON_FUNCTIONS_FN uint8_t *common_write_32_bit(uint32_t value, uint8_t ptr[__static 4]); +extern COMMON_FUNCTIONS_FN uint32_t common_read_32_bit(const uint8_t data_buf[__static 4]); bool nwk_interface_compare_mac_address(protocol_interface_info_entry_t *cur, uint_fast8_t addrlen, const uint8_t addr[]) { diff --git a/test/nanostack/unittest/stub/mac_mcps_sap_stub.c b/test/nanostack/unittest/stub/mac_mcps_sap_stub.c index 7ab34db72872..2fe48a69c144 100644 --- a/test/nanostack/unittest/stub/mac_mcps_sap_stub.c +++ b/test/nanostack/unittest/stub/mac_mcps_sap_stub.c @@ -191,3 +191,13 @@ void mac_cca_threshold_event_send(protocol_interface_rf_mac_setup_s *rf_ptr, uin { } + +int8_t mcps_generic_edfe_frame_init(struct protocol_interface_rf_mac_setup *rf_ptr, const mac_fcf_sequence_t *fcf, const uint8_t *data_ptr, const struct mcps_edfe_response_s *response) +{ + return 0; +} + +int8_t mcps_edfe_data_request(struct protocol_interface_rf_mac_setup *rf_ptr, mac_pre_build_frame_t *buffer) +{ + return 0; +} diff --git a/test/nanostack/unittest/stub/ws_ie_lib_stub.c b/test/nanostack/unittest/stub/ws_ie_lib_stub.c index eb2c2ebe7b03..20f6a4d9c629 100644 --- a/test/nanostack/unittest/stub/ws_ie_lib_stub.c +++ b/test/nanostack/unittest/stub/ws_ie_lib_stub.c @@ -63,12 +63,17 @@ bool ws_wh_rsl_read(uint8_t *data, uint16_t length, int8_t *rsl) } -uint8_t *ws_wh_fc_write(uint8_t *ptr, uint8_t flow_ctrl) +uint8_t *ws_wh_fc_write(uint8_t *ptr, struct ws_fc_ie *fc_ie) { - ptr += 4; + ptr += 5; return ptr; } +bool ws_wh_fc_read(uint8_t *data, uint16_t length, struct ws_fc_ie *fc_ie) +{ + return 0; +} + uint8_t *ws_wh_rsl_write(uint8_t *ptr, uint8_t rsl) { ptr += 4; From 7938795f2f5c20461f6923d62b8a96cd612f7645 Mon Sep 17 00:00:00 2001 From: Juha Heiskanen Date: Thu, 30 Jul 2020 16:39:10 +0300 Subject: [PATCH 15/30] Fixed new PD data request for check if EDFE exchange is active. --- source/MAC/IEEE802_15_4/mac_mcps_sap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/MAC/IEEE802_15_4/mac_mcps_sap.c b/source/MAC/IEEE802_15_4/mac_mcps_sap.c index b464020b4552..8ae296fac741 100644 --- a/source/MAC/IEEE802_15_4/mac_mcps_sap.c +++ b/source/MAC/IEEE802_15_4/mac_mcps_sap.c @@ -2096,7 +2096,7 @@ static int8_t mcps_pd_data_request(protocol_interface_rf_mac_setup_s *rf_ptr, ma return -1; } rf_ptr->macTxRequestAck = buffer->WaitResponse; - if (!rf_ptr->mac_ack_tx_active) { + if (!rf_ptr->mac_ack_tx_active && !rf_ptr->mac_edfe_tx_active) { return mcps_pd_data_cca_trig(rf_ptr, buffer); } else { return 0; From af8438e65e7b8e1851b29dc4ad930f15e9a6d8aa Mon Sep 17 00:00:00 2001 From: Jarkko Paso Date: Mon, 3 Aug 2020 10:48:14 +0300 Subject: [PATCH 16/30] Timing tool traces (#2401) * Added FHSS timing tool traces * Fixed TX done trace * timing tool: use TIMING_TOOL_TRACES flag for traces --- source/MAC/IEEE802_15_4/mac_pd_sap.c | 28 +++++++++++++++++++++++++++- source/Service_Libs/fhss/fhss_ws.c | 16 ++++++++++++++++ 2 files changed, 43 insertions(+), 1 deletion(-) diff --git a/source/MAC/IEEE802_15_4/mac_pd_sap.c b/source/MAC/IEEE802_15_4/mac_pd_sap.c index 459474384607..cee933428af6 100644 --- a/source/MAC/IEEE802_15_4/mac_pd_sap.c +++ b/source/MAC/IEEE802_15_4/mac_pd_sap.c @@ -36,6 +36,9 @@ #include "MAC/IEEE802_15_4/mac_mcps_sap.h" #include "MAC/IEEE802_15_4/mac_cca_threshold.h" #include "MAC/rf_driver_storage.h" +#include "ns_trace.h" + +#define TRACE_GROUP "mPDs" /* Define TX Timeot Period */ // Hardcoded to 1200ms. Should be changed dynamic: (FHSS) channel retries needs longer timeout @@ -373,6 +376,9 @@ static void mac_sap_cca_fail_cb(protocol_interface_rf_mac_setup_s *rf_ptr, uint static void mac_sap_no_ack_cb(protocol_interface_rf_mac_setup_s *rf_ptr) { +#ifdef TIMING_TOOL_TRACES + tr_info("%u no_ack", mac_mcps_sap_get_phy_timestamp(rf_ptr)); +#endif rf_ptr->macRfRadioTxActive = false; if (rf_ptr->mac_tx_retry < rf_ptr->mac_mlme_retry_max) { rf_ptr->mac_cca_retry = 0; @@ -438,6 +444,9 @@ static int8_t mac_data_interface_tx_done_cb(protocol_interface_rf_mac_setup_s *r if (rf_ptr->mac_ack_tx_active) { //Accept direct non crypted acks and crypted only if neighbor is at list if (rf_ptr->ack_tx_possible) { +#ifdef TIMING_TOOL_TRACES + tr_info("%u TX_start %u", mac_mcps_sap_get_phy_timestamp(rf_ptr), rf_ptr->mac_channel); +#endif return PHY_TX_ALLOWED; } @@ -454,6 +463,9 @@ 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)) { +#ifdef TIMING_TOOL_TRACES + tr_info("%u TX_start %u", mac_mcps_sap_get_phy_timestamp(rf_ptr), rf_ptr->mac_channel); +#endif 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) { @@ -501,12 +513,17 @@ static int8_t mac_data_interface_tx_done_cb(protocol_interface_rf_mac_setup_s *r return PHY_RESTART_CSMA; } } - +#ifdef TIMING_TOOL_TRACES + tr_info("%u TX_start %u", mac_mcps_sap_get_phy_timestamp(rf_ptr), rf_ptr->mac_channel); +#endif return 0; } if (rf_ptr->mac_ack_tx_active) { mac_data_ack_tx_finish(rf_ptr); +#ifdef TIMING_TOOL_TRACES + tr_info("%u TX_done", mac_mcps_sap_get_phy_timestamp(rf_ptr)); +#endif return 0; } else { @@ -531,6 +548,11 @@ static int8_t mac_data_interface_tx_done_cb(protocol_interface_rf_mac_setup_s *r * PHY_LINK_TX_FAIL either happened during transmission or when waiting Ack -> we must use the CCA count given by PHY. */ if ((cca_retry == 0) && (status != PHY_LINK_TX_FAIL)) { +#ifdef TIMING_TOOL_TRACES + if (status != PHY_LINK_CCA_FAIL) { + tr_info("%u TX_done", mac_mcps_sap_get_phy_timestamp(rf_ptr)); + } +#endif cca_retry = 1; } rf_ptr->mac_tx_status.cca_cnt += cca_retry; @@ -970,6 +992,10 @@ int8_t mac_pd_sap_data_cb(void *identifier, arm_phy_sap_msg_t *message) if (pd_data_ind->data_len < 3) { return -1; } +#ifdef TIMING_TOOL_TRACES + tr_info("%u RX_start", mac_pd_sap_get_phy_rx_time(rf_ptr)); + tr_info("%u RX_done", mac_mcps_sap_get_phy_timestamp(rf_ptr)); +#endif 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/Service_Libs/fhss/fhss_ws.c b/source/Service_Libs/fhss/fhss_ws.c index 5ccaa6ce6500..e11a3760a100 100644 --- a/source/Service_Libs/fhss/fhss_ws.c +++ b/source/Service_Libs/fhss/fhss_ws.c @@ -343,6 +343,9 @@ static void fhss_broadcast_handler(const fhss_api_t *fhss_api, uint16_t delay) #ifdef FHSS_CHANNEL_DEBUG tr_info("%"PRIu32" UC %u", fhss_structure->callbacks.read_timestamp(fhss_structure->fhss_api), fhss_structure->rx_channel); #endif /*FHSS_CHANNEL_DEBUG*/ +#ifdef TIMING_TOOL_TRACES + tr_info("%u UC_change %u", fhss_structure->callbacks.read_timestamp(fhss_structure->fhss_api), next_channel); +#endif } fhss_structure->callbacks.change_channel(fhss_structure->fhss_api, next_channel); #ifdef FHSS_CHANNEL_DEBUG_CBS @@ -350,6 +353,13 @@ static void fhss_broadcast_handler(const fhss_api_t *fhss_api, uint16_t delay) fhss_bc_switch(); } #endif /*FHSS_CHANNEL_DEBUG_CBS*/ +#ifdef TIMING_TOOL_TRACES + if (fhss_structure->ws->is_on_bc_channel == true) { + tr_info("%u BC_start %u", fhss_structure->callbacks.read_timestamp(fhss_structure->fhss_api), next_channel); + } else { + tr_info("%u BC_done", fhss_structure->callbacks.read_timestamp(fhss_structure->fhss_api)); + } +#endif } static int own_floor(float value) @@ -392,6 +402,9 @@ static void fhss_event_timer_cb(int8_t timer_id, uint16_t slots) } if (queue_size) { fhss_structure->callbacks.tx_poll(fhss_structure->fhss_api); +#ifdef TIMING_TOOL_TRACES + tr_info("%u TX_poll", fhss_structure->callbacks.read_timestamp(fhss_structure->fhss_api)); +#endif } } @@ -517,6 +530,9 @@ static void fhss_ws_update_uc_channel_callback(fhss_structure_t *fhss_structure) #ifdef FHSS_CHANNEL_DEBUG tr_info("%"PRIu32" UC %u %u", fhss_structure->callbacks.read_timestamp(fhss_structure->fhss_api), next_channel, fhss_structure->ws->uc_slot); #endif /*FHSS_CHANNEL_DEBUG*/ +#ifdef TIMING_TOOL_TRACES + tr_info("%u UC_change %u", fhss_structure->callbacks.read_timestamp(fhss_structure->fhss_api), next_channel); +#endif fhss_structure->callbacks.change_channel(fhss_structure->fhss_api, next_channel); #ifdef FHSS_CHANNEL_DEBUG_CBS if (fhss_uc_switch) { From 3fc1ae221bfc7297b806c5a546dafcf7fb55c065 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mika=20Lepp=C3=A4nen?= Date: Mon, 3 Aug 2020 22:49:12 +0300 Subject: [PATCH 17/30] BR EUI-64 is now selected for 4WH using PMKID on 4WH Message 1 When 4WH starts and PMKID is validated the BR EUI-64 used on validation can be either from previous succesful 4WH authentication with the BR (PTK EUI-64) or it can be received from EAPOL target during TLS or 4WH. In case BR EUI-64 has changed since last succesful 4WH, the PMKID is now validated against both the PTK EUI-64 and the received EUI-64. If either one matches to PMKID that is used for the 4WH negotiation. --- .../fwh_sec_prot/auth_fwh_sec_prot.c | 2 +- .../fwh_sec_prot/supp_fwh_sec_prot.c | 19 ++++++++++++++++--- .../protocols/key_sec_prot/key_sec_prot.c | 4 ++-- source/Security/protocols/sec_prot_lib.c | 12 ++++++++++-- source/Security/protocols/sec_prot_lib.h | 4 +++- 5 files changed, 32 insertions(+), 9 deletions(-) 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 285a75db8e3c..073cd9ef5388 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 @@ -234,7 +234,7 @@ static int8_t auth_fwh_sec_prot_message_send(sec_prot_t *prot, fwh_sec_prot_msg_ switch (msg) { case FWH_MESSAGE_1: { uint8_t pmkid[PMKID_LEN]; - if (sec_prot_lib_pmkid_generate(prot, pmkid, true) < 0) { + if (sec_prot_lib_pmkid_generate(prot, pmkid, true, false, NULL) < 0) { ns_dyn_mem_free(kde_start); return -1; } 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 ef3e9bd99152..41b6227fe862 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 @@ -473,7 +473,7 @@ static int8_t supp_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]; - prot->addr_get(prot, local_eui64, data->remote_eui64); + prot->addr_get(prot, local_eui64, NULL); uint8_t *remote_nonce = data->recv_eapol_pdu.msg.key.key_nonce; if (!remote_nonce) { @@ -553,11 +553,24 @@ static int8_t supp_fwh_kde_handle(sec_prot_t *prot) if (kde_pmkid_read(kde, kde_len, recv_pmkid) < 0) { goto error; } - if (sec_prot_lib_pmkid_generate(prot, calc_pmkid, false) < 0) { + /* Fix the used EUI-64 for the length of the 4WH handshake using the PMKID. Try + * first primary BR EUI-64 (e.g. validated by PTK procedure) for PMKID. + */ + if (sec_prot_lib_pmkid_generate(prot, calc_pmkid, false, false, data->remote_eui64) < 0) { goto error; } + // If PMKID is not valid if (memcmp(recv_pmkid, calc_pmkid, PMKID_LEN) != 0) { - goto error; + tr_info("PMKID mismatch, 1st EUI-64: %s", tr_array(data->remote_eui64, 8)); + // Try alternate EUI-64 (e.g. received during security handshake) + if (sec_prot_lib_pmkid_generate(prot, calc_pmkid, false, true, data->remote_eui64) < 0) { + goto error; + } + // If PMKID is not valid, fail + if (memcmp(recv_pmkid, calc_pmkid, PMKID_LEN) != 0) { + tr_error("PMKID mismatch, 2nd EUI-64: %s", tr_array(data->remote_eui64, 8)); + goto error; + } } } break; 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 ad75cf5853e1..ec3600e84cf6 100644 --- a/source/Security/protocols/key_sec_prot/key_sec_prot.c +++ b/source/Security/protocols/key_sec_prot/key_sec_prot.c @@ -171,7 +171,7 @@ static int8_t key_sec_prot_initial_key_send(sec_prot_t *prot, sec_prot_keys_t *s uint8_t *pmk = sec_prot_keys_pmk_get(sec_keys); uint8_t pmkid[PMKID_LEN]; if (pmk) { - if (sec_prot_lib_pmkid_generate(prot, pmkid, false) >= 0) { + if (sec_prot_lib_pmkid_generate(prot, pmkid, false, false, NULL) >= 0) { kde_len += KDE_PMKID_LEN; } else { pmk = NULL; @@ -270,7 +270,7 @@ static int8_t key_sec_prot_receive(sec_prot_t *prot, void *pdu, uint16_t size) 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 (sec_prot_lib_pmkid_generate(prot, pmkid, true, false, NULL) >= 0) { if (memcmp(remote_keyid, pmkid, PMKID_LEN) == 0) { prot->sec_keys->pmk_mismatch = false; } diff --git a/source/Security/protocols/sec_prot_lib.c b/source/Security/protocols/sec_prot_lib.c index 1df7d5dac33a..bc85d0b9f1b0 100644 --- a/source/Security/protocols/sec_prot_lib.c +++ b/source/Security/protocols/sec_prot_lib.c @@ -445,7 +445,7 @@ int8_t sec_prot_lib_mic_validate(uint8_t *ptk, uint8_t *mic, uint8_t *pdu, uint8 return 0; } -int8_t sec_prot_lib_pmkid_generate(sec_prot_t *prot, uint8_t *pmkid, bool is_auth) +int8_t sec_prot_lib_pmkid_generate(sec_prot_t *prot, uint8_t *pmkid, bool is_auth, bool alt_remote_eui64_use, uint8_t *used_remote_eui64) { uint8_t *pmk = sec_prot_keys_pmk_get(prot->sec_keys); if (!pmk) { @@ -456,14 +456,22 @@ int8_t sec_prot_lib_pmkid_generate(sec_prot_t *prot, uint8_t *pmkid, bool is_aut uint8_t remote_eui64[8]; // Tries to get the EUI-64 that is validated by PTK procedure or bound to supplicant entry uint8_t *remote_eui64_ptr = sec_prot_keys_ptk_eui_64_get(prot->sec_keys); - if (remote_eui64_ptr) { + if (remote_eui64_ptr && !alt_remote_eui64_use) { memcpy(remote_eui64, remote_eui64_ptr, 8); prot->addr_get(prot, local_eui64, NULL); } else { + // If request is for alternative EUI-64, but PTK EUI-64 is not present, returns failure + if (alt_remote_eui64_use && !remote_eui64_ptr) { + return -1; + } // If validated EUI-64 is not present, use the remote EUI-64 prot->addr_get(prot, local_eui64, remote_eui64); } + if (used_remote_eui64 != NULL) { + memcpy(used_remote_eui64, remote_eui64, 8); + } + if (is_auth) { return sec_prot_lib_pmkid_calc(pmk, local_eui64, remote_eui64, pmkid); } else { diff --git a/source/Security/protocols/sec_prot_lib.h b/source/Security/protocols/sec_prot_lib.h index 1ade05bd44e9..4d7fd088eeea 100644 --- a/source/Security/protocols/sec_prot_lib.h +++ b/source/Security/protocols/sec_prot_lib.h @@ -162,11 +162,13 @@ int8_t sec_prot_lib_mic_validate(uint8_t *ptk, uint8_t *mic, uint8_t *pdu, uint8 * \param prot security protocol * \param pmkid PMK ID * \param is_auth set for authenticator + * \param alt_remote_eui64_use use alternative remote EUI-64 if available + * \param used_remote_eui64 remote EUI-64 used on PMKID generation * * \return < 0 failure * \return >= 0 success */ -int8_t sec_prot_lib_pmkid_generate(sec_prot_t *prot, uint8_t *pmkid, bool is_auth); +int8_t sec_prot_lib_pmkid_generate(sec_prot_t *prot, uint8_t *pmkid, bool is_auth, bool alt_remote_eui64_use, uint8_t *used_remote_eui64); /** * sec_prot_lib_ptkid_generate generate PTK ID from PTK From 89826ce8af6772ac1ad5df0a7eb2c7671d07d6ea Mon Sep 17 00:00:00 2001 From: Jarkko Paso Date: Thu, 6 Aug 2020 12:34:27 +0300 Subject: [PATCH 18/30] Iotthd 4224 (#2403) * FHSS WS: use large retry backoff when broadcast schedule unknown * FHSS WS: Use large randomized retry backoff when TX/RX slots unknown --- source/Service_Libs/fhss/fhss_ws.c | 11 ++++++++++- source/Service_Libs/fhss/fhss_ws.h | 1 + 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/source/Service_Libs/fhss/fhss_ws.c b/source/Service_Libs/fhss/fhss_ws.c index e11a3760a100..05235ca0256b 100644 --- a/source/Service_Libs/fhss/fhss_ws.c +++ b/source/Service_Libs/fhss/fhss_ws.c @@ -295,6 +295,7 @@ static void fhss_broadcast_handler(const fhss_api_t *fhss_api, uint16_t delay) // stop broadcast schedule fhss_structure->ws->is_on_bc_channel = false; fhss_structure->ws->synchronization_time = 0; + fhss_structure->ws->broadcast_timer_running = false; return; } if (fhss_structure->ws->is_on_bc_channel == false) { @@ -479,6 +480,7 @@ static int16_t fhss_ws_synch_state_set_callback(const fhss_api_t *api, fhss_stat // Start broadcast schedule when BC intervals are known if (fhss_broadcast_interval && fhss_bc_dwell_interval) { fhss_broadcast_handler(fhss_structure->fhss_api, 0); + fhss_structure->ws->broadcast_timer_running = true; } // Start unicast schedule if ((fhss_structure->ws->fhss_configuration.ws_uc_channel_function != WS_FIXED_CHANNEL)) { @@ -491,6 +493,7 @@ static int16_t fhss_ws_synch_state_set_callback(const fhss_api_t *api, fhss_stat eventOS_callback_timer_stop(fhss_structure->fhss_event_timer); fhss_stop_timer(fhss_structure, fhss_unicast_handler); fhss_stop_timer(fhss_structure, fhss_broadcast_handler); + fhss_structure->ws->broadcast_timer_running = false; } fhss_structure->fhss_state = fhss_state; @@ -853,8 +856,13 @@ static uint32_t fhss_ws_get_retry_period_callback(const fhss_api_t *api, uint8_t if (!fhss_structure) { return return_value; } + // We don't know the broadcast schedule, use large backoff with MAC retries + if (fhss_structure->ws->broadcast_timer_running == false) { + return 100000; + } + // We don't know the TX/RX slots, use randomised large backoff with MAC retries if (fhss_structure->own_hop == 0xff) { - return return_value; + return ((uint32_t) randLIB_get_random_in_range(50, 150) * 1000); } if (fhss_structure->ws->is_on_bc_channel == true) { return return_value; @@ -955,6 +963,7 @@ int fhss_ws_set_parent(fhss_structure_t *fhss_structure, const uint8_t eui64[8], timeout -= MS_TO_US(bc_timing_info->broadcast_interval - bc_timing_info->broadcast_dwell_interval); } fhss_ws_start_timer(fhss_structure, timeout, fhss_broadcast_handler); + fhss_structure->ws->broadcast_timer_running = true; uint16_t slots_since_reception = (bc_timing_info->broadcast_interval_offset + time_from_reception_ms) / bc_timing_info->broadcast_interval; // TODO: Calculate drift error fhss_structure->ws->fhss_configuration.fhss_bc_dwell_interval = bc_timing_info->broadcast_dwell_interval; diff --git a/source/Service_Libs/fhss/fhss_ws.h b/source/Service_Libs/fhss/fhss_ws.h index f4d27c1bff09..26b8f4c969fe 100644 --- a/source/Service_Libs/fhss/fhss_ws.h +++ b/source/Service_Libs/fhss/fhss_ws.h @@ -41,6 +41,7 @@ struct fhss_ws { int16_t *tr51_channel_table; uint8_t *tr51_output_table; bool unicast_timer_running; + bool broadcast_timer_running; bool is_on_bc_channel; struct fhss_ws_configuration fhss_configuration; const struct broadcast_timing_info *parent_bc_info; From 66f1bffb4797d6dfe51bed4ee94e01c438fd264e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mika=20Lepp=C3=A4nen?= Date: Tue, 4 Aug 2020 07:18:43 +0300 Subject: [PATCH 19/30] Added storing of PAN version to NVM on BR PAN version is now stored in frame counters storage to NVM. Frame counters storage is written at least once a day to NVM which is frequent enough cycle for PAN version number update. --- source/6LoWPAN/ws/ws_bbr_api.c | 3 +++ source/6LoWPAN/ws/ws_bootstrap.c | 25 +++++++++++++++-------- source/6LoWPAN/ws/ws_common.c | 1 + source/6LoWPAN/ws/ws_common_defines.h | 1 + source/6LoWPAN/ws/ws_config.h | 4 ++++ source/6LoWPAN/ws/ws_pae_controller.c | 22 ++++++++++++-------- source/6LoWPAN/ws/ws_pae_controller.h | 6 ++++-- source/6LoWPAN/ws/ws_pae_nvm_data.c | 9 ++++++-- source/6LoWPAN/ws/ws_pae_nvm_data.h | 10 +++++---- source/Security/protocols/sec_prot_keys.h | 1 + 10 files changed, 57 insertions(+), 25 deletions(-) diff --git a/source/6LoWPAN/ws/ws_bbr_api.c b/source/6LoWPAN/ws/ws_bbr_api.c index f841be8144a5..8ae71ed6158d 100644 --- a/source/6LoWPAN/ws/ws_bbr_api.c +++ b/source/6LoWPAN/ws/ws_bbr_api.c @@ -573,6 +573,9 @@ void ws_bbr_pan_version_increase(protocol_interface_info_entry_t *cur) cur->ws_info->pan_information.pan_version++; // Inconsistent for border router to make information distribute faster ws_bootstrap_configuration_trickle_reset(cur); + + // Indicate new pan version to PAE controller + ws_pae_controller_nw_info_set(cur, cur->ws_info->network_pan_id, cur->ws_info->pan_information.pan_version, cur->ws_info->cfg->gen.network_name); } void ws_bbr_seconds_timer(protocol_interface_info_entry_t *cur, uint32_t seconds) diff --git a/source/6LoWPAN/ws/ws_bootstrap.c b/source/6LoWPAN/ws/ws_bootstrap.c index e14746fe738c..e4bee629dc7c 100644 --- a/source/6LoWPAN/ws/ws_bootstrap.c +++ b/source/6LoWPAN/ws/ws_bootstrap.c @@ -94,7 +94,7 @@ 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_nw_info_updated(protocol_interface_info_entry_t *interface_ptr, uint16_t pan_id, uint16_t pan_version, char *network_name); static void ws_bootstrap_authentication_completed(protocol_interface_info_entry_t *cur, auth_result_e result, uint8_t *target_eui_64); static const uint8_t *ws_bootstrap_authentication_next_target(protocol_interface_info_entry_t *cur, const uint8_t *previous_eui_64, uint16_t *pan_id); static void ws_bootstrap_pan_version_increment(protocol_interface_info_entry_t *cur); @@ -2312,7 +2312,7 @@ static void ws_bootstrap_rpl_callback(rpl_event_t event, void *handle) // Set both own port and border router port to 10253 ws_eapol_relay_start(cur, EAPOL_RELAY_SOCKET_PORT, dodag_info.dodag_id, EAPOL_RELAY_SOCKET_PORT); // Set network information to PAE - ws_pae_controller_nw_info_set(cur, cur->ws_info->network_pan_id, cur->ws_info->cfg->gen.network_name); + ws_pae_controller_nw_info_set(cur, cur->ws_info->network_pan_id, cur->ws_info->pan_information.pan_version, cur->ws_info->cfg->gen.network_name); // Network key is valid, indicate border router IID to controller ws_pae_controller_nw_key_valid(cur, &dodag_info.dodag_id[8]); @@ -2672,7 +2672,7 @@ static void ws_bootstrap_start_discovery(protocol_interface_info_entry_t *cur) static void ws_bootstrap_start_authentication(protocol_interface_info_entry_t *cur) { // Set PAN ID and network name to controller - ws_pae_controller_nw_info_set(cur, cur->ws_info->network_pan_id, cur->ws_info->cfg->gen.network_name); + ws_pae_controller_nw_info_set(cur, cur->ws_info->network_pan_id, cur->ws_info->pan_information.pan_version, cur->ws_info->cfg->gen.network_name); ws_pae_controller_authenticate(cur); } @@ -2720,22 +2720,26 @@ 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) +static void ws_bootstrap_nw_info_updated(protocol_interface_info_entry_t *cur, uint16_t pan_id, uint16_t pan_version, char *network_name) { - /* For border router, the PAE controller reads pan_id and network name from storage. + /* For border router, the PAE controller reads PAN ID, PAN version and network name from storage. * If they are set, takes them into use here. */ if (cur->bootsrap_mode == ARM_NWK_BOOTSRAP_MODE_6LoWPAN_BORDER_ROUTER) { - // Get pad_id and network name + // Get PAN 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 PAN ID has not been set, set it if (gen_cfg.network_pan_id == 0xffff) { gen_cfg.network_pan_id = pan_id; + // Sets PAN version + cur->ws_info->pan_information.pan_version = pan_version; + cur->ws_info->pan_information.pan_version_set = true; } + // If network name has not been set, set it if (strlen(gen_cfg.network_name) == 0) { strncpy(gen_cfg.network_name, network_name, 32); @@ -3082,8 +3086,11 @@ static void ws_bootstrap_event_handler(arm_event_s *event) } else { cur->ws_info->network_pan_id = cur->ws_info->cfg->gen.network_pan_id; } + if (!cur->ws_info->pan_information.pan_version_set) { + cur->ws_info->pan_information.pan_version = randLIB_get_random_in_range(0, 0xffff); + cur->ws_info->pan_information.pan_version_set = true; + } cur->ws_info->pan_information.pan_size = 0; - cur->ws_info->pan_information.pan_version = randLIB_get_random_in_range(0, 0xffff); cur->ws_info->pan_information.routing_cost = 0; cur->ws_info->pan_information.rpl_routing_method = true; cur->ws_info->pan_information.use_parent_bs = true; @@ -3112,7 +3119,7 @@ static void ws_bootstrap_event_handler(arm_event_s *event) ws_eapol_auth_relay_start(cur, EAPOL_RELAY_SOCKET_PORT, ll_addr, PAE_AUTH_SOCKET_PORT); // Set PAN ID and network name to controller - ws_pae_controller_nw_info_set(cur, cur->ws_info->network_pan_id, cur->ws_info->cfg->gen.network_name); + ws_pae_controller_nw_info_set(cur, cur->ws_info->network_pan_id, cur->ws_info->pan_information.pan_version, cur->ws_info->cfg->gen.network_name); // Set PAE port to 10254 and authenticator relay to 10253 (and to own ll address) ws_pae_controller_authenticator_start(cur, PAE_AUTH_SOCKET_PORT, ll_addr, EAPOL_RELAY_SOCKET_PORT); diff --git a/source/6LoWPAN/ws/ws_common.c b/source/6LoWPAN/ws/ws_common.c index 02b54ff6b092..0088c5542461 100644 --- a/source/6LoWPAN/ws/ws_common.c +++ b/source/6LoWPAN/ws/ws_common.c @@ -319,6 +319,7 @@ int8_t ws_common_allocate_and_init(protocol_interface_info_entry_t *cur) cur->ws_info->network_pan_id = 0xffff; cur->ws_info->pan_information.use_parent_bs = true; cur->ws_info->pan_information.rpl_routing_method = true; + cur->ws_info->pan_information.pan_version_set = false; cur->ws_info->pan_information.version = WS_FAN_VERSION_1_0; cur->ws_info->pending_key_index_info.state = NO_PENDING_PROCESS; diff --git a/source/6LoWPAN/ws/ws_common_defines.h b/source/6LoWPAN/ws/ws_common_defines.h index 423d183bda71..f6f5e5cca84d 100644 --- a/source/6LoWPAN/ws/ws_common_defines.h +++ b/source/6LoWPAN/ws/ws_common_defines.h @@ -67,6 +67,7 @@ typedef struct ws_pan_information_s { uint16_t pan_version; /**< Pan configuration version will be updatd by Border router at PAN. */ bool use_parent_bs: 1; /**< 1 for force to follow parent broadcast schedule. 0 node may define own schedule. */ bool rpl_routing_method: 1; /**< 1 when RPL routing is selected and 0 when L2 routing. */ + bool pan_version_set: 1; /**< 1 PAN version is set. */ unsigned version: 3; /**< Pan version support. */ } ws_pan_information_t; diff --git a/source/6LoWPAN/ws/ws_config.h b/source/6LoWPAN/ws/ws_config.h index 6b00d6004c70..62a338ea0d0b 100644 --- a/source/6LoWPAN/ws/ws_config.h +++ b/source/6LoWPAN/ws/ws_config.h @@ -69,6 +69,10 @@ #define PAN_VERSION_CHANGE_INTERVAL 3 +/* If PAN version lifetime would be 10 minutes, 1000 increments is about 7 days i.e. storage must + be written at least once a week */ +#define PAN_VERSION_STORAGE_READ_INCREMENT 1000 + // 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 diff --git a/source/6LoWPAN/ws/ws_pae_controller.c b/source/6LoWPAN/ws/ws_pae_controller.c index f033d1579269..204888ad5fcf 100644 --- a/source/6LoWPAN/ws/ws_pae_controller.c +++ b/source/6LoWPAN/ws/ws_pae_controller.c @@ -117,7 +117,7 @@ static void ws_pae_controller_frame_counter_timer(uint16_t seconds, pae_controll 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_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 int8_t ws_pae_controller_nvm_frame_counter_read(uint32_t *restart_cnt, uint64_t *stored_time, uint16_t *pan_version, frame_counters_t *counters); static pae_controller_t *ws_pae_controller_get_or_create(int8_t interface_id); 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); @@ -276,7 +276,7 @@ static void ws_pae_controller_keys_nw_info_init(sec_prot_keys_nw_info_t *sec_key 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) +int8_t ws_pae_controller_nw_info_set(protocol_interface_info_entry_t *interface_ptr, uint16_t pan_id, uint16_t pan_version, char *network_name) { (void) pan_id; (void) network_name; @@ -306,6 +306,9 @@ int8_t ws_pae_controller_nw_info_set(protocol_interface_info_entry_t *interface_ updated = true; } + // Store pan version + controller->sec_keys_nw_info.pan_version = pan_version; + if (controller->pae_nw_info_set) { controller->pae_nw_info_set(interface_ptr, pan_id, network_name, updated); } @@ -700,7 +703,7 @@ static int8_t ws_pae_controller_frame_counter_read(pae_controller_t *controller) uint64_t stored_time = 0; // Read frame counters - if (ws_pae_controller_nvm_frame_counter_read(&controller->restart_cnt, &stored_time, &controller->frame_counters) >= 0) { + if (ws_pae_controller_nvm_frame_counter_read(&controller->restart_cnt, &stored_time, &controller->sec_keys_nw_info.pan_version, &controller->frame_counters) >= 0) { // Current time is not valid if (ws_pae_current_time_set(stored_time) < 0) { ret_value = -1; @@ -708,6 +711,9 @@ static int8_t ws_pae_controller_frame_counter_read(pae_controller_t *controller) // This is used to ensure that PMK replay counters are fresh after each re-start. controller->restart_cnt++; + // Increments PAN version to ensure that it is fresh + controller->sec_keys_nw_info.pan_version += PAN_VERSION_STORAGE_READ_INCREMENT; + bool updated = false; // Checks frame counters for (uint8_t index = 0; index < GTK_NUM; index++) { @@ -724,7 +730,7 @@ static int8_t ws_pae_controller_frame_counter_read(pae_controller_t *controller) } if (updated) { // Writes incremented frame counters - ws_pae_nvm_store_frame_counter_tlv_create((nvm_tlv_t *) &controller->pae_nvm_buffer, controller->restart_cnt, &controller->frame_counters); + ws_pae_nvm_store_frame_counter_tlv_create((nvm_tlv_t *) &controller->pae_nvm_buffer, controller->restart_cnt, controller->sec_keys_nw_info.pan_version, &controller->frame_counters); ws_pae_controller_nvm_frame_counter_write((nvm_tlv_t *) &controller->pae_nvm_buffer); } } @@ -859,7 +865,7 @@ int8_t ws_pae_controller_auth_init(protocol_interface_info_entry_t *interface_pt /* 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); + controller->nw_info_updated(interface_ptr, controller->sec_keys_nw_info.key_pan_id, controller->sec_keys_nw_info.pan_version, controller->sec_keys_nw_info.network_name); } if (!read_gtks_to || sec_prot_keys_gtk_count(read_gtks_to) == 0) { // Key material invalid or GTKs are expired, delete GTKs from NVM @@ -1450,7 +1456,7 @@ static void ws_pae_controller_frame_counter_store(pae_controller_t *entry, bool if (update_needed || entry->frame_cnt_store_force_timer == 0) { tr_debug("Write frame counters: system time %"PRIu32"", protocol_core_monotonic_time / 10); // Writes modified frame counters - ws_pae_nvm_store_frame_counter_tlv_create((nvm_tlv_t *) &entry->pae_nvm_buffer, entry->restart_cnt, &entry->frame_counters); + ws_pae_nvm_store_frame_counter_tlv_create((nvm_tlv_t *) &entry->pae_nvm_buffer, entry->restart_cnt, entry->sec_keys_nw_info.pan_version, &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 @@ -1458,7 +1464,7 @@ static void ws_pae_controller_frame_counter_store(pae_controller_t *entry, bool } } -static int8_t ws_pae_controller_nvm_frame_counter_read(uint32_t *restart_cnt, uint64_t *stored_time, frame_counters_t *counters) +static int8_t ws_pae_controller_nvm_frame_counter_read(uint32_t *restart_cnt, uint64_t *stored_time, uint16_t *pan_version, frame_counters_t *counters) { nvm_tlv_t *tlv = ws_pae_nvm_store_generic_tlv_allocate_and_create( PAE_NVM_FRAME_COUNTER_TAG, PAE_NVM_FRAME_COUNTER_LEN); @@ -1471,7 +1477,7 @@ static int8_t ws_pae_controller_nvm_frame_counter_read(uint32_t *restart_cnt, ui return -1; } - if (ws_pae_nvm_store_frame_counter_tlv_read(tlv, restart_cnt, stored_time, counters) < 0) { + if (ws_pae_nvm_store_frame_counter_tlv_read(tlv, restart_cnt, stored_time, pan_version, counters) < 0) { ws_pae_nvm_store_generic_tlv_free(tlv); return -1; } diff --git a/source/6LoWPAN/ws/ws_pae_controller.h b/source/6LoWPAN/ws/ws_pae_controller.h index 2f7e01e6dff2..1e071bf8efc8 100644 --- a/source/6LoWPAN/ws/ws_pae_controller.h +++ b/source/6LoWPAN/ws/ws_pae_controller.h @@ -237,13 +237,14 @@ int8_t ws_pae_controller_certificate_revocation_list_remove(const arm_cert_revoc * * \param interface_ptr interface * \param pan_id PAD ID + * \param pan_version PAN version * \param network_name network name * * \return < 0 failure * \return >= 0 success * */ -int8_t ws_pae_controller_nw_info_set(protocol_interface_info_entry_t *interface_ptr, uint16_t pan_id, char *network_name); +int8_t ws_pae_controller_nw_info_set(protocol_interface_info_entry_t *interface_ptr, uint16_t pan_id, uint16_t pan_version, char *network_name); /** * ws_pae_controller_nw_key_valid network key is valid i.e. used successfully on bootstrap @@ -518,10 +519,11 @@ typedef void ws_pae_controller_pan_ver_increment(protocol_interface_info_entry_t * * \param interface_ptr interface * \param pan_id PAN ID + * \param pan_version PAN version * \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); +typedef void ws_pae_controller_nw_info_updated(protocol_interface_info_entry_t *interface_ptr, uint16_t pan_id, uint16_t pan_version, char *network_name); /** * ws_pae_controller_cb_register register PEA controller callbacks diff --git a/source/6LoWPAN/ws/ws_pae_nvm_data.c b/source/6LoWPAN/ws/ws_pae_nvm_data.c index 3212240af83b..793b7a48467a 100644 --- a/source/6LoWPAN/ws/ws_pae_nvm_data.c +++ b/source/6LoWPAN/ws/ws_pae_nvm_data.c @@ -281,7 +281,7 @@ int8_t ws_pae_nvm_store_keys_tlv_read(nvm_tlv_t *tlv_entry, sec_prot_keys_t *sec return 0; } -void ws_pae_nvm_store_frame_counter_tlv_create(nvm_tlv_t *tlv_entry, uint32_t restart_cnt, frame_counters_t *counters) +void ws_pae_nvm_store_frame_counter_tlv_create(nvm_tlv_t *tlv_entry, uint32_t restart_cnt, uint16_t pan_version, frame_counters_t *counters) { tlv_entry->tag = PAE_NVM_FRAME_COUNTER_TAG; tlv_entry->len = PAE_NVM_FRAME_COUNTER_LEN; @@ -293,6 +293,8 @@ void ws_pae_nvm_store_frame_counter_tlv_create(nvm_tlv_t *tlv_entry, uint32_t re uint64_t stored_time = ws_pae_current_time_get(); tlv = common_write_64_bit(stored_time, tlv); + tlv = common_write_16_bit(pan_version, tlv); + for (uint8_t index = 0; index < GTK_NUM; index++) { if (!counters->counter[index].set) { *tlv++ = PAE_NVM_FIELD_NOT_SET; @@ -309,7 +311,7 @@ void ws_pae_nvm_store_frame_counter_tlv_create(nvm_tlv_t *tlv_entry, uint32_t re tr_debug("NVM FRAME COUNTER write"); } -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) +int8_t ws_pae_nvm_store_frame_counter_tlv_read(nvm_tlv_t *tlv_entry, uint32_t *restart_cnt, uint64_t *stored_time, uint16_t *pan_version, frame_counters_t *counters) { if (!tlv_entry || !counters) { return -1; @@ -327,6 +329,9 @@ int8_t ws_pae_nvm_store_frame_counter_tlv_read(nvm_tlv_t *tlv_entry, uint32_t *r *stored_time = common_read_64_bit(tlv); tlv += 8; + *pan_version = common_read_16_bit(tlv); + tlv += 2; + for (uint8_t index = 0; index < GTK_NUM; index++) { // Frame counter not set if (*tlv++ == PAE_NVM_FIELD_NOT_SET) { diff --git a/source/6LoWPAN/ws/ws_pae_nvm_data.h b/source/6LoWPAN/ws/ws_pae_nvm_data.h index c55d56412b0f..d66e238fa0e9 100644 --- a/source/6LoWPAN/ws/ws_pae_nvm_data.h +++ b/source/6LoWPAN/ws/ws_pae_nvm_data.h @@ -41,8 +41,8 @@ // 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 +// restart counter + stored time + pan version + (frame counter set (1) + GTK (16) + frame counter (4)) * 4 +#define PAE_NVM_FRAME_COUNTER_LEN 4 + 8 + 2 + (1 + GTK_LEN + 4) * GTK_NUM #define PAE_NVM_DEFAULT_BUFFER_SIZE sizeof(nvm_tlv_t) + PAE_NVM_NW_INFO_LEN @@ -119,10 +119,11 @@ int8_t ws_pae_nvm_store_keys_tlv_read(nvm_tlv_t *tlv_entry, sec_prot_keys_t *sec * * \param tlv_entry TLV buffer pointer * \param restart_cnt re-start counter + * \param pan_version PAN version * \param counters frame counters * */ -void ws_pae_nvm_store_frame_counter_tlv_create(nvm_tlv_t *tlv_entry, uint32_t restart_cnt, frame_counters_t *counters); +void ws_pae_nvm_store_frame_counter_tlv_create(nvm_tlv_t *tlv_entry, uint32_t restart_cnt, uint16_t pan_version, frame_counters_t *counters); /** * ws_pae_nvm_store_frame_counter_tlv_read read from NVM frame counter TLV @@ -130,13 +131,14 @@ void ws_pae_nvm_store_frame_counter_tlv_create(nvm_tlv_t *tlv_entry, uint32_t re * \param tlv_entry TLV * \param restart_cnt re-start counter * \param stored_time stored timestampt + * \param pan_version PAN version * \param counters frame counters * * \return < 0 failure * \return >= 0 success * */ -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); +int8_t ws_pae_nvm_store_frame_counter_tlv_read(nvm_tlv_t *tlv_entry, uint32_t *restart_cnt, uint64_t *stored_time, uint16_t *pan_version, frame_counters_t *counters); /** * ws_pae_nvm_store_key_storage_index_tlv_create create NVM key storage index TLV diff --git a/source/Security/protocols/sec_prot_keys.h b/source/Security/protocols/sec_prot_keys.h index 06302519d270..5050ddeec123 100644 --- a/source/Security/protocols/sec_prot_keys.h +++ b/source/Security/protocols/sec_prot_keys.h @@ -142,6 +142,7 @@ typedef struct { 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 */ + uint16_t pan_version; /**< PAN version for keys */ bool updated : 1; /**< Network info has been updated */ } sec_prot_keys_nw_info_t; From fbfada9595b4d4d29c4670e01ca39ffbd407c80c Mon Sep 17 00:00:00 2001 From: Jarkko Paso Date: Mon, 10 Aug 2020 09:45:31 +0300 Subject: [PATCH 20/30] Adaptation IF: Allocate fragmentation buffer only if needed (#2407) * Adaptation IF: Allocate fragmentation buffer only if needed * unit tests: fixed adaptation interface tests --- source/6LoWPAN/adaptation_interface.c | 21 +++++++++++++------ source/MAC/IEEE802_15_4/sw_mac.c | 4 ++-- .../test_adaptation_interface.c | 17 +++++---------- 3 files changed, 22 insertions(+), 20 deletions(-) diff --git a/source/6LoWPAN/adaptation_interface.c b/source/6LoWPAN/adaptation_interface.c index 79e294745524..fac7616df629 100644 --- a/source/6LoWPAN/adaptation_interface.c +++ b/source/6LoWPAN/adaptation_interface.c @@ -351,17 +351,14 @@ int8_t lowpan_adaptation_interface_init(int8_t interface_id, uint16_t mac_mtu_si //Allocate new fragmenter_interface_t *interface_ptr = ns_dyn_mem_alloc(sizeof(fragmenter_interface_t)); - uint8_t *tx_buffer = ns_dyn_mem_alloc(mac_mtu_size); - if (!interface_ptr || !tx_buffer) { - ns_dyn_mem_free(interface_ptr); - ns_dyn_mem_free(tx_buffer); + if (!interface_ptr) { return -1; } memset(interface_ptr, 0, sizeof(fragmenter_interface_t)); interface_ptr->interface_id = interface_id; - interface_ptr->fragment_indirect_tx_buffer = tx_buffer; - interface_ptr->mtu_size = mac_mtu_size; + interface_ptr->fragment_indirect_tx_buffer = NULL; + interface_ptr->mtu_size = 0; interface_ptr->msduHandle = randLIB_get_8bit(); interface_ptr->local_frag_tag = randLIB_get_16bit(); @@ -997,6 +994,18 @@ int8_t lowpan_adaptation_interface_tx(protocol_interface_info_entry_t *cur, buff //Check packet size bool fragmented_needed = lowpan_adaptation_request_longer_than_mtu(cur, buf, interface_ptr); + if (fragmented_needed) { + // If fragmentation TX buffer not allocated, do it now. + if (!interface_ptr->fragment_indirect_tx_buffer && !interface_ptr->mtu_size) { + interface_ptr->fragment_indirect_tx_buffer = ns_dyn_mem_alloc(cur->mac_api->phyMTU); + if (interface_ptr->fragment_indirect_tx_buffer) { + interface_ptr->mtu_size = cur->mac_api->phyMTU; + } else { + tr_error("Failed to allocate fragmentation buffer"); + goto tx_error_handler; + } + } + } bool is_unicast = buf->link_specific.ieee802_15_4.requestAck; bool indirect = buf->link_specific.ieee802_15_4.indirectTxProcess; diff --git a/source/MAC/IEEE802_15_4/sw_mac.c b/source/MAC/IEEE802_15_4/sw_mac.c index 02d2b79cddba..7fd08c6d25a2 100644 --- a/source/MAC/IEEE802_15_4/sw_mac.c +++ b/source/MAC/IEEE802_15_4/sw_mac.c @@ -104,9 +104,9 @@ mac_api_t *ns_sw_mac_create(int8_t rf_driver_id, mac_description_storage_size_t // Set default MTU size to 127 unless it is too much for PHY driver if (driver->phy_driver->phy_MTU > MAC_IEEE_802_15_4_MAX_PHY_PACKET_SIZE) { - this->phyMTU = driver->phy_driver->phy_MTU; - } else { this->phyMTU = MAC_IEEE_802_15_4_MAX_PHY_PACKET_SIZE; + } else { + this->phyMTU = driver->phy_driver->phy_MTU; } mac_store.setup = mac_mlme_data_base_allocate(mac_store.dev_driver->phy_driver->PHY_MAC, mac_store.dev_driver, storage_sizes, this->phyMTU); diff --git a/test/nanostack/unittest/6LoWPAN/adaptation_interface/test_adaptation_interface.c b/test/nanostack/unittest/6LoWPAN/adaptation_interface/test_adaptation_interface.c index 41c91265b6fe..be79eed09f71 100644 --- a/test/nanostack/unittest/6LoWPAN/adaptation_interface/test_adaptation_interface.c +++ b/test/nanostack/unittest/6LoWPAN/adaptation_interface/test_adaptation_interface.c @@ -65,26 +65,17 @@ bool test_lowpan_adaptation_interface_init() return false; } - if (-1 != lowpan_adaptation_interface_init(0, 127)) { - return false; - } - nsdynmemlib_stub.returnCounter = 0; - - if (-1 != lowpan_adaptation_interface_init(0, 127)) { - return false; - } - nsdynmemlib_stub.returnCounter = 1; if (-1 != lowpan_adaptation_interface_init(0, 127)) { return false; } - nsdynmemlib_stub.returnCounter = 2; + nsdynmemlib_stub.returnCounter = 1; if (0 != lowpan_adaptation_interface_init(0, 127)) { return false; } - nsdynmemlib_stub.returnCounter = 2; + nsdynmemlib_stub.returnCounter = 1; if (0 != lowpan_adaptation_interface_init(0, 127)) { return false; } @@ -387,6 +378,7 @@ bool test_lowpan_adaptation_interface_tx() entry.id = 0; api.mcps_data_req = &mcps_data_req_cb; api.mcps_purge_req = &tester_mcps_purge_request; + api.phyMTU = 127; mac_neighbor_table_stub.test_neigh = NULL; buffer_t *test_buf = malloc(sizeof(buffer_t) + 2100); @@ -428,7 +420,7 @@ bool test_lowpan_adaptation_interface_tx() } //Test Indirect data allocation fail - nsdynmemlib_stub.returnCounter = 2; + nsdynmemlib_stub.returnCounter = 1; lowpan_adaptation_interface_init(0, 127); if (0 != lowpan_adaptation_indirect_queue_params_set(&entry, 106, 1, 2)) { @@ -774,6 +766,7 @@ bool test_lowpan_adaptation_interface_tx_confirm() entry.mac_api = &api; entry.id = 0; api.mcps_data_req = &mcps_data_req_cb; + api.phyMTU = 127; mac_neighbor_table_stub.test_neigh = NULL; mac_helper_stub.uint16_value = 110; From 4d8c03bc06763f7d99ed499d818583b46531ffb1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mika=20Lepp=C3=A4nen?= Date: Tue, 11 Aug 2020 14:36:07 +0300 Subject: [PATCH 21/30] Border Router RADIUS client basic authentication functionality (#2406) * Border Router RADIUS client basic authentication functionality Basic RADIUS authentication functionality. --- nanostack/ws_bbr_api.h | 35 + source/6LoWPAN/ws/ws_bbr_api.c | 37 + source/6LoWPAN/ws/ws_bbr_api_internal.h | 2 + source/6LoWPAN/ws/ws_bootstrap.c | 15 + source/6LoWPAN/ws/ws_pae_auth.c | 152 ++- source/6LoWPAN/ws/ws_pae_auth.h | 34 +- source/6LoWPAN/ws/ws_pae_controller.c | 182 +++- source/6LoWPAN/ws/ws_pae_controller.h | 51 +- source/6LoWPAN/ws/ws_pae_lib.c | 13 + source/6LoWPAN/ws/ws_pae_lib.h | 12 + source/6LoWPAN/ws/ws_pae_supp.c | 45 +- source/6LoWPAN/ws/ws_pae_supp.h | 5 +- source/6LoWPAN/ws/ws_pae_timers.c | 12 +- source/6LoWPAN/ws/ws_pae_timers.h | 12 +- source/Security/kmp/kmp_api.c | 127 ++- source/Security/kmp/kmp_api.h | 60 +- source/Security/kmp/kmp_eapol_pdu_if.c | 12 +- source/Security/kmp/kmp_socket_if.c | 123 ++- source/Security/kmp/kmp_socket_if.h | 4 +- .../eap_tls_sec_prot/auth_eap_tls_sec_prot.c | 12 +- .../radius_eap_tls_sec_prot.c | 526 +++++++++ .../radius_eap_tls_sec_prot.h | 36 + .../eap_tls_sec_prot/supp_eap_tls_sec_prot.c | 6 +- .../fwh_sec_prot/auth_fwh_sec_prot.c | 10 +- .../fwh_sec_prot/supp_fwh_sec_prot.c | 12 +- .../gkh_sec_prot/auth_gkh_sec_prot.c | 4 +- .../protocols/radius_sec_prot/avp_helper.c | 259 +++++ .../protocols/radius_sec_prot/avp_helper.h | 239 +++++ .../radius_sec_prot/radius_client_sec_prot.c | 995 ++++++++++++++++++ .../radius_sec_prot/radius_client_sec_prot.h | 36 + source/Security/protocols/sec_prot.h | 38 +- source/Security/protocols/sec_prot_cfg.h | 15 + source/Security/protocols/sec_prot_lib.c | 10 +- .../protocols/tls_sec_prot/tls_sec_prot.c | 4 +- .../hmac/{hmac_sha1.c => hmac_md.c} | 17 +- .../hmac/{hmac_sha1.h => hmac_md.h} | 12 +- source/Service_Libs/ieee_802_11/ieee_802_11.c | 4 +- sources.mk | 5 +- .../unittest/service_libs/hmac/Makefile | 2 +- .../unittest/service_libs/hmac/hmactest.cpp | 5 + .../unittest/service_libs/hmac/test_hmac.c | 67 +- .../unittest/service_libs/hmac/test_hmac.h | 1 + .../ieee_802_11/test_ieee_802_11.c | 7 + test/nanostack/unittest/stub/hmac_stub.c | 4 +- test/nanostack/unittest/stub/hmac_stub.h | 1 + 45 files changed, 3033 insertions(+), 227 deletions(-) create mode 100644 source/Security/protocols/eap_tls_sec_prot/radius_eap_tls_sec_prot.c create mode 100644 source/Security/protocols/eap_tls_sec_prot/radius_eap_tls_sec_prot.h create mode 100644 source/Security/protocols/radius_sec_prot/avp_helper.c create mode 100644 source/Security/protocols/radius_sec_prot/avp_helper.h create mode 100644 source/Security/protocols/radius_sec_prot/radius_client_sec_prot.c create mode 100644 source/Security/protocols/radius_sec_prot/radius_client_sec_prot.h rename source/Service_Libs/hmac/{hmac_sha1.c => hmac_md.c} (77%) rename source/Service_Libs/hmac/{hmac_sha1.h => hmac_md.h} (73%) diff --git a/nanostack/ws_bbr_api.h b/nanostack/ws_bbr_api.h index c07b98225ff5..e92a3ca3ee41 100644 --- a/nanostack/ws_bbr_api.h +++ b/nanostack/ws_bbr_api.h @@ -355,4 +355,39 @@ int ws_bbr_key_storage_memory_set(int8_t interface_id, uint8_t key_storages_numb */ int ws_bbr_key_storage_settings_set(int8_t interface_id, uint8_t alloc_max_number, uint16_t alloc_size, uint16_t storing_interval); +/** + * ws_bbr_radius_address_set Set RADIUS server IPv6 address + * + * Function sets external RADIUS server IPv6 address to Border Router. Setting the + * address enables external RADIUS server interface on Border Router. To disable external + * RADIUS server interface, call the function with remote address set to NULL. The RADIUS + * shared secret must be set before address is set using ws_bbr_radius_shared_secret_set() + * call. + * + * \param interface_id Network interface ID. + * \param address Pointer to IPv6 address or NULL to disable RADIUS. Address is in binary format (16 bytes). + * + * \return < 0 failure + * \return >= 0 success + * + */ +int ws_bbr_radius_address_set(int8_t interface_id, const uint8_t *address); + +/** + * ws_bbr_radius_shared_secret_set set RADIUS shared secret + * + * Function sets RADIUS shared secret to Border Router. Shared secret is usually an + * ASCII string. Check the format and length constraints for the shared secret from + * the documentation of RADIUS server you are connecting to. + * + * \param interface_id Network interface ID. + * \param shared_secret_len The length of the shared secret in bytes. Maximum length is 255 bytes. + * \param shared_secret Pointer to shared secret. Can be 8-bit ASCII string or byte array. Is not NUL terminated. + * + * \return < 0 failure + * \return >= 0 success + * + */ +int ws_bbr_radius_shared_secret_set(int8_t interface_id, const uint8_t shared_secret_len, const uint8_t *shared_secret); + #endif /* WS_BBR_API_H_ */ diff --git a/source/6LoWPAN/ws/ws_bbr_api.c b/source/6LoWPAN/ws/ws_bbr_api.c index 8ae71ed6158d..36732a42e9be 100644 --- a/source/6LoWPAN/ws/ws_bbr_api.c +++ b/source/6LoWPAN/ws/ws_bbr_api.c @@ -156,6 +156,20 @@ void ws_bbr_dhcp_address_lifetime_set(protocol_interface_info_entry_t *cur, uint DHCPv6_server_service_set_address_validlifetime(cur->id, current_global_prefix, dhcp_address_lifetime); } +bool ws_bbr_backbone_address_get(uint8_t *address) +{ + if (backbone_interface_id < 0) { + return false; + } + + if (arm_net_address_get(backbone_interface_id, ADDR_IPV6_GP, address) != 0) { + // No global prefix available + return false; + } + + return true; +} + static void ws_bbr_rpl_root_start(protocol_interface_info_entry_t *cur, uint8_t *dodag_id) { tr_info("RPL root start"); @@ -1072,3 +1086,26 @@ int ws_bbr_key_storage_settings_set(int8_t interface_id, uint8_t alloc_max_numbe return -1; #endif } + +int ws_bbr_radius_address_set(int8_t interface_id, const uint8_t *address) +{ +#ifdef HAVE_WS_BORDER_ROUTER + return ws_pae_controller_radius_address_set(interface_id, address); +#else + (void) interface_id; + (void) address; + return -1; +#endif +} + +int ws_bbr_radius_shared_secret_set(int8_t interface_id, const uint8_t shared_secret_len, const uint8_t *shared_secret) +{ +#ifdef HAVE_WS_BORDER_ROUTER + return ws_pae_controller_radius_shared_secret_set(interface_id, shared_secret_len, shared_secret); +#else + (void) interface_id; + (void) shared_secret_len; + (void) shared_secret; + return -1; +#endif +} diff --git a/source/6LoWPAN/ws/ws_bbr_api_internal.h b/source/6LoWPAN/ws/ws_bbr_api_internal.h index 249790feac30..4c24191cb895 100644 --- a/source/6LoWPAN/ws/ws_bbr_api_internal.h +++ b/source/6LoWPAN/ws/ws_bbr_api_internal.h @@ -35,6 +35,7 @@ void ws_bbr_dhcp_address_lifetime_set(protocol_interface_info_entry_t *cur, uint bool ws_bbr_ready_to_start(protocol_interface_info_entry_t *cur); +bool ws_bbr_backbone_address_get(uint8_t *address); #else @@ -44,6 +45,7 @@ bool ws_bbr_ready_to_start(protocol_interface_info_entry_t *cur); #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 +#define ws_bbr_backbone_address_get(address) 0 #endif //HAVE_WS_BORDER_ROUTER diff --git a/source/6LoWPAN/ws/ws_bootstrap.c b/source/6LoWPAN/ws/ws_bootstrap.c index e4bee629dc7c..8cfa16746bb4 100644 --- a/source/6LoWPAN/ws/ws_bootstrap.c +++ b/source/6LoWPAN/ws/ws_bootstrap.c @@ -3030,6 +3030,18 @@ static void ws_bootstrap_pan_config(protocol_interface_info_entry_t *cur) ws_llc_asynch_request(cur, &async_req); } +static int8_t ws_bootstrap_backbone_ip_addr_get(protocol_interface_info_entry_t *interface_ptr, uint8_t *address) +{ + (void) interface_ptr; + (void) address; + + if (ws_bbr_backbone_address_get(address)) { + return 0; + } + + return -1; +} + static void ws_bootstrap_event_handler(arm_event_s *event) { ws_bootsrap_event_type_e event_type; @@ -3121,6 +3133,9 @@ static void ws_bootstrap_event_handler(arm_event_s *event) // Set PAN ID and network name to controller ws_pae_controller_nw_info_set(cur, cur->ws_info->network_pan_id, cur->ws_info->pan_information.pan_version, cur->ws_info->cfg->gen.network_name); + // Set backbone IP address get callback + ws_pae_controller_auth_cb_register(cur, ws_bootstrap_backbone_ip_addr_get); + // Set PAE port to 10254 and authenticator relay to 10253 (and to own ll address) ws_pae_controller_authenticator_start(cur, PAE_AUTH_SOCKET_PORT, ll_addr, EAPOL_RELAY_SOCKET_PORT); diff --git a/source/6LoWPAN/ws/ws_pae_auth.c b/source/6LoWPAN/ws/ws_pae_auth.c index 8db7f28fe4f4..b435270c7714 100644 --- a/source/6LoWPAN/ws/ws_pae_auth.c +++ b/source/6LoWPAN/ws/ws_pae_auth.c @@ -39,9 +39,11 @@ #include "Security/protocols/sec_prot_keys.h" #include "Security/protocols/key_sec_prot/key_sec_prot.h" #include "Security/protocols/eap_tls_sec_prot/auth_eap_tls_sec_prot.h" +#include "Security/protocols/eap_tls_sec_prot/radius_eap_tls_sec_prot.h" #include "Security/protocols/tls_sec_prot/tls_sec_prot.h" #include "Security/protocols/fwh_sec_prot/auth_fwh_sec_prot.h" #include "Security/protocols/gkh_sec_prot/auth_gkh_sec_prot.h" +#include "Security/protocols/radius_sec_prot/radius_client_sec_prot.h" #include "6LoWPAN/ws/ws_cfg_settings.h" #include "6LoWPAN/ws/ws_pae_controller.h" #include "6LoWPAN/ws/ws_pae_timers.h" @@ -90,14 +92,16 @@ typedef struct { 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 */ + ws_pae_auth_ip_addr_get *ip_addr_get; /**< IP address get callback */ supp_list_t active_supp_list; /**< List of active supplicants */ arm_event_storage_t *timer; /**< Timer */ 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 */ + sec_cfg_t *sec_cfg; /**< Security configuration */ uint16_t supp_max_number; /**< Max number of stored supplicants */ + uint8_t relay_socked_msg_if_instance_id; /**< Relay socket message interface instance identifier */ + uint8_t radius_socked_msg_if_instance_id; /**< Radius socket message interface instance identifier */ bool timer_running : 1; /**< Timer is running */ bool gtk_new_inst_req_exp : 1; /**< GTK new install required timer expired */ bool gtk_new_act_time_exp: 1; /**< GTK new activation time expired */ @@ -119,22 +123,23 @@ static int8_t ws_pae_auth_timer_start(pae_auth_t *pae_auth); static int8_t ws_pae_auth_timer_stop(pae_auth_t *pae_auth); static bool ws_pae_auth_timer_running(pae_auth_t *pae_auth); static void ws_pae_auth_kmp_service_addr_get(kmp_service_t *service, kmp_api_t *kmp, kmp_addr_t *local_addr, kmp_addr_t *remote_addr); +static void ws_pae_auth_kmp_service_ip_addr_get(kmp_service_t *service, kmp_api_t *kmp, uint8_t *address); static kmp_api_t *ws_pae_auth_kmp_service_api_get(kmp_service_t *service, kmp_api_t *kmp, kmp_type_e type); -static kmp_api_t *ws_pae_auth_kmp_incoming_ind(kmp_service_t *service, kmp_type_e type, const kmp_addr_t *addr); +static kmp_api_t *ws_pae_auth_kmp_incoming_ind(kmp_service_t *service, uint8_t msg_if_instance_id, kmp_type_e type, const kmp_addr_t *addr, const void *pdu, uint16_t size); static void ws_pae_auth_kmp_api_create_confirm(kmp_api_t *kmp, kmp_result_e result); static void ws_pae_auth_kmp_api_create_indication(kmp_api_t *kmp, kmp_type_e type, kmp_addr_t *addr); static void ws_pae_auth_kmp_api_finished_indication(kmp_api_t *kmp, kmp_result_e result, kmp_sec_keys_t *sec_keys); static void ws_pae_auth_next_kmp_trigger(pae_auth_t *pae_auth, supp_entry_t *supp_entry); static kmp_type_e ws_pae_auth_next_protocol_get(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 *prot_cfg, sec_timer_cfg_t *timer_cfg); +static kmp_api_t *ws_pae_auth_kmp_create_and_start(kmp_service_t *service, kmp_type_e type, uint8_t socked_msg_if_instance_id, supp_entry_t *supp_entry, sec_cfg_t *sec_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 *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) +int8_t ws_pae_auth_init(protocol_interface_info_entry_t *interface_ptr, sec_prot_gtk_keys_t *next_gtks, const sec_prot_certs_t *certs, sec_cfg_t *sec_cfg, sec_prot_keys_nw_info_t *sec_keys_nw_info) { - if (!interface_ptr || !next_gtks || !certs || !sec_timer_cfg || !sec_prot_cfg || !sec_keys_nw_info) { + if (!interface_ptr || !next_gtks || !certs || !sec_cfg || !sec_keys_nw_info) { return -1; } @@ -147,7 +152,6 @@ 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; @@ -162,19 +166,21 @@ int8_t ws_pae_auth_init(protocol_interface_info_entry_t *interface_ptr, sec_prot 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->sec_cfg = sec_cfg; pae_auth->supp_max_number = SUPPLICANT_MAX_NUMBER; pae_auth->gtk_new_inst_req_exp = false; pae_auth->gtk_new_act_time_exp = false; + pae_auth->relay_socked_msg_if_instance_id = 0; + pae_auth->radius_socked_msg_if_instance_id = 0; + pae_auth->kmp_service = kmp_service_create(); if (!pae_auth->kmp_service) { goto error; } - if (kmp_service_cb_register(pae_auth->kmp_service, ws_pae_auth_kmp_incoming_ind, NULL, ws_pae_auth_kmp_service_addr_get, ws_pae_auth_kmp_service_api_get)) { + if (kmp_service_cb_register(pae_auth->kmp_service, ws_pae_auth_kmp_incoming_ind, NULL, ws_pae_auth_kmp_service_addr_get, ws_pae_auth_kmp_service_ip_addr_get, ws_pae_auth_kmp_service_api_get)) { goto error; } @@ -190,10 +196,18 @@ int8_t ws_pae_auth_init(protocol_interface_info_entry_t *interface_ptr, sec_prot goto error; } - if (auth_eap_tls_sec_prot_register(pae_auth->kmp_service) < 0) { + // Register radius EAP-TLS and radius client security protocols + if (radius_eap_tls_sec_prot_register(pae_auth->kmp_service) < 0) { + goto error; + } + if (radius_client_sec_prot_register(pae_auth->kmp_service) < 0) { goto error; } + // Register EAP-TLS and TLS security protocols + if (auth_eap_tls_sec_prot_register(pae_auth->kmp_service) < 0) { + goto error; + } if (server_tls_sec_prot_register(pae_auth->kmp_service) < 0) { goto error; } @@ -241,7 +255,24 @@ int8_t ws_pae_auth_addresses_set(protocol_interface_info_entry_t *interface_ptr, return -1; } - if (kmp_socket_if_register(pae_auth->kmp_service, local_port, remote_addr, remote_port) < 0) { + if (kmp_socket_if_register(pae_auth->kmp_service, &pae_auth->relay_socked_msg_if_instance_id, true, local_port, remote_addr, remote_port) < 0) { + return -1; + } + + return 0; +} + +int8_t ws_pae_auth_radius_address_set(protocol_interface_info_entry_t *interface_ptr, const uint8_t *remote_addr) +{ + pae_auth_t *pae_auth = ws_pae_auth_get(interface_ptr); + if (!pae_auth) { + return -1; + } + if (!pae_auth->kmp_service) { + return -1; + } + + if (kmp_socket_if_register(pae_auth->kmp_service, &pae_auth->radius_socked_msg_if_instance_id, false, 0, remote_addr, 1812) < 0) { return -1; } @@ -263,7 +294,7 @@ int8_t ws_pae_auth_delete(protocol_interface_info_entry_t *interface_ptr) return 0; } -void ws_pae_auth_cb_register(protocol_interface_info_entry_t *interface_ptr, ws_pae_auth_gtk_hash_set *hash_set, ws_pae_auth_nw_key_insert *nw_key_insert, ws_pae_auth_nw_key_index_set *nw_key_index_set, ws_pae_auth_nw_info_updated *nw_info_updated) +void ws_pae_auth_cb_register(protocol_interface_info_entry_t *interface_ptr, ws_pae_auth_gtk_hash_set *hash_set, ws_pae_auth_nw_key_insert *nw_key_insert, ws_pae_auth_nw_key_index_set *nw_key_index_set, ws_pae_auth_nw_info_updated *nw_info_updated, ws_pae_auth_ip_addr_get *ip_addr_get) { if (!interface_ptr) { return; @@ -278,6 +309,7 @@ void ws_pae_auth_cb_register(protocol_interface_info_entry_t *interface_ptr, ws_ 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; + pae_auth->ip_addr_get = ip_addr_get; } void ws_pae_auth_start(protocol_interface_info_entry_t *interface_ptr) @@ -392,7 +424,7 @@ int8_t ws_pae_auth_node_access_revoke_start(protocol_interface_info_entry_t *int // As default removes other keys than active int8_t not_removed_index = active_index; - uint32_t revocation_lifetime = ws_pae_timers_gtk_revocation_lifetime_get(pae_auth->sec_timer_cfg); + uint32_t revocation_lifetime = ws_pae_timers_gtk_revocation_lifetime_get(pae_auth->sec_cfg); uint32_t active_lifetime = sec_prot_keys_gtk_lifetime_get(pae_auth->sec_keys_nw_info->gtks, active_index); @@ -668,7 +700,7 @@ void ws_pae_auth_slow_timer(uint16_t 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); + pae_auth->gtk_new_inst_req_exp = ws_pae_timers_gtk_new_install_required(pae_auth->sec_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->sec_keys_nw_info->gtks); if (second_index < 0) { @@ -684,7 +716,7 @@ void ws_pae_auth_slow_timer(uint16_t seconds) } if (!pae_auth->gtk_new_act_time_exp) { - pae_auth->gtk_new_act_time_exp = ws_pae_timers_gtk_new_activation_time(pae_auth->sec_timer_cfg, timer_seconds); + pae_auth->gtk_new_act_time_exp = ws_pae_timers_gtk_new_activation_time(pae_auth->sec_cfg, timer_seconds); if (pae_auth->gtk_new_act_time_exp) { int8_t new_active_index = ws_pae_auth_new_gtk_activate(pae_auth); tr_info("GTK new activation time active index: %i, time: %"PRIu32", new index: %i, system time: %"PRIu32"", active_index, timer_seconds, new_active_index, protocol_core_monotonic_time / 10); @@ -739,7 +771,7 @@ 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; + uint32_t lifetime = pae_auth->sec_cfg->timer_cfg.gtk_expire_offset; 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->sec_keys_nw_info->gtks, last_index); @@ -842,6 +874,18 @@ static void ws_pae_auth_kmp_service_addr_get(kmp_service_t *service, kmp_api_t * } } +static void ws_pae_auth_kmp_service_ip_addr_get(kmp_service_t *service, kmp_api_t *kmp, uint8_t *address) +{ + (void) kmp; + + pae_auth_t *pae_auth = ws_pae_auth_by_kmp_service_get(service); + if (!pae_auth) { + return; + } + + pae_auth->ip_addr_get(pae_auth->interface_ptr, address); +} + static kmp_api_t *ws_pae_auth_kmp_service_api_get(kmp_service_t *service, kmp_api_t *kmp, kmp_type_e type) { (void) service; @@ -854,19 +898,26 @@ static kmp_api_t *ws_pae_auth_kmp_service_api_get(kmp_service_t *service, kmp_ap return ws_pae_lib_kmp_list_type_get(&supp_entry->kmp_list, type); } -static kmp_api_t *ws_pae_auth_kmp_incoming_ind(kmp_service_t *service, kmp_type_e type, const kmp_addr_t *addr) +static kmp_api_t *ws_pae_auth_kmp_incoming_ind(kmp_service_t *service, uint8_t msg_if_instance_id, kmp_type_e type, const kmp_addr_t *addr, const void *pdu, uint16_t size) { pae_auth_t *pae_auth = ws_pae_auth_by_kmp_service_get(service); if (!pae_auth) { return NULL; } - // Find supplicant from list of active supplicants + // For radius messages + if (msg_if_instance_id == pae_auth->radius_socked_msg_if_instance_id) { + // Find KMP from list of active supplicants based on radius message + kmp_api_t *kmp_api = ws_pae_lib_supp_list_kmp_receive_check(&pae_auth->active_supp_list, pdu, size); + return kmp_api; + } + + // For relay messages find supplicant from list of active supplicants based on EUI-64 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) { // 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)) { + if (ws_pae_lib_supp_list_active_limit_reached(&pae_auth->active_supp_list, pae_auth->sec_cfg->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; } @@ -894,14 +945,21 @@ static kmp_api_t *ws_pae_auth_kmp_incoming_ind(kmp_service_t *service, kmp_type_ // Increases waiting time for supplicant authentication ws_pae_lib_supp_timer_ticks_set(supp_entry, WAIT_FOR_AUTHENTICATION_TICKS); - // Get KMP for supplicant - kmp_api_t *kmp = ws_pae_lib_kmp_list_type_get(&supp_entry->kmp_list, type); + kmp_type_e kmp_type_to_search = type; + + // If radius is enabled, route EAP-TLS to radius EAP-TLS + if (pae_auth->sec_cfg->radius_cfg.radius_addr_set && type == IEEE_802_1X_MKA) { + kmp_type_to_search = RADIUS_IEEE_802_1X_MKA; + } + + // Search for existing KMP for supplicant + kmp_api_t *kmp = ws_pae_lib_kmp_list_type_get(&supp_entry->kmp_list, kmp_type_to_search); if (kmp) { return kmp; } // Create a new KMP for initial eapol-key - kmp = kmp_api_create(service, type + IEEE_802_1X_INITIAL_KEY, pae_auth->sec_prot_cfg, pae_auth->sec_timer_cfg); + kmp = kmp_api_create(service, type + IEEE_802_1X_INITIAL_KEY, pae_auth->relay_socked_msg_if_instance_id, pae_auth->sec_cfg); if (!kmp) { return 0; @@ -1000,15 +1058,15 @@ static void ws_pae_auth_next_kmp_trigger(pae_auth_t *pae_auth, supp_entry_t *sup // Increases waiting time for supplicant authentication ws_pae_lib_supp_timer_ticks_set(supp_entry, WAIT_FOR_AUTHENTICATION_TICKS); - if (next_type == IEEE_802_1X_MKA) { + if (next_type == IEEE_802_1X_MKA || next_type == RADIUS_IEEE_802_1X_MKA) { /* For EAP-TLS, limits the number of ongoing negotiations. If limit is reached, authenticator does not initiate EAP-TLS right away. If previous EAP-TLS negotiation completes before negotiation trigger timeout, authenticator initiates EAP-TLS towards supplicant. Otherwise supplicant must re-send initial EAPOL-Key to try again using its trickle schedule */ - uint16_t ongoing_eap_tls_cnt = ws_pae_lib_supp_list_kmp_count(&pae_auth->active_supp_list, IEEE_802_1X_MKA); - if (ongoing_eap_tls_cnt >= pae_auth->sec_prot_cfg->sec_max_ongoing_authentication) { + uint16_t ongoing_eap_tls_cnt = ws_pae_lib_supp_list_kmp_count(&pae_auth->active_supp_list, next_type); + if (ongoing_eap_tls_cnt >= pae_auth->sec_cfg->prot_cfg.sec_max_ongoing_authentication) { supp_entry->retry_ticks = EAP_TLS_NEGOTIATION_TRIGGER_TIMEOUT; tr_info("EAP-TLS max ongoing reached, count %i, delayed: eui-64: %s", ongoing_eap_tls_cnt, trace_array(supp_entry->addr.eui_64, 8)); return; @@ -1016,12 +1074,25 @@ 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, pae_auth->sec_timer_cfg); + kmp_api_t *new_kmp = ws_pae_auth_kmp_create_and_start(pae_auth->kmp_service, next_type, pae_auth->relay_socked_msg_if_instance_id, supp_entry, pae_auth->sec_cfg); if (!new_kmp) { return; } - // For EAP-TLS create also TLS in addition to EAP-TLS + // For radius EAP-TLS create also radius client in addition to EAP-TLS + if (next_type == RADIUS_IEEE_802_1X_MKA) { + if (ws_pae_lib_kmp_list_type_get(&supp_entry->kmp_list, RADIUS_CLIENT_PROT) != NULL) { + // Radius client already exists, wait for it to be deleted + ws_pae_lib_kmp_list_delete(&supp_entry->kmp_list, new_kmp); + return; + } + // Create radius client instance */ + if (ws_pae_auth_kmp_create_and_start(pae_auth->kmp_service, RADIUS_CLIENT_PROT, pae_auth->radius_socked_msg_if_instance_id, supp_entry, pae_auth->sec_cfg) == NULL) { + ws_pae_lib_kmp_list_delete(&supp_entry->kmp_list, new_kmp); + return; + } + } + // For EAP-TLS create also TLS client in addition to EAP-TLS if (next_type == IEEE_802_1X_MKA) { if (ws_pae_lib_kmp_list_type_get(&supp_entry->kmp_list, TLS_PROT) != NULL) { // TLS already exists, wait for it to be deleted @@ -1029,7 +1100,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, pae_auth->sec_timer_cfg) == NULL) { + if (ws_pae_auth_kmp_create_and_start(pae_auth->kmp_service, TLS_PROT, pae_auth->relay_socked_msg_if_instance_id, supp_entry, pae_auth->sec_cfg) == NULL) { ws_pae_lib_kmp_list_delete(&supp_entry->kmp_list, new_kmp); return; } @@ -1047,7 +1118,11 @@ static kmp_type_e ws_pae_auth_next_protocol_get(pae_auth_t *pae_auth, supp_entry if (sec_keys->pmk_mismatch) { sec_keys->ptk_mismatch = true; // start EAP-TLS towards supplicant - next_type = IEEE_802_1X_MKA; + if (pae_auth->sec_cfg->radius_cfg.radius_addr_set) { + next_type = RADIUS_IEEE_802_1X_MKA; + } else { + next_type = IEEE_802_1X_MKA; + } tr_info("PAE start EAP-TLS, eui-64: %s", trace_array(supp_entry->addr.eui_64, 8)); } else if (sec_keys->ptk_mismatch) { // start 4WH towards supplicant @@ -1056,7 +1131,7 @@ static kmp_type_e ws_pae_auth_next_protocol_get(pae_auth_t *pae_auth, supp_entry } int8_t gtk_index = -1; - if (next_type != IEEE_802_1X_MKA) { + if (next_type != IEEE_802_1X_MKA && next_type != RADIUS_IEEE_802_1X_MKA) { // Checks if GTK needs to be inserted gtk_index = sec_prot_keys_gtk_insert_index_from_gtkl_get(sec_keys); @@ -1073,7 +1148,7 @@ static kmp_type_e ws_pae_auth_next_protocol_get(pae_auth_t *pae_auth, supp_entry * has been, trigger 4WH to update also the PTK. This prevents writing multiple * GTK keys to same index using same PTK. */ - if (pae_auth->sec_timer_cfg->gtk_expire_offset > SHORT_GTK_LIFETIME && + if (pae_auth->sec_cfg->timer_cfg.gtk_expire_offset > SHORT_GTK_LIFETIME && sec_prot_keys_ptk_installed_gtk_hash_mismatch_check(sec_keys, gtk_index)) { // start 4WH towards supplicant next_type = IEEE_802_11_4WH; @@ -1096,15 +1171,22 @@ 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 *prot_cfg, sec_timer_cfg_t *timer_cfg) +static kmp_api_t *ws_pae_auth_kmp_create_and_start(kmp_service_t *service, kmp_type_e type, uint8_t socked_msg_if_instance_id, supp_entry_t *supp_entry, sec_cfg_t *sec_cfg) { // Create KMP instance for new authentication - kmp_api_t *kmp = kmp_api_create(service, type, prot_cfg, timer_cfg); + kmp_api_t *kmp = kmp_api_create(service, type, socked_msg_if_instance_id, sec_cfg); if (!kmp) { return NULL; } + kmp_api_data_set(kmp, supp_entry); + // Sets address to KMP + kmp_api_addr_set(kmp, &supp_entry->addr); + + // Sets security keys to KMP + kmp_api_sec_keys_set(kmp, &supp_entry->sec_keys); + if (ws_pae_lib_kmp_list_add(&supp_entry->kmp_list, kmp) == NULL) { kmp_api_delete(kmp); return NULL; @@ -1137,7 +1219,7 @@ static void ws_pae_auth_kmp_api_finished(kmp_api_t *kmp) pae_auth_t *pae_auth = NULL; supp_entry_t *retry_supp = NULL; // When EAP-TLS completes check if there are other supplicants that have requested it lately - if (kmp_api_type_get(kmp) == IEEE_802_1X_MKA) { + if (kmp_api_type_get(kmp) == IEEE_802_1X_MKA || kmp_api_type_get(kmp) == RADIUS_IEEE_802_1X_MKA) { kmp_service_t *service = kmp_api_service_get(kmp); pae_auth = ws_pae_auth_by_kmp_service_get(service); if (pae_auth) { diff --git a/source/6LoWPAN/ws/ws_pae_auth.h b/source/6LoWPAN/ws/ws_pae_auth.h index 6b2719df910a..fc1030a750d7 100644 --- a/source/6LoWPAN/ws/ws_pae_auth.h +++ b/source/6LoWPAN/ws/ws_pae_auth.h @@ -46,15 +46,14 @@ * \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_cfg security 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 *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); +int8_t ws_pae_auth_init(protocol_interface_info_entry_t *interface_ptr, sec_prot_gtk_keys_t *next_gtks, const sec_prot_certs_t *certs, sec_cfg_t *sec_cfg, sec_prot_keys_nw_info_t *sec_keys_nw_info); /** * ws_pae_auth_addresses_set set relay addresses @@ -70,6 +69,18 @@ int8_t ws_pae_auth_init(protocol_interface_info_entry_t *interface_ptr, sec_prot */ int8_t ws_pae_auth_addresses_set(protocol_interface_info_entry_t *interface_ptr, uint16_t local_port, const uint8_t *remote_addr, uint16_t remote_port); +/** + * ws_pae_auth_radius_address_set set radius address + * + * \param interface_ptr interface + * \param remote_addr remote address + * + * \return < 0 failure + * \return >= 0 success + * + */ +int8_t ws_pae_auth_radius_address_set(protocol_interface_info_entry_t *interface_ptr, const uint8_t *remote_addr); + /** * ws_pae_auth_delete deletes PAE authenticator * @@ -228,6 +239,15 @@ typedef void ws_pae_auth_nw_key_index_set(protocol_interface_info_entry_t *inter */ typedef void ws_pae_auth_nw_info_updated(protocol_interface_info_entry_t *interface_ptr); +/** + * ws_pae_auth_ip_addr_get gets IP addressing information related to KMP + * + * \param interface_ptr interface + * \param address IP address + * + */ +typedef void ws_pae_auth_ip_addr_get(protocol_interface_info_entry_t *interface_ptr, uint8_t *address); + /** * ws_pae_auth_cb_register register PAE authenticator callbacks * @@ -236,17 +256,18 @@ typedef void ws_pae_auth_nw_info_updated(protocol_interface_info_entry_t *interf * \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 + * \param ip_addr_get IP addressing information callback * */ -void ws_pae_auth_cb_register(protocol_interface_info_entry_t *interface_ptr, ws_pae_auth_gtk_hash_set *hash_set, ws_pae_auth_nw_key_insert *nw_key_insert, ws_pae_auth_nw_key_index_set *nw_key_index_set, ws_pae_auth_nw_info_updated *nw_info_updated); +void ws_pae_auth_cb_register(protocol_interface_info_entry_t *interface_ptr, ws_pae_auth_gtk_hash_set *hash_set, ws_pae_auth_nw_key_insert *nw_key_insert, ws_pae_auth_nw_key_index_set *nw_key_index_set, ws_pae_auth_nw_info_updated *nw_info_updated, ws_pae_auth_ip_addr_get *ip_addr_get); #else -#define ws_pae_auth_init(interface_ptr, gtks, next_gtks, certs, sec_timer_cfg, sec_prot_cfg) 1 +#define ws_pae_auth_init(interface_ptr, next_gtks, certs, sec_cfg, sec_keys_nw_info) 1 #define ws_pae_auth_timing_adjust(timing) #define ws_pae_auth_addresses_set(interface_ptr, local_port, remote_addr, remote_port) 1 #define ws_pae_auth_delete NULL -#define ws_pae_auth_cb_register(interface_ptr, hash_set, nw_key_insert, nw_key_index_set, nw_info_updated) {(void) hash_set;} +#define ws_pae_auth_cb_register(interface_ptr, hash_set, nw_key_insert, nw_key_index_set, nw_info_updated, ip_addr_get) {(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 @@ -257,6 +278,7 @@ void ws_pae_auth_cb_register(protocol_interface_info_entry_t *interface_ptr, ws_ #define ws_pae_auth_forced_gc(interface_ptr) #define ws_pae_auth_fast_timer NULL #define ws_pae_auth_slow_timer NULL +#define ws_pae_auth_radius_address_set(interface_ptr, remote_addr) -1 #endif diff --git a/source/6LoWPAN/ws/ws_pae_controller.c b/source/6LoWPAN/ws/ws_pae_controller.c index 204888ad5fcf..6511e7fcb9b8 100644 --- a/source/6LoWPAN/ws/ws_pae_controller.c +++ b/source/6LoWPAN/ws/ws_pae_controller.c @@ -75,8 +75,7 @@ typedef struct { 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 */ + sec_cfg_t sec_cfg; /**< Security configuration (configuration set values) */ uint32_t restart_cnt; /**< Re-start counter */ protocol_interface_info_entry_t *interface_ptr; /**< List link entry */ ws_pae_controller_auth_completed *auth_completed; /**< Authentication completed callback, continue bootstrap */ @@ -88,6 +87,7 @@ typedef struct { ws_pae_controller_pan_ver_increment *pan_ver_increment; /**< PAN version increment callback */ ws_pae_controller_nw_info_updated *nw_info_updated; /**< Network information updated callback */ ws_pae_controller_auth_next_target *auth_next_target; /**< Authentication next target callback */ + ws_pae_controller_ip_addr_get *ip_addr_get; /**< IP address get 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 */ @@ -102,6 +102,7 @@ typedef struct { bool gtkhash_set : 1; /**< GTK hashes are set */ bool key_index_set : 1; /**< NW key index is set */ bool frame_counter_read : 1; /**< Frame counters has been read */ + bool auth_started : 1; /**< Authenticator has been started */ } pae_controller_t; typedef struct { @@ -112,6 +113,9 @@ typedef struct { 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); +#ifdef HAVE_PAE_AUTH +static void ws_pae_controller_auth_ip_addr_get(protocol_interface_info_entry_t *interface_ptr, uint8_t *address); +#endif static pae_controller_t *ws_pae_controller_get(protocol_interface_info_entry_t *interface_ptr); static void ws_pae_controller_frame_counter_timer(uint16_t seconds, pae_controller_t *entry); static void ws_pae_controller_frame_counter_timer_trigger(uint16_t seconds, pae_controller_t *entry); @@ -147,6 +151,8 @@ pae_controller_config_t pae_controller_config = { .ext_cert_valid_enabled = false }; +sec_radius_cfg_t *pae_controller_radius_settings; + int8_t ws_pae_controller_authenticate(protocol_interface_info_entry_t *interface_ptr) { pae_controller_t *controller = ws_pae_controller_get(interface_ptr); @@ -211,11 +217,28 @@ int8_t ws_pae_controller_authenticator_start(protocol_interface_info_entry_t *in return -1; } + if (pae_controller_radius_settings) { + // If either address or password is set, both must be set + if (controller->sec_cfg.radius_cfg.radius_addr_set || controller->sec_cfg.radius_cfg.radius_shared_secret_len > 0) { + if (!controller->sec_cfg.radius_cfg.radius_addr_set) { + return -1; + } + if (controller->sec_cfg.radius_cfg.radius_shared_secret_len == 0) { + return -1; + } + if (ws_pae_auth_radius_address_set(interface_ptr, controller->sec_cfg.radius_cfg.radius_addr) < 0) { + return -1; + } + } + } + if (pae_controller_config.node_limit_set) { ws_pae_auth_node_limit_set(controller->interface_ptr, pae_controller_config.node_limit); } - ws_pae_auth_cb_register(interface_ptr, ws_pae_controller_gtk_hash_set, ws_pae_controller_nw_key_check_and_insert, ws_pae_controller_nw_key_index_check_and_set, ws_pae_controller_nw_info_updated_check); + ws_pae_auth_cb_register(interface_ptr, ws_pae_controller_gtk_hash_set, ws_pae_controller_nw_key_check_and_insert, ws_pae_controller_nw_key_index_check_and_set, ws_pae_controller_nw_info_updated_check, ws_pae_controller_auth_ip_addr_get); + + controller->auth_started = true; ws_pae_auth_start(interface_ptr); @@ -245,6 +268,21 @@ int8_t ws_pae_controller_cb_register(protocol_interface_info_entry_t *interface_ return 0; } +int8_t ws_pae_controller_auth_cb_register(protocol_interface_info_entry_t *interface_ptr, ws_pae_controller_ip_addr_get *ip_addr_get) +{ + if (!interface_ptr) { + return -1; + } + + pae_controller_t *controller = ws_pae_controller_get(interface_ptr); + if (!controller) { + return -1; + } + + controller->ip_addr_get = ip_addr_get; + return 0; +} + int8_t ws_pae_controller_set_target(protocol_interface_info_entry_t *interface_ptr, uint16_t target_pan_id, uint8_t *target_eui_64) { if (!interface_ptr) { @@ -334,6 +372,22 @@ static void ws_pae_controller_nw_info_updated_check(protocol_interface_info_entr } } +#ifdef HAVE_PAE_AUTH +static void ws_pae_controller_auth_ip_addr_get(protocol_interface_info_entry_t *interface_ptr, uint8_t *address) +{ + if (!interface_ptr) { + return; + } + + pae_controller_t *controller = ws_pae_controller_get(interface_ptr); + if (!controller) { + return; + } + + controller->ip_addr_get(interface_ptr, address); +} +#endif + int8_t ws_pae_controller_nw_key_valid(protocol_interface_info_entry_t *interface_ptr, uint8_t *br_iid) { if (!interface_ptr) { @@ -613,8 +667,7 @@ int8_t ws_pae_controller_init(protocol_interface_info_entry_t *interface_ptr) 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)); + memset(&controller->sec_cfg, 0, sizeof(sec_cfg_t)); ws_pae_controller_data_init(controller); @@ -631,24 +684,28 @@ int8_t ws_pae_controller_configure(protocol_interface_info_entry_t *interface_pt } if (sec_prot_cfg) { - controller->sec_prot_cfg.sec_prot_trickle_params.Imin = sec_prot_cfg->sec_prot_trickle_imin * 10; - controller->sec_prot_cfg.sec_prot_trickle_params.Imax = sec_prot_cfg->sec_prot_trickle_imax * 10; - 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_cfg.prot_cfg.sec_prot_trickle_params.Imin = sec_prot_cfg->sec_prot_trickle_imin * 10; + controller->sec_cfg.prot_cfg.sec_prot_trickle_params.Imax = sec_prot_cfg->sec_prot_trickle_imax * 10; + controller->sec_cfg.prot_cfg.sec_prot_trickle_params.k = 0; + controller->sec_cfg.prot_cfg.sec_prot_trickle_params.TimerExpirations = sec_prot_cfg->sec_prot_trickle_timer_exp; + controller->sec_cfg.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_cfg.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; + controller->sec_cfg.prot_cfg.initial_key_retry_delay = sec_prot_cfg->initial_key_retry_delay; + controller->sec_cfg.prot_cfg.initial_key_trickle_params.Imin = sec_prot_cfg->initial_key_imin; + controller->sec_cfg.prot_cfg.initial_key_trickle_params.Imax = sec_prot_cfg->initial_key_imax; + controller->sec_cfg.prot_cfg.initial_key_trickle_params.k = 0; + controller->sec_cfg.prot_cfg.initial_key_trickle_params.TimerExpirations = 2; + controller->sec_cfg.prot_cfg.initial_key_retry_cnt = sec_prot_cfg->initial_key_retry_cnt; } if (sec_timer_cfg) { - ws_pae_timers_settings_init(&controller->sec_timer_cfg, sec_timer_cfg); + ws_pae_timers_settings_init(&controller->sec_cfg.timer_cfg, sec_timer_cfg); + } + + if (pae_controller_radius_settings) { + controller->sec_cfg.radius_cfg = *pae_controller_radius_settings; } return 0; @@ -683,6 +740,7 @@ static void ws_pae_controller_data_init(pae_controller_t *controller) controller->frame_cnt_store_timer = FRAME_COUNTER_STORE_INTERVAL; controller->frame_cnt_store_force_timer = FRAME_COUNTER_STORE_FORCE_INTERVAL; controller->restart_cnt = 0; + controller->auth_started = false; ws_pae_controller_frame_counter_reset(&controller->frame_counters); sec_prot_keys_gtks_init(&controller->gtks); sec_prot_keys_gtks_init(&controller->next_gtks); @@ -802,7 +860,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, &controller->sec_keys_nw_info) < 0) { + if (ws_pae_supp_init(controller->interface_ptr, &controller->certs, &controller->sec_cfg, &controller->sec_keys_nw_info) < 0) { return -1; } @@ -832,7 +890,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->next_gtks, &controller->certs, &controller->sec_timer_cfg, &controller->sec_prot_cfg, &controller->sec_keys_nw_info) < 0) { + if (ws_pae_auth_init(controller->interface_ptr, &controller->next_gtks, &controller->certs, &controller->sec_cfg, &controller->sec_keys_nw_info) < 0) { return -1; } @@ -1113,6 +1171,88 @@ int8_t ws_pae_controller_certificate_revocation_list_remove(const arm_cert_revoc return ret; } +int8_t ws_pae_controller_radius_address_set(int8_t interface_id, const uint8_t *remote_addr) +{ + pae_controller_t *controller = ws_pae_controller_get_or_create(interface_id); + + // If remote address is not set, clear radius information + if (!remote_addr) { + if (pae_controller_radius_settings != NULL) { + pae_controller_radius_settings->radius_addr_set = false; + } + if (controller) { + ws_pae_controller_configure(controller->interface_ptr, NULL, NULL); + } + return 0; + } + + if (pae_controller_radius_settings == NULL) { + pae_controller_radius_settings = ns_dyn_mem_alloc(sizeof(sec_radius_cfg_t)); + if (!pae_controller_radius_settings) { + return -1; + } + memset(pae_controller_radius_settings, 0, sizeof(sec_radius_cfg_t)); + } + memcpy(pae_controller_radius_settings->radius_addr, remote_addr, 16); + pae_controller_radius_settings->radius_addr_set = true; + + if (controller) { + ws_pae_controller_configure(controller->interface_ptr, NULL, NULL); + if (ws_pae_auth_radius_address_set(controller->interface_ptr, controller->sec_cfg.radius_cfg.radius_addr) < 0) { + return -1; + } + } + + return 0; +} + +int8_t ws_pae_controller_radius_shared_secret_set(int8_t interface_id, const uint8_t shared_secret_len, const uint8_t *shared_secret) +{ + pae_controller_t *controller = ws_pae_controller_get_or_create(interface_id); + + // If shared secret is not set, clear radius information + if (shared_secret_len == 0 || !shared_secret) { + if (pae_controller_radius_settings != NULL) { + memset(pae_controller_radius_settings->radius_shared_secret, 0, pae_controller_radius_settings->radius_shared_secret_len); + pae_controller_radius_settings->radius_shared_secret_len = 0; + } + if (controller) { + ws_pae_controller_configure(controller->interface_ptr, NULL, NULL); + } + return 0; + } + + if (pae_controller_radius_settings == NULL) { + pae_controller_radius_settings = ns_dyn_mem_alloc(sizeof(sec_radius_cfg_t)); + if (!pae_controller_radius_settings) { + return -1; + } + memset(pae_controller_radius_settings, 0, sizeof(sec_radius_cfg_t)); + } + + if (pae_controller_radius_settings->radius_shared_secret != NULL && + pae_controller_radius_settings->radius_shared_secret_len != shared_secret_len) { + ns_dyn_mem_free(pae_controller_radius_settings->radius_shared_secret); + pae_controller_radius_settings->radius_shared_secret = NULL; + } + + if (pae_controller_radius_settings->radius_shared_secret == NULL) { + pae_controller_radius_settings->radius_shared_secret = ns_dyn_mem_alloc(shared_secret_len); + if (pae_controller_radius_settings->radius_shared_secret == NULL) { + return -1; + } + } + + memcpy(pae_controller_radius_settings->radius_shared_secret, shared_secret, shared_secret_len); + pae_controller_radius_settings->radius_shared_secret_len = shared_secret_len; + + if (controller) { + ws_pae_controller_configure(controller->interface_ptr, NULL, NULL); + } + + return 0; +} + int8_t ws_pae_controller_border_router_addr_write(protocol_interface_info_entry_t *interface_ptr, const uint8_t *eui_64) { if (!eui_64) { @@ -1175,7 +1315,7 @@ int8_t ws_pae_controller_gtk_update(int8_t interface_id, uint8_t *gtk[GTK_NUM]) for (uint8_t i = 0; i < GTK_NUM; i++) { if (gtk[i]) { uint32_t lifetime = sec_prot_keys_gtk_install_order_last_lifetime_get(&controller->gtks); - lifetime += controller->sec_timer_cfg.gtk_expire_offset; + lifetime += controller->sec_cfg.timer_cfg.gtk_expire_offset; if (sec_prot_keys_gtk_set(&controller->gtks, i, gtk[i], lifetime) >= 0) { controller->gtks_set = true; tr_info("GTK set index: %i, lifetime %"PRIu32", system time: %"PRIu32"", i, lifetime, protocol_core_monotonic_time / 10); diff --git a/source/6LoWPAN/ws/ws_pae_controller.h b/source/6LoWPAN/ws/ws_pae_controller.h index 1e071bf8efc8..96b14f1f896f 100644 --- a/source/6LoWPAN/ws/ws_pae_controller.h +++ b/source/6LoWPAN/ws/ws_pae_controller.h @@ -232,6 +232,31 @@ int8_t ws_pae_controller_certificate_revocation_list_add(const arm_cert_revocati */ int8_t ws_pae_controller_certificate_revocation_list_remove(const arm_cert_revocation_list_entry_s *crl); +/** + * ws_pae_controller_radius_address_set set radius address + * + * \param interface_id interface identifier + * \param remote_addr remote address + * + * \return < 0 failure + * \return >= 0 success + * + */ +int8_t ws_pae_controller_radius_address_set(int8_t interface_id, const uint8_t *remote_addr); + +/** + * ws_pae_controller_radius_shared_secret_set set radius shared secret + * + * \param interface_id interface identifier + * \param shared_secret_len shared secret + * \param shared_secret shared secret + * + * \return < 0 failure + * \return >= 0 success + * + */ +int8_t ws_pae_controller_radius_shared_secret_set(int8_t interface_id, const uint8_t shared_secret_len, const uint8_t *shared_secret); + /** * ws_pae_controller_nw_info_set set network information * @@ -526,7 +551,7 @@ typedef void ws_pae_controller_pan_ver_increment(protocol_interface_info_entry_t typedef void ws_pae_controller_nw_info_updated(protocol_interface_info_entry_t *interface_ptr, uint16_t pan_id, uint16_t pan_version, char *network_name); /** - * ws_pae_controller_cb_register register PEA controller callbacks + * ws_pae_controller_cb_register register controller callbacks * * \param interface_ptr interface * \param completed authentication completed callback @@ -545,6 +570,30 @@ typedef void ws_pae_controller_nw_info_updated(protocol_interface_info_entry_t * */ 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_ip_addr_get gets IP addressing information + * + * \param interface_ptr interface + * \param address IP address + * + * \return < 0 failure + * \return >= 0 success + * + */ +typedef int8_t ws_pae_controller_ip_addr_get(protocol_interface_info_entry_t *interface_ptr, uint8_t *address); + +/** + * ws_pae_controller_auth_cb_register register authenticator callbacks + * + * \param interface_ptr interface + * \param ip_addr_get IP address get callback + * + * \return < 0 failure + * \return >= 0 success + * + */ +int8_t ws_pae_controller_auth_cb_register(protocol_interface_info_entry_t *interface_ptr, ws_pae_controller_ip_addr_get *ip_addr_get); + /** * ws_pae_controller_fast_timer PAE controller fast timer call * diff --git a/source/6LoWPAN/ws/ws_pae_lib.c b/source/6LoWPAN/ws/ws_pae_lib.c index d47aff8a8fe6..52ceaaba6a2a 100644 --- a/source/6LoWPAN/ws/ws_pae_lib.c +++ b/source/6LoWPAN/ws/ws_pae_lib.c @@ -419,6 +419,19 @@ uint16_t ws_pae_lib_supp_list_kmp_count(supp_list_t *supp_list, kmp_type_e type) return kmp_count; } +kmp_api_t *ws_pae_lib_supp_list_kmp_receive_check(supp_list_t *supp_list, const void *pdu, uint16_t size) +{ + ns_list_foreach(supp_entry_t, entry, supp_list) { + ns_list_foreach(kmp_entry_t, kmp_entry, &entry->kmp_list) { + if (kmp_api_receive_check(kmp_entry->kmp, pdu, size)) { + return kmp_entry->kmp; + } + } + } + + return NULL; +} + supp_entry_t *ws_pae_lib_supp_list_entry_retry_timer_get(supp_list_t *supp_list) { supp_entry_t *retry_supp = NULL; diff --git a/source/6LoWPAN/ws/ws_pae_lib.h b/source/6LoWPAN/ws/ws_pae_lib.h index eed138e74c92..5058e3e36401 100644 --- a/source/6LoWPAN/ws/ws_pae_lib.h +++ b/source/6LoWPAN/ws/ws_pae_lib.h @@ -366,6 +366,18 @@ bool ws_pae_lib_supp_list_active_limit_reached(supp_list_t *active_supp_list, ui */ uint16_t ws_pae_lib_supp_list_kmp_count(supp_list_t *supp_list, kmp_type_e type); +/** + * ws_pae_lib_supp_list_kmp_receive_check check if received message is for this KMP in a list of supplicants + * + * \param supp_list list of supplicants + * \param pdu pdu + * \param size pdu size + * + * \return KMP api for the received message + * + */ +kmp_api_t *ws_pae_lib_supp_list_kmp_receive_check(supp_list_t *supp_list, const void *pdu, uint16_t size); + /** * ws_pae_lib_supp_list_entry_retry_timer_get checks if some supplicant has retry timer running * diff --git a/source/6LoWPAN/ws/ws_pae_supp.c b/source/6LoWPAN/ws/ws_pae_supp.c index 676e9de74f53..9beda28756ca 100644 --- a/source/6LoWPAN/ws/ws_pae_supp.c +++ b/source/6LoWPAN/ws/ws_pae_supp.c @@ -100,8 +100,7 @@ typedef struct { 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 */ + sec_cfg_t *sec_cfg; /**< Security configuration */ uint8_t nw_keys_used_cnt; /**< How many times bootstrap has been tried with current keys */ uint8_t initial_key_retry_cnt; /**< initial EAPOL-Key retry counter */ bool auth_trickle_running : 1; /**< Initial EAPOL-Key Trickle timer running */ @@ -126,6 +125,7 @@ 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_network_name_compare(char *name1, char *name2); 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); @@ -142,7 +142,7 @@ static int8_t ws_pae_supp_timer_stop(pae_supp_t *pae_supp); static bool ws_pae_supp_timer_running(pae_supp_t *pae_supp); static void ws_pae_supp_kmp_service_addr_get(kmp_service_t *service, kmp_api_t *kmp, kmp_addr_t *local_addr, kmp_addr_t *remote_addr); static kmp_api_t *ws_pae_supp_kmp_service_api_get(kmp_service_t *service, kmp_api_t *kmp, kmp_type_e type); -static kmp_api_t *ws_pae_supp_kmp_incoming_ind(kmp_service_t *service, kmp_type_e type, const kmp_addr_t *addr); +static kmp_api_t *ws_pae_supp_kmp_incoming_ind(kmp_service_t *service, uint8_t instance_id, kmp_type_e type, const kmp_addr_t *addr, const void *pdu, uint16_t size); static kmp_api_t *ws_pae_supp_kmp_tx_status_ind(kmp_service_t *service, uint8_t instance_id); static kmp_api_t *ws_pae_supp_kmp_create_and_start(kmp_service_t *service, kmp_type_e type, pae_supp_t *pae_supp); static int8_t ws_pae_supp_eapol_pdu_address_check(protocol_interface_info_entry_t *interface_ptr, const uint8_t *eui_64); @@ -200,7 +200,7 @@ int8_t ws_pae_supp_authenticate(protocol_interface_info_entry_t *interface_ptr, /* 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 (strcmp(pae_supp->sec_keys_nw_info->network_name, dest_network_name) != 0 || + if (ws_pae_supp_network_name_compare(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); @@ -350,7 +350,7 @@ int8_t ws_pae_supp_gtk_hash_update(protocol_interface_info_entry_t *interface_pt // Starts supplicant timer ws_pae_supp_timer_start(pae_supp); - tr_info("GTK update start imin: %i, imax: %i, max mismatch: %i, tr time: %i", pae_supp->sec_timer_cfg->gtk_request_imin, pae_supp->sec_timer_cfg->gtk_request_imax, pae_supp->sec_timer_cfg->gtk_max_mismatch, pae_supp->auth_trickle_timer.t); + tr_info("GTK update start imin: %i, imax: %i, max mismatch: %i, tr time: %i", pae_supp->sec_cfg->timer_cfg.gtk_request_imin, pae_supp->sec_cfg->timer_cfg.gtk_request_imax, pae_supp->sec_cfg->timer_cfg.gtk_max_mismatch, pae_supp->auth_trickle_timer.t); } } @@ -489,6 +489,14 @@ static int8_t ws_pae_supp_initial_key_send(pae_supp_t *pae_supp) return 0; } +static int8_t ws_pae_supp_network_name_compare(char *name1, char *name2) +{ + if (strlen(name1) == strlen(name2) && strcmp(name1, name2) == 0) { + return 0; + } + return -1; +} + 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 @@ -507,7 +515,7 @@ static int8_t ws_pae_supp_nw_keys_valid_check(pae_supp_t *pae_supp, uint16_t pan /* 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 && + if ((ws_pae_supp_network_name_compare(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) && @@ -564,7 +572,7 @@ void ws_pae_supp_cb_register(protocol_interface_info_entry_t *interface_ptr, ws_ 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, sec_prot_keys_nw_info_t *sec_keys_nw_info) +int8_t ws_pae_supp_init(protocol_interface_info_entry_t *interface_ptr, const sec_prot_certs_t *certs, sec_cfg_t *sec_cfg, sec_prot_keys_nw_info_t *sec_keys_nw_info) { if (!interface_ptr) { return -1; @@ -590,8 +598,7 @@ int8_t ws_pae_supp_init(protocol_interface_info_entry_t *interface_ptr, const se pae_supp->nw_keys_used_cnt = 0; 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->sec_cfg = sec_cfg; pae_supp->auth_trickle_running = false; pae_supp->auth_requested = false; pae_supp->timer_running = false; @@ -613,7 +620,7 @@ int8_t ws_pae_supp_init(protocol_interface_info_entry_t *interface_ptr, const se goto error; } - if (kmp_service_cb_register(pae_supp->kmp_service, ws_pae_supp_kmp_incoming_ind, ws_pae_supp_kmp_tx_status_ind, ws_pae_supp_kmp_service_addr_get, ws_pae_supp_kmp_service_api_get) < 0) { + if (kmp_service_cb_register(pae_supp->kmp_service, ws_pae_supp_kmp_incoming_ind, ws_pae_supp_kmp_tx_status_ind, ws_pae_supp_kmp_service_addr_get, NULL, ws_pae_supp_kmp_service_api_get) < 0) { goto error; } @@ -922,13 +929,13 @@ static void ws_pae_supp_initial_trickle_timer_start(pae_supp_t *pae_supp) * 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; + pae_supp->auth_trickle_params = pae_supp->sec_cfg->prot_cfg.initial_key_trickle_params; + pae_supp->initial_key_retry_timer = pae_supp->sec_cfg->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 = pae_supp->sec_prot_cfg->initial_key_retry_cnt; + pae_supp->initial_key_retry_cnt = pae_supp->sec_cfg->prot_cfg.initial_key_retry_cnt; } static void ws_pae_supp_initial_last_interval_trickle_timer_start(pae_supp_t *pae_supp) @@ -946,8 +953,8 @@ static void ws_pae_supp_initial_last_interval_trickle_timer_start(pae_supp_t *pa static void ws_pae_supp_initial_key_update_trickle_timer_start(pae_supp_t *pae_supp, uint8_t timer_expirations) { // Starts trickle for the key update - pae_supp->auth_trickle_params.Imin = pae_supp->sec_timer_cfg->gtk_request_imin; - pae_supp->auth_trickle_params.Imax = pae_supp->sec_timer_cfg->gtk_request_imax; + pae_supp->auth_trickle_params.Imin = pae_supp->sec_cfg->timer_cfg.gtk_request_imin; + pae_supp->auth_trickle_params.Imax = pae_supp->sec_cfg->timer_cfg.gtk_request_imax; pae_supp->auth_trickle_params.k = 0; pae_supp->auth_trickle_params.TimerExpirations = timer_expirations; @@ -1104,8 +1111,12 @@ static kmp_api_t *ws_pae_supp_kmp_service_api_get(kmp_service_t *service, kmp_ap return ws_pae_lib_kmp_list_type_get(&pae_supp->entry.kmp_list, type); } -static kmp_api_t *ws_pae_supp_kmp_incoming_ind(kmp_service_t *service, kmp_type_e type, const kmp_addr_t *addr) +static kmp_api_t *ws_pae_supp_kmp_incoming_ind(kmp_service_t *service, uint8_t instance_id, kmp_type_e type, const kmp_addr_t *addr, const void *pdu, uint16_t size) { + (void) instance_id; + (void) pdu; + (void) size; + // Should be MKA, 4WH or GKH and never initial EAPOL-key for supplicant if (type > IEEE_802_1X_INITIAL_KEY) { return NULL; @@ -1164,7 +1175,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, pae_supp->sec_timer_cfg); + kmp_api_t *kmp = kmp_api_create(service, type, 0, pae_supp->sec_cfg); if (!kmp) { return NULL; } diff --git a/source/6LoWPAN/ws/ws_pae_supp.h b/source/6LoWPAN/ws/ws_pae_supp.h index 33174954a77a..bed5ebc7e27a 100644 --- a/source/6LoWPAN/ws/ws_pae_supp.h +++ b/source/6LoWPAN/ws/ws_pae_supp.h @@ -38,15 +38,14 @@ * * \param interface_ptr interface * \param cert_chain certificate chain - * \param sec_timer_cfg timer configuration - * \param sec_prot_cfg protocol configuration + * \param sec_cfg security 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, sec_prot_keys_nw_info_t *sec_keys_nw_info); +int8_t ws_pae_supp_init(protocol_interface_info_entry_t *interface_ptr, const sec_prot_certs_t *certs, sec_cfg_t *sec_cfg, sec_prot_keys_nw_info_t *sec_keys_nw_info); /** * ws_pae_supp_delete deletes PAE supplicant diff --git a/source/6LoWPAN/ws/ws_pae_timers.c b/source/6LoWPAN/ws/ws_pae_timers.c index a07d0e6debcb..fb1abbe275df 100644 --- a/source/6LoWPAN/ws/ws_pae_timers.c +++ b/source/6LoWPAN/ws/ws_pae_timers.c @@ -144,9 +144,9 @@ static void ws_pae_timers_calculate(sec_timer_cfg_t *timer_settings) } } -bool ws_pae_timers_gtk_new_install_required(sec_timer_cfg_t *timer_settings, uint32_t seconds) +bool ws_pae_timers_gtk_new_install_required(sec_cfg_t *sec_cfg, uint32_t seconds) { - uint32_t gtk_new_install_req_seconds = timer_settings->gtk_expire_offset - timer_settings->gtk_new_install_req * timer_settings->gtk_expire_offset / 100; + uint32_t gtk_new_install_req_seconds = sec_cfg->timer_cfg.gtk_expire_offset - sec_cfg->timer_cfg.gtk_new_install_req * sec_cfg->timer_cfg.gtk_expire_offset / 100; if (seconds < gtk_new_install_req_seconds) { return true; @@ -155,9 +155,9 @@ bool ws_pae_timers_gtk_new_install_required(sec_timer_cfg_t *timer_settings, uin } } -bool ws_pae_timers_gtk_new_activation_time(sec_timer_cfg_t *timer_settings, uint32_t seconds) +bool ws_pae_timers_gtk_new_activation_time(sec_cfg_t *sec_cfg, uint32_t seconds) { - uint32_t gtk_gtk_new_activation_time_seconds = timer_settings->gtk_expire_offset / timer_settings->gtk_new_act_time; + uint32_t gtk_gtk_new_activation_time_seconds = sec_cfg->timer_cfg.gtk_expire_offset / sec_cfg->timer_cfg.gtk_new_act_time; if (seconds < gtk_gtk_new_activation_time_seconds) { return true; @@ -166,9 +166,9 @@ bool ws_pae_timers_gtk_new_activation_time(sec_timer_cfg_t *timer_settings, uint } } -uint32_t ws_pae_timers_gtk_revocation_lifetime_get(sec_timer_cfg_t *timer_settings) +uint32_t ws_pae_timers_gtk_revocation_lifetime_get(sec_cfg_t *sec_cfg) { - return timer_settings->gtk_expire_offset / timer_settings->revocat_lifetime_reduct; + return sec_cfg->timer_cfg.gtk_expire_offset / sec_cfg->timer_cfg.revocat_lifetime_reduct; } #endif /* HAVE_WS */ diff --git a/source/6LoWPAN/ws/ws_pae_timers.h b/source/6LoWPAN/ws/ws_pae_timers.h index 7b8f58052d68..57fceb97cbf6 100644 --- a/source/6LoWPAN/ws/ws_pae_timers.h +++ b/source/6LoWPAN/ws/ws_pae_timers.h @@ -53,35 +53,35 @@ void ws_pae_timers_gtk_time_settings_set(sec_timer_cfg_t *timer_settings, uint8_ /** * ws_pae_timers_gtk_new_install_required GTK new install required check * - * \param timer_settings timer settings + * \param sec_cfg security configuration * \param seconds elapsed seconds * * \return true new GTK install required expired * \return false GTK install not required * */ -bool ws_pae_timers_gtk_new_install_required(sec_timer_cfg_t *timer_settings, uint32_t seconds); +bool ws_pae_timers_gtk_new_install_required(sec_cfg_t *sec_cfg, uint32_t seconds); /** * ws_pae_timers_gtk_new_activation_time GTK new activation time * - * \param timer_settings timer settings + * \param sec_cfg security configuration * \param seconds elapsed seconds * * \return true GTK new activation time expired * \return false GTK new activation time not expired * */ -bool ws_pae_timers_gtk_new_activation_time(sec_timer_cfg_t *timer_settings, uint32_t seconds); +bool ws_pae_timers_gtk_new_activation_time(sec_cfg_t *sec_cfg, uint32_t seconds); /** * ws_pae_timers_gtk_revocation_lifetime_get GTK revocation lifetime get * - * \param timer_settings timer settings + * \param sec_cfg security configuration * * \return GTK revocation lifetime * */ -uint32_t ws_pae_timers_gtk_revocation_lifetime_get(sec_timer_cfg_t *timer_settings); +uint32_t ws_pae_timers_gtk_revocation_lifetime_get(sec_cfg_t *sec_cfg); #endif /* WS_PAE_TIMERS_H_ */ diff --git a/source/Security/kmp/kmp_api.c b/source/Security/kmp/kmp_api.c index d3a61fe867d2..e175d9a851ff 100644 --- a/source/Security/kmp/kmp_api.c +++ b/source/Security/kmp/kmp_api.c @@ -61,17 +61,26 @@ typedef struct { typedef NS_LIST_HEAD(kmp_sec_prot_entry_t, link) kmp_sec_prot_list_t; +typedef struct { + uint8_t instance_id; /**< Message interface instance identifier */ + uint8_t header_size; /**< Message interface header size */ + kmp_service_msg_if_send *send; /**< Message interface callback to send KMP frames */ + ns_list_link_t link; /**< Link */ +} kmp_msg_if_entry_t; + +typedef NS_LIST_HEAD(kmp_msg_if_entry_t, link) kmp_msg_if_list_t; + struct kmp_service_s { kmp_sec_prot_list_t sec_prot_list; /**< Security protocols list */ + kmp_msg_if_list_t msg_if_list; /**< Message interface list */ kmp_service_incoming_ind *incoming_ind; /**< Callback to application to indicate incoming KMP frame */ kmp_service_tx_status_ind *tx_status_ind; /**< Callback to application to indicate TX status */ kmp_service_addr_get *addr_get; /**< Callback to get addresses related to KMP */ + kmp_service_ip_addr_get *ip_addr_get; /**< Callback to get IP addresses related to KMP */ kmp_service_api_get *api_get; /**< Callback to get KMP API from a service */ - kmp_service_msg_if_send *send; /**< Callback to send KMP frames */ kmp_service_timer_if_start *timer_start; /**< Callback to start timer */ kmp_service_timer_if_stop *timer_stop; /**< Callback to stop timer */ kmp_service_event_if_event_send *event_send; /**< Callback to send event */ - uint8_t header_size; /**< Header size */ ns_list_link_t link; /**< Link */ }; @@ -85,6 +94,7 @@ static NS_LIST_DEFINE(kmp_service_list, kmp_service_t, link); // KMP instance identifier value static uint8_t kmp_instance_identifier = 0; +static kmp_msg_if_entry_t *kmp_api_msg_if_get(kmp_service_t *service, uint8_t msg_if_instance_id); static void kmp_api_sec_prot_create_confirm(sec_prot_t *prot, sec_prot_result_e result); static void kmp_api_sec_prot_create_indication(sec_prot_t *prot); static void kmp_api_sec_prot_finished_indication(sec_prot_t *prot, sec_prot_result_e result, sec_prot_keys_t *sec_keys); @@ -94,12 +104,13 @@ static void kmp_sec_prot_timer_start(sec_prot_t *prot); static void kmp_sec_prot_timer_stop(sec_prot_t *prot); static void kmp_sec_prot_state_machine_call(sec_prot_t *prot); static void kmp_sec_prot_eui64_addr_get(sec_prot_t *prot, uint8_t *local_eui64, uint8_t *remote_eui64); +static void kmp_sec_prot_ip_addr_get(sec_prot_t *prot, uint8_t *address); static sec_prot_t *kmp_sec_prot_by_type_get(sec_prot_t *prot, uint8_t type); 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 *prot_cfg, sec_timer_cfg_t *timer_cfg) +kmp_api_t *kmp_api_create(kmp_service_t *service, kmp_type_e type, uint8_t msg_if_instance_id, sec_cfg_t *sec_cfg) { if (!service) { return 0; @@ -120,6 +131,11 @@ kmp_api_t *kmp_api_create(kmp_service_t *service, kmp_type_e type, sec_prot_cfg_ // Size for security protocol internal data uint16_t sec_size = sec_prot->size(); + kmp_msg_if_entry_t *msg_if_entry = kmp_api_msg_if_get(service, msg_if_instance_id); + if (!msg_if_entry) { + return 0; + } + kmp_api_t *kmp = ns_dyn_mem_temporary_alloc(sizeof(kmp_api_t) + sec_size); if (!kmp) { return 0; @@ -137,9 +153,10 @@ kmp_api_t *kmp_api_create(kmp_service_t *service, kmp_type_e type, sec_prot_cfg_ kmp->timer_start_pending = false; kmp->receive_disable = false; - memset(&kmp->sec_prot, 0, sec_size); + memset(&kmp->sec_prot, 0, sec_size + offsetof(sec_prot_t, data)); - kmp->sec_prot.header_size = service->header_size; + kmp->sec_prot.header_size = msg_if_entry->header_size; + kmp->sec_prot.receive_peer_hdr_size = msg_if_entry->header_size; kmp->sec_prot.create_conf = kmp_api_sec_prot_create_confirm; kmp->sec_prot.create_ind = kmp_api_sec_prot_create_indication; kmp->sec_prot.finished_ind = kmp_api_sec_prot_finished_indication; @@ -149,10 +166,11 @@ kmp_api_t *kmp_api_create(kmp_service_t *service, kmp_type_e type, sec_prot_cfg_ kmp->sec_prot.timer_stop = kmp_sec_prot_timer_stop; kmp->sec_prot.state_machine_call = kmp_sec_prot_state_machine_call; kmp->sec_prot.addr_get = kmp_sec_prot_eui64_addr_get; + kmp->sec_prot.ip_addr_get = kmp_sec_prot_ip_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.prot_cfg = prot_cfg; - kmp->sec_prot.timer_cfg = timer_cfg; + kmp->sec_prot.sec_cfg = sec_cfg; + kmp->sec_prot.msg_if_instance_id = msg_if_instance_id; if (sec_prot->init(&kmp->sec_prot) < 0) { ns_dyn_mem_free(kmp); @@ -162,6 +180,16 @@ kmp_api_t *kmp_api_create(kmp_service_t *service, kmp_type_e type, sec_prot_cfg_ return (kmp_api_t *) kmp; } +static kmp_msg_if_entry_t *kmp_api_msg_if_get(kmp_service_t *service, uint8_t msg_if_instance_id) +{ + ns_list_foreach(kmp_msg_if_entry_t, list_entry, &service->msg_if_list) { + if (list_entry->instance_id == msg_if_instance_id) { + return list_entry; + } + } + return NULL; +} + int8_t kmp_api_start(kmp_api_t *kmp) { if (kmp->timer_start_pending) { @@ -216,12 +244,19 @@ static int8_t kmp_sec_prot_send(sec_prot_t *prot, void *pdu, uint16_t size) kmp_type_e kmp_id = kmp->type; if (kmp_id > IEEE_802_1X_INITIAL_KEY) { kmp_id -= IEEE_802_1X_INITIAL_KEY; + } else if (kmp_id == RADIUS_IEEE_802_1X_MKA) { + kmp_id = IEEE_802_1X_MKA; + } + + kmp_msg_if_entry_t *msg_if_entry = kmp_api_msg_if_get(kmp->service, prot->msg_if_instance_id); + if (!msg_if_entry) { + return -1; } int8_t result = -1; - if (kmp->service->send) { - result = kmp->service->send(kmp->service, kmp_id, kmp->addr, pdu, size, kmp->instance_identifier); + if (msg_if_entry->send) { + result = msg_if_entry->send(kmp->service, prot->msg_if_instance_id, kmp_id, kmp->addr, pdu, size, kmp->instance_identifier); } if (result < 0) { @@ -267,6 +302,13 @@ static void kmp_sec_prot_eui64_addr_get(sec_prot_t *prot, uint8_t *local_eui64, } } +static void kmp_sec_prot_ip_addr_get(sec_prot_t *prot, uint8_t *address) +{ + kmp_api_t *kmp = kmp_api_get_from_prot(prot); + + kmp->service->ip_addr_get(kmp->service, kmp, address); +} + static sec_prot_t *kmp_sec_prot_by_type_get(sec_prot_t *prot, uint8_t type) { kmp_api_t *kmp = kmp_api_get_from_prot(prot); @@ -277,9 +319,15 @@ static sec_prot_t *kmp_sec_prot_by_type_get(sec_prot_t *prot, uint8_t type) case SEC_PROT_TYPE_EAP_TLS: kmp_type = IEEE_802_1X_MKA; break; + case SEC_PROT_TYPE_RADIUS_EAP_TLS: + kmp_type = RADIUS_IEEE_802_1X_MKA; + break; case SEC_PROT_TYPE_TLS: kmp_type = TLS_PROT; break; + case SEC_PROT_TYPE_RADIUS_CLIENT: + kmp_type = RADIUS_CLIENT_PROT; + break; default: return NULL; } @@ -328,6 +376,17 @@ bool kmp_api_receive_disable(kmp_api_t *kmp) return kmp->receive_disable; } +bool kmp_api_receive_check(kmp_api_t *kmp, const void *pdu, uint16_t size) +{ + if (kmp->sec_prot.receive_check) { + int8_t ret = kmp->sec_prot.receive_check(&kmp->sec_prot, pdu, size); + if (ret >= 0) { + return true; + } + } + return false; +} + kmp_type_e kmp_api_type_from_id_get(uint8_t kmp_id) { switch (kmp_id) { @@ -380,12 +439,11 @@ kmp_service_t *kmp_service_create(void) } ns_list_init(&service->sec_prot_list); + ns_list_init(&service->msg_if_list); service->incoming_ind = 0; service->tx_status_ind = 0; service->addr_get = 0; service->api_get = 0; - service->send = 0; - service->header_size = 0; ns_list_add_to_start(&kmp_service_list, service); @@ -404,7 +462,10 @@ int8_t kmp_service_delete(kmp_service_t *service) ns_list_remove(&list_entry->sec_prot_list, sec_list_entry); ns_dyn_mem_free(sec_list_entry); } - + ns_list_foreach_safe(kmp_msg_if_entry_t, msg_if_list_entry, &list_entry->msg_if_list) { + ns_list_remove(&list_entry->msg_if_list, msg_if_list_entry); + ns_dyn_mem_free(msg_if_list_entry); + } ns_list_remove(&kmp_service_list, list_entry); ns_dyn_mem_free(list_entry); return 0; @@ -420,7 +481,7 @@ static void kmp_sec_prot_state_machine_call(sec_prot_t *prot) kmp->service->event_send(kmp->service, prot); } -int8_t kmp_service_cb_register(kmp_service_t *service, kmp_service_incoming_ind *incoming_ind, kmp_service_tx_status_ind *tx_status_ind, kmp_service_addr_get *addr_get, kmp_service_api_get *api_get) +int8_t kmp_service_cb_register(kmp_service_t *service, kmp_service_incoming_ind *incoming_ind, kmp_service_tx_status_ind *tx_status_ind, kmp_service_addr_get *addr_get, kmp_service_ip_addr_get *ip_addr_get, kmp_service_api_get *api_get) { if (!service) { return -1; @@ -429,30 +490,60 @@ int8_t kmp_service_cb_register(kmp_service_t *service, kmp_service_incoming_ind service->incoming_ind = incoming_ind; service->tx_status_ind = tx_status_ind; service->addr_get = addr_get; + service->ip_addr_get = ip_addr_get; service->api_get = api_get; return 0; } -int8_t kmp_service_msg_if_register(kmp_service_t *service, kmp_service_msg_if_send *send, uint8_t header_size) +int8_t kmp_service_msg_if_register(kmp_service_t *service, uint8_t instance_id, kmp_service_msg_if_send *send, uint8_t header_size) { if (!service) { return -1; } - service->send = send; - service->header_size = header_size; + kmp_msg_if_entry_t *entry = NULL; + + ns_list_foreach(kmp_msg_if_entry_t, list_entry, &service->msg_if_list) { + // Message interface already registered + if (list_entry->instance_id == instance_id) { + entry = list_entry; + break; + } + } + + // If removing message interface + if (send == NULL) { + if (entry != NULL) { + ns_list_remove(&service->msg_if_list, entry); + ns_dyn_mem_free(entry); + } + return 0; + } + + // Allocate new entry if does not exists + if (entry == NULL) { + entry = ns_dyn_mem_temporary_alloc(sizeof(kmp_msg_if_entry_t)); + if (entry == NULL) { + return -1; + } + ns_list_add_to_start(&service->msg_if_list, entry); + } + + entry->instance_id = instance_id; + entry->send = send; + entry->header_size = header_size; return 0; } -int8_t kmp_service_msg_if_receive(kmp_service_t *service, kmp_type_e type, const kmp_addr_t *addr, void *pdu, uint16_t size) +int8_t kmp_service_msg_if_receive(kmp_service_t *service, uint8_t instance_id, kmp_type_e type, const kmp_addr_t *addr, void *pdu, uint16_t size) { if (!service) { return -1; } - kmp_api_t *kmp = (kmp_api_t *) service->incoming_ind(service, type, addr); + kmp_api_t *kmp = (kmp_api_t *) service->incoming_ind(service, instance_id, type, addr, pdu, size); if (!kmp) { return -1; } diff --git a/source/Security/kmp/kmp_api.h b/source/Security/kmp/kmp_api.h index 10f36528bddd..f51a14058869 100644 --- a/source/Security/kmp/kmp_api.h +++ b/source/Security/kmp/kmp_api.h @@ -31,16 +31,19 @@ typedef enum { KMP_TYPE_NONE = 0, - IEEE_802_1X_MKA = 1, - IEEE_802_11_4WH = 6, - IEEE_802_11_GKH = 7, - TLS_PROT = 8, + IEEE_802_1X_MKA = 1, + RADIUS_IEEE_802_1X_MKA = 2, + IEEE_802_11_4WH = 6, + IEEE_802_11_GKH = 7, + TLS_PROT = 8, + RADIUS_CLIENT_PROT = 9, IEEE_802_1X_INITIAL_KEY = 10, - IEEE_802_1X_MKA_KEY = 11, - IEEE_802_11_4WH_KEY = 16, - IEEE_802_11_GKH_KEY = 17 + IEEE_802_1X_MKA_KEY = 11, + RADIUS_IEEE_802_1X_MKA_KEY = 12, + IEEE_802_11_4WH_KEY = 16, + IEEE_802_11_GKH_KEY = 17 } kmp_type_e; typedef enum { @@ -125,13 +128,13 @@ typedef void kmp_api_finished(kmp_api_t *kmp); * * \param service KMP service * \param type KMP type - * \param prot_cfg protocol configuration - * \param timer_cfg timer configuration + * \param msg_if_instance_id message interface instance identifier + * \param sec_cfg security configuration * * \return KMP instance or NULL * */ -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_t *kmp_api_create(kmp_service_t *service, kmp_type_e type, uint8_t msg_if_instance_id, sec_cfg_t *sec_cfg); /** * kmp_api_start start KMP api @@ -172,6 +175,18 @@ kmp_type_e kmp_api_type_get(kmp_api_t *kmp); */ bool kmp_api_receive_disable(kmp_api_t *kmp); +/** + * kmp_api_receive_check check if received message is for this KMP + * + * \param kmp instance + * \param pdu pdu + * \param size pdu size + * + * \return true/false true if message is for this KMP + * + */ +bool kmp_api_receive_check(kmp_api_t *kmp, const void *pdu, uint16_t size); + /** * kmp_api_type_from_id_get get KMP type from KMP id * @@ -274,13 +289,14 @@ int8_t kmp_service_delete(kmp_service_t *service); * kmp_service_incoming_ind Notifies application about incoming KMP frame * * \param service KMP service + * \param instance_id instance identifier * \param type protocol type * \param addr address * * \return KMP instance or NULL * */ -typedef kmp_api_t *kmp_service_incoming_ind(kmp_service_t *service, kmp_type_e type, const kmp_addr_t *addr); +typedef kmp_api_t *kmp_service_incoming_ind(kmp_service_t *service, uint8_t instance_id, kmp_type_e type, const kmp_addr_t *addr, const void *pdu, uint16_t size); /** * kmp_service_tx_status_ind Notifies application about TX status @@ -304,6 +320,16 @@ typedef kmp_api_t *kmp_service_tx_status_ind(kmp_service_t *service, uint8_t ins */ typedef void kmp_service_addr_get(kmp_service_t *service, kmp_api_t *kmp, kmp_addr_t *local_addr, kmp_addr_t *remote_addr); +/** + * kmp_service_ip_addr_get gets IP addressing information related to KMP + * + * \param service KMP service + * \param kmp KMP instance + * \param address IP address + * + */ +typedef void kmp_service_ip_addr_get(kmp_service_t *service, kmp_api_t *kmp, uint8_t *address); + /** * kmp_service_api_get gets KMP API from KMP service * @@ -323,18 +349,20 @@ typedef kmp_api_t *kmp_service_api_get(kmp_service_t *service, kmp_api_t *kmp, k * \param incoming_ind incoming message callback * \param tx_status tx status callback * \param addr_get gets addressing information callback + * \param ip_addr_get gets IP addressing information callback * \param api_get gets KMP API from KMP service * * \return < 0 failure * \return >= 0 success * */ -int8_t kmp_service_cb_register(kmp_service_t *service, kmp_service_incoming_ind *incoming_ind, kmp_service_tx_status_ind *tx_status_ind, kmp_service_addr_get *addr_get, kmp_service_api_get *api_get); +int8_t kmp_service_cb_register(kmp_service_t *service, kmp_service_incoming_ind *incoming_ind, kmp_service_tx_status_ind *tx_status_ind, kmp_service_addr_get *addr_get, kmp_service_ip_addr_get *ip_addr_get, kmp_service_api_get *api_get); /** * kmp_service_msg_if_receive receive a message * * \param service KMP service + * \param instance_id instance identifier * \param type protocol type * \param addr address * \param pdu pdu @@ -344,12 +372,13 @@ int8_t kmp_service_cb_register(kmp_service_t *service, kmp_service_incoming_ind * \return >= 0 success * */ -int8_t kmp_service_msg_if_receive(kmp_service_t *service, kmp_type_e kmp_id, const kmp_addr_t *addr, void *pdu, uint16_t size); +int8_t kmp_service_msg_if_receive(kmp_service_t *service, uint8_t instance_id, kmp_type_e kmp_id, const kmp_addr_t *addr, void *pdu, uint16_t size); /** * kmp_service_msg_if_send send a message * * \param service KMP service + * \param instance_id instance identifier * \param type protocol type * \param addr address * \param pdu pdu @@ -360,12 +389,13 @@ int8_t kmp_service_msg_if_receive(kmp_service_t *service, kmp_type_e kmp_id, con * \return >= 0 success * */ -typedef int8_t kmp_service_msg_if_send(kmp_service_t *service, kmp_type_e type, const kmp_addr_t *addr, void *pdu, uint16_t size, uint8_t tx_identifier); +typedef int8_t kmp_service_msg_if_send(kmp_service_t *service, uint8_t instance_id, kmp_type_e type, const kmp_addr_t *addr, void *pdu, uint16_t size, uint8_t tx_identifier); /** * kmp_service_msg_if_register registers message interface * * \param service KMP service + * \param instance_id message interface instance identifier * \param send KMP PDU send callback * \param header_size header size * @@ -373,7 +403,7 @@ typedef int8_t kmp_service_msg_if_send(kmp_service_t *service, kmp_type_e type, * \return >= 0 success * */ -int8_t kmp_service_msg_if_register(kmp_service_t *service, kmp_service_msg_if_send *send, uint8_t header_size); +int8_t kmp_service_msg_if_register(kmp_service_t *service, uint8_t instance_id, kmp_service_msg_if_send *send, uint8_t header_size); /** * kmp_service_tx_status tx status indication diff --git a/source/Security/kmp/kmp_eapol_pdu_if.c b/source/Security/kmp/kmp_eapol_pdu_if.c index 6cf5c8f064ef..f12bc517b979 100644 --- a/source/Security/kmp/kmp_eapol_pdu_if.c +++ b/source/Security/kmp/kmp_eapol_pdu_if.c @@ -49,7 +49,7 @@ typedef struct { static NS_LIST_DEFINE(kmp_eapol_pdu_if_list, kmp_eapol_pdu_if_t, link); -static int8_t kmp_eapol_pdu_if_send(kmp_service_t *service, kmp_type_e kmp_id, const kmp_addr_t *addr, void *pdu, uint16_t size, uint8_t tx_identifier); +static int8_t kmp_eapol_pdu_if_send(kmp_service_t *service, uint8_t instance_id, kmp_type_e kmp_id, const kmp_addr_t *addr, void *pdu, uint16_t size, uint8_t tx_identifier); static int8_t kmp_eapol_pdu_if_tx_status(protocol_interface_info_entry_t *interface_ptr, eapol_pdu_tx_status_e tx_status, uint8_t tx_identifier); int8_t kmp_eapol_pdu_if_register(kmp_service_t *service, protocol_interface_info_entry_t *interface_ptr) @@ -72,7 +72,7 @@ int8_t kmp_eapol_pdu_if_register(kmp_service_t *service, protocol_interface_info eapol_pdu_if->kmp_service = service; eapol_pdu_if->interface_ptr = interface_ptr; - if (kmp_service_msg_if_register(service, kmp_eapol_pdu_if_send, EAPOL_PDU_IF_HEADER_SIZE) < 0) { + if (kmp_service_msg_if_register(service, 0, kmp_eapol_pdu_if_send, EAPOL_PDU_IF_HEADER_SIZE) < 0) { ns_dyn_mem_free(eapol_pdu_if); return -1; } @@ -92,14 +92,16 @@ int8_t kmp_eapol_pdu_if_unregister(kmp_service_t *service) if (entry->kmp_service == service) { ns_list_remove(&kmp_eapol_pdu_if_list, entry); ns_dyn_mem_free(entry); - kmp_service_msg_if_register(service, NULL, 0); + kmp_service_msg_if_register(service, 0, NULL, 0); } } return 0; } -static int8_t kmp_eapol_pdu_if_send(kmp_service_t *service, kmp_type_e kmp_id, const kmp_addr_t *addr, void *pdu, uint16_t size, uint8_t tx_identifier) +static int8_t kmp_eapol_pdu_if_send(kmp_service_t *service, uint8_t instance_id, kmp_type_e kmp_id, const kmp_addr_t *addr, void *pdu, uint16_t size, uint8_t tx_identifier) { + (void) instance_id; // Only one instance of eapol interface possible + if (!service || !addr || !pdu) { return -1; } @@ -157,7 +159,7 @@ int8_t kmp_eapol_pdu_if_receive(protocol_interface_info_entry_t *interface_ptr, return -1; } - int8_t ret = kmp_service_msg_if_receive(service, type, &addr, data_pdu, data_pdu_size); + int8_t ret = kmp_service_msg_if_receive(service, 0, type, &addr, data_pdu, data_pdu_size); return ret; } diff --git a/source/Security/kmp/kmp_socket_if.c b/source/Security/kmp/kmp_socket_if.c index 79aca99ee658..66c78b10392f 100644 --- a/source/Security/kmp/kmp_socket_if.c +++ b/source/Security/kmp/kmp_socket_if.c @@ -43,51 +43,91 @@ typedef struct { kmp_service_t *kmp_service; /**< KMP service */ + uint8_t instance_id; /**< Instance identifier */ + bool relay; /**< Interface is relay interface */ ns_address_t remote_addr; /**< Remote address */ int8_t socket_id; /**< Socket ID */ + bool socket_id_set; /**< Socket ID is set */ ns_list_link_t link; /**< Link */ } kmp_socket_if_t; -static int8_t kmp_socket_if_send(kmp_service_t *service, kmp_type_e kmp_id, const kmp_addr_t *addr, void *pdu, uint16_t size, uint8_t tx_identifier); +static int8_t kmp_socket_if_send(kmp_service_t *service, uint8_t instance_id, kmp_type_e kmp_id, const kmp_addr_t *addr, void *pdu, uint16_t size, uint8_t tx_identifier); static void kmp_socket_if_socket_cb(void *ptr); static NS_LIST_DEFINE(kmp_socket_if_list, kmp_socket_if_t, link); +static uint8_t kmp_socket_if_instance_id = 1; -int8_t kmp_socket_if_register(kmp_service_t *service, uint16_t local_port, const uint8_t *remote_addr, uint16_t remote_port) +int8_t kmp_socket_if_register(kmp_service_t *service, uint8_t *instance_id, bool relay, uint16_t local_port, const uint8_t *remote_addr, uint16_t remote_port) { if (!service || !remote_addr) { return -1; } + kmp_socket_if_t *socket_if = NULL; + bool new_socket_if_allocated = false; + ns_list_foreach(kmp_socket_if_t, entry, &kmp_socket_if_list) { - if (entry->kmp_service == service) { - return -1; + if (entry->kmp_service == service && entry->instance_id == *instance_id) { + socket_if = entry; } } - kmp_socket_if_t *socket_if = ns_dyn_mem_alloc(sizeof(kmp_socket_if_t)); if (!socket_if) { - return -1; + socket_if = ns_dyn_mem_alloc(sizeof(kmp_socket_if_t)); + if (!socket_if) { + return -1; + } + memset(socket_if, 0, sizeof(kmp_socket_if_t)); + socket_if->socket_id = -1; + new_socket_if_allocated = true; } socket_if->kmp_service = service; + if (*instance_id == 0) { + socket_if->instance_id = kmp_socket_if_instance_id++; + if (socket_if->instance_id == 0) { + socket_if->instance_id++; + } + *instance_id = socket_if->instance_id; + } + + socket_if->relay = relay; + socket_if->remote_addr.type = ADDRESS_IPV6; + + bool address_changed = false; + if (memcmp(&socket_if->remote_addr.address, remote_addr, 16) != 0 || + socket_if->remote_addr.identifier != remote_port) { + address_changed = true; + } memcpy(&socket_if->remote_addr.address, remote_addr, 16); socket_if->remote_addr.identifier = remote_port; - socket_if->socket_id = socket_open(IPV6_NH_UDP, local_port, &kmp_socket_if_socket_cb); - if (socket_if->socket_id < 0) { - ns_dyn_mem_free(socket_if); - return -1; + if (socket_if->socket_id < 0 || address_changed) { + if (socket_if->socket_id >= 0) { + socket_close(socket_if->socket_id); + } + socket_if->socket_id = socket_open(IPV6_NH_UDP, local_port, &kmp_socket_if_socket_cb); + if (socket_if->socket_id < 0) { + ns_dyn_mem_free(socket_if); + return -1; + } + } + + uint8_t header_size = 0; + if (relay) { + header_size = SOCKET_IF_HEADER_SIZE; } - if (kmp_service_msg_if_register(service, kmp_socket_if_send, SOCKET_IF_HEADER_SIZE) < 0) { + if (kmp_service_msg_if_register(service, *instance_id, kmp_socket_if_send, header_size) < 0) { ns_dyn_mem_free(socket_if); return -1; } - ns_list_add_to_end(&kmp_socket_if_list, socket_if); + if (new_socket_if_allocated) { + ns_list_add_to_end(&kmp_socket_if_list, socket_if); + } return 0; } @@ -102,14 +142,14 @@ int8_t kmp_socket_if_unregister(kmp_service_t *service) if (entry->kmp_service == service) { ns_list_remove(&kmp_socket_if_list, entry); socket_close(entry->socket_id); + kmp_service_msg_if_register(service, entry->instance_id, NULL, 0); ns_dyn_mem_free(entry); - kmp_service_msg_if_register(service, NULL, 0); } } return 0; } -static int8_t kmp_socket_if_send(kmp_service_t *service, kmp_type_e kmp_id, const kmp_addr_t *addr, void *pdu, uint16_t size, uint8_t tx_identifier) +static int8_t kmp_socket_if_send(kmp_service_t *service, uint8_t instance_id, kmp_type_e kmp_id, const kmp_addr_t *addr, void *pdu, uint16_t size, uint8_t tx_identifier) { (void) tx_identifier; @@ -120,7 +160,7 @@ static int8_t kmp_socket_if_send(kmp_service_t *service, kmp_type_e kmp_id, cons kmp_socket_if_t *socket_if = NULL; ns_list_foreach(kmp_socket_if_t, entry, &kmp_socket_if_list) { - if (entry->kmp_service == service) { + if (entry->kmp_service == service && entry->instance_id == instance_id) { socket_if = entry; break; } @@ -130,14 +170,16 @@ static int8_t kmp_socket_if_send(kmp_service_t *service, kmp_type_e kmp_id, cons return -1; } - //Build UPD Relay - uint8_t *ptr = pdu; - memcpy(ptr, addr->relay_address, 16); - ptr += 16; - ptr = common_write_16_bit(addr->port, ptr); - memcpy(ptr, kmp_address_eui_64_get(addr), 8); - ptr += 8; - *ptr = kmp_id; + if (socket_if->relay) { + //Build UPD Relay + uint8_t *ptr = pdu; + memcpy(ptr, addr->relay_address, 16); + ptr += 16; + ptr = common_write_16_bit(addr->port, ptr); + memcpy(ptr, kmp_address_eui_64_get(addr), 8); + ptr += 8; + *ptr = kmp_id; + } socket_sendto(socket_if->socket_id, &socket_if->remote_addr, pdu, size); ns_dyn_mem_free(pdu); @@ -172,25 +214,30 @@ static void kmp_socket_if_socket_cb(void *ptr) ns_dyn_mem_free(pdu); return; } - kmp_addr_t addr; - addr.type = KMP_ADDR_EUI_64_AND_IP; + kmp_addr_t addr; + memset(&addr, 0, sizeof(kmp_addr_t)); + kmp_type_e type = KMP_TYPE_NONE; uint8_t *data_ptr = pdu; - memcpy(addr.relay_address, data_ptr, 16); - data_ptr += 16; - addr.port = common_read_16_bit(data_ptr); - data_ptr += 2; - memcpy(addr.eui_64, data_ptr, 8); - data_ptr += 8; - - kmp_type_e type = kmp_api_type_from_id_get(*data_ptr++); - if (type == KMP_TYPE_NONE) { - ns_dyn_mem_free(pdu); - return; - } + if (socket_if->relay) { + addr.type = KMP_ADDR_EUI_64_AND_IP; + memcpy(addr.relay_address, data_ptr, 16); + data_ptr += 16; + addr.port = common_read_16_bit(data_ptr); + data_ptr += 2; + memcpy(addr.eui_64, data_ptr, 8); + data_ptr += 8; + + type = kmp_api_type_from_id_get(*data_ptr++); + if (type == KMP_TYPE_NONE) { + ns_dyn_mem_free(pdu); + return; + } + cb_data->d_len -= SOCKET_IF_HEADER_SIZE; + } - kmp_service_msg_if_receive(socket_if->kmp_service, type, &addr, data_ptr, cb_data->d_len - 27); + kmp_service_msg_if_receive(socket_if->kmp_service, socket_if->instance_id, type, &addr, data_ptr, cb_data->d_len); ns_dyn_mem_free(pdu); } diff --git a/source/Security/kmp/kmp_socket_if.h b/source/Security/kmp/kmp_socket_if.h index af1d6950818b..20a55c8f45fc 100644 --- a/source/Security/kmp/kmp_socket_if.h +++ b/source/Security/kmp/kmp_socket_if.h @@ -33,6 +33,8 @@ * kmp_socket_if_register register socket interface to KMP service * * \param service KMP service to register to + * \param instance_id instance identifier, for new instance set to zero when called + * \param relay interface is relay interface * \param local_port local port * \param remote_addr remote address * \param remote_port remote port @@ -41,7 +43,7 @@ * \return >= 0 success * */ -int8_t kmp_socket_if_register(kmp_service_t *service, uint16_t local_port, const uint8_t *remote_addr, uint16_t remote_port); +int8_t kmp_socket_if_register(kmp_service_t *service, uint8_t *instance_id, bool relay, uint16_t local_port, const uint8_t *remote_addr, uint16_t remote_port); /** * kmp_socket_if_unregister unregister socket interface from KMP service 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 2fd7d96b65bc..84d3c013fa0a 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->prot_cfg->sec_prot_trickle_params); + sec_prot_timer_trickle_start(&data->common, &prot->sec_cfg->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->prot_cfg->sec_prot_trickle_params, ticks); + &prot->sec_cfg->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->prot_cfg->sec_prot_trickle_params); + sec_prot_timer_trickle_start(&data->common, &prot->sec_cfg->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->prot_cfg->sec_prot_trickle_params); + sec_prot_timer_trickle_start(&data->common, &prot->sec_cfg->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->prot_cfg->sec_prot_trickle_params); + sec_prot_timer_trickle_start(&data->common, &prot->sec_cfg->prot_cfg.sec_prot_trickle_params); } else { // TLS done, indicate success to peer if (data->tls_result == EAP_TLS_RESULT_HANDSHAKE_OVER) { @@ -557,7 +557,7 @@ static void auth_eap_tls_sec_prot_state_machine(sec_prot_t *prot) case EAP_TLS_STATE_FINISHED: { uint8_t *remote_eui_64 = sec_prot_remote_eui_64_addr_get(prot); - tr_info("EAP-TLS finished, eui-64: %s", remote_eui_64 ? trace_array(sec_prot_remote_eui_64_addr_get(prot), 8) : "not set"); + tr_info("EAP-TLS finished, eui-64: %s", remote_eui_64 ? trace_array(remote_eui_64, 8) : "not set"); auth_eap_tls_sec_prot_delete_tls(prot); prot->timer_stop(prot); prot->finished(prot); diff --git a/source/Security/protocols/eap_tls_sec_prot/radius_eap_tls_sec_prot.c b/source/Security/protocols/eap_tls_sec_prot/radius_eap_tls_sec_prot.c new file mode 100644 index 000000000000..2c85d85378dd --- /dev/null +++ b/source/Security/protocols/eap_tls_sec_prot/radius_eap_tls_sec_prot.c @@ -0,0 +1,526 @@ +/* + * 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 "common_functions.h" +#include "nsdynmemLIB.h" +#include "fhss_config.h" +#include "NWK_INTERFACE/Include/protocol.h" +#include "6LoWPAN/ws/ws_config.h" +#include "6LoWPAN/ws/ws_cfg_settings.h" +#include "Security/PANA/pana_eap_header.h" +#include "Security/protocols/sec_prot_cfg.h" +#include "Security/kmp/kmp_addr.h" +#include "Security/kmp/kmp_api.h" +#include "Security/PANA/pana_eap_header.h" +#include "Security/eapol/eapol_helper.h" +#include "Security/protocols/sec_prot_certs.h" +#include "Security/protocols/sec_prot_keys.h" +#include "Security/protocols/sec_prot.h" +#include "Security/protocols/sec_prot_lib.h" +#include "Security/protocols/eap_tls_sec_prot/eap_tls_sec_prot_lib.h" +#include "Security/protocols/eap_tls_sec_prot/radius_eap_tls_sec_prot.h" + +#ifdef HAVE_WS + +#define TRACE_GROUP "eapr" + +typedef enum { + EAP_TLS_STATE_INIT = SEC_STATE_INIT, + EAP_TLS_STATE_CREATE_REQ = SEC_STATE_CREATE_REQ, + EAP_TLS_STATE_CREATE_RESP = SEC_STATE_CREATE_RESP, + EAP_TLS_STATE_CREATE_IND = SEC_STATE_CREATE_IND, + + EAP_TLS_STATE_RESPONSE_ID = SEC_STATE_FIRST, + EAP_TLS_STATE_EAP_REQUEST, + EAP_TLS_STATE_EAP_RESPONSE, + EAP_TLS_STATE_RESPONSE_START, + EAP_TLS_STATE_RESPONSE, + + EAP_TLS_STATE_FINISH = SEC_STATE_FINISH, + EAP_TLS_STATE_FINISHED = SEC_STATE_FINISHED +} eap_tls_sec_prot_state_e; + +// Filters initial EAPOL-key re-transmission bursts +#define BURST_FILTER_TIMER_TIMEOUT 5 * 10 + +// How many times initial EAPOL-key is accepted on wait for identity response state +#define INITIAL_EAPOL_KEY_MAX_COUNT 2 + +typedef struct { + sec_prot_common_t common; /**< Common data */ + sec_prot_t *radius_client_prot; /**< RADIUS client security protocol */ + sec_prot_receive *radius_client_send; /**< RADIUS client security protocol send (receive from peer) */ + eapol_pdu_t recv_eapol_pdu; /**< Received EAPOL PDU */ + tls_data_t tls_send; /**< EAP-TLS send buffer */ + uint16_t recv_eap_msg_len; /**< Received EAP message length */ + uint8_t *recv_eap_msg; /**< Received EAP message */ + uint16_t burst_filt_timer; /**< Burst filter timer */ + uint8_t eap_id_seq; /**< EAP sequence */ + uint8_t recv_eap_id_seq; /**< Last received EAP sequence */ + uint8_t eap_code; /**< Received EAP code */ + uint8_t eap_type; /**< Received EAP type */ + uint8_t init_key_cnt; /**< How many time initial EAPOL-key has been received */ +} radius_eap_tls_sec_prot_int_t; + +static uint16_t radius_eap_tls_sec_prot_size(void); +static int8_t radius_eap_tls_sec_prot_init(sec_prot_t *prot); + +static void radius_eap_tls_sec_prot_create_request(sec_prot_t *prot, sec_prot_keys_t *sec_keys); +static void radius_eap_tls_sec_prot_delete(sec_prot_t *prot); +static int8_t radius_eap_tls_sec_prot_receive(sec_prot_t *prot, void *pdu, uint16_t size); +static int8_t radius_eap_tls_sec_prot_radius_client_receive(sec_prot_t *radius_client, void *pdu, uint16_t size); +static int8_t radius_eap_tls_sec_prot_radius_eap_message_forward(sec_prot_t *prot, uint8_t *eap_code); + +static void radius_eap_tls_sec_prot_state_machine(sec_prot_t *prot); + +static int8_t radius_eap_tls_sec_prot_message_handle(sec_prot_t *prot, uint8_t *data_ptr, uint16_t *length); +static int8_t radius_eap_tls_sec_prot_message_send(sec_prot_t *prot, uint8_t eap_code, uint8_t eap_type, uint8_t tls_state); + +static void radius_eap_tls_sec_prot_timer_timeout(sec_prot_t *prot, uint16_t ticks); +static int8_t radius_eap_tls_sec_prot_init_radius_client(sec_prot_t *prot); + +static void radius_eap_tls_sec_prot_seq_id_update(sec_prot_t *prot); + +#define eap_tls_sec_prot_get(prot) (radius_eap_tls_sec_prot_int_t *) &prot->data + +int8_t radius_eap_tls_sec_prot_register(kmp_service_t *service) +{ + if (!service) { + return -1; + } + + if (kmp_service_sec_protocol_register(service, RADIUS_IEEE_802_1X_MKA, radius_eap_tls_sec_prot_size, radius_eap_tls_sec_prot_init) < 0) { + return -1; + } + + return 0; +} + +static uint16_t radius_eap_tls_sec_prot_size(void) +{ + return sizeof(radius_eap_tls_sec_prot_int_t); +} + +static int8_t radius_eap_tls_sec_prot_init(sec_prot_t *prot) +{ + prot->create_req = radius_eap_tls_sec_prot_create_request; + prot->create_resp = 0; + prot->receive = radius_eap_tls_sec_prot_receive; + prot->receive_peer = radius_eap_tls_sec_prot_radius_client_receive; + prot->delete = radius_eap_tls_sec_prot_delete; + prot->state_machine = radius_eap_tls_sec_prot_state_machine; + prot->timer_timeout = radius_eap_tls_sec_prot_timer_timeout; + prot->receive_peer_hdr_size += EAPOL_BASE_LENGTH; // 4 bytes of EAPOL data + + radius_eap_tls_sec_prot_int_t *data = eap_tls_sec_prot_get(prot); + + sec_prot_init(&data->common); + sec_prot_state_set(prot, &data->common, EAP_TLS_STATE_INIT); + + data->radius_client_prot = NULL; + data->burst_filt_timer = BURST_FILTER_TIMER_TIMEOUT; + data->eap_id_seq = 0; + data->recv_eap_id_seq = 0; + data->eap_code = 0; + data->eap_type = 0; + eap_tls_sec_prot_lib_message_init(&data->tls_send); + data->init_key_cnt = 0; + return 0; +} + +static void radius_eap_tls_sec_prot_delete(sec_prot_t *prot) +{ + radius_eap_tls_sec_prot_int_t *data = eap_tls_sec_prot_get(prot); + eap_tls_sec_prot_lib_message_free(&data->tls_send); +} + +static void radius_eap_tls_sec_prot_create_request(sec_prot_t *prot, sec_prot_keys_t *sec_keys) +{ + prot->sec_keys = sec_keys; + + // Call state machine + prot->state_machine_call(prot); +} + +static int8_t radius_eap_tls_sec_prot_receive(sec_prot_t *prot, void *pdu, uint16_t size) +{ + radius_eap_tls_sec_prot_int_t *data = eap_tls_sec_prot_get(prot); + int8_t ret_val = -1; + + // Decoding is successful + if (eapol_parse_pdu_header(pdu, size, &data->recv_eapol_pdu)) { + // Handle EAP messages + if (data->recv_eapol_pdu.packet_type == EAPOL_EAP_TYPE) { + data->eap_code = data->recv_eapol_pdu.msg.eap.eap_code; + data->eap_type = data->recv_eapol_pdu.msg.eap.type; + + // Call state machine + prot->state_machine(prot); + } else if (data->recv_eapol_pdu.packet_type == EAPOL_KEY_TYPE && + sec_prot_state_get(&data->common) == EAP_TLS_STATE_RESPONSE_ID) { + /* If initial EAPOL-key transmission arrives to first EAP-TLS wait state i.e. + * when waiting for identity response, triggers re-transmission of identity + * request. This allows the supplicant to start EAP-TLS right away, if it has + * missed the original identity request. + */ + if (data->burst_filt_timer == 0 && data->init_key_cnt < INITIAL_EAPOL_KEY_MAX_COUNT) { + tr_info("EAP-TLS: initial EAPOL-key recv, eui-64: %s", trace_array(sec_prot_remote_eui_64_addr_get(prot), 8)); + sec_prot_result_set(&data->common, SEC_RESULT_TIMEOUT); + // Call state machine + prot->state_machine(prot); + // Resets trickle timer to give time for supplicant to answer + sec_prot_timer_trickle_start(&data->common, &prot->sec_cfg->prot_cfg.sec_prot_trickle_params); + data->init_key_cnt++; + } + // Filters repeated initial EAPOL-key messages + data->burst_filt_timer = BURST_FILTER_TIMER_TIMEOUT; + } + ret_val = 0; + } + + memset(&data->recv_eapol_pdu, 0, sizeof(eapol_pdu_t)); + data->eap_code = 0; + data->eap_type = 0; + + return ret_val; +} + +static int8_t radius_eap_tls_sec_prot_message_handle(sec_prot_t *prot, uint8_t *data_ptr, uint16_t *length) +{ + radius_eap_tls_sec_prot_int_t *data = eap_tls_sec_prot_get(prot); + + data_ptr = data->recv_eapol_pdu.msg.eap.data_ptr; + *length = data->recv_eapol_pdu.msg.eap.length; + + bool old_seq_id = false; + + // Already received sequence ID is received again, ignore + if (data->recv_eapol_pdu.msg.eap.id_seq < data->eap_id_seq) { + old_seq_id = true; + } else if (data->recv_eapol_pdu.msg.eap.id_seq == data->eap_id_seq) { + // Confirmation that supplicant has received the message, proceed with protocol + data->recv_eap_id_seq = data->recv_eapol_pdu.msg.eap.id_seq; + data->eap_id_seq++; + } + + tr_info("EAP-TLS: recv %s type %s id %i flags %x len %i, eui-64 %s", eap_msg_trace[data->eap_code - 1], + data->eap_type == EAP_IDENTITY ? "IDENTITY" : "TLS", data->recv_eapol_pdu.msg.eap.id_seq, + *length >= 6 ? data_ptr[0] : 0, *length, trace_array(sec_prot_remote_eui_64_addr_get(prot), 8)); + + if (old_seq_id) { + return EAP_TLS_MSG_DECODE_ERROR; + } + + if (data->eap_type == EAP_IDENTITY) { + return EAP_TLS_MSG_IDENTITY; + } + + if (!data_ptr || *length < 6) { + tr_error("EAP-TLS: decode error"); + return EAP_TLS_MSG_DECODE_ERROR; + } + + return EAP_TLS_MSG_CONTINUE; +} + +static int8_t radius_eap_tls_sec_prot_message_send(sec_prot_t *prot, uint8_t eap_code, uint8_t eap_type, uint8_t tls_state) +{ + radius_eap_tls_sec_prot_int_t *data = eap_tls_sec_prot_get(prot); + + uint8_t flags = 0xff; + // EAP-TLS flags field is always present during TLS exchange + if (tls_state == EAP_TLS_EXCHANGE_ONGOING) { + flags = 0x00; + } + + if (eap_code == EAP_REQ) { + if (eap_type == EAP_TLS && tls_state == EAP_TLS_EXCHANGE_START) { + eap_tls_sec_prot_lib_message_allocate(&data->tls_send, TLS_HEAD_LEN, 0); + flags = EAP_TLS_START; + } + } else if (eap_code == EAP_SUCCESS || eap_code == EAP_FAILURE) { + // Send Success and Failure with same identifier as received in EAP Response + data->eap_id_seq = data->recv_eap_id_seq; + } else { + return -1; + } + + uint16_t eapol_pdu_size; + uint8_t *eapol_decoded_data = eap_tls_sec_prot_lib_message_build(eap_code, eap_type, &flags, data->eap_id_seq, prot->header_size, &data->tls_send, &eapol_pdu_size); + if (!eapol_decoded_data) { + return -1; + } + + tr_info("EAP-TLS: send %s type %s id %i flags %x len %i, eui-64: %s", eap_msg_trace[eap_code - 1], + eap_type == EAP_IDENTITY ? "IDENTITY" : "TLS", data->eap_id_seq, flags, eapol_pdu_size, + trace_array(sec_prot_remote_eui_64_addr_get(prot), 8)); + + if (prot->send(prot, eapol_decoded_data, eapol_pdu_size + prot->header_size) < 0) { + return -1; + } + + return 0; +} + +static int8_t radius_eap_tls_sec_prot_radius_eap_message_forward(sec_prot_t *prot, uint8_t *eap_code) +{ + radius_eap_tls_sec_prot_int_t *data = eap_tls_sec_prot_get(prot); + + uint16_t eap_pdu_len = data->recv_eap_msg_len - prot->receive_peer_hdr_size; + uint8_t *eap_pdu = data->recv_eap_msg + prot->receive_peer_hdr_size; + + if (eap_pdu_len < 4) { + return -1; + } + + *eap_code = *eap_pdu++; + uint8_t eap_id_seq = *eap_pdu++; + uint16_t eap_len = common_read_16_bit(eap_pdu); + eap_pdu += 2; + + if (eap_pdu_len != eap_len) { + return -1; + } + + uint16_t eap_body_len = eap_len; + uint8_t eap_type = 0; + uint8_t flags = 0; + uint8_t *tls_ptr = NULL; + + if (*eap_code == EAP_REQ || *eap_code == EAP_RESPONSE) { + eap_type = *eap_pdu++; + eap_body_len--; + if (eap_type == EAP_TLS && eap_len >= 5) { + tls_ptr = eap_pdu; + flags = *tls_ptr; + } + } + + eapol_pdu_t eapol_pdu; + uint16_t eapol_pdu_size = eapol_pdu_eap_frame_init(&eapol_pdu, *eap_code, eap_id_seq, eap_type, eap_body_len, tls_ptr); + if (eapol_pdu_size - EAPOL_BASE_LENGTH != eap_len) { + return -1; + } + + eapol_write_pdu_frame(data->recv_eap_msg + prot->header_size, &eapol_pdu); + + tr_info("EAP-TLS: send %s type %s id %i flags %x len %i, eui-64: %s", eap_msg_trace[*eap_code - 1], + eap_type == EAP_IDENTITY ? "IDENTITY" : "TLS", data->eap_id_seq, flags, eapol_pdu_size, + trace_array(sec_prot_remote_eui_64_addr_get(prot), 8)); + + if (prot->send(prot, data->recv_eap_msg, eapol_pdu_size + prot->header_size) < 0) { + return -1; + } + + return 0; +} + +static void radius_eap_tls_sec_prot_timer_timeout(sec_prot_t *prot, uint16_t ticks) +{ + radius_eap_tls_sec_prot_int_t *data = eap_tls_sec_prot_get(prot); + + if (data->burst_filt_timer > ticks) { + data->burst_filt_timer -= ticks; + } else { + data->burst_filt_timer = 0; + } + + sec_prot_timer_timeout_handle(prot, &data->common, + &prot->sec_cfg->prot_cfg.sec_prot_trickle_params, ticks); +} + +static int8_t radius_eap_tls_sec_prot_radius_client_receive(sec_prot_t *radius_client, void *pdu, uint16_t size) +{ + sec_prot_t *prot = radius_client->type_get(radius_client, SEC_PROT_TYPE_RADIUS_EAP_TLS); + if (!prot) { + return -1; + } + + radius_eap_tls_sec_prot_int_t *data = eap_tls_sec_prot_get(prot); + + data->recv_eap_msg_len = size; + data->recv_eap_msg = pdu; + + prot->state_machine_call(prot); + + return 0; +} + +static int8_t radius_eap_tls_sec_prot_init_radius_client(sec_prot_t *prot) +{ + radius_eap_tls_sec_prot_int_t *data = eap_tls_sec_prot_get(prot); + if (data->radius_client_prot) { + return 0; + } + + data->radius_client_prot = prot->type_get(prot, SEC_PROT_TYPE_RADIUS_CLIENT); + if (!data->radius_client_prot) { + return -1; + } + data->radius_client_send = data->radius_client_prot->receive_peer; + + return 0; +} + +static void radius_eap_tls_sec_prot_state_machine(sec_prot_t *prot) +{ + radius_eap_tls_sec_prot_int_t *data = eap_tls_sec_prot_get(prot); + uint8_t *data_ptr = NULL; + uint16_t length = 0; + + // EAP-TLS authenticator state machine + switch (sec_prot_state_get(&data->common)) { + case EAP_TLS_STATE_INIT: + tr_info("EAP-TLS init"); + sec_prot_state_set(prot, &data->common, EAP_TLS_STATE_CREATE_REQ); + prot->timer_start(prot); + break; + + // Wait KMP-CREATE.request + case EAP_TLS_STATE_CREATE_REQ: + tr_info("EAP-TLS start, eui-64: %s", trace_array(sec_prot_remote_eui_64_addr_get(prot), 8)); + + // Set default timeout for the total maximum length of the negotiation + sec_prot_default_timeout_set(&data->common); + + // KMP-CREATE.confirm + prot->create_conf(prot, SEC_RESULT_OK); + + // Increment sequence ID + radius_eap_tls_sec_prot_seq_id_update(prot); + + // Sends EAP request, Identity + radius_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->sec_cfg->prot_cfg.sec_prot_trickle_params); + + sec_prot_state_set(prot, &data->common, EAP_TLS_STATE_RESPONSE_ID); + break; + + // Wait EAP response, Identity + case EAP_TLS_STATE_RESPONSE_ID: + + // On timeout + if (sec_prot_result_timeout_check(&data->common)) { + // Re-sends EAP request, Identity + radius_eap_tls_sec_prot_message_send(prot, EAP_REQ, EAP_IDENTITY, EAP_TLS_EXCHANGE_NONE); + return; + } + + // Handle EAP response (expected Identity) + if (radius_eap_tls_sec_prot_message_handle(prot, data_ptr, &length) != EAP_TLS_MSG_IDENTITY) { + return; + } + + tr_info("EAP-TLS EAP response id, eui-64: %s", trace_array(sec_prot_remote_eui_64_addr_get(prot), 8)); + + if (radius_eap_tls_sec_prot_init_radius_client(prot) < 0) { + tr_error("EAP-TLS: radius client init failed"); + return; + } + + // Send to radius client + data->radius_client_send(data->radius_client_prot, (void *) &data->recv_eapol_pdu, length); + + sec_prot_state_set(prot, &data->common, EAP_TLS_STATE_EAP_REQUEST); + break; + + // Wait EAP request + case EAP_TLS_STATE_EAP_REQUEST: + + // On timeout + if (sec_prot_result_timeout_check(&data->common)) { + // Do nothing for now + return; + } + + tr_info("EAP-TLS EAP request, eui-64: %s", trace_array(sec_prot_remote_eui_64_addr_get(prot), 8)); + + uint8_t eap_code; + if (radius_eap_tls_sec_prot_radius_eap_message_forward(prot, &eap_code) < 0) { + tr_error("EAP-TLS: EAP message forward failed"); + return; + } + + if (eap_code == EAP_SUCCESS) { + sec_prot_result_set(&data->common, SEC_RESULT_OK); + sec_prot_state_set(prot, &data->common, EAP_TLS_STATE_FINISH); + } else if (eap_code == EAP_FAILURE) { + sec_prot_result_set(&data->common, SEC_RESULT_ERROR); + sec_prot_state_set(prot, &data->common, EAP_TLS_STATE_FINISH); + } + + sec_prot_state_set(prot, &data->common, EAP_TLS_STATE_EAP_RESPONSE); + break; + + // Wait EAP response + case EAP_TLS_STATE_EAP_RESPONSE: + + // On timeout + if (sec_prot_result_timeout_check(&data->common)) { + // Do nothing for now + return; + } + + tr_info("EAP-TLS EAP response, eui-64: %s", trace_array(sec_prot_remote_eui_64_addr_get(prot), 8)); + + // Handle EAP response + if (radius_eap_tls_sec_prot_message_handle(prot, data_ptr, &length) != EAP_TLS_MSG_CONTINUE) { + return; + } + + // Send to radius client + data->radius_client_send(data->radius_client_prot, (void *) &data->recv_eapol_pdu, length); + + sec_prot_state_set(prot, &data->common, EAP_TLS_STATE_EAP_REQUEST); + break; + + case EAP_TLS_STATE_FINISH: + tr_info("EAP-TLS finish, eui-64: %s", trace_array(sec_prot_remote_eui_64_addr_get(prot), 8)); + + // KMP-FINISHED.indication, + prot->finished_ind(prot, sec_prot_result_get(&data->common), prot->sec_keys); + + sec_prot_state_set(prot, &data->common, EAP_TLS_STATE_FINISHED); + break; + + case EAP_TLS_STATE_FINISHED: { + uint8_t *remote_eui_64 = sec_prot_remote_eui_64_addr_get(prot); + tr_info("EAP-TLS finished, eui-64: %s", remote_eui_64 ? trace_array(sec_prot_remote_eui_64_addr_get(prot), 8) : "not set"); + prot->timer_stop(prot); + prot->finished(prot); + break; + } + default: + break; + } +} + +static void radius_eap_tls_sec_prot_seq_id_update(sec_prot_t *prot) +{ + radius_eap_tls_sec_prot_int_t *data = eap_tls_sec_prot_get(prot); + data->eap_id_seq++; +} + +#endif /* HAVE_WS */ + diff --git a/source/Security/protocols/eap_tls_sec_prot/radius_eap_tls_sec_prot.h b/source/Security/protocols/eap_tls_sec_prot/radius_eap_tls_sec_prot.h new file mode 100644 index 000000000000..03f510985fd5 --- /dev/null +++ b/source/Security/protocols/eap_tls_sec_prot/radius_eap_tls_sec_prot.h @@ -0,0 +1,36 @@ +/* + * 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 RADIUS_EAP_TLS_SEC_PROT_H_ +#define RADIUS_EAP_TLS_SEC_PROT_H_ + +/* + * Authenticator RADIUS EAP-TLS security protocol. Specified in RFC 5216. + * + */ + +/** + * radius_eap_tls_sec_prot_register register authenticator EAP-TLS protocol to KMP service + * + * \param service KMP service + * + * \return < 0 failure + * \return >= 0 success + */ +int8_t radius_eap_tls_sec_prot_register(kmp_service_t *service); + +#endif /* RADIUS_EAP_TLS_SEC_PROT_H_ */ 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 b7df2d6eb6fc..8e0952c1621e 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->prot_cfg->sec_prot_retry_timeout; + data->common.ticks = prot->sec_cfg->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->prot_cfg->sec_prot_retry_timeout; + data->common.ticks = prot->sec_cfg->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->prot_cfg->sec_prot_retry_timeout; + data->common.ticks = prot->sec_cfg->prot_cfg.sec_prot_retry_timeout; } // All fragments received for a message diff --git a/source/Security/protocols/fwh_sec_prot/auth_fwh_sec_prot.c b/source/Security/protocols/fwh_sec_prot/auth_fwh_sec_prot.c index 073cd9ef5388..1162eb9c356c 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 @@ -36,7 +36,7 @@ #include "Security/protocols/sec_prot.h" #include "Security/protocols/sec_prot_lib.h" #include "Security/protocols/fwh_sec_prot/auth_fwh_sec_prot.h" -#include "Service_Libs/hmac/hmac_sha1.h" +#include "Service_Libs/hmac/hmac_md.h" #include "Service_Libs/nist_aes_kw/nist_aes_kw.h" #ifdef HAVE_WS @@ -313,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->prot_cfg->sec_prot_trickle_params, ticks); + sec_prot_timer_timeout_handle(prot, &data->common, &prot->sec_cfg->prot_cfg.sec_prot_trickle_params, ticks); } static void auth_fwh_sec_prot_state_machine(sec_prot_t *prot) @@ -350,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->prot_cfg->sec_prot_trickle_params); + sec_prot_timer_trickle_start(&data->common, &prot->sec_cfg->prot_cfg.sec_prot_trickle_params); sec_prot_state_set(prot, &data->common, FWH_STATE_MESSAGE_2); break; @@ -378,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->prot_cfg->sec_prot_trickle_params); + sec_prot_timer_trickle_start(&data->common, &prot->sec_cfg->prot_cfg.sec_prot_trickle_params); sec_prot_state_set(prot, &data->common, FWH_STATE_MESSAGE_4); } @@ -406,7 +406,7 @@ static void auth_fwh_sec_prot_state_machine(sec_prot_t *prot) // 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, prot->timer_cfg->ptk_lifetime); + sec_prot_keys_ptk_write(prot->sec_keys, data->new_ptk, prot->sec_cfg->timer_cfg.ptk_lifetime); sec_prot_keys_ptk_eui_64_write(prot->sec_keys, data->remote_eui64); sec_prot_state_set(prot, &data->common, FWH_STATE_FINISH); } 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 41b6227fe862..a1074f7ec20e 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 @@ -35,7 +35,7 @@ #include "Security/protocols/sec_prot.h" #include "Security/protocols/sec_prot_lib.h" #include "Security/protocols/fwh_sec_prot/supp_fwh_sec_prot.h" -#include "Service_Libs/hmac/hmac_sha1.h" +#include "Service_Libs/hmac/hmac_md.h" #include "Service_Libs/nist_aes_kw/nist_aes_kw.h" #ifdef HAVE_WS @@ -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->prot_cfg->sec_prot_retry_timeout; + data->common.ticks = prot->sec_cfg->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->prot_cfg->sec_prot_retry_timeout; + data->common.ticks = prot->sec_cfg->prot_cfg.sec_prot_retry_timeout; sec_prot_state_set(prot, &data->common, FWH_STATE_MESSAGE_3); } else { // Ready to be deleted @@ -365,7 +365,7 @@ static void supp_fwh_sec_prot_state_machine(sec_prot_t *prot) // Send 4WH message 2 supp_fwh_sec_prot_message_send(prot, FWH_MESSAGE_2); - data->common.ticks = prot->prot_cfg->sec_prot_retry_timeout; + data->common.ticks = prot->sec_cfg->prot_cfg.sec_prot_retry_timeout; return; } else if (data->recv_msg != FWH_MESSAGE_3) { return; @@ -392,7 +392,7 @@ static void supp_fwh_sec_prot_state_machine(sec_prot_t *prot) // Sends 4WH Message 4 supp_fwh_sec_prot_message_send(prot, FWH_MESSAGE_4); - data->common.ticks = prot->prot_cfg->sec_prot_retry_timeout; + data->common.ticks = prot->sec_cfg->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, prot->timer_cfg->ptk_lifetime); + sec_prot_keys_ptk_write(prot->sec_keys, data->new_ptk, prot->sec_cfg->timer_cfg.ptk_lifetime); sec_prot_keys_ptk_eui_64_write(prot->sec_keys, data->remote_eui64); data->common.ticks = 60 * 10; // 60 seconds 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 7d736ae95b7d..d1101d2292e9 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 @@ -261,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->prot_cfg->sec_prot_trickle_params, ticks); + sec_prot_timer_timeout_handle(prot, &data->common, &prot->sec_cfg->prot_cfg.sec_prot_trickle_params, ticks); } static void auth_gkh_sec_prot_state_machine(sec_prot_t *prot) @@ -290,7 +290,7 @@ static void auth_gkh_sec_prot_state_machine(sec_prot_t *prot) 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->prot_cfg->sec_prot_trickle_params); + sec_prot_timer_trickle_start(&data->common, &prot->sec_cfg->prot_cfg.sec_prot_trickle_params); sec_prot_state_set(prot, &data->common, GKH_STATE_MESSAGE_2); diff --git a/source/Security/protocols/radius_sec_prot/avp_helper.c b/source/Security/protocols/radius_sec_prot/avp_helper.c new file mode 100644 index 000000000000..73cc2d98e5e1 --- /dev/null +++ b/source/Security/protocols/radius_sec_prot/avp_helper.c @@ -0,0 +1,259 @@ +/* + * Copyright (c) 2020, Arm Limited and affiliates. + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "nsconfig.h" +#include "ns_types.h" +#include "eventOS_event.h" +#include "ns_trace.h" +#include "string.h" +#include "common_functions.h" +#include "Security/protocols/radius_sec_prot/avp_helper.h" + +#ifdef HAVE_WS + +#define TRACE_GROUP "avp" + +// RFC 2865 + +// 1 User-Name +#define AVP_TYPE_USER_NAME 1 +// 4 for NAS-IP-Address +#define AVP_TYPE_NAS_IP_ADDRESS 4 +// 5 NAS-Port +#define AVP_TYPE_NAS_PORT 5 +// 12 Framed-MTU +#define AVP_TYPE_FRAMED_MTU 12 +// 24 State +#define AVP_TYPE_STATE 24 +// 26 Vendor-Specific +#define AVP_TYPE_VENDOR_SPECIFIC 26 +// 30 Called-Station-Id +#define AVP_TYPE_CALLED_STATION_ID 30 +// 31 Calling-Station-Id +#define AVP_TYPE_CALLING_STATION_ID 31 +// 32 NAS-Identifier +#define AVP_TYPE_NAS_IDENTIFIER 32 +// 61 NAS-Port-Type +#define AVP_TYPE_NAS_PORT_TYPE 61 + +// RFC 3579 + +// 79 EAP-Message +#define AVP_TYPE_EAP_MESSAGE 79 +// 80 Message-Authenticator +#define AVP_TYPE_MESSAGE_AUTHENTICATOR 80 + +// RFC 3162 + +// 95 NAS-IPv6-Address +#define AVP_TYPE_NAS_IPV6_ADDRESS 95 + + +static uint8_t *avp_header_write(uint8_t *ptr, const uint8_t type, const uint8_t data_length) +{ + *ptr++ = type; + *ptr++ = data_length + AVP_FIXED_LEN; + + return ptr; +} + +static uint8_t *avp_search(uint8_t *ptr, uint16_t len, const uint8_t type, uint8_t *avp_len) +{ + while (len >= AVP_FIXED_LEN) { + *avp_len = ptr[1]; + + // Validates length field + if (*avp_len > len) { + return NULL; + } + + if (ptr[0] == type) { + return ptr + AVP_FIXED_LEN; + } + + if (len > *avp_len) { + len -= *avp_len; + ptr += *avp_len; + } else { + return NULL; + } + } + + return NULL; +} + +static uint8_t *avp_vpa_search(uint8_t *ptr, uint16_t len, const uint32_t vendor_id, const uint8_t vendor_type, uint8_t *vendor_len) +{ + uint8_t avp_len = 0; + + while (len >= AVP_FIXED_LEN) { + avp_len = ptr[1]; + + // Validates length field + if (avp_len > len) { + return NULL; + } + + if (ptr[0] == AVP_TYPE_VENDOR_SPECIFIC && avp_len >= 9) { + ptr[2] = 0; + uint32_t avp_vendor_id = common_read_32_bit(&ptr[2]); + *vendor_len = ptr[7]; + if (avp_vendor_id == vendor_id && ptr[6] == vendor_type) { + return &ptr[8]; + } + } + + if (len > avp_len) { + len -= avp_len; + ptr += avp_len; + } else { + return NULL; + } + } + + return NULL; +} + +uint8_t *avp_user_name_write(uint8_t *ptr, const uint8_t name_len, const uint8_t *name) +{ + ptr = avp_header_write(ptr, AVP_TYPE_USER_NAME, name_len); + memcpy(ptr, name, name_len); + return ptr + name_len; +} + +uint8_t *avp_nas_ip_address_write(uint8_t *ptr, uint32_t addr) +{ + ptr = avp_header_write(ptr, AVP_TYPE_NAS_IP_ADDRESS, 4); + memcpy(ptr, &addr, 4); + return ptr + 4; +} + +uint8_t *avp_nas_port_write(uint8_t *ptr, const uint32_t port) +{ + ptr = avp_header_write(ptr, AVP_TYPE_NAS_PORT, 4); + ptr = common_write_32_bit(port, ptr); + return ptr; +} + +uint8_t *avp_framed_mtu_write(uint8_t *ptr, const uint32_t mtu) +{ + ptr = avp_header_write(ptr, AVP_TYPE_FRAMED_MTU, 4); + ptr = common_write_32_bit(mtu, ptr); + return ptr; +} + +uint8_t *avp_state_write(uint8_t *ptr, const uint8_t state_len, const uint8_t *state) +{ + ptr = avp_header_write(ptr, AVP_TYPE_STATE, state_len); + memcpy(ptr, state, state_len); + return ptr + state_len; +} + +uint8_t *avp_called_station_id_write(uint8_t *ptr, const uint8_t id_len, const uint8_t *id) +{ + ptr = avp_header_write(ptr, AVP_TYPE_CALLED_STATION_ID, id_len); + memcpy(ptr, id, id_len); + return ptr + id_len; +} + +uint8_t *avp_calling_station_id_write(uint8_t *ptr, const uint8_t id_len, const uint8_t *id) +{ + ptr = avp_header_write(ptr, AVP_TYPE_CALLING_STATION_ID, id_len); + memcpy(ptr, id, id_len); + return ptr + id_len; +} + +uint8_t *avp_nas_identifier_write(uint8_t *ptr, const uint8_t id_len, const uint8_t *id) +{ + ptr = avp_header_write(ptr, AVP_TYPE_NAS_IDENTIFIER, id_len); + memcpy(ptr, id, id_len); + return ptr + id_len; +} + +uint8_t *avp_nas_port_type_write(uint8_t *ptr, const uint32_t port_type) +{ + ptr = avp_header_write(ptr, AVP_TYPE_NAS_PORT_TYPE, 4); + ptr = common_write_32_bit(port_type, ptr); + return ptr; +} + +uint8_t *avp_eap_message_write(uint8_t *ptr, const uint8_t eap_len, const uint8_t *eap) +{ + ptr = avp_header_write(ptr, AVP_TYPE_EAP_MESSAGE, eap_len); + memcpy(ptr, eap, eap_len); + return ptr + eap_len; +} + +uint8_t *avp_message_authenticator_write(uint8_t *ptr, const uint8_t *auth) +{ + ptr = avp_header_write(ptr, AVP_TYPE_MESSAGE_AUTHENTICATOR, 16); + memcpy(ptr, auth, 16); + return ptr + 16; +} + +uint8_t *avp_nas_ipv6_address_write(uint8_t *ptr, const uint8_t *address) +{ + ptr = avp_header_write(ptr, AVP_TYPE_NAS_IPV6_ADDRESS, 16); + memcpy(ptr, address, 16); + return ptr + 16; +} + +uint8_t *avp_eap_message_read(uint8_t *ptr, uint16_t len, uint8_t *eap_len) +{ + ptr = avp_search(ptr, len, AVP_TYPE_EAP_MESSAGE, eap_len); + if (ptr == NULL) { + return NULL; + } + return ptr; +} + +uint8_t *avp_message_authenticator_read(uint8_t *ptr, uint16_t len) +{ + uint8_t auth_len = 0; + ptr = avp_search(ptr, len, AVP_TYPE_MESSAGE_AUTHENTICATOR, &auth_len); + if (ptr == NULL) { + return NULL; + } + if (auth_len < 18) { + return NULL; + } + return ptr; +} + +uint8_t *avp_state_read(uint8_t *ptr, uint16_t len, uint8_t *state_len) +{ + ptr = avp_search(ptr, len, AVP_TYPE_STATE, state_len); + if (ptr == NULL) { + return NULL; + } + return ptr; +} + +uint8_t *avp_vsa_ms_mppe_recv_key_read(uint8_t *ptr, uint16_t len, uint8_t *recv_key_len) +{ + const uint32_t vendor_id = 311; + const uint8_t vendor_type = 17; + + ptr = avp_vpa_search(ptr, len, vendor_id, vendor_type, recv_key_len); + if (ptr == NULL) { + return NULL; + } + return ptr; +} + +#endif + diff --git a/source/Security/protocols/radius_sec_prot/avp_helper.h b/source/Security/protocols/radius_sec_prot/avp_helper.h new file mode 100644 index 000000000000..1fdd5bb54e39 --- /dev/null +++ b/source/Security/protocols/radius_sec_prot/avp_helper.h @@ -0,0 +1,239 @@ +/* + * 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 AVP_HELPER_H_ +#define AVP_HELPER_H_ + +/* + * RADIUS AVP helper functions + * + */ + +#define AVP_FIXED_LEN 2 // type, length +#define AVP_VALUE_MAX_LEN 253 // 255 - type field - length field + +#define AVP_TYPE_USER_NAME_LEN(len) (AVP_FIXED_LEN + len) +#define AVP_TYPE_NAS_IP_ADDRESS_LEN (AVP_FIXED_LEN + 4) +#define AVP_TYPE_NAS_PORT_LEN (AVP_FIXED_LEN + 4) +#define AVP_TYPE_FRAMED_MTU_LEN (AVP_FIXED_LEN + 4) +#define AVP_TYPE_STATE_LEN (AVP_FIXED_LEN + 8) +//#define AVP_TYPE_VENDOR_SPECIFIC 26 +#define AVP_TYPE_CALLED_STATION_ID_LEN(len) (AVP_FIXED_LEN + len) +#define AVP_TYPE_CALLING_STATION_ID_LEN(len) (AVP_FIXED_LEN + len) +#define AVP_TYPE_NAS_IDENTIFIER_LEN(len) (AVP_FIXED_LEN + len) +#define AVP_TYPE_NAS_PORT_TYPE_LEN (AVP_FIXED_LEN + 4) +#define AVP_TYPE_EAP_MESSAGE_LEN(len) (AVP_FIXED_LEN + len) +#define AVP_TYPE_MESSAGE_AUTHENTICATOR_LEN (AVP_FIXED_LEN + 16) +#define AVP_TYPE_NAS_IPV6_ADDRESS_LEN (AVP_FIXED_LEN + 16) + +// Wireless - IEEE 802.11 +#define NAS_PORT_TYPE_WIRELESS_IEEE802_11 19 + +// EUI-64 in ascii string: 00-11-..-77 +#define STATION_ID_LEN 16 + 7 + +// MTU value TBD +#define FRAMED_MTU 1400 + +#define NAS_PORT 1 + +/** + * avp_user_name_write write use name + * + * \param ptr pointer where to write + * \param name_len name length + * \param name name + * + * return incremented write pointer + * + */ +uint8_t *avp_user_name_write(uint8_t *ptr, const uint8_t name_len, const uint8_t *name); + +/** + * avp_nas_ip_address_write nas ip address + * + * \param ptr pointer where to write + * \param addr address + * + * return incremented write pointer + * + */ +uint8_t *avp_nas_ip_address_write(uint8_t *ptr, uint32_t addr); + +/** + * avp_nas_port_write write nas port + * + * \param ptr pointer where to write + * \param port nas port + * + * return incremented write pointer + * + */ +uint8_t *avp_nas_port_write(uint8_t *ptr, const uint32_t port); + +/** + * avp_framed_mtu_write write frame mtu + * + * \param ptr pointer where to write + * \param mtu frame mtu + * + * return incremented write pointer + * + */ +uint8_t *avp_framed_mtu_write(uint8_t *ptr, const uint32_t mtu); + +/** + * avp_state_write write write state + * + * \param ptr pointer where to write + * \param state_len state length + * \param state state + * + * return incremented write pointer + * + */ +uint8_t *avp_state_write(uint8_t *ptr, const uint8_t state_len, const uint8_t *state); + +/** + * avp_called_station_id_write write called station id + * + * \param ptr pointer where to write + * \param id_len identifier length + * \param id identifier + * + * return incremented write pointer + * + */ +uint8_t *avp_called_station_id_write(uint8_t *ptr, const uint8_t id_len, const uint8_t *id); + +/** + * avp_calling_station_id_write write calling station id + * + * \param ptr pointer where to write + * \param id_len identifier length + * \param id identifier + * + * return incremented write pointer + * + */ +uint8_t *avp_calling_station_id_write(uint8_t *ptr, const uint8_t id_len, const uint8_t *id); + +/** + * avp_nas_identifier_write write nas identifier + * + * \param ptr pointer where to write + * \param id_len nas identifier length + * \param id nas identifier + * + * return incremented write pointer + * + */ +uint8_t *avp_nas_identifier_write(uint8_t *ptr, const uint8_t id_len, const uint8_t *id); + +/** + * avp_nas_port_type_write write nas port type + * + * \param ptr pointer where to write + * \param port_type port type + * + * return incremented write pointer + * + */ +uint8_t *avp_nas_port_type_write(uint8_t *ptr, const uint32_t port_type); + +/** + * avp_nas_message_write write eap message + * + * \param ptr pointer where to write + * \param eap_len eap length + * \param eap eap frame + * + * return incremented write pointer + * + */ +uint8_t *avp_eap_message_write(uint8_t *ptr, const uint8_t eap_len, const uint8_t *eap); + +/** + * avp_message_authenticator_write write message authenticator + * + * \param ptr pointer where to write + * \param auth authenticator + * + * return incremented write pointer + * + */ +uint8_t *avp_message_authenticator_write(uint8_t *ptr, const uint8_t *auth); + +/** + * avp_nas_ipv6_address_write write ipv6 address + * + * \param ptr pointer where to write + * \param address ipv6 address + * + * return incremented write pointer + * + */ +uint8_t *avp_nas_ipv6_address_write(uint8_t *ptr, const uint8_t *address); + +/** + * avp_eap_message_read read eap message + * + * \param ptr pointer to received message + * \param len received message length + * \param eap_len length of the eap frame + * + * return pointer to eap message or null + * + */ +uint8_t *avp_eap_message_read(uint8_t *ptr, uint16_t len, uint8_t *eap_len); + +/** + * avp_message_authenticator_read read message authenticator + * + * \param ptr pointer to received message + * \param len received message length + * + * return pointer to message authenticator or null + * + */ +uint8_t *avp_message_authenticator_read(uint8_t *ptr, uint16_t len); + +/** + * avp_state_read read state + * + * \param ptr pointer to received message + * \param len received message length + * \param state_len length of the state + * + * return pointer to state or null + * + */ +uint8_t *avp_state_read(uint8_t *ptr, uint16_t len, uint8_t *state_len); + +/** + * avp_vsa_ms_mppe_recv_key_read read vendor specific MS-MPPE-Recv-Key + * + * \param ptr pointer to received message + * \param len received message length + * \param recv_key_len length of the state + * + * return pointer to MS-MPPE-Recv-Key or null + * + */ +uint8_t *avp_vsa_ms_mppe_recv_key_read(uint8_t *ptr, uint16_t len, uint8_t *recv_key_len); + +#endif /* AVP_HELPER_H_ */ diff --git a/source/Security/protocols/radius_sec_prot/radius_client_sec_prot.c b/source/Security/protocols/radius_sec_prot/radius_client_sec_prot.c new file mode 100644 index 000000000000..a181cf0dd3cc --- /dev/null +++ b/source/Security/protocols/radius_sec_prot/radius_client_sec_prot.c @@ -0,0 +1,995 @@ +/* + * 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 "common_functions.h" +#include "nsdynmemLIB.h" +#include "randLIB.h" +#include "mbedtls/sha256.h" +#include "mbedtls/md5.h" +#include "fhss_config.h" +#include "Service_Libs/Trickle/trickle.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/PANA/pana_eap_header.h" +#include "Security/eapol/eapol_helper.h" +#include "Security/protocols/sec_prot_certs.h" +#include "Security/protocols/sec_prot_keys.h" +#include "Security/protocols/sec_prot.h" +#include "Security/protocols/sec_prot_lib.h" +#include "Security/protocols/eap_tls_sec_prot/eap_tls_sec_prot_lib.h" +#include "Security/protocols/radius_sec_prot/radius_client_sec_prot.h" +#include "Security/protocols/radius_sec_prot/avp_helper.h" +#include "Security/protocols/tls_sec_prot/tls_sec_prot_lib.h" +#include "Service_Libs/hmac/hmac_md.h" + +#ifdef HAVE_WS + +#define TRACE_GROUP "radp" + +typedef enum { + RADIUS_STATE_INIT = SEC_STATE_INIT, + RADIUS_STATE_CREATE_REQ = SEC_STATE_CREATE_REQ, + RADIUS_STATE_CREATE_RESP = SEC_STATE_CREATE_RESP, + RADIUS_STATE_CREATE_IND = SEC_STATE_CREATE_IND, + + RADIUS_STATE_STATE_RESPONSE_ID = SEC_STATE_FIRST, + RADIUS_STATE_SEND_INITIAL_ACCESS_REQUEST, + RADIUS_STATE_SEND_ACCESS_REQUEST, + RADIUS_STATE_ACCESS_ACCEPT_REJECT_CHALLENGE, + RADIUS_STATE_ACCESS_REQUEST, + RADIUS_STATE_CONFIGURE, + RADIUS_STATE_PROCESS, + + RADIUS_STATE_FINISH = SEC_STATE_FINISH, + RADIUS_STATE_FINISHED = SEC_STATE_FINISHED +} radius_client_sec_prot_state_e; + +#define RADIUS_MSG_FIXED_LENGTH 20 +#define RADIUS_ACCESS_REQUEST 1 +#define RADIUS_ACCESS_ACCEPT 2 +#define RADIUS_ACCESS_REJECT 3 +#define RADIUS_ACCESS_CHALLENGE 11 + +#define MS_MPPE_RECV_KEY_SALT_LEN 2 +#define MS_MPPE_RECV_KEY_BLOCK_LEN 16 + +typedef struct radius_client_sec_prot_lib_int_s radius_client_sec_prot_lib_int_t; + +typedef struct { + sec_prot_common_t common; /**< Common data */ + sec_prot_t *radius_eap_tls_prot; /**< Radius EAP-TLS security protocol */ + sec_prot_receive *radius_eap_tls_send; /**< Radius EAP-TLS security protocol send (receive from peer) */ + uint8_t radius_eap_tls_header_size; /**< Radius EAP-TLS header size */ + uint8_t new_pmk[PMK_LEN]; /**< New Pair Wise Master Key */ + uint16_t recv_eap_msg_len; /**< Received EAP message length */ + uint8_t *recv_eap_msg; /**< Received EAP message */ + uint16_t send_radius_msg_len; /**< Send radius message length */ + uint8_t *send_radius_msg; /**< Send radius message */ + uint8_t identity_len; /**< Supplicant EAP identity length */ + uint8_t *identity; /**< Supplicant EAP identity */ + uint8_t radius_code; /**< Radius code that was received */ + uint8_t radius_identifier; /**< Radius identifier that was last sent */ + uint8_t request_authenticator[16]; /**< Radius request authenticator that was last sent */ + uint8_t state_len; /**< Radius state length that was last received */ + uint8_t *state; /**< Radius state that was last received */ + uint8_t remote_eui_64_hash[8]; /**< Remote EUI-64 hash used for calling station id */ + bool remote_eui_64_hash_set : 1; /**< Remote EUI-64 hash used for calling station id set */ + bool new_pmk_set : 1; /**< New Pair Wise Master Key set */ +} radius_client_sec_prot_int_t; + +typedef struct { + uint8_t radius_client_identifier; /**< Radius client identifier */ + uint8_t local_eui64_hash[8]; /**< Local EUI-64 hash used for called stations id */ + uint8_t hash_random[16]; /**< Random used to generate local and remote EUI-64 hashes */ + bool local_eui64_hash_set : 1; /**< Local EUI-64 hash used for called stations id set */ + bool hash_random_set : 1; /**< Random used to generate local and remote EUI-64 hashes set */ +} radius_client_sec_prot_shared_t; + +static uint16_t radius_client_sec_prot_size(void); +static int8_t radius_client_sec_prot_init(sec_prot_t *prot); +static void radius_client_sec_prot_create_response(sec_prot_t *prot, sec_prot_result_e result); +static void radius_client_sec_prot_delete(sec_prot_t *prot); +static int8_t radius_client_sec_prot_receive_check(sec_prot_t *prot, const void *pdu, uint16_t size); +static int8_t radius_client_sec_prot_init_radius_eap_tls(sec_prot_t *prot); +static uint16_t radius_client_sec_prot_eap_avps_handle(uint16_t avp_length, uint8_t *avp_ptr, uint8_t *copy_to_ptr); +static int8_t radius_client_sec_prot_receive(sec_prot_t *prot, void *pdu, uint16_t size); +static int8_t radius_client_sec_prot_radius_eap_receive(sec_prot_t *prot, void *pdu, uint16_t size); +static void radius_client_sec_prot_allocate_and_create_radius_message(sec_prot_t *prot); +static int8_t radius_client_sec_prot_radius_msg_send(sec_prot_t *prot); +static uint8_t radius_client_sec_prot_identifier_allocate(void); +static uint8_t radius_client_sec_prot_hex_to_ascii(uint8_t value); +static int8_t radius_client_sec_prot_eui_64_hash_generate(uint8_t *eui_64, uint8_t *hashed_eui_64); +static void radius_client_sec_prot_station_id_generate(uint8_t *eui_64, uint8_t *station_id_ptr); +static int8_t radius_client_sec_prot_message_authenticator_calc(sec_prot_t *prot, uint16_t msg_len, uint8_t *msg_ptr, uint8_t *auth_ptr); +static int8_t radius_client_sec_prot_response_authenticator_calc(sec_prot_t *prot, uint16_t msg_len, uint8_t *msg_ptr, uint8_t *auth_ptr); +static int8_t radius_client_sec_prot_ms_mppe_recv_key_pmk_decrypt(sec_prot_t *prot, uint8_t *recv_key, uint8_t recv_key_len, uint8_t *request_authenticator, uint8_t *pmk_ptr); +static void radius_client_sec_prot_finished_send(sec_prot_t *prot); +static void radius_client_sec_prot_state_machine(sec_prot_t *prot); +static void radius_client_sec_prot_timer_timeout(sec_prot_t *prot, uint16_t ticks); + +#define radius_client_sec_prot_get(prot) (radius_client_sec_prot_int_t *) &prot->data + +// Data shared between radius client instances +static radius_client_sec_prot_shared_t *shared_data = NULL; + +int8_t radius_client_sec_prot_register(kmp_service_t *service) +{ + if (!service) { + return -1; + } + + if (kmp_service_sec_protocol_register(service, RADIUS_CLIENT_PROT, radius_client_sec_prot_size, radius_client_sec_prot_init) < 0) { + return -1; + } + + return 0; +} + +static uint16_t radius_client_sec_prot_size(void) +{ + return sizeof(radius_client_sec_prot_int_t); +} + +static int8_t radius_client_sec_prot_init(sec_prot_t *prot) +{ + prot->create_req = NULL; + prot->create_resp = radius_client_sec_prot_create_response; + prot->receive = radius_client_sec_prot_receive; + prot->receive_peer = radius_client_sec_prot_radius_eap_receive; + prot->delete = radius_client_sec_prot_delete; + prot->state_machine = radius_client_sec_prot_state_machine; + prot->timer_timeout = radius_client_sec_prot_timer_timeout; + prot->finished_send = radius_client_sec_prot_finished_send; + prot->receive_check = radius_client_sec_prot_receive_check; + + radius_client_sec_prot_int_t *data = radius_client_sec_prot_get(prot); + + sec_prot_init(&data->common); + sec_prot_state_set(prot, &data->common, RADIUS_STATE_INIT); + data->radius_eap_tls_prot = NULL; + data->radius_eap_tls_send = NULL; + data->radius_eap_tls_header_size = 0; + memset(data->new_pmk, 0, PMK_LEN); + data->recv_eap_msg_len = 0; + data->recv_eap_msg = NULL; + data->send_radius_msg_len = 0; + data->send_radius_msg = NULL; + data->identity_len = 0; + data->identity = NULL; + data->radius_code = 0; + data->radius_identifier = 0; + memset(data->request_authenticator, 0, 16); + data->state_len = 0; + data->state = NULL; + memset(data->remote_eui_64_hash, 0, 8); + data->remote_eui_64_hash_set = false; + data->new_pmk_set = false; + + if (!shared_data) { + shared_data = ns_dyn_mem_alloc(sizeof(radius_client_sec_prot_shared_t)); + if (!shared_data) { + return -1; + } + shared_data->radius_client_identifier = 0; + memset(shared_data->local_eui64_hash, 0, 8); + memset(shared_data->hash_random, 0, 16); + shared_data->local_eui64_hash_set = false; + shared_data->hash_random_set = false; + } + + return 0; +} + +static void radius_client_sec_prot_delete(sec_prot_t *prot) +{ + radius_client_sec_prot_int_t *data = radius_client_sec_prot_get(prot); + + if (data->recv_eap_msg != NULL) { + ns_dyn_mem_free(data->recv_eap_msg); + } + if (data->send_radius_msg != NULL) { + ns_dyn_mem_free(data->send_radius_msg); + } + if (data->identity != NULL) { + ns_dyn_mem_free(data->identity); + } + if (data->state != NULL) { + ns_dyn_mem_free(data->state); + } +} + +static void radius_client_sec_prot_create_response(sec_prot_t *prot, sec_prot_result_e result) +{ + radius_client_sec_prot_int_t *data = radius_client_sec_prot_get(prot); + + // Call state machine + sec_prot_result_set(&data->common, result); + prot->state_machine_call(prot); +} + +static int8_t radius_client_sec_prot_receive_check(sec_prot_t *prot, const void *pdu, uint16_t size) +{ + radius_client_sec_prot_int_t *data = radius_client_sec_prot_get(prot); + + if (size >= 2) { + const uint8_t *radius_msg = pdu; + if (radius_msg[1] == data->radius_identifier) { + return 0; + } + } + + return -1; +} + +static int8_t radius_client_sec_prot_init_radius_eap_tls(sec_prot_t *prot) +{ + radius_client_sec_prot_int_t *data = radius_client_sec_prot_get(prot); + if (data->radius_eap_tls_prot) { + return 0; + } + + data->radius_eap_tls_prot = prot->type_get(prot, SEC_PROT_TYPE_RADIUS_EAP_TLS); + if (!data->radius_eap_tls_prot) { + return -1; + } + data->radius_eap_tls_header_size = data->radius_eap_tls_prot->receive_peer_hdr_size; + data->radius_eap_tls_send = data->radius_eap_tls_prot->receive_peer; + + return 0; +} + +static uint16_t radius_client_sec_prot_eap_avps_handle(uint16_t avp_length, uint8_t *avp_ptr, uint8_t *copy_to_ptr) +{ + // Calculate EAP AVPs length and copy EAP AVPs to continuous buffer if buffer is give + uint16_t eap_len = 0; + while (true) { + uint8_t avp_eap_len; + uint8_t *eap_message = avp_eap_message_read(avp_ptr, avp_length, &avp_eap_len); + if (eap_message) { + avp_eap_len -= AVP_FIXED_LEN; + + // Calculate EAP AVPs length + eap_len += avp_eap_len; + + // Copy EAP AVPs to continuous buffer + if (copy_to_ptr) { + memcpy(copy_to_ptr, eap_message, avp_eap_len); + copy_to_ptr += avp_eap_len; + } + + uint16_t offset = eap_message - avp_ptr; + avp_length = avp_length - (offset + avp_eap_len); + avp_ptr = eap_message + avp_eap_len; + } else { + break; + } + } + + return eap_len; +} + +static int8_t radius_client_sec_prot_receive(sec_prot_t *prot, void *pdu, uint16_t size) +{ + radius_client_sec_prot_int_t *data = radius_client_sec_prot_get(prot); + + if (size < RADIUS_MSG_FIXED_LENGTH) { + return -1; + } + + uint8_t *radius_msg_ptr = pdu; + + uint8_t code = *radius_msg_ptr++; + uint8_t identifier = *radius_msg_ptr++; + /* If identifier does not match to sent identifier, silently ignore message, + already checked on socket if before routing the request to receive, so + this is double check to ensure correct routing */ + if (identifier != data->radius_identifier) { + return -1; + } + + uint16_t length = common_read_16_bit(radius_msg_ptr); + radius_msg_ptr += 2; + + // Store response authenticator + uint8_t recv_response_authenticator[16]; + memcpy(recv_response_authenticator, radius_msg_ptr, 16); + + // Replace response authenticator with request authenticator + memcpy(radius_msg_ptr, data->request_authenticator, 16); + radius_msg_ptr += 16; + + // Calculate expected response authenticator + uint8_t calc_response_authenticator[16]; + if (radius_client_sec_prot_response_authenticator_calc(prot, length, pdu, calc_response_authenticator) < 0) { + tr_error("Could not calculate response authenticator MD5 hash"); + return -1; + } + + // Verify that received and calculated response authenticator matches + if (memcmp(recv_response_authenticator, calc_response_authenticator, 16) != 0) { + tr_error("Invalid response authenticator recv: %s, calc: %s", tr_array(recv_response_authenticator, 16), tr_array(calc_response_authenticator, 16)); + return -1; + } + + uint16_t avp_length = length - RADIUS_MSG_FIXED_LENGTH; + + uint8_t *message_authenticator = avp_message_authenticator_read(radius_msg_ptr, avp_length); + if (message_authenticator == NULL) { + tr_error("No message authenticator"); + } + + // Store message authenticator + uint8_t recv_message_authenticator[16]; + memcpy(recv_message_authenticator, message_authenticator, 16); + + // Replace message authenticator with zero + memset(message_authenticator, 0, 16); + + // Calculate expected message authenticator + uint8_t calc_message_authenticator[16]; + if (radius_client_sec_prot_message_authenticator_calc(prot, length, pdu, calc_message_authenticator) < 0) { + tr_error("Could not calculate message authenticator HMAC-MD5 hash"); + return -1; + } + + // Verify that received and calculated message authenticator matches + if (memcmp(recv_message_authenticator, calc_message_authenticator, 16) != 0) { + tr_error("Invalid message authenticator recv: %s, calc: %s", tr_array(recv_message_authenticator, 16), tr_array(calc_message_authenticator, 16)); + return -1; + } + + // Calculate EAP AVPs length + data->recv_eap_msg_len = radius_client_sec_prot_eap_avps_handle(avp_length, radius_msg_ptr, NULL); + if (data->recv_eap_msg_len == 0) { + return -1; + } + + // Allocate memory for continuous EAP buffer + data->recv_eap_msg = ns_dyn_mem_temporary_alloc(data->recv_eap_msg_len + data->radius_eap_tls_header_size); + if (data->recv_eap_msg == NULL) { + tr_error("Cannot allocate eap msg"); + return -1; + } + + // Copy EAP AVPs to continuous buffer + uint16_t copy_eap_len = radius_client_sec_prot_eap_avps_handle(avp_length, radius_msg_ptr, data->recv_eap_msg + data->radius_eap_tls_header_size); + if (copy_eap_len != data->recv_eap_msg_len) { + ns_dyn_mem_free(data->recv_eap_msg); + return -1; + } + + // Store state + uint8_t state_len; + uint8_t *state = avp_state_read(radius_msg_ptr, avp_length, &state_len); + if (state) { + state_len -= AVP_FIXED_LEN; + if (data->state && data->state_len != state_len) { + ns_dyn_mem_free(data->state); + data->state = NULL; + } + if (!data->state) { + data->state = ns_dyn_mem_temporary_alloc(state_len); + } + if (!data->state) { + tr_error("Cannot allocate state"); + ns_dyn_mem_free(data->recv_eap_msg); + data->recv_eap_msg = NULL; + return -1; + } + memcpy(data->state, state, state_len); + data->state_len = state_len; + } else { + if (data->state) { + ns_dyn_mem_free(data->state); + data->state = NULL; + data->state_len = 0; + } + } + + if (code == RADIUS_ACCESS_ACCEPT) { + uint8_t recv_key_len; + uint8_t *recv_key = avp_vsa_ms_mppe_recv_key_read(radius_msg_ptr, avp_length, &recv_key_len); + if (recv_key && recv_key_len > AVP_FIXED_LEN) { + if (radius_client_sec_prot_ms_mppe_recv_key_pmk_decrypt(prot, recv_key, + recv_key_len - AVP_FIXED_LEN, data->request_authenticator, data->new_pmk) >= 0) { + data->new_pmk_set = true; + tr_info("RADIUS PMK: %s %s", tr_array(data->new_pmk, 16), tr_array(data->new_pmk + 16, 16)); + } + } + } + + data->radius_code = code; + data->recv_eap_msg_len += data->radius_eap_tls_header_size; + prot->state_machine(prot); + + return 0; +} + +static int8_t radius_client_sec_prot_radius_eap_receive(sec_prot_t *prot, void *pdu, uint16_t size) +{ + radius_client_sec_prot_int_t *data = radius_client_sec_prot_get(prot); + + data->recv_eap_msg_len = size; + data->recv_eap_msg = pdu; + + prot->state_machine(prot); + + data->recv_eap_msg_len = 0; + data->recv_eap_msg = NULL; + + return 0; +} + +static uint8_t radius_client_sec_prot_identifier_allocate(void) +{ + return shared_data->radius_client_identifier++; +} + +static uint8_t radius_client_sec_prot_eui_64_hash_get(sec_prot_t *prot, uint8_t *local_eui_64_hash, uint8_t *remote_eui_64_hash, bool remote_eui_64_hash_set) +{ + if (!shared_data->local_eui64_hash_set || !remote_eui_64_hash_set) { + uint8_t local_eui64[8]; + uint8_t remote_eui64[8]; + prot->addr_get(prot, local_eui64, remote_eui64); + if (!shared_data->local_eui64_hash_set) { + radius_client_sec_prot_eui_64_hash_generate(local_eui64, shared_data->local_eui64_hash); + shared_data->local_eui64_hash_set = true; + } + if (!remote_eui_64_hash_set) { + radius_client_sec_prot_eui_64_hash_generate(remote_eui64, remote_eui_64_hash); + } + } + memcpy(local_eui_64_hash, shared_data->local_eui64_hash, 8); + + return 0; +} + +static void radius_client_sec_prot_allocate_and_create_radius_message(sec_prot_t *prot) +{ + radius_client_sec_prot_int_t *data = radius_client_sec_prot_get(prot); + + // code(1), packet-identifier(1), length(2), authenticator(16) + uint16_t radius_msg_length = RADIUS_MSG_FIXED_LENGTH; + + eapol_pdu_t *eap_hdr = (eapol_pdu_t *) data->recv_eap_msg; + + if (eap_hdr->msg.eap.type == EAP_IDENTITY) { + uint16_t id_len = eap_hdr->msg.eap.length; + // Calculate identity length + if (id_len > 5) { + id_len -= 5; + } + // Maximum length is 253 bytes + if (id_len > AVP_VALUE_MAX_LEN) { + id_len = AVP_VALUE_MAX_LEN; + } + data->identity = ns_dyn_mem_temporary_alloc(id_len); + if (!data->identity) { + return; + } + data->identity_len = id_len; + memcpy(data->identity, eap_hdr->msg.eap.data_ptr, id_len); + } + + // Calculate eap fragments + uint16_t eap_len = eap_hdr->msg.eap.length; + while (true) { + if (eap_len > AVP_VALUE_MAX_LEN) { + eap_len -= AVP_VALUE_MAX_LEN; + radius_msg_length += AVP_TYPE_EAP_MESSAGE_LEN(AVP_VALUE_MAX_LEN); + } else { + radius_msg_length += AVP_TYPE_EAP_MESSAGE_LEN(eap_len); + break; + } + } + + radius_msg_length += AVP_TYPE_USER_NAME_LEN(data->identity_len); + radius_msg_length += AVP_TYPE_NAS_PORT_LEN; + radius_msg_length += AVP_TYPE_FRAMED_MTU_LEN; + + if (data->state) { + radius_msg_length += AVP_FIXED_LEN + data->state_len; + } + + radius_msg_length += AVP_TYPE_CALLED_STATION_ID_LEN(STATION_ID_LEN); + radius_msg_length += AVP_TYPE_CALLING_STATION_ID_LEN(STATION_ID_LEN); + radius_msg_length += AVP_TYPE_NAS_IDENTIFIER_LEN(STATION_ID_LEN); + radius_msg_length += AVP_TYPE_NAS_PORT_TYPE_LEN; + radius_msg_length += AVP_TYPE_MESSAGE_AUTHENTICATOR_LEN; + radius_msg_length += AVP_TYPE_NAS_IPV6_ADDRESS_LEN; + + uint8_t *radius_msg_ptr = ns_dyn_mem_temporary_alloc(radius_msg_length); + uint8_t *radius_msg_start_ptr = radius_msg_ptr; + + *radius_msg_ptr++ = RADIUS_ACCESS_REQUEST; // code + data->radius_identifier = radius_client_sec_prot_identifier_allocate(); + *radius_msg_ptr++ = data->radius_identifier; // identifier + radius_msg_ptr = common_write_16_bit(radius_msg_length, radius_msg_ptr); // length + + randLIB_get_n_bytes_random(data->request_authenticator, 16); + memcpy(radius_msg_ptr, data->request_authenticator, 16); // request authenticator + radius_msg_ptr += 16; + + radius_msg_ptr = avp_user_name_write(radius_msg_ptr, data->identity_len, data->identity); + + uint8_t local_eui_64_hash[8]; + radius_client_sec_prot_eui_64_hash_get(prot, local_eui_64_hash, data->remote_eui_64_hash, data->remote_eui_64_hash_set); + data->remote_eui_64_hash_set = true; + + uint8_t station_id[STATION_ID_LEN]; + + radius_client_sec_prot_station_id_generate(data->remote_eui_64_hash, station_id); + radius_msg_ptr = avp_calling_station_id_write(radius_msg_ptr, STATION_ID_LEN, station_id); + + radius_client_sec_prot_station_id_generate(local_eui_64_hash, station_id); + radius_msg_ptr = avp_called_station_id_write(radius_msg_ptr, STATION_ID_LEN, station_id); + + radius_msg_ptr = avp_nas_identifier_write(radius_msg_ptr, STATION_ID_LEN, station_id); + + radius_msg_ptr = avp_nas_port_write(radius_msg_ptr, NAS_PORT); + + radius_msg_ptr = avp_framed_mtu_write(radius_msg_ptr, FRAMED_MTU); + + if (data->state) { + radius_msg_ptr = avp_state_write(radius_msg_ptr, data->state_len, data->state); + } + + radius_msg_ptr = avp_nas_port_type_write(radius_msg_ptr, NAS_PORT_TYPE_WIRELESS_IEEE802_11); + + uint8_t address[16]; + prot->ip_addr_get(prot, address); + radius_msg_ptr = avp_nas_ipv6_address_write(radius_msg_ptr, address); + + // Write eap fragments + eap_len = eap_hdr->msg.eap.length; + uint8_t *eap_ptr = eap_hdr->packet_body; + while (true) { + if (eap_len > AVP_VALUE_MAX_LEN) { + eap_len -= AVP_VALUE_MAX_LEN; + radius_msg_ptr = avp_eap_message_write(radius_msg_ptr, AVP_VALUE_MAX_LEN, eap_ptr); + eap_ptr += AVP_VALUE_MAX_LEN; + } else { + radius_msg_ptr = avp_eap_message_write(radius_msg_ptr, eap_len, eap_ptr); + break; + } + } + + uint8_t *message_auth_ptr = radius_msg_ptr; + uint8_t message_auth[16]; + memset(message_auth, 0, 16); // zero for value calculation + radius_msg_ptr = avp_message_authenticator_write(radius_msg_ptr, message_auth); + // Calculate message authenticator + if (radius_client_sec_prot_message_authenticator_calc(prot, radius_msg_length, radius_msg_start_ptr, message_auth) < 0) { + ns_dyn_mem_free(radius_msg_start_ptr); + return; + } + // Write message authenticator + radius_msg_ptr = avp_message_authenticator_write(message_auth_ptr, message_auth); + + // Store message for sending + if (data->send_radius_msg != NULL) { + ns_dyn_mem_free(data->send_radius_msg); + } + data->send_radius_msg = radius_msg_start_ptr; + data->send_radius_msg_len = radius_msg_length; +} + +static int8_t radius_client_sec_prot_radius_msg_send(sec_prot_t *prot) +{ + radius_client_sec_prot_int_t *data = radius_client_sec_prot_get(prot); + + if (!data->send_radius_msg || data->send_radius_msg_len == 0) { + return -1; + } + + if (prot->send(prot, data->send_radius_msg, data->send_radius_msg_len) < 0) { + return -1; + } + data->send_radius_msg = NULL; + data->send_radius_msg_len = 0; + + return 0; +} + +static int8_t radius_client_sec_prot_eui_64_hash_generate(uint8_t *eui_64, uint8_t *hashed_eui_64) +{ + int8_t ret_val = 0; + + if (!shared_data->hash_random_set) { + randLIB_get_n_bytes_random(shared_data->hash_random, 16); + } + + uint8_t hashed_string[24]; + memcpy(&hashed_string[0], eui_64, 8); + memcpy(&hashed_string[8], shared_data->hash_random, 16); + + mbedtls_sha256_context ctx; + + mbedtls_sha256_init(&ctx); + + if (mbedtls_sha256_starts_ret(&ctx, 0) != 0) { + ret_val = -1; + goto error; + } + + if (mbedtls_sha256_update_ret(&ctx, hashed_string, 24) != 0) { + ret_val = -1; + goto error; + } + + uint8_t output[32]; + + if (mbedtls_sha256_finish_ret(&ctx, output) != 0) { + ret_val = -1; + goto error; + } + + memcpy(hashed_eui_64, output, 8); + +error: + mbedtls_sha256_free(&ctx); + + return ret_val; +} + +static uint8_t radius_client_sec_prot_hex_to_ascii(uint8_t value) +{ + char character = '0'; + if (value <= 9) { + character = '0' + value; + } else if (value >= 0x0A && value <= 0x0F) { + character = 'A' + value - 0x0A; + } + return character; +} + +static void radius_client_sec_prot_station_id_generate(uint8_t *eui_64, uint8_t *station_id_ptr) +{ + for (uint8_t i = 0; i < 8; i++) { + *station_id_ptr++ = radius_client_sec_prot_hex_to_ascii(eui_64[i] / 16); + *station_id_ptr++ = radius_client_sec_prot_hex_to_ascii(eui_64[i] % 16); + if (i != 7) { + *station_id_ptr++ = '-'; + } + } +} + +static int8_t radius_client_sec_prot_message_authenticator_calc(sec_prot_t *prot, uint16_t msg_len, uint8_t *msg_ptr, uint8_t *auth_ptr) +{ + const uint8_t *key = prot->sec_cfg->radius_cfg.radius_shared_secret; + uint16_t key_len = prot->sec_cfg->radius_cfg.radius_shared_secret_len; + if (prot->sec_cfg->radius_cfg.radius_shared_secret_len == 0) { + return -1; + } + +#ifndef MBEDTLS_MD5_C + tr_error("FATAL: MD5 MBEDTLS_MD5_C not enabled"); +#endif + + if (hmac_md_calc(ALG_HMAC_MD5, key, key_len, msg_ptr, msg_len, auth_ptr, 16) < 0) { + return -1; + } + + return 0; +} + +static int8_t radius_client_sec_prot_response_authenticator_calc(sec_prot_t *prot, uint16_t msg_len, uint8_t *msg_ptr, uint8_t *auth_ptr) +{ +#ifdef MBEDTLS_MD5_C + const uint8_t *key = prot->sec_cfg->radius_cfg.radius_shared_secret; + uint16_t key_len = prot->sec_cfg->radius_cfg.radius_shared_secret_len; + if (prot->sec_cfg->radius_cfg.radius_shared_secret_len == 0) { + return -1; + } + + int8_t ret_value = -1; + + mbedtls_md5_context ctx; + + mbedtls_md5_init(&ctx); + + if (mbedtls_md5_starts_ret(&ctx) != 0) { + goto end; + } + + if (mbedtls_md5_update_ret(&ctx, msg_ptr, msg_len) != 0) { + goto end; + } + + if (mbedtls_md5_update_ret(&ctx, key, key_len) != 0) { + goto end; + } + + if (mbedtls_md5_finish_ret(&ctx, auth_ptr) != 0) { + goto end; + } + + ret_value = 0; + +end: + mbedtls_md5_free(&ctx); + + return ret_value; +#else + (void) prot; + (void) msg_len; + (void) msg_ptr; + (void) auth_ptr; + + tr_error("FATAL: MD5 MBEDTLS_MD5_C not enabled"); + + return -1; +#endif +} + +static int8_t radius_client_sec_prot_ms_mppe_recv_key_pmk_decrypt(sec_prot_t *prot, uint8_t *recv_key, uint8_t recv_key_len, uint8_t *request_authenticator, uint8_t *pmk_ptr) +{ +#ifdef MBEDTLS_MD5_C + const uint8_t *key = prot->sec_cfg->radius_cfg.radius_shared_secret; + uint16_t key_len = prot->sec_cfg->radius_cfg.radius_shared_secret_len; + if (prot->sec_cfg->radius_cfg.radius_shared_secret_len == 0) { + return -1; + } + + if (recv_key_len < MS_MPPE_RECV_KEY_SALT_LEN + MS_MPPE_RECV_KEY_BLOCK_LEN) { + return -1; + } + + uint8_t *salt_ptr = recv_key; + uint8_t *cipher_text_ptr = recv_key + MS_MPPE_RECV_KEY_SALT_LEN; + int16_t cipher_text_len = recv_key_len - MS_MPPE_RECV_KEY_SALT_LEN; + + uint8_t plain_text[cipher_text_len]; + uint8_t *plain_text_ptr = plain_text; + + bool first_interm_b_value = true; + uint8_t interm_b_val[MS_MPPE_RECV_KEY_BLOCK_LEN]; + + bool md5_failed = false; + + mbedtls_md5_context ctx; + + while (cipher_text_len >= MS_MPPE_RECV_KEY_BLOCK_LEN) { + mbedtls_md5_init(&ctx); + + if (mbedtls_md5_starts_ret(&ctx) != 0) { + md5_failed = true; + break; + } + + if (mbedtls_md5_update_ret(&ctx, key, key_len) != 0) { + md5_failed = true; + break; + } + + if (first_interm_b_value) { + // b(1) = MD5(secret + request-authenticator + salt) + if (mbedtls_md5_update_ret(&ctx, request_authenticator, MS_MPPE_RECV_KEY_BLOCK_LEN) != 0) { + md5_failed = true; + break; + } + if (mbedtls_md5_update_ret(&ctx, salt_ptr, MS_MPPE_RECV_KEY_SALT_LEN) != 0) { + md5_failed = true; + break; + } + } else { + // b(i) = MD5(secret + cipher_text(i - 1)) + if (mbedtls_md5_update_ret(&ctx, cipher_text_ptr - MS_MPPE_RECV_KEY_BLOCK_LEN, MS_MPPE_RECV_KEY_BLOCK_LEN) != 0) { + md5_failed = true; + break; + } + } + + if (mbedtls_md5_finish_ret(&ctx, interm_b_val) != 0) { + md5_failed = true; + break; + } + mbedtls_md5_free(&ctx); + + first_interm_b_value = false; + + for (uint8_t index = 0; index < MS_MPPE_RECV_KEY_BLOCK_LEN; index++) { + *plain_text_ptr++ = *cipher_text_ptr++ ^ interm_b_val[index]; + } + + cipher_text_len -= MS_MPPE_RECV_KEY_BLOCK_LEN; + } + + if (md5_failed) { + mbedtls_md5_free(&ctx); + } + + if (md5_failed || cipher_text_len != 0) { + return -1; + } + + memcpy(pmk_ptr, plain_text + 1, PMK_LEN); + + return 0; +#else + (void) prot; + (void) recv_key; + (void) recv_key_len; + (void) request_authenticator; + (void) pmk_ptr; + + tr_error("FATAL: MD5 MBEDTLS_MD5_C not enabled"); + + return -1; +#endif +} + +static void radius_client_sec_prot_finished_send(sec_prot_t *prot) +{ + radius_client_sec_prot_int_t *data = radius_client_sec_prot_get(prot); + prot->timer_start(prot); + sec_prot_state_set(prot, &data->common, RADIUS_STATE_FINISHED); +} + +static void radius_client_sec_prot_timer_timeout(sec_prot_t *prot, uint16_t ticks) +{ + radius_client_sec_prot_int_t *data = radius_client_sec_prot_get(prot); + + sec_prot_timer_timeout_handle(prot, &data->common, + &prot->sec_cfg->prot_cfg.sec_prot_trickle_params, ticks); +} + +static void radius_client_sec_prot_state_machine(sec_prot_t *prot) +{ + radius_client_sec_prot_int_t *data = radius_client_sec_prot_get(prot); + + switch (sec_prot_state_get(&data->common)) { + case RADIUS_STATE_INIT: + tr_debug("Radius: init"); + sec_prot_state_set(prot, &data->common, RADIUS_STATE_STATE_RESPONSE_ID); + prot->timer_start(prot); + break; + + // Wait EAP response, Identity (starts RADIUS Client protocol) + case RADIUS_STATE_STATE_RESPONSE_ID: + tr_debug("Radius: start, eui-64: %s", trace_array(sec_prot_remote_eui_64_addr_get(prot), 8)); + + // Set default timeout for the total maximum length of the negotiation + sec_prot_default_timeout_set(&data->common); + + sec_prot_state_set(prot, &data->common, RADIUS_STATE_CREATE_RESP); + + if (radius_client_sec_prot_init_radius_eap_tls(prot) < 0) { + tr_error("Radius: EAP-TLS init failed"); + return; + } + + radius_client_sec_prot_allocate_and_create_radius_message(prot); + + // Send KMP-CREATE.indication + prot->create_ind(prot); + break; + + // Wait KMP-CREATE.response + case RADIUS_STATE_CREATE_RESP: + if (sec_prot_result_ok_check(&data->common)) { + sec_prot_state_set(prot, &data->common, RADIUS_STATE_SEND_INITIAL_ACCESS_REQUEST); + prot->state_machine_call(prot); + } else { + // Ready to be deleted + sec_prot_state_set(prot, &data->common, RADIUS_STATE_FINISHED); + } + break; + + case RADIUS_STATE_SEND_INITIAL_ACCESS_REQUEST: + tr_debug("Radius: send initial access request, eui-64: %s", trace_array(sec_prot_remote_eui_64_addr_get(prot), 8)); + + if (radius_client_sec_prot_radius_msg_send(prot) < 0) { + tr_error("Radius: msg send error"); + } + + // Start trickle timer to re-send if no response + sec_prot_timer_trickle_start(&data->common, &prot->sec_cfg->prot_cfg.sec_prot_trickle_params); + + sec_prot_state_set(prot, &data->common, RADIUS_STATE_ACCESS_ACCEPT_REJECT_CHALLENGE); + break; + + case RADIUS_STATE_ACCESS_ACCEPT_REJECT_CHALLENGE: + + // On timeout + if (sec_prot_result_timeout_check(&data->common)) { + // Do nothing for now + return; + } + + tr_debug("Radius: received access accept/reject/challenge, eui-64: %s", trace_array(sec_prot_remote_eui_64_addr_get(prot), 8)); + + // Send to radius EAP-TLS + data->radius_eap_tls_send(data->radius_eap_tls_prot, (void *) data->recv_eap_msg, data->recv_eap_msg_len); + data->recv_eap_msg = NULL; + data->recv_eap_msg_len = 0; + + if (data->radius_code == RADIUS_ACCESS_REJECT) { + sec_prot_result_set(&data->common, SEC_RESULT_ERROR); + sec_prot_state_set(prot, &data->common, RADIUS_STATE_FINISH); + } else if (data->radius_code == RADIUS_ACCESS_ACCEPT) { + if (data->new_pmk_set) { + sec_prot_result_set(&data->common, SEC_RESULT_OK); + } else { + sec_prot_result_set(&data->common, SEC_RESULT_ERROR); + } + sec_prot_state_set(prot, &data->common, RADIUS_STATE_FINISH); + } else if (data->radius_code == RADIUS_ACCESS_CHALLENGE) { + sec_prot_state_set(prot, &data->common, RADIUS_STATE_SEND_ACCESS_REQUEST); + } + break; + + case RADIUS_STATE_SEND_ACCESS_REQUEST: + + // On timeout + if (sec_prot_result_timeout_check(&data->common)) { + // Do nothing for now + return; + } + + tr_debug("Radius: send access request, eui-64: %s", trace_array(sec_prot_remote_eui_64_addr_get(prot), 8)); + + radius_client_sec_prot_allocate_and_create_radius_message(prot); + + if (radius_client_sec_prot_radius_msg_send(prot) < 0) { + tr_error("Radius: msg send error"); + } + + sec_prot_state_set(prot, &data->common, RADIUS_STATE_ACCESS_ACCEPT_REJECT_CHALLENGE); + break; + + case RADIUS_STATE_FINISH: + tr_debug("Radius: finish, eui-64: %s", trace_array(sec_prot_remote_eui_64_addr_get(prot), 8)); + + if (sec_prot_result_ok_check(&data->common)) { + sec_prot_keys_pmk_write(prot->sec_keys, data->new_pmk, prot->sec_cfg->timer_cfg.pmk_lifetime); + // Supplicant PMK is now valid + sec_prot_keys_pmk_mismatch_reset(prot->sec_keys); + /* Calls KMP-FINISHED.indication with ignore results because next + protocol is triggered from radius EAP-TLS */ + sec_prot_result_set(&data->common, SEC_RESULT_IGNORE); + } + + // KMP-FINISHED.indication + prot->finished_ind(prot, sec_prot_result_get(&data->common), prot->sec_keys); + sec_prot_state_set(prot, &data->common, RADIUS_STATE_FINISHED); + + break; + + case RADIUS_STATE_FINISHED: { + uint8_t *remote_eui_64 = sec_prot_remote_eui_64_addr_get(prot); + tr_debug("Radius: finished, eui-64: %s", remote_eui_64 ? trace_array(remote_eui_64, 8) : "not set"); + + prot->timer_stop(prot); + prot->finished(prot); + break; + } + + default: + break; + } +} + +#endif /* HAVE_WS */ diff --git a/source/Security/protocols/radius_sec_prot/radius_client_sec_prot.h b/source/Security/protocols/radius_sec_prot/radius_client_sec_prot.h new file mode 100644 index 000000000000..9d3a467284d4 --- /dev/null +++ b/source/Security/protocols/radius_sec_prot/radius_client_sec_prot.h @@ -0,0 +1,36 @@ +/* + * 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 RADIUS_CLIENT_SEC_PROT_H_ +#define RADIUS_CLIENT_SEC_PROT_H_ + +/* + * RADIUS client security protocol + * + */ + +/** + * radius_client_sec_prot_register register RADIUS client protocol to KMP service + * + * \param service KMP service + * + * \return < 0 failure + * \return >= 0 success + */ +int8_t radius_client_sec_prot_register(kmp_service_t *service); + +#endif /* RADIUS_CLIENT_SEC_PROT_H_ */ diff --git a/source/Security/protocols/sec_prot.h b/source/Security/protocols/sec_prot.h index c6ebae78a95d..3c7724124eed 100644 --- a/source/Security/protocols/sec_prot.h +++ b/source/Security/protocols/sec_prot.h @@ -34,7 +34,8 @@ typedef enum { SEC_RESULT_ERR_UNSPEC = -3, SEC_RESULT_TIMEOUT = -4, SEC_RESULT_ERROR = -5, - SEC_RESULT_CONF_ERROR = -6 + SEC_RESULT_CONF_ERROR = -6, + SEC_RESULT_IGNORE } sec_prot_result_e; typedef enum { @@ -49,7 +50,9 @@ typedef enum { typedef enum { SEC_PROT_TYPE_EAP_TLS = 0, - SEC_PROT_TYPE_TLS + SEC_PROT_TYPE_RADIUS_EAP_TLS, + SEC_PROT_TYPE_TLS, + SEC_PROT_TYPE_RADIUS_CLIENT } sec_prot_type_e; typedef enum { @@ -216,6 +219,15 @@ typedef void sec_prot_timer_timeout(sec_prot_t *prot, uint16_t ticks); */ typedef void sec_prot_eui64_addr_get(sec_prot_t *prot, uint8_t *local_eui64, uint8_t *remote_eui64); +/** + * sec_prot_ip_addr_get gets IP address for security protocol + * + * \param prot protocol + * \param address IP address + * + */ +typedef void sec_prot_ip_addr_get(sec_prot_t *prot, uint8_t *address); + /** * sec_prot_by_type_get gets security protocol * @@ -237,6 +249,19 @@ typedef sec_prot_t *sec_prot_by_type_get(sec_prot_t *prot, uint8_t type); */ typedef void sec_prot_receive_disable(sec_prot_t *prot); +/** + * sec_prot_receive_check check if received message is for this protocol + * + * \param prot protocol + * \param pdu pdu + * \param size pdu size + * + * \return < 0 message is not for this protocol + * \return >= 0 message is for this protocol + * + */ +typedef int8_t sec_prot_receive_check(sec_prot_t *prot, const void *pdu, uint16_t size); + typedef struct sec_prot_int_data_s sec_prot_int_data_t; // Security protocol data @@ -252,6 +277,8 @@ struct sec_prot_s { sec_prot_send *send; /**< Protocol send */ sec_prot_receive *receive; /**< Protocol receive */ + sec_prot_receive *receive_peer; /**< Protocol receive from peer (used by peer protocol for send) */ + sec_prot_tx_status_ind *tx_status_ind; /**< TX status indication */ sec_prot_delete *delete; /**< Protocol delete */ @@ -264,13 +291,16 @@ struct sec_prot_s { sec_prot_timer_timeout *timer_timeout; /**< Timer timeout */ sec_prot_eui64_addr_get *addr_get; /**< Gets EUI-64 addresses */ + sec_prot_ip_addr_get *ip_addr_get; /**< Gets IP address */ sec_prot_by_type_get *type_get; /**< Gets security protocol by type */ sec_prot_receive_disable *receive_disable; /**< Disable receiving of messages */ + sec_prot_receive_check *receive_check; /**< Check if messages is for this protocol */ sec_prot_keys_t *sec_keys; /**< Security keys storage pointer */ - sec_prot_cfg_t *prot_cfg; /**< Security protocol configuration pointer */ - sec_timer_cfg_t *timer_cfg; /**< Security timer configuration pointer */ + sec_cfg_t *sec_cfg; /**< Security configuration configuration pointer */ uint8_t header_size; /**< Header size */ + uint8_t receive_peer_hdr_size; /**< Receive from peer header size */ + uint8_t msg_if_instance_id; /**< Message interface instance identifier */ sec_prot_int_data_t *data; /**< Protocol internal data */ }; diff --git a/source/Security/protocols/sec_prot_cfg.h b/source/Security/protocols/sec_prot_cfg.h index f0a118b7c1df..f9c777e3fa37 100644 --- a/source/Security/protocols/sec_prot_cfg.h +++ b/source/Security/protocols/sec_prot_cfg.h @@ -43,4 +43,19 @@ typedef struct sec_timer_cfg_s { uint8_t gtk_new_install_req; /* GTK_NEW_INSTALL_REQUIRED (percent of GTK lifetime) */ } sec_timer_cfg_t; +/* Security radius configuration settings */ + +typedef struct sec_radius_cfg_s { + uint8_t radius_addr[16]; /**< Radius server IPv6 address */ + uint8_t *radius_shared_secret; /**< Radius shared secret */ + uint8_t radius_shared_secret_len; /**< Radius shared secret length */ + bool radius_addr_set : 1; /**< Radius server address is set */ +} sec_radius_cfg_t; + +typedef struct sec_cfg_s { + sec_prot_cfg_t prot_cfg; + sec_timer_cfg_t timer_cfg; + sec_radius_cfg_t radius_cfg; +} sec_cfg_t; + #endif /* SEC_PROT_CONF_H_ */ diff --git a/source/Security/protocols/sec_prot_lib.c b/source/Security/protocols/sec_prot_lib.c index bc85d0b9f1b0..604644fbc2c4 100644 --- a/source/Security/protocols/sec_prot_lib.c +++ b/source/Security/protocols/sec_prot_lib.c @@ -36,8 +36,8 @@ #include "Security/protocols/sec_prot_keys.h" #include "Security/protocols/sec_prot.h" #include "Security/protocols/sec_prot_lib.h" +#include "Service_Libs/hmac/hmac_md.h" #include "Service_Libs/ieee_802_11/ieee_802_11.h" -#include "Service_Libs/hmac/hmac_sha1.h" #include "Service_Libs/nist_aes_kw/nist_aes_kw.h" #include "mbedtls/sha256.h" @@ -297,7 +297,7 @@ int8_t sec_prot_lib_pmkid_calc(const uint8_t *pmk, const uint8_t *auth_eui64, co ptr += EUI64_LEN; memcpy(ptr, supp_eui64, EUI64_LEN); - if (hmac_sha1_calc(pmk, PMK_LEN, data, data_len, pmkid, PMKID_LEN) < 0) { + if (hmac_md_calc(ALG_HMAC_SHA1_160, pmk, PMK_LEN, data, data_len, pmkid, PMKID_LEN) < 0) { return -1; } @@ -319,7 +319,7 @@ int8_t sec_prot_lib_ptkid_calc(const uint8_t *ptk, const uint8_t *auth_eui64, co ptr += EUI64_LEN; memcpy(ptr, supp_eui64, EUI64_LEN); - if (hmac_sha1_calc(ptk, PTK_LEN, data, data_len, ptkid, PTKID_LEN) < 0) { + if (hmac_md_calc(ALG_HMAC_SHA1_160, ptk, PTK_LEN, data, data_len, ptkid, PTKID_LEN) < 0) { return -1; } @@ -351,7 +351,7 @@ uint8_t *sec_prot_lib_message_build(uint8_t *ptk, uint8_t *kde, uint16_t kde_len if (eapol_pdu->msg.key.key_information.key_mic) { uint8_t mic[EAPOL_KEY_MIC_LEN]; - if (hmac_sha1_calc(ptk, KCK_LEN, eapol_pdu_frame + header_size, eapol_pdu_size, mic, EAPOL_KEY_MIC_LEN) < 0) { + if (hmac_md_calc(ALG_HMAC_SHA1_160, ptk, KCK_LEN, eapol_pdu_frame + header_size, eapol_pdu_size, mic, EAPOL_KEY_MIC_LEN) < 0) { ns_dyn_mem_free(eapol_pdu_frame); return NULL; } @@ -434,7 +434,7 @@ int8_t sec_prot_lib_mic_validate(uint8_t *ptk, uint8_t *mic, uint8_t *pdu, uint8 eapol_write_key_packet_mic(pdu, 0); uint8_t calc_mic[EAPOL_KEY_MIC_LEN]; - if (hmac_sha1_calc(ptk, EAPOL_KEY_MIC_LEN, pdu, pdu_size, calc_mic, EAPOL_KEY_MIC_LEN) < 0) { + if (hmac_md_calc(ALG_HMAC_SHA1_160, ptk, EAPOL_KEY_MIC_LEN, pdu, pdu_size, calc_mic, EAPOL_KEY_MIC_LEN) < 0) { tr_error("MIC invalid"); return -1; } 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 d4b8c549ae82..472c0411dc30 100644 --- a/source/Security/protocols/tls_sec_prot/tls_sec_prot.c +++ b/source/Security/protocols/tls_sec_prot/tls_sec_prot.c @@ -375,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, prot->timer_cfg->pmk_lifetime); + sec_prot_keys_pmk_write(prot->sec_keys, data->new_pmk, prot->sec_cfg->timer_cfg.pmk_lifetime); } // KMP-FINISHED.indication, @@ -494,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, prot->timer_cfg->pmk_lifetime); + sec_prot_keys_pmk_write(prot->sec_keys, data->new_pmk, prot->sec_cfg->timer_cfg.pmk_lifetime); } // KMP-FINISHED.indication, diff --git a/source/Service_Libs/hmac/hmac_sha1.c b/source/Service_Libs/hmac/hmac_md.c similarity index 77% rename from source/Service_Libs/hmac/hmac_sha1.c rename to source/Service_Libs/hmac/hmac_md.c index 7e7e47dcb622..a3eb539b61ea 100644 --- a/source/Service_Libs/hmac/hmac_sha1.c +++ b/source/Service_Libs/hmac/hmac_md.c @@ -21,20 +21,20 @@ #include "ns_list.h" #include "ns_trace.h" #include "mbedtls/md.h" -#include "Service_Libs/hmac/hmac_sha1.h" +#include "hmac_md.h" #define TRACE_GROUP "hmac" -int8_t hmac_sha1_calc(const uint8_t *key, uint16_t key_len, const uint8_t *data, uint16_t data_len, uint8_t *result, uint8_t result_len) +int8_t hmac_md_calc(const alg_hmac_md_e md, const uint8_t *key, uint16_t key_len, const uint8_t *data, uint16_t data_len, uint8_t *result, uint8_t result_len) { #ifdef EXTRA_DEBUG_INFO // Extensive debug for now, to be disabled later - tr_debug("hmac_sha_1 key %s\n", trace_array(key, key_len)); + tr_debug("hmac_md key %s\n", trace_array(key, key_len)); const uint8_t *print_data = data; uint16_t print_data_len = data_len; while (true) { - tr_debug("hmac_sha_1 data %s\n", trace_array(print_data, print_data_len > 32 ? 32 : print_data_len)); + tr_debug("hmac_md data %s\n", trace_array(print_data, print_data_len > 32 ? 32 : print_data_len)); if (print_data_len > 32) { print_data_len -= 32; print_data += 32; @@ -44,7 +44,12 @@ int8_t hmac_sha1_calc(const uint8_t *key, uint16_t key_len, const uint8_t *data, } #endif - const mbedtls_md_type_t md_type = MBEDTLS_MD_SHA1; + mbedtls_md_type_t md_type; + if (md == ALG_HMAC_MD5) { + md_type = MBEDTLS_MD_MD5; + } else { + md_type = MBEDTLS_MD_SHA1; + } const mbedtls_md_info_t *md_info = mbedtls_md_info_from_type(md_type); if (md_info == NULL) { return -1; @@ -76,7 +81,7 @@ int8_t hmac_sha1_calc(const uint8_t *key, uint16_t key_len, const uint8_t *data, memcpy(result, result_value, result_len); #ifdef EXTRA_DEBUG_INFO - tr_debug("hmac_sha_1 result %s\n", trace_array(result_value, 20)); + tr_debug("hmac_md result %s\n", trace_array(result_value, 20)); #endif return 0; diff --git a/source/Service_Libs/hmac/hmac_sha1.h b/source/Service_Libs/hmac/hmac_md.h similarity index 73% rename from source/Service_Libs/hmac/hmac_sha1.h rename to source/Service_Libs/hmac/hmac_md.h index 77ef76bfc013..7c55b77a459d 100644 --- a/source/Service_Libs/hmac/hmac_sha1.h +++ b/source/Service_Libs/hmac/hmac_md.h @@ -18,11 +18,17 @@ #ifndef HMAC_SHA1_ #define HMAC_SHA1_ +typedef enum { + ALG_HMAC_MD5, + ALG_HMAC_SHA1_160 +} alg_hmac_md_e; + /** - * \brief Calculate HMAC-SHA1-160 + * \brief Calculate HMAC-SHA1-160 or HMAC-MD5 * - * Calculate HMAC-SHA1-160 + * Calculate HMAC-SHA1-160 or HMAC-MD5 * + * \param md message digest algorithm * \param key pointer to key * \param key_len key length * \param data pointer to data @@ -34,6 +40,6 @@ * \return >= 0 success * */ -int8_t hmac_sha1_calc(const uint8_t *key, uint16_t key_len, const uint8_t *data, uint16_t data_len, uint8_t *result, uint8_t result_len); +int8_t hmac_md_calc(const alg_hmac_md_e md, const uint8_t *key, uint16_t key_len, const uint8_t *data, uint16_t data_len, uint8_t *result, uint8_t result_len); #endif /* HMAC_SHA1_ */ diff --git a/source/Service_Libs/ieee_802_11/ieee_802_11.c b/source/Service_Libs/ieee_802_11/ieee_802_11.c index fb36a03c6727..6200ae0eb991 100644 --- a/source/Service_Libs/ieee_802_11/ieee_802_11.c +++ b/source/Service_Libs/ieee_802_11/ieee_802_11.c @@ -22,7 +22,7 @@ #include "ns_trace.h" #include "mbedtls/md.h" #include "Service_Libs/ieee_802_11/ieee_802_11.h" -#include "Service_Libs/hmac/hmac_sha1.h" +#include "Service_Libs/hmac/hmac_md.h" #define TRACE_GROUP "iprf" @@ -67,7 +67,7 @@ int8_t ieee_802_11_prf_finish(ieee_802_11_prf_t *prf, uint8_t *result) for (uint8_t i = 0; i < (prf->bits + 159) / 160; i++) { prf->string[prf->a_len + 1 + prf->b_len] = i; /* X (index) */ - if (hmac_sha1_calc(prf->key, prf->key_len, prf->string, string_len, result, 20) < 0) { + if (hmac_md_calc(ALG_HMAC_SHA1_160, prf->key, prf->key_len, prf->string, string_len, result, 20) < 0) { return -1; } result += 160 / 8; diff --git a/sources.mk b/sources.mk index e364c49b840b..97b4113c2078 100644 --- a/sources.mk +++ b/sources.mk @@ -113,12 +113,15 @@ SRCS += \ source/Security/protocols/sec_prot_certs.c \ source/Security/protocols/key_sec_prot/key_sec_prot.c \ source/Security/protocols/eap_tls_sec_prot/auth_eap_tls_sec_prot.c \ + source/Security/protocols/eap_tls_sec_prot/radius_eap_tls_sec_prot.c \ source/Security/protocols/eap_tls_sec_prot/supp_eap_tls_sec_prot.c \ source/Security/protocols/eap_tls_sec_prot/eap_tls_sec_prot_lib.c \ source/Security/protocols/fwh_sec_prot/auth_fwh_sec_prot.c \ source/Security/protocols/fwh_sec_prot/supp_fwh_sec_prot.c \ source/Security/protocols/gkh_sec_prot/auth_gkh_sec_prot.c \ source/Security/protocols/gkh_sec_prot/supp_gkh_sec_prot.c \ + source/Security/protocols/radius_sec_prot/radius_client_sec_prot.c \ + source/Security/protocols/radius_sec_prot/avp_helper.c \ source/Security/protocols/tls_sec_prot/tls_sec_prot.c \ source/Security/protocols/tls_sec_prot/tls_sec_prot_lib.c \ source/Security/PANA/eap_protocol.c \ @@ -142,7 +145,7 @@ SRCS += \ source/Service_Libs/fhss/channel_list.c \ source/Service_Libs/fhss/fhss_test_api.c \ source/Service_Libs/fnv_hash/fnv_hash.c \ - source/Service_Libs/hmac/hmac_sha1.c \ + source/Service_Libs/hmac/hmac_md.c \ source/Service_Libs/ieee_802_11/ieee_802_11.c \ source/Service_Libs/nist_aes_kw/nist_aes_kw.c \ source/Service_Libs/mac_neighbor_table/mac_neighbor_table.c \ diff --git a/test/nanostack/unittest/service_libs/hmac/Makefile b/test/nanostack/unittest/service_libs/hmac/Makefile index c4ec3f9eadb4..4b8cdbbf2219 100644 --- a/test/nanostack/unittest/service_libs/hmac/Makefile +++ b/test/nanostack/unittest/service_libs/hmac/Makefile @@ -4,7 +4,7 @@ COMPONENT_NAME = hmac_unit #This must be changed manually SRC_FILES = \ - ../../../../../source/Service_Libs/hmac/hmac_sha1.c \ + ../../../../../source/Service_Libs/hmac/hmac_md.c \ TEST_SRC_FILES = \ main.cpp \ diff --git a/test/nanostack/unittest/service_libs/hmac/hmactest.cpp b/test/nanostack/unittest/service_libs/hmac/hmactest.cpp index 3e4876021938..493fe28902e4 100644 --- a/test/nanostack/unittest/service_libs/hmac/hmactest.cpp +++ b/test/nanostack/unittest/service_libs/hmac/hmactest.cpp @@ -61,3 +61,8 @@ TEST(HMAC, test_HMAC_hmac_sha1_calc_7) { CHECK(test_HMAC_hmac_sha1_calc_7()); } + +TEST(HMAC, test_HMAC_hmac_md5_calc_1) +{ + CHECK(test_HMAC_hmac_md5_calc_1()); +} diff --git a/test/nanostack/unittest/service_libs/hmac/test_hmac.c b/test/nanostack/unittest/service_libs/hmac/test_hmac.c index 4b11450ba836..962feea87d01 100644 --- a/test/nanostack/unittest/service_libs/hmac/test_hmac.c +++ b/test/nanostack/unittest/service_libs/hmac/test_hmac.c @@ -21,8 +21,8 @@ #include #include +#include "Service_Libs/hmac/hmac_md.h" #include "ns_address_internal.h" -#include "Service_Libs/hmac/hmac_sha1.h" #include "mbedtls/md.h" #include "mbedtls_stub.h" @@ -49,7 +49,7 @@ bool test_HMAC_hmac_sha1_calc_1() mbedtls_stub.md.output_string = output; uint8_t result[20]; - int8_t ret = hmac_sha1_calc(key, key_len, data, data_len, result, 20); + int8_t ret = hmac_md_calc(ALG_HMAC_SHA1_160, key, key_len, data, data_len, result, 20); if (ret < 0) { return false; @@ -104,7 +104,7 @@ bool test_HMAC_hmac_sha1_calc_2() mbedtls_stub.md.finish_ret = 0; uint8_t result[20]; - int8_t ret = hmac_sha1_calc(key, key_len, data, data_len, result, 20); + int8_t ret = hmac_md_calc(ALG_HMAC_SHA1_160, key, key_len, data, data_len, result, 20); if (ret >= 0) { return false; @@ -149,7 +149,7 @@ bool test_HMAC_hmac_sha1_calc_3() mbedtls_stub.md.finish_ret = 0; uint8_t result[20]; - int8_t ret = hmac_sha1_calc(key, key_len, data, data_len, result, 20); + int8_t ret = hmac_md_calc(ALG_HMAC_SHA1_160, key, key_len, data, data_len, result, 20); if (ret >= 0) { return false; @@ -194,7 +194,7 @@ bool test_HMAC_hmac_sha1_calc_4() mbedtls_stub.md.finish_ret = 0; uint8_t result[20]; - int8_t ret = hmac_sha1_calc(key, key_len, data, data_len, result, 20); + int8_t ret = hmac_md_calc(ALG_HMAC_SHA1_160, key, key_len, data, data_len, result, 20); if (ret >= 0) { return false; @@ -239,7 +239,7 @@ bool test_HMAC_hmac_sha1_calc_5() mbedtls_stub.md.finish_ret = 0; uint8_t result[20]; - int8_t ret = hmac_sha1_calc(key, key_len, data, data_len, result, 20); + int8_t ret = hmac_md_calc(ALG_HMAC_SHA1_160, key, key_len, data, data_len, result, 20); if (ret >= 0) { return false; @@ -284,7 +284,7 @@ bool test_HMAC_hmac_sha1_calc_6() mbedtls_stub.md.finish_ret = -1; // FAIL uint8_t result[20]; - int8_t ret = hmac_sha1_calc(key, key_len, data, data_len, result, 20); + int8_t ret = hmac_md_calc(ALG_HMAC_SHA1_160, key, key_len, data, data_len, result, 20); if (ret >= 0) { return false; @@ -328,7 +328,7 @@ bool test_HMAC_hmac_sha1_calc_7() for (int i = 0; i < 30; i++) { result[i] = i; } - int8_t ret = hmac_sha1_calc(key, key_len, data, data_len, result, 10); + int8_t ret = hmac_md_calc(ALG_HMAC_SHA1_160, key, key_len, data, data_len, result, 10); if (ret < 0) { return false; @@ -368,3 +368,54 @@ bool test_HMAC_hmac_sha1_calc_7() return true; } + +bool test_HMAC_hmac_md5_calc_1() +{ + memset(&mbedtls_stub.md, 0, sizeof(mbedtls_stub.md)); + + uint8_t md_info; + mbedtls_stub.md.info_ret = &md_info; + + uint8_t md_key_string[key_len]; + uint8_t md_input_string[data_len]; + + mbedtls_stub.md.key_string = md_key_string; + mbedtls_stub.md.input_string = md_input_string; + mbedtls_stub.md.output_string = output; + + uint8_t result[20]; + int8_t ret = hmac_md_calc(ALG_HMAC_MD5, key, key_len, data, data_len, result, 20); + + if (ret < 0) { + return false; + } + if (mbedtls_stub.md.md_type != MBEDTLS_MD_MD5) { + return false; + } + if (mbedtls_stub.md.info != &md_info) { + return false; + } + if (mbedtls_stub.md.hmac != 1) { + return false; + } + if (mbedtls_stub.md.keylen != key_len) { + return false; + } + if (memcmp(mbedtls_stub.md.key_string, key, key_len) != 0) { + return false; + } + if (mbedtls_stub.md.ilen != data_len) { + return false; + } + if (memcmp(mbedtls_stub.md.input_string, data, data_len) != 0) { + return false; + } + if (mbedtls_stub.md.free_ctx == 0) { + return false; + } + if (memcmp(output, result, 20) != 0) { + return false; + } + return true; +} + diff --git a/test/nanostack/unittest/service_libs/hmac/test_hmac.h b/test/nanostack/unittest/service_libs/hmac/test_hmac.h index 96014bffcb9a..f7194dd43c87 100644 --- a/test/nanostack/unittest/service_libs/hmac/test_hmac.h +++ b/test/nanostack/unittest/service_libs/hmac/test_hmac.h @@ -30,6 +30,7 @@ bool test_HMAC_hmac_sha1_calc_4(); bool test_HMAC_hmac_sha1_calc_5(); bool test_HMAC_hmac_sha1_calc_6(); bool test_HMAC_hmac_sha1_calc_7(); +bool test_HMAC_hmac_md5_calc_1(); #ifdef __cplusplus } diff --git a/test/nanostack/unittest/service_libs/ieee_802_11/test_ieee_802_11.c b/test/nanostack/unittest/service_libs/ieee_802_11/test_ieee_802_11.c index 759fb8dc0351..66ddff0b3739 100644 --- a/test/nanostack/unittest/service_libs/ieee_802_11/test_ieee_802_11.c +++ b/test/nanostack/unittest/service_libs/ieee_802_11/test_ieee_802_11.c @@ -22,6 +22,7 @@ #include "ns_address_internal.h" #include "Service_Libs/ieee_802_11/ieee_802_11.h" +#include "Service_Libs/hmac/hmac_md.h" #include "hmac_stub.h" static const uint8_t a_string_val[] = {"123456789"}; @@ -90,6 +91,9 @@ bool test_IEEE_802_11_ieee_802_11_prf_1() } for (int i = 0; i < 3; i++) { + if (hmac_stub.data[i].md != ALG_HMAC_SHA1_160) { + return false; + } if (hmac_stub.data[i].key_len != key_len) { return false; } @@ -164,6 +168,9 @@ bool test_IEEE_802_11_ieee_802_11_prf_2() return false; } + if (hmac_stub.data[0].md != ALG_HMAC_SHA1_160) { + return false; + } if (hmac_stub.data[0].key_len != key_len) { return false; } diff --git a/test/nanostack/unittest/stub/hmac_stub.c b/test/nanostack/unittest/stub/hmac_stub.c index 786a2ebaea37..ecb69de0aaad 100644 --- a/test/nanostack/unittest/stub/hmac_stub.c +++ b/test/nanostack/unittest/stub/hmac_stub.c @@ -16,6 +16,7 @@ */ #include "nsconfig.h" #include "ns_types.h" +#include "Service_Libs/hmac/hmac_md.h" #include "hmac_stub.h" @@ -23,8 +24,9 @@ hmac_stub_def hmac_stub; -int8_t hmac_sha1_calc(const uint8_t *key, uint16_t key_len, const uint8_t *data, uint16_t data_len, uint8_t *result, uint8_t result_len) +int8_t hmac_md_calc(const alg_hmac_md_e md, const uint8_t *key, uint16_t key_len, const uint8_t *data, uint16_t data_len, uint8_t *result, uint8_t result_len) { + hmac_stub.data[hmac_stub.index].md = md; memcpy(hmac_stub.data[hmac_stub.index].key, key, key_len); hmac_stub.data[hmac_stub.index].key_len = key_len; memcpy(hmac_stub.data[hmac_stub.index].data, data, data_len); diff --git a/test/nanostack/unittest/stub/hmac_stub.h b/test/nanostack/unittest/stub/hmac_stub.h index f0bfdd9e3c0e..58a63830018e 100644 --- a/test/nanostack/unittest/stub/hmac_stub.h +++ b/test/nanostack/unittest/stub/hmac_stub.h @@ -22,6 +22,7 @@ extern "C" { #endif typedef struct { + int md; char *key; int key_len; char *data; From 0860b57879f9c52059859ea2c3c9c760a21945c2 Mon Sep 17 00:00:00 2001 From: Jarkko Paso Date: Wed, 12 Aug 2020 14:27:03 +0300 Subject: [PATCH 22/30] FHSS_WS: Fixed reading unicast remaining slots (#2408) * FHSS_WS: Fixed reading unicast remaining slots * Unit test: Fixed FHSS WS tests --- source/Service_Libs/fhss/fhss_ws.c | 5 ++++- .../unittest/service_libs/fhss_ws/test_fhss_ws.c | 15 +++++++++++++-- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/source/Service_Libs/fhss/fhss_ws.c b/source/Service_Libs/fhss/fhss_ws.c index 05235ca0256b..d37ff27a77f8 100644 --- a/source/Service_Libs/fhss/fhss_ws.c +++ b/source/Service_Libs/fhss/fhss_ws.c @@ -417,7 +417,10 @@ static uint32_t fhss_ws_calculate_ufsi(fhss_structure_t *fhss_structure, uint32_ cur_slot = fhss_structure->number_of_uc_channels; } cur_slot--; - uint32_t remaining_time_ms = US_TO_MS(get_remaining_slots_us(fhss_structure, fhss_unicast_handler, MS_TO_US(fhss_structure->ws->fhss_configuration.fhss_uc_dwell_interval))); + uint32_t remaining_time_ms = 0; + if (fhss_structure->ws->unicast_timer_running == true) { + remaining_time_ms = US_TO_MS(get_remaining_slots_us(fhss_structure, fhss_unicast_handler, MS_TO_US(dwell_time) - NS_TO_US(dwell_time * fhss_structure->ws->drift_per_millisecond_ns))); + } uint32_t time_to_tx = 0; uint32_t cur_time = fhss_structure->callbacks.read_timestamp(fhss_structure->fhss_api); if (cur_time < tx_time) { diff --git a/test/nanostack/unittest/service_libs/fhss_ws/test_fhss_ws.c b/test/nanostack/unittest/service_libs/fhss_ws/test_fhss_ws.c index c7125085bf55..c6943b1a8000 100644 --- a/test/nanostack/unittest/service_libs/fhss_ws/test_fhss_ws.c +++ b/test/nanostack/unittest/service_libs/fhss_ws/test_fhss_ws.c @@ -138,6 +138,11 @@ static fhss_api_t *test_generate_fhss_api(void) fhss_common_stub.fhss_struct.ws->fhss_configuration.fhss_broadcast_interval = 1000; fhss_common_stub.fhss_struct.ws->get_neighbor_info = &app_get_neighbor_info; fhss_common_stub.fhss_struct.number_of_channels = 50; + fhss_common_stub.fhss_struct.number_of_uc_channels = 50; + fhss_common_stub.fhss_struct.ws->fhss_configuration.unicast_channel_mask[1] = 0x0003ffff; + fhss_common_stub.fhss_struct.ws->fhss_configuration.unicast_channel_mask[0] = 0xffffffff; + fhss_common_stub.fhss_struct.ws->fhss_configuration.channel_mask[1] = 0x0003ffff; + fhss_common_stub.fhss_struct.ws->fhss_configuration.channel_mask[0] = 0xffffffff; fhss_common_stub.fhss_struct.rx_channel = DEFAULT_CHANNEL; fhss_common_stub.fhss_struct.fhss_state = FHSS_UNSYNCHRONIZED; fhss_common_stub.fhss_struct.own_hop = 0xff; @@ -273,6 +278,7 @@ bool test_fhss_ws_tx_handle_callback() memset(&neighbor_info, 0, sizeof(fhss_ws_neighbor_timing_info_t)); // Test direct hash channel function neighbor_info.uc_timing_info.unicast_channel_function = WS_DH1CF; + neighbor_info.uc_timing_info.unicast_number_of_channels = fhss_common_stub.fhss_struct.number_of_channels; if (fhss_common_stub.fhss_struct.fhss_api->tx_handle(api, DEFAULT_IS_BC_DEST, dest_address, DEFAULT_FRAME_TYPE, DEFAULT_FRAME_LENGTH, DEFAULT_PHY_HEAD_LENGTH, DEFAULT_PHY_TAIL_LENGTH, DEFAULT_TX_TIME) != 0) { return false; } @@ -332,6 +338,7 @@ bool test_fhss_ws_check_tx_conditions_callback() fhss_common_stub.fhss_struct.own_hop = 0; fhss_common_stub.fhss_struct.ws->fhss_configuration.fhss_broadcast_interval = 800; fhss_common_stub.fhss_struct.ws->fhss_configuration.fhss_bc_dwell_interval = 200; + fhss_common_stub.fhss_struct.ws->txrx_slot_length_ms = 100; fhss_platform_stub.remaining_slots_value = 550000; if (fhss_common_stub.fhss_struct.fhss_api->check_tx_conditions(api, DEFAULT_IS_BC_DEST, DEFAULT_HANDLE, DEFAULT_FRAME_TYPE, DEFAULT_FRAME_LENGTH, DEFAULT_PHY_HEAD_LENGTH, DEFAULT_PHY_TAIL_LENGTH) != true) { return false; @@ -356,6 +363,7 @@ bool test_fhss_ws_check_tx_conditions_callback() fhss_common_stub.fhss_struct.own_hop = 2; fhss_common_stub.fhss_struct.ws->fhss_configuration.fhss_broadcast_interval = 1000; fhss_common_stub.fhss_struct.ws->fhss_configuration.fhss_bc_dwell_interval = 250; + fhss_common_stub.fhss_struct.ws->txrx_slot_length_ms = 125; fhss_platform_stub.remaining_slots_value = 700000; if (fhss_common_stub.fhss_struct.fhss_api->check_tx_conditions(api, DEFAULT_IS_BC_DEST, DEFAULT_HANDLE, DEFAULT_FRAME_TYPE, DEFAULT_FRAME_LENGTH, DEFAULT_PHY_HEAD_LENGTH, DEFAULT_PHY_TAIL_LENGTH) != true) { return false; @@ -398,6 +406,7 @@ bool test_fhss_ws_data_tx_done_callback() bool test_fhss_ws_data_tx_fail_callback() { fhss_api_t *api = test_generate_fhss_api(); + fhss_common_stub.fhss_struct.ws->fhss_configuration.config_parameters.number_of_channel_retries = 4; // Test when FHSS struct not found disable_fhss_struct(); if (fhss_common_stub.fhss_struct.fhss_api->data_tx_fail(api, DEFAULT_HANDLE, DEFAULT_FRAME_TYPE, DEFAULT_BAD_CHANNEL) != false) { @@ -457,6 +466,7 @@ bool test_fhss_ws_write_synch_info_callback() fhss_api_t *api = test_generate_fhss_api(); fhss_common_stub.fhss_struct.ws->fhss_configuration.ws_uc_channel_function = WS_TR51CF; fhss_common_stub.fhss_struct.rx_channel = 0; + fhss_common_stub.fhss_struct.ws->unicast_timer_running = true; uint8_t synch_info[100] = {0x05, 0x15, 0x02, 0x00, 0x00, 0x00, 0x00, 0x05, 0x15, 0x01, 0x04, 0x00, 0x00, 0x00, 0x00, 0x3f}; // Test when FHSS struct not found disable_fhss_struct(); @@ -556,12 +566,13 @@ bool test_fhss_ws_get_retry_period_callback() // Test when own hop not set fhss_common_stub.fhss_struct.ws->is_on_bc_channel = false; fhss_common_stub.fhss_struct.own_hop = 0xff; - if (fhss_common_stub.fhss_struct.fhss_api->get_retry_period(api, NULL, 0) != 0) { + if (fhss_common_stub.fhss_struct.fhss_api->get_retry_period(api, NULL, 0) != 100000) { return false; } // Test when on broadcast channel fhss_common_stub.fhss_struct.ws->is_on_bc_channel = true; fhss_common_stub.fhss_struct.own_hop = 1; + fhss_common_stub.fhss_struct.ws->broadcast_timer_running = true; if (fhss_common_stub.fhss_struct.fhss_api->get_retry_period(api, NULL, 0) != 0) { return false; } @@ -655,7 +666,7 @@ bool test_fhss_ws_update_uc_channel_callback() // We do not want to start broadcast timer fhss_common_stub.fhss_struct.ws->fhss_configuration.fhss_bc_dwell_interval = 0; fhss_common_stub.fhss_struct.ws->fhss_configuration.fhss_broadcast_interval = 0; - fhss_common_stub.fhss_struct.ws->uc_slot = fhss_common_stub.fhss_struct.number_of_channels - 1; + fhss_common_stub.fhss_struct.ws->uc_slot = fhss_common_stub.fhss_struct.number_of_uc_channels - 1; // Test fixed channel enable_fhss_struct(); From 51bf94e77f558d81b9a7ea1c666ab1967ce06cd7 Mon Sep 17 00:00:00 2001 From: Jarkko Paso Date: Thu, 13 Aug 2020 12:20:29 +0300 Subject: [PATCH 23/30] Fix adaptation interface unit tests (#2409) --- .../6LoWPAN/adaptation_interface/test_adaptation_interface.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/nanostack/unittest/6LoWPAN/adaptation_interface/test_adaptation_interface.c b/test/nanostack/unittest/6LoWPAN/adaptation_interface/test_adaptation_interface.c index be79eed09f71..8d17a9fa092a 100644 --- a/test/nanostack/unittest/6LoWPAN/adaptation_interface/test_adaptation_interface.c +++ b/test/nanostack/unittest/6LoWPAN/adaptation_interface/test_adaptation_interface.c @@ -607,6 +607,7 @@ bool test_lowpan_adaptation_interface_indirect_tx() entry.mac_api = &api; api.mcps_data_req = NULL; + api.phyMTU = 127; socket_stub.buffer_ptr = NULL; entry.id = 0; @@ -1316,6 +1317,7 @@ bool test_lowpan_adaptation_interface_mpx_register() entry.id = 0; api.mcps_data_req = &mcps_data_req_cb; + api.phyMTU = 127; test_buf2->ip_routed_up = true; protocol_core_stub.entry_ptr = &entry; From 8f1f9d5f4625596b6ad51661690c971593161044 Mon Sep 17 00:00:00 2001 From: Juha Heiskanen Date: Tue, 11 Aug 2020 15:40:13 +0300 Subject: [PATCH 24/30] EDFE error handling update Added EDFE data wait timeout and functionality skip data packet send for testing data wait timeout. Added spossibility to test EDFE sender re-send logic. EDFE is not ccaepted for brodcast traffic. --- nanostack/mlme.h | 1 + nanostack/net_ws_test.h | 26 ++++++ source/6LoWPAN/ws/ws_common.c | 5 ++ source/6LoWPAN/ws/ws_llc.h | 2 + source/6LoWPAN/ws/ws_llc_data_service.c | 80 ++++++++++++++++++- source/MAC/IEEE802_15_4/mac_mcps_sap.c | 23 +++++- source/MAC/IEEE802_15_4/mac_mlme.c | 4 + source/MAC/IEEE802_15_4/mac_pd_sap.c | 11 +++ source/MAC/IEEE802_15_4/mac_pd_sap.h | 2 + .../nanostack/unittest/stub/mac_pd_sap_stub.c | 5 ++ 10 files changed, 156 insertions(+), 3 deletions(-) diff --git a/nanostack/mlme.h b/nanostack/mlme.h index 3a4e02d57949..ee6a244172fd 100644 --- a/nanostack/mlme.h +++ b/nanostack/mlme.h @@ -264,6 +264,7 @@ typedef enum { macAutoRequestKeyIndex = 0x7b, /* #include #include "Common_Protocols/icmpv6.h" +#include "mac_common_defines.h" +#include "net_interface.h" +#include "6LoWPAN/MAC/mpx_api.h" #include "6LoWPAN/ws/ws_config.h" #include "6LoWPAN/ws/ws_common_defines.h" +#include "6LoWPAN/ws/ws_llc.h" #include "6LoWPAN/ws/ws_common.h" #include "6LoWPAN/ws/ws_bootstrap.h" #include "6LoWPAN/ws/ws_bbr_api_internal.h" @@ -349,6 +353,7 @@ void ws_common_fast_timer(protocol_interface_info_entry_t *cur, uint16_t ticks) { ws_bootstrap_trickle_timer(cur, ticks); ws_nud_active_timer(cur, ticks); + ws_llc_fast_timer(cur, ticks); } diff --git a/source/6LoWPAN/ws/ws_llc.h b/source/6LoWPAN/ws/ws_llc.h index fd3b01050144..e7df162ae495 100644 --- a/source/6LoWPAN/ws/ws_llc.h +++ b/source/6LoWPAN/ws/ws_llc.h @@ -226,6 +226,8 @@ void ws_llc_hopping_schedule_config(struct protocol_interface_info_entry *interf void ws_llc_timer_seconds(struct protocol_interface_info_entry *interface, uint16_t seconds_update); +void ws_llc_fast_timer(struct protocol_interface_info_entry *interface, uint16_t ticks); + 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); diff --git a/source/6LoWPAN/ws/ws_llc_data_service.c b/source/6LoWPAN/ws/ws_llc_data_service.c index 89b48c4202d4..c9ffe9c1d409 100644 --- a/source/6LoWPAN/ws/ws_llc_data_service.c +++ b/source/6LoWPAN/ws/ws_llc_data_service.c @@ -119,7 +119,9 @@ typedef struct { typedef struct { uint8_t mac_handle_base; /**< Mac handle id base this will be updated by 1 after use */ uint8_t llc_message_list_size; /**< llc_message_list list size */ + uint16_t edfe_rx_wait_timer; mpx_class_t mpx_data_base; /**< MPX data be including USER API Class and user call backs */ + llc_message_list_t llc_message_list; /**< Active Message list */ llc_ie_params_t ie_params; /**< LLC IE header and Payload data configuration */ temp_entriest_t *temp_entries; @@ -171,6 +173,30 @@ static ws_neighbor_temp_class_t *ws_allocate_eapol_temp_entry(temp_entriest_t *b static void ws_llc_mpx_eapol_send(llc_data_base_t *base, llc_message_t *message); +static bool test_skip_first_init_response = false; +static uint8_t test_drop_data_message = 0; + + +int8_t ws_test_skip_edfe_data_send(int8_t interface_id, bool skip) +{ + protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(interface_id); + if (!cur || !ws_info(cur)) { + return -1; + } + test_skip_first_init_response = skip; + return 0; +} + +int8_t ws_test_drop_edfe_data_frames(int8_t interface_id, uint8_t number_of_dropped_frames) +{ + protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(interface_id); + if (!cur || !ws_info(cur)) { + return -1; + } + test_drop_data_message = number_of_dropped_frames; + return 0; +} + /** Discover Message by message handle id */ static llc_message_t *llc_message_discover_by_mac_handle(uint8_t handle, llc_message_list_t *list) { @@ -949,7 +975,7 @@ static void ws_llc_lowpan_mpx_data_request(llc_data_base_t *base, mpx_user_t *us nested_wp_id.vp_ie = true; } - if (data->ExtendedFrameExchange) { + if (data->ExtendedFrameExchange && data->TxAckReq) { ie_header_mask.fc_ie = true; } if (!data->TxAckReq) { @@ -996,11 +1022,12 @@ static void ws_llc_lowpan_mpx_data_request(llc_data_base_t *base, mpx_user_t *us data_req.msduLength = 0; data_req.msduHandle = message->msg_handle; - if (data->ExtendedFrameExchange) { + if (data->ExtendedFrameExchange && data->TxAckReq) { data_req.SeqNumSuppressed = true; data_req.PanIdSuppressed = true; data_req.TxAckReq = true; // This will be changed inside MAC } else { + data_req.ExtendedFrameExchange = false; //Do not accept EDFE for non unicast traffic if (!data->TxAckReq) { data_req.PanIdSuppressed = false; data_req.DstAddrMode = MAC_ADDR_MODE_NONE; @@ -1500,20 +1527,36 @@ static void ws_llc_mcps_edfe_handler(const mac_api_t *api, mcps_edfe_response_t if (!message) { //tr_debug("FC:Send a Final Frame"); + if (test_drop_data_message) { + test_drop_data_message--; + base->edfe_rx_wait_timer += 99; + response_message->edfe_message_status = MCPS_EDFE_MALFORMED_FRAME; + return; + } fc_ie.rx_flow_ctrl = 0; + base->edfe_rx_wait_timer = 0; ws_llc_build_edfe_response(base, response_message, fc_ie); response_message->edfe_message_status = MCPS_EDFE_FINAL_FRAME_TX; } else { + if (test_skip_first_init_response) { + //Skip data send and test timeout at Slave side + test_skip_first_init_response = false; + response_message->edfe_message_status = MCPS_EDFE_FINAL_FRAME_RX; + return; + } ws_llc_build_edfe_frame(message, response_message, fc_ie); } } else if (fc_ie.tx_flow_ctrl == 0 && fc_ie.rx_flow_ctrl == 0) { //tr_debug("FC:Received a Final Frame"); + base->edfe_rx_wait_timer = 0; response_message->edfe_message_status = MCPS_EDFE_FINAL_FRAME_RX; } else if (fc_ie.tx_flow_ctrl && fc_ie.rx_flow_ctrl) { + base->edfe_rx_wait_timer = fc_ie.tx_flow_ctrl + 99; fc_ie.tx_flow_ctrl = 0; fc_ie.rx_flow_ctrl = 255; //tr_debug("FC:Send a response"); + //Enable or refesh timeout timer ws_llc_build_edfe_response(base, response_message, fc_ie); response_message->edfe_message_status = MCPS_EDFE_RESPONSE_FRAME; } @@ -1771,6 +1814,39 @@ void ws_llc_hopping_schedule_config(struct protocol_interface_info_entry *interf base->ie_params.hopping_schedule = hopping_schedule; } +void ws_llc_fast_timer(struct protocol_interface_info_entry *interface, uint16_t ticks) +{ + llc_data_base_t *base = ws_llc_discover_by_interface(interface); + if (!base || !base->edfe_rx_wait_timer) { + return; + } + + if (ticks > 0xffff / 100) { + ticks = 0xffff; + } else if (ticks == 0) { + ticks = 1; + } else { + ticks *= 100; + } + + if (base->edfe_rx_wait_timer > ticks) { + base->edfe_rx_wait_timer -= ticks; + } else { + base->edfe_rx_wait_timer = 0; + tr_debug("EDFE Data Wait Timeout"); + //MAC edfe wait data timeout + if (interface->mac_api && interface->mac_api->mlme_req) { + mlme_set_t set_req; + uint8_t value = 0; + set_req.attr = macEdfeForceStop; + set_req.attr_index = 0; + set_req.value_pointer = &value; + set_req.value_size = 1; + interface->mac_api->mlme_req(interface->mac_api, MLME_SET, &set_req); + } + } +} + 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); diff --git a/source/MAC/IEEE802_15_4/mac_mcps_sap.c b/source/MAC/IEEE802_15_4/mac_mcps_sap.c index 8ae296fac741..086de4503474 100644 --- a/source/MAC/IEEE802_15_4/mac_mcps_sap.c +++ b/source/MAC/IEEE802_15_4/mac_mcps_sap.c @@ -1474,6 +1474,22 @@ static void mac_data_interface_internal_tx_confirm_handle(protocol_interface_rf_ } +static bool mcps_buffer_edfe_data_failure(protocol_interface_rf_mac_setup_s *rf_ptr, mac_pre_build_frame_t *buffer) +{ + if (!rf_ptr->mac_edfe_enabled || !buffer->ExtendedFrameExchange) { + return false; + } + + if (rf_ptr->mac_edfe_info->state > MAC_EDFE_FRAME_CONNECTING) { + //Set to idle + tr_debug("Edfe Data send fail"); + return true; + } + + return false; +} + + static void mcps_data_confirm_handle(protocol_interface_rf_mac_setup_s *rf_ptr, mac_pre_build_frame_t *buffer, mac_pre_parsed_frame_t *ack_buf) { @@ -1482,7 +1498,7 @@ static void mcps_data_confirm_handle(protocol_interface_rf_mac_setup_s *rf_ptr, mcps_data_conf_t confirm; if (rf_ptr->fhss_api && !buffer->asynch_request) { // FHSS checks if this failed buffer needs to be pushed back to TX queue and retransmitted - if ((rf_ptr->mac_tx_result == MAC_TX_FAIL) || (rf_ptr->mac_tx_result == MAC_CCA_FAIL)) { + if (!mcps_buffer_edfe_data_failure(rf_ptr, buffer) && ((rf_ptr->mac_tx_result == MAC_TX_FAIL) || (rf_ptr->mac_tx_result == MAC_CCA_FAIL))) { if (rf_ptr->fhss_api->data_tx_fail(rf_ptr->fhss_api, buffer->msduHandle, mac_convert_frame_type_to_fhss(buffer->fcf_dsn.frametype), rf_ptr->mac_tx_start_channel) == true) { if (rf_ptr->mac_tx_result == MAC_TX_FAIL) { @@ -1495,6 +1511,11 @@ static void mcps_data_confirm_handle(protocol_interface_rf_mac_setup_s *rf_ptr, return; } } + + if (rf_ptr->mac_edfe_enabled && buffer->ExtendedFrameExchange) { + rf_ptr->mac_edfe_info->state = MAC_EDFE_FRAME_IDLE; + } + } confirm.cca_retries = rf_ptr->mac_tx_status.cca_cnt + buffer->fhss_cca_retry_count; confirm.tx_retries = rf_ptr->mac_tx_status.retry + buffer->fhss_retry_count; diff --git a/source/MAC/IEEE802_15_4/mac_mlme.c b/source/MAC/IEEE802_15_4/mac_mlme.c index c49178e2a3ef..d8db1d60f668 100644 --- a/source/MAC/IEEE802_15_4/mac_mlme.c +++ b/source/MAC/IEEE802_15_4/mac_mlme.c @@ -512,6 +512,10 @@ static int8_t mac_mlme_boolean_set(protocol_interface_rf_mac_setup_s *rf_mac_set rf_mac_setup->dev_driver->phy_driver->extension(PHY_EXTENSION_ACCEPT_ANY_BEACON, (uint8_t *)&value); } break; + + case macEdfeForceStop: + return mac_data_edfe_force_stop(rf_mac_setup); + case macAcceptByPassUnknowDevice: rf_mac_setup->mac_security_bypass_unknow_device = value; break; diff --git a/source/MAC/IEEE802_15_4/mac_pd_sap.c b/source/MAC/IEEE802_15_4/mac_pd_sap.c index cee933428af6..54669e879451 100644 --- a/source/MAC/IEEE802_15_4/mac_pd_sap.c +++ b/source/MAC/IEEE802_15_4/mac_pd_sap.c @@ -432,6 +432,17 @@ static void mac_data_ack_tx_finish(protocol_interface_rf_mac_setup_s *rf_ptr) } } +int8_t mac_data_edfe_force_stop(protocol_interface_rf_mac_setup_s *rf_ptr) +{ + if (!rf_ptr->mac_edfe_enabled || rf_ptr->mac_edfe_info->state != MAC_EDFE_FRAME_WAIT_DATA) { + return -1; + } + //Set to idle + rf_ptr->mac_edfe_info->state = MAC_EDFE_FRAME_IDLE; + mac_data_ack_tx_finish(rf_ptr); + return 0; +} + 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) { diff --git a/source/MAC/IEEE802_15_4/mac_pd_sap.h b/source/MAC/IEEE802_15_4/mac_pd_sap.h index 9e524ebd101f..fdde95acac06 100644 --- a/source/MAC/IEEE802_15_4/mac_pd_sap.h +++ b/source/MAC/IEEE802_15_4/mac_pd_sap.h @@ -59,4 +59,6 @@ void mac_csma_backoff_start(struct protocol_interface_rf_mac_setup *rf_mac_setup */ void mac_pd_sap_state_machine(struct protocol_interface_rf_mac_setup *rf_mac_setup); +int8_t mac_data_edfe_force_stop(struct protocol_interface_rf_mac_setup *rf_ptr); + #endif /* MAC_PD_SAP_H_ */ diff --git a/test/nanostack/unittest/stub/mac_pd_sap_stub.c b/test/nanostack/unittest/stub/mac_pd_sap_stub.c index 2c27fa77da79..01d1be26a2d2 100644 --- a/test/nanostack/unittest/stub/mac_pd_sap_stub.c +++ b/test/nanostack/unittest/stub/mac_pd_sap_stub.c @@ -82,3 +82,8 @@ void mac_csma_backoff_start(protocol_interface_rf_mac_setup_s *rf_mac_setup) { } + +int8_t mac_data_edfe_force_stop(struct protocol_interface_rf_mac_setup *rf_ptr) +{ + return 0; +} From f827ffc364b828c3bffaa4a86844aa1bda253a57 Mon Sep 17 00:00:00 2001 From: Mika Date: Thu, 13 Aug 2020 15:34:07 +0300 Subject: [PATCH 25/30] Added information API to Wi-SUN and border router Added Gateway to Border router info Added new information API to Wi-SUN interface --- nanostack/ws_bbr_api.h | 2 + nanostack/ws_management_api.h | 32 +++++++++ .../Bootstraps/Generic/protocol_6lowpan.c | 5 +- source/6LoWPAN/ws/ws_bbr_api.c | 5 ++ source/6LoWPAN/ws/ws_bootstrap.c | 69 +++++++++++++++---- source/6LoWPAN/ws/ws_bootstrap.h | 12 ++-- source/6LoWPAN/ws/ws_common.c | 10 +++ source/6LoWPAN/ws/ws_common.h | 7 ++ source/6LoWPAN/ws/ws_empty_functions.c | 7 ++ source/6LoWPAN/ws/ws_management_api.c | 10 +++ source/Core/include/ns_address_internal.h | 1 + source/Core/ns_address_internal.c | 1 + .../unittest/stub/ws_bootstrap_stub.c | 8 ++- test/nanostack/unittest/stub/ws_common_stub.c | 8 +++ 14 files changed, 155 insertions(+), 22 deletions(-) diff --git a/nanostack/ws_bbr_api.h b/nanostack/ws_bbr_api.h index e92a3ca3ee41..f22e513a0e31 100644 --- a/nanostack/ws_bbr_api.h +++ b/nanostack/ws_bbr_api.h @@ -36,6 +36,8 @@ typedef struct bbr_information { /** Timestamp of the the device. Can be used as version number*/ uint64_t timestamp; + /** Default route Link Local address of north bound router*/ + uint8_t gateway[16]; /** Border router dodag id */ uint8_t dodag_id[16]; /** Address prefix given to devices in network set to 0 if not available*/ diff --git a/nanostack/ws_management_api.h b/nanostack/ws_management_api.h index 37e66999ab71..8d155595cdbc 100644 --- a/nanostack/ws_management_api.h +++ b/nanostack/ws_management_api.h @@ -102,6 +102,24 @@ typedef struct ws_statistics { uint32_t asynch_rx_count; } ws_statistics_t; +/** + * \brief Struct ws_info defines the Wi-SUN stack state. + */ +typedef struct ws_stack_info { + /** Parent link local address */ + uint8_t parent[16]; + /** parent RSSI Out measured RSSI value calculated using EWMA specified by Wi-SUN from range of -174 (0) to +80 (254) dBm.*/ + uint8_t rsl_out; + /** parent RSSI in measured RSSI value calculated using EWMA specified by Wi-SUN from range of -174 (0) to +80 (254) dBm.*/ + uint8_t rsl_in; + /** ETX To border router */ + uint16_t routing_cost; + /** Network PAN ID */ + uint16_t pan_id; + /** Wi-SUN join state defined by Wi-SUN specification 1-5*/ + uint8_t join_state; +} ws_stack_info_t; + /** * Initialize Wi-SUN stack. * @@ -582,6 +600,20 @@ int ws_statistics_start( int ws_statistics_stop( int8_t interface_id); +/** + * Get information from the stack state. + * Parent information and link qualities with stack state info + * + * \param interface_id Network interface ID. + * \param info_ptr Pointer to stored stack state. + * + * \return 0 Success. + * \return <0 Failure. + */ +int ws_stack_info_get( + int8_t interface_id, + ws_stack_info_t *info_ptr); + #ifdef __cplusplus } #endif diff --git a/source/6LoWPAN/Bootstraps/Generic/protocol_6lowpan.c b/source/6LoWPAN/Bootstraps/Generic/protocol_6lowpan.c index b89117b7c796..b5043e41a742 100644 --- a/source/6LoWPAN/Bootstraps/Generic/protocol_6lowpan.c +++ b/source/6LoWPAN/Bootstraps/Generic/protocol_6lowpan.c @@ -75,7 +75,6 @@ #include "Service_Libs/etx/etx.h" #include "Service_Libs/mac_neighbor_table/mac_neighbor_table.h" #include "6LoWPAN/ws/ws_common.h" -#include "6LoWPAN/ws/ws_bootstrap.h" #ifdef HAVE_WS #include "6LoWPAN/ws/ws_cfg_settings.h" #endif @@ -517,7 +516,7 @@ uint16_t protocol_6lowpan_neighbor_priority_set(int8_t interface_id, addrtype_t } if (new_primary) { - ws_primary_parent_update(cur, entry); + ws_common_primary_parent_update(cur, entry); } return 1; } else { @@ -550,7 +549,7 @@ uint16_t protocol_6lowpan_neighbor_second_priority_set(int8_t interface_id, addr protocol_stats_update(STATS_ETX_2ND_PARENT, etx_entry->etx >> 4); } if (new_secondary) { - ws_secondary_parent_update(cur); + ws_common_secondary_parent_update(cur); } return 1; } else { diff --git a/source/6LoWPAN/ws/ws_bbr_api.c b/source/6LoWPAN/ws/ws_bbr_api.c index 36732a42e9be..ce7a8cf90756 100644 --- a/source/6LoWPAN/ws/ws_bbr_api.c +++ b/source/6LoWPAN/ws/ws_bbr_api.c @@ -807,6 +807,11 @@ int ws_bbr_info_get(int8_t interface_id, bbr_information_t *info_ptr) memcpy(info_ptr->IID, wisun_if_addr + 8, 8); } + ipv6_route_t *next_hop = ipv6_route_choose_next_hop(ADDR_6TO4, backbone_interface_id, NULL); + if (next_hop) { + memcpy(info_ptr->gateway, next_hop->info.next_hop_addr, 16); + } + info_ptr->devices_in_network = ws_bbr_pan_size(cur); info_ptr->instance_id = current_instance_id; info_ptr->version = dodag_info.version_num; diff --git a/source/6LoWPAN/ws/ws_bootstrap.c b/source/6LoWPAN/ws/ws_bootstrap.c index 8cfa16746bb4..3065a6a22b7f 100644 --- a/source/6LoWPAN/ws/ws_bootstrap.c +++ b/source/6LoWPAN/ws/ws_bootstrap.c @@ -3304,33 +3304,32 @@ void ws_bootstrap_rpl_wait_process(protocol_interface_info_entry_t *cur) return; } -/* - -static bool ws_bootstrap_state_configure(struct protocol_interface_info_entry *cur) +static bool ws_bootstrap_state_discovery(struct protocol_interface_info_entry *cur) { - // Think about the state value - if (cur->nwk_bootstrap_state == ER_SCAN) { + if (cur->nwk_bootstrap_state == ER_ACTIVE_SCAN) { return true; } return false; } -*/ -static bool ws_bootstrap_state_discovery(struct protocol_interface_info_entry *cur) +static bool ws_bootstrap_state_authenticate(struct protocol_interface_info_entry *cur) { - if (cur->nwk_bootstrap_state == ER_ACTIVE_SCAN) { + // Think about the state value + if (cur->nwk_bootstrap_state == ER_PANA_AUTH) { return true; } return false; } -static bool ws_bootstrap_state_active(struct protocol_interface_info_entry *cur) +static bool ws_bootstrap_state_configure(struct protocol_interface_info_entry *cur) { - if (cur->nwk_bootstrap_state == ER_BOOTSRAP_DONE) { + // Think about the state value + if (cur->nwk_bootstrap_state == ER_SCAN) { return true; } return false; } + static bool ws_bootstrap_state_wait_rpl(struct protocol_interface_info_entry *cur) { // Think about the state value @@ -3340,6 +3339,14 @@ static bool ws_bootstrap_state_wait_rpl(struct protocol_interface_info_entry *cu return false; } +static bool ws_bootstrap_state_active(struct protocol_interface_info_entry *cur) +{ + if (cur->nwk_bootstrap_state == ER_BOOTSRAP_DONE) { + return true; + } + return false; +} + static void ws_bootstrap_state_change(protocol_interface_info_entry_t *cur, icmp_state_t nwk_bootstrap_state) { cur->bootsrap_state_machine_cnt = 1; @@ -3486,7 +3493,7 @@ void ws_bootstrap_seconds_timer(protocol_interface_info_entry_t *cur, uint32_t s } -void ws_primary_parent_update(protocol_interface_info_entry_t *interface, mac_neighbor_table_entry_t *neighbor) +void ws_bootstrap_primary_parent_update(protocol_interface_info_entry_t *interface, mac_neighbor_table_entry_t *neighbor) { if (interface->ws_info) { llc_neighbour_req_t neighbor_info; @@ -3497,11 +3504,11 @@ void ws_primary_parent_update(protocol_interface_info_entry_t *interface, mac_ne ws_bootsrap_create_ll_address(link_local_address, neighbor->mac64); dhcp_client_server_address_update(interface->id, NULL, link_local_address); - ws_secondary_parent_update(interface); + ws_bootstrap_secondary_parent_update(interface); } } -void ws_secondary_parent_update(protocol_interface_info_entry_t *interface) +void ws_bootstrap_secondary_parent_update(protocol_interface_info_entry_t *interface) { if (interface->ws_info) { ns_list_foreach(if_address_entry_t, address, &interface->ip_addresses) { @@ -3512,4 +3519,40 @@ void ws_secondary_parent_update(protocol_interface_info_entry_t *interface) } } +int ws_bootstrap_get_info(protocol_interface_info_entry_t *cur, struct ws_stack_info *info_ptr) +{ + + ws_neighbor_class_entry_t *ws_neighbour = NULL; + + memset(info_ptr, 0, sizeof(struct ws_stack_info)); + mac_neighbor_table_entry_t *mac_parent = mac_neighbor_entry_get_priority(mac_neighbor_info(cur)); + + if (mac_parent) { + ws_neighbour = ws_neighbor_class_entry_get(&cur->ws_info->neighbor_storage, mac_parent->index); + + memcpy(info_ptr->parent, ADDR_LINK_LOCAL_PREFIX, 8); + memcpy(info_ptr->parent + 8, mac_parent->mac64, 8); + info_ptr->parent[8] ^= 2; + } + if (ws_neighbour) { + info_ptr->rsl_in = ws_neighbour->rsl_in; + info_ptr->rsl_out = ws_neighbour->rsl_out; + info_ptr->routing_cost = ws_neighbour->routing_cost; + } + if (ws_bootstrap_state_discovery(cur)) { + info_ptr->join_state = 1; + } else if (ws_bootstrap_state_authenticate(cur)) { + info_ptr->join_state = 2; + } else if (ws_bootstrap_state_configure(cur)) { + info_ptr->join_state = 3; + } else if (ws_bootstrap_state_wait_rpl(cur)) { + info_ptr->join_state = 4; + } else if (ws_bootstrap_state_active(cur)) { + info_ptr->join_state = 5; + } + info_ptr->pan_id = cur->ws_info->network_pan_id; + + return 0; +} + #endif //HAVE_WS diff --git a/source/6LoWPAN/ws/ws_bootstrap.h b/source/6LoWPAN/ws/ws_bootstrap.h index 1a85e8150d13..d936c23ce6a1 100644 --- a/source/6LoWPAN/ws/ws_bootstrap.h +++ b/source/6LoWPAN/ws/ws_bootstrap.h @@ -33,6 +33,7 @@ struct llc_neighbour_req; struct ws_us_ie; struct ws_bs_ie; struct ws_neighbor_class_entry; +struct ws_stack_info; int ws_bootstrap_init(int8_t interface_id, net_6lowpan_mode_e bootstrap_mode); @@ -65,9 +66,9 @@ void ws_bootstrap_seconds_timer(protocol_interface_info_entry_t *cur, uint32_t s void ws_bootstrap_trickle_timer(protocol_interface_info_entry_t *cur, uint16_t ticks); -void ws_primary_parent_update(protocol_interface_info_entry_t *interface, mac_neighbor_table_entry_t *neighbor); +void ws_bootstrap_primary_parent_update(protocol_interface_info_entry_t *interface, mac_neighbor_table_entry_t *neighbor); -void ws_secondary_parent_update(protocol_interface_info_entry_t *interface); +void ws_bootstrap_secondary_parent_update(protocol_interface_info_entry_t *interface); void ws_nud_entry_remove_active(protocol_interface_info_entry_t *cur, void *neighbor); @@ -91,6 +92,8 @@ struct ws_neighbor_class_entry *ws_bootstrap_eapol_tx_temporary_set(struct proto void ws_bootstrap_eapol_tx_temporary_clear(struct protocol_interface_info_entry *interface); +int ws_bootstrap_get_info(protocol_interface_info_entry_t *cur, struct ws_stack_info *info_ptr); + #else #define ws_bootstrap_init(interface_id, bootstrap_mode) (-1) @@ -98,8 +101,9 @@ void ws_bootstrap_eapol_tx_temporary_clear(struct protocol_interface_info_entry #define ws_bootstrap_restart(cur) #define ws_bootstrap_neighbor_remove(cur, ll_address) #define ws_bootstrap_aro_failure(cur, ll_address) -#define ws_primary_parent_update(interface, neighbor) -#define ws_secondary_parent_update(interface) +#define ws_bootstrap_primary_parent_update(interface, neighbor) +#define ws_bootstrap_secondary_parent_update(interface) +#define ws_bootstrap_get_info(cur, info_ptr) #endif //HAVE_WS diff --git a/source/6LoWPAN/ws/ws_common.c b/source/6LoWPAN/ws/ws_common.c index 95e41737035c..841ce15dab8a 100644 --- a/source/6LoWPAN/ws/ws_common.c +++ b/source/6LoWPAN/ws/ws_common.c @@ -479,4 +479,14 @@ uint32_t ws_common_network_size_estimate_get(protocol_interface_info_entry_t *cu return network_size_estimate; } +void ws_common_primary_parent_update(protocol_interface_info_entry_t *interface, mac_neighbor_table_entry_t *neighbor) +{ + ws_bootstrap_primary_parent_update(interface, neighbor); +} + +void ws_common_secondary_parent_update(protocol_interface_info_entry_t *interface) +{ + ws_bootstrap_secondary_parent_update(interface); +} + #endif // HAVE_WS diff --git a/source/6LoWPAN/ws/ws_common.h b/source/6LoWPAN/ws/ws_common.h index a3d1eae85f8d..4dadf81b3656 100644 --- a/source/6LoWPAN/ws/ws_common.h +++ b/source/6LoWPAN/ws/ws_common.h @@ -151,6 +151,10 @@ 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); +void ws_common_primary_parent_update(protocol_interface_info_entry_t *interface, mac_neighbor_table_entry_t *neighbor); + +void ws_common_secondary_parent_update(protocol_interface_info_entry_t *interface); + #define ws_info(cur) ((cur)->ws_info) #else #define ws_info(cur) ((ws_info_t *) NULL) @@ -164,6 +168,9 @@ uint32_t ws_common_network_size_estimate_get(protocol_interface_info_entry_t *cu #define ws_common_latency_estimate_get(cur) 0 #define ws_common_datarate_get(cur) 0 #define ws_common_network_size_estimate_get(cur) 0 +#define ws_common_primary_parent_update(interface, neighbor) +#define ws_common_secondary_parent_update(interface) + #endif //HAVE_WS #endif //WS_COMMON_H_ diff --git a/source/6LoWPAN/ws/ws_empty_functions.c b/source/6LoWPAN/ws/ws_empty_functions.c index 59c9a1650c9d..e6721655f9ac 100644 --- a/source/6LoWPAN/ws/ws_empty_functions.c +++ b/source/6LoWPAN/ws/ws_empty_functions.c @@ -406,4 +406,11 @@ void ns_time_api_system_time_callback_set(ns_time_api_system_time_callback callb (void) callback; } +int ws_state_info_get(int8_t interface_id, ws_stack_info_t *info_ptr) +{ + (void) interface_id; + (void) info_ptr; + return -1; +} + #endif // no HAVE_WS diff --git a/source/6LoWPAN/ws/ws_management_api.c b/source/6LoWPAN/ws/ws_management_api.c index ef9e9cffbd0f..a32464355820 100644 --- a/source/6LoWPAN/ws/ws_management_api.c +++ b/source/6LoWPAN/ws/ws_management_api.c @@ -731,4 +731,14 @@ int ws_management_timing_parameters_validate( return 0; } +int ws_stack_info_get(int8_t interface_id, ws_stack_info_t *info_ptr) +{ + protocol_interface_info_entry_t *cur; + cur = protocol_stack_interface_info_get_by_id(interface_id); + if (!cur || !ws_info(cur) || !info_ptr) { + return -1; + } + return ws_bootstrap_get_info(cur, info_ptr); +} + #endif // HAVE_WS diff --git a/source/Core/include/ns_address_internal.h b/source/Core/include/ns_address_internal.h index cce42c644788..79bf398b70f2 100644 --- a/source/Core/include/ns_address_internal.h +++ b/source/Core/include/ns_address_internal.h @@ -142,6 +142,7 @@ extern const uint8_t ADDR_ALL_MPL_FORWARDERS[16]; // ff03::fc extern const uint8_t ADDR_ALL_DHCP_RELAY_AGENTS_AND_SERVERS[16]; // ff02::1:2 extern const uint8_t ADDR_LOOPBACK[16]; // ::1 extern const uint8_t ADDR_UNSPECIFIED[16]; // :: +extern const uint8_t ADDR_6TO4[16]; // 2002:: /* Don't bother having another 8 zero bytes for this - reuse ADDR_UNSPECIFIED */ #define ADDR_EUI64_ZERO ADDR_UNSPECIFIED diff --git a/source/Core/ns_address_internal.c b/source/Core/ns_address_internal.c index ca998f361eb4..6131df7a01af 100644 --- a/source/Core/ns_address_internal.c +++ b/source/Core/ns_address_internal.c @@ -81,6 +81,7 @@ const uint8_t ADDR_ALL_DHCP_RELAY_AGENTS_AND_SERVERS[16] = { 0xff, 0x02, [13] = const uint8_t ADDR_IPV4_MAPPED_PREFIX[12] = { [10] = 0xff, 0xff }; const uint8_t ADDR_LOOPBACK[16] = { [15] = 1 }; const uint8_t ADDR_UNSPECIFIED[16] = { 0 }; /* Note a few bits of code check for pointer equality with ADDR_UNSPECIFIED */ +const uint8_t ADDR_6TO4[16] = { 0x20, 0x02 }; /*Can be used as global address*/ #define ADDR_IPV4_COMPATIBLE ADDR_LOOPBACK /* First 96 bits match...*/ #define ADDR_MULTICAST_LINK_PREFIX ADDR_LINK_LOCAL_ALL_NODES /* ff02::xx */ diff --git a/test/nanostack/unittest/stub/ws_bootstrap_stub.c b/test/nanostack/unittest/stub/ws_bootstrap_stub.c index 47bc15ee2721..ff46f04f5417 100644 --- a/test/nanostack/unittest/stub/ws_bootstrap_stub.c +++ b/test/nanostack/unittest/stub/ws_bootstrap_stub.c @@ -106,12 +106,12 @@ void ws_bootstrap_configuration_trickle_reset(protocol_interface_info_entry_t *c } -void ws_primary_parent_update(protocol_interface_info_entry_t *interface, mac_neighbor_table_entry_t *neighbor) +void ws_bootstrap_primary_parent_update(protocol_interface_info_entry_t *interface, mac_neighbor_table_entry_t *neighbor) { } -void ws_secondary_parent_update(protocol_interface_info_entry_t *interface) +void ws_bootstrap_secondary_parent_update(protocol_interface_info_entry_t *interface) { } @@ -149,3 +149,7 @@ void ws_bootstrap_eapol_tx_temporary_clear(struct protocol_interface_info_entry { } +int ws_bootstrap_get_info(protocol_interface_info_entry_t *cur, struct ws_stack_info *info_ptr) +{ +} + diff --git a/test/nanostack/unittest/stub/ws_common_stub.c b/test/nanostack/unittest/stub/ws_common_stub.c index e5cf8f5aa291..4c07b798cd8d 100644 --- a/test/nanostack/unittest/stub/ws_common_stub.c +++ b/test/nanostack/unittest/stub/ws_common_stub.c @@ -102,3 +102,11 @@ uint16_t ws_active_channel_count(uint32_t *channel_mask, uint16_t number_of_chan { return 35; } + +void ws_common_primary_parent_update(protocol_interface_info_entry_t *interface, mac_neighbor_table_entry_t *neighbor) +{ +} + +void ws_common_secondary_parent_update(protocol_interface_info_entry_t *interface) +{ +} From fc97980aa820db5db9216b2757206971c86200bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mika=20Lepp=C3=A4nen?= Date: Thu, 13 Aug 2020 17:37:34 +0300 Subject: [PATCH 26/30] Changed RADIUS shared secret length to 16-bit value Added also get interface for RADIUS server IPv6 address and shared secret. --- nanostack/ws_bbr_api.h | 43 ++++++++++++++++---- source/6LoWPAN/ws/ws_bbr_api.c | 25 +++++++++++- source/6LoWPAN/ws/ws_pae_controller.c | 50 ++++++++++++++++++++++-- source/6LoWPAN/ws/ws_pae_controller.h | 33 ++++++++++++++-- source/Security/protocols/sec_prot_cfg.h | 2 +- 5 files changed, 136 insertions(+), 17 deletions(-) diff --git a/nanostack/ws_bbr_api.h b/nanostack/ws_bbr_api.h index f22e513a0e31..760a22801535 100644 --- a/nanostack/ws_bbr_api.h +++ b/nanostack/ws_bbr_api.h @@ -322,7 +322,7 @@ int ws_bbr_pan_configuration_get(int8_t interface_id, uint16_t *pan_id); int ws_bbr_pan_configuration_validate(int8_t interface_id, uint16_t pan_id); /** - * ws_bbr_key_storage_memory_set sets memory used for key storages + * Sets memory used for key storages * * This functions can be used to set memory used by EAPOL key storage. When memory * areas are set, module does not allocate memory internally from heap. @@ -339,7 +339,7 @@ int ws_bbr_pan_configuration_validate(int8_t interface_id, uint16_t pan_id); 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 + * 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 @@ -358,7 +358,7 @@ int ws_bbr_key_storage_memory_set(int8_t interface_id, uint8_t key_storages_numb int ws_bbr_key_storage_settings_set(int8_t interface_id, uint8_t alloc_max_number, uint16_t alloc_size, uint16_t storing_interval); /** - * ws_bbr_radius_address_set Set RADIUS server IPv6 address + * Set RADIUS server IPv6 address * * Function sets external RADIUS server IPv6 address to Border Router. Setting the * address enables external RADIUS server interface on Border Router. To disable external @@ -376,20 +376,49 @@ int ws_bbr_key_storage_settings_set(int8_t interface_id, uint8_t alloc_max_numbe int ws_bbr_radius_address_set(int8_t interface_id, const uint8_t *address); /** - * ws_bbr_radius_shared_secret_set set RADIUS shared secret + * Get RADIUS server IPv6 address * - * Function sets RADIUS shared secret to Border Router. Shared secret is usually an + * Function gets external RADIUS server IPv6 address to Border Router. + * + * \param interface_id Network interface ID. + * \param address buffer where to write address, must have space at least for 39 characters and NUL terminator + * + * \return < 0 failure + * \return >= 0 success + * + */ +int ws_bbr_radius_address_get(int8_t interface_id, uint8_t *address); + +/** + * Set RADIUS shared secret + * + * Function sets RADIUS shared secret to Border Router. Shared secret may be an * ASCII string. Check the format and length constraints for the shared secret from * the documentation of RADIUS server you are connecting to. * * \param interface_id Network interface ID. - * \param shared_secret_len The length of the shared secret in bytes. Maximum length is 255 bytes. + * \param shared_secret_len The length of the shared secret in bytes. * \param shared_secret Pointer to shared secret. Can be 8-bit ASCII string or byte array. Is not NUL terminated. * * \return < 0 failure * \return >= 0 success * */ -int ws_bbr_radius_shared_secret_set(int8_t interface_id, const uint8_t shared_secret_len, const uint8_t *shared_secret); +int ws_bbr_radius_shared_secret_set(int8_t interface_id, const uint16_t shared_secret_len, const uint8_t *shared_secret); + +/** + * Get RADIUS shared secret + * + * Function gets RADIUS shared secret to Border Router. + * + * \param interface_id Network interface ID. + * \param shared_secret_len On function call, is the size of the shared secret write buffer in bytes, on return is the shared secret length in bytes. + * \param shared_secret Pointer to buffer where to write shared secret or NULL. At maximum, bytes set by the length parameter are written. If NULL only buffer length is returned. + * + * \return < 0 failure + * \return >= 0 success + * + */ +int ws_bbr_radius_shared_secret_get(int8_t interface_id, uint16_t *shared_secret_len, uint8_t *shared_secret); #endif /* WS_BBR_API_H_ */ diff --git a/source/6LoWPAN/ws/ws_bbr_api.c b/source/6LoWPAN/ws/ws_bbr_api.c index ce7a8cf90756..878c431f512e 100644 --- a/source/6LoWPAN/ws/ws_bbr_api.c +++ b/source/6LoWPAN/ws/ws_bbr_api.c @@ -1103,7 +1103,18 @@ int ws_bbr_radius_address_set(int8_t interface_id, const uint8_t *address) #endif } -int ws_bbr_radius_shared_secret_set(int8_t interface_id, const uint8_t shared_secret_len, const uint8_t *shared_secret) +int ws_bbr_radius_address_get(int8_t interface_id, uint8_t *address) +{ +#ifdef HAVE_WS_BORDER_ROUTER + return ws_pae_controller_radius_address_get(interface_id, address); +#else + (void) interface_id; + (void) address; + return -1; +#endif +} + +int ws_bbr_radius_shared_secret_set(int8_t interface_id, const uint16_t shared_secret_len, const uint8_t *shared_secret) { #ifdef HAVE_WS_BORDER_ROUTER return ws_pae_controller_radius_shared_secret_set(interface_id, shared_secret_len, shared_secret); @@ -1114,3 +1125,15 @@ int ws_bbr_radius_shared_secret_set(int8_t interface_id, const uint8_t shared_se return -1; #endif } + +int ws_bbr_radius_shared_secret_get(int8_t interface_id, uint16_t *shared_secret_len, uint8_t *shared_secret) +{ +#ifdef HAVE_WS_BORDER_ROUTER + return ws_pae_controller_radius_shared_secret_get(interface_id, shared_secret_len, shared_secret); +#else + (void) interface_id; + (void) shared_secret_len; + (void) shared_secret; + return -1; +#endif +} diff --git a/source/6LoWPAN/ws/ws_pae_controller.c b/source/6LoWPAN/ws/ws_pae_controller.c index 6511e7fcb9b8..80b72e5231c2 100644 --- a/source/6LoWPAN/ws/ws_pae_controller.c +++ b/source/6LoWPAN/ws/ws_pae_controller.c @@ -1171,12 +1171,12 @@ int8_t ws_pae_controller_certificate_revocation_list_remove(const arm_cert_revoc return ret; } -int8_t ws_pae_controller_radius_address_set(int8_t interface_id, const uint8_t *remote_addr) +int8_t ws_pae_controller_radius_address_set(int8_t interface_id, const uint8_t *address) { pae_controller_t *controller = ws_pae_controller_get_or_create(interface_id); // If remote address is not set, clear radius information - if (!remote_addr) { + if (!address) { if (pae_controller_radius_settings != NULL) { pae_controller_radius_settings->radius_addr_set = false; } @@ -1193,7 +1193,7 @@ int8_t ws_pae_controller_radius_address_set(int8_t interface_id, const uint8_t * } memset(pae_controller_radius_settings, 0, sizeof(sec_radius_cfg_t)); } - memcpy(pae_controller_radius_settings->radius_addr, remote_addr, 16); + memcpy(pae_controller_radius_settings->radius_addr, address, 16); pae_controller_radius_settings->radius_addr_set = true; if (controller) { @@ -1206,7 +1206,23 @@ int8_t ws_pae_controller_radius_address_set(int8_t interface_id, const uint8_t * return 0; } -int8_t ws_pae_controller_radius_shared_secret_set(int8_t interface_id, const uint8_t shared_secret_len, const uint8_t *shared_secret) +int8_t ws_pae_controller_radius_address_get(int8_t interface_id, uint8_t *address) +{ + (void) interface_id; + + if (address == NULL) { + return -1; + } + + if (pae_controller_radius_settings == NULL || !pae_controller_radius_settings->radius_addr_set) { + return -1; + } + + memcpy(address, pae_controller_radius_settings->radius_addr, 16); + return 0; +} + +int8_t ws_pae_controller_radius_shared_secret_set(int8_t interface_id, const uint16_t shared_secret_len, const uint8_t *shared_secret) { pae_controller_t *controller = ws_pae_controller_get_or_create(interface_id); @@ -1253,6 +1269,32 @@ int8_t ws_pae_controller_radius_shared_secret_set(int8_t interface_id, const uin return 0; } +int8_t ws_pae_controller_radius_shared_secret_get(int8_t interface_id, uint16_t *shared_secret_len, uint8_t *shared_secret) +{ + (void) interface_id; + + if (shared_secret_len == NULL) { + return -1; + } + + uint16_t length = 0; + if (pae_controller_radius_settings != NULL) { + length = pae_controller_radius_settings->radius_shared_secret_len; + if (shared_secret != NULL) { + if (length > *shared_secret_len) { + length = *shared_secret_len; + } + if (length > 0 && pae_controller_radius_settings->radius_shared_secret != NULL) { + memcpy(shared_secret, pae_controller_radius_settings->radius_shared_secret, length); + } + } + } + + *shared_secret_len = length; + + return 0; +} + int8_t ws_pae_controller_border_router_addr_write(protocol_interface_info_entry_t *interface_ptr, const uint8_t *eui_64) { if (!eui_64) { diff --git a/source/6LoWPAN/ws/ws_pae_controller.h b/source/6LoWPAN/ws/ws_pae_controller.h index 96b14f1f896f..93c3abdd34e1 100644 --- a/source/6LoWPAN/ws/ws_pae_controller.h +++ b/source/6LoWPAN/ws/ws_pae_controller.h @@ -236,26 +236,51 @@ int8_t ws_pae_controller_certificate_revocation_list_remove(const arm_cert_revoc * ws_pae_controller_radius_address_set set radius address * * \param interface_id interface identifier - * \param remote_addr remote address + * \param address address + * + * \return < 0 failure + * \return >= 0 success + * + */ +int8_t ws_pae_controller_radius_address_set(int8_t interface_id, const uint8_t *address); + +/** + * ws_pae_controller_radius_address_set get radius address + * + * \param interface_id interface identifier + * \param address address buffer where to write address, must have space at least for 39 characters and NUL terminator * * \return < 0 failure * \return >= 0 success * */ -int8_t ws_pae_controller_radius_address_set(int8_t interface_id, const uint8_t *remote_addr); +int8_t ws_pae_controller_radius_address_get(int8_t interface_id, uint8_t *address); /** * ws_pae_controller_radius_shared_secret_set set radius shared secret * * \param interface_id interface identifier - * \param shared_secret_len shared secret + * \param shared_secret_len shared secret length + * \param shared_secret shared secret + * + * \return < 0 failure + * \return >= 0 success + * + */ +int8_t ws_pae_controller_radius_shared_secret_set(int8_t interface_id, const uint16_t shared_secret_len, const uint8_t *shared_secret); + +/** + * ws_pae_controller_radius_shared_secret_get get radius shared secret + * + * \param interface_id interface identifier + * \param shared_secret_len On call, shared secret buffer length, on return shared secret length * \param shared_secret shared secret * * \return < 0 failure * \return >= 0 success * */ -int8_t ws_pae_controller_radius_shared_secret_set(int8_t interface_id, const uint8_t shared_secret_len, const uint8_t *shared_secret); +int8_t ws_pae_controller_radius_shared_secret_get(int8_t interface_id, uint16_t *shared_secret_len, uint8_t *shared_secret); /** * ws_pae_controller_nw_info_set set network information diff --git a/source/Security/protocols/sec_prot_cfg.h b/source/Security/protocols/sec_prot_cfg.h index f9c777e3fa37..b7bed75d1fc2 100644 --- a/source/Security/protocols/sec_prot_cfg.h +++ b/source/Security/protocols/sec_prot_cfg.h @@ -48,7 +48,7 @@ typedef struct sec_timer_cfg_s { typedef struct sec_radius_cfg_s { uint8_t radius_addr[16]; /**< Radius server IPv6 address */ uint8_t *radius_shared_secret; /**< Radius shared secret */ - uint8_t radius_shared_secret_len; /**< Radius shared secret length */ + uint16_t radius_shared_secret_len; /**< Radius shared secret length */ bool radius_addr_set : 1; /**< Radius server address is set */ } sec_radius_cfg_t; From b46f3c635e89e9189775ca7a1c9fc5f7801ae5c3 Mon Sep 17 00:00:00 2001 From: Mika Date: Fri, 14 Aug 2020 15:27:38 +0300 Subject: [PATCH 27/30] add empty function for ws_stack_info_get --- source/6LoWPAN/ws/ws_empty_functions.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/6LoWPAN/ws/ws_empty_functions.c b/source/6LoWPAN/ws/ws_empty_functions.c index e6721655f9ac..bc3d4ec2e392 100644 --- a/source/6LoWPAN/ws/ws_empty_functions.c +++ b/source/6LoWPAN/ws/ws_empty_functions.c @@ -406,7 +406,7 @@ void ns_time_api_system_time_callback_set(ns_time_api_system_time_callback callb (void) callback; } -int ws_state_info_get(int8_t interface_id, ws_stack_info_t *info_ptr) +int ws_stack_info_get(int8_t interface_id, ws_stack_info_t *info_ptr) { (void) interface_id; (void) info_ptr; From d8e7d40aee7b80624a181f561ffcbaf3a1d4d034 Mon Sep 17 00:00:00 2001 From: Jarkko Paso Date: Mon, 17 Aug 2020 16:16:22 +0300 Subject: [PATCH 28/30] Iotthd 4239 (#2414) * Api to read CCA threshold table * Use existing cca threshold attribute when requesting threshold table * Some documentation to CCA threshold read API --- nanostack/net_interface.h | 20 +++++++++++++++++++ source/6LoWPAN/MAC/mac_helper.c | 20 +++++++++++++++++++ source/6LoWPAN/MAC/mac_helper.h | 2 ++ source/6LoWPAN/MAC/mac_response_handler.c | 13 ++++++++++++ source/6LoWPAN/ws/ws_bootstrap.c | 6 +----- source/MAC/IEEE802_15_4/mac_cca_threshold.c | 8 ++++++++ source/MAC/IEEE802_15_4/mac_cca_threshold.h | 9 +++++++++ source/MAC/IEEE802_15_4/mac_mlme.c | 8 +++++++- source/NWK_INTERFACE/Include/protocol.h | 1 + source/libNET/src/ns_net.c | 15 ++++++++++++++ .../unittest/stub/mac_cca_threshold_stub.c | 8 +++++++- 11 files changed, 103 insertions(+), 7 deletions(-) diff --git a/nanostack/net_interface.h b/nanostack/net_interface.h index 8b47bc6a4ac1..2062a76eb161 100644 --- a/nanostack/net_interface.h +++ b/nanostack/net_interface.h @@ -286,6 +286,12 @@ typedef struct { uint8_t *beacon_payload_tlv_ptr; /**< Optional steering parameters. */ } network_driver_setup_s; +/** CCA threshold table */ +typedef struct { + uint8_t number_of_channels; /**< Number of channels */ + const int8_t *cca_threshold_table; /**< CCA threshold table */ +} cca_threshold_table_s; + /** * Init 6LoWPAN library * @@ -1135,6 +1141,20 @@ extern int8_t arm_nwk_set_cca_threshold(int8_t interface_id, uint8_t cca_thresho */ extern int8_t arm_nwk_set_tx_output_power(int8_t interface_id, uint8_t tx_power); +/** + * \brief Get CCA threshold table. + * + * This function can be used to read CCA threshold table. + * CCA threshold table structure contains number of channels and an array indicating the currently used CCA threshold value of each channel. CCA threshold values are updated by library continuously. + * If channels are reconfigured, number of channels and table length are changed automatically. User should check the table length (number of channels) before reading the table. + * Automatic CCA threshold feature may not be enabled before interface is up, causing function to return NULL. + * Returned pointer to cca_threshold_table_s structure is valid until interface is destroyed. Re-reading the pointer with this function is allowed any time. + * + * \param interface_id Network interface ID. + * \return NULL if automatic CCA threshold feature is not enabled, otherwise pointer to CCA threshold structure. + */ +extern const cca_threshold_table_s *arm_nwk_get_cca_threshold_table(int8_t interface_id); + #ifdef __cplusplus } diff --git a/source/6LoWPAN/MAC/mac_helper.c b/source/6LoWPAN/MAC/mac_helper.c index 3475f87df387..ab5961f5f2a2 100644 --- a/source/6LoWPAN/MAC/mac_helper.c +++ b/source/6LoWPAN/MAC/mac_helper.c @@ -995,3 +995,23 @@ int8_t mac_helper_mac_device_description_pan_id_update(int8_t interface_id, uint cur->mac_api->mlme_req(cur->mac_api, MLME_SET, &set_req); return 0; } + +int8_t mac_helper_start_auto_cca_threshold(int8_t interface_id, uint8_t number_of_channels, int8_t default_dbm, int8_t high_limit, int8_t low_limit) +{ + protocol_interface_info_entry_t *cur; + cur = protocol_stack_interface_info_get_by_id(interface_id); + if (!cur || !cur->mac_api) { + return -1; + } + uint8_t start_cca_thr[4] = {number_of_channels, default_dbm, high_limit, low_limit}; + mlme_set_t set_req; + set_req.attr = macCCAThresholdStart; + set_req.value_pointer = &start_cca_thr; + set_req.value_size = sizeof(start_cca_thr); + cur->mac_api->mlme_req(cur->mac_api, MLME_SET, &set_req); + /* Get CCA threshold table. Table is stored to interface structure */ + mlme_get_t get_req; + get_req.attr = macCCAThreshold; + cur->mac_api->mlme_req(cur->mac_api, MLME_GET, &get_req); + return 0; +} diff --git a/source/6LoWPAN/MAC/mac_helper.h b/source/6LoWPAN/MAC/mac_helper.h index dbd5b13d647f..8c9c651cd1fd 100644 --- a/source/6LoWPAN/MAC/mac_helper.h +++ b/source/6LoWPAN/MAC/mac_helper.h @@ -134,4 +134,6 @@ int8_t mac_helper_mac_mlme_max_retry_set(int8_t interface_id, uint8_t mac_retry_ int8_t mac_helper_mac_device_description_pan_id_update(int8_t interface_id, uint16_t pan_id); +int8_t mac_helper_start_auto_cca_threshold(int8_t interface_id, uint8_t number_of_channels, int8_t default_dbm, int8_t high_limit, int8_t low_limit); + #endif // MAC_HELPER_H diff --git a/source/6LoWPAN/MAC/mac_response_handler.c b/source/6LoWPAN/MAC/mac_response_handler.c index 87d3003bbc68..68054aa1ce6a 100644 --- a/source/6LoWPAN/MAC/mac_response_handler.c +++ b/source/6LoWPAN/MAC/mac_response_handler.c @@ -81,6 +81,15 @@ static void mac_mlme_frame_counter_confirmation_handle(protocol_interface_info_e info_entry->mac_parameters->security_frame_counter = *temp_ptr; } +static void mac_mlme_cca_threshold_confirmation_handle(protocol_interface_info_entry_t *info_entry, mlme_get_conf_t *confirmation) +{ + if (confirmation->value_size < 1) { + return; + } + info_entry->mac_parameters->cca_thr_table.number_of_channels = confirmation->value_size; + info_entry->mac_parameters->cca_thr_table.cca_threshold_table = (int8_t *)confirmation->value_pointer; +} + static void mac_mlme_get_confirmation_handler(protocol_interface_info_entry_t *info_entry, mlme_get_conf_t *confirmation) { @@ -96,6 +105,10 @@ static void mac_mlme_get_confirmation_handler(protocol_interface_info_entry_t *i mac_mlme_frame_counter_confirmation_handle(info_entry, confirmation); break; + case macCCAThreshold: + mac_mlme_cca_threshold_confirmation_handle(info_entry, confirmation); + break; + default: break; diff --git a/source/6LoWPAN/ws/ws_bootstrap.c b/source/6LoWPAN/ws/ws_bootstrap.c index 3065a6a22b7f..6bd10d5aa613 100644 --- a/source/6LoWPAN/ws/ws_bootstrap.c +++ b/source/6LoWPAN/ws/ws_bootstrap.c @@ -2135,11 +2135,7 @@ int ws_bootstrap_set_rf_config(protocol_interface_info_entry_t *cur, phy_rf_chan 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); + mac_helper_start_auto_cca_threshold(cur->id, cur->ws_info->hopping_schdule.number_of_channels, CCA_DEFAULT_DBM, CCA_HIGH_LIMIT, CCA_LOW_LIMIT); return 0; } diff --git a/source/MAC/IEEE802_15_4/mac_cca_threshold.c b/source/MAC/IEEE802_15_4/mac_cca_threshold.c index 33b9b274107e..ffb40f16bf52 100644 --- a/source/MAC/IEEE802_15_4/mac_cca_threshold.c +++ b/source/MAC/IEEE802_15_4/mac_cca_threshold.c @@ -140,3 +140,11 @@ int8_t mac_cca_threshold_update(protocol_interface_rf_mac_setup_s *rf_ptr, uint8 tr_debug("Channel %u CCA threshold to %i", channel, rf_ptr->cca_threshold->ch_thresholds[channel]); return 0; } + +mac_cca_threshold_s *mac_get_cca_threshold_table(protocol_interface_rf_mac_setup_s *rf_ptr) +{ + if (!rf_ptr->cca_threshold) { + return NULL; + } + return rf_ptr->cca_threshold; +} diff --git a/source/MAC/IEEE802_15_4/mac_cca_threshold.h b/source/MAC/IEEE802_15_4/mac_cca_threshold.h index a2081ba5883e..6e0da89bd058 100644 --- a/source/MAC/IEEE802_15_4/mac_cca_threshold.h +++ b/source/MAC/IEEE802_15_4/mac_cca_threshold.h @@ -49,6 +49,7 @@ int8_t mac_cca_thr_deinit(protocol_interface_rf_mac_setup_s *rf_ptr); /** * @brief Read CCA threshold of specific channel. + * @param rf_ptr Pointer to MAC instance. * @param channel Channel. * @return CCA threshold (dBm), CCA_FAILED_DBM Feature not enabled. */ @@ -56,10 +57,18 @@ int8_t mac_cca_thr_get_dbm(protocol_interface_rf_mac_setup_s *rf_ptr, uint8_t ch /** * @brief Update CCA threshold of specific channel. + * @param rf_ptr Pointer to MAC instance. * @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); +/** + * @brief Get pointer to CCA threshold table. + * @param rf_ptr Pointer to MAC instance. + * @return CCA threshold table. + */ +mac_cca_threshold_s *mac_get_cca_threshold_table(protocol_interface_rf_mac_setup_s *rf_ptr); + #endif /* MAC_CCA_THRESHOLD_H_ */ diff --git a/source/MAC/IEEE802_15_4/mac_mlme.c b/source/MAC/IEEE802_15_4/mac_mlme.c index d8db1d60f668..e1e2e4d34382 100644 --- a/source/MAC/IEEE802_15_4/mac_mlme.c +++ b/source/MAC/IEEE802_15_4/mac_mlme.c @@ -878,7 +878,7 @@ int8_t mac_mlme_get_req(struct protocol_interface_rf_mac_setup *rf_mac_setup, ml if (!get_req || !rf_mac_setup) { return -1; } - + mac_cca_threshold_s *cca_thr_table = NULL; switch (get_req->attr) { case macDeviceTable: get_req->value_pointer = mac_sec_mib_device_description_get_attribute_index(rf_mac_setup, get_req->attr_index); @@ -908,6 +908,12 @@ int8_t mac_mlme_get_req(struct protocol_interface_rf_mac_setup *rf_mac_setup, ml get_req->value_size = 4; break; + case macCCAThreshold: + cca_thr_table = mac_get_cca_threshold_table(rf_mac_setup); + get_req->value_size = cca_thr_table->number_of_channels; + get_req->value_pointer = cca_thr_table->ch_thresholds; + break; + default: get_req->status = MLME_UNSUPPORTED_ATTRIBUTE; break; diff --git a/source/NWK_INTERFACE/Include/protocol.h b/source/NWK_INTERFACE/Include/protocol.h index 2a1b3fbbf975..9880a5d2cc8a 100644 --- a/source/NWK_INTERFACE/Include/protocol.h +++ b/source/NWK_INTERFACE/Include/protocol.h @@ -238,6 +238,7 @@ typedef struct arm_15_4_mac_parameters_t { uint16_t pan_id; uint16_t mac_short_address; mac_cordinator_s mac_cordinator_info; + cca_threshold_table_s cca_thr_table; uint8_t number_of_fhss_channel_retries; /* MAC Beacon info */ uint8_t *mac_beacon_payload; diff --git a/source/libNET/src/ns_net.c b/source/libNET/src/ns_net.c index caf446493f1b..ed35581c5e79 100644 --- a/source/libNET/src/ns_net.c +++ b/source/libNET/src/ns_net.c @@ -1570,3 +1570,18 @@ int8_t arm_nwk_set_tx_output_power(int8_t interface_id, uint8_t tx_power) cur->mac_api->mlme_req(cur->mac_api, MLME_SET, &set_req); return 0; } + +const cca_threshold_table_s *arm_nwk_get_cca_threshold_table(int8_t interface_id) +{ + protocol_interface_info_entry_t *cur; + cur = protocol_stack_interface_info_get_by_id(interface_id); + // Interface or MAC parameters not initialized + if (!cur || !cur->mac_parameters) { + return NULL; + } + // Automatic CCA threshold not initialized + if (!cur->mac_parameters->cca_thr_table.cca_threshold_table || !cur->mac_parameters->cca_thr_table.number_of_channels) { + return NULL; + } + return &cur->mac_parameters->cca_thr_table; +} diff --git a/test/nanostack/unittest/stub/mac_cca_threshold_stub.c b/test/nanostack/unittest/stub/mac_cca_threshold_stub.c index f1c88fb7220d..e71c16680a67 100644 --- a/test/nanostack/unittest/stub/mac_cca_threshold_stub.c +++ b/test/nanostack/unittest/stub/mac_cca_threshold_stub.c @@ -21,8 +21,9 @@ #include "ns_list.h" #include "ns_trace.h" #include "mac_defines.h" +#include "mac_cca_threshold.h" -int8_t mac_cca_threshold_update(protocol_interface_rf_mac_setup_s *rf_ptr, uint16_t event_data) +int8_t mac_cca_threshold_update(protocol_interface_rf_mac_setup_s *rf_ptr, uint8_t channel, int8_t dbm) { return 0; } @@ -41,3 +42,8 @@ int8_t mac_cca_thr_get_dbm(protocol_interface_rf_mac_setup_s *rf_ptr, uint8_t ch { return 0; } + +mac_cca_threshold_s *mac_get_cca_threshold_table(protocol_interface_rf_mac_setup_s *rf_ptr) +{ + return NULL; +} From 3323f36d586bf5c94cd3dd3e9169f93e34fb6486 Mon Sep 17 00:00:00 2001 From: Mika Date: Wed, 12 Aug 2020 15:12:21 +0300 Subject: [PATCH 29/30] Add support for Ethernet RA dns configuration Add interface to include default route to RA messages Add interface to include DNS server address in RA Messages Add interface to include DNS search list in RA messages Add parsing of DNS information from RA --- nanostack/net_ipv6_api.h | 46 +++++++ source/Common_Protocols/icmpv6.c | 34 +++++ source/Common_Protocols/icmpv6.h | 2 + source/ipv6_stack/protocol_ipv6.c | 117 +++++++++++++++++- source/ipv6_stack/protocol_ipv6.h | 8 ++ source/libNET/src/net_ipv6.c | 57 +++++++++ .../unittest/libNET/net_ipv6/Makefile | 1 + .../unittest/stub/protocol_ipv6_stub.c | 18 +++ 8 files changed, 282 insertions(+), 1 deletion(-) diff --git a/nanostack/net_ipv6_api.h b/nanostack/net_ipv6_api.h index c2d26c379236..7132d9057ff6 100644 --- a/nanostack/net_ipv6_api.h +++ b/nanostack/net_ipv6_api.h @@ -131,4 +131,50 @@ int8_t arm_nwk_ipv6_opaque_iid_key(const void *secret_key, uint8_t key_len); */ int8_t arm_nwk_ipv6_opaque_iid_enable(int8_t interface_id, bool enable); +/** + * \brief Enable/disable default route in Router advertisements + * + * Enable or disable RFC 4861 Default router configuration in router advertisements. + * This makes the device a default router in the interface. + * + * \param interface_id Interface ID. + * \param enable True to enable. + * \return 0 enabled/disabled OK. + * \return <0 failed (for example invalid interface ID). + * + */ +int8_t arm_nwk_ipv6_default_route_enable(int8_t interface_id, bool enable); + +/** + * \brief add Recursive DNS Server Option information to Router advertisements + * + * Add Recursive DNS Server Option from RFC 8106 to router advertisements. + * This makes it possible to configure DNS server address to other devices connected to the interface. + * + * \param interface_id Interface ID. + * \param address 16 byte array for IPv6 address. + * \param lifetime advertised lifetime of the entry. 0 to delete address. + * \return 0 DNS server option option successful. + * \return <0 failed (for example invalid interface ID). + * + */ +int8_t arm_nwk_ipv6_dns_server_add(int8_t interface_id, uint8_t *address, uint32_t lifetime); + +/** + * \brief add DNS Search List Option information to Router advertisements + * + * Add DNS Search List Option from RFC 8106 to router advertisements. + * This makes it possible to configure DNS search list to other devices connected to the interface. + * + * \param interface_id Interface ID. + * \param data byte array encoded following https://tools.ietf.org/html/rfc1035#section-3.1. + * \param data_len Length of the byte array + * \param lifetime advertised lifetime of the entry. 0 to delete address. + * \return 0 DNS server option option successful. + * \return <0 failed (for example invalid interface ID). + * + */ +int8_t arm_nwk_ipv6_dns_search_list_add(int8_t interface_id, uint8_t *data, uint16_t data_len, uint32_t lifetime); + + #endif /* NET_IPV6_API_H_ */ diff --git a/source/Common_Protocols/icmpv6.c b/source/Common_Protocols/icmpv6.c index c6d3efd81c96..7433f2640b6d 100644 --- a/source/Common_Protocols/icmpv6.c +++ b/source/Common_Protocols/icmpv6.c @@ -859,6 +859,40 @@ static buffer_t *icmpv6_ra_handler(buffer_t *buf) } else { ipv6_route_delete(prefix_ptr, prefix_length, cur->id, buf->src_sa.address, ROUTE_RADV); } + } else if (type == ICMPV6_OPT_DNS_SEARCH_LIST) { + + if (length < 8) { + tr_warn("Invalid RA DNS search list opt corrupt"); + goto next_option; // invalid not accepted + } + uint32_t dns_lifetime = common_read_32_bit(dptr + 2); // 2 x reserved + uint8_t *dns_search_list = dptr + 6; + uint8_t dns_search_list_len = length - 8; // Length includes type and length + + tr_info("DNS Search List: %s Lifetime: %lu", trace_array(dns_search_list, dns_search_list_len), (unsigned long) dns_lifetime); + // TODO Add DNS server to DNS information storage. + // dns_search_list_storage(cur, buf->src_sa.address, dns_search_list, dns_search_list_len, dns_lifetime); + (void)dns_search_list; + (void)dns_search_list_len; + (void)dns_lifetime; + + } else if (type == ICMPV6_OPT_RECURSIVE_DNS_SERVER) { + uint8_t dns_length = length / 8; + + if (dns_length < 3) { + tr_warn("Invalid RA DNS server opt corrupt"); + goto next_option; // invalid not accepted + } + uint8_t dns_count = (dns_length - 1) / 2; + uint32_t dns_lifetime = common_read_32_bit(dptr + 2); // 2 x reserved + for (int n = 0; n < dns_count; n++) { + uint8_t *dns_srv_addr = dptr + 6 + n * 16; + tr_info("DNS Server: %s Lifetime: %lu", trace_ipv6(dns_srv_addr), (unsigned long) dns_lifetime); + // TODO Add DNS server to DNS information storage. + // dns_server_storage(cur, buf->src_sa.address, dns_srv_addr, dns_lifetime); + (void)dns_srv_addr; + (void)dns_lifetime; + } } else if (type == ICMPV6_OPT_6LOWPAN_CONTEXT) { nd_ra_process_lowpan_context_option(cur, dptr - 2); } diff --git a/source/Common_Protocols/icmpv6.h b/source/Common_Protocols/icmpv6.h index 3ae2aa14edf3..1e705945547f 100644 --- a/source/Common_Protocols/icmpv6.h +++ b/source/Common_Protocols/icmpv6.h @@ -77,6 +77,8 @@ #define ICMPV6_OPT_REDIRECTED_HDR 4 #define ICMPV6_OPT_MTU 5 #define ICMPV6_OPT_ROUTE_INFO 24 +#define ICMPV6_OPT_RECURSIVE_DNS_SERVER 25 +#define ICMPV6_OPT_DNS_SEARCH_LIST 31 #define ICMPV6_OPT_ADDR_REGISTRATION 33 #define ICMPV6_OPT_6LOWPAN_CONTEXT 34 #define ICMPV6_OPT_AUTHORITATIVE_BORDER_RTR 35 diff --git a/source/ipv6_stack/protocol_ipv6.c b/source/ipv6_stack/protocol_ipv6.c index 6f717104c41d..b7cd9218faef 100644 --- a/source/ipv6_stack/protocol_ipv6.c +++ b/source/ipv6_stack/protocol_ipv6.c @@ -57,6 +57,11 @@ typedef struct ipv6_interface_route_on_link_t { ns_list_link_t link; } ipv6_interface_route_on_link_t; +typedef struct ipv6_interface_dns_server_on_link_t { + uint8_t addr[16]; /*!< DNS Server IPv6 address */ + ns_list_link_t link; +} ipv6_interface_dns_server_on_link_t; + #define WB_UPDATE_PERIOD_SECONDS 23 #define ROUTER_SOL_MAX_COUNTER 4 @@ -77,6 +82,14 @@ static NS_LIST_DEFINE(prefix_on_link, ipv6_interface_prefix_on_link_t, link); static NS_LIST_DEFINE(route_on_link, ipv6_interface_route_on_link_t, link); static prefix_list_t ipv6_prefixs = NS_LIST_INIT(ipv6_prefixs); + +/*Router advertisement daemon configurations*/ +static uint16_t radv_default_route_lifetime = 0; +static NS_LIST_DEFINE(dns_server_list, ipv6_interface_dns_server_on_link_t, link); + +static uint16_t dns_search_list_len = 0; +static uint8_t *dns_search_list_ptr = NULL; + bool tunnel_in_use = false; static void ethernet_data_conf_cb(const eth_mac_api_t *api, const eth_data_conf_t *data) @@ -426,6 +439,73 @@ void ipv6_stack_route_advert_update(uint8_t *address, uint8_t prefixLength, uint } } +void ipv6_stack_route_advert_default_route(struct protocol_interface_info_entry *cur, bool enable) +{ + if (enable) { + radv_default_route_lifetime = icmpv6_radv_max_rtr_adv_interval(cur) * 2 / 10; + } else { + radv_default_route_lifetime = 0; + } +} + +int8_t ipv6_stack_route_advert_dns_server_add(uint8_t *address) +{ + + if (!address) { + return -1; + } + + ns_list_foreach(ipv6_interface_dns_server_on_link_t, cur_server, &dns_server_list) { + if (memcmp(cur_server->addr, address, 16) == 0) { + return 0; + } + } + ipv6_interface_dns_server_on_link_t *new_entry = ns_dyn_mem_alloc(sizeof(ipv6_interface_dns_server_on_link_t)); + if (!new_entry) { + return -1; + } + memcpy(new_entry->addr, address, 16); + ns_list_add_to_end(&dns_server_list, new_entry); + return 0; +} + +void ipv6_stack_route_advert_dns_server_delete(uint8_t *address) +{ + /* If Address is NULL everything is cleared. + * */ + ns_list_foreach_safe(ipv6_interface_dns_server_on_link_t, cur_server, &dns_server_list) { + if (!address || memcmp(cur_server->addr, address, 16) == 0) { + ns_list_remove(&dns_server_list, cur_server); + ns_dyn_mem_free(cur_server); + } + } +} + +int8_t ipv6_stack_route_advert_dns_search_list_add(uint8_t *data, uint16_t data_len, uint32_t lifetime) +{ + + if (dns_search_list_ptr) { + ns_dyn_mem_free(dns_search_list_ptr); + dns_search_list_ptr = NULL; + dns_search_list_len = 0; + } + + // Check if this is delete operation + if (lifetime == 0 || data_len == 0 || data == NULL) { + return 0; + } + + dns_search_list_len = ((data_len / 8) + 1) * 8; //Should have padding to 8 bytes + dns_search_list_ptr = ns_dyn_mem_alloc(dns_search_list_len); + if (!dns_search_list_ptr) { + return -1; + } + + memset(dns_search_list_ptr, 0, dns_search_list_len); + memcpy(dns_search_list_ptr, data, data_len); + return 0; +} + void ipv6_prefix_on_link_update(uint8_t *address) { protocol_interface_info_entry_t *cur = nwk_interface_get_ipv6_ptr(); @@ -630,6 +710,7 @@ int8_t ipv6_interface_down(protocol_interface_info_entry_t *cur) icmpv6_prefix_list_free(&ipv6_prefixs); ipv6_prefix_online_list_free(); ipv6_rote_advert_list_free(); + ipv6_stack_route_advert_dns_server_delete(NULL); neighbor_cache_flush(&cur->neigh_cache); ipv6_route_table_remove_interface(cur->id); protocol_core_interface_info_reset(cur); @@ -661,6 +742,12 @@ void ipv6_nd_ra_advert(protocol_interface_info_entry_t *cur, const uint8_t *dest uint16_t length = 12 + 8 + 16; length += 32 * ns_list_count(&ipv6_prefixs); length += 32 * ns_list_count(&prefix_on_link); + if (ns_list_count(&dns_server_list)) { + length += 8 + 16 * ns_list_count(&dns_server_list); + } + if (dns_search_list_len) { + length += 8 + dns_search_list_len; + } ns_list_foreach(ipv6_interface_route_on_link_t, tmp_route, &route_on_link) { if (tmp_route->prefix_len < 65) { @@ -680,7 +767,7 @@ void ipv6_nd_ra_advert(protocol_interface_info_entry_t *cur, const uint8_t *dest *ptr++ = cur->adv_cur_hop_limit; *ptr++ = cur->rtr_adv_flags; //Do not advertise default route: set Router Lifetime to 0 - ptr = common_write_16_bit(0, ptr); + ptr = common_write_16_bit(radv_default_route_lifetime, ptr); ptr = common_write_32_bit(cur->adv_reachable_time, ptr); ptr = common_write_32_bit(cur->adv_retrans_timer, ptr); @@ -749,6 +836,34 @@ void ipv6_nd_ra_advert(protocol_interface_info_entry_t *cur, const uint8_t *dest } } + if (ns_list_count(&dns_server_list)) { + *ptr++ = ICMPV6_OPT_RECURSIVE_DNS_SERVER; + *ptr++ = 1 + 2 * ns_list_count(&dns_server_list); // length is multiples of 8 + *ptr++ = 0; // Reserved + *ptr++ = 0; // Reserved + /* RFC8106 The value of Lifetime SHOULD by default be at least 3 * MaxRtrAdvInterval + * + * Lifetimes are short so we dont support removing entries by setting the lifetime 0 + * Lifetime is also for all entries so no maintenance is possible + */ + ptr = common_write_32_bit(icmpv6_radv_max_rtr_adv_interval(cur) * 3 / 10, ptr); + + ns_list_foreach_safe(ipv6_interface_dns_server_on_link_t, dns, &dns_server_list) { + memcpy(ptr, dns->addr, 16); + ptr += 16; + } + } + + if (dns_search_list_ptr && dns_search_list_len > 0) { + *ptr++ = ICMPV6_OPT_DNS_SEARCH_LIST; + *ptr++ = 1 + dns_search_list_len / 8; // length is multiples of 8 + *ptr++ = 0; // Reserved + *ptr++ = 0; // Reserved + ptr = common_write_32_bit(icmpv6_radv_max_rtr_adv_interval(cur) * 3 / 10, ptr); + memcpy(ptr, dns_search_list_ptr, dns_search_list_len); + ptr += dns_search_list_len; + } + buffer_data_end_set(buf, ptr); memcpy(buf->dst_sa.address, dest, 16); /* Source must be LL address (even if non-LL dest) */ diff --git a/source/ipv6_stack/protocol_ipv6.h b/source/ipv6_stack/protocol_ipv6.h index 7d877ef2b2e8..51bbc911a772 100644 --- a/source/ipv6_stack/protocol_ipv6.h +++ b/source/ipv6_stack/protocol_ipv6.h @@ -66,6 +66,10 @@ void ipv6_nd_ra_advert(struct protocol_interface_info_entry *cur, const uint8_t void ipv6_interface_slaac_handler(struct protocol_interface_info_entry *cur, const uint8_t *slaacPrefix, uint8_t prefixLen, uint32_t validLifeTime, uint32_t preferredLifeTime); void ipv6_stack_route_advert_update(uint8_t *address, uint8_t prefixLength, uint8_t routePrefer); void ipv6_stack_route_advert_remove(uint8_t *address, uint8_t prefixLength); +void ipv6_stack_route_advert_default_route(struct protocol_interface_info_entry *cur, bool enable); +int8_t ipv6_stack_route_advert_dns_server_add(uint8_t *address); +void ipv6_stack_route_advert_dns_server_delete(uint8_t *address); +int8_t ipv6_stack_route_advert_dns_search_list_add(uint8_t *data, uint16_t data_len, uint32_t lifetime); void ipv6_prefix_on_link_update(uint8_t *address); void ipv6_prefix_on_link_remove(uint8_t *address); int8_t ipv6_interface_accept_ra(int8_t interface_id, net_ipv6_accept_ra_e accept_ra); @@ -77,6 +81,10 @@ int8_t ipv6_interface_accept_ra(int8_t interface_id, net_ipv6_accept_ra_e accept #define ipv6_nd_ra_advert(cur, dest) ((void)0) #define ipv6_interface_sitelocal_clone(buf) ((void)0) #define ipv6_stack_route_advert_remove(address, prefixLength) ((void)0) +#define ipv6_stack_route_advert_default_route(cur,enable) +#define ipv6_stack_route_advert_dns_server_add(address) +#define ipv6_stack_route_advert_dns_server_delete(address) +#define ipv6_stack_route_advert_dns_search_list_add(data, data_len, lifetime) #define ipv6_prefix_on_link_update(address) ((void)0) #define ipv6_prefix_on_link_remove(address) ((void)0) #define ipv6_stack_route_advert_update(address, prefixLength, routePrefer) ((void)0) diff --git a/source/libNET/src/net_ipv6.c b/source/libNET/src/net_ipv6.c index 164b387ec7dd..f990c1b2b302 100644 --- a/source/libNET/src/net_ipv6.c +++ b/source/libNET/src/net_ipv6.c @@ -25,6 +25,7 @@ #include "Common_Protocols/ipv6_flow.h" #include "Common_Protocols/ipv6_fragmentation.h" #include "NWK_INTERFACE/Include/protocol.h" +#include "ipv6_stack/protocol_ipv6.h" #include "net_ipv6_api.h" @@ -73,3 +74,59 @@ int8_t arm_nwk_ipv6_opaque_iid_enable(int8_t interface_id, bool enable) cur->opaque_slaac_iids = enable; return 0; } + +int8_t arm_nwk_ipv6_default_route_enable(int8_t interface_id, bool enable) +{ +#ifdef HAVE_ETHERNET + protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(interface_id); + if (!cur) { + return -1; + } + + ipv6_stack_route_advert_default_route(cur, enable); + return 0; +#else + (void)interface_id; + (void)enable; + return -1; +#endif +} + +int8_t arm_nwk_ipv6_dns_server_add(int8_t interface_id, uint8_t *address, uint32_t lifetime) +{ +#ifdef HAVE_ETHERNET + protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(interface_id); + if (!cur) { + return -1; + } + if (lifetime == 0) { + ipv6_stack_route_advert_dns_server_delete(address); + } else { + return ipv6_stack_route_advert_dns_server_add(address); + } + + return 0; +#else + (void)interface_id; + (void)address; + (void)lifetime; + return -1; +#endif +} + +int8_t arm_nwk_ipv6_dns_search_list_add(int8_t interface_id, uint8_t *data, uint16_t data_len, uint32_t lifetime) +{ +#ifdef HAVE_ETHERNET + protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(interface_id); + if (!cur) { + return -1; + } + return ipv6_stack_route_advert_dns_search_list_add(data, data_len, lifetime); +#else + (void)interface_id; + (void)data; + (void)data_len; + (void)lifetime; + return -1; +#endif +} diff --git a/test/nanostack/unittest/libNET/net_ipv6/Makefile b/test/nanostack/unittest/libNET/net_ipv6/Makefile index 3d37a5410bd2..cc699c75c7d2 100644 --- a/test/nanostack/unittest/libNET/net_ipv6/Makefile +++ b/test/nanostack/unittest/libNET/net_ipv6/Makefile @@ -13,6 +13,7 @@ TEST_SRC_FILES = \ ../../stub/protocol_core_stub.c \ ../../stub/ipv6_fragmentation_stub.c \ ../../stub/ipv6_flow_stub.c \ + ../../stub/protocol_ipv6_stub.c \ ../../stub/ipv6_routing_table_stub.c \ ../../stub/address_stub.c \ diff --git a/test/nanostack/unittest/stub/protocol_ipv6_stub.c b/test/nanostack/unittest/stub/protocol_ipv6_stub.c index 26fbec7364a2..25c359f80822 100644 --- a/test/nanostack/unittest/stub/protocol_ipv6_stub.c +++ b/test/nanostack/unittest/stub/protocol_ipv6_stub.c @@ -108,6 +108,24 @@ void ipv6_stack_route_advert_update(uint8_t *address, uint8_t prefixLength, uint { } +void ipv6_stack_route_advert_default_route(struct protocol_interface_info_entry *cur, bool enable) +{ +} + +int8_t ipv6_stack_route_advert_dns_server_add(uint8_t *address) +{ + return 0; +} + +void ipv6_stack_route_advert_dns_server_delete(uint8_t *address) +{ +} + +int8_t ipv6_stack_route_advert_dns_search_list_add(uint8_t *data, uint16_t data_len, uint32_t lifetime) +{ + return 0; +} + void ipv6_prefix_on_link_update(uint8_t *address) { From 62d8586ae055e66becb9a287911548c29eff39b5 Mon Sep 17 00:00:00 2001 From: Jarkko Paso Date: Mon, 17 Aug 2020 16:24:13 +0300 Subject: [PATCH 30/30] Ignore ns_monitor when receiving Ack (#2417) * Ignore ns_monitor when receiving Ack * Fixed NS monitor unit tests --- source/MAC/IEEE802_15_4/mac_mcps_sap.c | 6 ----- source/MAC/IEEE802_15_4/mac_pd_sap.c | 9 +++++++- .../mac/mac_mcps_sap/test_mac_mcps_sap.c | 20 ---------------- .../unittest/mac/mac_pd_sap/Makefile | 1 + .../unittest/mac/mac_pd_sap/test_mac_pd_sap.c | 23 +++++++++++++++++++ 5 files changed, 32 insertions(+), 27 deletions(-) diff --git a/source/MAC/IEEE802_15_4/mac_mcps_sap.c b/source/MAC/IEEE802_15_4/mac_mcps_sap.c index 086de4503474..22b8061c8819 100644 --- a/source/MAC/IEEE802_15_4/mac_mcps_sap.c +++ b/source/MAC/IEEE802_15_4/mac_mcps_sap.c @@ -2351,12 +2351,6 @@ 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 - if (!ns_monitor_packet_allocation_allowed()) { - // stack can not handle new packets for routing - return NULL; - } - mac_pre_parsed_frame_t *buffer = ns_dyn_mem_temporary_alloc(sizeof(mac_pre_parsed_frame_t) + frame_length); if (buffer) { diff --git a/source/MAC/IEEE802_15_4/mac_pd_sap.c b/source/MAC/IEEE802_15_4/mac_pd_sap.c index 54669e879451..799205ceb0e2 100644 --- a/source/MAC/IEEE802_15_4/mac_pd_sap.c +++ b/source/MAC/IEEE802_15_4/mac_pd_sap.c @@ -36,6 +36,7 @@ #include "MAC/IEEE802_15_4/mac_mcps_sap.h" #include "MAC/IEEE802_15_4/mac_cca_threshold.h" #include "MAC/rf_driver_storage.h" +#include "Core/include/ns_monitor.h" #include "ns_trace.h" #define TRACE_GROUP "mPDs" @@ -904,11 +905,17 @@ static int8_t mac_pd_sap_generate_edfe_response(protocol_interface_rf_mac_setup_ static mac_pre_parsed_frame_t *mac_pd_sap_allocate_receive_buffer(protocol_interface_rf_mac_setup_s *rf_ptr, const mac_fcf_sequence_t *fcf_read, arm_pd_sap_generic_ind_t *pd_data_ind) { + // Unless receiving Ack, check that system has enough space to handle the new packet + if (fcf_read->frametype != FC_ACK_FRAME) { + if (!ns_monitor_packet_allocation_allowed()) { + // stack can not handle new packets for routing + return NULL; + } + } mac_pre_parsed_frame_t *buffer = mcps_sap_pre_parsed_frame_buffer_get(pd_data_ind->data_ptr, pd_data_ind->data_len); if (!buffer) { return NULL; } - //Copy Pre Parsed values buffer->fcf_dsn = *fcf_read; buffer->timestamp = mac_pd_sap_get_phy_rx_time(rf_ptr); diff --git a/test/nanostack/unittest/mac/mac_mcps_sap/test_mac_mcps_sap.c b/test/nanostack/unittest/mac/mac_mcps_sap/test_mac_mcps_sap.c index cc72f50549d8..9508acf6e153 100644 --- a/test/nanostack/unittest/mac/mac_mcps_sap/test_mac_mcps_sap.c +++ b/test/nanostack/unittest/mac/mac_mcps_sap/test_mac_mcps_sap.c @@ -2194,26 +2194,6 @@ bool test_mcps_sap_pre_parsed_frame_buffer_get() if (memcmp(mac_header_message_start_pointer(buf), buffer, 8) != 0) { return false; } - ns_dyn_mem_free(buf); - - // Test that if dynamic memory is low, then allocation fails - nsdynmemlib_stub.returnCounter = 1; - ns_monitor_stub.return_bool = false; - - buf = mcps_sap_pre_parsed_frame_buffer_get(buffer, 8); - if (buf) { - return false; - } - - // Test that allocation succeeds when there is enough heap - nsdynmemlib_stub.returnCounter = 1; - ns_monitor_stub.return_bool = true; - - buf = mcps_sap_pre_parsed_frame_buffer_get(buffer, 8); - if (!buf || buf->frameLength != 8) { - return false; - } - ns_dyn_mem_free(buf); return true; } diff --git a/test/nanostack/unittest/mac/mac_pd_sap/Makefile b/test/nanostack/unittest/mac/mac_pd_sap/Makefile index 41e17bb44cba..e9dd6cd02d76 100644 --- a/test/nanostack/unittest/mac/mac_pd_sap/Makefile +++ b/test/nanostack/unittest/mac/mac_pd_sap/Makefile @@ -27,6 +27,7 @@ TEST_SRC_FILES = \ ../../stub/buffer_dyn_stub.c \ ../../stub/fhss_config_stub.c \ ../../stub/sw_mac_stub.c \ + ../../stub/ns_monitor_stub.c \ include ../../MakefileWorker.mk diff --git a/test/nanostack/unittest/mac/mac_pd_sap/test_mac_pd_sap.c b/test/nanostack/unittest/mac/mac_pd_sap/test_mac_pd_sap.c index 713fcfc5a73c..a217e6206c71 100644 --- a/test/nanostack/unittest/mac/mac_pd_sap/test_mac_pd_sap.c +++ b/test/nanostack/unittest/mac/mac_pd_sap/test_mac_pd_sap.c @@ -33,6 +33,7 @@ #include "nsdynmemLIB_stub.h" #include "fhss_config_stub.h" #include "sw_mac_stub.h" +#include "ns_monitor_stub.h" #include static int8_t tx_return = -1; @@ -438,7 +439,29 @@ bool test_mac_pd_sap_data_cb() return false; } + // Test when ns monitor don't allow reception + ns_monitor_stub.return_bool = false; + mac_mcps_sap_stub.pre_parsed = frame_buf; + nsdynmemlib_stub.returnCounter = 2; + fcf.frametype = FC_DATA_FRAME; + mac_header_helper_functions_stub.fcf = fcf; + phy_message.message.generic_data_ind.data_len = 32; + ret = mac_pd_sap_data_cb(&rf_ptr, &phy_message); + if (ret != -3) { + return false; + } + // Test when ns monitor allows Ack reception + ns_monitor_stub.return_bool = false; + mac_mcps_sap_stub.pre_parsed = frame_buf; + nsdynmemlib_stub.returnCounter = 2; + fcf.frametype = FC_ACK_FRAME; + mac_header_helper_functions_stub.fcf = fcf; + phy_message.message.generic_data_ind.data_len = 32; + ret = mac_pd_sap_data_cb(&rf_ptr, &phy_message); + if (ret != -1) { + return false; + } //Test MAC15_4_PD_SAP_DATA_TX_CONFIRM phy_message.id = MAC15_4_PD_SAP_DATA_TX_CONFIRM;