Merge pull request #13451 from artokin/nanostack_release_v12_4_0_for_5_15

[mbed-os-5.15] Nanostack release v12.4.0
pull/13537/head
Martin Kojtal 2020-09-02 09:51:11 +01:00 committed by GitHub
commit b9c0170a8e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
107 changed files with 5064 additions and 430 deletions

View File

@ -97,6 +97,9 @@ extern "C" {
// RF_PAC
#define TXPWR 0x1F
#define TXPWR_11 (11 << 0)
#define TXPWR_0 (0 << 0)
#define TXPWR_31 (31 << 0)
// RF_PADFE
#define PADFE 0xC0
@ -165,6 +168,9 @@ extern "C" {
#define SR_2 (2 << 0)
#define SR_1 (1 << 0)
// BBC_FSKPHRTX
#define DW (1 << 2)
// BBC_OFDMPHRTX
#define MCS 0x07
#define MCS_0 (0 << 0)

View File

@ -103,6 +103,7 @@ static int rf_set_fsk_symbol_rate_configuration(uint32_t symbol_rate, rf_modules
static int rf_configure_by_ofdm_bandwidth_option(uint8_t option, uint32_t data_rate, rf_modules_e module);
static void rf_calculate_symbol_rate(uint32_t baudrate, phy_modulation_e modulation);
static void rf_conf_set_cca_threshold(uint8_t percent);
static bool rf_conf_set_tx_power(uint8_t percent);
// Defined register read/write functions
#define rf_read_bbc_register(x, y) rf_read_rf_register(x, (rf_modules_e)(y + 2))
#define rf_read_common_register(x) rf_read_rf_register(x, COMMON)
@ -134,7 +135,10 @@ static uint8_t bbc0_irq_mask = 0;
static uint8_t bbc1_irq_mask = 0;
static bool rf_update_config = false;
static bool rf_update_tx_power = false;
static int8_t cca_threshold = -80;
static uint8_t rf_tx_power = TXPWR_31;
static bool data_whitening_enabled = true;
static bool cca_enabled = true;
static uint32_t rf_symbol_rate;
@ -303,9 +307,25 @@ static int8_t rf_extension(phy_extension_type_e extension_type, uint8_t *data_pt
case PHY_EXTENSION_SET_CCA_THRESHOLD:
rf_conf_set_cca_threshold(*data_ptr);
break;
case PHY_EXTENSION_SET_TX_POWER:
if (*data_ptr > 100) {
return -1;
}
rf_update_tx_power = rf_conf_set_tx_power(*data_ptr);
if (rf_update_tx_power && (rf_state == RF_IDLE)) {
rf_receive(rf_rx_channel, rf_module);
}
break;
case PHY_EXTENSION_SET_CHANNEL_CCA_THRESHOLD:
cca_threshold = (int8_t) *data_ptr; // *NOPAD*
break;
case PHY_EXTENSION_SET_DATA_WHITENING:
data_whitening_enabled = (bool) *data_ptr; // *NOPAD*
rf_update_config = true;
if (rf_state == RF_IDLE) {
rf_receive(rf_rx_channel, rf_module);
}
break;
case PHY_EXTENSION_SET_802_15_4_MODE:
mac_mode = (phy_802_15_4_mode_t) *data_ptr; // *NOPAD*
if (mac_mode == IEEE_802_15_4_2011) {
@ -418,6 +438,12 @@ static void rf_init_registers(rf_modules_e module)
rf_write_bbc_register_field(BBC_AFC0, module, AFEN0, 0);
// Enable FSK
if (phy_current_config.modulation == M_2FSK) {
// Enable or disable data whitening
if (data_whitening_enabled) {
rf_write_bbc_register_field(BBC_FSKPHRTX, module, DW, DW);
} else {
rf_write_bbc_register_field(BBC_FSKPHRTX, module, DW, 0);
}
rf_write_bbc_register_field(BBC_PC, module, PT, BB_MRFSK);
// Set bandwidth time product
rf_write_bbc_register_field(BBC_FSKC0, module, BT, BT_20);
@ -474,8 +500,10 @@ static void rf_init_registers(rf_modules_e module)
// Enable external front end with configuration 3
rf_write_rf_register_field(RF_PADFE, module, PADFE, RF_FEMODE3);
// Output power at 900MHz: 0 dBm with FSK/QPSK, less than -5 dBm with OFDM
rf_write_rf_register_field(RF_PAC, module, TXPWR, TXPWR_11);
rf_tx_power = TXPWR_11;
}
// Set TX output power
rf_write_rf_register_field(RF_PAC, module, TXPWR, rf_tx_power);
// Enable analog voltage regulator
rf_write_rf_register_field(RF_AUXS, module, AVEN, AVEN);
// Disable filtering FCS
@ -695,7 +723,7 @@ static void rf_handle_rx_start(void)
static void rf_receive(uint16_t rx_channel, rf_modules_e module)
{
if ((receiver_enabled == true) && (rf_update_config == false) && (rx_channel == rf_rx_channel)) {
if ((receiver_enabled == true) && (rf_update_config == false) && (rf_update_tx_power == false) && (rx_channel == rf_rx_channel)) {
return;
}
TEST_RX_DONE
@ -706,6 +734,12 @@ static void rf_receive(uint16_t rx_channel, rf_modules_e module)
rf_init_registers(module);
rf_change_state(RF_TXPREP, module);
}
if (rf_update_tx_power == true) {
rf_update_tx_power = false;
rf_change_state(RF_TRX_OFF, module);
rf_write_rf_register_field(RF_PAC, module, TXPWR, rf_tx_power);
rf_change_state(RF_TXPREP, module);
}
if (rx_channel != rf_rx_channel) {
rf_change_state(RF_TXPREP, module);
rf_set_channel(rx_channel, module);
@ -1170,6 +1204,17 @@ static void rf_conf_set_cca_threshold(uint8_t percent)
cca_threshold = MIN_CCA_THRESHOLD + (step * percent) / 100;
}
static bool rf_conf_set_tx_power(uint8_t percent)
{
uint8_t step = (TXPWR_31 - TXPWR_0);
uint8_t new_value = TXPWR_0 + (step * percent) / 100;
if (rf_tx_power != new_value) {
rf_tx_power = new_value;
return true;
}
return false;
}
static void rf_calculate_symbol_rate(uint32_t baudrate, phy_modulation_e modulation)
{
uint8_t bits_in_symbols = 4;

View File

@ -1328,7 +1328,7 @@ NanostackRfPhys2lp::NanostackRfPhys2lp(PinName spi_sdi, PinName spi_sdo, PinName
#ifdef AT24MAC
_mac(i2c_sda, i2c_scl),
#endif //AT24MAC
_mac_addr(), _rf(NULL), _mac_set(false),
_mac_addr(), _rf(NULL), _test_pins(NULL), _mac_set(false),
_spi_sdi(spi_sdi), _spi_sdo(spi_sdo), _spi_sclk(spi_sclk), _spi_cs(spi_cs), _spi_sdn(spi_sdn),
_spi_gpio0(spi_gpio0), _spi_gpio1(spi_gpio1), _spi_gpio2(spi_gpio2), _spi_gpio3(spi_gpio3)
{

View File

@ -26,7 +26,7 @@ The purpose of the library is to provide a light, simple and general tracing sol
* The trace function uses `stdout` as the default output target because it goes directly to serial port in mbed-os.
* The trace function produces traces like: `[<levl>][grp ]: msg`. This provides an easy way to detect trace prints and separate traces from normal prints (for example with _regex_).
* This approach requires a `sprintf` implementation (`stdio.h`). The memory consumption is pretty high, but it allows an efficient way to format traces.
* The solution is not Interrupt safe. (PRs are more than welcome.)
* The solution is not Interrupt safe. ([PRs](https://github.com/ARMmbed/mbed-trace/pulls) are more than welcome.)
* The solution is not thread safe by default. Thread safety for the actual trace calls can be enabled by providing wait and release callback functions that use mutexes defined by the application.
## Examples of traces
@ -43,7 +43,7 @@ The purpose of the library is to provide a light, simple and general tracing sol
### Prerequisites
* Initialize the serial port so that `stdout` works. You can verify that the serial port works using the `printf()` function.
* if you want to redirect the traces somewhere else, see the [trace API](https://github.com/ARMmbed/mbed-trace/blob/master/mbed-trace/mbed_trace.h#L245).
* If you want to redirect the traces somewhere else, see the [trace API](https://github.com/ARMmbed/mbed-trace/blob/master/mbed-trace/mbed_trace.h#L245).
* To enable the tracing API:
* With yotta: set `YOTTA_CFG_MBED_TRACE` to 1 or true. Setting the flag to 0 or false disables tracing.
* [With mbed OS 5](#enabling-the-tracing-api-in-mbed-os-5)
@ -54,7 +54,7 @@ The purpose of the library is to provide a light, simple and general tracing sol
* If thread safety is needed, configure the wait and release callback functions before initialization to enable the protection. Usually, this needs to be done only once in the application's lifetime.
* If [helping functions](#helping-functions) are used the mutex must be **recursive** (counting) so it can be acquired from a single thread repeatedly.
* Call the trace initialization (`mbed_trace_init`) once before using any other APIs. It allocates the trace buffer and initializes the internal variables.
* Define `TRACE_GROUP` in your source code (not in the header!) to use traces. It is a 1-4 characters long char-array (for example `#define TRACE_GROUP "APPL"`). This will be printed on every trace line.
* Define `TRACE_GROUP` in your **source code (not in the header)** to use traces. It is a 1-4 characters long char-array (for example `#define TRACE_GROUP "APPL"`). This will be printed on every trace line.
### Enabling the tracing API in mbed OS 5
@ -72,7 +72,7 @@ To do so, add the following to your mbed_app.json:
}
```
Don't forget to fulfill the other [prerequisites](#prerequisites)!
Do not forget to fulfill the other [prerequisites](#prerequisites)!
([Click here for more information on the configuration system](https://docs.mbed.com/docs/mbed-os-api/en/latest/config_system/))
@ -204,6 +204,52 @@ int main(void){
}
```
## Run-time trace group filtering
The trace groups you have defined using the `TRACE_GROUP` macro in your .c/.cpp files can be used to control tracing at run-time.
| Function | Explanation |
|-----------------------------------|--------------------------------------------------------------|
|`mbed_trace_include_filters_get()` | Get the exclusion filter list string. |
|`mbed_trace_include_filters_set()` | Set trace list to include only the traces matching the list. |
|`mbed_trace_exclude_filters_get()` | Get the inclusion filter list string. |
|`mbed_trace_exclude_filters_set()` | Set trace list to exclude the traces matching the list. |
The filter list is a null terminated string of comma (`,`) separated trace group names. The default maximum length of the string is 24 characters, including the terminating null. Length can be changed by defining the macro `DEFAULT_TRACE_FILTER_LENGTH`. Exclude and include filters can be combined freely as they both have their own filtering list.
The matching is done simply using `strstr()` from C standard libraries.
### Examples of trace group filtering
Assuming we have 4 modules called "MAIN", "HELP", "CALC" and "PRNT" we could use the filters in the following ways.
#### Inclusion filter
To include only "MAIN" and "CALC" traces to the trace prints, we can do:
```
mbed_trace_include_filters_set("MAIN,CALC");
```
This would print out only the traces from "MAIN" and "CALC", since they are the trace groups matching the filter list. Trace groups "HELP" and "PRNT" would not be printed out at all.
## Exclusion filter
```
mbed_trace_exclude_filters_set("HELP,PRNT");
```
This would exclue trace groups "HELP" and "PRNT" out of trace printing, thus leaving only prints from "MAIN" and "CALC" visible in the tracing.
### Reset filter
```
mbed_trace_include_filters_set(NULL);
```
This would reset the inclusion filters back to nothing and assuming no exclusion filter is in place either, all trace groups prints would get printed.
## Unit tests
To run unit tests:

View File

@ -23,8 +23,18 @@
extern "C" {
#endif
/** \defgroup ns_list Linked list support library.
*
* The ns_list.h file provides a doubly-linked list/queue, providing O(1)
* performance for all insertion/removal operations, and access to either
* end of the list.
*
* See \ref ns_list.h for documentation.
*/
/** \file
* \brief Linked list support library
* \ingroup ns_list
* \brief Linked list support library.
*
* The ns_list.h file provides a doubly-linked list/queue, providing O(1)
* performance for all insertion/removal operations, and access to either

View File

@ -1,3 +1,5 @@
# Copyright (c) 2019 ARM Limited
# SPDX-License-Identifier: Apache-2.0
# Define compiler toolchain with CC or PLATFORM variables
# Example (GCC toolchains)
# make PLATFORM=arm-linux-gnueabi-

View File

@ -19,6 +19,176 @@
extern "C" {
#endif
/**
* \defgroup nanostack-eventloop Nanostack's event system.
* Small event scheduler and timer system written in C.
*
* This event system is originating from project called Nanostack and developed within Arm. Therefore
* some of the types and names within this library are prefixed with `ns_*` or `arm_*` or `eventOS*`.
*
* <h3>Concept</h3>
*
* Event loop uses a concept called tasklet, which is just a callback function that receives events.
* There can be as many as 128 tasklets registered if memory allows. This is only limited by event ID being just 8-bits.
* Each tasklet is first registered to the event system, which then gives 8 bit ID number for the tasklet.
*
* @startuml
* package "eventOS" {
* [eventOS_event.h] - event_handler_create
* }
* node "application" {
* [tasklet1.cpp] ..> event_handler_create : register
* [tasklet1.cpp] - tasklet1
* [tasklet2.cpp] ..> event_handler_create : register
* [tasklet2.cpp] - tasklet2
* [tasklet3.cpp] ..> event_handler_create : register
* [tasklet3.cpp] - tasklet3
* }
* @enduml
*
* Events are send to a specific tasklet, identified by its ID.
* Each event is coded into a \ref arm_event_s structure which is then pushed into event loop by calling eventOS_event_send().
*
* @startuml
* partition tasklet1.cpp {
* (*) --> tasklet1
* }
* partition "eventOS" {
* tasklet1 -->[event:\nreceiver: 3\nevent_id: 1] eventOS_event_send
* }
* partition tasklet3.cpp {
* eventOS_event_send -->[event:\nreceiver: 3\nevent_id: 1] tasklet3
* }
* @enduml
*
* <h3>Usage</h3>
*
* To send or receive events, you first need to register your event handler.
* \code
* // In header
* extern uint8_t my_eventhandler_id;
* #define INITIALIZATION_EVENT 0
* #define MY_EVENT 1
*
* // In my_handler.cpp
* void my_event_handler(arm_event_t *e)
* {
* switch (e->event_type) {
* case INITIALIZATION_EVENT:
* // Initialize my module
* break;
* case MY_EVENT:
* // Event received
* break;
* }
* }
*
* // Register the handler
* my_eventhandler_id = eventOS_event_handler_create(my_event_handler, INITIALIZATION_EVENT);
* if (my_eventhandler_id < 0) {
* // fail
* }
* \endcode
*
* Each event is basically a \ref arm_event_s structure. You need to fill in the arm_event_s::receiver field.
* Rest of the fields are optional, and used only by the receiving callback. So you have different options to
* deliver data to a receiving tasklet. The structure is copied by the event system, so temporary storage may be used,
* and the structure may be freed after it has been pushed into event system.
*
* \code
* // Send the event
* arm_event_t e = {
* .receiver = my_eventhandler_id,
* .event_type = MY_EVENT
* };
*
* if (eventOS_event_send(e) != 0) {
* // fail
* }
* \endcode
*
* Where required, event system allows you to delay the event propagation.
*
* \code
* // Wait 3 seconds before the event
* #define MY_DELAY_MS 3000
*
* arm_event_t e = {
* .receiver = my_eventhandler_id,
* .event_type = MY_EVENT
* };
*
* uint32_t delay = eventOS_event_timer_ms_to_ticks(MY_DELAY_MS);
* eventOS_event_send_after(e, delay);
* \endcode
*
* \sa eventOS_event.h
* \sa eventOS_event_send_at
* \sa eventOS_event_send_in
* \sa eventOS_event_send_after
* \sa eventOS_event_send_every
*
* <h3>Pre-allocated events</h3>
*
* Two options are provided to limit the heap usage. First option is to use recurring events with eventOS_event_send_every(),
* so your event is only allocated once. This allows you to create application that does not use heap after initialization phase.
*
* Second option is to use pre-allocated or statically allocated event structure. In this model you create a space for
* \ref arm_event_storage structure and send events using eventOS_event_send_user_allocated() call. This is also
* very robust, as there is no allocation, so the sending of the event will never fail because of lack of memory.
*
* \code
* static bool pending = false;
* static arm_event_storage_t e;
* static int8_t foo_tasklet_id;
*
* void notify_foo()
* {
* if (!pending) {
* pending = true;
* e.data.receiver = foo_tasklet_id;
* e.data.type = MY_EVENT;
* eventOS_event_send_user_allocated(&e);
* }
* }
*
* void foo_event_handler(arm_event_t *e)
* {
* pending = false;
* // ...
* }
*
* \endcode
*
* <h3>Initialization</h3>
*
* Event system does not use malloc(), free() or any system heap directly, but uses nsdynmemLIB.h library instead.
* Event system must first be initialized by callind eventOS_scheduler_init(). This is usually done just after ns_dyn_mem_init() call.
* Where porting is already provided, these both are initialized in function called ns_hal_init().
*
* After initialization, you can start the event loop by calling eventOS_scheduler_run() which will never return. This is usually
* end of the `main()` function.
*
* \code
* extern void my_event_handler(arm_event_t *e);
* extern int8_t my_eventhandler_id;
*
* void main(void)
* {
* ns_dyn_mem_init(NULL, HEAP_SIZE, NULL, NULL);
* eventOS_scheduler_init();
* my_eventhandler_id = eventOS_event_handler_create(my_event_handler, INITIALIZATION_EVENT);
* eventOS_scheduler_run()
* }
* \endcode
*/
/**
* \file eventOS_event.h
* \ingroup nanostack-eventloop
* \brief Nanostack's event loop.
*/
#include "ns_types.h"
#include "ns_list.h"
@ -100,10 +270,10 @@ extern int8_t eventOS_event_send(const arm_event_t *event);
/* Alternate names for timer function from eventOS_event_timer.h;
* implementations may one day merge */
#define eventOS_event_send_at(event, at) eventOS_event_timer_request_at(event, at)
#define eventOS_event_send_in(event, in) eventOS_event_timer_request_in(event, in)
#define eventOS_event_send_after(event, after) eventOS_event_timer_request_after(event, after)
#define eventOS_event_send_every(event, every) eventOS_event_timer_request_every(event, every)
#define eventOS_event_send_at(event, at) eventOS_event_timer_request_at(event, at) ///< \copydoc eventOS_event_timer_request_at
#define eventOS_event_send_in(event, in) eventOS_event_timer_request_in(event, in) ///< \copydoc eventOS_event_timer_request_in
#define eventOS_event_send_after(event, after) eventOS_event_timer_request_after(event, after) ///< \copydoc eventOS_event_timer_request_after
#define eventOS_event_send_every(event, every) eventOS_event_timer_request_every(event, every) ///< \copydoc eventOS_event_timer_request_every
/**
* \brief Send user-allocated event to event scheduler.

View File

@ -18,6 +18,14 @@
#ifdef __cplusplus
extern "C" {
#endif
/**
* \file eventOS_event_timer.h
* \ingroup nanostack-eventloop
* \brief Functions for sending delayed events.
*/
#include "ns_types.h"
#include "eventOS_event.h"
@ -208,9 +216,8 @@ extern int8_t eventOS_event_timer_cancel(uint8_t event_id, int8_t tasklet_id);
/**
* System Timer shortest time in milli seconds
*
* \param ticks Time in 10 ms resolution
*
* \return none
* \return zero, if no timers are active.
* \return time in milliseconds to next timer event.
*
* */
extern uint32_t eventOS_event_timer_shortest_active_timer(void);

View File

@ -15,10 +15,16 @@
*/
#ifndef EVENTOS_SCHEDULER_H_
#define EVENTOS_SCHEDULER_H_
#ifdef __cplusplus
extern "C" {
#endif
/**
* \file eventOS_scheduler.h
* \ingroup nanostack-eventloop
* \brief Event scheduler's control functions.
*/
#include "ns_types.h"
/* Compatibility with older ns_types.h */

View File

@ -183,6 +183,14 @@ typedef void mcps_data_indication_ext(const mac_api_t *api, const mcps_data_ind_
typedef void mcps_ack_data_req_ext(const mac_api_t *api, mcps_ack_data_payload_t *data, int8_t rssi, uint8_t lqi);
/**
* @brief mcps_edfe_handler Callback for handle and detect edfe frame
* @param api The API which handled the response
* @param response_message Enhanced message response data and status
*/
typedef void mcps_edfe_handler(const mac_api_t *api, mcps_edfe_response_t *response_message);
/**
* @brief mcps_purge_confirm MCPS-PURGE confirm is called as a response to MCPS-PURGE request
* @param api The API which handled the request
@ -254,6 +262,15 @@ typedef int8_t mac_api_enable_mcps_ext(mac_api_t *api,
mcps_data_confirm_ext *data_cnf_cb,
mcps_ack_data_req_ext *ack_data_req_cb);
/**
* @brief mac_api_enable_mcps_edfe_ext Initialises MAC 2015 extension for EDFE handler callbacks must be non-NULL.
* @param api mac_api_t pointer, which is created by application.
* @param edfe_ind_cb Upper layer function to handle and detect EDFE's
* @return -1 if error, -2 if OOM, 0 otherwise
*/
typedef int8_t mac_api_enable_mcps_edfe_ext(mac_api_t *api,
mcps_edfe_handler *edfe_ind_cb);
/**
* \brief Struct mac_api_s defines functions for two-way communications between external MAC and Upper layer.
* Application creates mac_api_t object by calling external MAC's creator function.
@ -263,17 +280,18 @@ typedef int8_t mac_api_enable_mcps_ext(mac_api_t *api,
struct mac_api_s {
mac_api_initialize *mac_initialize; /**< MAC initialize function to use */
mac_api_enable_mcps_ext *mac_mcps_extension_enable; /**< MAC MCPS IE extension enable function, optional feature */
mac_api_enable_mcps_edfe_ext *mac_mcps_edfe_enable; /**< MAC MCPS MCPS EDFE frame extension enable function, optional feature */
//External MAC callbacks
mlme_request *mlme_req; /**< MAC MLME request function to use */
mcps_data_request *mcps_data_req; /**< MAC MCPS data request function to use */
mcps_data_request_ext *mcps_data_req_ext; /**< MAC MCPS data request with Information element extension function to use */
mcps_purge_request *mcps_purge_req; /**< MAC MCPS purge request function to use */
//Upper layer callbacksMLME_ASSOCIATE
mcps_data_confirm *data_conf_cb; /**< MAC MCPS data confirm callback function */
mcps_data_confirm_ext *data_conf_ext_cb; /**< MAC MCPS data confirm with payload callback function */
mcps_data_indication *data_ind_cb; /**< MAC MCPS data indication callback function */
mcps_data_indication_ext *data_ind_ext_cb; /**< MAC MCPS data indication with IE extension's callback function */
mcps_edfe_handler *edfe_ind_cb; /**< MAC MCPS EDFE detection extension's callback function */
mcps_ack_data_req_ext *enhanced_ack_data_req_cb; /**< Enhanced ACK IE element and payload request from MAC user */
mcps_purge_confirm *purge_conf_cb; /**< MAC MCPS purge confirm callback function */
mlme_confirm *mlme_conf_cb; /**< MAC MLME confirm callback function */

View File

@ -44,6 +44,7 @@ typedef struct mcps_data_req_s {
bool PendingBit: 1; /**< Specifies whether more fragments are to be sent or not */
bool SeqNumSuppressed: 1; /**< True suppress sequence number from frame. This will be only checked when 2015 extension is enabled */
bool PanIdSuppressed: 1; /**< True suppress PAN-id is done when possible from frame. This will be only checked when 2015 extension is enabled */
bool ExtendedFrameExchange: 1; /**< True for Extended Frame change. This will be only checked when 2015 extension and enhanced frame is enabled */
mlme_security_t Key; /**< Security key */
} mcps_data_req_t;
@ -86,6 +87,7 @@ typedef struct mcps_data_ind_s {
uint16_t SrcPANId; /**< Source PAN ID */
uint8_t SrcAddr[8]; /**< Source address */
unsigned DstAddrMode: 2; /**< Destination address mode */
bool DSN_suppressed: 1; /**< Indicate when DSN not include valid sequency id */
uint16_t DstPANId; /**< Destination PAN ID */
uint8_t DstAddr[8]; /**< Destination address */
uint8_t mpduLinkQuality; /**< LQI value measured during reception of the MPDU */
@ -164,5 +166,31 @@ typedef struct mcps_purge_conf_s {
uint8_t status; /**< Status of the purge performed */
} mcps_purge_conf_t;
#define MCPS_EDFE_NORMAL_FRAME 0 /**< Normal Data message normal behaviour */
#define MCPS_EDFE_MALFORMED_FRAME 1 /**< Drop whole packet */
#define MCPS_EDFE_TX_FRAME 2 /**< Tx message send data if pending in 1ms -5ms time window */
#define MCPS_EDFE_RESPONSE_FRAME 3 /**< Response message send data if pending in 1ms -5ms time window */
#define MCPS_EDFE_FINAL_FRAME_TX 4 /**< Final response message send in 1ms -5ms time window */
#define MCPS_EDFE_FINAL_FRAME_RX 5 /**< EDFE session can be close at MAC side and drop this packet */
/**
* @brief struct mcps_edfe_response_t EDFE detetction and response structure
*
*/
typedef struct mcps_edfe_response_s {
struct mcps_data_ie_list ie_elements; /**< IE hader and payload's elements from Packet */
struct mcps_data_req_ie_list ie_response; /**< IE hader and payload's elements for Response Packet */
uint8_t edfe_message_status; /**< Indicate Packet handler status */
uint8_t message_handle; /**< EDFE Data request message ID for detect pending data at LLC layer*/
int8_t rssi; /**< Received packet signal streng in dbm */
unsigned SrcAddrMode: 2; /**< Source address mode: used for RX validation and TX purpose */
unsigned DstAddrMode: 2; /**< Destination address mode: used for RX validation and TX purpose */
uint8_t Address[8]; /**< RX: Packet Address Src & TX Response Destination address */
bool SeqNumSuppressed: 1; /**< True suppress sequence number from frame. This will be only checked when 2015 extension is enabled */
bool PanIdSuppressed: 1; /**< True suppress PAN-id is done when possible from frame. */
bool wait_response: 1; /**< True enable response wait timer and re-send operation. */
bool use_message_handle_to_discover: 1; /**< EDFE Data request message ID is valid at message_handle. */
} mcps_edfe_response_t;
#endif // MAC_MCPS_H

View File

@ -264,6 +264,8 @@ typedef enum {
macAutoRequestKeyIndex = 0x7b, /*<The index of the key used for automatic data*/
macDefaultKeySource = 0x7c, /*<Default key source*/
//NON standard extension
macEdfeForceStop = 0xf2, /*< Use this command for Data wait timeout at LLC: Mac stop Edfe session data wait and enable normal FHSS mode */
macSetDataWhitening = 0xf3, /*< Enable or disable data whitening, boolean true for enable, false for disable */
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*/

View File

@ -286,6 +286,12 @@ typedef struct {
uint8_t *beacon_payload_tlv_ptr; /**< Optional steering parameters. */
} network_driver_setup_s;
/** CCA threshold table */
typedef struct {
uint8_t number_of_channels; /**< Number of channels */
const int8_t *cca_threshold_table; /**< CCA threshold table */
} cca_threshold_table_s;
/**
* Init 6LoWPAN library
*
@ -1135,6 +1141,20 @@ extern int8_t arm_nwk_set_cca_threshold(int8_t interface_id, uint8_t cca_thresho
*/
extern int8_t arm_nwk_set_tx_output_power(int8_t interface_id, uint8_t tx_power);
/**
* \brief Get CCA threshold table.
*
* This function can be used to read CCA threshold table.
* CCA threshold table structure contains number of channels and an array indicating the currently used CCA threshold value of each channel. CCA threshold values are updated by library continuously.
* If channels are reconfigured, number of channels and table length are changed automatically. User should check the table length (number of channels) before reading the table.
* Automatic CCA threshold feature may not be enabled before interface is up, causing function to return NULL.
* Returned pointer to cca_threshold_table_s structure is valid until interface is destroyed. Re-reading the pointer with this function is allowed any time.
*
* \param interface_id Network interface ID.
* \return NULL if automatic CCA threshold feature is not enabled, otherwise pointer to CCA threshold structure.
*/
extern const cca_threshold_table_s *arm_nwk_get_cca_threshold_table(int8_t interface_id);
#ifdef __cplusplus
}

View File

@ -131,4 +131,50 @@ int8_t arm_nwk_ipv6_opaque_iid_key(const void *secret_key, uint8_t key_len);
*/
int8_t arm_nwk_ipv6_opaque_iid_enable(int8_t interface_id, bool enable);
/**
* \brief Enable/disable default route in Router advertisements
*
* Enable or disable RFC 4861 Default router configuration in router advertisements.
* This makes the device a default router in the interface.
*
* \param interface_id Interface ID.
* \param enable True to enable.
* \return 0 enabled/disabled OK.
* \return <0 failed (for example invalid interface ID).
*
*/
int8_t arm_nwk_ipv6_default_route_enable(int8_t interface_id, bool enable);
/**
* \brief add Recursive DNS Server Option information to Router advertisements
*
* Add Recursive DNS Server Option from RFC 8106 to router advertisements.
* This makes it possible to configure DNS server address to other devices connected to the interface.
*
* \param interface_id Interface ID.
* \param address 16 byte array for IPv6 address.
* \param lifetime advertised lifetime of the entry. 0 to delete address.
* \return 0 DNS server option option successful.
* \return <0 failed (for example invalid interface ID).
*
*/
int8_t arm_nwk_ipv6_dns_server_add(int8_t interface_id, uint8_t *address, uint32_t lifetime);
/**
* \brief add DNS Search List Option information to Router advertisements
*
* Add DNS Search List Option from RFC 8106 to router advertisements.
* This makes it possible to configure DNS search list to other devices connected to the interface.
*
* \param interface_id Interface ID.
* \param data byte array encoded following https://tools.ietf.org/html/rfc1035#section-3.1.
* \param data_len Length of the byte array
* \param lifetime advertised lifetime of the entry. 0 to delete address.
* \return 0 DNS server option option successful.
* \return <0 failed (for example invalid interface ID).
*
*/
int8_t arm_nwk_ipv6_dns_search_list_add(int8_t interface_id, uint8_t *data, uint16_t data_len, uint32_t lifetime);
#endif /* NET_IPV6_API_H_ */

View File

@ -167,6 +167,43 @@ int ws_test_gtk_time_settings_set(
*/
int ws_test_next_gtk_set(int8_t interface_id, uint8_t *gtk[4]);
/**
* Sets 6LoWPAN fragmentation MTU size to test fragmentation
*
* \param interface_id Network interface ID.
* \param mtu_size Size of 6LoWPAN MTU when fragmentation occurs.
*
* \return 0 Success
* \return <0 Failure
*/
int ws_test_6lowpan_fragmentation_mtu_size_set(int8_t interface_id, uint16_t mtu_size);
/**
* Disable First EDFE data packet send.
*
* Made only for test purpose for test EDFE client Data wait timeout.
*
* \param interface_id Network interface ID.
* \param skip True for skip first data packet false disable unused flag.
*
* \return 0 Success
* \return <0 Failure
*/
void ws_test_skip_edfe_data_send(int8_t interface_id, bool skip);
/**
* Drop configured EDFE data packets.
*
* Made only for test purpose for test EDFE data sender retry send logic.
*
* \param interface_id Network interface ID.
* \param number_of_dropped_frames How many packets will be dropped.
*
* \return 0 Success
* \return <0 Failure
*/
int8_t ws_test_drop_edfe_data_frames(int8_t interface_id, uint8_t number_of_dropped_frames);
#ifdef __cplusplus
}
#endif

View File

@ -81,6 +81,7 @@ typedef enum {
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_DATA_WHITENING, /**< Enable or disable data whitening. Boolean true for enable, false for disable */
PHY_EXTENSION_SET_802_15_4_MODE /**< Set IEEE 802.15.4 mode as defined by phy_802_15_4_mode_t*/
} phy_extension_type_e;

View File

@ -712,11 +712,12 @@ static inline int8_t socket_read_session_address(int8_t socket, ns_address_t *ad
* | SOCKET_IPV6_MULTICAST_LOOP | bool | Yes | Yes | No |
* | SOCKET_IPV6_JOIN_GROUP | ns_ipv6_mreq_t | Set only | No | No |
* | SOCKET_IPV6_LEAVE_GROUP | ns_ipv6_mreq_t | Set only | No | No |
* | SOCKET_LATENCY | ns_ipv6_latency_t | Get only | No | No |
* | SOCKET_STAGGER | ns_ipv6_stagger_t | Get only | No | No |
* | SOCKET_EDFE_MODE | bool | Set only | No | No |
* | SOCKET_BROADCAST_PAN | int8_t | Yes | No | No |
* | SOCKET_LINK_LAYER_SECURITY | int8_t | Yes | No | No |
* | SOCKET_INTERFACE_SELECT | int8_t | Yes | No | No |
* | SOCKET_LATENCY | ns_ipv6_latency_t | Get only | No | No |
* | SOCKET_STAGGER | ns_ipv6_stagger_t | Get only | No | No |
*
*/
@ -755,11 +756,10 @@ static inline int8_t socket_read_session_address(int8_t socket, ns_address_t *ad
#define SOCKET_IPV6_JOIN_GROUP 15
/** Leave a multicast group, using ns_ipv6_mreq_t */
#define SOCKET_IPV6_LEAVE_GROUP 16
/** Read estimated latency to reach destination */
#define SOCKET_LATENCY 17
/** Read estimated stagger value that can be used as initial delay after bootstrap or firmware update. */
#define SOCKET_STAGGER 18
#define SOCKET_LATENCY 0xf9 /**< Not standard, read estimated latency to reach destination */
#define SOCKET_STAGGER 0xfa /**< Not standard, read estimated stagger value that can be used as initial delay after bootstrap or firmware update. */
#define SOCKET_EDFE_MODE 0xfb /**< Not standard, Extended Directed Frame Exchange mode enabled/disabled in MAC layer */
#define SOCKET_BROADCAST_PAN 0xfc /**< Internal use - transmit with IEEE 802.15.4 broadcast PAN ID */
#define SOCKET_LINK_LAYER_SECURITY 0xfd /**< Not standard enable or disable socket security at link layer (For 802.15.4). */
#define SOCKET_INTERFACE_SELECT 0xfe /**< Not standard socket interface ID. */

View File

@ -36,6 +36,8 @@
typedef struct bbr_information {
/** Timestamp of the the device. Can be used as version number*/
uint64_t timestamp;
/** Default route Link Local address of north bound router*/
uint8_t gateway[16];
/** Border router dodag id */
uint8_t dodag_id[16];
/** Address prefix given to devices in network set to 0 if not available*/
@ -130,9 +132,9 @@ int ws_bbr_info_get(int8_t interface_id, bbr_information_t *info_ptr);
*
* 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.
* IPv6 = Global Prefix + IID.
*
* Routing table is in the format: 18 bytes per entry
* Routing table is in the format: 16 bytes per entry
* | Node IID 8 bytes | parent IID 8 bytes |
* | 1122112211221122 | 1111111111111111 |
* | 1133113311331133 | 1111111111111111 |
@ -142,15 +144,18 @@ int ws_bbr_info_get(int8_t interface_id, bbr_information_t *info_ptr);
* | 1177117711771177 | 1155115511551155 |
* | 1188118811881188 | 1177117711771177 |
*
* Order is not assured only parent child link is given in random order
* 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
* When preparing to call this function ws_bbr_info_get function should be called to get the amount of devices in the network.
* Memory for table is allocated based on the size of network and needs to be sizeof(bbr_route_info_t) * amount of entries.
*
* \param interface_id interface ID of the Wi-SUN network
* \param table_ptr Application allocated memory block where routing table is written.
* Return value is amount of route entries written to the table.
*
* \param interface_id interface ID of the Wi-SUN network.
* \param table_ptr Application allocated memory 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 - x on success indicates amount of Route entries written to the table_ptr
* \return <0 in case of errors
*
*/
@ -317,7 +322,7 @@ 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
* 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.
@ -334,7 +339,7 @@ int ws_bbr_pan_configuration_validate(int8_t interface_id, uint16_t pan_id);
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
* 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
@ -352,4 +357,68 @@ int ws_bbr_key_storage_memory_set(int8_t interface_id, uint8_t key_storages_numb
*/
int ws_bbr_key_storage_settings_set(int8_t interface_id, uint8_t alloc_max_number, uint16_t alloc_size, uint16_t storing_interval);
/**
* Set RADIUS server IPv6 address
*
* Function sets external RADIUS server IPv6 address to Border Router. Setting the
* address enables external RADIUS server interface on Border Router. To disable external
* RADIUS server interface, call the function with remote address set to NULL. The RADIUS
* shared secret must be set before address is set using ws_bbr_radius_shared_secret_set()
* call.
*
* \param interface_id Network interface ID.
* \param address Pointer to IPv6 address or NULL to disable RADIUS. Address is in binary format (16 bytes).
*
* \return < 0 failure
* \return >= 0 success
*
*/
int ws_bbr_radius_address_set(int8_t interface_id, const uint8_t *address);
/**
* Get RADIUS server IPv6 address
*
* Function gets external RADIUS server IPv6 address to Border Router.
*
* \param interface_id Network interface ID.
* \param address buffer where to write address, must have space at least for 39 characters and NUL terminator
*
* \return < 0 failure
* \return >= 0 success
*
*/
int ws_bbr_radius_address_get(int8_t interface_id, uint8_t *address);
/**
* Set RADIUS shared secret
*
* Function sets RADIUS shared secret to Border Router. Shared secret may be an
* ASCII string. Check the format and length constraints for the shared secret from
* the documentation of RADIUS server you are connecting to.
*
* \param interface_id Network interface ID.
* \param shared_secret_len The length of the shared secret in bytes.
* \param shared_secret Pointer to shared secret. Can be 8-bit ASCII string or byte array. Is not NUL terminated.
*
* \return < 0 failure
* \return >= 0 success
*
*/
int ws_bbr_radius_shared_secret_set(int8_t interface_id, const uint16_t shared_secret_len, const uint8_t *shared_secret);
/**
* Get RADIUS shared secret
*
* Function gets RADIUS shared secret to Border Router.
*
* \param interface_id Network interface ID.
* \param shared_secret_len On function call, is the size of the shared secret write buffer in bytes, on return is the shared secret length in bytes.
* \param shared_secret Pointer to buffer where to write shared secret or NULL. At maximum, bytes set by the length parameter are written. If NULL only buffer length is returned.
*
* \return < 0 failure
* \return >= 0 success
*
*/
int ws_bbr_radius_shared_secret_get(int8_t interface_id, uint16_t *shared_secret_len, uint8_t *shared_secret);
#endif /* WS_BBR_API_H_ */

View File

@ -103,6 +103,24 @@ typedef struct ws_statistics {
uint32_t asynch_rx_count;
} ws_statistics_t;
/**
* \brief Struct ws_info defines the Wi-SUN stack state.
*/
typedef struct ws_stack_info {
/** Parent link local address */
uint8_t parent[16];
/** parent RSSI Out measured RSSI value calculated using EWMA specified by Wi-SUN from range of -174 (0) to +80 (254) dBm.*/
uint8_t rsl_out;
/** parent RSSI in measured RSSI value calculated using EWMA specified by Wi-SUN from range of -174 (0) to +80 (254) dBm.*/
uint8_t rsl_in;
/** ETX To border router */
uint16_t routing_cost;
/** Network PAN ID */
uint16_t pan_id;
/** Wi-SUN join state defined by Wi-SUN specification 1-5*/
uint8_t join_state;
} ws_stack_info_t;
/**
* Initialize Wi-SUN stack.
*
@ -583,6 +601,20 @@ int ws_statistics_start(
int ws_statistics_stop(
int8_t interface_id);
/**
* Get information from the stack state.
* Parent information and link qualities with stack state info
*
* \param interface_id Network interface ID.
* \param info_ptr Pointer to stored stack state.
*
* \return 0 Success.
* \return <0 Failure.
*/
int ws_stack_info_get(
int8_t interface_id,
ws_stack_info_t *info_ptr);
#ifdef __cplusplus
}
#endif

View File

@ -75,7 +75,6 @@
#include "Service_Libs/etx/etx.h"
#include "Service_Libs/mac_neighbor_table/mac_neighbor_table.h"
#include "6LoWPAN/ws/ws_common.h"
#include "6LoWPAN/ws/ws_bootstrap.h"
#ifdef HAVE_WS
#include "6LoWPAN/ws/ws_cfg_settings.h"
#endif
@ -517,7 +516,7 @@ uint16_t protocol_6lowpan_neighbor_priority_set(int8_t interface_id, addrtype_t
}
if (new_primary) {
ws_primary_parent_update(cur, entry);
ws_common_primary_parent_update(cur, entry);
}
return 1;
} else {
@ -550,7 +549,7 @@ uint16_t protocol_6lowpan_neighbor_second_priority_set(int8_t interface_id, addr
protocol_stats_update(STATS_ETX_2ND_PARENT, etx_entry->etx >> 4);
}
if (new_secondary) {
ws_secondary_parent_update(cur);
ws_common_secondary_parent_update(cur);
}
return 1;
} else {

View File

@ -31,6 +31,8 @@
static const uint8_t mac_helper_default_key_source[8] = {0xff, 0, 0, 0, 0, 0, 0, 0};
uint16_t test_6lowpan_fragmentation_mtu_size_override = 0;
static uint8_t mac_helper_header_security_aux_header_length(uint8_t keyIdmode);
static uint8_t mac_helper_security_mic_length_get(uint8_t security_level);
static void mac_helper_keytable_pairwise_descriptor_set(struct mac_api_s *api, const uint8_t *key, const uint8_t *mac64, uint8_t attribute_id);
@ -736,7 +738,11 @@ uint_fast16_t mac_helper_max_payload_size(protocol_interface_info_entry_t *cur,
{
uint16_t max;
max = cur->mac_api->phyMTU - frame_overhead;
if (test_6lowpan_fragmentation_mtu_size_override == 0) {
max = cur->mac_api->phyMTU - frame_overhead;
} else {
max = test_6lowpan_fragmentation_mtu_size_override - frame_overhead;
}
/* But if we want IEEE 802.15.4-2003 compatibility (and it looks like a
* standard PHY), limit ourselves to the 2003 maximum */
@ -744,6 +750,7 @@ uint_fast16_t mac_helper_max_payload_size(protocol_interface_info_entry_t *cur,
cur->mac_api->phyMTU == MAC_IEEE_802_15_4_MAX_PHY_PACKET_SIZE) {
max = MAC_IEEE_802_15_4_MAX_MAC_SAFE_PAYLOAD_SIZE;
}
return max;
}
@ -988,3 +995,23 @@ int8_t mac_helper_mac_device_description_pan_id_update(int8_t interface_id, uint
cur->mac_api->mlme_req(cur->mac_api, MLME_SET, &set_req);
return 0;
}
int8_t mac_helper_start_auto_cca_threshold(int8_t interface_id, uint8_t number_of_channels, int8_t default_dbm, int8_t high_limit, int8_t low_limit)
{
protocol_interface_info_entry_t *cur;
cur = protocol_stack_interface_info_get_by_id(interface_id);
if (!cur || !cur->mac_api) {
return -1;
}
uint8_t start_cca_thr[4] = {number_of_channels, default_dbm, high_limit, low_limit};
mlme_set_t set_req;
set_req.attr = macCCAThresholdStart;
set_req.value_pointer = &start_cca_thr;
set_req.value_size = sizeof(start_cca_thr);
cur->mac_api->mlme_req(cur->mac_api, MLME_SET, &set_req);
/* Get CCA threshold table. Table is stored to interface structure */
mlme_get_t get_req;
get_req.attr = macCCAThreshold;
cur->mac_api->mlme_req(cur->mac_api, MLME_GET, &get_req);
return 0;
}

View File

@ -30,6 +30,7 @@ struct ns_sockaddr;
struct buffer;
struct mac_api_s;
extern uint16_t test_6lowpan_fragmentation_mtu_size_override;
void mac_create_scan_request(mac_scan_type_t type, struct channel_list_s *chanlist, uint8_t scan_duration, struct mlme_scan_s *request);
@ -133,4 +134,6 @@ int8_t mac_helper_mac_mlme_max_retry_set(int8_t interface_id, uint8_t mac_retry_
int8_t mac_helper_mac_device_description_pan_id_update(int8_t interface_id, uint16_t pan_id);
int8_t mac_helper_start_auto_cca_threshold(int8_t interface_id, uint8_t number_of_channels, int8_t default_dbm, int8_t high_limit, int8_t low_limit);
#endif // MAC_HELPER_H

View File

@ -81,6 +81,15 @@ static void mac_mlme_frame_counter_confirmation_handle(protocol_interface_info_e
info_entry->mac_parameters->security_frame_counter = *temp_ptr;
}
static void mac_mlme_cca_threshold_confirmation_handle(protocol_interface_info_entry_t *info_entry, mlme_get_conf_t *confirmation)
{
if (confirmation->value_size < 1) {
return;
}
info_entry->mac_parameters->cca_thr_table.number_of_channels = confirmation->value_size;
info_entry->mac_parameters->cca_thr_table.cca_threshold_table = (int8_t *)confirmation->value_pointer;
}
static void mac_mlme_get_confirmation_handler(protocol_interface_info_entry_t *info_entry, mlme_get_conf_t *confirmation)
{
@ -96,6 +105,10 @@ static void mac_mlme_get_confirmation_handler(protocol_interface_info_entry_t *i
mac_mlme_frame_counter_confirmation_handle(info_entry, confirmation);
break;
case macCCAThreshold:
mac_mlme_cca_threshold_confirmation_handle(info_entry, confirmation);
break;
default:
break;

View File

@ -351,17 +351,14 @@ int8_t lowpan_adaptation_interface_init(int8_t interface_id, uint16_t mac_mtu_si
//Allocate new
fragmenter_interface_t *interface_ptr = ns_dyn_mem_alloc(sizeof(fragmenter_interface_t));
uint8_t *tx_buffer = ns_dyn_mem_alloc(mac_mtu_size);
if (!interface_ptr || !tx_buffer) {
ns_dyn_mem_free(interface_ptr);
ns_dyn_mem_free(tx_buffer);
if (!interface_ptr) {
return -1;
}
memset(interface_ptr, 0, sizeof(fragmenter_interface_t));
interface_ptr->interface_id = interface_id;
interface_ptr->fragment_indirect_tx_buffer = tx_buffer;
interface_ptr->mtu_size = mac_mtu_size;
interface_ptr->fragment_indirect_tx_buffer = NULL;
interface_ptr->mtu_size = 0;
interface_ptr->msduHandle = randLIB_get_8bit();
interface_ptr->local_frag_tag = randLIB_get_16bit();
@ -938,6 +935,7 @@ static void lowpan_data_request_to_mac(protocol_interface_info_entry_t *cur, buf
}
if (interface_ptr->mpx_api) {
dataReq.ExtendedFrameExchange = buf->options.edfe_mode;
interface_ptr->mpx_api->mpx_data_request(interface_ptr->mpx_api, &dataReq, interface_ptr->mpx_user_id);
} else {
cur->mac_api->mcps_data_req(cur->mac_api, &dataReq);
@ -996,6 +994,18 @@ int8_t lowpan_adaptation_interface_tx(protocol_interface_info_entry_t *cur, buff
//Check packet size
bool fragmented_needed = lowpan_adaptation_request_longer_than_mtu(cur, buf, interface_ptr);
if (fragmented_needed) {
// If fragmentation TX buffer not allocated, do it now.
if (!interface_ptr->fragment_indirect_tx_buffer && !interface_ptr->mtu_size) {
interface_ptr->fragment_indirect_tx_buffer = ns_dyn_mem_alloc(cur->mac_api->phyMTU);
if (interface_ptr->fragment_indirect_tx_buffer) {
interface_ptr->mtu_size = cur->mac_api->phyMTU;
} else {
tr_error("Failed to allocate fragmentation buffer");
goto tx_error_handler;
}
}
}
bool is_unicast = buf->link_specific.ieee802_15_4.requestAck;
bool indirect = buf->link_specific.ieee802_15_4.indirectTxProcess;

View File

@ -156,6 +156,20 @@ void ws_bbr_dhcp_address_lifetime_set(protocol_interface_info_entry_t *cur, uint
DHCPv6_server_service_set_address_validlifetime(cur->id, current_global_prefix, dhcp_address_lifetime);
}
bool ws_bbr_backbone_address_get(uint8_t *address)
{
if (backbone_interface_id < 0) {
return false;
}
if (arm_net_address_get(backbone_interface_id, ADDR_IPV6_GP, address) != 0) {
// No global prefix available
return false;
}
return true;
}
static void ws_bbr_rpl_root_start(protocol_interface_info_entry_t *cur, uint8_t *dodag_id)
{
tr_info("RPL root start");
@ -573,6 +587,9 @@ void ws_bbr_pan_version_increase(protocol_interface_info_entry_t *cur)
cur->ws_info->pan_information.pan_version++;
// Inconsistent for border router to make information distribute faster
ws_bootstrap_configuration_trickle_reset(cur);
// Indicate new pan version to PAE controller
ws_pae_controller_nw_info_set(cur, cur->ws_info->network_pan_id, cur->ws_info->pan_information.pan_version, cur->ws_info->cfg->gen.network_name);
}
void ws_bbr_seconds_timer(protocol_interface_info_entry_t *cur, uint32_t seconds)
@ -790,6 +807,11 @@ int ws_bbr_info_get(int8_t interface_id, bbr_information_t *info_ptr)
memcpy(info_ptr->IID, wisun_if_addr + 8, 8);
}
ipv6_route_t *next_hop = ipv6_route_choose_next_hop(ADDR_6TO4, backbone_interface_id, NULL);
if (next_hop) {
memcpy(info_ptr->gateway, next_hop->info.next_hop_addr, 16);
}
info_ptr->devices_in_network = ws_bbr_pan_size(cur);
info_ptr->instance_id = current_instance_id;
info_ptr->version = dodag_info.version_num;
@ -1069,3 +1091,49 @@ int ws_bbr_key_storage_settings_set(int8_t interface_id, uint8_t alloc_max_numbe
return -1;
#endif
}
int ws_bbr_radius_address_set(int8_t interface_id, const uint8_t *address)
{
#ifdef HAVE_WS_BORDER_ROUTER
return ws_pae_controller_radius_address_set(interface_id, address);
#else
(void) interface_id;
(void) address;
return -1;
#endif
}
int ws_bbr_radius_address_get(int8_t interface_id, uint8_t *address)
{
#ifdef HAVE_WS_BORDER_ROUTER
return ws_pae_controller_radius_address_get(interface_id, address);
#else
(void) interface_id;
(void) address;
return -1;
#endif
}
int ws_bbr_radius_shared_secret_set(int8_t interface_id, const uint16_t shared_secret_len, const uint8_t *shared_secret)
{
#ifdef HAVE_WS_BORDER_ROUTER
return ws_pae_controller_radius_shared_secret_set(interface_id, shared_secret_len, shared_secret);
#else
(void) interface_id;
(void) shared_secret_len;
(void) shared_secret;
return -1;
#endif
}
int ws_bbr_radius_shared_secret_get(int8_t interface_id, uint16_t *shared_secret_len, uint8_t *shared_secret)
{
#ifdef HAVE_WS_BORDER_ROUTER
return ws_pae_controller_radius_shared_secret_get(interface_id, shared_secret_len, shared_secret);
#else
(void) interface_id;
(void) shared_secret_len;
(void) shared_secret;
return -1;
#endif
}

View File

@ -35,6 +35,7 @@ void ws_bbr_dhcp_address_lifetime_set(protocol_interface_info_entry_t *cur, uint
bool ws_bbr_ready_to_start(protocol_interface_info_entry_t *cur);
bool ws_bbr_backbone_address_get(uint8_t *address);
#else
@ -44,6 +45,7 @@ bool ws_bbr_ready_to_start(protocol_interface_info_entry_t *cur);
#define ws_bbr_rpl_config( cur, imin, doubling, redundancy, dag_max_rank_increase, min_hop_rank_increase)
#define ws_bbr_dhcp_address_lifetime_set(cur, dhcp_address_lifetime)
#define ws_bbr_ready_to_start(cur) true
#define ws_bbr_backbone_address_get(address) 0
#endif //HAVE_WS_BORDER_ROUTER

View File

@ -76,7 +76,6 @@
#define TRACE_GROUP "wsbs"
static void ws_bootstrap_event_handler(arm_event_s *event);
static void ws_bootstrap_state_change(protocol_interface_info_entry_t *cur, icmp_state_t nwk_bootstrap_state);
static bool ws_bootstrap_state_discovery(struct protocol_interface_info_entry *cur);
@ -95,7 +94,7 @@ static void ws_bootstrap_nw_key_clear(protocol_interface_info_entry_t *cur, uint
static void ws_bootstrap_nw_key_index_set(protocol_interface_info_entry_t *cur, uint8_t index);
static void ws_bootstrap_nw_frame_counter_set(protocol_interface_info_entry_t *cur, uint32_t counter, uint8_t slot);
static void ws_bootstrap_nw_frame_counter_read(protocol_interface_info_entry_t *cur, uint32_t *counter, uint8_t slot);
static void ws_bootstrap_nw_info_updated(protocol_interface_info_entry_t *interface_ptr, uint16_t pan_id, char *network_name);
static void ws_bootstrap_nw_info_updated(protocol_interface_info_entry_t *interface_ptr, uint16_t pan_id, uint16_t pan_version, char *network_name);
static void ws_bootstrap_authentication_completed(protocol_interface_info_entry_t *cur, auth_result_e result, uint8_t *target_eui_64);
static const uint8_t *ws_bootstrap_authentication_next_target(protocol_interface_info_entry_t *cur, const uint8_t *previous_eui_64, uint16_t *pan_id);
static void ws_bootstrap_pan_version_increment(protocol_interface_info_entry_t *cur);
@ -157,7 +156,7 @@ static void ws_bootstap_eapol_neigh_entry_allocate(struct protocol_interface_inf
uint8_t mac_64[8];
memset(mac_64, 0, sizeof(mac_64));
mac_neighbor_table_entry_t *mac_entry = ws_bootstrap_mac_neighbor_add(interface, mac_64);
mac_neighbor_table_entry_t *mac_entry = ws_bootstrap_mac_neighbor_add(interface, mac_64);
if (!mac_entry) {
return;
@ -225,21 +224,21 @@ static void ws_bootstrap_address_notification_cb(struct protocol_interface_info_
if (addr->source == ADDR_SOURCE_UNKNOWN || !interface->ws_info) {
return;
}
if (reason == ADDR_CALLBACK_DAD_COMPLETE) {
//Trig Address Registartion only when Bootstrap is ready
//If address is generated manually we need to force registration
if (addr->source != ADDR_SOURCE_DHCP) {
//Trigger Address Registration only when Bootstrap is ready
if (interface->nwk_bootstrap_state == ER_BOOTSRAP_DONE) {
tr_debug("Address registration %s", trace_ipv6(addr->address));
ws_address_registration_update(interface, addr->address);
}
ws_address_reregister_trig(interface);
}
if (addr_ipv6_scope(addr->address, interface) > IPV6_SCOPE_LINK_LOCAL) {
// at least ula address available inside mesh.
interface->global_address_available = true;
}
} else if (reason == ADDR_CALLBACK_DELETED) {
// What to do?
// Go through address list and check if there is global address still available
@ -261,6 +260,14 @@ static void ws_bootstrap_address_notification_cb(struct protocol_interface_info_
}
}
}
// Addressing in Wi-SUN interface was changed for Border router send new event so Application can update the state
if (interface->bootsrap_mode == ARM_NWK_BOOTSRAP_MODE_6LoWPAN_BORDER_ROUTER &&
interface->nwk_bootstrap_state == ER_BOOTSRAP_DONE) {
if (interface->bootsrap_state_machine_cnt == 0) {
interface->bootsrap_state_machine_cnt = 10; //Re trigger state check
}
}
}
static int ws_bootstrap_tasklet_init(protocol_interface_info_entry_t *cur)
@ -486,7 +493,7 @@ static void ws_bootstrap_llc_hopping_update(struct protocol_interface_info_entry
cur->ws_info->hopping_schdule.fhss_bsi = fhss_configuration->bsi;
}
static uint8_t ws_generate_exluded_channel_list_from_active_channels(ws_excluded_channel_data_t *excluded_data, const uint32_t *selected_channel_mask, uint16_t number_of_channels)
static uint8_t ws_generate_exluded_channel_list_from_active_channels(ws_excluded_channel_data_t *excluded_data, const uint32_t *selected_channel_mask, const uint32_t *global_channel_mask, uint16_t number_of_channels)
{
bool active_range = false;
@ -494,6 +501,15 @@ static uint8_t ws_generate_exluded_channel_list_from_active_channels(ws_excluded
memset(excluded_data, 0, sizeof(ws_excluded_channel_data_t));
for (uint8_t i = 0; i < number_of_channels; i++) {
if (!(global_channel_mask[0 + (i / 32)] & (1 << (i % 32)))) {
//Global exluded channel
if (active_range) {
//Mark range stop here
active_range = false;
}
continue;
}
if (selected_channel_mask[0 + (i / 32)] & (1 << (i % 32))) {
if (active_range) {
//Mark range stop here
@ -549,7 +565,7 @@ static void ws_fhss_configure_channel_masks(protocol_interface_info_entry_t *cur
fhss_configuration->unicast_channel_mask[n] &= cur->ws_info->cfg->fhss.fhss_channel_mask[n];
}
//Update Exluded channels
cur->ws_info->hopping_schdule.channel_plan = ws_generate_exluded_channel_list_from_active_channels(&cur->ws_info->hopping_schdule.excluded_channels, fhss_configuration->unicast_channel_mask, cur->ws_info->hopping_schdule.number_of_channels);
cur->ws_info->hopping_schdule.channel_plan = ws_generate_exluded_channel_list_from_active_channels(&cur->ws_info->hopping_schdule.excluded_channels, fhss_configuration->unicast_channel_mask, fhss_configuration->channel_mask, cur->ws_info->hopping_schdule.number_of_channels);
}
static int8_t ws_fhss_initialize(protocol_interface_info_entry_t *cur)
@ -1424,7 +1440,7 @@ static void ws_bootstrap_pan_config_analyse(struct protocol_interface_info_entry
etx_lqi_dbm_update(cur->id, data->mpduLinkQuality, data->signal_dbm, neighbor_info.neighbor->index, neighbor_info.neighbor->mac64);
//Update Neighbor Broadcast and Unicast Parameters
ws_neighbor_class_neighbor_unicast_time_info_update(neighbor_info.ws_neighbor, ws_utt, data->timestamp);
ws_neighbor_class_neighbor_unicast_schedule_set(neighbor_info.ws_neighbor, ws_us);
ws_neighbor_class_neighbor_unicast_schedule_set(neighbor_info.ws_neighbor, ws_us, &cur->ws_info->hopping_schdule);
ws_neighbor_class_neighbor_broadcast_time_info_update(neighbor_info.ws_neighbor, &ws_bt_ie, data->timestamp);
ws_neighbor_class_neighbor_broadcast_schedule_set(neighbor_info.ws_neighbor, &ws_bs_ie);
}
@ -1508,7 +1524,7 @@ static void ws_bootstrap_pan_config_solicit_analyse(struct protocol_interface_in
if (ws_bootstrap_neighbor_info_request(cur, data->SrcAddr, &neighbor_info, false)) {
etx_lqi_dbm_update(cur->id, data->mpduLinkQuality, data->signal_dbm, neighbor_info.neighbor->index, neighbor_info.neighbor->mac64);
ws_neighbor_class_neighbor_unicast_time_info_update(neighbor_info.ws_neighbor, ws_utt, data->timestamp);
ws_neighbor_class_neighbor_unicast_schedule_set(neighbor_info.ws_neighbor, ws_us);
ws_neighbor_class_neighbor_unicast_schedule_set(neighbor_info.ws_neighbor, ws_us, &cur->ws_info->hopping_schdule);
}
@ -1564,6 +1580,26 @@ bool ws_bootstrap_validate_channel_plan(ws_us_ie_t *ws_us, struct protocol_inter
return true;
}
bool ws_bootstrap_validate_channel_function(ws_us_ie_t *ws_us, ws_bs_ie_t *ws_bs)
{
if (ws_us) {
if (ws_us->channel_function != WS_FIXED_CHANNEL &&
ws_us->channel_function != WS_TR51CF &&
ws_us->channel_function != WS_DH1CF) {
return false;
}
}
if (ws_bs) {
if (ws_bs->channel_function != WS_FIXED_CHANNEL &&
ws_bs->channel_function != WS_TR51CF &&
ws_bs->channel_function != WS_DH1CF) {
return false;
}
}
return true;
}
static void ws_bootstrap_asynch_ind(struct protocol_interface_info_entry *cur, const struct mcps_data_ind_s *data, const struct mcps_data_ie_list *ie_ext, uint8_t message_type)
{
@ -1602,7 +1638,8 @@ static void ws_bootstrap_asynch_ind(struct protocol_interface_info_entry *cur, c
return;
}
if (!ws_bootstrap_validate_channel_plan(&ws_us, cur)) {
if (!ws_bootstrap_validate_channel_plan(&ws_us, cur) ||
!ws_bootstrap_validate_channel_function(&ws_us, NULL)) {
return;
}
@ -2098,11 +2135,7 @@ int ws_bootstrap_set_rf_config(protocol_interface_info_entry_t *cur, phy_rf_chan
set_request.value_size = sizeof(mlme_multi_csma_ca_param_t);
cur->mac_api->mlme_req(cur->mac_api, MLME_SET, &set_request);
// Start automatic CCA threshold
uint8_t start_cca_thr[4] = {cur->ws_info->hopping_schdule.number_of_channels, CCA_DEFAULT_DBM, CCA_HIGH_LIMIT, CCA_LOW_LIMIT};
set_request.attr = macCCAThresholdStart;
set_request.value_pointer = &start_cca_thr;
set_request.value_size = sizeof(start_cca_thr);
cur->mac_api->mlme_req(cur->mac_api, MLME_SET, &set_request);
mac_helper_start_auto_cca_threshold(cur->id, cur->ws_info->hopping_schdule.number_of_channels, CCA_DEFAULT_DBM, CCA_HIGH_LIMIT, CCA_LOW_LIMIT);
return 0;
}
@ -2275,7 +2308,7 @@ static void ws_bootstrap_rpl_callback(rpl_event_t event, void *handle)
// Set both own port and border router port to 10253
ws_eapol_relay_start(cur, EAPOL_RELAY_SOCKET_PORT, dodag_info.dodag_id, EAPOL_RELAY_SOCKET_PORT);
// Set network information to PAE
ws_pae_controller_nw_info_set(cur, cur->ws_info->network_pan_id, cur->ws_info->cfg->gen.network_name);
ws_pae_controller_nw_info_set(cur, cur->ws_info->network_pan_id, cur->ws_info->pan_information.pan_version, cur->ws_info->cfg->gen.network_name);
// Network key is valid, indicate border router IID to controller
ws_pae_controller_nw_key_valid(cur, &dodag_info.dodag_id[8]);
@ -2635,7 +2668,7 @@ static void ws_bootstrap_start_discovery(protocol_interface_info_entry_t *cur)
static void ws_bootstrap_start_authentication(protocol_interface_info_entry_t *cur)
{
// Set PAN ID and network name to controller
ws_pae_controller_nw_info_set(cur, cur->ws_info->network_pan_id, cur->ws_info->cfg->gen.network_name);
ws_pae_controller_nw_info_set(cur, cur->ws_info->network_pan_id, cur->ws_info->pan_information.pan_version, cur->ws_info->cfg->gen.network_name);
ws_pae_controller_authenticate(cur);
}
@ -2683,22 +2716,26 @@ static void ws_bootstrap_nw_frame_counter_read(protocol_interface_info_entry_t *
mac_helper_key_link_frame_counter_read(cur->id, counter, slot);
}
static void ws_bootstrap_nw_info_updated(protocol_interface_info_entry_t *cur, uint16_t pan_id, char *network_name)
static void ws_bootstrap_nw_info_updated(protocol_interface_info_entry_t *cur, uint16_t pan_id, uint16_t pan_version, char *network_name)
{
/* For border router, the PAE controller reads pan_id and network name from storage.
/* For border router, the PAE controller reads PAN ID, PAN version and network name from storage.
* If they are set, takes them into use here.
*/
if (cur->bootsrap_mode == ARM_NWK_BOOTSRAP_MODE_6LoWPAN_BORDER_ROUTER) {
// Get pad_id and network name
// Get PAN ID and network name
ws_gen_cfg_t gen_cfg;
if (ws_cfg_gen_get(&gen_cfg, NULL) < 0) {
return;
}
// If pan_id has not been set, set it
// If PAN ID has not been set, set it
if (gen_cfg.network_pan_id == 0xffff) {
gen_cfg.network_pan_id = pan_id;
// Sets PAN version
cur->ws_info->pan_information.pan_version = pan_version;
cur->ws_info->pan_information.pan_version_set = true;
}
// If network name has not been set, set it
if (strlen(gen_cfg.network_name) == 0) {
strncpy(gen_cfg.network_name, network_name, 32);
@ -2989,6 +3026,18 @@ static void ws_bootstrap_pan_config(protocol_interface_info_entry_t *cur)
ws_llc_asynch_request(cur, &async_req);
}
static int8_t ws_bootstrap_backbone_ip_addr_get(protocol_interface_info_entry_t *interface_ptr, uint8_t *address)
{
(void) interface_ptr;
(void) address;
if (ws_bbr_backbone_address_get(address)) {
return 0;
}
return -1;
}
static void ws_bootstrap_event_handler(arm_event_s *event)
{
ws_bootsrap_event_type_e event_type;
@ -3045,8 +3094,11 @@ static void ws_bootstrap_event_handler(arm_event_s *event)
} else {
cur->ws_info->network_pan_id = cur->ws_info->cfg->gen.network_pan_id;
}
if (!cur->ws_info->pan_information.pan_version_set) {
cur->ws_info->pan_information.pan_version = randLIB_get_random_in_range(0, 0xffff);
cur->ws_info->pan_information.pan_version_set = true;
}
cur->ws_info->pan_information.pan_size = 0;
cur->ws_info->pan_information.pan_version = randLIB_get_random_in_range(0, 0xffff);
cur->ws_info->pan_information.routing_cost = 0;
cur->ws_info->pan_information.rpl_routing_method = true;
cur->ws_info->pan_information.use_parent_bs = true;
@ -3075,7 +3127,10 @@ static void ws_bootstrap_event_handler(arm_event_s *event)
ws_eapol_auth_relay_start(cur, EAPOL_RELAY_SOCKET_PORT, ll_addr, PAE_AUTH_SOCKET_PORT);
// Set PAN ID and network name to controller
ws_pae_controller_nw_info_set(cur, cur->ws_info->network_pan_id, cur->ws_info->cfg->gen.network_name);
ws_pae_controller_nw_info_set(cur, cur->ws_info->network_pan_id, cur->ws_info->pan_information.pan_version, cur->ws_info->cfg->gen.network_name);
// Set backbone IP address get callback
ws_pae_controller_auth_cb_register(cur, ws_bootstrap_backbone_ip_addr_get);
// Set PAE port to 10254 and authenticator relay to 10253 (and to own ll address)
ws_pae_controller_authenticator_start(cur, PAE_AUTH_SOCKET_PORT, ll_addr, EAPOL_RELAY_SOCKET_PORT);
@ -3173,7 +3228,7 @@ static int8_t ws_bootstrap_neighbor_set(protocol_interface_info_entry_t *cur, pa
}
ws_neighbor_class_neighbor_unicast_time_info_update(neighbor_info.ws_neighbor, &parent_ptr->ws_utt, parent_ptr->timestamp);
ws_neighbor_class_neighbor_unicast_schedule_set(neighbor_info.ws_neighbor, &parent_ptr->ws_us);
ws_neighbor_class_neighbor_unicast_schedule_set(neighbor_info.ws_neighbor, &parent_ptr->ws_us, &cur->ws_info->hopping_schdule);
return 0;
}
@ -3222,11 +3277,7 @@ void ws_bootstrap_configure_process(protocol_interface_info_entry_t *cur)
if (cur->ws_info->configuration_learned) {
ws_bootstrap_network_configuration_learn(cur);
ws_bootstrap_event_operation_start(cur);
return;
}
return;
@ -3249,7 +3300,22 @@ void ws_bootstrap_rpl_wait_process(protocol_interface_info_entry_t *cur)
return;
}
/*
static bool ws_bootstrap_state_discovery(struct protocol_interface_info_entry *cur)
{
if (cur->nwk_bootstrap_state == ER_ACTIVE_SCAN) {
return true;
}
return false;
}
static bool ws_bootstrap_state_authenticate(struct protocol_interface_info_entry *cur)
{
// Think about the state value
if (cur->nwk_bootstrap_state == ER_PANA_AUTH) {
return true;
}
return false;
}
static bool ws_bootstrap_state_configure(struct protocol_interface_info_entry *cur)
{
@ -3260,10 +3326,10 @@ static bool ws_bootstrap_state_configure(struct protocol_interface_info_entry *c
return false;
}
*/
static bool ws_bootstrap_state_discovery(struct protocol_interface_info_entry *cur)
static bool ws_bootstrap_state_wait_rpl(struct protocol_interface_info_entry *cur)
{
if (cur->nwk_bootstrap_state == ER_ACTIVE_SCAN) {
// Think about the state value
if (cur->nwk_bootstrap_state == ER_RPL_SCAN) {
return true;
}
return false;
@ -3276,14 +3342,6 @@ static bool ws_bootstrap_state_active(struct protocol_interface_info_entry *cur)
}
return false;
}
static bool ws_bootstrap_state_wait_rpl(struct protocol_interface_info_entry *cur)
{
// Think about the state value
if (cur->nwk_bootstrap_state == ER_RPL_SCAN) {
return true;
}
return false;
}
static void ws_bootstrap_state_change(protocol_interface_info_entry_t *cur, icmp_state_t nwk_bootstrap_state)
{
@ -3431,7 +3489,7 @@ void ws_bootstrap_seconds_timer(protocol_interface_info_entry_t *cur, uint32_t s
}
void ws_primary_parent_update(protocol_interface_info_entry_t *interface, mac_neighbor_table_entry_t *neighbor)
void ws_bootstrap_primary_parent_update(protocol_interface_info_entry_t *interface, mac_neighbor_table_entry_t *neighbor)
{
if (interface->ws_info) {
llc_neighbour_req_t neighbor_info;
@ -3442,11 +3500,11 @@ void ws_primary_parent_update(protocol_interface_info_entry_t *interface, mac_ne
ws_bootsrap_create_ll_address(link_local_address, neighbor->mac64);
dhcp_client_server_address_update(interface->id, NULL, link_local_address);
ws_secondary_parent_update(interface);
ws_bootstrap_secondary_parent_update(interface);
}
}
void ws_secondary_parent_update(protocol_interface_info_entry_t *interface)
void ws_bootstrap_secondary_parent_update(protocol_interface_info_entry_t *interface)
{
if (interface->ws_info) {
ns_list_foreach(if_address_entry_t, address, &interface->ip_addresses) {
@ -3457,4 +3515,40 @@ void ws_secondary_parent_update(protocol_interface_info_entry_t *interface)
}
}
int ws_bootstrap_get_info(protocol_interface_info_entry_t *cur, struct ws_stack_info *info_ptr)
{
ws_neighbor_class_entry_t *ws_neighbour = NULL;
memset(info_ptr, 0, sizeof(struct ws_stack_info));
mac_neighbor_table_entry_t *mac_parent = mac_neighbor_entry_get_priority(mac_neighbor_info(cur));
if (mac_parent) {
ws_neighbour = ws_neighbor_class_entry_get(&cur->ws_info->neighbor_storage, mac_parent->index);
memcpy(info_ptr->parent, ADDR_LINK_LOCAL_PREFIX, 8);
memcpy(info_ptr->parent + 8, mac_parent->mac64, 8);
info_ptr->parent[8] ^= 2;
}
if (ws_neighbour) {
info_ptr->rsl_in = ws_neighbour->rsl_in;
info_ptr->rsl_out = ws_neighbour->rsl_out;
info_ptr->routing_cost = ws_neighbour->routing_cost;
}
if (ws_bootstrap_state_discovery(cur)) {
info_ptr->join_state = 1;
} else if (ws_bootstrap_state_authenticate(cur)) {
info_ptr->join_state = 2;
} else if (ws_bootstrap_state_configure(cur)) {
info_ptr->join_state = 3;
} else if (ws_bootstrap_state_wait_rpl(cur)) {
info_ptr->join_state = 4;
} else if (ws_bootstrap_state_active(cur)) {
info_ptr->join_state = 5;
}
info_ptr->pan_id = cur->ws_info->network_pan_id;
return 0;
}
#endif //HAVE_WS

View File

@ -31,7 +31,9 @@ typedef enum {
struct llc_neighbour_req;
struct ws_us_ie;
struct ws_bs_ie;
struct ws_neighbor_class_entry;
struct ws_stack_info;
int ws_bootstrap_init(int8_t interface_id, net_6lowpan_mode_e bootstrap_mode);
@ -64,9 +66,9 @@ void ws_bootstrap_seconds_timer(protocol_interface_info_entry_t *cur, uint32_t s
void ws_bootstrap_trickle_timer(protocol_interface_info_entry_t *cur, uint16_t ticks);
void ws_primary_parent_update(protocol_interface_info_entry_t *interface, mac_neighbor_table_entry_t *neighbor);
void ws_bootstrap_primary_parent_update(protocol_interface_info_entry_t *interface, mac_neighbor_table_entry_t *neighbor);
void ws_secondary_parent_update(protocol_interface_info_entry_t *interface);
void ws_bootstrap_secondary_parent_update(protocol_interface_info_entry_t *interface);
void ws_nud_entry_remove_active(protocol_interface_info_entry_t *cur, void *neighbor);
@ -82,12 +84,16 @@ void ws_bootstrap_eapol_parent_synch(struct protocol_interface_info_entry *cur,
bool ws_bootstrap_validate_channel_plan(struct ws_us_ie *ws_us, struct protocol_interface_info_entry *cur);
bool ws_bootstrap_validate_channel_function(struct ws_us_ie *ws_us, struct ws_bs_ie *ws_bs);
void ws_bootstrap_eapol_rx_temporary_set(struct protocol_interface_info_entry *interface, const uint8_t *src64);
struct ws_neighbor_class_entry *ws_bootstrap_eapol_tx_temporary_set(struct protocol_interface_info_entry *interface, const uint8_t *src64);
void ws_bootstrap_eapol_tx_temporary_clear(struct protocol_interface_info_entry *interface);
int ws_bootstrap_get_info(protocol_interface_info_entry_t *cur, struct ws_stack_info *info_ptr);
#else
#define ws_bootstrap_init(interface_id, bootstrap_mode) (-1)
@ -95,8 +101,9 @@ void ws_bootstrap_eapol_tx_temporary_clear(struct protocol_interface_info_entry
#define ws_bootstrap_restart(cur)
#define ws_bootstrap_neighbor_remove(cur, ll_address)
#define ws_bootstrap_aro_failure(cur, ll_address)
#define ws_primary_parent_update(interface, neighbor)
#define ws_secondary_parent_update(interface)
#define ws_bootstrap_primary_parent_update(interface, neighbor)
#define ws_bootstrap_secondary_parent_update(interface)
#define ws_bootstrap_get_info(cur, info_ptr)
#endif //HAVE_WS

View File

@ -23,8 +23,12 @@
#include <ns_list.h>
#include <nsdynmemLIB.h>
#include "Common_Protocols/icmpv6.h"
#include "mac_common_defines.h"
#include "net_interface.h"
#include "6LoWPAN/MAC/mpx_api.h"
#include "6LoWPAN/ws/ws_config.h"
#include "6LoWPAN/ws/ws_common_defines.h"
#include "6LoWPAN/ws/ws_llc.h"
#include "6LoWPAN/ws/ws_common.h"
#include "6LoWPAN/ws/ws_bootstrap.h"
#include "6LoWPAN/ws/ws_bbr_api_internal.h"
@ -81,6 +85,18 @@ int8_t ws_generate_channel_list(uint32_t *channel_mask, uint16_t number_of_chann
return 0;
}
uint16_t ws_active_channel_count(uint32_t *channel_mask, uint16_t number_of_channels)
{
uint16_t active_channels = 0;
// Set channel maks outside excluded channels
for (uint16_t i = 0; i < number_of_channels; i++) {
if (channel_mask[0 + (i / 32)] & (1 << (i % 32))) {
active_channels++;
}
}
return active_channels;
}
uint32_t ws_decode_channel_spacing(uint8_t channel_spacing)
{
if (CHANNEL_SPACING_100 == channel_spacing) {
@ -307,6 +323,7 @@ int8_t ws_common_allocate_and_init(protocol_interface_info_entry_t *cur)
cur->ws_info->network_pan_id = 0xffff;
cur->ws_info->pan_information.use_parent_bs = true;
cur->ws_info->pan_information.rpl_routing_method = true;
cur->ws_info->pan_information.pan_version_set = false;
cur->ws_info->pan_information.version = WS_FAN_VERSION_1_0;
cur->ws_info->pending_key_index_info.state = NO_PENDING_PROCESS;
@ -336,6 +353,7 @@ void ws_common_fast_timer(protocol_interface_info_entry_t *cur, uint16_t ticks)
{
ws_bootstrap_trickle_timer(cur, ticks);
ws_nud_active_timer(cur, ticks);
ws_llc_fast_timer(cur, ticks);
}
@ -461,4 +479,14 @@ uint32_t ws_common_network_size_estimate_get(protocol_interface_info_entry_t *cu
return network_size_estimate;
}
void ws_common_primary_parent_update(protocol_interface_info_entry_t *interface, mac_neighbor_table_entry_t *neighbor)
{
ws_bootstrap_primary_parent_update(interface, neighbor);
}
void ws_common_secondary_parent_update(protocol_interface_info_entry_t *interface)
{
ws_bootstrap_secondary_parent_update(interface);
}
#endif // HAVE_WS

View File

@ -115,6 +115,8 @@ typedef struct ws_info_s {
int8_t ws_generate_channel_list(uint32_t *channel_mask, uint16_t number_of_channels, uint8_t regulatory_domain, uint8_t operating_class);
uint16_t ws_active_channel_count(uint32_t *channel_mask, uint16_t number_of_channels);
uint32_t ws_decode_channel_spacing(uint8_t channel_spacing);
uint32_t ws_get_datarate_using_operating_mode(uint8_t operating_mode);
@ -149,6 +151,10 @@ uint32_t ws_common_datarate_get(protocol_interface_info_entry_t *cur);
uint32_t ws_common_network_size_estimate_get(protocol_interface_info_entry_t *cur);
void ws_common_primary_parent_update(protocol_interface_info_entry_t *interface, mac_neighbor_table_entry_t *neighbor);
void ws_common_secondary_parent_update(protocol_interface_info_entry_t *interface);
#define ws_info(cur) ((cur)->ws_info)
#else
#define ws_info(cur) ((ws_info_t *) NULL)
@ -162,6 +168,9 @@ uint32_t ws_common_network_size_estimate_get(protocol_interface_info_entry_t *cu
#define ws_common_latency_estimate_get(cur) 0
#define ws_common_datarate_get(cur) 0
#define ws_common_network_size_estimate_get(cur) 0
#define ws_common_primary_parent_update(interface, neighbor)
#define ws_common_secondary_parent_update(interface)
#endif //HAVE_WS
#endif //WS_COMMON_H_

View File

@ -67,6 +67,7 @@ typedef struct ws_pan_information_s {
uint16_t pan_version; /**< Pan configuration version will be updatd by Border router at PAN. */
bool use_parent_bs: 1; /**< 1 for force to follow parent broadcast schedule. 0 node may define own schedule. */
bool rpl_routing_method: 1; /**< 1 when RPL routing is selected and 0 when L2 routing. */
bool pan_version_set: 1; /**< 1 PAN version is set. */
unsigned version: 3; /**< Pan version support. */
} ws_pan_information_t;
@ -130,6 +131,13 @@ typedef struct ws_bt_ie {
uint_fast24_t broadcast_interval_offset;
} ws_bt_ie_t;
/**
* @brief ws_fc_ie_t WS FC-IE element
*/
typedef struct ws_fc_ie {
uint8_t tx_flow_ctrl;
uint8_t rx_flow_ctrl;
} ws_fc_ie_t;
/**
* @brief ws_channel_plan_zero_t WS channel plan 0 define domain and class

View File

@ -69,6 +69,10 @@
#define PAN_VERSION_CHANGE_INTERVAL 3
/* If PAN version lifetime would be 10 minutes, 1000 increments is about 7 days i.e. storage must
be written at least once a week */
#define PAN_VERSION_STORAGE_READ_INCREMENT 1000
// RPL version number update intervall
// after restart version numbers are increased faster and then slowed down when network is stable
#define RPL_VERSION_LIFETIME 12*3600

View File

@ -380,6 +380,14 @@ int ws_test_next_gtk_set(int8_t interface_id, uint8_t *gtk[4])
return -1;
}
int ws_test_6lowpan_fragmentation_mtu_size_set(int8_t interface_id, uint16_t mtu_size)
{
(void) interface_id;
(void) mtu_size;
return -1;
}
int ws_statistics_start(int8_t interface_id, ws_statistics_t *stats_ptr)
{
(void) interface_id;
@ -398,4 +406,11 @@ void ns_time_api_system_time_callback_set(ns_time_api_system_time_callback callb
(void) callback;
}
int ws_stack_info_get(int8_t interface_id, ws_stack_info_t *info_ptr)
{
(void) interface_id;
(void) info_ptr;
return -1;
}
#endif // no HAVE_WS

View File

@ -110,10 +110,11 @@ uint8_t *ws_wh_bt_write(uint8_t *ptr)
}
uint8_t *ws_wh_fc_write(uint8_t *ptr, uint8_t flow_ctrl)
uint8_t *ws_wh_fc_write(uint8_t *ptr, ws_fc_ie_t *fc_ie)
{
ptr = ws_wh_header_base_write(ptr, 1, WH_IE_FC_TYPE);
*ptr++ = flow_ctrl;
ptr = ws_wh_header_base_write(ptr, 2, WH_IE_FC_TYPE);
*ptr++ = fc_ie->tx_flow_ctrl;
*ptr++ = fc_ie->rx_flow_ctrl;
return ptr;
}
@ -341,6 +342,19 @@ bool ws_wh_bt_read(uint8_t *data, uint16_t length, struct ws_bt_ie *bt_ie)
return true;
}
bool ws_wh_fc_read(uint8_t *data, uint16_t length, struct ws_fc_ie *fc_ie)
{
mac_header_IE_t fc_ie_data;
fc_ie_data.id = MAC_HEADER_ASSIGNED_EXTERNAL_ORG_IE_ID;
if (2 != mac_ie_header_sub_id_discover(data, length, &fc_ie_data, WH_IE_FC_TYPE)) {
return false;
}
data = fc_ie_data.content_ptr;
fc_ie->tx_flow_ctrl = *data++;
fc_ie->rx_flow_ctrl = *data;
return true;
}
bool ws_wh_rsl_read(uint8_t *data, uint16_t length, int8_t *rsl)
{
mac_header_IE_t rsl_ie_data;

View File

@ -23,6 +23,7 @@ struct ws_utt_ie;
struct ws_bt_ie;
struct ws_us_ie;
struct ws_hopping_schedule_s;
struct ws_fc_ie;
/**
* @brief ws_wp_network_name_t WS nested payload network name
@ -35,13 +36,14 @@ typedef struct ws_wp_network_name {
/* WS_WH HEADER IE */
uint8_t *ws_wh_utt_write(uint8_t *ptr, uint8_t message_type);
uint8_t *ws_wh_bt_write(uint8_t *ptr);
uint8_t *ws_wh_fc_write(uint8_t *ptr, uint8_t flow_ctrl);
uint8_t *ws_wh_fc_write(uint8_t *ptr, struct ws_fc_ie *fc_ie);
uint8_t *ws_wh_rsl_write(uint8_t *ptr, uint8_t rsl);
uint8_t *ws_wh_vh_write(uint8_t *ptr, uint8_t *vendor_header, uint8_t vendor_header_length);
uint8_t *ws_wh_ea_write(uint8_t *ptr, uint8_t *eui64);
bool ws_wh_utt_read(uint8_t *data, uint16_t length, struct ws_utt_ie *utt_ie);
bool ws_wh_bt_read(uint8_t *data, uint16_t length, struct ws_bt_ie *bt_ie);
bool ws_wh_fc_read(uint8_t *data, uint16_t length, struct ws_fc_ie *fc_ie);
bool ws_wh_rsl_read(uint8_t *data, uint16_t length, int8_t *rsl);
bool ws_wh_ea_read(uint8_t *data, uint16_t length, uint8_t *eui64);

View File

@ -226,6 +226,8 @@ void ws_llc_hopping_schedule_config(struct protocol_interface_info_entry *interf
void ws_llc_timer_seconds(struct protocol_interface_info_entry *interface, uint16_t seconds_update);
void ws_llc_fast_timer(struct protocol_interface_info_entry *interface, uint16_t ticks);
bool ws_llc_eapol_relay_forward_filter(struct protocol_interface_info_entry *interface, const uint8_t *joiner_eui64, uint8_t mac_sequency, uint32_t rx_timestamp);
ws_neighbor_temp_class_t *ws_llc_get_multicast_temp_entry(struct protocol_interface_info_entry *interface, const uint8_t *mac64);

View File

@ -112,10 +112,16 @@ typedef struct {
bool active_eapol_session: 1; /**< Indicating active EAPOL message */
} temp_entriest_t;
/** EDFE response and Enhanced ACK data length */
#define ENHANCED_FRAME_RESPONSE (WH_IE_ELEMENT_HEADER_LENGTH + 2 + WH_IE_ELEMENT_HEADER_LENGTH + 4 + WH_IE_ELEMENT_HEADER_LENGTH + 1 + WH_IE_ELEMENT_HEADER_LENGTH + 5)
typedef struct {
uint8_t mac_handle_base; /**< Mac handle id base this will be updated by 1 after use */
uint8_t llc_message_list_size; /**< llc_message_list list size */
uint16_t edfe_rx_wait_timer;
mpx_class_t mpx_data_base; /**< MPX data be including USER API Class and user call backs */
llc_message_list_t llc_message_list; /**< Active Message list */
llc_ie_params_t ie_params; /**< LLC IE header and Payload data configuration */
temp_entriest_t *temp_entries;
@ -123,7 +129,7 @@ typedef struct {
ws_asynch_ind *asynch_ind; /**< LLC Asynch data indication call back configured by user */
ws_asynch_confirm *asynch_confirm; /**< LLC Asynch data confirmation call back configured by user */
ws_neighbor_info_request *ws_neighbor_info_request_cb; /**< LLC Neighbour discover API*/
uint8_t ws_enhanced_ack_elements[WH_IE_ELEMENT_HEADER_LENGTH + 4 + WH_IE_ELEMENT_HEADER_LENGTH + 1];
uint8_t ws_enhanced_response_elements[ENHANCED_FRAME_RESPONSE];
ns_ie_iovec_t ws_header_vector;
protocol_interface_info_entry_t *interface_ptr; /**< List link entry */
@ -167,6 +173,30 @@ static ws_neighbor_temp_class_t *ws_allocate_eapol_temp_entry(temp_entriest_t *b
static void ws_llc_mpx_eapol_send(llc_data_base_t *base, llc_message_t *message);
static bool test_skip_first_init_response = false;
static uint8_t test_drop_data_message = 0;
int8_t ws_test_skip_edfe_data_send(int8_t interface_id, bool skip)
{
protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(interface_id);
if (!cur || !ws_info(cur)) {
return -1;
}
test_skip_first_init_response = skip;
return 0;
}
int8_t ws_test_drop_edfe_data_frames(int8_t interface_id, uint8_t number_of_dropped_frames)
{
protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(interface_id);
if (!cur || !ws_info(cur)) {
return -1;
}
test_drop_data_message = number_of_dropped_frames;
return 0;
}
/** Discover Message by message handle id */
static llc_message_t *llc_message_discover_by_mac_handle(uint8_t handle, llc_message_list_t *list)
{
@ -304,7 +334,7 @@ static uint16_t ws_wh_headers_length(wh_ie_sub_list_t requested_list, llc_ie_par
if (requested_list.fc_ie) {
//Static 1 bytes allways
length += WH_IE_ELEMENT_HEADER_LENGTH + 1;
length += WH_IE_ELEMENT_HEADER_LENGTH + 2;
}
if (requested_list.rsl_ie) {
@ -414,7 +444,6 @@ static void ws_llc_mac_confirm_cb(const mac_api_t *api, const mcps_data_conf_t *
}
protocol_interface_info_entry_t *interface = base->interface_ptr;
llc_message_t *message = llc_message_discover_by_mac_handle(data->msduHandle, &base->llc_message_list);
if (!message) {
return;
@ -520,14 +549,15 @@ static void ws_llc_ack_data_req_ext(const mac_api_t *api, mcps_ack_data_payload_
memset(data, 0, sizeof(mcps_ack_data_payload_t));
//Add just 2 header elements to inside 1 block
data->ie_elements.headerIeVectorList = &base->ws_header_vector;
base->ws_header_vector.ieBase = base->ws_enhanced_ack_elements;
base->ws_header_vector.iovLen = sizeof(base->ws_enhanced_ack_elements);
base->ws_header_vector.ieBase = base->ws_enhanced_response_elements;
data->ie_elements.headerIovLength = 1;
//Write Data to block
uint8_t *ptr = base->ws_enhanced_ack_elements;
uint8_t *ptr = base->ws_enhanced_response_elements;
ptr = ws_wh_utt_write(ptr, WS_FT_ACK);
ws_wh_rsl_write(ptr, ws_neighbor_class_rsl_from_dbm_calculate(rssi));
ptr = ws_wh_rsl_write(ptr, ws_neighbor_class_rsl_from_dbm_calculate(rssi));
base->ws_header_vector.iovLen = ptr - base->ws_enhanced_response_elements;
}
@ -613,8 +643,14 @@ static void ws_llc_data_indication_cb(const mac_api_t *api, const mcps_data_ind_
protocol_interface_info_entry_t *interface = base->interface_ptr;
//Validate Unicast shedule Channel Plan
if (us_ie_inline && !ws_bootstrap_validate_channel_plan(&us_ie, interface)) {
//Channel plan configuration mismatch
if (us_ie_inline &&
(!ws_bootstrap_validate_channel_plan(&us_ie, interface) ||
!ws_bootstrap_validate_channel_function(&us_ie, NULL))) {
//Channel plan or channel function configuration mismatch
return;
}
if (bs_ie_inline && !ws_bootstrap_validate_channel_function(NULL, &ws_bs_ie)) {
return;
}
@ -648,14 +684,14 @@ static void ws_llc_data_indication_cb(const mac_api_t *api, const mcps_data_ind_
}
}
if (!multicast && !ws_neighbor_class_neighbor_duplicate_packet_check(neighbor_info.ws_neighbor, data->DSN, data->timestamp)) {
if (!multicast && !data->DSN_suppressed && !ws_neighbor_class_neighbor_duplicate_packet_check(neighbor_info.ws_neighbor, data->DSN, data->timestamp)) {
tr_info("Drop duplicate message");
return;
}
ws_neighbor_class_neighbor_unicast_time_info_update(neighbor_info.ws_neighbor, &ws_utt, data->timestamp);
if (us_ie_inline) {
ws_neighbor_class_neighbor_unicast_schedule_set(neighbor_info.ws_neighbor, &us_ie);
ws_neighbor_class_neighbor_unicast_schedule_set(neighbor_info.ws_neighbor, &us_ie, &interface->ws_info->hopping_schdule);
}
//Update BS if it is part of message
if (bs_ie_inline) {
@ -730,8 +766,14 @@ static void ws_llc_eapol_indication_cb(const mac_api_t *api, const mcps_data_ind
protocol_interface_info_entry_t *interface = base->interface_ptr;
//Validate Unicast shedule Channel Plan
if (us_ie_inline && !ws_bootstrap_validate_channel_plan(&us_ie, interface)) {
//Channel plan configuration mismatch
if (us_ie_inline &&
(!ws_bootstrap_validate_channel_plan(&us_ie, interface) ||
!ws_bootstrap_validate_channel_function(&us_ie, NULL))) {
//Channel plan or channel function configuration mismatch
return;
}
if (bs_ie_inline && !ws_bootstrap_validate_channel_function(NULL, &ws_bs_ie)) {
return;
}
@ -755,7 +797,7 @@ static void ws_llc_eapol_indication_cb(const mac_api_t *api, const mcps_data_ind
uint8_t auth_eui64[8];
ws_neighbor_class_neighbor_unicast_time_info_update(neighbor_info.ws_neighbor, &ws_utt, data->timestamp);
if (us_ie_inline) {
ws_neighbor_class_neighbor_unicast_schedule_set(neighbor_info.ws_neighbor, &us_ie);
ws_neighbor_class_neighbor_unicast_schedule_set(neighbor_info.ws_neighbor, &us_ie, &interface->ws_info->hopping_schdule);
}
//Update BS if it is part of message
if (bs_ie_inline) {
@ -933,6 +975,9 @@ static void ws_llc_lowpan_mpx_data_request(llc_data_base_t *base, mpx_user_t *us
nested_wp_id.vp_ie = true;
}
if (data->ExtendedFrameExchange && data->TxAckReq) {
ie_header_mask.fc_ie = true;
}
if (!data->TxAckReq) {
nested_wp_id.bs_ie = true;
}
@ -977,17 +1022,31 @@ static void ws_llc_lowpan_mpx_data_request(llc_data_base_t *base, mpx_user_t *us
data_req.msduLength = 0;
data_req.msduHandle = message->msg_handle;
if (!data->TxAckReq) {
data_req.PanIdSuppressed = false;
data_req.DstAddrMode = MAC_ADDR_MODE_NONE;
} else {
if (data->ExtendedFrameExchange && data->TxAckReq) {
data_req.SeqNumSuppressed = true;
data_req.PanIdSuppressed = true;
data_req.TxAckReq = true; // This will be changed inside MAC
} else {
data_req.ExtendedFrameExchange = false; //Do not accept EDFE for non unicast traffic
if (!data->TxAckReq) {
data_req.PanIdSuppressed = false;
data_req.DstAddrMode = MAC_ADDR_MODE_NONE;
} else {
data_req.PanIdSuppressed = true;
}
}
uint8_t *ptr = ws_message_buffer_ptr_get(message);
message->messsage_type = WS_FT_DATA;
message->ie_vector_list[0].ieBase = ptr;
if (ie_header_mask.fc_ie) {
ws_fc_ie_t fc_ie;
fc_ie.tx_flow_ctrl = 50;//No data at initial frame
fc_ie.rx_flow_ctrl = 255;
//Write Flow control for 1 packet send this will be modified at real data send
ptr = ws_wh_fc_write(ptr, &fc_ie);
}
//Write UTT
ptr = ws_wh_utt_write(ptr, message->messsage_type);
@ -1022,6 +1081,9 @@ static void ws_llc_lowpan_mpx_data_request(llc_data_base_t *base, mpx_user_t *us
message->ie_vector_list[2].iovLen = data->msduLength;
ws_llc_lowpan_mpx_header_set(message, MPX_LOWPAN_ENC_USER_ID);
if (data->ExtendedFrameExchange) {
message->ie_ext.payloadIovLength = 0; //Set Back 2 at response handler
}
base->interface_ptr->mac_api->mcps_data_req_ext(base->interface_ptr->mac_api, &data_req, &message->ie_ext, NULL);
}
@ -1050,6 +1112,7 @@ static void ws_llc_eapol_data_req_init(mcps_data_req_t *data_req, llc_message_t
data_req->TxAckReq = message->ack_requested;
data_req->DstPANId = message->pan_id;
data_req->SrcAddrMode = message->src_address_type;
data_req->ExtendedFrameExchange = false;
if (!data_req->TxAckReq) {
data_req->PanIdSuppressed = false;
data_req->DstAddrMode = MAC_ADDR_MODE_NONE;
@ -1403,6 +1466,104 @@ void ws_llc_free_multicast_temp_entry(protocol_interface_info_entry_t *cur, ws_n
}
static void ws_llc_build_edfe_response(llc_data_base_t *base, mcps_edfe_response_t *response_message, ws_fc_ie_t fc_ie)
{
memset(&response_message->ie_response, 0, sizeof(mcps_data_req_ie_list_t));
response_message->ie_response.headerIeVectorList = &base->ws_header_vector;
base->ws_header_vector.ieBase = base->ws_enhanced_response_elements;
response_message->ie_response.headerIovLength = 1;
//Write Data to block
uint8_t *ptr = base->ws_header_vector.ieBase;
ptr = ws_wh_fc_write(ptr, &fc_ie);
ptr = ws_wh_utt_write(ptr, WS_FT_DATA);
ptr = ws_wh_bt_write(ptr);
ptr = ws_wh_rsl_write(ptr, ws_neighbor_class_rsl_from_dbm_calculate(response_message->rssi));
base->ws_header_vector.iovLen = ptr - base->ws_enhanced_response_elements;
response_message->SrcAddrMode = MAC_ADDR_MODE_NONE;
response_message->wait_response = false;
response_message->PanIdSuppressed = true;
}
static void ws_llc_build_edfe_frame(llc_message_t *message, mcps_edfe_response_t *response_message, ws_fc_ie_t fc_ie)
{
memset(&response_message->ie_response, 0, sizeof(mcps_data_req_ie_list_t));
uint8_t *ptr = message->ie_vector_list[0].ieBase;
fc_ie.tx_flow_ctrl = 0;//Put Data with Handshake
fc_ie.rx_flow_ctrl = 255;
//Write Flow control for 1 packet send this will be modified at real data send
ptr = ws_wh_fc_write(ptr, &fc_ie);
response_message->ie_response.headerIeVectorList = &message->ie_vector_list[0];
response_message->ie_response.headerIovLength = 1;
response_message->ie_response.payloadIeVectorList = &message->ie_vector_list[1];
response_message->ie_response.payloadIovLength = 2;
response_message->SrcAddrMode = MAC_ADDR_MODE_NONE;
response_message->wait_response = true;
response_message->PanIdSuppressed = true;
//tr_debug("FC:Send Data frame");
response_message->edfe_message_status = MCPS_EDFE_TX_FRAME;
}
static void ws_llc_mcps_edfe_handler(const mac_api_t *api, mcps_edfe_response_t *response_message)
{
// INSIDE this shuold not print anything
response_message->edfe_message_status = MCPS_EDFE_NORMAL_FRAME;
llc_data_base_t *base = ws_llc_discover_by_mac(api);
if (!base) {
return;
}
//Discover Here header FC-IE element
ws_fc_ie_t fc_ie;
if (!ws_wh_fc_read(response_message->ie_elements.headerIeList, response_message->ie_elements.headerIeListLength, &fc_ie)) {
return;
}
//tr_debug("Flow ctrl(%u TX,%u RX)", fc_ie.tx_flow_ctrl, fc_ie.rx_flow_ctrl);
if (fc_ie.tx_flow_ctrl == 0 && fc_ie.rx_flow_ctrl) {
llc_message_t *message = NULL;
if (response_message->use_message_handle_to_discover) {
message = llc_message_discover_by_mac_handle(response_message->message_handle, &base->llc_message_list);
}
if (!message) {
//tr_debug("FC:Send a Final Frame");
if (test_drop_data_message) {
test_drop_data_message--;
base->edfe_rx_wait_timer += 99;
response_message->edfe_message_status = MCPS_EDFE_MALFORMED_FRAME;
return;
}
fc_ie.rx_flow_ctrl = 0;
base->edfe_rx_wait_timer = 0;
ws_llc_build_edfe_response(base, response_message, fc_ie);
response_message->edfe_message_status = MCPS_EDFE_FINAL_FRAME_TX;
} else {
if (test_skip_first_init_response) {
//Skip data send and test timeout at Slave side
test_skip_first_init_response = false;
response_message->edfe_message_status = MCPS_EDFE_FINAL_FRAME_RX;
return;
}
ws_llc_build_edfe_frame(message, response_message, fc_ie);
}
} else if (fc_ie.tx_flow_ctrl == 0 && fc_ie.rx_flow_ctrl == 0) {
//tr_debug("FC:Received a Final Frame");
base->edfe_rx_wait_timer = 0;
response_message->edfe_message_status = MCPS_EDFE_FINAL_FRAME_RX;
} else if (fc_ie.tx_flow_ctrl && fc_ie.rx_flow_ctrl) {
base->edfe_rx_wait_timer = fc_ie.tx_flow_ctrl + 99;
fc_ie.tx_flow_ctrl = 0;
fc_ie.rx_flow_ctrl = 255;
//tr_debug("FC:Send a response");
//Enable or refesh timeout timer
ws_llc_build_edfe_response(base, response_message, fc_ie);
response_message->edfe_message_status = MCPS_EDFE_RESPONSE_FRAME;
}
}
int8_t ws_llc_create(struct protocol_interface_info_entry *interface, ws_asynch_ind *asynch_ind_cb, ws_asynch_confirm *asynch_cnf_cb, ws_neighbor_info_request *ws_neighbor_info_request_cb)
{
llc_data_base_t *base = ws_llc_discover_by_interface(interface);
@ -1423,6 +1584,7 @@ int8_t ws_llc_create(struct protocol_interface_info_entry *interface, ws_asynch_
base->ws_neighbor_info_request_cb = ws_neighbor_info_request_cb;
//Register MAC Extensions
base->interface_ptr->mac_api->mac_mcps_extension_enable(base->interface_ptr->mac_api, &ws_llc_mac_indication_cb, &ws_llc_mac_confirm_cb, &ws_llc_ack_data_req_ext);
base->interface_ptr->mac_api->mac_mcps_edfe_enable(base->interface_ptr->mac_api, &ws_llc_mcps_edfe_handler);
//Init MPX class
ws_llc_mpx_init(&base->mpx_data_base);
ws_llc_temp_neigh_info_table_reset(base->temp_entries);
@ -1508,6 +1670,7 @@ int8_t ws_llc_asynch_request(struct protocol_interface_info_entry *interface, as
data_req.SrcAddrMode = MAC_ADDR_MODE_64_BIT;
data_req.Key = request->security;
data_req.msduHandle = message->msg_handle;
data_req.ExtendedFrameExchange = false;
if (request->message_type == WS_FT_PAN_ADVERT_SOL) {
// PANID not know yet must be supressed
data_req.PanIdSuppressed = true;
@ -1651,6 +1814,39 @@ void ws_llc_hopping_schedule_config(struct protocol_interface_info_entry *interf
base->ie_params.hopping_schedule = hopping_schedule;
}
void ws_llc_fast_timer(struct protocol_interface_info_entry *interface, uint16_t ticks)
{
llc_data_base_t *base = ws_llc_discover_by_interface(interface);
if (!base || !base->edfe_rx_wait_timer) {
return;
}
if (ticks > 0xffff / 100) {
ticks = 0xffff;
} else if (ticks == 0) {
ticks = 1;
} else {
ticks *= 100;
}
if (base->edfe_rx_wait_timer > ticks) {
base->edfe_rx_wait_timer -= ticks;
} else {
base->edfe_rx_wait_timer = 0;
tr_debug("EDFE Data Wait Timeout");
//MAC edfe wait data timeout
if (interface->mac_api && interface->mac_api->mlme_req) {
mlme_set_t set_req;
uint8_t value = 0;
set_req.attr = macEdfeForceStop;
set_req.attr_index = 0;
set_req.value_pointer = &value;
set_req.value_size = 1;
interface->mac_api->mlme_req(interface->mac_api, MLME_SET, &set_req);
}
}
}
void ws_llc_timer_seconds(struct protocol_interface_info_entry *interface, uint16_t seconds_update)
{
llc_data_base_t *base = ws_llc_discover_by_interface(interface);

View File

@ -731,4 +731,14 @@ int ws_management_timing_parameters_validate(
return 0;
}
int ws_stack_info_get(int8_t interface_id, ws_stack_info_t *info_ptr)
{
protocol_interface_info_entry_t *cur;
cur = protocol_stack_interface_info_get_by_id(interface_id);
if (!cur || !ws_info(cur) || !info_ptr) {
return -1;
}
return ws_bootstrap_get_info(cur, info_ptr);
}
#endif // HAVE_WS

View File

@ -95,28 +95,6 @@ void ws_neighbor_class_neighbor_unicast_time_info_update(ws_neighbor_class_entry
ws_neighbor->fhss_data.uc_timing_info.ufsi = ws_utt->ufsi;
}
static void ws_neighbour_channel_list_enable_all(ws_channel_mask_t *channel_info, uint16_t number_of_channels)
{
uint32_t mask;
channel_info->channel_count = number_of_channels;
for (uint8_t n = 0; n < 8; n++) {
if (number_of_channels >= 32) {
mask = 0xffffffff;
number_of_channels -= 32;
} else if (number_of_channels) {
mask = 0;
//Start bit enable to MSB
for (uint16_t i = 0; i < (number_of_channels % 32); i++) {
mask |= 1 << i;
}
number_of_channels = 0;
} else {
mask = 0;
}
channel_info->channel_mask[n] = mask;
}
}
static void ws_neighbour_excluded_mask_by_range(ws_channel_mask_t *channel_info, ws_excluded_channel_range_t *range_info, uint16_t number_of_channels)
{
uint16_t range_start, range_stop;
@ -210,29 +188,34 @@ static void ws_neighbour_excluded_mask_by_mask(ws_channel_mask_t *channel_info,
}
}
void ws_neighbor_class_neighbor_unicast_schedule_set(ws_neighbor_class_entry_t *ws_neighbor, ws_us_ie_t *ws_us)
void ws_neighbor_class_neighbor_unicast_schedule_set(ws_neighbor_class_entry_t *ws_neighbor, ws_us_ie_t *ws_us, ws_hopping_schedule_t *own_shedule)
{
ws_neighbor->fhss_data.uc_timing_info.unicast_channel_function = ws_us->channel_function;
if (ws_us->channel_function == WS_FIXED_CHANNEL) {
ws_neighbor->fhss_data.uc_timing_info.fixed_channel = ws_us->function.zero.fixed_channel;
ws_neighbor->fhss_data.uc_timing_info.unicast_number_of_channels = 1;
} else {
if (ws_us->channel_plan == 0) {
ws_neighbor->fhss_data.uc_timing_info.unicast_number_of_channels = ws_common_channel_number_calc(ws_us->plan.zero.regulator_domain, ws_us->plan.zero.operation_class);
} else if (ws_us->channel_plan == 1) {
ws_neighbor->fhss_data.uc_timing_info.unicast_number_of_channels = ws_us->plan.one.number_of_channel;
}
//Handle excluded channel and generate activate channel list
if (ws_us->excluded_channel_ctrl == WS_EXC_CHAN_CTRL_RANGE) {
ws_neighbour_channel_list_enable_all(&ws_neighbor->fhss_data.uc_channel_list, ws_neighbor->fhss_data.uc_timing_info.unicast_number_of_channels);
ws_generate_channel_list(ws_neighbor->fhss_data.uc_channel_list.channel_mask, ws_neighbor->fhss_data.uc_timing_info.unicast_number_of_channels, own_shedule->regulatory_domain, own_shedule->operating_class);
ws_neighbor->fhss_data.uc_channel_list.channel_count = ws_active_channel_count(ws_neighbor->fhss_data.uc_channel_list.channel_mask, ws_neighbor->fhss_data.uc_timing_info.unicast_number_of_channels);
ws_neighbour_excluded_mask_by_range(&ws_neighbor->fhss_data.uc_channel_list, &ws_us->excluded_channels.range, ws_neighbor->fhss_data.uc_timing_info.unicast_number_of_channels);
} else if (ws_us->excluded_channel_ctrl == WS_EXC_CHAN_CTRL_BITMASK) {
ws_neighbour_channel_list_enable_all(&ws_neighbor->fhss_data.uc_channel_list, ws_neighbor->fhss_data.uc_timing_info.unicast_number_of_channels);
ws_generate_channel_list(ws_neighbor->fhss_data.uc_channel_list.channel_mask, ws_neighbor->fhss_data.uc_timing_info.unicast_number_of_channels, own_shedule->regulatory_domain, own_shedule->operating_class);
ws_neighbor->fhss_data.uc_channel_list.channel_count = ws_active_channel_count(ws_neighbor->fhss_data.uc_channel_list.channel_mask, ws_neighbor->fhss_data.uc_timing_info.unicast_number_of_channels);
ws_neighbour_excluded_mask_by_mask(&ws_neighbor->fhss_data.uc_channel_list, &ws_us->excluded_channels.mask, ws_neighbor->fhss_data.uc_timing_info.unicast_number_of_channels);
} else if (ws_us->excluded_channel_ctrl == WS_EXC_CHAN_CTRL_NONE) {
if (ws_neighbor->fhss_data.uc_timing_info.unicast_number_of_channels != ws_neighbor->fhss_data.uc_channel_list.channel_count) {
ws_neighbour_channel_list_enable_all(&ws_neighbor->fhss_data.uc_channel_list, ws_neighbor->fhss_data.uc_timing_info.unicast_number_of_channels);
ws_generate_channel_list(ws_neighbor->fhss_data.uc_channel_list.channel_mask, ws_neighbor->fhss_data.uc_timing_info.unicast_number_of_channels, own_shedule->regulatory_domain, own_shedule->operating_class);
ws_neighbor->fhss_data.uc_channel_list.channel_count = ws_active_channel_count(ws_neighbor->fhss_data.uc_channel_list.channel_mask, ws_neighbor->fhss_data.uc_timing_info.unicast_number_of_channels);
}
}

View File

@ -115,7 +115,7 @@ void ws_neighbor_class_neighbor_unicast_time_info_update(ws_neighbor_class_entry
* \param ws_us Unicast schedule IE data
*
*/
void ws_neighbor_class_neighbor_unicast_schedule_set(ws_neighbor_class_entry_t *ws_neighbor, ws_us_ie_t *ws_us);
void ws_neighbor_class_neighbor_unicast_schedule_set(ws_neighbor_class_entry_t *ws_neighbor, ws_us_ie_t *ws_us, ws_hopping_schedule_t *own_shedule);
/**

View File

@ -39,9 +39,11 @@
#include "Security/protocols/sec_prot_keys.h"
#include "Security/protocols/key_sec_prot/key_sec_prot.h"
#include "Security/protocols/eap_tls_sec_prot/auth_eap_tls_sec_prot.h"
#include "Security/protocols/eap_tls_sec_prot/radius_eap_tls_sec_prot.h"
#include "Security/protocols/tls_sec_prot/tls_sec_prot.h"
#include "Security/protocols/fwh_sec_prot/auth_fwh_sec_prot.h"
#include "Security/protocols/gkh_sec_prot/auth_gkh_sec_prot.h"
#include "Security/protocols/radius_sec_prot/radius_client_sec_prot.h"
#include "6LoWPAN/ws/ws_cfg_settings.h"
#include "6LoWPAN/ws/ws_pae_controller.h"
#include "6LoWPAN/ws/ws_pae_timers.h"
@ -90,14 +92,16 @@ typedef struct {
ws_pae_auth_nw_keys_remove *nw_keys_remove; /**< Network keys remove callback */
ws_pae_auth_nw_key_index_set *nw_key_index_set; /**< Key index set callback */
ws_pae_auth_nw_info_updated *nw_info_updated; /**< Security keys network info updated callback */
ws_pae_auth_ip_addr_get *ip_addr_get; /**< IP address get callback */
supp_list_t active_supp_list; /**< List of active supplicants */
arm_event_storage_t *timer; /**< Timer */
sec_prot_gtk_keys_t *next_gtks; /**< Next GTKs */
const sec_prot_certs_t *certs; /**< Certificates */
sec_prot_keys_nw_info_t *sec_keys_nw_info; /**< Security keys network information */
sec_timer_cfg_t *sec_timer_cfg; /**< Timer configuration */
sec_prot_cfg_t *sec_prot_cfg; /**< Protocol Configuration */
sec_cfg_t *sec_cfg; /**< Security configuration */
uint16_t supp_max_number; /**< Max number of stored supplicants */
uint8_t relay_socked_msg_if_instance_id; /**< Relay socket message interface instance identifier */
uint8_t radius_socked_msg_if_instance_id; /**< Radius socket message interface instance identifier */
bool timer_running : 1; /**< Timer is running */
bool gtk_new_inst_req_exp : 1; /**< GTK new install required timer expired */
bool gtk_new_act_time_exp: 1; /**< GTK new activation time expired */
@ -119,22 +123,23 @@ static int8_t ws_pae_auth_timer_start(pae_auth_t *pae_auth);
static int8_t ws_pae_auth_timer_stop(pae_auth_t *pae_auth);
static bool ws_pae_auth_timer_running(pae_auth_t *pae_auth);
static void ws_pae_auth_kmp_service_addr_get(kmp_service_t *service, kmp_api_t *kmp, kmp_addr_t *local_addr, kmp_addr_t *remote_addr);
static void ws_pae_auth_kmp_service_ip_addr_get(kmp_service_t *service, kmp_api_t *kmp, uint8_t *address);
static kmp_api_t *ws_pae_auth_kmp_service_api_get(kmp_service_t *service, kmp_api_t *kmp, kmp_type_e type);
static kmp_api_t *ws_pae_auth_kmp_incoming_ind(kmp_service_t *service, kmp_type_e type, const kmp_addr_t *addr);
static kmp_api_t *ws_pae_auth_kmp_incoming_ind(kmp_service_t *service, uint8_t msg_if_instance_id, kmp_type_e type, const kmp_addr_t *addr, const void *pdu, uint16_t size);
static void ws_pae_auth_kmp_api_create_confirm(kmp_api_t *kmp, kmp_result_e result);
static void ws_pae_auth_kmp_api_create_indication(kmp_api_t *kmp, kmp_type_e type, kmp_addr_t *addr);
static void ws_pae_auth_kmp_api_finished_indication(kmp_api_t *kmp, kmp_result_e result, kmp_sec_keys_t *sec_keys);
static void ws_pae_auth_next_kmp_trigger(pae_auth_t *pae_auth, supp_entry_t *supp_entry);
static kmp_type_e ws_pae_auth_next_protocol_get(pae_auth_t *pae_auth, supp_entry_t *supp_entry);
static kmp_api_t *ws_pae_auth_kmp_create_and_start(kmp_service_t *service, kmp_type_e type, supp_entry_t *supp_entry, sec_prot_cfg_t *prot_cfg, sec_timer_cfg_t *timer_cfg);
static kmp_api_t *ws_pae_auth_kmp_create_and_start(kmp_service_t *service, kmp_type_e type, uint8_t socked_msg_if_instance_id, supp_entry_t *supp_entry, sec_cfg_t *sec_cfg);
static void ws_pae_auth_kmp_api_finished(kmp_api_t *kmp);
static int8_t tasklet_id = -1;
static NS_LIST_DEFINE(pae_auth_list, pae_auth_t, link);
int8_t ws_pae_auth_init(protocol_interface_info_entry_t *interface_ptr, sec_prot_gtk_keys_t *next_gtks, const sec_prot_certs_t *certs, sec_timer_cfg_t *sec_timer_cfg, sec_prot_cfg_t *sec_prot_cfg, sec_prot_keys_nw_info_t *sec_keys_nw_info)
int8_t ws_pae_auth_init(protocol_interface_info_entry_t *interface_ptr, sec_prot_gtk_keys_t *next_gtks, const sec_prot_certs_t *certs, sec_cfg_t *sec_cfg, sec_prot_keys_nw_info_t *sec_keys_nw_info)
{
if (!interface_ptr || !next_gtks || !certs || !sec_timer_cfg || !sec_prot_cfg || !sec_keys_nw_info) {
if (!interface_ptr || !next_gtks || !certs || !sec_cfg || !sec_keys_nw_info) {
return -1;
}
@ -147,7 +152,6 @@ int8_t ws_pae_auth_init(protocol_interface_info_entry_t *interface_ptr, sec_prot
return -1;
}
memset(&pae_auth->network_name, 0, 33);
pae_auth->pan_id = 0xffff;
pae_auth->interface_ptr = interface_ptr;
@ -162,19 +166,21 @@ int8_t ws_pae_auth_init(protocol_interface_info_entry_t *interface_ptr, sec_prot
pae_auth->next_gtks = next_gtks;
pae_auth->certs = certs;
pae_auth->sec_keys_nw_info = sec_keys_nw_info;
pae_auth->sec_timer_cfg = sec_timer_cfg;
pae_auth->sec_prot_cfg = sec_prot_cfg;
pae_auth->sec_cfg = sec_cfg;
pae_auth->supp_max_number = SUPPLICANT_MAX_NUMBER;
pae_auth->gtk_new_inst_req_exp = false;
pae_auth->gtk_new_act_time_exp = false;
pae_auth->relay_socked_msg_if_instance_id = 0;
pae_auth->radius_socked_msg_if_instance_id = 0;
pae_auth->kmp_service = kmp_service_create();
if (!pae_auth->kmp_service) {
goto error;
}
if (kmp_service_cb_register(pae_auth->kmp_service, ws_pae_auth_kmp_incoming_ind, NULL, ws_pae_auth_kmp_service_addr_get, ws_pae_auth_kmp_service_api_get)) {
if (kmp_service_cb_register(pae_auth->kmp_service, ws_pae_auth_kmp_incoming_ind, NULL, ws_pae_auth_kmp_service_addr_get, ws_pae_auth_kmp_service_ip_addr_get, ws_pae_auth_kmp_service_api_get)) {
goto error;
}
@ -190,10 +196,18 @@ int8_t ws_pae_auth_init(protocol_interface_info_entry_t *interface_ptr, sec_prot
goto error;
}
if (auth_eap_tls_sec_prot_register(pae_auth->kmp_service) < 0) {
// Register radius EAP-TLS and radius client security protocols
if (radius_eap_tls_sec_prot_register(pae_auth->kmp_service) < 0) {
goto error;
}
if (radius_client_sec_prot_register(pae_auth->kmp_service) < 0) {
goto error;
}
// Register EAP-TLS and TLS security protocols
if (auth_eap_tls_sec_prot_register(pae_auth->kmp_service) < 0) {
goto error;
}
if (server_tls_sec_prot_register(pae_auth->kmp_service) < 0) {
goto error;
}
@ -241,7 +255,24 @@ int8_t ws_pae_auth_addresses_set(protocol_interface_info_entry_t *interface_ptr,
return -1;
}
if (kmp_socket_if_register(pae_auth->kmp_service, local_port, remote_addr, remote_port) < 0) {
if (kmp_socket_if_register(pae_auth->kmp_service, &pae_auth->relay_socked_msg_if_instance_id, true, local_port, remote_addr, remote_port) < 0) {
return -1;
}
return 0;
}
int8_t ws_pae_auth_radius_address_set(protocol_interface_info_entry_t *interface_ptr, const uint8_t *remote_addr)
{
pae_auth_t *pae_auth = ws_pae_auth_get(interface_ptr);
if (!pae_auth) {
return -1;
}
if (!pae_auth->kmp_service) {
return -1;
}
if (kmp_socket_if_register(pae_auth->kmp_service, &pae_auth->radius_socked_msg_if_instance_id, false, 0, remote_addr, 1812) < 0) {
return -1;
}
@ -263,7 +294,7 @@ int8_t ws_pae_auth_delete(protocol_interface_info_entry_t *interface_ptr)
return 0;
}
void ws_pae_auth_cb_register(protocol_interface_info_entry_t *interface_ptr, ws_pae_auth_gtk_hash_set *hash_set, ws_pae_auth_nw_key_insert *nw_key_insert, ws_pae_auth_nw_key_index_set *nw_key_index_set, ws_pae_auth_nw_info_updated *nw_info_updated)
void ws_pae_auth_cb_register(protocol_interface_info_entry_t *interface_ptr, ws_pae_auth_gtk_hash_set *hash_set, ws_pae_auth_nw_key_insert *nw_key_insert, ws_pae_auth_nw_key_index_set *nw_key_index_set, ws_pae_auth_nw_info_updated *nw_info_updated, ws_pae_auth_ip_addr_get *ip_addr_get)
{
if (!interface_ptr) {
return;
@ -278,6 +309,7 @@ void ws_pae_auth_cb_register(protocol_interface_info_entry_t *interface_ptr, ws_
pae_auth->nw_key_insert = nw_key_insert;
pae_auth->nw_key_index_set = nw_key_index_set;
pae_auth->nw_info_updated = nw_info_updated;
pae_auth->ip_addr_get = ip_addr_get;
}
void ws_pae_auth_start(protocol_interface_info_entry_t *interface_ptr)
@ -392,7 +424,7 @@ int8_t ws_pae_auth_node_access_revoke_start(protocol_interface_info_entry_t *int
// As default removes other keys than active
int8_t not_removed_index = active_index;
uint32_t revocation_lifetime = ws_pae_timers_gtk_revocation_lifetime_get(pae_auth->sec_timer_cfg);
uint32_t revocation_lifetime = ws_pae_timers_gtk_revocation_lifetime_get(pae_auth->sec_cfg);
uint32_t active_lifetime = sec_prot_keys_gtk_lifetime_get(pae_auth->sec_keys_nw_info->gtks, active_index);
@ -470,8 +502,10 @@ void ws_pae_auth_forced_gc(protocol_interface_info_entry_t *interface_ptr)
ws_pae_lib_supp_list_purge(&pae_auth->active_supp_list, 0, SUPPLICANT_NUMBER_TO_PURGE);
}
int8_t ws_pae_auth_nw_info_set(protocol_interface_info_entry_t *interface_ptr, uint16_t pan_id, char *network_name)
int8_t ws_pae_auth_nw_info_set(protocol_interface_info_entry_t *interface_ptr, uint16_t pan_id, char *network_name, bool updated)
{
(void) updated;
if (!interface_ptr || !network_name) {
return -1;
}
@ -666,7 +700,7 @@ void ws_pae_auth_slow_timer(uint16_t seconds)
uint32_t timer_seconds = sec_prot_keys_gtk_lifetime_decrement(pae_auth->sec_keys_nw_info->gtks, i, current_time, seconds);
if (active_index == i) {
if (!pae_auth->gtk_new_inst_req_exp) {
pae_auth->gtk_new_inst_req_exp = ws_pae_timers_gtk_new_install_required(pae_auth->sec_timer_cfg, timer_seconds);
pae_auth->gtk_new_inst_req_exp = ws_pae_timers_gtk_new_install_required(pae_auth->sec_cfg, timer_seconds);
if (pae_auth->gtk_new_inst_req_exp) {
int8_t second_index = sec_prot_keys_gtk_install_order_second_index_get(pae_auth->sec_keys_nw_info->gtks);
if (second_index < 0) {
@ -682,7 +716,7 @@ void ws_pae_auth_slow_timer(uint16_t seconds)
}
if (!pae_auth->gtk_new_act_time_exp) {
pae_auth->gtk_new_act_time_exp = ws_pae_timers_gtk_new_activation_time(pae_auth->sec_timer_cfg, timer_seconds);
pae_auth->gtk_new_act_time_exp = ws_pae_timers_gtk_new_activation_time(pae_auth->sec_cfg, timer_seconds);
if (pae_auth->gtk_new_act_time_exp) {
int8_t new_active_index = ws_pae_auth_new_gtk_activate(pae_auth);
tr_info("GTK new activation time active index: %i, time: %"PRIu32", new index: %i, system time: %"PRIu32"", active_index, timer_seconds, new_active_index, protocol_core_monotonic_time / 10);
@ -737,7 +771,7 @@ static void ws_pae_auth_gtk_key_insert(pae_auth_t *pae_auth)
}
// Gets latest installed key lifetime and adds GTK expire offset to it
uint32_t lifetime = pae_auth->sec_timer_cfg->gtk_expire_offset;
uint32_t lifetime = pae_auth->sec_cfg->timer_cfg.gtk_expire_offset;
int8_t last_index = sec_prot_keys_gtk_install_order_last_index_get(pae_auth->sec_keys_nw_info->gtks);
if (last_index >= 0) {
lifetime += sec_prot_keys_gtk_lifetime_get(pae_auth->sec_keys_nw_info->gtks, last_index);
@ -840,6 +874,18 @@ static void ws_pae_auth_kmp_service_addr_get(kmp_service_t *service, kmp_api_t *
}
}
static void ws_pae_auth_kmp_service_ip_addr_get(kmp_service_t *service, kmp_api_t *kmp, uint8_t *address)
{
(void) kmp;
pae_auth_t *pae_auth = ws_pae_auth_by_kmp_service_get(service);
if (!pae_auth) {
return;
}
pae_auth->ip_addr_get(pae_auth->interface_ptr, address);
}
static kmp_api_t *ws_pae_auth_kmp_service_api_get(kmp_service_t *service, kmp_api_t *kmp, kmp_type_e type)
{
(void) service;
@ -852,19 +898,26 @@ static kmp_api_t *ws_pae_auth_kmp_service_api_get(kmp_service_t *service, kmp_ap
return ws_pae_lib_kmp_list_type_get(&supp_entry->kmp_list, type);
}
static kmp_api_t *ws_pae_auth_kmp_incoming_ind(kmp_service_t *service, kmp_type_e type, const kmp_addr_t *addr)
static kmp_api_t *ws_pae_auth_kmp_incoming_ind(kmp_service_t *service, uint8_t msg_if_instance_id, kmp_type_e type, const kmp_addr_t *addr, const void *pdu, uint16_t size)
{
pae_auth_t *pae_auth = ws_pae_auth_by_kmp_service_get(service);
if (!pae_auth) {
return NULL;
}
// Find supplicant from list of active supplicants
// For radius messages
if (msg_if_instance_id == pae_auth->radius_socked_msg_if_instance_id) {
// Find KMP from list of active supplicants based on radius message
kmp_api_t *kmp_api = ws_pae_lib_supp_list_kmp_receive_check(&pae_auth->active_supp_list, pdu, size);
return kmp_api;
}
// For relay messages find supplicant from list of active supplicants based on EUI-64
supp_entry_t *supp_entry = ws_pae_lib_supp_list_entry_eui_64_get(&pae_auth->active_supp_list, kmp_address_eui_64_get(addr));
if (!supp_entry) {
// Checks if active supplicant list has space for new supplicants
if (ws_pae_lib_supp_list_active_limit_reached(&pae_auth->active_supp_list, pae_auth->sec_prot_cfg->sec_max_ongoing_authentication)) {
if (ws_pae_lib_supp_list_active_limit_reached(&pae_auth->active_supp_list, pae_auth->sec_cfg->prot_cfg.sec_max_ongoing_authentication)) {
tr_debug("PAE: active limit reached, eui-64: %s", trace_array(kmp_address_eui_64_get(addr), 8));
return NULL;
}
@ -892,14 +945,21 @@ static kmp_api_t *ws_pae_auth_kmp_incoming_ind(kmp_service_t *service, kmp_type_
// Increases waiting time for supplicant authentication
ws_pae_lib_supp_timer_ticks_set(supp_entry, WAIT_FOR_AUTHENTICATION_TICKS);
// Get KMP for supplicant
kmp_api_t *kmp = ws_pae_lib_kmp_list_type_get(&supp_entry->kmp_list, type);
kmp_type_e kmp_type_to_search = type;
// If radius is enabled, route EAP-TLS to radius EAP-TLS
if (pae_auth->sec_cfg->radius_cfg.radius_addr_set && type == IEEE_802_1X_MKA) {
kmp_type_to_search = RADIUS_IEEE_802_1X_MKA;
}
// Search for existing KMP for supplicant
kmp_api_t *kmp = ws_pae_lib_kmp_list_type_get(&supp_entry->kmp_list, kmp_type_to_search);
if (kmp) {
return kmp;
}
// Create a new KMP for initial eapol-key
kmp = kmp_api_create(service, type + IEEE_802_1X_INITIAL_KEY, pae_auth->sec_prot_cfg, pae_auth->sec_timer_cfg);
kmp = kmp_api_create(service, type + IEEE_802_1X_INITIAL_KEY, pae_auth->relay_socked_msg_if_instance_id, pae_auth->sec_cfg);
if (!kmp) {
return 0;
@ -998,15 +1058,15 @@ static void ws_pae_auth_next_kmp_trigger(pae_auth_t *pae_auth, supp_entry_t *sup
// Increases waiting time for supplicant authentication
ws_pae_lib_supp_timer_ticks_set(supp_entry, WAIT_FOR_AUTHENTICATION_TICKS);
if (next_type == IEEE_802_1X_MKA) {
if (next_type == IEEE_802_1X_MKA || next_type == RADIUS_IEEE_802_1X_MKA) {
/* For EAP-TLS, limits the number of ongoing negotiations. If limit
is reached, authenticator does not initiate EAP-TLS right away.
If previous EAP-TLS negotiation completes before negotiation
trigger timeout, authenticator initiates EAP-TLS towards
supplicant. Otherwise supplicant must re-send initial EAPOL-Key
to try again using its trickle schedule */
uint16_t ongoing_eap_tls_cnt = ws_pae_lib_supp_list_kmp_count(&pae_auth->active_supp_list, IEEE_802_1X_MKA);
if (ongoing_eap_tls_cnt >= pae_auth->sec_prot_cfg->sec_max_ongoing_authentication) {
uint16_t ongoing_eap_tls_cnt = ws_pae_lib_supp_list_kmp_count(&pae_auth->active_supp_list, next_type);
if (ongoing_eap_tls_cnt >= pae_auth->sec_cfg->prot_cfg.sec_max_ongoing_authentication) {
supp_entry->retry_ticks = EAP_TLS_NEGOTIATION_TRIGGER_TIMEOUT;
tr_info("EAP-TLS max ongoing reached, count %i, delayed: eui-64: %s", ongoing_eap_tls_cnt, trace_array(supp_entry->addr.eui_64, 8));
return;
@ -1014,12 +1074,25 @@ static void ws_pae_auth_next_kmp_trigger(pae_auth_t *pae_auth, supp_entry_t *sup
}
// Create new instance
kmp_api_t *new_kmp = ws_pae_auth_kmp_create_and_start(pae_auth->kmp_service, next_type, supp_entry, pae_auth->sec_prot_cfg, pae_auth->sec_timer_cfg);
kmp_api_t *new_kmp = ws_pae_auth_kmp_create_and_start(pae_auth->kmp_service, next_type, pae_auth->relay_socked_msg_if_instance_id, supp_entry, pae_auth->sec_cfg);
if (!new_kmp) {
return;
}
// For EAP-TLS create also TLS in addition to EAP-TLS
// For radius EAP-TLS create also radius client in addition to EAP-TLS
if (next_type == RADIUS_IEEE_802_1X_MKA) {
if (ws_pae_lib_kmp_list_type_get(&supp_entry->kmp_list, RADIUS_CLIENT_PROT) != NULL) {
// Radius client already exists, wait for it to be deleted
ws_pae_lib_kmp_list_delete(&supp_entry->kmp_list, new_kmp);
return;
}
// Create radius client instance */
if (ws_pae_auth_kmp_create_and_start(pae_auth->kmp_service, RADIUS_CLIENT_PROT, pae_auth->radius_socked_msg_if_instance_id, supp_entry, pae_auth->sec_cfg) == NULL) {
ws_pae_lib_kmp_list_delete(&supp_entry->kmp_list, new_kmp);
return;
}
}
// For EAP-TLS create also TLS client in addition to EAP-TLS
if (next_type == IEEE_802_1X_MKA) {
if (ws_pae_lib_kmp_list_type_get(&supp_entry->kmp_list, TLS_PROT) != NULL) {
// TLS already exists, wait for it to be deleted
@ -1027,7 +1100,7 @@ static void ws_pae_auth_next_kmp_trigger(pae_auth_t *pae_auth, supp_entry_t *sup
return;
}
// Create TLS instance */
if (ws_pae_auth_kmp_create_and_start(pae_auth->kmp_service, TLS_PROT, supp_entry, pae_auth->sec_prot_cfg, pae_auth->sec_timer_cfg) == NULL) {
if (ws_pae_auth_kmp_create_and_start(pae_auth->kmp_service, TLS_PROT, pae_auth->relay_socked_msg_if_instance_id, supp_entry, pae_auth->sec_cfg) == NULL) {
ws_pae_lib_kmp_list_delete(&supp_entry->kmp_list, new_kmp);
return;
}
@ -1045,7 +1118,11 @@ static kmp_type_e ws_pae_auth_next_protocol_get(pae_auth_t *pae_auth, supp_entry
if (sec_keys->pmk_mismatch) {
sec_keys->ptk_mismatch = true;
// start EAP-TLS towards supplicant
next_type = IEEE_802_1X_MKA;
if (pae_auth->sec_cfg->radius_cfg.radius_addr_set) {
next_type = RADIUS_IEEE_802_1X_MKA;
} else {
next_type = IEEE_802_1X_MKA;
}
tr_info("PAE start EAP-TLS, eui-64: %s", trace_array(supp_entry->addr.eui_64, 8));
} else if (sec_keys->ptk_mismatch) {
// start 4WH towards supplicant
@ -1054,7 +1131,7 @@ static kmp_type_e ws_pae_auth_next_protocol_get(pae_auth_t *pae_auth, supp_entry
}
int8_t gtk_index = -1;
if (next_type != IEEE_802_1X_MKA) {
if (next_type != IEEE_802_1X_MKA && next_type != RADIUS_IEEE_802_1X_MKA) {
// Checks if GTK needs to be inserted
gtk_index = sec_prot_keys_gtk_insert_index_from_gtkl_get(sec_keys);
@ -1071,7 +1148,7 @@ static kmp_type_e ws_pae_auth_next_protocol_get(pae_auth_t *pae_auth, supp_entry
* has been, trigger 4WH to update also the PTK. This prevents writing multiple
* GTK keys to same index using same PTK.
*/
if (pae_auth->sec_timer_cfg->gtk_expire_offset > SHORT_GTK_LIFETIME &&
if (pae_auth->sec_cfg->timer_cfg.gtk_expire_offset > SHORT_GTK_LIFETIME &&
sec_prot_keys_ptk_installed_gtk_hash_mismatch_check(sec_keys, gtk_index)) {
// start 4WH towards supplicant
next_type = IEEE_802_11_4WH;
@ -1094,15 +1171,22 @@ static kmp_type_e ws_pae_auth_next_protocol_get(pae_auth_t *pae_auth, supp_entry
return next_type;
}
static kmp_api_t *ws_pae_auth_kmp_create_and_start(kmp_service_t *service, kmp_type_e type, supp_entry_t *supp_entry, sec_prot_cfg_t *prot_cfg, sec_timer_cfg_t *timer_cfg)
static kmp_api_t *ws_pae_auth_kmp_create_and_start(kmp_service_t *service, kmp_type_e type, uint8_t socked_msg_if_instance_id, supp_entry_t *supp_entry, sec_cfg_t *sec_cfg)
{
// Create KMP instance for new authentication
kmp_api_t *kmp = kmp_api_create(service, type, prot_cfg, timer_cfg);
kmp_api_t *kmp = kmp_api_create(service, type, socked_msg_if_instance_id, sec_cfg);
if (!kmp) {
return NULL;
}
kmp_api_data_set(kmp, supp_entry);
// Sets address to KMP
kmp_api_addr_set(kmp, &supp_entry->addr);
// Sets security keys to KMP
kmp_api_sec_keys_set(kmp, &supp_entry->sec_keys);
if (ws_pae_lib_kmp_list_add(&supp_entry->kmp_list, kmp) == NULL) {
kmp_api_delete(kmp);
return NULL;
@ -1135,7 +1219,7 @@ static void ws_pae_auth_kmp_api_finished(kmp_api_t *kmp)
pae_auth_t *pae_auth = NULL;
supp_entry_t *retry_supp = NULL;
// When EAP-TLS completes check if there are other supplicants that have requested it lately
if (kmp_api_type_get(kmp) == IEEE_802_1X_MKA) {
if (kmp_api_type_get(kmp) == IEEE_802_1X_MKA || kmp_api_type_get(kmp) == RADIUS_IEEE_802_1X_MKA) {
kmp_service_t *service = kmp_api_service_get(kmp);
pae_auth = ws_pae_auth_by_kmp_service_get(service);
if (pae_auth) {

View File

@ -46,15 +46,14 @@
* \param next_gtks next group keys to be used
* \param cert_chain certificate chain
* \param timer_settings timer settings
* \param sec_timer_cfg timer configuration
* \param sec_prot_cfg protocol configuration
* \param sec_cfg security configuration
* \param sec_keys_nw_info security keys network information
*
* \return < 0 failure
* \return >= 0 success
*
*/
int8_t ws_pae_auth_init(protocol_interface_info_entry_t *interface_ptr, sec_prot_gtk_keys_t *next_gtks, const sec_prot_certs_t *certs, sec_timer_cfg_t *sec_timer_cfg, sec_prot_cfg_t *sec_prot_cfg, sec_prot_keys_nw_info_t *sec_keys_nw_info);
int8_t ws_pae_auth_init(protocol_interface_info_entry_t *interface_ptr, sec_prot_gtk_keys_t *next_gtks, const sec_prot_certs_t *certs, sec_cfg_t *sec_cfg, sec_prot_keys_nw_info_t *sec_keys_nw_info);
/**
* ws_pae_auth_addresses_set set relay addresses
@ -70,6 +69,18 @@ int8_t ws_pae_auth_init(protocol_interface_info_entry_t *interface_ptr, sec_prot
*/
int8_t ws_pae_auth_addresses_set(protocol_interface_info_entry_t *interface_ptr, uint16_t local_port, const uint8_t *remote_addr, uint16_t remote_port);
/**
* ws_pae_auth_radius_address_set set radius address
*
* \param interface_ptr interface
* \param remote_addr remote address
*
* \return < 0 failure
* \return >= 0 success
*
*/
int8_t ws_pae_auth_radius_address_set(protocol_interface_info_entry_t *interface_ptr, const uint8_t *remote_addr);
/**
* ws_pae_auth_delete deletes PAE authenticator
*
@ -174,12 +185,13 @@ void ws_pae_auth_forced_gc(protocol_interface_info_entry_t *interface_ptr);
* \param interface_ptr interface
* \param pan_id PAD ID
* \param network_name network name
* \param updated data has been updated
*
* \return < 0 failure
* \return >= 0 success
*
*/
int8_t ws_pae_auth_nw_info_set(protocol_interface_info_entry_t *interface_ptr, uint16_t pan_id, char *network_name);
int8_t ws_pae_auth_nw_info_set(protocol_interface_info_entry_t *interface_ptr, uint16_t pan_id, char *network_name, bool updated);
/**
* ws_pae_auth_gtk_hash_set GTK hash set callback
@ -227,6 +239,15 @@ typedef void ws_pae_auth_nw_key_index_set(protocol_interface_info_entry_t *inter
*/
typedef void ws_pae_auth_nw_info_updated(protocol_interface_info_entry_t *interface_ptr);
/**
* ws_pae_auth_ip_addr_get gets IP addressing information related to KMP
*
* \param interface_ptr interface
* \param address IP address
*
*/
typedef void ws_pae_auth_ip_addr_get(protocol_interface_info_entry_t *interface_ptr, uint8_t *address);
/**
* ws_pae_auth_cb_register register PAE authenticator callbacks
*
@ -235,17 +256,18 @@ typedef void ws_pae_auth_nw_info_updated(protocol_interface_info_entry_t *interf
* \param nw_key_insert network key index callback
* \param nw_key_index_set network send key index callback
* \param nw_info_updated network keys updated callback
* \param ip_addr_get IP addressing information callback
*
*/
void ws_pae_auth_cb_register(protocol_interface_info_entry_t *interface_ptr, ws_pae_auth_gtk_hash_set *hash_set, ws_pae_auth_nw_key_insert *nw_key_insert, ws_pae_auth_nw_key_index_set *nw_key_index_set, ws_pae_auth_nw_info_updated *nw_info_updated);
void ws_pae_auth_cb_register(protocol_interface_info_entry_t *interface_ptr, ws_pae_auth_gtk_hash_set *hash_set, ws_pae_auth_nw_key_insert *nw_key_insert, ws_pae_auth_nw_key_index_set *nw_key_index_set, ws_pae_auth_nw_info_updated *nw_info_updated, ws_pae_auth_ip_addr_get *ip_addr_get);
#else
#define ws_pae_auth_init(interface_ptr, gtks, next_gtks, certs, sec_timer_cfg, sec_prot_cfg) 1
#define ws_pae_auth_init(interface_ptr, next_gtks, certs, sec_cfg, sec_keys_nw_info) 1
#define ws_pae_auth_timing_adjust(timing)
#define ws_pae_auth_addresses_set(interface_ptr, local_port, remote_addr, remote_port) 1
#define ws_pae_auth_delete NULL
#define ws_pae_auth_cb_register(interface_ptr, hash_set, nw_key_insert, nw_key_index_set, nw_info_updated) {(void) hash_set;}
#define ws_pae_auth_cb_register(interface_ptr, hash_set, nw_key_insert, nw_key_index_set, nw_info_updated, ip_addr_get) {(void) hash_set;}
#define ws_pae_auth_start(interface_ptr)
#define ws_pae_auth_gtks_updated NULL
#define ws_pae_auth_nw_key_index_update NULL
@ -256,6 +278,7 @@ void ws_pae_auth_cb_register(protocol_interface_info_entry_t *interface_ptr, ws_
#define ws_pae_auth_forced_gc(interface_ptr)
#define ws_pae_auth_fast_timer NULL
#define ws_pae_auth_slow_timer NULL
#define ws_pae_auth_radius_address_set(interface_ptr, remote_addr) -1
#endif

View File

@ -52,7 +52,7 @@ typedef int8_t ws_pae_br_addr_read(protocol_interface_info_entry_t *interface_pt
typedef void ws_pae_gtks_updated(protocol_interface_info_entry_t *interface_ptr);
typedef int8_t ws_pae_gtk_hash_update(protocol_interface_info_entry_t *interface_ptr, uint8_t *gtkhash);
typedef int8_t ws_pae_nw_key_index_update(protocol_interface_info_entry_t *interface_ptr, uint8_t index);
typedef int8_t ws_pae_nw_info_set(protocol_interface_info_entry_t *interface_ptr, uint16_t pan_id, char *network_name);
typedef int8_t ws_pae_nw_info_set(protocol_interface_info_entry_t *interface_ptr, uint16_t pan_id, char *network_name, bool updated);
typedef struct {
uint8_t gtk[GTK_LEN]; /**< GTK key */
@ -75,8 +75,7 @@ typedef struct {
uint16_t frame_cnt_store_timer; /**< Timer to check if storing of frame counter value is needed */
uint32_t frame_cnt_store_force_timer; /**< Timer to force storing of frame counter, if no other updates */
frame_counters_t frame_counters; /**< Frame counters */
sec_timer_cfg_t sec_timer_cfg; /**< Timer configuration (configuration set values) */
sec_prot_cfg_t sec_prot_cfg; /**< Configuration */
sec_cfg_t sec_cfg; /**< Security configuration (configuration set values) */
uint32_t restart_cnt; /**< Re-start counter */
protocol_interface_info_entry_t *interface_ptr; /**< List link entry */
ws_pae_controller_auth_completed *auth_completed; /**< Authentication completed callback, continue bootstrap */
@ -88,6 +87,7 @@ typedef struct {
ws_pae_controller_pan_ver_increment *pan_ver_increment; /**< PAN version increment callback */
ws_pae_controller_nw_info_updated *nw_info_updated; /**< Network information updated callback */
ws_pae_controller_auth_next_target *auth_next_target; /**< Authentication next target callback */
ws_pae_controller_ip_addr_get *ip_addr_get; /**< IP address get callback */
ws_pae_delete *pae_delete; /**< PAE delete callback */
ws_pae_timer *pae_fast_timer; /**< PAE fast timer callback */
ws_pae_timer *pae_slow_timer; /**< PAE slow timer callback */
@ -102,6 +102,7 @@ typedef struct {
bool gtkhash_set : 1; /**< GTK hashes are set */
bool key_index_set : 1; /**< NW key index is set */
bool frame_counter_read : 1; /**< Frame counters has been read */
bool auth_started : 1; /**< Authenticator has been started */
} pae_controller_t;
typedef struct {
@ -112,12 +113,15 @@ typedef struct {
static void ws_pae_controller_keys_nw_info_init(sec_prot_keys_nw_info_t *sec_keys_nw_info, sec_prot_gtk_keys_t *gtks);
static void ws_pae_controller_nw_info_updated_check(protocol_interface_info_entry_t *interface_ptr);
#ifdef HAVE_PAE_AUTH
static void ws_pae_controller_auth_ip_addr_get(protocol_interface_info_entry_t *interface_ptr, uint8_t *address);
#endif
static pae_controller_t *ws_pae_controller_get(protocol_interface_info_entry_t *interface_ptr);
static void ws_pae_controller_frame_counter_timer(uint16_t seconds, pae_controller_t *entry);
static void ws_pae_controller_frame_counter_timer_trigger(uint16_t seconds, pae_controller_t *entry);
static void ws_pae_controller_frame_counter_store(pae_controller_t *entry, bool use_threshold);
static void ws_pae_controller_nvm_frame_counter_write(nvm_tlv_t *tlv_entry);
static int8_t ws_pae_controller_nvm_frame_counter_read(uint32_t *restart_cnt, uint64_t *stored_time, frame_counters_t *counters);
static int8_t ws_pae_controller_nvm_frame_counter_read(uint32_t *restart_cnt, uint64_t *stored_time, uint16_t *pan_version, frame_counters_t *counters);
static pae_controller_t *ws_pae_controller_get_or_create(int8_t interface_id);
static void ws_pae_controller_gtk_hash_set(protocol_interface_info_entry_t *interface_ptr, uint8_t *gtkhash);
static int8_t ws_pae_controller_nw_key_check_and_insert(protocol_interface_info_entry_t *interface_ptr, sec_prot_gtk_keys_t *gtks);
@ -147,6 +151,8 @@ pae_controller_config_t pae_controller_config = {
.ext_cert_valid_enabled = false
};
sec_radius_cfg_t *pae_controller_radius_settings;
int8_t ws_pae_controller_authenticate(protocol_interface_info_entry_t *interface_ptr)
{
pae_controller_t *controller = ws_pae_controller_get(interface_ptr);
@ -211,11 +217,28 @@ int8_t ws_pae_controller_authenticator_start(protocol_interface_info_entry_t *in
return -1;
}
if (pae_controller_radius_settings) {
// If either address or password is set, both must be set
if (controller->sec_cfg.radius_cfg.radius_addr_set || controller->sec_cfg.radius_cfg.radius_shared_secret_len > 0) {
if (!controller->sec_cfg.radius_cfg.radius_addr_set) {
return -1;
}
if (controller->sec_cfg.radius_cfg.radius_shared_secret_len == 0) {
return -1;
}
if (ws_pae_auth_radius_address_set(interface_ptr, controller->sec_cfg.radius_cfg.radius_addr) < 0) {
return -1;
}
}
}
if (pae_controller_config.node_limit_set) {
ws_pae_auth_node_limit_set(controller->interface_ptr, pae_controller_config.node_limit);
}
ws_pae_auth_cb_register(interface_ptr, ws_pae_controller_gtk_hash_set, ws_pae_controller_nw_key_check_and_insert, ws_pae_controller_nw_key_index_check_and_set, ws_pae_controller_nw_info_updated_check);
ws_pae_auth_cb_register(interface_ptr, ws_pae_controller_gtk_hash_set, ws_pae_controller_nw_key_check_and_insert, ws_pae_controller_nw_key_index_check_and_set, ws_pae_controller_nw_info_updated_check, ws_pae_controller_auth_ip_addr_get);
controller->auth_started = true;
ws_pae_auth_start(interface_ptr);
@ -245,6 +268,21 @@ int8_t ws_pae_controller_cb_register(protocol_interface_info_entry_t *interface_
return 0;
}
int8_t ws_pae_controller_auth_cb_register(protocol_interface_info_entry_t *interface_ptr, ws_pae_controller_ip_addr_get *ip_addr_get)
{
if (!interface_ptr) {
return -1;
}
pae_controller_t *controller = ws_pae_controller_get(interface_ptr);
if (!controller) {
return -1;
}
controller->ip_addr_get = ip_addr_get;
return 0;
}
int8_t ws_pae_controller_set_target(protocol_interface_info_entry_t *interface_ptr, uint16_t target_pan_id, uint8_t *target_eui_64)
{
if (!interface_ptr) {
@ -276,7 +314,7 @@ static void ws_pae_controller_keys_nw_info_init(sec_prot_keys_nw_info_t *sec_key
sec_keys_nw_info->updated = false;
}
int8_t ws_pae_controller_nw_info_set(protocol_interface_info_entry_t *interface_ptr, uint16_t pan_id, char *network_name)
int8_t ws_pae_controller_nw_info_set(protocol_interface_info_entry_t *interface_ptr, uint16_t pan_id, uint16_t pan_version, char *network_name)
{
(void) pan_id;
(void) network_name;
@ -290,20 +328,27 @@ int8_t ws_pae_controller_nw_info_set(protocol_interface_info_entry_t *interface_
return -1;
}
bool updated = false;
// Network name has been modified
if (network_name && strncmp(controller->sec_keys_nw_info.network_name, network_name, 33) != 0) {
if (network_name && strcmp(controller->sec_keys_nw_info.network_name, network_name) != 0) {
strncpy(controller->sec_keys_nw_info.network_name, network_name, 32);
controller->sec_keys_nw_info.updated = true;
updated = true;
}
// PAN ID has been modified
if (pan_id != 0xffff && pan_id != controller->sec_keys_nw_info.new_pan_id) {
controller->sec_keys_nw_info.new_pan_id = pan_id;
controller->sec_keys_nw_info.updated = true;
updated = true;
}
// Store pan version
controller->sec_keys_nw_info.pan_version = pan_version;
if (controller->pae_nw_info_set) {
controller->pae_nw_info_set(interface_ptr, pan_id, network_name);
controller->pae_nw_info_set(interface_ptr, pan_id, network_name, updated);
}
return 0;
@ -327,6 +372,22 @@ static void ws_pae_controller_nw_info_updated_check(protocol_interface_info_entr
}
}
#ifdef HAVE_PAE_AUTH
static void ws_pae_controller_auth_ip_addr_get(protocol_interface_info_entry_t *interface_ptr, uint8_t *address)
{
if (!interface_ptr) {
return;
}
pae_controller_t *controller = ws_pae_controller_get(interface_ptr);
if (!controller) {
return;
}
controller->ip_addr_get(interface_ptr, address);
}
#endif
int8_t ws_pae_controller_nw_key_valid(protocol_interface_info_entry_t *interface_ptr, uint8_t *br_iid)
{
if (!interface_ptr) {
@ -606,8 +667,7 @@ int8_t ws_pae_controller_init(protocol_interface_info_entry_t *interface_ptr)
controller->nw_info_updated = NULL;
controller->auth_next_target = NULL;
memset(&controller->sec_timer_cfg, 0, sizeof(ws_sec_timer_cfg_t));
memset(&controller->sec_prot_cfg, 0, sizeof(sec_prot_cfg_t));
memset(&controller->sec_cfg, 0, sizeof(sec_cfg_t));
ws_pae_controller_data_init(controller);
@ -624,24 +684,28 @@ int8_t ws_pae_controller_configure(protocol_interface_info_entry_t *interface_pt
}
if (sec_prot_cfg) {
controller->sec_prot_cfg.sec_prot_trickle_params.Imin = sec_prot_cfg->sec_prot_trickle_imin * 10;
controller->sec_prot_cfg.sec_prot_trickle_params.Imax = sec_prot_cfg->sec_prot_trickle_imax * 10;
controller->sec_prot_cfg.sec_prot_trickle_params.k = 0;
controller->sec_prot_cfg.sec_prot_trickle_params.TimerExpirations = sec_prot_cfg->sec_prot_trickle_timer_exp;
controller->sec_prot_cfg.sec_prot_retry_timeout = sec_prot_cfg->sec_prot_retry_timeout * 10;
controller->sec_cfg.prot_cfg.sec_prot_trickle_params.Imin = sec_prot_cfg->sec_prot_trickle_imin * 10;
controller->sec_cfg.prot_cfg.sec_prot_trickle_params.Imax = sec_prot_cfg->sec_prot_trickle_imax * 10;
controller->sec_cfg.prot_cfg.sec_prot_trickle_params.k = 0;
controller->sec_cfg.prot_cfg.sec_prot_trickle_params.TimerExpirations = sec_prot_cfg->sec_prot_trickle_timer_exp;
controller->sec_cfg.prot_cfg.sec_prot_retry_timeout = sec_prot_cfg->sec_prot_retry_timeout * 10;
controller->sec_prot_cfg.sec_max_ongoing_authentication = sec_prot_cfg->sec_max_ongoing_authentication;
controller->sec_cfg.prot_cfg.sec_max_ongoing_authentication = sec_prot_cfg->sec_max_ongoing_authentication;
controller->sec_prot_cfg.initial_key_retry_delay = sec_prot_cfg->initial_key_retry_delay;
controller->sec_prot_cfg.initial_key_trickle_params.Imin = sec_prot_cfg->initial_key_imin;
controller->sec_prot_cfg.initial_key_trickle_params.Imax = sec_prot_cfg->initial_key_imax;
controller->sec_prot_cfg.initial_key_trickle_params.k = 0;
controller->sec_prot_cfg.initial_key_trickle_params.TimerExpirations = 2;
controller->sec_prot_cfg.initial_key_retry_cnt = sec_prot_cfg->initial_key_retry_cnt;
controller->sec_cfg.prot_cfg.initial_key_retry_delay = sec_prot_cfg->initial_key_retry_delay;
controller->sec_cfg.prot_cfg.initial_key_trickle_params.Imin = sec_prot_cfg->initial_key_imin;
controller->sec_cfg.prot_cfg.initial_key_trickle_params.Imax = sec_prot_cfg->initial_key_imax;
controller->sec_cfg.prot_cfg.initial_key_trickle_params.k = 0;
controller->sec_cfg.prot_cfg.initial_key_trickle_params.TimerExpirations = 2;
controller->sec_cfg.prot_cfg.initial_key_retry_cnt = sec_prot_cfg->initial_key_retry_cnt;
}
if (sec_timer_cfg) {
ws_pae_timers_settings_init(&controller->sec_timer_cfg, sec_timer_cfg);
ws_pae_timers_settings_init(&controller->sec_cfg.timer_cfg, sec_timer_cfg);
}
if (pae_controller_radius_settings) {
controller->sec_cfg.radius_cfg = *pae_controller_radius_settings;
}
return 0;
@ -676,6 +740,7 @@ static void ws_pae_controller_data_init(pae_controller_t *controller)
controller->frame_cnt_store_timer = FRAME_COUNTER_STORE_INTERVAL;
controller->frame_cnt_store_force_timer = FRAME_COUNTER_STORE_FORCE_INTERVAL;
controller->restart_cnt = 0;
controller->auth_started = false;
ws_pae_controller_frame_counter_reset(&controller->frame_counters);
sec_prot_keys_gtks_init(&controller->gtks);
sec_prot_keys_gtks_init(&controller->next_gtks);
@ -696,7 +761,7 @@ static int8_t ws_pae_controller_frame_counter_read(pae_controller_t *controller)
uint64_t stored_time = 0;
// Read frame counters
if (ws_pae_controller_nvm_frame_counter_read(&controller->restart_cnt, &stored_time, &controller->frame_counters) >= 0) {
if (ws_pae_controller_nvm_frame_counter_read(&controller->restart_cnt, &stored_time, &controller->sec_keys_nw_info.pan_version, &controller->frame_counters) >= 0) {
// Current time is not valid
if (ws_pae_current_time_set(stored_time) < 0) {
ret_value = -1;
@ -704,6 +769,9 @@ static int8_t ws_pae_controller_frame_counter_read(pae_controller_t *controller)
// This is used to ensure that PMK replay counters are fresh after each re-start.
controller->restart_cnt++;
// Increments PAN version to ensure that it is fresh
controller->sec_keys_nw_info.pan_version += PAN_VERSION_STORAGE_READ_INCREMENT;
bool updated = false;
// Checks frame counters
for (uint8_t index = 0; index < GTK_NUM; index++) {
@ -720,7 +788,7 @@ static int8_t ws_pae_controller_frame_counter_read(pae_controller_t *controller)
}
if (updated) {
// Writes incremented frame counters
ws_pae_nvm_store_frame_counter_tlv_create((nvm_tlv_t *) &controller->pae_nvm_buffer, controller->restart_cnt, &controller->frame_counters);
ws_pae_nvm_store_frame_counter_tlv_create((nvm_tlv_t *) &controller->pae_nvm_buffer, controller->restart_cnt, controller->sec_keys_nw_info.pan_version, &controller->frame_counters);
ws_pae_controller_nvm_frame_counter_write((nvm_tlv_t *) &controller->pae_nvm_buffer);
}
}
@ -792,7 +860,7 @@ int8_t ws_pae_controller_supp_init(protocol_interface_info_entry_t *interface_pt
return -1;
}
if (ws_pae_supp_init(controller->interface_ptr, &controller->certs, &controller->sec_timer_cfg, &controller->sec_prot_cfg, &controller->sec_keys_nw_info) < 0) {
if (ws_pae_supp_init(controller->interface_ptr, &controller->certs, &controller->sec_cfg, &controller->sec_keys_nw_info) < 0) {
return -1;
}
@ -803,7 +871,7 @@ int8_t ws_pae_controller_supp_init(protocol_interface_info_entry_t *interface_pt
controller->pae_br_addr_read = ws_pae_supp_border_router_addr_read;
controller->pae_gtk_hash_update = ws_pae_supp_gtk_hash_update;
controller->pae_nw_key_index_update = ws_pae_supp_nw_key_index_update;
controller->pae_nw_info_set = NULL;
controller->pae_nw_info_set = ws_pae_supp_nw_info_set;
ws_pae_supp_cb_register(controller->interface_ptr, controller->auth_completed, controller->auth_next_target, ws_pae_controller_nw_key_check_and_insert, ws_pae_controller_active_nw_key_set, ws_pae_controller_gtk_hash_ptr_get, ws_pae_controller_nw_info_updated_check);
@ -822,7 +890,7 @@ int8_t ws_pae_controller_auth_init(protocol_interface_info_entry_t *interface_pt
return -1;
}
if (ws_pae_auth_init(controller->interface_ptr, &controller->next_gtks, &controller->certs, &controller->sec_timer_cfg, &controller->sec_prot_cfg, &controller->sec_keys_nw_info) < 0) {
if (ws_pae_auth_init(controller->interface_ptr, &controller->next_gtks, &controller->certs, &controller->sec_cfg, &controller->sec_keys_nw_info) < 0) {
return -1;
}
@ -855,7 +923,7 @@ int8_t ws_pae_controller_auth_init(protocol_interface_info_entry_t *interface_pt
/* If network information i.e pan_id and network name exists updates bootstrap with it,
(in case already configured by application then no changes are made) */
if (controller->nw_info_updated) {
controller->nw_info_updated(interface_ptr, controller->sec_keys_nw_info.key_pan_id, controller->sec_keys_nw_info.network_name);
controller->nw_info_updated(interface_ptr, controller->sec_keys_nw_info.key_pan_id, controller->sec_keys_nw_info.pan_version, controller->sec_keys_nw_info.network_name);
}
if (!read_gtks_to || sec_prot_keys_gtk_count(read_gtks_to) == 0) {
// Key material invalid or GTKs are expired, delete GTKs from NVM
@ -1103,6 +1171,130 @@ int8_t ws_pae_controller_certificate_revocation_list_remove(const arm_cert_revoc
return ret;
}
int8_t ws_pae_controller_radius_address_set(int8_t interface_id, const uint8_t *address)
{
pae_controller_t *controller = ws_pae_controller_get_or_create(interface_id);
// If remote address is not set, clear radius information
if (!address) {
if (pae_controller_radius_settings != NULL) {
pae_controller_radius_settings->radius_addr_set = false;
}
if (controller) {
ws_pae_controller_configure(controller->interface_ptr, NULL, NULL);
}
return 0;
}
if (pae_controller_radius_settings == NULL) {
pae_controller_radius_settings = ns_dyn_mem_alloc(sizeof(sec_radius_cfg_t));
if (!pae_controller_radius_settings) {
return -1;
}
memset(pae_controller_radius_settings, 0, sizeof(sec_radius_cfg_t));
}
memcpy(pae_controller_radius_settings->radius_addr, address, 16);
pae_controller_radius_settings->radius_addr_set = true;
if (controller) {
ws_pae_controller_configure(controller->interface_ptr, NULL, NULL);
if (ws_pae_auth_radius_address_set(controller->interface_ptr, controller->sec_cfg.radius_cfg.radius_addr) < 0) {
return -1;
}
}
return 0;
}
int8_t ws_pae_controller_radius_address_get(int8_t interface_id, uint8_t *address)
{
(void) interface_id;
if (address == NULL) {
return -1;
}
if (pae_controller_radius_settings == NULL || !pae_controller_radius_settings->radius_addr_set) {
return -1;
}
memcpy(address, pae_controller_radius_settings->radius_addr, 16);
return 0;
}
int8_t ws_pae_controller_radius_shared_secret_set(int8_t interface_id, const uint16_t shared_secret_len, const uint8_t *shared_secret)
{
pae_controller_t *controller = ws_pae_controller_get_or_create(interface_id);
// If shared secret is not set, clear radius information
if (shared_secret_len == 0 || !shared_secret) {
if (pae_controller_radius_settings != NULL) {
memset(pae_controller_radius_settings->radius_shared_secret, 0, pae_controller_radius_settings->radius_shared_secret_len);
pae_controller_radius_settings->radius_shared_secret_len = 0;
}
if (controller) {
ws_pae_controller_configure(controller->interface_ptr, NULL, NULL);
}
return 0;
}
if (pae_controller_radius_settings == NULL) {
pae_controller_radius_settings = ns_dyn_mem_alloc(sizeof(sec_radius_cfg_t));
if (!pae_controller_radius_settings) {
return -1;
}
memset(pae_controller_radius_settings, 0, sizeof(sec_radius_cfg_t));
}
if (pae_controller_radius_settings->radius_shared_secret != NULL &&
pae_controller_radius_settings->radius_shared_secret_len != shared_secret_len) {
ns_dyn_mem_free(pae_controller_radius_settings->radius_shared_secret);
pae_controller_radius_settings->radius_shared_secret = NULL;
}
if (pae_controller_radius_settings->radius_shared_secret == NULL) {
pae_controller_radius_settings->radius_shared_secret = ns_dyn_mem_alloc(shared_secret_len);
if (pae_controller_radius_settings->radius_shared_secret == NULL) {
return -1;
}
}
memcpy(pae_controller_radius_settings->radius_shared_secret, shared_secret, shared_secret_len);
pae_controller_radius_settings->radius_shared_secret_len = shared_secret_len;
if (controller) {
ws_pae_controller_configure(controller->interface_ptr, NULL, NULL);
}
return 0;
}
int8_t ws_pae_controller_radius_shared_secret_get(int8_t interface_id, uint16_t *shared_secret_len, uint8_t *shared_secret)
{
(void) interface_id;
if (shared_secret_len == NULL) {
return -1;
}
uint16_t length = 0;
if (pae_controller_radius_settings != NULL) {
length = pae_controller_radius_settings->radius_shared_secret_len;
if (shared_secret != NULL) {
if (length > *shared_secret_len) {
length = *shared_secret_len;
}
if (length > 0 && pae_controller_radius_settings->radius_shared_secret != NULL) {
memcpy(shared_secret, pae_controller_radius_settings->radius_shared_secret, length);
}
}
}
*shared_secret_len = length;
return 0;
}
int8_t ws_pae_controller_border_router_addr_write(protocol_interface_info_entry_t *interface_ptr, const uint8_t *eui_64)
{
if (!eui_64) {
@ -1165,7 +1357,7 @@ int8_t ws_pae_controller_gtk_update(int8_t interface_id, uint8_t *gtk[GTK_NUM])
for (uint8_t i = 0; i < GTK_NUM; i++) {
if (gtk[i]) {
uint32_t lifetime = sec_prot_keys_gtk_install_order_last_lifetime_get(&controller->gtks);
lifetime += controller->sec_timer_cfg.gtk_expire_offset;
lifetime += controller->sec_cfg.timer_cfg.gtk_expire_offset;
if (sec_prot_keys_gtk_set(&controller->gtks, i, gtk[i], lifetime) >= 0) {
controller->gtks_set = true;
tr_info("GTK set index: %i, lifetime %"PRIu32", system time: %"PRIu32"", i, lifetime, protocol_core_monotonic_time / 10);
@ -1446,7 +1638,7 @@ static void ws_pae_controller_frame_counter_store(pae_controller_t *entry, bool
if (update_needed || entry->frame_cnt_store_force_timer == 0) {
tr_debug("Write frame counters: system time %"PRIu32"", protocol_core_monotonic_time / 10);
// Writes modified frame counters
ws_pae_nvm_store_frame_counter_tlv_create((nvm_tlv_t *) &entry->pae_nvm_buffer, entry->restart_cnt, &entry->frame_counters);
ws_pae_nvm_store_frame_counter_tlv_create((nvm_tlv_t *) &entry->pae_nvm_buffer, entry->restart_cnt, entry->sec_keys_nw_info.pan_version, &entry->frame_counters);
ws_pae_controller_nvm_frame_counter_write((nvm_tlv_t *) &entry->pae_nvm_buffer);
// Reset force interval when ever values are stored
@ -1454,7 +1646,7 @@ static void ws_pae_controller_frame_counter_store(pae_controller_t *entry, bool
}
}
static int8_t ws_pae_controller_nvm_frame_counter_read(uint32_t *restart_cnt, uint64_t *stored_time, frame_counters_t *counters)
static int8_t ws_pae_controller_nvm_frame_counter_read(uint32_t *restart_cnt, uint64_t *stored_time, uint16_t *pan_version, frame_counters_t *counters)
{
nvm_tlv_t *tlv = ws_pae_nvm_store_generic_tlv_allocate_and_create(
PAE_NVM_FRAME_COUNTER_TAG, PAE_NVM_FRAME_COUNTER_LEN);
@ -1467,7 +1659,7 @@ static int8_t ws_pae_controller_nvm_frame_counter_read(uint32_t *restart_cnt, ui
return -1;
}
if (ws_pae_nvm_store_frame_counter_tlv_read(tlv, restart_cnt, stored_time, counters) < 0) {
if (ws_pae_nvm_store_frame_counter_tlv_read(tlv, restart_cnt, stored_time, pan_version, counters) < 0) {
ws_pae_nvm_store_generic_tlv_free(tlv);
return -1;
}

View File

@ -232,18 +232,69 @@ int8_t ws_pae_controller_certificate_revocation_list_add(const arm_cert_revocati
*/
int8_t ws_pae_controller_certificate_revocation_list_remove(const arm_cert_revocation_list_entry_s *crl);
/**
* ws_pae_controller_radius_address_set set radius address
*
* \param interface_id interface identifier
* \param address address
*
* \return < 0 failure
* \return >= 0 success
*
*/
int8_t ws_pae_controller_radius_address_set(int8_t interface_id, const uint8_t *address);
/**
* ws_pae_controller_radius_address_set get radius address
*
* \param interface_id interface identifier
* \param address address buffer where to write address, must have space at least for 39 characters and NUL terminator
*
* \return < 0 failure
* \return >= 0 success
*
*/
int8_t ws_pae_controller_radius_address_get(int8_t interface_id, uint8_t *address);
/**
* ws_pae_controller_radius_shared_secret_set set radius shared secret
*
* \param interface_id interface identifier
* \param shared_secret_len shared secret length
* \param shared_secret shared secret
*
* \return < 0 failure
* \return >= 0 success
*
*/
int8_t ws_pae_controller_radius_shared_secret_set(int8_t interface_id, const uint16_t shared_secret_len, const uint8_t *shared_secret);
/**
* ws_pae_controller_radius_shared_secret_get get radius shared secret
*
* \param interface_id interface identifier
* \param shared_secret_len On call, shared secret buffer length, on return shared secret length
* \param shared_secret shared secret
*
* \return < 0 failure
* \return >= 0 success
*
*/
int8_t ws_pae_controller_radius_shared_secret_get(int8_t interface_id, uint16_t *shared_secret_len, uint8_t *shared_secret);
/**
* ws_pae_controller_nw_info_set set network information
*
* \param interface_ptr interface
* \param pan_id PAD ID
* \param pan_version PAN version
* \param network_name network name
*
* \return < 0 failure
* \return >= 0 success
*
*/
int8_t ws_pae_controller_nw_info_set(protocol_interface_info_entry_t *interface_ptr, uint16_t pan_id, char *network_name);
int8_t ws_pae_controller_nw_info_set(protocol_interface_info_entry_t *interface_ptr, uint16_t pan_id, uint16_t pan_version, char *network_name);
/**
* ws_pae_controller_nw_key_valid network key is valid i.e. used successfully on bootstrap
@ -518,13 +569,14 @@ typedef void ws_pae_controller_pan_ver_increment(protocol_interface_info_entry_t
*
* \param interface_ptr interface
* \param pan_id PAN ID
* \param pan_version PAN version
* \param network_name network name
*
*/
typedef void ws_pae_controller_nw_info_updated(protocol_interface_info_entry_t *interface_ptr, uint16_t pan_id, char *network_name);
typedef void ws_pae_controller_nw_info_updated(protocol_interface_info_entry_t *interface_ptr, uint16_t pan_id, uint16_t pan_version, char *network_name);
/**
* ws_pae_controller_cb_register register PEA controller callbacks
* ws_pae_controller_cb_register register controller callbacks
*
* \param interface_ptr interface
* \param completed authentication completed callback
@ -543,6 +595,30 @@ typedef void ws_pae_controller_nw_info_updated(protocol_interface_info_entry_t *
*/
int8_t ws_pae_controller_cb_register(protocol_interface_info_entry_t *interface_ptr, ws_pae_controller_auth_completed *completed, ws_pae_controller_auth_next_target *auth_next_target, ws_pae_controller_nw_key_set *nw_key_set, ws_pae_controller_nw_key_clear *nw_key_clear, ws_pae_controller_nw_send_key_index_set *nw_send_key_index_set, ws_pae_controller_nw_frame_counter_set *nw_frame_counter_set, ws_pae_controller_nw_frame_counter_read *nw_frame_counter_read, ws_pae_controller_pan_ver_increment *pan_ver_increment, ws_pae_controller_nw_info_updated *nw_info_updated);
/**
* ws_pae_controller_ip_addr_get gets IP addressing information
*
* \param interface_ptr interface
* \param address IP address
*
* \return < 0 failure
* \return >= 0 success
*
*/
typedef int8_t ws_pae_controller_ip_addr_get(protocol_interface_info_entry_t *interface_ptr, uint8_t *address);
/**
* ws_pae_controller_auth_cb_register register authenticator callbacks
*
* \param interface_ptr interface
* \param ip_addr_get IP address get callback
*
* \return < 0 failure
* \return >= 0 success
*
*/
int8_t ws_pae_controller_auth_cb_register(protocol_interface_info_entry_t *interface_ptr, ws_pae_controller_ip_addr_get *ip_addr_get);
/**
* ws_pae_controller_fast_timer PAE controller fast timer call
*

View File

@ -419,6 +419,19 @@ uint16_t ws_pae_lib_supp_list_kmp_count(supp_list_t *supp_list, kmp_type_e type)
return kmp_count;
}
kmp_api_t *ws_pae_lib_supp_list_kmp_receive_check(supp_list_t *supp_list, const void *pdu, uint16_t size)
{
ns_list_foreach(supp_entry_t, entry, supp_list) {
ns_list_foreach(kmp_entry_t, kmp_entry, &entry->kmp_list) {
if (kmp_api_receive_check(kmp_entry->kmp, pdu, size)) {
return kmp_entry->kmp;
}
}
}
return NULL;
}
supp_entry_t *ws_pae_lib_supp_list_entry_retry_timer_get(supp_list_t *supp_list)
{
supp_entry_t *retry_supp = NULL;

View File

@ -366,6 +366,18 @@ bool ws_pae_lib_supp_list_active_limit_reached(supp_list_t *active_supp_list, ui
*/
uint16_t ws_pae_lib_supp_list_kmp_count(supp_list_t *supp_list, kmp_type_e type);
/**
* ws_pae_lib_supp_list_kmp_receive_check check if received message is for this KMP in a list of supplicants
*
* \param supp_list list of supplicants
* \param pdu pdu
* \param size pdu size
*
* \return KMP api for the received message
*
*/
kmp_api_t *ws_pae_lib_supp_list_kmp_receive_check(supp_list_t *supp_list, const void *pdu, uint16_t size);
/**
* ws_pae_lib_supp_list_entry_retry_timer_get checks if some supplicant has retry timer running
*

View File

@ -281,7 +281,7 @@ int8_t ws_pae_nvm_store_keys_tlv_read(nvm_tlv_t *tlv_entry, sec_prot_keys_t *sec
return 0;
}
void ws_pae_nvm_store_frame_counter_tlv_create(nvm_tlv_t *tlv_entry, uint32_t restart_cnt, frame_counters_t *counters)
void ws_pae_nvm_store_frame_counter_tlv_create(nvm_tlv_t *tlv_entry, uint32_t restart_cnt, uint16_t pan_version, frame_counters_t *counters)
{
tlv_entry->tag = PAE_NVM_FRAME_COUNTER_TAG;
tlv_entry->len = PAE_NVM_FRAME_COUNTER_LEN;
@ -293,6 +293,8 @@ void ws_pae_nvm_store_frame_counter_tlv_create(nvm_tlv_t *tlv_entry, uint32_t re
uint64_t stored_time = ws_pae_current_time_get();
tlv = common_write_64_bit(stored_time, tlv);
tlv = common_write_16_bit(pan_version, tlv);
for (uint8_t index = 0; index < GTK_NUM; index++) {
if (!counters->counter[index].set) {
*tlv++ = PAE_NVM_FIELD_NOT_SET;
@ -309,7 +311,7 @@ void ws_pae_nvm_store_frame_counter_tlv_create(nvm_tlv_t *tlv_entry, uint32_t re
tr_debug("NVM FRAME COUNTER write");
}
int8_t ws_pae_nvm_store_frame_counter_tlv_read(nvm_tlv_t *tlv_entry, uint32_t *restart_cnt, uint64_t *stored_time, frame_counters_t *counters)
int8_t ws_pae_nvm_store_frame_counter_tlv_read(nvm_tlv_t *tlv_entry, uint32_t *restart_cnt, uint64_t *stored_time, uint16_t *pan_version, frame_counters_t *counters)
{
if (!tlv_entry || !counters) {
return -1;
@ -327,6 +329,9 @@ int8_t ws_pae_nvm_store_frame_counter_tlv_read(nvm_tlv_t *tlv_entry, uint32_t *r
*stored_time = common_read_64_bit(tlv);
tlv += 8;
*pan_version = common_read_16_bit(tlv);
tlv += 2;
for (uint8_t index = 0; index < GTK_NUM; index++) {
// Frame counter not set
if (*tlv++ == PAE_NVM_FIELD_NOT_SET) {

View File

@ -41,8 +41,8 @@
// PTK EUI-64 set (1) + PTK EUI-64 (8) + PMK set (1) + PMK lifetime (4) + PMK (32) + PMK replay counter (8) + PTK set (1) + PTK lifetime (4) + PTK (48)
#define PAE_NVM_KEYS_LEN 1 + 8 + 1 + 4 + PMK_LEN + 8 + 1 + 4 + PTK_LEN
// restart counter + stored time + (frame counter set (1) + GTK (16) + frame counter (4)) * 4
#define PAE_NVM_FRAME_COUNTER_LEN 4 + 8 + (1 + GTK_LEN + 4) * GTK_NUM
// restart counter + stored time + pan version + (frame counter set (1) + GTK (16) + frame counter (4)) * 4
#define PAE_NVM_FRAME_COUNTER_LEN 4 + 8 + 2 + (1 + GTK_LEN + 4) * GTK_NUM
#define PAE_NVM_DEFAULT_BUFFER_SIZE sizeof(nvm_tlv_t) + PAE_NVM_NW_INFO_LEN
@ -119,10 +119,11 @@ int8_t ws_pae_nvm_store_keys_tlv_read(nvm_tlv_t *tlv_entry, sec_prot_keys_t *sec
*
* \param tlv_entry TLV buffer pointer
* \param restart_cnt re-start counter
* \param pan_version PAN version
* \param counters frame counters
*
*/
void ws_pae_nvm_store_frame_counter_tlv_create(nvm_tlv_t *tlv_entry, uint32_t restart_cnt, frame_counters_t *counters);
void ws_pae_nvm_store_frame_counter_tlv_create(nvm_tlv_t *tlv_entry, uint32_t restart_cnt, uint16_t pan_version, frame_counters_t *counters);
/**
* ws_pae_nvm_store_frame_counter_tlv_read read from NVM frame counter TLV
@ -130,13 +131,14 @@ void ws_pae_nvm_store_frame_counter_tlv_create(nvm_tlv_t *tlv_entry, uint32_t re
* \param tlv_entry TLV
* \param restart_cnt re-start counter
* \param stored_time stored timestampt
* \param pan_version PAN version
* \param counters frame counters
*
* \return < 0 failure
* \return >= 0 success
*
*/
int8_t ws_pae_nvm_store_frame_counter_tlv_read(nvm_tlv_t *tlv_entry, uint32_t *restart_cnt, uint64_t *stored_time, frame_counters_t *counters);
int8_t ws_pae_nvm_store_frame_counter_tlv_read(nvm_tlv_t *tlv_entry, uint32_t *restart_cnt, uint64_t *stored_time, uint16_t *pan_version, frame_counters_t *counters);
/**
* ws_pae_nvm_store_key_storage_index_tlv_create create NVM key storage index TLV

View File

@ -100,8 +100,7 @@ typedef struct {
uint8_t new_br_eui_64[8]; /**< Border router EUI-64 indicated by bootstrap after bootstrap start */
uint8_t comp_br_eui_64[8]; /**< Border router EUI-64 indicated by bootstrap after bootstrap completed */
sec_prot_keys_nw_info_t *sec_keys_nw_info; /**< Security keys network information */
sec_timer_cfg_t *sec_timer_cfg; /**< Timer configuration */
sec_prot_cfg_t *sec_prot_cfg; /**< Protocol Configuration */
sec_cfg_t *sec_cfg; /**< Security configuration */
uint8_t nw_keys_used_cnt; /**< How many times bootstrap has been tried with current keys */
uint8_t initial_key_retry_cnt; /**< initial EAPOL-Key retry counter */
bool auth_trickle_running : 1; /**< Initial EAPOL-Key Trickle timer running */
@ -126,6 +125,7 @@ static void ws_pae_supp_free(pae_supp_t *pae_supp);
static void ws_pae_supp_authenticate_response(pae_supp_t *pae_supp, auth_result_e result);
static int8_t ws_pae_supp_initial_key_send(pae_supp_t *pae_supp);
static void ws_pae_supp_nvm_update(pae_supp_t *pae_supp);
static int8_t ws_pae_supp_network_name_compare(char *name1, char *name2);
static int8_t ws_pae_supp_nw_keys_valid_check(pae_supp_t *pae_supp, uint16_t pan_id, char *dest_network_name);
static int8_t ws_pae_supp_nvm_keys_write(pae_supp_t *pae_supp);
static pae_supp_t *ws_pae_supp_get(protocol_interface_info_entry_t *interface_ptr);
@ -142,7 +142,7 @@ static int8_t ws_pae_supp_timer_stop(pae_supp_t *pae_supp);
static bool ws_pae_supp_timer_running(pae_supp_t *pae_supp);
static void ws_pae_supp_kmp_service_addr_get(kmp_service_t *service, kmp_api_t *kmp, kmp_addr_t *local_addr, kmp_addr_t *remote_addr);
static kmp_api_t *ws_pae_supp_kmp_service_api_get(kmp_service_t *service, kmp_api_t *kmp, kmp_type_e type);
static kmp_api_t *ws_pae_supp_kmp_incoming_ind(kmp_service_t *service, kmp_type_e type, const kmp_addr_t *addr);
static kmp_api_t *ws_pae_supp_kmp_incoming_ind(kmp_service_t *service, uint8_t instance_id, kmp_type_e type, const kmp_addr_t *addr, const void *pdu, uint16_t size);
static kmp_api_t *ws_pae_supp_kmp_tx_status_ind(kmp_service_t *service, uint8_t instance_id);
static kmp_api_t *ws_pae_supp_kmp_create_and_start(kmp_service_t *service, kmp_type_e type, pae_supp_t *pae_supp);
static int8_t ws_pae_supp_eapol_pdu_address_check(protocol_interface_info_entry_t *interface_ptr, const uint8_t *eui_64);
@ -200,7 +200,7 @@ int8_t ws_pae_supp_authenticate(protocol_interface_info_entry_t *interface_ptr,
/* Network name or PAN ID has changed, delete key data associated with border router
i.e PMK, PTK, EA-IE data (border router EUI-64) */
if (strcmp(pae_supp->sec_keys_nw_info->network_name, dest_network_name) != 0 ||
if (ws_pae_supp_network_name_compare(pae_supp->sec_keys_nw_info->network_name, dest_network_name) != 0 ||
(pae_supp->sec_keys_nw_info->key_pan_id != 0xFFFF && pae_supp->sec_keys_nw_info->key_pan_id != dest_pan_id)) {
sec_prot_keys_pmk_delete(&pae_supp->entry.sec_keys);
sec_prot_keys_ptk_delete(&pae_supp->entry.sec_keys);
@ -286,8 +286,9 @@ int8_t ws_pae_supp_nw_key_valid(protocol_interface_info_entry_t *interface_ptr,
/* If border router EUI-64 received on bootstrap complete does not match to
EUI-64 stored with keys, delete keys */
if (memcmp(ptk_eui_64, pae_supp->comp_br_eui_64, 8) != 0) {
tr_warn("Delete keys: PTK EUI-64 %s does not match to BR EUI-64 %s", tr_array(ptk_eui_64, 8), tr_array(pae_supp->comp_br_eui_64, 8));
if (!ptk_eui_64 || memcmp(ptk_eui_64, pae_supp->comp_br_eui_64, 8) != 0) {
tr_warn("Delete keys: PTK EUI-64 %s does not match to BR EUI-64 %s",
ptk_eui_64 ? tr_array(ptk_eui_64, 8) : "", tr_array(pae_supp->comp_br_eui_64, 8));
sec_prot_keys_pmk_delete(&pae_supp->entry.sec_keys);
sec_prot_keys_ptk_delete(&pae_supp->entry.sec_keys);
sec_prot_keys_ptk_eui_64_delete(&pae_supp->entry.sec_keys);
@ -349,7 +350,7 @@ int8_t ws_pae_supp_gtk_hash_update(protocol_interface_info_entry_t *interface_pt
// Starts supplicant timer
ws_pae_supp_timer_start(pae_supp);
tr_info("GTK update start imin: %i, imax: %i, max mismatch: %i, tr time: %i", pae_supp->sec_timer_cfg->gtk_request_imin, pae_supp->sec_timer_cfg->gtk_request_imax, pae_supp->sec_timer_cfg->gtk_max_mismatch, pae_supp->auth_trickle_timer.t);
tr_info("GTK update start imin: %i, imax: %i, max mismatch: %i, tr time: %i", pae_supp->sec_cfg->timer_cfg.gtk_request_imin, pae_supp->sec_cfg->timer_cfg.gtk_request_imax, pae_supp->sec_cfg->timer_cfg.gtk_max_mismatch, pae_supp->auth_trickle_timer.t);
}
}
@ -488,6 +489,14 @@ static int8_t ws_pae_supp_initial_key_send(pae_supp_t *pae_supp)
return 0;
}
static int8_t ws_pae_supp_network_name_compare(char *name1, char *name2)
{
if (strlen(name1) == strlen(name2) && strcmp(name1, name2) == 0) {
return 0;
}
return -1;
}
static int8_t ws_pae_supp_nw_keys_valid_check(pae_supp_t *pae_supp, uint16_t pan_id, char *dest_network_name)
{
// Checks how many times authentication has been tried with current network keys
@ -506,7 +515,7 @@ static int8_t ws_pae_supp_nw_keys_valid_check(pae_supp_t *pae_supp, uint16_t pan
/* Checks if keys match to network name and PAN ID and that needed keys exists (PMK,
PTK and a GTK), and calls inserts function that will update the network keys as
needed */
if ((strcmp(dest_network_name, pae_supp->sec_keys_nw_info->network_name) == 0 &&
if ((ws_pae_supp_network_name_compare(dest_network_name, pae_supp->sec_keys_nw_info->network_name) == 0 &&
pan_id == pae_supp->sec_keys_nw_info->key_pan_id) &&
(sec_prot_keys_gtk_count(pae_supp->sec_keys_nw_info->gtks) > 0) &&
(sec_prot_keys_pmk_get(&pae_supp->entry.sec_keys) != NULL) &&
@ -523,6 +532,31 @@ static int8_t ws_pae_supp_nw_keys_valid_check(pae_supp_t *pae_supp, uint16_t pan
}
}
int8_t ws_pae_supp_nw_info_set(protocol_interface_info_entry_t *interface_ptr, uint16_t pan_id, char *network_name, bool updated)
{
(void) pan_id;
(void) network_name;
pae_supp_t *pae_supp = ws_pae_supp_get(interface_ptr);
if (!pae_supp) {
return -1;
}
if (updated) {
tr_info("Delete old keys, new PAN ID: %i network name: %s", pan_id, network_name);
// Delete pair wise keys
sec_prot_keys_pmk_delete(&pae_supp->entry.sec_keys);
sec_prot_keys_ptk_delete(&pae_supp->entry.sec_keys);
sec_prot_keys_ptk_eui_64_delete(&pae_supp->entry.sec_keys);
// Delete GTKs
sec_prot_keys_gtks_init(pae_supp->sec_keys_nw_info->gtks);
sec_prot_keys_gtks_updated_set(pae_supp->sec_keys_nw_info->gtks);
ws_pae_supp_nvm_update(pae_supp);
}
return 0;
}
void ws_pae_supp_cb_register(protocol_interface_info_entry_t *interface_ptr, ws_pae_supp_auth_completed *completed, ws_pae_supp_auth_next_target *auth_next_target, ws_pae_supp_nw_key_insert *nw_key_insert, ws_pae_supp_nw_key_index_set *nw_key_index_set, ws_pae_supp_gtk_hash_ptr_get *gtk_hash_ptr_get, ws_pae_supp_nw_info_updated *nw_info_updated)
{
pae_supp_t *pae_supp = ws_pae_supp_get(interface_ptr);
@ -538,7 +572,7 @@ void ws_pae_supp_cb_register(protocol_interface_info_entry_t *interface_ptr, ws_
pae_supp->nw_info_updated = nw_info_updated;
}
int8_t ws_pae_supp_init(protocol_interface_info_entry_t *interface_ptr, const sec_prot_certs_t *certs, sec_timer_cfg_t *sec_timer_cfg, sec_prot_cfg_t *sec_prot_cfg, sec_prot_keys_nw_info_t *sec_keys_nw_info)
int8_t ws_pae_supp_init(protocol_interface_info_entry_t *interface_ptr, const sec_prot_certs_t *certs, sec_cfg_t *sec_cfg, sec_prot_keys_nw_info_t *sec_keys_nw_info)
{
if (!interface_ptr) {
return -1;
@ -564,8 +598,7 @@ int8_t ws_pae_supp_init(protocol_interface_info_entry_t *interface_ptr, const se
pae_supp->nw_keys_used_cnt = 0;
pae_supp->initial_key_retry_cnt = DEFAULT_INITIAL_KEY_RETRY_COUNT;
pae_supp->sec_keys_nw_info = sec_keys_nw_info;
pae_supp->sec_timer_cfg = sec_timer_cfg;
pae_supp->sec_prot_cfg = sec_prot_cfg;
pae_supp->sec_cfg = sec_cfg;
pae_supp->auth_trickle_running = false;
pae_supp->auth_requested = false;
pae_supp->timer_running = false;
@ -587,7 +620,7 @@ int8_t ws_pae_supp_init(protocol_interface_info_entry_t *interface_ptr, const se
goto error;
}
if (kmp_service_cb_register(pae_supp->kmp_service, ws_pae_supp_kmp_incoming_ind, ws_pae_supp_kmp_tx_status_ind, ws_pae_supp_kmp_service_addr_get, ws_pae_supp_kmp_service_api_get) < 0) {
if (kmp_service_cb_register(pae_supp->kmp_service, ws_pae_supp_kmp_incoming_ind, ws_pae_supp_kmp_tx_status_ind, ws_pae_supp_kmp_service_addr_get, NULL, ws_pae_supp_kmp_service_api_get) < 0) {
goto error;
}
@ -896,13 +929,13 @@ static void ws_pae_supp_initial_trickle_timer_start(pae_supp_t *pae_supp)
* There are two retries. Minimum time that sequence takes before authentication failure
* is 22 minutes and maximum is 124 minutes.
*/
pae_supp->auth_trickle_params = pae_supp->sec_prot_cfg->initial_key_trickle_params;
pae_supp->initial_key_retry_timer = pae_supp->sec_prot_cfg->initial_key_retry_delay;
pae_supp->auth_trickle_params = pae_supp->sec_cfg->prot_cfg.initial_key_trickle_params;
pae_supp->initial_key_retry_timer = pae_supp->sec_cfg->prot_cfg.initial_key_retry_delay;
trickle_start(&pae_supp->auth_trickle_timer, &pae_supp->auth_trickle_params);
tr_info("Initial EAPOL-Key trickle I: [%i,%i] %i, t: %i", pae_supp->auth_trickle_params.Imin, pae_supp->auth_trickle_params.Imax, pae_supp->auth_trickle_timer.I, pae_supp->auth_trickle_timer.t);
pae_supp->auth_trickle_running = true;
pae_supp->initial_key_retry_cnt = pae_supp->sec_prot_cfg->initial_key_retry_cnt;
pae_supp->initial_key_retry_cnt = pae_supp->sec_cfg->prot_cfg.initial_key_retry_cnt;
}
static void ws_pae_supp_initial_last_interval_trickle_timer_start(pae_supp_t *pae_supp)
@ -920,8 +953,8 @@ static void ws_pae_supp_initial_last_interval_trickle_timer_start(pae_supp_t *pa
static void ws_pae_supp_initial_key_update_trickle_timer_start(pae_supp_t *pae_supp, uint8_t timer_expirations)
{
// Starts trickle for the key update
pae_supp->auth_trickle_params.Imin = pae_supp->sec_timer_cfg->gtk_request_imin;
pae_supp->auth_trickle_params.Imax = pae_supp->sec_timer_cfg->gtk_request_imax;
pae_supp->auth_trickle_params.Imin = pae_supp->sec_cfg->timer_cfg.gtk_request_imin;
pae_supp->auth_trickle_params.Imax = pae_supp->sec_cfg->timer_cfg.gtk_request_imax;
pae_supp->auth_trickle_params.k = 0;
pae_supp->auth_trickle_params.TimerExpirations = timer_expirations;
@ -1078,8 +1111,12 @@ static kmp_api_t *ws_pae_supp_kmp_service_api_get(kmp_service_t *service, kmp_ap
return ws_pae_lib_kmp_list_type_get(&pae_supp->entry.kmp_list, type);
}
static kmp_api_t *ws_pae_supp_kmp_incoming_ind(kmp_service_t *service, kmp_type_e type, const kmp_addr_t *addr)
static kmp_api_t *ws_pae_supp_kmp_incoming_ind(kmp_service_t *service, uint8_t instance_id, kmp_type_e type, const kmp_addr_t *addr, const void *pdu, uint16_t size)
{
(void) instance_id;
(void) pdu;
(void) size;
// Should be MKA, 4WH or GKH and never initial EAPOL-key for supplicant
if (type > IEEE_802_1X_INITIAL_KEY) {
return NULL;
@ -1138,7 +1175,7 @@ static kmp_api_t *ws_pae_supp_kmp_incoming_ind(kmp_service_t *service, kmp_type_
static kmp_api_t *ws_pae_supp_kmp_create_and_start(kmp_service_t *service, kmp_type_e type, pae_supp_t *pae_supp)
{
// Create new instance
kmp_api_t *kmp = kmp_api_create(service, type, pae_supp->sec_prot_cfg, pae_supp->sec_timer_cfg);
kmp_api_t *kmp = kmp_api_create(service, type, 0, pae_supp->sec_cfg);
if (!kmp) {
return NULL;
}

View File

@ -38,15 +38,14 @@
*
* \param interface_ptr interface
* \param cert_chain certificate chain
* \param sec_timer_cfg timer configuration
* \param sec_prot_cfg protocol configuration
* \param sec_cfg security configuration
* \param sec_keys_nw_info security keys network information
*
* \return < 0 failure
* \return >= 0 success
*
*/
int8_t ws_pae_supp_init(protocol_interface_info_entry_t *interface_ptr, const sec_prot_certs_t *certs, sec_timer_cfg_t *sec_timer_cfg, sec_prot_cfg_t *sec_prot_cfg, sec_prot_keys_nw_info_t *sec_keys_nw_info);
int8_t ws_pae_supp_init(protocol_interface_info_entry_t *interface_ptr, const sec_prot_certs_t *certs, sec_cfg_t *sec_cfg, sec_prot_keys_nw_info_t *sec_keys_nw_info);
/**
* ws_pae_supp_delete deletes PAE supplicant
@ -173,6 +172,20 @@ int8_t ws_pae_supp_gtks_set(protocol_interface_info_entry_t *interface_ptr, sec_
*/
int8_t ws_pae_supp_eapol_target_remove(protocol_interface_info_entry_t *interface_ptr);
/**
* ws_pae_auth_nw_info_set set network information
*
* \param interface_ptr interface
* \param pan_id PAD ID
* \param network_name network name
* \param updated data has been updated
*
* \return < 0 failure
* \return >= 0 success
*
*/
int8_t ws_pae_supp_nw_info_set(protocol_interface_info_entry_t *interface_ptr, uint16_t pan_id, char *network_name, bool updated);
/**
* ws_pae_supp_nw_key_index_set network send key index set callback
*

View File

@ -144,9 +144,9 @@ static void ws_pae_timers_calculate(sec_timer_cfg_t *timer_settings)
}
}
bool ws_pae_timers_gtk_new_install_required(sec_timer_cfg_t *timer_settings, uint32_t seconds)
bool ws_pae_timers_gtk_new_install_required(sec_cfg_t *sec_cfg, uint32_t seconds)
{
uint32_t gtk_new_install_req_seconds = timer_settings->gtk_expire_offset - timer_settings->gtk_new_install_req * timer_settings->gtk_expire_offset / 100;
uint32_t gtk_new_install_req_seconds = sec_cfg->timer_cfg.gtk_expire_offset - sec_cfg->timer_cfg.gtk_new_install_req * sec_cfg->timer_cfg.gtk_expire_offset / 100;
if (seconds < gtk_new_install_req_seconds) {
return true;
@ -155,9 +155,9 @@ bool ws_pae_timers_gtk_new_install_required(sec_timer_cfg_t *timer_settings, uin
}
}
bool ws_pae_timers_gtk_new_activation_time(sec_timer_cfg_t *timer_settings, uint32_t seconds)
bool ws_pae_timers_gtk_new_activation_time(sec_cfg_t *sec_cfg, uint32_t seconds)
{
uint32_t gtk_gtk_new_activation_time_seconds = timer_settings->gtk_expire_offset / timer_settings->gtk_new_act_time;
uint32_t gtk_gtk_new_activation_time_seconds = sec_cfg->timer_cfg.gtk_expire_offset / sec_cfg->timer_cfg.gtk_new_act_time;
if (seconds < gtk_gtk_new_activation_time_seconds) {
return true;
@ -166,9 +166,9 @@ bool ws_pae_timers_gtk_new_activation_time(sec_timer_cfg_t *timer_settings, uint
}
}
uint32_t ws_pae_timers_gtk_revocation_lifetime_get(sec_timer_cfg_t *timer_settings)
uint32_t ws_pae_timers_gtk_revocation_lifetime_get(sec_cfg_t *sec_cfg)
{
return timer_settings->gtk_expire_offset / timer_settings->revocat_lifetime_reduct;
return sec_cfg->timer_cfg.gtk_expire_offset / sec_cfg->timer_cfg.revocat_lifetime_reduct;
}
#endif /* HAVE_WS */

View File

@ -53,35 +53,35 @@ void ws_pae_timers_gtk_time_settings_set(sec_timer_cfg_t *timer_settings, uint8_
/**
* ws_pae_timers_gtk_new_install_required GTK new install required check
*
* \param timer_settings timer settings
* \param sec_cfg security configuration
* \param seconds elapsed seconds
*
* \return true new GTK install required expired
* \return false GTK install not required
*
*/
bool ws_pae_timers_gtk_new_install_required(sec_timer_cfg_t *timer_settings, uint32_t seconds);
bool ws_pae_timers_gtk_new_install_required(sec_cfg_t *sec_cfg, uint32_t seconds);
/**
* ws_pae_timers_gtk_new_activation_time GTK new activation time
*
* \param timer_settings timer settings
* \param sec_cfg security configuration
* \param seconds elapsed seconds
*
* \return true GTK new activation time expired
* \return false GTK new activation time not expired
*
*/
bool ws_pae_timers_gtk_new_activation_time(sec_timer_cfg_t *timer_settings, uint32_t seconds);
bool ws_pae_timers_gtk_new_activation_time(sec_cfg_t *sec_cfg, uint32_t seconds);
/**
* ws_pae_timers_gtk_revocation_lifetime_get GTK revocation lifetime get
*
* \param timer_settings timer settings
* \param sec_cfg security configuration
*
* \return GTK revocation lifetime
*
*/
uint32_t ws_pae_timers_gtk_revocation_lifetime_get(sec_timer_cfg_t *timer_settings);
uint32_t ws_pae_timers_gtk_revocation_lifetime_get(sec_cfg_t *sec_cfg);
#endif /* WS_PAE_TIMERS_H_ */

View File

@ -18,12 +18,13 @@
#include "nsconfig.h"
#include <string.h>
#include <ns_list.h>
#include <nsdynmemLIB.h>
#include <net_ws_test.h>
#include "ns_list.h"
#include "nsdynmemLIB.h"
#include "net_ws_test.h"
#include "fhss_config.h"
#include "ws_management_api.h"
#include "mac_api.h"
#include "6LoWPAN/MAC/mac_helper.h"
#include "NWK_INTERFACE/Include/protocol.h"
#include "6LoWPAN/MAC/mac_helper.h"
#include "6LoWPAN/ws/ws_config.h"
@ -150,4 +151,17 @@ int ws_test_next_gtk_set(int8_t interface_id, uint8_t *gtk[4])
return ws_pae_controller_next_gtk_update(interface_id, gtk);
}
int ws_test_6lowpan_fragmentation_mtu_size_set(int8_t interface_id, uint16_t mtu_size)
{
protocol_interface_info_entry_t *cur;
cur = protocol_stack_interface_info_get_by_id(interface_id);
if (!cur || !ws_info(cur)) {
return -1;
}
test_6lowpan_fragmentation_mtu_size_override = mtu_size;
return 0;
}
#endif // HAVE_WS

View File

@ -859,6 +859,40 @@ static buffer_t *icmpv6_ra_handler(buffer_t *buf)
} else {
ipv6_route_delete(prefix_ptr, prefix_length, cur->id, buf->src_sa.address, ROUTE_RADV);
}
} else if (type == ICMPV6_OPT_DNS_SEARCH_LIST) {
if (length < 8) {
tr_warn("Invalid RA DNS search list opt corrupt");
goto next_option; // invalid not accepted
}
uint32_t dns_lifetime = common_read_32_bit(dptr + 2); // 2 x reserved
uint8_t *dns_search_list = dptr + 6;
uint8_t dns_search_list_len = length - 8; // Length includes type and length
tr_info("DNS Search List: %s Lifetime: %lu", trace_array(dns_search_list, dns_search_list_len), (unsigned long) dns_lifetime);
// TODO Add DNS server to DNS information storage.
// dns_search_list_storage(cur, buf->src_sa.address, dns_search_list, dns_search_list_len, dns_lifetime);
(void)dns_search_list;
(void)dns_search_list_len;
(void)dns_lifetime;
} else if (type == ICMPV6_OPT_RECURSIVE_DNS_SERVER) {
uint8_t dns_length = length / 8;
if (dns_length < 3) {
tr_warn("Invalid RA DNS server opt corrupt");
goto next_option; // invalid not accepted
}
uint8_t dns_count = (dns_length - 1) / 2;
uint32_t dns_lifetime = common_read_32_bit(dptr + 2); // 2 x reserved
for (int n = 0; n < dns_count; n++) {
uint8_t *dns_srv_addr = dptr + 6 + n * 16;
tr_info("DNS Server: %s Lifetime: %lu", trace_ipv6(dns_srv_addr), (unsigned long) dns_lifetime);
// TODO Add DNS server to DNS information storage.
// dns_server_storage(cur, buf->src_sa.address, dns_srv_addr, dns_lifetime);
(void)dns_srv_addr;
(void)dns_lifetime;
}
} else if (type == ICMPV6_OPT_6LOWPAN_CONTEXT) {
nd_ra_process_lowpan_context_option(cur, dptr - 2);
}

View File

@ -77,6 +77,8 @@
#define ICMPV6_OPT_REDIRECTED_HDR 4
#define ICMPV6_OPT_MTU 5
#define ICMPV6_OPT_ROUTE_INFO 24
#define ICMPV6_OPT_RECURSIVE_DNS_SERVER 25
#define ICMPV6_OPT_DNS_SEARCH_LIST 31
#define ICMPV6_OPT_ADDR_REGISTRATION 33
#define ICMPV6_OPT_6LOWPAN_CONTEXT 34
#define ICMPV6_OPT_AUTHORITATIVE_BORDER_RTR 35

View File

@ -142,6 +142,7 @@ extern const uint8_t ADDR_ALL_MPL_FORWARDERS[16]; // ff03::fc
extern const uint8_t ADDR_ALL_DHCP_RELAY_AGENTS_AND_SERVERS[16]; // ff02::1:2
extern const uint8_t ADDR_LOOPBACK[16]; // ::1
extern const uint8_t ADDR_UNSPECIFIED[16]; // ::
extern const uint8_t ADDR_6TO4[16]; // 2002::
/* Don't bother having another 8 zero bytes for this - reuse ADDR_UNSPECIFIED */
#define ADDR_EUI64_ZERO ADDR_UNSPECIFIED

View File

@ -124,6 +124,7 @@ typedef struct buffer_options {
bool need_predecessor: 1; /*!< Used as an indicator that predecessor address needed */
bool multicast_loop: 1; /*!< We want loopback if we're a group member (TX), or this IS the loopback if RX */
bool mpl_permitted: 1; /*!< MPL will be used if enabled on interface and scope >=3 */
bool edfe_mode: 1; /*!< Use Extended Directed Frame Exchange pattern in MAC layer */
#ifndef NO_IP_FRAGMENT_TX
bool ipv6_dontfrag: 1; /*!< Don't IPv6 fragment (RFC 3542) */
#endif

View File

@ -177,6 +177,7 @@ typedef struct inet_pcb_s {
bool recvpktinfo: 1;
bool recvhoplimit: 1;
bool recvtclass: 1;
bool edfe_mode: 1;
int_least24_t flow_label;
NS_LIST_HEAD(inet_group_t, link) mc_groups;
} inet_pcb_t;

View File

@ -81,6 +81,7 @@ const uint8_t ADDR_ALL_DHCP_RELAY_AGENTS_AND_SERVERS[16] = { 0xff, 0x02, [13] =
const uint8_t ADDR_IPV4_MAPPED_PREFIX[12] = { [10] = 0xff, 0xff };
const uint8_t ADDR_LOOPBACK[16] = { [15] = 1 };
const uint8_t ADDR_UNSPECIFIED[16] = { 0 }; /* Note a few bits of code check for pointer equality with ADDR_UNSPECIFIED */
const uint8_t ADDR_6TO4[16] = { 0x20, 0x02 }; /*Can be used as global address*/
#define ADDR_IPV4_COMPATIBLE ADDR_LOOPBACK /* First 96 bits match...*/
#define ADDR_MULTICAST_LINK_PREFIX ADDR_LINK_LOCAL_ALL_NODES /* ff02::xx */

View File

@ -401,6 +401,8 @@ inet_pcb_t *socket_inet_pcb_allocate(void)
inet_pcb->recvhoplimit = false;
inet_pcb->recvpktinfo = false;
inet_pcb->recvtclass = false;
inet_pcb->edfe_mode = false;
inet_pcb->link_layer_security = -1;
#ifndef NO_IPV6_PMTUD
inet_pcb->use_min_mtu = -1;
@ -1134,6 +1136,7 @@ int16_t socket_buffer_sendmsg(int8_t sid, buffer_t *buf, const struct ns_msghdr
buf->options.ipv6_use_min_mtu = inet_pcb->use_min_mtu;
buf->options.ipv6_dontfrag = inet_pcb->dontfrag;
buf->options.multicast_loop = inet_pcb->multicast_loop;
buf->options.edfe_mode = inet_pcb->edfe_mode;
/* Set default remote address from PCB */
if (inet_pcb->remote_port != 0 && !addr_ipv6_equal(inet_pcb->remote_address, ns_in6addr_any)) {

View File

@ -140,3 +140,11 @@ int8_t mac_cca_threshold_update(protocol_interface_rf_mac_setup_s *rf_ptr, uint8
tr_debug("Channel %u CCA threshold to %i", channel, rf_ptr->cca_threshold->ch_thresholds[channel]);
return 0;
}
mac_cca_threshold_s *mac_get_cca_threshold_table(protocol_interface_rf_mac_setup_s *rf_ptr)
{
if (!rf_ptr->cca_threshold) {
return NULL;
}
return rf_ptr->cca_threshold;
}

View File

@ -49,6 +49,7 @@ int8_t mac_cca_thr_deinit(protocol_interface_rf_mac_setup_s *rf_ptr);
/**
* @brief Read CCA threshold of specific channel.
* @param rf_ptr Pointer to MAC instance.
* @param channel Channel.
* @return CCA threshold (dBm), CCA_FAILED_DBM Feature not enabled.
*/
@ -56,10 +57,18 @@ int8_t mac_cca_thr_get_dbm(protocol_interface_rf_mac_setup_s *rf_ptr, uint8_t ch
/**
* @brief Update CCA threshold of specific channel.
* @param rf_ptr Pointer to MAC instance.
* @param channel Channel.
* @param dbm CCA threshold (dBm).
* @return 0 Updated, negative Already using this value.
*/
int8_t mac_cca_threshold_update(protocol_interface_rf_mac_setup_s *rf_ptr, uint8_t channel, int8_t dbm);
/**
* @brief Get pointer to CCA threshold table.
* @param rf_ptr Pointer to MAC instance.
* @return CCA threshold table.
*/
mac_cca_threshold_s *mac_get_cca_threshold_table(protocol_interface_rf_mac_setup_s *rf_ptr);
#endif /* MAC_CCA_THRESHOLD_H_ */

View File

@ -98,6 +98,8 @@ typedef struct mac_pre_build_frame {
bool asynch_request: 1;
bool message_builded: 1;
bool DSN_allocated: 1;
bool ExtendedFrameExchange: 1;
bool WaitResponse: 1;
unsigned security_mic_len: 5; //Max possible lengths 0, 4, 8, 16 bytes
unsigned priority: 2;
struct mac_pre_build_frame *next; //Pointer for queue purpose

View File

@ -147,6 +147,25 @@ typedef struct mac_mcps_data_conf_fail_s {
uint8_t status; /**< Status of the failing MSDU transmission */
} mac_mcps_data_conf_fail_t;
typedef enum mac_edfe_frame_state {
MAC_EDFE_FRAME_IDLE = 0,
MAC_EDFE_FRAME_CONNECTING,
MAC_EDFE_FRAME_CONNECTED,
MAC_EDFE_FRAME_TX_RESPONSE,
MAC_EDFE_FRAME_TX_FINAL_FRAME,
MAC_EDFE_FRAME_WAIT_DATA,
MAC_EDFE_FRAME_WAIT_RESPONSE
} mac_edfe_frame_state_e;
typedef struct mac_mcps_edfe_info_s {
mac_edfe_frame_state_e state;
uint8_t PeerAddr[8];
struct mac_pre_build_frame edfe_response_buffer;
} mac_mcps_edfe_frame_info_t;
typedef struct protocol_interface_rf_mac_setup {
int8_t mac_interface_id;
bool macUpState: 1;
@ -154,7 +173,10 @@ typedef struct protocol_interface_rf_mac_setup {
bool beaconSrcAddressModeLong: 1; //This force beacon src to mac64 otherwise shortAdressValid will define type
bool secFrameCounterPerKey: 1;
bool mac_extension_enabled: 1;
bool mac_edfe_enabled: 1; // Indicate when EFDE exchange is possible
bool mac_ack_tx_active: 1;
bool mac_edfe_tx_active: 1;
bool mac_edfe_response_tx_active: 1;
bool mac_frame_pending: 1;
/* MAC Capability Information */
bool macCapRxOnIdle: 1;
@ -279,6 +301,7 @@ typedef struct protocol_interface_rf_mac_setup {
struct mac_cca_threshold *cca_threshold;
//beacon_join_priority_tx_cb *beacon_join_priority_tx_cb_ptr;
struct mac_statistics_s *mac_statistics;
mac_mcps_edfe_frame_info_t *mac_edfe_info;
/* FHSS API*/
struct fhss_api *fhss_api;
} protocol_interface_rf_mac_setup_s;

View File

@ -87,9 +87,16 @@ int mac_set_channel(const fhss_api_t *fhss_api, uint8_t channel_number)
if (!mac_setup) {
return -1;
}
if (mac_setup->mac_ack_tx_active || (mac_setup->active_pd_data_request && (mac_setup->active_pd_data_request->asynch_request || mac_setup->timer_mac_event == MAC_TIMER_ACK))) {
return -1;
}
//EDFE packet check if active tx or frame change session open for example wait data
if (mac_setup->mac_edfe_enabled && (mac_setup->mac_edfe_tx_active || mac_setup->mac_edfe_info->state > MAC_EDFE_FRAME_CONNECTING)) {
return -1;
}
return mac_mlme_rf_channel_change(mac_setup, channel_number);
}

View File

@ -197,6 +197,18 @@ void mcps_sap_data_req_handler_ext(protocol_interface_rf_mac_setup_s *rf_mac_set
uint8_t status = MLME_SUCCESS;
mac_pre_build_frame_t *buffer = NULL;
if (rf_mac_setup->mac_edfe_enabled && data_req->ExtendedFrameExchange) {
if (rf_mac_setup->mac_edfe_info->state != MAC_EDFE_FRAME_IDLE) {
tr_debug("Accept only 1 active Efde Data request push");
status = MLME_UNSUPPORTED_LEGACY;
goto verify_status;
}
if (data_req->DstAddrMode != MAC_ADDR_MODE_64_BIT) {
status = MLME_INVALID_PARAMETER;
goto verify_status;
}
}
if (!rf_mac_setup->mac_security_enabled) {
if (data_req->Key.SecurityLevel) {
@ -254,7 +266,13 @@ void mcps_sap_data_req_handler_ext(protocol_interface_rf_mac_setup_s *rf_mac_set
buffer->upper_layer_request = true;
buffer->fcf_dsn.frametype = FC_DATA_FRAME;
buffer->fcf_dsn.ackRequested = data_req->TxAckReq;
buffer->ExtendedFrameExchange = data_req->ExtendedFrameExchange;
buffer->WaitResponse = data_req->TxAckReq;
if (data_req->ExtendedFrameExchange) {
buffer->fcf_dsn.ackRequested = false;
} else {
buffer->fcf_dsn.ackRequested = data_req->TxAckReq;
}
buffer->mac_header_length_with_security = 3;
mac_header_security_parameter_set(&buffer->aux_header, &data_req->Key);
@ -336,6 +354,7 @@ void mcps_sap_data_req_handler_ext(protocol_interface_rf_mac_setup_s *rf_mac_set
buffer->mac_payload = data_req->msdu;
buffer->mac_payload_length = data_req->msduLength;
//check that header + payload length is not bigger than MAC MTU
if (data_req->InDirectTx) {
mac_indirect_queue_write(rf_mac_setup, buffer);
} else {
@ -550,8 +569,14 @@ static uint8_t mac_data_interface_decrypt_packet(mac_pre_parsed_frame_t *b, mlme
//READ SRC Address
uint16_t SrcPANId = mac_header_get_src_panid(&b->fcf_dsn, mac_header_message_start_pointer(b), rf_mac_setup->pan_id);
mac_header_get_src_address(&b->fcf_dsn, mac_header_message_start_pointer(b), neighbour_validation.address);
neighbour_validation.addr_type = b->fcf_dsn.SrcAddrMode;
if (b->fcf_dsn.SrcAddrMode == MAC_ADDR_MODE_NONE && rf_mac_setup->mac_edfe_enabled && rf_mac_setup->mac_edfe_info->state > MAC_EDFE_FRAME_CONNECTING) {
memcpy(neighbour_validation.address, rf_mac_setup->mac_edfe_info->PeerAddr, 8);
neighbour_validation.addr_type = MAC_ADDR_MODE_64_BIT;
} else {
mac_header_get_src_address(&b->fcf_dsn, mac_header_message_start_pointer(b), neighbour_validation.address);
neighbour_validation.addr_type = b->fcf_dsn.SrcAddrMode;
}
neighbour_validation.keyId = security_params->KeyIndex;
// Get A Key description
@ -708,6 +733,7 @@ static int8_t mac_data_sap_rx_handler(mac_pre_parsed_frame_t *buf, protocol_inte
memset(data_ind, 0, sizeof(mcps_data_ind_t));
//Parse data
data_ind->DSN = buf->fcf_dsn.DSN;
data_ind->DSN_suppressed = buf->fcf_dsn.sequenceNumberSuppress;
data_ind->DstAddrMode = buf->fcf_dsn.DstAddrMode;
mac_header_get_dst_address(&buf->fcf_dsn, mac_header_message_start_pointer(buf), data_ind->DstAddr);
data_ind->SrcAddrMode = buf->fcf_dsn.SrcAddrMode;
@ -722,6 +748,10 @@ static int8_t mac_data_sap_rx_handler(mac_pre_parsed_frame_t *buf, protocol_inte
data_ind->timestamp = buf->timestamp;
/* Parse security part */
mac_header_security_components_read(buf, &data_ind->Key);
if (data_ind->SrcAddrMode == MAC_ADDR_MODE_NONE && rf_mac_setup->mac_edfe_enabled && rf_mac_setup->mac_edfe_info->state > MAC_EDFE_FRAME_CONNECTING) {
memcpy(data_ind->SrcAddr, rf_mac_setup->mac_edfe_info->PeerAddr, 8);
data_ind->SrcAddrMode = MAC_ADDR_MODE_64_BIT;
}
buf->neigh_info = mac_sec_mib_device_description_get(rf_mac_setup, data_ind->SrcAddr, data_ind->SrcAddrMode, data_ind->SrcPANId);
if (buf->fcf_dsn.securityEnabled) {
@ -795,7 +825,7 @@ static void mac_lib_res_no_data_to_req(mac_pre_parsed_frame_t *buffer, protocol_
buf->fcf_dsn.securityEnabled = buffer->fcf_dsn.securityEnabled;
buf->fcf_dsn.intraPan = true;
buf->fcf_dsn.ackRequested = true;
buf->WaitResponse = buf->fcf_dsn.ackRequested = true;
buf->mac_header_length_with_security = 3;
//Check PanID presents at header
buf->fcf_dsn.DstPanPresents = mac_dst_panid_present(&buf->fcf_dsn);
@ -1061,8 +1091,17 @@ void mac_mcps_trig_buffer_from_queue(protocol_interface_rf_mac_setup_s *rf_mac_s
buffer = mcps_sap_pd_req_queue_read(rf_mac_setup, is_bc_queue, false);
if (buffer) {
//Here
if (buffer->ExtendedFrameExchange) {
//Update here state and store peer
memcpy(rf_mac_setup->mac_edfe_info->PeerAddr, buffer->DstAddr, 8);
rf_mac_setup->mac_edfe_info->state = MAC_EDFE_FRAME_CONNECTING;
}
rf_mac_setup->active_pd_data_request = buffer;
if (mcps_pd_data_request(rf_mac_setup, buffer) != 0) {
if (buffer->ExtendedFrameExchange) {
rf_mac_setup->mac_edfe_info->state = MAC_EDFE_FRAME_IDLE;
}
rf_mac_setup->active_pd_data_request = NULL;
mac_mcps_asynch_finish(rf_mac_setup, buffer);
mcps_data_confirm_handle(rf_mac_setup, buffer, NULL);
@ -1079,15 +1118,24 @@ static int8_t mac_ack_sap_rx_handler(mac_pre_parsed_frame_t *buf, protocol_inter
{
//allocate Data ind primitiv and parse packet to that
mlme_security_t key;
uint8_t srcAddressMode;
uint8_t SrcAddr[8]; /**< Source address */
memset(SrcAddr, 0, 8);
memset(&key, 0, sizeof(mlme_security_t));
mac_header_get_src_address(&buf->fcf_dsn, mac_header_message_start_pointer(buf), SrcAddr);
srcAddressMode = buf->fcf_dsn.SrcAddrMode;
if (buf->fcf_dsn.SrcAddrMode) {
mac_header_get_src_address(&buf->fcf_dsn, mac_header_message_start_pointer(buf), SrcAddr);
} else {
if (rf_mac_setup->mac_edfe_enabled && (buf->fcf_dsn.frametype == FC_DATA_FRAME && !buf->fcf_dsn.ackRequested)) {
memcpy(SrcAddr, rf_mac_setup->mac_edfe_info->PeerAddr, 8);
srcAddressMode = MAC_ADDR_MODE_64_BIT;
}
}
uint16_t pan_id = mac_header_get_src_panid(&buf->fcf_dsn, mac_header_message_start_pointer(buf), rf_mac_setup->pan_id);
/* Parse security part */
mac_header_security_components_read(buf, &key);
buf->neigh_info = mac_sec_mib_device_description_get(rf_mac_setup, SrcAddr, buf->fcf_dsn.SrcAddrMode, pan_id);
buf->neigh_info = mac_sec_mib_device_description_get(rf_mac_setup, SrcAddr, srcAddressMode, pan_id);
if (buf->fcf_dsn.securityEnabled) {
uint8_t status = mac_data_interface_decrypt_packet(buf, &key);
if (status != MLME_SUCCESS) {
@ -1426,6 +1474,22 @@ static void mac_data_interface_internal_tx_confirm_handle(protocol_interface_rf_
}
static bool mcps_buffer_edfe_data_failure(protocol_interface_rf_mac_setup_s *rf_ptr, mac_pre_build_frame_t *buffer)
{
if (!rf_ptr->mac_edfe_enabled || !buffer->ExtendedFrameExchange) {
return false;
}
if (rf_ptr->mac_edfe_info->state > MAC_EDFE_FRAME_CONNECTING) {
//Set to idle
tr_debug("Edfe Data send fail");
return true;
}
return false;
}
static void mcps_data_confirm_handle(protocol_interface_rf_mac_setup_s *rf_ptr, mac_pre_build_frame_t *buffer, mac_pre_parsed_frame_t *ack_buf)
{
@ -1434,7 +1498,7 @@ static void mcps_data_confirm_handle(protocol_interface_rf_mac_setup_s *rf_ptr,
mcps_data_conf_t confirm;
if (rf_ptr->fhss_api && !buffer->asynch_request) {
// FHSS checks if this failed buffer needs to be pushed back to TX queue and retransmitted
if ((rf_ptr->mac_tx_result == MAC_TX_FAIL) || (rf_ptr->mac_tx_result == MAC_CCA_FAIL)) {
if (!mcps_buffer_edfe_data_failure(rf_ptr, buffer) && ((rf_ptr->mac_tx_result == MAC_TX_FAIL) || (rf_ptr->mac_tx_result == MAC_CCA_FAIL))) {
if (rf_ptr->fhss_api->data_tx_fail(rf_ptr->fhss_api, buffer->msduHandle, mac_convert_frame_type_to_fhss(buffer->fcf_dsn.frametype), rf_ptr->mac_tx_start_channel) == true) {
if (rf_ptr->mac_tx_result == MAC_TX_FAIL) {
@ -1447,6 +1511,11 @@ static void mcps_data_confirm_handle(protocol_interface_rf_mac_setup_s *rf_ptr,
return;
}
}
if (rf_ptr->mac_edfe_enabled && buffer->ExtendedFrameExchange) {
rf_ptr->mac_edfe_info->state = MAC_EDFE_FRAME_IDLE;
}
}
confirm.cca_retries = rf_ptr->mac_tx_status.cca_cnt + buffer->fhss_cca_retry_count;
confirm.tx_retries = rf_ptr->mac_tx_status.retry + buffer->fhss_retry_count;
@ -1622,7 +1691,11 @@ static int8_t mcps_generic_packet_build(protocol_interface_rf_mac_setup_s *rf_pt
tx_buf->len = frame_length;
uint8_t *mhr_start = ptr;
buffer->tx_time = mcps_generic_backoff_calc(rf_ptr);
if (buffer->ExtendedFrameExchange && buffer->fcf_dsn.SrcAddrMode == MAC_ADDR_MODE_NONE) {
buffer->tx_time = mac_mcps_sap_get_phy_timestamp(rf_ptr) + 300; //Send 300 us later
} else {
buffer->tx_time = mcps_generic_backoff_calc(rf_ptr);
}
ptr = mac_generic_packet_write(rf_ptr, ptr, buffer);
@ -1716,6 +1789,86 @@ int8_t mcps_generic_ack_data_request_init(protocol_interface_rf_mac_setup_s *rf_
return 0;
}
int8_t mcps_generic_edfe_frame_init(protocol_interface_rf_mac_setup_s *rf_ptr, const mac_fcf_sequence_t *fcf, const uint8_t *data_ptr, const mcps_edfe_response_t *response)
{
//Data Here
mac_pre_build_frame_t *buffer;
if (response->wait_response) {
buffer = rf_ptr->active_pd_data_request;
buffer->message_builded = false;
} else {
buffer = &rf_ptr->enhanced_ack_buffer;
memset(buffer, 0, sizeof(mac_pre_build_frame_t));
buffer->fcf_dsn.frametype = FC_DATA_FRAME;
buffer->fcf_dsn.frameVersion = fcf->frameVersion;
buffer->fcf_dsn.DstPanPresents = fcf->DstPanPresents;
buffer->fcf_dsn.DstAddrMode = response->DstAddrMode;
buffer->DstPANId = mac_header_get_src_panid(fcf, data_ptr, rf_ptr->pan_id);
buffer->SrcPANId = mac_header_get_dst_panid(fcf, data_ptr, rf_ptr->pan_id);
memcpy(buffer->DstAddr, response->Address, 8);
}
buffer->fcf_dsn.intraPan = response->PanIdSuppressed;
buffer->fcf_dsn.SrcAddrMode = response->SrcAddrMode;
buffer->fcf_dsn.SrcPanPresents = response->SrcAddrMode;
buffer->fcf_dsn.framePending = false;
buffer->fcf_dsn.sequenceNumberSuppress = fcf->sequenceNumberSuppress;
buffer->WaitResponse = response->wait_response;
buffer->ExtendedFrameExchange = true;
if (buffer->fcf_dsn.sequenceNumberSuppress) {
buffer->mac_header_length_with_security = 2;
} else {
buffer->mac_header_length_with_security = 3;
}
buffer->mac_header_length_with_security += mac_header_address_length(&buffer->fcf_dsn);
//Security
buffer->fcf_dsn.securityEnabled = fcf->securityEnabled;
if (buffer->fcf_dsn.securityEnabled) {
//Read Security AUX headers
const uint8_t *ptr = data_ptr;
ptr += mac_header_off_set_to_aux_header(fcf);
//Start parsing AUX header
mlme_security_t aux_parse;
mac_header_security_aux_header_parse(ptr, &aux_parse);
buffer->aux_header.KeyIdMode = aux_parse.KeyIdMode;
buffer->aux_header.KeyIndex = aux_parse.KeyIndex;
buffer->aux_header.securityLevel = aux_parse.SecurityLevel;
memcpy(buffer->aux_header.Keysource, aux_parse.Keysource, 8);
buffer->security_mic_len = mac_security_mic_length_get(buffer->aux_header.securityLevel);
buffer->fcf_dsn.frameVersion = MAC_FRAME_VERSION_2006;
buffer->mac_header_length_with_security += mac_header_security_aux_header_length(buffer->aux_header.securityLevel, buffer->aux_header.KeyIdMode);
}
uint16_t ie_header_length = 0;
uint16_t ie_payload_length = 0;
if (!mac_ie_vector_length_validate(response->ie_response.headerIeVectorList, response->ie_response.headerIovLength, &ie_header_length)) {
return -1;
}
if (!mac_ie_vector_length_validate(response->ie_response.payloadIeVectorList, response->ie_response.payloadIovLength, &ie_payload_length)) {
return -1;
}
buffer->ie_elements.headerIeVectorList = response->ie_response.headerIeVectorList;
buffer->ie_elements.headerIovLength = response->ie_response.headerIovLength;
buffer->ie_elements.payloadIeVectorList = response->ie_response.payloadIeVectorList;
buffer->ie_elements.payloadIovLength = response->ie_response.payloadIovLength;
buffer->headerIeLength = ie_header_length;
buffer->payloadsIeLength = ie_payload_length;
buffer->mac_payload = NULL;
buffer->mac_payload_length = 0;
//This will prepare MHR length with Header IE
mac_header_information_elements_preparation(buffer);
return 0;
}
int8_t mcps_generic_ack_build(protocol_interface_rf_mac_setup_s *rf_ptr, bool init_build)
{
@ -1854,8 +2007,11 @@ static int8_t mcps_generic_packet_rebuild(protocol_interface_rf_mac_setup_s *rf_
tx_buf->len = frame_length;
uint8_t *mhr_start = ptr;
buffer->tx_time = mcps_generic_backoff_calc(rf_ptr);
if (buffer->ExtendedFrameExchange && buffer->fcf_dsn.SrcAddrMode == MAC_ADDR_MODE_NONE) {
buffer->tx_time = mac_mcps_sap_get_phy_timestamp(rf_ptr) + 300; //Send 300 us later
} else {
buffer->tx_time = mcps_generic_backoff_calc(rf_ptr);
}
ptr = mac_generic_packet_write(rf_ptr, ptr, buffer);
@ -1884,15 +2040,39 @@ static int8_t mcps_pd_data_cca_trig(protocol_interface_rf_mac_setup_s *rf_ptr, m
cca_enabled = false;
rf_ptr->mac_ack_tx_active = true;
} else {
if (rf_ptr->mac_ack_tx_active) {
mac_csma_backoff_start(rf_ptr);
platform_exit_critical();
return -1;
if (buffer->ExtendedFrameExchange) {
if (buffer->fcf_dsn.SrcAddrMode) {
cca_enabled = true;
} else {
//Response
if (!buffer->WaitResponse) {
//Response
if (rf_ptr->mac_ack_tx_active) {
mac_csma_backoff_start(rf_ptr);
platform_exit_critical();
return -1;
}
rf_ptr->mac_edfe_response_tx_active = true;
} else {
rf_ptr->mac_edfe_response_tx_active = false;
}
cca_enabled = false;
rf_ptr->mac_edfe_tx_active = true;
}
} else {
if (rf_ptr->mac_ack_tx_active) {
mac_csma_backoff_start(rf_ptr);
platform_exit_critical();
return -1;
}
cca_enabled = true;
}
cca_enabled = true;
}
// Use double CCA check with FHSS for data packets only
if (rf_ptr->fhss_api && !rf_ptr->mac_ack_tx_active && !rf_ptr->active_pd_data_request->asynch_request) {
if (rf_ptr->fhss_api && !rf_ptr->mac_ack_tx_active && !rf_ptr->mac_edfe_tx_active && !rf_ptr->active_pd_data_request->asynch_request) {
if ((buffer->tx_time - (rf_ptr->multi_cca_interval * (rf_ptr->number_of_csma_ca_periods - 1))) > mac_mcps_sap_get_phy_timestamp(rf_ptr)) {
buffer->csma_periods_left = rf_ptr->number_of_csma_ca_periods - 1;
buffer->tx_time -= (rf_ptr->multi_cca_interval * (rf_ptr->number_of_csma_ca_periods - 1));
@ -1900,10 +2080,13 @@ static int8_t mcps_pd_data_cca_trig(protocol_interface_rf_mac_setup_s *rf_ptr, m
}
mac_pd_sap_set_phy_tx_time(rf_ptr, buffer->tx_time, cca_enabled);
if (mac_plme_cca_req(rf_ptr) != 0) {
if (buffer->fcf_dsn.frametype == MAC_FRAME_ACK) {
if (buffer->fcf_dsn.frametype == MAC_FRAME_ACK || (buffer->ExtendedFrameExchange && rf_ptr->mac_edfe_response_tx_active)) {
//ACK or EFDE Response
rf_ptr->mac_ack_tx_active = false;
// For Ack, stop the active TX process
rf_ptr->macTxProcessActive = false;
rf_ptr->mac_edfe_tx_active = false;
rf_ptr->mac_edfe_response_tx_active = false;
// If MAC had TX process active before Ack transmission,
// the TX process has to be restarted in case the Ack transmission failed.
if (rf_ptr->active_pd_data_request) {
@ -1925,7 +2108,6 @@ static int8_t mcps_pd_data_request(protocol_interface_rf_mac_setup_s *rf_ptr, ma
{
rf_ptr->macTxRequestAck = false;
memset(&(rf_ptr->mac_tx_status), 0, sizeof(mac_tx_status_t));
rf_ptr->mac_cca_retry = 0;
rf_ptr->mac_tx_retry = 0;
@ -1934,8 +2116,8 @@ static int8_t mcps_pd_data_request(protocol_interface_rf_mac_setup_s *rf_ptr, ma
if (mcps_generic_packet_build(rf_ptr, buffer) != 0) {
return -1;
}
rf_ptr->macTxRequestAck = buffer->fcf_dsn.ackRequested;
if (!rf_ptr->mac_ack_tx_active) {
rf_ptr->macTxRequestAck = buffer->WaitResponse;
if (!rf_ptr->mac_ack_tx_active && !rf_ptr->mac_edfe_tx_active) {
return mcps_pd_data_cca_trig(rf_ptr, buffer);
} else {
return 0;
@ -1943,6 +2125,24 @@ static int8_t mcps_pd_data_request(protocol_interface_rf_mac_setup_s *rf_ptr, ma
}
int8_t mcps_edfe_data_request(protocol_interface_rf_mac_setup_s *rf_ptr, mac_pre_build_frame_t *buffer)
{
rf_ptr->macTxRequestAck = false;
memset(&(rf_ptr->mac_tx_status), 0, sizeof(mac_tx_status_t));
rf_ptr->mac_cca_retry = 0;
rf_ptr->mac_tx_retry = 0;
rf_ptr->mac_tx_start_channel = rf_ptr->mac_channel;
buffer->aux_header.frameCounter = 0xffffffff;
mac_csma_param_init(rf_ptr);
if (mcps_generic_packet_build(rf_ptr, buffer) != 0) {
return -1;
}
rf_ptr->macTxRequestAck = buffer->WaitResponse;//buffer->fcf_dsn.ackRequested;
return mcps_pd_data_cca_trig(rf_ptr, buffer);
}
int8_t mcps_pd_data_rebuild(protocol_interface_rf_mac_setup_s *rf_ptr, mac_pre_build_frame_t *buffer)
{
if (mcps_generic_packet_rebuild(rf_ptr, buffer) != 0) {
@ -1955,7 +2155,10 @@ int8_t mcps_pd_data_rebuild(protocol_interface_rf_mac_setup_s *rf_ptr, mac_pre_b
bool mac_is_ack_request_set(mac_pre_build_frame_t *buffer)
{
return buffer->fcf_dsn.ackRequested;
if (buffer->fcf_dsn.ackRequested || buffer->WaitResponse) {
return true;
}
return false;
}
int mac_convert_frame_type_to_fhss(uint8_t frame_type)
@ -1979,11 +2182,20 @@ void mcps_sap_pd_req_queue_write(protocol_interface_rf_mac_setup_s *rf_mac_setup
if ((rf_mac_setup->macBroadcastDisabled == true) && !mac_is_ack_request_set(buffer)) {
goto push_to_queue;
}
if (buffer->ExtendedFrameExchange) {
//Update here state and store peer
memcpy(rf_mac_setup->mac_edfe_info->PeerAddr, buffer->DstAddr, 8);
rf_mac_setup->mac_edfe_info->state = MAC_EDFE_FRAME_CONNECTING;
}
if (rf_mac_setup->fhss_api && (buffer->asynch_request == false)) {
uint16_t frame_length = buffer->mac_payload_length + buffer->headerIeLength + buffer->payloadsIeLength;
if (rf_mac_setup->fhss_api->check_tx_conditions(rf_mac_setup->fhss_api, !mac_is_ack_request_set(buffer),
buffer->msduHandle, mac_convert_frame_type_to_fhss(buffer->fcf_dsn.frametype), frame_length,
rf_mac_setup->dev_driver->phy_driver->phy_header_length, rf_mac_setup->dev_driver->phy_driver->phy_tail_length) == false) {
if (buffer->ExtendedFrameExchange) {
rf_mac_setup->mac_edfe_info->state = MAC_EDFE_FRAME_IDLE;
}
goto push_to_queue;
}
}
@ -1992,10 +2204,16 @@ void mcps_sap_pd_req_queue_write(protocol_interface_rf_mac_setup_s *rf_mac_setup
if (mcps_pd_data_request(rf_mac_setup, buffer) != 0) {
rf_mac_setup->mac_tx_result = MAC_TX_PRECOND_FAIL;
rf_mac_setup->macTxRequestAck = false;
if (buffer->ExtendedFrameExchange) {
rf_mac_setup->mac_edfe_info->state = MAC_EDFE_FRAME_IDLE;
}
if (mcps_sap_pd_confirm(rf_mac_setup) != 0) {
// can't send event, try calling error handler directly
rf_mac_setup->mac_mcps_data_conf_fail.msduHandle = buffer->msduHandle;
rf_mac_setup->mac_mcps_data_conf_fail.status = buffer->status;
if (buffer->ExtendedFrameExchange) {
rf_mac_setup->mac_edfe_info->state = MAC_EDFE_FRAME_IDLE;
}
mcps_sap_prebuild_frame_buffer_free(buffer);
rf_mac_setup->active_pd_data_request = NULL;
mac_pd_data_confirm_failure_handle(rf_mac_setup);
@ -2133,12 +2351,6 @@ void mcps_sap_pre_parsed_frame_buffer_free(mac_pre_parsed_frame_t *buf)
mac_pre_parsed_frame_t *mcps_sap_pre_parsed_frame_buffer_get(const uint8_t *data_ptr, uint16_t frame_length)
{
// check that system has enough space to handle the new packet
if (!ns_monitor_packet_allocation_allowed()) {
// stack can not handle new packets for routing
return NULL;
}
mac_pre_parsed_frame_t *buffer = ns_dyn_mem_temporary_alloc(sizeof(mac_pre_parsed_frame_t) + frame_length);
if (buffer) {

View File

@ -35,6 +35,7 @@ struct arm_phy_sap_msg_s;
struct mcps_purge_s;
struct mcps_data_req_ie_list;
struct channel_list_s;
struct mcps_enhanced_frame_response_s;
/** Address types */
typedef enum {
@ -133,8 +134,12 @@ uint8_t mcps_sap_purge_reg_handler(struct protocol_interface_rf_mac_setup *rf_ma
int8_t mcps_pd_data_rebuild(struct protocol_interface_rf_mac_setup *rf_ptr, mac_pre_build_frame_t *buffer);
int8_t mcps_edfe_data_request(struct protocol_interface_rf_mac_setup *rf_ptr, mac_pre_build_frame_t *buffer);
int8_t mcps_generic_ack_data_request_init(struct protocol_interface_rf_mac_setup *rf_ptr, const mac_fcf_sequence_t *fcf, const uint8_t *data_ptr, const mcps_ack_data_payload_t *ack_payload);
int8_t mcps_generic_edfe_frame_init(struct protocol_interface_rf_mac_setup *rf_ptr, const mac_fcf_sequence_t *fcf, const uint8_t *data_ptr, const struct mcps_edfe_response_s *response);
int8_t mcps_generic_ack_build(struct protocol_interface_rf_mac_setup *rf_ptr, bool init_build);
int mcps_packet_ingress_rate_limit_by_memory(uint8_t free_heap_percentage);

View File

@ -512,6 +512,10 @@ static int8_t mac_mlme_boolean_set(protocol_interface_rf_mac_setup_s *rf_mac_set
rf_mac_setup->dev_driver->phy_driver->extension(PHY_EXTENSION_ACCEPT_ANY_BEACON, (uint8_t *)&value);
}
break;
case macEdfeForceStop:
return mac_data_edfe_force_stop(rf_mac_setup);
case macAcceptByPassUnknowDevice:
rf_mac_setup->mac_security_bypass_unknow_device = value;
break;
@ -807,6 +811,11 @@ int8_t mac_mlme_set_req(protocol_interface_rf_mac_setup_s *rf_mac_setup, const m
memcpy(rf_mac_setup->coord_long_address, set_req->value_pointer, 8);
}
return 0;
case macSetDataWhitening:
pu8 = (uint8_t *) set_req->value_pointer;
rf_mac_setup->dev_driver->phy_driver->extension(PHY_EXTENSION_SET_DATA_WHITENING, pu8);
tr_debug("%s data whitening", *pu8 == (bool) true ? "Enable" : "Disable");
return 0;
case macCCAThresholdStart:
pu8 = (uint8_t *) set_req->value_pointer;
mac_cca_thr_init(rf_mac_setup, *pu8, *((int8_t *)pu8 + 1), *((int8_t *)pu8 + 2), *((int8_t *)pu8 + 3));
@ -869,7 +878,7 @@ int8_t mac_mlme_get_req(struct protocol_interface_rf_mac_setup *rf_mac_setup, ml
if (!get_req || !rf_mac_setup) {
return -1;
}
mac_cca_threshold_s *cca_thr_table = NULL;
switch (get_req->attr) {
case macDeviceTable:
get_req->value_pointer = mac_sec_mib_device_description_get_attribute_index(rf_mac_setup, get_req->attr_index);
@ -899,6 +908,12 @@ int8_t mac_mlme_get_req(struct protocol_interface_rf_mac_setup *rf_mac_setup, ml
get_req->value_size = 4;
break;
case macCCAThreshold:
cca_thr_table = mac_get_cca_threshold_table(rf_mac_setup);
get_req->value_size = cca_thr_table->number_of_channels;
get_req->value_pointer = cca_thr_table->ch_thresholds;
break;
default:
get_req->status = MLME_UNSUPPORTED_ATTRIBUTE;
break;
@ -1706,6 +1721,7 @@ void mac_mlme_poll_req(protocol_interface_rf_mac_setup_s *cur, const mlme_poll_t
}
buf->fcf_dsn.frametype = FC_CMD_FRAME;
buf->WaitResponse = true;
buf->fcf_dsn.ackRequested = true;
buf->fcf_dsn.intraPan = true;

View File

@ -36,6 +36,10 @@
#include "MAC/IEEE802_15_4/mac_mcps_sap.h"
#include "MAC/IEEE802_15_4/mac_cca_threshold.h"
#include "MAC/rf_driver_storage.h"
#include "Core/include/ns_monitor.h"
#include "ns_trace.h"
#define TRACE_GROUP "mPDs"
/* Define TX Timeot Period */
// Hardcoded to 1200ms. Should be changed dynamic: (FHSS) channel retries needs longer timeout
@ -148,6 +152,8 @@ static void mac_tx_done_state_set(protocol_interface_rf_mac_setup_s *rf_ptr, mac
}
rf_ptr->macRfRadioTxActive = false;
rf_ptr->macTxProcessActive = false;
rf_ptr->mac_edfe_response_tx_active = false;
rf_ptr->mac_edfe_tx_active = false;
mcps_sap_pd_confirm(rf_ptr);
}
@ -175,7 +181,7 @@ int8_t mac_plme_cca_req(protocol_interface_rf_mac_setup_s *rf_mac_setup)
uint8_t *buffer;
uint16_t length;
if (rf_mac_setup->mac_ack_tx_active) {
if (rf_mac_setup->mac_ack_tx_active || (rf_mac_setup->mac_edfe_tx_active && rf_mac_setup->mac_edfe_response_tx_active)) {
buffer = tx_buf->enhanced_ack_buf;
length = tx_buf->ack_len;
} else {
@ -371,6 +377,9 @@ static void mac_sap_cca_fail_cb(protocol_interface_rf_mac_setup_s *rf_ptr, uint
static void mac_sap_no_ack_cb(protocol_interface_rf_mac_setup_s *rf_ptr)
{
#ifdef TIMING_TOOL_TRACES
tr_info("%u no_ack", mac_mcps_sap_get_phy_timestamp(rf_ptr));
#endif
rf_ptr->macRfRadioTxActive = false;
if (rf_ptr->mac_tx_retry < rf_ptr->mac_mlme_retry_max) {
rf_ptr->mac_cca_retry = 0;
@ -424,6 +433,17 @@ static void mac_data_ack_tx_finish(protocol_interface_rf_mac_setup_s *rf_ptr)
}
}
int8_t mac_data_edfe_force_stop(protocol_interface_rf_mac_setup_s *rf_ptr)
{
if (!rf_ptr->mac_edfe_enabled || rf_ptr->mac_edfe_info->state != MAC_EDFE_FRAME_WAIT_DATA) {
return -1;
}
//Set to idle
rf_ptr->mac_edfe_info->state = MAC_EDFE_FRAME_IDLE;
mac_data_ack_tx_finish(rf_ptr);
return 0;
}
static int8_t mac_data_interface_tx_done_cb(protocol_interface_rf_mac_setup_s *rf_ptr, phy_link_tx_status_e status, uint8_t cca_retry, uint8_t tx_retry)
{
@ -436,6 +456,9 @@ static int8_t mac_data_interface_tx_done_cb(protocol_interface_rf_mac_setup_s *r
if (rf_ptr->mac_ack_tx_active) {
//Accept direct non crypted acks and crypted only if neighbor is at list
if (rf_ptr->ack_tx_possible) {
#ifdef TIMING_TOOL_TRACES
tr_info("%u TX_start %u", mac_mcps_sap_get_phy_timestamp(rf_ptr), rf_ptr->mac_channel);
#endif
return PHY_TX_ALLOWED;
}
@ -447,7 +470,14 @@ static int8_t mac_data_interface_tx_done_cb(protocol_interface_rf_mac_setup_s *r
return PHY_TX_NOT_ALLOWED;
}
if (rf_ptr->mac_edfe_tx_active) {
return PHY_TX_ALLOWED;
}
if (mac_data_asynch_channel_switch(rf_ptr, rf_ptr->active_pd_data_request)) {
#ifdef TIMING_TOOL_TRACES
tr_info("%u TX_start %u", mac_mcps_sap_get_phy_timestamp(rf_ptr), rf_ptr->mac_channel);
#endif
rf_ptr->active_pd_data_request->initial_tx_channel = rf_ptr->mac_channel;
int8_t channel_cca_threshold = mac_cca_thr_get_dbm(rf_ptr, rf_ptr->mac_channel);
if (CCA_FAILED_DBM != channel_cca_threshold) {
@ -495,14 +525,34 @@ static int8_t mac_data_interface_tx_done_cb(protocol_interface_rf_mac_setup_s *r
return PHY_RESTART_CSMA;
}
}
#ifdef TIMING_TOOL_TRACES
tr_info("%u TX_start %u", mac_mcps_sap_get_phy_timestamp(rf_ptr), rf_ptr->mac_channel);
#endif
return 0;
}
if (rf_ptr->mac_ack_tx_active) {
mac_data_ack_tx_finish(rf_ptr);
#ifdef TIMING_TOOL_TRACES
tr_info("%u TX_done", mac_mcps_sap_get_phy_timestamp(rf_ptr));
#endif
return 0;
} else {
if (rf_ptr->mac_edfe_tx_active) {
if (rf_ptr->mac_edfe_response_tx_active) {
//Stop process here
rf_ptr->mac_edfe_response_tx_active = false;
rf_ptr->mac_edfe_tx_active = false;
if ((status == PHY_LINK_TX_DONE || status == PHY_LINK_TX_SUCCESS) && rf_ptr->mac_edfe_info->state == MAC_EDFE_FRAME_TX_FINAL_FRAME) {
//Set to idle
rf_ptr->mac_edfe_info->state = MAC_EDFE_FRAME_IDLE;
}
mac_data_ack_tx_finish(rf_ptr);
return 0;
}
}
// Do not update CCA count when Ack is received, it was already updated with PHY_LINK_TX_SUCCESS event
// Do not update CCA count when CCA_OK is received, PHY_LINK_TX_SUCCESS will update it
if ((status != PHY_LINK_TX_DONE) && (status != PHY_LINK_TX_DONE_PENDING) && (status != PHY_LINK_CCA_OK)) {
@ -510,6 +560,11 @@ static int8_t mac_data_interface_tx_done_cb(protocol_interface_rf_mac_setup_s *r
* PHY_LINK_TX_FAIL either happened during transmission or when waiting Ack -> we must use the CCA count given by PHY.
*/
if ((cca_retry == 0) && (status != PHY_LINK_TX_FAIL)) {
#ifdef TIMING_TOOL_TRACES
if (status != PHY_LINK_CCA_FAIL) {
tr_info("%u TX_done", mac_mcps_sap_get_phy_timestamp(rf_ptr));
}
#endif
cca_retry = 1;
}
rf_ptr->mac_tx_status.cca_cnt += cca_retry;
@ -671,7 +726,9 @@ static int8_t mac_pd_sap_validate_fcf(protocol_interface_rf_mac_setup_s *rf_ptr,
switch (fcf_read->frametype) {
case FC_DATA_FRAME:
if (fcf_read->SrcAddrMode == MAC_ADDR_MODE_NONE) {
return -1;
if (fcf_read->DstAddrMode == MAC_ADDR_MODE_NONE || fcf_read->frameVersion != MAC_FRAME_VERSION_2015) {
return -1;
}
} else if (fcf_read->DstAddrMode == MAC_ADDR_MODE_NONE && fcf_read->frameVersion != MAC_FRAME_VERSION_2015) {
return -1;
}
@ -821,13 +878,44 @@ static int8_t mac_pd_sap_generate_ack(protocol_interface_rf_mac_setup_s *rf_ptr,
return mcps_generic_ack_build(rf_ptr, true);
}
static int8_t mac_pd_sap_generate_edfe_response(protocol_interface_rf_mac_setup_s *rf_ptr, const mac_fcf_sequence_t *fcf_read, arm_pd_sap_generic_ind_t *pd_data_ind, mcps_edfe_response_t *response)
{
if (rf_ptr->mac_ack_tx_active) {
return -1;
}
if (rf_ptr->mac_edfe_info->state == MAC_EDFE_FRAME_CONNECTED && rf_ptr->macRfRadioTxActive && rf_ptr->active_pd_data_request) {
timer_mac_stop(rf_ptr);
rf_ptr->macRfRadioTxActive = false;
rf_ptr->macTxProcessActive = false;
}
if (mcps_generic_edfe_frame_init(rf_ptr, fcf_read, pd_data_ind->data_ptr, response)) {
return -1;
}
if (response->wait_response) {
return mcps_edfe_data_request(rf_ptr, rf_ptr->active_pd_data_request);
}
return mcps_generic_ack_build(rf_ptr, true);
}
static mac_pre_parsed_frame_t *mac_pd_sap_allocate_receive_buffer(protocol_interface_rf_mac_setup_s *rf_ptr, const mac_fcf_sequence_t *fcf_read, arm_pd_sap_generic_ind_t *pd_data_ind)
{
// Unless receiving Ack, check that system has enough space to handle the new packet
if (fcf_read->frametype != FC_ACK_FRAME) {
if (!ns_monitor_packet_allocation_allowed()) {
// stack can not handle new packets for routing
return NULL;
}
}
mac_pre_parsed_frame_t *buffer = mcps_sap_pre_parsed_frame_buffer_get(pd_data_ind->data_ptr, pd_data_ind->data_len);
if (!buffer) {
return NULL;
}
//Copy Pre Parsed values
buffer->fcf_dsn = *fcf_read;
buffer->timestamp = mac_pd_sap_get_phy_rx_time(rf_ptr);
@ -922,6 +1010,10 @@ int8_t mac_pd_sap_data_cb(void *identifier, arm_phy_sap_msg_t *message)
if (pd_data_ind->data_len < 3) {
return -1;
}
#ifdef TIMING_TOOL_TRACES
tr_info("%u RX_start", mac_pd_sap_get_phy_rx_time(rf_ptr));
tr_info("%u RX_done", mac_mcps_sap_get_phy_timestamp(rf_ptr));
#endif
mac_cca_threshold_event_send(rf_ptr, rf_ptr->mac_channel, pd_data_ind->dbm);
mac_fcf_sequence_t fcf_read;
const uint8_t *ptr = mac_header_parse_fcf_dsn(&fcf_read, pd_data_ind->data_ptr);
@ -953,6 +1045,77 @@ int8_t mac_pd_sap_data_cb(void *identifier, arm_phy_sap_msg_t *message)
}
return 0;
}
if (rf_ptr->mac_edfe_enabled && !fcf_read.ackRequested && fcf_read.frameVersion == MAC_FRAME_VERSION_2015 && buffer->fcf_dsn.frametype == FC_DATA_FRAME) {
mcps_edfe_response_t response;
mac_api_t *mac_api = get_sw_mac_api(rf_ptr);
response.ie_elements.payloadIeList = buffer->payloadsIePtr;
response.ie_elements.payloadIeListLength = buffer->payloadsIeLength;
response.ie_elements.headerIeList = buffer->headerIePtr;
response.ie_elements.headerIeListLength = buffer->headerIeLength;
response.DstAddrMode = buffer->fcf_dsn.DstAddrMode;
response.SrcAddrMode = buffer->fcf_dsn.SrcAddrMode;
response.rssi = pd_data_ind->dbm;
if (buffer->fcf_dsn.SrcAddrMode == MAC_ADDR_MODE_64_BIT) {
mac_header_get_src_address(&fcf_read, pd_data_ind->data_ptr, response.Address);
} else {
memcpy(response.Address, rf_ptr->mac_edfe_info->PeerAddr, 8);
}
if (rf_ptr->mac_edfe_info->state == MAC_EDFE_FRAME_CONNECTING && rf_ptr->active_pd_data_request) {
response.message_handle = rf_ptr->active_pd_data_request->msduHandle;
response.use_message_handle_to_discover = true;
} else {
response.use_message_handle_to_discover = false;
}
mac_api->edfe_ind_cb(mac_api, &response);
response.DstAddrMode = MAC_ADDR_MODE_64_BIT;
switch (response.edfe_message_status) {
case MCPS_EDFE_RESPONSE_FRAME:
if (buffer->fcf_dsn.SrcAddrMode == MAC_ADDR_MODE_64_BIT) {
memcpy(rf_ptr->mac_edfe_info->PeerAddr, response.Address, 8);
}
rf_ptr->mac_edfe_info->state = MAC_EDFE_FRAME_WAIT_DATA;
if (mac_pd_sap_generate_edfe_response(rf_ptr, &fcf_read, pd_data_ind, &response)) {
goto ERROR_HANDLER;
}
break;
case MCPS_EDFE_TX_FRAME:
rf_ptr->mac_edfe_info->state = MAC_EDFE_FRAME_CONNECTED;
if (mac_pd_sap_generate_edfe_response(rf_ptr, &fcf_read, pd_data_ind, &response)) {
goto ERROR_HANDLER;
}
break;
case MCPS_EDFE_FINAL_FRAME_TX:
if (mac_pd_sap_generate_edfe_response(rf_ptr, &fcf_read, pd_data_ind, &response)) {
goto ERROR_HANDLER;
}
rf_ptr->mac_edfe_info->state = MAC_EDFE_FRAME_TX_FINAL_FRAME;
break;
case MCPS_EDFE_FINAL_FRAME_RX:
//Mark session closed
rf_ptr->mac_edfe_info->state = MAC_EDFE_FRAME_IDLE;
rf_ptr->mac_edfe_tx_active = false;
if (mac_data_interface_tx_done_by_ack_cb(rf_ptr, buffer)) {
mcps_sap_pre_parsed_frame_buffer_free(buffer);
}
return 0;
case MCPS_EDFE_MALFORMED_FRAME:
goto ERROR_HANDLER;
case MCPS_EDFE_NORMAL_FRAME:
default:
break;
}
}
}
}
if (!buffer) {

View File

@ -59,4 +59,6 @@ void mac_csma_backoff_start(struct protocol_interface_rf_mac_setup *rf_mac_setup
*/
void mac_pd_sap_state_machine(struct protocol_interface_rf_mac_setup *rf_mac_setup);
int8_t mac_data_edfe_force_stop(struct protocol_interface_rf_mac_setup *rf_ptr);
#endif /* MAC_PD_SAP_H_ */

View File

@ -54,6 +54,7 @@ static int8_t ns_sw_mac_initialize(mac_api_t *api, mcps_data_confirm *mcps_data_
mcps_data_indication *mcps_data_ind_cb, mcps_purge_confirm *purge_conf_cb,
mlme_confirm *mlme_conf_callback, mlme_indication *mlme_ind_callback, int8_t parent_id);
static int8_t ns_sw_mac_api_enable_mcps_ext(mac_api_t *api, mcps_data_indication_ext *data_ind_cb, mcps_data_confirm_ext *data_cnf_cb, mcps_ack_data_req_ext *ack_data_req_cb);
static int8_t ns_sw_mac_api_enable_edfe_ext(mac_api_t *api, mcps_edfe_handler *edfe_ind_cb);
static void mlme_req(const mac_api_t *api, mlme_primitive id, const void *data);
static void mcps_req(const mac_api_t *api, const mcps_data_req_t *data);
@ -67,6 +68,7 @@ static int8_t sw_mac_net_phy_tx_done(int8_t driver_id, uint8_t tx_handle, phy_li
static int8_t sw_mac_net_phy_config_parser(int8_t driver_id, const uint8_t *data, uint16_t length);
static int8_t sw_mac_storage_decription_sizes_get(const mac_api_t *api, mac_description_storage_size_t *buffer);
static int8_t sw_mac_storage_decription_sizes_get(const mac_api_t *api, mac_description_storage_size_t *buffer)
{
if (!api || !buffer || api != mac_store.mac_api) {
@ -127,6 +129,7 @@ mac_api_t *ns_sw_mac_create(int8_t rf_driver_id, mac_description_storage_size_t
this->mac_initialize = &ns_sw_mac_initialize;
this->mac_mcps_extension_enable = &ns_sw_mac_api_enable_mcps_ext;
this->mac_mcps_edfe_enable = &ns_sw_mac_api_enable_edfe_ext;
this->mlme_req = &mlme_req;
this->mcps_data_req = &mcps_req;
this->mcps_data_req_ext = &mcps_req_ext;
@ -314,6 +317,33 @@ static int8_t ns_sw_mac_api_enable_mcps_ext(mac_api_t *api, mcps_data_indication
return 0;
}
static int8_t ns_sw_mac_api_enable_edfe_ext(mac_api_t *api, mcps_edfe_handler *edfe_ind_cb)
{
//TODO: Find from linked list instead
if (api != mac_store.mac_api) {
return -1;
}
mac_api_t *cur = mac_store.mac_api;
if (!mac_store.setup->mac_extension_enabled) {
return -1;
}
cur->edfe_ind_cb = edfe_ind_cb;
if (edfe_ind_cb) {
ns_dyn_mem_free(mac_store.setup->mac_edfe_info);
mac_store.setup->mac_edfe_info = ns_dyn_mem_alloc(sizeof(mac_mcps_edfe_frame_info_t));
if (!mac_store.setup->mac_edfe_info) {
return -2;
}
mac_store.setup->mac_edfe_info->state = MAC_EDFE_FRAME_IDLE;
mac_store.setup->mac_edfe_enabled = true;
} else {
mac_store.setup->mac_edfe_enabled = false;
}
return 0;
}
mac_api_t *get_sw_mac_api(protocol_interface_rf_mac_setup_s *setup)
{
if (!mac_store.mac_api || mac_store.mac_api->parent_id == -1 || mac_store.setup != setup) {

View File

@ -498,6 +498,7 @@ static void mpl_buffer_transmit(mpl_domain_t *domain, mpl_buffered_message_t *me
memcpy(buf->src_sa.address, message->message + IPV6_HDROFF_SRC_ADDR, 16);
ipv6_transmit_multicast_on_interface(buf, domain->interface);
tr_debug("MPL transmit %u", mpl_buffer_sequence(message));
}
static void mpl_buffer_inconsistent(const mpl_domain_t *domain, mpl_buffered_message_t *message)
@ -853,6 +854,7 @@ bool mpl_forwarder_process_message(buffer_t *buf, mpl_domain_t *domain, bool see
const uint8_t *seed_id = opt_data + 2;
uint8_t seed_id_len = mpl_seed_id_len(seed_id_type);
tr_debug("MPL %s %"PRIu8, seeding ? "transmit" : "received", sequence);
/* Special handling - just ignore the MPL option if receiving loopback copy.
* (MPL gets to process the outgoing message, and with seeding true - when
* looping back, we want to accept it without MPL getting in the way).

View File

@ -238,6 +238,7 @@ typedef struct arm_15_4_mac_parameters_t {
uint16_t pan_id;
uint16_t mac_short_address;
mac_cordinator_s mac_cordinator_info;
cca_threshold_table_s cca_thr_table;
uint8_t number_of_fhss_channel_retries;
/* MAC Beacon info */
uint8_t *mac_beacon_payload;

View File

@ -61,17 +61,26 @@ typedef struct {
typedef NS_LIST_HEAD(kmp_sec_prot_entry_t, link) kmp_sec_prot_list_t;
typedef struct {
uint8_t instance_id; /**< Message interface instance identifier */
uint8_t header_size; /**< Message interface header size */
kmp_service_msg_if_send *send; /**< Message interface callback to send KMP frames */
ns_list_link_t link; /**< Link */
} kmp_msg_if_entry_t;
typedef NS_LIST_HEAD(kmp_msg_if_entry_t, link) kmp_msg_if_list_t;
struct kmp_service_s {
kmp_sec_prot_list_t sec_prot_list; /**< Security protocols list */
kmp_msg_if_list_t msg_if_list; /**< Message interface list */
kmp_service_incoming_ind *incoming_ind; /**< Callback to application to indicate incoming KMP frame */
kmp_service_tx_status_ind *tx_status_ind; /**< Callback to application to indicate TX status */
kmp_service_addr_get *addr_get; /**< Callback to get addresses related to KMP */
kmp_service_ip_addr_get *ip_addr_get; /**< Callback to get IP addresses related to KMP */
kmp_service_api_get *api_get; /**< Callback to get KMP API from a service */
kmp_service_msg_if_send *send; /**< Callback to send KMP frames */
kmp_service_timer_if_start *timer_start; /**< Callback to start timer */
kmp_service_timer_if_stop *timer_stop; /**< Callback to stop timer */
kmp_service_event_if_event_send *event_send; /**< Callback to send event */
uint8_t header_size; /**< Header size */
ns_list_link_t link; /**< Link */
};
@ -85,6 +94,7 @@ static NS_LIST_DEFINE(kmp_service_list, kmp_service_t, link);
// KMP instance identifier value
static uint8_t kmp_instance_identifier = 0;
static kmp_msg_if_entry_t *kmp_api_msg_if_get(kmp_service_t *service, uint8_t msg_if_instance_id);
static void kmp_api_sec_prot_create_confirm(sec_prot_t *prot, sec_prot_result_e result);
static void kmp_api_sec_prot_create_indication(sec_prot_t *prot);
static void kmp_api_sec_prot_finished_indication(sec_prot_t *prot, sec_prot_result_e result, sec_prot_keys_t *sec_keys);
@ -94,12 +104,13 @@ static void kmp_sec_prot_timer_start(sec_prot_t *prot);
static void kmp_sec_prot_timer_stop(sec_prot_t *prot);
static void kmp_sec_prot_state_machine_call(sec_prot_t *prot);
static void kmp_sec_prot_eui64_addr_get(sec_prot_t *prot, uint8_t *local_eui64, uint8_t *remote_eui64);
static void kmp_sec_prot_ip_addr_get(sec_prot_t *prot, uint8_t *address);
static sec_prot_t *kmp_sec_prot_by_type_get(sec_prot_t *prot, uint8_t type);
static void kmp_sec_prot_receive_disable(sec_prot_t *prot);
#define kmp_api_get_from_prot(prot) (kmp_api_t *)(((uint8_t *)prot) - offsetof(kmp_api_t, sec_prot));
kmp_api_t *kmp_api_create(kmp_service_t *service, kmp_type_e type, sec_prot_cfg_t *prot_cfg, sec_timer_cfg_t *timer_cfg)
kmp_api_t *kmp_api_create(kmp_service_t *service, kmp_type_e type, uint8_t msg_if_instance_id, sec_cfg_t *sec_cfg)
{
if (!service) {
return 0;
@ -120,6 +131,11 @@ kmp_api_t *kmp_api_create(kmp_service_t *service, kmp_type_e type, sec_prot_cfg_
// Size for security protocol internal data
uint16_t sec_size = sec_prot->size();
kmp_msg_if_entry_t *msg_if_entry = kmp_api_msg_if_get(service, msg_if_instance_id);
if (!msg_if_entry) {
return 0;
}
kmp_api_t *kmp = ns_dyn_mem_temporary_alloc(sizeof(kmp_api_t) + sec_size);
if (!kmp) {
return 0;
@ -137,9 +153,10 @@ kmp_api_t *kmp_api_create(kmp_service_t *service, kmp_type_e type, sec_prot_cfg_
kmp->timer_start_pending = false;
kmp->receive_disable = false;
memset(&kmp->sec_prot, 0, sec_size);
memset(&kmp->sec_prot, 0, sec_size + offsetof(sec_prot_t, data));
kmp->sec_prot.header_size = service->header_size;
kmp->sec_prot.header_size = msg_if_entry->header_size;
kmp->sec_prot.receive_peer_hdr_size = msg_if_entry->header_size;
kmp->sec_prot.create_conf = kmp_api_sec_prot_create_confirm;
kmp->sec_prot.create_ind = kmp_api_sec_prot_create_indication;
kmp->sec_prot.finished_ind = kmp_api_sec_prot_finished_indication;
@ -149,10 +166,11 @@ kmp_api_t *kmp_api_create(kmp_service_t *service, kmp_type_e type, sec_prot_cfg_
kmp->sec_prot.timer_stop = kmp_sec_prot_timer_stop;
kmp->sec_prot.state_machine_call = kmp_sec_prot_state_machine_call;
kmp->sec_prot.addr_get = kmp_sec_prot_eui64_addr_get;
kmp->sec_prot.ip_addr_get = kmp_sec_prot_ip_addr_get;
kmp->sec_prot.type_get = kmp_sec_prot_by_type_get;
kmp->sec_prot.receive_disable = kmp_sec_prot_receive_disable;
kmp->sec_prot.prot_cfg = prot_cfg;
kmp->sec_prot.timer_cfg = timer_cfg;
kmp->sec_prot.sec_cfg = sec_cfg;
kmp->sec_prot.msg_if_instance_id = msg_if_instance_id;
if (sec_prot->init(&kmp->sec_prot) < 0) {
ns_dyn_mem_free(kmp);
@ -162,6 +180,16 @@ kmp_api_t *kmp_api_create(kmp_service_t *service, kmp_type_e type, sec_prot_cfg_
return (kmp_api_t *) kmp;
}
static kmp_msg_if_entry_t *kmp_api_msg_if_get(kmp_service_t *service, uint8_t msg_if_instance_id)
{
ns_list_foreach(kmp_msg_if_entry_t, list_entry, &service->msg_if_list) {
if (list_entry->instance_id == msg_if_instance_id) {
return list_entry;
}
}
return NULL;
}
int8_t kmp_api_start(kmp_api_t *kmp)
{
if (kmp->timer_start_pending) {
@ -216,12 +244,19 @@ static int8_t kmp_sec_prot_send(sec_prot_t *prot, void *pdu, uint16_t size)
kmp_type_e kmp_id = kmp->type;
if (kmp_id > IEEE_802_1X_INITIAL_KEY) {
kmp_id -= IEEE_802_1X_INITIAL_KEY;
} else if (kmp_id == RADIUS_IEEE_802_1X_MKA) {
kmp_id = IEEE_802_1X_MKA;
}
kmp_msg_if_entry_t *msg_if_entry = kmp_api_msg_if_get(kmp->service, prot->msg_if_instance_id);
if (!msg_if_entry) {
return -1;
}
int8_t result = -1;
if (kmp->service->send) {
result = kmp->service->send(kmp->service, kmp_id, kmp->addr, pdu, size, kmp->instance_identifier);
if (msg_if_entry->send) {
result = msg_if_entry->send(kmp->service, prot->msg_if_instance_id, kmp_id, kmp->addr, pdu, size, kmp->instance_identifier);
}
if (result < 0) {
@ -267,6 +302,13 @@ static void kmp_sec_prot_eui64_addr_get(sec_prot_t *prot, uint8_t *local_eui64,
}
}
static void kmp_sec_prot_ip_addr_get(sec_prot_t *prot, uint8_t *address)
{
kmp_api_t *kmp = kmp_api_get_from_prot(prot);
kmp->service->ip_addr_get(kmp->service, kmp, address);
}
static sec_prot_t *kmp_sec_prot_by_type_get(sec_prot_t *prot, uint8_t type)
{
kmp_api_t *kmp = kmp_api_get_from_prot(prot);
@ -277,9 +319,15 @@ static sec_prot_t *kmp_sec_prot_by_type_get(sec_prot_t *prot, uint8_t type)
case SEC_PROT_TYPE_EAP_TLS:
kmp_type = IEEE_802_1X_MKA;
break;
case SEC_PROT_TYPE_RADIUS_EAP_TLS:
kmp_type = RADIUS_IEEE_802_1X_MKA;
break;
case SEC_PROT_TYPE_TLS:
kmp_type = TLS_PROT;
break;
case SEC_PROT_TYPE_RADIUS_CLIENT:
kmp_type = RADIUS_CLIENT_PROT;
break;
default:
return NULL;
}
@ -328,6 +376,17 @@ bool kmp_api_receive_disable(kmp_api_t *kmp)
return kmp->receive_disable;
}
bool kmp_api_receive_check(kmp_api_t *kmp, const void *pdu, uint16_t size)
{
if (kmp->sec_prot.receive_check) {
int8_t ret = kmp->sec_prot.receive_check(&kmp->sec_prot, pdu, size);
if (ret >= 0) {
return true;
}
}
return false;
}
kmp_type_e kmp_api_type_from_id_get(uint8_t kmp_id)
{
switch (kmp_id) {
@ -380,12 +439,11 @@ kmp_service_t *kmp_service_create(void)
}
ns_list_init(&service->sec_prot_list);
ns_list_init(&service->msg_if_list);
service->incoming_ind = 0;
service->tx_status_ind = 0;
service->addr_get = 0;
service->api_get = 0;
service->send = 0;
service->header_size = 0;
ns_list_add_to_start(&kmp_service_list, service);
@ -404,7 +462,10 @@ int8_t kmp_service_delete(kmp_service_t *service)
ns_list_remove(&list_entry->sec_prot_list, sec_list_entry);
ns_dyn_mem_free(sec_list_entry);
}
ns_list_foreach_safe(kmp_msg_if_entry_t, msg_if_list_entry, &list_entry->msg_if_list) {
ns_list_remove(&list_entry->msg_if_list, msg_if_list_entry);
ns_dyn_mem_free(msg_if_list_entry);
}
ns_list_remove(&kmp_service_list, list_entry);
ns_dyn_mem_free(list_entry);
return 0;
@ -420,7 +481,7 @@ static void kmp_sec_prot_state_machine_call(sec_prot_t *prot)
kmp->service->event_send(kmp->service, prot);
}
int8_t kmp_service_cb_register(kmp_service_t *service, kmp_service_incoming_ind *incoming_ind, kmp_service_tx_status_ind *tx_status_ind, kmp_service_addr_get *addr_get, kmp_service_api_get *api_get)
int8_t kmp_service_cb_register(kmp_service_t *service, kmp_service_incoming_ind *incoming_ind, kmp_service_tx_status_ind *tx_status_ind, kmp_service_addr_get *addr_get, kmp_service_ip_addr_get *ip_addr_get, kmp_service_api_get *api_get)
{
if (!service) {
return -1;
@ -429,30 +490,60 @@ int8_t kmp_service_cb_register(kmp_service_t *service, kmp_service_incoming_ind
service->incoming_ind = incoming_ind;
service->tx_status_ind = tx_status_ind;
service->addr_get = addr_get;
service->ip_addr_get = ip_addr_get;
service->api_get = api_get;
return 0;
}
int8_t kmp_service_msg_if_register(kmp_service_t *service, kmp_service_msg_if_send *send, uint8_t header_size)
int8_t kmp_service_msg_if_register(kmp_service_t *service, uint8_t instance_id, kmp_service_msg_if_send *send, uint8_t header_size)
{
if (!service) {
return -1;
}
service->send = send;
service->header_size = header_size;
kmp_msg_if_entry_t *entry = NULL;
ns_list_foreach(kmp_msg_if_entry_t, list_entry, &service->msg_if_list) {
// Message interface already registered
if (list_entry->instance_id == instance_id) {
entry = list_entry;
break;
}
}
// If removing message interface
if (send == NULL) {
if (entry != NULL) {
ns_list_remove(&service->msg_if_list, entry);
ns_dyn_mem_free(entry);
}
return 0;
}
// Allocate new entry if does not exists
if (entry == NULL) {
entry = ns_dyn_mem_temporary_alloc(sizeof(kmp_msg_if_entry_t));
if (entry == NULL) {
return -1;
}
ns_list_add_to_start(&service->msg_if_list, entry);
}
entry->instance_id = instance_id;
entry->send = send;
entry->header_size = header_size;
return 0;
}
int8_t kmp_service_msg_if_receive(kmp_service_t *service, kmp_type_e type, const kmp_addr_t *addr, void *pdu, uint16_t size)
int8_t kmp_service_msg_if_receive(kmp_service_t *service, uint8_t instance_id, kmp_type_e type, const kmp_addr_t *addr, void *pdu, uint16_t size)
{
if (!service) {
return -1;
}
kmp_api_t *kmp = (kmp_api_t *) service->incoming_ind(service, type, addr);
kmp_api_t *kmp = (kmp_api_t *) service->incoming_ind(service, instance_id, type, addr, pdu, size);
if (!kmp) {
return -1;
}

View File

@ -31,16 +31,19 @@
typedef enum {
KMP_TYPE_NONE = 0,
IEEE_802_1X_MKA = 1,
IEEE_802_11_4WH = 6,
IEEE_802_11_GKH = 7,
TLS_PROT = 8,
IEEE_802_1X_MKA = 1,
RADIUS_IEEE_802_1X_MKA = 2,
IEEE_802_11_4WH = 6,
IEEE_802_11_GKH = 7,
TLS_PROT = 8,
RADIUS_CLIENT_PROT = 9,
IEEE_802_1X_INITIAL_KEY = 10,
IEEE_802_1X_MKA_KEY = 11,
IEEE_802_11_4WH_KEY = 16,
IEEE_802_11_GKH_KEY = 17
IEEE_802_1X_MKA_KEY = 11,
RADIUS_IEEE_802_1X_MKA_KEY = 12,
IEEE_802_11_4WH_KEY = 16,
IEEE_802_11_GKH_KEY = 17
} kmp_type_e;
typedef enum {
@ -125,13 +128,13 @@ typedef void kmp_api_finished(kmp_api_t *kmp);
*
* \param service KMP service
* \param type KMP type
* \param prot_cfg protocol configuration
* \param timer_cfg timer configuration
* \param msg_if_instance_id message interface instance identifier
* \param sec_cfg security configuration
*
* \return KMP instance or NULL
*
*/
kmp_api_t *kmp_api_create(kmp_service_t *service, kmp_type_e type, sec_prot_cfg_t *prot_cfg, sec_timer_cfg_t *timer_cfg);
kmp_api_t *kmp_api_create(kmp_service_t *service, kmp_type_e type, uint8_t msg_if_instance_id, sec_cfg_t *sec_cfg);
/**
* kmp_api_start start KMP api
@ -172,6 +175,18 @@ kmp_type_e kmp_api_type_get(kmp_api_t *kmp);
*/
bool kmp_api_receive_disable(kmp_api_t *kmp);
/**
* kmp_api_receive_check check if received message is for this KMP
*
* \param kmp instance
* \param pdu pdu
* \param size pdu size
*
* \return true/false true if message is for this KMP
*
*/
bool kmp_api_receive_check(kmp_api_t *kmp, const void *pdu, uint16_t size);
/**
* kmp_api_type_from_id_get get KMP type from KMP id
*
@ -274,13 +289,14 @@ int8_t kmp_service_delete(kmp_service_t *service);
* kmp_service_incoming_ind Notifies application about incoming KMP frame
*
* \param service KMP service
* \param instance_id instance identifier
* \param type protocol type
* \param addr address
*
* \return KMP instance or NULL
*
*/
typedef kmp_api_t *kmp_service_incoming_ind(kmp_service_t *service, kmp_type_e type, const kmp_addr_t *addr);
typedef kmp_api_t *kmp_service_incoming_ind(kmp_service_t *service, uint8_t instance_id, kmp_type_e type, const kmp_addr_t *addr, const void *pdu, uint16_t size);
/**
* kmp_service_tx_status_ind Notifies application about TX status
@ -304,6 +320,16 @@ typedef kmp_api_t *kmp_service_tx_status_ind(kmp_service_t *service, uint8_t ins
*/
typedef void kmp_service_addr_get(kmp_service_t *service, kmp_api_t *kmp, kmp_addr_t *local_addr, kmp_addr_t *remote_addr);
/**
* kmp_service_ip_addr_get gets IP addressing information related to KMP
*
* \param service KMP service
* \param kmp KMP instance
* \param address IP address
*
*/
typedef void kmp_service_ip_addr_get(kmp_service_t *service, kmp_api_t *kmp, uint8_t *address);
/**
* kmp_service_api_get gets KMP API from KMP service
*
@ -323,18 +349,20 @@ typedef kmp_api_t *kmp_service_api_get(kmp_service_t *service, kmp_api_t *kmp, k
* \param incoming_ind incoming message callback
* \param tx_status tx status callback
* \param addr_get gets addressing information callback
* \param ip_addr_get gets IP addressing information callback
* \param api_get gets KMP API from KMP service
*
* \return < 0 failure
* \return >= 0 success
*
*/
int8_t kmp_service_cb_register(kmp_service_t *service, kmp_service_incoming_ind *incoming_ind, kmp_service_tx_status_ind *tx_status_ind, kmp_service_addr_get *addr_get, kmp_service_api_get *api_get);
int8_t kmp_service_cb_register(kmp_service_t *service, kmp_service_incoming_ind *incoming_ind, kmp_service_tx_status_ind *tx_status_ind, kmp_service_addr_get *addr_get, kmp_service_ip_addr_get *ip_addr_get, kmp_service_api_get *api_get);
/**
* kmp_service_msg_if_receive receive a message
*
* \param service KMP service
* \param instance_id instance identifier
* \param type protocol type
* \param addr address
* \param pdu pdu
@ -344,12 +372,13 @@ int8_t kmp_service_cb_register(kmp_service_t *service, kmp_service_incoming_ind
* \return >= 0 success
*
*/
int8_t kmp_service_msg_if_receive(kmp_service_t *service, kmp_type_e kmp_id, const kmp_addr_t *addr, void *pdu, uint16_t size);
int8_t kmp_service_msg_if_receive(kmp_service_t *service, uint8_t instance_id, kmp_type_e kmp_id, const kmp_addr_t *addr, void *pdu, uint16_t size);
/**
* kmp_service_msg_if_send send a message
*
* \param service KMP service
* \param instance_id instance identifier
* \param type protocol type
* \param addr address
* \param pdu pdu
@ -360,12 +389,13 @@ int8_t kmp_service_msg_if_receive(kmp_service_t *service, kmp_type_e kmp_id, con
* \return >= 0 success
*
*/
typedef int8_t kmp_service_msg_if_send(kmp_service_t *service, kmp_type_e type, const kmp_addr_t *addr, void *pdu, uint16_t size, uint8_t tx_identifier);
typedef int8_t kmp_service_msg_if_send(kmp_service_t *service, uint8_t instance_id, kmp_type_e type, const kmp_addr_t *addr, void *pdu, uint16_t size, uint8_t tx_identifier);
/**
* kmp_service_msg_if_register registers message interface
*
* \param service KMP service
* \param instance_id message interface instance identifier
* \param send KMP PDU send callback
* \param header_size header size
*
@ -373,7 +403,7 @@ typedef int8_t kmp_service_msg_if_send(kmp_service_t *service, kmp_type_e type,
* \return >= 0 success
*
*/
int8_t kmp_service_msg_if_register(kmp_service_t *service, kmp_service_msg_if_send *send, uint8_t header_size);
int8_t kmp_service_msg_if_register(kmp_service_t *service, uint8_t instance_id, kmp_service_msg_if_send *send, uint8_t header_size);
/**
* kmp_service_tx_status tx status indication

View File

@ -49,7 +49,7 @@ typedef struct {
static NS_LIST_DEFINE(kmp_eapol_pdu_if_list, kmp_eapol_pdu_if_t, link);
static int8_t kmp_eapol_pdu_if_send(kmp_service_t *service, kmp_type_e kmp_id, const kmp_addr_t *addr, void *pdu, uint16_t size, uint8_t tx_identifier);
static int8_t kmp_eapol_pdu_if_send(kmp_service_t *service, uint8_t instance_id, kmp_type_e kmp_id, const kmp_addr_t *addr, void *pdu, uint16_t size, uint8_t tx_identifier);
static int8_t kmp_eapol_pdu_if_tx_status(protocol_interface_info_entry_t *interface_ptr, eapol_pdu_tx_status_e tx_status, uint8_t tx_identifier);
int8_t kmp_eapol_pdu_if_register(kmp_service_t *service, protocol_interface_info_entry_t *interface_ptr)
@ -72,7 +72,7 @@ int8_t kmp_eapol_pdu_if_register(kmp_service_t *service, protocol_interface_info
eapol_pdu_if->kmp_service = service;
eapol_pdu_if->interface_ptr = interface_ptr;
if (kmp_service_msg_if_register(service, kmp_eapol_pdu_if_send, EAPOL_PDU_IF_HEADER_SIZE) < 0) {
if (kmp_service_msg_if_register(service, 0, kmp_eapol_pdu_if_send, EAPOL_PDU_IF_HEADER_SIZE) < 0) {
ns_dyn_mem_free(eapol_pdu_if);
return -1;
}
@ -92,14 +92,16 @@ int8_t kmp_eapol_pdu_if_unregister(kmp_service_t *service)
if (entry->kmp_service == service) {
ns_list_remove(&kmp_eapol_pdu_if_list, entry);
ns_dyn_mem_free(entry);
kmp_service_msg_if_register(service, NULL, 0);
kmp_service_msg_if_register(service, 0, NULL, 0);
}
}
return 0;
}
static int8_t kmp_eapol_pdu_if_send(kmp_service_t *service, kmp_type_e kmp_id, const kmp_addr_t *addr, void *pdu, uint16_t size, uint8_t tx_identifier)
static int8_t kmp_eapol_pdu_if_send(kmp_service_t *service, uint8_t instance_id, kmp_type_e kmp_id, const kmp_addr_t *addr, void *pdu, uint16_t size, uint8_t tx_identifier)
{
(void) instance_id; // Only one instance of eapol interface possible
if (!service || !addr || !pdu) {
return -1;
}
@ -157,7 +159,7 @@ int8_t kmp_eapol_pdu_if_receive(protocol_interface_info_entry_t *interface_ptr,
return -1;
}
int8_t ret = kmp_service_msg_if_receive(service, type, &addr, data_pdu, data_pdu_size);
int8_t ret = kmp_service_msg_if_receive(service, 0, type, &addr, data_pdu, data_pdu_size);
return ret;
}

View File

@ -43,52 +43,92 @@
typedef struct {
kmp_service_t *kmp_service; /**< KMP service */
uint8_t instance_id; /**< Instance identifier */
bool relay; /**< Interface is relay interface */
ns_address_t remote_addr; /**< Remote address */
int8_t socket_id; /**< Socket ID */
bool socket_id_set; /**< Socket ID is set */
ns_list_link_t link; /**< Link */
} kmp_socket_if_t;
static int8_t kmp_socket_if_send(kmp_service_t *service, kmp_type_e kmp_id, const kmp_addr_t *addr, void *pdu, uint16_t size, uint8_t tx_identifier);
static int8_t kmp_socket_if_send(kmp_service_t *service, uint8_t instance_id, kmp_type_e kmp_id, const kmp_addr_t *addr, void *pdu, uint16_t size, uint8_t tx_identifier);
static void kmp_socket_if_socket_cb(void *ptr);
static NS_LIST_DEFINE(kmp_socket_if_list, kmp_socket_if_t, link);
static uint8_t kmp_socket_if_instance_id = 1;
int8_t kmp_socket_if_register(kmp_service_t *service, uint16_t local_port, const uint8_t *remote_addr, uint16_t remote_port)
int8_t kmp_socket_if_register(kmp_service_t *service, uint8_t *instance_id, bool relay, uint16_t local_port, const uint8_t *remote_addr, uint16_t remote_port)
{
if (!service || !remote_addr) {
return -1;
}
kmp_socket_if_t *socket_if = NULL;
bool new_socket_if_allocated = false;
ns_list_foreach(kmp_socket_if_t, entry, &kmp_socket_if_list) {
if (entry->kmp_service == service) {
return -1;
if (entry->kmp_service == service && entry->instance_id == *instance_id) {
socket_if = entry;
}
}
kmp_socket_if_t *socket_if = ns_dyn_mem_alloc(sizeof(kmp_socket_if_t));
if (!socket_if) {
return -1;
socket_if = ns_dyn_mem_alloc(sizeof(kmp_socket_if_t));
if (!socket_if) {
return -1;
}
memset(socket_if, 0, sizeof(kmp_socket_if_t));
socket_if->socket_id = -1;
new_socket_if_allocated = true;
}
socket_if->kmp_service = service;
if (*instance_id == 0) {
socket_if->instance_id = kmp_socket_if_instance_id++;
if (socket_if->instance_id == 0) {
socket_if->instance_id++;
}
*instance_id = socket_if->instance_id;
}
socket_if->relay = relay;
socket_if->remote_addr.type = ADDRESS_IPV6;
bool address_changed = false;
if (memcmp(&socket_if->remote_addr.address, remote_addr, 16) != 0 ||
socket_if->remote_addr.identifier != remote_port) {
address_changed = true;
}
memcpy(&socket_if->remote_addr.address, remote_addr, 16);
socket_if->remote_addr.identifier = remote_port;
socket_if->socket_id = socket_open(IPV6_NH_UDP, local_port, &kmp_socket_if_socket_cb);
if (socket_if->socket_id < 0) {
if (socket_if->socket_id < 0 || address_changed) {
if (socket_if->socket_id >= 0) {
socket_close(socket_if->socket_id);
}
socket_if->socket_id = socket_open(IPV6_NH_UDP, local_port, &kmp_socket_if_socket_cb);
if (socket_if->socket_id < 0) {
ns_dyn_mem_free(socket_if);
return -1;
}
}
uint8_t header_size = 0;
if (relay) {
header_size = SOCKET_IF_HEADER_SIZE;
}
if (kmp_service_msg_if_register(service, *instance_id, kmp_socket_if_send, header_size) < 0) {
ns_dyn_mem_free(socket_if);
return -1;
}
if (kmp_service_msg_if_register(service, kmp_socket_if_send, SOCKET_IF_HEADER_SIZE) < 0) {
ns_dyn_mem_free(socket_if);
return -1;
if (new_socket_if_allocated) {
ns_list_add_to_end(&kmp_socket_if_list, socket_if);
}
ns_list_add_to_end(&kmp_socket_if_list, socket_if);
return 0;
}
@ -102,14 +142,14 @@ int8_t kmp_socket_if_unregister(kmp_service_t *service)
if (entry->kmp_service == service) {
ns_list_remove(&kmp_socket_if_list, entry);
socket_close(entry->socket_id);
kmp_service_msg_if_register(service, entry->instance_id, NULL, 0);
ns_dyn_mem_free(entry);
kmp_service_msg_if_register(service, NULL, 0);
}
}
return 0;
}
static int8_t kmp_socket_if_send(kmp_service_t *service, kmp_type_e kmp_id, const kmp_addr_t *addr, void *pdu, uint16_t size, uint8_t tx_identifier)
static int8_t kmp_socket_if_send(kmp_service_t *service, uint8_t instance_id, kmp_type_e kmp_id, const kmp_addr_t *addr, void *pdu, uint16_t size, uint8_t tx_identifier)
{
(void) tx_identifier;
@ -120,7 +160,7 @@ static int8_t kmp_socket_if_send(kmp_service_t *service, kmp_type_e kmp_id, cons
kmp_socket_if_t *socket_if = NULL;
ns_list_foreach(kmp_socket_if_t, entry, &kmp_socket_if_list) {
if (entry->kmp_service == service) {
if (entry->kmp_service == service && entry->instance_id == instance_id) {
socket_if = entry;
break;
}
@ -130,14 +170,16 @@ static int8_t kmp_socket_if_send(kmp_service_t *service, kmp_type_e kmp_id, cons
return -1;
}
//Build UPD Relay
uint8_t *ptr = pdu;
memcpy(ptr, addr->relay_address, 16);
ptr += 16;
ptr = common_write_16_bit(addr->port, ptr);
memcpy(ptr, kmp_address_eui_64_get(addr), 8);
ptr += 8;
*ptr = kmp_id;
if (socket_if->relay) {
//Build UPD Relay
uint8_t *ptr = pdu;
memcpy(ptr, addr->relay_address, 16);
ptr += 16;
ptr = common_write_16_bit(addr->port, ptr);
memcpy(ptr, kmp_address_eui_64_get(addr), 8);
ptr += 8;
*ptr = kmp_id;
}
socket_sendto(socket_if->socket_id, &socket_if->remote_addr, pdu, size);
ns_dyn_mem_free(pdu);
@ -172,25 +214,30 @@ static void kmp_socket_if_socket_cb(void *ptr)
ns_dyn_mem_free(pdu);
return;
}
kmp_addr_t addr;
addr.type = KMP_ADDR_EUI_64_AND_IP;
memset(&addr, 0, sizeof(kmp_addr_t));
kmp_type_e type = KMP_TYPE_NONE;
uint8_t *data_ptr = pdu;
memcpy(addr.relay_address, data_ptr, 16);
data_ptr += 16;
addr.port = common_read_16_bit(data_ptr);
data_ptr += 2;
memcpy(addr.eui_64, data_ptr, 8);
data_ptr += 8;
kmp_type_e type = kmp_api_type_from_id_get(*data_ptr++);
if (type == KMP_TYPE_NONE) {
ns_dyn_mem_free(pdu);
return;
if (socket_if->relay) {
addr.type = KMP_ADDR_EUI_64_AND_IP;
memcpy(addr.relay_address, data_ptr, 16);
data_ptr += 16;
addr.port = common_read_16_bit(data_ptr);
data_ptr += 2;
memcpy(addr.eui_64, data_ptr, 8);
data_ptr += 8;
type = kmp_api_type_from_id_get(*data_ptr++);
if (type == KMP_TYPE_NONE) {
ns_dyn_mem_free(pdu);
return;
}
cb_data->d_len -= SOCKET_IF_HEADER_SIZE;
}
kmp_service_msg_if_receive(socket_if->kmp_service, type, &addr, data_ptr, cb_data->d_len - 27);
kmp_service_msg_if_receive(socket_if->kmp_service, socket_if->instance_id, type, &addr, data_ptr, cb_data->d_len);
ns_dyn_mem_free(pdu);
}

View File

@ -33,6 +33,8 @@
* kmp_socket_if_register register socket interface to KMP service
*
* \param service KMP service to register to
* \param instance_id instance identifier, for new instance set to zero when called
* \param relay interface is relay interface
* \param local_port local port
* \param remote_addr remote address
* \param remote_port remote port
@ -41,7 +43,7 @@
* \return >= 0 success
*
*/
int8_t kmp_socket_if_register(kmp_service_t *service, uint16_t local_port, const uint8_t *remote_addr, uint16_t remote_port);
int8_t kmp_socket_if_register(kmp_service_t *service, uint8_t *instance_id, bool relay, uint16_t local_port, const uint8_t *remote_addr, uint16_t remote_port);
/**
* kmp_socket_if_unregister unregister socket interface from KMP service

View File

@ -189,7 +189,7 @@ static int8_t auth_eap_tls_sec_prot_receive(sec_prot_t *prot, void *pdu, uint16_
// Call state machine
prot->state_machine(prot);
// Resets trickle timer to give time for supplicant to answer
sec_prot_timer_trickle_start(&data->common, &prot->prot_cfg->sec_prot_trickle_params);
sec_prot_timer_trickle_start(&data->common, &prot->sec_cfg->prot_cfg.sec_prot_trickle_params);
data->init_key_cnt++;
}
// Filters repeated initial EAPOL-key messages
@ -297,7 +297,7 @@ static void auth_eap_tls_sec_prot_timer_timeout(sec_prot_t *prot, uint16_t ticks
}
sec_prot_timer_timeout_handle(prot, &data->common,
&prot->prot_cfg->sec_prot_trickle_params, ticks);
&prot->sec_cfg->prot_cfg.sec_prot_trickle_params, ticks);
}
static void auth_eap_tls_sec_prot_tls_create_indication(sec_prot_t *tls_prot)
@ -421,7 +421,7 @@ static void auth_eap_tls_sec_prot_state_machine(sec_prot_t *prot)
auth_eap_tls_sec_prot_message_send(prot, EAP_REQ, EAP_IDENTITY, EAP_TLS_EXCHANGE_NONE);
// Start trickle timer to re-send if no response
sec_prot_timer_trickle_start(&data->common, &prot->prot_cfg->sec_prot_trickle_params);
sec_prot_timer_trickle_start(&data->common, &prot->sec_cfg->prot_cfg.sec_prot_trickle_params);
sec_prot_state_set(prot, &data->common, EAP_TLS_STATE_RESPONSE_ID);
break;
@ -445,7 +445,7 @@ static void auth_eap_tls_sec_prot_state_machine(sec_prot_t *prot)
auth_eap_tls_sec_prot_message_send(prot, EAP_REQ, EAP_TLS, EAP_TLS_EXCHANGE_START);
// Start trickle timer to re-send if no response
sec_prot_timer_trickle_start(&data->common, &prot->prot_cfg->sec_prot_trickle_params);
sec_prot_timer_trickle_start(&data->common, &prot->sec_cfg->prot_cfg.sec_prot_trickle_params);
sec_prot_state_set(prot, &data->common, EAP_TLS_STATE_RESPONSE_START);
break;
@ -527,7 +527,7 @@ static void auth_eap_tls_sec_prot_state_machine(sec_prot_t *prot)
auth_eap_tls_sec_prot_message_send(prot, EAP_REQ, EAP_TLS, EAP_TLS_EXCHANGE_ONGOING);
// Start trickle timer to re-send if no response
sec_prot_timer_trickle_start(&data->common, &prot->prot_cfg->sec_prot_trickle_params);
sec_prot_timer_trickle_start(&data->common, &prot->sec_cfg->prot_cfg.sec_prot_trickle_params);
} else {
// TLS done, indicate success to peer
if (data->tls_result == EAP_TLS_RESULT_HANDSHAKE_OVER) {
@ -557,7 +557,7 @@ static void auth_eap_tls_sec_prot_state_machine(sec_prot_t *prot)
case EAP_TLS_STATE_FINISHED: {
uint8_t *remote_eui_64 = sec_prot_remote_eui_64_addr_get(prot);
tr_info("EAP-TLS finished, eui-64: %s", remote_eui_64 ? trace_array(sec_prot_remote_eui_64_addr_get(prot), 8) : "not set");
tr_info("EAP-TLS finished, eui-64: %s", remote_eui_64 ? trace_array(remote_eui_64, 8) : "not set");
auth_eap_tls_sec_prot_delete_tls(prot);
prot->timer_stop(prot);
prot->finished(prot);

View File

@ -0,0 +1,526 @@
/*
* Copyright (c) 2020, Arm Limited and affiliates.
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "nsconfig.h"
#include <string.h>
#include "ns_types.h"
#include "ns_list.h"
#include "ns_trace.h"
#include "common_functions.h"
#include "nsdynmemLIB.h"
#include "fhss_config.h"
#include "NWK_INTERFACE/Include/protocol.h"
#include "6LoWPAN/ws/ws_config.h"
#include "6LoWPAN/ws/ws_cfg_settings.h"
#include "Security/PANA/pana_eap_header.h"
#include "Security/protocols/sec_prot_cfg.h"
#include "Security/kmp/kmp_addr.h"
#include "Security/kmp/kmp_api.h"
#include "Security/PANA/pana_eap_header.h"
#include "Security/eapol/eapol_helper.h"
#include "Security/protocols/sec_prot_certs.h"
#include "Security/protocols/sec_prot_keys.h"
#include "Security/protocols/sec_prot.h"
#include "Security/protocols/sec_prot_lib.h"
#include "Security/protocols/eap_tls_sec_prot/eap_tls_sec_prot_lib.h"
#include "Security/protocols/eap_tls_sec_prot/radius_eap_tls_sec_prot.h"
#ifdef HAVE_WS
#define TRACE_GROUP "eapr"
typedef enum {
EAP_TLS_STATE_INIT = SEC_STATE_INIT,
EAP_TLS_STATE_CREATE_REQ = SEC_STATE_CREATE_REQ,
EAP_TLS_STATE_CREATE_RESP = SEC_STATE_CREATE_RESP,
EAP_TLS_STATE_CREATE_IND = SEC_STATE_CREATE_IND,
EAP_TLS_STATE_RESPONSE_ID = SEC_STATE_FIRST,
EAP_TLS_STATE_EAP_REQUEST,
EAP_TLS_STATE_EAP_RESPONSE,
EAP_TLS_STATE_RESPONSE_START,
EAP_TLS_STATE_RESPONSE,
EAP_TLS_STATE_FINISH = SEC_STATE_FINISH,
EAP_TLS_STATE_FINISHED = SEC_STATE_FINISHED
} eap_tls_sec_prot_state_e;
// Filters initial EAPOL-key re-transmission bursts
#define BURST_FILTER_TIMER_TIMEOUT 5 * 10
// How many times initial EAPOL-key is accepted on wait for identity response state
#define INITIAL_EAPOL_KEY_MAX_COUNT 2
typedef struct {
sec_prot_common_t common; /**< Common data */
sec_prot_t *radius_client_prot; /**< RADIUS client security protocol */
sec_prot_receive *radius_client_send; /**< RADIUS client security protocol send (receive from peer) */
eapol_pdu_t recv_eapol_pdu; /**< Received EAPOL PDU */
tls_data_t tls_send; /**< EAP-TLS send buffer */
uint16_t recv_eap_msg_len; /**< Received EAP message length */
uint8_t *recv_eap_msg; /**< Received EAP message */
uint16_t burst_filt_timer; /**< Burst filter timer */
uint8_t eap_id_seq; /**< EAP sequence */
uint8_t recv_eap_id_seq; /**< Last received EAP sequence */
uint8_t eap_code; /**< Received EAP code */
uint8_t eap_type; /**< Received EAP type */
uint8_t init_key_cnt; /**< How many time initial EAPOL-key has been received */
} radius_eap_tls_sec_prot_int_t;
static uint16_t radius_eap_tls_sec_prot_size(void);
static int8_t radius_eap_tls_sec_prot_init(sec_prot_t *prot);
static void radius_eap_tls_sec_prot_create_request(sec_prot_t *prot, sec_prot_keys_t *sec_keys);
static void radius_eap_tls_sec_prot_delete(sec_prot_t *prot);
static int8_t radius_eap_tls_sec_prot_receive(sec_prot_t *prot, void *pdu, uint16_t size);
static int8_t radius_eap_tls_sec_prot_radius_client_receive(sec_prot_t *radius_client, void *pdu, uint16_t size);
static int8_t radius_eap_tls_sec_prot_radius_eap_message_forward(sec_prot_t *prot, uint8_t *eap_code);
static void radius_eap_tls_sec_prot_state_machine(sec_prot_t *prot);
static int8_t radius_eap_tls_sec_prot_message_handle(sec_prot_t *prot, uint8_t *data_ptr, uint16_t *length);
static int8_t radius_eap_tls_sec_prot_message_send(sec_prot_t *prot, uint8_t eap_code, uint8_t eap_type, uint8_t tls_state);
static void radius_eap_tls_sec_prot_timer_timeout(sec_prot_t *prot, uint16_t ticks);
static int8_t radius_eap_tls_sec_prot_init_radius_client(sec_prot_t *prot);
static void radius_eap_tls_sec_prot_seq_id_update(sec_prot_t *prot);
#define eap_tls_sec_prot_get(prot) (radius_eap_tls_sec_prot_int_t *) &prot->data
int8_t radius_eap_tls_sec_prot_register(kmp_service_t *service)
{
if (!service) {
return -1;
}
if (kmp_service_sec_protocol_register(service, RADIUS_IEEE_802_1X_MKA, radius_eap_tls_sec_prot_size, radius_eap_tls_sec_prot_init) < 0) {
return -1;
}
return 0;
}
static uint16_t radius_eap_tls_sec_prot_size(void)
{
return sizeof(radius_eap_tls_sec_prot_int_t);
}
static int8_t radius_eap_tls_sec_prot_init(sec_prot_t *prot)
{
prot->create_req = radius_eap_tls_sec_prot_create_request;
prot->create_resp = 0;
prot->receive = radius_eap_tls_sec_prot_receive;
prot->receive_peer = radius_eap_tls_sec_prot_radius_client_receive;
prot->delete = radius_eap_tls_sec_prot_delete;
prot->state_machine = radius_eap_tls_sec_prot_state_machine;
prot->timer_timeout = radius_eap_tls_sec_prot_timer_timeout;
prot->receive_peer_hdr_size += EAPOL_BASE_LENGTH; // 4 bytes of EAPOL data
radius_eap_tls_sec_prot_int_t *data = eap_tls_sec_prot_get(prot);
sec_prot_init(&data->common);
sec_prot_state_set(prot, &data->common, EAP_TLS_STATE_INIT);
data->radius_client_prot = NULL;
data->burst_filt_timer = BURST_FILTER_TIMER_TIMEOUT;
data->eap_id_seq = 0;
data->recv_eap_id_seq = 0;
data->eap_code = 0;
data->eap_type = 0;
eap_tls_sec_prot_lib_message_init(&data->tls_send);
data->init_key_cnt = 0;
return 0;
}
static void radius_eap_tls_sec_prot_delete(sec_prot_t *prot)
{
radius_eap_tls_sec_prot_int_t *data = eap_tls_sec_prot_get(prot);
eap_tls_sec_prot_lib_message_free(&data->tls_send);
}
static void radius_eap_tls_sec_prot_create_request(sec_prot_t *prot, sec_prot_keys_t *sec_keys)
{
prot->sec_keys = sec_keys;
// Call state machine
prot->state_machine_call(prot);
}
static int8_t radius_eap_tls_sec_prot_receive(sec_prot_t *prot, void *pdu, uint16_t size)
{
radius_eap_tls_sec_prot_int_t *data = eap_tls_sec_prot_get(prot);
int8_t ret_val = -1;
// Decoding is successful
if (eapol_parse_pdu_header(pdu, size, &data->recv_eapol_pdu)) {
// Handle EAP messages
if (data->recv_eapol_pdu.packet_type == EAPOL_EAP_TYPE) {
data->eap_code = data->recv_eapol_pdu.msg.eap.eap_code;
data->eap_type = data->recv_eapol_pdu.msg.eap.type;
// Call state machine
prot->state_machine(prot);
} else if (data->recv_eapol_pdu.packet_type == EAPOL_KEY_TYPE &&
sec_prot_state_get(&data->common) == EAP_TLS_STATE_RESPONSE_ID) {
/* If initial EAPOL-key transmission arrives to first EAP-TLS wait state i.e.
* when waiting for identity response, triggers re-transmission of identity
* request. This allows the supplicant to start EAP-TLS right away, if it has
* missed the original identity request.
*/
if (data->burst_filt_timer == 0 && data->init_key_cnt < INITIAL_EAPOL_KEY_MAX_COUNT) {
tr_info("EAP-TLS: initial EAPOL-key recv, eui-64: %s", trace_array(sec_prot_remote_eui_64_addr_get(prot), 8));
sec_prot_result_set(&data->common, SEC_RESULT_TIMEOUT);
// Call state machine
prot->state_machine(prot);
// Resets trickle timer to give time for supplicant to answer
sec_prot_timer_trickle_start(&data->common, &prot->sec_cfg->prot_cfg.sec_prot_trickle_params);
data->init_key_cnt++;
}
// Filters repeated initial EAPOL-key messages
data->burst_filt_timer = BURST_FILTER_TIMER_TIMEOUT;
}
ret_val = 0;
}
memset(&data->recv_eapol_pdu, 0, sizeof(eapol_pdu_t));
data->eap_code = 0;
data->eap_type = 0;
return ret_val;
}
static int8_t radius_eap_tls_sec_prot_message_handle(sec_prot_t *prot, uint8_t *data_ptr, uint16_t *length)
{
radius_eap_tls_sec_prot_int_t *data = eap_tls_sec_prot_get(prot);
data_ptr = data->recv_eapol_pdu.msg.eap.data_ptr;
*length = data->recv_eapol_pdu.msg.eap.length;
bool old_seq_id = false;
// Already received sequence ID is received again, ignore
if (data->recv_eapol_pdu.msg.eap.id_seq < data->eap_id_seq) {
old_seq_id = true;
} else if (data->recv_eapol_pdu.msg.eap.id_seq == data->eap_id_seq) {
// Confirmation that supplicant has received the message, proceed with protocol
data->recv_eap_id_seq = data->recv_eapol_pdu.msg.eap.id_seq;
data->eap_id_seq++;
}
tr_info("EAP-TLS: recv %s type %s id %i flags %x len %i, eui-64 %s", eap_msg_trace[data->eap_code - 1],
data->eap_type == EAP_IDENTITY ? "IDENTITY" : "TLS", data->recv_eapol_pdu.msg.eap.id_seq,
*length >= 6 ? data_ptr[0] : 0, *length, trace_array(sec_prot_remote_eui_64_addr_get(prot), 8));
if (old_seq_id) {
return EAP_TLS_MSG_DECODE_ERROR;
}
if (data->eap_type == EAP_IDENTITY) {
return EAP_TLS_MSG_IDENTITY;
}
if (!data_ptr || *length < 6) {
tr_error("EAP-TLS: decode error");
return EAP_TLS_MSG_DECODE_ERROR;
}
return EAP_TLS_MSG_CONTINUE;
}
static int8_t radius_eap_tls_sec_prot_message_send(sec_prot_t *prot, uint8_t eap_code, uint8_t eap_type, uint8_t tls_state)
{
radius_eap_tls_sec_prot_int_t *data = eap_tls_sec_prot_get(prot);
uint8_t flags = 0xff;
// EAP-TLS flags field is always present during TLS exchange
if (tls_state == EAP_TLS_EXCHANGE_ONGOING) {
flags = 0x00;
}
if (eap_code == EAP_REQ) {
if (eap_type == EAP_TLS && tls_state == EAP_TLS_EXCHANGE_START) {
eap_tls_sec_prot_lib_message_allocate(&data->tls_send, TLS_HEAD_LEN, 0);
flags = EAP_TLS_START;
}
} else if (eap_code == EAP_SUCCESS || eap_code == EAP_FAILURE) {
// Send Success and Failure with same identifier as received in EAP Response
data->eap_id_seq = data->recv_eap_id_seq;
} else {
return -1;
}
uint16_t eapol_pdu_size;
uint8_t *eapol_decoded_data = eap_tls_sec_prot_lib_message_build(eap_code, eap_type, &flags, data->eap_id_seq, prot->header_size, &data->tls_send, &eapol_pdu_size);
if (!eapol_decoded_data) {
return -1;
}
tr_info("EAP-TLS: send %s type %s id %i flags %x len %i, eui-64: %s", eap_msg_trace[eap_code - 1],
eap_type == EAP_IDENTITY ? "IDENTITY" : "TLS", data->eap_id_seq, flags, eapol_pdu_size,
trace_array(sec_prot_remote_eui_64_addr_get(prot), 8));
if (prot->send(prot, eapol_decoded_data, eapol_pdu_size + prot->header_size) < 0) {
return -1;
}
return 0;
}
static int8_t radius_eap_tls_sec_prot_radius_eap_message_forward(sec_prot_t *prot, uint8_t *eap_code)
{
radius_eap_tls_sec_prot_int_t *data = eap_tls_sec_prot_get(prot);
uint16_t eap_pdu_len = data->recv_eap_msg_len - prot->receive_peer_hdr_size;
uint8_t *eap_pdu = data->recv_eap_msg + prot->receive_peer_hdr_size;
if (eap_pdu_len < 4) {
return -1;
}
*eap_code = *eap_pdu++;
uint8_t eap_id_seq = *eap_pdu++;
uint16_t eap_len = common_read_16_bit(eap_pdu);
eap_pdu += 2;
if (eap_pdu_len != eap_len) {
return -1;
}
uint16_t eap_body_len = eap_len;
uint8_t eap_type = 0;
uint8_t flags = 0;
uint8_t *tls_ptr = NULL;
if (*eap_code == EAP_REQ || *eap_code == EAP_RESPONSE) {
eap_type = *eap_pdu++;
eap_body_len--;
if (eap_type == EAP_TLS && eap_len >= 5) {
tls_ptr = eap_pdu;
flags = *tls_ptr;
}
}
eapol_pdu_t eapol_pdu;
uint16_t eapol_pdu_size = eapol_pdu_eap_frame_init(&eapol_pdu, *eap_code, eap_id_seq, eap_type, eap_body_len, tls_ptr);
if (eapol_pdu_size - EAPOL_BASE_LENGTH != eap_len) {
return -1;
}
eapol_write_pdu_frame(data->recv_eap_msg + prot->header_size, &eapol_pdu);
tr_info("EAP-TLS: send %s type %s id %i flags %x len %i, eui-64: %s", eap_msg_trace[*eap_code - 1],
eap_type == EAP_IDENTITY ? "IDENTITY" : "TLS", data->eap_id_seq, flags, eapol_pdu_size,
trace_array(sec_prot_remote_eui_64_addr_get(prot), 8));
if (prot->send(prot, data->recv_eap_msg, eapol_pdu_size + prot->header_size) < 0) {
return -1;
}
return 0;
}
static void radius_eap_tls_sec_prot_timer_timeout(sec_prot_t *prot, uint16_t ticks)
{
radius_eap_tls_sec_prot_int_t *data = eap_tls_sec_prot_get(prot);
if (data->burst_filt_timer > ticks) {
data->burst_filt_timer -= ticks;
} else {
data->burst_filt_timer = 0;
}
sec_prot_timer_timeout_handle(prot, &data->common,
&prot->sec_cfg->prot_cfg.sec_prot_trickle_params, ticks);
}
static int8_t radius_eap_tls_sec_prot_radius_client_receive(sec_prot_t *radius_client, void *pdu, uint16_t size)
{
sec_prot_t *prot = radius_client->type_get(radius_client, SEC_PROT_TYPE_RADIUS_EAP_TLS);
if (!prot) {
return -1;
}
radius_eap_tls_sec_prot_int_t *data = eap_tls_sec_prot_get(prot);
data->recv_eap_msg_len = size;
data->recv_eap_msg = pdu;
prot->state_machine_call(prot);
return 0;
}
static int8_t radius_eap_tls_sec_prot_init_radius_client(sec_prot_t *prot)
{
radius_eap_tls_sec_prot_int_t *data = eap_tls_sec_prot_get(prot);
if (data->radius_client_prot) {
return 0;
}
data->radius_client_prot = prot->type_get(prot, SEC_PROT_TYPE_RADIUS_CLIENT);
if (!data->radius_client_prot) {
return -1;
}
data->radius_client_send = data->radius_client_prot->receive_peer;
return 0;
}
static void radius_eap_tls_sec_prot_state_machine(sec_prot_t *prot)
{
radius_eap_tls_sec_prot_int_t *data = eap_tls_sec_prot_get(prot);
uint8_t *data_ptr = NULL;
uint16_t length = 0;
// EAP-TLS authenticator state machine
switch (sec_prot_state_get(&data->common)) {
case EAP_TLS_STATE_INIT:
tr_info("EAP-TLS init");
sec_prot_state_set(prot, &data->common, EAP_TLS_STATE_CREATE_REQ);
prot->timer_start(prot);
break;
// Wait KMP-CREATE.request
case EAP_TLS_STATE_CREATE_REQ:
tr_info("EAP-TLS start, eui-64: %s", trace_array(sec_prot_remote_eui_64_addr_get(prot), 8));
// Set default timeout for the total maximum length of the negotiation
sec_prot_default_timeout_set(&data->common);
// KMP-CREATE.confirm
prot->create_conf(prot, SEC_RESULT_OK);
// Increment sequence ID
radius_eap_tls_sec_prot_seq_id_update(prot);
// Sends EAP request, Identity
radius_eap_tls_sec_prot_message_send(prot, EAP_REQ, EAP_IDENTITY, EAP_TLS_EXCHANGE_NONE);
// Start trickle timer to re-send if no response
sec_prot_timer_trickle_start(&data->common, &prot->sec_cfg->prot_cfg.sec_prot_trickle_params);
sec_prot_state_set(prot, &data->common, EAP_TLS_STATE_RESPONSE_ID);
break;
// Wait EAP response, Identity
case EAP_TLS_STATE_RESPONSE_ID:
// On timeout
if (sec_prot_result_timeout_check(&data->common)) {
// Re-sends EAP request, Identity
radius_eap_tls_sec_prot_message_send(prot, EAP_REQ, EAP_IDENTITY, EAP_TLS_EXCHANGE_NONE);
return;
}
// Handle EAP response (expected Identity)
if (radius_eap_tls_sec_prot_message_handle(prot, data_ptr, &length) != EAP_TLS_MSG_IDENTITY) {
return;
}
tr_info("EAP-TLS EAP response id, eui-64: %s", trace_array(sec_prot_remote_eui_64_addr_get(prot), 8));
if (radius_eap_tls_sec_prot_init_radius_client(prot) < 0) {
tr_error("EAP-TLS: radius client init failed");
return;
}
// Send to radius client
data->radius_client_send(data->radius_client_prot, (void *) &data->recv_eapol_pdu, length);
sec_prot_state_set(prot, &data->common, EAP_TLS_STATE_EAP_REQUEST);
break;
// Wait EAP request
case EAP_TLS_STATE_EAP_REQUEST:
// On timeout
if (sec_prot_result_timeout_check(&data->common)) {
// Do nothing for now
return;
}
tr_info("EAP-TLS EAP request, eui-64: %s", trace_array(sec_prot_remote_eui_64_addr_get(prot), 8));
uint8_t eap_code;
if (radius_eap_tls_sec_prot_radius_eap_message_forward(prot, &eap_code) < 0) {
tr_error("EAP-TLS: EAP message forward failed");
return;
}
if (eap_code == EAP_SUCCESS) {
sec_prot_result_set(&data->common, SEC_RESULT_OK);
sec_prot_state_set(prot, &data->common, EAP_TLS_STATE_FINISH);
} else if (eap_code == EAP_FAILURE) {
sec_prot_result_set(&data->common, SEC_RESULT_ERROR);
sec_prot_state_set(prot, &data->common, EAP_TLS_STATE_FINISH);
}
sec_prot_state_set(prot, &data->common, EAP_TLS_STATE_EAP_RESPONSE);
break;
// Wait EAP response
case EAP_TLS_STATE_EAP_RESPONSE:
// On timeout
if (sec_prot_result_timeout_check(&data->common)) {
// Do nothing for now
return;
}
tr_info("EAP-TLS EAP response, eui-64: %s", trace_array(sec_prot_remote_eui_64_addr_get(prot), 8));
// Handle EAP response
if (radius_eap_tls_sec_prot_message_handle(prot, data_ptr, &length) != EAP_TLS_MSG_CONTINUE) {
return;
}
// Send to radius client
data->radius_client_send(data->radius_client_prot, (void *) &data->recv_eapol_pdu, length);
sec_prot_state_set(prot, &data->common, EAP_TLS_STATE_EAP_REQUEST);
break;
case EAP_TLS_STATE_FINISH:
tr_info("EAP-TLS finish, eui-64: %s", trace_array(sec_prot_remote_eui_64_addr_get(prot), 8));
// KMP-FINISHED.indication,
prot->finished_ind(prot, sec_prot_result_get(&data->common), prot->sec_keys);
sec_prot_state_set(prot, &data->common, EAP_TLS_STATE_FINISHED);
break;
case EAP_TLS_STATE_FINISHED: {
uint8_t *remote_eui_64 = sec_prot_remote_eui_64_addr_get(prot);
tr_info("EAP-TLS finished, eui-64: %s", remote_eui_64 ? trace_array(sec_prot_remote_eui_64_addr_get(prot), 8) : "not set");
prot->timer_stop(prot);
prot->finished(prot);
break;
}
default:
break;
}
}
static void radius_eap_tls_sec_prot_seq_id_update(sec_prot_t *prot)
{
radius_eap_tls_sec_prot_int_t *data = eap_tls_sec_prot_get(prot);
data->eap_id_seq++;
}
#endif /* HAVE_WS */

View File

@ -0,0 +1,36 @@
/*
* Copyright (c) 2020, Arm Limited and affiliates.
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef RADIUS_EAP_TLS_SEC_PROT_H_
#define RADIUS_EAP_TLS_SEC_PROT_H_
/*
* Authenticator RADIUS EAP-TLS security protocol. Specified in RFC 5216.
*
*/
/**
* radius_eap_tls_sec_prot_register register authenticator EAP-TLS protocol to KMP service
*
* \param service KMP service
*
* \return < 0 failure
* \return >= 0 success
*/
int8_t radius_eap_tls_sec_prot_register(kmp_service_t *service);
#endif /* RADIUS_EAP_TLS_SEC_PROT_H_ */

View File

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

View File

@ -36,7 +36,7 @@
#include "Security/protocols/sec_prot.h"
#include "Security/protocols/sec_prot_lib.h"
#include "Security/protocols/fwh_sec_prot/auth_fwh_sec_prot.h"
#include "Service_Libs/hmac/hmac_sha1.h"
#include "Service_Libs/hmac/hmac_md.h"
#include "Service_Libs/nist_aes_kw/nist_aes_kw.h"
#ifdef HAVE_WS
@ -234,7 +234,7 @@ static int8_t auth_fwh_sec_prot_message_send(sec_prot_t *prot, fwh_sec_prot_msg_
switch (msg) {
case FWH_MESSAGE_1: {
uint8_t pmkid[PMKID_LEN];
if (sec_prot_lib_pmkid_generate(prot, pmkid, true) < 0) {
if (sec_prot_lib_pmkid_generate(prot, pmkid, true, false, NULL) < 0) {
ns_dyn_mem_free(kde_start);
return -1;
}
@ -313,7 +313,7 @@ static int8_t auth_fwh_sec_prot_message_send(sec_prot_t *prot, fwh_sec_prot_msg_
static void auth_fwh_sec_prot_timer_timeout(sec_prot_t *prot, uint16_t ticks)
{
fwh_sec_prot_int_t *data = fwh_sec_prot_get(prot);
sec_prot_timer_timeout_handle(prot, &data->common, &prot->prot_cfg->sec_prot_trickle_params, ticks);
sec_prot_timer_timeout_handle(prot, &data->common, &prot->sec_cfg->prot_cfg.sec_prot_trickle_params, ticks);
}
static void auth_fwh_sec_prot_state_machine(sec_prot_t *prot)
@ -350,7 +350,7 @@ static void auth_fwh_sec_prot_state_machine(sec_prot_t *prot)
auth_fwh_sec_prot_message_send(prot, FWH_MESSAGE_1);
// Start trickle timer to re-send if no response
sec_prot_timer_trickle_start(&data->common, &prot->prot_cfg->sec_prot_trickle_params);
sec_prot_timer_trickle_start(&data->common, &prot->sec_cfg->prot_cfg.sec_prot_trickle_params);
sec_prot_state_set(prot, &data->common, FWH_STATE_MESSAGE_2);
break;
@ -378,7 +378,7 @@ static void auth_fwh_sec_prot_state_machine(sec_prot_t *prot)
auth_fwh_sec_prot_message_send(prot, FWH_MESSAGE_3);
// Start trickle timer to re-send if no response
sec_prot_timer_trickle_start(&data->common, &prot->prot_cfg->sec_prot_trickle_params);
sec_prot_timer_trickle_start(&data->common, &prot->sec_cfg->prot_cfg.sec_prot_trickle_params);
sec_prot_state_set(prot, &data->common, FWH_STATE_MESSAGE_4);
}
@ -406,7 +406,7 @@ static void auth_fwh_sec_prot_state_machine(sec_prot_t *prot)
// Reset PTK mismatch
sec_prot_keys_ptk_mismatch_reset(prot->sec_keys);
// Update PTK
sec_prot_keys_ptk_write(prot->sec_keys, data->new_ptk, prot->timer_cfg->ptk_lifetime);
sec_prot_keys_ptk_write(prot->sec_keys, data->new_ptk, prot->sec_cfg->timer_cfg.ptk_lifetime);
sec_prot_keys_ptk_eui_64_write(prot->sec_keys, data->remote_eui64);
sec_prot_state_set(prot, &data->common, FWH_STATE_FINISH);
}

View File

@ -35,7 +35,7 @@
#include "Security/protocols/sec_prot.h"
#include "Security/protocols/sec_prot_lib.h"
#include "Security/protocols/fwh_sec_prot/supp_fwh_sec_prot.h"
#include "Service_Libs/hmac/hmac_sha1.h"
#include "Service_Libs/hmac/hmac_md.h"
#include "Service_Libs/nist_aes_kw/nist_aes_kw.h"
#ifdef HAVE_WS
@ -139,7 +139,7 @@ static int8_t supp_fwh_sec_prot_init(sec_prot_t *prot)
sec_prot_init(&data->common);
sec_prot_state_set(prot, &data->common, FWH_STATE_INIT);
data->common.ticks = prot->prot_cfg->sec_prot_retry_timeout;
data->common.ticks = prot->sec_cfg->prot_cfg.sec_prot_retry_timeout;
data->msg3_received = false;
data->msg3_retry_wait = false;
data->recv_replay_cnt = 0;
@ -337,7 +337,7 @@ static void supp_fwh_sec_prot_state_machine(sec_prot_t *prot)
if (sec_prot_result_ok_check(&data->common)) {
// Send 4WH message 2
supp_fwh_sec_prot_message_send(prot, FWH_MESSAGE_2);
data->common.ticks = prot->prot_cfg->sec_prot_retry_timeout;
data->common.ticks = prot->sec_cfg->prot_cfg.sec_prot_retry_timeout;
sec_prot_state_set(prot, &data->common, FWH_STATE_MESSAGE_3);
} else {
// Ready to be deleted
@ -365,7 +365,7 @@ static void supp_fwh_sec_prot_state_machine(sec_prot_t *prot)
// Send 4WH message 2
supp_fwh_sec_prot_message_send(prot, FWH_MESSAGE_2);
data->common.ticks = prot->prot_cfg->sec_prot_retry_timeout;
data->common.ticks = prot->sec_cfg->prot_cfg.sec_prot_retry_timeout;
return;
} else if (data->recv_msg != FWH_MESSAGE_3) {
return;
@ -392,7 +392,7 @@ static void supp_fwh_sec_prot_state_machine(sec_prot_t *prot)
// Sends 4WH Message 4
supp_fwh_sec_prot_message_send(prot, FWH_MESSAGE_4);
data->common.ticks = prot->prot_cfg->sec_prot_retry_timeout;
data->common.ticks = prot->sec_cfg->prot_cfg.sec_prot_retry_timeout;
sec_prot_state_set(prot, &data->common, FWH_STATE_FINISH);
break;
@ -409,7 +409,7 @@ static void supp_fwh_sec_prot_state_machine(sec_prot_t *prot)
tr_info("4WH: finish, wait Message 3 retry");
sec_prot_keys_ptk_write(prot->sec_keys, data->new_ptk, prot->timer_cfg->ptk_lifetime);
sec_prot_keys_ptk_write(prot->sec_keys, data->new_ptk, prot->sec_cfg->timer_cfg.ptk_lifetime);
sec_prot_keys_ptk_eui_64_write(prot->sec_keys, data->remote_eui64);
data->common.ticks = 60 * 10; // 60 seconds
@ -473,7 +473,7 @@ static int8_t supp_fwh_sec_prot_ptk_generate(sec_prot_t *prot, sec_prot_keys_t *
fwh_sec_prot_int_t *data = fwh_sec_prot_get(prot);
uint8_t local_eui64[8];
prot->addr_get(prot, local_eui64, data->remote_eui64);
prot->addr_get(prot, local_eui64, NULL);
uint8_t *remote_nonce = data->recv_eapol_pdu.msg.key.key_nonce;
if (!remote_nonce) {
@ -553,11 +553,24 @@ static int8_t supp_fwh_kde_handle(sec_prot_t *prot)
if (kde_pmkid_read(kde, kde_len, recv_pmkid) < 0) {
goto error;
}
if (sec_prot_lib_pmkid_generate(prot, calc_pmkid, false) < 0) {
/* Fix the used EUI-64 for the length of the 4WH handshake using the PMKID. Try
* first primary BR EUI-64 (e.g. validated by PTK procedure) for PMKID.
*/
if (sec_prot_lib_pmkid_generate(prot, calc_pmkid, false, false, data->remote_eui64) < 0) {
goto error;
}
// If PMKID is not valid
if (memcmp(recv_pmkid, calc_pmkid, PMKID_LEN) != 0) {
goto error;
tr_info("PMKID mismatch, 1st EUI-64: %s", tr_array(data->remote_eui64, 8));
// Try alternate EUI-64 (e.g. received during security handshake)
if (sec_prot_lib_pmkid_generate(prot, calc_pmkid, false, true, data->remote_eui64) < 0) {
goto error;
}
// If PMKID is not valid, fail
if (memcmp(recv_pmkid, calc_pmkid, PMKID_LEN) != 0) {
tr_error("PMKID mismatch, 2nd EUI-64: %s", tr_array(data->remote_eui64, 8));
goto error;
}
}
}
break;

View File

@ -261,7 +261,7 @@ static int8_t auth_gkh_sec_prot_message_send(sec_prot_t *prot, gkh_sec_prot_msg_
static void auth_gkh_sec_prot_timer_timeout(sec_prot_t *prot, uint16_t ticks)
{
gkh_sec_prot_int_t *data = gkh_sec_prot_get(prot);
sec_prot_timer_timeout_handle(prot, &data->common, &prot->prot_cfg->sec_prot_trickle_params, ticks);
sec_prot_timer_timeout_handle(prot, &data->common, &prot->sec_cfg->prot_cfg.sec_prot_trickle_params, ticks);
}
static void auth_gkh_sec_prot_state_machine(sec_prot_t *prot)
@ -290,7 +290,7 @@ static void auth_gkh_sec_prot_state_machine(sec_prot_t *prot)
auth_gkh_sec_prot_message_send(prot, GKH_MESSAGE_1);
// Start trickle timer to re-send if no response
sec_prot_timer_trickle_start(&data->common, &prot->prot_cfg->sec_prot_trickle_params);
sec_prot_timer_trickle_start(&data->common, &prot->sec_cfg->prot_cfg.sec_prot_trickle_params);
sec_prot_state_set(prot, &data->common, GKH_STATE_MESSAGE_2);

View File

@ -171,7 +171,7 @@ static int8_t key_sec_prot_initial_key_send(sec_prot_t *prot, sec_prot_keys_t *s
uint8_t *pmk = sec_prot_keys_pmk_get(sec_keys);
uint8_t pmkid[PMKID_LEN];
if (pmk) {
if (sec_prot_lib_pmkid_generate(prot, pmkid, false) >= 0) {
if (sec_prot_lib_pmkid_generate(prot, pmkid, false, false, NULL) >= 0) {
kde_len += KDE_PMKID_LEN;
} else {
pmk = NULL;
@ -270,7 +270,7 @@ static int8_t key_sec_prot_receive(sec_prot_t *prot, void *pdu, uint16_t size)
if (kde_pmkid_read(kde, kde_len, remote_keyid) >= 0) {
tr_debug("recv PMKID: %s", trace_array(remote_keyid, 16));
uint8_t pmkid[PMKID_LEN];
if (sec_prot_lib_pmkid_generate(prot, pmkid, true) >= 0) {
if (sec_prot_lib_pmkid_generate(prot, pmkid, true, false, NULL) >= 0) {
if (memcmp(remote_keyid, pmkid, PMKID_LEN) == 0) {
prot->sec_keys->pmk_mismatch = false;
}

View File

@ -0,0 +1,259 @@
/*
* Copyright (c) 2020, Arm Limited and affiliates.
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "nsconfig.h"
#include "ns_types.h"
#include "eventOS_event.h"
#include "ns_trace.h"
#include "string.h"
#include "common_functions.h"
#include "Security/protocols/radius_sec_prot/avp_helper.h"
#ifdef HAVE_WS
#define TRACE_GROUP "avp"
// RFC 2865
// 1 User-Name
#define AVP_TYPE_USER_NAME 1
// 4 for NAS-IP-Address
#define AVP_TYPE_NAS_IP_ADDRESS 4
// 5 NAS-Port
#define AVP_TYPE_NAS_PORT 5
// 12 Framed-MTU
#define AVP_TYPE_FRAMED_MTU 12
// 24 State
#define AVP_TYPE_STATE 24
// 26 Vendor-Specific
#define AVP_TYPE_VENDOR_SPECIFIC 26
// 30 Called-Station-Id
#define AVP_TYPE_CALLED_STATION_ID 30
// 31 Calling-Station-Id
#define AVP_TYPE_CALLING_STATION_ID 31
// 32 NAS-Identifier
#define AVP_TYPE_NAS_IDENTIFIER 32
// 61 NAS-Port-Type
#define AVP_TYPE_NAS_PORT_TYPE 61
// RFC 3579
// 79 EAP-Message
#define AVP_TYPE_EAP_MESSAGE 79
// 80 Message-Authenticator
#define AVP_TYPE_MESSAGE_AUTHENTICATOR 80
// RFC 3162
// 95 NAS-IPv6-Address
#define AVP_TYPE_NAS_IPV6_ADDRESS 95
static uint8_t *avp_header_write(uint8_t *ptr, const uint8_t type, const uint8_t data_length)
{
*ptr++ = type;
*ptr++ = data_length + AVP_FIXED_LEN;
return ptr;
}
static uint8_t *avp_search(uint8_t *ptr, uint16_t len, const uint8_t type, uint8_t *avp_len)
{
while (len >= AVP_FIXED_LEN) {
*avp_len = ptr[1];
// Validates length field
if (*avp_len > len) {
return NULL;
}
if (ptr[0] == type) {
return ptr + AVP_FIXED_LEN;
}
if (len > *avp_len) {
len -= *avp_len;
ptr += *avp_len;
} else {
return NULL;
}
}
return NULL;
}
static uint8_t *avp_vpa_search(uint8_t *ptr, uint16_t len, const uint32_t vendor_id, const uint8_t vendor_type, uint8_t *vendor_len)
{
uint8_t avp_len = 0;
while (len >= AVP_FIXED_LEN) {
avp_len = ptr[1];
// Validates length field
if (avp_len > len) {
return NULL;
}
if (ptr[0] == AVP_TYPE_VENDOR_SPECIFIC && avp_len >= 9) {
ptr[2] = 0;
uint32_t avp_vendor_id = common_read_32_bit(&ptr[2]);
*vendor_len = ptr[7];
if (avp_vendor_id == vendor_id && ptr[6] == vendor_type) {
return &ptr[8];
}
}
if (len > avp_len) {
len -= avp_len;
ptr += avp_len;
} else {
return NULL;
}
}
return NULL;
}
uint8_t *avp_user_name_write(uint8_t *ptr, const uint8_t name_len, const uint8_t *name)
{
ptr = avp_header_write(ptr, AVP_TYPE_USER_NAME, name_len);
memcpy(ptr, name, name_len);
return ptr + name_len;
}
uint8_t *avp_nas_ip_address_write(uint8_t *ptr, uint32_t addr)
{
ptr = avp_header_write(ptr, AVP_TYPE_NAS_IP_ADDRESS, 4);
memcpy(ptr, &addr, 4);
return ptr + 4;
}
uint8_t *avp_nas_port_write(uint8_t *ptr, const uint32_t port)
{
ptr = avp_header_write(ptr, AVP_TYPE_NAS_PORT, 4);
ptr = common_write_32_bit(port, ptr);
return ptr;
}
uint8_t *avp_framed_mtu_write(uint8_t *ptr, const uint32_t mtu)
{
ptr = avp_header_write(ptr, AVP_TYPE_FRAMED_MTU, 4);
ptr = common_write_32_bit(mtu, ptr);
return ptr;
}
uint8_t *avp_state_write(uint8_t *ptr, const uint8_t state_len, const uint8_t *state)
{
ptr = avp_header_write(ptr, AVP_TYPE_STATE, state_len);
memcpy(ptr, state, state_len);
return ptr + state_len;
}
uint8_t *avp_called_station_id_write(uint8_t *ptr, const uint8_t id_len, const uint8_t *id)
{
ptr = avp_header_write(ptr, AVP_TYPE_CALLED_STATION_ID, id_len);
memcpy(ptr, id, id_len);
return ptr + id_len;
}
uint8_t *avp_calling_station_id_write(uint8_t *ptr, const uint8_t id_len, const uint8_t *id)
{
ptr = avp_header_write(ptr, AVP_TYPE_CALLING_STATION_ID, id_len);
memcpy(ptr, id, id_len);
return ptr + id_len;
}
uint8_t *avp_nas_identifier_write(uint8_t *ptr, const uint8_t id_len, const uint8_t *id)
{
ptr = avp_header_write(ptr, AVP_TYPE_NAS_IDENTIFIER, id_len);
memcpy(ptr, id, id_len);
return ptr + id_len;
}
uint8_t *avp_nas_port_type_write(uint8_t *ptr, const uint32_t port_type)
{
ptr = avp_header_write(ptr, AVP_TYPE_NAS_PORT_TYPE, 4);
ptr = common_write_32_bit(port_type, ptr);
return ptr;
}
uint8_t *avp_eap_message_write(uint8_t *ptr, const uint8_t eap_len, const uint8_t *eap)
{
ptr = avp_header_write(ptr, AVP_TYPE_EAP_MESSAGE, eap_len);
memcpy(ptr, eap, eap_len);
return ptr + eap_len;
}
uint8_t *avp_message_authenticator_write(uint8_t *ptr, const uint8_t *auth)
{
ptr = avp_header_write(ptr, AVP_TYPE_MESSAGE_AUTHENTICATOR, 16);
memcpy(ptr, auth, 16);
return ptr + 16;
}
uint8_t *avp_nas_ipv6_address_write(uint8_t *ptr, const uint8_t *address)
{
ptr = avp_header_write(ptr, AVP_TYPE_NAS_IPV6_ADDRESS, 16);
memcpy(ptr, address, 16);
return ptr + 16;
}
uint8_t *avp_eap_message_read(uint8_t *ptr, uint16_t len, uint8_t *eap_len)
{
ptr = avp_search(ptr, len, AVP_TYPE_EAP_MESSAGE, eap_len);
if (ptr == NULL) {
return NULL;
}
return ptr;
}
uint8_t *avp_message_authenticator_read(uint8_t *ptr, uint16_t len)
{
uint8_t auth_len = 0;
ptr = avp_search(ptr, len, AVP_TYPE_MESSAGE_AUTHENTICATOR, &auth_len);
if (ptr == NULL) {
return NULL;
}
if (auth_len < 18) {
return NULL;
}
return ptr;
}
uint8_t *avp_state_read(uint8_t *ptr, uint16_t len, uint8_t *state_len)
{
ptr = avp_search(ptr, len, AVP_TYPE_STATE, state_len);
if (ptr == NULL) {
return NULL;
}
return ptr;
}
uint8_t *avp_vsa_ms_mppe_recv_key_read(uint8_t *ptr, uint16_t len, uint8_t *recv_key_len)
{
const uint32_t vendor_id = 311;
const uint8_t vendor_type = 17;
ptr = avp_vpa_search(ptr, len, vendor_id, vendor_type, recv_key_len);
if (ptr == NULL) {
return NULL;
}
return ptr;
}
#endif

View File

@ -0,0 +1,239 @@
/*
* Copyright (c) 2020, Arm Limited and affiliates.
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef AVP_HELPER_H_
#define AVP_HELPER_H_
/*
* RADIUS AVP helper functions
*
*/
#define AVP_FIXED_LEN 2 // type, length
#define AVP_VALUE_MAX_LEN 253 // 255 - type field - length field
#define AVP_TYPE_USER_NAME_LEN(len) (AVP_FIXED_LEN + len)
#define AVP_TYPE_NAS_IP_ADDRESS_LEN (AVP_FIXED_LEN + 4)
#define AVP_TYPE_NAS_PORT_LEN (AVP_FIXED_LEN + 4)
#define AVP_TYPE_FRAMED_MTU_LEN (AVP_FIXED_LEN + 4)
#define AVP_TYPE_STATE_LEN (AVP_FIXED_LEN + 8)
//#define AVP_TYPE_VENDOR_SPECIFIC 26
#define AVP_TYPE_CALLED_STATION_ID_LEN(len) (AVP_FIXED_LEN + len)
#define AVP_TYPE_CALLING_STATION_ID_LEN(len) (AVP_FIXED_LEN + len)
#define AVP_TYPE_NAS_IDENTIFIER_LEN(len) (AVP_FIXED_LEN + len)
#define AVP_TYPE_NAS_PORT_TYPE_LEN (AVP_FIXED_LEN + 4)
#define AVP_TYPE_EAP_MESSAGE_LEN(len) (AVP_FIXED_LEN + len)
#define AVP_TYPE_MESSAGE_AUTHENTICATOR_LEN (AVP_FIXED_LEN + 16)
#define AVP_TYPE_NAS_IPV6_ADDRESS_LEN (AVP_FIXED_LEN + 16)
// Wireless - IEEE 802.11
#define NAS_PORT_TYPE_WIRELESS_IEEE802_11 19
// EUI-64 in ascii string: 00-11-..-77
#define STATION_ID_LEN 16 + 7
// MTU value TBD
#define FRAMED_MTU 1400
#define NAS_PORT 1
/**
* avp_user_name_write write use name
*
* \param ptr pointer where to write
* \param name_len name length
* \param name name
*
* return incremented write pointer
*
*/
uint8_t *avp_user_name_write(uint8_t *ptr, const uint8_t name_len, const uint8_t *name);
/**
* avp_nas_ip_address_write nas ip address
*
* \param ptr pointer where to write
* \param addr address
*
* return incremented write pointer
*
*/
uint8_t *avp_nas_ip_address_write(uint8_t *ptr, uint32_t addr);
/**
* avp_nas_port_write write nas port
*
* \param ptr pointer where to write
* \param port nas port
*
* return incremented write pointer
*
*/
uint8_t *avp_nas_port_write(uint8_t *ptr, const uint32_t port);
/**
* avp_framed_mtu_write write frame mtu
*
* \param ptr pointer where to write
* \param mtu frame mtu
*
* return incremented write pointer
*
*/
uint8_t *avp_framed_mtu_write(uint8_t *ptr, const uint32_t mtu);
/**
* avp_state_write write write state
*
* \param ptr pointer where to write
* \param state_len state length
* \param state state
*
* return incremented write pointer
*
*/
uint8_t *avp_state_write(uint8_t *ptr, const uint8_t state_len, const uint8_t *state);
/**
* avp_called_station_id_write write called station id
*
* \param ptr pointer where to write
* \param id_len identifier length
* \param id identifier
*
* return incremented write pointer
*
*/
uint8_t *avp_called_station_id_write(uint8_t *ptr, const uint8_t id_len, const uint8_t *id);
/**
* avp_calling_station_id_write write calling station id
*
* \param ptr pointer where to write
* \param id_len identifier length
* \param id identifier
*
* return incremented write pointer
*
*/
uint8_t *avp_calling_station_id_write(uint8_t *ptr, const uint8_t id_len, const uint8_t *id);
/**
* avp_nas_identifier_write write nas identifier
*
* \param ptr pointer where to write
* \param id_len nas identifier length
* \param id nas identifier
*
* return incremented write pointer
*
*/
uint8_t *avp_nas_identifier_write(uint8_t *ptr, const uint8_t id_len, const uint8_t *id);
/**
* avp_nas_port_type_write write nas port type
*
* \param ptr pointer where to write
* \param port_type port type
*
* return incremented write pointer
*
*/
uint8_t *avp_nas_port_type_write(uint8_t *ptr, const uint32_t port_type);
/**
* avp_nas_message_write write eap message
*
* \param ptr pointer where to write
* \param eap_len eap length
* \param eap eap frame
*
* return incremented write pointer
*
*/
uint8_t *avp_eap_message_write(uint8_t *ptr, const uint8_t eap_len, const uint8_t *eap);
/**
* avp_message_authenticator_write write message authenticator
*
* \param ptr pointer where to write
* \param auth authenticator
*
* return incremented write pointer
*
*/
uint8_t *avp_message_authenticator_write(uint8_t *ptr, const uint8_t *auth);
/**
* avp_nas_ipv6_address_write write ipv6 address
*
* \param ptr pointer where to write
* \param address ipv6 address
*
* return incremented write pointer
*
*/
uint8_t *avp_nas_ipv6_address_write(uint8_t *ptr, const uint8_t *address);
/**
* avp_eap_message_read read eap message
*
* \param ptr pointer to received message
* \param len received message length
* \param eap_len length of the eap frame
*
* return pointer to eap message or null
*
*/
uint8_t *avp_eap_message_read(uint8_t *ptr, uint16_t len, uint8_t *eap_len);
/**
* avp_message_authenticator_read read message authenticator
*
* \param ptr pointer to received message
* \param len received message length
*
* return pointer to message authenticator or null
*
*/
uint8_t *avp_message_authenticator_read(uint8_t *ptr, uint16_t len);
/**
* avp_state_read read state
*
* \param ptr pointer to received message
* \param len received message length
* \param state_len length of the state
*
* return pointer to state or null
*
*/
uint8_t *avp_state_read(uint8_t *ptr, uint16_t len, uint8_t *state_len);
/**
* avp_vsa_ms_mppe_recv_key_read read vendor specific MS-MPPE-Recv-Key
*
* \param ptr pointer to received message
* \param len received message length
* \param recv_key_len length of the state
*
* return pointer to MS-MPPE-Recv-Key or null
*
*/
uint8_t *avp_vsa_ms_mppe_recv_key_read(uint8_t *ptr, uint16_t len, uint8_t *recv_key_len);
#endif /* AVP_HELPER_H_ */

View File

@ -0,0 +1,995 @@
/*
* Copyright (c) 2020, Arm Limited and affiliates.
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "nsconfig.h"
#include <string.h>
#include "ns_types.h"
#include "ns_list.h"
#include "ns_trace.h"
#include "common_functions.h"
#include "nsdynmemLIB.h"
#include "randLIB.h"
#include "mbedtls/sha256.h"
#include "mbedtls/md5.h"
#include "fhss_config.h"
#include "Service_Libs/Trickle/trickle.h"
#include "NWK_INTERFACE/Include/protocol.h"
#include "6LoWPAN/ws/ws_config.h"
#include "Security/protocols/sec_prot_cfg.h"
#include "Security/kmp/kmp_addr.h"
#include "Security/kmp/kmp_api.h"
#include "Security/PANA/pana_eap_header.h"
#include "Security/eapol/eapol_helper.h"
#include "Security/protocols/sec_prot_certs.h"
#include "Security/protocols/sec_prot_keys.h"
#include "Security/protocols/sec_prot.h"
#include "Security/protocols/sec_prot_lib.h"
#include "Security/protocols/eap_tls_sec_prot/eap_tls_sec_prot_lib.h"
#include "Security/protocols/radius_sec_prot/radius_client_sec_prot.h"
#include "Security/protocols/radius_sec_prot/avp_helper.h"
#include "Security/protocols/tls_sec_prot/tls_sec_prot_lib.h"
#include "Service_Libs/hmac/hmac_md.h"
#ifdef HAVE_WS
#define TRACE_GROUP "radp"
typedef enum {
RADIUS_STATE_INIT = SEC_STATE_INIT,
RADIUS_STATE_CREATE_REQ = SEC_STATE_CREATE_REQ,
RADIUS_STATE_CREATE_RESP = SEC_STATE_CREATE_RESP,
RADIUS_STATE_CREATE_IND = SEC_STATE_CREATE_IND,
RADIUS_STATE_STATE_RESPONSE_ID = SEC_STATE_FIRST,
RADIUS_STATE_SEND_INITIAL_ACCESS_REQUEST,
RADIUS_STATE_SEND_ACCESS_REQUEST,
RADIUS_STATE_ACCESS_ACCEPT_REJECT_CHALLENGE,
RADIUS_STATE_ACCESS_REQUEST,
RADIUS_STATE_CONFIGURE,
RADIUS_STATE_PROCESS,
RADIUS_STATE_FINISH = SEC_STATE_FINISH,
RADIUS_STATE_FINISHED = SEC_STATE_FINISHED
} radius_client_sec_prot_state_e;
#define RADIUS_MSG_FIXED_LENGTH 20
#define RADIUS_ACCESS_REQUEST 1
#define RADIUS_ACCESS_ACCEPT 2
#define RADIUS_ACCESS_REJECT 3
#define RADIUS_ACCESS_CHALLENGE 11
#define MS_MPPE_RECV_KEY_SALT_LEN 2
#define MS_MPPE_RECV_KEY_BLOCK_LEN 16
typedef struct radius_client_sec_prot_lib_int_s radius_client_sec_prot_lib_int_t;
typedef struct {
sec_prot_common_t common; /**< Common data */
sec_prot_t *radius_eap_tls_prot; /**< Radius EAP-TLS security protocol */
sec_prot_receive *radius_eap_tls_send; /**< Radius EAP-TLS security protocol send (receive from peer) */
uint8_t radius_eap_tls_header_size; /**< Radius EAP-TLS header size */
uint8_t new_pmk[PMK_LEN]; /**< New Pair Wise Master Key */
uint16_t recv_eap_msg_len; /**< Received EAP message length */
uint8_t *recv_eap_msg; /**< Received EAP message */
uint16_t send_radius_msg_len; /**< Send radius message length */
uint8_t *send_radius_msg; /**< Send radius message */
uint8_t identity_len; /**< Supplicant EAP identity length */
uint8_t *identity; /**< Supplicant EAP identity */
uint8_t radius_code; /**< Radius code that was received */
uint8_t radius_identifier; /**< Radius identifier that was last sent */
uint8_t request_authenticator[16]; /**< Radius request authenticator that was last sent */
uint8_t state_len; /**< Radius state length that was last received */
uint8_t *state; /**< Radius state that was last received */
uint8_t remote_eui_64_hash[8]; /**< Remote EUI-64 hash used for calling station id */
bool remote_eui_64_hash_set : 1; /**< Remote EUI-64 hash used for calling station id set */
bool new_pmk_set : 1; /**< New Pair Wise Master Key set */
} radius_client_sec_prot_int_t;
typedef struct {
uint8_t radius_client_identifier; /**< Radius client identifier */
uint8_t local_eui64_hash[8]; /**< Local EUI-64 hash used for called stations id */
uint8_t hash_random[16]; /**< Random used to generate local and remote EUI-64 hashes */
bool local_eui64_hash_set : 1; /**< Local EUI-64 hash used for called stations id set */
bool hash_random_set : 1; /**< Random used to generate local and remote EUI-64 hashes set */
} radius_client_sec_prot_shared_t;
static uint16_t radius_client_sec_prot_size(void);
static int8_t radius_client_sec_prot_init(sec_prot_t *prot);
static void radius_client_sec_prot_create_response(sec_prot_t *prot, sec_prot_result_e result);
static void radius_client_sec_prot_delete(sec_prot_t *prot);
static int8_t radius_client_sec_prot_receive_check(sec_prot_t *prot, const void *pdu, uint16_t size);
static int8_t radius_client_sec_prot_init_radius_eap_tls(sec_prot_t *prot);
static uint16_t radius_client_sec_prot_eap_avps_handle(uint16_t avp_length, uint8_t *avp_ptr, uint8_t *copy_to_ptr);
static int8_t radius_client_sec_prot_receive(sec_prot_t *prot, void *pdu, uint16_t size);
static int8_t radius_client_sec_prot_radius_eap_receive(sec_prot_t *prot, void *pdu, uint16_t size);
static void radius_client_sec_prot_allocate_and_create_radius_message(sec_prot_t *prot);
static int8_t radius_client_sec_prot_radius_msg_send(sec_prot_t *prot);
static uint8_t radius_client_sec_prot_identifier_allocate(void);
static uint8_t radius_client_sec_prot_hex_to_ascii(uint8_t value);
static int8_t radius_client_sec_prot_eui_64_hash_generate(uint8_t *eui_64, uint8_t *hashed_eui_64);
static void radius_client_sec_prot_station_id_generate(uint8_t *eui_64, uint8_t *station_id_ptr);
static int8_t radius_client_sec_prot_message_authenticator_calc(sec_prot_t *prot, uint16_t msg_len, uint8_t *msg_ptr, uint8_t *auth_ptr);
static int8_t radius_client_sec_prot_response_authenticator_calc(sec_prot_t *prot, uint16_t msg_len, uint8_t *msg_ptr, uint8_t *auth_ptr);
static int8_t radius_client_sec_prot_ms_mppe_recv_key_pmk_decrypt(sec_prot_t *prot, uint8_t *recv_key, uint8_t recv_key_len, uint8_t *request_authenticator, uint8_t *pmk_ptr);
static void radius_client_sec_prot_finished_send(sec_prot_t *prot);
static void radius_client_sec_prot_state_machine(sec_prot_t *prot);
static void radius_client_sec_prot_timer_timeout(sec_prot_t *prot, uint16_t ticks);
#define radius_client_sec_prot_get(prot) (radius_client_sec_prot_int_t *) &prot->data
// Data shared between radius client instances
static radius_client_sec_prot_shared_t *shared_data = NULL;
int8_t radius_client_sec_prot_register(kmp_service_t *service)
{
if (!service) {
return -1;
}
if (kmp_service_sec_protocol_register(service, RADIUS_CLIENT_PROT, radius_client_sec_prot_size, radius_client_sec_prot_init) < 0) {
return -1;
}
return 0;
}
static uint16_t radius_client_sec_prot_size(void)
{
return sizeof(radius_client_sec_prot_int_t);
}
static int8_t radius_client_sec_prot_init(sec_prot_t *prot)
{
prot->create_req = NULL;
prot->create_resp = radius_client_sec_prot_create_response;
prot->receive = radius_client_sec_prot_receive;
prot->receive_peer = radius_client_sec_prot_radius_eap_receive;
prot->delete = radius_client_sec_prot_delete;
prot->state_machine = radius_client_sec_prot_state_machine;
prot->timer_timeout = radius_client_sec_prot_timer_timeout;
prot->finished_send = radius_client_sec_prot_finished_send;
prot->receive_check = radius_client_sec_prot_receive_check;
radius_client_sec_prot_int_t *data = radius_client_sec_prot_get(prot);
sec_prot_init(&data->common);
sec_prot_state_set(prot, &data->common, RADIUS_STATE_INIT);
data->radius_eap_tls_prot = NULL;
data->radius_eap_tls_send = NULL;
data->radius_eap_tls_header_size = 0;
memset(data->new_pmk, 0, PMK_LEN);
data->recv_eap_msg_len = 0;
data->recv_eap_msg = NULL;
data->send_radius_msg_len = 0;
data->send_radius_msg = NULL;
data->identity_len = 0;
data->identity = NULL;
data->radius_code = 0;
data->radius_identifier = 0;
memset(data->request_authenticator, 0, 16);
data->state_len = 0;
data->state = NULL;
memset(data->remote_eui_64_hash, 0, 8);
data->remote_eui_64_hash_set = false;
data->new_pmk_set = false;
if (!shared_data) {
shared_data = ns_dyn_mem_alloc(sizeof(radius_client_sec_prot_shared_t));
if (!shared_data) {
return -1;
}
shared_data->radius_client_identifier = 0;
memset(shared_data->local_eui64_hash, 0, 8);
memset(shared_data->hash_random, 0, 16);
shared_data->local_eui64_hash_set = false;
shared_data->hash_random_set = false;
}
return 0;
}
static void radius_client_sec_prot_delete(sec_prot_t *prot)
{
radius_client_sec_prot_int_t *data = radius_client_sec_prot_get(prot);
if (data->recv_eap_msg != NULL) {
ns_dyn_mem_free(data->recv_eap_msg);
}
if (data->send_radius_msg != NULL) {
ns_dyn_mem_free(data->send_radius_msg);
}
if (data->identity != NULL) {
ns_dyn_mem_free(data->identity);
}
if (data->state != NULL) {
ns_dyn_mem_free(data->state);
}
}
static void radius_client_sec_prot_create_response(sec_prot_t *prot, sec_prot_result_e result)
{
radius_client_sec_prot_int_t *data = radius_client_sec_prot_get(prot);
// Call state machine
sec_prot_result_set(&data->common, result);
prot->state_machine_call(prot);
}
static int8_t radius_client_sec_prot_receive_check(sec_prot_t *prot, const void *pdu, uint16_t size)
{
radius_client_sec_prot_int_t *data = radius_client_sec_prot_get(prot);
if (size >= 2) {
const uint8_t *radius_msg = pdu;
if (radius_msg[1] == data->radius_identifier) {
return 0;
}
}
return -1;
}
static int8_t radius_client_sec_prot_init_radius_eap_tls(sec_prot_t *prot)
{
radius_client_sec_prot_int_t *data = radius_client_sec_prot_get(prot);
if (data->radius_eap_tls_prot) {
return 0;
}
data->radius_eap_tls_prot = prot->type_get(prot, SEC_PROT_TYPE_RADIUS_EAP_TLS);
if (!data->radius_eap_tls_prot) {
return -1;
}
data->radius_eap_tls_header_size = data->radius_eap_tls_prot->receive_peer_hdr_size;
data->radius_eap_tls_send = data->radius_eap_tls_prot->receive_peer;
return 0;
}
static uint16_t radius_client_sec_prot_eap_avps_handle(uint16_t avp_length, uint8_t *avp_ptr, uint8_t *copy_to_ptr)
{
// Calculate EAP AVPs length and copy EAP AVPs to continuous buffer if buffer is give
uint16_t eap_len = 0;
while (true) {
uint8_t avp_eap_len;
uint8_t *eap_message = avp_eap_message_read(avp_ptr, avp_length, &avp_eap_len);
if (eap_message) {
avp_eap_len -= AVP_FIXED_LEN;
// Calculate EAP AVPs length
eap_len += avp_eap_len;
// Copy EAP AVPs to continuous buffer
if (copy_to_ptr) {
memcpy(copy_to_ptr, eap_message, avp_eap_len);
copy_to_ptr += avp_eap_len;
}
uint16_t offset = eap_message - avp_ptr;
avp_length = avp_length - (offset + avp_eap_len);
avp_ptr = eap_message + avp_eap_len;
} else {
break;
}
}
return eap_len;
}
static int8_t radius_client_sec_prot_receive(sec_prot_t *prot, void *pdu, uint16_t size)
{
radius_client_sec_prot_int_t *data = radius_client_sec_prot_get(prot);
if (size < RADIUS_MSG_FIXED_LENGTH) {
return -1;
}
uint8_t *radius_msg_ptr = pdu;
uint8_t code = *radius_msg_ptr++;
uint8_t identifier = *radius_msg_ptr++;
/* If identifier does not match to sent identifier, silently ignore message,
already checked on socket if before routing the request to receive, so
this is double check to ensure correct routing */
if (identifier != data->radius_identifier) {
return -1;
}
uint16_t length = common_read_16_bit(radius_msg_ptr);
radius_msg_ptr += 2;
// Store response authenticator
uint8_t recv_response_authenticator[16];
memcpy(recv_response_authenticator, radius_msg_ptr, 16);
// Replace response authenticator with request authenticator
memcpy(radius_msg_ptr, data->request_authenticator, 16);
radius_msg_ptr += 16;
// Calculate expected response authenticator
uint8_t calc_response_authenticator[16];
if (radius_client_sec_prot_response_authenticator_calc(prot, length, pdu, calc_response_authenticator) < 0) {
tr_error("Could not calculate response authenticator MD5 hash");
return -1;
}
// Verify that received and calculated response authenticator matches
if (memcmp(recv_response_authenticator, calc_response_authenticator, 16) != 0) {
tr_error("Invalid response authenticator recv: %s, calc: %s", tr_array(recv_response_authenticator, 16), tr_array(calc_response_authenticator, 16));
return -1;
}
uint16_t avp_length = length - RADIUS_MSG_FIXED_LENGTH;
uint8_t *message_authenticator = avp_message_authenticator_read(radius_msg_ptr, avp_length);
if (message_authenticator == NULL) {
tr_error("No message authenticator");
}
// Store message authenticator
uint8_t recv_message_authenticator[16];
memcpy(recv_message_authenticator, message_authenticator, 16);
// Replace message authenticator with zero
memset(message_authenticator, 0, 16);
// Calculate expected message authenticator
uint8_t calc_message_authenticator[16];
if (radius_client_sec_prot_message_authenticator_calc(prot, length, pdu, calc_message_authenticator) < 0) {
tr_error("Could not calculate message authenticator HMAC-MD5 hash");
return -1;
}
// Verify that received and calculated message authenticator matches
if (memcmp(recv_message_authenticator, calc_message_authenticator, 16) != 0) {
tr_error("Invalid message authenticator recv: %s, calc: %s", tr_array(recv_message_authenticator, 16), tr_array(calc_message_authenticator, 16));
return -1;
}
// Calculate EAP AVPs length
data->recv_eap_msg_len = radius_client_sec_prot_eap_avps_handle(avp_length, radius_msg_ptr, NULL);
if (data->recv_eap_msg_len == 0) {
return -1;
}
// Allocate memory for continuous EAP buffer
data->recv_eap_msg = ns_dyn_mem_temporary_alloc(data->recv_eap_msg_len + data->radius_eap_tls_header_size);
if (data->recv_eap_msg == NULL) {
tr_error("Cannot allocate eap msg");
return -1;
}
// Copy EAP AVPs to continuous buffer
uint16_t copy_eap_len = radius_client_sec_prot_eap_avps_handle(avp_length, radius_msg_ptr, data->recv_eap_msg + data->radius_eap_tls_header_size);
if (copy_eap_len != data->recv_eap_msg_len) {
ns_dyn_mem_free(data->recv_eap_msg);
return -1;
}
// Store state
uint8_t state_len;
uint8_t *state = avp_state_read(radius_msg_ptr, avp_length, &state_len);
if (state) {
state_len -= AVP_FIXED_LEN;
if (data->state && data->state_len != state_len) {
ns_dyn_mem_free(data->state);
data->state = NULL;
}
if (!data->state) {
data->state = ns_dyn_mem_temporary_alloc(state_len);
}
if (!data->state) {
tr_error("Cannot allocate state");
ns_dyn_mem_free(data->recv_eap_msg);
data->recv_eap_msg = NULL;
return -1;
}
memcpy(data->state, state, state_len);
data->state_len = state_len;
} else {
if (data->state) {
ns_dyn_mem_free(data->state);
data->state = NULL;
data->state_len = 0;
}
}
if (code == RADIUS_ACCESS_ACCEPT) {
uint8_t recv_key_len;
uint8_t *recv_key = avp_vsa_ms_mppe_recv_key_read(radius_msg_ptr, avp_length, &recv_key_len);
if (recv_key && recv_key_len > AVP_FIXED_LEN) {
if (radius_client_sec_prot_ms_mppe_recv_key_pmk_decrypt(prot, recv_key,
recv_key_len - AVP_FIXED_LEN, data->request_authenticator, data->new_pmk) >= 0) {
data->new_pmk_set = true;
tr_info("RADIUS PMK: %s %s", tr_array(data->new_pmk, 16), tr_array(data->new_pmk + 16, 16));
}
}
}
data->radius_code = code;
data->recv_eap_msg_len += data->radius_eap_tls_header_size;
prot->state_machine(prot);
return 0;
}
static int8_t radius_client_sec_prot_radius_eap_receive(sec_prot_t *prot, void *pdu, uint16_t size)
{
radius_client_sec_prot_int_t *data = radius_client_sec_prot_get(prot);
data->recv_eap_msg_len = size;
data->recv_eap_msg = pdu;
prot->state_machine(prot);
data->recv_eap_msg_len = 0;
data->recv_eap_msg = NULL;
return 0;
}
static uint8_t radius_client_sec_prot_identifier_allocate(void)
{
return shared_data->radius_client_identifier++;
}
static uint8_t radius_client_sec_prot_eui_64_hash_get(sec_prot_t *prot, uint8_t *local_eui_64_hash, uint8_t *remote_eui_64_hash, bool remote_eui_64_hash_set)
{
if (!shared_data->local_eui64_hash_set || !remote_eui_64_hash_set) {
uint8_t local_eui64[8];
uint8_t remote_eui64[8];
prot->addr_get(prot, local_eui64, remote_eui64);
if (!shared_data->local_eui64_hash_set) {
radius_client_sec_prot_eui_64_hash_generate(local_eui64, shared_data->local_eui64_hash);
shared_data->local_eui64_hash_set = true;
}
if (!remote_eui_64_hash_set) {
radius_client_sec_prot_eui_64_hash_generate(remote_eui64, remote_eui_64_hash);
}
}
memcpy(local_eui_64_hash, shared_data->local_eui64_hash, 8);
return 0;
}
static void radius_client_sec_prot_allocate_and_create_radius_message(sec_prot_t *prot)
{
radius_client_sec_prot_int_t *data = radius_client_sec_prot_get(prot);
// code(1), packet-identifier(1), length(2), authenticator(16)
uint16_t radius_msg_length = RADIUS_MSG_FIXED_LENGTH;
eapol_pdu_t *eap_hdr = (eapol_pdu_t *) data->recv_eap_msg;
if (eap_hdr->msg.eap.type == EAP_IDENTITY) {
uint16_t id_len = eap_hdr->msg.eap.length;
// Calculate identity length
if (id_len > 5) {
id_len -= 5;
}
// Maximum length is 253 bytes
if (id_len > AVP_VALUE_MAX_LEN) {
id_len = AVP_VALUE_MAX_LEN;
}
data->identity = ns_dyn_mem_temporary_alloc(id_len);
if (!data->identity) {
return;
}
data->identity_len = id_len;
memcpy(data->identity, eap_hdr->msg.eap.data_ptr, id_len);
}
// Calculate eap fragments
uint16_t eap_len = eap_hdr->msg.eap.length;
while (true) {
if (eap_len > AVP_VALUE_MAX_LEN) {
eap_len -= AVP_VALUE_MAX_LEN;
radius_msg_length += AVP_TYPE_EAP_MESSAGE_LEN(AVP_VALUE_MAX_LEN);
} else {
radius_msg_length += AVP_TYPE_EAP_MESSAGE_LEN(eap_len);
break;
}
}
radius_msg_length += AVP_TYPE_USER_NAME_LEN(data->identity_len);
radius_msg_length += AVP_TYPE_NAS_PORT_LEN;
radius_msg_length += AVP_TYPE_FRAMED_MTU_LEN;
if (data->state) {
radius_msg_length += AVP_FIXED_LEN + data->state_len;
}
radius_msg_length += AVP_TYPE_CALLED_STATION_ID_LEN(STATION_ID_LEN);
radius_msg_length += AVP_TYPE_CALLING_STATION_ID_LEN(STATION_ID_LEN);
radius_msg_length += AVP_TYPE_NAS_IDENTIFIER_LEN(STATION_ID_LEN);
radius_msg_length += AVP_TYPE_NAS_PORT_TYPE_LEN;
radius_msg_length += AVP_TYPE_MESSAGE_AUTHENTICATOR_LEN;
radius_msg_length += AVP_TYPE_NAS_IPV6_ADDRESS_LEN;
uint8_t *radius_msg_ptr = ns_dyn_mem_temporary_alloc(radius_msg_length);
uint8_t *radius_msg_start_ptr = radius_msg_ptr;
*radius_msg_ptr++ = RADIUS_ACCESS_REQUEST; // code
data->radius_identifier = radius_client_sec_prot_identifier_allocate();
*radius_msg_ptr++ = data->radius_identifier; // identifier
radius_msg_ptr = common_write_16_bit(radius_msg_length, radius_msg_ptr); // length
randLIB_get_n_bytes_random(data->request_authenticator, 16);
memcpy(radius_msg_ptr, data->request_authenticator, 16); // request authenticator
radius_msg_ptr += 16;
radius_msg_ptr = avp_user_name_write(radius_msg_ptr, data->identity_len, data->identity);
uint8_t local_eui_64_hash[8];
radius_client_sec_prot_eui_64_hash_get(prot, local_eui_64_hash, data->remote_eui_64_hash, data->remote_eui_64_hash_set);
data->remote_eui_64_hash_set = true;
uint8_t station_id[STATION_ID_LEN];
radius_client_sec_prot_station_id_generate(data->remote_eui_64_hash, station_id);
radius_msg_ptr = avp_calling_station_id_write(radius_msg_ptr, STATION_ID_LEN, station_id);
radius_client_sec_prot_station_id_generate(local_eui_64_hash, station_id);
radius_msg_ptr = avp_called_station_id_write(radius_msg_ptr, STATION_ID_LEN, station_id);
radius_msg_ptr = avp_nas_identifier_write(radius_msg_ptr, STATION_ID_LEN, station_id);
radius_msg_ptr = avp_nas_port_write(radius_msg_ptr, NAS_PORT);
radius_msg_ptr = avp_framed_mtu_write(radius_msg_ptr, FRAMED_MTU);
if (data->state) {
radius_msg_ptr = avp_state_write(radius_msg_ptr, data->state_len, data->state);
}
radius_msg_ptr = avp_nas_port_type_write(radius_msg_ptr, NAS_PORT_TYPE_WIRELESS_IEEE802_11);
uint8_t address[16];
prot->ip_addr_get(prot, address);
radius_msg_ptr = avp_nas_ipv6_address_write(radius_msg_ptr, address);
// Write eap fragments
eap_len = eap_hdr->msg.eap.length;
uint8_t *eap_ptr = eap_hdr->packet_body;
while (true) {
if (eap_len > AVP_VALUE_MAX_LEN) {
eap_len -= AVP_VALUE_MAX_LEN;
radius_msg_ptr = avp_eap_message_write(radius_msg_ptr, AVP_VALUE_MAX_LEN, eap_ptr);
eap_ptr += AVP_VALUE_MAX_LEN;
} else {
radius_msg_ptr = avp_eap_message_write(radius_msg_ptr, eap_len, eap_ptr);
break;
}
}
uint8_t *message_auth_ptr = radius_msg_ptr;
uint8_t message_auth[16];
memset(message_auth, 0, 16); // zero for value calculation
radius_msg_ptr = avp_message_authenticator_write(radius_msg_ptr, message_auth);
// Calculate message authenticator
if (radius_client_sec_prot_message_authenticator_calc(prot, radius_msg_length, radius_msg_start_ptr, message_auth) < 0) {
ns_dyn_mem_free(radius_msg_start_ptr);
return;
}
// Write message authenticator
radius_msg_ptr = avp_message_authenticator_write(message_auth_ptr, message_auth);
// Store message for sending
if (data->send_radius_msg != NULL) {
ns_dyn_mem_free(data->send_radius_msg);
}
data->send_radius_msg = radius_msg_start_ptr;
data->send_radius_msg_len = radius_msg_length;
}
static int8_t radius_client_sec_prot_radius_msg_send(sec_prot_t *prot)
{
radius_client_sec_prot_int_t *data = radius_client_sec_prot_get(prot);
if (!data->send_radius_msg || data->send_radius_msg_len == 0) {
return -1;
}
if (prot->send(prot, data->send_radius_msg, data->send_radius_msg_len) < 0) {
return -1;
}
data->send_radius_msg = NULL;
data->send_radius_msg_len = 0;
return 0;
}
static int8_t radius_client_sec_prot_eui_64_hash_generate(uint8_t *eui_64, uint8_t *hashed_eui_64)
{
int8_t ret_val = 0;
if (!shared_data->hash_random_set) {
randLIB_get_n_bytes_random(shared_data->hash_random, 16);
}
uint8_t hashed_string[24];
memcpy(&hashed_string[0], eui_64, 8);
memcpy(&hashed_string[8], shared_data->hash_random, 16);
mbedtls_sha256_context ctx;
mbedtls_sha256_init(&ctx);
if (mbedtls_sha256_starts_ret(&ctx, 0) != 0) {
ret_val = -1;
goto error;
}
if (mbedtls_sha256_update_ret(&ctx, hashed_string, 24) != 0) {
ret_val = -1;
goto error;
}
uint8_t output[32];
if (mbedtls_sha256_finish_ret(&ctx, output) != 0) {
ret_val = -1;
goto error;
}
memcpy(hashed_eui_64, output, 8);
error:
mbedtls_sha256_free(&ctx);
return ret_val;
}
static uint8_t radius_client_sec_prot_hex_to_ascii(uint8_t value)
{
char character = '0';
if (value <= 9) {
character = '0' + value;
} else if (value >= 0x0A && value <= 0x0F) {
character = 'A' + value - 0x0A;
}
return character;
}
static void radius_client_sec_prot_station_id_generate(uint8_t *eui_64, uint8_t *station_id_ptr)
{
for (uint8_t i = 0; i < 8; i++) {
*station_id_ptr++ = radius_client_sec_prot_hex_to_ascii(eui_64[i] / 16);
*station_id_ptr++ = radius_client_sec_prot_hex_to_ascii(eui_64[i] % 16);
if (i != 7) {
*station_id_ptr++ = '-';
}
}
}
static int8_t radius_client_sec_prot_message_authenticator_calc(sec_prot_t *prot, uint16_t msg_len, uint8_t *msg_ptr, uint8_t *auth_ptr)
{
const uint8_t *key = prot->sec_cfg->radius_cfg.radius_shared_secret;
uint16_t key_len = prot->sec_cfg->radius_cfg.radius_shared_secret_len;
if (prot->sec_cfg->radius_cfg.radius_shared_secret_len == 0) {
return -1;
}
#ifndef MBEDTLS_MD5_C
tr_error("FATAL: MD5 MBEDTLS_MD5_C not enabled");
#endif
if (hmac_md_calc(ALG_HMAC_MD5, key, key_len, msg_ptr, msg_len, auth_ptr, 16) < 0) {
return -1;
}
return 0;
}
static int8_t radius_client_sec_prot_response_authenticator_calc(sec_prot_t *prot, uint16_t msg_len, uint8_t *msg_ptr, uint8_t *auth_ptr)
{
#ifdef MBEDTLS_MD5_C
const uint8_t *key = prot->sec_cfg->radius_cfg.radius_shared_secret;
uint16_t key_len = prot->sec_cfg->radius_cfg.radius_shared_secret_len;
if (prot->sec_cfg->radius_cfg.radius_shared_secret_len == 0) {
return -1;
}
int8_t ret_value = -1;
mbedtls_md5_context ctx;
mbedtls_md5_init(&ctx);
if (mbedtls_md5_starts_ret(&ctx) != 0) {
goto end;
}
if (mbedtls_md5_update_ret(&ctx, msg_ptr, msg_len) != 0) {
goto end;
}
if (mbedtls_md5_update_ret(&ctx, key, key_len) != 0) {
goto end;
}
if (mbedtls_md5_finish_ret(&ctx, auth_ptr) != 0) {
goto end;
}
ret_value = 0;
end:
mbedtls_md5_free(&ctx);
return ret_value;
#else
(void) prot;
(void) msg_len;
(void) msg_ptr;
(void) auth_ptr;
tr_error("FATAL: MD5 MBEDTLS_MD5_C not enabled");
return -1;
#endif
}
static int8_t radius_client_sec_prot_ms_mppe_recv_key_pmk_decrypt(sec_prot_t *prot, uint8_t *recv_key, uint8_t recv_key_len, uint8_t *request_authenticator, uint8_t *pmk_ptr)
{
#ifdef MBEDTLS_MD5_C
const uint8_t *key = prot->sec_cfg->radius_cfg.radius_shared_secret;
uint16_t key_len = prot->sec_cfg->radius_cfg.radius_shared_secret_len;
if (prot->sec_cfg->radius_cfg.radius_shared_secret_len == 0) {
return -1;
}
if (recv_key_len < MS_MPPE_RECV_KEY_SALT_LEN + MS_MPPE_RECV_KEY_BLOCK_LEN) {
return -1;
}
uint8_t *salt_ptr = recv_key;
uint8_t *cipher_text_ptr = recv_key + MS_MPPE_RECV_KEY_SALT_LEN;
int16_t cipher_text_len = recv_key_len - MS_MPPE_RECV_KEY_SALT_LEN;
uint8_t plain_text[cipher_text_len];
uint8_t *plain_text_ptr = plain_text;
bool first_interm_b_value = true;
uint8_t interm_b_val[MS_MPPE_RECV_KEY_BLOCK_LEN];
bool md5_failed = false;
mbedtls_md5_context ctx;
while (cipher_text_len >= MS_MPPE_RECV_KEY_BLOCK_LEN) {
mbedtls_md5_init(&ctx);
if (mbedtls_md5_starts_ret(&ctx) != 0) {
md5_failed = true;
break;
}
if (mbedtls_md5_update_ret(&ctx, key, key_len) != 0) {
md5_failed = true;
break;
}
if (first_interm_b_value) {
// b(1) = MD5(secret + request-authenticator + salt)
if (mbedtls_md5_update_ret(&ctx, request_authenticator, MS_MPPE_RECV_KEY_BLOCK_LEN) != 0) {
md5_failed = true;
break;
}
if (mbedtls_md5_update_ret(&ctx, salt_ptr, MS_MPPE_RECV_KEY_SALT_LEN) != 0) {
md5_failed = true;
break;
}
} else {
// b(i) = MD5(secret + cipher_text(i - 1))
if (mbedtls_md5_update_ret(&ctx, cipher_text_ptr - MS_MPPE_RECV_KEY_BLOCK_LEN, MS_MPPE_RECV_KEY_BLOCK_LEN) != 0) {
md5_failed = true;
break;
}
}
if (mbedtls_md5_finish_ret(&ctx, interm_b_val) != 0) {
md5_failed = true;
break;
}
mbedtls_md5_free(&ctx);
first_interm_b_value = false;
for (uint8_t index = 0; index < MS_MPPE_RECV_KEY_BLOCK_LEN; index++) {
*plain_text_ptr++ = *cipher_text_ptr++ ^ interm_b_val[index];
}
cipher_text_len -= MS_MPPE_RECV_KEY_BLOCK_LEN;
}
if (md5_failed) {
mbedtls_md5_free(&ctx);
}
if (md5_failed || cipher_text_len != 0) {
return -1;
}
memcpy(pmk_ptr, plain_text + 1, PMK_LEN);
return 0;
#else
(void) prot;
(void) recv_key;
(void) recv_key_len;
(void) request_authenticator;
(void) pmk_ptr;
tr_error("FATAL: MD5 MBEDTLS_MD5_C not enabled");
return -1;
#endif
}
static void radius_client_sec_prot_finished_send(sec_prot_t *prot)
{
radius_client_sec_prot_int_t *data = radius_client_sec_prot_get(prot);
prot->timer_start(prot);
sec_prot_state_set(prot, &data->common, RADIUS_STATE_FINISHED);
}
static void radius_client_sec_prot_timer_timeout(sec_prot_t *prot, uint16_t ticks)
{
radius_client_sec_prot_int_t *data = radius_client_sec_prot_get(prot);
sec_prot_timer_timeout_handle(prot, &data->common,
&prot->sec_cfg->prot_cfg.sec_prot_trickle_params, ticks);
}
static void radius_client_sec_prot_state_machine(sec_prot_t *prot)
{
radius_client_sec_prot_int_t *data = radius_client_sec_prot_get(prot);
switch (sec_prot_state_get(&data->common)) {
case RADIUS_STATE_INIT:
tr_debug("Radius: init");
sec_prot_state_set(prot, &data->common, RADIUS_STATE_STATE_RESPONSE_ID);
prot->timer_start(prot);
break;
// Wait EAP response, Identity (starts RADIUS Client protocol)
case RADIUS_STATE_STATE_RESPONSE_ID:
tr_debug("Radius: start, eui-64: %s", trace_array(sec_prot_remote_eui_64_addr_get(prot), 8));
// Set default timeout for the total maximum length of the negotiation
sec_prot_default_timeout_set(&data->common);
sec_prot_state_set(prot, &data->common, RADIUS_STATE_CREATE_RESP);
if (radius_client_sec_prot_init_radius_eap_tls(prot) < 0) {
tr_error("Radius: EAP-TLS init failed");
return;
}
radius_client_sec_prot_allocate_and_create_radius_message(prot);
// Send KMP-CREATE.indication
prot->create_ind(prot);
break;
// Wait KMP-CREATE.response
case RADIUS_STATE_CREATE_RESP:
if (sec_prot_result_ok_check(&data->common)) {
sec_prot_state_set(prot, &data->common, RADIUS_STATE_SEND_INITIAL_ACCESS_REQUEST);
prot->state_machine_call(prot);
} else {
// Ready to be deleted
sec_prot_state_set(prot, &data->common, RADIUS_STATE_FINISHED);
}
break;
case RADIUS_STATE_SEND_INITIAL_ACCESS_REQUEST:
tr_debug("Radius: send initial access request, eui-64: %s", trace_array(sec_prot_remote_eui_64_addr_get(prot), 8));
if (radius_client_sec_prot_radius_msg_send(prot) < 0) {
tr_error("Radius: msg send error");
}
// Start trickle timer to re-send if no response
sec_prot_timer_trickle_start(&data->common, &prot->sec_cfg->prot_cfg.sec_prot_trickle_params);
sec_prot_state_set(prot, &data->common, RADIUS_STATE_ACCESS_ACCEPT_REJECT_CHALLENGE);
break;
case RADIUS_STATE_ACCESS_ACCEPT_REJECT_CHALLENGE:
// On timeout
if (sec_prot_result_timeout_check(&data->common)) {
// Do nothing for now
return;
}
tr_debug("Radius: received access accept/reject/challenge, eui-64: %s", trace_array(sec_prot_remote_eui_64_addr_get(prot), 8));
// Send to radius EAP-TLS
data->radius_eap_tls_send(data->radius_eap_tls_prot, (void *) data->recv_eap_msg, data->recv_eap_msg_len);
data->recv_eap_msg = NULL;
data->recv_eap_msg_len = 0;
if (data->radius_code == RADIUS_ACCESS_REJECT) {
sec_prot_result_set(&data->common, SEC_RESULT_ERROR);
sec_prot_state_set(prot, &data->common, RADIUS_STATE_FINISH);
} else if (data->radius_code == RADIUS_ACCESS_ACCEPT) {
if (data->new_pmk_set) {
sec_prot_result_set(&data->common, SEC_RESULT_OK);
} else {
sec_prot_result_set(&data->common, SEC_RESULT_ERROR);
}
sec_prot_state_set(prot, &data->common, RADIUS_STATE_FINISH);
} else if (data->radius_code == RADIUS_ACCESS_CHALLENGE) {
sec_prot_state_set(prot, &data->common, RADIUS_STATE_SEND_ACCESS_REQUEST);
}
break;
case RADIUS_STATE_SEND_ACCESS_REQUEST:
// On timeout
if (sec_prot_result_timeout_check(&data->common)) {
// Do nothing for now
return;
}
tr_debug("Radius: send access request, eui-64: %s", trace_array(sec_prot_remote_eui_64_addr_get(prot), 8));
radius_client_sec_prot_allocate_and_create_radius_message(prot);
if (radius_client_sec_prot_radius_msg_send(prot) < 0) {
tr_error("Radius: msg send error");
}
sec_prot_state_set(prot, &data->common, RADIUS_STATE_ACCESS_ACCEPT_REJECT_CHALLENGE);
break;
case RADIUS_STATE_FINISH:
tr_debug("Radius: finish, eui-64: %s", trace_array(sec_prot_remote_eui_64_addr_get(prot), 8));
if (sec_prot_result_ok_check(&data->common)) {
sec_prot_keys_pmk_write(prot->sec_keys, data->new_pmk, prot->sec_cfg->timer_cfg.pmk_lifetime);
// Supplicant PMK is now valid
sec_prot_keys_pmk_mismatch_reset(prot->sec_keys);
/* Calls KMP-FINISHED.indication with ignore results because next
protocol is triggered from radius EAP-TLS */
sec_prot_result_set(&data->common, SEC_RESULT_IGNORE);
}
// KMP-FINISHED.indication
prot->finished_ind(prot, sec_prot_result_get(&data->common), prot->sec_keys);
sec_prot_state_set(prot, &data->common, RADIUS_STATE_FINISHED);
break;
case RADIUS_STATE_FINISHED: {
uint8_t *remote_eui_64 = sec_prot_remote_eui_64_addr_get(prot);
tr_debug("Radius: finished, eui-64: %s", remote_eui_64 ? trace_array(remote_eui_64, 8) : "not set");
prot->timer_stop(prot);
prot->finished(prot);
break;
}
default:
break;
}
}
#endif /* HAVE_WS */

View File

@ -0,0 +1,36 @@
/*
* Copyright (c) 2020, Arm Limited and affiliates.
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef RADIUS_CLIENT_SEC_PROT_H_
#define RADIUS_CLIENT_SEC_PROT_H_
/*
* RADIUS client security protocol
*
*/
/**
* radius_client_sec_prot_register register RADIUS client protocol to KMP service
*
* \param service KMP service
*
* \return < 0 failure
* \return >= 0 success
*/
int8_t radius_client_sec_prot_register(kmp_service_t *service);
#endif /* RADIUS_CLIENT_SEC_PROT_H_ */

View File

@ -34,7 +34,8 @@ typedef enum {
SEC_RESULT_ERR_UNSPEC = -3,
SEC_RESULT_TIMEOUT = -4,
SEC_RESULT_ERROR = -5,
SEC_RESULT_CONF_ERROR = -6
SEC_RESULT_CONF_ERROR = -6,
SEC_RESULT_IGNORE
} sec_prot_result_e;
typedef enum {
@ -49,7 +50,9 @@ typedef enum {
typedef enum {
SEC_PROT_TYPE_EAP_TLS = 0,
SEC_PROT_TYPE_TLS
SEC_PROT_TYPE_RADIUS_EAP_TLS,
SEC_PROT_TYPE_TLS,
SEC_PROT_TYPE_RADIUS_CLIENT
} sec_prot_type_e;
typedef enum {
@ -216,6 +219,15 @@ typedef void sec_prot_timer_timeout(sec_prot_t *prot, uint16_t ticks);
*/
typedef void sec_prot_eui64_addr_get(sec_prot_t *prot, uint8_t *local_eui64, uint8_t *remote_eui64);
/**
* sec_prot_ip_addr_get gets IP address for security protocol
*
* \param prot protocol
* \param address IP address
*
*/
typedef void sec_prot_ip_addr_get(sec_prot_t *prot, uint8_t *address);
/**
* sec_prot_by_type_get gets security protocol
*
@ -237,6 +249,19 @@ typedef sec_prot_t *sec_prot_by_type_get(sec_prot_t *prot, uint8_t type);
*/
typedef void sec_prot_receive_disable(sec_prot_t *prot);
/**
* sec_prot_receive_check check if received message is for this protocol
*
* \param prot protocol
* \param pdu pdu
* \param size pdu size
*
* \return < 0 message is not for this protocol
* \return >= 0 message is for this protocol
*
*/
typedef int8_t sec_prot_receive_check(sec_prot_t *prot, const void *pdu, uint16_t size);
typedef struct sec_prot_int_data_s sec_prot_int_data_t;
// Security protocol data
@ -252,6 +277,8 @@ struct sec_prot_s {
sec_prot_send *send; /**< Protocol send */
sec_prot_receive *receive; /**< Protocol receive */
sec_prot_receive *receive_peer; /**< Protocol receive from peer (used by peer protocol for send) */
sec_prot_tx_status_ind *tx_status_ind; /**< TX status indication */
sec_prot_delete *delete; /**< Protocol delete */
@ -264,13 +291,16 @@ struct sec_prot_s {
sec_prot_timer_timeout *timer_timeout; /**< Timer timeout */
sec_prot_eui64_addr_get *addr_get; /**< Gets EUI-64 addresses */
sec_prot_ip_addr_get *ip_addr_get; /**< Gets IP address */
sec_prot_by_type_get *type_get; /**< Gets security protocol by type */
sec_prot_receive_disable *receive_disable; /**< Disable receiving of messages */
sec_prot_receive_check *receive_check; /**< Check if messages is for this protocol */
sec_prot_keys_t *sec_keys; /**< Security keys storage pointer */
sec_prot_cfg_t *prot_cfg; /**< Security protocol configuration pointer */
sec_timer_cfg_t *timer_cfg; /**< Security timer configuration pointer */
sec_cfg_t *sec_cfg; /**< Security configuration configuration pointer */
uint8_t header_size; /**< Header size */
uint8_t receive_peer_hdr_size; /**< Receive from peer header size */
uint8_t msg_if_instance_id; /**< Message interface instance identifier */
sec_prot_int_data_t *data; /**< Protocol internal data */
};

View File

@ -43,4 +43,19 @@ typedef struct sec_timer_cfg_s {
uint8_t gtk_new_install_req; /* GTK_NEW_INSTALL_REQUIRED (percent of GTK lifetime) */
} sec_timer_cfg_t;
/* Security radius configuration settings */
typedef struct sec_radius_cfg_s {
uint8_t radius_addr[16]; /**< Radius server IPv6 address */
uint8_t *radius_shared_secret; /**< Radius shared secret */
uint16_t radius_shared_secret_len; /**< Radius shared secret length */
bool radius_addr_set : 1; /**< Radius server address is set */
} sec_radius_cfg_t;
typedef struct sec_cfg_s {
sec_prot_cfg_t prot_cfg;
sec_timer_cfg_t timer_cfg;
sec_radius_cfg_t radius_cfg;
} sec_cfg_t;
#endif /* SEC_PROT_CONF_H_ */

View File

@ -142,6 +142,7 @@ typedef struct {
sec_prot_gtk_keys_t *gtks; /**< Link to GTKs */
uint16_t new_pan_id; /**< new PAN ID indicated by bootstrap */
uint16_t key_pan_id; /**< PAN ID for keys */
uint16_t pan_version; /**< PAN version for keys */
bool updated : 1; /**< Network info has been updated */
} sec_prot_keys_nw_info_t;

View File

@ -36,8 +36,8 @@
#include "Security/protocols/sec_prot_keys.h"
#include "Security/protocols/sec_prot.h"
#include "Security/protocols/sec_prot_lib.h"
#include "Service_Libs/hmac/hmac_md.h"
#include "Service_Libs/ieee_802_11/ieee_802_11.h"
#include "Service_Libs/hmac/hmac_sha1.h"
#include "Service_Libs/nist_aes_kw/nist_aes_kw.h"
#include "mbedtls/sha256.h"
@ -297,7 +297,7 @@ int8_t sec_prot_lib_pmkid_calc(const uint8_t *pmk, const uint8_t *auth_eui64, co
ptr += EUI64_LEN;
memcpy(ptr, supp_eui64, EUI64_LEN);
if (hmac_sha1_calc(pmk, PMK_LEN, data, data_len, pmkid, PMKID_LEN) < 0) {
if (hmac_md_calc(ALG_HMAC_SHA1_160, pmk, PMK_LEN, data, data_len, pmkid, PMKID_LEN) < 0) {
return -1;
}
@ -319,7 +319,7 @@ int8_t sec_prot_lib_ptkid_calc(const uint8_t *ptk, const uint8_t *auth_eui64, co
ptr += EUI64_LEN;
memcpy(ptr, supp_eui64, EUI64_LEN);
if (hmac_sha1_calc(ptk, PTK_LEN, data, data_len, ptkid, PTKID_LEN) < 0) {
if (hmac_md_calc(ALG_HMAC_SHA1_160, ptk, PTK_LEN, data, data_len, ptkid, PTKID_LEN) < 0) {
return -1;
}
@ -351,7 +351,7 @@ uint8_t *sec_prot_lib_message_build(uint8_t *ptk, uint8_t *kde, uint16_t kde_len
if (eapol_pdu->msg.key.key_information.key_mic) {
uint8_t mic[EAPOL_KEY_MIC_LEN];
if (hmac_sha1_calc(ptk, KCK_LEN, eapol_pdu_frame + header_size, eapol_pdu_size, mic, EAPOL_KEY_MIC_LEN) < 0) {
if (hmac_md_calc(ALG_HMAC_SHA1_160, ptk, KCK_LEN, eapol_pdu_frame + header_size, eapol_pdu_size, mic, EAPOL_KEY_MIC_LEN) < 0) {
ns_dyn_mem_free(eapol_pdu_frame);
return NULL;
}
@ -434,7 +434,7 @@ int8_t sec_prot_lib_mic_validate(uint8_t *ptk, uint8_t *mic, uint8_t *pdu, uint8
eapol_write_key_packet_mic(pdu, 0);
uint8_t calc_mic[EAPOL_KEY_MIC_LEN];
if (hmac_sha1_calc(ptk, EAPOL_KEY_MIC_LEN, pdu, pdu_size, calc_mic, EAPOL_KEY_MIC_LEN) < 0) {
if (hmac_md_calc(ALG_HMAC_SHA1_160, ptk, EAPOL_KEY_MIC_LEN, pdu, pdu_size, calc_mic, EAPOL_KEY_MIC_LEN) < 0) {
tr_error("MIC invalid");
return -1;
}
@ -445,7 +445,7 @@ int8_t sec_prot_lib_mic_validate(uint8_t *ptk, uint8_t *mic, uint8_t *pdu, uint8
return 0;
}
int8_t sec_prot_lib_pmkid_generate(sec_prot_t *prot, uint8_t *pmkid, bool is_auth)
int8_t sec_prot_lib_pmkid_generate(sec_prot_t *prot, uint8_t *pmkid, bool is_auth, bool alt_remote_eui64_use, uint8_t *used_remote_eui64)
{
uint8_t *pmk = sec_prot_keys_pmk_get(prot->sec_keys);
if (!pmk) {
@ -456,14 +456,22 @@ int8_t sec_prot_lib_pmkid_generate(sec_prot_t *prot, uint8_t *pmkid, bool is_aut
uint8_t remote_eui64[8];
// Tries to get the EUI-64 that is validated by PTK procedure or bound to supplicant entry
uint8_t *remote_eui64_ptr = sec_prot_keys_ptk_eui_64_get(prot->sec_keys);
if (remote_eui64_ptr) {
if (remote_eui64_ptr && !alt_remote_eui64_use) {
memcpy(remote_eui64, remote_eui64_ptr, 8);
prot->addr_get(prot, local_eui64, NULL);
} else {
// If request is for alternative EUI-64, but PTK EUI-64 is not present, returns failure
if (alt_remote_eui64_use && !remote_eui64_ptr) {
return -1;
}
// If validated EUI-64 is not present, use the remote EUI-64
prot->addr_get(prot, local_eui64, remote_eui64);
}
if (used_remote_eui64 != NULL) {
memcpy(used_remote_eui64, remote_eui64, 8);
}
if (is_auth) {
return sec_prot_lib_pmkid_calc(pmk, local_eui64, remote_eui64, pmkid);
} else {

View File

@ -162,11 +162,13 @@ int8_t sec_prot_lib_mic_validate(uint8_t *ptk, uint8_t *mic, uint8_t *pdu, uint8
* \param prot security protocol
* \param pmkid PMK ID
* \param is_auth set for authenticator
* \param alt_remote_eui64_use use alternative remote EUI-64 if available
* \param used_remote_eui64 remote EUI-64 used on PMKID generation
*
* \return < 0 failure
* \return >= 0 success
*/
int8_t sec_prot_lib_pmkid_generate(sec_prot_t *prot, uint8_t *pmkid, bool is_auth);
int8_t sec_prot_lib_pmkid_generate(sec_prot_t *prot, uint8_t *pmkid, bool is_auth, bool alt_remote_eui64_use, uint8_t *used_remote_eui64);
/**
* sec_prot_lib_ptkid_generate generate PTK ID from PTK

View File

@ -375,7 +375,7 @@ static void client_tls_sec_prot_state_machine(sec_prot_t *prot)
data->calculating = false;
if (sec_prot_result_ok_check(&data->common)) {
sec_prot_keys_pmk_write(prot->sec_keys, data->new_pmk, prot->timer_cfg->pmk_lifetime);
sec_prot_keys_pmk_write(prot->sec_keys, data->new_pmk, prot->sec_cfg->timer_cfg.pmk_lifetime);
}
// KMP-FINISHED.indication,
@ -494,7 +494,7 @@ static void server_tls_sec_prot_state_machine(sec_prot_t *prot)
data->calculating = false;
if (sec_prot_result_ok_check(&data->common)) {
sec_prot_keys_pmk_write(prot->sec_keys, data->new_pmk, prot->timer_cfg->pmk_lifetime);
sec_prot_keys_pmk_write(prot->sec_keys, data->new_pmk, prot->sec_cfg->timer_cfg.pmk_lifetime);
}
// KMP-FINISHED.indication,

View File

@ -83,6 +83,7 @@ static void fhss_event_timer_cb(int8_t timer_id, uint16_t slots);
static void fhss_ws_update_uc_channel_callback(fhss_structure_t *fhss_structure);
static void fhss_unicast_handler(const fhss_api_t *fhss_api, uint16_t delay);
static bool fhss_ws_check_tx_allowed(fhss_structure_t *fhss_structure);
static int32_t fhss_channel_index_from_mask(const uint32_t *channel_mask, int32_t channel_index, uint16_t number_of_channels);
// This function supports rounding up
static int64_t divide_integer(int64_t dividend, int32_t divisor)
@ -235,12 +236,14 @@ static int32_t fhss_ws_calc_bc_channel(fhss_structure_t *fhss_structure)
if (fhss_structure->ws->fhss_configuration.ws_bc_channel_function == WS_TR51CF) {
next_channel = tr51_get_bc_channel_index(fhss_structure->ws->tr51_channel_table, fhss_structure->ws->tr51_output_table, fhss_structure->ws->bc_slot, fhss_structure->ws->fhss_configuration.bsi, fhss_structure->number_of_channels, NULL);
next_channel = fhss_channel_index_from_mask(fhss_structure->ws->fhss_configuration.channel_mask, next_channel, fhss_structure->number_of_channels);
if (++fhss_structure->ws->bc_slot == fhss_structure->number_of_channels) {
fhss_structure->ws->bc_slot = 0;
}
} else if (fhss_structure->ws->fhss_configuration.ws_bc_channel_function == WS_DH1CF) {
fhss_structure->ws->bc_slot++;
next_channel = dh1cf_get_bc_channel_index(fhss_structure->ws->bc_slot, fhss_structure->ws->fhss_configuration.bsi, fhss_structure->number_of_channels);
next_channel = fhss_channel_index_from_mask(fhss_structure->ws->fhss_configuration.channel_mask, next_channel, fhss_structure->number_of_channels);
} else if (fhss_structure->ws->fhss_configuration.ws_bc_channel_function == WS_VENDOR_DEF_CF) {
if (fhss_structure->ws->fhss_configuration.vendor_defined_cf) {
next_channel = fhss_structure->ws->fhss_configuration.vendor_defined_cf(fhss_structure->fhss_api, fhss_structure->ws->bc_slot, NULL, fhss_structure->ws->fhss_configuration.bsi, fhss_structure->number_of_channels);
@ -264,6 +267,22 @@ static uint8_t calc_own_tx_trig_slot(uint8_t own_hop)
return (own_hop & 1);
}
static int32_t fhss_channel_index_from_mask(const uint32_t *channel_mask, int32_t channel_index, uint16_t number_of_channels)
{
//Function will return real active channel index at list
int32_t active_channels = 0;
// Set channel maks outside excluded channels
for (int32_t i = 0; i < number_of_channels; i++) {
if (channel_mask[0 + (i / 32)] & (1 << (i % 32))) {
if (channel_index == active_channels) {
return i;
}
active_channels++;
}
}
return 0;
}
static void fhss_broadcast_handler(const fhss_api_t *fhss_api, uint16_t delay)
{
int32_t next_channel;
@ -276,6 +295,7 @@ static void fhss_broadcast_handler(const fhss_api_t *fhss_api, uint16_t delay)
// stop broadcast schedule
fhss_structure->ws->is_on_bc_channel = false;
fhss_structure->ws->synchronization_time = 0;
fhss_structure->ws->broadcast_timer_running = false;
return;
}
if (fhss_structure->ws->is_on_bc_channel == false) {
@ -324,6 +344,9 @@ static void fhss_broadcast_handler(const fhss_api_t *fhss_api, uint16_t delay)
#ifdef FHSS_CHANNEL_DEBUG
tr_info("%"PRIu32" UC %u", fhss_structure->callbacks.read_timestamp(fhss_structure->fhss_api), fhss_structure->rx_channel);
#endif /*FHSS_CHANNEL_DEBUG*/
#ifdef TIMING_TOOL_TRACES
tr_info("%u UC_change %u", fhss_structure->callbacks.read_timestamp(fhss_structure->fhss_api), next_channel);
#endif
}
fhss_structure->callbacks.change_channel(fhss_structure->fhss_api, next_channel);
#ifdef FHSS_CHANNEL_DEBUG_CBS
@ -331,6 +354,13 @@ static void fhss_broadcast_handler(const fhss_api_t *fhss_api, uint16_t delay)
fhss_bc_switch();
}
#endif /*FHSS_CHANNEL_DEBUG_CBS*/
#ifdef TIMING_TOOL_TRACES
if (fhss_structure->ws->is_on_bc_channel == true) {
tr_info("%u BC_start %u", fhss_structure->callbacks.read_timestamp(fhss_structure->fhss_api), next_channel);
} else {
tr_info("%u BC_done", fhss_structure->callbacks.read_timestamp(fhss_structure->fhss_api));
}
#endif
}
static int own_floor(float value)
@ -373,6 +403,9 @@ static void fhss_event_timer_cb(int8_t timer_id, uint16_t slots)
}
if (queue_size) {
fhss_structure->callbacks.tx_poll(fhss_structure->fhss_api);
#ifdef TIMING_TOOL_TRACES
tr_info("%u TX_poll", fhss_structure->callbacks.read_timestamp(fhss_structure->fhss_api));
#endif
}
}
@ -384,7 +417,10 @@ static uint32_t fhss_ws_calculate_ufsi(fhss_structure_t *fhss_structure, uint32_
cur_slot = fhss_structure->number_of_uc_channels;
}
cur_slot--;
uint32_t remaining_time_ms = US_TO_MS(get_remaining_slots_us(fhss_structure, fhss_unicast_handler, MS_TO_US(fhss_structure->ws->fhss_configuration.fhss_uc_dwell_interval)));
uint32_t remaining_time_ms = 0;
if (fhss_structure->ws->unicast_timer_running == true) {
remaining_time_ms = US_TO_MS(get_remaining_slots_us(fhss_structure, fhss_unicast_handler, MS_TO_US(dwell_time) - NS_TO_US(dwell_time * fhss_structure->ws->drift_per_millisecond_ns)));
}
uint32_t time_to_tx = 0;
uint32_t cur_time = fhss_structure->callbacks.read_timestamp(fhss_structure->fhss_api);
if (cur_time < tx_time) {
@ -447,6 +483,7 @@ static int16_t fhss_ws_synch_state_set_callback(const fhss_api_t *api, fhss_stat
// Start broadcast schedule when BC intervals are known
if (fhss_broadcast_interval && fhss_bc_dwell_interval) {
fhss_broadcast_handler(fhss_structure->fhss_api, 0);
fhss_structure->ws->broadcast_timer_running = true;
}
// Start unicast schedule
if ((fhss_structure->ws->fhss_configuration.ws_uc_channel_function != WS_FIXED_CHANNEL)) {
@ -459,6 +496,7 @@ static int16_t fhss_ws_synch_state_set_callback(const fhss_api_t *api, fhss_stat
eventOS_callback_timer_stop(fhss_structure->fhss_event_timer);
fhss_stop_timer(fhss_structure, fhss_unicast_handler);
fhss_stop_timer(fhss_structure, fhss_broadcast_handler);
fhss_structure->ws->broadcast_timer_running = false;
}
fhss_structure->fhss_state = fhss_state;
@ -477,12 +515,14 @@ static void fhss_ws_update_uc_channel_callback(fhss_structure_t *fhss_structure)
if (fhss_structure->ws->fhss_configuration.ws_uc_channel_function == WS_FIXED_CHANNEL) {
return;
} else if (fhss_structure->ws->fhss_configuration.ws_uc_channel_function == WS_TR51CF) {
next_channel = fhss_structure->rx_channel = tr51_get_uc_channel_index(fhss_structure->ws->tr51_channel_table, fhss_structure->ws->tr51_output_table, fhss_structure->ws->uc_slot, mac_address, fhss_structure->number_of_uc_channels, NULL);
next_channel = tr51_get_uc_channel_index(fhss_structure->ws->tr51_channel_table, fhss_structure->ws->tr51_output_table, fhss_structure->ws->uc_slot, mac_address, fhss_structure->number_of_uc_channels, NULL);
next_channel = fhss_structure->rx_channel = fhss_channel_index_from_mask(fhss_structure->ws->fhss_configuration.unicast_channel_mask, next_channel, fhss_structure->number_of_channels);
if (++fhss_structure->ws->uc_slot == fhss_structure->number_of_uc_channels) {
fhss_structure->ws->uc_slot = 0;
}
} else if (fhss_structure->ws->fhss_configuration.ws_uc_channel_function == WS_DH1CF) {
next_channel = fhss_structure->rx_channel = dh1cf_get_uc_channel_index(fhss_structure->ws->uc_slot, mac_address, fhss_structure->number_of_uc_channels);
next_channel = dh1cf_get_uc_channel_index(fhss_structure->ws->uc_slot, mac_address, fhss_structure->number_of_uc_channels);
next_channel = fhss_structure->rx_channel = fhss_channel_index_from_mask(fhss_structure->ws->fhss_configuration.unicast_channel_mask, next_channel, fhss_structure->number_of_channels);
fhss_structure->ws->uc_slot++;
} else if (fhss_structure->ws->fhss_configuration.ws_uc_channel_function == WS_VENDOR_DEF_CF) {
if (fhss_structure->ws->fhss_configuration.vendor_defined_cf) {
@ -496,6 +536,9 @@ static void fhss_ws_update_uc_channel_callback(fhss_structure_t *fhss_structure)
#ifdef FHSS_CHANNEL_DEBUG
tr_info("%"PRIu32" UC %u %u", fhss_structure->callbacks.read_timestamp(fhss_structure->fhss_api), next_channel, fhss_structure->ws->uc_slot);
#endif /*FHSS_CHANNEL_DEBUG*/
#ifdef TIMING_TOOL_TRACES
tr_info("%u UC_change %u", fhss_structure->callbacks.read_timestamp(fhss_structure->fhss_api), next_channel);
#endif
fhss_structure->callbacks.change_channel(fhss_structure->fhss_api, next_channel);
#ifdef FHSS_CHANNEL_DEBUG_CBS
if (fhss_uc_switch) {
@ -540,8 +583,10 @@ static int fhss_ws_tx_handle_callback(const fhss_api_t *api, bool is_broadcast_a
int32_t tx_channel = neighbor_timing_info->uc_timing_info.fixed_channel;
if (neighbor_timing_info->uc_timing_info.unicast_channel_function == WS_TR51CF) {
tx_channel = tr51_get_uc_channel_index(fhss_structure->ws->tr51_channel_table, fhss_structure->ws->tr51_output_table, destination_slot, destination_address, neighbor_timing_info->uc_timing_info.unicast_number_of_channels, NULL);
tx_channel = fhss_channel_index_from_mask(neighbor_timing_info->uc_channel_list.channel_mask, tx_channel, fhss_structure->number_of_channels);
} else if (neighbor_timing_info->uc_timing_info.unicast_channel_function == WS_DH1CF) {
tx_channel = dh1cf_get_uc_channel_index(destination_slot, destination_address, neighbor_timing_info->uc_channel_list.channel_count);
tx_channel = fhss_channel_index_from_mask(neighbor_timing_info->uc_channel_list.channel_mask, tx_channel, fhss_structure->number_of_channels);
} else if (neighbor_timing_info->uc_timing_info.unicast_channel_function == WS_VENDOR_DEF_CF) {
if (fhss_structure->ws->fhss_configuration.vendor_defined_cf) {
tx_channel = fhss_structure->ws->fhss_configuration.vendor_defined_cf(fhss_structure->fhss_api, fhss_structure->ws->bc_slot, destination_address, fhss_structure->ws->fhss_configuration.bsi, neighbor_timing_info->uc_timing_info.unicast_number_of_channels);
@ -814,8 +859,13 @@ static uint32_t fhss_ws_get_retry_period_callback(const fhss_api_t *api, uint8_t
if (!fhss_structure) {
return return_value;
}
// We don't know the broadcast schedule, use large backoff with MAC retries
if (fhss_structure->ws->broadcast_timer_running == false) {
return 100000;
}
// We don't know the TX/RX slots, use randomised large backoff with MAC retries
if (fhss_structure->own_hop == 0xff) {
return return_value;
return ((uint32_t) randLIB_get_random_in_range(50, 150) * 1000);
}
if (fhss_structure->ws->is_on_bc_channel == true) {
return return_value;
@ -916,6 +966,7 @@ int fhss_ws_set_parent(fhss_structure_t *fhss_structure, const uint8_t eui64[8],
timeout -= MS_TO_US(bc_timing_info->broadcast_interval - bc_timing_info->broadcast_dwell_interval);
}
fhss_ws_start_timer(fhss_structure, timeout, fhss_broadcast_handler);
fhss_structure->ws->broadcast_timer_running = true;
uint16_t slots_since_reception = (bc_timing_info->broadcast_interval_offset + time_from_reception_ms) / bc_timing_info->broadcast_interval;
// TODO: Calculate drift error
fhss_structure->ws->fhss_configuration.fhss_bc_dwell_interval = bc_timing_info->broadcast_dwell_interval;

View File

@ -41,6 +41,7 @@ struct fhss_ws {
int16_t *tr51_channel_table;
uint8_t *tr51_output_table;
bool unicast_timer_running;
bool broadcast_timer_running;
bool is_on_bc_channel;
struct fhss_ws_configuration fhss_configuration;
const struct broadcast_timing_info *parent_bc_info;

View File

@ -21,20 +21,20 @@
#include "ns_list.h"
#include "ns_trace.h"
#include "mbedtls/md.h"
#include "Service_Libs/hmac/hmac_sha1.h"
#include "hmac_md.h"
#define TRACE_GROUP "hmac"
int8_t hmac_sha1_calc(const uint8_t *key, uint16_t key_len, const uint8_t *data, uint16_t data_len, uint8_t *result, uint8_t result_len)
int8_t hmac_md_calc(const alg_hmac_md_e md, const uint8_t *key, uint16_t key_len, const uint8_t *data, uint16_t data_len, uint8_t *result, uint8_t result_len)
{
#ifdef EXTRA_DEBUG_INFO
// Extensive debug for now, to be disabled later
tr_debug("hmac_sha_1 key %s\n", trace_array(key, key_len));
tr_debug("hmac_md key %s\n", trace_array(key, key_len));
const uint8_t *print_data = data;
uint16_t print_data_len = data_len;
while (true) {
tr_debug("hmac_sha_1 data %s\n", trace_array(print_data, print_data_len > 32 ? 32 : print_data_len));
tr_debug("hmac_md data %s\n", trace_array(print_data, print_data_len > 32 ? 32 : print_data_len));
if (print_data_len > 32) {
print_data_len -= 32;
print_data += 32;
@ -44,7 +44,12 @@ int8_t hmac_sha1_calc(const uint8_t *key, uint16_t key_len, const uint8_t *data,
}
#endif
const mbedtls_md_type_t md_type = MBEDTLS_MD_SHA1;
mbedtls_md_type_t md_type;
if (md == ALG_HMAC_MD5) {
md_type = MBEDTLS_MD_MD5;
} else {
md_type = MBEDTLS_MD_SHA1;
}
const mbedtls_md_info_t *md_info = mbedtls_md_info_from_type(md_type);
if (md_info == NULL) {
return -1;
@ -76,7 +81,7 @@ int8_t hmac_sha1_calc(const uint8_t *key, uint16_t key_len, const uint8_t *data,
memcpy(result, result_value, result_len);
#ifdef EXTRA_DEBUG_INFO
tr_debug("hmac_sha_1 result %s\n", trace_array(result_value, 20));
tr_debug("hmac_md result %s\n", trace_array(result_value, 20));
#endif
return 0;

View File

@ -18,11 +18,17 @@
#ifndef HMAC_SHA1_
#define HMAC_SHA1_
typedef enum {
ALG_HMAC_MD5,
ALG_HMAC_SHA1_160
} alg_hmac_md_e;
/**
* \brief Calculate HMAC-SHA1-160
* \brief Calculate HMAC-SHA1-160 or HMAC-MD5
*
* Calculate HMAC-SHA1-160
* Calculate HMAC-SHA1-160 or HMAC-MD5
*
* \param md message digest algorithm
* \param key pointer to key
* \param key_len key length
* \param data pointer to data
@ -34,6 +40,6 @@
* \return >= 0 success
*
*/
int8_t hmac_sha1_calc(const uint8_t *key, uint16_t key_len, const uint8_t *data, uint16_t data_len, uint8_t *result, uint8_t result_len);
int8_t hmac_md_calc(const alg_hmac_md_e md, const uint8_t *key, uint16_t key_len, const uint8_t *data, uint16_t data_len, uint8_t *result, uint8_t result_len);
#endif /* HMAC_SHA1_ */

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