mirror of https://github.com/ARMmbed/mbed-os.git
				
				
				
			Merge commit '93c77e83625be3989aecb9b3c2b7e930b34eb529'
* commit '93c77e83625be3989aecb9b3c2b7e930b34eb529': Squashed 'features/nanostack/sal-stack-nanostack/' changes from cc03296c27..b3fe5744d1pull/13082/head
						commit
						fc465e7581
					
				| 
						 | 
				
			
			@ -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/).
 | 
			
		||||
 | 
			
		||||

 | 
			
		||||
 | 
			
		||||
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  | 
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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*/
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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_ */
 | 
			
		||||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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_ */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
 *
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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)
 | 
			
		||||
| 
						 | 
				
			
			@ -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)
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			@ -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)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -432,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;
 | 
			
		||||
| 
						 | 
				
			
			@ -449,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;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
 */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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_ */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
											
										
									
								
							| 
						 | 
				
			
			@ -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;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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 */
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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_ */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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 */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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);
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
											
										
									
								
							| 
						 | 
				
			
			@ -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_ */
 | 
			
		||||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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 */
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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_ */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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 */
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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_ */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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(>khash[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;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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 */
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -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_ */
 | 
			
		||||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
 *
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -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_ */
 | 
			
		||||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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*/
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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_ */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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 */
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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 */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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_ */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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)
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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_ */
 | 
			
		||||
| 
						 | 
				
			
			@ -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);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -34,7 +34,9 @@ SRCS += \
 | 
			
		|||
	source/6LoWPAN/ws/ws_pae_lib.c \
 | 
			
		||||
	source/6LoWPAN/ws/ws_pae_nvm_data.c \
 | 
			
		||||
	source/6LoWPAN/ws/ws_pae_nvm_store.c \
 | 
			
		||||
	source/6LoWPAN/ws/ws_pae_time.c \
 | 
			
		||||
	source/6LoWPAN/ws/ws_pae_timers.c \
 | 
			
		||||
	source/6LoWPAN/ws/ws_pae_key_storage.c \
 | 
			
		||||
	source/6LoWPAN/ws/ws_eapol_relay.c \
 | 
			
		||||
	source/6LoWPAN/ws/ws_eapol_auth_relay.c \
 | 
			
		||||
	source/6LoWPAN/ws/ws_eapol_relay_lib.c \
 | 
			
		||||
| 
						 | 
				
			
			@ -79,6 +81,7 @@ SRCS += \
 | 
			
		|||
	source/MAC/IEEE802_15_4/mac_timer.c \
 | 
			
		||||
	source/MAC/IEEE802_15_4/sw_mac.c \
 | 
			
		||||
	source/MAC/IEEE802_15_4/mac_fhss_callbacks.c \
 | 
			
		||||
	source/MAC/IEEE802_15_4/mac_cca_threshold.c \
 | 
			
		||||
	source/MAC/ethernet/ethernet_mac_api.c \
 | 
			
		||||
	source/MAC/serial/serial_mac_api.c \
 | 
			
		||||
	source/MAC/virtual_rf/virtual_rf_client.c \
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue