From 96d7abd79fc58007ec6ed11dc73e64145b30d528 Mon Sep 17 00:00:00 2001 From: Arto Kinnunen Date: Mon, 17 Aug 2020 17:18:15 +0300 Subject: [PATCH] Squashed 'features/nanostack/sal-stack-nanostack/' changes from b3fe5744d1..48609aeded 48609aeded Merge branch 'release_internal' into release_external 62d8586ae0 Ignore ns_monitor when receiving Ack (#2417) 3323f36d58 Add support for Ethernet RA dns configuration d8e7d40aee Iotthd 4239 (#2414) b46f3c635e add empty function for ws_stack_info_get fc97980aa8 Changed RADIUS shared secret length to 16-bit value f827ffc364 Added information API to Wi-SUN and border router 8f1f9d5f46 EDFE error handling update 51bf94e77f Fix adaptation interface unit tests (#2409) 0860b57879 FHSS_WS: Fixed reading unicast remaining slots (#2408) 4d8c03bc06 Border Router RADIUS client basic authentication functionality (#2406) fbfada9595 Adaptation IF: Allocate fragmentation buffer only if needed (#2407) 66f1bffb47 Added storing of PAN version to NVM on BR 89826ce8af Iotthd 4224 (#2403) 3fc1ae221b BR EUI-64 is now selected for 4WH using PMKID on 4WH Message 1 af8438e65e Timing tool traces (#2401) 7938795f2f Fixed new PD data request for check if EDFE exchange is active. 85ab8fd3e1 Extented Frame exchange support 86b1f27041 Merge pull request #2399 from ARMmbed/IOTTHD-4220 fed69e04d7 Add missing test method to ws_empty_functions 6b58e26c30 Add EDFE mode to Socket API setsockopt 12830770e6 Test API to adjust 6LoWPAN fragmentation MTU size (#2398) e787874424 Init MAC MTU size based on driver MTU size (#2397) bf8e89e0b7 Ignore neighbors using unsupported channel function (#2395) 1c263fd54e FHSS exclude channel usage from mask and Brazilian Domain support 841dcbeccb MAC: Configurable data whitening (#2393) 9a10d66add Fix global address detection (#2392) f27fe86a24 Corrected network name and PAN ID change on auth start bcce0ed0ef Clarified border router routing table API description e4630a4916 Wi-SUN interface now informs address changes as interface events 2174374df3 Fix error found by coverity (#2389) 843254a510 MPL: traces for transmit and receive message (#2387) git-subtree-dir: features/nanostack/sal-stack-nanostack git-subtree-split: 48609aeded2059177f8877b8f94558fc68b9595f --- nanostack/mac_api.h | 20 +- nanostack/mac_mcps.h | 28 + nanostack/mlme.h | 2 + nanostack/net_interface.h | 20 + nanostack/net_ipv6_api.h | 46 + nanostack/net_ws_test.h | 37 + nanostack/platform/arm_hal_phy.h | 1 + nanostack/socket_api.h | 12 +- nanostack/ws_bbr_api.h | 87 +- nanostack/ws_management_api.h | 32 + .../Bootstraps/Generic/protocol_6lowpan.c | 5 +- source/6LoWPAN/MAC/mac_helper.c | 29 +- source/6LoWPAN/MAC/mac_helper.h | 3 + source/6LoWPAN/MAC/mac_response_handler.c | 13 + source/6LoWPAN/adaptation_interface.c | 22 +- source/6LoWPAN/ws/ws_bbr_api.c | 68 ++ source/6LoWPAN/ws/ws_bbr_api_internal.h | 2 + source/6LoWPAN/ws/ws_bootstrap.c | 182 +++- source/6LoWPAN/ws/ws_bootstrap.h | 15 +- source/6LoWPAN/ws/ws_common.c | 28 + source/6LoWPAN/ws/ws_common.h | 9 + source/6LoWPAN/ws/ws_common_defines.h | 8 + source/6LoWPAN/ws/ws_config.h | 4 + source/6LoWPAN/ws/ws_empty_functions.c | 15 + source/6LoWPAN/ws/ws_ie_lib.c | 20 +- source/6LoWPAN/ws/ws_ie_lib.h | 4 +- source/6LoWPAN/ws/ws_llc.h | 2 + source/6LoWPAN/ws/ws_llc_data_service.c | 232 +++- source/6LoWPAN/ws/ws_management_api.c | 10 + source/6LoWPAN/ws/ws_neighbor_class.c | 35 +- source/6LoWPAN/ws/ws_neighbor_class.h | 2 +- source/6LoWPAN/ws/ws_pae_auth.c | 156 ++- source/6LoWPAN/ws/ws_pae_auth.h | 37 +- source/6LoWPAN/ws/ws_pae_controller.c | 258 ++++- source/6LoWPAN/ws/ws_pae_controller.h | 82 +- source/6LoWPAN/ws/ws_pae_lib.c | 13 + source/6LoWPAN/ws/ws_pae_lib.h | 12 + source/6LoWPAN/ws/ws_pae_nvm_data.c | 9 +- source/6LoWPAN/ws/ws_pae_nvm_data.h | 10 +- source/6LoWPAN/ws/ws_pae_supp.c | 75 +- source/6LoWPAN/ws/ws_pae_supp.h | 19 +- source/6LoWPAN/ws/ws_pae_timers.c | 12 +- source/6LoWPAN/ws/ws_pae_timers.h | 12 +- source/6LoWPAN/ws/ws_test_api.c | 20 +- source/Common_Protocols/icmpv6.c | 34 + source/Common_Protocols/icmpv6.h | 2 + source/Core/include/ns_address_internal.h | 1 + source/Core/include/ns_buffer.h | 1 + source/Core/include/ns_socket.h | 1 + source/Core/ns_address_internal.c | 1 + source/Core/ns_socket.c | 3 + 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_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 | 266 ++++- source/MAC/IEEE802_15_4/mac_mcps_sap.h | 5 + source/MAC/IEEE802_15_4/mac_mlme.c | 18 +- source/MAC/IEEE802_15_4/mac_pd_sap.c | 171 ++- source/MAC/IEEE802_15_4/mac_pd_sap.h | 2 + source/MAC/IEEE802_15_4/sw_mac.c | 30 + source/MPL/mpl.c | 2 + source/NWK_INTERFACE/Include/protocol.h | 1 + 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 | 12 +- .../fwh_sec_prot/supp_fwh_sec_prot.c | 31 +- .../gkh_sec_prot/auth_gkh_sec_prot.c | 4 +- .../protocols/key_sec_prot/key_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_keys.h | 1 + source/Security/protocols/sec_prot_lib.c | 22 +- source/Security/protocols/sec_prot_lib.h | 4 +- .../protocols/tls_sec_prot/tls_sec_prot.c | 4 +- source/Service_Libs/fhss/fhss_ws.c | 59 +- source/Service_Libs/fhss/fhss_ws.h | 1 + .../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 +- source/ipv6_stack/protocol_ipv6.c | 117 +- source/ipv6_stack/protocol_ipv6.h | 8 + source/libNET/src/net_ipv6.c | 57 + source/libNET/src/ns_net.c | 18 +- source/libNET/src/socket_api.c | 7 + sources.mk | 5 +- 98 files changed, 4756 insertions(+), 414 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/mac_api.h b/nanostack/mac_api.h index 1de9dbc276..a972554b92 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 05fbec040b..614a01e326 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/nanostack/mlme.h b/nanostack/mlme.h index 841f097cb6..ee6a244172 100644 --- a/nanostack/mlme.h +++ b/nanostack/mlme.h @@ -264,6 +264,8 @@ typedef enum { macAutoRequestKeyIndex = 0x7b, /*= 0 success + * + */ +int ws_bbr_radius_address_set(int8_t interface_id, const uint8_t *address); + +/** + * Get RADIUS server IPv6 address + * + * 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. + * \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 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/nanostack/ws_management_api.h b/nanostack/ws_management_api.h index 37e66999ab..8d155595cd 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 b89117b7c7..b5043e41a7 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/MAC/mac_helper.c b/source/6LoWPAN/MAC/mac_helper.c index 9e9b5a266c..ab5961f5f2 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; } @@ -988,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 6c68c6dc2f..8c9c651cd1 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); @@ -133,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 87d3003bbc..68054aa1ce 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/adaptation_interface.c b/source/6LoWPAN/adaptation_interface.c index 87d6657735..fac7616df6 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(); @@ -938,6 +935,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); @@ -996,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/6LoWPAN/ws/ws_bbr_api.c b/source/6LoWPAN/ws/ws_bbr_api.c index f841be8144..878c431f51 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"); @@ -573,6 +587,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) @@ -790,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; @@ -1069,3 +1091,49 @@ 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_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); +#else + (void) interface_id; + (void) shared_secret_len; + (void) shared_secret; + 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_bbr_api_internal.h b/source/6LoWPAN/ws/ws_bbr_api_internal.h index 249790feac..4c24191cb8 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 0d02498a5d..6bd10d5aa6 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); @@ -95,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); @@ -157,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; @@ -225,21 +224,21 @@ static void ws_bootstrap_address_notification_cb(struct protocol_interface_info_ 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); } 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 @@ -261,6 +260,14 @@ static void ws_bootstrap_address_notification_cb(struct protocol_interface_info_ } } } + + // 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 + } + } } static int ws_bootstrap_tasklet_init(protocol_interface_info_entry_t *cur) @@ -486,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; @@ -494,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 @@ -549,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) @@ -1424,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); } @@ -1508,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); } @@ -1564,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) { @@ -1602,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; } @@ -2098,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; } @@ -2275,7 +2308,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]); @@ -2635,7 +2668,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); } @@ -2683,22 +2716,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); @@ -2989,6 +3026,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; @@ -3045,8 +3094,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; @@ -3075,7 +3127,10 @@ 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 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); @@ -3173,7 +3228,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; } @@ -3222,11 +3277,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; @@ -3249,7 +3300,22 @@ void ws_bootstrap_rpl_wait_process(protocol_interface_info_entry_t *cur) return; } -/* +static bool ws_bootstrap_state_discovery(struct protocol_interface_info_entry *cur) +{ + if (cur->nwk_bootstrap_state == ER_ACTIVE_SCAN) { + return true; + } + return false; +} + +static bool ws_bootstrap_state_authenticate(struct protocol_interface_info_entry *cur) +{ + // Think about the state value + if (cur->nwk_bootstrap_state == ER_PANA_AUTH) { + return true; + } + return false; +} static bool ws_bootstrap_state_configure(struct protocol_interface_info_entry *cur) { @@ -3260,10 +3326,10 @@ static bool ws_bootstrap_state_configure(struct protocol_interface_info_entry *c return false; } -*/ -static bool ws_bootstrap_state_discovery(struct protocol_interface_info_entry *cur) +static bool ws_bootstrap_state_wait_rpl(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_RPL_SCAN) { return true; } return false; @@ -3276,14 +3342,6 @@ static bool ws_bootstrap_state_active(struct protocol_interface_info_entry *cur) } return false; } -static bool ws_bootstrap_state_wait_rpl(struct protocol_interface_info_entry *cur) -{ - // Think about the state value - if (cur->nwk_bootstrap_state == ER_RPL_SCAN) { - return true; - } - return false; -} static void ws_bootstrap_state_change(protocol_interface_info_entry_t *cur, icmp_state_t nwk_bootstrap_state) { @@ -3431,7 +3489,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; @@ -3442,11 +3500,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) { @@ -3457,4 +3515,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 c9cdcd46b4..d936c23ce6 100644 --- a/source/6LoWPAN/ws/ws_bootstrap.h +++ b/source/6LoWPAN/ws/ws_bootstrap.h @@ -31,7 +31,9 @@ typedef enum { 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); @@ -64,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); @@ -82,12 +84,16 @@ 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); 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) @@ -95,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 010f6c14ac..841ce15dab 100644 --- a/source/6LoWPAN/ws/ws_common.c +++ b/source/6LoWPAN/ws/ws_common.c @@ -23,8 +23,12 @@ #include #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" @@ -81,6 +85,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) { @@ -307,6 +323,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; @@ -336,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); } @@ -461,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 08d726ee6b..4dadf81b36 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); @@ -149,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) @@ -162,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_common_defines.h b/source/6LoWPAN/ws/ws_common_defines.h index 749a5aa1fa..f6f5e5cca8 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; @@ -130,6 +131,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_config.h b/source/6LoWPAN/ws/ws_config.h index 6b00d6004c..62a338ea0d 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_empty_functions.c b/source/6LoWPAN/ws/ws_empty_functions.c index f9e4e97195..bc3d4ec2e3 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; @@ -398,4 +406,11 @@ void ns_time_api_system_time_callback_set(ns_time_api_system_time_callback callb (void) callback; } +int ws_stack_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_ie_lib.c b/source/6LoWPAN/ws/ws_ie_lib.c index 0dfdc8b5ac..633b01c60e 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 1beadcd898..3be8bff8b5 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.h b/source/6LoWPAN/ws/ws_llc.h index fd3b010501..e7df162ae4 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 73f468a27c..c9ffe9c1d4 100644 --- a/source/6LoWPAN/ws/ws_llc_data_service.c +++ b/source/6LoWPAN/ws/ws_llc_data_service.c @@ -112,10 +112,16 @@ 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 */ + 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; @@ -123,7 +129,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 */ @@ -167,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) { @@ -304,7 +334,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 +444,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 +549,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; } @@ -613,8 +643,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; } @@ -648,14 +684,14 @@ 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; } 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) { @@ -730,8 +766,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; } @@ -755,7 +797,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) { @@ -933,6 +975,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 && data->TxAckReq) { + ie_header_mask.fc_ie = true; + } if (!data->TxAckReq) { nested_wp_id.bs_ie = true; } @@ -977,17 +1022,31 @@ 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->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; + } 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); @@ -1022,6 +1081,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); } @@ -1050,6 +1112,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; @@ -1403,6 +1466,104 @@ 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"); + 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; + } +} + + + 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); @@ -1423,6 +1584,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); @@ -1508,6 +1670,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; @@ -1651,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/6LoWPAN/ws/ws_management_api.c b/source/6LoWPAN/ws/ws_management_api.c index ef9e9cffbd..a324643558 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/6LoWPAN/ws/ws_neighbor_class.c b/source/6LoWPAN/ws/ws_neighbor_class.c index 214c46f871..eedb016240 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 f470a25a8b..e1ebf04823 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/6LoWPAN/ws/ws_pae_auth.c b/source/6LoWPAN/ws/ws_pae_auth.c index 077c3ae580..b435270c77 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); @@ -470,8 +502,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; } @@ -666,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) { @@ -682,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); @@ -737,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); @@ -840,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; @@ -852,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; } @@ -892,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; @@ -998,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; @@ -1014,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 @@ -1027,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; } @@ -1045,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 @@ -1054,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); @@ -1071,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; @@ -1094,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; @@ -1135,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 db84db0656..fc1030a750 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 * @@ -174,12 +185,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 @@ -227,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 * @@ -235,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 @@ -256,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 05eb06983b..80b72e5231 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 */ @@ -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,12 +113,15 @@ 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); 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); @@ -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) { @@ -276,7 +314,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; @@ -290,20 +328,27 @@ 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; } + // 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); + controller->pae_nw_info_set(interface_ptr, pan_id, network_name, updated); } return 0; @@ -327,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) { @@ -606,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); @@ -624,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; @@ -676,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); @@ -696,7 +761,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; @@ -704,6 +769,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++) { @@ -720,7 +788,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); } } @@ -792,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; } @@ -803,7 +871,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); @@ -822,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; } @@ -855,7 +923,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 @@ -1103,6 +1171,130 @@ 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 *address) +{ + pae_controller_t *controller = ws_pae_controller_get_or_create(interface_id); + + // If remote address is not set, clear radius information + if (!address) { + 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, address, 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_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); + + // 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_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) { @@ -1165,7 +1357,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); @@ -1446,7 +1638,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 @@ -1454,7 +1646,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); @@ -1467,7 +1659,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 2f7e01e6df..93c3abdd34 100644 --- a/source/6LoWPAN/ws/ws_pae_controller.h +++ b/source/6LoWPAN/ws/ws_pae_controller.h @@ -232,18 +232,69 @@ 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 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_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 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_get(int8_t interface_id, uint16_t *shared_secret_len, uint8_t *shared_secret); + /** * ws_pae_controller_nw_info_set set network information * * \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,13 +569,14 @@ 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 + * ws_pae_controller_cb_register register controller callbacks * * \param interface_ptr interface * \param completed authentication completed callback @@ -543,6 +595,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 d47aff8a8f..52ceaaba6a 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 eed138e74c..5058e3e364 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_nvm_data.c b/source/6LoWPAN/ws/ws_pae_nvm_data.c index 3212240af8..793b7a4846 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 c55d56412b..d66e238fa0 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/6LoWPAN/ws/ws_pae_supp.c b/source/6LoWPAN/ws/ws_pae_supp.c index 7954010d50..9beda28756 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); @@ -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); @@ -349,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); } } @@ -488,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 @@ -506,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) && @@ -523,6 +532,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); @@ -538,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; @@ -564,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; @@ -587,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; } @@ -896,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) @@ -920,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; @@ -1078,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; @@ -1138,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 7bd2017061..bed5ebc7e2 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 @@ -173,6 +172,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 * diff --git a/source/6LoWPAN/ws/ws_pae_timers.c b/source/6LoWPAN/ws/ws_pae_timers.c index a07d0e6deb..fb1abbe275 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 7b8f58052d..57fceb97cb 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/6LoWPAN/ws/ws_test_api.c b/source/6LoWPAN/ws/ws_test_api.c index 16f9c5926a..2e7cc97259 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 diff --git a/source/Common_Protocols/icmpv6.c b/source/Common_Protocols/icmpv6.c index c6d3efd81c..7433f2640b 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 3ae2aa14ed..1e70594554 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/Core/include/ns_address_internal.h b/source/Core/include/ns_address_internal.h index cce42c6447..79bf398b70 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/include/ns_buffer.h b/source/Core/include/ns_buffer.h index b33148a14d..0168495ff2 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 941c7403da..c4e6e638c2 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_address_internal.c b/source/Core/ns_address_internal.c index ca998f361e..6131df7a01 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/source/Core/ns_socket.c b/source/Core/ns_socket.c index e0fbffd724..bd919a99af 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/MAC/IEEE802_15_4/mac_cca_threshold.c b/source/MAC/IEEE802_15_4/mac_cca_threshold.c index 33b9b27410..ffb40f16bf 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 a2081ba588..6e0da89bd0 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_data_buffer.h b/source/MAC/IEEE802_15_4/mac_data_buffer.h index 4888cc816d..e01ee3a040 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 ff67616990..5052ad5d4e 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 fd56ecbd74..8925c5ae4a 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 ee16dc8670..22b8061c88 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) { @@ -1426,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) { @@ -1434,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) { @@ -1447,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; @@ -1622,7 +1691,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 +1789,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 +2007,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 +2040,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 +2080,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 +2108,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,8 +2116,8 @@ 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; - if (!rf_ptr->mac_ack_tx_active) { + rf_ptr->macTxRequestAck = buffer->WaitResponse; + 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; @@ -1943,6 +2125,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 +2155,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 +2182,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 +2204,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); @@ -2133,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_mcps_sap.h b/source/MAC/IEEE802_15_4/mac_mcps_sap.h index 1a84004141..fb212e20a2 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 901ef01071..e1e2e4d343 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; @@ -807,6 +811,11 @@ int8_t mac_mlme_set_req(protocol_interface_rf_mac_setup_s *rf_mac_setup, const m memcpy(rf_mac_setup->coord_long_address, set_req->value_pointer, 8); } return 0; + case 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)); @@ -869,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); @@ -899,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; @@ -1706,6 +1721,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 ec34ef77ae..799205ceb0 100644 --- a/source/MAC/IEEE802_15_4/mac_pd_sap.c +++ b/source/MAC/IEEE802_15_4/mac_pd_sap.c @@ -36,6 +36,10 @@ #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" /* Define TX Timeot Period */ // Hardcoded to 1200ms. Should be changed dynamic: (FHSS) channel retries needs longer timeout @@ -148,6 +152,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 +181,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 { @@ -371,6 +377,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; @@ -424,6 +433,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) { @@ -436,6 +456,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; } @@ -447,7 +470,14 @@ 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)) { +#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) { @@ -495,14 +525,34 @@ 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 { + + 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)) { @@ -510,6 +560,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; @@ -671,7 +726,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,13 +878,44 @@ 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) { + // 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); @@ -922,6 +1010,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); @@ -953,6 +1045,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/mac_pd_sap.h b/source/MAC/IEEE802_15_4/mac_pd_sap.h index 9e524ebd10..fdde95acac 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/source/MAC/IEEE802_15_4/sw_mac.c b/source/MAC/IEEE802_15_4/sw_mac.c index 67e5884227..7fd08c6d25 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/source/MPL/mpl.c b/source/MPL/mpl.c index 1474c89187..f8e0b93dc1 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). diff --git a/source/NWK_INTERFACE/Include/protocol.h b/source/NWK_INTERFACE/Include/protocol.h index 2a1b3fbbf9..9880a5d2cc 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/Security/kmp/kmp_api.c b/source/Security/kmp/kmp_api.c index d3a61fe867..e175d9a851 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 10f36528bd..f51a140588 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 6cf5c8f064..f12bc517b9 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 79aca99ee6..66c78b1039 100644 --- a/source/Security/kmp/kmp_socket_if.c +++ b/source/Security/kmp/kmp_socket_if.c @@ -43,52 +43,92 @@ 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) { + 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, *instance_id, kmp_socket_if_send, header_size) < 0) { ns_dyn_mem_free(socket_if); return -1; } - if (kmp_service_msg_if_register(service, kmp_socket_if_send, SOCKET_IF_HEADER_SIZE) < 0) { - ns_dyn_mem_free(socket_if); - return -1; + if (new_socket_if_allocated) { + ns_list_add_to_end(&kmp_socket_if_list, socket_if); } - 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; - + 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 af1d695081..20a55c8f45 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 2fd7d96b65..84d3c013fa 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 0000000000..2c85d85378 --- /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 0000000000..03f510985f --- /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 b7df2d6eb6..8e0952c162 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 285a75db8e..1162eb9c35 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 @@ -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; } @@ -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 ef3e9bd991..a1074f7ec2 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 @@ -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/gkh_sec_prot/auth_gkh_sec_prot.c b/source/Security/protocols/gkh_sec_prot/auth_gkh_sec_prot.c index 7d736ae95b..d1101d2292 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/key_sec_prot/key_sec_prot.c b/source/Security/protocols/key_sec_prot/key_sec_prot.c index ad75cf5853..ec3600e84c 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/radius_sec_prot/avp_helper.c b/source/Security/protocols/radius_sec_prot/avp_helper.c new file mode 100644 index 0000000000..73cc2d98e5 --- /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 0000000000..1fdd5bb54e --- /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 0000000000..a181cf0dd3 --- /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 0000000000..9d3a467284 --- /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 c6ebae78a9..3c7724124e 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 f0a118b7c1..b7bed75d1f 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 */ + uint16_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_keys.h b/source/Security/protocols/sec_prot_keys.h index 06302519d2..5050ddeec1 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; diff --git a/source/Security/protocols/sec_prot_lib.c b/source/Security/protocols/sec_prot_lib.c index 1df7d5dac3..604644fbc2 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; } @@ -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 1ade05bd44..4d7fd088ee 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 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 d4b8c549ae..472c0411dc 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/fhss/fhss_ws.c b/source/Service_Libs/fhss/fhss_ws.c index 80c3f90d14..d37ff27a77 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; @@ -276,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) { @@ -324,6 +344,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 @@ -331,6 +354,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) @@ -373,6 +403,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 } } @@ -384,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) { @@ -447,6 +483,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)) { @@ -459,6 +496,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; @@ -477,12 +515,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) { @@ -496,6 +536,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) { @@ -540,8 +583,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); @@ -814,8 +859,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; @@ -916,6 +966,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 f4d27c1bff..26b8f4c969 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; 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 7e7e47dcb6..a3eb539b61 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 77ef76bfc0..7c55b77a45 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 fb36a03c67..6200ae0eb9 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/source/ipv6_stack/protocol_ipv6.c b/source/ipv6_stack/protocol_ipv6.c index 6f717104c4..b7cd9218fa 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 7d877ef2b2..51bbc911a7 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 164b387ec7..f990c1b2b3 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/source/libNET/src/ns_net.c b/source/libNET/src/ns_net.c index e369f6c375..ed35581c5e 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; } @@ -1569,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/source/libNET/src/socket_api.c b/source/libNET/src/socket_api.c index 105c8579aa..d02df10121 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; } diff --git a/sources.mk b/sources.mk index e364c49b84..97b4113c20 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 \