Squashed 'features/nanostack/sal-stack-nanostack/' changes from 84a07ce..0345477

0345477 Remove test file eapol_helper_stub from release
2f7767a Merge branch 'release_internal' into release_external
fdd6c2d wi-sun address registration fix:
48330ea Disabled TLS platform memory
794e053 Wi-sun config sol message handler update
c69a41d Removed ETX unknow neighbour trace.
7a5b2a7 Wi-sun State machine update
bfc7843 Enabled non-blocking ECC calculation on TLS server
ce36f2c Fix issues found by coverity (#2087)
2c4981b DHCP client fix's
6c00aa2 Correcting timeout handling
d04523e Added timer to supplicant to filter EAP-TLS re-transmission bursts
3524877 Fix issues found by coverity (#2082)
e5f1627 Increased TLS queue size, corrected EUI-64 read and added traces
67bb748 Codereview cleaning's
9350293 DHCPv6 client server address update.
de00ace Reduced EAP-TLS retries to from four to two
bff9c6e Previous BR EUI-64 is now used on second authentication attempt
a2019f4 RPL target address publish update
cea03d6 DHCPc6 client cancel support
f562de5 Corrected supplicant EAP-TLS sequence id validation
bf36b5a Added traces to EAP-TLS delay and TLS protocol
203fdae Removed RSL check from ETX for testing purpose.
c1bfeb6 Added print for debugging why SRH validate check fail.
fc429e7 Corrected function parameter check
0aef534 Added support for fourth network key to MAC helper and WS bootstrap
d861208 Added validation for ETX Acceleration definitions.
cbb4acf Accept do faster ETX caclculation after last ETX probe or unicast traffic.
202e579 Removed debug trace print which may affect crash.
68c3d7b Fix missing RPL Prefix Slaac delete handler.
588c385 Drop only non trusted devices when life is over 60 seconds old.
99e8ce7 Cleaned trace print.
8c57c10 Code clean and Keep time update at 16-bit.
9ff35ab ETX calculate and sampling update.
535c005 Corrected EAPOL key reuse on supplicant bootstrap restart
01058c0 Fix for valid lifetime for slaac based address. (#2071)
ed4d0c0 Merge pull request #2067 from ARMmbed/IOTTHD-3413
b3ec1f3 MAC: iotthd-3413 Review updates
dce4e25 Merge pull request #2068 from ARMmbed/ws_dhcp_update
06fe62e Fixed static definition.
14a244d Wi-sun BBR, bootsrap and RPL Prefix calback update
669b325 DHCPV6 client update
d03187e NEW API for do address decrecation
7864962 Added comment for dhcp client configure at Wi-SUN bootstrap.
890f955 Dio prefix handler fix
9f7bf49 Code style, added missing function stub  and function rename fix.
78c4ae9 MAC: Added address and pan id filtering for 802.15.4-2015
0ebd37a Wi-sun DHCPV6, RPL DIO forwarding, dhcpv6 client  update
85f9a81 Added generation of SLAAC address on BBR (#2065)
561aefa Created Wi-SUN specific NA handler
30bce91 MAC: Moved MAC filters in data ind callback
b961948 MAC: Cleaning data indication callback
318ab48 Merge pull request #2064 from ARMmbed/IOTTHD-3426
1a9be20 MAC unit tests: updated cca prepare test
fd5683d FHSS WS: Removed temporary debug traces
6527e05 MAC: Fixed multi csma
1e1f69a modified trickle analyse function for pan configuration
b7a8268 Merge pull request #2063 from ARMmbed/fhss_mac_retry_correct
a21bede CCA RETRY and and TX reretry clear calculation when FHSS re-send packet at new channel.
c7235f8 Merge pull request #2062 from ARMmbed/ns_aro_fix
4489dda Merge pull request #2060 from ARMmbed/IOTTHD-3426_traces
b1484d8 Corrected GAK generation flagging
db51b73 Configure Thread neighbour and destination cache (#2057)
0306276 FHSS WS: Added temporary debug traces
7d88d7f Enabled Multicast NS to trig NA for wi-sun.
609086d Do not add ack callback for multicast NS.
be18109 Fixed missing address re registration.
7d8dab4 IPv6 routing cache configuration update (#2056)
f701d39 Corrected PAN ID checking for NVM keys and MAC key remove on discovery
1eda5e3 Enabled mbed TLS to use nsdynmemlib on simulator
42c154d Merge pull request #2054 from ARMmbed/IOTTHD-3374
75cce02 Add bootstrap Down event when re-starting network discovery
aab7191 MAC: Use minimum CSMA for Asynch
3d93f64 Merge pull request #2053 from ARMmbed/ws_eapol_bootstrap
d29dfa7 Merge pull request #2052 from ARMmbed/IOTTHD-3375
7689c8c FHSS WS: Added maximum drift compensation step
7b55332 PAN Configuration failure fix and enabler
1a798ab FHHS old synch disable
47f65aa Merge pull request #2051 from ARMmbed/IOTTHD-3415
324902d Merge pull request #2048 from ARMmbed/IOTTHD-3388
142a32a Update Trickle expiration
c5f5fa7 omit NA messages from NS
5d29046 Merge pull request #2040 from ARMmbed/fix_compiler_warnings
8c0b6db FHSS WS: Fixed drifting TX trig timer
708a7d5 Review corrections
1f63902 Merge pull request #2047 from ARMmbed/eapol_bt
e9759e8 Added trigger to authenticator to re-start delayed EAP-TLS
30c538a Modified MLR handling
c56fa8d Code style fix
f298cd3 Parent synch fix and EAPOL synch fix
02942b0 Merge pull request #2046 from ARMmbed/iotthd-3260
5020291 Wi-sun dicovery trickle update
572861b Merge pull request #2041 from ARMmbed/iotthd-3309
e32d3c1 Merge pull request #2038 from ARMmbed/IOTTHD-3341
a2addf8 EAPOL parent synch update
b9e3ee0 FHSS WS: Implemented fhss retry logic
1c25c24 Corrected 4WH and GKH replay counters
45a76e1 Corrected eapol key length
39582e8 Merge pull request #2039 from ARMmbed/iotthd-3352
a428ba7 wi-sun LLC update
5ad1743 EAPOL helper update
db2e2cd Fix compiler warnings in MDNS service
924acad Fix armc6 compiler warnings
64e924e Check object before usage (#2036)
2d7e923 Corrected supplicant 4WH timeout after Message 1
6cde07a Merge pull request #2034 from ARMmbed/ws_aro_lifetime_fix
9c97cac Merge pull request #2032 from ARMmbed/ws_enable_multi_csma
80ecfdc WS: Enable checking CCA twice on TX channel
780e521 Fixxed ARO lifetime /60 +1 . now resolution is OK.
fe4073b Merge pull request #2030 from ARMmbed/IOTTHD-3340
902fdd8 create multicast forward check for PBBR
420c5be Disabled initial EAPOL-Key retry on GTK lifetime mismatch
25ae74e Merge pull request #2029 from ARMmbed/fhss_compensation_fix
6023d7b WS: change csma periods to 1 to make tests pass
b5a71c4 MAC unit tests: Updated CCA prepare test
a1f3ceb MAC: Make multi CSMA configurable
f4e9a1b Disable fhss compensation at parent selection if fixed channel mode is enabled for broadcast.
2417093 Added limits to number of EAP-TLS and TLS sessions
6845ab8 Corrected EAP-TLS retries and ids and initial EAPOL-Key handling
50961c9 Removed random from EAPOL PAN version increment
b862823 Fixed interop findings for DUA handling
a91a2b4 Thread discovery response update (#2024)
ffd4db2 MAC: Implemented double cca check
4ac7842 Corrected authenticator GTK setting
32af62b Merge pull request #2021 from ARMmbed/fhss_synch_fix
5c81b36 ws FHSS synch fix
9dfe724 Corrected 4WH retries and timeouts
b47c583 Added check for MBEDTLS_NIST_KW_C flag to nist KW module
2be2634 Merge pull request #2019 from ARMmbed/fhss_warnings_fix
342ca76 FHSS: Fixed IAR warnings from channel functions
359c7b9 Merge pull request #2017 from ARMmbed/IOTTHD-3065
570123d Merge pull request #2015 from ARMmbed/tls_free
1d7693b Change the re-registration delay (#2016)
b33e0c1 FHSS WS: Fixed large broadcast interval issue
9640ec0 Merge pull request #2014 from ARMmbed/IOTTHD-3338
798b513 Corrected TLS library free on failure cases
f6d1299 FHSS WS: Fixed compensation when on BC channel
5fa004c address entry removal updated (#2013)
a8e3e73 Test mode updates for BBR (#2011)
d8cc9b5 Merge pull request #2012 from ARMmbed/dhcp_fix
33cd6bf Typo realay->relay.
90a77aa DHCP relay and Renew update
bd12214 DHCP client address request update
74dc531 Merge pull request #1994 from ARMmbed/enable_eapol
e921dcd Merge pull request #2007 from ARMmbed/ws_mpl_fix
17e27a4 MTD status check added (#2010)
a0e893b Merge pull request #2008 from ARMmbed/IOTTHD-3234
274abdd address registration and coap port updates (#2009)
ae91f87 MAC: Increase backoff exponent when retry count grows
f871797 Merge pull request #2001 from ARMmbed/iotthd-2949
2b6ddf0 Corrected traces and coverity error
b0b804d Corrected security protocol data alignment
439e051 Corrected HMAC calculation
6962f42 Corrected traces
ff765cf Changed some hex traces to decimals for readability
bc3f4f1 Added session message counter check to supplicant 4WH
d963915 Corrected four way handshake Message 2 retry
1bcf070 Enable EAPOL flags
83fc53a Security policy check added. (#2004)
7b7e67c MPL SEED ID compres disable for wi-sun.
345c34f Merge pull request #2003 from ARMmbed/fix_rsl_out
716851d Thread uri updated. (#2005)
c4d81f4 WS neigh: Fixed reading RSL out
ac266e8 Merge pull request #2006 from ARMmbed/merge_nanostack_v10.1.1_changes_back_to_master
aaad726 Merge branch 'release_internal'
b4fc3f9 Update README (#2002)
64c5f23 Update Pan information when it heard from Parent.
2b61377 RPL DAO target request Update
bba1105 Merge pull request #1999 from ARMmbed/IOTTHD-3246
08dfcfc Merge branch 'release_internal'
4edc186 Extra security policy bits handling  (#1995)
5a42e88 Corrected PAE controller stop
ac2425c Corrected compiling errors
d4fded3 Merge pull request #1996 from ARMmbed/ws_bbr_pan_size
da6fd12 Fixed Default small network setup set to follow standard.
90a335b Merge pull request #1982 from ARMmbed/iotthd-3258
df2b98e Merge pull request #1979 from ARMmbed/IOTTHD-3233
2b356e0 Added next GTK set to empty functions
3ece393 Corrected compilation warnings from tracing and UT stubs
13e68c3 Corrected defects
ac51ec5 Corrected coverity, compiler and astyle errors
96c5496 Added GTK, PMK, PTK lifecycles and node's access of revocation
8f10a6e Fixed tlv length check. (#1992)
f2ba36d MAC unit tests: Missing stub added
1ef8dd6 Added public configuration API for Wi-SUN BBR
16d52fb Merge pull request #1991 from ARMmbed/aro_failure_fix
187ad94 Neighbour remove clear active Nud table if neighbor is at list.
5e89e16 Fix ARO register failure handler:
81cd273 Added an extra byte to security policy. (#1989)
cd1afb1 MAC: Fixed aborting active TX when sending Ack
b0a3c70 WS/MAC: removed trace causing crash, fixed MAC min BE set
3f0e56c FHSS WS: TX poll improvement to enhance hidden node situations
22cbb02 Merge pull request #1983 from ARMmbed/iothhd-2950
3835702 Address policy update's
aba9dd6 Updated new rule to address source select
2ed0f76 Fixed Echo request handle
6e31d0a Fix DHCPv6 relay:
f40f518 Added prefence time back to ULA prefix add wi-sun.
0bee3db Changed debug traces to info traces
1c45286 Fixed defects and coding style
553fbb1 Corrected memory error on security protocol finish
f47ad87 PAE supplicant and authenticator GTK update procedure
b4091c0 Defined WS RPL default configure

git-subtree-dir: features/nanostack/sal-stack-nanostack
git-subtree-split: 03454773bef569096bc177fb92930796a2d18c96
pull/10624/head^2
Arto Kinnunen 2019-05-21 14:22:20 +03:00
parent fbef0d8e70
commit 1c29564f65
131 changed files with 6327 additions and 1300 deletions

View File

@ -1,17 +1,39 @@
ARM IPV6/6LoWPAN stack.
ARM Mesh networking stack
=======================
This repository contains the ARM IPv6/6LoWPAN/Thread Stack for mbed OS.
This repository contains the ARM mesh networking stack that provides support for the following mesh protocols:
* 6LoWPAN with Neighbor Discovery (ND) and Mesh Link Establishment (MLE)
* Thread
* Wi-SUN
All networking stacks are using IEEE 802.15.4 based radios.
The full documentation is hosted in [Mbed OS documentation](https://os.mbed.com/docs/mbed-os/latest/reference/mesh-tech.html).
On mbed OS, mesh networking stacks can be used through [Mbed Mesh API](https://os.mbed.com/docs/mbed-os/latest/apis/mesh-api.html) and [Network Socket API](https://os.mbed.com/docs/mbed-os/v5.11/apis/network-socket.html).
To see, how the mesh networking stack works, check the example application [mbed-os-example-mesh-minimal](https://github.com/ARMmbed/mbed-os-example-mesh-minimal).
##6LoWPAN with ND and MLE
This networking stack is using standard 6LoWPAN and uses:
* Neighbor Discovery Protocol ([RFC4861](https://tools.ietf.org/html/rfc4861)) to locate other devices in the mesh network.
* Mesh-Link-Establishment ([draft-kelsey-intarea-mesh-link-establishment-06](https://tools.ietf.org/html/draft-kelsey-intarea-mesh-link-establishment-06)) is used for establishing and configuring secure radio links.
##Thread
Thread is standardized by [Thread group](https://www.threadgroup.org/).
![](docs/img/thread_certified.png)
mbed OS is now a Thread Certified Component. Using IPv6 with 6LoWPAN as the foundation, Thread technology provides a low-power, self-healing mesh network designed for the home.
The documentation is hosted in [here](https://os.mbed.com/docs/v5.6/tutorials/6lowpan-mesh.html).
##Wi-SUN
Wi-SUN (Smart Utility Networks) specification is standardized by [Wi-SUN Alliance](https://www.wi-sun.org/).
On mbed OS, usage is through [mbed Mesh API](https://os.mbed.com/docs/v5.6/reference/mesh.html) and [Socket API](https://os.mbed.com/docs/v5.6/reference/network-socket.html).
To see, how the 6LoWPAN Stack works, check the example application [mbed-os-example-mesh-minimal](https://github.com/ARMmbed/mbed-os-example-mesh-minimal).
Mbed OS release 5.12 contains the initial Mbed Wi-SUN FAN implementation. Functionality of the Mbed Wi-SUN network stack will be updated when the Wi-SUN protocol is specified further.
## License

View File

@ -133,6 +133,16 @@ uint16_t dhcp_service_init(int8_t interface_id, dhcp_instance_type_e instance_ty
*/
void dhcp_service_relay_instance_enable(uint16_t instance, uint8_t *server_address);
/**
* \brief Get DHCPv6 Relay Agent address pointer.
*
* \param instance The instance ID of the registered server.
*
* \return NULL when address is not available
* {
*/
uint8_t *dhcp_service_relay_global_addres_get(uint16_t instance);
/**
* \brief Deletes a server instance.
@ -188,6 +198,15 @@ uint32_t dhcp_service_send_req(uint16_t instance_id, uint8_t options, void *ptr,
*/
void dhcp_service_set_retry_timers(uint32_t msg_tr_id, uint16_t timeout_init, uint16_t timeout_max, uint8_t retrans_max);
/**
* \brief Update DHCP service server address to active tx process.
*
* \param msg_tr_id The message transaction ID.
* \param server_address New destination address to server / relay Agent.
*
*/
void dhcp_service_update_server_address(uint32_t msg_tr_id, uint8_t *server_address);
/**
* \brief Stops transactions for a message (retransmissions).
*

View File

@ -143,13 +143,13 @@ typedef int16_t fhss_synch_state_set(const fhss_api_t *api, fhss_states fhss_sta
typedef uint32_t fhss_read_timestamp(const fhss_api_t *api);
/**
* @brief Get retransmission period. FHSS uses different retry periods for different destinations.
* @brief Get additional retransmission period. FHSS uses different retry periods depending on destination or channel availability.
* @param api FHSS instance.
* @param destination_address Destination MAC address.
* @param phy_mtu PHY MTU size.
* @return Retransmission period.
* @return Retransmission period in microsecond which should be added to normal backoff period.
*/
typedef uint16_t fhss_get_retry_period(const fhss_api_t *api, uint8_t *destination_address, uint16_t phy_mtu);
typedef uint32_t fhss_get_retry_period(const fhss_api_t *api, uint8_t *destination_address, uint16_t phy_mtu);
/**
* @brief Write synchronization info to given pointer.

View File

@ -264,6 +264,7 @@ typedef enum {
macAutoRequestKeyIndex = 0x7b, /*<The index of the key used for automatic data*/
macDefaultKeySource = 0x7c, /*<Default key source*/
//NON standard extension
macMultiCSMAParameters = 0xfa, /*<Multi CSMA parameters*/
macRfConfiguration = 0xfb, /*<RF channel configuration parameters*/
macAcceptByPassUnknowDevice = 0xfc, /*< Accept data trough MAC if packet is data can be authenticated by group key nad MIC. Security enforsment point must be handled carefully these packets */
macLoadBalancingBeaconTx = 0xfd, /*< Trig Beacon from load balance module periodic */
@ -499,4 +500,14 @@ typedef struct mlme_poll_conf_s {
uint8_t status; /**< Status of Poll operation */
} mlme_poll_conf_t;
/**
* @brief struct mlme_multi_csma_ca_param_s Set multi CSMA-CA parameters
*
* Non standard extension to perform CCA multiple times before transmission
*/
typedef struct mlme_multi_csma_ca_s {
uint8_t number_of_csma_ca_periods; /**< Number of CSMA-CA periods */
uint16_t multi_cca_interval; /**< Length of the additional CSMA-CA period(s) in microseconds */
} mlme_multi_csma_ca_param_t;
#endif /* MLME_H_ */

View File

@ -51,6 +51,40 @@ int8_t arm_nwk_ipv6_frag_mru(uint16_t frag_mru);
*/
int8_t arm_nwk_ipv6_max_cache_entries(uint16_t max_entries);
/**
* \brief Configure destination cache.
*
* Set destination cache maximum entry count, thresholds where amount of entries is kept during operation and lifetime.
*
* Note: This must be called before arm_nwk_interface_lowpan_init()
*
* \param max_entries Maximum number of entries allowed in destination cache at any time.
* \param short_term_threshold Amount of cache entries kept in memory in short term. Must be less than max_entries.
* \param long_term_threshold Amount of entries kept in memory over long period of time. Must be less than short_term_threshold.
* \param lifetime Lifetime of cache entry, must be over 120 seconds
*
* \return 0 Change OK.
* \return <0 Change invalid - unable to change the maximum for cache.
*/
int8_t arm_nwk_ipv6_destination_cache_configure(uint16_t max_entries, uint16_t short_term_threshold, uint16_t long_term_threshold, uint16_t lifetime);
/**
* \brief Configure neighbour cache.
*
* Set neighbour cache maximum entry count, thresholds where amount of entries is kept during operation and lifetime.
*
* Note: This must be called before arm_nwk_interface_lowpan_init()
*
* \param max_entries Maximum number of entries allowed in neighbour cache at any time.
* \param short_term_threshold Amount of cache entries kept in memory in short term. Must be less than max_entries.
* \param long_term_threshold Amount of entries kept in memory over long period of time. Must be less than short_term_threshold.
* \param lifetime Lifetime of cache entry, must be over 120 seconds
*
* \return 0 Change OK.
* \return <0 Change invalid - unable to change the maximum for cache.
*/
int8_t arm_nwk_ipv6_neighbour_cache_configure(uint16_t max_entries, uint16_t short_term_threshold, uint16_t long_term_threshold, uint16_t lifetime);
/**
* \brief Configure automatic flow label calculation.
*

View File

@ -241,6 +241,19 @@ int thread_test_version_set(int8_t interface_id, uint8_t version);
*/
int thread_test_router_selection_jitter_set(int8_t interface_id, uint32_t jitter);
/**
* \brief Set Thread PBBR status response override.
*
* \param interface_id Network Interface
* \param dua_status expected dua response value from PBBR
* \param dua_count number of times dua_response is repeated
* \param ba_failure_count number of times bba failure is repeated
*
* \return 0, OK
* \return <0 Error
*/
int thread_test_pbbr_response_override_set(int8_t interface_id, uint8_t dua_status, uint8_t dua_count, uint8_t ba_failure_count);
/**
* \brief Sets the thread MIN_DELAY_TIMER default value.
*

View File

@ -113,9 +113,9 @@ int ws_test_active_key_set(int8_t interface_id, uint8_t index);
* Pairwise Transient Key (PTK) lifetimes.
*
* \param interface_id Network interface ID.
* \param gtk_lifetime GTK lifetime in minutes
* \param pmk_lifetime PMK lifetime in minutes
* \param ptk_lifetime PTK lifetime in minutes
* \param gtk_lifetime GTK lifetime in minutes or zero if value is not changed
* \param pmk_lifetime PMK lifetime in minutes or zero if value is not changed
* \param ptk_lifetime PTK lifetime in minutes or zero if value is not changed
*
* \return 0 Lifetimes are set
* \return <0 Lifetime set has failed
@ -135,9 +135,10 @@ int ws_test_key_lifetime_set(
* maximum mismatch time in minutes.
*
* \param interface_id Network interface ID.
* \param revocat_lifetime_reduct GTK Revocation Lifetime Reduction (1 / value * GTK lifetime)
* \param new_activation_time GTK New Activation Time (1 / value * GTK lifetime)
* \param max_mismatch GTK maximum mismatch in minutes
* \param revocat_lifetime_reduct GTK Revocation Lifetime Reduction (1 / value * GTK lifetime) or zero if value is not changed
* \param new_activation_time GTK New Activation Time (1 / value * GTK lifetime) or zero if value is not changed
* \param new_install_req GTK New Install Required (percent * GTK lifetime) or zero if value is not changed
* \param max_mismatch GTK maximum mismatch in minutes or zero if value is not changed
*
* \return 0 Lifetimes are set
* \return <0 Lifetime set has failed.
@ -146,9 +147,26 @@ int ws_test_gtk_time_settings_set(
int8_t interface_id,
uint8_t revocat_lifetime_reduct,
uint8_t new_activation_time,
uint8_t new_install_req,
uint32_t max_mismatch
);
/**
* Sets Next Group Transient Keys used during GTK life cycle
*
* Sets next Group Transient Keys (GTKs) used during GTK life cycle. Up to four
* GTKs can be set (GTKs from index 0 to 3). When next GTK(s) are set, border
* router inserts GTKs from the next GTK list into use during GTK update
* procedure.
*
* \param interface_id Network interface ID.
* \param gtk GTK array, if GTK is not set, pointer for the index shall be NULL.
*
* \return 0 GTKs are set
* \return <0 GTK set has failed
*/
int ws_test_next_gtk_set(int8_t interface_id, uint8_t *gtk[4]);
#ifdef __cplusplus
}
#endif

View File

@ -29,6 +29,11 @@
extern "C" {
#endif
/** PHY_LINK_CCA_PREPARE status definitions */
#define PHY_TX_NOT_ALLOWED -1 /**< TX not allowed. Do not continue to CCA process. */
#define PHY_TX_ALLOWED 0 /**< TX allowed. Continue to CCA process. */
#define PHY_RESTART_CSMA 1 /**< Restart CSMA-CA timer. CSMA-CA period must be calculated using given backoff time (PHY_EXTENSION_SET_CSMA_PARAMETERS) */
/** Interface states */
typedef enum {
PHY_INTERFACE_RESET, /**< Reset PHY driver and set to idle. */
@ -45,9 +50,16 @@ typedef enum {
PHY_LINK_TX_SUCCESS, /**< MAC TX complete. MAC will a make decision to enter wait ACK or TX done state. */
PHY_LINK_TX_FAIL, /**< Link TX process fail. */
PHY_LINK_CCA_FAIL, /**< RF link CCA process fail. */
PHY_LINK_CCA_PREPARE, /**< RX Tx timeout prepare operation like channel switch to Tx channel from Receive one If operation fail must return not zero*/
PHY_LINK_CCA_OK, /**< RF link CCA process ok. */
PHY_LINK_CCA_PREPARE, /**< Prepare for CCA after CSMA-CA: changes to CCA channel and gives permission to TX. See PHY_LINK_CCA_PREPARE status definitions for return values */
} phy_link_tx_status_e;
/** MAC filtering modes. Set corresponding bit to 1 (1 << MAC_FRAME_VERSION_X) in PHY_EXTENSION_FILTERING_SUPPORT request when PHY can handle the filtering of this frame type.
* NOTE: Currently MAC supports filtering and Acking only 802.15.4-2015 frames. Any other frame version must be filtered and Acked by PHY with either HW or SW solution. */
typedef enum {
MAC_FRAME_VERSION_2 = 2 /**< 802.15.4-2015 */
} phy_link_filters_e;
/** Extension types */
typedef enum {
PHY_EXTENSION_CTRL_PENDING_BIT, /**< Control MAC pending bit for indirect data. */
@ -64,7 +76,8 @@ typedef enum {
PHY_EXTENSION_GET_TIMESTAMP, /**< Read 32-bit constant monotonic time stamp in us */
PHY_EXTENSION_SET_CSMA_PARAMETERS, /**< CSMA parameter's are given by phy_csma_params_t structure remember type cast uint8_t pointer to structure type*/
PHY_EXTENSION_GET_SYMBOLS_PER_SECOND, /**< Read Symbols per seconds which will help to convert symbol time to real time */
PHY_EXTENSION_SET_RF_CONFIGURATION /**< Set RF configuration using phy_rf_channel_parameters_s structure */
PHY_EXTENSION_SET_RF_CONFIGURATION, /**< Set RF configuration using phy_rf_channel_parameters_s structure */
PHY_EXTENSION_FILTERING_SUPPORT /**< Return filtering modes that can be supported by the PHY driver. See phy_link_filters_e */
} phy_extension_type_e;
/** Address types */

View File

@ -83,6 +83,7 @@ typedef struct link_configuration {
uint8_t version; /**< current protocol version*/
uint16_t rfChannel; /**< current rf channel*/
uint8_t securityPolicy; /**< Commission Security Policy*/
uint8_t securityPolicyExt; /**< Additional Security Policy byte*/
uint64_t timestamp;/**< commissioning data set timestamp. [48 bit timestamp seconds]-[15 bit timestamp ticks]-[U bit] */
} link_configuration_s;

View File

@ -45,6 +45,36 @@
*/
int ws_bbr_start(int8_t interface_id, int8_t backbone_interface_id);
/**
* Border router configuration options
*/
#define BBR_ULA_C 0x0001 /**< Static ULA prefix created automatically */
#define BBR_GUA_C 0x0002 /**< Routable prefix is learned from the backbone */
#define BBR_GUA_ROUTE 0x0004 /**< More specific route is added for GUA prefix */
#define BBR_GUA_SLAAC 0x0008 /**< Use SLAAC addressing in routable prefix */
#define BBR_GUA_WAIT 0x0010 /**< Wait backbone availability before starting RPL dodag */
#define BBR_BB_WAIT 0x0020 /**< Wait backbone availability before starting Wi-SUN network */
/**
* Configure border router features.
*
* \param interface_id interface ID of the Wi-SUN network
* \param options Options configured to Border router
* BBR_ULA_C Configure Mesh local ULA prefix with SLAAC address (default)
* BBR_GUA_C Configure GUA/ULA prefix from backbone to RPL (default)
* BBR_GUA_ROUTE Add more specific route for GUA (default)
* BBR_GUA_SLAAC Use SLAAC address generation in GUA prefix
* BBR_GUA_WAIT Start RPL root only when GUA is available
* BBR_BB_WAIT Start Wi-SUN network only when backbone is ready
*
* By default Wi-SUN network is started and is treated as separate interface even if backbone is not available.
*
* Default route RPL options when backbone is set up. RPL root is always Grounded
*
* \return 0 on success
* \return <0 in case of errors
*
*/
int ws_bbr_configure(int8_t interface_id, uint16_t options);
/**
* Stop backbone Border router.
*

View File

@ -339,6 +339,26 @@ int8_t mac_helper_security_default_key_set(protocol_interface_info_entry_t *inte
return 0;
}
int8_t mac_helper_security_default_recv_key_set(protocol_interface_info_entry_t *interface, const uint8_t *key, uint8_t id, uint8_t keyid_mode)
{
if (id == 0 || keyid_mode > 3) {
return -1;
}
mac_helper_keytable_descriptor_set(interface->mac_api, key, id, interface->mac_parameters->mac_default_key_attribute_id);
return 0;
}
int8_t mac_helper_security_auto_request_key_index_set(protocol_interface_info_entry_t *interface, uint8_t id)
{
if (id == 0) {
return -1;
}
mac_helper_pib_8bit_set(interface, macAutoRequestKeyIndex, id);
return 0;
}
int8_t mac_helper_security_pairwisekey_set(protocol_interface_info_entry_t *interface, const uint8_t *key, const uint8_t *mac_64, uint8_t key_attribute)
{
@ -374,6 +394,33 @@ int8_t mac_helper_security_prev_key_set(protocol_interface_info_entry_t *interfa
}
int8_t mac_helper_security_key_to_descriptor_set(protocol_interface_info_entry_t *interface, const uint8_t *key, uint8_t id, uint8_t descriptor)
{
if (id == 0) {
return -1;
}
mac_helper_keytable_descriptor_set(interface->mac_api, key, id, descriptor);
return 0;
}
int8_t mac_helper_security_key_descriptor_clear(protocol_interface_info_entry_t *interface, uint8_t descriptor)
{
if (!interface->mac_api) {
return -1;
}
mlme_set_t set_req;
mlme_key_descriptor_entry_t key_description;
memset(&key_description, 0, sizeof(mlme_key_descriptor_entry_t));
set_req.attr = macKeyTable;
set_req.value_pointer = &key_description;
set_req.value_size = sizeof(mlme_key_descriptor_entry_t);
set_req.attr_index = descriptor;
interface->mac_api->mlme_req(interface->mac_api, MLME_SET, &set_req);
return 0;
}
void mac_helper_security_key_swap_next_to_default(protocol_interface_info_entry_t *interface)
{

View File

@ -67,10 +67,18 @@ uint8_t mac_helper_default_key_index_get(struct protocol_interface_info_entry *i
int8_t mac_helper_security_default_key_set(struct protocol_interface_info_entry *interface, const uint8_t *key, uint8_t id, uint8_t keyid_mode);
int8_t mac_helper_security_default_recv_key_set(struct protocol_interface_info_entry *interface, const uint8_t *key, uint8_t id, uint8_t keyid_mode);
int8_t mac_helper_security_auto_request_key_index_set(struct protocol_interface_info_entry *interface, uint8_t id);
int8_t mac_helper_security_next_key_set(struct protocol_interface_info_entry *interface, uint8_t *key, uint8_t id, uint8_t keyid_mode);
int8_t mac_helper_security_prev_key_set(struct protocol_interface_info_entry *interface, uint8_t *key, uint8_t id, uint8_t keyid_mode);
int8_t mac_helper_security_key_to_descriptor_set(struct protocol_interface_info_entry *interface, const uint8_t *key, uint8_t id, uint8_t descriptor);
int8_t mac_helper_security_key_descriptor_clear(struct protocol_interface_info_entry *interface, uint8_t descriptor);
void mac_helper_security_key_swap_next_to_default(struct protocol_interface_info_entry *interface);
int8_t mac_helper_security_pairwisekey_set(struct protocol_interface_info_entry *interface, const uint8_t *key, const uint8_t *mac_64, uint8_t key_attribute);

View File

@ -926,7 +926,7 @@ 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)) {
!ws_common_allow_child_registration(cur_interface, aro_out->eui64)) {
aro_out->present = true;
aro_out->status = ARO_FULL;
return true;

View File

@ -34,6 +34,7 @@
#ifdef HAVE_THREAD_V2
void thread_address_registration_init(void);
bool thread_address_registration_running(void);
void thread_address_registration_deinit(void);
void thread_address_registration_timer_set(protocol_interface_info_entry_t *interface, uint16_t dua_delay_seconds, uint16_t mlr_refresh_seconds);
@ -41,6 +42,7 @@ void thread_address_registration_timer(protocol_interface_info_entry_t *interfac
#else
#define thread_address_registration_init(void)
#define thread_address_registration_running(void)
#define thread_address_registration_deinit(void)
#define thread_address_registration_timer_set(interface, dua_delay_seconds, mlr_refresh_seconds);

View File

@ -517,6 +517,34 @@ static int thread_border_relay_to_leader_cb(int8_t service_id, uint8_t source_ad
}
#ifdef HAVE_THREAD_BORDER_ROUTER
static bool thread_bbr_default_route_exists(struct protocol_interface_info_entry *cur, uint8_t prefix_ptr[8])
{
uint16_t rloc16 = mac_helper_mac16_address_get(cur);
ns_list_foreach(thread_network_data_prefix_cache_entry_t, prefix, &cur->thread_info->networkDataStorage.localPrefixList) {
if (prefix_ptr &&
(prefix->servicesPrefixLen != 64 ||
memcmp(prefix_ptr, prefix->servicesPrefix, 8) != 0)) {
// Only matching prefixes are counted
continue;
}
ns_list_foreach(thread_network_server_data_entry_t, br, &prefix->borderRouterList) {
if (br->routerID == 0xfffe) {
continue;
}
if (!br->P_default_route) {
continue;
}
if (rloc16 != br->routerID) {
// different default route exists
return true;
}
}
}
return false;
}
static bool thread_bbr_i_host_prefix(struct protocol_interface_info_entry *cur, uint8_t prefix_ptr[8], uint8_t *br_count, bool *i_am_lowest)
{
bool i_host_this_prefix = false;
@ -600,14 +628,15 @@ static void thread_bbr_network_data_send(thread_bbr_t *this, uint8_t prefix[8],
this->br_info_published = true;
}
static void thread_bbr_routing_enable(thread_bbr_t *this)
static void thread_bbr_routing_enable(thread_bbr_t *this, bool multicast_routing_enabled)
{
if (this->routing_enabled) {
return;
}
tr_info("br: enable routing");
// Start multicast proxying
multicast_fwd_set_forwarding(this->interface_id, true);
// We do not enable multicast forwarding as there is other default router present in network
multicast_fwd_set_forwarding(this->interface_id, multicast_routing_enabled);
this->routing_enabled = true;
}
@ -663,7 +692,13 @@ static void thread_bbr_status_check(thread_bbr_t *this, uint32_t seconds)
// Check from network data are we currently BR or not and change routing state
if (this->br_hosted) {
thread_bbr_routing_enable(this);
//If there is a default router present in any prefix other than us we do not forward multicast
//This prevents multicasts to different interfaces where Thread Mesh is forwarder
bool forward_multicast = !thread_bbr_default_route_exists(cur, NULL);
thread_extension_bbr_mcast_fwd_check(cur->id, &forward_multicast);
thread_bbr_routing_enable(this, forward_multicast);
} else {
thread_bbr_routing_disable(this);
}
@ -896,6 +931,15 @@ int8_t thread_bbr_init(int8_t interface_id, uint16_t external_commisssioner_port
return 0;
}
int8_t thread_bbr_get_commissioner_service(int8_t interface_id)
{
thread_bbr_t *this = thread_bbr_find_by_interface(interface_id);
if (!this) {
return 0;
}
return this->br_service_id;
}
void thread_bbr_delete(int8_t interface_id)
{
thread_bbr_t *this = thread_bbr_find_by_interface(interface_id);
@ -1100,8 +1144,11 @@ int thread_bbr_start(int8_t interface_id, int8_t backbone_interface_id)
// By default multicast forwarding is not enabled as it causes multicast loops
multicast_fwd_set_forwarding(this->interface_id, false);
// Adjust BBR neighbor and destination cache size
arm_nwk_ipv6_max_cache_entries(THREAD_BBR_IPV6_DESTINATION_CACHE_SIZE);
// Configure BBR neighbour cache parameters
arm_nwk_ipv6_neighbour_cache_configure(THREAD_BBR_IPV6_NEIGHBOUR_CACHE_SIZE,
THREAD_BBR_IPV6_NEIGHBOUR_CACHE_SHORT_TERM,
THREAD_BBR_IPV6_NEIGHBOUR_CACHE_LONG_TERM,
THREAD_BBR_IPV6_NEIGHBOUR_CACHE_LIFETIME);
thread_extension_bbr_init(interface_id, backbone_interface_id);
@ -1125,6 +1172,7 @@ int thread_bbr_timeout_set(int8_t interface_id, uint32_t timeout_a, uint32_t tim
#endif // HAVE_THREAD_BORDER_ROUTER
}
int thread_bbr_prefix_set(int8_t interface_id, uint8_t *prefix)
{
(void) interface_id;
@ -1159,8 +1207,6 @@ int thread_bbr_validation_interface_address_set(int8_t interface_id, const uint8
#endif // HAVE_THREAD_BORDER_ROUTER
}
void thread_bbr_stop(int8_t interface_id)
{
(void) interface_id;

View File

@ -66,6 +66,13 @@ void thread_bbr_seconds_timer(int8_t interface_id, uint32_t tics);
* \param interface_id current interface id
*/
int thread_bbr_commissioner_proxy_service_update(int8_t interface_id);
/**
* \brief get commissioner service id to add new services
*
* \param interface_id current interface id
* \return service id or 0 if invalid
*/
int8_t thread_bbr_get_commissioner_service(int8_t interface_id);
#else
#define thread_bbr_init(interface_id, external_commisssioner_port)

View File

@ -888,6 +888,7 @@ void thread_interface_init(protocol_interface_info_entry_t *cur)
thread_discovery_reset(cur->id);
thread_routing_set_mesh_callbacks(cur);
dhcp_client_init(cur->id);
dhcp_client_configure(cur->id, false, false, false);
thread_management_client_init(cur->id);
thread_address_registration_init();
cur->mpl_seed_id_mode = MULTICAST_MPL_SEED_ID_MAC_SHORT;
@ -945,6 +946,31 @@ static void thread_interface_bootsrap_mode_init(protocol_interface_info_entry_t
tr_debug("Set End node Mode");
cur->thread_info->thread_device_mode = THREAD_DEVICE_MODE_END_DEVICE;
}
if (cur->thread_info->thread_device_mode == THREAD_DEVICE_MODE_ROUTER) {
// set router neighbour cache
ipv6_neighbour_cache_configure(THREAD_ROUTER_IPV6_NEIGHBOUR_CACHE_SIZE,
THREAD_ROUTER_IPV6_NEIGHBOUR_CACHE_SHORT_TERM,
THREAD_ROUTER_IPV6_NEIGHBOUR_CACHE_LONG_TERM,
THREAD_ROUTER_IPV6_NEIGHBOUR_CACHE_LIFETIME);
// set router destination cache
ipv6_destination_cache_configure(THREAD_ROUTER_IPV6_DESTINATION_CACHE_SIZE,
THREAD_ROUTER_IPV6_DESTINATION_CACHE_SHORT_TERM,
THREAD_ROUTER_IPV6_DESTINATION_CACHE_LONG_TERM,
THREAD_ROUTER_IPV6_DESTINATION_CACHE_LIFETIME);
} else {
// device is some sort of end device
ipv6_neighbour_cache_configure(THREAD_END_DEVICE_IPV6_NEIGHBOUR_CACHE_SIZE,
THREAD_END_DEVICE_IPV6_NEIGHBOUR_CACHE_SHORT_TERM,
THREAD_END_DEVICE_IPV6_NEIGHBOUR_CACHE_LONG_TERM,
THREAD_END_DEVICE_IPV6_NEIGHBOUR_CACHE_LIFETIME);
ipv6_destination_cache_configure(THREAD_END_DEVICE_IPV6_DESTINATION_CACHE_SIZE,
THREAD_END_DEVICE_IPV6_DESTINATION_CACHE_SHORT_TERM,
THREAD_END_DEVICE_IPV6_DESTINATION_CACHE_LONG_TERM,
THREAD_END_DEVICE_IPV6_DESTINATION_CACHE_LIFETIME);
}
cur->thread_info->thread_attached_state = THREAD_STATE_NETWORK_DISCOVER;
}
@ -2540,7 +2566,7 @@ int thread_bootstrap_network_data_process(protocol_interface_info_entry_t *cur,
} else {
tr_debug("SLAAC address set as NOT preferred.");
}
addr_set_preferred_lifetime(cur, e, genericService.P_preferred ? 0xfffffffff : 0);
addr_set_preferred_lifetime(cur, e, genericService.P_preferred ? 0xffffffff : 0);
}
}
}

View File

@ -988,11 +988,7 @@ void thread_seconds_timer(protocol_interface_info_entry_t *cur, uint32_t ticks)
thread_resolution_client_timer(cur->id, ticks);
thread_key_switch_timer(cur, ticks);
thread_child_update_req_timer(cur, ticks);
if (!thread_bootstrap_should_register_address(cur)) {
/* Only FTD refreshes the address registration timer */
thread_address_registration_timer(cur, ticks);
}
if (thread_attach_ready(cur) != 0) {
return;

View File

@ -192,6 +192,7 @@ typedef struct thread_connectivity_s {
typedef struct thread_parent_info_s {
uint8_t mac64[8];
uint16_t shortAddress;
uint16_t version;
uint8_t router_id;
uint8_t pathCostToLeader;
bool childUpdatePending: 1;

View File

@ -326,11 +326,34 @@
*/
#define THREAD_BBR_ROUTER_ID_REQUEST_STATUS THREAD_COAP_STATUS_TLV_HAVE_CHILD_ID_REQUEST
/*
* Number of destination and neighbor cache entries assuming 250 thread devices (worst case) connecting to cloud service.
/* Border Router IPv6 neighbour and destination cache configuration
* Number of neighbor cache entries assuming 250 thread devices (worst case) connecting to cloud service.
* Six entries reserved for backbone devices.
*/
#define THREAD_BBR_IPV6_DESTINATION_CACHE_SIZE 256
#define THREAD_BBR_IPV6_NEIGHBOUR_CACHE_SIZE 256
#define THREAD_BBR_IPV6_NEIGHBOUR_CACHE_SHORT_TERM 128
#define THREAD_BBR_IPV6_NEIGHBOUR_CACHE_LONG_TERM 32
#define THREAD_BBR_IPV6_NEIGHBOUR_CACHE_LIFETIME 600
/* Router IPv6 neighbour and destination cache configuration */
#define THREAD_ROUTER_IPV6_NEIGHBOUR_CACHE_SIZE 128
#define THREAD_ROUTER_IPV6_NEIGHBOUR_CACHE_SHORT_TERM 64
#define THREAD_ROUTER_IPV6_NEIGHBOUR_CACHE_LONG_TERM 8
#define THREAD_ROUTER_IPV6_NEIGHBOUR_CACHE_LIFETIME 600
#define THREAD_ROUTER_IPV6_DESTINATION_CACHE_SIZE 32
#define THREAD_ROUTER_IPV6_DESTINATION_CACHE_SHORT_TERM 16
#define THREAD_ROUTER_IPV6_DESTINATION_CACHE_LONG_TERM 4
#define THREAD_ROUTER_IPV6_DESTINATION_CACHE_LIFETIME 600
/* End device IPv6 neighbour and destination cache configuration */
#define THREAD_END_DEVICE_IPV6_NEIGHBOUR_CACHE_SIZE 32
#define THREAD_END_DEVICE_IPV6_NEIGHBOUR_CACHE_SHORT_TERM 16
#define THREAD_END_DEVICE_IPV6_NEIGHBOUR_CACHE_LONG_TERM 4
#define THREAD_END_DEVICE_IPV6_NEIGHBOUR_CACHE_LIFETIME 600
#define THREAD_END_DEVICE_IPV6_DESTINATION_CACHE_SIZE 16
#define THREAD_END_DEVICE_IPV6_DESTINATION_CACHE_SHORT_TERM 8
#define THREAD_END_DEVICE_IPV6_DESTINATION_CACHE_LONG_TERM 4
#define THREAD_END_DEVICE_IPV6_DESTINATION_CACHE_LIFETIME 600
/*
* Timeout to solicit address from DHCP if previous request fails.

View File

@ -49,6 +49,7 @@ void thread_extension_mtd_service_register(protocol_interface_info_entry_t *cur)
void thread_extension_network_data_process(struct protocol_interface_info_entry *cur);
int thread_extension_primary_bbr_get(struct protocol_interface_info_entry *cur, uint8_t *addr_ptr, uint8_t *seq_ptr, uint32_t *timer1_ptr, uint32_t *timer2_ptr);
void thread_extension_address_registration(struct protocol_interface_info_entry *interface, const uint8_t *addr, const uint8_t *child_mac64, bool refresh_child_entry, bool duplicate_child_detected);
void thread_extension_child_address_registration_response_process(struct protocol_interface_info_entry *interface);
void thread_extension_dua_address_generate(protocol_interface_info_entry_t *cur, const uint8_t *domain_prefix, uint8_t domain_prefix_len);
void thread_extension_aloc_generate(struct protocol_interface_info_entry *cur);
bool thread_extension_aloc_map(protocol_interface_info_entry_t *cur, uint16_t *addr16);
@ -62,11 +63,13 @@ int thread_extension_service_init(protocol_interface_info_entry_t *cur);
void thread_extension_addr_ntf_send(struct protocol_interface_info_entry *cur, uint8_t *destination_address, const uint8_t *addr_data_ptr, uint8_t bbr_status);
#ifdef HAVE_THREAD_ROUTER
bool thread_extension_joining_enabled(int8_t interface_id);
bool thread_extension_is_reed_upgrade_allowed(protocol_interface_info_entry_t *cur);
uint8_t thread_extension_discover_response_len(protocol_interface_info_entry_t *cur);
uint8_t *thread_extension_discover_response_write(protocol_interface_info_entry_t *cur, uint8_t *ptr);
#else
#define thread_extension_joining_enabled(interface_id) (false)
#define thread_extension_is_reed_upgrade_allowed(cur) (true)
#define thread_extension_discover_response_len(cur) (0)
#define thread_extension_discover_response_write(cur, ptr) (ptr)
#endif //HAVE_THREAD_ROUTER
@ -78,10 +81,12 @@ uint8_t *thread_extension_discover_response_write(protocol_interface_info_entry_
#define thread_extension_network_data_process(cur) ((void) 0)
#define thread_extension_primary_bbr_get(cur,addr_ptr,seq_ptr,timer1_ptr, timer2_ptr) (-1)
#define thread_extension_address_registration(interface,addr,child_mac64,refresh_child_entry,duplicate_child_detected) ((void) 0)
#define thread_extension_child_address_registration_response_process(interface) ((void) 0)
#define thread_extension_aloc_generate(cur) ((void) 0)
#define thread_extension_aloc_map(cur, addr16) (false)
#define thread_extension_mcast_subscrition_change(interface) ((void) 0)
#define thread_extension_enabled(cur) (false)
#define thread_extension_is_reed_upgrade_allowed(cur) (true)
#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)

View File

@ -47,7 +47,6 @@ typedef struct thread_pbbr_dua_info {
} thread_pbbr_dua_info_t;
#if defined(HAVE_THREAD_V2) && defined(HAVE_THREAD_BORDER_ROUTER)
int8_t thread_extension_bbr_init(int8_t interface_id, int8_t backbone_interface_id);
void thread_extension_bbr_delete(int8_t interface_id);
bool thread_extension_bbr_nd_query_process(protocol_interface_info_entry_t *cur, const uint8_t *target_addr, uint16_t rloc);
@ -58,6 +57,10 @@ int thread_extension_bbr_address_set(int8_t interface_id, const uint8_t *addr_pt
void thread_extension_bbr_route_update(protocol_interface_info_entry_t *cur);
int thread_extension_bbr_prefix_set(int8_t interface_id, uint8_t *prefix);
void thread_extension_bbr_old_partition_data_clean(int8_t interface_id);
void thread_extension_bbr_status_override_get(uint8_t *dua_status, uint8_t *dua_count, uint8_t *ba_failure_count);
void thread_extension_bbr_status_override_set(uint8_t dua_status, uint8_t dua_count, uint8_t ba_failure_count);
void thread_extension_status_override_count_set(uint8_t value);
void thread_extension_bbr_mcast_fwd_check(int8_t interface_id, bool *multicast_fwd);
#else
@ -72,6 +75,10 @@ void thread_extension_bbr_old_partition_data_clean(int8_t interface_id);
#define thread_extension_bbr_sequence_number_set(interface_id, seq_number) (-1)
#define thread_extension_bbr_prefix_set(interface_id, prefix) 0
#define thread_extension_bbr_old_partition_data_clean(interface_id)
#define thread_extension_bbr_status_override_get(dua_status, dua_count, ba_failure_count);
#define thread_extension_bbr_status_override_set(dua_status, dua_count, ba_failure_count);
#define thread_extension_status_override_count_set(value)
#define thread_extension_bbr_mcast_fwd_check(interface_id, multicast_fwd)
#endif
#ifdef __cplusplus

View File

@ -1,3 +1,4 @@
/*
* Copyright (c) 2017-2019, Arm Limited and affiliates.
* SPDX-License-Identifier: BSD-3-Clause
@ -38,6 +39,7 @@ extern "C" {
#define thread_extension_bootstrap_free(cur);
#define thread_extension_bootstrap_device_certificate_set(cur, device_certificate_ptr, device_certificate_len, priv_key_ptr, priv_key_len) (-1)
#define thread_extension_bootstrap_network_certificate_set(cur, domain_certificate_ptr, domain_certificate_len) (-1)
#define thread_extension_bootstrap_network_certificate_available(cur) (false)
#define thread_extension_bootstrap_network_private_key_set(cur, priv_key_ptr, priv_key_len) (-1)
#define thread_extension_bootstrap_thread_name_set(cur, thread_name) (-1)
#define thread_extension_bootstrap_commission_start(cur, parent_address, port, done_cb) (-1)

View File

@ -897,6 +897,7 @@ static void thread_mle_child_request_receive_cb(int8_t interface_id, mle_message
parent->shortAddress = scan_result->shortAddress;
parent->router_id = (scan_result->shortAddress >> 10);
memcpy(parent->mac64, scan_result->mac64, 8);
parent->version = scan_result->version;
//Check Network Data TLV
if (networkDataTlv.tlvType == MLE_TYPE_NETWORK_DATA) {
thread_bootstrap_network_data_save(cur, &leaderData, networkDataTlv.dataPtr, networkDataTlv.tlvLen);

View File

@ -58,6 +58,7 @@
#include "thread_network_synch.h"
#include "thread_network_data_lib.h"
#include "thread_joiner_application.h"
#include "thread_extension.h"
#include "6LoWPAN/Thread/thread_extension_bootstrap.h"
#include "mac_api.h"
#include "6LoWPAN/MAC/mac_helper.h"
@ -318,6 +319,7 @@ static link_configuration_s *link_configuration_create(void)
}
memset(this, 0, sizeof(link_configuration_s));
this->securityPolicy = SECURITY_POLICY_ALL_SECURITY; // Set all default values ('1') for security policy flags
this->securityPolicyExt = SECURITY_POLICY_ALL_SECURITY; // Set all default values
return this;
}
@ -345,6 +347,7 @@ static void link_configuration_copy(link_configuration_s *this, link_configurati
this->panId = configuration_ptr->panId;
this->rfChannel = configuration_ptr->rfChannel;
this->securityPolicy = configuration_ptr->securityPolicy;
this->securityPolicyExt = configuration_ptr->securityPolicyExt;
this->timestamp = configuration_ptr->timestamp;
return;
}
@ -396,10 +399,14 @@ static int link_configuration_update(link_configuration_s *link_configuration, u
if (thread_meshcop_tlv_find(msg_ptr, msg_len, MESHCOP_TLV_PSKC, &ptr) >= 16) {
memcpy(link_configuration->PSKc, ptr, 16);
}
if (thread_meshcop_tlv_find(msg_ptr, msg_len, MESHCOP_TLV_SECURITY_POLICY, &ptr) >= 3) {
uint16_t tlv_len = thread_meshcop_tlv_find(msg_ptr, msg_len, MESHCOP_TLV_SECURITY_POLICY, &ptr);
if (tlv_len >= 3) {
link_configuration->securityPolicyExt = SECURITY_POLICY_ALL_SECURITY;
link_configuration->securityPolicy = ptr[2];
link_configuration->key_rotation = common_read_16_bit(ptr);
if (tlv_len > 3) {
link_configuration->securityPolicyExt = ptr[3];
}
}
return 0;
@ -512,8 +519,8 @@ static void device_configuration_validate(device_configuration_s *this)
this->vendor_stack_version[1] = (uint8_t)(THREAD_ARM_OUI >> 8);
this->vendor_stack_version[2] = (uint8_t)(THREAD_ARM_OUI);
this->vendor_stack_version[3] = (uint8_t)(THREAD_BUILD_NUMBER >> 4);
this->vendor_stack_version[4] = (uint8_t)(((THREAD_BUILD_NUMBER & 0x0f) << 4) || THREAD_REVISION_NUMBER);
this->vendor_stack_version[5] = (uint8_t)((THREAD_VERSION_MIN << 4) || THREAD_VERSION_MAJ);
this->vendor_stack_version[4] = (uint8_t)(((THREAD_BUILD_NUMBER & 0x0f) << 4) | THREAD_REVISION_NUMBER);
this->vendor_stack_version[5] = (uint8_t)((THREAD_VERSION_MIN << 4) | THREAD_VERSION_MAJ);
}
}
@ -710,7 +717,7 @@ static void configuration_set_copy_mandatory(configuration_set_t *destination_pt
tr_debug("mandatory TLVs needed: %s", trace_array(tlv_list, tlv_list_len));
configuration_set_add_fields(destination_ptr, source_ptr->data, source_ptr->length, tlv_list, tlv_list_len);
}
static void configuration_set_generate(configuration_set_t *destination_ptr, link_configuration_s *configuration_ptr)
static void configuration_set_generate(int8_t interface_id, configuration_set_t *destination_ptr, link_configuration_s *configuration_ptr)
{
uint8_t *response_ptr;
@ -733,11 +740,18 @@ static void configuration_set_generate(configuration_set_t *destination_ptr, lin
response_ptr = thread_tmfcop_tlv_data_write(response_ptr, MESHCOP_TLV_PSKC, 16, configuration_ptr->PSKc);
response_ptr = thread_tmfcop_tlv_data_write(response_ptr, MESHCOP_TLV_NETWORK_NAME, stringlen((char *)&configuration_ptr->name, 16), configuration_ptr->name);
*response_ptr++ = MESHCOP_TLV_SECURITY_POLICY; // type
protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(interface_id);
if (thread_extension_version_check(thread_info(cur)->version)) {
*response_ptr++ = 4; // length
response_ptr = common_write_16_bit(configuration_ptr->key_rotation, response_ptr);
*response_ptr++ = configuration_ptr->securityPolicy;
*response_ptr++ = configuration_ptr->securityPolicyExt;
} else {
*response_ptr++ = 3; // length
response_ptr = common_write_16_bit(configuration_ptr->key_rotation, response_ptr);
*response_ptr++ = configuration_ptr->securityPolicy;
}
response_ptr = thread_tmfcop_tlv_data_write_uint64(response_ptr, MESHCOP_TLV_ACTIVE_TIME_STAMP, configuration_ptr->timestamp);
destination_ptr->length = response_ptr - destination_ptr->data;
}
@ -859,7 +873,7 @@ int thread_joiner_application_init(int8_t interface_id, device_configuration_s *
//If no master key or PSKc set we assume not valid configuration for thread network others may be possible to be 0
//This allows some configurations to be set statically for testing purposes
this->configuration_valid = true;
configuration_set_generate(this->active_configuration_ptr, this->configuration_ptr);
configuration_set_generate(this->interface_id, this->active_configuration_ptr, this->configuration_ptr);
}
}
// Always load link configuration from bootstrap state machine. NVM overrides Static configuration
@ -1533,7 +1547,7 @@ int thread_joiner_application_link_configuration_store(int8_t interface_id, link
}
thread_joiner_application_validate_settings(this);// Generate all random information
configuration_set_generate(this->active_configuration_ptr, link_config);
configuration_set_generate(this->interface_id, this->active_configuration_ptr, link_config);
link_configuration_update(this->configuration_ptr, this->active_configuration_ptr->data, this->active_configuration_ptr->length);
this->configuration_ptr->key_sequence = link_config->key_sequence;
this->configuration_valid = true;

View File

@ -744,6 +744,7 @@ static bool thread_address_registration_tlv_check(protocol_interface_info_entry_
}
}
}
thread_extension_child_address_registration_response_process(cur);
return ret_val;
}

View File

@ -67,6 +67,7 @@
#include "6LoWPAN/Thread/thread_tmfcop_lib.h"
#include "6LoWPAN/Thread/thread_nvm_store.h"
#include "6LoWPAN/Thread/thread_neighbor_class.h"
#include "6LoWPAN/Thread/thread_extension_bootstrap.h"
#include "thread_management_if.h"
#include "Common_Protocols/ipv6.h"
#include "Common_Protocols/icmpv6.h"
@ -1484,6 +1485,12 @@ void thread_router_bootstrap_mle_receive_cb(int8_t interface_id, mle_message_t *
return;
}
// check if security policy prevents sending of parent response
if (!thread_extension_is_reed_upgrade_allowed(cur)) {
tr_debug("Security policy prevents parent response; drop packet");
return;
}
if (thread_am_reed(cur)) {
// If we are in REED mode and receive PARENT_REQ from our parent, don't send response.
if (thread_router_parent_address_check(cur, mle_msg->packet_src_address)) {
@ -1597,8 +1604,14 @@ void thread_router_bootstrap_mle_receive_cb(int8_t interface_id, mle_message_t *
return;
}
// If we are in REED mode and receive child ID request from our parent, call connection error.
// check if security policy prevents sending of child id response
if (!thread_extension_is_reed_upgrade_allowed(cur)) {
tr_debug("Security policy prevents child id response; drop packet");
return;
}
if (thread_am_reed(cur)) {
// If we are in REED mode and receive child ID request from our parent, call connection error.
if (thread_router_parent_address_check(cur, mle_msg->packet_src_address)) {
tr_debug("Child ID req from own parent -> connection error");
entry_temp = mac_neighbor_entry_get_by_ll64(mac_neighbor_info(cur), mle_msg->packet_src_address, false, NULL);
@ -2226,6 +2239,10 @@ bool thread_router_bootstrap_reed_upgrade(protocol_interface_info_entry_t *cur)
return false;
}
if (!thread_extension_is_reed_upgrade_allowed(cur)) {
return false;
}
if (thread_am_router(cur)) {
return false;
}

View File

@ -49,6 +49,7 @@
#include "6LoWPAN/Thread/thread_discovery.h"
#include "6LoWPAN/Thread/thread_nvm_store.h"
#include "6LoWPAN/Thread/thread_extension_bootstrap.h"
#include "6LoWPAN/Thread/thread_extension_bbr.h"
#include "6LoWPAN/Thread/thread_neighbor_class.h"
#include "MLE/mle.h"
#include "thread_meshcop_lib.h"
@ -639,6 +640,23 @@ int thread_test_version_set(int8_t interface_id, uint8_t version)
return -1;
#endif
}
int thread_test_pbbr_response_override_set(int8_t interface_id, uint8_t dua_status, uint8_t dua_count, uint8_t ba_failure_count)
{
#ifdef HAVE_THREAD
(void)interface_id;
thread_extension_bbr_status_override_set(dua_status, dua_count, ba_failure_count);
return 0;
#else
(void)interface_id;
(void)dua_status;
(void)dua_count;
(void)ba_failure_count;
return -1;
#endif
}
int thread_test_router_selection_jitter_set(int8_t interface_id, uint32_t jitter)
{
#ifdef HAVE_THREAD

View File

@ -35,8 +35,11 @@
#include "net_rpl.h"
#include "Service_Libs/nd_proxy/nd_proxy.h"
#include "6LoWPAN/ws/ws_bbr_api_internal.h"
#include "6LoWPAN/ws/ws_pae_controller.h"
#include "DHCPv6_Server/DHCPv6_server_service.h"
#include "ws_bbr_api.h"
#define TRACE_GROUP "wsbs"
#define RPL_INSTANCE_ID 1
@ -49,6 +52,7 @@
*
*/
static int8_t backbone_interface_id = -1; // BBR backbone information
static uint16_t configuration = BBR_ULA_C | BBR_GUA_C | BBR_GUA_ROUTE;
static uint8_t static_dodag_prefix[8] = {0xfd, 0x00, 0x61, 0x72, 0x6d};
static uint8_t static_ula_address[16] = {0};
@ -109,15 +113,10 @@ static void ws_bbr_rpl_root_start(uint8_t *dodag_id)
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);
// Save configured static id to check for changes later
memcpy(static_dodag_id, dodag_id, 16);
}
static void ws_bbr_rpl_root_stop(void)
@ -130,6 +129,17 @@ static void ws_bbr_rpl_root_stop(void)
memset(global_dodag_id, 0, 16);
}
static void ws_bbr_ula_prefix_enable(uint8_t *dodag_id)
{
tr_info("RPL ula prefix start");
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 int ws_border_router_proxy_validate(int8_t interface_id, uint8_t *address)
{
@ -170,12 +180,13 @@ static int ws_bbr_static_ula_create(protocol_interface_info_entry_t *cur)
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_address_entry_t *add_entry = icmpv6_slaac_address_add(cur, static_dodag_prefix, 64, 0xffffffff, 0xffffffff, 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));
addr_policy_table_add_entry(static_dodag_prefix, 64, 2, WS_NON_PREFFRED_LABEL);
return 0;
}
@ -266,6 +277,32 @@ static bool wisun_dhcp_address_add_cb(int8_t interfaceId, dhcp_address_cache_upd
return true;
}
static void ws_bbr_dhcp_server_start(protocol_interface_info_entry_t *cur, uint8_t *global_id)
{
uint8_t ll[16];
memcpy(ll, ADDR_LINK_LOCAL_PREFIX, 8);
memcpy(&ll[8], cur->mac, 8);
ll[8] ^= 2;
tr_debug("DHCP server activate %s", trace_ipv6(global_id));
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);
ws_dhcp_client_address_request(cur, global_id, ll);
}
static void ws_bbr_dhcp_server_stop(protocol_interface_info_entry_t *cur, uint8_t *global_id)
{
tr_debug("DHCP server deactivate %s", trace_ipv6(global_id));
DHCPv6_server_service_delete(cur->id, global_id, false);
}
static void ws_bbr_rpl_status_check(protocol_interface_info_entry_t *cur)
{
@ -277,56 +314,73 @@ static void ws_bbr_rpl_status_check(protocol_interface_info_entry_t *cur)
ws_bbr_dodag_get(cur, static_id, global_id);
// Check if we need to wait for Global ID
if (configuration & BBR_GUA_WAIT) {
if (memcmp(global_dodag_id, ADDR_UNSPECIFIED, 16) == 0 &&
memcmp(global_id, ADDR_UNSPECIFIED, 16) == 0) {
// We need to wait for Global connectivity to start anything
return;
}
}
if (memcmp(static_dodag_id, static_id, 16) != 0) {
// Static id updated or first setup
ws_bbr_rpl_root_start(static_id);
if (configuration & BBR_ULA_C) {
// Start static ULA prefix and routing always
ws_bbr_ula_prefix_enable(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);
rpl_control_update_dodag_route(protocol_6lowpan_rpl_root_dodag, NULL, 0, 0, 0, true);
rpl_control_update_dodag_prefix(protocol_6lowpan_rpl_root_dodag, global_dodag_id, 64, 0, 0, 0, true);
rpl_control_update_dodag_route(protocol_6lowpan_rpl_root_dodag, global_dodag_id, 64, 0, 0, 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);
ws_bbr_dhcp_server_stop(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);
//DHCPv6 Server flags set 0 by default
uint8_t t_flags = 0;
// Add default route to RPL
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);
// Enable default routing to backbone
ipv6_route_add_with_info(global_id, 64, backbone_interface_id, NULL, ROUTE_THREAD_BBR, NULL, 0, 0xffffffff, 0);
if (configuration & BBR_GUA_SLAAC) {
// GUA prefix is using SLAAC so no DHCP started and set correct flags for prefix
t_flags = PIO_A;
icmpv6_slaac_address_add(cur, global_id, 64, 0xffffffff, 0xffffffff, true, SLAAC_IID_FIXED);
} else {
ws_bbr_dhcp_server_start(cur, global_id);
}
if (configuration & BBR_GUA_C) {
// Add also global prefix and route to RPL
uint32_t valid_lifetime;
if (t_flags & PIO_A) {
valid_lifetime = 7200;
} else {
valid_lifetime = 0;
}
rpl_control_update_dodag_prefix(protocol_6lowpan_rpl_root_dodag, global_id, 64, t_flags, valid_lifetime, valid_lifetime, false);
}
if (configuration & BBR_GUA_ROUTE) {
// Add also global prefix and route to RPL
rpl_control_update_dodag_route(protocol_6lowpan_rpl_root_dodag, global_id, 64, 0, 7200, false);
}
}
memcpy(global_dodag_id, global_id, 16);
rpl_control_increment_dodag_version(protocol_6lowpan_rpl_root_dodag);
@ -420,12 +474,44 @@ uint16_t ws_bbr_pan_size(protocol_interface_info_entry_t *cur)
if (test_pan_size_override != 0xffff) {
return test_pan_size_override;
}
//
const uint8_t *prefix_ptr;
if ((configuration & (BBR_ULA_C | BBR_GUA_C)) == BBR_GUA_C) {
//Use just GUA Prefix
prefix_ptr = global_dodag_id;
rpl_control_get_instance_dao_target_count(cur->rpl_domain, RPL_INSTANCE_ID, NULL, &result);
} else {
//Use ULA for indentifier
prefix_ptr = static_dodag_id;
}
rpl_control_get_instance_dao_target_count(cur->rpl_domain, RPL_INSTANCE_ID, NULL, prefix_ptr, &result);
return result;
}
bool ws_bbr_ready_to_start(protocol_interface_info_entry_t *cur)
{
(void)cur;
uint8_t global_address[16];
if (backbone_interface_id < 0) {
// No need to wait for backbone
return true;
}
if ((configuration & BBR_BB_WAIT) != BBR_BB_WAIT) {
// No need to wait for backbone
return true;
}
if (arm_net_address_get(backbone_interface_id, ADDR_IPV6_GP, global_address) != 0) {
// No global prefix available
return false;
}
return true;
}
#endif //HAVE_WS_BORDER_ROUTER
/* Public APIs
@ -471,18 +557,44 @@ void ws_bbr_stop(int8_t interface_id)
(void)interface_id;
#endif
}
int ws_bbr_configure(int8_t interface_id, uint16_t options)
{
#ifdef HAVE_WS_BORDER_ROUTER
(void)interface_id;
if (protocol_6lowpan_rpl_root_dodag &&
options != configuration) {
//Configuration changed delete previus setup
ws_bbr_rpl_root_stop();
}
configuration = options;
return 0;
#else
(void)interface_id;
(void)options;
return -1;
#endif
}
int ws_bbr_node_keys_remove(int8_t interface_id, uint8_t *eui64)
{
(void) interface_id;
(void) eui64;
#ifdef HAVE_WS_BORDER_ROUTER
return ws_pae_controller_node_keys_remove(interface_id, eui64);
#else
return -1;
#endif
}
int ws_bbr_node_access_revoke_start(int8_t interface_id)
{
(void) interface_id;
#ifdef HAVE_WS_BORDER_ROUTER
return ws_pae_controller_node_access_revoke_start(interface_id);
#else
return -1;
#endif
}

View File

@ -29,13 +29,15 @@ 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);
bool ws_bbr_ready_to_start(protocol_interface_info_entry_t *cur);
#else
#define ws_bbr_seconds_timer( cur, seconds)
#define ws_bbr_pan_size(cur) 0
#define ws_bbr_rpl_config( imin, doubling, redundancy);
#define ws_bbr_rpl_config( imin, doubling, redundancy)
#define ws_bbr_ready_to_start(cur) true
#endif //HAVE_WS_BORDER_ROUTER

View File

@ -85,8 +85,21 @@ static uint16_t ws_bootstrap_routing_cost_calculate(protocol_interface_info_entr
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_mac_security_enable(protocol_interface_info_entry_t *cur);
static void ws_bootstrap_nw_key_set(protocol_interface_info_entry_t *cur, uint8_t operation, uint8_t index, uint8_t *key);
static void ws_bootstrap_nw_key_clear(protocol_interface_info_entry_t *cur, uint8_t slot);
static void ws_bootstrap_nw_key_index_set(protocol_interface_info_entry_t *cur, uint8_t index);
static void ws_bootstrap_nw_frame_counter_set(protocol_interface_info_entry_t *cur, uint32_t counter);
static void ws_bootstrap_authentication_completed(protocol_interface_info_entry_t *cur, bool success);
static void ws_bootstrap_pan_version_increment(protocol_interface_info_entry_t *cur);
static ws_nud_table_entry_t *ws_nud_entry_discover(protocol_interface_info_entry_t *cur, void *neighbor);
static void ws_nud_entry_remove(protocol_interface_info_entry_t *cur, mac_neighbor_table_entry_t *entry_ptr);
typedef enum {
WS_PARENT_SOFT_SYNCH = 0, /**< let FHSS make decision if synchronization is needed*/
WS_PARENT_HARD_SYNCH, /**< Synch FHSS with latest synch information*/
WS_EAPOL_PARENT_SYNCH, /**< Broadcast synch with EAPOL parent*/
} ws_parent_synch_e;
mac_neighbor_table_entry_t *ws_bootstrap_mac_neighbor_add(struct protocol_interface_info_entry *interface, const uint8_t *src64)
@ -142,6 +155,9 @@ static void ws_bootstrap_address_notification_cb(struct protocol_interface_info_
} else if (reason == ADDR_CALLBACK_DELETED) {
// What to do?
// Go through address list and check if there is global address still available
//Discover prefix policy
addr_policy_remove_by_label(WS_NON_PREFFRED_LABEL);
interface->global_address_available = false;
ns_list_foreach(if_address_entry_t, addr_str, &interface->ip_addresses) {
if (addr_ipv6_scope(addr_str->address, interface) > IPV6_SCOPE_LINK_LOCAL) {
@ -150,8 +166,14 @@ static void ws_bootstrap_address_notification_cb(struct protocol_interface_info_
break;
}
}
} else {
tr_debug("Address notification addr: %s reason: %d", trace_ipv6(addr->address), reason);
} else if (reason == ADDR_CALLBACK_TIMER) {
tr_debug("Address Re registration %s", trace_ipv6(addr->address));
if (!interface->ws_info->address_registration_event_active) {
interface->ws_info->address_registration_event_active = true;
tr_info("Register ARO");
ws_bootsrap_event_trig(WS_ADDRESS_ADDED, interface->bootStrapId, ARM_LIB_LOW_PRIORITY_EVENT, NULL);
}
}
}
@ -170,6 +192,21 @@ static int ws_bootstrap_tasklet_init(protocol_interface_info_entry_t *cur)
return 0;
}
static void ws_nwk_event_post(protocol_interface_info_entry_t *cur, arm_nwk_interface_status_type_e posted_event)
{
arm_event_s event = {
.receiver = cur->net_start_tasklet,
.sender = protocol_read_tasklet_id(), /**< Event sender Tasklet ID */
.event_type = ARM_LIB_NWK_INTERFACE_EVENT,
.event_data = posted_event,
.event_id = (int8_t) cur->id,
.data_ptr = NULL,
.priority = ARM_LIB_LOW_PRIORITY_EVENT,
};
if (eventOS_event_send(&event) != 0) {
tr_error("nwk_net_event_post(): event send failed");
}
}
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)
{
@ -218,8 +255,9 @@ static ws_nud_table_entry_t *ws_nud_entry_get_free(protocol_interface_info_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) {
ws_nud_table_entry_t *entry = ws_nud_entry_discover(cur, neighbor);
if (entry) {
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);
@ -228,11 +266,21 @@ void ws_nud_entry_remove_active(protocol_interface_info_entry_t *cur, void *neig
}
mac_neighbor_table_neighbor_connected(mac_neighbor_info(cur), mac_neighbor);
return;
}
}
}
static ws_nud_table_entry_t *ws_nud_entry_discover(protocol_interface_info_entry_t *cur, void *neighbor)
{
ns_list_foreach(ws_nud_table_entry_t, entry, &cur->ws_info->active_nud_process) {
if (entry->neighbor_info == neighbor) {
return entry;
}
}
return NULL;
}
static void ws_nud_state_clean(protocol_interface_info_entry_t *cur, ws_nud_table_entry_t *entry)
{
mac_neighbor_table_entry_t *neighbor = entry->neighbor_info;
@ -244,6 +292,14 @@ static void ws_nud_state_clean(protocol_interface_info_entry_t *cur, ws_nud_tabl
}
}
static void ws_nud_entry_remove(protocol_interface_info_entry_t *cur, mac_neighbor_table_entry_t *entry_ptr)
{
ws_nud_table_entry_t *nud_entry = ws_nud_entry_discover(cur, entry_ptr);
if (nud_entry) {
ws_nud_state_clean(cur, nud_entry);
}
}
static bool ws_nud_message_build(protocol_interface_info_entry_t *cur, mac_neighbor_table_entry_t *neighbor)
{
//Send NS
@ -444,8 +500,6 @@ static int8_t ws_fhss_discovery_configure(protocol_interface_info_entry_t *cur)
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);
@ -477,7 +531,7 @@ static int8_t ws_fhss_enable(protocol_interface_info_entry_t *cur)
/* 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)
static void ws_bootstrap_primary_parent_set(struct protocol_interface_info_entry *cur, llc_neighbour_req_t *neighbor_info, ws_parent_synch_e synch_req)
{
fhss_ws_configuration_t fhss_configuration;
@ -490,7 +544,9 @@ static void ws_bootstrap_primary_parent_set(struct protocol_interface_info_entry
// Learning broadcast network configuration
if (neighbor_info->ws_neighbor->broadcast_shedule_info_stored) {
if (synch_req != WS_EAPOL_PARENT_SYNCH) {
ws_fhss_set_defaults(cur, &fhss_configuration);
}
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;
@ -500,18 +556,36 @@ static void ws_bootstrap_primary_parent_set(struct protocol_interface_info_entry
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;
neighbor_info->ws_neighbor->synch_done = true;
}
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);
ns_fhss_ws_set_parent(cur->ws_info->fhss_api, neighbor_info->neighbor->mac64, &neighbor_info->ws_neighbor->fhss_data.bc_timing_info, synch_req != WS_PARENT_SOFT_SYNCH);
// Update LLC to follow updated fhss settings
ws_bootstrap_llc_hopping_update(cur, &fhss_configuration);
}
void ws_bootstrap_eapol_parent_synch(struct protocol_interface_info_entry *cur, llc_neighbour_req_t *neighbor_info)
{
if (cur->ws_info->configuration_learned || !neighbor_info->ws_neighbor->broadcast_shedule_info_stored || !neighbor_info->ws_neighbor->broadcast_timing_info_stored) {
return;
}
if (memcmp(neighbor_info->neighbor->mac64, cur->ws_info->parent_info.addr, 8)) {
return;
}
//Store Brodacst Shedule
if (!neighbor_info->ws_neighbor->synch_done) {
ws_bootstrap_primary_parent_set(cur, neighbor_info, WS_EAPOL_PARENT_SYNCH);
} else {
ns_fhss_ws_set_parent(cur->ws_info->fhss_api, neighbor_info->neighbor->mac64, &neighbor_info->ws_neighbor->fhss_data.bc_timing_info, false);
}
}
static void ws_bootstrap_ll_address_validate(struct protocol_interface_info_entry *cur)
{
// Configure EUI64 for MAC if missing
@ -572,10 +646,13 @@ uint16_t ws_etx_read(protocol_interface_info_entry_t *interface, addrtype_t addr
}
} else {
if (!ws_neighbour || !etx_entry || etx_entry->etx_samples < 1 ||
!ws_neighbour->candidate_parent) {
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");
if (etx_entry && etx_entry->etx_samples) {
tr_debug("ws_etx_read not valid %u RSL IN(%u), %u RSL out(%u)", ws_neighbor_class_rsl_in_get(ws_neighbour), ws_neighbour->rsl_in, ws_neighbor_class_rsl_out_get(ws_neighbour), ws_neighbour->rsl_out);
}
return 0xffff;
}
@ -589,6 +666,7 @@ uint16_t ws_etx_read(protocol_interface_info_entry_t *interface, addrtype_t addr
} else {
if (!ws_neighbour->broadcast_timing_info_stored) {
//Global shedule is stored already
tr_debug("ws_etx_read not valid NO BTI");
return 0xffff;
}
}
@ -598,10 +676,6 @@ uint16_t ws_etx_read(protocol_interface_info_entry_t *interface, addrtype_t addr
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;
@ -624,7 +698,8 @@ static int8_t ws_bootstrap_up(protocol_interface_info_entry_t *cur)
return -3;
}
//Enable Power bootup timer setup
cur->ws_info->power_up_setup = true;
// Save FHSS api
cur->ws_info->fhss_api = ns_sw_mac_get_fhss_api(cur->mac_api);
@ -642,14 +717,16 @@ static int8_t ws_bootstrap_up(protocol_interface_info_entry_t *cur)
/* 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;
cur->ipv6_neighbour_cache.omit_na_aro_success = true;
/* Omit sending of NA and consider ACK to be success */
cur->ipv6_neighbour_cache.omit_na = 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_configure(cur->id, true, true, true); //RENEW uses SOLICIT, Interface will use 1 instance for address get, IAID address hint is not used.
dhcp_client_solicit_timeout_set(cur->id, WS_DHCP_SOLICIT_TIMEOUT, WS_DHCP_SOLICIT_MAX_RT, WS_DHCP_SOLICIT_MAX_RC);
@ -819,6 +896,7 @@ static void ws_bootstrap_pan_advertisement_analyse(struct protocol_interface_inf
// Save route cost for all neighbours
llc_neighbour_req_t neighbor_info;
neighbor_info.neighbor = NULL;
if (ws_bootstrap_neighbor_info_request(cur, data->SrcAddr, &neighbor_info, false)) {
neighbor_info.ws_neighbor->routing_cost = pan_information.routing_cost;
}
@ -848,14 +926,14 @@ static void ws_bootstrap_pan_advertisement_analyse(struct protocol_interface_inf
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");
tr_info("EAPOL target dropped Higher Pan cost %u > %u current", pan_cost, current_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");
tr_info("EAPOL target dropped Lower link quality %u < %u current", data->signal_dbm, cur->ws_info->parent_info.signal_dbm);
return;
}
@ -895,13 +973,17 @@ parent_selected:
ws_bootstrap_pan_advertisement_analyse_active(cur, &pan_information);
// Learn latest network information
if (cur->bootsrap_mode != ARM_NWK_BOOTSRAP_MODE_6LoWPAN_BORDER_ROUTER) {
if (cur->bootsrap_mode != ARM_NWK_BOOTSRAP_MODE_6LoWPAN_BORDER_ROUTER && neighbor_info.neighbor) {
if (neighbor_info.neighbor->link_role == PRIORITY_PARENT_NEIGHBOUR) {
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)
@ -930,7 +1012,6 @@ static void ws_bootstrap_pan_config_analyse(struct protocol_interface_info_entry
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;
@ -986,19 +1067,26 @@ static void ws_bootstrap_pan_config_analyse(struct protocol_interface_info_entry
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
tr_info("PAN Config analyse own:%d, heard:%d", cur->ws_info->pan_information.pan_version, pan_version);
if (cur->ws_info->pan_information.pan_version == pan_version) {
// Same version heard so it is consistent
trickle_consistent_heard(&cur->ws_info->trickle_pan_config);
if (neighbor_info.neighbor->link_role == PRIORITY_PARENT_NEIGHBOUR) {
ws_bootstrap_primary_parent_set(cur, &neighbor_info, WS_PARENT_SOFT_SYNCH);
}
// no need to process more
return;
} else {
tr_info("different pan version heard");
// received version is different so we need to reset the trickle
trickle_inconsistent_heard(&cur->ws_info->trickle_pan_config, &cur->ws_info->trickle_params_pan_discovery);
if (neighbor_info.neighbor->link_role == PRIORITY_PARENT_NEIGHBOUR) {
ws_bootstrap_primary_parent_set(cur, &neighbor_info, WS_PARENT_HARD_SYNCH);
}
if (common_serial_number_greater_16(cur->ws_info->pan_information.pan_version, pan_version)) {
// older version heard ignoring the message
return;
}
}
}
if (cur->bootsrap_mode == ARM_NWK_BOOTSRAP_MODE_6LoWPAN_BORDER_ROUTER) {
@ -1006,28 +1094,18 @@ static void ws_bootstrap_pan_config_analyse(struct protocol_interface_info_entry
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
* Learn new information from neighbor
*/
tr_info("Updated PAN configuration heard");
tr_info("Updated PAN configuration own:%d, heard:%d", cur->ws_info->pan_information.pan_version, pan_version);
// restart PAN version timer
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);
ws_pae_controller_gtk_hash_update(cur, gtkhash_ptr);
ws_pae_controller_nw_key_index_update(cur, data->Key.KeyIndex - 1);
if (!cur->ws_info->configuration_learned) {
// Generate own hopping schedules Follow first parent broadcast and plans and also use same unicast dwell
@ -1036,7 +1114,7 @@ static void ws_bootstrap_pan_config_analyse(struct protocol_interface_info_entry
// 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);
ws_bootstrap_primary_parent_set(cur, &neighbor_info, WS_PARENT_HARD_SYNCH);
// set neighbor as priority parent clear if there is others
protocol_6lowpan_neighbor_priority_clear_all(cur->id, PRIORITY_1ST);
neighbor_info.neighbor->link_role = PRIORITY_PARENT_NEIGHBOUR;
@ -1060,13 +1138,13 @@ static void ws_bootstrap_pan_config_solicit_analyse(struct protocol_interface_in
*/
llc_neighbour_req_t neighbor_info;
if (!ws_bootstrap_neighbor_info_request(cur, data->SrcAddr, &neighbor_info, true)) {
return;
}
if (ws_bootstrap_neighbor_info_request(cur, data->SrcAddr, &neighbor_info, false)) {
etx_lqi_dbm_update(cur->id, data->mpduLinkQuality, data->signal_dbm, neighbor_info.neighbor->index);
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
@ -1175,19 +1253,19 @@ static void ws_bootstrap_asynch_ind(struct protocol_interface_info_entry *cur, c
switch (message_type) {
case WS_FT_PAN_ADVERT:
// Analyse Advertisement
tr_debug("received ADVERT");
tr_info("received ADVERT Src:%s rssi:%d", trace_array(data->SrcAddr, 8), data->signal_dbm);
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");
tr_info("received ADVERT SOL Src:%s rssi:%d", trace_array(data->SrcAddr, 8), data->signal_dbm);
ws_bootstrap_pan_advertisement_solicit_analyse(cur, data, &ws_utt, &ws_us);
break;
case WS_FT_PAN_CONF:
tr_debug("received CONFIG");
tr_info("received CONFIG Src:%s rssi:%d", trace_array(data->SrcAddr, 8), data->signal_dbm);
ws_bootstrap_pan_config_analyse(cur, data, ie_ext, &ws_utt, &ws_us);
break;
default:
tr_debug("received CONFIG SOL");
tr_info("received CONFIG SOL Src:%s rssi:%d", trace_array(data->SrcAddr, 8), data->signal_dbm);
ws_bootstrap_pan_config_solicit_analyse(cur, data, &ws_utt, &ws_us);
break;
}
@ -1221,6 +1299,8 @@ static void ws_bootstrap_neighbor_table_clean(struct protocol_interface_info_ent
continue;
}
if (cur->trusted_device) {
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;
@ -1233,7 +1313,18 @@ static void ws_bootstrap_neighbor_table_clean(struct protocol_interface_info_ent
// Possible parent is limited to 3 by default?
continue;
}
}
if (cur->trusted_device) {
neighbor_entry_ptr = cur;
} else {
if (cur->link_lifetime - cur->lifetime > WS_NEIGHBOR_NOT_TRUSTED_LINK_TIMEOUT) {
//Accept only Enough Old not trusted Device
neighbor_entry_ptr = cur;
}
}
}
if (neighbor_entry_ptr) {
tr_info("dropped oldest neighbour %s", trace_array(neighbor_entry_ptr->mac64, 8));
@ -1299,6 +1390,10 @@ static void ws_neighbor_entry_remove_notify(mac_neighbor_table_entry_t *entry_pt
protocol_6lowpan_release_short_link_address_from_neighcache(cur, entry_ptr->mac16);
protocol_6lowpan_release_long_link_address_from_neighcache(cur, entry_ptr->mac64);
}
//NUD Process Clear Here
ws_nud_entry_remove(cur, entry_ptr);
ws_bootstrap_neighbor_delete(cur, entry_ptr->index);
}
@ -1387,6 +1482,13 @@ int ws_bootstrap_init(int8_t interface_id, net_6lowpan_mode_e bootstrap_mode)
if (!etx_storage_list_allocate(cur->id, buffer.device_decription_table_size)) {
return -1;
}
if (!etx_cached_etx_parameter_set(WS_ETX_MIN_WAIT_TIME, WS_ETX_MIN_SAMPLE_COUNT)) {
etx_storage_list_allocate(cur->id, 0);
return -1;
}
etx_max_update_set(WS_ETX_MAX_UPDATE);
if (blacklist_init() != 0) {
tr_err("MLE blacklist init failed.");
return -1;
@ -1452,7 +1554,7 @@ int ws_bootstrap_init(int8_t interface_id, net_6lowpan_mode_e bootstrap_mode)
ret_val = -4;
goto init_fail;
}
if (ws_pae_controller_cb_register(cur, &ws_bootstrap_authentication_completed, &ws_bootstrap_key_insert) < 0) {
if (ws_pae_controller_cb_register(cur, &ws_bootstrap_authentication_completed, &ws_bootstrap_nw_key_set, &ws_bootstrap_nw_key_clear, &ws_bootstrap_nw_key_index_set, &ws_bootstrap_nw_frame_counter_set, &ws_bootstrap_pan_version_increment) < 0) {
ret_val = -4;
goto init_fail;
}
@ -1542,26 +1644,32 @@ int ws_bootstrap_set_rf_config(protocol_interface_info_entry_t *cur, phy_rf_chan
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);
// Set multi CSMA-CA configuration
mlme_multi_csma_ca_param_t multi_csma_params = {WS_NUMBER_OF_CSMA_PERIODS, WS_CSMA_MULTI_CCA_INTERVAL};
set_request.attr = macMultiCSMAParameters;
set_request.value_pointer = &multi_csma_params;
set_request.value_size = sizeof(mlme_multi_csma_ca_param_t);
cur->mac_api->mlme_req(cur->mac_api, MLME_SET, &set_request);
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
mac_neighbor_table_neighbor_remove(mac_neighbor_info(cur), mac_neighbor);
}
return 0;
}
int ws_bootstrap_aro_failure(protocol_interface_info_entry_t *cur, const uint8_t *ll_address)
{
blacklist_update(ll_address, false);
rpl_control_neighbor_delete(cur, ll_address);
ws_bootstrap_neighbor_remove(cur, ll_address);
return 0;
}
static void ws_bootstrap_mac_activate(protocol_interface_info_entry_t *cur, uint16_t channel, uint16_t panid, bool coordinator)
{
@ -1592,6 +1700,7 @@ static void ws_bootstrap_fhss_activate(protocol_interface_info_entry_t *cur)
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_security_enable(cur);
ws_bootstrap_mac_activate(cur, cur->ws_info->fhss_uc_fixed_channel, cur->ws_info->network_pan_id, true);
return;
}
@ -1619,7 +1728,8 @@ static void ws_bootstrap_network_configuration_learn(protocol_interface_info_ent
// 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);
uint8_t *gtkhash = ws_pae_controller_gtk_hash_ptr_get(cur);
ws_llc_set_gtkhash(cur, gtkhash);
// TODO update own fhss schedules we are starting to follow first parent
return;
@ -1728,32 +1838,12 @@ static void ws_dhcp_client_global_adress_cb(int8_t interface, uint8_t dhcp_addr[
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)
@ -1778,24 +1868,30 @@ static void ws_rpl_prefix_callback(prefix_entry_t *prefix, void *handle, uint8_t
* from a prefix advertised by a parent.
*/
if (prefix->options & PIO_A) {
if (parent_link_local) {
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);
/*
* Give SLAAC addresses a different label and low precedence to indicate that
* they probably shouldn't be used for external traffic. SLAAC use in Wi-SUN is non-standard,
* and we use it for mesh-local traffic we should prefer any DHCP-assigned addresses
* for talking to the outside world
*
*/
addr_policy_table_add_entry(prefix->prefix, prefix->prefix_len, 2, WS_NON_PREFFRED_LABEL);
}
} else {
icmpv6_slaac_prefix_update(cur, prefix->prefix, prefix->prefix_len, 0, 0);
}
} 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
if (parent_link_local) {
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;
}
} else {
/* Deprecate address and remove client */
tr_debug("Prefix invalidation %s", trace_ipv6(prefix->prefix));
dhcp_client_global_address_delete(cur->id, NULL, prefix->prefix);
}
}
}
@ -1839,10 +1935,13 @@ 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);
}
static void ws_bootstrap_pan_version_increment(protocol_interface_info_entry_t *cur)
{
cur->ws_info->pan_version_timer = 1;
}
// Start network scan
@ -1870,7 +1969,19 @@ static void ws_bootstrap_start_discovery(protocol_interface_info_entry_t *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);
if (cur->ws_info->power_up_setup) {
cur->ws_info->power_up_setup = false;
tr_debug("PAS init I %u and t %u", cur->ws_info->trickle_pan_advertisement_solicit.I, cur->ws_info->trickle_pan_advertisement_solicit.t);
} else {
trickle_inconsistent_heard(&cur->ws_info->trickle_pan_advertisement_solicit, &cur->ws_info->trickle_params_pan_discovery);
}
if ((cur->lowpan_info & INTERFACE_NWK_BOOTSRAP_ACTIVE) != INTERFACE_NWK_BOOTSRAP_ACTIVE) {
// we have sent bootstrap ready event and now
// restarted discovery so bootstrap down event is sent
cur->lowpan_info |= INTERFACE_NWK_BOOTSRAP_ACTIVE;
ws_nwk_event_post(cur, ARM_NWK_NWK_CONNECTION_DOWN);
}
// 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;
@ -1879,25 +1990,38 @@ static void ws_bootstrap_start_discovery(protocol_interface_info_entry_t *cur)
// Start authentication
static void ws_bootstrap_start_authentication(protocol_interface_info_entry_t *cur)
{
tr_debug("authentication start");
// Set PAN ID and network name to controller
ws_pae_controller_nw_info_set(cur, cur->ws_info->network_pan_id, cur->ws_info->network_name);
ws_pae_controller_authenticate(cur);
}
static void ws_bootstrap_key_insert(protocol_interface_info_entry_t *cur, uint8_t gtk_index, uint8_t *gtk)
static void ws_bootstrap_mac_security_enable(protocol_interface_info_entry_t *cur)
{
// 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_nw_key_set(protocol_interface_info_entry_t *cur, uint8_t slot, uint8_t index, uint8_t *key)
{
mac_helper_security_key_to_descriptor_set(cur, key, index + 1, slot);
}
static void ws_bootstrap_nw_key_clear(protocol_interface_info_entry_t *cur, uint8_t slot)
{
mac_helper_security_key_descriptor_clear(cur, slot);
}
static void ws_bootstrap_nw_key_index_set(protocol_interface_info_entry_t *cur, uint8_t index)
{
// Set send key
mac_helper_security_auto_request_key_index_set(cur, index + 1);
}
static void ws_bootstrap_nw_frame_counter_set(protocol_interface_info_entry_t *cur, uint32_t counter)
{
// Set frame counter
mac_helper_link_frame_counter_set(cur->id, counter);
}
static void ws_bootstrap_authentication_completed(protocol_interface_info_entry_t *cur, bool success)
@ -1955,7 +2079,7 @@ void ws_bootstrap_event_configuration_start(protocol_interface_info_entry_t *cur
}
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);
ws_bootstrap_state_change(cur, ER_PANA_AUTH);
}
void ws_bootstrap_event_operation_start(protocol_interface_info_entry_t *cur)
{
@ -2155,6 +2279,13 @@ static void ws_bootstrap_event_handler(arm_event_s *event)
if (cur->bootsrap_mode == ARM_NWK_BOOTSRAP_MODE_6LoWPAN_BORDER_ROUTER) {
tr_debug("Border router start network");
if (!ws_bbr_ready_to_start(cur)) {
// Wi-SUN not started yet we wait for Border router permission
ws_bootstrap_state_change(cur, ER_WAIT_RESTART);
cur->nwk_nd_re_scan_count = randLIB_get_random_in_range(40, 100);
return;
}
ws_pae_controller_auth_init(cur);
// Randomize fixed channels. Only used if channel plan is fixed.
@ -2167,7 +2298,9 @@ static void ws_bootstrap_event_handler(arm_event_s *event)
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);
uint8_t *gtkhash = ws_pae_controller_gtk_hash_ptr_get(cur);
ws_llc_set_gtkhash(cur, gtkhash);
cur->ws_info->pan_version_timer = PAN_VERSION_LIFETIME;
// Set default parameters for FHSS when starting a discovery
@ -2187,6 +2320,9 @@ static void ws_bootstrap_event_handler(arm_event_s *event)
// Set authenticator relay to port 10253 and PAE to 10254 (and to own ll address)
ws_eapol_auth_relay_start(cur, EAPOL_RELAY_SOCKET_PORT, ll_addr, PAE_AUTH_SOCKET_PORT);
// Set PAN ID and network name to controller
ws_pae_controller_nw_info_set(cur, cur->ws_info->network_pan_id, cur->ws_info->network_name);
// Set PAE port to 10254 and authenticator relay to 10253 (and to own ll address)
ws_pae_controller_authenticator_start(cur, PAE_AUTH_SOCKET_PORT, ll_addr, EAPOL_RELAY_SOCKET_PORT);
break;
@ -2199,21 +2335,6 @@ static void ws_bootstrap_event_handler(arm_event_s *event)
// 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");
@ -2375,10 +2496,15 @@ static void ws_bootstrap_state_change(protocol_interface_info_entry_t *cur, icmp
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_WAIT_RESTART:
tr_debug("WS SM:Wait for startup");
ws_bootstrap_event_discovery_start(cur);
break;
case ER_ACTIVE_SCAN:
tr_debug("WS SM:Active Scan");
ws_bootstrap_network_scan_process(cur);
@ -2387,6 +2513,19 @@ void ws_bootstrap_state_machine(protocol_interface_info_entry_t *cur)
tr_debug("WS SM:configuration Scan");
ws_bootstrap_configure_process(cur);
break;
case ER_PANA_AUTH:
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 ER_RPL_SCAN:
tr_debug("WS SM:Wait RPL to contact DODAG root");
ws_bootstrap_rpl_wait_process(cur);
@ -2396,10 +2535,8 @@ void ws_bootstrap_state_machine(protocol_interface_info_entry_t *cur)
// 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);
}
}
@ -2416,7 +2553,10 @@ void ws_bootstrap_trickle_timer(protocol_interface_info_entry_t *cur, uint16_t t
// send PAN Configuration solicit
if (cur->ws_info->pas_requests > PCS_MAX) {
// if MAX PCS sent restart discovery
tr_debug("Restart???");
// Remove network keys from MAC
ws_pae_controller_nw_keys_remove(cur);
ws_bootstrap_event_discovery_start(cur);
return;
}
@ -2459,7 +2599,12 @@ void ws_primary_parent_update(protocol_interface_info_entry_t *interface, mac_ne
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_bootstrap_primary_parent_set(interface, &neighbor_info, WS_PARENT_HARD_SYNCH);
uint8_t link_local_address[16];
memcpy(link_local_address, ADDR_LINK_LOCAL_PREFIX, 8);
memcpy(link_local_address + 8, neighbor->mac64, 8);
link_local_address[8] ^= 2;
dhcp_client_server_address_update(interface->id, NULL, link_local_address);
ws_secondary_parent_update(interface);
}

View File

@ -23,7 +23,6 @@ typedef enum {
WS_INIT_EVENT = 0, /**< tasklet initializion event*/
WS_DISCOVERY_START, /**< discovery start*/
WS_CONFIGURATION_START, /**< configuration learn start*/
WS_AUTHENTICATION_START, /**< authentication start*/
WS_OPERATION_START, /**< active operation start*/
WS_ROUTING_READY, /**< RPL routing connected to BR*/
WS_ADDRESS_ADDED /**< Address added to IF*/
@ -31,6 +30,8 @@ typedef enum {
#ifdef HAVE_WS
struct llc_neighbour_req;
int ws_bootstrap_init(int8_t interface_id, net_6lowpan_mode_e bootstrap_mode);
void ws_bootstrap_state_machine(protocol_interface_info_entry_t *cur);
@ -41,6 +42,8 @@ int ws_bootstrap_set_rf_config(protocol_interface_info_entry_t *cur, phy_rf_chan
int ws_bootstrap_neighbor_remove(protocol_interface_info_entry_t *cur, const uint8_t *ll_address);
int ws_bootstrap_aro_failure(protocol_interface_info_entry_t *cur, const uint8_t *ll_address);
/*State machine transactions*/
void ws_bootstrap_event_discovery_start(protocol_interface_info_entry_t *cur);
@ -72,12 +75,15 @@ void ws_dhcp_client_address_delete(protocol_interface_info_entry_t *cur, uint8_t
bool ws_eapol_relay_state_active(protocol_interface_info_entry_t *cur);
void ws_bootstrap_eapol_parent_synch(struct protocol_interface_info_entry *cur, struct llc_neighbour_req *neighbor_info);
#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_bootstrap_aro_failure(cur, ll_address)
#define ws_primary_parent_update(interface, neighbor)
#define ws_secondary_parent_update(interface)

View File

@ -274,6 +274,7 @@ int8_t ws_common_allocate_and_init(protocol_interface_info_entry_t *cur)
cur->ws_info->hopping_schdule.operating_mode = OPERATING_MODE_3;
cur->ws_info->hopping_schdule.operating_class = 2;
ws_common_regulatory_domain_config(cur);
cur->ws_info->network_size_config = NETWORK_SIZE_AUTOMATIC;
ws_common_network_size_configure(cur, 10); // defaults to small network size
// Set defaults for the device. user can modify these.
@ -302,7 +303,12 @@ void ws_common_network_size_configure(protocol_interface_info_entry_t *cur, uint
// imin: 14 (16s)
// doublings:3 (128s)
// redundancy; 0 Disabled
ws_bbr_rpl_config(0, 0, 0);// set the default values
if (cur->ws_info->network_size_config == NETWORK_SIZE_AUTOMATIC) {
ws_bbr_rpl_config(14, 3, 0);
} else {
ws_bbr_rpl_config(0, 0, 0);
}
} else if (network_size < 300) {
// Configure the Wi-SUN discovery trickle parameters
cur->ws_info->trickle_params_pan_discovery = trickle_params_pan_discovery_medium;
@ -348,11 +354,19 @@ void ws_common_neighbor_update(protocol_interface_info_entry_t *cur, const uint8
void ws_common_aro_failure(protocol_interface_info_entry_t *cur, const uint8_t *ll_address)
{
//Neighbor connectected update
tr_warn("ARO registration Failure %s", trace_ipv6(ll_address));
ws_bootstrap_aro_failure(cur, ll_address);
}
void ws_common_neighbor_remove(protocol_interface_info_entry_t *cur, const uint8_t *ll_address)
{
tr_debug("neighbor remove %s", trace_ipv6(ll_address));
ws_bootstrap_neighbor_remove(cur, ll_address);
}
bool ws_common_allow_child_registration(protocol_interface_info_entry_t *interface)
bool ws_common_allow_child_registration(protocol_interface_info_entry_t *interface, const uint8_t *eui64)
{
uint8_t child_count = 0;
uint8_t max_child_count = mac_neighbor_info(interface)->list_total_size - WS_NON_CHILD_NEIGHBOUR_COUNT;
@ -362,6 +376,12 @@ bool ws_common_allow_child_registration(protocol_interface_info_entry_t *interfa
max_child_count = test_max_child_count_override;
}
//Validate Is EUI64 already allocated for any address
if (ipv6_neighbour_has_registered_by_eui64(&interface->ipv6_neighbour_cache, eui64)) {
tr_info("Child registration from old child");
return true;
}
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)) {

View File

@ -79,6 +79,7 @@ typedef struct ws_info_s {
bool trickle_pa_running: 1;
bool trickle_pcs_running: 1;
bool trickle_pc_running: 1;
bool power_up_setup: 1;
// default fhss parameters for this device
uint8_t fhss_uc_dwell_interval;
uint8_t fhss_bc_dwell_interval;
@ -118,7 +119,9 @@ void ws_common_neighbor_update(protocol_interface_info_entry_t *cur, const uint8
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);
void ws_common_neighbor_remove(protocol_interface_info_entry_t *cur, const uint8_t *ll_address);
bool ws_common_allow_child_registration(protocol_interface_info_entry_t *cur, const uint8_t *eui64);
#define ws_info(cur) ((cur)->ws_info)
#else
@ -126,8 +129,9 @@ bool ws_common_allow_child_registration(protocol_interface_info_entry_t *cur);
#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_neighbor_remove(cur, ll_address)
#define ws_common_fast_timer(cur, ticks) ((void) 0)
#define ws_common_allow_child_registration(cur) (false)
#define ws_common_allow_child_registration(cur, eui64) (false)
#endif //HAVE_WS

View File

@ -186,6 +186,7 @@ typedef struct ws_bs_ie {
#define WS_FAN_VERSION_1_0 1
#define WS_NEIGHBOR_LINK_TIMEOUT 2200
#define WS_NEIGHBOR_NOT_TRUSTED_LINK_TIMEOUT 60
#define WS_NEIGHBOR_NUD_TIMEOUT WS_NEIGHBOR_LINK_TIMEOUT / 2
#define WS_NEIGBOR_ETX_SAMPLE_MAX 3
@ -198,6 +199,18 @@ typedef struct ws_bs_ie {
#define WS_NUD_RANDOM_COMPARE (WS_NUD_RAND_PROBABILITY*WS_NUD_RANDOM_SAMPLE_LENGTH) / 100
#define WS_ETX_MIN_SAMPLE_COUNT 4
#define WS_ETX_MAX_UPDATE 1024
#define WS_ETX_MIN_WAIT_TIME 60
/**
* Wi-sun spesific non-preferred prefix policy label
*/
#define WS_NON_PREFFRED_LABEL 36
/*
* Threshold (referenced to DEVICE_MIN_SENS) above which a neighbor node may be considered for inclusion into candidate parent set
*/
@ -226,6 +239,11 @@ typedef struct ws_bs_ie {
*/
#define WS_TACK_MAX_MS 5
// With FHSS we need to check CCA twice on TX channel
#define WS_NUMBER_OF_CSMA_PERIODS 2
// Interval between two CCA checks
#define WS_CSMA_MULTI_CCA_INTERVAL 1000
/* Default FHSS timing information
*
*/

View File

@ -27,8 +27,8 @@
*
*/
#define WS_RPL_DIO_IMIN 14
#define WS_RPL_DIO_DOUBLING 3
#define WS_RPL_DIO_IMIN 15
#define WS_RPL_DIO_DOUBLING 2
#define WS_RPL_DIO_REDUNDANCY 0

View File

@ -197,12 +197,15 @@ int8_t ws_eapol_pdu_send_to_mpx(protocol_interface_info_entry_t *interface_ptr,
}
msdu_entry->data_ptr = data;
msdu_entry->buffer = buffer;
msdu_entry->handle = eapol_pdu_data->msdu_handle++;
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;
data_request.msduHandle = eapol_pdu_data->msdu_handle;
eapol_pdu_data->msdu_handle++;
eapol_pdu_data->mpx_api->mpx_data_request(eapol_pdu_data->mpx_api, &data_request, eapol_pdu_data->mpx_user_id);
return 0;

View File

@ -181,5 +181,12 @@ int ws_test_gtk_time_settings_set(int8_t interface_id, uint8_t revocat_lifetime_
return -1;
}
#endif // no HAVE_WS
int ws_test_next_gtk_set(int8_t interface_id, uint8_t *gtk[4])
{
(void) interface_id;
(void) gtk;
return -1;
}
#endif // no HAVE_WS

View File

@ -36,6 +36,8 @@
#include "6LoWPAN/ws/ws_llc.h"
#include "6LoWPAN/ws/ws_mpx_header.h"
#include "6LoWPAN/ws/ws_pae_controller.h"
#include "Security/PANA/pana_eap_header.h"
#include "Security/eapol/eapol_helper.h"
#include "Service_Libs/etx/etx.h"
#include "fhss_ws_extension.h"
@ -511,9 +513,12 @@ static void ws_llc_mac_indication_cb(const mac_api_t *api, const mcps_data_ind_t
mac_payload_IE_t ws_wp_nested;
ws_us_ie_t us_ie;
bool us_ie_inline = false;
bool bs_ie_inline = false;
ws_wp_nested.id = WS_WP_NESTED_IE;
ws_bs_ie_t ws_bs_ie;
if (mac_ie_payload_discover(ie_ext->payloadIeList, ie_ext->payloadIeListLength, &ws_wp_nested) > 2) {
us_ie_inline = ws_wp_nested_us_read(ws_wp_nested.content_ptr, ws_wp_nested.length, &us_ie);
bs_ie_inline = ws_wp_nested_bs_read(ws_wp_nested.content_ptr, ws_wp_nested.length, &ws_bs_ie);
}
llc_neighbour_req_t neighbor_info;
@ -534,7 +539,11 @@ static void ws_llc_mac_indication_cb(const mac_api_t *api, const mcps_data_ind_t
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);
}
if (bs_ie_inline) {
ws_neighbor_class_neighbor_broadcast_schedule_set(neighbor_info.ws_neighbor, &ws_bs_ie);
}
}
//Update BT if it is part of message
ws_bt_ie_t ws_bt;
@ -543,6 +552,8 @@ static void ws_llc_mac_indication_cb(const mac_api_t *api, const mcps_data_ind_t
if (neighbor_info.neighbor->link_role == PRIORITY_PARENT_NEIGHBOUR) {
// We have broadcast schedule set up set the broadcast parent schedule
ns_fhss_ws_set_parent(interface->ws_info->fhss_api, neighbor_info.neighbor->mac64, &neighbor_info.ws_neighbor->fhss_data.bc_timing_info, false);
} else if (ws_utt.message_type == WS_FT_EAPOL) {
ws_bootstrap_eapol_parent_synch(interface, &neighbor_info);
}
}
@ -617,6 +628,37 @@ static uint16_t ws_mpx_header_size_get(llc_data_base_t *base, uint16_t user_id)
return header_size;
}
static bool ws_eapol_handshake_first_msg(uint8_t *pdu, uint16_t length, protocol_interface_info_entry_t *cur)
{
if (!ws_eapol_relay_state_active(cur)) {
return false;
}
eapol_pdu_t eapol_pdu;
uint8_t kmp_type = *pdu++;
length--;
if (!eapol_parse_pdu_header(pdu, length, &eapol_pdu)) {
return false;
}
if (eapol_pdu.packet_type == EAPOL_EAP_TYPE) {
if (eapol_pdu.msg.eap.eap_code == EAP_REQ && eapol_pdu.msg.eap.type == EAP_IDENTITY) {
return true;
}
} else {
uint8_t key_mask = eapol_pdu_key_mask_get(&eapol_pdu);
if (kmp_type == 6 && key_mask == KEY_INFO_KEY_ACK) {
//FWK first message validation
return true;
} else if (kmp_type == 7 && key_mask == (KEY_INFO_KEY_ACK | KEY_INFO_KEY_MIC | KEY_INFO_SECURED_KEY_FRAME)) {
//GWK first message validation
return true;
}
}
return false;
}
static void ws_llc_mpx_data_request(const mpx_api_t *api, const struct mcps_data_req_s *data, uint16_t user_id)
{
llc_data_base_t *base = ws_llc_discover_by_mpx(api);
@ -646,11 +688,9 @@ static void ws_llc_mpx_data_request(const mpx_api_t *api, const struct mcps_data
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;
}
ie_header_mask.bt_ie = ws_eapol_relay_state_active(base->interface_ptr);
ie_header_mask.ea_ie = ws_eapol_handshake_first_msg(data->msdu, data->msduLength, base->interface_ptr);
nested_wp_id.bs_ie = ie_header_mask.ea_ie;
}
@ -735,6 +775,11 @@ static void ws_llc_mpx_data_request(const mpx_api_t *api, const struct mcps_data
ptr = ws_wp_base_write(ptr, nested_ie_length);
//Write unicast schedule
ptr = ws_wp_nested_hopping_schedule_write(ptr, base->ie_params.hopping_schedule, true);
if (nested_wp_id.bs_ie) {
//Write Broadcastcast schedule
ptr = ws_wp_nested_hopping_schedule_write(ptr, base->ie_params.hopping_schedule, false);
}
}

View File

@ -138,7 +138,6 @@ 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;

View File

@ -31,6 +31,7 @@ typedef struct ws_neighbor_class_entry {
bool candidate_parent: 1;
bool broadcast_timing_info_stored: 1;
bool broadcast_shedule_info_stored: 1;
bool synch_done : 1;
} ws_neighbor_class_entry_t;
/**
@ -147,7 +148,7 @@ uint8_t ws_neighbor_class_rssi_from_dbm_calculate(int8_t dbm_heard);
*
*/
#define ws_neighbor_class_rsl_in_get(ws_neighbour) (ws_neighbour->rsl_in >> WS_RSL_SCALING)
#define ws_neighbor_class_rsl_out_get(ws_neighbour) (ws_neighbour->rsl_in >> WS_RSL_SCALING)
#define ws_neighbor_class_rsl_out_get(ws_neighbour) (ws_neighbour->rsl_out >> WS_RSL_SCALING)
/**
* ws_neighbor_class_neighbor_broadcast_schedule_set a function for update neighbor broadcast shedule information

View File

@ -17,6 +17,7 @@
#include "nsconfig.h"
#include <string.h>
#include <randLIB.h>
#include "ns_types.h"
#include "ns_list.h"
#include "ns_trace.h"
@ -39,6 +40,7 @@
#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_timers.h"
#include "6LoWPAN/ws/ws_pae_auth.h"
#include "6LoWPAN/ws/ws_pae_lib.h"
@ -54,23 +56,43 @@
// Wait for for supplicant to indicate activity (e.g. to send a message)
#define WAIT_FOR_AUTHENTICATION_TICKS 5 * 60 * 10 // 5 minutes
// Maximum number of simultaneous EAP-TLS negotiations
#define MAX_SIMULTANEOUS_EAP_TLS_NEGOTIATIONS 3
/* If EAP-TLS is delayed due to simultaneous negotiations limit, defines how
long to wait for previous negotiation to complete */
#define EAP_TLS_NEGOTIATION_TRIGGER_TIMEOUT 60 * 10 // 60 seconds
typedef struct {
ns_list_link_t link; /**< Link */
kmp_service_t *kmp_service; /**< KMP service */
protocol_interface_info_entry_t *interface_ptr; /**< Interface pointer */
ws_pae_auth_gtk_hash_set *hash_set; /**< GTK hash set callback */
ws_pae_auth_nw_key_insert *nw_key_insert; /**< Key insert callback */
ws_pae_auth_nw_key_index_set *nw_key_index_set; /**< Key index set callback */
supp_list_t active_supp_list; /**< List of active supplicants */
supp_list_t inactive_supp_list; /**< List of inactive supplicants */
arm_event_storage_t *timer; /**< Timer */
sec_prot_gtk_keys_t *gtks; /**< GTKs */
sec_prot_gtk_keys_t *next_gtks; /**< Next GTKs */
const sec_prot_certs_t *certs; /**< Certificates */
bool timer_running; /**< Timer is running */
timer_settings_t *timer_settings; /**< Timer settings */
uint16_t slow_timer_seconds; /**< Slow timer seconds */
bool timer_running : 1; /**< Timer is running */
bool gtk_new_inst_req_exp : 1; /**< GTK new install required timer expired */
bool gtk_new_act_time_exp: 1; /**< GTK new activation time expired */
} pae_auth_t;
static int8_t ws_pae_auth_network_keys_from_gtks_set(pae_auth_t *pae_auth);
static int8_t ws_pae_auth_active_gtk_set(pae_auth_t *pae_auth, uint8_t index);
static int8_t ws_pae_auth_network_key_index_set(pae_auth_t *pae_auth, uint8_t index);
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 void ws_pae_auth_gtk_key_insert(pae_auth_t *pae_auth);
static int8_t ws_pae_auth_new_gtk_activate(pae_auth_t *pae_auth);
static int8_t ws_pae_auth_timer_if_start(kmp_service_t *service, kmp_api_t *kmp);
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);
@ -82,13 +104,15 @@ static kmp_api_t *ws_pae_auth_kmp_incoming_ind(kmp_service_t *service, kmp_type_
static void ws_pae_auth_kmp_api_create_confirm(kmp_api_t *kmp, kmp_result_e result);
static void ws_pae_auth_kmp_api_create_indication(kmp_api_t *kmp, kmp_type_e type, kmp_addr_t *addr);
static void ws_pae_auth_kmp_api_finished_indication(kmp_api_t *kmp, kmp_result_e result, kmp_sec_keys_t *sec_keys);
static void ws_pae_auth_next_kmp_trigger(pae_auth_t *pae_auth, supp_entry_t *supp_entry);
static kmp_type_e ws_pae_auth_next_protocol_get(supp_entry_t *supp_entry);
static kmp_api_t *ws_pae_auth_kmp_create_and_start(kmp_service_t *service, kmp_type_e type, supp_entry_t *supp_entry);
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)
int8_t ws_pae_auth_init(protocol_interface_info_entry_t *interface_ptr, sec_prot_gtk_keys_t *gtks, sec_prot_gtk_keys_t *next_gtks, const sec_prot_certs_t *certs, timer_settings_t *timer_settings)
{
if (!interface_ptr || !gtks || !certs) {
return -1;
@ -108,8 +132,17 @@ int8_t ws_pae_auth_init(protocol_interface_info_entry_t *interface_ptr, sec_prot
ws_pae_lib_supp_list_init(&pae_auth->inactive_supp_list);
pae_auth->timer = NULL;
pae_auth->hash_set = NULL;
pae_auth->nw_key_insert = NULL;
pae_auth->nw_key_index_set = NULL;
pae_auth->gtks = gtks;
pae_auth->next_gtks = next_gtks;
pae_auth->certs = certs;
pae_auth->timer_settings = timer_settings;
pae_auth->slow_timer_seconds = 0;
pae_auth->gtk_new_inst_req_exp = false;
pae_auth->gtk_new_act_time_exp = false;
pae_auth->kmp_service = kmp_service_create();
if (!pae_auth->kmp_service) {
@ -205,6 +238,212 @@ int8_t ws_pae_auth_delete(protocol_interface_info_entry_t *interface_ptr)
return 0;
}
void ws_pae_auth_cb_register(protocol_interface_info_entry_t *interface_ptr, ws_pae_auth_gtk_hash_set *hash_set, ws_pae_auth_nw_key_insert *nw_key_insert, ws_pae_auth_nw_key_index_set *nw_key_index_set)
{
if (!interface_ptr) {
return;
}
pae_auth_t *pae_auth = ws_pae_auth_get(interface_ptr);
if (!pae_auth) {
return;
}
pae_auth->hash_set = hash_set;
pae_auth->nw_key_insert = nw_key_insert;
pae_auth->nw_key_index_set = nw_key_index_set;
}
void ws_pae_auth_start(protocol_interface_info_entry_t *interface_ptr)
{
if (!interface_ptr) {
return;
}
pae_auth_t *pae_auth = ws_pae_auth_get(interface_ptr);
if (!pae_auth) {
return;
}
// Checks if there is predefined active key
int8_t index = sec_prot_keys_gtk_status_active_get(pae_auth->gtks);
if (index < 0) {
// If there is no key, inserts a new one
ws_pae_auth_gtk_key_insert(pae_auth);
index = sec_prot_keys_gtk_install_order_first_index_get(pae_auth->gtks);
ws_pae_auth_active_gtk_set(pae_auth, index);
} else {
ws_pae_auth_active_gtk_set(pae_auth, index);
}
// Inserts keys and updates GTK hash on stack
ws_pae_auth_network_keys_from_gtks_set(pae_auth);
// Sets active key index
ws_pae_auth_network_key_index_set(pae_auth, index);
}
void ws_pae_auth_gtks_updated(protocol_interface_info_entry_t *interface_ptr)
{
if (!interface_ptr) {
return;
}
pae_auth_t *pae_auth = ws_pae_auth_get(interface_ptr);
if (!pae_auth) {
return;
}
ws_pae_auth_network_keys_from_gtks_set(pae_auth);
}
int8_t ws_pae_auth_nw_key_index_update(protocol_interface_info_entry_t *interface_ptr, uint8_t index)
{
if (!interface_ptr) {
return -1;
}
pae_auth_t *pae_auth = ws_pae_auth_get(interface_ptr);
if (!pae_auth) {
return -1;
}
ws_pae_auth_active_gtk_set(pae_auth, index);
ws_pae_auth_network_key_index_set(pae_auth, index);
return 0;
}
int8_t ws_pae_auth_node_keys_remove(protocol_interface_info_entry_t *interface_ptr, uint8_t *eui_64)
{
if (!interface_ptr) {
return -1;
}
pae_auth_t *pae_auth = ws_pae_auth_get(interface_ptr);
if (!pae_auth) {
return -1;
}
// Checks if supplicant is active
supp_entry_t *supp = ws_pae_lib_supp_list_entry_eui_64_get(&pae_auth->active_supp_list, eui_64);
if (supp) {
// Deletes keys and marks as revoked
sec_prot_keys_pmk_delete(&supp->sec_keys);
sec_prot_keys_ptk_delete(&supp->sec_keys);
supp->access_revoked = true;
tr_info("Access revoked; keys removed, eui-64: %s", trace_array(kmp_address_eui_64_get(supp->addr), 8));
return 0;
}
// Checks if supplicant is inactive
supp = ws_pae_lib_supp_list_entry_eui_64_get(&pae_auth->inactive_supp_list, eui_64);
if (supp) {
// Deletes supplicant
tr_info("Access revoked; deleted, eui-64: %s", trace_array(kmp_address_eui_64_get(supp->addr), 8));
ws_pae_lib_supp_list_remove(&pae_auth->inactive_supp_list, supp);
return 0;
}
return -1;
}
int8_t ws_pae_auth_node_access_revoke_start(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;
}
// Gets active GTK
int8_t active_index = sec_prot_keys_gtk_status_active_get(pae_auth->gtks);
if (active_index >= 0) {
// As default removes other keys than active
int8_t not_removed_index = active_index;
uint32_t revocation_lifetime = ws_pae_timers_gtk_revocation_lifetime_get(pae_auth->timer_settings);
uint32_t active_lifetime = sec_prot_keys_gtk_lifetime_get(pae_auth->gtks, active_index);
// If active GTK lifetime is larger than revocation lifetime decrements active GTK lifetime
if (active_lifetime > revocation_lifetime) {
sec_prot_keys_gtk_lifetime_decrement(pae_auth->gtks, active_index, active_lifetime - revocation_lifetime);
tr_info("Access revocation start, GTK active index: %i, revoked lifetime: %"PRIu32"", active_index, revocation_lifetime);
} else {
// Otherwise decrements lifetime of the GTK to be installed after the active one
int8_t second_index = sec_prot_keys_gtk_install_order_second_index_get(pae_auth->gtks);
if (second_index >= 0) {
// Second GTK revocation lifetime is the active GTK lifetime added with revocation time
uint32_t second_revocation_lifetime = active_lifetime + revocation_lifetime;
uint32_t second_lifetime = sec_prot_keys_gtk_lifetime_get(pae_auth->gtks, second_index);
if (second_lifetime > second_revocation_lifetime) {
sec_prot_keys_gtk_lifetime_decrement(pae_auth->gtks, second_index, second_lifetime - second_revocation_lifetime);
tr_info("Access revocation start, GTK second active index: %i, revoked lifetime: %"PRIu32"", second_index, second_revocation_lifetime);
}
// Removes other keys than active and GTK to be installed next
not_removed_index = second_index;
}
}
// Deletes other GTKs
int8_t last_index = sec_prot_keys_gtk_install_order_last_index_get(pae_auth->gtks);
while (last_index >= 0 && last_index != not_removed_index) {
tr_info("Access revocation GTK clear index: %i", last_index);
sec_prot_keys_gtk_clear(pae_auth->gtks, last_index);
last_index = sec_prot_keys_gtk_install_order_last_index_get(pae_auth->gtks);
}
}
// Adds new GTK
ws_pae_auth_gtk_key_insert(pae_auth);
ws_pae_auth_network_keys_from_gtks_set(pae_auth);
return 0;
}
static int8_t ws_pae_auth_network_keys_from_gtks_set(pae_auth_t *pae_auth)
{
// Authenticator keys are always fresh
sec_prot_keys_gtk_status_all_fresh_set(pae_auth->gtks);
if (pae_auth->hash_set) {
uint8_t gtk_hash[32];
sec_prot_keys_gtks_hash_generate(pae_auth->gtks, gtk_hash);
pae_auth->hash_set(pae_auth->interface_ptr, gtk_hash);
}
if (pae_auth->nw_key_insert) {
pae_auth->nw_key_insert(pae_auth->interface_ptr, pae_auth->gtks);
}
return 0;
}
static int8_t ws_pae_auth_active_gtk_set(pae_auth_t *pae_auth, uint8_t index)
{
return sec_prot_keys_gtk_status_active_set(pae_auth->gtks, index);
}
static int8_t ws_pae_auth_gtk_clear(pae_auth_t *pae_auth, uint8_t index)
{
return sec_prot_keys_gtk_clear(pae_auth->gtks, index);
}
static int8_t ws_pae_auth_network_key_index_set(pae_auth_t *pae_auth, uint8_t index)
{
if (pae_auth->nw_key_index_set) {
pae_auth->nw_key_index_set(pae_auth->interface_ptr, index);
}
return 0;
}
static void ws_pae_auth_free(pae_auth_t *pae_auth)
{
if (!pae_auth) {
@ -287,7 +526,7 @@ static void ws_pae_auth_tasklet_handler(arm_event_s *event)
}
}
void ws_pae_auth_timer(uint16_t ticks)
void ws_pae_auth_fast_timer(uint16_t ticks)
{
ns_list_foreach(pae_auth_t, pae_auth, &pae_auth_list) {
if (!ws_pae_auth_timer_running(pae_auth)) {
@ -302,6 +541,111 @@ void ws_pae_auth_timer(uint16_t ticks)
}
}
void ws_pae_auth_slow_timer(uint16_t seconds)
{
ns_list_foreach(pae_auth_t, pae_auth, &pae_auth_list) {
// Gets index of currently active GTK
int8_t active_index = sec_prot_keys_gtk_status_active_get(pae_auth->gtks);
for (uint8_t i = 0; i < GTK_NUM; i++) {
if (!sec_prot_keys_gtk_is_set(pae_auth->gtks, i)) {
continue;
}
uint32_t timer_seconds = sec_prot_keys_gtk_lifetime_decrement(pae_auth->gtks, i, seconds);
if (active_index == i) {
if (!pae_auth->gtk_new_inst_req_exp) {
pae_auth->gtk_new_inst_req_exp = ws_pae_timers_gtk_new_install_required(pae_auth->timer_settings, timer_seconds);
if (pae_auth->gtk_new_inst_req_exp) {
int8_t second_index = sec_prot_keys_gtk_install_order_second_index_get(pae_auth->gtks);
if (second_index < 0) {
tr_info("GTK new install required active index: %i, time: %"PRIu32", system time: %"PRIu32"", active_index, timer_seconds, protocol_core_monotonic_time / 10);
ws_pae_auth_gtk_key_insert(pae_auth);
ws_pae_auth_network_keys_from_gtks_set(pae_auth);
} else {
tr_info("GTK new install already done; second index: %i, time: %"PRIu32", system time: %"PRIu32"", second_index, timer_seconds, protocol_core_monotonic_time / 10);
}
}
}
if (!pae_auth->gtk_new_act_time_exp) {
pae_auth->gtk_new_act_time_exp = ws_pae_timers_gtk_new_activation_time(pae_auth->timer_settings, timer_seconds);
if (pae_auth->gtk_new_act_time_exp) {
int8_t new_active_index = ws_pae_auth_new_gtk_activate(pae_auth);
tr_info("GTK new activation time active index: %i, time: %"PRIu32", new index: %i, system time: %"PRIu32"", active_index, timer_seconds, new_active_index, protocol_core_monotonic_time / 10);
if (new_active_index >= 0) {
ws_pae_auth_network_key_index_set(pae_auth, new_active_index);
}
pae_auth->gtk_new_inst_req_exp = false;
pae_auth->gtk_new_act_time_exp = false;
}
}
}
if (timer_seconds == 0) {
tr_info("GTK expired index: %i, system time: %"PRIu32"", i, protocol_core_monotonic_time / 10);
ws_pae_auth_gtk_clear(pae_auth, i);
ws_pae_auth_network_keys_from_gtks_set(pae_auth);
}
}
pae_auth->slow_timer_seconds += seconds;
if (pae_auth->slow_timer_seconds > 60) {
ws_pae_lib_supp_list_slow_timer_update(&pae_auth->active_supp_list, pae_auth->timer_settings, pae_auth->slow_timer_seconds);
ws_pae_lib_supp_list_slow_timer_update(&pae_auth->inactive_supp_list, pae_auth->timer_settings, pae_auth->slow_timer_seconds);
pae_auth->slow_timer_seconds = 0;
}
}
}
static void ws_pae_auth_gtk_key_insert(pae_auth_t *pae_auth)
{
// Gets index to install the key
uint8_t install_index = sec_prot_keys_gtk_install_index_get(pae_auth->gtks);
// Key to install
uint8_t gtk_value[GTK_LEN];
// Checks if next GTK values are set and gets first GTK to install
int8_t next_gtk_index = sec_prot_keys_gtk_install_order_first_index_get(pae_auth->next_gtks);
if (next_gtk_index >= 0) {
// Gets GTK value
uint8_t *gtk = sec_prot_keys_gtk_get(pae_auth->next_gtks, next_gtk_index);
memcpy(gtk_value, gtk, GTK_LEN);
// Sets same key back to next GTKs but as the last key to be installed
sec_prot_keys_gtk_clear(pae_auth->next_gtks, next_gtk_index);
sec_prot_keys_gtk_set(pae_auth->next_gtks, next_gtk_index, gtk_value, 0);
} else {
randLIB_get_n_bytes_random(gtk_value, GTK_LEN);
}
// Gets latest installed key lifetime and adds GTK expire offset to it
uint32_t lifetime = pae_auth->timer_settings->gtk_expire_offset;
int8_t last_index = sec_prot_keys_gtk_install_order_last_index_get(pae_auth->gtks);
if (last_index >= 0) {
lifetime += sec_prot_keys_gtk_lifetime_get(pae_auth->gtks, last_index);
}
// Installs the new key
sec_prot_keys_gtk_clear(pae_auth->gtks, install_index);
sec_prot_keys_gtk_set(pae_auth->gtks, install_index, gtk_value, lifetime);
// Authenticator keys are always fresh
sec_prot_keys_gtk_status_all_fresh_set(pae_auth->gtks);
tr_info("GTK install new index: %i, lifetime: %"PRIu32" system time: %"PRIu32"", install_index, lifetime, protocol_core_monotonic_time / 10);
}
static int8_t ws_pae_auth_new_gtk_activate(pae_auth_t *pae_auth)
{
int8_t new_active_index = sec_prot_keys_gtk_install_order_second_index_get(pae_auth->gtks);
if (new_active_index >= 0) {
ws_pae_auth_active_gtk_set(pae_auth, new_active_index);
}
return new_active_index;
}
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);
@ -363,19 +707,16 @@ 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)
{
(void) service;
pae_auth_t *pae_auth = ws_pae_auth_by_kmp_service_get(service);
if (!pae_auth) {
return;
}
#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);
@ -422,6 +763,8 @@ static kmp_api_t *ws_pae_auth_kmp_incoming_ind(kmp_service_t *service, kmp_type_
return 0;
}
sec_prot_keys_init(&supp_entry->sec_keys, pae_auth->gtks, pae_auth->certs);
// Fixes the address of the supplicant to keys
sec_prot_keys_ptk_eui_64_write(&supp_entry->sec_keys, kmp_address_eui_64_get(addr));
} else {
// Updates relay address
kmp_address_copy(supp_entry->addr, addr);
@ -498,64 +841,116 @@ static void ws_pae_auth_kmp_api_finished_indication(kmp_api_t *kmp, kmp_result_e
// Should not be possible
return;
}
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) {
// Should not be possible
return;
}
// Gets type
kmp_type_e type = kmp_api_type_get(kmp);
ws_pae_auth_next_kmp_trigger(pae_auth, supp_entry);
}
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
static void ws_pae_auth_next_kmp_trigger(pae_auth_t *pae_auth, supp_entry_t *supp_entry)
{
// Disables KMP retry timer
supp_entry->retry_ticks = 0;
// Get next protocol based on what keys supplicant has
kmp_type_e next_type = ws_pae_auth_next_protocol_get(supp_entry);
if (next_type == KMP_TYPE_NONE) {
// All done
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) {
if (next_type == IEEE_802_1X_MKA) {
/* For EAP-TLS, limits the number of ongoing negotiations. If limit
is reached, authenticator does not initiate EAP-TLS right away.
If previous EAP-TLS negotiation completes before negotiation
trigger timeout, authenticator initiates EAP-TLS towards
supplicant. Otherwise supplicant must re-send initial EAPOL-Key
to try again using its trickle schedule */
uint16_t ongoing_eap_tls_cnt = ws_pae_lib_supp_list_kmp_count(&pae_auth->active_supp_list, IEEE_802_1X_MKA);
if (ongoing_eap_tls_cnt >= MAX_SIMULTANEOUS_EAP_TLS_NEGOTIATIONS) {
supp_entry->retry_ticks = EAP_TLS_NEGOTIATION_TRIGGER_TIMEOUT;
tr_info("EAP-TLS max ongoing reached, count %i, delayed: eui-64: %s", ongoing_eap_tls_cnt, trace_array(kmp_address_eui_64_get(supp_entry->addr), 8));
return;
}
}
// Create new instance
kmp_api_t *new_kmp = ws_pae_auth_kmp_create_and_start(pae_auth->kmp_service, type, supp_entry);
kmp_api_t *new_kmp = ws_pae_auth_kmp_create_and_start(pae_auth->kmp_service, next_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 (next_type == IEEE_802_1X_MKA) {
if (ws_pae_lib_kmp_list_type_get(&supp_entry->kmp_list, TLS_PROT) != NULL) {
// TLS already exists, wait for it to be deleted
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) {
if (ws_pae_auth_kmp_create_and_start(pae_auth->kmp_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);
kmp_api_create_request(new_kmp, next_type, supp_entry->addr, &supp_entry->sec_keys);
}
static kmp_type_e ws_pae_auth_next_protocol_get(supp_entry_t *supp_entry)
{
kmp_type_e next_type = KMP_TYPE_NONE;
sec_prot_keys_t *sec_keys = &supp_entry->sec_keys;
// Supplicant has indicated that PMK is not valid
if (sec_keys->pmk_mismatch) {
sec_keys->ptk_mismatch = true;
// start EAP-TLS towards supplicant
next_type = IEEE_802_1X_MKA;
tr_info("PAE start EAP-TLS, eui-64: %s", trace_array(kmp_address_eui_64_get(supp_entry->addr), 8));
} else if (sec_keys->ptk_mismatch) {
// start 4WH towards supplicant
next_type = IEEE_802_11_4WH;
tr_info("PAE start 4WH, eui-64: %s", trace_array(kmp_address_eui_64_get(supp_entry->addr), 8));
}
int8_t gtk_index = -1;
if (next_type != IEEE_802_1X_MKA) {
// Checks if GTK needs to be inserted
gtk_index = sec_prot_keys_gtk_insert_index_from_gtkl_get(sec_keys);
// For 4WH insert always a key, in case no other then active
if (next_type == IEEE_802_11_4WH && gtk_index < 0) {
gtk_index = sec_prot_keys_gtk_status_active_get(sec_keys->gtks);
}
}
if (gtk_index >= 0) {
if (next_type == KMP_TYPE_NONE && gtk_index >= 0) {
// Update just GTK
next_type = IEEE_802_11_GKH;
tr_info("PAE start GKH, eui-64: %s", trace_array(kmp_address_eui_64_get(supp_entry->addr), 8));
}
tr_info("PAE update GTK index: %i, eui-64: %s", gtk_index, trace_array(kmp_address_eui_64_get(supp_entry->addr), 8));
}
if (next_type == KMP_TYPE_NONE) {
tr_info("PAE authenticated, eui-64: %s", trace_array(kmp_address_eui_64_get(supp_entry->addr), 8));
}
return next_type;
}
static kmp_api_t *ws_pae_auth_kmp_create_and_start(kmp_service_t *service, kmp_type_e type, supp_entry_t *supp_entry)
{
// Create KMP instance for new authentication
@ -594,8 +989,25 @@ static void ws_pae_auth_kmp_api_finished(kmp_api_t *kmp)
return;
}
pae_auth_t *pae_auth = NULL;
supp_entry_t *retry_supp = NULL;
// When EAP-TLS completes check if there are other supplicants that have requested it lately
if (kmp_api_type_get(kmp) == IEEE_802_1X_MKA) {
kmp_service_t *service = kmp_api_service_get(kmp);
pae_auth = ws_pae_auth_by_kmp_service_get(service);
if (pae_auth) {
retry_supp = ws_pae_lib_supp_list_entry_retry_timer_get(&pae_auth->active_supp_list);
}
}
// Delete KMP
ws_pae_lib_kmp_list_delete(&supp_entry->kmp_list, kmp);
if (retry_supp) {
tr_info("PAE next KMP trigger, eui-64: %s", trace_array(kmp_address_eui_64_get(retry_supp->addr), 8));
ws_pae_auth_next_kmp_trigger(pae_auth, retry_supp);
}
}
#endif /* HAVE_PAE_AUTH */

View File

@ -44,13 +44,15 @@
* \param remote_addr remote address
* \param remote_port remote port
* \param gtks group keys
* \param next_gtks next group keys to be used
* \param cert_chain certificate chain
* \param timer_settings timer settings
*
* \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);
int8_t ws_pae_auth_init(protocol_interface_info_entry_t *interface_ptr, sec_prot_gtk_keys_t *gtks, sec_prot_gtk_keys_t *next_gtks, const sec_prot_certs_t *certs, timer_settings_t *timer_settings);
/**
* ws_pae_auth_addresses_set set relay addresses
@ -78,19 +80,126 @@ int8_t ws_pae_auth_addresses_set(protocol_interface_info_entry_t *interface_ptr,
int8_t ws_pae_auth_delete(protocol_interface_info_entry_t *interface_ptr);
/**
* ws_pae_auth_timer PAE authenticator timer call
* ws_pae_auth_fast_timer PAE authenticator fast timer call
*
* \param ticks elapsed ticks
*
*/
void ws_pae_auth_timer(uint16_t ticks);
void ws_pae_auth_fast_timer(uint16_t ticks);
/**
* ws_pae_auth_slow_timer PAE authenticator slow call
*
* \param seconds elapsed seconds
*
*/
void ws_pae_auth_slow_timer(uint16_t seconds);
/**
* ws_pae_auth_start start PAE authenticator
*
* \param interface_ptr interface
*
*/
void ws_pae_auth_start(protocol_interface_info_entry_t *interface_ptr);
/**
* ws_pae_auth_gtks_updated indicates that GTKs has been updated
*
* \param interface_ptr interface
*
*/
void ws_pae_auth_gtks_updated(protocol_interface_info_entry_t *interface_ptr);
/**
* ws_pae_auth_gtks_updated indicates that key index has been updated
*
* \param interface_ptr interface
* \param index key index
*
* \return < 0 failure
* \return >= 0 success
*
*/
int8_t ws_pae_auth_nw_key_index_update(protocol_interface_info_entry_t *interface_ptr, uint8_t index);
/**
* ws_pae_auth_node_keys_remove removes nodes keys
*
* \param interface_ptr interface
* \param eui64 node's EUI-64
*
* \return < 0 failure
* \return >= 0 success
*
*/
int8_t ws_pae_auth_node_keys_remove(protocol_interface_info_entry_t *interface_ptr, uint8_t *eui64);
/**
* ws_pae_auth_node_access_revoke_start start node's access revoke
*
* \param interface_ptr interface
*
* \return < 0 failure
* \return >= 0 success
*
*/
int8_t ws_pae_auth_node_access_revoke_start(protocol_interface_info_entry_t *interface_ptr);
/**
* ws_pae_auth_gtk_hash_set GTK hash set callback
*
* \param interface_ptr interface
* \param gtkhash GTK hash, 32 bytes
*
*/
typedef void ws_pae_auth_gtk_hash_set(protocol_interface_info_entry_t *interface_ptr, uint8_t *gtkhash);
/**
* ws_pae_auth_nw_key_insert network key insert callback
*
* \param interface_ptr interface
* \param gtks group keys
*
* \return < 0 failure
* \return >= 0 success
*
*/
typedef int8_t ws_pae_auth_nw_key_insert(protocol_interface_info_entry_t *interface_ptr, sec_prot_gtk_keys_t *gtks);
/**
* ws_pae_auth_nw_key_index_set network send key index set callback
*
* \param interface_ptr interface
* \param index network send key index
*
*/
typedef void ws_pae_auth_nw_key_index_set(protocol_interface_info_entry_t *interface_ptr, uint8_t index);
/**
* ws_pae_auth_cb_register register PAE authenticator callbacks
*
* \param interface_ptr interface
* \param hash_set GTK hash set callback
* \param nw_key_insert network key index callback
* \param nw_key_index_set network send key index callback
*
*/
void ws_pae_auth_cb_register(protocol_interface_info_entry_t *interface_ptr, ws_pae_auth_gtk_hash_set *hash_set, ws_pae_auth_nw_key_insert *nw_key_insert, ws_pae_auth_nw_key_index_set *nw_key_index_set);
#else
#define ws_pae_auth_init(interface_ptr, gtks, certs) 1
#define ws_pae_auth_init(interface_ptr, gtks, next_gtks, certs, timer_settings) 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
#define ws_pae_auth_cb_register(interface_ptr, hash_set, nw_key_insert, nw_key_index_set) {(void) hash_set;}
#define ws_pae_auth_start(interface_ptr)
#define ws_pae_auth_gtks_updated NULL
#define ws_pae_auth_nw_key_index_update NULL
#define ws_pae_auth_node_keys_remove(interface_ptr, eui64) -1
#define ws_pae_auth_node_access_revoke_start(interface_ptr)
#define ws_pae_auth_fast_timer NULL
#define ws_pae_auth_slow_timer NULL
#endif

View File

@ -28,8 +28,10 @@
#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_timers.h"
#include "6LoWPAN/ws/ws_pae_supp.h"
#include "6LoWPAN/ws/ws_pae_auth.h"
#include "mbedtls/sha256.h"
#ifdef HAVE_WS
@ -39,7 +41,15 @@ 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 void ws_pae_gtks_updated(protocol_interface_info_entry_t *interface_ptr);
typedef int8_t ws_pae_gtk_hash_update(protocol_interface_info_entry_t *interface_ptr, uint8_t *gtkhash);
typedef int8_t ws_pae_nw_key_index_update(protocol_interface_info_entry_t *interface_ptr, uint8_t index);
typedef struct {
uint8_t hash[8]; /**< GTK hash for the key */
bool installed : 1; /**< Key has been installed on MAC */
bool fresh : 1; /**< Key is fresh i.e. not used on sending */
} nw_key_t;
typedef struct {
ns_list_link_t link; /**< Link */
@ -47,68 +57,94 @@ typedef struct {
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_gtk_keys_t next_gtks; /**< Next GTKs */
int8_t gtk_index; /**< GTK index */
uint8_t gtkhash[32]; /**< GTK hashes */
sec_prot_certs_t certs; /**< Certificates */
nw_key_t nw_key[4]; /**< Currently active network keys (on MAC) */
char *network_name; /**< Network name for GAK generation */
timer_settings_t timer_settings; /**< Timer settings */
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_controller_nw_key_set *nw_key_set; /**< Key set callback */
ws_pae_controller_nw_key_clear *nw_key_clear; /**< Key clear callback */
ws_pae_controller_nw_send_key_index_set *nw_send_key_index_set; /**< Send key index set callback */
ws_pae_controller_nw_frame_counter_set *nw_frame_counter_set; /**< Frame counter set callback */
ws_pae_controller_pan_ver_increment *pan_ver_increment; /**< PAN version increment callback */
ws_pae_delete *pae_delete; /**< PAE delete callback */
ws_pae_timer *pae_timer; /**< PAE timer callback */
ws_pae_timer *pae_fast_timer; /**< PAE fast timer callback */
ws_pae_timer *pae_slow_timer; /**< PAE slow 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 */
ws_pae_gtks_updated *pae_gtks_updated; /**< PAE GTKs updated */
ws_pae_gtk_hash_update *pae_gtk_hash_update; /**< PAE GTK HASH update */
ws_pae_nw_key_index_update *pae_nw_key_index_update; /**< PAE NW key index update */
bool gtks_set : 1; /**< GTKs are set */
bool gtkhash_set : 1; /**< GTK hashes are set */
bool key_index_set : 1; /**< NW key index is set */
} 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 pae_controller_t *ws_pae_controller_get_or_create(int8_t interface_id);
static void ws_pae_controller_gtk_hash_set(protocol_interface_info_entry_t *interface_ptr, uint8_t *gtkhash);
static int8_t ws_pae_controller_nw_key_check_and_insert(protocol_interface_info_entry_t *interface_ptr, sec_prot_gtk_keys_t *gtks);
static void ws_pae_controller_active_nw_key_clear(nw_key_t *nw_key);
static void ws_pae_controller_active_nw_key_set(protocol_interface_info_entry_t *cur, uint8_t index);
static int8_t ws_pae_controller_gak_from_gtk(uint8_t *gak, uint8_t *gtk, char *network_name);
static void ws_pae_controller_nw_key_index_check_and_set(protocol_interface_info_entry_t *interface_ptr, uint8_t index);
static void ws_pae_controller_data_init(pae_controller_t *controller);
static NS_LIST_DEFINE(pae_controller_list, pae_controller_t, link);
#if !defined(HAVE_PAE_SUPP) && !defined(HAVE_PAE_AUTH)
static void ws_pae_controller_test_keys_set(sec_prot_gtk_keys_t *gtks)
{
uint8_t gtk[2][GTK_LEN];
uint8_t gtk[GTK_LEN];
// Test data
for (int i = 0; i < GTK_LEN; i++) {
gtk[0][i] = 0xcf - i;
gtk[1][i] = 0xef - i;
gtk[i] = 0xcf - 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);
sec_prot_keys_gtk_set(gtks, 0, gtk, GTK_DEFAULT_LIFETIME);
}
#else
#define ws_pae_controller_test_keys_set(gtks);
#endif
int8_t ws_pae_controller_authenticate(protocol_interface_info_entry_t *interface_ptr)
{
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);
#ifdef HAVE_PAE_SUPP
// In case test keys are set uses those and does not initiate authentication
if (controller->gtks_set) {
if (sec_prot_keys_gtks_are_updated(&controller->gtks)) {
ws_pae_controller_nw_key_check_and_insert(controller->interface_ptr, &controller->gtks);
sec_prot_keys_gtks_updated_reset(&controller->gtks);
}
controller->auth_completed(interface_ptr, true);
return 0;
}
///////////
// 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);
if (ws_pae_supp_authenticate(controller->interface_ptr, controller->target_pan_id, controller->target_eui_64) < 0) {
controller->auth_completed(interface_ptr, false);
}
////////////////
#else
ws_pae_controller_test_keys_set(&controller->gtks);
ws_pae_controller_nw_key_check_and_insert(interface_ptr, &controller->gtks);
ws_pae_controller_nw_key_index_check_and_set(interface_ptr, 0);
controller->auth_completed(interface_ptr, true);
#endif
return 0;
}
@ -127,21 +163,32 @@ int8_t ws_pae_controller_authenticator_start(protocol_interface_info_entry_t *in
return -1;
}
#ifdef HAVE_PAE_AUTH
if (sec_prot_keys_gtks_are_updated(&controller->gtks)) {
ws_pae_auth_gtks_updated(interface_ptr);
if (controller->gtk_index >= 0) {
controller->pae_nw_key_index_update(interface_ptr, controller->gtk_index);
}
sec_prot_keys_gtks_updated_reset(&controller->gtks);
}
#else
ws_pae_controller_test_keys_set(&controller->gtks);
uint8_t index;
uint8_t *gtk = sec_prot_keys_get_gtk_to_insert(&controller->gtks, &index);
controller->key_insert(controller->interface_ptr, index, gtk);
ws_pae_controller_nw_key_check_and_insert(interface_ptr, &controller->gtks);
ws_pae_controller_nw_key_index_check_and_set(interface_ptr, 0);
#endif
if (ws_pae_auth_addresses_set(interface_ptr, local_port, remote_addr, remote_port) < 0) {
return -1;
}
ws_pae_auth_cb_register(interface_ptr, ws_pae_controller_gtk_hash_set, ws_pae_controller_nw_key_check_and_insert, ws_pae_controller_nw_key_index_check_and_set);
ws_pae_auth_start(interface_ptr);
return 0;
}
int8_t ws_pae_controller_cb_register(protocol_interface_info_entry_t *interface_ptr, ws_pae_controller_auth_completed *completed, ws_pae_controller_key_insert *key_insert)
int8_t ws_pae_controller_cb_register(protocol_interface_info_entry_t *interface_ptr, ws_pae_controller_auth_completed *completed, ws_pae_controller_nw_key_set *nw_key_set, ws_pae_controller_nw_key_clear *nw_key_clear, ws_pae_controller_nw_send_key_index_set *nw_send_key_index_set, ws_pae_controller_nw_frame_counter_set *nw_frame_counter_set, ws_pae_controller_pan_ver_increment *pan_ver_increment)
{
if (!interface_ptr) {
return -1;
@ -153,7 +200,11 @@ int8_t ws_pae_controller_cb_register(protocol_interface_info_entry_t *interface_
}
controller->auth_completed = completed;
controller->key_insert = key_insert;
controller->nw_key_set = nw_key_set;
controller->nw_key_clear = nw_key_clear;
controller->nw_send_key_index_set = nw_send_key_index_set;
controller->nw_frame_counter_set = nw_frame_counter_set;
controller->pan_ver_increment = pan_ver_increment;
return 0;
}
@ -189,6 +240,8 @@ int8_t ws_pae_controller_nw_info_set(protocol_interface_info_entry_t *interface_
return -1;
}
controller->network_name = network_name;
return ws_pae_supp_nw_info_set(interface_ptr, pan_id, network_name);
}
@ -206,6 +259,202 @@ int8_t ws_pae_controller_nw_key_valid(protocol_interface_info_entry_t *interface
return ws_pae_supp_nw_key_valid(interface_ptr);
}
static int8_t ws_pae_controller_nw_key_check_and_insert(protocol_interface_info_entry_t *interface_ptr, sec_prot_gtk_keys_t *gtks)
{
int8_t ret = -1;
pae_controller_t *controller = ws_pae_controller_get(interface_ptr);
if (!controller) {
return ret;
}
uint8_t gtkhash[GTK_ALL_HASHES_LEN];
sec_prot_keys_gtks_hash_generate(gtks, gtkhash);
nw_key_t *nw_key = controller->nw_key;
// Delete old keys
uint8_t *gtk_hash_ptr = gtkhash;
for (uint8_t i = 0; i < GTK_NUM; i++) {
// If hash is not set for a key
if (sec_prot_keys_gtk_hash_empty(gtk_hash_ptr)) {
// Deletes the key if it is set
if (!sec_prot_keys_gtk_hash_empty(nw_key[i].hash)) {
tr_info("NW key remove: %i", i);
controller->nw_key_clear(interface_ptr, i);
nw_key[i].installed = false;
}
}
gtk_hash_ptr += GTK_HASH_LEN;
}
// Insert new keys
gtk_hash_ptr = gtkhash;
for (uint8_t i = 0; i < GTK_NUM; i++) {
// If hash is set for a key
if (!sec_prot_keys_gtk_hash_empty(gtk_hash_ptr)) {
int hash_matches = memcmp(gtk_hash_ptr, nw_key[i].hash, GTK_HASH_LEN);
// If the hash does not match (not set or modified) or not installed
if (hash_matches != 0 || !nw_key[i].installed) {
memcpy(nw_key[i].hash, gtk_hash_ptr, GTK_HASH_LEN);
nw_key[i].installed = true;
if (hash_matches != 0) {
nw_key[i].fresh = true;
}
uint8_t *gtk = sec_prot_keys_gtk_get(gtks, i);
tr_info("NW key set: %i, hash: %s", i, trace_array(nw_key[i].hash, 8));
uint8_t gak[GTK_LEN];
if (ws_pae_controller_gak_from_gtk(gak, gtk, controller->network_name) >= 0) {
controller->nw_key_set(interface_ptr, i, i, gak);
ret = 0;
} else {
tr_error("GAK generation failed network name: %s", controller->network_name);
ret = -1;
}
}
}
gtk_hash_ptr += GTK_HASH_LEN;
}
return ret;
}
static void ws_pae_controller_active_nw_key_clear(nw_key_t *nw_key)
{
memset(nw_key, 0, sizeof(nw_key_t));
nw_key->installed = false;
nw_key->fresh = false;
}
static int8_t ws_pae_controller_gak_from_gtk(uint8_t *gak, uint8_t *gtk, char *network_name)
{
#if defined(HAVE_PAE_SUPP) || defined(HAVE_PAE_AUTH)
uint8_t network_name_len = strlen(network_name);
if (network_name_len == 0) {
return -1;
}
uint8_t input[network_name_len + GTK_LEN];
memcpy(input, network_name, network_name_len);
memcpy(input + network_name_len, gtk, GTK_LEN);
int8_t ret_val = 0;
mbedtls_sha256_context ctx;
mbedtls_sha256_init(&ctx);
if (mbedtls_sha256_starts_ret(&ctx, 0) != 0) {
ret_val = -1;
goto error;
}
if (mbedtls_sha256_update_ret(&ctx, input, network_name_len + GTK_LEN) != 0) {
ret_val = -1;
goto error;
}
uint8_t output[32];
if (mbedtls_sha256_finish_ret(&ctx, output) != 0) {
ret_val = -1;
goto error;
}
memcpy(gak, &output[0], 16);
error:
mbedtls_sha256_free(&ctx);
return ret_val;
#else
(void) network_name;
memcpy(gak, gtk, 16);
return 0;
#endif
}
int8_t ws_pae_controller_nw_key_index_update(protocol_interface_info_entry_t *interface_ptr, uint8_t index)
{
pae_controller_t *controller = ws_pae_controller_get(interface_ptr);
if (!controller) {
return -1;
}
if (controller->pae_nw_key_index_update) {
controller->pae_nw_key_index_update(interface_ptr, index);
}
return 0;
}
void ws_pae_controller_nw_keys_remove(protocol_interface_info_entry_t *interface_ptr)
{
pae_controller_t *controller = ws_pae_controller_get(interface_ptr);
if (!controller) {
return;
}
tr_info("NW keys remove");
nw_key_t *nw_key = controller->nw_key;
for (uint8_t i = 0; i < GTK_NUM; i++) {
// Deletes the key if it is set
if (!sec_prot_keys_gtk_hash_empty(nw_key[i].hash)) {
tr_info("NW key remove: %i", i);
controller->nw_key_clear(interface_ptr, i);
nw_key[i].installed = false;
}
}
}
static void ws_pae_controller_nw_key_index_check_and_set(protocol_interface_info_entry_t *interface_ptr, uint8_t index)
{
pae_controller_t *controller = ws_pae_controller_get(interface_ptr);
if (!controller) {
return;
}
if (controller->nw_send_key_index_set) {
tr_info("NW send key index set: %i", index + 1);
controller->nw_send_key_index_set(interface_ptr, index);
controller->nw_frame_counter_set(interface_ptr, 0);
}
// Do not update PAN version for initial key index set
if (controller->key_index_set) {
if (controller->pan_ver_increment) {
controller->pan_ver_increment(interface_ptr);
}
} else {
controller->key_index_set = true;
}
}
static void ws_pae_controller_active_nw_key_set(protocol_interface_info_entry_t *cur, uint8_t index)
{
pae_controller_t *controller = ws_pae_controller_get(cur);
if (!controller) {
return;
}
if (controller->nw_send_key_index_set) {
controller->nw_send_key_index_set(controller->interface_ptr, index);
// If index has changed and the key for the index is fresh reset frame counter
if (controller->gtk_index != index && controller->nw_key[index].fresh) {
controller->nw_frame_counter_set(cur, 0);
}
controller->gtk_index = index;
controller->nw_key[index].fresh = false;
}
}
int8_t ws_pae_controller_init(protocol_interface_info_entry_t *interface_ptr)
{
if (!interface_ptr) {
@ -221,75 +470,97 @@ int8_t ws_pae_controller_init(protocol_interface_info_entry_t *interface_ptr)
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;
controller->nw_key_set = NULL;
controller->nw_key_clear = NULL;
controller->nw_send_key_index_set = NULL;
controller->nw_frame_counter_set = NULL;
controller->pan_ver_increment = NULL;
sec_prot_keys_gtks_init(&controller->gtks);
sec_prot_certs_init(&controller->certs);
ws_pae_controller_data_init(controller);
ns_list_add_to_end(&pae_controller_list, controller);
return 0;
}
static void ws_pae_controller_data_init(pae_controller_t *controller)
{
memset(controller->target_eui_64, 0, 8);
memset(controller->br_eui_64, 0, 8);
memset(controller->gtkhash, 0, 32);
ws_pae_controller_active_nw_key_clear(&controller->nw_key[0]);
ws_pae_controller_active_nw_key_clear(&controller->nw_key[1]);
ws_pae_controller_active_nw_key_clear(&controller->nw_key[2]);
ws_pae_controller_active_nw_key_clear(&controller->nw_key[3]);
controller->target_pan_id = 0xffff;
controller->pae_delete = NULL;
controller->pae_fast_timer = NULL;
controller->pae_slow_timer = NULL;
controller->pae_br_addr_write = NULL;
controller->pae_br_addr_read = NULL;
controller->pae_gtks_updated = NULL;
controller->pae_gtk_hash_update = NULL;
controller->pae_nw_key_index_update = NULL;
controller->gtks_set = false;
controller->gtkhash_set = false;
controller->key_index_set = false;
controller->gtk_index = -1;
controller->network_name = NULL;
sec_prot_keys_gtks_init(&controller->gtks);
sec_prot_keys_gtks_init(&controller->next_gtks);
sec_prot_certs_init(&controller->certs);
ws_pae_timers_settings_init(&controller->timer_settings);
}
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) {
if (ws_pae_supp_init(controller->interface_ptr, &controller->certs, &controller->timer_settings) < 0) {
return -1;
}
controller->pae_delete = ws_pae_supp_delete;
controller->pae_timer = ws_pae_supp_timer;
controller->pae_fast_timer = ws_pae_supp_fast_timer;
controller->pae_slow_timer = ws_pae_supp_slow_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;
controller->pae_gtk_hash_update = ws_pae_supp_gtk_hash_update;
controller->pae_nw_key_index_update = ws_pae_supp_nw_key_index_update;
ws_pae_supp_cb_register(controller->interface_ptr, controller->auth_completed, controller->key_insert);
ws_pae_supp_cb_register(controller->interface_ptr, controller->auth_completed, ws_pae_controller_nw_key_check_and_insert, ws_pae_controller_active_nw_key_set);
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) {
if (ws_pae_auth_init(controller->interface_ptr, &controller->gtks, &controller->next_gtks, &controller->certs, &controller->timer_settings) < 0) {
return -1;
}
controller->pae_delete = ws_pae_auth_delete;
controller->pae_timer = ws_pae_auth_timer;
controller->pae_fast_timer = ws_pae_auth_fast_timer;
controller->pae_slow_timer = ws_pae_auth_slow_timer;
controller->pae_gtks_updated = ws_pae_auth_gtks_updated;
controller->pae_nw_key_index_update = ws_pae_auth_nw_key_index_update;
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;
@ -300,6 +571,12 @@ int8_t ws_pae_controller_stop(protocol_interface_info_entry_t *interface_ptr)
controller->pae_delete(interface_ptr);
}
// Free data
sec_prot_certs_delete(&controller->certs);
// Init controller data
ws_pae_controller_data_init(controller);
return 0;
}
@ -317,9 +594,6 @@ int8_t ws_pae_controller_delete(protocol_interface_info_entry_t *interface_ptr)
}
ns_list_remove(&pae_controller_list, controller);
sec_prot_certs_delete(&controller->certs);
ns_dyn_mem_free(controller);
return 0;
@ -327,29 +601,135 @@ int8_t ws_pae_controller_delete(protocol_interface_info_entry_t *interface_ptr)
int8_t ws_pae_controller_certificate_chain_set(const arm_certificate_chain_entry_s *new_chain)
{
if (!new_chain) {
return -1;
}
ns_list_foreach(pae_controller_t, entry, &pae_controller_list) {
// Delete previous information
sec_prot_certs_delete(&entry->certs);
// Adds a trusted certificate from index 0
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);
// Adds own certificate chain from indexes 1 to 3
for (uint8_t i = 1; i < SEC_PROT_CERT_CHAIN_DEPTH; i++) {
if (new_chain->cert_chain[i]) {
sec_prot_certs_cert_set(&entry->certs.own_cert_chain, i - 1, (uint8_t *) new_chain->cert_chain[i], new_chain->cert_len[i]);
if (new_chain->key_chain[i]) {
// Will be the key from top certificate in chain after all certificates are added
uint8_t key_len = strlen((char *) new_chain->key_chain[i]) + 1;
sec_prot_certs_priv_key_set(&entry->certs.own_cert_chain, (uint8_t *) new_chain->key_chain[i], key_len);
}
}
}
}
return 0;
}
int8_t ws_pae_controller_trusted_certificate_add(const arm_certificate_entry_s *cert)
{
if (!cert) {
return -1;
}
int8_t ret = -1;
ns_list_foreach(pae_controller_t, entry, &pae_controller_list) {
cert_chain_entry_t *trusted_cert = sec_prot_certs_chain_entry_create();
sec_prot_certs_cert_set(trusted_cert, 0, (uint8_t *) cert->cert, cert->cert_len);
if (sec_prot_certs_chain_list_entry_find(&entry->certs.trusted_cert_chain_list, trusted_cert)) {
sec_prot_certs_chain_entry_delete(trusted_cert);
continue;
}
sec_prot_certs_chain_list_add(&entry->certs.trusted_cert_chain_list, trusted_cert);
ret = 0;
}
return ret;
}
int8_t ws_pae_controller_trusted_certificate_remove(const arm_certificate_entry_s *cert)
{
if (!cert) {
return -1;
}
int8_t ret = -1;
cert_chain_entry_t *trusted_cert = sec_prot_certs_chain_entry_create();
sec_prot_certs_cert_set(trusted_cert, 0, (uint8_t *) cert->cert, cert->cert_len);
ns_list_foreach(pae_controller_t, entry, &pae_controller_list) {
cert_chain_entry_t *removed_cert = sec_prot_certs_chain_list_entry_find(&entry->certs.trusted_cert_chain_list, trusted_cert);
if (removed_cert) {
sec_prot_certs_chain_list_entry_delete(&entry->certs.trusted_cert_chain_list, removed_cert);
ret = 0;
}
}
sec_prot_certs_chain_entry_delete(trusted_cert);
return ret;
}
int8_t ws_pae_controller_certificate_revocation_list_add(const arm_cert_revocation_list_entry_s *crl)
{
if (!crl) {
return -1;
}
int8_t ret = -1;
ns_list_foreach(pae_controller_t, entry, &pae_controller_list) {
cert_revocat_list_entry_t *cert_revoc_list = sec_prot_certs_revocat_list_entry_create();
sec_prot_certs_revocat_list_set(cert_revoc_list, crl->crl, crl->crl_len);
if (sec_prot_certs_revocat_lists_entry_find(&entry->certs.cert_revocat_lists, cert_revoc_list)) {
sec_prot_certs_revocat_list_entry_delete(cert_revoc_list);
continue;
}
sec_prot_certs_revocat_lists_add(&entry->certs.cert_revocat_lists, cert_revoc_list);
ret = 0;
}
return ret;
}
int8_t ws_pae_controller_certificate_revocation_list_remove(const arm_cert_revocation_list_entry_s *crl)
{
if (!crl) {
return -1;
}
int8_t ret = -1;
cert_revocat_list_entry_t *cert_revoc_list = sec_prot_certs_revocat_list_entry_create();
sec_prot_certs_revocat_list_set(cert_revoc_list, crl->crl, crl->crl_len);
ns_list_foreach(pae_controller_t, entry, &pae_controller_list) {
cert_revocat_list_entry_t *removed_cert_revoc_list = sec_prot_certs_revocat_lists_entry_find(&entry->certs.cert_revocat_lists, cert_revoc_list);
if (removed_cert_revoc_list) {
sec_prot_certs_revocat_lists_entry_delete(&entry->certs.cert_revocat_lists, removed_cert_revoc_list);
ret = 0;
}
}
sec_prot_certs_revocat_list_entry_delete(cert_revoc_list);
return ret;
}
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) {
if (!eui_64) {
return -1;
}
@ -365,12 +745,11 @@ int8_t ws_pae_controller_border_router_addr_write(protocol_interface_info_entry_
}
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) {
if (!eui_64) {
return -1;
}
@ -388,11 +767,197 @@ int8_t ws_pae_controller_border_router_addr_read(protocol_interface_info_entry_t
return 0;
}
void ws_pae_controller_timer(uint16_t ticks)
int8_t ws_pae_controller_gtk_update(int8_t interface_id, uint8_t *gtk[4])
{
if (!gtk) {
return -1;
}
pae_controller_t *controller = ws_pae_controller_get_or_create(interface_id);
if (!controller) {
return -1;
}
// Removes keys set as not used
for (uint8_t i = 0; i < GTK_NUM; i++) {
if (!gtk[i]) {
sec_prot_keys_gtk_clear(&controller->gtks, i);
}
}
// Inserts new keys
for (uint8_t i = 0; i < GTK_NUM; i++) {
if (gtk[i]) {
uint32_t lifetime = sec_prot_keys_gtk_install_order_last_lifetime_get(&controller->gtks);
lifetime += controller->timer_settings.gtk_expire_offset;
if (sec_prot_keys_gtk_set(&controller->gtks, i, gtk[i], lifetime) >= 0) {
tr_info("GTK set index: %i, lifetime %"PRIu32", system time: %"PRIu32"", i, lifetime, protocol_core_monotonic_time / 10);
}
}
}
// Notifies PAE authenticator that GTKs have been updated */
if (controller->pae_gtks_updated) {
controller->pae_gtks_updated(controller->interface_ptr);
}
return 0;
}
int8_t ws_pae_controller_next_gtk_update(int8_t interface_id, uint8_t *gtk[4])
{
if (!gtk) {
return -1;
}
pae_controller_t *controller = ws_pae_controller_get_or_create(interface_id);
if (!controller) {
return -1;
}
// Inserts new keys and removed keys set as not used
for (uint8_t i = 0; i < GTK_NUM; i++) {
if (gtk[i]) {
sec_prot_keys_gtk_set(&controller->next_gtks, i, gtk[i], 0);
} else {
sec_prot_keys_gtk_clear(&controller->next_gtks, i);
}
}
return 0;
}
int8_t ws_pae_controller_active_key_update(int8_t interface_id, uint8_t index)
{
pae_controller_t *controller = ws_pae_controller_get_or_create(interface_id);
if (!controller) {
return -1;
}
controller->gtk_index = index;
if (controller->pae_nw_key_index_update) {
controller->pae_nw_key_index_update(controller->interface_ptr, index);
}
return 0;
}
int8_t ws_pae_controller_key_lifetime_update(int8_t interface_id, uint32_t gtk_lifetime, uint32_t pmk_lifetime, uint32_t ptk_lifetime)
{
pae_controller_t *controller = ws_pae_controller_get_or_create(interface_id);
if (!controller) {
return -1;
}
ws_pae_timers_lifetime_set(&controller->timer_settings, gtk_lifetime, pmk_lifetime, ptk_lifetime);
return 0;
}
int8_t ws_pae_controller_gtk_time_settings_update(int8_t interface_id, uint8_t revocat_lifetime_reduct, uint8_t new_activation_time, uint8_t new_install_req, uint32_t max_mismatch)
{
pae_controller_t *controller = ws_pae_controller_get_or_create(interface_id);
if (!controller) {
return -1;
}
ws_pae_timers_gtk_time_settings_set(&controller->timer_settings, revocat_lifetime_reduct, new_activation_time, new_install_req, max_mismatch);
return 0;
}
int8_t ws_pae_controller_node_keys_remove(int8_t interface_id, uint8_t *eui_64)
{
#ifndef HAVE_PAE_AUTH
(void) eui_64;
#endif
pae_controller_t *controller = ws_pae_controller_get_or_create(interface_id);
if (!controller) {
return -1;
}
return ws_pae_auth_node_keys_remove(controller->interface_ptr, eui_64);
}
int8_t ws_pae_controller_node_access_revoke_start(int8_t interface_id)
{
pae_controller_t *controller = ws_pae_controller_get_or_create(interface_id);
if (!controller) {
return -1;
}
ws_pae_auth_node_access_revoke_start(controller->interface_ptr);
return -1;
}
static void ws_pae_controller_gtk_hash_set(protocol_interface_info_entry_t *interface_ptr, uint8_t *gtkhash)
{
pae_controller_t *controller = ws_pae_controller_get(interface_ptr);
if (!controller) {
return;
}
memcpy(controller->gtkhash, gtkhash, 32);
tr_info("GTK hash set %s %s %s %s",
trace_array(&gtkhash[0], 8),
trace_array(&gtkhash[8], 8),
trace_array(&gtkhash[16], 8),
trace_array(&gtkhash[24], 8));
// Do not update PAN version for initial hash set
if (controller->gtkhash_set) {
if (controller->pan_ver_increment) {
controller->pan_ver_increment(interface_ptr);
}
} else {
controller->gtkhash_set = true;
}
}
uint8_t *ws_pae_controller_gtk_hash_ptr_get(protocol_interface_info_entry_t *interface_ptr)
{
pae_controller_t *controller = ws_pae_controller_get(interface_ptr);
if (!controller) {
return NULL;
}
return controller->gtkhash;
}
int8_t ws_pae_controller_gtk_hash_update(protocol_interface_info_entry_t *interface_ptr, uint8_t *gtkhash)
{
pae_controller_t *controller = ws_pae_controller_get(interface_ptr);
if (!controller) {
return -1;
}
memcpy(controller->gtkhash, gtkhash, 32);
if (controller->pae_gtk_hash_update) {
return controller->pae_gtk_hash_update(interface_ptr, gtkhash);
}
return 0;
}
void ws_pae_controller_fast_timer(uint16_t ticks)
{
ns_list_foreach(pae_controller_t, entry, &pae_controller_list) {
if (entry->pae_timer) {
entry->pae_timer(ticks);
if (entry->pae_fast_timer) {
entry->pae_fast_timer(ticks);
}
}
}
void ws_pae_controller_slow_timer(uint16_t seconds)
{
ns_list_foreach(pae_controller_t, entry, &pae_controller_list) {
if (entry->pae_slow_timer) {
entry->pae_slow_timer(seconds);
}
}
}
@ -408,5 +973,24 @@ static pae_controller_t *ws_pae_controller_get(protocol_interface_info_entry_t *
return NULL;
}
static pae_controller_t *ws_pae_controller_get_or_create(int8_t interface_id)
{
protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(interface_id);
if (!cur) {
return NULL;
}
pae_controller_t *controller = ws_pae_controller_get(cur);
if (!controller) {
if (ws_pae_controller_init(cur) < 0) {
return NULL;
}
controller = ws_pae_controller_get(cur);
}
return controller;
}
#endif /* HAVE_WS */

View File

@ -124,6 +124,50 @@ int8_t ws_pae_controller_delete(protocol_interface_info_entry_t *interface_ptr);
*/
int8_t ws_pae_controller_certificate_chain_set(const arm_certificate_chain_entry_s *chain);
/**
* ws_pae_controller_trusted_certificate_add add trusted certificate
*
* \param cert trusted certificate
*
* \return < 0 failure
* \return >= 0 success
*
*/
int8_t ws_pae_controller_trusted_certificate_add(const arm_certificate_entry_s *cert);
/**
* ws_pae_controller_trusted_certificate_remove remove trusted certificate
*
* \param cert trusted certificate
*
* \return < 0 failure
* \return >= 0 success
*
*/
int8_t ws_pae_controller_trusted_certificate_remove(const arm_certificate_entry_s *cert);
/**
* ws_pae_controller_certificate_revocation_list_add add certification revocation list
*
* \param crl certification revocation list
*
* \return < 0 failure
* \return >= 0 success
*
*/
int8_t ws_pae_controller_certificate_revocation_list_add(const arm_cert_revocation_list_entry_s *crl);
/**
* ws_pae_controller_certificate_revocation_list_remove remove certification revocation list
*
* \param crl certification revocation list
*
* \return < 0 failure
* \return >= 0 success
*
*/
int8_t ws_pae_controller_certificate_revocation_list_remove(const arm_cert_revocation_list_entry_s *crl);
/**
* ws_pae_controller_nw_info_set set network information
*
@ -173,14 +217,172 @@ int8_t ws_pae_controller_border_router_addr_write(protocol_interface_info_entry_
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
* ws_pae_controller_gtk_update update GTKs (test interface)
*
* \param interface_ptr interface
* \param gtk_index index of the new GTK key
* \param gtk new GTK key
* \param interface_id interface identifier
* \param gtk GTK array, if GTK is not set, pointer for the index shall be NULL.
*
* \return < 0 failure
* \return >= 0 success
*
*/
typedef void ws_pae_controller_key_insert(protocol_interface_info_entry_t *interface_ptr, uint8_t gtk_index, uint8_t *gtk);
int8_t ws_pae_controller_gtk_update(int8_t interface_id, uint8_t *gtk[4]);
/**
* ws_pae_controller_next_gtk_update update next GTKs used during GTK lifecycle (test interface)
*
* \param interface_id interface identifier
* \param gtk GTK array, if GTK is not set, pointer for the index shall be NULL.
*
* \return < 0 failure
* \return >= 0 success
*
*/
int8_t ws_pae_controller_next_gtk_update(int8_t interface_id, uint8_t *gtk[4]);
/**
* ws_pae_controller_key_lifetime_update update key lifetime
*
* \param interface_id interface identifier
* \param gtk_lifetime GTK lifetime
* \param pmk_lifetime PMK lifetime
* \param ptk_lifetime PTK lifetime
*
* \return < 0 failure
* \return >= 0 success
*
*/
int8_t ws_pae_controller_key_lifetime_update(int8_t interface_id, uint32_t gtk_lifetime, uint32_t pmk_lifetime, uint32_t ptk_lifetime);
/**
* ws_pae_controller_gtk_time_settings_update update GTK time settings
*
* \param interface_id interface identifier
* \param revocat_lifetime_reduct revocation lifetime reduction
* \param new_activation_time new activation time
* \param new_install_req new install required
* \param max_mismatch max mismatch time
*
* \return < 0 failure
* \return >= 0 success
*
*/
int8_t ws_pae_controller_gtk_time_settings_update(int8_t interface_id, uint8_t revocat_lifetime_reduct, uint8_t new_activation_time, uint8_t new_install_req, uint32_t max_mismatch);
/**
* ws_pae_controller_node_keys_remove remove node's keys
*
* \param interface_id interface identifier
* \param eui-64 EUI-64
*
* \return < 0 failure
* \return >= 0 success
*
*/
int8_t ws_pae_controller_node_keys_remove(int8_t interface_id, uint8_t *eui_64);
/**
* ws_pae_controller_node_access_revoke_start start node's access revoke
*
* \param interface_id interface identifier
*
* \return < 0 failure
* \return >= 0 success
*
*/
int8_t ws_pae_controller_node_access_revoke_start(int8_t interface_id);
/**
* ws_pae_controller_active_key_update update active key (test interface)
*
* \param interface_id interface identifier
* \param index GTK index
*
* \return < 0 failure
* \return >= 0 success
*
*/
int8_t ws_pae_controller_active_key_update(int8_t interface_id, uint8_t index);
/**
* ws_pae_controller_gtk_hash_ptr_get get pointer to GTK hash storage
*
* \param interface_ptr interface
*
* \return pointer to GTK has storage or NULL
*
*/
uint8_t *ws_pae_controller_gtk_hash_ptr_get(protocol_interface_info_entry_t *interface_ptr);
/**
* ws_pae_controller_gtk_hash_update GTK hash has been updated (on PAN configuration)
*
* \param interface_ptr interface
* \param gtkhash new GTK hash
*
* \return < 0 failure
* \return >= 0 success
*
*/
int8_t ws_pae_controller_gtk_hash_update(protocol_interface_info_entry_t *interface_ptr, uint8_t *gtkhash);
/**
* ws_pae_controller_nw_key_index_update key index been updated (on PAN configuration)
*
* \param interface_ptr interface
* \param index key index
*
* \return < 0 failure
* \return >= 0 success
*
*/
int8_t ws_pae_controller_nw_key_index_update(protocol_interface_info_entry_t *interface_ptr, uint8_t index);
/**
* ws_pae_controller_nw_keys_remove remove network keys
*
* \param interface_ptr interface
*
*/
void ws_pae_controller_nw_keys_remove(protocol_interface_info_entry_t *interface_ptr);
/**
* ws_pae_controller_nw_key_insert network key insert callback
*
* \param interface_ptr interface
* \param slot key slot (MAC key descriptor), from 0 to 4
* \param index index of the new network key
* \param key new key
*
*/
typedef void ws_pae_controller_nw_key_set(protocol_interface_info_entry_t *interface_ptr, uint8_t slot, uint8_t index, uint8_t *key);
/**
* ws_pae_controller_nw_key_clear network key clear callback
*
* \param interface_ptr interface
* \param slot key slot (MAC key descriptor), from 0 to 4
*
*/
typedef void ws_pae_controller_nw_key_clear(protocol_interface_info_entry_t *interface_ptr, uint8_t slot);
/**
* ws_pae_controller_nw_send_key_index_set network send key index set callback
*
* \param interface_ptr interface
* \param index index of the key to be used on sending
*
*/
typedef void ws_pae_controller_nw_send_key_index_set(protocol_interface_info_entry_t *interface_ptr, uint8_t index);
/**
* ws_pae_controller_nw_frame_counter_set network frame counter set callback
*
* \param interface_ptr interface
* \param counter frame counter
*
*/
typedef void ws_pae_controller_nw_frame_counter_set(protocol_interface_info_entry_t *interface_ptr, uint32_t counter);
/**
* ws_pae_controller_auth_completed authentication completed callback
@ -191,26 +393,47 @@ typedef void ws_pae_controller_key_insert(protocol_interface_info_entry_t *inter
*/
typedef void ws_pae_controller_auth_completed(protocol_interface_info_entry_t *interface_ptr, bool success);
/**
* ws_pae_controller_pan_ver_increment PAN version increment callback
*
* \param interface_ptr interface
*
*/
typedef void ws_pae_controller_pan_ver_increment(protocol_interface_info_entry_t *interface_ptr);
/**
* 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
* \param nw_key_set network key set callback
* \param nw_key_clear network key clear callback
* \param nw_send_key_index_set network send key index set callback
* \param nw_frame_counter_set network frame counter set callback
* \param pan_ver_increment PAN version increment 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);
int8_t ws_pae_controller_cb_register(protocol_interface_info_entry_t *interface_ptr, ws_pae_controller_auth_completed *completed, ws_pae_controller_nw_key_set *nw_key_set, ws_pae_controller_nw_key_clear *nw_key_clear, ws_pae_controller_nw_send_key_index_set *nw_send_key_index_set, ws_pae_controller_nw_frame_counter_set *nw_frame_counter_set, ws_pae_controller_pan_ver_increment *pan_ver_increment);
/**
* ws_pae_controller_timer PAE controller timer call
* ws_pae_controller_fast_timer PAE controller fast timer call
*
* \param ticks elapsed ticks
*
*/
void ws_pae_controller_timer(uint16_t ticks);
void ws_pae_controller_fast_timer(uint16_t ticks);
/**
* ws_pae_controller_slow_timer PAE controller slow timer call
*
* \param seconds elapsed seconds
*
*/
void ws_pae_controller_slow_timer(uint16_t seconds);
#else
@ -222,14 +445,16 @@ void ws_pae_controller_timer(uint16_t ticks);
#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_gtk_set(interface_id, gtk) -1
#define ws_pae_controller_next_gtks_update(interface_id, gtk) -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)
#define ws_pae_controller_cb_register(interface_ptr, completed, nw_key_set, nw_key_clear, nw_send_key_index_set, pan_ver_increment) 1
#endif

View File

@ -28,6 +28,7 @@
#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_timers.h"
#include "6LoWPAN/ws/ws_pae_lib.h"
#ifdef HAVE_WS
@ -208,13 +209,28 @@ bool ws_pae_lib_supp_list_timer_update(supp_list_t *active_supp_list, supp_list_
return timer_running;
}
void ws_pae_lib_supp_list_slow_timer_update(supp_list_t *supp_list, timer_settings_t *timer_settings, uint16_t seconds)
{
ns_list_foreach(supp_entry_t, entry, supp_list) {
if (sec_prot_keys_pmk_lifetime_decrement(&entry->sec_keys, timer_settings->pmk_lifetime, seconds)) {
tr_info("PMK and PTK expired, eui-64: %s, system time: %"PRIu32"", trace_array(kmp_address_eui_64_get(entry->addr), 8), protocol_core_monotonic_time / 10);
}
if (sec_prot_keys_ptk_lifetime_decrement(&entry->sec_keys, timer_settings->ptk_lifetime, seconds)) {
tr_info("PTK expired, eui-64: %s, system time: %"PRIu32"", trace_array(kmp_address_eui_64_get(entry->addr), 8), protocol_core_monotonic_time / 10);
}
}
}
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->retry_ticks = 0;
entry->active = true;
entry->access_revoked = false;
}
void ws_pae_lib_supp_delete(supp_entry_t *entry)
@ -235,9 +251,20 @@ bool ws_pae_lib_supp_timer_update(supp_entry_t *entry, uint16_t ticks, ws_pae_li
entry->ticks -= ticks;
} else {
entry->ticks = 0;
entry->retry_ticks = 0;
}
}
// Updates retry timer
if (entry->retry_ticks > ticks) {
entry->retry_ticks -= ticks;
} else {
if (entry->retry_ticks > 0) {
tr_info("EAP-TLS max ongoing delay timeout eui-64: %s", trace_array(kmp_address_eui_64_get(entry->addr), 8));
}
entry->retry_ticks = 0;
}
return keep_timer_running;
}
@ -274,6 +301,12 @@ void ws_pae_lib_supp_list_to_inactive(supp_list_t *active_supp_list, supp_list_t
tr_debug("PAE: to inactive, eui-64: %s", trace_array(kmp_address_eui_64_get(entry->addr), 8));
if (entry->access_revoked) {
tr_info("Access revoked; deleted, eui-64: %s", trace_array(kmp_address_eui_64_get(entry->addr), 8));
ws_pae_lib_supp_list_remove(active_supp_list, entry);
return;
}
ns_list_remove(active_supp_list, entry);
ns_list_add_to_start(inactive_supp_list, entry);
@ -286,4 +319,35 @@ void ws_pae_lib_supp_list_to_inactive(supp_list_t *active_supp_list, supp_list_t
entry->addr = addr;
}
uint16_t ws_pae_lib_supp_list_kmp_count(supp_list_t *supp_list, kmp_type_e type)
{
uint16_t kmp_count = 0;
ns_list_foreach(supp_entry_t, entry, supp_list) {
ns_list_foreach(kmp_entry_t, kmp_entry, &entry->kmp_list) {
if (kmp_api_type_get(kmp_entry->kmp) == type) {
kmp_count++;
}
}
}
return kmp_count;
}
supp_entry_t *ws_pae_lib_supp_list_entry_retry_timer_get(supp_list_t *supp_list)
{
supp_entry_t *retry_supp = NULL;
ns_list_foreach(supp_entry_t, entry, supp_list) {
// Finds entry with shortest timeout i.e. oldest one
if (entry->retry_ticks > 0) {
if (!retry_supp || retry_supp->retry_ticks > entry->retry_ticks) {
retry_supp = entry;
}
}
}
return retry_supp;
}
#endif /* HAVE_WS */

View File

@ -18,6 +18,11 @@
#ifndef WS_PAE_LIB_H_
#define WS_PAE_LIB_H_
/*
* Port access entity library functions.
*
*/
typedef struct {
kmp_api_t *kmp; /**< KMP API */
bool timer_running; /**< Timer running inside KMP */
@ -31,7 +36,9 @@ typedef struct {
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 */
uint16_t retry_ticks; /**< Retry ticks */
bool active : 1; /**< Is active */
bool access_revoked : 1; /**< Nodes access is revoked */
ns_list_link_t link; /**< Link */
} supp_entry_t;
@ -144,11 +151,6 @@ typedef void ws_pae_lib_kmp_timer_timeout(kmp_api_t *kmp, uint16_t ticks);
*/
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
*
@ -211,6 +213,16 @@ void ws_pae_lib_supp_list_delete(supp_list_t *supp_list);
*/
bool ws_pae_lib_supp_list_timer_update(supp_list_t *active_supp_list, supp_list_t *inactive_supp_list, uint16_t ticks, ws_pae_lib_kmp_timer_timeout timeout);
/**
* ws_pae_lib_supp_list_slow_timer_update updates slow timer on supplicant list
*
* \param supp_list list of supplicants
* \param timer_settings timer settings
* \param seconds seconds
*
*/
void ws_pae_lib_supp_list_slow_timer_update(supp_list_t *supp_list, timer_settings_t *timer_settings, uint16_t seconds);
/**
* ws_pae_lib_supp_list_timer_update updates supplicant timers
*
@ -268,4 +280,25 @@ void ws_pae_lib_supp_list_to_active(supp_list_t *active_supp_list, supp_list_t *
*/
void ws_pae_lib_supp_list_to_inactive(supp_list_t *active_supp_list, supp_list_t *inactive_supp_list, supp_entry_t *entry);
/**
* ws_pae_lib_supp_list_kmp_count counts the number of KMPs of a certain type in a list of supplicants
*
* \param supp_list list of supplicants
* \param type KMP type
*
* \return number of KMPs in the supplicant list
*
*/
uint16_t ws_pae_lib_supp_list_kmp_count(supp_list_t *supp_list, kmp_type_e type);
/**
* ws_pae_lib_supp_list_entry_retry_timer_get checks if some supplicant has retry timer running
*
* \param supp_list list of supplicants
*
* \return supplicant with retry timer running or NULL if no supplicants with timer running
*
*/
supp_entry_t *ws_pae_lib_supp_list_entry_retry_timer_get(supp_list_t *supp_list);
#endif /* WS_PAE_AUTH_H_ */

View File

@ -104,8 +104,7 @@ int8_t ws_pae_nvm_store_nw_info_tlv_read(nvm_tlv_entry_t *tlv_entry, uint16_t *p
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);
sec_prot_keys_gtk_set(gtks, i, tlv, lifetime);
tlv += GTK_LEN;
} else {
tlv += 4 + GTK_LEN;

View File

@ -18,6 +18,12 @@
#ifndef WS_PAE_NVM_DATA_H_
#define WS_PAE_NVM_DATA_H_
/*
* Port access entity non-volatile memory (NVM) data module. Module is used
* to create and parse PAE NVM data TLVs.
*
*/
/**
* ws_pae_nvm_store_nw_info_tlv_create create NVM network info TLV
*

View File

@ -18,6 +18,12 @@
#ifndef WS_PAE_NVM_STORE_H_
#define WS_PAE_NVM_STORE_H_
/*
* Port access entity non-volatile memory (NVM) storage module. Module is used
* to write and read PAE NVM data TLVs to/from filesystem.
*
*/
// tag + length
#define NVM_TLV_FIXED_LEN 4

View File

@ -17,6 +17,7 @@
#include "nsconfig.h"
#include <string.h>
#include <randLIB.h>
#include "ns_types.h"
#include "ns_list.h"
#include "ns_trace.h"
@ -41,6 +42,7 @@
#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_timers.h"
#include "6LoWPAN/ws/ws_pae_supp.h"
#include "6LoWPAN/ws/ws_pae_lib.h"
#include "6LoWPAN/ws/ws_pae_nvm_store.h"
@ -61,16 +63,24 @@
// 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
// Wait for re-authentication after GTK update
#define WAIT_FOR_REAUTHENTICATION_TICKS 120 * 10 // 120 seconds
// How many times in maximum stored keys are used for authentication
#define STORED_KEYS_MAXIMUM_USE_COUNT 2
// Delay for sending the initial EAPOL-Key
#define INITIAL_KEY_TIMER_MIN 3
#define INITIAL_KEY_TIMER_MAX 30
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 */
uint16_t new_pan_id; /**< new PAN ID indicated by bootstrap */
uint16_t key_pan_id; /**< PAN ID for keys */
bool updated : 1; /**< Network info has been updated */
} sec_prot_keys_nw_info_t;
@ -79,25 +89,31 @@ typedef struct {
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 */
ws_pae_supp_nw_key_insert *nw_key_insert; /**< Key insert callback */
ws_pae_supp_nw_key_index_set *nw_key_index_set; /**< Key index set callback */
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 */
uint16_t initial_key_timer; /**< Timer to trigger initial EAPOL-Key */
trickle_t auth_trickle_timer; /**< Trickle timer for re-sending initial EAPOL-key or for GTK mismatch */
trickle_params_t auth_trickle_params; /**< Trickle parameters for initial EAPOL-key or for GTK mismatch */
sec_prot_gtk_keys_t gtks; /**< GTKs */
uint8_t new_br_eui_64[8]; /**< Border router EUI-64 indicated by bootstrap */
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 */
timer_settings_t *timer_settings; /**< Timer settings */
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_trickle_running : 1; /**< Initial EAPOL-Key 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 */
bool new_br_eui_64_fresh : 1; /**< Border router address is fresh (set during this authentication attempt) */
} 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 */
#define TRICKLE_IMIN_180_SECS 180
static trickle_params_t initial_eapol_key_trickle_params = {
.Imin = TRICKLE_IMIN_180_SECS, /* 180 second; ticks are 1 second */
.Imax = TRICKLE_IMIN_180_SECS << 1, /* 360 second */
.k = 0, /* infinity - no consistency checking */
.TimerExpirations = 3
};
@ -122,6 +138,7 @@ static kmp_api_t *ws_pae_supp_kmp_service_api_get(kmp_service_t *service, kmp_ap
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 int8_t ws_pae_supp_parent_eui_64_get(protocol_interface_info_entry_t *interface_ptr, 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);
@ -152,29 +169,33 @@ int8_t ws_pae_supp_authenticate(protocol_interface_info_entry_t *interface_ptr,
// Delete GTKs
sec_prot_keys_gtks_init(pae_supp->sec_keys_nw_info.gtks);
/* PAN ID has changed, delete key data associated with border router
i.e PMK, PTK, EA-IE data (border router EUI-64) */
if (pae_supp->sec_keys_nw_info.key_pan_id != 0xFFFF && pae_supp->sec_keys_nw_info.key_pan_id != dest_pan_id) {
sec_prot_keys_pmk_delete(&pae_supp->entry.sec_keys);
sec_prot_keys_ptk_delete(&pae_supp->entry.sec_keys);
sec_prot_keys_ptk_eui_64_delete(&pae_supp->entry.sec_keys);
}
pae_supp->sec_keys_nw_info.key_pan_id = dest_pan_id;
// Prepare to receive new border router address
pae_supp->new_br_eui_64_set = false;
pae_supp->new_br_eui_64_fresh = 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);
}
pae_supp->auth_requested = true;
// Starts trickle
trickle_start(&pae_supp->auth_trickle_timer, &auth_trickle_params);
pae_supp->auth_trickle_running = true;
// Randomizes the sending of initial EAPOL-Key messsage
pae_supp->initial_key_timer = randLIB_get_random_in_range(INITIAL_KEY_TIMER_MIN, INITIAL_KEY_TIMER_MAX);
// Starts supplicant timer
ws_pae_supp_timer_start(pae_supp);
pae_supp->auth_requested = true;
tr_debug("PAE active");
tr_debug("PAE active, timer %i", pae_supp->initial_key_timer);
return 1;
}
@ -187,8 +208,8 @@ int8_t ws_pae_supp_nw_info_set(protocol_interface_info_entry_t *interface_ptr, u
}
// 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;
if (pan_id != 0xffff && pan_id != pae_supp->sec_keys_nw_info.new_pan_id) {
pae_supp->sec_keys_nw_info.new_pan_id = pan_id;
pae_supp->sec_keys_nw_info.updated = true;
}
@ -211,6 +232,7 @@ int8_t ws_pae_supp_border_router_addr_write(protocol_interface_info_entry_t *int
memcpy(pae_supp->new_br_eui_64, eui_64, 8);
pae_supp->new_br_eui_64_set = true;
pae_supp->new_br_eui_64_fresh = true;
return 0;
}
@ -222,11 +244,12 @@ int8_t ws_pae_supp_border_router_addr_read(protocol_interface_info_entry_t *inte
return -1;
}
if (!pae_supp->entry.sec_keys.ptk_eui_64 || !pae_supp->entry.sec_keys.ptk_eui_64_set) {
uint8_t *br_eui_64 = sec_prot_keys_ptk_eui_64_get(&pae_supp->entry.sec_keys);
if (!br_eui_64) {
return -1;
}
memcpy(eui_64, pae_supp->entry.sec_keys.ptk_eui_64, 8);
memcpy(eui_64, br_eui_64, 8);
return 0;
}
@ -238,6 +261,8 @@ int8_t ws_pae_supp_nw_key_valid(protocol_interface_info_entry_t *interface_ptr)
return -1;
}
tr_info("NW key valid");
// Stored keys are valid
pae_supp->nw_keys_used_cnt = 0;
@ -247,6 +272,69 @@ int8_t ws_pae_supp_nw_key_valid(protocol_interface_info_entry_t *interface_ptr)
return 0;
}
int8_t ws_pae_supp_gtk_hash_update(protocol_interface_info_entry_t *interface_ptr, uint8_t *gtkhash)
{
pae_supp_t *pae_supp = ws_pae_supp_get(interface_ptr);
if (!pae_supp) {
return -1;
}
// Check GTK hashes and initiate EAPOL procedure if mismatch is detected */
gtk_mismatch_e mismatch = sec_prot_keys_gtks_hash_update(&pae_supp->gtks, gtkhash);
if (mismatch > GTK_NO_MISMATCH) {
tr_info("GTK hash update %s %s %s %s",
trace_array(&gtkhash[0], 8),
trace_array(&gtkhash[8], 8),
trace_array(&gtkhash[16], 8),
trace_array(&gtkhash[24], 8));
// Mismatch, initiate EAPOL
if (!pae_supp->auth_trickle_running) {
uint8_t timer_expirations = 3;
// For GTK lifetime mismatch send only once
if (mismatch == GTK_LIFETIME_MISMATCH) {
timer_expirations = 1;
}
pae_supp->auth_trickle_params.Imin = pae_supp->timer_settings->gtk_request_imin;
pae_supp->auth_trickle_params.Imax = pae_supp->timer_settings->gtk_request_imax;
pae_supp->auth_trickle_params.k = 0;
pae_supp->auth_trickle_params.TimerExpirations = timer_expirations;
// Starts trickle
trickle_start(&pae_supp->auth_trickle_timer, &pae_supp->auth_trickle_params);
pae_supp->auth_trickle_running = true;
// Starts supplicant timer
ws_pae_supp_timer_start(pae_supp);
tr_info("GTK update start imin: %i, imax: %i, max mismatch: %i, tr time: %i", pae_supp->timer_settings->gtk_request_imin, pae_supp->timer_settings->gtk_request_imax, pae_supp->timer_settings->gtk_max_mismatch, pae_supp->auth_trickle_timer.t);
}
}
// Modify keys
pae_supp->nw_key_insert(pae_supp->interface_ptr, pae_supp->sec_keys_nw_info.gtks);
return 0;
}
int8_t ws_pae_supp_nw_key_index_update(protocol_interface_info_entry_t *interface_ptr, uint8_t index)
{
pae_supp_t *pae_supp = ws_pae_supp_get(interface_ptr);
if (!pae_supp) {
return -1;
}
if (sec_prot_keys_gtk_status_active_set(&pae_supp->gtks, index) >= 0) {
tr_info("NW send key index set: %i", index + 1);
pae_supp->nw_key_index_set(interface_ptr, index);
} else {
tr_info("NW send key index: %i, no changes", index + 1);
}
return 0;
}
static void ws_pae_supp_nvm_update(pae_supp_t *pae_supp)
{
// Check if NW info or GTKs have been changed
@ -268,7 +356,7 @@ 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,
nvm_tlv_entry_t *tlv_entry = ws_pae_nvm_store_nw_info_tlv_create(pae_supp->sec_keys_nw_info.key_pan_id,
pae_supp->sec_keys_nw_info.network_name,
&pae_supp->gtks);
ns_list_add_to_end(&tlv_list, tlv_entry);
@ -288,7 +376,7 @@ static int8_t ws_pae_supp_nvm_nw_info_read(pae_supp_t *pae_supp)
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,
ws_pae_nvm_store_nw_info_tlv_read(entry, &pae_supp->sec_keys_nw_info.key_pan_id,
pae_supp->sec_keys_nw_info.network_name,
&pae_supp->gtks);
ns_list_remove(&tlv_list, entry);
@ -340,11 +428,29 @@ 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)
{
if (!pae_supp->auth_requested) {
// If not making initial authentication updates target (RPL parent) for each EAPOL-key message
uint8_t parent_eui_64[8];
if (ws_pae_supp_parent_eui_64_get(pae_supp->interface_ptr, parent_eui_64) < 0) {
return -1;
}
// Stores target/parent address
kmp_address_init(KMP_ADDR_EUI_64, &pae_supp->target_addr, parent_eui_64);
// Sets parent address in use
pae_supp->entry.addr = (kmp_addr_t *) &pae_supp->target_addr;
ws_pae_lib_supp_timer_ticks_set(&pae_supp->entry, WAIT_FOR_REAUTHENTICATION_TICKS);
tr_info("PAE wait for auth seconds: %i", WAIT_FOR_REAUTHENTICATION_TICKS / 10);
}
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;
}
tr_info("EAPOL target: %s", trace_array(kmp_address_eui_64_get(pae_supp->entry.addr), 8));
kmp_api_create_request(kmp, IEEE_802_1X_MKA_KEY, pae_supp->entry.addr, &pae_supp->entry.sec_keys);
return 0;
@ -365,34 +471,21 @@ static int8_t ws_pae_supp_nw_keys_valid_check(pae_supp_t *pae_supp, uint16_t pan
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 {
/* Checks if keys match to PAN ID and that needed keys exists (PMK, PTK and a GTK),
and calls inserts function that will update the network keys as needed */
if ((pan_id == pae_supp->sec_keys_nw_info.key_pan_id) &&
(sec_prot_keys_gtk_count(pae_supp->sec_keys_nw_info.gtks) > 0) &&
(sec_prot_keys_pmk_get(&pae_supp->entry.sec_keys) != NULL) &&
(sec_prot_keys_ptk_get(&pae_supp->entry.sec_keys) != NULL)) {
tr_debug("Existing keys used, counter %i", pae_supp->nw_keys_used_cnt);
if (pae_supp->nw_key_insert(pae_supp->interface_ptr, pae_supp->sec_keys_nw_info.gtks) >= 0) {
tr_debug("Keys inserted");
}
pae_supp->nw_keys_used_cnt++;
return 0;
} else {
pae_supp->nw_keys_used_cnt = 0;
return -1;
}
}
@ -405,10 +498,12 @@ static void ws_pae_supp_keys_nw_info_init(sec_prot_keys_nw_info_t *sec_keys_nw_i
memset(sec_keys_nw_info, 0, sizeof(sec_prot_keys_nw_info_t));
sec_keys_nw_info->gtks = gtks;
sec_keys_nw_info->new_pan_id = 0xFFFF;
sec_keys_nw_info->key_pan_id = 0xFFFF;
sec_keys_nw_info->updated = false;
}
void ws_pae_supp_cb_register(protocol_interface_info_entry_t *interface_ptr, ws_pae_supp_auth_completed *completed, ws_pae_supp_key_insert *key_insert)
void ws_pae_supp_cb_register(protocol_interface_info_entry_t *interface_ptr, ws_pae_supp_auth_completed *completed, ws_pae_supp_nw_key_insert *nw_key_insert, ws_pae_supp_nw_key_index_set *nw_key_index_set)
{
pae_supp_t *pae_supp = ws_pae_supp_get(interface_ptr);
if (!pae_supp) {
@ -416,10 +511,11 @@ void ws_pae_supp_cb_register(protocol_interface_info_entry_t *interface_ptr, ws_
}
pae_supp->auth_completed = completed;
pae_supp->key_insert = key_insert;
pae_supp->nw_key_insert = nw_key_insert;
pae_supp->nw_key_index_set = nw_key_index_set;
}
int8_t ws_pae_supp_init(protocol_interface_info_entry_t *interface_ptr, const sec_prot_certs_t *certs)
int8_t ws_pae_supp_init(protocol_interface_info_entry_t *interface_ptr, const sec_prot_certs_t *certs, timer_settings_t *timer_settings)
{
if (!interface_ptr) {
return -1;
@ -435,10 +531,17 @@ int8_t ws_pae_supp_init(protocol_interface_info_entry_t *interface_ptr, const se
}
pae_supp->interface_ptr = interface_ptr;
pae_supp->auth_completed = 0;
pae_supp->key_insert = 0;
pae_supp->auth_trickle_running = false;
pae_supp->auth_completed = NULL;
pae_supp->nw_key_insert = NULL;
pae_supp->nw_key_index_set = NULL;
pae_supp->initial_key_timer = 0;
pae_supp->nw_keys_used_cnt = 0;
pae_supp->timer_settings = timer_settings;
pae_supp->auth_trickle_running = false;
pae_supp->auth_requested = false;
pae_supp->timer_running = false;
pae_supp->new_br_eui_64_set = false;
pae_supp->new_br_eui_64_fresh = false;
ws_pae_lib_supp_init(&pae_supp->entry);
@ -449,8 +552,6 @@ int8_t ws_pae_supp_init(protocol_interface_info_entry_t *interface_ptr, const se
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) {
@ -619,29 +720,18 @@ static void ws_pae_supp_tasklet_handler(arm_event_s *event)
}
}
void ws_pae_supp_timer(uint16_t ticks)
void ws_pae_supp_fast_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) {
if (!pae_supp->initial_key_timer && !pae_supp->auth_trickle_running && !running) {
tr_debug("PAE idle");
// Sets target/parent address to null
@ -655,6 +745,48 @@ void ws_pae_supp_timer(uint16_t ticks)
}
}
void ws_pae_supp_slow_timer(uint16_t seconds)
{
ns_list_foreach(pae_supp_t, pae_supp, &pae_supp_list) {
// Checks whether initial EAPOL-Key message needs to be re-send or new GTK request to be sent
if (pae_supp->auth_trickle_running) {
if (trickle_timer(&pae_supp->auth_trickle_timer, &pae_supp->auth_trickle_params, seconds)) {
ws_pae_supp_initial_key_send(pae_supp);
}
// Maximum number of trickle expires, authentication fails
if (!trickle_running(&pae_supp->auth_trickle_timer, &pae_supp->auth_trickle_params)) {
ws_pae_supp_authenticate_response(pae_supp, false);
}
}
// Decrements GTK lifetimes
for (uint8_t i = 0; i < GTK_NUM; i++) {
if (!sec_prot_keys_gtk_is_set(&pae_supp->gtks, i)) {
continue;
}
sec_prot_keys_gtk_lifetime_decrement(&pae_supp->gtks, i, seconds);
}
if (pae_supp->initial_key_timer > 0) {
if (pae_supp->initial_key_timer > seconds) {
pae_supp->initial_key_timer -= seconds;
} else {
pae_supp->initial_key_timer = 0;
// Sends initial EAPOL-Key message
ws_pae_supp_initial_key_send(pae_supp);
// Starts trickle
pae_supp->auth_trickle_params = initial_eapol_key_trickle_params;
trickle_start(&pae_supp->auth_trickle_timer, &pae_supp->auth_trickle_params);
pae_supp->auth_trickle_running = true;
}
}
}
}
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);
@ -720,21 +852,38 @@ static int8_t ws_pae_supp_eapol_pdu_address_check(protocol_interface_info_entry_
}
}
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);
uint8_t parent_eui_64[8];
if (ws_pae_supp_parent_eui_64_get(interface_ptr, parent_eui_64) < 0) {
return -1;
}
// Message from RPL parent, route to self
if (parent_ll_addr && memcmp(&parent_ll_addr[8], eui_64, 8) == 0) {
if (memcmp(parent_eui_64, eui_64, 8) == 0) {
return 0;
}
return -1;
}
static int8_t ws_pae_supp_parent_eui_64_get(protocol_interface_info_entry_t *interface_ptr, uint8_t *eui_64)
{
rpl_dodag_info_t dodag_info;
if (!interface_ptr->rpl_domain) {
return -1;
}
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);
if (parent_ll_addr) {
memcpy(eui_64, &parent_ll_addr[8], 8);
eui_64[0] |= 0x02;
return 0;
}
}
return 0;
return -1;
}
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)
@ -752,14 +901,24 @@ static void ws_pae_supp_kmp_service_addr_get(kmp_service_t *service, kmp_api_t *
kmp_address_eui_64_set(local_addr, mac_params.mac_long);
}
if (pae_supp->new_br_eui_64_set) {
// BR address has been received during authentication attempt
if (pae_supp->new_br_eui_64_fresh) {
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);
uint8_t *eui_64 = sec_prot_keys_ptk_eui_64_get(&pae_supp->entry.sec_keys);
// BR address is set on security keys (confirmed using 4WH)
if (eui_64) {
kmp_address_eui_64_set(remote_addr, eui_64);
} else {
// For initial EAPOL key, if BR address has been received during previous attempt, generate PMKID using it
if (pae_supp->new_br_eui_64_set && kmp_api_type_get(kmp) >= IEEE_802_1X_INITIAL_KEY) {
kmp_address_eui_64_set(remote_addr, pae_supp->new_br_eui_64);
} else {
memset(remote_addr, 0, sizeof(kmp_addr_t));
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)
@ -897,18 +1056,12 @@ static void ws_pae_supp_kmp_api_finished_indication(kmp_api_t *kmp, kmp_result_e
ws_pae_lib_supp_timer_ticks_set(&pae_supp->entry, WAIT_FOR_AUTHENTICATION_TICKS);
}
if ((type == IEEE_802_11_4WH || type == IEEE_802_11_GKH) && result == KMP_RESULT_OK) {
if (sec_keys) {
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, &gtk_index);
if (gtk) {
pae_supp->key_insert(pae_supp->interface_ptr, gtk_index, gtk);
sec_prot_keys_gtk_insert_index_clear(keys->gtks);
}
pae_supp->nw_key_insert(pae_supp->interface_ptr, 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);
}
}

View File

@ -38,12 +38,13 @@
*
* \param interface_ptr interface
* \param cert_chain certificate chain
* \param timer_settings timer settings
*
* \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);
int8_t ws_pae_supp_init(protocol_interface_info_entry_t *interface_ptr, const sec_prot_certs_t *certs, timer_settings_t *timer_settings);
/**
* ws_pae_supp_delete deletes PAE supplicant
@ -57,12 +58,20 @@ int8_t ws_pae_supp_init(protocol_interface_info_entry_t *interface_ptr, const se
int8_t ws_pae_supp_delete(protocol_interface_info_entry_t *interface_ptr);
/**
* ws_pae_supp_timer PAE supplicant timer call
* ws_pae_supp_fast_timer PAE supplicant fast timer call
*
* \param ticks elapsed ticks
*
*/
void ws_pae_supp_timer(uint16_t ticks);
void ws_pae_supp_fast_timer(uint16_t ticks);
/**
* ws_pae_supp_slow_timer PAE supplicant slow timer call
*
* \param ticks elapsed seconds
*
*/
void ws_pae_supp_slow_timer(uint16_t seconds);
/**
* ws_pae_supp_authenticate start EAPOL authentication
@ -126,6 +135,39 @@ int8_t ws_pae_supp_border_router_addr_read(protocol_interface_info_entry_t *inte
*/
int8_t ws_pae_supp_nw_key_valid(protocol_interface_info_entry_t *interface_ptr);
/**
* ws_pae_supp_gtk_hash_update GTK hash has been updated (on PAN configuration)
*
* \param interface_ptr interface
* \param gtkhash GTK hash, 32 bytes
*
* \return < 0 failure
* \return >= 0 success
*
*/
int8_t ws_pae_supp_gtk_hash_update(protocol_interface_info_entry_t *interface_ptr, uint8_t *gtkhash);
/**
* ws_pae_supp_nw_key_index_update key index been updated (on PAN configuration)
*
* \param interface_ptr interface
* \param index key index
*
* \return < 0 failure
* \return >= 0 success
*
*/
int8_t ws_pae_supp_nw_key_index_update(protocol_interface_info_entry_t *interface_ptr, uint8_t index);
/**
* ws_pae_supp_nw_key_index_set network send key index set callback
*
* \param interface_ptr interface
* \param index network send key index
*
*/
typedef void ws_pae_supp_nw_key_index_set(protocol_interface_info_entry_t *interface_ptr, uint8_t index);
/**
* ws_pae_supp_auth_completed authentication completed callback
*
@ -136,36 +178,42 @@ int8_t ws_pae_supp_nw_key_valid(protocol_interface_info_entry_t *interface_ptr);
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
* ws_pae_supp_nw_key_insert network key insert callback
*
* \param interface_ptr interface
* \param gtk_index index of the new GTK key
* \param gtk new GTK key
* \param gtks group keys
*
* \return < 0 failure
* \return >= 0 success
*
*/
typedef void ws_pae_supp_key_insert(protocol_interface_info_entry_t *interface_ptr, uint8_t gtk_index, uint8_t *gtk);
typedef int8_t ws_pae_supp_nw_key_insert(protocol_interface_info_entry_t *interface_ptr, sec_prot_gtk_keys_t *gtks);
/**
* 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
* \param nw_key_insert network key index callback
* \param nw_key_index_set network send key index 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);
void ws_pae_supp_cb_register(protocol_interface_info_entry_t *interface_ptr, ws_pae_supp_auth_completed *completed, ws_pae_supp_nw_key_insert *nw_key_insert, ws_pae_supp_nw_key_index_set *nw_key_index_set);
#else
#define ws_pae_supp_init(interface_ptr, certs) 1
#define ws_pae_supp_init(interface_ptr, certs, timer_settings) 1
#define ws_pae_supp_delete NULL
#define ws_pae_supp_cb_register(interface_ptr, completed, key_insert)
#define ws_pae_supp_cb_register(interface_ptr, completed, nw_key_insert, nw_key_index_set)
#define ws_pae_supp_nw_info_set(interface_ptr, pan_id, network_name) -1
#define ws_pae_supp_nw_key_valid(interface_ptr) -1
#define ws_pae_supp_timer NULL
#define ws_pae_supp_fast_timer NULL
#define ws_pae_supp_slow_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
#define ws_pae_supp_gtk_hash_update NULL
#define ws_pae_supp_nw_key_index_update NULL
#endif

View File

@ -0,0 +1,177 @@
/*
* 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.
*/
#include "nsconfig.h"
#include <string.h>
#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 "6LoWPAN/ws/ws_pae_timers.h"
#ifdef HAVE_WS
#define TRACE_GROUP "wspt"
#define SECONDS_IN_DAY 24 * 60 * 60
#define SECONDS_IN_MONTH 30 * SECONDS_IN_DAY
#define SECONDS_IN_MINUTE 60
#define DEFAULT_GTK_EXPIRE_OFFSET 43200 // 30 days
#define DEFAULT_PMK_LIFETIME 4 // 4 months
#define DEFAULT_PTK_LIFETIME 2 // 2 months
#define DEFAULT_GTK_NEW_ACTIVATION_TIME 720 // default 1/720 * 30 days --> 60 minutes
#define DEFAULT_REVOCATION_LIFETIME_REDUCTION 30 // default 1/30 * 30 days --> 1 day
#define DEFAULT_GTK_REQUEST_IMIN 4 // 4 minutes
#define DEFAULT_GTK_REQUEST_IMAX 64 // 64 minutes
#define DEFAULT_GTK_MAX_MISMATCH 64 // 64 minutes
#define DEFAULT_GTK_NEW_INSTALL_REQUIRED 80 // 80 percent of GTK lifetime --> 24 days
static void ws_pae_timers_calculate(timer_settings_t *timer_settings);
void ws_pae_timers_settings_init(timer_settings_t *timer_settings)
{
timer_settings->gtk_expire_offset = DEFAULT_GTK_EXPIRE_OFFSET * SECONDS_IN_MINUTE;
timer_settings->pmk_lifetime = DEFAULT_PMK_LIFETIME * SECONDS_IN_MONTH;
timer_settings->ptk_lifetime = DEFAULT_PTK_LIFETIME * SECONDS_IN_MONTH;
timer_settings->gtk_new_act_time = DEFAULT_GTK_NEW_ACTIVATION_TIME;
timer_settings->revocat_lifetime_reduct = DEFAULT_REVOCATION_LIFETIME_REDUCTION;
timer_settings->gtk_request_imin = DEFAULT_GTK_REQUEST_IMIN * SECONDS_IN_MINUTE;
timer_settings->gtk_request_imax = DEFAULT_GTK_REQUEST_IMAX * SECONDS_IN_MINUTE;
timer_settings->gtk_max_mismatch = DEFAULT_GTK_MAX_MISMATCH * SECONDS_IN_MINUTE;
timer_settings->gtk_new_install_req = DEFAULT_GTK_NEW_INSTALL_REQUIRED;
}
void ws_pae_timers_lifetime_set(timer_settings_t *timer_settings, uint32_t gtk_lifetime, uint32_t pmk_lifetime, uint32_t ptk_lifetime)
{
if (gtk_lifetime) {
timer_settings->gtk_expire_offset = gtk_lifetime * 60;
}
if (pmk_lifetime) {
timer_settings->pmk_lifetime = pmk_lifetime * 60;
}
if (ptk_lifetime) {
timer_settings->ptk_lifetime = ptk_lifetime * 60;
}
ws_pae_timers_calculate(timer_settings);
}
void ws_pae_timers_gtk_time_settings_set(timer_settings_t *timer_settings, uint8_t revocat_lifetime_reduct, uint8_t new_activation_time, uint8_t new_install_req, uint32_t max_mismatch)
{
if (revocat_lifetime_reduct) {
timer_settings->revocat_lifetime_reduct = revocat_lifetime_reduct;
}
if (new_activation_time) {
timer_settings->gtk_new_act_time = new_activation_time;
}
if (new_install_req) {
timer_settings->gtk_new_install_req = new_install_req;
}
if (max_mismatch) {
timer_settings->gtk_max_mismatch = max_mismatch * 60;
}
ws_pae_timers_calculate(timer_settings);
}
static void ws_pae_timers_calculate(timer_settings_t *timer_settings)
{
// Calculate GTK_NEW_INSTALL_REQUIRED < 100 * (1 - 1 / REVOCATION_LIFETIME_REDUCTION)
uint8_t calc_gtk_new_install_req = 100 - (100 / timer_settings->revocat_lifetime_reduct);
if (timer_settings->gtk_expire_offset < 3600) {
// For very short GTKs give some more time to distribute the new GTK key to network, tune this if needed
calc_gtk_new_install_req = calc_gtk_new_install_req * 60 / 100;
}
if (timer_settings->gtk_new_install_req > calc_gtk_new_install_req) {
tr_info("GTK new install required adjusted %i", calc_gtk_new_install_req);
timer_settings->gtk_new_install_req = calc_gtk_new_install_req;
}
// Verify that GTK request Imin and Imax are sensible when compared to revocation lifetime
timer_settings->gtk_request_imin = DEFAULT_GTK_REQUEST_IMIN * SECONDS_IN_MINUTE;
timer_settings->gtk_request_imax = DEFAULT_GTK_REQUEST_IMAX * SECONDS_IN_MINUTE;
uint32_t gtk_revocation_lifetime = timer_settings->gtk_expire_offset / timer_settings->revocat_lifetime_reduct;
uint32_t new_activation_time = timer_settings->gtk_expire_offset / timer_settings->gtk_new_act_time;
uint32_t time_to_update = gtk_revocation_lifetime;
if (gtk_revocation_lifetime > new_activation_time) {
time_to_update = gtk_revocation_lifetime - new_activation_time;
}
tr_info("Key timers revocation lifetime: %"PRIu32", new activation time: %"PRIu32", max mismatch %i, time to update: %"PRIu32"", gtk_revocation_lifetime, new_activation_time, timer_settings->gtk_max_mismatch, time_to_update);
// If time to update results smaller GTK request Imax use it for calculation otherwise use GTK max mismatch
if (time_to_update < timer_settings->gtk_max_mismatch) {
// If time to update is smaller than GTK request Imax update GTK request values
if (timer_settings->gtk_request_imax > time_to_update) {
timer_settings->gtk_request_imin = time_to_update / 4;
timer_settings->gtk_request_imax = time_to_update / 2;
tr_info("GTK request timers adjusted Imin: %i, Imax: %i", timer_settings->gtk_request_imin, timer_settings->gtk_request_imax);
}
} else if (timer_settings->gtk_request_imax > timer_settings->gtk_max_mismatch) {
// If GTK request Imax is larger than GTK max mismatch update GTK request values
// For small GTK max mismatch times, scale the Imin to be larger than default 4 / 64;
uint16_t scaler;
if (timer_settings->gtk_max_mismatch < 50) {
scaler = 10;
} else if (timer_settings->gtk_max_mismatch > 600) {
scaler = 1;
} else {
// About 1 minute mismatch, results 37 seconds Imin and 60 seconds Imax
scaler = (600 - timer_settings->gtk_max_mismatch) / 54;
}
timer_settings->gtk_request_imin = timer_settings->gtk_max_mismatch * scaler * DEFAULT_GTK_REQUEST_IMIN / DEFAULT_GTK_REQUEST_IMAX;
timer_settings->gtk_request_imax = timer_settings->gtk_max_mismatch;
tr_info("GTK request timers adjusted Imin: %i, Imax: %i", timer_settings->gtk_request_imin, timer_settings->gtk_request_imax);
}
}
bool ws_pae_timers_gtk_new_install_required(timer_settings_t *timer_settings, uint32_t seconds)
{
uint32_t gtk_new_install_req_seconds = timer_settings->gtk_expire_offset - timer_settings->gtk_new_install_req * timer_settings->gtk_expire_offset / 100;
if (seconds < gtk_new_install_req_seconds) {
return true;
} else {
return false;
}
}
bool ws_pae_timers_gtk_new_activation_time(timer_settings_t *timer_settings, uint32_t seconds)
{
uint32_t gtk_gtk_new_activation_time_seconds = timer_settings->gtk_expire_offset / timer_settings->gtk_new_act_time;
if (seconds < gtk_gtk_new_activation_time_seconds) {
return true;
} else {
return false;
}
}
uint32_t ws_pae_timers_gtk_revocation_lifetime_get(timer_settings_t *timer_settings)
{
return timer_settings->gtk_expire_offset / timer_settings->revocat_lifetime_reduct;
}
#endif /* HAVE_WS */

View File

@ -0,0 +1,98 @@
/*
* 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 WS_PAE_TIMERS_H_
#define WS_PAE_TIMERS_H_
typedef struct {
uint32_t gtk_expire_offset; // GTK lifetime; GTK_EXPIRE_OFFSET (seconds)
uint32_t pmk_lifetime; // PMK lifetime (seconds)
uint32_t ptk_lifetime; // PTK lifetime (seconds)
uint16_t gtk_new_act_time; // GTK_NEW_ACTIVATION_TIME (1/X of expire offset)
uint16_t revocat_lifetime_reduct; // REVOCATION_LIFETIME_REDUCTION (reduction of lifetime)
uint16_t gtk_request_imin; // GTK_REQUEST_IMIN (seconds)
uint16_t gtk_request_imax; // GTK_REQUEST_IMAX (seconds)
uint16_t gtk_max_mismatch; // GTK_MAX_MISMATCH (seconds)
uint8_t gtk_new_install_req; // GTK_NEW_INSTALL_REQUIRED (percent of GTK lifetime)
} timer_settings_t;
/**
* ws_pae_timers_settings_init initializes timer settings structure
*
* \param timer_settings timer settings
*
*/
void ws_pae_timers_settings_init(timer_settings_t *timer_settings);
/**
* ws_pae_timers_lifetime_set sets GTK, PTK and PTK lifetimes
*
* \param timer_settings timer settings
* \param gtk_lifetime GTK lifetime
* \param pmk_lifetime PMK lifetime
* \param ptk_lifetime PTK lifetime
*
*/
void ws_pae_timers_lifetime_set(timer_settings_t *timer_settings, uint32_t gtk_lifetime, uint32_t pmk_lifetime, uint32_t ptk_lifetime);
/**
* ws_pae_timers_gtk_time_settings_set sets GTK, PTK and PTK lifetimes
*
* \param timer_settings timer settings
* \param revocat_lifetime_reduct revocation lifetime reduction
* \param new_activation_time new activation time
* \param new_install_req new install required
* \param max_mismatch max mismatch
*
*/
void ws_pae_timers_gtk_time_settings_set(timer_settings_t *timer_settings, uint8_t revocat_lifetime_reduct, uint8_t new_activation_time, uint8_t new_install_req, uint32_t max_mismatch);
/**
* ws_pae_timers_gtk_new_install_required GTK new install required check
*
* \param timer_settings timer settings
* \param seconds elapsed seconds
*
* \return true new GTK install required expired
* \return false GTK install not required
*
*/
bool ws_pae_timers_gtk_new_install_required(timer_settings_t *timer_settings, uint32_t seconds);
/**
* ws_pae_timers_gtk_new_activation_time GTK new activation time
*
* \param timer_settings timer settings
* \param seconds elapsed seconds
*
* \return true GTK new activation time expired
* \return false GTK new activation time not expired
*
*/
bool ws_pae_timers_gtk_new_activation_time(timer_settings_t *timer_settings, uint32_t seconds);
/**
* ws_pae_timers_gtk_revocation_lifetime_get GTK revocation lifetime get
*
* \param timer_settings timer settings
*
* \return GTK revocation lifetime
*
*/
uint32_t ws_pae_timers_gtk_revocation_lifetime_get(timer_settings_t *timer_settings);
#endif /* WS_PAE_TIMERS_H_ */

View File

@ -25,6 +25,7 @@
#include "6LoWPAN/ws/ws_config.h"
#include "6LoWPAN/ws/ws_common.h"
#include "6LoWPAN/ws/ws_bbr_api_internal.h"
#include "6LoWPAN/ws/ws_pae_controller.h"
#include "randLIB.h"
#include "ns_trace.h"
@ -60,7 +61,7 @@ int ws_test_gtk_set(int8_t interface_id, uint8_t *gtk[4])
(void) interface_id;
(void) gtk;
return 0;
return ws_pae_controller_gtk_update(interface_id, gtk);
}
int ws_test_active_key_set(int8_t interface_id, uint8_t index)
@ -68,7 +69,7 @@ int ws_test_active_key_set(int8_t interface_id, uint8_t index)
(void) interface_id;
(void) index;
return 0;
return ws_pae_controller_active_key_update(interface_id, index);
}
int ws_test_key_lifetime_set(int8_t interface_id, uint32_t gtk_lifetime, uint32_t pmk_lifetime, uint32_t ptk_lifetime)
@ -78,17 +79,27 @@ int ws_test_key_lifetime_set(int8_t interface_id, uint32_t gtk_lifetime, uint32_
(void) pmk_lifetime;
(void) ptk_lifetime;
return 0;
return ws_pae_controller_key_lifetime_update(interface_id, gtk_lifetime, pmk_lifetime, ptk_lifetime);
}
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)
int ws_test_gtk_time_settings_set(int8_t interface_id, uint8_t revocat_lifetime_reduct, uint8_t new_activation_time, uint8_t new_install_req, uint32_t max_mismatch)
{
(void) interface_id;
(void) revocat_lifetime_reduct;
(void) new_activation_time;
(void) new_install_req;
(void) max_mismatch;
return 0;
return ws_pae_controller_gtk_time_settings_update(interface_id, revocat_lifetime_reduct, new_activation_time, new_install_req, max_mismatch);
}
int ws_test_next_gtk_set(int8_t interface_id, uint8_t *gtk[4])
{
(void) interface_id;
(void) gtk;
return ws_pae_controller_next_gtk_update(interface_id, gtk);
}
#endif // HAVE_WS

View File

@ -325,12 +325,12 @@ static buffer_t *icmpv6_echo_request_handler(buffer_t *buf)
if (addr_is_ipv6_multicast(buf->dst_sa.address)) {
const uint8_t *ipv6_ptr;
memcpy(buf->dst_sa.address, buf->src_sa.address, 16);
ipv6_ptr = addr_select_source(cur, buf->dst_sa.address, 0);
if (!ipv6_ptr) {
tr_debug("No address");
return buffer_free(buf);
}
memcpy(buf->dst_sa.address, buf->src_sa.address, 16);
memcpy(buf->src_sa.address, ipv6_ptr, 16);
} else {
memswap(buf->dst_sa.address, buf->src_sa.address, 16);
@ -570,16 +570,8 @@ int icmpv6_slaac_prefix_update(struct protocol_interface_info_entry *cur, const
//Validate first current list If prefix is already defined adress
ns_list_foreach_safe(if_address_entry_t, e, &cur->ip_addresses) {
if (e->source == ADDR_SOURCE_SLAAC && (e->prefix_len == prefix_len) && bitsequal(e->address, prefix_ptr, prefix_len)) {
//Update Current lifetimes (see RFC 4862 for rules detail)
if (valid_lifetime > (2 * 60 * 60) || valid_lifetime > e->valid_lifetime) {
addr_set_valid_lifetime(cur, e, valid_lifetime);
} else if (e->valid_lifetime <= (2 * 60 * 60)) {
//NOT Update Valid Lifetime
} else {
addr_set_valid_lifetime(cur, e, 2 * 60 * 60);
}
addr_set_preferred_lifetime(cur, e, preferred_lifetime);
addr_lifetime_update(cur, e, valid_lifetime, preferred_lifetime, 2 * 60 * 60);
ret_val = 0;
}
}
@ -1320,6 +1312,63 @@ uint8_t *icmpv6_write_mtu_option(uint32_t mtu, uint8_t *dptr)
return dptr;
}
void ack_receive_cb(struct buffer *buffer_ptr, uint8_t status)
{
/*icmpv6_na_handler functionality based on ACK*/
ipv6_neighbour_t *neighbour_entry;
uint8_t ll_target[16];
if (status != SOCKET_TX_DONE) {
/*NS failed*/
return;
}
if (buffer_ptr->dst_sa.addr_type == ADDR_IPV6) {
/*Full IPv6 address*/
memcpy(ll_target, buffer_ptr->dst_sa.address, 16);
} else if (buffer_ptr->dst_sa.addr_type == ADDR_802_15_4_LONG) {
// Build link local address from long MAC address
memcpy(ll_target, ADDR_LINK_LOCAL_PREFIX, 8);
memcpy(ll_target + 8, &buffer_ptr->dst_sa.address[2], 8);
ll_target[8] ^= 2;
} else {
tr_warn("wrong address %d %s", buffer_ptr->dst_sa.addr_type, trace_array(buffer_ptr->dst_sa.address, 16));
return;
}
neighbour_entry = ipv6_neighbour_lookup(&buffer_ptr->interface->ipv6_neighbour_cache, ll_target);
if (neighbour_entry) {
ipv6_neighbour_update_from_na(&buffer_ptr->interface->ipv6_neighbour_cache, neighbour_entry, NA_S, buffer_ptr->dst_sa.addr_type, buffer_ptr->dst_sa.address);
}
if (ws_info(buffer_ptr->interface)) {
ws_common_neighbor_update(buffer_ptr->interface, ll_target);
}
}
void ack_remove_neighbour_cb(struct buffer *buffer_ptr, uint8_t status)
{
/*icmpv6_na_handler functionality based on ACK*/
uint8_t ll_target[16];
(void)status;
if (buffer_ptr->dst_sa.addr_type == ADDR_IPV6) {
/*Full IPv6 address*/
memcpy(ll_target, buffer_ptr->dst_sa.address, 16);
} else if (buffer_ptr->dst_sa.addr_type == ADDR_802_15_4_LONG) {
// Build link local address from long MAC address
memcpy(ll_target, ADDR_LINK_LOCAL_PREFIX, 8);
memcpy(ll_target + 8, &buffer_ptr->dst_sa.address[2], 8);
ll_target[8] ^= 2;
} else {
tr_warn("wrong address %d %s", buffer_ptr->dst_sa.addr_type, trace_array(buffer_ptr->dst_sa.address, 16));
return;
}
if (ws_info(buffer_ptr->interface)) {
ws_common_neighbor_remove(buffer_ptr->interface, ll_target);
}
}
buffer_t *icmpv6_build_ns(protocol_interface_info_entry_t *cur, const uint8_t target_addr[16], const uint8_t *prompting_src_addr, bool unicast, bool unspecified_source, const aro_t *aro)
{
if (!cur || addr_is_ipv6_multicast(target_addr)) {
@ -1394,10 +1443,15 @@ buffer_t *icmpv6_build_ns(protocol_interface_info_entry_t *cur, const uint8_t ta
}
/* If ARO Success sending is omitted, MAC ACK is used instead */
/* Setting callback for receiving ACK from adaptation layer */
if (aro && cur->ipv6_neighbour_cache.omit_aro_success) {
if (aro && cur->ipv6_neighbour_cache.omit_na_aro_success) {
buf->ack_receive_cb = rpl_control_address_register_done;
}
}
if (unicast && (!aro && cur->ipv6_neighbour_cache.omit_na)) {
/*MAC ACK is processed as success response*/
buf->ack_receive_cb = ack_receive_cb;
}
buf->src_sa.addr_type = ADDR_IPV6;
/* NS packets are implicitly on-link. If we ever find ourselves sending an
@ -1530,11 +1584,16 @@ buffer_t *icmpv6_build_na(protocol_interface_info_entry_t *cur, bool solicited,
tr_debug("Build NA");
/* Check if ARO status == success, then sending can be omitted with flag */
if (aro && cur->ipv6_neighbour_cache.omit_aro_success && aro->status == ARO_SUCCESS) {
tr_debug("Omit success reply");
/* Check if ARO response and status == success, then sending can be omitted with flag */
if (aro && cur->ipv6_neighbour_cache.omit_na_aro_success && aro->status == ARO_SUCCESS) {
tr_debug("Omit NA ARO success");
return NULL;
}
/* All other than ARO NA messages are omitted and MAC ACK is considered as success */
if (!tllao_required && (!aro && cur->ipv6_neighbour_cache.omit_na)) {
return NULL;
}
buffer_t *buf = buffer_get(8 + 16 + 16 + 16); /* fixed, target addr, target ll addr, aro */
if (!buf) {
@ -1616,6 +1675,11 @@ buffer_t *icmpv6_build_na(protocol_interface_info_entry_t *cur, bool solicited,
memcpy(ptr, aro->eui64, 8);
ptr += 8;
}
if (ws_info(cur) && aro && aro->status != ARO_SUCCESS) {
/*If Aro failed we will kill the neigbour after we have succeeded in sending message*/
buf->ack_receive_cb = ack_remove_neighbour_cb;
}
//Force Next Hop is destination
ipv6_buffer_route_to(buf, buf->dst_sa.address, cur);

View File

@ -35,9 +35,11 @@ prefix_entry_t *icmpv6_prefix_add(prefix_list_t *list, const uint8_t *prefixPtr,
entry = icmpv6_prefix_compare(list, prefixPtr, prefix_len);
if (entry) {
if (flags != 0xff) {
entry->options = flags;
entry->lifetime = lifeTime;
entry->preftime = prefTime;
}
return entry;
}

View File

@ -156,6 +156,7 @@ void addr_fast_timer(struct protocol_interface_info_entry *cur, uint_fast16_t ti
void addr_slow_timer(struct protocol_interface_info_entry *cur, uint_fast16_t seconds);
struct if_address_entry *addr_add(struct protocol_interface_info_entry *cur, const uint8_t address[__static 16], uint_fast8_t prefix_len, if_address_source_t source, uint32_t valid_lifetime, uint32_t preferred_lifetime, bool skip_dad);
int_fast8_t addr_delete(struct protocol_interface_info_entry *cur, const uint8_t address[__static 16]);
int_fast8_t addr_deprecate(struct protocol_interface_info_entry *cur, const uint8_t address[__static 16]);
void addr_delete_matching(struct protocol_interface_info_entry *cur, const uint8_t *prefix, uint8_t prefix_len, if_address_source_t source);
void addr_delete_entry(struct protocol_interface_info_entry *cur, if_address_entry_t *addr);
void addr_set_non_preferred(struct protocol_interface_info_entry *cur, if_address_source_t source);
@ -166,6 +167,8 @@ void addr_cb(struct protocol_interface_info_entry *interface, if_address_entry_t
void addr_set_valid_lifetime(struct protocol_interface_info_entry *interface, if_address_entry_t *entry, uint32_t valid_lifetime);
void addr_set_preferred_lifetime(struct protocol_interface_info_entry *interface, if_address_entry_t *entry, uint32_t preferred_lifetime);
void addr_lifetime_update(struct protocol_interface_info_entry *interface, if_address_entry_t *address, uint32_t valid_lifetime, uint32_t preferred_lifetime, uint32_t threshold);
int_fast8_t addr_policy_table_add_entry(const uint8_t *prefix, uint8_t len, uint8_t precedence, uint8_t label);
int_fast8_t addr_policy_table_delete_entry(const uint8_t *prefix, uint8_t len);
uint8_t addr_len_from_type(addrtype_t addr_type);
@ -178,6 +181,8 @@ struct if_address_entry *addr_get_entry(const struct protocol_interface_info_ent
bool addr_is_assigned_to_interface(const struct protocol_interface_info_entry *interface, const uint8_t addr[__static 16]);
bool addr_is_tentative_for_interface(const struct protocol_interface_info_entry *interface, const uint8_t addr[__static 16]);
void addr_policy_remove_by_label(uint8_t label);
void addr_duplicate_detected(struct protocol_interface_info_entry *interface, const uint8_t addr[__static 16]);
struct if_group_entry *addr_add_group(struct protocol_interface_info_entry *interface, const uint8_t group[__static 16]);

View File

@ -690,6 +690,13 @@ const uint8_t *addr_select_source(protocol_interface_info_entry_t *interface, co
}
}
/* Rule 9 select most precated one */
if (policy_SA->precedence > policy_SB->precedence) {
PREFER_SA;
} else if (policy_SB->precedence > policy_SA->precedence) {
PREFER_SB;
}
/* Tie */
PREFER_SA;
}
@ -858,6 +865,7 @@ void addr_fast_timer(protocol_interface_info_entry_t *cur, uint_fast16_t ticks)
}
#endif
} else {
addr->addr_reg_done = 0;
addr_cb(cur, addr, ADDR_CALLBACK_TIMER);
}
@ -1002,6 +1010,19 @@ int_fast8_t addr_delete(protocol_interface_info_entry_t *cur, const uint8_t addr
return -1;
}
int_fast8_t addr_deprecate(protocol_interface_info_entry_t *cur, const uint8_t address[static 16])
{
ns_list_foreach(if_address_entry_t, e, &cur->ip_addresses) {
if (memcmp(e->address, address, 16) == 0) {
tr_debug("Deprecate address %s", trace_ipv6(e->address));
addr_lifetime_update(cur, e, 0, 0, 30 * 60); //Accept max 30 min lifetime
return 0;
}
}
return -1;
}
void addr_delete_matching(protocol_interface_info_entry_t *cur, const uint8_t *prefix, uint8_t prefix_len, if_address_source_t source)
{
ns_list_foreach_safe(if_address_entry_t, e, &cur->ip_addresses) {
@ -1091,6 +1112,20 @@ void addr_set_preferred_lifetime(protocol_interface_info_entry_t *interface, if_
}
}
void addr_lifetime_update(protocol_interface_info_entry_t *interface, if_address_entry_t *address, uint32_t valid_lifetime, uint32_t preferred_lifetime, uint32_t threshold)
{
//Update Current lifetimes (see RFC 4862 for rules detail)
if (valid_lifetime > threshold || valid_lifetime > address->valid_lifetime) {
addr_set_valid_lifetime(interface, address, valid_lifetime);
} else if (address->valid_lifetime <= threshold) {
//NOT Update Valid Lifetime
} else {
addr_set_valid_lifetime(interface, address, threshold);
}
addr_set_preferred_lifetime(interface, address, preferred_lifetime);
}
void memswap(uint8_t *restrict a, uint8_t *restrict b, uint_fast8_t len)
{
while (len--) {
@ -1398,6 +1433,21 @@ int8_t addr_interface_select_source(protocol_interface_info_entry_t *cur, uint8_
return ret_val;
}
void addr_policy_remove_by_label(uint8_t label)
{
ns_list_foreach_safe(addr_policy_table_entry_t, entry, &addr_policy_table) {
if (entry->label == label) {
/*
* Remove label policy if no local address matches"
*/
if (!protocol_interface_any_address_match(entry->prefix, entry->prefix_len)) {
ns_list_remove(&addr_policy_table, entry);
ns_dyn_mem_free(entry);
}
}
}
}
// This last function must always be compiled with tracing enabled
#ifndef FEA_TRACE_SUPPORT
#define FEA_TRACE_SUPPORT 1

View File

@ -272,7 +272,7 @@ void DHCPv6_server_service_timeout_cb(uint32_t timeUpdateInSeconds)
* /param guaPrefix Prefix which will be removed
* /param delete_gua_addresses Whether or not assigned addresses with the prefix should be removed from the interface.
*/
void DHCPv6_server_service_delete(int8_t interface, uint8_t guaPrefix[static 16], bool delete_gua_addresses)
void DHCPv6_server_service_delete(int8_t interface, uint8_t guaPrefix[static 8], bool delete_gua_addresses)
{
dhcpv6_gua_server_entry_s *serverInfo = libdhcpv6_server_data_get_by_prefix_and_interfaceid(interface, guaPrefix);
if (serverInfo) {
@ -390,7 +390,7 @@ int DHCPv6_server_service_init(int8_t interface, uint8_t guaPrefix[static 16], u
return -1;
}
void DHCPv6_server_service_delete(int8_t interface, uint8_t guaPrefix[static 16], bool delete_gua_addresses)
void DHCPv6_server_service_delete(int8_t interface, uint8_t guaPrefix[static 8], bool delete_gua_addresses)
{
(void) interface;
(void) guaPrefix;

View File

@ -54,7 +54,7 @@ void DHCPv6_server_service_callback_set(int8_t interface, uint8_t guaPrefix[stat
* /param guaPrefix Prefix which will be removed
* /param delete_gua_addresses Whether or not assigned addresses with the prefix should be removed from the interface.
*/
void DHCPv6_server_service_delete(int8_t interface, uint8_t guaPrefix[static 16], bool delete_gua_addresses);
void DHCPv6_server_service_delete(int8_t interface, uint8_t guaPrefix[static 8], bool delete_gua_addresses);
void DHCPv6_server_service_timeout_cb(uint32_t timeUpdateInSeconds);

View File

@ -38,9 +38,12 @@ void dhcp_client_init(int8_t interface);
/* Set configurations for DHCP client
*
* /param interface Client Inteface ID
* /param renew_uses_solicit Instead of renew message SOLICIT is used.
* /param one_client_for_this_interface True Interface use oneinstance for allocate address
* /param no_address_hint IAID use address at Solicit
*/
void dhcp_client_configure(int8_t interface, bool renew_uses_solicit);
void dhcp_client_configure(int8_t interface, bool renew_uses_solicit, bool one_client_for_this_interface, bool no_address_hint);
/* Set Timeout parameters for SOLICIT transactions
*
@ -92,11 +95,13 @@ void dhcp_client_global_address_renew(int8_t interface);
* /param prefix dhcp server ML16 address where address is registered.
*
*/
void dhcp_client_global_address_delete(int8_t interface, uint8_t dhcp_addr[static 16], uint8_t prefix[static 16]);
void dhcp_client_global_address_delete(int8_t interface, uint8_t *dhcp_addr, uint8_t prefix[static 16]);
void dhcp_relay_agent_enable(int8_t interface, uint8_t border_router_address[static 16]);
int dhcp_client_server_address_update(int8_t interface, uint8_t prefix[static 16], uint8_t server_address[static 16]);
#endif /* DHCPV6_CLIENT_API_H_ */

View File

@ -41,11 +41,14 @@ typedef struct {
uint8_t libDhcp_instance;
int8_t interface;
bool renew_uses_solicit: 1;
bool one_instance_interface: 1;
bool no_address_hint: 1;
} dhcp_client_class_t;
static dhcp_client_class_t dhcp_client;
void dhcpv6_client_set_address(int8_t interface_id, dhcpv6_client_server_data_t *srv_data_ptr);
static bool dhcpv6_client_set_address(int8_t interface_id, dhcpv6_client_server_data_t *srv_data_ptr);
void dhcpv6_renew(protocol_interface_info_entry_t *interface, if_address_entry_t *addr, if_address_callback_t reason);
void dhcp_client_init(int8_t interface)
@ -57,14 +60,19 @@ void dhcp_client_init(int8_t interface)
dhcp_client.sol_timeout = 0;
dhcp_client.sol_max_rt = 0;
dhcp_client.sol_max_rc = 0;
dhcp_client.renew_uses_solicit = false;
dhcp_client.one_instance_interface = false;
dhcp_client.no_address_hint = false;
return;
}
void dhcp_client_configure(int8_t interface, bool renew_uses_solicit)
void dhcp_client_configure(int8_t interface, bool renew_uses_solicit, bool one_client_for_this_interface, bool no_address_hint)
{
// Set true if RENEW is not used and SOLICIT sent instead.
(void)interface;
dhcp_client.renew_uses_solicit = renew_uses_solicit;
dhcp_client.one_instance_interface = one_client_for_this_interface;
dhcp_client.no_address_hint = no_address_hint;
}
void dhcp_client_solicit_timeout_set(int8_t interface, uint16_t timeout, uint16_t max_rt, uint8_t max_rc)
@ -170,6 +178,14 @@ int dhcp_solicit_resp_cb(uint16_t instance_id, void *ptr, uint8_t msg_name, uin
goto error_exit;
}
if (dhcp_client.one_instance_interface && memcmp(srv_data_ptr->iaNontemporalAddress.addressPrefix, dhcp_ia_non_temporal_params.nonTemporalAddress, 16)) {
protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(dhcp_client.interface);
if (cur) {
addr_deprecate(cur, srv_data_ptr->iaNontemporalAddress.addressPrefix);
}
}
memcpy(srv_data_ptr->iaNontemporalAddress.addressPrefix, dhcp_ia_non_temporal_params.nonTemporalAddress, 16);
srv_data_ptr->iaNontemporalAddress.preferredTime = dhcp_ia_non_temporal_params.preferredValidLifeTime;
srv_data_ptr->iaNontemporalAddress.validLifetime = dhcp_ia_non_temporal_params.validLifeTime;
@ -177,13 +193,13 @@ int dhcp_solicit_resp_cb(uint16_t instance_id, void *ptr, uint8_t msg_name, uin
srv_data_ptr->serverLinkType = serverId.linkType;
srv_data_ptr->T0 = dhcp_ia_non_temporal_params.T0;
srv_data_ptr->T1 = dhcp_ia_non_temporal_params.T1;
srv_data_ptr->iaNonTemporalStructValid = true;
dhcpv6_client_set_address(dhcp_client.interface, srv_data_ptr);
bool status = dhcpv6_client_set_address(dhcp_client.interface, srv_data_ptr);
if (dhcp_client.global_address_cb) {
dhcp_client.global_address_cb(dhcp_client.interface, srv_data_ptr->server_address, srv_data_ptr->iaNontemporalAddress.addressPrefix, true);
dhcp_client.global_address_cb(dhcp_client.interface, srv_data_ptr->server_address, srv_data_ptr->iaNontemporalAddress.addressPrefix, status);
}
return RET_MSG_ACCEPTED;
error_exit:
@ -198,20 +214,36 @@ int dhcp_client_get_global_address(int8_t interface, uint8_t dhcp_addr[static 16
uint8_t *payload_ptr;
uint32_t payload_len;
dhcpv6_client_server_data_t *srv_data_ptr;
bool add_prefix;
if (mac64 == NULL || dhcp_addr == NULL) {
tr_error("Invalid parameters");
return -1;
}
if (!prefix) {
if (!prefix || dhcp_client.one_instance_interface) {
//NULL Definition will only check That Interface is not generated
if (libdhcpv6_nonTemporal_entry_get_by_instance(dhcp_client.libDhcp_instance)) {
srv_data_ptr = libdhcpv6_nonTemporal_entry_get_by_instance(dhcp_client.libDhcp_instance);
if (srv_data_ptr) {
//Already Created to same interface
if (dhcp_client.one_instance_interface && prefix) {
if (srv_data_ptr->iaNonTemporalStructValid) {
if (memcmp(srv_data_ptr->iaNontemporalAddress.addressPrefix, prefix, 8)) {
//Request new address direct from Server if prefix is new
srv_data_ptr->iaNonTemporalStructValid = false;
dhcpv6_renew(protocol_stack_interface_info_get_by_id(interface), NULL, ADDR_CALLBACK_TIMER);
}
return 0;
}
}
return -1;
}
} else if (dhcp_client_server_address_update(interface, prefix, dhcp_addr) == 0) {
//No need for allocate new
return 0;
}
tr_debug("GEN new Dhcpv6 client %u", dhcp_client.libDhcp_instance);
srv_data_ptr = libdhcvp6_nontemporalAddress_server_data_allocate(interface, dhcp_client.libDhcp_instance, mac64, link_type, prefix, dhcp_addr);
if (!srv_data_ptr) {
@ -219,7 +251,15 @@ int dhcp_client_get_global_address(int8_t interface, uint8_t dhcp_addr[static 16
return -1;
}
payload_len = libdhcpv6_solication_message_length(link_type, prefix != NULL, 0);
if (!prefix || dhcp_client.no_address_hint) {
add_prefix = false;
} else {
add_prefix = prefix != NULL;
}
payload_len = libdhcpv6_solication_message_length(link_type, add_prefix, 0);
payload_ptr = ns_dyn_mem_temporary_alloc(payload_len);
if (!payload_ptr) {
@ -238,7 +278,7 @@ int dhcp_client_get_global_address(int8_t interface, uint8_t dhcp_addr[static 16
solPacket.transActionId = libdhcpv6_txid_get();
/*Non Temporal Address */
if (prefix) {
if (prefix && !dhcp_client.no_address_hint) {
dhcpv6_ia_non_temporal_address_s nonTemporalAddress = {0};
nonTemporalAddress.requestedAddress = prefix;
libdhcpv6_generic_nontemporal_address_message_write(payload_ptr, &solPacket, &nonTemporalAddress, NULL);
@ -253,6 +293,7 @@ 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;
}
srv_data_ptr->iaNonTemporalStructValid = false;
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);
@ -261,13 +302,44 @@ int dhcp_client_get_global_address(int8_t interface, uint8_t dhcp_addr[static 16
return 0;
}
int dhcp_client_server_address_update(int8_t interface, uint8_t prefix[static 16], uint8_t server_address[static 16])
{
dhcpv6_client_server_data_t *srv_data_ptr = NULL;
if (dhcp_client.interface != interface) {
tr_debug("Interface not match");
return -1;
}
if (prefix) {
srv_data_ptr = libdhcpv6_nonTemporal_entry_get_by_prefix(interface, prefix);
} else if (dhcp_client.one_instance_interface) {
srv_data_ptr = libdhcpv6_nonTemporal_entry_get_by_instance(dhcp_client.libDhcp_instance);
}
if (!srv_data_ptr) {
return -1;
}
if (memcmp(srv_data_ptr->server_address, server_address, 16) == 0) {
return 0;
}
memcpy(srv_data_ptr->server_address, server_address, 16);
if (!srv_data_ptr->iaNonTemporalStructValid) {
dhcp_service_update_server_address(srv_data_ptr->transActionId, server_address);
}
return 0;
}
void dhcp_client_global_address_renew(int8_t interface)
{
(void)interface;
return;
}
void dhcp_client_global_address_delete(int8_t interface, uint8_t dhcp_addr[static 16], uint8_t prefix[static 16])
void dhcp_client_global_address_delete(int8_t interface, uint8_t *dhcp_addr, uint8_t prefix[static 16])
{
protocol_interface_info_entry_t *cur;
dhcpv6_client_server_data_t *srv_data_ptr;
@ -276,33 +348,35 @@ void dhcp_client_global_address_delete(int8_t interface, uint8_t dhcp_addr[stati
srv_data_ptr = libdhcpv6_nonTemporal_entry_get_by_prefix(interface, prefix);
cur = protocol_stack_interface_info_get_by_id(interface);
do {
if (cur == NULL || srv_data_ptr == NULL) {
return;
}
dhcp_service_req_remove(srv_data_ptr->transActionId);// remove all pending retransmissions
tr_debug("Deleting address: %s", trace_ipv6(srv_data_ptr->iaNontemporalAddress.addressPrefix));
dhcp_service_req_remove(srv_data_ptr->transActionId);// remove all pending retransmissions
if (dhcp_client.one_instance_interface) {
addr_deprecate(cur, srv_data_ptr->iaNontemporalAddress.addressPrefix);
} else {
addr_delete(cur, srv_data_ptr->iaNontemporalAddress.addressPrefix);
}
libdhcvp6_nontemporalAddress_server_data_free(srv_data_ptr);
srv_data_ptr = libdhcpv6_nonTemporal_entry_get_by_prefix(interface, prefix);
} while (srv_data_ptr);
return;
}
void dhcpv6_renew(protocol_interface_info_entry_t *interface, if_address_entry_t *addr, if_address_callback_t reason)
{
dhcpv6_ia_non_temporal_address_s nonTemporalAddress = {0};
dhcp_link_options_params_t serverLink;
uint8_t *payload_ptr;
uint32_t payload_len;
dhcpv6_client_server_data_t *srv_data_ptr = libdhcpv6_nonTemporal_entry_get_by_prefix(interface->id, addr->address);
dhcpv6_client_server_data_t *srv_data_ptr;
if (addr) {
srv_data_ptr = libdhcpv6_nonTemporal_entry_get_by_prefix(interface->id, addr->address);
} else {
srv_data_ptr = libdhcpv6_nonTemporal_entry_get_by_instance(dhcp_client.libDhcp_instance);
}
if (srv_data_ptr == NULL) {
tr_warn("Dhcp address lost");
return ;
return;
}
if (reason == ADDR_CALLBACK_INVALIDATED) {
dhcp_service_req_remove(srv_data_ptr->transActionId);//stop retransmissions of renew
@ -315,10 +389,12 @@ void dhcpv6_renew(protocol_interface_info_entry_t *interface, if_address_entry_t
return;
}
payload_len = libdhcpv6_address_request_message_len(srv_data_ptr->clientLinkIdType, srv_data_ptr->serverLinkType, 0);
payload_len = libdhcpv6_address_request_message_len(srv_data_ptr->clientLinkIdType, srv_data_ptr->serverLinkType, 0, !dhcp_client.no_address_hint);
payload_ptr = ns_dyn_mem_temporary_alloc(payload_len);
if (payload_ptr == NULL) {
if (addr) {
addr->state_timer = 200; //Retry after 20 seconds
}
tr_error("Out of memory");
return ;
}
@ -337,18 +413,33 @@ void dhcpv6_renew(protocol_interface_info_entry_t *interface, if_address_entry_t
packetReq.messageType = DHCPV6_SOLICATION_TYPE;
}
serverLink.linkID = srv_data_ptr->serverLinkId;
serverLink.linkType = srv_data_ptr->serverLinkType;
if (dhcp_client.no_address_hint && dhcp_client.renew_uses_solicit) {
packetReq.timerT0 = 0;
packetReq.timerT1 = 0;
libdhcpv6_generic_nontemporal_address_message_write(payload_ptr, &packetReq, NULL, &serverLink);
} else {
// Set Address information
dhcpv6_ia_non_temporal_address_s nonTemporalAddress = {0};
nonTemporalAddress.requestedAddress = srv_data_ptr->iaNontemporalAddress.addressPrefix;
nonTemporalAddress.preferredLifeTime = srv_data_ptr->iaNontemporalAddress.preferredTime;
nonTemporalAddress.validLifeTime = srv_data_ptr->iaNontemporalAddress.validLifetime;
serverLink.linkID = srv_data_ptr->serverLinkId;
serverLink.linkType = srv_data_ptr->serverLinkType;
libdhcpv6_generic_nontemporal_address_message_write(payload_ptr, &packetReq, &nonTemporalAddress, &serverLink);
}
// send solicit
srv_data_ptr->transActionId = dhcp_service_send_req(dhcp_client.service_instance, 0, srv_data_ptr, srv_data_ptr->server_address, payload_ptr, payload_len, dhcp_solicit_resp_cb);
uint8_t *server_address = dhcp_service_relay_global_addres_get(dhcp_client.relay_instance);
if (!server_address) {
server_address = srv_data_ptr->server_address;
}
srv_data_ptr->transActionId = dhcp_service_send_req(dhcp_client.service_instance, 0, srv_data_ptr, server_address, payload_ptr, payload_len, dhcp_solicit_resp_cb);
if (srv_data_ptr->transActionId == 0) {
ns_dyn_mem_free(payload_ptr);
if (addr) {
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) {
@ -357,7 +448,7 @@ void dhcpv6_renew(protocol_interface_info_entry_t *interface, if_address_entry_t
}
}
void dhcpv6_client_set_address(int8_t interface_id, dhcpv6_client_server_data_t *srv_data_ptr)
static bool dhcpv6_client_set_address(int8_t interface_id, dhcpv6_client_server_data_t *srv_data_ptr)
{
protocol_interface_info_entry_t *cur = NULL;
if_address_entry_t *address_entry = NULL;
@ -365,10 +456,11 @@ void dhcpv6_client_set_address(int8_t interface_id, dhcpv6_client_server_data_t
cur = protocol_stack_interface_info_get_by_id(interface_id);
if (!cur) {
return;
return false;
}
renewTimer = libdhcpv6_renew_time_define(srv_data_ptr);
srv_data_ptr->iaNonTemporalStructValid = true;
address_entry = addr_get_entry(cur, srv_data_ptr->iaNontemporalAddress.addressPrefix);
if (address_entry == NULL) {
// create new
@ -380,8 +472,10 @@ void dhcpv6_client_set_address(int8_t interface_id, dhcpv6_client_server_data_t
if (address_entry == NULL) {
tr_error("Address add failed");
return;
srv_data_ptr->iaNonTemporalStructValid = false;
return false;
}
if (renewTimer) {
// translate seconds to 100ms ticks
if (renewTimer < 0xffffffff / 10) {
@ -392,6 +486,7 @@ void dhcpv6_client_set_address(int8_t interface_id, dhcpv6_client_server_data_t
}
address_entry->state_timer = renewTimer;
address_entry->cb = dhcpv6_renew;
return true;
}
#endif

View File

@ -192,6 +192,7 @@ typedef struct protocol_interface_rf_mac_setup {
unsigned macCurrentBE: 4;
uint8_t macMaxCSMABackoffs;
uint8_t backoff_period_in_10us; // max 2550us - it's 320us for standard 250kbps
uint8_t mac_frame_filters;
/* MAC channel parameters */
channel_list_s mac_channel_list;
uint8_t scan_duration; //Needed???
@ -219,6 +220,8 @@ typedef struct protocol_interface_rf_mac_setup {
uint16_t mac_ack_wait_duration;
uint8_t mac_mlme_retry_max;
uint8_t aUnitBackoffPeriod;
uint8_t number_of_csma_ca_periods; /**< Number of CSMA-CA periods */
uint16_t multi_cca_interval; /**< Length of the additional CSMA-CA period(s) in microseconds */
/* Indirect queue parameters */
struct mac_pre_build_frame *indirect_pd_data_request_queue;
arm_event_t mac_mcps_timer_event;

View File

@ -267,6 +267,9 @@ const uint8_t *mac_header_parse_fcf_dsn(mac_fcf_sequence_t *header, const uint8_
} else {
header->DSN = 0;
}
//Check PanID presents at header
header->DstPanPresents = mac_dst_panid_present(header);
header->SrcPanPresents = mac_src_panid_present(header);
return ptr;
}

View File

@ -362,8 +362,6 @@ static int8_t mac_virtual_data_req_handler(protocol_interface_rf_mac_setup_s *rf
}
mac_header_parse_fcf_dsn(&buffer->fcf_dsn, data_ptr);
buffer->fcf_dsn.DstPanPresents = mac_dst_panid_present(&buffer->fcf_dsn);
buffer->fcf_dsn.SrcPanPresents = mac_src_panid_present(&buffer->fcf_dsn);
// Use MAC sequence as handle
buffer->msduHandle = buffer->fcf_dsn.DSN;
memcpy(buffer->mac_payload, data_ptr, data_length);
@ -982,11 +980,6 @@ static void mac_data_interface_frame_handler(mac_pre_parsed_frame_t *buf)
mcps_sap_pre_parsed_frame_buffer_free(buf);
return;
}
if (mac_filter_modify_link_quality(rf_mac_setup->mac_interface_id, buf) == 1) {
mcps_sap_pre_parsed_frame_buffer_free(buf);
return;
}
/* push data to stack if sniffer mode is enabled */
if (rf_mac_setup->macProminousMode) {
mac_nap_tun_data_handler(buf, rf_mac_setup);
@ -1423,13 +1416,20 @@ static void mcps_data_confirm_handle(protocol_interface_rf_mac_setup_s *rf_ptr,
// FHSS checks if this failed buffer needs to be pushed back to TX queue and retransmitted
if ((rf_ptr->mac_tx_result == MAC_TX_FAIL) || (rf_ptr->mac_tx_result == MAC_CCA_FAIL)) {
if (rf_ptr->fhss_api->data_tx_fail(rf_ptr->fhss_api, buffer->msduHandle, mac_convert_frame_type_to_fhss(buffer->fcf_dsn.frametype)) == true) {
if (rf_ptr->mac_tx_result == MAC_TX_FAIL) {
buffer->fhss_retry_count += 1 + rf_ptr->mac_tx_status.retry;
} else {
buffer->fhss_retry_count += rf_ptr->mac_tx_status.retry;
}
buffer->fhss_cca_retry_count += rf_ptr->mac_tx_status.cca_cnt;
mcps_sap_pd_req_queue_write(rf_ptr, buffer);
return;
}
}
}
confirm.cca_retries = rf_ptr->mac_tx_status.cca_cnt;
confirm.tx_retries = rf_ptr->mac_tx_status.retry;
confirm.cca_retries = rf_ptr->mac_tx_status.cca_cnt + buffer->fhss_cca_retry_count;
confirm.tx_retries = rf_ptr->mac_tx_status.retry + buffer->fhss_retry_count;
mac_common_data_confirmation_handle(rf_ptr, buffer);
confirm.msduHandle = buffer->msduHandle;
confirm.status = buffer->status;
@ -1600,9 +1600,8 @@ 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)
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)
{
(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;
@ -1740,7 +1739,7 @@ int8_t mcps_generic_ack_build(protocol_interface_rf_mac_setup_s *rf_ptr, const m
rf_ptr->dev_driver->phy_driver->extension(PHY_EXTENSION_SET_CSMA_PARAMETERS, (uint8_t *) &csma_params);
if (rf_ptr->active_pd_data_request) {
timer_mac_stop(rf_ptr);
mac_pd_sap_set_phy_tx_time(rf_ptr, 0, false);
mac_pd_abort_active_tx(rf_ptr);
}
return mcps_pd_data_cca_trig(rf_ptr, buffer);
}
@ -1828,6 +1827,13 @@ static int8_t mcps_pd_data_cca_trig(protocol_interface_rf_mac_setup_s *rf_ptr, m
}
cca_enabled = true;
}
// Use double CCA check with FHSS for data packets only
if (rf_ptr->fhss_api && !rf_ptr->mac_ack_tx_active && !rf_ptr->active_pd_data_request->asynch_request) {
if ((buffer->tx_time - (rf_ptr->multi_cca_interval * (rf_ptr->number_of_csma_ca_periods - 1))) > mac_mcps_sap_get_phy_timestamp(rf_ptr)) {
buffer->csma_periods_left = rf_ptr->number_of_csma_ca_periods - 1;
buffer->tx_time -= (rf_ptr->multi_cca_interval * (rf_ptr->number_of_csma_ca_periods - 1));
}
}
mac_pd_sap_set_phy_tx_time(rf_ptr, buffer->tx_time, cca_enabled);
if (mac_plme_cca_req(rf_ptr) != 0) {
if (buffer->fcf_dsn.frametype == MAC_FRAME_ACK) {

View File

@ -57,6 +57,11 @@ typedef enum {
#define MAC_SAP_TRIG_TX 7
#define MCPS_SAP_DATA_ACK_CNF_EVENT 8
// Default number of CSMA-CA periods
#define MAC_DEFAULT_NUMBER_OF_CSMA_PERIODS 1
// Interval between two CCA checks
#define MAC_DEFAULT_CSMA_MULTI_CCA_INTERVAL 1000
/**
* @brief struct mac_aux_security_header_t MAC auxiliarity security header structure
* INTERNAL use only
@ -126,6 +131,9 @@ typedef struct mac_pre_build_frame {
uint8_t *mac_payload;
uint8_t status;
uint8_t asynch_channel;
uint8_t csma_periods_left;
uint8_t fhss_retry_count;
uint8_t fhss_cca_retry_count;
uint32_t tx_time;
bool upper_layer_request;
bool mac_allocated_payload_ptr: 1;
@ -206,6 +214,6 @@ uint8_t mcps_sap_purge_reg_handler(struct protocol_interface_rf_mac_setup *rf_ma
int8_t mcps_pd_data_rebuild(struct protocol_interface_rf_mac_setup *rf_ptr, mac_pre_build_frame_t *buffer);
int8_t mcps_generic_ack_build(struct protocol_interface_rf_mac_setup *rf_ptr, const mac_fcf_sequence_t *fcf, const uint8_t *data_ptr, const mcps_ack_data_payload_t *ack_payload, uint32_t rx_time);
int8_t mcps_generic_ack_build(struct protocol_interface_rf_mac_setup *rf_ptr, const mac_fcf_sequence_t *fcf, const uint8_t *data_ptr, const mcps_ack_data_payload_t *ack_payload);
#endif /* MAC_IEEE802_15_4_MAC_MCPS_SAP_H_ */

View File

@ -582,7 +582,7 @@ static int8_t mac_mlme_8bit_set(protocol_interface_rf_mac_setup_s *rf_mac_setup,
break;
case macMinBE:
if (value > rf_mac_setup->macMaxBE) {
if (value < rf_mac_setup->macMaxBE) {
rf_mac_setup->macMinBE = value;
}
break;
@ -724,6 +724,16 @@ static int8_t mac_mlme_handle_set_values(protocol_interface_rf_mac_setup_s *rf_m
return -1;
}
static int8_t mac_mlme_set_multi_csma_parameters(protocol_interface_rf_mac_setup_s *rf_mac_setup, const mlme_set_t *set_req)
{
mlme_multi_csma_ca_param_t multi_csma_params;
memcpy(&multi_csma_params, set_req->value_pointer, sizeof(mlme_multi_csma_ca_param_t));
rf_mac_setup->multi_cca_interval = multi_csma_params.multi_cca_interval;
rf_mac_setup->number_of_csma_ca_periods = multi_csma_params.number_of_csma_ca_periods;
tr_debug("Multi CSMA-CA, interval: %u, periods %u", rf_mac_setup->multi_cca_interval, rf_mac_setup->number_of_csma_ca_periods);
return 0;
}
int8_t mac_mlme_set_req(protocol_interface_rf_mac_setup_s *rf_mac_setup, const mlme_set_t *set_req)
{
if (!set_req || !rf_mac_setup || !rf_mac_setup->dev_driver || !rf_mac_setup->dev_driver->phy_driver) {
@ -749,6 +759,8 @@ 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 macMultiCSMAParameters:
return mac_mlme_set_multi_csma_parameters(rf_mac_setup, set_req);
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);
@ -1072,6 +1084,8 @@ protocol_interface_rf_mac_setup_s *mac_mlme_data_base_allocate(uint8_t *mac64, a
entry->mac_interface_id = -1;
entry->dev_driver = dev_driver;
entry->aUnitBackoffPeriod = 20; //This can be different in some Platform 20 comes from 12-symbol turnaround and 8 symbol CCA read
entry->number_of_csma_ca_periods = MAC_DEFAULT_NUMBER_OF_CSMA_PERIODS;
entry->multi_cca_interval = MAC_DEFAULT_CSMA_MULTI_CCA_INTERVAL;
if (mac_sec_mib_init(entry, storage_sizes) != 0) {
mac_mlme_data_base_deallocate(entry);
@ -1140,6 +1154,10 @@ 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;
dev_driver->phy_driver->extension(PHY_EXTENSION_FILTERING_SUPPORT, (uint8_t *)&entry->mac_frame_filters);
if (entry->mac_frame_filters & (1 << MAC_FRAME_VERSION_2)) {
tr_debug("PHY supports 802.15.4-2015 frame filtering");
}
mac_mlme_set_symbol_rate(entry);
//How many 10us ticks backoff period is for waiting 20symbols which is typically 10 bytes time

View File

@ -41,7 +41,7 @@
// Measured 3750us with 1280 byte secured packet from calculating TX time to starting CSMA timer on PHY.
// Typically varies from 500us to several milliseconds depending on packet size and the platform.
// MAC should learn and make this dynamic by sending first few packets with predefined CSMA period.
#define MIN_FHSS_CSMA_PERIOD_US 4000
#define MIN_FHSS_CSMA_PERIOD_US 5000
static int8_t mac_data_interface_tx_done_cb(protocol_interface_rf_mac_setup_s *rf_ptr, phy_link_tx_status_e status, uint8_t cca_retry, uint8_t tx_retry);
static void mac_sap_cca_fail_cb(protocol_interface_rf_mac_setup_s *rf_ptr);
@ -83,6 +83,10 @@ void mac_csma_backoff_start(protocol_interface_rf_mac_setup_s *rf_mac_setup)
uint32_t mac_csma_backoff_get(protocol_interface_rf_mac_setup_s *rf_mac_setup)
{
// Use minimum allowed CSMA-CA for asynch frames
if (rf_mac_setup->active_pd_data_request->asynch_request) {
return MIN_FHSS_CSMA_PERIOD_US;
}
uint8_t backoff = mac_csma_random_backoff_get(rf_mac_setup);
uint32_t backoff_in_us;
//Multiple aUnitBackoffPeriod symbol time
@ -101,6 +105,13 @@ uint32_t mac_csma_backoff_get(protocol_interface_rf_mac_setup_s *rf_mac_setup)
if (backoff_in_us < MIN_FHSS_CSMA_PERIOD_US) {
backoff_in_us += MIN_FHSS_CSMA_PERIOD_US;
}
// Backoff must be long enough to make multiple CCA checks
if (backoff_in_us < (uint32_t)(rf_mac_setup->multi_cca_interval * (rf_mac_setup->number_of_csma_ca_periods - 1))) {
backoff_in_us += ((rf_mac_setup->multi_cca_interval * (rf_mac_setup->number_of_csma_ca_periods - 1)) - backoff_in_us);
}
if (rf_mac_setup->mac_tx_retry) {
backoff_in_us += rf_mac_setup->fhss_api->get_retry_period(rf_mac_setup->fhss_api, rf_mac_setup->active_pd_data_request->DstAddr, rf_mac_setup->dev_driver->phy_driver->phy_MTU);
}
}
return backoff_in_us;
}
@ -199,6 +210,20 @@ int8_t mac_pd_sap_req(protocol_interface_rf_mac_setup_s *rf_mac_setup)
}
/**
* Abort active PHY transmission.
*
* \param rf_mac_setup pointer to MAC.
*
*/
void mac_pd_abort_active_tx(protocol_interface_rf_mac_setup_s *rf_mac_setup)
{
phy_csma_params_t csma_params;
// Set TX time to 0 to abort current transmission
csma_params.backoff_time = 0;
rf_mac_setup->dev_driver->phy_driver->extension(PHY_EXTENSION_SET_CSMA_PARAMETERS, (uint8_t *) &csma_params);
}
/**
* Set PHY TX time.
*
@ -227,6 +252,9 @@ void mac_pd_sap_set_phy_tx_time(protocol_interface_rf_mac_setup_s *rf_mac_setup,
*/
static uint32_t mac_pd_sap_get_phy_rx_time(protocol_interface_rf_mac_setup_s *rf_mac_setup)
{
if (!rf_mac_setup->rf_csma_extension_supported) {
return 0;
}
uint8_t rx_time_buffer[4];
rf_mac_setup->dev_driver->phy_driver->extension(PHY_EXTENSION_READ_RX_TIME, rx_time_buffer);
return common_read_32_bit(rx_time_buffer);
@ -341,6 +369,10 @@ static void mac_sap_no_ack_cb(protocol_interface_rf_mac_setup_s *rf_ptr)
rf_ptr->mac_cca_retry = 0;
rf_ptr->mac_tx_retry++; //Update retry counter
mac_csma_param_init(rf_ptr);
// Increase current backoff exponent when retry count grows
for (int retry_index = rf_ptr->mac_tx_retry; retry_index > 0; retry_index--) {
mac_csma_BE_update(rf_ptr);
}
rf_ptr->mac_tx_status.retry++;
/*Send retry using random interval*/
if (mcps_pd_data_rebuild(rf_ptr, rf_ptr->active_pd_data_request)) {
@ -387,17 +419,17 @@ static int8_t mac_data_interface_tx_done_cb(protocol_interface_rf_mac_setup_s *r
if (status == PHY_LINK_CCA_PREPARE) {
if (rf_ptr->mac_ack_tx_active) {
return 0;
return PHY_TX_ALLOWED;
}
if (mac_data_asynch_channel_switch(rf_ptr, rf_ptr->active_pd_data_request)) {
return 0;
return PHY_TX_ALLOWED;
}
if (rf_ptr->fhss_api) {
mac_pre_build_frame_t *active_buf = rf_ptr->active_pd_data_request;
if (!active_buf) {
return -1;
return PHY_TX_NOT_ALLOWED;
}
// Change to destination channel and write synchronization info to Beacon frames here
@ -408,16 +440,22 @@ static int8_t mac_data_interface_tx_done_cb(protocol_interface_rf_mac_setup_s *r
// When FHSS TX handle returns -1, transmission of the packet is currently not allowed -> restart CCA timer
if (tx_handle_retval == -1) {
mac_sap_cca_fail_cb(rf_ptr);
return -2;
return PHY_TX_NOT_ALLOWED;
}
// When FHSS TX handle returns -3, we are trying to transmit broadcast packet on unicast channel -> push back
// to queue by using CCA fail event
if (tx_handle_retval == -3) {
mac_tx_done_state_set(rf_ptr, MAC_CCA_FAIL);
return -3;
return PHY_TX_NOT_ALLOWED;
} else if (tx_handle_retval == -2) {
mac_tx_done_state_set(rf_ptr, MAC_UNKNOWN_DESTINATION);
return -2;
return PHY_TX_NOT_ALLOWED;
}
if (active_buf->csma_periods_left > 0) {
active_buf->csma_periods_left--;
active_buf->tx_time += rf_ptr->multi_cca_interval;
mac_pd_sap_set_phy_tx_time(rf_ptr, active_buf->tx_time, true);
return PHY_RESTART_CSMA;
}
}
@ -479,6 +517,9 @@ static int8_t mac_data_interface_tx_done_cb(protocol_interface_rf_mac_setup_s *r
mac_sap_cca_fail_cb(rf_ptr);
break;
case PHY_LINK_CCA_OK:
break;
case PHY_LINK_TX_FAIL:
mac_sap_no_ack_cb(rf_ptr);
break;
@ -531,7 +572,7 @@ static int8_t mac_data_interface_tx_done_by_ack_cb(protocol_interface_rf_mac_set
return 0;
}
static bool mac_pd_sap_ack_validation(protocol_interface_rf_mac_setup_s *rf_ptr, mac_fcf_sequence_t *fcf_dsn, const uint8_t *data_ptr)
static bool mac_pd_sap_ack_validation(protocol_interface_rf_mac_setup_s *rf_ptr, const mac_fcf_sequence_t *fcf_dsn, const uint8_t *data_ptr)
{
if (!rf_ptr->active_pd_data_request || !rf_ptr->active_pd_data_request->fcf_dsn.ackRequested) {
return false; //No active Data request anymore or no ACK request for current TX
@ -587,77 +628,133 @@ static bool mac_pd_sap_ack_validation(protocol_interface_rf_mac_setup_s *rf_ptr,
return true;
}
int8_t mac_pd_sap_data_cb(void *identifier, arm_phy_sap_msg_t *message)
static int8_t mac_pd_sap_validate_fcf(protocol_interface_rf_mac_setup_s *rf_ptr, const mac_fcf_sequence_t *fcf_read, arm_pd_sap_generic_ind_t *pd_data_ind)
{
protocol_interface_rf_mac_setup_s *rf_ptr = (protocol_interface_rf_mac_setup_s *)identifier;
mac_pre_parsed_frame_t *buffer = NULL;
if (!rf_ptr || !message) {
return -1;
}
if (!rf_ptr->macUpState) {
return -2;
}
if (message->id == MAC15_4_PD_SAP_DATA_IND) {
const uint8_t *ptr;
arm_pd_sap_generic_ind_t *pd_data_ind = &(message->message.generic_data_ind);
if (pd_data_ind->data_len < 3) {
return -1;
}
ptr = pd_data_ind->data_ptr;
uint32_t time_stamp = 0;
if (rf_ptr->rf_csma_extension_supported) {
time_stamp = mac_pd_sap_get_phy_rx_time(rf_ptr);
}
mac_fcf_sequence_t fcf_read;
ptr = mac_header_parse_fcf_dsn(&fcf_read, ptr);
//Check PanID presents at header
fcf_read.DstPanPresents = mac_dst_panid_present(&fcf_read);
fcf_read.SrcPanPresents = mac_src_panid_present(&fcf_read);
int16_t length = pd_data_ind->data_len;
if (!rf_ptr->macProminousMode) {
//Unsupported Frame
if (fcf_read.frametype > FC_CMD_FRAME || (fcf_read.frametype == FC_ACK_FRAME && fcf_read.frameVersion != MAC_FRAME_VERSION_2015)) {
goto ERROR_HANDLER;
}
switch (fcf_read.frametype) {
switch (fcf_read->frametype) {
case FC_DATA_FRAME:
if (fcf_read.SrcAddrMode == MAC_ADDR_MODE_NONE) {
if (fcf_read->SrcAddrMode == MAC_ADDR_MODE_NONE) {
return -1;
} else if (fcf_read.DstAddrMode == MAC_ADDR_MODE_NONE && fcf_read.frameVersion != MAC_FRAME_VERSION_2015) {
} else if (fcf_read->DstAddrMode == MAC_ADDR_MODE_NONE && fcf_read->frameVersion != MAC_FRAME_VERSION_2015) {
return -1;
}
break;
case FC_BEACON_FRAME:
if (fcf_read.SrcAddrMode == MAC_ADDR_MODE_NONE || fcf_read.DstAddrMode != MAC_ADDR_MODE_NONE) {
if (fcf_read->SrcAddrMode == MAC_ADDR_MODE_NONE || fcf_read->DstAddrMode != MAC_ADDR_MODE_NONE) {
return -1;
}
break;
case FC_ACK_FRAME:
//Validate here that we are waiting ack
if (fcf_read.ackRequested) {
// Only accept version 2015 Acks
if (fcf_read->frameVersion != MAC_FRAME_VERSION_2015) {
return -1;
}
//Validate Ack doesn't request Ack
if (fcf_read->ackRequested) {
return -1;
}
//Validate ACK
if (!mac_pd_sap_ack_validation(rf_ptr, &fcf_read, pd_data_ind->data_ptr)) {
if (!mac_pd_sap_ack_validation(rf_ptr, fcf_read, pd_data_ind->data_ptr)) {
return -1;
}
break;
case FC_CMD_FRAME:
break;
default:
return -1;
}
return 0;
}
static bool mac_pd_sap_panid_filter_common(const uint8_t *mac_header, const mac_fcf_sequence_t *fcf_read, uint16_t own_pan_id)
{
// Beacon frames shouldn't be dropped as they might be used by load balancing
if (fcf_read->frametype == MAC_FRAME_BEACON) {
return true;
}
if (own_pan_id == 0xffff) {
return true;
}
uint16_t dst_pan_id = mac_header_get_dst_panid(fcf_read, mac_header, 0xffff);
if (dst_pan_id == 0xffff) {
return true;
}
if (own_pan_id == dst_pan_id) {
return true;
}
return false;
}
static bool mac_pd_sap_panid_v2_filter(const uint8_t *ptr, const mac_fcf_sequence_t *fcf_read, uint16_t pan_id)
{
if ((fcf_read->DstAddrMode == MAC_ADDR_MODE_NONE) && (fcf_read->frametype == FC_DATA_FRAME || fcf_read->frametype == FC_CMD_FRAME)) {
return true;
}
if ((fcf_read->DstAddrMode == MAC_ADDR_MODE_64_BIT) && (fcf_read->SrcAddrMode == MAC_ADDR_MODE_64_BIT) && fcf_read->intraPan) {
return true;
}
return mac_pd_sap_panid_filter_common(ptr, fcf_read, pan_id);
}
static bool mac_pd_sap_addr_filter_common(const uint8_t *mac_header, const mac_fcf_sequence_t *fcf_read, uint8_t *mac_64bit_addr, uint16_t mac_16bit_addr)
{
uint8_t cmp_table[8] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
uint8_t dst_addr[8];
mac_header_get_dst_address(fcf_read, mac_header, dst_addr);
switch (fcf_read->DstAddrMode) {
case MAC_ADDR_MODE_16_BIT:
if (!memcmp(dst_addr, cmp_table, 2)) {
return true;
}
uint8_t temp[2];
common_write_16_bit(mac_16bit_addr, temp);
if (!memcmp(temp, dst_addr, 2)) {
return true;
}
break;
case MAC_ADDR_MODE_64_BIT:
if (!memcmp(dst_addr, cmp_table, 8)) {
return true;
}
if (!memcmp(mac_64bit_addr, dst_addr, 8)) {
return true;
}
break;
case MAC_ADDR_MODE_NONE:
return true;
break;
default:
break;
}
return false;
}
//Generate ACK when Extension is enabled and ACK is requested
if (rf_ptr->mac_extension_enabled && fcf_read.ackRequested && fcf_read.frameVersion == MAC_FRAME_VERSION_2015) {
//SEND ACK here
static bool mac_pd_sap_addr_v2_filter(const uint8_t *mac_header, const mac_fcf_sequence_t *fcf_read, uint8_t *mac_64bit_addr, uint16_t mac_16bit_addr)
{
return mac_pd_sap_addr_filter_common(mac_header, fcf_read, mac_64bit_addr, mac_16bit_addr);
}
static bool mac_pd_sap_rx_filter(const uint8_t *mac_header, const mac_fcf_sequence_t *fcf_read, uint8_t phy_filter_mask, uint8_t *mac_64bit_addr, uint16_t mac_16bit_addr, uint16_t pan_id)
{
uint8_t version = fcf_read->frameVersion;
if (version == MAC_FRAME_VERSION_2015 && !(phy_filter_mask & (1 << MAC_FRAME_VERSION_2))) {
if (!mac_pd_sap_panid_v2_filter(mac_header, fcf_read, pan_id)) {
return false;
}
if (!mac_pd_sap_addr_v2_filter(mac_header, fcf_read, mac_64bit_addr, mac_16bit_addr)) {
return false;
}
}
return true;
}
static int8_t mac_pd_sap_generate_ack(protocol_interface_rf_mac_setup_s *rf_ptr, const mac_fcf_sequence_t *fcf_read, arm_pd_sap_generic_ind_t *pd_data_ind)
{
//Generate ACK when Extension is enabled and ACK is requested only for version 2 frames.
if (!rf_ptr->mac_extension_enabled || !fcf_read->ackRequested || (fcf_read->frameVersion != MAC_FRAME_VERSION_2015)) {
return 0;
}
if (rf_ptr->mac_ack_tx_active) {
return -1;
}
@ -667,48 +764,38 @@ int8_t mac_pd_sap_data_cb(void *identifier, arm_phy_sap_msg_t *message)
mac_api->enhanced_ack_data_req_cb(mac_api, &ack_payload, pd_data_ind->dbm, pd_data_ind->link_quality);
//Calculate Delta time
if (mcps_generic_ack_build(rf_ptr, &fcf_read, pd_data_ind->data_ptr, &ack_payload, time_stamp) != 0) {
return -1;
}
}
}
buffer = mcps_sap_pre_parsed_frame_buffer_get(pd_data_ind->data_ptr, pd_data_ind->data_len);
return mcps_generic_ack_build(rf_ptr, fcf_read, pd_data_ind->data_ptr, &ack_payload);
}
static mac_pre_parsed_frame_t *mac_pd_sap_allocate_receive_buffer(protocol_interface_rf_mac_setup_s *rf_ptr, const mac_fcf_sequence_t *fcf_read, arm_pd_sap_generic_ind_t *pd_data_ind)
{
mac_pre_parsed_frame_t *buffer = mcps_sap_pre_parsed_frame_buffer_get(pd_data_ind->data_ptr, pd_data_ind->data_len);
if (!buffer) {
sw_mac_stats_update(rf_ptr, STAT_MAC_RX_DROP, 0);
return -3;
return NULL;
}
//Copy Pre Parsed values
buffer->fcf_dsn = fcf_read;
buffer->timestamp = time_stamp;
buffer->fcf_dsn = *fcf_read;
buffer->timestamp = mac_pd_sap_get_phy_rx_time(rf_ptr);
buffer->ack_pendinfg_status = mac_data_interface_read_last_ack_pending_status(rf_ptr);
// Upward direction functions assume no headroom and are trusting that removed bytes are still valid.
// see mac.c:655
/* Set default flags */
buffer->dbm = pd_data_ind->dbm;
buffer->LQI = pd_data_ind->link_quality;
buffer->mac_class_ptr = rf_ptr;
//Dnamic calculation for FCF + SEQ parse
buffer->mac_header_length = ptr - pd_data_ind->data_ptr;
if (!rf_ptr->macProminousMode) {
return buffer;
}
static int8_t mac_pd_sap_parse_length_fields(mac_pre_parsed_frame_t *buffer, arm_pd_sap_generic_ind_t *pd_data_ind, const uint8_t *parse_ptr)
{
if (buffer->fcf_dsn.frametype > FC_CMD_FRAME) {
goto ERROR_HANDLER;
return -1;
}
buffer->mac_header_length = parse_ptr - pd_data_ind->data_ptr;
int16_t length = pd_data_ind->data_len;
buffer->mac_header_length += mac_header_address_length(&buffer->fcf_dsn);
length -= buffer->mac_header_length;
if (length < 0) {
goto ERROR_HANDLER;
return -1;
}
buffer->mac_payload_length = (buffer->frameLength - buffer->mac_header_length);
@ -747,38 +834,80 @@ int8_t mac_pd_sap_data_cb(void *identifier, arm_phy_sap_msg_t *message)
//Verify that data length is not negative
if (length < 0) {
goto ERROR_HANDLER;
return -1;
}
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;
if (buffer->fcf_dsn.frametype == FC_CMD_FRAME && length == 0) {
return -1;
}
return 0;
}
int8_t mac_pd_sap_data_cb(void *identifier, arm_phy_sap_msg_t *message)
{
protocol_interface_rf_mac_setup_s *rf_ptr = (protocol_interface_rf_mac_setup_s *)identifier;
if (!rf_ptr || !message) {
return -1;
}
//Parse IE Elements
if (!rf_ptr->macUpState) {
return -2;
}
if (message->id == MAC15_4_PD_SAP_DATA_IND) {
arm_pd_sap_generic_ind_t *pd_data_ind = &(message->message.generic_data_ind);
if (pd_data_ind->data_len < 3) {
return -1;
}
mac_fcf_sequence_t fcf_read;
const uint8_t *ptr = mac_header_parse_fcf_dsn(&fcf_read, pd_data_ind->data_ptr);
mac_pre_parsed_frame_t *buffer = mac_pd_sap_allocate_receive_buffer(rf_ptr, &fcf_read, pd_data_ind);
if (buffer && mac_filter_modify_link_quality(rf_ptr->mac_interface_id, buffer) == 1) {
goto ERROR_HANDLER;
}
if (!rf_ptr->macProminousMode) {
if (mac_pd_sap_validate_fcf(rf_ptr, &fcf_read, pd_data_ind)) {
goto ERROR_HANDLER;
}
if (!mac_pd_sap_rx_filter(pd_data_ind->data_ptr, &fcf_read, rf_ptr->mac_frame_filters, rf_ptr->mac64, rf_ptr->mac_short_address, rf_ptr->pan_id)) {
goto ERROR_HANDLER;
}
if (mac_pd_sap_generate_ack(rf_ptr, &fcf_read, pd_data_ind)) {
goto ERROR_HANDLER;
}
if (buffer) {
if (mac_pd_sap_parse_length_fields(buffer, pd_data_ind, ptr)) {
goto ERROR_HANDLER;
}
if (!mac_header_information_elements_parse(buffer)) {
goto ERROR_HANDLER;
}
}
if (!rf_ptr->macProminousMode && buffer->fcf_dsn.frametype == FC_ACK_FRAME) {
if (buffer->fcf_dsn.frametype == FC_ACK_FRAME) {
if (mac_data_interface_tx_done_by_ack_cb(rf_ptr, buffer)) {
mcps_sap_pre_parsed_frame_buffer_free(buffer);
}
return 0;
} else {
}
}
}
if (!buffer) {
sw_mac_stats_update(rf_ptr, STAT_MAC_RX_DROP, 0);
return -3;
}
if (mcps_sap_pd_ind(buffer) == 0) {
return 0;
}
}
ERROR_HANDLER:
mcps_sap_pre_parsed_frame_buffer_free(buffer);
sw_mac_stats_update(rf_ptr, STAT_MAC_RX_DROP, 0);
return -1;
} else if (message->id == MAC15_4_PD_SAP_DATA_TX_CONFIRM) {
arm_pd_sap_15_4_confirm_with_params_t *pd_data_cnf = &(message->message.mac15_4_pd_sap_confirm);
return mac_data_interface_tx_done_cb(rf_ptr, pd_data_cnf->status, pd_data_cnf->cca_retry, pd_data_cnf->tx_retry);

View File

@ -39,6 +39,8 @@ int8_t mac_pd_sap_req(struct protocol_interface_rf_mac_setup *rf_mac_setup);
int8_t mac_plme_cca_req(struct protocol_interface_rf_mac_setup *rf_mac_setup);
void mac_pd_abort_active_tx(struct protocol_interface_rf_mac_setup *rf_mac_setup);
void mac_pd_sap_set_phy_tx_time(struct protocol_interface_rf_mac_setup *rf_mac_setup, uint32_t tx_time, bool cca_enabled);
void mac_pd_sap_rf_low_level_function_set(void *mac_ptr, void *driver);

View File

@ -33,6 +33,7 @@
#include "Service_Libs/Trickle/trickle.h"
#include "6LoWPAN/MAC/mac_helper.h"
#include "6LoWPAN/Thread/thread_common.h"
#include "6LoWPAN/ws/ws_common.h"
#include "MPL/mpl.h"
#define TRACE_GROUP "mpl"
@ -1105,7 +1106,8 @@ static buffer_t *mpl_exthdr_provider(buffer_t *buf, ipv6_exthdr_stage_t stage, i
/* "Compress" seed ID if it's the IPv6 source address */
/* (For Thread, also compress if source is the 16-bit address) */
if (seed_id_len == 16 && addr_ipv6_equal(seed_id, buf->src_sa.address)) {
/* (For Wi-sun, not support seed id address compression */
if (!ws_info(buf->interface) && seed_id_len == 16 && addr_ipv6_equal(seed_id, buf->src_sa.address)) {
seed_id_len = 0;
} else if (seed_id_len == 2 && thread_addr_is_mesh_local_16(buf->src_sa.address, buf->interface) &&
seed_id[0] == buf->src_sa.address[14] && seed_id[1] == buf->src_sa.address[15]) {

View File

@ -121,6 +121,7 @@ typedef enum icmp_state {
ER_BOOTSTRAP_SCAN_FAIL,
ER_BOOTSTRAP_LEADER_UP,
ER_BOOTSTRAP_NEW_FRAGMENT_START,
ER_WAIT_RESTART,
ER_RPL_LOCAL_REPAIR,
} icmp_state_t;
@ -514,4 +515,5 @@ extern void protocol_core_dhcpv6_allocated_address_remove(protocol_interface_inf
extern void nwk_bootsrap_state_update(arm_nwk_interface_status_type_e posted_event, protocol_interface_info_entry_t *cur);
void bootsrap_next_state_kick(icmp_state_t new_state, protocol_interface_info_entry_t *cur);
int8_t protocol_interface_address_compare(const uint8_t *addr);
bool protocol_interface_any_address_match(const uint8_t *prefix, uint8_t prefix_len);
#endif /* _NS_PROTOCOL_H */

View File

@ -81,6 +81,7 @@
#include "6LoWPAN/Fragmentation/cipv6_fragmenter.h"
#include "Service_Libs/load_balance/load_balance_api.h"
#include "Service_Libs/pan_blacklist/pan_blacklist_api.h"
#include "Service_Libs/etx/etx.h"
#include "mac_api.h"
#include "ethernet_mac_api.h"
@ -260,6 +261,7 @@ void core_timer_event_handle(uint16_t ticksUpdate)
if (cur->nwk_wpan_nvm_api) {
cur->nwk_wpan_nvm_api->nvm_params_update_cb(cur->nwk_wpan_nvm_api, false);
}
etx_cache_timer(cur->id, seconds);
}
} else if (cur->nwk_id == IF_IPV6) {
//Slow Pointer Update
@ -300,6 +302,9 @@ void core_timer_event_handle(uint16_t ticksUpdate)
ipv6_destination_cache_timer(seconds);
ipv6_frag_timer(seconds);
cipv6_frag_timer(seconds);
#ifdef HAVE_WS
ws_pae_controller_slow_timer(seconds);
#endif
protocol_6lowpan_mle_timer(seconds);
/* This limit bad behaviour device's MLE link reject generation */
@ -339,7 +344,7 @@ void core_timer_event_handle(uint16_t ticksUpdate)
icmpv6_radv_timer(ticksUpdate);
protocol_core_security_tick_update(ticksUpdate);
#ifdef HAVE_WS
ws_pae_controller_timer(ticksUpdate);
ws_pae_controller_fast_timer(ticksUpdate);
#endif
platform_enter_critical();
protocol_core_timer_info.core_timer_event = false;
@ -1135,3 +1140,27 @@ int8_t protocol_interface_address_compare(const uint8_t *addr)
return -1;
}
static bool protocol_address_prefix_cmp(protocol_interface_info_entry_t *interface, const uint8_t *prefix, uint8_t prefix_len)
{
ns_list_foreach(if_address_entry_t, adr, &interface->ip_addresses) {
if (bitsequal(adr->address, prefix, prefix_len)) {
/* Prefix stil used at list so stop checking */
return true;
}
}
return false;
}
bool protocol_interface_any_address_match(const uint8_t *prefix, uint8_t prefix_len)
{
ns_list_foreach(protocol_interface_info_entry_t, cur, &protocol_interface_info_list) {
if (protocol_address_prefix_cmp(cur, prefix, prefix_len)) {
return true;
}
}
return false;
}

View File

@ -151,17 +151,6 @@ static void rpl_control_publish_own_addresses(rpl_domain_t *domain, rpl_instance
}
}
static void rpl_control_publish_own_address(rpl_domain_t *domain, const if_address_entry_t *addr)
{
ns_list_foreach(rpl_instance_t, instance, &domain->instances) {
if (!rpl_instance_am_root(instance)) {
uint32_t descriptor = 0;
bool want_descriptor = rpl_policy_target_descriptor_for_own_address(domain, addr->address, addr->source, addr->data, &descriptor);
rpl_instance_publish_dao_target(instance, addr->address, 128, addr->valid_lifetime, true, want_descriptor, descriptor);
}
}
}
void rpl_control_publish_host_address(rpl_domain_t *domain, const uint8_t addr[16], uint32_t lifetime)
{
ns_list_foreach(rpl_instance_t, instance, &domain->instances) {
@ -260,10 +249,6 @@ static void rpl_control_addr_notifier(struct protocol_interface_info_entry *inte
}
switch (reason) {
case ADDR_CALLBACK_DAD_COMPLETE:
case ADDR_CALLBACK_REFRESHED:
rpl_control_publish_own_address(interface->rpl_domain, addr);
break;
case ADDR_CALLBACK_DELETED:
rpl_control_unpublish_address(interface->rpl_domain, addr->address);
break;
@ -345,11 +330,7 @@ void rpl_control_set_domain_on_interface(protocol_interface_info_entry_t *cur, r
cur->rpl_domain = domain;
addr_add_group(cur, ADDR_LINK_LOCAL_ALL_RPL_NODES);
}
ns_list_foreach(if_address_entry_t, addr, &cur->ip_addresses) {
if (!addr_is_ipv6_link_local(addr->address)) {
rpl_control_publish_own_address(domain, addr);
}
}
if (downstream) {
domain->non_storing_downstream_interface = cur->id;
}
@ -690,8 +671,9 @@ static void rpl_control_process_prefix_options(protocol_interface_info_entry_t *
bool router_addr_set = false;
rpl_neighbour_t *pref_parent = rpl_instance_preferred_parent(instance);
// const rpl_dodag_conf_t *conf = rpl_dodag_get_config(dodag);
if (neighbour == pref_parent) {
rpl_dodag_update_unpublished_dio_prefix_start(dodag);
}
for (;;) {
const uint8_t *ptr = rpl_control_find_option(start, end - start, RPL_PREFIX_INFO_OPTION, 30);
@ -735,6 +717,9 @@ static void rpl_control_process_prefix_options(protocol_interface_info_entry_t *
start = ptr + 32;
}
if (neighbour == pref_parent) {
rpl_dodag_update_unpublished_dio_prefix_finish(dodag);
}
}
void rpl_control_process_prefix_option(prefix_entry_t *prefix, protocol_interface_info_entry_t *cur)
@ -894,10 +879,6 @@ malformed:
if (!instance) {
return buffer_free(buf);
}
if ((g_mop_prf & RPL_MODE_MASK) != RPL_MODE_NO_DOWNWARD) {
rpl_control_publish_own_addresses(domain, instance);
}
}
/* Lookup any existing neighbour entry */
@ -1156,7 +1137,7 @@ void rpl_control_transmit_dio(rpl_domain_t *domain, protocol_interface_info_entr
} else {
prefix->options &= ~ PIO_R;
if (rpl_dodag_mop(dodag) == RPL_MODE_NON_STORING) {
if (rpl_dodag_mop(dodag) == RPL_MODE_NON_STORING && prefix->lifetime != 0) {
continue;
}
}
@ -1194,7 +1175,7 @@ void rpl_control_transmit_dio(rpl_domain_t *domain, protocol_interface_info_entr
ns_list_foreach_safe(prefix_entry_t, prefix, prefixes) {
/* See equivalent checks in length calculation above */
if ((prefix->options & (PIO_L | RPL_PIO_PUBLISHED)) == PIO_L ||
(!(prefix->options & PIO_R) && rpl_dodag_mop(dodag) == RPL_MODE_NON_STORING)) {
(!(prefix->options & PIO_R) && rpl_dodag_mop(dodag) == RPL_MODE_NON_STORING && prefix->lifetime != 0)) {
continue;
}
@ -1207,6 +1188,14 @@ void rpl_control_transmit_dio(rpl_domain_t *domain, protocol_interface_info_entr
common_write_32_bit(0, ptr + 12); // reserved
memcpy(ptr + 16, prefix->prefix, 16);
ptr += 32;
/* Transmitting a multicast DIO decrements the hold count for 0 lifetime prefixes */
if (dst == NULL && (prefix->options & RPL_PIO_AGE)) {
int hold_count = prefix->options & RPL_PIO_HOLD_MASK;
if (hold_count) {
hold_count--;
prefix->options = (prefix->options & ~RPL_PIO_HOLD_MASK) | hold_count;
}
}
}
ns_list_foreach_safe(rpl_dio_route_t, route, routes) {
@ -1616,6 +1605,7 @@ void rpl_control_slow_timer(uint16_t seconds)
ns_list_foreach(rpl_domain_t, domain, &rpl_domains) {
ns_list_foreach_safe(rpl_instance_t, instance, &domain->instances) {
rpl_control_publish_own_addresses(domain, instance);
rpl_instance_slow_timer(instance, seconds);
rpl_downward_dao_slow_timer(instance, seconds);
/* We purge one item from each instance, so as not to favour one domain or instance */
@ -1654,13 +1644,14 @@ rpl_instance_t *rpl_control_lookup_instance(rpl_domain_t *domain, uint8_t instan
return rpl_lookup_instance(domain, instance_id, dodagid);
}
bool rpl_control_get_instance_dao_target_count(rpl_domain_t *domain, uint8_t instance_id, const uint8_t *dodagid, uint16_t *target_count)
bool rpl_control_get_instance_dao_target_count(rpl_domain_t *domain, uint8_t instance_id, const uint8_t *dodagid, const uint8_t *prefix, uint16_t *target_count)
{
rpl_instance_t *instance = rpl_lookup_instance(domain, instance_id, dodagid);
if (!instance) {
return false;
}
*target_count = rpl_upward_read_dao_target_list_size(instance);
*target_count = rpl_upward_read_dao_target_list_size(instance, prefix);
return true;
}

View File

@ -160,7 +160,7 @@ void rpl_control_print(route_print_fn_t *print_fn);
struct rpl_instance *rpl_control_enumerate_instances(rpl_domain_t *domain, struct rpl_instance *instance);
struct rpl_instance *rpl_control_lookup_instance(rpl_domain_t *domain, uint8_t instance_id, const uint8_t *dodagid);
bool rpl_control_get_instance_dao_target_count(rpl_domain_t *domain, uint8_t instance_id, const uint8_t *dodagid, uint16_t *target_count);
bool rpl_control_get_instance_dao_target_count(rpl_domain_t *domain, uint8_t instance_id, const uint8_t *dodagid, const uint8_t *prefix, uint16_t *target_count);
bool rpl_control_read_dodag_info(const struct rpl_instance *instance, struct rpl_dodag_info_t *dodag_info);
const rpl_dodag_conf_t *rpl_control_get_dodag_config(const struct rpl_instance *instance);
const uint8_t *rpl_control_preferred_parent_addr(const struct rpl_instance *instance, bool global);

View File

@ -345,8 +345,9 @@ void rpl_instance_publish_dao_target(rpl_instance_t *instance, const uint8_t *pr
{
rpl_dao_target_t *target = rpl_instance_lookup_published_dao_target(instance, prefix, prefix_len);
if (target) {
int diff = target->lifetime > valid_lifetime ? target->lifetime - valid_lifetime : valid_lifetime - target->lifetime;
target->lifetime = valid_lifetime;
if (!own) {
if (!own && diff > 60) {
/* For non-owned targets, publish triggers a refresh */
rpl_downward_target_refresh(target);
rpl_instance_dao_trigger(instance, 0);
@ -590,7 +591,7 @@ void rpl_instance_send_address_registration(protocol_interface_info_entry_t *int
aro.status = ARO_SUCCESS;
aro.present = true;
aro.lifetime = addr->valid_lifetime;
aro.lifetime = (addr->valid_lifetime / 60) + 1;
memcpy(aro.eui64, interface->mac, 8);
// go through neighbour list, and send to all assigned parents.

View File

@ -932,6 +932,33 @@ const prefix_list_t *rpl_dodag_get_prefix_list(const rpl_dodag_t *dodag)
{
return &dodag->prefixes;
}
/* Called before updating all prefixes in a DIO */
void rpl_dodag_update_unpublished_dio_prefix_start(rpl_dodag_t *dodag)
{
/* Clear age flags - will use as a marker for entries being in the DIO */
ns_list_foreach(prefix_entry_t, entry, &dodag->prefixes) {
if (!(entry->options & RPL_PIO_PUBLISHED)) {
entry->options &= ~RPL_PIO_AGE;
}
}
}
/* Called after updating all prefixes in a DIO */
void rpl_dodag_update_unpublished_dio_prefix_finish(rpl_dodag_t *dodag)
{
/* Any remaining non-published entries that don't have the age flag
* set are not being sent by parent any more, so we should stop sending
* too, except for the minimimum count requirement on 0 lifetime.
*/
ns_list_foreach_safe(prefix_entry_t, entry, &dodag->prefixes) {
if ((entry->options & (RPL_PIO_PUBLISHED | RPL_PIO_AGE | RPL_PIO_HOLD_MASK)) == 0) {
rpl_dodag_delete_dio_prefix(dodag, entry);
}
}
}
prefix_entry_t *rpl_dodag_update_dio_prefix(rpl_dodag_t *dodag, const uint8_t *prefix, uint8_t prefix_len, uint8_t flags, uint32_t lifetime, uint32_t preftime, bool publish, bool age)
{
/* Don't let them set funny flags - we won't propagate them either.
@ -948,20 +975,30 @@ prefix_entry_t *rpl_dodag_update_dio_prefix(rpl_dodag_t *dodag, const uint8_t *p
flags |= RPL_PIO_AGE;
}
if (lifetime == 0) {
flags |= RPL_MAX_FINAL_RTR_ADVERTISEMENTS;
}
prefix_entry_t *entry = icmpv6_prefix_add(&dodag->prefixes, prefix, prefix_len, lifetime, preftime, flags);
prefix_entry_t *entry = icmpv6_prefix_add(&dodag->prefixes, prefix, prefix_len, lifetime, preftime, 0xff);
/* icmpv6_prefix_add indicates a new entry by leaving options set to 0xFF */
if (entry) {
/* Newly-seen zero lifetimes should be advertised at least a few times -
* count this down in the RPL_PIO_HOLD_COUNT field
*/
if (lifetime == 0 && (entry->options == 0xFF || entry->lifetime != 0)) {
flags |= RPL_MAX_FINAL_RTR_ADVERTISEMENTS;
}
entry->options = flags;
entry->lifetime = lifetime;
entry->preftime = preftime;
}
return entry;
}
void rpl_dodag_delete_dio_prefix(rpl_dodag_t *dodag, prefix_entry_t *prefix)
{
rpl_instance_t *instance = dodag->instance;
if (instance && instance->domain->prefix_cb) {
instance->domain->prefix_cb(prefix, instance->domain->cb_handle, NULL);
}
ns_list_remove(&dodag->prefixes, prefix);
ns_dyn_mem_free(prefix);
}
@ -984,7 +1021,11 @@ static void rpl_dodag_age_prefixes(rpl_dodag_t *dodag, uint16_t seconds)
prefix->lifetime -= seconds;
} else {
prefix->lifetime = 0;
if ((prefix->options & RPL_PIO_HOLD_MASK) == 0) {
/* Only delete on timeout if we're publishing - otherwise we will
* keep advertising until we see our parent stop advertising it - deletion
* is handled in rpl_control_process_prefix_options.
*/
if ((prefix->options & (RPL_PIO_PUBLISHED | RPL_PIO_HOLD_MASK)) == RPL_PIO_PUBLISHED) {
rpl_dodag_delete_dio_prefix(dodag, prefix);
}
}
@ -1742,8 +1783,19 @@ void rpl_upward_print_instance(rpl_instance_t *instance, route_print_fn_t *print
}
}
uint16_t rpl_upward_read_dao_target_list_size(const rpl_instance_t *instance)
uint16_t rpl_upward_read_dao_target_list_size(const rpl_instance_t *instance, const uint8_t *target_prefix)
{
if (target_prefix) {
uint16_t registered_address_count = 0;
ns_list_foreach(rpl_dao_target_t, target, &instance->dao_targets) {
if (bitsequal(target->prefix, target_prefix, 64)) {
registered_address_count++;
}
}
return registered_address_count;
}
return ns_list_count(&instance->dao_targets);
}

View File

@ -112,6 +112,8 @@ rpl_dio_route_t *rpl_dodag_update_dio_route(rpl_dodag_t *dodag, const uint8_t *p
void rpl_dodag_delete_dio_route(rpl_dodag_t *dodag, rpl_dio_route_t *route);
const rpl_dio_route_list_t *rpl_dodag_get_route_list(const rpl_dodag_t *dodag);
void rpl_dodag_update_unpublished_dio_prefix_start(rpl_dodag_t *dodag);
void rpl_dodag_update_unpublished_dio_prefix_finish(rpl_dodag_t *dodag);
prefix_entry_t *rpl_dodag_update_dio_prefix(rpl_dodag_t *dodag, const uint8_t *prefix, uint8_t prefix_len, uint8_t flags, uint32_t lifetime, uint32_t preftime, bool publish, bool age);
void rpl_dodag_delete_dio_prefix(rpl_dodag_t *dodag, prefix_entry_t *prefix);
const prefix_list_t *rpl_dodag_get_prefix_list(const rpl_dodag_t *dodag);
@ -143,5 +145,5 @@ void rpl_instance_run_parent_selection(rpl_instance_t *instance);
void rpl_upward_print_instance(rpl_instance_t *instance, route_print_fn_t *print_fn);
bool rpl_upward_read_dodag_info(const rpl_instance_t *instance, struct rpl_dodag_info_t *dodag_info);
uint16_t rpl_upward_read_dao_target_list_size(const rpl_instance_t *instance);
uint16_t rpl_upward_read_dao_target_list_size(const rpl_instance_t *instance, const uint8_t *target_prefix);
#endif /* RPL_UPWARD_H_ */

View File

@ -1161,7 +1161,7 @@ buffer_t *tls_client_up(buffer_t *buf, sec_suite_t *tls_suite)
if (tls_header_ptr) {
if (tls_header_ptr->type == TLS_HANDSHAKE && (tls_heap != 0)) {
tr_debug("Type:Handshake");
if ((tls_suite->state == TLS_CHANGE_CHIPHER)) {
if (tls_suite->state == TLS_CHANGE_CHIPHER) {
if (tls_header_ptr->length < 32) {
tr_debug("Too short Chiher Text");
} else if ((algo_ok & 0x20) && (tls_suite->state == PRF_CALC)) {
@ -1477,7 +1477,7 @@ buffer_t *tls_server_up(buffer_t *buf, sec_suite_t *tls_suite)
if (tls_header_ptr) {
if (tls_header_ptr->type == TLS_HANDSHAKE && (tls_heap != 0)) {
tr_debug("Type:Handshake");
if ((tls_suite->state == TLS_CHANGE_CHIPHER)) {
if (tls_suite->state == TLS_CHANGE_CHIPHER) {
if (tls_header_ptr->length < 32) {
tr_debug("Too short Chiher Text");
} else if ((algo_ok & 0x20) && (tls_suite->state == PRF_CALC)) {

View File

@ -274,5 +274,25 @@ uint16_t eapol_pdu_key_frame_init(eapol_pdu_t *eapol_pdu, uint16_t data_length,
}
uint8_t eapol_pdu_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;
}
#endif

View File

@ -23,6 +23,7 @@
#define EAPOL_KEY_TYPE 3
#define EAPOL_KEY_NONCE_LEN 32
#define EAPOL_KEY_MIC_LEN 16
#define EAPOL_KEY_LEN 16
#define EAPOL_BASE_LENGTH 4 //Protocol version 1 byte, Packet type 1 byte, packet length 2 byte
@ -96,4 +97,18 @@ uint16_t eapol_pdu_key_frame_init(eapol_pdu_t *eapol_pdu, uint16_t data_length,
void eapol_write_key_packet_mic(uint8_t *eapol_pdu, uint8_t *mic);
#define KEY_INFO_INSTALL 0x01
#define KEY_INFO_KEY_ACK 0x02
#define KEY_INFO_KEY_MIC 0x04
#define KEY_INFO_SECURED_KEY_FRAME 0x08
/**
* eapol_pdu_key_mask_get gets masked EAPOL-Key message bits
*
* \param eapol_pdu EAPOL PDU
*
* \return mask
*/
uint8_t eapol_pdu_key_mask_get(eapol_pdu_t *eapol_pdu);
#endif /* EAPOL_HELPER_H_ */

View File

@ -45,7 +45,8 @@ struct kmp_api_s {
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 */
bool timer_start_pending : 1; /**< Timer is pending to start */
bool receive_disable : 1; /**< Receiving disabled, do not route messages anymore */
sec_prot_t sec_prot; /**< Security protocol interface */
};
@ -88,6 +89,7 @@ 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);
static void kmp_sec_prot_receive_disable(sec_prot_t *prot);
#define kmp_api_get_from_prot(prot) (kmp_api_t *)(((uint8_t *)prot) - offsetof(kmp_api_t, sec_prot));
@ -126,6 +128,7 @@ kmp_api_t *kmp_api_create(kmp_service_t *service, kmp_type_e type)
kmp->addr = 0;
kmp->service = service;
kmp->timer_start_pending = false;
kmp->receive_disable = false;
memset(&kmp->sec_prot, 0, sec_size);
@ -140,6 +143,7 @@ kmp_api_t *kmp_api_create(kmp_service_t *service, kmp_type_e type)
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;
kmp->sec_prot.receive_disable = kmp_sec_prot_receive_disable;
if (sec_prot->init(&kmp->sec_prot) < 0) {
ns_dyn_mem_free(kmp);
@ -279,6 +283,12 @@ static sec_prot_t *kmp_sec_prot_by_type_get(sec_prot_t *prot, uint8_t type)
return &kmp_by_type->sec_prot;
}
static void kmp_sec_prot_receive_disable(sec_prot_t *prot)
{
kmp_api_t *kmp = kmp_api_get_from_prot(prot);
kmp->receive_disable = true;
}
void kmp_api_delete(kmp_api_t *kmp)
{
if (kmp->sec_prot.delete) {
@ -312,9 +322,9 @@ kmp_type_e kmp_api_type_from_id_get(uint8_t kmp_id)
case IEEE_802_11_4WH:
return IEEE_802_11_4WH;
case IEEE_802_11_GKH:
return IEEE_802_1X_MKA;
return IEEE_802_11_GKH;
default:
return INVALID_KMP_TYPE;
return KMP_TYPE_NONE;
}
}
@ -426,6 +436,11 @@ int8_t kmp_service_msg_if_receive(kmp_service_t *service, kmp_type_e type, const
return -1;
}
// Security protocol has disables message receiving
if (kmp->receive_disable) {
return -1;
}
int8_t ret = kmp->sec_prot.receive(&kmp->sec_prot, pdu, size);
return ret;
}

View File

@ -29,7 +29,7 @@
*/
typedef enum {
INVALID_KMP_TYPE = 0,
KMP_TYPE_NONE = 0,
IEEE_802_1X_MKA = 1,
IEEE_802_11_4WH = 6,

View File

@ -151,7 +151,7 @@ int8_t kmp_eapol_pdu_if_receive(protocol_interface_info_entry_t *interface_ptr,
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) {
if (type == KMP_TYPE_NONE) {
return -1;
}

View File

@ -180,7 +180,7 @@ static void kmp_socket_if_socket_cb(void *ptr)
data_ptr += 8;
kmp_type_e type = kmp_api_type_from_id_get(*data_ptr++);
if (type == INVALID_KMP_TYPE) {
if (type == KMP_TYPE_NONE) {
ns_dyn_mem_free(pdu);
return;
}

View File

@ -60,6 +60,7 @@ typedef struct {
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 recv_eap_id_seq; /**< Last received EAP sequence */
uint8_t eap_code; /**< Received EAP code */
uint8_t eap_type; /**< Received EAP type */
int8_t tls_result; /**< Result of TLS operation */
@ -72,7 +73,7 @@ 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
.TimerExpirations = 2
};
static uint16_t auth_eap_tls_sec_prot_size(void);
@ -129,6 +130,7 @@ static int8_t auth_eap_tls_sec_prot_init(sec_prot_t *prot)
data->tls_prot = NULL;
data->eap_id_seq = 0;
data->recv_eap_id_seq = 0;
data->eap_code = 0;
data->eap_type = 0;
eap_tls_sec_prot_lib_message_init(&data->tls_recv);
@ -188,21 +190,32 @@ static int8_t auth_eap_tls_sec_prot_message_handle(sec_prot_t *prot)
uint16_t length = data->recv_eapol_pdu.msg.eap.length;
bool new_seq_id = false;
bool old_seq_id = false;
// Already received sequence ID is received again, ignore
if (data->recv_eapol_pdu.msg.eap.id_seq < data->eap_id_seq) {
old_seq_id = true;
} else if (data->recv_eapol_pdu.msg.eap.id_seq == data->eap_id_seq) {
// Confirmation that supplicant has received the message, proceed with protocol
if (data->recv_eapol_pdu.msg.eap.id_seq == data->eap_id_seq) {
data->recv_eap_id_seq = 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],
tr_info("EAP-TLS: recv %s type %s id %i flags %x len %i, eui-64 %s", eap_msg_trace[data->eap_code - 1],
data->eap_type == EAP_IDENTITY ? "IDENTITY" : "TLS", data->recv_eapol_pdu.msg.eap.id_seq,
length >= 6 ? data_ptr[0] : 0, length);
length >= 6 ? data_ptr[0] : 0, length, trace_array(sec_prot_remote_eui_64_addr_get(prot), 8));
if (old_seq_id) {
return EAP_TLS_MSG_DECODE_ERROR;
}
if (data->eap_type == EAP_IDENTITY) {
return EAP_TLS_MSG_IDENTITY;
}
if (!data_ptr || length < 6) {
tr_error("EAP-TLS: decode error");
return EAP_TLS_MSG_DECODE_ERROR;
}
@ -226,16 +239,23 @@ static int8_t auth_eap_tls_sec_prot_message_send(sec_prot_t *prot, uint8_t eap_c
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) {
} else if (eap_code == EAP_SUCCESS || eap_code == EAP_FAILURE) {
// Send Success and Failure with same identifier as received in EAP Response
data->eap_id_seq = data->recv_eap_id_seq;
} else {
return -1;
}
uint16_t eapol_pdu_size;
uint8_t *eapol_decoded_data = eap_tls_sec_prot_lib_message_build(eap_code, eap_type, flags, data->eap_id_seq, prot->header_size, &data->tls_send, &eapol_pdu_size);
uint8_t *eapol_decoded_data = eap_tls_sec_prot_lib_message_build(eap_code, eap_type, &flags, data->eap_id_seq, prot->header_size, &data->tls_send, &eapol_pdu_size);
if (!eapol_decoded_data) {
return -1;
}
tr_info("EAP-TLS: send %s type %s id %i flags %x len %i, eui-64: %s", eap_msg_trace[eap_code - 1],
eap_type == EAP_IDENTITY ? "IDENTITY" : "TLS", data->eap_id_seq, flags, eapol_pdu_size,
trace_array(sec_prot_remote_eui_64_addr_get(prot), 8));
if (prot->send(prot, eapol_decoded_data, eapol_pdu_size + prot->header_size) < 0) {
return -1;
}
@ -267,10 +287,13 @@ static void auth_eap_tls_sec_prot_tls_finished_indication(sec_prot_t *tls_prot,
if (result == SEC_RESULT_OK) {
data->tls_result = EAP_TLS_RESULT_HANDSHAKE_OVER;
tr_info("EAP-TLS: handshake success");
} else if (result == SEC_RESULT_CONF_ERROR) {
data->tls_result = EAP_TLS_RESULT_HANDSHAKE_FATAL_ERROR;
tr_error("EAP-TLS: handshake fatal error");
} else {
data->tls_result = EAP_TLS_RESULT_HANDSHAKE_FAILED;
tr_error("EAP-TLS: handshake failed");
}
data->tls_ongoing = false;
@ -328,12 +351,7 @@ 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)
{
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;
}
// Triggers TLS to terminate if it is not already terminating by its own
sec_prot_t *tls_prot = prot->type_get(prot, SEC_PROT_TYPE_TLS);
if (tls_prot) {
tls_prot->finished_send(tls_prot);
@ -353,7 +371,7 @@ static void auth_eap_tls_sec_prot_state_machine(sec_prot_t *prot)
// Wait KMP-CREATE.request
case EAP_TLS_STATE_CREATE_REQ:
tr_debug("EAP-TLS start");
tr_info("EAP-TLS start, eui-64: %s", trace_array(sec_prot_remote_eui_64_addr_get(prot), 8));
prot->timer_start(prot);
@ -387,9 +405,6 @@ static void auth_eap_tls_sec_prot_state_machine(sec_prot_t *prot)
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);
@ -477,6 +492,8 @@ static void auth_eap_tls_sec_prot_state_machine(sec_prot_t *prot)
} else {
// TLS done, indicate success to peer
if (data->tls_result == EAP_TLS_RESULT_HANDSHAKE_OVER) {
// Supplicant PMK is now valid
sec_prot_keys_pmk_mismatch_reset(prot->sec_keys);
// Sends EAP success
auth_eap_tls_sec_prot_message_send(prot, EAP_SUCCESS, 0, EAP_TLS_EXCHANGE_NONE);
} else {
@ -491,13 +508,12 @@ static void auth_eap_tls_sec_prot_state_machine(sec_prot_t *prot)
break;
case EAP_TLS_STATE_FINISH:
tr_debug("EAP-TLS finish");
tr_info("EAP-TLS finish, eui-64: %s", trace_array(sec_prot_remote_eui_64_addr_get(prot), 8));
// KMP-FINISHED.indication,
prot->finished_ind(prot, sec_prot_result_get(&data->common), prot->sec_keys);
sec_prot_state_set(prot, &data->common, EAP_TLS_STATE_FINISHED);
data->common.ticks = 10 * 10;
break;
case EAP_TLS_STATE_FINISHED:

View File

@ -88,6 +88,7 @@ int8_t eap_tls_sec_prot_lib_message_handle(uint8_t *data, uint16_t length, bool
// Handles the length field
if (data[0] & EAP_TLS_FRAGMENT_LENGTH) {
if (length < 5) {
tr_error("EAP-TLS: decode error");
return EAP_TLS_MSG_DECODE_ERROR;
}
@ -138,19 +139,16 @@ int8_t eap_tls_sec_prot_lib_message_handle(uint8_t *data, uint16_t length, bool
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)
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);
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);

View File

@ -117,6 +117,6 @@ int8_t eap_tls_sec_prot_lib_message_handle(uint8_t *data, uint16_t length, bool
* \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);
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_ */

View File

@ -53,12 +53,16 @@ typedef enum {
EAP_TLS_STATE_FINISHED = SEC_STATE_FINISHED
} eap_tls_sec_prot_state_e;
// Filters EAP re-transmission bursts that arrive with same EAP sequence number
#define BURST_FILTER_TIMER_TIMEOUT 5 * 10
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 */
uint16_t burst_filt_timer; /**< Burst filter timer */
uint8_t eap_id_seq; /**< EAP sequence */
uint8_t eap_code; /**< Received EAP code */
uint8_t eap_type; /**< Received EAP type */
@ -72,7 +76,7 @@ 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
.TimerExpirations = 2
};
static uint16_t supp_eap_tls_sec_prot_size(void);
@ -127,6 +131,7 @@ static int8_t supp_eap_tls_sec_prot_init(sec_prot_t *prot)
sec_prot_state_set(prot, &data->common, EAP_TLS_STATE_INIT);
data->tls_prot = NULL;
data->burst_filt_timer = 0;
data->eap_id_seq = 0;
data->eap_code = 0;
data->eap_type = 0;
@ -186,15 +191,30 @@ static int8_t supp_eap_tls_sec_prot_message_handle(sec_prot_t *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],
tr_info("EAP-TLS recv %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);
uint8_t new_seq_id = false;
// New sequence identifier received
if (data->recv_eapol_pdu.msg.eap.id_seq > data->eap_id_seq) {
data->burst_filt_timer = BURST_FILTER_TIMER_TIMEOUT;
new_seq_id = true;
} else if (data->recv_eapol_pdu.msg.eap.id_seq == data->eap_id_seq) {
if (data->burst_filt_timer > 0) {
/* If retransmission arrives when burst filter timer is running, ignores it
and starts timer again */
data->burst_filt_timer = BURST_FILTER_TIMER_TIMEOUT;
return EAP_TLS_MSG_DECODE_ERROR;
} else {
// If retransmission arrives after timeout, starts timer again
data->burst_filt_timer = BURST_FILTER_TIMER_TIMEOUT;
}
} else if (data->recv_eapol_pdu.msg.eap.id_seq < data->eap_id_seq) {
// Already received sequence ID is received again, ignore
return EAP_TLS_MSG_DECODE_ERROR;
}
if (data->eap_type == EAP_IDENTITY) {
return EAP_TLS_MSG_IDENTITY;
}
@ -233,11 +253,14 @@ static int8_t supp_eap_tls_sec_prot_message_send(sec_prot_t *prot, uint8_t eap_c
}
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);
uint8_t *eapol_decoded_data = eap_tls_sec_prot_lib_message_build(eap_code, eap_type, &flags, data->eap_id_seq, prot->header_size, &data->tls_send, &eapol_pdu_size);
if (!eapol_decoded_data) {
return -1;
}
tr_info("EAP-TLS: send %s type %s id %i flags %x len %i", eap_msg_trace[eap_code - 1],
eap_type == EAP_IDENTITY ? "IDENTITY" : "TLS", data->eap_id_seq, flags, eapol_pdu_size);
if (prot->send(prot, eapol_decoded_data, eapol_pdu_size + prot->header_size) < 0) {
return -1;
}
@ -248,6 +271,13 @@ static int8_t supp_eap_tls_sec_prot_message_send(sec_prot_t *prot, uint8_t eap_c
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);
if (data->burst_filt_timer > ticks) {
data->burst_filt_timer -= ticks;
} else {
data->burst_filt_timer = 0;
}
sec_prot_timer_timeout_handle(prot, &data->common, &eap_tls_trickle_params, ticks);
}
@ -278,11 +308,14 @@ static void supp_eap_tls_sec_prot_tls_finished_indication(sec_prot_t *tls_prot,
if (result == SEC_RESULT_OK) {
data->tls_result = EAP_TLS_RESULT_HANDSHAKE_OVER;
tr_info("EAP-TLS: handshake success");
} else if (result == SEC_RESULT_CONF_ERROR) {
data->tls_result = EAP_TLS_RESULT_HANDSHAKE_FATAL_ERROR;
tr_error("EAP-TLS: handshake fatal error");
} else {
// On failure has sent ALERT
data->tls_result = EAP_TLS_RESULT_HANDSHAKE_FAILED;
tr_error("EAP-TLS: handshake failed");
}
data->tls_ongoing = false;
@ -340,12 +373,7 @@ 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)
{
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;
}
// Triggers TLS to terminate if it is not already terminating by its own
sec_prot_t *tls_prot = prot->type_get(prot, SEC_PROT_TYPE_TLS);
if (tls_prot) {
tls_prot->finished_send(tls_prot);
@ -374,7 +402,7 @@ static void supp_eap_tls_sec_prot_state_machine(sec_prot_t *prot)
// Store sequence ID
supp_eap_tls_sec_prot_seq_id_update(prot);
tr_debug("EAP-TLS start");
tr_info("EAP-TLS start");
prot->timer_start(prot);
@ -402,8 +430,8 @@ static void supp_eap_tls_sec_prot_state_machine(sec_prot_t *prot)
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);
/* Waits for next trickle expire. If trickle expirations reach the limit,
terminates EAP-TLS */
return;
}
@ -435,8 +463,8 @@ static void supp_eap_tls_sec_prot_state_machine(sec_prot_t *prot)
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);
/* Waits for next trickle expire. If trickle expirations reach the limit,
terminates EAP-TLS */
return;
}
@ -488,7 +516,7 @@ static void supp_eap_tls_sec_prot_state_machine(sec_prot_t *prot)
break;
case EAP_TLS_STATE_FINISH:
tr_debug("EAP-TLS finish");
tr_info("EAP-TLS finish");
// KMP-FINISHED.indication,
prot->finished_ind(prot, sec_prot_result_get(&data->common), prot->sec_keys);

View File

@ -155,12 +155,18 @@ static int8_t auth_fwh_sec_prot_receive(sec_prot_t *prot, void *pdu, uint16_t si
// 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) {
tr_info("4WH: recv %s, eui-64: %s", data->recv_msg == FWH_MESSAGE_2 ? "Message 2" : "Message 4", trace_array(sec_prot_remote_eui_64_addr_get(prot), 8));
// Call state machine
data->recv_pdu = pdu;
data->recv_size = size;
prot->state_machine(prot);
} else {
tr_error("4WH: recv error, eui-64: %s", trace_array(sec_prot_remote_eui_64_addr_get(prot), 8));
}
ret_val = 0;
} else {
tr_error("4WH: recv error, eui-64: %s", trace_array(sec_prot_remote_eui_64_addr_get(prot), 8));
}
memset(&data->recv_eapol_pdu, 0, sizeof(eapol_pdu_t));
@ -180,7 +186,7 @@ static fwh_sec_prot_msg_e auth_fwh_sec_prot_message_get(eapol_pdu_t *eapol_pdu,
return FWH_MESSAGE_UNKNOWN;
}
uint8_t key_mask = sec_prot_lib_key_mask_get(eapol_pdu);
uint8_t key_mask = eapol_pdu_key_mask_get(eapol_pdu);
switch (key_mask) {
case KEY_INFO_KEY_MIC:
@ -241,14 +247,14 @@ static int8_t auth_fwh_sec_prot_message_send(sec_prot_t *prot, fwh_sec_prot_msg_
break;
case FWH_MESSAGE_3: {
uint8_t gtk_index;
uint8_t *gtk = sec_prot_keys_get_gtk_to_insert(prot->sec_keys->gtks, &gtk_index);
uint8_t *gtk = sec_prot_keys_get_gtk_to_insert(prot->sec_keys, &gtk_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);
uint8_t gtkl = sec_prot_keys_fresh_gtkl_get(prot->sec_keys->gtks);
kde_end = kde_gtkl_write(kde_end, gtkl);
kde_padding_write(kde_end, kde_start + kde_len);
}
@ -267,7 +273,7 @@ static int8_t auth_fwh_sec_prot_message_send(sec_prot_t *prot, fwh_sec_prot_msg_
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_length = EAPOL_KEY_LEN;
eapol_pdu.msg.key.key_nonce = data->nonce;
break;
case FWH_MESSAGE_3:
@ -279,7 +285,7 @@ static int8_t auth_fwh_sec_prot_message_send(sec_prot_t *prot, fwh_sec_prot_msg_
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;
eapol_pdu.msg.key.key_length = EAPOL_KEY_LEN;
break;
default:
break;
@ -293,6 +299,8 @@ static int8_t auth_fwh_sec_prot_message_send(sec_prot_t *prot, fwh_sec_prot_msg_
return -1;
}
tr_info("4WH: send %s, eui-64: %s", msg == FWH_MESSAGE_1 ? "Message 1" : "Message 3", trace_array(sec_prot_remote_eui_64_addr_get(prot), 8));
if (prot->send(prot, eapol_pdu_frame, eapol_pdu_size + prot->header_size) < 0) {
return -1;
}
@ -319,7 +327,7 @@ static void auth_fwh_sec_prot_state_machine(sec_prot_t *prot)
// Wait KMP-CREATE.request
case FWH_STATE_CREATE_REQ:
tr_debug("4WH start");
tr_info("4WH: start, eui-64: %s", trace_array(sec_prot_remote_eui_64_addr_get(prot), 8));
uint8_t *pmk = sec_prot_keys_pmk_get(prot->sec_keys);
if (!pmk) { // If PMK is not set fails
@ -383,13 +391,18 @@ static void auth_fwh_sec_prot_state_machine(sec_prot_t *prot)
return;
}
// If GTK was inserted set it valid
sec_prot_keys_gtkl_from_gtk_insert_index_set(prot->sec_keys);
// Reset PTK mismatch
sec_prot_keys_ptk_mismatch_reset(prot->sec_keys);
// Update PTK
sec_prot_keys_ptk_write(prot->sec_keys, data->new_ptk);
sec_prot_state_set(prot, &data->common, FWH_STATE_FINISH);
}
break;
case FWH_STATE_FINISH:
tr_debug("4WH finish");
tr_info("4WH: finish, eui-64: %s", trace_array(sec_prot_remote_eui_64_addr_get(prot), 8));
// KMP-FINISHED.indication,
prot->finished_ind(prot, sec_prot_result_get(&data->common), 0);
@ -417,6 +430,7 @@ static int8_t auth_fwh_sec_prot_ptk_generate(sec_prot_t *prot, sec_prot_keys_t *
uint8_t *remote_nonce = data->recv_eapol_pdu.msg.key.key_nonce;
if (!remote_nonce) {
tr_error("SNonce invalid");
return 1;
}

View File

@ -47,6 +47,7 @@ typedef enum {
FWH_STATE_CREATE_IND = SEC_STATE_CREATE_IND,
FWH_STATE_MESSAGE_1 = SEC_STATE_FIRST,
FWH_STATE_MESSAGE_3,
FWH_STATE_MESSAGE_3_RETRY_WAIT,
FWH_STATE_CREATE_RESP_SUPP_RETRY,
FWH_STATE_FINISH = SEC_STATE_FINISH,
FWH_STATE_FINISHED = SEC_STATE_FINISHED
@ -76,22 +77,18 @@ typedef struct {
void *recv_pdu; /**< received pdu */
uint16_t recv_size; /**< received pdu size */
uint64_t recv_replay_cnt; /**< received replay counter */
bool msg3_received : 1; /**< Valid Message 3 has been received */
bool msg3_retry_wait : 1; /**< Waiting for Message 3 retry */
bool recv_replay_cnt_set : 1; /**< received replay counter set */
} 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 fwh_sec_prot_msg_e supp_fwh_sec_prot_message_get(sec_prot_t *prot, eapol_pdu_t *eapol_pdu);
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);
@ -101,6 +98,7 @@ static int8_t supp_fwh_sec_prot_ptk_generate(sec_prot_t *prot, sec_prot_keys_t *
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 bool supp_fwh_sec_prot_recv_replay_cnt_compare(uint64_t received_counter, 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);
@ -141,6 +139,10 @@ static int8_t supp_fwh_sec_prot_init(sec_prot_t *prot)
sec_prot_state_set(prot, &data->common, FWH_STATE_INIT);
data->common.ticks = 30 * 10; // 30 seconds
data->msg3_received = false;
data->msg3_retry_wait = false;
data->recv_replay_cnt = 0;
data->recv_replay_cnt_set = false;
uint8_t eui64[8] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08};
sec_prot_lib_nonce_init(data->snonce, eui64, 1000);
@ -171,14 +173,20 @@ static int8_t supp_fwh_sec_prot_receive(sec_prot_t *prot, void *pdu, uint16_t si
// 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);
data->recv_msg = supp_fwh_sec_prot_message_get(prot, &data->recv_eapol_pdu);
if (data->recv_msg != FWH_MESSAGE_UNKNOWN) {
tr_info("4WH: recv %s", data->recv_msg == FWH_MESSAGE_1 ? "Message 1" : "Message 3");
// Call state machine
data->recv_pdu = pdu;
data->recv_size = size;
prot->state_machine(prot);
} else {
tr_error("4WH: recv error");
}
ret_val = 0;
} else {
tr_error("4WH: recv error");
}
memset(&data->recv_eapol_pdu, 0, sizeof(eapol_pdu_t));
@ -189,7 +197,7 @@ static int8_t supp_fwh_sec_prot_receive(sec_prot_t *prot, void *pdu, uint16_t si
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)
static fwh_sec_prot_msg_e supp_fwh_sec_prot_message_get(sec_prot_t *prot, eapol_pdu_t *eapol_pdu)
{
fwh_sec_prot_msg_e msg = FWH_MESSAGE_UNKNOWN;
@ -198,23 +206,33 @@ static fwh_sec_prot_msg_e supp_fwh_sec_prot_message_get(eapol_pdu_t *eapol_pdu,
return FWH_MESSAGE_UNKNOWN;
}
uint8_t key_mask = sec_prot_lib_key_mask_get(eapol_pdu);
uint8_t key_mask = eapol_pdu_key_mask_get(eapol_pdu);
switch (key_mask) {
// Message 1
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)) {
/* Must have valid replay counter, both larger for PMK and larger that is used on
* the four way handshake session (note: PMK replay counter is not updated for Message 1
* but session specific counter is)
*/
if (sec_prot_keys_pmk_replay_cnt_compare(eapol_pdu->msg.key.replay_counter, prot->sec_keys) &&
supp_fwh_sec_prot_recv_replay_cnt_compare(eapol_pdu->msg.key.replay_counter, prot)) {
msg = FWH_MESSAGE_1;
} else {
tr_error("4WH: invalid replay counter %"PRId64, eapol_pdu->msg.key.replay_counter);
}
break;
// Message 3
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 (sec_prot_keys_pmk_replay_cnt_compare(eapol_pdu->msg.key.replay_counter, prot->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;
}
} else {
tr_error("4WH: invalid replay counter %"PRId64, eapol_pdu->msg.key.replay_counter);
}
break;
default:
@ -256,6 +274,8 @@ static int8_t supp_fwh_sec_prot_message_send(sec_prot_t *prot, fwh_sec_prot_msg_
return -1;
}
tr_info("4WH: send %s", msg == FWH_MESSAGE_2 ? "Message 2" : "Message 4");
if (prot->send(prot, eapol_pdu_frame, eapol_pdu_size + prot->header_size) < 0) {
return -1;
}
@ -266,7 +286,7 @@ static int8_t supp_fwh_sec_prot_message_send(sec_prot_t *prot, fwh_sec_prot_msg_
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);
sec_prot_timer_timeout_handle(prot, &data->common, NULL, ticks);
}
static void supp_fwh_sec_prot_state_machine(sec_prot_t *prot)
@ -291,7 +311,7 @@ static void supp_fwh_sec_prot_state_machine(sec_prot_t *prot)
return;
}
tr_debug("4WH start");
tr_info("4WH: start");
// Store authenticator nonce for check when 4WH Message 3 is received
supp_fwh_sec_prot_anonce_store(prot);
@ -335,9 +355,13 @@ static void supp_fwh_sec_prot_state_machine(sec_prot_t *prot)
if (supp_fwh_sec_prot_ptk_generate(prot, prot->sec_keys) < 0) {
return;
}
supp_fwh_sec_prot_recv_replay_counter_store(prot);
// Send 4WH message 2
supp_fwh_sec_prot_message_send(prot, FWH_MESSAGE_2);
data->common.ticks = 30 * 10; // 30 seconds
return;
} else if (data->recv_msg != FWH_MESSAGE_3) {
return;
}
@ -359,6 +383,7 @@ static void supp_fwh_sec_prot_state_machine(sec_prot_t *prot)
supp_fwh_sec_prot_recv_replay_counter_store(prot);
supp_fwh_sec_prot_security_replay_counter_update(prot);
data->msg3_received = true;
// Sends 4WH Message 4
supp_fwh_sec_prot_message_send(prot, FWH_MESSAGE_4);
@ -367,19 +392,37 @@ static void supp_fwh_sec_prot_state_machine(sec_prot_t *prot)
break;
case FWH_STATE_FINISH:
tr_debug("4WH finish");
if (data->msg3_retry_wait) {
tr_info("4WH: Message 3 retry timeout");
sec_prot_state_set(prot, &data->common, FWH_STATE_FINISHED);
return;
}
// If Message 3 has been received updates key data and waits for Message 3 retry
if (data->msg3_received) {
data->msg3_retry_wait = true;
tr_info("4WH: finish, wait Message 3 retry");
// 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);
data->common.ticks = 60 * 10; // 60 seconds
// KMP-FINISHED.indication
prot->finished_ind(prot, sec_prot_result_get(&data->common), prot->sec_keys);
sec_prot_state_set(prot, &data->common, FWH_STATE_MESSAGE_3_RETRY_WAIT);
} else {
tr_info("4WH: finish");
// KMP-FINISHED.indication
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:
case FWH_STATE_MESSAGE_3_RETRY_WAIT:
if (sec_prot_result_timeout_check(&data->common)) {
prot->timer_stop(prot);
prot->finished(prot);
tr_info("4WH: Message 3 retry timeout");
sec_prot_state_set(prot, &data->common, FWH_STATE_FINISHED);
} else {
if (data->recv_msg != FWH_MESSAGE_3) {
return;
@ -403,25 +446,15 @@ static void supp_fwh_sec_prot_state_machine(sec_prot_t *prot)
supp_fwh_sec_prot_recv_replay_counter_store(prot);
supp_fwh_sec_prot_security_replay_counter_update(prot);
tr_debug("4WH start again");
tr_info("4WH: send Message 4 again");
// Send KMP-CREATE.indication
prot->create_ind(prot);
sec_prot_state_set(prot, &data->common, FWH_STATE_CREATE_RESP_SUPP_RETRY);
supp_fwh_sec_prot_message_send(prot, FWH_MESSAGE_4);
}
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);
}
case FWH_STATE_FINISHED:
prot->timer_stop(prot);
prot->finished(prot);
break;
default:
@ -438,7 +471,8 @@ static int8_t supp_fwh_sec_prot_ptk_generate(sec_prot_t *prot, sec_prot_keys_t *
uint8_t *remote_nonce = data->recv_eapol_pdu.msg.key.key_nonce;
if (!remote_nonce) {
return 1;
tr_error("No ANonce");
return -1;
}
uint8_t *pmk = sec_prot_keys_pmk_get(sec_keys);
@ -457,6 +491,21 @@ 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;
data->recv_replay_cnt_set = true;
}
static bool supp_fwh_sec_prot_recv_replay_cnt_compare(uint64_t received_counter, sec_prot_t *prot)
{
fwh_sec_prot_int_t *data = fwh_sec_prot_get(prot);
// If previous value is set must be greater
if (data->recv_replay_cnt_set && received_counter > data->recv_replay_cnt) {
return true;
} else if (!data->recv_replay_cnt_set && received_counter >= data->recv_replay_cnt) {
// Otherwise allows also same value e.g. zero
return true;
}
return false;
}
static void supp_fwh_sec_prot_anonce_store(sec_prot_t *prot)
@ -469,6 +518,7 @@ 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) {
tr_error("ANonce invalid");
return -1;
}
return 0;
@ -508,7 +558,7 @@ static int8_t supp_fwh_kde_handle(sec_prot_t *prot)
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) {
if (sec_prot_lib_gtk_read(kde, kde_len, prot->sec_keys) < 0) {
goto error;
}
break;
@ -521,6 +571,7 @@ static int8_t supp_fwh_kde_handle(sec_prot_t *prot)
return 0;
error:
tr_error("Invalid KDEs");
ns_dyn_mem_free(kde);
return -1;
}

View File

@ -139,12 +139,18 @@ static int8_t auth_gkh_sec_prot_receive(sec_prot_t *prot, void *pdu, uint16_t si
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) {
tr_info("GKH: recv Message 2, eui-64: %s", trace_array(sec_prot_remote_eui_64_addr_get(prot), 8));
// Call state machine
data->recv_pdu = pdu;
data->recv_size = size;
prot->state_machine(prot);
} else {
tr_error("GKH: recv error, eui-64: %s", trace_array(sec_prot_remote_eui_64_addr_get(prot), 8));
}
ret_val = 0;
} else {
tr_error("GKH: recv error, eui-64: %s", trace_array(sec_prot_remote_eui_64_addr_get(prot), 8));
}
memset(&data->recv_eapol_pdu, 0, sizeof(eapol_pdu_t));
@ -163,7 +169,7 @@ static gkh_sec_prot_msg_e auth_gkh_sec_prot_message_get(eapol_pdu_t *eapol_pdu,
return GKH_MESSAGE_UNKNOWN;
}
uint8_t key_mask = sec_prot_lib_key_mask_get(eapol_pdu);
uint8_t key_mask = eapol_pdu_key_mask_get(eapol_pdu);
switch (key_mask) {
case KEY_INFO_KEY_MIC | KEY_INFO_SECURED_KEY_FRAME:
@ -204,14 +210,14 @@ static int8_t auth_gkh_sec_prot_message_send(sec_prot_t *prot, gkh_sec_prot_msg_
switch (msg) {
case GKH_MESSAGE_1: {
uint8_t gtk_index;
uint8_t *gtk = sec_prot_keys_get_gtk_to_insert(prot->sec_keys->gtks, &gtk_index);
uint8_t *gtk = sec_prot_keys_get_gtk_to_insert(prot->sec_keys, &gtk_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);
uint8_t gtkl = sec_prot_keys_fresh_gtkl_get(prot->sec_keys->gtks);
kde_end = kde_gtkl_write(kde_end, gtkl);
kde_padding_write(kde_end, kde_start + kde_len);
}
@ -245,6 +251,8 @@ static int8_t auth_gkh_sec_prot_message_send(sec_prot_t *prot, gkh_sec_prot_msg_
return -1;
}
tr_info("GKH: send Message 1, eui-64: %s", trace_array(sec_prot_remote_eui_64_addr_get(prot), 8));
if (prot->send(prot, eapol_pdu_frame, eapol_pdu_size + prot->header_size) < 0) {
return -1;
}
@ -270,7 +278,7 @@ static void auth_gkh_sec_prot_state_machine(sec_prot_t *prot)
// Wait KMP-CREATE.request
case GKH_STATE_CREATE_REQ:
tr_debug("GKH start");
tr_info("GKH start, eui-64: %s", trace_array(sec_prot_remote_eui_64_addr_get(prot), 8));
prot->timer_start(prot);
@ -296,12 +304,15 @@ static void auth_gkh_sec_prot_state_machine(sec_prot_t *prot)
if (auth_gkh_sec_prot_mic_validate(prot) < 0) {
return;
}
// Set inserted GTK valid
sec_prot_keys_gtkl_from_gtk_insert_index_set(prot->sec_keys);
sec_prot_state_set(prot, &data->common, GKH_STATE_FINISH);
}
break;
case GKH_STATE_FINISH:
tr_debug("GKH finish");
tr_info("GKH finish, eui-64: %s", trace_array(sec_prot_remote_eui_64_addr_get(prot), 8));
// KMP-FINISHED.indication,
prot->finished_ind(prot, sec_prot_result_get(&data->common), 0);

View File

@ -142,12 +142,18 @@ static int8_t supp_gkh_sec_prot_receive(sec_prot_t *prot, void *pdu, uint16_t si
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) {
tr_info("GKH: recv Message 1");
// Call state machine
data->recv_pdu = pdu;
data->recv_size = size;
prot->state_machine(prot);
} else {
tr_error("GKH: recv error");
}
ret_val = 0;
} else {
tr_error("GKH: recv error");
}
memset(&data->recv_eapol_pdu, 0, sizeof(eapol_pdu_t));
@ -166,16 +172,18 @@ static gkh_sec_prot_msg_e supp_gkh_sec_prot_message_get(eapol_pdu_t *eapol_pdu,
return GKH_MESSAGE_UNKNOWN;
}
uint8_t key_mask = sec_prot_lib_key_mask_get(eapol_pdu);
uint8_t key_mask = eapol_pdu_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 (sec_prot_keys_pmk_replay_cnt_compare(eapol_pdu->msg.key.replay_counter, 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;
}
} else {
tr_error("GKH: invalid replay counter %"PRId64, eapol_pdu->msg.key.replay_counter);
}
break;
default:
@ -207,6 +215,8 @@ static int8_t supp_gkh_sec_prot_message_send(sec_prot_t *prot, gkh_sec_prot_msg_
return -1;
}
tr_info("GKH: send Message 2");
if (prot->send(prot, eapol_pdu_frame, eapol_pdu_size + prot->header_size) < 0) {
return -1;
}
@ -304,15 +314,11 @@ static int8_t supp_gkh_kde_handle(sec_prot_t *prot)
}
// If a valid new GTK value present, insert it
int8_t ret = sec_prot_lib_gtk_read(kde, kde_len, prot->sec_keys->gtks);
int8_t ret = sec_prot_lib_gtk_read(kde, kde_len, prot->sec_keys);
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;
}
return ret;
}
#endif /* HAVE_WS */

View File

@ -113,13 +113,23 @@ static void key_sec_prot_create_request(sec_prot_t *prot, sec_prot_keys_t *sec_k
uint16_t kde_len = KDE_GTKL_LEN;
uint8_t *pmk = sec_prot_keys_pmk_get(sec_keys);
uint8_t pmkid[PMKID_LEN];
if (pmk) {
if (sec_prot_lib_pmkid_generate(prot, pmkid, false) >= 0) {
kde_len += KDE_PMKID_LEN;
} else {
pmk = NULL;
}
}
uint8_t *ptk = sec_prot_keys_ptk_get(sec_keys);
uint8_t ptkid[PTKID_LEN];
if (ptk) {
if (sec_prot_lib_ptkid_generate(prot, ptkid, false) >= 0) {
kde_len += KDE_PTKID_LEN;
} else {
ptk = NULL;
}
}
uint8_t *kde_start = ns_dyn_mem_temporary_alloc(kde_len);
@ -130,20 +140,14 @@ static void key_sec_prot_create_request(sec_prot_t *prot, sec_prot_keys_t *sec_k
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);
uint8_t gtkl = sec_prot_keys_fresh_gtkl_get(sec_keys->gtks);
kde_end = kde_gtkl_write(kde_end, gtkl);
kde_len = kde_end - kde_start;
@ -157,14 +161,15 @@ static void key_sec_prot_create_request(sec_prot_t *prot, sec_prot_keys_t *sec_k
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_pdu.msg.key.replay_counter = 0;
eapol_pdu.msg.key.key_length = 0;
eapol_write_pdu_frame(eapol_decoded_data + prot->header_size, &eapol_pdu);
tr_info("Initial EAPOL-Key send, PMKID %s PTKID %s GTKL %x", pmk ? "set" : "not set", ptk ? "set" : "not set", gtkl);
if (prot->send(prot, eapol_decoded_data, eapol_pdu_size + prot->header_size) < 0) {
data->result = SEC_RESULT_ERR_NO_MEM;
}
@ -187,11 +192,67 @@ static void key_sec_prot_create_response(sec_prot_t *prot, sec_prot_result_e res
static int8_t key_sec_prot_receive(sec_prot_t *prot, void *pdu, uint16_t size)
{
eapol_pdu_t eapol_pdu;
tr_info("Initial EAPOL-Key recv, eui-64: %s", trace_array(sec_prot_remote_eui_64_addr_get(prot), 8));
// Decoding is successful
if (eapol_parse_pdu_header(pdu, size, &eapol_pdu)) {
if (eapol_pdu.packet_type != EAPOL_KEY_TYPE) {
tr_info("not EAPOL-Key packet");
prot->finished(prot);
return -1;
}
uint16_t kde_len;
uint8_t *kde = sec_prot_lib_message_handle(prot->sec_keys->ptk, &kde_len, &eapol_pdu);
if (!kde) {
tr_error("no KDEs");
prot->finished(prot);
return -1;
}
// Default assumption is that PMK and PTK are not valid
prot->sec_keys->pmk_mismatch = true;
prot->sec_keys->ptk_mismatch = true;
// Checks if supplicant indicates that it has valid PMK
uint8_t remote_keyid[KEYID_LEN];
if (kde_pmkid_read(kde, kde_len, remote_keyid) >= 0) {
uint8_t pmkid[PMKID_LEN];
if (sec_prot_lib_pmkid_generate(prot, pmkid, true) >= 0) {
if (memcmp(remote_keyid, pmkid, PMKID_LEN) == 0) {
prot->sec_keys->pmk_mismatch = false;
}
}
}
// Checks if supplicant indicates that it has valid PTK
if (kde_ptkid_read(kde, kde_len, remote_keyid) >= 0) {
uint8_t ptkid[PTKID_LEN];
if (sec_prot_lib_ptkid_generate(prot, ptkid, true) >= 0) {
if (memcmp(remote_keyid, ptkid, PTKID_LEN) == 0) {
prot->sec_keys->ptk_mismatch = false;
}
}
}
// Get the GTKL that supplicant indicates
uint8_t gtkl;
if (kde_gtkl_read(kde, kde_len, &gtkl) >= 0) {
prot->sec_keys->gtkl = gtkl;
} else {
tr_error("no GTKL");
return -1;
}
tr_info("PMK %s PTK %s GTKL %x", prot->sec_keys->pmk_mismatch ? "not live" : "live", prot->sec_keys->ptk_mismatch ? "not live" : "live", gtkl);
ns_dyn_mem_free(kde);
prot->create_ind(prot);
return 0;
} else {
tr_error("Invalid");
// No error handling yet, indicate just that ready to be deleted
prot->finished(prot);
return -1;
@ -208,8 +269,6 @@ static void key_sec_prot_state_machine(sec_prot_t *prot)
// empty
break;
case KEY_CREATE_REQ:
tr_debug("initial EAPOL-Key send");
// KMP-CREATE.confirm
prot->create_conf(prot, data->result);
@ -221,8 +280,6 @@ static void key_sec_prot_state_machine(sec_prot_t *prot)
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);

View File

@ -207,6 +207,18 @@ typedef void sec_prot_eui64_addr_get(sec_prot_t *prot, uint8_t *local_eui64, uin
*/
typedef sec_prot_t *sec_prot_by_type_get(sec_prot_t *prot, uint8_t type);
/**
* sec_prot_receive_disable disables receiving of messages
*
* \param prot protocol
*
* \return security protocol or NULL
*
*/
typedef void sec_prot_receive_disable(sec_prot_t *prot);
typedef struct sec_prot_int_data_s sec_prot_int_data_t;
// Security protocol data
struct sec_prot_s {
sec_prot_create_request *create_req; /**< Create request */
@ -232,10 +244,11 @@ struct sec_prot_s {
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_receive_disable *receive_disable; /**< Disable receiving of messages */
sec_prot_keys_t *sec_keys; /**< Security keys storage pointer */
uint8_t header_size; /**< Header size */
uint8_t data; /**< Protocol internal data */
sec_prot_int_data_t *data; /**< Protocol internal data */
};
#endif /* SEC_PROT_H_ */

View File

@ -71,6 +71,11 @@ void sec_prot_certs_chain_entry_init(cert_chain_entry_t *entry)
memset(entry, 0, sizeof(cert_chain_entry_t));
}
void sec_prot_certs_chain_entry_delete(cert_chain_entry_t *entry)
{
ns_dyn_mem_free(entry);
}
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) {
@ -127,6 +132,33 @@ void sec_prot_certs_chain_list_delete(cert_chain_list_t *chain_list)
}
}
void sec_prot_certs_chain_list_entry_delete(cert_chain_list_t *chain_list, cert_chain_entry_t *entry)
{
ns_list_remove(chain_list, entry);
sec_prot_certs_chain_entry_delete(entry);
}
cert_chain_entry_t *sec_prot_certs_chain_list_entry_find(cert_chain_list_t *chain_list, cert_chain_entry_t *entry)
{
ns_list_foreach(cert_chain_entry_t, list_entry, chain_list) {
bool match = true;
for (uint8_t i = 0; i < SEC_PROT_CERT_CHAIN_DEPTH; i++) {
if (list_entry->cert_len[i] != entry->cert_len[i]) {
match = false;
break;
}
if (memcmp(list_entry->cert[i], entry->cert[i], list_entry->cert_len[i]) != 0) {
match = false;
break;
}
}
if (match) {
return list_entry;
}
}
return NULL;
}
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));
@ -142,7 +174,12 @@ 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)
void sec_prot_certs_revocat_list_entry_delete(cert_revocat_list_entry_t *entry)
{
ns_dyn_mem_free(entry);
}
int8_t sec_prot_certs_revocat_list_set(cert_revocat_list_entry_t *entry, const uint8_t *crl, uint16_t crl_len)
{
if (!entry) {
return -1;
@ -154,7 +191,7 @@ int8_t sec_prot_certs_revocat_list_set(cert_revocat_list_entry_t *entry, uint8_t
return 0;
}
uint8_t *sec_prot_certs_revocat_list_get(const cert_revocat_list_entry_t *entry, uint16_t *crl_len)
const uint8_t *sec_prot_certs_revocat_list_get(const cert_revocat_list_entry_t *entry, uint16_t *crl_len)
{
if (!entry) {
return NULL;
@ -168,6 +205,25 @@ void sec_prot_certs_revocat_lists_add(cert_revocat_lists_t *cert_revocat_lists,
ns_list_add_to_end(cert_revocat_lists, entry);
}
void sec_prot_certs_revocat_lists_entry_delete(cert_revocat_lists_t *cert_revocat_lists, cert_revocat_list_entry_t *entry)
{
ns_list_remove(cert_revocat_lists, entry);
sec_prot_certs_revocat_list_entry_delete(entry);
}
cert_revocat_list_entry_t *sec_prot_certs_revocat_lists_entry_find(cert_revocat_lists_t *cert_revocat_lists, cert_revocat_list_entry_t *entry)
{
ns_list_foreach_safe(cert_revocat_list_entry_t, list_entry, cert_revocat_lists) {
if (list_entry->crl_len == entry->crl_len) {
if (memcmp(list_entry->crl, entry->crl, list_entry->crl_len) == 0) {
return list_entry;
}
}
}
return NULL;
}
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) {

View File

@ -46,7 +46,7 @@ typedef struct {
} cert_chain_entry_t;
typedef struct {
uint8_t *crl; /**< Certificate Revocation List */
const 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;
@ -92,6 +92,13 @@ cert_chain_entry_t *sec_prot_certs_chain_entry_create(void);
*/
void sec_prot_certs_chain_entry_init(cert_chain_entry_t *entry);
/**
* sec_prot_certs_chain_entry_delete deletes certificate chain entry
*
* \param entry certificate chain entry
*/
void sec_prot_certs_chain_entry_delete(cert_chain_entry_t *entry);
/**
* sec_prot_certs_cert_set set certificate to chain entry
*
@ -153,6 +160,26 @@ void sec_prot_certs_chain_list_add(cert_chain_list_t *cert_chain_list, cert_chai
*/
void sec_prot_certs_chain_list_delete(cert_chain_list_t *chain_list);
/**
* sec_prot_certs_chain_list_entry_delete deletes entry from certificate chain list
*
* \param cert_chain_list certificate chain entry list
* \param entry deleted certificate chain entry
*
*/
void sec_prot_certs_chain_list_entry_delete(cert_chain_list_t *chain_list, cert_chain_entry_t *entry);
/**
* sec_prot_certs_chain_list_entry_find finds entry from certificate chain list
*
* \param cert_chain_list certificate chain entry list
* \param entry searched certificate chain entry
*
* \return certificate chain entry or NULL
*
*/
cert_chain_entry_t *sec_prot_certs_chain_list_entry_find(cert_chain_list_t *chain_list, cert_chain_entry_t *entry);
/**
* sec_prot_certs_revocat_list_entry_create allocate memory for certificate revocation list entry
*
@ -167,6 +194,13 @@ cert_revocat_list_entry_t *sec_prot_certs_revocat_list_entry_create(void);
*/
void sec_prot_certs_revocat_list_entry_init(cert_revocat_list_entry_t *entry);
/**
* sec_prot_certs_revocat_list_entry_delete deletes certificate revocation list entry
*
* \param entry certificate revocation list entry
*/
void sec_prot_certs_revocat_list_entry_delete(cert_revocat_list_entry_t *entry);
/**
* sec_prot_certs_revocat_list_set set certificate revocation list to list entry
*
@ -177,7 +211,7 @@ void sec_prot_certs_revocat_list_entry_init(cert_revocat_list_entry_t *entry);
* \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);
int8_t sec_prot_certs_revocat_list_set(cert_revocat_list_entry_t *entry, const uint8_t *crl, uint16_t crl_len);
/**
* sec_prot_certs_revocat_list_set set certificate revocation list from list entry
@ -187,16 +221,35 @@ int8_t sec_prot_certs_revocat_list_set(cert_revocat_list_entry_t *entry, uint8_t
*
* \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);
const 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
* sec_prot_certs_revocat_lists_add add certificate revocation list entry to certificate revocation lists
*
* \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_revocat_lists_entry_delete delete certificate revocation list entry from certificate revocation lists
*
* \param cert_revocat_lists certificate revocation lists
* \param entry certificate revocation list entry
*
*/
void sec_prot_certs_revocat_lists_entry_delete(cert_revocat_lists_t *cert_revocat_lists, cert_revocat_list_entry_t *entry);
/**
* sec_prot_certs_revocat_lists_entry_find find certificate revocation list entry from certificate revocation lists
*
* \param cert_revocat_lists certificate revocation lists
* \param entry certificate revocation list entry
*
* \return certificate revocation list entry or NULL
*/
cert_revocat_list_entry_t *sec_prot_certs_revocat_lists_entry_find(cert_revocat_lists_t *cert_revocat_lists, cert_revocat_list_entry_t *entry);
/**
* sec_prot_certs_chain_list_delete delete certificate chain list
*

View File

@ -25,8 +25,14 @@
#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/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"
#ifdef HAVE_WS
@ -47,13 +53,20 @@ sec_prot_keys_t *sec_prot_keys_create(sec_prot_gtk_keys_t *gtks, const sec_prot_
void sec_prot_keys_init(sec_prot_keys_t *sec_keys, sec_prot_gtk_keys_t *gtks, const sec_prot_certs_t *certs)
{
memset(sec_keys, 0, sizeof(sec_prot_keys_t));
sec_keys->pmk_lifetime = PMK_LIFETIME_INSTALL;
sec_keys->ptk_lifetime = PTK_LIFETIME_INSTALL;
sec_keys->pmk_key_replay_cnt = 0;
sec_keys->gtks = gtks;
sec_keys->certs = certs;
sec_keys->gtkl = 0;
sec_keys->gtk_set_index = -1;
sec_keys->pmk_set = false;
sec_keys->ptk_set = false;
sec_keys->pmk_key_replay_cnt_set = false;
sec_keys->updated = false;
sec_keys->ptk_eui_64_set = false;
sec_keys->pmk_mismatch = false;
sec_keys->ptk_mismatch = false;
}
void sec_prot_keys_delete(sec_prot_keys_t *sec_keys)
@ -76,7 +89,6 @@ sec_prot_gtk_keys_t *sec_prot_keys_gtks_create(void)
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;
}
@ -89,10 +101,22 @@ 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_key_replay_cnt_set = false;
sec_keys->pmk_lifetime = PMK_LIFETIME_INSTALL;
sec_keys->pmk_set = true;
sec_keys->updated = true;
}
void sec_prot_keys_pmk_delete(sec_prot_keys_t *sec_keys)
{
memset(sec_keys->pmk, 0, PMK_LEN);
sec_keys->pmk_key_replay_cnt = 0;
sec_keys->pmk_key_replay_cnt_set = false;
sec_keys->pmk_lifetime = PMK_LIFETIME_INSTALL;
sec_keys->pmk_set = false;
sec_keys->updated = true;
}
uint8_t *sec_prot_keys_pmk_get(sec_prot_keys_t *sec_keys)
{
if (!sec_keys->pmk_set) {
@ -109,21 +133,87 @@ uint64_t sec_prot_keys_pmk_replay_cnt_get(sec_prot_keys_t *sec_keys)
void sec_prot_keys_pmk_replay_cnt_set(sec_prot_keys_t *sec_keys, uint64_t counter)
{
sec_keys->pmk_key_replay_cnt_set = true;
sec_keys->pmk_key_replay_cnt = counter;
}
void sec_prot_keys_pmk_replay_cnt_increment(sec_prot_keys_t *sec_keys)
{
// Start from zero i.e. does not increment on first call
if (!sec_keys->pmk_key_replay_cnt_set) {
sec_keys->pmk_key_replay_cnt_set = true;
return;
}
sec_keys->pmk_key_replay_cnt++;
}
bool sec_prot_keys_pmk_replay_cnt_compare(uint64_t received_counter, sec_prot_keys_t *sec_keys)
{
// If previous value is set must be greater
if (sec_keys->pmk_key_replay_cnt_set && received_counter > sec_keys->pmk_key_replay_cnt) {
return true;
} else if (!sec_keys->pmk_key_replay_cnt_set && received_counter >= sec_keys->pmk_key_replay_cnt) {
// Otherwise allows also same value e.g. zero
return true;
}
return false;
}
void sec_prot_keys_pmk_mismatch_set(sec_prot_keys_t *sec_keys)
{
sec_keys->pmk_mismatch = true;
}
void sec_prot_keys_pmk_mismatch_reset(sec_prot_keys_t *sec_keys)
{
sec_keys->pmk_mismatch = false;
}
bool sec_prot_keys_pmk_mismatch_is_set(sec_prot_keys_t *sec_keys)
{
return sec_keys->pmk_mismatch;
}
bool sec_prot_keys_pmk_lifetime_decrement(sec_prot_keys_t *sec_keys, uint32_t default_lifetime, uint8_t seconds)
{
if (!sec_keys->pmk_set) {
return false;
}
if (sec_keys->pmk_lifetime == PMK_LIFETIME_INSTALL) {
sec_keys->pmk_lifetime = default_lifetime;
}
if (sec_keys->pmk_lifetime > seconds) {
sec_keys->pmk_lifetime -= seconds;
} else {
if (sec_keys->pmk_lifetime > 0) {
sec_keys->pmk_lifetime = 0;
sec_prot_keys_ptk_delete(sec_keys);
sec_prot_keys_pmk_delete(sec_keys);
return true;
}
}
return false;
}
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_lifetime = PTK_LIFETIME_INSTALL;
sec_keys->ptk_set = true;
sec_keys->updated = true;
}
void sec_prot_keys_ptk_delete(sec_prot_keys_t *sec_keys)
{
memset(sec_keys->ptk, 0, PTK_LEN);
sec_keys->ptk_lifetime = PTK_LIFETIME_INSTALL;
sec_keys->ptk_set = false;
sec_keys->updated = true;
}
uint8_t *sec_prot_keys_ptk_get(sec_prot_keys_t *sec_keys)
{
if (!sec_keys->ptk_set) {
@ -133,29 +223,66 @@ uint8_t *sec_prot_keys_ptk_get(sec_prot_keys_t *sec_keys)
return sec_keys->ptk;
}
void sec_prot_keys_ptk_eui_64_set(sec_prot_keys_t *sec_keys, uint8_t *eui_64)
void sec_prot_keys_ptk_mismatch_set(sec_prot_keys_t *sec_keys)
{
sec_keys->ptk_eui_64 = eui_64;
sec_keys->ptk_mismatch = true;
}
void sec_prot_keys_ptk_eui_64_write(sec_prot_keys_t *sec_keys, uint8_t *eui_64)
void sec_prot_keys_ptk_mismatch_reset(sec_prot_keys_t *sec_keys)
{
sec_keys->ptk_mismatch = false;
}
bool sec_prot_keys_ptk_mismatch_is_set(sec_prot_keys_t *sec_keys)
{
return sec_keys->ptk_mismatch;
}
void sec_prot_keys_ptk_eui_64_write(sec_prot_keys_t *sec_keys, const 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) {
if (!sec_keys->ptk_eui_64_set) {
return NULL;
}
return sec_keys->ptk_eui_64;
}
void sec_prot_keys_ptk_eui_64_delete(sec_prot_keys_t *sec_keys)
{
memset(sec_keys->ptk_eui_64, 0, 8);
sec_keys->ptk_eui_64_set = false;
sec_keys->updated = true;
}
bool sec_prot_keys_ptk_lifetime_decrement(sec_prot_keys_t *sec_keys, uint32_t default_lifetime, uint8_t seconds)
{
if (!sec_keys->ptk_set) {
return false;
}
if (sec_keys->ptk_lifetime == PTK_LIFETIME_INSTALL) {
sec_keys->ptk_lifetime = default_lifetime;
}
if (sec_keys->ptk_lifetime > seconds) {
sec_keys->ptk_lifetime -= seconds;
} else {
if (sec_keys->ptk_lifetime > 0) {
sec_prot_keys_ptk_delete(sec_keys);
sec_keys->ptk_lifetime = 0;
return true;
}
}
return false;
}
bool sec_prot_keys_are_updated(sec_prot_keys_t *sec_keys)
{
return sec_keys->updated;
@ -166,82 +293,129 @@ 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 sec_prot_keys_fresh_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);
uint8_t gtkl = 0;
for (uint8_t i = 0; i < GTK_NUM; i++) {
if (sec_prot_keys_gtk_status_is_live(gtks, i)) {
gtkl |= 1 << i;
}
}
return gtkl;
}
void sec_prot_keys_gtkl_set(sec_prot_gtk_keys_t *gtks, uint8_t gtkl)
void sec_prot_keys_gtkl_set(sec_prot_keys_t *sec_keys, 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;
}
}
}
sec_keys->gtkl = gtkl;
}
bool sec_prot_keys_gtk_is_live(sec_prot_gtk_keys_t *gtks, uint8_t index)
bool sec_prot_keys_gtkl_gtk_is_live(sec_prot_keys_t *sec_keys, uint8_t index)
{
if (index >= GTK_NUM || !gtks->gtk[index].live) {
if (index >= GTK_NUM) {
return false;
}
if (sec_keys->gtkl & (1 << index)) {
return true;
}
return false;
}
int8_t sec_prot_keys_gtk_insert_index_set(sec_prot_gtk_keys_t *gtks, uint8_t index)
int8_t sec_prot_keys_gtkl_gtk_live_set(sec_prot_keys_t *sec_keys, uint8_t index)
{
if (index >= GTK_NUM || !gtks->gtk[index].set) {
if (index >= GTK_NUM) {
return -1;
}
gtks->gtk_set_index = index;
sec_keys->gtkl |= (1 << index);
return 0;
}
int8_t sec_prot_keys_gtk_insert_index_get(sec_prot_gtk_keys_t *gtks)
int8_t sec_prot_keys_gtk_insert_index_set(sec_prot_keys_t *sec_keys, uint8_t index)
{
return gtks->gtk_set_index;
if (index >= GTK_NUM || !sec_keys->gtks->gtk[index].set) {
return -1;
}
sec_keys->gtk_set_index = index;
return 0;
}
void sec_prot_keys_gtk_insert_index_clear(sec_prot_gtk_keys_t *gtks)
int8_t sec_prot_keys_gtk_insert_index_get(sec_prot_keys_t *sec_keys)
{
gtks->gtk_set_index = -1;
return sec_keys->gtk_set_index;
}
uint8_t *sec_prot_keys_get_gtk_to_insert(sec_prot_gtk_keys_t *gtks, uint8_t *index)
void sec_prot_keys_gtk_insert_index_clear(sec_prot_keys_t *sec_keys)
{
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;
sec_keys->gtk_set_index = -1;
}
void sec_prot_keys_gtkl_from_gtk_insert_index_set(sec_prot_keys_t *sec_keys)
{
if (sec_keys->gtk_set_index >= 0) {
sec_prot_keys_gtkl_gtk_live_set(sec_keys, sec_keys->gtk_set_index);
sec_prot_keys_gtk_insert_index_clear(sec_keys);
}
}
int8_t sec_prot_keys_gtk_insert_index_from_gtkl_get(sec_prot_keys_t *sec_keys)
{
// Get currently active key index
int8_t active_index = sec_prot_keys_gtk_status_active_get(sec_keys->gtks);
if (active_index >= 0 && !sec_prot_keys_gtkl_gtk_is_live(sec_keys, active_index)) {
// If currently active key is not live on remote, inserts it
sec_prot_keys_gtk_insert_index_set(sec_keys, active_index);
return active_index;
}
// Checks all keys
for (uint8_t i = 0; i < GTK_NUM; i++) {
if (sec_prot_keys_gtk_status_is_live(sec_keys->gtks, i)) {
// If key is live, but not indicated on GTKL inserts it
if (!sec_prot_keys_gtkl_gtk_is_live(sec_keys, i)) {
sec_prot_keys_gtk_insert_index_set(sec_keys, i);
return i;
}
}
}
return -1;
}
uint8_t *sec_prot_keys_get_gtk_to_insert(sec_prot_keys_t *sec_keys, uint8_t *index)
{
if (sec_keys->gtk_set_index >= 0 && sec_keys->gtks->gtk[sec_keys->gtk_set_index].set) {
*index = sec_keys->gtk_set_index;
return sec_keys->gtks->gtk[sec_keys->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)
int8_t sec_prot_keys_gtk_set(sec_prot_gtk_keys_t *gtks, uint8_t index, uint8_t *gtk, uint32_t lifetime)
{
if (!gtk || index >= GTK_NUM) {
return -1;
}
if (gtks->gtk[index].set && memcmp(gtks->gtk[index].key, gtk, GTK_LEN) != 0) {
// If same GTK is given again, do not update
if (gtks->gtk[index].set && memcmp(gtks->gtk[index].key, gtk, GTK_LEN) == 0) {
return -1;
}
sec_prot_keys_gtk_clear(gtks, index);
uint8_t install_order = sec_prot_keys_gtk_install_order_last_get(gtks);
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
gtks->gtk[index].lifetime = lifetime;
gtks->gtk[index].status = GTK_STATUS_NEW;
gtks->gtk[index].install_order = install_order;
memcpy(gtks->gtk[index].key, gtk, GTK_LEN);
gtks->updated = true;
@ -249,6 +423,22 @@ int8_t sec_prot_keys_gtk_set(sec_prot_gtk_keys_t *gtks, uint8_t index, uint8_t *
return 0;
}
int8_t sec_prot_keys_gtk_clear(sec_prot_gtk_keys_t *gtks, uint8_t index)
{
if (!gtks || index >= GTK_NUM) {
return -1;
}
gtks->gtk[index].set = false;
gtks->gtk[index].lifetime = 0; // Should be provided by authenticator
gtks->gtk[index].status = GTK_STATUS_NEW;
memset(gtks->gtk[index].key, 0, GTK_LEN);
sec_prot_keys_gtk_install_order_update(gtks);
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) {
@ -276,15 +466,15 @@ uint32_t sec_prot_keys_gtk_lifetime_get(sec_prot_gtk_keys_t *gtks, uint8_t index
return gtks->gtk[index].lifetime;
}
void sec_prot_keys_gtk_lifetime_set(sec_prot_gtk_keys_t *gtks, uint8_t index, uint32_t lifetime)
uint32_t sec_prot_keys_gtk_lifetime_decrement(sec_prot_gtk_keys_t *gtks, uint8_t index, uint16_t seconds)
{
if (index >= GTK_NUM || !gtks->gtk[index].set) {
return;
if (gtks->gtk[index].lifetime > seconds) {
gtks->gtk[index].lifetime -= seconds;
} else {
gtks->gtk[index].lifetime = 0;
}
gtks->gtk[index].lifetime = lifetime;
gtks->updated = true;
return gtks->gtk[index].lifetime;
}
bool sec_prot_keys_gtks_are_updated(sec_prot_gtk_keys_t *gtks)
@ -302,4 +492,290 @@ void sec_prot_keys_gtks_updated_reset(sec_prot_gtk_keys_t *gtks)
gtks->updated = false;
}
void sec_prot_keys_gtk_status_fresh_set(sec_prot_gtk_keys_t *gtks, uint8_t index)
{
if (index >= GTK_NUM || !gtks->gtk[index].set) {
return;
}
// Active key remains as active, old keys are never reused
if (gtks->gtk[index].status < GTK_STATUS_FRESH) {
gtks->gtk[index].status = GTK_STATUS_FRESH;
}
}
void sec_prot_keys_gtk_status_all_fresh_set(sec_prot_gtk_keys_t *gtks)
{
for (uint8_t i = 0; i < GTK_NUM; i++) {
sec_prot_keys_gtk_status_fresh_set(gtks, i);
}
}
int8_t sec_prot_keys_gtk_status_active_set(sec_prot_gtk_keys_t *gtks, uint8_t index)
{
if (index >= GTK_NUM || !gtks->gtk[index].set) {
return -1;
}
// If key is valid to be taken into use sets it active
if (gtks->gtk[index].status == GTK_STATUS_FRESH) {
// Sets previously active key old
for (uint8_t i = 0; i < GTK_NUM; i++) {
// Sets previously active key old
if (gtks->gtk[i].status == GTK_STATUS_ACTIVE) {
gtks->gtk[i].status = GTK_STATUS_OLD;
}
}
gtks->gtk[index].status = GTK_STATUS_ACTIVE;
return 0;
}
return -1;
}
int8_t sec_prot_keys_gtk_status_active_get(sec_prot_gtk_keys_t *gtks)
{
for (uint8_t i = 0; i < GTK_NUM; i++) {
if (gtks->gtk[i].status == GTK_STATUS_ACTIVE) {
return i;
}
}
return -1;
}
bool sec_prot_keys_gtk_status_is_live(sec_prot_gtk_keys_t *gtks, uint8_t index)
{
if (index >= GTK_NUM || !gtks->gtk[index].set) {
return false;
}
if (gtks->gtk[index].status == GTK_STATUS_FRESH || gtks->gtk[index].status == GTK_STATUS_ACTIVE) {
return true;
}
return false;
}
void sec_prot_keys_gtk_status_new_set(sec_prot_gtk_keys_t *gtks, uint8_t index)
{
if (index >= GTK_NUM || !gtks->gtk[index].set) {
return;
}
gtks->gtk[index].status = GTK_STATUS_NEW;
}
void sec_prot_keys_gtks_hash_generate(sec_prot_gtk_keys_t *gtks, uint8_t *gtkhash)
{
memset(gtkhash, 0, GTK_ALL_HASHES_LEN);
uint8_t *gtk_hash_ptr = gtkhash;
for (uint8_t i = 0; i < GTK_NUM; i++) {
if (sec_prot_keys_gtk_is_set(gtks, i)) {
uint8_t *gtk = sec_prot_keys_gtk_get(gtks, i);
sec_prot_lib_gtkhash_generate(gtk, gtk_hash_ptr);
}
gtk_hash_ptr += GTK_HASH_LEN;
}
}
gtk_mismatch_e sec_prot_keys_gtks_hash_update(sec_prot_gtk_keys_t *gtks, uint8_t *gtkhash)
{
uint8_t *gtk_hash_ptr = gtkhash;
gtk_mismatch_e mismatch = GTK_NO_MISMATCH;
for (uint8_t i = 0; i < GTK_NUM; i++, gtk_hash_ptr += 8) {
// If hash is not set, stop using the key
if (sec_prot_keys_gtk_hash_empty(gtk_hash_ptr)) {
if (sec_prot_keys_gtk_is_set(gtks, i)) {
uint32_t lifetime = sec_prot_keys_gtk_lifetime_get(gtks, i);
if (lifetime > GTK_EXPIRE_MISMATCH_TIME) {
tr_info("GTK mismatch %i expired time, lifetime: %"PRIu32"", i, lifetime);
if (mismatch < GTK_LIFETIME_MISMATCH) {
mismatch = GTK_LIFETIME_MISMATCH;
}
}
sec_prot_keys_gtk_clear(gtks, i);
}
} else {
// Check is hash matches to existing key
uint8_t gtk_hash[8];
uint8_t *gtk = sec_prot_keys_gtk_get(gtks, i);
if (!gtk) {
// Hash set but GTK is not known, set mismatch
tr_info("GTK mismatch: %i", i);
if (mismatch < GTK_HASH_MISMATCH) {
mismatch = GTK_HASH_MISMATCH;
}
continue;
}
sec_prot_lib_gtkhash_generate(gtk, gtk_hash);
if (memcmp(gtk_hash, gtk_hash_ptr, 8) == 0) {
// Key is fresh (or active, if old do not change state)
sec_prot_keys_gtk_status_fresh_set(gtks, i);
} else {
// Hash does not match, set mismatch and delete key
tr_info("GTK mismatch: %i", i);
if (mismatch < GTK_HASH_MISMATCH) {
mismatch = GTK_HASH_MISMATCH;
}
sec_prot_keys_gtk_clear(gtks, i);
}
}
}
return mismatch;
}
bool sec_prot_keys_gtk_hash_empty(uint8_t *gtkhash)
{
const uint8_t empty_hash[GTK_HASH_LEN] = {0};
if (memcmp(gtkhash, empty_hash, GTK_HASH_LEN) == 0) {
return true;
} else {
return false;
}
}
int8_t sec_prot_keys_gtk_install_order_last_get(sec_prot_gtk_keys_t *gtks)
{
int8_t install_order = -1;
// Gets the last key index
for (uint8_t i = 0; i < GTK_NUM; i++) {
if (sec_prot_keys_gtk_is_set(gtks, i)) {
if (gtks->gtk[i].install_order > install_order) {
install_order = gtks->gtk[i].install_order;
}
}
}
return install_order + 1;
}
int8_t sec_prot_keys_gtk_install_order_last_index_get(sec_prot_gtk_keys_t *gtks)
{
int8_t install_order = -1;
int8_t index = -1;
// Gets the last key index
for (uint8_t i = 0; i < GTK_NUM; i++) {
if (sec_prot_keys_gtk_is_set(gtks, i)) {
if (gtks->gtk[i].install_order > install_order) {
install_order = gtks->gtk[i].install_order;
index = i;
}
}
}
return index;
}
uint32_t sec_prot_keys_gtk_install_order_last_lifetime_get(sec_prot_gtk_keys_t *gtks)
{
uint32_t lifetime = 0;
int8_t install_order = -1;
// Gets the last key index
for (uint8_t i = 0; i < GTK_NUM; i++) {
if (sec_prot_keys_gtk_is_set(gtks, i)) {
if (gtks->gtk[i].install_order > install_order) {
install_order = gtks->gtk[i].install_order;
lifetime = gtks->gtk[i].lifetime;
}
}
}
return lifetime;
}
int8_t sec_prot_keys_gtk_install_order_first_index_get(sec_prot_gtk_keys_t *gtks)
{
// Gets the first key index
for (uint8_t i = 0; i < GTK_NUM; i++) {
if (sec_prot_keys_gtk_is_set(gtks, i)) {
if (gtks->gtk[i].install_order == GTK_INSTALL_ORDER_FIRST) {
return i;
}
}
}
return -1;
}
int8_t sec_prot_keys_gtk_install_order_second_index_get(sec_prot_gtk_keys_t *gtks)
{
// Gets the first key index
for (uint8_t i = 0; i < GTK_NUM; i++) {
if (sec_prot_keys_gtk_is_set(gtks, i)) {
if (gtks->gtk[i].install_order == GTK_INSTALL_ORDER_SECOND) {
return i;
}
}
}
return -1;
}
void sec_prot_keys_gtk_install_order_update(sec_prot_gtk_keys_t *gtks)
{
int8_t ordered_indexes[4] = {-1, -1, -1, -1};
// Creates table of ordered indexes
for (uint8_t i = 0; i < GTK_NUM; i++) {
if (sec_prot_keys_gtk_is_set(gtks, i)) {
ordered_indexes[gtks->gtk[i].install_order] = i;
}
}
// Updates indexes of the GTKs
uint8_t new_install_order = 0;
for (uint8_t i = 0; i < GTK_NUM; i++) {
if (ordered_indexes[i] >= 0) {
gtks->gtk[ordered_indexes[i]].install_order = new_install_order++;
}
}
}
int8_t sec_prot_keys_gtk_install_index_get(sec_prot_gtk_keys_t *gtks)
{
// Gets the index of the last key to be installed
int8_t install_index = sec_prot_keys_gtk_install_order_last_index_get(gtks);
if (install_index < 0) {
install_index = 0;
}
// Checks if there is free index, and available uses that for new GTK
for (uint8_t ctr = 0, i = install_index; ctr < GTK_NUM; ctr++) {
if (!sec_prot_keys_gtk_is_set(gtks, i)) {
install_index = i;
break;
}
i++;
if (i >= GTK_NUM) {
i = 0;
}
}
return install_index;
}
uint8_t sec_prot_keys_gtk_count(sec_prot_gtk_keys_t *gtks)
{
uint8_t count = 0;
for (uint8_t i = 0; i < GTK_NUM; i++) {
if (sec_prot_keys_gtk_is_set(gtks, i)) {
count++;
}
}
return count;
}
#endif /* HAVE_WS */

View File

@ -39,21 +39,36 @@
#define PMKID_LEN 16
#define PTKID_LEN 16
#define KEYID_LEN 16
#define GTK_DEFAULT_LIFETIME 60 * 60 * 24 * 30 // 30 days
#define GTK_EXPIRE_MISMATCH_TIME 60 // Supplicant GTK expire time mismatch occurs if GTK expires before this time
#define GTK_STATUS_NEW 0 // New GTK, can transition to fresh
#define GTK_STATUS_FRESH 1 // Fresh GTK, live based on hash, can transition to active
#define GTK_STATUS_ACTIVE 2 // Active GTK, live based on hash, can transition to old
#define GTK_STATUS_OLD 3 // Old GTK, not to be used for sending
#define GTK_INSTALL_ORDER_FIRST 0 // Install order runs from 0 to 3, where 0 is the GTK to be installed first
#define GTK_INSTALL_ORDER_SECOND 1 // Install order runs from 0 to 3, where 1 is the GTK to be installed second
#define GTK_HASH_LEN 8
#define GTK_ALL_HASHES_LEN GTK_HASH_LEN * GTK_NUM
#define PMK_LIFETIME_INSTALL 0xFFFFF
#define PTK_LIFETIME_INSTALL 0xFFFFF
typedef struct {
uint8_t key[GTK_LEN]; /**< Group Transient Key (128 bits) */
uint32_t lifetime; /**< Lifetime is seconds */
uint32_t lifetime; /**< GTK lifetime in seconds */
unsigned status : 2; /**< Group Transient Key status */
unsigned install_order : 2; /**< Order in which GTK keys are added */
bool set: 1; /**< Group Transient Key set (valid value) */
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 */
bool updated: 1; /**< Group Transient Keys has been updated */
} sec_prot_gtk_keys_t;
// Security key data
@ -61,15 +76,32 @@ 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 */
uint8_t ptk_eui_64[8]; /**< 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 */
uint32_t pmk_lifetime; /**< PMK lifetime in seconds */
uint32_t ptk_lifetime; /**< PTK lifetime in seconds */
uint8_t gtkl; /**< Remote GTKL information */
int8_t gtk_set_index; /**< Index of GTK to set */
bool pmk_set: 1; /**< Pairwise Master Key set */
bool ptk_set: 1; /**< Pairwise Transient Key set */
bool pmk_key_replay_cnt_set: 1; /**< Pairwise Master Key replay counter set */
bool updated: 1; /**< Keys has been updated */
bool ptk_eui_64_set: 1; /**< Remote EUI-64 used to derive PTK is set */
bool pmk_mismatch: 1; /**< Remote PMK mismatch reported */
bool ptk_mismatch: 1; /**< Remote PTK mismatch reported */
} sec_prot_keys_t;
/*
* GTK mismatch types, list is ordered according to priority of mismatch i.e. if there
* are both hash and lifetime mismatch, hash has greater priority
*/
typedef enum {
GTK_NO_MISMATCH = 0,
GTK_LIFETIME_MISMATCH,
GTK_HASH_MISMATCH,
} gtk_mismatch_e;
/**
* sec_prot_keys_create allocates memory for security keys
*
@ -131,6 +163,14 @@ void sec_prot_keys_gtks_delete(sec_prot_gtk_keys_t *gtks);
*/
void sec_prot_keys_pmk_write(sec_prot_keys_t *sec_keys, uint8_t *pmk);
/**
* sec_prot_keys_pmk_delete deletes PMK
*
* \param sec_keys security keys
*
*/
void sec_prot_keys_pmk_delete(sec_prot_keys_t *sec_keys);
/**
* sec_prot_keys_pmk_get gets Pairwise Master Key
*
@ -168,6 +208,57 @@ void sec_prot_keys_pmk_replay_cnt_set(sec_prot_keys_t *sec_keys, uint64_t counte
*/
void sec_prot_keys_pmk_replay_cnt_increment(sec_prot_keys_t *sec_keys);
/**
* sec_prot_keys_pmk_replay_cnt_compare compares received replay counter value to PMK replay counter
*
* \param received_counter received replay counter
* \param sec_keys security keys
*
* \return TRUE received replay counter is valid
* \return FALSE received replay counter is not valid
*
*/
bool sec_prot_keys_pmk_replay_cnt_compare(uint64_t received_counter, sec_prot_keys_t *sec_keys);
/**
* sec_prot_keys_pmk_mismatch_set set PMK mismatch
*
* \param sec_keys security keys
*
*/
void sec_prot_keys_pmk_mismatch_set(sec_prot_keys_t *sec_keys);
/**
* sec_prot_keys_pmk_mismatch_reset reset PMK mismatch
*
* \param sec_keys security keys
*
*/
void sec_prot_keys_pmk_mismatch_reset(sec_prot_keys_t *sec_keys);
/**
* sec_prot_keys_pmk_mismatch_is_set check if PMK mismatch is set
*
* \param sec_keys security keys
*
* \return TRUE or FALSE
*
*/
bool sec_prot_keys_pmk_mismatch_is_set(sec_prot_keys_t *sec_keys);
/**
* sec_prot_keys_pmk_lifetime_decrement decrements PMK lifetime
*
* \param sec_keys security keys
* \param default_lifetime default lifetime for PMK
* \param seconds elapsed seconds
*
* \return true PMK expired and deleted both PMK and PTK
* \return false PMK not expired
*
*/
bool sec_prot_keys_pmk_lifetime_decrement(sec_prot_keys_t *sec_keys, uint32_t default_lifetime, uint8_t seconds);
/**
* sec_prot_keys_ptk_write writes Pairwise Transient Key
*
@ -177,6 +268,14 @@ void sec_prot_keys_pmk_replay_cnt_increment(sec_prot_keys_t *sec_keys);
*/
void sec_prot_keys_ptk_write(sec_prot_keys_t *sec_keys, uint8_t *ptk);
/**
* sec_prot_keys_ptk_delete deletes PTK
*
* \param sec_keys security keys
*
*/
void sec_prot_keys_ptk_delete(sec_prot_keys_t *sec_keys);
/**
* sec_prot_keys_ptk_get gets Pairwise Transient Key
*
@ -188,13 +287,30 @@ void sec_prot_keys_ptk_write(sec_prot_keys_t *sec_keys, uint8_t *ptk);
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
* sec_prot_keys_ptk_mismatch_set set PTK mismatch
*
* \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);
void sec_prot_keys_ptk_mismatch_set(sec_prot_keys_t *sec_keys);
/**
* sec_prot_keys_ptk_mismatch_reset reset PTK mismatch
*
* \param sec_keys security keys
*
*/
void sec_prot_keys_ptk_mismatch_reset(sec_prot_keys_t *sec_keys);
/**
* sec_prot_keys_ptk_mismatch_is_set check if PTK mismatch is set
*
* \param sec_keys security keys
*
* \return TRUE or FALSE
*
*/
bool sec_prot_keys_ptk_mismatch_is_set(sec_prot_keys_t *sec_keys);
/**
* sec_prot_keys_ptk_eui_64_write writes PTK EUI-64
@ -203,7 +319,7 @@ void sec_prot_keys_ptk_eui_64_set(sec_prot_keys_t *sec_keys, uint8_t *eui_64);
* \param eui64 EUI-64
*
*/
void sec_prot_keys_ptk_eui_64_write(sec_prot_keys_t *sec_keys, uint8_t *eui_64);
void sec_prot_keys_ptk_eui_64_write(sec_prot_keys_t *sec_keys, const uint8_t *eui_64);
/**
* sec_prot_keys_ptk_eui_64_get gets PTK EUI-64
@ -215,6 +331,27 @@ void sec_prot_keys_ptk_eui_64_write(sec_prot_keys_t *sec_keys, uint8_t *eui_64);
*/
uint8_t *sec_prot_keys_ptk_eui_64_get(sec_prot_keys_t *sec_keys);
/**
* sec_prot_keys_ptk_eui_64_delete deletes PTK EUI-64
*
* \param sec_keys security keys
*
*/
void sec_prot_keys_ptk_eui_64_delete(sec_prot_keys_t *sec_keys);
/**
* sec_prot_keys_ptk_lifetime_decrement decrements PTK lifetime
*
* \param sec_keys security keys
* \param default_lifetime default lifetime for PTK
* \param seconds elapsed seconds
*
* \return true PTK expired and deleted
* \return false PTK not expired
*
*/
bool sec_prot_keys_ptk_lifetime_decrement(sec_prot_keys_t *sec_keys, uint32_t default_lifetime, uint8_t seconds);
/**
* sec_prot_keys_are_updated returns security keys have been updated flag
*
@ -230,81 +367,111 @@ bool sec_prot_keys_are_updated(sec_prot_keys_t *sec_keys);
*
* \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
* sec_prot_keys_fresh_gtkl_get gets GTK liveness based on GTK status fields
*
* \param gtks GTK keys
*
* \return bit field indicating GTK liveness
*
*/
uint8_t sec_prot_keys_gtkl_get(sec_prot_gtk_keys_t *gtks);
uint8_t sec_prot_keys_fresh_gtkl_get(sec_prot_gtk_keys_t *gtks);
/**
* sec_prot_keys_gtkl_set sets Group Transient Key liveness
* sec_prot_keys_gtkl_set sets GTK liveness storage
*
* \param gtks GTK keys
* \param sec_keys security keys
* \param gtkl bit field indicating GTK liveness
*
*/
void sec_prot_keys_gtkl_set(sec_prot_gtk_keys_t *gtks, uint8_t gtkl);
void sec_prot_keys_gtkl_set(sec_prot_keys_t *sec_keys, uint8_t gtkl);
/**
* sec_prot_keys_gtk_is_live checks if Group Transient Key is live
* sec_prot_keys_gtkl_set checks whether GTK is live on GTK liveness storage
*
* \param gtks GTK keys
* \param index GTK index
* \param sec_keys security keys
* \param index index of the GTK which liveness is returned
*
* \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);
bool sec_prot_keys_gtkl_gtk_is_live(sec_prot_keys_t *sec_keys, uint8_t index);
/**
* sec_prot_keys_gtkl_gtk_live_set sets that GTK is live to GTK liveness storage
*
* \param sec_keys security keys
* \param index index of the GTK which is set live
*
* \return < 0 failure
* \return >= 0 success
*
*/
int8_t sec_prot_keys_gtkl_gtk_live_set(sec_prot_keys_t *sec_keys, uint8_t index);
/**
* sec_prot_keys_gtk_insert_index_set sets index of GTK to be inserted
*
* \param gtks GTK keys
* \param sec_keys security 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);
int8_t sec_prot_keys_gtk_insert_index_set(sec_prot_keys_t *sec_keys, uint8_t index);
/**
* sec_prot_keys_gtk_insert_index_get gets index of GTK to be inserted
*
* \param gtks GTK keys
* \param sec_keys security 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);
int8_t sec_prot_keys_gtk_insert_index_get(sec_prot_keys_t *sec_keys);
/**
* sec_prot_keys_gtk_insert_index_clear clears the index of GTK to be inserted
*
* \param gtks GTK keys
* \param sec_keys security keys
*
*/
void sec_prot_keys_gtk_insert_index_clear(sec_prot_gtk_keys_t *gtks);
void sec_prot_keys_gtk_insert_index_clear(sec_prot_keys_t *sec_keys);
/**
* sec_prot_keys_gtkl_from_gtk_insert_index_set sets inserted GTK as live to GTK liveness storage
*
* \param sec_keys security keys
*
*/
void sec_prot_keys_gtkl_from_gtk_insert_index_set(sec_prot_keys_t *sec_keys);
/**
* sec_prot_keys_gtk_insert_index_from_gtkl_get gets inserted GTK based on GTK liveness storage
*
* \param sec_keys security keys
*
* \return >= 0 GTK index
* \return < 0 no GTK to be inserted
*
*/
int8_t sec_prot_keys_gtk_insert_index_from_gtkl_get(sec_prot_keys_t *sec_keys);
/**
* sec_prot_keys_get_gtk_to_insert gets GTK that is marked to be inserted
*
* \param gtks GTK keys
* \param sec_keys security 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);
uint8_t *sec_prot_keys_get_gtk_to_insert(sec_prot_keys_t *sec_keys, uint8_t *index);
/**
* sec_prot_keys_gtk_set sets Group Transient Key
@ -312,12 +479,25 @@ uint8_t *sec_prot_keys_get_gtk_to_insert(sec_prot_gtk_keys_t *gtks, uint8_t *ind
* \param gtks GTK keys
* \param index index
* \param gtk gtk value
* \param lifetime GTK lifetime
*
* \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);
int8_t sec_prot_keys_gtk_set(sec_prot_gtk_keys_t *gtks, uint8_t index, uint8_t *gtk, uint32_t lifetime);
/**
* sec_prot_keys_gtk_clear clears Group Transient Key
*
* \param gtks GTK keys
* \param index index
*
* \return < 0 failure
* \return >= 0 success
*
*/
int8_t sec_prot_keys_gtk_clear(sec_prot_gtk_keys_t *gtks, uint8_t index);
/**
* sec_prot_keys_gtk_is_set checks if Group Transient Key is set
@ -353,14 +533,16 @@ uint8_t *sec_prot_keys_gtk_get(sec_prot_gtk_keys_t *gtks, uint8_t index);
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
* sec_prot_keys_gtk_lifetime_decrement decrements GTK lifetime
*
* \param gtks GTK keys
* \param index index
* \param lifetime GTK lifetime
* \param index index for GTK
* \param seconds elapsed seconds
*
* \return new GTK lifetime
*
*/
void sec_prot_keys_gtk_lifetime_set(sec_prot_gtk_keys_t *gtks, uint8_t index, uint32_t lifetime);
uint32_t sec_prot_keys_gtk_lifetime_decrement(sec_prot_gtk_keys_t *gtks, uint8_t index, uint16_t seconds);
/**
* sec_prot_keys_gtks_are_updated returns GTKs have been updated flag
@ -390,4 +572,163 @@ void sec_prot_keys_gtks_updated_set(sec_prot_gtk_keys_t *gtks);
*/
void sec_prot_keys_gtks_updated_reset(sec_prot_gtk_keys_t *gtks);
/**
* sec_prot_keys_gtk_status_fresh_set sets GTK as status fresh (if GTK status new)
*
* \param gtks GTK keys
* \param index index
*
*/
void sec_prot_keys_gtk_status_fresh_set(sec_prot_gtk_keys_t *gtks, uint8_t index);
/**
* sec_prot_keys_gtk_status_fresh_set sets all GTK statuses fresh (if GTK status new)
*
* \param gtks GTK keys
*
*/
void sec_prot_keys_gtk_status_all_fresh_set(sec_prot_gtk_keys_t *gtks);
/**
* sec_prot_keys_gtk_status_active_set sets fresh GTK to active, and currently active as old
*
* \param gtks GTK keys
* \param index index
*
* \return < 0 failure
* \return >= 0 success
*
*/
int8_t sec_prot_keys_gtk_status_active_set(sec_prot_gtk_keys_t *gtks, uint8_t index);
/**
* sec_prot_keys_gtk_status_active_get gets active GTK
*
* \param gtks GTK keys
*
* \return >= 0 GTK index
* \return < 0 no active GTK
*
*/
int8_t sec_prot_keys_gtk_status_active_get(sec_prot_gtk_keys_t *gtks);
/**
* sec_prot_keys_gtk_status_is_live checks whether GTK is active
*
* \param gtks GTK keys
* \param index index
*
* \return TRUE active, FALSE non active
*
*/
bool sec_prot_keys_gtk_status_is_live(sec_prot_gtk_keys_t *gtks, uint8_t index);
/**
* sec_prot_keys_gtks_hash_generate generate GTK hash based on all GTKs
*
* \param gtks GTK keys
* \param gtk_hash GTK hash
*
*/
void sec_prot_keys_gtks_hash_generate(sec_prot_gtk_keys_t *gtks, uint8_t *gtk_hash);
/**
* sec_prot_keys_gtks_hash_update update GTKs based on GTK hash
*
* \param gtks GTK keys
* \param gtk_hash GTK hash
*
* \return GTK mismatch type or no mismatch
*
*/
gtk_mismatch_e sec_prot_keys_gtks_hash_update(sec_prot_gtk_keys_t *gtks, uint8_t *gtkhash);
/**
* sec_prot_keys_gtk_hash_empty checks if GTK hash field is empty
*
* \param gtk_hash GTK hash
*
* \return TRUE GTK hash is empty, FALSE GTK hash is set
*
*/
bool sec_prot_keys_gtk_hash_empty(uint8_t *gtkhash);
/**
* sec_prot_keys_gtk_install_order_last_get gets install order of the last GTK to be installd
*
* \param gtks GTK keys
*
* \return install order
*
*/
int8_t sec_prot_keys_gtk_install_order_last_get(sec_prot_gtk_keys_t *gtks);
/**
* sec_prot_keys_gtk_install_order_last_get gets GTK that is to be installed last
*
* \param gtks GTK keys
*
* \return GTK index
*
*/
int8_t sec_prot_keys_gtk_install_order_last_index_get(sec_prot_gtk_keys_t *gtks);
/**
* sec_prot_keys_gtk_install_order_last_lifetime_get gets lifetime of the GTK that is to be installed last
*
* \param gtks GTK keys
*
* \return lifetime
*
*/
uint32_t sec_prot_keys_gtk_install_order_last_lifetime_get(sec_prot_gtk_keys_t *gtks);
/**
* sec_prot_keys_gtk_install_order_first_index_get gets index of the GTK that is to be installed first
*
* \param gtks GTK keys
*
* \return GTK index
*
*/
int8_t sec_prot_keys_gtk_install_order_first_index_get(sec_prot_gtk_keys_t *gtks);
/**
* sec_prot_keys_gtk_install_order_second_index_get gets index of the GTK that is to be installed second first
*
* \param gtks GTK keys
*
* \return GTK index
*
*/
int8_t sec_prot_keys_gtk_install_order_second_index_get(sec_prot_gtk_keys_t *gtks);
/**
* sec_prot_keys_gtk_install_order_update updates install order (if GTKs are removed set the order back)
*
* \param gtks GTK keys
*
*/
void sec_prot_keys_gtk_install_order_update(sec_prot_gtk_keys_t *gtks);
/**
* sec_prot_keys_gtk_install_index_get gets a free index for GTK to be installed
*
* \param gtks GTK keys
*
* \return GTK index
*
*/
int8_t sec_prot_keys_gtk_install_index_get(sec_prot_gtk_keys_t *gtks);
/**
* sec_prot_keys_gtk_count counts GTK keys
*
* \param gtks GTK keys
*
* \return count of keys, 0 for no keys
*
*/
uint8_t sec_prot_keys_gtk_count(sec_prot_gtk_keys_t *gtks);
#endif /* SEC_PROT_KEYS_H_ */

View File

@ -38,6 +38,7 @@
#include "Service_Libs/ieee_802_11/ieee_802_11.h"
#include "Service_Libs/hmac/hmac_sha1.h"
#include "Service_Libs/nist_aes_kw/nist_aes_kw.h"
#include "mbedtls/sha256.h"
#ifdef HAVE_WS
@ -53,7 +54,7 @@ void sec_prot_init(sec_prot_common_t *data)
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) {
if (data->trickle_running && trickle_params) {
bool running = trickle_running(&data->trickle_timer, trickle_params);
// Checks for trickle timer expiration */
@ -108,9 +109,16 @@ void sec_prot_state_set(sec_prot_t *prot, sec_prot_common_t *data, uint8_t state
return;
case SEC_STATE_FINISHED:
// If not already on finished state
if (data->state != SEC_STATE_FINISHED) {
// Wait for timeout
data->trickle_running = false;
data->ticks = SEC_FINISHED_TIMEOUT;
}
data->trickle_running = false;
// Disables receiving of messages when state machine sets SEC_STATE_FINISHED
prot->receive_disable(prot);
// Clear result
sec_prot_result_set(data, SEC_RESULT_OK);
break;
@ -159,22 +167,10 @@ bool sec_prot_result_ok_check(sec_prot_common_t *data)
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
// 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
}
/*
@ -285,10 +281,11 @@ int8_t sec_prot_lib_pmkid_calc(const uint8_t *pmk, const uint8_t *auth_eui64, co
ptr += EUI64_LEN;
memcpy(ptr, supp_eui64, EUI64_LEN);
if (hmac_sha1_calc(pmk, PMK_LEN, data, data_len, pmkid) < 0) {
if (hmac_sha1_calc(pmk, PMK_LEN, data, data_len, pmkid, PMKID_LEN) < 0) {
return -1;
}
tr_info("PMKID %s EUI-64 %s %s", trace_array(pmkid, PMKID_LEN), trace_array(auth_eui64, 8), trace_array(supp_eui64, 8));
return 0;
}
@ -306,10 +303,11 @@ int8_t sec_prot_lib_ptkid_calc(const uint8_t *ptk, const uint8_t *auth_eui64, co
ptr += EUI64_LEN;
memcpy(ptr, supp_eui64, EUI64_LEN);
if (hmac_sha1_calc(ptk, PTK_LEN, data, data_len, ptkid) < 0) {
if (hmac_sha1_calc(ptk, PTK_LEN, data, data_len, ptkid, PTKID_LEN) < 0) {
return -1;
}
tr_info("PTKID %s EUI-64 %s %s", trace_array(ptkid, PTKID_LEN), trace_array(auth_eui64, 8), trace_array(supp_eui64, 8));
return 0;
}
@ -337,7 +335,7 @@ uint8_t *sec_prot_lib_message_build(uint8_t *ptk, uint8_t *kde, uint16_t kde_len
if (eapol_pdu->msg.key.key_information.key_mic) {
uint8_t mic[EAPOL_KEY_MIC_LEN];
if (hmac_sha1_calc(ptk, KCK_LEN, eapol_pdu_frame + header_size, eapol_pdu_size, mic) < 0) {
if (hmac_sha1_calc(ptk, KCK_LEN, eapol_pdu_frame + header_size, eapol_pdu_size, mic, EAPOL_KEY_MIC_LEN) < 0) {
ns_dyn_mem_free(eapol_pdu_frame);
return NULL;
}
@ -362,6 +360,7 @@ uint8_t *sec_prot_lib_message_handle(uint8_t *ptk, uint16_t *kde_len, eapol_pdu_
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) {
tr_error("Decrypt failed");
ns_dyn_mem_free(kde);
return NULL;
}
@ -373,42 +372,40 @@ uint8_t *sec_prot_lib_message_handle(uint8_t *ptk, uint16_t *kde_len, eapol_pdu_
return kde;
}
int8_t sec_prot_lib_gtk_read(uint8_t *kde, uint16_t kde_len, sec_prot_gtk_keys_t *gtks)
int8_t sec_prot_lib_gtk_read(uint8_t *kde, uint16_t kde_len, sec_prot_keys_t *sec_keys)
{
// If a valid new GTK value present, insert it
int8_t gtk_set_index = -1;
int8_t gtk_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 = 0;
if (kde_lifetime_read(kde, kde_len, &lifetime) >= 0) {
}
uint32_t lifetime;
if (kde_lifetime_read(kde, kde_len, &lifetime) >= 0) {
sec_prot_keys_gtk_lifetime_set(gtks, key_id, lifetime);
// A new GTK value
if (sec_prot_keys_gtk_set(sec_keys->gtks, key_id, gtk, lifetime) >= 0) {
gtk_index = (int8_t) key_id; // Insert
}
}
uint8_t gtkl;
if (kde_gtkl_read(kde, kde_len, &gtkl) >= 0) {
sec_prot_keys_gtkl_set(gtks, gtkl);
sec_prot_keys_gtkl_set(sec_keys, gtkl);
} else {
tr_error("No GTKL");
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_index >= 0) {
if (!sec_prot_keys_gtkl_gtk_is_live(sec_keys, gtk_index)) {
tr_error("mismatch between GTK and GTKL");
}
}
if (gtk_set_index >= 0) {
sec_prot_keys_gtk_insert_index_set(gtks, gtk_set_index);
}
tr_info("GTK recv index %i lifetime %"PRIu32"", gtk_index, sec_prot_keys_gtk_lifetime_get(sec_keys->gtks, gtk_index));
return 0;
}
@ -421,45 +418,36 @@ int8_t sec_prot_lib_mic_validate(uint8_t *ptk, uint8_t *mic, uint8_t *pdu, uint8
eapol_write_key_packet_mic(pdu, 0);
uint8_t calc_mic[EAPOL_KEY_MIC_LEN];
if (hmac_sha1_calc(ptk, EAPOL_KEY_MIC_LEN, pdu, pdu_size, calc_mic) < 0) {
if (hmac_sha1_calc(ptk, EAPOL_KEY_MIC_LEN, pdu, pdu_size, calc_mic, EAPOL_KEY_MIC_LEN) < 0) {
tr_error("MIC invalid");
return -1;
}
if (memcmp(recv_mic, calc_mic, EAPOL_KEY_MIC_LEN) != 0) {
tr_error("MIC invalid");
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;
}
uint8_t local_eui64[8];
uint8_t remote_eui64[8];
// Tries to get the EUI-64 that is validated by PTK procedure or bound to supplicant entry
uint8_t *remote_eui64_ptr = sec_prot_keys_ptk_eui_64_get(prot->sec_keys);
if (remote_eui64_ptr) {
memcpy(remote_eui64, remote_eui64_ptr, 8);
prot->addr_get(prot, local_eui64, NULL);
} else {
// If validated EUI-64 is not present, use the remote EUI-64
prot->addr_get(prot, local_eui64, remote_eui64);
}
if (is_auth) {
return sec_prot_lib_pmkid_calc(pmk, local_eui64, remote_eui64, pmkid);
} else {
@ -470,12 +458,16 @@ int8_t sec_prot_lib_pmkid_generate(sec_prot_t *prot, uint8_t *pmkid, bool is_aut
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);
prot->addr_get(prot, local_eui64, NULL);
uint8_t *ptk = sec_prot_keys_pmk_get(prot->sec_keys);
if (!ptk) {
return -1;
}
// Uses always the EUI-64 that is validated by PTK procedure or bound to supplicant entry
uint8_t *remote_eui64 = sec_prot_keys_ptk_eui_64_get(prot->sec_keys);
if (!remote_eui64) {
return -1;
}
if (is_auth) {
return sec_prot_lib_ptkid_calc(ptk, local_eui64, remote_eui64, ptkid);
@ -484,5 +476,46 @@ int8_t sec_prot_lib_ptkid_generate(sec_prot_t *prot, uint8_t *ptkid, bool is_aut
}
}
int8_t sec_prot_lib_gtkhash_generate(uint8_t *gtk, uint8_t *gtk_hash)
{
int8_t ret_val = 0;
mbedtls_sha256_context ctx;
mbedtls_sha256_init(&ctx);
if (mbedtls_sha256_starts_ret(&ctx, 0) != 0) {
ret_val = -1;
goto error;
}
if (mbedtls_sha256_update_ret(&ctx, gtk, 16) != 0) {
ret_val = -1;
goto error;
}
uint8_t output[32];
if (mbedtls_sha256_finish_ret(&ctx, output) != 0) {
ret_val = -1;
goto error;
}
memcpy(gtk_hash, &output[24], 8);
error:
mbedtls_sha256_free(&ctx);
return ret_val;
}
uint8_t *sec_prot_remote_eui_64_addr_get(sec_prot_t *prot)
{
if (prot->sec_keys && prot->sec_keys->ptk_eui_64_set) {
return prot->sec_keys->ptk_eui_64;
} else {
return NULL;
}
}
#endif /* HAVE_WS */

Some files were not shown because too many files have changed in this diff Show More