From 780e9afb8f3b8f09e66573e7d4ba096dd9a87dd7 Mon Sep 17 00:00:00 2001 From: Arto Kinnunen Date: Mon, 25 Feb 2019 14:23:32 +0200 Subject: [PATCH] Squashed 'features/nanostack/sal-stack-nanostack/' changes from 513a38e..c5ee9e4 c5ee9e4 Remove content from unit tests f7ca82a Merge branch 'release_internal' into release_external b400a6a Fix for pr #1984 (#1987) 30d25bc Fix compiler warnings (#1986) d46d7b3 Prioritise thread control messages (#1984) e59dbd8 Update domain address lifetime (#1985) 8a5cb75 Merge pull request #1980 from ARMmbed/sync_with_MbedOS bd6feab Update coding style ff14e80 (via Mbed OS) nanostack: icmpv6: fix build warning f5e3423 (via Mbed OS) Require dependencies from nanostack mbed_lib.json 3aec837 Restore ws_management_api.h to the latest version cd7ae3f (via Mbed OS) Review changes corrected 4f23008 (via Mbed OS) This is a initial version of Wi-Sun interface implementation. To get Wi-Sun mesh network working, also nanostack with Wi-Sun support is needed. ws_empty_functions.c and ws_management_api.h are temporary included here, so that wisun_tasklet will compiled without problems. They will replaced with the official versions with next nanostack release. e029444 Merge pull request #1981 from ARMmbed/iotthd-3111 d7e8aea Path control size from 5->7. a5fe76f randomise challenge tlv for parent request retries. (#1977) a1c8277 Merge pull request #1978 from ARMmbed/IOTTHD-3219 62f8b41 Fix compiler warnings 1ec7a84 Fix issues found by coverity 5fe7120 Merge pull request #1974 from ARMmbed/iotthd-3100 51358f9 Removed Unncessary debug print. 136d1b1 Merge pull request #1973 from ARMmbed/IOTTHD-3018 4e557ae DHCPv6 update: 85b33e1 Update BBR prefix assignment (#1972) 899b2c5 DHCPv6 client and server update: 9009eaf Update copyright year to test files 6a56318 Update copyright year to Nanostack files a83472e Added Wi-Sun certificate and security test interfaces 7f4ebf1 Corrected compiler warnings 52e4c3f Added supplicant PAE NVM storage 92df57b Added key data access functions to key storage 5972bc3 Merge pull request #1959 from ARMmbed/ws_eapol_ie_update 98af118 Merge pull request #1965 from ARMmbed/IOTTHD-3193 fc76d1e Merge pull request #1963 from ARMmbed/rename_socket_h ba3a649 Added WS flagging to EAP header parser 048f14a Rename address.h 5739b4a Fixed aro registration error 887d931 Rename socket.h to ns_socket.h 7ebaa8e Add Nanostack configuration for WS (#1961) ed87161 Code style fix. e20028a Fix compiler warnings (#1957) b86f885 EAPOL data flow IE update 65472de Fixed Function protype typo. f539287 Added support for write/READ EA-IE header IE Element's ce72b55 Merge pull request #1958 from ARMmbed/tls_conf_err 1e8b18c Added handling for mbed TLS configuration error bdfea40 WS: Use common channel number calc function 4802aae Merge pull request #1930 from ARMmbed/IOTTHD-3027 2b8c846 PAE BR address write/read interface 9777ad1 Remove yotta references (#1954) af8890b Merge pull request #1949 from ARMmbed/eapol_eap_and_tls c546d4f WS: Fixed EU domain channel numbers in neighbor class cff6f0b WS: Missing return value fix ebcdba5 Changed EAP-TLS identity to anonymous 34d2f15 Corrected defects and coding style 79c7157 WS: Default domain config update 0724863 Merge branch 'master' into IOTTHD-3027 65ccc41 WS: RF config set in own functions 76d235e MAC: Fixed virtual driver warnings 88641c1 Updates to PAEs and other security protocols f57138f Security key storage and certificate info updates b7177c5 TLS security protocol and mbed TLS security protocol library 9c9e3c9 EAP-TLS protocol implementation 9c5fc92 WS: Fixed code style acce0dd Added empty function for test 4b28192 Added support for ARO registration failure 9d251fa Added empty function fr new interface 61f520f Added api to configure network size parameters 4d26258 Flagged mbed TLS KW header and corrected bool definitions 3d903fa Corrected NIST AES KW flagging 2f4e099 Removed temporary KW functions and corrected ut and style 6481549 Added GKH MIC validation and encryption cc3ce58 Moved 4WH functions to library and added constants 650771c Added unit test to NIST AES KW library 6a82e7d added parent priority handling. (#1942) 7b7f1c1 Merge pull request #1945 from ARMmbed/fix_synch_parent_warn 38b28e2 Fix coverity error (#1943) c4afedc thread_mle_message_handler: fix build warning (#1940) a5be64a Follow Mbed OS coding style (#1941) 6298cef Sync mbed_lib.json with Mbed OS (#1935) afe3ec6 Added Wi-Sun flagging to eapol helper 28d10d6 Merge pull request #1901 from ARMmbed/kmp_pae_init 3f56121 Disabled EAPOL flags 97f07a9 Tuned EAPOL timers for small networks 6e063b6 added Wi-SUN neighbor table management to Wi-SUN 7f4c61d Corrected KMP api start on authenticator 91ca2e6 Corrected KMP timer active check and security protocol address get 65d983f If mbedtls NIST AES KW is not enabled defined it as null algorithm 16dbe27 Added unit test stub for PAE controller a524936 Moved EAPOL relay port and IP address configuration to bootstrap 68fa4f6 Added extra debug info flags to new security libraries c4411ea Removed extra memory frees from KMP socket and eapol if and fixed KMP comments 8088a86 Added and fixed security protocols comments cc32457 Modified PAEs to use protocol core timer function call 03469f3 Modified PAE entities to be bound to interface 369c8a0 Added 4WH integrity protection and encryption ebae1d5 Added HMAC-SHA1, IEEE 802.11 PRF and NIST AES KW libraries 2d50887 Corrected Wi-SUN security component initializations 8a8b6ef Added configuration flags for supplicant and authenticator PAEs and EAPOL relay 3868ff1 PAE and security protocols timer support c61066a Corrected GKH to set eapol-KEY message group key negotation bit correctly dfe52d9 Added 4WH,GKH and EAP-TLS module and modified kmp service 782f3fb Relay message flow optimization bbd6ee1 Integrate EAPOL new encode and decode functionality 1802ee7 EAPOL message parser and write helper function. da15653 EAPOL relay and KMP changes fad633f EAPOL relay cc97054 Unicast Shedule update a099524 EAPOL authtentication start fix 3f32a7a Fix valgrind uninitilaized data use. 6e9f6a4 Corrected memory errors and some compiler warnings c5f1af3 Initial EAPOL changes e48aa79 WS: Use Tack in Ack wait time 59a65ea Change FHSS timing defaults be06ecb FHSS WS: Fixed synch parent warning a3aa38b Thread extension commission updates (#1870) 3e89d0a Multicast registrations update (#1931) e18055a MAC: Update symbol rate when RF configuration changed 9eada28 WS: Store RF configuration 35145a3 MAC: RF configuration delivery implemented d6b2bbc Merge pull request #1928 from ARMmbed/IOTTHD-3028 80683e2 MAC/WS: Implemented Ack wait duration set 0e9ead2 Remove excess tracing (#1927) ae210cd Merge pull request #1923 from ARMmbed/IOTTHD-3080 17fad47 Merge pull request #1924 from ARMmbed/IOTTHD-1608 6fd6bd5 Update thread neighbor table initialisation (#1926) c09d38a Merge pull request #1925 from ARMmbed/fix_protocol_if_fhss 9ac5301 MAC MLME: Removed BEA TX trace which was causing stack overflow 5dee7b1 FHSS: Use debug callback in TX/RX slot switch f779fad WS/Protocol: Fixed getting interface pointer using FHSS api 4177fa4 Prevalidate CoAP msg source address 5451b1a FHSS unit tests: Updated timestamp callback a2997b1 FHSS: Removed debug trace which was causing crash 3b6a921 FHSS: Debug callback update ec1c41d FHSS: Use given TX time in synch calculation f0c0f66 MAC: Write FHSS synch info with tx time 78ea0eb FHSS: Debug callbacks added c4ef759 MAC: Write FHSS synch info before calling PHY TX function 9cca341 FHSS: Use timestamp delivered by MAC be46564 Add CoAP message validation 883eb46 Add callback for CoAP message prevalidation (#1918) 59bbe31 Merge pull request #1917 from ARMmbed/IOTTHD-3029 ac4a76e Fixed promiscuous/sniffer mode bc2fb64 FHSS WS: time convert to support negative values 7dce509 FHSS WS: Clock drift compensation implemented ac7c90a Fix Thread resolution client initialisation (#1915) b744186 Set the default unicast channel function as Direct Hash 612c4b5 Update DHCP to follow Wi-SUN specification eeb5168 IPv6 route metrics update (#1912) 1debcca Fix compilation warnings noticed in mbed-os (#1909) 0a18231 Change ARO routes to be direct route instead of on-link 7fb321e Merge pull request #1906 from ARMmbed/parent_update_fix b5afc35 Fixed missing broadcast synch information loose with default zeroes. 3dbc874 Add missing closing bracket 0d746f0 Changed Wi-SUN HW type to match specification 2804bf4 Enabled roaming and routing between multiple Wi-SUN BR git-subtree-dir: features/nanostack/sal-stack-nanostack git-subtree-split: c5ee9e4e6682c4e4c23845f7b13c02d259162c36 --- .gitignore | 4 +- Makefile | 2 +- mbed_lib.json | 22 +- nanostack/dhcp_service_api.h | 2 +- nanostack/ethernet_mac_api.h | 2 +- nanostack/mlme.h | 1 + nanostack/multicast_api.h | 2 +- nanostack/net_address_extension.h | 2 +- nanostack/net_interface.h | 60 +- nanostack/net_load_balance_api.h | 2 +- nanostack/net_nvm_api.h | 2 +- nanostack/net_thread_test.h | 26 +- nanostack/net_ws_test.h | 157 ++ nanostack/ns_mdns_api.h | 2 +- nanostack/ns_sha256.h | 2 +- nanostack/platform/arm_hal_phy.h | 20 +- nanostack/serial_mac_api.h | 2 +- nanostack/socket_api.h | 2 +- nanostack/thread_commissioning_api.h | 2 +- nanostack/thread_diagcop_lib.h | 2 +- nanostack/thread_management_api.h | 2 +- nanostack/thread_meshcop_lib.h | 2 +- nanostack/ws_bbr_api.h | 93 + nanostack/ws_management_api.h | 261 ++ .../6LoWPAN/Bootstraps/Generic/network_lib.c | 4 +- .../Bootstraps/Generic/protocol_6lowpan.c | 5 +- .../Generic/protocol_6lowpan_bootstrap.c | 4 +- .../6LoWPAN/Fragmentation/cipv6_fragmenter.c | 4 +- source/6LoWPAN/IPHC_Decode/iphc_compress.c | 2 +- source/6LoWPAN/IPHC_Decode/iphc_decompress.c | 2 +- source/6LoWPAN/MAC/beacon_handler.c | 2 +- source/6LoWPAN/MAC/beacon_handler.h | 2 +- source/6LoWPAN/MAC/mac_helper.h | 4 +- source/6LoWPAN/MAC/mac_response_handler.c | 6 +- source/6LoWPAN/MAC/mac_response_handler.h | 2 +- source/6LoWPAN/Mesh/mesh.c | 4 +- source/6LoWPAN/ND/nd_defines.h | 4 +- source/6LoWPAN/ND/nd_router_object.c | 18 +- source/6LoWPAN/NVM/nwk_nvm.c | 4 +- source/6LoWPAN/Thread/thread_bbr_api.c | 2 + source/6LoWPAN/Thread/thread_beacon.c | 2 +- source/6LoWPAN/Thread/thread_beacon.h | 2 +- source/6LoWPAN/Thread/thread_bootstrap.c | 12 +- .../thread_border_router_api_internal.h | 2 +- .../6LoWPAN/Thread/thread_commissioning_api.c | 2 +- .../6LoWPAN/Thread/thread_commissioning_if.c | 2 +- source/6LoWPAN/Thread/thread_common.c | 18 +- source/6LoWPAN/Thread/thread_common.h | 6 +- source/6LoWPAN/Thread/thread_config.h | 2 +- source/6LoWPAN/Thread/thread_constants.h | 4 +- source/6LoWPAN/Thread/thread_dhcpv6_server.c | 2 +- source/6LoWPAN/Thread/thread_extension.h | 2 +- .../Thread/thread_extension_bootstrap.h | 2 +- source/6LoWPAN/Thread/thread_host_bootstrap.c | 7 +- source/6LoWPAN/Thread/thread_leader_service.c | 38 +- .../Thread/thread_lowpower_private_api.c | 2 +- source/6LoWPAN/Thread/thread_management_api.c | 2 +- source/6LoWPAN/Thread/thread_management_if.c | 25 +- .../6LoWPAN/Thread/thread_management_server.c | 97 +- .../6LoWPAN/Thread/thread_management_server.h | 2 +- source/6LoWPAN/Thread/thread_mdns.c | 2 +- source/6LoWPAN/Thread/thread_meshcop_lib.c | 2 +- .../Thread/thread_mle_message_handler.c | 6 +- source/6LoWPAN/Thread/thread_nd.c | 5 +- .../Thread/thread_network_data_storage.c | 24 +- source/6LoWPAN/Thread/thread_nvm_store.c | 4 +- .../6LoWPAN/Thread/thread_resolution_client.c | 11 +- .../6LoWPAN/Thread/thread_resolution_server.c | 2 +- .../6LoWPAN/Thread/thread_router_bootstrap.c | 17 +- source/6LoWPAN/Thread/thread_test_api.c | 46 +- source/6LoWPAN/adaptation_interface.c | 104 +- source/6LoWPAN/lowpan_adaptation_interface.h | 4 +- source/6LoWPAN/ws/ws_bbr_api.c | 488 ++++ source/6LoWPAN/ws/ws_bbr_api_internal.h | 42 + source/6LoWPAN/ws/ws_bootstrap.c | 2480 +++++++++++++++++ source/6LoWPAN/ws/ws_bootstrap.h | 9 +- source/6LoWPAN/ws/ws_common.c | 381 +++ source/6LoWPAN/ws/ws_common.h | 18 +- source/6LoWPAN/ws/ws_common_defines.h | 25 +- source/6LoWPAN/ws/ws_config.h | 124 + source/6LoWPAN/ws/ws_eapol_auth_relay.c | 205 ++ source/6LoWPAN/ws/ws_eapol_auth_relay.h | 64 + source/6LoWPAN/ws/ws_eapol_pdu.c | 315 +++ source/6LoWPAN/ws/ws_eapol_pdu.h | 145 + source/6LoWPAN/ws/ws_eapol_relay.c | 193 ++ source/6LoWPAN/ws/ws_eapol_relay.h | 70 + source/6LoWPAN/ws/ws_eapol_relay_lib.c | 53 + source/6LoWPAN/ws/ws_eapol_relay_lib.h | 23 + source/6LoWPAN/ws/ws_empty_functions.c | 185 ++ source/6LoWPAN/ws/ws_ie_lib.c | 557 ++++ source/6LoWPAN/ws/ws_ie_lib.h | 66 + source/6LoWPAN/ws/ws_llc.h | 208 ++ source/6LoWPAN/ws/ws_llc_data_service.c | 1067 +++++++ source/6LoWPAN/ws/ws_management_api.c | 262 ++ source/6LoWPAN/ws/ws_mpx_header.c | 146 + source/6LoWPAN/ws/ws_mpx_header.h | 41 + source/6LoWPAN/ws/ws_neighbor_class.c | 188 ++ source/6LoWPAN/ws/ws_neighbor_class.h | 2 +- source/6LoWPAN/ws/ws_pae_auth.c | 603 ++++ source/6LoWPAN/ws/ws_pae_auth.h | 97 + source/6LoWPAN/ws/ws_pae_controller.c | 412 +++ source/6LoWPAN/ws/ws_pae_controller.h | 236 ++ source/6LoWPAN/ws/ws_pae_lib.c | 289 ++ source/6LoWPAN/ws/ws_pae_lib.h | 271 ++ source/6LoWPAN/ws/ws_pae_nvm_data.c | 214 ++ source/6LoWPAN/ws/ws_pae_nvm_data.h | 69 + source/6LoWPAN/ws/ws_pae_nvm_store.c | 204 ++ source/6LoWPAN/ws/ws_pae_nvm_store.h | 65 + source/6LoWPAN/ws/ws_pae_supp.c | 930 +++++++ source/6LoWPAN/ws/ws_pae_supp.h | 172 ++ source/6LoWPAN/ws/ws_test_api.c | 94 + source/Common_Protocols/icmpv6.c | 35 +- source/Common_Protocols/ipv6.c | 4 +- source/Common_Protocols/ipv6_flow.c | 2 +- source/Common_Protocols/ipv6_fragmentation.c | 4 +- source/Common_Protocols/ipv6_resolution.c | 4 +- source/Common_Protocols/ipv6_resolution.h | 4 +- source/Common_Protocols/tcp.c | 4 +- source/Common_Protocols/udp.c | 4 +- source/Core/buffer_dyn.c | 6 +- .../{address.h => ns_address_internal.h} | 4 +- source/Core/include/ns_buffer.h | 4 +- source/Core/include/{socket.h => ns_socket.h} | 2 +- .../Core/{address.c => ns_address_internal.c} | 9 +- source/Core/ns_socket.c | 4 +- source/Core/sockbuf.c | 2 +- source/DHCPv6_Server/DHCPv6_Server_service.c | 3 +- source/DHCPv6_Server/DHCPv6_server_service.h | 2 +- source/DHCPv6_client/dhcpv6_client_api.h | 18 +- source/DHCPv6_client/dhcpv6_client_service.c | 70 +- source/MAC/IEEE802_15_4/mac_defines.h | 4 +- source/MAC/IEEE802_15_4/mac_fhss_callbacks.h | 2 +- .../mac_header_helper_functions.c | 9 +- source/MAC/IEEE802_15_4/mac_mcps_sap.c | 10 +- source/MAC/IEEE802_15_4/mac_mlme.c | 51 +- source/MAC/IEEE802_15_4/mac_pd_sap.c | 26 +- source/MAC/IEEE802_15_4/mac_security_mib.c | 2 +- source/MAC/IEEE802_15_4/mac_security_mib.h | 2 +- source/MAC/ethernet/ethernet_mac_api.c | 2 +- source/MAC/rf_driver_storage.c | 2 +- source/MAC/rf_driver_storage.h | 2 +- source/MAC/serial/serial_mac_api.c | 2 +- source/MAC/virtual_rf/virtual_rf_client.c | 4 +- source/MAC/virtual_rf/virtual_rf_driver.c | 18 +- source/MLE/mle.c | 4 +- source/MLE/mle.h | 4 +- source/MLE/mle_tlv.c | 2 +- source/NWK_INTERFACE/Include/protocol.h | 4 +- source/NWK_INTERFACE/protocol_core.c | 12 +- source/NWK_INTERFACE/protocol_timer.c | 2 +- source/RPL/rpl_control.c | 29 +- source/RPL/rpl_control.h | 5 +- source/RPL/rpl_downward.c | 3 +- source/RPL/rpl_mrhof.c | 2 +- source/RPL/rpl_objective.h | 2 +- source/RPL/rpl_of0.c | 2 +- source/RPL/rpl_policy.c | 4 +- source/RPL/rpl_policy.h | 4 +- source/RPL/rpl_structures.h | 2 +- source/RPL/rpl_upward.c | 27 +- source/RPL/rpl_upward.h | 4 +- source/Security/Common/sec_lib.h | 2 +- source/Security/Common/sec_lib_definitions.h | 2 +- source/Security/Common/security_lib.c | 4 +- source/Security/PANA/eap_protocol.c | 4 +- source/Security/PANA/pana.c | 4 +- source/Security/PANA/pana.h | 2 +- source/Security/PANA/pana_avp.c | 2 +- source/Security/PANA/pana_avp.h | 2 +- source/Security/PANA/pana_client.c | 4 +- source/Security/PANA/pana_eap_header.c | 4 +- source/Security/PANA/pana_eap_header.h | 6 +- source/Security/PANA/pana_internal_api.h | 2 +- source/Security/PANA/pana_server.c | 6 +- source/Security/TLS/tls_ccm_crypt.h | 2 +- source/Security/TLS/tls_lib.c | 6 +- source/Security/TLS/tls_lib.h | 2 +- source/Security/eapol/eapol_helper.c | 278 ++ source/Security/eapol/eapol_helper.h | 99 + source/Security/eapol/kde_helper.c | 244 ++ source/Security/eapol/kde_helper.h | 172 ++ source/Security/kmp/kmp_addr.c | 177 ++ source/Security/kmp/kmp_addr.h | 138 + source/Security/kmp/kmp_api.c | 508 ++++ source/Security/kmp/kmp_api.h | 457 +++ source/Security/kmp/kmp_eapol_pdu_if.c | 164 ++ source/Security/kmp/kmp_eapol_pdu_if.h | 62 + source/Security/kmp/kmp_socket_if.c | 204 ++ source/Security/kmp/kmp_socket_if.h | 57 + .../eap_tls_sec_prot/auth_eap_tls_sec_prot.c | 521 ++++ .../eap_tls_sec_prot/auth_eap_tls_sec_prot.h | 36 + .../eap_tls_sec_prot/eap_tls_sec_prot_lib.c | 230 ++ .../eap_tls_sec_prot/eap_tls_sec_prot_lib.h | 122 + .../eap_tls_sec_prot/supp_eap_tls_sec_prot.c | 516 ++++ .../eap_tls_sec_prot/supp_eap_tls_sec_prot.h | 37 + .../fwh_sec_prot/auth_fwh_sec_prot.c | 436 +++ .../fwh_sec_prot/auth_fwh_sec_prot.h | 37 + .../fwh_sec_prot/supp_fwh_sec_prot.c | 528 ++++ .../fwh_sec_prot/supp_fwh_sec_prot.h | 37 + .../gkh_sec_prot/auth_gkh_sec_prot.c | 329 +++ .../gkh_sec_prot/auth_gkh_sec_prot.h | 31 + .../gkh_sec_prot/supp_gkh_sec_prot.c | 319 +++ .../gkh_sec_prot/supp_gkh_sec_prot.h | 31 + .../protocols/key_sec_prot/key_sec_prot.c | 239 ++ .../protocols/key_sec_prot/key_sec_prot.h | 38 + source/Security/protocols/sec_prot.h | 241 ++ source/Security/protocols/sec_prot_certs.c | 179 ++ source/Security/protocols/sec_prot_certs.h | 207 ++ source/Security/protocols/sec_prot_keys.c | 305 ++ source/Security/protocols/sec_prot_keys.h | 393 +++ source/Security/protocols/sec_prot_lib.c | 488 ++++ source/Security/protocols/sec_prot_lib.h | 291 ++ .../protocols/tls_sec_prot/tls_sec_prot.c | 551 ++++ .../protocols/tls_sec_prot/tls_sec_prot.h | 49 + .../protocols/tls_sec_prot/tls_sec_prot_lib.c | 442 +++ .../protocols/tls_sec_prot/tls_sec_prot_lib.h | 169 ++ .../Service_Libs/CCM_lib/mbedOS/aes_mbedtls.c | 2 +- .../CCM_lib/mbedOS/aes_mbedtls_adapter.c | 6 +- .../Neighbor_cache/neighbor_cache.c | 2 +- source/Service_Libs/SHA256_Lib/ns_sha256.c | 2 +- source/Service_Libs/Trickle/trickle.c | 2 +- source/Service_Libs/blacklist/blacklist.c | 2 +- source/Service_Libs/etx/etx.c | 4 +- source/Service_Libs/fhss/channel_functions.c | 229 ++ source/Service_Libs/fhss/fhss.c | 29 +- source/Service_Libs/fhss/fhss_channel.c | 29 +- source/Service_Libs/fhss/fhss_channel.h | 16 +- source/Service_Libs/fhss/fhss_ws.c | 844 ++++++ source/Service_Libs/fhss/fhss_ws.h | 3 + .../fhss/fhss_ws_empty_functions.c | 1 + source/Service_Libs/hmac/hmac_sha1.c | 78 + source/Service_Libs/hmac/hmac_sha1.h | 38 + source/Service_Libs/ieee_802_11/ieee_802_11.c | 77 + source/Service_Libs/ieee_802_11/ieee_802_11.h | 129 + .../Service_Libs/load_balance/load_balance.c | 2 +- .../load_balance/load_balance_api.h | 2 +- .../mac_neighbor_table/mac_neighbor_table.c | 4 +- source/Service_Libs/mdns/ns_fnet_events.c | 2 +- source/Service_Libs/mdns/ns_fnet_port.c | 4 +- source/Service_Libs/mdns/ns_mdns_api.c | 2 +- source/Service_Libs/mle_service/mle_service.c | 9 +- .../mle_service/mle_service_api.h | 4 +- .../mle_service/mle_service_buffer.c | 2 +- .../mle_service/mle_service_buffer.h | 2 +- .../mle_service_frame_counter_table.c | 4 +- .../mle_service/mle_service_security.c | 4 +- .../mle_service/mle_service_security.h | 2 +- source/Service_Libs/nist_aes_kw/nist_aes_kw.c | 116 + source/Service_Libs/nist_aes_kw/nist_aes_kw.h | 38 + .../pan_blacklist/pan_blacklist.c | 2 +- source/Service_Libs/utils/isqrt.c | 2 +- source/Service_Libs/utils/isqrt.h | 2 +- source/Service_Libs/utils/ns_crc.c | 2 +- source/Service_Libs/utils/ns_crc.h | 2 +- source/Service_Libs/utils/ns_file_system.c | 2 +- source/Service_Libs/whiteboard/whiteboard.c | 2 +- source/Service_Libs/whiteboard/whiteboard.h | 3 +- source/configs/base/cfg_ws_border_router.h | 26 + source/configs/base/cfg_ws_router.h | 24 + source/configs/cfg_generic.h | 7 +- source/configs/cfg_ws_border_router.h | 28 + source/configs/cfg_ws_router.h | 23 + source/ipv6_stack/ipv6_routing_table.c | 20 +- source/ipv6_stack/ipv6_routing_table.h | 6 +- source/ipv6_stack/protocol_ipv6.c | 4 +- source/libDHCPv6/libDHCPv6.c | 15 +- source/libDHCPv6/libDHCPv6.h | 5 +- source/libDHCPv6/libDHCPv6_server.c | 11 +- source/libDHCPv6/libDHCPv6_server.h | 2 +- source/libNET/src/net_ipv6.c | 4 +- source/libNET/src/net_load_balance.c | 8 +- source/libNET/src/net_mle.c | 4 +- source/libNET/src/net_rpl.c | 9 +- source/libNET/src/ns_net.c | 49 +- source/libNET/src/socket_api.c | 4 +- source/nsconfig.h | 7 +- sources.mk | 46 +- 277 files changed, 23626 insertions(+), 446 deletions(-) create mode 100644 nanostack/net_ws_test.h create mode 100644 nanostack/ws_bbr_api.h create mode 100644 nanostack/ws_management_api.h create mode 100644 source/6LoWPAN/ws/ws_bbr_api.c create mode 100644 source/6LoWPAN/ws/ws_bbr_api_internal.h create mode 100644 source/6LoWPAN/ws/ws_bootstrap.c create mode 100644 source/6LoWPAN/ws/ws_common.c create mode 100644 source/6LoWPAN/ws/ws_config.h create mode 100644 source/6LoWPAN/ws/ws_eapol_auth_relay.c create mode 100644 source/6LoWPAN/ws/ws_eapol_auth_relay.h create mode 100644 source/6LoWPAN/ws/ws_eapol_pdu.c create mode 100644 source/6LoWPAN/ws/ws_eapol_pdu.h create mode 100644 source/6LoWPAN/ws/ws_eapol_relay.c create mode 100644 source/6LoWPAN/ws/ws_eapol_relay.h create mode 100644 source/6LoWPAN/ws/ws_eapol_relay_lib.c create mode 100644 source/6LoWPAN/ws/ws_eapol_relay_lib.h create mode 100644 source/6LoWPAN/ws/ws_empty_functions.c create mode 100644 source/6LoWPAN/ws/ws_ie_lib.c create mode 100644 source/6LoWPAN/ws/ws_ie_lib.h create mode 100644 source/6LoWPAN/ws/ws_llc.h create mode 100644 source/6LoWPAN/ws/ws_llc_data_service.c create mode 100644 source/6LoWPAN/ws/ws_management_api.c create mode 100644 source/6LoWPAN/ws/ws_mpx_header.c create mode 100644 source/6LoWPAN/ws/ws_mpx_header.h create mode 100644 source/6LoWPAN/ws/ws_neighbor_class.c create mode 100644 source/6LoWPAN/ws/ws_pae_auth.c create mode 100644 source/6LoWPAN/ws/ws_pae_auth.h create mode 100644 source/6LoWPAN/ws/ws_pae_controller.c create mode 100644 source/6LoWPAN/ws/ws_pae_controller.h create mode 100644 source/6LoWPAN/ws/ws_pae_lib.c create mode 100644 source/6LoWPAN/ws/ws_pae_lib.h create mode 100644 source/6LoWPAN/ws/ws_pae_nvm_data.c create mode 100644 source/6LoWPAN/ws/ws_pae_nvm_data.h create mode 100644 source/6LoWPAN/ws/ws_pae_nvm_store.c create mode 100644 source/6LoWPAN/ws/ws_pae_nvm_store.h create mode 100644 source/6LoWPAN/ws/ws_pae_supp.c create mode 100644 source/6LoWPAN/ws/ws_pae_supp.h create mode 100644 source/6LoWPAN/ws/ws_test_api.c rename source/Core/include/{address.h => ns_address_internal.h} (99%) rename source/Core/include/{socket.h => ns_socket.h} (99%) rename source/Core/{address.c => ns_address_internal.c} (99%) create mode 100644 source/Security/eapol/eapol_helper.c create mode 100644 source/Security/eapol/eapol_helper.h create mode 100644 source/Security/eapol/kde_helper.c create mode 100644 source/Security/eapol/kde_helper.h create mode 100644 source/Security/kmp/kmp_addr.c create mode 100644 source/Security/kmp/kmp_addr.h create mode 100644 source/Security/kmp/kmp_api.c create mode 100644 source/Security/kmp/kmp_api.h create mode 100644 source/Security/kmp/kmp_eapol_pdu_if.c create mode 100644 source/Security/kmp/kmp_eapol_pdu_if.h create mode 100644 source/Security/kmp/kmp_socket_if.c create mode 100644 source/Security/kmp/kmp_socket_if.h create mode 100644 source/Security/protocols/eap_tls_sec_prot/auth_eap_tls_sec_prot.c create mode 100644 source/Security/protocols/eap_tls_sec_prot/auth_eap_tls_sec_prot.h create mode 100644 source/Security/protocols/eap_tls_sec_prot/eap_tls_sec_prot_lib.c create mode 100644 source/Security/protocols/eap_tls_sec_prot/eap_tls_sec_prot_lib.h create mode 100644 source/Security/protocols/eap_tls_sec_prot/supp_eap_tls_sec_prot.c create mode 100644 source/Security/protocols/eap_tls_sec_prot/supp_eap_tls_sec_prot.h create mode 100644 source/Security/protocols/fwh_sec_prot/auth_fwh_sec_prot.c create mode 100644 source/Security/protocols/fwh_sec_prot/auth_fwh_sec_prot.h create mode 100644 source/Security/protocols/fwh_sec_prot/supp_fwh_sec_prot.c create mode 100644 source/Security/protocols/fwh_sec_prot/supp_fwh_sec_prot.h create mode 100644 source/Security/protocols/gkh_sec_prot/auth_gkh_sec_prot.c create mode 100644 source/Security/protocols/gkh_sec_prot/auth_gkh_sec_prot.h create mode 100644 source/Security/protocols/gkh_sec_prot/supp_gkh_sec_prot.c create mode 100644 source/Security/protocols/gkh_sec_prot/supp_gkh_sec_prot.h create mode 100644 source/Security/protocols/key_sec_prot/key_sec_prot.c create mode 100644 source/Security/protocols/key_sec_prot/key_sec_prot.h create mode 100644 source/Security/protocols/sec_prot.h create mode 100644 source/Security/protocols/sec_prot_certs.c create mode 100644 source/Security/protocols/sec_prot_certs.h create mode 100644 source/Security/protocols/sec_prot_keys.c create mode 100644 source/Security/protocols/sec_prot_keys.h create mode 100644 source/Security/protocols/sec_prot_lib.c create mode 100644 source/Security/protocols/sec_prot_lib.h create mode 100644 source/Security/protocols/tls_sec_prot/tls_sec_prot.c create mode 100644 source/Security/protocols/tls_sec_prot/tls_sec_prot.h create mode 100644 source/Security/protocols/tls_sec_prot/tls_sec_prot_lib.c create mode 100644 source/Security/protocols/tls_sec_prot/tls_sec_prot_lib.h create mode 100644 source/Service_Libs/fhss/channel_functions.c create mode 100644 source/Service_Libs/fhss/fhss_ws.c create mode 100644 source/Service_Libs/hmac/hmac_sha1.c create mode 100644 source/Service_Libs/hmac/hmac_sha1.h create mode 100644 source/Service_Libs/ieee_802_11/ieee_802_11.c create mode 100644 source/Service_Libs/ieee_802_11/ieee_802_11.h create mode 100644 source/Service_Libs/nist_aes_kw/nist_aes_kw.c create mode 100644 source/Service_Libs/nist_aes_kw/nist_aes_kw.h create mode 100644 source/configs/base/cfg_ws_border_router.h create mode 100644 source/configs/base/cfg_ws_router.h create mode 100644 source/configs/cfg_ws_border_router.h create mode 100644 source/configs/cfg_ws_router.h diff --git a/.gitignore b/.gitignore index bfdcfcbd4f..0730e7a544 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,4 @@ .settings/ -.yotta.json *.dep *.htm *.crf @@ -66,8 +65,7 @@ cscope.files !debugger.ini *Log.txt *.mpw -yotta_modules -yotta_targets build html site + diff --git a/Makefile b/Makefile index addfc4bff1..67d9d854d1 100644 --- a/Makefile +++ b/Makefile @@ -109,7 +109,7 @@ clean-extra: $(CLEANTESTDIRS) # 3. TBD: importing to mbed OS TARGET_DIR:=release -CONFIGURATIONS_TO_BUILD:=lowpan_border_router lowpan_host lowpan_router nanostack_full thread_border_router thread_router thread_end_device ethernet_host +CONFIGURATIONS_TO_BUILD:=lowpan_border_router lowpan_host lowpan_router nanostack_full thread_border_router thread_router thread_end_device ethernet_host ws_border_router ws_router TOOLCHAINS_TO_BUILD:=GCC ARM ARMC6 IAR CORES_TO_BUILD:=Cortex-M0 Cortex-M3 diff --git a/mbed_lib.json b/mbed_lib.json index ba94bfbc7d..6640b5e3ef 100644 --- a/mbed_lib.json +++ b/mbed_lib.json @@ -1,7 +1,25 @@ { "name": "nanostack", + "requires": ["nanostack-eventloop", "coap-service"], "config": { - "configuration": "nanostack_full" + "configuration": { + "help": "Build time configuration. Refer to Handbook for valid values. Default: full stack", + "value": "nanostack_full" + } }, - "macros": ["NS_USE_EXTERNAL_MBED_TLS"] + "macros": ["NS_USE_EXTERNAL_MBED_TLS"], + "target_overrides": { + "KW24D": { + "nanostack.configuration": "lowpan_router" + }, + "NCS36510": { + "nanostack.configuration": "lowpan_router" + }, + "TB_SENSE_12": { + "nanostack.configuration": "lowpan_router" + }, + "KW41Z": { + "nanostack.configuration": "lowpan_router" + } + } } diff --git a/nanostack/dhcp_service_api.h b/nanostack/dhcp_service_api.h index 992977a046..5bdce7b35d 100644 --- a/nanostack/dhcp_service_api.h +++ b/nanostack/dhcp_service_api.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2017, Arm Limited and affiliates. + * Copyright (c) 2013-2018, Arm Limited and affiliates. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/nanostack/ethernet_mac_api.h b/nanostack/ethernet_mac_api.h index bc5bd828bb..0e83cadfa1 100644 --- a/nanostack/ethernet_mac_api.h +++ b/nanostack/ethernet_mac_api.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2017, Arm Limited and affiliates. + * Copyright (c) 2016-2018, Arm Limited and affiliates. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/nanostack/mlme.h b/nanostack/mlme.h index dbe32537ae..5db31f7c3d 100644 --- a/nanostack/mlme.h +++ b/nanostack/mlme.h @@ -264,6 +264,7 @@ typedef enum { macAutoRequestKeyIndex = 0x7b, /* -#include "Core/include/socket.h" +#include "Core/include/ns_socket.h" #include "nsdynmemLIB.h" #include "ns_trace.h" #include "NWK_INTERFACE/Include/protocol.h" diff --git a/source/6LoWPAN/Bootstraps/Generic/protocol_6lowpan.c b/source/6LoWPAN/Bootstraps/Generic/protocol_6lowpan.c index 683f3849b9..1a1d7a5545 100644 --- a/source/6LoWPAN/Bootstraps/Generic/protocol_6lowpan.c +++ b/source/6LoWPAN/Bootstraps/Generic/protocol_6lowpan.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2018, Arm Limited and affiliates. + * Copyright (c) 2013-2019, Arm Limited and affiliates. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -22,7 +22,7 @@ #include "eventOS_scheduler.h" #include "ns_trace.h" #include "nsdynmemLIB.h" -#include "Core/include/socket.h" +#include "Core/include/ns_socket.h" #include "NWK_INTERFACE/Include/protocol.h" #include "Common_Protocols/udp.h" #include "Common_Protocols/ipv6.h" @@ -373,6 +373,7 @@ void protocol_6lowpan_configure_core(protocol_interface_info_entry_t *cur) cur->ipv6_neighbour_cache.link_mtu = LOWPAN_MTU; #ifdef HAVE_6LOWPAN_ND cur->ipv6_neighbour_cache.send_nud_probes = nd_params.send_nud_probes; + cur->ipv6_neighbour_cache.probe_avoided_routers = nd_params.send_nud_probes; cur->iids_map_to_mac = nd_params.iids_map_to_mac; #endif cur->ip_multicast_as_mac_unicast_to_parent = false; diff --git a/source/6LoWPAN/Bootstraps/Generic/protocol_6lowpan_bootstrap.c b/source/6LoWPAN/Bootstraps/Generic/protocol_6lowpan_bootstrap.c index 1e0aff1179..5f3f17becc 100644 --- a/source/6LoWPAN/Bootstraps/Generic/protocol_6lowpan_bootstrap.c +++ b/source/6LoWPAN/Bootstraps/Generic/protocol_6lowpan_bootstrap.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2018, Arm Limited and affiliates. + * Copyright (c) 2015-2019, Arm Limited and affiliates. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -1408,6 +1408,8 @@ static void lowpan_mle_receive_security_bypass_cb(int8_t interface_id, mle_messa pana_reset_client_session(); bootsrap_next_state_kick(ER_PANA_AUTH_ERROR, interface); } +#else + (void)mle_msg; #endif } diff --git a/source/6LoWPAN/Fragmentation/cipv6_fragmenter.c b/source/6LoWPAN/Fragmentation/cipv6_fragmenter.c index 1c9879ce5d..df2b4404e3 100644 --- a/source/6LoWPAN/Fragmentation/cipv6_fragmenter.c +++ b/source/6LoWPAN/Fragmentation/cipv6_fragmenter.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2017, Arm Limited and affiliates. + * Copyright (c) 2013-2019, Arm Limited and affiliates. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -26,7 +26,7 @@ #include "string.h" #include "ns_trace.h" #include "randLIB.h" -#include "Core/include/socket.h" +#include "Core/include/ns_socket.h" #include "6LoWPAN/IPHC_Decode/cipv6.h" #include "6LoWPAN/Fragmentation/cipv6_fragmenter.h" #include "NWK_INTERFACE/Include/protocol.h" diff --git a/source/6LoWPAN/IPHC_Decode/iphc_compress.c b/source/6LoWPAN/IPHC_Decode/iphc_compress.c index 6ebee21c34..735955aca9 100644 --- a/source/6LoWPAN/IPHC_Decode/iphc_compress.c +++ b/source/6LoWPAN/IPHC_Decode/iphc_compress.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014-2017, Arm Limited and affiliates. + * Copyright (c) 2014-2018, Arm Limited and affiliates. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/source/6LoWPAN/IPHC_Decode/iphc_decompress.c b/source/6LoWPAN/IPHC_Decode/iphc_decompress.c index c6c475b830..8b584297e1 100644 --- a/source/6LoWPAN/IPHC_Decode/iphc_decompress.c +++ b/source/6LoWPAN/IPHC_Decode/iphc_decompress.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014-2017, Arm Limited and affiliates. + * Copyright (c) 2014-2018, Arm Limited and affiliates. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/source/6LoWPAN/MAC/beacon_handler.c b/source/6LoWPAN/MAC/beacon_handler.c index 1c595294fa..34c7b3c98b 100644 --- a/source/6LoWPAN/MAC/beacon_handler.c +++ b/source/6LoWPAN/MAC/beacon_handler.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2017, Arm Limited and affiliates. + * Copyright (c) 2016-2018, Arm Limited and affiliates. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/source/6LoWPAN/MAC/beacon_handler.h b/source/6LoWPAN/MAC/beacon_handler.h index 664d613d68..c08680f60f 100644 --- a/source/6LoWPAN/MAC/beacon_handler.h +++ b/source/6LoWPAN/MAC/beacon_handler.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2017, Arm Limited and affiliates. + * Copyright (c) 2016-2018, Arm Limited and affiliates. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/source/6LoWPAN/MAC/mac_helper.h b/source/6LoWPAN/MAC/mac_helper.h index dece92c5c7..8bc04f7e04 100644 --- a/source/6LoWPAN/MAC/mac_helper.h +++ b/source/6LoWPAN/MAC/mac_helper.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2018, Arm Limited and affiliates. + * Copyright (c) 2016-2019, Arm Limited and affiliates. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -19,7 +19,7 @@ #define MAC_HELPER_H #include "mlme.h" -#include "Core/include/address.h" +#include "Core/include/ns_address_internal.h" struct channel_list_s; struct nwk_scan_params; diff --git a/source/6LoWPAN/MAC/mac_response_handler.c b/source/6LoWPAN/MAC/mac_response_handler.c index eb5bfcb2a2..1c89a92578 100644 --- a/source/6LoWPAN/MAC/mac_response_handler.c +++ b/source/6LoWPAN/MAC/mac_response_handler.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2018, Arm Limited and affiliates. + * Copyright (c) 2016-2019, Arm Limited and affiliates. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -22,8 +22,8 @@ #include "NWK_INTERFACE/Include/protocol_abstract.h" #include "NWK_INTERFACE/Include/protocol_timer.h" #include "Service_Libs/mle_service/mle_service_api.h" -#include "Core/include/address.h" -#include "Core/include/socket.h" +#include "Core/include/ns_address_internal.h" +#include "Core/include/ns_socket.h" #include "6LoWPAN/Thread/thread_common.h" #include "6LoWPAN/Thread/thread_management_internal.h" #include "6LoWPAN/MAC/mac_helper.h" diff --git a/source/6LoWPAN/MAC/mac_response_handler.h b/source/6LoWPAN/MAC/mac_response_handler.h index 96e8e7f4b7..dc58042ee7 100644 --- a/source/6LoWPAN/MAC/mac_response_handler.h +++ b/source/6LoWPAN/MAC/mac_response_handler.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2017, Arm Limited and affiliates. + * Copyright (c) 2016-2018, Arm Limited and affiliates. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/source/6LoWPAN/Mesh/mesh.c b/source/6LoWPAN/Mesh/mesh.c index 16c74e41ac..4cdbbb138c 100644 --- a/source/6LoWPAN/Mesh/mesh.c +++ b/source/6LoWPAN/Mesh/mesh.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014-2017, Arm Limited and affiliates. + * Copyright (c) 2014-2017, 2019, Arm Limited and affiliates. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -29,7 +29,7 @@ #include "NWK_INTERFACE/Include/protocol.h" #include "NWK_INTERFACE/Include/protocol_stats.h" #include "6LoWPAN/IPHC_Decode/cipv6.h" -#include "Core/include/socket.h" +#include "Core/include/ns_socket.h" #include "6LoWPAN/Mesh/mesh.h" #include "6LoWPAN/MAC/mac_helper.h" diff --git a/source/6LoWPAN/ND/nd_defines.h b/source/6LoWPAN/ND/nd_defines.h index ec23632c9d..6cc37bd17c 100644 --- a/source/6LoWPAN/ND/nd_defines.h +++ b/source/6LoWPAN/ND/nd_defines.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014-2017, Arm Limited and affiliates. + * Copyright (c) 2014-2017, 2019, Arm Limited and affiliates. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -18,7 +18,7 @@ #ifndef ND_DEFINES_H_ #define ND_DEFINES_H_ -#include "Core/include/address.h" +#include "Core/include/ns_address_internal.h" #include "ns_list.h" #include "6LoWPAN/IPHC_Decode/lowpan_context.h" #include "Common_Protocols/icmpv6_prefix.h" diff --git a/source/6LoWPAN/ND/nd_router_object.c b/source/6LoWPAN/ND/nd_router_object.c index b6399d3a73..e53119bb89 100644 --- a/source/6LoWPAN/ND/nd_router_object.c +++ b/source/6LoWPAN/ND/nd_router_object.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2018, Arm Limited and affiliates. + * Copyright (c) 2013-2019, Arm Limited and affiliates. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -831,6 +831,8 @@ buffer_t *nd_dar_parse(buffer_t *buf, protocol_interface_info_entry_t *cur_inter } drop: +#else + (void)cur_interface; #endif return buffer_free(buf); @@ -845,7 +847,7 @@ static void nd_update_registration(protocol_interface_info_entry_t *cur_interfac neigh->lifetime = aro->lifetime * UINT32_C(60); ipv6_neighbour_set_state(&cur_interface->ipv6_neighbour_cache, neigh, IP_NEIGHBOUR_STALE); /* Register with 2 seconds off the lifetime - don't want the NCE to expire before the route */ - ipv6_route_add(neigh->ip_address, 128, cur_interface->id, NULL, ROUTE_ARO, neigh->lifetime - 2, 0); + ipv6_route_add_metric(neigh->ip_address, 128, cur_interface->id, neigh->ip_address, ROUTE_ARO, NULL, 0, neigh->lifetime - 2, 32); /* We need to know peer is a host before publishing - this needs MLE. Not yet established * what to do without MLE - might need special external/non-external prioritisation at root. @@ -864,19 +866,19 @@ static void nd_update_registration(protocol_interface_info_entry_t *cur_interfac neigh->type = IP_NEIGHBOUR_TENTATIVE; neigh->lifetime = 2; ipv6_neighbour_set_state(&cur_interface->ipv6_neighbour_cache, neigh, IP_NEIGHBOUR_STALE); - ipv6_route_add(neigh->ip_address, 128, cur_interface->id, NULL, ROUTE_ARO, 4, 0); + ipv6_route_add_metric(neigh->ip_address, 128, cur_interface->id, neigh->ip_address, ROUTE_ARO, NULL, 0, 4, 32); rpl_control_unpublish_address(protocol_6lowpan_rpl_domain, neigh->ip_address); } } void nd_remove_registration(protocol_interface_info_entry_t *cur_interface, addrtype_t ll_type, const uint8_t *ll_address) { - ns_list_foreach_safe(ipv6_neighbour_t, cur, &cur_interface->ipv6_neighbour_cache.list) { if ((cur->type == IP_NEIGHBOUR_REGISTERED || cur->type == IP_NEIGHBOUR_TENTATIVE) && ipv6_neighbour_ll_addr_match(cur, ll_type, ll_address)) { - ipv6_route_delete(cur->ip_address, 128, cur_interface->id, NULL, + + ipv6_route_delete(cur->ip_address, 128, cur_interface->id, cur->ip_address, ROUTE_ARO); ipv6_neighbour_entry_remove(&cur_interface->ipv6_neighbour_cache, cur); @@ -923,6 +925,12 @@ bool nd_ns_aro_handler(protocol_interface_info_entry_t *cur_interface, const uin } /* TODO - check hard upper limit on registrations? */ + if (ws_info(cur_interface) && + !ws_common_allow_child_registration(cur_interface)) { + aro_out->present = true; + aro_out->status = ARO_FULL; + return true; + } /* We need to have entry in the Neighbour Cache */ ipv6_neighbour_t *neigh = ipv6_neighbour_lookup_or_create(&cur_interface->ipv6_neighbour_cache, src_addr); diff --git a/source/6LoWPAN/NVM/nwk_nvm.c b/source/6LoWPAN/NVM/nwk_nvm.c index d4badef577..1da43f28cf 100644 --- a/source/6LoWPAN/NVM/nwk_nvm.c +++ b/source/6LoWPAN/NVM/nwk_nvm.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, Arm Limited and affiliates. + * Copyright (c) 2017-2019, Arm Limited and affiliates. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -22,7 +22,7 @@ #include "string.h" #include "randLIB.h" #include "nsdynmemLIB.h" -#include "Core/include/socket.h" +#include "Core/include/ns_socket.h" #include "NWK_INTERFACE/Include/protocol.h" #include "6LoWPAN/MAC/mac_helper.h" #include "6LoWPAN/NVM/nwk_nvm.h" diff --git a/source/6LoWPAN/Thread/thread_bbr_api.c b/source/6LoWPAN/Thread/thread_bbr_api.c index 1b02085e85..da53a45684 100644 --- a/source/6LoWPAN/Thread/thread_bbr_api.c +++ b/source/6LoWPAN/Thread/thread_bbr_api.c @@ -757,6 +757,7 @@ bool thread_bbr_routing_enabled(protocol_interface_info_entry_t *cur) void thread_bbr_network_data_update_notify(protocol_interface_info_entry_t *cur) { + (void)cur; thread_mdns_network_data_update_notify(); thread_extension_bbr_route_update(cur); } @@ -1000,6 +1001,7 @@ int thread_bbr_dua_entry_add(int8_t interface_id, const uint8_t *addr_data_ptr, // Route info autofreed route->info_autofree = true; } + route->lifetime = lifetime; // update lifetime also from old route map = route->info.info; memcpy(map->mleid_ptr, mleid_ptr, 8); map->last_contact_time = protocol_core_monotonic_time; diff --git a/source/6LoWPAN/Thread/thread_beacon.c b/source/6LoWPAN/Thread/thread_beacon.c index 56a6d2fa9d..115cf02134 100644 --- a/source/6LoWPAN/Thread/thread_beacon.c +++ b/source/6LoWPAN/Thread/thread_beacon.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2017, Arm Limited and affiliates. + * Copyright (c) 2015-2019, Arm Limited and affiliates. * SPDX-License-Identifier: BSD-3-Clause * * Redistribution and use in source and binary forms, with or without diff --git a/source/6LoWPAN/Thread/thread_beacon.h b/source/6LoWPAN/Thread/thread_beacon.h index 5c0ee94421..bd50f1a15a 100644 --- a/source/6LoWPAN/Thread/thread_beacon.h +++ b/source/6LoWPAN/Thread/thread_beacon.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2017, Arm Limited and affiliates. + * Copyright (c) 2015-2019, Arm Limited and affiliates. * SPDX-License-Identifier: BSD-3-Clause * * Redistribution and use in source and binary forms, with or without diff --git a/source/6LoWPAN/Thread/thread_bootstrap.c b/source/6LoWPAN/Thread/thread_bootstrap.c index ddcdca0c19..38e900c4c3 100644 --- a/source/6LoWPAN/Thread/thread_bootstrap.c +++ b/source/6LoWPAN/Thread/thread_bootstrap.c @@ -902,6 +902,7 @@ void thread_interface_init(protocol_interface_info_entry_t *cur) cur->if_snoop = thread_nd_snoop; cur->if_icmp_handler = thread_nd_icmp_handler; cur->ipv6_neighbour_cache.send_nud_probes = false; + cur->ipv6_neighbour_cache.probe_avoided_routers = false; cur->ipv6_neighbour_cache.recv_addr_reg = true; cur->send_mld = false; cur->ip_multicast_as_mac_unicast_to_parent = true; @@ -1514,6 +1515,7 @@ int thread_bootstrap_reset(protocol_interface_info_entry_t *cur) cur->thread_info->thread_attached_state = THREAD_STATE_NETWORK_DISCOVER; } cur->ipv6_neighbour_cache.send_nud_probes = false; //Disable NUD probing + cur->ipv6_neighbour_cache.probe_avoided_routers = false; cur->ip_multicast_as_mac_unicast_to_parent = true; //Define Default Contexts if (cur->thread_info->thread_device_mode == THREAD_DEVICE_MODE_SLEEPY_END_DEVICE) { @@ -2726,7 +2728,7 @@ int thread_bootstrap_network_data_activate(protocol_interface_info_entry_t *cur) thread_border_router_network_data_update_notify(cur); thread_bbr_network_data_update_notify(cur); - thread_maintenance_timer_set(cur, THREAD_MAINTENANCE_TIMER_INTERVAL); + thread_maintenance_timer_set(cur); return 0; } @@ -2846,7 +2848,7 @@ void thread_bootstrap_network_prefixes_process(protocol_interface_info_entry_t * thread_addr_write_mesh_local_16(addr, curBorderRouter->routerID, cur->thread_info); /* Do not allow multiple DHCP solicits from one prefix => delete previous */ dhcp_client_global_address_delete(cur->id, NULL, curPrefix->servicesPrefix); - if (dhcp_client_get_global_address(cur->id, addr, curPrefix->servicesPrefix, cur->mac, thread_dhcp_client_gua_error_cb) == 0) { + if (dhcp_client_get_global_address(cur->id, addr, curPrefix->servicesPrefix, cur->mac, DHCPV6_DUID_HARDWARE_EUI64_TYPE, thread_dhcp_client_gua_error_cb) == 0) { tr_debug("GP Address Requested"); } } @@ -2856,8 +2858,8 @@ void thread_bootstrap_network_prefixes_process(protocol_interface_info_entry_t * if ((cur->bootsrap_mode == ARM_NWK_BOOTSRAP_MODE_6LoWPAN_HOST || cur->bootsrap_mode == ARM_NWK_BOOTSRAP_MODE_6LoWPAN_SLEEPY_HOST) && cur->thread_info->requestFullNetworkData == false) { + tr_debug("Invalidate router ID: %04x", curBorderRouter->routerID); curBorderRouter->routerID = 0xfffe; - tr_debug("Invalidated router ID: %04x", curBorderRouter->routerID); } } @@ -2868,7 +2870,9 @@ void thread_bootstrap_network_prefixes_process(protocol_interface_info_entry_t * } // generate address based on res1 bit if (curBorderRouter->P_res1) { - thread_extension_dua_address_generate(cur, curPrefix->servicesPrefix, 64); + if (!thread_dhcpv6_address_entry_available(curPrefix->servicesPrefix, &cur->ip_addresses)) { + thread_extension_dua_address_generate(cur, curPrefix->servicesPrefix, 64); + } } } // for each borderRouterList diff --git a/source/6LoWPAN/Thread/thread_border_router_api_internal.h b/source/6LoWPAN/Thread/thread_border_router_api_internal.h index c1227173dd..53db69b22b 100644 --- a/source/6LoWPAN/Thread/thread_border_router_api_internal.h +++ b/source/6LoWPAN/Thread/thread_border_router_api_internal.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2017, Arm Limited and affiliates. + * Copyright (c) 2016-2019, Arm Limited and affiliates. * SPDX-License-Identifier: BSD-3-Clause * * Redistribution and use in source and binary forms, with or without diff --git a/source/6LoWPAN/Thread/thread_commissioning_api.c b/source/6LoWPAN/Thread/thread_commissioning_api.c index fd339dc755..2b498bb151 100644 --- a/source/6LoWPAN/Thread/thread_commissioning_api.c +++ b/source/6LoWPAN/Thread/thread_commissioning_api.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2017, Arm Limited and affiliates. + * Copyright (c) 2015-2019, Arm Limited and affiliates. * SPDX-License-Identifier: BSD-3-Clause * * Redistribution and use in source and binary forms, with or without diff --git a/source/6LoWPAN/Thread/thread_commissioning_if.c b/source/6LoWPAN/Thread/thread_commissioning_if.c index fc11217f7a..af327f6cb3 100644 --- a/source/6LoWPAN/Thread/thread_commissioning_if.c +++ b/source/6LoWPAN/Thread/thread_commissioning_if.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014-2017, Arm Limited and affiliates. + * Copyright (c) 2014-2019, Arm Limited and affiliates. * SPDX-License-Identifier: BSD-3-Clause * * Redistribution and use in source and binary forms, with or without diff --git a/source/6LoWPAN/Thread/thread_common.c b/source/6LoWPAN/Thread/thread_common.c index c87e55d839..c1babfdd04 100644 --- a/source/6LoWPAN/Thread/thread_common.c +++ b/source/6LoWPAN/Thread/thread_common.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014-2015, 2017-2018, Arm Limited and affiliates. + * Copyright (c) 2014-2015, 2017-2019, Arm Limited and affiliates. * SPDX-License-Identifier: BSD-3-Clause * * Redistribution and use in source and binary forms, with or without @@ -88,7 +88,7 @@ #include "6LoWPAN/MAC/mac_pairwise_key.h" #include "6LoWPAN/MAC/mac_data_poll.h" #include "Service_Libs/etx/etx.h" -#include "Core/include/address.h" +#include "Core/include/ns_address_internal.h" #include "6LoWPAN/Thread/thread_nvm_store.h" #define TRACE_GROUP "thrd" @@ -484,7 +484,9 @@ int thread_info_allocate_and_init(protocol_interface_info_entry_t *cur) cur->thread_info->version = thread_version; // Default implementation version cur->thread_info->thread_device_mode = THREAD_DEVICE_MODE_END_DEVICE; cur->thread_info->childUpdateReqTimer = -1; + cur->thread_info->parent_priority = CONNECTIVITY_PP_INVALID; // default invalid - calculated using child count + thread_maintenance_timer_set(cur); thread_routing_init(&cur->thread_info->routing); thread_network_local_server_data_base_init(&cur->thread_info->localServerDataBase); memset(&cur->thread_info->registered_commissioner, 0, sizeof(thread_commissioner_t)); @@ -961,7 +963,9 @@ static void thread_maintenance_timer(protocol_interface_info_entry_t *cur, uint3 } } - thread_info(cur)->thread_maintenance_timer = THREAD_MAINTENANCE_TIMER_INTERVAL ; + thread_maintenance_timer_set(cur); + + tr_debug("NWK data maintenance scan"); thread_bootstrap_network_data_activate(cur); } @@ -1245,7 +1249,9 @@ uint8_t *thread_connectivity_tlv_write(uint8_t *ptr, protocol_interface_info_ent *ptr++ = 10; // determine parent priority - if ((mode & MLE_DEV_MASK) == MLE_RFD_DEV && (3 * mle_class_rfd_entry_count_get(cur) > 2 * THREAD_MAX_MTD_CHILDREN)) { + if ((thread->parent_priority & CONNECTIVITY_PP_MASK) != CONNECTIVITY_PP_INVALID) { + *ptr++ = thread->parent_priority & CONNECTIVITY_PP_MASK; + } else if ((mode & MLE_DEV_MASK) == MLE_RFD_DEV && (3 * mle_class_rfd_entry_count_get(cur) > 2 * THREAD_MAX_MTD_CHILDREN)) { *ptr++ = CONNECTIVITY_PP_LOW; } else if (!(mode & MLE_RX_ON_IDLE) && (3 * mle_class_sleepy_entry_count_get(cur) > 2 * THREAD_MAX_SED_CHILDREN)) { *ptr++ = CONNECTIVITY_PP_LOW; @@ -2155,9 +2161,9 @@ void thread_neighbor_communication_update(protocol_interface_info_entry_t *cur, thread_neighbor_last_communication_time_update(&cur->thread_info->neighbor_class, neighbor_attribute_index); } -void thread_maintenance_timer_set(protocol_interface_info_entry_t *cur, uint16_t delay) +void thread_maintenance_timer_set(protocol_interface_info_entry_t *cur) { - thread_info(cur)->thread_maintenance_timer = delay; + thread_info(cur)->thread_maintenance_timer = THREAD_MAINTENANCE_TIMER_INTERVAL + randLIB_get_random_in_range(0, THREAD_MAINTENANCE_TIMER_INTERVAL / 10); } #endif diff --git a/source/6LoWPAN/Thread/thread_common.h b/source/6LoWPAN/Thread/thread_common.h index 3c3a798346..62053a5597 100644 --- a/source/6LoWPAN/Thread/thread_common.h +++ b/source/6LoWPAN/Thread/thread_common.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014-2018, Arm Limited and affiliates. + * Copyright (c) 2014-2019, Arm Limited and affiliates. * SPDX-License-Identifier: BSD-3-Clause * * Redistribution and use in source and binary forms, with or without @@ -68,6 +68,7 @@ struct mac_neighbor_table_entry; #define THREAD_KEY_INDEX(seq) ((uint8_t) (((seq) & 0x0000007f) + 1)) extern uint8_t thread_version; +extern uint8_t thread_max_mcast_addr; extern uint32_t thread_delay_timer_default; extern uint32_t thread_router_selection_jitter; extern uint16_t thread_joiner_port; @@ -316,6 +317,7 @@ typedef struct thread_info_s { //uint8_t lastValidRouteMask[8]; int8_t interface_id; //Thread Interface ID uint8_t version; + uint8_t parent_priority; uint8_t testMaxActiveRouterIdLimit; //Default for this is 32 uint8_t maxChildCount; //Default for this is 24 uint8_t partition_weighting; @@ -448,7 +450,7 @@ bool thread_partition_match(protocol_interface_info_entry_t *cur, thread_leader_ void thread_partition_info_update(protocol_interface_info_entry_t *cur, thread_leader_data_t *leaderData); void thread_neighbor_communication_update(protocol_interface_info_entry_t *cur, uint8_t neighbor_attribute_index); bool thread_stable_context_check(protocol_interface_info_entry_t *cur, buffer_t *buf); -void thread_maintenance_timer_set(protocol_interface_info_entry_t *cur, uint16_t delay); +void thread_maintenance_timer_set(protocol_interface_info_entry_t *cur); #else // HAVE_THREAD NS_DUMMY_DEFINITIONS_OK diff --git a/source/6LoWPAN/Thread/thread_config.h b/source/6LoWPAN/Thread/thread_config.h index 6952684196..a4542f01cf 100644 --- a/source/6LoWPAN/Thread/thread_config.h +++ b/source/6LoWPAN/Thread/thread_config.h @@ -247,7 +247,7 @@ * value for better performance. */ #define THREAD_INDIRECT_BIG_PACKETS_TOTAL 10 -#define THREAD_INDIRECT_SMALL_PACKETS_PER_CHILD 2 +#define THREAD_INDIRECT_SMALL_PACKETS_PER_CHILD 3 /** * Maximum number of MTD children, default 16 diff --git a/source/6LoWPAN/Thread/thread_constants.h b/source/6LoWPAN/Thread/thread_constants.h index 971a1fa1c9..1fdc2aadfd 100644 --- a/source/6LoWPAN/Thread/thread_constants.h +++ b/source/6LoWPAN/Thread/thread_constants.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2018, Arm Limited and affiliates. + * Copyright (c) 2016-2019, Arm Limited and affiliates. * SPDX-License-Identifier: BSD-3-Clause * * Redistribution and use in source and binary forms, with or without @@ -186,4 +186,6 @@ /** Thread prefix minimum lifetime in seconds */ #define THREAD_MIN_PREFIX_LIFETIME 3600 +#define THREAD_MCAST_ADDR_PER_MSG 4 // One multicast registration message fits 4 addresses by default + #endif /* THREAD_CONSTANTS_H_ */ diff --git a/source/6LoWPAN/Thread/thread_dhcpv6_server.c b/source/6LoWPAN/Thread/thread_dhcpv6_server.c index 3795fb6263..c01e385bb0 100644 --- a/source/6LoWPAN/Thread/thread_dhcpv6_server.c +++ b/source/6LoWPAN/Thread/thread_dhcpv6_server.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, Arm Limited and affiliates. + * Copyright (c) 2015, 2018-2019, Arm Limited and affiliates. * SPDX-License-Identifier: BSD-3-Clause * * Redistribution and use in source and binary forms, with or without diff --git a/source/6LoWPAN/Thread/thread_extension.h b/source/6LoWPAN/Thread/thread_extension.h index b6f64d1e90..2e9fd3d41f 100644 --- a/source/6LoWPAN/Thread/thread_extension.h +++ b/source/6LoWPAN/Thread/thread_extension.h @@ -85,7 +85,7 @@ uint8_t *thread_extension_discover_response_write(protocol_interface_info_entry_ #define thread_extension_version_check(version) (false) #define thread_extension_discover_response_read(nwk_info, discover_response_tlv, data_ptr, data_len) ((void) 0) #define thread_extension_discover_response_tlv_write(data, version, securityPolicy) ((void) 0) -#define thread_extension_service_init(cur) (0) +#define thread_extension_service_init(cur) ((void) 0) #define thread_extension_joining_enabled(interface_id) (false) #define thread_extension_discover_response_len(cur) (0) #define thread_extension_discover_response_write(cur, ptr) (ptr) diff --git a/source/6LoWPAN/Thread/thread_extension_bootstrap.h b/source/6LoWPAN/Thread/thread_extension_bootstrap.h index e6132ccdd9..a03eef1848 100644 --- a/source/6LoWPAN/Thread/thread_extension_bootstrap.h +++ b/source/6LoWPAN/Thread/thread_extension_bootstrap.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, Arm Limited and affiliates. + * Copyright (c) 2017-2019, Arm Limited and affiliates. * SPDX-License-Identifier: BSD-3-Clause * * Redistribution and use in source and binary forms, with or without diff --git a/source/6LoWPAN/Thread/thread_host_bootstrap.c b/source/6LoWPAN/Thread/thread_host_bootstrap.c index 7532bc54f0..7685f6454c 100644 --- a/source/6LoWPAN/Thread/thread_host_bootstrap.c +++ b/source/6LoWPAN/Thread/thread_host_bootstrap.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2018, Arm Limited and affiliates. + * Copyright (c) 2015-2019, Arm Limited and affiliates. * SPDX-License-Identifier: BSD-3-Clause * * Redistribution and use in source and binary forms, with or without @@ -73,7 +73,7 @@ #include "Service_Libs/blacklist/blacklist.h" #include "6LoWPAN/MAC/mac_helper.h" #include "6LoWPAN/MAC/mac_data_poll.h" -#include "Core/include/address.h" +#include "Core/include/ns_address_internal.h" #include "Service_Libs/mac_neighbor_table/mac_neighbor_table.h" #define TRACE_GROUP "tebs" @@ -470,8 +470,9 @@ static bool thread_host_prefer_parent_response(protocol_interface_info_entry_t * { (void) connectivity; (void) cur; + bool cur_version = thread_extension_version_check(thread_info(cur)->version); - if (!thread_extension_version_check(thread_info(cur)->version)) { + if (!cur_version) { return false; } diff --git a/source/6LoWPAN/Thread/thread_leader_service.c b/source/6LoWPAN/Thread/thread_leader_service.c index 5cfed0eccd..28b6282e70 100644 --- a/source/6LoWPAN/Thread/thread_leader_service.c +++ b/source/6LoWPAN/Thread/thread_leader_service.c @@ -393,11 +393,6 @@ static int thread_leader_service_active_set_cb(int8_t service_id, uint8_t source response_ptr = payload; - if (!thread_management_server_source_address_check(this->interface_id, source_address)) { - response_code = COAP_MSG_CODE_RESPONSE_BAD_REQUEST; - goto send_error_response; - } - if (3 <= thread_meshcop_tlv_find(request_ptr->payload_ptr, request_ptr->payload_len, MESHCOP_TLV_CHANNEL, &ptr) && (linkConfiguration->rfChannel != common_read_16_bit(&ptr[1]) || linkConfiguration->channel_page != *ptr)) { tr_debug("Channel changed"); @@ -559,11 +554,6 @@ static int thread_leader_service_pending_set_cb(int8_t service_id, uint8_t sourc tr_info("thread management Pending set"); - if (!thread_management_server_source_address_check(this->interface_id, source_address)) { - response_code = COAP_MSG_CODE_RESPONSE_BAD_REQUEST; - goto send_error_response; - } - if (2 <= thread_meshcop_tlv_data_get_uint16(request_ptr->payload_ptr, request_ptr->payload_len, MESHCOP_TLV_COMMISSIONER_SESSION_ID, &session_id)) { // Session id present must be valid if (cur->thread_info->registered_commissioner.session_id != session_id) { @@ -660,7 +650,6 @@ send_error_response: static int thread_leader_service_commissioner_set_cb(int8_t service_id, uint8_t source_address[16], uint16_t source_port, sn_coap_hdr_s *request_ptr) { thread_leader_service_t *this = thread_leader_service_find_by_service(service_id); - sn_coap_msg_code_e response_code = COAP_MSG_CODE_RESPONSE_CHANGED; uint16_t session_id; uint16_t br_locator; uint8_t payload[5]; // 4 + 1 @@ -682,10 +671,6 @@ static int thread_leader_service_commissioner_set_cb(int8_t service_id, uint8_t tr_info("thread management commissioner set"); - if (!thread_management_server_source_address_check(this->interface_id, source_address)) { - response_code = COAP_MSG_CODE_RESPONSE_BAD_REQUEST; - goto send_error_response; - } //Check if the CoAp payload is greater than maximum commissioner data size and reject if (request_ptr->payload_len > THREAD_MAX_COMMISSIONER_DATA_SIZE) { tr_error("Payload length greater than maximum commissioner data size"); @@ -725,9 +710,7 @@ static int thread_leader_service_commissioner_set_cb(int8_t service_id, uint8_t send_response: // build response ptr = thread_meshcop_tlv_data_write_uint8(ptr, MESHCOP_TLV_STATE, ret == 0 ? 1 : 0xff); - -send_error_response: - coap_service_response_send(this->coap_service_id, COAP_REQUEST_OPTIONS_NONE, request_ptr, response_code, COAP_CT_OCTET_STREAM, payload, ptr - payload); + coap_service_response_send(this->coap_service_id, COAP_REQUEST_OPTIONS_NONE, request_ptr, COAP_MSG_CODE_RESPONSE_CHANGED, COAP_CT_OCTET_STREAM, payload, ptr - payload); return 0; } @@ -1050,7 +1033,6 @@ static int thread_leader_service_release_cb(int8_t service_id, uint8_t source_ad static int thread_leader_service_petition_cb(int8_t service_id, uint8_t source_address[16], uint16_t source_port, sn_coap_hdr_s *request_ptr) { thread_leader_service_t *this = thread_leader_service_find_by_service(service_id); - sn_coap_msg_code_e response_code = COAP_MSG_CODE_RESPONSE_CHANGED; uint8_t payload[79];// max length for commissioner id is 64 + 4 byte header + 4 + 1 + 4 + 2 uint8_t *ptr; uint16_t session_id = 0; @@ -1067,11 +1049,6 @@ static int thread_leader_service_petition_cb(int8_t service_id, uint8_t source_a tr_debug("Thread management commissioner petition"); - if (!thread_management_server_source_address_check(this->interface_id, source_address)) { - response_code = COAP_MSG_CODE_RESPONSE_BAD_REQUEST; - goto send_error_response; - } - // save values from message tlv_length = thread_meshcop_tlv_find(request_ptr->payload_ptr, request_ptr->payload_len, MESHCOP_TLV_COMMISSIONER_ID, &tlv_data_ptr); @@ -1098,8 +1075,7 @@ static int thread_leader_service_petition_cb(int8_t service_id, uint8_t source_a tr_debug("Petition req recv id %s, RESP session id: %d ret %d", commissioner_id_ptr ? commissioner_id_ptr : "(none)", session_id, ret); -send_error_response: - coap_service_response_send(this->coap_service_id, COAP_REQUEST_OPTIONS_NONE, request_ptr, response_code, COAP_CT_OCTET_STREAM, payload, ptr - payload); + coap_service_response_send(this->coap_service_id, COAP_REQUEST_OPTIONS_NONE, request_ptr, COAP_MSG_CODE_RESPONSE_CHANGED, COAP_CT_OCTET_STREAM, payload, ptr - payload); return 0; } @@ -1110,7 +1086,6 @@ send_error_response: static int thread_leader_service_petition_ka_cb(int8_t service_id, uint8_t source_address[16], uint16_t source_port, sn_coap_hdr_s *request_ptr) { thread_leader_service_t *this = thread_leader_service_find_by_service(service_id); - sn_coap_msg_code_e response_code = COAP_MSG_CODE_RESPONSE_CHANGED; uint8_t payload[5]; //status 4 + 1 uint8_t *ptr; uint16_t session_id = 0; @@ -1125,12 +1100,6 @@ static int thread_leader_service_petition_ka_cb(int8_t service_id, uint8_t sourc tr_debug("Thread management commissioner keep alive"); - if (!thread_management_server_source_address_check(this->interface_id, source_address)) { - response_code = COAP_MSG_CODE_RESPONSE_BAD_REQUEST; - ptr = payload; - goto send_error_response; - } - if (2 <= thread_meshcop_tlv_find(request_ptr->payload_ptr, request_ptr->payload_len, MESHCOP_TLV_COMMISSIONER_SESSION_ID, &ptr)) { session_id = common_read_16_bit(ptr); } @@ -1149,8 +1118,7 @@ static int thread_leader_service_petition_ka_cb(int8_t service_id, uint8_t sourc ptr = payload; ptr = thread_meshcop_tlv_data_write_uint8(ptr, MESHCOP_TLV_STATE, state == true ? 1 : 0xff); -send_error_response: - coap_service_response_send(this->coap_service_id, COAP_REQUEST_OPTIONS_NONE, request_ptr, response_code, COAP_CT_OCTET_STREAM, payload, ptr - payload); + coap_service_response_send(this->coap_service_id, COAP_REQUEST_OPTIONS_NONE, request_ptr, COAP_MSG_CODE_RESPONSE_CHANGED, COAP_CT_OCTET_STREAM, payload, ptr - payload); return 0; } diff --git a/source/6LoWPAN/Thread/thread_lowpower_private_api.c b/source/6LoWPAN/Thread/thread_lowpower_private_api.c index 48ab2b0b31..cf3e8cf04f 100644 --- a/source/6LoWPAN/Thread/thread_lowpower_private_api.c +++ b/source/6LoWPAN/Thread/thread_lowpower_private_api.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, Arm Limited and affiliates. + * Copyright (c) 2017-2019, Arm Limited and affiliates. * SPDX-License-Identifier: BSD-3-Clause * * Redistribution and use in source and binary forms, with or without diff --git a/source/6LoWPAN/Thread/thread_management_api.c b/source/6LoWPAN/Thread/thread_management_api.c index 69ba03a5d0..60e02e3aee 100644 --- a/source/6LoWPAN/Thread/thread_management_api.c +++ b/source/6LoWPAN/Thread/thread_management_api.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2017, Arm Limited and affiliates. + * Copyright (c) 2015-2019, Arm Limited and affiliates. * SPDX-License-Identifier: BSD-3-Clause * * Redistribution and use in source and binary forms, with or without diff --git a/source/6LoWPAN/Thread/thread_management_if.c b/source/6LoWPAN/Thread/thread_management_if.c index a1497f63f9..6398816844 100644 --- a/source/6LoWPAN/Thread/thread_management_if.c +++ b/source/6LoWPAN/Thread/thread_management_if.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014-2018, Arm Limited and affiliates. + * Copyright (c) 2014-2019, Arm Limited and affiliates. * SPDX-License-Identifier: BSD-3-Clause * * Redistribution and use in source and binary forms, with or without @@ -94,6 +94,7 @@ static const uint8_t thread_discovery_extented_address[8] = {0x35, 0x06, 0xfe, 0 uint32_t thread_delay_timer_default = THREAD_DELAY_TIMER_DEFAULT_SECONDS; uint32_t thread_router_selection_jitter = THREAD_ROUTER_SELECTION_JITTER; uint16_t thread_joiner_port = THREAD_DEFAULT_JOINER_PORT; +uint8_t thread_max_mcast_addr = THREAD_MCAST_ADDR_PER_MSG; /* * Prototypes @@ -1345,6 +1346,11 @@ int8_t thread_management_get_request_full_nwk_data(int8_t interface_id, bool *fu int thread_management_device_certificate_set(int8_t interface_id, const unsigned char *device_certificate_ptr, uint16_t device_certificate_len, const unsigned char *priv_key_ptr, uint16_t priv_key_len) { + (void) device_certificate_ptr; + (void) device_certificate_len; + (void) priv_key_ptr; + (void) priv_key_len; + #ifdef HAVE_THREAD protocol_interface_info_entry_t *cur; @@ -1358,17 +1364,19 @@ int thread_management_device_certificate_set(int8_t interface_id, const unsigned #else (void) interface_id; - (void) device_certificate_ptr; - (void) device_certificate_len; - (void) priv_key_ptr; - (void) priv_key_len; return -1; #endif } int thread_management_network_certificate_set(int8_t interface_id, const unsigned char *network_certificate_ptr, uint16_t network_certificate_len, const unsigned char *priv_key_ptr, uint16_t priv_key_len) { + (void) network_certificate_ptr; + (void) network_certificate_len; + (void) priv_key_ptr; + (void) priv_key_len; + #ifdef HAVE_THREAD protocol_interface_info_entry_t *cur; + int ret_val; cur = protocol_stack_interface_info_get_by_id(interface_id); if (!cur) { @@ -1376,17 +1384,14 @@ int thread_management_network_certificate_set(int8_t interface_id, const unsigne return -1; } - if (0 > thread_extension_bootstrap_network_certificate_set(cur, network_certificate_ptr, network_certificate_len)) { + ret_val = thread_extension_bootstrap_network_certificate_set(cur, network_certificate_ptr, network_certificate_len); + if (0 > ret_val) { return -1; } return thread_extension_bootstrap_network_private_key_set(cur, priv_key_ptr, priv_key_len); #else (void) interface_id; - (void) network_certificate_ptr; - (void) network_certificate_len; - (void) priv_key_ptr; - (void) priv_key_len; return -1; #endif } diff --git a/source/6LoWPAN/Thread/thread_management_server.c b/source/6LoWPAN/Thread/thread_management_server.c index 25e9d33f10..c14f2475ec 100644 --- a/source/6LoWPAN/Thread/thread_management_server.c +++ b/source/6LoWPAN/Thread/thread_management_server.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014-2018, Arm Limited and affiliates. + * Copyright (c) 2014-2019, Arm Limited and affiliates. * SPDX-License-Identifier: BSD-3-Clause * * Redistribution and use in source and binary forms, with or without @@ -66,10 +66,19 @@ #include "thread_management_server.h" #include "mac_api.h" #include "6LoWPAN/MAC/mac_data_poll.h" +#include "Common_Protocols/ipv6_constants.h" +#include "Core/include/ns_address_internal.h" #include "mlme.h" #ifdef HAVE_THREAD +//#define TRACE_DEEP +#ifdef TRACE_DEEP +#define tr_deep tr_debug +#else +#define tr_deep(...) +#endif + typedef struct scan_query { int8_t coap_service_id; uint8_t channel_mask[6]; //interface_id, source_address)) { - // request is coming from illegal address, return error immediately - coap_service_response_send(service_id, COAP_REQUEST_OPTIONS_NONE, request_ptr, COAP_MSG_CODE_RESPONSE_BAD_REQUEST, COAP_CT_OCTET_STREAM, NULL, 0); - return 0; - } - return thread_management_server_tmf_get_request_handler(this->interface_id, service_id, request_ptr); } @@ -416,7 +420,6 @@ static int thread_management_server_commissioner_get_cb(int8_t service_id, uint8 (void) source_port; protocol_interface_info_entry_t *cur; thread_management_server_t *this = thread_management_find_by_service(service_id); - sn_coap_msg_code_e return_code = COAP_MSG_CODE_RESPONSE_CHANGED; uint8_t response_msg[2 + 2 + 2 + 2 + 2 + 16 + 2 + 2]; uint8_t *request_tlv_ptr = NULL; uint16_t request_tlv_len; @@ -432,11 +435,6 @@ static int thread_management_server_commissioner_get_cb(int8_t service_id, uint8 } payload_ptr = ptr = response_msg; - if (!thread_management_server_source_address_check(this->interface_id, source_address)) { - return_code = COAP_MSG_CODE_RESPONSE_BAD_REQUEST; - goto send_response; - } - if (!cur->thread_info->registered_commissioner.commissioner_valid) { //Error in message is responded with Thread status or if we have access rights problem tr_warn("No registered commissioner"); @@ -464,7 +462,7 @@ static int thread_management_server_commissioner_get_cb(int8_t service_id, uint8 goto send_response; } send_response: - coap_service_response_send(this->coap_service_id, COAP_REQUEST_OPTIONS_NONE, request_ptr, return_code, COAP_CT_OCTET_STREAM, payload_ptr, ptr - payload_ptr); + coap_service_response_send(this->coap_service_id, COAP_REQUEST_OPTIONS_NONE, request_ptr, COAP_MSG_CODE_RESPONSE_CHANGED, COAP_CT_OCTET_STREAM, payload_ptr, ptr - payload_ptr); return 0; } @@ -1118,6 +1116,58 @@ error_exit: return 0; } +static int coap_msg_prevalidate_cb(int8_t local_interface_id, uint8_t local_address[static 16], uint16_t local_port, int8_t recv_interface_id, uint8_t source_address[static 16], uint16_t source_port, char *coap_uri) +{ + protocol_interface_info_entry_t *cur_local, *cur_source; + uint_fast8_t addr_scope; + + (void) source_address; + (void) source_port; + (void) coap_uri; + + cur_local = protocol_stack_interface_info_get_by_id(local_interface_id); + + if (!cur_local) { + tr_error("No interface for %d", local_interface_id); + return -1; + } + + if (local_port != THREAD_MANAGEMENT_PORT) { + // Message not sent to THREAD_MANAGEMENT_PORT, let it come through + tr_deep("Message %s port %d is not mgmt port", coap_uri, local_port); + return 0; + } + + // check message source address + if (!thread_management_server_source_address_check(local_interface_id, source_address)) { + tr_deep("Drop CoAP msg %s from %s", coap_uri, trace_ipv6(source_address)); + return 3; + } + + /* check our local address scope */ + addr_scope = addr_ipv6_scope(local_address, cur_local); + if (addr_scope > IPV6_SCOPE_REALM_LOCAL) { + tr_deep("Drop CoAP msg %s to %s due %d", coap_uri, trace_ipv6(local_address), addr_scope); + return 1; + } + + if (local_interface_id != recv_interface_id) { + // message received from different interface + cur_source = protocol_stack_interface_info_get_by_id(recv_interface_id); + if (!cur_source) { + tr_deep("No cur for if %d", recv_interface_id); + return -1; + } + addr_scope = addr_ipv6_scope(source_address, cur_source); + if (addr_scope < IPV6_SCOPE_REALM_LOCAL) { + tr_deep("Drop CoAP msg %s from %s to %s due %d", coap_uri, trace_ipv6(source_address), trace_ipv6(local_address), addr_scope); + return 2; + } + } + + return 0; +} + /** * Public interface functions */ @@ -1162,6 +1212,7 @@ int thread_management_server_init(int8_t interface_id) ns_dyn_mem_free(this); return -3; } + coap_service_msg_prevalidate_callback_set(THREAD_MANAGEMENT_PORT, coap_msg_prevalidate_cb); #ifdef HAVE_THREAD_ROUTER if (thread_leader_service_init(interface_id, this->coap_service_id) != 0) { tr_error("Thread leader service init failed"); @@ -1554,10 +1605,15 @@ int thread_management_server_commisoner_data_get(int8_t interface_id, thread_man bool thread_management_server_source_address_check(int8_t interface_id, uint8_t source_address[16]) { link_configuration_s *linkConfiguration; - linkConfiguration = thread_joiner_application_get_config(interface_id); + if (memcmp(ADDR_LINK_LOCAL_PREFIX, source_address, 8) == 0) { + // Source address is from Link local address + return true; + } + + linkConfiguration = thread_joiner_application_get_config(interface_id); if (!linkConfiguration) { - tr_error("No link configuration."); + tr_error("No link cfg for if %d", interface_id); return false; } @@ -1566,15 +1622,12 @@ bool thread_management_server_source_address_check(int8_t interface_id, uint8_t // Source address is RLOC or ALOC } else if (memcmp(source_address, linkConfiguration->mesh_local_ula_prefix, 8) == 0) { // Source address is ML64 TODO this should check that destination address is ALOC or RLOC CoaP Service does not support - } else if (memcmp(ADDR_LINK_LOCAL_PREFIX, source_address, 8)) { - // Source address is from Link local address } else { - tr_error("Message out of thread network; ML prefix: %s, src addr: %s", - trace_ipv6_prefix(linkConfiguration->mesh_local_ula_prefix, 64), - trace_ipv6(source_address)); + tr_deep("Message out of thread network; ML prefix: %s, src addr: %s", + trace_ipv6_prefix(linkConfiguration->mesh_local_ula_prefix, 64), + trace_ipv6(source_address)); return false; } - // TODO: Add other (security) related checks here return true; } diff --git a/source/6LoWPAN/Thread/thread_management_server.h b/source/6LoWPAN/Thread/thread_management_server.h index b7ca9fb5c1..f083a01221 100644 --- a/source/6LoWPAN/Thread/thread_management_server.h +++ b/source/6LoWPAN/Thread/thread_management_server.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014-2017, Arm Limited and affiliates. + * Copyright (c) 2014-2019, Arm Limited and affiliates. * SPDX-License-Identifier: BSD-3-Clause * * Redistribution and use in source and binary forms, with or without diff --git a/source/6LoWPAN/Thread/thread_mdns.c b/source/6LoWPAN/Thread/thread_mdns.c index e90f53bc16..168bff5e81 100644 --- a/source/6LoWPAN/Thread/thread_mdns.c +++ b/source/6LoWPAN/Thread/thread_mdns.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, Arm Limited and affiliates. + * Copyright (c) 2017-2019, Arm Limited and affiliates. * SPDX-License-Identifier: BSD-3-Clause * * Redistribution and use in source and binary forms, with or without diff --git a/source/6LoWPAN/Thread/thread_meshcop_lib.c b/source/6LoWPAN/Thread/thread_meshcop_lib.c index ed9cba0ae7..09a70ce682 100644 --- a/source/6LoWPAN/Thread/thread_meshcop_lib.c +++ b/source/6LoWPAN/Thread/thread_meshcop_lib.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2017, Arm Limited and affiliates. + * Copyright (c) 2015-2019, Arm Limited and affiliates. * SPDX-License-Identifier: BSD-3-Clause * * Redistribution and use in source and binary forms, with or without diff --git a/source/6LoWPAN/Thread/thread_mle_message_handler.c b/source/6LoWPAN/Thread/thread_mle_message_handler.c index a6530d4ba1..c88e5acb93 100644 --- a/source/6LoWPAN/Thread/thread_mle_message_handler.c +++ b/source/6LoWPAN/Thread/thread_mle_message_handler.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2018, Arm Limited and affiliates. + * Copyright (c) 2016-2019, Arm Limited and affiliates. * SPDX-License-Identifier: BSD-3-Clause * * Redistribution and use in source and binary forms, with or without @@ -759,7 +759,7 @@ static void thread_host_child_update_request_process(protocol_interface_info_ent uint64_t pending_timestamp = 0;// means no pending timestamp mac_neighbor_table_entry_t *entry_temp; bool data_request_needed = false; - mle_tlv_info_t tlv_info = {0}; + mle_tlv_info_t tlv_info = {MLE_TYPE_SRC_ADDRESS, 0, 0}; tr_debug("Child update request"); entry_temp = mac_neighbor_entry_get_by_ll64(mac_neighbor_info(cur), mle_msg->packet_src_address, false, NULL); @@ -831,7 +831,7 @@ static void thread_parse_child_update_response(protocol_interface_info_entry_t * thread_leader_data_t leaderData = {0}; uint8_t status; bool leader_data_received; - mle_tlv_info_t tlv_info = {0}; + mle_tlv_info_t tlv_info = {MLE_TYPE_SRC_ADDRESS, 0, 0}; if (cur->thread_info->thread_endnode_parent == NULL) { return; diff --git a/source/6LoWPAN/Thread/thread_nd.c b/source/6LoWPAN/Thread/thread_nd.c index 82b8f97647..f25da1ca09 100644 --- a/source/6LoWPAN/Thread/thread_nd.c +++ b/source/6LoWPAN/Thread/thread_nd.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014-2018, Arm Limited and affiliates. + * Copyright (c) 2014-2019, Arm Limited and affiliates. * SPDX-License-Identifier: BSD-3-Clause * * Redistribution and use in source and binary forms, with or without @@ -42,7 +42,7 @@ #include "eventOS_event.h" #include "common_functions.h" #include "socket_api.h" -#include "Core/include/socket.h" +#include "Core/include/ns_socket.h" #include "NWK_INTERFACE/Include/protocol.h" #include "Common_Protocols/ipv6.h" #include "6LoWPAN/Bootstraps/protocol_6lowpan.h" @@ -213,6 +213,7 @@ static mac_neighbor_table_entry_t *thread_nd_child_mleid_get(protocol_interface_ static int thread_nd_address_query_lookup(int8_t interface_id, const uint8_t target_addr[static 16], uint16_t *rloc, uint16_t *addr_out, bool *proxy, uint32_t *last_transaction_time, uint8_t *mleid_ptr) { + (void) rloc; protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(interface_id); if (!cur) { return -1; diff --git a/source/6LoWPAN/Thread/thread_network_data_storage.c b/source/6LoWPAN/Thread/thread_network_data_storage.c index 16b9c58fb6..4936f1982b 100755 --- a/source/6LoWPAN/Thread/thread_network_data_storage.c +++ b/source/6LoWPAN/Thread/thread_network_data_storage.c @@ -1565,14 +1565,12 @@ int thread_nd_local_list_add_service(thread_network_data_cache_entry_t *networkD */ int thread_nd_local_list_add_on_mesh_prefix(thread_network_data_cache_entry_t *networkDataList, thread_prefix_tlv_t *prefixTlv, thread_border_router_tlv_entry_t *service) { - bool trigDataPropagate = false; thread_network_data_prefix_cache_entry_t *prefix_entry; thread_network_server_data_entry_t *server_entry; - if (service->P_dhcp) { - tr_debug("Add DHCPv6 prefix:%s server: %04x", trace_ipv6_prefix(prefixTlv->Prefix, prefixTlv->PrefixLen), service->routerID); - } else { - tr_debug("Add SLAAC prefix:%s server: %04x", trace_ipv6_prefix(prefixTlv->Prefix, prefixTlv->PrefixLen), service->routerID); - } + bool trigDataPropagate = false; + + tr_debug("Add %s%s%s prefix:%s server: %04x", service->P_dhcp ? "DHCPv6" : "", service->P_slaac ? "SLAAC " : "", service->P_res1 ? "P_res1 " : "", + trace_ipv6_prefix(prefixTlv->Prefix, prefixTlv->PrefixLen), service->routerID); if (!networkDataList) { return -1; @@ -1634,6 +1632,10 @@ int thread_nd_local_list_add_on_mesh_prefix(thread_network_data_cache_entry_t *n trigDataPropagate = true; } + if (server_entry->P_res1 != service->P_res1) { + server_entry->P_res1 = service->P_res1; + trigDataPropagate = true; + } } if (trigDataPropagate) { @@ -1647,7 +1649,6 @@ int thread_nd_local_list_add_on_mesh_prefix(thread_network_data_cache_entry_t *n return 0; } - /** * Del DHCPv6 Server information to route List * @@ -1671,13 +1672,8 @@ int thread_nd_local_list_del_on_mesh_server(thread_network_data_cache_entry_t *n return -1; } - if (service->P_dhcp) { - tr_debug("Del DHCPv6 server: %s", - trace_array(prefixTlv->Prefix, prefixBits_to_bytes(prefixTlv->PrefixLen))); - } else { - tr_debug("Del SLAAC server: %s", - trace_array(prefixTlv->Prefix, prefixBits_to_bytes(prefixTlv->PrefixLen))); - } + tr_debug("Del %s%s%s prefix: %s", service->P_dhcp ? "DHCPv6" : "", service->P_slaac ? "SLAAC " : "", service->P_res1 ? "P_res1 " : "", + trace_array(prefixTlv->Prefix, prefixBits_to_bytes(prefixTlv->PrefixLen))); main_list = thread_prefix_entry_get(&networkDataList->localPrefixList, prefixTlv); if (!main_list) { diff --git a/source/6LoWPAN/Thread/thread_nvm_store.c b/source/6LoWPAN/Thread/thread_nvm_store.c index ba85a26511..683d2f07cb 100644 --- a/source/6LoWPAN/Thread/thread_nvm_store.c +++ b/source/6LoWPAN/Thread/thread_nvm_store.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017-2018, Arm Limited and affiliates. + * Copyright (c) 2017-2019, Arm Limited and affiliates. * SPDX-License-Identifier: BSD-3-Clause * * Redistribution and use in source and binary forms, with or without @@ -35,7 +35,7 @@ #include #include -#include "Core/include/address.h" +#include "Core/include/ns_address_internal.h" #include "ns_file_system.h" #include "thread_config.h" #include "thread_common.h" diff --git a/source/6LoWPAN/Thread/thread_resolution_client.c b/source/6LoWPAN/Thread/thread_resolution_client.c index be83ddb2af..79740a0296 100644 --- a/source/6LoWPAN/Thread/thread_resolution_client.c +++ b/source/6LoWPAN/Thread/thread_resolution_client.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014-2017, Arm Limited and affiliates. + * Copyright (c) 2014-2019, Arm Limited and affiliates. * SPDX-License-Identifier: BSD-3-Clause * * Redistribution and use in source and binary forms, with or without @@ -33,7 +33,7 @@ #include "ns_list.h" #include "ns_trace.h" #include "nsdynmemLIB.h" -#include "Core/include/address.h" +#include "Core/include/ns_address_internal.h" #include "thread_tmfcop_lib.h" #include "coap_service_api.h" @@ -293,9 +293,14 @@ void thread_resolution_client_init(int8_t interface_id) this->interface_id = interface_id; this->notification_cb_ptr = NULL; this->error_cb_ptr = NULL; - ns_list_init(&this->queries); //TODO: Check if to use ephemeral port here this->coap_service_id = thread_management_server_service_id_get(interface_id); + if (this->coap_service_id < 0) { + tr_err("Thread resolution client init failed"); + ns_dyn_mem_free(this); + return; + } + ns_list_init(&this->queries); ns_list_add_to_start(&instance_list, this); coap_service_register_uri(this->coap_service_id, THREAD_URI_ADDRESS_NOTIFICATION, COAP_SERVICE_ACCESS_POST_ALLOWED, thread_resolution_client_notification_post_cb); diff --git a/source/6LoWPAN/Thread/thread_resolution_server.c b/source/6LoWPAN/Thread/thread_resolution_server.c index e20541eb2b..bbf2821eff 100644 --- a/source/6LoWPAN/Thread/thread_resolution_server.c +++ b/source/6LoWPAN/Thread/thread_resolution_server.c @@ -173,7 +173,7 @@ int thread_resolution_server_init(int8_t interface_id, thread_resolution_server_ this->interface_id = interface_id; this->coap_service_id = thread_management_server_service_id_get(interface_id); if (this->coap_service_id < 0) { - tr_warn("Thread resolution srv init failed"); + tr_err("Thread resolution srv init failed"); ns_dyn_mem_free(this); return -3; } diff --git a/source/6LoWPAN/Thread/thread_router_bootstrap.c b/source/6LoWPAN/Thread/thread_router_bootstrap.c index 6b31791f1a..f1399a7298 100644 --- a/source/6LoWPAN/Thread/thread_router_bootstrap.c +++ b/source/6LoWPAN/Thread/thread_router_bootstrap.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2018, Arm Limited and affiliates. + * Copyright (c) 2015-2019, Arm Limited and affiliates. * SPDX-License-Identifier: BSD-3-Clause * * Redistribution and use in source and binary forms, with or without @@ -83,7 +83,7 @@ #include "mac_api.h" #include "6LoWPAN/MAC/mac_data_poll.h" #include "thread_border_router_api.h" -#include "Core/include/address.h" +#include "Core/include/ns_address_internal.h" #include "Service_Libs/mac_neighbor_table/mac_neighbor_table.h" #ifdef HAVE_THREAD_ROUTER @@ -1407,6 +1407,7 @@ static void thread_address_registration_tlv_parse(uint8_t *ptr, uint16_t data_le //Register GP --> 16 int retVal = thread_nd_address_registration(cur, tempIPv6Address, mac16, cur->mac_parameters->pan_id, mac64, &new_neighbour_created); thread_extension_address_registration(cur, tempIPv6Address, mac64, new_neighbour_created, retVal == -2); + (void) retVal; } else { tr_debug("No Context %u", ctxId); } @@ -1427,6 +1428,7 @@ static void thread_address_registration_tlv_parse(uint8_t *ptr, uint16_t data_le //Register GP --> 16 int retVal = thread_nd_address_registration(cur, ptr, mac16, cur->mac_parameters->pan_id, mac64, &new_neighbour_created); thread_extension_address_registration(cur, ptr, mac64, new_neighbour_created, retVal == -2); + (void) retVal; } ptr += 16; @@ -1809,6 +1811,11 @@ void thread_router_bootstrap_mle_receive_cb(int8_t interface_id, mle_message_t * update_mac_mib = true; entry_temp->mac16 = shortAddress; // short address refreshed + if (thread_is_router_addr(shortAddress)) { + // Set full data as REED/Router needs full data (SED will not make links) + thread_neighbor_class_request_full_data_setup_set(&cur->thread_info->neighbor_class, entry_temp->index, true); + } + if (entry_temp->connected_device) { if (mle_tlv_read_tlv(MLE_TYPE_ADDRESS_REGISTRATION, mle_msg->data_ptr, mle_msg->data_length, &addressRegisteredTlv)) { if (!entry_temp->ffd_device) { @@ -1942,9 +1949,9 @@ void thread_router_bootstrap_mle_receive_cb(int8_t interface_id, mle_message_t * uint32_t timeout = 0; uint64_t active_timestamp = 0; uint64_t pending_timestamp = 0; - mle_tlv_info_t addressRegisterTlv = {0}; - mle_tlv_info_t challengeTlv = {0}; - mle_tlv_info_t tlv_req = {0}; + mle_tlv_info_t addressRegisterTlv = {MLE_TYPE_SRC_ADDRESS, 0, 0}; + mle_tlv_info_t challengeTlv = {MLE_TYPE_SRC_ADDRESS, 0, 0}; + mle_tlv_info_t tlv_req = {MLE_TYPE_SRC_ADDRESS, 0, 0}; entry_temp = mac_neighbor_entry_get_by_ll64(mac_neighbor_info(cur), mle_msg->packet_src_address, false, NULL); if (mle_tlv_read_8_bit_tlv(MLE_TYPE_STATUS, mle_msg->data_ptr, mle_msg->data_length, &status)) { diff --git a/source/6LoWPAN/Thread/thread_test_api.c b/source/6LoWPAN/Thread/thread_test_api.c index 51719670e3..c1f0668e40 100644 --- a/source/6LoWPAN/Thread/thread_test_api.c +++ b/source/6LoWPAN/Thread/thread_test_api.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014-2018, Arm Limited and affiliates. + * Copyright (c) 2014-2019, Arm Limited and affiliates. * SPDX-License-Identifier: BSD-3-Clause * * Redistribution and use in source and binary forms, with or without @@ -634,6 +634,7 @@ int thread_test_version_set(int8_t interface_id, uint8_t version) return 0; #else + (void)version; (void)interface_id; return -1; #endif @@ -1269,6 +1270,23 @@ int8_t thread_test_joiner_router_joiner_port_set(uint16_t port) } +int8_t thread_test_mcast_address_per_message_set(uint8_t value) +{ +#ifdef HAVE_THREAD + if (value == 0 || value > 15) { + tr_err("Value not in range. Valid range 1-15"); + return -1; + } + + thread_max_mcast_addr = value; + + return 0; +#else + (void)value; + return -1; +#endif +} + int thread_test_mle_message_send(int8_t interface_id, uint8_t *dst_address, uint8_t msg_id, bool write_src_addr, bool write_leader_data, bool write_network_data, bool write_timestamp, bool write_operational_set, bool write_challenge, uint8_t *msg_ptr, uint8_t msg_len) { #ifdef HAVE_THREAD @@ -1341,6 +1359,8 @@ int thread_test_mle_message_send(int8_t interface_id, uint8_t *dst_address, uint (void)msg_id; (void)write_src_addr; (void)write_leader_data; + (void)write_network_data; + (void)write_timestamp; (void)write_operational_set; (void)write_challenge; (void)msg_ptr; @@ -1367,3 +1387,27 @@ int thread_test_extension_name_set(int8_t interface_id, char extension_name[16]) return -1; #endif } + +int thread_test_parent_priority_set(int8_t interface_id, uint8_t parent_priority) +{ +#ifdef HAVE_THREAD + protocol_interface_info_entry_t *cur; + + cur = protocol_stack_interface_info_get_by_id(interface_id); + if (!cur) { + tr_warn("Invalid interface id"); + return -1; + } + + if (!cur->thread_info) { + tr_warn("Not Thread specific interface"); + return -2; + } + cur->thread_info->parent_priority = parent_priority; + return 0; +#else + (void) interface_id; + (void) parent_priority; + return -1; +#endif +} diff --git a/source/6LoWPAN/adaptation_interface.c b/source/6LoWPAN/adaptation_interface.c index b2ba8466e4..eca2559836 100644 --- a/source/6LoWPAN/adaptation_interface.c +++ b/source/6LoWPAN/adaptation_interface.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2018, Arm Limited and affiliates. + * Copyright (c) 2016-2019, Arm Limited and affiliates. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -23,8 +23,8 @@ #include "ns_list.h" #include "randLIB.h" #include "nsdynmemLIB.h" -#include "Core/include/address.h" -#include "Core/include/socket.h" +#include "Core/include/ns_address_internal.h" +#include "Core/include/ns_socket.h" #include "mac_api.h" #include "mac_mcps.h" #include "mac_common_defines.h" @@ -40,6 +40,8 @@ #include "6LoWPAN/IPHC_Decode/iphc_decompress.h" #include "lowpan_adaptation_interface.h" #include "MLE/mle.h" +#include "Service_Libs/mle_service/mle_service_api.h" +#include "Common_Protocols/icmpv6.h" #ifdef HAVE_RPL #include "RPL/rpl_data.h" #endif @@ -787,49 +789,112 @@ static fragmenter_tx_entry_t *lowpan_adaptation_indirect_first_cached_request_ge return NULL; } -static void lowpan_adaptation_make_room_for_small_packet(protocol_interface_info_entry_t *cur, fragmenter_interface_t *interface_ptr, mac_neighbor_table_entry_t *neighbour_to_count) +static bool lowpan_adaptation_is_priority_message(buffer_t *buf) +{ + // Mle messages + if (buf->dst_sa.port == MLE_ALLOCATED_PORT || buf->src_sa.port == MLE_ALLOCATED_PORT) { + return true; + } + + // Management messages: address solicit, response, query, notification + if (buf->dst_sa.port == THREAD_MANAGEMENT_PORT || buf->src_sa.port == THREAD_MANAGEMENT_PORT) { + return true; + } + + // dhcp messages + if (buf->dst_sa.port == DHCPV6_SERVER_PORT || buf->src_sa.port == DHCPV6_SERVER_PORT) { + return true; + } + + if (buf->dst_sa.port == DHCPV6_CLIENT_PORT || buf->src_sa.port == DHCPV6_CLIENT_PORT) { + return true; + } + + // ICMPv6 messages + if (buf->options.type == ICMPV6_TYPE_ERROR_DESTINATION_UNREACH || + buf->options.type == ICMPV6_TYPE_ERROR_PACKET_TOO_BIG || + buf->options.type == ICMPV6_TYPE_ERROR_TIME_EXCEEDED || + buf->options.type == ICMPV6_TYPE_ERROR_PARAMETER_PROBLEM) { + return true; + } + return false; +} + +static bool lowpan_adaptation_make_room_for_small_packet(protocol_interface_info_entry_t *cur, fragmenter_interface_t *interface_ptr, mac_neighbor_table_entry_t *neighbour_to_count, fragmenter_tx_entry_t *new_entry) { if (interface_ptr->max_indirect_small_packets_per_child == 0) { - return; + // this means there is always space for small packets - no need to check further + return true; } uint_fast16_t count = 0; + fragmenter_tx_entry_t *low_priority_msg_ptr = NULL; ns_list_foreach_reverse_safe(fragmenter_tx_entry_t, tx_entry, &interface_ptr->indirect_tx_queue) { mac_neighbor_table_entry_t *tx_neighbour = mac_neighbor_table_address_discover(mac_neighbor_info(cur), tx_entry->buf->dst_sa.address + 2, tx_entry->buf->dst_sa.addr_type); if (tx_neighbour == neighbour_to_count && buffer_data_length(tx_entry->buf) <= interface_ptr->indirect_big_packet_threshold) { + if (!lowpan_adaptation_is_priority_message(tx_entry->buf)) { + // if there is sub priorities inside message example age here you could compare + low_priority_msg_ptr = tx_entry; + } if (++count >= interface_ptr->max_indirect_small_packets_per_child) { - tr_debug_extra("Purge seq: %d", tx_entry->buf->seq); - if (lowpan_adaptation_indirect_queue_free_message(cur, interface_ptr, tx_entry) == false) { + if (!low_priority_msg_ptr) { + // take last entry if no low priority entry found + if (lowpan_adaptation_is_priority_message(new_entry->buf)) { + low_priority_msg_ptr = tx_entry; + } else { + return false; + } + } + tr_debug_extra("Purge seq: %d", low_priority_msg_ptr->buf->seq); + if (lowpan_adaptation_indirect_queue_free_message(cur, interface_ptr, low_priority_msg_ptr) == false) { /* entry could not be purged from mac, try next entry */ tr_debug_extra("Purge failed, try next"); count--; } + low_priority_msg_ptr = NULL; } } } + return true; } -static void lowpan_adaptation_make_room_for_big_packet(struct protocol_interface_info_entry *cur, fragmenter_interface_t *interface_ptr) +static bool lowpan_adaptation_make_room_for_big_packet(struct protocol_interface_info_entry *cur, fragmenter_interface_t *interface_ptr, fragmenter_tx_entry_t *new_entry) { if (interface_ptr->max_indirect_big_packets_total == 0) { - return; + // this means there is always space for big packets - no need to check further + return true; } uint_fast16_t count = 0; + fragmenter_tx_entry_t *low_priority_msg_ptr = NULL; ns_list_foreach_reverse_safe(fragmenter_tx_entry_t, tx_entry, &interface_ptr->indirect_tx_queue) { if (buffer_data_length(tx_entry->buf) > interface_ptr->indirect_big_packet_threshold) { + if (!lowpan_adaptation_is_priority_message(tx_entry->buf)) { + // if there is sub priorities inside message example age here you could compare + low_priority_msg_ptr = tx_entry; + } if (++count >= interface_ptr->max_indirect_big_packets_total) { - tr_debug_extra("Purge seq: %d", tx_entry->buf->seq); - if (lowpan_adaptation_indirect_queue_free_message(cur, interface_ptr, tx_entry) == false) { - tr_debug("Purge failed, try next entry"); + if (!low_priority_msg_ptr) { + // take last entry if no low priority entry found + if (lowpan_adaptation_is_priority_message(new_entry->buf)) { + low_priority_msg_ptr = tx_entry; + } else { + return false; + } + } + tr_debug_extra("Purge seq: %d", low_priority_msg_ptr->buf->seq); + if (lowpan_adaptation_indirect_queue_free_message(cur, interface_ptr, low_priority_msg_ptr) == false) { + tr_debug_extra("Purge failed, try next entry"); /* entry could not be purged from mac, try next entry */ count--; } + low_priority_msg_ptr = NULL; } } } + return true; } static void lowpan_data_request_to_mac(protocol_interface_info_entry_t *cur, buffer_t *buf, fragmenter_tx_entry_t *tx_ptr, fragmenter_interface_t *interface_ptr) @@ -868,6 +933,7 @@ static void lowpan_data_request_to_mac(protocol_interface_info_entry_t *cur, buf int8_t lowpan_adaptation_interface_tx(protocol_interface_info_entry_t *cur, buffer_t *buf) { + bool is_room_for_new_message; if (!buf) { return -1; } @@ -940,9 +1006,9 @@ int8_t lowpan_adaptation_interface_tx(protocol_interface_info_entry_t *cur, buff // Make room for new message if needed */ if (buffer_data_length(buf) <= interface_ptr->indirect_big_packet_threshold) { - lowpan_adaptation_make_room_for_small_packet(cur, interface_ptr, neigh_entry_ptr); + is_room_for_new_message = lowpan_adaptation_make_room_for_small_packet(cur, interface_ptr, neigh_entry_ptr, tx_ptr); } else { - lowpan_adaptation_make_room_for_big_packet(cur, interface_ptr); + is_room_for_new_message = lowpan_adaptation_make_room_for_big_packet(cur, interface_ptr, tx_ptr); } if (lowpan_adaptation_indirect_mac_data_request_active(interface_ptr, tx_ptr)) { @@ -951,7 +1017,15 @@ int8_t lowpan_adaptation_interface_tx(protocol_interface_info_entry_t *cur, buff tx_ptr->indirect_data_cached = true; } - ns_list_add_to_end(&interface_ptr->indirect_tx_queue, tx_ptr); + if (is_room_for_new_message) { + ns_list_add_to_end(&interface_ptr->indirect_tx_queue, tx_ptr); + } else { + if (tx_ptr->fragmenter_buf) { + ns_dyn_mem_free(tx_ptr->fragmenter_buf); + } + ns_dyn_mem_free(tx_ptr); + goto tx_error_handler; + } // Check if current message can be delivered to MAC or should some cached message be delivered first tx_ptr_cached = lowpan_adaptation_indirect_first_cached_request_get(interface_ptr, tx_ptr); diff --git a/source/6LoWPAN/lowpan_adaptation_interface.h b/source/6LoWPAN/lowpan_adaptation_interface.h index 4921c3b120..562e482034 100644 --- a/source/6LoWPAN/lowpan_adaptation_interface.h +++ b/source/6LoWPAN/lowpan_adaptation_interface.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2018, Arm Limited and affiliates. + * Copyright (c) 2016-2019, Arm Limited and affiliates. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -17,7 +17,7 @@ #ifndef LOWPAN_ADAPTATION_INTERFACE_H_ #define LOWPAN_ADAPTATION_INTERFACE_H_ -#include "Core/include/address.h" +#include "Core/include/ns_address_internal.h" struct protocol_interface_info_entry; struct mcps_data_conf_s; diff --git a/source/6LoWPAN/ws/ws_bbr_api.c b/source/6LoWPAN/ws/ws_bbr_api.c new file mode 100644 index 0000000000..5d242ae687 --- /dev/null +++ b/source/6LoWPAN/ws/ws_bbr_api.c @@ -0,0 +1,488 @@ +/* + * Copyright (c) 2018-2019, 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 +#include "nsconfig.h" +#include "ns_types.h" +#include "ns_trace.h" +#include "net_interface.h" +#include "eventOS_event.h" +#include "NWK_INTERFACE/Include/protocol.h" +#include "6LoWPAN/Bootstraps/protocol_6lowpan.h" +#include "6LoWPAN/Bootstraps/protocol_6lowpan_interface.h" +#include "6LoWPAN/ws/ws_config.h" +#include "6LoWPAN/ws/ws_common.h" +#include "6LoWPAN/ws/ws_bootstrap.h" +#include "RPL/rpl_control.h" +#include "RPL/rpl_data.h" +#include "Common_Protocols/icmpv6.h" +#include "Common_Protocols/icmpv6_radv.h" +#include "ws_management_api.h" +#include "net_rpl.h" +#include "Service_Libs/nd_proxy/nd_proxy.h" +#include "6LoWPAN/ws/ws_bbr_api_internal.h" +#include "DHCPv6_Server/DHCPv6_server_service.h" + +#define TRACE_GROUP "wsbs" + +#define RPL_INSTANCE_ID 1 + +#ifdef HAVE_WS_BORDER_ROUTER + + +/* when creating BBR make ULA dodag ID always and when network becomes available add prefix to DHCP + * + * + */ +static int8_t backbone_interface_id = -1; // BBR backbone information + +static uint8_t static_dodag_prefix[8] = {0xfd, 0x00, 0x61, 0x72, 0x6d}; +static uint8_t static_ula_address[16] = {0}; +static uint8_t static_dodag_id[16] = {0}; +static uint8_t global_dodag_id[16] = {0}; +static uint32_t bbr_delay_timer = 20; // initial delay. + +static rpl_dodag_conf_t rpl_conf = { + // Lifetime values + .default_lifetime = 120, + .lifetime_unit = 60, + .objective_code_point = 1, // MRHOF algorithm used + .authentication = 0, + .path_control_size = 7, + .dag_max_rank_increase = 2048, + .min_hop_rank_increase = 256, + // DIO configuration + .dio_interval_min = WS_RPL_DIO_IMIN, + .dio_interval_doublings = WS_RPL_DIO_DOUBLING, + .dio_redundancy_constant = WS_RPL_DIO_REDUNDANCY +}; + +void ws_bbr_rpl_config(uint8_t imin, uint8_t doubling, uint8_t redundancy) +{ + if (imin == 0 || doubling == 0) { + // use default values + imin = WS_RPL_DIO_IMIN; + doubling = WS_RPL_DIO_DOUBLING; + redundancy = WS_RPL_DIO_REDUNDANCY; + } + if (rpl_conf.dio_interval_min == imin && + rpl_conf.dio_interval_doublings == doubling && + rpl_conf.dio_redundancy_constant == redundancy) { + // Same values no update needed + return; + } + rpl_conf.dio_interval_min = imin; + rpl_conf.dio_interval_doublings = doubling; + rpl_conf.dio_redundancy_constant = redundancy; + if (protocol_6lowpan_rpl_root_dodag) { + rpl_control_update_dodag_config(protocol_6lowpan_rpl_root_dodag, &rpl_conf); + rpl_control_increment_dodag_version(protocol_6lowpan_rpl_root_dodag); + } +} + +static void ws_bbr_rpl_root_start(uint8_t *dodag_id) +{ + tr_info("RPL root start"); + rpl_data_init_root(); + + if (protocol_6lowpan_rpl_root_dodag) { + rpl_control_delete_dodag_root(protocol_6lowpan_rpl_domain, protocol_6lowpan_rpl_root_dodag); + protocol_6lowpan_rpl_root_dodag = NULL; + } + + protocol_6lowpan_rpl_root_dodag = rpl_control_create_dodag_root(protocol_6lowpan_rpl_domain, RPL_INSTANCE_ID, dodag_id, &rpl_conf, rpl_conf.min_hop_rank_increase, RPL_GROUNDED | RPL_MODE_NON_STORING | RPL_DODAG_PREF(0)); + if (!protocol_6lowpan_rpl_root_dodag) { + tr_err("RPL dodag init failed"); + return; + } + memcpy(static_dodag_id, dodag_id, 16); + + // RPL memory limits set larger for Border router + rpl_control_set_memory_limits(64 * 1024, 0); + + uint8_t t_flags = PIO_A; + + rpl_control_update_dodag_prefix(protocol_6lowpan_rpl_root_dodag, dodag_id, 64, t_flags, 7200, 7200, false); + rpl_control_update_dodag_route(protocol_6lowpan_rpl_root_dodag, dodag_id, 64, 0x18, 7200, false); +} + +static void ws_bbr_rpl_root_stop(void) +{ + tr_info("RPL root stop"); + rpl_control_delete_dodag_root(protocol_6lowpan_rpl_domain, protocol_6lowpan_rpl_root_dodag); + protocol_6lowpan_rpl_root_dodag = NULL; + memset(static_ula_address, 0, 16); + memset(static_dodag_id, 0, 16); + memset(global_dodag_id, 0, 16); +} + +static int ws_border_router_proxy_validate(int8_t interface_id, uint8_t *address) +{ + + /* Could also check route type, but I don't think it really matters */ + ipv6_route_t *route; + route = ipv6_route_choose_next_hop(address, interface_id, NULL); + if (!route || route->prefix_len < 128) { + return -1; + } + + return 0; +} + +int ws_border_router_proxy_state_update(int8_t caller_interface_id, int8_t handler_interface_id, bool status) +{ + (void)caller_interface_id; + + protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(handler_interface_id); + if (!cur) { + tr_error("No Interface"); + return -1; + } + + if (status) { + tr_debug("Border router Backhaul link ready"); + } else { + tr_debug("Border router Backhaul link down"); + } + return 0; +} + +static int ws_bbr_static_ula_create(protocol_interface_info_entry_t *cur) +{ + if (memcmp(static_ula_address, ADDR_UNSPECIFIED, 16) != 0) { + // address generated + return 0; + } + tr_info("BBR generate ula prefix"); + + // This address is only used if no other address available. + if_address_entry_t *add_entry = icmpv6_slaac_address_add(cur, static_dodag_prefix, 64, 0xffffffff, 0, true, SLAAC_IID_FIXED); + if (!add_entry) { + return -1; + } + memcpy(static_ula_address, add_entry->address, 16); + tr_info("BBR generate ula prefix addr %s", trace_ipv6(static_ula_address)); + + return 0; +} + +/* + * 0 static non rooted self generated own address + * 1 static address with backbone connectivity + */ +static int ws_bbr_static_dodag_get(protocol_interface_info_entry_t *cur, uint8_t *dodag_id_ptr) +{ + + protocol_interface_info_entry_t *bb_interface = protocol_stack_interface_info_get_by_id(backbone_interface_id); + + if (bb_interface && bb_interface->ipv6_configure->ipv6_stack_mode == NET_IPV6_BOOTSTRAP_STATIC) { + // static configuration for ethernet available + ns_list_foreach(if_address_entry_t, add_entry, &cur->ip_addresses) { + if (memcmp(add_entry->address, bb_interface->ipv6_configure->static_prefix64, 8) == 0) { + //tr_info("BBR static config available"); + if (dodag_id_ptr) { + memcpy(dodag_id_ptr, add_entry->address, 16); + } + return 1; + } + } + } + ws_bbr_static_ula_create(cur); + + // only own generated prefix available + if (dodag_id_ptr) { + memcpy(dodag_id_ptr, static_ula_address, 16); + } + + return 0; +} + + +static int ws_bbr_dodag_get(protocol_interface_info_entry_t *cur, uint8_t *static_dodag_id_ptr, uint8_t *dodag_id_ptr) +{ + uint8_t global_address[16]; + + if (static_dodag_id_ptr) { + memset(static_dodag_id_ptr, 0, 16); + } + + if (dodag_id_ptr) { + memset(dodag_id_ptr, 0, 16); + } + + if (ws_bbr_static_dodag_get(cur, static_dodag_id_ptr) < 0) { + // no static configuration available + return -1; + } + + if (arm_net_address_get(backbone_interface_id, ADDR_IPV6_GP, global_address) != 0) { + // No global prefix available + return 0; + } + if (memcmp(global_address, dodag_id_ptr, 8) == 0) { + // static address is same + return 0; + } + memcpy(dodag_id_ptr, global_address, 16); + return 0; +} +static void wisun_bbr_na_send(int8_t interface_id, const uint8_t target[static 16]) +{ + protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(interface_id); + if (!cur) { + return; + } + + buffer_t *buffer = icmpv6_build_na(cur, false, true, true, target, NULL, ADDR_UNSPECIFIED); + protocol_push(buffer); + return; + +} + +static bool wisun_dhcp_address_add_cb(int8_t interfaceId, dhcp_address_cache_update_t *address_info, void *route_src) +{ + (void)route_src; + protocol_interface_info_entry_t *curPtr = protocol_stack_interface_info_get_by_id(interfaceId); + if (!curPtr) { + return false; + } + + // When address is allocated we send NA to backbone to notify the new address and flush from other BBRs + wisun_bbr_na_send(backbone_interface_id, address_info->allocatedAddress); + return true; +} + + +static void ws_bbr_rpl_status_check(protocol_interface_info_entry_t *cur) +{ + + uint8_t static_id[16] = {0}; + uint8_t global_id[16] = {0}; + + //tr_info("BBR status check"); + + ws_bbr_dodag_get(cur, static_id, global_id); + + if (memcmp(static_dodag_id, static_id, 16) != 0) { + // Static id updated or first setup + ws_bbr_rpl_root_start(static_id); + } + if (memcmp(global_dodag_id, global_id, 16) != 0) { + // Global prefix changed + if (memcmp(global_dodag_id, ADDR_UNSPECIFIED, 16) != 0) { + // TODO remove old global prefix + tr_info("RPL GUA deactivate %s", trace_ipv6(global_dodag_id)); + + rpl_control_update_dodag_prefix(protocol_6lowpan_rpl_root_dodag, static_dodag_id, 64, PIO_A, 7200, 7200, false); + rpl_control_update_dodag_route(protocol_6lowpan_rpl_root_dodag, static_dodag_id, 64, 0x18, 7200, false); + + // Old backbone information is deleted after 120 seconds + rpl_control_update_dodag_route(protocol_6lowpan_rpl_root_dodag, NULL, 0, 0, 120, true); + rpl_control_update_dodag_prefix(protocol_6lowpan_rpl_root_dodag, global_dodag_id, 64, 0, 120, 0, true); + rpl_control_update_dodag_route(protocol_6lowpan_rpl_root_dodag, global_dodag_id, 64, 0, 120, true); + ipv6_route_add_with_info(global_dodag_id, 64, backbone_interface_id, NULL, ROUTE_THREAD_BBR, NULL, 0, 120, 0); + DHCPv6_server_service_delete(cur->id, global_dodag_id, false); + + // Set old addresses to deferred and timeout + ws_dhcp_client_address_delete(cur, global_dodag_id); + } + // TODO add global prefix + if (memcmp(global_id, ADDR_UNSPECIFIED, 16) != 0) { + //DHCPv6 Server set here + //Interface LL64 address + uint8_t ll[16]; + memcpy(ll, ADDR_LINK_LOCAL_PREFIX, 8); + memcpy(&ll[8], cur->mac, 8); + ll[8] ^= 2; + + if (DHCPv6_server_service_init(cur->id, global_id, cur->mac, DHCPV6_DUID_HARDWARE_IEEE_802_NETWORKS_TYPE) != 0) { + tr_error("DHCPv6 Server create fail"); + return; + } + DHCPv6_server_service_callback_set(cur->id, global_id, NULL, wisun_dhcp_address_add_cb); + + DHCPv6_server_service_set_address_autonous_flag(cur->id, global_id, true); + DHCPv6_server_service_set_address_validlifetime(cur->id, global_id, 7200); + + tr_info("RPL GUA activate %s", trace_ipv6(global_id)); + ws_dhcp_client_address_request(cur, global_id, ll); + + rpl_control_update_dodag_route(protocol_6lowpan_rpl_root_dodag, NULL, 0, 0, 7200, false); + rpl_control_update_dodag_prefix(protocol_6lowpan_rpl_root_dodag, static_dodag_id, 64, PIO_A, 7200, 0, false); + rpl_control_update_dodag_route(protocol_6lowpan_rpl_root_dodag, static_dodag_id, 64, 0x18, 7200, false); + rpl_control_update_dodag_prefix(protocol_6lowpan_rpl_root_dodag, global_id, 64, 0, 7200, 7200, false); + rpl_control_update_dodag_route(protocol_6lowpan_rpl_root_dodag, global_id, 64, 0, 7200, false); + ipv6_route_add_with_info(global_id, 64, backbone_interface_id, NULL, ROUTE_THREAD_BBR, NULL, 0, 0xffffffff, 0); + } + memcpy(global_dodag_id, global_id, 16); + rpl_control_increment_dodag_version(protocol_6lowpan_rpl_root_dodag); + nd_proxy_downstream_interface_register(cur->id, ws_border_router_proxy_validate, ws_border_router_proxy_state_update); + } + +} + +void ws_bbr_seconds_timer(protocol_interface_info_entry_t *cur, uint32_t seconds) +{ + (void)seconds; + + if (!ws_info(cur)) { + return; + } + if (cur->bootsrap_mode != ARM_NWK_BOOTSRAP_MODE_6LoWPAN_BORDER_ROUTER) { + // Not a border router + return; + } + if (!cur->rpl_domain) { + // RPL not started + return; + } + + if (bbr_delay_timer > seconds) { + bbr_delay_timer -= seconds; + } else { + bbr_delay_timer = 20; // 20 second interval between status checks + + // prequisists + // Wi-SUN network configuration started without RPL + + // RPL configured simple + // 1. Wait for backend connection + // 2. When address becomes available in backend start RPL dodag + // 3. if address removed remove dodag + + // RPL configured Advanced + // 1. Add ULA DODAG and and start ROOT even without backend + // a. If static prefix configured use it. + // b. generate random ULA and publish it to backend + // 2. if GUA prefix becomes available in backend add new prefix to DODAG + // 3. if GUA prefix is removed remove the prefix. + + if (protocol_6lowpan_rpl_root_dodag) { + // Border router is active + if (0 != protocol_interface_address_compare(static_dodag_id)) { + // Dodag has become invalid need to delete + tr_info("RPL static dodag not valid anymore %s", trace_ipv6(static_dodag_id)); + ws_bbr_rpl_root_stop(); + } else { + + } + } + ws_bbr_rpl_status_check(cur); + + } + // Normal BBR operation + if (protocol_6lowpan_rpl_root_dodag) { + if (cur->ws_info->pan_version_timer > seconds) { + cur->ws_info->pan_version_timer -= seconds; + } else { + // Border router has timed out + tr_debug("Border router version number update"); + cur->ws_info->pan_version_timer = PAN_VERSION_LIFETIME; + cur->ws_info->pan_information.pan_version++; + // Inconsistent for border router to make information distribute faster + ws_bootstrap_configuration_trickle_reset(cur); + + if (cur->ws_info->network_size_config == NETWORK_SIZE_AUTOMATIC) { + ws_common_network_size_configure(cur, cur->ws_info->pan_information.pan_size); + } + // We update the RPL version in same time to allow nodes to reselect parent + // As configuration is made so that devices cant move downward in dodag this allows it + // TODO think the correct rate for this + if (cur->ws_info->pan_information.pan_version && cur->ws_info->pan_information.pan_version % RPL_VERSION_LIFETIME / PAN_VERSION_LIFETIME == 0) { + // Third the rate of configuration version change at default 5 hours + rpl_control_increment_dodag_version(protocol_6lowpan_rpl_root_dodag); + } + } + + } + +} + +uint16_t test_pan_size_override = 0xffff; + +uint16_t ws_bbr_pan_size(protocol_interface_info_entry_t *cur) +{ + uint16_t result = 0; + if (test_pan_size_override != 0xffff) { + return test_pan_size_override; + } + + rpl_control_get_instance_dao_target_count(cur->rpl_domain, RPL_INSTANCE_ID, NULL, &result); + return result; +} + + +#endif //HAVE_WS_BORDER_ROUTER + +/* Public APIs + * + */ + +int ws_bbr_start(int8_t interface_id, int8_t bb_interface_id) +{ +#ifdef HAVE_WS_BORDER_ROUTER + + (void)interface_id; + protocol_interface_info_entry_t *bb_interface = protocol_stack_interface_info_get_by_id(bb_interface_id); + + if (!bb_interface) { + return -1; + } + // TODO make bb configurations + + backbone_interface_id = bb_interface_id; + + return 0; +#else + (void)interface_id; + (void)bb_interface_id; + return -1; +#endif +} +void ws_bbr_stop(int8_t interface_id) +{ +#ifdef HAVE_WS_BORDER_ROUTER + + (void)interface_id; + backbone_interface_id = -1; + + if (!protocol_6lowpan_rpl_domain) { + return; + } + + rpl_control_delete_dodag_root(protocol_6lowpan_rpl_domain, protocol_6lowpan_rpl_root_dodag); + protocol_6lowpan_rpl_root_dodag = NULL; + +#else + (void)interface_id; +#endif +} + +int ws_bbr_node_keys_remove(int8_t interface_id, uint8_t *eui64) +{ + (void) interface_id; + (void) eui64; + + return -1; +} + +int ws_bbr_node_access_revoke_start(int8_t interface_id) +{ + (void) interface_id; + + return -1; +} diff --git a/source/6LoWPAN/ws/ws_bbr_api_internal.h b/source/6LoWPAN/ws/ws_bbr_api_internal.h new file mode 100644 index 0000000000..a3e7b6e44b --- /dev/null +++ b/source/6LoWPAN/ws/ws_bbr_api_internal.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2018-2019, Arm Limited and affiliates. + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef WS_BBR_API_PRIVATE_H_ +#define WS_BBR_API_PRIVATE_H_ + + +#ifdef HAVE_WS_BORDER_ROUTER + +extern uint16_t test_pan_size_override; + +void ws_bbr_seconds_timer(protocol_interface_info_entry_t *cur, uint32_t seconds); + +uint16_t ws_bbr_pan_size(protocol_interface_info_entry_t *cur); + +void ws_bbr_rpl_config(uint8_t imin, uint8_t doubling, uint8_t redundancy); + + + +#else + +#define ws_bbr_seconds_timer( cur, seconds) +#define ws_bbr_pan_size(cur) 0 +#define ws_bbr_rpl_config( imin, doubling, redundancy); + +#endif //HAVE_WS_BORDER_ROUTER + +#endif /* WS_BBR_API_PRIVATE_H_ */ diff --git a/source/6LoWPAN/ws/ws_bootstrap.c b/source/6LoWPAN/ws/ws_bootstrap.c new file mode 100644 index 0000000000..56caffe04a --- /dev/null +++ b/source/6LoWPAN/ws/ws_bootstrap.c @@ -0,0 +1,2480 @@ +/* + * Copyright (c) 2018-2019, 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 +#include "nsconfig.h" +#include "ns_types.h" +#include "ns_trace.h" +#include "net_interface.h" +#include "eventOS_event.h" +#include "randLIB.h" +#include "common_functions.h" +#include "mac_common_defines.h" +#include "sw_mac.h" +#include "ccmLIB.h" +#include "NWK_INTERFACE/Include/protocol.h" +#include "6LoWPAN/Bootstraps/protocol_6lowpan.h" +#include "6LoWPAN/Bootstraps/protocol_6lowpan_interface.h" +#include "ipv6_stack/protocol_ipv6.h" +#include "6LoWPAN/MAC/mac_helper.h" +#include "6LoWPAN/MAC/mac_data_poll.h" +#include "6LoWPAN/MAC/mpx_api.h" +#include "6LoWPAN/MAC/mac_ie_lib.h" +#include "MPL/mpl.h" +#include "RPL/rpl_protocol.h" +#include "RPL/rpl_control.h" +#include "RPL/rpl_data.h" +#include "Common_Protocols/icmpv6.h" +#include "Common_Protocols/icmpv6_radv.h" +#include "Common_Protocols/ipv6_constants.h" +#include "Service_Libs/Trickle/trickle.h" +#include "Service_Libs/fhss/channel_list.h" +#include "6LoWPAN/ws/ws_common_defines.h" +#include "6LoWPAN/ws/ws_common_defines.h" +#include "6LoWPAN/ws/ws_config.h" +#include "6LoWPAN/ws/ws_common.h" +#include "6LoWPAN/ws/ws_bootstrap.h" +#include "6LoWPAN/ws/ws_bbr_api_internal.h" +#include "6LoWPAN/ws/ws_common_defines.h" +#include "6LoWPAN/ws/ws_llc.h" +#include "6LoWPAN/ws/ws_neighbor_class.h" +#include "6LoWPAN/ws/ws_ie_lib.h" +#include "6LoWPAN/lowpan_adaptation_interface.h" +#include "Service_Libs/etx/etx.h" +#include "Service_Libs/mac_neighbor_table/mac_neighbor_table.h" +#include "Service_Libs/nd_proxy/nd_proxy.h" +#include "Service_Libs/blacklist/blacklist.h" +#include "platform/topo_trace.h" +#include "libDHCPv6/libDHCPv6.h" +#include "DHCPv6_client/dhcpv6_client_api.h" +#include "ws_management_api.h" +#include "net_rpl.h" +#include "mac_api.h" +#include "6LoWPAN/ws/ws_pae_controller.h" +#include "6LoWPAN/ws/ws_eapol_pdu.h" +#include "6LoWPAN/ws/ws_eapol_auth_relay.h" +#include "6LoWPAN/ws/ws_eapol_relay.h" + +#define TRACE_GROUP "wsbs" + +#ifdef HAVE_WS + +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_active(struct protocol_interface_info_entry *cur); +//static bool ws_bootstrap_state_wait_rpl(struct protocol_interface_info_entry *cur); +static bool ws_bootstrap_state_discovery(struct protocol_interface_info_entry *cur); +static int8_t ws_bootsrap_event_trig(ws_bootsrap_event_type_e event_type, int8_t interface_id, arm_library_event_priority_e priority, void *event_data); + +static bool ws_bootstrap_neighbor_info_request(struct protocol_interface_info_entry *interface, const uint8_t *mac_64, llc_neighbour_req_t *neighbor_buffer, bool request_new); +static uint16_t ws_bootstrap_routing_cost_calculate(protocol_interface_info_entry_t *cur); +static uint16_t ws_bootstrap_rank_get(protocol_interface_info_entry_t *cur); +static uint16_t ws_bootstrap_min_rank_inc_get(protocol_interface_info_entry_t *cur); + +static void ws_bootstrap_key_insert(protocol_interface_info_entry_t *cur, uint8_t gtk_index, uint8_t *gtk); +static void ws_bootstrap_authentication_completed(protocol_interface_info_entry_t *cur, bool success); + +mac_neighbor_table_entry_t *ws_bootstrap_mac_neighbor_add(struct protocol_interface_info_entry *interface, const uint8_t *src64) + +{ + mac_neighbor_table_entry_t *neighbor = mac_neighbor_table_address_discover(mac_neighbor_info(interface), src64, MAC_ADDR_MODE_64_BIT); + if (neighbor) { + return neighbor; + } + + neighbor = mac_neighbor_table_entry_allocate(mac_neighbor_info(interface), src64); + if (!neighbor) { + return NULL; + } + // TODO only call these for new neighbour + mlme_device_descriptor_t device_desc; + neighbor->lifetime = WS_NEIGHBOR_LINK_TIMEOUT; + neighbor->link_lifetime = WS_NEIGHBOR_LINK_TIMEOUT; + tr_debug("Added new neighbor %s : index:%u", trace_array(src64, 8), neighbor->index); + mac_helper_device_description_write(interface, &device_desc, neighbor->mac64, neighbor->mac16, 0, false); + mac_helper_devicetable_set(&device_desc, interface, neighbor->index, interface->mac_parameters->mac_default_key_index, true); + return neighbor; +} + +static void ws_bootstrap_neighbor_delete(struct protocol_interface_info_entry *interface, uint8_t attribute_index) +{ + mac_helper_devicetable_remove(interface->mac_api, attribute_index); + etx_neighbor_remove(interface->id, attribute_index); + ws_neighbor_class_entry_remove(&interface->ws_info->neighbor_storage, attribute_index); +} + +static void ws_bootstrap_neighbor_list_clean(struct protocol_interface_info_entry *interface) +{ + + mac_neighbor_table_neighbor_list_clean(mac_neighbor_info(interface)); +} + +static void ws_bootstrap_address_notification_cb(struct protocol_interface_info_entry *interface, const struct if_address_entry *addr, if_address_callback_t reason) +{ + /* No need for LL address registration */ + if (addr->source == ADDR_SOURCE_UNKNOWN) { + return; + } + if (reason == ADDR_CALLBACK_DAD_COMPLETE) { + //Trig Address Registartion only when Bootstrap is ready + if (interface->nwk_bootstrap_state == ER_BOOTSRAP_DONE || addr->source == ADDR_SOURCE_DHCP) { + ws_bootsrap_event_trig(WS_ADDRESS_ADDED, interface->bootStrapId, ARM_LIB_LOW_PRIORITY_EVENT, (void *)addr); + } + 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 + interface->global_address_available = false; + ns_list_foreach(if_address_entry_t, addr_str, &interface->ip_addresses) { + if (addr_ipv6_scope(addr_str->address, interface) > IPV6_SCOPE_LINK_LOCAL) { + // at least ula address available inside mesh. + interface->global_address_available = true; + break; + } + } + } else { + tr_debug("Address notification addr: %s reason: %d", trace_ipv6(addr->address), reason); + } +} + +static int ws_bootstrap_tasklet_init(protocol_interface_info_entry_t *cur) +{ + if (cur->bootStrapId < 0) { + cur->bootStrapId = eventOS_event_handler_create(&ws_bootstrap_event_handler, WS_INIT_EVENT); + tr_debug("WS tasklet init"); + } + + if (cur->bootStrapId < 0) { + tr_error("tasklet init failed"); + return -1; + } + + + return 0; +} + +static int8_t ws_bootsrap_event_trig(ws_bootsrap_event_type_e event_type, int8_t interface_id, arm_library_event_priority_e priority, void *event_data) +{ + arm_event_s event = { + .receiver = interface_id, + .sender = 0, + .event_type = event_type, + .priority = priority, + .data_ptr = event_data, + }; + return eventOS_event_send(&event); +} + +static void ws_nud_table_reset(protocol_interface_info_entry_t *cur) +{ + //Empty active list + ns_list_foreach_safe(ws_nud_table_entry_t, entry, &cur->ws_info->active_nud_process) { + ns_list_remove(&cur->ws_info->active_nud_process, entry); + } + + //Empty free list + ns_list_foreach_safe(ws_nud_table_entry_t, entry, &cur->ws_info->free_nud_entries) { + ns_list_remove(&cur->ws_info->free_nud_entries, entry); + } + //Add to free list to full + for (int i = 0; i < ACTIVE_NUD_PROCESS_MAX; i++) { + ns_list_add_to_end(&cur->ws_info->free_nud_entries, &cur->ws_info->nud_table_entrys[i]); + } +} + +static ws_nud_table_entry_t *ws_nud_entry_get_free(protocol_interface_info_entry_t *cur) +{ + ws_nud_table_entry_t *entry = ns_list_get_first(&cur->ws_info->free_nud_entries); + if (entry) { + entry->wait_response = false; + entry->retry_count = 0; + entry->nud_process = false; + entry->timer = randLIB_get_random_in_range(1, 900); + entry->neighbor_info = NULL; + ns_list_remove(&cur->ws_info->free_nud_entries, entry); + ns_list_add_to_end(&cur->ws_info->active_nud_process, entry); + } + return entry; +} + + +void ws_nud_entry_remove_active(protocol_interface_info_entry_t *cur, void *neighbor) +{ + ns_list_foreach(ws_nud_table_entry_t, entry, &cur->ws_info->active_nud_process) { + if (entry->neighbor_info == neighbor) { + mac_neighbor_table_entry_t *mac_neighbor = neighbor; + ns_list_remove(&cur->ws_info->active_nud_process, entry); + ns_list_add_to_end(&cur->ws_info->free_nud_entries, entry); + if (mac_neighbor->nud_active) { + mac_neighbor_table_neighbor_refresh(mac_neighbor_info(cur), mac_neighbor, mac_neighbor->link_lifetime); + } + + mac_neighbor_table_neighbor_connected(mac_neighbor_info(cur), mac_neighbor); + return; + } + } +} + +static void ws_nud_state_clean(protocol_interface_info_entry_t *cur, ws_nud_table_entry_t *entry) +{ + mac_neighbor_table_entry_t *neighbor = entry->neighbor_info; + ns_list_remove(&cur->ws_info->active_nud_process, entry); + ns_list_add_to_end(&cur->ws_info->free_nud_entries, entry); + if (neighbor->nud_active) { + neighbor->nud_active = false; + mac_neighbor_info(cur)->active_nud_process--; + } +} + +static bool ws_nud_message_build(protocol_interface_info_entry_t *cur, mac_neighbor_table_entry_t *neighbor) +{ + //Send NS + uint8_t ll_target[16]; + memcpy(ll_target, ADDR_LINK_LOCAL_PREFIX, 8); + memcpy(ll_target + 8, neighbor->mac64, 8); + ll_target[8] ^= 2; + tr_info("NUD generate NS %u", neighbor->index); + buffer_t *buffer = icmpv6_build_ns(cur, ll_target, NULL, true, false, NULL); + if (buffer) { + protocol_push(buffer); + return true; + } + return false; +} + +void ws_nud_active_timer(protocol_interface_info_entry_t *cur, uint16_t ticks) +{ + //Convert TICKS to real milliseconds + if (ticks > 0xffff / 100) { + ticks = 0xffff; + } else { + ticks *= 100; + } + + ns_list_foreach_safe(ws_nud_table_entry_t, entry, &cur->ws_info->active_nud_process) { + if (entry->timer <= ticks) { + //TX Process or timeout + if (entry->wait_response) { + //Timeout for NUD or Probe + if (entry->nud_process) { + tr_debug("NUD NA timeout"); + if (entry->retry_count < 2) { + entry->timer = randLIB_get_random_in_range(1, 900); + entry->wait_response = false; + } else { + //Clear entry from active list + ws_nud_state_clean(cur, entry); + //Remove whole entry + mac_neighbor_table_neighbor_remove(mac_neighbor_info(cur), entry->neighbor_info); + } + } else { + ws_nud_state_clean(cur, entry); + } + + } else { + //Random TX wait period is over + entry->wait_response = ws_nud_message_build(cur, entry->neighbor_info); + if (!entry->wait_response) { + if (entry->nud_process && entry->retry_count < 2) { + entry->timer = randLIB_get_random_in_range(1, 900); + } else { + //Clear entry from active list + //Remove and try again later on + ws_nud_state_clean(cur, entry); + } + } else { + entry->retry_count++; + entry->timer = 5001; + } + } + } else { + entry->timer -= ticks; + } + } +} + +static fhss_ws_neighbor_timing_info_t *ws_get_neighbor_info(const fhss_api_t *api, uint8_t eui64[8]) +{ + protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_fhss_api(api); + if (!cur || !cur->mac_parameters || !mac_neighbor_info(cur)) { + return NULL; + } + mac_neighbor_table_entry_t *mac_neighbor = mac_neighbor_table_address_discover(mac_neighbor_info(cur), eui64, MAC_ADDR_MODE_64_BIT); + if (!mac_neighbor) { + return NULL; + } + ws_neighbor_class_entry_t *ws_neighbor = ws_neighbor_class_entry_get(&cur->ws_info->neighbor_storage, mac_neighbor->index); + if (!ws_neighbor) { + return NULL; + } + return &ws_neighbor->fhss_data; +} +static void ws_bootstrap_llc_hopping_update(struct protocol_interface_info_entry *cur, const fhss_ws_configuration_t *fhss_configuration) +{ + memcpy(cur->ws_info->hopping_schdule.channel_mask, fhss_configuration->channel_mask, sizeof(uint32_t) * 8); + cur->ws_info->hopping_schdule.uc_fixed_channel = fhss_configuration->unicast_fixed_channel; + cur->ws_info->hopping_schdule.bc_fixed_channel = fhss_configuration->broadcast_fixed_channel; + cur->ws_info->hopping_schdule.uc_channel_function = fhss_configuration->ws_uc_channel_function; + cur->ws_info->hopping_schdule.bc_channel_function = fhss_configuration->ws_bc_channel_function; + cur->ws_info->hopping_schdule.fhss_bc_dwell_interval = fhss_configuration->fhss_bc_dwell_interval; + cur->ws_info->hopping_schdule.fhss_broadcast_interval = fhss_configuration->fhss_broadcast_interval; + cur->ws_info->hopping_schdule.fhss_uc_dwell_interval = fhss_configuration->fhss_uc_dwell_interval; + cur->ws_info->hopping_schdule.fhss_bsi = fhss_configuration->bsi; +} + +static int8_t ws_fhss_initialize(protocol_interface_info_entry_t *cur) +{ + fhss_api_t *fhss_api = ns_sw_mac_get_fhss_api(cur->mac_api); + + if (!fhss_api) { + // When FHSS doesn't exist yet, create one + fhss_ws_configuration_t fhss_configuration; + memset(&fhss_configuration, 0, sizeof(fhss_ws_configuration_t)); + ws_generate_channel_list(fhss_configuration.channel_mask, cur->ws_info->hopping_schdule.number_of_channels, cur->ws_info->hopping_schdule.regulatory_domain); + + // using bitwise AND operation for user set channel mask to remove channels not allowed in this device + for (uint8_t n = 0; n < 8; n++) { + fhss_configuration.channel_mask[n] &= cur->ws_info->fhss_channel_mask[n]; + } + + fhss_configuration.fhss_uc_dwell_interval = cur->ws_info->fhss_uc_dwell_interval; + fhss_configuration.ws_uc_channel_function = (fhss_ws_channel_functions)cur->ws_info->fhss_uc_channel_function; + fhss_configuration.ws_bc_channel_function = (fhss_ws_channel_functions)cur->ws_info->fhss_bc_channel_function; + fhss_configuration.fhss_bc_dwell_interval = cur->ws_info->fhss_bc_dwell_interval; + fhss_configuration.fhss_broadcast_interval = cur->ws_info->fhss_bc_interval; + + fhss_api = ns_fhss_ws_create(&fhss_configuration, cur->ws_info->fhss_timer_ptr); + if (!fhss_api) { + tr_error("fhss create failed"); + return -1; + } + ns_sw_mac_fhss_register(cur->mac_api, fhss_api); + } else { + // Read defaults from the configuration to help FHSS testing + const fhss_ws_configuration_t *fhss_configuration = ns_fhss_ws_configuration_get(fhss_api); + if (!fhss_configuration) { + // no configuration set yet + return 0; + } + memcpy(cur->ws_info->fhss_channel_mask, fhss_configuration->channel_mask, sizeof(uint32_t) * 8); + cur->ws_info->fhss_uc_channel_function = fhss_configuration->ws_uc_channel_function; + cur->ws_info->fhss_bc_channel_function = fhss_configuration->ws_bc_channel_function; + cur->ws_info->fhss_bc_dwell_interval = fhss_configuration->fhss_bc_dwell_interval; + cur->ws_info->fhss_bc_interval = fhss_configuration->fhss_broadcast_interval; + cur->ws_info->fhss_uc_dwell_interval = fhss_configuration->fhss_uc_dwell_interval; + } + return 0; +} +static int8_t ws_fhss_set_defaults(protocol_interface_info_entry_t *cur, fhss_ws_configuration_t *fhss_configuration) +{ + fhss_configuration->fhss_uc_dwell_interval = cur->ws_info->fhss_uc_dwell_interval; + fhss_configuration->ws_uc_channel_function = (fhss_ws_channel_functions)cur->ws_info->fhss_uc_channel_function; + fhss_configuration->ws_bc_channel_function = (fhss_ws_channel_functions)cur->ws_info->fhss_bc_channel_function; + fhss_configuration->fhss_bc_dwell_interval = cur->ws_info->fhss_bc_dwell_interval; + fhss_configuration->fhss_broadcast_interval = cur->ws_info->fhss_bc_interval; + if (cur->ws_info->fhss_uc_fixed_channel != 0xffff) { + fhss_configuration->unicast_fixed_channel = cur->ws_info->fhss_uc_fixed_channel; + } + fhss_configuration->broadcast_fixed_channel = cur->ws_info->fhss_bc_fixed_channel; + ws_generate_channel_list(fhss_configuration->channel_mask, cur->ws_info->hopping_schdule.number_of_channels, cur->ws_info->hopping_schdule.regulatory_domain); + + // using bitwise AND operation for user set channel mask to remove channels not allowed in this device + for (uint8_t n = 0; n < 8; n++) { + fhss_configuration->channel_mask[n] &= cur->ws_info->fhss_channel_mask[n]; + } + return 0; +} +static int8_t ws_fhss_border_router_configure(protocol_interface_info_entry_t *cur) +{ + // Read configuration of existing FHSS and start using the default values for any network + fhss_ws_configuration_t fhss_configuration; + memset(&fhss_configuration, 0, sizeof(fhss_ws_configuration_t)); + + if (ns_fhss_ws_configuration_get(cur->ws_info->fhss_api)) { + memcpy(&fhss_configuration, ns_fhss_ws_configuration_get(cur->ws_info->fhss_api), sizeof(fhss_ws_configuration_t)); + } + ws_fhss_set_defaults(cur, &fhss_configuration); + ns_fhss_ws_configuration_set(cur->ws_info->fhss_api, &fhss_configuration); + ws_bootstrap_llc_hopping_update(cur, &fhss_configuration); + + return 0; +} + +static uint16_t ws_randomize_fixed_channel(uint16_t configured_fixed_channel, uint8_t number_of_channels) +{ + if (configured_fixed_channel == 0xFFFF) { + return randLIB_get_random_in_range(0, number_of_channels - 1); + } else { + return configured_fixed_channel; + } +} + +static int8_t ws_fhss_discovery_configure(protocol_interface_info_entry_t *cur) +{ + // Read configuration of existing FHSS and start using the default values for any network + fhss_ws_configuration_t fhss_configuration; + memset(&fhss_configuration, 0, sizeof(fhss_ws_configuration_t)); + + if (ns_fhss_ws_configuration_get(cur->ws_info->fhss_api)) { + memcpy(&fhss_configuration, ns_fhss_ws_configuration_get(cur->ws_info->fhss_api), sizeof(fhss_ws_configuration_t)); + } + + fhss_configuration.fhss_uc_dwell_interval = 0; + fhss_configuration.ws_uc_channel_function = WS_FIXED_CHANNEL; + fhss_configuration.ws_bc_channel_function = WS_FIXED_CHANNEL; + fhss_configuration.fhss_bc_dwell_interval = 0; + fhss_configuration.fhss_broadcast_interval = 0; + uint8_t tmp_uc_fixed_channel = ws_randomize_fixed_channel(cur->ws_info->fhss_uc_fixed_channel, cur->ws_info->hopping_schdule.number_of_channels); + uint8_t tmp_bc_fixed_channel = ws_randomize_fixed_channel(cur->ws_info->fhss_bc_fixed_channel, cur->ws_info->hopping_schdule.number_of_channels); + memset(fhss_configuration.channel_mask, 0, sizeof(uint32_t) * 8); + channel_list_set_channel(fhss_configuration.channel_mask, tmp_uc_fixed_channel, true); + fhss_configuration.unicast_fixed_channel = tmp_uc_fixed_channel; + fhss_configuration.broadcast_fixed_channel = tmp_bc_fixed_channel; + ns_fhss_ws_configuration_set(cur->ws_info->fhss_api, &fhss_configuration); + ws_bootstrap_llc_hopping_update(cur, &fhss_configuration); + + return 0; +} + +static int8_t ws_fhss_enable(protocol_interface_info_entry_t *cur) +{ + const fhss_ws_configuration_t *fhss_configuration = ns_fhss_ws_configuration_get(cur->ws_info->fhss_api); + + if (!cur->ws_info->fhss_api || !fhss_configuration) { + return -1; + } + // Set the LLC information to follow the actual fhss settings + ws_bootstrap_llc_hopping_update(cur, fhss_configuration); + + // Set neighbor info callback + if (ns_fhss_set_neighbor_info_fp(cur->ws_info->fhss_api, &ws_get_neighbor_info)) { + return -1; + } + if (cur->bootsrap_mode == ARM_NWK_BOOTSRAP_MODE_6LoWPAN_BORDER_ROUTER) { + ns_fhss_ws_set_hop_count(cur->ws_info->fhss_api, 0); + } + return 0; +} + +/* Sets the parent and broadcast schedule we are following + * + */ +static void ws_bootstrap_primary_parent_set(struct protocol_interface_info_entry *cur, llc_neighbour_req_t *neighbor_info, bool force_synch) +{ + + fhss_ws_configuration_t fhss_configuration; + if (!neighbor_info->ws_neighbor->broadcast_timing_info_stored) { + tr_error("No BC timing info for set new parent"); + return; + } + + memcpy(&fhss_configuration, ns_fhss_ws_configuration_get(cur->ws_info->fhss_api), sizeof(fhss_ws_configuration_t)); + + // Learning broadcast network configuration + if (neighbor_info->ws_neighbor->broadcast_shedule_info_stored) { + ws_fhss_set_defaults(cur, &fhss_configuration); + fhss_configuration.ws_bc_channel_function = (fhss_ws_channel_functions)neighbor_info->ws_neighbor->fhss_data.bc_timing_info.broadcast_channel_function; + if (fhss_configuration.ws_bc_channel_function == WS_FIXED_CHANNEL) { + cur->ws_info->hopping_schdule.bc_fixed_channel = neighbor_info->ws_neighbor->fhss_data.bc_timing_info.fixed_channel; + cur->ws_info->fhss_bc_fixed_channel = neighbor_info->ws_neighbor->fhss_data.bc_timing_info.fixed_channel; + } + fhss_configuration.bsi = neighbor_info->ws_neighbor->fhss_data.bc_timing_info.broadcast_schedule_id; + fhss_configuration.fhss_bc_dwell_interval = neighbor_info->ws_neighbor->fhss_data.bc_timing_info.broadcast_dwell_interval; + fhss_configuration.fhss_broadcast_interval = neighbor_info->ws_neighbor->fhss_data.bc_timing_info.broadcast_interval; + fhss_configuration.broadcast_fixed_channel = cur->ws_info->fhss_bc_fixed_channel; + + } + + ns_fhss_ws_configuration_set(cur->ws_info->fhss_api, &fhss_configuration); + + // We have broadcast schedule set up set the broadcast parent schedule + ns_fhss_ws_set_parent(cur->ws_info->fhss_api, neighbor_info->neighbor->mac64, &neighbor_info->ws_neighbor->fhss_data.bc_timing_info, force_synch); + + // Update LLC to follow updated fhss settings + ws_bootstrap_llc_hopping_update(cur, &fhss_configuration); +} + +static void ws_bootstrap_ll_address_validate(struct protocol_interface_info_entry *cur) +{ + // Configure EUI64 for MAC if missing + uint8_t mac64[8]; + if (!cur->mac_api) { + return; + } + + cur->mac_api->mac64_get(cur->mac_api, MAC_EXTENDED_DYNAMIC, mac64); + + if (memcmp(mac64, ADDR_UNSPECIFIED, 8) == 0) { + cur->mac_api->mac64_get(cur->mac_api, MAC_EXTENDED_READ_ONLY, mac64); + } + + if (memcmp(mac64, ADDR_UNSPECIFIED, 8) == 0) { + // Generate random mac because it was not available + randLIB_get_n_bytes_random(mac64, 8); + mac64[0] |= 2; //Set Local Bit + mac64[0] &= ~1; //Clear multicast bit + + tr_info("Generated random MAC %s", trace_array(mac64, 8)); + } + mac_helper_mac64_set(cur, mac64); + + memcpy(cur->iid_eui64, mac64, 8); + /* Invert U/L Bit */ + cur->iid_eui64[0] ^= 2; + memcpy(cur->iid_slaac, cur->iid_eui64, 8); + +} + +/* \return 0x0100 to 0xFFFF ETX value (8 bit fraction) + * \return 0xFFFF address not associated + * \return 0x0000 address unknown or other error + * \return 0x0001 no ETX statistics on this interface + */ +uint16_t ws_etx_read(protocol_interface_info_entry_t *interface, addrtype_t addr_type, const uint8_t *addr_ptr) +{ + + uint16_t etx; + if (!addr_ptr || !interface) { + return 0; + } + + uint8_t attribute_index; + + mac_neighbor_table_entry_t *mac_neighbor = mac_neighbor_table_address_discover(mac_neighbor_info(interface), addr_ptr + PAN_ID_LEN, addr_type); + if (!mac_neighbor) { + return 0xffff; + } + attribute_index = mac_neighbor->index; + ws_neighbor_class_entry_t *ws_neighbour = ws_neighbor_class_entry_get(&interface->ws_info->neighbor_storage, attribute_index); + etx_storage_t *etx_entry = etx_storage_entry_get(interface->id, attribute_index); + + if (interface->bootsrap_mode == ARM_NWK_BOOTSRAP_MODE_6LoWPAN_BORDER_ROUTER) { + if (!ws_neighbour || !etx_entry) { + return 0xffff; + } + } else { + + if (!ws_neighbour || !etx_entry || etx_entry->etx_samples < 1 || + !ws_neighbour->candidate_parent) { + // if RSL value is not good enough candidate parent flag is removed and device not accepted as parent + //tr_debug("ws_etx_read not valid parent"); + return 0xffff; + } + + //If we are not following gbobal Broadcast synch + if (!interface->ws_info->pan_information.use_parent_bs) { + //We must know both information's here + if (!ws_neighbour->broadcast_shedule_info_stored || + !ws_neighbour->broadcast_timing_info_stored) { + return 0xffff; + } + } else { + if (!ws_neighbour->broadcast_timing_info_stored) { + //Global shedule is stored already + return 0xffff; + } + } + } + + etx = etx_local_etx_read(interface->id, attribute_index); + if (etx == 0) { + return 0xffff; + } + if (etx > 0x800) { + // Wi-SUN section 6.2.3.1.6.1 says ETX can only be maximum of 1024 (8*128) in RPL units, ie 8.0. + etx = 0x800; + } + + //tr_debug("ws_etx_read etx:%d", etx); + return etx; +} + +static int8_t ws_bootstrap_up(protocol_interface_info_entry_t *cur) +{ + int8_t ret_val = -1; + + if (!cur) { + return -1; + } + + if ((cur->configure_flags & INTERFACE_SETUP_MASK) != INTERFACE_SETUP_READY) { + tr_error("Interface not yet fully configured"); + return -2; + } + if (ws_fhss_initialize(cur) != 0) { + tr_error("fhss initialization failed"); + return -3; + } + + + // Save FHSS api + cur->ws_info->fhss_api = ns_sw_mac_get_fhss_api(cur->mac_api); + + ws_bootstrap_ll_address_validate(cur); + + addr_interface_set_ll64(cur, NULL); + cur->nwk_nd_re_scan_count = 0; + //WS_interface_up(cur); + // Trigger discovery for bootstrap + ret_val = nwk_6lowpan_up(cur); + if (ret_val) { + goto cleanup; + } + + /* Disable SLLAO send/mandatory receive with the ARO */ + cur->ipv6_neighbour_cache.use_eui64_as_slla_in_aro = true; + /* Omit sending of NA if ARO SUCCESS */ + cur->ipv6_neighbour_cache.omit_aro_success = true; + // do not process AROs from NA. This is overriden by Wi-SUN specific failure handling + cur->ipv6_neighbour_cache.recv_na_aro = false; + /* Disable NUD Probes */ + cur->ipv6_neighbour_cache.send_nud_probes = false; + cur->ipv6_neighbour_cache.probe_avoided_routers = true; + dhcp_client_init(cur->id); + dhcp_client_configure(cur->id, true); //RENEW uses SOLICIT + dhcp_client_solicit_timeout_set(cur->id, WS_DHCP_SOLICIT_TIMEOUT, WS_DHCP_SOLICIT_MAX_RT, WS_DHCP_SOLICIT_MAX_RC); + + + ws_nud_table_reset(cur); + + blacklist_params_set( + WS_BLACKLIST_ENTRY_LIFETIME, + WS_BLACKLIST_TIMER_MAX_TIMEOUT, + WS_BLACKLIST_TIMER_TIMEOUT, + WS_BLACKLIST_ENTRY_MAX_NBR, + WS_BLACKLIST_PURGE_NBR, + WS_BLACKLIST_PURGE_TIMER_TIMEOUT); + + ws_bootstrap_event_discovery_start(cur); + + return 0; +cleanup: + return ret_val; +} + +static int8_t ws_bootstrap_down(protocol_interface_info_entry_t *cur) +{ + if (!cur || !(cur->lowpan_info & INTERFACE_NWK_ACTIVE)) { + return -1; + } + + tr_debug("Wi-SUN ifdown"); + + // Reset WS information + // ws_common_reset(cur) + ws_llc_reset(cur); + if (nd_proxy_downstream_interface_unregister(cur->id) != 0) { + tr_warn("nd proxy unregister failed"); + } + ws_nud_table_reset(cur); + dhcp_client_delete(cur->id); + ws_eapol_relay_delete(cur); + ws_eapol_auth_relay_delete(cur); + ws_pae_controller_stop(cur); + blacklist_clear(); + + return nwk_6lowpan_down(cur); +} + +void ws_bootstrap_configuration_reset(protocol_interface_info_entry_t *cur) +{ + // Configure IP stack to operate as Wi-SUN node + + // Do not process beacons + cur->mac_parameters->beacon_ind = NULL; + cur->mac_parameters->mac_security_level = 0; + + // Set default parameters to interface + cur->configure_flags = INTERFACE_BOOTSTRAP_DEFINED; + cur->configure_flags |= INTERFACE_SECURITY_DEFINED; + cur->lowpan_info = 0; + + switch (cur->bootsrap_mode) { + // case NET_6LOWPAN_SLEEPY_HOST: + case ARM_NWK_BOOTSRAP_MODE_6LoWPAN_HOST: + break; + + case ARM_NWK_BOOTSRAP_MODE_6LoWPAN_ROUTER: + case ARM_NWK_BOOTSRAP_MODE_6LoWPAN_BORDER_ROUTER: + cur->lowpan_info |= INTERFACE_NWK_ROUTER_DEVICE; + break; + + default: + tr_err("Invalid bootstrap_mode"); + } + + cur->nwk_bootstrap_state = ER_ACTIVE_SCAN; + cur->ws_info->network_pan_id = 0xffff; + cur->ws_info->trickle_pas_running = false; + cur->ws_info->trickle_pa_running = false; + cur->ws_info->trickle_pcs_running = false; + cur->ws_info->trickle_pc_running = false; + + //cur->mac_security_key_usage_update_cb = ws_management_mac_security_key_update_cb; + return; +} + +static bool ws_bootstrap_network_name_matches(const struct mcps_data_ie_list *ie_ext, const char *network_name_ptr) +{ + if (!network_name_ptr || !ie_ext) { + return false; + } + + ws_wp_network_name_t network_name; + if (!ws_wp_nested_network_name_read(ie_ext->payloadIeList, ie_ext->payloadIeListLength, &network_name)) { + tr_warn("No network name IE"); + return false; + } + + if (network_name_ptr == NULL || strncmp(network_name_ptr, (char *)network_name.network_name, network_name.network_name_length) != 0) { + return false; + } + return true; +} + +static void ws_bootstrap_pan_advertisement_analyse_active(struct protocol_interface_info_entry *cur, ws_pan_information_t *pan_information) +{ + /* TODO In Active state + * + * A consistent transmission is defined as a PAN Advertisement received by a node with PAN ID and + * NETNAME-IE / Network Name matching that of the receiving node, and with a PAN-IE / Routing Cost + * the same or better than (less than or equal to) that of the receiving node. + * + * Inconsistent: + * PAN Advertisement solicit + * + * A PAN Advertisement received by a node with PAN ID and NETNAME-IE / Network name matching + * that of the receiving node, and PAN-IE / Routing Cost worse than (greater than) that of the receiving node. + * + */ + + if (pan_information->routing_cost <= cur->ws_info->pan_information.routing_cost) { + trickle_consistent_heard(&cur->ws_info->trickle_pan_advertisement); + } else { + trickle_inconsistent_heard(&cur->ws_info->trickle_pan_advertisement, &cur->ws_info->trickle_params_pan_discovery); + } + + // automatic network size adjustment + if (cur->ws_info->network_size_config == NETWORK_SIZE_AUTOMATIC && + cur->bootsrap_mode != ARM_NWK_BOOTSRAP_MODE_6LoWPAN_BORDER_ROUTER && + cur->ws_info->pan_information.pan_size != pan_information->pan_size) { + ws_common_network_size_configure(cur, pan_information->pan_size); + } +} + +static void ws_bootstrap_pan_advertisement_analyse(struct protocol_interface_info_entry *cur, const struct mcps_data_ind_s *data, const struct mcps_data_ie_list *ie_ext, ws_utt_ie_t *ws_utt, ws_us_ie_t *ws_us) +{ + + //Validate Pan Conrfirmation is at packet + ws_pan_information_t pan_information; + if (!ws_wp_nested_pan_read(ie_ext->payloadIeList, ie_ext->payloadIeListLength, &pan_information)) { + // Corrupted + tr_error("No pan information"); + return; + } + + // if in active scan state + if (!ws_bootstrap_state_discovery(cur)) { + if (data->SrcPANId != cur->ws_info->network_pan_id) { + tr_debug("Wrong PAN id r:%u own:%u", data->SrcPANId, cur->ws_info->network_pan_id); + return; + } + } + + + // Check pan flags so that it is valid + if (!pan_information.rpl_routing_method) { + // NOT RPL routing + tr_warn("Not supported routing"); + return; + } + + /* TODO smart neighbour process + * + * Unsecure packet we cant trust the device? + * + * This message is received from tens of devices and we must select the best parent + * + * We save the best parent and create entry when we have selected the EAPOL target + * + */ + + // Save route cost for all neighbours + llc_neighbour_req_t neighbor_info; + if (ws_bootstrap_neighbor_info_request(cur, data->SrcAddr, &neighbor_info, false)) { + neighbor_info.ws_neighbor->routing_cost = pan_information.routing_cost; + } + + // Save the best network parent + + if (ws_bootstrap_state_discovery(cur)) { + // Discovery state processing + tr_info("potential parent addr:%s panid:%x signal:%d", trace_array(data->SrcAddr, 8), data->SrcPANId, data->signal_dbm); + + // This parent is selected and used for authentication. + if (memcmp(cur->ws_info->parent_info.addr, ADDR_UNSPECIFIED, 8) != 0) { + + // if we dont have higher than threshold signal only signal level decides parent + if (ws_neighbor_class_rssi_from_dbm_calculate(cur->ws_info->parent_info.signal_dbm) < (CAND_PARENT_THRESHOLD + CAND_PARENT_HYSTERISIS) && + ws_neighbor_class_rssi_from_dbm_calculate(data->signal_dbm) > ws_neighbor_class_rssi_from_dbm_calculate(cur->ws_info->parent_info.signal_dbm)) { + // automatically select the best quality link from the below threshold + goto parent_selected; + } + // Drop if signal quality is not good enough + if (ws_neighbor_class_rssi_from_dbm_calculate(data->signal_dbm) < (CAND_PARENT_THRESHOLD + CAND_PARENT_HYSTERISIS)) { + tr_info("EAPOL target dropped Link quality too low"); + return; + } + + // Select the lowest PAN cost + uint16_t pan_cost = (pan_information.routing_cost / PRC_WEIGHT_FACTOR) + (pan_information.pan_size / PS_WEIGHT_FACTOR); + uint16_t current_pan_cost = (cur->ws_info->parent_info.pan_information.routing_cost / PRC_WEIGHT_FACTOR) + (cur->ws_info->parent_info.pan_information.pan_size / PS_WEIGHT_FACTOR); + if (current_pan_cost < pan_cost) { + tr_info("EAPOL target dropped Higher Pan cost"); + return; + } + + // If pan cost is the same then we select the one we hear highest + if (current_pan_cost == pan_cost && + cur->ws_info->parent_info.signal_dbm > data->signal_dbm) { + tr_info("EAPOL target dropped Lower link quality"); + return; + } + + } else { + // First advertise heard + + if (ws_neighbor_class_rssi_from_dbm_calculate(data->signal_dbm) < (CAND_PARENT_THRESHOLD + CAND_PARENT_HYSTERISIS)) { + // First neighbor is too low we need to wait one extra trickle + cur->bootsrap_state_machine_cnt += cur->ws_info->trickle_params_pan_discovery.Imin + randLIB_get_8bit() % 50; + } + } + +parent_selected: + // Parent valid store information + cur->ws_info->parent_info.ws_utt = *ws_utt; + // Saved from unicast IE + cur->ws_info->parent_info.ws_us = *ws_us; + + // Saved from Pan information, do not overwrite pan_version as it is not valid here + cur->ws_info->parent_info.pan_information.pan_size = pan_information.pan_size; + cur->ws_info->parent_info.pan_information.routing_cost = pan_information.routing_cost; + cur->ws_info->parent_info.pan_information.use_parent_bs = pan_information.use_parent_bs; + cur->ws_info->parent_info.pan_information.rpl_routing_method = pan_information.rpl_routing_method; + cur->ws_info->parent_info.pan_information.version = pan_information.version; + + // Saved from message + cur->ws_info->parent_info.timestamp = data->timestamp; + cur->ws_info->parent_info.pan_id = data->SrcPANId; + cur->ws_info->parent_info.link_quality = data->mpduLinkQuality; + cur->ws_info->parent_info.signal_dbm = data->signal_dbm; + memcpy(cur->ws_info->parent_info.addr, data->SrcAddr, 8); + + tr_info("New parent addr:%s panid:%x signal:%d", trace_array(cur->ws_info->parent_info.addr, 8), cur->ws_info->parent_info.pan_id, cur->ws_info->parent_info.signal_dbm); + return; + } + // Active state processing + ws_bootstrap_pan_advertisement_analyse_active(cur, &pan_information); + + // Learn latest network information + if (cur->bootsrap_mode != ARM_NWK_BOOTSRAP_MODE_6LoWPAN_BORDER_ROUTER) { + cur->ws_info->pan_information.pan_size = pan_information.pan_size; + cur->ws_info->pan_information.routing_cost = pan_information.routing_cost; + cur->ws_info->pan_information.rpl_routing_method = pan_information.rpl_routing_method; + cur->ws_info->pan_information.use_parent_bs = pan_information.use_parent_bs; + cur->ws_info->pan_information.version = pan_information.version; + } +} + +static void ws_bootstrap_pan_advertisement_solicit_analyse(struct protocol_interface_info_entry *cur, const struct mcps_data_ind_s *data, ws_utt_ie_t *ws_utt, ws_us_ie_t *ws_us) +{ + + (void)data; + (void)ws_utt; + (void)ws_us; + /* + * An inconsistent transmission is defined as: + * A PAN Advertisement Solicit with NETNAME-IE matching that of the receiving node. + */ + trickle_inconsistent_heard(&cur->ws_info->trickle_pan_advertisement, &cur->ws_info->trickle_params_pan_discovery); + /* + * A consistent transmission is defined as + * a PAN Advertisement Solicit with NETNAME-IE / Network Name matching that configured on the receiving node. + */ + trickle_consistent_heard(&cur->ws_info->trickle_pan_advertisement_solicit); +} + + +static void ws_bootstrap_pan_config_analyse(struct protocol_interface_info_entry *cur, const struct mcps_data_ind_s *data, const struct mcps_data_ie_list *ie_ext, ws_utt_ie_t *ws_utt, ws_us_ie_t *ws_us) +{ + + uint16_t pan_version; + ws_bs_ie_t ws_bs_ie; + uint8_t *gtkhash_ptr; + + + if (data->SrcPANId != cur->ws_info->network_pan_id) { + tr_debug("Wrong PAN id r:%u own:%u", data->SrcPANId, cur->ws_info->network_pan_id); + return; + } + ws_bt_ie_t ws_bt_ie; + if (!ws_wh_bt_read(ie_ext->headerIeList, ie_ext->headerIeListLength, &ws_bt_ie)) { + tr_warn("BT-IE"); + return; + } + + /* + * A consistent transmission is defined as a PAN Configuration with a PAN-ID matching that of the receiving node and + * a PANVER-IE / PAN Version greater than or equal to the receiving node’s current PAN version. + * + * A inconsistent transmission is defined as: + * + * A PAN Configuration with PAN-ID matching that of the receiving node and a + * PANVER-IE / PAN Version that is less than the receiving node’s current PAN version. + */ + + // TODO Add this to neighbor table + // TODO save all information from config message if version number has changed + + if (!ws_wp_nested_pan_version_read(ie_ext->payloadIeList, ie_ext->payloadIeListLength, &pan_version)) { + // Corrupted + tr_warn("no version"); + return; + } + + gtkhash_ptr = ws_wp_nested_gtkhash_read(ie_ext->payloadIeList, ie_ext->payloadIeListLength); + + if (!gtkhash_ptr) { + // Corrupted + tr_error("No gtk hash"); + return; + } + + if (!ws_wp_nested_bs_read(ie_ext->payloadIeList, ie_ext->payloadIeListLength, &ws_bs_ie)) { + // Corrupted + tr_error("No broadcast schedule"); + return; + } + llc_neighbour_req_t neighbor_info; + if (!ws_bootstrap_neighbor_info_request(cur, data->SrcAddr, &neighbor_info, true)) { + return; + } + + etx_lqi_dbm_update(cur->id, data->mpduLinkQuality, data->signal_dbm, neighbor_info.neighbor->index); + //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_broadcast_time_info_update(neighbor_info.ws_neighbor, &ws_bt_ie, data->timestamp); + ws_neighbor_class_neighbor_broadcast_schedule_set(neighbor_info.ws_neighbor, &ws_bs_ie); + + if (cur->ws_info->configuration_learned) { + // received version is lower se we need to reset the trickle + if (cur->ws_info->pan_information.pan_version == pan_version) { + trickle_consistent_heard(&cur->ws_info->trickle_pan_config); + } else { + tr_info("different pan version heard"); + trickle_inconsistent_heard(&cur->ws_info->trickle_pan_config, &cur->ws_info->trickle_params_pan_discovery); + if (common_serial_number_greater_16(cur->ws_info->pan_information.pan_version, pan_version)) { + // older version heard ignoring the message + return; + } + } + + + } + + if (cur->bootsrap_mode == ARM_NWK_BOOTSRAP_MODE_6LoWPAN_BORDER_ROUTER) { + //Border router does not learn network information + return; + } + + if (cur->ws_info->configuration_learned) { + bool old_version = cur->ws_info->pan_information.pan_version == pan_version; + if (neighbor_info.neighbor->link_role == PRIORITY_PARENT_NEIGHBOUR) { + // RPL priority parent configuration we must update FHSS data + //Update synch to primary parent allways to update broadcast shedule and timing + ws_bootstrap_primary_parent_set(cur, &neighbor_info, !old_version); + } + + if (old_version) { + // No new information + return; + } + } + + /* + * Learn new information from border router + */ + tr_info("Updated PAN configuration heard"); + + cur->ws_info->pan_version_timeout_timer = PAN_VERSION_TIMEOUT; + cur->ws_info->pan_information.pan_version = pan_version; + memcpy(cur->ws_info->gtkhash, gtkhash_ptr, 32); + + if (!cur->ws_info->configuration_learned) { + // Generate own hopping schedules Follow first parent broadcast and plans and also use same unicast dwell + tr_info("learn network configuration"); + cur->ws_info->configuration_learned = true; + // return to state machine after 1-2 s + cur->bootsrap_state_machine_cnt = randLIB_get_random_in_range(10, 20); + // enable frequency hopping for unicast channel and start listening first neighbour + ws_bootstrap_primary_parent_set(cur, &neighbor_info, true); + // set neighbor as priority parent clear if there is others + protocol_6lowpan_neighbor_priority_clear_all(cur->id, PRIORITY_1ST); + neighbor_info.neighbor->link_role = PRIORITY_PARENT_NEIGHBOUR; + } +} + +static void ws_bootstrap_pan_config_solicit_analyse(struct protocol_interface_info_entry *cur, const struct mcps_data_ind_s *data, ws_utt_ie_t *ws_utt, ws_us_ie_t *ws_us) +{ + if (data->SrcPANId != cur->ws_info->network_pan_id) { + tr_debug("Wrong PAN id r:%u own:%u", data->SrcPANId, cur->ws_info->network_pan_id); + return; + } + + /* TODO smart neighbour process + * + * Unsecure packet we cant trust the device? + * + * Question mark in specification also present, now we create neighbour. + * this is moved in future to NS/ND processing triggered by RPL + * + */ + + llc_neighbour_req_t neighbor_info; + if (!ws_bootstrap_neighbor_info_request(cur, data->SrcAddr, &neighbor_info, true)) { + return; + } + + etx_lqi_dbm_update(cur->id, data->mpduLinkQuality, data->signal_dbm, neighbor_info.neighbor->index); + 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); + + /* + * A consistent transmission is defined as a PAN Configuration Solicit with + * a PAN-ID matching that of the receiving node and a NETNAME-IE / Network Name + * matching that configured on the receiving node. + */ + trickle_consistent_heard(&cur->ws_info->trickle_pan_config_solicit); + /* + * inconsistent transmission is defined as either: + * A PAN Configuration Solicit with a PAN-ID matching that of the receiving node and + * a NETNAME-IE / Network Name matching the network name configured on the receiving + */ + trickle_inconsistent_heard(&cur->ws_info->trickle_pan_config, &cur->ws_info->trickle_params_pan_discovery); +} +static bool ws_bootstrap_network_found(protocol_interface_info_entry_t *cur) +{ + tr_debug("analyze network discovery result"); + + // This parent is used for authentication to the network + if (memcmp(cur->ws_info->parent_info.addr, ADDR_UNSPECIFIED, 8) == 0) { + // No parent found yet + return false; + } + return true; +} + +static bool ws_channel_plan_zero_compare(ws_channel_plan_zero_t *rx_plan, ws_hopping_schedule_t *hopping_schdule) +{ + if (rx_plan->operation_class != hopping_schdule->operating_class) { + return false; + } else if (rx_plan->regulator_domain != hopping_schdule->regulatory_domain) { + return false; + } + return true; +} + +static bool ws_channel_plan_one_compare(ws_channel_plan_one_t *rx_plan, ws_hopping_schedule_t *hopping_schdule) +{ + uint16_t num_of_channel = hopping_schdule->number_of_channels; + if (rx_plan->ch0 != hopping_schdule->ch0_freq) { + return false; + } else if (rx_plan->channel_spacing != hopping_schdule->channel_spacing) { + return false; + } else if (rx_plan->number_of_channel != num_of_channel) { + 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) +{ + + if (data->SrcAddrMode != MAC_ADDR_MODE_64_BIT) { + // Not from long address + return; + } + //Validate network name + switch (message_type) { + case WS_FT_PAN_ADVERT: + case WS_FT_PAN_ADVERT_SOL: + case WS_FT_PAN_CONF_SOL: + //Check Network Name + if (!ws_bootstrap_network_name_matches(ie_ext, cur->ws_info->network_name)) { + // Not in our network + return; + } + break; + case WS_FT_PAN_CONF: + break; + default: + return; + } + + //UTT-IE and US-IE are mandatory for all Asynch Messages + ws_utt_ie_t ws_utt; + if (!ws_wh_utt_read(ie_ext->headerIeList, ie_ext->headerIeListLength, &ws_utt)) { + // Corrupted + return; + } + + ws_us_ie_t ws_us; + if (!ws_wp_nested_us_read(ie_ext->payloadIeList, ie_ext->payloadIeListLength, &ws_us)) { + // Corrupted + return; + } + + //Compare Unicast channel Plan + if (ws_us.channel_plan != cur->ws_info->hopping_schdule.channel_plan) { + return; + } + + if (ws_us.channel_plan == 0) { + if (!ws_channel_plan_zero_compare(&ws_us.plan.zero, &cur->ws_info->hopping_schdule)) { + return; + } + } else if (ws_us.channel_plan == 1) { + if (!ws_channel_plan_one_compare(&ws_us.plan.one, &cur->ws_info->hopping_schdule)) { + return; + } + } + + //Handle Message's + switch (message_type) { + case WS_FT_PAN_ADVERT: + // Analyse Advertisement + tr_debug("received ADVERT"); + ws_bootstrap_pan_advertisement_analyse(cur, data, ie_ext, &ws_utt, &ws_us); + break; + case WS_FT_PAN_ADVERT_SOL: + tr_debug("received ADVERT SOL"); + ws_bootstrap_pan_advertisement_solicit_analyse(cur, data, &ws_utt, &ws_us); + break; + case WS_FT_PAN_CONF: + tr_debug("received CONFIG"); + ws_bootstrap_pan_config_analyse(cur, data, ie_ext, &ws_utt, &ws_us); + break; + default: + tr_debug("received CONFIG SOL"); + ws_bootstrap_pan_config_solicit_analyse(cur, data, &ws_utt, &ws_us); + break; + } +} + +static void ws_bootstrap_asynch_confirm(struct protocol_interface_info_entry *interface, uint8_t asynch_message) +{ + (void)interface; + (void)asynch_message; +} +static void ws_bootstrap_neighbor_table_clean(struct protocol_interface_info_entry *interface) +{ + uint8_t ll_target[16]; + + if (mac_neighbor_info(interface)->neighbour_list_size <= mac_neighbor_info(interface)->list_total_size - WS_NON_CHILD_NEIGHBOUR_COUNT) { + // Enough neighbor entries + return; + } + memcpy(ll_target, ADDR_LINK_LOCAL_PREFIX, 8); + + mac_neighbor_table_entry_t *neighbor_entry_ptr = NULL; + ns_list_foreach_safe(mac_neighbor_table_entry_t, cur, &mac_neighbor_info(interface)->neighbour_list) { + + if (cur->link_role == PRIORITY_PARENT_NEIGHBOUR) { + //This is our primary parent we cannot delete + continue; + } + + if (neighbor_entry_ptr && neighbor_entry_ptr->lifetime < cur->lifetime) { + // We have already shorter link entry found this cannot replace it + continue; + } + + if (ipv6_neighbour_has_registered_by_eui64(&interface->ipv6_neighbour_cache, cur->mac64)) { + // We have registered entry so we have been selected as parent + continue; + } + + memcpy(ll_target + 8, cur->mac64, 8); + ll_target[8] ^= 2; + + if (rpl_control_is_dodag_parent(interface, ll_target)) { + // Possible parent is limited to 3 by default? + continue; + } + neighbor_entry_ptr = cur; + } + if (neighbor_entry_ptr) { + tr_info("dropped oldest neighbour %s", trace_array(neighbor_entry_ptr->mac64, 8)); + mac_neighbor_table_neighbor_remove(mac_neighbor_info(interface), neighbor_entry_ptr); + } + +} + +static bool ws_bootstrap_neighbor_info_request(struct protocol_interface_info_entry *interface, const uint8_t *mac_64, llc_neighbour_req_t *neighbor_buffer, bool request_new) +{ + neighbor_buffer->neighbor = mac_neighbor_table_address_discover(mac_neighbor_info(interface), mac_64, ADDR_802_15_4_LONG); + if (neighbor_buffer->neighbor) { + neighbor_buffer->ws_neighbor = ws_neighbor_class_entry_get(&interface->ws_info->neighbor_storage, neighbor_buffer->neighbor->index); + if (!neighbor_buffer->ws_neighbor) { + return false; + } + return true; + } + if (!request_new) { + return false; + } + uint8_t ll_target[16]; + memcpy(ll_target, ADDR_LINK_LOCAL_PREFIX, 8); + memcpy(ll_target + 8, mac_64, 8); + ll_target[8] ^= 2; + + + if (blacklist_reject(ll_target)) { + // Rejected by blacklist + return false; + } + + ws_bootstrap_neighbor_table_clean(interface); + + neighbor_buffer->neighbor = ws_bootstrap_mac_neighbor_add(interface, mac_64); + + if (!neighbor_buffer->neighbor) { + return false; + } + + neighbor_buffer->ws_neighbor = ws_neighbor_class_entry_get(&interface->ws_info->neighbor_storage, neighbor_buffer->neighbor->index); + if (!neighbor_buffer->ws_neighbor) { + mac_neighbor_table_neighbor_remove(mac_neighbor_info(interface), neighbor_buffer->neighbor); + return false; + } + return true; +} + + +static void ws_neighbor_entry_remove_notify(mac_neighbor_table_entry_t *entry_ptr, void *user_data) +{ + + protocol_interface_info_entry_t *cur = user_data; + lowpan_adaptation_remove_free_indirect_table(cur, entry_ptr); + // Sleepy host + if (cur->lowpan_info & INTERFACE_NWK_CONF_MAC_RX_OFF_IDLE) { + mac_data_poll_protocol_poll_mode_decrement(cur); + } + + //TODO State machine check here + + if (entry_ptr->ffd_device) { + protocol_6lowpan_release_short_link_address_from_neighcache(cur, entry_ptr->mac16); + protocol_6lowpan_release_long_link_address_from_neighcache(cur, entry_ptr->mac64); + } + ws_bootstrap_neighbor_delete(cur, entry_ptr->index); +} + +static bool ws_neighbor_entry_nud_notify(mac_neighbor_table_entry_t *entry_ptr, void *user_data) +{ + uint32_t time_from_start = entry_ptr->link_lifetime - entry_ptr->lifetime; + bool activate_nud = false; + protocol_interface_info_entry_t *cur = user_data; + + ws_neighbor_class_entry_t *ws_neighbor = ws_neighbor_class_entry_get(&cur->ws_info->neighbor_storage, entry_ptr->index); + etx_storage_t *etx_entry = etx_storage_entry_get(cur->id, entry_ptr->index); + + if (!entry_ptr->trusted_device || !ws_neighbor || !etx_entry) { + return false; + } + + if (time_from_start > WS_NEIGHBOR_NUD_TIMEOUT) { + + if (time_from_start > WS_NEIGHBOR_NUD_TIMEOUT * 1.5) { + activate_nud = true; + } else { + uint16_t switch_prob = randLIB_get_random_in_range(0, WS_NUD_RANDOM_SAMPLE_LENGTH - 1); + //Take Random from time WS_NEIGHBOR_NUD_TIMEOUT - WS_NEIGHBOR_NUD_TIMEOUT*1.5 + if (switch_prob < WS_NUD_RANDOM_COMPARE) { + activate_nud = true; + } + } + } else if (etx_entry->etx_samples < WS_NEIGBOR_ETX_SAMPLE_MAX) { + //Take Random number for trig a prope. + //ETX Sample 0: random 1-8 + //ETX Sample 1: random 2-16 + //ETX Sample 2: random 4-32 + uint32_t probe_period = WS_PROBE_INIT_BASE_SECONDS << etx_entry->etx_samples; + uint32_t time_block = 1 << etx_entry->etx_samples; + if (time_from_start >= probe_period) { + tr_debug("Link Probe test %u Sample trig", etx_entry->etx_samples); + activate_nud = true; + } else if (time_from_start > time_block) { + uint16_t switch_prob = randLIB_get_random_in_range(0, probe_period - 1); + //Take Random from time WS_NEIGHBOR_NUD_TIMEOUT - WS_NEIGHBOR_NUD_TIMEOUT*1.5 + if (switch_prob < 2) { + tr_debug("Link Probe test with jitter %"PRIu32", sample %u", time_from_start, etx_entry->etx_samples); + activate_nud = true; + } + } + } + + if (!activate_nud) { + return false; + } + + ws_nud_table_entry_t *entry = ws_nud_entry_get_free(cur); + if (!entry) { + return false; + } + entry->neighbor_info = entry_ptr; + + if (etx_entry->etx_samples >= WS_NEIGBOR_ETX_SAMPLE_MAX) { + entry->nud_process = true; + } + return true; +} + +int ws_bootstrap_init(int8_t interface_id, net_6lowpan_mode_e bootstrap_mode) +{ + int ret_val = 0; + + ws_neighbor_class_t neigh_info; + neigh_info.neigh_info_list = NULL; + neigh_info.list_size = 0; + protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(interface_id); + if (!cur) { + return -1; + } + + mac_description_storage_size_t buffer; + if (!cur->mac_api || !cur->mac_api->mac_storage_sizes_get || cur->mac_api->mac_storage_sizes_get(cur->mac_api, &buffer) != 0) { + return -2; + } + + if (buffer.key_description_table_size < 4) { + tr_err("MAC key_description_table_size too short %d<4", buffer.key_description_table_size); + return -2; + } + + if (!etx_storage_list_allocate(cur->id, buffer.device_decription_table_size)) { + return -1; + } + if (blacklist_init() != 0) { + tr_err("MLE blacklist init failed."); + return -1; + } + + switch (bootstrap_mode) { + // case NET_6LOWPAN_SLEEPY_HOST: + case NET_6LOWPAN_HOST: + cur->bootsrap_mode = ARM_NWK_BOOTSRAP_MODE_6LoWPAN_HOST; + break; + case NET_6LOWPAN_ROUTER: + cur->bootsrap_mode = ARM_NWK_BOOTSRAP_MODE_6LoWPAN_ROUTER; + break; + case NET_6LOWPAN_BORDER_ROUTER: + cur->bootsrap_mode = ARM_NWK_BOOTSRAP_MODE_6LoWPAN_BORDER_ROUTER; + break; + default: + return -3; + } + + if (!ws_neighbor_class_alloc(&neigh_info, buffer.device_decription_table_size)) { + ret_val = -1; + goto init_fail; + } + + //Disable allways by default + lowpan_adaptation_interface_mpx_register(interface_id, NULL, 0); + + mac_neighbor_table_delete(mac_neighbor_info(cur)); + mac_neighbor_info(cur) = mac_neighbor_table_create(buffer.device_decription_table_size, ws_neighbor_entry_remove_notify + , ws_neighbor_entry_nud_notify, cur); + if (!mac_neighbor_info(cur)) { + ret_val = -1; + goto init_fail; + } + + ws_llc_create(cur, &ws_bootstrap_asynch_ind, &ws_bootstrap_asynch_confirm, &ws_bootstrap_neighbor_info_request); + + mpx_api_t *mpx_api = ws_llc_mpx_api_get(cur); + if (!mpx_api) { + ret_val = -4; + goto init_fail; + } + + if (ws_common_allocate_and_init(cur) < 0) { + ret_val = -4; + goto init_fail; + } + + if (ws_bootstrap_tasklet_init(cur) != 0) { + ret_val = -4; + goto init_fail; + } + + //Register MPXUser to adapatation layer + if (lowpan_adaptation_interface_mpx_register(interface_id, mpx_api, MPX_LOWPAN_ENC_USER_ID) != 0) { + ret_val = -4; + goto init_fail; + } + + //Init PAE controller and set callback + if (ws_pae_controller_init(cur) < 0) { + ret_val = -4; + goto init_fail; + } + if (ws_pae_controller_cb_register(cur, &ws_bootstrap_authentication_completed, &ws_bootstrap_key_insert) < 0) { + ret_val = -4; + goto init_fail; + } + + //Init EAPOL PDU handler and register it to MPX + if (ws_eapol_pdu_init(cur) < 0) { + ret_val = -4; + goto init_fail; + } + if (ws_eapol_pdu_mpx_register(cur, mpx_api, MPX_KEY_MANAGEMENT_ENC_USER_ID != 0)) { + ret_val = -4; + // add deallocs + goto init_fail; + } + + cur->if_up = ws_bootstrap_up; + cur->if_down = ws_bootstrap_down; + cur->ws_info->neighbor_storage = neigh_info; + cur->etx_read_override = ws_etx_read; + + ws_bootstrap_configuration_reset(cur); + addr_notification_register(ws_bootstrap_address_notification_cb); + //Enable MAC Security by pass + mlme_set_t set_req; + bool state = true; + set_req.attr = macAcceptByPassUnknowDevice; + set_req.attr_index = 0; + set_req.value_pointer = &state; + set_req.value_size = sizeof(bool); + cur->mac_api->mlme_req(cur->mac_api, MLME_SET, &set_req); + + // Set the default parameters for MPL + cur->mpl_proactive_forwarding = true; + + cur->mpl_data_trickle_params.Imin = MPL_MS_TO_TICKS(DATA_MESSAGE_IMIN); + cur->mpl_data_trickle_params.Imax = MPL_MS_TO_TICKS(DATA_MESSAGE_IMAX); + cur->mpl_data_trickle_params.TimerExpirations = DATA_MESSAGE_TIMER_EXPIRATIONS; + cur->mpl_data_trickle_params.k = 8; + + // Specification is ruling out the compression mode, but we are now doing it. + cur->mpl_seed = true; + cur->mpl_seed_id_mode = MULTICAST_MPL_SEED_ID_IPV6_SRC_FOR_DOMAIN; + cur->mpl_seed_set_entry_lifetime = MPL_SEED_SET_ENTRY_TIMEOUT; + + cur->mpl_control_trickle_params.TimerExpirations = 0; + + mpl_domain_create(cur, ADDR_ALL_MPL_FORWARDERS, NULL, MULTICAST_MPL_SEED_ID_DEFAULT, -1, 0, NULL, NULL); + addr_add_group(cur, ADDR_REALM_LOCAL_ALL_NODES); + addr_add_group(cur, ADDR_REALM_LOCAL_ALL_ROUTERS); + + return 0; + + //Error handling and free memory +init_fail: + lowpan_adaptation_interface_mpx_register(interface_id, NULL, 0); + ws_eapol_pdu_mpx_register(cur, NULL, 0); + mac_neighbor_table_delete(mac_neighbor_info(cur)); + etx_storage_list_allocate(cur->id, 0); + ws_neighbor_class_dealloc(&neigh_info); + ws_llc_delete(cur); + ws_eapol_pdu_delete(cur); + ws_pae_controller_delete(cur); + return ret_val; +} + +int ws_bootstrap_restart(int8_t interface_id) +{ + protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(interface_id); + if (!cur || !cur->ws_info) { + return -1; + } + ws_bootstrap_event_discovery_start(cur); + return 0; +} + +int ws_bootstrap_set_rf_config(protocol_interface_info_entry_t *cur, phy_rf_channel_configuration_s rf_configs) +{ + mlme_set_t set_request; + // Set RF configuration + set_request.attr = macRfConfiguration; + set_request.value_pointer = &rf_configs; + set_request.value_size = sizeof(phy_rf_channel_configuration_s); + cur->mac_api->mlme_req(cur->mac_api, MLME_SET, &set_request); + // Set Ack wait duration + uint16_t ack_wait_symbols = WS_ACK_WAIT_SYMBOLS + (WS_TACK_MAX_MS * (rf_configs.datarate / 1000)); + set_request.attr = macAckWaitDuration; + set_request.value_pointer = &ack_wait_symbols; + set_request.value_size = sizeof(ack_wait_symbols); + cur->mac_api->mlme_req(cur->mac_api, MLME_SET, &set_request); + return 0; +} + +int ws_bootstrap_neighbor_remove(protocol_interface_info_entry_t *cur, const uint8_t *ll_address) +{ + tr_warn("ARO registration Failure %s", trace_ipv6(ll_address)); + + blacklist_update(ll_address, false); + rpl_control_neighbor_delete(cur, ll_address); + + mac_neighbor_table_entry_t *mac_neighbor = mac_neighbor_entry_get_by_ll64(mac_neighbor_info(cur), ll_address, false, NULL); + + if (mac_neighbor) { + ws_bootstrap_neighbor_delete(cur, mac_neighbor->index); + // TODO Add to blacklist + } + return 0; +} + + + +static void ws_bootstrap_mac_activate(protocol_interface_info_entry_t *cur, uint16_t channel, uint16_t panid, bool coordinator) +{ + mlme_start_t start_req; + memset(&start_req, 0, sizeof(mlme_start_t)); + + cur->mac_parameters->pan_id = panid; + cur->mac_parameters->mac_channel = channel; + + start_req.PANId = panid; + start_req.LogicalChannel = channel; + start_req.BeaconOrder = 0x0f; + start_req.SuperframeOrder = 0x0f; + start_req.PANCoordinator = coordinator; + + if (cur->mac_api) { + cur->mac_api->mlme_req(cur->mac_api, MLME_START, (void *)&start_req); + } +} + +static void ws_bootstrap_fhss_activate(protocol_interface_info_entry_t *cur) +{ + tr_debug("FHSS activate"); + ws_fhss_enable(cur); + ws_llc_hopping_schedule_config(cur, &cur->ws_info->hopping_schdule); + // Only supporting fixed channel + + tr_debug("MAC init"); + mac_helper_pib_boolean_set(cur, macRxOnWhenIdle, true); + cur->lowpan_info &= ~INTERFACE_NWK_CONF_MAC_RX_OFF_IDLE; + ws_bootstrap_mac_activate(cur, cur->ws_info->fhss_uc_fixed_channel, cur->ws_info->network_pan_id, true); + return; +} + +static void ws_bootstrap_network_information_learn(protocol_interface_info_entry_t *cur) +{ + tr_debug("learn network information from parent"); + + // Start following network broadcast timing schedules + + // Regulatory domain saving? cant change? + + // Save network information + cur->ws_info->network_pan_id = cur->ws_info->parent_info.pan_id; + cur->ws_info->pan_information = cur->ws_info->parent_info.pan_information; + cur->ws_info->pan_information.pan_version = 0; // This is learned from actual configuration + + // TODO create parent neighbour table entry for unicast schedule to enable authentication + + return; +} +static void ws_bootstrap_network_configuration_learn(protocol_interface_info_entry_t *cur) +{ + tr_debug("Start using PAN configuration"); + + // Timing information can be modified here + ws_llc_set_pan_information_pointer(cur, &cur->ws_info->pan_information); + ws_llc_set_gtkhash(cur, cur->ws_info->gtkhash); + // TODO update own fhss schedules we are starting to follow first parent + + return; +} + +static void ws_bootstrap_ip_stack_addr_clear(protocol_interface_info_entry_t *cur) +{ + tr_debug("ip stack address clear"); + ns_list_foreach_safe(if_address_entry_t, addr, &cur->ip_addresses) { + if (addr->source != ADDR_SOURCE_STATIC && + addr_ipv6_scope(addr->address, cur) > IPV6_SCOPE_LINK_LOCAL) { + // Remove all exept User set address + addr_delete_entry(cur, addr); + } + } +} + +static void ws_bootstrap_ip_stack_reset(protocol_interface_info_entry_t *cur) +{ + tr_debug("ip stack reset"); + // Delete all temporary cached information + ipv6_neighbour_cache_flush(&cur->ipv6_neighbour_cache); + lowpan_context_list_free(&cur->lowpan_contexts); +} + +static void ws_bootstrap_ip_stack_activate(protocol_interface_info_entry_t *cur) +{ + tr_debug("ip stack init"); + clear_power_state(ICMP_ACTIVE); + cur->lowpan_info |= INTERFACE_NWK_BOOTSRAP_ACTIVE; + ws_bootstrap_ip_stack_reset(cur); +} + +static void ws_set_fhss_hop(protocol_interface_info_entry_t *cur) +{ + uint16_t own_rank = ws_bootstrap_rank_get(cur); + uint16_t rank_inc = ws_bootstrap_min_rank_inc_get(cur); + if (own_rank == 0xffff || rank_inc == 0xffff) { + return; + } + // Calculate own hop count. This method gets inaccurate when hop count increases. + uint8_t own_hop = (own_rank - rank_inc) / rank_inc; + ns_fhss_ws_set_hop_count(cur->ws_info->fhss_api, own_hop); + tr_debug("own hop: %u, own rank: %u, rank inc: %u", own_hop, own_rank, rank_inc); +} + +static void ws_address_registration_update(protocol_interface_info_entry_t *interface) +{ + if (!interface->ws_info->address_registration_event_active) { + interface->ws_info->address_registration_event_active = true; + tr_info("RPL parent update ... register ARO"); + ws_bootsrap_event_trig(WS_ADDRESS_ADDED, interface->bootStrapId, ARM_LIB_LOW_PRIORITY_EVENT, NULL); + } +} + +static void ws_bootstrap_rpl_callback(rpl_event_t event, void *handle) +{ + + protocol_interface_info_entry_t *cur = handle; + if (!cur->rpl_domain || cur->interface_mode != INTERFACE_UP) { + return; + } + // if waiting for RPL and + if (event == RPL_EVENT_DAO_DONE) { + // Trigger statemachine check + cur->bootsrap_state_machine_cnt = 1; + rpl_dodag_info_t dodag_info; + struct rpl_instance *instance = rpl_control_enumerate_instances(cur->rpl_domain, NULL); + + if (instance && rpl_control_read_dodag_info(instance, &dodag_info)) { + tr_debug("Enable DHCPv6 relay"); + dhcp_relay_agent_enable(cur->id, dodag_info.dodag_id); + + tr_debug("Start EAPOL relay"); + // 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->network_name); + // Network key is valid + ws_pae_controller_nw_key_valid(cur); + } + + ws_set_fhss_hop(cur); + + } else if (event == RPL_EVENT_LOCAL_REPAIR_NO_MORE_DIS) { + /* + * RPL goes to passive mode, but does not require any extra changed + * + * We could remove our current addresses learned from RPL + * We could send solicit for configuration and then select new parent when those arrive + * + */ + + } else if (event == RPL_EVENT_DAO_PARENT_SWITCH) { + ws_address_registration_update(cur); + } + cur->ws_info->rpl_state = event; + tr_info("RPL event %d", event); +} + +static void ws_dhcp_client_global_adress_cb(int8_t interface, uint8_t dhcp_addr[static 16], uint8_t prefix[static 16], bool register_status) +{ + (void)prefix; + (void)interface; + //TODO add handler for negative status + tr_debug("DHCPv6 %s status %u", trace_ipv6(dhcp_addr), register_status); +} + +static bool ws_address_entry_available(uint8_t *prefixPtr, if_address_list_t *list) +{ + bool addressReady = false; + ns_list_foreach(if_address_entry_t, entry, list) { + if (prefixPtr) { + if (memcmp(entry->address, prefixPtr, 8) == 0) { + addressReady = true; + break; + } + } else { + if (entry->source == ADDR_SOURCE_DHCP) { + addressReady = true; + break; + } + } + } + return addressReady; +} + +void ws_dhcp_client_address_request(protocol_interface_info_entry_t *cur, uint8_t *prefix, uint8_t *parent_link_local) +{ + if (!ws_address_entry_available(prefix, &cur->ip_addresses)) { + if (dhcp_client_get_global_address(cur->id, parent_link_local, prefix, cur->mac, DHCPV6_DUID_HARDWARE_IEEE_802_NETWORKS_TYPE, ws_dhcp_client_global_adress_cb) != 0) { + tr_error("DHCPp client request fail"); + } + } +} + +void ws_dhcp_client_address_delete(protocol_interface_info_entry_t *cur, uint8_t *prefix) +{ + dhcp_client_global_address_delete(cur->id, NULL, prefix); +} + +bool ws_eapol_relay_state_active(protocol_interface_info_entry_t *cur) +{ + if (cur->bootsrap_mode == ARM_NWK_BOOTSRAP_MODE_6LoWPAN_BORDER_ROUTER || cur->nwk_bootstrap_state == ER_BOOTSRAP_DONE) { + return true; + } + + return false; +} + +static void ws_rpl_prefix_callback(prefix_entry_t *prefix, void *handle, uint8_t *parent_link_local) +{ + protocol_interface_info_entry_t *cur = (protocol_interface_info_entry_t *) handle; + /* Check if A-Flag. + * A RPL node may use this option for the purpose of Stateless Address Autoconfiguration (SLAAC) + * from a prefix advertised by a parent. + */ + if (prefix->options & PIO_A) { + if (icmpv6_slaac_prefix_update(cur, prefix->prefix, prefix->prefix_len, prefix->lifetime, prefix->preftime) != 0) { + ipv6_interface_slaac_handler(cur, prefix->prefix, prefix->prefix_len, prefix->lifetime, prefix->preftime); + } + } else if (prefix->prefix_len) { + if (prefix->preftime == 0) { + // Delete all pending transactions from DHCP + // TODO this also deletes the address even when lifetime would allow it to be present + dhcp_client_global_address_delete(cur->id, NULL, prefix->prefix); + } else { + // Create new address using DHCP + ws_dhcp_client_address_request(cur, prefix->prefix, parent_link_local); + } + // If we have addresses generated we update the lifetimes always + ns_list_foreach(if_address_entry_t, entry, &cur->ip_addresses) { + if (entry->prefix_len == prefix->prefix_len && bitsequal(entry->address, prefix->prefix, prefix->prefix_len)) { + entry->preferred_lifetime = prefix->preftime; + entry->valid_lifetime = prefix->lifetime; + } + } + } +} + +static void ws_bootstrap_rpl_activate(protocol_interface_info_entry_t *cur) +{ + tr_debug("RPL Activate"); + bool downstream = true; + bool leaf = false; + + addr_add_router_groups(cur); + rpl_control_set_domain_on_interface(cur, protocol_6lowpan_rpl_domain, downstream); + rpl_control_set_callback(protocol_6lowpan_rpl_domain, ws_bootstrap_rpl_callback, ws_rpl_prefix_callback, cur); + // If i am router I Do this + rpl_control_force_leaf(protocol_6lowpan_rpl_domain, leaf); + + cur->ws_info->rpl_state = 0xff; // Set invalid state and learn from event +} + +static void ws_bootstrap_network_start(protocol_interface_info_entry_t *cur) +{ + //Set Network names, Pan information configure, hopping schedule & GTKHash + ws_llc_set_network_name(cur, (uint8_t *)cur->ws_info->network_name, strlen(cur->ws_info->network_name)); + ws_llc_set_pan_information_pointer(cur, &cur->ws_info->pan_information); +} + +static void ws_bootstrap_network_discovery_configure(protocol_interface_info_entry_t *cur) +{ + // Reset information to defaults + cur->ws_info->network_pan_id = 0xffff; + + ws_common_regulatory_domain_config(cur); + ws_fhss_discovery_configure(cur); + + //Set Network names, Pan information configure, hopping schedule & GTKHash + ws_llc_set_network_name(cur, (uint8_t *)cur->ws_info->network_name, strlen(cur->ws_info->network_name)); +} + + +static void ws_bootstrap_advertise_start(protocol_interface_info_entry_t *cur) +{ + cur->ws_info->trickle_pa_running = true; + trickle_start(&cur->ws_info->trickle_pan_advertisement, &cur->ws_info->trickle_params_pan_discovery); + trickle_inconsistent_heard(&cur->ws_info->trickle_pan_advertisement, &cur->ws_info->trickle_params_pan_discovery); + cur->ws_info->trickle_pc_running = true; + trickle_start(&cur->ws_info->trickle_pan_config, &cur->ws_info->trickle_params_pan_discovery); + trickle_inconsistent_heard(&cur->ws_info->trickle_pan_config, &cur->ws_info->trickle_params_pan_discovery); +} + +// Start network scan +static void ws_bootstrap_start_discovery(protocol_interface_info_entry_t *cur) +{ + tr_debug("router discovery start"); + ws_bootstrap_state_change(cur, ER_ACTIVE_SCAN); + cur->nwk_nd_re_scan_count = 0; + cur->ws_info->configuration_learned = false; + cur->ws_info->pan_version_timeout_timer = 0; + // Clear parent info + memset(cur->ws_info->parent_info.addr, 0, 8); + + // Clear learned neighbours + ws_bootstrap_neighbor_list_clean(cur); + + // Clear RPL information + rpl_control_remove_domain_from_interface(cur); + + // Clear ip stack from old information + ws_bootstrap_ip_stack_reset(cur); + // New network scan started old addresses not assumed valid anymore + ws_bootstrap_ip_stack_addr_clear(cur); + + // Reset advertisement solicit trickle to start discovering network + cur->ws_info->trickle_pas_running = true; + trickle_start(&cur->ws_info->trickle_pan_advertisement_solicit, &cur->ws_info->trickle_params_pan_discovery); + trickle_inconsistent_heard(&cur->ws_info->trickle_pan_advertisement_solicit, &cur->ws_info->trickle_params_pan_discovery); + + // Discovery statemachine is checkked after two trickle interval + cur->bootsrap_state_machine_cnt = 2 * cur->ws_info->trickle_params_pan_discovery.Imin + randLIB_get_8bit() % 50; +} + +// Start authentication +static void ws_bootstrap_start_authentication(protocol_interface_info_entry_t *cur) +{ + tr_debug("authentication start"); + ws_pae_controller_authenticate(cur); +} + + +static void ws_bootstrap_key_insert(protocol_interface_info_entry_t *cur, uint8_t gtk_index, uint8_t *gtk) +{ + // Convert GTK to Group AES Key (GAK) + + // Verify HASH etc. + + // Check index, for now only reacts to keys of index 0 + if (gtk_index == 0) { + mac_helper_security_key_clean(cur); + mac_helper_default_security_level_set(cur, AES_SECURITY_LEVEL_ENC_MIC64); + mac_helper_default_security_key_id_mode_set(cur, MAC_KEY_ID_MODE_IDX); + //Set Keys + mac_helper_security_default_key_set(cur, gtk, gtk_index + 1, MAC_KEY_ID_MODE_IDX); + } +} + +static void ws_bootstrap_authentication_completed(protocol_interface_info_entry_t *cur, bool success) +{ + if (success) { + tr_debug("authentication success"); + ws_bootstrap_event_configuration_start(cur); + } else { + tr_debug("authentication failed"); + // What else to do to start over again... + ws_bootstrap_event_discovery_start(cur); + } +} + +// Start configuration learning +static void ws_bootstrap_start_configuration_learn(protocol_interface_info_entry_t *cur) +{ + tr_debug("router configuration learn start"); + ws_bootstrap_state_change(cur, ER_SCAN); + + cur->ws_info->configuration_learned = false; + // Clear parent info + + memset(cur->ws_info->parent_info.addr, 0, 8); + + // Clear all temporary information + ws_bootstrap_ip_stack_reset(cur); + + cur->ws_info->pas_requests = 0; + // Reset advertisement solicit trickle to start discovering network + cur->ws_info->trickle_pcs_running = true; + trickle_start(&cur->ws_info->trickle_pan_config_solicit, &cur->ws_info->trickle_params_pan_discovery); + trickle_inconsistent_heard(&cur->ws_info->trickle_pan_config_solicit, &cur->ws_info->trickle_params_pan_discovery); +} +static void ws_bootstrap_rpl_scan_start(protocol_interface_info_entry_t *cur) +{ + tr_debug("Start RPL learn"); + // routers wait until RPL root is contacted + ws_bootstrap_state_change(cur, ER_RPL_SCAN); + // Set timeout for check to 30 -60 seconds + cur->bootsrap_state_machine_cnt = randLIB_get_random_in_range(WS_RPL_DIS_INITIAL_TIMEOUT / 2, WS_RPL_DIS_INITIAL_TIMEOUT); +} + +/* + * Event transitions + * + * */ +void ws_bootstrap_event_discovery_start(protocol_interface_info_entry_t *cur) +{ + ws_bootsrap_event_trig(WS_DISCOVERY_START, cur->bootStrapId, ARM_LIB_LOW_PRIORITY_EVENT, NULL); +} +void ws_bootstrap_event_configuration_start(protocol_interface_info_entry_t *cur) +{ + ws_bootsrap_event_trig(WS_CONFIGURATION_START, cur->bootStrapId, ARM_LIB_LOW_PRIORITY_EVENT, NULL); +} +void ws_bootstrap_event_authentication_start(protocol_interface_info_entry_t *cur) +{ + ws_bootsrap_event_trig(WS_AUTHENTICATION_START, cur->bootStrapId, ARM_LIB_LOW_PRIORITY_EVENT, NULL); +} +void ws_bootstrap_event_operation_start(protocol_interface_info_entry_t *cur) +{ + ws_bootsrap_event_trig(WS_OPERATION_START, cur->bootStrapId, ARM_LIB_LOW_PRIORITY_EVENT, NULL); +} +void ws_bootstrap_event_routing_ready(protocol_interface_info_entry_t *cur) +{ + ws_bootsrap_event_trig(WS_ROUTING_READY, cur->bootStrapId, ARM_LIB_LOW_PRIORITY_EVENT, NULL); +} +void ws_bootstrap_configuration_trickle_reset(protocol_interface_info_entry_t *cur) +{ + trickle_inconsistent_heard(&cur->ws_info->trickle_pan_config, &cur->ws_info->trickle_params_pan_discovery); +} + + +static void ws_bootstrap_pan_advert_solicit(protocol_interface_info_entry_t *cur) +{ + asynch_request_t async_req; + memset(&async_req, 0, sizeof(asynch_request_t)); + async_req.message_type = WS_FT_PAN_ADVERT_SOL; + //Request UTT Header and US and Net name from payload + async_req.wh_requested_ie_list.utt_ie = true; + async_req.wp_requested_nested_ie_list.us_ie = true; + async_req.wp_requested_nested_ie_list.net_name_ie = true; + + ws_generate_channel_list(async_req.channel_list.channel_mask, cur->ws_info->hopping_schdule.number_of_channels, cur->ws_info->hopping_schdule.regulatory_domain); + + async_req.channel_list.channel_page = CHANNEL_PAGE_10; + async_req.security.SecurityLevel = 0; + + ws_llc_asynch_request(cur, &async_req); +} + +static void ws_bootstrap_pan_config_solicit(protocol_interface_info_entry_t *cur) +{ + asynch_request_t async_req; + memset(&async_req, 0, sizeof(asynch_request_t)); + async_req.message_type = WS_FT_PAN_CONF_SOL; + //Request UTT Header and US and Net name from payload + async_req.wh_requested_ie_list.utt_ie = true; + async_req.wp_requested_nested_ie_list.us_ie = true; + async_req.wp_requested_nested_ie_list.net_name_ie = true; + + ws_generate_channel_list(async_req.channel_list.channel_mask, cur->ws_info->hopping_schdule.number_of_channels, cur->ws_info->hopping_schdule.regulatory_domain); + + async_req.channel_list.channel_page = CHANNEL_PAGE_10; + async_req.security.SecurityLevel = 0; + + ws_llc_asynch_request(cur, &async_req); +} + +static struct rpl_instance *ws_get_rpl_instance(protocol_interface_info_entry_t *cur) +{ + if (!cur || !cur->rpl_domain) { + return NULL; + } + struct rpl_instance *best_instance = NULL; + ns_list_foreach(struct rpl_instance, instance, &cur->rpl_domain->instances) { + best_instance = instance; + // Select best grounded and lowest rank? But there should be only one really + } + return best_instance; +} + +static uint16_t ws_bootstrap_routing_cost_calculate(protocol_interface_info_entry_t *cur) +{ + mac_neighbor_table_entry_t *mac_neighbor = mac_neighbor_entry_get_priority(mac_neighbor_info(cur)); + if (!mac_neighbor) { + return 0xffff; + } + ws_neighbor_class_entry_t *ws_neighbor = ws_neighbor_class_entry_get(&cur->ws_info->neighbor_storage, mac_neighbor->index); + if (!ws_neighbor) { + return 0xffff; + } + + uint16_t etx = etx_local_etx_read(cur->id, mac_neighbor->index); + if (etx == 0) { + etx = 0xffff; + } + if (etx > 0x800) { + // Wi-SUN section 6.2.3.1.6.1 says ETX can only be maximum of 1024 (8*128) in RPL units, ie 8.0. + etx = 0x800; + } + etx = etx >> 1; + + return ws_neighbor->routing_cost + etx; +} + +static uint16_t ws_bootstrap_rank_get(protocol_interface_info_entry_t *cur) +{ + struct rpl_instance *rpl_instance = ws_get_rpl_instance(cur); + if (!rpl_instance) { + return 0xffff; + } + return rpl_control_current_rank(rpl_instance); +} + + +static uint16_t ws_bootstrap_min_rank_inc_get(protocol_interface_info_entry_t *cur) +{ + struct rpl_instance *rpl_instance = ws_get_rpl_instance(cur); + if (!rpl_instance) { + return 0xffff; + } + struct rpl_dodag_info_t dodag_info; + if (!rpl_control_read_dodag_info(rpl_instance, &dodag_info)) { + return 0xffff; + } + return dodag_info.dag_min_hop_rank_inc; +} + +static void ws_bootstrap_pan_advert(protocol_interface_info_entry_t *cur) +{ + asynch_request_t async_req; + memset(&async_req, 0, sizeof(asynch_request_t)); + async_req.message_type = WS_FT_PAN_ADVERT; + //Request UTT Header, Pan information and US and Net name from payload + async_req.wh_requested_ie_list.utt_ie = true; + async_req.wp_requested_nested_ie_list.us_ie = true; + async_req.wp_requested_nested_ie_list.pan_ie = true; + async_req.wp_requested_nested_ie_list.net_name_ie = true; + + ws_generate_channel_list(async_req.channel_list.channel_mask, cur->ws_info->hopping_schdule.number_of_channels, cur->ws_info->hopping_schdule.regulatory_domain); + + async_req.channel_list.channel_page = CHANNEL_PAGE_10; + async_req.security.SecurityLevel = 0; + + if (cur->bootsrap_mode == ARM_NWK_BOOTSRAP_MODE_6LoWPAN_BORDER_ROUTER) { + // Border routers write the NW size + cur->ws_info->pan_information.pan_size = ws_bbr_pan_size(cur); + cur->ws_info->pan_information.routing_cost = 0; + } else { + // Nodes need to calculate routing cost + // PAN size is saved from latest PAN advertisement + cur->ws_info->pan_information.routing_cost = ws_bootstrap_routing_cost_calculate(cur); + } + + + ws_llc_asynch_request(cur, &async_req); +} + +static void ws_bootstrap_pan_config(protocol_interface_info_entry_t *cur) +{ + asynch_request_t async_req; + memset(&async_req, 0, sizeof(asynch_request_t)); + async_req.message_type = WS_FT_PAN_CONF; + //Request UTT Header, Pan information and US and Net name from payload + async_req.wh_requested_ie_list.utt_ie = true; + async_req.wh_requested_ie_list.bt_ie = true; + async_req.wp_requested_nested_ie_list.us_ie = true; + async_req.wp_requested_nested_ie_list.bs_ie = true; + async_req.wp_requested_nested_ie_list.pan_version_ie = true; + async_req.wp_requested_nested_ie_list.gtkhash_ie = true; + async_req.wp_requested_nested_ie_list.vp_ie = true; + + ws_generate_channel_list(async_req.channel_list.channel_mask, cur->ws_info->hopping_schdule.number_of_channels, cur->ws_info->hopping_schdule.regulatory_domain); + + async_req.channel_list.channel_page = CHANNEL_PAGE_10; + async_req.security.SecurityLevel = mac_helper_default_security_level_get(cur); + async_req.security.KeyIdMode = mac_helper_default_security_key_id_mode_get(cur); + async_req.security.KeyIndex = mac_helper_default_key_index_get(cur); + ws_llc_asynch_request(cur, &async_req); +} + +static bool ws_bootstrap_address_registration_ongoing(protocol_interface_info_entry_t *cur) +{ + ns_list_foreach(if_address_entry_t, addr, &cur->ip_addresses) { + if (addr->addr_reg_pend != 0) { + return true; + } + } + + return false; +} + +static void ws_bootstrap_event_handler(arm_event_s *event) +{ + ws_bootsrap_event_type_e event_type; + event_type = (ws_bootsrap_event_type_e)event->event_type; + protocol_interface_info_entry_t *cur; + cur = protocol_stack_interface_info_get_by_bootstrap_id(event->receiver); + if (!cur) { + return; + } + + switch (event_type) { + case WS_INIT_EVENT: + tr_debug("tasklet init"); + break; + case WS_DISCOVERY_START: + tr_info("Discovery start"); + // All trickle timers stopped to allow entry from any state + cur->ws_info->trickle_pa_running = false; + cur->ws_info->trickle_pc_running = false; + cur->ws_info->trickle_pas_running = false; + cur->ws_info->trickle_pcs_running = false; + + if (cur->bootsrap_mode == ARM_NWK_BOOTSRAP_MODE_6LoWPAN_BORDER_ROUTER) { + tr_debug("Border router start network"); + ws_pae_controller_auth_init(cur); + + // Randomize fixed channels. Only used if channel plan is fixed. + cur->ws_info->fhss_uc_fixed_channel = ws_randomize_fixed_channel(cur->ws_info->fhss_uc_fixed_channel, cur->ws_info->hopping_schdule.number_of_channels); + cur->ws_info->fhss_bc_fixed_channel = ws_randomize_fixed_channel(cur->ws_info->fhss_bc_fixed_channel, cur->ws_info->hopping_schdule.number_of_channels); + cur->ws_info->network_pan_id = randLIB_get_random_in_range(0, 0xfffd); + 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; + cur->ws_info->pan_information.version = WS_FAN_VERSION_1_0; + ws_llc_set_gtkhash(cur, cur->ws_info->gtkhash); + cur->ws_info->pan_version_timer = PAN_VERSION_LIFETIME; + + // Set default parameters for FHSS when starting a discovery + ws_fhss_border_router_configure(cur); + ws_bootstrap_fhss_activate(cur); + ws_bootstrap_event_operation_start(cur); + + uint8_t ll_addr[16]; + addr_interface_get_ll_address(cur, ll_addr, 1); + + //SET EAPOL authenticator EUI64 + ws_pae_controller_border_router_addr_write(cur, cur->mac); + + // Set EAPOL relay to port 10255 and authenticator relay to 10253 (and to own ll address) + ws_eapol_relay_start(cur, BR_EAPOL_RELAY_SOCKET_PORT, ll_addr, EAPOL_RELAY_SOCKET_PORT); + + // Set authenticator relay to port 10253 and PAE to 10254 (and to own ll address) + ws_eapol_auth_relay_start(cur, EAPOL_RELAY_SOCKET_PORT, ll_addr, PAE_AUTH_SOCKET_PORT); + + // Set 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); + break; + } + ws_pae_controller_supp_init(cur); + + // Configure LLC for network discovery + ws_bootstrap_network_discovery_configure(cur); + ws_bootstrap_fhss_activate(cur); + // Start network scan + ws_bootstrap_start_discovery(cur); + break; + case WS_AUTHENTICATION_START: + tr_info("authentication start"); + // only advert sol stopped as we might be doing re authentication + cur->ws_info->trickle_pas_running = false; + //Add Test ecurity key and security level's + + + // Advertisements stopped during the EAPOL + cur->ws_info->trickle_pa_running = false; + cur->ws_info->trickle_pc_running = false; + cur->ws_info->trickle_pas_running = false; + cur->ws_info->trickle_pcs_running = false; + + ws_bootstrap_start_authentication(cur); + break; + + case WS_CONFIGURATION_START: + tr_info("Configuration start"); + // Old configuration is considered invalid stopping all + cur->ws_info->trickle_pa_running = false; + cur->ws_info->trickle_pc_running = false; + cur->ws_info->trickle_pas_running = false; + cur->ws_info->trickle_pcs_running = false; + + // Build list of possible neighbours and learn first broadcast schedule + + ws_bootstrap_start_configuration_learn(cur); + break; + case WS_OPERATION_START: + tr_info("operation start"); + // Advertisements stopped during the RPL scan + cur->ws_info->trickle_pa_running = false; + cur->ws_info->trickle_pc_running = false; + cur->ws_info->trickle_pas_running = false; + cur->ws_info->trickle_pcs_running = false; + // Activate RPL + // Activate IPv6 stack + ws_bootstrap_ip_stack_activate(cur); + ws_bootstrap_rpl_activate(cur); + ws_bootstrap_network_start(cur); + // Wait for RPL start + if (cur->bootsrap_mode == ARM_NWK_BOOTSRAP_MODE_6LoWPAN_BORDER_ROUTER) { + ws_bootstrap_event_routing_ready(cur); + } else { + ws_bootstrap_rpl_scan_start(cur); + } + break; + case WS_ROUTING_READY: + tr_info("Routing ready"); + // stopped all to make sure we can enter here from any state + cur->ws_info->trickle_pa_running = false; + cur->ws_info->trickle_pc_running = false; + cur->ws_info->trickle_pas_running = false; + cur->ws_info->trickle_pcs_running = false; + + ws_bootstrap_advertise_start(cur); + ws_bootstrap_state_change(cur, ER_BOOTSRAP_DONE); + break; + case WS_ADDRESS_ADDED: + cur->ws_info->address_registration_event_active = false; + if (!ws_bootstrap_address_registration_ongoing(cur)) { + rpl_control_register_address(cur, (if_address_entry_t *) event->data_ptr); + } + break; + default: + tr_err("Invalid event received"); + break; + } +} + + +/* + * State machine + * + * */ +void ws_bootstrap_network_scan_process(protocol_interface_info_entry_t *cur) +{ + + if (!ws_bootstrap_network_found(cur)) { + // Next check will be after one trickle + cur->bootsrap_state_machine_cnt += cur->ws_info->trickle_params_pan_discovery.Imin + randLIB_get_8bit() % 50; + return; + } + tr_info("select network"); + + // Add EAPOL neighbour + llc_neighbour_req_t neighbor_info; + if (!ws_bootstrap_neighbor_info_request(cur, cur->ws_info->parent_info.addr, &neighbor_info, true)) { + return; + } + + ws_neighbor_class_neighbor_unicast_time_info_update(neighbor_info.ws_neighbor, &cur->ws_info->parent_info.ws_utt, cur->ws_info->parent_info.timestamp); + ws_neighbor_class_neighbor_unicast_schedule_set(neighbor_info.ws_neighbor, &cur->ws_info->parent_info.ws_us); + + + ws_bootstrap_network_information_learn(cur); + ws_bootstrap_fhss_activate(cur); + + ws_pae_controller_set_target(cur, cur->ws_info->parent_info.pan_id, cur->ws_info->parent_info.addr); // temporary!!! store since auth + ws_bootstrap_event_authentication_start(cur); + return; +} + +void ws_bootstrap_configure_process(protocol_interface_info_entry_t *cur) +{ + + if (cur->ws_info->configuration_learned) { + ws_bootstrap_network_configuration_learn(cur); + + + ws_bootstrap_event_operation_start(cur); + + + return; + } + return; +} +void ws_bootstrap_rpl_wait_process(protocol_interface_info_entry_t *cur) +{ + + if (cur->ws_info->rpl_state == RPL_EVENT_DAO_DONE) { + // RPL routing is ready + ws_bootstrap_event_routing_ready(cur); + } else if (!rpl_control_have_dodag(cur->rpl_domain)) { + // RPL not ready send DIS message if possible + if (cur->bootsrap_mode == ARM_NWK_BOOTSRAP_MODE_6LoWPAN_ROUTER) { + // TODO Multicast DIS should be sent only if no DIO heard for some time + rpl_control_transmit_dis(cur->rpl_domain, cur, 0, 0, NULL, 0, ADDR_LINK_LOCAL_ALL_RPL_NODES); + } + // set timer for next DIS + cur->bootsrap_state_machine_cnt = randLIB_get_random_in_range(WS_RPL_DIS_TIMEOUT / 2, WS_RPL_DIS_TIMEOUT); + } + return; +} + +/* + + static bool ws_bootstrap_state_active(struct protocol_interface_info_entry *cur) +{ + if(cur->nwk_bootstrap_state == ER_BOOTSRAP_DONE) { + return true; + } + return false; +} + +static bool ws_bootstrap_state_configure(struct protocol_interface_info_entry *cur) +{ + // Think about the state value + if(cur->nwk_bootstrap_state == ER_SCAN) { + return true; + } + return false; +} + +static bool ws_bootstrap_state_wait_rpl(struct protocol_interface_info_entry *cur) +{ + // Think about the state value + if(cur->nwk_bootstrap_state == ER_RPL_SCAN) { + return true; + } + return false; +} +*/ +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 void ws_bootstrap_state_change(protocol_interface_info_entry_t *cur, icmp_state_t nwk_bootstrap_state) +{ + cur->bootsrap_state_machine_cnt = 1; + cur->nwk_bootstrap_state = nwk_bootstrap_state; +} +void ws_bootstrap_state_machine(protocol_interface_info_entry_t *cur) +{ + + switch (cur->nwk_bootstrap_state) { + case ER_ACTIVE_SCAN: + tr_debug("WS SM:Active Scan"); + ws_bootstrap_network_scan_process(cur); + break; + case ER_SCAN: + tr_debug("WS SM:configuration Scan"); + ws_bootstrap_configure_process(cur); + break; + case ER_RPL_SCAN: + tr_debug("WS SM:Wait RPL to contact DODAG root"); + ws_bootstrap_rpl_wait_process(cur); + break; + case ER_BOOTSRAP_DONE: + tr_debug("WS SM:Bootstrap Done"); + // Bootstrap_done event to application + nwk_bootsrap_state_update(ARM_NWK_BOOTSTRAP_READY, cur); + break; + + default: + tr_warn("WS SM:Invalid state %d", cur->nwk_bootstrap_state); + + } +} + +void ws_bootstrap_trickle_timer(protocol_interface_info_entry_t *cur, uint16_t ticks) +{ + if (cur->ws_info->trickle_pas_running && + trickle_timer(&cur->ws_info->trickle_pan_advertisement_solicit, &cur->ws_info->trickle_params_pan_discovery, ticks)) { + // send PAN advertisement solicit + tr_info("Send PAN advertisement Solicit"); + ws_bootstrap_pan_advert_solicit(cur); + } + if (cur->ws_info->trickle_pcs_running && + trickle_timer(&cur->ws_info->trickle_pan_config_solicit, &cur->ws_info->trickle_params_pan_discovery, ticks)) { + // send PAN Configuration solicit + if (cur->ws_info->pas_requests > PCS_MAX) { + // if MAX PCS sent restart discovery + tr_debug("Restart???"); + ws_bootstrap_event_discovery_start(cur); + return; + } + tr_info("Send PAN configuration Solicit"); + cur->ws_info->pas_requests++; + ws_bootstrap_pan_config_solicit(cur); + } + if (cur->ws_info->trickle_pa_running && + trickle_timer(&cur->ws_info->trickle_pan_advertisement, &cur->ws_info->trickle_params_pan_discovery, ticks)) { + // send PAN advertisement + tr_info("Send PAN advertisement"); + ws_bootstrap_pan_advert(cur); + } + if (cur->ws_info->trickle_pc_running && + trickle_timer(&cur->ws_info->trickle_pan_config, &cur->ws_info->trickle_params_pan_discovery, ticks)) { + // send PAN Configuration + tr_info("Send PAN configuration"); + ws_bootstrap_pan_config(cur); + } +} + + +void ws_bootstrap_seconds_timer(protocol_interface_info_entry_t *cur, uint32_t seconds) +{ + if (cur->ws_info->pan_version_timeout_timer) { + // PAN version timer running + if (cur->ws_info->pan_version_timeout_timer > seconds) { + cur->ws_info->pan_version_timeout_timer -= seconds; + } else { + // Border router has timed out + tr_warn("Border router has timed out"); + ws_bootstrap_event_discovery_start(cur); + } + } +} + +void ws_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; + neighbor_info.neighbor = neighbor; + neighbor_info.ws_neighbor = ws_neighbor_class_entry_get(&interface->ws_info->neighbor_storage, neighbor->index); + ws_bootstrap_primary_parent_set(interface, &neighbor_info, true); + + ws_secondary_parent_update(interface); + } +} + +void ws_secondary_parent_update(protocol_interface_info_entry_t *interface) +{ + if (interface->ws_info) { + ns_list_foreach(if_address_entry_t, address, &interface->ip_addresses) { + if (!addr_is_ipv6_link_local(address->address)) { + address->addr_reg_done = 0; + ws_address_registration_update(interface); + } + } + } +} + +#endif //HAVE_WS diff --git a/source/6LoWPAN/ws/ws_bootstrap.h b/source/6LoWPAN/ws/ws_bootstrap.h index c967b1c86c..d678cd7e2c 100644 --- a/source/6LoWPAN/ws/ws_bootstrap.h +++ b/source/6LoWPAN/ws/ws_bootstrap.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2018, Arm Limited and affiliates. + * Copyright (c) 2018-2019, Arm Limited and affiliates. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -37,6 +37,10 @@ void ws_bootstrap_state_machine(protocol_interface_info_entry_t *cur); int ws_bootstrap_restart(int8_t interface_id); +int ws_bootstrap_set_rf_config(protocol_interface_info_entry_t *cur, phy_rf_channel_configuration_s rf_configs); + +int ws_bootstrap_neighbor_remove(protocol_interface_info_entry_t *cur, const uint8_t *ll_address); + /*State machine transactions*/ void ws_bootstrap_event_discovery_start(protocol_interface_info_entry_t *cur); @@ -66,11 +70,14 @@ void ws_dhcp_client_address_request(protocol_interface_info_entry_t *cur, uint8_ void ws_dhcp_client_address_delete(protocol_interface_info_entry_t *cur, uint8_t *prefix); +bool ws_eapol_relay_state_active(protocol_interface_info_entry_t *cur); + #else #define ws_bootstrap_init(interface_id, bootstrap_mode) (-1) #define ws_bootstrap_state_machine(cur) #define ws_bootstrap_restart(cur) +#define ws_bootstrap_neighbor_remove(cur, ll_address) #define ws_primary_parent_update(interface, neighbor) #define ws_secondary_parent_update(interface) diff --git a/source/6LoWPAN/ws/ws_common.c b/source/6LoWPAN/ws/ws_common.c new file mode 100644 index 0000000000..5d46b71172 --- /dev/null +++ b/source/6LoWPAN/ws/ws_common.c @@ -0,0 +1,381 @@ +/* + * Copyright (c) 2018-2019, 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 +#include "nsconfig.h" +#include "ns_types.h" +#include "ns_trace.h" +#include "randLIB.h" +#include +#include +#include "6LoWPAN/ws/ws_config.h" +#include "6LoWPAN/ws/ws_common_defines.h" +#include "6LoWPAN/ws/ws_common.h" +#include "6LoWPAN/ws/ws_bootstrap.h" +#include "6LoWPAN/ws/ws_bbr_api_internal.h" +#include "Service_Libs/mac_neighbor_table/mac_neighbor_table.h" +#include "Service_Libs/blacklist/blacklist.h" +#include "ws_management_api.h" +#include "mac_api.h" + +#ifdef HAVE_WS +#define TRACE_GROUP "wscm" + +int8_t DEVICE_MIN_SENS = -93; + +#define TRICKLE_IMIN_60_SECS (60 * 10) +#define TRICKLE_IMIN_30_SECS (30 * 10) +#define TRICKLE_IMIN_15_SECS (15 * 10) + +static const trickle_params_t trickle_params_pan_discovery_large = { + .Imin = TRICKLE_IMIN_60_SECS, /* 60 second; ticks are 1s */ + .Imax = TRICKLE_IMIN_60_SECS << 4, /* 960 seconds 16 min*/ + .k = 1, /* 1 */ + .TimerExpirations = TRICKLE_EXPIRATIONS_INFINITE +}; + +static const trickle_params_t trickle_params_pan_discovery_medium = { + .Imin = TRICKLE_IMIN_30_SECS, /* 30 second; ticks are 1s */ + .Imax = TRICKLE_IMIN_30_SECS << 3, /* 240 seconds 4 min*/ + .k = 1, /* 1 */ + .TimerExpirations = TRICKLE_EXPIRATIONS_INFINITE +}; + +static const trickle_params_t trickle_params_pan_discovery_small = { + .Imin = TRICKLE_IMIN_15_SECS, /* 15 second; ticks are 1s */ + .Imax = TRICKLE_IMIN_15_SECS << 2, /* 60 seconds 1 min*/ + .k = 1, /* 1 */ + .TimerExpirations = TRICKLE_EXPIRATIONS_INFINITE +}; + +uint16_t test_max_child_count_override = 0xffff; + + +int8_t ws_generate_channel_list(uint32_t *channel_mask, uint16_t number_of_channels, uint8_t regulatory_domain) +{ + (void)regulatory_domain; + for (uint8_t i = 0; i < number_of_channels; i++) { + channel_mask[0 + (i / 32)] |= (1 << (i % 32)); + } + return 0; +} + +static uint32_t ws_decode_channel_spacing(uint8_t channel_spacing) +{ + if (CHANNEL_SPACING_100 == channel_spacing) { + return 100000; + } else if (CHANNEL_SPACING_200 == channel_spacing) { + return 200000; + } else if (CHANNEL_SPACING_250 == channel_spacing) { + return 250000; + } else if (CHANNEL_SPACING_400 == channel_spacing) { + return 400000; + } else if (CHANNEL_SPACING_600 == channel_spacing) { + return 600000; + } + return 0; +} + +static uint32_t ws_get_datarate_using_operating_mode(uint8_t operating_mode) +{ + if ((OPERATING_MODE_1a == operating_mode) || (OPERATING_MODE_1b == operating_mode)) { + return 50000; + } else if ((OPERATING_MODE_2a == operating_mode) || (OPERATING_MODE_2b == operating_mode)) { + return 100000; + } else if (OPERATING_MODE_3 == operating_mode) { + return 150000; + } else if ((OPERATING_MODE_4a == operating_mode) || (OPERATING_MODE_4b == operating_mode)) { + return 200000; + } else if (OPERATING_MODE_5 == operating_mode) { + return 300000; + } + return 0; +} + +static phy_modulation_index_e ws_get_modulation_index_using_operating_mode(uint8_t operating_mode) +{ + if ((OPERATING_MODE_1b == operating_mode) || (OPERATING_MODE_2b == operating_mode) || (OPERATING_MODE_4b == operating_mode)) { + return MODULATION_INDEX_1_0; + } else { + return MODULATION_INDEX_0_5; + } +} + +static int ws_set_domain_rf_config(protocol_interface_info_entry_t *cur) +{ + phy_rf_channel_configuration_s rf_configs; + rf_configs.channel_0_center_frequency = (uint32_t)cur->ws_info->hopping_schdule.ch0_freq * 100000; + rf_configs.channel_spacing = ws_decode_channel_spacing(cur->ws_info->hopping_schdule.channel_spacing); + rf_configs.datarate = ws_get_datarate_using_operating_mode(cur->ws_info->hopping_schdule.operating_mode); + rf_configs.modulation_index = ws_get_modulation_index_using_operating_mode(cur->ws_info->hopping_schdule.operating_mode); + rf_configs.modulation = M_2FSK; + rf_configs.number_of_channels = cur->ws_info->hopping_schdule.number_of_channels; + ws_bootstrap_set_rf_config(cur, rf_configs); + return 0; +} + +int8_t ws_common_regulatory_domain_config(protocol_interface_info_entry_t *cur) +{ + cur->ws_info->hopping_schdule.channel_plan = 0; + + if (cur->ws_info->hopping_schdule.regulatory_domain == REG_DOMAIN_KR) { + if (cur->ws_info->hopping_schdule.operating_class == 1) { + cur->ws_info->hopping_schdule.ch0_freq = 9171; + cur->ws_info->hopping_schdule.channel_spacing = CHANNEL_SPACING_200; + } else if (cur->ws_info->hopping_schdule.operating_class == 2) { + cur->ws_info->hopping_schdule.ch0_freq = 9173; + cur->ws_info->hopping_schdule.channel_spacing = CHANNEL_SPACING_400; + } else { + return -1; + } + } else if (cur->ws_info->hopping_schdule.regulatory_domain == REG_DOMAIN_EU) { + if (cur->ws_info->hopping_schdule.operating_class == 1) { + cur->ws_info->hopping_schdule.ch0_freq = 8631; + cur->ws_info->hopping_schdule.channel_spacing = CHANNEL_SPACING_100; + } else if (cur->ws_info->hopping_schdule.operating_class == 2) { + cur->ws_info->hopping_schdule.ch0_freq = 8631; + cur->ws_info->hopping_schdule.channel_spacing = CHANNEL_SPACING_200; + } else if (cur->ws_info->hopping_schdule.operating_class == 3) { + cur->ws_info->hopping_schdule.ch0_freq = 8701; + cur->ws_info->hopping_schdule.channel_spacing = CHANNEL_SPACING_100; + } else if (cur->ws_info->hopping_schdule.operating_class == 4) { + cur->ws_info->hopping_schdule.ch0_freq = 8702; + cur->ws_info->hopping_schdule.channel_spacing = CHANNEL_SPACING_200; + } else { + return -1; + } + } else if (cur->ws_info->hopping_schdule.regulatory_domain == REG_DOMAIN_NA) { + if (cur->ws_info->hopping_schdule.operating_class == 1) { + cur->ws_info->hopping_schdule.ch0_freq = 9022; + cur->ws_info->hopping_schdule.channel_spacing = CHANNEL_SPACING_200; + } else if (cur->ws_info->hopping_schdule.operating_class == 2) { + cur->ws_info->hopping_schdule.ch0_freq = 9024; + cur->ws_info->hopping_schdule.channel_spacing = CHANNEL_SPACING_400; + } else if (cur->ws_info->hopping_schdule.operating_class == 3) { + cur->ws_info->hopping_schdule.ch0_freq = 9026; + cur->ws_info->hopping_schdule.channel_spacing = CHANNEL_SPACING_600; + } else { + return -1; + } + } else if (cur->ws_info->hopping_schdule.regulatory_domain == REG_DOMAIN_JP) { + if (cur->ws_info->hopping_schdule.operating_class == 1) { + cur->ws_info->hopping_schdule.ch0_freq = 9206; + cur->ws_info->hopping_schdule.channel_spacing = CHANNEL_SPACING_200; + } else if (cur->ws_info->hopping_schdule.operating_class == 2) { + cur->ws_info->hopping_schdule.ch0_freq = 9209; + cur->ws_info->hopping_schdule.channel_spacing = CHANNEL_SPACING_400; + } else if (cur->ws_info->hopping_schdule.operating_class == 3) { + cur->ws_info->hopping_schdule.ch0_freq = 9208; + cur->ws_info->hopping_schdule.channel_spacing = CHANNEL_SPACING_600; + } else { + return -1; + } + } else if (cur->ws_info->hopping_schdule.regulatory_domain == REG_DOMAIN_WW) { + if (cur->ws_info->hopping_schdule.operating_class == 1) { + cur->ws_info->hopping_schdule.ch0_freq = 24002; + cur->ws_info->hopping_schdule.channel_spacing = CHANNEL_SPACING_200; + } else if (cur->ws_info->hopping_schdule.operating_class == 2) { + cur->ws_info->hopping_schdule.ch0_freq = 24004; + cur->ws_info->hopping_schdule.channel_spacing = CHANNEL_SPACING_400; + } else { + return -1; + } + } else { + return -1; + } + cur->ws_info->hopping_schdule.number_of_channels = (uint8_t)ws_common_channel_number_calc(cur->ws_info->hopping_schdule.regulatory_domain, cur->ws_info->hopping_schdule.operating_class); + if (!cur->ws_info->hopping_schdule.number_of_channels) { + return -1; + } + // Note: doesn't work for Brazil region + ws_generate_channel_list(cur->ws_info->hopping_schdule.channel_mask, cur->ws_info->hopping_schdule.number_of_channels, cur->ws_info->hopping_schdule.regulatory_domain); + ws_set_domain_rf_config(cur); + return 0; +} + +uint16_t ws_common_channel_number_calc(uint8_t regulatory_domain, uint8_t operating_class) +{ + if (regulatory_domain == REG_DOMAIN_KR) { + if (operating_class == 1) { + return 32; + } else if (operating_class == 2) { + return 16; + } + } else if (regulatory_domain == REG_DOMAIN_EU) { + if (operating_class == 1) { + return 69; + } else if (operating_class == 2) { + return 35; + } else if (operating_class == 3) { + return 55; + } else if (operating_class == 4) { + return 27; + } + } else if (regulatory_domain == REG_DOMAIN_NA) { + if (operating_class == 1) { + return 129; + } else if (operating_class == 2) { + return 64; + } else if (operating_class == 3) { + return 42; + } + } else if (regulatory_domain == REG_DOMAIN_JP) { + if (operating_class == 1) { + return 38; + } else if (operating_class == 2) { + return 18; + } else if (operating_class == 3) { + return 12; + } + } else if (regulatory_domain == REG_DOMAIN_WW) { + if (operating_class == 1) { + // TODO we dont support this yet, but it is used as test value + return 416; + } else if (operating_class == 2) { + return 207; + } + } + return 0; +} + +int8_t ws_common_allocate_and_init(protocol_interface_info_entry_t *cur) +{ + + if (!cur->ws_info) { + cur->ws_info = ns_dyn_mem_alloc(sizeof(ws_info_t)); + } + if (!cur->ws_info) { + return -1; + } + + memset(cur->ws_info, 0, sizeof(ws_info_t)); + ns_list_init(&cur->ws_info->active_nud_process); + ns_list_init(&cur->ws_info->free_nud_entries); + + cur->ws_info->pan_information.use_parent_bs = true; + cur->ws_info->pan_information.rpl_routing_method = true; + cur->ws_info->pan_information.version = WS_FAN_VERSION_1_0; + + cur->ws_info->hopping_schdule.regulatory_domain = REG_DOMAIN_EU; + cur->ws_info->hopping_schdule.operating_mode = OPERATING_MODE_3; + cur->ws_info->hopping_schdule.operating_class = 2; + ws_common_regulatory_domain_config(cur); + ws_common_network_size_configure(cur, 10); // defaults to small network size + + // Set defaults for the device. user can modify these. + cur->ws_info->fhss_uc_fixed_channel = 0xffff; + cur->ws_info->fhss_bc_fixed_channel = 0xffff; + cur->ws_info->fhss_uc_dwell_interval = WS_FHSS_UC_DWELL_INTERVAL; + cur->ws_info->fhss_bc_interval = WS_FHSS_BC_INTERVAL; + cur->ws_info->fhss_bc_dwell_interval = WS_FHSS_BC_DWELL_INTERVAL; + cur->ws_info->fhss_uc_channel_function = WS_DH1CF; + cur->ws_info->fhss_bc_channel_function = WS_DH1CF; + for (uint8_t n = 0; n < 8; n++) { + cur->ws_info->fhss_channel_mask[n] = 0xffffffff; + } + + return 0; +} +void ws_common_network_size_configure(protocol_interface_info_entry_t *cur, uint16_t network_size) +{ + // TODO Modify NUD timings based on network size + // TODO Modify EAPOLL timings + + if (network_size < 100) { + // Configure the Wi-SUN discovery trickle parameters + cur->ws_info->trickle_params_pan_discovery = trickle_params_pan_discovery_small; + // default values are for Wi-SUN small network parameters + // imin: 14 (16s) + // doublings:3 (128s) + // redundancy; 0 Disabled + ws_bbr_rpl_config(0, 0, 0);// set the default values + } else if (network_size < 300) { + // Configure the Wi-SUN discovery trickle parameters + cur->ws_info->trickle_params_pan_discovery = trickle_params_pan_discovery_medium; + // Something in between + // imin: 15 (32s) + // doublings:3 (262s) + // redundancy; 7 + ws_bbr_rpl_config(15, 3, 7); + } else { + // Configure the Wi-SUN discovery trickle parameters + cur->ws_info->trickle_params_pan_discovery = trickle_params_pan_discovery_large; + // Wi-SUN Large network parameters + // imin: 19 (524s, 9 min) + // doublings:1 (1048s, 17 min) + // redundancy; 1 Really heavy redundancy + ws_bbr_rpl_config(19, 1, 1); + } + return; +} + +void ws_common_seconds_timer(protocol_interface_info_entry_t *cur, uint32_t seconds) +{ + ws_bbr_seconds_timer(cur, seconds); + ws_bootstrap_seconds_timer(cur, seconds); + blacklist_ttl_update(seconds); +} + +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); +} + + +void ws_common_neighbor_update(protocol_interface_info_entry_t *cur, const uint8_t *ll_address) +{ + //Neighbor connectected update + mac_neighbor_table_entry_t *mac_neighbor = mac_neighbor_entry_get_by_ll64(mac_neighbor_info(cur), ll_address, false, NULL); + if (mac_neighbor) { + ws_nud_entry_remove_active(cur, mac_neighbor); + } +} + +void ws_common_aro_failure(protocol_interface_info_entry_t *cur, const uint8_t *ll_address) +{ + //Neighbor connectected update + ws_bootstrap_neighbor_remove(cur, ll_address); +} + +bool ws_common_allow_child_registration(protocol_interface_info_entry_t *interface) +{ + uint8_t child_count = 0; + uint8_t max_child_count = mac_neighbor_info(interface)->list_total_size - WS_NON_CHILD_NEIGHBOUR_COUNT; + + // Test API to limit child count + if (test_max_child_count_override != 0xffff) { + max_child_count = test_max_child_count_override; + } + + ns_list_foreach_safe(mac_neighbor_table_entry_t, cur, &mac_neighbor_info(interface)->neighbour_list) { + + if (ipv6_neighbour_has_registered_by_eui64(&interface->ipv6_neighbour_cache, cur->mac64)) { + child_count++; + } + } + if (child_count >= max_child_count) { + tr_warn("Child registration not allowed %d/%d, max:%d", child_count, max_child_count, mac_neighbor_info(interface)->list_total_size); + return false; + } + tr_info("Child registration allowed %d/%d, max:%d", child_count, max_child_count, mac_neighbor_info(interface)->list_total_size); + return true; +} + + +#endif // HAVE_WS + diff --git a/source/6LoWPAN/ws/ws_common.h b/source/6LoWPAN/ws/ws_common.h index f2625f22ab..08cb4a5cc4 100644 --- a/source/6LoWPAN/ws/ws_common.h +++ b/source/6LoWPAN/ws/ws_common.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2018, Arm Limited and affiliates. + * Copyright (c) 2018-2019, Arm Limited and affiliates. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -24,10 +24,14 @@ #include "fhss_api.h" #include "fhss_config.h" #include "net_fhss.h" +#include "NWK_INTERFACE/Include/protocol.h" #include "6LoWPAN/ws/ws_common_defines.h" #include "6LoWPAN/ws/ws_neighbor_class.h" #include "Service_Libs/mac_neighbor_table/mac_neighbor_table.h" + +extern uint16_t test_max_child_count_override; + struct ws_pan_information_s; struct ws_neighbor_class_s; @@ -61,6 +65,8 @@ typedef struct ws_info_s { trickle_t trickle_pan_config; trickle_t trickle_pan_advertisement_solicit; trickle_t trickle_pan_advertisement; + trickle_params_t trickle_params_pan_discovery; + uint8_t network_size_config; // configuration for network size selection of application. uint8_t rpl_state; // state from rpl_event_t uint8_t pas_requests; // Amount of PAN solicits sent parent_info_t parent_info; @@ -98,20 +104,30 @@ int8_t ws_generate_channel_list(uint32_t *channel_mask, uint16_t number_of_chann int8_t ws_common_regulatory_domain_config(protocol_interface_info_entry_t *cur); +uint16_t ws_common_channel_number_calc(uint8_t regulatory_domain, uint8_t operating_class); + int8_t ws_common_allocate_and_init(protocol_interface_info_entry_t *cur); +void ws_common_network_size_configure(protocol_interface_info_entry_t *cur, uint16_t network_size); + void ws_common_seconds_timer(protocol_interface_info_entry_t *cur, uint32_t seconds); void ws_common_fast_timer(protocol_interface_info_entry_t *cur, uint16_t ticks); void ws_common_neighbor_update(protocol_interface_info_entry_t *cur, const uint8_t *ll_address); +void ws_common_aro_failure(protocol_interface_info_entry_t *cur, const uint8_t *ll_address); + +bool ws_common_allow_child_registration(protocol_interface_info_entry_t *cur); + #define ws_info(cur) ((cur)->ws_info) #else #define ws_info(cur) ((ws_info_t *) NULL) #define ws_common_seconds_timer(cur, seconds) #define ws_common_neighbor_update(cur, ll_address) ((void) 0) +#define ws_common_aro_failure(cur, ll_address) #define ws_common_fast_timer(cur, ticks) ((void) 0) +#define ws_common_allow_child_registration(cur) (false) #endif //HAVE_WS diff --git a/source/6LoWPAN/ws/ws_common_defines.h b/source/6LoWPAN/ws/ws_common_defines.h index 5a4ceba72e..bf799edfe8 100644 --- a/source/6LoWPAN/ws/ws_common_defines.h +++ b/source/6LoWPAN/ws/ws_common_defines.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2018, Arm Limited and affiliates. + * Copyright (c) 2018-2019, Arm Limited and affiliates. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -27,6 +27,7 @@ #define WH_IE_RSL_TYPE 4 /**< Received Signal Level information */ #define WH_IE_MHDS_TYPE 5 /**< MHDS information for mesh routing */ #define WH_IE_VH_TYPE 6 /**< Vendor header information */ +#define WH_IE_EA_TYPE 9 /**< Eapol Auhtenticator EUI-64 header information */ #define WS_WP_NESTED_IE 4 /**< WS nested Payload IE element'selement could include mltiple sub payload IE */ @@ -215,12 +216,28 @@ typedef struct ws_bs_ie { */ #define WS_RPL_DIS_TIMEOUT 1800 +/* + * MAC Ack wait duration in symbols. 2-FSK modulation used -> 1 bit per symbol. + */ +#define WS_ACK_WAIT_SYMBOLS 800 + +/* + * Tack max time in milliseconds. + */ +#define WS_TACK_MAX_MS 5 + /* Default FHSS timing information * */ -#define WS_FHSS_UC_DWELL_INTERVAL 250; -#define WS_FHSS_BC_INTERVAL 800; -#define WS_FHSS_BC_DWELL_INTERVAL 200; +#define WS_FHSS_UC_DWELL_INTERVAL 255; +#define WS_FHSS_BC_INTERVAL 1020; +#define WS_FHSS_BC_DWELL_INTERVAL 255; +/* + * EAPOL relay and PAE authenticator socket settings + */ +#define EAPOL_RELAY_SOCKET_PORT 10253 +#define BR_EAPOL_RELAY_SOCKET_PORT 10255 +#define PAE_AUTH_SOCKET_PORT 10254 #endif /* WS_COMMON_DEFINES_H_ */ diff --git a/source/6LoWPAN/ws/ws_config.h b/source/6LoWPAN/ws/ws_config.h new file mode 100644 index 0000000000..7720af7872 --- /dev/null +++ b/source/6LoWPAN/ws/ws_config.h @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2018-2019, Arm Limited and affiliates. + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef WS_CONFIG_H_ +#define WS_CONFIG_H_ + + +/*RPL parameters for DIO messages + * + * Small scale spec recomendation imin 15, doubling 2, redudancy 0 + * Small scale values imin 14, doubling 3, redudancy 0 + * Large scale network imin 19, doubling 1, redudancy 1 + * + */ + +#define WS_RPL_DIO_IMIN 14 +#define WS_RPL_DIO_DOUBLING 3 +#define WS_RPL_DIO_REDUNDANCY 0 + + +/* Border router version change interval + * + * Minimum interval at which a Border Router shall increment its PAN Version value. + */ + +#define PAN_VERSION_LIFETIME 240 + +#define RPL_VERSION_LIFETIME 5*3600 + +/* Border router connection lost timeout + * + * Interval within which a node expects to detect a change in PAN Version + * (delivered via a PAN Configuration frame / PAN-IE). + * + * the maximum Trickle interval specified for DISC_IMAX (32 minutes). + * + */ + +#define PAN_VERSION_TIMEOUT 1920 + +/* Routing Cost Weighting factor + */ +#define PRC_WEIGHT_FACTOR 256 + +/* Routing Cost Weighting factor + */ +#define PS_WEIGHT_FACTOR 64 + +/* Smoothing factor for RSL calculation 1/8 + */ +#define WS_RSL_SCALING 3 + +/* Device min sensitivity. This value is dynamically configured and depends on radio + * + * Default value for us is -93 + */ +extern int8_t DEVICE_MIN_SENS; + +/* Candidate parent Threshold + */ +#define CAND_PARENT_THRESHOLD 10 + +/* Candidate parent Threshold hysteresis + */ +#define CAND_PARENT_HYSTERISIS 3 + +/* Maximum amount of Pan Configuration Solicits before restarting Discovery. + */ +#define PCS_MAX 5 + + +/* Multicast MPL data message parameters + * IMIN = 10 seconds, IMAX = 3 doublings + */ + +#define DATA_MESSAGE_IMIN (10 * 1000) +#define DATA_MESSAGE_TIMER_EXPIRATIONS 3 +#define DATA_MESSAGE_IMAX (DATA_MESSAGE_IMIN) +#define MPL_SEED_SET_ENTRY_TIMEOUT (DATA_MESSAGE_IMAX * 24 * 4 / 1000) // 10 seconds per hop making this 240 seconds + +/* DHCP client timeout configuration values + * + */ +#define WS_DHCP_SOLICIT_TIMEOUT 60 +#define WS_DHCP_SOLICIT_MAX_RT 3600 +#define WS_DHCP_SOLICIT_MAX_RC 0 + + +/* Neighbour table configuration + * + * Amount of RPL candidate parents + * Amount of ND reply entries left + * rest are used as child count, but is related to neighbour table size + */ +#define WS_RPL_CANDIDATE_PARENT_COUNT 3 // Largest possible value +#define WS_TEMPORARY_NEIGHBOUR_ENTRIES 7 +#define WS_NON_CHILD_NEIGHBOUR_COUNT (WS_RPL_CANDIDATE_PARENT_COUNT + WS_TEMPORARY_NEIGHBOUR_ENTRIES) + +/* + * Neighbour blacklist timers + */ +#define WS_BLACKLIST_ENTRY_LIFETIME 60*30 // initial value for reject +#define WS_BLACKLIST_TIMER_MAX_TIMEOUT 60*60 // Can increase to this +#define WS_BLACKLIST_TIMER_TIMEOUT 60*30 // Blacklist is valid this time after first accept +#define WS_BLACKLIST_ENTRY_MAX_NBR 10 +#define WS_BLACKLIST_PURGE_NBR 3 +#define WS_BLACKLIST_PURGE_TIMER_TIMEOUT 60 + + +#endif /* WS_CONFIG_H_ */ diff --git a/source/6LoWPAN/ws/ws_eapol_auth_relay.c b/source/6LoWPAN/ws/ws_eapol_auth_relay.c new file mode 100644 index 0000000000..cad3a52128 --- /dev/null +++ b/source/6LoWPAN/ws/ws_eapol_auth_relay.c @@ -0,0 +1,205 @@ +/* + * Copyright (c) 2018-2019, Arm Limited and affiliates. + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "nsconfig.h" +#include +#include "ns_types.h" +#include "ns_list.h" +#include "ns_trace.h" +#include "nsdynmemLIB.h" +#include "fhss_config.h" +#include "NWK_INTERFACE/Include/protocol.h" +#include "mac_api.h" +#include "mac_mcps.h" +#include "Common_Protocols/ipv6_constants.h" +#include "socket_api.h" +#include "6LoWPAN/MAC/mac_helper.h" +#include "6LoWPAN/MAC/mpx_api.h" +#include "6LoWPAN/ws/ws_config.h" +#include "6LoWPAN/ws/ws_eapol_pdu.h" +#include "6LoWPAN/ws/ws_eapol_relay_lib.h" +#include "6LoWPAN/ws/ws_eapol_auth_relay.h" +#include "common_functions.h" + +#ifdef HAVE_WS +#ifdef HAVE_PAE_AUTH + +#define TRACE_GROUP "wsar" + +typedef struct { + protocol_interface_info_entry_t *interface_ptr; /**< Interface pointer */ + ns_address_t remote_addr; /**< Remote address and port */ + ns_address_t relay_addr; /**< Relay address */ + int8_t socket_id; /**< Socket ID for relay */ + ns_list_link_t link; /**< Link */ +} eapol_auth_relay_t; + +static eapol_auth_relay_t *ws_eapol_auth_relay_get(protocol_interface_info_entry_t *interface_ptr); +static void ws_eapol_auth_relay_socket_cb(void *cb); +static int8_t ws_eapol_auth_relay_send_to_kmp(eapol_auth_relay_t *eapol_auth_relay, const uint8_t *eui_64, const uint8_t *ip_addr, uint16_t port, const void *data, uint16_t data_len); + +static NS_LIST_DEFINE(eapol_auth_relay_list, eapol_auth_relay_t, link); + +int8_t ws_eapol_auth_relay_start(protocol_interface_info_entry_t *interface_ptr, uint16_t local_port, const uint8_t *remote_addr, uint16_t remote_port) +{ + if (!interface_ptr || !remote_addr) { + return -1; + } + + if (ws_eapol_auth_relay_get(interface_ptr)) { + return 0; + } + + eapol_auth_relay_t *eapol_auth_relay = ns_dyn_mem_alloc(sizeof(eapol_auth_relay_t)); + if (!eapol_auth_relay) { + return -1; + } + + eapol_auth_relay->interface_ptr = interface_ptr; + + eapol_auth_relay->remote_addr.type = ADDRESS_IPV6; + memcpy(&eapol_auth_relay->relay_addr.address, remote_addr, 16); + eapol_auth_relay->relay_addr.identifier = remote_port; + + eapol_auth_relay->socket_id = socket_open(IPV6_NH_UDP, local_port, &ws_eapol_auth_relay_socket_cb); + if (eapol_auth_relay->socket_id < 0) { + ns_dyn_mem_free(eapol_auth_relay); + return -1; + } + + ns_list_add_to_end(&eapol_auth_relay_list, eapol_auth_relay); + + return 0; +} + +int8_t ws_eapol_auth_relay_delete(protocol_interface_info_entry_t *interface_ptr) +{ + if (!interface_ptr) { + return -1; + } + + eapol_auth_relay_t *eapol_auth_relay = ws_eapol_auth_relay_get(interface_ptr); + if (!eapol_auth_relay) { + return -1; + } + + socket_close(eapol_auth_relay->socket_id); + + ns_list_remove(&eapol_auth_relay_list, eapol_auth_relay); + ns_dyn_mem_free(eapol_auth_relay); + + return 0; +} + +static eapol_auth_relay_t *ws_eapol_auth_relay_get(protocol_interface_info_entry_t *interface_ptr) +{ + ns_list_foreach(eapol_auth_relay_t, entry, &eapol_auth_relay_list) { + if (entry->interface_ptr == interface_ptr) { + return entry; + } + } + + return NULL; +} + +static void ws_eapol_auth_relay_socket_cb(void *cb) +{ + socket_callback_t *cb_data = cb; + + if (cb_data->event_type != SOCKET_DATA) { + return; + } + + eapol_auth_relay_t *eapol_auth_relay = NULL; + + ns_list_foreach(eapol_auth_relay_t, entry, &eapol_auth_relay_list) { + if (entry->socket_id == cb_data->socket_id) { + eapol_auth_relay = entry; + break; + } + } + + if (!eapol_auth_relay) { + return; + } + + uint8_t *socket_pdu = ns_dyn_mem_temporary_alloc(cb_data->d_len); + if (!socket_pdu) { + return; + } + + ns_address_t src_addr; + + if (socket_recvfrom(cb_data->socket_id, socket_pdu, cb_data->d_len, 0, &src_addr) != cb_data->d_len) { + ns_dyn_mem_free(socket_pdu); + return; + } + + // Message from source port 10254 (KMP service) -> to IP relay on node or on authenticator + if (src_addr.identifier == eapol_auth_relay->relay_addr.identifier) { + uint8_t *ptr = socket_pdu; + uint8_t *eui_64; + ns_address_t relay_ip_addr; + relay_ip_addr.type = ADDRESS_IPV6; + memcpy(relay_ip_addr.address, ptr, 16); + ptr += 16; + relay_ip_addr.identifier = common_read_16_bit(ptr); + ptr += 2; + eui_64 = ptr; + ptr += 8; + uint16_t data_len = cb_data->d_len - 26; + ws_eapol_relay_lib_send_to_relay(eapol_auth_relay->socket_id, eui_64, &relay_ip_addr, + ptr, data_len); + ns_dyn_mem_free(socket_pdu); + // Other source port (either 10253 or node relay source port) -> to KMP service + } else { + uint8_t *ptr = socket_pdu; + ws_eapol_auth_relay_send_to_kmp(eapol_auth_relay, ptr, src_addr.address, src_addr.identifier, + ptr + 8, cb_data->d_len - 8); + ns_dyn_mem_free(socket_pdu); + } +} + +static int8_t ws_eapol_auth_relay_send_to_kmp(eapol_auth_relay_t *eapol_auth_relay, const uint8_t *eui_64, const uint8_t *ip_addr, uint16_t port, const void *data, uint16_t data_len) +{ + ns_address_t dest_addr = eapol_auth_relay->relay_addr; + + uint8_t temp_array[26]; + ns_iovec_t msg_iov[2]; + ns_msghdr_t msghdr; + //Set messages name buffer + msghdr.msg_name = &dest_addr; + msghdr.msg_namelen = sizeof(dest_addr); + msghdr.msg_iov = &msg_iov[0]; + msghdr.msg_iovlen = 2; + msghdr.msg_control = NULL; + msghdr.msg_controllen = 0; + uint8_t *ptr = temp_array; + memcpy(ptr, ip_addr, 16); + ptr += 16; + ptr = common_write_16_bit(port, ptr); + memcpy(ptr, eui_64, 8); + msg_iov[0].iov_base = temp_array; + msg_iov[0].iov_len = 26; + msg_iov[1].iov_base = (void *)data; + msg_iov[1].iov_len = data_len; + socket_sendmsg(eapol_auth_relay->socket_id, &msghdr, NS_MSG_LEGACY0); + return 0; +} + +#endif /* HAVE_PAE_AUTH */ +#endif /* HAVE_WS */ diff --git a/source/6LoWPAN/ws/ws_eapol_auth_relay.h b/source/6LoWPAN/ws/ws_eapol_auth_relay.h new file mode 100644 index 0000000000..d0a7aa6c09 --- /dev/null +++ b/source/6LoWPAN/ws/ws_eapol_auth_relay.h @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2018-2019, Arm Limited and affiliates. + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef WS_EAPOL_AUTH_RELAY_H_ +#define WS_EAPOL_AUTH_RELAY_H_ + +#ifdef HAVE_PAE_AUTH + +/* + * EAPOL authenticator relay acts as a proxy between EAPOL UDP relay and + * authenticator PAE (KMP service). Relay is bound by default to EAPOL UDP + * relay port 10253 (set by local port parameter) and transfers messages + * to/from authenticator PAE. As default PAE is bound to UDP port 10254 + * (set by remote address and port parameters). + * + */ + +/** + * ws_eapol_auth_relay_start start authenticator relay + * + * \param interface_ptr interface + * \param local_port local port + * \param remote_addr remote address + * \param remote_port remote port + * + * \return < 0 failure + * \return >= 0 success + * + */ +int8_t ws_eapol_auth_relay_start(protocol_interface_info_entry_t *interface_ptr, uint16_t local_port, const uint8_t *remote_addr, uint16_t remote_port); + +/** + * ws_eapol_auth_relay_delete delete authenticator relay + * + * \param interface_ptr interface + * + * \return < 0 failure + * \return >= 0 success + * + */ +int8_t ws_eapol_auth_relay_delete(protocol_interface_info_entry_t *interface_ptr); + +#else + +#define ws_eapol_auth_relay_start(interface_ptr, local_port, remote_addr, remote_port) +#define ws_eapol_auth_relay_delete(interface_ptr) + +#endif + +#endif /* WS_EAPOL_AUTH_RELAY_H_ */ diff --git a/source/6LoWPAN/ws/ws_eapol_pdu.c b/source/6LoWPAN/ws/ws_eapol_pdu.c new file mode 100644 index 0000000000..eb13735085 --- /dev/null +++ b/source/6LoWPAN/ws/ws_eapol_pdu.c @@ -0,0 +1,315 @@ +/* + * Copyright (c) 2018-2019, Arm Limited and affiliates. + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "nsconfig.h" +#include +#include "ns_types.h" +#include "ns_list.h" +#include "ns_trace.h" +#include "nsdynmemLIB.h" +#include "fhss_config.h" +#include "NWK_INTERFACE/Include/protocol.h" +#include "mac_api.h" +#include "mac_mcps.h" +#include "Common_Protocols/ipv6_constants.h" +#include "socket_api.h" +#include "6LoWPAN/MAC/mac_helper.h" +#include "6LoWPAN/MAC/mpx_api.h" +#include "6LoWPAN/ws/ws_config.h" +#include "6LoWPAN/ws/ws_eapol_pdu.h" + +#ifdef HAVE_WS + +#define TRACE_GROUP "wsep" + +typedef struct { + uint8_t handle; + void *data_ptr; + void *buffer; + ns_list_link_t link; +} eapol_pdu_msdu_t; + +typedef NS_LIST_HEAD(eapol_pdu_msdu_t, link) eapol_pdu_msdu_list_t; + +typedef struct { + uint8_t priority; + ws_eapol_pdu_address_check *addr_check; + ws_eapol_pdu_receive *receive; + ns_list_link_t link; +} eapol_pdu_recv_cb_t; + +typedef NS_LIST_HEAD(eapol_pdu_recv_cb_t, link) eapol_pdu_recv_cb_list_t; + +typedef struct { + eapol_pdu_recv_cb_list_t recv_cb_list; /**< List of receive callbacks */ + eapol_pdu_msdu_list_t msdu_list; /**< MSDU list */ + ws_eapol_pdu_receive *receive; /**< data receive callback */ + protocol_interface_info_entry_t *interface_ptr; /**< Interface pointer */ + mpx_api_t *mpx_api; /**< MPX api */ + uint16_t mpx_user_id; /**< MPX user identifier */ + uint8_t msdu_handle; /**< MSDU handle */ + ns_list_link_t link; /**< Link */ +} eapol_pdu_data_t; + +static void ws_eapol_pdu_mpx_data_confirm(const mpx_api_t *api, const struct mcps_data_conf_s *data); +static void ws_eapol_pdu_mpx_data_indication(const mpx_api_t *api, const struct mcps_data_ind_s *data); +static void ws_eapol_pdu_data_request_primitiv_set(mcps_data_req_t *dataReq, protocol_interface_info_entry_t *cur); +static eapol_pdu_data_t *ws_eapol_pdu_data_get(protocol_interface_info_entry_t *interface_ptr); + +static NS_LIST_DEFINE(eapol_pdu_data_list, eapol_pdu_data_t, link); + +int8_t ws_eapol_pdu_init(protocol_interface_info_entry_t *interface_ptr) +{ + if (!interface_ptr) { + return -1; + } + + if (ws_eapol_pdu_data_get(interface_ptr) != NULL) { + return 0; + } + + eapol_pdu_data_t *eapol_pdu_data = ns_dyn_mem_alloc(sizeof(eapol_pdu_data_t)); + if (!eapol_pdu_data) { + return -1; + } + + eapol_pdu_data->interface_ptr = interface_ptr; + ns_list_init(&eapol_pdu_data->recv_cb_list); + ns_list_init(&eapol_pdu_data->msdu_list); + eapol_pdu_data->msdu_handle = 0; + + ns_list_add_to_end(&eapol_pdu_data_list, eapol_pdu_data); + + return 0; +} + +int8_t ws_eapol_pdu_delete(protocol_interface_info_entry_t *interface_ptr) +{ + if (!interface_ptr) { + return -1; + } + + eapol_pdu_data_t *eapol_pdu_data = ws_eapol_pdu_data_get(interface_ptr); + + if (!eapol_pdu_data) { + return -1; + } + + ns_list_foreach_safe(eapol_pdu_recv_cb_t, cb_entry, &eapol_pdu_data->recv_cb_list) { + ns_list_remove(&eapol_pdu_data->recv_cb_list, cb_entry); + ns_dyn_mem_free(cb_entry); + } + + ns_list_foreach_safe(eapol_pdu_msdu_t, msdu_entry, &eapol_pdu_data->msdu_list) { + ns_list_remove(&eapol_pdu_data->msdu_list, msdu_entry); + ns_dyn_mem_free(msdu_entry); + } + + ns_list_remove(&eapol_pdu_data_list, eapol_pdu_data); + ns_dyn_mem_free(eapol_pdu_data); + + return 0; +} + +int8_t ws_eapol_pdu_cb_register(protocol_interface_info_entry_t *interface_ptr, const eapol_pdu_recv_cb_data_t *cb_data) +{ + if (!interface_ptr || !cb_data) { + return -1; + } + + eapol_pdu_data_t *eapol_pdu_data = ws_eapol_pdu_data_get(interface_ptr); + + if (!eapol_pdu_data) { + return -1; + } + + eapol_pdu_recv_cb_t *new_cb = ns_dyn_mem_alloc(sizeof(eapol_pdu_recv_cb_t)); + if (!new_cb) { + return -1; + } + + new_cb->priority = cb_data->priority; + new_cb->addr_check = cb_data->addr_check; + new_cb->receive = cb_data->receive; + + ns_list_foreach(eapol_pdu_recv_cb_t, entry, &eapol_pdu_data->recv_cb_list) { + if (new_cb->priority <= entry->priority) { + ns_list_add_before(&eapol_pdu_data->recv_cb_list, entry, new_cb); + return 0; + } + } + + ns_list_add_to_end(&eapol_pdu_data->recv_cb_list, new_cb); + return 0; +} + +int8_t ws_eapol_pdu_cb_unregister(protocol_interface_info_entry_t *interface_ptr, const eapol_pdu_recv_cb_data_t *cb_data) +{ + if (!interface_ptr || !cb_data) { + return -1; + } + + eapol_pdu_data_t *eapol_pdu_data = ws_eapol_pdu_data_get(interface_ptr); + + if (!eapol_pdu_data) { + return -1; + } + + ns_list_foreach_safe(eapol_pdu_recv_cb_t, entry, &eapol_pdu_data->recv_cb_list) { + if (entry->receive == cb_data->receive) { + ns_list_remove(&eapol_pdu_data->recv_cb_list, entry); + ns_dyn_mem_free(entry); + return 0; + } + } + + return -1; +} + +int8_t ws_eapol_pdu_send_to_mpx(protocol_interface_info_entry_t *interface_ptr, const uint8_t *eui_64, void *data, uint16_t size, void *buffer) +{ + eapol_pdu_data_t *eapol_pdu_data = ws_eapol_pdu_data_get(interface_ptr); + + if (!eapol_pdu_data) { + return -1; + } + + mcps_data_req_t data_request; + ws_eapol_pdu_data_request_primitiv_set(&data_request, eapol_pdu_data->interface_ptr); + + eapol_pdu_msdu_t *msdu_entry = ns_dyn_mem_temporary_alloc(sizeof(eapol_pdu_msdu_t)); + if (!msdu_entry) { + return -1; + } + msdu_entry->data_ptr = data; + msdu_entry->buffer = buffer; + msdu_entry->handle = eapol_pdu_data->msdu_handle++; + ns_list_add_to_start(&eapol_pdu_data->msdu_list, msdu_entry); + + memcpy(data_request.DstAddr, eui_64, 8); + data_request.msdu = data; + data_request.msduLength = size; + + eapol_pdu_data->mpx_api->mpx_data_request(eapol_pdu_data->mpx_api, &data_request, eapol_pdu_data->mpx_user_id); + return 0; +} + +static void ws_eapol_pdu_data_request_primitiv_set(mcps_data_req_t *dataReq, protocol_interface_info_entry_t *cur) +{ + memset(dataReq, 0, sizeof(mcps_data_req_t)); + + dataReq->InDirectTx = false; + dataReq->TxAckReq = true; + dataReq->SrcAddrMode = ADDR_802_15_4_LONG; + dataReq->DstAddrMode = ADDR_802_15_4_LONG; + dataReq->DstPANId = mac_helper_panid_get(cur); +} + +int8_t ws_eapol_pdu_mpx_register(protocol_interface_info_entry_t *interface_ptr, struct mpx_api_s *mpx_api, uint16_t mpx_user_id) +{ + if (!interface_ptr) { + return -1; + } + + eapol_pdu_data_t *eapol_pdu_data = ws_eapol_pdu_data_get(interface_ptr); + + if (!eapol_pdu_data) { + return -1; + } + + if (!mpx_api && eapol_pdu_data->mpx_api) { + //Disable Data Callbacks from MPX Class + eapol_pdu_data->mpx_api->mpx_user_registration(eapol_pdu_data->mpx_api, NULL, NULL, eapol_pdu_data->mpx_user_id); + } + + eapol_pdu_data->mpx_api = mpx_api; + eapol_pdu_data->mpx_user_id = mpx_user_id; + + if (eapol_pdu_data->mpx_api) { + eapol_pdu_data->mpx_api->mpx_user_registration(eapol_pdu_data->mpx_api, ws_eapol_pdu_mpx_data_confirm, ws_eapol_pdu_mpx_data_indication, eapol_pdu_data->mpx_user_id); + } + return 0; +} + +static void ws_eapol_pdu_mpx_data_confirm(const mpx_api_t *api, const struct mcps_data_conf_s *data) +{ + eapol_pdu_data_t *eapol_pdu_data = NULL; + + ns_list_foreach(eapol_pdu_data_t, entry, &eapol_pdu_data_list) { + if (entry->mpx_api == api) { + eapol_pdu_data = entry; + break; + } + } + + if (!eapol_pdu_data) { + return; + } + + ns_list_foreach(eapol_pdu_msdu_t, msdu, &eapol_pdu_data->msdu_list) { + if (msdu->handle == data->msduHandle) { + ns_dyn_mem_free(msdu->buffer); + ns_list_remove(&eapol_pdu_data->msdu_list, msdu); + ns_dyn_mem_free(msdu); + return; + } + } +} + +static void ws_eapol_pdu_mpx_data_indication(const mpx_api_t *api, const struct mcps_data_ind_s *data) +{ + if (!data || !data->msduLength || !data->msdu_ptr) { + return; + } + + eapol_pdu_data_t *eapol_pdu_data = NULL; + + ns_list_foreach(eapol_pdu_data_t, entry, &eapol_pdu_data_list) { + if (entry->mpx_api == api) { + eapol_pdu_data = entry; + break; + } + } + + if (!eapol_pdu_data) { + return; + } + + ns_list_foreach(eapol_pdu_recv_cb_t, entry, &eapol_pdu_data->recv_cb_list) { + if (entry->addr_check(eapol_pdu_data->interface_ptr, data->SrcAddr) >= 0) { + entry->receive(eapol_pdu_data->interface_ptr, data->SrcAddr, data->msdu_ptr, data->msduLength); + break; + } + } +} + +static eapol_pdu_data_t *ws_eapol_pdu_data_get(protocol_interface_info_entry_t *interface_ptr) +{ + eapol_pdu_data_t *eapol_pdu_data = NULL; + + ns_list_foreach(eapol_pdu_data_t, entry, &eapol_pdu_data_list) { + if (entry->interface_ptr == interface_ptr) { + eapol_pdu_data = entry; + break; + } + } + + return eapol_pdu_data; +} + +#endif /* HAVE_WS */ + diff --git a/source/6LoWPAN/ws/ws_eapol_pdu.h b/source/6LoWPAN/ws/ws_eapol_pdu.h new file mode 100644 index 0000000000..fc99e08285 --- /dev/null +++ b/source/6LoWPAN/ws/ws_eapol_pdu.h @@ -0,0 +1,145 @@ +/* + * Copyright (c) 2018-2019, Arm Limited and affiliates. + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef WS_EAPOL_PDU_H_ +#define WS_EAPOL_PDU_H_ + +/* + * EAPOL PDU module transfers EAPOL PDUs to/from MPX. Several users + * (e.g. supplicant PAE and EAPOL relay) can register to incoming + * EAPOL PDUs. When registering, users need to define priority that + * defines in which order incoming EAPOL PDUs are offered to them. + * + * Incoming EAPOL PDU user callbacks form a pair on EAPOL PDU module: + * address check callback is called first, and if it returns match + * then incoming EAPOL PDU callback is called. + * + */ + +/** + * ws_eapol_pdu_init initialize EAPOL PDU module + * + * \param interface_ptr interface + * + * \return < 0 failure + * \return >= 0 success + * + */ +int8_t ws_eapol_pdu_init(protocol_interface_info_entry_t *interface_ptr); + +/** + * ws_eapol_pdu_mpx_register register EAPOL PDU module to MPX + * + * \param interface_ptr interface + * \param mpx_api MPX API + * \param mpx_user_id MPX user id + * + * \return < 0 failure + * \return >= 0 success + * + */ +int8_t ws_eapol_pdu_mpx_register(protocol_interface_info_entry_t *interface_ptr, struct mpx_api_s *mpx_api, uint16_t mpx_user_id); + +/** + * ws_eapol_pdu_delete delete EAPOL PDU module + * + * \param interface_ptr interface + * + * \return < 0 failure + * \return >= 0 success + * + */ +int8_t ws_eapol_pdu_delete(protocol_interface_info_entry_t *interface_ptr); + +/** + * ws_eapol_pdu_address_check check incoming EAPOL PDU address + * + * \param interface_ptr interface + * \param eui_64 source EUI-64 + * + * \return < 0 address does not match + * \return >= 0 address matches, call the PDU receive callback + * + */ +typedef int8_t ws_eapol_pdu_address_check(protocol_interface_info_entry_t *interface_ptr, const uint8_t *eui_64); + +/** + * ws_eapol_pdu_receive receive EAPOL PDU + * + * \param interface_ptr interface + * \param eui_64 source EUI-64 + * \param data EAPOL PDU + * \param size PDU size + * + * \return < 0 failure + * \return >= 0 success + * + */ +typedef int8_t ws_eapol_pdu_receive(protocol_interface_info_entry_t *interface_ptr, const uint8_t *eui_64, void *data, uint16_t size); + +typedef enum { + EAPOL_PDU_RECV_HIGH_PRIORITY = 0, + EAPOL_PDU_RECV_MEDIUM_PRIORITY = 100, + EAPOL_PDU_RECV_LOW_PRIORITY = 200 +} eapol_pdu_recv_prior_t; + +typedef struct { + eapol_pdu_recv_prior_t priority; /**< Priority: high, medium or low */ + ws_eapol_pdu_address_check *addr_check; /**< Address check callback */ + ws_eapol_pdu_receive *receive; /**< PDU receive callback */ +} eapol_pdu_recv_cb_data_t; + +/** + * ws_eapol_pdu_cb_register register an incoming EAPOL PDU callback + * + * \param interface_ptr interface + * \param cb_data callback data + * + * \return < 0 failure + * \return >= 0 success + * + */ +int8_t ws_eapol_pdu_cb_register(protocol_interface_info_entry_t *interface_ptr, const eapol_pdu_recv_cb_data_t *cb_data); + +/** + * ws_eapol_pdu_cb_unregister unregister an incoming EAPOL PDU callback + * + * \param interface_ptr interface + * \param cb_data callback data + * + * \return < 0 failure + * \return >= 0 success + * + */ +int8_t ws_eapol_pdu_cb_unregister(protocol_interface_info_entry_t *interface_ptr, const eapol_pdu_recv_cb_data_t *cb_data); + +/** + * ws_eapol_pdu_send_to_mpx send EAPOL PDU to MPX + * + * \param interface_ptr interface + * \param eui_64 destination EUI-64 + * \param data EAPOL PDU + * \param size PDU size + * \param buffer pointer to allocated buffer + * + * \return < 0 failure + * \return >= 0 success + * + */ +int8_t ws_eapol_pdu_send_to_mpx(protocol_interface_info_entry_t *interface_ptr, const uint8_t *eui_64, void *data, uint16_t size, void *buffer); + +#endif /* WS_EAPOL_PDU_H_ */ diff --git a/source/6LoWPAN/ws/ws_eapol_relay.c b/source/6LoWPAN/ws/ws_eapol_relay.c new file mode 100644 index 0000000000..269ad38d6d --- /dev/null +++ b/source/6LoWPAN/ws/ws_eapol_relay.c @@ -0,0 +1,193 @@ +/* + * Copyright (c) 2018-2019, Arm Limited and affiliates. + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "nsconfig.h" +#include +#include "ns_types.h" +#include "ns_list.h" +#include "ns_trace.h" +#include "nsdynmemLIB.h" +#include "fhss_config.h" +#include "NWK_INTERFACE/Include/protocol.h" +#include "mac_api.h" +#include "mac_mcps.h" +#include "Common_Protocols/ipv6_constants.h" +#include "socket_api.h" +#include "6LoWPAN/MAC/mac_helper.h" +#include "6LoWPAN/MAC/mpx_api.h" +#include "6LoWPAN/ws/ws_config.h" +#include "6LoWPAN/ws/ws_eapol_pdu.h" +#include "6LoWPAN/ws/ws_eapol_relay_lib.h" +#include "6LoWPAN/ws/ws_eapol_relay.h" + +#ifdef HAVE_WS +#ifdef HAVE_EAPOL_RELAY + +#define TRACE_GROUP "wser" + +typedef struct { + protocol_interface_info_entry_t *interface_ptr; /**< Interface pointer */ + ns_address_t remote_addr; /**< Remote address (border router address) */ + int8_t socket_id; /**< Socket ID for relay */ + ns_list_link_t link; /**< Link */ +} eapol_relay_t; + +static eapol_relay_t *ws_eapol_relay_get(protocol_interface_info_entry_t *interface_ptr); +static int8_t ws_eapol_relay_eapol_pdu_address_check(protocol_interface_info_entry_t *interface_ptr, const uint8_t *eui_64); +static int8_t ws_eapol_relay_eapol_pdu_receive(protocol_interface_info_entry_t *interface_ptr, const uint8_t *eui_64, void *pdu, uint16_t size); +static void ws_eapol_relay_socket_cb(void *cb); + +static const eapol_pdu_recv_cb_data_t eapol_pdu_recv_cb_data = { + .priority = EAPOL_PDU_RECV_LOW_PRIORITY, + .addr_check = ws_eapol_relay_eapol_pdu_address_check, + .receive = ws_eapol_relay_eapol_pdu_receive +}; + +static NS_LIST_DEFINE(eapol_relay_list, eapol_relay_t, link); + +int8_t ws_eapol_relay_start(protocol_interface_info_entry_t *interface_ptr, uint16_t local_port, const uint8_t *remote_addr, uint16_t remote_port) +{ + if (!interface_ptr || !remote_addr) { + return -1; + } + + if (ws_eapol_relay_get(interface_ptr)) { + return 0; + } + + eapol_relay_t *eapol_relay = ns_dyn_mem_alloc(sizeof(eapol_relay_t)); + if (!eapol_relay) { + return -1; + } + + eapol_relay->interface_ptr = interface_ptr; + + eapol_relay->remote_addr.type = ADDRESS_IPV6; + memcpy(&eapol_relay->remote_addr.address, remote_addr, 16); + eapol_relay->remote_addr.identifier = remote_port; + + eapol_relay->socket_id = socket_open(IPV6_NH_UDP, local_port, &ws_eapol_relay_socket_cb); + if (eapol_relay->socket_id < 0) { + ns_dyn_mem_free(eapol_relay); + return -1; + } + + if (ws_eapol_pdu_cb_register(interface_ptr, &eapol_pdu_recv_cb_data) < 0) { + ns_dyn_mem_free(eapol_relay); + return -1; + } + + ns_list_add_to_end(&eapol_relay_list, eapol_relay); + + return 0; +} + +int8_t ws_eapol_relay_delete(protocol_interface_info_entry_t *interface_ptr) +{ + if (!interface_ptr) { + return -1; + } + + eapol_relay_t *eapol_relay = ws_eapol_relay_get(interface_ptr); + if (!eapol_relay) { + return -1; + } + + socket_close(eapol_relay->socket_id); + + ws_eapol_pdu_cb_unregister(interface_ptr, &eapol_pdu_recv_cb_data); + + ns_list_remove(&eapol_relay_list, eapol_relay); + ns_dyn_mem_free(eapol_relay); + + return 0; +} + +static eapol_relay_t *ws_eapol_relay_get(protocol_interface_info_entry_t *interface_ptr) +{ + ns_list_foreach(eapol_relay_t, entry, &eapol_relay_list) { + if (entry->interface_ptr == interface_ptr) { + return entry; + } + } + + return NULL; +} + +static int8_t ws_eapol_relay_eapol_pdu_address_check(protocol_interface_info_entry_t *interface_ptr, const uint8_t *eui_64) +{ + (void) eui_64; + (void) interface_ptr; + + // Low priority, always route all here if asked + return 0; +} + +static int8_t ws_eapol_relay_eapol_pdu_receive(protocol_interface_info_entry_t *interface_ptr, const uint8_t *eui_64, void *pdu, uint16_t size) +{ + eapol_relay_t *eapol_relay = ws_eapol_relay_get(interface_ptr); + if (!eapol_relay) { + return -1; + } + + ws_eapol_relay_lib_send_to_relay(eapol_relay->socket_id, eui_64, &eapol_relay->remote_addr, pdu, size); + + return 0; +} + +static void ws_eapol_relay_socket_cb(void *cb) +{ + socket_callback_t *cb_data = cb; + + if (cb_data->event_type != SOCKET_DATA) { + return; + } + + eapol_relay_t *eapol_relay = NULL; + + ns_list_foreach(eapol_relay_t, entry, &eapol_relay_list) { + if (entry->socket_id == cb_data->socket_id) { + eapol_relay = entry; + break; + } + } + + if (!eapol_relay) { + return; + } + + uint8_t *socket_pdu = ns_dyn_mem_temporary_alloc(cb_data->d_len); + if (!socket_pdu) { + return; + } + + ns_address_t src_addr; + + if (socket_recvfrom(cb_data->socket_id, socket_pdu, cb_data->d_len, 0, &src_addr) != cb_data->d_len) { + ns_dyn_mem_free(socket_pdu); + return; + } + + //First 8 byte is EUID64 and rsr payload + if (ws_eapol_pdu_send_to_mpx(eapol_relay->interface_ptr, socket_pdu, socket_pdu + 8, cb_data->d_len - 8, socket_pdu) < 0) { + ns_dyn_mem_free(socket_pdu); + } +} + +#endif /* HAVE_EAPOL_RELAY */ +#endif /* HAVE_WS */ + diff --git a/source/6LoWPAN/ws/ws_eapol_relay.h b/source/6LoWPAN/ws/ws_eapol_relay.h new file mode 100644 index 0000000000..dbbfbc584a --- /dev/null +++ b/source/6LoWPAN/ws/ws_eapol_relay.h @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2018-2019, Arm Limited and affiliates. + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef WS_EAPOL_RELAY_H_ +#define WS_EAPOL_RELAY_H_ + +#ifdef HAVE_EAPOL_RELAY + +/* + * EAPOL relay conveys EAPOL PDUs between authenticator EAPOL relay and local + * MPX interface. + * + * On supplicant (i.e. node) relay should be bound to UDP port 10253 (local + * port parameter). + * + * On authenticator (border router) relay will need to use some other port than + * 10253 since authenticator EAPOL relay is bound to port 10253. + * + * Border router address needs to be set on start (remote address and remote port + * parameter). + * + */ + +/** + * ws_eapol_relay_start start EAPOL relay + * + * \param interface_ptr interface + * \param local_port local port + * \param remote_addr remote address (border router relay address) + * \param remote_port remote port (border router relay port) + * + * \return < 0 failure + * \return >= 0 success + * + */ +int8_t ws_eapol_relay_start(protocol_interface_info_entry_t *interface_ptr, uint16_t local_port, const uint8_t *remote_addr, uint16_t remote_port); + +/** + * ws_eapol_relay_delete delete EAPOL + * + * \param interface_ptr interface + * + * \return < 0 failure + * \return >= 0 success + * + */ +int8_t ws_eapol_relay_delete(protocol_interface_info_entry_t *interface_ptr); + +#else + +#define ws_eapol_relay_start(interface_ptr, local_port, remote_addr, remote_port); +#define ws_eapol_relay_delete(interface_ptr); + +#endif + +#endif /* WS_EAPOL_RELAY_H_ */ diff --git a/source/6LoWPAN/ws/ws_eapol_relay_lib.c b/source/6LoWPAN/ws/ws_eapol_relay_lib.c new file mode 100644 index 0000000000..4352d77149 --- /dev/null +++ b/source/6LoWPAN/ws/ws_eapol_relay_lib.c @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2018-2019, 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 "socket_api.h" +#include "6LoWPAN/ws/ws_config.h" +#include "6LoWPAN/ws/ws_eapol_relay_lib.h" + +#ifdef HAVE_WS + +#define TRACE_GROUP "wsrl" + +int8_t ws_eapol_relay_lib_send_to_relay(const uint8_t socket_id, const uint8_t *eui_64, const ns_address_t *dest_addr, const void *data, uint16_t data_len) +{ + ns_address_t addr = *dest_addr; + + ns_iovec_t msg_iov[2]; + ns_msghdr_t msghdr; + //Set messages name buffer + msghdr.msg_name = &addr; + msghdr.msg_namelen = sizeof(addr); + msghdr.msg_iov = &msg_iov[0]; + msghdr.msg_iovlen = 2; + msghdr.msg_control = NULL; + msghdr.msg_controllen = 0; + msg_iov[0].iov_base = (void *)eui_64; + msg_iov[0].iov_len = 8; + msg_iov[1].iov_base = (void *)data; + msg_iov[1].iov_len = data_len; + socket_sendmsg(socket_id, &msghdr, NS_MSG_LEGACY0); + return 0; +} + +#endif /* HAVE_WS */ + diff --git a/source/6LoWPAN/ws/ws_eapol_relay_lib.h b/source/6LoWPAN/ws/ws_eapol_relay_lib.h new file mode 100644 index 0000000000..b1c387951a --- /dev/null +++ b/source/6LoWPAN/ws/ws_eapol_relay_lib.h @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2018-2019, Arm Limited and affiliates. + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef WS_EAPOL_RELAY_LIB_H_ +#define WS_EAPOL_RELAY_LIB_H_ + +int8_t ws_eapol_relay_lib_send_to_relay(const uint8_t socket_id, const uint8_t *eui_64, const ns_address_t *dest_addr, const void *data, uint16_t data_len); + +#endif /* WS_EAPOL_RELAY_LIB_H_ */ diff --git a/source/6LoWPAN/ws/ws_empty_functions.c b/source/6LoWPAN/ws/ws_empty_functions.c new file mode 100644 index 0000000000..982e27bd79 --- /dev/null +++ b/source/6LoWPAN/ws/ws_empty_functions.c @@ -0,0 +1,185 @@ +/* + * Copyright (c) 2018-2019, 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 +#include "nsconfig.h" +#include "ns_types.h" +#include "ns_trace.h" +#include +#include +#include "NWK_INTERFACE/Include/protocol.h" +#include "6LoWPAN/ws/ws_common.h" + +#include "ws_management_api.h" + +#ifndef HAVE_WS +int ws_management_node_init( + int8_t interface_id, + uint8_t regulatory_domain, + char *network_name_ptr, + fhss_timer_t *fhss_timer_ptr) +{ + (void)interface_id; + (void)regulatory_domain; + (void)network_name_ptr; + (void)fhss_timer_ptr; + return -1; +} + +int ws_management_regulatory_domain_set( + int8_t interface_id, + uint8_t regulatory_domain, + uint8_t operating_class, + uint8_t operating_mode) +{ + (void)interface_id; + (void)regulatory_domain; + (void)operating_class; + (void)operating_mode; + return -1; +} + +int ws_management_network_size_set( + int8_t interface_id, + uint8_t network_size) +{ + (void)interface_id; + (void)network_size; + return -1; +} + +int ws_management_channel_mask_set( + int8_t interface_id, + uint32_t channel_mask[8]) +{ + (void)interface_id; + (void)channel_mask; + return -1; +} + +int ws_management_channel_plan_set( + int8_t interface_id, + uint8_t channel_plan, + uint8_t uc_channel_function, + uint8_t bc_channel_function, + uint32_t ch0_freq, // Stack can not modify this + uint8_t channel_spacing,// Stack can not modify this + uint8_t number_of_channels) +{ + (void)interface_id; + (void)channel_plan; + (void)uc_channel_function; + (void)bc_channel_function; + (void)ch0_freq; + (void)channel_spacing; + (void)number_of_channels; + return -1; +} + +int ws_management_fhss_timing_configure( + int8_t interface_id, + uint8_t fhss_uc_dwell_interval, + uint32_t fhss_broadcast_interval, + uint8_t fhss_bc_dwell_interval) +{ + (void)interface_id; + (void)fhss_uc_dwell_interval; + (void)fhss_broadcast_interval; + (void)fhss_bc_dwell_interval; + return -1; +} + +int ws_management_fhss_unicast_channel_function_configure( + int8_t interface_id, + uint8_t channel_function, + uint16_t fixed_channel, + uint8_t dwell_interval) +{ + (void)interface_id; + (void)channel_function; + (void)fixed_channel; + (void)dwell_interval; + return -1; +} + +int ws_management_fhss_broadcast_channel_function_configure( + int8_t interface_id, + uint8_t channel_function, + uint16_t fixed_channel, + uint8_t dwell_interval, + uint32_t broadcast_interval) +{ + (void)interface_id; + (void)channel_function; + (void)fixed_channel; + (void)dwell_interval; + (void)broadcast_interval; + return -1; +} + +/* ### test api ### */ +int ws_test_pan_size_set(int8_t interface_id, uint16_t pan_size) +{ + (void) interface_id; + (void) pan_size; + return -1; +} +int ws_test_max_child_count_set(int8_t interface_id, uint16_t child_count) +{ + (void) interface_id; + (void) child_count; + return -1; +} + +int ws_test_gtk_set(int8_t interface_id, uint8_t *gtk[4]) +{ + (void) interface_id; + (void) gtk; + + return -1; +} + +int ws_test_active_key_set(int8_t interface_id, uint8_t index) +{ + (void) interface_id; + (void) index; + + return -1; +} + +int ws_test_key_lifetime_set(int8_t interface_id, uint32_t gtk_lifetime, uint32_t pmk_lifetime, uint32_t ptk_lifetime) +{ + (void) interface_id; + (void) gtk_lifetime; + (void) pmk_lifetime; + (void) ptk_lifetime; + + return -1; +} + +int ws_test_gtk_time_settings_set(int8_t interface_id, uint8_t revocat_lifetime_reduct, uint8_t new_activation_time, uint32_t max_mismatch) +{ + (void) interface_id; + (void) revocat_lifetime_reduct; + (void) new_activation_time; + (void) max_mismatch; + + return -1; +} + +#endif // no HAVE_WS + diff --git a/source/6LoWPAN/ws/ws_ie_lib.c b/source/6LoWPAN/ws/ws_ie_lib.c new file mode 100644 index 0000000000..92b95bce68 --- /dev/null +++ b/source/6LoWPAN/ws/ws_ie_lib.c @@ -0,0 +1,557 @@ +/* + * Copyright (c) 2018-2019, 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 "mac_common_defines.h" +#include "6LoWPAN/MAC/mac_ie_lib.h" +#include "6LoWPAN/ws/ws_common_defines.h" +#include "6LoWPAN/ws/ws_ie_lib.h" + +static uint8_t *ws_wh_header_base_write(uint8_t *ptr, uint16_t length, uint8_t type) +{ + ptr = mac_ie_header_base_write(ptr, MAC_HEADER_ASSIGNED_EXTERNAL_ORG_IE_ID, length + 1); + *ptr++ = type; + return ptr; +} + +static uint16_t ws_channel_plan_length(uint8_t channel_plan) +{ + switch (channel_plan) { + case 0: + //Regulator domain and operationg class inline + return 2; + case 1: + //CHo, Channel spasing and number of channel's inline + return 6; + + default: + return 0; + } +} + +static uint16_t ws_channel_function_length(uint8_t channel_function, uint16_t hop_channel_count) +{ + switch (channel_function) { + case 0: + //Fixed channel inline + return 2; + case 1: + case 2: + return 0; + case 3: + //Hop count + channel hop list + return (1 + hop_channel_count); + default: + return 0; + + } +} + +uint16_t ws_wp_nested_hopping_schedule_length(struct ws_hopping_schedule_s *hopping_schedule, bool unicast_schedule) +{ + uint16_t length; + uint8_t channel_function; + if (unicast_schedule) { + length = 4; + channel_function = hopping_schedule->uc_channel_function; + } else { + length = 10; + channel_function = hopping_schedule->bc_channel_function; + } + + length += ws_channel_plan_length(hopping_schedule->channel_plan); + + length += ws_channel_function_length(channel_function, 1); + + //Todo Derive some how exluded channel control + return length; +} + +uint8_t *ws_wh_utt_write(uint8_t *ptr, uint8_t message_type) +{ + ptr = ws_wh_header_base_write(ptr, 4, WH_IE_UTT_TYPE); + *ptr++ = message_type; + memset(ptr, 0, 3); + ptr += 3; + return ptr; +} + +uint8_t *ws_wh_bt_write(uint8_t *ptr) +{ + ptr = ws_wh_header_base_write(ptr, 5, WH_IE_BT_TYPE); + memset(ptr, 0, 5); + ptr += 5; + return ptr; +} + + +uint8_t *ws_wh_fc_write(uint8_t *ptr, uint8_t flow_ctrl) +{ + ptr = ws_wh_header_base_write(ptr, 1, WH_IE_FC_TYPE); + *ptr++ = flow_ctrl; + return ptr; +} + +uint8_t *ws_wh_rsl_write(uint8_t *ptr, int8_t rssi) +{ + ptr = ws_wh_header_base_write(ptr, 1, WH_IE_RSL_TYPE); + *ptr++ = rssi; + return ptr; +} + +uint8_t *ws_wh_ea_write(uint8_t *ptr, uint8_t *eui64) +{ + ptr = ws_wh_header_base_write(ptr, 8, WH_IE_EA_TYPE); + memcpy(ptr, eui64, 8); + ptr += 8; + return ptr; +} + +uint8_t *ws_wh_vh_write(uint8_t *ptr, uint8_t *vendor_header, uint8_t vendor_header_length) +{ + ptr = ws_wh_header_base_write(ptr, vendor_header_length, WH_IE_VH_TYPE); + if (vendor_header_length) { + memcpy(ptr, vendor_header, vendor_header_length); + ptr += vendor_header_length; + } + return ptr; +} + +uint8_t *ws_wp_base_write(uint8_t *ptr, uint16_t length) +{ + return mac_ie_payload_base_write(ptr, WS_WP_NESTED_IE, length); +} + +uint8_t *ws_wp_nested_hopping_schedule_write(uint8_t *ptr, struct ws_hopping_schedule_s *hopping_schedule, bool unicast_schedule) +{ + //Calculate length + uint16_t length = ws_wp_nested_hopping_schedule_length(hopping_schedule, unicast_schedule); + if (!unicast_schedule) { + ptr = mac_ie_nested_ie_long_base_write(ptr, WP_PAYLOAD_IE_BS_TYPE, length); + ptr = common_write_32_bit_inverse(hopping_schedule->fhss_broadcast_interval, ptr); + ptr = common_write_16_bit_inverse(hopping_schedule->fhss_bsi, ptr); + *ptr++ = hopping_schedule->fhss_bc_dwell_interval; + } else { + ptr = mac_ie_nested_ie_long_base_write(ptr, WP_PAYLOAD_IE_US_TYPE, length); + *ptr++ = hopping_schedule->fhss_uc_dwell_interval; + } + + *ptr++ = hopping_schedule->clock_drift; + *ptr++ = hopping_schedule->timing_accurancy; + uint8_t channel_info_base = 0; + channel_info_base = (hopping_schedule->channel_plan); + if (unicast_schedule) { + channel_info_base |= (hopping_schedule->uc_channel_function << 3); + } else { + channel_info_base |= (hopping_schedule->bc_channel_function << 3); + } + //Todo define excluded channel ctrl + + *ptr++ = channel_info_base; + + switch (hopping_schedule->channel_plan) { + case 0: + //Regulator domain and operationg class inline + *ptr++ = hopping_schedule->regulatory_domain; + *ptr++ = hopping_schedule->operating_class; + break; + case 1: + //CHo, Channel spasing and number of channel's inline + ptr = common_write_24_bit(hopping_schedule->fhss_uc_dwell_interval, ptr); + *ptr++ = ((hopping_schedule->channel_spacing << 4) & 0xf0); + ptr = common_write_16_bit(hopping_schedule->number_of_channels, ptr); + break; + default: + break; + } + uint8_t cf = hopping_schedule->uc_channel_function; + uint16_t fixed_channel = hopping_schedule->uc_fixed_channel; + if (!unicast_schedule) { + cf = hopping_schedule->bc_channel_function; + } + switch (cf) { + case 0: + //Fixed channel inline + if (!unicast_schedule) { + fixed_channel = hopping_schedule->bc_fixed_channel; + } + ptr = common_write_16_bit_inverse(fixed_channel, ptr); + break; + case 1: + case 2: + //No Inline + break; + case 3: + //TODO do this properly + //Hop count + channel hop list + *ptr++ = 1; + *ptr++ = 0; + break; + default: + break; + + } + return ptr; +} + +uint8_t *ws_wp_nested_vp_write(uint8_t *ptr, uint8_t *vendor_payload, uint16_t vendor_payload_length) +{ + if (vendor_payload_length) { + ptr = mac_ie_nested_ie_long_base_write(ptr, WP_PAYLOAD_IE_VP_TYPE, vendor_payload_length); + memcpy(ptr, vendor_payload, vendor_payload_length); + ptr += vendor_payload_length; + } + return ptr; +} + +uint8_t *ws_wp_nested_pan_info_write(uint8_t *ptr, struct ws_pan_information_s *pan_congiguration) +{ + if (!pan_congiguration) { + return mac_ie_nested_ie_short_base_write(ptr, WP_PAYLOAD_IE_PAN_TYPE, 0); + } + ptr = mac_ie_nested_ie_short_base_write(ptr, WP_PAYLOAD_IE_PAN_TYPE, 5); + ptr = common_write_16_bit_inverse(pan_congiguration->pan_size, ptr); + ptr = common_write_16_bit_inverse(pan_congiguration->routing_cost, ptr); + uint8_t temp8 = 0; + temp8 |= (pan_congiguration->use_parent_bs << 0); + temp8 |= (pan_congiguration->rpl_routing_method << 1); + temp8 |= pan_congiguration->version << 5; + *ptr++ = temp8; + return ptr; +} + + +uint8_t *ws_wp_nested_netname_write(uint8_t *ptr, uint8_t *network_name, uint8_t network_name_length) +{ + ptr = mac_ie_nested_ie_short_base_write(ptr, WP_PAYLOAD_IE_NETNAME_TYPE, network_name_length); + if (network_name_length) { + memcpy(ptr, network_name, network_name_length); + ptr += network_name_length; + } + return ptr; +} + +uint8_t *ws_wp_nested_pan_ver_write(uint8_t *ptr, struct ws_pan_information_s *pan_congiguration) +{ + if (!pan_congiguration) { + return ptr; + } + ptr = mac_ie_nested_ie_short_base_write(ptr, WP_PAYLOAD_IE_PAN_VER_TYPE, 2); + return common_write_16_bit_inverse(pan_congiguration->pan_version, ptr); +} + +uint8_t *ws_wp_nested_gtkhash_write(uint8_t *ptr, uint8_t *gtkhash, uint8_t gtkhash_length) +{ + ptr = mac_ie_nested_ie_short_base_write(ptr, WP_PAYLOAD_IE_GTKHASH_TYPE, gtkhash_length); + if (gtkhash_length) { + memcpy(ptr, gtkhash, 32); + ptr += 32; + } + return ptr; +} + +bool ws_wh_utt_read(uint8_t *data, uint16_t length, struct ws_utt_ie *utt_ie) +{ + mac_header_IE_t utt_ie_data; + utt_ie_data.id = MAC_HEADER_ASSIGNED_EXTERNAL_ORG_IE_ID; + if (4 != mac_ie_header_sub_id_discover(data, length, &utt_ie_data, WH_IE_UTT_TYPE)) { + // NO UTT header + return false; + } + data = utt_ie_data.content_ptr; + utt_ie->message_type = *data++; + utt_ie->ufsi = common_read_24_bit_inverse(data); + return true; +} + +bool ws_wh_bt_read(uint8_t *data, uint16_t length, struct ws_bt_ie *bt_ie) +{ + mac_header_IE_t btt_ie_data; + btt_ie_data.id = MAC_HEADER_ASSIGNED_EXTERNAL_ORG_IE_ID; + if (5 != mac_ie_header_sub_id_discover(data, length, &btt_ie_data, WH_IE_BT_TYPE)) { + return false; + } + data = btt_ie_data.content_ptr; + bt_ie->broadcast_slot_number = common_read_16_bit_inverse(data); + bt_ie->broadcast_interval_offset = common_read_24_bit_inverse(data + 2); + return true; +} + +bool ws_wh_rsl_read(uint8_t *data, uint16_t length, int8_t *rsl) +{ + mac_header_IE_t rsl_ie_data; + rsl_ie_data.id = MAC_HEADER_ASSIGNED_EXTERNAL_ORG_IE_ID; + if (1 != mac_ie_header_sub_id_discover(data, length, &rsl_ie_data, WH_IE_RSL_TYPE)) { + return false; + } + *rsl = *rsl_ie_data.content_ptr; + + return true; +} + +bool ws_wh_ea_read(uint8_t *data, uint16_t length, uint8_t *eui64) +{ + mac_header_IE_t rsl_ie_data; + rsl_ie_data.id = MAC_HEADER_ASSIGNED_EXTERNAL_ORG_IE_ID; + if (8 != mac_ie_header_sub_id_discover(data, length, &rsl_ie_data, WH_IE_EA_TYPE)) { + return false; + } + memcpy(eui64, rsl_ie_data.content_ptr, 8); + + return true; +} + +static uint8_t *ws_channel_plan_zero_read(uint8_t *ptr, ws_channel_plan_zero_t *plan) +{ + plan->regulator_domain = *ptr++; + plan->operation_class = *ptr++; + return ptr; +} + +static uint8_t *ws_channel_plan_one_read(uint8_t *ptr, ws_channel_plan_one_t *plan) +{ + plan->ch0 = common_read_24_bit_inverse(ptr); + ptr += 3; + plan->channel_spacing = (*ptr++ & 0xf0) >> 4; + plan->number_of_channel = common_read_16_bit_inverse(ptr); + ptr += 2; + return ptr; +} + +static uint8_t *ws_channel_function_zero_read(uint8_t *ptr, ws_channel_function_zero_t *plan) +{ + plan->fixed_channel = common_read_16_bit_inverse(ptr); + return ptr + 2; +} + +static uint8_t *ws_channel_function_three_read(uint8_t *ptr, ws_channel_function_three_t *plan) +{ + plan->channel_hop_count = *ptr++; + plan->channel_list = ptr++; + return ptr; +} + +bool ws_wp_nested_us_read(uint8_t *data, uint16_t length, struct ws_us_ie *us_ie) +{ + mac_nested_payload_IE_t nested_payload_ie; + nested_payload_ie.id = WP_PAYLOAD_IE_US_TYPE; + nested_payload_ie.type_long = true; + if (mac_ie_nested_discover(data, length, &nested_payload_ie) < 4) { + return false; + } + data = nested_payload_ie.content_ptr; + us_ie->dwell_interval = *data++; + us_ie->clock_drift = *data++; + us_ie->timing_accurancy = *data++; + us_ie->channel_plan = (*data & 3); + us_ie->channel_function = (*data & 0x38) >> 3; + us_ie->excluded_channel_ctrl = (*data & 0xc0) >> 6; + data++; + uint16_t info_length = 0; + nested_payload_ie.length -= 4; + info_length = ws_channel_plan_length(us_ie->channel_plan); + if (nested_payload_ie.length < info_length) { + return false; + } + + nested_payload_ie.length -= info_length; + switch (us_ie->channel_plan) { + case 0: + data = ws_channel_plan_zero_read(data, &us_ie->plan.zero); + break; + + case 1: + data = ws_channel_plan_one_read(data, &us_ie->plan.one); + break; + default: + return false; + + } + + info_length = ws_channel_function_length(us_ie->channel_function, 0); + + if (nested_payload_ie.length < info_length) { + return false; + } + nested_payload_ie.length -= info_length; + + + switch (us_ie->channel_function) { + case 0: + data = ws_channel_function_zero_read(data, &us_ie->function.zero); + break; + + case 1: + case 2: + break; + + case 3: + + data = ws_channel_function_three_read(data, &us_ie->function.three); + info_length = us_ie->function.three.channel_hop_count; + if (nested_payload_ie.length < info_length) { + return false; + } + nested_payload_ie.length -= info_length; + data += info_length; + break; + default: + return false; + + } + + return true; +} +bool ws_wp_nested_bs_read(uint8_t *data, uint16_t length, struct ws_bs_ie *bs_ie) +{ + mac_nested_payload_IE_t nested_payload_ie; + nested_payload_ie.id = WP_PAYLOAD_IE_BS_TYPE; + nested_payload_ie.type_long = true; + if (mac_ie_nested_discover(data, length, &nested_payload_ie) < 10) { + return false; + } + data = nested_payload_ie.content_ptr; + bs_ie->broadcast_interval = common_read_32_bit_inverse(data); + bs_ie->broadcast_schedule_identifier = common_read_16_bit_inverse(data + 4); + data += 6; + bs_ie->dwell_interval = *data++; + bs_ie->clock_drift = *data++; + bs_ie->timing_accurancy = *data++; + + bs_ie->channel_plan = (*data & 3); + bs_ie->channel_function = (*data & 0x38) >> 3; + bs_ie->excluded_channel_ctrl = (*data & 0xc0) >> 6; + data++; + nested_payload_ie.length -= 10; + uint16_t info_length = 0; + + info_length = ws_channel_plan_length(bs_ie->channel_plan); + if (nested_payload_ie.length < info_length) { + return false; + } + nested_payload_ie.length -= info_length; + switch (bs_ie->channel_plan) { + case 0: + data = ws_channel_plan_zero_read(data, &bs_ie->plan.zero); + break; + + case 1: + data = ws_channel_plan_one_read(data, &bs_ie->plan.one); + break; + default: + return false; + + } + + info_length = ws_channel_function_length(bs_ie->channel_function, 0); + if (nested_payload_ie.length < info_length) { + return false; + } + nested_payload_ie.length -= info_length; + + switch (bs_ie->channel_function) { + case 0: + data = ws_channel_function_zero_read(data, &bs_ie->function.zero); + break; + + case 1: + case 2: + break; + + case 3: + data = ws_channel_function_three_read(data, &bs_ie->function.three); + info_length = bs_ie->function.three.channel_hop_count; + if (nested_payload_ie.length < info_length) { + return false; + } + nested_payload_ie.length -= info_length; + data += info_length; + break; + default: + return false; + + } + + return true; +} + +bool ws_wp_nested_pan_read(uint8_t *data, uint16_t length, struct ws_pan_information_s *pan_congiguration) +{ + mac_nested_payload_IE_t nested_payload_ie; + nested_payload_ie.id = WP_PAYLOAD_IE_PAN_TYPE; + nested_payload_ie.type_long = false; + if (mac_ie_nested_discover(data, length, &nested_payload_ie) != 5) { + return false; + } + + pan_congiguration->pan_size = common_read_16_bit_inverse(nested_payload_ie.content_ptr); + pan_congiguration->routing_cost = common_read_16_bit_inverse(nested_payload_ie.content_ptr + 2); + pan_congiguration->use_parent_bs = (nested_payload_ie.content_ptr[4] & 0x01) == 0x01; + pan_congiguration->rpl_routing_method = (nested_payload_ie.content_ptr[4] & 0x02) == 0x02; + pan_congiguration->version = (nested_payload_ie.content_ptr[4] & 0xe0) >> 5; + + return true; +} + +bool ws_wp_nested_pan_version_read(uint8_t *data, uint16_t length, uint16_t *pan_version) +{ + mac_nested_payload_IE_t nested_payload_ie; + nested_payload_ie.id = WP_PAYLOAD_IE_PAN_VER_TYPE; + nested_payload_ie.type_long = false; + if (mac_ie_nested_discover(data, length, &nested_payload_ie) != 2) { + return false; + } + *pan_version = common_read_16_bit_inverse(nested_payload_ie.content_ptr); + + return true; +} + +uint8_t *ws_wp_nested_gtkhash_read(uint8_t *data, uint16_t length) +{ + mac_nested_payload_IE_t nested_payload_ie; + nested_payload_ie.id = WP_PAYLOAD_IE_GTKHASH_TYPE; + nested_payload_ie.type_long = false; + if (mac_ie_nested_discover(data, length, &nested_payload_ie) != 32) { + return NULL; + } + + return nested_payload_ie.content_ptr; +} + + +bool ws_wp_nested_network_name_read(uint8_t *data, uint16_t length, ws_wp_network_name_t *network_name) +{ + mac_nested_payload_IE_t nested_payload_ie; + nested_payload_ie.id = WP_PAYLOAD_IE_NETNAME_TYPE; + nested_payload_ie.type_long = false; + + if (0 == mac_ie_nested_discover(data, length, &nested_payload_ie)) { + return false; + } else if (nested_payload_ie.length > 32) { + //Too long name + return false; + } + network_name->network_name = nested_payload_ie.content_ptr; + network_name->network_name_length = nested_payload_ie.length; + return true; +} + diff --git a/source/6LoWPAN/ws/ws_ie_lib.h b/source/6LoWPAN/ws/ws_ie_lib.h new file mode 100644 index 0000000000..e992b09fd2 --- /dev/null +++ b/source/6LoWPAN/ws/ws_ie_lib.h @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2018-2019, Arm Limited and affiliates. + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef WS_IE_LIB_H_ +#define WS_IE_LIB_H_ + +struct ws_pan_information_s; +struct ws_utt_ie; +struct ws_bt_ie; +struct ws_us_ie; +struct ws_hopping_schedule_s; + +/** + * @brief ws_wp_network_name_t WS nested payload network name + */ +typedef struct ws_wp_network_name { + uint8_t network_name_length; + uint8_t *network_name; +} ws_wp_network_name_t; + +/* 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_rsl_write(uint8_t *ptr, int8_t rssi); +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_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); + +/* WS_WP_NESTED PAYLOD IE */ +uint8_t *ws_wp_base_write(uint8_t *ptr, uint16_t length); +uint8_t *ws_wp_nested_hopping_schedule_write(uint8_t *ptr, struct ws_hopping_schedule_s *hopping_schedule, bool unicast_schedule); +uint8_t *ws_wp_nested_vp_write(uint8_t *ptr, uint8_t *vendor_payload, uint16_t vendor_payload_length); +uint8_t *ws_wp_nested_pan_info_write(uint8_t *ptr, struct ws_pan_information_s *pan_congiguration); +uint8_t *ws_wp_nested_netname_write(uint8_t *ptr, uint8_t *network_name, uint8_t network_name_length); +uint8_t *ws_wp_nested_pan_ver_write(uint8_t *ptr, struct ws_pan_information_s *pan_congiguration); +uint8_t *ws_wp_nested_gtkhash_write(uint8_t *ptr, uint8_t *gtkhash, uint8_t gtkhash_length); +uint16_t ws_wp_nested_hopping_schedule_length(struct ws_hopping_schedule_s *hopping_schedule, bool unicast_schedule); + +bool ws_wp_nested_us_read(uint8_t *data, uint16_t length, struct ws_us_ie *us_ie); +bool ws_wp_nested_bs_read(uint8_t *data, uint16_t length, struct ws_bs_ie *bs_ie); +bool ws_wp_nested_pan_read(uint8_t *data, uint16_t length, struct ws_pan_information_s *pan_congiguration); +bool ws_wp_nested_pan_version_read(uint8_t *data, uint16_t length, uint16_t *pan_version); +bool ws_wp_nested_network_name_read(uint8_t *data, uint16_t length, ws_wp_network_name_t *network_name); +uint8_t *ws_wp_nested_gtkhash_read(uint8_t *data, uint16_t length); + + +#endif /* WS_IE_LIB_H_ */ diff --git a/source/6LoWPAN/ws/ws_llc.h b/source/6LoWPAN/ws/ws_llc.h new file mode 100644 index 0000000000..a1dab61bff --- /dev/null +++ b/source/6LoWPAN/ws/ws_llc.h @@ -0,0 +1,208 @@ +/* + * Copyright (c) 2018-2019, Arm Limited and affiliates. + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef WS_LLC_H_ +#define WS_LLC_H_ + +#include "6LoWPAN/ws/ws_neighbor_class.h" +#include "Service_Libs/mac_neighbor_table/mac_neighbor_table.h" + +struct protocol_interface_info_entry; +struct mcps_data_ind_s; +struct mcps_data_ie_list; +struct channel_list_s; +struct ws_pan_information_s; +struct mlme_security_s; +struct ws_hopping_schedule_s; +struct ws_neighbor_class_entry; +struct mac_neighbor_table_entry; + + +/** + * @brief wh_ie_sub_list_t ws asynch header IE elemnt request list + */ +typedef struct wh_ie_sub_list_s { + bool utt_ie: 1; /**< Unicast Timing and Frame type information */ + bool bt_ie: 1; /**< Broadcast timing information */ + bool fc_ie: 1; /**< Flow Control for Extended Direct Frame Exchange */ + bool rsl_ie: 1; /**< Received Signal Level information */ + bool vh_ie: 1; /**< Vendor header information */ + bool ea_ie: 1; /**< EAPOL autheticator EUI-64 header information */ +} wh_ie_sub_list_t; + +/** + * @brief wp_nested_ie_sub_list_t ws asynch Nested Payload sub IE element request list + */ +typedef struct wp_nested_ie_sub_list_s { + bool us_ie: 1; /**< Unicast Schedule information */ + bool bs_ie: 1; /**< Broadcast Schedule information */ + bool vp_ie: 1; /**< Vendor Payload information */ + bool pan_ie: 1; /**< PAN Information */ + bool net_name_ie: 1; /**< Network Name information */ + bool pan_version_ie: 1; /**< Pan configuration version */ + bool gtkhash_ie: 1; /**< GTK Hash information */ +} wp_nested_ie_sub_list_t; + +/** + * @brief asynch_request_t Asynch message request parameters + */ +typedef struct asynch_request_s { + unsigned message_type: 3; /**< Asynch message type: WS_FT_PAN_ADVERT, WS_FT_PAN_ADVERT_SOL, WS_FT_PAN_CONF or WS_FT_PAN_CONF_SOL. */ + wh_ie_sub_list_t wh_requested_ie_list; /**< WH-IE header list to message. */ + wp_nested_ie_sub_list_t wp_requested_nested_ie_list; /**< WP-IE Nested IE list to message. */ + struct mlme_security_s security; /**< Request MAC security paramaters */ + struct channel_list_s channel_list; /**< Channel List. */ +} asynch_request_t; + + +/** + * @brief LLC neighbour info request parameters + */ +typedef struct llc_neighbour_req { + struct mac_neighbor_table_entry *neighbor; /**< Generic Link Layer Neighbor information entry. */ + struct ws_neighbor_class_entry *ws_neighbor; /**< Wi-sun Neighbor information entry. */ +} llc_neighbour_req_t; + +/** + * @brief ws_asynch_ind ws asynch data indication + * @param interface Interface pointer + * @param data MCPS-DATA.indication specific values + * @param ie_ext Information element list + */ +typedef void ws_asynch_ind(struct protocol_interface_info_entry *interface, const struct mcps_data_ind_s *data, const struct mcps_data_ie_list *ie_ext, uint8_t message_type); + +/** + * @brief ws_asynch_confirm ws asynch data confirmation to asynch message request + * @param api The API which handled the response + * @param data MCPS-DATA.confirm specific values + * @param user_id MPX user ID + */ +typedef void ws_asynch_confirm(struct protocol_interface_info_entry *interface, uint8_t asynch_message); + +/** + * @brief ws_asynch_confirm ws asynch data confirmation to asynch message request + * @param interface The interface pointer + * @param mac_64 Neighbor 64-bit address + * @param neighbor_buffer Buffer where neighbor infor is buffered + * @param request_new true if is possible to allocate new entry + * + * @return true when neighbor info is available + * @return false when no neighbor info + */ +typedef bool ws_neighbor_info_request(struct protocol_interface_info_entry *interface, const uint8_t *mac_64, llc_neighbour_req_t *neighbor_buffer, bool request_new); + +/** + * @brief ws_llc_create ws LLC module create + * @param interface Interface pointer + * @param asynch_ind_cb Asynch indication + * @param ie_ext Information element list + * + * Function allocate and init LLC class and init it 2 supported 2 API: ws asynch and MPX user are internally registered. + */ +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); + +/** + * @brief ws_llc_reset Reset ws LLC parametrs and clean messages + * @param interface Interface pointer + * + */ +void ws_llc_reset(struct protocol_interface_info_entry *interface); + +/** + * @brief ws_llc_delete Delete LLC interface. ONLY for Test purpose. + * @param interface Interface pointer + * + */ +int8_t ws_llc_delete(struct protocol_interface_info_entry *interface); + +/** + * @brief ws_llc_mpx_api_get Get MPX api for registration purpose. + * @param interface Interface pointer + * + * @return NULL when MPX is not vailabale + * @return Pointer to MPX API + * + */ +mpx_api_t *ws_llc_mpx_api_get(struct protocol_interface_info_entry *interface); + +/** + * @brief ws_llc_asynch_request ws asynch message request to all giving channels + * @param interface Interface pointer + * @param request Asynch message parameters: type, IE and channel list + * + * @return 0 Asynch message pushed to MAC + * @return -1 memory allocate problem + * @return -2 Parameter problem + * + */ +int8_t ws_llc_asynch_request(struct protocol_interface_info_entry *interface, asynch_request_t *request); + + +/** + * @brief ws_llc_set_vendor_header_data Configure WS vendor Header data information (Data of WH_IE_VH_TYPE IE element) + * @param interface Interface pointer + * @param vendor_header pointer to vendor header this pointer must keep alive when it is configured to LLC + * @param vendor_header_length configured vendor header length + * + */ +void ws_llc_set_vendor_header_data(struct protocol_interface_info_entry *interface, uint8_t *vendor_header, uint8_t vendor_header_length); + +/** + * @brief ws_llc_set_vendor_payload_data Configure WS vendor payload data information (Data of WP_PAYLOAD_IE_VP_TYPE IE element) + * @param interface Interface pointer + * @param vendor_payload pointer to vendor payload this pointer must keep alive when it is configured to LLC + * @param vendor_payload_length configured vendor payload length + * + */ +void ws_llc_set_vendor_payload_data(struct protocol_interface_info_entry *interface, uint8_t *vendor_payload, uint8_t vendor_payload_length); + +/** + * @brief ws_llc_set_network_name Configure WS Network name (Data of WP_PAYLOAD_IE_NETNAME_TYPE IE element) + * @param interface Interface pointer + * @param name_length configured network name length + * @param name pointer to network name this pointer must keep alive when it is configured to LLC + * + */ +void ws_llc_set_network_name(struct protocol_interface_info_entry *interface, uint8_t *name, uint8_t name_length); + +/** + * @brief ws_llc_set_gtkhash Configure WS GTK hash information (Data of WP_PAYLOAD_IE_GTKHASH_TYPE IE element) + * @param interface Interface pointer + * @param gtkhash pointer to GTK hash which length is 32 bytes this pointer must keep alive when it is configured to LLC + * + */ +void ws_llc_set_gtkhash(struct protocol_interface_info_entry *interface, uint8_t *gtkhash); + +/** + * @brief ws_llc_set_pan_information_pointer Configure WS PAN information (Data of WP_PAYLOAD_IE_PAN_TYPE IE element) + * @param interface Interface pointer + * @param pan_information_pointer pointer to Pan information this pointer must keep alive when it is configured to LLC + * + */ +void ws_llc_set_pan_information_pointer(struct protocol_interface_info_entry *interface, struct ws_pan_information_s *pan_information_pointer); + +/** + * @brief ws_llc_hopping_schedule_config Configure channel hopping + * @param interface Interface pointer + * @param hopping_schedule pointer to Channel hopping schedule + * + */ +void ws_llc_hopping_schedule_config(struct protocol_interface_info_entry *interface, struct ws_hopping_schedule_s *hopping_schedule); + + + +#endif /* WS_LLC_H_ */ diff --git a/source/6LoWPAN/ws/ws_llc_data_service.c b/source/6LoWPAN/ws/ws_llc_data_service.c new file mode 100644 index 0000000000..e9e3e2eb9b --- /dev/null +++ b/source/6LoWPAN/ws/ws_llc_data_service.c @@ -0,0 +1,1067 @@ +/* + * Copyright (c) 2018-2019, Arm Limited and affiliates. + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "nsconfig.h" +#include +#include "ns_types.h" +#include "ns_list.h" +#include "ns_trace.h" +#include "nsdynmemLIB.h" +#include "mac_common_defines.h" +#include "mac_api.h" +#include "mac_mcps.h" +#include "common_functions.h" +#include "NWK_INTERFACE/Include/protocol.h" +#include "6LoWPAN/MAC/mac_helper.h" +#include "6LoWPAN/MAC/mpx_api.h" +#include "6LoWPAN/MAC/mac_ie_lib.h" +#include "6LoWPAN/ws/ws_common_defines.h" +#include "6LoWPAN/ws/ws_common.h" +#include "6LoWPAN/ws/ws_bootstrap.h" +#include "6LoWPAN/ws/ws_ie_lib.h" +#include "6LoWPAN/ws/ws_llc.h" +#include "6LoWPAN/ws/ws_mpx_header.h" +#include "6LoWPAN/ws/ws_pae_controller.h" +#include "Service_Libs/etx/etx.h" +#include "fhss_ws_extension.h" + +#ifdef HAVE_WS + +#define TRACE_GROUP "wllc" + +#define LLC_MESSAGE_QUEUE_LIST_SIZE_MAX 16 //Do not config over 30 never +#define MPX_USER_SIZE 2 + +typedef struct { + uint16_t user_id; /**< User ID for identify MPX User */ + mpx_data_confirm *data_confirm; /**< User registred MPX Data confirmation call back */ + mpx_data_indication *data_ind; /**< User registred MPX Data indication call back */ +} mpx_user_t; + + +typedef struct { + mpx_api_t mpx_api; /**< API for MPX user like Stack and EAPOL */ + mpx_user_t mpx_user_table[MPX_USER_SIZE]; /**< MPX user list include registered call back pointers and user id's */ + unsigned mpx_id: 4; /**< MPX class sequence number */ +} mpx_class_t; + + +typedef struct { + uint16_t supported_channels; /**< Configured Channel count. This will define Channel infor mask length to some information element */ + uint16_t network_name_length; /**< Network name length */ + uint16_t vendor_payload_length; /**< Vendor spesific payload length */ + uint8_t vendor_header_length; /**< Vendor spesific header length */ + uint8_t gtkhash_length; /**< GTK hash length */ + ws_pan_information_t *pan_congiguration; /**< Pan configururation */ + struct ws_hopping_schedule_s *hopping_schedule;/**< Channel hopping schedule */ + uint8_t *gtkhash; /**< Pointer to GTK HASH user must give pointer which include 4 64-bit HASH array */ + uint8_t *network_name; /**< Network name */ + uint8_t *vendor_header_data; /**< Vendor spesific header data */ + uint8_t *vendor_payload; /**< Vendor spesific payload data */ +} llc_ie_params_t; + +typedef struct { + uint8_t dst_address[8]; /**< Destination address */ + unsigned messsage_type: 3; /**< Frame type to UTT */ + unsigned mpx_id: 5; /**< MPX sequence */ + bool ack_requested: 1; /**< ACK requested */ + unsigned dst_address_type: 2; /**< Destination address type */ + uint8_t msg_handle; /**< LLC genetaed unique MAC handle */ + uint8_t mpx_user_handle; /**< This MPX user defined handle */ + ns_ie_iovec_t ie_vector_list[3]; /**< IE vectors: 1 for Header's, 1 for Payload and for MPX payload */ + mcps_data_req_ie_list_t ie_ext; + ns_list_link_t link; /**< List link entry */ + uint8_t ie_buffer[]; /**< Trailing buffer data */ +} llc_message_t; + +/** get pointer to Mac header start point*/ +#define ws_message_buffer_ptr_get(x) (&(x)->ie_buffer[0]) + +typedef NS_LIST_HEAD(llc_message_t, link) llc_message_list_t; + +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 */ + 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 */ + 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]; + ns_ie_iovec_t ws_header_vector; + protocol_interface_info_entry_t *interface_ptr; /**< List link entry */ + ns_list_link_t link; /**< List link entry */ +} llc_data_base_t; + +static NS_LIST_DEFINE(llc_data_base_list, llc_data_base_t, link); + +static uint16_t ws_wp_nested_message_length(wp_nested_ie_sub_list_t requested_list, llc_ie_params_t *params); +static uint16_t ws_wh_headers_length(wh_ie_sub_list_t requested_list, llc_ie_params_t *params); + +/** LLC message local functions */ +static llc_message_t *llc_message_discover_by_mac_handle(uint8_t handle, llc_message_list_t *list); +static llc_message_t *llc_message_discover_by_mpx_id(uint8_t handle, llc_message_list_t *list); +static llc_message_t *llc_message_discover_mpx_user_id(uint8_t handle, uint16_t user_id, llc_message_list_t *list); +static void llc_message_free(llc_message_t *message, llc_data_base_t *llc_base); +static llc_message_t *llc_message_allocate(uint16_t ie_buffer_size, llc_data_base_t *llc_base, bool mpx_user); + +/** LLC interface sepesific local functions */ +static llc_data_base_t *ws_llc_discover_by_interface(struct protocol_interface_info_entry *interface); +static llc_data_base_t *ws_llc_discover_by_mac(const mac_api_t *api); +static llc_data_base_t *ws_llc_discover_by_mpx(const mpx_api_t *api); + +static mpx_user_t *ws_llc_mpx_user_discover(mpx_class_t *mpx_class, uint16_t user_id); +static llc_data_base_t *ws_llc_base_allocate(void); +static void ws_llc_mac_confirm_cb(const mac_api_t *api, const mcps_data_conf_t *data, const mcps_data_conf_payload_t *conf_data); +static void ws_llc_mac_indication_cb(const mac_api_t *api, const mcps_data_ind_t *data, const mcps_data_ie_list_t *ie_ext); +static uint16_t ws_mpx_header_size_get(llc_data_base_t *base, uint16_t user_id); +static void ws_llc_mpx_data_request(const mpx_api_t *api, const struct mcps_data_req_s *data, uint16_t user_id); +static int8_t ws_llc_mpx_data_cb_register(const mpx_api_t *api, mpx_data_confirm *confirm_cb, mpx_data_indication *indication_cb, uint16_t user_id); +static uint16_t ws_llc_mpx_header_size_get(const mpx_api_t *api, uint16_t user_id); +static uint8_t ws_llc_mpx_data_purge_request(const mpx_api_t *api, struct mcps_purge_s *purge, uint16_t user_id); +static void ws_llc_mpx_init(mpx_class_t *mpx_class); + +/** Discover Message by message handle id */ +static llc_message_t *llc_message_discover_by_mac_handle(uint8_t handle, llc_message_list_t *list) +{ + ns_list_foreach(llc_message_t, message, list) { + if (message->msg_handle == handle) { + return message; + } + } + return NULL; +} + +static llc_message_t *llc_message_discover_by_mpx_id(uint8_t handle, llc_message_list_t *list) +{ + ns_list_foreach(llc_message_t, message, list) { + if ((message->messsage_type == WS_FT_DATA || message->messsage_type == WS_FT_EAPOL) && message->mpx_id == handle) { + return message; + } + } + return NULL; +} + + +static llc_message_t *llc_message_discover_mpx_user_id(uint8_t handle, uint16_t user_id, llc_message_list_t *list) +{ + uint8_t message_type; + if (user_id == MPX_LOWPAN_ENC_USER_ID) { + message_type = WS_FT_DATA; + } else { + message_type = WS_FT_EAPOL; + } + + ns_list_foreach(llc_message_t, message, list) { + if (message->messsage_type == message_type && message->mpx_user_handle == handle) { + return message; + } + } + return NULL; +} + + + + +//Free message and delete from list +static void llc_message_free(llc_message_t *message, llc_data_base_t *llc_base) +{ + ns_list_remove(&llc_base->llc_message_list, message); + ns_dyn_mem_free(message); + llc_base->llc_message_list_size--; +} + +static llc_message_t *llc_message_allocate(uint16_t ie_buffer_size, llc_data_base_t *llc_base, bool mpx_user) +{ + if (llc_base->llc_message_list_size >= LLC_MESSAGE_QUEUE_LIST_SIZE_MAX) { + return NULL; + } + + llc_message_t *message = ns_dyn_mem_temporary_alloc(sizeof(llc_message_t) + ie_buffer_size); + if (!message) { + return NULL; + } + message->ack_requested = false; + + //Guarantee + while (1) { + if (llc_message_discover_by_mac_handle(llc_base->mac_handle_base, &llc_base->llc_message_list)) { + llc_base->mac_handle_base++; + } else { + break; + } + } + if (mpx_user) { + while (1) { + if (llc_message_discover_by_mpx_id(llc_base->mpx_data_base.mpx_id, &llc_base->llc_message_list)) { + llc_base->mpx_data_base.mpx_id++; + } else { + break; + } + } + } + + //Storage handle and update base + message->msg_handle = llc_base->mac_handle_base++; + if (mpx_user) { + message->mpx_id = llc_base->mpx_data_base.mpx_id++; + } + llc_base->llc_message_list_size++; + ns_list_add_to_end(&llc_base->llc_message_list, message); + return message; +} + +static llc_data_base_t *ws_llc_discover_by_interface(struct protocol_interface_info_entry *interface) +{ + ns_list_foreach(llc_data_base_t, base, &llc_data_base_list) { + if (base->interface_ptr == interface) { + return base; + } + } + return NULL; +} + +static llc_data_base_t *ws_llc_discover_by_mac(const mac_api_t *api) +{ + ns_list_foreach(llc_data_base_t, base, &llc_data_base_list) { + if (base->interface_ptr->mac_api == api) { + return base; + } + } + return NULL; +} + +static llc_data_base_t *ws_llc_discover_by_mpx(const mpx_api_t *api) +{ + ns_list_foreach(llc_data_base_t, base, &llc_data_base_list) { + if (&base->mpx_data_base.mpx_api == api) { + return base; + } + } + return NULL; +} + +static uint16_t ws_wh_headers_length(wh_ie_sub_list_t requested_list, llc_ie_params_t *params) +{ + uint16_t length = 0; + if (requested_list.utt_ie) { + //Static 4 bytes allways UTT + length += WH_IE_ELEMENT_HEADER_LENGTH + 4; + } + + if (requested_list.bt_ie) { + //Static 5 bytes allways + length += WH_IE_ELEMENT_HEADER_LENGTH + 5; + } + + if (requested_list.fc_ie) { + //Static 1 bytes allways + length += WH_IE_ELEMENT_HEADER_LENGTH + 1; + } + + if (requested_list.rsl_ie) { + //Static 1 bytes allways + length += WH_IE_ELEMENT_HEADER_LENGTH + 1; + } + + if (requested_list.vh_ie) { + //Dynamic length + length += WH_IE_ELEMENT_HEADER_LENGTH + params->vendor_header_length; + } + + if (requested_list.ea_ie) { + length += WH_IE_ELEMENT_HEADER_LENGTH + 8; + } + + return length; +} + +static uint16_t ws_wp_nested_message_length(wp_nested_ie_sub_list_t requested_list, llc_ie_params_t *params) +{ + uint16_t length = 0; + if (requested_list.gtkhash_ie) { + //Static 32 bytes allways + length += WS_WP_SUB_IE_ELEMENT_HEADER_LENGTH + params->gtkhash_length; + } + + if (requested_list.net_name_ie) { + //Dynamic length + length += WS_WP_SUB_IE_ELEMENT_HEADER_LENGTH + params->network_name_length; + } + + if (requested_list.vp_ie && params->vendor_payload_length) { + //Dynamic length + length += WS_WP_SUB_IE_ELEMENT_HEADER_LENGTH + params->vendor_payload_length; + } + + if (requested_list.pan_ie) { + //Static 5 bytes allways + length += WS_WP_SUB_IE_ELEMENT_HEADER_LENGTH; + if (params->pan_congiguration) { + length += 5; + } + } + + if (requested_list.pan_version_ie) { + //Static 2 bytes allways + length += WS_WP_SUB_IE_ELEMENT_HEADER_LENGTH; + if (params->pan_congiguration) { + length += 2; + } + } + + if (requested_list.bs_ie) { + ///Dynamic length + length += WS_WP_SUB_IE_ELEMENT_HEADER_LENGTH + ws_wp_nested_hopping_schedule_length(params->hopping_schedule, false); + } + + if (requested_list.us_ie) { + //Dynamic length + length += WS_WP_SUB_IE_ELEMENT_HEADER_LENGTH + ws_wp_nested_hopping_schedule_length(params->hopping_schedule, true); + } + + return length; +} + +static mpx_user_t *ws_llc_mpx_user_discover(mpx_class_t *mpx_class, uint16_t user_id) +{ + for (int i = 0; i < MPX_USER_SIZE; i++) { + if (mpx_class->mpx_user_table[i].user_id == user_id) { + return &mpx_class->mpx_user_table[i]; + } + } + return NULL; +} + +static llc_data_base_t *ws_llc_base_allocate(void) +{ + llc_data_base_t *base = ns_dyn_mem_temporary_alloc(sizeof(llc_data_base_t)); + if (!base) { + return NULL; + } + memset(base, 0, sizeof(llc_data_base_t)); + + + ns_list_init(&base->llc_message_list); + ns_list_add_to_end(&llc_data_base_list, base); + return base; +} + +/** WS LLC MAC data extension confirmation */ +static void ws_llc_mac_confirm_cb(const mac_api_t *api, const mcps_data_conf_t *data, const mcps_data_conf_payload_t *conf_data) +{ + (void) conf_data; + llc_data_base_t *base = ws_llc_discover_by_mac(api); + if (!base) { + return; + } + + 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; + } + + uint8_t messsage_type = message->messsage_type; + uint8_t mpx_user_handle = message->mpx_user_handle; + //ETX update + if (message->ack_requested && messsage_type == WS_FT_DATA) { + llc_neighbour_req_t neighbor_info; + bool success = false; + + switch (data->status) { + case MLME_SUCCESS: + case MLME_TX_NO_ACK: + case MLME_NO_DATA: + if (data->status == MLME_SUCCESS || data->status == MLME_NO_DATA) { + success = true; + } + + if (message->dst_address_type == MAC_ADDR_MODE_64_BIT && base->ws_neighbor_info_request_cb(interface, message->dst_address, &neighbor_info, false)) { + etx_transm_attempts_update(interface->id, 1 + data->tx_retries, success, neighbor_info.neighbor->index); + //TODO discover RSL from Enchanced ACK Header IE elements + ws_utt_ie_t ws_utt; + if (ws_wh_utt_read(conf_data->headerIeList, conf_data->headerIeListLength, &ws_utt)) { + //UTT header + if (success) { + neighbor_info.neighbor->lifetime = neighbor_info.neighbor->link_lifetime; + } + + ws_neighbor_class_neighbor_unicast_time_info_update(neighbor_info.ws_neighbor, &ws_utt, data->timestamp); + } + + int8_t rsl; + if (ws_wh_rsl_read(conf_data->headerIeList, conf_data->headerIeListLength, &rsl)) { + ws_neighbor_class_rsl_out_calculate(neighbor_info.ws_neighbor, rsl); + } + } + + break; + default: + break; + } + } + //Free message + llc_message_free(message, base); + + if (messsage_type == WS_FT_DATA || messsage_type == WS_FT_EAPOL) { + mpx_user_t *user_cb; + uint16_t mpx_user_id; + if (messsage_type == WS_FT_DATA) { + mpx_user_id = MPX_LOWPAN_ENC_USER_ID; + } else { + mpx_user_id = MPX_KEY_MANAGEMENT_ENC_USER_ID; + } + + user_cb = ws_llc_mpx_user_discover(&base->mpx_data_base, mpx_user_id); + if (user_cb && user_cb->data_confirm) { + //Call MPX registered call back + mcps_data_conf_t data_conf = *data; + data_conf.msduHandle = mpx_user_handle; + user_cb->data_confirm(&base->mpx_data_base.mpx_api, &data_conf); + } + return; + } + //Async message Confirmation + base->asynch_confirm(base->interface_ptr, messsage_type); + +} + +static void ws_llc_ack_data_req_ext(const mac_api_t *api, mcps_ack_data_payload_t *data, int8_t rssi, uint8_t lqi) +{ + (void) lqi; + llc_data_base_t *base = ws_llc_discover_by_mac(api); + if (!base) { + return; + } + /* Init all by zero */ + 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); + data->ie_elements.headerIovLength = 1; + + //Write Data to block + uint8_t *ptr = base->ws_enhanced_ack_elements; + ptr = ws_wh_utt_write(ptr, WS_FT_ACK); + uint8_t rsl = ws_neighbor_class_rssi_from_dbm_calculate(rssi); + ws_wh_rsl_write(ptr, rsl); +} + +/** WS LLC MAC data extension indication */ +static void ws_llc_mac_indication_cb(const mac_api_t *api, const mcps_data_ind_t *data, const mcps_data_ie_list_t *ie_ext) +{ + llc_data_base_t *base = ws_llc_discover_by_mac(api); + if (!base) { + return; + } + + //Discover Header WH_IE_UTT_TYPE + ws_utt_ie_t ws_utt; + if (!ws_wh_utt_read(ie_ext->headerIeList, ie_ext->headerIeListLength, &ws_utt)) { + // NO UTT header + return; + } + + protocol_interface_info_entry_t *interface = base->interface_ptr; + if (!base->ie_params.gtkhash && ws_utt.message_type == WS_FT_DATA) { + return; + } + + //Discover 2 Payload Heder + if (ws_utt.message_type == WS_FT_DATA || ws_utt.message_type == WS_FT_EAPOL) { + + if (data->SrcAddrMode != ADDR_802_15_4_LONG) { + return; + } + + mac_payload_IE_t mpx_ie; + mpx_ie.id = MAC_PAYLOAD_MPX_IE_GROUP_ID; + if (mac_ie_payload_discover(ie_ext->payloadIeList, ie_ext->payloadIeListLength, &mpx_ie) < 1) { + // NO MPX + return; + } + //Validate MPX header + mpx_msg_t mpx_frame; + if (!ws_llc_mpx_header_frame_parse(mpx_ie.content_ptr, mpx_ie.length, &mpx_frame)) { + return; + } + + if (mpx_frame.transfer_type != MPX_FT_FULL_FRAME) { + return; //Support only FULL Frame's + } + + mac_payload_IE_t ws_wp_nested; + ws_us_ie_t us_ie; + bool us_ie_inline = false; + ws_wp_nested.id = WS_WP_NESTED_IE; + if (mac_ie_payload_discover(ie_ext->payloadIeList, ie_ext->payloadIeListLength, &ws_wp_nested) > 2) { + us_ie_inline = ws_wp_nested_us_read(ws_wp_nested.content_ptr, ws_wp_nested.length, &us_ie); + } + + llc_neighbour_req_t neighbor_info; + + if (!base->ws_neighbor_info_request_cb(interface, data->SrcAddr, &neighbor_info, us_ie_inline)) { + tr_debug("Drop message no neighbor"); + 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); + } + + if (ws_utt.message_type == WS_FT_EAPOL) { + uint8_t auth_eui64[8]; + //Discover and write Auhtenticator EUI-64 + if (ws_wh_ea_read(ie_ext->headerIeList, ie_ext->headerIeListLength, auth_eui64)) { + ws_pae_controller_border_router_addr_write(base->interface_ptr, auth_eui64); + } + } + + //Update BT if it is part of message + ws_bt_ie_t ws_bt; + if (ws_wh_bt_read(ie_ext->headerIeList, ie_ext->headerIeListLength, &ws_bt)) { + ws_neighbor_class_neighbor_broadcast_time_info_update(neighbor_info.ws_neighbor, &ws_bt, data->timestamp); + if (neighbor_info.neighbor->link_role == PRIORITY_PARENT_NEIGHBOUR) { + // We have broadcast schedule set up set the broadcast parent schedule + ns_fhss_ws_set_parent(interface->ws_info->fhss_api, neighbor_info.neighbor->mac64, &neighbor_info.ws_neighbor->fhss_data.bc_timing_info, false); + } + } + + //Refresh Neighbor if unicast + if (ws_utt.message_type == WS_FT_DATA && data->DstAddrMode == ADDR_802_15_4_LONG) { + neighbor_info.neighbor->lifetime = neighbor_info.neighbor->link_lifetime; + etx_lqi_dbm_update(interface->id, data->mpduLinkQuality, data->signal_dbm, neighbor_info.neighbor->index); + } + if (ws_utt.message_type == WS_FT_DATA) { + // Calculate RSL for all UDATA packages heard + ws_neighbor_class_rsl_in_calculate(neighbor_info.ws_neighbor, data->signal_dbm); + + if (data->Key.SecurityLevel) { + //SET trusted state + mac_neighbor_table_trusted_neighbor(mac_neighbor_info(interface), neighbor_info.neighbor, true); + } + } + + // Discover MPX + mpx_user_t *user_cb = ws_llc_mpx_user_discover(&base->mpx_data_base, mpx_frame.multiplex_id); + if (user_cb && user_cb->data_ind) { + mcps_data_ind_t data_ind = *data; + data_ind.msdu_ptr = mpx_frame.frame_ptr; + data_ind.msduLength = mpx_frame.frame_length; + user_cb->data_ind(&base->mpx_data_base.mpx_api, &data_ind); + } + return; + } + + //Asynch Message + if (ws_utt.message_type < WS_FT_DATA && base->asynch_ind) { + mac_payload_IE_t ws_wp_nested; + + ws_wp_nested.id = WS_WP_NESTED_IE; + if (mac_ie_payload_discover(ie_ext->payloadIeList, ie_ext->payloadIeListLength, &ws_wp_nested) < 2) { + // NO WS_WP_NESTED_IE Payload + return; + } + + mcps_data_ie_list_t asynch_ie_list; + asynch_ie_list.headerIeList = ie_ext->headerIeList, + asynch_ie_list.headerIeListLength = ie_ext->headerIeListLength; + asynch_ie_list.payloadIeList = ws_wp_nested.content_ptr; + asynch_ie_list.payloadIeListLength = ws_wp_nested.length; + base->asynch_ind(interface, data, &asynch_ie_list, ws_utt.message_type); + } + +} + +static uint16_t ws_mpx_header_size_get(llc_data_base_t *base, uint16_t user_id) +{ + //TODO add WS_WP_NESTED_IE support + uint16_t header_size = 0; + if (user_id == MPX_LOWPAN_ENC_USER_ID) { + header_size += 7 + 8 + 5 + 2; //UTT+BTT+ MPX + Padding + if (base->ie_params.vendor_header_length) { + header_size += base->ie_params.vendor_header_length + 3; + } + + if (base->ie_params.vendor_payload_length) { + header_size += base->ie_params.vendor_payload_length + 2; + } + + //Dynamic length + header_size += 2 + WS_WP_SUB_IE_ELEMENT_HEADER_LENGTH + ws_wp_nested_hopping_schedule_length(base->ie_params.hopping_schedule, true); + + } else if (MPX_KEY_MANAGEMENT_ENC_USER_ID) { + header_size += 7 + 5 + 2; + //Dynamic length + header_size += 2 + WS_WP_SUB_IE_ELEMENT_HEADER_LENGTH + ws_wp_nested_hopping_schedule_length(base->ie_params.hopping_schedule, true); + } + return header_size; +} + +static void ws_llc_mpx_data_request(const mpx_api_t *api, const struct mcps_data_req_s *data, uint16_t user_id) +{ + llc_data_base_t *base = ws_llc_discover_by_mpx(api); + if (!base) { + return; + } + + mpx_user_t *user_cb = ws_llc_mpx_user_discover(&base->mpx_data_base, user_id); + if (!user_cb || !user_cb->data_confirm || !user_cb->data_ind) { + return; + } + + wh_ie_sub_list_t ie_header_mask; + memset(&ie_header_mask, 0, sizeof(wh_ie_sub_list_t)); + + wp_nested_ie_sub_list_t nested_wp_id; + memset(&nested_wp_id, 0, sizeof(wp_nested_ie_sub_list_t)); + ie_header_mask.utt_ie = true; + + if (user_id == MPX_LOWPAN_ENC_USER_ID) { + ie_header_mask.bt_ie = true; + if (base->ie_params.vendor_header_length) { + ie_header_mask.vh_ie = true; + } + + if (base->ie_params.vendor_payload_length) { + nested_wp_id.vp_ie = true; + } + } else if (user_id == MPX_KEY_MANAGEMENT_ENC_USER_ID) { + + if (*data->msdu == 1) { //Only when KMP_ID is 1 + ie_header_mask.ea_ie = ws_eapol_relay_state_active(base->interface_ptr); + ie_header_mask.bt_ie = ie_header_mask.ea_ie; + } + + } + + nested_wp_id.us_ie = true; + + uint16_t ie_header_length = ws_wh_headers_length(ie_header_mask, &base->ie_params); + uint16_t nested_ie_length = ws_wp_nested_message_length(nested_wp_id, &base->ie_params); + + uint16_t over_head_size = ie_header_length; + if (nested_ie_length) { + over_head_size += nested_ie_length + 2; + } + //Mpx header size + over_head_size += 5; //MPX FuLL frame 3 bytes + IE header 2 bytes + + //Allocate Message + llc_message_t *message = llc_message_allocate(over_head_size, base, true); + if (!message) { + mcps_data_conf_t data_conf; + memset(&data_conf, 0, sizeof(mcps_data_conf_t)); + data_conf.msduHandle = data->msduHandle; + data_conf.status = MLME_TRANSACTION_OVERFLOW; + user_cb->data_confirm(&base->mpx_data_base.mpx_api, &data_conf); + return; + } + mcps_data_req_t data_req; + message->mpx_user_handle = data->msduHandle; + message->ack_requested = data->TxAckReq; + if (data->TxAckReq) { + message->dst_address_type = data->DstAddrMode; + memcpy(message->dst_address, data->DstAddr, 8); + } + data_req = *data; + data_req.msdu = NULL; + 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 { + data_req.PanIdSuppressed = true; + } + + uint8_t *ptr = ws_message_buffer_ptr_get(message); + if (user_id == MPX_LOWPAN_ENC_USER_ID) { + message->messsage_type = WS_FT_DATA; + } else { + message->messsage_type = WS_FT_EAPOL; + } + + message->ie_vector_list[0].ieBase = ptr; + //Write UTT + + ptr = ws_wh_utt_write(ptr, message->messsage_type); + if (ie_header_mask.bt_ie) { + ptr = ws_wh_bt_write(ptr); + } + + if (user_id == MPX_LOWPAN_ENC_USER_ID) { + if (ie_header_mask.vh_ie) { + ptr = ws_wh_vh_write(ptr, base->ie_params.vendor_header_data, base->ie_params.vendor_header_length); + } + } else if (user_id == MPX_KEY_MANAGEMENT_ENC_USER_ID) { + if (ie_header_mask.ea_ie) { + uint8_t eapol_auth_eui64[8]; + ws_pae_controller_border_router_addr_read(base->interface_ptr, eapol_auth_eui64); + ptr = ws_wh_ea_write(ptr, eapol_auth_eui64); + } + } + + + + message->ie_vector_list[0].iovLen = ie_header_length; + message->ie_ext.headerIeVectorList = &message->ie_vector_list[0]; + message->ie_ext.headerIovLength = 1; + message->ie_ext.payloadIeVectorList = &message->ie_vector_list[1]; + message->ie_ext.payloadIovLength = 2; + message->ie_vector_list[1].ieBase = ptr; + + if (nested_ie_length) { + ptr = ws_wp_base_write(ptr, nested_ie_length); + //Write unicast schedule + ptr = ws_wp_nested_hopping_schedule_write(ptr, base->ie_params.hopping_schedule, true); + } + + + ptr = mac_ie_payload_base_write(ptr, MAC_PAYLOAD_MPX_IE_GROUP_ID, data->msduLength + 3); + mpx_msg_t mpx_header; + mpx_header.transfer_type = MPX_FT_FULL_FRAME; + mpx_header.transaction_id = message->mpx_id; + mpx_header.multiplex_id = user_id; + ptr = ws_llc_mpx_header_write(ptr, &mpx_header); + message->ie_vector_list[1].iovLen = ptr - (uint8_t *)message->ie_vector_list[1].ieBase; + message->ie_vector_list[2].ieBase = data->msdu; + message->ie_vector_list[2].iovLen = data->msduLength; + base->interface_ptr->mac_api->mcps_data_req_ext(base->interface_ptr->mac_api, &data_req, &message->ie_ext, NULL); + +} + + +static int8_t ws_llc_mpx_data_cb_register(const mpx_api_t *api, mpx_data_confirm *confirm_cb, mpx_data_indication *indication_cb, uint16_t user_id) +{ + llc_data_base_t *base = ws_llc_discover_by_mpx(api); + if (!base) { + return -1; + } + + mpx_user_t *user_cb = ws_llc_mpx_user_discover(&base->mpx_data_base, user_id); + if (!user_cb) { + return -1; + } + user_cb->data_confirm = confirm_cb; + user_cb->data_ind = indication_cb; + return 0; +} + +static uint16_t ws_llc_mpx_header_size_get(const mpx_api_t *api, uint16_t user_id) +{ + llc_data_base_t *base = ws_llc_discover_by_mpx(api); + if (!base) { + return 0; + } + + return ws_mpx_header_size_get(base, user_id); +} + +static uint8_t ws_llc_mpx_data_purge_request(const mpx_api_t *api, struct mcps_purge_s *purge, uint16_t user_id) +{ + llc_data_base_t *base = ws_llc_discover_by_mpx(api); + if (!base) { + return MLME_INVALID_HANDLE; + } + llc_message_t *message = llc_message_discover_mpx_user_id(purge->msduHandle, user_id, &base->llc_message_list); + if (!message) { + return MLME_INVALID_HANDLE; + } + + mcps_purge_t purge_req; + uint8_t purge_status; + purge_req.msduHandle = message->msg_handle; + purge_status = base->interface_ptr->mac_api->mcps_purge_req(base->interface_ptr->mac_api, &purge_req); + if (purge_status == 0) { + llc_message_free(message, base); + } + + return purge_status; +} + +static void ws_llc_mpx_init(mpx_class_t *mpx_class) +{ + //Init Mbed Class and API + mpx_class->mpx_user_table[0].user_id = MPX_LOWPAN_ENC_USER_ID; + mpx_class->mpx_user_table[1].user_id = MPX_KEY_MANAGEMENT_ENC_USER_ID; + mpx_class->mpx_api.mpx_headroom_size_get = &ws_llc_mpx_header_size_get; + mpx_class->mpx_api.mpx_user_registration = &ws_llc_mpx_data_cb_register; + mpx_class->mpx_api.mpx_data_request = &ws_llc_mpx_data_request; + mpx_class->mpx_api.mpx_data_purge = &ws_llc_mpx_data_purge_request; +} + +static void ws_llc_clean(llc_data_base_t *base) +{ + //Clean Message queue's + mcps_purge_t purge_req; + ns_list_foreach_safe(llc_message_t, message, &base->llc_message_list) { + purge_req.msduHandle = message->msg_handle; + llc_message_free(message, base); + base->interface_ptr->mac_api->mcps_purge_req(base->interface_ptr->mac_api, &purge_req); + + } + memset(&base->ie_params, 0, sizeof(llc_ie_params_t)); +} + + +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); + if (base) { + ws_llc_clean(base); + return 0; + } + + //Allocate Data base + base = ws_llc_base_allocate(); + if (!base) { + return -2; + } + + base->interface_ptr = interface; + base->asynch_ind = asynch_ind_cb; + base->asynch_confirm = asynch_cnf_cb; + 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); + //Init MPX class + ws_llc_mpx_init(&base->mpx_data_base); + return 0; +} + +int8_t ws_llc_delete(struct protocol_interface_info_entry *interface) +{ + llc_data_base_t *base = ws_llc_discover_by_interface(interface); + if (!base) { + return -1; + } + + ws_llc_clean(base); + + ns_list_remove(&llc_data_base_list, base); + //Disable Mac extension + base->interface_ptr->mac_api->mac_mcps_extension_enable(base->interface_ptr->mac_api, NULL, NULL, NULL); + ns_dyn_mem_free(base); + return 0; +} + + + +void ws_llc_reset(struct protocol_interface_info_entry *interface) +{ + llc_data_base_t *base = ws_llc_discover_by_interface(interface); + if (!base) { + return; + } + ws_llc_clean(base); +} + +mpx_api_t *ws_llc_mpx_api_get(struct protocol_interface_info_entry *interface) +{ + llc_data_base_t *base = ws_llc_discover_by_interface(interface); + if (!base) { + return NULL; + } + return &base->mpx_data_base.mpx_api; +} + +int8_t ws_llc_asynch_request(struct protocol_interface_info_entry *interface, asynch_request_t *request) +{ + llc_data_base_t *base = ws_llc_discover_by_interface(interface); + if (!base) { + return -1; + } + + //Calculate IE Buffer size + request->wh_requested_ie_list.fc_ie = false; //Never should not be a part Asynch message + request->wh_requested_ie_list.rsl_ie = false; //Never should not be a part Asynch message + request->wh_requested_ie_list.vh_ie = false; + uint16_t header_buffer_length = ws_wh_headers_length(request->wh_requested_ie_list, &base->ie_params); + uint16_t wp_nested_payload_length = ws_wp_nested_message_length(request->wp_requested_nested_ie_list, &base->ie_params); + + //Allocated + uint16_t total_length = header_buffer_length; + if (wp_nested_payload_length) { + total_length += 2 + wp_nested_payload_length; + } + //Allocate LLC message pointer + + llc_message_t *message = llc_message_allocate(total_length, base, false); + if (!message) { + if (base->asynch_confirm) { + base->asynch_confirm(interface, request->message_type); + } + return 0; + } + message->messsage_type = request->message_type; + + mcps_data_req_t data_req; + memset(&data_req, 0, sizeof(mcps_data_req_t)); + data_req.SeqNumSuppressed = true; + data_req.SrcAddrMode = MAC_ADDR_MODE_64_BIT; + data_req.Key = request->security; + data_req.msduHandle = message->msg_handle; + if (request->message_type == WS_FT_PAN_ADVERT_SOL) { + // PANID not know yet must be supressed + data_req.PanIdSuppressed = true; + } + + uint8_t *ptr = ws_message_buffer_ptr_get(message); + + message->ie_vector_list[0].ieBase = ptr; + message->ie_vector_list[0].iovLen = header_buffer_length; + + message->ie_ext.headerIeVectorList = &message->ie_vector_list[0]; + message->ie_ext.headerIovLength = 1; + + + //Write UTT + if (request->wh_requested_ie_list.utt_ie) { + ptr = ws_wh_utt_write(ptr, message->messsage_type); + } + + if (request->wh_requested_ie_list.bt_ie) { + //Static 5 bytes allways + ptr = ws_wh_bt_write(ptr); + } + + if (wp_nested_payload_length) { + message->ie_vector_list[1].ieBase = ptr; + message->ie_vector_list[1].iovLen = 2 + wp_nested_payload_length; + message->ie_ext.payloadIeVectorList = &message->ie_vector_list[1]; + message->ie_ext.payloadIovLength = 1; + ptr = ws_wp_base_write(ptr, wp_nested_payload_length); + + if (request->wp_requested_nested_ie_list.us_ie) { + //Write unicast schedule + ptr = ws_wp_nested_hopping_schedule_write(ptr, base->ie_params.hopping_schedule, true); + } + + if (request->wp_requested_nested_ie_list.bs_ie) { + //Write Broadcastcast schedule + ptr = ws_wp_nested_hopping_schedule_write(ptr, base->ie_params.hopping_schedule, false); + } + + if (request->wp_requested_nested_ie_list.pan_ie) { + //Write Pan information + ptr = ws_wp_nested_pan_info_write(ptr, base->ie_params.pan_congiguration); + } + + if (request->wp_requested_nested_ie_list.net_name_ie) { + //Write network name + ptr = ws_wp_nested_netname_write(ptr, base->ie_params.network_name, base->ie_params.network_name_length); + } + + if (request->wp_requested_nested_ie_list.pan_version_ie) { + //Write pan version + ptr = ws_wp_nested_pan_ver_write(ptr, base->ie_params.pan_congiguration); + } + + if (request->wp_requested_nested_ie_list.gtkhash_ie) { + //Write GTKHASH + ptr = ws_wp_nested_gtkhash_write(ptr, base->ie_params.gtkhash, base->ie_params.gtkhash_length); + } + + if (request->wp_requested_nested_ie_list.vp_ie) { + //Write Vendor spesific payload + ptr = ws_wp_nested_vp_write(ptr, base->ie_params.vendor_payload, base->ie_params.vendor_payload_length); + } + } + + base->interface_ptr->mac_api->mcps_data_req_ext(base->interface_ptr->mac_api, &data_req, &message->ie_ext, &request->channel_list); + + return 0; +} + + +void ws_llc_set_vendor_header_data(struct protocol_interface_info_entry *interface, uint8_t *vendor_header, uint8_t vendor_header_length) +{ + llc_data_base_t *base = ws_llc_discover_by_interface(interface); + if (!base) { + return; + } + base->ie_params.vendor_header_data = vendor_header; + base->ie_params.vendor_header_length = vendor_header_length; +} + + +void ws_llc_set_vendor_payload_data(struct protocol_interface_info_entry *interface, uint8_t *vendor_payload, uint8_t vendor_payload_length) +{ + llc_data_base_t *base = ws_llc_discover_by_interface(interface); + if (!base) { + return; + } + + base->ie_params.vendor_payload = vendor_payload; + base->ie_params.vendor_payload_length = vendor_payload_length; +} + + +void ws_llc_set_network_name(struct protocol_interface_info_entry *interface, uint8_t *name, uint8_t name_length) +{ + llc_data_base_t *base = ws_llc_discover_by_interface(interface); + if (!base) { + return; + } + + base->ie_params.network_name = name; + base->ie_params.network_name_length = name_length; +} + +void ws_llc_set_gtkhash(struct protocol_interface_info_entry *interface, uint8_t *gtkhash) +{ + llc_data_base_t *base = ws_llc_discover_by_interface(interface); + if (!base) { + return; + } + + base->ie_params.gtkhash = gtkhash; + if (base->ie_params.gtkhash) { + base->ie_params.gtkhash_length = 32; + } else { + base->ie_params.gtkhash_length = 0; + } +} + + + +void ws_llc_set_pan_information_pointer(struct protocol_interface_info_entry *interface, struct ws_pan_information_s *pan_information_pointer) +{ + llc_data_base_t *base = ws_llc_discover_by_interface(interface); + if (!base) { + return; + } + + base->ie_params.pan_congiguration = pan_information_pointer; +} + +void ws_llc_hopping_schedule_config(struct protocol_interface_info_entry *interface, struct ws_hopping_schedule_s *hopping_schedule) +{ + llc_data_base_t *base = ws_llc_discover_by_interface(interface); + if (!base) { + return; + } + base->ie_params.hopping_schedule = hopping_schedule; +} +#endif diff --git a/source/6LoWPAN/ws/ws_management_api.c b/source/6LoWPAN/ws/ws_management_api.c new file mode 100644 index 0000000000..e733080d8d --- /dev/null +++ b/source/6LoWPAN/ws/ws_management_api.c @@ -0,0 +1,262 @@ +/* + * Copyright (c) 2018-2019, 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 +#include "nsconfig.h" +#include "ns_types.h" +#include "ns_trace.h" +#include +#include +#include "NWK_INTERFACE/Include/protocol.h" +#include "6LoWPAN/ws/ws_common.h" +#include "6LoWPAN/ws/ws_bootstrap.h" + +#include "ws_management_api.h" + +#define TRACE_GROUP "wsmg" + +#ifdef HAVE_WS + +int ws_management_node_init( + int8_t interface_id, + uint8_t regulatory_domain, + char *network_name_ptr, + fhss_timer_t *fhss_timer_ptr) +{ + protocol_interface_info_entry_t *cur; + + cur = protocol_stack_interface_info_get_by_id(interface_id); + if (!cur || !ws_info(cur)) { + return -1; + } + if (!network_name_ptr || !fhss_timer_ptr) { + return -2; + } + cur->ws_info->hopping_schdule.regulatory_domain = regulatory_domain; + if (ws_common_regulatory_domain_config(cur) < 0) { + // Invalid regulatory domain set + return -3; + } + strncpy(cur->ws_info->network_name, network_name_ptr, 32); + cur->ws_info->fhss_timer_ptr = fhss_timer_ptr; + return 0; +} + +int ws_management_regulatory_domain_set( + int8_t interface_id, + uint8_t regulatory_domain, + uint8_t operating_class, + uint8_t operating_mode) +{ + uint8_t regulatory_domain_saved; + uint8_t operating_class_saved; + uint8_t operating_mode_saved; + protocol_interface_info_entry_t *cur; + + cur = protocol_stack_interface_info_get_by_id(interface_id); + if (!cur || !ws_info(cur)) { + return -1; + } + regulatory_domain_saved = cur->ws_info->hopping_schdule.regulatory_domain; + operating_class_saved = cur->ws_info->hopping_schdule.operating_mode; + operating_mode_saved = cur->ws_info->hopping_schdule.operating_class; + if (regulatory_domain != 255) { + cur->ws_info->hopping_schdule.regulatory_domain = regulatory_domain; + } + if (operating_mode != 255) { + cur->ws_info->hopping_schdule.operating_mode = operating_mode; + } + if (operating_class != 255) { + cur->ws_info->hopping_schdule.operating_class = operating_class; + } + if (ws_common_regulatory_domain_config(cur) != 0) { + // Restore old config on failure + //tr_error("unsupported regulatory domain: %d class: %d, mode: %d", regulatory_domain, operating_class, operating_mode); + cur->ws_info->hopping_schdule.regulatory_domain = regulatory_domain_saved; + cur->ws_info->hopping_schdule.operating_mode = operating_mode_saved; + cur->ws_info->hopping_schdule.operating_class = operating_class_saved; + ws_common_regulatory_domain_config(cur); + return -1; + } + // if settings change reset_restart for the settings needed + if (cur->lowpan_info & INTERFACE_NWK_ACTIVE) { + // bootstrap active need to restart + ws_bootstrap_restart(interface_id); + } + + return 0; +} + +int ws_management_network_size_set( + int8_t interface_id, + uint8_t network_size) +{ + protocol_interface_info_entry_t *cur; + + cur = protocol_stack_interface_info_get_by_id(interface_id); + if (!cur || !ws_info(cur)) { + return -1; + } + if (network_size > NETWORK_SIZE_LARGE) { + return -2; + } + ws_info(cur)->network_size_config = network_size; + + if (network_size == NETWORK_SIZE_LARGE) { + ws_common_network_size_configure(cur, 5000); + } else { + ws_common_network_size_configure(cur, 10); + } + return 0; +} + +int ws_management_channel_mask_set( + int8_t interface_id, + uint32_t channel_mask[8]) +{ + protocol_interface_info_entry_t *cur; + + cur = protocol_stack_interface_info_get_by_id(interface_id); + if (!cur || !ws_info(cur)) { + return -1; + } + memcpy(cur->ws_info->fhss_channel_mask, channel_mask, sizeof(uint32_t) * 8); + return 0; +} + +int ws_management_channel_plan_set( + int8_t interface_id, + uint8_t channel_plan, + uint8_t uc_channel_function, + uint8_t bc_channel_function, + uint32_t ch0_freq, // Stack can not modify this + uint8_t channel_spacing,// Stack can not modify this + uint8_t number_of_channels) +{ + protocol_interface_info_entry_t *cur; + + cur = protocol_stack_interface_info_get_by_id(interface_id); + if (!cur || !ws_info(cur)) { + return -1; + } + cur->ws_info->hopping_schdule.channel_plan = channel_plan; + cur->ws_info->hopping_schdule.uc_channel_function = uc_channel_function; + cur->ws_info->hopping_schdule.bc_channel_function = bc_channel_function; + cur->ws_info->hopping_schdule.ch0_freq = ch0_freq; + cur->ws_info->hopping_schdule.channel_spacing = channel_spacing; + cur->ws_info->hopping_schdule.number_of_channels = number_of_channels; + + // TODO update fields to llc + return 0; +} + +int ws_management_fhss_timing_configure( + int8_t interface_id, + uint8_t fhss_uc_dwell_interval, + uint32_t fhss_broadcast_interval, + uint8_t fhss_bc_dwell_interval) +{ + protocol_interface_info_entry_t *cur; + + cur = protocol_stack_interface_info_get_by_id(interface_id); + if (!cur || !ws_info(cur)) { + return -1; + } + if (fhss_uc_dwell_interval > 0) { + cur->ws_info->fhss_uc_dwell_interval = fhss_uc_dwell_interval; + } + if (fhss_broadcast_interval > 0) { + cur->ws_info->fhss_bc_interval = fhss_broadcast_interval; + + } + if (fhss_bc_dwell_interval > 0) { + cur->ws_info->fhss_bc_dwell_interval = fhss_bc_dwell_interval; + + } + + // if settings change reset_restart for the settings needed + if (cur->lowpan_info & INTERFACE_NWK_ACTIVE) { + // bootstrap active need to restart + ws_bootstrap_restart(interface_id); + } + return 0; +} + +int ws_management_fhss_unicast_channel_function_configure( + int8_t interface_id, + uint8_t channel_function, + uint16_t fixed_channel, + uint8_t dwell_interval) +{ + protocol_interface_info_entry_t *cur; + + cur = protocol_stack_interface_info_get_by_id(interface_id); + if (!cur || !ws_info(cur)) { + return -1; + } + if (channel_function != WS_FIXED_CHANNEL && + channel_function != WS_VENDOR_DEF_CF && + channel_function != WS_DH1CF && + channel_function != WS_TR51CF) { + return -2; + } + cur->ws_info->fhss_uc_channel_function = channel_function; + cur->ws_info->fhss_uc_fixed_channel = fixed_channel; + cur->ws_info->fhss_uc_dwell_interval = dwell_interval; + + // if settings change reset_restart for the settings needed + if (cur->lowpan_info & INTERFACE_NWK_ACTIVE) { + // bootstrap active need to restart + ws_bootstrap_restart(interface_id); + } + return 0; + +} + +int ws_management_fhss_broadcast_channel_function_configure( + int8_t interface_id, + uint8_t channel_function, + uint16_t fixed_channel, + uint8_t dwell_interval, + uint32_t broadcast_interval) +{ + protocol_interface_info_entry_t *cur; + + cur = protocol_stack_interface_info_get_by_id(interface_id); + if (!cur || !ws_info(cur)) { + return -1; + } + if (channel_function != WS_FIXED_CHANNEL && + channel_function != WS_VENDOR_DEF_CF && + channel_function != WS_DH1CF && + channel_function != WS_TR51CF) { + return -2; + } + cur->ws_info->fhss_bc_channel_function = channel_function; + cur->ws_info->fhss_bc_fixed_channel = fixed_channel; + cur->ws_info->fhss_bc_dwell_interval = dwell_interval; + cur->ws_info->fhss_bc_interval = broadcast_interval; + + // if settings change reset_restart for the settings needed + if (cur->lowpan_info & INTERFACE_NWK_ACTIVE) { + // bootstrap active need to restart + ws_bootstrap_restart(interface_id); + } + return 0; + +} +#endif // HAVE_WS diff --git a/source/6LoWPAN/ws/ws_mpx_header.c b/source/6LoWPAN/ws/ws_mpx_header.c new file mode 100644 index 0000000000..6d0ad5ae56 --- /dev/null +++ b/source/6LoWPAN/ws/ws_mpx_header.c @@ -0,0 +1,146 @@ +/* + * Copyright (c) 2018-2019, Arm Limited and affiliates. + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "nsconfig.h" +#include +#include "ns_types.h" +#include "ns_list.h" +#include "ns_trace.h" +#include "nsdynmemLIB.h" +#include "common_functions.h" +#include "mac_common_defines.h" +#include "ws_mpx_header.h" + +bool ws_llc_mpx_header_frame_parse(uint8_t *ptr, uint16_t length, mpx_msg_t *msg) +{ + if (!length) { + return false; + } + memset(msg, 0, sizeof(mpx_msg_t)); + bool fragmented_number_present = false; + bool multiplex_id_present = false; + bool fragment_total_size = false; + + msg->transfer_type = *ptr & 7; + msg->transaction_id = ((*ptr++ & 0xf8) >> 3); + length--; + + + switch (msg->transfer_type) { + case MPX_FT_FULL_FRAME: + multiplex_id_present = true; + break; + case MPX_FT_FULL_FRAME_SMALL_MULTILEX_ID: + break; + case MPX_FT_FIRST_OR_SUB_FRAGMENT: + case MPX_FT_LAST_FRAGMENT: + fragmented_number_present = true; + if (length < 2) { + return false; + } + break; + case MPX_FT_ABORT: + if (length == 2) { + fragment_total_size = true; + } else if (length) { + return false; + } + break; + default: + return false; + } + + if (fragmented_number_present) { + + msg->fragment_number = *ptr++; + length--; + if (msg->fragment_number == 0) { //First fragment + fragment_total_size = true; + multiplex_id_present = true; + } + } + + if (fragment_total_size) { + if (length < 2) { + return false; + } + msg->total_upper_layer_size = common_read_16_bit_inverse(ptr); + ptr += 2; + length -= 2; + } + + if (multiplex_id_present) { + if (length < 3) { + return false; + } + msg->multiplex_id = common_read_16_bit_inverse(ptr); + ptr += 2; + length -= 2; + } + + msg->frame_ptr = ptr; + msg->frame_length = length; + return true; +} + + +uint8_t *ws_llc_mpx_header_write(uint8_t *ptr, const mpx_msg_t *msg) +{ + + bool fragmented_number_present = false; + bool multiplex_id_present = false; + bool fragment_total_size = false; + + *ptr = msg->transfer_type; + *ptr++ |= ((msg->transaction_id << 3) & 0xf8); + + switch (msg->transfer_type) { + case MPX_FT_FULL_FRAME: + multiplex_id_present = true; + break; + case MPX_FT_FULL_FRAME_SMALL_MULTILEX_ID: + break; + case MPX_FT_FIRST_OR_SUB_FRAGMENT: + case MPX_FT_LAST_FRAGMENT: + fragmented_number_present = true; + if (msg->fragment_number == 0) { + fragment_total_size = true; + multiplex_id_present = true; + } + break; + case MPX_FT_ABORT: + if (msg->total_upper_layer_size) { + fragment_total_size = true; + } + break; + default: + break; + } + + if (fragmented_number_present) { + *ptr++ = msg->fragment_number; + } + + if (fragment_total_size) { + ptr = common_write_16_bit_inverse(msg->total_upper_layer_size, ptr); + } + + if (multiplex_id_present) { + ptr = common_write_16_bit_inverse(msg->multiplex_id, ptr); + } + return ptr; +} diff --git a/source/6LoWPAN/ws/ws_mpx_header.h b/source/6LoWPAN/ws/ws_mpx_header.h new file mode 100644 index 0000000000..2e64b0571b --- /dev/null +++ b/source/6LoWPAN/ws/ws_mpx_header.h @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2018-2019, Arm Limited and affiliates. + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef WS_MPX_HEADER_H_ +#define WS_MPX_HEADER_H_ + +#define MPX_FT_FULL_FRAME 0 +#define MPX_FT_FULL_FRAME_SMALL_MULTILEX_ID 1 +#define MPX_FT_FIRST_OR_SUB_FRAGMENT 2 +#define MPX_FT_LAST_FRAGMENT 4 +#define MPX_FT_ABORT 6 + +typedef struct { + unsigned transfer_type: 3; + unsigned transaction_id: 5; + uint8_t fragment_number; + uint16_t total_upper_layer_size; + uint16_t multiplex_id; + uint8_t *frame_ptr; + uint16_t frame_length; +} mpx_msg_t; + +bool ws_llc_mpx_header_frame_parse(uint8_t *ptr, uint16_t length, mpx_msg_t *msg); +uint8_t *ws_llc_mpx_header_write(uint8_t *ptr, const mpx_msg_t *msg); + + +#endif /* WS_MPX_HEADER_H_ */ diff --git a/source/6LoWPAN/ws/ws_neighbor_class.c b/source/6LoWPAN/ws/ws_neighbor_class.c new file mode 100644 index 0000000000..230e5e9986 --- /dev/null +++ b/source/6LoWPAN/ws/ws_neighbor_class.c @@ -0,0 +1,188 @@ +/* + * Copyright (c) 2018-2019, Arm Limited and affiliates. + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "nsconfig.h" +#include +#include "ns_types.h" +#include "ns_list.h" +#include "ns_trace.h" +#include "nsdynmemLIB.h" +#include "fhss_config.h" +#include "6LoWPAN/ws/ws_config.h" +#include "6LoWPAN/ws/ws_neighbor_class.h" +#include "6LoWPAN/ws/ws_common.h" +#include "ws_management_api.h" + +#ifdef HAVE_WS + + +#define TRACE_GROUP "wsne" + + +bool ws_neighbor_class_alloc(ws_neighbor_class_t *class_data, uint8_t list_size) +{ + + class_data->neigh_info_list = ns_dyn_mem_alloc(sizeof(ws_neighbor_class_entry_t) * list_size); + if (!class_data->neigh_info_list) { + return false; + } + + class_data->list_size = list_size; + ws_neighbor_class_entry_t *list_ptr = class_data->neigh_info_list; + for (uint8_t i = 0; i < list_size; i++) { + memset(list_ptr, 0, sizeof(ws_neighbor_class_entry_t)); + list_ptr->rsl_in = RSL_UNITITIALIZED; + list_ptr->rsl_out = RSL_UNITITIALIZED; + list_ptr++; + } + return true; +} + + +void ws_neighbor_class_dealloc(ws_neighbor_class_t *class_data) +{ + ns_dyn_mem_free(class_data->neigh_info_list); + class_data->neigh_info_list = NULL; + class_data->list_size = 0; +} + +ws_neighbor_class_entry_t *ws_neighbor_class_entry_get(ws_neighbor_class_t *class_data, uint8_t attribute_index) +{ + if (!class_data->neigh_info_list || attribute_index >= class_data->list_size) { + return NULL; + } + + ws_neighbor_class_entry_t *entry = class_data->neigh_info_list + attribute_index; + return entry; +} + +uint8_t ws_neighbor_class_entry_index_get(ws_neighbor_class_t *class_data, ws_neighbor_class_entry_t *entry) +{ + if (!class_data->neigh_info_list) { + return 0xff; + } + return entry - class_data->neigh_info_list; +} + +void ws_neighbor_class_entry_remove(ws_neighbor_class_t *class_data, uint8_t attribute_index) +{ + ws_neighbor_class_entry_t *entry = ws_neighbor_class_entry_get(class_data, attribute_index); + if (entry) { + memset(entry, 0, sizeof(ws_neighbor_class_entry_t)); + entry->rsl_in = RSL_UNITITIALIZED; + entry->rsl_out = RSL_UNITITIALIZED; + } +} + +void ws_neighbor_class_neighbor_unicast_time_info_update(ws_neighbor_class_entry_t *ws_neighbor, ws_utt_ie_t *ws_utt, uint32_t timestamp) +{ + ws_neighbor->fhss_data.uc_timing_info.utt_rx_timestamp = timestamp; + ws_neighbor->fhss_data.uc_timing_info.ufsi = ws_utt->ufsi; +} + +void ws_neighbor_class_neighbor_unicast_schedule_set(ws_neighbor_class_entry_t *ws_neighbor, ws_us_ie_t *ws_us) +{ + 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; + } else { + ws_neighbor->fhss_data.uc_timing_info.unicast_number_of_channels = 0; + } + } + ws_neighbor->fhss_data.uc_timing_info.unicast_dwell_interval = ws_us->dwell_interval; +} + + +void ws_neighbor_class_neighbor_broadcast_time_info_update(ws_neighbor_class_entry_t *ws_neighbor, ws_bt_ie_t *ws_bt_ie, uint32_t timestamp) +{ + ws_neighbor->broadcast_timing_info_stored = true; + ws_neighbor->fhss_data.bc_timing_info.bt_rx_timestamp = timestamp; + ws_neighbor->fhss_data.bc_timing_info.broadcast_slot = ws_bt_ie->broadcast_slot_number; + ws_neighbor->fhss_data.bc_timing_info.broadcast_interval_offset = ws_bt_ie->broadcast_interval_offset; +} + + +void ws_neighbor_class_neighbor_broadcast_schedule_set(ws_neighbor_class_entry_t *ws_neighbor, ws_bs_ie_t *ws_bs_ie) +{ + ws_neighbor->broadcast_shedule_info_stored = true; + ws_neighbor->fhss_data.bc_timing_info.broadcast_channel_function = ws_bs_ie->channel_function; + if (ws_bs_ie->channel_function == WS_FIXED_CHANNEL) { + ws_neighbor->fhss_data.bc_timing_info.fixed_channel = ws_bs_ie->function.zero.fixed_channel; + } + ws_neighbor->fhss_data.bc_timing_info.broadcast_dwell_interval = ws_bs_ie->dwell_interval; + ws_neighbor->fhss_data.bc_timing_info.broadcast_interval = ws_bs_ie->broadcast_interval; + ws_neighbor->fhss_data.bc_timing_info.broadcast_schedule_id = ws_bs_ie->broadcast_schedule_identifier; +} + +uint8_t ws_neighbor_class_rssi_from_dbm_calculate(int8_t dbm_heard) +{ + if (DEVICE_MIN_SENS > dbm_heard) { + // We are hearing packet with lower than min_sens dynamically learn the sensitivity + tr_info("heard packet below min sensitivity"); + DEVICE_MIN_SENS = dbm_heard; + } + return dbm_heard - DEVICE_MIN_SENS; +} + +static void ws_neighbor_class_parent_set_analyze(ws_neighbor_class_entry_t *ws_neighbor) +{ + if (ws_neighbor->rsl_in == RSL_UNITITIALIZED || + ws_neighbor->rsl_out == RSL_UNITITIALIZED) { + ws_neighbor->candidate_parent = false; + return; + } + + if (ws_neighbor_class_rsl_in_get(ws_neighbor) < (CAND_PARENT_THRESHOLD - CAND_PARENT_HYSTERISIS) && + ws_neighbor_class_rsl_out_get(ws_neighbor) < (CAND_PARENT_THRESHOLD - CAND_PARENT_HYSTERISIS)) { + ws_neighbor->candidate_parent = false; + } + + if (ws_neighbor_class_rsl_in_get(ws_neighbor) > (CAND_PARENT_THRESHOLD + CAND_PARENT_HYSTERISIS) && + ws_neighbor_class_rsl_out_get(ws_neighbor) > (CAND_PARENT_THRESHOLD + CAND_PARENT_HYSTERISIS)) { + ws_neighbor->candidate_parent = true; + } +} + +void ws_neighbor_class_rsl_in_calculate(ws_neighbor_class_entry_t *ws_neighbor, int8_t dbm_heard) +{ + uint8_t rssi = ws_neighbor_class_rssi_from_dbm_calculate(dbm_heard); + if (ws_neighbor->rsl_in == RSL_UNITITIALIZED) { + ws_neighbor->rsl_in = rssi << WS_RSL_SCALING; + } + ws_neighbor->rsl_in = ws_neighbor->rsl_in + rssi - (ws_neighbor->rsl_in >> WS_RSL_SCALING); + ws_neighbor_class_parent_set_analyze(ws_neighbor); + return; +} + +void ws_neighbor_class_rsl_out_calculate(ws_neighbor_class_entry_t *ws_neighbor, uint8_t rsl_reported) +{ + if (ws_neighbor->rsl_out == RSL_UNITITIALIZED) { + ws_neighbor->rsl_out = rsl_reported << WS_RSL_SCALING; + } + ws_neighbor->rsl_out = ws_neighbor->rsl_out + rsl_reported - (ws_neighbor->rsl_out >> WS_RSL_SCALING); + ws_neighbor_class_parent_set_analyze(ws_neighbor); + return; +} + +#endif /* HAVE_WS */ + diff --git a/source/6LoWPAN/ws/ws_neighbor_class.h b/source/6LoWPAN/ws/ws_neighbor_class.h index 738f9340ff..3858465430 100644 --- a/source/6LoWPAN/ws/ws_neighbor_class.h +++ b/source/6LoWPAN/ws/ws_neighbor_class.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2018, Arm Limited and affiliates. + * Copyright (c) 2018-2019, Arm Limited and affiliates. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/source/6LoWPAN/ws/ws_pae_auth.c b/source/6LoWPAN/ws/ws_pae_auth.c new file mode 100644 index 0000000000..ff89417ae1 --- /dev/null +++ b/source/6LoWPAN/ws/ws_pae_auth.c @@ -0,0 +1,603 @@ +/* + * Copyright (c) 2018-2019, Arm Limited and affiliates. + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "nsconfig.h" +#include +#include "ns_types.h" +#include "ns_list.h" +#include "ns_trace.h" +#include "nsdynmemLIB.h" +#include "fhss_config.h" +#include "eventOS_event.h" +#include "eventOS_scheduler.h" +#include "eventOS_event_timer.h" +#include "ns_address.h" +#include "NWK_INTERFACE/Include/protocol.h" +#include "6LoWPAN/ws/ws_config.h" +#include "Security/kmp/kmp_addr.h" +#include "Security/kmp/kmp_api.h" +#include "Security/kmp/kmp_socket_if.h" +#include "Security/protocols/sec_prot_certs.h" +#include "Security/protocols/sec_prot_keys.h" +#include "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/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 "6LoWPAN/ws/ws_pae_controller.h" +#include "6LoWPAN/ws/ws_pae_auth.h" +#include "6LoWPAN/ws/ws_pae_lib.h" + +#ifdef HAVE_WS +#ifdef HAVE_PAE_AUTH + +#define TRACE_GROUP "wspa" + +#define PAE_TASKLET_INIT 1 +#define PAE_TASKLET_EVENT 2 +#define PAE_TASKLET_TIMER 3 + +// Wait for for supplicant to indicate activity (e.g. to send a message) +#define WAIT_FOR_AUTHENTICATION_TICKS 5 * 60 * 10 // 5 minutes + +typedef struct { + ns_list_link_t link; /**< Link */ + kmp_service_t *kmp_service; /**< KMP service */ + protocol_interface_info_entry_t *interface_ptr; /**< Interface pointer */ + supp_list_t active_supp_list; /**< List of active supplicants */ + supp_list_t inactive_supp_list; /**< List of inactive supplicants */ + arm_event_storage_t *timer; /**< Timer */ + sec_prot_gtk_keys_t *gtks; /**< GTKs */ + const sec_prot_certs_t *certs; /**< Certificates */ + bool timer_running; /**< Timer is running */ +} pae_auth_t; + +static void ws_pae_auth_free(pae_auth_t *pae_auth); +static pae_auth_t *ws_pae_auth_get(protocol_interface_info_entry_t *interface_ptr); +static pae_auth_t *ws_pae_auth_by_kmp_service_get(kmp_service_t *service); +static int8_t ws_pae_auth_event_send(kmp_service_t *service, void *data); +static void ws_pae_auth_tasklet_handler(arm_event_s *event); +static int8_t ws_pae_auth_timer_if_start(kmp_service_t *service, kmp_api_t *kmp); +static int8_t ws_pae_auth_timer_if_stop(kmp_service_t *service, kmp_api_t *kmp); +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 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 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 kmp_api_t *ws_pae_auth_kmp_create_and_start(kmp_service_t *service, kmp_type_e type, supp_entry_t *supp_entry); +static void ws_pae_auth_kmp_api_finished(kmp_api_t *kmp); + +static int8_t tasklet_id = -1; +static NS_LIST_DEFINE(pae_auth_list, pae_auth_t, link); + +int8_t ws_pae_auth_init(protocol_interface_info_entry_t *interface_ptr, sec_prot_gtk_keys_t *gtks, const sec_prot_certs_t *certs) +{ + if (!interface_ptr || !gtks || !certs) { + return -1; + } + + if (ws_pae_auth_get(interface_ptr) != NULL) { + return 0; + } + + pae_auth_t *pae_auth = ns_dyn_mem_alloc(sizeof(pae_auth_t)); + if (!pae_auth) { + return -1; + } + + pae_auth->interface_ptr = interface_ptr; + ws_pae_lib_supp_list_init(&pae_auth->active_supp_list); + ws_pae_lib_supp_list_init(&pae_auth->inactive_supp_list); + pae_auth->timer = NULL; + + pae_auth->gtks = gtks; + pae_auth->certs = certs; + + 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, ws_pae_auth_kmp_service_addr_get, ws_pae_auth_kmp_service_api_get)) { + goto error; + } + + if (kmp_service_event_if_register(pae_auth->kmp_service, ws_pae_auth_event_send)) { + goto error; + } + + if (kmp_service_timer_if_register(pae_auth->kmp_service, ws_pae_auth_timer_if_start, ws_pae_auth_timer_if_stop)) { + goto error; + } + + if (key_sec_prot_register(pae_auth->kmp_service) < 0) { + goto error; + } + + 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; + } + + if (auth_fwh_sec_prot_register(pae_auth->kmp_service) < 0) { + goto error; + } + + if (auth_gkh_sec_prot_register(pae_auth->kmp_service) < 0) { + goto error; + } + + if (tasklet_id < 0) { + tasklet_id = eventOS_event_handler_create(ws_pae_auth_tasklet_handler, PAE_TASKLET_INIT); + if (tasklet_id < 0) { + goto error; + } + } + + if (ws_pae_auth_timer_stop(pae_auth) < 0) { + goto error; + } + + ns_list_add_to_end(&pae_auth_list, pae_auth); + + return 0; + +error: + ws_pae_auth_free(pae_auth); + + return -1; +} + +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) +{ + if (!interface_ptr || !remote_addr) { + return -1; + } + + 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, local_port, remote_addr, remote_port) < 0) { + return -1; + } + + return 0; +} + +int8_t ws_pae_auth_delete(protocol_interface_info_entry_t *interface_ptr) +{ + if (!interface_ptr) { + return -1; + } + + pae_auth_t *pae_auth = ws_pae_auth_get(interface_ptr); + if (!pae_auth) { + return -1; + } + + ws_pae_auth_free(pae_auth); + return 0; +} + +static void ws_pae_auth_free(pae_auth_t *pae_auth) +{ + if (!pae_auth) { + return; + } + + ws_pae_lib_supp_list_delete(&pae_auth->active_supp_list); + ws_pae_lib_supp_list_delete(&pae_auth->inactive_supp_list); + + kmp_socket_if_unregister(pae_auth->kmp_service); + + kmp_service_delete(pae_auth->kmp_service); + + ns_list_remove(&pae_auth_list, pae_auth); + ns_dyn_mem_free(pae_auth); +} + +static pae_auth_t *ws_pae_auth_get(protocol_interface_info_entry_t *interface_ptr) +{ + ns_list_foreach(pae_auth_t, entry, &pae_auth_list) { + if (entry->interface_ptr == interface_ptr) { + return entry; + } + } + + return NULL; +} + +static pae_auth_t *ws_pae_auth_by_kmp_service_get(kmp_service_t *service) +{ + ns_list_foreach(pae_auth_t, entry, &pae_auth_list) { + if (entry->kmp_service == service) { + return entry; + } + } + + return NULL; +} + +static int8_t ws_pae_auth_event_send(kmp_service_t *service, void *data) +{ + pae_auth_t *pae_auth = ws_pae_auth_by_kmp_service_get(service); + if (!pae_auth) { + return -1; + } + + arm_event_s event = { + .receiver = tasklet_id, + .sender = 0, + .event_id = pae_auth->interface_ptr->id, + .data_ptr = data, + .event_type = PAE_TASKLET_EVENT, + .priority = ARM_LIB_LOW_PRIORITY_EVENT, + }; + + if (eventOS_event_send(&event) != 0) { + return -1; + } + + return 0; +} + +static void ws_pae_auth_tasklet_handler(arm_event_s *event) +{ + if (event->event_type == PAE_TASKLET_INIT) { + + } else if (event->event_type == PAE_TASKLET_EVENT) { + pae_auth_t *pae_auth = NULL; + + ns_list_foreach(pae_auth_t, entry, &pae_auth_list) { + if (entry->interface_ptr->id == event->event_id) { + pae_auth = entry; + break; + } + } + + if (pae_auth) { + kmp_service_event_if_event(pae_auth->kmp_service, event->data_ptr); + } + } +} + +void ws_pae_auth_timer(uint16_t ticks) +{ + ns_list_foreach(pae_auth_t, pae_auth, &pae_auth_list) { + if (!ws_pae_auth_timer_running(pae_auth)) { + continue; + } + + // Updates KMP timers + bool running = ws_pae_lib_supp_list_timer_update(&pae_auth->active_supp_list, &pae_auth->inactive_supp_list, ticks, kmp_service_timer_if_timeout); + if (!running) { + ws_pae_auth_timer_stop(pae_auth); + } + } +} + +static int8_t ws_pae_auth_timer_if_start(kmp_service_t *service, kmp_api_t *kmp) +{ + pae_auth_t *pae_auth = ws_pae_auth_by_kmp_service_get(service); + if (!pae_auth) { + return -1; + } + + if (ws_pae_auth_timer_start(pae_auth) < 0) { + return -1; + } + + supp_entry_t *supp_entry = kmp_api_data_get(kmp); + if (!supp_entry) { + return -1; + } + + kmp_entry_t *entry = ws_pae_lib_kmp_list_entry_get(&supp_entry->kmp_list, kmp); + if (!entry) { + return -1; + } + + ws_pae_lib_supp_list_to_active(&pae_auth->active_supp_list, &pae_auth->inactive_supp_list, supp_entry); + + ws_pae_lib_kmp_timer_start(&supp_entry->kmp_list, entry); + return 0; +} + +static int8_t ws_pae_auth_timer_if_stop(kmp_service_t *service, kmp_api_t *kmp) +{ + (void) service; + + supp_entry_t *supp_entry = kmp_api_data_get(kmp); + + kmp_entry_t *entry = ws_pae_lib_kmp_list_entry_get(&supp_entry->kmp_list, kmp); + if (!entry) { + return -1; + } + + ws_pae_lib_kmp_timer_stop(&supp_entry->kmp_list, entry); + return 0; +} + +static int8_t ws_pae_auth_timer_start(pae_auth_t *pae_auth) +{ + pae_auth->timer_running = true; + return 0; +} + +static int8_t ws_pae_auth_timer_stop(pae_auth_t *pae_auth) +{ + pae_auth->timer_running = false; + return 0; +} + +static bool ws_pae_auth_timer_running(pae_auth_t *pae_auth) +{ + return pae_auth->timer_running; +} + +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) +{ + (void) service; + +#if 0 + // Get own EUI-64 + link_layer_address_s mac_params; + if (arm_nwk_mac_address_read(pae_auth->interface_ptr->id, &mac_params) >= 0) { + kmp_address_eui_64_set(local_addr, mac_params.mac_long); + } +#endif + + // For now fixed since not yet support for EA-IE in supplicants + uint8_t addr[8] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}; + kmp_address_eui_64_set(local_addr, addr); + + // Get supplicant address + supp_entry_t *entry = kmp_api_data_get(kmp); + if (entry && entry->addr) { + kmp_address_copy(remote_addr, entry->addr); + } +} + +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; + + supp_entry_t *supp_entry = kmp_api_data_get(kmp); + if (!supp_entry) { + return NULL; + } + + 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) +{ + 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 + supp_entry_t *supp_entry = ws_pae_lib_supp_list_entry_eui_64_get(&pae_auth->active_supp_list, kmp_address_eui_64_get(addr)); + + if (!supp_entry) { + // Find supplicant from list of inactive supplicants + supp_entry = ws_pae_lib_supp_list_entry_eui_64_get(&pae_auth->inactive_supp_list, kmp_address_eui_64_get(addr)); + if (supp_entry) { + // Move supplicant to active list + ws_pae_lib_supp_list_to_active(&pae_auth->active_supp_list, &pae_auth->inactive_supp_list, supp_entry); + } + } + + // If does not exists add it to list + if (!supp_entry) { + supp_entry = ws_pae_lib_supp_list_add(&pae_auth->active_supp_list, addr); + if (!supp_entry) { + return 0; + } + sec_prot_keys_init(&supp_entry->sec_keys, pae_auth->gtks, pae_auth->certs); + } else { + // Updates relay address + kmp_address_copy(supp_entry->addr, addr); + } + + // 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); + if (kmp) { + return kmp; + } + + // Create a new KMP for initial eapol-key + kmp = kmp_api_create(service, type + IEEE_802_1X_INITIAL_KEY); + + if (!kmp) { + return 0; + } + + 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 0; + } + + kmp_api_cb_register(kmp, + ws_pae_auth_kmp_api_create_confirm, + ws_pae_auth_kmp_api_create_indication, + ws_pae_auth_kmp_api_finished_indication, + ws_pae_auth_kmp_api_finished); + + if (kmp_api_start(kmp) < 0) { + ws_pae_lib_kmp_list_delete(&supp_entry->kmp_list, kmp); + return 0; + } + + return kmp; +} + +static void ws_pae_auth_kmp_api_create_confirm(kmp_api_t *kmp, kmp_result_e result) +{ + (void) kmp; + (void) result; + // If KMP-CREATE.request has failed, authentication error, just stop for now +} + +static void ws_pae_auth_kmp_api_create_indication(kmp_api_t *kmp, kmp_type_e type, kmp_addr_t *addr) +{ + (void) type; + (void) addr; + // For now, accept every KMP-CREATE.indication + kmp_api_create_response(kmp, KMP_RESULT_OK); +} + +static void ws_pae_auth_kmp_api_finished_indication(kmp_api_t *kmp, kmp_result_e result, kmp_sec_keys_t *sec_keys) +{ + (void) sec_keys; + + // For now, just ignore if not ok + if (result != KMP_RESULT_OK) { + return; + } + + supp_entry_t *supp_entry = kmp_api_data_get(kmp); + if (!supp_entry) { + // Should not be possible + return; + } + + // Gets type + kmp_type_e type = kmp_api_type_get(kmp); + + if (type > IEEE_802_1X_INITIAL_KEY) { + // For EAPOL-key, start EAP-TLS towards supplicant + type = IEEE_802_1X_MKA; + tr_debug("PAE start EAP-TLS, eui-64: %s", trace_array(kmp_address_eui_64_get(supp_entry->addr), 8)); + } else if (type == IEEE_802_1X_MKA) { + // After EAP-TLS start 4WH towards supplicant + type = IEEE_802_11_4WH; + // Insert GTK0 + sec_prot_keys_gtk_insert_index_set(supp_entry->sec_keys.gtks, 0); + tr_debug("PAE start 4WH, eui-64: %s", trace_array(kmp_address_eui_64_get(supp_entry->addr), 8)); + } else if (type == IEEE_802_11_4WH) { + // After 4WH start GKH towards supplicant + type = IEEE_802_11_GKH; + // Insert GTK1 + sec_prot_keys_gtk_insert_index_set(supp_entry->sec_keys.gtks, 1); + tr_debug("PAE start GKH, eui-64: %s", trace_array(kmp_address_eui_64_get(supp_entry->addr), 8)); + } else if (type == IEEE_802_11_GKH) { + tr_debug("PAE authenticated, eui-64: %s", trace_array(kmp_address_eui_64_get(supp_entry->addr), 8)); + // After GKH end + return; + } + + // Increases waiting time for supplicant authentication + ws_pae_lib_supp_timer_ticks_set(supp_entry, WAIT_FOR_AUTHENTICATION_TICKS); + + kmp_service_t *service = kmp_api_service_get(kmp); + pae_auth_t *pae_auth = ws_pae_auth_by_kmp_service_get(service); + if (!pae_auth) { + return; + } + + // Create new instance + kmp_api_t *new_kmp = ws_pae_auth_kmp_create_and_start(pae_auth->kmp_service, type, supp_entry); + if (!new_kmp) { + return; + } + + // For EAP-TLS create also TLS in addition to EAP-TLS + if (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 + ws_pae_lib_kmp_list_delete(&supp_entry->kmp_list, new_kmp); + return; + } + // Create TLS instance */ + if (ws_pae_auth_kmp_create_and_start(service, TLS_PROT, supp_entry) == NULL) { + ws_pae_lib_kmp_list_delete(&supp_entry->kmp_list, new_kmp); + return; + } + } + + kmp_api_create_request(new_kmp, type, supp_entry->addr, &supp_entry->sec_keys); +} + +static kmp_api_t *ws_pae_auth_kmp_create_and_start(kmp_service_t *service, kmp_type_e type, supp_entry_t *supp_entry) +{ + // Create KMP instance for new authentication + kmp_api_t *kmp = kmp_api_create(service, type); + + if (!kmp) { + return NULL; + } + + if (ws_pae_lib_kmp_list_add(&supp_entry->kmp_list, kmp) == NULL) { + kmp_api_delete(kmp); + return NULL; + } + + kmp_api_cb_register(kmp, + ws_pae_auth_kmp_api_create_confirm, + ws_pae_auth_kmp_api_create_indication, + ws_pae_auth_kmp_api_finished_indication, + ws_pae_auth_kmp_api_finished); + + kmp_api_data_set(kmp, supp_entry); + + if (kmp_api_start(kmp) < 0) { + ws_pae_lib_kmp_list_delete(&supp_entry->kmp_list, kmp); + return NULL; + } + + return kmp; +} + +static void ws_pae_auth_kmp_api_finished(kmp_api_t *kmp) +{ + supp_entry_t *supp_entry = kmp_api_data_get(kmp); + if (!supp_entry) { + // Should not be possible + return; + } + + // Delete KMP + ws_pae_lib_kmp_list_delete(&supp_entry->kmp_list, kmp); +} + +#endif /* HAVE_PAE_AUTH */ +#endif /* HAVE_WS */ + diff --git a/source/6LoWPAN/ws/ws_pae_auth.h b/source/6LoWPAN/ws/ws_pae_auth.h new file mode 100644 index 0000000000..b33589c661 --- /dev/null +++ b/source/6LoWPAN/ws/ws_pae_auth.h @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2018-2019, Arm Limited and affiliates. + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef WS_PAE_AUTH_H_ +#define WS_PAE_AUTH_H_ + +#ifdef HAVE_PAE_AUTH + +/* + * Authenticator port access entity controls key security protocols using KMP API. + * + * Configures KMP service network access and provides timing and callback services + * for it. Registers needed security protocols to KMP service. + * + * PAE Maintains security keys that are internal to port access entity for + * each supplicant and maintains supplicant security registration state. + * + * Autenticator PAE controls network access keys and provides new network + * access keys to supplicants when they are changed. When supplicant + * network keys are updated, also other keys (master key, pairwise key) + * are updated as needed. + * + */ + +/** + * ws_pae_auth_init initializes PAE authenticator + * + * \param interface_ptr interface + * \param local_port local port + * \param remote_addr remote address + * \param remote_port remote port + * \param gtks group keys + * \param cert_chain certificate chain + * + * \return < 0 failure + * \return >= 0 success + * + */ +int8_t ws_pae_auth_init(protocol_interface_info_entry_t *interface_ptr, sec_prot_gtk_keys_t *gtks, const sec_prot_certs_t *certs); + +/** + * ws_pae_auth_addresses_set set relay addresses + * + * \param interface_ptr interface + * \param local_port local port + * \param remote_addr remote address + * \param remote_port remote port + * + * \return < 0 failure + * \return >= 0 success + * + */ +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_delete deletes PAE authenticator + * + * \param interface_ptr interface + * + * \return < 0 failure + * \return >= 0 success + * + */ +int8_t ws_pae_auth_delete(protocol_interface_info_entry_t *interface_ptr); + +/** + * ws_pae_auth_timer PAE authenticator timer call + * + * \param ticks elapsed ticks + * + */ +void ws_pae_auth_timer(uint16_t ticks); + +#else + +#define ws_pae_auth_init(interface_ptr, gtks, certs) 1 +#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_timer NULL + +#endif + +#endif /* WS_PAE_AUTH_H_ */ diff --git a/source/6LoWPAN/ws/ws_pae_controller.c b/source/6LoWPAN/ws/ws_pae_controller.c new file mode 100644 index 0000000000..edb051ebb4 --- /dev/null +++ b/source/6LoWPAN/ws/ws_pae_controller.c @@ -0,0 +1,412 @@ +/* + * Copyright (c) 2018-2019, Arm Limited and affiliates. + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "nsconfig.h" +#include +#include "ns_types.h" +#include "ns_list.h" +#include "ns_trace.h" +#include "nsdynmemLIB.h" +#include "fhss_config.h" +#include "ns_address.h" +#include "NWK_INTERFACE/Include/protocol.h" +#include "6LoWPAN/ws/ws_config.h" +#include "6LoWPAN/ws/ws_pae_controller.h" +#include "Security/protocols/sec_prot_certs.h" +#include "Security/protocols/sec_prot_keys.h" +#include "6LoWPAN/ws/ws_pae_supp.h" +#include "6LoWPAN/ws/ws_pae_auth.h" + +#ifdef HAVE_WS + +#define TRACE_GROUP "wspc" + +typedef int8_t ws_pae_delete(protocol_interface_info_entry_t *interface_ptr); +typedef void ws_pae_timer(uint16_t ticks); +typedef int8_t ws_pae_br_addr_write(protocol_interface_info_entry_t *interface_ptr, const uint8_t *eui_64); +typedef int8_t ws_pae_br_addr_read(protocol_interface_info_entry_t *interface_ptr, uint8_t *eui_64); + + +typedef struct { + ns_list_link_t link; /**< Link */ + uint8_t target_eui_64[8]; /**< EAPOL target */ + uint16_t target_pan_id; /**< EAPOL target PAN ID */ + uint8_t br_eui_64[8]; /**< Border router EUI-64 */ + sec_prot_gtk_keys_t gtks; /**< GTKs */ + sec_prot_certs_t certs; /**< Certificates */ + protocol_interface_info_entry_t *interface_ptr; /**< List link entry */ + ws_pae_controller_auth_completed *auth_completed; /**< Authentication completed callback, continue bootstrap */ + ws_pae_controller_key_insert *key_insert; /**< Key insert callback */ + ws_pae_delete *pae_delete; /**< PAE delete callback */ + ws_pae_timer *pae_timer; /**< PAE timer callback */ + ws_pae_br_addr_write *pae_br_addr_write; /**< PAE Border router EUI-64 write callback */ + ws_pae_br_addr_read *pae_br_addr_read; /**< PAE Border router EUI-64 read callback */ +} pae_controller_t; + +static void ws_pae_controller_test_keys_set(sec_prot_gtk_keys_t *gtks); +static pae_controller_t *ws_pae_controller_get(protocol_interface_info_entry_t *interface_ptr); + +static NS_LIST_DEFINE(pae_controller_list, pae_controller_t, link); + +static void ws_pae_controller_test_keys_set(sec_prot_gtk_keys_t *gtks) +{ + uint8_t gtk[2][GTK_LEN]; + + // Test data + for (int i = 0; i < GTK_LEN; i++) { + gtk[0][i] = 0xcf - i; + gtk[1][i] = 0xef - i; + } + + sec_prot_keys_gtk_set(gtks, 0, gtk[0]); + sec_prot_keys_gtk_set(gtks, 1, gtk[1]); + + sec_prot_keys_gtkl_set(gtks, 0xFF); + + sec_prot_keys_gtk_insert_index_set(gtks, 0); +} + +int8_t ws_pae_controller_authenticate(protocol_interface_info_entry_t *interface_ptr) +{ + if (!interface_ptr) { + return -1; + } + + pae_controller_t *controller = ws_pae_controller_get(interface_ptr); + if (!controller) { + return -1; + } + + if (ws_pae_supp_authenticate(controller->interface_ptr, controller->target_pan_id, controller->target_eui_64) == PAE_SUPP_NOT_ENABLED) { + // Already authenticated + ws_pae_controller_test_keys_set(&controller->gtks); + + uint8_t index; + uint8_t *gtk = sec_prot_keys_get_gtk_to_insert(&controller->gtks, &index); + + controller->key_insert(controller->interface_ptr, index, gtk); + controller->auth_completed(interface_ptr, true); + } + + /////////// + // For now fixed since not yet support for EA-IE + const uint8_t addr[8] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}; + if (controller->pae_br_addr_write) { + controller->pae_br_addr_write(interface_ptr, addr); + } + //////////////// + + return 0; +} + +int8_t ws_pae_controller_authenticator_start(protocol_interface_info_entry_t *interface_ptr, uint16_t local_port, const uint8_t *remote_addr, uint16_t remote_port) +{ + (void) local_port; + (void) remote_port; + + if (!interface_ptr || !remote_addr) { + return -1; + } + + pae_controller_t *controller = ws_pae_controller_get(interface_ptr); + if (!controller) { + return -1; + } + + ws_pae_controller_test_keys_set(&controller->gtks); + + uint8_t index; + uint8_t *gtk = sec_prot_keys_get_gtk_to_insert(&controller->gtks, &index); + + controller->key_insert(controller->interface_ptr, index, gtk); + + if (ws_pae_auth_addresses_set(interface_ptr, local_port, remote_addr, remote_port) < 0) { + return -1; + } + + return 0; +} + +int8_t ws_pae_controller_cb_register(protocol_interface_info_entry_t *interface_ptr, ws_pae_controller_auth_completed *completed, ws_pae_controller_key_insert *key_insert) +{ + if (!interface_ptr) { + return -1; + } + + pae_controller_t *controller = ws_pae_controller_get(interface_ptr); + if (!controller) { + return -1; + } + + controller->auth_completed = completed; + controller->key_insert = key_insert; + + 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) { + return -1; + } + + pae_controller_t *controller = ws_pae_controller_get(interface_ptr); + if (!controller) { + return -1; + } + + controller->target_pan_id = target_pan_id; + memcpy(controller->target_eui_64, target_eui_64, 8); + + return 0; +} + +int8_t ws_pae_controller_nw_info_set(protocol_interface_info_entry_t *interface_ptr, uint16_t pan_id, char *network_name) +{ + (void) pan_id; + (void) network_name; + + if (!interface_ptr) { + return -1; + } + + pae_controller_t *controller = ws_pae_controller_get(interface_ptr); + if (!controller) { + return -1; + } + + return ws_pae_supp_nw_info_set(interface_ptr, pan_id, network_name); +} + +int8_t ws_pae_controller_nw_key_valid(protocol_interface_info_entry_t *interface_ptr) +{ + if (!interface_ptr) { + return -1; + } + + pae_controller_t *controller = ws_pae_controller_get(interface_ptr); + if (!controller) { + return -1; + } + + return ws_pae_supp_nw_key_valid(interface_ptr); +} + +int8_t ws_pae_controller_init(protocol_interface_info_entry_t *interface_ptr) +{ + if (!interface_ptr) { + return -1; + } + + if (ws_pae_controller_get(interface_ptr) != NULL) { + return 0; + } + + pae_controller_t *controller = ns_dyn_mem_alloc(sizeof(pae_controller_t)); + if (!controller) { + return -1; + } + + memset(controller->target_eui_64, 0, 8); + memset(controller->br_eui_64, 0, 8); + controller->interface_ptr = interface_ptr; + controller->auth_completed = NULL; + controller->key_insert = NULL; + controller->pae_delete = NULL; + controller->pae_timer = NULL; + controller->pae_br_addr_write = NULL; + controller->pae_br_addr_read = NULL; + + sec_prot_keys_gtks_init(&controller->gtks); + sec_prot_certs_init(&controller->certs); + + ns_list_add_to_end(&pae_controller_list, controller); + + return 0; +} + +int8_t ws_pae_controller_supp_init(protocol_interface_info_entry_t *interface_ptr) +{ + if (!interface_ptr) { + return -1; + } + + pae_controller_t *controller = ws_pae_controller_get(interface_ptr); + if (!controller) { + return -1; + } + + if (ws_pae_supp_init(controller->interface_ptr, &controller->certs) < 0) { + return -1; + } + + controller->pae_delete = ws_pae_supp_delete; + controller->pae_timer = ws_pae_supp_timer; + controller->pae_br_addr_write = ws_pae_supp_border_router_addr_write; + controller->pae_br_addr_read = ws_pae_supp_border_router_addr_read; + + ws_pae_supp_cb_register(controller->interface_ptr, controller->auth_completed, controller->key_insert); + + return 0; +} + +int8_t ws_pae_controller_auth_init(protocol_interface_info_entry_t *interface_ptr) +{ + if (!interface_ptr) { + return -1; + } + + pae_controller_t *controller = ws_pae_controller_get(interface_ptr); + if (!controller) { + return -1; + } + + if (ws_pae_auth_init(controller->interface_ptr, &controller->gtks, &controller->certs) < 0) { + return -1; + } + + controller->pae_delete = ws_pae_auth_delete; + controller->pae_timer = ws_pae_auth_timer; + + return 0; +} +int8_t ws_pae_controller_stop(protocol_interface_info_entry_t *interface_ptr) +{ + if (!interface_ptr) { + return -1; + } + + pae_controller_t *controller = ws_pae_controller_get(interface_ptr); + if (!controller) { + return -1; + } + + // If PAE has been initialized, deletes it + if (controller->pae_delete) { + controller->pae_delete(interface_ptr); + } + + return 0; +} + +int8_t ws_pae_controller_delete(protocol_interface_info_entry_t *interface_ptr) +{ + if (!interface_ptr) { + return -1; + } + + ws_pae_controller_stop(interface_ptr); + + pae_controller_t *controller = ws_pae_controller_get(interface_ptr); + if (!controller) { + return -1; + } + + ns_list_remove(&pae_controller_list, controller); + + sec_prot_certs_delete(&controller->certs); + + ns_dyn_mem_free(controller); + + return 0; +} + +int8_t ws_pae_controller_certificate_chain_set(const arm_certificate_chain_entry_s *new_chain) +{ + ns_list_foreach(pae_controller_t, entry, &pae_controller_list) { + // Delete previous information + sec_prot_certs_delete(&entry->certs); + + if (new_chain->cert_chain[0]) { + cert_chain_entry_t *root_ca_chain = sec_prot_certs_chain_entry_create(); + sec_prot_certs_cert_set(root_ca_chain, 0, (uint8_t *) new_chain->cert_chain[0], new_chain->cert_len[0]); + sec_prot_certs_chain_list_add(&entry->certs.trusted_cert_chain_list, root_ca_chain); + } + + if (new_chain->cert_chain[1] && new_chain->key_chain[1]) { + sec_prot_certs_cert_set(&entry->certs.own_cert_chain, 0, (uint8_t *) new_chain->cert_chain[1], new_chain->cert_len[1]); + uint8_t key_len = strlen((char *) new_chain->key_chain[1]) + 1; + sec_prot_certs_priv_key_set(&entry->certs.own_cert_chain, (uint8_t *) new_chain->key_chain[1], key_len); + } + } + + return 0; +} + +int8_t ws_pae_controller_border_router_addr_write(protocol_interface_info_entry_t *interface_ptr, const uint8_t *eui_64) +{ + if (!interface_ptr || !eui_64) { + return -1; + } + + pae_controller_t *controller = ws_pae_controller_get(interface_ptr); + if (!controller) { + return -1; + } + + if (controller->pae_br_addr_write) { + return controller->pae_br_addr_write(interface_ptr, eui_64); + } else { + memcpy(controller->br_eui_64, eui_64, 8); + } + + return 0; + +} + +int8_t ws_pae_controller_border_router_addr_read(protocol_interface_info_entry_t *interface_ptr, uint8_t *eui_64) +{ + if (!interface_ptr || !eui_64) { + return -1; + } + + pae_controller_t *controller = ws_pae_controller_get(interface_ptr); + if (!controller) { + return -1; + } + + if (controller->pae_br_addr_read) { + return controller->pae_br_addr_read(interface_ptr, eui_64); + } else { + memcpy(eui_64, controller->br_eui_64, 8); + } + + return 0; +} + +void ws_pae_controller_timer(uint16_t ticks) +{ + ns_list_foreach(pae_controller_t, entry, &pae_controller_list) { + if (entry->pae_timer) { + entry->pae_timer(ticks); + } + } +} + +static pae_controller_t *ws_pae_controller_get(protocol_interface_info_entry_t *interface_ptr) +{ + ns_list_foreach(pae_controller_t, entry, &pae_controller_list) { + if (entry->interface_ptr == interface_ptr) { + return entry; + } + } + + return NULL; +} + +#endif /* HAVE_WS */ + diff --git a/source/6LoWPAN/ws/ws_pae_controller.h b/source/6LoWPAN/ws/ws_pae_controller.h new file mode 100644 index 0000000000..db1115534f --- /dev/null +++ b/source/6LoWPAN/ws/ws_pae_controller.h @@ -0,0 +1,236 @@ +/* + * Copyright (c) 2018-2019, Arm Limited and affiliates. + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef WS_PAE_CONTROLLER_H_ +#define WS_PAE_CONTROLLER_H_ + +#ifdef HAVE_WS + +/** + * ws_pae_controller_set_target sets EAPOL target for PAE supplicant + * + * \param interface_ptr interface + * \param target_pan_id EAPOL target PAN ID + * \param target_eui_64 EAPOL target + * + * \return < 0 failure + * \return >= 0 success + * + */ +int8_t ws_pae_controller_set_target(protocol_interface_info_entry_t *interface_ptr, uint16_t target_pan_id, uint8_t *target_eui_64); + +/** + * ws_pae_controller_authenticate start PAE supplicant authentication + * + * \param interface_ptr interface + * + * \return < 0 failure + * \return >= 0 success + * + */ +int8_t ws_pae_controller_authenticate(protocol_interface_info_entry_t *interface_ptr); + +/** + * ws_pae_controller_authenticator_start start PAE authenticator + * + * \param interface_ptr interface + * \param local_port local port + * \param remote_addr remote address + * \param remote_port remote port + * + * \return < 0 failure + * \return >= 0 success + * + */ +int8_t ws_pae_controller_authenticator_start(protocol_interface_info_entry_t *interface_ptr, uint16_t local_port, const uint8_t *remote_addr, uint16_t remote_port); + +/** + * ws_pae_controller_init initializes PAE controller + * + * \param interface_ptr interface + * + * \return < 0 failure + * \return >= 0 success + * + */ +int8_t ws_pae_controller_init(protocol_interface_info_entry_t *interface_ptr); + +/** + * ws_pae_controller_init initializes PAE supplicant + * + * \param interface_ptr interface + * + * \return < 0 failure + * \return >= 0 success + * + */ +int8_t ws_pae_controller_supp_init(protocol_interface_info_entry_t *interface_ptr); + +/** + * ws_pae_controller_init initializes PAE authenticator + * + * \param interface_ptr interface + * + * \return < 0 failure + * \return >= 0 success + * + */ +int8_t ws_pae_controller_auth_init(protocol_interface_info_entry_t *interface_ptr); + +/** + * ws_pae_controller_stop stop PAE controller (e.g. on interface down) + * + * \param interface_ptr interface + * + * \return < 0 failure + * \return >= 0 success + * + */ +int8_t ws_pae_controller_stop(protocol_interface_info_entry_t *interface_ptr); + +/** + * ws_pae_controller_delete delete PAE controller (e.g. failure to create interface) + * + * \param interface_ptr interface + * + * \return < 0 failure + * \return >= 0 success + * + */ +int8_t ws_pae_controller_delete(protocol_interface_info_entry_t *interface_ptr); + +/** + * ws_pae_controller_certificate_chain_set set certificate chain + * + * \param chain certificate chain + * + * \return < 0 failure + * \return >= 0 success + * + */ +int8_t ws_pae_controller_certificate_chain_set(const arm_certificate_chain_entry_s *chain); + +/** + * ws_pae_controller_nw_info_set set network information + * + * \param interface_ptr interface + * \param pan_id PAD ID + * \param network_name network name + * + * \return < 0 failure + * \return >= 0 success + * + */ +int8_t ws_pae_controller_nw_info_set(protocol_interface_info_entry_t *interface_ptr, uint16_t pan_id, char *network_name); + +/** + * ws_pae_controller_nw_key_valid network key is valid i.e. used successfully on bootstrap + * + * \param interface_ptr interface + * + * \return < 0 failure + * \return >= 0 success + * + */ +int8_t ws_pae_controller_nw_key_valid(protocol_interface_info_entry_t *interface_ptr); + +/** + * ws_pae_controller_border_router_addr_write write border router address + * + * \param interface_ptr interface + * \param eui_64 pointer to EUI-64 + * + * \return < 0 failure + * \return >= 0 success + * + */ +int8_t ws_pae_controller_border_router_addr_write(protocol_interface_info_entry_t *interface_ptr, const uint8_t *eui_64); + +/** + * ws_pae_controller_border_router_addr_read read border router address + * + * \param interface_ptr interface + * \param eui_64 pointer to EUI-64 + * + * \return < 0 failure + * \return >= 0 success + * + */ +int8_t ws_pae_controller_border_router_addr_read(protocol_interface_info_entry_t *interface_ptr, uint8_t *eui_64); + +/** + * ws_pae_controller_key_insert new GTK key available callback + * + * \param interface_ptr interface + * \param gtk_index index of the new GTK key + * \param gtk new GTK key + * + */ +typedef void ws_pae_controller_key_insert(protocol_interface_info_entry_t *interface_ptr, uint8_t gtk_index, uint8_t *gtk); + +/** + * ws_pae_controller_auth_completed authentication completed callback + * + * \param interface_ptr interface + * \param success true if authentication was successful + * + */ +typedef void ws_pae_controller_auth_completed(protocol_interface_info_entry_t *interface_ptr, bool success); + +/** + * ws_pae_controller_cb_register register PEA controller callbacks + * + * \param interface_ptr interface + * \param completed authentication completed callback + * \param key_insert GTK key insert callback + * + * \return < 0 failure + * \return >= 0 success + * + */ +int8_t ws_pae_controller_cb_register(protocol_interface_info_entry_t *interface_ptr, ws_pae_controller_auth_completed *completed, ws_pae_controller_key_insert *key_insert); + +/** + * ws_pae_controller_timer PAE controller timer call + * + * \param ticks elapsed ticks + * + */ +void ws_pae_controller_timer(uint16_t ticks); + +#else + +#define ws_pae_controller_set_target(interface_ptr, target_pan_id, target_dest_eui_64) +#define ws_pae_controller_authenticate(interface_ptr) + +#define ws_pae_controller_authenticator_start(interface_ptr, local_port, remote_address, remote_port) + +#define ws_pae_controller_border_router_addr_write(interface_ptr, eui_64) -1 +#define ws_pae_controller_border_router_addr_read(interface_ptr, eui_64) -1 + +#define ws_pae_controller_init(interface_ptr) 1 +#define ws_pae_controller_supp_init(interface_ptr) 1 +#define ws_pae_controller_auth_init(interface_ptr) 1 + +#define ws_pae_controller_stop(interface_ptr) +#define ws_pae_controller_delete(interface_ptr) +#define ws_pae_controller_cb_register(interface_ptr, completed, key_insert) 1 +#define ws_pae_controller_timer(ticks) + +#endif + +#endif /* WS_PAE_CONTROLLER_H_ */ diff --git a/source/6LoWPAN/ws/ws_pae_lib.c b/source/6LoWPAN/ws/ws_pae_lib.c new file mode 100644 index 0000000000..3d613e10f9 --- /dev/null +++ b/source/6LoWPAN/ws/ws_pae_lib.c @@ -0,0 +1,289 @@ +/* + * Copyright (c) 2018-2019, Arm Limited and affiliates. + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "nsconfig.h" +#include +#include "ns_types.h" +#include "ns_list.h" +#include "ns_trace.h" +#include "nsdynmemLIB.h" +#include "fhss_config.h" +#include "NWK_INTERFACE/Include/protocol.h" +#include "6LoWPAN/ws/ws_config.h" +#include "Security/kmp/kmp_addr.h" +#include "Security/kmp/kmp_api.h" +#include "Security/protocols/sec_prot_certs.h" +#include "Security/protocols/sec_prot_keys.h" +#include "6LoWPAN/ws/ws_pae_lib.h" + +#ifdef HAVE_WS + +#define TRACE_GROUP "wspl" + +void ws_pae_lib_kmp_list_init(kmp_list_t *kmp_list) +{ + ns_list_init(kmp_list); +} + +kmp_entry_t *ws_pae_lib_kmp_list_add(kmp_list_t *kmp_list, kmp_api_t *kmp) +{ + // Already in list + kmp_entry_t *entry = ws_pae_lib_kmp_list_entry_get(kmp_list, kmp); + if (entry) { + return entry; + } + + entry = ns_dyn_mem_alloc(sizeof(kmp_entry_t)); + if (!entry) { + return NULL; + } + entry->kmp = kmp; + entry->timer_running = false; + + ns_list_add_to_end(kmp_list, entry); + + return entry; +} + +int8_t ws_pae_lib_kmp_list_delete(kmp_list_t *kmp_list, kmp_api_t *kmp) +{ + kmp_entry_t *entry = ws_pae_lib_kmp_list_entry_get(kmp_list, kmp); + + if (entry) { + ns_list_remove(kmp_list, entry); + kmp_api_delete(entry->kmp); + ns_dyn_mem_free(entry); + return 0; + } + + return -1; +} + +kmp_api_t *ws_pae_lib_kmp_list_type_get(kmp_list_t *kmp_list, kmp_type_e type) +{ + ns_list_foreach(kmp_entry_t, cur, kmp_list) { + if (kmp_api_type_get(cur->kmp) == type) { + return cur->kmp; + } + } + + return 0; +} + +void ws_pae_lib_kmp_list_free(kmp_list_t *kmp_list) +{ + ns_list_foreach_safe(kmp_entry_t, cur, kmp_list) { + kmp_api_delete(cur->kmp); + ns_dyn_mem_free(cur); + } +} + +kmp_entry_t *ws_pae_lib_kmp_list_entry_get(kmp_list_t *kmp_list, kmp_api_t *kmp) +{ + ns_list_foreach(kmp_entry_t, cur, kmp_list) { + if (cur->kmp == kmp) { + return cur; + } + } + + return 0; +} + +void ws_pae_lib_kmp_timer_start(kmp_list_t *kmp_list, kmp_entry_t *entry) +{ + if (ns_list_get_first(kmp_list) != entry) { + ns_list_remove(kmp_list, entry); + ns_list_add_to_start(kmp_list, entry); + } + entry->timer_running = true; +} + +void ws_pae_lib_kmp_timer_stop(kmp_list_t *kmp_list, kmp_entry_t *entry) +{ + if (ns_list_get_last(kmp_list) != entry) { + ns_list_remove(kmp_list, entry); + ns_list_add_to_end(kmp_list, entry); + } + entry->timer_running = false; +} + +bool ws_pae_lib_kmp_timer_update(kmp_list_t *kmp_list, uint16_t ticks, ws_pae_lib_kmp_timer_timeout timeout) +{ + if (ns_list_is_empty(kmp_list)) { + return false; + } + + bool timer_running = false; + + ns_list_foreach_safe(kmp_entry_t, entry, kmp_list) { + if (entry->timer_running) { + timeout(entry->kmp, ticks); + timer_running = true; + } else { + break; + } + } + + return timer_running; +} + +void ws_pae_lib_supp_list_init(supp_list_t *supp_list) +{ + ns_list_init(supp_list); +} + +supp_entry_t *ws_pae_lib_supp_list_add(supp_list_t *supp_list, const kmp_addr_t *addr) +{ + supp_entry_t *entry = ns_dyn_mem_alloc(sizeof(supp_entry_t)); + + if (!entry) { + return NULL; + } + + ws_pae_lib_supp_init(entry); + + entry->addr = kmp_address_create(KMP_ADDR_EUI_64_AND_IP, 0); + kmp_address_copy(entry->addr, addr); + + ns_list_add_to_end(supp_list, entry); + + return entry; +} + +int8_t ws_pae_lib_supp_list_remove(supp_list_t *supp_list, supp_entry_t *supp) +{ + ns_list_remove(supp_list, supp); + + ws_pae_lib_supp_delete(supp); + + ns_dyn_mem_free(supp); + return 0; +} + +supp_entry_t *ws_pae_lib_supp_list_entry_eui_64_get(const supp_list_t *supp_list, const uint8_t *eui_64) +{ + ns_list_foreach(supp_entry_t, cur, supp_list) { + if (memcmp(kmp_address_eui_64_get(cur->addr), eui_64, 8) == 0) { + return cur; + } + } + + return 0; +} + +void ws_pae_lib_supp_list_delete(supp_list_t *supp_list) +{ + ns_list_foreach_safe(supp_entry_t, entry, supp_list) { + ws_pae_lib_supp_list_remove(supp_list, entry); + } +} + +bool ws_pae_lib_supp_list_timer_update(supp_list_t *active_supp_list, supp_list_t *inactive_supp_list, uint16_t ticks, ws_pae_lib_kmp_timer_timeout timeout) +{ + bool timer_running = false; + + ns_list_foreach_safe(supp_entry_t, entry, active_supp_list) { + bool running = ws_pae_lib_supp_timer_update(entry, ticks, timeout); + if (running) { + timer_running = true; + } else { + ws_pae_lib_supp_list_to_inactive(active_supp_list, inactive_supp_list, entry); + } + } + + return timer_running; +} + +void ws_pae_lib_supp_init(supp_entry_t *entry) +{ + ws_pae_lib_kmp_list_init(&entry->kmp_list); + entry->addr = 0; + memset(&entry->sec_keys, 0, sizeof(sec_prot_keys_t)); + entry->ticks = 0; + entry->active = true; +} + +void ws_pae_lib_supp_delete(supp_entry_t *entry) +{ + ws_pae_lib_kmp_list_free(&entry->kmp_list); + kmp_address_delete(entry->addr); +} + +bool ws_pae_lib_supp_timer_update(supp_entry_t *entry, uint16_t ticks, ws_pae_lib_kmp_timer_timeout timeout) +{ + // Updates KMP timers and calls timeout callback + bool keep_timer_running = ws_pae_lib_kmp_timer_update(&entry->kmp_list, ticks, timeout); + + // If KMPs are not active updates supplicant timer + if (!keep_timer_running) { + if (entry->ticks > ticks) { + keep_timer_running = true; + entry->ticks -= ticks; + } else { + entry->ticks = 0; + } + } + + return keep_timer_running; +} + +void ws_pae_lib_supp_timer_ticks_set(supp_entry_t *entry, uint32_t ticks) +{ + entry->ticks = ticks; +} + +void ws_pae_lib_supp_list_to_active(supp_list_t *active_supp_list, supp_list_t *inactive_supp_list, supp_entry_t *entry) +{ + if (entry->active) { + return; + } + + tr_debug("PAE: to active, eui-64: %s", trace_array(kmp_address_eui_64_get(entry->addr), 8)); + + ns_list_remove(inactive_supp_list, entry); + ns_list_add_to_start(active_supp_list, entry); + + entry->active = true; + entry->ticks = 0; + + // Adds relay address data + kmp_addr_t *addr = kmp_address_create(KMP_ADDR_EUI_64_AND_IP, kmp_address_eui_64_get(entry->addr)); + kmp_address_delete(entry->addr); + entry->addr = addr; +} + +void ws_pae_lib_supp_list_to_inactive(supp_list_t *active_supp_list, supp_list_t *inactive_supp_list, supp_entry_t *entry) +{ + if (!entry->active) { + return; + } + + tr_debug("PAE: to inactive, eui-64: %s", trace_array(kmp_address_eui_64_get(entry->addr), 8)); + + ns_list_remove(active_supp_list, entry); + ns_list_add_to_start(inactive_supp_list, entry); + + entry->active = false; + entry->ticks = 0; + + // Removes relay address data + kmp_addr_t *addr = kmp_address_create(KMP_ADDR_EUI_64, kmp_address_eui_64_get(entry->addr)); + kmp_address_delete(entry->addr); + entry->addr = addr; +} + +#endif /* HAVE_WS */ diff --git a/source/6LoWPAN/ws/ws_pae_lib.h b/source/6LoWPAN/ws/ws_pae_lib.h new file mode 100644 index 0000000000..6ccc888447 --- /dev/null +++ b/source/6LoWPAN/ws/ws_pae_lib.h @@ -0,0 +1,271 @@ +/* + * Copyright (c) 2018-2019, Arm Limited and affiliates. + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef WS_PAE_LIB_H_ +#define WS_PAE_LIB_H_ + +typedef struct { + kmp_api_t *kmp; /**< KMP API */ + bool timer_running; /**< Timer running inside KMP */ + ns_list_link_t link; /**< Link */ +} kmp_entry_t; + +typedef NS_LIST_HEAD(kmp_entry_t, link) kmp_list_t; + +typedef struct { + kmp_list_t kmp_list; /**< Ongoing KMP negotiations */ + kmp_addr_t *addr; /**< EUI-64 (Relay IP address, Relay port) */ + sec_prot_keys_t sec_keys; /**< Security keys */ + uint32_t ticks; /**< Ticks */ + bool active; /**< Is active */ + ns_list_link_t link; /**< Link */ +} supp_entry_t; + +typedef NS_LIST_HEAD(supp_entry_t, link) supp_list_t; + +/** + * ws_pae_lib_kmp_list_init initializes KMP list + * + * \param kmp_list KMP list + * + * \return < 0 failure + * \return >= 0 success + * + */ +void ws_pae_lib_kmp_list_init(kmp_list_t *kmp_list); + +/** + * ws_pae_lib_kmp_list_add adds KMP to KMP list + * + * \param kmp_list KMP list + * \param kmp KMP + * + * \return KMP list entry on success + * \return NULL on failure + * + */ +kmp_entry_t *ws_pae_lib_kmp_list_add(kmp_list_t *kmp_list, kmp_api_t *kmp); + +/** + * ws_pae_lib_kmp_list_delete deletes KMP from KMP list + * + * \param kmp_list KMP list + * \param kmp KMP + * + * \return < 0 failure + * \return >= 0 success + * + */ +int8_t ws_pae_lib_kmp_list_delete(kmp_list_t *kmp_list, kmp_api_t *kmp); + +/** + * ws_pae_lib_kmp_list_free frees KMP list + * + * \param kmp_list KMP list + * + */ +void ws_pae_lib_kmp_list_free(kmp_list_t *kmp_list); + +/** + * ws_pae_lib_kmp_list_type_get gets KMP entry from KMP list based on KMP type + * + * \param kmp_list KMP list + * \param type type + * + * \return KMP on success + * \return NULL on failure + * + */ +kmp_api_t *ws_pae_lib_kmp_list_type_get(kmp_list_t *kmp_list, kmp_type_e type); + +/** + * ws_pae_lib_kmp_list_entry_get gets KMP entry from KMP list based on KMP + * + * \param kmp_list KMP list + * \param kmp KMP + * + * \return KMP list entry on success + * \return NULL on failure + * + */ +kmp_entry_t *ws_pae_lib_kmp_list_entry_get(kmp_list_t *kmp_list, kmp_api_t *kmp); + +/** + * ws_pae_lib_kmp_timer_start starts KMP timer + * + * \param kmp_list KMP list + * \param entry KMP list entry + * + */ +void ws_pae_lib_kmp_timer_start(kmp_list_t *kmp_list, kmp_entry_t *entry); + +/** + * ws_pae_lib_kmp_timer_stop stops KMP timer + * + * \param kmp_list KMP list + * \param entry KMP list entry + * + */ +void ws_pae_lib_kmp_timer_stop(kmp_list_t *kmp_list, kmp_entry_t *entry); + +/** + * ws_pae_lib_kmp_timer_timeout KMP timer timeout callback + * + * \param kmp KMP + * \param ticks timer ticks + * + */ +typedef void ws_pae_lib_kmp_timer_timeout(kmp_api_t *kmp, uint16_t ticks); + +/** + * ws_pae_lib_kmp_timer_update updates KMP timers on KMP list + * + * \param kmp_list KMP list + * \param ticks timer ticks + * \param timeout callback to call on timeout + * + * \return true KMP list has KMPs + * \return false no KMPs on KMP list + * + */ +bool ws_pae_lib_kmp_timer_update(kmp_list_t *kmp_list, uint16_t ticks, ws_pae_lib_kmp_timer_timeout timeout); + + + + + + +/** + * ws_pae_lib_supp_list_init initiates supplicant list + * + * \param supp_list supplicant list + * + */ +void ws_pae_lib_supp_list_init(supp_list_t *supp_list); + +/** + * ws_pae_lib_supp_list_add adds entry to supplicant list + * + * \param supp_list supplicant list + * \param addr address + * + * \return supplicant list entry on success + * \return NULL on failure + */ +supp_entry_t *ws_pae_lib_supp_list_add(supp_list_t *supp_list, const kmp_addr_t *addr); + +/** + * ws_pae_lib_supp_list_add removes entry from supplicant list + * + * \param supp_list supplicant list + * \param entry entry + * + * \return < 0 failure + * \return >= 0 success + */ +int8_t ws_pae_lib_supp_list_remove(supp_list_t *supp_list, supp_entry_t *entry); + +/** + * ws_pae_lib_supp_list_entry_eui_64_get gets entry from supplicant list based on EUI-64 + * + * \param supp_list supplicant list + * \param eui_64 EUI-64 + * + * \return supplicant list entry on success + * \return NULL on failure + */ +supp_entry_t *ws_pae_lib_supp_list_entry_eui_64_get(const supp_list_t *supp_list, const uint8_t *eui_64); + +/** + * ws_pae_lib_supp_list_delete deletes supplicant list + * + * \param supp_list supplicant list + * + */ +void ws_pae_lib_supp_list_delete(supp_list_t *supp_list); + +/** + * ws_pae_lib_supp_list_timer_update updates timers on supplicant list + * + * \param active_supp_list list of active supplicants + * \param inactive_supp_list list of inactive supplicants + * \param ticks timer ticks + * \param timeout callback to call on timeout + * + * \return true timer needs still to be running + * \return false timer can be stopped + */ +bool ws_pae_lib_supp_list_timer_update(supp_list_t *active_supp_list, supp_list_t *inactive_supp_list, uint16_t ticks, ws_pae_lib_kmp_timer_timeout timeout); + +/** + * ws_pae_lib_supp_list_timer_update updates supplicant timers + * + * \param entry supplicant entry + * \param ticks timer ticks + * \param timeout callback to call on timeout + * + * \return true timer needs still to be running + * \return false timer can be stopped + */ +bool ws_pae_lib_supp_timer_update(supp_entry_t *entry, uint16_t ticks, ws_pae_lib_kmp_timer_timeout timeout); + +/** + * ws_pae_lib_supp_init initiates supplicant entry + * + * \param entry supplicant entry + * + */ +void ws_pae_lib_supp_init(supp_entry_t *entry); + +/** + * ws_pae_lib_supp_delete deletes supplicant entry + * + * \param entry supplicant entry + * + */ +void ws_pae_lib_supp_delete(supp_entry_t *entry); + +/** + * ws_pae_lib_supp_timer_ticks_set sets supplicant timer ticks + * + * \param entry supplicant entry + * \param ticks ticks + * + */ +void ws_pae_lib_supp_timer_ticks_set(supp_entry_t *entry, uint32_t ticks); + +/** + * ws_pae_lib_supp_list_to_active move supplicant to active supplicants list + * + * \param active_supp_list list of active supplicants + * \param inactive_supp_list list of inactive supplicants + * \param entry supplicant entry + * + */ +void ws_pae_lib_supp_list_to_active(supp_list_t *active_supp_list, supp_list_t *inactive_supp_list, supp_entry_t *entry); + +/** + * ws_pae_lib_supp_list_to_inactive move supplicant to inactive supplicants list + * + * \param active_supp_list list of active supplicants + * \param inactive_supp_list list of inactive supplicants + * \param entry supplicant entry + * + */ +void ws_pae_lib_supp_list_to_inactive(supp_list_t *active_supp_list, supp_list_t *inactive_supp_list, supp_entry_t *entry); + +#endif /* WS_PAE_AUTH_H_ */ diff --git a/source/6LoWPAN/ws/ws_pae_nvm_data.c b/source/6LoWPAN/ws/ws_pae_nvm_data.c new file mode 100644 index 0000000000..b528ef267a --- /dev/null +++ b/source/6LoWPAN/ws/ws_pae_nvm_data.c @@ -0,0 +1,214 @@ +/* + * Copyright (c) 2019, Arm Limited and affiliates. + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "nsconfig.h" +#include +#include "ns_types.h" +#include "ns_list.h" +#include "ns_trace.h" +#include "nsdynmemLIB.h" +#include "common_functions.h" +#include "6LoWPAN/ws/ws_config.h" +#include "ns_file_system.h" +#include "Security/protocols/sec_prot_certs.h" +#include "Security/protocols/sec_prot_keys.h" +#include "6LoWPAN/ws/ws_pae_nvm_store.h" +#include "6LoWPAN/ws/ws_pae_nvm_data.h" + +#ifdef HAVE_WS + +#define TRACE_GROUP "wsnv" + +#define PAE_NVM_NW_INFO_TAG 1 +#define PAE_NVM_KEYS_TAG 2 + +// pan_id (2) + network name (33) + (GTK set (1) + GTK lifetime (4) + GTK (16)) * 4 +#define PAE_NVM_NW_INFO_LEN 2 + 33 + (1 + 4 + GTK_LEN) * GTK_NUM + +// PTK EUI-64 set (1) + PTK EUI-64 (8) + PMK set (1) + PMK (32) + PMK replay counter (8) + PTK set (1) + PTK (48) +#define PAE_NVM_KEYS_LEN 1 + 8 + 1 + PMK_LEN + 8 + 1 + PTK_LEN + +nvm_tlv_entry_t *ws_pae_nvm_store_nw_info_tlv_create(uint16_t pan_id, char *nw_name, sec_prot_gtk_keys_t *gtks) +{ + nvm_tlv_entry_t *tlv_entry = ns_dyn_mem_temporary_alloc(sizeof(nvm_tlv_entry_t) + PAE_NVM_NW_INFO_LEN); + if (!tlv_entry) { + return NULL; + } + + tlv_entry->tag = PAE_NVM_NW_INFO_TAG; + tlv_entry->len = PAE_NVM_NW_INFO_LEN; + + uint8_t *tlv = ((uint8_t *) &tlv_entry->tag) + NVM_TLV_FIXED_LEN; + + tlv = common_write_16_bit(pan_id, tlv); + + memset(tlv, 0, 33); + strncpy((char *)tlv, nw_name, 32); + tlv += 33; + + for (uint8_t i = 0; i < GTK_NUM; i++) { + if (sec_prot_keys_gtk_is_set(gtks, i)) { + *tlv++ = 1; // GTK is set + uint32_t lifetime = sec_prot_keys_gtk_lifetime_get(gtks, i); + tlv = common_write_32_bit(lifetime, tlv); + + uint8_t *gtk = sec_prot_keys_gtk_get(gtks, i); + memcpy(tlv, gtk, GTK_LEN); + tlv += GTK_LEN; + } else { + *tlv++ = 0; // GTK is not set + memset(tlv, 0, 4 + GTK_LEN); + tlv += 4 + GTK_LEN; + } + } + + tr_debug("NVM NW_INFO write PAN ID %i name: %s", pan_id, nw_name); + + return tlv_entry; +} + +int8_t ws_pae_nvm_store_nw_info_tlv_read(nvm_tlv_entry_t *tlv_entry, uint16_t *pan_id, char *nw_name, sec_prot_gtk_keys_t *gtks) +{ + if (!tlv_entry || !pan_id || !nw_name || !gtks) { + return -1; + } + + if (tlv_entry->tag != PAE_NVM_NW_INFO_TAG || tlv_entry->len != PAE_NVM_NW_INFO_LEN) { + return -1; + } + + uint8_t *tlv = ((uint8_t *) &tlv_entry->tag) + NVM_TLV_FIXED_LEN; + + *pan_id = common_read_16_bit(tlv); + tlv += 2; + + memset(nw_name, 0, 33); + strncpy(nw_name, (char *) tlv, 32); + tlv += 33; + + for (uint8_t i = 0; i < GTK_NUM; i++) { + if (*tlv++ == 1) { /* GTK is set */ + uint32_t lifetime = common_read_32_bit(tlv); + tlv += 4; + sec_prot_keys_gtk_set(gtks, i, tlv); + sec_prot_keys_gtk_lifetime_set(gtks, i, lifetime); + tlv += GTK_LEN; + } else { + tlv += 4 + GTK_LEN; + } + } + sec_prot_keys_gtks_updated_reset(gtks); + + tr_debug("NVM NW_INFO read PAN ID %i name: %s", *pan_id, nw_name); + + return 0; +} + +nvm_tlv_entry_t *ws_pae_nvm_store_keys_tlv_create(sec_prot_keys_t *sec_keys) +{ + nvm_tlv_entry_t *tlv_entry = ns_dyn_mem_temporary_alloc(sizeof(nvm_tlv_entry_t) + PAE_NVM_KEYS_LEN); + if (!tlv_entry) { + return NULL; + } + + tlv_entry->tag = PAE_NVM_KEYS_TAG; + tlv_entry->len = PAE_NVM_KEYS_LEN; + + uint8_t *tlv = ((uint8_t *) &tlv_entry->tag) + NVM_TLV_FIXED_LEN; + + uint8_t *eui_64 = sec_prot_keys_ptk_eui_64_get(sec_keys); + if (eui_64) { + *tlv++ = 1; + memcpy(tlv, eui_64, 8); + } else { + *tlv++ = 0; + memset(tlv, 0, 8); + } + tlv += 8; + + uint8_t *pmk = sec_prot_keys_pmk_get(sec_keys); + if (pmk) { + *tlv++ = 1; + memcpy(tlv, pmk, PMK_LEN); + } else { + *tlv++ = 0; + memset(tlv, 0, PMK_LEN); + } + tlv += PMK_LEN; + + uint64_t counter = sec_prot_keys_pmk_replay_cnt_get(sec_keys); + tlv = common_write_64_bit(counter, tlv); + + uint8_t *ptk = sec_prot_keys_ptk_get(sec_keys); + if (ptk) { + *tlv++ = 1; + memcpy(tlv, ptk, PTK_LEN); + } else { + *tlv++ = 0; + memset(tlv, 0, PTK_LEN); + } + tlv += PTK_LEN; + + tr_debug("NVM KEYS write"); + + return tlv_entry; +} + +int8_t ws_pae_nvm_store_keys_tlv_read(nvm_tlv_entry_t *tlv_entry, sec_prot_keys_t *sec_keys) +{ + if (!tlv_entry || !sec_keys) { + return -1; + } + + if (tlv_entry->tag != PAE_NVM_KEYS_TAG || tlv_entry->len != PAE_NVM_KEYS_LEN) { + return -1; + } + + uint8_t *tlv = ((uint8_t *) &tlv_entry->tag) + NVM_TLV_FIXED_LEN; + + // EUI-64 set */ + if (*tlv++ == 1) { + sec_prot_keys_ptk_eui_64_write(sec_keys, tlv); + } + tlv += 8; + + // PMK set + if (*tlv++ == 1) { + sec_prot_keys_pmk_write(sec_keys, tlv); + } + tlv += PMK_LEN; + + uint64_t counter = common_read_64_bit(tlv); + tlv += 8; + sec_prot_keys_pmk_replay_cnt_set(sec_keys, counter); + + // PTK set + if (*tlv++ == 1) { + sec_prot_keys_ptk_write(sec_keys, tlv); + } + + tlv += PTK_LEN; + + sec_prot_keys_updated_reset(sec_keys); + + tr_debug("NVM KEYS read"); + + return 0; +} + +#endif /* HAVE_WS */ + diff --git a/source/6LoWPAN/ws/ws_pae_nvm_data.h b/source/6LoWPAN/ws/ws_pae_nvm_data.h new file mode 100644 index 0000000000..24d4af8a48 --- /dev/null +++ b/source/6LoWPAN/ws/ws_pae_nvm_data.h @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2018-2019, Arm Limited and affiliates. + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef WS_PAE_NVM_DATA_H_ +#define WS_PAE_NVM_DATA_H_ + +/** + * ws_pae_nvm_store_nw_info_tlv_create create NVM network info TLV + * + * \param pan_id PAN ID + * \param nw_name network name + * \param gtks GTK keys + * + * \return TLV entry or NULL + * + */ +nvm_tlv_entry_t *ws_pae_nvm_store_nw_info_tlv_create(uint16_t pan_id, char *nw_name, sec_prot_gtk_keys_t *gtks); + +/** + * ws_pae_nvm_store_nw_info_tlv_read read from NVM network info TLV + * + * \param tlv_entry TLV entry + * \param pan_id PAN ID + * \param nw_name network name + * \param gtks GTK keys + * + * \return < 0 failure + * \return >= 0 success + * + */ +int8_t ws_pae_nvm_store_nw_info_tlv_read(nvm_tlv_entry_t *tlv_entry, uint16_t *pan_id, char *nw_name, sec_prot_gtk_keys_t *gtks); + +/** + * ws_pae_nvm_store_keys_tlv_create create NVM keys TLV + * + * \param sec_keys security keys + * + * \return TLV entry or NULL + * + */ +nvm_tlv_entry_t *ws_pae_nvm_store_keys_tlv_create(sec_prot_keys_t *sec_keys); + +/** + * ws_pae_nvm_store_nw_info_tlv_read read from NVM keys TLV + * + * \param tlv_entry TLV entry + * \param sec_keys security keys + * + * \return < 0 failure + * \return >= 0 success + * + */ +int8_t ws_pae_nvm_store_keys_tlv_read(nvm_tlv_entry_t *tlv_entry, sec_prot_keys_t *sec_keys); + +#endif /* WS_PAE_NVM_DATA_H_ */ diff --git a/source/6LoWPAN/ws/ws_pae_nvm_store.c b/source/6LoWPAN/ws/ws_pae_nvm_store.c new file mode 100644 index 0000000000..568c360206 --- /dev/null +++ b/source/6LoWPAN/ws/ws_pae_nvm_store.c @@ -0,0 +1,204 @@ +/* + * Copyright (c) 2019, 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 +#include "ns_types.h" +#include "ns_list.h" +#include "ns_trace.h" +#include "nsdynmemLIB.h" +#include "common_functions.h" +#include "6LoWPAN/ws/ws_config.h" +#include "ns_file_system.h" +#include "Security/protocols/sec_prot_certs.h" +#include "Security/protocols/sec_prot_keys.h" +#include "6LoWPAN/ws/ws_pae_nvm_store.h" + +#ifdef HAVE_WS + +#define TRACE_GROUP "wsnv" + +#define MAX_ROOT_PATH_LEN 200 + +static uint16_t ws_pae_nvm_store_path_len_get(const char *file_name); +static const char *ws_pae_nvm_store_get_root_path(void); +static int8_t ws_pae_nvm_store_root_path_valid(void); +static int8_t ws_pae_nvm_store_create_path(char *fast_data_path, const char *file_name); +static int8_t ws_pae_nvm_store_write(const char *file_name, nvm_tlv_list_t *tlv_list); +static int8_t ws_pae_nvm_store_read(const char *file_name, nvm_tlv_list_t *tlv_list); + +int8_t ws_pae_nvm_store_tlv_file_write(const char *file, nvm_tlv_list_t *tlv_list) +{ + if (!ws_pae_nvm_store_root_path_valid()) { + return PAE_NVM_FILE_ROOT_PATH_INVALID; + } + + uint16_t path_len = ws_pae_nvm_store_path_len_get(file); + + char nw_info_path[path_len]; + + ws_pae_nvm_store_create_path(nw_info_path, file); + + return ws_pae_nvm_store_write(nw_info_path, tlv_list); +} + +int8_t ws_pae_nvm_store_tlv_file_read(const char *file, nvm_tlv_list_t *tlv_list) +{ + if (!ws_pae_nvm_store_root_path_valid()) { + return PAE_NVM_FILE_ROOT_PATH_INVALID; + } + + uint16_t path_len = ws_pae_nvm_store_path_len_get(file); + + char nw_info_path[path_len]; + + ws_pae_nvm_store_create_path(nw_info_path, file); + + return ws_pae_nvm_store_read(nw_info_path, tlv_list); +} + +static const char *ws_pae_nvm_store_get_root_path(void) +{ + char *path = ns_file_system_get_root_path(); + + if (NULL == path) { + return ""; + } + return path; +} + +static int8_t ws_pae_nvm_store_root_path_valid(void) +{ + if (NULL == ns_file_system_get_root_path()) { + return 0; + } + int path_len = strlen(ws_pae_nvm_store_get_root_path()); + if (path_len == 0 || path_len > MAX_ROOT_PATH_LEN) { + return 0; + } + return 1; +} + +static uint16_t ws_pae_nvm_store_path_len_get(const char *file_name) +{ + return strlen(file_name) + strlen(ws_pae_nvm_store_get_root_path()) + 1; +} + +static int8_t ws_pae_nvm_store_create_path(char *data_path, const char *file_name) +{ + strcpy(data_path, ws_pae_nvm_store_get_root_path()); + strcat(data_path, file_name); + return 0; +} + +static int8_t ws_pae_nvm_store_write(const char *file_name, nvm_tlv_list_t *tlv_list) +{ + FILE *fp = fopen(file_name, "w"); + if (fp == NULL) { + tr_error("NVM open error: %s", file_name); + return PAE_NVM_FILE_CANNOT_OPEN; + } + + uint16_t list_count = ns_list_count(tlv_list); + size_t n_bytes = fwrite(&list_count, 1, sizeof(uint16_t), fp); + if (n_bytes != sizeof(uint16_t)) { + tr_warning("NVM TLV list count write error"); + fclose(fp); + return PAE_NVM_FILE_WRITE_ERROR; + } + + bool failure = false; + + ns_list_foreach(nvm_tlv_entry_t, entry, tlv_list) { + n_bytes = fwrite(&entry->tag, 1, entry->len + NVM_TLV_FIXED_LEN, fp); + if (n_bytes != (size_t) entry->len + NVM_TLV_FIXED_LEN) { + failure = true; + break; + } + } + + fclose(fp); + if (failure) { + tr_error("NVM write error %s", file_name); + return PAE_NVM_FILE_WRITE_ERROR; + } else { + return PAE_NVM_FILE_SUCCESS; + } +} + +static int8_t ws_pae_nvm_store_read(const char *file_name, nvm_tlv_list_t *tlv_list) +{ + FILE *fp = fopen(file_name, "r"); + if (fp == NULL) { + tr_warning("File not found: %s", file_name); + return PAE_NVM_FILE_CANNOT_OPEN; + } + + uint16_t list_count; + size_t n_bytes = fread(&list_count, 1, sizeof(uint16_t), fp); + if (n_bytes != sizeof(uint16_t)) { + tr_warning("NVM TLV list count read error %s", file_name); + fclose(fp); + return PAE_NVM_FILE_READ_ERROR; + } + + bool failure = false; + + while (list_count-- > 0) { + nvm_tlv_entry_t entry_header; + n_bytes = fread(&entry_header.tag, 1, NVM_TLV_FIXED_LEN, fp); + if (n_bytes != NVM_TLV_FIXED_LEN) { + failure = true; + break; + } + uint16_t len = entry_header.len; + + nvm_tlv_entry_t *entry = ns_dyn_mem_temporary_alloc(sizeof(nvm_tlv_entry_t) + len); + if (!entry) { + failure = true; + break; + } + + memcpy(&entry->tag, &entry_header.tag, NVM_TLV_FIXED_LEN); + + if (len > 0) { + uint8_t *data_ptr = ((uint8_t *)&entry->tag) + NVM_TLV_FIXED_LEN; + n_bytes = fread(data_ptr, 1, len, fp); + if (n_bytes != len) { + ns_dyn_mem_free(entry); + failure = true; + break; + } + } + + ns_list_add_to_end(tlv_list, entry); + } + + fclose(fp); + + if (failure) { + tr_error("NVM read error %s", file_name); + return PAE_NVM_FILE_READ_ERROR; + } else { + return PAE_NVM_FILE_SUCCESS; // return how many bytes was written. + } +} + + +#endif /* HAVE_WS */ + diff --git a/source/6LoWPAN/ws/ws_pae_nvm_store.h b/source/6LoWPAN/ws/ws_pae_nvm_store.h new file mode 100644 index 0000000000..4fd0bf60b1 --- /dev/null +++ b/source/6LoWPAN/ws/ws_pae_nvm_store.h @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2018-2019, Arm Limited and affiliates. + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef WS_PAE_NVM_STORE_H_ +#define WS_PAE_NVM_STORE_H_ + +// tag + length +#define NVM_TLV_FIXED_LEN 4 + +typedef struct { + ns_list_link_t link; /**< Link */ + uint16_t tag; /**< Unique tag */ + uint16_t len; /**< Number of the bytes after the length field */ +} nvm_tlv_entry_t; + +typedef NS_LIST_HEAD(nvm_tlv_entry_t, link) nvm_tlv_list_t; + +#define PAE_NVM_FILE_SUCCESS 0 +#define PAE_NVM_FILE_READ_ERROR -1 +#define PAE_NVM_FILE_WRITE_ERROR -2 +#define PAE_NVM_FILE_VERSION_WRONG -3 +#define PAE_NVM_FILE_CANNOT_OPEN -4 +#define PAE_NVM_FILE_ROOT_PATH_INVALID -5 +#define PAE_NVM_FILE_PARAMETER_INVALID -6 +#define PAE_NVM_FILE_REMOVE_ERROR -7 + +/** + * ws_pae_nvm_store_tlv_file_write write a list of TLVs to file + * + * \param file file name + * \param tlv_list TLV list + * + * \return < 0 failure + * \return >= 0 success + * + */ +int8_t ws_pae_nvm_store_tlv_file_write(const char *file, nvm_tlv_list_t *tlv_list); + +/** + * ws_pae_nvm_store_tlv_file_read read a list of TLVs from file + * + * \param file file name + * \param tlv_list TLV list + * + * \return < 0 failure + * \return >= 0 success + * + */ +int8_t ws_pae_nvm_store_tlv_file_read(const char *file, nvm_tlv_list_t *tlv_list); + +#endif /* WS_PAE_NVM_STORE_H_ */ diff --git a/source/6LoWPAN/ws/ws_pae_supp.c b/source/6LoWPAN/ws/ws_pae_supp.c new file mode 100644 index 0000000000..73ba16943b --- /dev/null +++ b/source/6LoWPAN/ws/ws_pae_supp.c @@ -0,0 +1,930 @@ +/* + * Copyright (c) 2018-2019, Arm Limited and affiliates. + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "nsconfig.h" +#include +#include "ns_types.h" +#include "ns_list.h" +#include "ns_trace.h" +#include "nsdynmemLIB.h" +#include "fhss_config.h" +#include "eventOS_event.h" +#include "eventOS_scheduler.h" +#include "eventOS_event_timer.h" +#include "ns_address.h" +#include "NWK_INTERFACE/Include/protocol.h" +#include "RPL/rpl_protocol.h" +#include "RPL/rpl_control.h" +#include "RPL/rpl_data.h" +#include "6LoWPAN/ws/ws_config.h" +#include "Security/kmp/kmp_addr.h" +#include "Security/kmp/kmp_api.h" +#include "Security/protocols/sec_prot_certs.h" +#include "Security/protocols/sec_prot_keys.h" +#include "Security/protocols/key_sec_prot/key_sec_prot.h" +#include "Security/protocols/eap_tls_sec_prot/supp_eap_tls_sec_prot.h" +#include "Security/protocols/tls_sec_prot/tls_sec_prot.h" +#include "Security/protocols/fwh_sec_prot/supp_fwh_sec_prot.h" +#include "Security/protocols/gkh_sec_prot/supp_gkh_sec_prot.h" +#include "6LoWPAN/ws/ws_pae_controller.h" +#include "6LoWPAN/ws/ws_pae_supp.h" +#include "6LoWPAN/ws/ws_pae_lib.h" +#include "6LoWPAN/ws/ws_pae_nvm_store.h" +#include "6LoWPAN/ws/ws_pae_nvm_data.h" +#include "6LoWPAN/MAC/mpx_api.h" +#include "6LoWPAN/ws/ws_eapol_pdu.h" +#include "Security/kmp/kmp_eapol_pdu_if.h" + +#ifdef HAVE_WS +#ifdef HAVE_PAE_SUPP + +#define TRACE_GROUP "wsps" + +#define PAE_TASKLET_INIT 1 +#define PAE_TASKLET_EVENT 2 +#define PAE_TASKLET_TIMER 3 + +// Wait for for authenticator to continue with authentication (e.g. after EAP-TLS to initiate 4WH) +#define WAIT_FOR_AUTHENTICATION_TICKS 30 * 10 // 30 seconds + +// How many times in maximum stored keys are used for authentication +#define STORED_KEYS_MAXIMUM_USE_COUNT 2 + +const char *NW_INFO_FILE = "pae_nw_info"; +const char *KEYS_FILE = "pae_keys"; + +typedef struct { + char network_name[33]; /**< Network name for keys */ + sec_prot_gtk_keys_t *gtks; /**< Link to GTKs */ + uint16_t pan_id; /**< PAN ID for keys */ + bool updated : 1; /**< Network info has been updated */ +} sec_prot_keys_nw_info_t; + +typedef struct { + ns_list_link_t link; /**< Link */ + kmp_service_t *kmp_service; /**< KMP service */ + protocol_interface_info_entry_t *interface_ptr; /**< Interface */ + ws_pae_supp_auth_completed *auth_completed; /**< Authentication completed callback, continue bootstrap */ + ws_pae_supp_key_insert *key_insert; /**< Key insert callback */ + supp_entry_t entry; /**< Supplicant data */ + kmp_addr_t target_addr; /**< EAPOL target (parent) address */ + trickle_t auth_trickle_timer; /**< Trickle timer for re-sending initial EAPOL-key */ + sec_prot_gtk_keys_t gtks; /**< GTKs */ + uint8_t new_br_eui_64[8]; /**< Border router EUI-64 indicated by bootstrap */ + uint8_t ptk_eui_64[8]; /**< Border router EUI-64 used on PTK generation */ + sec_prot_keys_nw_info_t sec_keys_nw_info; /**< Security keys network information */ + uint8_t nw_keys_used_cnt; /**< How many times bootstrap has been tried with current keys */ + bool auth_trickle_running : 1; /**< Trickle timer running */ + bool auth_requested : 1; /**< Authentication has been requested */ + bool timer_running : 1; /**< Timer is running */ + bool new_br_eui_64_set : 1; /**< Border router address has been set */ +} pae_supp_t; + +// Wi-SUN specification states initial retransmission to be around 5 minutes and maximum 60 minutes +static const trickle_params_t auth_trickle_params = { + .Imin = 30 * 10, /* 30s; ticks are 100ms */ + .Imax = 60 * 10, /* 60s */ + .k = 0, /* infinity - no consistency checking */ + .TimerExpirations = 3 +}; + +static void ws_pae_supp_free(pae_supp_t *pae_supp); +static void ws_pae_supp_authenticate_response(pae_supp_t *pae_supp, bool success); +static int8_t ws_pae_supp_initial_key_send(pae_supp_t *pae_supp); +static void ws_pae_supp_nvm_update(pae_supp_t *pae_supp); +static int8_t ws_pae_supp_nw_keys_valid_check(pae_supp_t *pae_supp, uint16_t pan_id); +static int8_t ws_pae_supp_nvm_nw_info_write(pae_supp_t *pae_supp); +static int8_t ws_pae_supp_nvm_keys_write(pae_supp_t *pae_supp); +static pae_supp_t *ws_pae_supp_get(protocol_interface_info_entry_t *interface_ptr); +static int8_t ws_pae_supp_event_send(kmp_service_t *service, void *data); +static void ws_pae_supp_tasklet_handler(arm_event_s *event); +static int8_t ws_pae_supp_timer_if_start(kmp_service_t *service, kmp_api_t *kmp); +static int8_t ws_pae_supp_timer_if_stop(kmp_service_t *service, kmp_api_t *kmp); +static int8_t ws_pae_supp_timer_start(pae_supp_t *pae_supp); +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_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); + +static void ws_pae_supp_kmp_api_create_confirm(kmp_api_t *kmp, kmp_result_e result); +static void ws_pae_supp_kmp_api_create_indication(kmp_api_t *kmp, kmp_type_e type, kmp_addr_t *addr); +static void ws_pae_supp_kmp_api_finished_indication(kmp_api_t *kmp, kmp_result_e result, kmp_sec_keys_t *sec_keys); +static void ws_pae_supp_kmp_api_finished(kmp_api_t *kmp); + +static const eapol_pdu_recv_cb_data_t eapol_pdu_recv_cb_data = { + .priority = EAPOL_PDU_RECV_HIGH_PRIORITY, + .addr_check = ws_pae_supp_eapol_pdu_address_check, + .receive = kmp_eapol_pdu_if_receive +}; + +static int8_t tasklet_id = -1; +static NS_LIST_DEFINE(pae_supp_list, pae_supp_t, link); + +int8_t ws_pae_supp_authenticate(protocol_interface_info_entry_t *interface_ptr, uint16_t dest_pan_id, uint8_t *dest_eui_64) +{ + pae_supp_t *pae_supp = ws_pae_supp_get(interface_ptr); + if (!pae_supp) { + return -1; + } + + if (ws_pae_supp_nw_keys_valid_check(pae_supp, dest_pan_id) >= 0) { + pae_supp->auth_completed(interface_ptr, true); + return 0; + } + + // Delete GTKs + sec_prot_keys_gtks_init(pae_supp->sec_keys_nw_info.gtks); + + // Prepare to receive new border router address + pae_supp->new_br_eui_64_set = false; + + // Stores target/parent address + kmp_address_init(KMP_ADDR_EUI_64, &pae_supp->target_addr, dest_eui_64); + // Sets target address in use + pae_supp->entry.addr = (kmp_addr_t *) &pae_supp->target_addr; + + // Sends initial EAPOL-Key message + if (ws_pae_supp_initial_key_send(pae_supp) < 0) { + pae_supp->auth_completed(interface_ptr, false); + } + + // Starts trickle + trickle_start(&pae_supp->auth_trickle_timer, &auth_trickle_params); + pae_supp->auth_trickle_running = true; + + // Starts supplicant timer + ws_pae_supp_timer_start(pae_supp); + + pae_supp->auth_requested = true; + + tr_debug("PAE active"); + + return 1; +} + +int8_t ws_pae_supp_nw_info_set(protocol_interface_info_entry_t *interface_ptr, uint16_t pan_id, char *network_name) +{ + pae_supp_t *pae_supp = ws_pae_supp_get(interface_ptr); + if (!pae_supp) { + return -1; + } + + // PAN ID has been modified + if (pan_id != 0xffff && pan_id != pae_supp->sec_keys_nw_info.pan_id) { + pae_supp->sec_keys_nw_info.pan_id = pan_id; + pae_supp->sec_keys_nw_info.updated = true; + } + + // Network name has been modified + if (network_name && strncmp(pae_supp->sec_keys_nw_info.network_name, network_name, 33) != 0) { + strncpy(pae_supp->sec_keys_nw_info.network_name, network_name, 32); + pae_supp->sec_keys_nw_info.updated = true; + } + + + return 0; +} + +int8_t ws_pae_supp_border_router_addr_write(protocol_interface_info_entry_t *interface_ptr, const uint8_t *eui_64) +{ + pae_supp_t *pae_supp = ws_pae_supp_get(interface_ptr); + if (!pae_supp) { + return -1; + } + + memcpy(pae_supp->new_br_eui_64, eui_64, 8); + pae_supp->new_br_eui_64_set = true; + + return 0; +} + +int8_t ws_pae_supp_border_router_addr_read(protocol_interface_info_entry_t *interface_ptr, uint8_t *eui_64) +{ + pae_supp_t *pae_supp = ws_pae_supp_get(interface_ptr); + if (!pae_supp) { + return -1; + } + + if (!pae_supp->entry.sec_keys.ptk_eui_64 || !pae_supp->entry.sec_keys.ptk_eui_64_set) { + return -1; + } + + memcpy(eui_64, pae_supp->entry.sec_keys.ptk_eui_64, 8); + + return 0; +} + +int8_t ws_pae_supp_nw_key_valid(protocol_interface_info_entry_t *interface_ptr) +{ + pae_supp_t *pae_supp = ws_pae_supp_get(interface_ptr); + if (!pae_supp) { + return -1; + } + + // Stored keys are valid + pae_supp->nw_keys_used_cnt = 0; + + // Update NVM if data has been changed + ws_pae_supp_nvm_update(pae_supp); + + return 0; +} + +static void ws_pae_supp_nvm_update(pae_supp_t *pae_supp) +{ + // Check if NW info or GTKs have been changed + if (pae_supp->sec_keys_nw_info.updated || sec_prot_keys_gtks_are_updated(pae_supp->sec_keys_nw_info.gtks)) { + ws_pae_supp_nvm_nw_info_write(pae_supp); + pae_supp->sec_keys_nw_info.updated = false; + sec_prot_keys_gtks_updated_reset(pae_supp->sec_keys_nw_info.gtks); + } + + // Check if pairwise security keys have been changed + if (sec_prot_keys_are_updated(&pae_supp->entry.sec_keys)) { + ws_pae_supp_nvm_keys_write(pae_supp); + sec_prot_keys_updated_reset(&pae_supp->entry.sec_keys); + } +} + +static int8_t ws_pae_supp_nvm_nw_info_write(pae_supp_t *pae_supp) +{ + nvm_tlv_list_t tlv_list; + ns_list_init(&tlv_list); + + nvm_tlv_entry_t *tlv_entry = ws_pae_nvm_store_nw_info_tlv_create(pae_supp->sec_keys_nw_info.pan_id, + pae_supp->sec_keys_nw_info.network_name, + &pae_supp->gtks); + ns_list_add_to_end(&tlv_list, tlv_entry); + + ws_pae_nvm_store_tlv_file_write(NW_INFO_FILE, &tlv_list); + ns_list_remove(&tlv_list, tlv_entry); + ns_dyn_mem_free(tlv_entry); + + return 0; +} + +static int8_t ws_pae_supp_nvm_nw_info_read(pae_supp_t *pae_supp) +{ + nvm_tlv_list_t tlv_list; + ns_list_init(&tlv_list); + + ws_pae_nvm_store_tlv_file_read(NW_INFO_FILE, &tlv_list); + + ns_list_foreach_safe(nvm_tlv_entry_t, entry, &tlv_list) { + ws_pae_nvm_store_nw_info_tlv_read(entry, &pae_supp->sec_keys_nw_info.pan_id, + pae_supp->sec_keys_nw_info.network_name, + &pae_supp->gtks); + ns_list_remove(&tlv_list, entry); + ns_dyn_mem_free(entry); + } + + return 0; +} + +static int8_t ws_pae_supp_nvm_keys_write(pae_supp_t *pae_supp) +{ + nvm_tlv_list_t tlv_list; + ns_list_init(&tlv_list); + + nvm_tlv_entry_t *tlv_entry = ws_pae_nvm_store_keys_tlv_create(&pae_supp->entry.sec_keys); + ns_list_add_to_end(&tlv_list, tlv_entry); + + ws_pae_nvm_store_tlv_file_write(KEYS_FILE, &tlv_list); + ns_list_remove(&tlv_list, tlv_entry); + ns_dyn_mem_free(tlv_entry); + + return 0; +} + +static int8_t ws_pae_supp_nvm_keys_read(pae_supp_t *pae_supp) +{ + nvm_tlv_list_t tlv_list; + ns_list_init(&tlv_list); + + ws_pae_nvm_store_tlv_file_read(KEYS_FILE, &tlv_list); + + ns_list_foreach_safe(nvm_tlv_entry_t, entry, &tlv_list) { + ws_pae_nvm_store_keys_tlv_read(entry, &pae_supp->entry.sec_keys); + ns_list_remove(&tlv_list, entry); + ns_dyn_mem_free(entry); + } + + return 0; +} + +static void ws_pae_supp_authenticate_response(pae_supp_t *pae_supp, bool success) +{ + pae_supp->auth_trickle_running = false; + if (pae_supp->auth_requested && pae_supp->auth_completed) { + pae_supp->auth_requested = false; + pae_supp->auth_completed(pae_supp->interface_ptr, success); + } +} + +static int8_t ws_pae_supp_initial_key_send(pae_supp_t *pae_supp) +{ + kmp_api_t *kmp = ws_pae_supp_kmp_create_and_start(pae_supp->kmp_service, IEEE_802_1X_MKA_KEY, pae_supp); + if (!kmp) { + return -1; + } + + kmp_api_create_request(kmp, IEEE_802_1X_MKA_KEY, pae_supp->entry.addr, &pae_supp->entry.sec_keys); + + return 0; +} + +static int8_t ws_pae_supp_nw_keys_valid_check(pae_supp_t *pae_supp, uint16_t pan_id) +{ + // Checks how many times authentication has been tried with current network keys + if (pae_supp->nw_keys_used_cnt >= STORED_KEYS_MAXIMUM_USE_COUNT) { + tr_debug("Keys not valid, delete GTKs"); + + // Delete GTKs + sec_prot_keys_gtks_init(pae_supp->sec_keys_nw_info.gtks); + sec_prot_keys_gtks_updated_set(pae_supp->sec_keys_nw_info.gtks); + ws_pae_supp_nvm_update(pae_supp); + + pae_supp->nw_keys_used_cnt = 0; + return -1; + } + + // First attempt to authenticate, checks if keys exists + if (pae_supp->nw_keys_used_cnt == 0 && pan_id == pae_supp->sec_keys_nw_info.pan_id) { + sec_prot_gtk_keys_t *gtks = pae_supp->sec_keys_nw_info.gtks; + + bool key_inserted = false; + + for (uint8_t i = 0; i < GTK_NUM; i++) { + uint8_t *gtk = sec_prot_keys_gtk_get(gtks, i); + if (gtk) { + // Insert also non-live keys since GTK hash information not yet received + pae_supp->key_insert(pae_supp->interface_ptr, i, gtk); + key_inserted = true; + } + } + + if (key_inserted) { + tr_debug("Keys inserted"); + pae_supp->nw_keys_used_cnt++; + return 0; + } + } + + if (pae_supp->nw_keys_used_cnt == 0) { + return -1; + } else { + tr_debug("Existing keys used, counter %i", pae_supp->nw_keys_used_cnt); + pae_supp->nw_keys_used_cnt++; + return 0; + } +} + +static void ws_pae_supp_keys_nw_info_init(sec_prot_keys_nw_info_t *sec_keys_nw_info, sec_prot_gtk_keys_t *gtks) +{ + if (!sec_keys_nw_info) { + return; + } + + memset(sec_keys_nw_info, 0, sizeof(sec_prot_keys_nw_info_t)); + + sec_keys_nw_info->gtks = gtks; + sec_keys_nw_info->updated = false; +} + +void ws_pae_supp_cb_register(protocol_interface_info_entry_t *interface_ptr, ws_pae_supp_auth_completed *completed, ws_pae_supp_key_insert *key_insert) +{ + pae_supp_t *pae_supp = ws_pae_supp_get(interface_ptr); + if (!pae_supp) { + return; + } + + pae_supp->auth_completed = completed; + pae_supp->key_insert = key_insert; +} + +int8_t ws_pae_supp_init(protocol_interface_info_entry_t *interface_ptr, const sec_prot_certs_t *certs) +{ + if (!interface_ptr) { + return -1; + } + + if (ws_pae_supp_get(interface_ptr) != NULL) { + return 0; + } + + pae_supp_t *pae_supp = ns_dyn_mem_alloc(sizeof(pae_supp_t)); + if (!pae_supp) { + return -1; + } + + pae_supp->interface_ptr = interface_ptr; + pae_supp->auth_completed = 0; + pae_supp->key_insert = 0; + pae_supp->auth_trickle_running = false; + pae_supp->nw_keys_used_cnt = 0; + + ws_pae_lib_supp_init(&pae_supp->entry); + + ws_pae_supp_keys_nw_info_init(&pae_supp->sec_keys_nw_info, &pae_supp->gtks); + + kmp_address_init(KMP_ADDR_EUI_64, &pae_supp->target_addr, 0); + + sec_prot_keys_gtks_init(&pae_supp->gtks); + sec_prot_keys_init(&pae_supp->entry.sec_keys, &pae_supp->gtks, certs); + memset(pae_supp->new_br_eui_64, 0, 8); + memset(pae_supp->ptk_eui_64, 0, 8); + sec_prot_keys_ptk_eui_64_set(&pae_supp->entry.sec_keys, pae_supp->ptk_eui_64); + + pae_supp->kmp_service = kmp_service_create(); + if (!pae_supp->kmp_service) { + goto error; + } + + if (kmp_service_cb_register(pae_supp->kmp_service, ws_pae_supp_kmp_incoming_ind, ws_pae_supp_kmp_service_addr_get, ws_pae_supp_kmp_service_api_get) < 0) { + goto error; + } + + if (kmp_service_event_if_register(pae_supp->kmp_service, ws_pae_supp_event_send)) { + goto error; + } + + if (kmp_service_timer_if_register(pae_supp->kmp_service, ws_pae_supp_timer_if_start, ws_pae_supp_timer_if_stop)) { + goto error; + } + + if (kmp_eapol_pdu_if_register(pae_supp->kmp_service, interface_ptr) < 0) { + goto error; + } + + if (ws_eapol_pdu_cb_register(interface_ptr, &eapol_pdu_recv_cb_data) < 0) { + goto error; + } + + if (key_sec_prot_register(pae_supp->kmp_service) < 0) { + goto error; + } + + if (supp_eap_tls_sec_prot_register(pae_supp->kmp_service) < 0) { + goto error; + } + + if (client_tls_sec_prot_register(pae_supp->kmp_service) < 0) { + goto error; + } + + if (supp_fwh_sec_prot_register(pae_supp->kmp_service) < 0) { + goto error; + } + + if (supp_gkh_sec_prot_register(pae_supp->kmp_service) < 0) { + goto error; + } + + if (tasklet_id < 0) { + tasklet_id = eventOS_event_handler_create(ws_pae_supp_tasklet_handler, PAE_TASKLET_INIT); + if (tasklet_id < 0) { + goto error; + } + } + + if (ws_pae_supp_timer_stop(pae_supp) < 0) { + goto error; + } + + ws_pae_supp_nvm_nw_info_read(pae_supp); + ws_pae_supp_nvm_keys_read(pae_supp); + + ns_list_add_to_end(&pae_supp_list, pae_supp); + + return 0; + +error: + ws_pae_supp_free(pae_supp); + + return -1; +} + +int8_t ws_pae_supp_delete(protocol_interface_info_entry_t *interface_ptr) +{ + if (!interface_ptr) { + return -1; + } + + pae_supp_t *pae_supp = ws_pae_supp_get(interface_ptr); + if (!pae_supp) { + return -1; + } + + ws_pae_supp_free(pae_supp); + return 0; +} + +static void ws_pae_supp_free(pae_supp_t *pae_supp) +{ + if (!pae_supp) { + return; + } + + ws_pae_lib_supp_delete(&pae_supp->entry); + + kmp_eapol_pdu_if_unregister(pae_supp->kmp_service); + + ws_eapol_pdu_cb_unregister(pae_supp->interface_ptr, &eapol_pdu_recv_cb_data); + + kmp_service_delete(pae_supp->kmp_service); + + ns_list_remove(&pae_supp_list, pae_supp); + ns_dyn_mem_free(pae_supp); +} + +static pae_supp_t *ws_pae_supp_get(protocol_interface_info_entry_t *interface_ptr) +{ + ns_list_foreach(pae_supp_t, entry, &pae_supp_list) { + if (entry->interface_ptr == interface_ptr) { + return entry; + } + } + + return NULL; +} + +static pae_supp_t *ws_pae_supp_by_kmp_service_get(kmp_service_t *service) +{ + ns_list_foreach(pae_supp_t, entry, &pae_supp_list) { + if (entry->kmp_service == service) { + return entry; + } + } + + return NULL; +} + +static int8_t ws_pae_supp_event_send(kmp_service_t *service, void *data) +{ + pae_supp_t *pae_supp = ws_pae_supp_by_kmp_service_get(service); + if (!pae_supp) { + return -1; + } + + arm_event_s event = { + .receiver = tasklet_id, + .sender = 0, + .event_id = pae_supp->interface_ptr->id, + .data_ptr = data, + .event_type = PAE_TASKLET_EVENT, + .priority = ARM_LIB_LOW_PRIORITY_EVENT, + }; + + if (eventOS_event_send(&event) != 0) { + return -1; + } + + return 0; +} + +static void ws_pae_supp_tasklet_handler(arm_event_s *event) +{ + if (event->event_type == PAE_TASKLET_INIT) { + + } else if (event->event_type == PAE_TASKLET_EVENT) { + pae_supp_t *pae_supp = NULL; + + ns_list_foreach(pae_supp_t, entry, &pae_supp_list) { + if (entry->interface_ptr->id == event->event_id) { + pae_supp = entry; + break; + } + } + + if (pae_supp) { + kmp_service_event_if_event(pae_supp->kmp_service, event->data_ptr); + } + } +} + +void ws_pae_supp_timer(uint16_t ticks) +{ + ns_list_foreach(pae_supp_t, pae_supp, &pae_supp_list) { + if (!ws_pae_supp_timer_running(pae_supp)) { + continue; + } + + // Checks whether initial EAPOL-Key message needs to be re-send + if (pae_supp->auth_trickle_running) { + if (trickle_timer(&pae_supp->auth_trickle_timer, &auth_trickle_params, ticks)) { + ws_pae_supp_initial_key_send(pae_supp); + } + // Maximum number of trickle expires, authentication fails + if (!trickle_running(&pae_supp->auth_trickle_timer, &auth_trickle_params)) { + ws_pae_supp_authenticate_response(pae_supp, false); + } + } + + // Updates KMP timers and supplicant authentication ongoing timer + bool running = ws_pae_lib_supp_timer_update(&pae_supp->entry, ticks, kmp_service_timer_if_timeout); + + // Checks whether timer needs to be active + if (!pae_supp->auth_trickle_running && !running) { + + tr_debug("PAE idle"); + // Sets target/parent address to null + pae_supp->entry.addr = NULL; + + // If not already completed, restart bootstrap + ws_pae_supp_authenticate_response(pae_supp, false); + + ws_pae_supp_timer_stop(pae_supp); + } + } +} + +static int8_t ws_pae_supp_timer_if_start(kmp_service_t *service, kmp_api_t *kmp) +{ + pae_supp_t *pae_supp = ws_pae_supp_by_kmp_service_get(service); + if (!pae_supp) { + return -1; + } + + if (ws_pae_supp_timer_start(pae_supp) < 0) { + return -1; + } + + kmp_entry_t *entry = kmp_api_data_get(kmp); + if (!entry) { + return -1; + } + ws_pae_lib_kmp_timer_start(&pae_supp->entry.kmp_list, entry); + return 0; +} + +static int8_t ws_pae_supp_timer_if_stop(kmp_service_t *service, kmp_api_t *kmp) +{ + pae_supp_t *pae_supp = ws_pae_supp_by_kmp_service_get(service); + if (!pae_supp) { + return -1; + } + + kmp_entry_t *entry = kmp_api_data_get(kmp); + if (!entry) { + return -1; + } + ws_pae_lib_kmp_timer_stop(&pae_supp->entry.kmp_list, entry); + return 0; +} + +static int8_t ws_pae_supp_timer_start(pae_supp_t *pae_supp) +{ + pae_supp->timer_running = true; + return 0; +} + +static int8_t ws_pae_supp_timer_stop(pae_supp_t *pae_supp) +{ + pae_supp->timer_running = false; + return 0; +} + +static bool ws_pae_supp_timer_running(pae_supp_t *pae_supp) +{ + return pae_supp->timer_running; +} + +static int8_t ws_pae_supp_eapol_pdu_address_check(protocol_interface_info_entry_t *interface_ptr, const uint8_t *eui_64) +{ + pae_supp_t *pae_supp = ws_pae_supp_get(interface_ptr); + if (!pae_supp) { + return -1; + } + + // Message from EAPOL target node, route to self + if (pae_supp->entry.addr) { + if (memcmp(eui_64, kmp_address_eui_64_get(pae_supp->entry.addr), 8) == 0) { + return 0; + } + } + + rpl_dodag_info_t dodag_info; + struct rpl_instance *instance = rpl_control_enumerate_instances(interface_ptr->rpl_domain, NULL); + if (instance && rpl_control_read_dodag_info(instance, &dodag_info)) { + // Get parent + const uint8_t *parent_ll_addr = rpl_control_preferred_parent_addr(instance, false); + + // Message from RPL parent, route to self + if (parent_ll_addr && memcmp(&parent_ll_addr[8], eui_64, 8) == 0) { + return 0; + } + + return -1; + } + + return 0; +} + +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) +{ + (void) kmp; + + pae_supp_t *pae_supp = ws_pae_supp_by_kmp_service_get(service); + if (!pae_supp) { + return; + } + + // Get own EUI-64 + link_layer_address_s mac_params; + if (arm_nwk_mac_address_read(pae_supp->interface_ptr->id, &mac_params) >= 0) { + kmp_address_eui_64_set(local_addr, mac_params.mac_long); + } + + if (pae_supp->new_br_eui_64_set) { + kmp_address_eui_64_set(remote_addr, pae_supp->new_br_eui_64); + } else if (pae_supp->entry.sec_keys.ptk_eui_64_set) { + kmp_address_eui_64_set(remote_addr, pae_supp->entry.sec_keys.ptk_eui_64); + } else { + memset(remote_addr, 0, 8); + tr_error("No border router EUI-64"); + } +} + +static kmp_api_t *ws_pae_supp_kmp_service_api_get(kmp_service_t *service, kmp_api_t *kmp, kmp_type_e type) +{ + (void) kmp; + + pae_supp_t *pae_supp = ws_pae_supp_by_kmp_service_get(service); + if (!pae_supp) { + return NULL; + } + + 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) +{ + // Should be MKA, 4WH or GKH and never initial EAPOL-key for supplicant + if (type > IEEE_802_1X_INITIAL_KEY) { + return NULL; + } + + pae_supp_t *pae_supp = ws_pae_supp_by_kmp_service_get(service); + if (!pae_supp) { + return NULL; + } + + if (!pae_supp->entry.addr) { + // Does no longer wait for authentication, ignores message + return NULL; + } + + // No longer runs trickle timer for re-sending initial EAPOL-key + pae_supp->auth_trickle_running = false; + + // Updates parent address + kmp_address_copy(pae_supp->entry.addr, addr); + + // Check if ongoing + kmp_api_t *kmp = ws_pae_lib_kmp_list_type_get(&pae_supp->entry.kmp_list, type); + if (kmp) { + return kmp; + } + + // Create new instance + kmp = ws_pae_supp_kmp_create_and_start(service, type, pae_supp); + + // For EAP-TLS create also TLS in addition to EAP-TLS + if (type == IEEE_802_1X_MKA) { + if (ws_pae_lib_kmp_list_type_get(&pae_supp->entry.kmp_list, TLS_PROT) != NULL) { + // TLS already exists, wait for it to be deleted + ws_pae_lib_kmp_list_delete(&pae_supp->entry.kmp_list, kmp); + return NULL; + } + // Create TLS instance */ + if (ws_pae_supp_kmp_create_and_start(service, TLS_PROT, pae_supp) == NULL) { + ws_pae_lib_kmp_list_delete(&pae_supp->entry.kmp_list, kmp); + return NULL; + } + } + + return kmp; +} + +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); + if (!kmp) { + return NULL; + } + + // Updates parent address + kmp_api_addr_set(kmp, pae_supp->entry.addr); + + // Sets security keys to KMP + kmp_api_sec_keys_set(kmp, &pae_supp->entry.sec_keys); + + kmp_api_cb_register( + kmp, ws_pae_supp_kmp_api_create_confirm, + ws_pae_supp_kmp_api_create_indication, + ws_pae_supp_kmp_api_finished_indication, + ws_pae_supp_kmp_api_finished); + + kmp_entry_t *kmp_entry = ws_pae_lib_kmp_list_add(&pae_supp->entry.kmp_list, kmp); + if (!kmp_entry) { + kmp_api_delete(kmp); + return NULL; + } + + kmp_api_data_set(kmp, kmp_entry); + + if (kmp_api_start(kmp) < 0) { + ws_pae_lib_kmp_list_delete(&pae_supp->entry.kmp_list, kmp); + return NULL; + } + + return kmp; +} + +static void ws_pae_supp_kmp_api_create_confirm(kmp_api_t *kmp, kmp_result_e result) +{ + kmp_service_t *service = kmp_api_service_get(kmp); + pae_supp_t *pae_supp = ws_pae_supp_by_kmp_service_get(service); + if (!pae_supp) { + return; + } + + // KMP-CREATE.request has failed, authentication error + if (result != KMP_RESULT_OK) { + ws_pae_supp_authenticate_response(pae_supp, false); + } +} + +static void ws_pae_supp_kmp_api_create_indication(kmp_api_t *kmp, kmp_type_e type, kmp_addr_t *addr) +{ + (void) addr; + (void) type; + + // For now, accept every KMP-CREATE.indication + kmp_api_create_response(kmp, KMP_RESULT_OK); +} + +static void ws_pae_supp_kmp_api_finished_indication(kmp_api_t *kmp, kmp_result_e result, kmp_sec_keys_t *sec_keys) +{ + kmp_service_t *service = kmp_api_service_get(kmp); + pae_supp_t *pae_supp = ws_pae_supp_by_kmp_service_get(service); + if (!pae_supp) { + return; + } + + kmp_type_e type = kmp_api_type_get(kmp); + + // Whenever EAP-TLS, 4WH or GKH completes increase timer for wait for authentication + if (type < IEEE_802_1X_INITIAL_KEY && result == KMP_RESULT_OK) { + ws_pae_lib_supp_timer_ticks_set(&pae_supp->entry, WAIT_FOR_AUTHENTICATION_TICKS); + } + + sec_prot_keys_t *keys = sec_keys; + // Key is to be inserted + if (keys) { + uint8_t gtk_index; + uint8_t *gtk = sec_prot_keys_get_gtk_to_insert(keys->gtks, >k_index); + if (gtk) { + pae_supp->key_insert(pae_supp->interface_ptr, gtk_index, gtk); + sec_prot_keys_gtk_insert_index_clear(keys->gtks); + } + } + + if ((type == IEEE_802_11_4WH || type == IEEE_802_11_GKH) && result == KMP_RESULT_OK) { + ws_pae_supp_authenticate_response(pae_supp, true); + } +} + +static void ws_pae_supp_kmp_api_finished(kmp_api_t *kmp) +{ + kmp_service_t *service = kmp_api_service_get(kmp); + pae_supp_t *pae_supp = ws_pae_supp_by_kmp_service_get(service); + if (!pae_supp) { + return; + } + + // Delete KMP + ws_pae_lib_kmp_list_delete(&pae_supp->entry.kmp_list, kmp); +} + +#endif /* HAVE_PAE_SUPP */ +#endif /* HAVE_WS */ + diff --git a/source/6LoWPAN/ws/ws_pae_supp.h b/source/6LoWPAN/ws/ws_pae_supp.h new file mode 100644 index 0000000000..2a525f94d9 --- /dev/null +++ b/source/6LoWPAN/ws/ws_pae_supp.h @@ -0,0 +1,172 @@ +/* + * Copyright (c) 2018-2019, Arm Limited and affiliates. + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef WS_PAE_SUPP_H_ +#define WS_PAE_SUPP_H_ + +#define PAE_SUPP_NOT_ENABLED 5 + +#ifdef HAVE_PAE_SUPP + +/* + * Supplicant port access entity controls key security protocols using KMP API. + * + * Configures KMP service network access and provides timing and callback services + * for it. Registers needed security protocols to KMP service. + * + * PAE maintains security keys that are internal to port access entity. After + * (re-)authentication provides network access keys to application. + * + */ + +/** + * ws_pae_supp_init initializes PAE supplicant + * + * \param interface_ptr interface + * \param cert_chain certificate chain + * + * \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); + +/** + * ws_pae_supp_delete deletes PAE supplicant + * + * \param interface_ptr interface + * + * \return < 0 failure + * \return >= 0 success + * + */ +int8_t ws_pae_supp_delete(protocol_interface_info_entry_t *interface_ptr); + +/** + * ws_pae_supp_timer PAE supplicant timer call + * + * \param ticks elapsed ticks + * + */ +void ws_pae_supp_timer(uint16_t ticks); + +/** + * ws_pae_supp_authenticate start EAPOL authentication + * + * \param interface_ptr interface + * \param dest_pan_id EAPOL target PAN ID + * \param dest_eui_64 EAPOL target + * + * \return < 0 failure + * \return 0 authentication done, continue + * \return > 0 authentication started + * + */ +int8_t ws_pae_supp_authenticate(protocol_interface_info_entry_t *interface_ptr, uint16_t dest_pan_id, uint8_t *dest_eui_64); + +/** + * ws_pae_supp_nw_info_set set network information + * + * \param interface_ptr interface + * \param pan_id PAD ID + * \param network_name network name + * + * \return < 0 failure + * \return >= 0 success + * + */ +int8_t ws_pae_supp_nw_info_set(protocol_interface_info_entry_t *interface_ptr, uint16_t pan_id, char *network_name); + +/** + * ws_pae_supp_border_router_addr_write write border router address + * + * \param interface_ptr interface + * \param eui_64 pointer to EUI-64 + * + * \return < 0 failure + * \return >= 0 success + * + */ +int8_t ws_pae_supp_border_router_addr_write(protocol_interface_info_entry_t *interface_ptr, const uint8_t *eui_64); + +/** + * ws_pae_supp_border_router_addr_read read border router address + * + * \param interface_ptr interface + * \param eui_64 pointer to EUI-64 + * + * \return < 0 failure + * \return >= 0 success + * + */ +int8_t ws_pae_supp_border_router_addr_read(protocol_interface_info_entry_t *interface_ptr, uint8_t *eui_64); + +/** + * ws_pae_supp_nw_key_valid network key is valid i.e. used successfully on bootstrap + * + * \param interface_ptr interface + * + * \return < 0 failure + * \return >= 0 success + * + */ +int8_t ws_pae_supp_nw_key_valid(protocol_interface_info_entry_t *interface_ptr); + +/** + * ws_pae_supp_auth_completed authentication completed callback + * + * \param interface_ptr interface + * \param success true if authentication was successful + * + */ +typedef void ws_pae_supp_auth_completed(protocol_interface_info_entry_t *interface_ptr, bool success); + +/** + * ws_pae_supp_key_insert new GTK key available + * + * \param interface_ptr interface + * \param gtk_index index of the new GTK key + * \param gtk new GTK key + * + */ +typedef void ws_pae_supp_key_insert(protocol_interface_info_entry_t *interface_ptr, uint8_t gtk_index, uint8_t *gtk); + +/** + * ws_pae_supp_cb_register register PEA supplicant callbacks + * + * \param interface_ptr interface + * \param completed authentication completed callback + * \param key_insert GTK key insert callback + * + */ +void ws_pae_supp_cb_register(protocol_interface_info_entry_t *interface_ptr, ws_pae_supp_auth_completed *completed, ws_pae_supp_key_insert *key_insert); + +#else + +#define ws_pae_supp_init(interface_ptr, certs) 1 +#define ws_pae_supp_delete NULL +#define ws_pae_supp_cb_register(interface_ptr, completed, key_insert) +#define ws_pae_supp_nw_info_set(interface_ptr, pan_id, network_name) -1 +#define ws_pae_supp_nw_key_valid(interface_ptr) -1 +#define ws_pae_supp_timer NULL +#define ws_pae_supp_authenticate(interface_ptr, dest_pan_id, dest_eui_64) PAE_SUPP_NOT_ENABLED +#define ws_pae_supp_border_router_addr_write NULL +#define ws_pae_supp_border_router_addr_read NULL + +#endif + +#endif /* WS_PAE_SUPP_H_ */ diff --git a/source/6LoWPAN/ws/ws_test_api.c b/source/6LoWPAN/ws/ws_test_api.c new file mode 100644 index 0000000000..c320f5b4a8 --- /dev/null +++ b/source/6LoWPAN/ws/ws_test_api.c @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2018-2019, 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 +#include +#include +#include "NWK_INTERFACE/Include/protocol.h" +#include "6LoWPAN/ws/ws_config.h" +#include "6LoWPAN/ws/ws_common.h" +#include "6LoWPAN/ws/ws_bbr_api_internal.h" +#include "randLIB.h" + +#include "ns_trace.h" +#include "common_functions.h" + +#define TRACE_GROUP "wste" + +#ifdef HAVE_WS + +int ws_test_pan_size_set(int8_t interface_id, uint16_t pan_size) +{ + + (void) interface_id; +#ifdef HAVE_WS_BORDER_ROUTER + test_pan_size_override = pan_size; + return 0; +#else + (void) pan_size; + return -1; +#endif +} + +int ws_test_max_child_count_set(int8_t interface_id, uint16_t child_count) +{ + + (void) interface_id; + test_max_child_count_override = child_count; + return 0; +} + +int ws_test_gtk_set(int8_t interface_id, uint8_t *gtk[4]) +{ + (void) interface_id; + (void) gtk; + + return 0; +} + +int ws_test_active_key_set(int8_t interface_id, uint8_t index) +{ + (void) interface_id; + (void) index; + + return 0; +} + +int ws_test_key_lifetime_set(int8_t interface_id, uint32_t gtk_lifetime, uint32_t pmk_lifetime, uint32_t ptk_lifetime) +{ + (void) interface_id; + (void) gtk_lifetime; + (void) pmk_lifetime; + (void) ptk_lifetime; + + return 0; +} + +int ws_test_gtk_time_settings_set(int8_t interface_id, uint8_t revocat_lifetime_reduct, uint8_t new_activation_time, uint32_t max_mismatch) +{ + (void) interface_id; + (void) revocat_lifetime_reduct; + (void) new_activation_time; + (void) max_mismatch; + + return 0; +} + +#endif // HAVE_WS diff --git a/source/Common_Protocols/icmpv6.c b/source/Common_Protocols/icmpv6.c index 2dd17b9143..547ed947d5 100644 --- a/source/Common_Protocols/icmpv6.c +++ b/source/Common_Protocols/icmpv6.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2018, Arm Limited and affiliates. + * Copyright (c) 2013-2019, Arm Limited and affiliates. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -34,7 +34,7 @@ #include "Common_Protocols/ip.h" #include "Common_Protocols/ipv6.h" #include "Common_Protocols/mld.h" -#include "Core/include/socket.h" +#include "Core/include/ns_socket.h" #include "ipv6_stack/protocol_ipv6.h" #include "ipv6_stack/ipv6_routing_table.h" #include "ip_fsc.h" @@ -340,6 +340,26 @@ static buffer_t *icmpv6_echo_request_handler(buffer_t *buf) } #ifdef HAVE_IPV6_ND + +static void icmpv6_na_wisun_aro_handler(protocol_interface_info_entry_t *cur_interface, const uint8_t *dptr, const uint8_t *src_addr) +{ + (void) src_addr; + dptr += 2; + uint16_t life_time; + uint8_t nd_status = *dptr; + dptr += 4; + life_time = common_read_16_bit(dptr); + dptr += 2; + if (memcmp(dptr, cur_interface->mac, 8) != 0) { + return; + } + + (void)life_time; + if (nd_status != ARO_SUCCESS) { + ws_common_aro_failure(cur_interface, src_addr); + } +} + static void icmpv6_na_aro_handler(protocol_interface_info_entry_t *cur_interface, const uint8_t *dptr, const uint8_t *dst_addr) { (void)dst_addr; @@ -985,11 +1005,14 @@ static buffer_t *icmpv6_na_handler(buffer_t *buf) goto drop; } - if (cur->ipv6_neighbour_cache.recv_na_aro) { - const uint8_t *aro = icmpv6_find_option_in_buffer(buf, 20, ICMPV6_OPT_ADDR_REGISTRATION, 2); - if (aro) { + const uint8_t *aro = icmpv6_find_option_in_buffer(buf, 20, ICMPV6_OPT_ADDR_REGISTRATION, 2); + if (aro) { + if (cur->ipv6_neighbour_cache.recv_na_aro) { icmpv6_na_aro_handler(cur, aro, buf->dst_sa.address); } + if (ws_info(cur)) { + icmpv6_na_wisun_aro_handler(cur, aro, buf->src_sa.address); + } } /* No need to create a neighbour cache entry if one doesn't already exist */ @@ -1092,7 +1115,7 @@ buffer_t *icmpv6_up(buffer_t *buf) buf = rpl_control_source_route_error_handler(buf, cur); } #endif - /* no break */ + /* fall through */ default: if (buf) { diff --git a/source/Common_Protocols/ipv6.c b/source/Common_Protocols/ipv6.c index e125cca31e..fe3102591d 100644 --- a/source/Common_Protocols/ipv6.c +++ b/source/Common_Protocols/ipv6.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2018, Arm Limited and affiliates. + * Copyright (c) 2013-2019, Arm Limited and affiliates. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -23,7 +23,7 @@ #include "ns_types.h" #include "string.h" #include "nsdynmemLIB.h" -#include "Core/include/socket.h" +#include "Core/include/ns_socket.h" #include "ns_trace.h" #include "NWK_INTERFACE/Include/protocol.h" #include "NWK_INTERFACE/Include/protocol_stats.h" diff --git a/source/Common_Protocols/ipv6_flow.c b/source/Common_Protocols/ipv6_flow.c index 9670f0d395..60e1657881 100644 --- a/source/Common_Protocols/ipv6_flow.c +++ b/source/Common_Protocols/ipv6_flow.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2017, Arm Limited and affiliates. + * Copyright (c) 2016-2018, Arm Limited and affiliates. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/source/Common_Protocols/ipv6_fragmentation.c b/source/Common_Protocols/ipv6_fragmentation.c index 961c92c2f3..1386b398ea 100644 --- a/source/Common_Protocols/ipv6_fragmentation.c +++ b/source/Common_Protocols/ipv6_fragmentation.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2018, Arm Limited and affiliates. + * Copyright (c) 2015-2019, Arm Limited and affiliates. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -36,7 +36,7 @@ #include "nsdynmemLIB.h" #include #include "ns_trace.h" -#include "Core/include/socket.h" +#include "Core/include/ns_socket.h" #include "NWK_INTERFACE/Include/protocol.h" #include "Common_Protocols/ip.h" #include "Common_Protocols/ipv6.h" diff --git a/source/Common_Protocols/ipv6_resolution.c b/source/Common_Protocols/ipv6_resolution.c index b374b1da4e..790b226b8a 100644 --- a/source/Common_Protocols/ipv6_resolution.c +++ b/source/Common_Protocols/ipv6_resolution.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2017, Arm Limited and affiliates. + * Copyright (c) 2015-2019, Arm Limited and affiliates. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -21,7 +21,7 @@ #include "ns_list.h" #include "ns_trace.h" #include "nsdynmemLIB.h" -#include "Core/include/socket.h" +#include "Core/include/ns_socket.h" #include "NWK_INTERFACE/Include/protocol.h" #include "Common_Protocols/ipv6.h" #include "Common_Protocols/icmpv6.h" diff --git a/source/Common_Protocols/ipv6_resolution.h b/source/Common_Protocols/ipv6_resolution.h index a54b4d5488..63b6d4b5bc 100644 --- a/source/Common_Protocols/ipv6_resolution.h +++ b/source/Common_Protocols/ipv6_resolution.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2017, Arm Limited and affiliates. + * Copyright (c) 2015-2017, 2019, Arm Limited and affiliates. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -19,7 +19,7 @@ #ifndef IPV6_RESOLUTION_H_ #define IPV6_RESOLUTION_H_ -#include "Core/include/address.h" +#include "Core/include/ns_address_internal.h" struct ipv6_neighbour; struct ipv6_neighbour_cache; diff --git a/source/Common_Protocols/tcp.c b/source/Common_Protocols/tcp.c index d3c9add1a5..311a0e96a7 100644 --- a/source/Common_Protocols/tcp.c +++ b/source/Common_Protocols/tcp.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2018, Arm Limited and affiliates. + * Copyright (c) 2013-2019, Arm Limited and affiliates. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -20,7 +20,7 @@ #include "ns_types.h" #include "ns_trace.h" #include "eventOS_event.h" -#include "Core/include/socket.h" +#include "Core/include/ns_socket.h" #include "nsdynmemLIB.h" #include "ip_fsc.h" #include "ns_sha256.h" diff --git a/source/Common_Protocols/udp.c b/source/Common_Protocols/udp.c index df1c1cc9f8..a232e6762c 100644 --- a/source/Common_Protocols/udp.c +++ b/source/Common_Protocols/udp.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2017, Arm Limited and affiliates. + * Copyright (c) 2013-2017, 2019, Arm Limited and affiliates. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -25,7 +25,7 @@ #include "Common_Protocols/ipv6_constants.h" #include "Common_Protocols/icmpv6.h" #include "Common_Protocols/udp.h" -#include "Core/include/socket.h" +#include "Core/include/ns_socket.h" #include "common_functions.h" #define TRACE_GROUP "udp" diff --git a/source/Core/buffer_dyn.c b/source/Core/buffer_dyn.c index 7bb1a12663..1b34e64997 100644 --- a/source/Core/buffer_dyn.c +++ b/source/Core/buffer_dyn.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011-2018, Arm Limited and affiliates. + * Copyright (c) 2011-2019, Arm Limited and affiliates. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -19,9 +19,9 @@ #include "string.h" #include "ns_types.h" #include "nsdynmemLIB.h" -#include "Core/include/address.h" +#include "Core/include/ns_address_internal.h" #include "Core/include/ns_buffer.h" -#include "Core/include/socket.h" +#include "Core/include/ns_socket.h" #include "ns_trace.h" #include "platform/arm_hal_interrupt.h" #include "NWK_INTERFACE/Include/protocol_stats.h" diff --git a/source/Core/include/address.h b/source/Core/include/ns_address_internal.h similarity index 99% rename from source/Core/include/address.h rename to source/Core/include/ns_address_internal.h index 22f4e380ea..8295226283 100644 --- a/source/Core/include/address.h +++ b/source/Core/include/ns_address_internal.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2010-2018, Arm Limited and affiliates. + * Copyright (c) 2008, 2010-2019, Arm Limited and affiliates. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -16,7 +16,7 @@ */ /** * - * \file address.h + * \file ns_address_internal.h * \brief address type definitions. * * nanoStack: supported address types and associated data structures. diff --git a/source/Core/include/ns_buffer.h b/source/Core/include/ns_buffer.h index 71ef81016d..7ebb6e0545 100644 --- a/source/Core/include/ns_buffer.h +++ b/source/Core/include/ns_buffer.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2018, Arm Limited and affiliates. + * Copyright (c) 2008-2019, Arm Limited and affiliates. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -32,7 +32,7 @@ #endif #include "ns_types.h" -#include "Core/include/address.h" +#include "Core/include/ns_address_internal.h" #include "NWK_INTERFACE/Include/protocol_abstract.h" #include "ns_list.h" #include "ipv6_stack/ipv6_routing_table.h" diff --git a/source/Core/include/socket.h b/source/Core/include/ns_socket.h similarity index 99% rename from source/Core/include/socket.h rename to source/Core/include/ns_socket.h index 6585c64ecc..5e1c566e20 100644 --- a/source/Core/include/socket.h +++ b/source/Core/include/ns_socket.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2017, Arm Limited and affiliates. + * Copyright (c) 2008-2017, 2019, Arm Limited and affiliates. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/source/Core/address.c b/source/Core/ns_address_internal.c similarity index 99% rename from source/Core/address.c rename to source/Core/ns_address_internal.c index 7f8b173a4e..386d00c01d 100644 --- a/source/Core/address.c +++ b/source/Core/ns_address_internal.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2010-2018, Arm Limited and affiliates. + * Copyright (c) 2008, 2010-2019, Arm Limited and affiliates. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -15,8 +15,8 @@ * limitations under the License. */ /** - * \file address.c - * \brief Utility functions concernig addresses + * \file ns_address_internal.c + * \brief Utility functions concerning addresses * * This file contains all the utility functions that can be used to * check, manipulate etc. addresses. @@ -176,6 +176,9 @@ static bool addr_is_ipv4_mapped(const uint8_t addr[static 16]) /* Scope(A), as defined in RFC 6724 plus RFC 4007 */ uint_fast8_t addr_ipv6_scope(const uint8_t addr[static 16], const protocol_interface_info_entry_t *interface) { +#ifndef HAVE_THREAD + (void)interface; +#endif if (addr_is_ipv6_multicast(addr)) { return addr_ipv6_multicast_scope(addr); } diff --git a/source/Core/ns_socket.c b/source/Core/ns_socket.c index bb9bf3d5a2..24f7738c6f 100644 --- a/source/Core/ns_socket.c +++ b/source/Core/ns_socket.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2015, 2017-2018, Arm Limited and affiliates. + * Copyright (c) 2008-2015, 2017-2019, Arm Limited and affiliates. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -29,7 +29,7 @@ #include "eventOS_event.h" #include "eventOS_scheduler.h" #include "nsdynmemLIB.h" -#include "Core/include/socket.h" +#include "Core/include/ns_socket.h" #include "socket_api.h" #include "NWK_INTERFACE/Include/protocol.h" #include "Common_Protocols/tcp.h" diff --git a/source/Core/sockbuf.c b/source/Core/sockbuf.c index a61017cbfd..80e1bdd1da 100644 --- a/source/Core/sockbuf.c +++ b/source/Core/sockbuf.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2017, Arm Limited and affiliates. + * Copyright (c) 2016-2018, Arm Limited and affiliates. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/source/DHCPv6_Server/DHCPv6_Server_service.c b/source/DHCPv6_Server/DHCPv6_Server_service.c index 97a3fabcfd..4776d6ddea 100644 --- a/source/DHCPv6_Server/DHCPv6_Server_service.c +++ b/source/DHCPv6_Server/DHCPv6_Server_service.c @@ -232,7 +232,6 @@ int DHCPv6_server_service_init(int8_t interface, uint8_t guaPrefix[static 16], u uint16_t socketInstance; protocol_interface_info_entry_t *cur; (void)serverDUID; - (void)serverDUIDType; //allocate Socket Service socketInstance = dhcp_service_init(interface, DHCP_INSTANCE_SERVER, DHCPV6_server_service_request_handler); cur = protocol_stack_interface_info_get_by_id(interface); @@ -246,7 +245,7 @@ int DHCPv6_server_service_init(int8_t interface, uint8_t guaPrefix[static 16], u retVal = -2; } else { //allocate server - dhcpv6_gua_server_entry_s *serverInfo = libdhcpv6_gua_server_allocate(guaPrefix, interface, cur->mac, DHCPV6_DUID_HARDWARE_EUI64_TYPE); + dhcpv6_gua_server_entry_s *serverInfo = libdhcpv6_gua_server_allocate(guaPrefix, interface, cur->mac, serverDUIDType); if (serverInfo) { serverInfo->socketInstance_id = socketInstance; socketInstance = 0; diff --git a/source/DHCPv6_Server/DHCPv6_server_service.h b/source/DHCPv6_Server/DHCPv6_server_service.h index d2ba01068f..7373bedaa0 100644 --- a/source/DHCPv6_Server/DHCPv6_server_service.h +++ b/source/DHCPv6_Server/DHCPv6_server_service.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014-2017, Arm Limited and affiliates. + * Copyright (c) 2014-2018, Arm Limited and affiliates. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/source/DHCPv6_client/dhcpv6_client_api.h b/source/DHCPv6_client/dhcpv6_client_api.h index 69ae1ddd20..b1b6609e88 100644 --- a/source/DHCPv6_client/dhcpv6_client_api.h +++ b/source/DHCPv6_client/dhcpv6_client_api.h @@ -34,9 +34,22 @@ * /param interface interface id of this instance. * */ - void dhcp_client_init(int8_t interface); +/* Set configurations for DHCP client + * + * /param renew_uses_solicit Instead of renew message SOLICIT is used. + */ +void dhcp_client_configure(int8_t interface, bool renew_uses_solicit); + +/* Set Timeout parameters for SOLICIT transactions + * + * /param timeout SOLICIT timeout initial value. 0 means use defaults + * /param max_rt SOLICIT timeout max value. + * /param max_rc SOLICIT re-transmission count. 0 means infinite. + */ +void dhcp_client_solicit_timeout_set(int8_t interface, uint16_t timeout, uint16_t max_rt, uint8_t max_rc); + /* Delete dhcp client. * * When this is called all addressed assigned by this module are removed from stack. @@ -57,13 +70,14 @@ void dhcp_client_delete(int8_t interface); * /param dhcp_addr dhcp server ML16 address where address is registered. * /param prefix dhcp server ML16 address where address is registered. * /param mac64 64 bit mac address for identifieng client. + * /param link_type Link hardware type. * /param error_cb error callback that is called if address cannot be created or becomes invalid. * /param register_status true if address registered. * */ typedef void (dhcp_client_global_adress_cb)(int8_t interface, uint8_t dhcp_addr[static 16], uint8_t prefix[static 16], bool register_status); -int dhcp_client_get_global_address(int8_t interface, uint8_t dhcp_addr[static 16], uint8_t prefix[static 16], uint8_t mac64[static 8], dhcp_client_global_adress_cb *error_cb); +int dhcp_client_get_global_address(int8_t interface, uint8_t dhcp_addr[static 16], uint8_t prefix[static 16], uint8_t mac64[static 8], uint16_t link_type, dhcp_client_global_adress_cb *error_cb); /* Renew all leased adddresses might be used when short address changes * diff --git a/source/DHCPv6_client/dhcpv6_client_service.c b/source/DHCPv6_client/dhcpv6_client_service.c index c5f1e437f9..0e1c97cd81 100644 --- a/source/DHCPv6_client/dhcpv6_client_service.c +++ b/source/DHCPv6_client/dhcpv6_client_service.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, Arm Limited and affiliates. + * Copyright (c) 2018-2019, Arm Limited and affiliates. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -35,8 +35,12 @@ typedef struct { dhcp_client_global_adress_cb *global_address_cb; uint16_t service_instance; uint16_t relay_instance; + uint16_t sol_timeout; + uint16_t sol_max_rt; + uint8_t sol_max_rc; uint8_t libDhcp_instance; int8_t interface; + bool renew_uses_solicit: 1; } dhcp_client_class_t; static dhcp_client_class_t dhcp_client; @@ -50,6 +54,26 @@ void dhcp_client_init(int8_t interface) dhcp_client.service_instance = dhcp_service_init(interface, DHCP_INSTANCE_CLIENT, NULL); dhcp_client.interface = interface; dhcp_client.libDhcp_instance = libdhcpv6_nonTemporal_entry_get_unique_instance_id(); + dhcp_client.sol_timeout = 0; + dhcp_client.sol_max_rt = 0; + dhcp_client.sol_max_rc = 0; + + return; +} +void dhcp_client_configure(int8_t interface, bool renew_uses_solicit) +{ + // Set true if RENEW is not used and SOLICIT sent instead. + (void)interface; + dhcp_client.renew_uses_solicit = renew_uses_solicit; +} + +void dhcp_client_solicit_timeout_set(int8_t interface, uint16_t timeout, uint16_t max_rt, uint8_t max_rc) +{ + // Set the default retry values for SOLICIT and RENEW messages. + (void)interface; + dhcp_client.sol_timeout = timeout; + dhcp_client.sol_max_rt = max_rt; + dhcp_client.sol_max_rc = max_rc; return; } @@ -167,26 +191,36 @@ error_exit: return RET_MSG_ACCEPTED; } -int dhcp_client_get_global_address(int8_t interface, uint8_t dhcp_addr[static 16], uint8_t prefix[static 16], uint8_t mac64[static 8], dhcp_client_global_adress_cb *error_cb) +int dhcp_client_get_global_address(int8_t interface, uint8_t dhcp_addr[static 16], uint8_t prefix[static 16], uint8_t mac64[static 8], uint16_t link_type, dhcp_client_global_adress_cb *error_cb) { dhcpv6_solication_base_packet_s solPacket = {0}; - dhcpv6_ia_non_temporal_address_s nonTemporalAddress = {0}; + uint8_t *payload_ptr; uint32_t payload_len; dhcpv6_client_server_data_t *srv_data_ptr; - if (mac64 == NULL || prefix == NULL || dhcp_addr == NULL) { + if (mac64 == NULL || dhcp_addr == NULL) { tr_error("Invalid parameters"); return -1; } - srv_data_ptr = libdhcvp6_nontemporalAddress_server_data_allocate(interface, dhcp_client.libDhcp_instance, mac64, DHCPV6_DUID_HARDWARE_EUI64_TYPE, prefix, dhcp_addr); + if (!prefix) { + //NULL Definition will only check That Interface is not generated + if (libdhcpv6_nonTemporal_entry_get_by_instance(dhcp_client.libDhcp_instance)) { + //Already Created to same interface + return -1; + } + } + + srv_data_ptr = libdhcvp6_nontemporalAddress_server_data_allocate(interface, dhcp_client.libDhcp_instance, mac64, link_type, prefix, dhcp_addr); + if (!srv_data_ptr) { tr_error("OOM srv_data_ptr"); return -1; } - payload_len = libdhcpv6_solication_message_length(DHCPV6_DUID_HARDWARE_EUI64_TYPE, true, 0); + payload_len = libdhcpv6_solication_message_length(link_type, prefix != NULL, 0); + payload_ptr = ns_dyn_mem_temporary_alloc(payload_len); if (!payload_ptr) { libdhcvp6_nontemporalAddress_server_data_free(srv_data_ptr); @@ -198,13 +232,19 @@ int dhcp_client_get_global_address(int8_t interface, uint8_t dhcp_addr[static 16 srv_data_ptr->GlobalAddress = true; // Build solicit solPacket.clientDUID.linkID = mac64; - solPacket.clientDUID.linkType = DHCPV6_DUID_HARDWARE_EUI64_TYPE; + solPacket.clientDUID.linkType = link_type; solPacket.iaID = srv_data_ptr->IAID; solPacket.messageType = DHCPV6_SOLICATION_TYPE; solPacket.transActionId = libdhcpv6_txid_get(); /*Non Temporal Address */ - nonTemporalAddress.requestedAddress = prefix; - libdhcpv6_generic_nontemporal_address_message_write(payload_ptr, &solPacket, &nonTemporalAddress, NULL); + + if (prefix) { + dhcpv6_ia_non_temporal_address_s nonTemporalAddress = {0}; + nonTemporalAddress.requestedAddress = prefix; + libdhcpv6_generic_nontemporal_address_message_write(payload_ptr, &solPacket, &nonTemporalAddress, NULL); + } else { + libdhcpv6_generic_nontemporal_address_message_write(payload_ptr, &solPacket, NULL, NULL); + } // send solicit srv_data_ptr->transActionId = dhcp_service_send_req(dhcp_client.service_instance, 0, srv_data_ptr, dhcp_addr, payload_ptr, payload_len, dhcp_solicit_resp_cb); @@ -213,6 +253,10 @@ int dhcp_client_get_global_address(int8_t interface, uint8_t dhcp_addr[static 16 libdhcvp6_nontemporalAddress_server_data_free(srv_data_ptr); return -1; } + if (dhcp_client.sol_timeout != 0) { + // Default retry values are modified from specification update to message + dhcp_service_set_retry_timers(srv_data_ptr->transActionId, dhcp_client.sol_timeout, dhcp_client.sol_max_rt, dhcp_client.sol_max_rc); + } return 0; } @@ -289,6 +333,10 @@ void dhcpv6_renew(protocol_interface_info_entry_t *interface, if_address_entry_t .requestedOptionList = NULL, }; + if (dhcp_client.renew_uses_solicit) { + packetReq.messageType = DHCPV6_SOLICATION_TYPE; + } + // Set Address information nonTemporalAddress.requestedAddress = srv_data_ptr->iaNontemporalAddress.addressPrefix; nonTemporalAddress.preferredLifeTime = srv_data_ptr->iaNontemporalAddress.preferredTime; @@ -303,6 +351,10 @@ void dhcpv6_renew(protocol_interface_info_entry_t *interface, if_address_entry_t addr->state_timer = 200; //Retry after 20 seconds tr_error("DHCP renew send failed"); } + if (packetReq.messageType == DHCPV6_SOLICATION_TYPE && dhcp_client.sol_timeout != 0) { + // Default retry values are modified from specification update to message + dhcp_service_set_retry_timers(srv_data_ptr->transActionId, dhcp_client.sol_timeout, dhcp_client.sol_max_rt, dhcp_client.sol_max_rc); + } } void dhcpv6_client_set_address(int8_t interface_id, dhcpv6_client_server_data_t *srv_data_ptr) diff --git a/source/MAC/IEEE802_15_4/mac_defines.h b/source/MAC/IEEE802_15_4/mac_defines.h index 6a398396cc..d5623049ed 100644 --- a/source/MAC/IEEE802_15_4/mac_defines.h +++ b/source/MAC/IEEE802_15_4/mac_defines.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014-2018, Arm Limited and affiliates. + * Copyright (c) 2014-2019, Arm Limited and affiliates. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -216,7 +216,7 @@ typedef struct protocol_interface_rf_mac_setup { uint8_t mac_sequence; uint8_t mac_tx_retry; uint8_t mac_cca_retry; - uint8_t mac_ack_wait_duration; + uint16_t mac_ack_wait_duration; uint8_t mac_mlme_retry_max; uint8_t aUnitBackoffPeriod; /* Indirect queue parameters */ diff --git a/source/MAC/IEEE802_15_4/mac_fhss_callbacks.h b/source/MAC/IEEE802_15_4/mac_fhss_callbacks.h index 364c94339f..744e7c2485 100644 --- a/source/MAC/IEEE802_15_4/mac_fhss_callbacks.h +++ b/source/MAC/IEEE802_15_4/mac_fhss_callbacks.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2017, Arm Limited and affiliates. + * Copyright (c) 2016-2018, Arm Limited and affiliates. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/source/MAC/IEEE802_15_4/mac_header_helper_functions.c b/source/MAC/IEEE802_15_4/mac_header_helper_functions.c index c43c1103fc..7865cc7cf7 100644 --- a/source/MAC/IEEE802_15_4/mac_header_helper_functions.c +++ b/source/MAC/IEEE802_15_4/mac_header_helper_functions.c @@ -26,6 +26,7 @@ #include "MAC/IEEE802_15_4/mac_defines.h" #include "MAC/IEEE802_15_4/mac_mcps_sap.h" #include "MAC/IEEE802_15_4/mac_header_helper_functions.h" +#include "MAC/rf_driver_storage.h" static uint8_t *mcps_mac_security_aux_header_start_pointer_get(const mac_pre_parsed_frame_t *buffer); static uint8_t *mac_header_information_elements_write(const mac_pre_build_frame_t *buffer, uint8_t *ptr); @@ -569,7 +570,13 @@ uint8_t *mac_generic_packet_write(struct protocol_interface_rf_mac_setup *rf_ptr ptr += buffer->mac_payload_length; } if (rf_ptr->fhss_api) { - rf_ptr->fhss_api->write_synch_info(rf_ptr->fhss_api, ie_start, buffer->headerIeLength, FHSS_DATA_FRAME, buffer->tx_time); + if (buffer->fcf_dsn.frametype == FC_BEACON_FRAME) { + dev_driver_tx_buffer_s *tx_buf = &rf_ptr->dev_driver_tx_buffer; + uint8_t *synch_info = tx_buf->buf + rf_ptr->dev_driver->phy_driver->phy_header_length + tx_buf->len - FHSS_SYNCH_INFO_LENGTH; + rf_ptr->fhss_api->write_synch_info(rf_ptr->fhss_api, synch_info, FHSS_SYNCH_INFO_LENGTH, FHSS_SYNCH_FRAME, buffer->tx_time); + } else { + rf_ptr->fhss_api->write_synch_info(rf_ptr->fhss_api, ie_start, buffer->headerIeLength, FHSS_DATA_FRAME, buffer->tx_time); + } } return ptr; } diff --git a/source/MAC/IEEE802_15_4/mac_mcps_sap.c b/source/MAC/IEEE802_15_4/mac_mcps_sap.c index 2e15a2657a..b884b2c0f1 100644 --- a/source/MAC/IEEE802_15_4/mac_mcps_sap.c +++ b/source/MAC/IEEE802_15_4/mac_mcps_sap.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014-2018, Arm Limited and affiliates. + * Copyright (c) 2014-2019, Arm Limited and affiliates. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -987,7 +987,11 @@ static void mac_data_interface_frame_handler(mac_pre_parsed_frame_t *buf) mcps_sap_pre_parsed_frame_buffer_free(buf); return; } - //Sniffer Should push here data to stack!!!! + /* push data to stack if sniffer mode is enabled */ + if (rf_mac_setup->macProminousMode) { + mac_nap_tun_data_handler(buf, rf_mac_setup); + return; + } mac_api_t *mac = get_sw_mac_api(rf_mac_setup); if (!mac || (rf_mac_setup->mac_mlme_scan_resp && buf->fcf_dsn.frametype != MAC_FRAME_BEACON)) { mcps_sap_pre_parsed_frame_buffer_free(buf); @@ -1596,9 +1600,9 @@ static int8_t mcps_generic_packet_build(protocol_interface_rf_mac_setup_s *rf_pt return 0; } - int8_t mcps_generic_ack_build(protocol_interface_rf_mac_setup_s *rf_ptr, const mac_fcf_sequence_t *fcf, const uint8_t *data_ptr, const mcps_ack_data_payload_t *ack_payload, uint32_t rx_time) { + (void)rx_time; phy_device_driver_s *dev_driver = rf_ptr->dev_driver->phy_driver; dev_driver_tx_buffer_s *tx_buf = &rf_ptr->dev_driver_tx_buffer; diff --git a/source/MAC/IEEE802_15_4/mac_mlme.c b/source/MAC/IEEE802_15_4/mac_mlme.c index b4efbb2e55..03eb5fdfae 100644 --- a/source/MAC/IEEE802_15_4/mac_mlme.c +++ b/source/MAC/IEEE802_15_4/mac_mlme.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2018, Arm Limited and affiliates. + * Copyright (c) 2013-2019, Arm Limited and affiliates. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -68,6 +68,7 @@ static int8_t mac_mlme_rf_channel_set(struct protocol_interface_rf_mac_setup *rf static void mac_mlme_timer_cb(int8_t timer_id, uint16_t slots); static void mac_mlme_start_confirm_handler(protocol_interface_rf_mac_setup_s *rf_ptr, const mlme_start_conf_t *conf); static void mac_mlme_scan_confirm_handler(protocol_interface_rf_mac_setup_s *rf_ptr, const mlme_scan_conf_t *conf); +static int mac_mlme_set_symbol_rate(protocol_interface_rf_mac_setup_s *rf_mac_setup); static void mac_mlme_energy_scan_start(protocol_interface_rf_mac_setup_s *rf_mac_setup, uint8_t channel) { @@ -635,6 +636,29 @@ void mac_extended_mac_set(protocol_interface_rf_mac_setup_s *rf_mac_setup, const } } +static uint32_t mac_calc_ack_wait_duration(protocol_interface_rf_mac_setup_s *rf_mac_setup, uint16_t symbols) +{ + uint32_t AckWaitDuration = 0; + if (rf_mac_setup->rf_csma_extension_supported) { + AckWaitDuration = symbols * rf_mac_setup->symbol_time_us; + } + return AckWaitDuration; +} + +static int8_t mac_mlme_set_ack_wait_duration(protocol_interface_rf_mac_setup_s *rf_mac_setup, const mlme_set_t *set_req) +{ + uint16_t symbols = common_read_16_bit_inverse((uint8_t *)set_req->value_pointer); + uint32_t ack_wait_time_us = mac_calc_ack_wait_duration(rf_mac_setup, symbols); + if (ack_wait_time_us < 50) { + return -1; + } + // MAC timer uses 50us resolution + rf_mac_setup->mac_ack_wait_duration = ack_wait_time_us / 50; + tr_debug("Set macAckWaitDuration: %uus", rf_mac_setup->mac_ack_wait_duration * 50); + + return 0; +} + static int8_t mac_mlme_device_description_set(protocol_interface_rf_mac_setup_s *rf_mac_setup, const mlme_set_t *set_req) { @@ -707,6 +731,8 @@ int8_t mac_mlme_set_req(protocol_interface_rf_mac_setup_s *rf_mac_setup, const m } switch (set_req->attr) { + case macAckWaitDuration: + return mac_mlme_set_ack_wait_duration(rf_mac_setup, set_req); case macDeviceTable: return mac_mlme_device_description_set(rf_mac_setup, set_req); case macKeyTable: @@ -723,6 +749,10 @@ int8_t mac_mlme_set_req(protocol_interface_rf_mac_setup_s *rf_mac_setup, const m memcpy(rf_mac_setup->coord_long_address, set_req->value_pointer, 8); } return 0; + case macRfConfiguration: + rf_mac_setup->dev_driver->phy_driver->extension(PHY_EXTENSION_SET_RF_CONFIGURATION, (uint8_t *) set_req->value_pointer); + mac_mlme_set_symbol_rate(rf_mac_setup); + return 0; default: return mac_mlme_handle_set_values(rf_mac_setup, set_req); } @@ -1009,6 +1039,17 @@ static uint8_t mac_backoff_ticks_calc(phy_device_driver_s *phy_driver) return (uint8_t) ticks; } +static int mac_mlme_set_symbol_rate(protocol_interface_rf_mac_setup_s *rf_mac_setup) +{ + if (rf_mac_setup->rf_csma_extension_supported) { + rf_mac_setup->dev_driver->phy_driver->extension(PHY_EXTENSION_GET_SYMBOLS_PER_SECOND, (uint8_t *) &rf_mac_setup->symbol_rate); + rf_mac_setup->symbol_time_us = 1000000 / rf_mac_setup->symbol_rate; + tr_debug("SW-MAC driver support rf extension %"PRIu32" symbol/seconds %"PRIu32" us symbol time length", rf_mac_setup->symbol_rate, rf_mac_setup->symbol_time_us); + return 0; + } + return -1; +} + protocol_interface_rf_mac_setup_s *mac_mlme_data_base_allocate(uint8_t *mac64, arm_device_driver_list_s *dev_driver, mac_description_storage_size_t *storage_sizes) { uint16_t total_length = 0; @@ -1099,11 +1140,7 @@ protocol_interface_rf_mac_setup_s *mac_mlme_data_base_allocate(uint8_t *mac64, a bool rf_support = false; dev_driver->phy_driver->extension(PHY_EXTENSION_DYNAMIC_RF_SUPPORTED, (uint8_t *)&rf_support); entry->rf_csma_extension_supported = rf_support; - if (entry->rf_csma_extension_supported) { - entry->dev_driver->phy_driver->extension(PHY_EXTENSION_GET_SYMBOLS_PER_SECOND, (uint8_t *) &entry->symbol_rate); - entry->symbol_time_us = 1000000 / entry->symbol_rate; - tr_debug("SW-MAC driver support rf extension %"PRIu32" symbol/seconds %"PRIu32" us symbol time length", entry->symbol_rate, entry->symbol_time_us); - } + mac_mlme_set_symbol_rate(entry); //How many 10us ticks backoff period is for waiting 20symbols which is typically 10 bytes time entry->backoff_period_in_10us = mac_backoff_ticks_calc(dev_driver->phy_driver); @@ -1710,8 +1747,6 @@ int8_t mac_mlme_beacon_tx(protocol_interface_rf_mac_setup_s *rf_ptr) }*/ } buf->priority = MAC_PD_DATA_HIGH_PRIOTITY; - - tr_debug("BEA tx"); mcps_sap_pd_req_queue_write(rf_ptr, buf); sw_mac_stats_update(rf_ptr, STAT_MAC_BEA_TX_COUNT, 0); return 0; diff --git a/source/MAC/IEEE802_15_4/mac_pd_sap.c b/source/MAC/IEEE802_15_4/mac_pd_sap.c index 5e9dabc58a..0e1a760b7f 100644 --- a/source/MAC/IEEE802_15_4/mac_pd_sap.c +++ b/source/MAC/IEEE802_15_4/mac_pd_sap.c @@ -400,13 +400,6 @@ static int8_t mac_data_interface_tx_done_cb(protocol_interface_rf_mac_setup_s *r return -1; } - if (active_buf->fcf_dsn.frametype == FC_BEACON_FRAME) { - // FHSS synchronization info is written in the end of transmitted (Beacon) buffer - dev_driver_tx_buffer_s *tx_buf = &rf_ptr->dev_driver_tx_buffer; - uint8_t *synch_info = tx_buf->buf + rf_ptr->dev_driver->phy_driver->phy_header_length + tx_buf->len - FHSS_SYNCH_INFO_LENGTH; - rf_ptr->fhss_api->write_synch_info(rf_ptr->fhss_api, synch_info, 0, FHSS_SYNCH_FRAME, 0); - } - // Change to destination channel and write synchronization info to Beacon frames here int tx_handle_retval = rf_ptr->fhss_api->tx_handle(rf_ptr->fhss_api, !mac_is_ack_request_set(active_buf), active_buf->DstAddr, mac_convert_frame_type_to_fhss(active_buf->fcf_dsn.frametype), @@ -760,16 +753,15 @@ int8_t mac_pd_sap_data_cb(void *identifier, arm_phy_sap_msg_t *message) buffer->mac_payload_length -= (buffer->security_aux_header_length + mic_len); } + //Do not accept command frame with length 0 + if (fcf_read.frametype == FC_CMD_FRAME && length == 0) { + goto ERROR_HANDLER; + } - } - //Do not accept commend frame with length 0 - if (fcf_read.frametype == FC_CMD_FRAME && length == 0) { - goto ERROR_HANDLER; - } - - //Parse IE Elements - if (!mac_header_information_elements_parse(buffer)) { - goto ERROR_HANDLER; + //Parse IE Elements + if (!mac_header_information_elements_parse(buffer)) { + goto ERROR_HANDLER; + } } if (!rf_ptr->macProminousMode && buffer->fcf_dsn.frametype == FC_ACK_FRAME) { @@ -777,9 +769,7 @@ int8_t mac_pd_sap_data_cb(void *identifier, arm_phy_sap_msg_t *message) mcps_sap_pre_parsed_frame_buffer_free(buffer); } return 0; - } else { - if (mcps_sap_pd_ind(buffer) == 0) { return 0; } diff --git a/source/MAC/IEEE802_15_4/mac_security_mib.c b/source/MAC/IEEE802_15_4/mac_security_mib.c index 5dc9efc122..2fe2b8fbeb 100644 --- a/source/MAC/IEEE802_15_4/mac_security_mib.c +++ b/source/MAC/IEEE802_15_4/mac_security_mib.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2017, Arm Limited and affiliates. + * Copyright (c) 2016-2018, Arm Limited and affiliates. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/source/MAC/IEEE802_15_4/mac_security_mib.h b/source/MAC/IEEE802_15_4/mac_security_mib.h index 258fd0cf3d..05be16d572 100644 --- a/source/MAC/IEEE802_15_4/mac_security_mib.h +++ b/source/MAC/IEEE802_15_4/mac_security_mib.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2017, Arm Limited and affiliates. + * Copyright (c) 2016-2018, Arm Limited and affiliates. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/source/MAC/ethernet/ethernet_mac_api.c b/source/MAC/ethernet/ethernet_mac_api.c index 6c0413563c..913b141734 100644 --- a/source/MAC/ethernet/ethernet_mac_api.c +++ b/source/MAC/ethernet/ethernet_mac_api.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2017, Arm Limited and affiliates. + * Copyright (c) 2016-2018, Arm Limited and affiliates. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/source/MAC/rf_driver_storage.c b/source/MAC/rf_driver_storage.c index bea47ea4a8..6257406c3e 100644 --- a/source/MAC/rf_driver_storage.c +++ b/source/MAC/rf_driver_storage.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2017, Arm Limited and affiliates. + * Copyright (c) 2016-2018, Arm Limited and affiliates. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/source/MAC/rf_driver_storage.h b/source/MAC/rf_driver_storage.h index 0447f98fac..d9a82d9531 100644 --- a/source/MAC/rf_driver_storage.h +++ b/source/MAC/rf_driver_storage.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2017, Arm Limited and affiliates. + * Copyright (c) 2016-2018, Arm Limited and affiliates. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/source/MAC/serial/serial_mac_api.c b/source/MAC/serial/serial_mac_api.c index bf32f60729..469635208c 100644 --- a/source/MAC/serial/serial_mac_api.c +++ b/source/MAC/serial/serial_mac_api.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2017, Arm Limited and affiliates. + * Copyright (c) 2016-2018, Arm Limited and affiliates. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/source/MAC/virtual_rf/virtual_rf_client.c b/source/MAC/virtual_rf/virtual_rf_client.c index c6e4227a52..81395991f3 100644 --- a/source/MAC/virtual_rf/virtual_rf_client.c +++ b/source/MAC/virtual_rf/virtual_rf_client.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2018, Arm Limited and affiliates. + * Copyright (c) 2016-2019, Arm Limited and affiliates. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -31,7 +31,7 @@ static phy_device_driver_s device_driver; static int8_t rf_driver_id = (-1); -static const phy_rf_channel_configuration_s phy_2_4ghz = {2405000000, 5000000, 250000, 16, M_OQPSK}; +static const phy_rf_channel_configuration_s phy_2_4ghz = {.channel_0_center_frequency = 2405000000, .channel_spacing = 5000000, .datarate = 250000, .number_of_channels = 16, .modulation = M_OQPSK}; static const phy_device_channel_page_s phy_channel_pages = { CHANNEL_PAGE_0, &phy_2_4ghz}; static int8_t phy_rf_rx(const uint8_t *data_ptr, uint16_t data_len, uint8_t link_quality, int8_t dbm, int8_t driver_id) diff --git a/source/MAC/virtual_rf/virtual_rf_driver.c b/source/MAC/virtual_rf/virtual_rf_driver.c index ac90cf5246..78e8b9ef2c 100644 --- a/source/MAC/virtual_rf/virtual_rf_driver.c +++ b/source/MAC/virtual_rf/virtual_rf_driver.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2017, Arm Limited and affiliates. + * Copyright (c) 2016-2019, Arm Limited and affiliates. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -38,15 +38,15 @@ static int8_t rf_driver_id = (-1); static bool data_request_pending_flag = false; /** XXX: dummy values copied from Atmel RF driver */ -static const phy_rf_channel_configuration_s phy_2_4ghz = {2405000000, 5000000, 250000, 16, M_OQPSK}; -static const phy_rf_channel_configuration_s phy_subghz = {868300000, 2000000, 250000, 11, M_OQPSK}; +static const phy_rf_channel_configuration_s phy_2_4ghz = {.channel_0_center_frequency = 2405000000, .channel_spacing = 5000000, .datarate = 250000, .number_of_channels = 16, .modulation = M_OQPSK}; +static const phy_rf_channel_configuration_s phy_subghz = {.channel_0_center_frequency = 868300000, .channel_spacing = 2000000, .datarate = 250000, .number_of_channels = 11, .modulation = M_OQPSK}; -static const phy_rf_channel_configuration_s phy_subghz_8_ch = {868300000, 2000000, 250000, 8, M_OQPSK}; -static const phy_rf_channel_configuration_s phy_subghz_11_ch = {868300000, 2000000, 250000, 11, M_OQPSK}; -static const phy_rf_channel_configuration_s phy_subghz_16_ch = {868300000, 2000000, 250000, 16, M_OQPSK}; -static const phy_rf_channel_configuration_s phy_2_4ghz_14_ch = {2405000000, 1000000, 250000, 14, M_OQPSK}; -static const phy_rf_channel_configuration_s phy_2_4ghz_5_ch = {2405000000, 1000000, 250000, 5, M_OQPSK}; //For FHSS testing only -static const phy_rf_channel_configuration_s phy_2_4ghz_256_ch = {2405000000, 1000000, 250000, 256, M_OQPSK}; //For FHSS testing only +static const phy_rf_channel_configuration_s phy_subghz_8_ch = {.channel_0_center_frequency = 868300000, .channel_spacing = 2000000, .datarate = 250000, .number_of_channels = 8, .modulation = M_OQPSK}; +static const phy_rf_channel_configuration_s phy_subghz_11_ch = {.channel_0_center_frequency = 868300000, .channel_spacing = 2000000, .datarate = 250000, .number_of_channels = 11, .modulation = M_OQPSK}; +static const phy_rf_channel_configuration_s phy_subghz_16_ch = {.channel_0_center_frequency = 868300000, .channel_spacing = 2000000, .datarate = 250000, .number_of_channels = 16, .modulation = M_OQPSK}; +static const phy_rf_channel_configuration_s phy_2_4ghz_14_ch = {.channel_0_center_frequency = 2405000000, .channel_spacing = 1000000, .datarate = 250000, .number_of_channels = 14, .modulation = M_OQPSK}; +static const phy_rf_channel_configuration_s phy_2_4ghz_5_ch = {.channel_0_center_frequency = 2405000000, .channel_spacing = 1000000, .datarate = 250000, .number_of_channels = 5, .modulation = M_OQPSK}; //For FHSS testing only +static const phy_rf_channel_configuration_s phy_2_4ghz_256_ch = {.channel_0_center_frequency = 2405000000, .channel_spacing = 1000000, .datarate = 250000, .number_of_channels = 256, .modulation = M_OQPSK}; //For FHSS testing only static phy_device_channel_page_s phy_channel_pages[] = { {CHANNEL_PAGE_0, &phy_2_4ghz}, // this will be modified to contain 11 or 16 channels, depending on radio type diff --git a/source/MLE/mle.c b/source/MLE/mle.c index 87644b2ef5..8c24f6b0b1 100644 --- a/source/MLE/mle.c +++ b/source/MLE/mle.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2018, Arm Limited and affiliates. + * Copyright (c) 2013-2019, Arm Limited and affiliates. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -23,7 +23,7 @@ #include "eventOS_event.h" #include "eventOS_event_timer.h" #include "socket_api.h" -#include "Core/include/socket.h" +#include "Core/include/ns_socket.h" #include "nsdynmemLIB.h" #include "ns_trace.h" #include "string.h" diff --git a/source/MLE/mle.h b/source/MLE/mle.h index a842556956..7d4389b433 100644 --- a/source/MLE/mle.h +++ b/source/MLE/mle.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2018, Arm Limited and affiliates. + * Copyright (c) 2013-2019, Arm Limited and affiliates. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -19,7 +19,7 @@ #define MLE_H_ #include "nsconfig.h" -#include "Core/include/address.h" +#include "Core/include/ns_address_internal.h" #include "ns_list.h" struct buffer; diff --git a/source/MLE/mle_tlv.c b/source/MLE/mle_tlv.c index 383ee64514..284fb435ff 100644 --- a/source/MLE/mle_tlv.c +++ b/source/MLE/mle_tlv.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014-2017, Arm Limited and affiliates. + * Copyright (c) 2014-2018, Arm Limited and affiliates. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/source/NWK_INTERFACE/Include/protocol.h b/source/NWK_INTERFACE/Include/protocol.h index 18e12b5e99..b61bcbd3fa 100644 --- a/source/NWK_INTERFACE/Include/protocol.h +++ b/source/NWK_INTERFACE/Include/protocol.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014-2018, Arm Limited and affiliates. + * Copyright (c) 2014-2019, Arm Limited and affiliates. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -33,7 +33,7 @@ #include "NWK_INTERFACE/Include/protocol_abstract.h" // Users of protocol.h can assume it includes these headers -#include "Core/include/address.h" +#include "Core/include/ns_address_internal.h" #include "Core/include/ns_buffer.h" // Headers below this are implementation details - users of protocol.h shouldn't rely on them diff --git a/source/NWK_INTERFACE/protocol_core.c b/source/NWK_INTERFACE/protocol_core.c index c7a55e0107..b4225aa1c9 100644 --- a/source/NWK_INTERFACE/protocol_core.c +++ b/source/NWK_INTERFACE/protocol_core.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014-2018, Arm Limited and affiliates. + * Copyright (c) 2014-2019, Arm Limited and affiliates. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -23,7 +23,7 @@ #include "eventOS_callback_timer.h" #include "ns_trace.h" #include "nsdynmemLIB.h" -#include "Core/include/socket.h" +#include "Core/include/ns_socket.h" #include "NWK_INTERFACE/Include/protocol.h" #include "NWK_INTERFACE/Include/protocol_timer.h" #include "platform/arm_hal_interrupt.h" @@ -66,6 +66,9 @@ #include "6LoWPAN/Thread/thread_management_internal.h" #include "6LoWPAN/ws/ws_bootstrap.h" #include "6LoWPAN/ws/ws_common.h" +#ifdef HAVE_WS +#include "6LoWPAN/ws/ws_pae_controller.h" +#endif #include "ipv6_stack/protocol_ipv6.h" #include "Service_Libs/whiteboard/whiteboard.h" @@ -335,6 +338,9 @@ void core_timer_event_handle(uint16_t ticksUpdate) rpl_control_fast_timer(ticksUpdate); icmpv6_radv_timer(ticksUpdate); protocol_core_security_tick_update(ticksUpdate); +#ifdef HAVE_WS + ws_pae_controller_timer(ticksUpdate); +#endif platform_enter_critical(); protocol_core_timer_info.core_timer_event = false; platform_exit_critical(); @@ -778,7 +784,7 @@ protocol_interface_info_entry_t *protocol_stack_interface_info_get_by_fhss_api(c { #ifdef HAVE_WS ns_list_foreach(protocol_interface_info_entry_t, cur, &protocol_interface_info_list) { - if (cur->ws_info->fhss_api == fhss_api) { + if (cur->ws_info && (cur->ws_info->fhss_api == fhss_api)) { return cur; } } diff --git a/source/NWK_INTERFACE/protocol_timer.c b/source/NWK_INTERFACE/protocol_timer.c index e53b199ece..6997849ee7 100644 --- a/source/NWK_INTERFACE/protocol_timer.c +++ b/source/NWK_INTERFACE/protocol_timer.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014-2017, Arm Limited and affiliates. + * Copyright (c) 2014-2018, Arm Limited and affiliates. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/source/RPL/rpl_control.c b/source/RPL/rpl_control.c index 6c5650b419..91f54154d3 100644 --- a/source/RPL/rpl_control.c +++ b/source/RPL/rpl_control.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2018, Arm Limited and affiliates. + * Copyright (c) 2015-2019, Arm Limited and affiliates. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -227,6 +227,25 @@ void rpl_control_address_register_done(struct buffer *buf, uint8_t status) } } +bool rpl_control_is_dodag_parent(protocol_interface_info_entry_t *interface, const uint8_t ll_addr[16]) +{ + // go through instances and parents and check if they match the address. + ns_list_foreach(struct rpl_instance, instance, &interface->rpl_domain->instances) { + if (rpl_instance_address_is_parent(instance, ll_addr)) { + return true; + } + } + return false; +} +void rpl_control_neighbor_delete(protocol_interface_info_entry_t *interface, const uint8_t ll_addr[16]) +{ + // go through instances and delete address. + ns_list_foreach(struct rpl_instance, instance, &interface->rpl_domain->instances) { + rpl_instance_neighbor_delete(instance, ll_addr); + } + return; +} + /* Address changes need to trigger DAO target re-evaluation */ static void rpl_control_addr_notifier(struct protocol_interface_info_entry *interface, const if_address_entry_t *addr, if_address_callback_t reason) { @@ -489,6 +508,14 @@ void rpl_control_increment_dodag_version(rpl_dodag_t *dodag) rpl_dodag_set_version_number_as_root(dodag, new_version); } } +void rpl_control_update_dodag_config(struct rpl_dodag *dodag, const rpl_dodag_conf_t *conf) +{ + + if (rpl_dodag_am_root(dodag)) { + rpl_dodag_update_config(dodag, conf, NULL, NULL); + } +} + void rpl_control_set_dodag_pref(rpl_dodag_t *dodag, uint8_t pref) { diff --git a/source/RPL/rpl_control.h b/source/RPL/rpl_control.h index 100f5d87a2..7e9f123e87 100644 --- a/source/RPL/rpl_control.h +++ b/source/RPL/rpl_control.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2018, Arm Limited and affiliates. + * Copyright (c) 2015-2019, Arm Limited and affiliates. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -127,6 +127,7 @@ void rpl_control_delete_dodag_root(rpl_domain_t *domain, struct rpl_dodag *dodag void rpl_control_update_dodag_route(struct rpl_dodag *dodag, const uint8_t *prefix, uint8_t prefix_len, uint8_t flags, uint32_t lifetime, bool age); void rpl_control_update_dodag_prefix(struct rpl_dodag *dodag, const uint8_t *prefix, uint8_t prefix_len, uint8_t flags, uint32_t lifetime, uint32_t preftime, bool age); void rpl_control_increment_dodag_version(struct rpl_dodag *dodag); +void rpl_control_update_dodag_config(struct rpl_dodag *dodag, const rpl_dodag_conf_t *conf); void rpl_control_set_dodag_pref(struct rpl_dodag *dodag, uint8_t pref); void rpl_control_increment_dtsn(struct rpl_dodag *dodag); @@ -148,6 +149,8 @@ void rpl_control_publish_host_address(rpl_domain_t *domain, const uint8_t addr[1 void rpl_control_unpublish_address(rpl_domain_t *domain, const uint8_t addr[16]); void rpl_control_register_address(struct protocol_interface_info_entry *interface, if_address_entry_t *addr); void rpl_control_address_register_done(struct buffer *buf, uint8_t status); +bool rpl_control_is_dodag_parent(struct protocol_interface_info_entry *interface, const uint8_t ll_addr[16]); +void rpl_control_neighbor_delete(struct protocol_interface_info_entry *interface, const uint8_t ll_addr[16]); /* Configure and return the routing lookup predicate for a specified RPL instance ID */ ipv6_route_predicate_fn_t *rpl_control_get_route_predicate(rpl_domain_t *domain, uint8_t instance_id, const uint8_t src[16], const uint8_t dst[16]); diff --git a/source/RPL/rpl_downward.c b/source/RPL/rpl_downward.c index fa922e9edc..5f4c9f316a 100644 --- a/source/RPL/rpl_downward.c +++ b/source/RPL/rpl_downward.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2018, Arm Limited and affiliates. + * Copyright (c) 2015-2019, Arm Limited and affiliates. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -625,6 +625,7 @@ bool rpl_instance_address_registration_done(protocol_interface_info_entry_t *int addr->state_timer = (addr->preferred_lifetime * randLIB_get_random_in_range(75, 85) / 10); } else { tr_error("Address registration failed"); + rpl_delete_neighbour(instance, neighbour); } /* If that was last one to reply, send next one. */ diff --git a/source/RPL/rpl_mrhof.c b/source/RPL/rpl_mrhof.c index 9a34b02086..ea52ee2507 100644 --- a/source/RPL/rpl_mrhof.c +++ b/source/RPL/rpl_mrhof.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2017, Arm Limited and affiliates. + * Copyright (c) 2015-2018, Arm Limited and affiliates. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/source/RPL/rpl_objective.h b/source/RPL/rpl_objective.h index cf02a92b36..67c35fd7c8 100644 --- a/source/RPL/rpl_objective.h +++ b/source/RPL/rpl_objective.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2017, Arm Limited and affiliates. + * Copyright (c) 2015, 2017-2018, Arm Limited and affiliates. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/source/RPL/rpl_of0.c b/source/RPL/rpl_of0.c index 8a93ec4bb2..aa6927c1f1 100644 --- a/source/RPL/rpl_of0.c +++ b/source/RPL/rpl_of0.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2017, Arm Limited and affiliates. + * Copyright (c) 2015-2018, Arm Limited and affiliates. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/source/RPL/rpl_policy.c b/source/RPL/rpl_policy.c index f72df852e9..f31a51ec13 100644 --- a/source/RPL/rpl_policy.c +++ b/source/RPL/rpl_policy.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2017, Arm Limited and affiliates. + * Copyright (c) 2015-2019, Arm Limited and affiliates. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -24,7 +24,7 @@ #include "net_interface.h" -#include "Core/include/address.h" +#include "Core/include/ns_address_internal.h" #include "Service_Libs/etx/etx.h" #include "Common_Protocols/ipv6_resolution.h" #include "ipv6_stack/ipv6_routing_table.h" diff --git a/source/RPL/rpl_policy.h b/source/RPL/rpl_policy.h index 61b4034591..469656f474 100644 --- a/source/RPL/rpl_policy.h +++ b/source/RPL/rpl_policy.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2017, Arm Limited and affiliates. + * Copyright (c) 2015-2017, 2019, Arm Limited and affiliates. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -18,7 +18,7 @@ #ifndef RPL_POLICY_H_ #define RPL_POLICY_H_ -#include "Core/include/address.h" +#include "Core/include/ns_address_internal.h" #include "rpl_control.h" bool rpl_policy_join_instance(rpl_domain_t *domain, uint8_t instance_id, const uint8_t *dodagid); diff --git a/source/RPL/rpl_structures.h b/source/RPL/rpl_structures.h index a98d41039e..fac901ccd4 100644 --- a/source/RPL/rpl_structures.h +++ b/source/RPL/rpl_structures.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2017, Arm Limited and affiliates. + * Copyright (c) 2015-2018, Arm Limited and affiliates. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/source/RPL/rpl_upward.c b/source/RPL/rpl_upward.c index 96481e5ede..5990fbdf6a 100644 --- a/source/RPL/rpl_upward.c +++ b/source/RPL/rpl_upward.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2018, Arm Limited and affiliates. + * Copyright (c) 2015-2019, Arm Limited and affiliates. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -38,7 +38,7 @@ #include "net_interface.h" -#include "Core/include/address.h" +#include "Core/include/ns_address_internal.h" #include "Common_Protocols/icmpv6.h" #include "Common_Protocols/icmpv6_prefix.h" #include "NWK_INTERFACE/Include/protocol_abstract.h" @@ -1564,6 +1564,29 @@ uint16_t rpl_instance_current_rank(const rpl_instance_t *instance) return instance->current_rank; } +bool rpl_instance_address_is_parent(rpl_instance_t *instance, const uint8_t *ipv6_addr) +{ + ns_list_foreach(rpl_neighbour_t, neighbour, &instance->candidate_neighbours) { + if (neighbour->dodag_parent && addr_ipv6_equal(neighbour->ll_address, ipv6_addr)) { + return true; + } + if (!neighbour->dodag_parent) { + // list is ordered so first encounter of false means no more parents in list + return false; + } + } + return false; +} +void rpl_instance_neighbor_delete(rpl_instance_t *instance, const uint8_t *ipv6_addr) +{ + ns_list_foreach_safe(rpl_neighbour_t, neighbour, &instance->candidate_neighbours) { + if (addr_ipv6_equal(neighbour->ll_address, ipv6_addr)) { + rpl_delete_neighbour(instance, neighbour); + } + } + return; +} + void rpl_instance_slow_timer(rpl_instance_t *instance, uint16_t seconds) { ns_list_foreach(rpl_dodag_t, dodag, &instance->dodags) { diff --git a/source/RPL/rpl_upward.h b/source/RPL/rpl_upward.h index 1225e28549..5c626fa10a 100644 --- a/source/RPL/rpl_upward.h +++ b/source/RPL/rpl_upward.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2018, Arm Limited and affiliates. + * Copyright (c) 2015-2019, Arm Limited and affiliates. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -83,6 +83,8 @@ void rpl_instance_dio_trigger(rpl_instance_t *instance, struct protocol_interfac void rpl_instance_set_local_repair(rpl_instance_t *instance, bool repair); bool rpl_instance_local_repair(const rpl_instance_t *instance); uint16_t rpl_instance_current_rank(const rpl_instance_t *instance); +bool rpl_instance_address_is_parent(rpl_instance_t *instance, const uint8_t *ipv6_addr); +void rpl_instance_neighbor_delete(rpl_instance_t *instance, const uint8_t *ipv6_addr); void rpl_instance_slow_timer(rpl_instance_t *instance, uint16_t seconds); rpl_dodag_t *rpl_lookup_dodag(const rpl_instance_t *instance, const uint8_t *dodagid); diff --git a/source/Security/Common/sec_lib.h b/source/Security/Common/sec_lib.h index 30c5d46090..a1601e7fcc 100644 --- a/source/Security/Common/sec_lib.h +++ b/source/Security/Common/sec_lib.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2017, Arm Limited and affiliates. + * Copyright (c) 2013-2018, Arm Limited and affiliates. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/source/Security/Common/sec_lib_definitions.h b/source/Security/Common/sec_lib_definitions.h index 3be681c36f..d52883e19c 100644 --- a/source/Security/Common/sec_lib_definitions.h +++ b/source/Security/Common/sec_lib_definitions.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014-2017, Arm Limited and affiliates. + * Copyright (c) 2014-2018, Arm Limited and affiliates. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/source/Security/Common/security_lib.c b/source/Security/Common/security_lib.c index 67e163ab7a..ff3d31a0be 100644 --- a/source/Security/Common/security_lib.c +++ b/source/Security/Common/security_lib.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2017, Arm Limited and affiliates. + * Copyright (c) 2013-2019, Arm Limited and affiliates. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -20,7 +20,7 @@ #include "string.h" #include "eventOS_event.h" #include "nsdynmemLIB.h" -#include "Core/include/socket.h" +#include "Core/include/ns_socket.h" #include "NWK_INTERFACE/Include/protocol.h" #include "shalib.h" #include "randLIB.h" diff --git a/source/Security/PANA/eap_protocol.c b/source/Security/PANA/eap_protocol.c index 37fd10b266..8de694d335 100644 --- a/source/Security/PANA/eap_protocol.c +++ b/source/Security/PANA/eap_protocol.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017-2018, Arm Limited and affiliates. + * Copyright (c) 2017-2019, Arm Limited and affiliates. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -22,7 +22,7 @@ #include "eventOS_event.h" #include "ns_trace.h" #include "string.h" -#include "Core/include/socket.h" +#include "Core/include/ns_socket.h" #include "NWK_INTERFACE/Include/protocol.h" #include "6LoWPAN/Bootstraps/protocol_6lowpan.h" #include "6LoWPAN/Bootstraps/protocol_6lowpan_bootstrap.h" diff --git a/source/Security/PANA/pana.c b/source/Security/PANA/pana.c index 5ae36b7c34..f09eca992b 100644 --- a/source/Security/PANA/pana.c +++ b/source/Security/PANA/pana.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2018, Arm Limited and affiliates. + * Copyright (c) 2013-2019, Arm Limited and affiliates. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -22,7 +22,7 @@ #include "string.h" #include "randLIB.h" #include "nsdynmemLIB.h" -#include "Core/include/socket.h" +#include "Core/include/ns_socket.h" #include "NWK_INTERFACE/Include/protocol.h" #include "ccmLIB.h" #include "shalib.h" diff --git a/source/Security/PANA/pana.h b/source/Security/PANA/pana.h index 94b09392b8..a8b3f37256 100644 --- a/source/Security/PANA/pana.h +++ b/source/Security/PANA/pana.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2017, Arm Limited and affiliates. + * Copyright (c) 2013-2018, Arm Limited and affiliates. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/source/Security/PANA/pana_avp.c b/source/Security/PANA/pana_avp.c index 6962abafa7..f9f32dbaa8 100644 --- a/source/Security/PANA/pana_avp.c +++ b/source/Security/PANA/pana_avp.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, Arm Limited and affiliates. + * Copyright (c) 2017-2018, Arm Limited and affiliates. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/source/Security/PANA/pana_avp.h b/source/Security/PANA/pana_avp.h index 2aece9bd2f..5ee046c929 100644 --- a/source/Security/PANA/pana_avp.h +++ b/source/Security/PANA/pana_avp.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, Arm Limited and affiliates. + * Copyright (c) 2017-2018, Arm Limited and affiliates. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/source/Security/PANA/pana_client.c b/source/Security/PANA/pana_client.c index 52803fe8d1..d724e28539 100644 --- a/source/Security/PANA/pana_client.c +++ b/source/Security/PANA/pana_client.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, Arm Limited and affiliates. + * Copyright (c) 2017-2019, Arm Limited and affiliates. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -23,7 +23,7 @@ #include "string.h" #include "randLIB.h" #include "nsdynmemLIB.h" -#include "Core/include/socket.h" +#include "Core/include/ns_socket.h" #include "NWK_INTERFACE/Include/protocol.h" #include "ccmLIB.h" #include "shalib.h" diff --git a/source/Security/PANA/pana_eap_header.c b/source/Security/PANA/pana_eap_header.c index 99cda0ffa0..8d9ae32728 100644 --- a/source/Security/PANA/pana_eap_header.c +++ b/source/Security/PANA/pana_eap_header.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, Arm Limited and affiliates. + * Copyright (c) 2017-2019, Arm Limited and affiliates. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -19,7 +19,7 @@ #include "string.h" #include "common_functions.h" #include "Security/PANA/pana_eap_header.h" -#ifdef PANA +#if defined(PANA) || defined(HAVE_WS) bool eap_header_parse(uint8_t *data_ptr, uint16_t length, eap_header_t *header) { diff --git a/source/Security/PANA/pana_eap_header.h b/source/Security/PANA/pana_eap_header.h index 44dfa6f659..2498134433 100644 --- a/source/Security/PANA/pana_eap_header.h +++ b/source/Security/PANA/pana_eap_header.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, Arm Limited and affiliates. + * Copyright (c) 2017-2019, Arm Limited and affiliates. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -52,7 +52,7 @@ * */ -typedef struct { +typedef struct eap_header { uint16_t length; uint8_t eap_code; uint8_t id_seq; @@ -60,7 +60,7 @@ typedef struct { uint8_t *data_ptr; } eap_header_t; -typedef struct { +typedef struct eap_tls_header { uint8_t *data_ptr; uint8_t eap_tls_flags; uint16_t tls_frame_length; diff --git a/source/Security/PANA/pana_internal_api.h b/source/Security/PANA/pana_internal_api.h index 9ca385bf03..927f7ee18a 100644 --- a/source/Security/PANA/pana_internal_api.h +++ b/source/Security/PANA/pana_internal_api.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014-2017, Arm Limited and affiliates. + * Copyright (c) 2014-2018, Arm Limited and affiliates. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/source/Security/PANA/pana_server.c b/source/Security/PANA/pana_server.c index 5fbe45c937..e2b863e8f7 100644 --- a/source/Security/PANA/pana_server.c +++ b/source/Security/PANA/pana_server.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, Arm Limited and affiliates. + * Copyright (c) 2017-2019, Arm Limited and affiliates. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -22,7 +22,7 @@ #include "string.h" #include "randLIB.h" #include "nsdynmemLIB.h" -#include "Core/include/socket.h" +#include "Core/include/ns_socket.h" #include "NWK_INTERFACE/Include/protocol.h" #include "ccmLIB.h" #include "shalib.h" @@ -1742,6 +1742,8 @@ int8_t pana_server_restore_from_nvm(uint8_t *nvm_data, int8_t interface_id) int8_t pana_server_nvm_callback_set(pana_server_update_cb *update_cb, pana_server_session_get_cb *nvm_get, pana_server_session_get_by_id_cb *nvm_session_get, uint8_t *nvm_static_buffer) { (void)update_cb; + (void)nvm_get; + (void)nvm_session_get; (void)nvm_static_buffer; return -1; } diff --git a/source/Security/TLS/tls_ccm_crypt.h b/source/Security/TLS/tls_ccm_crypt.h index d845eae5e7..b82de08207 100644 --- a/source/Security/TLS/tls_ccm_crypt.h +++ b/source/Security/TLS/tls_ccm_crypt.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, Arm Limited and affiliates. + * Copyright (c) 2017-2018, Arm Limited and affiliates. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/source/Security/TLS/tls_lib.c b/source/Security/TLS/tls_lib.c index e4b438d132..99c206df68 100644 --- a/source/Security/TLS/tls_lib.c +++ b/source/Security/TLS/tls_lib.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2017, Arm Limited and affiliates. + * Copyright (c) 2013-2019, Arm Limited and affiliates. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -18,14 +18,14 @@ #include "ns_types.h" #ifdef PANA #include "string.h" -#include "Core/include/address.h" +#include "Core/include/ns_address_internal.h" #include "Core/include/ns_buffer.h" #ifdef ECC #include "libX509_V3.h" #include "ecc.h" #endif #include "randLIB.h" -#include "Core/include/socket.h" +#include "Core/include/ns_socket.h" //#include "6LoWPAN/Bootstraps/network_lib.h" #include "shalib.h" #include "Security/TLS/tls_lib.h" diff --git a/source/Security/TLS/tls_lib.h b/source/Security/TLS/tls_lib.h index ce07760455..c369e20635 100644 --- a/source/Security/TLS/tls_lib.h +++ b/source/Security/TLS/tls_lib.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2017, Arm Limited and affiliates. + * Copyright (c) 2013-2018, Arm Limited and affiliates. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/source/Security/eapol/eapol_helper.c b/source/Security/eapol/eapol_helper.c new file mode 100644 index 0000000000..64a45e3935 --- /dev/null +++ b/source/Security/eapol/eapol_helper.c @@ -0,0 +1,278 @@ +/* + * Copyright (c) 2018-2019, 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/PANA/pana_eap_header.h" +#include "Security/eapol/eapol_helper.h" + +#ifdef HAVE_WS + +#define KEY_INFO_VERSION_BIT_MASK 0x0007 +#define KEY_INFO_VERSION_BIT_SHIFT 0 +#define KEY_INFO_KEY_TYPE_BIT_MASK 0x0008 +#define KEY_INFO_KEY_TYPE_BIT_SHIFT 3 +#define KEY_INFO_INSTALL_BIT_MASK 0x0040 +#define KEY_INFO_INSTALL_BIT_SHIFT 6 +#define KEY_INFO_ACK_BIT_MASK 0x0080 +#define KEY_INFO_ACK_BIT_SHIFT 7 +#define KEY_INFO_MIC_MASK 0x0100 +#define KEY_INFO_MIC_SHIFT 8 +#define KEY_INFO_SECURE_MASK 0x0200 +#define KEY_INFO_SECURE_SHIFT 9 +#define KEY_INFO_ERROR_MASK 0x0400 +#define KEY_INFO_ERROR_SHIFT 10 +#define KEY_INFO_REQUEST_MASK 0x0800 +#define KEY_INFO_REQUEST_SHIFT 11 +#define KEY_INFO_ENC_KEY_DATA_MASK 0x1000 +#define KEY_INFO_ENC_KEY_DATA_SHIFT 12 +#define KEY_INFO_SMK_MASK 0x2000 +#define KEY_INFO_SMK_SHIFT 13 + +static uint8_t *eapol_key_information_write(eapol_key_information_t *key_information, uint8_t *ptr) +{ + uint16_t key_info = 0; + key_info |= (key_information->description_version << KEY_INFO_VERSION_BIT_SHIFT); + key_info |= (key_information->pairwise_key << KEY_INFO_KEY_TYPE_BIT_SHIFT); + key_info |= (key_information->install << KEY_INFO_INSTALL_BIT_SHIFT); + key_info |= (key_information->key_ack << KEY_INFO_ACK_BIT_SHIFT); + key_info |= (key_information->key_mic << KEY_INFO_MIC_SHIFT); + key_info |= (key_information->secured_key_frame << KEY_INFO_SECURE_SHIFT); + key_info |= (key_information->error << KEY_INFO_ERROR_SHIFT); + key_info |= (key_information->request << KEY_INFO_REQUEST_SHIFT); + key_info |= (key_information->encrypted_key_data << KEY_INFO_ENC_KEY_DATA_SHIFT); + key_info |= (key_information->smk_handshake << KEY_INFO_SMK_SHIFT); + return common_write_16_bit(key_info, ptr); +} + +static uint8_t *eapol_key_information_read(eapol_key_information_t *key_information, uint8_t *ptr) +{ + uint16_t key_info = common_read_16_bit(ptr); + key_information->description_version = ((key_info & KEY_INFO_VERSION_BIT_MASK) >> KEY_INFO_VERSION_BIT_SHIFT); + key_information->pairwise_key = ((key_info & KEY_INFO_KEY_TYPE_BIT_MASK) >> KEY_INFO_KEY_TYPE_BIT_SHIFT); + key_information->install = ((key_info & KEY_INFO_INSTALL_BIT_MASK) >> KEY_INFO_INSTALL_BIT_SHIFT); + key_information->key_ack = ((key_info & KEY_INFO_ACK_BIT_MASK) >> KEY_INFO_ACK_BIT_SHIFT); + key_information->key_mic = ((key_info & KEY_INFO_MIC_MASK) >> KEY_INFO_MIC_SHIFT); + key_information->secured_key_frame = ((key_info & KEY_INFO_SECURE_MASK) >> KEY_INFO_SECURE_SHIFT); + key_information->error = ((key_info & KEY_INFO_ERROR_MASK) >> KEY_INFO_ERROR_SHIFT); + key_information->request = ((key_info & KEY_INFO_REQUEST_MASK) >> KEY_INFO_REQUEST_SHIFT); + key_information->encrypted_key_data = ((key_info & KEY_INFO_ENC_KEY_DATA_MASK) >> KEY_INFO_ENC_KEY_DATA_SHIFT); + key_information->smk_handshake = ((key_info & KEY_INFO_SMK_MASK) >> KEY_INFO_SMK_SHIFT); + return ptr + 2; +} + + +static bool eapol_parse_eap_packet(eapol_pdu_t *eapol_pdu) +{ + return eap_header_parse(eapol_pdu->packet_body, eapol_pdu->packet_length, &eapol_pdu->msg.eap); +} + + +static bool eapol_parse_key_packet(eapol_pdu_t *eapol_pdu) +{ + if (eapol_pdu->packet_length < EAPOL_KEY_FRAME_BASE_SIZE) { + return false; + } + uint8_t *ptr = eapol_pdu->packet_body; + eapol_key_frame_t *key_frame = &eapol_pdu->msg.key; + key_frame->key_description = *ptr++; + if (key_frame->key_description != EAPOL_RSN_KEY_DESCRIPTION) { + return false; + } + ptr = eapol_key_information_read(&key_frame->key_information, ptr); + if (key_frame->key_information.description_version != KEY_DESCRIPTION_HMAC_SHA1_MIC_AES_ENC) { + return false; + } + key_frame->key_length = common_read_16_bit(ptr); + ptr += 2; + + key_frame->replay_counter = common_read_64_bit(ptr); + ptr += 8; + + key_frame->key_nonce = ptr; + ptr += 32; + + key_frame->key_iv = ptr; + ptr += 16; + + key_frame->key_rsc = ptr; + ptr += 16; //Skip 8 byte RSC + RESERVED 8 + + key_frame->key_mic = ptr; + ptr += 16; + + key_frame->key_data_length = common_read_16_bit(ptr); + ptr += 2; + key_frame->key_data = ptr; + if (key_frame->key_data_length > (eapol_pdu->packet_length - EAPOL_KEY_FRAME_BASE_SIZE)) { + return false; + } + + return true; + +} + +void eapol_write_key_packet_mic(uint8_t *eapol_pdu, uint8_t *mic) +{ + if (mic) { + memcpy(&eapol_pdu[81], mic, 16); + } else { + memset(&eapol_pdu[81], 0, 16); + } +} + +bool eapol_parse_pdu_header(uint8_t *ptr, uint16_t data_length, eapol_pdu_t *eapol_pdu) +{ + //Validate MIN length + if (data_length < EAPOL_BASE_LENGTH) { + return false; + } + //Validate Protocol version + uint8_t protocol = *ptr++; + if (protocol != EAPOL_PROTOCOL_VERSION) { + return false; + } + eapol_pdu->packet_type = *ptr++; + eapol_pdu->packet_length = common_read_16_bit(ptr); + ptr += 2; + //Validate Body Length + if (eapol_pdu->packet_length > data_length - EAPOL_BASE_LENGTH) { + return false; + } + eapol_pdu->packet_body = ptr; + + if (eapol_pdu->packet_type == EAPOL_EAP_TYPE) { + return eapol_parse_eap_packet(eapol_pdu); + } else if (eapol_pdu->packet_type == EAPOL_KEY_TYPE) { + return eapol_parse_key_packet(eapol_pdu); + } else { + return false; + } + +} + +uint8_t *eapol_write_pdu_frame(uint8_t *ptr, eapol_pdu_t *eapol_pdu) +{ + *ptr++ = EAPOL_PROTOCOL_VERSION; + *ptr++ = eapol_pdu->packet_type; + ptr = common_write_16_bit(eapol_pdu->packet_length, ptr); + eapol_pdu->packet_body = ptr; + + if (eapol_pdu->packet_type == EAPOL_EAP_TYPE) { + eap_header_t *eap_header = &eapol_pdu->msg.eap; + ptr = eap_header_build(ptr, eap_header->length, eap_header->eap_code, eap_header->id_seq, eap_header->type); + memcpy(ptr, eap_header->data_ptr, eap_header->length - (ptr - eapol_pdu->packet_body)); + ptr += eap_header->length - (ptr - eapol_pdu->packet_body); + + } else if (eapol_pdu->packet_type == EAPOL_KEY_TYPE) { + eapol_key_frame_t *key_frame = &eapol_pdu->msg.key; + *ptr++ = key_frame->key_description; + ptr = eapol_key_information_write(&key_frame->key_information, ptr); + ptr = common_write_16_bit(key_frame->key_length, ptr); + ptr = common_write_64_bit(key_frame->replay_counter, ptr); + + if (key_frame->key_nonce) { + memcpy(ptr, key_frame->key_nonce, 32); + } else { + memset(ptr, 0, 32); + } + ptr += 32; + + if (key_frame->key_iv) { + memcpy(ptr, key_frame->key_iv, 16); + } else { + memset(ptr, 0, 16); + } + ptr += 16; + + if (key_frame->key_rsc) { + memcpy(ptr, key_frame->key_rsc, 8); + } else { + memset(ptr, 0, 8); + } + ptr += 8; + + //Reserved 8bytes + memset(ptr, 0, 8); + ptr += 8; + + if (key_frame->key_mic && key_frame->key_information.key_mic) { + memcpy(ptr, key_frame->key_mic, 16); + } else { + memset(ptr, 0, 16); + } + ptr += 16; + ptr = common_write_16_bit(key_frame->key_data_length, ptr); + if (key_frame->key_data_length && key_frame->key_data) { + memcpy(ptr, key_frame->key_data, key_frame->key_data_length); + ptr += key_frame->key_data_length; + } + } + + return ptr; +} + + + +uint16_t eapol_pdu_eap_frame_init(eapol_pdu_t *eapol_pdu, uint8_t eap_code, uint8_t id_seq, uint8_t type, uint16_t data_length, uint8_t *data_ptr) +{ + memset(eapol_pdu, 0, sizeof(eapol_pdu_t)); + + eapol_pdu->packet_type = EAPOL_EAP_TYPE; + eapol_pdu->packet_length = data_length; + eapol_pdu->msg.eap.eap_code = eap_code; + eapol_pdu->msg.eap.data_ptr = data_ptr; + eapol_pdu->msg.eap.length = data_length; + eapol_pdu->msg.eap.id_seq = id_seq; + eapol_pdu->msg.eap.type = type; + + if (eap_code == EAP_REQ || eap_code == EAP_RESPONSE) { + eapol_pdu->packet_body += 5; + eapol_pdu->msg.eap.length++; // Add space for type + eapol_pdu->packet_length++; + } else { + eapol_pdu->packet_body += 4; + } + + return eapol_pdu_total_length(eapol_pdu); + +} + +uint16_t eapol_pdu_key_frame_init(eapol_pdu_t *eapol_pdu, uint16_t data_length, uint8_t *data_ptr) +{ + memset(eapol_pdu, 0, sizeof(eapol_pdu_t)); + + eapol_pdu->packet_type = EAPOL_KEY_TYPE; + eapol_pdu->packet_length = data_length + EAPOL_KEY_FRAME_BASE_SIZE; + eapol_pdu->msg.key.key_data = data_ptr; + eapol_pdu->msg.key.key_description = EAPOL_RSN_KEY_DESCRIPTION; + eapol_pdu->msg.key.key_data_length = data_length; + eapol_pdu->msg.key.key_information.description_version = KEY_DESCRIPTION_HMAC_SHA1_MIC_AES_ENC; + + return eapol_pdu_total_length(eapol_pdu); + +} + +#endif + diff --git a/source/Security/eapol/eapol_helper.h b/source/Security/eapol/eapol_helper.h new file mode 100644 index 0000000000..47439f1f79 --- /dev/null +++ b/source/Security/eapol/eapol_helper.h @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2018-2019, 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 EAPOL_HELPER_H_ +#define EAPOL_HELPER_H_ + +#define EAPOL_PROTOCOL_VERSION 3 +#define EAPOL_EAP_TYPE 0 +#define EAPOL_KEY_TYPE 3 +#define EAPOL_KEY_NONCE_LEN 32 +#define EAPOL_KEY_MIC_LEN 16 + +#define EAPOL_BASE_LENGTH 4 //Protocol version 1 byte, Packet type 1 byte, packet length 2 byte + +#define EAPOL_KEY_FRAME_BASE_SIZE 95 + +struct eap_header_t; + +typedef struct eapol_key_information { + unsigned description_version: 3; + bool pairwise_key: 1; + bool install: 1; + bool key_ack: 1; + bool key_mic: 1; + bool secured_key_frame: 1; + bool error: 1; + bool request: 1; + bool encrypted_key_data: 1; + bool smk_handshake: 1; +} eapol_key_information_t; + +typedef struct eapol_key_frame { + uint8_t key_description; + eapol_key_information_t key_information; + uint16_t key_length; + uint64_t replay_counter; + uint8_t *key_nonce; /*< Write operation: NULL memset are by 0, otherwise write data */ + uint8_t *key_iv; /*< Write operation: NULL memset are by 0, otherwise write data */ + uint8_t *key_rsc; /*< Write operation: NULL memset are by 0, otherwise write data */ + uint8_t *key_mic; /*< Write operation: NULL memset are by 0, otherwise write data */ + uint16_t key_data_length; + uint8_t *key_data; +} eapol_key_frame_t; + +typedef struct eapol_pdu { + uint8_t packet_type; /*< EAPOL_EAP_TYPE or EAPOL_KEY_TYPE */ + uint16_t packet_length; /*< EAPOL Total length includin full packet body and data */ + uint8_t *packet_body; /*< Data pointer to packet body*/ + union { + eapol_key_frame_t key; + struct eap_header eap; + } msg; +} eapol_pdu_t; + +#define EAPOL_RSN_KEY_DESCRIPTION 2 +#define KEY_DESCRIPTION_HMAC_MD5_MIC_ARC4_ENC 1 +#define KEY_DESCRIPTION_HMAC_SHA1_MIC_AES_ENC 2 +#define KEY_DESCRIPTION_AES_128_CMAC_MIC_AES_ENC 3 + +/** + * Helper macro to get full message length + */ +#define eapol_pdu_total_length(x) (x->packet_length + EAPOL_BASE_LENGTH) + +/** + * Helper macro to message start + */ +#define eapol_pdu_msg_start(x) (x->packet_body - EAPOL_BASE_LENGTH) + +/** + * Parse EAPOL message to EAPOL-pdu frame + * + * \return true when message is valid and supported otherwise return false + */ +bool eapol_parse_pdu_header(uint8_t *ptr, uint16_t data_length, eapol_pdu_t *eapol_pdu); + +uint8_t *eapol_write_pdu_frame(uint8_t *ptr, eapol_pdu_t *eapol_pdu); + +uint16_t eapol_pdu_eap_frame_init(eapol_pdu_t *eapol_pdu, uint8_t eap_code, uint8_t id_seq, uint8_t type, uint16_t data_length, uint8_t *data_ptr); + +uint16_t eapol_pdu_key_frame_init(eapol_pdu_t *eapol_pdu, uint16_t data_length, uint8_t *data_ptr); + +void eapol_write_key_packet_mic(uint8_t *eapol_pdu, uint8_t *mic); + +#endif /* EAPOL_HELPER_H_ */ diff --git a/source/Security/eapol/kde_helper.c b/source/Security/eapol/kde_helper.c new file mode 100644 index 0000000000..042c42a649 --- /dev/null +++ b/source/Security/eapol/kde_helper.c @@ -0,0 +1,244 @@ +/* + * Copyright (c) 2018-2019, 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/eapol/kde_helper.h" + +#ifdef HAVE_WS + +#define TRACE_GROUP "kdeh" + +#define IEEE_802_11_OUI ieee_802_11_oui +#define WISUN_OUI wisun_oui + +const uint8_t ieee_802_11_oui[3] = {0x00, 0x0F, 0xAC}; +const uint8_t wisun_oui[3] = {0x0C, 0x5A, 0x9E}; + +#define KDE_TYPE 0xdd + +// IEEE 802.11 +#define KDE_GTK 0x01 +#define KDE_PMKID 0x04 +#define KDE_LIFETIME 0x07 +// Wi-Sun +#define KDE_PTKID 0x01 +#define KDE_GTKL 0x02 + +#define GTK_LEN 16 +#define PMKID_LEN 16 +#define PTKID_LEN 16 + +#define KDE_MIN_LEN 6 +#define KDE_FIXED_LEN 2 + +#define KDE_PADDED_MIN_LEN 16 + +#define KDE_TYPE_INDEX 0 +#define KDE_LENGTH_INDEX 1 +#define KDE_OUI1_INDEX 2 +#define KDE_OUI2_INDEX 3 +#define KDE_OUI3_INDEX 4 +#define KDE_DATA_TYPE_INDEX 5 +#define KDE_DATA_INDEX 6 + +/* + From IEEE 802.11 chapter 11.6.2 EAPOL-Key frames + + If the Encrypted Key Data subfield (of the Key Information field) is 1, + the entire Key Data field shall be encrypted. If the Key Data field + uses the NIST AES key wrap, then the Key Data field shall be padded before + encrypting if the key data length is less than 16 octets or if it is not + a multiple of 8. + The padding consists of appending a single octet 0xdd followed by zero + or more 0x00 octets. When processing a received EAPOL-Key message, the + receiver shall ignore this trailing padding. +*/ +uint16_t kde_padded_length_calc(uint16_t kde_length) +{ + if (kde_length < KDE_PADDED_MIN_LEN) { + return KDE_PADDED_MIN_LEN; + } + + return ((kde_length + 7) / 8) * 8; +} + +void kde_padding_write(uint8_t *start_ptr, uint8_t *end_ptr) +{ + uint8_t padding = 0xdd; + + while (start_ptr < end_ptr) { + *start_ptr++ = padding; + padding = 0x00; + } +} + +static uint8_t *kde_header_write(uint8_t *ptr, const uint8_t *oui, uint8_t data_type, uint8_t data_length) +{ + *ptr++ = KDE_TYPE; + *ptr++ = data_length - KDE_FIXED_LEN; + *ptr++ = oui[0]; + *ptr++ = oui[1]; + *ptr++ = oui[2]; + *ptr++ = data_type; + + return ptr; +} + +static const uint8_t *kde_search(const uint8_t *ptr, uint16_t len, const uint8_t *oui, uint8_t data_type, uint16_t kde_min_len) +{ + while (len >= KDE_MIN_LEN) { + uint16_t kde_len = ptr[1] + KDE_FIXED_LEN; + + // Type shall be 0xdd and length shall be at least 6 */ + if (ptr[KDE_TYPE_INDEX] != 0xdd || kde_len < KDE_MIN_LEN || kde_len > len) { + return NULL; + } + + if (kde_len >= kde_min_len && ptr[KDE_OUI1_INDEX] == oui[0] && ptr[KDE_OUI2_INDEX] == oui[1] + && ptr[KDE_OUI3_INDEX] == oui[2] && ptr[KDE_DATA_TYPE_INDEX] == data_type) { + return &ptr[KDE_DATA_INDEX]; + } + + if (len > kde_len) { + len -= kde_len; + ptr += kde_len; + } else { + return NULL; + } + } + + return NULL; +} + +uint8_t *kde_gtk_write(uint8_t *ptr, uint8_t key_id, const uint8_t *gtk) +{ + ptr = kde_header_write(ptr, IEEE_802_11_OUI, KDE_GTK, KDE_GTK_LEN); + + // bits 0-1: keyid (0,1,2, or 3), bit 2: Tx, other: reserved (0) + *ptr++ = key_id; + *ptr++ = 0x00; // reserved + memcpy(ptr, gtk, GTK_LEN); + ptr += GTK_LEN; + + return ptr; +} + +uint8_t *kde_pmkid_write(uint8_t *ptr, const uint8_t *pmkid) +{ + ptr = kde_header_write(ptr, IEEE_802_11_OUI, KDE_PMKID, KDE_PMKID_LEN); + + memcpy(ptr, pmkid, PMKID_LEN); + ptr += PMKID_LEN; + + return ptr; +} + +uint8_t *kde_ptkid_write(uint8_t *ptr, const uint8_t *ptkid) +{ + ptr = kde_header_write(ptr, WISUN_OUI, KDE_PTKID, KDE_PTKID_LEN); + + memcpy(ptr, ptkid, PTKID_LEN); + ptr += PTKID_LEN; + + return ptr; +} + +uint8_t *kde_lifetime_write(uint8_t *ptr, uint32_t lifetime) +{ + ptr = kde_header_write(ptr, IEEE_802_11_OUI, KDE_LIFETIME, KDE_LIFETIME_LEN); + ptr = common_write_32_bit(lifetime, ptr); + + return ptr; +} + +uint8_t *kde_gtkl_write(uint8_t *ptr, uint8_t gtkl) +{ + ptr = kde_header_write(ptr, WISUN_OUI, KDE_GTKL, KDE_GTKL_LEN); + *ptr++ = gtkl; + + return ptr; +} + +int8_t kde_gtk_read(const uint8_t *ptr, uint16_t len, uint8_t *key_id, uint8_t *gtk) +{ + ptr = kde_search(ptr, len, IEEE_802_11_OUI, KDE_GTK, KDE_GTK_LEN); + if (ptr == NULL) { + return -1; + } + + *key_id = *ptr++ & 0x03; + ptr++; + memcpy(gtk, ptr, GTK_LEN); + + return 0; +} + +int8_t kde_pmkid_read(const uint8_t *ptr, uint16_t len, uint8_t *pmkid) +{ + ptr = kde_search(ptr, len, IEEE_802_11_OUI, KDE_PMKID, KDE_PMKID_LEN); + if (ptr == NULL) { + return -1; + } + + memcpy(pmkid, ptr, PMKID_LEN); + + return 0; +} + +int8_t kde_ptkid_read(const uint8_t *ptr, uint16_t len, uint8_t *ptkid) +{ + ptr = kde_search(ptr, len, WISUN_OUI, KDE_PTKID, KDE_PTKID_LEN); + if (ptr == NULL) { + return -1; + } + + memcpy(ptkid, ptr, PTKID_LEN); + + return 0; +} + +int8_t kde_lifetime_read(const uint8_t *ptr, uint16_t len, uint32_t *lifetime) +{ + ptr = kde_search(ptr, len, IEEE_802_11_OUI, KDE_LIFETIME, KDE_LIFETIME_LEN); + if (ptr == NULL) { + return -1; + } + + *lifetime = common_read_32_bit(ptr); + + return 0; +} + +int8_t kde_gtkl_read(const uint8_t *ptr, uint16_t len, uint8_t *gtkl) +{ + ptr = kde_search(ptr, len, WISUN_OUI, KDE_GTKL, KDE_GTKL_LEN); + if (ptr == NULL) { + return -1; + } + + *gtkl = *ptr; + + return 0; +} + +#endif + diff --git a/source/Security/eapol/kde_helper.h b/source/Security/eapol/kde_helper.h new file mode 100644 index 0000000000..b735828e61 --- /dev/null +++ b/source/Security/eapol/kde_helper.h @@ -0,0 +1,172 @@ +/* + * Copyright (c) 2018-2019, 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 KDE_HELPER_H_ +#define KDE_HELPER_H_ + +/* + * EAPOL KDE helper functions + * + */ + +#define KDE_GTK_LEN 6 + 2 + 16 +#define KDE_PMKID_LEN 6 + 16 +#define KDE_PTKID_LEN 6 + 16 +#define KDE_LIFETIME_LEN 6 + 4 +#define KDE_GTKL_LEN 6 + 1 + +/** + * kde_padded_length_calc calculates padded length for kde (see IEEE 802.11 chapter 11.6.2 EAPOL-Key frames) + * + * \param kde_length length without padding + * + * \return padded length + */ +uint16_t kde_padded_length_calc(uint16_t kde_length); + +/** + * kde_padding_write writes padded bytes + * + * \param start_ptr first byte of the padding + * \param end_ptr last bytes next byte + * + */ +void kde_padding_write(uint8_t *start_ptr, uint8_t *end_ptr); + +/** + * kde_gtk_write writes GTK + * + * \param ptr pointer where to write + * \param key_id key identifier (index) + * \param gtk GTK + * + * return incremented write pointer + * + */ +uint8_t *kde_gtk_write(uint8_t *ptr, uint8_t key_id, const uint8_t *gtk); + +/** + * kde_pmkid_write writes PMKID + * + * \param ptr pointer where to write + * \param pmkid PMKID + * + * return incremented write pointer + * + */ +uint8_t *kde_pmkid_write(uint8_t *ptr, const uint8_t *pmkid); + +/** + * kde_ptkid_write writes PTKID + * + * \param ptr pointer where to write + * \param pmkid PTKID + * + * return incremented write pointer + * + */ +uint8_t *kde_ptkid_write(uint8_t *ptr, const uint8_t *ptkid); + +/** + * kde_lifetime_write writes GTK lifetime + * + * \param ptr pointer where to write + * \param lifetime GTK lifetime + * + * return incremented write pointer + * + */ +uint8_t *kde_lifetime_write(uint8_t *ptr, uint32_t lifetime); + +/** + * kde_gtkl_write writes GTK liveness information + * + * \param ptr pointer where to write + * \param gtkl GTK liveness bit field + * + * return incremented write pointer + * + */ +uint8_t *kde_gtkl_write(uint8_t *ptr, uint8_t gtkl); + +/** + * kde_gtk_read reads GTK + * + * \param ptr pointer where to read + * \param len length of the remaining data + * \param key_id key identifier (index) + * \param gtk GTK + * + * \return < 0 failure + * \return >= 0 success + * + */ +int8_t kde_gtk_read(const uint8_t *ptr, uint16_t len, uint8_t *key_id, uint8_t *gtk); + +/** + * kde_pmkid_read reads PMKID + * + * \param ptr pointer where to read + * \param len length of the remaining data + * \param pmkid PMKID + * + * \return < 0 failure + * \return >= 0 success + * + */ +int8_t kde_pmkid_read(const uint8_t *ptr, uint16_t len, uint8_t *pmkid); + +/** + * kde_ptkid_read reads PTKID + * + * \param ptr pointer where to read + * \param len length of the remaining data + * \param ptkid PTKID + * + * \return < 0 failure + * \return >= 0 success + * + */ +int8_t kde_ptkid_read(const uint8_t *ptr, uint16_t len, uint8_t *ptkid); + +/** + * kde_lifetime_read reads GTK lifetime + * + * \param ptr pointer where to read + * \param len length of the remaining data + * \param lifetime GTK lifetime + * + * \return < 0 failure + * \return >= 0 success + * + */ +int8_t kde_lifetime_read(const uint8_t *ptr, uint16_t len, uint32_t *lifetime); + +/** + * kde_gtkl_read reads GTK liveness information + * + * \param ptr pointer where to read + * \param len length of the remaining data + * \param gtkl GTK liveness bit field + * + * \return < 0 failure + * \return >= 0 success + * + */ +int8_t kde_gtkl_read(const uint8_t *ptr, uint16_t len, uint8_t *gtkl); + +#endif /* KDE_HELPER_H_ */ diff --git a/source/Security/kmp/kmp_addr.c b/source/Security/kmp/kmp_addr.c new file mode 100644 index 0000000000..bbff7bdad8 --- /dev/null +++ b/source/Security/kmp/kmp_addr.c @@ -0,0 +1,177 @@ +/* + * Copyright (c) 2016-2019, Arm Limited and affiliates. + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "nsconfig.h" +#include +#include "ns_types.h" +#include "ns_list.h" +#include "ns_trace.h" +#include "nsdynmemLIB.h" +#include "eventOS_event.h" +#include "eventOS_scheduler.h" +#include "eventOS_event_timer.h" +#include "NWK_INTERFACE/Include/protocol.h" +#include "Common_Protocols/ipv6_constants.h" +#include "6LoWPAN/ws/ws_config.h" +#include "Security/kmp/kmp_addr.h" + +#ifdef HAVE_WS + +#define TRACE_GROUP "kmar" + +#define KMP_ADDR_DYN_ALLOC 0x80 +#define KMP_ADDR_TYPE_MASK 0x0F + +typedef struct { + uint8_t type; + uint8_t eui_64[8]; + address_t ip_addr; + uint16_t port; +} kmp_eui_64_ip_addr_t; + +kmp_addr_t *kmp_address_create(kmp_addr_e type, const uint8_t *eui_64) +{ + uint8_t size; + if (type == KMP_ADDR_EUI_64) { + size = sizeof(kmp_addr_t); + } else if (type == KMP_ADDR_EUI_64_AND_IP) { + size = sizeof(kmp_eui_64_ip_addr_t); + } else { + return 0; + } + + kmp_addr_t *addr = ns_dyn_mem_alloc(size); + if (!addr) { + return 0; + } + + kmp_address_init(type, addr, eui_64); + + addr->type |= KMP_ADDR_DYN_ALLOC; + + return addr; +} + +void kmp_address_init(kmp_addr_e type, kmp_addr_t *addr, const uint8_t *eui_64) +{ + uint8_t size; + if (type == KMP_ADDR_EUI_64) { + size = sizeof(kmp_addr_t); + } else if (type == KMP_ADDR_EUI_64_AND_IP) { + size = sizeof(kmp_eui_64_ip_addr_t); + } else { + return; + } + + kmp_addr_t *kmp_addr = addr; + + memset(addr, 0, size); + kmp_addr->type = type; + if (eui_64) { + memcpy(kmp_addr->eui_64, eui_64, 8); + } +} + +void kmp_address_delete(kmp_addr_t *addr) +{ + if (addr && (addr->type & KMP_ADDR_DYN_ALLOC)) { + ns_dyn_mem_free(addr); + } +} + +const uint8_t *kmp_address_eui_64_get(const kmp_addr_t *addr) +{ + if (!addr) { + return NULL; + } + + return addr->eui_64; +} + +const uint8_t *kmp_address_ip_get(const kmp_addr_t *addr) +{ + if (!addr || (addr->type & KMP_ADDR_TYPE_MASK) != KMP_ADDR_EUI_64_AND_IP) { + return NULL; + } + + return ((kmp_eui_64_ip_addr_t *)addr)->ip_addr; +} + +uint16_t kmp_address_port_get(const kmp_addr_t *addr) +{ + if (!addr || (addr->type & KMP_ADDR_TYPE_MASK) != KMP_ADDR_EUI_64_AND_IP) { + return 0; + } + + return ((kmp_eui_64_ip_addr_t *)addr)->port; +} + +int8_t kmp_address_eui_64_set(kmp_addr_t *addr, const uint8_t *eui64) +{ + if (!addr) { + return -1; + } + + memcpy(addr->eui_64, eui64, 8); + return 0; +} + +int8_t kmp_address_ip_set(kmp_addr_t *addr, const uint8_t *ip_addr) +{ + if (!addr || !ip_addr || (addr->type & KMP_ADDR_TYPE_MASK) != KMP_ADDR_EUI_64_AND_IP) { + return -1; + } + + memcpy(((kmp_eui_64_ip_addr_t *)addr)->ip_addr, ip_addr, sizeof(address_t)); + return 0; +} + +int8_t kmp_address_port_set(kmp_addr_t *addr, const uint16_t port) +{ + if (!addr || (addr->type & KMP_ADDR_TYPE_MASK) != KMP_ADDR_EUI_64_AND_IP) { + return -1; + } + + ((kmp_eui_64_ip_addr_t *)addr)->port = port; + return 0; +} + +int8_t kmp_address_copy(kmp_addr_t *to_addr, const kmp_addr_t *from_addr) +{ + if (!to_addr || !from_addr) { + return -1; + } + + memcpy(to_addr->eui_64, from_addr->eui_64, 8); + + kmp_eui_64_ip_addr_t *to_ip_addr = (kmp_eui_64_ip_addr_t *) to_addr; + kmp_eui_64_ip_addr_t *from_ip_addr = (kmp_eui_64_ip_addr_t *) from_addr; + + if ((to_ip_addr->type & KMP_ADDR_TYPE_MASK) == KMP_ADDR_EUI_64_AND_IP + && (from_ip_addr->type & KMP_ADDR_TYPE_MASK) == KMP_ADDR_EUI_64_AND_IP) { + memcpy(to_ip_addr->ip_addr, from_ip_addr->ip_addr, sizeof(address_t)); + to_ip_addr->port = from_ip_addr->port; + } else if ((to_ip_addr->type & KMP_ADDR_TYPE_MASK) == KMP_ADDR_EUI_64_AND_IP) { + memset(to_ip_addr->ip_addr, 0, sizeof(address_t)); + to_ip_addr->port = 0; + } + + return 0; +} + +#endif /* HAVE_WS */ + diff --git a/source/Security/kmp/kmp_addr.h b/source/Security/kmp/kmp_addr.h new file mode 100644 index 0000000000..967839707c --- /dev/null +++ b/source/Security/kmp/kmp_addr.h @@ -0,0 +1,138 @@ +/* + * Copyright (c) 2016-2018, 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 KMP_ADDR_H_ +#define KMP_ADDR_H_ + +typedef enum { + KMP_ADDR_EUI_64 = 0, + KMP_ADDR_EUI_64_AND_IP +} kmp_addr_e; + +typedef struct { + uint8_t type; + uint8_t eui_64[8]; +} kmp_addr_t; + +/** + * kmp_address_create creates address + * + * \param type address type + * \param eui_64 EUI-64 + * + * \return address + * + */ +kmp_addr_t *kmp_address_create(kmp_addr_e type, const uint8_t *eui_64); + +/** + * kmp_address_init initializes address + * + * \param type address type + * \param addr address + * \param eui_64 EUI-64 + * + */ +void kmp_address_init(kmp_addr_e type, kmp_addr_t *addr, const uint8_t *eui_64); + +/** + * kmp_address_delete deletes address + * + * \param addr address + * + */ +void kmp_address_delete(kmp_addr_t *addr); + +/** + * kmp_address_eui_64_get get EUI-64 + * + * \param addr address + * + * \return EUI-64 + * + */ +const uint8_t *kmp_address_eui_64_get(const kmp_addr_t *addr); + +/** + * kmp_address_ip_get get IP address + * + * \param addr address + * + * \return IP address + * + */ +const uint8_t *kmp_address_ip_get(const kmp_addr_t *addr); + +/** + * kmp_address_port_get get port + * + * \param addr address + * + * \return port + * + */ +uint16_t kmp_address_port_get(const kmp_addr_t *addr); + +/** + * kmp_address_eui_64_set set EUI-64 + * + * \param addr address + * \param ip_addr EUI-64 + * + * \return < 0 failure + * \return >= 0 success + * + */ +int8_t kmp_address_eui_64_set(kmp_addr_t *addr, const uint8_t *eui64); + +/** + * kmp_address_ip_set set IP address + * + * \param addr address + * \param ip_addr IP address + * + * \return < 0 failure + * \return >= 0 success + * + */ +int8_t kmp_address_ip_set(kmp_addr_t *addr, const uint8_t *ip_addr); + +/** + * kmp_address_port_set set port address + * + * \param addr address + * \param port port + * + * \return < 0 failure + * \return >= 0 success + * + */ +int8_t kmp_address_port_set(kmp_addr_t *addr, const uint16_t port); + +/** + * kmp_address_copy copies address + * + * \param to_addr address to copy to + * \param from_addr address to copy from + * + * \return < 0 failure + * \return >= 0 success + * + */ +int8_t kmp_address_copy(kmp_addr_t *to_addr, const kmp_addr_t *from_addr); + +#endif /* KMP_ADDR_H_ */ diff --git a/source/Security/kmp/kmp_api.c b/source/Security/kmp/kmp_api.c new file mode 100644 index 0000000000..27ed10d4a6 --- /dev/null +++ b/source/Security/kmp/kmp_api.c @@ -0,0 +1,508 @@ +/* + * Copyright (c) 2016-2019, Arm Limited and affiliates. + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "nsconfig.h" +#include +#include "ns_types.h" +#include "ns_list.h" +#include "ns_trace.h" +#include "nsdynmemLIB.h" +#include "NWK_INTERFACE/Include/protocol.h" +#include "Common_Protocols/ipv6_constants.h" +#include "socket_api.h" +#include "6LoWPAN/ws/ws_config.h" +#include "Security/kmp/kmp_addr.h" +#include "Security/kmp/kmp_api.h" +#include "Security/kmp/kmp_socket_if.h" +#include "Security/protocols/sec_prot_certs.h" +#include "Security/protocols/sec_prot_keys.h" +#include "Security/protocols/sec_prot.h" + +#ifdef HAVE_WS + +#define TRACE_GROUP "kmap" + +struct kmp_api_s { + void *app_data_ptr; /**< Opaque pointer for application data */ + kmp_api_create_confirm *create_conf; /**< KMP-CREATE.confirm callback */ + kmp_api_create_indication *create_ind; /**< KMP-CREATE.indication callback */ + kmp_api_finished_indication *finished_ind; /**< KMP-FINISHED.indication callback */ + kmp_api_finished *finished; /**< Finished i.e. ready to be deleted callback */ + kmp_type_e type; /**< KMP type */ + kmp_addr_t *addr; /**< Supplicant EUI-64, Relay IP address, Relay port */ + kmp_service_t *service; /**< KMP service */ + bool timer_start_pending; /**< Timer is pending to start */ + sec_prot_t sec_prot; /**< Security protocol interface */ +}; + +typedef struct { + kmp_type_e type; /**< Security protocol type callback */ + kmp_sec_prot_size *size; /**< Security protocol data size callback */ + kmp_sec_prot_init *init; /**< Security protocol init */ + ns_list_link_t link; /**< Link */ +} kmp_sec_prot_entry_t; + +typedef NS_LIST_HEAD(kmp_sec_prot_entry_t, link) kmp_sec_prot_list_t; + +struct kmp_service_s { + kmp_sec_prot_list_t sec_prot_list; /**< Security protocols list */ + kmp_service_incoming_ind *incoming_ind; /**< Callback to application to indicate incoming KMP frame */ + kmp_service_addr_get *addr_get; /**< Callback to get 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 */ +}; + +typedef struct { + uint8_t kmp_id; /**< Kmp id */ + uint8_t kmp_data; /**< Kmp data e.g. eapol frame */ +} kmp_pdu_t; + +static NS_LIST_DEFINE(kmp_service_list, kmp_service_t, link); + +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); +static void kmp_api_sec_prot_finished(sec_prot_t *prot); +static int8_t kmp_sec_prot_send(sec_prot_t *prot, void *pdu, uint16_t size); +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 sec_prot_t *kmp_sec_prot_by_type_get(sec_prot_t *prot, uint8_t type); + +#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) +{ + if (!service) { + return 0; + } + + kmp_sec_prot_entry_t *sec_prot = 0; + ns_list_foreach(kmp_sec_prot_entry_t, list_entry, &service->sec_prot_list) { + if (list_entry->type == type) { + sec_prot = list_entry; + break; + } + } + + if (!sec_prot) { + // Unknown security protocol + return 0; + } + // Size for security protocol internal data + uint16_t sec_size = sec_prot->size(); + + kmp_api_t *kmp = ns_dyn_mem_temporary_alloc(sizeof(kmp_api_t) + sec_size); + if (!kmp) { + return 0; + } + + kmp->type = type; + kmp->app_data_ptr = 0; + kmp->create_conf = 0; + kmp->create_ind = 0; + kmp->finished_ind = 0; + kmp->finished = 0; + kmp->addr = 0; + kmp->service = service; + kmp->timer_start_pending = false; + + memset(&kmp->sec_prot, 0, sec_size); + + kmp->sec_prot.header_size = service->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; + kmp->sec_prot.finished = kmp_api_sec_prot_finished; + kmp->sec_prot.send = kmp_sec_prot_send; + kmp->sec_prot.timer_start = kmp_sec_prot_timer_start; + 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.type_get = kmp_sec_prot_by_type_get; + + if (sec_prot->init(&kmp->sec_prot) < 0) { + ns_dyn_mem_free(kmp); + return 0; + } + + return (kmp_api_t *) kmp; +} + +int8_t kmp_api_start(kmp_api_t *kmp) +{ + if (kmp->timer_start_pending) { + if (kmp->service->timer_start(kmp->service, kmp) < 0) { + return -1; + } + } + return 0; +} + +void kmp_api_create_request(kmp_api_t *kmp, kmp_type_e type, kmp_addr_t *addr, kmp_sec_keys_t *sec_keys) +{ + kmp->type = type; + kmp->addr = addr; + kmp->sec_prot.create_req(&kmp->sec_prot, sec_keys); +} + +void kmp_api_create_response(kmp_api_t *kmp, kmp_result_e result) +{ + kmp->sec_prot.create_resp(&kmp->sec_prot, (sec_prot_result_e) result); +} + +static void kmp_api_sec_prot_create_confirm(sec_prot_t *prot, sec_prot_result_e result) +{ + kmp_api_t *kmp = kmp_api_get_from_prot(prot); + kmp->create_conf((kmp_api_t *)kmp, (kmp_result_e) result); +} + +static void kmp_api_sec_prot_create_indication(sec_prot_t *prot) +{ + kmp_api_t *kmp = kmp_api_get_from_prot(prot); + kmp->create_ind((kmp_api_t *)kmp, kmp->type, kmp->addr); +} + +static void kmp_api_sec_prot_finished_indication(sec_prot_t *prot, sec_prot_result_e result, sec_prot_keys_t *sec_keys) +{ + kmp_api_t *kmp = kmp_api_get_from_prot(prot); + kmp->finished_ind((kmp_api_t *)kmp, (kmp_result_e) result, sec_keys); +} + +static void kmp_api_sec_prot_finished(sec_prot_t *prot) +{ + kmp_api_t *kmp = kmp_api_get_from_prot(prot); + kmp->finished((kmp_api_t *)kmp); +} + +static int8_t kmp_sec_prot_send(sec_prot_t *prot, void *pdu, uint16_t size) +{ + kmp_api_t *kmp = kmp_api_get_from_prot(prot); + + // Convert from internal initial key type to real type if needed + kmp_type_e kmp_id = kmp->type; + if (kmp_id > IEEE_802_1X_INITIAL_KEY) { + kmp_id -= IEEE_802_1X_INITIAL_KEY; + } + + int8_t result = -1; + + if (kmp->service->send) { + result = kmp->service->send(kmp->service, kmp_id, kmp->addr, pdu, size); + } + + if (result < 0) { + ns_dyn_mem_free(pdu); + } + + return result; +} + +static void kmp_sec_prot_timer_start(sec_prot_t *prot) +{ + kmp_api_t *kmp = kmp_api_get_from_prot(prot); + kmp->timer_start_pending = false; + if (kmp->service->timer_start(kmp->service, kmp) < 0) { + kmp->timer_start_pending = true; + } +} + +static void kmp_sec_prot_timer_stop(sec_prot_t *prot) +{ + kmp_api_t *kmp = kmp_api_get_from_prot(prot); + kmp->service->timer_stop(kmp->service, kmp); + kmp->timer_start_pending = false; +} + +static void kmp_sec_prot_eui64_addr_get(sec_prot_t *prot, uint8_t *local_eui64, uint8_t *remote_eui64) +{ + kmp_api_t *kmp = kmp_api_get_from_prot(prot); + + kmp_addr_t local_addr; + kmp_address_init(KMP_ADDR_EUI_64, &local_addr, NULL); + + kmp_addr_t remote_addr; + kmp_address_init(KMP_ADDR_EUI_64, &remote_addr, NULL); + + kmp->service->addr_get(kmp->service, kmp, &local_addr, &remote_addr); + + if (local_eui64) { + memcpy(local_eui64, kmp_address_eui_64_get(&local_addr), 8); + } + if (remote_eui64) { + memcpy(remote_eui64, kmp_address_eui_64_get(&remote_addr), 8); + } +} + +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); + + kmp_type_e kmp_type; + + switch (type) { + case SEC_PROT_TYPE_EAP_TLS: + kmp_type = IEEE_802_1X_MKA; + break; + case SEC_PROT_TYPE_TLS: + kmp_type = TLS_PROT; + break; + default: + return NULL; + } + + kmp_api_t *kmp_by_type = kmp->service->api_get(kmp->service, kmp, kmp_type); + if (!kmp_by_type) { + return NULL; + } + + return &kmp_by_type->sec_prot; +} + +void kmp_api_delete(kmp_api_t *kmp) +{ + if (kmp->sec_prot.delete) { + kmp->sec_prot.delete(&kmp->sec_prot); + } + ns_dyn_mem_free(kmp); +} + +void kmp_api_cb_register(kmp_api_t *kmp, kmp_api_create_confirm *create_conf, kmp_api_create_indication *create_ind, kmp_api_finished_indication *finished_ind, kmp_api_finished *finished) +{ + if (!kmp) { + return; + } + + kmp->create_conf = create_conf; + kmp->create_ind = create_ind; + kmp->finished_ind = finished_ind; + kmp->finished = finished; +} + +kmp_type_e kmp_api_type_get(kmp_api_t *kmp) +{ + return kmp->type; +} + +kmp_type_e kmp_api_type_from_id_get(uint8_t kmp_id) +{ + switch (kmp_id) { + case IEEE_802_1X_MKA: + return IEEE_802_1X_MKA; + case IEEE_802_11_4WH: + return IEEE_802_11_4WH; + case IEEE_802_11_GKH: + return IEEE_802_1X_MKA; + default: + return INVALID_KMP_TYPE; + } +} + +kmp_service_t *kmp_api_service_get(kmp_api_t *kmp) +{ + return kmp->service; +} + +void kmp_api_data_set(kmp_api_t *kmp, void *data) +{ + kmp->app_data_ptr = data; +} + +void *kmp_api_data_get(kmp_api_t *kmp) +{ + return kmp->app_data_ptr; +} + +void kmp_api_addr_set(kmp_api_t *kmp, kmp_addr_t *addr) +{ + kmp->addr = addr; +} + +void kmp_api_sec_keys_set(kmp_api_t *kmp, kmp_sec_keys_t *sec_keys) +{ + kmp->sec_prot.sec_keys = sec_keys; +} + +kmp_service_t *kmp_service_create(void) +{ + kmp_service_t *service = ns_dyn_mem_alloc(sizeof(kmp_service_t)); + if (!service) { + return NULL; + } + + ns_list_init(&service->sec_prot_list); + service->incoming_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); + + return service; +} + +int8_t kmp_service_delete(kmp_service_t *service) +{ + if (!service) { + return -1; + } + + ns_list_foreach_safe(kmp_service_t, list_entry, &kmp_service_list) { + if (list_entry == service) { + ns_list_foreach_safe(kmp_sec_prot_entry_t, sec_list_entry, &list_entry->sec_prot_list) { + ns_list_remove(&list_entry->sec_prot_list, sec_list_entry); + ns_dyn_mem_free(sec_list_entry); + } + + ns_list_remove(&kmp_service_list, list_entry); + ns_dyn_mem_free(list_entry); + return 0; + } + } + + return -1; +} + +static void kmp_sec_prot_state_machine_call(sec_prot_t *prot) +{ + kmp_api_t *kmp = kmp_api_get_from_prot(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_addr_get *addr_get, kmp_service_api_get *api_get) +{ + if (!service) { + return -1; + } + + service->incoming_ind = incoming_ind; + service->addr_get = 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) +{ + if (!service) { + return -1; + } + + service->send = send; + service->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) +{ + if (!service) { + return -1; + } + + kmp_api_t *kmp = (kmp_api_t *) service->incoming_ind(service, type, addr); + if (!kmp) { + return -1; + } + + int8_t ret = kmp->sec_prot.receive(&kmp->sec_prot, pdu, size); + return ret; +} + +int8_t kmp_service_sec_protocol_register(kmp_service_t *service, kmp_type_e type, kmp_sec_prot_size *size, kmp_sec_prot_init *init) +{ + if (!service) { + return -1; + } + + ns_list_foreach(kmp_sec_prot_entry_t, list_entry, &service->sec_prot_list) { + // Already registered + if (list_entry->type == type) { + return -1; + } + } + + kmp_sec_prot_entry_t *sec_prot = ns_dyn_mem_temporary_alloc(sizeof(kmp_sec_prot_entry_t)); + if (!sec_prot) { + return -1; + } + + sec_prot->type = type; + sec_prot->size = size; + sec_prot->init = init; + + ns_list_add_to_start(&service->sec_prot_list, sec_prot); + + return 0; +} + +int8_t kmp_service_sec_protocol_unregister(kmp_service_t *service, kmp_type_e type) +{ + ns_list_foreach(kmp_sec_prot_entry_t, list_entry, &service->sec_prot_list) { + if (list_entry->type == type) { + ns_list_remove(&service->sec_prot_list, list_entry); + ns_dyn_mem_free(list_entry); + return 0; + } + } + return -1; +} + +void kmp_service_timer_if_timeout(kmp_api_t *kmp, uint16_t ticks) +{ + kmp->sec_prot.timer_timeout(&kmp->sec_prot, ticks); +} + +int8_t kmp_service_timer_if_register(kmp_service_t *service, kmp_service_timer_if_start start, kmp_service_timer_if_stop stop) +{ + if (!service) { + return -1; + } + + service->timer_start = start; + service->timer_stop = stop; + return 0; +} + +void kmp_service_event_if_event(kmp_service_t *service, void *data) +{ + (void) service; + + // For now, only state machine events + sec_prot_t *prot = data; + prot->state_machine(prot); +} + +int8_t kmp_service_event_if_register(kmp_service_t *service, kmp_service_event_if_event_send send) +{ + if (!service) { + return -1; + } + + service->event_send = send; + return 0; +} + +#endif /* HAVE_WS */ + diff --git a/source/Security/kmp/kmp_api.h b/source/Security/kmp/kmp_api.h new file mode 100644 index 0000000000..a03ad8e249 --- /dev/null +++ b/source/Security/kmp/kmp_api.h @@ -0,0 +1,457 @@ +/* + * Copyright (c) 2016-2019, 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 KMP_API_H_ +#define KMP_API_H_ + +/* + * KMP API and KMP service module. KMP API offers key management security + * protocols interface towards application. + * + * KMP service provides security protocols access to network, timing + * services and callback services. Application must configure KMP service + * before using KMP API. + * + */ + +typedef enum { + INVALID_KMP_TYPE = 0, + + IEEE_802_1X_MKA = 1, + IEEE_802_11_4WH = 6, + IEEE_802_11_GKH = 7, + TLS_PROT = 8, + + IEEE_802_1X_INITIAL_KEY = 10, + + IEEE_802_1X_MKA_KEY = 11, + IEEE_802_11_4WH_KEY = 16, + IEEE_802_11_GKH_KEY = 17 +} kmp_type_e; + + +typedef enum { + KMP_RESULT_OK = 0, + KMP_RESULT_ERR_NO_MEM = -1, + KMP_RESULT_ERR_UNSPEC = -2 +} kmp_result_e; + +typedef void kmp_sec_keys_t; +typedef struct sec_prot_s sec_prot_t; +typedef struct kmp_api_s kmp_api_t; +typedef struct kmp_service_s kmp_service_t; + +/** + * kmp_api_create_request KMP-CREATE.request + * + * \param kmp instance + * \param type protocol type + * \param addr address + * \param sec_keys security keys + * + */ +void kmp_api_create_request(kmp_api_t *kmp, kmp_type_e type, kmp_addr_t *addr, kmp_sec_keys_t *sec_keys); + +/** + * kmp_api_create_confirm KMP-CREATE.confirm + * + * \param kmp instance + * \param result ok or fail + * + */ +typedef void kmp_api_create_confirm(kmp_api_t *kmp, kmp_result_e result); + +/** + * kmp_api_create_indication KMP-CREATE.indication + * + * \param kmp instance + * \param type protocol type + * \param addr address + * + */ +typedef void kmp_api_create_indication(kmp_api_t *kmp, kmp_type_e type, kmp_addr_t *addr); + +/** + * kmp_api_create_response KMP-CREATE.response + * + * \param kmp instance + * \param result ok or fail + * + */ +void kmp_api_create_response(kmp_api_t *kmp, kmp_result_e result); + +/** + * kmp_api_finished_indication KMP-FINISHED.indication + * + * \param kmp instance + * \param result ok or fail + * \param sec_keys security keys + * + */ +typedef void kmp_api_finished_indication(kmp_api_t *kmp, kmp_result_e result, kmp_sec_keys_t *sec_keys); + +/** + * kmp_api_finished will be called when KMP has finished and is ready for delete + * + * \param kmp instance + * + */ +typedef void kmp_api_finished(kmp_api_t *kmp); + +/** + * kmp_api_create create KMP api + * + * \param service KMP service + * \param type KMP type + * + * \return KMP instance or NULL + * + */ +kmp_api_t *kmp_api_create(kmp_service_t *service, kmp_type_e type); + +/** + * kmp_api_start start KMP api + * + * \param kmp instance + * + * \return < 0 failure + * \return >= 0 success + * + */ +int8_t kmp_api_start(kmp_api_t *kmp); + +/** + * kmp_api_create create KMP api + * + * \param kmp instance + * + */ +void kmp_api_delete(kmp_api_t *kmp); + +/** + * kmp_api_type_get get KMP type + * + * \param kmp instance + * + * \return kmp_type_e KMP type + * + */ +kmp_type_e kmp_api_type_get(kmp_api_t *kmp); + +/** + * kmp_api_type_from_id_get get KMP type from KMP id + * + * \param kmp_id KMP identifier + * + * \return kmp_type_e KMP type + * + */ +kmp_type_e kmp_api_type_from_id_get(uint8_t kmp_id); + +/** + * kmp_api_service_get get KMP service for KMP instance + * + * \param kmp instance + * + * \return service + * + */ +kmp_service_t *kmp_api_service_get(kmp_api_t *kmp); + +/** + * kmp_api_data_set set application data + * + * \param kmp instance + * \param data data + * + */ +void kmp_api_data_set(kmp_api_t *kmp, void *data); + +/** + * kmp_api_data_get read application data + * + * \param kmp instance + * + * \return data + * + */ +void *kmp_api_data_get(kmp_api_t *kmp); + +/** + * kmp_api_addr_set set address + * + * \param kmp instance + * \param addr addr + * + */ +void kmp_api_addr_set(kmp_api_t *kmp, kmp_addr_t *addr); + +/** + * kmp_api_sec_keys_set set security keys + * + * \param kmp instance + * \param sec_keys security keys + * + */ +void kmp_api_sec_keys_set(kmp_api_t *kmp, kmp_sec_keys_t *sec_keys); + +/** + * kmp_api_cb_register registers api callbacks + * + * \param kmp instance + * \param create_conf KMP-CREATE.confirm callback + * \param create_ind KMP-CREATE.indication callback + * \param finished_ind KMP-FINISHED.indication + * \param finish KMP has finished and is ready for delete + * + */ +void kmp_api_cb_register(kmp_api_t *kmp, kmp_api_create_confirm *create_conf, kmp_api_create_indication *create_ind, kmp_api_finished_indication *finished_ind, kmp_api_finished *finished); + +/** + * kmp_service_create creates KMP service + * + * \return service or NULL + * + */ +kmp_service_t *kmp_service_create(void); + +/** + * kmp_service_delete deletes KMP service + * + * \param service KMP service + * + * \return < 0 failure + * \return >= 0 success + * + */ +int8_t kmp_service_delete(kmp_service_t *service); + +/** + * kmp_service_incoming_ind Notifies application about incoming KMP frame + * + * \param service KMP service + * \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); + +/** + * kmp_service_addr_get gets addressing information related to KMP + * + * \param service KMP service + * \param kmp KMP instance + * \param local_addr Local address + * \param remote_addr Remote address + * + */ +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_api_get gets KMP API from KMP service + * + * \param service KMP service + * \param kmp KMP instance + * \param type protocol type + * + * \return KMP instance or NULL + * + */ +typedef kmp_api_t *kmp_service_api_get(kmp_service_t *service, kmp_api_t *kmp, kmp_type_e type); + +/** + * kmp_service_cb_register registers service callbacks + * + * \param service KMP service + * \param incoming_ind incoming message callback + * \param addr_get gets addressing information callback + * + * \return < 0 failure + * \return >= 0 success + * + */ +int8_t kmp_service_cb_register(kmp_service_t *service, kmp_service_incoming_ind *incoming_ind, kmp_service_addr_get *addr_get, kmp_service_api_get *api_get); + +/** + * kmp_service_msg_if_receive receive a message + * + * \param service KMP service + * \param type protocol type + * \param addr address + * \param pdu pdu + * \param size pdu size + * + * \return < 0 failure + * \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); + +/** + * kmp_service_msg_if_send send a message + * + * \param service KMP service + * \param type protocol type + * \param addr address + * \param pdu pdu + * \param size pdu size + * + * \return < 0 failure + * \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); + +/** + * kmp_service_msg_if_register registers message interface + * + * \param service KMP service + * \param send KMP PDU send callback + * \param header_size header size + * + * \return < 0 failure + * \return >= 0 success + * + */ +int8_t kmp_service_msg_if_register(kmp_service_t *service, kmp_service_msg_if_send *send, uint8_t header_size); + +/** + * kmp_sec_prot_size security protocol data size + * + * \return size + * + */ +typedef uint16_t kmp_sec_prot_size(void); + +/** + * kmp_sec_prot_init security protocol init callback + * + * \param prot protocol data + * + * \return < 0 failure + * \return >= 0 success + * + */ +typedef int8_t kmp_sec_prot_init(sec_prot_t *prot); + +/** + * kmp_service_sec_protocol_register register a security protocol to KMP service + * + * \param service KMP service + * \param type protocol type + * \param size size callback + * \param init init callback + * + * \return < 0 failure + * \return >= 0 success + * + */ +int8_t kmp_service_sec_protocol_register(kmp_service_t *service, kmp_type_e type, kmp_sec_prot_size *size, kmp_sec_prot_init *init); + +/** + * kmp_service_sec_protocol_unregister unregister a security protocol from KMP service + * + * \param service KMP service + * \param type protocol type + * + * \return < 0 failure + * \return >= 0 success + * + */ +int8_t kmp_service_sec_protocol_unregister(kmp_service_t *service, kmp_type_e type); + +/** + * kmp_service_timer_if_timeout timer timeout + * + * \param service KMP instance + * + */ +void kmp_service_timer_if_timeout(kmp_api_t *kmp, uint16_t ticks); + +/** + * kmp_service_timer_if_start timer start callback + * + * \param service KMP service + * \param kmp KMP instance + * + * \return < 0 failure + * \return >= 0 success + * + */ +typedef int8_t kmp_service_timer_if_start(kmp_service_t *service, kmp_api_t *kmp); + +/** + * kmp_service_timer_if_stop timer stop callback + * + * \param service KMP service + * \param kmp KMP instance + * + * \return < 0 failure + * \return >= 0 success + * + */ +typedef int8_t kmp_service_timer_if_stop(kmp_service_t *service, kmp_api_t *kmp); + +/** + * kmp_service_timer_if_register register a timer interface to KMP service + * + * \param service KMP service + * \param start timer start callback + * \param stop timer stop callback + * + * \return < 0 failure + * \return >= 0 success + * + */ +int8_t kmp_service_timer_if_register(kmp_service_t *service, kmp_service_timer_if_start start, kmp_service_timer_if_stop stop); + +/** + * kmp_service_event_if_event event callback + * + * \param service KMP service + * \param data opaque callback data + * + */ +void kmp_service_event_if_event(kmp_service_t *service, void *data); + +/** + * kmp_service_event_if_event_send event send callback + * + * \param service KMP service + * \param data opaque callback data + * + * \return < 0 failure + * \return >= 0 success + * + */ +typedef int8_t kmp_service_event_if_event_send(kmp_service_t *service, void *data); + +/** + * kmp_service_event_if_register register an event interface to KMP service + * + * \param service KMP service + * \param send send event + * + * \return < 0 failure + * \return >= 0 success + * + */ +int8_t kmp_service_event_if_register(kmp_service_t *service, kmp_service_event_if_event_send send); + +#endif /* KMP_API_H_ */ diff --git a/source/Security/kmp/kmp_eapol_pdu_if.c b/source/Security/kmp/kmp_eapol_pdu_if.c new file mode 100644 index 0000000000..c56f5b09ee --- /dev/null +++ b/source/Security/kmp/kmp_eapol_pdu_if.c @@ -0,0 +1,164 @@ +/* + * Copyright (c) 2016-2019, Arm Limited and affiliates. + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "nsconfig.h" +#include +#include "ns_types.h" +#include "ns_list.h" +#include "ns_trace.h" +#include "nsdynmemLIB.h" +#include "6LoWPAN/ws/ws_config.h" +#include "NWK_INTERFACE/Include/protocol.h" +#include "Security/kmp/kmp_addr.h" +#include "Security/kmp/kmp_api.h" +#include "Security/kmp/kmp_eapol_pdu_if.h" +#include "6LoWPAN/MAC/mpx_api.h" +#include "6LoWPAN/ws/ws_eapol_pdu.h" + +#ifdef HAVE_WS + +#define TRACE_GROUP "kmep" + +#define EAPOL_PDU_IF_HEADER_SIZE 1 + +typedef struct { + uint8_t kmp_id; /**< Kmp id */ + uint8_t kmp_data; /**< Kmp data e.g. eapol frame */ +} eapol_kmp_pdu_t; + +typedef struct { + kmp_service_t *kmp_service; /**< KMP service */ + protocol_interface_info_entry_t *interface_ptr; /**< Interface pointer */ + ns_list_link_t link; /**< Link */ +} kmp_eapol_pdu_if_t; + +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); + +int8_t kmp_eapol_pdu_if_register(kmp_service_t *service, protocol_interface_info_entry_t *interface_ptr) +{ + if (!service || !interface_ptr) { + return -1; + } + + ns_list_foreach(kmp_eapol_pdu_if_t, entry, &kmp_eapol_pdu_if_list) { + if (entry->kmp_service == service || entry->interface_ptr == interface_ptr) { + return -1; + } + } + + kmp_eapol_pdu_if_t *eapol_pdu_if = ns_dyn_mem_alloc(sizeof(kmp_eapol_pdu_if_t)); + if (!eapol_pdu_if) { + return -1; + } + + 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) { + ns_dyn_mem_free(eapol_pdu_if); + return -1; + } + + ns_list_add_to_end(&kmp_eapol_pdu_if_list, eapol_pdu_if); + + return 0; +} + +int8_t kmp_eapol_pdu_if_unregister(kmp_service_t *service) +{ + if (!service) { + return -1; + } + + ns_list_foreach_safe(kmp_eapol_pdu_if_t, entry, &kmp_eapol_pdu_if_list) { + 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); + } + } + 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) +{ + if (!service || !addr || !pdu) { + return -1; + } + + protocol_interface_info_entry_t *interface_ptr = NULL; + + ns_list_foreach(kmp_eapol_pdu_if_t, entry, &kmp_eapol_pdu_if_list) { + if (entry->kmp_service == service) { + interface_ptr = entry->interface_ptr; + break; + } + } + + if (!interface_ptr) { + return -1; + } + + const uint8_t *eui_64 = kmp_address_eui_64_get(addr); + if (!eui_64) { + return -1; + } + + uint8_t *ptr = pdu; + *ptr = kmp_id; + + int8_t ret = ws_eapol_pdu_send_to_mpx(interface_ptr, eui_64, pdu, size, pdu); + + return ret; +} + +int8_t kmp_eapol_pdu_if_receive(protocol_interface_info_entry_t *interface_ptr, const uint8_t *eui_64, void *pdu, uint16_t size) +{ + kmp_service_t *service = NULL; + + ns_list_foreach(kmp_eapol_pdu_if_t, entry, &kmp_eapol_pdu_if_list) { + if (entry->interface_ptr == interface_ptr) { + service = entry->kmp_service; + break; + } + } + + if (!service) { + return -1; + } + + kmp_addr_t addr; + kmp_address_init(KMP_ADDR_EUI_64, &addr, eui_64); + + eapol_kmp_pdu_t *eapol_kmp_pdu = pdu; + uint16_t data_pdu_size = size - sizeof(uint8_t); + void *data_pdu = &eapol_kmp_pdu->kmp_data; + + kmp_type_e type = kmp_api_type_from_id_get(eapol_kmp_pdu->kmp_id); + if (type == INVALID_KMP_TYPE) { + return -1; + } + + int8_t ret = kmp_service_msg_if_receive(service, type, &addr, data_pdu, data_pdu_size); + + return ret; +} + +#endif /* HAVE_WS */ + diff --git a/source/Security/kmp/kmp_eapol_pdu_if.h b/source/Security/kmp/kmp_eapol_pdu_if.h new file mode 100644 index 0000000000..eaad14b075 --- /dev/null +++ b/source/Security/kmp/kmp_eapol_pdu_if.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2016-2019, 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 KMP_EAPOL_PDU_IF_H_ +#define KMP_EAPOL_PDU_IF_H_ + +/* + * Supplicant KMP interface to/from EAPOL PDU interface (to MPX). + */ + +/** + * kmp_eapol_pdu_if_register register EAPOL PDU interface to KMP service + * + * \param service KMP service to register to + * \param interface_ptr interface + * + * \return < 0 failure + * \return >= 0 success + * + */ +int8_t kmp_eapol_pdu_if_register(kmp_service_t *service, protocol_interface_info_entry_t *interface_ptr); + +/** + * kmp_eapol_pdu_if_unregister unregister EAPOL PDU interface from KMP service + * + * \param service KMP service to unregister from + * + * \return < 0 failure + * \return >= 0 success + * + */ +int8_t kmp_eapol_pdu_if_unregister(kmp_service_t *service); + +/** + * kmp_eapol_pdu_if_receive receive EAPOL PDU to KMP service + * + * \param interface_ptr interface + * \param eui_64 source EUI-64 + * \param pdu EAPOL pdu + * \param size EAPOL pdu size + * + * \return < 0 failure + * \return >= 0 success + * + */ +int8_t kmp_eapol_pdu_if_receive(protocol_interface_info_entry_t *interface_ptr, const uint8_t *eui_64, void *pdu, uint16_t size); + +#endif /* KMP_EAPOL_PDU_IF_H_ */ diff --git a/source/Security/kmp/kmp_socket_if.c b/source/Security/kmp/kmp_socket_if.c new file mode 100644 index 0000000000..ba6412678b --- /dev/null +++ b/source/Security/kmp/kmp_socket_if.c @@ -0,0 +1,204 @@ +/* + * Copyright (c) 2016-2019, Arm Limited and affiliates. + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "nsconfig.h" +#include +#include "ns_types.h" +#include "ns_list.h" +#include "ns_trace.h" +#include "ns_address.h" +#include "nsdynmemLIB.h" +#include "eventOS_event.h" +#include "eventOS_scheduler.h" +#include "eventOS_event_timer.h" +#include "NWK_INTERFACE/Include/protocol.h" +#include "Common_Protocols/ipv6_constants.h" +#include "socket_api.h" +#include "6LoWPAN/ws/ws_config.h" +#include "Security/kmp/kmp_addr.h" +#include "Security/kmp/kmp_api.h" +#include "Security/kmp/kmp_socket_if.h" +#include "common_functions.h" + +#ifdef HAVE_WS + +#define TRACE_GROUP "kmsi" + +#define SOCKET_IF_HEADER_SIZE 27 + +typedef struct { + kmp_service_t *kmp_service; /**< KMP service */ + ns_address_t remote_addr; /**< Remote address */ + int8_t socket_id; /**< Socket ID */ + 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); +static void kmp_socket_if_socket_cb(void *ptr); + +static NS_LIST_DEFINE(kmp_socket_if_list, kmp_socket_if_t, link); + +int8_t kmp_socket_if_register(kmp_service_t *service, uint16_t local_port, const uint8_t *remote_addr, uint16_t remote_port) +{ + if (!service || !remote_addr) { + return -1; + } + + ns_list_foreach(kmp_socket_if_t, entry, &kmp_socket_if_list) { + if (entry->kmp_service == service) { + return -1; + } + } + + kmp_socket_if_t *socket_if = ns_dyn_mem_alloc(sizeof(kmp_socket_if_t)); + if (!socket_if) { + return -1; + } + + socket_if->kmp_service = service; + + socket_if->remote_addr.type = ADDRESS_IPV6; + memcpy(&socket_if->remote_addr.address, remote_addr, 16); + socket_if->remote_addr.identifier = remote_port; + + socket_if->socket_id = socket_open(IPV6_NH_UDP, local_port, &kmp_socket_if_socket_cb); + if (socket_if->socket_id < 0) { + ns_dyn_mem_free(socket_if); + return -1; + } + + if (kmp_service_msg_if_register(service, kmp_socket_if_send, SOCKET_IF_HEADER_SIZE) < 0) { + ns_dyn_mem_free(socket_if); + return -1; + } + + ns_list_add_to_end(&kmp_socket_if_list, socket_if); + + return 0; +} + +int8_t kmp_socket_if_unregister(kmp_service_t *service) +{ + if (!service) { + return -1; + } + + ns_list_foreach_safe(kmp_socket_if_t, entry, &kmp_socket_if_list) { + if (entry->kmp_service == service) { + ns_list_remove(&kmp_socket_if_list, entry); + socket_close(entry->socket_id); + 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) +{ + if (!service || !pdu || !addr) { + return -1; + } + + kmp_socket_if_t *socket_if = NULL; + + ns_list_foreach(kmp_socket_if_t, entry, &kmp_socket_if_list) { + if (entry->kmp_service == service) { + socket_if = entry; + break; + } + } + + if (!socket_if) { + return -1; + } + + //Build UPD Relay + uint8_t *ptr = pdu; + memcpy(ptr, kmp_address_ip_get(addr), 16); + ptr += 16; + ptr = common_write_16_bit(kmp_address_port_get(addr), 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); + + return 0; +} + +static void kmp_socket_if_socket_cb(void *ptr) +{ + socket_callback_t *cb_data = ptr; + + if (cb_data->event_type != SOCKET_DATA) { + return; + } + + kmp_socket_if_t *socket_if = NULL; + + ns_list_foreach(kmp_socket_if_t, entry, &kmp_socket_if_list) { + if (entry->socket_id == cb_data->socket_id) { + socket_if = entry; + break; + } + } + + if (!socket_if) { + return; + } + + uint8_t *pdu = ns_dyn_mem_temporary_alloc(cb_data->d_len); + + if (socket_recvfrom(cb_data->socket_id, pdu, cb_data->d_len, 0, 0) != cb_data->d_len) { + ns_dyn_mem_free(pdu); + return; + } + uint8_t *relay_address, *euid64; + uint16_t relay_port; + uint8_t *data_ptr = pdu; + relay_address = data_ptr; + data_ptr += 16; + relay_port = common_read_16_bit(data_ptr); + data_ptr += 2; + euid64 = data_ptr; + data_ptr += 8; + + kmp_type_e type = kmp_api_type_from_id_get(*data_ptr++); + if (type == INVALID_KMP_TYPE) { + ns_dyn_mem_free(pdu); + return; + } + + kmp_addr_t *addr = kmp_address_create(KMP_ADDR_EUI_64_AND_IP, euid64); + if (!addr) { + ns_dyn_mem_free(pdu); + return; + } + + kmp_address_ip_set(addr, relay_address); + kmp_address_port_set(addr, relay_port); + + kmp_service_msg_if_receive(socket_if->kmp_service, type, addr, data_ptr, cb_data->d_len - 27); + kmp_address_delete(addr); + + ns_dyn_mem_free(pdu); +} + +#endif /* HAVE_WS */ + diff --git a/source/Security/kmp/kmp_socket_if.h b/source/Security/kmp/kmp_socket_if.h new file mode 100644 index 0000000000..af1d695081 --- /dev/null +++ b/source/Security/kmp/kmp_socket_if.h @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2016-2019, 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 KMP_SOCKET_IF_H_ +#define KMP_SOCKET_IF_H_ + +/* + * Authenticator KMP socket interface to/from EAPOL authenticator relay. EAPOL + * authenticator relay address and port are provided in register call (remote + * address and remote port parameters) + * + * Authenticator KMP socket must be bound to port that EAPOL authenticator + * uses to send messages to Authenticator KMP. Default port is 10254 (local port + * parameter) + * + */ + +/** + * kmp_socket_if_register register socket interface to KMP service + * + * \param service KMP service to register to + * \param local_port local port + * \param remote_addr remote address + * \param remote_port remote port + * + * \return < 0 failure + * \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); + +/** + * kmp_socket_if_unregister unregister socket interface from KMP service + * + * \param service KMP service to unregister from + * + * \return < 0 failure + * \return >= 0 success + * + */ +int8_t kmp_socket_if_unregister(kmp_service_t *service); + +#endif /* KMP_SOCKET_IF_H_ */ 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 new file mode 100644 index 0000000000..19895c3cb3 --- /dev/null +++ b/source/Security/protocols/eap_tls_sec_prot/auth_eap_tls_sec_prot.c @@ -0,0 +1,521 @@ +/* + * Copyright (c) 2019, Arm Limited and affiliates. + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "nsconfig.h" +#include +#include "ns_types.h" +#include "ns_list.h" +#include "ns_trace.h" +#include "nsdynmemLIB.h" +#include "fhss_config.h" +#include "NWK_INTERFACE/Include/protocol.h" +#include "6LoWPAN/ws/ws_config.h" +#include "Security/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/auth_eap_tls_sec_prot.h" + +#ifdef HAVE_WS + +#define TRACE_GROUP "eapa" + +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_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; + +typedef struct { + sec_prot_common_t common; /**< Common data */ + sec_prot_t *tls_prot; /**< TLS security protocol */ + eapol_pdu_t recv_eapol_pdu; /**< Received EAPOL PDU */ + tls_data_t tls_send; /**< EAP-TLS send buffer */ + tls_data_t tls_recv; /**< EAP-TLS receive buffer */ + uint8_t eap_id_seq; /**< EAP sequence */ + uint8_t eap_code; /**< Received EAP code */ + uint8_t eap_type; /**< Received EAP type */ + int8_t tls_result; /**< Result of TLS operation */ + bool wait_tls: 1; /**< Wait TLS (ECC calculation) before sending EAP-TLS message */ + bool tls_ongoing: 1; /**< TLS handshake is ongoing */ + bool send_pending: 1; /**< TLS data is not yet send to network */ +} eap_tls_sec_prot_int_t; + +static const trickle_params_t eap_tls_trickle_params = { + .Imin = 200, /* 20s; ticks are 100ms */ + .Imax = 450, /* 45s */ + .k = 0, /* infinity - no consistency checking */ + .TimerExpirations = 4 +}; + +static uint16_t auth_eap_tls_sec_prot_size(void); +static int8_t auth_eap_tls_sec_prot_init(sec_prot_t *prot); + +static void auth_eap_tls_sec_prot_create_request(sec_prot_t *prot, sec_prot_keys_t *sec_keys); +static void auth_eap_tls_sec_prot_delete(sec_prot_t *prot); +static int8_t auth_eap_tls_sec_prot_receive(sec_prot_t *prot, void *pdu, uint16_t size); + +static void auth_eap_tls_sec_prot_state_machine(sec_prot_t *prot); + +static int8_t auth_eap_tls_sec_prot_message_handle(sec_prot_t *prot); +static int8_t auth_eap_tls_sec_prot_message_send(sec_prot_t *prot, uint8_t eap_code, uint8_t eap_type, uint8_t tls_state); + +static void auth_eap_tls_sec_prot_timer_timeout(sec_prot_t *prot, uint16_t ticks); +static void auth_eap_tls_sec_prot_init_tls(sec_prot_t *prot); +static void auth_eap_tls_sec_prot_delete_tls(sec_prot_t *prot); + +static void auth_eap_tls_sec_prot_seq_id_update(sec_prot_t *prot); + +#define eap_tls_sec_prot_get(prot) (eap_tls_sec_prot_int_t *) &prot->data + +int8_t auth_eap_tls_sec_prot_register(kmp_service_t *service) +{ + if (!service) { + return -1; + } + + if (kmp_service_sec_protocol_register(service, IEEE_802_1X_MKA, auth_eap_tls_sec_prot_size, auth_eap_tls_sec_prot_init) < 0) { + return -1; + } + + return 0; +} + +static uint16_t auth_eap_tls_sec_prot_size(void) +{ + return sizeof(eap_tls_sec_prot_int_t); +} + +static int8_t auth_eap_tls_sec_prot_init(sec_prot_t *prot) +{ + prot->create_req = auth_eap_tls_sec_prot_create_request; + prot->create_resp = 0; + prot->receive = auth_eap_tls_sec_prot_receive; + prot->delete = auth_eap_tls_sec_prot_delete; + prot->state_machine = auth_eap_tls_sec_prot_state_machine; + prot->timer_timeout = auth_eap_tls_sec_prot_timer_timeout; + + 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->tls_prot = NULL; + data->eap_id_seq = 0; + data->eap_code = 0; + data->eap_type = 0; + eap_tls_sec_prot_lib_message_init(&data->tls_recv); + eap_tls_sec_prot_lib_message_init(&data->tls_send); + data->tls_result = EAP_TLS_RESULT_ERROR; + data->wait_tls = false; + data->tls_ongoing = false; + data->send_pending = false; + return 0; +} + +static void auth_eap_tls_sec_prot_delete(sec_prot_t *prot) +{ + eap_tls_sec_prot_int_t *data = eap_tls_sec_prot_get(prot); + eap_tls_sec_prot_lib_message_free(&data->tls_send); + eap_tls_sec_prot_lib_message_free(&data->tls_recv); +} + +static void auth_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 auth_eap_tls_sec_prot_receive(sec_prot_t *prot, void *pdu, uint16_t size) +{ + 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 only EAP messages (ignore initial EAPOL-key retransmissions) + 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); + } + 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 auth_eap_tls_sec_prot_message_handle(sec_prot_t *prot) +{ + eap_tls_sec_prot_int_t *data = eap_tls_sec_prot_get(prot); + + uint8_t *data_ptr = data->recv_eapol_pdu.msg.eap.data_ptr; + uint16_t length = data->recv_eapol_pdu.msg.eap.length; + + bool new_seq_id = false; + // Confirmation that supplicant has received the message, proceed with protocol + if (data->recv_eapol_pdu.msg.eap.id_seq == data->eap_id_seq) { + data->eap_id_seq++; + new_seq_id = true; + } + + tr_debug("recv EAP %s type %s id %i flags %x len %i", 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); + + if (data->eap_type == EAP_IDENTITY) { + return EAP_TLS_MSG_IDENTITY; + } + + if (!data_ptr || length < 6) { + return EAP_TLS_MSG_DECODE_ERROR; + } + + length -= 5; // EAP fields: code, id, length, type + + return eap_tls_sec_prot_lib_message_handle(data_ptr, length, new_seq_id, &data->tls_send, &data->tls_recv); +} + +static int8_t auth_eap_tls_sec_prot_message_send(sec_prot_t *prot, uint8_t eap_code, uint8_t eap_type, uint8_t tls_state) +{ + 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) { + 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; + } + + if (prot->send(prot, eapol_decoded_data, eapol_pdu_size + prot->header_size) < 0) { + return -1; + } + + return 0; +} + +static void auth_eap_tls_sec_prot_timer_timeout(sec_prot_t *prot, uint16_t ticks) +{ + eap_tls_sec_prot_int_t *data = eap_tls_sec_prot_get(prot); + sec_prot_timer_timeout_handle(prot, &data->common, &eap_tls_trickle_params, ticks); +} + +static void auth_eap_tls_sec_prot_tls_create_indication(sec_prot_t *tls_prot) +{ + tls_prot->create_resp(tls_prot, SEC_RESULT_OK); +} + +static void auth_eap_tls_sec_prot_tls_finished_indication(sec_prot_t *tls_prot, sec_prot_result_e result, sec_prot_keys_t *sec_keys) +{ + (void) sec_keys; + + sec_prot_t *prot = tls_prot->type_get(tls_prot, SEC_PROT_TYPE_EAP_TLS); + if (!prot) { + return; + } + + eap_tls_sec_prot_int_t *data = eap_tls_sec_prot_get(prot); + + if (result == SEC_RESULT_OK) { + data->tls_result = EAP_TLS_RESULT_HANDSHAKE_OVER; + } else if (result == SEC_RESULT_CONF_ERROR) { + data->tls_result = EAP_TLS_RESULT_HANDSHAKE_FATAL_ERROR; + } else { + data->tls_result = EAP_TLS_RESULT_HANDSHAKE_FAILED; + } + + data->tls_ongoing = false; + + if (data->tls_result == EAP_TLS_RESULT_HANDSHAKE_FATAL_ERROR) { + // On fatal error terminate right away + prot->state_machine_call(prot); + } +} + +static int8_t auth_eap_tls_sec_prot_tls_send(sec_prot_t *tls_prot, void *pdu, uint16_t size) +{ + sec_prot_t *prot = tls_prot->type_get(tls_prot, SEC_PROT_TYPE_EAP_TLS); + if (!prot) { + return -1; + } + + eap_tls_sec_prot_int_t *data = eap_tls_sec_prot_get(prot); + + eap_tls_sec_prot_lib_message_free(&data->tls_send); + + data->tls_send.data = pdu; + data->tls_send.total_len = size; + data->tls_send.handled_len = 0; + + data->send_pending = true; + + prot->state_machine_call(prot); + + return 0; +} + +static void auth_eap_tls_sec_prot_init_tls(sec_prot_t *prot) +{ + eap_tls_sec_prot_int_t *data = eap_tls_sec_prot_get(prot); + if (data->tls_prot) { + return; + } + + data->tls_prot = prot->type_get(prot, SEC_PROT_TYPE_TLS); + if (!data->tls_prot) { + return; + } + + data->tls_prot->header_size = TLS_HEAD_LEN; + data->tls_prot->sec_keys = prot->sec_keys; + + data->tls_prot->create_conf = NULL; + data->tls_prot->create_ind = auth_eap_tls_sec_prot_tls_create_indication; + data->tls_prot->finished_ind = auth_eap_tls_sec_prot_tls_finished_indication; + data->tls_prot->send = auth_eap_tls_sec_prot_tls_send; + + data->tls_ongoing = true; +} + +static void auth_eap_tls_sec_prot_delete_tls(sec_prot_t *prot) +{ + eap_tls_sec_prot_int_t *data = eap_tls_sec_prot_get(prot); + // If initialized, TLS terminates on its own + if (data->tls_prot) { + return; + } + + sec_prot_t *tls_prot = prot->type_get(prot, SEC_PROT_TYPE_TLS); + if (tls_prot) { + tls_prot->finished_send(tls_prot); + } +} + +static void auth_eap_tls_sec_prot_state_machine(sec_prot_t *prot) +{ + eap_tls_sec_prot_int_t *data = eap_tls_sec_prot_get(prot); + int8_t result = EAP_TLS_MSG_CONTINUE; + + // EAP-TLS authenticator state machine + switch (sec_prot_state_get(&data->common)) { + case EAP_TLS_STATE_INIT: + sec_prot_state_set(prot, &data->common, EAP_TLS_STATE_CREATE_REQ); + break; + + // Wait KMP-CREATE.request + case EAP_TLS_STATE_CREATE_REQ: + tr_debug("EAP-TLS start"); + + prot->timer_start(prot); + + // KMP-CREATE.confirm + prot->create_conf(prot, SEC_RESULT_OK); + + // Increment sequence ID + auth_eap_tls_sec_prot_seq_id_update(prot); + + // Sends EAP request, Identity + 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, &eap_tls_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 + auth_eap_tls_sec_prot_message_send(prot, EAP_REQ, EAP_IDENTITY, EAP_TLS_EXCHANGE_NONE); + return; + } + + // Handle EAP response (expected Identity) + if (auth_eap_tls_sec_prot_message_handle(prot) != EAP_TLS_MSG_IDENTITY) { + return; + } + + // Increment sequence ID + //auth_eap_tls_sec_prot_seq_id_update(prot); + + // Sends EAP request, TLS EAP start + 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, &eap_tls_trickle_params); + + sec_prot_state_set(prot, &data->common, EAP_TLS_STATE_RESPONSE_START); + break; + + // Wait EAP response, TLS handshake + case EAP_TLS_STATE_RESPONSE_START: + case EAP_TLS_STATE_RESPONSE: + + // On timeout + if (sec_prot_result_timeout_check(&data->common)) { + if (sec_prot_state_get(&data->common) == EAP_TLS_STATE_RESPONSE_START) { + // Re-sends EAP request, TLS EAP start + auth_eap_tls_sec_prot_message_send(prot, EAP_REQ, EAP_TLS, EAP_TLS_EXCHANGE_START); + } else { + // Re-sends EAP request, TLS EAP + auth_eap_tls_sec_prot_message_send(prot, EAP_REQ, EAP_TLS, EAP_TLS_EXCHANGE_ONGOING); + } + return; + } + + sec_prot_state_set(prot, &data->common, EAP_TLS_STATE_RESPONSE); + + // EAP response + if (data->eap_code == EAP_RESPONSE) { + // Handle EAP response, TLS EAP + result = auth_eap_tls_sec_prot_message_handle(prot); + if (result == EAP_TLS_MSG_DECODE_ERROR) { + return; + } + if (result == EAP_TLS_MSG_IDENTITY) { + // If received EAP response, Identity: re-sends EAP request, TLS EAP start + auth_eap_tls_sec_prot_message_send(prot, EAP_REQ, EAP_TLS, EAP_TLS_EXCHANGE_START); + return; + } + + // All fragments received for a message + if (result == EAP_TLS_MSG_RECEIVE_DONE) { + auth_eap_tls_sec_prot_init_tls(prot); + + if (data->tls_ongoing) { + // Call TLS + data->tls_prot->receive(data->tls_prot, data->tls_recv.data, data->tls_recv.total_len); + eap_tls_sec_prot_lib_message_init(&data->tls_recv); + sec_prot_timer_trickle_stop(&data->common); + if (data->tls_result == EAP_TLS_RESULT_HANDSHAKE_FAILED && !data->send_pending) { + // In case has received alert and aborted can fail already here + eap_tls_sec_prot_lib_message_free(&data->tls_send); + } else { + data->wait_tls = true; + } + } + } else if (result == EAP_TLS_MSG_SEND_DONE) { + // All fragments send for a message, no new fragment received + eap_tls_sec_prot_lib_message_free(&data->tls_send); + } + // Wait TLS to process the received message + if (data->wait_tls) { + return; + } + } else { + // Call from TLS + if (data->tls_result == EAP_TLS_RESULT_HANDSHAKE_FATAL_ERROR) { + // Send failure + eap_tls_sec_prot_lib_message_free(&data->tls_send); + } + + // Call from TLS + data->wait_tls = false; + } + + // TLS EAP message to be send + if (data->tls_send.total_len > 0 || result == EAP_TLS_MSG_MORE_FRAG) { + data->send_pending = false; + + // Sends EAP request, TLS EAP, TLS exchange + 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, &eap_tls_trickle_params); + } else { + // TLS done, indicate success to peer + if (data->tls_result == EAP_TLS_RESULT_HANDSHAKE_OVER) { + // Sends EAP success + auth_eap_tls_sec_prot_message_send(prot, EAP_SUCCESS, 0, EAP_TLS_EXCHANGE_NONE); + } else { + // Sends EAP failure + auth_eap_tls_sec_prot_message_send(prot, EAP_FAILURE, 0, EAP_TLS_EXCHANGE_NONE); + sec_prot_result_set(&data->common, SEC_RESULT_ERROR); + } + + // Done + sec_prot_state_set(prot, &data->common, EAP_TLS_STATE_FINISH); + } + break; + + case EAP_TLS_STATE_FINISH: + tr_debug("EAP-TLS finish"); + + // 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); + data->common.ticks = 10 * 10; + break; + + case EAP_TLS_STATE_FINISHED: + auth_eap_tls_sec_prot_delete_tls(prot); + prot->timer_stop(prot); + prot->finished(prot); + break; + + default: + break; + } +} + +static void auth_eap_tls_sec_prot_seq_id_update(sec_prot_t *prot) +{ + 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/auth_eap_tls_sec_prot.h b/source/Security/protocols/eap_tls_sec_prot/auth_eap_tls_sec_prot.h new file mode 100644 index 0000000000..cbe295247a --- /dev/null +++ b/source/Security/protocols/eap_tls_sec_prot/auth_eap_tls_sec_prot.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2019, 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 AUTH_EAP_TLS_SEC_PROT_H_ +#define AUTH_EAP_TLS_SEC_PROT_H_ + +/* + * Authenticator EAP-TLS security protocol. Specified in RFC 5216. + * + */ + +/** + * auth_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 auth_eap_tls_sec_prot_register(kmp_service_t *service); + +#endif /* AUTH_EAP_TLS_SEC_PROT_H_ */ diff --git a/source/Security/protocols/eap_tls_sec_prot/eap_tls_sec_prot_lib.c b/source/Security/protocols/eap_tls_sec_prot/eap_tls_sec_prot_lib.c new file mode 100644 index 0000000000..c67f304597 --- /dev/null +++ b/source/Security/protocols/eap_tls_sec_prot/eap_tls_sec_prot_lib.c @@ -0,0 +1,230 @@ +/* + * Copyright (c) 2019, Arm Limited and affiliates. + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "nsconfig.h" +#include +#include "ns_types.h" +#include "ns_list.h" +#include "ns_trace.h" +#include "nsdynmemLIB.h" +#include "common_functions.h" +#include "fhss_config.h" +#include "NWK_INTERFACE/Include/protocol.h" +#include "6LoWPAN/ws/ws_config.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" + +#ifdef HAVE_WS + +#define TRACE_GROUP "eapl" + +static int8_t eap_tls_sec_prot_lib_ack_update(tls_data_t *tls); +static uint8_t *eap_tls_sec_prot_lib_fragment_write(uint8_t *data, uint16_t total_len, uint16_t handled_len, uint16_t *message_len, uint8_t *flags); +static int8_t eap_tls_sec_prot_lib_fragment_read(tls_data_t *tls, uint8_t *data, uint16_t len); + +const uint8_t eap_msg_trace[4][10] = {"REQ", "RESPONSE", "SUCCESS", "FAILURE"}; + +int8_t eap_tls_sec_prot_lib_message_allocate(tls_data_t *data, uint8_t head_len, uint16_t len) +{ + ns_dyn_mem_free(data->data); + + data->data = ns_dyn_mem_temporary_alloc(head_len + len); + if (!data->data) { + return -1; + } + data->total_len = len; + data->handled_len = 0; + + return 0; +} + +void eap_tls_sec_prot_lib_message_free(tls_data_t *data) +{ + ns_dyn_mem_free(data->data); + data->handled_len = 0; + data->data = 0; + data->total_len = 0; +} + +void eap_tls_sec_prot_lib_message_init(tls_data_t *data) +{ + data->handled_len = 0; + data->data = 0; + data->total_len = 0; +} + +int8_t eap_tls_sec_prot_lib_message_handle(uint8_t *data, uint16_t length, bool new_seq_id, tls_data_t *tls_send, tls_data_t *tls_recv) +{ + int8_t result = EAP_TLS_MSG_CONTINUE; + + // EAP-TLS start + if (data[0] & EAP_TLS_START) { + result = EAP_TLS_MSG_START; + } else if (data[0] & EAP_TLS_MORE_FRAGMENTS) { + // More fragments + eap_tls_sec_prot_lib_message_allocate(tls_send, TLS_HEAD_LEN, 0); + + // Handles the length field + if (data[0] & EAP_TLS_FRAGMENT_LENGTH) { + if (length < 5) { + return EAP_TLS_MSG_DECODE_ERROR; + } + + uint32_t len = common_read_32_bit(&data[1]); + + //For first fragment allocates data for incoming TLS packet + if (!tls_recv->data) { + eap_tls_sec_prot_lib_message_allocate(tls_recv, 0, len); + } + length -= 4; + data += 4; + } + result = EAP_TLS_MSG_MORE_FRAG; + } else if (data[0] == 0) { + // Last (or only) fragment or fragment acknowledge. If sending data + // updates acknowledged fragments. + if (new_seq_id && eap_tls_sec_prot_lib_ack_update(tls_send)) { + // All send, free data + eap_tls_sec_prot_lib_message_allocate(tls_send, TLS_HEAD_LEN, 0); + result = EAP_TLS_MSG_SEND_DONE; + } + } + + length -= 1; // EAP-TLS flags + data += 1; + + // TLS data not included + if (length == 0) { + if (new_seq_id && result == EAP_TLS_MSG_CONTINUE) { + // If received only EAP-TLS header fails, and is not start, + // fragment acknowledge or last frame + result = EAP_TLS_MSG_FAIL; + } + + return result; + } + + // New (not seen) sequence identifier, update received data + if (new_seq_id) { + if (!tls_recv->data) { + eap_tls_sec_prot_lib_message_allocate(tls_recv, 0, length); + } + if (eap_tls_sec_prot_lib_fragment_read(tls_recv, data, length)) { + result = EAP_TLS_MSG_RECEIVE_DONE; + } + } + + return result; +} + +uint8_t *eap_tls_sec_prot_lib_message_build(uint8_t eap_code, uint8_t eap_type, uint8_t flags, uint8_t eap_id_seq, uint8_t header_size, tls_data_t *tls_send, uint16_t *length) +{ + uint16_t eap_len = 4; + uint8_t *data_ptr = NULL; + + // Write EAP-TLS data (from EAP-TLS flags field onward) + if (tls_send->data) { + data_ptr = eap_tls_sec_prot_lib_fragment_write(tls_send->data + TLS_HEAD_LEN, tls_send->total_len, tls_send->handled_len, &eap_len, &flags); + } + + tr_debug("send EAP %s type %s id %i flags %x len %i", eap_msg_trace[eap_code - 1], + eap_type == EAP_IDENTITY ? "IDENTITY" : "TLS", eap_id_seq, flags, eap_len); + + eapol_pdu_t eapol_pdu; + + *length = eapol_pdu_eap_frame_init(&eapol_pdu, eap_code, eap_id_seq, eap_type, eap_len, data_ptr); + + uint8_t *eapol_decoded_data = ns_dyn_mem_temporary_alloc(*length + header_size); + if (!eapol_decoded_data) { + return NULL; + } + + eapol_write_pdu_frame(eapol_decoded_data + header_size, &eapol_pdu); + + return eapol_decoded_data; +} + +static int8_t eap_tls_sec_prot_lib_ack_update(tls_data_t *tls) +{ + if (!tls->data || !tls->total_len) { + return false; + } + + if (tls->handled_len + TLS_FRAGMENT_LEN < tls->total_len) { + tls->handled_len += TLS_FRAGMENT_LEN; + return false; + } + + tls->handled_len = tls->total_len; + return true; +} + +static int8_t eap_tls_sec_prot_lib_fragment_read(tls_data_t *tls, uint8_t *data, uint16_t len) +{ + if (tls->handled_len + len > tls->total_len) { + return true; + } + + memcpy(tls->data + tls->handled_len, data, len); + tls->handled_len += len; + + if (tls->handled_len == tls->total_len) { + return true; + } + + return false; +} + +static uint8_t *eap_tls_sec_prot_lib_fragment_write(uint8_t *data, uint16_t total_len, uint16_t handled_len, uint16_t *message_len, uint8_t *flags) +{ + uint8_t *data_begin = data + handled_len; + + if (*flags != 0xff) { + data_begin -= 1; + *message_len += 1; + data_begin[0] = *flags; + } + + if (total_len - handled_len > TLS_FRAGMENT_LEN) { + *message_len += TLS_FRAGMENT_LEN; + + if (handled_len == 0) { + data_begin -= 4; // length + *message_len += 4; + *flags |= EAP_TLS_MORE_FRAGMENTS | EAP_TLS_FRAGMENT_LENGTH; + data_begin[0] = *flags; + common_write_32_bit(total_len, &data_begin[1]); + } else { + *flags |= EAP_TLS_MORE_FRAGMENTS; + data_begin[0] = *flags; + } + } else { + *message_len += total_len - handled_len; + } + + return data_begin; +} + +#endif /* HAVE_WS */ + diff --git a/source/Security/protocols/eap_tls_sec_prot/eap_tls_sec_prot_lib.h b/source/Security/protocols/eap_tls_sec_prot/eap_tls_sec_prot_lib.h new file mode 100644 index 0000000000..37ff0f2741 --- /dev/null +++ b/source/Security/protocols/eap_tls_sec_prot/eap_tls_sec_prot_lib.h @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2019, 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 EAP_TLS_SEC_PROT_LIB_H_ +#define EAP_TLS_SEC_PROT_LIB_H_ + +/* + * EAP-TLS security protocol library + * + */ + +typedef enum { + EAP_TLS_EXCHANGE_NONE = 0, + EAP_TLS_EXCHANGE_START, + EAP_TLS_EXCHANGE_ONGOING +} eap_tls_sec_prot_tls_exchange_e; + +typedef enum { + EAP_TLS_MSG_IDENTITY = 0, + EAP_TLS_MSG_START, + EAP_TLS_MSG_CONTINUE, + EAP_TLS_MSG_SEND_DONE, + EAP_TLS_MSG_MORE_FRAG, + EAP_TLS_MSG_RECEIVE_DONE, + EAP_TLS_MSG_DECODE_ERROR, + EAP_TLS_MSG_FAIL, +} eap_tls_sec_prot_msg_e; + +typedef enum { + EAP_TLS_RESULT_NONE = 0, + EAP_TLS_RESULT_ERROR, + EAP_TLS_RESULT_HANDSHAKE_OVER, + EAP_TLS_RESULT_HANDSHAKE_FAILED, + EAP_TLS_RESULT_HANDSHAKE_FATAL_ERROR, +} eap_tls_sec_prot_result_e; + +typedef struct { + uint8_t *data; /**< Data buffer */ + uint16_t total_len; /**< Total length of the data buffer */ + uint16_t handled_len; /**< Handled length of the data buffer (e.g. acked by other end) */ +} tls_data_t; + +#define TLS_FRAGMENT_LEN 1100 //EAP-TLS fragment length +#define TLS_HEAD_LEN 5 //EAP-TLS flags and EAP-TLS length + +extern const uint8_t eap_msg_trace[4][10]; + +/** + * eap_tls_sec_prot_lib_message_allocate allocate message buffer + * + * \param data data buffer (length of the allocated data is header length + data length) + * \param head_len header length + * \param len data len + * + * \return < 0 failure + * \return >= 0 success + * + */ +int8_t eap_tls_sec_prot_lib_message_allocate(tls_data_t *data, uint8_t head_len, uint16_t len); + +/** + * eap_tls_sec_prot_lib_message_free free message buffer + * + * \param data data buffer + * + */ +void eap_tls_sec_prot_lib_message_free(tls_data_t *data); + +/** + * eap_tls_sec_prot_lib_message_init init message buffer + * + * \param data data buffer + * + */ +void eap_tls_sec_prot_lib_message_init(tls_data_t *data); + +/** + * eap_tls_sec_prot_lib_message_handle decode incoming message EAP-TLS part (from EAP-TLS flags field onward) + * + * \param data message data (points to EAP-TLS flags) + * \param length of the message remaining + * \param new_seq_id EAP sequence identifier is new (message is not re-send by other end) + * \param tls_send EAP-TLS send buffer, when sending data, updates the data (fragments) that has been acknowledged by other end + * \param tls_recv EAP_TLS receive buffer, if receiving data, updates the received data (fragments) + * + * \return < 0 failure + * \return >= 0 success + * + */ +int8_t eap_tls_sec_prot_lib_message_handle(uint8_t *data, uint16_t length, bool new_seq_id, tls_data_t *tls_send, tls_data_t *tls_recv); + +/** + * eap_tls_sec_prot_lib_message_build builds EAP-TLS message + * + * \param eap_code EAP code + * \param eap_type EAP type + * \param flags EAP-TLS flags + * \param eap_id_seq EAP sequence identifier + * \param header_size header size + * \param tls_send EAP-TLS send buffer, sends either a fragment or full message + * \param length of the message to be send + * + * \return pointer to message to be sent or NULL in case of failure + * + */ +uint8_t *eap_tls_sec_prot_lib_message_build(uint8_t eap_code, uint8_t eap_type, uint8_t flags, uint8_t eap_id_seq, uint8_t header_size, tls_data_t *tls_send, uint16_t *length); + +#endif /* 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 new file mode 100644 index 0000000000..5a61d865aa --- /dev/null +++ b/source/Security/protocols/eap_tls_sec_prot/supp_eap_tls_sec_prot.c @@ -0,0 +1,516 @@ +/* + * Copyright (c) 2019, Arm Limited and affiliates. + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "nsconfig.h" +#include +#include "ns_types.h" +#include "ns_list.h" +#include "ns_trace.h" +#include "nsdynmemLIB.h" +#include "fhss_config.h" +#include "NWK_INTERFACE/Include/protocol.h" +#include "6LoWPAN/ws/ws_config.h" +#include "Security/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/supp_eap_tls_sec_prot.h" + +#ifdef HAVE_WS + +#define TRACE_GROUP "eaps" + +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_REQUEST_ID = SEC_STATE_FIRST, + EAP_TLS_STATE_REQUEST_TLS_EAP, + EAP_TLS_STATE_REQUEST, + + EAP_TLS_STATE_FINISH = SEC_STATE_FINISH, + EAP_TLS_STATE_FINISHED = SEC_STATE_FINISHED +} eap_tls_sec_prot_state_e; + +typedef struct { + sec_prot_common_t common; /**< Common data */ + sec_prot_t *tls_prot; /**< TLS security protocol */ + eapol_pdu_t recv_eapol_pdu; /**< Received EAPOL PDU */ + tls_data_t tls_send; /**< EAP-TLS send buffer */ + tls_data_t tls_recv; /**< EAP-TLS receive buffer */ + uint8_t eap_id_seq; /**< EAP sequence */ + uint8_t eap_code; /**< Received EAP code */ + uint8_t eap_type; /**< Received EAP type */ + int8_t tls_result; /**< Result of TLS operation */ + bool wait_tls: 1; /**< Wait TLS (ECC calculation) before sending EAP-TLS message */ + bool tls_ongoing: 1; /**< TLS handshake is ongoing */ + bool send_pending: 1; /**< TLS data is not yet send to network */ +} eap_tls_sec_prot_int_t; + +static const trickle_params_t eap_tls_trickle_params = { + .Imin = 200, /* 20s; ticks are 100ms */ + .Imax = 450, /* 45s */ + .k = 0, /* infinity - no consistency checking */ + .TimerExpirations = 4 +}; + +static uint16_t supp_eap_tls_sec_prot_size(void); +static int8_t supp_eap_tls_sec_prot_init(sec_prot_t *prot); + +static void supp_eap_tls_sec_prot_create_response(sec_prot_t *prot, sec_prot_result_e result); +static void supp_eap_tls_sec_prot_delete(sec_prot_t *prot); +static int8_t supp_eap_tls_sec_prot_receive(sec_prot_t *prot, void *pdu, uint16_t size); + +static void supp_eap_tls_sec_prot_state_machine(sec_prot_t *prot); + +static int8_t supp_eap_tls_sec_prot_message_handle(sec_prot_t *prot); +static int8_t supp_eap_tls_sec_prot_message_send(sec_prot_t *prot, uint8_t eap_code, uint8_t eap_type, uint8_t tls_state); + +static void supp_eap_tls_sec_prot_timer_timeout(sec_prot_t *prot, uint16_t ticks); +static void supp_eap_tls_sec_prot_init_tls(sec_prot_t *prot); +static void supp_eap_tls_sec_prot_delete_tls(sec_prot_t *prot); + +static void supp_eap_tls_sec_prot_seq_id_update(sec_prot_t *prot); + +#define eap_tls_sec_prot_get(prot) (eap_tls_sec_prot_int_t *) &prot->data + +int8_t supp_eap_tls_sec_prot_register(kmp_service_t *service) +{ + if (!service) { + return -1; + } + + if (kmp_service_sec_protocol_register(service, IEEE_802_1X_MKA, supp_eap_tls_sec_prot_size, supp_eap_tls_sec_prot_init) < 0) { + return -1; + } + + return 0; +} + +static uint16_t supp_eap_tls_sec_prot_size(void) +{ + return sizeof(eap_tls_sec_prot_int_t); +} + +static int8_t supp_eap_tls_sec_prot_init(sec_prot_t *prot) +{ + prot->create_req = 0; + prot->create_resp = supp_eap_tls_sec_prot_create_response; + prot->receive = supp_eap_tls_sec_prot_receive; + prot->delete = supp_eap_tls_sec_prot_delete; + prot->state_machine = supp_eap_tls_sec_prot_state_machine; + prot->timer_timeout = supp_eap_tls_sec_prot_timer_timeout; + + 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->tls_prot = NULL; + data->eap_id_seq = 0; + data->eap_code = 0; + data->eap_type = 0; + eap_tls_sec_prot_lib_message_init(&data->tls_recv); + eap_tls_sec_prot_lib_message_init(&data->tls_send); + data->tls_result = EAP_TLS_RESULT_ERROR; + data->wait_tls = false; + data->tls_ongoing = false; + return 0; +} + +static void supp_eap_tls_sec_prot_delete(sec_prot_t *prot) +{ + eap_tls_sec_prot_int_t *data = eap_tls_sec_prot_get(prot); + eap_tls_sec_prot_lib_message_free(&data->tls_send); + eap_tls_sec_prot_lib_message_free(&data->tls_recv); +} + +static void supp_eap_tls_sec_prot_create_response(sec_prot_t *prot, sec_prot_result_e result) +{ + eap_tls_sec_prot_int_t *data = eap_tls_sec_prot_get(prot); + + // Call state machine + sec_prot_result_set(&data->common, result); + prot->state_machine_call(prot); +} + +static int8_t supp_eap_tls_sec_prot_receive(sec_prot_t *prot, void *pdu, uint16_t size) +{ + 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 only EAP messages (should never receive EAPOL-key messages during EAP-TLS) + 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); + } + 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 supp_eap_tls_sec_prot_message_handle(sec_prot_t *prot) +{ + eap_tls_sec_prot_int_t *data = eap_tls_sec_prot_get(prot); + + uint8_t *data_ptr = data->recv_eapol_pdu.msg.eap.data_ptr; + uint16_t length = data->recv_eapol_pdu.msg.eap.length; + + uint8_t new_seq_id = false; + if (data->recv_eapol_pdu.msg.eap.id_seq > data->eap_id_seq) { + new_seq_id = true; + } + + tr_debug("recv EAP %s type %s id %i flags %x len %i", 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); + + if (data->eap_type == EAP_IDENTITY) { + return EAP_TLS_MSG_IDENTITY; + } + + if (!data_ptr || length < 6) { + return EAP_TLS_MSG_DECODE_ERROR; + } + + length -= 5; // EAP fields: code, id, length, type + + return eap_tls_sec_prot_lib_message_handle(data_ptr, length, new_seq_id, &data->tls_send, &data->tls_recv); +} + +static int8_t supp_eap_tls_sec_prot_message_send(sec_prot_t *prot, uint8_t eap_code, uint8_t eap_type, uint8_t tls_state) +{ + 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_RESPONSE) { + if (eap_type == EAP_IDENTITY) { + const uint8_t identity[] = {"Anonymous"}; + const uint8_t identity_size = sizeof(identity) - 1; + if (data->tls_send.total_len != identity_size) { + eap_tls_sec_prot_lib_message_allocate(&data->tls_send, TLS_HEAD_LEN, identity_size); + memcpy(data->tls_send.data + TLS_HEAD_LEN, identity, identity_size); + } + flags = 0xff; + } + } 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; + } + + if (prot->send(prot, eapol_decoded_data, eapol_pdu_size + prot->header_size) < 0) { + return -1; + } + + return 0; +} + +static void supp_eap_tls_sec_prot_timer_timeout(sec_prot_t *prot, uint16_t ticks) +{ + eap_tls_sec_prot_int_t *data = eap_tls_sec_prot_get(prot); + sec_prot_timer_timeout_handle(prot, &data->common, &eap_tls_trickle_params, ticks); +} + +static void supp_eap_tls_sec_prot_tls_create_confirm(sec_prot_t *tls_prot, sec_prot_result_e result) +{ + if (result != SEC_RESULT_OK) { + sec_prot_t *prot = tls_prot->type_get(tls_prot, SEC_PROT_TYPE_EAP_TLS); + if (!prot) { + return; + } + + eap_tls_sec_prot_int_t *data = eap_tls_sec_prot_get(prot); + + sec_prot_state_set(prot, &data->common, EAP_TLS_STATE_FINISH); + } +} + +static void supp_eap_tls_sec_prot_tls_finished_indication(sec_prot_t *tls_prot, sec_prot_result_e result, sec_prot_keys_t *sec_keys) +{ + (void) sec_keys; + + sec_prot_t *prot = tls_prot->type_get(tls_prot, SEC_PROT_TYPE_EAP_TLS); + if (!prot) { + return; + } + + eap_tls_sec_prot_int_t *data = eap_tls_sec_prot_get(prot); + + if (result == SEC_RESULT_OK) { + data->tls_result = EAP_TLS_RESULT_HANDSHAKE_OVER; + } else if (result == SEC_RESULT_CONF_ERROR) { + data->tls_result = EAP_TLS_RESULT_HANDSHAKE_FATAL_ERROR; + } else { + // On failure has sent ALERT + data->tls_result = EAP_TLS_RESULT_HANDSHAKE_FAILED; + } + + data->tls_ongoing = false; + + if (data->tls_result == EAP_TLS_RESULT_HANDSHAKE_OVER || data->tls_result == EAP_TLS_RESULT_HANDSHAKE_FATAL_ERROR) { + // On fatal error and on success calls state machine to sent empty EAP-TLS message + prot->state_machine_call(prot); + } +} + +static int8_t supp_eap_tls_sec_prot_tls_send(sec_prot_t *tls_prot, void *pdu, uint16_t size) +{ + sec_prot_t *prot = tls_prot->type_get(tls_prot, SEC_PROT_TYPE_EAP_TLS); + if (!prot) { + return -1; + } + + eap_tls_sec_prot_int_t *data = eap_tls_sec_prot_get(prot); + + eap_tls_sec_prot_lib_message_free(&data->tls_send); + + data->tls_send.data = pdu; + data->tls_send.total_len = size; + data->tls_send.handled_len = 0; + + data->send_pending = true; + + prot->state_machine_call(prot); + + return 0; +} + +static void supp_eap_tls_sec_prot_init_tls(sec_prot_t *prot) +{ + eap_tls_sec_prot_int_t *data = eap_tls_sec_prot_get(prot); + if (data->tls_prot) { + return; + } + + data->tls_prot = prot->type_get(prot, SEC_PROT_TYPE_TLS); + if (!data->tls_prot) { + return; + } + + data->tls_prot->header_size = TLS_HEAD_LEN; + data->tls_prot->sec_keys = prot->sec_keys; + + data->tls_prot->create_conf = supp_eap_tls_sec_prot_tls_create_confirm; + data->tls_prot->create_ind = NULL; + data->tls_prot->finished_ind = supp_eap_tls_sec_prot_tls_finished_indication; + data->tls_prot->send = supp_eap_tls_sec_prot_tls_send; + + data->tls_ongoing = true; +} + +static void supp_eap_tls_sec_prot_delete_tls(sec_prot_t *prot) +{ + eap_tls_sec_prot_int_t *data = eap_tls_sec_prot_get(prot); + // If initialized, TLS terminates on its own + if (data->tls_prot) { + return; + } + + sec_prot_t *tls_prot = prot->type_get(prot, SEC_PROT_TYPE_TLS); + if (tls_prot) { + tls_prot->finished_send(tls_prot); + } +} + +static void supp_eap_tls_sec_prot_state_machine(sec_prot_t *prot) +{ + eap_tls_sec_prot_int_t *data = eap_tls_sec_prot_get(prot); + int8_t result; + + // EAP-TLS supplicant state machine + switch (sec_prot_state_get(&data->common)) { + case EAP_TLS_STATE_INIT: + sec_prot_state_set(prot, &data->common, EAP_TLS_STATE_REQUEST_ID); + break; + + // Wait EAP request, Identity (starts handshake on supplicant) + case EAP_TLS_STATE_REQUEST_ID: + + // Handle EAP request, Identity + if (supp_eap_tls_sec_prot_message_handle(prot) != EAP_TLS_MSG_IDENTITY) { + return; + } + + // Store sequence ID + supp_eap_tls_sec_prot_seq_id_update(prot); + + tr_debug("EAP-TLS start"); + + prot->timer_start(prot); + + // Send KMP-CREATE.indication + prot->create_ind(prot); + sec_prot_state_set(prot, &data->common, EAP_TLS_STATE_CREATE_RESP); + break; + + // Wait KMP-CREATE.response + case EAP_TLS_STATE_CREATE_RESP: + if (sec_prot_result_ok_check(&data->common)) { + // Send EAP response, Identity + supp_eap_tls_sec_prot_message_send(prot, EAP_RESPONSE, EAP_IDENTITY, EAP_TLS_EXCHANGE_NONE); + + // Start trickle timer to re-send if no response + sec_prot_timer_trickle_start(&data->common, &eap_tls_trickle_params); + + sec_prot_state_set(prot, &data->common, EAP_TLS_STATE_REQUEST_TLS_EAP); + } else { + // Ready to be deleted + sec_prot_state_set(prot, &data->common, EAP_TLS_STATE_FINISHED); + } + break; + + case EAP_TLS_STATE_REQUEST_TLS_EAP: + // On timeout + if (sec_prot_result_timeout_check(&data->common)) { + // Re-send EAP response, Identity + supp_eap_tls_sec_prot_message_send(prot, EAP_RESPONSE, EAP_IDENTITY, EAP_TLS_EXCHANGE_NONE); + return; + } + + // Handle EAP request (expected TLS EAP start) + result = supp_eap_tls_sec_prot_message_handle(prot); + + if (result == EAP_TLS_MSG_IDENTITY) { + // If received EAP request, Identity: re-send EAP response, Identity + supp_eap_tls_sec_prot_message_send(prot, EAP_RESPONSE, EAP_IDENTITY, EAP_TLS_EXCHANGE_NONE); + return; + } + + // Handle EAP request, TLS EAP start + if (result != EAP_TLS_MSG_START) { + return; + } + + // Store sequence ID + supp_eap_tls_sec_prot_seq_id_update(prot); + + sec_prot_state_set(prot, &data->common, EAP_TLS_STATE_REQUEST); + + // Initialize TLS protocol + supp_eap_tls_sec_prot_init_tls(prot); + // Request TLS to start (send client hello) + data->tls_prot->create_req(data->tls_prot, prot->sec_keys); + break; + + case EAP_TLS_STATE_REQUEST: + // On timeout + if (sec_prot_result_timeout_check(&data->common)) { + // Re-send EAP response + supp_eap_tls_sec_prot_message_send(prot, EAP_RESPONSE, EAP_TLS, EAP_TLS_EXCHANGE_ONGOING); + return; + } + + // EAP success + if (data->eap_code == EAP_SUCCESS) { + sec_prot_state_set(prot, &data->common, EAP_TLS_STATE_FINISH); + return; + } else if (data->eap_code == EAP_FAILURE) { + sec_prot_result_set(&data->common, SEC_RESULT_ERROR); + sec_prot_state_set(prot, &data->common, EAP_TLS_STATE_FINISH); + return; + } else if (data->eap_code == EAP_REQ) { + // EAP request, handle EAP request, TLS EAP + result = supp_eap_tls_sec_prot_message_handle(prot); + if (result == EAP_TLS_MSG_DECODE_ERROR) { + return; + } + + // Store sequence ID + supp_eap_tls_sec_prot_seq_id_update(prot); + + // All fragments received for a message + if (result == EAP_TLS_MSG_RECEIVE_DONE && data->tls_ongoing) { + // Call TLS + data->tls_prot->receive(data->tls_prot, data->tls_recv.data, data->tls_recv.total_len); + eap_tls_sec_prot_lib_message_init(&data->tls_recv); + sec_prot_timer_trickle_stop(&data->common); + if (data->send_pending || data->tls_result != EAP_TLS_RESULT_HANDSHAKE_FAILED) { + data->wait_tls = true; + } + } + // Wait TLS to process the received message + if (data->wait_tls) { + return; + } + } else { + data->wait_tls = false; + if (!data->tls_send.data || data->tls_result == EAP_TLS_RESULT_HANDSHAKE_FATAL_ERROR) { + // If no more data send response, TLS EAP (empty) + eap_tls_sec_prot_lib_message_allocate(&data->tls_send, TLS_HEAD_LEN, 0); + } + } + // Send EAP response + supp_eap_tls_sec_prot_message_send(prot, EAP_RESPONSE, EAP_TLS, EAP_TLS_EXCHANGE_ONGOING); + data->send_pending = false; + + // Start trickle timer to re-send if no response + sec_prot_timer_trickle_start(&data->common, &eap_tls_trickle_params); + break; + + case EAP_TLS_STATE_FINISH: + tr_debug("EAP-TLS finish"); + + // 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: + supp_eap_tls_sec_prot_delete_tls(prot); + prot->timer_stop(prot); + prot->finished(prot); + break; + + default: + break; + } +} + +static void supp_eap_tls_sec_prot_seq_id_update(sec_prot_t *prot) +{ + eap_tls_sec_prot_int_t *data = eap_tls_sec_prot_get(prot); + data->eap_id_seq = data->recv_eapol_pdu.msg.eap.id_seq; +} + +#endif /* HAVE_WS */ + diff --git a/source/Security/protocols/eap_tls_sec_prot/supp_eap_tls_sec_prot.h b/source/Security/protocols/eap_tls_sec_prot/supp_eap_tls_sec_prot.h new file mode 100644 index 0000000000..78ececd7bc --- /dev/null +++ b/source/Security/protocols/eap_tls_sec_prot/supp_eap_tls_sec_prot.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2019, 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 SUPP_EAP_TLS_SEC_PROT_H_ +#define SUPP_EAP_TLS_SEC_PROT_H_ + +/* + * Supplicant (peer) EAP-TLS security protocol. Specified in RFC 5216. + * + */ + +/** + * supp_eap_tls_sec_prot_register register supplicant EAP-TLS protocol to KMP service + * + * \param service KMP service + * + * \return < 0 failure + * \return >= 0 success + */ +int8_t supp_eap_tls_sec_prot_register(kmp_service_t *service); + +#endif /* SUPP_EAP_TLS_SEC_PROT_H_ */ + 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 new file mode 100644 index 0000000000..b46db4676c --- /dev/null +++ b/source/Security/protocols/fwh_sec_prot/auth_fwh_sec_prot.c @@ -0,0 +1,436 @@ +/* + * Copyright (c) 2016-2019, Arm Limited and affiliates. + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "nsconfig.h" +#include +#include "ns_types.h" +#include "ns_list.h" +#include "ns_trace.h" +#include "nsdynmemLIB.h" +#include "fhss_config.h" +#include "NWK_INTERFACE/Include/protocol.h" +#include "6LoWPAN/ws/ws_config.h" +#include "Security/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/eapol/kde_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/fwh_sec_prot/auth_fwh_sec_prot.h" +#include "Service_Libs/hmac/hmac_sha1.h" +#include "Service_Libs/nist_aes_kw/nist_aes_kw.h" + +#ifdef HAVE_WS + +#define TRACE_GROUP "afwh" + +typedef enum { + FWH_STATE_INIT = SEC_STATE_INIT, + FWH_STATE_CREATE_REQ = SEC_STATE_CREATE_REQ, + FWH_STATE_MESSAGE_2 = SEC_STATE_FIRST, + FWH_STATE_MESSAGE_4, + FWH_STATE_FINISH = SEC_STATE_FINISH, + FWH_STATE_FINISHED = SEC_STATE_FINISHED +} fwh_sec_prot_state_e; + +typedef enum { + FWH_MESSAGE_UNKNOWN = 0, + FWH_MESSAGE_1, + FWH_MESSAGE_2, + FWH_MESSAGE_3, + FWH_MESSAGE_4 +} fwh_sec_prot_msg_e; + +typedef struct { + sec_prot_common_t common; /**< Common data */ + eapol_pdu_t recv_eapol_pdu; /**< Received EAPOL PDU */ + fwh_sec_prot_msg_e recv_msg; /**< Received message */ + uint8_t nonce[EAPOL_KEY_NONCE_LEN]; /**< Authenticator nonce */ + uint8_t new_ptk[PTK_LEN]; /**< PTK (384 bits) */ + void *recv_pdu; /**< received pdu */ + uint16_t recv_size; /**< received pdu size */ +} fwh_sec_prot_int_t; + +static const trickle_params_t fwh_trickle_params = { + .Imin = 50, /* 5000ms; ticks are 100ms */ + .Imax = 150, /* 15000ms */ + .k = 0, /* infinity - no consistency checking */ + .TimerExpirations = 4 +}; + +static uint16_t auth_fwh_sec_prot_size(void); +static int8_t auth_fwh_sec_prot_init(sec_prot_t *prot); + +static void auth_fwh_sec_prot_create_request(sec_prot_t *prot, sec_prot_keys_t *sec_keys); +static void auth_fwh_sec_prot_delete(sec_prot_t *prot); +static int8_t auth_fwh_sec_prot_receive(sec_prot_t *prot, void *pdu, uint16_t size); +static fwh_sec_prot_msg_e auth_fwh_sec_prot_message_get(eapol_pdu_t *eapol_pdu, sec_prot_keys_t *sec_keys); +static void auth_fwh_sec_prot_state_machine(sec_prot_t *prot); + +static int8_t auth_fwh_sec_prot_message_send(sec_prot_t *prot, fwh_sec_prot_msg_e msg); +static void auth_fwh_sec_prot_timer_timeout(sec_prot_t *prot, uint16_t ticks); + +static int8_t auth_fwh_sec_prot_ptk_generate(sec_prot_t *prot, sec_prot_keys_t *sec_keys); +static int8_t auth_fwh_sec_prot_mic_validate(sec_prot_t *prot); + +#define fwh_sec_prot_get(prot) (fwh_sec_prot_int_t *) &prot->data + +int8_t auth_fwh_sec_prot_register(kmp_service_t *service) +{ + if (!service) { + return -1; + } + + if (kmp_service_sec_protocol_register(service, IEEE_802_11_4WH, auth_fwh_sec_prot_size, auth_fwh_sec_prot_init) < 0) { + return -1; + } + + return 0; +} + +static uint16_t auth_fwh_sec_prot_size(void) +{ + return sizeof(fwh_sec_prot_int_t); +} + +static int8_t auth_fwh_sec_prot_init(sec_prot_t *prot) +{ + prot->create_req = auth_fwh_sec_prot_create_request; + prot->create_resp = 0; + prot->receive = auth_fwh_sec_prot_receive; + prot->delete = auth_fwh_sec_prot_delete; + prot->state_machine = auth_fwh_sec_prot_state_machine; + prot->timer_timeout = auth_fwh_sec_prot_timer_timeout; + + fwh_sec_prot_int_t *data = fwh_sec_prot_get(prot); + sec_prot_init(&data->common); + sec_prot_state_set(prot, &data->common, FWH_STATE_INIT); + + data->common.ticks = 15 * 10; // 15 seconds + + uint8_t eui64[8] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}; + sec_prot_lib_nonce_init(data->nonce, eui64, 1000); + + return 0; +} + +static void auth_fwh_sec_prot_delete(sec_prot_t *prot) +{ + // No op at the moment + (void) prot; +} + +static void auth_fwh_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 auth_fwh_sec_prot_receive(sec_prot_t *prot, void *pdu, uint16_t size) +{ + fwh_sec_prot_int_t *data = fwh_sec_prot_get(prot); + int8_t ret_val = -1; + + // Decoding is successful + if (eapol_parse_pdu_header(pdu, size, &data->recv_eapol_pdu)) { + // Get message + data->recv_msg = auth_fwh_sec_prot_message_get(&data->recv_eapol_pdu, prot->sec_keys); + if (data->recv_msg != FWH_MESSAGE_UNKNOWN) { + // Call state machine + data->recv_pdu = pdu; + data->recv_size = size; + prot->state_machine(prot); + } + ret_val = 0; + } + + memset(&data->recv_eapol_pdu, 0, sizeof(eapol_pdu_t)); + data->recv_msg = FWH_MESSAGE_UNKNOWN; + data->recv_pdu = 0; + data->recv_size = 0; + + return ret_val; +} + +static fwh_sec_prot_msg_e auth_fwh_sec_prot_message_get(eapol_pdu_t *eapol_pdu, sec_prot_keys_t *sec_keys) +{ + fwh_sec_prot_msg_e msg = FWH_MESSAGE_UNKNOWN; + + if (!eapol_pdu->msg.key.key_information.pairwise_key) { + // This is mismatch between KMP ID indicating 802.11/4WH and key type + return FWH_MESSAGE_UNKNOWN; + } + + uint8_t key_mask = sec_prot_lib_key_mask_get(eapol_pdu); + + switch (key_mask) { + case KEY_INFO_KEY_MIC: + // Only accept message from supplicant with expected replay counter + if (eapol_pdu->msg.key.replay_counter == sec_prot_keys_pmk_replay_cnt_get(sec_keys)) { + msg = FWH_MESSAGE_2; + } + break; + case KEY_INFO_KEY_MIC | KEY_INFO_SECURED_KEY_FRAME: + // Only accept message from supplicant with expected replay counter + if (eapol_pdu->msg.key.replay_counter == sec_prot_keys_pmk_replay_cnt_get(sec_keys)) { + msg = FWH_MESSAGE_4; + } + break; + default: + break; + } + + return msg; +} + +static int8_t auth_fwh_sec_prot_message_send(sec_prot_t *prot, fwh_sec_prot_msg_e msg) +{ + fwh_sec_prot_int_t *data = fwh_sec_prot_get(prot); + + uint16_t kde_len = 0; + + switch (msg) { + case FWH_MESSAGE_1: + kde_len = KDE_PMKID_LEN; + break; + case FWH_MESSAGE_3: + kde_len = KDE_GTK_LEN + KDE_LIFETIME_LEN + KDE_GTKL_LEN; + kde_len = kde_len + 8; // One 64 bit block for AES Key Wrap + kde_len = kde_padded_length_calc(kde_len); + break; + default: + break; + } + + uint8_t *kde_start = ns_dyn_mem_temporary_alloc(kde_len); + + if (!kde_start) { + return -1; + } + + uint8_t *kde_end = kde_start; + + switch (msg) { + case FWH_MESSAGE_1: { + uint8_t pmkid[PMKID_LEN]; + if (sec_prot_lib_pmkid_generate(prot, pmkid, true) < 0) { + ns_dyn_mem_free(kde_start); + return -1; + } + kde_end = kde_pmkid_write(kde_end, pmkid); + } + break; + case FWH_MESSAGE_3: { + uint8_t gtk_index; + uint8_t *gtk = sec_prot_keys_get_gtk_to_insert(prot->sec_keys->gtks, >k_index); + if (gtk) { + kde_end = kde_gtk_write(kde_end, gtk_index, gtk); + + uint32_t gtk_lifetime = sec_prot_keys_gtk_lifetime_get(prot->sec_keys->gtks, gtk_index); + kde_end = kde_lifetime_write(kde_end, gtk_lifetime); + } + uint8_t gtkl = sec_prot_keys_gtkl_get(prot->sec_keys->gtks); + kde_end = kde_gtkl_write(kde_end, gtkl); + kde_padding_write(kde_end, kde_start + kde_len); + } + break; + default: + break; + } + + eapol_pdu_t eapol_pdu; + uint16_t eapol_pdu_size = eapol_pdu_key_frame_init(&eapol_pdu, kde_len, NULL); + + eapol_pdu.msg.key.key_information.pairwise_key = true; + + switch (msg) { + case FWH_MESSAGE_1: + sec_prot_keys_pmk_replay_cnt_increment(prot->sec_keys); + eapol_pdu.msg.key.replay_counter = sec_prot_keys_pmk_replay_cnt_get(prot->sec_keys); + eapol_pdu.msg.key.key_information.key_ack = true; + eapol_pdu.msg.key.key_length = 32; + eapol_pdu.msg.key.key_nonce = data->nonce; + break; + case FWH_MESSAGE_3: + sec_prot_keys_pmk_replay_cnt_increment(prot->sec_keys); + eapol_pdu.msg.key.replay_counter = sec_prot_keys_pmk_replay_cnt_get(prot->sec_keys); + eapol_pdu.msg.key.key_information.install = true; + eapol_pdu.msg.key.key_information.key_ack = true; + eapol_pdu.msg.key.key_information.key_mic = true; + eapol_pdu.msg.key.key_information.secured_key_frame = true; + eapol_pdu.msg.key.key_information.encrypted_key_data = true; + eapol_pdu.msg.key.key_nonce = data->nonce; + eapol_pdu.msg.key.key_length = 32; + break; + default: + break; + } + + uint8_t *eapol_pdu_frame = sec_prot_lib_message_build(data->new_ptk, kde_start, kde_len, &eapol_pdu, eapol_pdu_size, prot->header_size); + + ns_dyn_mem_free(kde_start); + + if (eapol_pdu_frame == NULL) { + return -1; + } + + if (prot->send(prot, eapol_pdu_frame, eapol_pdu_size + prot->header_size) < 0) { + return -1; + } + + return 0; +} + +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, &fwh_trickle_params, ticks); +} + +static void auth_fwh_sec_prot_state_machine(sec_prot_t *prot) +{ + fwh_sec_prot_int_t *data = fwh_sec_prot_get(prot); + + // 4WH authenticator state machine + switch (sec_prot_state_get(&data->common)) { + case FWH_STATE_INIT: + prot->timer_start(prot); + sec_prot_state_set(prot, &data->common, FWH_STATE_CREATE_REQ); + break; + + // Wait KMP-CREATE.request + case FWH_STATE_CREATE_REQ: + tr_debug("4WH start"); + + uint8_t *pmk = sec_prot_keys_pmk_get(prot->sec_keys); + if (!pmk) { // If PMK is not set fails + prot->create_conf(prot, SEC_RESULT_ERROR); + sec_prot_state_set(prot, &data->common, FWH_STATE_FINISHED); + return; + } + + // KMP-CREATE.confirm + prot->create_conf(prot, SEC_RESULT_OK); + + // Sends 4WH Message 1 + sec_prot_lib_nonce_generate(data->nonce); + 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, &fwh_trickle_params); + + sec_prot_state_set(prot, &data->common, FWH_STATE_MESSAGE_2); + break; + + // Wait 4WH message 2 + case FWH_STATE_MESSAGE_2: + if (sec_prot_result_timeout_check(&data->common)) { + // Re-sends 4WH Message 1 + sec_prot_lib_nonce_generate(data->nonce); + auth_fwh_sec_prot_message_send(prot, FWH_MESSAGE_1); + } else { + if (data->recv_msg != FWH_MESSAGE_2) { + return; + } + + if (auth_fwh_sec_prot_ptk_generate(prot, prot->sec_keys) < 0) { + return; + } + if (auth_fwh_sec_prot_mic_validate(prot) < 0) { + memset(data->new_ptk, 0, PTK_LEN); + return; + } + + // Sends 4WH Message 3 + 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, &fwh_trickle_params); + + sec_prot_state_set(prot, &data->common, FWH_STATE_MESSAGE_4); + } + break; + + // Wait 4WH message 4 + case FWH_STATE_MESSAGE_4: + if (sec_prot_result_timeout_check(&data->common)) { + // Re-sends 4WH Message 3 + auth_fwh_sec_prot_message_send(prot, FWH_MESSAGE_3); + } else { + if (data->recv_msg != FWH_MESSAGE_4) { + return; + } + if (auth_fwh_sec_prot_mic_validate(prot) < 0) { + return; + } + + sec_prot_keys_ptk_write(prot->sec_keys, data->new_ptk); + sec_prot_state_set(prot, &data->common, FWH_STATE_FINISH); + } + break; + + case FWH_STATE_FINISH: + tr_debug("4WH finish"); + + // KMP-FINISHED.indication, + prot->finished_ind(prot, sec_prot_result_get(&data->common), 0); + sec_prot_state_set(prot, &data->common, FWH_STATE_FINISHED); + break; + + case FWH_STATE_FINISHED: + prot->timer_stop(prot); + prot->finished(prot); + break; + + default: + break; + } +} + +static int8_t auth_fwh_sec_prot_ptk_generate(sec_prot_t *prot, sec_prot_keys_t *sec_keys) +{ + fwh_sec_prot_int_t *data = fwh_sec_prot_get(prot); + + uint8_t local_eui64[8]; + uint8_t remote_eui64[8]; + + prot->addr_get(prot, local_eui64, remote_eui64); + + uint8_t *remote_nonce = data->recv_eapol_pdu.msg.key.key_nonce; + if (!remote_nonce) { + return 1; + } + + uint8_t *pmk = sec_prot_keys_pmk_get(sec_keys); + sec_prot_lib_ptk_calc(pmk, local_eui64, remote_eui64, data->nonce, remote_nonce, data->new_ptk); + + return 0; +} + +static int8_t auth_fwh_sec_prot_mic_validate(sec_prot_t *prot) +{ + fwh_sec_prot_int_t *data = fwh_sec_prot_get(prot); + return sec_prot_lib_mic_validate(data->new_ptk, data->recv_eapol_pdu.msg.key.key_mic, data->recv_pdu, data->recv_size); +} + +#endif /* HAVE_WS */ + diff --git a/source/Security/protocols/fwh_sec_prot/auth_fwh_sec_prot.h b/source/Security/protocols/fwh_sec_prot/auth_fwh_sec_prot.h new file mode 100644 index 0000000000..efeab123d2 --- /dev/null +++ b/source/Security/protocols/fwh_sec_prot/auth_fwh_sec_prot.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2016-2019, 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 AUTH_FWH_SEC_PROT_H_ +#define AUTH_FWH_SEC_PROT_H_ + +/* + * Authenticator Four Way Handshake (4WH) security protocol. 4WH protocol is + * specified in IEEE 802.11 and Wi-SUN FANWG-FANTPS. + * + */ + +/** + * auth_fwh_sec_prot_register register authenticator 4WH protocol to KMP service + * + * \param service KMP service + * + * \return < 0 failure + * \return >= 0 success + */ +int8_t auth_fwh_sec_prot_register(kmp_service_t *service); + +#endif /* AUTH_FWH_SEC_PROT_H_ */ 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 new file mode 100644 index 0000000000..97fc30958f --- /dev/null +++ b/source/Security/protocols/fwh_sec_prot/supp_fwh_sec_prot.c @@ -0,0 +1,528 @@ +/* + * Copyright (c) 2016-2019, Arm Limited and affiliates. + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "nsconfig.h" +#include +#include "ns_types.h" +#include "ns_list.h" +#include "ns_trace.h" +#include "nsdynmemLIB.h" +#include "fhss_config.h" +#include "NWK_INTERFACE/Include/protocol.h" +#include "6LoWPAN/ws/ws_config.h" +#include "Security/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/eapol/kde_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/fwh_sec_prot/supp_fwh_sec_prot.h" +#include "Service_Libs/hmac/hmac_sha1.h" +#include "Service_Libs/nist_aes_kw/nist_aes_kw.h" + +#ifdef HAVE_WS + +#define TRACE_GROUP "sfwh" + +typedef enum { + FWH_STATE_INIT = SEC_STATE_INIT, + FWH_STATE_CREATE_RESP = SEC_STATE_CREATE_RESP, + FWH_STATE_CREATE_IND = SEC_STATE_CREATE_IND, + FWH_STATE_MESSAGE_1 = SEC_STATE_FIRST, + FWH_STATE_MESSAGE_3, + FWH_STATE_CREATE_RESP_SUPP_RETRY, + FWH_STATE_FINISH = SEC_STATE_FINISH, + FWH_STATE_FINISHED = SEC_STATE_FINISHED +} fwh_sec_prot_state_e; + +typedef enum { + FWH_MESSAGE_UNKNOWN = 0, + FWH_MESSAGE_1, + FWH_MESSAGE_2, + FWH_MESSAGE_3, + FWH_MESSAGE_4 +} fwh_sec_prot_msg_e; + +#define KEY_INFO_INSTALL 0x01 +#define KEY_INFO_KEY_ACK 0x02 +#define KEY_INFO_KEY_MIC 0x04 +#define KEY_INFO_SECURED_KEY_FRAME 0x08 + +typedef struct { + sec_prot_common_t common; /**< Common data */ + eapol_pdu_t recv_eapol_pdu; /**< Received EAPOL PDU */ + fwh_sec_prot_msg_e recv_msg; /**< Received message */ + uint8_t snonce[EAPOL_KEY_NONCE_LEN]; /**< Supplicant nonce */ + uint8_t anonce[EAPOL_KEY_NONCE_LEN]; /**< Authenticator nonce */ + uint8_t new_ptk[PTK_LEN]; /**< PTK (384 bits) */ + uint8_t remote_eui64[8]; /**< Remote EUI-64 used to calculate PTK */ + void *recv_pdu; /**< received pdu */ + uint16_t recv_size; /**< received pdu size */ + uint64_t recv_replay_cnt; /**< received replay counter */ +} fwh_sec_prot_int_t; + +static const trickle_params_t fwh_trickle_params = { + .Imin = 50, /* 5000ms; ticks are 100ms */ + .Imax = 150, /* 15000ms */ + .k = 0, /* infinity - no consistency checking */ + .TimerExpirations = 4 +}; + +static uint16_t supp_fwh_sec_prot_size(void); +static int8_t supp_fwh_sec_prot_init(sec_prot_t *prot); + +static void supp_fwh_sec_prot_create_response(sec_prot_t *prot, sec_prot_result_e result); +static void supp_fwh_sec_prot_delete(sec_prot_t *prot); +static int8_t supp_fwh_sec_prot_receive(sec_prot_t *prot, void *pdu, uint16_t size); +static fwh_sec_prot_msg_e supp_fwh_sec_prot_message_get(eapol_pdu_t *eapol_pdu, sec_prot_keys_t *sec_keys); +static void supp_fwh_sec_prot_state_machine(sec_prot_t *prot); + +static int8_t supp_fwh_sec_prot_message_send(sec_prot_t *prot, fwh_sec_prot_msg_e msg); +static void supp_fwh_sec_prot_timer_timeout(sec_prot_t *prot, uint16_t ticks); + +static int8_t supp_fwh_sec_prot_ptk_generate(sec_prot_t *prot, sec_prot_keys_t *sec_keys); +static int8_t supp_fwh_sec_prot_mic_validate(sec_prot_t *prot); + +static void supp_fwh_sec_prot_recv_replay_counter_store(sec_prot_t *prot); +static void supp_fwh_sec_prot_anonce_store(sec_prot_t *prot); +static int8_t supp_fwh_sec_prot_anonce_validate(sec_prot_t *prot); +static void supp_fwh_sec_prot_security_replay_counter_update(sec_prot_t *prot); + +static int8_t supp_fwh_kde_handle(sec_prot_t *prot); + +#define fwh_sec_prot_get(prot) (fwh_sec_prot_int_t *) &prot->data + +int8_t supp_fwh_sec_prot_register(kmp_service_t *service) +{ + if (!service) { + return -1; + } + + if (kmp_service_sec_protocol_register(service, IEEE_802_11_4WH, supp_fwh_sec_prot_size, supp_fwh_sec_prot_init) < 0) { + return -1; + } + + return 0; +} + +static uint16_t supp_fwh_sec_prot_size(void) +{ + return sizeof(fwh_sec_prot_int_t); +} + +static int8_t supp_fwh_sec_prot_init(sec_prot_t *prot) +{ + prot->create_req = 0; + prot->create_resp = supp_fwh_sec_prot_create_response; + prot->receive = supp_fwh_sec_prot_receive; + prot->delete = supp_fwh_sec_prot_delete; + prot->state_machine = supp_fwh_sec_prot_state_machine; + prot->timer_timeout = supp_fwh_sec_prot_timer_timeout; + + fwh_sec_prot_int_t *data = fwh_sec_prot_get(prot); + sec_prot_init(&data->common); + sec_prot_state_set(prot, &data->common, FWH_STATE_INIT); + + data->common.ticks = 30 * 10; // 30 seconds + + uint8_t eui64[8] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}; + sec_prot_lib_nonce_init(data->snonce, eui64, 1000); + + return 0; +} + +static void supp_fwh_sec_prot_delete(sec_prot_t *prot) +{ + // No op at the moment + (void) prot; +} + +static void supp_fwh_sec_prot_create_response(sec_prot_t *prot, sec_prot_result_e result) +{ + fwh_sec_prot_int_t *data = fwh_sec_prot_get(prot); + + // Call state machine + sec_prot_result_set(&data->common, result); + prot->state_machine_call(prot); +} + +static int8_t supp_fwh_sec_prot_receive(sec_prot_t *prot, void *pdu, uint16_t size) +{ + fwh_sec_prot_int_t *data = fwh_sec_prot_get(prot); + int8_t ret_val = -1; + + // Decoding is successful + if (eapol_parse_pdu_header(pdu, size, &data->recv_eapol_pdu)) { + // Get message + data->recv_msg = supp_fwh_sec_prot_message_get(&data->recv_eapol_pdu, prot->sec_keys); + if (data->recv_msg != FWH_MESSAGE_UNKNOWN) { + // Call state machine + data->recv_pdu = pdu; + data->recv_size = size; + prot->state_machine(prot); + } + ret_val = 0; + } + + memset(&data->recv_eapol_pdu, 0, sizeof(eapol_pdu_t)); + data->recv_msg = FWH_MESSAGE_UNKNOWN; + data->recv_pdu = 0; + data->recv_size = 0; + + return ret_val; +} + +static fwh_sec_prot_msg_e supp_fwh_sec_prot_message_get(eapol_pdu_t *eapol_pdu, sec_prot_keys_t *sec_keys) +{ + fwh_sec_prot_msg_e msg = FWH_MESSAGE_UNKNOWN; + + if (!eapol_pdu->msg.key.key_information.pairwise_key) { + // This is mismatch between KMP ID indicating 802.11/4WH and key type + return FWH_MESSAGE_UNKNOWN; + } + + uint8_t key_mask = sec_prot_lib_key_mask_get(eapol_pdu); + + switch (key_mask) { + case KEY_INFO_KEY_ACK: + // Must have valid replay counter + if (eapol_pdu->msg.key.replay_counter > sec_prot_keys_pmk_replay_cnt_get(sec_keys)) { + msg = FWH_MESSAGE_1; + } + break; + case KEY_INFO_INSTALL | KEY_INFO_KEY_ACK | KEY_INFO_KEY_MIC | KEY_INFO_SECURED_KEY_FRAME: + // Must have valid replay counter + if (eapol_pdu->msg.key.replay_counter > sec_prot_keys_pmk_replay_cnt_get(sec_keys)) { + if (eapol_pdu->msg.key.key_information.encrypted_key_data) { + // This should include the GTK KDE, Lifetime KDE and GTKL KDE. + // At least some of them should be present + msg = FWH_MESSAGE_3; + } + } + break; + default: + break; + } + + return msg; +} + +static int8_t supp_fwh_sec_prot_message_send(sec_prot_t *prot, fwh_sec_prot_msg_e msg) +{ + fwh_sec_prot_int_t *data = fwh_sec_prot_get(prot); + + eapol_pdu_t eapol_pdu; + uint16_t eapol_pdu_size = eapol_pdu_key_frame_init(&eapol_pdu, 0, NULL); + + eapol_pdu.msg.key.key_information.pairwise_key = true; + + switch (msg) { + case FWH_MESSAGE_2: + eapol_pdu.msg.key.replay_counter = data->recv_replay_cnt; + eapol_pdu.msg.key.key_information.key_mic = true; + eapol_pdu.msg.key.key_length = 0; + eapol_pdu.msg.key.key_nonce = data->snonce; + break; + case FWH_MESSAGE_4: + eapol_pdu.msg.key.replay_counter = data->recv_replay_cnt; + eapol_pdu.msg.key.key_information.key_mic = true; + eapol_pdu.msg.key.key_information.secured_key_frame = true; + eapol_pdu.msg.key.key_length = 0; + break; + default: + break; + } + + uint8_t *eapol_pdu_frame = sec_prot_lib_message_build(data->new_ptk, 0, 0, &eapol_pdu, eapol_pdu_size, prot->header_size); + + if (eapol_pdu_frame == NULL) { + return -1; + } + + if (prot->send(prot, eapol_pdu_frame, eapol_pdu_size + prot->header_size) < 0) { + return -1; + } + + return 0; +} + +static void supp_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, &fwh_trickle_params, ticks); +} + +static void supp_fwh_sec_prot_state_machine(sec_prot_t *prot) +{ + fwh_sec_prot_int_t *data = fwh_sec_prot_get(prot); + + // 4WH supplicant state machine + switch (sec_prot_state_get(&data->common)) { + case FWH_STATE_INIT: + prot->timer_start(prot); + sec_prot_state_set(prot, &data->common, FWH_STATE_MESSAGE_1); + break; + + // Wait 4WH message 1 (starts handshake on supplicant) + case FWH_STATE_MESSAGE_1: + if (data->recv_msg != FWH_MESSAGE_1) { + return; + } + + // PMKID must be valid + if (supp_fwh_kde_handle(prot) < 0) { + return; + } + + tr_debug("4WH start"); + + // Store authenticator nonce for check when 4WH Message 3 is received + supp_fwh_sec_prot_anonce_store(prot); + sec_prot_lib_nonce_generate(data->snonce); + if (supp_fwh_sec_prot_ptk_generate(prot, prot->sec_keys) < 0) { + return; + } + + supp_fwh_sec_prot_recv_replay_counter_store(prot); + + // Send KMP-CREATE.indication + prot->create_ind(prot); + sec_prot_state_set(prot, &data->common, FWH_STATE_CREATE_RESP); + break; + + // Wait KMP-CREATE.response + case FWH_STATE_CREATE_RESP: + 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 = 30 * 10; // 30 seconds + sec_prot_state_set(prot, &data->common, FWH_STATE_MESSAGE_3); + } else { + // Ready to be deleted + sec_prot_state_set(prot, &data->common, FWH_STATE_FINISHED); + } + break; + + // Wait 4WH message 3 (message 2 has been sent) + case FWH_STATE_MESSAGE_3: + if (data->recv_msg == FWH_MESSAGE_1) { + + // PMKID must be valid + if (supp_fwh_kde_handle(prot) < 0) { + return; + } + + // Store authenticator nonce for check when 4WH Message 3 is received + supp_fwh_sec_prot_anonce_store(prot); + sec_prot_lib_nonce_generate(data->snonce); + if (supp_fwh_sec_prot_ptk_generate(prot, prot->sec_keys) < 0) { + return; + } + // Send 4WH message 2 + supp_fwh_sec_prot_message_send(prot, FWH_MESSAGE_2); + data->common.ticks = 30 * 10; // 30 seconds + } else if (data->recv_msg != FWH_MESSAGE_3) { + return; + } + + // MIC must be valid + if (supp_fwh_sec_prot_mic_validate(prot) < 0) { + return; + } + + // Nonce must match to 4WH Message 1 + if (supp_fwh_sec_prot_anonce_validate(prot) < 0) { + return; + } + + // Must have at least GTKL + if (supp_fwh_kde_handle(prot) < 0) { + return; + } + + supp_fwh_sec_prot_recv_replay_counter_store(prot); + supp_fwh_sec_prot_security_replay_counter_update(prot); + + // Sends 4WH Message 4 + supp_fwh_sec_prot_message_send(prot, FWH_MESSAGE_4); + data->common.ticks = 30 * 10; // 30 seconds + sec_prot_state_set(prot, &data->common, FWH_STATE_FINISH); + break; + + case FWH_STATE_FINISH: + tr_debug("4WH finish"); + + // KMP-FINISHED.indication + sec_prot_keys_ptk_write(prot->sec_keys, data->new_ptk); + sec_prot_keys_ptk_eui_64_write(prot->sec_keys, data->remote_eui64); + prot->finished_ind(prot, sec_prot_result_get(&data->common), prot->sec_keys); + sec_prot_state_set(prot, &data->common, FWH_STATE_FINISHED); + break; + + case FWH_STATE_FINISHED: + if (sec_prot_result_timeout_check(&data->common)) { + prot->timer_stop(prot); + prot->finished(prot); + } else { + if (data->recv_msg != FWH_MESSAGE_3) { + return; + } + + // MIC must be valid + if (supp_fwh_sec_prot_mic_validate(prot) < 0) { + return; + } + + // Nonce must match to 4WH Message 1 + if (supp_fwh_sec_prot_anonce_validate(prot) < 0) { + return; + } + + // Must have at least GTKL + if (supp_fwh_kde_handle(prot) < 0) { + return; + } + + supp_fwh_sec_prot_recv_replay_counter_store(prot); + supp_fwh_sec_prot_security_replay_counter_update(prot); + + tr_debug("4WH start again"); + + // Send KMP-CREATE.indication + prot->create_ind(prot); + sec_prot_state_set(prot, &data->common, FWH_STATE_CREATE_RESP_SUPP_RETRY); + } + break; + + // Special case for second receiving of 4WH message 3 + case FWH_STATE_CREATE_RESP_SUPP_RETRY: + if (sec_prot_result_ok_check(&data->common)) { + // Send 4WH message 4 + supp_fwh_sec_prot_message_send(prot, FWH_MESSAGE_4); + data->common.ticks = 30 * 10; // 30 seconds + sec_prot_state_set(prot, &data->common, FWH_STATE_FINISH); + } else { + // Ready to be deleted + sec_prot_state_set(prot, &data->common, FWH_STATE_FINISHED); + } + break; + + default: + break; + } +} + +static int8_t supp_fwh_sec_prot_ptk_generate(sec_prot_t *prot, sec_prot_keys_t *sec_keys) +{ + 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); + + uint8_t *remote_nonce = data->recv_eapol_pdu.msg.key.key_nonce; + if (!remote_nonce) { + return 1; + } + + uint8_t *pmk = sec_prot_keys_pmk_get(sec_keys); + sec_prot_lib_ptk_calc(pmk, local_eui64, data->remote_eui64, data->snonce, remote_nonce, data->new_ptk); + + return 0; +} + +static int8_t supp_fwh_sec_prot_mic_validate(sec_prot_t *prot) +{ + fwh_sec_prot_int_t *data = fwh_sec_prot_get(prot); + return sec_prot_lib_mic_validate(data->new_ptk, data->recv_eapol_pdu.msg.key.key_mic, data->recv_pdu, data->recv_size); +} + +static void supp_fwh_sec_prot_recv_replay_counter_store(sec_prot_t *prot) +{ + fwh_sec_prot_int_t *data = fwh_sec_prot_get(prot); + data->recv_replay_cnt = data->recv_eapol_pdu.msg.key.replay_counter; +} + +static void supp_fwh_sec_prot_anonce_store(sec_prot_t *prot) +{ + fwh_sec_prot_int_t *data = fwh_sec_prot_get(prot); + memcpy(data->anonce, data->recv_eapol_pdu.msg.key.key_nonce, EAPOL_KEY_NONCE_LEN); +} + +static int8_t supp_fwh_sec_prot_anonce_validate(sec_prot_t *prot) +{ + fwh_sec_prot_int_t *data = fwh_sec_prot_get(prot); + if (memcmp(data->anonce, data->recv_eapol_pdu.msg.key.key_nonce, EAPOL_KEY_NONCE_LEN) != 0) { + return -1; + } + return 0; +} + +static void supp_fwh_sec_prot_security_replay_counter_update(sec_prot_t *prot) +{ + fwh_sec_prot_int_t *data = fwh_sec_prot_get(prot); + sec_prot_keys_pmk_replay_cnt_set(prot->sec_keys, data->recv_eapol_pdu.msg.key.replay_counter); +} + +static int8_t supp_fwh_kde_handle(sec_prot_t *prot) +{ + fwh_sec_prot_int_t *data = fwh_sec_prot_get(prot); + + uint16_t kde_len; + uint8_t *kde = sec_prot_lib_message_handle(data->new_ptk, &kde_len, &data->recv_eapol_pdu); + if (!kde) { + return -1; + } + + switch (data->recv_msg) { + case FWH_MESSAGE_1: { + uint8_t recv_pmkid[PMKID_LEN]; + uint8_t calc_pmkid[PMKID_LEN]; + if (kde_pmkid_read(kde, kde_len, recv_pmkid) < 0) { + goto error; + } + if (sec_prot_lib_pmkid_generate(prot, calc_pmkid, false) < 0) { + goto error; + } + if (memcmp(recv_pmkid, calc_pmkid, PMKID_LEN) != 0) { + goto error; + } + } + break; + + case FWH_MESSAGE_3: + // If a valid new GTK value present, insert it + if (sec_prot_lib_gtk_read(kde, kde_len, prot->sec_keys->gtks) < 0) { + goto error; + } + break; + + default: + break; + } + + ns_dyn_mem_free(kde); + return 0; + +error: + ns_dyn_mem_free(kde); + return -1; +} + +#endif /* HAVE_WS */ diff --git a/source/Security/protocols/fwh_sec_prot/supp_fwh_sec_prot.h b/source/Security/protocols/fwh_sec_prot/supp_fwh_sec_prot.h new file mode 100644 index 0000000000..2cb2284e3c --- /dev/null +++ b/source/Security/protocols/fwh_sec_prot/supp_fwh_sec_prot.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2016-2019, 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 SUPP_FWH_SEC_PROT_H_ +#define SUPP_FWH_SEC_PROT_H_ + +/* + * Supplicant Four Way Handshake (4WH) security protocol. 4WH protocol is + * specified in IEEE 802.11 and Wi-SUN FANWG-FANTPS. + * + */ + +/** + * supp_fwh_sec_prot_register register supplicant 4WH protocol to KMP service + * + * \param service KMP service + * + * \return < 0 failure + * \return >= 0 success + */ +int8_t supp_fwh_sec_prot_register(kmp_service_t *service); + +#endif /* SUPP_FWH_SEC_PROT_H_ */ 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 new file mode 100644 index 0000000000..ce204f082c --- /dev/null +++ b/source/Security/protocols/gkh_sec_prot/auth_gkh_sec_prot.c @@ -0,0 +1,329 @@ +/* + * Copyright (c) 2018-2019, Arm Limited and affiliates. + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "nsconfig.h" +#include +#include "ns_types.h" +#include "ns_list.h" +#include "ns_trace.h" +#include "nsdynmemLIB.h" +#include "fhss_config.h" +#include "NWK_INTERFACE/Include/protocol.h" +#include "6LoWPAN/ws/ws_config.h" +#include "Security/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/eapol/kde_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/gkh_sec_prot/auth_gkh_sec_prot.h" + +#ifdef HAVE_WS + +#define TRACE_GROUP "agkh" + +typedef enum { + GKH_STATE_INIT = SEC_STATE_INIT, + GKH_STATE_CREATE_REQ = SEC_STATE_CREATE_REQ, + GKH_STATE_MESSAGE_2 = SEC_STATE_FIRST, + GKH_STATE_FINISH = SEC_STATE_FINISH, + GKH_STATE_FINISHED = SEC_STATE_FINISHED +} gkh_sec_prot_state_e; + +typedef enum { + GKH_MESSAGE_UNKNOWN = 0, + GKH_MESSAGE_1, + GKH_MESSAGE_2 +} gkh_sec_prot_msg_e; + +typedef struct { + sec_prot_common_t common; /**< Common data */ + eapol_pdu_t recv_eapol_pdu; /**< Received EAPOL PDU */ + void *recv_pdu; /**< Received pdu */ + uint16_t recv_size; /**< Received pdu size */ +} gkh_sec_prot_int_t; + +static const trickle_params_t gkh_trickle_params = { + .Imin = 50, /* 5000ms; ticks are 100ms */ + .Imax = 150, /* 15000ms */ + .k = 0, /* infinity - no consistency checking */ + .TimerExpirations = 4 +}; + +static uint16_t auth_gkh_sec_prot_size(void); +static int8_t auth_gkh_sec_prot_init(sec_prot_t *prot); + +static void auth_gkh_sec_prot_create_request(sec_prot_t *prot, sec_prot_keys_t *sec_keys); +static void auth_gkh_sec_prot_delete(sec_prot_t *prot); +static int8_t auth_gkh_sec_prot_receive(sec_prot_t *prot, void *pdu, uint16_t size); +static gkh_sec_prot_msg_e auth_gkh_sec_prot_message_get(eapol_pdu_t *eapol_pdu, sec_prot_keys_t *sec_keys); +static void auth_gkh_sec_prot_state_machine(sec_prot_t *prot); + +static int8_t auth_gkh_sec_prot_message_send(sec_prot_t *prot, gkh_sec_prot_msg_e msg); +static void auth_gkh_sec_prot_timer_timeout(sec_prot_t *prot, uint16_t ticks); +static int8_t auth_gkh_sec_prot_mic_validate(sec_prot_t *prot); + +#define gkh_sec_prot_get(prot) (gkh_sec_prot_int_t *) &prot->data + +int8_t auth_gkh_sec_prot_register(kmp_service_t *service) +{ + if (!service) { + return -1; + } + + if (kmp_service_sec_protocol_register(service, IEEE_802_11_GKH, auth_gkh_sec_prot_size, auth_gkh_sec_prot_init) < 0) { + return -1; + } + + return 0; +} + +static uint16_t auth_gkh_sec_prot_size(void) +{ + return sizeof(gkh_sec_prot_int_t); +} + +static int8_t auth_gkh_sec_prot_init(sec_prot_t *prot) +{ + prot->create_req = auth_gkh_sec_prot_create_request; + prot->create_resp = 0; + prot->receive = auth_gkh_sec_prot_receive; + prot->delete = auth_gkh_sec_prot_delete; + prot->state_machine = auth_gkh_sec_prot_state_machine; + prot->timer_timeout = auth_gkh_sec_prot_timer_timeout; + + gkh_sec_prot_int_t *data = gkh_sec_prot_get(prot); + sec_prot_init(&data->common); + sec_prot_state_set(prot, &data->common, GKH_STATE_INIT); + + return 0; +} + +static void auth_gkh_sec_prot_delete(sec_prot_t *prot) +{ + // No op at the moment + (void) prot; +} + +static void auth_gkh_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 auth_gkh_sec_prot_receive(sec_prot_t *prot, void *pdu, uint16_t size) +{ + gkh_sec_prot_int_t *data = gkh_sec_prot_get(prot); + int8_t ret_val = -1; + + // Decoding is successful + if (eapol_parse_pdu_header(pdu, size, &data->recv_eapol_pdu)) { + // Get message + if (auth_gkh_sec_prot_message_get(&data->recv_eapol_pdu, prot->sec_keys) != GKH_MESSAGE_UNKNOWN) { + // Call state machine + data->recv_pdu = pdu; + data->recv_size = size; + prot->state_machine(prot); + } + ret_val = 0; + } + + memset(&data->recv_eapol_pdu, 0, sizeof(eapol_pdu_t)); + data->recv_pdu = 0; + data->recv_size = 0; + + return ret_val; +} + +static gkh_sec_prot_msg_e auth_gkh_sec_prot_message_get(eapol_pdu_t *eapol_pdu, sec_prot_keys_t *sec_keys) +{ + gkh_sec_prot_msg_e msg = GKH_MESSAGE_UNKNOWN; + + if (eapol_pdu->msg.key.key_information.pairwise_key) { + // This is mismatch between KMP ID indicating 802.11/GKH and key type + return GKH_MESSAGE_UNKNOWN; + } + + uint8_t key_mask = sec_prot_lib_key_mask_get(eapol_pdu); + + switch (key_mask) { + case KEY_INFO_KEY_MIC | KEY_INFO_SECURED_KEY_FRAME: + // Only accept message from supplicant with expected replay counter + if (eapol_pdu->msg.key.replay_counter == sec_prot_keys_pmk_replay_cnt_get(sec_keys)) { + msg = GKH_MESSAGE_2; + } + break; + default: + break; + } + + return msg; +} + +static int8_t auth_gkh_sec_prot_message_send(sec_prot_t *prot, gkh_sec_prot_msg_e msg) +{ + uint16_t kde_len = 0; + + switch (msg) { + case GKH_MESSAGE_1: + kde_len = KDE_GTK_LEN + KDE_LIFETIME_LEN + KDE_GTKL_LEN; + kde_len = kde_len + 8; // One 64 bit block for AES Key Wrap + kde_len = kde_padded_length_calc(kde_len); + break; + default: + break; + } + + uint8_t *kde_start = ns_dyn_mem_temporary_alloc(kde_len); + + if (!kde_start) { + return -1; + } + + uint8_t *kde_end = kde_start; + + switch (msg) { + case GKH_MESSAGE_1: { + uint8_t gtk_index; + uint8_t *gtk = sec_prot_keys_get_gtk_to_insert(prot->sec_keys->gtks, >k_index); + if (gtk) { + kde_end = kde_gtk_write(kde_end, gtk_index, gtk); + + uint32_t gtk_lifetime = sec_prot_keys_gtk_lifetime_get(prot->sec_keys->gtks, gtk_index); + kde_end = kde_lifetime_write(kde_end, gtk_lifetime); + } + uint8_t gtkl = sec_prot_keys_gtkl_get(prot->sec_keys->gtks); + kde_end = kde_gtkl_write(kde_end, gtkl); + kde_padding_write(kde_end, kde_start + kde_len); + } + break; + default: + break; + } + + eapol_pdu_t eapol_pdu; + uint16_t eapol_pdu_size = eapol_pdu_key_frame_init(&eapol_pdu, kde_len, NULL); + + switch (msg) { + case GKH_MESSAGE_1: + sec_prot_keys_pmk_replay_cnt_increment(prot->sec_keys); + eapol_pdu.msg.key.replay_counter = sec_prot_keys_pmk_replay_cnt_get(prot->sec_keys); + eapol_pdu.msg.key.key_information.key_ack = true; + eapol_pdu.msg.key.key_information.key_mic = true; + eapol_pdu.msg.key.key_information.secured_key_frame = true; + eapol_pdu.msg.key.key_information.encrypted_key_data = true; + eapol_pdu.msg.key.key_length = 0; + break; + default: + break; + } + + uint8_t *eapol_pdu_frame = sec_prot_lib_message_build(prot->sec_keys->ptk, kde_start, kde_len, &eapol_pdu, eapol_pdu_size, prot->header_size); + + ns_dyn_mem_free(kde_start); + + if (eapol_pdu_frame == NULL) { + return -1; + } + + if (prot->send(prot, eapol_pdu_frame, eapol_pdu_size + prot->header_size) < 0) { + return -1; + } + + return 0; +} + +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, &gkh_trickle_params, ticks); +} + +static void auth_gkh_sec_prot_state_machine(sec_prot_t *prot) +{ + gkh_sec_prot_int_t *data = gkh_sec_prot_get(prot); + + // GKH authenticator state machine + switch (sec_prot_state_get(&data->common)) { + case GKH_STATE_INIT: + sec_prot_state_set(prot, &data->common, GKH_STATE_CREATE_REQ); + break; + + // Wait KMP-CREATE.request + case GKH_STATE_CREATE_REQ: + tr_debug("GKH start"); + + prot->timer_start(prot); + + // KMP-CREATE.confirm + prot->create_conf(prot, SEC_RESULT_OK); + + // Sends 4WH Message 1 + auth_gkh_sec_prot_message_send(prot, GKH_MESSAGE_1); + + // Start trickle timer to re-send if no response + sec_prot_timer_trickle_start(&data->common, &gkh_trickle_params); + + sec_prot_state_set(prot, &data->common, GKH_STATE_MESSAGE_2); + break; + + // Wait GKH message 2 + case GKH_STATE_MESSAGE_2: + + if (sec_prot_result_timeout_check(&data->common)) { + // Re-sends GKH Message 1 + auth_gkh_sec_prot_message_send(prot, GKH_MESSAGE_1); + } else { + if (auth_gkh_sec_prot_mic_validate(prot) < 0) { + return; + } + sec_prot_state_set(prot, &data->common, GKH_STATE_FINISH); + } + break; + + case GKH_STATE_FINISH: + tr_debug("GKH finish"); + + // KMP-FINISHED.indication, + prot->finished_ind(prot, sec_prot_result_get(&data->common), 0); + + sec_prot_state_set(prot, &data->common, GKH_STATE_FINISHED); + break; + + case GKH_STATE_FINISHED: + prot->timer_stop(prot); + prot->finished(prot); + break; + + default: + break; + } +} + +static int8_t auth_gkh_sec_prot_mic_validate(sec_prot_t *prot) +{ + gkh_sec_prot_int_t *data = gkh_sec_prot_get(prot); + return sec_prot_lib_mic_validate(prot->sec_keys->ptk, data->recv_eapol_pdu.msg.key.key_mic, data->recv_pdu, data->recv_size); +} + +#endif /* HAVE_WS */ + diff --git a/source/Security/protocols/gkh_sec_prot/auth_gkh_sec_prot.h b/source/Security/protocols/gkh_sec_prot/auth_gkh_sec_prot.h new file mode 100644 index 0000000000..2ec9829bd0 --- /dev/null +++ b/source/Security/protocols/gkh_sec_prot/auth_gkh_sec_prot.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2018-2019, 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 AUTH_GKH_SEC_PROT_H_ +#define AUTH_GKH_SEC_PROT_H_ + +/** + * auth_gkh_sec_prot_register register authenticator GKH protocol to KMP service + * + * \param service KMP service + * + * \return < 0 failure + * \return >= 0 success + */ +int8_t auth_gkh_sec_prot_register(kmp_service_t *service); + +#endif /* AUTH_GKH_SEC_PROT_H_ */ diff --git a/source/Security/protocols/gkh_sec_prot/supp_gkh_sec_prot.c b/source/Security/protocols/gkh_sec_prot/supp_gkh_sec_prot.c new file mode 100644 index 0000000000..5fd7a98d17 --- /dev/null +++ b/source/Security/protocols/gkh_sec_prot/supp_gkh_sec_prot.c @@ -0,0 +1,319 @@ +/* + * Copyright (c) 2018-2019, Arm Limited and affiliates. + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "nsconfig.h" +#include +#include "ns_types.h" +#include "ns_list.h" +#include "ns_trace.h" +#include "nsdynmemLIB.h" +#include "fhss_config.h" +#include "NWK_INTERFACE/Include/protocol.h" +#include "6LoWPAN/ws/ws_config.h" +#include "Security/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/gkh_sec_prot/supp_gkh_sec_prot.h" + +#ifdef HAVE_WS + +#define TRACE_GROUP "sgkh" + +typedef enum { + GKH_STATE_INIT = SEC_STATE_INIT, + GKH_STATE_CREATE_RESP = SEC_STATE_CREATE_RESP, + GKH_STATE_CREATE_IND = SEC_STATE_CREATE_IND, + GKH_STATE_MESSAGE_1 = SEC_STATE_FIRST, + GKH_STATE_FINISH = SEC_STATE_FINISH, + GKH_STATE_FINISHED = SEC_STATE_FINISHED +} gkh_sec_prot_state_e; + +typedef enum { + GKH_MESSAGE_UNKNOWN = 0, + GKH_MESSAGE_1, + GKH_MESSAGE_2 +} gkh_sec_prot_msg_e; + +typedef struct { + sec_prot_common_t common; /**< Common data */ + eapol_pdu_t recv_eapol_pdu; /**< Received EAPOL PDU */ + void *recv_pdu; /**< Received pdu */ + uint16_t recv_size; /**< Received pdu size */ +} gkh_sec_prot_int_t; + +static const trickle_params_t gkh_trickle_params = { + .Imin = 50, /* 5000ms; ticks are 100ms */ + .Imax = 150, /* 15000ms */ + .k = 0, /* infinity - no consistency checking */ + .TimerExpirations = 4 +}; + +static uint16_t supp_gkh_sec_prot_size(void); +static int8_t supp_gkh_sec_prot_init(sec_prot_t *prot); + +static void supp_gkh_sec_prot_create_response(sec_prot_t *prot, sec_prot_result_e result); +static void supp_gkh_sec_prot_delete(sec_prot_t *prot); +static int8_t supp_gkh_sec_prot_receive(sec_prot_t *prot, void *pdu, uint16_t size); +static gkh_sec_prot_msg_e supp_gkh_sec_prot_message_get(eapol_pdu_t *eapol_pdu, sec_prot_keys_t *sec_keys); +static void supp_gkh_sec_prot_state_machine(sec_prot_t *prot); + +static int8_t supp_gkh_sec_prot_message_send(sec_prot_t *prot, gkh_sec_prot_msg_e msg); +static void supp_gkh_sec_prot_timer_timeout(sec_prot_t *prot, uint16_t ticks); +static int8_t supp_gkh_sec_prot_mic_validate(sec_prot_t *prot); +static void supp_gkh_sec_prot_security_replay_counter_update(sec_prot_t *prot); +static int8_t supp_gkh_kde_handle(sec_prot_t *prot); + +#define gkh_sec_prot_get(prot) (gkh_sec_prot_int_t *) &prot->data + +int8_t supp_gkh_sec_prot_register(kmp_service_t *service) +{ + if (!service) { + return -1; + } + + if (kmp_service_sec_protocol_register(service, IEEE_802_11_GKH, supp_gkh_sec_prot_size, supp_gkh_sec_prot_init) < 0) { + return -1; + } + + return 0; +} + +static uint16_t supp_gkh_sec_prot_size(void) +{ + return sizeof(gkh_sec_prot_int_t); +} + +static int8_t supp_gkh_sec_prot_init(sec_prot_t *prot) +{ + prot->create_req = 0; + prot->create_resp = supp_gkh_sec_prot_create_response; + prot->receive = supp_gkh_sec_prot_receive; + prot->delete = supp_gkh_sec_prot_delete; + prot->state_machine = supp_gkh_sec_prot_state_machine; + prot->timer_timeout = supp_gkh_sec_prot_timer_timeout; + + gkh_sec_prot_int_t *data = gkh_sec_prot_get(prot); + sec_prot_init(&data->common); + sec_prot_state_set(prot, &data->common, GKH_STATE_INIT); + + return 0; +} + +static void supp_gkh_sec_prot_delete(sec_prot_t *prot) +{ + // No op at the moment + (void) prot; +} + +static void supp_gkh_sec_prot_create_response(sec_prot_t *prot, sec_prot_result_e result) +{ + gkh_sec_prot_int_t *data = gkh_sec_prot_get(prot); + + // Call state machine + sec_prot_result_set(&data->common, result); + prot->state_machine_call(prot); +} + +static int8_t supp_gkh_sec_prot_receive(sec_prot_t *prot, void *pdu, uint16_t size) +{ + gkh_sec_prot_int_t *data = gkh_sec_prot_get(prot); + int8_t ret_val = -1; + + // Decoding is successful + if (eapol_parse_pdu_header(pdu, size, &data->recv_eapol_pdu)) { + // Get message + if (supp_gkh_sec_prot_message_get(&data->recv_eapol_pdu, prot->sec_keys) != GKH_MESSAGE_UNKNOWN) { + // Call state machine + data->recv_pdu = pdu; + data->recv_size = size; + prot->state_machine(prot); + } + ret_val = 0; + } + + memset(&data->recv_eapol_pdu, 0, sizeof(eapol_pdu_t)); + data->recv_pdu = 0; + data->recv_size = 0; + + return ret_val; +} + +static gkh_sec_prot_msg_e supp_gkh_sec_prot_message_get(eapol_pdu_t *eapol_pdu, sec_prot_keys_t *sec_keys) +{ + gkh_sec_prot_msg_e msg = GKH_MESSAGE_UNKNOWN; + + if (eapol_pdu->msg.key.key_information.pairwise_key) { + // This is mismatch between KMP ID indicating 802.11/GKH and key type + return GKH_MESSAGE_UNKNOWN; + } + + uint8_t key_mask = sec_prot_lib_key_mask_get(eapol_pdu); + + switch (key_mask) { + case KEY_INFO_KEY_ACK | KEY_INFO_KEY_MIC | KEY_INFO_SECURED_KEY_FRAME: + // Must have valid replay counter + if (eapol_pdu->msg.key.replay_counter > sec_prot_keys_pmk_replay_cnt_get(sec_keys)) { + if (eapol_pdu->msg.key.key_information.encrypted_key_data) { + // This should include the GTK KDE, Lifetime KDE and GTKL KDE. + msg = GKH_MESSAGE_1; + } + } + break; + default: + break; + } + + return msg; +} + +static int8_t supp_gkh_sec_prot_message_send(sec_prot_t *prot, gkh_sec_prot_msg_e msg) +{ + eapol_pdu_t eapol_pdu; + uint16_t eapol_pdu_size = eapol_pdu_key_frame_init(&eapol_pdu, 0, NULL); + + switch (msg) { + case GKH_MESSAGE_2: + eapol_pdu.msg.key.replay_counter = sec_prot_keys_pmk_replay_cnt_get(prot->sec_keys); + eapol_pdu.msg.key.key_information.key_mic = true; + eapol_pdu.msg.key.key_information.secured_key_frame = true; + eapol_pdu.msg.key.key_length = 0; + break; + default: + break; + } + + uint8_t *eapol_pdu_frame = sec_prot_lib_message_build(prot->sec_keys->ptk, NULL, 0, &eapol_pdu, eapol_pdu_size, prot->header_size); + + if (eapol_pdu_frame == NULL) { + return -1; + } + + if (prot->send(prot, eapol_pdu_frame, eapol_pdu_size + prot->header_size) < 0) { + return -1; + } + + return 0; +} + +static void supp_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, &gkh_trickle_params, ticks); +} + +static void supp_gkh_sec_prot_state_machine(sec_prot_t *prot) +{ + gkh_sec_prot_int_t *data = gkh_sec_prot_get(prot); + + // GKH supplicant state machine + switch (sec_prot_state_get(&data->common)) { + case GKH_STATE_INIT: + sec_prot_state_set(prot, &data->common, GKH_STATE_MESSAGE_1); + break; + + // Wait GKH message 1 (starts handshake on supplicant) + case GKH_STATE_MESSAGE_1: + if (supp_gkh_sec_prot_mic_validate(prot) < 0) { + return; + } + + if (supp_gkh_kde_handle(prot) < 0) { + return; + } + + supp_gkh_sec_prot_security_replay_counter_update(prot); + + tr_debug("GKH start"); + + prot->timer_start(prot); + + // Send KMP-CREATE.indication + prot->create_ind(prot); + sec_prot_state_set(prot, &data->common, GKH_STATE_CREATE_RESP); + break; + + // Wait KMP-CREATE.response + case GKH_STATE_CREATE_RESP: + if (sec_prot_result_ok_check(&data->common)) { + // Send GKH message 2 + supp_gkh_sec_prot_message_send(prot, GKH_MESSAGE_2); + sec_prot_state_set(prot, &data->common, GKH_STATE_FINISH); + } else { + // Ready to be deleted + sec_prot_state_set(prot, &data->common, GKH_STATE_FINISHED); + } + break; + + case GKH_STATE_FINISH: + tr_debug("GKH finish"); + + // KMP-FINISHED.indication, + prot->finished_ind(prot, sec_prot_result_get(&data->common), prot->sec_keys); + sec_prot_state_set(prot, &data->common, GKH_STATE_FINISHED); + break; + + case GKH_STATE_FINISHED: + prot->timer_stop(prot); + prot->finished(prot); + break; + + default: + break; + } +} + +static int8_t supp_gkh_sec_prot_mic_validate(sec_prot_t *prot) +{ + gkh_sec_prot_int_t *data = gkh_sec_prot_get(prot); + return sec_prot_lib_mic_validate(prot->sec_keys->ptk, data->recv_eapol_pdu.msg.key.key_mic, data->recv_pdu, data->recv_size); +} + +static void supp_gkh_sec_prot_security_replay_counter_update(sec_prot_t *prot) +{ + gkh_sec_prot_int_t *data = gkh_sec_prot_get(prot); + sec_prot_keys_pmk_replay_cnt_set(prot->sec_keys, data->recv_eapol_pdu.msg.key.replay_counter); +} + +static int8_t supp_gkh_kde_handle(sec_prot_t *prot) +{ + gkh_sec_prot_int_t *data = gkh_sec_prot_get(prot); + + uint16_t kde_len; + uint8_t *kde = sec_prot_lib_message_handle(prot->sec_keys->ptk, &kde_len, &data->recv_eapol_pdu); + if (!kde) { + return -1; + } + + // If a valid new GTK value present, insert it + int8_t ret = sec_prot_lib_gtk_read(kde, kde_len, prot->sec_keys->gtks); + + ns_dyn_mem_free(kde); + + if (ret < 0 || sec_prot_keys_gtk_insert_index_get(prot->sec_keys->gtks) < 0) { + return -1; + } else { + return 0; + } +} + +#endif /* HAVE_WS */ + diff --git a/source/Security/protocols/gkh_sec_prot/supp_gkh_sec_prot.h b/source/Security/protocols/gkh_sec_prot/supp_gkh_sec_prot.h new file mode 100644 index 0000000000..a8832db62f --- /dev/null +++ b/source/Security/protocols/gkh_sec_prot/supp_gkh_sec_prot.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2018-2019, 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 SUPP_GKH_SEC_PROT_H_ +#define SUPP_GKH_SEC_PROT_H_ + +/** + * supp_gkh_sec_prot_register register supplicant GKH protocol to KMP service + * + * \param service KMP service + * + * \return < 0 failure + * \return >= 0 success + */ +int8_t supp_gkh_sec_prot_register(kmp_service_t *service); + +#endif /* SUPP_GKH_SEC_PROT_H_ */ diff --git a/source/Security/protocols/key_sec_prot/key_sec_prot.c b/source/Security/protocols/key_sec_prot/key_sec_prot.c new file mode 100644 index 0000000000..4320d44e9c --- /dev/null +++ b/source/Security/protocols/key_sec_prot/key_sec_prot.c @@ -0,0 +1,239 @@ +/* + * Copyright (c) 2016-2019, Arm Limited and affiliates. + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "nsconfig.h" +#include +#include "ns_types.h" +#include "ns_list.h" +#include "ns_trace.h" +#include "nsdynmemLIB.h" +#include "fhss_config.h" +#include "NWK_INTERFACE/Include/protocol.h" +#include "6LoWPAN/ws/ws_config.h" +#include "Security/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/eapol/kde_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/key_sec_prot/key_sec_prot.h" + +#ifdef HAVE_WS + +#define TRACE_GROUP "ksep" + +typedef enum { + KEY_INIT = 0, + KEY_CREATE_REQ, + KEY_CREATE_RESP, + KEY_FINISH, +} key_sec_prot_state_e; + +typedef struct { + key_sec_prot_state_e state; /**< Protocol state machine state */ + sec_prot_result_e result; /**< Result for ongoing negotiation */ +} key_sec_prot_int_t; + +static uint16_t key_sec_prot_size(void); +static int8_t key_sec_prot_init(sec_prot_t *prot); + +static void key_sec_prot_create_request(sec_prot_t *prot, sec_prot_keys_t *sec_keys); +static void key_sec_prot_create_response(sec_prot_t *prot, sec_prot_result_e result); +static void key_sec_prot_delete(sec_prot_t *prot); +static int8_t key_sec_prot_receive(sec_prot_t *prot, void *pdu, uint16_t size); +static void key_sec_prot_state_machine(sec_prot_t *prot); + +#define key_sec_prot_get(prot) (key_sec_prot_int_t *) &prot->data + +int8_t key_sec_prot_register(kmp_service_t *service) +{ + if (!service) { + return -1; + } + + if (kmp_service_sec_protocol_register(service, IEEE_802_1X_MKA_KEY, key_sec_prot_size, key_sec_prot_init) < 0) { + return -1; + } + + if (kmp_service_sec_protocol_register(service, IEEE_802_11_GKH_KEY, key_sec_prot_size, key_sec_prot_init) < 0) { + return -1; + } + + return 0; +} + +static uint16_t key_sec_prot_size(void) +{ + return sizeof(key_sec_prot_int_t); +} + +static int8_t key_sec_prot_init(sec_prot_t *prot) +{ + prot->create_req = key_sec_prot_create_request; + prot->create_resp = key_sec_prot_create_response; + + prot->receive = key_sec_prot_receive; + prot->delete = key_sec_prot_delete; + prot->state_machine = key_sec_prot_state_machine; + + key_sec_prot_int_t *data = key_sec_prot_get(prot); + data->state = KEY_INIT; + data->result = SEC_RESULT_OK; + + return 0; +} + +static void key_sec_prot_delete(sec_prot_t *prot) +{ + // No op at the moment + (void) prot; +} + +static void key_sec_prot_create_request(sec_prot_t *prot, sec_prot_keys_t *sec_keys) +{ + key_sec_prot_int_t *data = key_sec_prot_get(prot); + + uint16_t kde_len = KDE_GTKL_LEN; + + uint8_t *pmk = sec_prot_keys_pmk_get(sec_keys); + if (pmk) { + kde_len += KDE_PMKID_LEN; + } + + uint8_t *ptk = sec_prot_keys_ptk_get(sec_keys); + if (ptk) { + kde_len += KDE_PTKID_LEN; + } + + uint8_t *kde_start = ns_dyn_mem_temporary_alloc(kde_len); + if (!kde_start) { + return; + } + + uint8_t *kde_end = kde_start; + + if (pmk) { + uint8_t pmkid[PMKID_LEN]; + if (sec_prot_lib_pmkid_generate(prot, pmkid, true) >= 0) { + kde_end = kde_pmkid_write(kde_end, pmkid); + } + } + + if (ptk) { + uint8_t ptkid[PTKID_LEN]; + if (sec_prot_lib_ptkid_generate(prot, ptkid, true) >= 0) { + kde_end = kde_ptkid_write(kde_end, ptkid); + } + } + + uint8_t gtkl = sec_prot_keys_gtkl_get(sec_keys->gtks); + kde_end = kde_gtkl_write(kde_end, gtkl); + + kde_len = kde_end - kde_start; + + eapol_pdu_t eapol_pdu; + + uint16_t eapol_pdu_size = eapol_pdu_key_frame_init(&eapol_pdu, kde_len, kde_start); + + uint8_t *eapol_decoded_data = ns_dyn_mem_temporary_alloc(eapol_pdu_size + prot->header_size); // In future fill with data that defines eapol message + + if (!eapol_decoded_data) { + data->result = SEC_RESULT_ERR_NO_MEM; + } else { + //Test Data + eapol_pdu.msg.key.key_information.install = false; + eapol_pdu.msg.key.key_information.pairwise_key = false; + eapol_pdu.msg.key.key_information.request = true; + eapol_pdu.msg.key.replay_counter = 10; + eapol_pdu.msg.key.key_length = 32; + eapol_write_pdu_frame(eapol_decoded_data + prot->header_size, &eapol_pdu); + + if (prot->send(prot, eapol_decoded_data, eapol_pdu_size + prot->header_size) < 0) { + data->result = SEC_RESULT_ERR_NO_MEM; + } + } + + ns_dyn_mem_free(kde_start); + + data->state = KEY_CREATE_REQ; + prot->state_machine_call(prot); +} + +static void key_sec_prot_create_response(sec_prot_t *prot, sec_prot_result_e result) +{ + key_sec_prot_int_t *data = key_sec_prot_get(prot); + data->state = KEY_CREATE_RESP; + data->result = result; + prot->state_machine_call(prot); +} + +static int8_t key_sec_prot_receive(sec_prot_t *prot, void *pdu, uint16_t size) +{ + eapol_pdu_t eapol_pdu; + // Decoding is successful + if (eapol_parse_pdu_header(pdu, size, &eapol_pdu)) { + prot->create_ind(prot); + return 0; + } else { + // No error handling yet, indicate just that ready to be deleted + prot->finished(prot); + return -1; + } +} + +static void key_sec_prot_state_machine(sec_prot_t *prot) +{ + key_sec_prot_int_t *data = key_sec_prot_get(prot); + + // Mixes currently supplicant and authenticator states + switch (data->state) { + case KEY_INIT: + // empty + break; + case KEY_CREATE_REQ: + tr_debug("initial EAPOL-Key send"); + + // KMP-CREATE.confirm + prot->create_conf(prot, data->result); + + if (data->result == SEC_RESULT_OK) { + // KMP-FINISHED.indication, no meaning for eapol-key, just completes transfer + prot->finished_ind(prot, SEC_RESULT_OK, 0); + } + // Ready to be deleted + prot->finished(prot); + break; + case KEY_CREATE_RESP: + tr_debug("initial EAPOL-Key receive"); + + if (data->result == SEC_RESULT_OK) { + // KMP-FINISHED.indication, no meaning for eapol-key, just completes transfer + prot->finished_ind(prot, SEC_RESULT_OK, 0); + } + // Ready to be deleted + prot->finished(prot); + break; + default: + break; + } +} + +#endif /* HAVE_WS */ + diff --git a/source/Security/protocols/key_sec_prot/key_sec_prot.h b/source/Security/protocols/key_sec_prot/key_sec_prot.h new file mode 100644 index 0000000000..9cb00897f9 --- /dev/null +++ b/source/Security/protocols/key_sec_prot/key_sec_prot.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2016-2019, 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 KEY_SEC_PROT_H_ +#define KEY_SEC_PROT_H_ + +/* + * EAPOL-Key security protocol. Protocol is used for sending and receiving + * initial EAPOL-Key message that is used to start the supplicant + * authentication. Specified in Wi-SUN FANWG-FANTPS. + * + */ + +/** + * key_sec_prot_register register EAPOL-Key protocol to KMP service + * + * \param service KMP service + * + * \return < 0 failure + * \return >= 0 success + */ +int8_t key_sec_prot_register(kmp_service_t *service); + +#endif /* KEY_SEC_PROT_H_ */ diff --git a/source/Security/protocols/sec_prot.h b/source/Security/protocols/sec_prot.h new file mode 100644 index 0000000000..f1dc886200 --- /dev/null +++ b/source/Security/protocols/sec_prot.h @@ -0,0 +1,241 @@ +/* + * Copyright (c) 2016-2019, 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 SEC_PROT_H_ +#define SEC_PROT_H_ + +/* + * Interface between KMP API and key management security protocols. Interface + * provides abstraction for different security protocols for KMP API module. + * + * For security protocols it provides access to network, timing, callback + * security keys and network address services. + * + */ + +typedef enum { + SEC_RESULT_OK = 0, + SEC_RESULT_ERR_NO_MEM = -1, + SEC_RESULT_TIMEOUT = -2, + SEC_RESULT_ERROR = -3, + SEC_RESULT_CONF_ERROR = -4 +} sec_prot_result_e; + +typedef enum { + SEC_STATE_INIT = 0, + SEC_STATE_CREATE_REQ, + SEC_STATE_CREATE_RESP, + SEC_STATE_CREATE_IND, + SEC_STATE_FINISH, + SEC_STATE_FINISHED, + SEC_STATE_FIRST +} sec_prot_state_e; + +typedef enum { + SEC_PROT_TYPE_EAP_TLS = 0, + SEC_PROT_TYPE_TLS +} sec_prot_type_e; + +/** + * sec_prot_create_request KMP-CREATE.request to security protocol + * + * \param prot protocol + * \param sec_keys security keys + * + */ +typedef void sec_prot_create_request(sec_prot_t *prot, sec_prot_keys_t *sec_keys); + +/** + * sec_prot_create_response KMP-CREATE.response from security protocol + * + * \param prot protocol + * \param result result + * + */ +typedef void sec_prot_create_response(sec_prot_t *prot, sec_prot_result_e result); + +/** + * sec_prot_create_confirm KMP-CREATE.confirm from security protocol + * + * \param prot protocol + * \param result result + * + */ +typedef void sec_prot_create_confirm(sec_prot_t *prot, sec_prot_result_e result); + +/** + * sec_prot_create_indication KMP-CREATE.indication from security protocol + * + * \param prot protocol + * + */ +typedef void sec_prot_create_indication(sec_prot_t *prot); + +/** + * sec_prot_finished_indication KMP-FINISHED.indication from security protocol + * + * \param prot protocol + * \param result result + * \param sec_keys security keys + * + */ +typedef void sec_prot_finished_indication(sec_prot_t *prot, sec_prot_result_e result, sec_prot_keys_t *sec_keys); + +/** + * sec_prot_finished Security protocol has finished and is ready for delete + * + * \param prot protocol + * + */ +typedef void sec_prot_finished(sec_prot_t *prot); + +/** + * sec_prot_finished_send Security protocol finished send + * + * \param prot protocol + * + */ +typedef void sec_prot_finished_send(sec_prot_t *prot); + +/** + * sec_prot_receive receive a message + * + * \param prot protocol + * \param pdu pdu + * \param size pdu size + * + * \return < 0 failure + * \return >= 0 success + * + */ +typedef int8_t sec_prot_receive(sec_prot_t *prot, void *pdu, uint16_t size); + +/** + * sec_prot_send send a message + * + * \param prot protocol + * \param pdu pdu + * \param size pdu size + * + * \return < 0 failure + * \return >= 0 success + * + */ +typedef int8_t sec_prot_send(sec_prot_t *prot, void *pdu, uint16_t size); + +/** + * sec_prot_delete delete the protocol data + * + * \param prot protocol + * + */ +typedef void sec_prot_delete(sec_prot_t *prot); + +/** + * sec_prot_state_machine protocol state machine + * + * \param prot protocol + * + */ +typedef void sec_prot_state_machine(sec_prot_t *prot); + +/** + * sec_prot_state_machine_call call protocol state machine + * + * \param prot protocol + * + */ +typedef void sec_prot_state_machine_call(sec_prot_t *prot); + +/** + * sec_prot_timer_start start timer + * + * \param prot protocol + * + */ +typedef void sec_prot_timer_start(sec_prot_t *prot); + +/** + * sec_prot_timer_stop stop timer + * + * \param prot protocol + * + */ +typedef void sec_prot_timer_stop(sec_prot_t *prot); + +/** + * sec_prot_timer_timeout timer timeout + * + * \param prot protocol + * \param ticks timer ticks + * + */ +typedef void sec_prot_timer_timeout(sec_prot_t *prot, uint16_t ticks); + +/** + * sec_prot_eui64_addr_get gets EUI-64 addresses + * + * \param prot protocol + * \param local_eui64 local EUI-64 + * \param remote_eui64 remote EUI-64 + * + */ +typedef void sec_prot_eui64_addr_get(sec_prot_t *prot, uint8_t *local_eui64, uint8_t *remote_eui64); + +/** + * sec_prot_by_type_get gets security protocol + * + * \param prot protocol + * \param type security protocol type + * + * \return security protocol or NULL + * + */ +typedef sec_prot_t *sec_prot_by_type_get(sec_prot_t *prot, uint8_t type); + +// Security protocol data +struct sec_prot_s { + sec_prot_create_request *create_req; /**< Create request */ + sec_prot_create_response *create_resp; /**< Create response */ + + sec_prot_create_confirm *create_conf; /**< Create confirm */ + sec_prot_create_indication *create_ind; /**< Create indication */ + sec_prot_finished_indication *finished_ind; /**< Finished indication */ + sec_prot_finished *finished; /**< Finished i.e. ready to be deleted */ + sec_prot_finished_send *finished_send; /**< Send finished */ + + sec_prot_send *send; /**< Protocol send */ + sec_prot_receive *receive; /**< Protocol receive */ + + sec_prot_delete *delete; /**< Protocol delete */ + + sec_prot_state_machine_call *state_machine_call; /**< Call state machine */ + sec_prot_state_machine *state_machine; /**< Protocol state machine */ + + sec_prot_timer_start *timer_start; /**< Start timer */ + sec_prot_timer_stop *timer_stop; /**< Stop timer */ + sec_prot_timer_timeout *timer_timeout; /**< Timer timeout */ + + sec_prot_eui64_addr_get *addr_get; /**< Gets EUI-64 addresses */ + sec_prot_by_type_get *type_get; /**< Gets security protocol by type */ + + sec_prot_keys_t *sec_keys; /**< Security keys storage pointer */ + uint8_t header_size; /**< Header size */ + uint8_t data; /**< Protocol internal data */ +}; + +#endif /* SEC_PROT_H_ */ diff --git a/source/Security/protocols/sec_prot_certs.c b/source/Security/protocols/sec_prot_certs.c new file mode 100644 index 0000000000..3414fb272c --- /dev/null +++ b/source/Security/protocols/sec_prot_certs.c @@ -0,0 +1,179 @@ +/* + * Copyright (c) 2016-2019, Arm Limited and affiliates. + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "nsconfig.h" +#include +#include "ns_types.h" +#include "ns_list.h" +#include "ns_trace.h" +#include "nsdynmemLIB.h" +#include "NWK_INTERFACE/Include/protocol.h" +#include "Common_Protocols/ipv6_constants.h" +#include "socket_api.h" +#include "6LoWPAN/ws/ws_config.h" +#include "Security/protocols/sec_prot_certs.h" +#include "Security/protocols/sec_prot_keys.h" + +#ifdef HAVE_WS + +#define TRACE_GROUP "spce" + +int8_t sec_prot_certs_init(sec_prot_certs_t *certs) +{ + if (!certs) { + return -1; + } + + sec_prot_certs_chain_entry_init(&certs->own_cert_chain); + ns_list_init(&certs->trusted_cert_chain_list); + ns_list_init(&certs->cert_revocat_lists); + + return 0; +} + +void sec_prot_certs_delete(sec_prot_certs_t *certs) +{ + if (!certs) { + return; + } + + sec_prot_certs_chain_entry_init(&certs->own_cert_chain); + sec_prot_certs_chain_list_delete(&certs->trusted_cert_chain_list); + sec_prot_certs_revocat_lists_delete(&certs->cert_revocat_lists); +} + +cert_chain_entry_t *sec_prot_certs_chain_entry_create(void) +{ + cert_chain_entry_t *entry = ns_dyn_mem_alloc(sizeof(cert_chain_entry_t)); + if (!entry) { + return NULL; + } + sec_prot_certs_chain_entry_init(entry); + return entry; +} + +void sec_prot_certs_chain_entry_init(cert_chain_entry_t *entry) +{ + memset(entry, 0, sizeof(cert_chain_entry_t)); +} + +int8_t sec_prot_certs_cert_set(cert_chain_entry_t *entry, uint8_t index, uint8_t *cert, uint16_t cert_len) +{ + if (!entry || index >= SEC_PROT_CERT_CHAIN_DEPTH) { + return -1; + } + + entry->cert[index] = cert; + entry->cert_len[index] = cert_len; + + return 0; +} + +uint8_t *sec_prot_certs_cert_get(const cert_chain_entry_t *entry, uint8_t index, uint16_t *cert_len) +{ + if (!entry || index >= SEC_PROT_CERT_CHAIN_DEPTH || !entry->cert[index]) { + return NULL; + } + + *cert_len = entry->cert_len[index]; + return entry->cert[index]; +} + +int8_t sec_prot_certs_priv_key_set(cert_chain_entry_t *entry, uint8_t *key, uint8_t key_len) +{ + if (!entry) { + return -1; + } + + entry->key = key; + entry->key_len = key_len; + + return 0; +} + +uint8_t *sec_prot_certs_priv_key_get(const cert_chain_entry_t *entry, uint8_t *key_len) +{ + if (!entry) { + return NULL; + } + *key_len = entry->key_len; + return entry->key; +} + +void sec_prot_certs_chain_list_add(cert_chain_list_t *cert_chain_list, cert_chain_entry_t *entry) +{ + ns_list_add_to_end(cert_chain_list, entry); +} + +void sec_prot_certs_chain_list_delete(cert_chain_list_t *chain_list) +{ + ns_list_foreach_safe(cert_chain_entry_t, entry, chain_list) { + ns_list_remove(chain_list, entry); + ns_dyn_mem_free(entry); + } +} + +cert_revocat_list_entry_t *sec_prot_certs_revocat_list_entry_create(void) +{ + cert_revocat_list_entry_t *entry = ns_dyn_mem_alloc(sizeof(cert_revocat_list_entry_t)); + if (!entry) { + return NULL; + } + sec_prot_certs_revocat_list_entry_init(entry); + return entry; +} + +void sec_prot_certs_revocat_list_entry_init(cert_revocat_list_entry_t *entry) +{ + memset(entry, 0, sizeof(cert_revocat_list_entry_t)); +} + +int8_t sec_prot_certs_revocat_list_set(cert_revocat_list_entry_t *entry, uint8_t *crl, uint16_t crl_len) +{ + if (!entry) { + return -1; + } + + entry->crl = crl; + entry->crl_len = crl_len; + + return 0; +} + +uint8_t *sec_prot_certs_revocat_list_get(const cert_revocat_list_entry_t *entry, uint16_t *crl_len) +{ + if (!entry) { + return NULL; + } + *crl_len = entry->crl_len; + return entry->crl; +} + +void sec_prot_certs_revocat_lists_add(cert_revocat_lists_t *cert_revocat_lists, cert_revocat_list_entry_t *entry) +{ + ns_list_add_to_end(cert_revocat_lists, entry); +} + +void sec_prot_certs_revocat_lists_delete(cert_revocat_lists_t *cert_revocat_lists) +{ + ns_list_foreach_safe(cert_revocat_list_entry_t, entry, cert_revocat_lists) { + ns_list_remove(cert_revocat_lists, entry); + ns_dyn_mem_free(entry); + } +} + +#endif /* HAVE_WS */ diff --git a/source/Security/protocols/sec_prot_certs.h b/source/Security/protocols/sec_prot_certs.h new file mode 100644 index 0000000000..eb53ec5248 --- /dev/null +++ b/source/Security/protocols/sec_prot_certs.h @@ -0,0 +1,207 @@ +/* + * Copyright (c) 2016-2019, 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 SEC_PROT_CERTS_H_ +#define SEC_PROT_CERTS_H_ + +/* + * Security protocols certificate interface. This is used by security protocols to + * access certificate information. + * + * Own certificate chain contains the certificate chain that is sent on TLS handshake + * to remote end. Typically this is one certificate long, and the certificate chains + * to root CA certificate or to intermediate certificate known to other end. It is + * also possible to send chain longer than one certificate. + * + * Key on own certificate chain must be the private key of the certificate used on + * TLS handshake. + * + * Trusted certificate chains contains the root CA certificates and intermediate + * certificates chains that are used to validate remote certificates. + * + */ + +#define SEC_PROT_CERT_CHAIN_DEPTH 4 + +typedef struct { + uint8_t *cert[SEC_PROT_CERT_CHAIN_DEPTH]; /**< Certificate chain (from bottom up) */ + uint16_t cert_len[SEC_PROT_CERT_CHAIN_DEPTH]; /**< Certificate chain length */ + uint8_t *key; /**< Private key */ + uint8_t key_len; /**< Private key length*/ + ns_list_link_t link; /**< Link */ +} cert_chain_entry_t; + +typedef struct { + uint8_t *crl; /**< Certificate Revocation List */ + uint16_t crl_len; /**< Certificate Revocation List length */ + ns_list_link_t link; /**< Link */ +} cert_revocat_list_entry_t; + +typedef NS_LIST_HEAD(cert_chain_entry_t, link) cert_chain_list_t; +typedef NS_LIST_HEAD(cert_revocat_list_entry_t, link) cert_revocat_lists_t; + +typedef struct { + cert_chain_entry_t own_cert_chain; /**< Own certificate chain */ + cert_chain_list_t trusted_cert_chain_list; /**< Trusted certificate chain lists */ + cert_revocat_lists_t cert_revocat_lists; /**< Certificate Revocation Lists */ +} sec_prot_certs_t; + +/** + * sec_prot_certs_init initialize certificate information + * + * \param certs certificate information + * + * \return < 0 failure + * \return >= 0 success + */ +int8_t sec_prot_certs_init(sec_prot_certs_t *certs); + +/** + * sec_prot_certs_delete delete certificate information + * + * \param certs certificate information + * + */ +void sec_prot_certs_delete(sec_prot_certs_t *certs); + +/** + * sec_prot_certs_chain_entry_create allocate memory for certificate chain entry + * + * \return certificate chain entry or NULL + */ +cert_chain_entry_t *sec_prot_certs_chain_entry_create(void); + +/** + * sec_prot_certs_chain_entry_init initialize certificate chain entry + * + * \param entry certificate chain entry + */ +void sec_prot_certs_chain_entry_init(cert_chain_entry_t *entry); + +/** + * sec_prot_certs_cert_set set certificate to chain entry + * + * \param entry certificate chain entry + * \param index index for certificate + * \param cert certificate + * \param cert_len certificate length + * + * \return < 0 failure + * \return >= 0 success + */ +int8_t sec_prot_certs_cert_set(cert_chain_entry_t *entry, uint8_t index, uint8_t *cert, uint16_t cert_len); + +/** + * sec_prot_certs_cert_get get certificate from chain entry + * + * \param entry certificate chain entry + * \param index index for certificate + * \param cert_len certificate length + * + * \return pointer to certificate or NULL + */ +uint8_t *sec_prot_certs_cert_get(const cert_chain_entry_t *entry, uint8_t index, uint16_t *cert_len); + +/** + * sec_prot_certs_priv_key_set set certificate (chain) private key + * + * \param entry certificate chain entry + * \param key key + * \param key_len key length + * + * \return < 0 failure + * \return >= 0 success + */ +int8_t sec_prot_certs_priv_key_set(cert_chain_entry_t *entry, uint8_t *key, uint8_t key_len); + +/** + * sec_prot_certs_priv_key_get get certificate (chain) private key + * + * \param entry certificate chain entry + * \param key_len key length + * + * \return pointer to key or NULL + */ +uint8_t *sec_prot_certs_priv_key_get(const cert_chain_entry_t *entry, uint8_t *key_len); + +/** + * sec_prot_certs_chain_list_add add certificate chain entry to certificate chain list + * + * \param cert_chain_list certificate chain entry list + * \param entry certificate chain entry + */ +void sec_prot_certs_chain_list_add(cert_chain_list_t *cert_chain_list, cert_chain_entry_t *entry); + +/** + * sec_prot_certs_chain_list_delete delete certificate chain list + * + * \param cert_chain_list certificate chain entry list + */ +void sec_prot_certs_chain_list_delete(cert_chain_list_t *chain_list); + +/** + * sec_prot_certs_revocat_list_entry_create allocate memory for certificate revocation list entry + * + * \return certificate revocation list entry or NULL + */ +cert_revocat_list_entry_t *sec_prot_certs_revocat_list_entry_create(void); + +/** + * sec_prot_certs_revocat_list_entry_init initialize certificate revocation list entry + * + * \param entry certificate revocation list entry + */ +void sec_prot_certs_revocat_list_entry_init(cert_revocat_list_entry_t *entry); + +/** + * sec_prot_certs_revocat_list_set set certificate revocation list to list entry + * + * \param entry certificate revocation list entry + * \param crl certificate revocation list + * \param crl_len certificate revocation list length + * + * \return < 0 failure + * \return >= 0 success + */ +int8_t sec_prot_certs_revocat_list_set(cert_revocat_list_entry_t *entry, uint8_t *crl, uint16_t crl_len); + +/** + * sec_prot_certs_revocat_list_set set certificate revocation list from list entry + * + * \param entry certificate revocation list entry + * \param crl_len certificate revocation list length + * + * \return pointer to crl or NULL + */ +uint8_t *sec_prot_certs_revocat_list_get(const cert_revocat_list_entry_t *entry, uint16_t *crl_len); + +/** + * sec_prot_certs_revocat_lists_add add certificate chain entry to certificate chain list + * + * \param cert_revocat_lists certificate revocation lists + * \param entry certificate revocation list entry + */ +void sec_prot_certs_revocat_lists_add(cert_revocat_lists_t *cert_revocat_lists, cert_revocat_list_entry_t *entry); + +/** + * sec_prot_certs_chain_list_delete delete certificate chain list + * + * \param cert_revocat_lists certificate revocation lists + */ +void sec_prot_certs_revocat_lists_delete(cert_revocat_lists_t *cert_revocat_lists); + +#endif /* SEC_PROT_CERTS_H_ */ diff --git a/source/Security/protocols/sec_prot_keys.c b/source/Security/protocols/sec_prot_keys.c new file mode 100644 index 0000000000..ce7a8dc61e --- /dev/null +++ b/source/Security/protocols/sec_prot_keys.c @@ -0,0 +1,305 @@ +/* + * Copyright (c) 2016-2019, Arm Limited and affiliates. + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "nsconfig.h" +#include +#include "ns_types.h" +#include "ns_list.h" +#include "ns_trace.h" +#include "nsdynmemLIB.h" +#include "NWK_INTERFACE/Include/protocol.h" +#include "Common_Protocols/ipv6_constants.h" +#include "socket_api.h" +#include "6LoWPAN/ws/ws_config.h" +#include "Security/protocols/sec_prot_certs.h" +#include "Security/protocols/sec_prot_keys.h" + +#ifdef HAVE_WS + +#define TRACE_GROUP "spke" + +sec_prot_keys_t *sec_prot_keys_create(sec_prot_gtk_keys_t *gtks, const sec_prot_certs_t *certs) +{ + sec_prot_keys_t *sec_keys = ns_dyn_mem_alloc(sizeof(sec_prot_keys_t)); + if (!sec_keys) { + return NULL; + } + + sec_prot_keys_init(sec_keys, gtks, certs); + + return sec_keys; +} + +void sec_prot_keys_init(sec_prot_keys_t *sec_keys, sec_prot_gtk_keys_t *gtks, const sec_prot_certs_t *certs) +{ + memset(sec_keys, 0, sizeof(sec_prot_keys_t)); + sec_keys->pmk_key_replay_cnt = 0; + sec_keys->gtks = gtks; + sec_keys->certs = certs; + sec_keys->pmk_set = false; + sec_keys->ptk_set = false; + sec_keys->updated = false; + sec_keys->ptk_eui_64_set = false; +} + +void sec_prot_keys_delete(sec_prot_keys_t *sec_keys) +{ + ns_dyn_mem_free(sec_keys); +} + +sec_prot_gtk_keys_t *sec_prot_keys_gtks_create(void) +{ + sec_prot_gtk_keys_t *gtks = ns_dyn_mem_alloc(sizeof(sec_prot_gtk_keys_t)); + if (!gtks) { + return NULL; + } + + sec_prot_keys_gtks_init(gtks); + + return gtks; +} + +void sec_prot_keys_gtks_init(sec_prot_gtk_keys_t *gtks) +{ + memset(gtks, 0, sizeof(sec_prot_gtk_keys_t)); + gtks->gtk_set_index = -1; + gtks->updated = false; +} + +void sec_prot_keys_gtks_delete(sec_prot_gtk_keys_t *gtks) +{ + ns_dyn_mem_free(gtks); +} + +void sec_prot_keys_pmk_write(sec_prot_keys_t *sec_keys, uint8_t *pmk) +{ + memcpy(sec_keys->pmk, pmk, PMK_LEN); + sec_keys->pmk_key_replay_cnt = 0; + sec_keys->pmk_set = true; + sec_keys->updated = true; +} + +uint8_t *sec_prot_keys_pmk_get(sec_prot_keys_t *sec_keys) +{ + if (!sec_keys->pmk_set) { + return NULL; + } + + return sec_keys->pmk; +} + +uint64_t sec_prot_keys_pmk_replay_cnt_get(sec_prot_keys_t *sec_keys) +{ + return sec_keys->pmk_key_replay_cnt; +} + +void sec_prot_keys_pmk_replay_cnt_set(sec_prot_keys_t *sec_keys, uint64_t counter) +{ + sec_keys->pmk_key_replay_cnt = counter; +} + +void sec_prot_keys_pmk_replay_cnt_increment(sec_prot_keys_t *sec_keys) +{ + sec_keys->pmk_key_replay_cnt++; +} + +void sec_prot_keys_ptk_write(sec_prot_keys_t *sec_keys, uint8_t *ptk) +{ + memcpy(sec_keys->ptk, ptk, PTK_LEN); + sec_keys->ptk_set = true; + sec_keys->updated = true; +} + +uint8_t *sec_prot_keys_ptk_get(sec_prot_keys_t *sec_keys) +{ + if (!sec_keys->ptk_set) { + return NULL; + } + + return sec_keys->ptk; +} + +void sec_prot_keys_ptk_eui_64_set(sec_prot_keys_t *sec_keys, uint8_t *eui_64) +{ + sec_keys->ptk_eui_64 = eui_64; +} + +void sec_prot_keys_ptk_eui_64_write(sec_prot_keys_t *sec_keys, uint8_t *eui_64) +{ + if (sec_keys->ptk_eui_64) { + memcpy(sec_keys->ptk_eui_64, eui_64, 8); + sec_keys->ptk_eui_64_set = true; + sec_keys->updated = true; + } +} + +uint8_t *sec_prot_keys_ptk_eui_64_get(sec_prot_keys_t *sec_keys) +{ + if (!sec_keys->ptk_eui_64 || !sec_keys->ptk_eui_64_set) { + return NULL; + } + + return sec_keys->ptk_eui_64; +} + +bool sec_prot_keys_are_updated(sec_prot_keys_t *sec_keys) +{ + return sec_keys->updated; +} + +void sec_prot_keys_updated_reset(sec_prot_keys_t *sec_keys) +{ + sec_keys->updated = false; +} + +uint8_t sec_prot_keys_gtkl_get(sec_prot_gtk_keys_t *gtks) +{ + uint8_t gtkl = (uint8_t) gtks->gtk[0].live | + (((uint8_t) gtks->gtk[1].live) << 1) | + (((uint8_t) gtks->gtk[2].live) << 2) | + (((uint8_t) gtks->gtk[3].live) << 3); + + return gtkl; +} + +void sec_prot_keys_gtkl_set(sec_prot_gtk_keys_t *gtks, uint8_t gtkl) +{ + for (uint8_t i = 0; i < GTK_NUM; i++) { + if (gtks->gtk[i].set) { + if ((gtkl >> i) & 0x01) { + gtks->gtk[i].live = true; // Live on authenticator + } else { + gtks->gtk[i].live = false; + } + } + } +} + +bool sec_prot_keys_gtk_is_live(sec_prot_gtk_keys_t *gtks, uint8_t index) +{ + if (index > GTK_NUM || !gtks->gtk[index].live) { + return false; + } + + return true; +} + +int8_t sec_prot_keys_gtk_insert_index_set(sec_prot_gtk_keys_t *gtks, uint8_t index) +{ + if (index > GTK_NUM || !gtks->gtk[index].set) { + return -1; + } + + gtks->gtk_set_index = index; + return 0; +} + +int8_t sec_prot_keys_gtk_insert_index_get(sec_prot_gtk_keys_t *gtks) +{ + return gtks->gtk_set_index; +} + +void sec_prot_keys_gtk_insert_index_clear(sec_prot_gtk_keys_t *gtks) +{ + gtks->gtk_set_index = -1; +} + +uint8_t *sec_prot_keys_get_gtk_to_insert(sec_prot_gtk_keys_t *gtks, uint8_t *index) +{ + if (gtks->gtk_set_index >= 0 && gtks->gtk[gtks->gtk_set_index].set && gtks->gtk[gtks->gtk_set_index].live) { + *index = gtks->gtk_set_index; + return gtks->gtk[gtks->gtk_set_index].key; + } else { + return NULL; + } +} + +int8_t sec_prot_keys_gtk_set(sec_prot_gtk_keys_t *gtks, uint8_t index, uint8_t *gtk) +{ + if (!gtk || index >= GTK_NUM) { + return -1; + } + + if (gtks->gtk[index].set && memcmp(gtks->gtk[index].key, gtk, GTK_LEN) != 0) { + return -1; + } + + gtks->gtk[index].set = true; + gtks->gtk[index].live = false; // Set from GTKL + gtks->gtk[index].hash = false; // Not verified yet + gtks->gtk[index].lifetime = 0; // Should be provided by authenticator + memcpy(gtks->gtk[index].key, gtk, GTK_LEN); + + gtks->updated = true; + + return 0; +} + +bool sec_prot_keys_gtk_is_set(sec_prot_gtk_keys_t *gtks, uint8_t index) +{ + if (index >= GTK_NUM || !gtks->gtk[index].set) { + return false; + } + + return true; +} + +uint8_t *sec_prot_keys_gtk_get(sec_prot_gtk_keys_t *gtks, uint8_t index) +{ + if (index >= GTK_NUM || !gtks->gtk[index].set) { + return NULL; + } + + return gtks->gtk[index].key; +} + +uint32_t sec_prot_keys_gtk_lifetime_get(sec_prot_gtk_keys_t *gtks, uint8_t index) +{ + if (index >= GTK_NUM || !gtks->gtk[index].set) { + return 0; + } + + return gtks->gtk[index].lifetime; +} + +void sec_prot_keys_gtk_lifetime_set(sec_prot_gtk_keys_t *gtks, uint8_t index, uint32_t lifetime) +{ + if (index >= GTK_NUM || !gtks->gtk[index].set) { + return; + + } + gtks->gtk[index].lifetime = lifetime; + + gtks->updated = true; +} + +bool sec_prot_keys_gtks_are_updated(sec_prot_gtk_keys_t *gtks) +{ + return gtks->updated; +} + +void sec_prot_keys_gtks_updated_set(sec_prot_gtk_keys_t *gtks) +{ + gtks->updated = true; +} + +void sec_prot_keys_gtks_updated_reset(sec_prot_gtk_keys_t *gtks) +{ + gtks->updated = false; +} + +#endif /* HAVE_WS */ diff --git a/source/Security/protocols/sec_prot_keys.h b/source/Security/protocols/sec_prot_keys.h new file mode 100644 index 0000000000..0f748ad14a --- /dev/null +++ b/source/Security/protocols/sec_prot_keys.h @@ -0,0 +1,393 @@ +/* + * Copyright (c) 2016-2019, 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 SEC_PROT_KEYS_H_ +#define SEC_PROT_KEYS_H_ + +/* + * Security protocols EAPOL key storage module. This is used by EAPOL protocols to store + * and update key information. This can be used either as supplicant key storage or as + * an authenticator key storage for a specific supplicant. Storage can be also used to + * access global security data (Group Transient Keys and certificate information). + * + */ + +#define PMK_LEN 32 +#define PTK_LEN 48 +#define GTK_LEN 16 +#define GTK_NUM 4 + +#define KCK_LEN 16 +#define KEK_LEN 16 + +#define KCK_INDEX 0 +#define KEK_INDEX 16 + +#define PMKID_LEN 16 +#define PTKID_LEN 16 + +#define GTK_DEFAULT_LIFETIME 60 * 60 * 24 * 30 // 30 days + +typedef struct { + uint8_t key[GTK_LEN]; /**< Group Transient Key (128 bits) */ + uint32_t lifetime; /**< Lifetime is seconds */ + bool set: 1; /**< Group Transient Key set (valid value) */ + bool live: 1; /**< Group Transient Key live (as indicated by authenticator) */ + bool hash: 1; /**< Group Transient Key matches to hash */ +} gtk_key_t; + +typedef struct { + gtk_key_t gtk[GTK_NUM]; /**< 4 Group Transient Keys */ + int8_t gtk_set_index; /**< Group Transient Key to insert */ + bool updated; /**< Group Transient Keys has been updated */ +} sec_prot_gtk_keys_t; + +// Security key data +typedef struct { + uint64_t pmk_key_replay_cnt; /**< Pairwise Master Key replay counter */ + uint8_t pmk[PMK_LEN]; /**< Pairwise Master Key (256 bits) */ + uint8_t ptk[PTK_LEN]; /**< Pairwise Transient Key (384 bits) */ + uint8_t *ptk_eui_64; /**< Pointer to remote EUI-64 used to derive PTK or NULL */ + sec_prot_gtk_keys_t *gtks; /**< Group Transient Keys */ + const sec_prot_certs_t *certs; /**< Certificates */ + bool pmk_set: 1; /**< Pairwise Master Key set */ + bool ptk_set: 1; /**< Pairwise Transient Key set */ + bool updated: 1; /**< Keys has been updated */ + bool ptk_eui_64_set: 1; /**< Remote EUI-64 used to derive PTK is set */ +} sec_prot_keys_t; + +/** + * sec_prot_keys_create allocates memory for security keys + * + * \param gtks GTK keys + * \param cert_chain certificates + * + * \return security keys or NULL + */ +sec_prot_keys_t *sec_prot_keys_create(sec_prot_gtk_keys_t *gtks, const sec_prot_certs_t *certs); + +/** + * sec_prot_keys_init initialises security keys + * + * \param sec_keys security keys + * \param gtks GTK keys + * \param cert_chain certificates + * + */ +void sec_prot_keys_init(sec_prot_keys_t *sec_keys, sec_prot_gtk_keys_t *gtks, const sec_prot_certs_t *certs); + +/** + * sec_prot_keys_delete frees security keys memory + * + * \param sec_keys security keys + * + */ +void sec_prot_keys_delete(sec_prot_keys_t *sec_keys); + +/** + * sec_prot_keys_gtks_create allocates memory for GTK keys + * + * \return GTK keys or NULL + * + */ +sec_prot_gtk_keys_t *sec_prot_keys_gtks_create(void); + +/** + * sec_prot_keys_gtks_init initialises GTK keys + * + * \param gtks GTK keys + * + */ +void sec_prot_keys_gtks_init(sec_prot_gtk_keys_t *gtks); + +/** + * sec_prot_keys_gtks_delete frees GTK keys memory + * + * \param gtks GTK keys + * + */ +void sec_prot_keys_gtks_delete(sec_prot_gtk_keys_t *gtks); + +/** + * sec_prot_keys_pmk_write writes Pairwise Master Key + * + * \param sec_keys security keys + * \param pmk Pairwise Master Key + * + */ +void sec_prot_keys_pmk_write(sec_prot_keys_t *sec_keys, uint8_t *pmk); + +/** + * sec_prot_keys_pmk_get gets Pairwise Master Key + * + * \param sec_keys security keys + * + * \return PMK or NULL + * + */ +uint8_t *sec_prot_keys_pmk_get(sec_prot_keys_t *sec_keys); + +/** + * sec_prot_keys_pmk_replay_cnt_get gets PMK replay counter value + * + * \param sec_keys security keys + * + * \return replay counter value + * + */ +uint64_t sec_prot_keys_pmk_replay_cnt_get(sec_prot_keys_t *sec_keys); + +/** + * sec_prot_keys_pmk_replay_cnt_set sets PMK replay counter value + * + * \param sec_keys security keys + * \param counter new value for replay counter + * + */ +void sec_prot_keys_pmk_replay_cnt_set(sec_prot_keys_t *sec_keys, uint64_t counter); + +/** + * sec_prot_keys_pmk_replay_cnt_increment increments PMK replay counter value by one + * + * \param sec_keys security keys + * + */ +void sec_prot_keys_pmk_replay_cnt_increment(sec_prot_keys_t *sec_keys); + +/** + * sec_prot_keys_ptk_write writes Pairwise Transient Key + * + * \param sec_keys security keys + * \param ptk Pairwise Transient Key + * + */ +void sec_prot_keys_ptk_write(sec_prot_keys_t *sec_keys, uint8_t *ptk); + +/** + * sec_prot_keys_ptk_get gets Pairwise Transient Key + * + * \param sec_keys security keys + * + * \return PTK or NULL + * + */ +uint8_t *sec_prot_keys_ptk_get(sec_prot_keys_t *sec_keys); + +/** + * sec_prot_keys_ptk_eui_64_set sets PTK EUI-64 storage + * + * \param sec_keys security keys + * \param eui64 EUI-64 storage + * + */ +void sec_prot_keys_ptk_eui_64_set(sec_prot_keys_t *sec_keys, uint8_t *eui_64); + +/** + * sec_prot_keys_ptk_eui_64_write writes PTK EUI-64 + * + * \param sec_keys security keys + * \param eui64 EUI-64 + * + */ +void sec_prot_keys_ptk_eui_64_write(sec_prot_keys_t *sec_keys, uint8_t *eui_64); + +/** + * sec_prot_keys_ptk_eui_64_get gets PTK EUI-64 + * + * \param sec_keys security keys + * + * \return EUI-64 OR NULL + * + */ +uint8_t *sec_prot_keys_ptk_eui_64_get(sec_prot_keys_t *sec_keys); + +/** + * sec_prot_keys_are_updated returns security keys have been updated flag + * + * \param sec_keys security keys + * + * \return TRUE keys have been updated, FALSE keys have not been updated + * + */ +bool sec_prot_keys_are_updated(sec_prot_keys_t *sec_keys); + +/** + * sec_prot_keys_updated_reset resets security keys have been updated flag + * + * \param sec_keys security keys + * + * + */ +void sec_prot_keys_updated_reset(sec_prot_keys_t *sec_keys); + +/** + * sec_prot_keys_gtkl_get gets Group Transient Key liveness + * + * \param gtks GTK keys + * + * \return bit field indicating GTK liveness + * + */ +uint8_t sec_prot_keys_gtkl_get(sec_prot_gtk_keys_t *gtks); + +/** + * sec_prot_keys_gtkl_set sets Group Transient Key liveness + * + * \param gtks GTK keys + * \param gtkl bit field indicating GTK liveness + * + */ +void sec_prot_keys_gtkl_set(sec_prot_gtk_keys_t *gtks, uint8_t gtkl); + +/** + * sec_prot_keys_gtk_is_live checks if Group Transient Key is live + * + * \param gtks GTK keys + * \param index GTK index + * + * \return TRUE GTK is live, FALSE GTK is not live + * + */ +bool sec_prot_keys_gtk_is_live(sec_prot_gtk_keys_t *gtks, uint8_t index); + +/** + * sec_prot_keys_gtk_insert_index_set sets index of GTK to be inserted + * + * \param gtks GTK keys + * \param index GTK index + * + * \return < 0 failure + * \return >= 0 success + * + */ +int8_t sec_prot_keys_gtk_insert_index_set(sec_prot_gtk_keys_t *gtks, uint8_t index); + +/** + * sec_prot_keys_gtk_insert_index_get gets index of GTK to be inserted + * + * \param gtks GTK keys + * + * \return >= 0 GTK index + * \return < 0 no GTK to be inserted + * + */ +int8_t sec_prot_keys_gtk_insert_index_get(sec_prot_gtk_keys_t *gtks); + +/** + * sec_prot_keys_gtk_insert_index_clear clears the index of GTK to be inserted + * + * \param gtks GTK keys + * + */ +void sec_prot_keys_gtk_insert_index_clear(sec_prot_gtk_keys_t *gtks); + +/** + * sec_prot_keys_get_gtk_to_insert gets GTK that is marked to be inserted + * + * \param gtks GTK keys + * \param index index of the returned GTK + * + * \return GTK or NULL + * + */ +uint8_t *sec_prot_keys_get_gtk_to_insert(sec_prot_gtk_keys_t *gtks, uint8_t *index); + +/** + * sec_prot_keys_gtk_set sets Group Transient Key + * + * \param gtks GTK keys + * \param index index + * \param gtk gtk value + * + * \return < 0 failure + * \return >= 0 success + * + */ +int8_t sec_prot_keys_gtk_set(sec_prot_gtk_keys_t *gtks, uint8_t index, uint8_t *gtk); + +/** + * sec_prot_keys_gtk_is_set checks if Group Transient Key is set + * + * \param gtks GTK keys + * \param index index + * + * \return TRUE GTK is set, FALSE GTK is not set + * + */ +bool sec_prot_keys_gtk_is_set(sec_prot_gtk_keys_t *gtks, uint8_t index); + +/** + * sec_prot_keys_gtk_gets gets Group Transient Key + * + * \param gtks GTK keys + * \param index index + * + * \return GTK or NULL + * + */ +uint8_t *sec_prot_keys_gtk_get(sec_prot_gtk_keys_t *gtks, uint8_t index); + +/** + * sec_prot_keys_gtk_lifetime_get gets GTK lifetime + * + * \param gtks GTK keys + * \param index index + * + * \return GTK lifetime + * + */ +uint32_t sec_prot_keys_gtk_lifetime_get(sec_prot_gtk_keys_t *gtks, uint8_t index); + +/** + * sec_prot_keys_gtk_lifetime_set sets GTK lifetime + * + * \param gtks GTK keys + * \param index index + * \param lifetime GTK lifetime + * + */ +void sec_prot_keys_gtk_lifetime_set(sec_prot_gtk_keys_t *gtks, uint8_t index, uint32_t lifetime); + +/** + * sec_prot_keys_gtks_are_updated returns GTKs have been updated flag + * + * \param gtks GTK keys + * + * \return TRUE GTKs have been updated, FALSE GTKs have not been updated + * + */ +bool sec_prot_keys_gtks_are_updated(sec_prot_gtk_keys_t *gtks); + +/** + * sec_prot_keys_gtks_updated_set sets GTKs have been updated flag + * + * \param gtks GTK keys + * + * + */ +void sec_prot_keys_gtks_updated_set(sec_prot_gtk_keys_t *gtks); + +/** + * sec_prot_keys_gtks_updated_set resets GTKs have been updated flag + * + * \param gtks GTK keys + * + * + */ +void sec_prot_keys_gtks_updated_reset(sec_prot_gtk_keys_t *gtks); + +#endif /* SEC_PROT_KEYS_H_ */ diff --git a/source/Security/protocols/sec_prot_lib.c b/source/Security/protocols/sec_prot_lib.c new file mode 100644 index 0000000000..f5c42d65b7 --- /dev/null +++ b/source/Security/protocols/sec_prot_lib.c @@ -0,0 +1,488 @@ +/* + * Copyright (c) 2016-2019, 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 +#include "ns_types.h" +#include "ns_list.h" +#include "ns_trace.h" +#include "nsdynmemLIB.h" +#include "fhss_config.h" +#include "NWK_INTERFACE/Include/protocol.h" +#include "6LoWPAN/ws/ws_config.h" +#include "Service_Libs/Trickle/trickle.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/eapol/kde_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 "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" + +#ifdef HAVE_WS + +#define TRACE_GROUP "secl" + +void sec_prot_init(sec_prot_common_t *data) +{ + data->state = SEC_STATE_INIT; + data->result = SEC_RESULT_OK; + data->ticks = SEC_TOTAL_TIMEOUT; + data->trickle_running = false; +} + +void sec_prot_timer_timeout_handle(sec_prot_t *prot, sec_prot_common_t *data, const trickle_params_t *trickle_params, uint16_t ticks) +{ + if (data->trickle_running) { + bool running = trickle_running(&data->trickle_timer, trickle_params); + + // Checks for trickle timer expiration */ + if (trickle_timer(&data->trickle_timer, trickle_params, ticks)) { + sec_prot_result_set(data, SEC_RESULT_TIMEOUT); + prot->state_machine(prot); + } + + // Checks if maximum number of trickle timer expirations has happened + if (running && !trickle_running(&data->trickle_timer, trickle_params)) { + sec_prot_result_set(data, SEC_RESULT_TIMEOUT); + sec_prot_state_set(prot, data, SEC_STATE_FINISH); + } + } + + if (data->ticks > ticks) { + data->ticks -= ticks; + } else { + tr_debug("prot timeout"); + data->ticks = 0; + sec_prot_result_set(data, SEC_RESULT_TIMEOUT); + sec_prot_state_set(prot, data, SEC_STATE_FINISH); + } +} + +void sec_prot_timer_trickle_start(sec_prot_common_t *data, const trickle_params_t *trickle_params) +{ + trickle_start(&data->trickle_timer, trickle_params); + data->trickle_running = true; +} + +void sec_prot_timer_trickle_stop(sec_prot_common_t *data) +{ + trickle_stop(&data->trickle_timer); + data->trickle_running = false; +} + +void sec_prot_state_set(sec_prot_t *prot, sec_prot_common_t *data, uint8_t state) +{ + switch (state) { + case SEC_STATE_FINISH: + if (data->state == SEC_STATE_FINISHED) { + // Already, do not update state; + } else { + data->state = SEC_STATE_FINISH; + } + data->trickle_running = false; + data->ticks = SEC_FINISHED_TIMEOUT; + + // Go to SEC_STATE_FINISH or SEC_STATE_FINISHED + prot->state_machine(prot); + return; + + case SEC_STATE_FINISHED: + // Wait for timeout + data->trickle_running = false; + data->ticks = SEC_FINISHED_TIMEOUT; + // Clear result + sec_prot_result_set(data, SEC_RESULT_OK); + break; + + case SEC_STATE_INIT: + data->state = SEC_STATE_INIT; + prot->state_machine(prot); + return; + + default: + break; + } + + data->state = state; +} + +uint8_t sec_prot_state_get(sec_prot_common_t *data) +{ + return data->state; +} + +void sec_prot_result_set(sec_prot_common_t *data, sec_prot_result_e result) +{ + data->result = result; +} + +sec_prot_result_e sec_prot_result_get(sec_prot_common_t *data) +{ + return data->result; +} + +bool sec_prot_result_timeout_check(sec_prot_common_t *data) +{ + if (data->result == SEC_RESULT_TIMEOUT) { + data->result = SEC_RESULT_OK; + return true; + } + return false; +} + +bool sec_prot_result_ok_check(sec_prot_common_t *data) +{ + if (data->result == SEC_RESULT_OK) { + return true; + } + return false; +} + +/* + * IEEE 802.11 advises using sequential nonces, but should this be + * randlib? + */ +void sec_prot_lib_nonce_generate(uint8_t *nonce) +{ + // For now, use randlib + randLIB_get_n_bytes_random(nonce, EAPOL_KEY_NONCE_LEN); + +#if 0 + for (int i = 31; i >= 0; i--) { + if (++nonce[i] != 0) { + break; + } + } +#endif +} + +/* + * From IEEE 802.11 how to init nonce calculation by using non-secure random + * + * PRF-256(Random number, “Init Counter”, Local MAC Address || Time) + */ +void sec_prot_lib_nonce_init(uint8_t *nonce, uint8_t *eui64, uint64_t time) +{ + // For now, use randlib + uint8_t random[EAPOL_KEY_NONCE_LEN]; + randLIB_get_n_bytes_random(random, EAPOL_KEY_NONCE_LEN); + + const uint8_t a_string_val[] = {"Init Counter"}; + const uint8_t a_string_val_len = sizeof(a_string_val) - 1; + + ieee_802_11_prf_t prf; + + uint16_t string_len = ieee_802_11_prf_setup(&prf, EAPOL_KEY_NONCE_LEN * 8, a_string_val_len, EUI64_LEN + EUI64_LEN); + uint8_t string[string_len]; + + uint8_t *a_string = ieee_802_11_prf_get_a_string(&prf, string); + memcpy(a_string, a_string_val, a_string_val_len); + + uint8_t *b_string = ieee_802_11_prf_get_b_string(&prf, string); + memcpy(b_string, eui64, EUI64_LEN); + b_string += EUI64_LEN; + memcpy(b_string, &time, sizeof(uint64_t)); + + uint16_t result_len = ieee_802_11_prf_starts(&prf, random, EAPOL_KEY_NONCE_LEN); + + ieee_802_11_prf_update(&prf, string); + + uint8_t result[result_len]; + + ieee_802_11_prf_finish(&prf, result); + + memcpy(nonce, result, EAPOL_KEY_NONCE_LEN); +} + +/* + * PTK = PRF-384(PMK, “Pairwise key expansion”, Min(AUTH EUI-64, SUP EUI-64) || + * Max(AUTH EUI-64, SUP EUI-64) || Min (Anonce, Snonce) || Max(Anonce, Snonce)) + * + * PMK is 256 bits, PTK is 382 bits + */ +int8_t sec_prot_lib_ptk_calc(const uint8_t *pmk, const uint8_t *eui64_1, const uint8_t *eui64_2, const uint8_t *nonce1, const uint8_t *nonce2, uint8_t *ptk) +{ + const uint8_t a_string_val[] = {"Pairwise key expansion"}; + const uint8_t a_string_val_len = sizeof(a_string_val) - 1; + + const uint8_t *min_eui64 = eui64_1; + const uint8_t *max_eui64 = eui64_2; + if (memcmp(eui64_1, eui64_2, EUI64_LEN) > 0) { + min_eui64 = eui64_2; + max_eui64 = eui64_1; + } + + const uint8_t *min_nonce = nonce1; + const uint8_t *max_nonce = nonce2; + if (memcmp(nonce1, nonce2, EAPOL_KEY_NONCE_LEN) > 0) { + min_nonce = nonce2; + max_nonce = nonce1; + } + + ieee_802_11_prf_t prf; + + uint16_t string_len = ieee_802_11_prf_setup(&prf, 384, a_string_val_len, EUI64_LEN + EUI64_LEN + EAPOL_KEY_NONCE_LEN + EAPOL_KEY_NONCE_LEN); + uint8_t string[string_len]; + + uint8_t *a_string = ieee_802_11_prf_get_a_string(&prf, string); + memcpy(a_string, a_string_val, a_string_val_len); + + uint8_t *b_string = ieee_802_11_prf_get_b_string(&prf, string); + memcpy(b_string, min_eui64, EUI64_LEN); + b_string += EUI64_LEN; + memcpy(b_string, max_eui64, EUI64_LEN); + b_string += EUI64_LEN; + + memcpy(b_string, min_nonce, EAPOL_KEY_NONCE_LEN); + b_string += EAPOL_KEY_NONCE_LEN; + memcpy(b_string, max_nonce, EAPOL_KEY_NONCE_LEN); + + uint16_t result_len = ieee_802_11_prf_starts(&prf, pmk, PMK_LEN); + + ieee_802_11_prf_update(&prf, string); + + uint8_t result[result_len]; + + ieee_802_11_prf_finish(&prf, result); + + memcpy(ptk, result, PTK_LEN); + + return 0; +} + +int8_t sec_prot_lib_pmkid_calc(const uint8_t *pmk, const uint8_t *auth_eui64, const uint8_t *supp_eui64, uint8_t *pmkid) +{ + const uint8_t pmk_string_val[] = {"PMK Name"}; + const uint8_t pmk_string_val_len = sizeof(pmk_string_val) - 1; + + const uint8_t data_len = pmk_string_val_len + EUI64_LEN + EUI64_LEN; + uint8_t data[data_len]; + uint8_t *ptr = data; + memcpy(ptr, pmk_string_val, pmk_string_val_len); + ptr += pmk_string_val_len; + memcpy(ptr, auth_eui64, EUI64_LEN); + ptr += EUI64_LEN; + memcpy(ptr, supp_eui64, EUI64_LEN); + + if (hmac_sha1_calc(pmk, PMK_LEN, data, data_len, pmkid) < 0) { + return -1; + } + + return 0; +} + +int8_t sec_prot_lib_ptkid_calc(const uint8_t *ptk, const uint8_t *auth_eui64, const uint8_t *supp_eui64, uint8_t *ptkid) +{ + const uint8_t ptk_string_val[] = {"PTK Name"}; + const uint8_t ptk_string_val_len = sizeof(ptk_string_val) - 1; + + const uint8_t data_len = ptk_string_val_len + EUI64_LEN + EUI64_LEN; + uint8_t data[data_len]; + uint8_t *ptr = data; + memcpy(ptr, ptk_string_val, ptk_string_val_len); + ptr += ptk_string_val_len; + memcpy(ptr, auth_eui64, EUI64_LEN); + ptr += EUI64_LEN; + memcpy(ptr, supp_eui64, EUI64_LEN); + + if (hmac_sha1_calc(ptk, PTK_LEN, data, data_len, ptkid) < 0) { + return -1; + } + + return 0; +} + +uint8_t *sec_prot_lib_message_build(uint8_t *ptk, uint8_t *kde, uint16_t kde_len, eapol_pdu_t *eapol_pdu, uint16_t eapol_pdu_size, uint8_t header_size) +{ + uint8_t *eapol_pdu_frame = ns_dyn_mem_temporary_alloc(header_size + eapol_pdu_size); + + if (!eapol_pdu_frame) { + return NULL; + } + + uint8_t *eapol_kde = eapol_write_pdu_frame(eapol_pdu_frame + header_size, eapol_pdu); + + if (kde) { + if (eapol_pdu->msg.key.key_information.encrypted_key_data) { + size_t output_len = kde_len; + if (nist_aes_key_wrap(1, &ptk[KEK_INDEX], 128, kde, kde_len - 8, eapol_kde, &output_len) < 0 || output_len != kde_len) { + ns_dyn_mem_free(eapol_pdu_frame); + return NULL; + } + } else { + memcpy(eapol_kde, kde, 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) < 0) { + ns_dyn_mem_free(eapol_pdu_frame); + return NULL; + } + eapol_write_key_packet_mic(eapol_pdu_frame + header_size, mic); + } + + return eapol_pdu_frame; +} + +uint8_t *sec_prot_lib_message_handle(uint8_t *ptk, uint16_t *kde_len, eapol_pdu_t *eapol_pdu) +{ + if (eapol_pdu->msg.key.key_data_length == 0 || eapol_pdu->msg.key.key_data == NULL) { + return NULL; + } + + uint8_t *key_data = eapol_pdu->msg.key.key_data; + uint16_t key_data_len = eapol_pdu->msg.key.key_data_length; + + uint8_t *kde = ns_dyn_mem_temporary_alloc(key_data_len); + *kde_len = key_data_len; + + if (eapol_pdu->msg.key.key_information.encrypted_key_data) { + size_t output_len = eapol_pdu->msg.key.key_data_length; + if (nist_aes_key_wrap(0, &ptk[KEK_INDEX], 128, key_data, key_data_len, kde, &output_len) < 0 || output_len != (size_t) key_data_len - 8) { + ns_dyn_mem_free(kde); + return NULL; + } + *kde_len = output_len; + } else { + memcpy(kde, key_data, *kde_len); + } + + return kde; +} + +int8_t sec_prot_lib_gtk_read(uint8_t *kde, uint16_t kde_len, sec_prot_gtk_keys_t *gtks) +{ + // If a valid new GTK value present, insert it + int8_t gtk_set_index = -1; + + uint8_t key_id; + uint8_t gtk[GTK_LEN]; + + if (kde_gtk_read(kde, kde_len, &key_id, gtk) >= 0) { + // A new GTK value + if (sec_prot_keys_gtk_set(gtks, key_id, gtk) >= 0) { + gtk_set_index = (int8_t) key_id; // Insert + } + + uint32_t lifetime; + if (kde_lifetime_read(kde, kde_len, &lifetime) >= 0) { + sec_prot_keys_gtk_lifetime_set(gtks, key_id, lifetime); + } + } + uint8_t gtkl; + if (kde_gtkl_read(kde, kde_len, >kl) >= 0) { + sec_prot_keys_gtkl_set(gtks, gtkl); + } else { + return -1; + } + + // Sanity checks + if (gtk_set_index >= 0) { + if (!sec_prot_keys_gtk_is_live(gtks, gtk_set_index)) { + gtk_set_index = -1; + } + } + + if (gtk_set_index >= 0) { + sec_prot_keys_gtk_insert_index_set(gtks, gtk_set_index); + } + + return 0; +} + +int8_t sec_prot_lib_mic_validate(uint8_t *ptk, uint8_t *mic, uint8_t *pdu, uint8_t pdu_size) +{ + uint8_t recv_mic[EAPOL_KEY_MIC_LEN]; + memcpy(recv_mic, mic, EAPOL_KEY_MIC_LEN); + + 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) < 0) { + return -1; + } + if (memcmp(recv_mic, calc_mic, EAPOL_KEY_MIC_LEN) != 0) { + return -1; + } + return 0; +} + +uint8_t sec_prot_lib_key_mask_get(eapol_pdu_t *eapol_pdu) +{ + uint8_t key_mask = 0; + + if (eapol_pdu->msg.key.key_information.install) { + key_mask |= KEY_INFO_INSTALL; + } + if (eapol_pdu->msg.key.key_information.key_ack) { + key_mask |= KEY_INFO_KEY_ACK; + } + if (eapol_pdu->msg.key.key_information.key_mic) { + key_mask |= KEY_INFO_KEY_MIC; + } + if (eapol_pdu->msg.key.key_information.secured_key_frame) { + key_mask |= KEY_INFO_SECURED_KEY_FRAME; + } + + return key_mask; +} + +int8_t sec_prot_lib_pmkid_generate(sec_prot_t *prot, uint8_t *pmkid, bool is_auth) +{ + uint8_t local_eui64[8]; + uint8_t remote_eui64[8]; + prot->addr_get(prot, local_eui64, remote_eui64); + uint8_t *pmk = sec_prot_keys_pmk_get(prot->sec_keys); + if (!pmk) { + return -1; + } + + if (is_auth) { + return sec_prot_lib_pmkid_calc(pmk, local_eui64, remote_eui64, pmkid); + } else { + return sec_prot_lib_pmkid_calc(pmk, remote_eui64, local_eui64, pmkid); + } +} + +int8_t sec_prot_lib_ptkid_generate(sec_prot_t *prot, uint8_t *ptkid, bool is_auth) +{ + uint8_t local_eui64[8]; + uint8_t remote_eui64[8]; + prot->addr_get(prot, local_eui64, remote_eui64); + uint8_t *ptk = sec_prot_keys_pmk_get(prot->sec_keys); + if (!ptk) { + return -1; + } + + if (is_auth) { + return sec_prot_lib_ptkid_calc(ptk, local_eui64, remote_eui64, ptkid); + } else { + return sec_prot_lib_ptkid_calc(ptk, remote_eui64, local_eui64, ptkid); + } +} + + +#endif /* HAVE_WS */ diff --git a/source/Security/protocols/sec_prot_lib.h b/source/Security/protocols/sec_prot_lib.h new file mode 100644 index 0000000000..ebf32bf809 --- /dev/null +++ b/source/Security/protocols/sec_prot_lib.h @@ -0,0 +1,291 @@ +/* + * Copyright (c) 2016-2019, 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 SEC_PROT_LIB_H_ +#define SEC_PROT_LIB_H_ + +/* + * Library functions used by security protocols. These include helper functions + * related to different hash functions, common message handling functions, and + * common timer and state machine functions. + * + */ + +#define EUI64_LEN 8 +#define SEC_TOTAL_TIMEOUT 30 * 60 * 10 // 30 minutes +#define SEC_FINISHED_TIMEOUT 5 * 10 // 5 seconds + +#define FWH_NONCE_LENGTH 32 +#define EUI64_LEN 8 +#define SEC_TOTAL_TIMEOUT 30 * 60 * 10 // 30 minutes +#define SEC_FINISHED_TIMEOUT 5 * 10 // 5 seconds + +#define KEY_INFO_INSTALL 0x01 +#define KEY_INFO_KEY_ACK 0x02 +#define KEY_INFO_KEY_MIC 0x04 +#define KEY_INFO_SECURED_KEY_FRAME 0x08 + +// Common data shared between security protocols needing general timers and state machines +typedef struct { + trickle_t trickle_timer; /**< Trickle timer for re-sending */ + uint16_t ticks; /**< Timer ticks */ + int8_t state; /**< Protocol state machine state */ + sec_prot_result_e result; /**< Result for ongoing negotiation */ + bool trickle_running; /**< Trickle running */ +} sec_prot_common_t; + +/** + * sec_prot_lib_nonce_init init nonce + * + * \param nonce nonce + * \param eui64 EUI-64 + * \param time current time + * + */ +void sec_prot_lib_nonce_init(uint8_t *nonce, uint8_t *eui64, uint64_t time); + +/** + * sec_prot_lib_nonce_generate generates nonce + * + * \param nonce nonce + * + */ +void sec_prot_lib_nonce_generate(uint8_t *nonce); + +/** + * sec_prot_lib_pmkid_calc calculates PKMID from PMK + * + * \param pmk PMK + * \param auth_eui64 authenticator EUI-64 + * \param supp_eui64 supplicant EUI-64 + * \param pmkid PMKID + * + * \return < 0 failure + * \return >= 0 success + */ +int8_t sec_prot_lib_pmkid_calc(const uint8_t *pmk, const uint8_t *auth_eui64, const uint8_t *supp_eui64, uint8_t *pmkid); + +/** + * sec_prot_lib_ptkid_calc calculates PTMID from PTK + * + * \param pmk PTK + * \param auth_eui64 authenticator EUI-64 + * \param supp_eui64 supplicant EUI-64 + * \param pmkid PTKID + * + * \return < 0 failure + * \return >= 0 success + */ +int8_t sec_prot_lib_ptkid_calc(const uint8_t *ptk, const uint8_t *auth_eui64, const uint8_t *supp_eui64, uint8_t *ptkid); + +/** + * sec_prot_lib_ptk_calc calculates PTK from KMP, EUI-64s and nonces + * + * \param pmk PMK + * \param eui64_1 first EUI-64 + * \param eui64_2 second EUI-64 + * \param nonce1 first nonce + * \param nonce2 second nonce + * \param ptk PTK + * + * \return < 0 failure + * \return >= 0 success + */ +int8_t sec_prot_lib_ptk_calc(const uint8_t *pmk, const uint8_t *eui64_1, const uint8_t *eui64_2, const uint8_t *nonce1, const uint8_t *nonce2, uint8_t *ptk); + +/** + * sec_prot_lib_message_build builds a message + * + * \param ptk PTK for MIC calculation and encryption + * \param kde KDEs + * \param kde_len length of the KDEs + * \param eapol_pdu EAPOL PDU + * \param eapol_pdu_size EAPOL PDU size + * \param header_size lower level header size + * + * \return < 0 failure + * \return >= 0 success + */ +uint8_t *sec_prot_lib_message_build(uint8_t *ptk, uint8_t *kde, uint16_t kde_len, eapol_pdu_t *eapol_pdu, uint16_t eapol_pdu_size, uint8_t header_size); + +/** + * sec_prot_lib_message_handle handles a message + * + * \param ptk PTK for decryption + * \param kde_len length of the KDEs + * \param eapol_pdu EAPOL PDU + * + * \return pointer to start of the KDEs + * \return NULL failure + */ +uint8_t *sec_prot_lib_message_handle(uint8_t *ptk, uint16_t *kde_len, eapol_pdu_t *eapol_pdu); + +/** + * sec_prot_lib_gtk_read reads GTK, GTKL and lifetime KDEs + * + * \param kde KDEs + * \param kde_len length of the KDEs + * \param gtks GTKs + * + * \return < 0 failure + * \return >= 0 success + */ +int8_t sec_prot_lib_gtk_read(uint8_t *kde, uint16_t kde_len, sec_prot_gtk_keys_t *gtks); + +/** + * sec_prot_lib_mic_validate validates MIC + * + * \param ptk PTK for MIC validation + * \param kde_len length of the KDEs + * \param pdu pointer to message + * \param pdu_size message size + * + * \return < 0 failure + * \return >= 0 success + */ +int8_t sec_prot_lib_mic_validate(uint8_t *ptk, uint8_t *mic, uint8_t *pdu, uint8_t pdu_size); + +/** + * sec_prot_lib_key_mask_get gets masked EAPOL-Key message bits + * + * \param eapol_pdu EAPOL PDU + * + * \return mask + */ +uint8_t sec_prot_lib_key_mask_get(eapol_pdu_t *eapol_pdu); + +/** + * sec_prot_lib_pmkid_generate generate PMK ID from PMK + * + * \param prot security protocol + * \param pmkid PMK ID + * \param is_auth set for authenticator + * + * \return < 0 failure + * \return >= 0 success + */ +int8_t sec_prot_lib_pmkid_generate(sec_prot_t *prot, uint8_t *pmkid, bool is_auth); + +/** + * sec_prot_lib_ptkid_generate generate PTK ID from PTK + * + * \param prot security protocol + * \param ptkid PTK ID + * \param is_auth set for authenticator + * + * \return < 0 failure + * \return >= 0 success + */ +int8_t sec_prot_lib_ptkid_generate(sec_prot_t *prot, uint8_t *ptkid, bool is_auth); + +/** + * sec_prot_init initiates common data + * + * \param data common data + * + */ +void sec_prot_init(sec_prot_common_t *data); + +/** + * sec_prot_init timeout handler + * + * \param prot protocol + * \param data common data + * \param trickle_params trickle parameters + * + */ +void sec_prot_timer_timeout_handle(sec_prot_t *prot, sec_prot_common_t *data, const trickle_params_t *trickle_params, uint16_t ticks); + +/** + * sec_prot_timer_trickle_start starts trickle timer + * + * \param data common data + * \param trickle_params trickle parameters + * + */ +void sec_prot_timer_trickle_start(sec_prot_common_t *data, const trickle_params_t *trickle_params); + +/** + * sec_prot_timer_trickle_stop stops trickle timer + * + * \param data common data + * + */ +void sec_prot_timer_trickle_stop(sec_prot_common_t *data); + +/** + * sec_prot_state_set sets state machine state + * + * \param prot protocol + * \param data common data + * \param state new state + * + */ +void sec_prot_state_set(sec_prot_t *prot, sec_prot_common_t *data, uint8_t state); + +/** + * sec_prot_state_get gets state machine state + * + * \param data common data + * + * \return state + * + */ +uint8_t sec_prot_state_get(sec_prot_common_t *data); + +/** + * sec_prot_result_set sets result for operation + * + * \param data common data + * \param result result + * + */ +void sec_prot_result_set(sec_prot_common_t *data, sec_prot_result_e result); + +/** + * sec_prot_result_get gets result for operation + * + * \param data common data + * + * \return result + * + */ +sec_prot_result_e sec_prot_result_get(sec_prot_common_t *data); + +/** + * sec_prot_result_timeout_check checks if result is timeout + * + * \param data common data + * + * \return true result is timeout + * \return false result is not timeout + * + */ +bool sec_prot_result_timeout_check(sec_prot_common_t *data); + +/** + * sec_prot_result_ok_check checks if result is ok + * + * \param data common data + * + * \return true result is ok + * \return false result is not ok + * + */ +bool sec_prot_result_ok_check(sec_prot_common_t *data); + +#endif /* SEC_PROT_LIB_H_ */ diff --git a/source/Security/protocols/tls_sec_prot/tls_sec_prot.c b/source/Security/protocols/tls_sec_prot/tls_sec_prot.c new file mode 100644 index 0000000000..b4cac8675c --- /dev/null +++ b/source/Security/protocols/tls_sec_prot/tls_sec_prot.c @@ -0,0 +1,551 @@ +/* + * Copyright (c) 2019, Arm Limited and affiliates. + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "nsconfig.h" +#include +#include "ns_types.h" +#include "ns_list.h" +#include "ns_trace.h" +#include "nsdynmemLIB.h" +#include "fhss_config.h" +#include "NWK_INTERFACE/Include/protocol.h" +#include "6LoWPAN/ws/ws_config.h" +#include "Security/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/tls_sec_prot/tls_sec_prot.h" +#include "Security/protocols/tls_sec_prot/tls_sec_prot_lib.h" + +#ifdef HAVE_WS + +#define TRACE_GROUP "tlsp" + +typedef enum { + TLS_STATE_INIT = SEC_STATE_INIT, + TLS_STATE_CREATE_REQ = SEC_STATE_CREATE_REQ, + TLS_STATE_CREATE_RESP = SEC_STATE_CREATE_RESP, + TLS_STATE_CREATE_IND = SEC_STATE_CREATE_IND, + + TLS_STATE_CLIENT_HELLO = SEC_STATE_FIRST, + TLS_STATE_CONFIGURE, + TLS_STATE_PROCESS, + + TLS_STATE_FINISH = SEC_STATE_FINISH, + TLS_STATE_FINISHED = SEC_STATE_FINISHED +} eap_tls_sec_prot_state_e; + +typedef struct { + sec_prot_common_t common; /**< Common data */ + uint8_t new_pmk[PMK_LEN]; /**< New Pair Wise Master Key */ + tls_data_t tls_send; /**< TLS send buffer */ + tls_data_t tls_recv; /**< TLS receive buffer */ + uint32_t int_timer; /**< TLS intermediate timer timeout */ + uint32_t fin_timer; /**< TLS final timer timeout */ + bool timer_running; /**< TLS timer running */ + bool finished; /**< TLS finished */ + bool calculating; /**< TLS is calculating */ + uint8_t tls_sec_inst; /**< TLS security library storage, SHALL BE THE LAST FIELD */ +} tls_sec_prot_int_t; + +static uint16_t tls_sec_prot_size(void); +static int8_t client_tls_sec_prot_init(sec_prot_t *prot); +static int8_t server_tls_sec_prot_init(sec_prot_t *prot); + +static void tls_sec_prot_create_request(sec_prot_t *prot, sec_prot_keys_t *sec_keys); +static void tls_sec_prot_create_response(sec_prot_t *prot, sec_prot_result_e result); +static void tls_sec_prot_delete(sec_prot_t *prot); +static int8_t tls_sec_prot_receive(sec_prot_t *prot, void *pdu, uint16_t size); +static void tls_sec_prot_finished_send(sec_prot_t *prot); + +static void client_tls_sec_prot_state_machine(sec_prot_t *prot); +static void server_tls_sec_prot_state_machine(sec_prot_t *prot); + +static void tls_sec_prot_timer_timeout(sec_prot_t *prot, uint16_t ticks); + +static int16_t tls_sec_prot_tls_send(void *handle, const void *buf, size_t len); +static int16_t tls_sec_prot_tls_receive(void *handle, unsigned char *buf, size_t len); +static void tls_sec_prot_tls_export_keys(void *handle, const uint8_t *master_secret, const uint8_t *eap_tls_key_material); +static void tls_sec_prot_tls_set_timer(void *handle, uint32_t inter, uint32_t fin); +static int8_t tls_sec_prot_tls_get_timer(void *handle); + +static int8_t tls_sec_prot_tls_configure_and_connect(sec_prot_t *prot, bool is_server); + +#define tls_sec_prot_get(prot) (tls_sec_prot_int_t *) &prot->data + +int8_t client_tls_sec_prot_register(kmp_service_t *service) +{ + if (!service) { + return -1; + } + + if (kmp_service_sec_protocol_register(service, TLS_PROT, tls_sec_prot_size, client_tls_sec_prot_init) < 0) { + return -1; + } + + return 0; +} + +int8_t server_tls_sec_prot_register(kmp_service_t *service) +{ + if (!service) { + return -1; + } + + if (kmp_service_sec_protocol_register(service, TLS_PROT, tls_sec_prot_size, server_tls_sec_prot_init) < 0) { + return -1; + } + + return 0; +} + +static uint16_t tls_sec_prot_size(void) +{ + return sizeof(tls_sec_prot_int_t) + tls_sec_prot_lib_size(); +} + +static int8_t client_tls_sec_prot_init(sec_prot_t *prot) +{ + prot->create_req = tls_sec_prot_create_request; + prot->create_resp = NULL; + prot->receive = tls_sec_prot_receive; + prot->delete = tls_sec_prot_delete; + prot->state_machine = client_tls_sec_prot_state_machine; + prot->timer_timeout = tls_sec_prot_timer_timeout; + prot->finished_send = tls_sec_prot_finished_send; + + tls_sec_prot_int_t *data = tls_sec_prot_get(prot); + + sec_prot_init(&data->common); + sec_prot_state_set(prot, &data->common, TLS_STATE_INIT); + + memset(data->new_pmk, 0, PMK_LEN); + data->finished = false; + // Set from security parameters + eap_tls_sec_prot_lib_message_init(&data->tls_recv); + eap_tls_sec_prot_lib_message_init(&data->tls_send); + data->int_timer = 0; + data->fin_timer = 0; + data->timer_running = false; + data->calculating = false; + return 0; +} + +static int8_t server_tls_sec_prot_init(sec_prot_t *prot) +{ + prot->create_req = NULL; + prot->create_resp = tls_sec_prot_create_response; + prot->receive = tls_sec_prot_receive; + prot->delete = tls_sec_prot_delete; + prot->state_machine = server_tls_sec_prot_state_machine; + prot->timer_timeout = tls_sec_prot_timer_timeout; + prot->finished_send = tls_sec_prot_finished_send; + + tls_sec_prot_int_t *data = tls_sec_prot_get(prot); + + sec_prot_init(&data->common); + sec_prot_state_set(prot, &data->common, TLS_STATE_INIT); + + memset(data->new_pmk, 0, PMK_LEN); + data->finished = false; + // Set from security parameters + eap_tls_sec_prot_lib_message_init(&data->tls_recv); + eap_tls_sec_prot_lib_message_init(&data->tls_send); + data->int_timer = 0; + data->fin_timer = 0; + data->timer_running = false; + data->calculating = false; + return 0; +} + +static void tls_sec_prot_delete(sec_prot_t *prot) +{ + tls_sec_prot_int_t *data = tls_sec_prot_get(prot); + eap_tls_sec_prot_lib_message_free(&data->tls_send); + eap_tls_sec_prot_lib_message_free(&data->tls_recv); +} + +static void 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 void tls_sec_prot_create_response(sec_prot_t *prot, sec_prot_result_e result) +{ + tls_sec_prot_int_t *data = tls_sec_prot_get(prot); + + // Call state machine + sec_prot_result_set(&data->common, result); + prot->state_machine_call(prot); +} + +static int8_t tls_sec_prot_receive(sec_prot_t *prot, void *pdu, uint16_t size) +{ + tls_sec_prot_int_t *data = tls_sec_prot_get(prot); + + // Discards old data + eap_tls_sec_prot_lib_message_free(&data->tls_recv); + + data->tls_recv.data = pdu; + data->tls_recv.total_len = size; + + prot->state_machine(prot); + + return 0; +} + +static void tls_sec_prot_finished_send(sec_prot_t *prot) +{ + tls_sec_prot_int_t *data = tls_sec_prot_get(prot); + prot->timer_start(prot); + sec_prot_state_set(prot, &data->common, TLS_STATE_FINISHED); +} + +static void tls_sec_prot_timer_timeout(sec_prot_t *prot, uint16_t ticks) +{ + tls_sec_prot_int_t *data = tls_sec_prot_get(prot); + + if (data->timer_running) { + if (data->int_timer > ticks) { + data->int_timer -= ticks; + } else { + data->int_timer = 0; + } + + if (data->fin_timer > ticks) { + data->fin_timer -= ticks; + } else { + data->fin_timer = 0; + prot->state_machine_call(prot); + } + } + + if (data->calculating) { + prot->state_machine(prot); + } + + sec_prot_timer_timeout_handle(prot, &data->common, NULL, ticks); +} + +static void client_tls_sec_prot_state_machine(sec_prot_t *prot) +{ + tls_sec_prot_int_t *data = tls_sec_prot_get(prot); + int8_t result; + + switch (sec_prot_state_get(&data->common)) { + case TLS_STATE_INIT: + sec_prot_state_set(prot, &data->common, TLS_STATE_CREATE_REQ); + break; + + // Wait KMP-CREATE.request + case TLS_STATE_CREATE_REQ: + tr_debug("TLS start"); + + prot->timer_start(prot); + + prot->create_conf(prot, SEC_RESULT_OK); + + sec_prot_state_set(prot, &data->common, TLS_STATE_CONFIGURE); + + prot->state_machine_call(prot); + break; + + case TLS_STATE_CONFIGURE: + if (tls_sec_prot_tls_configure_and_connect(prot, false) < 0) { + sec_prot_result_set(&data->common, SEC_RESULT_CONF_ERROR); + sec_prot_state_set(prot, &data->common, TLS_STATE_FINISH); + return; + } + sec_prot_state_set(prot, &data->common, TLS_STATE_PROCESS); + prot->state_machine(prot); + break; + + case TLS_STATE_PROCESS: + result = tls_sec_prot_lib_process((tls_security_t *) &data->tls_sec_inst); + + if (result == TLS_SEC_PROT_LIB_CALCULATING) { + data->calculating = true; + prot->state_machine_call(prot); + return; + } else { + data->calculating = false; + } + + if (data->tls_send.data) { + prot->send(prot, data->tls_send.data, data->tls_send.handled_len); + eap_tls_sec_prot_lib_message_init(&data->tls_send); + } + + if (result != TLS_SEC_PROT_LIB_CONTINUE) { + if (result == TLS_SEC_PROT_LIB_ERROR) { + sec_prot_result_set(&data->common, SEC_RESULT_ERROR); + } + sec_prot_state_set(prot, &data->common, TLS_STATE_FINISH); + } + break; + + case TLS_STATE_FINISH: + tr_debug("TLS finish"); + + data->calculating = false; + + if (sec_prot_result_ok_check(&data->common)) { + sec_prot_keys_pmk_write(prot->sec_keys, data->new_pmk); + } + + // KMP-FINISHED.indication, + prot->finished_ind(prot, sec_prot_result_get(&data->common), prot->sec_keys); + sec_prot_state_set(prot, &data->common, TLS_STATE_FINISHED); + + tls_sec_prot_lib_free((tls_security_t *) &data->tls_sec_inst); + break; + + case TLS_STATE_FINISHED: + prot->timer_stop(prot); + prot->finished(prot); + break; + + default: + break; + } +} + +static void server_tls_sec_prot_state_machine(sec_prot_t *prot) +{ + tls_sec_prot_int_t *data = tls_sec_prot_get(prot); + int8_t result; + + switch (sec_prot_state_get(&data->common)) { + case TLS_STATE_INIT: + sec_prot_state_set(prot, &data->common, TLS_STATE_CLIENT_HELLO); + break; + + // Wait EAP request, Identity (starts handshake on supplicant) + case TLS_STATE_CLIENT_HELLO: + + tr_debug("TLS start"); + + prot->timer_start(prot); + + sec_prot_state_set(prot, &data->common, TLS_STATE_CREATE_RESP); + + // Send KMP-CREATE.indication + prot->create_ind(prot); + break; + + // Wait KMP-CREATE.response + case TLS_STATE_CREATE_RESP: + if (sec_prot_result_ok_check(&data->common)) { + sec_prot_state_set(prot, &data->common, TLS_STATE_CONFIGURE); + prot->state_machine_call(prot); + } else { + // Ready to be deleted + sec_prot_state_set(prot, &data->common, TLS_STATE_FINISHED); + } + break; + + case TLS_STATE_CONFIGURE: + if (tls_sec_prot_tls_configure_and_connect(prot, true) < 0) { + sec_prot_result_set(&data->common, SEC_RESULT_CONF_ERROR); + sec_prot_state_set(prot, &data->common, TLS_STATE_FINISH); + return; + } + sec_prot_state_set(prot, &data->common, TLS_STATE_PROCESS); + prot->state_machine(prot); + break; + + case TLS_STATE_PROCESS: + result = tls_sec_prot_lib_process((tls_security_t *) &data->tls_sec_inst); + + if (result == TLS_SEC_PROT_LIB_CALCULATING) { + data->calculating = true; + prot->state_machine_call(prot); + return; + } else { + data->calculating = false; + } + + if (data->tls_send.data) { + prot->send(prot, data->tls_send.data, data->tls_send.handled_len); + eap_tls_sec_prot_lib_message_init(&data->tls_send); + } + + if (result != TLS_SEC_PROT_LIB_CONTINUE) { + if (result == TLS_SEC_PROT_LIB_ERROR) { + sec_prot_result_set(&data->common, SEC_RESULT_ERROR); + } + sec_prot_state_set(prot, &data->common, TLS_STATE_FINISH); + } + break; + + case TLS_STATE_FINISH: + tr_debug("TLS finish"); + + data->calculating = false; + + if (sec_prot_result_ok_check(&data->common)) { + sec_prot_keys_pmk_write(prot->sec_keys, data->new_pmk); + } + + // KMP-FINISHED.indication, + prot->finished_ind(prot, sec_prot_result_get(&data->common), prot->sec_keys); + sec_prot_state_set(prot, &data->common, TLS_STATE_FINISHED); + + tls_sec_prot_lib_free((tls_security_t *) &data->tls_sec_inst); + break; + + case TLS_STATE_FINISHED: + prot->timer_stop(prot); + prot->finished(prot); + break; + + default: + break; + } +} + +static int16_t tls_sec_prot_tls_send(void *handle, const void *buf, size_t len) +{ + sec_prot_t *prot = handle; + tls_sec_prot_int_t *data = tls_sec_prot_get(prot); + + if (!data->tls_send.data) { + eap_tls_sec_prot_lib_message_allocate(&data->tls_send, prot->header_size, TLS_SEC_PROT_BUFFER_SIZE); + } + + memcpy(data->tls_send.data + prot->header_size + data->tls_send.handled_len, buf, len); + data->tls_send.handled_len += len; + + return len; +} + +static int16_t tls_sec_prot_tls_receive(void *handle, unsigned char *buf, size_t len) +{ + sec_prot_t *prot = handle; + tls_sec_prot_int_t *data = tls_sec_prot_get(prot); + + if (data->tls_recv.data && len > 0) { + + uint16_t copy_len = len; + bool all_copied = false; + + if ((uint16_t) copy_len >= data->tls_recv.total_len - data->tls_recv.handled_len) { + copy_len = data->tls_recv.total_len - data->tls_recv.handled_len; + all_copied = true; + } + + memcpy(buf, data->tls_recv.data + data->tls_recv.handled_len, copy_len); + + data->tls_recv.handled_len += copy_len; + + if (all_copied) { + eap_tls_sec_prot_lib_message_free(&data->tls_recv); + } + + return copy_len; + } + + return TLS_SEC_PROT_LIB_NO_DATA; +} + +static void tls_sec_prot_tls_export_keys(void *handle, const uint8_t *master_secret, const uint8_t *eap_tls_key_material) +{ + (void) master_secret; + + sec_prot_t *prot = handle; + tls_sec_prot_int_t *data = tls_sec_prot_get(prot); + + if (eap_tls_key_material) { + memcpy(data->new_pmk, eap_tls_key_material, PMK_LEN); + } + +#ifdef EXTRA_DEBUG_INFO + const uint8_t *print_data = eap_tls_key_material; + uint16_t print_data_len = 128; + while (true) { + tr_debug("EAP-TLS key material %s\n", trace_array(print_data, print_data_len > 32 ? 32 : print_data_len)); + if (print_data_len > 32) { + print_data_len -= 32; + print_data += 32; + } else { + break; + } + } +#endif +} + +static void tls_sec_prot_tls_set_timer(void *handle, uint32_t inter, uint32_t fin) +{ + sec_prot_t *prot = handle; + tls_sec_prot_int_t *data = tls_sec_prot_get(prot); + + if (fin == 0) { + data->timer_running = false; + data->int_timer = 0; + data->fin_timer = 0; + return; + } + + data->timer_running = true; + data->int_timer = inter / 100; + data->fin_timer = fin / 100; +} + +static int8_t tls_sec_prot_tls_get_timer(void *handle) +{ + sec_prot_t *prot = handle; + tls_sec_prot_int_t *data = tls_sec_prot_get(prot); + + if (!data->timer_running) { + return TLS_SEC_PROT_LIB_TIMER_CANCELLED; + } else if (data->fin_timer == 0) { + return TLS_SEC_PROT_LIB_TIMER_FIN_EXPIRY; + } else if (data->int_timer == 0) { + return TLS_SEC_PROT_LIB_TIMER_INT_EXPIRY; + } + + return TLS_SEC_PROT_LIB_TIMER_NO_EXPIRY; +} + +static int8_t tls_sec_prot_tls_configure_and_connect(sec_prot_t *prot, bool is_server) +{ + tls_sec_prot_int_t *data = tls_sec_prot_get(prot); + + if (tls_sec_prot_lib_init((tls_security_t *)&data->tls_sec_inst) < 0) { + return -1; + } + + tls_sec_prot_lib_set_cb_register((tls_security_t *)&data->tls_sec_inst, prot, + tls_sec_prot_tls_send, tls_sec_prot_tls_receive, tls_sec_prot_tls_export_keys, + tls_sec_prot_tls_set_timer, tls_sec_prot_tls_get_timer); + + if (tls_sec_prot_lib_connect((tls_security_t *)&data->tls_sec_inst, is_server, prot->sec_keys->certs) < 0) { + return -1; + } + + return 0; +} + +#endif /* HAVE_WS */ diff --git a/source/Security/protocols/tls_sec_prot/tls_sec_prot.h b/source/Security/protocols/tls_sec_prot/tls_sec_prot.h new file mode 100644 index 0000000000..5ed9621ea7 --- /dev/null +++ b/source/Security/protocols/tls_sec_prot/tls_sec_prot.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2019, 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 TLS_SEC_PROT_H_ +#define TLS_SEC_PROT_H_ + +/* + * TLS security protocol + * + */ + +#define TLS_SEC_PROT_BUFFER_SIZE 1200 // Send buffer size (maximum size for a TLS data for a flight) + +/** + * client_tls_sec_prot_register register client TLS protocol to KMP service + * + * \param service KMP service + * + * \return < 0 failure + * \return >= 0 success + */ +int8_t client_tls_sec_prot_register(kmp_service_t *service); + +/** + * server_tls_sec_prot_register register server TLS protocol to KMP service + * + * \param service KMP service + * + * \return < 0 failure + * \return >= 0 success + */ +int8_t server_tls_sec_prot_register(kmp_service_t *service); + + +#endif /* TLS_SEC_PROT_H_ */ diff --git a/source/Security/protocols/tls_sec_prot/tls_sec_prot_lib.c b/source/Security/protocols/tls_sec_prot/tls_sec_prot_lib.c new file mode 100644 index 0000000000..9ce586ba97 --- /dev/null +++ b/source/Security/protocols/tls_sec_prot/tls_sec_prot_lib.c @@ -0,0 +1,442 @@ +/* + * Copyright (c) 2019, 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 +#include "ns_types.h" +#include "ns_list.h" +#include "ns_trace.h" +#include "nsdynmemLIB.h" +#include "common_functions.h" +#include "Security/protocols/sec_prot_certs.h" +#include "Security/protocols/tls_sec_prot/tls_sec_prot_lib.h" +#include "mbedtls/sha256.h" +#include "mbedtls/error.h" +#include "mbedtls/platform.h" +#include "mbedtls/ssl_cookie.h" +#include "mbedtls/entropy.h" +#include "mbedtls/entropy_poll.h" +#include "mbedtls/ctr_drbg.h" +#include "mbedtls/ssl_ciphersuites.h" +#include "mbedtls/debug.h" + +#include "mbedtls/ssl_internal.h" + +#ifdef HAVE_WS + +#define TRACE_GROUP "tlsl" + +#define TLS_HANDSHAKE_TIMEOUT_MIN 25000 +#define TLS_HANDSHAKE_TIMEOUT_MAX 201000 + +//#define TLS_SEC_PROT_LIB_TLS_DEBUG // Enable mbed TLS debug traces + +struct tls_security_s { + mbedtls_ssl_config conf; /**< mbed TLS SSL configuration */ + mbedtls_ssl_context ssl; /**< mbed TLS SSL context */ + + mbedtls_ctr_drbg_context ctr_drbg; /**< mbed TLS pseudo random number generator context */ + mbedtls_entropy_context entropy; /**< mbed TLS entropy context */ + + mbedtls_x509_crt cacert; /**< CA certificate(s) */ + mbedtls_x509_crl crl; /**< Certificate Revocation List */ + mbedtls_x509_crt owncert; /**< Own certificate(s) */ + mbedtls_pk_context pkey; /**< Private key for own certificate */ + + uint8_t client_random[32]; /**< Client random (from Client Hello) */ + uint8_t server_random[32]; /**< Server random (from Server Hello) */ + + void *handle; /**< Handle provided in callbacks (defined by library user) */ + tls_sec_prot_lib_send *send; /**< Send callback */ + tls_sec_prot_lib_receive *receive; /**< Receive callback */ + tls_sec_prot_lib_export_keys *export_keys; /**< Export keys callback */ + tls_sec_prot_lib_set_timer *set_timer; /**< Set timer callback */ + tls_sec_prot_lib_get_timer *get_timer; /**< Get timer callback */ +}; + +static void tls_sec_prot_lib_ssl_set_timer(void *ctx, uint32_t int_ms, uint32_t fin_ms); +static int tls_sec_prot_lib_ssl_get_timer(void *ctx); +static int tls_sec_lib_entropy_poll(void *data, unsigned char *output, size_t len, size_t *olen); +static int tls_sec_prot_lib_ssl_send(void *ctx, const unsigned char *buf, size_t len); +static int tls_sec_prot_lib_ssl_recv(void *ctx, unsigned char *buf, size_t len); +static int tls_sec_prot_lib_ssl_export_keys(void *ctx, const unsigned char *ms, + const unsigned char *kb, size_t maclen, size_t keylen, size_t ivlen); +static void tls_sec_prot_lib_random_extract(tls_security_t *sec, const uint8_t *buf, uint16_t len); +#ifdef TLS_SEC_PROT_LIB_TLS_DEBUG +static void tls_sec_prot_lib_debug(void *ctx, int level, const char *file, int line, const char *string); +#endif + +int8_t tls_sec_prot_lib_init(tls_security_t *sec) +{ + const char *pers = "ws_tls"; + + mbedtls_ssl_init(&sec->ssl); + mbedtls_ssl_config_init(&sec->conf); + mbedtls_ctr_drbg_init(&sec->ctr_drbg); + mbedtls_entropy_init(&sec->entropy); + + mbedtls_x509_crt_init(&sec->cacert); + mbedtls_x509_crl_init(&sec->crl); + mbedtls_x509_crt_init(&sec->owncert); + mbedtls_pk_init(&sec->pkey); + + if (mbedtls_entropy_add_source(&sec->entropy, tls_sec_lib_entropy_poll, NULL, + 128, MBEDTLS_ENTROPY_SOURCE_WEAK) < 0) { + return -1; + } + + if ((mbedtls_ctr_drbg_seed(&sec->ctr_drbg, mbedtls_entropy_func, &sec->entropy, + (const unsigned char *) pers, strlen(pers))) != 0) { + return -1; + } + + return 0; +} + +uint16_t tls_sec_prot_lib_size(void) +{ + return sizeof(tls_security_t); +} + +void tls_sec_prot_lib_set_cb_register(tls_security_t *sec, void *handle, + tls_sec_prot_lib_send *send, tls_sec_prot_lib_receive *receive, + tls_sec_prot_lib_export_keys *export_keys, tls_sec_prot_lib_set_timer *set_timer, + tls_sec_prot_lib_get_timer *get_timer) +{ + if (!sec) { + return; + } + + sec->handle = handle; + sec->send = send; + sec->receive = receive; + sec->export_keys = export_keys; + sec->set_timer = set_timer; + sec->get_timer = get_timer; +} + +void tls_sec_prot_lib_free(tls_security_t *sec) +{ + mbedtls_x509_crt_free(&sec->cacert); + mbedtls_x509_crl_free(&sec->crl); + mbedtls_x509_crt_free(&sec->owncert); + mbedtls_pk_free(&sec->pkey); + mbedtls_entropy_free(&sec->entropy); + mbedtls_ctr_drbg_free(&sec->ctr_drbg); + mbedtls_ssl_config_free(&sec->conf); + mbedtls_ssl_free(&sec->ssl); +} + +static int tls_sec_prot_lib_configure_certificates(tls_security_t *sec, const sec_prot_certs_t *certs) +{ + if (!certs->own_cert_chain.cert[0]) { + return -1; + } + + // Parse own certificate chain + uint8_t index = 0; + while (true) { + uint16_t cert_len; + uint8_t *cert = sec_prot_certs_cert_get(&certs->own_cert_chain, index, &cert_len); + if (!cert) { + if (index == 0) { + return -1; + } + break; + } + if (mbedtls_x509_crt_parse(&sec->owncert, cert, cert_len) < 0) { + return -1; + } + index++; + } + + // Parse private key + uint8_t key_len; + uint8_t *key = sec_prot_certs_priv_key_get(&certs->own_cert_chain, &key_len); + if (!key) { + return -1; + } + + if (mbedtls_pk_parse_key(&sec->pkey, key, key_len, NULL, 0) < 0) { + return -1; + } + + // Configure own certificate chain and private key + if (mbedtls_ssl_conf_own_cert(&sec->conf, &sec->owncert, &sec->pkey) != 0) { + return -1; + } + + // Parse trusted certificate chains + ns_list_foreach(cert_chain_entry_t, entry, &certs->trusted_cert_chain_list) { + index = 0; + while (true) { + uint16_t cert_len; + uint8_t *cert = sec_prot_certs_cert_get(entry, index, &cert_len); + if (!cert) { + if (index == 0) { + return -1; + } + break; + } + if (mbedtls_x509_crt_parse(&sec->cacert, cert, cert_len) < 0) { + return -1; + } + index++; + } + } + + // Parse certificate revocation lists + ns_list_foreach(cert_revocat_list_entry_t, entry, &certs->cert_revocat_lists) { + uint16_t crl_len; + uint8_t *crl = sec_prot_certs_revocat_list_get(entry, &crl_len); + if (!crl) { + break; + } + if (mbedtls_x509_crl_parse(&sec->crl, crl, crl_len) < 0) { + return -1; + } + } + + // Configure trusted certificates and certificate revocation lists + mbedtls_ssl_conf_ca_chain(&sec->conf, &sec->cacert, &sec->crl); + + // Certificate verify required on both client and server + mbedtls_ssl_conf_authmode(&sec->conf, MBEDTLS_SSL_VERIFY_REQUIRED); + + return 0; +} + +int8_t tls_sec_prot_lib_connect(tls_security_t *sec, bool is_server, const sec_prot_certs_t *certs) +{ + if (!sec) { + return -1; + } + + int endpoint = MBEDTLS_SSL_IS_CLIENT; + if (is_server) { + endpoint = MBEDTLS_SSL_IS_SERVER; + } + + if ((mbedtls_ssl_config_defaults(&sec->conf, endpoint, MBEDTLS_SSL_TRANSPORT_STREAM, 0)) != 0) { + return -1; + } + + // Configure random number generator + mbedtls_ssl_conf_rng(&sec->conf, mbedtls_ctr_drbg_random, &sec->ctr_drbg); + +#ifdef MBEDTLS_ECP_RESTARTABLE + // Set ECC calculation maximum operations (affects only client) + mbedtls_ecp_set_max_ops(ECC_CALCULATION_MAX_OPS); +#endif + + if ((mbedtls_ssl_setup(&sec->ssl, &sec->conf)) != 0) { + return -1; + } + + // Set calbacks + mbedtls_ssl_set_bio(&sec->ssl, sec, tls_sec_prot_lib_ssl_send, tls_sec_prot_lib_ssl_recv, NULL); + mbedtls_ssl_set_timer_cb(&sec->ssl, sec, tls_sec_prot_lib_ssl_set_timer, tls_sec_prot_lib_ssl_get_timer); + + // Configure certificates, keys and certificate revocation list + if (tls_sec_prot_lib_configure_certificates(sec, certs) != 0) { + tr_debug("security credential configure failed"); + return -1; + } + + + // Configure ciphersuites + static const int sec_suites[] = { + MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8, + 0, + 0, + 0 + }; + mbedtls_ssl_conf_ciphersuites(&sec->conf, sec_suites); + +#ifdef TLS_SEC_PROT_LIB_TLS_DEBUG + mbedtls_ssl_conf_dbg(&sec->conf, tls_sec_prot_lib_debug, sec); + mbedtls_debug_set_threshold(5); +#endif + + // Export keys callback + mbedtls_ssl_conf_export_keys_cb(&sec->conf, tls_sec_prot_lib_ssl_export_keys, sec); + + mbedtls_ssl_conf_min_version(&sec->conf, MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MAJOR_VERSION_3); + mbedtls_ssl_conf_max_version(&sec->conf, MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MAJOR_VERSION_3); + + return 0; +} + +#ifdef TLS_SEC_PROT_LIB_TLS_DEBUG +static void tls_sec_prot_lib_debug(void *ctx, int level, const char *file, int line, const char *string) +{ + (void) ctx; + tr_debug("%i %s %i %s", level, file, line, string); +} +#endif + +int8_t tls_sec_prot_lib_process(tls_security_t *sec) +{ + int ret = -1; + + while (ret != MBEDTLS_ERR_SSL_WANT_READ) { + ret = mbedtls_ssl_handshake_step(&sec->ssl); + +#ifdef MBEDTLS_ECP_RESTARTABLE + if (ret == MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS /* || ret == MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS */) { + return TLS_SEC_PROT_LIB_CALCULATING; + } +#endif + + if (ret && (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE)) { + return TLS_SEC_PROT_LIB_ERROR; + } + + if (sec->ssl.state == MBEDTLS_SSL_HANDSHAKE_OVER) { + return TLS_SEC_PROT_LIB_HANDSHAKE_OVER; + } + } + + return TLS_SEC_PROT_LIB_CONTINUE; +} + +static void tls_sec_prot_lib_ssl_set_timer(void *ctx, uint32_t int_ms, uint32_t fin_ms) +{ + tls_security_t *sec = (tls_security_t *)ctx; + sec->set_timer(sec->handle, int_ms, fin_ms); +} + +static int tls_sec_prot_lib_ssl_get_timer(void *ctx) +{ + tls_security_t *sec = (tls_security_t *)ctx; + return sec->get_timer(sec->handle); +} + +static int tls_sec_prot_lib_ssl_send(void *ctx, const unsigned char *buf, size_t len) +{ + tls_security_t *sec = (tls_security_t *)ctx; + + tls_sec_prot_lib_random_extract(sec, buf, len); + + return sec->send(sec->handle, buf, len); +} + +static int tls_sec_prot_lib_ssl_recv(void *ctx, unsigned char *buf, size_t len) +{ + tls_security_t *sec = (tls_security_t *)ctx; + int16_t ret = sec->receive(sec->handle, buf, len); + + if (ret == TLS_SEC_PROT_LIB_NO_DATA) { + return MBEDTLS_ERR_SSL_WANT_READ; + } + + tls_sec_prot_lib_random_extract(sec, buf, len); + + return ret; +} + +static void tls_sec_prot_lib_random_extract(tls_security_t *sec, const uint8_t *buf, uint16_t len) +{ + static uint8_t *random_ptr = NULL; + static uint8_t step = 0; + + if (step == 0) { + if (*buf++ != 22 && len < 5) { + return; + } + + buf++; // version + buf++; + + buf++; // length + buf++; + + step++; + + if (len < 6) { + return; + } + } + + if (step == 1) { + if (*buf == 0x01) { // Client hello + random_ptr = sec->client_random; + } else if (*buf == 0x02) { // Server hello + random_ptr = sec->server_random; + } else { + return; + } + buf++; + + buf++; // length + buf++; + buf++; + + buf++; // version + buf++; + + memcpy(random_ptr, buf, 32); + + step = 0; + } +} + +static int tls_sec_prot_lib_ssl_export_keys(void *ctx, const unsigned char *ms, + const unsigned char *kb, size_t maclen, + size_t keylen, size_t ivlen) +{ + (void) kb; + (void) maclen; + (void) keylen; + (void) ivlen; + + tls_security_t *sec = (tls_security_t *)ctx; + + uint8_t eap_tls_key_material[128]; + uint8_t random[64]; + memcpy(random, sec->client_random, 32); + memcpy(&random[32], sec->server_random, 32); + + sec->ssl.handshake->tls_prf(ms, 48, "client EAP encryption", + random, 64, eap_tls_key_material, 128); + + sec->export_keys(sec->handle, ms, eap_tls_key_material); + return 0; +} + +static int tls_sec_lib_entropy_poll(void *ctx, unsigned char *output, size_t len, size_t *olen) +{ + (void)ctx; + + char *c = (char *)ns_dyn_mem_temporary_alloc(len); + if (!c) { + return MBEDTLS_ERR_ENTROPY_SOURCE_FAILED; + } + memset(c, 0, len); + for (uint16_t i = 0; i < len; i++) { + *(c + i) = (char)randLIB_get_8bit(); + } + memmove(output, c, len); + *olen = len; + + ns_dyn_mem_free(c); + return (0); +} + +#endif /* HAVE_WS */ + diff --git a/source/Security/protocols/tls_sec_prot/tls_sec_prot_lib.h b/source/Security/protocols/tls_sec_prot/tls_sec_prot_lib.h new file mode 100644 index 0000000000..fc4a40b9f0 --- /dev/null +++ b/source/Security/protocols/tls_sec_prot/tls_sec_prot_lib.h @@ -0,0 +1,169 @@ +/* + * Copyright (c) 2019, 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 TLS_SEC_PROT_LIB_H_ +#define TLS_SEC_PROT_LIB_H_ + +/* + * TLS security protocol library to connect to mbed TLS + * + */ + +typedef struct tls_security_s tls_security_t; + +typedef enum { + TLS_SEC_PROT_LIB_ERROR = -2, + TLS_SEC_PROT_LIB_NO_DATA = -1, + TLS_SEC_PROT_LIB_CONTINUE = 0, + TLS_SEC_PROT_LIB_CALCULATING, + TLS_SEC_PROT_LIB_HANDSHAKE_OVER, +} tls_sec_prot_lib_ret_e; + +typedef enum { + TLS_SEC_PROT_LIB_TIMER_CANCELLED = -1, + TLS_SEC_PROT_LIB_TIMER_NO_EXPIRY = 0, + TLS_SEC_PROT_LIB_TIMER_INT_EXPIRY = 1, + TLS_SEC_PROT_LIB_TIMER_FIN_EXPIRY = 2, +} tls_sec_prot_lib_timer_e; + +// Maximum operations made on one round of ECC calculation +#define ECC_CALCULATION_MAX_OPS 200 + +/** + * tls_sec_prot_lib_init initialize security library + * + * \param sec security library instance + * + * \return < 0 failure + * \return >= 0 success + */ +int8_t tls_sec_prot_lib_init(tls_security_t *sec); + +/** + * tls_sec_prot_lib_size get security library instance size + * + * \return size + */ +uint16_t tls_sec_prot_lib_size(void); + +/** + * tls_sec_prot_lib_send send data callback + * + * \param handle caller defined handle + * \param buf buffer to be send + * \param len length of the buffer + * + * \return length of the send data + */ +typedef int16_t tls_sec_prot_lib_send(void *handle, const void *buf, size_t len); + +/** + * tls_sec_prot_lib_receive receive data callback + * + * \param handle caller defined handle + * \param buf receive buffer + * \param len receive buffer length + * + * \return length of the received data written to receive buffer + * \return TLS_SEC_PROT_LIB_NO_DATA no more data received + */ +typedef int16_t tls_sec_prot_lib_receive(void *handle, unsigned char *buf, size_t len); + +/** + * tls_sec_prot_lib_set_timer set timer callback + * + * \param handle caller defined handle + * \param inter intermediate timeout + * \param fin final timeout + * + */ +typedef void tls_sec_prot_lib_set_timer(void *handle, uint32_t inter, uint32_t fin); + +/** + * tls_sec_prot_lib_get_timer get timer callback + * + * \param handle caller defined handle + * + * \return TLS_SEC_PROT_LIB_TIMER_CANCELLED timer cancelled + * \return TLS_SEC_PROT_LIB_TIMER_FIN_EXPIRY final timeout has expired + * \return TLS_SEC_PROT_LIB_TIMER_INT_EXPIRY intermediate timeout has expired + * \retunt TLS_SEC_PROT_LIB_TIMER_NO_EXPIRY timer has not expired + * + */ +typedef int8_t tls_sec_prot_lib_get_timer(void *handle); + +/** + * tls_sec_prot_lib_export_keys export key material after handshake is completed + * + * \param handle caller defined handle + * \param master_secret TLS master secret, 48 bytes + * \param eap_tls_key_material EAP TLS key material, 128 bytes + * + */ +typedef void tls_sec_prot_lib_export_keys(void *handle, const uint8_t *master_secret, const uint8_t *eap_tls_key_material); + +/** + * tls_sec_prot_lib_set_cb_register register callbacks to library + * + * \param sec security library instance + * \param handle caller defined handle + * \param send send data callback + * \param receive receive data callback + * \param export_keys export keys callback + * \param set_timer set timer callback + * \param get_timer get timer callback + * + */ +void tls_sec_prot_lib_set_cb_register(tls_security_t *sec, void *handle, + tls_sec_prot_lib_send *send, tls_sec_prot_lib_receive *receive, + tls_sec_prot_lib_export_keys *export_keys, tls_sec_prot_lib_set_timer *set_timer, + tls_sec_prot_lib_get_timer *get_timer); + +/** + * tls_sec_prot_lib_free free security library internal data (e.g. TLS data) + * + * \param sec security library instance + * + */ +void tls_sec_prot_lib_free(tls_security_t *sec); + +/** + * tls_sec_prot_lib_connect start TLS handshake + * + * \param sec security library instance + * \param is_server TRUE if TLS server, FALSE for TLS client + * \param certs certificates + * + * \return < 0 failure + * \return >= 0 success + */ +int8_t tls_sec_prot_lib_connect(tls_security_t *sec, bool is_server, const sec_prot_certs_t *certs); + +/** + * tls_sec_prot_lib_process process TLS (call e.g. after incoming message) + * + * \param sec Security library instance + * + * \return TLS_SEC_PROT_LIB_ERROR failure, failure, stop TLS negotiation + * \return TLS_SEC_PROT_LIB_CONTINUE continue processing (send output message) + * \return TLS_SEC_PROT_LIB_CALCULATING calculation ongoing, call process again + * \return TLS_SEC_PROT_LIB_HANDSHAKE_OVER handshake completed successfully + * + */ +int8_t tls_sec_prot_lib_process(tls_security_t *sec); + +#endif /* TLS_SEC_PROT_LIB_H_ */ diff --git a/source/Service_Libs/CCM_lib/mbedOS/aes_mbedtls.c b/source/Service_Libs/CCM_lib/mbedOS/aes_mbedtls.c index 1f94ba0aa6..36bdd0f590 100644 --- a/source/Service_Libs/CCM_lib/mbedOS/aes_mbedtls.c +++ b/source/Service_Libs/CCM_lib/mbedOS/aes_mbedtls.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006-2017, Arm Limited and affiliates. + * Copyright (c) 2006-2018, Arm Limited and affiliates. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/source/Service_Libs/CCM_lib/mbedOS/aes_mbedtls_adapter.c b/source/Service_Libs/CCM_lib/mbedOS/aes_mbedtls_adapter.c index e0b0514faf..afc9132db8 100644 --- a/source/Service_Libs/CCM_lib/mbedOS/aes_mbedtls_adapter.c +++ b/source/Service_Libs/CCM_lib/mbedOS/aes_mbedtls_adapter.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2018, Arm Limited and affiliates. + * Copyright (c) 2015-2019, Arm Limited and affiliates. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -83,7 +83,9 @@ arm_aes_context_t *arm_aes_start(const uint8_t key[static 16]) arm_aes_context_t *context = mbed_tls_context_get(); if (context) { mbedtls_aes_init(&context->ctx); - mbedtls_aes_setkey_enc(&context->ctx, key, 128); + if (0 != mbedtls_aes_setkey_enc(&context->ctx, key, 128)) { + return NULL; + } } return context; } diff --git a/source/Service_Libs/Neighbor_cache/neighbor_cache.c b/source/Service_Libs/Neighbor_cache/neighbor_cache.c index 63258e70a8..4f057a5574 100644 --- a/source/Service_Libs/Neighbor_cache/neighbor_cache.c +++ b/source/Service_Libs/Neighbor_cache/neighbor_cache.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014-2017, Arm Limited and affiliates. + * Copyright (c) 2014-2018, Arm Limited and affiliates. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/source/Service_Libs/SHA256_Lib/ns_sha256.c b/source/Service_Libs/SHA256_Lib/ns_sha256.c index 7973bfc4f2..10fce9c06a 100644 --- a/source/Service_Libs/SHA256_Lib/ns_sha256.c +++ b/source/Service_Libs/SHA256_Lib/ns_sha256.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006-2017, Arm Limited and affiliates. + * Copyright (c) 2006-2018, Arm Limited and affiliates. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/source/Service_Libs/Trickle/trickle.c b/source/Service_Libs/Trickle/trickle.c index 6c4c28f922..4640b49371 100644 --- a/source/Service_Libs/Trickle/trickle.c +++ b/source/Service_Libs/Trickle/trickle.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014-2017, Arm Limited and affiliates. + * Copyright (c) 2014-2018, Arm Limited and affiliates. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/source/Service_Libs/blacklist/blacklist.c b/source/Service_Libs/blacklist/blacklist.c index 5deb976aed..a614ed12c1 100644 --- a/source/Service_Libs/blacklist/blacklist.c +++ b/source/Service_Libs/blacklist/blacklist.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, Arm Limited and affiliates. + * Copyright (c) 2017-2018, Arm Limited and affiliates. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/source/Service_Libs/etx/etx.c b/source/Service_Libs/etx/etx.c index 735a6e1774..c7b3b63a32 100644 --- a/source/Service_Libs/etx/etx.c +++ b/source/Service_Libs/etx/etx.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014-2018, Arm Limited and affiliates. + * Copyright (c) 2014-2019, Arm Limited and affiliates. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -23,7 +23,7 @@ #include "platform/arm_hal_phy.h" #include "net_interface.h" -#include "Core/include/address.h" +#include "Core/include/ns_address_internal.h" #include "MLE/mle.h" #include "NWK_INTERFACE/Include/protocol.h" #include "NWK_INTERFACE/Include/protocol_stats.h" diff --git a/source/Service_Libs/fhss/channel_functions.c b/source/Service_Libs/fhss/channel_functions.c new file mode 100644 index 0000000000..1d2d0c372c --- /dev/null +++ b/source/Service_Libs/fhss/channel_functions.c @@ -0,0 +1,229 @@ +/* + * Copyright (c) 2018-2019, 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" + +#define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k)))) + +#define final(a,b,c) \ +{ \ + c ^= b; c -= rot(b, 14); \ + a ^= c; a -= rot(c, 11); \ + b ^= a; b -= rot(a, 25); \ + c ^= b; c -= rot(b, 16); \ + a ^= c; a -= rot(c, 4); \ + b ^= a; b -= rot(a, 14); \ + c ^= b; c -= rot(b, 24); \ +} + +#define mix(a,b,c) \ +{ \ + a -= c; a ^= rot(c, 4); c += b; \ + b -= a; b ^= rot(a, 6); a += c; \ + c -= b; c ^= rot(b, 8); b += a; \ + a -= c; a ^= rot(c, 16); c += b; \ + b -= a; b ^= rot(a, 19); a += c; \ + c -= b; c ^= rot(b, 4); b += a; \ +} + +static uint32_t global_seed = 1; + + +uint16_t tr51_calc_nearest_prime_number(uint16_t start_value) +{ + if (start_value < 2) { + return 0; + } + uint16_t divider = start_value - 1; + while (start_value) { + if (start_value % divider--) { + if (divider == 1) { + break; + } + } else { + divider = ++start_value - 1; + } + } + return start_value; +} + +static void tr51_seed_rand(uint32_t seed) +{ + if (!seed) { + seed = 1; + } + global_seed = seed; +} + +static int32_t tr51_get_rand(void) +{ + uint32_t random_val = ((global_seed * 1103515245) + 12345) & 0x7fffffff; + global_seed = random_val; + return random_val; +} + +/** + * @brief Calculate channel table based on TR51 channel function. + * @param number_of_channels Number of channels in table. + * @param nearest_prime Nearest prime number. Must be equal to or larger than number_of_channels. + * @param channel_table Output channel table. Has to be at least nearest_prime in length. + */ +static void tr51_calculate_channel_table(uint16_t number_of_channels, uint16_t nearest_prime, int16_t *channel_table) +{ + int32_t i, j, k; + tr51_seed_rand(1); + for (i = 0; i < nearest_prime; i++) { + channel_table[i] = -1; + } + for (i = 0; i < number_of_channels; i++) { + j = tr51_get_rand() % number_of_channels; + k = 0; + while (k <= i) { + if (j == channel_table[k]) { + j = tr51_get_rand() % number_of_channels; + k = 0; + } else { + k = k + 1; + } + } + channel_table[i] = j; + } +} + +static void tr51_compute_cfd(uint8_t *mac, uint8_t *first_element, uint8_t *step_size, uint16_t channel_table_length) +{ + *first_element = (mac[5] ^ mac[6] ^ mac[7]) % channel_table_length; + *step_size = (mac[7] % (channel_table_length - 1)) + 1; +} + +static uint8_t tr51_find_excluded(int32_t channel, uint32_t *excluded_channels) +{ + if (excluded_channels != NULL) { + uint8_t index = channel / 32; + channel %= 32; + if (excluded_channels[index] & ((uint32_t)1 << channel)) { + return true; + } + } + return false; +} + +/** + * @brief Calculate hopping sequence for a specific peer using tr51 channel function. + * @param channel_table Used channel table. + * @param channel_table_length Length of the used channel table. + * @param first_element Start generated by CFD function. + * @param step_size Step size generated by CFD function. + * @param output_table Output hopping sequence table. + * @param excluded_channels Bit mask where excluded channels are set to 1. + * @return Number of channels in sequence. + */ +static uint16_t tr51_calculate_hopping_sequence(int16_t *channel_table, uint16_t channel_table_length, uint8_t first_element, uint8_t step_size, uint8_t *output_table, uint32_t *excluded_channels) +{ + uint16_t cntr = channel_table_length; + uint8_t index = first_element; + uint8_t slot = 0; + while (cntr--) { + if (channel_table[index] != -1) { + if (tr51_find_excluded(channel_table[index], excluded_channels) == false) { + output_table[slot] = channel_table[index]; + slot++; + } + } + index += step_size; + index %= channel_table_length; + } + return slot; +} + +static uint32_t dh1cf_hashword(const uint32_t *key, size_t key_length, uint32_t init_value) +{ + uint32_t a, b, c; + a = b = c = 0xdeadbeef + (((uint32_t)key_length) << 2) + init_value; + while (key_length > 3) { + a += key[0]; + b += key[1]; + c += key[2]; + mix(a, b, c); + key_length -= 3; + key += 3; + } + switch (key_length) { + case 3: + c += key[2]; + /* fall through */ + case 2: + b += key[1]; + /* fall through */ + case 1: + a += key[0]; + final(a, b, c); + /* fall through */ + case 0: + break; + } + return c; +} + +int32_t dh1cf_get_uc_channel_index(uint16_t slot_number, uint8_t *mac, int16_t number_of_channels) +{ + int32_t channel_number; + uint32_t key[3]; + key[0] = (uint32_t)slot_number; + key[1] = mac[4] << 24 | mac[5] << 16 | mac[6] << 8 | mac[7]; + key[2] = mac[0] << 24 | mac[1] << 16 | mac[2] << 8 | mac[3]; + channel_number = dh1cf_hashword(key, 3, 0) % number_of_channels; + return channel_number; +} + +int32_t dh1cf_get_bc_channel_index(uint16_t slot_number, uint16_t bsi, int16_t number_of_channels) +{ + int32_t channel_number; + uint32_t key[3]; + key[0] = (uint32_t)slot_number; + key[1] = bsi << 16; + key[2] = 0; + channel_number = dh1cf_hashword(key, 3, 0) % number_of_channels; + return channel_number; +} + +int tr51_init_channel_table(int16_t *channel_table, int16_t number_of_channels) +{ + uint16_t nearest_prime = tr51_calc_nearest_prime_number(number_of_channels); + tr51_calculate_channel_table(number_of_channels, nearest_prime, channel_table); + return 0; +} + +int32_t tr51_get_uc_channel_index(int16_t *channel_table, uint8_t *output_table, uint16_t slot_number, uint8_t *mac, int16_t number_of_channels, uint32_t *excluded_channels) +{ + uint16_t nearest_prime = tr51_calc_nearest_prime_number(number_of_channels); + uint8_t first_element; + uint8_t step_size; + tr51_compute_cfd(mac, &first_element, &step_size, nearest_prime); + tr51_calculate_hopping_sequence(channel_table, nearest_prime, first_element, step_size, output_table, excluded_channels); + return output_table[slot_number]; +} + +int32_t tr51_get_bc_channel_index(int16_t *channel_table, uint8_t *output_table, uint16_t slot_number, uint16_t bsi, int16_t number_of_channels, uint32_t *excluded_channels) +{ + uint16_t nearest_prime = tr51_calc_nearest_prime_number(number_of_channels); + uint8_t mac[8] = {0, 0, 0, 0, 0, 0, (uint8_t)(bsi >> 8), (uint8_t)bsi}; + uint8_t first_element; + uint8_t step_size; + tr51_compute_cfd(mac, &first_element, &step_size, nearest_prime); + tr51_calculate_hopping_sequence(channel_table, nearest_prime, first_element, step_size, output_table, excluded_channels); + return output_table[slot_number]; +} diff --git a/source/Service_Libs/fhss/fhss.c b/source/Service_Libs/fhss/fhss.c index 400e458557..8ee00ed7f6 100644 --- a/source/Service_Libs/fhss/fhss.c +++ b/source/Service_Libs/fhss/fhss.c @@ -45,6 +45,7 @@ static int8_t fhss_beacon_create_tasklet(fhss_structure_t *fhss_structure); static void fhss_beacon_tasklet_func(arm_event_s *event); static int fhss_beacon_periodic_start(fhss_structure_t *fhss_structure, uint32_t time_to_first_beacon); static void fhss_beacon_periodic_stop(fhss_structure_t *fhss_structure); +static int fhss_reset_synch_monitor(fhss_synch_monitor_s *synch_monitor); fhss_structure_t *fhss_enable(fhss_api_t *fhss_api, const fhss_configuration_t *fhss_configuration, const fhss_timer_t *fhss_timer, fhss_statistics_t *fhss_statistics) { @@ -80,6 +81,7 @@ fhss_structure_t *fhss_enable(fhss_api_t *fhss_api, const fhss_configuration_t * if (!fhss_struct->bs->fhss_configuration.fhss_max_synch_interval) { fhss_struct->bs->fhss_configuration.fhss_max_synch_interval = 240; } + fhss_reset_synch_monitor(&fhss_struct->bs->synch_monitor); ns_list_init(&fhss_struct->fhss_failed_tx_list); fhss_struct->own_hop = 0xff; fhss_reset(fhss_struct); @@ -263,6 +265,11 @@ static int fhss_update_txrx_slots(fhss_structure_t *fhss_structure) tx_slot_up_limit += (tx_slot_length * 2); } } +#ifdef FHSS_CHANNEL_DEBUG_CBS + if (fhss_bc_switch && fhss_structure->bs->tx_allowed != tx_allowed) { + fhss_bc_switch(); + } +#endif /*FHSS_CHANNEL_DEBUG_CBS*/ fhss_structure->bs->tx_allowed = tx_allowed; return 0; } @@ -735,7 +742,7 @@ static int16_t fhss_synch_state_set_callback(const fhss_api_t *api, fhss_states memcpy(fhss_structure->synch_parent, beacon_info->source_address, 8); platform_enter_critical(); // Calculate time since the Beacon was received - uint32_t elapsed_time = fhss_structure->fhss_api->read_timestamp(fhss_structure->fhss_api) - beacon_info->timestamp; + uint32_t elapsed_time = fhss_structure->callbacks.read_timestamp(fhss_structure->fhss_api) - beacon_info->timestamp; // Synchronize to given PAN fhss_beacon_received(fhss_structure, beacon_info->synch_info, elapsed_time); platform_exit_critical(); @@ -978,7 +985,6 @@ static int fhss_tx_handle_callback(const fhss_api_t *api, bool is_broadcast_addr if (frame_type == FHSS_DATA_FRAME) { if (is_broadcast_addr == true) { if (fhss_is_current_channel_broadcast(fhss_structure) == false) { - tr_info("Broadcast on UC channel -> Back to queue"); return -3; } } @@ -1059,7 +1065,7 @@ static uint8_t *fhss_beacon_encode_raw(uint8_t *buffer, const fhss_synchronizati return buffer; } -static void fhss_beacon_build(fhss_structure_t *fhss_structure, uint8_t *dest) +static void fhss_beacon_build(fhss_structure_t *fhss_structure, uint8_t *dest, uint32_t tx_time) { fhss_synchronization_beacon_payload_s temp_payload; platform_enter_critical(); @@ -1075,8 +1081,12 @@ static void fhss_beacon_build(fhss_structure_t *fhss_structure, uint8_t *dest) temp_payload.number_of_broadcast_channels = config->fhss_number_of_bc_channels; temp_payload.number_of_tx_slots = config->fhss_number_of_tx_slots; temp_payload.time_since_last_beacon = 0; // XXX not available yet - uint32_t tx_time = fhss_get_tx_time(fhss_structure, 71, 0, 0); - temp_payload.processing_delay = fhss_structure->bs->fhss_configuration.fhss_tuning_parameters.tx_processing_delay + tx_time; + uint32_t time_to_tx = 0; + uint32_t cur_time = fhss_structure->callbacks.read_timestamp(fhss_structure->fhss_api); + if (cur_time < tx_time) { + time_to_tx = tx_time - cur_time; + } + temp_payload.processing_delay = fhss_structure->bs->fhss_configuration.fhss_tuning_parameters.tx_processing_delay + time_to_tx; temp_payload.superframe_length = config->fhss_superframe_length; temp_payload.number_of_superframes_per_channel = config->fhss_number_of_superframes; platform_exit_critical(); @@ -1091,7 +1101,7 @@ static int16_t fhss_write_synch_info_callback(const fhss_api_t *api, uint8_t *pt if (!fhss_structure || !ptr || (frame_type != FHSS_SYNCH_FRAME)) { return -1; } - fhss_beacon_build(fhss_structure, ptr); + fhss_beacon_build(fhss_structure, ptr, tx_time); return FHSS_SYNCH_INFO_LENGTH; } @@ -1123,6 +1133,9 @@ static bool fhss_data_tx_fail_callback(const fhss_api_t *api, uint8_t handle, in if (fhss_structure->fhss_state == FHSS_UNSYNCHRONIZED) { return false; } +#ifdef FHSS_CHANNEL_DEBUG + tr_info("TX failed on ch: %u", debug_destination_channel); +#endif /*FHSS_CHANNEL_DEBUG*/ // Channel retries are disabled -> return if (fhss_structure->bs->fhss_configuration.fhss_number_of_channel_retries == 0) { return false; @@ -1162,7 +1175,7 @@ static void fhss_receive_frame_callback(const fhss_api_t *api, uint16_t pan_id, fhss_update_synch_parent_address(fhss_structure); platform_enter_critical(); // Calculate time since the Beacon was received - uint32_t elapsed_time = api->read_timestamp(api) - timestamp; + uint32_t elapsed_time = fhss_structure->callbacks.read_timestamp(api) - timestamp; // Synchronize to given PAN fhss_beacon_received(fhss_structure, synch_info, elapsed_time); platform_exit_critical(); @@ -1422,6 +1435,6 @@ static void fhss_beacon_tasklet_func(arm_event_s *event) } // Update Beacon info lifetimes else if (event->event_type == FHSS_UPDATE_SYNCH_INFO_STORAGE) { - fhss_update_beacon_info_lifetimes(fhss_structure, fhss_read_timestamp_cb(fhss_structure->fhss_api)); + fhss_update_beacon_info_lifetimes(fhss_structure, fhss_structure->callbacks.read_timestamp(fhss_structure->fhss_api)); } } diff --git a/source/Service_Libs/fhss/fhss_channel.c b/source/Service_Libs/fhss/fhss_channel.c index d799d910c3..8ad6c3cf52 100644 --- a/source/Service_Libs/fhss/fhss_channel.c +++ b/source/Service_Libs/fhss/fhss_channel.c @@ -27,8 +27,14 @@ #define TRACE_GROUP "fhss" -// Enable this flag to use channel traces -// #define FHSS_CHANNEL_DEBUG +#ifdef FHSS_CHANNEL_DEBUG_CBS +void (*fhss_uc_switch)(void) = NULL; +void (*fhss_bc_switch)(void) = NULL; +#endif /*FHSS_CHANNEL_DEBUG_CBS*/ + +#ifdef FHSS_CHANNEL_DEBUG +uint8_t debug_destination_channel = 0; +#endif /*FHSS_CHANNEL_DEBUG*/ static uint8_t fhss_get_bc_index(const fhss_structure_t *fhss_structure); @@ -138,13 +144,22 @@ bool fhss_change_to_next_channel(fhss_structure_t *fhss_structure) next_channel = channel_list_get_channel(fhss_structure->bs->fhss_configuration.channel_mask, channel_index_tmp); fhss_structure->rx_channel = next_channel; -#ifdef FHSS_CHANNEL_DEBUG + if (fhss_is_current_channel_broadcast(fhss_structure) == true) { +#ifdef FHSS_CHANNEL_DEBUG tr_info("%"PRIu32" BC %u", fhss_structure->platform_functions.fhss_get_timestamp(fhss_structure->fhss_api), next_channel); - } else { - tr_info("%"PRIu32" UC %u", fhss_structure->platform_functions.fhss_get_timestamp(fhss_structure->fhss_api), next_channel); - } #endif /*FHSS_CHANNEL_DEBUG*/ + } else { +#ifdef FHSS_CHANNEL_DEBUG_CBS + if (fhss_uc_switch) { + fhss_uc_switch(); + } +#endif /*FHSS_CHANNEL_DEBUG_CBS*/ +#ifdef FHSS_CHANNEL_DEBUG + tr_info("%"PRIu32" UC %u", fhss_structure->platform_functions.fhss_get_timestamp(fhss_structure->fhss_api), next_channel); +#endif /*FHSS_CHANNEL_DEBUG*/ + } + fhss_structure->callbacks.change_channel(fhss_structure->fhss_api, next_channel); return broadcast_channel; } @@ -231,7 +246,7 @@ int fhss_change_to_tx_channel(fhss_structure_t *fhss_structure, uint8_t *destina uint8_t destination_channel = fhss_get_destination_channel(fhss_structure, destination_address); fhss_structure->callbacks.change_channel(fhss_structure->fhss_api, destination_channel); #ifdef FHSS_CHANNEL_DEBUG - tr_info("TX channel: %u", destination_channel); + debug_destination_channel = destination_channel; #endif /*FHSS_CHANNEL_DEBUG*/ } } diff --git a/source/Service_Libs/fhss/fhss_channel.h b/source/Service_Libs/fhss/fhss_channel.h index 42094aee0a..af35ba6475 100644 --- a/source/Service_Libs/fhss/fhss_channel.h +++ b/source/Service_Libs/fhss/fhss_channel.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2017, Arm Limited and affiliates. + * Copyright (c) 2016-2018, Arm Limited and affiliates. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -24,4 +24,18 @@ int fhss_change_to_tx_channel(fhss_structure_t *fhss_structure, uint8_t *destina int fhss_change_to_parent_channel(fhss_structure_t *fhss_structure); int fhss_change_to_rx_channel(fhss_structure_t *fhss_structure); + +// Enable this flag to use channel traces +// #define FHSS_CHANNEL_DEBUG +// Enable this flag to use debug callbacks +// #define FHSS_CHANNEL_DEBUG_CBS + +#ifdef FHSS_CHANNEL_DEBUG +extern uint8_t debug_destination_channel; +#endif /*FHSS_CHANNEL_DEBUG*/ +#ifdef FHSS_CHANNEL_DEBUG_CBS +extern void (*fhss_uc_switch)(void); +extern void (*fhss_bc_switch)(void); +#endif /*FHSS_CHANNEL_DEBUG_CBS*/ + #endif /*FHSS_CHANNEL_H_*/ diff --git a/source/Service_Libs/fhss/fhss_ws.c b/source/Service_Libs/fhss/fhss_ws.c new file mode 100644 index 0000000000..04f7bfa050 --- /dev/null +++ b/source/Service_Libs/fhss/fhss_ws.c @@ -0,0 +1,844 @@ +/* + * Copyright (c) 2018-2019, 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 "fhss_api.h" +#include "fhss_config.h" +#include "fhss.h" +#include "fhss_common.h" +#include "channel_list.h" +#include "channel_functions.h" +#include "fhss_ws.h" +#include "nsdynmemLIB.h" +#include "common_functions.h" +#include "eventOS_callback_timer.h" +#include "randLIB.h" +#include "ns_trace.h" +#include "platform/arm_hal_interrupt.h" +#include + +#define TRACE_GROUP "fhss" + +// Enable this flag to use channel traces +// #define FHSS_CHANNEL_DEBUG +// Enable this flag to use debug callbacks +// #define FHSS_CHANNEL_DEBUG_CBS + +#ifdef FHSS_CHANNEL_DEBUG_CBS +void (*fhss_uc_switch)(void) = NULL; +void (*fhss_bc_switch)(void) = NULL; +#endif /*FHSS_CHANNEL_DEBUG_CBS*/ +// Seconds to milliseconds +#define S_TO_MS(x) (((int32_t)x)*1000) +// Milliseconds to seconds +#define MS_TO_S(x) divide_integer(x, 1000) +// Seconds to microseconds +#define S_TO_US(x) (((int32_t)x)*1000000) +// Microseconds to seconds +#define US_TO_S(x) divide_integer(x, 1000000) +// Milliseconds to microseconds +#define MS_TO_US(x) (((int32_t)x)*1000) +// Microseconds to milliseconds +#define US_TO_MS(x) divide_integer(x, 1000) +// Milliseconds to nanoseconds +#define MS_TO_NS(x) (((int32_t)x)*1000000) +// Nanoseconds to milliseconds +#define NS_TO_MS(x) divide_integer(x, 1000000) +// Microseconds to nanoseconds +#define US_TO_NS(x) (((int32_t)x)*1000) +// Nanoseconds to microseconds +#define NS_TO_US(x) divide_integer(x, 1000) +#define DEF_2E24 0x1000000 +#define IE_HEADER_LENGTH_MASK 0x007f +#define IE_HEADER_ID_MASK 0x7f80 +#define WH_IE_ID 0x2a +#define WH_SUB_ID_UTT 1 +#define WH_SUB_ID_BT 2 + +#ifdef HAVE_WS + +struct ws_ie_t { + uint8_t *content_ptr; + unsigned length: 7; + uint8_t id; +}; + +static int fhss_ws_manage_channel_table_allocation(fhss_structure_t *fhss_structure, uint16_t channel_count); +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 uint8_t fhss_set_txrx_slot_length(fhss_structure_t *fhss_structure); + +// This function supports rounding up +static int32_t divide_integer(int32_t dividend, int32_t divisor) +{ + if (dividend < 0) { + return (dividend - divisor / 2) / divisor; + } + return (dividend + divisor / 2) / divisor; +} + +static uint32_t get_remaining_slots_us(fhss_structure_t *fhss_structure, void (*callback)(const fhss_api_t *api, uint16_t), uint32_t max_timeout_us) +{ + uint32_t remaining_time_us = fhss_structure->platform_functions.fhss_get_remaining_slots(callback, fhss_structure->fhss_api); + // When remaining time goes negative, use 0. + if (remaining_time_us > max_timeout_us) { + remaining_time_us = 0; + } + return remaining_time_us; +} + +void fhss_ws_start_timer(fhss_structure_t *fhss_structure, uint32_t time, void (*callback)(const fhss_api_t *fhss_api, uint16_t)) +{ + // Number of millisecond slots in timeout(us) + int32_t time_in_ms = divide_integer(time, 1000); + // Reduce the compensation (per millisecond) from timeout. + time -= NS_TO_US(time_in_ms * fhss_structure->ws->drift_per_millisecond_ns); + fhss_start_timer(fhss_structure, time, callback); +} + +fhss_structure_t *fhss_ws_enable(fhss_api_t *fhss_api, const fhss_ws_configuration_t *fhss_configuration, const fhss_timer_t *fhss_timer) +{ + if (!fhss_api || !fhss_configuration || !fhss_timer) { + tr_err("Invalid FHSS enable configuration"); + return NULL; + } + int channel_count = channel_list_count_channels(fhss_configuration->channel_mask); + if (channel_count <= 0) { + // There must be at least one configured channel in channel list + return NULL; + } + fhss_structure_t *fhss_struct = fhss_allocate_instance(fhss_api, fhss_timer); + if (!fhss_struct) { + return NULL; + } + fhss_struct->ws = ns_dyn_mem_alloc(sizeof(fhss_ws_t)); + if (!fhss_struct->ws) { + fhss_free_instance(fhss_api); + return NULL; + } + memset(fhss_struct->ws, 0, sizeof(fhss_ws_t)); + if (fhss_ws_manage_channel_table_allocation(fhss_struct, channel_count)) { + ns_dyn_mem_free(fhss_struct->ws); + fhss_free_instance(fhss_api); + tr_error("Failed to allocate channel tables"); + return NULL; + } + + fhss_struct->fhss_event_timer = eventOS_callback_timer_register(fhss_event_timer_cb); + fhss_struct->ws->fhss_configuration = *fhss_configuration; + fhss_struct->number_of_channels = channel_count; + fhss_struct->own_hop = 0xff; + fhss_struct->rx_channel = fhss_configuration->unicast_fixed_channel; + fhss_struct->ws->min_synch_interval = DEFAULT_MIN_SYNCH_INTERVAL; + fhss_set_txrx_slot_length(fhss_struct); + ns_list_init(&fhss_struct->fhss_failed_tx_list); + return fhss_struct; +} + +static int fhss_ws_manage_channel_table_allocation(fhss_structure_t *fhss_structure, uint16_t channel_count) +{ + // Must allocate channel table for TR51 + if (!fhss_structure->ws->tr51_channel_table && !fhss_structure->ws->tr51_output_table) { + fhss_structure->ws->tr51_channel_table = ns_dyn_mem_alloc(sizeof(int16_t) * tr51_calc_nearest_prime_number(channel_count)); + if (!fhss_structure->ws->tr51_channel_table) { + return -1; + } + fhss_structure->ws->tr51_output_table = ns_dyn_mem_alloc(sizeof(int16_t) * channel_count); + if (!fhss_structure->ws->tr51_output_table) { + ns_dyn_mem_free(fhss_structure->ws->tr51_channel_table); + return -1; + } + tr51_init_channel_table(fhss_structure->ws->tr51_channel_table, channel_count); + } + return 0; +} + +static uint8_t fhss_set_txrx_slot_length(fhss_structure_t *fhss_structure) +{ + uint8_t number_of_tx_slots = ((fhss_structure->ws->fhss_configuration.fhss_broadcast_interval - fhss_structure->ws->fhss_configuration.fhss_bc_dwell_interval) / WS_MAX_TXRX_SLOT_LEN_MS) / 2; + if (!number_of_tx_slots) { + return 0; + } + fhss_structure->ws->txrx_slot_length_ms = (fhss_structure->ws->fhss_configuration.fhss_broadcast_interval - fhss_structure->ws->fhss_configuration.fhss_bc_dwell_interval) / (number_of_tx_slots * 2); + return number_of_tx_slots; +} + +static int32_t fhss_ws_calc_bc_channel(fhss_structure_t *fhss_structure) +{ + int32_t next_channel = fhss_structure->ws->fhss_configuration.broadcast_fixed_channel; + + 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); + 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) { + next_channel = dh1cf_get_bc_channel_index(fhss_structure->ws->bc_slot, fhss_structure->ws->fhss_configuration.bsi, fhss_structure->number_of_channels); + fhss_structure->ws->bc_slot++; + } 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); + } + } +#ifdef FHSS_CHANNEL_DEBUG + tr_info("%"PRIu32" BC %u %u", fhss_structure->callbacks.read_timestamp(fhss_structure->fhss_api), next_channel, fhss_structure->ws->bc_slot); +#endif /*FHSS_CHANNEL_DEBUG*/ + return next_channel; +} + +static void fhss_broadcast_handler(const fhss_api_t *fhss_api, uint16_t delay) +{ + int32_t next_channel; + fhss_structure_t *fhss_structure = fhss_get_object_with_api(fhss_api); + if (!fhss_structure) { + return; + } + + if (fhss_structure->ws->fhss_configuration.fhss_bc_dwell_interval == 0 || fhss_structure->ws->fhss_configuration.fhss_broadcast_interval == 0) { + // stop broadcast schedule + fhss_structure->ws->is_on_bc_channel = false; + return; + } + if (fhss_structure->ws->is_on_bc_channel == false) { + fhss_ws_start_timer(fhss_structure, MS_TO_US(fhss_structure->ws->fhss_configuration.fhss_bc_dwell_interval) - (delay * fhss_structure->platform_functions.fhss_resolution_divider), fhss_broadcast_handler); + fhss_structure->ws->is_on_bc_channel = true; + next_channel = fhss_structure->ws->bc_channel = fhss_ws_calc_bc_channel(fhss_structure); + + /* Start timer with random timeout to trigger broadcast TX queue poll event. + * Min random is 1/50 of the channel dwell interval. + * Max random is 1/10 of the channel dwell interval. + * Event timer resolution is 50us. + */ + uint32_t bc_dwell_us = MS_TO_US(fhss_structure->ws->fhss_configuration.fhss_bc_dwell_interval); + uint16_t bc_min_random = (bc_dwell_us / 50) / 50; + uint16_t bc_max_random = (bc_dwell_us / 10) / 50; + eventOS_callback_timer_start(fhss_structure->fhss_event_timer, randLIB_get_random_in_range(bc_min_random, bc_max_random)); + } else { + uint32_t timeout = MS_TO_US(fhss_structure->ws->fhss_configuration.fhss_broadcast_interval - fhss_structure->ws->fhss_configuration.fhss_bc_dwell_interval); + fhss_ws_start_timer(fhss_structure, timeout - (delay * fhss_structure->platform_functions.fhss_resolution_divider), fhss_broadcast_handler); + fhss_structure->ws->is_on_bc_channel = false; + // Should return to own (unicast) listening channel after broadcast channel + next_channel = fhss_structure->rx_channel; + /* Start timer with random timeout to trigger unicast TX queue poll event. + * Min random is 1/30 of the TX slot length. + * Max random is 1/10 of the TX slot length. + * Event timer resolution is 50us. + */ + uint32_t txrx_slot_length_us = MS_TO_US(fhss_structure->ws->txrx_slot_length_ms); + uint16_t uc_min_random = (txrx_slot_length_us / 30) / 50; + uint16_t uc_max_random = (txrx_slot_length_us / 10) / 50; + bool tx_allowed = fhss_ws_check_tx_allowed(fhss_structure); + if (!tx_allowed) { + uc_min_random += (txrx_slot_length_us) / 50; + uc_max_random += (txrx_slot_length_us) / 50; + } + eventOS_callback_timer_start(fhss_structure->fhss_event_timer, randLIB_get_random_in_range(uc_min_random, uc_max_random)); + +#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*/ + } + fhss_structure->callbacks.change_channel(fhss_structure->fhss_api, next_channel); +#ifdef FHSS_CHANNEL_DEBUG_CBS + if (fhss_bc_switch) { + fhss_bc_switch(); + } +#endif /*FHSS_CHANNEL_DEBUG_CBS*/ +} + +static int own_floor(float value) +{ + return (int)value; +} + +static int own_ceil(float value) +{ + int ivalue = (int)value; + if (value == (float)ivalue) { + return ivalue; + } + return ivalue + 1; +} + +static void fhss_event_timer_cb(int8_t timer_id, uint16_t slots) +{ + (void) slots; + uint16_t queue_size = 0; + fhss_structure_t *fhss_structure = fhss_get_object_with_timer_id(timer_id); + + + if (fhss_structure->ws->is_on_bc_channel == true) { + queue_size = fhss_structure->callbacks.read_tx_queue_size(fhss_structure->fhss_api, true); + } else { + // On unicast, start timer to trigger polling event on next TX slot + uint32_t delay_between_tx_slots_us = MS_TO_US(fhss_structure->ws->txrx_slot_length_ms) * 2; + if (delay_between_tx_slots_us < get_remaining_slots_us(fhss_structure, fhss_broadcast_handler, MS_TO_US(fhss_structure->ws->fhss_configuration.fhss_broadcast_interval))) { + eventOS_callback_timer_start(fhss_structure->fhss_event_timer, delay_between_tx_slots_us / 50); + } + queue_size = fhss_structure->callbacks.read_tx_queue_size(fhss_structure->fhss_api, false); + } + if (queue_size) { + fhss_structure->callbacks.tx_poll(fhss_structure->fhss_api); + } +} + +static uint32_t fhss_ws_calculate_ufsi(fhss_structure_t *fhss_structure, uint32_t tx_time) +{ + uint8_t dwell_time = fhss_structure->ws->fhss_configuration.fhss_uc_dwell_interval; + uint16_t cur_slot = fhss_structure->ws->uc_slot; + if (cur_slot == 0) { + cur_slot = fhss_structure->number_of_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 time_to_tx = 0; + uint32_t cur_time = fhss_structure->callbacks.read_timestamp(fhss_structure->fhss_api); + if (cur_time < tx_time) { + time_to_tx = US_TO_MS(tx_time - cur_time); + } + uint64_t ms_since_seq_start = (cur_slot * dwell_time) + (dwell_time - remaining_time_ms) + time_to_tx; + uint32_t seq_length = 0x10000; + if (fhss_structure->ws->fhss_configuration.ws_uc_channel_function == WS_TR51CF) { + ms_since_seq_start %= (dwell_time * fhss_structure->number_of_channels); + seq_length = fhss_structure->number_of_channels; + } + return own_floor((float)(ms_since_seq_start * DEF_2E24) / (seq_length * dwell_time)); +} + +static uint32_t fhss_ws_calculate_broadcast_interval_offset(fhss_structure_t *fhss_structure, uint32_t tx_time) +{ + uint8_t dwell_time = fhss_structure->ws->fhss_configuration.fhss_bc_dwell_interval; + uint32_t broadcast_interval = fhss_structure->ws->fhss_configuration.fhss_broadcast_interval; + uint32_t remaining_time_ms = US_TO_MS(get_remaining_slots_us(fhss_structure, fhss_broadcast_handler, MS_TO_US(fhss_structure->ws->fhss_configuration.fhss_broadcast_interval))); + if (fhss_structure->ws->is_on_bc_channel == true) { + remaining_time_ms += (broadcast_interval - dwell_time); + } + uint32_t time_to_tx = 0; + uint32_t cur_time = fhss_structure->callbacks.read_timestamp(fhss_structure->fhss_api); + if (cur_time < tx_time) { + time_to_tx = US_TO_MS(tx_time - cur_time); + } + return (broadcast_interval - remaining_time_ms) + time_to_tx; +} + +static uint16_t fhss_ws_calculate_destination_slot(fhss_ws_neighbor_timing_info_t *neighbor_timing_info, uint32_t tx_time) +{ + uint_fast24_t ufsi = neighbor_timing_info->uc_timing_info.ufsi; + uint32_t ufsi_timestamp = neighbor_timing_info->uc_timing_info.utt_rx_timestamp; + uint8_t dwell_time = neighbor_timing_info->uc_timing_info.unicast_dwell_interval; + uint32_t seq_length = 0x10000; + if (neighbor_timing_info->uc_timing_info.unicast_channel_function == WS_TR51CF) { + seq_length = neighbor_timing_info->uc_timing_info.unicast_number_of_channels; + } + uint32_t dest_ms_since_seq_start = own_ceil((float)((uint64_t)ufsi * seq_length * dwell_time) / DEF_2E24); + return (own_floor(((float)(US_TO_MS(tx_time - ufsi_timestamp) + dest_ms_since_seq_start) / dwell_time)) % seq_length); +} + +static uint32_t fhss_ws_get_sf_timeout_callback(fhss_structure_t *fhss_structure) +{ + return MS_TO_US(fhss_structure->ws->fhss_configuration.fhss_uc_dwell_interval); +} + +static int16_t fhss_ws_synch_state_set_callback(const fhss_api_t *api, fhss_states fhss_state, uint16_t pan_id) +{ + (void) pan_id; + fhss_structure_t *fhss_structure = fhss_get_object_with_api(api); + if (!fhss_structure) { + return -1; + } + if (fhss_state == FHSS_SYNCHRONIZED) { + uint32_t fhss_broadcast_interval = fhss_structure->ws->fhss_configuration.fhss_broadcast_interval; + uint8_t fhss_bc_dwell_interval = fhss_structure->ws->fhss_configuration.fhss_bc_dwell_interval; + + // Start broadcast schedule when BC intervals are known + if (fhss_broadcast_interval && fhss_bc_dwell_interval) { + fhss_broadcast_handler(fhss_structure->fhss_api, 0); + } + // Start unicast schedule + if ((fhss_structure->ws->fhss_configuration.ws_uc_channel_function != WS_FIXED_CHANNEL)) { + fhss_ws_update_uc_channel_callback(fhss_structure); + fhss_ws_start_timer(fhss_structure, MS_TO_US(fhss_structure->ws->fhss_configuration.fhss_uc_dwell_interval), fhss_unicast_handler); + fhss_structure->ws->unicast_timer_running = true; + } + } + + fhss_structure->fhss_state = fhss_state; + int16_t current_channel = fhss_structure->rx_channel; + if (fhss_structure->ws->is_on_bc_channel == true) { + current_channel = fhss_structure->ws->bc_channel; + } + return current_channel; +} + +static void fhss_ws_update_uc_channel_callback(fhss_structure_t *fhss_structure) +{ + uint8_t mac_address[8]; + int32_t next_channel = fhss_structure->rx_channel; + fhss_structure->callbacks.read_mac_address(fhss_structure->fhss_api, mac_address); + 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_channels, NULL); + if (++fhss_structure->ws->uc_slot == fhss_structure->number_of_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_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) { + next_channel = fhss_structure->rx_channel = fhss_structure->ws->fhss_configuration.vendor_defined_cf(fhss_structure->fhss_api, fhss_structure->ws->bc_slot, mac_address, fhss_structure->ws->fhss_configuration.bsi, fhss_structure->number_of_channels); + } + } + // Do not switch unicast channel when broadcast channel is active. + if (fhss_structure->ws->is_on_bc_channel == true) { + return; + } +#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*/ + fhss_structure->callbacks.change_channel(fhss_structure->fhss_api, next_channel); +#ifdef FHSS_CHANNEL_DEBUG_CBS + if (fhss_uc_switch) { + fhss_uc_switch(); + } +#endif /*FHSS_CHANNEL_DEBUG_CBS*/ +} + +static int fhss_ws_tx_handle_callback(const fhss_api_t *api, bool is_broadcast_addr, uint8_t *destination_address, int frame_type, uint16_t frame_length, uint8_t phy_header_length, uint8_t phy_tail_length, uint32_t tx_time) +{ + (void) frame_type; + (void) frame_length; + (void) phy_header_length; + (void) phy_tail_length; + fhss_structure_t *fhss_structure = fhss_get_object_with_api(api); + if (!fhss_structure) { + return -1; + } + if (is_broadcast_addr) { + return 0; + } + // Do not allow unicast destination on broadcast channel + if (!is_broadcast_addr && (fhss_structure->ws->is_on_bc_channel == true)) { + return -1; + } + // Check TX/RX slot + if (!fhss_ws_check_tx_allowed(fhss_structure)) { + return -1; + } + if (fhss_structure->fhss_state == FHSS_SYNCHRONIZED) { + fhss_ws_neighbor_timing_info_t *neighbor_timing_info = fhss_structure->ws->get_neighbor_info(api, destination_address); + if (!neighbor_timing_info) { + tr_err("FHSS: No neighbor info: %s", trace_array(destination_address, 8)); + return -2; + } + // TODO: WS bootstrap has to store neighbors number of channels + if (neighbor_timing_info->uc_timing_info.unicast_number_of_channels == 0) { + neighbor_timing_info->uc_timing_info.unicast_number_of_channels = fhss_structure->number_of_channels; + } + uint16_t destination_slot = fhss_ws_calculate_destination_slot(neighbor_timing_info, tx_time); + 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); + } 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_timing_info.unicast_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); + } else { + tr_err("FHSS: vendor defined configuration failed"); + return -1; + } + } +#ifdef FHSS_CHANNEL_DEBUG + tr_debug("TX channel: %u %u", tx_channel, destination_slot + 1); +#endif /*FHSS_CHANNEL_DEBUG*/ + fhss_structure->callbacks.change_channel(fhss_structure->fhss_api, tx_channel); + } + return 0; +} + +static bool fhss_check_bad_channel(fhss_structure_t *fhss_structure, uint8_t handle) +{ + // When operating on fixed channel, we must ignore the bad channel check. + if (fhss_structure->ws->fhss_configuration.ws_uc_channel_function == WS_FIXED_CHANNEL) { + return true; + } + fhss_failed_tx_t *failed_tx = fhss_failed_handle_find(fhss_structure, handle); + if (!failed_tx) { + return true; + } + if (failed_tx->bad_channel == fhss_structure->rx_channel) { + return false; + } + return true; +} + +static bool fhss_ws_check_tx_allowed(fhss_structure_t *fhss_structure) +{ + // Ignore TX/RX slots + if (fhss_structure->own_hop == 0xff) { + return true; + } + // Currently on broadcast channel + if (fhss_structure->ws->is_on_bc_channel == true) { + return true; + } + uint8_t number_of_tx_slots = fhss_set_txrx_slot_length(fhss_structure); + // Allow transmission when broadcast interval is very short comparing to MAX slot length + if (!number_of_tx_slots) { + return true; + } + + uint32_t remaining_time_ms = get_remaining_slots_us(fhss_structure, fhss_broadcast_handler, MS_TO_US(fhss_structure->ws->fhss_configuration.fhss_broadcast_interval)) / 1000; + uint32_t tx_slot_begin = (fhss_structure->ws->fhss_configuration.fhss_broadcast_interval - fhss_structure->ws->fhss_configuration.fhss_bc_dwell_interval) - (fhss_structure->ws->txrx_slot_length_ms * (fhss_structure->own_hop & 1)); + uint32_t rx_slot_begin = tx_slot_begin - fhss_structure->ws->txrx_slot_length_ms; + uint8_t n_o_tx_slots = number_of_tx_slots; + + while (n_o_tx_slots--) { + if ((remaining_time_ms <= tx_slot_begin) && (remaining_time_ms > rx_slot_begin)) { + return true; + } + tx_slot_begin -= (2 * fhss_structure->ws->txrx_slot_length_ms); + rx_slot_begin = tx_slot_begin - fhss_structure->ws->txrx_slot_length_ms; + } + + return false; +} + +static bool fhss_ws_check_tx_time(fhss_structure_t *fhss_structure, uint16_t tx_length, uint8_t phy_header_length, uint8_t phy_tail_length) +{ + if (!fhss_structure->ws->fhss_configuration.fhss_broadcast_interval || !fhss_structure->ws->fhss_configuration.fhss_bc_dwell_interval) { + return true; + } + uint32_t tx_time = fhss_get_tx_time(fhss_structure, tx_length, phy_header_length, phy_tail_length); + uint32_t time_to_bc_channel_us = get_remaining_slots_us(fhss_structure, fhss_broadcast_handler, MS_TO_US(fhss_structure->ws->fhss_configuration.fhss_broadcast_interval)); + if (tx_time > time_to_bc_channel_us) { + return false; + } + return true; +} + +static bool fhss_ws_check_tx_conditions_callback(const fhss_api_t *api, bool is_broadcast_addr, uint8_t handle, int frame_type, uint16_t frame_length, uint8_t phy_header_length, uint8_t phy_tail_length) +{ + (void) frame_type; + fhss_structure_t *fhss_structure = fhss_get_object_with_api(api); + if (!fhss_structure) { + return true; + } + // Do not allow broadcast destination on unicast channel + if (is_broadcast_addr && (fhss_structure->ws->is_on_bc_channel == false)) { + return false; + } + // Do not allow unicast destination on broadcast channel + if (!is_broadcast_addr && (fhss_structure->ws->is_on_bc_channel == true)) { + return false; + } + // This condition will check that message is not sent on bad channel + if (fhss_check_bad_channel(fhss_structure, handle) == false) { + return false; + } + // Check that there is enough unicast TX time before next broadcast channel. We try to avoid delaying the change to broadcast channel because of ongoing transmission. + if (!is_broadcast_addr && !fhss_ws_check_tx_time(fhss_structure, frame_length, phy_header_length, phy_tail_length)) { + return false; + } + // Check TX/RX slot for unicast frames + if (!is_broadcast_addr && !fhss_ws_check_tx_allowed(fhss_structure)) { + return false; + } + return true; +} + +static uint8_t fhss_ws_ie_header_discover(uint8_t *header_ptr, uint16_t length, struct ws_ie_t *header_ie, uint8_t sub_id) +{ + struct ws_ie_t ie_element; + uint8_t *sub_id_ptr; + uint16_t ie_dummy; + while (length > 2) { + ie_dummy = common_read_16_bit_inverse(header_ptr); + ie_element.length = (ie_dummy & IE_HEADER_LENGTH_MASK); + ie_element.id = ((ie_dummy & IE_HEADER_ID_MASK) >> 7); + ie_element.content_ptr = header_ptr + 2; + sub_id_ptr = ie_element.content_ptr; + if (ie_element.length && (header_ie->id == ie_element.id) && (*sub_id_ptr == sub_id)) { + sub_id_ptr++; + ie_element.length--; + header_ie->content_ptr = sub_id_ptr; + header_ie->length = ie_element.length; + return ie_element.length; + } + length -= ie_element.length + 2; + header_ptr += ie_element.length + 2; + } + return 0; +} + +static int16_t fhss_ws_write_synch_info_callback(const fhss_api_t *api, uint8_t *ptr, uint8_t length, int frame_type, uint32_t tx_time) +{ + fhss_structure_t *fhss_structure = fhss_get_object_with_api(api); + if (!fhss_structure || !ptr || (frame_type != FHSS_DATA_FRAME)) { + return -1; + } + platform_enter_critical(); + struct ws_ie_t header_ie; + header_ie.id = WH_IE_ID; + if (fhss_ws_ie_header_discover(ptr, length, &header_ie, WH_SUB_ID_UTT)) { + uint32_t ufsi = fhss_ws_calculate_ufsi(fhss_structure, tx_time); + common_write_24_bit_inverse(ufsi, header_ie.content_ptr + 1); + } + if (fhss_ws_ie_header_discover(ptr, length, &header_ie, WH_SUB_ID_BT)) { + uint32_t broadcast_interval_offset = fhss_ws_calculate_broadcast_interval_offset(fhss_structure, tx_time); + common_write_16_bit_inverse(fhss_structure->ws->bc_slot, header_ie.content_ptr); + common_write_24_bit_inverse(broadcast_interval_offset, header_ie.content_ptr + 2); + } + platform_exit_critical(); + //TODO return destination channel here + return fhss_structure->rx_channel; +} + +static void fhss_ws_data_tx_done_callback(const fhss_api_t *api, bool waiting_ack, bool tx_completed, uint8_t handle) +{ + fhss_structure_t *fhss_structure = fhss_get_object_with_api(api); + if (!fhss_structure) { + return; + } + if (fhss_structure->fhss_state == FHSS_SYNCHRONIZED) { + if (waiting_ack == false) { + if (fhss_structure->ws->is_on_bc_channel == false) { + fhss_structure->callbacks.change_channel(fhss_structure->fhss_api, fhss_structure->rx_channel); + } else { + fhss_structure->callbacks.change_channel(fhss_structure->fhss_api, fhss_structure->ws->bc_channel); + } + } + } + // Buffer was successfully transmitted. Remove stored failure handle if exists. + if (tx_completed == true) { + fhss_failed_tx_t *fhss_failed_tx = fhss_failed_handle_find(fhss_structure, handle); + if (fhss_failed_tx) { + fhss_failed_handle_remove(fhss_structure, handle); + } + } +} + +static bool fhss_ws_data_tx_fail_callback(const fhss_api_t *api, uint8_t handle, int frame_type) +{ + fhss_structure_t *fhss_structure = fhss_get_object_with_api(api); + if (!fhss_structure) { + return false; + } + // Only use channel retries when device is synchronized + if (fhss_structure->fhss_state == FHSS_UNSYNCHRONIZED) { + return false; + } + + // Use channel retries only for data frames + if (FHSS_DATA_FRAME != frame_type) { + return false; + } + + fhss_failed_tx_t *fhss_failed_tx = fhss_failed_handle_find(fhss_structure, handle); + if (fhss_failed_tx) { + fhss_failed_tx->retries_done++; + if (fhss_failed_tx->retries_done >= WS_NUMBER_OF_CHANNEL_RETRIES) { + // No more retries. Return false to stop retransmitting. + fhss_failed_handle_remove(fhss_structure, handle); + return false; + } + fhss_failed_tx->bad_channel = fhss_structure->rx_channel; + } else { + // Create new failure handle and return true to retransmit + fhss_failed_handle_add(fhss_structure, handle, fhss_structure->rx_channel); + } + return true; +} + +static void fhss_ws_receive_frame_callback(const fhss_api_t *api, uint16_t pan_id, uint8_t *source_address, uint32_t timestamp, uint8_t *synch_info, int frame_type) +{ + (void) api; + (void) pan_id; + (void) source_address; + (void) timestamp; + (void) synch_info; + (void) frame_type; +} + +static bool fhss_ws_is_broadcast_channel_callback(const fhss_api_t *api) +{ + fhss_structure_t *fhss_structure = fhss_get_object_with_api(api); + if (!fhss_structure) { + return true; + } + return fhss_structure->ws->is_on_bc_channel; +} + +static bool fhss_ws_use_broadcast_queue_cb(const fhss_api_t *api, bool is_broadcast_addr, int frame_type) +{ + (void) frame_type; + fhss_structure_t *fhss_structure = fhss_get_object_with_api(api); + if (!fhss_structure) { + return false; + } + // Broadcast packets are stored in broadcast queue + return is_broadcast_addr; +} + +static void fhss_unicast_handler(const fhss_api_t *fhss_api, uint16_t delay) +{ + uint32_t timeout = 0; + fhss_structure_t *fhss_structure = fhss_get_object_with_api(fhss_api); + if (!fhss_structure) { + return; + } + timeout = fhss_ws_get_sf_timeout_callback(fhss_structure); + if (!timeout) { + fhss_stop_timer(fhss_structure, fhss_unicast_handler); + fhss_structure->ws->unicast_timer_running = false; + return; + } + fhss_ws_start_timer(fhss_structure, timeout - (delay * fhss_structure->platform_functions.fhss_resolution_divider), fhss_unicast_handler); + fhss_structure->ws->unicast_timer_running = true; + fhss_ws_update_uc_channel_callback(fhss_structure); + // Unless we have broadcast schedule, we have to poll unicast queue when changing channel. This is randomized by the unicast schedule. + if (!fhss_structure->ws->fhss_configuration.fhss_broadcast_interval || !fhss_structure->ws->fhss_configuration.fhss_bc_dwell_interval) { + if (fhss_structure->callbacks.read_tx_queue_size(fhss_structure->fhss_api, false)) { + fhss_structure->callbacks.tx_poll(fhss_structure->fhss_api); + } + } +} + +int fhss_ws_set_callbacks(fhss_structure_t *fhss_structure) +{ + // Set external API + fhss_structure->fhss_api->is_broadcast_channel = &fhss_ws_is_broadcast_channel_callback; + fhss_structure->fhss_api->use_broadcast_queue = &fhss_ws_use_broadcast_queue_cb; + fhss_structure->fhss_api->tx_handle = &fhss_ws_tx_handle_callback; + fhss_structure->fhss_api->check_tx_conditions = &fhss_ws_check_tx_conditions_callback; + fhss_structure->fhss_api->receive_frame = &fhss_ws_receive_frame_callback; + fhss_structure->fhss_api->data_tx_done = &fhss_ws_data_tx_done_callback; + fhss_structure->fhss_api->data_tx_fail = &fhss_ws_data_tx_fail_callback; + fhss_structure->fhss_api->synch_state_set = &fhss_ws_synch_state_set_callback; + fhss_structure->fhss_api->read_timestamp = NULL; + fhss_structure->fhss_api->get_retry_period = NULL; + fhss_structure->fhss_api->write_synch_info = &fhss_ws_write_synch_info_callback; + fhss_structure->fhss_api->init_callbacks = &fhss_init_callbacks_cb; + return 0; +} + +int fhss_ws_set_parent(fhss_structure_t *fhss_structure, const uint8_t eui64[8], const broadcast_timing_info_t *bc_timing_info, const bool force_synch) +{ + (void) eui64; + if (!fhss_structure->ws) { + return -1; + } + if (!bc_timing_info->broadcast_interval || !bc_timing_info->broadcast_dwell_interval) { + return -1; + } + if (((uint32_t)S_TO_US(fhss_structure->ws->min_synch_interval) > (fhss_structure->callbacks.read_timestamp(fhss_structure->fhss_api) - fhss_structure->ws->synchronization_time)) && !force_synch) { + return 0; + } + platform_enter_critical(); + uint32_t prev_synchronization_time = fhss_structure->ws->synchronization_time; + fhss_structure->ws->synchronization_time = fhss_structure->callbacks.read_timestamp(fhss_structure->fhss_api); + uint32_t time_since_last_synch_us = fhss_structure->ws->synchronization_time - prev_synchronization_time; + uint32_t own_bc_interval_offset = fhss_ws_calculate_broadcast_interval_offset(fhss_structure, fhss_structure->ws->synchronization_time); + fhss_stop_timer(fhss_structure, fhss_broadcast_handler); + uint32_t time_from_reception_ms = US_TO_MS(fhss_structure->callbacks.read_timestamp(fhss_structure->fhss_api) - bc_timing_info->bt_rx_timestamp); + uint32_t true_bc_interval_offset = (bc_timing_info->broadcast_interval_offset + time_from_reception_ms) % bc_timing_info->broadcast_interval; + if (true_bc_interval_offset >= bc_timing_info->broadcast_dwell_interval) { + fhss_structure->ws->is_on_bc_channel = false; + } + uint32_t timeout = MS_TO_US(bc_timing_info->broadcast_interval - true_bc_interval_offset); + + if (fhss_structure->ws->is_on_bc_channel) { + 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); + 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; + fhss_structure->ws->fhss_configuration.fhss_broadcast_interval = bc_timing_info->broadcast_interval; + fhss_set_txrx_slot_length(fhss_structure); + fhss_structure->ws->bc_slot = bc_timing_info->broadcast_slot + slots_since_reception; + if (fhss_structure->ws->fhss_configuration.ws_bc_channel_function == WS_TR51CF) { + fhss_structure->ws->bc_slot %= fhss_structure->number_of_channels; + } + platform_exit_critical(); + //TODO: support multiple parents + fhss_structure->ws->parent_bc_info = bc_timing_info; + if (prev_synchronization_time) { + if (SYNCH_COMPENSATION_MIN_INTERVAL <= US_TO_S(time_since_last_synch_us)) { + // Update clock drift + fhss_structure->ws->drift_per_millisecond_ns += divide_integer(MS_TO_NS(true_bc_interval_offset - own_bc_interval_offset), US_TO_MS(time_since_last_synch_us)); + } + tr_debug("synch to parent: %s, drift: %"PRIi32"ms in %"PRIu32" seconds, compensation: %"PRIi32"ns per ms", trace_array(eui64, 8), true_bc_interval_offset - own_bc_interval_offset, US_TO_S(time_since_last_synch_us), fhss_structure->ws->drift_per_millisecond_ns); + } + return 0; +} + +int fhss_ws_remove_parent(fhss_structure_t *fhss_structure, const uint8_t eui64[8]) +{ + (void) eui64; + if (!fhss_structure->ws) { + return -1; + } + fhss_structure->ws->parent_bc_info = NULL; + return 0; +} + +int fhss_ws_configuration_set(fhss_structure_t *fhss_structure, const fhss_ws_configuration_t *fhss_configuration) +{ + int channel_count = channel_list_count_channels(fhss_configuration->channel_mask); + if (channel_count <= 0) { + return -1; + } + platform_enter_critical(); + if (fhss_configuration->ws_uc_channel_function == WS_FIXED_CHANNEL || fhss_configuration->fhss_uc_dwell_interval == 0) { + fhss_stop_timer(fhss_structure, fhss_unicast_handler); + fhss_structure->ws->unicast_timer_running = false; + } + if ((fhss_structure->ws->unicast_timer_running == false) && (fhss_configuration->ws_uc_channel_function != WS_FIXED_CHANNEL) && fhss_configuration->fhss_uc_dwell_interval) { + fhss_ws_start_timer(fhss_structure, MS_TO_US(fhss_configuration->fhss_uc_dwell_interval), fhss_unicast_handler); + fhss_structure->ws->unicast_timer_running = true; + } + fhss_structure->ws->fhss_configuration = *fhss_configuration; + fhss_structure->number_of_channels = channel_count; + if (fhss_configuration->ws_uc_channel_function == WS_FIXED_CHANNEL) { + fhss_structure->rx_channel = fhss_configuration->unicast_fixed_channel; + } + platform_exit_critical(); + tr_info("fhss Configuration set, UC channel: %d, BC channel: %d, UC CF: %d, BC CF: %d, channels: %d, uc dwell: %d, bc dwell: %d, bc interval: %"PRIu32", bsi:%d", + fhss_structure->ws->fhss_configuration.unicast_fixed_channel, + fhss_structure->ws->fhss_configuration.broadcast_fixed_channel, + fhss_structure->ws->fhss_configuration.ws_uc_channel_function, + fhss_structure->ws->fhss_configuration.ws_bc_channel_function, + fhss_structure->number_of_channels, + fhss_structure->ws->fhss_configuration.fhss_uc_dwell_interval, + fhss_structure->ws->fhss_configuration.fhss_bc_dwell_interval, + fhss_structure->ws->fhss_configuration.fhss_broadcast_interval, + fhss_structure->ws->fhss_configuration.bsi); + return 0; +} + +int fhss_ws_set_hop_count(fhss_structure_t *fhss_structure, const uint8_t hop_count) +{ + fhss_structure->own_hop = hop_count; + return 0; +} + +#endif // HAVE_WS diff --git a/source/Service_Libs/fhss/fhss_ws.h b/source/Service_Libs/fhss/fhss_ws.h index 5af1b2c40e..c86898c2b1 100644 --- a/source/Service_Libs/fhss/fhss_ws.h +++ b/source/Service_Libs/fhss/fhss_ws.h @@ -25,6 +25,8 @@ #define WS_MAX_TXRX_SLOT_LEN_MS 100 // Default minimum broadcast synchronization interval in seconds #define DEFAULT_MIN_SYNCH_INTERVAL 60 +// Drift compensation allowed if at least SYNCH_COMPENSATION_MIN_INTERVAL (seconds) since last synchronization +#define SYNCH_COMPENSATION_MIN_INTERVAL 60 typedef struct fhss_ws fhss_ws_t; struct fhss_ws { @@ -34,6 +36,7 @@ struct fhss_ws { uint16_t min_synch_interval; uint32_t txrx_slot_length_ms; uint32_t synchronization_time; + int32_t drift_per_millisecond_ns; int16_t *tr51_channel_table; uint8_t *tr51_output_table; bool unicast_timer_running; diff --git a/source/Service_Libs/fhss/fhss_ws_empty_functions.c b/source/Service_Libs/fhss/fhss_ws_empty_functions.c index 07597662f9..11896b55c2 100644 --- a/source/Service_Libs/fhss/fhss_ws_empty_functions.c +++ b/source/Service_Libs/fhss/fhss_ws_empty_functions.c @@ -51,6 +51,7 @@ int fhss_ws_set_parent(fhss_structure_t *fhss_structure, const uint8_t eui64[8], (void) fhss_structure; (void) eui64; (void) bc_timing_info; + (void) force_synch; return -1; } diff --git a/source/Service_Libs/hmac/hmac_sha1.c b/source/Service_Libs/hmac/hmac_sha1.c new file mode 100644 index 0000000000..f4c79d2d21 --- /dev/null +++ b/source/Service_Libs/hmac/hmac_sha1.c @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2016-2019, 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 "mbedtls/md.h" +#include "Service_Libs/hmac/hmac_sha1.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) +{ +#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)); + + 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)); + if (print_data_len > 32) { + print_data_len -= 32; + print_data += 32; + } else { + break; + } + } +#endif + + const mbedtls_md_type_t 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; + } + + mbedtls_md_context_t ctx; + + mbedtls_md_init(&ctx); + if (mbedtls_md_setup(&ctx, md_info, 1) != 0) { + return -1; + } + if (mbedtls_md_hmac_starts(&ctx, (const unsigned char *) key, key_len) != 0) { + goto error; + } + if (mbedtls_md_hmac_update(&ctx, (const unsigned char *) data, data_len) != 0) { + goto error; + } + if (mbedtls_md_hmac_finish(&ctx, result) != 0) { + goto error; + } + mbedtls_md_free(&ctx); + +#ifdef EXTRA_DEBUG_INFO + tr_debug("hmac_sha_1 result %s\n", trace_array(result, 20)); +#endif + return 0; + +error: + mbedtls_md_free(&ctx); + return -1; +} diff --git a/source/Service_Libs/hmac/hmac_sha1.h b/source/Service_Libs/hmac/hmac_sha1.h new file mode 100644 index 0000000000..e387e46781 --- /dev/null +++ b/source/Service_Libs/hmac/hmac_sha1.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2016-2018, 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 HMAC_SHA1_ +#define HMAC_SHA1_ + +/** + * \brief Calculate HMAC-SHA1-160 + * + * Calculate HMAC-SHA1-160 + * + * \param key pointer to key + * \param key_len key length + * \param data pointer to data + * \param data_len data length + * \param result pointer to result, must be at least 160 bytes + * + * \return < 0 failure + * \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); + +#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 new file mode 100644 index 0000000000..544586f890 --- /dev/null +++ b/source/Service_Libs/ieee_802_11/ieee_802_11.c @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2016-2019, 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 "mbedtls/md.h" +#include "Service_Libs/ieee_802_11/ieee_802_11.h" +#include "Service_Libs/hmac/hmac_sha1.h" + +#define TRACE_GROUP "iprf" + +uint16_t ieee_802_11_prf_setup(ieee_802_11_prf_t *prf, uint16_t bits, uint16_t a_len, uint16_t b_len) +{ + prf->bits = bits; + prf->a_len = a_len; + prf->b_len = b_len; + return a_len + 1 + b_len + 1; // A string + Y + B string + X (index) +} + +uint8_t *ieee_802_11_prf_get_a_string(ieee_802_11_prf_t *prf, uint8_t *string) +{ + (void) prf; + return string; +} + +uint8_t *ieee_802_11_prf_get_b_string(ieee_802_11_prf_t *prf, uint8_t *string) +{ + return string + prf->a_len + 1; +} + +uint16_t ieee_802_11_prf_starts(ieee_802_11_prf_t *prf, const uint8_t *key, uint16_t key_len) +{ + prf->key = key; + prf->key_len = key_len; + + uint8_t iterations = (prf->bits + 159) / 160; + uint16_t result_len = 160 / 8 * iterations; + return result_len; +} + +void ieee_802_11_prf_update(ieee_802_11_prf_t *prf, uint8_t *string) +{ + prf->string = string; + prf->string[prf->a_len] = 0x00; /* Y (0) */ +} + +int8_t ieee_802_11_prf_finish(ieee_802_11_prf_t *prf, uint8_t *result) +{ + uint16_t string_len = prf->a_len + 1 + prf->b_len + 1; + + 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) < 0) { + return -1; + } + result += 160 / 8; + } + + return 0; +} diff --git a/source/Service_Libs/ieee_802_11/ieee_802_11.h b/source/Service_Libs/ieee_802_11/ieee_802_11.h new file mode 100644 index 0000000000..80dc118633 --- /dev/null +++ b/source/Service_Libs/ieee_802_11/ieee_802_11.h @@ -0,0 +1,129 @@ +/* + * Copyright (c) 2016-2018, 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 IEEE_802_11_ +#define IEEE_802_11_ + +typedef struct { + const uint8_t *key; /**< Key string */ + uint8_t *string; /**< Data string (A string + Y + B string + X) */ + uint16_t bits; /**< Number of PRF bits */ + uint16_t key_len; /**< Key string length */ + uint16_t a_len; /**< A string length */ + uint16_t b_len; /**< B string length */ +} ieee_802_11_prf_t; + +/* + From IEEE 802.11 chapter 11.6.1.2 PRF: + + In the following, K is a key; A is a unique label for each different purpose + of the PRF; B is a variable-length string; Y is a single octet containing 0; + X is a single octet containing the loop parameter i; and || denotes concatenation: + + H-SHA-1(K, A, B, X) ← HMAC-SHA-1(K, A || Y || B || X) + + PRF(K, A, B, Len) + for i ← 0 to (Len+159)/160 do + R ← R || H-SHA-1(K, A, B, i) + return L(R, 0, Len) + + PRF-128(K, A, B) = PRF(K, A, B, 128) + PRF-192(K, A, B) = PRF(K, A, B, 192) + PRF-256(K, A, B) = PRF(K, A, B, 256) + PRF-384(K, A, B) = PRF(K, A, B, 384) + PRF-512(K, A, B) = PRF(K, A, B, 512) +*/ + +/** + * \brief Setup IEEE 802.11 PRF + * + * Update is made based on failed and successful message sending + * attempts for a message. + * + * \param prf pointer to PRF data + * \param bits number of bits + * \param a_len A string length + * \param b_len B string length + * + * \return length of the combined string that is input parameter for further functions + * (this is length of the A string + Y + B string + X) + */ +uint16_t ieee_802_11_prf_setup(ieee_802_11_prf_t *prf, uint16_t bits, uint16_t a_len, uint16_t b_len); + +/** + * \brief Get A string pointer + * + * Get a pointer to A string start that is used to write A string contents + * + * \param prf pointer to PRF data + * \param string pointer to input string + * + * \return pointer to A string part of the input string + */ +uint8_t *ieee_802_11_prf_get_a_string(ieee_802_11_prf_t *prf, uint8_t *string); + +/** + * \brief Get B string pointer + * + * Get a pointer to B string start that is used to write B string contents + * + * \param prf pointer to PRF data + * \param string pointer to input string + * + * \return pointer to B string part of the input string + */ +uint8_t *ieee_802_11_prf_get_b_string(ieee_802_11_prf_t *prf, uint8_t *string); + +/** + * \brief Start PRF process + * + * Start PRF process + * + * \param prf pointer to PRF data + * \param key key + * \param key_len key length + * + * \return length of the return string + */ +uint16_t ieee_802_11_prf_starts(ieee_802_11_prf_t *prf, const uint8_t *key, uint16_t key_len); + +/** + * \brief Update PRF process + * + * Update PRF process + * + * \param prf pointer to PRF data + * \param string pointer to input string + * + */ +void ieee_802_11_prf_update(ieee_802_11_prf_t *prf, uint8_t *string); + +/** + * \brief Finish PRF process + * + * Finish PRF process + * + * \param prf pointer to PRF data + * \param result pointer to result string + * + * \return < 0 failure + * \return >= 0 success + * + */ +int8_t ieee_802_11_prf_finish(ieee_802_11_prf_t *prf, uint8_t *result); + +#endif /* IEEE_802_11_*/ diff --git a/source/Service_Libs/load_balance/load_balance.c b/source/Service_Libs/load_balance/load_balance.c index 76b734bd5c..74d02ae442 100644 --- a/source/Service_Libs/load_balance/load_balance.c +++ b/source/Service_Libs/load_balance/load_balance.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2017, Arm Limited and affiliates. + * Copyright (c) 2016-2018, Arm Limited and affiliates. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/source/Service_Libs/load_balance/load_balance_api.h b/source/Service_Libs/load_balance/load_balance_api.h index 58498c5199..498847da8f 100644 --- a/source/Service_Libs/load_balance/load_balance_api.h +++ b/source/Service_Libs/load_balance/load_balance_api.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2017, Arm Limited and affiliates. + * Copyright (c) 2016-2018, Arm Limited and affiliates. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/source/Service_Libs/mac_neighbor_table/mac_neighbor_table.c b/source/Service_Libs/mac_neighbor_table/mac_neighbor_table.c index 21d66058ac..89ebcce39e 100644 --- a/source/Service_Libs/mac_neighbor_table/mac_neighbor_table.c +++ b/source/Service_Libs/mac_neighbor_table/mac_neighbor_table.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, Arm Limited and affiliates. + * Copyright (c) 2018-2019, Arm Limited and affiliates. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -23,7 +23,7 @@ #include "common_functions.h" #include "nsdynmemLIB.h" #include "Service_Libs/mac_neighbor_table/mac_neighbor_table.h" -#include "Core/include/address.h" +#include "Core/include/ns_address_internal.h" #include "platform/topo_trace.h" #define TRACE_GROUP "mnei" diff --git a/source/Service_Libs/mdns/ns_fnet_events.c b/source/Service_Libs/mdns/ns_fnet_events.c index 883dfd2f1e..1749e7b258 100644 --- a/source/Service_Libs/mdns/ns_fnet_events.c +++ b/source/Service_Libs/mdns/ns_fnet_events.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, Arm Limited and affiliates. + * Copyright (c) 2017-2018, Arm Limited and affiliates. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/source/Service_Libs/mdns/ns_fnet_port.c b/source/Service_Libs/mdns/ns_fnet_port.c index d6907489d6..456a2f200e 100644 --- a/source/Service_Libs/mdns/ns_fnet_port.c +++ b/source/Service_Libs/mdns/ns_fnet_port.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, Arm Limited and affiliates. + * Copyright (c) 2017-2019, Arm Limited and affiliates. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -33,7 +33,7 @@ #include "socket_api.h" #include "net_interface.h" #include "nsdynmemLIB.h" -#include "Core/include/address.h" +#include "Core/include/ns_address_internal.h" #include "ns_fnet_events.h" diff --git a/source/Service_Libs/mdns/ns_mdns_api.c b/source/Service_Libs/mdns/ns_mdns_api.c index 435c049afa..e0c8958146 100644 --- a/source/Service_Libs/mdns/ns_mdns_api.c +++ b/source/Service_Libs/mdns/ns_mdns_api.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, Arm Limited and affiliates. + * Copyright (c) 2017-2018, Arm Limited and affiliates. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/source/Service_Libs/mle_service/mle_service.c b/source/Service_Libs/mle_service/mle_service.c index 75a4b87ba0..37e53276fe 100644 --- a/source/Service_Libs/mle_service/mle_service.c +++ b/source/Service_Libs/mle_service/mle_service.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2018, Arm Limited and affiliates. + * Copyright (c) 2015-2019, Arm Limited and affiliates. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -26,7 +26,7 @@ #include "ns_list.h" #include "randLIB.h" #include "socket_api.h" -#include "Core/include/socket.h" +#include "Core/include/ns_socket.h" #include "net_interface.h" #include "common_functions.h" #include "Common_Protocols/ipv6_constants.h" @@ -228,6 +228,11 @@ static void mle_service_tr_timeout_handler(mle_service_msg_buf_t *cur_ptr) cur_ptr->tokens_delay = false; } + // Randomise Challenge TLV value + if (cur_ptr->challengePtr) { + randLIB_get_n_bytes_random(cur_ptr->challengePtr, cur_ptr->challengeLen); + } + //Trig Buffer to socket mle_service_build_packet_send(srv_ptr, sec_params, cur_ptr); diff --git a/source/Service_Libs/mle_service/mle_service_api.h b/source/Service_Libs/mle_service/mle_service_api.h index 27b5d0e732..76a91950dc 100644 --- a/source/Service_Libs/mle_service/mle_service_api.h +++ b/source/Service_Libs/mle_service/mle_service_api.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2018, Arm Limited and affiliates. + * Copyright (c) 2015-2019, Arm Limited and affiliates. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -804,6 +804,6 @@ void mle_service_frame_counter_entry_delete(int8_t interface_id, uint8_t attribu */ void mle_service_receive_filter_cb_set(mle_service_filter_cb *filter_cb); #else -#define mle_service_receive_filter_cb_set(filter_cb) ((void) 0) +#define mle_service_receive_filter_cb_set(filter_cb) ((void) filter_cb) #endif /* MLE_TEST */ #endif /* MLE_SERVICE_API_H_ */ diff --git a/source/Service_Libs/mle_service/mle_service_buffer.c b/source/Service_Libs/mle_service/mle_service_buffer.c index e8a90a4674..834f96edf0 100644 --- a/source/Service_Libs/mle_service/mle_service_buffer.c +++ b/source/Service_Libs/mle_service/mle_service_buffer.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2017, Arm Limited and affiliates. + * Copyright (c) 2015-2018, Arm Limited and affiliates. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/source/Service_Libs/mle_service/mle_service_buffer.h b/source/Service_Libs/mle_service/mle_service_buffer.h index 2d5c4f8999..4f10475920 100644 --- a/source/Service_Libs/mle_service/mle_service_buffer.h +++ b/source/Service_Libs/mle_service/mle_service_buffer.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2017, Arm Limited and affiliates. + * Copyright (c) 2015-2018, Arm Limited and affiliates. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/source/Service_Libs/mle_service/mle_service_frame_counter_table.c b/source/Service_Libs/mle_service/mle_service_frame_counter_table.c index 3f48ed637f..14af37f30d 100644 --- a/source/Service_Libs/mle_service/mle_service_frame_counter_table.c +++ b/source/Service_Libs/mle_service/mle_service_frame_counter_table.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, Arm Limited and affiliates. + * Copyright (c) 2018-2019, Arm Limited and affiliates. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -22,7 +22,7 @@ #include "common_functions.h" #include "ccmLIB.h" #include "nsdynmemLIB.h" -#include "Core/include/address.h" +#include "Core/include/ns_address_internal.h" #include "Core/include/ns_buffer.h" #include "MLE/mle.h" #include "mac_common_defines.h" diff --git a/source/Service_Libs/mle_service/mle_service_security.c b/source/Service_Libs/mle_service/mle_service_security.c index 37d8a8f101..33c11d2e48 100644 --- a/source/Service_Libs/mle_service/mle_service_security.c +++ b/source/Service_Libs/mle_service/mle_service_security.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2017, Arm Limited and affiliates. + * Copyright (c) 2015-2019, Arm Limited and affiliates. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -28,7 +28,7 @@ #include "common_functions.h" #include "ccmLIB.h" #include "nsdynmemLIB.h" -#include "Core/include/address.h" +#include "Core/include/ns_address_internal.h" #include "Core/include/ns_buffer.h" #include "MLE/mle.h" #include "mac_common_defines.h" diff --git a/source/Service_Libs/mle_service/mle_service_security.h b/source/Service_Libs/mle_service/mle_service_security.h index 674bfef76e..1d3e3f033e 100644 --- a/source/Service_Libs/mle_service/mle_service_security.h +++ b/source/Service_Libs/mle_service/mle_service_security.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2017, Arm Limited and affiliates. + * Copyright (c) 2015-2018, Arm Limited and affiliates. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/source/Service_Libs/nist_aes_kw/nist_aes_kw.c b/source/Service_Libs/nist_aes_kw/nist_aes_kw.c new file mode 100644 index 0000000000..6164731010 --- /dev/null +++ b/source/Service_Libs/nist_aes_kw/nist_aes_kw.c @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2016-2019, 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" +#if defined(HAVE_WS) && (defined(HAVE_PAE_SUPP) || defined(HAVE_PAE_AUTH)) +#include "mbedtls/nist_kw.h" +#endif +#include "Service_Libs/nist_aes_kw/nist_aes_kw.h" + +#ifdef HAVE_WS + +#define TRACE_GROUP "naes" + +int8_t nist_aes_key_wrap(uint8_t is_wrap, const uint8_t *key, int16_t key_bits, const uint8_t *input, size_t input_len, uint8_t *output, size_t *output_len) +{ +#if defined(HAVE_PAE_SUPP) || defined(HAVE_PAE_AUTH) + + int8_t ret_val = 0; + mbedtls_nist_kw_context ctx; + +#ifdef EXTRA_DEBUG_INFO + const uint8_t *print_data = key; + uint16_t print_data_len = key_bits / 8; + while (true) { + tr_debug("nist_aes_key_wrap key %s\n", trace_array(print_data, print_data_len > 32 ? 32 : print_data_len)); + if (print_data_len > 32) { + print_data_len -= 32; + print_data += 32; + } else { + break; + } + } + + print_data = input; + print_data_len = input_len; + while (true) { + tr_debug("nist_aes_key_wrap in %s\n", trace_array(print_data, print_data_len > 32 ? 32 : print_data_len)); + if (print_data_len > 32) { + print_data_len -= 32; + print_data += 32; + } else { + break; + } + } +#endif + + mbedtls_nist_kw_init(&ctx); + + if (mbedtls_nist_kw_setkey(&ctx, MBEDTLS_CIPHER_ID_AES, key, key_bits, is_wrap) != 0) { + ret_val = -1; + goto error; + } + + size_t out_size = *output_len; + + if (is_wrap) { + if (mbedtls_nist_kw_wrap(&ctx, MBEDTLS_KW_MODE_KW, input, input_len, output, output_len, out_size) != 0) { + ret_val = -1; + goto error; + } + } else { + if (mbedtls_nist_kw_unwrap(&ctx, MBEDTLS_KW_MODE_KW, input, input_len, output, output_len, out_size) != 0) { + ret_val = -1; + goto error; + } + } + +#ifdef EXTRA_DEBUG_INFO + print_data = output; + print_data_len = *output_len; + while (true) { + tr_debug("nist_aes_key_wrap out %s\n", trace_array(print_data, print_data_len > 32 ? 32 : print_data_len)); + if (print_data_len > 32) { + print_data_len -= 32; + print_data += 32; + } else { + break; + } + } +#endif + +error: + mbedtls_nist_kw_free(&ctx); + + return ret_val; +#else + (void) is_wrap; + (void) key; + (void) key_bits; + (void) input; + (void) input_len; + (void) output; + (void) output_len; + return 0; +#endif +} + +#endif diff --git a/source/Service_Libs/nist_aes_kw/nist_aes_kw.h b/source/Service_Libs/nist_aes_kw/nist_aes_kw.h new file mode 100644 index 0000000000..9f2eed8aab --- /dev/null +++ b/source/Service_Libs/nist_aes_kw/nist_aes_kw.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2016-2018, 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 NIST_AES_KW_ +#define NIST_AES_KW_ + +/** + * \brief NIST AES Key Wrap encode + * + * NIST AES Key Wrap encode + * + * \param key pointer to key + * \param key_bits key length in bits + * \param input pointer to input data + * \param input_len input data length + * \param output pointer to output data, storage must be at least 8 bytes longer than input_len + * + * \return < 0 failure + * \return >= 0 success + * + */ +int8_t nist_aes_key_wrap(uint8_t is_wrap, const uint8_t *key, int16_t key_bits, const uint8_t *input, size_t input_len, uint8_t *output, size_t *output_len); + +#endif /* NIST_AES_KW_ */ diff --git a/source/Service_Libs/pan_blacklist/pan_blacklist.c b/source/Service_Libs/pan_blacklist/pan_blacklist.c index 3de3fbfc2b..0efcffc970 100644 --- a/source/Service_Libs/pan_blacklist/pan_blacklist.c +++ b/source/Service_Libs/pan_blacklist/pan_blacklist.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, Arm Limited and affiliates. + * Copyright (c) 2017-2018, Arm Limited and affiliates. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/source/Service_Libs/utils/isqrt.c b/source/Service_Libs/utils/isqrt.c index 78039f9c2b..85ca0c07f3 100644 --- a/source/Service_Libs/utils/isqrt.c +++ b/source/Service_Libs/utils/isqrt.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014-2017, Arm Limited and affiliates. + * Copyright (c) 2014-2018, Arm Limited and affiliates. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/source/Service_Libs/utils/isqrt.h b/source/Service_Libs/utils/isqrt.h index 9502ffd955..373a74244a 100644 --- a/source/Service_Libs/utils/isqrt.h +++ b/source/Service_Libs/utils/isqrt.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014-2015, 2017, Arm Limited and affiliates. + * Copyright (c) 2014-2015, 2017-2018, Arm Limited and affiliates. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/source/Service_Libs/utils/ns_crc.c b/source/Service_Libs/utils/ns_crc.c index 155d5ef288..40e85f96f2 100644 --- a/source/Service_Libs/utils/ns_crc.c +++ b/source/Service_Libs/utils/ns_crc.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2017, Arm Limited and affiliates. + * Copyright (c) 2015, 2017-2018, Arm Limited and affiliates. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/source/Service_Libs/utils/ns_crc.h b/source/Service_Libs/utils/ns_crc.h index b7b47289e3..f229b97e67 100644 --- a/source/Service_Libs/utils/ns_crc.h +++ b/source/Service_Libs/utils/ns_crc.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2017, Arm Limited and affiliates. + * Copyright (c) 2015-2018, Arm Limited and affiliates. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/source/Service_Libs/utils/ns_file_system.c b/source/Service_Libs/utils/ns_file_system.c index a547c12be6..5ea3cca5fd 100644 --- a/source/Service_Libs/utils/ns_file_system.c +++ b/source/Service_Libs/utils/ns_file_system.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, Arm Limited and affiliates. + * Copyright (c) 2017-2018, Arm Limited and affiliates. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/source/Service_Libs/whiteboard/whiteboard.c b/source/Service_Libs/whiteboard/whiteboard.c index a7be8ba8f3..eb6c205bdb 100644 --- a/source/Service_Libs/whiteboard/whiteboard.c +++ b/source/Service_Libs/whiteboard/whiteboard.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2017, Arm Limited and affiliates. + * Copyright (c) 2013-2018, Arm Limited and affiliates. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/source/Service_Libs/whiteboard/whiteboard.h b/source/Service_Libs/whiteboard/whiteboard.h index 01b9e90f18..e3e22db395 100644 --- a/source/Service_Libs/whiteboard/whiteboard.h +++ b/source/Service_Libs/whiteboard/whiteboard.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2017, Arm Limited and affiliates. + * Copyright (c) 2013-2019, Arm Limited and affiliates. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -38,6 +38,7 @@ extern uint16_t whiteboard_size_get(void); #define whiteboard_table_check_address(address) NULL #define whiteboard_table_update(address, eui64, status) NULL #define whiteboard_interface_unregister_all_address(nwk_id) +#define whiteboard_interface_register(address, nwk_id) #define whiteboard_interface_address_cmp(address) false #endif diff --git a/source/configs/base/cfg_ws_border_router.h b/source/configs/base/cfg_ws_border_router.h new file mode 100644 index 0000000000..cfcb5f7bc2 --- /dev/null +++ b/source/configs/base/cfg_ws_border_router.h @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2019, 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. + */ + +/* Config Flags for WS Border router */ +#include "cfg_ws_router.h" + +#define HAVE_RPL_ROOT +#define HAVE_RPL_DAO_HANDLING +#define HAVE_6LOWPAN_BORDER_ROUTER +#define HAVE_WS_BORDER_ROUTER +#define HAVE_ND_PROXY +#define MULTICAST_FORWARDING diff --git a/source/configs/base/cfg_ws_router.h b/source/configs/base/cfg_ws_router.h new file mode 100644 index 0000000000..4a0e906133 --- /dev/null +++ b/source/configs/base/cfg_ws_router.h @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2019, 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. + */ + +#define HAVE_6LOWPAN_ROUTER +#define HAVE_WS_ROUTER +#define HAVE_RPL +#define HAVE_IPV6_ND +#define HAVE_6LOWPAN_ND +#define HAVE_MPL +#define HAVE_WS diff --git a/source/configs/cfg_generic.h b/source/configs/cfg_generic.h index 762997f420..7e645ef43e 100644 --- a/source/configs/cfg_generic.h +++ b/source/configs/cfg_generic.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2016-2018, Arm Limited and affiliates. + * Copyright (c) 2014, 2016-2019, Arm Limited and affiliates. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -20,6 +20,7 @@ #include "base/cfg_lowpan_border_router.h" #include "base/cfg_local_socket.h" #include "base/cfg_rf_tunnel.h" +#include "base/cfg_ws_border_router.h" #define FEA_TRACE_SUPPORT #define EXTRA_CONSISTENCY_CHECKS @@ -30,4 +31,8 @@ #define HAVE_DHCPV6_SERVER #define TCP_TEST #define THREAD_THCI_SUPPORT +#define HAVE_WS #define MLE_TEST +//#define HAVE_PAE_SUPP +//#define HAVE_PAE_AUTH +//#define HAVE_EAPOL_RELAY diff --git a/source/configs/cfg_ws_border_router.h b/source/configs/cfg_ws_border_router.h new file mode 100644 index 0000000000..638fd8f3b9 --- /dev/null +++ b/source/configs/cfg_ws_border_router.h @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2019, 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 "base/cfg_ethernet.h" +#include "base/cfg_local_socket.h" +#include "base/cfg_ws_border_router.h" + +#define FEA_TRACE_SUPPORT +#define HAVE_DHCPV6_SERVER +#define EXTRA_CONSISTENCY_CHECKS + +//#define HAVE_PAE_SUPP +//#define HAVE_PAE_AUTH +//#define HAVE_EAPOL_RELAY diff --git a/source/configs/cfg_ws_router.h b/source/configs/cfg_ws_router.h new file mode 100644 index 0000000000..b3ce93f785 --- /dev/null +++ b/source/configs/cfg_ws_router.h @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2019, 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 "base/cfg_ws_router.h" + +#define FEA_TRACE_SUPPORT +#define EXTRA_CONSISTENCY_CHECKS + diff --git a/source/ipv6_stack/ipv6_routing_table.c b/source/ipv6_stack/ipv6_routing_table.c index 5b99738bd8..804ec63049 100644 --- a/source/ipv6_stack/ipv6_routing_table.c +++ b/source/ipv6_stack/ipv6_routing_table.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2018, Arm Limited and affiliates. + * Copyright (c) 2012-2019, Arm Limited and affiliates. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -37,7 +37,7 @@ #include "randLIB.h" #include "ns_trace.h" #include "string.h" -#include "Core/include/address.h" +#include "Core/include/ns_address_internal.h" #include "ipv6_stack/ipv6_routing_table.h" #include "Common_Protocols/ipv6_constants.h" #include "Common_Protocols/icmpv6.h" @@ -172,6 +172,7 @@ void ipv6_neighbour_cache_init(ipv6_neighbour_cache_t *cache, int8_t interface_i cache->recv_addr_reg = false; cache->send_addr_reg = false; cache->send_nud_probes = true; + cache->probe_avoided_routers = true; cache->recv_na_aro = false; cache->recv_ns_aro = false; cache->route_if_info.metric = 0; @@ -409,6 +410,16 @@ void ipv6_neighbour_delete_registered_by_eui64(ipv6_neighbour_cache_t *cache, co } } +bool ipv6_neighbour_has_registered_by_eui64(ipv6_neighbour_cache_t *cache, const uint8_t *eui64) +{ + ns_list_foreach_safe(ipv6_neighbour_t, cur, &cache->list) { + if (cur->type != IP_NEIGHBOUR_GARBAGE_COLLECTIBLE && memcmp(ipv6_neighbour_eui64(cache, cur), eui64, 8) == 0) { + return true; + } + } + return false; +} + void ipv6_neighbour_set_state(ipv6_neighbour_cache_t *cache, ipv6_neighbour_t *entry, ip_neighbour_cache_state_t state) { if (!ipv6_neighbour_state_is_probably_reachable(entry->state) && @@ -1099,6 +1110,7 @@ static const char *route_src_names[] = { /* (Others are assumed to be always reachable) */ static const bool ipv6_route_probing[ROUTE_MAX] = { [ROUTE_RADV] = true, + [ROUTE_ARO] = true, [ROUTE_RPL_DAO] = true, [ROUTE_RPL_DIO] = true, [ROUTE_RPL_ROOT] = true, @@ -1225,7 +1237,7 @@ static bool ipv6_route_same_router(const ipv6_route_t *a, const ipv6_route_t *b) static void ipv6_route_probe(ipv6_route_t *route) { ipv6_neighbour_cache_t *ncache = ipv6_neighbour_cache_by_interface_id(route->info.interface_id); - if (!ncache || !ncache->send_nud_probes || route->probe_timer) { + if (!ncache || !ncache->probe_avoided_routers || route->probe_timer) { return; } @@ -1378,7 +1390,7 @@ ipv6_route_t *ipv6_route_choose_next_hop(const uint8_t *dest, int8_t interface_i continue; } - if (ncache->send_nud_probes && ipv6_route_probing[route->info.source]) { + if (ncache->probe_avoided_routers && ipv6_route_probing[route->info.source]) { /* Going via a router - check reachability, as per RFC 4191. * This only applies for certain routes (currently those from RAs) */ reachable = ipv6_neighbour_addr_is_probably_reachable(ncache, route->info.next_hop_addr); diff --git a/source/ipv6_stack/ipv6_routing_table.h b/source/ipv6_stack/ipv6_routing_table.h index 19f1beabc8..8d2eb0250e 100644 --- a/source/ipv6_stack/ipv6_routing_table.h +++ b/source/ipv6_stack/ipv6_routing_table.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2014-2018, Arm Limited and affiliates. + * Copyright (c) 2012, 2014-2019, Arm Limited and affiliates. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -24,7 +24,7 @@ #define IPV6_ROUTING_TABLE_H_ #include "ns_list.h" -#include "Core/include/address.h" +#include "Core/include/ns_address_internal.h" /* Address Resolution and Neighbour Unreachablity Detection constants from * RFC 4861, updated by RFC 7048. @@ -119,6 +119,7 @@ typedef struct ipv6_neighbour_cache { bool send_addr_reg : 1; bool recv_addr_reg : 1; bool send_nud_probes : 1; + bool probe_avoided_routers : 1; bool recv_ns_aro : 1; bool recv_na_aro : 1; bool use_eui64_as_slla_in_aro : 1; @@ -159,6 +160,7 @@ extern bool ipv6_neighbour_addr_is_probably_reachable(ipv6_neighbour_cache_t *ca extern bool ipv6_neighbour_ll_addr_match(const ipv6_neighbour_t *entry, addrtype_t ll_type, const uint8_t *ll_address); extern void ipv6_neighbour_invalidate_ll_addr(ipv6_neighbour_cache_t *cache, addrtype_t ll_type, const uint8_t *ll_address); extern void ipv6_neighbour_delete_registered_by_eui64(ipv6_neighbour_cache_t *cache, const uint8_t *eui64); +extern bool ipv6_neighbour_has_registered_by_eui64(ipv6_neighbour_cache_t *cache, const uint8_t *eui64); extern void ipv6_neighbour_entry_update_unsolicited(ipv6_neighbour_cache_t *cache, ipv6_neighbour_t *entry, addrtype_t type, const uint8_t *ll_address/*, bool tentative*/); extern ipv6_neighbour_t *ipv6_neighbour_update_unsolicited(ipv6_neighbour_cache_t *cache, const uint8_t *ip_address, addrtype_t ll_type, const uint8_t *ll_address); extern void ipv6_neighbour_reachability_confirmation(const uint8_t ip_address[__static 16], int8_t interface_id); diff --git a/source/ipv6_stack/protocol_ipv6.c b/source/ipv6_stack/protocol_ipv6.c index b351eb8178..ca528daf62 100644 --- a/source/ipv6_stack/protocol_ipv6.c +++ b/source/ipv6_stack/protocol_ipv6.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2018, Arm Limited and affiliates. + * Copyright (c) 2012-2019, Arm Limited and affiliates. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -20,7 +20,7 @@ #include "ns_list.h" #include "ns_trace.h" #include "nsdynmemLIB.h" -#include "Core/include/socket.h" +#include "Core/include/ns_socket.h" #include "NWK_INTERFACE/Include/protocol.h" #include "Common_Protocols/ipv6.h" #include "Common_Protocols/icmpv6.h" diff --git a/source/libDHCPv6/libDHCPv6.c b/source/libDHCPv6/libDHCPv6.c index 0ca070faf1..3bc2ec7844 100644 --- a/source/libDHCPv6/libDHCPv6.c +++ b/source/libDHCPv6/libDHCPv6.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014-2017, Arm Limited and affiliates. + * Copyright (c) 2014-2019, Arm Limited and affiliates. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -220,7 +220,8 @@ dhcpv6_client_server_data_t *libdhcpv6_nonTemporal_entry_get_by_prefix(int8_t in uint16_t libdhcpv6_duid_option_size(uint16_t linkType) { uint16_t length = 8; // Type & Length header part *2 - if (linkType == DHCPV6_DUID_HARDWARE_EUI64_TYPE) { + if (linkType == DHCPV6_DUID_HARDWARE_EUI64_TYPE || + linkType == DHCPV6_DUID_HARDWARE_IEEE_802_NETWORKS_TYPE) { length += 8; } else { length += 6; @@ -452,7 +453,8 @@ int libdhcpv6_compare_DUID(dhcp_link_options_params_t *targetId, dhcp_link_optio { if (targetId->linkType == parsedId->linkType) { uint8_t cmpLen; - if (targetId->linkType == DHCPV6_DUID_HARDWARE_EUI64_TYPE) { + if (targetId->linkType == DHCPV6_DUID_HARDWARE_EUI64_TYPE || + targetId->linkType == DHCPV6_DUID_HARDWARE_IEEE_802_NETWORKS_TYPE) { //Compare Current Interface EUID64 cmpLen = 8; } else { @@ -625,6 +627,8 @@ int libdhcpv6_get_duid_by_selected_type_id_opt(uint8_t *ptr, uint16_t data_lengt return 0; } else if ((params->linkType == DHCPV6_DUID_HARDWARE_EUI64_TYPE) && (option_msg.len == DHCPV6_SERVER_ID_MAC64_OPTION_LEN)) { return 0; + } else if ((params->linkType == DHCPV6_DUID_HARDWARE_IEEE_802_NETWORKS_TYPE) && (option_msg.len == DHCPV6_SERVER_ID_MAC64_OPTION_LEN)) { + return 0; } } } @@ -683,6 +687,11 @@ int libdhcpv6_get_IA_address(uint8_t *ptr, uint16_t data_length, dhcp_ia_non_tem return 0; } } + } else if (length == 0) { + params->nonTemporalAddress = NULL; + params->preferredValidLifeTime = 0; + params->validLifeTime = 0; + return 0; } } return -1; diff --git a/source/libDHCPv6/libDHCPv6.h b/source/libDHCPv6/libDHCPv6.h index 7722e8ff8d..a32f46c1c0 100644 --- a/source/libDHCPv6/libDHCPv6.h +++ b/source/libDHCPv6/libDHCPv6.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014-2015, 2017, Arm Limited and affiliates. + * Copyright (c) 2014-2015, 2017-2018, Arm Limited and affiliates. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -189,6 +189,7 @@ typedef struct dhcpv6_relay_msg { /** Server Identifier END */ /** Common for server and Client Identifier option */ #define DHCPV6_DUID_LINK_LAYER_TYPE 0x0003 +#define DHCPV6_DUID_HARDWARE_IEEE_802_NETWORKS_TYPE 0x0006 #define DHCPV6_DUID_HARDWARE_EUI64_TYPE 0x001b #define DHCPV6_DUID_HARDWARE_EUI48_TYPE 0x0001 @@ -340,7 +341,7 @@ uint8_t *libdhcvp6_request_option_write(uint8_t *ptr, uint8_t optionCnt, uint16_ * \param ptr payload pointer * \param duidPtr pointer id * \param duidRole supported values DHCPV6_SERVER_ID_OPTION & DHCPV6_CLIENT_ID_OPTION - * \param linkType supported values DHCPV6_DUID_HARDWARE_EUI64_TYPE & DHCPV6_DUID_HARDWARE_EUI48_TYPE + * \param linkType supported values DHCPV6_DUID_HARDWARE_EUI64_TYPE & DHCPV6_DUID_HARDWARE_EUI48_TYPE & DHCPV6_DUID_HARDWARE_IEEE_802_NETWORKS_TYPE * * return incremented pointer after write */ diff --git a/source/libDHCPv6/libDHCPv6_server.c b/source/libDHCPv6/libDHCPv6_server.c index bac446af7a..69cd434737 100644 --- a/source/libDHCPv6/libDHCPv6_server.c +++ b/source/libDHCPv6/libDHCPv6_server.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014-2017, Arm Limited and affiliates. + * Copyright (c) 2014-2019, Arm Limited and affiliates. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -60,7 +60,8 @@ static void libdhcpv6_address_generate(dhcpv6_gua_server_entry_s *serverInfo, dh memcpy(ptr, serverInfo->guaPrefix, 8); ptr += 8; if (serverInfo->enableAddressAutonous) { - if (entry->linkType == DHCPV6_DUID_HARDWARE_EUI64_TYPE) { + if (entry->linkType == DHCPV6_DUID_HARDWARE_EUI64_TYPE || + entry->linkType == DHCPV6_DUID_HARDWARE_IEEE_802_NETWORKS_TYPE) { memcpy(ptr, entry->linkId, 8); *ptr ^= 2; } else if (entry->linkType == DHCPV6_DUID_HARDWARE_EUI48_TYPE) { @@ -131,7 +132,8 @@ dhcpv6_gua_server_entry_s *libdhcpv6_server_data_get_by_prefix_and_socketinstanc { ns_list_foreach(dhcpv6_gua_server_entry_s, cur, &dhcpv6_gua_server_list) { if (cur->socketInstance_id == socketInstance) { - if (memcmp(cur->guaPrefix, prefixPtr, 8) == 0) { + + if (!prefixPtr || memcmp(cur->guaPrefix, prefixPtr, 8) == 0) { return cur; } } @@ -211,7 +213,8 @@ dhcpv6_alloacted_address_entry_t *libdhcpv6_address_allocated_list_scan(dhcpv6_g { dhcpv6_alloacted_address_entry_t *newEntry = NULL; uint16_t duiLength = 6; - if (linkType == DHCPV6_DUID_HARDWARE_EUI64_TYPE) { + if (linkType == DHCPV6_DUID_HARDWARE_EUI64_TYPE || + linkType == DHCPV6_DUID_HARDWARE_IEEE_802_NETWORKS_TYPE) { duiLength = 8; } ns_list_foreach(dhcpv6_alloacted_address_entry_t, cur, &serverInfo->allocatedAddressList) { diff --git a/source/libDHCPv6/libDHCPv6_server.h b/source/libDHCPv6/libDHCPv6_server.h index 1aa0079c53..02977f3b07 100644 --- a/source/libDHCPv6/libDHCPv6_server.h +++ b/source/libDHCPv6/libDHCPv6_server.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014-2015, 2017, Arm Limited and affiliates. + * Copyright (c) 2014-2015, 2017-2018, Arm Limited and affiliates. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/source/libNET/src/net_ipv6.c b/source/libNET/src/net_ipv6.c index 302e2950dd..3320a07924 100644 --- a/source/libNET/src/net_ipv6.c +++ b/source/libNET/src/net_ipv6.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2017, Arm Limited and affiliates. + * Copyright (c) 2016-2019, Arm Limited and affiliates. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -21,7 +21,7 @@ #include "ns_types.h" #include "nsdynmemLIB.h" -#include "Core/include/address.h" +#include "Core/include/ns_address_internal.h" #include "Common_Protocols/ipv6_flow.h" #include "Common_Protocols/ipv6_fragmentation.h" #include "NWK_INTERFACE/Include/protocol.h" diff --git a/source/libNET/src/net_load_balance.c b/source/libNET/src/net_load_balance.c index 4440532bcc..71d072b547 100644 --- a/source/libNET/src/net_load_balance.c +++ b/source/libNET/src/net_load_balance.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2018, Arm Limited and affiliates. + * Copyright (c) 2016-2019, Arm Limited and affiliates. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -313,9 +313,13 @@ int8_t net_load_balance_load_level_update_enable(int8_t interface_id, uint16_t e return load_balance_network_load_monitor_enable(interface_ptr->lb_api, expected_device_count, RPL_DODAG_PREF_MASK + 1, net_load_balance_api_get_node_count_cb, net_load_balance_api_get_set_load_level_cb); #else + (void)interface_id; + (void)expected_device_count; return -1; #endif #else + (void)interface_id; + (void)expected_device_count; return -1; #endif } @@ -338,9 +342,11 @@ int8_t net_load_balance_load_level_update_disable(int8_t interface_id) return load_balance_network_load_monitor_disable(interface_ptr->lb_api); #else + (void)interface_id; return -1; #endif #else + (void)interface_id; return -1; #endif } diff --git a/source/libNET/src/net_mle.c b/source/libNET/src/net_mle.c index ef4f5b46bd..39be3ee252 100644 --- a/source/libNET/src/net_mle.c +++ b/source/libNET/src/net_mle.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2017, Arm Limited and affiliates. + * Copyright (c) 2016-2017, 2019, Arm Limited and affiliates. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -25,7 +25,7 @@ #include "string.h" #include "ns_trace.h" #include "net_mle_api.h" -#include "Core/include/address.h" +#include "Core/include/ns_address_internal.h" #include "net_interface.h" #include "MLE/mle.h" #include "NWK_INTERFACE/Include/protocol.h" diff --git a/source/libNET/src/net_rpl.c b/source/libNET/src/net_rpl.c index 5037894a1a..70e26a5c29 100644 --- a/source/libNET/src/net_rpl.c +++ b/source/libNET/src/net_rpl.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014-2017, Arm Limited and affiliates. + * Copyright (c) 2014-2019, Arm Limited and affiliates. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -19,7 +19,7 @@ #include "ns_types.h" #include -#include "Core/include/address.h" +#include "Core/include/ns_address_internal.h" #include "NWK_INTERFACE/Include/protocol.h" #include "6LoWPAN/Bootstraps/protocol_6lowpan.h" #include "RPL/rpl_protocol.h" @@ -74,6 +74,11 @@ int8_t arm_nwk_6lowpan_rpl_dodag_init(int8_t interface_id, const uint8_t *dodag_ } return 0; #else // !HAVE_RPL_ROOT + (void)dodag_id; + (void)config; + (void)instance_id; + (void)flags; + return -1; #endif } diff --git a/source/libNET/src/ns_net.c b/source/libNET/src/ns_net.c index 7cf133b82c..8f5c498917 100644 --- a/source/libNET/src/ns_net.c +++ b/source/libNET/src/ns_net.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014-2018, Arm Limited and affiliates. + * Copyright (c) 2014-2019, Arm Limited and affiliates. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -28,7 +28,7 @@ #include "socket_api.h" #include "nsdynmemLIB.h" #include "NWK_INTERFACE/Include/protocol.h" -#include "Core/include/socket.h" +#include "Core/include/ns_socket.h" #ifdef HAVE_RPL #include "RPL/rpl_of0.h" #include "RPL/rpl_mrhof.h" @@ -67,6 +67,9 @@ #include "6LoWPAN/Thread/thread_bootstrap.h" #include "6LoWPAN/Thread/thread_management_internal.h" #include "6LoWPAN/ws/ws_bootstrap.h" +#ifdef HAVE_WS +#include "6LoWPAN/ws/ws_pae_controller.h" +#endif #include "BorderRouter/border_router.h" #include "Service_Libs/mle_service/mle_service_api.h" #include "6LoWPAN/MAC/mac_data_poll.h" @@ -692,6 +695,8 @@ int8_t arm_nwk_interface_ethernet_init(eth_mac_api_t *api, const char *interface cur->interface_name = interface_name_ptr; return cur->id; #else + (void)api; + (void)interface_name_ptr; return -2; #endif } @@ -928,12 +933,41 @@ int8_t arm_nwk_link_layer_security_mode(int8_t interface_id, net_6lowpan_link_la int8_t arm_network_certificate_chain_set(const arm_certificate_chain_entry_s *chain_info) { -#ifndef PANA +#if !defined(PANA) && !defined(HAVE_WS) (void)chain_info; #endif + +#ifdef HAVE_WS + ws_pae_controller_certificate_chain_set(chain_info); +#endif + return pana_interface_certificate_chain_set(chain_info); } +int8_t arm_network_trusted_certificate_add(const arm_certificate_entry_s *cert) +{ + (void) cert; + return -1; +} + +int8_t arm_network_trusted_certificate_remove(const arm_certificate_entry_s *cert) +{ + (void) cert; + return -1; +} + +int8_t arm_network_certificate_revocation_list_add(const arm_cert_revocation_list_entry_s *crl) +{ + (void) crl; + return -1; +} + +int8_t arm_network_certificate_revocation_list_remove(const arm_cert_revocation_list_entry_s *crl) +{ + (void) crl; + return -1; +} + /** * \brief Read Pana server security key material * @@ -1016,11 +1050,20 @@ int8_t arm_pana_client_library_init(int8_t interface_id, net_tls_cipher_e cipher int8_t arm_nwk_interface_configure_ipv6_bootstrap_set(int8_t interface_id, net_ipv6_mode_e bootstrap_mode, const uint8_t *ipv6_prefix_pointer) { +#ifndef HAVE_ETHERNET + (void)interface_id; + (void)bootstrap_mode; + (void)ipv6_prefix_pointer; +#endif return ipv6_interface_configure_ipv6_bootstrap_set(interface_id, bootstrap_mode, ipv6_prefix_pointer); } int8_t arm_nwk_interface_accept_ipv6_ra(int8_t interface_id, net_ipv6_accept_ra_e accept_ra) { +#ifndef HAVE_ETHERNET + (void)interface_id; + (void)accept_ra; +#endif return ipv6_interface_accept_ra(interface_id, accept_ra); } diff --git a/source/libNET/src/socket_api.c b/source/libNET/src/socket_api.c index 8609d577ab..65b192145d 100644 --- a/source/libNET/src/socket_api.c +++ b/source/libNET/src/socket_api.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014-2018, Arm Limited and affiliates. + * Copyright (c) 2014-2019, Arm Limited and affiliates. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -33,7 +33,7 @@ #include "ns_trace.h" #include "string.h" #include "nsdynmemLIB.h" -#include "Core/include/socket.h" +#include "Core/include/ns_socket.h" #include "NWK_INTERFACE/Include/protocol.h" #include "Common_Protocols/ipv6_constants.h" #include "Common_Protocols/ipv6_flow.h" diff --git a/source/nsconfig.h b/source/nsconfig.h index 59e3dc1a6f..9a6db864a2 100644 --- a/source/nsconfig.h +++ b/source/nsconfig.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014-2017, Arm Limited and affiliates. + * Copyright (c) 2014-2019, Arm Limited and affiliates. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -32,11 +32,6 @@ #define _ns_cfg_header(x) __ns_cfg_header(configs/cfg_##x.h) #define ns_cfg_header(x) _ns_cfg_header(x) - -#ifdef YOTTA_CFG_NANOSTACK_CONFIGURATION -#define NSCONFIG YOTTA_CFG_NANOSTACK_CONFIGURATION -#endif - #ifdef MBED_CONF_NANOSTACK_CONFIGURATION #define NSCONFIG MBED_CONF_NANOSTACK_CONFIGURATION #endif diff --git a/sources.mk b/sources.mk index e6461345da..4d0628b2f5 100644 --- a/sources.mk +++ b/sources.mk @@ -18,6 +18,26 @@ SRCS += \ source/6LoWPAN/Mesh/mesh.c \ source/6LoWPAN/ND/nd_router_object.c \ source/6LoWPAN/NVM/nwk_nvm.c \ + source/6LoWPAN/ws/ws_ie_lib.c \ + source/6LoWPAN/ws/ws_llc_data_service.c \ + source/6LoWPAN/ws/ws_mpx_header.c \ + source/6LoWPAN/ws/ws_neighbor_class.c \ + source/6LoWPAN/ws/ws_bootstrap.c \ + source/6LoWPAN/ws/ws_common.c \ + source/6LoWPAN/ws/ws_management_api.c \ + source/6LoWPAN/ws/ws_bbr_api.c \ + source/6LoWPAN/ws/ws_test_api.c \ + source/6LoWPAN/ws/ws_empty_functions.c \ + source/6LoWPAN/ws/ws_pae_controller.c \ + source/6LoWPAN/ws/ws_pae_supp.c \ + source/6LoWPAN/ws/ws_pae_auth.c \ + source/6LoWPAN/ws/ws_pae_lib.c \ + source/6LoWPAN/ws/ws_pae_nvm_data.c \ + source/6LoWPAN/ws/ws_pae_nvm_store.c \ + source/6LoWPAN/ws/ws_eapol_relay.c \ + source/6LoWPAN/ws/ws_eapol_auth_relay.c \ + source/6LoWPAN/ws/ws_eapol_relay_lib.c \ + source/6LoWPAN/ws/ws_eapol_pdu.c \ source/BorderRouter/border_router.c \ source/Common_Protocols/icmpv6.c \ source/Common_Protocols/icmpv6_prefix.c \ @@ -29,7 +49,7 @@ SRCS += \ source/Common_Protocols/mld.c \ source/Common_Protocols/tcp.c \ source/Common_Protocols/udp.c \ - source/Core/address.c \ + source/Core/ns_address_internal.c \ source/Core/buffer_dyn.c \ source/Core/sockbuf.c \ source/Core/ns_socket.c \ @@ -75,6 +95,25 @@ SRCS += \ source/RPL/rpl_mrhof.c \ source/RPL/rpl_policy.c \ source/Security/Common/security_lib.c \ + source/Security/eapol/eapol_helper.c \ + source/Security/eapol/kde_helper.c \ + source/Security/kmp/kmp_api.c \ + source/Security/kmp/kmp_addr.c \ + source/Security/kmp/kmp_eapol_pdu_if.c \ + source/Security/kmp/kmp_socket_if.c \ + source/Security/protocols/sec_prot_lib.c \ + source/Security/protocols/sec_prot_keys.c \ + 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/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/tls_sec_prot/tls_sec_prot.c \ + source/Security/protocols/tls_sec_prot/tls_sec_prot_lib.c \ source/Security/PANA/eap_protocol.c \ source/Security/PANA/pana.c \ source/Security/PANA/pana_avp.c \ @@ -89,10 +128,15 @@ SRCS += \ source/Service_Libs/fhss/fhss_configuration_interface.c \ source/Service_Libs/fhss/fhss_statistics.c \ source/Service_Libs/fhss/fhss.c \ + source/Service_Libs/fhss/fhss_ws.c \ source/Service_Libs/fhss/fhss_ws_empty_functions.c \ source/Service_Libs/fhss/fhss_common.c \ + source/Service_Libs/fhss/channel_functions.c \ source/Service_Libs/fhss/channel_list.c \ source/Service_Libs/fnv_hash/fnv_hash.c \ + source/Service_Libs/hmac/hmac_sha1.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 \ source/Service_Libs/mle_service/mle_service.c \ source/Service_Libs/mle_service/mle_service_buffer.c \