Merge pull request #13473 from artokin/nanostack_relase_12_4_0_to_master

Nanostack release v12.4.0
pull/13501/head
Martin Kojtal 2020-08-25 09:40:45 +01:00 committed by GitHub
commit a32168c819
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
110 changed files with 5251 additions and 472 deletions

View File

@ -28,52 +28,99 @@
// #define TEST_GPIOS_ENABLED
// Arduino pin defaults for convenience
#if !defined(ATMEL_SPI_MOSI)
#define ATMEL_SPI_MOSI D11
#if defined(MBED_CONF_ATMEL_RF_SPI_MOSI)
#define ATMEL_SPI_MOSI MBED_CONF_ATMEL_RF_SPI_MOSI
#else
#define ATMEL_SPI_MOSI D11
#endif
#if !defined(ATMEL_SPI_MISO)
#define ATMEL_SPI_MISO D12
#if defined(MBED_CONF_ATMEL_RF_SPI_MISO)
#define ATMEL_SPI_MISO MBED_CONF_ATMEL_RF_SPI_MISO
#else
#define ATMEL_SPI_MISO D12
#endif
#if !defined(ATMEL_SPI_SCLK)
#define ATMEL_SPI_SCLK D13
#if defined(MBED_CONF_ATMEL_RF_SPI_SCLK)
#define ATMEL_SPI_SCLK MBED_CONF_ATMEL_RF_SPI_SCLK
#else
#define ATMEL_SPI_SCLK D13
#endif
#if !defined(ATMEL_SPI_CS)
#define ATMEL_SPI_CS D10
#if defined(MBED_CONF_ATMEL_RF_SPI_CS)
#define ATMEL_SPI_CS MBED_CONF_ATMEL_RF_SPI_CS
#else
#define ATMEL_SPI_CS D10
#endif
#if !defined(ATMEL_SPI_RST)
#define ATMEL_SPI_RST D5
#if defined(MBED_CONF_ATMEL_RF_SPI_RST)
#define ATMEL_SPI_RST MBED_CONF_ATMEL_RF_SPI_RST
#else
#define ATMEL_SPI_RST D5
#endif
#if !defined(ATMEL_SPI_SLP)
#define ATMEL_SPI_SLP D7
#if defined(MBED_CONF_ATMEL_RF_SPI_SLP)
#define ATMEL_SPI_SLP MBED_CONF_ATMEL_RF_SPI_SLP
#else
#define ATMEL_SPI_SLP D7
#endif
#if !defined(ATMEL_SPI_IRQ)
#define ATMEL_SPI_IRQ D9
#if defined(MBED_CONF_ATMEL_RF_SPI_IRQ)
#define ATMEL_SPI_IRQ MBED_CONF_ATMEL_RF_SPI_IRQ
#else
#define ATMEL_SPI_IRQ D9
#endif
#if !defined(ATMEL_I2C_SDA)
#define ATMEL_I2C_SDA D14
#if defined(MBED_CONF_ATMEL_RF_I2C_SDA)
#define ATMEL_I2C_SDA MBED_CONF_ATMEL_RF_I2C_SDA
#else
#define ATMEL_I2C_SDA D14
#endif
#if !defined(ATMEL_I2C_SCL)
#define ATMEL_I2C_SCL D15
#if defined(MBED_CONF_ATMEL_RF_I2C_SCL)
#define ATMEL_I2C_SCL MBED_CONF_ATMEL_RF_I2C_SCL
#else
#define ATMEL_I2C_SCL D15
#endif
#if !defined(TEST_PIN_TX)
#define TEST_PIN_TX D6
#if defined(MBED_CONF_ATMEL_RF_TEST_PIN_TX)
#define TEST_PIN_TX MBED_CONF_ATMEL_RF_TEST_PIN_TX
#else
#define TEST_PIN_TX D6
#endif
#if !defined(TEST_PIN_RX)
#define TEST_PIN_RX D3
#if defined(MBED_CONF_ATMEL_RF_TEST_PIN_RX)
#define TEST_PIN_RX MBED_CONF_ATMEL_RF_TEST_PIN_RX
#else
#define TEST_PIN_RX D3
#endif
#if !defined(TEST_PIN_CSMA)
#define TEST_PIN_CSMA D4
#if defined(MBED_CONF_ATMEL_RF_TEST_PIN_CSMA)
#define TEST_PIN_CSMA MBED_CONF_ATMEL_RF_TEST_PIN_CSMA
#else
#define TEST_PIN_CSMA D4
#endif
#if !defined(TEST_PIN_SPARE_1)
#if defined(MBED_CONF_ATMEL_RF_TEST_PIN_SPARE_1)
#define TEST_PIN_SPARE_1 MBED_CONF_ATMEL_RF_TEST_PIN_SPARE_1
#else
#define TEST_PIN_SPARE_1 D2
#endif
#if !defined(TEST_PIN_SPARE_2)
#if defined(MBED_CONF_ATMEL_RF_TEST_PIN_SPARE_2)
#define TEST_PIN_SPARE_2 MBED_CONF_ATMEL_RF_TEST_PIN_SPARE_2
#else
#define TEST_PIN_SPARE_2 D8
#endif
#if !defined(SE2435L_CSD)
#define SE2435L_CSD D2
#if defined(MBED_CONF_ATMEL_RF_SE2435L_CSD)
#define SE2435L_CSD MBED_CONF_ATMEL_RF_SE2435L_CSD
#else
#define SE2435L_CSD D2
#endif
#if !defined(SE2435L_ANT_SEL)
#if defined(MBED_CONF_ATMEL_RF_SE2435L_ANT_SEL)
#define SE2435L_ANT_SEL MBED_CONF_ATMEL_RF_SE2435L_ANT_SEL
#else
#define SE2435L_ANT_SEL D8
#endif

View File

@ -1,6 +1,70 @@
{
"name": "atmel-rf",
"config": {
"SPI_MOSI": {
"help": "SPI_MOSI pin configured for SPI connection.",
"value": null
},
"SPI_MISO": {
"help": "SPI_MISO pin configured for SPI connection.",
"value": null
},
"SPI_SCLK": {
"help": "SPI_SCLK pin configured for SPI connection.",
"value": null
},
"SPI_CS": {
"help": "SPI_CS pin configured for SPI connection.",
"value": null
},
"SPI_RST": {
"help": "SPI_RST pin configured for SPI connection.",
"value": null
},
"SPI_SLP": {
"help": "SPI_SLP pin configured for SPI connection.",
"value": null
},
"SPI_IRQ": {
"help": "SPI_IRQ pin configured for SPI connection.",
"value": null
},
"I2C_SDA": {
"help": "I2C_SDA pin configured for I2C connection.",
"value": null
},
"I2C_SCL": {
"help": "I2C_SCL pin configured for I2C connection.",
"value": null
},
"TEST_PIN_TX": {
"help": "TEST_PIN_TX pin configured for TX.",
"value": null
},
"TEST_PIN_RX": {
"help": "TEST_PIN_RX pin configured for RX.",
"value": null
},
"TEST_PIN_CSMA": {
"help": "TEST_PIN_CSMA pin configured for CSMA.",
"value": null
},
"TEST_PIN_SPARE_1": {
"help": "TEST_PIN_SPARE_1.",
"value": null
},
"TEST_PIN_SPARE_2": {
"help": "TEST_PIN_SPARE_2.",
"value": null
},
"SE2435L_CSD": {
"help": "SE2435L_CSD pin configuration.",
"value": null
},
"SE2435L_ANT_SEL": {
"help": "SE2435L_ANT_SEL pin confuguration.",
"value": null
},
"full-spi-speed": {
"help": "Maximum SPI clock speed (Hz), as long as sufficient inter-byte spacing",
"value": 7500000

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

@ -34,8 +34,21 @@
#include "inttypes.h"
#include "Timeout.h"
#include "platform/mbed_error.h"
#include "platform/mbed_version.h"
#if (MBED_VERSION > MBED_ENCODE_VERSION(6, 0, 0))
/* Mbed OS 6.0 introduces support for chrono time management */
using namespace std::chrono;
#define ATMEL_RF_TIME_50US 50us
#define ATMEL_RF_TIME_2MS 2ms
#define ATMEL_RF_TIME_10MS 10ms
#define ATMEL_RF_ATTACH(timer_ref, signal_ref, timeout_ref) timer_ref.attach(signal_ref, timeout_ref)
#else
#define ATMEL_RF_TIME_50US 50
#define ATMEL_RF_TIME_2MS 2
#define ATMEL_RF_TIME_10MS 10
#define ATMEL_RF_ATTACH(timer_ref, signal_ref, timeout_ref) timer_ref.attach_us(signal_ref, timeout_ref)
#endif
#define TRACE_GROUP "AtRF"
@ -347,7 +360,6 @@ static rf_trx_part_e rf_radio_type_read(void)
return ret_val;
}
/*
* \brief Function starts the ACK wait timeout.
*
@ -358,9 +370,9 @@ static rf_trx_part_e rf_radio_type_read(void)
static void rf_if_ack_wait_timer_start(uint16_t slots)
{
#ifdef MBED_CONF_RTOS_PRESENT
rf->ack_timer.attach(rf_if_ack_timer_signal, slots * 50us);
ATMEL_RF_ATTACH(rf->ack_timer, rf_if_ack_timer_signal, slots * ATMEL_RF_TIME_50US);
#else
rf->ack_timer.attach(rf_ack_wait_timer_interrupt, slots * 50us);
ATMEL_RF_ATTACH(rf->ack_timer, rf_ack_wait_timer_interrupt, slots * ATMEL_RF_TIME_50US);
#endif
}
@ -374,9 +386,9 @@ static void rf_if_ack_wait_timer_start(uint16_t slots)
static void rf_if_calibration_timer_start(uint32_t slots)
{
#ifdef MBED_CONF_RTOS_PRESENT
rf->cal_timer.attach(rf_if_cal_timer_signal, slots * 50us);
ATMEL_RF_ATTACH(rf->cal_timer, rf_if_cal_timer_signal, slots * ATMEL_RF_TIME_50US);
#else
rf->cal_timer.attach(rf_calibration_timer_interrupt, slots * 50us);
ATMEL_RF_ATTACH(rf->cal_timer, rf_calibration_timer_interrupt, slots * ATMEL_RF_TIME_50US);
#endif
}
@ -390,9 +402,9 @@ static void rf_if_calibration_timer_start(uint32_t slots)
static void rf_if_cca_timer_start(uint32_t slots)
{
#ifdef MBED_CONF_RTOS_PRESENT
rf->cca_timer.attach(rf_if_cca_timer_signal, slots * 50us);
ATMEL_RF_ATTACH(rf->cca_timer, rf_if_cca_timer_signal, slots * ATMEL_RF_TIME_50US);
#else
rf->cca_timer.attach(rf_cca_timer_interrupt, slots * 50us);
ATMEL_RF_ATTACH(rf->cca_timer, rf_cca_timer_interrupt, slots * ATMEL_RF_TIME_50US);
#endif
}
@ -521,14 +533,14 @@ static void rf_if_reset_radio(void)
#endif
rf->IRQ.rise(nullptr);
rf->RST = 1;
ThisThread::sleep_for(2ms);
ThisThread::sleep_for(ATMEL_RF_TIME_2MS);
rf->RST = 0;
ThisThread::sleep_for(10ms);
ThisThread::sleep_for(ATMEL_RF_TIME_10MS);
CS_RELEASE();
rf->SLP_TR = 0;
ThisThread::sleep_for(10ms);
ThisThread::sleep_for(ATMEL_RF_TIME_10MS);
rf->RST = 1;
ThisThread::sleep_for(10ms);
ThisThread::sleep_for(ATMEL_RF_TIME_10MS);
rf->IRQ.rise(&rf_if_interrupt_handler);
}

View File

@ -31,8 +31,18 @@
#include "Thread.h"
#include "mbed_wait_api.h"
#include "platform/mbed_error.h"
#include "platform/mbed_version.h"
#if (MBED_VERSION > MBED_ENCODE_VERSION(6, 0, 0))
/* Mbed OS 6.0 introduces support for chrono time management */
using namespace std::chrono;
#define S2LP_USE_CHRONO
#define S2LP_TIME_50US 50us
#define S2LP_TIME_10MS 10ms
#else
#define S2LP_TIME_10MS 10
#endif
using namespace mbed;
using namespace rtos;
@ -278,7 +288,11 @@ static void rf_calculate_symbol_rate(uint32_t baudrate, phy_modulation_e modulat
static uint32_t rf_get_timestamp(void)
{
#ifdef S2LP_USE_CHRONO
return (uint32_t)rf->tx_timer.elapsed_time().count();
#else
return (uint32_t)rf->tx_timer.read_us();
#endif
}
static void rf_update_tx_active_time(void)
@ -868,7 +882,11 @@ static void rf_cca_timer_stop(void)
static void rf_cca_timer_start(uint32_t slots)
{
#ifdef S2LP_USE_CHRONO
rf->cca_timer.attach(rf_cca_timer_signal, microseconds(slots));
#else
rf->cca_timer.attach_us(rf_cca_timer_signal, slots);
#endif
TEST_CSMA_STARTED
}
@ -905,7 +923,11 @@ static void rf_backup_timer_stop(void)
static void rf_backup_timer_start(uint32_t slots)
{
#ifdef S2LP_USE_CHRONO
rf->backup_timer.attach(rf_backup_timer_signal, microseconds(slots));
#else
rf->backup_timer.attach_us(rf_backup_timer_signal, slots);
#endif
}
static int8_t rf_start_cca(uint8_t *data_ptr, uint16_t data_length, uint8_t tx_handle, data_protocol_e data_protocol)
@ -1179,10 +1201,10 @@ static void rf_reset(void)
{
// Shutdown
rf->SDN = 1;
ThisThread::sleep_for(10ms);
ThisThread::sleep_for(S2LP_TIME_10MS);
// Wake up
rf->SDN = 0;
ThisThread::sleep_for(10ms);
ThisThread::sleep_for(S2LP_TIME_10MS);
}
static void rf_init(void)
@ -1330,7 +1352,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

@ -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

@ -102,6 +102,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.
*
@ -582,6 +600,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;

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