Squashed 'features/nanostack/sal-stack-nanostack/' changes from cc03296c27..b3fe5744d1

b3fe5744d1 Remove test files from the release
b2bf24ca85 Merge branch 'release_internal' into release_external
0ed25a7485 Fix errors found from coverity scan (#2386)
7a138f7e51 Added IID for border router info structure
4021b0c1ef LLC secure data duplicate check update and EAPOL relay duplicate fix
b190a97eeb Remove Thread-protocol from README (#2383)
ae8ae32cfe EAPOL relay agent rx filter from joiner side
0d4eb7a46e Removed dead code part
fc644f5e5b RPL new parent accept update and NUD operation
f5920e2d0c ETX API update and RPL ETX threshold callback update.
1fdee20a40 Wi-sun keep all candidates alive by NUD.
bd746da33d Key storage settings are no longer cleared on delete
bd388fcb08 Changed EAPOL initial-Key retries from 2 to 4 on large NW
a3d80a3235 WS bootstrap: Default CCA threshold to -60dBm (#2377)
72b26a72c2 Created extra large network setup for Wi-SUN
38dd4a6423 Corrected PTK and PMK lifetime handling
64f2a77239 Cleared EAPOL temporary trace print's.
02ec23fa27 Timed parent selection is now imim-imin*2 earlier there was just 5 seconds randomize.
3b2d906b75 Added check for network name and DODAG ID IID (EUI-64) (#2373)
ee45f4be32 Updated initial key trickles
184425b038 Fixed parent target address set.
07ec2374a1 Updated Discovery and RPL setup large & medium size network
a94d8f2e5d RPL version num update
9e2ac1d855 Double default eapol entry size for test purpose.
6b8beefb51 Clear all neighbors only on eapol next target check
faa19e1fba Corrected next address set
8a917fb9a5 Continue trickle on initial EAPOL-key TX failure
cfdb193c3e Merge pull request #2368 from ARMmbed/sync_with_mbedos
f7a15fa68d (via MbedOS) ws: added support for brazilian regulatory domain
c397edb121 Changed large network initial-key trickle parameters
758f5347b5 Added maximum frame counter storing interval
b0ea148d41 Corrected key storage configuration setting
be3c94e03b WS RPL paret soft filter update
8b1d537a02 Adjusted EAPOL limits and timers
9a2166869f Merge branch 'release_internal' into release_external
8e72b80826 MAC CCA thr: Check if channel out of range (#2363)
146a0a38c2 Corrected trace on authenticator
d04a96dd48 Merge pull request #2361 from ARMmbed/sync_with_mbedos
2c2b915198 Added empty function for ns time callback
76ac0decce Remove NCS36510 target
0258ac3197 Remove KW24D target
788f01b93d Netsocket/lwIP Stack: Remove support for ARM Compiler 5
2fbc7a1c4f Corrected invalid memory read on access revoke
941b9b42dc Updates to stagger/latency (#2358)
c2abaaafba Corrected defects
1811194bf2 Corrected warning trace, validations and ut stubs
69e2d1989e Added NS filesystem and interface to application
c5b6993ddd refactored packet ingress
a05605eca3 Unsecured packets will be acked by default automatically.
36dfb2924f MAC: Implemented automatic CCA threshold (#2353)
0396b9738c Revert EAPOL simplify failure handling and focus this problem later on.
b2fe3d49db Ignoring authentication failure if security protocol already started
11de56dad8 Added info API for Wi-SUN border router
87a4f691fe Added EAPOL key storage to authenticator and unified GTK storage (#2345)
ff1ca25ed7 EAPOL failure simplify and EAPOL relay agent add trace when eapol temp pool is empty
6667b31ae8 Update NA trace
34cdafe214 Temporary EAPOL neighbour entry Update and MAC MLME update
d092f833a8 Iotthd 3995 (#2347)
e2ea4e41f7 Disabled BR (TLS server) EC calculation queue
575985190d Changed the rate limiting function to calculate the values runtime
899e75510b Make it possible to update tr51 table to larger dynamically
8436669c10 Added configuration for DHCP lifetime value
da732bc28e When network name or PAN ID is changed authenticator updates MAC keys

git-subtree-dir: features/nanostack/sal-stack-nanostack
git-subtree-split: b3fe5744d1ab20792223ff08f08ef97a1f89682b
pull/13082/head^2
Arto Kinnunen 2020-06-08 15:41:19 +03:00
parent e357a4329c
commit 93c77e8362
101 changed files with 5642 additions and 1409 deletions

View File

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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.9 KiB

View File

@ -9,12 +9,6 @@
},
"macros": ["NS_USE_EXTERNAL_MBED_TLS"],
"target_overrides": {
"KW24D": {
"nanostack.configuration": "lowpan_router"
},
"NCS36510": {
"nanostack.configuration": "lowpan_router"
},
"TB_SENSE_12": {
"nanostack.configuration": "lowpan_router"
},

View File

@ -88,6 +88,16 @@ typedef struct fhss_configuration {
*/
typedef int32_t fhss_vendor_defined_cf(const fhss_api_t *api, uint16_t slot, uint8_t eui64[8], uint16_t bsi, uint16_t number_of_channels);
/**
* \brief Struct fhss_config_parameters defines FHSS configuration parameters.
*
*/
typedef struct fhss_config_parameters {
/** Number of channel retries defines how many consecutive channels are used when retransmitting a frame after initial transmission channel. */
uint8_t number_of_channel_retries;
} fhss_config_parameters_t;
/**
* \brief Struct fhss_ws_configuration defines configuration of WS FHSS.
*/
@ -125,6 +135,9 @@ typedef struct fhss_ws_configuration {
/** Vendor defined channel function. */
fhss_vendor_defined_cf *vendor_defined_cf;
/** Configuration parameters. */
fhss_config_parameters_t config_parameters;
} fhss_ws_configuration_t;
/**

View File

@ -39,6 +39,17 @@ extern "C" {
*/
int8_t fhss_set_optimal_packet_length(const fhss_api_t *fhss_api, uint16_t packet_length);
/**
* \brief Set number of channel retries
*
* \param fhss_api FHSS instance.
* \param number_of_channel_retries Number of channel retries
*
* \return 0 Success
* \return -1 Failure
*/
int8_t fhss_set_number_of_channel_retries(const fhss_api_t *fhss_api, uint8_t number_of_channel_retries);
#ifdef __cplusplus
}
#endif

View File

@ -264,6 +264,8 @@ typedef enum {
macAutoRequestKeyIndex = 0x7b, /*<The index of the key used for automatic data*/
macDefaultKeySource = 0x7c, /*<Default key source*/
//NON standard extension
macCCAThresholdStart = 0xf4, /*< Start automatic CCA threshold */
macDevicePendingAckTrig = 0xf5, /*< Trig Pending ACK for Accepted Data packet for temporary neighbour */
mac802_15_4Mode = 0xf6, /*<IEEE 802.15.4 mode*/
macDeviceDescriptionPanIDUpdate = 0xf7, /*<Thread pending link update case this will update device descrioton list pan-id to new one*/
macTXPower = 0xf8, /*<TX output power*/

View File

@ -50,6 +50,109 @@ int ns_file_system_set_root_path(const char *root_path);
*/
char *ns_file_system_get_root_path(void);
/**
* \brief NS file handle
*
*/
typedef void *NS_FILE;
/**
* File open callback
*
* Depending on underlying file system file open for read for non-existing
* files can return success. In that case file read will fail.
*
* \param filename filename
* \param mode can be either "r" or "w"
*
* \return file handle
* \return NULL on error
*
*/
typedef NS_FILE(*ns_file_open)(const char *filename, const char *mode);
/**
* File close callback
*
* \param handle file handle
*
* \return 0 on success
* \return < 0 in case of errors
*
*/
typedef int (*ns_file_close)(NS_FILE *handle);
/**
* File remove callback
*
* \param filename filename
*
* \return 0 on success
* \return < 0 in case of errors
*
*/
typedef int (*ns_file_remove)(const char *filename);
/**
* File write callback
*
* Write is not stream write. The whole file is written from start to end
* and if function is called again, previous file content is replaced with
* new content.
*
* \param handle file handle
* \param buffer buffer
* \param buffer buffer size
*
* \return bytes written
*
*/
typedef size_t (*ns_file_write)(NS_FILE *handle, const void *buffer, size_t size);
/**
* File read callback
*
* Read is not stream read. The whole file is read from start to end
* and if function is called again, read is started from start again.
*
* \param handle file handle
* \param buffer buffer
* \param size buffer size
*
* \return bytes written
*
*/
typedef size_t (*ns_file_read)(NS_FILE *handle, void *buffer, size_t size);
/**
* File size callback
*
* Reads file size.
*
* \param handle file handle
* \param size file size
*
* \return 0 on success
* \return < 0 in case of reading file size is not supported
*
*/
typedef int (*ns_file_size)(NS_FILE *handle, size_t *size);
/**
* File callbacks set
*
* Sets file handling callbacks to nanostack.
*
* \param open file open callback
* \param close file close callback
* \param remove file remove callback
* \param write file write callback
* \param read file read callback
* \param size file size callback
*
*/
void ns_file_system_callbacks_set(ns_file_open open, ns_file_close close, ns_file_remove remove, ns_file_write write, ns_file_read read, ns_file_size size);
#ifdef __cplusplus
}
#endif

51
nanostack/ns_time_api.h Normal file
View File

@ -0,0 +1,51 @@
/*
* Copyright (c) 2020, Arm Limited and affiliates.
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* \file ns_time_api.h
* \brief Nanostack time API
*
* This is Nanostack time API.
*
*/
#ifndef NS_TIME_API_H_
#define NS_TIME_API_H_
#include "ns_types.h"
/**
* System time callback.
*
* Callback shall return the system time in seconds after 1970.
*
* \param seconds system time in seconds
*
*/
typedef uint64_t ns_time_api_system_time_callback(void);
/**
* System time callback set.
*
* Sets callback for the system time.
*
* \param callback system time callback
*
*/
void ns_time_api_system_time_callback_set(ns_time_api_system_time_callback callback);
#endif /* NS_TIME_API_H_ */

View File

@ -80,6 +80,7 @@ typedef enum {
PHY_EXTENSION_FILTERING_SUPPORT, /**< Return filtering modes that can be supported by the PHY driver. See phy_link_filters_e */
PHY_EXTENSION_SET_TX_POWER, /**< Set TX output power which is given as percentage of maximum. 0 is the lowest possible TX power and 100 is the highest possible TX power */
PHY_EXTENSION_SET_CCA_THRESHOLD, /**< Set CCA threshold which is given as percentage of maximum threshold. 0 is the lowest(strictest) possible threshold and 100 is the highest possible threshold */
PHY_EXTENSION_SET_CHANNEL_CCA_THRESHOLD, /**< Set CCA threshold which is given as dBm. This value is set in PHY_LINK_CCA_PREPARE callback and PHY driver should update the CCA threshold configuration */
PHY_EXTENSION_SET_802_15_4_MODE /**< Set IEEE 802.15.4 mode as defined by phy_802_15_4_mode_t*/
} phy_extension_type_e;

View File

@ -30,6 +30,36 @@
#include "ns_types.h"
/**
* \brief Struct ws_statistics Border router dynamic information.
*/
typedef struct bbr_information {
/** Timestamp of the the device. Can be used as version number*/
uint64_t timestamp;
/** Border router dodag id */
uint8_t dodag_id[16];
/** Address prefix given to devices in network set to 0 if not available*/
uint8_t prefix[8];
/** Address IID of the border router set to 0 if not available*/
uint8_t IID[8];
/** Amount of devices in the network. */
uint16_t devices_in_network;
/** Border router instance identifier defined in RPL */
uint8_t instance_id;
/** RPL version number */
uint8_t version;
} bbr_information_t;
/**
* \brief Struct route_info is parent child relation structure.
*/
typedef struct bbr_route_info {
/** IID of target device public IPv6 address can be formed by combining prefix + IID*/
uint8_t target[8];
/** IID of parent*/
uint8_t parent[8];
} bbr_route_info_t;
/**
* Start backbone border router service.
*
@ -83,6 +113,49 @@ int ws_bbr_configure(int8_t interface_id, uint16_t options);
*/
void ws_bbr_stop(int8_t interface_id);
/**
* Get border router information
*
* \param interface_id interface ID of the Wi-SUN network
* \param info_ptr Structure given to stack where information is stored
*
* \return 0 on success
* \return <0 in case of errors
*
*/
int ws_bbr_info_get(int8_t interface_id, bbr_information_t *info_ptr);
/**
* Routing table get
*
* Table is Parent child relation using the Global address IID of the devices
* To get the full IPv6 address of the device.
* IPv6 = Global Prefix + IID.
*
* Routing table is in the format: 18 bytes per entry
* | Node IID 8 bytes | parent IID 8 bytes |
* | 1122112211221122 | 1111111111111111 |
* | 1133113311331133 | 1111111111111111 |
* | 1144114411441144 | 1111111111111111 |
* | 1155115511551155 | 1122112211221122 |
* | 1166116611661166 | 1122112211221122 |
* | 1177117711771177 | 1155115511551155 |
* | 1188118811881188 | 1177117711771177 |
*
* Order is not assured only parent child link is given in random order
*
* Return value is device amount in network divided by 16 bytes per route entry
*
* \param interface_id interface ID of the Wi-SUN network
* \param table_ptr Application allocated memory block where routing table is written.
* \param table_len Length of the table allocated by application given as amount of entries.
*
* \return 0 - x on success indicates amount of bytes written to the table_ptr
* \return <0 in case of errors
*
*/
int ws_bbr_routing_table_get(int8_t interface_id, bbr_route_info_t *table_ptr, uint16_t table_len);
/**
* Remove node's keys from border router
*
@ -243,4 +316,40 @@ int ws_bbr_pan_configuration_get(int8_t interface_id, uint16_t *pan_id);
*/
int ws_bbr_pan_configuration_validate(int8_t interface_id, uint16_t pan_id);
/**
* ws_bbr_key_storage_memory_set sets memory used for key storages
*
* This functions can be used to set memory used by EAPOL key storage. When memory
* areas are set, module does not allocate memory internally from heap.
*
* \param interface_id Network interface ID.
* \param key_storages_number number of memory areas.
* \param key_storage_size array of memory area sizes.
* \param key_storages array of memory area start pointers.
*
* \return < 0 failure
* \return >= 0 success
*
*/
int ws_bbr_key_storage_memory_set(int8_t interface_id, uint8_t key_storages_number, const uint16_t *key_storage_size, void **key_storages);
/**
* ws_bbr_key_storage_settings_set sets key storage settings
*
* This functions can be used to set the settings of EAPOL key storage.
* Allocation max number and allocation size sets the settings that are used when key storage
* memory is allocated dynamically from heap. These settings must be set before (first) interface
* up and shall not be set if key storage memory is set by ws_pae_key_storage_memory_set() call.
*
* \param interface_id Network interface ID.
* \param alloc_max_number maximum number of allocation made to dynamic memory.
* \param alloc_size size of each allocation.
* \param storing_interval interval in which the check to store to NVM is made.
*
* \return < 0 failure
* \return >= 0 success
*
*/
int ws_bbr_key_storage_settings_set(int8_t interface_id, uint8_t alloc_max_number, uint16_t alloc_size, uint16_t storing_interval);
#endif /* WS_BBR_API_H_ */

View File

@ -75,10 +75,16 @@ extern "C" {
#define CHANNEL_SPACING_100 0x03 // 100 khz
#define CHANNEL_SPACING_250 0x04 // 250 khz
#define NETWORK_SIZE_CERTIFICATE 0x00
#define NETWORK_SIZE_SMALL 0x01
#define NETWORK_SIZE_MEDIUM 0x08
#define NETWORK_SIZE_LARGE 0x10
/*
* Network Size definitions are device amount in hundreds of devices.
* These definitions are meant to give some estimates of sizes. Any value can be given as parameter
*/
#define NETWORK_SIZE_CERTIFICATE 0x00 // Network configuration used in Wi-SUN certification
#define NETWORK_SIZE_SMALL 0x01 // Small networks
#define NETWORK_SIZE_MEDIUM 0x08 // 100 - 800 device networks are medium sized
#define NETWORK_SIZE_LARGE 0x0F // 800 - 1500 device networks are large
#define NETWORK_SIZE_XLARGE 0x19 // 2500+ devices
#define NETWORK_SIZE_AUTOMATIC 0xFF
/** Temporary API change flag. this will be removed when new version of API is implemented on applications
@ -229,9 +235,9 @@ int ws_management_regulatory_domain_validate(
*
* timing parameters follows the specification example from Wi-SUN specification
*
* Default value: medium
* small network size: hundreds of devices
* Large network size: thousands of devices
* Default value: medium 100 - 800 device
* small network size: less than 100 devices
* Large network size: 800 - 1500 devices
* automatic: when discovering the network network size is learned
* from advertisements and timings adjusted accordingly
*

View File

@ -83,6 +83,9 @@
#define TRACE_GROUP_LOWPAN "6lo"
#define TRACE_GROUP "6lo"
/* Data rate for application used in Stagger calculation */
#define STAGGER_DATARATE_FOR_APPL(n) ((n)*25/100)
#ifdef HAVE_RPL
rpl_domain_t *protocol_6lowpan_rpl_domain;
/* Having to sidestep old rpl_dodag_t type for the moment */
@ -800,7 +803,7 @@ bool protocol_6lowpan_latency_estimate_get(int8_t interface_id, uint32_t *latenc
latency_estimate = 100;
} else if (thread_info(cur_interface)) {
// thread network
latency_estimate = 1000;
latency_estimate = 2000;
} else if (ws_info(cur_interface)) {
latency_estimate = ws_common_latency_estimate_get(cur_interface);
} else {
@ -820,14 +823,13 @@ bool protocol_6lowpan_stagger_estimate_get(int8_t interface_id, uint32_t data_am
{
size_t network_size;
uint32_t datarate;
uint32_t stagger_value;
protocol_interface_info_entry_t *cur_interface = protocol_stack_interface_info_get_by_id(interface_id);
if (!cur_interface) {
return false;
}
*stagger_min = 1;
if (cur_interface->eth_mac_api) {
// either PPP or Ethernet interface.
network_size = 1;
@ -849,16 +851,25 @@ bool protocol_6lowpan_stagger_estimate_get(int8_t interface_id, uint32_t data_am
// If no data amount given, use 1kB
data_amount = 1;
}
/**Example:
* Maximum stagger value to send 1kB on 50 devices network using datarate 50000 kb/:
* (1 * 1024 * 8 * 50) / (50000/4)) = ~ 32s
*
* devices: 50, datarate: 250kbps => stagger ~ 6s
* devices: 1000, datarate: 50kbps => stagger ~ 655s
/*
* Do not occupy whole bandwidth, leave space for network formation etc...
*/
/* Do not occupy whole bandwidth, halve the theoretical datarate and reserve room for other channel usage */
datarate = datarate / 4;
*stagger_max = (uint16_t) * stagger_min + ((data_amount * 1024 * 8 * network_size) / datarate);
datarate = STAGGER_DATARATE_FOR_APPL(datarate);
stagger_value = 1 + ((data_amount * 1024 * 8 * network_size) / datarate);
/**
* Example:
* Maximum stagger value to send 1kB to 100 device network using data rate of 50kbs:
* 1 + (1 * 1024 * 8 * 100) / (50000*0.25) = 66s
*/
*stagger_min = stagger_value / 5; // Minimum stagger value is 1/5 of the max
if (stagger_value > 0xFFFF) {
*stagger_max = 0xFFFF;
} else {
*stagger_max = (uint16_t)stagger_value;
}
// Randomize stagger value
*stagger_rand = randLIB_get_random_in_range(*stagger_min, *stagger_max);

View File

@ -588,7 +588,7 @@ static void mle_neigh_entry_update_by_mle_tlv_list(int8_t interface_id, mac_neig
uint8_t link_idr;
uint8_t iop_flags;
if (mle_link_quality_tlv_parse(mac64, short_address, mle_tlv_info.dataPtr, mle_tlv_info.tlvLen, &iop_flags, &link_idr)) {
etx_remote_incoming_idr_update(interface_id, link_idr, entry_temp->index);
etx_remote_incoming_idr_update(interface_id, link_idr, entry_temp->index, entry_temp->mac64);
if ((iop_flags & MLE_NEIGHBOR_PRIORITY_LINK) == MLE_NEIGHBOR_PRIORITY_LINK) {
entry_temp->link_role = CHILD_NEIGHBOUR;
@ -965,9 +965,9 @@ int protocol_6lowpan_router_synch_to_new_router(protocol_interface_info_entry_t
static uint8_t mle_calculate_idr(int8_t interface_id, mle_message_t *mle_msg, mac_neighbor_table_entry_t *entry_temp)
{
if (!entry_temp) {
return etx_lqi_dbm_update(-2, mle_msg->lqi, mle_msg->dbm, 0) >> 3;
return etx_lqi_dbm_update(-2, mle_msg->lqi, mle_msg->dbm, 0, NULL) >> 3;
}
return etx_lqi_dbm_update(interface_id, mle_msg->lqi, mle_msg->dbm, entry_temp->index) >> 3;
return etx_lqi_dbm_update(interface_id, mle_msg->lqi, mle_msg->dbm, entry_temp->index, entry_temp->mac64) >> 3;
}
@ -1609,7 +1609,7 @@ static void lowpan_neighbor_entry_remove_notify(mac_neighbor_table_entry_t *entr
}
mac_helper_devicetable_remove(cur_interface->mac_api, entry_ptr->index, entry_ptr->mac64);
//Removes ETX neighbor
etx_neighbor_remove(cur_interface->id, entry_ptr->index);
etx_neighbor_remove(cur_interface->id, entry_ptr->index, entry_ptr->mac64);
//Remove MLE frame counter info
mle_service_frame_counter_entry_delete(cur_interface->id, entry_ptr->index);

View File

@ -900,11 +900,13 @@ void mac_helper_devicetable_remove(mac_api_t *mac_api, uint8_t attribute_index,
set_req.attr_index = attribute_index;
set_req.value_pointer = (void *)&device_desc;
set_req.value_size = sizeof(mlme_device_descriptor_t);
tr_debug("Unregister Device %u, mac64: %s", attribute_index, trace_array(mac64, 8));
if (mac64) {
tr_debug("Unregister Device %u, mac64: %s", attribute_index, trace_array(mac64, 8));
}
mac_api->mlme_req(mac_api, MLME_SET, &set_req);
}
void mac_helper_device_description_write(protocol_interface_info_entry_t *cur, mlme_device_descriptor_t *device_desc, uint8_t *mac64, uint16_t mac16, uint32_t frame_counter, bool exempt)
void mac_helper_device_description_write(protocol_interface_info_entry_t *cur, mlme_device_descriptor_t *device_desc, const uint8_t *mac64, uint16_t mac16, uint32_t frame_counter, bool exempt)
{
memcpy(device_desc->ExtAddress, mac64, 8);
device_desc->ShortAddress = mac16;
@ -914,14 +916,19 @@ void mac_helper_device_description_write(protocol_interface_info_entry_t *cur, m
}
void mac_helper_devicetable_set(const mlme_device_descriptor_t *device_desc, protocol_interface_info_entry_t *cur, uint8_t attribute_index, uint8_t keyID, bool force_set)
{
if (!cur->mac_api) {
if (!force_set && cur->mac_parameters->SecurityEnabled && cur->mac_parameters->mac_default_key_index != keyID) {
tr_debug("Do not set counter by index %u != %u", cur->mac_parameters->mac_default_key_index, keyID);
return;
}
if (!force_set && cur->mac_parameters->SecurityEnabled && cur->mac_parameters->mac_default_key_index != keyID) {
tr_debug("Do not set counter by index %u != %u", cur->mac_parameters->mac_default_key_index, keyID);
tr_debug("Register Device %u, mac16 %x mac64: %s, %"PRIu32, attribute_index, device_desc->ShortAddress, trace_array(device_desc->ExtAddress, 8), device_desc->FrameCounter);
mac_helper_devicetable_direct_set(cur->mac_api, device_desc, attribute_index);
}
void mac_helper_devicetable_direct_set(struct mac_api_s *mac_api, const mlme_device_descriptor_t *device_desc, uint8_t attribute_index)
{
if (!mac_api) {
return;
}
@ -930,7 +937,20 @@ void mac_helper_devicetable_set(const mlme_device_descriptor_t *device_desc, pro
set_req.attr_index = attribute_index;
set_req.value_pointer = (void *)device_desc;
set_req.value_size = sizeof(mlme_device_descriptor_t);
tr_debug("Register Device %u, mac16 %x mac64: %s, %"PRIu32, attribute_index, device_desc->ShortAddress, trace_array(device_desc->ExtAddress, 8), device_desc->FrameCounter);
mac_api->mlme_req(mac_api, MLME_SET, &set_req);
}
void mac_helper_devicetable_ack_trig(const mlme_device_descriptor_t *device_desc, protocol_interface_info_entry_t *cur)
{
if (!cur->mac_api) {
return;
}
mlme_set_t set_req;
set_req.attr = macDevicePendingAckTrig;
set_req.attr_index = 0;
set_req.value_pointer = (void *)device_desc;
set_req.value_size = sizeof(mlme_device_descriptor_t);
cur->mac_api->mlme_req(cur->mac_api, MLME_SET, &set_req);
}

View File

@ -121,9 +121,14 @@ int8_t mac_helper_key_link_frame_counter_set(int8_t interface_id, uint32_t seq_p
void mac_helper_devicetable_remove(struct mac_api_s *mac_api, uint8_t attribute_index, uint8_t *mac64);
void mac_helper_device_description_write(struct protocol_interface_info_entry *cur, mlme_device_descriptor_t *device_desc, uint8_t *mac64, uint16_t mac16, uint32_t frame_counter, bool exempt);
void mac_helper_device_description_write(struct protocol_interface_info_entry *cur, mlme_device_descriptor_t *device_desc, const uint8_t *mac64, uint16_t mac16, uint32_t frame_counter, bool exempt);
void mac_helper_devicetable_set(const mlme_device_descriptor_t *device_dec, struct protocol_interface_info_entry *cur, uint8_t attribute_index, uint8_t keyID, bool force_set);
void mac_helper_devicetable_direct_set(struct mac_api_s *mac_api, const mlme_device_descriptor_t *device_desc, uint8_t attribute_index);
void mac_helper_devicetable_ack_trig(const mlme_device_descriptor_t *device_desc, struct protocol_interface_info_entry *cur);
int8_t mac_helper_mac_mlme_max_retry_set(int8_t interface_id, uint8_t mac_retry_set);
int8_t mac_helper_mac_device_description_pan_id_update(int8_t interface_id, uint16_t pan_id);

View File

@ -141,7 +141,7 @@ static void thread_neighbor_remove(mac_neighbor_table_entry_t *entry_ptr, void *
thread_reset_neighbour_info(cur, entry_ptr);
//Removes ETX neighbor
etx_neighbor_remove(cur->id, entry_ptr->index);
etx_neighbor_remove(cur->id, entry_ptr->index, entry_ptr->mac64);
//Remove MLE frame counter info
mle_service_frame_counter_entry_delete(cur->id, entry_ptr->index);
}

View File

@ -34,7 +34,7 @@
#include "nsconfig.h"
#include <string.h>
#include <stdio.h>
#include "Service_Libs/utils/ns_file.h"
#include "Core/include/ns_address_internal.h"
#include "ns_file_system.h"
#include "thread_config.h"
@ -44,16 +44,13 @@
#define TRACE_GROUP "tnvm"
const char *FAST_DATA_FILE = "f_d";
#define FAST_DATA_VERSION 1
#define LINK_INFO_WRITE_DELAY 2
#define LINK_INFO_SHORT_ADDR_NOT_SET 0xffff
#define LINK_INFO_WRITE_DONE 0xffff
const char *LINK_INFO_FILE = "l_i";
#define LINK_INFO_DATA_VERSION 1
const char *LEADER_INFO_FILE = "ld_i";
#define LEADER_INFO_DATA_VERSION 1
typedef struct {
uint8_t mac[8];
@ -67,18 +64,15 @@ typedef struct {
} thread_nvm_store_link_info_t;
const char *THREAD_NVM_ACTIVE_CONF_FILE = "a_c";
#define ACTIVE_CONF_DATA_VERSION 1
const char *DEVICE_CONF_FILE = "s_d";
#define DEVICE_CONF_VERSION 1
const char *THREAD_NVM_PENDING_CONF_FILE = "p_c";
#define PENDING_CONF_DATA_VERSION 1
static const char *thread_nvm_store_get_root_path(void);
static int root_path_valid(void);
static int thread_nvm_store_read(const char *file_name, void *data, uint32_t data_size, uint32_t *version);
static int thread_nvm_store_write(const char *file_name, void *data, uint32_t data_size, uint32_t version);
static int thread_nvm_store_read(const char *file_name, void *data, uint32_t data_size);
static int thread_nvm_store_write(const char *file_name, void *data, uint32_t data_size);
static void thread_nvm_store_create_path(char *fast_data_path, const char *file_name);
static int thread_nvm_store_fast_data_save(thread_nvm_fast_data_t *fast_data_to_set);
static int thread_nvm_store_all_counters_store(uint32_t mac_frame_counter, uint32_t mle_frame_counter, uint32_t seq_counter);
@ -131,13 +125,12 @@ int thread_nvm_store_mleid_rloc_map_write(thread_nvm_mleid_rloc_map *mleid_rloc_
}
thread_nvm_store_create_path(lc_data_path, LEADER_INFO_FILE);
tr_debug("writing to store rloc mapping info");
return thread_nvm_store_write(lc_data_path, mleid_rloc_map, sizeof(thread_nvm_mleid_rloc_map), LEADER_INFO_DATA_VERSION);
return thread_nvm_store_write(lc_data_path, mleid_rloc_map, sizeof(thread_nvm_mleid_rloc_map));
}
int thread_nvm_store_mleid_rloc_map_read(thread_nvm_mleid_rloc_map *mleid_rloc_map)
{
char lc_data_path[LEADER_INFO_STRING_LEN];
uint32_t version;
if (NULL == mleid_rloc_map) {
return THREAD_NVM_FILE_PARAMETER_INVALID;
}
@ -146,7 +139,7 @@ int thread_nvm_store_mleid_rloc_map_read(thread_nvm_mleid_rloc_map *mleid_rloc_m
}
thread_nvm_store_create_path(lc_data_path, LEADER_INFO_FILE);
int ret = thread_nvm_store_read(lc_data_path, mleid_rloc_map, sizeof(thread_nvm_mleid_rloc_map), &version);
int ret = thread_nvm_store_read(lc_data_path, mleid_rloc_map, sizeof(thread_nvm_mleid_rloc_map));
if (THREAD_NVM_FILE_SUCCESS != ret) {
tr_info("Leader data map read failed");
@ -154,12 +147,6 @@ int thread_nvm_store_mleid_rloc_map_read(thread_nvm_mleid_rloc_map *mleid_rloc_m
return ret;
}
if (LEADER_INFO_DATA_VERSION != version) {
tr_info("Leader data map version mismatch %"PRIu32, version);
thread_nvm_store_mleid_rloc_map_remove();
return THREAD_NVM_FILE_VERSION_WRONG;
}
return ret;
}
@ -191,7 +178,7 @@ int thread_nvm_store_device_configuration_write(uint8_t *mac_ptr, uint8_t *mleid
memcpy(d_c.mle_id, mleid_ptr, sizeof(d_c.mle_id));
char device_conf_path[DEVICE_CONF_STRING_LEN];
thread_nvm_store_create_path(device_conf_path, DEVICE_CONF_FILE);
return thread_nvm_store_write(device_conf_path, &d_c, sizeof(thread_nvm_device_conf_t), DEVICE_CONF_VERSION);
return thread_nvm_store_write(device_conf_path, &d_c, sizeof(thread_nvm_device_conf_t));
}
int thread_nvm_store_device_configuration_read(uint8_t *mac_ptr, uint8_t *mleid_ptr)
@ -202,18 +189,12 @@ int thread_nvm_store_device_configuration_read(uint8_t *mac_ptr, uint8_t *mleid_
}
char device_conf_path[DEVICE_CONF_STRING_LEN];
thread_nvm_store_create_path(device_conf_path, DEVICE_CONF_FILE);
uint32_t version;
thread_nvm_device_conf_t d_c;
ret = thread_nvm_store_read(device_conf_path, &d_c, sizeof(thread_nvm_device_conf_t), &version);
ret = thread_nvm_store_read(device_conf_path, &d_c, sizeof(thread_nvm_device_conf_t));
if (THREAD_NVM_FILE_SUCCESS == ret) {
if (THREAD_NVM_FILE_SUCCESS == ret && DEVICE_CONF_VERSION != version) {
tr_info("fast data version mismatch %"PRIu32, version);
ret = THREAD_NVM_FILE_VERSION_WRONG;
} else {
memcpy(mac_ptr, d_c.mac, sizeof(d_c.mac));
memcpy(mleid_ptr, d_c.mle_id, sizeof(d_c.mle_id));
}
memcpy(mac_ptr, d_c.mac, sizeof(d_c.mac));
memcpy(mleid_ptr, d_c.mle_id, sizeof(d_c.mle_id));
}
return ret;
}
@ -228,13 +209,12 @@ int thread_nvm_store_pending_configuration_write(void *data, uint16_t size)
return THREAD_NVM_FILE_ROOT_PATH_INVALID;
}
thread_nvm_store_create_path(pc_data_path, THREAD_NVM_PENDING_CONF_FILE);
return thread_nvm_store_write(pc_data_path, data, size, PENDING_CONF_DATA_VERSION);
return thread_nvm_store_write(pc_data_path, data, size);
}
int thread_nvm_store_pending_configuration_read(void *data, uint16_t size)
{
char pc_data_path[PENDING_CONF_STRING_LEN];
uint32_t version;
if (NULL == data) {
return THREAD_NVM_FILE_PARAMETER_INVALID;
}
@ -243,11 +223,7 @@ int thread_nvm_store_pending_configuration_read(void *data, uint16_t size)
}
thread_nvm_store_create_path(pc_data_path, THREAD_NVM_PENDING_CONF_FILE);
int ret = thread_nvm_store_read(pc_data_path, data, size, &version);
if (THREAD_NVM_FILE_SUCCESS == ret && PENDING_CONF_DATA_VERSION != version) {
tr_info("Pending configuration version mismatch %"PRIu32, version);
return THREAD_NVM_FILE_VERSION_WRONG;
}
int ret = thread_nvm_store_read(pc_data_path, data, size);
return ret;
}
@ -262,13 +238,12 @@ int thread_nvm_store_active_configuration_write(void *data, uint16_t data_size)
}
thread_nvm_store_create_path(ac_data_path, THREAD_NVM_ACTIVE_CONF_FILE);
return thread_nvm_store_write(ac_data_path, data, data_size, ACTIVE_CONF_DATA_VERSION);
return thread_nvm_store_write(ac_data_path, data, data_size);
}
int thread_nvm_store_active_configuration_read(void *data, uint16_t data_size)
{
char ac_data_path[ACTIVE_CONF_STRING_LEN];
uint32_t version;
if (NULL == data) {
return THREAD_NVM_FILE_PARAMETER_INVALID;
}
@ -277,11 +252,7 @@ int thread_nvm_store_active_configuration_read(void *data, uint16_t data_size)
}
thread_nvm_store_create_path(ac_data_path, THREAD_NVM_ACTIVE_CONF_FILE);
int ret = thread_nvm_store_read(ac_data_path, data, data_size, &version);
if (THREAD_NVM_FILE_SUCCESS == ret && ACTIVE_CONF_DATA_VERSION != version) {
tr_info("active configuration version mismatch %"PRIu32, version);
return THREAD_NVM_FILE_VERSION_WRONG;
}
int ret = thread_nvm_store_read(ac_data_path, data, data_size);
return ret;
}
@ -399,12 +370,7 @@ int thread_nvm_store_fast_data_read(thread_nvm_fast_data_t *fast_data)
if (root_path_valid()) {
char fast_data_path[FAST_DATA_STRING_LEN];
thread_nvm_store_create_path(fast_data_path, FAST_DATA_FILE);
uint32_t version;
ret = thread_nvm_store_read(fast_data_path, fast_data, sizeof(thread_nvm_fast_data_t), &version);
if (THREAD_NVM_FILE_SUCCESS == ret && FAST_DATA_VERSION != version) {
tr_info("fast data version mismatch %"PRIu32, version);
return THREAD_NVM_FILE_VERSION_WRONG;
}
ret = thread_nvm_store_read(fast_data_path, fast_data, sizeof(thread_nvm_fast_data_t));
} else {
fast_data->mac_frame_counter = cached_fast_data.mac_frame_counter;
fast_data->mle_frame_counter = cached_fast_data.mle_frame_counter;
@ -417,26 +383,19 @@ static int thread_nvm_store_fast_data_save(thread_nvm_fast_data_t *fast_data_to_
{
char fast_data_path[FAST_DATA_STRING_LEN];
thread_nvm_store_create_path(fast_data_path, FAST_DATA_FILE);
return thread_nvm_store_write(fast_data_path, fast_data_to_set, sizeof(thread_nvm_fast_data_t), FAST_DATA_VERSION);
return thread_nvm_store_write(fast_data_path, fast_data_to_set, sizeof(thread_nvm_fast_data_t));
}
static int thread_nvm_store_write(const char *file_name, void *data, uint32_t data_size, uint32_t version)
static int thread_nvm_store_write(const char *file_name, void *data, uint32_t data_size)
{
FILE *fp = fopen(file_name, "w");
NS_FILE *fp = ns_fopen(file_name, "w");
if (fp == NULL) {
tr_error("NVM open error: %s", file_name);
return THREAD_NVM_FILE_CANNOT_OPEN;
}
size_t n_bytes = fwrite(&version, 1, sizeof(uint32_t), fp);
if (n_bytes != sizeof(uint32_t)) {
tr_warning("NVM version write error");
fclose(fp);
return THREAD_NVM_FILE_WRITE_ERROR;
}
n_bytes = fwrite(data, 1, data_size, fp);
fclose(fp);
size_t n_bytes = ns_fwrite(fp, data, data_size);
ns_fclose(fp);
if (n_bytes != data_size) {
tr_error("NVM write error %s", file_name);
return THREAD_NVM_FILE_WRITE_ERROR;
@ -446,23 +405,16 @@ static int thread_nvm_store_write(const char *file_name, void *data, uint32_t da
}
// returns 0 when ok
static int thread_nvm_store_read(const char *file_name, void *data, uint32_t data_size, uint32_t *version)
static int thread_nvm_store_read(const char *file_name, void *data, uint32_t data_size)
{
FILE *fp = fopen(file_name, "r");
NS_FILE *fp = ns_fopen(file_name, "r");
if (fp == NULL) {
tr_warning("File not found: %s", file_name);
return THREAD_NVM_FILE_CANNOT_OPEN;
}
size_t n_bytes = fread(version, 1, sizeof(uint32_t), fp);
if (n_bytes != sizeof(uint32_t)) {
tr_warning("NVM version read error %s", file_name);
fclose(fp);
return THREAD_NVM_FILE_READ_ERROR;
}
n_bytes = fread(data, 1, data_size, fp);
fclose(fp);
size_t n_bytes = ns_fread(fp, data, data_size);
ns_fclose(fp);
if (n_bytes != data_size) {
tr_error("NVM read error %s", file_name);
return THREAD_NVM_FILE_READ_ERROR;
@ -488,8 +440,7 @@ int thread_nvm_store_link_info_read(void)
strcpy(link_info_path, thread_nvm_store_get_root_path());
strcat(link_info_path, LINK_INFO_FILE);
uint32_t version = 0;
status = thread_nvm_store_read(link_info_path, &nvm_link_info_tmp, sizeof(nvm_link_info_t), &version);
status = thread_nvm_store_read(link_info_path, &nvm_link_info_tmp, sizeof(nvm_link_info_t));
if (status != THREAD_NVM_FILE_SUCCESS) {
if (!memcmp(cached_link_info.nvm_link_info.mac, ADDR_UNSPECIFIED, 8) &&
@ -499,9 +450,6 @@ int thread_nvm_store_link_info_read(void)
return THREAD_NVM_FILE_READ_ERROR;
}
return status;
} else if (ACTIVE_CONF_DATA_VERSION != version) {
tr_info("link info version mismatch %"PRIu32, version);
return THREAD_NVM_FILE_VERSION_WRONG;
}
memcpy(cached_link_info.nvm_link_info.mac, nvm_link_info_tmp.mac, 8);
cached_link_info.nvm_link_info.short_addr = nvm_link_info_tmp.short_addr;
@ -597,7 +545,7 @@ static void thread_nvm_store_link_info_delayed_write(uint32_t seconds)
strcpy(link_info_path, thread_nvm_store_get_root_path());
strcat(link_info_path, LINK_INFO_FILE);
tr_info("link info write parent mac: %s parent short addr: %"PRIu16, trace_array(cached_link_info.nvm_link_info.mac, 8), cached_link_info.nvm_link_info.short_addr);
thread_nvm_store_write(link_info_path, &cached_link_info.nvm_link_info, sizeof(nvm_link_info_t), LINK_INFO_DATA_VERSION);
thread_nvm_store_write(link_info_path, &cached_link_info.nvm_link_info, sizeof(nvm_link_info_t));
}
void thread_nvm_store_seconds_timer(uint32_t seconds)

View File

@ -155,7 +155,7 @@ static void lowpan_adaptation_etx_update_cb(protocol_interface_info_entry_t *cur
// Gets table entry
mac_neighbor_table_entry_t *neigh_table_ptr = mac_neighbor_table_address_discover(mac_neighbor_info(cur), buf->dst_sa.address + PAN_ID_LEN, buf->dst_sa.addr_type);
if (neigh_table_ptr) {
etx_transm_attempts_update(cur->id, 1 + confirm->tx_retries, success, neigh_table_ptr->index);
etx_transm_attempts_update(cur->id, 1 + confirm->tx_retries, success, neigh_table_ptr->index, neigh_table_ptr->mac64);
// Updates ETX statistics
etx_storage_t *etx_entry = etx_storage_entry_get(cur->id, neigh_table_ptr->index);
if (etx_entry) {

View File

@ -20,6 +20,7 @@
#include "ns_types.h"
#include "ns_trace.h"
#include "net_interface.h"
#include "socket_api.h"
#include "eventOS_event.h"
#include "NWK_INTERFACE/Include/protocol.h"
#include "6LoWPAN/Bootstraps/protocol_6lowpan.h"
@ -28,6 +29,7 @@
#include "6LoWPAN/ws/ws_common.h"
#include "6LoWPAN/ws/ws_bootstrap.h"
#include "6LoWPAN/ws/ws_cfg_settings.h"
#include "6LoWPAN/ws/ws_pae_key_storage.h"
#include "RPL/rpl_control.h"
#include "RPL/rpl_data.h"
#include "Common_Protocols/icmpv6.h"
@ -52,7 +54,6 @@ static uint8_t current_instance_id = RPL_INSTANCE_ID;
#define WS_ULA_LIFETIME 24*3600
#define WS_ROUTE_LIFETIME WS_ULA_LIFETIME
#define WS_DHCP_ADDRESS_LIFETIME 2*3600
#define BBR_CHECK_INTERVAL 60
#define BBR_BACKUP_ULA_DELAY 300
@ -68,7 +69,7 @@ static uint8_t static_dodag_prefix[8] = {0xfd, 0x00, 0x72, 0x83, 0x7e};
static uint8_t static_dodag_id_prefix[8] = {0xfd, 0x00, 0x61, 0x72, 0x6d};
static uint8_t current_dodag_id[16] = {0};
static uint8_t current_local_prefix[8] = {0};
static uint8_t current_global_prefix[8] = {0};
static uint8_t current_global_prefix[16] = {0}; // DHCP requires 16 bytes prefix
static uint32_t bbr_delay_timer = BBR_CHECK_INTERVAL; // initial delay.
static uint32_t global_prefix_unavailable_timer = 0; // initial delay.
@ -94,7 +95,16 @@ static void ws_bbr_rpl_version_timer_start(protocol_interface_info_entry_t *cur,
//stable version for RPL so slow timer update is ok
cur->ws_info->rpl_version_timer = RPL_VERSION_LIFETIME;
} else {
cur->ws_info->rpl_version_timer = RPL_VERSION_LIFETIME_RESTART;
if (cur->ws_info->cfg->gen.network_size <= NETWORK_SIZE_SMALL) {
// handles also NETWORK_SIZE_CERTIFICATE
cur->ws_info->rpl_version_timer = RPL_VERSION_LIFETIME_RESTART_SMALL;
} else if (cur->ws_info->cfg->gen.network_size <= NETWORK_SIZE_MEDIUM) {
cur->ws_info->rpl_version_timer = RPL_VERSION_LIFETIME_RESTART_MEDIUM;
} else if (cur->ws_info->cfg->gen.network_size <= NETWORK_SIZE_LARGE) {
cur->ws_info->rpl_version_timer = RPL_VERSION_LIFETIME_RESTART_LARGE;
} else {
cur->ws_info->rpl_version_timer = RPL_VERSION_LIFETIME_RESTART_EXTRA_LARGE;
}
}
}
@ -137,6 +147,15 @@ void ws_bbr_rpl_config(protocol_interface_info_entry_t *cur, uint8_t imin, uint8
}
}
void ws_bbr_dhcp_address_lifetime_set(protocol_interface_info_entry_t *cur, uint32_t dhcp_address_lifetime)
{
if (!cur) {
return;
}
// Change the setting if the border router is active
DHCPv6_server_service_set_address_validlifetime(cur->id, current_global_prefix, dhcp_address_lifetime);
}
static void ws_bbr_rpl_root_start(protocol_interface_info_entry_t *cur, uint8_t *dodag_id)
{
tr_info("RPL root start");
@ -223,7 +242,10 @@ static if_address_entry_t *ws_bbr_slaac_generate(protocol_interface_info_entry_t
static void ws_bbr_slaac_remove(protocol_interface_info_entry_t *cur, uint8_t *ula_prefix)
{
icmpv6_slaac_prefix_update(cur, ula_prefix, 64, 0, 0);
if (cur) {
icmpv6_slaac_prefix_update(cur, ula_prefix, 64, 0, 0);
}
addr_policy_table_delete_entry(ula_prefix, 64);
}
@ -328,7 +350,7 @@ static bool wisun_dhcp_address_add_cb(int8_t interfaceId, dhcp_address_cache_upd
return true;
}
static void ws_bbr_dhcp_server_start(protocol_interface_info_entry_t *cur, uint8_t *global_id)
static void ws_bbr_dhcp_server_start(protocol_interface_info_entry_t *cur, uint8_t *global_id, uint32_t dhcp_address_lifetime)
{
uint8_t ll[16];
memcpy(ll, ADDR_LINK_LOCAL_PREFIX, 8);
@ -344,7 +366,7 @@ static void ws_bbr_dhcp_server_start(protocol_interface_info_entry_t *cur, uint8
DHCPv6_server_service_callback_set(cur->id, global_id, NULL, wisun_dhcp_address_add_cb);
//Enable SLAAC mode to border router
DHCPv6_server_service_set_address_autonous_flag(cur->id, global_id, true, false);
DHCPv6_server_service_set_address_validlifetime(cur->id, global_id, WS_DHCP_ADDRESS_LIFETIME);
DHCPv6_server_service_set_address_validlifetime(cur->id, global_id, dhcp_address_lifetime);
//SEt max value for not limiting address allocation
DHCPv6_server_service_set_max_clients_accepts_count(cur->id, global_id, MAX_SUPPORTED_ADDRESS_LIST_SIZE);
@ -352,6 +374,9 @@ static void ws_bbr_dhcp_server_start(protocol_interface_info_entry_t *cur, uint8
}
static void ws_bbr_dhcp_server_stop(protocol_interface_info_entry_t *cur, uint8_t *global_id)
{
if (!cur) {
return;
}
uint8_t temp_address[16];
memcpy(temp_address, global_id, 8);
memset(temp_address + 8, 0, 8);
@ -359,7 +384,6 @@ static void ws_bbr_dhcp_server_stop(protocol_interface_info_entry_t *cur, uint8_
DHCPv6_server_service_delete(cur->id, global_id, false);
//Delete Client
dhcp_client_global_address_delete(cur->id, NULL, temp_address);
}
static void ws_bbr_routing_stop(protocol_interface_info_entry_t *cur)
@ -506,7 +530,7 @@ static void ws_bbr_rpl_status_check(protocol_interface_info_entry_t *cur)
return;
}
}
ws_bbr_dhcp_server_start(cur, global_prefix);
ws_bbr_dhcp_server_start(cur, global_prefix, cur->ws_info->cfg->bbr.dhcp_address_lifetime);
rpl_control_update_dodag_prefix(protocol_6lowpan_rpl_root_dodag, global_prefix, 64, 0, 0, 0, false);
// no check for failure should have
@ -623,6 +647,11 @@ uint16_t test_pan_size_override = 0xffff;
uint16_t ws_bbr_pan_size(protocol_interface_info_entry_t *cur)
{
uint16_t result = 0;
if (!cur || !cur->rpl_domain) {
return 0;
}
if (test_pan_size_override != 0xffff) {
return test_pan_size_override;
}
@ -701,7 +730,6 @@ void ws_bbr_stop(int8_t interface_id)
protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(interface_id);
ws_bbr_routing_stop(cur);
backbone_interface_id = -1;
current_instance_id++;
@ -728,6 +756,86 @@ int ws_bbr_configure(int8_t interface_id, uint16_t options)
return -1;
#endif
}
int ws_bbr_info_get(int8_t interface_id, bbr_information_t *info_ptr)
{
#ifdef HAVE_WS_BORDER_ROUTER
protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(interface_id);
rpl_dodag_info_t dodag_info;
if (!info_ptr) {
return -1;
}
if (!cur || !protocol_6lowpan_rpl_root_dodag) {
tr_warn("bbr not started");
return -1;
}
struct rpl_instance *instance = rpl_control_lookup_instance(protocol_6lowpan_rpl_domain, current_instance_id, current_dodag_id);
if (!instance) {
tr_warn("bbr instance not found");
return -2;
}
// Zero the structure
memset(info_ptr, 0, sizeof(bbr_information_t));
rpl_control_read_dodag_info(instance, &dodag_info);
memcpy(info_ptr->dodag_id, current_dodag_id, 16);
memcpy(info_ptr->prefix, current_global_prefix, 8);
// Get the Wi-SUN interface generated address that is used in the RF interface.
const uint8_t *wisun_if_addr = addr_select_with_prefix(cur, current_global_prefix, 64, SOCKET_IPV6_PREFER_SRC_PUBLIC);
if (wisun_if_addr) {
memcpy(info_ptr->IID, wisun_if_addr + 8, 8);
}
info_ptr->devices_in_network = ws_bbr_pan_size(cur);
info_ptr->instance_id = current_instance_id;
info_ptr->version = dodag_info.version_num;
info_ptr->timestamp = protocol_core_monotonic_time; // TODO switch to second timer
// consider DTSN included It can also be added for getting device information
// Consider own device API to get DTSN, DHCP lifetime values
return 0;
#else
(void) interface_id;
(void) info_ptr;
return -1;
#endif
}
int ws_bbr_routing_table_get(int8_t interface_id, bbr_route_info_t *table_ptr, uint16_t table_len)
{
#ifdef HAVE_WS_BORDER_ROUTER
protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(interface_id);
int length;
if (!cur || !protocol_6lowpan_rpl_root_dodag) {
return -1;
}
struct rpl_instance *instance = rpl_control_lookup_instance(protocol_6lowpan_rpl_domain, current_instance_id, current_dodag_id);
if (!instance) {
tr_warn("bbr instance not found");
return -2;
}
memset(table_ptr, 0, table_len);
/* RPL structure must match the external structure so we dont need to make conversion.
*
*/
length = rpl_control_route_table_get(instance, current_global_prefix, (rpl_route_info_t *)table_ptr, table_len);
return length;
#else
(void) interface_id;
(void) table_ptr;
(void) table_len;
return -1;
#endif
}
int ws_bbr_node_keys_remove(int8_t interface_id, uint8_t *eui64)
{
@ -782,8 +890,8 @@ int ws_bbr_rpl_parameters_set(int8_t interface_id, uint8_t dio_interval_min, uin
#ifdef HAVE_WS_BORDER_ROUTER
protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(interface_id);
ws_rpl_cfg_t cfg;
if (ws_cfg_rpl_get(&cfg, NULL) < 0) {
ws_bbr_cfg_t cfg;
if (ws_cfg_bbr_get(&cfg, NULL) < 0) {
return -1;
}
@ -797,7 +905,7 @@ int ws_bbr_rpl_parameters_set(int8_t interface_id, uint8_t dio_interval_min, uin
cfg.dio_redundancy_constant = dio_redundancy_constant;
}
if (ws_cfg_rpl_set(cur, NULL, &cfg, 0) < 0) {
if (ws_cfg_bbr_set(cur, NULL, &cfg, 0) < 0) {
return -2;
}
@ -818,8 +926,8 @@ int ws_bbr_rpl_parameters_get(int8_t interface_id, uint8_t *dio_interval_min, ui
return -1;
}
ws_rpl_cfg_t cfg;
if (ws_cfg_rpl_get(&cfg, NULL) < 0) {
ws_bbr_cfg_t cfg;
if (ws_cfg_bbr_get(&cfg, NULL) < 0) {
return -2;
}
@ -840,8 +948,8 @@ int ws_bbr_rpl_parameters_validate(int8_t interface_id, uint8_t dio_interval_min
{
(void) interface_id;
#ifdef HAVE_WS_BORDER_ROUTER
ws_rpl_cfg_t cfg;
if (ws_cfg_rpl_get(&cfg, NULL) < 0) {
ws_bbr_cfg_t cfg;
if (ws_cfg_bbr_get(&cfg, NULL) < 0) {
return -2;
}
@ -855,7 +963,7 @@ int ws_bbr_rpl_parameters_validate(int8_t interface_id, uint8_t dio_interval_min
cfg.dio_redundancy_constant = dio_redundancy_constant;
}
if (ws_cfg_rpl_validate(NULL, &cfg) < 0) {
if (ws_cfg_bbr_validate(NULL, &cfg) < 0) {
return -3;
}
@ -935,3 +1043,29 @@ int ws_bbr_pan_configuration_validate(int8_t interface_id, uint16_t pan_id)
return -1;
#endif
}
int ws_bbr_key_storage_memory_set(int8_t interface_id, uint8_t key_storages_number, const uint16_t *key_storage_size, void **key_storages)
{
(void) interface_id;
#ifdef HAVE_WS_BORDER_ROUTER
return ws_pae_key_storage_memory_set(key_storages_number, key_storage_size, key_storages);
#else
(void) key_storages_number;
(void) key_storage_size;
(void) key_storages;
return -1;
#endif
}
int ws_bbr_key_storage_settings_set(int8_t interface_id, uint8_t alloc_max_number, uint16_t alloc_size, uint16_t storing_interval)
{
(void) interface_id;
#ifdef HAVE_WS_BORDER_ROUTER
return ws_pae_key_storage_settings_set(alloc_max_number, alloc_size, storing_interval);
#else
(void) alloc_max_number;
(void) alloc_size;
(void) storing_interval;
return -1;
#endif
}

View File

@ -31,6 +31,8 @@ uint16_t ws_bbr_pan_size(protocol_interface_info_entry_t *cur);
void ws_bbr_rpl_config(protocol_interface_info_entry_t *cur, uint8_t imin, uint8_t doubling, uint8_t redundancy, uint16_t dag_max_rank_increase, uint16_t min_hop_rank_increase);
void ws_bbr_dhcp_address_lifetime_set(protocol_interface_info_entry_t *cur, uint32_t dhcp_address_lifetime);
bool ws_bbr_ready_to_start(protocol_interface_info_entry_t *cur);
@ -40,6 +42,7 @@ bool ws_bbr_ready_to_start(protocol_interface_info_entry_t *cur);
#define ws_bbr_pan_version_increase(cur)
#define ws_bbr_pan_size(cur) 0
#define ws_bbr_rpl_config( cur, imin, doubling, redundancy, dag_max_rank_increase, min_hop_rank_increase)
#define ws_bbr_dhcp_address_lifetime_set(cur, dhcp_address_lifetime)
#define ws_bbr_ready_to_start(cur) true
#endif //HAVE_WS_BORDER_ROUTER

View File

@ -95,14 +95,16 @@ static void ws_bootstrap_nw_key_clear(protocol_interface_info_entry_t *cur, uint
static void ws_bootstrap_nw_key_index_set(protocol_interface_info_entry_t *cur, uint8_t index);
static void ws_bootstrap_nw_frame_counter_set(protocol_interface_info_entry_t *cur, uint32_t counter, uint8_t slot);
static void ws_bootstrap_nw_frame_counter_read(protocol_interface_info_entry_t *cur, uint32_t *counter, uint8_t slot);
static void ws_bootstrap_nw_info_updated(protocol_interface_info_entry_t *interface_ptr, uint16_t pan_id, char *network_name);
static void ws_bootstrap_authentication_completed(protocol_interface_info_entry_t *cur, auth_result_e result, uint8_t *target_eui_64);
static const uint8_t *ws_bootstrap_authentication_next_target(protocol_interface_info_entry_t *cur, const uint8_t *previous_eui_64, uint16_t *pan_id);
static void ws_bootstrap_pan_version_increment(protocol_interface_info_entry_t *cur);
static ws_nud_table_entry_t *ws_nud_entry_discover(protocol_interface_info_entry_t *cur, void *neighbor);
static void ws_nud_entry_remove(protocol_interface_info_entry_t *cur, mac_neighbor_table_entry_t *entry_ptr);
static bool ws_neighbor_entry_nud_notify(mac_neighbor_table_entry_t *entry_ptr, void *user_data);
static void ws_address_registration_update(protocol_interface_info_entry_t *interface, const uint8_t addr[16]);
static int8_t ws_bootstrap_neighbor_set(protocol_interface_info_entry_t *cur, parent_info_t *parent_ptr, bool clear_list);
static void ws_bootstrap_candidate_table_reset(protocol_interface_info_entry_t *cur);
static parent_info_t *ws_bootstrap_candidate_parent_get(struct protocol_interface_info_entry *cur, const uint8_t *addr, bool create);
@ -146,14 +148,68 @@ mac_neighbor_table_entry_t *ws_bootstrap_mac_neighbor_add(struct protocol_interf
static void ws_bootstrap_neighbor_delete(struct protocol_interface_info_entry *interface, mac_neighbor_table_entry_t *entry_ptr)
{
mac_helper_devicetable_remove(interface->mac_api, entry_ptr->index, entry_ptr->mac64);
etx_neighbor_remove(interface->id, entry_ptr->index);
etx_neighbor_remove(interface->id, entry_ptr->index, entry_ptr->mac64);
ws_neighbor_class_entry_remove(&interface->ws_info->neighbor_storage, entry_ptr->index);
}
static void ws_bootstap_eapol_neigh_entry_allocate(struct protocol_interface_info_entry *interface)
{
uint8_t mac_64[8];
memset(mac_64, 0, sizeof(mac_64));
mac_neighbor_table_entry_t *mac_entry = ws_bootstrap_mac_neighbor_add(interface, mac_64);
if (!mac_entry) {
return;
}
mac_entry->lifetime = 0xffffffff;
mac_entry->link_lifetime = 0xffffffff;
ws_neighbor_class_entry_t *ws_neigh = ws_neighbor_class_entry_get(&interface->ws_info->neighbor_storage, mac_entry->index);
if (!ws_neigh) {
return;
}
interface->ws_info->eapol_tx_index = mac_entry->index;
}
void ws_bootstrap_eapol_rx_temporary_set(struct protocol_interface_info_entry *interface, const uint8_t *src64)
{
mlme_device_descriptor_t device_desc;
mac_helper_device_description_write(interface, &device_desc, src64, 0xffff, 0, false);
mac_helper_devicetable_ack_trig(&device_desc, interface);
}
ws_neighbor_class_entry_t *ws_bootstrap_eapol_tx_temporary_set(struct protocol_interface_info_entry *interface, const uint8_t *src64)
{
mlme_device_descriptor_t device_desc;
mac_neighbor_table_entry_t *mac_entry = mac_neighbor_table_attribute_discover(mac_neighbor_info(interface), interface->ws_info->eapol_tx_index);
if (!mac_entry) {
return NULL;
}
memcpy(mac_entry->mac64, src64, 8);
mac_helper_device_description_write(interface, &device_desc, src64, 0xffff, 0, false);
mac_helper_devicetable_direct_set(interface->mac_api, &device_desc, interface->ws_info->eapol_tx_index);
return ws_neighbor_class_entry_get(&interface->ws_info->neighbor_storage, mac_entry->index);
}
void ws_bootstrap_eapol_tx_temporary_clear(struct protocol_interface_info_entry *interface)
{
mac_neighbor_table_entry_t *mac_entry = mac_neighbor_table_attribute_discover(mac_neighbor_info(interface), interface->ws_info->eapol_tx_index);
if (!mac_entry) {
return;
}
memset(mac_entry->mac64, 0xff, 8);
mac_helper_devicetable_remove(interface->mac_api, interface->ws_info->eapol_tx_index, NULL);
}
static void ws_bootstrap_neighbor_list_clean(struct protocol_interface_info_entry *interface)
{
mac_neighbor_table_neighbor_list_clean(mac_neighbor_info(interface));
//Allocate EAPOL TX temporary neigh entry
ws_bootstap_eapol_neigh_entry_allocate(interface);
}
static void ws_address_reregister_trig(struct protocol_interface_info_entry *interface)
@ -486,8 +542,8 @@ static uint8_t ws_generate_exluded_channel_list_from_active_channels(ws_excluded
static void ws_fhss_configure_channel_masks(protocol_interface_info_entry_t *cur, fhss_ws_configuration_t *fhss_configuration)
{
ws_generate_channel_list(fhss_configuration->channel_mask, cur->ws_info->hopping_schdule.number_of_channels, cur->ws_info->hopping_schdule.regulatory_domain);
ws_generate_channel_list(fhss_configuration->unicast_channel_mask, cur->ws_info->hopping_schdule.number_of_channels, cur->ws_info->hopping_schdule.regulatory_domain);
ws_generate_channel_list(fhss_configuration->channel_mask, cur->ws_info->hopping_schdule.number_of_channels, cur->ws_info->hopping_schdule.regulatory_domain, cur->ws_info->hopping_schdule.operating_class);
ws_generate_channel_list(fhss_configuration->unicast_channel_mask, cur->ws_info->hopping_schdule.number_of_channels, cur->ws_info->hopping_schdule.regulatory_domain, cur->ws_info->hopping_schdule.operating_class);
// using bitwise AND operation for user set channel mask to remove channels not allowed in this device
for (uint8_t n = 0; n < 8; n++) {
fhss_configuration->unicast_channel_mask[n] &= cur->ws_info->cfg->fhss.fhss_channel_mask[n];
@ -510,6 +566,7 @@ static int8_t ws_fhss_initialize(protocol_interface_info_entry_t *cur)
fhss_configuration.ws_bc_channel_function = (fhss_ws_channel_functions)cur->ws_info->cfg->fhss.fhss_bc_channel_function;
fhss_configuration.fhss_bc_dwell_interval = cur->ws_info->cfg->fhss.fhss_bc_dwell_interval;
fhss_configuration.fhss_broadcast_interval = cur->ws_info->cfg->fhss.fhss_bc_interval;
fhss_configuration.config_parameters.number_of_channel_retries = WS_NUMBER_OF_CHANNEL_RETRIES;
fhss_api = ns_fhss_ws_create(&fhss_configuration, cur->ws_info->fhss_timer_ptr);
if (!fhss_api) {
@ -1069,7 +1126,7 @@ static parent_info_t *ws_bootstrap_candidate_parent_allocate(protocol_interface_
return entry;
}
static void ws_bootstrap_candidate_parent_free(protocol_interface_info_entry_t *cur, uint8_t *addr)
static void ws_bootstrap_candidate_parent_free(protocol_interface_info_entry_t *cur, const uint8_t *addr)
{
ns_list_foreach_safe(parent_info_t, entry, &cur->ws_info->parent_list_reserved) {
if (memcmp(entry->addr, addr, 8) == 0) {
@ -1286,14 +1343,15 @@ static void ws_bootstrap_pan_advertisement_solicit_analyse(struct protocol_inter
* a PAN Advertisement Solicit with NETNAME-IE / Network Name matching that configured on the receiving node.
*/
trickle_consistent_heard(&cur->ws_info->trickle_pan_advertisement_solicit);
/*
* Optimized PAN discovery to select faster the parent if we hear solicit from someone else
*/
if (ws_bootstrap_state_discovery(cur) &&
cur->bootsrap_state_machine_cnt > cur->ws_info->trickle_params_pan_discovery.Imin + 50) {
cur->bootsrap_state_machine_cnt = cur->ws_info->trickle_params_pan_discovery.Imin + randLIB_get_8bit() % 50;
if (ws_bootstrap_state_discovery(cur) && cur->ws_info->cfg->gen.network_size <= NETWORK_SIZE_MEDIUM &&
cur->bootsrap_state_machine_cnt > cur->ws_info->trickle_params_pan_discovery.Imin * 2) {
cur->bootsrap_state_machine_cnt = cur->ws_info->trickle_params_pan_discovery.Imin + randLIB_get_random_in_range(0, cur->ws_info->trickle_params_pan_discovery.Imin);
tr_info("Making parent selection in %u s", (cur->bootsrap_state_machine_cnt / 10));
}
}
@ -1347,6 +1405,7 @@ static void ws_bootstrap_pan_config_analyse(struct protocol_interface_info_entry
tr_error("No broadcast schedule");
return;
}
llc_neighbour_req_t neighbor_info;
bool neighbour_pointer_valid;
@ -1362,7 +1421,7 @@ static void ws_bootstrap_pan_config_analyse(struct protocol_interface_info_entry
}
if (neighbour_pointer_valid) {
etx_lqi_dbm_update(cur->id, data->mpduLinkQuality, data->signal_dbm, neighbor_info.neighbor->index);
etx_lqi_dbm_update(cur->id, data->mpduLinkQuality, data->signal_dbm, neighbor_info.neighbor->index, neighbor_info.neighbor->mac64);
//Update Neighbor Broadcast and Unicast Parameters
ws_neighbor_class_neighbor_unicast_time_info_update(neighbor_info.ws_neighbor, ws_utt, data->timestamp);
ws_neighbor_class_neighbor_unicast_schedule_set(neighbor_info.ws_neighbor, ws_us);
@ -1447,7 +1506,7 @@ static void ws_bootstrap_pan_config_solicit_analyse(struct protocol_interface_in
llc_neighbour_req_t neighbor_info;
if (ws_bootstrap_neighbor_info_request(cur, data->SrcAddr, &neighbor_info, false)) {
etx_lqi_dbm_update(cur->id, data->mpduLinkQuality, data->signal_dbm, neighbor_info.neighbor->index);
etx_lqi_dbm_update(cur->id, data->mpduLinkQuality, data->signal_dbm, neighbor_info.neighbor->index, neighbor_info.neighbor->mac64);
ws_neighbor_class_neighbor_unicast_time_info_update(neighbor_info.ws_neighbor, ws_utt, data->timestamp);
ws_neighbor_class_neighbor_unicast_schedule_set(neighbor_info.ws_neighbor, ws_us);
}
@ -1607,6 +1666,10 @@ static void ws_bootstrap_neighbor_table_clean(struct protocol_interface_info_ent
ns_list_foreach_safe(mac_neighbor_table_entry_t, cur, &mac_neighbor_info(interface)->neighbour_list) {
ws_neighbor_class_entry_t *ws_neighbor = ws_neighbor_class_entry_get(&interface->ws_info->neighbor_storage, cur->index);
if (cur->index == interface->ws_info->eapol_tx_index) {
continue;
}
if (cur->link_role == PRIORITY_PARENT_NEIGHBOUR) {
//This is our primary parent we cannot delete
continue;
@ -1758,7 +1821,7 @@ static bool ws_neighbor_entry_nud_notify(mac_neighbor_table_entry_t *entry_ptr,
return false;
}
if (!rpl_control_is_dodag_parent_candidate(cur, ll_address, WS_NEIGHBOUR_MAX_CANDIDATE_PROBE)) {
if (!rpl_control_is_dodag_parent_candidate(cur, ll_address, cur->ws_info->cfg->gen.rpl_parent_candidate_max)) {
//NUD Not needed for if neighbour is not parent candidate
return false;
}
@ -1921,7 +1984,7 @@ int ws_bootstrap_init(int8_t interface_id, net_6lowpan_mode_e bootstrap_mode)
ret_val = -4;
goto init_fail;
}
if (ws_pae_controller_cb_register(cur, &ws_bootstrap_authentication_completed, &ws_bootstrap_nw_key_set, &ws_bootstrap_nw_key_clear, &ws_bootstrap_nw_key_index_set, &ws_bootstrap_nw_frame_counter_set, &ws_bootstrap_nw_frame_counter_read, &ws_bootstrap_pan_version_increment) < 0) {
if (ws_pae_controller_cb_register(cur, &ws_bootstrap_authentication_completed, &ws_bootstrap_authentication_next_target, &ws_bootstrap_nw_key_set, &ws_bootstrap_nw_key_clear, &ws_bootstrap_nw_key_index_set, &ws_bootstrap_nw_frame_counter_set, &ws_bootstrap_nw_frame_counter_read, &ws_bootstrap_pan_version_increment, &ws_bootstrap_nw_info_updated) < 0) {
ret_val = -4;
goto init_fail;
}
@ -1957,6 +2020,8 @@ int ws_bootstrap_init(int8_t interface_id, net_6lowpan_mode_e bootstrap_mode)
set_req.value_size = sizeof(bool);
cur->mac_api->mlme_req(cur->mac_api, MLME_SET, &set_req);
mac_helper_mac_mlme_max_retry_set(cur->id, WS_MAX_FRAME_RETRIES);
// Set the default parameters for MPL
cur->mpl_proactive_forwarding = true;
@ -2032,6 +2097,12 @@ int ws_bootstrap_set_rf_config(protocol_interface_info_entry_t *cur, phy_rf_chan
set_request.value_pointer = &multi_csma_params;
set_request.value_size = sizeof(mlme_multi_csma_ca_param_t);
cur->mac_api->mlme_req(cur->mac_api, MLME_SET, &set_request);
// Start automatic CCA threshold
uint8_t start_cca_thr[4] = {cur->ws_info->hopping_schdule.number_of_channels, CCA_DEFAULT_DBM, CCA_HIGH_LIMIT, CCA_LOW_LIMIT};
set_request.attr = macCCAThresholdStart;
set_request.value_pointer = &start_cca_thr;
set_request.value_size = sizeof(start_cca_thr);
cur->mac_api->mlme_req(cur->mac_api, MLME_SET, &set_request);
return 0;
}
@ -2205,8 +2276,8 @@ static void ws_bootstrap_rpl_callback(rpl_event_t event, void *handle)
ws_eapol_relay_start(cur, EAPOL_RELAY_SOCKET_PORT, dodag_info.dodag_id, EAPOL_RELAY_SOCKET_PORT);
// Set network information to PAE
ws_pae_controller_nw_info_set(cur, cur->ws_info->network_pan_id, cur->ws_info->cfg->gen.network_name);
// Network key is valid
ws_pae_controller_nw_key_valid(cur);
// Network key is valid, indicate border router IID to controller
ws_pae_controller_nw_key_valid(cur, &dodag_info.dodag_id[8]);
// After successful DAO ACK connection to border router is verified
cur->ws_info->pan_timeout_timer = cur->ws_info->cfg->timing.pan_timeout;
@ -2308,19 +2379,21 @@ static void ws_rpl_prefix_callback(prefix_entry_t *prefix, void *handle, uint8_t
static bool ws_rpl_candidate_soft_filtering(protocol_interface_info_entry_t *cur, struct rpl_instance *instance)
{
//If bootstrap active we not need any candidate filtering
if ((cur->lowpan_info & INTERFACE_NWK_BOOTSRAP_ACTIVE) && (ws_info(cur)->cfg->gen.network_size == NETWORK_SIZE_CERTIFICATE)) {
return true;
}
//Already many candidates
if (rpl_control_candidate_list_size(cur, instance) > cur->ws_info->cfg->rpl.rpl_parent_candidate_max) {
uint16_t candidate_list_size = rpl_control_candidate_list_size(cur, instance);
if (candidate_list_size >= cur->ws_info->cfg->gen.rpl_parent_candidate_max) {
return false;
}
uint16_t selected_parents = rpl_control_selected_parent_count(cur, instance);
//Already enough selected candidates
if (rpl_control_selected_parent_count(cur, instance) >= cur->ws_info->cfg->rpl.rpl_selected_parent_max) {
return false;
if (selected_parents >= cur->ws_info->cfg->gen.rpl_selected_parent_max) {
candidate_list_size -= selected_parents;
if (candidate_list_size >= 2) {
//We have more candidates than selected
return false;
}
}
return true;
@ -2354,6 +2427,19 @@ static bool ws_rpl_new_parent_callback(uint8_t *ll_parent_address, void *handle,
ws_neighbor_temp_class_t *entry = ws_llc_get_multicast_temp_entry(cur, mac64);
if (!ws_rpl_candidate_soft_filtering(cur, instance)) {
//Acept only better than own rank here
if (candidate_rank >= rpl_control_current_rank(instance)) {
//Do not accept no more siblings
return false;
}
uint16_t candidate_list_size = rpl_control_candidate_list_size(cur, instance);
if (candidate_list_size > cur->ws_info->cfg->gen.rpl_parent_candidate_max + 1) {
//Accept only 1 better 1 time
return false;
}
if (!neigh_buffer.neighbor) {
//Do not accept any new in that Place
return false;
@ -2386,42 +2472,6 @@ static bool ws_rpl_new_parent_callback(uint8_t *ll_parent_address, void *handle,
if (neigh_buffer.neighbor) {
return true;
}
#if 0
if (!rpl_control_find_worst_neighbor(cur, instance, replacing)) {
return false;
}
// +2 Is for PAN ID space
memcpy(mac64 + 2, replacing + 8, 8);
mac64[2] ^= 2;
if (ws_etx_read(cur, ADDR_802_15_4_LONG, mac64) == 0xffff) {
//Not proped yet because ETX is 0xffff
return false;
}
uint16_t etx = 0;
if (neigh_buffer.neighbor) {
etx = etx_local_etx_read(cur->id, neigh_buffer.neighbor->index);
}
// Accept now only better one's when max candidates selected and max candidate list size is reached
if (!rpl_possible_better_candidate(cur, instance, replacing, candidate_rank, etx)) {
return false;
}
//TODO if replacing has poor ETX, put it in blacklist as "poor ETX" to prevent reselection
//Mark That We can try remove replaced link
replace_ok = true;
neigh_create:
if (neigh_buffer.neighbor) {
//Use Already discovered entry
create_ok = true;
goto neigh_create_ok;
}
#endif
if (!entry) {
//No Multicast Entry Available
@ -2435,7 +2485,7 @@ neigh_create:
//Copy fhss temporary data
*ws_neigh = entry->neigh_info_list;
//ETX Create here
etx_lqi_dbm_update(cur->id, entry->mpduLinkQuality, entry->signal_dbm, neigh_buffer.neighbor->index);
etx_lqi_dbm_update(cur->id, entry->mpduLinkQuality, entry->signal_dbm, neigh_buffer.neighbor->index, neigh_buffer.neighbor->mac64);
mac_neighbor_table_trusted_neighbor(mac_neighbor_info(cur), neigh_buffer.neighbor, true);
}
ws_llc_free_multicast_temp_entry(cur, entry);
@ -2562,7 +2612,7 @@ static void ws_bootstrap_start_discovery(protocol_interface_info_entry_t *cur)
}
// Discovery statemachine is checkked after we have sent the Solicit
uint16_t time_to_solicit = 0;
uint32_t time_to_solicit = 0;
if (cur->ws_info->trickle_pan_advertisement_solicit.t > cur->ws_info->trickle_pan_advertisement_solicit.now) {
time_to_solicit = cur->ws_info->trickle_pan_advertisement_solicit.t - cur->ws_info->trickle_pan_advertisement_solicit.now;
}
@ -2571,7 +2621,13 @@ static void ws_bootstrap_start_discovery(protocol_interface_info_entry_t *cur)
cur->ws_info->trickle_params_pan_discovery.Imin, cur->ws_info->trickle_params_pan_discovery.Imax, cur->ws_info->trickle_params_pan_discovery.TimerExpirations, cur->ws_info->trickle_params_pan_discovery.k,
cur->ws_info->trickle_pan_advertisement_solicit.I, cur->ws_info->trickle_pan_advertisement_solicit.t, cur->ws_info->trickle_pan_advertisement_solicit.now, cur->ws_info->trickle_pan_advertisement_solicit.c);
cur->bootsrap_state_machine_cnt = time_to_solicit + cur->ws_info->trickle_params_pan_discovery.Imin + randLIB_get_8bit() % 50;
time_to_solicit += cur->ws_info->trickle_params_pan_discovery.Imin + randLIB_get_random_in_range(0, cur->ws_info->trickle_params_pan_discovery.Imin);
if (time_to_solicit > 0xffff) {
time_to_solicit = 0xffff;
}
cur->bootsrap_state_machine_cnt = time_to_solicit;
tr_info("Making parent selection in %u s", (cur->bootsrap_state_machine_cnt / 10));
}
@ -2627,6 +2683,32 @@ static void ws_bootstrap_nw_frame_counter_read(protocol_interface_info_entry_t *
mac_helper_key_link_frame_counter_read(cur->id, counter, slot);
}
static void ws_bootstrap_nw_info_updated(protocol_interface_info_entry_t *cur, uint16_t pan_id, char *network_name)
{
/* For border router, the PAE controller reads pan_id and network name from storage.
* If they are set, takes them into use here.
*/
if (cur->bootsrap_mode == ARM_NWK_BOOTSRAP_MODE_6LoWPAN_BORDER_ROUTER) {
// Get pad_id and network name
ws_gen_cfg_t gen_cfg;
if (ws_cfg_gen_get(&gen_cfg, NULL) < 0) {
return;
}
// If pan_id has not been set, set it
if (gen_cfg.network_pan_id == 0xffff) {
gen_cfg.network_pan_id = pan_id;
}
// If network name has not been set, set it
if (strlen(gen_cfg.network_name) == 0) {
strncpy(gen_cfg.network_name, network_name, 32);
}
// Stores the settings
ws_cfg_gen_set(cur, NULL, &gen_cfg, 0);
}
}
static void ws_bootstrap_authentication_completed(protocol_interface_info_entry_t *cur, auth_result_e result, uint8_t *target_eui_64)
{
(void) target_eui_64;
@ -2658,6 +2740,24 @@ static void ws_bootstrap_authentication_completed(protocol_interface_info_entry_
}
}
static const uint8_t *ws_bootstrap_authentication_next_target(protocol_interface_info_entry_t *cur, const uint8_t *previous_eui_64, uint16_t *pan_id)
{
ws_bootstrap_candidate_parent_free(cur, previous_eui_64);
// Gets best target
parent_info_t *parent_info = ws_bootstrap_candidate_parent_get_best(cur);
if (parent_info) {
/* On failure still continues with the new parent, and on next call,
will try to set the neighbor again */
ws_bootstrap_neighbor_set(cur, parent_info, true);
*pan_id = parent_info->pan_id;
return parent_info->addr;
}
// If no targets found, retries the last one
return previous_eui_64;
}
// Start configuration learning
static void ws_bootstrap_start_configuration_learn(protocol_interface_info_entry_t *cur)
{
@ -2731,7 +2831,7 @@ static void ws_set_asynch_channel_list(protocol_interface_info_entry_t *cur, asy
uint16_t channel_number = cur->ws_info->cfg->fhss.fhss_uc_fixed_channel;
async_req->channel_list.channel_mask[0 + (channel_number / 32)] = (1 << (channel_number % 32));
} else {
ws_generate_channel_list(async_req->channel_list.channel_mask, cur->ws_info->hopping_schdule.number_of_channels, cur->ws_info->hopping_schdule.regulatory_domain);
ws_generate_channel_list(async_req->channel_list.channel_mask, cur->ws_info->hopping_schdule.number_of_channels, cur->ws_info->hopping_schdule.regulatory_domain, cur->ws_info->hopping_schdule.operating_class);
}
async_req->channel_list.channel_page = CHANNEL_PAGE_10;
@ -3047,6 +3147,36 @@ static void ws_bootstrap_event_handler(arm_event_s *event)
}
}
static int8_t ws_bootstrap_neighbor_set(protocol_interface_info_entry_t *cur, parent_info_t *parent_ptr, bool clear_list)
{
uint16_t pan_id = cur->ws_info->network_pan_id;
// Add EAPOL neighbor
cur->ws_info->network_pan_id = parent_ptr->pan_id;
cur->ws_info->pan_information = parent_ptr->pan_information;
cur->ws_info->pan_information.pan_version = 0; // This is learned from actual configuration
// If PAN ID changes, clear learned neighbors and activate FHSS
if (pan_id != cur->ws_info->network_pan_id) {
if (clear_list) {
ws_bootstrap_neighbor_list_clean(cur);
}
ws_bootstrap_fhss_activate(cur);
}
llc_neighbour_req_t neighbor_info;
if (!ws_bootstrap_neighbor_info_request(cur, parent_ptr->addr, &neighbor_info, true)) {
//Remove Neighbour and set Link setup back
ns_list_remove(&cur->ws_info->parent_list_reserved, parent_ptr);
ns_list_add_to_end(&cur->ws_info->parent_list_free, parent_ptr);
return -1;
}
ws_neighbor_class_neighbor_unicast_time_info_update(neighbor_info.ws_neighbor, &parent_ptr->ws_utt, parent_ptr->timestamp);
ws_neighbor_class_neighbor_unicast_schedule_set(neighbor_info.ws_neighbor, &parent_ptr->ws_us);
return 0;
}
/*
* State machine
*
@ -3067,29 +3197,21 @@ select_best_candidate:
// randomize new channel and start MAC
ws_bootstrap_fhss_activate(cur);
// Next check will be after one trickle
cur->bootsrap_state_machine_cnt += cur->ws_info->trickle_params_pan_discovery.Imin + randLIB_get_8bit() % 50;
uint32_t random_start = cur->ws_info->trickle_params_pan_discovery.Imin + randLIB_get_random_in_range(0, cur->ws_info->trickle_params_pan_discovery.Imin);
if (random_start > 0xffff) {
random_start = 0xffff;
}
cur->bootsrap_state_machine_cnt = random_start;
tr_info("Making parent selection in %u s", (cur->bootsrap_state_machine_cnt / 10));
return;
}
tr_info("selected parent:%s panid %u", trace_array(selected_parent_ptr->addr, 8), selected_parent_ptr->pan_id);
// Add EAPOL neighbour
cur->ws_info->network_pan_id = selected_parent_ptr->pan_id;
cur->ws_info->pan_information = selected_parent_ptr->pan_information;
cur->ws_info->pan_information.pan_version = 0; // This is learned from actual configuration
ws_bootstrap_fhss_activate(cur);
llc_neighbour_req_t neighbor_info;
if (!ws_bootstrap_neighbor_info_request(cur, selected_parent_ptr->addr, &neighbor_info, true)) {
//Remove Neighbour and set Link setup back
ns_list_remove(&cur->ws_info->parent_list_reserved, selected_parent_ptr);
ns_list_add_to_end(&cur->ws_info->parent_list_free, selected_parent_ptr);
if (ws_bootstrap_neighbor_set(cur, selected_parent_ptr, false) < 0) {
goto select_best_candidate;
}
ws_neighbor_class_neighbor_unicast_time_info_update(neighbor_info.ws_neighbor, &selected_parent_ptr->ws_utt, selected_parent_ptr->timestamp);
ws_neighbor_class_neighbor_unicast_schedule_set(neighbor_info.ws_neighbor, &selected_parent_ptr->ws_us);
ws_pae_controller_set_target(cur, selected_parent_ptr->pan_id, selected_parent_ptr->addr); // temporary!!! store since auth
ws_bootstrap_event_authentication_start(cur);
return;
@ -3305,6 +3427,8 @@ void ws_bootstrap_seconds_timer(protocol_interface_info_entry_t *cur, uint32_t s
}
}
ws_llc_timer_seconds(cur, seconds);
}
void ws_primary_parent_update(protocol_interface_info_entry_t *interface, mac_neighbor_table_entry_t *neighbor)

View File

@ -31,6 +31,7 @@ typedef enum {
struct llc_neighbour_req;
struct ws_us_ie;
struct ws_neighbor_class_entry;
int ws_bootstrap_init(int8_t interface_id, net_6lowpan_mode_e bootstrap_mode);
@ -81,6 +82,12 @@ void ws_bootstrap_eapol_parent_synch(struct protocol_interface_info_entry *cur,
bool ws_bootstrap_validate_channel_plan(struct ws_us_ie *ws_us, struct protocol_interface_info_entry *cur);
void ws_bootstrap_eapol_rx_temporary_set(struct protocol_interface_info_entry *interface, const uint8_t *src64);
struct ws_neighbor_class_entry *ws_bootstrap_eapol_tx_temporary_set(struct protocol_interface_info_entry *interface, const uint8_t *src64);
void ws_bootstrap_eapol_tx_temporary_clear(struct protocol_interface_info_entry *interface);
#else
#define ws_bootstrap_init(interface_id, bootstrap_mode) (-1)

View File

@ -49,8 +49,9 @@
#define TRICKLE_IMIN_15_SECS 15
typedef struct ws_cfg_nw_size_s {
ws_gen_cfg_t gen; /**< General configuration */
ws_timing_cfg_t timing; /**< Timing configuration */
ws_rpl_cfg_t rpl; /**< RPL configuration */
ws_bbr_cfg_t bbr; /**< RPL configuration */
ws_sec_prot_cfg_t sec_prot; /**< Security protocols configuration */
} ws_cfg_nw_size_t;
@ -69,7 +70,7 @@ typedef union {
ws_gen_cfg_t gen;
ws_phy_cfg_t phy;
ws_timing_cfg_t timing;
ws_rpl_cfg_t rpl;
ws_bbr_cfg_t bbr;
ws_fhss_cfg_t fhss;
ws_mpl_cfg_t mpl;
ws_sec_timer_cfg_t sec_timer;
@ -81,12 +82,13 @@ static int8_t ws_cfg_to_get(ws_cfgs_t **cfg, ws_cfgs_t *new_cfg, ws_cfg_validate
static void ws_cfg_network_size_config_set_small(ws_cfg_nw_size_t *cfg);
static void ws_cfg_network_size_config_set_medium(ws_cfg_nw_size_t *cfg);
static void ws_cfg_network_size_config_set_large(ws_cfg_nw_size_t *cfg);
static void ws_cfg_network_size_config_set_xlarge(ws_cfg_nw_size_t *cfg);
static void ws_cfg_network_size_config_set_certificate(ws_cfg_nw_size_t *cfg);
static int8_t ws_cfg_network_size_default_set(ws_gen_cfg_t *cfg);
static int8_t ws_cfg_gen_default_set(ws_gen_cfg_t *cfg);
static int8_t ws_cfg_phy_default_set(ws_phy_cfg_t *cfg);
static int8_t ws_cfg_timing_default_set(ws_timing_cfg_t *cfg);
static int8_t ws_cfg_rpl_default_set(ws_rpl_cfg_t *cfg);
static int8_t ws_cfg_bbr_default_set(ws_bbr_cfg_t *cfg);
static int8_t ws_cfg_mpl_default_set(ws_mpl_cfg_t *cfg);
static int8_t ws_cfg_fhss_default_set(ws_fhss_cfg_t *cfg);
static int8_t ws_cfg_sec_timer_default_set(ws_sec_timer_cfg_t *cfg);
@ -107,7 +109,7 @@ static const ws_cfg_cb_t cfg_cb[] = {
CFG_CB(ws_cfg_gen_default_set, ws_cfg_gen_validate, ws_cfg_gen_set, offsetof(ws_cfg_t, gen)),
CFG_CB(ws_cfg_phy_default_set, ws_cfg_phy_validate, ws_cfg_phy_set, offsetof(ws_cfg_t, phy)),
CFG_CB(ws_cfg_timing_default_set, ws_cfg_timing_validate, ws_cfg_timing_set, offsetof(ws_cfg_t, timing)),
CFG_CB(ws_cfg_rpl_default_set, ws_cfg_rpl_validate, ws_cfg_rpl_set, offsetof(ws_cfg_t, rpl)),
CFG_CB(ws_cfg_bbr_default_set, ws_cfg_bbr_validate, ws_cfg_bbr_set, offsetof(ws_cfg_t, bbr)),
CFG_CB(ws_cfg_mpl_default_set, ws_cfg_mpl_validate, ws_cfg_mpl_set, offsetof(ws_cfg_t, mpl)),
CFG_CB(ws_cfg_fhss_default_set, ws_cfg_fhss_validate, ws_cfg_fhss_set, offsetof(ws_cfg_t, fhss)),
CFG_CB(ws_cfg_sec_timer_default_set, ws_cfg_sec_timer_validate, ws_cfg_sec_timer_set, offsetof(ws_cfg_t, sec_timer)),
@ -128,10 +130,12 @@ static int8_t ws_cfg_to_get(ws_cfgs_t **cfg, ws_cfgs_t *new_cfg, ws_cfg_validate
if (*cfg == NULL) {
// In case external configuration is not same as internal
if (nw_size_external_cfg && (!flags || !(*flags & CFG_FLAGS_FORCE_INTERNAL_CONFIG))) {
if (ws_cfg_ptr == (ws_cfgs_t *) &ws_cfg.timing) {
if (ws_cfg_ptr == (ws_cfgs_t *) &ws_cfg.gen) {
*cfg = (ws_cfgs_t *) &nw_size_external_cfg->gen;
} else if (ws_cfg_ptr == (ws_cfgs_t *) &ws_cfg.timing) {
*cfg = (ws_cfgs_t *) &nw_size_external_cfg->timing;
} else if (ws_cfg_ptr == (ws_cfgs_t *) &ws_cfg.rpl) {
*cfg = (ws_cfgs_t *) &nw_size_external_cfg->rpl;
} else if (ws_cfg_ptr == (ws_cfgs_t *) &ws_cfg.bbr) {
*cfg = (ws_cfgs_t *) &nw_size_external_cfg->bbr;
} else if (ws_cfg_ptr == (ws_cfgs_t *) &ws_cfg.sec_prot) {
*cfg = (ws_cfgs_t *) &nw_size_external_cfg->sec_prot;
} else {
@ -245,8 +249,9 @@ int8_t ws_cfg_network_size_set(protocol_interface_info_entry_t *cur, ws_gen_cfg_
cfg->network_size = new_cfg->network_size;
ws_cfg_nw_size_t nw_size_cfg;
ws_cfg_gen_get(&nw_size_cfg.gen, NULL);
ws_cfg_timing_get(&nw_size_cfg.timing, NULL);
ws_cfg_rpl_get(&nw_size_cfg.rpl, NULL);
ws_cfg_bbr_get(&nw_size_cfg.bbr, NULL);
ws_cfg_sec_prot_get(&nw_size_cfg.sec_prot, NULL);
ws_cfg_network_size_config_set_size set_function = NULL;
@ -257,8 +262,10 @@ int8_t ws_cfg_network_size_set(protocol_interface_info_entry_t *cur, ws_gen_cfg_
set_function = ws_cfg_network_size_config_set_small;
} else if (cfg->network_size <= NETWORK_SIZE_MEDIUM) {
set_function = ws_cfg_network_size_config_set_medium;
} else {
} else if (cfg->network_size <= NETWORK_SIZE_LARGE) {
set_function = ws_cfg_network_size_config_set_large;
} else {
set_function = ws_cfg_network_size_config_set_xlarge;
}
// Overrides the values on the new configuration
@ -279,13 +286,17 @@ int8_t ws_cfg_network_size_set(protocol_interface_info_entry_t *cur, ws_gen_cfg_
}
/* Sets values if changed or network size has been previously automatic (to make sure
the settings are in sync */
if (ws_cfg_gen_validate(&ws_cfg.gen, &nw_size_cfg.gen) == CFG_SETTINGS_CHANGED ||
old_network_size == NETWORK_SIZE_AUTOMATIC) {
ws_cfg_gen_set(cur, &ws_cfg.gen, &nw_size_cfg.gen, &set_flags);
}
if (ws_cfg_timing_validate(&ws_cfg.timing, &nw_size_cfg.timing) == CFG_SETTINGS_CHANGED ||
old_network_size == NETWORK_SIZE_AUTOMATIC) {
ws_cfg_timing_set(cur, &ws_cfg.timing, &nw_size_cfg.timing, &set_flags);
}
if (ws_cfg_rpl_validate(&ws_cfg.rpl, &nw_size_cfg.rpl) == CFG_SETTINGS_CHANGED ||
if (ws_cfg_bbr_validate(&ws_cfg.bbr, &nw_size_cfg.bbr) == CFG_SETTINGS_CHANGED ||
old_network_size == NETWORK_SIZE_AUTOMATIC) {
ws_cfg_rpl_set(cur, &ws_cfg.rpl, &nw_size_cfg.rpl, &set_flags);
ws_cfg_bbr_set(cur, &ws_cfg.bbr, &nw_size_cfg.bbr, &set_flags);
}
if (ws_cfg_sec_prot_validate(&ws_cfg.sec_prot, &nw_size_cfg.sec_prot) == CFG_SETTINGS_CHANGED ||
old_network_size == NETWORK_SIZE_AUTOMATIC) {
@ -305,8 +316,10 @@ int8_t ws_cfg_network_size_configure(protocol_interface_info_entry_t *cur, uint1
// Read settings that are affected by network size
ws_cfg_nw_size_t new_nw_size_cfg;
uint8_t flags = CFG_FLAGS_OVERRIDE_DISABLE_VAL_SET | CFG_FLAGS_FORCE_INTERNAL_CONFIG;
ws_cfg_gen_get(&new_nw_size_cfg.gen, &flags);
ws_cfg_timing_get(&new_nw_size_cfg.timing, &flags);
ws_cfg_rpl_get(&new_nw_size_cfg.rpl, &flags);
ws_cfg_bbr_get(&new_nw_size_cfg.bbr, &flags);
ws_cfg_sec_prot_get(&new_nw_size_cfg.sec_prot, &flags);
if (!nw_size_external_cfg) {
@ -321,16 +334,20 @@ int8_t ws_cfg_network_size_configure(protocol_interface_info_entry_t *cur, uint1
if (network_size < 100) {
// Automatic
ws_cfg_network_size_config_set_small(&new_nw_size_cfg);
} else if (network_size < 300) {
} else if (network_size < 800) {
// Medium
ws_cfg_network_size_config_set_medium(&new_nw_size_cfg);
} else if (network_size < 1500) {
// Medium
ws_cfg_network_size_config_set_large(&new_nw_size_cfg);
} else {
// Large
ws_cfg_network_size_config_set_large(&new_nw_size_cfg);
ws_cfg_network_size_config_set_xlarge(&new_nw_size_cfg);
}
ws_cfg_gen_set(cur, NULL, &new_nw_size_cfg.gen, &flags);
ws_cfg_timing_set(cur, NULL, &new_nw_size_cfg.timing, &flags);
ws_cfg_rpl_set(cur, NULL, &new_nw_size_cfg.rpl, &flags);
ws_cfg_bbr_set(cur, NULL, &new_nw_size_cfg.bbr, &flags);
ws_cfg_sec_prot_set(cur, NULL, &new_nw_size_cfg.sec_prot, &flags);
return CFG_SETTINGS_OK;
@ -338,112 +355,190 @@ int8_t ws_cfg_network_size_configure(protocol_interface_info_entry_t *cur, uint1
static void ws_cfg_network_size_config_set_small(ws_cfg_nw_size_t *cfg)
{
// Configure the Wi-SUN parent configuration
cfg->gen.rpl_parent_candidate_max = WS_RPL_PARENT_CANDIDATE_MAX;
cfg->gen.rpl_selected_parent_max = WS_RPL_SELECTED_PARENT_MAX;
// Configure the Wi-SUN timing trickle parameter
cfg->timing.disc_trickle_imin = TRICKLE_IMIN_15_SECS; // 15 seconds
cfg->timing.disc_trickle_imax = TRICKLE_IMIN_15_SECS << 2; // 60 seconds
cfg->timing.disc_trickle_k = 1;
cfg->timing.pan_timeout = PAN_VERSION_SMALL_NETWORK_TIMEOUT;
cfg->timing.temp_link_min_timeout = WS_NEIGHBOR_TEMPORARY_LINK_MIN_TIMEOUT_SMALL;
cfg->timing.temp_eapol_min_timeout = WS_EAPOL_TEMPORARY_ENTRY_SMALL_TIMEOUT;
// RPL configuration
cfg->rpl.dio_interval_min = WS_RPL_DIO_IMIN_SMALL; // 15; 32s seconds
cfg->rpl.dio_interval_doublings = WS_RPL_DIO_DOUBLING_SMALL; // 2; 128
cfg->rpl.dio_redundancy_constant = WS_RPL_DIO_REDUNDANCY_SMALL; // Disabled
cfg->rpl.dag_max_rank_increase = WS_RPL_MAX_HOP_RANK_INCREASE;
cfg->rpl.min_hop_rank_increase = WS_RPL_MIN_HOP_RANK_INCREASE;
cfg->rpl.rpl_parent_candidate_max = WS_RPL_PARENT_CANDIDATE_MAX;
cfg->rpl.rpl_selected_parent_max = WS_RPL_SELECTED_PARENT_MAX;
cfg->bbr.dio_interval_min = WS_RPL_DIO_IMIN_SMALL; // 15; 32s seconds
cfg->bbr.dio_interval_doublings = WS_RPL_DIO_DOUBLING_SMALL; // 2; 128
cfg->bbr.dio_redundancy_constant = WS_RPL_DIO_REDUNDANCY_SMALL; // Disabled
cfg->bbr.dag_max_rank_increase = WS_RPL_MAX_HOP_RANK_INCREASE;
cfg->bbr.min_hop_rank_increase = WS_RPL_MIN_HOP_RANK_INCREASE;
cfg->bbr.dhcp_address_lifetime = WS_DHCP_ADDRESS_LIFETIME_SMALL;
// EAPOL configuration
cfg->sec_prot.sec_prot_trickle_imin = SEC_PROT_SMALL_IMIN;
cfg->sec_prot.sec_prot_trickle_imax = SEC_PROT_SMALL_IMAX;
cfg->sec_prot.sec_prot_trickle_timer_exp = SEC_PROT_TIMER_EXPIRATIONS;
cfg->sec_prot.sec_prot_retry_timeout = SEC_PROT_RETRY_TIMEOUT_SMALL;
cfg->sec_prot.sec_max_ongoing_authentication = MAX_SIMULTANEOUS_EAP_TLS_NEGOTIATIONS_SMALL;
cfg->sec_prot.sec_max_ongoing_authentication = MAX_SIMULTANEOUS_SECURITY_NEGOTIATIONS_SMALL;
cfg->sec_prot.initial_key_retry_delay = DEFAULT_INITIAL_KEY_RETRY_TIMER;
cfg->sec_prot.initial_key_imin = SMALL_NW_INITIAL_KEY_TRICKLE_IMIN_SECS;
cfg->sec_prot.initial_key_imax = SMALL_NW_INITIAL_KEY_TRICKLE_IMAX_SECS;
cfg->sec_prot.initial_key_retry_cnt = DEFAULT_INITIAL_KEY_RETRY_COUNT;
}
static void ws_cfg_network_size_config_set_medium(ws_cfg_nw_size_t *cfg)
{
// Configure the Wi-SUN parent configuration
cfg->gen.rpl_parent_candidate_max = WS_RPL_PARENT_CANDIDATE_MAX;
cfg->gen.rpl_selected_parent_max = WS_RPL_SELECTED_PARENT_MAX;
// Configure the Wi-SUN timing trickle parameters
cfg->timing.disc_trickle_imin = TRICKLE_IMIN_30_SECS; // 30 seconds
cfg->timing.disc_trickle_imax = TRICKLE_IMIN_30_SECS << 5; // 960 seconds; 16 minutes
cfg->timing.disc_trickle_imin = TRICKLE_IMIN_60_SECS; // 60 seconds
cfg->timing.disc_trickle_imax = TRICKLE_IMIN_60_SECS << 4; // 960 seconds; 16 minutes
cfg->timing.disc_trickle_k = 1;
cfg->timing.pan_timeout = PAN_VERSION_MEDIUM_NETWORK_TIMEOUT;
cfg->timing.temp_link_min_timeout = WS_NEIGHBOR_TEMPORARY_LINK_MIN_TIMEOUT_SMALL;
cfg->timing.temp_eapol_min_timeout = WS_EAPOL_TEMPORARY_ENTRY_MEDIUM_TIMEOUT;
// RPL configuration
cfg->rpl.dio_interval_min = WS_RPL_DIO_IMIN_MEDIUM; // 15; 32s
cfg->rpl.dio_interval_doublings = WS_RPL_DIO_DOUBLING_MEDIUM; // 2; 1024s
cfg->rpl.dio_redundancy_constant = WS_RPL_DIO_REDUNDANCY_MEDIUM; // 10
cfg->rpl.dag_max_rank_increase = WS_RPL_MAX_HOP_RANK_INCREASE;
cfg->rpl.min_hop_rank_increase = WS_RPL_MIN_HOP_RANK_INCREASE;
cfg->rpl.rpl_parent_candidate_max = WS_RPL_PARENT_CANDIDATE_MAX;
cfg->rpl.rpl_selected_parent_max = WS_RPL_SELECTED_PARENT_MAX;
cfg->bbr.dio_interval_min = WS_RPL_DIO_IMIN_MEDIUM; // 17; 128s
cfg->bbr.dio_interval_doublings = WS_RPL_DIO_DOUBLING_MEDIUM; // 3; 1024s
cfg->bbr.dio_redundancy_constant = WS_RPL_DIO_REDUNDANCY_MEDIUM; // 10
cfg->bbr.dag_max_rank_increase = WS_RPL_MAX_HOP_RANK_INCREASE;
cfg->bbr.min_hop_rank_increase = WS_RPL_MIN_HOP_RANK_INCREASE;
cfg->bbr.dhcp_address_lifetime = WS_DHCP_ADDRESS_LIFETIME_MEDIUM;
// EAPOL configuration
cfg->sec_prot.sec_prot_trickle_imin = SEC_PROT_SMALL_IMIN;
cfg->sec_prot.sec_prot_trickle_imax = SEC_PROT_SMALL_IMAX;
cfg->sec_prot.sec_prot_trickle_timer_exp = SEC_PROT_TIMER_EXPIRATIONS;
cfg->sec_prot.sec_prot_retry_timeout = SEC_PROT_RETRY_TIMEOUT_SMALL;
cfg->sec_prot.sec_max_ongoing_authentication = MAX_SIMULTANEOUS_EAP_TLS_NEGOTIATIONS_MEDIUM;
cfg->sec_prot.sec_max_ongoing_authentication = MAX_SIMULTANEOUS_SECURITY_NEGOTIATIONS_MEDIUM;
cfg->sec_prot.initial_key_retry_delay = DEFAULT_INITIAL_KEY_RETRY_TIMER;
cfg->sec_prot.initial_key_imin = MEDIUM_NW_INITIAL_KEY_TRICKLE_IMIN_SECS;
cfg->sec_prot.initial_key_imax = MEDIUM_NW_INITIAL_KEY_TRICKLE_IMAX_SECS;
cfg->sec_prot.initial_key_retry_cnt = DEFAULT_INITIAL_KEY_RETRY_COUNT;
}
static void ws_cfg_network_size_config_set_large(ws_cfg_nw_size_t *cfg)
{
// Configure the Wi-SUN parent configuration
cfg->gen.rpl_parent_candidate_max = WS_RPL_PARENT_CANDIDATE_MAX;
cfg->gen.rpl_selected_parent_max = WS_RPL_SELECTED_PARENT_MAX;
// Configure the Wi-SUN timing trickle parameters
cfg->timing.disc_trickle_imin = TRICKLE_IMIN_60_SECS; // 60 seconds
cfg->timing.disc_trickle_imax = TRICKLE_IMIN_60_SECS << 4; // 960 seconds; 16 minutes
cfg->timing.disc_trickle_imin = TRICKLE_IMIN_60_SECS << 2; // 240 seconds
cfg->timing.disc_trickle_imax = 1536; // 1536 seconds; 25 minutes
cfg->timing.disc_trickle_k = 1;
cfg->timing.pan_timeout = PAN_VERSION_LARGE_NETWORK_TIMEOUT;
cfg->timing.temp_link_min_timeout = WS_NEIGHBOR_TEMPORARY_LINK_MIN_TIMEOUT_LARGE;
cfg->timing.temp_eapol_min_timeout = WS_EAPOL_TEMPORARY_ENTRY_LARGE_TIMEOUT;
// RPL configuration
cfg->rpl.dio_interval_min = WS_RPL_DIO_IMIN_LARGE; // 19; 524s, 9min
cfg->rpl.dio_interval_doublings = WS_RPL_DIO_DOUBLING_LARGE; // 1; 1024s, 17min
cfg->rpl.dio_redundancy_constant = WS_RPL_DIO_REDUNDANCY_LARGE; // 10
cfg->rpl.dag_max_rank_increase = WS_RPL_MAX_HOP_RANK_INCREASE;
cfg->rpl.min_hop_rank_increase = WS_RPL_MIN_HOP_RANK_INCREASE;
cfg->rpl.rpl_parent_candidate_max = WS_RPL_PARENT_CANDIDATE_MAX;
cfg->rpl.rpl_selected_parent_max = WS_RPL_SELECTED_PARENT_MAX;
cfg->bbr.dio_interval_min = WS_RPL_DIO_IMIN_LARGE; // 18; 262s, 4.5min
cfg->bbr.dio_interval_doublings = WS_RPL_DIO_DOUBLING_LARGE; // 3; 2048s, 34min
cfg->bbr.dio_redundancy_constant = WS_RPL_DIO_REDUNDANCY_LARGE; // 10
cfg->bbr.dag_max_rank_increase = WS_RPL_MAX_HOP_RANK_INCREASE;
cfg->bbr.min_hop_rank_increase = WS_RPL_MIN_HOP_RANK_INCREASE;
cfg->bbr.dhcp_address_lifetime = WS_DHCP_ADDRESS_LIFETIME_LARGE;
// EAPOL configuration
cfg->sec_prot.sec_prot_trickle_imin = SEC_PROT_LARGE_IMIN;
cfg->sec_prot.sec_prot_trickle_imax = SEC_PROT_LARGE_IMAX;
cfg->sec_prot.sec_prot_trickle_timer_exp = SEC_PROT_TIMER_EXPIRATIONS;
cfg->sec_prot.sec_prot_retry_timeout = SEC_PROT_RETRY_TIMEOUT_LARGE;
cfg->sec_prot.sec_max_ongoing_authentication = MAX_SIMULTANEOUS_EAP_TLS_NEGOTIATIONS_LARGE;
cfg->sec_prot.sec_max_ongoing_authentication = MAX_SIMULTANEOUS_SECURITY_NEGOTIATIONS_LARGE;
cfg->sec_prot.initial_key_retry_delay = NONE_INITIAL_KEY_RETRY_TIMER;
cfg->sec_prot.initial_key_imin = LARGE_NW_INITIAL_KEY_TRICKLE_IMIN_SECS;
cfg->sec_prot.initial_key_imax = LARGE_NW_INITIAL_KEY_TRICKLE_IMAX_SECS;
cfg->sec_prot.initial_key_retry_cnt = LARGE_NW_INITIAL_KEY_RETRY_COUNT;
}
static void ws_cfg_network_size_config_set_xlarge(ws_cfg_nw_size_t *cfg)
{
// Configure the Wi-SUN parent configuration
cfg->gen.rpl_parent_candidate_max = WS_RPL_PARENT_CANDIDATE_MAX;
cfg->gen.rpl_selected_parent_max = WS_RPL_SELECTED_PARENT_MAX;
// Configure the Wi-SUN timing trickle parameters
cfg->timing.disc_trickle_imin = TRICKLE_IMIN_60_SECS << 2; // 240 seconds
cfg->timing.disc_trickle_imax = 1920; // 1920 seconds; 32 minutes
cfg->timing.disc_trickle_k = 1;
cfg->timing.pan_timeout = PAN_VERSION_XLARGE_NETWORK_TIMEOUT;
cfg->timing.temp_link_min_timeout = WS_NEIGHBOR_TEMPORARY_LINK_MIN_TIMEOUT_LARGE;
cfg->timing.temp_eapol_min_timeout = WS_EAPOL_TEMPORARY_ENTRY_LARGE_TIMEOUT;
// RPL configuration
cfg->bbr.dio_interval_min = WS_RPL_DIO_IMIN_XLARGE; // 18; 262s, 4.5min
cfg->bbr.dio_interval_doublings = WS_RPL_DIO_DOUBLING_XLARGE; // 4; 2048s, 34min
cfg->bbr.dio_redundancy_constant = WS_RPL_DIO_REDUNDANCY_XLARGE; // 10
cfg->bbr.dag_max_rank_increase = WS_RPL_MAX_HOP_RANK_INCREASE;
cfg->bbr.min_hop_rank_increase = WS_RPL_MIN_HOP_RANK_INCREASE;
cfg->bbr.dhcp_address_lifetime = WS_DHCP_ADDRESS_LIFETIME_LARGE;
// EAPOL configuration
cfg->sec_prot.sec_prot_trickle_imin = SEC_PROT_LARGE_IMIN;
cfg->sec_prot.sec_prot_trickle_imax = SEC_PROT_LARGE_IMAX;
cfg->sec_prot.sec_prot_trickle_timer_exp = SEC_PROT_TIMER_EXPIRATIONS;
cfg->sec_prot.sec_prot_retry_timeout = SEC_PROT_RETRY_TIMEOUT_LARGE;
cfg->sec_prot.sec_max_ongoing_authentication = MAX_SIMULTANEOUS_SECURITY_NEGOTIATIONS_LARGE;
cfg->sec_prot.initial_key_retry_delay = NONE_INITIAL_KEY_RETRY_TIMER;
cfg->sec_prot.initial_key_imin = EXTRA_LARGE_NW_INITIAL_KEY_TRICKLE_IMIN_SECS;
cfg->sec_prot.initial_key_imax = EXTRA_LARGE_NW_INITIAL_KEY_TRICKLE_IMAX_SECS;
cfg->sec_prot.initial_key_retry_cnt = EXTRA_LARGE_NW_INITIAL_KEY_RETRY_COUNT;
}
static void ws_cfg_network_size_config_set_certificate(ws_cfg_nw_size_t *cfg)
{
// Configure the Wi-SUN parent configuration
cfg->gen.rpl_parent_candidate_max = WS_CERTIFICATE_RPL_PARENT_CANDIDATE_MAX;
cfg->gen.rpl_selected_parent_max = WS_CERTIFICATE_RPL_SELECTED_PARENT_MAX;
// Configure the Wi-SUN timing trickle parameters
cfg->timing.disc_trickle_imin = TRICKLE_IMIN_15_SECS; // 15 seconds
cfg->timing.disc_trickle_imax = TRICKLE_IMIN_15_SECS << 2; // 60 seconds
cfg->timing.disc_trickle_k = 1;
cfg->timing.pan_timeout = PAN_VERSION_SMALL_NETWORK_TIMEOUT;
cfg->timing.temp_link_min_timeout = WS_NEIGHBOR_TEMPORARY_LINK_MIN_TIMEOUT_SMALL;
cfg->timing.temp_eapol_min_timeout = WS_EAPOL_TEMPORARY_ENTRY_SMALL_TIMEOUT;
// RPL configuration (small)
cfg->rpl.dio_interval_min = WS_RPL_DIO_IMIN_SMALL; // 15; 32s seconds
cfg->rpl.dio_interval_doublings = WS_RPL_DIO_DOUBLING_SMALL; // 2; 128
cfg->rpl.dio_redundancy_constant = WS_RPL_DIO_REDUNDANCY_SMALL; // Disabled
cfg->rpl.dag_max_rank_increase = WS_CERTIFICATE_RPL_MAX_HOP_RANK_INCREASE;
cfg->rpl.min_hop_rank_increase = WS_CERTIFICATE_RPL_MIN_HOP_RANK_INCREASE;
cfg->rpl.rpl_parent_candidate_max = WS_CERTIFICATE_RPL_PARENT_CANDIDATE_MAX;
cfg->rpl.rpl_selected_parent_max = WS_CERTIFICATE_RPL_SELECTED_PARENT_MAX;
cfg->bbr.dio_interval_min = WS_RPL_DIO_IMIN_SMALL; // 15; 32s seconds
cfg->bbr.dio_interval_doublings = WS_RPL_DIO_DOUBLING_SMALL; // 2; 128
cfg->bbr.dio_redundancy_constant = WS_RPL_DIO_REDUNDANCY_SMALL; // Disabled
cfg->bbr.dag_max_rank_increase = WS_CERTIFICATE_RPL_MAX_HOP_RANK_INCREASE;
cfg->bbr.min_hop_rank_increase = WS_CERTIFICATE_RPL_MIN_HOP_RANK_INCREASE;
cfg->bbr.dhcp_address_lifetime = WS_DHCP_ADDRESS_LIFETIME_SMALL;
// EAPOL configuration
cfg->sec_prot.sec_prot_trickle_imin = SEC_PROT_SMALL_IMIN;
cfg->sec_prot.sec_prot_trickle_imax = SEC_PROT_SMALL_IMAX;
cfg->sec_prot.sec_prot_trickle_timer_exp = SEC_PROT_TIMER_EXPIRATIONS;
cfg->sec_prot.sec_prot_retry_timeout = SEC_PROT_RETRY_TIMEOUT_SMALL;
cfg->sec_prot.sec_max_ongoing_authentication = MAX_SIMULTANEOUS_EAP_TLS_NEGOTIATIONS_SMALL;
cfg->sec_prot.sec_max_ongoing_authentication = MAX_SIMULTANEOUS_SECURITY_NEGOTIATIONS_SMALL;
cfg->sec_prot.initial_key_retry_delay = DEFAULT_INITIAL_KEY_RETRY_TIMER;
cfg->sec_prot.initial_key_imin = SMALL_NW_INITIAL_KEY_TRICKLE_IMIN_SECS;
cfg->sec_prot.initial_key_imax = SMALL_NW_INITIAL_KEY_TRICKLE_IMAX_SECS;
cfg->sec_prot.initial_key_retry_cnt = DEFAULT_INITIAL_KEY_RETRY_COUNT;
}
static int8_t ws_cfg_gen_default_set(ws_gen_cfg_t *cfg)
{
memset(cfg->network_name, 0, sizeof(cfg->network_name));
cfg->network_pan_id = 0xffff;
cfg->rpl_parent_candidate_max = WS_RPL_PARENT_CANDIDATE_MAX;
cfg->rpl_selected_parent_max = WS_RPL_SELECTED_PARENT_MAX;
return CFG_SETTINGS_OK;
}
@ -467,7 +562,9 @@ int8_t ws_cfg_gen_validate(ws_gen_cfg_t *cfg, ws_gen_cfg_t *new_cfg)
// Regulator domain, operating mode or class has changed
if (strcmp(cfg->network_name, new_cfg->network_name) != 0 ||
cfg->network_pan_id != new_cfg->network_pan_id) {
cfg->network_pan_id != new_cfg->network_pan_id ||
cfg->rpl_parent_candidate_max != new_cfg->rpl_parent_candidate_max ||
cfg->rpl_selected_parent_max != new_cfg->rpl_selected_parent_max) {
return CFG_SETTINGS_CHANGED;
}
@ -493,6 +590,8 @@ int8_t ws_cfg_gen_set(protocol_interface_info_entry_t *cur, ws_gen_cfg_t *cfg, w
strncpy(cfg->network_name, new_cfg->network_name, 32);
}
cfg->network_pan_id = new_cfg->network_pan_id;
cfg->rpl_parent_candidate_max = new_cfg->rpl_parent_candidate_max;
cfg->rpl_selected_parent_max = new_cfg->rpl_selected_parent_max;
if (cur && !(cfg_flags & CFG_FLAGS_BOOTSTRAP_RESTART_DISABLE)) {
ws_bootstrap_restart_delayed(cur->id);
@ -584,11 +683,12 @@ int8_t ws_cfg_phy_set(protocol_interface_info_entry_t *cur, ws_phy_cfg_t *cfg, w
static int8_t ws_cfg_timing_default_set(ws_timing_cfg_t *cfg)
{
// Configure the Wi-SUN timing trickle parameters
cfg->disc_trickle_imin = TRICKLE_IMIN_30_SECS; // 30 seconds
cfg->disc_trickle_imax = TRICKLE_IMIN_30_SECS << 5; // 960 seconds; 16 minutes
cfg->disc_trickle_imin = TRICKLE_IMIN_60_SECS; // 60 seconds
cfg->disc_trickle_imax = TRICKLE_IMIN_60_SECS << 4; // 960 seconds; 16 minutes
cfg->disc_trickle_k = 1;
cfg->pan_timeout = PAN_VERSION_MEDIUM_NETWORK_TIMEOUT;
cfg->temp_link_min_timeout = WS_NEIGHBOR_TEMPORARY_LINK_MIN_TIMEOUT_SMALL;
cfg->temp_eapol_min_timeout = WS_EAPOL_TEMPORARY_ENTRY_MEDIUM_TIMEOUT;
return CFG_SETTINGS_OK;
}
@ -658,58 +758,56 @@ int8_t ws_cfg_timing_set(protocol_interface_info_entry_t *cur, ws_timing_cfg_t *
return CFG_SETTINGS_OK;
}
static int8_t ws_cfg_rpl_default_set(ws_rpl_cfg_t *cfg)
static int8_t ws_cfg_bbr_default_set(ws_bbr_cfg_t *cfg)
{
// Something in between
// imin: 15 (32s)
// doublings:5 (960s)
// imin: 17 (128s)
// doublings:3 (1024s)
// redundancy; 10
//ws_bbr_rpl_config(cur, 15, 5, 10, WS_RPL_MAX_HOP_RANK_INCREASE, WS_RPL_MIN_HOP_RANK_INCREASE);
//ws_bbr_rpl_config(cur, 17, 3, 10, WS_RPL_MAX_HOP_RANK_INCREASE, WS_RPL_MIN_HOP_RANK_INCREASE);
cfg->dio_interval_min = 15; // 32s
cfg->dio_interval_doublings = 5; // 1024s
cfg->dio_interval_min = WS_RPL_DIO_IMIN_MEDIUM; // 128s
cfg->dio_interval_doublings = WS_RPL_DIO_DOUBLING_MEDIUM; // 1024s
cfg->dio_redundancy_constant = 10;
cfg->dag_max_rank_increase = WS_RPL_MAX_HOP_RANK_INCREASE;
cfg->min_hop_rank_increase = WS_RPL_MIN_HOP_RANK_INCREASE;
cfg->rpl_parent_candidate_max = WS_RPL_PARENT_CANDIDATE_MAX;
cfg->rpl_selected_parent_max = WS_RPL_SELECTED_PARENT_MAX;
cfg->dhcp_address_lifetime = WS_DHCP_ADDRESS_LIFETIME_MEDIUM;
return CFG_SETTINGS_OK;
}
int8_t ws_cfg_rpl_get(ws_rpl_cfg_t *cfg, uint8_t *flags)
int8_t ws_cfg_bbr_get(ws_bbr_cfg_t *cfg, uint8_t *flags)
{
ws_rpl_cfg_t *get_cfg = NULL;
ws_cfg_to_get((ws_cfgs_t **) &get_cfg, NULL, NULL, (ws_cfgs_t *) &ws_cfg.rpl, 0, flags);
ws_bbr_cfg_t *get_cfg = NULL;
ws_cfg_to_get((ws_cfgs_t **) &get_cfg, NULL, NULL, (ws_cfgs_t *) &ws_cfg.bbr, 0, flags);
*cfg = *get_cfg;
return CFG_SETTINGS_OK;
}
int8_t ws_cfg_rpl_validate(ws_rpl_cfg_t *cfg, ws_rpl_cfg_t *new_cfg)
int8_t ws_cfg_bbr_validate(ws_bbr_cfg_t *cfg, ws_bbr_cfg_t *new_cfg)
{
ws_cfg_to_get((ws_cfgs_t **) &cfg, (ws_cfgs_t *) new_cfg, NULL, (ws_cfgs_t *) &ws_cfg.rpl, 0, 0);
ws_cfg_to_get((ws_cfgs_t **) &cfg, (ws_cfgs_t *) new_cfg, NULL, (ws_cfgs_t *) &ws_cfg.bbr, 0, 0);
if (cfg->dio_interval_min != new_cfg->dio_interval_min ||
cfg->dio_interval_doublings != new_cfg->dio_interval_doublings ||
cfg->dio_redundancy_constant != new_cfg->dio_redundancy_constant ||
cfg->dag_max_rank_increase != new_cfg->dag_max_rank_increase ||
cfg->min_hop_rank_increase != new_cfg->min_hop_rank_increase ||
cfg->rpl_parent_candidate_max != new_cfg->rpl_parent_candidate_max ||
cfg->rpl_selected_parent_max != new_cfg->rpl_selected_parent_max) {
cfg->dhcp_address_lifetime != new_cfg->dhcp_address_lifetime) {
return CFG_SETTINGS_CHANGED;
}
return CFG_SETTINGS_OK;
}
int8_t ws_cfg_rpl_set(protocol_interface_info_entry_t *cur, ws_rpl_cfg_t *cfg, ws_rpl_cfg_t *new_cfg, uint8_t *flags)
int8_t ws_cfg_bbr_set(protocol_interface_info_entry_t *cur, ws_bbr_cfg_t *cfg, ws_bbr_cfg_t *new_cfg, uint8_t *flags)
{
(void) cur;
(void) flags;
uint8_t cfg_flags;
int8_t ret = ws_cfg_to_get((ws_cfgs_t **) &cfg, (ws_cfgs_t *) new_cfg, (ws_cfg_validate) ws_cfg_rpl_validate, (ws_cfgs_t *) &ws_cfg.rpl, &cfg_flags, flags);
int8_t ret = ws_cfg_to_get((ws_cfgs_t **) &cfg, (ws_cfgs_t *) new_cfg, (ws_cfg_validate) ws_cfg_bbr_validate, (ws_cfgs_t *) &ws_cfg.bbr, &cfg_flags, flags);
if (ret != CFG_SETTINGS_CHANGED) {
return ret;
}
@ -719,13 +817,14 @@ int8_t ws_cfg_rpl_set(protocol_interface_info_entry_t *cur, ws_rpl_cfg_t *cfg, w
ws_bbr_rpl_config(cur, new_cfg->dio_interval_min, new_cfg->dio_interval_doublings,
new_cfg->dio_redundancy_constant, new_cfg->dag_max_rank_increase,
new_cfg->min_hop_rank_increase);
ws_bbr_dhcp_address_lifetime_set(cur, new_cfg->dhcp_address_lifetime);
}
if (cfg == new_cfg) {
return CFG_SETTINGS_OK;
}
ws_cfg_trace((ws_cfgs_t *) cfg, (ws_cfgs_t *) new_cfg, sizeof(ws_rpl_cfg_t), "rpl");
ws_cfg_trace((ws_cfgs_t *) cfg, (ws_cfgs_t *) new_cfg, sizeof(ws_bbr_cfg_t), "rpl");
*cfg = *new_cfg;
@ -978,7 +1077,12 @@ static int8_t ws_cfg_sec_prot_default_set(ws_sec_prot_cfg_t *cfg)
cfg->sec_prot_trickle_imax = SEC_PROT_SMALL_IMAX;
cfg->sec_prot_trickle_timer_exp = 2;
cfg->sec_prot_retry_timeout = SEC_PROT_RETRY_TIMEOUT_SMALL;
cfg->sec_max_ongoing_authentication = MAX_SIMULTANEOUS_EAP_TLS_NEGOTIATIONS_MEDIUM;
cfg->sec_max_ongoing_authentication = MAX_SIMULTANEOUS_SECURITY_NEGOTIATIONS_MEDIUM;
cfg->initial_key_retry_delay = DEFAULT_INITIAL_KEY_RETRY_TIMER;
cfg->initial_key_imin = MEDIUM_NW_INITIAL_KEY_TRICKLE_IMIN_SECS;
cfg->initial_key_imax = MEDIUM_NW_INITIAL_KEY_TRICKLE_IMAX_SECS;
cfg->initial_key_retry_cnt = DEFAULT_INITIAL_KEY_RETRY_COUNT;
return CFG_SETTINGS_OK;
}
@ -999,7 +1103,11 @@ int8_t ws_cfg_sec_prot_validate(ws_sec_prot_cfg_t *cfg, ws_sec_prot_cfg_t *new_c
cfg->sec_prot_trickle_imax != new_cfg->sec_prot_trickle_imax ||
cfg->sec_prot_trickle_timer_exp != new_cfg->sec_prot_trickle_timer_exp ||
cfg->sec_prot_retry_timeout != new_cfg->sec_prot_retry_timeout ||
cfg->sec_max_ongoing_authentication != new_cfg->sec_max_ongoing_authentication) {
cfg->sec_max_ongoing_authentication != new_cfg->sec_max_ongoing_authentication ||
cfg->initial_key_retry_delay != new_cfg->initial_key_retry_delay ||
cfg->initial_key_imin != new_cfg->initial_key_retry_delay ||
cfg->initial_key_imax != new_cfg->initial_key_retry_delay ||
cfg->initial_key_retry_cnt != new_cfg->initial_key_retry_delay) {
return CFG_SETTINGS_CHANGED;
}
@ -1095,8 +1203,9 @@ int8_t ws_cfg_settings_get(protocol_interface_info_entry_t *cur, ws_cfg_t *cfg)
*cfg = ws_cfg;
ws_cfg_gen_get(&cfg->gen, NULL);
ws_cfg_timing_get(&cfg->timing, NULL);
ws_cfg_rpl_get(&cfg->rpl, NULL);
ws_cfg_bbr_get(&cfg->bbr, NULL);
ws_cfg_sec_prot_get(&cfg->sec_prot, NULL);
return CFG_SETTINGS_OK;

View File

@ -27,6 +27,8 @@ typedef struct ws_gen_cfg_s {
uint8_t network_size; /**< Network size selection; default medium (= 8) */
char network_name[33]; /**< Network name; max 32 octets + terminating 0 */
uint16_t network_pan_id; /**< PAN identifier; PAN_ID; default 0xffff */
uint16_t rpl_parent_candidate_max; /**< RPL parent candidate maximum value; default 5 */
uint16_t rpl_selected_parent_max; /**< RPL selected parent maximum value; default 2 */
} ws_gen_cfg_t;
/**
@ -47,20 +49,20 @@ typedef struct ws_timing_cfg_s {
uint8_t disc_trickle_k; /**< Discovery trickle k; DISC_K; default 1 */
uint16_t pan_timeout; /**< PAN timeout; PAN_TIMEOUT; seconds; range 60-15300; default 3840 */
uint16_t temp_link_min_timeout; /**< Temporary neighbor link minimum timeout; seconds; default 260 */
uint16_t temp_eapol_min_timeout; /**< Temporary neighbor link minimum timeout; seconds; default 330 */
} ws_timing_cfg_t;
/**
* \brief Struct ws_rpl_cfg_t RPL configuration
*/
typedef struct ws_rpl_cfg_s {
typedef struct ws_bbr_cfg_s {
uint8_t dio_interval_min; /**> DIO interval min; DEFAULT_DIO_INTERVAL_MIN; 2^value in milliseconds; range 1-255; default */
uint8_t dio_interval_doublings; /**> DIO interval doublings; DEFAULT_DIO_INTERVAL_DOUBLINGS; range 1-8; default */
uint8_t dio_redundancy_constant; /**> DIO redundancy constant; DEFAULT_DIO_REDUNDANCY_CONSTANT; range 0-10; default */
uint16_t dag_max_rank_increase;
uint16_t min_hop_rank_increase;
uint16_t rpl_parent_candidate_max; /**< RPL parent candidate maximum value; default 5 */
uint16_t rpl_selected_parent_max; /**< RPL selected parent maximum value; default 2 */
} ws_rpl_cfg_t;
uint32_t dhcp_address_lifetime; /**> DHCP address lifetime in seconds minimum 2 hours and maximum as days hours*/
} ws_bbr_cfg_t;
/**
* \brief Struct ws_fhss_cfg_t Frequency hopping configuration
@ -106,11 +108,15 @@ typedef struct ws_sec_timer_cfg_s {
* \brief Struct ws_sec_prot_cfg_t Security protocols configuration
*/
typedef struct ws_sec_prot_cfg_s {
uint16_t sec_prot_retry_timeout; /**< Security protocol retry timeout; seconds; default 330 */
uint16_t sec_prot_trickle_imin; /**< Security protocol trickle parameters Imin; seconds; default 30 */
uint16_t sec_prot_trickle_imax; /**< Security protocol trickle parameters Imax; seconds; default 90 */
uint8_t sec_prot_trickle_timer_exp; /**< Security protocol trickle timer expirations; default 2 */
uint16_t sec_max_ongoing_authentication; /**< Pae authenticator max Accept ongoing authentication count */
uint16_t sec_prot_retry_timeout; /**< Security protocol retry timeout; seconds; default 330 */
uint16_t sec_prot_trickle_imin; /**< Security protocol trickle parameters Imin; seconds; default 30 */
uint16_t sec_prot_trickle_imax; /**< Security protocol trickle parameters Imax; seconds; default 90 */
uint8_t sec_prot_trickle_timer_exp; /**< Security protocol trickle timer expirations; default 2 */
uint16_t sec_max_ongoing_authentication; /**< Pae authenticator max Accept ongoing authentication count */
uint16_t initial_key_retry_delay; /**< Delay before starting initial key trickle; seconds; default 120 */
uint16_t initial_key_imin; /**< Initial key trickle Imin; seconds; default 360 */
uint16_t initial_key_imax; /**< Initial key trickle Imax; seconds; default 720 */
uint8_t initial_key_retry_cnt; /**< Number of initial key retries; default 2 */
} ws_sec_prot_cfg_t;
/**
@ -120,7 +126,7 @@ typedef struct ws_cfg_s {
ws_gen_cfg_t gen; /**< General configuration */
ws_phy_cfg_t phy; /**< Physical layer configuration */
ws_timing_cfg_t timing; /**< Timing configuration */
ws_rpl_cfg_t rpl; /**< RPL configuration */
ws_bbr_cfg_t bbr; /**< RPL configuration */
ws_fhss_cfg_t fhss; /**< Frequency hopping configuration */
ws_mpl_cfg_t mpl; /**< Multicast configuration */
ws_sec_timer_cfg_t sec_timer; /**< Security timers configuration */
@ -161,9 +167,9 @@ int8_t ws_cfg_timing_get(ws_timing_cfg_t *cfg, uint8_t *flags);
int8_t ws_cfg_timing_validate(ws_timing_cfg_t *cfg, ws_timing_cfg_t *new_cfg);
int8_t ws_cfg_timing_set(protocol_interface_info_entry_t *cur, ws_timing_cfg_t *cfg, ws_timing_cfg_t *new_cfg, uint8_t *flags);
int8_t ws_cfg_rpl_get(ws_rpl_cfg_t *cfg, uint8_t *flags);
int8_t ws_cfg_rpl_validate(ws_rpl_cfg_t *cfg, ws_rpl_cfg_t *new_cfg);
int8_t ws_cfg_rpl_set(protocol_interface_info_entry_t *cur, ws_rpl_cfg_t *cfg, ws_rpl_cfg_t *new_cfg, uint8_t *flags);
int8_t ws_cfg_bbr_get(ws_bbr_cfg_t *cfg, uint8_t *flags);
int8_t ws_cfg_bbr_validate(ws_bbr_cfg_t *cfg, ws_bbr_cfg_t *new_cfg);
int8_t ws_cfg_bbr_set(protocol_interface_info_entry_t *cur, ws_bbr_cfg_t *cfg, ws_bbr_cfg_t *new_cfg, uint8_t *flags);
int8_t ws_cfg_mpl_get(ws_mpl_cfg_t *cfg, uint8_t *flags);
int8_t ws_cfg_mpl_validate(ws_mpl_cfg_t *cfg, ws_mpl_cfg_t *new_cfg);

View File

@ -49,12 +49,34 @@ uint8_t DEVICE_MIN_SENS = 174 - 93;
uint16_t test_max_child_count_override = 0xffff;
int8_t ws_generate_channel_list(uint32_t *channel_mask, uint16_t number_of_channels, uint8_t regulatory_domain)
int8_t ws_generate_channel_list(uint32_t *channel_mask, uint16_t number_of_channels, uint8_t regulatory_domain, uint8_t operating_class)
{
(void)regulatory_domain;
for (uint8_t i = 0; i < number_of_channels; i++) {
channel_mask[0 + (i / 32)] |= (1 << (i % 32));
uint32_t excluded_start_channel = 0xFFFFFFFF;
uint32_t excluded_end_channel = 0xFFFFFFFF;
if (regulatory_domain == REG_DOMAIN_BZ) {
if (operating_class == 1) {
excluded_start_channel = 26;
excluded_end_channel = 64;
} else if (operating_class == 2) {
excluded_start_channel = 12;
excluded_end_channel = 32;
} else if (operating_class == 3) {
excluded_start_channel = 7;
excluded_end_channel = 21;
}
}
// Clear channel mask
for (uint8_t i = 0; i < 8; i++) {
channel_mask[i] = 0;
}
// Set channel maks outside excluded channels
for (uint16_t i = 0; i < number_of_channels; i++) {
if (i < excluded_start_channel || i > excluded_end_channel) {
channel_mask[0 + (i / 32)] |= (1 << (i % 32));
}
}
return 0;
}
@ -159,6 +181,19 @@ int8_t ws_common_regulatory_domain_config(protocol_interface_info_entry_t *cur,
} else {
return -1;
}
} else if (hopping_schdule->regulatory_domain == REG_DOMAIN_BZ) {
if (hopping_schdule->operating_class == 1) {
hopping_schdule->ch0_freq = 9022;
hopping_schdule->channel_spacing = CHANNEL_SPACING_200;
} else if (hopping_schdule->operating_class == 2) {
hopping_schdule->ch0_freq = 9024;
hopping_schdule->channel_spacing = CHANNEL_SPACING_400;
} else if (hopping_schdule->operating_class == 3) {
hopping_schdule->ch0_freq = 9026;
hopping_schdule->channel_spacing = CHANNEL_SPACING_600;
} else {
return -1;
}
} else if (hopping_schdule->regulatory_domain == REG_DOMAIN_JP) {
if (hopping_schdule->operating_class == 1) {
hopping_schdule->ch0_freq = 9206;
@ -189,6 +224,7 @@ int8_t ws_common_regulatory_domain_config(protocol_interface_info_entry_t *cur,
if (!hopping_schdule->number_of_channels) {
return -1;
}
return 0;
}
@ -232,6 +268,14 @@ uint16_t ws_common_channel_number_calc(uint8_t regulatory_domain, uint8_t operat
} else if (operating_class == 3) {
return 12;
}
} else if (regulatory_domain == REG_DOMAIN_BZ) {
if (operating_class == 1) {
return 129;
} else if (operating_class == 2) {
return 64;
} else if (operating_class == 3) {
return 42;
}
} else if (regulatory_domain == REG_DOMAIN_WW) {
if (operating_class == 1) {
// TODO we dont support this yet, but it is used as test value
@ -388,11 +432,13 @@ uint32_t ws_common_latency_estimate_get(protocol_interface_info_entry_t *cur)
if (network_size <= NETWORK_SIZE_SMALL) {
// handles also NETWORK_SIZE_CERTIFICATE
latency = 8000;
latency = 4000;
} else if (network_size <= NETWORK_SIZE_MEDIUM) {
latency = 8000;
} else if (network_size <= NETWORK_SIZE_LARGE) {
latency = 16000;
} else {
latency = 32000;
latency = 24000;
}
return latency;
@ -405,22 +451,11 @@ uint32_t ws_common_datarate_get(protocol_interface_info_entry_t *cur)
uint32_t ws_common_network_size_estimate_get(protocol_interface_info_entry_t *cur)
{
uint32_t network_size_estimate = 0;
uint8_t network_size = cur->ws_info->cfg->gen.network_size;
uint32_t network_size_estimate = 100;
if (network_size == NETWORK_SIZE_AUTOMATIC) {
network_size = cur->ws_info->pan_information.pan_size / 100;
}
if (network_size <= NETWORK_SIZE_SMALL) {
// tens of devices (now 30), handles also NETWORK_SIZE_CERTIFICATE
network_size_estimate = 30;
} else if (network_size <= NETWORK_SIZE_MEDIUM) {
// hundreds of devices (now 300)
network_size_estimate = 300;
} else {
// huge amount of devices (now 1000)
network_size_estimate = 1000;
if ((cur->ws_info->cfg->gen.network_size != NETWORK_SIZE_AUTOMATIC) &&
(cur->ws_info->cfg->gen.network_size != NETWORK_SIZE_CERTIFICATE)) {
network_size_estimate = cur->ws_info->cfg->gen.network_size * 100;
}
return network_size_estimate;

View File

@ -82,6 +82,7 @@ typedef struct ws_info_s {
trickle_params_t trickle_params_pan_discovery;
uint8_t rpl_state; // state from rpl_event_t
uint8_t pas_requests; // Amount of PAN solicits sent
uint8_t eapol_tx_index;
parent_info_t parent_info[WS_PARENT_LIST_SIZE];
parent_info_list_t parent_list_free;
parent_info_list_t parent_list_reserved;
@ -112,7 +113,7 @@ typedef struct ws_info_s {
#ifdef HAVE_WS
int8_t ws_generate_channel_list(uint32_t *channel_mask, uint16_t number_of_channels, uint8_t regulatory_domain);
int8_t ws_generate_channel_list(uint32_t *channel_mask, uint16_t number_of_channels, uint8_t regulatory_domain, uint8_t operating_class);
uint32_t ws_decode_channel_spacing(uint8_t channel_spacing);

View File

@ -236,9 +236,12 @@ typedef struct ws_bs_ie {
#define WS_NEIGHBOR_TEMPORARY_LINK_MIN_TIMEOUT_SMALL 260
#define WS_NEIGHBOR_NUD_TIMEOUT WS_NEIGHBOR_LINK_TIMEOUT / 2
#define WS_EAPOL_TEMPORARY_ENTRY_SMALL_TIMEOUT 330
#define WS_EAPOL_TEMPORARY_ENTRY_MEDIUM_TIMEOUT WS_EAPOL_TEMPORARY_ENTRY_SMALL_TIMEOUT
#define WS_EAPOL_TEMPORARY_ENTRY_LARGE_TIMEOUT 750
#define WS_NEIGHBOR_ETX_SAMPLE_MAX 3
#define WS_NEIGHBOR_FIRST_ETX_SAMPLE_MIN_COUNT 3 //This can't be bigger than WS_NEIGHBOR_ETX_SAMPLE_MAX
#define WS_NEIGHBOUR_MAX_CANDIDATE_PROBE 5
#define WS_PROBE_INIT_BASE_SECONDS 8
@ -295,6 +298,34 @@ typedef struct ws_bs_ie {
*/
#define WS_TACK_MAX_MS 5
/* WS requires at least 19 MAC retransmissions (total 1+19=20 attempts). Default 802.15.4 macMaxFrameRetries is 3 (total 1+3=4 attempts).
* At least 4 channel retries must be used: (Initial channel + WS_NUMBER_OF_CHANNEL_RETRIES) * MAC attempts = (1+4)*4=20 attempts
*
* Valid settings could be for example:
* WS_MAX_FRAME_RETRIES WS_NUMBER_OF_CHANNEL_RETRIES Total attempts
* 0 19 1+0*1+19=20
* 1 9 1+1*1+9=20
* 2 6 1+2*1+6=21
* 3 4 1+3*1+4=20
*
*/
#define WS_MAX_FRAME_RETRIES 3
#define WS_NUMBER_OF_CHANNEL_RETRIES 4
#if (1 + WS_MAX_FRAME_RETRIES) * (1 + WS_NUMBER_OF_CHANNEL_RETRIES) < 20
#warning "MAX frame retries set too low"
#endif
/*
* Automatic CCA threshold: default threshold and range in dBm.
*/
#define CCA_DEFAULT_DBM -60
#define CCA_HIGH_LIMIT -60
#define CCA_LOW_LIMIT -100
/*
* Config new version consistent filter period in 100ms periods
*/

View File

@ -31,14 +31,18 @@
#define WS_RPL_DIO_DOUBLING_SMALL 2
#define WS_RPL_DIO_REDUNDANCY_SMALL 0
#define WS_RPL_DIO_IMIN_MEDIUM 15
#define WS_RPL_DIO_DOUBLING_MEDIUM 5
#define WS_RPL_DIO_IMIN_MEDIUM 17
#define WS_RPL_DIO_DOUBLING_MEDIUM 3
#define WS_RPL_DIO_REDUNDANCY_MEDIUM 10
#define WS_RPL_DIO_IMIN_LARGE 19
#define WS_RPL_DIO_DOUBLING_LARGE 1
#define WS_RPL_DIO_IMIN_LARGE 18
#define WS_RPL_DIO_DOUBLING_LARGE 3
#define WS_RPL_DIO_REDUNDANCY_LARGE 10 // May need some tuning still
#define WS_RPL_DIO_IMIN_XLARGE 18
#define WS_RPL_DIO_DOUBLING_XLARGE 4
#define WS_RPL_DIO_REDUNDANCY_XLARGE 10 // May need some tuning still
#define WS_RPL_DIO_IMIN_AUTOMATIC 14
#define WS_RPL_DIO_DOUBLING_AUTOMATIC 3
#define WS_RPL_DIO_REDUNDANCY_AUTOMATIC 0
@ -46,6 +50,10 @@
#define WS_RPL_MIN_HOP_RANK_INCREASE 196
#define WS_RPL_MAX_HOP_RANK_INCREASE 2048
#define WS_DHCP_ADDRESS_LIFETIME_SMALL 2*3600 // small networks less than devices 100
#define WS_DHCP_ADDRESS_LIFETIME_MEDIUM 12*3600 // Medium size networks from 100 - 1000 device networks
#define WS_DHCP_ADDRESS_LIFETIME_LARGE 24*3600 // Large size networks 1000 + device networks
#define WS_CERTIFICATE_RPL_MIN_HOP_RANK_INCREASE 128
#define WS_CERTIFICATE_RPL_MAX_HOP_RANK_INCREASE 0
@ -64,7 +72,10 @@
// RPL version number update intervall
// after restart version numbers are increased faster and then slowed down when network is stable
#define RPL_VERSION_LIFETIME 12*3600
#define RPL_VERSION_LIFETIME_RESTART 3600
#define RPL_VERSION_LIFETIME_RESTART_SMALL 3600
#define RPL_VERSION_LIFETIME_RESTART_MEDIUM 2*3600
#define RPL_VERSION_LIFETIME_RESTART_LARGE 4*3600
#define RPL_VERSION_LIFETIME_RESTART_EXTRA_LARGE 8*3600
/* Border router connection lost timeout
*
@ -81,6 +92,8 @@
#define PAN_VERSION_LARGE_NETWORK_TIMEOUT 90*60
#define PAN_VERSION_XLARGE_NETWORK_TIMEOUT 120*60
/* Routing Cost Weighting factor
*/
#define PRC_WEIGHT_FACTOR 256
@ -153,10 +166,11 @@ extern uint8_t DEVICE_MIN_SENS;
/*
* MAC frame counter NVM storing configuration
*/
#define FRAME_COUNTER_STORE_INTERVAL 60 // Time interval (on seconds) between frame counter store operations
#define FRAME_COUNTER_STORE_TRIGGER 5 // Delay (on seconds) before storing, when storing of frame counters is triggered
#define FRAME_COUNTER_INCREMENT 1000 // How much frame counter is incremented on start up
#define FRAME_COUNTER_STORE_THRESHOLD 800 // How much frame counter must increment before it is stored
#define FRAME_COUNTER_STORE_INTERVAL 60 // Time interval (on seconds) between checking if frame counter storing is needed
#define FRAME_COUNTER_STORE_FORCE_INTERVAL (3600 * 20) // Time interval (on seconds) before frame counter storing is forced (if no other storing operations triggered)
#define FRAME_COUNTER_STORE_TRIGGER 5 // Delay (on seconds) before storing, when storing of frame counters is triggered
#define FRAME_COUNTER_INCREMENT 1000 // How much frame counter is incremented on start up
#define FRAME_COUNTER_STORE_THRESHOLD 800 // How much frame counter must increment before it is stored
/*
@ -199,10 +213,10 @@ extern uint8_t DEVICE_MIN_SENS;
#define SEC_PROT_TIMER_EXPIRATIONS 2 // Number of retries
// Maximum number of simultaneous EAP-TLS negotiations
#define MAX_SIMULTANEOUS_EAP_TLS_NEGOTIATIONS_SMALL 3
#define MAX_SIMULTANEOUS_EAP_TLS_NEGOTIATIONS_MEDIUM 20
#define MAX_SIMULTANEOUS_EAP_TLS_NEGOTIATIONS_LARGE 50
// Maximum number of simultaneous security negotiations
#define MAX_SIMULTANEOUS_SECURITY_NEGOTIATIONS_SMALL 3
#define MAX_SIMULTANEOUS_SECURITY_NEGOTIATIONS_MEDIUM 20
#define MAX_SIMULTANEOUS_SECURITY_NEGOTIATIONS_LARGE 50
/*
* Security protocol timer configuration parameters
@ -218,4 +232,33 @@ extern uint8_t DEVICE_MIN_SENS;
#define DEFAULT_GTK_MAX_MISMATCH 64 // 64 minutes
#define DEFAULT_GTK_NEW_INSTALL_REQUIRED 80 // 80 percent of GTK lifetime --> 24 days
/*
* Security protocol initial EAPOL-key parameters
*/
// How long the wait is before the first initial EAPOL-key retry
#define DEFAULT_INITIAL_KEY_RETRY_TIMER 120
#define NONE_INITIAL_KEY_RETRY_TIMER 0
// Small network Default trickle values for sending of initial EAPOL-key
#define SMALL_NW_INITIAL_KEY_TRICKLE_IMIN_SECS 360 /* 6 to 8.3 minutes */
#define SMALL_NW_INITIAL_KEY_TRICKLE_IMAX_SECS 500
// Small network Default trickle values for sending of initial EAPOL-key
#define MEDIUM_NW_INITIAL_KEY_TRICKLE_IMIN_SECS 360 /* 6 to 12 minutes */
#define MEDIUM_NW_INITIAL_KEY_TRICKLE_IMAX_SECS 720
// Large network trickle values for sending of initial EAPOL-key
#define LARGE_NW_INITIAL_KEY_TRICKLE_IMIN_SECS 600 /* 10 to 20 minutes */
#define LARGE_NW_INITIAL_KEY_TRICKLE_IMAX_SECS 1200
#define LARGE_NW_INITIAL_KEY_RETRY_COUNT 4
// Very slow network values for sending of initial EAPOL-key
#define EXTRA_LARGE_NW_INITIAL_KEY_TRICKLE_IMIN_SECS 600 /* 10 to 20 minutes */
#define EXTRA_LARGE_NW_INITIAL_KEY_TRICKLE_IMAX_SECS 1200
#define EXTRA_LARGE_NW_INITIAL_KEY_RETRY_COUNT 4
// How many times sending of initial EAPOL-key is retried
#define DEFAULT_INITIAL_KEY_RETRY_COUNT 2
#endif /* WS_CONFIG_H_ */

View File

@ -31,6 +31,7 @@
#include "6LoWPAN/MAC/mpx_api.h"
#include "6LoWPAN/ws/ws_config.h"
#include "6LoWPAN/ws/ws_eapol_pdu.h"
#include "6LoWPAN/ws/ws_llc.h"
#ifdef HAVE_WS
@ -49,6 +50,7 @@ typedef NS_LIST_HEAD(eapol_pdu_msdu_t, link) eapol_pdu_msdu_list_t;
typedef struct {
uint8_t priority;
bool filter_requsted: 1;
ws_eapol_pdu_address_check *addr_check;
ws_eapol_pdu_receive *receive;
ns_list_link_t link;
@ -147,6 +149,7 @@ int8_t ws_eapol_pdu_cb_register(protocol_interface_info_entry_t *interface_ptr,
new_cb->priority = cb_data->priority;
new_cb->addr_check = cb_data->addr_check;
new_cb->receive = cb_data->receive;
new_cb->filter_requsted = cb_data->filter_requsted;
ns_list_foreach(eapol_pdu_recv_cb_t, entry, &eapol_pdu_data->recv_cb_list) {
if (new_cb->priority <= entry->priority) {
@ -307,6 +310,11 @@ static void ws_eapol_pdu_mpx_data_indication(const mpx_api_t *api, const struct
ns_list_foreach(eapol_pdu_recv_cb_t, entry, &eapol_pdu_data->recv_cb_list) {
if (entry->addr_check(eapol_pdu_data->interface_ptr, data->SrcAddr) >= 0) {
if (entry->filter_requsted && !ws_llc_eapol_relay_forward_filter(eapol_pdu_data->interface_ptr, data->SrcAddr, data->DSN, data->timestamp)) {
tr_info("EAPOL relay filter drop");
return;
}
entry->receive(eapol_pdu_data->interface_ptr, data->SrcAddr, data->msdu_ptr, data->msduLength);
break;
}

View File

@ -99,6 +99,7 @@ typedef enum {
typedef struct {
eapol_pdu_recv_prior_t priority; /**< Priority: high, medium or low */
bool filter_requsted: 1; /**< True when EAPOL temporary filter requsted, false for normal functionality */
ws_eapol_pdu_address_check *addr_check; /**< Address check callback */
ws_eapol_pdu_receive *receive; /**< PDU receive callback */
} eapol_pdu_recv_cb_data_t;

View File

@ -53,6 +53,7 @@ static void ws_eapol_relay_socket_cb(void *cb);
static const eapol_pdu_recv_cb_data_t eapol_pdu_recv_cb_data = {
.priority = EAPOL_PDU_RECV_LOW_PRIORITY,
.filter_requsted = true,
.addr_check = ws_eapol_relay_eapol_pdu_address_check,
.receive = ws_eapol_relay_eapol_pdu_receive
};

View File

@ -25,6 +25,7 @@
#include "6LoWPAN/ws/ws_common.h"
#include "ws_management_api.h"
#include "ns_time_api.h"
#ifndef HAVE_WS
int ws_management_node_init(
@ -392,4 +393,9 @@ int ws_statistics_stop(int8_t interface_id)
return -1;
}
void ns_time_api_system_time_callback_set(ns_time_api_system_time_callback callback)
{
(void) callback;
}
#endif // no HAVE_WS

View File

@ -78,11 +78,18 @@ typedef struct llc_neighbour_req {
struct ws_neighbor_class_entry *ws_neighbor; /**< Wi-sun Neighbor information entry. */
} llc_neighbour_req_t;
typedef struct eapol_temporary_info_s {
uint8_t eapol_rx_relay_filter; /*!< seconds for dropping duplicate id */
uint8_t last_rx_mac_sequency; /*!< Only compared when Timer is active */
uint16_t eapol_timeout; /*!< EAPOL relay Temporary entry lifetime */
} eapol_temporary_info_t;
/**
* Neighbor temporary structure for storage FHSS data before create a real Neighbour info
*/
typedef struct ws_neighbor_temp_class_s {
struct ws_neighbor_class_entry neigh_info_list; /*!< Allocated hopping info array*/
eapol_temporary_info_t eapol_temp_info;
uint8_t mac64[8];
uint8_t mpduLinkQuality;
int8_t signal_dbm;
@ -217,6 +224,10 @@ void ws_llc_set_pan_information_pointer(struct protocol_interface_info_entry *in
*/
void ws_llc_hopping_schedule_config(struct protocol_interface_info_entry *interface, struct ws_hopping_schedule_s *hopping_schedule);
void ws_llc_timer_seconds(struct protocol_interface_info_entry *interface, uint16_t seconds_update);
bool ws_llc_eapol_relay_forward_filter(struct protocol_interface_info_entry *interface, const uint8_t *joiner_eui64, uint8_t mac_sequency, uint32_t rx_timestamp);
ws_neighbor_temp_class_t *ws_llc_get_multicast_temp_entry(struct protocol_interface_info_entry *interface, const uint8_t *mac64);
void ws_llc_free_multicast_temp_entry(struct protocol_interface_info_entry *interface, ws_neighbor_temp_class_t *neighbor);

File diff suppressed because it is too large Load Diff

View File

@ -41,9 +41,11 @@ int ws_management_node_init(
protocol_interface_info_entry_t *cur;
cur = protocol_stack_interface_info_get_by_id(interface_id);
if (interface_id >= 0 && (!cur || !ws_info(cur))) {
return -1;
}
if (!network_name_ptr || !fhss_timer_ptr) {
return -2;
}
@ -70,7 +72,9 @@ int ws_management_node_init(
return -4;
}
cur->ws_info->fhss_timer_ptr = fhss_timer_ptr;
if (cur && ws_info(cur)) {
cur->ws_info->fhss_timer_ptr = fhss_timer_ptr;
}
return 0;
}
@ -398,7 +402,7 @@ int ws_management_channel_plan_set(
protocol_interface_info_entry_t *cur;
cur = protocol_stack_interface_info_get_by_id(interface_id);
if (interface_id >= 0 && (!cur || !ws_info(cur))) {
if (!cur || !ws_info(cur)) {
return -1;
}
cur->ws_info->hopping_schdule.channel_plan = channel_plan;

View File

@ -322,5 +322,32 @@ void ws_neighbor_class_rsl_out_calculate(ws_neighbor_class_entry_t *ws_neighbor,
return;
}
bool ws_neighbor_class_neighbor_duplicate_packet_check(ws_neighbor_class_entry_t *ws_neighbor, uint8_t mac_dsn, uint32_t rx_timestamp)
{
if (ws_neighbor->last_DSN != mac_dsn) {
// New packet allways accepted
ws_neighbor->last_DSN = mac_dsn;
return true;
}
if (!ws_neighbor->unicast_data_rx) {
// No unicast info stored always accepted
return true;
}
rx_timestamp -= ws_neighbor->fhss_data.uc_timing_info.utt_rx_timestamp;
rx_timestamp /= 1000000; //Convert to s
//Compare only when last rx timestamp is less than 5 seconds
if (rx_timestamp < 5) {
//Packet is sent too fast filter it out
return false;
}
return true;
}
#endif /* HAVE_WS */

View File

@ -28,6 +28,7 @@ typedef struct ws_neighbor_class_entry {
uint16_t rsl_in; /*!< RSL EWMA heard from neighbour*/
uint16_t rsl_out; /*!< RSL EWMA heard by neighbour*/
uint16_t routing_cost; /*!< ETX to border Router. */
uint8_t last_DSN;
bool candidate_parent: 1;
bool broadcast_timing_info_stored: 1;
bool broadcast_shedule_info_stored: 1;
@ -181,4 +182,6 @@ void ws_neighbor_class_rsl_in_calculate(ws_neighbor_class_entry_t *ws_neighbor,
*/
void ws_neighbor_class_rsl_out_calculate(ws_neighbor_class_entry_t *ws_neighbor, uint8_t rsl_reported);
bool ws_neighbor_class_neighbor_duplicate_packet_check(ws_neighbor_class_entry_t *ws_neighbor, uint8_t mac_dsn, uint32_t rx_timestamp);
#endif /* WS_NEIGHBOR_CLASS_H_ */

View File

@ -28,6 +28,7 @@
#include "eventOS_scheduler.h"
#include "eventOS_event_timer.h"
#include "ns_address.h"
#include "Service_Libs/utils/ns_file.h"
#include "NWK_INTERFACE/Include/protocol.h"
#include "6LoWPAN/ws/ws_config.h"
#include "Security/protocols/sec_prot_cfg.h"
@ -46,6 +47,8 @@
#include "6LoWPAN/ws/ws_pae_timers.h"
#include "6LoWPAN/ws/ws_pae_auth.h"
#include "6LoWPAN/ws/ws_pae_lib.h"
#include "6LoWPAN/ws/ws_pae_time.h"
#include "6LoWPAN/ws/ws_pae_key_storage.h"
#ifdef HAVE_WS
#ifdef HAVE_PAE_AUTH
@ -56,16 +59,18 @@
#define PAE_TASKLET_EVENT 2
#define PAE_TASKLET_TIMER 3
// Wait for for supplicant to indicate activity (e.g. to send a message)
#define WAIT_FOR_AUTHENTICATION_TICKS 5 * 60 * 10 // 5 minutes
/* Wait for supplicant to indicate activity (e.g. to send a message) when
authentication is ongoing */
#define WAIT_FOR_AUTHENTICATION_TICKS 2 * 60 * 10 // 2 minutes
// Wait after authentication has completed before supplicant entry goes inactive
#define WAIT_AFTER_AUTHENTICATION_TICKS 15 * 10 // 15 seconds
/* If EAP-TLS is delayed due to simultaneous negotiations limit, defines how
long to wait for previous negotiation to complete */
#define EAP_TLS_NEGOTIATION_TRIGGER_TIMEOUT 60 * 10 // 60 seconds
// Default for maximum number of supplicants
#define SUPPLICANT_MAX_NUMBER 1000
#define SUPPLICANT_MAX_NUMBER 5000
/* Default for number of supplicants to purge per garbage collect call from
nanostack monitor */
@ -76,21 +81,23 @@
typedef struct {
ns_list_link_t link; /**< Link */
uint16_t pan_id; /**< PAN ID */
char network_name[33]; /**< Network name */
kmp_service_t *kmp_service; /**< KMP service */
protocol_interface_info_entry_t *interface_ptr; /**< Interface pointer */
ws_pae_auth_gtk_hash_set *hash_set; /**< GTK hash set callback */
ws_pae_auth_nw_key_insert *nw_key_insert; /**< Key insert callback */
ws_pae_auth_nw_keys_remove *nw_keys_remove; /**< Network keys remove callback */
ws_pae_auth_nw_key_index_set *nw_key_index_set; /**< Key index set callback */
ws_pae_auth_nw_info_updated *nw_info_updated; /**< Security keys network info updated callback */
supp_list_t active_supp_list; /**< List of active supplicants */
supp_list_t inactive_supp_list; /**< List of inactive supplicants */
arm_event_storage_t *timer; /**< Timer */
sec_prot_gtk_keys_t *gtks; /**< GTKs */
sec_prot_gtk_keys_t *next_gtks; /**< Next GTKs */
const sec_prot_certs_t *certs; /**< Certificates */
sec_prot_keys_nw_info_t *sec_keys_nw_info; /**< Security keys network information */
sec_timer_cfg_t *sec_timer_cfg; /**< Timer configuration */
sec_prot_cfg_t *sec_prot_cfg; /**< Protocol Configuration */
uint16_t supp_max_number; /**< Max number of stored supplicants */
uint16_t slow_timer_seconds; /**< Slow timer seconds */
bool timer_running : 1; /**< Timer is running */
bool gtk_new_inst_req_exp : 1; /**< GTK new install required timer expired */
bool gtk_new_act_time_exp: 1; /**< GTK new activation time expired */
@ -119,15 +126,15 @@ static void ws_pae_auth_kmp_api_create_indication(kmp_api_t *kmp, kmp_type_e typ
static void ws_pae_auth_kmp_api_finished_indication(kmp_api_t *kmp, kmp_result_e result, kmp_sec_keys_t *sec_keys);
static void ws_pae_auth_next_kmp_trigger(pae_auth_t *pae_auth, supp_entry_t *supp_entry);
static kmp_type_e ws_pae_auth_next_protocol_get(pae_auth_t *pae_auth, supp_entry_t *supp_entry);
static kmp_api_t *ws_pae_auth_kmp_create_and_start(kmp_service_t *service, kmp_type_e type, supp_entry_t *supp_entry, sec_prot_cfg_t *cfg);
static kmp_api_t *ws_pae_auth_kmp_create_and_start(kmp_service_t *service, kmp_type_e type, supp_entry_t *supp_entry, sec_prot_cfg_t *prot_cfg, sec_timer_cfg_t *timer_cfg);
static void ws_pae_auth_kmp_api_finished(kmp_api_t *kmp);
static int8_t tasklet_id = -1;
static NS_LIST_DEFINE(pae_auth_list, pae_auth_t, link);
int8_t ws_pae_auth_init(protocol_interface_info_entry_t *interface_ptr, sec_prot_gtk_keys_t *gtks, sec_prot_gtk_keys_t *next_gtks, const sec_prot_certs_t *certs, sec_timer_cfg_t *sec_timer_cfg, sec_prot_cfg_t *sec_prot_cfg)
int8_t ws_pae_auth_init(protocol_interface_info_entry_t *interface_ptr, sec_prot_gtk_keys_t *next_gtks, const sec_prot_certs_t *certs, sec_timer_cfg_t *sec_timer_cfg, sec_prot_cfg_t *sec_prot_cfg, sec_prot_keys_nw_info_t *sec_keys_nw_info)
{
if (!interface_ptr || !gtks || !certs) {
if (!interface_ptr || !next_gtks || !certs || !sec_timer_cfg || !sec_prot_cfg || !sec_keys_nw_info) {
return -1;
}
@ -140,23 +147,25 @@ int8_t ws_pae_auth_init(protocol_interface_info_entry_t *interface_ptr, sec_prot
return -1;
}
memset(&pae_auth->network_name, 0, 33);
pae_auth->pan_id = 0xffff;
pae_auth->interface_ptr = interface_ptr;
ws_pae_lib_supp_list_init(&pae_auth->active_supp_list);
ws_pae_lib_supp_list_init(&pae_auth->inactive_supp_list);
pae_auth->timer = NULL;
pae_auth->hash_set = NULL;
pae_auth->nw_key_insert = NULL;
pae_auth->nw_keys_remove = NULL;
pae_auth->nw_key_index_set = NULL;
pae_auth->gtks = gtks;
pae_auth->next_gtks = next_gtks;
pae_auth->certs = certs;
pae_auth->sec_keys_nw_info = sec_keys_nw_info;
pae_auth->sec_timer_cfg = sec_timer_cfg;
pae_auth->sec_prot_cfg = sec_prot_cfg;
pae_auth->supp_max_number = SUPPLICANT_MAX_NUMBER;
pae_auth->slow_timer_seconds = 0;
pae_auth->gtk_new_inst_req_exp = false;
pae_auth->gtk_new_act_time_exp = false;
@ -254,7 +263,7 @@ int8_t ws_pae_auth_delete(protocol_interface_info_entry_t *interface_ptr)
return 0;
}
void ws_pae_auth_cb_register(protocol_interface_info_entry_t *interface_ptr, ws_pae_auth_gtk_hash_set *hash_set, ws_pae_auth_nw_key_insert *nw_key_insert, ws_pae_auth_nw_key_index_set *nw_key_index_set)
void ws_pae_auth_cb_register(protocol_interface_info_entry_t *interface_ptr, ws_pae_auth_gtk_hash_set *hash_set, ws_pae_auth_nw_key_insert *nw_key_insert, ws_pae_auth_nw_key_index_set *nw_key_index_set, ws_pae_auth_nw_info_updated *nw_info_updated)
{
if (!interface_ptr) {
return;
@ -268,6 +277,7 @@ void ws_pae_auth_cb_register(protocol_interface_info_entry_t *interface_ptr, ws_
pae_auth->hash_set = hash_set;
pae_auth->nw_key_insert = nw_key_insert;
pae_auth->nw_key_index_set = nw_key_index_set;
pae_auth->nw_info_updated = nw_info_updated;
}
void ws_pae_auth_start(protocol_interface_info_entry_t *interface_ptr)
@ -282,15 +292,17 @@ void ws_pae_auth_start(protocol_interface_info_entry_t *interface_ptr)
}
// Checks if there is predefined active key
int8_t index = sec_prot_keys_gtk_status_active_get(pae_auth->gtks);
int8_t index = sec_prot_keys_gtk_status_active_get(pae_auth->sec_keys_nw_info->gtks);
if (index < 0) {
// If there is no key, inserts a new one
ws_pae_auth_gtk_key_insert(pae_auth);
index = sec_prot_keys_gtk_install_order_first_index_get(pae_auth->gtks);
index = sec_prot_keys_gtk_install_order_first_index_get(pae_auth->sec_keys_nw_info->gtks);
ws_pae_auth_active_gtk_set(pae_auth, index);
} else {
ws_pae_auth_active_gtk_set(pae_auth, index);
}
// Update keys to NVM as needed
pae_auth->nw_info_updated(pae_auth->interface_ptr);
// Inserts keys and updates GTK hash on stack
ws_pae_auth_network_keys_from_gtks_set(pae_auth);
@ -331,13 +343,15 @@ int8_t ws_pae_auth_nw_key_index_update(protocol_interface_info_entry_t *interfac
int8_t ws_pae_auth_node_keys_remove(protocol_interface_info_entry_t *interface_ptr, uint8_t *eui_64)
{
int8_t ret_value = -1;
if (!interface_ptr) {
return -1;
return ret_value;
}
pae_auth_t *pae_auth = ws_pae_auth_get(interface_ptr);
if (!pae_auth) {
return -1;
return ret_value;
}
// Checks if supplicant is active
@ -348,20 +362,16 @@ int8_t ws_pae_auth_node_keys_remove(protocol_interface_info_entry_t *interface_p
sec_prot_keys_pmk_delete(&supp->sec_keys);
sec_prot_keys_ptk_delete(&supp->sec_keys);
supp->access_revoked = true;
tr_info("Access revoked; keys removed, eui-64: %s", trace_array(supp->addr.eui_64, 8));
return 0;
tr_info("Access revoked; keys removed, eui-64: %s", trace_array(eui_64, 8));
ret_value = 0;
}
// Checks if supplicant is inactive
supp = ws_pae_lib_supp_list_entry_eui_64_get(&pae_auth->inactive_supp_list, eui_64);
if (supp) {
// Deletes supplicant
tr_info("Access revoked; deleted, eui-64: %s", trace_array(supp->addr.eui_64, 8));
ws_pae_lib_supp_list_remove(&pae_auth->inactive_supp_list, supp);
return 0;
if (ws_pae_key_storage_supp_delete(pae_auth, eui_64)) {
tr_info("Access revoked; key store deleted, eui-64: %s", trace_array(eui_64, 8));
ret_value = 0;
}
return -1;
return ret_value;
}
int8_t ws_pae_auth_node_access_revoke_start(protocol_interface_info_entry_t *interface_ptr)
@ -376,7 +386,7 @@ int8_t ws_pae_auth_node_access_revoke_start(protocol_interface_info_entry_t *int
}
// Gets active GTK
int8_t active_index = sec_prot_keys_gtk_status_active_get(pae_auth->gtks);
int8_t active_index = sec_prot_keys_gtk_status_active_get(pae_auth->sec_keys_nw_info->gtks);
if (active_index >= 0) {
// As default removes other keys than active
@ -384,22 +394,24 @@ int8_t ws_pae_auth_node_access_revoke_start(protocol_interface_info_entry_t *int
uint32_t revocation_lifetime = ws_pae_timers_gtk_revocation_lifetime_get(pae_auth->sec_timer_cfg);
uint32_t active_lifetime = sec_prot_keys_gtk_lifetime_get(pae_auth->gtks, active_index);
uint32_t active_lifetime = sec_prot_keys_gtk_lifetime_get(pae_auth->sec_keys_nw_info->gtks, active_index);
uint64_t current_time = ws_pae_current_time_get();
// If active GTK lifetime is larger than revocation lifetime decrements active GTK lifetime
if (active_lifetime > revocation_lifetime) {
sec_prot_keys_gtk_lifetime_decrement(pae_auth->gtks, active_index, active_lifetime - revocation_lifetime);
sec_prot_keys_gtk_lifetime_decrement(pae_auth->sec_keys_nw_info->gtks, active_index, current_time, active_lifetime - revocation_lifetime);
tr_info("Access revocation start, GTK active index: %i, revoked lifetime: %"PRIu32"", active_index, revocation_lifetime);
} else {
// Otherwise decrements lifetime of the GTK to be installed after the active one
int8_t second_index = sec_prot_keys_gtk_install_order_second_index_get(pae_auth->gtks);
int8_t second_index = sec_prot_keys_gtk_install_order_second_index_get(pae_auth->sec_keys_nw_info->gtks);
if (second_index >= 0) {
// Second GTK revocation lifetime is the active GTK lifetime added with revocation time
uint32_t second_revocation_lifetime = active_lifetime + revocation_lifetime;
uint32_t second_lifetime = sec_prot_keys_gtk_lifetime_get(pae_auth->gtks, second_index);
uint32_t second_lifetime = sec_prot_keys_gtk_lifetime_get(pae_auth->sec_keys_nw_info->gtks, second_index);
if (second_lifetime > second_revocation_lifetime) {
sec_prot_keys_gtk_lifetime_decrement(pae_auth->gtks, second_index, second_lifetime - second_revocation_lifetime);
sec_prot_keys_gtk_lifetime_decrement(pae_auth->sec_keys_nw_info->gtks, second_index, current_time, second_lifetime - second_revocation_lifetime);
tr_info("Access revocation start, GTK second active index: %i, revoked lifetime: %"PRIu32"", second_index, second_revocation_lifetime);
}
// Removes other keys than active and GTK to be installed next
@ -408,11 +420,11 @@ int8_t ws_pae_auth_node_access_revoke_start(protocol_interface_info_entry_t *int
}
// Deletes other GTKs
int8_t last_index = sec_prot_keys_gtk_install_order_last_index_get(pae_auth->gtks);
int8_t last_index = sec_prot_keys_gtk_install_order_last_index_get(pae_auth->sec_keys_nw_info->gtks);
while (last_index >= 0 && last_index != not_removed_index) {
tr_info("Access revocation GTK clear index: %i", last_index);
sec_prot_keys_gtk_clear(pae_auth->gtks, last_index);
last_index = sec_prot_keys_gtk_install_order_last_index_get(pae_auth->gtks);
sec_prot_keys_gtk_clear(pae_auth->sec_keys_nw_info->gtks, last_index);
last_index = sec_prot_keys_gtk_install_order_last_index_get(pae_auth->sec_keys_nw_info->gtks);
}
}
@ -420,6 +432,9 @@ int8_t ws_pae_auth_node_access_revoke_start(protocol_interface_info_entry_t *int
ws_pae_auth_gtk_key_insert(pae_auth);
ws_pae_auth_network_keys_from_gtks_set(pae_auth);
// Update keys to NVM as needed
pae_auth->nw_info_updated(pae_auth->interface_ptr);
return 0;
}
@ -452,22 +467,69 @@ void ws_pae_auth_forced_gc(protocol_interface_info_entry_t *interface_ptr)
/* Purge in maximum five entries from supplicant list (starting from oldest one)
per call to the function (called by nanostack monitor) */
ws_pae_lib_supp_list_purge(&pae_auth->active_supp_list, &pae_auth->inactive_supp_list, 0, SUPPLICANT_NUMBER_TO_PURGE);
ws_pae_lib_supp_list_purge(&pae_auth->active_supp_list, 0, SUPPLICANT_NUMBER_TO_PURGE);
}
int8_t ws_pae_auth_nw_info_set(protocol_interface_info_entry_t *interface_ptr, uint16_t pan_id, char *network_name)
{
if (!interface_ptr || !network_name) {
return -1;
}
pae_auth_t *pae_auth = ws_pae_auth_get(interface_ptr);
if (!pae_auth) {
return -1;
}
// On authenticator pan_id is always selected locally and is always valid for keys
if (pae_auth->sec_keys_nw_info->key_pan_id != pan_id) {
pae_auth->sec_keys_nw_info->key_pan_id = pan_id;
pae_auth->sec_keys_nw_info->updated = true;
}
bool update_keys = false;
if (pae_auth->pan_id != 0xffff && pae_auth->pan_id != pan_id) {
update_keys = true;
}
pae_auth->pan_id = pan_id;
if (strlen((char *) &pae_auth->network_name) > 0 && strcmp((char *) &pae_auth->network_name, network_name) != 0) {
update_keys = true;
}
strcpy((char *) &pae_auth->network_name, network_name);
if (!update_keys) {
return 0;
}
if (pae_auth->nw_keys_remove) {
pae_auth->nw_keys_remove(pae_auth->interface_ptr);
}
ws_pae_auth_network_keys_from_gtks_set(pae_auth);
int8_t index = sec_prot_keys_gtk_status_active_get(pae_auth->sec_keys_nw_info->gtks);
if (index >= 0) {
// Sets active key index
ws_pae_auth_network_key_index_set(pae_auth, index);
}
return 0;
}
static int8_t ws_pae_auth_network_keys_from_gtks_set(pae_auth_t *pae_auth)
{
// Authenticator keys are always fresh
sec_prot_keys_gtk_status_all_fresh_set(pae_auth->gtks);
sec_prot_keys_gtk_status_all_fresh_set(pae_auth->sec_keys_nw_info->gtks);
if (pae_auth->hash_set) {
uint8_t gtk_hash[32];
sec_prot_keys_gtks_hash_generate(pae_auth->gtks, gtk_hash);
sec_prot_keys_gtks_hash_generate(pae_auth->sec_keys_nw_info->gtks, gtk_hash);
pae_auth->hash_set(pae_auth->interface_ptr, gtk_hash);
}
if (pae_auth->nw_key_insert) {
pae_auth->nw_key_insert(pae_auth->interface_ptr, pae_auth->gtks);
pae_auth->nw_key_insert(pae_auth->interface_ptr, pae_auth->sec_keys_nw_info->gtks);
}
return 0;
@ -475,12 +537,12 @@ static int8_t ws_pae_auth_network_keys_from_gtks_set(pae_auth_t *pae_auth)
static int8_t ws_pae_auth_active_gtk_set(pae_auth_t *pae_auth, uint8_t index)
{
return sec_prot_keys_gtk_status_active_set(pae_auth->gtks, index);
return sec_prot_keys_gtk_status_active_set(pae_auth->sec_keys_nw_info->gtks, index);
}
static int8_t ws_pae_auth_gtk_clear(pae_auth_t *pae_auth, uint8_t index)
{
return sec_prot_keys_gtk_clear(pae_auth->gtks, index);
return sec_prot_keys_gtk_clear(pae_auth->sec_keys_nw_info->gtks, index);
}
static int8_t ws_pae_auth_network_key_index_set(pae_auth_t *pae_auth, uint8_t index)
@ -499,7 +561,6 @@ static void ws_pae_auth_free(pae_auth_t *pae_auth)
}
ws_pae_lib_supp_list_delete(&pae_auth->active_supp_list);
ws_pae_lib_supp_list_delete(&pae_auth->inactive_supp_list);
kmp_socket_if_unregister(pae_auth->kmp_service);
@ -582,7 +643,7 @@ void ws_pae_auth_fast_timer(uint16_t ticks)
}
// Updates KMP timers
bool running = ws_pae_lib_supp_list_timer_update(&pae_auth->active_supp_list, &pae_auth->inactive_supp_list, ticks, kmp_service_timer_if_timeout);
bool running = ws_pae_lib_supp_list_timer_update(pae_auth, &pae_auth->active_supp_list, ticks, kmp_service_timer_if_timeout);
if (!running) {
ws_pae_auth_timer_stop(pae_auth);
}
@ -594,22 +655,26 @@ void ws_pae_auth_slow_timer(uint16_t seconds)
ns_list_foreach(pae_auth_t, pae_auth, &pae_auth_list) {
// Gets index of currently active GTK
int8_t active_index = sec_prot_keys_gtk_status_active_get(pae_auth->gtks);
int8_t active_index = sec_prot_keys_gtk_status_active_get(pae_auth->sec_keys_nw_info->gtks);
uint64_t current_time = ws_pae_current_time_get();
for (uint8_t i = 0; i < GTK_NUM; i++) {
if (!sec_prot_keys_gtk_is_set(pae_auth->gtks, i)) {
if (!sec_prot_keys_gtk_is_set(pae_auth->sec_keys_nw_info->gtks, i)) {
continue;
}
uint32_t timer_seconds = sec_prot_keys_gtk_lifetime_decrement(pae_auth->gtks, i, seconds);
uint32_t timer_seconds = sec_prot_keys_gtk_lifetime_decrement(pae_auth->sec_keys_nw_info->gtks, i, current_time, seconds);
if (active_index == i) {
if (!pae_auth->gtk_new_inst_req_exp) {
pae_auth->gtk_new_inst_req_exp = ws_pae_timers_gtk_new_install_required(pae_auth->sec_timer_cfg, timer_seconds);
if (pae_auth->gtk_new_inst_req_exp) {
int8_t second_index = sec_prot_keys_gtk_install_order_second_index_get(pae_auth->gtks);
int8_t second_index = sec_prot_keys_gtk_install_order_second_index_get(pae_auth->sec_keys_nw_info->gtks);
if (second_index < 0) {
tr_info("GTK new install required active index: %i, time: %"PRIu32", system time: %"PRIu32"", active_index, timer_seconds, protocol_core_monotonic_time / 10);
ws_pae_auth_gtk_key_insert(pae_auth);
ws_pae_auth_network_keys_from_gtks_set(pae_auth);
// Update keys to NVM as needed
pae_auth->nw_info_updated(pae_auth->interface_ptr);
} else {
tr_info("GTK new install already done; second index: %i, time: %"PRIu32", system time: %"PRIu32"", second_index, timer_seconds, protocol_core_monotonic_time / 10);
}
@ -626,6 +691,8 @@ void ws_pae_auth_slow_timer(uint16_t seconds)
}
pae_auth->gtk_new_inst_req_exp = false;
pae_auth->gtk_new_act_time_exp = false;
// Update keys to NVM as needed
pae_auth->nw_info_updated(pae_auth->interface_ptr);
}
}
}
@ -634,22 +701,22 @@ void ws_pae_auth_slow_timer(uint16_t seconds)
tr_info("GTK expired index: %i, system time: %"PRIu32"", i, protocol_core_monotonic_time / 10);
ws_pae_auth_gtk_clear(pae_auth, i);
ws_pae_auth_network_keys_from_gtks_set(pae_auth);
// Update keys to NVM as needed
pae_auth->nw_info_updated(pae_auth->interface_ptr);
}
}
pae_auth->slow_timer_seconds += seconds;
if (pae_auth->slow_timer_seconds > 60) {
ws_pae_lib_supp_list_slow_timer_update(&pae_auth->active_supp_list, pae_auth->sec_timer_cfg, pae_auth->slow_timer_seconds);
ws_pae_lib_supp_list_slow_timer_update(&pae_auth->inactive_supp_list, pae_auth->sec_timer_cfg, pae_auth->slow_timer_seconds);
pae_auth->slow_timer_seconds = 0;
}
ws_pae_lib_supp_list_slow_timer_update(&pae_auth->active_supp_list, seconds);
}
// Update key storage timer
ws_pae_key_storage_timer(seconds);
}
static void ws_pae_auth_gtk_key_insert(pae_auth_t *pae_auth)
{
// Gets index to install the key
uint8_t install_index = sec_prot_keys_gtk_install_index_get(pae_auth->gtks);
uint8_t install_index = sec_prot_keys_gtk_install_index_get(pae_auth->sec_keys_nw_info->gtks);
// Key to install
uint8_t gtk_value[GTK_LEN];
@ -671,24 +738,24 @@ static void ws_pae_auth_gtk_key_insert(pae_auth_t *pae_auth)
// Gets latest installed key lifetime and adds GTK expire offset to it
uint32_t lifetime = pae_auth->sec_timer_cfg->gtk_expire_offset;
int8_t last_index = sec_prot_keys_gtk_install_order_last_index_get(pae_auth->gtks);
int8_t last_index = sec_prot_keys_gtk_install_order_last_index_get(pae_auth->sec_keys_nw_info->gtks);
if (last_index >= 0) {
lifetime += sec_prot_keys_gtk_lifetime_get(pae_auth->gtks, last_index);
lifetime += sec_prot_keys_gtk_lifetime_get(pae_auth->sec_keys_nw_info->gtks, last_index);
}
// Installs the new key
sec_prot_keys_gtk_clear(pae_auth->gtks, install_index);
sec_prot_keys_gtk_set(pae_auth->gtks, install_index, gtk_value, lifetime);
sec_prot_keys_gtk_clear(pae_auth->sec_keys_nw_info->gtks, install_index);
sec_prot_keys_gtk_set(pae_auth->sec_keys_nw_info->gtks, install_index, gtk_value, lifetime);
// Authenticator keys are always fresh
sec_prot_keys_gtk_status_all_fresh_set(pae_auth->gtks);
sec_prot_keys_gtk_status_all_fresh_set(pae_auth->sec_keys_nw_info->gtks);
tr_info("GTK install new index: %i, lifetime: %"PRIu32" system time: %"PRIu32"", install_index, lifetime, protocol_core_monotonic_time / 10);
}
static int8_t ws_pae_auth_new_gtk_activate(pae_auth_t *pae_auth)
{
int8_t new_active_index = sec_prot_keys_gtk_install_order_second_index_get(pae_auth->gtks);
int8_t new_active_index = sec_prot_keys_gtk_install_order_second_index_get(pae_auth->sec_keys_nw_info->gtks);
if (new_active_index >= 0) {
ws_pae_auth_active_gtk_set(pae_auth, new_active_index);
}
@ -717,8 +784,6 @@ static int8_t ws_pae_auth_timer_if_start(kmp_service_t *service, kmp_api_t *kmp)
return -1;
}
ws_pae_lib_supp_list_to_active(&pae_auth->active_supp_list, &pae_auth->inactive_supp_list, supp_entry);
ws_pae_lib_kmp_timer_start(&supp_entry->kmp_list, entry);
return 0;
}
@ -798,26 +863,27 @@ static kmp_api_t *ws_pae_auth_kmp_incoming_ind(kmp_service_t *service, kmp_type_
supp_entry_t *supp_entry = ws_pae_lib_supp_list_entry_eui_64_get(&pae_auth->active_supp_list, kmp_address_eui_64_get(addr));
if (!supp_entry) {
// Find supplicant from list of inactive supplicants
supp_entry = ws_pae_lib_supp_list_entry_eui_64_get(&pae_auth->inactive_supp_list, kmp_address_eui_64_get(addr));
// Checks if active supplicant list has space for new supplicants
if (ws_pae_lib_supp_list_active_limit_reached(&pae_auth->active_supp_list, pae_auth->sec_prot_cfg->sec_max_ongoing_authentication)) {
tr_debug("PAE: active limit reached, eui-64: %s", trace_array(kmp_address_eui_64_get(addr), 8));
return NULL;
}
// Find supplicant from key storage
supp_entry = ws_pae_key_storage_supp_read(pae_auth, kmp_address_eui_64_get(addr), pae_auth->sec_keys_nw_info->gtks, pae_auth->certs);
if (supp_entry) {
// Move supplicant to active list
ws_pae_lib_supp_list_to_active(&pae_auth->active_supp_list, &pae_auth->inactive_supp_list, supp_entry);
tr_debug("PAE: to active, eui-64: %s", trace_array(supp_entry->addr.eui_64, 8));
ns_list_add_to_start(&pae_auth->active_supp_list, supp_entry);
}
}
// If does not exists add it to list
if (!supp_entry) {
// Checks if maximum number of supplicants is reached and purge supplicant list (starting from oldest one)
ws_pae_lib_supp_list_purge(&pae_auth->active_supp_list, &pae_auth->inactive_supp_list, pae_auth->supp_max_number, 0);
supp_entry = ws_pae_lib_supp_list_add(&pae_auth->active_supp_list, addr);
if (!supp_entry) {
return 0;
}
sec_prot_keys_init(&supp_entry->sec_keys, pae_auth->gtks, pae_auth->certs);
// Fixes the address of the supplicant to keys
sec_prot_keys_ptk_eui_64_write(&supp_entry->sec_keys, kmp_address_eui_64_get(addr));
sec_prot_keys_init(&supp_entry->sec_keys, pae_auth->sec_keys_nw_info->gtks, pae_auth->certs);
} else {
// Updates relay address
kmp_address_copy(&supp_entry->addr, addr);
@ -833,7 +899,7 @@ static kmp_api_t *ws_pae_auth_kmp_incoming_ind(kmp_service_t *service, kmp_type_
}
// Create a new KMP for initial eapol-key
kmp = kmp_api_create(service, type + IEEE_802_1X_INITIAL_KEY, pae_auth->sec_prot_cfg);
kmp = kmp_api_create(service, type + IEEE_802_1X_INITIAL_KEY, pae_auth->sec_prot_cfg, pae_auth->sec_timer_cfg);
if (!kmp) {
return 0;
@ -913,10 +979,11 @@ static void ws_pae_auth_next_kmp_trigger(pae_auth_t *pae_auth, supp_entry_t *sup
kmp_type_e next_type = ws_pae_auth_next_protocol_get(pae_auth, supp_entry);
if (next_type == KMP_TYPE_NONE) {
// Supplicant goes inactive after 15 seconds
ws_pae_lib_supp_timer_ticks_set(supp_entry, WAIT_AFTER_AUTHENTICATION_TICKS);
// All done
return;
} else {
kmp_api_t *api = ws_pae_lib_kmp_list_type_get(&supp_entry->kmp_list, next_type);
if (api != NULL) {
/* For other types than GTK, only one ongoing negotiation at the same time,
@ -947,7 +1014,7 @@ static void ws_pae_auth_next_kmp_trigger(pae_auth_t *pae_auth, supp_entry_t *sup
}
// Create new instance
kmp_api_t *new_kmp = ws_pae_auth_kmp_create_and_start(pae_auth->kmp_service, next_type, supp_entry, pae_auth->sec_prot_cfg);
kmp_api_t *new_kmp = ws_pae_auth_kmp_create_and_start(pae_auth->kmp_service, next_type, supp_entry, pae_auth->sec_prot_cfg, pae_auth->sec_timer_cfg);
if (!new_kmp) {
return;
}
@ -960,7 +1027,7 @@ static void ws_pae_auth_next_kmp_trigger(pae_auth_t *pae_auth, supp_entry_t *sup
return;
}
// Create TLS instance */
if (ws_pae_auth_kmp_create_and_start(pae_auth->kmp_service, TLS_PROT, supp_entry, pae_auth->sec_prot_cfg) == NULL) {
if (ws_pae_auth_kmp_create_and_start(pae_auth->kmp_service, TLS_PROT, supp_entry, pae_auth->sec_prot_cfg, pae_auth->sec_timer_cfg) == NULL) {
ws_pae_lib_kmp_list_delete(&supp_entry->kmp_list, new_kmp);
return;
}
@ -1027,11 +1094,10 @@ static kmp_type_e ws_pae_auth_next_protocol_get(pae_auth_t *pae_auth, supp_entry
return next_type;
}
static kmp_api_t *ws_pae_auth_kmp_create_and_start(kmp_service_t *service, kmp_type_e type, supp_entry_t *supp_entry, sec_prot_cfg_t *cfg)
static kmp_api_t *ws_pae_auth_kmp_create_and_start(kmp_service_t *service, kmp_type_e type, supp_entry_t *supp_entry, sec_prot_cfg_t *prot_cfg, sec_timer_cfg_t *timer_cfg)
{
// Create KMP instance for new authentication
kmp_api_t *kmp = kmp_api_create(service, type, cfg);
kmp_api_t *kmp = kmp_api_create(service, type, prot_cfg, timer_cfg);
if (!kmp) {
return NULL;
@ -1084,7 +1150,6 @@ static void ws_pae_auth_kmp_api_finished(kmp_api_t *kmp)
tr_info("PAE next KMP trigger, eui-64: %s", trace_array(retry_supp->addr.eui_64, 8));
ws_pae_auth_next_kmp_trigger(pae_auth, retry_supp);
}
}
#endif /* HAVE_PAE_AUTH */

View File

@ -43,18 +43,18 @@
* \param local_port local port
* \param remote_addr remote address
* \param remote_port remote port
* \param gtks group keys
* \param next_gtks next group keys to be used
* \param cert_chain certificate chain
* \param timer_settings timer settings
* \param sec_timer_cfg timer configuration
* \param sec_prot_cfg protocol configuration
* \param sec_keys_nw_info security keys network information
*
* \return < 0 failure
* \return >= 0 success
*
*/
int8_t ws_pae_auth_init(protocol_interface_info_entry_t *interface_ptr, sec_prot_gtk_keys_t *gtks, sec_prot_gtk_keys_t *next_gtks, const sec_prot_certs_t *certs, sec_timer_cfg_t *sec_timer_cfg, sec_prot_cfg_t *sec_prot_cfg);
int8_t ws_pae_auth_init(protocol_interface_info_entry_t *interface_ptr, sec_prot_gtk_keys_t *next_gtks, const sec_prot_certs_t *certs, sec_timer_cfg_t *sec_timer_cfg, sec_prot_cfg_t *sec_prot_cfg, sec_prot_keys_nw_info_t *sec_keys_nw_info);
/**
* ws_pae_auth_addresses_set set relay addresses
@ -168,6 +168,19 @@ int8_t ws_pae_auth_node_limit_set(protocol_interface_info_entry_t *interface_ptr
*/
void ws_pae_auth_forced_gc(protocol_interface_info_entry_t *interface_ptr);
/**
* ws_pae_auth_nw_info_set set network information
*
* \param interface_ptr interface
* \param pan_id PAD ID
* \param network_name network name
*
* \return < 0 failure
* \return >= 0 success
*
*/
int8_t ws_pae_auth_nw_info_set(protocol_interface_info_entry_t *interface_ptr, uint16_t pan_id, char *network_name);
/**
* ws_pae_auth_gtk_hash_set GTK hash set callback
*
@ -189,6 +202,14 @@ typedef void ws_pae_auth_gtk_hash_set(protocol_interface_info_entry_t *interface
*/
typedef int8_t ws_pae_auth_nw_key_insert(protocol_interface_info_entry_t *interface_ptr, sec_prot_gtk_keys_t *gtks);
/**
* ws_pae_auth_nw_keys_remove remove network keys callback
*
* \param interface_ptr interface
*
*/
typedef void ws_pae_auth_nw_keys_remove(protocol_interface_info_entry_t *interface_ptr);
/**
* ws_pae_auth_nw_key_index_set network send key index set callback
*
@ -198,6 +219,14 @@ typedef int8_t ws_pae_auth_nw_key_insert(protocol_interface_info_entry_t *interf
*/
typedef void ws_pae_auth_nw_key_index_set(protocol_interface_info_entry_t *interface_ptr, uint8_t index);
/**
* ws_pae_auth_nw_info_updated security keys network information updated
*
* \param interface_ptr interface
*
*/
typedef void ws_pae_auth_nw_info_updated(protocol_interface_info_entry_t *interface_ptr);
/**
* ws_pae_auth_cb_register register PAE authenticator callbacks
*
@ -205,9 +234,10 @@ typedef void ws_pae_auth_nw_key_index_set(protocol_interface_info_entry_t *inter
* \param hash_set GTK hash set callback
* \param nw_key_insert network key index callback
* \param nw_key_index_set network send key index callback
* \param nw_info_updated network keys updated callback
*
*/
void ws_pae_auth_cb_register(protocol_interface_info_entry_t *interface_ptr, ws_pae_auth_gtk_hash_set *hash_set, ws_pae_auth_nw_key_insert *nw_key_insert, ws_pae_auth_nw_key_index_set *nw_key_index_set);
void ws_pae_auth_cb_register(protocol_interface_info_entry_t *interface_ptr, ws_pae_auth_gtk_hash_set *hash_set, ws_pae_auth_nw_key_insert *nw_key_insert, ws_pae_auth_nw_key_index_set *nw_key_index_set, ws_pae_auth_nw_info_updated *nw_info_updated);
#else
@ -215,10 +245,11 @@ void ws_pae_auth_cb_register(protocol_interface_info_entry_t *interface_ptr, ws_
#define ws_pae_auth_timing_adjust(timing)
#define ws_pae_auth_addresses_set(interface_ptr, local_port, remote_addr, remote_port) 1
#define ws_pae_auth_delete NULL
#define ws_pae_auth_cb_register(interface_ptr, hash_set, nw_key_insert, nw_key_index_set) {(void) hash_set;}
#define ws_pae_auth_cb_register(interface_ptr, hash_set, nw_key_insert, nw_key_index_set, nw_info_updated) {(void) hash_set;}
#define ws_pae_auth_start(interface_ptr)
#define ws_pae_auth_gtks_updated NULL
#define ws_pae_auth_nw_key_index_update NULL
#define ws_pae_auth_nw_info_set NULL
#define ws_pae_auth_node_keys_remove(interface_ptr, eui64) -1
#define ws_pae_auth_node_access_revoke_start(interface_ptr)
#define ws_pae_auth_node_limit_set(interface_ptr, limit)

View File

@ -24,6 +24,7 @@
#include "fhss_config.h"
#include "ns_address.h"
#include "ws_management_api.h"
#include "Service_Libs/utils/ns_file.h"
#include "NWK_INTERFACE/Include/protocol.h"
#include "6LoWPAN/ws/ws_config.h"
#include "6LoWPAN/ws/ws_cfg_settings.h"
@ -36,6 +37,8 @@
#include "6LoWPAN/ws/ws_pae_auth.h"
#include "6LoWPAN/ws/ws_pae_nvm_store.h"
#include "6LoWPAN/ws/ws_pae_nvm_data.h"
#include "6LoWPAN/ws/ws_pae_time.h"
#include "6LoWPAN/ws/ws_pae_key_storage.h"
#include "mbedtls/sha256.h"
#ifdef HAVE_WS
@ -49,6 +52,7 @@ typedef int8_t ws_pae_br_addr_read(protocol_interface_info_entry_t *interface_pt
typedef void ws_pae_gtks_updated(protocol_interface_info_entry_t *interface_ptr);
typedef int8_t ws_pae_gtk_hash_update(protocol_interface_info_entry_t *interface_ptr, uint8_t *gtkhash);
typedef int8_t ws_pae_nw_key_index_update(protocol_interface_info_entry_t *interface_ptr, uint8_t index);
typedef int8_t ws_pae_nw_info_set(protocol_interface_info_entry_t *interface_ptr, uint16_t pan_id, char *network_name);
typedef struct {
uint8_t gtk[GTK_LEN]; /**< GTK key */
@ -63,15 +67,17 @@ typedef struct {
uint8_t br_eui_64[8]; /**< Border router EUI-64 */
sec_prot_gtk_keys_t gtks; /**< GTKs */
sec_prot_gtk_keys_t next_gtks; /**< Next GTKs */
sec_prot_keys_nw_info_t sec_keys_nw_info; /**< Security keys network information */
int8_t gtk_index; /**< GTK index */
uint8_t gtkhash[32]; /**< GTK hashes */
sec_prot_certs_t certs; /**< Certificates */
nw_key_t nw_key[GTK_NUM]; /**< Currently active network keys (on MAC) */
char *network_name; /**< Network name for GAK generation */
uint16_t frame_cnt_store_timer; /**< Timer for storing frame counter value */
uint16_t frame_cnt_store_timer; /**< Timer to check if storing of frame counter value is needed */
uint32_t frame_cnt_store_force_timer; /**< Timer to force storing of frame counter, if no other updates */
frame_counters_t frame_counters; /**< Frame counters */
sec_timer_cfg_t sec_timer_cfg; /**< Timer configuration (configuration set values) */
sec_prot_cfg_t sec_prot_cfg; /**< Configuration */
uint32_t restart_cnt; /**< Re-start counter */
protocol_interface_info_entry_t *interface_ptr; /**< List link entry */
ws_pae_controller_auth_completed *auth_completed; /**< Authentication completed callback, continue bootstrap */
ws_pae_controller_nw_key_set *nw_key_set; /**< Key set callback */
@ -80,6 +86,8 @@ typedef struct {
ws_pae_controller_nw_frame_counter_set *nw_frame_counter_set; /**< Frame counter set callback */
ws_pae_controller_nw_frame_counter_read *nw_frame_counter_read; /**< Frame counter read callback */
ws_pae_controller_pan_ver_increment *pan_ver_increment; /**< PAN version increment callback */
ws_pae_controller_nw_info_updated *nw_info_updated; /**< Network information updated callback */
ws_pae_controller_auth_next_target *auth_next_target; /**< Authentication next target callback */
ws_pae_delete *pae_delete; /**< PAE delete callback */
ws_pae_timer *pae_fast_timer; /**< PAE fast timer callback */
ws_pae_timer *pae_slow_timer; /**< PAE slow timer callback */
@ -88,7 +96,8 @@ typedef struct {
ws_pae_gtks_updated *pae_gtks_updated; /**< PAE GTKs updated */
ws_pae_gtk_hash_update *pae_gtk_hash_update; /**< PAE GTK HASH update */
ws_pae_nw_key_index_update *pae_nw_key_index_update; /**< PAE NW key index update */
nvm_tlv_entry_t *pae_nvm_buffer; /**< Buffer For PAE NVM write operation*/
ws_pae_nw_info_set *pae_nw_info_set; /**< PAE security key network info set */
uint8_t pae_nvm_buffer[PAE_NVM_DEFAULT_BUFFER_SIZE]; /**< Buffer for PAE NVM read and write operations */
bool gtks_set : 1; /**< GTKs are set */
bool gtkhash_set : 1; /**< GTK hashes are set */
bool key_index_set : 1; /**< NW key index is set */
@ -101,12 +110,14 @@ typedef struct {
bool ext_cert_valid_enabled : 1; /**< Extended certificate validation enabled */
} pae_controller_config_t;
static void ws_pae_controller_keys_nw_info_init(sec_prot_keys_nw_info_t *sec_keys_nw_info, sec_prot_gtk_keys_t *gtks);
static void ws_pae_controller_nw_info_updated_check(protocol_interface_info_entry_t *interface_ptr);
static pae_controller_t *ws_pae_controller_get(protocol_interface_info_entry_t *interface_ptr);
static void ws_pae_controller_frame_counter_timer(uint16_t seconds, pae_controller_t *entry);
static void ws_pae_controller_frame_counter_timer_trigger(uint16_t seconds, pae_controller_t *entry);
static void ws_pae_controller_frame_counter_store(pae_controller_t *entry, bool use_threshold);
static void ws_pae_controller_nvm_frame_counter_write(nvm_tlv_entry_t *tlv_entry);
static int8_t ws_pae_controller_nvm_frame_counter_read(frame_counters_t *counters);
static void ws_pae_controller_nvm_frame_counter_write(nvm_tlv_t *tlv_entry);
static int8_t ws_pae_controller_nvm_frame_counter_read(uint32_t *restart_cnt, uint64_t *stored_time, frame_counters_t *counters);
static pae_controller_t *ws_pae_controller_get_or_create(int8_t interface_id);
static void ws_pae_controller_gtk_hash_set(protocol_interface_info_entry_t *interface_ptr, uint8_t *gtkhash);
static int8_t ws_pae_controller_nw_key_check_and_insert(protocol_interface_info_entry_t *interface_ptr, sec_prot_gtk_keys_t *gtks);
@ -114,12 +125,19 @@ static void ws_pae_controller_active_nw_key_clear(nw_key_t *nw_key);
static void ws_pae_controller_active_nw_key_set(protocol_interface_info_entry_t *cur, uint8_t index);
static int8_t ws_pae_controller_gak_from_gtk(uint8_t *gak, uint8_t *gtk, char *network_name);
static void ws_pae_controller_frame_counter_store_and_nw_keys_remove(protocol_interface_info_entry_t *interface_ptr, pae_controller_t *controller, bool use_threshold);
#ifdef HAVE_PAE_AUTH
static void ws_pae_controller_nw_key_index_check_and_set(protocol_interface_info_entry_t *interface_ptr, uint8_t index);
#endif
static void ws_pae_controller_data_init(pae_controller_t *controller);
static void ws_pae_controller_frame_counter_read(pae_controller_t *controller);
static int8_t ws_pae_controller_frame_counter_read(pae_controller_t *controller);
static void ws_pae_controller_frame_counter_reset(frame_counters_t *frame_counters);
static int8_t ws_pae_controller_nw_info_read(pae_controller_t *controller, sec_prot_gtk_keys_t *gtks);
static int8_t ws_pae_controller_nvm_nw_info_write(protocol_interface_info_entry_t *interface_ptr, uint16_t pan_id, char *network_name, sec_prot_gtk_keys_t *gtks);
static int8_t ws_pae_controller_nvm_nw_info_read(protocol_interface_info_entry_t *interface_ptr, uint16_t *pan_id, char *network_name, sec_prot_gtk_keys_t *gtks);
static const char *FRAME_COUNTER_FILE = FRAME_COUNTER_FILE_NAME;
static const char *NW_INFO_FILE = NW_INFO_FILE_NAME;
static NS_LIST_DEFINE(pae_controller_list, pae_controller_t, link);
@ -129,26 +147,6 @@ pae_controller_config_t pae_controller_config = {
.ext_cert_valid_enabled = false
};
#if !defined(HAVE_PAE_SUPP) && !defined(HAVE_PAE_AUTH)
static void ws_pae_controller_test_keys_set(sec_prot_gtk_keys_t *gtks)
{
uint8_t gtk[GTK_LEN];
// Test data
for (int i = 0; i < GTK_LEN; i++) {
gtk[i] = 0xcf - i;
}
sec_prot_keys_gtk_set(gtks, 0, gtk, GTK_DEFAULT_LIFETIME);
}
#else
#define ws_pae_controller_test_keys_set(gtks);
#endif
int8_t ws_pae_controller_authenticate(protocol_interface_info_entry_t *interface_ptr)
{
pae_controller_t *controller = ws_pae_controller_get(interface_ptr);
@ -168,16 +166,9 @@ int8_t ws_pae_controller_authenticate(protocol_interface_info_entry_t *interface
return 0;
}
if (ws_pae_supp_authenticate(controller->interface_ptr, controller->target_pan_id, controller->target_eui_64) < 0) {
if (ws_pae_supp_authenticate(controller->interface_ptr, controller->target_pan_id, controller->target_eui_64, controller->sec_keys_nw_info.network_name) < 0) {
controller->auth_completed(interface_ptr, AUTH_RESULT_ERR_UNSPEC, controller->target_eui_64);
}
#else
ws_pae_controller_test_keys_set(&controller->gtks);
ws_pae_controller_nw_key_check_and_insert(interface_ptr, &controller->gtks);
ws_pae_controller_nw_key_index_check_and_set(interface_ptr, 0);
controller->auth_completed(interface_ptr, AUTH_RESULT_OK);
#endif
return 0;
@ -216,20 +207,6 @@ int8_t ws_pae_controller_authenticator_start(protocol_interface_info_entry_t *in
return -1;
}
#ifdef HAVE_PAE_AUTH
if (sec_prot_keys_gtks_are_updated(&controller->gtks)) {
ws_pae_auth_gtks_updated(interface_ptr);
if (controller->gtk_index >= 0) {
controller->pae_nw_key_index_update(interface_ptr, controller->gtk_index);
}
sec_prot_keys_gtks_updated_reset(&controller->gtks);
}
#else
ws_pae_controller_test_keys_set(&controller->gtks);
ws_pae_controller_nw_key_check_and_insert(interface_ptr, &controller->gtks);
ws_pae_controller_nw_key_index_check_and_set(interface_ptr, 0);
#endif
if (ws_pae_auth_addresses_set(interface_ptr, local_port, remote_addr, remote_port) < 0) {
return -1;
}
@ -238,14 +215,14 @@ int8_t ws_pae_controller_authenticator_start(protocol_interface_info_entry_t *in
ws_pae_auth_node_limit_set(controller->interface_ptr, pae_controller_config.node_limit);
}
ws_pae_auth_cb_register(interface_ptr, ws_pae_controller_gtk_hash_set, ws_pae_controller_nw_key_check_and_insert, ws_pae_controller_nw_key_index_check_and_set);
ws_pae_auth_cb_register(interface_ptr, ws_pae_controller_gtk_hash_set, ws_pae_controller_nw_key_check_and_insert, ws_pae_controller_nw_key_index_check_and_set, ws_pae_controller_nw_info_updated_check);
ws_pae_auth_start(interface_ptr);
return 0;
}
int8_t ws_pae_controller_cb_register(protocol_interface_info_entry_t *interface_ptr, ws_pae_controller_auth_completed *completed, ws_pae_controller_nw_key_set *nw_key_set, ws_pae_controller_nw_key_clear *nw_key_clear, ws_pae_controller_nw_send_key_index_set *nw_send_key_index_set, ws_pae_controller_nw_frame_counter_set *nw_frame_counter_set, ws_pae_controller_nw_frame_counter_read *nw_frame_counter_read, ws_pae_controller_pan_ver_increment *pan_ver_increment)
int8_t ws_pae_controller_cb_register(protocol_interface_info_entry_t *interface_ptr, ws_pae_controller_auth_completed *completed, ws_pae_controller_auth_next_target *auth_next_target, ws_pae_controller_nw_key_set *nw_key_set, ws_pae_controller_nw_key_clear *nw_key_clear, ws_pae_controller_nw_send_key_index_set *nw_send_key_index_set, ws_pae_controller_nw_frame_counter_set *nw_frame_counter_set, ws_pae_controller_nw_frame_counter_read *nw_frame_counter_read, ws_pae_controller_pan_ver_increment *pan_ver_increment, ws_pae_controller_nw_info_updated *nw_info_updated)
{
if (!interface_ptr) {
return -1;
@ -263,7 +240,8 @@ int8_t ws_pae_controller_cb_register(protocol_interface_info_entry_t *interface_
controller->nw_frame_counter_set = nw_frame_counter_set;
controller->nw_frame_counter_read = nw_frame_counter_read;
controller->pan_ver_increment = pan_ver_increment;
controller->nw_info_updated = nw_info_updated;
controller->auth_next_target = auth_next_target;
return 0;
}
@ -284,6 +262,20 @@ int8_t ws_pae_controller_set_target(protocol_interface_info_entry_t *interface_p
return 0;
}
static void ws_pae_controller_keys_nw_info_init(sec_prot_keys_nw_info_t *sec_keys_nw_info, sec_prot_gtk_keys_t *gtks)
{
if (!sec_keys_nw_info) {
return;
}
memset(sec_keys_nw_info, 0, sizeof(sec_prot_keys_nw_info_t));
sec_keys_nw_info->gtks = gtks;
sec_keys_nw_info->new_pan_id = 0xFFFF;
sec_keys_nw_info->key_pan_id = 0xFFFF;
sec_keys_nw_info->updated = false;
}
int8_t ws_pae_controller_nw_info_set(protocol_interface_info_entry_t *interface_ptr, uint16_t pan_id, char *network_name)
{
(void) pan_id;
@ -298,12 +290,44 @@ int8_t ws_pae_controller_nw_info_set(protocol_interface_info_entry_t *interface_
return -1;
}
controller->network_name = network_name;
// Network name has been modified
if (network_name && strncmp(controller->sec_keys_nw_info.network_name, network_name, 33) != 0) {
strncpy(controller->sec_keys_nw_info.network_name, network_name, 32);
controller->sec_keys_nw_info.updated = true;
}
return ws_pae_supp_nw_info_set(interface_ptr, pan_id, network_name);
// PAN ID has been modified
if (pan_id != 0xffff && pan_id != controller->sec_keys_nw_info.new_pan_id) {
controller->sec_keys_nw_info.new_pan_id = pan_id;
controller->sec_keys_nw_info.updated = true;
}
if (controller->pae_nw_info_set) {
controller->pae_nw_info_set(interface_ptr, pan_id, network_name);
}
return 0;
}
int8_t ws_pae_controller_nw_key_valid(protocol_interface_info_entry_t *interface_ptr)
static void ws_pae_controller_nw_info_updated_check(protocol_interface_info_entry_t *interface_ptr)
{
if (!interface_ptr) {
return;
}
pae_controller_t *controller = ws_pae_controller_get(interface_ptr);
if (!controller) {
return;
}
if (controller->sec_keys_nw_info.updated || sec_prot_keys_gtks_are_updated(controller->sec_keys_nw_info.gtks)) {
ws_pae_controller_nvm_nw_info_write(interface_ptr, controller->sec_keys_nw_info.key_pan_id, controller->sec_keys_nw_info.network_name, controller->sec_keys_nw_info.gtks);
controller->sec_keys_nw_info.updated = false;
sec_prot_keys_gtks_updated_reset(controller->sec_keys_nw_info.gtks);
}
}
int8_t ws_pae_controller_nw_key_valid(protocol_interface_info_entry_t *interface_ptr, uint8_t *br_iid)
{
if (!interface_ptr) {
return -1;
@ -314,7 +338,7 @@ int8_t ws_pae_controller_nw_key_valid(protocol_interface_info_entry_t *interface
return -1;
}
return ws_pae_supp_nw_key_valid(interface_ptr);
return ws_pae_supp_nw_key_valid(interface_ptr, br_iid);
}
static int8_t ws_pae_controller_nw_key_check_and_insert(protocol_interface_info_entry_t *interface_ptr, sec_prot_gtk_keys_t *gtks)
@ -366,21 +390,21 @@ static int8_t ws_pae_controller_nw_key_check_and_insert(protocol_interface_info_
sec_prot_keys_gtk_hash_generate(gtk, gtkhash);
tr_info("NW key set: %i, hash: %s", i, trace_array(gtkhash, 8));
uint8_t gak[GTK_LEN];
if (ws_pae_controller_gak_from_gtk(gak, gtk, controller->network_name) >= 0) {
if (ws_pae_controller_gak_from_gtk(gak, gtk, controller->sec_keys_nw_info.network_name) >= 0) {
// Install the new network key derived from GTK and network name (GAK) to MAC
controller->nw_key_set(interface_ptr, i, i, gak);
nw_key[i].installed = true;
ret = 0;
#ifdef EXTRA_DEBUG_INFO
tr_info("NW name: %s", controller->network_name);
size_t nw_name_len = strlen(controller->network_name);
tr_info("NW name: %s", trace_array((uint8_t *)controller->network_name, nw_name_len));
tr_info("NW name: %s", controller->sec_keys_nw_info.network_name);
size_t nw_name_len = strlen(controller->sec_keys_nw_info.network_name);
tr_info("NW name: %s", trace_array((uint8_t *)controller->sec_keys_nw_info.network_name, nw_name_len));
tr_info("GTK: %s", trace_array(gtk, 16));
tr_info("GAK: %s", trace_array(gak, 16));
#endif
} else {
tr_error("GAK generation failed network name: %s", controller->network_name);
tr_error("GAK generation failed network name: %s", controller->sec_keys_nw_info.network_name);
continue;
}
@ -512,6 +536,7 @@ static void ws_pae_controller_frame_counter_store_and_nw_keys_remove(protocol_in
}
}
#ifdef HAVE_PAE_AUTH
static void ws_pae_controller_nw_key_index_check_and_set(protocol_interface_info_entry_t *interface_ptr, uint8_t index)
{
pae_controller_t *controller = ws_pae_controller_get(interface_ptr);
@ -534,6 +559,7 @@ static void ws_pae_controller_nw_key_index_check_and_set(protocol_interface_info
controller->key_index_set = true;
}
}
#endif
static void ws_pae_controller_active_nw_key_set(protocol_interface_info_entry_t *cur, uint8_t index)
{
@ -564,11 +590,9 @@ int8_t ws_pae_controller_init(protocol_interface_info_entry_t *interface_ptr)
}
pae_controller_t *controller = ns_dyn_mem_alloc(sizeof(pae_controller_t));
void *pae_nvm_buffer = ws_pae_buffer_allocate();
if (!controller || !pae_nvm_buffer) {
if (!controller) {
ns_dyn_mem_free(controller);
ns_dyn_mem_free(pae_nvm_buffer);
return -1;
}
@ -579,7 +603,9 @@ int8_t ws_pae_controller_init(protocol_interface_info_entry_t *interface_ptr)
controller->nw_send_key_index_set = NULL;
controller->nw_frame_counter_set = NULL;
controller->pan_ver_increment = NULL;
controller->pae_nvm_buffer = pae_nvm_buffer;
controller->nw_info_updated = NULL;
controller->auth_next_target = NULL;
memset(&controller->sec_timer_cfg, 0, sizeof(ws_sec_timer_cfg_t));
memset(&controller->sec_prot_cfg, 0, sizeof(sec_prot_cfg_t));
@ -603,7 +629,15 @@ int8_t ws_pae_controller_configure(protocol_interface_info_entry_t *interface_pt
controller->sec_prot_cfg.sec_prot_trickle_params.k = 0;
controller->sec_prot_cfg.sec_prot_trickle_params.TimerExpirations = sec_prot_cfg->sec_prot_trickle_timer_exp;
controller->sec_prot_cfg.sec_prot_retry_timeout = sec_prot_cfg->sec_prot_retry_timeout * 10;
controller->sec_prot_cfg.sec_max_ongoing_authentication = sec_prot_cfg->sec_max_ongoing_authentication;
controller->sec_prot_cfg.initial_key_retry_delay = sec_prot_cfg->initial_key_retry_delay;
controller->sec_prot_cfg.initial_key_trickle_params.Imin = sec_prot_cfg->initial_key_imin;
controller->sec_prot_cfg.initial_key_trickle_params.Imax = sec_prot_cfg->initial_key_imax;
controller->sec_prot_cfg.initial_key_trickle_params.k = 0;
controller->sec_prot_cfg.initial_key_trickle_params.TimerExpirations = 2;
controller->sec_prot_cfg.initial_key_retry_cnt = sec_prot_cfg->initial_key_retry_cnt;
}
if (sec_timer_cfg) {
@ -613,7 +647,6 @@ int8_t ws_pae_controller_configure(protocol_interface_info_entry_t *interface_pt
return 0;
}
static void ws_pae_controller_data_init(pae_controller_t *controller)
{
memset(controller->target_eui_64, 0, 8);
@ -634,29 +667,43 @@ static void ws_pae_controller_data_init(pae_controller_t *controller)
controller->pae_gtks_updated = NULL;
controller->pae_gtk_hash_update = NULL;
controller->pae_nw_key_index_update = NULL;
controller->pae_nw_info_set = NULL;
controller->gtks_set = false;
controller->gtkhash_set = false;
controller->key_index_set = false;
controller->frame_counter_read = false;
controller->gtk_index = -1;
controller->network_name = NULL;
controller->frame_cnt_store_timer = FRAME_COUNTER_STORE_INTERVAL;
controller->frame_cnt_store_force_timer = FRAME_COUNTER_STORE_FORCE_INTERVAL;
controller->restart_cnt = 0;
ws_pae_controller_frame_counter_reset(&controller->frame_counters);
sec_prot_keys_gtks_init(&controller->gtks);
sec_prot_keys_gtks_init(&controller->next_gtks);
sec_prot_certs_init(&controller->certs);
sec_prot_certs_ext_certificate_validation_set(&controller->certs, pae_controller_config.ext_cert_valid_enabled);
ws_pae_controller_keys_nw_info_init(&controller->sec_keys_nw_info, &controller->gtks);
}
static void ws_pae_controller_frame_counter_read(pae_controller_t *controller)
static int8_t ws_pae_controller_frame_counter_read(pae_controller_t *controller)
{
int8_t ret_value = 0;
if (controller->frame_counter_read) {
return;
return ret_value;
}
controller->frame_counter_read = true;
uint64_t stored_time = 0;
// Read frame counters
if (ws_pae_controller_nvm_frame_counter_read(&controller->frame_counters) >= 0) {
if (ws_pae_controller_nvm_frame_counter_read(&controller->restart_cnt, &stored_time, &controller->frame_counters) >= 0) {
// Current time is not valid
if (ws_pae_current_time_set(stored_time) < 0) {
ret_value = -1;
}
// This is used to ensure that PMK replay counters are fresh after each re-start.
controller->restart_cnt++;
bool updated = false;
// Checks frame counters
for (uint8_t index = 0; index < GTK_NUM; index++) {
@ -673,10 +720,12 @@ static void ws_pae_controller_frame_counter_read(pae_controller_t *controller)
}
if (updated) {
// Writes incremented frame counters
ws_pae_nvm_store_frame_counter_tlv_create(controller->pae_nvm_buffer, &controller->frame_counters);
ws_pae_controller_nvm_frame_counter_write(controller->pae_nvm_buffer);
ws_pae_nvm_store_frame_counter_tlv_create((nvm_tlv_t *) &controller->pae_nvm_buffer, controller->restart_cnt, &controller->frame_counters);
ws_pae_controller_nvm_frame_counter_write((nvm_tlv_t *) &controller->pae_nvm_buffer);
}
}
return ret_value;
}
static void ws_pae_controller_frame_counter_reset(frame_counters_t *frame_counters)
@ -689,6 +738,53 @@ static void ws_pae_controller_frame_counter_reset(frame_counters_t *frame_counte
}
}
static int8_t ws_pae_controller_nw_info_read(pae_controller_t *controller, sec_prot_gtk_keys_t *gtks)
{
if (ws_pae_controller_nvm_nw_info_read(controller->interface_ptr, &controller->sec_keys_nw_info.key_pan_id, controller->sec_keys_nw_info.network_name, gtks) < 0) {
// If no stored GTKs and network info (pan_id and network name) exits
return -1;
}
// Sets also new pan_id used for pan_id set by bootstrap
controller->sec_keys_nw_info.new_pan_id = controller->sec_keys_nw_info.key_pan_id;
return 0;
}
static int8_t ws_pae_controller_nvm_nw_info_write(protocol_interface_info_entry_t *interface_ptr, uint16_t pan_id, char *network_name, sec_prot_gtk_keys_t *gtks)
{
nvm_tlv_t *tlv = ws_pae_controller_nvm_tlv_get(interface_ptr);
if (!tlv) {
return -1;
}
ws_pae_nvm_store_nw_info_tlv_create(tlv, pan_id, network_name, gtks);
ws_pae_nvm_store_tlv_file_write(NW_INFO_FILE, tlv);
return 0;
}
static int8_t ws_pae_controller_nvm_nw_info_read(protocol_interface_info_entry_t *interface_ptr, uint16_t *pan_id, char *network_name, sec_prot_gtk_keys_t *gtks)
{
nvm_tlv_t *tlv_entry = ws_pae_controller_nvm_tlv_get(interface_ptr);
if (!tlv_entry) {
return -1;
}
ws_pae_nvm_store_generic_tlv_create(tlv_entry, PAE_NVM_NW_INFO_TAG, PAE_NVM_NW_INFO_LEN);
if (ws_pae_nvm_store_tlv_file_read(NW_INFO_FILE, tlv_entry) < 0) {
return -1;
}
if (ws_pae_nvm_store_nw_info_tlv_read(tlv_entry, pan_id, network_name, gtks) < 0) {
return -1;
}
return 0;
}
int8_t ws_pae_controller_supp_init(protocol_interface_info_entry_t *interface_ptr)
{
pae_controller_t *controller = ws_pae_controller_get(interface_ptr);
@ -696,7 +792,7 @@ int8_t ws_pae_controller_supp_init(protocol_interface_info_entry_t *interface_pt
return -1;
}
if (ws_pae_supp_init(controller->interface_ptr, &controller->certs, &controller->sec_timer_cfg, &controller->sec_prot_cfg) < 0) {
if (ws_pae_supp_init(controller->interface_ptr, &controller->certs, &controller->sec_timer_cfg, &controller->sec_prot_cfg, &controller->sec_keys_nw_info) < 0) {
return -1;
}
@ -707,10 +803,14 @@ int8_t ws_pae_controller_supp_init(protocol_interface_info_entry_t *interface_pt
controller->pae_br_addr_read = ws_pae_supp_border_router_addr_read;
controller->pae_gtk_hash_update = ws_pae_supp_gtk_hash_update;
controller->pae_nw_key_index_update = ws_pae_supp_nw_key_index_update;
controller->pae_nw_info_set = NULL;
ws_pae_supp_cb_register(controller->interface_ptr, controller->auth_completed, ws_pae_controller_nw_key_check_and_insert, ws_pae_controller_active_nw_key_set, ws_pae_controller_gtk_hash_ptr_get);
ws_pae_supp_cb_register(controller->interface_ptr, controller->auth_completed, controller->auth_next_target, ws_pae_controller_nw_key_check_and_insert, ws_pae_controller_active_nw_key_set, ws_pae_controller_gtk_hash_ptr_get, ws_pae_controller_nw_info_updated_check);
ws_pae_controller_frame_counter_read(controller);
ws_pae_controller_nw_info_read(controller, controller->sec_keys_nw_info.gtks);
// Set active key back to fresh so that it can be used again after re-start
sec_prot_keys_gtk_status_active_to_fresh_set(&controller->gtks);
return 0;
}
@ -722,7 +822,7 @@ int8_t ws_pae_controller_auth_init(protocol_interface_info_entry_t *interface_pt
return -1;
}
if (ws_pae_auth_init(controller->interface_ptr, &controller->gtks, &controller->next_gtks, &controller->certs, &controller->sec_timer_cfg, &controller->sec_prot_cfg) < 0) {
if (ws_pae_auth_init(controller->interface_ptr, &controller->next_gtks, &controller->certs, &controller->sec_timer_cfg, &controller->sec_prot_cfg, &controller->sec_keys_nw_info) < 0) {
return -1;
}
@ -731,8 +831,45 @@ int8_t ws_pae_controller_auth_init(protocol_interface_info_entry_t *interface_pt
controller->pae_slow_timer = ws_pae_auth_slow_timer;
controller->pae_gtks_updated = ws_pae_auth_gtks_updated;
controller->pae_nw_key_index_update = ws_pae_auth_nw_key_index_update;
controller->pae_nw_info_set = ws_pae_auth_nw_info_set;
ws_pae_controller_frame_counter_read(controller);
sec_prot_gtk_keys_t *read_gtks_to = controller->sec_keys_nw_info.gtks;
if (ws_pae_controller_frame_counter_read(controller) < 0) {
tr_error("Stored key material invalid");
// Key material invalid, do not read GTKs or any other security data
read_gtks_to = NULL;
}
#ifdef HAVE_PAE_AUTH
if (sec_prot_keys_gtks_are_updated(&controller->gtks)) {
// If application has set GTK keys prepare those for use
ws_pae_auth_gtks_updated(interface_ptr);
if (controller->gtk_index >= 0) {
controller->pae_nw_key_index_update(interface_ptr, controller->gtk_index);
}
sec_prot_keys_gtks_updated_reset(&controller->gtks);
}
#endif
if (ws_pae_controller_nw_info_read(controller, read_gtks_to) >= 0) {
/* If network information i.e pan_id and network name exists updates bootstrap with it,
(in case already configured by application then no changes are made) */
if (controller->nw_info_updated) {
controller->nw_info_updated(interface_ptr, controller->sec_keys_nw_info.key_pan_id, controller->sec_keys_nw_info.network_name);
}
if (!read_gtks_to || sec_prot_keys_gtk_count(read_gtks_to) == 0) {
// Key material invalid or GTKs are expired, delete GTKs from NVM
ws_pae_controller_nvm_nw_info_write(controller->interface_ptr, controller->sec_keys_nw_info.key_pan_id, controller->sec_keys_nw_info.network_name, NULL);
}
}
ws_pae_key_storage_init();
if (read_gtks_to) {
ws_pae_key_storage_read(controller->restart_cnt);
} else {
// Key material invalid, delete key storage
ws_pae_key_storage_remove();
}
return 0;
}
@ -747,6 +884,15 @@ int8_t ws_pae_controller_stop(protocol_interface_info_entry_t *interface_ptr)
// Stores frame counters and removes network keys from PAE controller and MAC
ws_pae_controller_frame_counter_store_and_nw_keys_remove(interface_ptr, controller, false);
// Store security key network info if it has been modified
ws_pae_controller_nw_info_updated_check(interface_ptr);
// Store key storage if it has been modified
ws_pae_key_storage_store();
// Delete key storage
ws_pae_key_storage_delete();
// If PAE has been initialized, deletes it
if (controller->pae_delete) {
controller->pae_delete(interface_ptr);
@ -775,7 +921,6 @@ int8_t ws_pae_controller_delete(protocol_interface_info_entry_t *interface_ptr)
}
ns_list_remove(&pae_controller_list, controller);
ns_dyn_mem_free(controller->pae_nvm_buffer);
ns_dyn_mem_free(controller);
return 0;
@ -1028,6 +1173,10 @@ int8_t ws_pae_controller_gtk_update(int8_t interface_id, uint8_t *gtk[GTK_NUM])
}
}
// Sets active key
int8_t index = sec_prot_keys_gtk_install_order_first_index_get(&controller->gtks);
sec_prot_keys_gtk_status_active_set(&controller->gtks, index);
// Notifies PAE authenticator that GTKs have been updated */
if (controller->pae_gtks_updated) {
controller->pae_gtks_updated(controller->interface_ptr);
@ -1234,6 +1383,13 @@ static void ws_pae_controller_frame_counter_timer(uint16_t seconds, pae_controll
entry->frame_cnt_store_timer = FRAME_COUNTER_STORE_INTERVAL;
ws_pae_controller_frame_counter_store(entry, true);
}
if (entry->frame_cnt_store_force_timer > seconds) {
entry->frame_cnt_store_force_timer -= seconds;
} else {
entry->frame_cnt_store_force_timer = 0;
ws_pae_controller_frame_counter_store(entry, true);
}
}
static void ws_pae_controller_frame_counter_timer_trigger(uint16_t seconds, pae_controller_t *entry)
@ -1287,33 +1443,38 @@ static void ws_pae_controller_frame_counter_store(pae_controller_t *entry, bool
}
}
if (update_needed) {
if (update_needed || entry->frame_cnt_store_force_timer == 0) {
tr_debug("Write frame counters: system time %"PRIu32"", protocol_core_monotonic_time / 10);
// Writes modified frame counters
ws_pae_nvm_store_frame_counter_tlv_create(entry->pae_nvm_buffer, &entry->frame_counters);
ws_pae_controller_nvm_frame_counter_write(entry->pae_nvm_buffer);
ws_pae_nvm_store_frame_counter_tlv_create((nvm_tlv_t *) &entry->pae_nvm_buffer, entry->restart_cnt, &entry->frame_counters);
ws_pae_controller_nvm_frame_counter_write((nvm_tlv_t *) &entry->pae_nvm_buffer);
// Reset force interval when ever values are stored
entry->frame_cnt_store_force_timer = FRAME_COUNTER_STORE_FORCE_INTERVAL;
}
}
static int8_t ws_pae_controller_nvm_frame_counter_read(frame_counters_t *counters)
static int8_t ws_pae_controller_nvm_frame_counter_read(uint32_t *restart_cnt, uint64_t *stored_time, frame_counters_t *counters)
{
nvm_tlv_list_t tlv_list;
ns_list_init(&tlv_list);
if (ws_pae_nvm_store_tlv_file_read(FRAME_COUNTER_FILE, &tlv_list) < 0) {
nvm_tlv_t *tlv = ws_pae_nvm_store_generic_tlv_allocate_and_create(
PAE_NVM_FRAME_COUNTER_TAG, PAE_NVM_FRAME_COUNTER_LEN);
if (!tlv) {
return -1;
}
int8_t result = -1;
ns_list_foreach_safe(nvm_tlv_entry_t, entry, &tlv_list) {
if (ws_pae_nvm_store_frame_counter_tlv_read(entry, counters) >= 0) {
result = 0;
}
ns_list_remove(&tlv_list, entry);
ns_dyn_mem_free(entry);
if (ws_pae_nvm_store_tlv_file_read(FRAME_COUNTER_FILE, tlv) < 0) {
ws_pae_nvm_store_generic_tlv_free(tlv);
return -1;
}
return result;
if (ws_pae_nvm_store_frame_counter_tlv_read(tlv, restart_cnt, stored_time, counters) < 0) {
ws_pae_nvm_store_generic_tlv_free(tlv);
return -1;
}
ws_pae_nvm_store_generic_tlv_free(tlv);
return 0;
}
static pae_controller_t *ws_pae_controller_get(protocol_interface_info_entry_t *interface_ptr)
@ -1346,22 +1507,19 @@ static pae_controller_t *ws_pae_controller_get_or_create(int8_t interface_id)
return controller;
}
nvm_tlv_entry_t *ws_pae_controller_nvm_tlv_get(protocol_interface_info_entry_t *interface_ptr)
nvm_tlv_t *ws_pae_controller_nvm_tlv_get(protocol_interface_info_entry_t *interface_ptr)
{
pae_controller_t *controller = ws_pae_controller_get(interface_ptr);
if (!controller) {
return NULL;
}
return controller->pae_nvm_buffer;
return (nvm_tlv_t *) &controller->pae_nvm_buffer;
}
static void ws_pae_controller_nvm_frame_counter_write(nvm_tlv_entry_t *tlv_entry)
static void ws_pae_controller_nvm_frame_counter_write(nvm_tlv_t *tlv_entry)
{
nvm_tlv_list_t tlv_list;
ns_list_init(&tlv_list);
ns_list_add_to_end(&tlv_list, tlv_entry);
ws_pae_nvm_store_tlv_file_write(FRAME_COUNTER_FILE, &tlv_list);
ws_pae_nvm_store_tlv_file_write(FRAME_COUNTER_FILE, tlv_entry);
}

View File

@ -249,12 +249,13 @@ int8_t ws_pae_controller_nw_info_set(protocol_interface_info_entry_t *interface_
* ws_pae_controller_nw_key_valid network key is valid i.e. used successfully on bootstrap
*
* \param interface_ptr interface
* \param br_iid border router IID for which the keys are valid
*
* \return < 0 failure
* \return >= 0 success
*
*/
int8_t ws_pae_controller_nw_key_valid(protocol_interface_info_entry_t *interface_ptr);
int8_t ws_pae_controller_nw_key_valid(protocol_interface_info_entry_t *interface_ptr, uint8_t *br_iid);
/**
* ws_pae_controller_border_router_addr_write write border router address
@ -278,7 +279,7 @@ int8_t ws_pae_controller_border_router_addr_write(protocol_interface_info_entry_
* \return >= 0 success
*
*/
int8_t ws_pae_controller_border_router_addr_read(protocol_interface_info_entry_t *interface_ptr, uint8_t *eui_64);
int8_t ws_pae_controller_border_router_addr_read(protocol_interface_info_entry_t *interface_ptr, uint8_t *iid);
/**
* ws_pae_controller_gtk_update update GTKs (test interface)
@ -492,6 +493,18 @@ typedef void ws_pae_controller_nw_frame_counter_read(protocol_interface_info_ent
*/
typedef void ws_pae_controller_auth_completed(protocol_interface_info_entry_t *interface_ptr, auth_result_e result, uint8_t *target_eui_64);
/**
* ws_pae_controller_auth_next_target get next target to attempt authentication
*
* \param interface_ptr interface
* \param previous_eui_64 EUI-64 of previous target
* \param pan_id pan id
*
* \return EUI-64 of the next target or previous target if new one not available
*
*/
typedef const uint8_t *ws_pae_controller_auth_next_target(protocol_interface_info_entry_t *interface_ptr, const uint8_t *previous_eui_64, uint16_t *pan_id);
/**
* ws_pae_controller_pan_ver_increment PAN version increment callback
*
@ -500,23 +513,35 @@ typedef void ws_pae_controller_auth_completed(protocol_interface_info_entry_t *i
*/
typedef void ws_pae_controller_pan_ver_increment(protocol_interface_info_entry_t *interface_ptr);
/**
* ws_pae_controller_nw_info_updated network information is updated (read from memory)
*
* \param interface_ptr interface
* \param pan_id PAN ID
* \param network_name network name
*
*/
typedef void ws_pae_controller_nw_info_updated(protocol_interface_info_entry_t *interface_ptr, uint16_t pan_id, char *network_name);
/**
* ws_pae_controller_cb_register register PEA controller callbacks
*
* \param interface_ptr interface
* \param completed authentication completed callback
* \param next_target authentication next target callback
* \param nw_key_set network key set callback
* \param nw_key_clear network key clear callback
* \param nw_send_key_index_set network send key index set callback
* \param nw_frame_counter_set network frame counter set callback
* \param nw_frame_counter_read network frame counter read callback
* \param pan_ver_increment PAN version increment callback
* \param nw_info_updated network information updated callback
*
* \return < 0 failure
* \return >= 0 success
*
*/
int8_t ws_pae_controller_cb_register(protocol_interface_info_entry_t *interface_ptr, ws_pae_controller_auth_completed *completed, ws_pae_controller_nw_key_set *nw_key_set, ws_pae_controller_nw_key_clear *nw_key_clear, ws_pae_controller_nw_send_key_index_set *nw_send_key_index_set, ws_pae_controller_nw_frame_counter_set *nw_frame_counter_set, ws_pae_controller_nw_frame_counter_read *nw_frame_counter_read, ws_pae_controller_pan_ver_increment *pan_ver_increment);
int8_t ws_pae_controller_cb_register(protocol_interface_info_entry_t *interface_ptr, ws_pae_controller_auth_completed *completed, ws_pae_controller_auth_next_target *auth_next_target, ws_pae_controller_nw_key_set *nw_key_set, ws_pae_controller_nw_key_clear *nw_key_clear, ws_pae_controller_nw_send_key_index_set *nw_send_key_index_set, ws_pae_controller_nw_frame_counter_set *nw_frame_counter_set, ws_pae_controller_nw_frame_counter_read *nw_frame_counter_read, ws_pae_controller_pan_ver_increment *pan_ver_increment, ws_pae_controller_nw_info_updated *nw_info_updated);
/**
* ws_pae_controller_fast_timer PAE controller fast timer call
@ -534,7 +559,7 @@ void ws_pae_controller_fast_timer(uint16_t ticks);
*/
void ws_pae_controller_slow_timer(uint16_t seconds);
struct nvm_tlv_entry *ws_pae_controller_nvm_tlv_get(protocol_interface_info_entry_t *interface_ptr);
struct nvm_tlv *ws_pae_controller_nvm_tlv_get(protocol_interface_info_entry_t *interface_ptr);
/**
* ws_pae_controller_forced_gc PAE controller garbage cleanup callback

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,164 @@
/*
* Copyright (c) 2020, Arm Limited and affiliates.
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef WS_PAE_KEY_STORAGE_H_
#define WS_PAE_KEY_STORAGE_H_
/*
* Port access entity key storage functions.
*
*/
// Number of storages i.e. records in NVM
#define DEFAULT_NUMBER_OF_STORAGES 50
// Number of entries stored in a storage i.e. one record in NVM
#define DEFAULT_NUMBER_OF_ENTRIES_IN_ONE_STORAGE 100
// Interval to check if storage has been modified and needs to be updated to NVM
#define DEFAULT_STORING_INTERVAL 3600
struct supp_entry_s;
struct sec_prot_gtk_keys_s;
struct sec_prot_certs_s;
/**
* ws_pae_key_storage_memory_set sets memory used for key storages
*
* This functions can be used to set memory used by key storage. When memory areas
* are set, module does not allocate memory internally from heap.
*
* \param key_storages_number number of memory areas
* \param key_storage_size array of memory area sizes
* \param key_storages array of memory area start pointers
*
* \return < 0 failure
* \return >= 0 success
*
*/
int8_t ws_pae_key_storage_memory_set(uint8_t key_storages_number, const uint16_t *key_storage_size, void **key_storages);
/**
* ws_pae_key_storage_memory_set sets key storage settings
*
* Allocation max number and allocation size sets the settings that are used when key storage
* memory is allocated dynamically from heap. These settings must be set before (first) interface
* up and shall not be set if key storage memory is set by ws_pae_key_storage_memory_set() call.
*
* \param alloc_max_number maximum number of allocation made to dynamic memory
* \param alloc_size size of each allocation
* \param storing_interval interval in which the check to store to NVM is made
*
* \return < 0 failure
* \return >= 0 success
*
*/
int8_t ws_pae_key_storage_settings_set(uint8_t alloc_max_number, uint16_t alloc_size, uint16_t storing_interval);
/**
* ws_pae_key_storage_init init key storage
*
*/
void ws_pae_key_storage_init(void);
/**
* ws_pae_key_storage_init delete key storage
*
*/
void ws_pae_key_storage_delete(void);
/**
* ws_pae_key_storage_store store to NVM
*
* Checks whether key storage data has been updated and stores to NVM.
*
* \return < 0 failure
* \return >= 0 success
*
*/
int8_t ws_pae_key_storage_store(void);
/**
* ws_pae_key_storage_read read from NVM
*
* Reads key storage data from NVM.
*
*/
void ws_pae_key_storage_read(uint32_t restart_cnt);
/**
* ws_pae_key_storage_remove remove storage from NVM
*
* Removes key storage data from NVM.
*
*/
void ws_pae_key_storage_remove(void);
/**
* ws_pae_key_storage_supp_write writes supplicant entry to key storage
*
* \param instance instance
* \param pae_supp supplicant entry
*
* \return < 0 failure
* \return >= 0 success
*
*/
int8_t ws_pae_key_storage_supp_write(const void *instance, struct supp_entry_s *pae_supp);
/**
* ws_pae_key_storage_supp_read reads supplicant entry from key storage
*
* \param instance instance
* \param eui_64 EUI-64 of the supplicant
* \param gtks GTK keys
* \param cert_chain certificates
*
* \return supplicant entry or NULL if supplicant entry does not exits
*
*/
struct supp_entry_s *ws_pae_key_storage_supp_read(const void *instance, const uint8_t *eui_64, struct sec_prot_gtk_keys_s *gtks, const struct sec_prot_certs_s *certs);
/**
* ws_pae_key_storage_supp_delete delete supplicant entry from key storage
*
* \param instance instance
* \param eui_64 EUI-64 of the supplicant
*
* \return true entry was deleted
* \return false entry was not deleted
*
*/
bool ws_pae_key_storage_supp_delete(const void *instance, const uint8_t *eui64);
/**
* ws_pae_key_storage_timer key storage timers
*
* \param seconds Seconds passed
*
*/
void ws_pae_key_storage_timer(uint16_t seconds);
/**
* ws_pae_key_storage_storing_interval_get gets key storage storing interval
*
* \return storing interval in seconds
*
*/
uint16_t ws_pae_key_storage_storing_interval_get(void);
#endif /* WS_PAE_KEY_STORAGE_H_ */

View File

@ -26,13 +26,14 @@
#include "NWK_INTERFACE/Include/protocol.h"
#include "6LoWPAN/ws/ws_cfg_settings.h"
#include "6LoWPAN/ws/ws_config.h"
#include "6LoWPAN/ws/ws_pae_timers.h"
#include "Security/protocols/sec_prot_cfg.h"
#include "6LoWPAN/ws/ws_pae_timers.h"
#include "Security/kmp/kmp_addr.h"
#include "Security/kmp/kmp_api.h"
#include "Security/protocols/sec_prot_certs.h"
#include "Security/protocols/sec_prot_keys.h"
#include "6LoWPAN/ws/ws_pae_lib.h"
#include "6LoWPAN/ws/ws_pae_key_storage.h"
#ifdef HAVE_WS
@ -126,6 +127,16 @@ kmp_entry_t *ws_pae_lib_kmp_list_entry_get(kmp_list_t *kmp_list, kmp_api_t *kmp)
return 0;
}
bool ws_pae_lib_kmp_list_empty(kmp_list_t *kmp_list)
{
return ns_list_is_empty(kmp_list);
}
uint8_t ws_pae_lib_kmp_list_count(kmp_list_t *kmp_list)
{
return ns_list_count(kmp_list);
}
void ws_pae_lib_kmp_timer_start(kmp_list_t *kmp_list, kmp_entry_t *entry)
{
if (ns_list_get_first(kmp_list) != entry) {
@ -171,7 +182,7 @@ void ws_pae_lib_supp_list_init(supp_list_t *supp_list)
supp_entry_t *ws_pae_lib_supp_list_add(supp_list_t *supp_list, const kmp_addr_t *addr)
{
supp_entry_t *entry = ns_dyn_mem_alloc(sizeof(supp_entry_t));
supp_entry_t *entry = ns_dyn_mem_temporary_alloc(sizeof(supp_entry_t));
if (!entry) {
return NULL;
@ -215,33 +226,32 @@ void ws_pae_lib_supp_list_delete(supp_list_t *supp_list)
}
}
bool ws_pae_lib_supp_list_timer_update(supp_list_t *active_supp_list, supp_list_t *inactive_supp_list, uint16_t ticks, ws_pae_lib_kmp_timer_timeout timeout)
bool ws_pae_lib_supp_list_timer_update(void *instance, supp_list_t *active_supp_list, uint16_t ticks, ws_pae_lib_kmp_timer_timeout timeout)
{
bool timer_running = false;
ns_list_foreach_safe(supp_entry_t, entry, active_supp_list) {
bool running = ws_pae_lib_supp_timer_update(entry, ticks, timeout);
bool running = ws_pae_lib_supp_timer_update(instance, entry, ticks, timeout);
if (running) {
timer_running = true;
} else {
ws_pae_lib_supp_list_to_inactive(active_supp_list, inactive_supp_list, entry);
ws_pae_lib_supp_list_to_inactive(instance, active_supp_list, entry);
}
}
return timer_running;
}
void ws_pae_lib_supp_list_slow_timer_update(supp_list_t *supp_list, sec_timer_cfg_t *timer_settings, uint16_t seconds)
void ws_pae_lib_supp_list_slow_timer_update(supp_list_t *supp_list, uint16_t seconds)
{
ns_list_foreach(supp_entry_t, entry, supp_list) {
if (sec_prot_keys_pmk_lifetime_decrement(&entry->sec_keys, timer_settings->pmk_lifetime, seconds)) {
if (sec_prot_keys_pmk_lifetime_decrement(&entry->sec_keys, seconds)) {
tr_info("PMK and PTK expired, eui-64: %s, system time: %"PRIu32"", trace_array(entry->addr.eui_64, 8), protocol_core_monotonic_time / 10);
}
if (sec_prot_keys_ptk_lifetime_decrement(&entry->sec_keys, timer_settings->ptk_lifetime, seconds)) {
if (sec_prot_keys_ptk_lifetime_decrement(&entry->sec_keys, seconds)) {
tr_info("PTK expired, eui-64: %s, system time: %"PRIu32"", trace_array(entry->addr.eui_64, 8), protocol_core_monotonic_time / 10);
}
}
}
void ws_pae_lib_supp_init(supp_entry_t *entry)
@ -251,6 +261,7 @@ void ws_pae_lib_supp_init(supp_entry_t *entry)
memset(&entry->sec_keys, 0, sizeof(sec_prot_keys_t));
entry->ticks = 0;
entry->retry_ticks = 0;
entry->store_ticks = ws_pae_key_storage_storing_interval_get() * 1000;
entry->active = true;
entry->access_revoked = false;
}
@ -260,7 +271,7 @@ void ws_pae_lib_supp_delete(supp_entry_t *entry)
ws_pae_lib_kmp_list_free(&entry->kmp_list);
}
bool ws_pae_lib_supp_timer_update(supp_entry_t *entry, uint16_t ticks, ws_pae_lib_kmp_timer_timeout timeout)
bool ws_pae_lib_supp_timer_update(void *instance, supp_entry_t *entry, uint16_t ticks, ws_pae_lib_kmp_timer_timeout timeout)
{
// Updates KMP timers and calls timeout callback
bool keep_timer_running = ws_pae_lib_kmp_timer_update(&entry->kmp_list, ticks, timeout);
@ -286,6 +297,19 @@ bool ws_pae_lib_supp_timer_update(supp_entry_t *entry, uint16_t ticks, ws_pae_li
entry->retry_ticks = 0;
}
if (!instance) {
return keep_timer_running;
}
// Updates retry timer
if (entry->store_ticks > ticks) {
entry->store_ticks -= ticks;
} else {
tr_info("PAE active entry key storage update timeout");
ws_pae_key_storage_supp_write(instance, entry);
entry->store_ticks = ws_pae_key_storage_storing_interval_get() * 1000;
}
return keep_timer_running;
}
@ -326,7 +350,7 @@ void ws_pae_lib_supp_list_to_active(supp_list_t *active_supp_list, supp_list_t *
entry->addr.type = KMP_ADDR_EUI_64_AND_IP;
}
void ws_pae_lib_supp_list_to_inactive(supp_list_t *active_supp_list, supp_list_t *inactive_supp_list, supp_entry_t *entry)
void ws_pae_lib_supp_list_to_inactive(void *instance, supp_list_t *active_supp_list, supp_entry_t *entry)
{
if (!entry->active) {
return;
@ -340,34 +364,28 @@ void ws_pae_lib_supp_list_to_inactive(supp_list_t *active_supp_list, supp_list_t
return;
}
ns_list_remove(active_supp_list, entry);
ns_list_add_to_start(inactive_supp_list, entry);
// Store to key storage
ws_pae_key_storage_supp_write(instance, entry);
entry->active = false;
entry->ticks = 0;
// Removes relay address data
entry->addr.type = KMP_ADDR_EUI_64;
entry->addr.port = 0;
memset(entry->addr.relay_address, 0, 16);
// Remove supplicant entry
ws_pae_lib_supp_list_remove(active_supp_list, entry);
}
void ws_pae_lib_supp_list_purge(supp_list_t *active_supp_list, supp_list_t *inactive_supp_list, uint16_t max_number, uint8_t max_purge)
void ws_pae_lib_supp_list_purge(supp_list_t *active_supp_list, uint16_t max_number, uint8_t max_purge)
{
uint16_t active_supp = ns_list_count(active_supp_list);
uint16_t inactive_supp = ns_list_count(inactive_supp_list);
if (active_supp + inactive_supp > max_number) {
uint16_t remove_count = active_supp + inactive_supp - max_number;
if (active_supp > max_number) {
uint16_t remove_count = active_supp - max_number;
if (max_purge > 0 && remove_count > max_purge) {
remove_count = max_purge;
}
// Remove entries from inactive list
ns_list_foreach_safe(supp_entry_t, entry, inactive_supp_list) {
if (remove_count > 0) {
tr_info("Inactive supplicant removed, eui-64: %s", trace_array(kmp_address_eui_64_get(&entry->addr), 8));
ws_pae_lib_supp_list_remove(inactive_supp_list, entry);
// Remove entries from active list if there are no active KMPs ongoing for the entry
ns_list_foreach_safe(supp_entry_t, entry, active_supp_list) {
if (remove_count > 0 && ws_pae_lib_kmp_list_empty(&entry->kmp_list)) {
tr_info("Active supplicant removed, eui-64: %s", trace_array(kmp_address_eui_64_get(&entry->addr), 8));
ws_pae_lib_supp_list_remove(active_supp_list, entry);
remove_count--;
} else {
break;
@ -376,6 +394,16 @@ void ws_pae_lib_supp_list_purge(supp_list_t *active_supp_list, supp_list_t *inac
}
}
bool ws_pae_lib_supp_list_active_limit_reached(supp_list_t *active_supp_list, uint16_t max_number)
{
uint16_t active_supp = ns_list_count(active_supp_list);
if (active_supp > max_number) {
return true;
}
return false;
}
uint16_t ws_pae_lib_supp_list_kmp_count(supp_list_t *supp_list, kmp_type_e type)
{
uint16_t kmp_count = 0;

View File

@ -31,12 +31,13 @@ typedef struct {
typedef NS_LIST_HEAD(kmp_entry_t, link) kmp_list_t;
typedef struct {
typedef struct supp_entry_s {
kmp_list_t kmp_list; /**< Ongoing KMP negotiations */
kmp_addr_t addr; /**< EUI-64 (Relay IP address, Relay port) */
sec_prot_keys_t sec_keys; /**< Security keys */
uint32_t ticks; /**< Ticks */
uint16_t retry_ticks; /**< Retry ticks */
uint16_t store_ticks; /**< NVM store ticks */
bool active : 1; /**< Is active */
bool access_revoked : 1; /**< Nodes access is revoked */
ns_list_link_t link; /**< Link */
@ -123,6 +124,27 @@ kmp_api_t *ws_pae_lib_kmp_list_instance_id_get(kmp_list_t *kmp_list, uint8_t ins
*/
kmp_entry_t *ws_pae_lib_kmp_list_entry_get(kmp_list_t *kmp_list, kmp_api_t *kmp);
/**
* ws_pae_lib_kmp_list_empty checks whether KMP list is empty
*
* \param kmp_list KMP list
*
* \return true list is empty
* \return false list is not empty
*
*/
bool ws_pae_lib_kmp_list_empty(kmp_list_t *kmp_list);
/**
* ws_pae_lib_kmp_list_count counts entries on KMP list
*
* \param kmp_list KMP list
*
* \return count of entries on the list
*
*/
uint8_t ws_pae_lib_kmp_list_count(kmp_list_t *kmp_list);
/**
* ws_pae_lib_kmp_timer_start starts KMP timer
*
@ -215,6 +237,7 @@ void ws_pae_lib_supp_list_delete(supp_list_t *supp_list);
/**
* ws_pae_lib_supp_list_timer_update updates timers on supplicant list
*
* \param instance Instance
* \param active_supp_list list of active supplicants
* \param inactive_supp_list list of inactive supplicants
* \param ticks timer ticks
@ -223,17 +246,16 @@ void ws_pae_lib_supp_list_delete(supp_list_t *supp_list);
* \return true timer needs still to be running
* \return false timer can be stopped
*/
bool ws_pae_lib_supp_list_timer_update(supp_list_t *active_supp_list, supp_list_t *inactive_supp_list, uint16_t ticks, ws_pae_lib_kmp_timer_timeout timeout);
bool ws_pae_lib_supp_list_timer_update(void *instance, supp_list_t *active_supp_list, uint16_t ticks, ws_pae_lib_kmp_timer_timeout timeout);
/**
* ws_pae_lib_supp_list_slow_timer_update updates slow timer on supplicant list
*
* \param supp_list list of supplicants
* \param timer_settings timer settings
* \param seconds seconds
*
*/
void ws_pae_lib_supp_list_slow_timer_update(supp_list_t *supp_list, sec_timer_cfg_t *timer_settings, uint16_t seconds);
void ws_pae_lib_supp_list_slow_timer_update(supp_list_t *supp_list, uint16_t seconds);
/**
* ws_pae_lib_supp_list_timer_update updates supplicant timers
@ -245,7 +267,7 @@ void ws_pae_lib_supp_list_slow_timer_update(supp_list_t *supp_list, sec_timer_cf
* \return true timer needs still to be running
* \return false timer can be stopped
*/
bool ws_pae_lib_supp_timer_update(supp_entry_t *entry, uint16_t ticks, ws_pae_lib_kmp_timer_timeout timeout);
bool ws_pae_lib_supp_timer_update(void *instance, supp_entry_t *entry, uint16_t ticks, ws_pae_lib_kmp_timer_timeout timeout);
/**
* ws_pae_lib_supp_init initiates supplicant entry
@ -304,24 +326,34 @@ void ws_pae_lib_supp_list_to_active(supp_list_t *active_supp_list, supp_list_t *
/**
* ws_pae_lib_supp_list_to_inactive move supplicant to inactive supplicants list
*
* \param instance Instance
* \param active_supp_list list of active supplicants
* \param inactive_supp_list list of inactive supplicants
* \param entry supplicant entry
*
*/
void ws_pae_lib_supp_list_to_inactive(supp_list_t *active_supp_list, supp_list_t *inactive_supp_list, supp_entry_t *entry);
void ws_pae_lib_supp_list_to_inactive(void *instance, supp_list_t *active_supp_list, supp_entry_t *entry);
/**
* ws_pae_lib_supp_list_purge purge inactive supplicants list
*
* \param active_supp_list list of active supplicants
* \param inactive_supp_list list of inactive supplicants
* \param max_number maximum number of supplicant entries, can be set to 0 in combination with max_purge
* to free list entries even when maximum number supplicant entries has not been reached
* \param max_purge maximum number of supplicants to purge in one call, 0 means not limited
*
*/
void ws_pae_lib_supp_list_purge(supp_list_t *active_supp_list, supp_list_t *inactive_supp_list, uint16_t max_number, uint8_t max_purge);
void ws_pae_lib_supp_list_purge(supp_list_t *active_supp_list, uint16_t max_number, uint8_t max_purge);
/**
* ws_pae_lib_supp_list_limit_reached_check check if active supplicant list limit has been reached
*
* \param active_supp_list list of active supplicants
* \param max_number maximum number of supplicant entries
*
* \return true limit has been reached
* \return false limit has not been reached
*/
bool ws_pae_lib_supp_list_active_limit_reached(supp_list_t *active_supp_list, uint16_t max_number);
/**
* ws_pae_lib_supp_list_kmp_count counts the number of KMPs of a certain type in a list of supplicants

View File

@ -24,38 +24,50 @@
#include "common_functions.h"
#include "6LoWPAN/ws/ws_config.h"
#include "ns_file_system.h"
#include "NWK_INTERFACE/Include/protocol.h"
#include "Service_Libs/utils/ns_file.h"
#include "Security/protocols/sec_prot_certs.h"
#include "Security/protocols/sec_prot_keys.h"
#include "6LoWPAN/ws/ws_pae_nvm_store.h"
#include "6LoWPAN/ws/ws_pae_nvm_data.h"
#include "6LoWPAN/ws/ws_pae_controller.h"
#include "6LoWPAN/ws/ws_pae_time.h"
#ifdef HAVE_WS
#define TRACE_GROUP "wsnv"
#define PAE_NVM_NW_INFO_TAG 1
#define PAE_NVM_KEYS_TAG 2
#define PAE_NVM_FRAME_COUNTER_TAG 3
// pan_id (2) + network name (33) + (GTK set (1) + GTK lifetime (4) + GTK (16)) * 4
#define PAE_NVM_NW_INFO_LEN 2 + 33 + (1 + 4 + GTK_LEN) * GTK_NUM
// PTK EUI-64 set (1) + PTK EUI-64 (8) + PMK set (1) + PMK (32) + PMK replay counter (8) + PTK set (1) + PTK (48)
#define PAE_NVM_KEYS_LEN 1 + 8 + 1 + PMK_LEN + 8 + 1 + PTK_LEN
// (frame counter set (1) + GTK (16) + frame counter (4)) * 4
#define PAE_NVM_FRAME_COUNTER_LEN (1 + GTK_LEN + 4) * GTK_NUM
#define PAE_NVM_FIELD_NOT_SET 0 // Field is not present
#define PAE_NVM_FIELD_SET 1 // Field is present
nvm_tlv_entry_t *ws_pae_buffer_allocate(void)
void ws_pae_nvm_store_generic_tlv_create(nvm_tlv_t *tlv_entry, uint16_t tag, uint16_t length)
{
//Allocate worts case buffer
return ns_dyn_mem_temporary_alloc(sizeof(nvm_tlv_entry_t) + PAE_NVM_NW_INFO_LEN);
tlv_entry->tag = tag;
tlv_entry->len = length;
}
void ws_pae_nvm_store_nw_info_tlv_create(nvm_tlv_entry_t *tlv_entry, uint16_t pan_id, char *nw_name, sec_prot_gtk_keys_t *gtks)
nvm_tlv_t *ws_pae_nvm_store_generic_tlv_allocate_and_create(uint16_t tag, uint16_t length)
{
nvm_tlv_t *tlv_entry = ns_dyn_mem_alloc(length + sizeof(nvm_tlv_t));
if (!tlv_entry) {
return NULL;
}
tlv_entry->tag = tag;
tlv_entry->len = length;
return tlv_entry;
}
void ws_pae_nvm_store_generic_tlv_free(nvm_tlv_t *tlv_entry)
{
if (!tlv_entry) {
return;
}
ns_dyn_mem_free(tlv_entry);
}
void ws_pae_nvm_store_nw_info_tlv_create(nvm_tlv_t *tlv_entry, uint16_t pan_id, char *nw_name, sec_prot_gtk_keys_t *gtks)
{
int len;
tlv_entry->tag = PAE_NVM_NW_INFO_TAG;
@ -75,19 +87,31 @@ void ws_pae_nvm_store_nw_info_tlv_create(nvm_tlv_entry_t *tlv_entry, uint16_t pa
memcpy((char *)tlv, nw_name, len);
tlv += 33;
uint64_t current_time = ws_pae_current_time_get();
for (uint8_t i = 0; i < GTK_NUM; i++) {
if (sec_prot_keys_gtk_is_set(gtks, i)) {
if (gtks && sec_prot_keys_gtk_is_set(gtks, i)) {
*tlv++ = PAE_NVM_FIELD_SET; // GTK is set
uint32_t lifetime = sec_prot_keys_gtk_lifetime_get(gtks, i);
tlv = common_write_32_bit(lifetime, tlv);
uint64_t expirytime = sec_prot_keys_gtk_exptime_from_lifetime_get(gtks, i, current_time);
// Sets stored expiration time to GTKs; no need to update anymore to NVM if not changed
sec_prot_keys_gtk_expirytime_set(gtks, i, expirytime);
tlv = common_write_64_bit(expirytime, tlv);
uint8_t status = sec_prot_keys_gtk_status_get(gtks, i);
*tlv++ = status;
uint8_t install_order = sec_prot_keys_gtk_install_order_get(gtks, i);
*tlv++ = install_order;
uint8_t *gtk = sec_prot_keys_gtk_get(gtks, i);
memcpy(tlv, gtk, GTK_LEN);
tlv += GTK_LEN;
} else {
*tlv++ = PAE_NVM_FIELD_NOT_SET; // GTK is not set
memset(tlv, 0, 4 + GTK_LEN);
tlv += 4 + GTK_LEN;
memset(tlv, 0, 8 + 1 + 1 + GTK_LEN);
tlv += 8 + 1 + 1 + GTK_LEN;
}
}
@ -95,9 +119,9 @@ void ws_pae_nvm_store_nw_info_tlv_create(nvm_tlv_entry_t *tlv_entry, uint16_t pa
}
int8_t ws_pae_nvm_store_nw_info_tlv_read(nvm_tlv_entry_t *tlv_entry, uint16_t *pan_id, char *nw_name, sec_prot_gtk_keys_t *gtks)
int8_t ws_pae_nvm_store_nw_info_tlv_read(nvm_tlv_t *tlv_entry, uint16_t *pan_id, char *nw_name, sec_prot_gtk_keys_t *gtks)
{
if (!tlv_entry || !pan_id || !nw_name || !gtks) {
if (!tlv_entry || !pan_id || !nw_name) {
return -1;
}
@ -107,31 +131,60 @@ int8_t ws_pae_nvm_store_nw_info_tlv_read(nvm_tlv_entry_t *tlv_entry, uint16_t *p
uint8_t *tlv = ((uint8_t *) &tlv_entry->tag) + NVM_TLV_FIXED_LEN;
*pan_id = common_read_16_bit(tlv);
if (*pan_id == 0xffff) {
// If application has not set pan_id read it from NVM
*pan_id = common_read_16_bit(tlv);
}
tlv += 2;
memset(nw_name, 0, 33);
strncpy(nw_name, (char *) tlv, 32);
if (strlen(nw_name) == 0) {
// If application has not set network name read it from NVM
memset(nw_name, 0, 33);
strncpy(nw_name, (char *) tlv, 32);
}
tlv += 33;
for (uint8_t i = 0; i < GTK_NUM; i++) {
if (*tlv++ == PAE_NVM_FIELD_SET) { /* GTK is set */
uint32_t lifetime = common_read_32_bit(tlv);
tlv += 4;
sec_prot_keys_gtk_set(gtks, i, tlv, lifetime);
tlv += GTK_LEN;
} else {
tlv += 4 + GTK_LEN;
uint64_t current_time = ws_pae_current_time_get();
tr_debug("NVM NW_INFO current time: %"PRIi64, current_time);
if (gtks && sec_prot_keys_gtk_count(gtks) == 0) {
// If application has not set GTKs read them from NVM
for (uint8_t i = 0; i < GTK_NUM; i++) {
if (*tlv++ == PAE_NVM_FIELD_SET) { /* GTK is set */
uint64_t expirytime = common_read_64_bit(tlv);
uint32_t lifetime = 0;
if (ws_pae_time_diff_calc(current_time, expirytime, &lifetime, true) < 0) {
tlv += 8 + 1 + 1 + GTK_LEN;
tr_debug("GTK index %i, expired expiry time: %"PRIi64", lifetime: %"PRIi32, i, expirytime, lifetime);
continue;
}
tlv += 8;
uint8_t status = *tlv++;
uint8_t install_order = *tlv++;
tr_debug("GTK index: %i, status: %i, install order %i, expiry time: %"PRIi64", lifetime: %"PRIi32, i, status, install_order, expirytime, lifetime);
sec_prot_keys_gtk_set(gtks, i, tlv, lifetime);
sec_prot_keys_gtk_expirytime_set(gtks, i, expirytime);
tlv += GTK_LEN;
sec_prot_keys_gtk_status_set(gtks, i, status);
sec_prot_keys_gtk_install_order_set(gtks, i, install_order);
} else {
tlv += 8 + 1 + 1 + GTK_LEN;
}
}
sec_prot_keys_gtks_updated_reset(gtks);
}
sec_prot_keys_gtks_updated_reset(gtks);
tr_debug("NVM NW_INFO read PAN ID %i name: %s", *pan_id, nw_name);
return 0;
}
void ws_pae_nvm_store_keys_tlv_create(nvm_tlv_entry_t *tlv_entry, sec_prot_keys_t *sec_keys)
void ws_pae_nvm_store_keys_tlv_create(nvm_tlv_t *tlv_entry, sec_prot_keys_t *sec_keys)
{
tlv_entry->tag = PAE_NVM_KEYS_TAG;
tlv_entry->len = PAE_NVM_KEYS_LEN;
@ -151,10 +204,12 @@ void ws_pae_nvm_store_keys_tlv_create(nvm_tlv_entry_t *tlv_entry, sec_prot_keys_
uint8_t *pmk = sec_prot_keys_pmk_get(sec_keys);
if (pmk) {
*tlv++ = PAE_NVM_FIELD_SET;
uint32_t lifetime = sec_prot_keys_pmk_lifetime_get(sec_keys);
tlv = common_write_32_bit(lifetime, tlv);
memcpy(tlv, pmk, PMK_LEN);
} else {
*tlv++ = PAE_NVM_FIELD_NOT_SET;
memset(tlv, 0, PMK_LEN);
memset(tlv, 0, 4 + PMK_LEN);
}
tlv += PMK_LEN;
@ -164,18 +219,19 @@ void ws_pae_nvm_store_keys_tlv_create(nvm_tlv_entry_t *tlv_entry, sec_prot_keys_
uint8_t *ptk = sec_prot_keys_ptk_get(sec_keys);
if (ptk) {
*tlv++ = PAE_NVM_FIELD_SET;
uint32_t lifetime = sec_prot_keys_ptk_lifetime_get(sec_keys);
tlv = common_write_32_bit(lifetime, tlv);
memcpy(tlv, ptk, PTK_LEN);
} else {
*tlv++ = PAE_NVM_FIELD_NOT_SET;
memset(tlv, 0, PTK_LEN);
memset(tlv, 0, 4 + PTK_LEN);
}
tlv += PTK_LEN;
tr_debug("NVM KEYS write");
}
int8_t ws_pae_nvm_store_keys_tlv_read(nvm_tlv_entry_t *tlv_entry, sec_prot_keys_t *sec_keys)
int8_t ws_pae_nvm_store_keys_tlv_read(nvm_tlv_t *tlv_entry, sec_prot_keys_t *sec_keys)
{
if (!tlv_entry || !sec_keys) {
return -1;
@ -195,7 +251,11 @@ int8_t ws_pae_nvm_store_keys_tlv_read(nvm_tlv_entry_t *tlv_entry, sec_prot_keys_
// PMK set
if (*tlv++ == PAE_NVM_FIELD_SET) {
sec_prot_keys_pmk_write(sec_keys, tlv);
uint32_t lifetime = common_read_32_bit(tlv);
tlv += 4;
sec_prot_keys_pmk_write(sec_keys, tlv, lifetime);
} else {
tlv += 4;
}
tlv += PMK_LEN;
@ -205,7 +265,11 @@ int8_t ws_pae_nvm_store_keys_tlv_read(nvm_tlv_entry_t *tlv_entry, sec_prot_keys_
// PTK set
if (*tlv++ == PAE_NVM_FIELD_SET) {
sec_prot_keys_ptk_write(sec_keys, tlv);
uint32_t lifetime = common_read_32_bit(tlv);
tlv += 4;
sec_prot_keys_ptk_write(sec_keys, tlv, lifetime);
} else {
tlv += 4;
}
tlv += PTK_LEN;
@ -217,13 +281,18 @@ int8_t ws_pae_nvm_store_keys_tlv_read(nvm_tlv_entry_t *tlv_entry, sec_prot_keys_
return 0;
}
void ws_pae_nvm_store_frame_counter_tlv_create(nvm_tlv_entry_t *tlv_entry, frame_counters_t *counters)
void ws_pae_nvm_store_frame_counter_tlv_create(nvm_tlv_t *tlv_entry, uint32_t restart_cnt, frame_counters_t *counters)
{
tlv_entry->tag = PAE_NVM_FRAME_COUNTER_TAG;
tlv_entry->len = PAE_NVM_FRAME_COUNTER_LEN;
uint8_t *tlv = ((uint8_t *) &tlv_entry->tag) + NVM_TLV_FIXED_LEN;
tlv = common_write_32_bit(restart_cnt, tlv);
uint64_t stored_time = ws_pae_current_time_get();
tlv = common_write_64_bit(stored_time, tlv);
for (uint8_t index = 0; index < GTK_NUM; index++) {
if (!counters->counter[index].set) {
*tlv++ = PAE_NVM_FIELD_NOT_SET;
@ -240,7 +309,7 @@ void ws_pae_nvm_store_frame_counter_tlv_create(nvm_tlv_entry_t *tlv_entry, frame
tr_debug("NVM FRAME COUNTER write");
}
int8_t ws_pae_nvm_store_frame_counter_tlv_read(nvm_tlv_entry_t *tlv_entry, frame_counters_t *counters)
int8_t ws_pae_nvm_store_frame_counter_tlv_read(nvm_tlv_t *tlv_entry, uint32_t *restart_cnt, uint64_t *stored_time, frame_counters_t *counters)
{
if (!tlv_entry || !counters) {
return -1;
@ -252,6 +321,12 @@ int8_t ws_pae_nvm_store_frame_counter_tlv_read(nvm_tlv_entry_t *tlv_entry, frame
uint8_t *tlv = ((uint8_t *) &tlv_entry->tag) + NVM_TLV_FIXED_LEN;
*restart_cnt = common_read_32_bit(tlv);
tlv += 4;
*stored_time = common_read_64_bit(tlv);
tlv += 8;
for (uint8_t index = 0; index < GTK_NUM; index++) {
// Frame counter not set
if (*tlv++ == PAE_NVM_FIELD_NOT_SET) {
@ -272,5 +347,61 @@ int8_t ws_pae_nvm_store_frame_counter_tlv_read(nvm_tlv_entry_t *tlv_entry, frame
return 0;
}
void ws_pae_nvm_store_key_storage_index_tlv_create(nvm_tlv_t *tlv_entry, uint64_t bitfield)
{
tlv_entry->tag = PAE_NVM_KEY_STORAGE_INDEX_TAG;
tlv_entry->len = PAE_NVM_KEY_STORAGE_INDEX_LEN;
uint8_t *tlv = ((uint8_t *) &tlv_entry->tag) + NVM_TLV_FIXED_LEN;
tlv = common_write_64_bit(bitfield, tlv);
tr_debug("NVM KEY STORAGE INDEX write");
}
int8_t ws_pae_nvm_store_key_storage_index_tlv_read(nvm_tlv_t *tlv_entry, uint64_t *bitfield)
{
if (!tlv_entry || !bitfield) {
return -1;
}
if (tlv_entry->tag != PAE_NVM_KEY_STORAGE_INDEX_TAG || tlv_entry->len != PAE_NVM_KEY_STORAGE_INDEX_LEN) {
return -1;
}
uint8_t *tlv = ((uint8_t *) &tlv_entry->tag) + NVM_TLV_FIXED_LEN;
*bitfield = common_read_64_bit(tlv);
tlv += 8;
tr_debug("NVM KEY STORAGE INDEX read");
return 0;
}
void ws_pae_nvm_store_key_storage_tlv_create(nvm_tlv_t *tlv_entry, uint16_t length)
{
memset(tlv_entry, 0, sizeof(key_storage_nvm_tlv_entry_t));
tlv_entry->tag = PAE_NVM_KEY_STORAGE_TAG;
tlv_entry->len = length - sizeof(nvm_tlv_t);
tr_debug("NVM KEY STORAGE create");
}
int8_t ws_pae_nvm_store_key_storage_tlv_read(nvm_tlv_t *tlv_entry, uint16_t length)
{
if (!tlv_entry || !length) {
return -1;
}
if (tlv_entry->tag != PAE_NVM_KEY_STORAGE_TAG || tlv_entry->len != length - sizeof(nvm_tlv_t)) {
return -1;
}
tr_debug("NVM KEY STORAGE read");
return 0;
}
#endif /* HAVE_WS */

View File

@ -24,10 +24,52 @@
*
*/
// file names
#define NW_INFO_FILE_NAME "pae_nw_info"
#define KEYS_FILE_NAME "pae_keys"
#define FRAME_COUNTER_FILE_NAME "pae_frame_counter"
#define PAE_NVM_NW_INFO_TAG 1
#define PAE_NVM_KEYS_TAG 2
#define PAE_NVM_FRAME_COUNTER_TAG 3
#define PAE_NVM_KEY_STORAGE_INDEX_TAG 4
#define PAE_NVM_KEY_STORAGE_TAG 5
// pan_id (2) + network name (33) + (GTK set (1) + GTK expiry timestamp (8) + status (1) + install order (1) + GTK (16)) * 4
#define PAE_NVM_NW_INFO_LEN 2 + 33 + (1 + 8 + 1 + 1 + GTK_LEN) * GTK_NUM
// PTK EUI-64 set (1) + PTK EUI-64 (8) + PMK set (1) + PMK lifetime (4) + PMK (32) + PMK replay counter (8) + PTK set (1) + PTK lifetime (4) + PTK (48)
#define PAE_NVM_KEYS_LEN 1 + 8 + 1 + 4 + PMK_LEN + 8 + 1 + 4 + PTK_LEN
// restart counter + stored time + (frame counter set (1) + GTK (16) + frame counter (4)) * 4
#define PAE_NVM_FRAME_COUNTER_LEN 4 + 8 + (1 + GTK_LEN + 4) * GTK_NUM
#define PAE_NVM_DEFAULT_BUFFER_SIZE sizeof(nvm_tlv_t) + PAE_NVM_NW_INFO_LEN
// key storage index bitfield (8)
#define PAE_NVM_KEY_STORAGE_INDEX_LEN 8
/**
* ws_pae_nvm_store_generic_tlv_create create NVM generic storage TLV
*
* \param tlv_entry TLV entry
* \param tag tag
* \param length length of the (whole) entry
*
* \return < 0 failure
* \return >= 0 success
*
*/
void ws_pae_nvm_store_generic_tlv_create(nvm_tlv_t *tlv_entry, uint16_t tag, uint16_t length);
nvm_tlv_t *ws_pae_nvm_store_generic_tlv_allocate_and_create(uint16_t tag, uint16_t length);
void ws_pae_nvm_store_generic_tlv_free(nvm_tlv_t *tlv_entry);
/**
* ws_pae_nvm_store_nw_info_tlv_create create NVM network info TLV
*
* \param tlv_entry TLV entry pointer
* \param tlv_entry TLV
* \param pan_id PAN ID
* \param nw_name network name
* \param gtks GTK keys
@ -35,12 +77,12 @@
* \return TLV entry or NULL
*
*/
void ws_pae_nvm_store_nw_info_tlv_create(nvm_tlv_entry_t *tlv_entry, uint16_t pan_id, char *nw_name, sec_prot_gtk_keys_t *gtks);
void ws_pae_nvm_store_nw_info_tlv_create(nvm_tlv_t *tlv_entry, uint16_t pan_id, char *nw_name, sec_prot_gtk_keys_t *gtks);
/**
* ws_pae_nvm_store_nw_info_tlv_read read from NVM network info TLV
*
* \param tlv_entry TLV entry
* \param tlv_entry TLV
* \param pan_id PAN ID
* \param nw_name network name
* \param gtks GTK keys
@ -49,50 +91,101 @@ void ws_pae_nvm_store_nw_info_tlv_create(nvm_tlv_entry_t *tlv_entry, uint16_t pa
* \return >= 0 success
*
*/
int8_t ws_pae_nvm_store_nw_info_tlv_read(nvm_tlv_entry_t *tlv_entry, uint16_t *pan_id, char *nw_name, sec_prot_gtk_keys_t *gtks);
int8_t ws_pae_nvm_store_nw_info_tlv_read(nvm_tlv_t *tlv_entry, uint16_t *pan_id, char *nw_name, sec_prot_gtk_keys_t *gtks);
/**
* ws_pae_nvm_store_keys_tlv_create create NVM keys TLV
*
* \param tlv_entry TLV entry buffer pointer
* \param tlv_entry TLV
* \param sec_keys security keys
*
*/
void ws_pae_nvm_store_keys_tlv_create(nvm_tlv_entry_t *tlv_entry, sec_prot_keys_t *sec_keys);
void ws_pae_nvm_store_keys_tlv_create(nvm_tlv_t *tlv_entry, sec_prot_keys_t *sec_keys);
/**
* ws_pae_nvm_store_nw_info_tlv_read read from NVM keys TLV
*
* \param tlv_entry TLV entry
* \param tlv_entry TLV
* \param sec_keys security keys
*
* \return < 0 failure
* \return >= 0 success
*
*/
int8_t ws_pae_nvm_store_keys_tlv_read(nvm_tlv_entry_t *tlv_entry, sec_prot_keys_t *sec_keys);
int8_t ws_pae_nvm_store_keys_tlv_read(nvm_tlv_t *tlv_entry, sec_prot_keys_t *sec_keys);
/**
* ws_pae_nvm_store_frame_counter_tlv_create create NVM frame counter TLV
*
* \param tlv_entry TLV entry buffer pointer
* \param tlv_entry TLV buffer pointer
* \param restart_cnt re-start counter
* \param counters frame counters
*
*/
void ws_pae_nvm_store_frame_counter_tlv_create(nvm_tlv_entry_t *tlv_entry, frame_counters_t *counters);
void ws_pae_nvm_store_frame_counter_tlv_create(nvm_tlv_t *tlv_entry, uint32_t restart_cnt, frame_counters_t *counters);
/**
* ws_pae_nvm_store_frame_counter_tlv_read read from NVM frame counter TLV
*
* \param tlv_entry TLV entry
* \param tlv_entry TLV
* \param restart_cnt re-start counter
* \param stored_time stored timestampt
* \param counters frame counters
*
* \return < 0 failure
* \return >= 0 success
*
*/
int8_t ws_pae_nvm_store_frame_counter_tlv_read(nvm_tlv_entry_t *tlv_entry, frame_counters_t *counters);
int8_t ws_pae_nvm_store_frame_counter_tlv_read(nvm_tlv_t *tlv_entry, uint32_t *restart_cnt, uint64_t *stored_time, frame_counters_t *counters);
nvm_tlv_entry_t *ws_pae_buffer_allocate(void);
/**
* ws_pae_nvm_store_key_storage_index_tlv_create create NVM key storage index TLV
*
* \param tlv_entry TLV entry
* \param bitfield index of filenames
*
* \return < 0 failure
* \return >= 0 success
*
*/
void ws_pae_nvm_store_key_storage_index_tlv_create(nvm_tlv_t *tlv_entry, uint64_t bitfield);
/**
* ws_pae_nvm_store_key_storage_index_tlv_read read NVM key storage index TLV
*
* \param tlv_entry TLV entry
* \param bitfield index of filenames
*
* \return < 0 failure
* \return >= 0 success
*
*/
int8_t ws_pae_nvm_store_key_storage_index_tlv_read(nvm_tlv_t *tlv_entry, uint64_t *bitfield);
/**
* ws_pae_nvm_store_key_storage_tlv_create create NVM key storage TLV
*
* \param tlv_entry TLV entry
* \param length length of the (whole) entry
*
* \return < 0 failure
* \return >= 0 success
*
*/
void ws_pae_nvm_store_key_storage_tlv_create(nvm_tlv_t *tlv_entry, uint16_t length);
/**
* ws_pae_nvm_store_key_storage_tlv_read read NVM key storage TLV
*
* \param tlv_entry TLV entry
* \param length length of the (whole) entry
*
* \return < 0 failure
* \return >= 0 success
*
*/
int8_t ws_pae_nvm_store_key_storage_tlv_read(nvm_tlv_t *tlv_entry, uint16_t length);
nvm_tlv_t *ws_pae_buffer_allocate(void);
#endif /* WS_PAE_NVM_DATA_H_ */

View File

@ -17,7 +17,6 @@
#include "nsconfig.h"
#include <string.h>
#include <stdio.h>
#include "ns_types.h"
#include "ns_list.h"
#include "ns_trace.h"
@ -25,9 +24,11 @@
#include "common_functions.h"
#include "6LoWPAN/ws/ws_config.h"
#include "ns_file_system.h"
#include "Service_Libs/utils/ns_file.h"
#include "Security/protocols/sec_prot_certs.h"
#include "Security/protocols/sec_prot_keys.h"
#include "6LoWPAN/ws/ws_pae_nvm_store.h"
#include "ns_file_system.h"
#ifdef HAVE_WS
@ -39,10 +40,10 @@ static uint16_t ws_pae_nvm_store_path_len_get(const char *file_name);
static const char *ws_pae_nvm_store_get_root_path(void);
static int8_t ws_pae_nvm_store_root_path_valid(void);
static int8_t ws_pae_nvm_store_create_path(char *fast_data_path, const char *file_name);
static int8_t ws_pae_nvm_store_write(const char *file_name, nvm_tlv_list_t *tlv_list);
static int8_t ws_pae_nvm_store_read(const char *file_name, nvm_tlv_list_t *tlv_list);
static int8_t ws_pae_nvm_store_write(const char *file_name, nvm_tlv_t *tlv);
static int8_t ws_pae_nvm_store_read(const char *file_name, nvm_tlv_t *tlv);
int8_t ws_pae_nvm_store_tlv_file_write(const char *file, nvm_tlv_list_t *tlv_list)
int8_t ws_pae_nvm_store_tlv_file_write(const char *file, nvm_tlv_t *tlv)
{
if (!ws_pae_nvm_store_root_path_valid()) {
return PAE_NVM_FILE_ROOT_PATH_INVALID;
@ -54,10 +55,10 @@ int8_t ws_pae_nvm_store_tlv_file_write(const char *file, nvm_tlv_list_t *tlv_lis
ws_pae_nvm_store_create_path(nw_info_path, file);
return ws_pae_nvm_store_write(nw_info_path, tlv_list);
return ws_pae_nvm_store_write(nw_info_path, tlv);
}
int8_t ws_pae_nvm_store_tlv_file_read(const char *file, nvm_tlv_list_t *tlv_list)
int8_t ws_pae_nvm_store_tlv_file_read(const char *file, nvm_tlv_t *tlv)
{
if (!ws_pae_nvm_store_root_path_valid()) {
return PAE_NVM_FILE_ROOT_PATH_INVALID;
@ -69,7 +70,27 @@ int8_t ws_pae_nvm_store_tlv_file_read(const char *file, nvm_tlv_list_t *tlv_list
ws_pae_nvm_store_create_path(nw_info_path, file);
return ws_pae_nvm_store_read(nw_info_path, tlv_list);
return ws_pae_nvm_store_read(nw_info_path, tlv);
}
int8_t ws_pae_nvm_store_tlv_file_remove(const char *file)
{
if (!ws_pae_nvm_store_root_path_valid()) {
return PAE_NVM_FILE_ROOT_PATH_INVALID;
}
uint16_t path_len = ws_pae_nvm_store_path_len_get(file);
char nw_info_path[path_len];
ws_pae_nvm_store_create_path(nw_info_path, file);
int ret = ns_fremove(nw_info_path);
if (ret < 0) {
return -1;
}
return 0;
}
static const char *ws_pae_nvm_store_get_root_path(void)
@ -106,104 +127,49 @@ static int8_t ws_pae_nvm_store_create_path(char *data_path, const char *file_nam
return 0;
}
static int8_t ws_pae_nvm_store_write(const char *file_name, nvm_tlv_list_t *tlv_list)
static int8_t ws_pae_nvm_store_write(const char *file_name, nvm_tlv_t *tlv)
{
FILE *fp = fopen(file_name, "w");
if (!file_name || !tlv) {
return -1;
}
NS_FILE *fp = ns_fopen(file_name, "w");
if (fp == NULL) {
tr_error("NVM open error: %s", file_name);
return PAE_NVM_FILE_CANNOT_OPEN;
}
uint16_t list_count = ns_list_count(tlv_list);
size_t n_bytes = fwrite(&list_count, 1, sizeof(uint16_t), fp);
if (n_bytes != sizeof(uint16_t)) {
tr_warning("NVM TLV list count write error");
fclose(fp);
return PAE_NVM_FILE_WRITE_ERROR;
}
bool failure = false;
ns_list_foreach(nvm_tlv_entry_t, entry, tlv_list) {
n_bytes = fwrite(&entry->tag, 1, entry->len + NVM_TLV_FIXED_LEN, fp);
if (n_bytes != (size_t) entry->len + NVM_TLV_FIXED_LEN) {
failure = true;
break;
}
}
fclose(fp);
if (failure) {
size_t n_bytes = ns_fwrite(fp, tlv, tlv->len + sizeof(nvm_tlv_t));
ns_fclose(fp);
if (n_bytes != tlv->len + sizeof(nvm_tlv_t)) {
tr_error("NVM write error %s", file_name);
return PAE_NVM_FILE_WRITE_ERROR;
} else {
return PAE_NVM_FILE_SUCCESS;
}
return PAE_NVM_FILE_SUCCESS;
}
static int8_t ws_pae_nvm_store_read(const char *file_name, nvm_tlv_list_t *tlv_list)
static int8_t ws_pae_nvm_store_read(const char *file_name, nvm_tlv_t *tlv)
{
FILE *fp = fopen(file_name, "r");
if (!file_name || !tlv) {
return -1;
}
NS_FILE *fp = ns_fopen(file_name, "r");
if (fp == NULL) {
tr_warning("File not found: %s", file_name);
return PAE_NVM_FILE_CANNOT_OPEN;
}
uint16_t list_count;
size_t n_bytes = fread(&list_count, 1, sizeof(uint16_t), fp);
if (n_bytes != sizeof(uint16_t)) {
tr_warning("NVM TLV list count read error %s", file_name);
fclose(fp);
size_t n_bytes = ns_fread(fp, tlv, tlv->len + sizeof(nvm_tlv_t));
ns_fclose(fp);
if (n_bytes != tlv->len + sizeof(nvm_tlv_t)) {
tr_warning("File not found or cannot be read: %s", file_name);
return PAE_NVM_FILE_READ_ERROR;
}
bool failure = false;
while (list_count-- > 0) {
nvm_tlv_entry_t entry_header;
memset(&entry_header, 0, sizeof(nvm_tlv_entry_t));
n_bytes = fread(&entry_header.tag, 1, NVM_TLV_FIXED_LEN, fp);
if (n_bytes != NVM_TLV_FIXED_LEN) {
failure = true;
break;
}
uint16_t len = entry_header.len;
nvm_tlv_entry_t *entry = ns_dyn_mem_temporary_alloc(sizeof(nvm_tlv_entry_t) + len);
if (!entry) {
failure = true;
break;
}
memcpy(&entry->tag, &entry_header.tag, NVM_TLV_FIXED_LEN);
if (len > 0) {
uint8_t *data_ptr = ((uint8_t *)&entry->tag) + NVM_TLV_FIXED_LEN;
n_bytes = fread(data_ptr, 1, len, fp);
if (n_bytes != len) {
ns_dyn_mem_free(entry);
failure = true;
break;
}
}
ns_list_add_to_end(tlv_list, entry);
}
fclose(fp);
if (failure) {
ns_list_foreach_safe(nvm_tlv_entry_t, entry, tlv_list) {
ns_list_remove(tlv_list, entry);
ns_dyn_mem_free(entry);
}
tr_error("NVM read error %s", file_name);
return PAE_NVM_FILE_READ_ERROR;
} else {
return PAE_NVM_FILE_SUCCESS; // return how many bytes was written.
}
return PAE_NVM_FILE_SUCCESS;
}
#endif /* HAVE_WS */

View File

@ -24,22 +24,6 @@
*
*/
// tag + length
#define NVM_TLV_FIXED_LEN 4
// file names
#define NW_INFO_FILE_NAME "pae_nw_info"
#define KEYS_FILE_NAME "pae_keys"
#define FRAME_COUNTER_FILE_NAME "pae_frame_counter"
typedef struct nvm_tlv_entry {
ns_list_link_t link; /**< Link */
uint16_t tag; /**< Unique tag */
uint16_t len; /**< Number of the bytes after the length field */
} nvm_tlv_entry_t;
typedef NS_LIST_HEAD(nvm_tlv_entry_t, link) nvm_tlv_list_t;
#define PAE_NVM_FILE_SUCCESS 0
#define PAE_NVM_FILE_READ_ERROR -1
#define PAE_NVM_FILE_WRITE_ERROR -2
@ -49,28 +33,53 @@ typedef NS_LIST_HEAD(nvm_tlv_entry_t, link) nvm_tlv_list_t;
#define PAE_NVM_FILE_PARAMETER_INVALID -6
#define PAE_NVM_FILE_REMOVE_ERROR -7
typedef struct nvm_tlv {
uint16_t tag; /**< Unique tag */
uint16_t len; /**< Number of the bytes after the length field */
} nvm_tlv_t;
typedef struct {
nvm_tlv_t nvm_tlv; /**< NVM TLV */
uint64_t reference_time; /**< Reference time used for timers (set when file is created) */
uint32_t reference_restart_cnt; /**< Reference re-start counter set when file is created) */
} key_storage_nvm_tlv_entry_t;
// tag + length
#define NVM_TLV_FIXED_LEN sizeof(nvm_tlv_t)
/**
* ws_pae_nvm_store_tlv_file_write write a list of TLVs to file
*
* \param file file name
* \param tlv_list TLV list
* \param tlv TLV
*
* \return < 0 failure
* \return >= 0 success
*
*/
int8_t ws_pae_nvm_store_tlv_file_write(const char *file, nvm_tlv_list_t *tlv_list);
int8_t ws_pae_nvm_store_tlv_file_write(const char *file, nvm_tlv_t *tlv);
/**
* ws_pae_nvm_store_tlv_file_read read a list of TLVs from file
*
* \param file file name
* \param tlv_list TLV list
* \param tlv TLV
*
* \return < 0 failure
* \return >= 0 success
*
*/
int8_t ws_pae_nvm_store_tlv_file_read(const char *file, nvm_tlv_list_t *tlv_list);
int8_t ws_pae_nvm_store_tlv_file_read(const char *file, nvm_tlv_t *tlv);
/**
* ws_pae_nvm_store_tlv_file_remove delete a file
*
* \param file file name
*
* \return < 0 failure
* \return >= 0 success
*
*/
int8_t ws_pae_nvm_store_tlv_file_remove(const char *file);
#endif /* WS_PAE_NVM_STORE_H_ */

View File

@ -28,6 +28,7 @@
#include "eventOS_scheduler.h"
#include "eventOS_event_timer.h"
#include "ns_address.h"
#include "Service_Libs/utils/ns_file.h"
#include "NWK_INTERFACE/Include/protocol.h"
#include "RPL/rpl_protocol.h"
#include "RPL/rpl_control.h"
@ -48,6 +49,7 @@
#include "6LoWPAN/ws/ws_pae_timers.h"
#include "6LoWPAN/ws/ws_pae_supp.h"
#include "6LoWPAN/ws/ws_pae_lib.h"
#include "6LoWPAN/ws/ws_pae_time.h"
#include "6LoWPAN/ws/ws_pae_nvm_store.h"
#include "6LoWPAN/ws/ws_pae_nvm_data.h"
#include "6LoWPAN/MAC/mpx_api.h"
@ -79,31 +81,25 @@
#define INITIAL_KEY_TIMER_MIN 3
#define INITIAL_KEY_TIMER_MAX 30
typedef struct {
char network_name[33]; /**< Network name for keys */
sec_prot_gtk_keys_t *gtks; /**< Link to GTKs */
uint16_t new_pan_id; /**< new PAN ID indicated by bootstrap */
uint16_t key_pan_id; /**< PAN ID for keys */
bool updated : 1; /**< Network info has been updated */
} sec_prot_keys_nw_info_t;
typedef struct {
ns_list_link_t link; /**< Link */
kmp_service_t *kmp_service; /**< KMP service */
protocol_interface_info_entry_t *interface_ptr; /**< Interface */
ws_pae_supp_auth_completed *auth_completed; /**< Authentication completed callback, continue bootstrap */
ws_pae_supp_auth_next_target *auth_next_target; /**< Authentication next target callback */
ws_pae_supp_nw_key_insert *nw_key_insert; /**< Key insert callback */
ws_pae_supp_nw_key_index_set *nw_key_index_set; /**< Key index set callback */
ws_pae_supp_gtk_hash_ptr_get *gtk_hash_ptr_get; /**< Get pointer to GTK hash storage callback */
ws_pae_supp_nw_info_updated *nw_info_updated; /**< Security keys network info updated callback */
supp_entry_t entry; /**< Supplicant data */
kmp_addr_t target_addr; /**< EAPOL target (parent) address */
uint16_t initial_key_timer; /**< Timer to trigger initial EAPOL-Key */
uint16_t initial_key_retry_timer; /**< Timer to trigger initial EAPOL-Key 1st retry */
trickle_t auth_trickle_timer; /**< Trickle timer for re-sending initial EAPOL-key or for GTK mismatch */
trickle_params_t auth_trickle_params; /**< Trickle parameters for initial EAPOL-key or for GTK mismatch */
sec_prot_gtk_keys_t gtks; /**< GTKs */
uint8_t new_br_eui_64[8]; /**< Border router EUI-64 indicated by bootstrap */
sec_prot_keys_nw_info_t sec_keys_nw_info; /**< Security keys network information */
uint8_t new_br_eui_64[8]; /**< Border router EUI-64 indicated by bootstrap after bootstrap start */
uint8_t comp_br_eui_64[8]; /**< Border router EUI-64 indicated by bootstrap after bootstrap completed */
sec_prot_keys_nw_info_t *sec_keys_nw_info; /**< Security keys network information */
sec_timer_cfg_t *sec_timer_cfg; /**< Timer configuration */
sec_prot_cfg_t *sec_prot_cfg; /**< Protocol Configuration */
uint8_t nw_keys_used_cnt; /**< How many times bootstrap has been tried with current keys */
@ -111,47 +107,26 @@ typedef struct {
bool auth_trickle_running : 1; /**< Initial EAPOL-Key Trickle timer running */
bool auth_requested : 1; /**< Authentication has been requested by the bootstrap */
bool timer_running : 1; /**< Timer is running */
bool new_br_eui_64_set : 1; /**< Border router address has been set */
bool new_br_eui_64_set : 1; /**< Border router address has been set after bootstrap start */
bool new_br_eui_64_fresh : 1; /**< Border router address is fresh (set during this authentication attempt) */
bool entry_address_active: 1;
bool comp_br_eui_64_set : 1; /**< Border router address has been set after bootstrap completed */
bool entry_address_active: 1; /**< EAPOL target address is set */
bool tx_failure_on_initial_key: 1; /**< TX failure has happened on initial EAPOL-key sequence */
} pae_supp_t;
// How many times sending of initial EAPOL-key is retried
#define INITIAL_KEY_RETRY_COUNT 2
// How many times sending of initial EAPOL-key is initiated on key update
#define KEY_UPDATE_RETRY_COUNT 3
#define LIFETIME_MISMATCH_RETRY_COUNT 1 /* No retries */
// How long the wait is before the first initial EAPOL-key retry
#define DEFAULT_INITIAL_KEY_RETRY_TIMER 120
#define NONE_INITIAL_KEY_RETRY_TIMER 0
// Default trickle values for sending of initial EAPOL-key
#define DEFAULT_TRICKLE_IMIN_SECS 360 /* 6 to 12 minutes */
#define DEFAULT_TRICKLE_IMAX_SECS 720
// Very slow network values for sending of initial EAPOL-key
#define VERY_SLOW_NW_TRICKLE_IMIN_SECS 600 /* 10 to 60 minutes */
#define VERY_SLOW_NW_TRICKLE_IMAX_SECS 3600
// Trickle timer on how long to wait response after last retry before failing authentication
#define LAST_INTERVAL_TRICKLE_IMIN_SECS 240 /* 4 minutes */
#define LAST_INTERVAL_TRICKLE_IMAX_SECS 240
static trickle_params_t initial_eapol_key_trickle_params = {
.Imin = DEFAULT_TRICKLE_IMIN_SECS, /* 360 second; ticks are 1 second */
.Imax = DEFAULT_TRICKLE_IMAX_SECS, /* 720 second */
.k = 0, /* infinity - no consistency checking */
.TimerExpirations = 2
};
static void ws_pae_supp_free(pae_supp_t *pae_supp);
static void ws_pae_supp_authenticate_response(pae_supp_t *pae_supp, auth_result_e result);
static int8_t ws_pae_supp_initial_key_send(pae_supp_t *pae_supp);
static void ws_pae_supp_nvm_update(pae_supp_t *pae_supp);
static int8_t ws_pae_supp_nw_keys_valid_check(pae_supp_t *pae_supp, uint16_t pan_id);
static int8_t ws_pae_supp_nvm_nw_info_write(pae_supp_t *pae_supp);
static int8_t ws_pae_supp_nw_keys_valid_check(pae_supp_t *pae_supp, uint16_t pan_id, char *dest_network_name);
static int8_t ws_pae_supp_nvm_keys_write(pae_supp_t *pae_supp);
static pae_supp_t *ws_pae_supp_get(protocol_interface_info_entry_t *interface_ptr);
static int8_t ws_pae_supp_event_send(kmp_service_t *service, void *data);
@ -182,16 +157,15 @@ static void ws_pae_supp_kmp_api_finished(kmp_api_t *kmp);
static const eapol_pdu_recv_cb_data_t eapol_pdu_recv_cb_data = {
.priority = EAPOL_PDU_RECV_HIGH_PRIORITY,
.filter_requsted = false,
.addr_check = ws_pae_supp_eapol_pdu_address_check,
.receive = kmp_eapol_pdu_if_receive
};
static const char *NW_INFO_FILE = NW_INFO_FILE_NAME;
static const char *KEYS_FILE = KEYS_FILE_NAME;
static int8_t tasklet_id = -1;
static NS_LIST_DEFINE(pae_supp_list, pae_supp_t, link);
static uint8_t timing_value = 0; // Timing value set based e.g. on network size
static void ws_pae_supp_address_set(pae_supp_t *pae_supp, kmp_addr_t *address)
{
@ -209,33 +183,35 @@ static bool ws_pae_supp_address_is_set(pae_supp_t *pae_supp)
return pae_supp->entry_address_active;
}
int8_t ws_pae_supp_authenticate(protocol_interface_info_entry_t *interface_ptr, uint16_t dest_pan_id, uint8_t *dest_eui_64)
int8_t ws_pae_supp_authenticate(protocol_interface_info_entry_t *interface_ptr, uint16_t dest_pan_id, uint8_t *dest_eui_64, char *dest_network_name)
{
pae_supp_t *pae_supp = ws_pae_supp_get(interface_ptr);
if (!pae_supp) {
return -1;
}
if (ws_pae_supp_nw_keys_valid_check(pae_supp, dest_pan_id) >= 0) {
if (ws_pae_supp_nw_keys_valid_check(pae_supp, dest_pan_id, dest_network_name) >= 0) {
pae_supp->auth_completed(interface_ptr, AUTH_RESULT_OK, NULL);
return 0;
}
// Delete GTKs
sec_prot_keys_gtks_init(pae_supp->sec_keys_nw_info.gtks);
sec_prot_keys_gtks_init(pae_supp->sec_keys_nw_info->gtks);
/* PAN ID has changed, delete key data associated with border router
/* Network name or PAN ID has changed, delete key data associated with border router
i.e PMK, PTK, EA-IE data (border router EUI-64) */
if (pae_supp->sec_keys_nw_info.key_pan_id != 0xFFFF && pae_supp->sec_keys_nw_info.key_pan_id != dest_pan_id) {
if (strcmp(pae_supp->sec_keys_nw_info->network_name, dest_network_name) != 0 ||
(pae_supp->sec_keys_nw_info->key_pan_id != 0xFFFF && pae_supp->sec_keys_nw_info->key_pan_id != dest_pan_id)) {
sec_prot_keys_pmk_delete(&pae_supp->entry.sec_keys);
sec_prot_keys_ptk_delete(&pae_supp->entry.sec_keys);
sec_prot_keys_ptk_eui_64_delete(&pae_supp->entry.sec_keys);
}
pae_supp->sec_keys_nw_info.key_pan_id = dest_pan_id;
pae_supp->sec_keys_nw_info->key_pan_id = dest_pan_id;
// Prepare to receive new border router address
pae_supp->new_br_eui_64_fresh = false;
pae_supp->comp_br_eui_64_set = false;
// Stores target/parent address
kmp_address_init(KMP_ADDR_EUI_64, &pae_supp->target_addr, dest_eui_64);
@ -255,29 +231,6 @@ int8_t ws_pae_supp_authenticate(protocol_interface_info_entry_t *interface_ptr,
return 1;
}
int8_t ws_pae_supp_nw_info_set(protocol_interface_info_entry_t *interface_ptr, uint16_t pan_id, char *network_name)
{
pae_supp_t *pae_supp = ws_pae_supp_get(interface_ptr);
if (!pae_supp) {
return -1;
}
// PAN ID has been modified
if (pan_id != 0xffff && pan_id != pae_supp->sec_keys_nw_info.new_pan_id) {
pae_supp->sec_keys_nw_info.new_pan_id = pan_id;
pae_supp->sec_keys_nw_info.updated = true;
}
// Network name has been modified
if (network_name && strncmp(pae_supp->sec_keys_nw_info.network_name, network_name, 33) != 0) {
strncpy(pae_supp->sec_keys_nw_info.network_name, network_name, 32);
pae_supp->sec_keys_nw_info.updated = true;
}
return 0;
}
int8_t ws_pae_supp_border_router_addr_write(protocol_interface_info_entry_t *interface_ptr, const uint8_t *eui_64)
{
pae_supp_t *pae_supp = ws_pae_supp_get(interface_ptr);
@ -299,9 +252,14 @@ int8_t ws_pae_supp_border_router_addr_read(protocol_interface_info_entry_t *inte
return -1;
}
// Check if there is border router EUI-64 on used on 4WH PTK generation
uint8_t *br_eui_64 = sec_prot_keys_ptk_eui_64_get(&pae_supp->entry.sec_keys);
if (!br_eui_64) {
return -1;
// Check if there is border router EUI-64 indicated by the bootstrap when bootstrap completed
if (!pae_supp->comp_br_eui_64_set) {
return -1;
}
br_eui_64 = pae_supp->comp_br_eui_64;
}
memcpy(eui_64, br_eui_64, 8);
@ -309,14 +267,31 @@ int8_t ws_pae_supp_border_router_addr_read(protocol_interface_info_entry_t *inte
return 0;
}
int8_t ws_pae_supp_nw_key_valid(protocol_interface_info_entry_t *interface_ptr)
int8_t ws_pae_supp_nw_key_valid(protocol_interface_info_entry_t *interface_ptr, uint8_t *br_iid)
{
pae_supp_t *pae_supp = ws_pae_supp_get(interface_ptr);
if (!pae_supp) {
return -1;
}
tr_info("NW key valid");
tr_info("NW key valid indication");
// Store border router EUI-64 received on bootstrap complete
memcpy(pae_supp->comp_br_eui_64, br_iid, 8);
pae_supp->comp_br_eui_64[0] ^= 0x02;
pae_supp->comp_br_eui_64_set = true;
// Get the EUI-64 used on 4WH handshake PTK generation
uint8_t *ptk_eui_64 = sec_prot_keys_ptk_eui_64_get(&pae_supp->entry.sec_keys);
/* If border router EUI-64 received on bootstrap complete does not match to
EUI-64 stored with keys, delete keys */
if (memcmp(ptk_eui_64, pae_supp->comp_br_eui_64, 8) != 0) {
tr_warn("Delete keys: PTK EUI-64 %s does not match to BR EUI-64 %s", tr_array(ptk_eui_64, 8), tr_array(pae_supp->comp_br_eui_64, 8));
sec_prot_keys_pmk_delete(&pae_supp->entry.sec_keys);
sec_prot_keys_ptk_delete(&pae_supp->entry.sec_keys);
sec_prot_keys_ptk_eui_64_delete(&pae_supp->entry.sec_keys);
}
// Stored keys are valid
pae_supp->nw_keys_used_cnt = 0;
@ -335,7 +310,7 @@ static int8_t ws_pae_supp_gtk_hash_mismatch_check(pae_supp_t *pae_supp)
}
// Check GTK hashes and initiate EAPOL procedure if mismatch is detected */
gtk_mismatch_e mismatch = sec_prot_keys_gtks_hash_update(&pae_supp->gtks, gtkhash);
gtk_mismatch_e mismatch = sec_prot_keys_gtks_hash_update(pae_supp->sec_keys_nw_info->gtks, gtkhash);
if (mismatch != GTK_NO_MISMATCH) {
return -1;
}
@ -352,7 +327,7 @@ int8_t ws_pae_supp_gtk_hash_update(protocol_interface_info_entry_t *interface_pt
}
// Check GTK hashes and initiate EAPOL procedure if mismatch is detected */
gtk_mismatch_e mismatch = sec_prot_keys_gtks_hash_update(&pae_supp->gtks, gtkhash);
gtk_mismatch_e mismatch = sec_prot_keys_gtks_hash_update(pae_supp->sec_keys_nw_info->gtks, gtkhash);
if (mismatch > GTK_NO_MISMATCH) {
tr_info("GTK hash update %s %s %s %s",
trace_array(&gtkhash[0], 8),
@ -379,7 +354,7 @@ int8_t ws_pae_supp_gtk_hash_update(protocol_interface_info_entry_t *interface_pt
}
// Modify keys
pae_supp->nw_key_insert(pae_supp->interface_ptr, pae_supp->sec_keys_nw_info.gtks);
pae_supp->nw_key_insert(pae_supp->interface_ptr, pae_supp->sec_keys_nw_info->gtks);
return 0;
}
@ -391,7 +366,7 @@ int8_t ws_pae_supp_nw_key_index_update(protocol_interface_info_entry_t *interfac
return -1;
}
if (sec_prot_keys_gtk_status_active_set(&pae_supp->gtks, index) >= 0) {
if (sec_prot_keys_gtk_status_active_set(pae_supp->sec_keys_nw_info->gtks, index) >= 0) {
pae_supp->nw_key_index_set(interface_ptr, index);
} else {
tr_info("NW send key index: %i, no changes", index + 1);
@ -407,7 +382,7 @@ int8_t ws_pae_supp_gtks_set(protocol_interface_info_entry_t *interface_ptr, sec_
return -1;
}
pae_supp->gtks = *gtks;
*pae_supp->sec_keys_nw_info->gtks = *gtks;
return 0;
}
@ -427,12 +402,8 @@ int8_t ws_pae_supp_eapol_target_remove(protocol_interface_info_entry_t *interfac
static void ws_pae_supp_nvm_update(pae_supp_t *pae_supp)
{
// Check if NW info or GTKs have been changed
if (pae_supp->sec_keys_nw_info.updated || sec_prot_keys_gtks_are_updated(pae_supp->sec_keys_nw_info.gtks)) {
ws_pae_supp_nvm_nw_info_write(pae_supp);
pae_supp->sec_keys_nw_info.updated = false;
sec_prot_keys_gtks_updated_reset(pae_supp->sec_keys_nw_info.gtks);
}
// Indicate to PAE controller that NW info or GTKs may have been changed
pae_supp->nw_info_updated(pae_supp->interface_ptr);
// Check if pairwise security keys have been changed
if (sec_prot_keys_are_updated(&pae_supp->entry.sec_keys)) {
@ -441,75 +412,30 @@ static void ws_pae_supp_nvm_update(pae_supp_t *pae_supp)
}
}
static int8_t ws_pae_supp_nvm_nw_info_write(pae_supp_t *pae_supp)
{
nvm_tlv_entry_t *tlv_entry = ws_pae_controller_nvm_tlv_get(pae_supp->interface_ptr);
if (!tlv_entry) {
return -1;
}
nvm_tlv_list_t tlv_list;
ns_list_init(&tlv_list);
ws_pae_nvm_store_nw_info_tlv_create(tlv_entry, pae_supp->sec_keys_nw_info.key_pan_id,
pae_supp->sec_keys_nw_info.network_name,
&pae_supp->gtks);
ns_list_add_to_end(&tlv_list, tlv_entry);
ws_pae_nvm_store_tlv_file_write(NW_INFO_FILE, &tlv_list);
return 0;
}
static int8_t ws_pae_supp_nvm_nw_info_read(pae_supp_t *pae_supp)
{
nvm_tlv_list_t tlv_list;
ns_list_init(&tlv_list);
ws_pae_nvm_store_tlv_file_read(NW_INFO_FILE, &tlv_list);
ns_list_foreach_safe(nvm_tlv_entry_t, entry, &tlv_list) {
ws_pae_nvm_store_nw_info_tlv_read(entry, &pae_supp->sec_keys_nw_info.key_pan_id,
pae_supp->sec_keys_nw_info.network_name,
&pae_supp->gtks);
ns_list_remove(&tlv_list, entry);
ns_dyn_mem_free(entry);
}
return 0;
}
static int8_t ws_pae_supp_nvm_keys_write(pae_supp_t *pae_supp)
{
nvm_tlv_entry_t *tlv_entry = ws_pae_controller_nvm_tlv_get(pae_supp->interface_ptr);
if (!tlv_entry) {
nvm_tlv_t *tlv = ws_pae_controller_nvm_tlv_get(pae_supp->interface_ptr);
if (!tlv) {
return -1;
}
nvm_tlv_list_t tlv_list;
ns_list_init(&tlv_list);
ws_pae_nvm_store_keys_tlv_create(tlv_entry, &pae_supp->entry.sec_keys);
ns_list_add_to_end(&tlv_list, tlv_entry);
ws_pae_nvm_store_tlv_file_write(KEYS_FILE, &tlv_list);
ws_pae_nvm_store_keys_tlv_create(tlv, &pae_supp->entry.sec_keys);
ws_pae_nvm_store_tlv_file_write(KEYS_FILE, tlv);
return 0;
}
static int8_t ws_pae_supp_nvm_keys_read(pae_supp_t *pae_supp)
{
nvm_tlv_list_t tlv_list;
ns_list_init(&tlv_list);
ws_pae_nvm_store_tlv_file_read(KEYS_FILE, &tlv_list);
ns_list_foreach_safe(nvm_tlv_entry_t, entry, &tlv_list) {
ws_pae_nvm_store_keys_tlv_read(entry, &pae_supp->entry.sec_keys);
ns_list_remove(&tlv_list, entry);
ns_dyn_mem_free(entry);
nvm_tlv_t *tlv = ws_pae_controller_nvm_tlv_get(pae_supp->interface_ptr);
if (!tlv) {
return -1;
}
ws_pae_nvm_store_generic_tlv_create(tlv, PAE_NVM_KEYS_TAG, PAE_NVM_KEYS_LEN);
if (ws_pae_nvm_store_tlv_file_read(KEYS_FILE_NAME, tlv) < 0) {
return -1;
}
ws_pae_nvm_store_keys_tlv_read(tlv, &pae_supp->entry.sec_keys);
return 0;
}
@ -562,29 +488,31 @@ static int8_t ws_pae_supp_initial_key_send(pae_supp_t *pae_supp)
return 0;
}
static int8_t ws_pae_supp_nw_keys_valid_check(pae_supp_t *pae_supp, uint16_t pan_id)
static int8_t ws_pae_supp_nw_keys_valid_check(pae_supp_t *pae_supp, uint16_t pan_id, char *dest_network_name)
{
// Checks how many times authentication has been tried with current network keys
if (pae_supp->nw_keys_used_cnt >= STORED_KEYS_MAXIMUM_USE_COUNT) {
tr_debug("Keys not valid, delete GTKs");
// Delete GTKs
sec_prot_keys_gtks_init(pae_supp->sec_keys_nw_info.gtks);
sec_prot_keys_gtks_updated_set(pae_supp->sec_keys_nw_info.gtks);
sec_prot_keys_gtks_init(pae_supp->sec_keys_nw_info->gtks);
sec_prot_keys_gtks_updated_set(pae_supp->sec_keys_nw_info->gtks);
ws_pae_supp_nvm_update(pae_supp);
pae_supp->nw_keys_used_cnt = 0;
return -1;
}
/* Checks if keys match to PAN ID and that needed keys exists (PMK, PTK and a GTK),
and calls inserts function that will update the network keys as needed */
if ((pan_id == pae_supp->sec_keys_nw_info.key_pan_id) &&
(sec_prot_keys_gtk_count(pae_supp->sec_keys_nw_info.gtks) > 0) &&
/* Checks if keys match to network name and PAN ID and that needed keys exists (PMK,
PTK and a GTK), and calls inserts function that will update the network keys as
needed */
if ((strcmp(dest_network_name, pae_supp->sec_keys_nw_info->network_name) == 0 &&
pan_id == pae_supp->sec_keys_nw_info->key_pan_id) &&
(sec_prot_keys_gtk_count(pae_supp->sec_keys_nw_info->gtks) > 0) &&
(sec_prot_keys_pmk_get(&pae_supp->entry.sec_keys) != NULL) &&
(sec_prot_keys_ptk_get(&pae_supp->entry.sec_keys) != NULL)) {
tr_debug("Existing keys used, counter %i", pae_supp->nw_keys_used_cnt);
if (pae_supp->nw_key_insert(pae_supp->interface_ptr, pae_supp->sec_keys_nw_info.gtks) >= 0) {
if (pae_supp->nw_key_insert(pae_supp->interface_ptr, pae_supp->sec_keys_nw_info->gtks) >= 0) {
tr_debug("Keys inserted");
}
pae_supp->nw_keys_used_cnt++;
@ -595,21 +523,7 @@ static int8_t ws_pae_supp_nw_keys_valid_check(pae_supp_t *pae_supp, uint16_t pan
}
}
static void ws_pae_supp_keys_nw_info_init(sec_prot_keys_nw_info_t *sec_keys_nw_info, sec_prot_gtk_keys_t *gtks)
{
if (!sec_keys_nw_info) {
return;
}
memset(sec_keys_nw_info, 0, sizeof(sec_prot_keys_nw_info_t));
sec_keys_nw_info->gtks = gtks;
sec_keys_nw_info->new_pan_id = 0xFFFF;
sec_keys_nw_info->key_pan_id = 0xFFFF;
sec_keys_nw_info->updated = false;
}
void ws_pae_supp_cb_register(protocol_interface_info_entry_t *interface_ptr, ws_pae_supp_auth_completed *completed, ws_pae_supp_nw_key_insert *nw_key_insert, ws_pae_supp_nw_key_index_set *nw_key_index_set, ws_pae_supp_gtk_hash_ptr_get *gtk_hash_ptr_get)
void ws_pae_supp_cb_register(protocol_interface_info_entry_t *interface_ptr, ws_pae_supp_auth_completed *completed, ws_pae_supp_auth_next_target *auth_next_target, ws_pae_supp_nw_key_insert *nw_key_insert, ws_pae_supp_nw_key_index_set *nw_key_index_set, ws_pae_supp_gtk_hash_ptr_get *gtk_hash_ptr_get, ws_pae_supp_nw_info_updated *nw_info_updated)
{
pae_supp_t *pae_supp = ws_pae_supp_get(interface_ptr);
if (!pae_supp) {
@ -617,12 +531,14 @@ void ws_pae_supp_cb_register(protocol_interface_info_entry_t *interface_ptr, ws_
}
pae_supp->auth_completed = completed;
pae_supp->auth_next_target = auth_next_target;
pae_supp->nw_key_insert = nw_key_insert;
pae_supp->nw_key_index_set = nw_key_index_set;
pae_supp->gtk_hash_ptr_get = gtk_hash_ptr_get;
pae_supp->nw_info_updated = nw_info_updated;
}
int8_t ws_pae_supp_init(protocol_interface_info_entry_t *interface_ptr, const sec_prot_certs_t *certs, sec_timer_cfg_t *sec_timer_cfg, sec_prot_cfg_t *sec_prot_cfg)
int8_t ws_pae_supp_init(protocol_interface_info_entry_t *interface_ptr, const sec_prot_certs_t *certs, sec_timer_cfg_t *sec_timer_cfg, sec_prot_cfg_t *sec_prot_cfg, sec_prot_keys_nw_info_t *sec_keys_nw_info)
{
if (!interface_ptr) {
return -1;
@ -639,13 +555,15 @@ int8_t ws_pae_supp_init(protocol_interface_info_entry_t *interface_ptr, const se
pae_supp->interface_ptr = interface_ptr;
pae_supp->auth_completed = NULL;
pae_supp->auth_next_target = NULL;
pae_supp->nw_key_insert = NULL;
pae_supp->nw_key_index_set = NULL;
pae_supp->gtk_hash_ptr_get = NULL;
pae_supp->initial_key_timer = 0;
pae_supp->initial_key_retry_timer = 0;
pae_supp->nw_keys_used_cnt = 0;
pae_supp->initial_key_retry_cnt = INITIAL_KEY_RETRY_COUNT;
pae_supp->initial_key_retry_cnt = DEFAULT_INITIAL_KEY_RETRY_COUNT;
pae_supp->sec_keys_nw_info = sec_keys_nw_info;
pae_supp->sec_timer_cfg = sec_timer_cfg;
pae_supp->sec_prot_cfg = sec_prot_cfg;
pae_supp->auth_trickle_running = false;
@ -653,16 +571,15 @@ int8_t ws_pae_supp_init(protocol_interface_info_entry_t *interface_ptr, const se
pae_supp->timer_running = false;
pae_supp->new_br_eui_64_set = false;
pae_supp->new_br_eui_64_fresh = false;
pae_supp->comp_br_eui_64_set = false;
pae_supp->entry_address_active = false;
ws_pae_lib_supp_init(&pae_supp->entry);
ws_pae_supp_keys_nw_info_init(&pae_supp->sec_keys_nw_info, &pae_supp->gtks);
kmp_address_init(KMP_ADDR_EUI_64, &pae_supp->target_addr, 0);
sec_prot_keys_gtks_init(&pae_supp->gtks);
sec_prot_keys_init(&pae_supp->entry.sec_keys, &pae_supp->gtks, certs);
sec_prot_keys_gtks_init(pae_supp->sec_keys_nw_info->gtks);
sec_prot_keys_init(&pae_supp->entry.sec_keys, pae_supp->sec_keys_nw_info->gtks, certs);
memset(pae_supp->new_br_eui_64, 0, 8);
pae_supp->kmp_service = kmp_service_create();
@ -721,7 +638,6 @@ int8_t ws_pae_supp_init(protocol_interface_info_entry_t *interface_ptr, const se
goto error;
}
ws_pae_supp_nvm_nw_info_read(pae_supp);
ws_pae_supp_nvm_keys_read(pae_supp);
ns_list_add_to_end(&pae_supp_list, pae_supp);
@ -840,7 +756,7 @@ void ws_pae_supp_fast_timer(uint16_t ticks)
}
// Updates KMP timers and supplicant authentication ongoing timer
bool running = ws_pae_lib_supp_timer_update(&pae_supp->entry, ticks, kmp_service_timer_if_timeout);
bool running = ws_pae_lib_supp_timer_update(NULL, &pae_supp->entry, ticks, kmp_service_timer_if_timeout);
// Checks whether timer needs to be active
if (!ws_pae_supp_authentication_ongoing(pae_supp) && !running) {
@ -881,6 +797,15 @@ void ws_pae_supp_slow_timer(uint16_t seconds)
// Checks if trickle timer expires
if (trickle_timer(&pae_supp->auth_trickle_timer, &pae_supp->auth_trickle_params, seconds)) {
if (pae_supp->initial_key_retry_cnt > 0) {
// On initial EAPOL-key TX failure, check for other parents
if (pae_supp->auth_requested && pae_supp->tx_failure_on_initial_key) {
// Returns same target if no other valid targets found
const uint8_t *next_target = pae_supp->auth_next_target(pae_supp->interface_ptr, kmp_address_eui_64_get(&pae_supp->target_addr), &pae_supp->sec_keys_nw_info->key_pan_id);
kmp_address_eui_64_set(&pae_supp->target_addr, next_target);
ws_pae_supp_address_set(pae_supp, &pae_supp->target_addr);
}
pae_supp->tx_failure_on_initial_key = false;
// Sends initial EAPOL-key
if (ws_pae_supp_initial_key_send(pae_supp) < 0) {
tr_info("EAPOL-Key send failed");
}
@ -895,7 +820,12 @@ void ws_pae_supp_slow_timer(uint16_t seconds)
tr_info("GTKs do not match to GTK hash");
retry = true;
}
ws_pae_supp_authenticate_response(pae_supp, AUTH_RESULT_ERR_UNSPEC);
auth_result_e result = AUTH_RESULT_ERR_UNSPEC;
if (pae_supp->tx_failure_on_initial_key) {
result = AUTH_RESULT_ERR_TX_NO_ACK;
pae_supp->tx_failure_on_initial_key = false;
}
ws_pae_supp_authenticate_response(pae_supp, result);
if (retry) {
// Start trickle timer to try re-authentication
ws_pae_supp_initial_key_update_trickle_timer_start(pae_supp, KEY_UPDATE_RETRY_COUNT);
@ -921,10 +851,11 @@ void ws_pae_supp_slow_timer(uint16_t seconds)
// Decrements GTK lifetimes
for (uint8_t i = 0; i < GTK_NUM; i++) {
if (!sec_prot_keys_gtk_is_set(&pae_supp->gtks, i)) {
if (!sec_prot_keys_gtk_is_set(pae_supp->sec_keys_nw_info->gtks, i)) {
continue;
}
sec_prot_keys_gtk_lifetime_decrement(&pae_supp->gtks, i, seconds);
uint64_t current_time = ws_pae_current_time_get();
sec_prot_keys_gtk_lifetime_decrement(pae_supp->sec_keys_nw_info->gtks, i, current_time, seconds);
}
if (pae_supp->initial_key_timer > 0) {
@ -932,7 +863,7 @@ void ws_pae_supp_slow_timer(uint16_t seconds)
pae_supp->initial_key_timer -= seconds;
} else {
pae_supp->initial_key_timer = 0;
pae_supp->tx_failure_on_initial_key = false;
// Sends initial EAPOL-Key message
if (ws_pae_supp_initial_key_send(pae_supp) < 0) {
tr_info("EAPOL-Key send failed");
@ -946,46 +877,40 @@ void ws_pae_supp_slow_timer(uint16_t seconds)
static void ws_pae_supp_initial_trickle_timer_start(pae_supp_t *pae_supp)
{
pae_supp->auth_trickle_params = initial_eapol_key_trickle_params;
/* Starts trickle for initial EAPOL-key. Default sequence has fixed delay of 2 minutes,
* one re-transmit interval, last re-transmit interval transmit time and a wait time
* for the authenticator to answer the last re-transmit.
*
* Interval I [6,12] minutes. Sequence:
*
* fixed 2 minutes delay + I + last I transmit time t + wait for answer [2,4] minutes
*
* There are two retries. Minimum time that sequence takes before authentication failure
* is 16 minutes and maximum is 30 minutes.
*
*
* Extremely slow network
*
* Starts trickle for initial EAPOL-key, Interval I [10,60] minutes. Sequence:
* I + last I transmit time t + wait for answer [2,4] minutes
* There are two retries. Minimum time that sequence takes before authentication failure
* is 22 minutes and maximum is 124 minutes.
*/
pae_supp->auth_trickle_params = pae_supp->sec_prot_cfg->initial_key_trickle_params;
pae_supp->initial_key_retry_timer = pae_supp->sec_prot_cfg->initial_key_retry_delay;
// Very fast, medium and slow network
if (timing_value < 25) {
/* Starts trickle for initial EAPOL-key. Sequence has fixed delay of 2 minutes,
* one re-transmit interval, last re-transmit interval transmit time and a wait time
* for the authenticator to answer the last re-transmit.
*
* Interval I [6,12] minutes. Sequence:
*
* fixed 2 minutes delay + I + last I transmit time t + wait for answer [2,4] minutes
*
* There are two retries. Minimum time that sequence takes before authentication failure
* is 16 minutes and maximum is 30 minutes.
*/
pae_supp->initial_key_retry_timer = DEFAULT_INITIAL_KEY_RETRY_TIMER; // 2 minutes
} else {
/* Extremely slow network
*
* Starts trickle for initial EAPOL-key, Interval I [10,60] minutes. Sequence:
* I + last I transmit time t + wait for answer [2,4] minutes
* There are two retries. Minimum time that sequence takes before authentication failure
* is 22 minutes and maximum is 124 minutes.
*/
pae_supp->auth_trickle_params.Imin = VERY_SLOW_NW_TRICKLE_IMIN_SECS;
pae_supp->auth_trickle_params.Imax = VERY_SLOW_NW_TRICKLE_IMAX_SECS;
pae_supp->initial_key_retry_timer = NONE_INITIAL_KEY_RETRY_TIMER; // 0 seconds
}
trickle_start(&pae_supp->auth_trickle_timer, &pae_supp->auth_trickle_params);
tr_info("Initial EAPOL-Key trickle I: [%i,%i] %i, t: %i", pae_supp->auth_trickle_params.Imin, pae_supp->auth_trickle_params.Imax, pae_supp->auth_trickle_timer.I, pae_supp->auth_trickle_timer.t);
pae_supp->auth_trickle_running = true;
pae_supp->initial_key_retry_cnt = INITIAL_KEY_RETRY_COUNT;
pae_supp->initial_key_retry_cnt = pae_supp->sec_prot_cfg->initial_key_retry_cnt;
}
static void ws_pae_supp_initial_last_interval_trickle_timer_start(pae_supp_t *pae_supp)
{
// Starts trickle last to wait response after last retry before failing authentication
pae_supp->auth_trickle_params = initial_eapol_key_trickle_params;
pae_supp->auth_trickle_params.Imin = LAST_INTERVAL_TRICKLE_IMIN_SECS;
pae_supp->auth_trickle_params.Imax = LAST_INTERVAL_TRICKLE_IMAX_SECS;
pae_supp->auth_trickle_params.k = 0;
pae_supp->auth_trickle_params.TimerExpirations = 1;
// Set I to [iMin,iMax] (4 to 4 minutes) -> t is [I/2 - I] (2 minutes to 4 minutes)
trickle_start(&pae_supp->auth_trickle_timer, &pae_supp->auth_trickle_params);
@ -1213,7 +1138,7 @@ static kmp_api_t *ws_pae_supp_kmp_incoming_ind(kmp_service_t *service, kmp_type_
static kmp_api_t *ws_pae_supp_kmp_create_and_start(kmp_service_t *service, kmp_type_e type, pae_supp_t *pae_supp)
{
// Create new instance
kmp_api_t *kmp = kmp_api_create(service, type, pae_supp->sec_prot_cfg);
kmp_api_t *kmp = kmp_api_create(service, type, pae_supp->sec_prot_cfg, pae_supp->sec_timer_cfg);
if (!kmp) {
return NULL;
}
@ -1308,7 +1233,12 @@ static void ws_pae_supp_kmp_api_finished_indication(kmp_api_t *kmp, kmp_result_e
that bootstrap can decide if EAPOL target should be changed */
else if (type > IEEE_802_1X_INITIAL_KEY && result == KMP_RESULT_ERR_TX_NO_ACK) {
tr_info("Initial EAPOL-Key TX failure, target: %s", trace_array(kmp_address_eui_64_get(&pae_supp->entry.addr), 8));
ws_pae_supp_authenticate_response(pae_supp, AUTH_RESULT_ERR_TX_NO_ACK);
/* Fails authentication only if other authentication protocols are not yet
started by authenticator */
if (ws_pae_lib_kmp_list_count(&pae_supp->entry.kmp_list) <= 1) {
// Continues with trickle but selects different parent
pae_supp->tx_failure_on_initial_key = true;
}
}
}

View File

@ -40,12 +40,13 @@
* \param cert_chain certificate chain
* \param sec_timer_cfg timer configuration
* \param sec_prot_cfg protocol configuration
* \param sec_keys_nw_info security keys network information
*
* \return < 0 failure
* \return >= 0 success
*
*/
int8_t ws_pae_supp_init(protocol_interface_info_entry_t *interface_ptr, const sec_prot_certs_t *certs, sec_timer_cfg_t *sec_timer_cfg, sec_prot_cfg_t *sec_prot_cfg);
int8_t ws_pae_supp_init(protocol_interface_info_entry_t *interface_ptr, const sec_prot_certs_t *certs, sec_timer_cfg_t *sec_timer_cfg, sec_prot_cfg_t *sec_prot_cfg, sec_prot_keys_nw_info_t *sec_keys_nw_info);
/**
* ws_pae_supp_delete deletes PAE supplicant
@ -80,26 +81,14 @@ void ws_pae_supp_slow_timer(uint16_t seconds);
* \param interface_ptr interface
* \param dest_pan_id EAPOL target PAN ID
* \param dest_eui_64 EAPOL target
* \param dest_network_name EAPOL target network name
*
* \return < 0 failure
* \return 0 authentication done, continue
* \return > 0 authentication started
*
*/
int8_t ws_pae_supp_authenticate(protocol_interface_info_entry_t *interface_ptr, uint16_t dest_pan_id, uint8_t *dest_eui_64);
/**
* ws_pae_supp_nw_info_set set network information
*
* \param interface_ptr interface
* \param pan_id PAD ID
* \param network_name network name
*
* \return < 0 failure
* \return >= 0 success
*
*/
int8_t ws_pae_supp_nw_info_set(protocol_interface_info_entry_t *interface_ptr, uint16_t pan_id, char *network_name);
int8_t ws_pae_supp_authenticate(protocol_interface_info_entry_t *interface_ptr, uint16_t dest_pan_id, uint8_t *dest_eui_64, char *dest_network_name);
/**
* ws_pae_supp_border_router_addr_write write border router address
@ -129,12 +118,13 @@ int8_t ws_pae_supp_border_router_addr_read(protocol_interface_info_entry_t *inte
* ws_pae_supp_nw_key_valid network key is valid i.e. used successfully on bootstrap
*
* \param interface_ptr interface
* \param br_iid border router IID for which the keys are valid
*
* \return < 0 failure
* \return >= 0 success
*
*/
int8_t ws_pae_supp_nw_key_valid(protocol_interface_info_entry_t *interface_ptr);
int8_t ws_pae_supp_nw_key_valid(protocol_interface_info_entry_t *interface_ptr, uint8_t *br_iid);
/**
* ws_pae_supp_gtk_hash_update GTK hash has been updated (on PAN configuration)
@ -202,6 +192,17 @@ typedef void ws_pae_supp_nw_key_index_set(protocol_interface_info_entry_t *inter
*/
typedef void ws_pae_supp_auth_completed(protocol_interface_info_entry_t *interface_ptr, auth_result_e result, uint8_t *target_eui_64);
/**
* ws_pae_supp_auth_next_target get next target to attempt authentication
*
* \param interface_ptr interface
* \param previous_eui_64 EUI-64 of previous target
*
* \return EUI-64 of the next target or previous target if new one not available
*
*/
typedef const uint8_t *ws_pae_supp_auth_next_target(protocol_interface_info_entry_t *interface_ptr, const uint8_t *previous_eui_64, uint16_t *pan_id);
/**
* ws_pae_supp_nw_key_insert network key insert callback
*
@ -224,6 +225,14 @@ typedef int8_t ws_pae_supp_nw_key_insert(protocol_interface_info_entry_t *interf
*/
typedef uint8_t *ws_pae_supp_gtk_hash_ptr_get(protocol_interface_info_entry_t *interface_ptr);
/**
* ws_pae_supp_nw_info_updated security keys network information updated
*
* \param interface_ptr interface
*
*/
typedef void ws_pae_supp_nw_info_updated(protocol_interface_info_entry_t *interface_ptr);
/**
* ws_pae_supp_cb_register register PEA supplicant callbacks
*
@ -231,9 +240,10 @@ typedef uint8_t *ws_pae_supp_gtk_hash_ptr_get(protocol_interface_info_entry_t *i
* \param completed authentication completed callback
* \param nw_key_insert network key index callback
* \param nw_key_index_set network send key index callback
* \param nw_info_updated security keys network information updated callback
*
*/
void ws_pae_supp_cb_register(protocol_interface_info_entry_t *interface_ptr, ws_pae_supp_auth_completed *completed, ws_pae_supp_nw_key_insert *nw_key_insert, ws_pae_supp_nw_key_index_set *nw_key_index_set, ws_pae_supp_gtk_hash_ptr_get *gtk_hash_ptr_get);
void ws_pae_supp_cb_register(protocol_interface_info_entry_t *interface_ptr, ws_pae_supp_auth_completed *completed, ws_pae_supp_auth_next_target *auth_next_target, ws_pae_supp_nw_key_insert *nw_key_insert, ws_pae_supp_nw_key_index_set *nw_key_index_set, ws_pae_supp_gtk_hash_ptr_get *gtk_hash_ptr_get, ws_pae_supp_nw_info_updated *nw_info_updated);
#else
@ -241,7 +251,6 @@ void ws_pae_supp_cb_register(protocol_interface_info_entry_t *interface_ptr, ws_
#define ws_pae_supp_delete NULL
#define ws_pae_supp_timing_adjust(timing) 1
#define ws_pae_supp_cb_register(interface_ptr, completed, nw_key_insert, nw_key_index_set)
#define ws_pae_supp_nw_info_set(interface_ptr, pan_id, network_name) -1
#define ws_pae_supp_nw_key_valid(interface_ptr) -1
#define ws_pae_supp_fast_timer NULL
#define ws_pae_supp_slow_timer NULL

View File

@ -0,0 +1,190 @@
/*
* Copyright (c) 2020, Arm Limited and affiliates.
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "nsconfig.h"
#include <string.h>
#include "ns_types.h"
#include "ns_list.h"
#include "ns_trace.h"
#include "ns_time_api.h"
#include "6LoWPAN/ws/ws_config.h"
#include "6LoWPAN/ws/ws_pae_time.h"
#include "Security/protocols/sec_prot_certs.h"
#include "Security/protocols/sec_prot_keys.h"
#ifdef HAVE_WS
#define TRACE_GROUP "wst"
// Wednesday, January 1, 2020 0:00:00 GMT
#define CURRENT_TIME_INIT_VALUE 1577836800
// Increment two hours in addition to maximum storing interval
#define CURRENT_TIME_INCREMENT_VALUE (2 * 3600)
static uint64_t current_time = CURRENT_TIME_INIT_VALUE;
static ns_time_api_system_time_callback *system_time_callback = NULL;
uint16_t ws_pae_time_to_short_convert(uint32_t time)
{
uint16_t short_time;
time_format_t format;
if (time < STIME_TIME_MAX) {
short_time = time;
format = TIME_FORMAT_SECONDS;
} else if (time < (STIME_TIME_MAX * 60)) {
short_time = time / 60;
format = TIME_FORMAT_MINUTES;
} else if (time < (STIME_TIME_MAX * 3600)) {
short_time = time / 3600;
format = TIME_FORMAT_HOURS;
} else {
short_time = time / 86400;
format = TIME_FORMAT_DAYS;
}
short_time |= ((uint16_t) format) << STIME_TIME_BITS;
return short_time;
}
uint32_t ws_pae_time_from_short_convert(uint16_t short_time)
{
uint32_t time;
time_format_t format = short_time >> STIME_TIME_BITS;
short_time &= STIME_TIME_MASK;
if (format == TIME_FORMAT_SECONDS) {
time = short_time;
} else if (format == TIME_FORMAT_MINUTES) {
time = short_time * 60;
} else if (format == TIME_FORMAT_HOURS) {
time = short_time * 3600;
} else {
time = short_time * 86400;
}
return time;
}
bool ws_pae_time_from_short_time_compare(uint16_t short_time1, uint16_t short_time2)
{
uint32_t time1 = ws_pae_time_from_short_convert(short_time1);
uint32_t time2 = ws_pae_time_from_short_convert(short_time2);
// Calculate difference
uint32_t difference;
if (time1 > time2) {
difference = time1 - time2;
} else {
difference = time2 - time1;
}
// Allow variable difference to be regarded as same based on format
if (STIME_FORMAT_GET(short_time1) == TIME_FORMAT_DAYS || STIME_FORMAT_GET(short_time2) == TIME_FORMAT_DAYS) {
if (difference > 2 * 24 * 3600) { // Two days
return false;
}
} else if (STIME_FORMAT_GET(short_time1) == TIME_FORMAT_HOURS || STIME_FORMAT_GET(short_time2) == TIME_FORMAT_HOURS) {
if (difference > 2 * 3600) { // Two hours
return false;
}
} else if (STIME_FORMAT_GET(short_time1) == TIME_FORMAT_MINUTES || STIME_FORMAT_GET(short_time2) == TIME_FORMAT_MINUTES) {
if (difference > 5 * 60) { // 5 minutes
return false;
}
} else {
if (difference > 10) { // 10 seconds
return false;
}
}
return true;
}
int8_t ws_pae_time_diff_calc(uint64_t curr_time, uint64_t comp_time, uint32_t *time_diff, bool future)
{
int32_t difference;
*time_diff = 0;
// Comparison time is in future
if (curr_time < comp_time) {
if (!future) {
// Do not allow times in future
return -1;
}
difference = comp_time - curr_time;
} else {
// Comparison time is in past
if (future) {
// Do not allow times in past
return -1;
}
difference = curr_time - comp_time;
}
// If difference is more two years time is invalid
if (difference > SEC_MAXIMUM_LIFETIME) {
return -1;
}
*time_diff = difference;
return 0;
}
uint64_t ws_pae_current_time_get(void)
{
if (system_time_callback) {
return system_time_callback();
}
return current_time;
}
void ws_pae_current_time_update(uint16_t seconds)
{
current_time += seconds;
}
int8_t ws_pae_current_time_set(uint64_t time)
{
current_time = time;
if (system_time_callback) {
uint64_t system_time = system_time_callback();
// System time has gone backwards
if (system_time < current_time || system_time > current_time + SYSTEM_TIME_MAXIMUM_DIFF) {
tr_error("FATAL: system time less than reference time or more than 12 months in future: %"PRIi64" reference time: %"PRIi64, system_time, current_time);
return -1;
}
} else {
current_time += FRAME_COUNTER_STORE_FORCE_INTERVAL + CURRENT_TIME_INCREMENT_VALUE;
}
return 0;
}
void ns_time_api_system_time_callback_set(ns_time_api_system_time_callback callback)
{
system_time_callback = callback;
}
#endif /* HAVE_WS */

View File

@ -0,0 +1,116 @@
/*
* Copyright (c) 2020, Arm Limited and affiliates.
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef WS_PAE_TIME_H_
#define WS_PAE_TIME_H_
/*
* Port access entity time functions.
*
*/
typedef enum {
TIME_FORMAT_SECONDS = 0,
TIME_FORMAT_MINUTES,
TIME_FORMAT_HOURS,
TIME_FORMAT_DAYS,
} time_format_t;
#define STIME_TIME_BITS 14
#define STIME_TIME_MAX 0x3FFF
#define STIME_TIME_MASK STIME_TIME_MAX
#define STIME_FORMAT_GET(stime) (stime >> STIME_TIME_BITS)
#define STIME_TIME_GET(stime) (stime & STIME_TIME_MASK)
// Maximum difference in stored and indicated system time
#define SYSTEM_TIME_MAXIMUM_DIFF (60 * 60 * 24 * 30 * 12)
/**
* ws_pae_time_to_short_convert convert time to short format
*
* \param time time in seconds to convert
*
* \return < 0 failure
* \return >= 0 success
*
*/
uint16_t ws_pae_time_to_short_convert(uint32_t time);
/**
* ws_pae_time_from_short_convert convert short time to time format
*
* \param short_time short_time to convert
*
* \return time in seconds
*
*/
uint32_t ws_pae_time_from_short_convert(uint16_t short_time);
/**
* ws_pae_time_from_short_time_compare compare two times in short format
*
* \param short_time1 time 1 to compare
* \param short_time1 time 2 to compare
*
* \return true times are equal
* \return false times are not equal
*
*/
bool ws_pae_time_from_short_time_compare(uint16_t short_time1, uint16_t short_time2);
/**
* ws_pae_time_diff_calc calculates difference between two times
*
* \param curr_time current time
* \param comp_time time which is compared
* \param time_diff returns time difference
* \param future compared time should in future
*
* \return < 0 failure
* \return >= 0 success
*
*/
int8_t ws_pae_time_diff_calc(uint64_t curr_time, uint64_t comp_time, uint32_t *time_diff, bool future);
/**
* ws_pae_current_time_get gets current time
*
* \return current time in seconds after 1970
*
*/
uint64_t ws_pae_current_time_get(void);
/**
* ws_pae_current_time_get updates current time
*
* \param seconds seconds to be added to current time
*
*/
void ws_pae_current_time_update(uint16_t seconds);
/**
* ws_pae_current_time_set sets current time
*
* \param time new time
*
* \return < 0 failure
* \return >= 0 success
*/
int8_t ws_pae_current_time_set(uint64_t time);
#endif /* WS_PAE_KEY_STORAGE_H_ */

View File

@ -26,6 +26,7 @@
#include "NWK_INTERFACE/Include/protocol.h"
#include "6LoWPAN/ws/ws_config.h"
#include "6LoWPAN/ws/ws_cfg_settings.h"
#include "Security/protocols/sec_prot_cfg.h"
#include "6LoWPAN/ws/ws_pae_timers.h"
#ifdef HAVE_WS

View File

@ -18,18 +18,6 @@
#ifndef WS_PAE_TIMERS_H_
#define WS_PAE_TIMERS_H_
typedef struct sec_timer_cfg_s {
uint32_t gtk_expire_offset; /* GTK lifetime; GTK_EXPIRE_OFFSET (seconds) */
uint32_t pmk_lifetime; /* PMK lifetime (seconds) */
uint32_t ptk_lifetime; /* PTK lifetime (seconds) */
uint16_t gtk_new_act_time; /* GTK_NEW_ACTIVATION_TIME (1/X of expire offset) */
uint16_t revocat_lifetime_reduct; /* REVOCATION_LIFETIME_REDUCTION (reduction of lifetime) */
uint16_t gtk_request_imin; /* GTK_REQUEST_IMIN (seconds) */
uint16_t gtk_request_imax; /* GTK_REQUEST_IMAX (seconds) */
uint16_t gtk_max_mismatch; /* GTK_MAX_MISMATCH (seconds) */
uint8_t gtk_new_install_req; /* GTK_NEW_INSTALL_REQUIRED (percent of GTK lifetime) */
} sec_timer_cfg_t;
/**
* ws_pae_timers_settings_init initializes timer settings structure
*

View File

@ -23,7 +23,9 @@
#include <net_ws_test.h>
#include "fhss_config.h"
#include "ws_management_api.h"
#include "mac_api.h"
#include "NWK_INTERFACE/Include/protocol.h"
#include "6LoWPAN/MAC/mac_helper.h"
#include "6LoWPAN/ws/ws_config.h"
#include "6LoWPAN/ws/ws_common.h"
#include "6LoWPAN/ws/ws_bbr_api_internal.h"

View File

@ -1714,7 +1714,11 @@ buffer_t *icmpv6_build_na(protocol_interface_info_entry_t *cur, bool solicited,
buf->info = (buffer_info_t)(B_DIR_DOWN | B_FROM_ICMP | B_TO_ICMP);
buf->interface = cur;
tr_info("Build NA");
if (aro) {
tr_info("Build NA ARO");
} else {
tr_info("Build NA");
}
return (buf);
}

View File

@ -35,5 +35,10 @@ void ns_monitor_timer(uint16_t seconds);
int ns_monitor_heap_gc_threshold_set(uint8_t percentage_high, uint8_t percentage_critical);
int ns_monitor_packet_ingress_rate_limit_by_memory(uint8_t free_heap_percentage);
bool ns_monitor_packet_allocation_allowed(void);
#endif // _NS_MONITOR_H

View File

@ -62,6 +62,8 @@ typedef struct ns_monitor__s {
static ns_monitor_t *ns_monitor_ptr = NULL;
static uint8_t ns_dyn_mem_rate_limiting_threshold_percentage = 0; // Percentage of free memory required to allow routing
typedef void (ns_maintenance_gc_cb)(bool full_gc);
/*
@ -189,3 +191,31 @@ int ns_monitor_heap_gc_threshold_set(uint8_t percentage_high, uint8_t percentage
return -1;
}
int ns_monitor_packet_ingress_rate_limit_by_memory(uint8_t free_heap_percentage)
{
if (free_heap_percentage < 100) {
ns_dyn_mem_rate_limiting_threshold_percentage = free_heap_percentage;
return 0;
}
return -1;
}
bool ns_monitor_packet_allocation_allowed(void)
{
// If there is no packets to forward this should not be blocked.
// There should be cleanup routine enabled that will remove unneeded memory to prevent locks
// this could trigger a function to clean packets from routing and allow newest packets
const mem_stat_t *ns_dyn_mem_stat = ns_dyn_mem_get_mem_stat();
if (ns_dyn_mem_stat && ns_dyn_mem_rate_limiting_threshold_percentage) {
if (ns_dyn_mem_stat->heap_sector_allocated_bytes > ns_dyn_mem_stat->heap_sector_size / 100 * (100 - ns_dyn_mem_rate_limiting_threshold_percentage)) {
// Packet allocation not allowed as memory is running low.
return false;
}
}
return true;
}

View File

@ -0,0 +1,142 @@
/*
* Copyright (c) 2020, Arm Limited and affiliates.
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "string.h"
#include "nsconfig.h"
#include "ns_types.h"
#include "ns_trace.h"
#include "nsdynmemLIB.h"
#include "MAC/IEEE802_15_4/mac_defines.h"
#include "MAC/IEEE802_15_4/mac_cca_threshold.h"
#define TRACE_GROUP "mcth"
int8_t mac_cca_thr_init(protocol_interface_rf_mac_setup_s *rf_ptr, uint8_t number_of_channels, int8_t default_dbm, int8_t high_limit, int8_t low_limit)
{
// No changes
if (rf_ptr->cca_threshold &&
(number_of_channels == rf_ptr->cca_threshold->number_of_channels) &&
(default_dbm == rf_ptr->cca_threshold->default_dbm) &&
(high_limit == rf_ptr->cca_threshold->high_limit) &&
(low_limit == rf_ptr->cca_threshold->low_limit)) {
return -1;
}
// Validate given dBm range. Default must be in between high and low limit.
if ((default_dbm > high_limit) || (default_dbm < low_limit)) {
return -1;
}
mac_cca_thr_deinit(rf_ptr);
rf_ptr->cca_threshold = ns_dyn_mem_alloc(sizeof(mac_cca_threshold_s));
if (!rf_ptr->cca_threshold) {
return -1;
}
rf_ptr->cca_threshold->ch_thresholds = ns_dyn_mem_alloc(number_of_channels);
if (!rf_ptr->cca_threshold->ch_thresholds) {
ns_dyn_mem_free(rf_ptr->cca_threshold);
rf_ptr->cca_threshold = 0;
return -1;
}
memset(rf_ptr->cca_threshold->ch_thresholds, default_dbm, number_of_channels);
rf_ptr->cca_threshold->high_limit = high_limit;
rf_ptr->cca_threshold->low_limit = low_limit;
rf_ptr->cca_threshold->default_dbm = default_dbm;
rf_ptr->cca_threshold->number_of_channels = number_of_channels;
tr_info("Initialized CCA threshold: %u, %i, %i, %i", number_of_channels, default_dbm, high_limit, low_limit);
return 0;
}
int8_t mac_cca_thr_deinit(protocol_interface_rf_mac_setup_s *rf_ptr)
{
if (!rf_ptr->cca_threshold) {
return -1;
}
ns_dyn_mem_free(rf_ptr->cca_threshold->ch_thresholds);
ns_dyn_mem_free(rf_ptr->cca_threshold);
rf_ptr->cca_threshold = 0;
return 0;
}
int8_t mac_cca_thr_get_dbm(protocol_interface_rf_mac_setup_s *rf_ptr, uint8_t channel)
{
if (!rf_ptr->cca_threshold) {
return CCA_FAILED_DBM;
}
// If channel is unknown, use default threshold
if (channel > (rf_ptr->cca_threshold->number_of_channels - 1)) {
return rf_ptr->cca_threshold->default_dbm;
}
return rf_ptr->cca_threshold->ch_thresholds[channel];
}
static int8_t mac_cca_thr_set_dbm(protocol_interface_rf_mac_setup_s *rf_ptr, uint8_t channel, int8_t dbm)
{
if (rf_ptr->cca_threshold->ch_thresholds[channel] != dbm) {
rf_ptr->cca_threshold->ch_thresholds[channel] = dbm;
return 0;
}
return -1;
}
static int8_t mac_cca_thr_update_channel_threshold(protocol_interface_rf_mac_setup_s *rf_ptr, uint8_t channel, int8_t dbm)
{
// Already on low limit
if (rf_ptr->cca_threshold->ch_thresholds[channel] == rf_ptr->cca_threshold->low_limit) {
return -1;
}
// Already using lower threshold
if (rf_ptr->cca_threshold->ch_thresholds[channel] <= (dbm - CCA_THRESHOLD_STEP)) {
return -1;
}
// Do not set below configured low limit
if ((dbm - CCA_THRESHOLD_STEP) < rf_ptr->cca_threshold->low_limit) {
return mac_cca_thr_set_dbm(rf_ptr, channel, rf_ptr->cca_threshold->low_limit);
}
return mac_cca_thr_set_dbm(rf_ptr, channel, dbm - CCA_THRESHOLD_STEP);
}
static int8_t mac_cca_thr_channel_failed(protocol_interface_rf_mac_setup_s *rf_ptr, uint8_t channel)
{
// Already on high limit
if (rf_ptr->cca_threshold->ch_thresholds[channel] == rf_ptr->cca_threshold->high_limit) {
return -1;
}
// Do not set above configured high limit
if ((rf_ptr->cca_threshold->ch_thresholds[channel] + CCA_THRESHOLD_STEP) > rf_ptr->cca_threshold->high_limit) {
return mac_cca_thr_set_dbm(rf_ptr, channel, rf_ptr->cca_threshold->high_limit);
}
return mac_cca_thr_set_dbm(rf_ptr, channel, rf_ptr->cca_threshold->ch_thresholds[channel] + CCA_THRESHOLD_STEP);
}
int8_t mac_cca_threshold_update(protocol_interface_rf_mac_setup_s *rf_ptr, uint8_t channel, int8_t dbm)
{
if (!rf_ptr->cca_threshold) {
return -1;
}
if (channel > (rf_ptr->cca_threshold->number_of_channels - 1)) {
return -1;
}
if (dbm == CCA_FAILED_DBM) {
if (mac_cca_thr_channel_failed(rf_ptr, channel)) {
return -1;
}
} else {
if (mac_cca_thr_update_channel_threshold(rf_ptr, channel, dbm)) {
return -1;
}
}
tr_debug("Channel %u CCA threshold to %i", channel, rf_ptr->cca_threshold->ch_thresholds[channel]);
return 0;
}

View File

@ -0,0 +1,65 @@
/*
* Copyright (c) 2020, Arm Limited and affiliates.
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef MAC_CCA_THRESHOLD_H_
#define MAC_CCA_THRESHOLD_H_
#define CCA_THRESHOLD_STEP 1
#define CCA_FAILED_DBM 0x7F
typedef struct mac_cca_threshold {
int8_t *ch_thresholds;
int8_t high_limit;
int8_t low_limit;
int8_t default_dbm;
uint8_t number_of_channels;
} mac_cca_threshold_s;
/**
* @brief Initialize automatic CCA threshold.
* @param rf_ptr Pointer to MAC instance.
* @param number_of_channels Number of MAC channels.
* @param default_dbm Default threshold.
* @param high_limit Highest allowed CCA threshold.
* @param low_limit Lowest allowed CCA threshold.
* @return 0 Success, negative Failed.
*/
int8_t mac_cca_thr_init(protocol_interface_rf_mac_setup_s *rf_ptr, uint8_t number_of_channels, int8_t default_dbm, int8_t high_limit, int8_t low_limit);
/**
* @brief Deinitialize automatic CCA threshold.
* @param rf_ptr Pointer to MAC instance.
* @return 0 Success, negative Not found.
*/
int8_t mac_cca_thr_deinit(protocol_interface_rf_mac_setup_s *rf_ptr);
/**
* @brief Read CCA threshold of specific channel.
* @param channel Channel.
* @return CCA threshold (dBm), CCA_FAILED_DBM Feature not enabled.
*/
int8_t mac_cca_thr_get_dbm(protocol_interface_rf_mac_setup_s *rf_ptr, uint8_t channel);
/**
* @brief Update CCA threshold of specific channel.
* @param channel Channel.
* @param dbm CCA threshold (dBm).
* @return 0 Updated, negative Already using this value.
*/
int8_t mac_cca_threshold_update(protocol_interface_rf_mac_setup_s *rf_ptr, uint8_t channel, int8_t dbm);
#endif /* MAC_CCA_THRESHOLD_H_ */

View File

@ -91,11 +91,13 @@ typedef struct mac_pre_build_frame {
uint8_t csma_periods_left;
uint8_t fhss_retry_count;
uint8_t fhss_cca_retry_count;
uint16_t initial_tx_channel;
uint32_t tx_time;
bool upper_layer_request: 1;
bool mac_allocated_payload_ptr: 1;
bool asynch_request: 1;
bool message_builded: 1;
bool DSN_allocated: 1;
unsigned security_mic_len: 5; //Max possible lengths 0, 4, 8, 16 bytes
unsigned priority: 2;
struct mac_pre_build_frame *next; //Pointer for queue purpose

View File

@ -276,6 +276,7 @@ typedef struct protocol_interface_rf_mac_setup {
struct arm_device_driver_list *tun_extension_rf_driver;
/* End of API Control */
struct mlme_scan_conf_s *mac_mlme_scan_resp;
struct mac_cca_threshold *cca_threshold;
//beacon_join_priority_tx_cb *beacon_join_priority_tx_cb_ptr;
struct mac_statistics_s *mac_statistics;
/* FHSS API*/

View File

@ -34,6 +34,7 @@
#include "fhss_api.h"
#include "platform/arm_hal_interrupt.h"
#include "common_functions.h"
#include "Core/include/ns_monitor.h"
#include "MAC/IEEE802_15_4/sw_mac_internal.h"
#include "MAC/IEEE802_15_4/mac_defines.h"
@ -45,6 +46,7 @@
#include "MAC/IEEE802_15_4/mac_mcps_sap.h"
#include "MAC/IEEE802_15_4/mac_header_helper_functions.h"
#include "MAC/IEEE802_15_4/mac_indirect_data.h"
#include "MAC/IEEE802_15_4/mac_cca_threshold.h"
#include "MAC/rf_driver_storage.h"
#include "sw_mac.h"
@ -74,8 +76,6 @@ static void mac_pd_data_confirm_failure_handle(protocol_interface_rf_mac_setup_s
static int8_t mac_tasklet_event_handler = -1;
static ns_mem_heap_size_t ns_dyn_mem_rate_limiting_threshold = 0xFFFFFFFF;
/**
* Get PHY time stamp.
*
@ -1196,6 +1196,9 @@ static void mac_mcps_sap_data_tasklet(arm_event_s *event)
case MAC_MLME_SCAN_CONFIRM_HANDLER:
mac_mlme_scan_confirmation_handle((protocol_interface_rf_mac_setup_s *) event->data_ptr);
break;
case MAC_CCA_THR_UPDATE:
mac_cca_threshold_update((protocol_interface_rf_mac_setup_s *) event->data_ptr, event->event_data >> 8, (int8_t) event->event_data);
break;
case MAC_SAP_TRIG_TX:
mac_clear_active_event((protocol_interface_rf_mac_setup_s *) event->data_ptr, MAC_SAP_TRIG_TX);
mac_mcps_trig_buffer_from_queue((protocol_interface_rf_mac_setup_s *) event->data_ptr);
@ -1221,7 +1224,9 @@ mac_pre_build_frame_t *mcps_sap_prebuild_frame_buffer_get(uint16_t payload_size)
return NULL;
}
memset(buffer, 0, sizeof(mac_pre_build_frame_t));
buffer->initial_tx_channel = 0xffff;
buffer->aux_header.frameCounter = 0xffffffff;
buffer->DSN_allocated = false;
if (payload_size) {
//Mac interlnal payload allocate
buffer->mac_payload = ns_dyn_mem_temporary_alloc(payload_size);
@ -1498,7 +1503,10 @@ static void mcps_generic_sequence_number_allocate(protocol_interface_rf_mac_setu
switch (buffer->fcf_dsn.frametype) {
case MAC_FRAME_CMD:
case MAC_FRAME_DATA:
buffer->fcf_dsn.DSN = mac_mlme_set_new_sqn(rf_ptr);
if (!buffer->DSN_allocated) {
buffer->fcf_dsn.DSN = mac_mlme_set_new_sqn(rf_ptr);
buffer->DSN_allocated = true;
}
break;
case MAC_FRAME_BEACON:
buffer->fcf_dsn.DSN = mac_mlme_set_new_beacon_sqn(rf_ptr);
@ -2126,8 +2134,8 @@ void mcps_sap_pre_parsed_frame_buffer_free(mac_pre_parsed_frame_t *buf)
mac_pre_parsed_frame_t *mcps_sap_pre_parsed_frame_buffer_get(const uint8_t *data_ptr, uint16_t frame_length)
{
// check that system has enough space to handle the new packet
const mem_stat_t *ns_dyn_mem_stat = ns_dyn_mem_get_mem_stat();
if (ns_dyn_mem_stat && ns_dyn_mem_stat->heap_sector_allocated_bytes > ns_dyn_mem_rate_limiting_threshold) {
if (!ns_monitor_packet_allocation_allowed()) {
// stack can not handle new packets for routing
return NULL;
}
@ -2251,6 +2259,25 @@ void mcps_sap_trig_tx(void *mac_ptr)
}
}
void mac_cca_threshold_event_send(protocol_interface_rf_mac_setup_s *rf_ptr, uint8_t channel, int16_t dbm)
{
// Return if feature is not initialized
if (!rf_ptr->cca_threshold) {
return;
}
uint16_t data = channel << 8 | (uint8_t) dbm;
arm_event_s event = {
.receiver = mac_tasklet_event_handler,
.sender = 0,
.event_id = 0,
.event_data = data,
.data_ptr = rf_ptr,
.event_type = MAC_CCA_THR_UPDATE,
.priority = ARM_LIB_LOW_PRIORITY_EVENT,
};
eventOS_event_send(&event);
}
void mac_generic_event_trig(uint8_t event_type, void *mac_ptr, bool low_latency)
{
@ -2363,18 +2390,6 @@ uint8_t mcps_sap_purge_reg_handler(protocol_interface_rf_mac_setup_s *rf_mac_set
return confirmation.status;
}
int mcps_packet_ingress_rate_limit_by_memory(uint8_t free_heap_percentage)
{
const mem_stat_t *ns_dyn_mem_stat = ns_dyn_mem_get_mem_stat();
if (ns_dyn_mem_stat && free_heap_percentage < 100) {
ns_dyn_mem_rate_limiting_threshold = ns_dyn_mem_stat->heap_sector_size / 100 * (100 - free_heap_percentage);
return 0;
}
return -1;
}
void mcps_pending_packet_counter_update_check(protocol_interface_rf_mac_setup_s *rf_mac_setup, mac_pre_build_frame_t *buffer)
{
if (buffer->fcf_dsn.securityEnabled) {

View File

@ -56,6 +56,7 @@ typedef enum {
#define MAC_MLME_SCAN_CONFIRM_HANDLER 6
#define MAC_SAP_TRIG_TX 7
#define MCPS_SAP_DATA_ACK_CNF_EVENT 8
#define MAC_CCA_THR_UPDATE 9
// Default number of CSMA-CA periods
#define MAC_DEFAULT_NUMBER_OF_CSMA_PERIODS 1
@ -142,4 +143,6 @@ uint32_t mac_mcps_sap_get_phy_timestamp(struct protocol_interface_rf_mac_setup *
void mcps_pending_packet_counter_update_check(struct protocol_interface_rf_mac_setup *rf_mac_setup, mac_pre_build_frame_t *buffer);
void mac_cca_threshold_event_send(struct protocol_interface_rf_mac_setup *rf_mac_setup, uint8_t channel, int16_t dbm);
#endif /* MAC_IEEE802_15_4_MAC_MCPS_SAP_H_ */

View File

@ -48,6 +48,7 @@
#include "MAC/IEEE802_15_4/mac_timer.h"
#include "MAC/IEEE802_15_4/mac_pd_sap.h"
#include "MAC/IEEE802_15_4/mac_mcps_sap.h"
#include "MAC/IEEE802_15_4/mac_cca_threshold.h"
#include "MAC/virtual_rf/virtual_rf_defines.h"
#include "MAC/rf_driver_storage.h"
@ -668,14 +669,50 @@ static int8_t mac_mlme_set_ack_wait_duration(protocol_interface_rf_mac_setup_s *
return 0;
}
static void mac_mlme_trig_pending_ack(protocol_interface_rf_mac_setup_s *rf_mac_setup, mlme_device_descriptor_t *device_ptr)
{
platform_enter_critical();
if (rf_mac_setup->mac_ack_tx_active && !rf_mac_setup->ack_tx_possible &&
device_ptr->PANId == rf_mac_setup->enhanced_ack_buffer.DstPANId) {
//Compare address for pending neigbour add
if (rf_mac_setup->enhanced_ack_buffer.fcf_dsn.DstAddrMode == MAC_ADDR_MODE_16_BIT) {
uint16_t short_id = common_read_16_bit(rf_mac_setup->enhanced_ack_buffer.DstAddr);
if (short_id == device_ptr->ShortAddress) {
rf_mac_setup->ack_tx_possible = true;
}
} else if (rf_mac_setup->enhanced_ack_buffer.fcf_dsn.DstAddrMode == MAC_ADDR_MODE_64_BIT) {
if (memcmp(device_ptr->ExtAddress, rf_mac_setup->enhanced_ack_buffer.DstAddr, 8) == 0) {
rf_mac_setup->ack_tx_possible = true;
}
}
}
platform_exit_critical();
}
static int8_t mac_mlme_device_description_set(protocol_interface_rf_mac_setup_s *rf_mac_setup, const mlme_set_t *set_req)
{
if (set_req->value_size != sizeof(mlme_device_descriptor_t)) {
return -1;
}
if (mac_sec_mib_device_description_set(set_req->attr_index, (mlme_device_descriptor_t *) set_req->value_pointer, rf_mac_setup) != 0) {
return -1;
}
return mac_sec_mib_device_description_set(set_req->attr_index, (mlme_device_descriptor_t *) set_req->value_pointer, rf_mac_setup);
mac_mlme_trig_pending_ack(rf_mac_setup, (mlme_device_descriptor_t *) set_req->value_pointer);
return 0;
}
static int8_t mac_mlme_device_pending_ack_trig(protocol_interface_rf_mac_setup_s *rf_mac_setup, const mlme_set_t *set_req)
{
if (set_req->value_size != sizeof(mlme_device_descriptor_t)) {
return -1;
}
mac_mlme_trig_pending_ack(rf_mac_setup, (mlme_device_descriptor_t *) set_req->value_pointer);
return 0;
}
static int8_t mac_mlme_key_description_set(protocol_interface_rf_mac_setup_s *rf_mac_setup, const mlme_set_t *set_req)
@ -754,6 +791,8 @@ int8_t mac_mlme_set_req(protocol_interface_rf_mac_setup_s *rf_mac_setup, const m
return mac_mlme_set_ack_wait_duration(rf_mac_setup, set_req);
case macDeviceTable:
return mac_mlme_device_description_set(rf_mac_setup, set_req);
case macDevicePendingAckTrig:
return mac_mlme_device_pending_ack_trig(rf_mac_setup, set_req);
case macKeyTable:
return mac_mlme_key_description_set(rf_mac_setup, set_req);
case macDefaultKeySource:
@ -768,6 +807,10 @@ int8_t mac_mlme_set_req(protocol_interface_rf_mac_setup_s *rf_mac_setup, const m
memcpy(rf_mac_setup->coord_long_address, set_req->value_pointer, 8);
}
return 0;
case macCCAThresholdStart:
pu8 = (uint8_t *) set_req->value_pointer;
mac_cca_thr_init(rf_mac_setup, *pu8, *((int8_t *)pu8 + 1), *((int8_t *)pu8 + 2), *((int8_t *)pu8 + 3));
return 0;
case mac802_15_4Mode:
pu8 = (uint8_t *) set_req->value_pointer;
if (rf_mac_setup->current_mac_mode == *pu8) {
@ -1059,6 +1102,7 @@ void mac_mlme_data_base_deallocate(struct protocol_interface_rf_mac_setup *rf_ma
ns_dyn_mem_free(rf_mac->mac_beacon_payload);
mac_sec_mib_deinit(rf_mac);
mac_cca_thr_deinit(rf_mac);
ns_dyn_mem_free(rf_mac);
}
}

View File

@ -34,6 +34,7 @@
#include "MAC/IEEE802_15_4/mac_mlme.h"
#include "MAC/IEEE802_15_4/mac_filter.h"
#include "MAC/IEEE802_15_4/mac_mcps_sap.h"
#include "MAC/IEEE802_15_4/mac_cca_threshold.h"
#include "MAC/rf_driver_storage.h"
/* Define TX Timeot Period */
@ -45,7 +46,7 @@
#define MIN_FHSS_CSMA_PERIOD_US 5000
static int8_t mac_data_interface_tx_done_cb(protocol_interface_rf_mac_setup_s *rf_ptr, phy_link_tx_status_e status, uint8_t cca_retry, uint8_t tx_retry);
static void mac_sap_cca_fail_cb(protocol_interface_rf_mac_setup_s *rf_ptr);
static void mac_sap_cca_fail_cb(protocol_interface_rf_mac_setup_s *rf_ptr, uint16_t failed_channel);
void mac_csma_param_init(protocol_interface_rf_mac_setup_s *rf_mac_setup)
{
@ -273,7 +274,7 @@ void mac_pd_sap_state_machine(protocol_interface_rf_mac_setup_s *rf_mac_setup)
if (rf_mac_setup->mac_tx_result == MAC_TIMER_CCA) {
if (rf_mac_setup->rf_csma_extension_supported) {
mac_sap_cca_fail_cb(rf_mac_setup);
mac_sap_cca_fail_cb(rf_mac_setup, 0xffff);
return;
}
@ -328,7 +329,7 @@ void mac_pd_sap_state_machine(protocol_interface_rf_mac_setup_s *rf_mac_setup)
}
}
static void mac_sap_cca_fail_cb(protocol_interface_rf_mac_setup_s *rf_ptr)
static void mac_sap_cca_fail_cb(protocol_interface_rf_mac_setup_s *rf_ptr, uint16_t failed_channel)
{
if (rf_ptr->mac_ack_tx_active) {
if (rf_ptr->active_pd_data_request) {
@ -340,6 +341,11 @@ static void mac_sap_cca_fail_cb(protocol_interface_rf_mac_setup_s *rf_ptr)
if (rf_ptr->mac_cca_retry > rf_ptr->macMaxCSMABackoffs || (rf_ptr->active_pd_data_request && rf_ptr->active_pd_data_request->asynch_request)) {
//Send MAC_CCA_FAIL
mac_tx_done_state_set(rf_ptr, MAC_CCA_FAIL);
if (failed_channel != 0xffff && rf_ptr->active_pd_data_request) {
if (failed_channel == rf_ptr->active_pd_data_request->initial_tx_channel) {
mac_cca_threshold_event_send(rf_ptr, failed_channel, CCA_FAILED_DBM);
}
}
} else {
timer_mac_stop(rf_ptr);
mac_csma_BE_update(rf_ptr);
@ -414,7 +420,7 @@ static void mac_data_ack_tx_finish(protocol_interface_rf_mac_setup_s *rf_ptr)
mcps_pending_packet_counter_update_check(rf_ptr, rf_ptr->active_pd_data_request);
//GEN TX failure
mac_sap_cca_fail_cb(rf_ptr);
mac_sap_cca_fail_cb(rf_ptr, 0xffff);
}
}
@ -442,6 +448,11 @@ static int8_t mac_data_interface_tx_done_cb(protocol_interface_rf_mac_setup_s *r
}
if (mac_data_asynch_channel_switch(rf_ptr, rf_ptr->active_pd_data_request)) {
rf_ptr->active_pd_data_request->initial_tx_channel = rf_ptr->mac_channel;
int8_t channel_cca_threshold = mac_cca_thr_get_dbm(rf_ptr, rf_ptr->mac_channel);
if (CCA_FAILED_DBM != channel_cca_threshold) {
rf_ptr->dev_driver->phy_driver->extension(PHY_EXTENSION_SET_CHANNEL_CCA_THRESHOLD, (uint8_t *)&channel_cca_threshold);
}
return PHY_TX_ALLOWED;
}
@ -458,7 +469,7 @@ static int8_t mac_data_interface_tx_done_cb(protocol_interface_rf_mac_setup_s *r
rf_ptr->dev_driver->phy_driver->phy_tail_length, active_buf->tx_time);
// When FHSS TX handle returns -1, transmission of the packet is currently not allowed -> restart CCA timer
if (tx_handle_retval == -1) {
mac_sap_cca_fail_cb(rf_ptr);
mac_sap_cca_fail_cb(rf_ptr, 0xffff);
return PHY_TX_NOT_ALLOWED;
}
// When FHSS TX handle returns -3, we are trying to transmit broadcast packet on unicast channel -> push back
@ -470,6 +481,13 @@ static int8_t mac_data_interface_tx_done_cb(protocol_interface_rf_mac_setup_s *r
mac_tx_done_state_set(rf_ptr, MAC_UNKNOWN_DESTINATION);
return PHY_TX_NOT_ALLOWED;
}
if (rf_ptr->mac_cca_retry == 0 && rf_ptr->active_pd_data_request) {
rf_ptr->active_pd_data_request->initial_tx_channel = rf_ptr->mac_channel;
}
int8_t channel_cca_threshold = mac_cca_thr_get_dbm(rf_ptr, rf_ptr->mac_channel);
if (CCA_FAILED_DBM != channel_cca_threshold) {
rf_ptr->dev_driver->phy_driver->extension(PHY_EXTENSION_SET_CHANNEL_CCA_THRESHOLD, (uint8_t *)&channel_cca_threshold);
}
if (active_buf->csma_periods_left > 0) {
active_buf->csma_periods_left--;
active_buf->tx_time += rf_ptr->multi_cca_interval;
@ -501,7 +519,7 @@ static int8_t mac_data_interface_tx_done_cb(protocol_interface_rf_mac_setup_s *r
rf_ptr->mac_tx_retry += tx_retry;
timer_mac_stop(rf_ptr);
}
uint16_t failed_channel = rf_ptr->mac_channel;
if (rf_ptr->fhss_api && rf_ptr->active_pd_data_request->asynch_request == false) {
/* waiting_ack == false allows FHSS to change back to RX channel after transmission
* tx_completed == true allows FHSS to delete stored failure handles
@ -543,7 +561,7 @@ static int8_t mac_data_interface_tx_done_cb(protocol_interface_rf_mac_setup_s *r
break;
case PHY_LINK_CCA_FAIL:
mac_sap_cca_fail_cb(rf_ptr);
mac_sap_cca_fail_cb(rf_ptr, failed_channel);
break;
case PHY_LINK_CCA_OK:
@ -788,10 +806,16 @@ static int8_t mac_pd_sap_generate_ack(protocol_interface_rf_mac_setup_s *rf_ptr,
return -1;
}
if (mac_sec_mib_device_description_get(rf_ptr, rf_ptr->enhanced_ack_buffer.DstAddr, rf_ptr->enhanced_ack_buffer.fcf_dsn.DstAddrMode, rf_ptr->enhanced_ack_buffer.DstPANId)) {
if (rf_ptr->enhanced_ack_buffer.fcf_dsn.securityEnabled == 0 || rf_ptr->enhanced_ack_buffer.aux_header.securityLevel == 0) {
//Unsecured data will be acked immediately
rf_ptr->ack_tx_possible = true;
} else {
rf_ptr->ack_tx_possible = false;
if (mac_sec_mib_device_description_get(rf_ptr, rf_ptr->enhanced_ack_buffer.DstAddr, rf_ptr->enhanced_ack_buffer.fcf_dsn.DstAddrMode, rf_ptr->enhanced_ack_buffer.DstPANId)) {
rf_ptr->ack_tx_possible = true;
} else {
rf_ptr->ack_tx_possible = false;
}
}
return mcps_generic_ack_build(rf_ptr, true);
@ -898,7 +922,7 @@ int8_t mac_pd_sap_data_cb(void *identifier, arm_phy_sap_msg_t *message)
if (pd_data_ind->data_len < 3) {
return -1;
}
mac_cca_threshold_event_send(rf_ptr, rf_ptr->mac_channel, pd_data_ind->dbm);
mac_fcf_sequence_t fcf_read;
const uint8_t *ptr = mac_header_parse_fcf_dsn(&fcf_read, pd_data_ind->data_ptr);

View File

@ -295,21 +295,6 @@ int8_t mac_sec_mib_device_description_set(uint8_t atribute_index, mlme_device_de
*device_ptr = *device_descriptor;
if (rf_mac_setup->mac_ack_tx_active && !rf_mac_setup->ack_tx_possible &&
device_ptr->PANId == rf_mac_setup->enhanced_ack_buffer.DstPANId) {
//Compare address for pending neigbour add
if (rf_mac_setup->enhanced_ack_buffer.fcf_dsn.DstAddrMode == MAC_ADDR_MODE_16_BIT) {
uint16_t short_id = common_read_16_bit(rf_mac_setup->enhanced_ack_buffer.DstAddr);
if (short_id == device_ptr->ShortAddress) {
rf_mac_setup->ack_tx_possible = true;
}
} else if (rf_mac_setup->enhanced_ack_buffer.fcf_dsn.DstAddrMode == MAC_ADDR_MODE_64_BIT) {
if (memcmp(device_ptr->ExtAddress, rf_mac_setup->enhanced_ack_buffer.DstAddr, 8) == 0) {
rf_mac_setup->ack_tx_possible = true;
}
}
}
platform_exit_critical();
return 0;

View File

@ -22,6 +22,7 @@
#include "nsdynmemLIB.h"
#include "common_functions.h"
#include "MAC/rf_driver_storage.h"
#include "Core/include/ns_monitor.h"
typedef struct eth_mac_internal_s {
eth_mac_api_t *mac_api;
@ -269,6 +270,11 @@ static int8_t eth_mac_net_phy_rx(const uint8_t *data_ptr, uint16_t data_len, uin
return -1;
}
if (!ns_monitor_packet_allocation_allowed()) {
// stack can not handle new packets for routing
return -1;
}
eth_data_ind_t *data_ind = ns_dyn_mem_temporary_alloc(sizeof(eth_data_ind_t));
if (!data_ind) {
return -1;

View File

@ -23,6 +23,7 @@
#include "common_functions.h"
#include "ns_trace.h"
#include "MAC/rf_driver_storage.h"
#include "Core/include/ns_monitor.h"
#define TRACE_GROUP "seMa"
@ -317,10 +318,16 @@ static int8_t serial_mac_net_phy_rx(const uint8_t *data_ptr, uint16_t data_len,
(void)link_quality;
(void) dbm;
if (!ns_monitor_packet_allocation_allowed()) {
// stack can not handle new packets for routing
return -1;
}
serial_data_ind_t *data_ind = ns_dyn_mem_temporary_alloc(sizeof(serial_data_ind_t));
if (!data_ind) {
return -1;
}
data_ind->msdu = ns_dyn_mem_temporary_alloc(data_len);
if (!data_ind->msdu) {
ns_dyn_mem_free(data_ind);

View File

@ -391,7 +391,7 @@ static void rpl_control_addr_notifier(struct protocol_interface_info_entry *inte
}
}
static void rpl_control_etx_change_callback(int8_t nwk_id, uint16_t previous_etx, uint16_t current_etx, uint8_t attribute_index)
static void rpl_control_etx_change_callback(int8_t nwk_id, uint16_t previous_etx, uint16_t current_etx, uint8_t attribute_index, const uint8_t *mac64)
{
protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(nwk_id);
@ -405,14 +405,29 @@ static void rpl_control_etx_change_callback(int8_t nwk_id, uint16_t previous_et
uint16_t delay = rpl_policy_etx_change_parent_selection_delay(domain);
tr_debug("Triggering parent selection due to ETX %s on neigh index %u, etx %u", better ? "better" : "worse", attribute_index, current_etx);
rpl_dodag_t *dodag = NULL;
//Define Link Local Address
uint8_t ll_parent_address[16];
memcpy(ll_parent_address, ADDR_LINK_LOCAL_PREFIX, 8);
memcpy(ll_parent_address + 8, mac64, 8);
ll_parent_address[8] ^= 2;
ns_list_foreach(rpl_instance_t, instance, &domain->instances) {
if (better) {
dodag = rpl_instance_current_dodag(instance);
}
rpl_instance_trigger_parent_selection(instance, delay, dodag);
if (rpl_instance_am_root(instance)) {
rpl_downward_paths_invalidate(instance);
} else {
if (better) {
//Only react here for candidate updates and when DODAG version is configured
if (rpl_instance_address_is_candidate(instance, ll_parent_address, 0)) {
dodag = rpl_instance_current_dodag(instance);
if (dodag) {
rpl_instance_trigger_parent_selection(instance, delay, dodag);
}
}
} else if (rpl_instance_address_is_parent(instance, ll_parent_address)) {
//Quick reaction for selected parent only
rpl_instance_trigger_parent_selection(instance, delay, NULL);
}
}
}
}
@ -1886,6 +1901,11 @@ static void rpl_domain_print(const rpl_domain_t *domain, route_print_fn_t *print
}
}
uint16_t rpl_control_route_table_get(struct rpl_instance *instance, uint8_t *prefix, rpl_route_info_t *output_table, uint16_t output_table_len)
{
return rpl_downward_route_table_get(instance, prefix, output_table, output_table_len);
}
void rpl_control_print(route_print_fn_t *print_fn)
{
unsigned t = protocol_core_monotonic_time % 10;

View File

@ -44,6 +44,10 @@ typedef void rpl_prefix_callback_t(struct prefix_entry_t *prefix, void *handle,
typedef bool rpl_new_parent_callback_t(uint8_t *ll_parent_address, void *handle, struct rpl_instance *instance, uint16_t candidate_rank);
typedef struct rpl_route_info {
uint8_t node[8]; /* IID of parent in parent child relation table */
uint8_t parent[8]; /* IID of child in parent child relation table */
} rpl_route_info_t;
typedef struct rpl_domain {
NS_LIST_HEAD_INCOMPLETE(struct rpl_instance) instances;
@ -186,6 +190,7 @@ ipv6_route_predicate_fn_t *rpl_control_get_route_predicate(rpl_domain_t *domain,
/* Diagnostic APIs */
void rpl_control_print(route_print_fn_t *print_fn);
uint16_t rpl_control_route_table_get(struct rpl_instance *instance, uint8_t *prefix, rpl_route_info_t *output_table, uint16_t output_table_len);
struct rpl_instance *rpl_control_enumerate_instances(rpl_domain_t *domain, struct rpl_instance *instance);
struct rpl_instance *rpl_control_lookup_instance(rpl_domain_t *domain, uint8_t instance_id, const uint8_t *dodagid);

View File

@ -1754,6 +1754,52 @@ void rpl_downward_print_instance(rpl_instance_t *instance, route_print_fn_t *pri
}
}
uint16_t rpl_downward_route_table_get(rpl_instance_t *instance, uint8_t *prefix, rpl_route_info_t *output_table, uint16_t output_table_len)
{
uint16_t index = 0;
if (!prefix || !output_table || !output_table_len) {
return 0;
}
if (ns_list_is_empty(&instance->dao_targets)) {
return 0;
}
if (!rpl_instance_am_root(instance)) {
// Question should this be available also for non roots in storing mode
return 0;
}
#ifdef HAVE_RPL_ROOT
rpl_downward_compute_paths(instance);
ns_list_foreach(rpl_dao_target_t, target, &instance->dao_targets) {
if (memcmp(target->prefix, prefix, 8) != 0) {
continue;
}
if (target->root) {
/* Target has root structure
* We take the first transit only from table as simple topology is needed
*/
rpl_dao_root_transit_t *transit = ns_list_get_first(&target->info.root.transits);
if (transit) {
memcpy(output_table->node, &target->prefix[8], 8);
memcpy(output_table->parent, &transit->transit[8], 8);
index++;
if (index == output_table_len) {
//table is full
return index;
}
output_table++;
}
}
/* We dont put non roots to list so border router is not visible as a node in list*/
}
#endif
return index;
}
rpl_dao_target_t *rpl_instance_get_active_target_confirmation(rpl_instance_t *instance)
{
ns_list_foreach_safe(rpl_dao_target_t, n, &instance->dao_targets) {

View File

@ -27,6 +27,7 @@ struct rpl_dao_root_transit;
void rpl_downward_dao_slow_timer(struct rpl_instance *instance, uint16_t seconds);
void rpl_downward_dao_timer(struct rpl_instance *instance, uint16_t ticks);
void rpl_downward_print_instance(struct rpl_instance *instance, route_print_fn_t *print_fn);
uint16_t rpl_downward_route_table_get(rpl_instance_t *instance, uint8_t *prefix, rpl_route_info_t *output_table, uint16_t output_table_len);
void rpl_downward_convert_dodag_preferences_to_dao_path_control(struct rpl_dodag *dodag);
void rpl_downward_process_dao_parent_changes(struct rpl_instance *instance);

View File

@ -99,7 +99,7 @@ static void kmp_sec_prot_receive_disable(sec_prot_t *prot);
#define kmp_api_get_from_prot(prot) (kmp_api_t *)(((uint8_t *)prot) - offsetof(kmp_api_t, sec_prot));
kmp_api_t *kmp_api_create(kmp_service_t *service, kmp_type_e type, sec_prot_cfg_t *cfg)
kmp_api_t *kmp_api_create(kmp_service_t *service, kmp_type_e type, sec_prot_cfg_t *prot_cfg, sec_timer_cfg_t *timer_cfg)
{
if (!service) {
return 0;
@ -151,7 +151,8 @@ kmp_api_t *kmp_api_create(kmp_service_t *service, kmp_type_e type, sec_prot_cfg_
kmp->sec_prot.addr_get = kmp_sec_prot_eui64_addr_get;
kmp->sec_prot.type_get = kmp_sec_prot_by_type_get;
kmp->sec_prot.receive_disable = kmp_sec_prot_receive_disable;
kmp->sec_prot.cfg = cfg;
kmp->sec_prot.prot_cfg = prot_cfg;
kmp->sec_prot.timer_cfg = timer_cfg;
if (sec_prot->init(&kmp->sec_prot) < 0) {
ns_dyn_mem_free(kmp);

View File

@ -125,12 +125,13 @@ typedef void kmp_api_finished(kmp_api_t *kmp);
*
* \param service KMP service
* \param type KMP type
* \param cfg configuration
* \param prot_cfg protocol configuration
* \param timer_cfg timer configuration
*
* \return KMP instance or NULL
*
*/
kmp_api_t *kmp_api_create(kmp_service_t *service, kmp_type_e type, sec_prot_cfg_t *cfg);
kmp_api_t *kmp_api_create(kmp_service_t *service, kmp_type_e type, sec_prot_cfg_t *prot_cfg, sec_timer_cfg_t *timer_cfg);
/**
* kmp_api_start start KMP api

View File

@ -189,7 +189,7 @@ static int8_t auth_eap_tls_sec_prot_receive(sec_prot_t *prot, void *pdu, uint16_
// Call state machine
prot->state_machine(prot);
// Resets trickle timer to give time for supplicant to answer
sec_prot_timer_trickle_start(&data->common, &prot->cfg->sec_prot_trickle_params);
sec_prot_timer_trickle_start(&data->common, &prot->prot_cfg->sec_prot_trickle_params);
data->init_key_cnt++;
}
// Filters repeated initial EAPOL-key messages
@ -297,7 +297,7 @@ static void auth_eap_tls_sec_prot_timer_timeout(sec_prot_t *prot, uint16_t ticks
}
sec_prot_timer_timeout_handle(prot, &data->common,
&prot->cfg->sec_prot_trickle_params, ticks);
&prot->prot_cfg->sec_prot_trickle_params, ticks);
}
static void auth_eap_tls_sec_prot_tls_create_indication(sec_prot_t *tls_prot)
@ -421,7 +421,7 @@ static void auth_eap_tls_sec_prot_state_machine(sec_prot_t *prot)
auth_eap_tls_sec_prot_message_send(prot, EAP_REQ, EAP_IDENTITY, EAP_TLS_EXCHANGE_NONE);
// Start trickle timer to re-send if no response
sec_prot_timer_trickle_start(&data->common, &prot->cfg->sec_prot_trickle_params);
sec_prot_timer_trickle_start(&data->common, &prot->prot_cfg->sec_prot_trickle_params);
sec_prot_state_set(prot, &data->common, EAP_TLS_STATE_RESPONSE_ID);
break;
@ -445,7 +445,7 @@ static void auth_eap_tls_sec_prot_state_machine(sec_prot_t *prot)
auth_eap_tls_sec_prot_message_send(prot, EAP_REQ, EAP_TLS, EAP_TLS_EXCHANGE_START);
// Start trickle timer to re-send if no response
sec_prot_timer_trickle_start(&data->common, &prot->cfg->sec_prot_trickle_params);
sec_prot_timer_trickle_start(&data->common, &prot->prot_cfg->sec_prot_trickle_params);
sec_prot_state_set(prot, &data->common, EAP_TLS_STATE_RESPONSE_START);
break;
@ -527,7 +527,7 @@ static void auth_eap_tls_sec_prot_state_machine(sec_prot_t *prot)
auth_eap_tls_sec_prot_message_send(prot, EAP_REQ, EAP_TLS, EAP_TLS_EXCHANGE_ONGOING);
// Start trickle timer to re-send if no response
sec_prot_timer_trickle_start(&data->common, &prot->cfg->sec_prot_trickle_params);
sec_prot_timer_trickle_start(&data->common, &prot->prot_cfg->sec_prot_trickle_params);
} else {
// TLS done, indicate success to peer
if (data->tls_result == EAP_TLS_RESULT_HANDSHAKE_OVER) {

View File

@ -404,7 +404,7 @@ static void supp_eap_tls_sec_prot_state_machine(sec_prot_t *prot)
}
// Set retry timeout based on network size
data->common.ticks = prot->cfg->sec_prot_retry_timeout;
data->common.ticks = prot->prot_cfg->sec_prot_retry_timeout;
// Store sequence ID
supp_eap_tls_sec_prot_seq_id_update(prot);
@ -449,7 +449,7 @@ static void supp_eap_tls_sec_prot_state_machine(sec_prot_t *prot)
supp_eap_tls_sec_prot_seq_id_update(prot);
sec_prot_state_set(prot, &data->common, EAP_TLS_STATE_REQUEST);
data->common.ticks = prot->cfg->sec_prot_retry_timeout;
data->common.ticks = prot->prot_cfg->sec_prot_retry_timeout;
// Initialize TLS protocol
if (supp_eap_tls_sec_prot_init_tls(prot) < 0) {
@ -483,7 +483,7 @@ static void supp_eap_tls_sec_prot_state_machine(sec_prot_t *prot)
// Store sequence ID
if (supp_eap_tls_sec_prot_seq_id_update(prot)) {
// When receiving a new sequence number, adds more time for re-send if no response
data->common.ticks = prot->cfg->sec_prot_retry_timeout;
data->common.ticks = prot->prot_cfg->sec_prot_retry_timeout;
}
// All fragments received for a message

View File

@ -66,6 +66,7 @@ typedef struct {
fwh_sec_prot_msg_e recv_msg; /**< Received message */
uint8_t nonce[EAPOL_KEY_NONCE_LEN]; /**< Authenticator nonce */
uint8_t new_ptk[PTK_LEN]; /**< PTK (384 bits) */
uint8_t remote_eui64[8]; /**< Remote EUI-64 used to calculate PTK */
void *recv_pdu; /**< received pdu */
uint16_t recv_size; /**< received pdu size */
} fwh_sec_prot_int_t;
@ -265,14 +266,20 @@ static int8_t auth_fwh_sec_prot_message_send(sec_prot_t *prot, fwh_sec_prot_msg_
switch (msg) {
case FWH_MESSAGE_1:
sec_prot_keys_pmk_replay_cnt_increment(prot->sec_keys);
if (!sec_prot_keys_pmk_replay_cnt_increment(prot->sec_keys)) {
ns_dyn_mem_free(kde_start);
return 1;
}
eapol_pdu.msg.key.replay_counter = sec_prot_keys_pmk_replay_cnt_get(prot->sec_keys);
eapol_pdu.msg.key.key_information.key_ack = true;
eapol_pdu.msg.key.key_length = EAPOL_KEY_LEN;
eapol_pdu.msg.key.key_nonce = data->nonce;
break;
case FWH_MESSAGE_3:
sec_prot_keys_pmk_replay_cnt_increment(prot->sec_keys);
if (!sec_prot_keys_pmk_replay_cnt_increment(prot->sec_keys)) {
ns_dyn_mem_free(kde_start);
return -1;
}
eapol_pdu.msg.key.replay_counter = sec_prot_keys_pmk_replay_cnt_get(prot->sec_keys);
eapol_pdu.msg.key.key_information.install = true;
eapol_pdu.msg.key.key_information.key_ack = true;
@ -306,7 +313,7 @@ static int8_t auth_fwh_sec_prot_message_send(sec_prot_t *prot, fwh_sec_prot_msg_
static void auth_fwh_sec_prot_timer_timeout(sec_prot_t *prot, uint16_t ticks)
{
fwh_sec_prot_int_t *data = fwh_sec_prot_get(prot);
sec_prot_timer_timeout_handle(prot, &data->common, &prot->cfg->sec_prot_trickle_params, ticks);
sec_prot_timer_timeout_handle(prot, &data->common, &prot->prot_cfg->sec_prot_trickle_params, ticks);
}
static void auth_fwh_sec_prot_state_machine(sec_prot_t *prot)
@ -343,7 +350,7 @@ static void auth_fwh_sec_prot_state_machine(sec_prot_t *prot)
auth_fwh_sec_prot_message_send(prot, FWH_MESSAGE_1);
// Start trickle timer to re-send if no response
sec_prot_timer_trickle_start(&data->common, &prot->cfg->sec_prot_trickle_params);
sec_prot_timer_trickle_start(&data->common, &prot->prot_cfg->sec_prot_trickle_params);
sec_prot_state_set(prot, &data->common, FWH_STATE_MESSAGE_2);
break;
@ -371,7 +378,7 @@ static void auth_fwh_sec_prot_state_machine(sec_prot_t *prot)
auth_fwh_sec_prot_message_send(prot, FWH_MESSAGE_3);
// Start trickle timer to re-send if no response
sec_prot_timer_trickle_start(&data->common, &prot->cfg->sec_prot_trickle_params);
sec_prot_timer_trickle_start(&data->common, &prot->prot_cfg->sec_prot_trickle_params);
sec_prot_state_set(prot, &data->common, FWH_STATE_MESSAGE_4);
}
@ -391,12 +398,16 @@ static void auth_fwh_sec_prot_state_machine(sec_prot_t *prot)
}
// PTK is fresh for installing any GTKs
sec_prot_keys_ptk_installed_gtk_hash_clear_all(prot->sec_keys);
/* Store the hash for to-be installed GTK as used for the PTK, on 4WH
this stores only the hash in NVM and does not affect otherwise */
sec_prot_keys_ptk_installed_gtk_hash_set(prot->sec_keys, true);
// If GTK was inserted set it valid
sec_prot_keys_gtkl_from_gtk_insert_index_set(prot->sec_keys);
// Reset PTK mismatch
sec_prot_keys_ptk_mismatch_reset(prot->sec_keys);
// Update PTK
sec_prot_keys_ptk_write(prot->sec_keys, data->new_ptk);
sec_prot_keys_ptk_write(prot->sec_keys, data->new_ptk, prot->timer_cfg->ptk_lifetime);
sec_prot_keys_ptk_eui_64_write(prot->sec_keys, data->remote_eui64);
sec_prot_state_set(prot, &data->common, FWH_STATE_FINISH);
}
break;
@ -427,9 +438,7 @@ static int8_t auth_fwh_sec_prot_ptk_generate(sec_prot_t *prot, sec_prot_keys_t *
fwh_sec_prot_int_t *data = fwh_sec_prot_get(prot);
uint8_t local_eui64[8];
uint8_t remote_eui64[8];
prot->addr_get(prot, local_eui64, remote_eui64);
prot->addr_get(prot, local_eui64, data->remote_eui64);
uint8_t *remote_nonce = data->recv_eapol_pdu.msg.key.key_nonce;
if (!remote_nonce) {
@ -438,7 +447,7 @@ static int8_t auth_fwh_sec_prot_ptk_generate(sec_prot_t *prot, sec_prot_keys_t *
}
uint8_t *pmk = sec_prot_keys_pmk_get(sec_keys);
sec_prot_lib_ptk_calc(pmk, local_eui64, remote_eui64, data->nonce, remote_nonce, data->new_ptk);
sec_prot_lib_ptk_calc(pmk, local_eui64, data->remote_eui64, data->nonce, remote_nonce, data->new_ptk);
return 0;
}

View File

@ -139,7 +139,7 @@ static int8_t supp_fwh_sec_prot_init(sec_prot_t *prot)
sec_prot_init(&data->common);
sec_prot_state_set(prot, &data->common, FWH_STATE_INIT);
data->common.ticks = prot->cfg->sec_prot_retry_timeout;
data->common.ticks = prot->prot_cfg->sec_prot_retry_timeout;
data->msg3_received = false;
data->msg3_retry_wait = false;
data->recv_replay_cnt = 0;
@ -337,7 +337,7 @@ static void supp_fwh_sec_prot_state_machine(sec_prot_t *prot)
if (sec_prot_result_ok_check(&data->common)) {
// Send 4WH message 2
supp_fwh_sec_prot_message_send(prot, FWH_MESSAGE_2);
data->common.ticks = prot->cfg->sec_prot_retry_timeout;
data->common.ticks = prot->prot_cfg->sec_prot_retry_timeout;
sec_prot_state_set(prot, &data->common, FWH_STATE_MESSAGE_3);
} else {
// Ready to be deleted
@ -365,7 +365,7 @@ static void supp_fwh_sec_prot_state_machine(sec_prot_t *prot)
// Send 4WH message 2
supp_fwh_sec_prot_message_send(prot, FWH_MESSAGE_2);
data->common.ticks = prot->cfg->sec_prot_retry_timeout;
data->common.ticks = prot->prot_cfg->sec_prot_retry_timeout;
return;
} else if (data->recv_msg != FWH_MESSAGE_3) {
return;
@ -392,7 +392,7 @@ static void supp_fwh_sec_prot_state_machine(sec_prot_t *prot)
// Sends 4WH Message 4
supp_fwh_sec_prot_message_send(prot, FWH_MESSAGE_4);
data->common.ticks = prot->cfg->sec_prot_retry_timeout;
data->common.ticks = prot->prot_cfg->sec_prot_retry_timeout;
sec_prot_state_set(prot, &data->common, FWH_STATE_FINISH);
break;
@ -409,7 +409,7 @@ static void supp_fwh_sec_prot_state_machine(sec_prot_t *prot)
tr_info("4WH: finish, wait Message 3 retry");
sec_prot_keys_ptk_write(prot->sec_keys, data->new_ptk);
sec_prot_keys_ptk_write(prot->sec_keys, data->new_ptk, prot->timer_cfg->ptk_lifetime);
sec_prot_keys_ptk_eui_64_write(prot->sec_keys, data->remote_eui64);
data->common.ticks = 60 * 10; // 60 seconds

View File

@ -226,7 +226,10 @@ static int8_t auth_gkh_sec_prot_message_send(sec_prot_t *prot, gkh_sec_prot_msg_
switch (msg) {
case GKH_MESSAGE_1:
sec_prot_keys_pmk_replay_cnt_increment(prot->sec_keys);
if (!sec_prot_keys_pmk_replay_cnt_increment(prot->sec_keys)) {
ns_dyn_mem_free(kde_start);
return -1;
}
eapol_pdu.msg.key.replay_counter = sec_prot_keys_pmk_replay_cnt_get(prot->sec_keys);
eapol_pdu.msg.key.key_information.key_ack = true;
eapol_pdu.msg.key.key_information.key_mic = true;
@ -258,7 +261,7 @@ static int8_t auth_gkh_sec_prot_message_send(sec_prot_t *prot, gkh_sec_prot_msg_
static void auth_gkh_sec_prot_timer_timeout(sec_prot_t *prot, uint16_t ticks)
{
gkh_sec_prot_int_t *data = gkh_sec_prot_get(prot);
sec_prot_timer_timeout_handle(prot, &data->common, &prot->cfg->sec_prot_trickle_params, ticks);
sec_prot_timer_timeout_handle(prot, &data->common, &prot->prot_cfg->sec_prot_trickle_params, ticks);
}
static void auth_gkh_sec_prot_state_machine(sec_prot_t *prot)
@ -283,16 +286,16 @@ static void auth_gkh_sec_prot_state_machine(sec_prot_t *prot)
// KMP-CREATE.confirm
prot->create_conf(prot, SEC_RESULT_OK);
// Sends 4WH Message 1
// Sends GKH Message 1
auth_gkh_sec_prot_message_send(prot, GKH_MESSAGE_1);
// Start trickle timer to re-send if no response
sec_prot_timer_trickle_start(&data->common, &prot->cfg->sec_prot_trickle_params);
sec_prot_timer_trickle_start(&data->common, &prot->prot_cfg->sec_prot_trickle_params);
sec_prot_state_set(prot, &data->common, GKH_STATE_MESSAGE_2);
// Store the hash for to-be installed GTK as used for the PTK
sec_prot_keys_ptk_installed_gtk_hash_set(prot->sec_keys);
sec_prot_keys_ptk_installed_gtk_hash_set(prot->sec_keys, false);
break;
// Wait GKH message 2

View File

@ -268,6 +268,7 @@ static int8_t key_sec_prot_receive(sec_prot_t *prot, void *pdu, uint16_t size)
// Checks if supplicant indicates that it has valid PMK
uint8_t remote_keyid[KEYID_LEN];
if (kde_pmkid_read(kde, kde_len, remote_keyid) >= 0) {
tr_debug("recv PMKID: %s", trace_array(remote_keyid, 16));
uint8_t pmkid[PMKID_LEN];
if (sec_prot_lib_pmkid_generate(prot, pmkid, true) >= 0) {
if (memcmp(remote_keyid, pmkid, PMKID_LEN) == 0) {
@ -278,6 +279,7 @@ static int8_t key_sec_prot_receive(sec_prot_t *prot, void *pdu, uint16_t size)
// Checks if supplicant indicates that it has valid PTK
if (kde_ptkid_read(kde, kde_len, remote_keyid) >= 0) {
tr_debug("recv PTKID: %s", trace_array(remote_keyid, 16));
uint8_t ptkid[PTKID_LEN];
if (sec_prot_lib_ptkid_generate(prot, ptkid, true) >= 0) {
if (memcmp(remote_keyid, ptkid, PTKID_LEN) == 0) {

View File

@ -268,7 +268,8 @@ struct sec_prot_s {
sec_prot_receive_disable *receive_disable; /**< Disable receiving of messages */
sec_prot_keys_t *sec_keys; /**< Security keys storage pointer */
sec_prot_cfg_t *cfg; /**< Configuration pointer */
sec_prot_cfg_t *prot_cfg; /**< Security protocol configuration pointer */
sec_timer_cfg_t *timer_cfg; /**< Security timer configuration pointer */
uint8_t header_size; /**< Header size */
sec_prot_int_data_t *data; /**< Protocol internal data */
};

View File

@ -54,7 +54,7 @@ typedef struct {
typedef NS_LIST_HEAD(cert_chain_entry_t, link) cert_chain_list_t;
typedef NS_LIST_HEAD(cert_revocat_list_entry_t, link) cert_revocat_lists_t;
typedef struct {
typedef struct sec_prot_certs_s {
cert_chain_entry_t own_cert_chain; /**< Own certificate chain */
cert_chain_list_t trusted_cert_chain_list; /**< Trusted certificate chain lists */
cert_revocat_lists_t cert_revocat_lists; /**< Certificate Revocation Lists */

View File

@ -24,6 +24,23 @@ typedef struct sec_prot_cfg_s {
trickle_params_t sec_prot_trickle_params;
uint16_t sec_prot_retry_timeout;
uint16_t sec_max_ongoing_authentication;
uint16_t initial_key_retry_delay;
trickle_params_t initial_key_trickle_params;
uint8_t initial_key_retry_cnt;
} sec_prot_cfg_t;
/* Security timer configuration settings */
typedef struct sec_timer_cfg_s {
uint32_t gtk_expire_offset; /* GTK lifetime; GTK_EXPIRE_OFFSET (seconds) */
uint32_t pmk_lifetime; /* PMK lifetime (seconds) */
uint32_t ptk_lifetime; /* PTK lifetime (seconds) */
uint16_t gtk_new_act_time; /* GTK_NEW_ACTIVATION_TIME (1/X of expire offset) */
uint16_t revocat_lifetime_reduct; /* REVOCATION_LIFETIME_REDUCTION (reduction of lifetime) */
uint16_t gtk_request_imin; /* GTK_REQUEST_IMIN (seconds) */
uint16_t gtk_request_imax; /* GTK_REQUEST_IMAX (seconds) */
uint16_t gtk_max_mismatch; /* GTK_MAX_MISMATCH (seconds) */
uint8_t gtk_new_install_req; /* GTK_NEW_INSTALL_REQUIRED (percent of GTK lifetime) */
} sec_timer_cfg_t;
#endif /* SEC_PROT_CONF_H_ */

View File

@ -56,8 +56,8 @@ sec_prot_keys_t *sec_prot_keys_create(sec_prot_gtk_keys_t *gtks, const sec_prot_
void sec_prot_keys_init(sec_prot_keys_t *sec_keys, sec_prot_gtk_keys_t *gtks, const sec_prot_certs_t *certs)
{
memset(sec_keys, 0, sizeof(sec_prot_keys_t));
sec_keys->pmk_lifetime = PMK_LIFETIME_INSTALL;
sec_keys->ptk_lifetime = PTK_LIFETIME_INSTALL;
sec_keys->pmk_lifetime = 0;
sec_keys->ptk_lifetime = 0;
sec_keys->pmk_key_replay_cnt = 0;
sec_keys->gtks = gtks;
sec_keys->certs = certs;
@ -101,12 +101,12 @@ void sec_prot_keys_gtks_delete(sec_prot_gtk_keys_t *gtks)
ns_dyn_mem_free(gtks);
}
void sec_prot_keys_pmk_write(sec_prot_keys_t *sec_keys, uint8_t *pmk)
void sec_prot_keys_pmk_write(sec_prot_keys_t *sec_keys, uint8_t *pmk, uint32_t pmk_lifetime)
{
memcpy(sec_keys->pmk, pmk, PMK_LEN);
sec_keys->pmk_key_replay_cnt = 0;
sec_keys->pmk_key_replay_cnt_set = false;
sec_keys->pmk_lifetime = PMK_LIFETIME_INSTALL;
sec_keys->pmk_lifetime = pmk_lifetime;
sec_keys->pmk_set = true;
sec_keys->updated = true;
}
@ -116,7 +116,7 @@ void sec_prot_keys_pmk_delete(sec_prot_keys_t *sec_keys)
memset(sec_keys->pmk, 0, PMK_LEN);
sec_keys->pmk_key_replay_cnt = 0;
sec_keys->pmk_key_replay_cnt_set = false;
sec_keys->pmk_lifetime = PMK_LIFETIME_INSTALL;
sec_keys->pmk_lifetime = 0;
sec_keys->pmk_set = false;
sec_keys->updated = true;
}
@ -130,6 +130,15 @@ uint8_t *sec_prot_keys_pmk_get(sec_prot_keys_t *sec_keys)
return sec_keys->pmk;
}
uint32_t sec_prot_keys_pmk_lifetime_get(sec_prot_keys_t *sec_keys)
{
if (!sec_keys->pmk_set) {
return 0;
}
return sec_keys->pmk_lifetime;
}
uint64_t sec_prot_keys_pmk_replay_cnt_get(sec_prot_keys_t *sec_keys)
{
return sec_keys->pmk_key_replay_cnt;
@ -140,15 +149,20 @@ void sec_prot_keys_pmk_replay_cnt_set(sec_prot_keys_t *sec_keys, uint64_t counte
sec_keys->pmk_key_replay_cnt_set = true;
sec_keys->pmk_key_replay_cnt = counter;
}
void sec_prot_keys_pmk_replay_cnt_increment(sec_prot_keys_t *sec_keys)
bool sec_prot_keys_pmk_replay_cnt_increment(sec_prot_keys_t *sec_keys)
{
// Start from zero i.e. does not increment on first call
if (!sec_keys->pmk_key_replay_cnt_set) {
sec_keys->pmk_key_replay_cnt_set = true;
return;
return true;
}
// If counter is near to exhaust return error (ignores MSB 32bits which are re-start counter)
if ((sec_keys->pmk_key_replay_cnt & PMK_KEY_REPLAY_CNT_LIMIT_MASK) > PMK_KEY_REPLAY_CNT_LIMIT) {
sec_keys->pmk_key_replay_cnt |= 0xFFFF; // Invalidate counter; will result removal of keys
return false;
}
sec_keys->pmk_key_replay_cnt++;
return true;
}
bool sec_prot_keys_pmk_replay_cnt_compare(uint64_t received_counter, sec_prot_keys_t *sec_keys)
@ -179,16 +193,12 @@ bool sec_prot_keys_pmk_mismatch_is_set(sec_prot_keys_t *sec_keys)
return sec_keys->pmk_mismatch;
}
bool sec_prot_keys_pmk_lifetime_decrement(sec_prot_keys_t *sec_keys, uint32_t default_lifetime, uint8_t seconds)
bool sec_prot_keys_pmk_lifetime_decrement(sec_prot_keys_t *sec_keys, uint8_t seconds)
{
if (!sec_keys->pmk_set) {
return false;
}
if (sec_keys->pmk_lifetime == PMK_LIFETIME_INSTALL) {
sec_keys->pmk_lifetime = default_lifetime;
}
if (sec_keys->pmk_lifetime > seconds) {
sec_keys->pmk_lifetime -= seconds;
} else {
@ -202,10 +212,10 @@ bool sec_prot_keys_pmk_lifetime_decrement(sec_prot_keys_t *sec_keys, uint32_t de
return false;
}
void sec_prot_keys_ptk_write(sec_prot_keys_t *sec_keys, uint8_t *ptk)
void sec_prot_keys_ptk_write(sec_prot_keys_t *sec_keys, uint8_t *ptk, uint32_t ptk_lifetime)
{
memcpy(sec_keys->ptk, ptk, PTK_LEN);
sec_keys->ptk_lifetime = PTK_LIFETIME_INSTALL;
sec_keys->ptk_lifetime = ptk_lifetime;
sec_keys->ptk_set = true;
sec_keys->updated = true;
}
@ -213,7 +223,7 @@ void sec_prot_keys_ptk_write(sec_prot_keys_t *sec_keys, uint8_t *ptk)
void sec_prot_keys_ptk_delete(sec_prot_keys_t *sec_keys)
{
memset(sec_keys->ptk, 0, PTK_LEN);
sec_keys->ptk_lifetime = PTK_LIFETIME_INSTALL;
sec_keys->ptk_lifetime = 0;
sec_keys->ptk_set = false;
sec_keys->updated = true;
}
@ -227,6 +237,15 @@ uint8_t *sec_prot_keys_ptk_get(sec_prot_keys_t *sec_keys)
return sec_keys->ptk;
}
uint32_t sec_prot_keys_ptk_lifetime_get(sec_prot_keys_t *sec_keys)
{
if (!sec_keys->ptk_set) {
return 0;
}
return sec_keys->ptk_lifetime;
}
void sec_prot_keys_ptk_mismatch_set(sec_prot_keys_t *sec_keys)
{
sec_keys->ptk_mismatch = true;
@ -265,16 +284,12 @@ void sec_prot_keys_ptk_eui_64_delete(sec_prot_keys_t *sec_keys)
sec_keys->updated = true;
}
bool sec_prot_keys_ptk_lifetime_decrement(sec_prot_keys_t *sec_keys, uint32_t default_lifetime, uint8_t seconds)
bool sec_prot_keys_ptk_lifetime_decrement(sec_prot_keys_t *sec_keys, uint8_t seconds)
{
if (!sec_keys->ptk_set) {
return false;
}
if (sec_keys->ptk_lifetime == PTK_LIFETIME_INSTALL) {
sec_keys->ptk_lifetime = default_lifetime;
}
if (sec_keys->ptk_lifetime > seconds) {
sec_keys->ptk_lifetime -= seconds;
} else {
@ -380,8 +395,11 @@ int8_t sec_prot_keys_gtk_insert_index_from_gtkl_get(sec_prot_keys_t *sec_keys)
// Checks all keys
for (uint8_t i = 0; i < GTK_NUM; i++) {
if (sec_prot_keys_gtk_status_is_live(sec_keys->gtks, i)) {
// If key is live, but not indicated on GTKL inserts it
if (sec_prot_keys_gtk_status_is_live(sec_keys->gtks, i) ||
sec_prot_keys_gtk_status_get(sec_keys->gtks, i) == GTK_STATUS_OLD) {
/* If key is live, but not indicated on GTKL inserts it. Also old keys indicated
still on GTK hash are inserted, since supplicants do not know the status of the
key and might need the key for receive (only) from not updated neighbors */
if (!sec_prot_keys_gtkl_gtk_is_live(sec_keys, i)) {
sec_prot_keys_gtk_insert_index_set(sec_keys, i);
return i;
@ -438,6 +456,8 @@ int8_t sec_prot_keys_gtk_clear(sec_prot_gtk_keys_t *gtks, uint8_t index)
gtks->gtk[index].status = GTK_STATUS_NEW;
memset(gtks->gtk[index].key, 0, GTK_LEN);
gtks->updated = true;
sec_prot_keys_gtk_install_order_update(gtks);
return 0;
@ -470,7 +490,7 @@ uint32_t sec_prot_keys_gtk_lifetime_get(sec_prot_gtk_keys_t *gtks, uint8_t index
return gtks->gtk[index].lifetime;
}
uint32_t sec_prot_keys_gtk_lifetime_decrement(sec_prot_gtk_keys_t *gtks, uint8_t index, uint16_t seconds)
uint32_t sec_prot_keys_gtk_lifetime_decrement(sec_prot_gtk_keys_t *gtks, uint8_t index, uint64_t current_time, uint16_t seconds)
{
if (gtks->gtk[index].lifetime > seconds) {
gtks->gtk[index].lifetime -= seconds;
@ -478,9 +498,44 @@ uint32_t sec_prot_keys_gtk_lifetime_decrement(sec_prot_gtk_keys_t *gtks, uint8_t
gtks->gtk[index].lifetime = 0;
}
// Calculates expiration timestamp for GTK from current time and lifetime
uint64_t expirytime = current_time + gtks->gtk[index].lifetime;
uint64_t diff;
// Compares calculated timestamp to stored one
if (gtks->gtk[index].expirytime >= expirytime) {
diff = gtks->gtk[index].expirytime - expirytime;
} else {
diff = expirytime - gtks->gtk[index].expirytime;
}
// If timestamps differ for more than 5 minutes marks field as updated (and stores to NVM)
if (diff > 300) {
gtks->updated = true;
}
return gtks->gtk[index].lifetime;
}
uint64_t sec_prot_keys_gtk_exptime_from_lifetime_get(sec_prot_gtk_keys_t *gtks, uint8_t index, uint64_t current_time)
{
if (index >= GTK_NUM || !gtks->gtk[index].set) {
return 0;
}
uint32_t lifetime = gtks->gtk[index].lifetime;
return current_time + lifetime;
}
int8_t sec_prot_keys_gtk_expirytime_set(sec_prot_gtk_keys_t *gtks, uint8_t index, uint64_t expirytime)
{
if (index >= GTK_NUM || !gtks->gtk[index].set) {
return -1;
}
gtks->gtk[index].expirytime = expirytime;
return 0;
}
bool sec_prot_keys_gtks_are_updated(sec_prot_gtk_keys_t *gtks)
{
return gtks->updated;
@ -505,6 +560,7 @@ void sec_prot_keys_gtk_status_fresh_set(sec_prot_gtk_keys_t *gtks, uint8_t index
// Active key remains as active, old keys are never reused
if (gtks->gtk[index].status < GTK_STATUS_FRESH) {
gtks->gtk[index].status = GTK_STATUS_FRESH;
gtks->updated = true;
}
}
@ -528,9 +584,11 @@ int8_t sec_prot_keys_gtk_status_active_set(sec_prot_gtk_keys_t *gtks, uint8_t in
// Sets previously active key old
if (gtks->gtk[i].status == GTK_STATUS_ACTIVE) {
gtks->gtk[i].status = GTK_STATUS_OLD;
gtks->updated = true;
}
}
gtks->gtk[index].status = GTK_STATUS_ACTIVE;
gtks->updated = true;
return 0;
}
@ -548,6 +606,16 @@ int8_t sec_prot_keys_gtk_status_active_get(sec_prot_gtk_keys_t *gtks)
return -1;
}
int8_t sec_prot_keys_gtk_status_active_to_fresh_set(sec_prot_gtk_keys_t *gtks)
{
int8_t index = sec_prot_keys_gtk_status_active_get(gtks);
if (index < 0) {
return -1;
}
return sec_prot_keys_gtk_status_set(gtks, index, GTK_STATUS_FRESH);
}
bool sec_prot_keys_gtk_status_is_live(sec_prot_gtk_keys_t *gtks, uint8_t index)
{
if (index >= GTK_NUM || !gtks->gtk[index].set) {
@ -567,9 +635,36 @@ void sec_prot_keys_gtk_status_new_set(sec_prot_gtk_keys_t *gtks, uint8_t index)
return;
}
if (gtks->gtk[index].status != GTK_STATUS_NEW) {
gtks->updated = true;
}
gtks->gtk[index].status = GTK_STATUS_NEW;
}
uint8_t sec_prot_keys_gtk_status_get(sec_prot_gtk_keys_t *gtks, uint8_t index)
{
if (index >= GTK_NUM || !gtks->gtk[index].set) {
return 0;
}
return gtks->gtk[index].status;
}
int8_t sec_prot_keys_gtk_status_set(sec_prot_gtk_keys_t *gtks, uint8_t index, uint8_t status)
{
if (index >= GTK_NUM || !gtks->gtk[index].set) {
return -1;
}
if (gtks->gtk[index].status != status) {
gtks->updated = true;
}
gtks->gtk[index].status = status;
return 0;
}
void sec_prot_keys_gtks_hash_generate(sec_prot_gtk_keys_t *gtks, uint8_t *gtkhash)
{
memset(gtkhash, 0, GTK_ALL_HASHES_LEN);
@ -758,6 +853,9 @@ void sec_prot_keys_gtk_install_order_update(sec_prot_gtk_keys_t *gtks)
uint8_t new_install_order = 0;
for (uint8_t i = 0; i < GTK_NUM; i++) {
if (ordered_indexes[i] >= 0) {
if (gtks->gtk[ordered_indexes[i]].install_order != new_install_order) {
gtks->updated = true;
}
gtks->gtk[ordered_indexes[i]].install_order = new_install_order++;
}
}
@ -786,6 +884,29 @@ int8_t sec_prot_keys_gtk_install_index_get(sec_prot_gtk_keys_t *gtks)
return install_index;
}
uint8_t sec_prot_keys_gtk_install_order_get(sec_prot_gtk_keys_t *gtks, uint8_t index)
{
if (index >= GTK_NUM || !gtks->gtk[index].set) {
return 0;
}
return gtks->gtk[index].install_order;
}
int8_t sec_prot_keys_gtk_install_order_set(sec_prot_gtk_keys_t *gtks, uint8_t index, uint8_t install_order)
{
if (index >= GTK_NUM || !gtks->gtk[index].set) {
return -1;
}
if (gtks->gtk[index].install_order != install_order) {
gtks->updated = true;
}
gtks->gtk[index].install_order = install_order;
return 0;
}
uint8_t sec_prot_keys_gtk_count(sec_prot_gtk_keys_t *gtks)
{
uint8_t count = 0;
@ -802,12 +923,13 @@ uint8_t sec_prot_keys_gtk_count(sec_prot_gtk_keys_t *gtks)
void sec_prot_keys_ptk_installed_gtk_hash_clear_all(sec_prot_keys_t *sec_keys)
{
for (uint8_t index = 0; index < GTK_NUM; index++) {
memset(sec_keys->ins_gtk_hash[sec_keys->gtk_set_index].hash, 0, INS_GTK_HASH_LEN);
memset(sec_keys->ins_gtk_hash[index].hash, 0, INS_GTK_HASH_LEN);
}
sec_keys->ins_gtk_hash_set = 0;
sec_keys->ins_gtk_4wh_hash_set = 0;
}
void sec_prot_keys_ptk_installed_gtk_hash_set(sec_prot_keys_t *sec_keys)
void sec_prot_keys_ptk_installed_gtk_hash_set(sec_prot_keys_t *sec_keys, bool is_4wh)
{
if (sec_keys->gtk_set_index >= 0) {
uint8_t *gtk = sec_prot_keys_gtk_get(sec_keys->gtks, sec_keys->gtk_set_index);
@ -824,12 +946,22 @@ void sec_prot_keys_ptk_installed_gtk_hash_set(sec_prot_keys_t *sec_keys)
*/
memcpy(sec_keys->ins_gtk_hash[sec_keys->gtk_set_index].hash, gtk_hash, INS_GTK_HASH_LEN);
sec_keys->ins_gtk_hash_set |= (1 << sec_keys->gtk_set_index);
/* If used on 4WH will store the hash in case GKH is initiated later for the
* same index as 4WH (likely to happen if just GTK update is made). This allows
* that NVM storage does not need to be updated since hash is already stored. */
if (is_4wh) {
sec_keys->ins_gtk_4wh_hash_set |= (1 << sec_keys->gtk_set_index);
} else {
sec_keys->ins_gtk_4wh_hash_set &= ~(1 << sec_keys->gtk_set_index);
}
}
}
bool sec_prot_keys_ptk_installed_gtk_hash_mismatch_check(sec_prot_keys_t *sec_keys, uint8_t gtk_index)
{
if ((sec_keys->ins_gtk_hash_set & (1 << sec_keys->gtk_set_index)) == 0) {
// If not set or the key has been inserted by 4WH then there is no mismatch
if ((sec_keys->ins_gtk_hash_set & (1 << sec_keys->gtk_set_index)) == 0 ||
(sec_keys->ins_gtk_hash_set & (1 << sec_keys->gtk_set_index)) == 1) {
return false;
}

View File

@ -41,7 +41,7 @@
#define PTKID_LEN 16
#define KEYID_LEN 16
#define GTK_DEFAULT_LIFETIME 60 * 60 * 24 * 30 // 30 days
#define GTK_DEFAULT_LIFETIME (60 * 60 * 24 * 30) // 30 days
#define GTK_EXPIRE_MISMATCH_TIME 60 // Supplicant GTK expire time mismatch occurs if GTK expires before this time
#define GTK_STATUS_NEW 0 // New GTK, can transition to fresh
@ -56,18 +56,22 @@
#define GTK_ALL_HASHES_LEN GTK_HASH_LEN * GTK_NUM
#define INS_GTK_HASH_LEN 2
#define PMK_LIFETIME_INSTALL 0xFFFFF
#define PTK_LIFETIME_INSTALL 0xFFFFF
// Limit is 60000 (of 65536)
#define PMK_KEY_REPLAY_CNT_LIMIT 60000 // Upper limit for PMK replay counter
#define PMK_KEY_REPLAY_CNT_LIMIT_MASK 0xFFFF // Upper limit mask
#define SEC_MAXIMUM_LIFETIME (60 * 60 * 24 * 30 * 24) // Maximum life time for PMK, PTK, GTKs etc. is two years
typedef struct {
uint8_t key[GTK_LEN]; /**< Group Transient Key (128 bits) */
uint64_t expirytime; /**< GTK expiry time on storage */
uint32_t lifetime; /**< GTK lifetime in seconds */
unsigned status : 2; /**< Group Transient Key status */
unsigned install_order : 2; /**< Order in which GTK keys are added */
bool set: 1; /**< Group Transient Key set (valid value) */
} gtk_key_t;
typedef struct {
typedef struct sec_prot_gtk_keys_s {
gtk_key_t gtk[GTK_NUM]; /**< 4 Group Transient Keys */
bool updated: 1; /**< Group Transient Keys has been updated */
} sec_prot_gtk_keys_t;
@ -90,6 +94,7 @@ typedef struct {
uint8_t gtkl; /**< Remote GTKL information */
int8_t gtk_set_index; /**< Index of GTK to set */
unsigned ins_gtk_hash_set: 4; /**< Hash for inserted GTKs for a PTK set */
unsigned ins_gtk_4wh_hash_set: 4; /**< Hash for inserted GTKs for a PTK set for a 4WH */
bool pmk_set: 1; /**< Pairwise Master Key set */
bool ptk_set: 1; /**< Pairwise Transient Key set */
bool pmk_key_replay_cnt_set: 1; /**< Pairwise Master Key replay counter set */
@ -111,6 +116,35 @@ typedef struct {
frame_counter_t counter[GTK_NUM]; /**< Frame counter for each GTK key */
} frame_counters_t;
// Authenticator supplicant security key data
typedef struct {
uint8_t pmk[PMK_LEN]; /**< Pairwise Master Key (256 bits) */
uint8_t ptk[PTK_LEN]; /**< Pairwise Transient Key (384 bits) */
uint8_t ptk_eui_64[8]; /**< Remote EUI-64 used to derive PTK or NULL */
sec_prot_gtk_hash_t ins_gtk_hash[GTK_NUM]; /**< Hashes for inserted GTKs for a PTK */
uint16_t pmk_key_replay_cnt; /**< Pairwise Master Key replay counter */
uint16_t pmk_lifetime; /**< PMK lifetime (short time format) */
uint16_t ptk_lifetime; /**< PTK lifetime (short time format) */
unsigned ins_gtk_hash_set: 4; /**< Hash for inserted GTKs for a PTK set */
unsigned ins_gtk_4wh_hash_set: 4; /**< Hash for inserted GTKs for a PTK set for a 4WH */
bool pmk_set: 1; /**< Pairwise Master Key set */
bool ptk_set: 1; /**< Pairwise Transient Key set */
bool pmk_lifetime_set: 1; /**< PMK lifetime (short time format) */
bool ptk_lifetime_set: 1; /**< PTK lifetime (short time format) */
bool pmk_key_replay_cnt_set: 1; /**< Pairwise Master Key replay counter set */
bool ptk_eui_64_set: 1; /**< Remote EUI-64 used to derive PTK is set */
bool eui_64_set: 1; /**< Remote EUI-64 is set */
} sec_prot_keys_storage_t;
// Security keys (GTKs) and needed network information
typedef struct {
char network_name[33]; /**< Network name for keys */
sec_prot_gtk_keys_t *gtks; /**< Link to GTKs */
uint16_t new_pan_id; /**< new PAN ID indicated by bootstrap */
uint16_t key_pan_id; /**< PAN ID for keys */
bool updated : 1; /**< Network info has been updated */
} sec_prot_keys_nw_info_t;
/*
* GTK mismatch types, list is ordered according to priority of mismatch i.e. if there
* are both hash and lifetime mismatch, hash has greater priority
@ -178,9 +212,10 @@ void sec_prot_keys_gtks_delete(sec_prot_gtk_keys_t *gtks);
*
* \param sec_keys security keys
* \param pmk Pairwise Master Key
* \param pmk_lifetime PMK lifetime
*
*/
void sec_prot_keys_pmk_write(sec_prot_keys_t *sec_keys, uint8_t *pmk);
void sec_prot_keys_pmk_write(sec_prot_keys_t *sec_keys, uint8_t *pmk, uint32_t pmk_lifetime);
/**
* sec_prot_keys_pmk_delete deletes PMK
@ -200,6 +235,16 @@ void sec_prot_keys_pmk_delete(sec_prot_keys_t *sec_keys);
*/
uint8_t *sec_prot_keys_pmk_get(sec_prot_keys_t *sec_keys);
/**
* sec_prot_keys_pmk_lifetime_get Pairwise Master Key lifetime
*
* \param sec_keys security keys
*
* \return PMK lifetime
*
*/
uint32_t sec_prot_keys_pmk_lifetime_get(sec_prot_keys_t *sec_keys);
/**
* sec_prot_keys_pmk_replay_cnt_get gets PMK replay counter value
*
@ -224,8 +269,11 @@ void sec_prot_keys_pmk_replay_cnt_set(sec_prot_keys_t *sec_keys, uint64_t counte
*
* \param sec_keys security keys
*
* \return TRUE counter was incremented
* \return FALSE counter increment failed
*
*/
void sec_prot_keys_pmk_replay_cnt_increment(sec_prot_keys_t *sec_keys);
bool sec_prot_keys_pmk_replay_cnt_increment(sec_prot_keys_t *sec_keys);
/**
* sec_prot_keys_pmk_replay_cnt_compare compares received replay counter value to PMK replay counter
@ -269,23 +317,23 @@ bool sec_prot_keys_pmk_mismatch_is_set(sec_prot_keys_t *sec_keys);
* sec_prot_keys_pmk_lifetime_decrement decrements PMK lifetime
*
* \param sec_keys security keys
* \param default_lifetime default lifetime for PMK
* \param seconds elapsed seconds
*
* \return true PMK expired and deleted both PMK and PTK
* \return false PMK not expired
*
*/
bool sec_prot_keys_pmk_lifetime_decrement(sec_prot_keys_t *sec_keys, uint32_t default_lifetime, uint8_t seconds);
bool sec_prot_keys_pmk_lifetime_decrement(sec_prot_keys_t *sec_keys, uint8_t seconds);
/**
* sec_prot_keys_ptk_write writes Pairwise Transient Key
*
* \param sec_keys security keys
* \param ptk Pairwise Transient Key
* \param ptk_lifetime PTK lifetime
*
*/
void sec_prot_keys_ptk_write(sec_prot_keys_t *sec_keys, uint8_t *ptk);
void sec_prot_keys_ptk_write(sec_prot_keys_t *sec_keys, uint8_t *ptk, uint32_t ptk_lifetime);
/**
* sec_prot_keys_ptk_delete deletes PTK
@ -305,6 +353,16 @@ void sec_prot_keys_ptk_delete(sec_prot_keys_t *sec_keys);
*/
uint8_t *sec_prot_keys_ptk_get(sec_prot_keys_t *sec_keys);
/**
* sec_prot_keys_ptk_lifetime_get gets Pairwise Transient Key lifetime
*
* \param sec_keys security keys
*
* \return PTK lifetime
*
*/
uint32_t sec_prot_keys_ptk_lifetime_get(sec_prot_keys_t *sec_keys);
/**
* sec_prot_keys_ptk_mismatch_set set PTK mismatch
*
@ -362,14 +420,13 @@ void sec_prot_keys_ptk_eui_64_delete(sec_prot_keys_t *sec_keys);
* sec_prot_keys_ptk_lifetime_decrement decrements PTK lifetime
*
* \param sec_keys security keys
* \param default_lifetime default lifetime for PTK
* \param seconds elapsed seconds
*
* \return true PTK expired and deleted
* \return false PTK not expired
*
*/
bool sec_prot_keys_ptk_lifetime_decrement(sec_prot_keys_t *sec_keys, uint32_t default_lifetime, uint8_t seconds);
bool sec_prot_keys_ptk_lifetime_decrement(sec_prot_keys_t *sec_keys, uint8_t seconds);
/**
* sec_prot_keys_are_updated returns security keys have been updated flag
@ -556,12 +613,38 @@ uint32_t sec_prot_keys_gtk_lifetime_get(sec_prot_gtk_keys_t *gtks, uint8_t index
*
* \param gtks GTK keys
* \param index index for GTK
* \param current_time current timestamp
* \param seconds elapsed seconds
*
* \return new GTK lifetime
*
*/
uint32_t sec_prot_keys_gtk_lifetime_decrement(sec_prot_gtk_keys_t *gtks, uint8_t index, uint16_t seconds);
uint32_t sec_prot_keys_gtk_lifetime_decrement(sec_prot_gtk_keys_t *gtks, uint8_t index, uint64_t current_time, uint16_t seconds);
/**
* sec_prot_keys_gtk_exptime_from_lifetime_get converts GTK lifetime to expiry time.
*
* \param gtks GTK keys
* \param index index for GTK
* \param current_time current time
*
* \return expiry time
*
*/
uint64_t sec_prot_keys_gtk_exptime_from_lifetime_get(sec_prot_gtk_keys_t *gtks, uint8_t index, uint64_t current_time);
/**
* sec_prot_keys_gtk_expirytime_set sets GTK expiry time
*
* \param gtks GTK keys
* \param index index for GTK
* \param expirytime expiry time
*
* \return < 0 failure
* \return >= 0 success
*
*/
int8_t sec_prot_keys_gtk_expirytime_set(sec_prot_gtk_keys_t *gtks, uint8_t index, uint64_t expirytime);
/**
* sec_prot_keys_gtks_are_updated returns GTKs have been updated flag
@ -631,6 +714,17 @@ int8_t sec_prot_keys_gtk_status_active_set(sec_prot_gtk_keys_t *gtks, uint8_t in
*/
int8_t sec_prot_keys_gtk_status_active_get(sec_prot_gtk_keys_t *gtks);
/**
* sec_prot_keys_gtk_status_active_to_fresh_set sets active GTK to fresh GTK
*
* \param gtks GTK keys
*
* \return < 0 failure
* \return >= 0 success
*
*/
int8_t sec_prot_keys_gtk_status_active_to_fresh_set(sec_prot_gtk_keys_t *gtks);
/**
* sec_prot_keys_gtk_status_is_live checks whether GTK is active
*
@ -642,6 +736,30 @@ int8_t sec_prot_keys_gtk_status_active_get(sec_prot_gtk_keys_t *gtks);
*/
bool sec_prot_keys_gtk_status_is_live(sec_prot_gtk_keys_t *gtks, uint8_t index);
/**
* sec_prot_keys_gtk_status_get gets GTK status
*
* \param gtks GTK keys
* \param index index
*
* \return GTK status
*
*/
uint8_t sec_prot_keys_gtk_status_get(sec_prot_gtk_keys_t *gtks, uint8_t index);
/**
* sec_prot_keys_gtk_status_get sets GTK status
*
* \param gtks GTK keys
* \param index index
* \param status status
*
* \return < 0 failure
* \return >= 0 success
*
*/
int8_t sec_prot_keys_gtk_status_set(sec_prot_gtk_keys_t *gtks, uint8_t index, uint8_t status);
/**
* sec_prot_keys_gtks_hash_generate generate GTK hash based on all GTKs
*
@ -761,6 +879,30 @@ void sec_prot_keys_gtk_install_order_update(sec_prot_gtk_keys_t *gtks);
*/
int8_t sec_prot_keys_gtk_install_index_get(sec_prot_gtk_keys_t *gtks);
/**
* sec_prot_keys_gtk_install_order_get gets GTK install order
*
* \param gtks GTK keys
* \param index index
*
* \return GTK install order
*
*/
uint8_t sec_prot_keys_gtk_install_order_get(sec_prot_gtk_keys_t *gtks, uint8_t gtk_index);
/**
* sec_prot_keys_gtk_install_order_set sets GTK install order
*
* \param gtks GTK keys
* \param index index
* \param install_order GTK install order
*
* \return < 0 failure
* \return >= 0 success
*
*/
int8_t sec_prot_keys_gtk_install_order_set(sec_prot_gtk_keys_t *gtks, uint8_t gtk_index, uint8_t install_order);
/**
* sec_prot_keys_gtk_count counts GTK keys
*
@ -784,9 +926,10 @@ void sec_prot_keys_ptk_installed_gtk_hash_clear_all(sec_prot_keys_t *sec_keys);
* to supplicant using the current PTK
*
* \param sec_keys security keys
* \param is_4wh set by 4WH
*
*/
void sec_prot_keys_ptk_installed_gtk_hash_set(sec_prot_keys_t *sec_keys);
void sec_prot_keys_ptk_installed_gtk_hash_set(sec_prot_keys_t *sec_keys, bool is_4wh);
/**
* sec_prot_keys_ptk_installed_gtk_hash_set check if PTK is being used to store new GTK for the index

View File

@ -274,6 +274,12 @@ int8_t sec_prot_lib_ptk_calc(const uint8_t *pmk, const uint8_t *eui64_1, const u
memcpy(ptk, result, PTK_LEN);
#ifdef EXTRA_DEBUG_INFO
tr_debug("PTK EUI: %s %s", trace_array(eui64_1, 8), trace_array(eui64_2, 8));
tr_debug("PTK NONCE: %s %s", trace_array(nonce1, 32), trace_array(nonce2, 32));
tr_debug("PTK: %s:%s", trace_array(ptk, PTK_LEN / 2), trace_array(ptk + PTK_LEN / 2, PTK_LEN / 2));
#endif
return 0;
}
@ -469,7 +475,7 @@ int8_t sec_prot_lib_ptkid_generate(sec_prot_t *prot, uint8_t *ptkid, bool is_aut
{
uint8_t local_eui64[8];
prot->addr_get(prot, local_eui64, NULL);
uint8_t *ptk = sec_prot_keys_pmk_get(prot->sec_keys);
uint8_t *ptk = sec_prot_keys_ptk_get(prot->sec_keys);
if (!ptk) {
return -1;
}
@ -524,7 +530,10 @@ uint8_t *sec_prot_remote_eui_64_addr_get(sec_prot_t *prot)
if (prot->sec_keys && prot->sec_keys->ptk_eui_64_set) {
return prot->sec_keys->ptk_eui_64;
} else {
return NULL;
static uint8_t remote_eui64[8];
memset(remote_eui64, 0, 8);
prot->addr_get(prot, NULL, (uint8_t *) &remote_eui64);
return remote_eui64;
}
}

View File

@ -69,15 +69,20 @@ typedef struct {
bool timer_running : 1; /**< TLS timer running */
bool finished : 1; /**< TLS finished */
bool calculating : 1; /**< TLS is calculating */
#ifdef SERVER_TLS_EC_CALC_QUEUE
bool queued : 1; /**< TLS is queued */
#endif
bool library_init : 1; /**< TLS library has been initialized */
tls_sec_prot_lib_int_t *tls_sec_inst; /**< TLS security library storage, SHALL BE THE LAST FIELD */
} tls_sec_prot_int_t;
// TLS server EC queue is currently disabled, since EC calculation is made on server in one go
#ifdef SERVER_TLS_EC_CALC_QUEUE
typedef struct {
ns_list_link_t link; /**< Link */
sec_prot_t *prot; /**< Protocol instance */
} tls_sec_prot_queue_t;
#endif
static uint16_t tls_sec_prot_size(void);
static int8_t client_tls_sec_prot_init(sec_prot_t *prot);
@ -102,15 +107,22 @@ static int8_t tls_sec_prot_tls_get_timer(void *handle);
static int8_t tls_sec_prot_tls_configure_and_connect(sec_prot_t *prot, bool is_server);
#ifdef SERVER_TLS_EC_CALC_QUEUE
static bool tls_sec_prot_queue_check(sec_prot_t *prot);
static bool tls_sec_prot_queue_process(sec_prot_t *prot);
static void tls_sec_prot_queue_remove(sec_prot_t *prot);
#else
#define tls_sec_prot_queue_process(prot) true
#define tls_sec_prot_queue_remove(prot)
#endif /* SERVER_TLS_EC_CALC_QUEUE */
static uint16_t tls_sec_prot_send_buffer_size_get(sec_prot_t *prot);
#define tls_sec_prot_get(prot) (tls_sec_prot_int_t *) &prot->data
#ifdef SERVER_TLS_EC_CALC_QUEUE
static NS_LIST_DEFINE(tls_sec_prot_queue, tls_sec_prot_queue_t, link);
#endif
int8_t client_tls_sec_prot_register(kmp_service_t *service)
{
@ -168,7 +180,9 @@ static int8_t client_tls_sec_prot_init(sec_prot_t *prot)
data->fin_timer_timeout = false;
data->timer_running = false;
data->calculating = false;
#ifdef SERVER_TLS_EC_CALC_QUEUE
data->queued = false;
#endif
data->library_init = false;
return 0;
}
@ -198,7 +212,9 @@ static int8_t server_tls_sec_prot_init(sec_prot_t *prot)
data->fin_timer_timeout = false;
data->timer_running = false;
data->calculating = false;
#ifdef SERVER_TLS_EC_CALC_QUEUE
data->queued = false;
#endif
data->library_init = false;
return 0;
}
@ -281,7 +297,11 @@ static void tls_sec_prot_timer_timeout(sec_prot_t *prot, uint16_t ticks)
if (data->fin_timer_timeout) {
data->fin_timer_timeout = false;
prot->state_machine(prot);
} else if (data->calculating || data->queued) {
} else if (data->calculating
#ifdef SERVER_TLS_EC_CALC_QUEUE
|| data->queued
#endif
) {
prot->state_machine(prot);
}
}
@ -355,7 +375,7 @@ static void client_tls_sec_prot_state_machine(sec_prot_t *prot)
data->calculating = false;
if (sec_prot_result_ok_check(&data->common)) {
sec_prot_keys_pmk_write(prot->sec_keys, data->new_pmk);
sec_prot_keys_pmk_write(prot->sec_keys, data->new_pmk, prot->timer_cfg->pmk_lifetime);
}
// KMP-FINISHED.indication,
@ -385,7 +405,9 @@ static void server_tls_sec_prot_state_machine(sec_prot_t *prot)
{
tls_sec_prot_int_t *data = tls_sec_prot_get(prot);
int8_t result;
#ifdef SERVER_TLS_EC_CALC_QUEUE
bool client_hello = false;
#endif
switch (sec_prot_state_get(&data->common)) {
case TLS_STATE_INIT:
@ -400,7 +422,9 @@ static void server_tls_sec_prot_state_machine(sec_prot_t *prot)
case TLS_STATE_CLIENT_HELLO:
tr_debug("TLS: start, eui-64: %s", trace_array(sec_prot_remote_eui_64_addr_get(prot), 8));
#ifdef SERVER_TLS_EC_CALC_QUEUE
client_hello = true;
#endif
sec_prot_state_set(prot, &data->common, TLS_STATE_CREATE_RESP);
@ -430,6 +454,7 @@ static void server_tls_sec_prot_state_machine(sec_prot_t *prot)
break;
case TLS_STATE_PROCESS:
#ifdef SERVER_TLS_EC_CALC_QUEUE
// If not client hello, reserves slot on TLS queue
if (!client_hello && !tls_sec_prot_queue_check(prot)) {
data->queued = true;
@ -437,6 +462,7 @@ static void server_tls_sec_prot_state_machine(sec_prot_t *prot)
} else {
data->queued = false;
}
#endif
result = tls_sec_prot_lib_process((tls_security_t *) &data->tls_sec_inst);
@ -468,7 +494,7 @@ static void server_tls_sec_prot_state_machine(sec_prot_t *prot)
data->calculating = false;
if (sec_prot_result_ok_check(&data->common)) {
sec_prot_keys_pmk_write(prot->sec_keys, data->new_pmk);
sec_prot_keys_pmk_write(prot->sec_keys, data->new_pmk, prot->timer_cfg->pmk_lifetime);
}
// KMP-FINISHED.indication,
@ -636,6 +662,7 @@ static int8_t tls_sec_prot_tls_configure_and_connect(sec_prot_t *prot, bool is_s
return 0;
}
#ifdef SERVER_TLS_EC_CALC_QUEUE
static bool tls_sec_prot_queue_check(sec_prot_t *prot)
{
bool queue_add = true;
@ -703,6 +730,7 @@ static void tls_sec_prot_queue_remove(sec_prot_t *prot)
}
}
}
#endif
static uint16_t tls_sec_prot_send_buffer_size_get(sec_prot_t *prot)
{

View File

@ -37,9 +37,14 @@
#define TRACE_GROUP "etx"
typedef struct {
uint8_t attribute_index;
const uint8_t *mac64;
} ext_neigh_info_t;
static uint16_t etx_current_calc(uint16_t etx, uint8_t accumulated_failures);
static uint16_t etx_dbm_lqi_calc(uint8_t lqi, int8_t dbm);
static void etx_value_change_callback_needed_check(uint16_t etx, uint16_t *stored_diff_etx, uint8_t accumulated_failures, uint8_t attribute_index);
static void etx_value_change_callback_needed_check(uint16_t etx, uint16_t *stored_diff_etx, uint8_t accumulated_failures, ext_neigh_info_t *etx_neigh_info);
static void etx_accum_failures_callback_needed_check(etx_storage_t *entry, uint8_t attribute_index);
static void etx_cache_entry_init(uint8_t attribute_index);
@ -90,7 +95,7 @@ static ext_info_t etx_info = {
.interface_id = -1
};
static void etx_calculation(etx_storage_t *entry, uint16_t attempts, uint8_t acks_rx, uint8_t attribute_index)
static void etx_calculation(etx_storage_t *entry, uint16_t attempts, uint8_t acks_rx, ext_neigh_info_t *etx_neigh_info)
{
if (etx_info.hysteresis && !entry->stored_diff_etx) {
if (entry->etx_samples >= etx_info.init_etx_sample_count) {
@ -130,9 +135,9 @@ static void etx_calculation(etx_storage_t *entry, uint16_t attempts, uint8_t ack
entry->etx = etx;
if (entry->etx_samples >= etx_info.init_etx_sample_count) {
etx_cache_entry_init(attribute_index);
etx_cache_entry_init(etx_neigh_info->attribute_index);
// Checks if ETX value change callback is needed
etx_value_change_callback_needed_check(entry->etx, &(entry->stored_diff_etx), entry->accumulated_failures, attribute_index);
etx_value_change_callback_needed_check(entry->etx, &(entry->stored_diff_etx), entry->accumulated_failures, etx_neigh_info);
}
}
@ -203,7 +208,7 @@ static etx_sample_storage_t *etx_cache_sample_update(uint8_t attribute_index, ui
* \param addr_type address type, ADDR_802_15_4_SHORT or ADDR_802_15_4_LONG
* \param addr_ptr PAN ID with 802.15.4 address
*/
void etx_transm_attempts_update(int8_t interface_id, uint8_t attempts, bool success, uint8_t attribute_index)
void etx_transm_attempts_update(int8_t interface_id, uint8_t attempts, bool success, uint8_t attribute_index, const uint8_t *mac64_addr_ptr)
{
uint8_t accumulated_failures;
// Gets table entry
@ -212,6 +217,10 @@ void etx_transm_attempts_update(int8_t interface_id, uint8_t attempts, bool succ
return;
}
ext_neigh_info_t etx_neigh_info;
etx_neigh_info.attribute_index = attribute_index;
etx_neigh_info.mac64 = mac64_addr_ptr;
if (entry->etx_samples < 7) {
entry->etx_samples++;
}
@ -225,7 +234,7 @@ void etx_transm_attempts_update(int8_t interface_id, uint8_t attempts, bool succ
return;
}
etx_calculation(entry, storage->attempts_count, storage->received_acks, attribute_index);
etx_calculation(entry, storage->attempts_count, storage->received_acks, &etx_neigh_info);
if (entry->etx_samples < 7 && !success) {
entry->etx_samples = 7; //Stop Probing to failure
@ -254,7 +263,7 @@ void etx_transm_attempts_update(int8_t interface_id, uint8_t attempts, bool succ
if (entry->etx) {
if (success) {
etx_calculation(entry, attempts + accumulated_failures, 1, attribute_index);
etx_calculation(entry, attempts + accumulated_failures, 1, &etx_neigh_info);
}
}
}
@ -268,35 +277,42 @@ void etx_transm_attempts_update(int8_t interface_id, uint8_t attempts, bool succ
* \param remote_incoming_idr Remote incoming IDR
* \param mac64_addr_ptr long MAC address
*/
void etx_remote_incoming_idr_update(int8_t interface_id, uint8_t remote_incoming_idr, uint8_t attribute_index)
void etx_remote_incoming_idr_update(int8_t interface_id, uint8_t remote_incoming_idr, uint8_t attribute_index, const uint8_t *mac64_addr_ptr)
{
etx_storage_t *entry = etx_storage_entry_get(interface_id, attribute_index);
if (entry) {
// If ETX has been set
if (entry->etx) {
// If hysteresis is set stores ETX value to enable comparison
if (etx_info.hysteresis && !entry->stored_diff_etx) {
entry->stored_diff_etx = entry->etx;
}
// remote EXT = remote incoming IDR^2 (12 bit fraction)
uint32_t remote_ext = ((uint32_t)remote_incoming_idr * remote_incoming_idr) << 2;
// ETX = 7/8 * current ETX + 1/8 * remote ETX */
uint32_t etx = entry->etx - (entry->etx >> ETX_MOVING_AVERAGE_FRACTION);
etx += remote_ext >> ETX_MOVING_AVERAGE_FRACTION;
if (etx > 0xffff) {
entry->etx = 0xffff;
} else {
entry->etx = etx;
}
// Checks if ETX value change callback is needed
etx_value_change_callback_needed_check(entry->etx, &(entry->stored_diff_etx), entry->accumulated_failures, attribute_index);
}
entry->remote_incoming_idr = remote_incoming_idr;
if (!entry) {
return;
}
ext_neigh_info_t etx_neigh_info;
etx_neigh_info.attribute_index = attribute_index;
etx_neigh_info.mac64 = mac64_addr_ptr;
// If ETX has been set
if (entry->etx) {
// If hysteresis is set stores ETX value to enable comparison
if (etx_info.hysteresis && !entry->stored_diff_etx) {
entry->stored_diff_etx = entry->etx;
}
// remote EXT = remote incoming IDR^2 (12 bit fraction)
uint32_t remote_ext = ((uint32_t)remote_incoming_idr * remote_incoming_idr) << 2;
// ETX = 7/8 * current ETX + 1/8 * remote ETX */
uint32_t etx = entry->etx - (entry->etx >> ETX_MOVING_AVERAGE_FRACTION);
etx += remote_ext >> ETX_MOVING_AVERAGE_FRACTION;
if (etx > 0xffff) {
entry->etx = 0xffff;
} else {
entry->etx = etx;
}
// Checks if ETX value change callback is needed
etx_value_change_callback_needed_check(entry->etx, &(entry->stored_diff_etx), entry->accumulated_failures, &etx_neigh_info);
}
entry->remote_incoming_idr = remote_incoming_idr;
}
/**
@ -442,14 +458,18 @@ static uint16_t etx_current_calc(uint16_t etx, uint8_t accumulated_failures)
*
* \return 0x0100 to 0xFFFF local incoming IDR value (8 bit fraction)
*/
uint16_t etx_lqi_dbm_update(int8_t interface_id, uint8_t lqi, int8_t dbm, uint8_t attribute_index)
uint16_t etx_lqi_dbm_update(int8_t interface_id, uint8_t lqi, int8_t dbm, uint8_t attribute_index, const uint8_t *mac64_addr_ptr)
{
uint32_t local_incoming_idr = 0;
uint32_t etx = 0;
etx_storage_t *entry = etx_storage_entry_get(interface_id, attribute_index);
if (entry) {
ext_neigh_info_t etx_neigh_info;
etx_neigh_info.attribute_index = attribute_index;
etx_neigh_info.mac64 = mac64_addr_ptr;
// If local ETX is not set calculate it based on LQI and dBm
if (!entry->etx) {
etx = etx_dbm_lqi_calc(lqi, dbm);
@ -458,7 +478,7 @@ uint16_t etx_lqi_dbm_update(int8_t interface_id, uint8_t lqi, int8_t dbm, uint8_
entry->tmp_etx = true;
if (etx_info.callback_ptr) {
etx_info.callback_ptr(etx_info.interface_id, 0, entry->etx >> 4,
attribute_index);
attribute_index, mac64_addr_ptr);
}
}
// If local ETX has been calculated without remote incoming IDR and
@ -474,7 +494,7 @@ uint16_t etx_lqi_dbm_update(int8_t interface_id, uint8_t lqi, int8_t dbm, uint8_
entry->etx = etx >> 12;
local_incoming_idr >>= 4;
etx_value_change_callback_needed_check(entry->etx, &(entry->stored_diff_etx), entry->accumulated_failures, attribute_index);
etx_value_change_callback_needed_check(entry->etx, &(entry->stored_diff_etx), entry->accumulated_failures, &etx_neigh_info);
}
}
@ -721,7 +741,7 @@ uint8_t etx_accum_failures_callback_register(nwk_interface_id nwk_id, int8_t int
*
* \return ETX value (12 bit fraction)
*/
static void etx_value_change_callback_needed_check(uint16_t etx, uint16_t *stored_diff_etx, uint8_t accumulated_failures, uint8_t attribute_index)
static void etx_value_change_callback_needed_check(uint16_t etx, uint16_t *stored_diff_etx, uint8_t accumulated_failures, ext_neigh_info_t *etx_neigh_info)
{
uint16_t current_etx;
bool callback = false;
@ -747,7 +767,7 @@ static void etx_value_change_callback_needed_check(uint16_t etx, uint16_t *store
// Calls callback function
if (callback) {
etx_info.callback_ptr(etx_info.interface_id, (*stored_diff_etx) >> 4, current_etx >> 4, attribute_index);
etx_info.callback_ptr(etx_info.interface_id, (*stored_diff_etx) >> 4, current_etx >> 4, etx_neigh_info->attribute_index, etx_neigh_info->mac64);
*stored_diff_etx = current_etx;
}
}
@ -782,7 +802,7 @@ static void etx_accum_failures_callback_needed_check(etx_storage_t *entry, uint8
* \param mac64_addr_ptr long MAC address
*
*/
void etx_neighbor_remove(int8_t interface_id, uint8_t attribute_index)
void etx_neighbor_remove(int8_t interface_id, uint8_t attribute_index, const uint8_t *mac64_addr_ptr)
{
//tr_debug("Remove attribute %u", attribute_index);
@ -795,7 +815,8 @@ void etx_neighbor_remove(int8_t interface_id, uint8_t attribute_index)
if (!stored_diff_etx) {
stored_diff_etx = 0xffff;
}
etx_info.callback_ptr(etx_info.interface_id, stored_diff_etx, 0xffff, attribute_index);
etx_info.callback_ptr(etx_info.interface_id, stored_diff_etx, 0xffff, attribute_index, mac64_addr_ptr);
}
if (etx_info.cache_sample_requested) {
@ -829,7 +850,10 @@ void etx_cache_timer(int8_t interface_id, uint16_t seconds_update)
etx_sample_storage_t *storage = etx_info.etx_cache_storage_list + neighbour->index;
if (etx_update_possible(storage, etx_entry, seconds_update)) {
etx_calculation(etx_entry, storage->attempts_count, storage->received_acks, neighbour->index);
ext_neigh_info_t etx_neigh_info;
etx_neigh_info.attribute_index = neighbour->index;
etx_neigh_info.mac64 = neighbour->mac64;
etx_calculation(etx_entry, storage->attempts_count, storage->received_acks, &etx_neigh_info);
}
}

View File

@ -76,8 +76,9 @@ typedef struct etx_sample_storage_s {
* \param attempts number of attempts to send message
* \param success was message sending successful
* \param attribute_index Neighbour attribute index
* \param mac64_addr_ptr Neighbour MAC64
*/
void etx_transm_attempts_update(int8_t interface_id, uint8_t attempts, bool success, uint8_t attribute_index);
void etx_transm_attempts_update(int8_t interface_id, uint8_t attempts, bool success, uint8_t attribute_index, const uint8_t *mac64_addr_ptr);
/**
* \brief A function to update ETX value based on remote incoming IDR
@ -88,8 +89,9 @@ void etx_transm_attempts_update(int8_t interface_id, uint8_t attempts, bool succ
* \param interface_id Interface identifier
* \param remote_incoming_idr Remote incoming IDR
* \param attribute_index Neighbour attribute index
* \param mac64_addr_ptr Neighbour MAC64
*/
void etx_remote_incoming_idr_update(int8_t interface_id, uint8_t remote_incoming_idr, uint8_t attribute_index);
void etx_remote_incoming_idr_update(int8_t interface_id, uint8_t remote_incoming_idr, uint8_t attribute_index, const uint8_t *mac64_addr_ptr);
/**
* \brief A function to read ETX value
@ -139,10 +141,11 @@ uint16_t etx_local_etx_read(int8_t interface_id, uint8_t attribute_index);
* \param lqi link quality indicator
* \param dbm measured dBm
* \param attribute_index Neighbour attribute index
* \param mac64_addr_ptr Neighbour MAC64
*
* \return 0x0100 to 0xFFFF local incoming IDR value (8 bit fraction)
*/
uint16_t etx_lqi_dbm_update(int8_t interface_id, uint8_t lqi, int8_t dbm, uint8_t attribute_index);
uint16_t etx_lqi_dbm_update(int8_t interface_id, uint8_t lqi, int8_t dbm, uint8_t attribute_index, const uint8_t *mac64_addr_ptr);
/**
* \brief A function callback that indicates ETX value change
@ -154,9 +157,10 @@ uint16_t etx_lqi_dbm_update(int8_t interface_id, uint8_t lqi, int8_t dbm, uint8_
* \param previous_etx ETX value to what the current ETX was compared (8 bit fraction)
* \param current_etx current ETX value (8 bit fraction)
* \param attribute_index Neighbour attribute index
* \param mac64_addr_ptr Pointer to MAC64 for given etx update
*
*/
typedef void (etx_value_change_handler_t)(int8_t nwk_id, uint16_t previous_etx, uint16_t current_etx, uint8_t attribute_index);
typedef void (etx_value_change_handler_t)(int8_t nwk_id, uint16_t previous_etx, uint16_t current_etx, uint8_t attribute_index, const uint8_t *mac64_addr_ptr);
/**
* \brief A function callback that indicates the number of accumulated TX failures
@ -232,9 +236,10 @@ uint8_t etx_accum_failures_callback_register(nwk_interface_id nwk_id, int8_t int
* if that is set.
*
* \param attribute_index Neighbour attribute index
* \param mac64_addr_ptr Neighbour MAC64
*
*/
void etx_neighbor_remove(int8_t interface_id, uint8_t attribute_index);
void etx_neighbor_remove(int8_t interface_id, uint8_t attribute_index, const uint8_t *mac64_addr_ptr);
/**
* \brief A function for update cached ETX calculation

View File

@ -44,3 +44,18 @@ int8_t fhss_set_optimal_packet_length(const fhss_api_t *fhss_api, uint16_t packe
#endif
return 0;
}
int8_t fhss_set_number_of_channel_retries(const fhss_api_t *fhss_api, uint8_t number_of_channel_retries)
{
(void) fhss_api;
(void) number_of_channel_retries;
#ifdef HAVE_WS
fhss_structure_t *fhss_structure = fhss_get_object_with_api(fhss_api);
if (!fhss_structure || !fhss_structure->ws) {
return -1;
}
fhss_structure->ws->fhss_configuration.config_parameters.number_of_channel_retries = number_of_channel_retries;
tr_debug("Setting number of channel retries to: %u", number_of_channel_retries);
#endif
return 0;
}

View File

@ -750,16 +750,18 @@ static bool fhss_ws_data_tx_fail_callback(const fhss_api_t *api, uint8_t handle,
if (fhss_structure->fhss_state == FHSS_UNSYNCHRONIZED) {
return false;
}
// Use channel retries only for data frames
if (FHSS_DATA_FRAME != frame_type) {
return false;
}
// Channel retries are disabled
if (!fhss_structure->ws->fhss_configuration.config_parameters.number_of_channel_retries) {
return false;
}
fhss_failed_tx_t *fhss_failed_tx = fhss_failed_handle_find(fhss_structure, handle);
if (fhss_failed_tx) {
fhss_failed_tx->retries_done++;
if (fhss_failed_tx->retries_done >= WS_NUMBER_OF_CHANNEL_RETRIES) {
if (fhss_failed_tx->retries_done >= fhss_structure->ws->fhss_configuration.config_parameters.number_of_channel_retries) {
// No more retries. Return false to stop retransmitting.
fhss_failed_handle_remove(fhss_structure, handle);
return false;
@ -966,6 +968,19 @@ int fhss_ws_configuration_set(fhss_structure_t *fhss_structure, const fhss_ws_co
if (channel_count <= 0) {
return -1;
}
if (fhss_structure->number_of_channels < channel_count ||
(channel_count_uc && fhss_structure->number_of_uc_channels < channel_count_uc)) {
// Channel amount changed to largeneed to reallocate channel table
ns_dyn_mem_free(fhss_structure->ws->tr51_channel_table);
fhss_structure->ws->tr51_channel_table = NULL;
ns_dyn_mem_free(fhss_structure->ws->tr51_output_table);
fhss_structure->ws->tr51_output_table = NULL;
if (fhss_ws_manage_channel_table_allocation(fhss_structure, channel_count_uc > channel_count ? channel_count_uc : channel_count)) {
return -1;
}
}
platform_enter_critical();
if (fhss_configuration->ws_uc_channel_function == WS_FIXED_CHANNEL || fhss_configuration->fhss_uc_dwell_interval == 0) {
fhss_stop_timer(fhss_structure, fhss_unicast_handler);

View File

@ -17,10 +17,6 @@
#ifndef FHSS_WS_H_
#define FHSS_WS_H_
/* WS requires at least 19 MAC retransmissions (total 1+19=20 attempts). 802.15.4 macMaxFrameRetries is 3 (total 1+3=4 attempts).
* At least 4 channel retries must be used: (Initial channel + WS_NUMBER_OF_CHANNEL_RETRIES) * MAC attempts = (1+4)*4=20 attempts
*/
#define WS_NUMBER_OF_CHANNEL_RETRIES 4
// TX slot length is optimised to this packet length
#define OPTIMAL_PACKET_LENGTH 500
// Default TX/RX slot length in milliseconds. Is used when datarate is not given by PHY.

View File

@ -101,6 +101,10 @@ void mac_neighbor_table_neighbor_timeout_update(mac_neighbor_table_t *table_clas
ns_list_foreach_safe(mac_neighbor_table_entry_t, cur, &table_class->neighbour_list) {
if (cur->lifetime > time_update) {
if (cur->lifetime == 0xffffffff && cur->link_lifetime == 0xffffffff) {
continue; //Infinite Lifetime too not touch
}
cur->lifetime -= time_update;
if (!table_class->user_nud_notify_cb || table_class->active_nud_process > ACTIVE_NUD_PROCESS_MAX || cur->nud_active || !cur->rx_on_idle) {
continue;

View File

@ -94,10 +94,6 @@
#elif defined(__clang__)
#define FNET_CFG_COMP_CLANG (1)
#define FNET_COMP_STR "CLANG"
/* Keil uVision compiler using armcc. */
#elif defined(__CC_ARM)
#define FNET_CFG_COMP_UV (1)
#define FNET_COMP_STR "UV"
/* GNU GCC */
#elif defined(__GNUC__)
#define FNET_CFG_COMP_GNUC (1)

View File

@ -29,5 +29,5 @@ int ns_conf_gc_threshold_set(uint8_t percentage_high, uint8_t percentage_critica
int ns_conf_packet_ingress_rate_limit_by_mem(uint8_t free_heap_percentage)
{
return mcps_packet_ingress_rate_limit_by_memory(free_heap_percentage);
return ns_monitor_packet_ingress_rate_limit_by_memory(free_heap_percentage);
}

View File

@ -0,0 +1,110 @@
/*
* Copyright (c) 2017, Arm Limited and affiliates.
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef _NS_FILE_H_
#define _NS_FILE_H_
/**
* \file ns_file.h
* \brief Nanostack file handling API.
*/
#include "ns_file_system.h"
/**
* File open
*
* Depending on underlying file system file open for read for non-existing
* files can return success. In that case file read will fail.
*
* \param filename filename
* \param mode can be either "r" or "w"
*
* \return file handle
* \return NULL on error
*
*/
NS_FILE ns_fopen(const char *filename, const char *mode);
/**
* File close
*
* \param handle file handle
*
* \return 0 on success
* \return < 0 in case of errors
*
*/
int ns_fclose(NS_FILE *ns_handle);
/**
* File remove
*
* \param filename filename
*
* \return 0 on success
* \return < 0 in case of errors
*
*/
int ns_fremove(const char *filename);
/**
* File write
*
* Write is not stream write. The whole file is written from start to end
* and if function is called again, previous file content is replaced with
* new content.
*
* \param handle file handle
* \param buffer buffer
* \param buffer buffer size
*
* \return bytes written
*
*/
size_t ns_fwrite(NS_FILE *ns_handle, const void *buffer, size_t size);
/**
* File read
*
* Read is not stream read. The whole file is read from start to end
* and if function is called again, read is started from start again.
*
* \param handle file handle
* \param buffer buffer
* \param size buffer size
*
* \return bytes written
*
*/
size_t ns_fread(NS_FILE *ns_handle, void *buffer, size_t size);
/**
* File size callback
*
* Reads file size.
*
* \param handle file handle
* \param size file size
*
* \return 0 on success
* \return < 0 in case of reading file size is not supported
*
*/
int ns_fsize(NS_FILE *ns_handle, size_t *size);
#endif /* _NS_FILE_SYSTEM_H_ */

View File

@ -16,12 +16,21 @@
*/
#include <string.h>
#include <stdio.h>
#include "ns_types.h"
#include "nsdynmemLIB.h"
#include "ns_file_system.h"
#include "ns_file.h"
static char *file_system_root;
static ns_file_open file_open_cb = NULL;
static ns_file_close file_close_cb = NULL;
static ns_file_remove file_remove_cb = NULL;
static ns_file_write file_write_cb = NULL;
static ns_file_read file_read_cb = NULL;
static ns_file_size file_size_cb = NULL;
int ns_file_system_set_root_path(const char *root_path)
{
char *new_root_path;
@ -50,3 +59,99 @@ char *ns_file_system_get_root_path(void)
{
return file_system_root;
}
void ns_file_system_callbacks_set(ns_file_open open, ns_file_close close, ns_file_remove remove, ns_file_write write, ns_file_read read, ns_file_size size)
{
file_open_cb = open;
file_close_cb = close;
file_remove_cb = remove;
file_write_cb = write;
file_read_cb = read;
file_size_cb = size;
}
NS_FILE ns_fopen(const char *file_name, const char *mode)
{
if (!file_name || !mode || (*mode != 'r' && *mode != 'w')) {
return NULL;
}
if (file_open_cb) {
return file_open_cb(file_name, mode);
}
FILE *file = fopen(file_name, mode);
if (file == NULL) {
return NULL;
}
return (NS_FILE) file;
}
int ns_fclose(NS_FILE *ns_handle)
{
if (!ns_handle) {
return -1;
}
if (file_close_cb) {
return file_close_cb(ns_handle);
}
fclose((FILE *) ns_handle);
return 0;
}
int ns_fremove(const char *file_name)
{
if (file_remove_cb) {
return file_remove_cb(file_name);
}
if (!file_name) {
return -1;
}
return remove(file_name);
}
size_t ns_fwrite(NS_FILE *ns_handle, const void *buffer, size_t size)
{
if (!ns_handle || !buffer || size == 0) {
return 0;
}
if (file_write_cb) {
return file_write_cb(ns_handle, buffer, size);
}
rewind((FILE *) ns_handle);
return fwrite(buffer, 1, size, (FILE *) ns_handle);
}
size_t ns_fread(NS_FILE *ns_handle, void *buffer, size_t size)
{
if (!ns_handle || !buffer || size == 0) {
return 0;
}
if (file_read_cb) {
return file_read_cb(ns_handle, buffer, size);
}
rewind((FILE *) ns_handle);
return fread(buffer, 1, size, (FILE *) ns_handle);
}
int ns_fsize(NS_FILE *ns_handle, size_t *size)
{
if (!ns_handle || !size) {
return 0;
}
if (file_size_cb) {
return file_size_cb(ns_handle, size);
}
fseek((FILE *) ns_handle, 0L, SEEK_END);
return ftell((FILE *) ns_handle);
}

View File

@ -24,10 +24,6 @@
#include "ns_types.h"
#ifdef __CC_ARM
#pragma diag_suppress 546 // transfer of control bypasses initialization
#endif
#define __ns_cfg_header(x) #x
#define _ns_cfg_header(x) __ns_cfg_header(configs/cfg_##x.h)
#define ns_cfg_header(x) _ns_cfg_header(x)

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