From d8420fb4c9b4072789b189e9d46e63551cfafd19 Mon Sep 17 00:00:00 2001 From: Arto Kinnunen Date: Mon, 8 Jun 2020 15:03:29 +0300 Subject: [PATCH 1/5] 802.15.4 STM S2LP driver update Sync with master v1.0.5 --- .../source/NanostackRfPhys2lp.cpp | 22 ++++++++++++++++--- .../source/rf_configuration.c | 2 +- .../stm-s2lp-rf-driver/NanostackRfPhys2lp.h | 6 ++--- 3 files changed, 23 insertions(+), 7 deletions(-) diff --git a/components/802.15.4_RF/stm-s2lp-rf-driver/source/NanostackRfPhys2lp.cpp b/components/802.15.4_RF/stm-s2lp-rf-driver/source/NanostackRfPhys2lp.cpp index 843d4c4fbd..720a0535ec 100644 --- a/components/802.15.4_RF/stm-s2lp-rf-driver/source/NanostackRfPhys2lp.cpp +++ b/components/802.15.4_RF/stm-s2lp-rf-driver/source/NanostackRfPhys2lp.cpp @@ -182,7 +182,9 @@ static bool rf_rx_filter(uint8_t *mac_header, uint8_t *mac_64bit_addr, uint8_t * static void rf_cca_timer_start(uint32_t slots); static RFPins *rf; +#ifdef TEST_GPIOS_ENABLED static TestPins_S2LP *test_pins; +#endif static phy_device_driver_s device_driver; static int8_t rf_radio_driver_id = -1; static uint8_t *tx_data_ptr; @@ -207,6 +209,7 @@ static uint8_t s2lp_short_address[2]; static uint8_t s2lp_MAC[8]; static rf_mode_e rf_mode = RF_MODE_NORMAL; static bool rf_update_config = false; +static bool rf_update_cca_threshold = false; static uint16_t cur_packet_len = 0xffff; static uint32_t receiver_ready_timestamp; static int16_t rssi_threshold = RSSI_THRESHOLD; @@ -704,6 +707,13 @@ static int8_t rf_extension(phy_extension_type_e extension_type, uint8_t *data_pt rf_receive(rf_rx_channel); } break; + case PHY_EXTENSION_SET_CHANNEL_CCA_THRESHOLD: + if ((rssi_threshold != (int8_t)*data_ptr) && (rf_state != RF_RX_STARTED)) { + rssi_threshold = (int8_t)*data_ptr; // *NOPAD* + rf_update_cca_threshold = true; + rf_receive(rf_rx_channel); + } + break; default: break; } @@ -752,9 +762,9 @@ static void rf_tx_sent_handler(void) TEST_TX_DONE rf_backup_timer_stop(); rf_disable_interrupt(TX_DATA_SENT); + rf_update_tx_active_time(); if (rf_state != RF_TX_ACK) { tx_finnish_time = rf_get_timestamp(); - rf_update_tx_active_time(); rf_state = RF_IDLE; rf_receive(rf_rx_channel); if (device_driver.phy_tx_done_cb) { @@ -821,7 +831,6 @@ static void rf_cca_timer_interrupt(void) } rf_flush_tx_fifo(); tx_finnish_time = rf_get_timestamp(); - rf_update_tx_active_time(); if (device_driver.phy_tx_done_cb) { device_driver.phy_tx_done_cb(rf_radio_driver_id, mac_tx_handle, PHY_LINK_CCA_FAIL, 0, 0); } @@ -955,7 +964,6 @@ static void rf_handle_ack(uint8_t seq_number, uint8_t pending) phy_link_tx_status_e phy_status; if (tx_sequence == (uint16_t)seq_number) { tx_finnish_time = rf_get_timestamp(); - rf_update_tx_active_time(); if (pending) { phy_status = PHY_LINK_TX_DONE_PENDING; } else { @@ -1047,6 +1055,12 @@ static void rf_receive(uint8_t rx_channel) rf_update_config = false; rf_set_channel_configuration_registers(); } + if (rf_update_cca_threshold == true) { + rf_update_cca_threshold = false; + uint8_t rssi_th; + rf_conf_calculate_rssi_threshold_registers(rssi_threshold, &rssi_th); + rf_write_register(RSSI_TH, rssi_th); + } if (rx_channel != rf_rx_channel) { rf_write_register(CHNUM, rx_channel * rf_channel_multiplier); rf_rx_channel = rf_new_channel = rx_channel; @@ -1280,7 +1294,9 @@ int8_t NanostackRfPhys2lp::rf_register() } rf = _rf; +#ifdef TEST_GPIOS_ENABLED test_pins = _test_pins; +#endif int8_t radio_id = rf_device_register(_mac_addr); if (radio_id < 0) { diff --git a/components/802.15.4_RF/stm-s2lp-rf-driver/source/rf_configuration.c b/components/802.15.4_RF/stm-s2lp-rf-driver/source/rf_configuration.c index 3cb0c2b6a1..9f261ee02d 100644 --- a/components/802.15.4_RF/stm-s2lp-rf-driver/source/rf_configuration.c +++ b/components/802.15.4_RF/stm-s2lp-rf-driver/source/rf_configuration.c @@ -157,7 +157,7 @@ void rf_conf_calculate_rx_filter_bandwidth_registers(uint32_t rx_bandwidth, uint int16_t rf_conf_cca_threshold_percent_to_rssi(uint8_t percent) { - uint8_t step = (MAX_RSSI_THRESHOLD-MIN_RSSI_THRESHOLD); + uint8_t step = (MAX_RSSI_THRESHOLD - MIN_RSSI_THRESHOLD); return MIN_RSSI_THRESHOLD + (step * percent) / 100; } diff --git a/components/802.15.4_RF/stm-s2lp-rf-driver/stm-s2lp-rf-driver/NanostackRfPhys2lp.h b/components/802.15.4_RF/stm-s2lp-rf-driver/stm-s2lp-rf-driver/NanostackRfPhys2lp.h index d092c10623..280aa3ddba 100644 --- a/components/802.15.4_RF/stm-s2lp-rf-driver/stm-s2lp-rf-driver/NanostackRfPhys2lp.h +++ b/components/802.15.4_RF/stm-s2lp-rf-driver/stm-s2lp-rf-driver/NanostackRfPhys2lp.h @@ -67,8 +67,8 @@ #define S2LP_TEST_PIN_RX D5 #endif -#if defined(TMBED_CONF_S2LP_TEST_PIN_CSMA) -#define S2LP_TEST_PIN_CSMA TMBED_CONF_S2LP_TEST_PIN_CSMA +#if defined(MBED_CONF_S2LP_TEST_PIN_CSMA) +#define S2LP_TEST_PIN_CSMA MBED_CONF_S2LP_TEST_PIN_CSMA #else #define S2LP_TEST_PIN_CSMA D4 #endif @@ -80,7 +80,7 @@ #endif #if defined(MBED_CONF_S2LP_TEST_PIN_SPARE_2) -#define S2LP_TEST_PIN_SPARE_2 DMBED_CONF_S2LP_TEST_PIN_SPARE_2 +#define S2LP_TEST_PIN_SPARE_2 MBED_CONF_S2LP_TEST_PIN_SPARE_2 #else #define S2LP_TEST_PIN_SPARE_2 D8 #endif From 05290a86771cb6df5f43b980c8e39ae03a93077e Mon Sep 17 00:00:00 2001 From: Arto Kinnunen Date: Mon, 8 Jun 2020 15:33:46 +0300 Subject: [PATCH 2/5] Update 802.15.4 Atmel RF driver Sync with master version v3.3.0 --- .../atmel-rf-driver/NanostackRfPhyAtmel.h | 10 + .../atmel-rf-driver/source/AT86RF215Reg.h | 58 +++++- .../atmel-rf-driver/source/AT86RFReg.h | 1 + .../source/NanostackRfPhyAT86RF215.cpp | 195 +++++++++++++++--- .../source/NanostackRfPhyAtmel.cpp | 30 ++- .../atmel-rf-driver/source/rfbits.h | 8 + 6 files changed, 264 insertions(+), 38 deletions(-) diff --git a/components/802.15.4_RF/atmel-rf-driver/atmel-rf-driver/NanostackRfPhyAtmel.h b/components/802.15.4_RF/atmel-rf-driver/atmel-rf-driver/NanostackRfPhyAtmel.h index 028663f63e..d6fab5cf5d 100644 --- a/components/802.15.4_RF/atmel-rf-driver/atmel-rf-driver/NanostackRfPhyAtmel.h +++ b/components/802.15.4_RF/atmel-rf-driver/atmel-rf-driver/NanostackRfPhyAtmel.h @@ -70,9 +70,16 @@ #if !defined(TEST_PIN_SPARE_2) #define TEST_PIN_SPARE_2 D8 #endif +#if !defined(SE2435L_CSD) +#define SE2435L_CSD D2 +#endif +#if !defined(SE2435L_ANT_SEL) +#define SE2435L_ANT_SEL D8 +#endif class RFBits; class TestPins; +class Se2435Pins; class NanostackRfPhyAtmel : public NanostackRfPhy { public: @@ -86,10 +93,13 @@ public: virtual void set_mac_address(uint8_t *mac); private: +#if !defined(DISABLE_AT24MAC) AT24Mac _mac; +#endif uint8_t _mac_addr[8]; RFBits *_rf; TestPins *_test_pins; + Se2435Pins *_se2435_pa_pins; bool _mac_set; const PinName _spi_mosi; diff --git a/components/802.15.4_RF/atmel-rf-driver/source/AT86RF215Reg.h b/components/802.15.4_RF/atmel-rf-driver/source/AT86RF215Reg.h index 5463570f14..6836b0cb3f 100644 --- a/components/802.15.4_RF/atmel-rf-driver/source/AT86RF215Reg.h +++ b/components/802.15.4_RF/atmel-rf-driver/source/AT86RF215Reg.h @@ -26,6 +26,7 @@ extern "C" { #define RF24_IRQS 0x01 #define BBC0_IRQS 0x02 #define BBC1_IRQS 0x03 +#define RF_AUXS 0x01 #define RF_CFG 0x06 #define RF_IQIFC1 0x0B #define RF_PN 0x0D @@ -47,6 +48,8 @@ extern "C" { #define RF_EDV 0x10 #define RF_TXCUTC 0x12 #define RF_TXDFE 0x13 +#define RF_PAC 0x14 +#define RF_PADFE 0x16 #define BBC_IRQM 0x00 #define BBC_PC 0x01 #define BBC_RXFLL 0x04 @@ -55,6 +58,9 @@ extern "C" { #define BBC_TXFLH 0x07 #define BBC_FBLL 0x08 #define BBC_FBLH 0x09 +#define BBC_OFDMPHRTX 0x0C +#define BBC_OFDMC 0x0E +#define BBC_OFDMSW 0x0F #define BBC_OQPSKC0 0x10 #define BBC_OQPSKC1 0x11 #define BBC_OQPSKC2 0x12 @@ -82,6 +88,20 @@ extern "C" { #define BBC1_FBRXS 0x3000 #define BBC1_FBTXS 0x3800 +// RF_AUXS +#define EXTLNABYP (1 << 7) +#define AGCMAP 0x60 +#define AGCMAP_2 (2 << 5) +#define AVEN (1 << 3) + +// RF_PAC +#define TXPWR 0x1F +#define TXPWR_11 (11 << 0) + +// RF_PADFE +#define PADFE 0xC0 +#define RF_FEMODE3 (3 << 6) + // RF_AGCC #define AGCI (1 << 6) #define AVGS 0x30 @@ -90,7 +110,7 @@ extern "C" { // RF_AGCS #define TGT 0xE0 #define TGT_1 (1 << 5) - +#define TGT_3 (3 << 5) // RF_RXBWC #define BW 0x0F @@ -131,6 +151,7 @@ extern "C" { // RF_TXDFE, RF_RXDFE #define RCUT 0xE0 #define RCUT_4 (4 << 5) +#define RCUT_3 (3 << 5) #define RCUT_2 (2 << 5) #define RCUT_1 (1 << 5) #define RCUT_0 (0 << 5) @@ -144,6 +165,41 @@ extern "C" { #define SR_2 (2 << 0) #define SR_1 (1 << 0) +// BBC_OFDMPHRTX +#define MCS 0x07 +#define MCS_0 (0 << 0) +#define MCS_1 (1 << 0) +#define MCS_2 (2 << 0) +#define MCS_3 (3 << 0) +#define MCS_4 (4 << 0) +#define MCS_5 (5 << 0) +#define MCS_6 (6 << 0) + +// BBC_OFDMC +#define SSRX 0xC0 +#define SSRX_0 (0 << 6) +#define SSRX_1 (1 << 6) +#define SSRX_2 (2 << 6) +#define SSRX_3 (3 << 6) +#define SSTX 0x30 +#define SSTX_0 (0 << 4) +#define SSTX_1 (1 << 4) +#define SSTX_2 (2 << 4) +#define SSTX_3 (3 << 4) +#define LFO (1 << 3) +#define POI (1 << 2) +#define OPT 0x03 +#define OPT_1 (0 << 0) +#define OPT_2 (1 << 0) +#define OPT_3 (2 << 0) +#define OPT_4 (3 << 0) + +// BBC_OFDMSW +#define OFDM_PDT 0xE0 +#define OFDM_PDT_5 (5 << 5) +#define OFDM_PDT_4 (4 << 5) +#define OFDM_PDT_3 (3 << 5) + // BBC_FSKC0 #define BT 0xC0 #define BT_20 (3 << 6) diff --git a/components/802.15.4_RF/atmel-rf-driver/source/AT86RFReg.h b/components/802.15.4_RF/atmel-rf-driver/source/AT86RFReg.h index c53d9fe922..fb86b7119b 100644 --- a/components/802.15.4_RF/atmel-rf-driver/source/AT86RFReg.h +++ b/components/802.15.4_RF/atmel-rf-driver/source/AT86RFReg.h @@ -48,6 +48,7 @@ extern "C" { #define PART_AT86RF212 0x07 #define PART_AT86RF233 0x0B #define PART_AT86RF215 0x34 +#define PART_AT86RF215M 0x36 #define VERSION_AT86RF212 0x01 #define VERSION_AT86RF212B 0x03 diff --git a/components/802.15.4_RF/atmel-rf-driver/source/NanostackRfPhyAT86RF215.cpp b/components/802.15.4_RF/atmel-rf-driver/source/NanostackRfPhyAT86RF215.cpp index 09c3180010..488b337527 100644 --- a/components/802.15.4_RF/atmel-rf-driver/source/NanostackRfPhyAT86RF215.cpp +++ b/components/802.15.4_RF/atmel-rf-driver/source/NanostackRfPhyAT86RF215.cpp @@ -23,6 +23,7 @@ #include "platform/mbed_wait_api.h" #include "nanostack/platform/arm_hal_phy.h" #include "NanostackRfPhyAtmel.h" +#include "AT86RFReg.h" #include "AT86RF215Reg.h" #include "mbed_trace.h" #include "common_functions.h" @@ -99,6 +100,7 @@ static int rf_set_channel(uint16_t channel, rf_modules_e module); static int rf_set_ch0_frequency(uint32_t frequency, rf_modules_e module); static int rf_set_channel_spacing(uint32_t channel_spacing, rf_modules_e module); static int rf_set_fsk_symbol_rate_configuration(uint32_t symbol_rate, rf_modules_e module); +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); // Defined register read/write functions @@ -164,6 +166,7 @@ using namespace rtos; #include "rfbits.h" static RFBits *rf; static TestPins *test_pins; +static Se2435Pins *se2435_pa_pins = NULL; #define MAC_FRAME_TYPE_MASK 0x07 #define MAC_TYPE_ACK (2) @@ -300,6 +303,9 @@ 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_CHANNEL_CCA_THRESHOLD: + cca_threshold = (int8_t) *data_ptr; // *NOPAD* + 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) { @@ -378,7 +384,8 @@ static void rf_init(void) static void rf_init_registers(rf_modules_e module) { // O-QPSK configuration using IEEE Std 802.15.4-2011 - // FSK configuration using IEEE Std 802.15.4g-2012 + // FSK/OFDM configuration using IEEE Std 802.15.4g-2012 + // OFDM configuration is experimental only if (mac_mode == IEEE_802_15_4_2011) { device_driver.link_type = PHY_LINK_15_4_2_4GHZ_TYPE; // 16-bit FCS @@ -405,41 +412,72 @@ static void rf_init_registers(rf_modules_e module) rf_write_bbc_register_field(BBC_AFFTM, module, TYPE_2, TYPE_2); } else if (mac_mode == IEEE_802_15_4G_2012) { device_driver.link_type = PHY_LINK_15_4_SUBGHZ_TYPE; - // Enable FSK - rf_write_bbc_register_field(BBC_PC, module, PT, BB_MRFSK); // Disable auto ack rf_write_bbc_register_field(BBC_AMCS, module, AACK, 0); // Disable address filter unit 0 rf_write_bbc_register_field(BBC_AFC0, module, AFEN0, 0); - // Set bandwidth time product - rf_write_bbc_register_field(BBC_FSKC0, module, BT, BT_20); - // Disable interleaving - rf_write_bbc_register_field(BBC_FSKC2, module, FECIE, 0); - // Disable receiver override - rf_write_bbc_register_field(BBC_FSKC2, module, RXO, RXO_DIS); - // Set modulation index - if (phy_current_config.modulation_index == MODULATION_INDEX_0_5) { - rf_write_bbc_register_field(BBC_FSKC0, module, MIDX, MIDX_05); - rf_write_rf_register_field(RF_TXDFE, module, RCUT, RCUT_0); - } else { - rf_write_bbc_register_field(BBC_FSKC0, module, MIDX, MIDX_10); - rf_write_rf_register_field(RF_TXDFE, module, RCUT, RCUT_4); + // Enable FSK + if (phy_current_config.modulation == M_2FSK) { + 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); + // Disable interleaving + rf_write_bbc_register_field(BBC_FSKC2, module, FECIE, 0); + // Disable receiver override + rf_write_bbc_register_field(BBC_FSKC2, module, RXO, RXO_DIS); + // Set modulation index + if (phy_current_config.modulation_index == MODULATION_INDEX_0_5) { + rf_write_bbc_register_field(BBC_FSKC0, module, MIDX, MIDX_05); + rf_write_rf_register_field(RF_TXDFE, module, RCUT, RCUT_0); + } else { + rf_write_bbc_register_field(BBC_FSKC0, module, MIDX, MIDX_10); + rf_write_rf_register_field(RF_TXDFE, module, RCUT, RCUT_4); + } + // Set Gain control settings + rf_write_rf_register_field(RF_AGCC, module, AVGS, AVGS_8_SAMPLES); + rf_write_rf_register_field(RF_AGCS, module, TGT, TGT_1); + // Set symbol rate and related configurations + rf_set_fsk_symbol_rate_configuration(phy_current_config.datarate, module); + // Set preamble length + uint8_t preamble_len = 24; + if (phy_current_config.datarate < 150000) { + preamble_len = 8; + } else if (phy_current_config.datarate < 300000) { + preamble_len = 12; + } + rf_write_bbc_register(BBC_FSKPLL, module, preamble_len); + // Set preamble detector threshold + rf_write_bbc_register_field(BBC_FSKC3, module, PDT, PDT_6); + } else if (phy_current_config.modulation == M_OFDM) { + rf_write_bbc_register_field(BBC_PC, module, PT, BB_MROFDM); + // Set TX scrambler seed + rf_write_bbc_register_field(BBC_OFDMC, module, SSTX, SSTX_0); + // Set RX scrambler seed + rf_write_bbc_register_field(BBC_OFDMC, module, SSRX, SSRX_0); + // Set phyOFDMInterleaving + rf_write_bbc_register_field(BBC_OFDMC, module, POI, 0); + // Set low frequency offset bit + rf_write_bbc_register_field(BBC_OFDMC, module, LFO, 0); + // Configure using bandwidth option + rf_configure_by_ofdm_bandwidth_option(4, 300000, module); + // Set Gain control settings + rf_write_rf_register_field(RF_AGCC, module, AVGS, AVGS_8_SAMPLES); + rf_write_rf_register_field(RF_AGCC, module, AGCI, 0); + rf_write_rf_register_field(RF_AGCS, module, TGT, TGT_3); } - // Set Gain control settings - rf_write_rf_register_field(RF_AGCC, module, AVGS, AVGS_8_SAMPLES); - rf_write_rf_register_field(RF_AGCS, module, TGT, TGT_1); - // Set symbol rate and related configurations - rf_set_fsk_symbol_rate_configuration(phy_current_config.datarate, module); - // Set preamble length - uint8_t preamble_len = 24; - if (phy_current_config.datarate < 150000) { - preamble_len = 8; - } else if (phy_current_config.datarate < 300000) { - preamble_len = 12; - } - rf_write_bbc_register(BBC_FSKPLL, module, preamble_len); - rf_write_bbc_register_field(BBC_FSKC3, module, PDT, PDT_6); } + if (se2435_pa_pins) { + // Wakeup SE2435L + se2435_pa_pins->CSD = 1; + // Antenna port selection: (0 - port 1, 1 - port 2) + se2435_pa_pins->ANT_SEL = 0; + // 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); + } + // Enable analog voltage regulator + rf_write_rf_register_field(RF_AUXS, module, AVEN, AVEN); // Disable filtering FCS rf_write_bbc_register_field(BBC_PC, module, FCSFE, 0); // Set channel spacing @@ -488,9 +526,10 @@ static int8_t rf_start_csma_ca(uint8_t *data_ptr, uint16_t data_length, uint8_t tx_sequence = *(data_ptr + 2); } rf_write_tx_buffer(data_ptr, data_length, rf_module); - if (phy_current_config.modulation == M_OQPSK) { + // Add CRC bytes + if (mac_mode == IEEE_802_15_4_2011) { data_length += 2; - } else if (phy_current_config.modulation == M_2FSK) { + } else { data_length += 4; } rf_write_tx_packet_length(data_length, rf_module); @@ -614,9 +653,10 @@ static void rf_handle_rx_done(void) rf_handle_ack(rx_buffer[2], rx_buffer[0] & MAC_DATA_PENDING); } else { int8_t rssi = (int8_t) rf_read_rf_register(RF_EDV, rf_module); - if (phy_current_config.modulation == M_OQPSK) { + // Cut CRC bytes + if (mac_mode == IEEE_802_15_4_2011) { cur_rx_packet_len -= 2; - } else if (phy_current_config.modulation == M_2FSK) { + } else { cur_rx_packet_len -= 4; } device_driver.phy_rx_cb(rx_buffer, cur_rx_packet_len, 0xf0, rssi, rf_radio_driver_id); @@ -1055,6 +1095,75 @@ static int rf_set_fsk_symbol_rate_configuration(uint32_t symbol_rate, rf_modules return 0; } +static int rf_configure_by_ofdm_bandwidth_option(uint8_t option, uint32_t data_rate, rf_modules_e module) +{ + if (!option || option > 4) { + return -1; + } + uint32_t datarate_tmp = 100000 >> (option - 1); + + // Set modulation and coding scheme + if (data_rate == datarate_tmp) { + rf_write_bbc_register_field(BBC_OFDMPHRTX, module, MCS, MCS_0); + } else if (data_rate == datarate_tmp * 2) { + rf_write_bbc_register_field(BBC_OFDMPHRTX, module, MCS, MCS_1); + } else if (data_rate == datarate_tmp * 4) { + rf_write_bbc_register_field(BBC_OFDMPHRTX, module, MCS, MCS_2); + } else if (data_rate == datarate_tmp * 8) { + rf_write_bbc_register_field(BBC_OFDMPHRTX, module, MCS, MCS_3); + } else if (data_rate == datarate_tmp * 12) { + rf_write_bbc_register_field(BBC_OFDMPHRTX, module, MCS, MCS_4); + } else if (data_rate == datarate_tmp * 16) { + rf_write_bbc_register_field(BBC_OFDMPHRTX, module, MCS, MCS_5); + } else if (data_rate == datarate_tmp * 24) { + rf_write_bbc_register_field(BBC_OFDMPHRTX, module, MCS, MCS_6); + } else { + return -1; + } + if (option == 1) { + rf_write_bbc_register_field(BBC_OFDMC, module, OPT, OPT_1); + rf_write_rf_register_field(RF_TXDFE, module, SR, SR_3); + rf_write_rf_register_field(RF_RXDFE, module, SR, SR_3); + rf_write_rf_register_field(RF_TXDFE, module, RCUT, RCUT_4); + rf_write_rf_register_field(RF_RXDFE, module, RCUT, RCUT_4); + rf_write_rf_register_field(RF_TXCUTC, module, LPFCUT, RF_FLC800KHZ); + rf_write_rf_register_field(RF_RXBWC, module, BW, RF_BW1250KHZ_IF2000KHZ); + rf_write_rf_register_field(RF_RXBWC, module, IFS, IFS); + rf_write_bbc_register_field(BBC_OFDMSW, module, OFDM_PDT, OFDM_PDT_5); + } else if (option == 2) { + rf_write_bbc_register_field(BBC_OFDMC, module, OPT, OPT_2); + rf_write_rf_register_field(RF_TXDFE, module, SR, SR_3); + rf_write_rf_register_field(RF_RXDFE, module, SR, SR_3); + rf_write_rf_register_field(RF_TXDFE, module, RCUT, RCUT_3); + rf_write_rf_register_field(RF_RXDFE, module, RCUT, RCUT_2); + rf_write_rf_register_field(RF_TXCUTC, module, LPFCUT, RF_FLC500KHZ); + rf_write_rf_register_field(RF_RXBWC, module, BW, RF_BW800KHZ_IF1000KHZ); + rf_write_rf_register_field(RF_RXBWC, module, IFS, IFS); + rf_write_bbc_register_field(BBC_OFDMSW, module, OFDM_PDT, OFDM_PDT_5); + } else if (option == 3) { + rf_write_bbc_register_field(BBC_OFDMC, module, OPT, OPT_3); + rf_write_rf_register_field(RF_TXDFE, module, SR, SR_6); + rf_write_rf_register_field(RF_RXDFE, module, SR, SR_6); + rf_write_rf_register_field(RF_TXDFE, module, RCUT, RCUT_3); + rf_write_rf_register_field(RF_RXDFE, module, RCUT, RCUT_2); + rf_write_rf_register_field(RF_TXCUTC, module, LPFCUT, RF_FLC250KHZ); + rf_write_rf_register_field(RF_RXBWC, module, BW, RF_BW400KHZ_IF500KHZ); + rf_write_rf_register_field(RF_RXBWC, module, IFS, 0); + rf_write_bbc_register_field(BBC_OFDMSW, module, OFDM_PDT, OFDM_PDT_4); + } else if (option == 4) { + rf_write_bbc_register_field(BBC_OFDMC, module, OPT, OPT_4); + rf_write_rf_register_field(RF_TXDFE, module, SR, SR_6); + rf_write_rf_register_field(RF_RXDFE, module, SR, SR_6); + rf_write_rf_register_field(RF_TXDFE, module, RCUT, RCUT_2); + rf_write_rf_register_field(RF_RXDFE, module, RCUT, RCUT_1); + rf_write_rf_register_field(RF_TXCUTC, module, LPFCUT, RF_FLC160KHZ); + rf_write_rf_register_field(RF_RXBWC, module, BW, RF_BW250KHZ_IF250KHZ); + rf_write_rf_register_field(RF_RXBWC, module, IFS, 1); + rf_write_bbc_register_field(BBC_OFDMSW, module, OFDM_PDT, OFDM_PDT_3); + } + return 0; +} + static void rf_conf_set_cca_threshold(uint8_t percent) { uint8_t step = (MAX_CCA_THRESHOLD - MIN_CCA_THRESHOLD); @@ -1094,10 +1203,28 @@ int RFBits::init_215_driver(RFBits *_rf, TestPins *_test_pins, const uint8_t mac test_pins = _test_pins; irq_thread_215.start(mbed::callback(this, &RFBits::rf_irq_task)); rf->spi.frequency(25000000); + /* Atmel AT86RF215 Device Family datasheet: + * Errata #9: RF215M device has a wrong part number + * Description: + * The RF215M device part number is 0x34 instead of 0x36 (register RF_PN.PN). + */ +#if !defined(HAVE_AT86RF215M) *rf_part_num = rf_read_common_register(RF_PN); +#else + *rf_part_num = PART_AT86RF215M; + // AT86RF215M is Sub-GHz only transceiver. Change default settings. + rf_module = RF_09; + mac_mode = IEEE_802_15_4G_2012; +#endif rf_version_num = rf_read_common_register(RF_VN); tr_info("RF version number: %x", rf_version_num); return rf_device_register(mac); } +int RFBits::init_se2435_pa(Se2435Pins *_se2435_pa_pins) +{ + se2435_pa_pins = _se2435_pa_pins; + return 0; +} + #endif // MBED_CONF_NANOSTACK_CONFIGURATION && DEVICE_SPI && DEVICE_INTERRUPTIN && defined(MBED_CONF_RTOS_PRESENT) diff --git a/components/802.15.4_RF/atmel-rf-driver/source/NanostackRfPhyAtmel.cpp b/components/802.15.4_RF/atmel-rf-driver/source/NanostackRfPhyAtmel.cpp index e747af742d..ef3ce7f447 100644 --- a/components/802.15.4_RF/atmel-rf-driver/source/NanostackRfPhyAtmel.cpp +++ b/components/802.15.4_RF/atmel-rf-driver/source/NanostackRfPhyAtmel.cpp @@ -275,8 +275,15 @@ TestPins::TestPins(PinName test_pin_1, PinName test_pin_2, PinName test_pin_3, P { } +Se2435Pins::Se2435Pins(PinName csd_pin, PinName ant_sel_pin) + : CSD(csd_pin), + ANT_SEL(ant_sel_pin) +{ +} + static RFBits *rf; static TestPins *test_pins; +static Se2435Pins *se2435_pa_pins; static uint8_t rf_part_num = 0; /*TODO: RSSI Base value setting*/ static int8_t rf_rssi_base_val = -91; @@ -2168,14 +2175,21 @@ static uint8_t rf_scale_lqi(int8_t rssi) NanostackRfPhyAtmel::NanostackRfPhyAtmel(PinName spi_mosi, PinName spi_miso, PinName spi_sclk, PinName spi_cs, PinName spi_rst, PinName spi_slp, PinName spi_irq, PinName i2c_sda, PinName i2c_scl) - : _mac(i2c_sda, i2c_scl), _mac_addr(), _rf(NULL), _test_pins(NULL), _mac_set(false), - _spi_mosi(spi_mosi), _spi_miso(spi_miso), _spi_sclk(spi_sclk), - _spi_cs(spi_cs), _spi_rst(spi_rst), _spi_slp(spi_slp), _spi_irq(spi_irq) + : +#if !defined(DISABLE_AT24MAC) + _mac(i2c_sda, i2c_scl), +#endif + _mac_addr(), _rf(NULL), _test_pins(NULL), _se2435_pa_pins(NULL), _mac_set(false), + _spi_mosi(spi_mosi), _spi_miso(spi_miso), _spi_sclk(spi_sclk), + _spi_cs(spi_cs), _spi_rst(spi_rst), _spi_slp(spi_slp), _spi_irq(spi_irq) { _rf = new RFBits(_spi_mosi, _spi_miso, _spi_sclk, _spi_cs, _spi_rst, _spi_slp, _spi_irq); #ifdef TEST_GPIOS_ENABLED _test_pins = new TestPins(TEST_PIN_TX, TEST_PIN_RX, TEST_PIN_CSMA, TEST_PIN_SPARE_1, TEST_PIN_SPARE_2); #endif +#ifdef SE2435L_PA + _se2435_pa_pins = new Se2435Pins(SE2435L_CSD, SE2435L_ANT_SEL); +#endif } NanostackRfPhyAtmel::~NanostackRfPhyAtmel() @@ -2200,19 +2214,29 @@ int8_t NanostackRfPhyAtmel::rf_register() // Read the mac address if it hasn't been set by a user rf = _rf; test_pins = _test_pins; + se2435_pa_pins = _se2435_pa_pins; if (!_mac_set) { +// Unless AT24MAC is available, using randomly generated MAC address +#if !defined(DISABLE_AT24MAC) int ret = _mac.read_eui64((void *)_mac_addr); if (ret < 0) { rf = NULL; rf_if_unlock(); return -1; } +#else + randLIB_seed_random(); + randLIB_get_n_bytes_random(_mac_addr, 8); + _mac_addr[0] |= 2; //Set Local Bit + _mac_addr[0] &= ~1; //Clear multicast bit +#endif } /*Reset RF module*/ rf_if_reset_radio(); rf_part_num = rf_if_read_part_num(); int8_t radio_id = -1; if (rf_part_num != PART_AT86RF231 && rf_part_num != PART_AT86RF233 && rf_part_num != PART_AT86RF212) { + rf->init_se2435_pa(_se2435_pa_pins); // Register RF type 215. Jumps to AT86RF215 driver. radio_id = rf->init_215_driver(_rf, _test_pins, _mac_addr, &rf_part_num); } else { diff --git a/components/802.15.4_RF/atmel-rf-driver/source/rfbits.h b/components/802.15.4_RF/atmel-rf-driver/source/rfbits.h index 94143e6a8b..e9b17b2ea8 100644 --- a/components/802.15.4_RF/atmel-rf-driver/source/rfbits.h +++ b/components/802.15.4_RF/atmel-rf-driver/source/rfbits.h @@ -51,6 +51,7 @@ public: Timeout cca_timer; Timer tx_timer; int init_215_driver(RFBits *_rf, TestPins *_test_pins, const uint8_t mac[8], uint8_t *rf_part_num); + int init_se2435_pa(Se2435Pins *_se2435_pa_pins); #ifdef MBED_CONF_RTOS_PRESENT Thread irq_thread; Thread irq_thread_215; @@ -70,4 +71,11 @@ public: DigitalOut TEST5; }; +class Se2435Pins { +public: + Se2435Pins(PinName csd_pin, PinName ant_sel_pin); + DigitalOut CSD; + DigitalOut ANT_SEL; +}; + #endif /* RFBITS_H_ */ From 0d469c4bca9688a6da1f91c38dbb1de7fbbc9869 Mon Sep 17 00:00:00 2001 From: Arto Kinnunen Date: Mon, 8 Jun 2020 15:37:22 +0300 Subject: [PATCH 3/5] Update 802.15.4 MCR20 RF driver Sync with master version v1.0.9 --- components/802.15.4_RF/mcr20a-rf-driver/source/MCR20Drv.c | 1 + .../802.15.4_RF/mcr20a-rf-driver/source/NanostackRfPhyMcr20a.cpp | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/components/802.15.4_RF/mcr20a-rf-driver/source/MCR20Drv.c b/components/802.15.4_RF/mcr20a-rf-driver/source/MCR20Drv.c index 064fb284a0..3460732479 100644 --- a/components/802.15.4_RF/mcr20a-rf-driver/source/MCR20Drv.c +++ b/components/802.15.4_RF/mcr20a-rf-driver/source/MCR20Drv.c @@ -115,6 +115,7 @@ void MCR20Drv_Init xcvr_spi_configure_speed(gXcvrSpiInstance_c, 8000000); gXcvrDeassertCS_d(); + MCR20Drv_RST_B_Deassert(); RF_IRQ_Init(); RF_IRQ_Disable(); mPhyIrqDisableCnt = 1; diff --git a/components/802.15.4_RF/mcr20a-rf-driver/source/NanostackRfPhyMcr20a.cpp b/components/802.15.4_RF/mcr20a-rf-driver/source/NanostackRfPhyMcr20a.cpp index 755d2fb137..e0e8e46a72 100644 --- a/components/802.15.4_RF/mcr20a-rf-driver/source/NanostackRfPhyMcr20a.cpp +++ b/components/802.15.4_RF/mcr20a-rf-driver/source/NanostackRfPhyMcr20a.cpp @@ -62,7 +62,6 @@ extern "C" { #define gXcvrRunState_d gXcvrPwrAutodoze_c #define gXcvrLowPowerState_d gXcvrPwrHibernate_c -#define gXcvrLowPowerState_d gXcvrPwrAutodoze_c namespace { From ee2de0f99a393e9a868ea8c6bf655a7513bc09fb Mon Sep 17 00:00:00 2001 From: Arto Kinnunen Date: Mon, 8 Jun 2020 15:40:23 +0300 Subject: [PATCH 4/5] Squashed 'features/frameworks/nanostack-libservice/' changes from 9a61e73787..c6cae6992a c6cae6992a Merge pull request #90 from ARMmbed/sync_with_mbedos bc57095abb Netsocket/lwIP Stack: Remove support for ARM Compiler 5 git-subtree-dir: features/frameworks/nanostack-libservice git-subtree-split: c6cae6992a12f62f19cf7875f889304d5c1ded6d --- mbed-client-libservice/common_functions.h | 12 +++--------- mbed-client-libservice/ns_types.h | 16 +++++----------- 2 files changed, 8 insertions(+), 20 deletions(-) diff --git a/mbed-client-libservice/common_functions.h b/mbed-client-libservice/common_functions.h index c2f529b8b2..c08ae59300 100644 --- a/mbed-client-libservice/common_functions.h +++ b/mbed-client-libservice/common_functions.h @@ -509,9 +509,7 @@ COMMON_FUNCTIONS_FN uint_fast8_t common_count_leading_zeros(uint8_t value) COMMON_FUNCTIONS_FN uint_fast8_t common_count_leading_zeros_8(uint8_t value) { -#ifdef __CC_ARM - return value ? __clz((unsigned int) value << 24) : 8; -#elif defined __GNUC__ +#if defined __GNUC__ return value ? __builtin_clz((unsigned int) value << 24) : 8; #else uint_fast8_t cnt = 0; @@ -536,9 +534,7 @@ COMMON_FUNCTIONS_FN uint_fast8_t common_count_leading_zeros_8(uint8_t value) COMMON_FUNCTIONS_FN uint_fast8_t common_count_leading_zeros_16(uint16_t value) { -#ifdef __CC_ARM - return value ? __clz((unsigned int) value << 16) : 16; -#elif defined __GNUC__ +#if defined __GNUC__ return value ? __builtin_clz((unsigned int) value << 16) : 16; #else uint_fast8_t cnt = 0; @@ -567,9 +563,7 @@ COMMON_FUNCTIONS_FN uint_fast8_t common_count_leading_zeros_16(uint16_t value) COMMON_FUNCTIONS_FN uint_fast8_t common_count_leading_zeros_32(uint32_t value) { -#ifdef __CC_ARM - return __clz(value); -#elif defined __GNUC__ +#if defined __GNUC__ return value ? __builtin_clz(value) : 32; #else uint_fast8_t cnt = 0; diff --git a/mbed-client-libservice/ns_types.h b/mbed-client-libservice/ns_types.h index bbb28dd369..994db323e8 100644 --- a/mbed-client-libservice/ns_types.h +++ b/mbed-client-libservice/ns_types.h @@ -106,8 +106,6 @@ typedef int_fast32_t int_fast24_t; #define NS_NORETURN _Noreturn #elif defined __GNUC__ #define NS_NORETURN __attribute__((__noreturn__)) -#elif defined __CC_ARM -#define NS_NORETURN __declspec(noreturn) #elif defined __IAR_SYSTEMS_ICC__ #define NS_NORETURN __noreturn #else @@ -117,7 +115,7 @@ typedef int_fast32_t int_fast24_t; /* C11's "alignas" macro, emulated for integer expressions if necessary */ #ifndef __alignas_is_defined -#if defined __CC_ARM || defined __TASKING__ +#if defined __TASKING__ #define alignas(n) __align(n) #define __alignas_is_defined 1 #elif (defined __STDC_VERSION__ && __STDC_VERSION__ >= 201112L) || (defined __cplusplus && __cplusplus >= 201103L) @@ -149,7 +147,7 @@ typedef int_fast32_t int_fast24_t; * static int foo(void) MAYBE_UNUSED; * ~~~ */ -#if defined __CC_ARM || defined __GNUC__ +#if defined __GNUC__ #define MAYBE_UNUSED __attribute__((unused)) #else #define MAYBE_UNUSED @@ -219,7 +217,7 @@ typedef int_fast32_t int_fast24_t; #else /* C */ # if __STDC_VERSION__ >= 201112L # define NS_STATIC_ASSERT(test, str) _Static_assert(test, str); -# elif defined __GNUC__ && NS_GCC_VERSION >= 40600 && !defined __CC_ARM +# elif defined __GNUC__ && NS_GCC_VERSION >= 40600 # ifdef _Static_assert /* * Some versions of glibc cdefs.h (which comes in via above) @@ -255,7 +253,7 @@ typedef int_fast32_t int_fast24_t; /** \brief Pragma to suppress warnings about always true/false comparisons */ -#if defined __GNUC__ && NS_GCC_VERSION >= 40600 && !defined __CC_ARM +#if defined __GNUC__ && NS_GCC_VERSION >= 40600 #define NS_FUNNY_COMPARE_OK _Pragma("GCC diagnostic push") \ _Pragma("GCC diagnostic ignored \"-Wtype-limits\"") #define NS_FUNNY_COMPARE_RESTORE _Pragma("GCC diagnostic pop") @@ -272,11 +270,7 @@ typedef int_fast32_t int_fast24_t; * components should ensure this is not included by only using it in * a ifdef blocks providing dummy definitions. */ -#ifdef __CC_ARM -// statement is unreachable(111), controlling expression is constant(236), expression has no effect(174), -// function was declared but never referenced(177), variable was set but never used(550) -#define NS_DUMMY_DEFINITIONS_OK _Pragma("diag_suppress=111,236,174,177,550") -#elif defined __IAR_SYSTEMS_ICC__ +#if defined __IAR_SYSTEMS_ICC__ // controlling expression is constant #define NS_DUMMY_DEFINITIONS_OK _Pragma("diag_suppress=Pe236") #else From 93c77e83625be3989aecb9b3c2b7e930b34eb529 Mon Sep 17 00:00:00 2001 From: Arto Kinnunen Date: Mon, 8 Jun 2020 15:41:19 +0300 Subject: [PATCH 5/5] Squashed 'features/nanostack/sal-stack-nanostack/' changes from cc03296c27..b3fe5744d1 b3fe5744d1 Remove test files from the release b2bf24ca85 Merge branch 'release_internal' into release_external 0ed25a7485 Fix errors found from coverity scan (#2386) 7a138f7e51 Added IID for border router info structure 4021b0c1ef LLC secure data duplicate check update and EAPOL relay duplicate fix b190a97eeb Remove Thread-protocol from README (#2383) ae8ae32cfe EAPOL relay agent rx filter from joiner side 0d4eb7a46e Removed dead code part fc644f5e5b RPL new parent accept update and NUD operation f5920e2d0c ETX API update and RPL ETX threshold callback update. 1fdee20a40 Wi-sun keep all candidates alive by NUD. bd746da33d Key storage settings are no longer cleared on delete bd388fcb08 Changed EAPOL initial-Key retries from 2 to 4 on large NW a3d80a3235 WS bootstrap: Default CCA threshold to -60dBm (#2377) 72b26a72c2 Created extra large network setup for Wi-SUN 38dd4a6423 Corrected PTK and PMK lifetime handling 64f2a77239 Cleared EAPOL temporary trace print's. 02ec23fa27 Timed parent selection is now imim-imin*2 earlier there was just 5 seconds randomize. 3b2d906b75 Added check for network name and DODAG ID IID (EUI-64) (#2373) ee45f4be32 Updated initial key trickles 184425b038 Fixed parent target address set. 07ec2374a1 Updated Discovery and RPL setup large & medium size network a94d8f2e5d RPL version num update 9e2ac1d855 Double default eapol entry size for test purpose. 6b8beefb51 Clear all neighbors only on eapol next target check faa19e1fba Corrected next address set 8a917fb9a5 Continue trickle on initial EAPOL-key TX failure cfdb193c3e Merge pull request #2368 from ARMmbed/sync_with_mbedos f7a15fa68d (via MbedOS) ws: added support for brazilian regulatory domain c397edb121 Changed large network initial-key trickle parameters 758f5347b5 Added maximum frame counter storing interval b0ea148d41 Corrected key storage configuration setting be3c94e03b WS RPL paret soft filter update 8b1d537a02 Adjusted EAPOL limits and timers 9a2166869f Merge branch 'release_internal' into release_external 8e72b80826 MAC CCA thr: Check if channel out of range (#2363) 146a0a38c2 Corrected trace on authenticator d04a96dd48 Merge pull request #2361 from ARMmbed/sync_with_mbedos 2c2b915198 Added empty function for ns time callback 76ac0decce Remove NCS36510 target 0258ac3197 Remove KW24D target 788f01b93d Netsocket/lwIP Stack: Remove support for ARM Compiler 5 2fbc7a1c4f Corrected invalid memory read on access revoke 941b9b42dc Updates to stagger/latency (#2358) c2abaaafba Corrected defects 1811194bf2 Corrected warning trace, validations and ut stubs 69e2d1989e Added NS filesystem and interface to application c5b6993ddd refactored packet ingress a05605eca3 Unsecured packets will be acked by default automatically. 36dfb2924f MAC: Implemented automatic CCA threshold (#2353) 0396b9738c Revert EAPOL simplify failure handling and focus this problem later on. b2fe3d49db Ignoring authentication failure if security protocol already started 11de56dad8 Added info API for Wi-SUN border router 87a4f691fe Added EAPOL key storage to authenticator and unified GTK storage (#2345) ff1ca25ed7 EAPOL failure simplify and EAPOL relay agent add trace when eapol temp pool is empty 6667b31ae8 Update NA trace 34cdafe214 Temporary EAPOL neighbour entry Update and MAC MLME update d092f833a8 Iotthd 3995 (#2347) e2ea4e41f7 Disabled BR (TLS server) EC calculation queue 575985190d Changed the rate limiting function to calculate the values runtime 899e75510b Make it possible to update tr51 table to larger dynamically 8436669c10 Added configuration for DHCP lifetime value da732bc28e When network name or PAN ID is changed authenticator updates MAC keys git-subtree-dir: features/nanostack/sal-stack-nanostack git-subtree-split: b3fe5744d1ab20792223ff08f08ef97a1f89682b --- README.md | 22 +- docs/img/thread_certified.png | Bin 10158 -> 0 bytes mbed_lib.json | 6 - nanostack/fhss_config.h | 13 + nanostack/fhss_test_api.h | 11 + nanostack/mlme.h | 2 + nanostack/ns_file_system.h | 103 ++ nanostack/ns_time_api.h | 51 + nanostack/platform/arm_hal_phy.h | 1 + nanostack/ws_bbr_api.h | 109 ++ nanostack/ws_management_api.h | 20 +- .../Bootstraps/Generic/protocol_6lowpan.c | 35 +- .../Generic/protocol_6lowpan_bootstrap.c | 8 +- source/6LoWPAN/MAC/mac_helper.c | 34 +- source/6LoWPAN/MAC/mac_helper.h | 7 +- source/6LoWPAN/Thread/thread_bootstrap.c | 2 +- source/6LoWPAN/Thread/thread_nvm_store.c | 102 +- source/6LoWPAN/adaptation_interface.c | 2 +- source/6LoWPAN/ws/ws_bbr_api.c | 168 ++- source/6LoWPAN/ws/ws_bbr_api_internal.h | 3 + source/6LoWPAN/ws/ws_bootstrap.c | 280 +++-- source/6LoWPAN/ws/ws_bootstrap.h | 7 + source/6LoWPAN/ws/ws_cfg_settings.c | 259 +++-- source/6LoWPAN/ws/ws_cfg_settings.h | 32 +- source/6LoWPAN/ws/ws_common.c | 79 +- source/6LoWPAN/ws/ws_common.h | 3 +- source/6LoWPAN/ws/ws_common_defines.h | 33 +- source/6LoWPAN/ws/ws_config.h | 69 +- source/6LoWPAN/ws/ws_eapol_pdu.c | 8 + source/6LoWPAN/ws/ws_eapol_pdu.h | 1 + source/6LoWPAN/ws/ws_eapol_relay.c | 1 + source/6LoWPAN/ws/ws_empty_functions.c | 6 + source/6LoWPAN/ws/ws_llc.h | 11 + source/6LoWPAN/ws/ws_llc_data_service.c | 939 +++++++++++---- source/6LoWPAN/ws/ws_management_api.c | 8 +- source/6LoWPAN/ws/ws_neighbor_class.c | 27 + source/6LoWPAN/ws/ws_neighbor_class.h | 3 + source/6LoWPAN/ws/ws_pae_auth.c | 227 ++-- source/6LoWPAN/ws/ws_pae_auth.h | 39 +- source/6LoWPAN/ws/ws_pae_controller.c | 356 ++++-- source/6LoWPAN/ws/ws_pae_controller.h | 33 +- source/6LoWPAN/ws/ws_pae_key_storage.c | 1002 +++++++++++++++++ source/6LoWPAN/ws/ws_pae_key_storage.h | 164 +++ source/6LoWPAN/ws/ws_pae_lib.c | 86 +- source/6LoWPAN/ws/ws_pae_lib.h | 50 +- source/6LoWPAN/ws/ws_pae_nvm_data.c | 221 +++- source/6LoWPAN/ws/ws_pae_nvm_data.h | 119 +- source/6LoWPAN/ws/ws_pae_nvm_store.c | 134 +-- source/6LoWPAN/ws/ws_pae_nvm_store.h | 49 +- source/6LoWPAN/ws/ws_pae_supp.c | 340 +++--- source/6LoWPAN/ws/ws_pae_supp.h | 45 +- source/6LoWPAN/ws/ws_pae_time.c | 190 ++++ source/6LoWPAN/ws/ws_pae_time.h | 116 ++ source/6LoWPAN/ws/ws_pae_timers.c | 1 + source/6LoWPAN/ws/ws_pae_timers.h | 12 - source/6LoWPAN/ws/ws_test_api.c | 2 + source/Common_Protocols/icmpv6.c | 6 +- source/Core/include/ns_monitor.h | 5 + source/Core/ns_monitor.c | 30 + source/MAC/IEEE802_15_4/mac_cca_threshold.c | 142 +++ source/MAC/IEEE802_15_4/mac_cca_threshold.h | 65 ++ source/MAC/IEEE802_15_4/mac_data_buffer.h | 2 + source/MAC/IEEE802_15_4/mac_defines.h | 1 + source/MAC/IEEE802_15_4/mac_mcps_sap.c | 49 +- source/MAC/IEEE802_15_4/mac_mcps_sap.h | 3 + source/MAC/IEEE802_15_4/mac_mlme.c | 46 +- source/MAC/IEEE802_15_4/mac_pd_sap.c | 44 +- source/MAC/IEEE802_15_4/mac_security_mib.c | 15 - source/MAC/ethernet/ethernet_mac_api.c | 6 + source/MAC/serial/serial_mac_api.c | 7 + source/RPL/rpl_control.c | 30 +- source/RPL/rpl_control.h | 5 + source/RPL/rpl_downward.c | 46 + source/RPL/rpl_downward.h | 1 + source/Security/kmp/kmp_api.c | 5 +- source/Security/kmp/kmp_api.h | 5 +- .../eap_tls_sec_prot/auth_eap_tls_sec_prot.c | 10 +- .../eap_tls_sec_prot/supp_eap_tls_sec_prot.c | 6 +- .../fwh_sec_prot/auth_fwh_sec_prot.c | 29 +- .../fwh_sec_prot/supp_fwh_sec_prot.c | 10 +- .../gkh_sec_prot/auth_gkh_sec_prot.c | 13 +- .../protocols/key_sec_prot/key_sec_prot.c | 2 + source/Security/protocols/sec_prot.h | 3 +- source/Security/protocols/sec_prot_certs.h | 2 +- source/Security/protocols/sec_prot_cfg.h | 17 + source/Security/protocols/sec_prot_keys.c | 186 ++- source/Security/protocols/sec_prot_keys.h | 169 ++- source/Security/protocols/sec_prot_lib.c | 13 +- .../protocols/tls_sec_prot/tls_sec_prot.c | 34 +- source/Service_Libs/etx/etx.c | 106 +- source/Service_Libs/etx/etx.h | 15 +- source/Service_Libs/fhss/fhss_test_api.c | 15 + source/Service_Libs/fhss/fhss_ws.c | 21 +- source/Service_Libs/fhss/fhss_ws.h | 4 - .../mac_neighbor_table/mac_neighbor_table.c | 4 + .../port/compiler/fnet_comp_config.h | 4 - source/Service_Libs/utils/ns_conf.c | 2 +- source/Service_Libs/utils/ns_file.h | 110 ++ source/Service_Libs/utils/ns_file_system.c | 105 ++ source/nsconfig.h | 4 - sources.mk | 3 + 101 files changed, 5642 insertions(+), 1409 deletions(-) delete mode 100644 docs/img/thread_certified.png create mode 100644 nanostack/ns_time_api.h create mode 100644 source/6LoWPAN/ws/ws_pae_key_storage.c create mode 100644 source/6LoWPAN/ws/ws_pae_key_storage.h create mode 100644 source/6LoWPAN/ws/ws_pae_time.c create mode 100644 source/6LoWPAN/ws/ws_pae_time.h create mode 100644 source/MAC/IEEE802_15_4/mac_cca_threshold.c create mode 100644 source/MAC/IEEE802_15_4/mac_cca_threshold.h create mode 100644 source/Service_Libs/utils/ns_file.h diff --git a/README.md b/README.md index f614033fa7..ddddf390c7 100644 --- a/README.md +++ b/README.md @@ -3,37 +3,29 @@ ARM Mesh networking stack This repository contains the ARM mesh networking stack that provides support for the following mesh protocols: - * 6LoWPAN with Neighbor Discovery (ND) and Mesh Link Establishment (MLE) - * Thread - * Wi-SUN +* 6LoWPAN with Neighbor Discovery (ND) and Mesh Link Establishment (MLE) +* Wi-SUN - All networking stacks are using IEEE 802.15.4 based radios. +All networking stacks are using IEEE 802.15.4 based radios. The full documentation is hosted in [Mbed OS documentation](https://os.mbed.com/docs/mbed-os/latest/reference/mesh-tech.html). -On mbed OS, mesh networking stacks can be used through [Mbed Mesh API](https://os.mbed.com/docs/mbed-os/latest/apis/mesh-api.html) and [Network Socket API](https://os.mbed.com/docs/mbed-os/v5.11/apis/network-socket.html). +On mbed OS, mesh networking stacks can be used through [Mbed Mesh API](https://os.mbed.com/docs/mbed-os/latest/apis/mesh-api.html) and [Network Socket API](https://os.mbed.com/docs/mbed-os/latest/apis/network-socket.html). To see, how the mesh networking stack works, check the example application [mbed-os-example-mesh-minimal](https://github.com/ARMmbed/mbed-os-example-mesh-minimal). - -##6LoWPAN with ND and MLE + +## 6LoWPAN with ND and MLE This networking stack is using standard 6LoWPAN and uses: * Neighbor Discovery Protocol ([RFC4861](https://tools.ietf.org/html/rfc4861)) to locate other devices in the mesh network. * Mesh-Link-Establishment ([draft-kelsey-intarea-mesh-link-establishment-06](https://tools.ietf.org/html/draft-kelsey-intarea-mesh-link-establishment-06)) is used for establishing and configuring secure radio links. - -##Thread -Thread is standardized by [Thread group](https://www.threadgroup.org/). -![](docs/img/thread_certified.png) -mbed OS is now a Thread Certified Component. Using IPv6 with 6LoWPAN as the foundation, Thread technology provides a low-power, self-healing mesh network designed for the home. - -##Wi-SUN +## Wi-SUN Wi-SUN (Smart Utility Networks) specification is standardized by [Wi-SUN Alliance](https://www.wi-sun.org/). -Mbed OS release 5.12 contains the initial Mbed Wi-SUN FAN implementation. Functionality of the Mbed Wi-SUN network stack will be updated when the Wi-SUN protocol is specified further. ## License diff --git a/docs/img/thread_certified.png b/docs/img/thread_certified.png deleted file mode 100644 index c86ee53a7e8bd22e2725a12dbf05381e805dc4ea..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10158 zcmaiabzIZm_y0h0gv1Ex5=VDSjphwFVsws>mPQ1mHc|uxq+>`oNJvOYNl1r;0fNBj zkQ9C|Kab!4-~F-ebsy*4d+s^++}DX`99&O>49oxqfk0$hnyLmM5bnSKH$()$H*NZ> z=fKYcKQ&W7!)H!@fp$KQAZ3SVNJlm;54)$1299-T;99E6M$eaa^W?o& z23KQ}nEbUdUw9vs-OqaCIo3*qh|X_%t>ynfqD3RcJgdfCcTN4>7p}c|&QfuNsb}?c zQSdT^+3xT*ZdF4XkzRcS@45+uo9cKrU>UL-DY`$=!OsKfNO0 z;f>HmsA`1ufju(_lqo?4w$XdYKmoQRipskg(zAQGs0;ytl*lxw$l7e5zlLjC(7V$_ z{ty~?0?5Uvcd}4sZ%R)AUXP3VNMl#u8w&!3-y`>JID7zOf9YLV@PQfx>LK(|SvlQ! ztpxo*N9e;B@=6*YN=Y%5hCxw02$YQLDtdO^WyQ1bpj!&BPw)0h;cnd|77ql{#4{UU zJ^$;7>MK!N9JZk%q#~AkMFawI4eIF&EM|Z0U^$MscK0@e#!3I9&PupBdt^b^?=Ar5 zZO-j}X>K{l!A1oFvH45VW|)N-k9{eE7t4LaikSksO0j2Nl;%r-P1SEd`nR(&h{xL+ zB#jd%B;FJ+4n?*PXev{Lb-7a}Xdz0Jfi}a1-C~6iVEhj+|M z8snHLo&ax^U5wkmp$T)n<=~51=DhpP>UPzbsVOd6@#g3Kgzta%14p~NPrk^F(g9kD zfkr-{Bu*FzyFDo=0VUHnuhg6WJ@*e|krW6#U|Lz}DU!|rd$0ucP!tWs`M#sHq-eq`SvpxW(>J-u%>i+7{r#>>rv?vj0WjK;AE>-(}cy+QG?kqt_VbHhp3AH(|cgP#`QnxrTgWyYc5?NaPi z{Naz@sPa+%A@DptDEyKL4PB>-Rm)^Cql0uPp*29^s%V%X75Oo%&473&6+t6M`J;QN z2vj8Ay(~%)h?p18bKyZ5H~KR{sH+gq7X=M9 z@FoF{Qvp1dV>F_0;35T~Jda*XPH?MCTV7pVwVtOp^r{9EOAaKHszv_Y-K{>pQ@Fc1 z`Bt#(w;Kx29XrD=&>eJL?@yC$@(s_Qd7EIclIcH;oxU2K8C)quF$h^b`@Zm!7vtr~ zl~PZgp!p&AT=0yNW5_fTIT|||DuqB#jE|37cc1UfRV~@i-?b?z_bUvRY%j(XU3&%x zFaH-MRxrfe_r7Yt+;O>#2)=(!`Zi3XPZ_Ckt^_tS!*Yf`Ijl&IMV)dpSv`q_+f`nw zp8u$^XmzG~8WBgFATOzdja^x|zP{F)T|E+n#9Nay#^PnJ*{SjO%=#t-44aD=TCLkWXP!DxTbM`9h28&|CGmhvr8ZQ@ zcgh)NNBP|D;SSeDp6!`!*5}Qen~+Pxjwqf$qV{jx3^J1PCvONY_1z&QInY_CkW@=F5!0hDgxI5KLO71#k@mhUcDu*J>dnkUS~)bU*qs$T63YehbqkM28I!!WrtM37~Au+ zO-`pfOM?qt?2Fqp&qo*Ma}+M(^*_+<5a*B({hf*`{09F1@_G;3_*pVFpM{*qMYnuY zY%o{6jNcvaMCrWA6-RtrWm15geb5wt-1|POg8OQ6Kb7;IB@{A`%A?Q3328KfcIQrKUJEy=t-{2JRq>=c3!Q zvhsw|&7^oBSZ5)erE-1U{;6?-ti$a?E3%L^j(c|d^Qg=kFv0jcf8TOE_|`|Xr3ECi ziF=C!u0BV;huZ(%t!QRcs~W$?7D6cEa;&U`i*nP|?5!-k)WNCNb(`f!!OH!qb)+=w z>4@1?*GJk53)u>4i7X9%kXVxbnU5%aD(_SUGn_ns|8yc!As}Nrg^)eJP!%^J{G%pO z#d?+uw@oOcc-APs2*P63$lI|Z=x9yNr(?5gRd$HMw@oL+1Cl+ccJgI!xz%kw2KhuF zU9Negy(UQ4o@ytk4Fc{x^GlX_+FRbijN7fRd6LD*lH4U0HD^ET`H8NwF5-+h zx`@~&vc+?udY~t;(6hYBjQY>1(>>e9}FLaX$}*|%hTLlU!@mG>PTa?9Qx@3}K&G-=V08nCW! z^?rc^8ur%F;xegblEp_`JWzwgp43s*B*_HdEySqxWVMNKt*|y`5bkF)j))Ct=B96A zFYh2v>t&&%tBv_fQA0dQW~e748M4m}JtFIZj|k19oZR|$R%Rh$5PJgE)DoUw*^Gjy zK4s_1^v;X@eunM3Jk?ZIU!q1Mcmiuk>~bc5prJXnaSb?BLCk3Ob^Gh&gGA-p82(W| z|0rUldxChhR7#xuX54?N2^_JZ{YAr-g^hEng2*FRG`TjvLNal643S*-vW@hUdm= zolmJ&5UviPDzwy#hBWL1s=+5EZVl`ndOQ2_e+y9Vq%K2-rqp8`ihh`+-pa{M+WQ}C z2PrUz3iBvwk%TI&8(YIXM2xMWkZ`Hl#fYS>4xGzvMYXB65Nw3+*F<5wda{|7>1*}6 zA>bM_#0#Ys+QhX~X=I6PfRRf9qP zMIBm1TUnWIE3=tjRoI^@Id{2bs~}@(un!@y(SV)|_n80AcvB{gYFqX(0X($gX4eoB zUCL$9@q4MPkH5_q9Cw3c`uz)axu6%~1PP8d2{2(#!mQlSe)XRaDhxAE-X%$B+)t8~ zZ0|FXQg|;`BuOYfS(x$qJgwSA*Y^KO)W8%$_IuT(V zi3;Pki)v)mfMLPUBH7|+7~3`5O{QM*J!5o|!d3b4U6b>x6lG53wIb6un{izejuxwU zbPw0DcoB7^LL@yV*a(`0Ya1}3AFiTXWN;u%*JPU>FKK-)&IVD)x6w(Bz?3ZR{KiB)6 zA5|e7%A6gr%=2C4AEDZO4mZ}?`2mHjHO*0cb7^!soQOvOr}dr=j)=%)G;Mup&!EwA zW|E_BETGzxd2fY~3*iqeObP;EISi9DwImyy-6)&3;s4VBm#QtijsA5~Qid^VF{;ob z>VcGsw6jjn_K(Vo8B=A;&2J=_+D=@qN zws){dxJ@(mb9NzGmCUv&;jM5Xwy--G8K2D%Z%9;8;Y3Py7L@p>zYe0(0oQ=_w^oWzC)Lcx?^?EQ`7rABUJWQz6N z#g8m;Ku$amSiC-bETZTe&xRaX602hV&C9~?L_jzXJLLLGbrP5-#?DsGK6wPBPR z4u}GLXMfB9J|>I_M^es0V)>)D@z#I-v=i=286yNKL3`XF2}&t>E|Dc|sse^53xv8ZkVn5hrxw2E;mV)~h2L-g^I|dkgpHkwg4iFmMs*K#sAiJT*W9+h z!bL$rJYyZ$#t4HD1NjU(JhM-zW{IegyT@#dlK$1xTJ|u|OD&#u3z*T;jWxqp_ElTC8{nwIg z-iV>xyyV;^alc3?CV#ZlXtwJ+Cg9-3w~qXbBo!~9N+N!3KNNlEYRqD?3 zrM0$bTJ0Hs*X*3C!OHFTev0qeRiUQua@6tDZF2`S@1G?p-fGJH0>OW5ZEtU{0m1sw z3uooU)m5wAy*>YYheQgdcFiV%*D75qFy)Dt%iO&KZHu`%wQ85wAxUazT3TSIBjl;A?Y&R{&J zR>k+Y{ZYBVeYmNI6FoLz|Mzn1v-8GGc8HUc?xf)7b5v)$>FdPVlivkl3KzZ(u-x`w z&JUPpiQv@s%3zt2T{d4EPTEcM{<=l0r@j;+MmSGG*%cwAvzr{LX{y#OG~=P|El)+_ zaqFddo<;GmJn>MWn%JPi6^T*`pG-!SYjbJx|0n+J*|ToDXo(0URcDnTc(3P*zx;dX zdEUA2?lH6fnJgD=W%aX0ad9(72c9$%`(0m;zVwGv60+Rik=6ThetD3m`e&q?{HJ6q zx|BOmh^Bmd3-=a58V^Yd2!l~;81X*^a$SLcHx7wi&>N$}+*_-=X8{&GnJ)hM=Lg@z zup!OKhr6W-Jmu$yKR;b+%i|uEpZRGslNLVp-3xw?g^XT|u7t zl%(4S`q_-hmp4?wpXYZ67#P11tmk0`yA%%aNg9uek}Mp_Sn)h1X!k<;Z%`DLj*P=db=ZpdOLAm8Y8qMxufu?#sEm2ToO;;CeHHGW^J#ZtQmMojI=g zpS6`P1L{Rm4C&Gm6pr8I@=UC|6L2&_QMZ#ERGS*rIC@k=Rop>leWi=?%f?_PP8QXZ zSE?}Ak{sQqW0R92Umt69(RqxoZ?xs^yjn%~sSy!Y#RSHyYg<7HV{ztDaQ(fQx!=RH z2>M`eQV$Vhc$v?(VH4Nz0ZY-v6bI9^Hv+*|@?FCL);rYy${f|UDu>{)<)tV!XsHl* z<8Mq7_s&PZ2`-E{JTdIArK7{ zFTLk*`LMxAP_f1|ac0KQbN4}!o6X!Z#xk53GugAWWZnqtMX;I3ln~TIQ99|}<{dna z#7%Ke#VRU)nvMCZh!Z%H#PbWdvuvXIwGiXiry(=0OJ9oE@?+}dY^TC0CUL2K#r+U% zOLJO=^XNvNZ;*#e-@k|Df%#8DtC77;GlKSRW)ac?M5T|O@U8AEft)C%27|yjF!|Jq*@MGI)DP|m&%ScZX8KtVf9lR5LH~3?BcQ+9Y zBN>MD=K1!wd{HYHc@^sFQm)L9)BTbbeL_LLc=ida?dKfWmngxC++{G6VmIEa^hgep z+*E5GA&WxT*DHQKWef2r{OetK^n zWh(3vRSL_?7o#3}ce1~{Y0@nxK3BaL91{|wV1dNATg`s=aQkoTy=CbfA~b)`^kT6G zD0FrGjKm%@s|=OweZ|WD*;L>rFIm5OcCu*+4e2H-Ty08wiNLSv(tKXN_=+!0mew^2 zDo@{1;yd(#Km@ZY?#T_(g#C*wo~|B?Ma3F=t=`W0t2`>1v+dK)FdEwffvoCjz{(B^ z&XfTj+P*G0$rT35BC+VxL+=9|P%#%IzqGx|m-(lAKW@iF6B`Eu@KPd!l;jE-$i<737704)F0);c@-!4Ri`=9W3`JR~B_E6*x$2e{CAcx+CG#HA*iQ_B1Nrtch*WwecRZuUPEH^ z44J{8(C$?G-U9@B0|B!S@Hj{K?}^O|e)q4&?N3t0_2vea-}>SLee~l~W#LGCnkO3J zB?m+ny{}neGB{=s%ba~0p~8_U5X_S!5{?5@278y5viZS6Dl)_w{&Qp_;m?nM5eE|4 z>H_6H*powG09^ULe1i>=6~)6Y$U&Q}8o6-llvzfTx09F)rr)n4p8-ojq(h{d$Kj7EI( zI9Hi#Tb$mILq4vn)YU3~;Pnw5xpLp^?dQK<0x0UQ%gYw+B$kBi3=M@oW3lK@T^H$f;SzWlfj**4Kut?w~i@jrt^nqA|i=FWv1r6Itgk`jBKnY8r%v<1XdU`9E z*xX;7fY!D@-u?Q1Nk+$8l;Na{)+li_fli1ZF*vAtHm*ghe@iaL^GAC~%$NVHtggRI z8RnYIl@^c6%i&}1g(=dXM>X(XDD4vhkw1Gq_p8Kx8ONU?r&AiE_?<3v?*;}tTc4zg z;U5NEvT$;rTDSeadQ6w?>|d>*8kscVaix%`^8Gn?VhJtJ$I}P8_7y>zzgxPyzjwst zb*<0WSbQFLloi_C@oeW5o++~JAaXg9dHi@cceCnz z>)ZZ&l{dDNc&kIC*cbY&7F^Xu2hAV#r~()Qm)ix}tv9b4kL*(b1lywEG$vrJXTfhFkdNy5LY2F*rK}ibQ-&@GiDB2gOv+< z@A2p_0wzo$gZj5uTxrzPg76L|8>x8x6CdB<0@W4Ri(#p4KKQtLvatZiu_2aa;R(Lw z#}{X=L3M5syg9XJUEG0|shYyxM5TJ4=c-I>&L36m=oU@9IQ*epXUf9qbQLeQ!11%= zpv&!}0t2C$?Z|pzSZY{@he#D4&9gNf@y)CE->MEKH;Z{++6^yeUF$5kkIAxotYeX{ z|AbnX-n?XPS9D)zdD9GqggjW%;wc}HqT&o4iw>8-jDBhAWOF{6^Og^}@M^no>znG% z!nZo_Z1mOPEmMUp2SK?p+FZlDWd~DFcY;rutNv=~>FMzb1YYsSp+)GfdH9J31xiGC zg;cZeFG=z&IU8BoG#4)*izXyV;uUNbW-YHP(dzb-3nMPHbF;34#V@R@PNJ)sIawvCGDFD(5AXRF2W&@5ON5^TeYe6MV)Ak<#Q-mBMc= zlv3Yu6nKQBQLtpk(oo1fMBt#!Z#;C$tyF#H&NaEd61jhDb;VRuvDMPuQ6Q;9s0b{viDADYD1U(Z5rUl~pC$zp&@JD`aOT0T{N3PhesU5sgHWx==> zh#1j*-5$fiT>3D-Adx>m7t*>r_}^Up@?w>9B3i}+=Q`Qc#c2*US6ucRthg@Nr{k@HEG zx$tP|iH~Yno~E$eF^|DoJWQ~nGlG8!Ko zqzVWR1lj3tDN)Wohb$56{fu;mMXIHiTl+jQDlzT-03~2UX}t?!y#QBMFYVpG6r{6% zBm!^lkX$R&;&ProaJ>!W+4<$fZ$T{n+P@Zc?Buv5Vqzt>+@`v2odIL?#d!x903R@| zCEhf&vbxiMhLpH5QhXcB8Qn@(gNY2B^MTWnAUaeysY<^c)gn`~nYHh+F~1*d)Q-)< zRkvR-|Ita+46Qb$(NpPi0U6^vl=utYYRV7T%&8RQo9WRwPCARfei}vd@|g z#OGGM^gsHJxV>2m8t~Mo0K2Y`962~5^%~g0rxyGwK3Z`=PeDrOD|gG_8PfD2aeazv_wwf8dM;j1c^YdBEk5WEW2< zTu(t%jxMItc?%fGc6Tkby1HBDCJh2fjejrXtD1c-9jrJ169qc5O-q6}#Zb-$=C6{q zCSOIJG3}m?_~BzW`!t<%vv~_TJ{3TfA%W?%Z5x?~CICu+Wf#r;kU5+kJC+qn?=^mCwL*qNgzl^KY9bP@*VpVVC@3&o@-5}C+xau4 zOY*_RwWWPo{|?Vg$4xhLaGBGNJWl_8q{zZMjAdbI1Ij<{%S9!(nY*+5eWz-sbb5$+Lu#9 zx(21w*QCwIs%qY=TsU^jMAAr4!bQ&7$uE$!;piV z%1=c+Uf5GfAZkSfC`4tjB?G<1eV_Slnm;(}PX+Jb?wvj`Z>n7L|8+a*Ch@JX($d?E zOUH^pj-ctfE`D!vG23lw<0>2f$yd29bXx5m&;sMLVrf|!AN`i#t3R%o+&FLhN>zL7^4OG<27+#7nVZ}=DP#5P#X{g%q;jMA z)=LHkBF|;J)(Xa_n!nRUv0dG4bR-2Eih?i}R0FFt{S&VK-Q{`Yv{a&@T(DYgU|U&p z4_|CUQj$gYyUypTux_ly#;tc~s1?%kdBvHQ=2>S^J+#_OEG(2Y%Cx63c|M9&&WF)i zUs_(?svUO;_uHv8{@B-cP}7gx++6;^4^~%6nrzTKpJ&gKKKp}wRJIu0#t>qk7S8Pym$w4^eu^o2C7gkZ8Yo{N&K34ZTS$Yevfu$U<6M$S| zoMti!LAGChFsDd_Fd*Dwe(0vrlAmcqF@I20TJ((S z2bDs*0^TeRh>HyZhAdu)zQvhd<19cxKd%4O)%hE6e2xR6q6DiA4CaUks)u%9aX5fp zKF0PDZ5oa@!;Dhae1GUke(&Gr9sxX1aycBDjQGjXf@5eTKaf?bB1ljTgs);0U^Uu) zLJ{(8Z?$9^ky;w%c_w^;HCLd2907;+_noMz@}xSZ(I~U6J~u{9TBzOw6%VIZ+y{() zH`2KKSM3La5u5C<++mr%P~(O}`d3&W$Xg8P=bJ(yP-{ERFpmM*=68qCmMB->{ojq zT#k#Zj(`St^>y6@f(u<2GAwYQ(6)!--dckE&fb=0};{}TKquoe|$s$ zvy1;R_WM7I4@ze=Ewq$RVd9tp1EIEuubd|f3|02&^2+dV_wj-CBmb-F8|5Fp6}nqL zuZYLDcZ8$5t-EiIM-9Y>M+y}=0b2lg1k>mC5fbuT4pzyw(u#^Ux1?W}*hC6<;&O6w z6882y)&MFhq(F4k*Z@%Ai$%-6@=7jIuIp+bGoMV46M=+w$T2Ql(j%95vV0nkPyRZ$xQ03OVlJmpkf|i09bq-j6NfJqWzZ*^5Y`+ zKL7ypBjb$z{tGq!#~W1tW8)ow-M%rEUK0hLOnp+%Dc3agkdO1G%k}AH|jDhgZ~F9d5B+K<~P`8I;nN{Qdu2uLk z#!zE@88IAuYwz&^AOk3q)n+Lcwb3qfPC42*W=dDjk8oRo zNx3+vD8MgOKN+*r|DiPs2EZRj@PJP#*!ybG3mP&ik}zd)z#ba;bR50^-EpA$E{g1) zMg#*!UGXv%mpvtb*)dGjBZvq%nE;!(OY^Gsp$~)r5EeUA0Jyi_?51BA&~_>q4+UH7 zv*WyLKy-c+dda~80&T`2@4r4-*v`bo!B7-D|6oiMow(L)7E5>%2*?c-xt?ctzs%HT zVuMW6P|NX!4S<1K_}4{69d;Qc diff --git a/mbed_lib.json b/mbed_lib.json index 6640b5e3ef..1fddbd2cba 100644 --- a/mbed_lib.json +++ b/mbed_lib.json @@ -9,12 +9,6 @@ }, "macros": ["NS_USE_EXTERNAL_MBED_TLS"], "target_overrides": { - "KW24D": { - "nanostack.configuration": "lowpan_router" - }, - "NCS36510": { - "nanostack.configuration": "lowpan_router" - }, "TB_SENSE_12": { "nanostack.configuration": "lowpan_router" }, diff --git a/nanostack/fhss_config.h b/nanostack/fhss_config.h index 9a286128ac..5c55965733 100644 --- a/nanostack/fhss_config.h +++ b/nanostack/fhss_config.h @@ -88,6 +88,16 @@ typedef struct fhss_configuration { */ typedef int32_t fhss_vendor_defined_cf(const fhss_api_t *api, uint16_t slot, uint8_t eui64[8], uint16_t bsi, uint16_t number_of_channels); +/** + * \brief Struct fhss_config_parameters defines FHSS configuration parameters. + * + */ +typedef struct fhss_config_parameters { + /** Number of channel retries defines how many consecutive channels are used when retransmitting a frame after initial transmission channel. */ + uint8_t number_of_channel_retries; +} fhss_config_parameters_t; + + /** * \brief Struct fhss_ws_configuration defines configuration of WS FHSS. */ @@ -125,6 +135,9 @@ typedef struct fhss_ws_configuration { /** Vendor defined channel function. */ fhss_vendor_defined_cf *vendor_defined_cf; + /** Configuration parameters. */ + fhss_config_parameters_t config_parameters; + } fhss_ws_configuration_t; /** diff --git a/nanostack/fhss_test_api.h b/nanostack/fhss_test_api.h index 270c5a27a3..e6a93cc2c0 100644 --- a/nanostack/fhss_test_api.h +++ b/nanostack/fhss_test_api.h @@ -39,6 +39,17 @@ extern "C" { */ int8_t fhss_set_optimal_packet_length(const fhss_api_t *fhss_api, uint16_t packet_length); +/** + * \brief Set number of channel retries + * + * \param fhss_api FHSS instance. + * \param number_of_channel_retries Number of channel retries + * + * \return 0 Success + * \return -1 Failure + */ +int8_t fhss_set_number_of_channel_retries(const fhss_api_t *fhss_api, uint8_t number_of_channel_retries); + #ifdef __cplusplus } #endif diff --git a/nanostack/mlme.h b/nanostack/mlme.h index 233e349ba0..841f097cb6 100644 --- a/nanostack/mlme.h +++ b/nanostack/mlme.h @@ -264,6 +264,8 @@ typedef enum { macAutoRequestKeyIndex = 0x7b, /*= 0 success + * + */ +int ws_bbr_key_storage_memory_set(int8_t interface_id, uint8_t key_storages_number, const uint16_t *key_storage_size, void **key_storages); + +/** + * ws_bbr_key_storage_settings_set sets key storage settings + * + * This functions can be used to set the settings of EAPOL key storage. + * Allocation max number and allocation size sets the settings that are used when key storage + * memory is allocated dynamically from heap. These settings must be set before (first) interface + * up and shall not be set if key storage memory is set by ws_pae_key_storage_memory_set() call. + * + * \param interface_id Network interface ID. + * \param alloc_max_number maximum number of allocation made to dynamic memory. + * \param alloc_size size of each allocation. + * \param storing_interval interval in which the check to store to NVM is made. + * + * \return < 0 failure + * \return >= 0 success + * + */ +int ws_bbr_key_storage_settings_set(int8_t interface_id, uint8_t alloc_max_number, uint16_t alloc_size, uint16_t storing_interval); + #endif /* WS_BBR_API_H_ */ diff --git a/nanostack/ws_management_api.h b/nanostack/ws_management_api.h index 99092ba5f5..37e66999ab 100644 --- a/nanostack/ws_management_api.h +++ b/nanostack/ws_management_api.h @@ -75,10 +75,16 @@ extern "C" { #define CHANNEL_SPACING_100 0x03 // 100 khz #define CHANNEL_SPACING_250 0x04 // 250 khz -#define NETWORK_SIZE_CERTIFICATE 0x00 -#define NETWORK_SIZE_SMALL 0x01 -#define NETWORK_SIZE_MEDIUM 0x08 -#define NETWORK_SIZE_LARGE 0x10 +/* + * Network Size definitions are device amount in hundreds of devices. + * These definitions are meant to give some estimates of sizes. Any value can be given as parameter + */ + +#define NETWORK_SIZE_CERTIFICATE 0x00 // Network configuration used in Wi-SUN certification +#define NETWORK_SIZE_SMALL 0x01 // Small networks +#define NETWORK_SIZE_MEDIUM 0x08 // 100 - 800 device networks are medium sized +#define NETWORK_SIZE_LARGE 0x0F // 800 - 1500 device networks are large +#define NETWORK_SIZE_XLARGE 0x19 // 2500+ devices #define NETWORK_SIZE_AUTOMATIC 0xFF /** Temporary API change flag. this will be removed when new version of API is implemented on applications @@ -229,9 +235,9 @@ int ws_management_regulatory_domain_validate( * * timing parameters follows the specification example from Wi-SUN specification * - * Default value: medium - * small network size: hundreds of devices - * Large network size: thousands of devices + * Default value: medium 100 - 800 device + * small network size: less than 100 devices + * Large network size: 800 - 1500 devices * automatic: when discovering the network network size is learned * from advertisements and timings adjusted accordingly * diff --git a/source/6LoWPAN/Bootstraps/Generic/protocol_6lowpan.c b/source/6LoWPAN/Bootstraps/Generic/protocol_6lowpan.c index bacac2e6a5..b89117b7c7 100644 --- a/source/6LoWPAN/Bootstraps/Generic/protocol_6lowpan.c +++ b/source/6LoWPAN/Bootstraps/Generic/protocol_6lowpan.c @@ -83,6 +83,9 @@ #define TRACE_GROUP_LOWPAN "6lo" #define TRACE_GROUP "6lo" +/* Data rate for application used in Stagger calculation */ +#define STAGGER_DATARATE_FOR_APPL(n) ((n)*25/100) + #ifdef HAVE_RPL rpl_domain_t *protocol_6lowpan_rpl_domain; /* Having to sidestep old rpl_dodag_t type for the moment */ @@ -800,7 +803,7 @@ bool protocol_6lowpan_latency_estimate_get(int8_t interface_id, uint32_t *latenc latency_estimate = 100; } else if (thread_info(cur_interface)) { // thread network - latency_estimate = 1000; + latency_estimate = 2000; } else if (ws_info(cur_interface)) { latency_estimate = ws_common_latency_estimate_get(cur_interface); } else { @@ -820,14 +823,13 @@ bool protocol_6lowpan_stagger_estimate_get(int8_t interface_id, uint32_t data_am { size_t network_size; uint32_t datarate; + uint32_t stagger_value; protocol_interface_info_entry_t *cur_interface = protocol_stack_interface_info_get_by_id(interface_id); if (!cur_interface) { return false; } - *stagger_min = 1; - if (cur_interface->eth_mac_api) { // either PPP or Ethernet interface. network_size = 1; @@ -849,16 +851,25 @@ bool protocol_6lowpan_stagger_estimate_get(int8_t interface_id, uint32_t data_am // If no data amount given, use 1kB data_amount = 1; } - /**Example: - * Maximum stagger value to send 1kB on 50 devices network using datarate 50000 kb/: - * (1 * 1024 * 8 * 50) / (50000/4)) = ~ 32s - * - * devices: 50, datarate: 250kbps => stagger ~ 6s - * devices: 1000, datarate: 50kbps => stagger ~ 655s + + /* + * Do not occupy whole bandwidth, leave space for network formation etc... */ - /* Do not occupy whole bandwidth, halve the theoretical datarate and reserve room for other channel usage */ - datarate = datarate / 4; - *stagger_max = (uint16_t) * stagger_min + ((data_amount * 1024 * 8 * network_size) / datarate); + datarate = STAGGER_DATARATE_FOR_APPL(datarate); + stagger_value = 1 + ((data_amount * 1024 * 8 * network_size) / datarate); + /** + * Example: + * Maximum stagger value to send 1kB to 100 device network using data rate of 50kbs: + * 1 + (1 * 1024 * 8 * 100) / (50000*0.25) = 66s + */ + + *stagger_min = stagger_value / 5; // Minimum stagger value is 1/5 of the max + + if (stagger_value > 0xFFFF) { + *stagger_max = 0xFFFF; + } else { + *stagger_max = (uint16_t)stagger_value; + } // Randomize stagger value *stagger_rand = randLIB_get_random_in_range(*stagger_min, *stagger_max); diff --git a/source/6LoWPAN/Bootstraps/Generic/protocol_6lowpan_bootstrap.c b/source/6LoWPAN/Bootstraps/Generic/protocol_6lowpan_bootstrap.c index cbe3e12c67..0a21788cc2 100644 --- a/source/6LoWPAN/Bootstraps/Generic/protocol_6lowpan_bootstrap.c +++ b/source/6LoWPAN/Bootstraps/Generic/protocol_6lowpan_bootstrap.c @@ -588,7 +588,7 @@ static void mle_neigh_entry_update_by_mle_tlv_list(int8_t interface_id, mac_neig uint8_t link_idr; uint8_t iop_flags; if (mle_link_quality_tlv_parse(mac64, short_address, mle_tlv_info.dataPtr, mle_tlv_info.tlvLen, &iop_flags, &link_idr)) { - etx_remote_incoming_idr_update(interface_id, link_idr, entry_temp->index); + etx_remote_incoming_idr_update(interface_id, link_idr, entry_temp->index, entry_temp->mac64); if ((iop_flags & MLE_NEIGHBOR_PRIORITY_LINK) == MLE_NEIGHBOR_PRIORITY_LINK) { entry_temp->link_role = CHILD_NEIGHBOUR; @@ -965,9 +965,9 @@ int protocol_6lowpan_router_synch_to_new_router(protocol_interface_info_entry_t static uint8_t mle_calculate_idr(int8_t interface_id, mle_message_t *mle_msg, mac_neighbor_table_entry_t *entry_temp) { if (!entry_temp) { - return etx_lqi_dbm_update(-2, mle_msg->lqi, mle_msg->dbm, 0) >> 3; + return etx_lqi_dbm_update(-2, mle_msg->lqi, mle_msg->dbm, 0, NULL) >> 3; } - return etx_lqi_dbm_update(interface_id, mle_msg->lqi, mle_msg->dbm, entry_temp->index) >> 3; + return etx_lqi_dbm_update(interface_id, mle_msg->lqi, mle_msg->dbm, entry_temp->index, entry_temp->mac64) >> 3; } @@ -1609,7 +1609,7 @@ static void lowpan_neighbor_entry_remove_notify(mac_neighbor_table_entry_t *entr } mac_helper_devicetable_remove(cur_interface->mac_api, entry_ptr->index, entry_ptr->mac64); //Removes ETX neighbor - etx_neighbor_remove(cur_interface->id, entry_ptr->index); + etx_neighbor_remove(cur_interface->id, entry_ptr->index, entry_ptr->mac64); //Remove MLE frame counter info mle_service_frame_counter_entry_delete(cur_interface->id, entry_ptr->index); diff --git a/source/6LoWPAN/MAC/mac_helper.c b/source/6LoWPAN/MAC/mac_helper.c index e33c7fe6f9..9e9b5a266c 100644 --- a/source/6LoWPAN/MAC/mac_helper.c +++ b/source/6LoWPAN/MAC/mac_helper.c @@ -900,11 +900,13 @@ void mac_helper_devicetable_remove(mac_api_t *mac_api, uint8_t attribute_index, set_req.attr_index = attribute_index; set_req.value_pointer = (void *)&device_desc; set_req.value_size = sizeof(mlme_device_descriptor_t); - tr_debug("Unregister Device %u, mac64: %s", attribute_index, trace_array(mac64, 8)); + if (mac64) { + tr_debug("Unregister Device %u, mac64: %s", attribute_index, trace_array(mac64, 8)); + } mac_api->mlme_req(mac_api, MLME_SET, &set_req); } -void mac_helper_device_description_write(protocol_interface_info_entry_t *cur, mlme_device_descriptor_t *device_desc, uint8_t *mac64, uint16_t mac16, uint32_t frame_counter, bool exempt) +void mac_helper_device_description_write(protocol_interface_info_entry_t *cur, mlme_device_descriptor_t *device_desc, const uint8_t *mac64, uint16_t mac16, uint32_t frame_counter, bool exempt) { memcpy(device_desc->ExtAddress, mac64, 8); device_desc->ShortAddress = mac16; @@ -914,14 +916,19 @@ void mac_helper_device_description_write(protocol_interface_info_entry_t *cur, m } void mac_helper_devicetable_set(const mlme_device_descriptor_t *device_desc, protocol_interface_info_entry_t *cur, uint8_t attribute_index, uint8_t keyID, bool force_set) - { - if (!cur->mac_api) { + if (!force_set && cur->mac_parameters->SecurityEnabled && cur->mac_parameters->mac_default_key_index != keyID) { + tr_debug("Do not set counter by index %u != %u", cur->mac_parameters->mac_default_key_index, keyID); return; } - if (!force_set && cur->mac_parameters->SecurityEnabled && cur->mac_parameters->mac_default_key_index != keyID) { - tr_debug("Do not set counter by index %u != %u", cur->mac_parameters->mac_default_key_index, keyID); + tr_debug("Register Device %u, mac16 %x mac64: %s, %"PRIu32, attribute_index, device_desc->ShortAddress, trace_array(device_desc->ExtAddress, 8), device_desc->FrameCounter); + mac_helper_devicetable_direct_set(cur->mac_api, device_desc, attribute_index); +} + +void mac_helper_devicetable_direct_set(struct mac_api_s *mac_api, const mlme_device_descriptor_t *device_desc, uint8_t attribute_index) +{ + if (!mac_api) { return; } @@ -930,7 +937,20 @@ void mac_helper_devicetable_set(const mlme_device_descriptor_t *device_desc, pro set_req.attr_index = attribute_index; set_req.value_pointer = (void *)device_desc; set_req.value_size = sizeof(mlme_device_descriptor_t); - tr_debug("Register Device %u, mac16 %x mac64: %s, %"PRIu32, attribute_index, device_desc->ShortAddress, trace_array(device_desc->ExtAddress, 8), device_desc->FrameCounter); + mac_api->mlme_req(mac_api, MLME_SET, &set_req); +} + +void mac_helper_devicetable_ack_trig(const mlme_device_descriptor_t *device_desc, protocol_interface_info_entry_t *cur) +{ + if (!cur->mac_api) { + return; + } + + mlme_set_t set_req; + set_req.attr = macDevicePendingAckTrig; + set_req.attr_index = 0; + set_req.value_pointer = (void *)device_desc; + set_req.value_size = sizeof(mlme_device_descriptor_t); cur->mac_api->mlme_req(cur->mac_api, MLME_SET, &set_req); } diff --git a/source/6LoWPAN/MAC/mac_helper.h b/source/6LoWPAN/MAC/mac_helper.h index 3e6ac27897..6c68c6dc2f 100644 --- a/source/6LoWPAN/MAC/mac_helper.h +++ b/source/6LoWPAN/MAC/mac_helper.h @@ -121,9 +121,14 @@ int8_t mac_helper_key_link_frame_counter_set(int8_t interface_id, uint32_t seq_p void mac_helper_devicetable_remove(struct mac_api_s *mac_api, uint8_t attribute_index, uint8_t *mac64); -void mac_helper_device_description_write(struct protocol_interface_info_entry *cur, mlme_device_descriptor_t *device_desc, uint8_t *mac64, uint16_t mac16, uint32_t frame_counter, bool exempt); +void mac_helper_device_description_write(struct protocol_interface_info_entry *cur, mlme_device_descriptor_t *device_desc, const uint8_t *mac64, uint16_t mac16, uint32_t frame_counter, bool exempt); void mac_helper_devicetable_set(const mlme_device_descriptor_t *device_dec, struct protocol_interface_info_entry *cur, uint8_t attribute_index, uint8_t keyID, bool force_set); + +void mac_helper_devicetable_direct_set(struct mac_api_s *mac_api, const mlme_device_descriptor_t *device_desc, uint8_t attribute_index); + +void mac_helper_devicetable_ack_trig(const mlme_device_descriptor_t *device_desc, struct protocol_interface_info_entry *cur); + int8_t mac_helper_mac_mlme_max_retry_set(int8_t interface_id, uint8_t mac_retry_set); int8_t mac_helper_mac_device_description_pan_id_update(int8_t interface_id, uint16_t pan_id); diff --git a/source/6LoWPAN/Thread/thread_bootstrap.c b/source/6LoWPAN/Thread/thread_bootstrap.c index 07e231c864..1d0537d343 100644 --- a/source/6LoWPAN/Thread/thread_bootstrap.c +++ b/source/6LoWPAN/Thread/thread_bootstrap.c @@ -141,7 +141,7 @@ static void thread_neighbor_remove(mac_neighbor_table_entry_t *entry_ptr, void * thread_reset_neighbour_info(cur, entry_ptr); //Removes ETX neighbor - etx_neighbor_remove(cur->id, entry_ptr->index); + etx_neighbor_remove(cur->id, entry_ptr->index, entry_ptr->mac64); //Remove MLE frame counter info mle_service_frame_counter_entry_delete(cur->id, entry_ptr->index); } diff --git a/source/6LoWPAN/Thread/thread_nvm_store.c b/source/6LoWPAN/Thread/thread_nvm_store.c index 683d2f07cb..876639933c 100644 --- a/source/6LoWPAN/Thread/thread_nvm_store.c +++ b/source/6LoWPAN/Thread/thread_nvm_store.c @@ -34,7 +34,7 @@ #include "nsconfig.h" #include -#include +#include "Service_Libs/utils/ns_file.h" #include "Core/include/ns_address_internal.h" #include "ns_file_system.h" #include "thread_config.h" @@ -44,16 +44,13 @@ #define TRACE_GROUP "tnvm" const char *FAST_DATA_FILE = "f_d"; -#define FAST_DATA_VERSION 1 #define LINK_INFO_WRITE_DELAY 2 #define LINK_INFO_SHORT_ADDR_NOT_SET 0xffff #define LINK_INFO_WRITE_DONE 0xffff const char *LINK_INFO_FILE = "l_i"; -#define LINK_INFO_DATA_VERSION 1 const char *LEADER_INFO_FILE = "ld_i"; -#define LEADER_INFO_DATA_VERSION 1 typedef struct { uint8_t mac[8]; @@ -67,18 +64,15 @@ typedef struct { } thread_nvm_store_link_info_t; const char *THREAD_NVM_ACTIVE_CONF_FILE = "a_c"; -#define ACTIVE_CONF_DATA_VERSION 1 const char *DEVICE_CONF_FILE = "s_d"; -#define DEVICE_CONF_VERSION 1 const char *THREAD_NVM_PENDING_CONF_FILE = "p_c"; -#define PENDING_CONF_DATA_VERSION 1 static const char *thread_nvm_store_get_root_path(void); static int root_path_valid(void); -static int thread_nvm_store_read(const char *file_name, void *data, uint32_t data_size, uint32_t *version); -static int thread_nvm_store_write(const char *file_name, void *data, uint32_t data_size, uint32_t version); +static int thread_nvm_store_read(const char *file_name, void *data, uint32_t data_size); +static int thread_nvm_store_write(const char *file_name, void *data, uint32_t data_size); static void thread_nvm_store_create_path(char *fast_data_path, const char *file_name); static int thread_nvm_store_fast_data_save(thread_nvm_fast_data_t *fast_data_to_set); static int thread_nvm_store_all_counters_store(uint32_t mac_frame_counter, uint32_t mle_frame_counter, uint32_t seq_counter); @@ -131,13 +125,12 @@ int thread_nvm_store_mleid_rloc_map_write(thread_nvm_mleid_rloc_map *mleid_rloc_ } thread_nvm_store_create_path(lc_data_path, LEADER_INFO_FILE); tr_debug("writing to store rloc mapping info"); - return thread_nvm_store_write(lc_data_path, mleid_rloc_map, sizeof(thread_nvm_mleid_rloc_map), LEADER_INFO_DATA_VERSION); + return thread_nvm_store_write(lc_data_path, mleid_rloc_map, sizeof(thread_nvm_mleid_rloc_map)); } int thread_nvm_store_mleid_rloc_map_read(thread_nvm_mleid_rloc_map *mleid_rloc_map) { char lc_data_path[LEADER_INFO_STRING_LEN]; - uint32_t version; if (NULL == mleid_rloc_map) { return THREAD_NVM_FILE_PARAMETER_INVALID; } @@ -146,7 +139,7 @@ int thread_nvm_store_mleid_rloc_map_read(thread_nvm_mleid_rloc_map *mleid_rloc_m } thread_nvm_store_create_path(lc_data_path, LEADER_INFO_FILE); - int ret = thread_nvm_store_read(lc_data_path, mleid_rloc_map, sizeof(thread_nvm_mleid_rloc_map), &version); + int ret = thread_nvm_store_read(lc_data_path, mleid_rloc_map, sizeof(thread_nvm_mleid_rloc_map)); if (THREAD_NVM_FILE_SUCCESS != ret) { tr_info("Leader data map read failed"); @@ -154,12 +147,6 @@ int thread_nvm_store_mleid_rloc_map_read(thread_nvm_mleid_rloc_map *mleid_rloc_m return ret; } - if (LEADER_INFO_DATA_VERSION != version) { - tr_info("Leader data map version mismatch %"PRIu32, version); - thread_nvm_store_mleid_rloc_map_remove(); - return THREAD_NVM_FILE_VERSION_WRONG; - } - return ret; } @@ -191,7 +178,7 @@ int thread_nvm_store_device_configuration_write(uint8_t *mac_ptr, uint8_t *mleid memcpy(d_c.mle_id, mleid_ptr, sizeof(d_c.mle_id)); char device_conf_path[DEVICE_CONF_STRING_LEN]; thread_nvm_store_create_path(device_conf_path, DEVICE_CONF_FILE); - return thread_nvm_store_write(device_conf_path, &d_c, sizeof(thread_nvm_device_conf_t), DEVICE_CONF_VERSION); + return thread_nvm_store_write(device_conf_path, &d_c, sizeof(thread_nvm_device_conf_t)); } int thread_nvm_store_device_configuration_read(uint8_t *mac_ptr, uint8_t *mleid_ptr) @@ -202,18 +189,12 @@ int thread_nvm_store_device_configuration_read(uint8_t *mac_ptr, uint8_t *mleid_ } char device_conf_path[DEVICE_CONF_STRING_LEN]; thread_nvm_store_create_path(device_conf_path, DEVICE_CONF_FILE); - uint32_t version; thread_nvm_device_conf_t d_c; - ret = thread_nvm_store_read(device_conf_path, &d_c, sizeof(thread_nvm_device_conf_t), &version); + ret = thread_nvm_store_read(device_conf_path, &d_c, sizeof(thread_nvm_device_conf_t)); if (THREAD_NVM_FILE_SUCCESS == ret) { - if (THREAD_NVM_FILE_SUCCESS == ret && DEVICE_CONF_VERSION != version) { - tr_info("fast data version mismatch %"PRIu32, version); - ret = THREAD_NVM_FILE_VERSION_WRONG; - } else { - memcpy(mac_ptr, d_c.mac, sizeof(d_c.mac)); - memcpy(mleid_ptr, d_c.mle_id, sizeof(d_c.mle_id)); - } + memcpy(mac_ptr, d_c.mac, sizeof(d_c.mac)); + memcpy(mleid_ptr, d_c.mle_id, sizeof(d_c.mle_id)); } return ret; } @@ -228,13 +209,12 @@ int thread_nvm_store_pending_configuration_write(void *data, uint16_t size) return THREAD_NVM_FILE_ROOT_PATH_INVALID; } thread_nvm_store_create_path(pc_data_path, THREAD_NVM_PENDING_CONF_FILE); - return thread_nvm_store_write(pc_data_path, data, size, PENDING_CONF_DATA_VERSION); + return thread_nvm_store_write(pc_data_path, data, size); } int thread_nvm_store_pending_configuration_read(void *data, uint16_t size) { char pc_data_path[PENDING_CONF_STRING_LEN]; - uint32_t version; if (NULL == data) { return THREAD_NVM_FILE_PARAMETER_INVALID; } @@ -243,11 +223,7 @@ int thread_nvm_store_pending_configuration_read(void *data, uint16_t size) } thread_nvm_store_create_path(pc_data_path, THREAD_NVM_PENDING_CONF_FILE); - int ret = thread_nvm_store_read(pc_data_path, data, size, &version); - if (THREAD_NVM_FILE_SUCCESS == ret && PENDING_CONF_DATA_VERSION != version) { - tr_info("Pending configuration version mismatch %"PRIu32, version); - return THREAD_NVM_FILE_VERSION_WRONG; - } + int ret = thread_nvm_store_read(pc_data_path, data, size); return ret; } @@ -262,13 +238,12 @@ int thread_nvm_store_active_configuration_write(void *data, uint16_t data_size) } thread_nvm_store_create_path(ac_data_path, THREAD_NVM_ACTIVE_CONF_FILE); - return thread_nvm_store_write(ac_data_path, data, data_size, ACTIVE_CONF_DATA_VERSION); + return thread_nvm_store_write(ac_data_path, data, data_size); } int thread_nvm_store_active_configuration_read(void *data, uint16_t data_size) { char ac_data_path[ACTIVE_CONF_STRING_LEN]; - uint32_t version; if (NULL == data) { return THREAD_NVM_FILE_PARAMETER_INVALID; } @@ -277,11 +252,7 @@ int thread_nvm_store_active_configuration_read(void *data, uint16_t data_size) } thread_nvm_store_create_path(ac_data_path, THREAD_NVM_ACTIVE_CONF_FILE); - int ret = thread_nvm_store_read(ac_data_path, data, data_size, &version); - if (THREAD_NVM_FILE_SUCCESS == ret && ACTIVE_CONF_DATA_VERSION != version) { - tr_info("active configuration version mismatch %"PRIu32, version); - return THREAD_NVM_FILE_VERSION_WRONG; - } + int ret = thread_nvm_store_read(ac_data_path, data, data_size); return ret; } @@ -399,12 +370,7 @@ int thread_nvm_store_fast_data_read(thread_nvm_fast_data_t *fast_data) if (root_path_valid()) { char fast_data_path[FAST_DATA_STRING_LEN]; thread_nvm_store_create_path(fast_data_path, FAST_DATA_FILE); - uint32_t version; - ret = thread_nvm_store_read(fast_data_path, fast_data, sizeof(thread_nvm_fast_data_t), &version); - if (THREAD_NVM_FILE_SUCCESS == ret && FAST_DATA_VERSION != version) { - tr_info("fast data version mismatch %"PRIu32, version); - return THREAD_NVM_FILE_VERSION_WRONG; - } + ret = thread_nvm_store_read(fast_data_path, fast_data, sizeof(thread_nvm_fast_data_t)); } else { fast_data->mac_frame_counter = cached_fast_data.mac_frame_counter; fast_data->mle_frame_counter = cached_fast_data.mle_frame_counter; @@ -417,26 +383,19 @@ static int thread_nvm_store_fast_data_save(thread_nvm_fast_data_t *fast_data_to_ { char fast_data_path[FAST_DATA_STRING_LEN]; thread_nvm_store_create_path(fast_data_path, FAST_DATA_FILE); - return thread_nvm_store_write(fast_data_path, fast_data_to_set, sizeof(thread_nvm_fast_data_t), FAST_DATA_VERSION); + return thread_nvm_store_write(fast_data_path, fast_data_to_set, sizeof(thread_nvm_fast_data_t)); } -static int thread_nvm_store_write(const char *file_name, void *data, uint32_t data_size, uint32_t version) +static int thread_nvm_store_write(const char *file_name, void *data, uint32_t data_size) { - FILE *fp = fopen(file_name, "w"); + NS_FILE *fp = ns_fopen(file_name, "w"); if (fp == NULL) { tr_error("NVM open error: %s", file_name); return THREAD_NVM_FILE_CANNOT_OPEN; } - size_t n_bytes = fwrite(&version, 1, sizeof(uint32_t), fp); - if (n_bytes != sizeof(uint32_t)) { - tr_warning("NVM version write error"); - fclose(fp); - return THREAD_NVM_FILE_WRITE_ERROR; - } - - n_bytes = fwrite(data, 1, data_size, fp); - fclose(fp); + size_t n_bytes = ns_fwrite(fp, data, data_size); + ns_fclose(fp); if (n_bytes != data_size) { tr_error("NVM write error %s", file_name); return THREAD_NVM_FILE_WRITE_ERROR; @@ -446,23 +405,16 @@ static int thread_nvm_store_write(const char *file_name, void *data, uint32_t da } // returns 0 when ok -static int thread_nvm_store_read(const char *file_name, void *data, uint32_t data_size, uint32_t *version) +static int thread_nvm_store_read(const char *file_name, void *data, uint32_t data_size) { - FILE *fp = fopen(file_name, "r"); + NS_FILE *fp = ns_fopen(file_name, "r"); if (fp == NULL) { tr_warning("File not found: %s", file_name); return THREAD_NVM_FILE_CANNOT_OPEN; } - size_t n_bytes = fread(version, 1, sizeof(uint32_t), fp); - if (n_bytes != sizeof(uint32_t)) { - tr_warning("NVM version read error %s", file_name); - fclose(fp); - return THREAD_NVM_FILE_READ_ERROR; - } - - n_bytes = fread(data, 1, data_size, fp); - fclose(fp); + size_t n_bytes = ns_fread(fp, data, data_size); + ns_fclose(fp); if (n_bytes != data_size) { tr_error("NVM read error %s", file_name); return THREAD_NVM_FILE_READ_ERROR; @@ -488,8 +440,7 @@ int thread_nvm_store_link_info_read(void) strcpy(link_info_path, thread_nvm_store_get_root_path()); strcat(link_info_path, LINK_INFO_FILE); - uint32_t version = 0; - status = thread_nvm_store_read(link_info_path, &nvm_link_info_tmp, sizeof(nvm_link_info_t), &version); + status = thread_nvm_store_read(link_info_path, &nvm_link_info_tmp, sizeof(nvm_link_info_t)); if (status != THREAD_NVM_FILE_SUCCESS) { if (!memcmp(cached_link_info.nvm_link_info.mac, ADDR_UNSPECIFIED, 8) && @@ -499,9 +450,6 @@ int thread_nvm_store_link_info_read(void) return THREAD_NVM_FILE_READ_ERROR; } return status; - } else if (ACTIVE_CONF_DATA_VERSION != version) { - tr_info("link info version mismatch %"PRIu32, version); - return THREAD_NVM_FILE_VERSION_WRONG; } memcpy(cached_link_info.nvm_link_info.mac, nvm_link_info_tmp.mac, 8); cached_link_info.nvm_link_info.short_addr = nvm_link_info_tmp.short_addr; @@ -597,7 +545,7 @@ static void thread_nvm_store_link_info_delayed_write(uint32_t seconds) strcpy(link_info_path, thread_nvm_store_get_root_path()); strcat(link_info_path, LINK_INFO_FILE); tr_info("link info write parent mac: %s parent short addr: %"PRIu16, trace_array(cached_link_info.nvm_link_info.mac, 8), cached_link_info.nvm_link_info.short_addr); - thread_nvm_store_write(link_info_path, &cached_link_info.nvm_link_info, sizeof(nvm_link_info_t), LINK_INFO_DATA_VERSION); + thread_nvm_store_write(link_info_path, &cached_link_info.nvm_link_info, sizeof(nvm_link_info_t)); } void thread_nvm_store_seconds_timer(uint32_t seconds) diff --git a/source/6LoWPAN/adaptation_interface.c b/source/6LoWPAN/adaptation_interface.c index 99636719d9..87d6657735 100644 --- a/source/6LoWPAN/adaptation_interface.c +++ b/source/6LoWPAN/adaptation_interface.c @@ -155,7 +155,7 @@ static void lowpan_adaptation_etx_update_cb(protocol_interface_info_entry_t *cur // Gets table entry mac_neighbor_table_entry_t *neigh_table_ptr = mac_neighbor_table_address_discover(mac_neighbor_info(cur), buf->dst_sa.address + PAN_ID_LEN, buf->dst_sa.addr_type); if (neigh_table_ptr) { - etx_transm_attempts_update(cur->id, 1 + confirm->tx_retries, success, neigh_table_ptr->index); + etx_transm_attempts_update(cur->id, 1 + confirm->tx_retries, success, neigh_table_ptr->index, neigh_table_ptr->mac64); // Updates ETX statistics etx_storage_t *etx_entry = etx_storage_entry_get(cur->id, neigh_table_ptr->index); if (etx_entry) { diff --git a/source/6LoWPAN/ws/ws_bbr_api.c b/source/6LoWPAN/ws/ws_bbr_api.c index d180102e4a..f841be8144 100644 --- a/source/6LoWPAN/ws/ws_bbr_api.c +++ b/source/6LoWPAN/ws/ws_bbr_api.c @@ -20,6 +20,7 @@ #include "ns_types.h" #include "ns_trace.h" #include "net_interface.h" +#include "socket_api.h" #include "eventOS_event.h" #include "NWK_INTERFACE/Include/protocol.h" #include "6LoWPAN/Bootstraps/protocol_6lowpan.h" @@ -28,6 +29,7 @@ #include "6LoWPAN/ws/ws_common.h" #include "6LoWPAN/ws/ws_bootstrap.h" #include "6LoWPAN/ws/ws_cfg_settings.h" +#include "6LoWPAN/ws/ws_pae_key_storage.h" #include "RPL/rpl_control.h" #include "RPL/rpl_data.h" #include "Common_Protocols/icmpv6.h" @@ -52,7 +54,6 @@ static uint8_t current_instance_id = RPL_INSTANCE_ID; #define WS_ULA_LIFETIME 24*3600 #define WS_ROUTE_LIFETIME WS_ULA_LIFETIME -#define WS_DHCP_ADDRESS_LIFETIME 2*3600 #define BBR_CHECK_INTERVAL 60 #define BBR_BACKUP_ULA_DELAY 300 @@ -68,7 +69,7 @@ static uint8_t static_dodag_prefix[8] = {0xfd, 0x00, 0x72, 0x83, 0x7e}; static uint8_t static_dodag_id_prefix[8] = {0xfd, 0x00, 0x61, 0x72, 0x6d}; static uint8_t current_dodag_id[16] = {0}; static uint8_t current_local_prefix[8] = {0}; -static uint8_t current_global_prefix[8] = {0}; +static uint8_t current_global_prefix[16] = {0}; // DHCP requires 16 bytes prefix static uint32_t bbr_delay_timer = BBR_CHECK_INTERVAL; // initial delay. static uint32_t global_prefix_unavailable_timer = 0; // initial delay. @@ -94,7 +95,16 @@ static void ws_bbr_rpl_version_timer_start(protocol_interface_info_entry_t *cur, //stable version for RPL so slow timer update is ok cur->ws_info->rpl_version_timer = RPL_VERSION_LIFETIME; } else { - cur->ws_info->rpl_version_timer = RPL_VERSION_LIFETIME_RESTART; + if (cur->ws_info->cfg->gen.network_size <= NETWORK_SIZE_SMALL) { + // handles also NETWORK_SIZE_CERTIFICATE + cur->ws_info->rpl_version_timer = RPL_VERSION_LIFETIME_RESTART_SMALL; + } else if (cur->ws_info->cfg->gen.network_size <= NETWORK_SIZE_MEDIUM) { + cur->ws_info->rpl_version_timer = RPL_VERSION_LIFETIME_RESTART_MEDIUM; + } else if (cur->ws_info->cfg->gen.network_size <= NETWORK_SIZE_LARGE) { + cur->ws_info->rpl_version_timer = RPL_VERSION_LIFETIME_RESTART_LARGE; + } else { + cur->ws_info->rpl_version_timer = RPL_VERSION_LIFETIME_RESTART_EXTRA_LARGE; + } } } @@ -137,6 +147,15 @@ void ws_bbr_rpl_config(protocol_interface_info_entry_t *cur, uint8_t imin, uint8 } } +void ws_bbr_dhcp_address_lifetime_set(protocol_interface_info_entry_t *cur, uint32_t dhcp_address_lifetime) +{ + if (!cur) { + return; + } + // Change the setting if the border router is active + DHCPv6_server_service_set_address_validlifetime(cur->id, current_global_prefix, dhcp_address_lifetime); +} + static void ws_bbr_rpl_root_start(protocol_interface_info_entry_t *cur, uint8_t *dodag_id) { tr_info("RPL root start"); @@ -223,7 +242,10 @@ static if_address_entry_t *ws_bbr_slaac_generate(protocol_interface_info_entry_t static void ws_bbr_slaac_remove(protocol_interface_info_entry_t *cur, uint8_t *ula_prefix) { - icmpv6_slaac_prefix_update(cur, ula_prefix, 64, 0, 0); + if (cur) { + icmpv6_slaac_prefix_update(cur, ula_prefix, 64, 0, 0); + } + addr_policy_table_delete_entry(ula_prefix, 64); } @@ -328,7 +350,7 @@ static bool wisun_dhcp_address_add_cb(int8_t interfaceId, dhcp_address_cache_upd return true; } -static void ws_bbr_dhcp_server_start(protocol_interface_info_entry_t *cur, uint8_t *global_id) +static void ws_bbr_dhcp_server_start(protocol_interface_info_entry_t *cur, uint8_t *global_id, uint32_t dhcp_address_lifetime) { uint8_t ll[16]; memcpy(ll, ADDR_LINK_LOCAL_PREFIX, 8); @@ -344,7 +366,7 @@ static void ws_bbr_dhcp_server_start(protocol_interface_info_entry_t *cur, uint8 DHCPv6_server_service_callback_set(cur->id, global_id, NULL, wisun_dhcp_address_add_cb); //Enable SLAAC mode to border router DHCPv6_server_service_set_address_autonous_flag(cur->id, global_id, true, false); - DHCPv6_server_service_set_address_validlifetime(cur->id, global_id, WS_DHCP_ADDRESS_LIFETIME); + DHCPv6_server_service_set_address_validlifetime(cur->id, global_id, dhcp_address_lifetime); //SEt max value for not limiting address allocation DHCPv6_server_service_set_max_clients_accepts_count(cur->id, global_id, MAX_SUPPORTED_ADDRESS_LIST_SIZE); @@ -352,6 +374,9 @@ static void ws_bbr_dhcp_server_start(protocol_interface_info_entry_t *cur, uint8 } static void ws_bbr_dhcp_server_stop(protocol_interface_info_entry_t *cur, uint8_t *global_id) { + if (!cur) { + return; + } uint8_t temp_address[16]; memcpy(temp_address, global_id, 8); memset(temp_address + 8, 0, 8); @@ -359,7 +384,6 @@ static void ws_bbr_dhcp_server_stop(protocol_interface_info_entry_t *cur, uint8_ DHCPv6_server_service_delete(cur->id, global_id, false); //Delete Client dhcp_client_global_address_delete(cur->id, NULL, temp_address); - } static void ws_bbr_routing_stop(protocol_interface_info_entry_t *cur) @@ -506,7 +530,7 @@ static void ws_bbr_rpl_status_check(protocol_interface_info_entry_t *cur) return; } } - ws_bbr_dhcp_server_start(cur, global_prefix); + ws_bbr_dhcp_server_start(cur, global_prefix, cur->ws_info->cfg->bbr.dhcp_address_lifetime); rpl_control_update_dodag_prefix(protocol_6lowpan_rpl_root_dodag, global_prefix, 64, 0, 0, 0, false); // no check for failure should have @@ -623,6 +647,11 @@ uint16_t test_pan_size_override = 0xffff; uint16_t ws_bbr_pan_size(protocol_interface_info_entry_t *cur) { uint16_t result = 0; + + if (!cur || !cur->rpl_domain) { + return 0; + } + if (test_pan_size_override != 0xffff) { return test_pan_size_override; } @@ -701,7 +730,6 @@ void ws_bbr_stop(int8_t interface_id) protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(interface_id); ws_bbr_routing_stop(cur); - backbone_interface_id = -1; current_instance_id++; @@ -728,6 +756,86 @@ int ws_bbr_configure(int8_t interface_id, uint16_t options) return -1; #endif } +int ws_bbr_info_get(int8_t interface_id, bbr_information_t *info_ptr) +{ +#ifdef HAVE_WS_BORDER_ROUTER + + protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(interface_id); + rpl_dodag_info_t dodag_info; + + if (!info_ptr) { + return -1; + } + if (!cur || !protocol_6lowpan_rpl_root_dodag) { + tr_warn("bbr not started"); + return -1; + } + struct rpl_instance *instance = rpl_control_lookup_instance(protocol_6lowpan_rpl_domain, current_instance_id, current_dodag_id); + if (!instance) { + tr_warn("bbr instance not found"); + return -2; + } + // Zero the structure + memset(info_ptr, 0, sizeof(bbr_information_t)); + + rpl_control_read_dodag_info(instance, &dodag_info); + + memcpy(info_ptr->dodag_id, current_dodag_id, 16); + memcpy(info_ptr->prefix, current_global_prefix, 8); + + // Get the Wi-SUN interface generated address that is used in the RF interface. + const uint8_t *wisun_if_addr = addr_select_with_prefix(cur, current_global_prefix, 64, SOCKET_IPV6_PREFER_SRC_PUBLIC); + + if (wisun_if_addr) { + memcpy(info_ptr->IID, wisun_if_addr + 8, 8); + } + + info_ptr->devices_in_network = ws_bbr_pan_size(cur); + info_ptr->instance_id = current_instance_id; + info_ptr->version = dodag_info.version_num; + info_ptr->timestamp = protocol_core_monotonic_time; // TODO switch to second timer + // consider DTSN included It can also be added for getting device information + // Consider own device API to get DTSN, DHCP lifetime values + return 0; + +#else + (void) interface_id; + (void) info_ptr; + + return -1; +#endif +} + +int ws_bbr_routing_table_get(int8_t interface_id, bbr_route_info_t *table_ptr, uint16_t table_len) +{ +#ifdef HAVE_WS_BORDER_ROUTER + protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(interface_id); + int length; + if (!cur || !protocol_6lowpan_rpl_root_dodag) { + return -1; + } + + struct rpl_instance *instance = rpl_control_lookup_instance(protocol_6lowpan_rpl_domain, current_instance_id, current_dodag_id); + if (!instance) { + tr_warn("bbr instance not found"); + return -2; + } + memset(table_ptr, 0, table_len); + + /* RPL structure must match the external structure so we dont need to make conversion. + * + */ + length = rpl_control_route_table_get(instance, current_global_prefix, (rpl_route_info_t *)table_ptr, table_len); + + return length; +#else + (void) interface_id; + (void) table_ptr; + (void) table_len; + + return -1; +#endif +} int ws_bbr_node_keys_remove(int8_t interface_id, uint8_t *eui64) { @@ -782,8 +890,8 @@ int ws_bbr_rpl_parameters_set(int8_t interface_id, uint8_t dio_interval_min, uin #ifdef HAVE_WS_BORDER_ROUTER protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(interface_id); - ws_rpl_cfg_t cfg; - if (ws_cfg_rpl_get(&cfg, NULL) < 0) { + ws_bbr_cfg_t cfg; + if (ws_cfg_bbr_get(&cfg, NULL) < 0) { return -1; } @@ -797,7 +905,7 @@ int ws_bbr_rpl_parameters_set(int8_t interface_id, uint8_t dio_interval_min, uin cfg.dio_redundancy_constant = dio_redundancy_constant; } - if (ws_cfg_rpl_set(cur, NULL, &cfg, 0) < 0) { + if (ws_cfg_bbr_set(cur, NULL, &cfg, 0) < 0) { return -2; } @@ -818,8 +926,8 @@ int ws_bbr_rpl_parameters_get(int8_t interface_id, uint8_t *dio_interval_min, ui return -1; } - ws_rpl_cfg_t cfg; - if (ws_cfg_rpl_get(&cfg, NULL) < 0) { + ws_bbr_cfg_t cfg; + if (ws_cfg_bbr_get(&cfg, NULL) < 0) { return -2; } @@ -840,8 +948,8 @@ int ws_bbr_rpl_parameters_validate(int8_t interface_id, uint8_t dio_interval_min { (void) interface_id; #ifdef HAVE_WS_BORDER_ROUTER - ws_rpl_cfg_t cfg; - if (ws_cfg_rpl_get(&cfg, NULL) < 0) { + ws_bbr_cfg_t cfg; + if (ws_cfg_bbr_get(&cfg, NULL) < 0) { return -2; } @@ -855,7 +963,7 @@ int ws_bbr_rpl_parameters_validate(int8_t interface_id, uint8_t dio_interval_min cfg.dio_redundancy_constant = dio_redundancy_constant; } - if (ws_cfg_rpl_validate(NULL, &cfg) < 0) { + if (ws_cfg_bbr_validate(NULL, &cfg) < 0) { return -3; } @@ -935,3 +1043,29 @@ int ws_bbr_pan_configuration_validate(int8_t interface_id, uint16_t pan_id) return -1; #endif } + +int ws_bbr_key_storage_memory_set(int8_t interface_id, uint8_t key_storages_number, const uint16_t *key_storage_size, void **key_storages) +{ + (void) interface_id; +#ifdef HAVE_WS_BORDER_ROUTER + return ws_pae_key_storage_memory_set(key_storages_number, key_storage_size, key_storages); +#else + (void) key_storages_number; + (void) key_storage_size; + (void) key_storages; + return -1; +#endif +} + +int ws_bbr_key_storage_settings_set(int8_t interface_id, uint8_t alloc_max_number, uint16_t alloc_size, uint16_t storing_interval) +{ + (void) interface_id; +#ifdef HAVE_WS_BORDER_ROUTER + return ws_pae_key_storage_settings_set(alloc_max_number, alloc_size, storing_interval); +#else + (void) alloc_max_number; + (void) alloc_size; + (void) storing_interval; + return -1; +#endif +} diff --git a/source/6LoWPAN/ws/ws_bbr_api_internal.h b/source/6LoWPAN/ws/ws_bbr_api_internal.h index ee465916af..249790feac 100644 --- a/source/6LoWPAN/ws/ws_bbr_api_internal.h +++ b/source/6LoWPAN/ws/ws_bbr_api_internal.h @@ -31,6 +31,8 @@ uint16_t ws_bbr_pan_size(protocol_interface_info_entry_t *cur); void ws_bbr_rpl_config(protocol_interface_info_entry_t *cur, uint8_t imin, uint8_t doubling, uint8_t redundancy, uint16_t dag_max_rank_increase, uint16_t min_hop_rank_increase); +void ws_bbr_dhcp_address_lifetime_set(protocol_interface_info_entry_t *cur, uint32_t dhcp_address_lifetime); + bool ws_bbr_ready_to_start(protocol_interface_info_entry_t *cur); @@ -40,6 +42,7 @@ bool ws_bbr_ready_to_start(protocol_interface_info_entry_t *cur); #define ws_bbr_pan_version_increase(cur) #define ws_bbr_pan_size(cur) 0 #define ws_bbr_rpl_config( cur, imin, doubling, redundancy, dag_max_rank_increase, min_hop_rank_increase) +#define ws_bbr_dhcp_address_lifetime_set(cur, dhcp_address_lifetime) #define ws_bbr_ready_to_start(cur) true #endif //HAVE_WS_BORDER_ROUTER diff --git a/source/6LoWPAN/ws/ws_bootstrap.c b/source/6LoWPAN/ws/ws_bootstrap.c index 6a6079acfa..0d02498a5d 100644 --- a/source/6LoWPAN/ws/ws_bootstrap.c +++ b/source/6LoWPAN/ws/ws_bootstrap.c @@ -95,14 +95,16 @@ static void ws_bootstrap_nw_key_clear(protocol_interface_info_entry_t *cur, uint static void ws_bootstrap_nw_key_index_set(protocol_interface_info_entry_t *cur, uint8_t index); static void ws_bootstrap_nw_frame_counter_set(protocol_interface_info_entry_t *cur, uint32_t counter, uint8_t slot); static void ws_bootstrap_nw_frame_counter_read(protocol_interface_info_entry_t *cur, uint32_t *counter, uint8_t slot); +static void ws_bootstrap_nw_info_updated(protocol_interface_info_entry_t *interface_ptr, uint16_t pan_id, char *network_name); static void ws_bootstrap_authentication_completed(protocol_interface_info_entry_t *cur, auth_result_e result, uint8_t *target_eui_64); +static const uint8_t *ws_bootstrap_authentication_next_target(protocol_interface_info_entry_t *cur, const uint8_t *previous_eui_64, uint16_t *pan_id); static void ws_bootstrap_pan_version_increment(protocol_interface_info_entry_t *cur); static ws_nud_table_entry_t *ws_nud_entry_discover(protocol_interface_info_entry_t *cur, void *neighbor); static void ws_nud_entry_remove(protocol_interface_info_entry_t *cur, mac_neighbor_table_entry_t *entry_ptr); static bool ws_neighbor_entry_nud_notify(mac_neighbor_table_entry_t *entry_ptr, void *user_data); static void ws_address_registration_update(protocol_interface_info_entry_t *interface, const uint8_t addr[16]); - +static int8_t ws_bootstrap_neighbor_set(protocol_interface_info_entry_t *cur, parent_info_t *parent_ptr, bool clear_list); static void ws_bootstrap_candidate_table_reset(protocol_interface_info_entry_t *cur); static parent_info_t *ws_bootstrap_candidate_parent_get(struct protocol_interface_info_entry *cur, const uint8_t *addr, bool create); @@ -146,14 +148,68 @@ mac_neighbor_table_entry_t *ws_bootstrap_mac_neighbor_add(struct protocol_interf static void ws_bootstrap_neighbor_delete(struct protocol_interface_info_entry *interface, mac_neighbor_table_entry_t *entry_ptr) { mac_helper_devicetable_remove(interface->mac_api, entry_ptr->index, entry_ptr->mac64); - etx_neighbor_remove(interface->id, entry_ptr->index); + etx_neighbor_remove(interface->id, entry_ptr->index, entry_ptr->mac64); ws_neighbor_class_entry_remove(&interface->ws_info->neighbor_storage, entry_ptr->index); } +static void ws_bootstap_eapol_neigh_entry_allocate(struct protocol_interface_info_entry *interface) +{ + uint8_t mac_64[8]; + memset(mac_64, 0, sizeof(mac_64)); + + mac_neighbor_table_entry_t *mac_entry = ws_bootstrap_mac_neighbor_add(interface, mac_64); + + if (!mac_entry) { + return; + } + mac_entry->lifetime = 0xffffffff; + mac_entry->link_lifetime = 0xffffffff; + ws_neighbor_class_entry_t *ws_neigh = ws_neighbor_class_entry_get(&interface->ws_info->neighbor_storage, mac_entry->index); + if (!ws_neigh) { + return; + } + interface->ws_info->eapol_tx_index = mac_entry->index; +} + +void ws_bootstrap_eapol_rx_temporary_set(struct protocol_interface_info_entry *interface, const uint8_t *src64) +{ + mlme_device_descriptor_t device_desc; + + mac_helper_device_description_write(interface, &device_desc, src64, 0xffff, 0, false); + mac_helper_devicetable_ack_trig(&device_desc, interface); +} + +ws_neighbor_class_entry_t *ws_bootstrap_eapol_tx_temporary_set(struct protocol_interface_info_entry *interface, const uint8_t *src64) +{ + mlme_device_descriptor_t device_desc; + mac_neighbor_table_entry_t *mac_entry = mac_neighbor_table_attribute_discover(mac_neighbor_info(interface), interface->ws_info->eapol_tx_index); + if (!mac_entry) { + return NULL; + } + + memcpy(mac_entry->mac64, src64, 8); + mac_helper_device_description_write(interface, &device_desc, src64, 0xffff, 0, false); + mac_helper_devicetable_direct_set(interface->mac_api, &device_desc, interface->ws_info->eapol_tx_index); + return ws_neighbor_class_entry_get(&interface->ws_info->neighbor_storage, mac_entry->index); +} + +void ws_bootstrap_eapol_tx_temporary_clear(struct protocol_interface_info_entry *interface) +{ + mac_neighbor_table_entry_t *mac_entry = mac_neighbor_table_attribute_discover(mac_neighbor_info(interface), interface->ws_info->eapol_tx_index); + if (!mac_entry) { + return; + } + + memset(mac_entry->mac64, 0xff, 8); + mac_helper_devicetable_remove(interface->mac_api, interface->ws_info->eapol_tx_index, NULL); +} + static void ws_bootstrap_neighbor_list_clean(struct protocol_interface_info_entry *interface) { mac_neighbor_table_neighbor_list_clean(mac_neighbor_info(interface)); + //Allocate EAPOL TX temporary neigh entry + ws_bootstap_eapol_neigh_entry_allocate(interface); } static void ws_address_reregister_trig(struct protocol_interface_info_entry *interface) @@ -486,8 +542,8 @@ static uint8_t ws_generate_exluded_channel_list_from_active_channels(ws_excluded static void ws_fhss_configure_channel_masks(protocol_interface_info_entry_t *cur, fhss_ws_configuration_t *fhss_configuration) { - ws_generate_channel_list(fhss_configuration->channel_mask, cur->ws_info->hopping_schdule.number_of_channels, cur->ws_info->hopping_schdule.regulatory_domain); - ws_generate_channel_list(fhss_configuration->unicast_channel_mask, cur->ws_info->hopping_schdule.number_of_channels, cur->ws_info->hopping_schdule.regulatory_domain); + ws_generate_channel_list(fhss_configuration->channel_mask, cur->ws_info->hopping_schdule.number_of_channels, cur->ws_info->hopping_schdule.regulatory_domain, cur->ws_info->hopping_schdule.operating_class); + ws_generate_channel_list(fhss_configuration->unicast_channel_mask, cur->ws_info->hopping_schdule.number_of_channels, cur->ws_info->hopping_schdule.regulatory_domain, cur->ws_info->hopping_schdule.operating_class); // using bitwise AND operation for user set channel mask to remove channels not allowed in this device for (uint8_t n = 0; n < 8; n++) { fhss_configuration->unicast_channel_mask[n] &= cur->ws_info->cfg->fhss.fhss_channel_mask[n]; @@ -510,6 +566,7 @@ static int8_t ws_fhss_initialize(protocol_interface_info_entry_t *cur) fhss_configuration.ws_bc_channel_function = (fhss_ws_channel_functions)cur->ws_info->cfg->fhss.fhss_bc_channel_function; fhss_configuration.fhss_bc_dwell_interval = cur->ws_info->cfg->fhss.fhss_bc_dwell_interval; fhss_configuration.fhss_broadcast_interval = cur->ws_info->cfg->fhss.fhss_bc_interval; + fhss_configuration.config_parameters.number_of_channel_retries = WS_NUMBER_OF_CHANNEL_RETRIES; fhss_api = ns_fhss_ws_create(&fhss_configuration, cur->ws_info->fhss_timer_ptr); if (!fhss_api) { @@ -1069,7 +1126,7 @@ static parent_info_t *ws_bootstrap_candidate_parent_allocate(protocol_interface_ return entry; } -static void ws_bootstrap_candidate_parent_free(protocol_interface_info_entry_t *cur, uint8_t *addr) +static void ws_bootstrap_candidate_parent_free(protocol_interface_info_entry_t *cur, const uint8_t *addr) { ns_list_foreach_safe(parent_info_t, entry, &cur->ws_info->parent_list_reserved) { if (memcmp(entry->addr, addr, 8) == 0) { @@ -1286,14 +1343,15 @@ static void ws_bootstrap_pan_advertisement_solicit_analyse(struct protocol_inter * a PAN Advertisement Solicit with NETNAME-IE / Network Name matching that configured on the receiving node. */ trickle_consistent_heard(&cur->ws_info->trickle_pan_advertisement_solicit); - /* * Optimized PAN discovery to select faster the parent if we hear solicit from someone else */ - if (ws_bootstrap_state_discovery(cur) && - cur->bootsrap_state_machine_cnt > cur->ws_info->trickle_params_pan_discovery.Imin + 50) { - cur->bootsrap_state_machine_cnt = cur->ws_info->trickle_params_pan_discovery.Imin + randLIB_get_8bit() % 50; + if (ws_bootstrap_state_discovery(cur) && cur->ws_info->cfg->gen.network_size <= NETWORK_SIZE_MEDIUM && + cur->bootsrap_state_machine_cnt > cur->ws_info->trickle_params_pan_discovery.Imin * 2) { + + cur->bootsrap_state_machine_cnt = cur->ws_info->trickle_params_pan_discovery.Imin + randLIB_get_random_in_range(0, cur->ws_info->trickle_params_pan_discovery.Imin); + tr_info("Making parent selection in %u s", (cur->bootsrap_state_machine_cnt / 10)); } } @@ -1347,6 +1405,7 @@ static void ws_bootstrap_pan_config_analyse(struct protocol_interface_info_entry tr_error("No broadcast schedule"); return; } + llc_neighbour_req_t neighbor_info; bool neighbour_pointer_valid; @@ -1362,7 +1421,7 @@ static void ws_bootstrap_pan_config_analyse(struct protocol_interface_info_entry } if (neighbour_pointer_valid) { - etx_lqi_dbm_update(cur->id, data->mpduLinkQuality, data->signal_dbm, neighbor_info.neighbor->index); + etx_lqi_dbm_update(cur->id, data->mpduLinkQuality, data->signal_dbm, neighbor_info.neighbor->index, neighbor_info.neighbor->mac64); //Update Neighbor Broadcast and Unicast Parameters ws_neighbor_class_neighbor_unicast_time_info_update(neighbor_info.ws_neighbor, ws_utt, data->timestamp); ws_neighbor_class_neighbor_unicast_schedule_set(neighbor_info.ws_neighbor, ws_us); @@ -1447,7 +1506,7 @@ static void ws_bootstrap_pan_config_solicit_analyse(struct protocol_interface_in llc_neighbour_req_t neighbor_info; if (ws_bootstrap_neighbor_info_request(cur, data->SrcAddr, &neighbor_info, false)) { - etx_lqi_dbm_update(cur->id, data->mpduLinkQuality, data->signal_dbm, neighbor_info.neighbor->index); + etx_lqi_dbm_update(cur->id, data->mpduLinkQuality, data->signal_dbm, neighbor_info.neighbor->index, neighbor_info.neighbor->mac64); ws_neighbor_class_neighbor_unicast_time_info_update(neighbor_info.ws_neighbor, ws_utt, data->timestamp); ws_neighbor_class_neighbor_unicast_schedule_set(neighbor_info.ws_neighbor, ws_us); } @@ -1607,6 +1666,10 @@ static void ws_bootstrap_neighbor_table_clean(struct protocol_interface_info_ent ns_list_foreach_safe(mac_neighbor_table_entry_t, cur, &mac_neighbor_info(interface)->neighbour_list) { ws_neighbor_class_entry_t *ws_neighbor = ws_neighbor_class_entry_get(&interface->ws_info->neighbor_storage, cur->index); + if (cur->index == interface->ws_info->eapol_tx_index) { + continue; + } + if (cur->link_role == PRIORITY_PARENT_NEIGHBOUR) { //This is our primary parent we cannot delete continue; @@ -1758,7 +1821,7 @@ static bool ws_neighbor_entry_nud_notify(mac_neighbor_table_entry_t *entry_ptr, return false; } - if (!rpl_control_is_dodag_parent_candidate(cur, ll_address, WS_NEIGHBOUR_MAX_CANDIDATE_PROBE)) { + if (!rpl_control_is_dodag_parent_candidate(cur, ll_address, cur->ws_info->cfg->gen.rpl_parent_candidate_max)) { //NUD Not needed for if neighbour is not parent candidate return false; } @@ -1921,7 +1984,7 @@ int ws_bootstrap_init(int8_t interface_id, net_6lowpan_mode_e bootstrap_mode) ret_val = -4; goto init_fail; } - if (ws_pae_controller_cb_register(cur, &ws_bootstrap_authentication_completed, &ws_bootstrap_nw_key_set, &ws_bootstrap_nw_key_clear, &ws_bootstrap_nw_key_index_set, &ws_bootstrap_nw_frame_counter_set, &ws_bootstrap_nw_frame_counter_read, &ws_bootstrap_pan_version_increment) < 0) { + if (ws_pae_controller_cb_register(cur, &ws_bootstrap_authentication_completed, &ws_bootstrap_authentication_next_target, &ws_bootstrap_nw_key_set, &ws_bootstrap_nw_key_clear, &ws_bootstrap_nw_key_index_set, &ws_bootstrap_nw_frame_counter_set, &ws_bootstrap_nw_frame_counter_read, &ws_bootstrap_pan_version_increment, &ws_bootstrap_nw_info_updated) < 0) { ret_val = -4; goto init_fail; } @@ -1957,6 +2020,8 @@ int ws_bootstrap_init(int8_t interface_id, net_6lowpan_mode_e bootstrap_mode) set_req.value_size = sizeof(bool); cur->mac_api->mlme_req(cur->mac_api, MLME_SET, &set_req); + mac_helper_mac_mlme_max_retry_set(cur->id, WS_MAX_FRAME_RETRIES); + // Set the default parameters for MPL cur->mpl_proactive_forwarding = true; @@ -2032,6 +2097,12 @@ int ws_bootstrap_set_rf_config(protocol_interface_info_entry_t *cur, phy_rf_chan set_request.value_pointer = &multi_csma_params; set_request.value_size = sizeof(mlme_multi_csma_ca_param_t); cur->mac_api->mlme_req(cur->mac_api, MLME_SET, &set_request); + // Start automatic CCA threshold + uint8_t start_cca_thr[4] = {cur->ws_info->hopping_schdule.number_of_channels, CCA_DEFAULT_DBM, CCA_HIGH_LIMIT, CCA_LOW_LIMIT}; + set_request.attr = macCCAThresholdStart; + set_request.value_pointer = &start_cca_thr; + set_request.value_size = sizeof(start_cca_thr); + cur->mac_api->mlme_req(cur->mac_api, MLME_SET, &set_request); return 0; } @@ -2205,8 +2276,8 @@ static void ws_bootstrap_rpl_callback(rpl_event_t event, void *handle) ws_eapol_relay_start(cur, EAPOL_RELAY_SOCKET_PORT, dodag_info.dodag_id, EAPOL_RELAY_SOCKET_PORT); // Set network information to PAE ws_pae_controller_nw_info_set(cur, cur->ws_info->network_pan_id, cur->ws_info->cfg->gen.network_name); - // Network key is valid - ws_pae_controller_nw_key_valid(cur); + // Network key is valid, indicate border router IID to controller + ws_pae_controller_nw_key_valid(cur, &dodag_info.dodag_id[8]); // After successful DAO ACK connection to border router is verified cur->ws_info->pan_timeout_timer = cur->ws_info->cfg->timing.pan_timeout; @@ -2308,19 +2379,21 @@ static void ws_rpl_prefix_callback(prefix_entry_t *prefix, void *handle, uint8_t static bool ws_rpl_candidate_soft_filtering(protocol_interface_info_entry_t *cur, struct rpl_instance *instance) { - //If bootstrap active we not need any candidate filtering - if ((cur->lowpan_info & INTERFACE_NWK_BOOTSRAP_ACTIVE) && (ws_info(cur)->cfg->gen.network_size == NETWORK_SIZE_CERTIFICATE)) { - return true; - } - //Already many candidates - if (rpl_control_candidate_list_size(cur, instance) > cur->ws_info->cfg->rpl.rpl_parent_candidate_max) { + uint16_t candidate_list_size = rpl_control_candidate_list_size(cur, instance); + if (candidate_list_size >= cur->ws_info->cfg->gen.rpl_parent_candidate_max) { return false; } + uint16_t selected_parents = rpl_control_selected_parent_count(cur, instance); + //Already enough selected candidates - if (rpl_control_selected_parent_count(cur, instance) >= cur->ws_info->cfg->rpl.rpl_selected_parent_max) { - return false; + if (selected_parents >= cur->ws_info->cfg->gen.rpl_selected_parent_max) { + candidate_list_size -= selected_parents; + if (candidate_list_size >= 2) { + //We have more candidates than selected + return false; + } } return true; @@ -2354,6 +2427,19 @@ static bool ws_rpl_new_parent_callback(uint8_t *ll_parent_address, void *handle, ws_neighbor_temp_class_t *entry = ws_llc_get_multicast_temp_entry(cur, mac64); if (!ws_rpl_candidate_soft_filtering(cur, instance)) { + + //Acept only better than own rank here + if (candidate_rank >= rpl_control_current_rank(instance)) { + //Do not accept no more siblings + return false; + } + + uint16_t candidate_list_size = rpl_control_candidate_list_size(cur, instance); + if (candidate_list_size > cur->ws_info->cfg->gen.rpl_parent_candidate_max + 1) { + //Accept only 1 better 1 time + return false; + } + if (!neigh_buffer.neighbor) { //Do not accept any new in that Place return false; @@ -2386,42 +2472,6 @@ static bool ws_rpl_new_parent_callback(uint8_t *ll_parent_address, void *handle, if (neigh_buffer.neighbor) { return true; } -#if 0 - if (!rpl_control_find_worst_neighbor(cur, instance, replacing)) { - return false; - } - - // +2 Is for PAN ID space - memcpy(mac64 + 2, replacing + 8, 8); - mac64[2] ^= 2; - - if (ws_etx_read(cur, ADDR_802_15_4_LONG, mac64) == 0xffff) { - //Not proped yet because ETX is 0xffff - return false; - } - - uint16_t etx = 0; - if (neigh_buffer.neighbor) { - etx = etx_local_etx_read(cur->id, neigh_buffer.neighbor->index); - } - - // Accept now only better one's when max candidates selected and max candidate list size is reached - if (!rpl_possible_better_candidate(cur, instance, replacing, candidate_rank, etx)) { - return false; - } - //TODO if replacing has poor ETX, put it in blacklist as "poor ETX" to prevent reselection - //Mark That We can try remove replaced link - replace_ok = true; - -neigh_create: - - - if (neigh_buffer.neighbor) { - //Use Already discovered entry - create_ok = true; - goto neigh_create_ok; - } -#endif if (!entry) { //No Multicast Entry Available @@ -2435,7 +2485,7 @@ neigh_create: //Copy fhss temporary data *ws_neigh = entry->neigh_info_list; //ETX Create here - etx_lqi_dbm_update(cur->id, entry->mpduLinkQuality, entry->signal_dbm, neigh_buffer.neighbor->index); + etx_lqi_dbm_update(cur->id, entry->mpduLinkQuality, entry->signal_dbm, neigh_buffer.neighbor->index, neigh_buffer.neighbor->mac64); mac_neighbor_table_trusted_neighbor(mac_neighbor_info(cur), neigh_buffer.neighbor, true); } ws_llc_free_multicast_temp_entry(cur, entry); @@ -2562,7 +2612,7 @@ static void ws_bootstrap_start_discovery(protocol_interface_info_entry_t *cur) } // Discovery statemachine is checkked after we have sent the Solicit - uint16_t time_to_solicit = 0; + uint32_t time_to_solicit = 0; if (cur->ws_info->trickle_pan_advertisement_solicit.t > cur->ws_info->trickle_pan_advertisement_solicit.now) { time_to_solicit = cur->ws_info->trickle_pan_advertisement_solicit.t - cur->ws_info->trickle_pan_advertisement_solicit.now; } @@ -2571,7 +2621,13 @@ static void ws_bootstrap_start_discovery(protocol_interface_info_entry_t *cur) cur->ws_info->trickle_params_pan_discovery.Imin, cur->ws_info->trickle_params_pan_discovery.Imax, cur->ws_info->trickle_params_pan_discovery.TimerExpirations, cur->ws_info->trickle_params_pan_discovery.k, cur->ws_info->trickle_pan_advertisement_solicit.I, cur->ws_info->trickle_pan_advertisement_solicit.t, cur->ws_info->trickle_pan_advertisement_solicit.now, cur->ws_info->trickle_pan_advertisement_solicit.c); - cur->bootsrap_state_machine_cnt = time_to_solicit + cur->ws_info->trickle_params_pan_discovery.Imin + randLIB_get_8bit() % 50; + time_to_solicit += cur->ws_info->trickle_params_pan_discovery.Imin + randLIB_get_random_in_range(0, cur->ws_info->trickle_params_pan_discovery.Imin); + + if (time_to_solicit > 0xffff) { + time_to_solicit = 0xffff; + } + cur->bootsrap_state_machine_cnt = time_to_solicit; + tr_info("Making parent selection in %u s", (cur->bootsrap_state_machine_cnt / 10)); } @@ -2627,6 +2683,32 @@ static void ws_bootstrap_nw_frame_counter_read(protocol_interface_info_entry_t * mac_helper_key_link_frame_counter_read(cur->id, counter, slot); } +static void ws_bootstrap_nw_info_updated(protocol_interface_info_entry_t *cur, uint16_t pan_id, char *network_name) +{ + /* For border router, the PAE controller reads pan_id and network name from storage. + * If they are set, takes them into use here. + */ + if (cur->bootsrap_mode == ARM_NWK_BOOTSRAP_MODE_6LoWPAN_BORDER_ROUTER) { + // Get pad_id and network name + ws_gen_cfg_t gen_cfg; + if (ws_cfg_gen_get(&gen_cfg, NULL) < 0) { + return; + } + + // If pan_id has not been set, set it + if (gen_cfg.network_pan_id == 0xffff) { + gen_cfg.network_pan_id = pan_id; + } + // If network name has not been set, set it + if (strlen(gen_cfg.network_name) == 0) { + strncpy(gen_cfg.network_name, network_name, 32); + } + + // Stores the settings + ws_cfg_gen_set(cur, NULL, &gen_cfg, 0); + } +} + static void ws_bootstrap_authentication_completed(protocol_interface_info_entry_t *cur, auth_result_e result, uint8_t *target_eui_64) { (void) target_eui_64; @@ -2658,6 +2740,24 @@ static void ws_bootstrap_authentication_completed(protocol_interface_info_entry_ } } +static const uint8_t *ws_bootstrap_authentication_next_target(protocol_interface_info_entry_t *cur, const uint8_t *previous_eui_64, uint16_t *pan_id) +{ + ws_bootstrap_candidate_parent_free(cur, previous_eui_64); + + // Gets best target + parent_info_t *parent_info = ws_bootstrap_candidate_parent_get_best(cur); + if (parent_info) { + /* On failure still continues with the new parent, and on next call, + will try to set the neighbor again */ + ws_bootstrap_neighbor_set(cur, parent_info, true); + *pan_id = parent_info->pan_id; + return parent_info->addr; + } + + // If no targets found, retries the last one + return previous_eui_64; +} + // Start configuration learning static void ws_bootstrap_start_configuration_learn(protocol_interface_info_entry_t *cur) { @@ -2731,7 +2831,7 @@ static void ws_set_asynch_channel_list(protocol_interface_info_entry_t *cur, asy uint16_t channel_number = cur->ws_info->cfg->fhss.fhss_uc_fixed_channel; async_req->channel_list.channel_mask[0 + (channel_number / 32)] = (1 << (channel_number % 32)); } else { - ws_generate_channel_list(async_req->channel_list.channel_mask, cur->ws_info->hopping_schdule.number_of_channels, cur->ws_info->hopping_schdule.regulatory_domain); + ws_generate_channel_list(async_req->channel_list.channel_mask, cur->ws_info->hopping_schdule.number_of_channels, cur->ws_info->hopping_schdule.regulatory_domain, cur->ws_info->hopping_schdule.operating_class); } async_req->channel_list.channel_page = CHANNEL_PAGE_10; @@ -3047,6 +3147,36 @@ static void ws_bootstrap_event_handler(arm_event_s *event) } } +static int8_t ws_bootstrap_neighbor_set(protocol_interface_info_entry_t *cur, parent_info_t *parent_ptr, bool clear_list) +{ + uint16_t pan_id = cur->ws_info->network_pan_id; + + // Add EAPOL neighbor + cur->ws_info->network_pan_id = parent_ptr->pan_id; + cur->ws_info->pan_information = parent_ptr->pan_information; + cur->ws_info->pan_information.pan_version = 0; // This is learned from actual configuration + + // If PAN ID changes, clear learned neighbors and activate FHSS + if (pan_id != cur->ws_info->network_pan_id) { + if (clear_list) { + ws_bootstrap_neighbor_list_clean(cur); + } + ws_bootstrap_fhss_activate(cur); + } + + llc_neighbour_req_t neighbor_info; + if (!ws_bootstrap_neighbor_info_request(cur, parent_ptr->addr, &neighbor_info, true)) { + //Remove Neighbour and set Link setup back + ns_list_remove(&cur->ws_info->parent_list_reserved, parent_ptr); + ns_list_add_to_end(&cur->ws_info->parent_list_free, parent_ptr); + return -1; + } + + ws_neighbor_class_neighbor_unicast_time_info_update(neighbor_info.ws_neighbor, &parent_ptr->ws_utt, parent_ptr->timestamp); + ws_neighbor_class_neighbor_unicast_schedule_set(neighbor_info.ws_neighbor, &parent_ptr->ws_us); + return 0; +} + /* * State machine * @@ -3067,29 +3197,21 @@ select_best_candidate: // randomize new channel and start MAC ws_bootstrap_fhss_activate(cur); // Next check will be after one trickle - cur->bootsrap_state_machine_cnt += cur->ws_info->trickle_params_pan_discovery.Imin + randLIB_get_8bit() % 50; + uint32_t random_start = cur->ws_info->trickle_params_pan_discovery.Imin + randLIB_get_random_in_range(0, cur->ws_info->trickle_params_pan_discovery.Imin); + if (random_start > 0xffff) { + random_start = 0xffff; + } + cur->bootsrap_state_machine_cnt = random_start; + tr_info("Making parent selection in %u s", (cur->bootsrap_state_machine_cnt / 10)); return; } tr_info("selected parent:%s panid %u", trace_array(selected_parent_ptr->addr, 8), selected_parent_ptr->pan_id); - // Add EAPOL neighbour - cur->ws_info->network_pan_id = selected_parent_ptr->pan_id; - cur->ws_info->pan_information = selected_parent_ptr->pan_information; - cur->ws_info->pan_information.pan_version = 0; // This is learned from actual configuration - - ws_bootstrap_fhss_activate(cur); - llc_neighbour_req_t neighbor_info; - if (!ws_bootstrap_neighbor_info_request(cur, selected_parent_ptr->addr, &neighbor_info, true)) { - //Remove Neighbour and set Link setup back - ns_list_remove(&cur->ws_info->parent_list_reserved, selected_parent_ptr); - ns_list_add_to_end(&cur->ws_info->parent_list_free, selected_parent_ptr); + if (ws_bootstrap_neighbor_set(cur, selected_parent_ptr, false) < 0) { goto select_best_candidate; } - ws_neighbor_class_neighbor_unicast_time_info_update(neighbor_info.ws_neighbor, &selected_parent_ptr->ws_utt, selected_parent_ptr->timestamp); - ws_neighbor_class_neighbor_unicast_schedule_set(neighbor_info.ws_neighbor, &selected_parent_ptr->ws_us); - ws_pae_controller_set_target(cur, selected_parent_ptr->pan_id, selected_parent_ptr->addr); // temporary!!! store since auth ws_bootstrap_event_authentication_start(cur); return; @@ -3305,6 +3427,8 @@ void ws_bootstrap_seconds_timer(protocol_interface_info_entry_t *cur, uint32_t s } } + ws_llc_timer_seconds(cur, seconds); + } void ws_primary_parent_update(protocol_interface_info_entry_t *interface, mac_neighbor_table_entry_t *neighbor) diff --git a/source/6LoWPAN/ws/ws_bootstrap.h b/source/6LoWPAN/ws/ws_bootstrap.h index 949eac4a99..c9cdcd46b4 100644 --- a/source/6LoWPAN/ws/ws_bootstrap.h +++ b/source/6LoWPAN/ws/ws_bootstrap.h @@ -31,6 +31,7 @@ typedef enum { struct llc_neighbour_req; struct ws_us_ie; +struct ws_neighbor_class_entry; int ws_bootstrap_init(int8_t interface_id, net_6lowpan_mode_e bootstrap_mode); @@ -81,6 +82,12 @@ void ws_bootstrap_eapol_parent_synch(struct protocol_interface_info_entry *cur, bool ws_bootstrap_validate_channel_plan(struct ws_us_ie *ws_us, struct protocol_interface_info_entry *cur); +void ws_bootstrap_eapol_rx_temporary_set(struct protocol_interface_info_entry *interface, const uint8_t *src64); + +struct ws_neighbor_class_entry *ws_bootstrap_eapol_tx_temporary_set(struct protocol_interface_info_entry *interface, const uint8_t *src64); + +void ws_bootstrap_eapol_tx_temporary_clear(struct protocol_interface_info_entry *interface); + #else #define ws_bootstrap_init(interface_id, bootstrap_mode) (-1) diff --git a/source/6LoWPAN/ws/ws_cfg_settings.c b/source/6LoWPAN/ws/ws_cfg_settings.c index bebe6627d7..8eacf4802d 100644 --- a/source/6LoWPAN/ws/ws_cfg_settings.c +++ b/source/6LoWPAN/ws/ws_cfg_settings.c @@ -49,8 +49,9 @@ #define TRICKLE_IMIN_15_SECS 15 typedef struct ws_cfg_nw_size_s { + ws_gen_cfg_t gen; /**< General configuration */ ws_timing_cfg_t timing; /**< Timing configuration */ - ws_rpl_cfg_t rpl; /**< RPL configuration */ + ws_bbr_cfg_t bbr; /**< RPL configuration */ ws_sec_prot_cfg_t sec_prot; /**< Security protocols configuration */ } ws_cfg_nw_size_t; @@ -69,7 +70,7 @@ typedef union { ws_gen_cfg_t gen; ws_phy_cfg_t phy; ws_timing_cfg_t timing; - ws_rpl_cfg_t rpl; + ws_bbr_cfg_t bbr; ws_fhss_cfg_t fhss; ws_mpl_cfg_t mpl; ws_sec_timer_cfg_t sec_timer; @@ -81,12 +82,13 @@ static int8_t ws_cfg_to_get(ws_cfgs_t **cfg, ws_cfgs_t *new_cfg, ws_cfg_validate static void ws_cfg_network_size_config_set_small(ws_cfg_nw_size_t *cfg); static void ws_cfg_network_size_config_set_medium(ws_cfg_nw_size_t *cfg); static void ws_cfg_network_size_config_set_large(ws_cfg_nw_size_t *cfg); +static void ws_cfg_network_size_config_set_xlarge(ws_cfg_nw_size_t *cfg); static void ws_cfg_network_size_config_set_certificate(ws_cfg_nw_size_t *cfg); static int8_t ws_cfg_network_size_default_set(ws_gen_cfg_t *cfg); static int8_t ws_cfg_gen_default_set(ws_gen_cfg_t *cfg); static int8_t ws_cfg_phy_default_set(ws_phy_cfg_t *cfg); static int8_t ws_cfg_timing_default_set(ws_timing_cfg_t *cfg); -static int8_t ws_cfg_rpl_default_set(ws_rpl_cfg_t *cfg); +static int8_t ws_cfg_bbr_default_set(ws_bbr_cfg_t *cfg); static int8_t ws_cfg_mpl_default_set(ws_mpl_cfg_t *cfg); static int8_t ws_cfg_fhss_default_set(ws_fhss_cfg_t *cfg); static int8_t ws_cfg_sec_timer_default_set(ws_sec_timer_cfg_t *cfg); @@ -107,7 +109,7 @@ static const ws_cfg_cb_t cfg_cb[] = { CFG_CB(ws_cfg_gen_default_set, ws_cfg_gen_validate, ws_cfg_gen_set, offsetof(ws_cfg_t, gen)), CFG_CB(ws_cfg_phy_default_set, ws_cfg_phy_validate, ws_cfg_phy_set, offsetof(ws_cfg_t, phy)), CFG_CB(ws_cfg_timing_default_set, ws_cfg_timing_validate, ws_cfg_timing_set, offsetof(ws_cfg_t, timing)), - CFG_CB(ws_cfg_rpl_default_set, ws_cfg_rpl_validate, ws_cfg_rpl_set, offsetof(ws_cfg_t, rpl)), + CFG_CB(ws_cfg_bbr_default_set, ws_cfg_bbr_validate, ws_cfg_bbr_set, offsetof(ws_cfg_t, bbr)), CFG_CB(ws_cfg_mpl_default_set, ws_cfg_mpl_validate, ws_cfg_mpl_set, offsetof(ws_cfg_t, mpl)), CFG_CB(ws_cfg_fhss_default_set, ws_cfg_fhss_validate, ws_cfg_fhss_set, offsetof(ws_cfg_t, fhss)), CFG_CB(ws_cfg_sec_timer_default_set, ws_cfg_sec_timer_validate, ws_cfg_sec_timer_set, offsetof(ws_cfg_t, sec_timer)), @@ -128,10 +130,12 @@ static int8_t ws_cfg_to_get(ws_cfgs_t **cfg, ws_cfgs_t *new_cfg, ws_cfg_validate if (*cfg == NULL) { // In case external configuration is not same as internal if (nw_size_external_cfg && (!flags || !(*flags & CFG_FLAGS_FORCE_INTERNAL_CONFIG))) { - if (ws_cfg_ptr == (ws_cfgs_t *) &ws_cfg.timing) { + if (ws_cfg_ptr == (ws_cfgs_t *) &ws_cfg.gen) { + *cfg = (ws_cfgs_t *) &nw_size_external_cfg->gen; + } else if (ws_cfg_ptr == (ws_cfgs_t *) &ws_cfg.timing) { *cfg = (ws_cfgs_t *) &nw_size_external_cfg->timing; - } else if (ws_cfg_ptr == (ws_cfgs_t *) &ws_cfg.rpl) { - *cfg = (ws_cfgs_t *) &nw_size_external_cfg->rpl; + } else if (ws_cfg_ptr == (ws_cfgs_t *) &ws_cfg.bbr) { + *cfg = (ws_cfgs_t *) &nw_size_external_cfg->bbr; } else if (ws_cfg_ptr == (ws_cfgs_t *) &ws_cfg.sec_prot) { *cfg = (ws_cfgs_t *) &nw_size_external_cfg->sec_prot; } else { @@ -245,8 +249,9 @@ int8_t ws_cfg_network_size_set(protocol_interface_info_entry_t *cur, ws_gen_cfg_ cfg->network_size = new_cfg->network_size; ws_cfg_nw_size_t nw_size_cfg; + ws_cfg_gen_get(&nw_size_cfg.gen, NULL); ws_cfg_timing_get(&nw_size_cfg.timing, NULL); - ws_cfg_rpl_get(&nw_size_cfg.rpl, NULL); + ws_cfg_bbr_get(&nw_size_cfg.bbr, NULL); ws_cfg_sec_prot_get(&nw_size_cfg.sec_prot, NULL); ws_cfg_network_size_config_set_size set_function = NULL; @@ -257,8 +262,10 @@ int8_t ws_cfg_network_size_set(protocol_interface_info_entry_t *cur, ws_gen_cfg_ set_function = ws_cfg_network_size_config_set_small; } else if (cfg->network_size <= NETWORK_SIZE_MEDIUM) { set_function = ws_cfg_network_size_config_set_medium; - } else { + } else if (cfg->network_size <= NETWORK_SIZE_LARGE) { set_function = ws_cfg_network_size_config_set_large; + } else { + set_function = ws_cfg_network_size_config_set_xlarge; } // Overrides the values on the new configuration @@ -279,13 +286,17 @@ int8_t ws_cfg_network_size_set(protocol_interface_info_entry_t *cur, ws_gen_cfg_ } /* Sets values if changed or network size has been previously automatic (to make sure the settings are in sync */ + if (ws_cfg_gen_validate(&ws_cfg.gen, &nw_size_cfg.gen) == CFG_SETTINGS_CHANGED || + old_network_size == NETWORK_SIZE_AUTOMATIC) { + ws_cfg_gen_set(cur, &ws_cfg.gen, &nw_size_cfg.gen, &set_flags); + } if (ws_cfg_timing_validate(&ws_cfg.timing, &nw_size_cfg.timing) == CFG_SETTINGS_CHANGED || old_network_size == NETWORK_SIZE_AUTOMATIC) { ws_cfg_timing_set(cur, &ws_cfg.timing, &nw_size_cfg.timing, &set_flags); } - if (ws_cfg_rpl_validate(&ws_cfg.rpl, &nw_size_cfg.rpl) == CFG_SETTINGS_CHANGED || + if (ws_cfg_bbr_validate(&ws_cfg.bbr, &nw_size_cfg.bbr) == CFG_SETTINGS_CHANGED || old_network_size == NETWORK_SIZE_AUTOMATIC) { - ws_cfg_rpl_set(cur, &ws_cfg.rpl, &nw_size_cfg.rpl, &set_flags); + ws_cfg_bbr_set(cur, &ws_cfg.bbr, &nw_size_cfg.bbr, &set_flags); } if (ws_cfg_sec_prot_validate(&ws_cfg.sec_prot, &nw_size_cfg.sec_prot) == CFG_SETTINGS_CHANGED || old_network_size == NETWORK_SIZE_AUTOMATIC) { @@ -305,8 +316,10 @@ int8_t ws_cfg_network_size_configure(protocol_interface_info_entry_t *cur, uint1 // Read settings that are affected by network size ws_cfg_nw_size_t new_nw_size_cfg; uint8_t flags = CFG_FLAGS_OVERRIDE_DISABLE_VAL_SET | CFG_FLAGS_FORCE_INTERNAL_CONFIG; + + ws_cfg_gen_get(&new_nw_size_cfg.gen, &flags); ws_cfg_timing_get(&new_nw_size_cfg.timing, &flags); - ws_cfg_rpl_get(&new_nw_size_cfg.rpl, &flags); + ws_cfg_bbr_get(&new_nw_size_cfg.bbr, &flags); ws_cfg_sec_prot_get(&new_nw_size_cfg.sec_prot, &flags); if (!nw_size_external_cfg) { @@ -321,16 +334,20 @@ int8_t ws_cfg_network_size_configure(protocol_interface_info_entry_t *cur, uint1 if (network_size < 100) { // Automatic ws_cfg_network_size_config_set_small(&new_nw_size_cfg); - } else if (network_size < 300) { + } else if (network_size < 800) { // Medium ws_cfg_network_size_config_set_medium(&new_nw_size_cfg); + } else if (network_size < 1500) { + // Medium + ws_cfg_network_size_config_set_large(&new_nw_size_cfg); } else { // Large - ws_cfg_network_size_config_set_large(&new_nw_size_cfg); + ws_cfg_network_size_config_set_xlarge(&new_nw_size_cfg); } + ws_cfg_gen_set(cur, NULL, &new_nw_size_cfg.gen, &flags); ws_cfg_timing_set(cur, NULL, &new_nw_size_cfg.timing, &flags); - ws_cfg_rpl_set(cur, NULL, &new_nw_size_cfg.rpl, &flags); + ws_cfg_bbr_set(cur, NULL, &new_nw_size_cfg.bbr, &flags); ws_cfg_sec_prot_set(cur, NULL, &new_nw_size_cfg.sec_prot, &flags); return CFG_SETTINGS_OK; @@ -338,112 +355,190 @@ int8_t ws_cfg_network_size_configure(protocol_interface_info_entry_t *cur, uint1 static void ws_cfg_network_size_config_set_small(ws_cfg_nw_size_t *cfg) { + // Configure the Wi-SUN parent configuration + cfg->gen.rpl_parent_candidate_max = WS_RPL_PARENT_CANDIDATE_MAX; + cfg->gen.rpl_selected_parent_max = WS_RPL_SELECTED_PARENT_MAX; + // Configure the Wi-SUN timing trickle parameter cfg->timing.disc_trickle_imin = TRICKLE_IMIN_15_SECS; // 15 seconds cfg->timing.disc_trickle_imax = TRICKLE_IMIN_15_SECS << 2; // 60 seconds cfg->timing.disc_trickle_k = 1; cfg->timing.pan_timeout = PAN_VERSION_SMALL_NETWORK_TIMEOUT; cfg->timing.temp_link_min_timeout = WS_NEIGHBOR_TEMPORARY_LINK_MIN_TIMEOUT_SMALL; + cfg->timing.temp_eapol_min_timeout = WS_EAPOL_TEMPORARY_ENTRY_SMALL_TIMEOUT; // RPL configuration - cfg->rpl.dio_interval_min = WS_RPL_DIO_IMIN_SMALL; // 15; 32s seconds - cfg->rpl.dio_interval_doublings = WS_RPL_DIO_DOUBLING_SMALL; // 2; 128 - cfg->rpl.dio_redundancy_constant = WS_RPL_DIO_REDUNDANCY_SMALL; // Disabled - cfg->rpl.dag_max_rank_increase = WS_RPL_MAX_HOP_RANK_INCREASE; - cfg->rpl.min_hop_rank_increase = WS_RPL_MIN_HOP_RANK_INCREASE; - cfg->rpl.rpl_parent_candidate_max = WS_RPL_PARENT_CANDIDATE_MAX; - cfg->rpl.rpl_selected_parent_max = WS_RPL_SELECTED_PARENT_MAX; + cfg->bbr.dio_interval_min = WS_RPL_DIO_IMIN_SMALL; // 15; 32s seconds + cfg->bbr.dio_interval_doublings = WS_RPL_DIO_DOUBLING_SMALL; // 2; 128 + cfg->bbr.dio_redundancy_constant = WS_RPL_DIO_REDUNDANCY_SMALL; // Disabled + cfg->bbr.dag_max_rank_increase = WS_RPL_MAX_HOP_RANK_INCREASE; + cfg->bbr.min_hop_rank_increase = WS_RPL_MIN_HOP_RANK_INCREASE; + cfg->bbr.dhcp_address_lifetime = WS_DHCP_ADDRESS_LIFETIME_SMALL; // EAPOL configuration cfg->sec_prot.sec_prot_trickle_imin = SEC_PROT_SMALL_IMIN; cfg->sec_prot.sec_prot_trickle_imax = SEC_PROT_SMALL_IMAX; cfg->sec_prot.sec_prot_trickle_timer_exp = SEC_PROT_TIMER_EXPIRATIONS; cfg->sec_prot.sec_prot_retry_timeout = SEC_PROT_RETRY_TIMEOUT_SMALL; - cfg->sec_prot.sec_max_ongoing_authentication = MAX_SIMULTANEOUS_EAP_TLS_NEGOTIATIONS_SMALL; + + cfg->sec_prot.sec_max_ongoing_authentication = MAX_SIMULTANEOUS_SECURITY_NEGOTIATIONS_SMALL; + + cfg->sec_prot.initial_key_retry_delay = DEFAULT_INITIAL_KEY_RETRY_TIMER; + cfg->sec_prot.initial_key_imin = SMALL_NW_INITIAL_KEY_TRICKLE_IMIN_SECS; + cfg->sec_prot.initial_key_imax = SMALL_NW_INITIAL_KEY_TRICKLE_IMAX_SECS; + cfg->sec_prot.initial_key_retry_cnt = DEFAULT_INITIAL_KEY_RETRY_COUNT; } static void ws_cfg_network_size_config_set_medium(ws_cfg_nw_size_t *cfg) { + // Configure the Wi-SUN parent configuration + cfg->gen.rpl_parent_candidate_max = WS_RPL_PARENT_CANDIDATE_MAX; + cfg->gen.rpl_selected_parent_max = WS_RPL_SELECTED_PARENT_MAX; + // Configure the Wi-SUN timing trickle parameters - cfg->timing.disc_trickle_imin = TRICKLE_IMIN_30_SECS; // 30 seconds - cfg->timing.disc_trickle_imax = TRICKLE_IMIN_30_SECS << 5; // 960 seconds; 16 minutes + cfg->timing.disc_trickle_imin = TRICKLE_IMIN_60_SECS; // 60 seconds + cfg->timing.disc_trickle_imax = TRICKLE_IMIN_60_SECS << 4; // 960 seconds; 16 minutes cfg->timing.disc_trickle_k = 1; cfg->timing.pan_timeout = PAN_VERSION_MEDIUM_NETWORK_TIMEOUT; cfg->timing.temp_link_min_timeout = WS_NEIGHBOR_TEMPORARY_LINK_MIN_TIMEOUT_SMALL; + cfg->timing.temp_eapol_min_timeout = WS_EAPOL_TEMPORARY_ENTRY_MEDIUM_TIMEOUT; // RPL configuration - cfg->rpl.dio_interval_min = WS_RPL_DIO_IMIN_MEDIUM; // 15; 32s - cfg->rpl.dio_interval_doublings = WS_RPL_DIO_DOUBLING_MEDIUM; // 2; 1024s - cfg->rpl.dio_redundancy_constant = WS_RPL_DIO_REDUNDANCY_MEDIUM; // 10 - cfg->rpl.dag_max_rank_increase = WS_RPL_MAX_HOP_RANK_INCREASE; - cfg->rpl.min_hop_rank_increase = WS_RPL_MIN_HOP_RANK_INCREASE; - cfg->rpl.rpl_parent_candidate_max = WS_RPL_PARENT_CANDIDATE_MAX; - cfg->rpl.rpl_selected_parent_max = WS_RPL_SELECTED_PARENT_MAX; + cfg->bbr.dio_interval_min = WS_RPL_DIO_IMIN_MEDIUM; // 17; 128s + cfg->bbr.dio_interval_doublings = WS_RPL_DIO_DOUBLING_MEDIUM; // 3; 1024s + cfg->bbr.dio_redundancy_constant = WS_RPL_DIO_REDUNDANCY_MEDIUM; // 10 + cfg->bbr.dag_max_rank_increase = WS_RPL_MAX_HOP_RANK_INCREASE; + cfg->bbr.min_hop_rank_increase = WS_RPL_MIN_HOP_RANK_INCREASE; + cfg->bbr.dhcp_address_lifetime = WS_DHCP_ADDRESS_LIFETIME_MEDIUM; // EAPOL configuration cfg->sec_prot.sec_prot_trickle_imin = SEC_PROT_SMALL_IMIN; cfg->sec_prot.sec_prot_trickle_imax = SEC_PROT_SMALL_IMAX; cfg->sec_prot.sec_prot_trickle_timer_exp = SEC_PROT_TIMER_EXPIRATIONS; cfg->sec_prot.sec_prot_retry_timeout = SEC_PROT_RETRY_TIMEOUT_SMALL; - cfg->sec_prot.sec_max_ongoing_authentication = MAX_SIMULTANEOUS_EAP_TLS_NEGOTIATIONS_MEDIUM; + + cfg->sec_prot.sec_max_ongoing_authentication = MAX_SIMULTANEOUS_SECURITY_NEGOTIATIONS_MEDIUM; + + cfg->sec_prot.initial_key_retry_delay = DEFAULT_INITIAL_KEY_RETRY_TIMER; + cfg->sec_prot.initial_key_imin = MEDIUM_NW_INITIAL_KEY_TRICKLE_IMIN_SECS; + cfg->sec_prot.initial_key_imax = MEDIUM_NW_INITIAL_KEY_TRICKLE_IMAX_SECS; + cfg->sec_prot.initial_key_retry_cnt = DEFAULT_INITIAL_KEY_RETRY_COUNT; } static void ws_cfg_network_size_config_set_large(ws_cfg_nw_size_t *cfg) { + // Configure the Wi-SUN parent configuration + cfg->gen.rpl_parent_candidate_max = WS_RPL_PARENT_CANDIDATE_MAX; + cfg->gen.rpl_selected_parent_max = WS_RPL_SELECTED_PARENT_MAX; + // Configure the Wi-SUN timing trickle parameters - cfg->timing.disc_trickle_imin = TRICKLE_IMIN_60_SECS; // 60 seconds - cfg->timing.disc_trickle_imax = TRICKLE_IMIN_60_SECS << 4; // 960 seconds; 16 minutes + cfg->timing.disc_trickle_imin = TRICKLE_IMIN_60_SECS << 2; // 240 seconds + cfg->timing.disc_trickle_imax = 1536; // 1536 seconds; 25 minutes cfg->timing.disc_trickle_k = 1; cfg->timing.pan_timeout = PAN_VERSION_LARGE_NETWORK_TIMEOUT; cfg->timing.temp_link_min_timeout = WS_NEIGHBOR_TEMPORARY_LINK_MIN_TIMEOUT_LARGE; + cfg->timing.temp_eapol_min_timeout = WS_EAPOL_TEMPORARY_ENTRY_LARGE_TIMEOUT; // RPL configuration - cfg->rpl.dio_interval_min = WS_RPL_DIO_IMIN_LARGE; // 19; 524s, 9min - cfg->rpl.dio_interval_doublings = WS_RPL_DIO_DOUBLING_LARGE; // 1; 1024s, 17min - cfg->rpl.dio_redundancy_constant = WS_RPL_DIO_REDUNDANCY_LARGE; // 10 - cfg->rpl.dag_max_rank_increase = WS_RPL_MAX_HOP_RANK_INCREASE; - cfg->rpl.min_hop_rank_increase = WS_RPL_MIN_HOP_RANK_INCREASE; - cfg->rpl.rpl_parent_candidate_max = WS_RPL_PARENT_CANDIDATE_MAX; - cfg->rpl.rpl_selected_parent_max = WS_RPL_SELECTED_PARENT_MAX; + cfg->bbr.dio_interval_min = WS_RPL_DIO_IMIN_LARGE; // 18; 262s, 4.5min + cfg->bbr.dio_interval_doublings = WS_RPL_DIO_DOUBLING_LARGE; // 3; 2048s, 34min + cfg->bbr.dio_redundancy_constant = WS_RPL_DIO_REDUNDANCY_LARGE; // 10 + cfg->bbr.dag_max_rank_increase = WS_RPL_MAX_HOP_RANK_INCREASE; + cfg->bbr.min_hop_rank_increase = WS_RPL_MIN_HOP_RANK_INCREASE; + cfg->bbr.dhcp_address_lifetime = WS_DHCP_ADDRESS_LIFETIME_LARGE; // EAPOL configuration cfg->sec_prot.sec_prot_trickle_imin = SEC_PROT_LARGE_IMIN; cfg->sec_prot.sec_prot_trickle_imax = SEC_PROT_LARGE_IMAX; cfg->sec_prot.sec_prot_trickle_timer_exp = SEC_PROT_TIMER_EXPIRATIONS; cfg->sec_prot.sec_prot_retry_timeout = SEC_PROT_RETRY_TIMEOUT_LARGE; - cfg->sec_prot.sec_max_ongoing_authentication = MAX_SIMULTANEOUS_EAP_TLS_NEGOTIATIONS_LARGE; + + cfg->sec_prot.sec_max_ongoing_authentication = MAX_SIMULTANEOUS_SECURITY_NEGOTIATIONS_LARGE; + + cfg->sec_prot.initial_key_retry_delay = NONE_INITIAL_KEY_RETRY_TIMER; + cfg->sec_prot.initial_key_imin = LARGE_NW_INITIAL_KEY_TRICKLE_IMIN_SECS; + cfg->sec_prot.initial_key_imax = LARGE_NW_INITIAL_KEY_TRICKLE_IMAX_SECS; + cfg->sec_prot.initial_key_retry_cnt = LARGE_NW_INITIAL_KEY_RETRY_COUNT; +} + +static void ws_cfg_network_size_config_set_xlarge(ws_cfg_nw_size_t *cfg) +{ + // Configure the Wi-SUN parent configuration + cfg->gen.rpl_parent_candidate_max = WS_RPL_PARENT_CANDIDATE_MAX; + cfg->gen.rpl_selected_parent_max = WS_RPL_SELECTED_PARENT_MAX; + + // Configure the Wi-SUN timing trickle parameters + cfg->timing.disc_trickle_imin = TRICKLE_IMIN_60_SECS << 2; // 240 seconds + cfg->timing.disc_trickle_imax = 1920; // 1920 seconds; 32 minutes + cfg->timing.disc_trickle_k = 1; + cfg->timing.pan_timeout = PAN_VERSION_XLARGE_NETWORK_TIMEOUT; + cfg->timing.temp_link_min_timeout = WS_NEIGHBOR_TEMPORARY_LINK_MIN_TIMEOUT_LARGE; + cfg->timing.temp_eapol_min_timeout = WS_EAPOL_TEMPORARY_ENTRY_LARGE_TIMEOUT; + + // RPL configuration + cfg->bbr.dio_interval_min = WS_RPL_DIO_IMIN_XLARGE; // 18; 262s, 4.5min + cfg->bbr.dio_interval_doublings = WS_RPL_DIO_DOUBLING_XLARGE; // 4; 2048s, 34min + cfg->bbr.dio_redundancy_constant = WS_RPL_DIO_REDUNDANCY_XLARGE; // 10 + cfg->bbr.dag_max_rank_increase = WS_RPL_MAX_HOP_RANK_INCREASE; + cfg->bbr.min_hop_rank_increase = WS_RPL_MIN_HOP_RANK_INCREASE; + cfg->bbr.dhcp_address_lifetime = WS_DHCP_ADDRESS_LIFETIME_LARGE; + + // EAPOL configuration + cfg->sec_prot.sec_prot_trickle_imin = SEC_PROT_LARGE_IMIN; + cfg->sec_prot.sec_prot_trickle_imax = SEC_PROT_LARGE_IMAX; + cfg->sec_prot.sec_prot_trickle_timer_exp = SEC_PROT_TIMER_EXPIRATIONS; + cfg->sec_prot.sec_prot_retry_timeout = SEC_PROT_RETRY_TIMEOUT_LARGE; + + cfg->sec_prot.sec_max_ongoing_authentication = MAX_SIMULTANEOUS_SECURITY_NEGOTIATIONS_LARGE; + + cfg->sec_prot.initial_key_retry_delay = NONE_INITIAL_KEY_RETRY_TIMER; + cfg->sec_prot.initial_key_imin = EXTRA_LARGE_NW_INITIAL_KEY_TRICKLE_IMIN_SECS; + cfg->sec_prot.initial_key_imax = EXTRA_LARGE_NW_INITIAL_KEY_TRICKLE_IMAX_SECS; + cfg->sec_prot.initial_key_retry_cnt = EXTRA_LARGE_NW_INITIAL_KEY_RETRY_COUNT; } static void ws_cfg_network_size_config_set_certificate(ws_cfg_nw_size_t *cfg) { + // Configure the Wi-SUN parent configuration + cfg->gen.rpl_parent_candidate_max = WS_CERTIFICATE_RPL_PARENT_CANDIDATE_MAX; + cfg->gen.rpl_selected_parent_max = WS_CERTIFICATE_RPL_SELECTED_PARENT_MAX; + // Configure the Wi-SUN timing trickle parameters cfg->timing.disc_trickle_imin = TRICKLE_IMIN_15_SECS; // 15 seconds cfg->timing.disc_trickle_imax = TRICKLE_IMIN_15_SECS << 2; // 60 seconds cfg->timing.disc_trickle_k = 1; cfg->timing.pan_timeout = PAN_VERSION_SMALL_NETWORK_TIMEOUT; cfg->timing.temp_link_min_timeout = WS_NEIGHBOR_TEMPORARY_LINK_MIN_TIMEOUT_SMALL; + cfg->timing.temp_eapol_min_timeout = WS_EAPOL_TEMPORARY_ENTRY_SMALL_TIMEOUT; // RPL configuration (small) - cfg->rpl.dio_interval_min = WS_RPL_DIO_IMIN_SMALL; // 15; 32s seconds - cfg->rpl.dio_interval_doublings = WS_RPL_DIO_DOUBLING_SMALL; // 2; 128 - cfg->rpl.dio_redundancy_constant = WS_RPL_DIO_REDUNDANCY_SMALL; // Disabled - cfg->rpl.dag_max_rank_increase = WS_CERTIFICATE_RPL_MAX_HOP_RANK_INCREASE; - cfg->rpl.min_hop_rank_increase = WS_CERTIFICATE_RPL_MIN_HOP_RANK_INCREASE; - cfg->rpl.rpl_parent_candidate_max = WS_CERTIFICATE_RPL_PARENT_CANDIDATE_MAX; - cfg->rpl.rpl_selected_parent_max = WS_CERTIFICATE_RPL_SELECTED_PARENT_MAX; + cfg->bbr.dio_interval_min = WS_RPL_DIO_IMIN_SMALL; // 15; 32s seconds + cfg->bbr.dio_interval_doublings = WS_RPL_DIO_DOUBLING_SMALL; // 2; 128 + cfg->bbr.dio_redundancy_constant = WS_RPL_DIO_REDUNDANCY_SMALL; // Disabled + cfg->bbr.dag_max_rank_increase = WS_CERTIFICATE_RPL_MAX_HOP_RANK_INCREASE; + cfg->bbr.min_hop_rank_increase = WS_CERTIFICATE_RPL_MIN_HOP_RANK_INCREASE; + cfg->bbr.dhcp_address_lifetime = WS_DHCP_ADDRESS_LIFETIME_SMALL; // EAPOL configuration cfg->sec_prot.sec_prot_trickle_imin = SEC_PROT_SMALL_IMIN; cfg->sec_prot.sec_prot_trickle_imax = SEC_PROT_SMALL_IMAX; cfg->sec_prot.sec_prot_trickle_timer_exp = SEC_PROT_TIMER_EXPIRATIONS; cfg->sec_prot.sec_prot_retry_timeout = SEC_PROT_RETRY_TIMEOUT_SMALL; - cfg->sec_prot.sec_max_ongoing_authentication = MAX_SIMULTANEOUS_EAP_TLS_NEGOTIATIONS_SMALL; + + cfg->sec_prot.sec_max_ongoing_authentication = MAX_SIMULTANEOUS_SECURITY_NEGOTIATIONS_SMALL; + + cfg->sec_prot.initial_key_retry_delay = DEFAULT_INITIAL_KEY_RETRY_TIMER; + cfg->sec_prot.initial_key_imin = SMALL_NW_INITIAL_KEY_TRICKLE_IMIN_SECS; + cfg->sec_prot.initial_key_imax = SMALL_NW_INITIAL_KEY_TRICKLE_IMAX_SECS; + cfg->sec_prot.initial_key_retry_cnt = DEFAULT_INITIAL_KEY_RETRY_COUNT; } static int8_t ws_cfg_gen_default_set(ws_gen_cfg_t *cfg) { memset(cfg->network_name, 0, sizeof(cfg->network_name)); cfg->network_pan_id = 0xffff; + cfg->rpl_parent_candidate_max = WS_RPL_PARENT_CANDIDATE_MAX; + cfg->rpl_selected_parent_max = WS_RPL_SELECTED_PARENT_MAX; return CFG_SETTINGS_OK; } @@ -467,7 +562,9 @@ int8_t ws_cfg_gen_validate(ws_gen_cfg_t *cfg, ws_gen_cfg_t *new_cfg) // Regulator domain, operating mode or class has changed if (strcmp(cfg->network_name, new_cfg->network_name) != 0 || - cfg->network_pan_id != new_cfg->network_pan_id) { + cfg->network_pan_id != new_cfg->network_pan_id || + cfg->rpl_parent_candidate_max != new_cfg->rpl_parent_candidate_max || + cfg->rpl_selected_parent_max != new_cfg->rpl_selected_parent_max) { return CFG_SETTINGS_CHANGED; } @@ -493,6 +590,8 @@ int8_t ws_cfg_gen_set(protocol_interface_info_entry_t *cur, ws_gen_cfg_t *cfg, w strncpy(cfg->network_name, new_cfg->network_name, 32); } cfg->network_pan_id = new_cfg->network_pan_id; + cfg->rpl_parent_candidate_max = new_cfg->rpl_parent_candidate_max; + cfg->rpl_selected_parent_max = new_cfg->rpl_selected_parent_max; if (cur && !(cfg_flags & CFG_FLAGS_BOOTSTRAP_RESTART_DISABLE)) { ws_bootstrap_restart_delayed(cur->id); @@ -584,11 +683,12 @@ int8_t ws_cfg_phy_set(protocol_interface_info_entry_t *cur, ws_phy_cfg_t *cfg, w static int8_t ws_cfg_timing_default_set(ws_timing_cfg_t *cfg) { // Configure the Wi-SUN timing trickle parameters - cfg->disc_trickle_imin = TRICKLE_IMIN_30_SECS; // 30 seconds - cfg->disc_trickle_imax = TRICKLE_IMIN_30_SECS << 5; // 960 seconds; 16 minutes + cfg->disc_trickle_imin = TRICKLE_IMIN_60_SECS; // 60 seconds + cfg->disc_trickle_imax = TRICKLE_IMIN_60_SECS << 4; // 960 seconds; 16 minutes cfg->disc_trickle_k = 1; cfg->pan_timeout = PAN_VERSION_MEDIUM_NETWORK_TIMEOUT; cfg->temp_link_min_timeout = WS_NEIGHBOR_TEMPORARY_LINK_MIN_TIMEOUT_SMALL; + cfg->temp_eapol_min_timeout = WS_EAPOL_TEMPORARY_ENTRY_MEDIUM_TIMEOUT; return CFG_SETTINGS_OK; } @@ -658,58 +758,56 @@ int8_t ws_cfg_timing_set(protocol_interface_info_entry_t *cur, ws_timing_cfg_t * return CFG_SETTINGS_OK; } -static int8_t ws_cfg_rpl_default_set(ws_rpl_cfg_t *cfg) +static int8_t ws_cfg_bbr_default_set(ws_bbr_cfg_t *cfg) { // Something in between - // imin: 15 (32s) - // doublings:5 (960s) + // imin: 17 (128s) + // doublings:3 (1024s) // redundancy; 10 - //ws_bbr_rpl_config(cur, 15, 5, 10, WS_RPL_MAX_HOP_RANK_INCREASE, WS_RPL_MIN_HOP_RANK_INCREASE); + //ws_bbr_rpl_config(cur, 17, 3, 10, WS_RPL_MAX_HOP_RANK_INCREASE, WS_RPL_MIN_HOP_RANK_INCREASE); - cfg->dio_interval_min = 15; // 32s - cfg->dio_interval_doublings = 5; // 1024s + cfg->dio_interval_min = WS_RPL_DIO_IMIN_MEDIUM; // 128s + cfg->dio_interval_doublings = WS_RPL_DIO_DOUBLING_MEDIUM; // 1024s cfg->dio_redundancy_constant = 10; cfg->dag_max_rank_increase = WS_RPL_MAX_HOP_RANK_INCREASE; cfg->min_hop_rank_increase = WS_RPL_MIN_HOP_RANK_INCREASE; - cfg->rpl_parent_candidate_max = WS_RPL_PARENT_CANDIDATE_MAX; - cfg->rpl_selected_parent_max = WS_RPL_SELECTED_PARENT_MAX; + cfg->dhcp_address_lifetime = WS_DHCP_ADDRESS_LIFETIME_MEDIUM; return CFG_SETTINGS_OK; } -int8_t ws_cfg_rpl_get(ws_rpl_cfg_t *cfg, uint8_t *flags) +int8_t ws_cfg_bbr_get(ws_bbr_cfg_t *cfg, uint8_t *flags) { - ws_rpl_cfg_t *get_cfg = NULL; - ws_cfg_to_get((ws_cfgs_t **) &get_cfg, NULL, NULL, (ws_cfgs_t *) &ws_cfg.rpl, 0, flags); + ws_bbr_cfg_t *get_cfg = NULL; + ws_cfg_to_get((ws_cfgs_t **) &get_cfg, NULL, NULL, (ws_cfgs_t *) &ws_cfg.bbr, 0, flags); *cfg = *get_cfg; return CFG_SETTINGS_OK; } -int8_t ws_cfg_rpl_validate(ws_rpl_cfg_t *cfg, ws_rpl_cfg_t *new_cfg) +int8_t ws_cfg_bbr_validate(ws_bbr_cfg_t *cfg, ws_bbr_cfg_t *new_cfg) { - ws_cfg_to_get((ws_cfgs_t **) &cfg, (ws_cfgs_t *) new_cfg, NULL, (ws_cfgs_t *) &ws_cfg.rpl, 0, 0); + ws_cfg_to_get((ws_cfgs_t **) &cfg, (ws_cfgs_t *) new_cfg, NULL, (ws_cfgs_t *) &ws_cfg.bbr, 0, 0); if (cfg->dio_interval_min != new_cfg->dio_interval_min || cfg->dio_interval_doublings != new_cfg->dio_interval_doublings || cfg->dio_redundancy_constant != new_cfg->dio_redundancy_constant || cfg->dag_max_rank_increase != new_cfg->dag_max_rank_increase || cfg->min_hop_rank_increase != new_cfg->min_hop_rank_increase || - cfg->rpl_parent_candidate_max != new_cfg->rpl_parent_candidate_max || - cfg->rpl_selected_parent_max != new_cfg->rpl_selected_parent_max) { + cfg->dhcp_address_lifetime != new_cfg->dhcp_address_lifetime) { return CFG_SETTINGS_CHANGED; } return CFG_SETTINGS_OK; } -int8_t ws_cfg_rpl_set(protocol_interface_info_entry_t *cur, ws_rpl_cfg_t *cfg, ws_rpl_cfg_t *new_cfg, uint8_t *flags) +int8_t ws_cfg_bbr_set(protocol_interface_info_entry_t *cur, ws_bbr_cfg_t *cfg, ws_bbr_cfg_t *new_cfg, uint8_t *flags) { (void) cur; (void) flags; uint8_t cfg_flags; - int8_t ret = ws_cfg_to_get((ws_cfgs_t **) &cfg, (ws_cfgs_t *) new_cfg, (ws_cfg_validate) ws_cfg_rpl_validate, (ws_cfgs_t *) &ws_cfg.rpl, &cfg_flags, flags); + int8_t ret = ws_cfg_to_get((ws_cfgs_t **) &cfg, (ws_cfgs_t *) new_cfg, (ws_cfg_validate) ws_cfg_bbr_validate, (ws_cfgs_t *) &ws_cfg.bbr, &cfg_flags, flags); if (ret != CFG_SETTINGS_CHANGED) { return ret; } @@ -719,13 +817,14 @@ int8_t ws_cfg_rpl_set(protocol_interface_info_entry_t *cur, ws_rpl_cfg_t *cfg, w ws_bbr_rpl_config(cur, new_cfg->dio_interval_min, new_cfg->dio_interval_doublings, new_cfg->dio_redundancy_constant, new_cfg->dag_max_rank_increase, new_cfg->min_hop_rank_increase); + ws_bbr_dhcp_address_lifetime_set(cur, new_cfg->dhcp_address_lifetime); } if (cfg == new_cfg) { return CFG_SETTINGS_OK; } - ws_cfg_trace((ws_cfgs_t *) cfg, (ws_cfgs_t *) new_cfg, sizeof(ws_rpl_cfg_t), "rpl"); + ws_cfg_trace((ws_cfgs_t *) cfg, (ws_cfgs_t *) new_cfg, sizeof(ws_bbr_cfg_t), "rpl"); *cfg = *new_cfg; @@ -978,7 +1077,12 @@ static int8_t ws_cfg_sec_prot_default_set(ws_sec_prot_cfg_t *cfg) cfg->sec_prot_trickle_imax = SEC_PROT_SMALL_IMAX; cfg->sec_prot_trickle_timer_exp = 2; cfg->sec_prot_retry_timeout = SEC_PROT_RETRY_TIMEOUT_SMALL; - cfg->sec_max_ongoing_authentication = MAX_SIMULTANEOUS_EAP_TLS_NEGOTIATIONS_MEDIUM; + cfg->sec_max_ongoing_authentication = MAX_SIMULTANEOUS_SECURITY_NEGOTIATIONS_MEDIUM; + cfg->initial_key_retry_delay = DEFAULT_INITIAL_KEY_RETRY_TIMER; + cfg->initial_key_imin = MEDIUM_NW_INITIAL_KEY_TRICKLE_IMIN_SECS; + cfg->initial_key_imax = MEDIUM_NW_INITIAL_KEY_TRICKLE_IMAX_SECS; + cfg->initial_key_retry_cnt = DEFAULT_INITIAL_KEY_RETRY_COUNT; + return CFG_SETTINGS_OK; } @@ -999,7 +1103,11 @@ int8_t ws_cfg_sec_prot_validate(ws_sec_prot_cfg_t *cfg, ws_sec_prot_cfg_t *new_c cfg->sec_prot_trickle_imax != new_cfg->sec_prot_trickle_imax || cfg->sec_prot_trickle_timer_exp != new_cfg->sec_prot_trickle_timer_exp || cfg->sec_prot_retry_timeout != new_cfg->sec_prot_retry_timeout || - cfg->sec_max_ongoing_authentication != new_cfg->sec_max_ongoing_authentication) { + cfg->sec_max_ongoing_authentication != new_cfg->sec_max_ongoing_authentication || + cfg->initial_key_retry_delay != new_cfg->initial_key_retry_delay || + cfg->initial_key_imin != new_cfg->initial_key_retry_delay || + cfg->initial_key_imax != new_cfg->initial_key_retry_delay || + cfg->initial_key_retry_cnt != new_cfg->initial_key_retry_delay) { return CFG_SETTINGS_CHANGED; } @@ -1095,8 +1203,9 @@ int8_t ws_cfg_settings_get(protocol_interface_info_entry_t *cur, ws_cfg_t *cfg) *cfg = ws_cfg; + ws_cfg_gen_get(&cfg->gen, NULL); ws_cfg_timing_get(&cfg->timing, NULL); - ws_cfg_rpl_get(&cfg->rpl, NULL); + ws_cfg_bbr_get(&cfg->bbr, NULL); ws_cfg_sec_prot_get(&cfg->sec_prot, NULL); return CFG_SETTINGS_OK; diff --git a/source/6LoWPAN/ws/ws_cfg_settings.h b/source/6LoWPAN/ws/ws_cfg_settings.h index 334489d513..bc46336229 100644 --- a/source/6LoWPAN/ws/ws_cfg_settings.h +++ b/source/6LoWPAN/ws/ws_cfg_settings.h @@ -27,6 +27,8 @@ typedef struct ws_gen_cfg_s { uint8_t network_size; /**< Network size selection; default medium (= 8) */ char network_name[33]; /**< Network name; max 32 octets + terminating 0 */ uint16_t network_pan_id; /**< PAN identifier; PAN_ID; default 0xffff */ + uint16_t rpl_parent_candidate_max; /**< RPL parent candidate maximum value; default 5 */ + uint16_t rpl_selected_parent_max; /**< RPL selected parent maximum value; default 2 */ } ws_gen_cfg_t; /** @@ -47,20 +49,20 @@ typedef struct ws_timing_cfg_s { uint8_t disc_trickle_k; /**< Discovery trickle k; DISC_K; default 1 */ uint16_t pan_timeout; /**< PAN timeout; PAN_TIMEOUT; seconds; range 60-15300; default 3840 */ uint16_t temp_link_min_timeout; /**< Temporary neighbor link minimum timeout; seconds; default 260 */ + uint16_t temp_eapol_min_timeout; /**< Temporary neighbor link minimum timeout; seconds; default 330 */ } ws_timing_cfg_t; /** * \brief Struct ws_rpl_cfg_t RPL configuration */ -typedef struct ws_rpl_cfg_s { +typedef struct ws_bbr_cfg_s { uint8_t dio_interval_min; /**> DIO interval min; DEFAULT_DIO_INTERVAL_MIN; 2^value in milliseconds; range 1-255; default */ uint8_t dio_interval_doublings; /**> DIO interval doublings; DEFAULT_DIO_INTERVAL_DOUBLINGS; range 1-8; default */ uint8_t dio_redundancy_constant; /**> DIO redundancy constant; DEFAULT_DIO_REDUNDANCY_CONSTANT; range 0-10; default */ uint16_t dag_max_rank_increase; uint16_t min_hop_rank_increase; - uint16_t rpl_parent_candidate_max; /**< RPL parent candidate maximum value; default 5 */ - uint16_t rpl_selected_parent_max; /**< RPL selected parent maximum value; default 2 */ -} ws_rpl_cfg_t; + uint32_t dhcp_address_lifetime; /**> DHCP address lifetime in seconds minimum 2 hours and maximum as days hours*/ +} ws_bbr_cfg_t; /** * \brief Struct ws_fhss_cfg_t Frequency hopping configuration @@ -106,11 +108,15 @@ typedef struct ws_sec_timer_cfg_s { * \brief Struct ws_sec_prot_cfg_t Security protocols configuration */ typedef struct ws_sec_prot_cfg_s { - uint16_t sec_prot_retry_timeout; /**< Security protocol retry timeout; seconds; default 330 */ - uint16_t sec_prot_trickle_imin; /**< Security protocol trickle parameters Imin; seconds; default 30 */ - uint16_t sec_prot_trickle_imax; /**< Security protocol trickle parameters Imax; seconds; default 90 */ - uint8_t sec_prot_trickle_timer_exp; /**< Security protocol trickle timer expirations; default 2 */ - uint16_t sec_max_ongoing_authentication; /**< Pae authenticator max Accept ongoing authentication count */ + uint16_t sec_prot_retry_timeout; /**< Security protocol retry timeout; seconds; default 330 */ + uint16_t sec_prot_trickle_imin; /**< Security protocol trickle parameters Imin; seconds; default 30 */ + uint16_t sec_prot_trickle_imax; /**< Security protocol trickle parameters Imax; seconds; default 90 */ + uint8_t sec_prot_trickle_timer_exp; /**< Security protocol trickle timer expirations; default 2 */ + uint16_t sec_max_ongoing_authentication; /**< Pae authenticator max Accept ongoing authentication count */ + uint16_t initial_key_retry_delay; /**< Delay before starting initial key trickle; seconds; default 120 */ + uint16_t initial_key_imin; /**< Initial key trickle Imin; seconds; default 360 */ + uint16_t initial_key_imax; /**< Initial key trickle Imax; seconds; default 720 */ + uint8_t initial_key_retry_cnt; /**< Number of initial key retries; default 2 */ } ws_sec_prot_cfg_t; /** @@ -120,7 +126,7 @@ typedef struct ws_cfg_s { ws_gen_cfg_t gen; /**< General configuration */ ws_phy_cfg_t phy; /**< Physical layer configuration */ ws_timing_cfg_t timing; /**< Timing configuration */ - ws_rpl_cfg_t rpl; /**< RPL configuration */ + ws_bbr_cfg_t bbr; /**< RPL configuration */ ws_fhss_cfg_t fhss; /**< Frequency hopping configuration */ ws_mpl_cfg_t mpl; /**< Multicast configuration */ ws_sec_timer_cfg_t sec_timer; /**< Security timers configuration */ @@ -161,9 +167,9 @@ int8_t ws_cfg_timing_get(ws_timing_cfg_t *cfg, uint8_t *flags); int8_t ws_cfg_timing_validate(ws_timing_cfg_t *cfg, ws_timing_cfg_t *new_cfg); int8_t ws_cfg_timing_set(protocol_interface_info_entry_t *cur, ws_timing_cfg_t *cfg, ws_timing_cfg_t *new_cfg, uint8_t *flags); -int8_t ws_cfg_rpl_get(ws_rpl_cfg_t *cfg, uint8_t *flags); -int8_t ws_cfg_rpl_validate(ws_rpl_cfg_t *cfg, ws_rpl_cfg_t *new_cfg); -int8_t ws_cfg_rpl_set(protocol_interface_info_entry_t *cur, ws_rpl_cfg_t *cfg, ws_rpl_cfg_t *new_cfg, uint8_t *flags); +int8_t ws_cfg_bbr_get(ws_bbr_cfg_t *cfg, uint8_t *flags); +int8_t ws_cfg_bbr_validate(ws_bbr_cfg_t *cfg, ws_bbr_cfg_t *new_cfg); +int8_t ws_cfg_bbr_set(protocol_interface_info_entry_t *cur, ws_bbr_cfg_t *cfg, ws_bbr_cfg_t *new_cfg, uint8_t *flags); int8_t ws_cfg_mpl_get(ws_mpl_cfg_t *cfg, uint8_t *flags); int8_t ws_cfg_mpl_validate(ws_mpl_cfg_t *cfg, ws_mpl_cfg_t *new_cfg); diff --git a/source/6LoWPAN/ws/ws_common.c b/source/6LoWPAN/ws/ws_common.c index 7bfb66df4e..010f6c14ac 100644 --- a/source/6LoWPAN/ws/ws_common.c +++ b/source/6LoWPAN/ws/ws_common.c @@ -49,12 +49,34 @@ uint8_t DEVICE_MIN_SENS = 174 - 93; uint16_t test_max_child_count_override = 0xffff; - -int8_t ws_generate_channel_list(uint32_t *channel_mask, uint16_t number_of_channels, uint8_t regulatory_domain) +int8_t ws_generate_channel_list(uint32_t *channel_mask, uint16_t number_of_channels, uint8_t regulatory_domain, uint8_t operating_class) { - (void)regulatory_domain; - for (uint8_t i = 0; i < number_of_channels; i++) { - channel_mask[0 + (i / 32)] |= (1 << (i % 32)); + uint32_t excluded_start_channel = 0xFFFFFFFF; + uint32_t excluded_end_channel = 0xFFFFFFFF; + + if (regulatory_domain == REG_DOMAIN_BZ) { + if (operating_class == 1) { + excluded_start_channel = 26; + excluded_end_channel = 64; + } else if (operating_class == 2) { + excluded_start_channel = 12; + excluded_end_channel = 32; + } else if (operating_class == 3) { + excluded_start_channel = 7; + excluded_end_channel = 21; + } + } + + // Clear channel mask + for (uint8_t i = 0; i < 8; i++) { + channel_mask[i] = 0; + } + + // Set channel maks outside excluded channels + for (uint16_t i = 0; i < number_of_channels; i++) { + if (i < excluded_start_channel || i > excluded_end_channel) { + channel_mask[0 + (i / 32)] |= (1 << (i % 32)); + } } return 0; } @@ -159,6 +181,19 @@ int8_t ws_common_regulatory_domain_config(protocol_interface_info_entry_t *cur, } else { return -1; } + } else if (hopping_schdule->regulatory_domain == REG_DOMAIN_BZ) { + if (hopping_schdule->operating_class == 1) { + hopping_schdule->ch0_freq = 9022; + hopping_schdule->channel_spacing = CHANNEL_SPACING_200; + } else if (hopping_schdule->operating_class == 2) { + hopping_schdule->ch0_freq = 9024; + hopping_schdule->channel_spacing = CHANNEL_SPACING_400; + } else if (hopping_schdule->operating_class == 3) { + hopping_schdule->ch0_freq = 9026; + hopping_schdule->channel_spacing = CHANNEL_SPACING_600; + } else { + return -1; + } } else if (hopping_schdule->regulatory_domain == REG_DOMAIN_JP) { if (hopping_schdule->operating_class == 1) { hopping_schdule->ch0_freq = 9206; @@ -189,6 +224,7 @@ int8_t ws_common_regulatory_domain_config(protocol_interface_info_entry_t *cur, if (!hopping_schdule->number_of_channels) { return -1; } + return 0; } @@ -232,6 +268,14 @@ uint16_t ws_common_channel_number_calc(uint8_t regulatory_domain, uint8_t operat } else if (operating_class == 3) { return 12; } + } else if (regulatory_domain == REG_DOMAIN_BZ) { + if (operating_class == 1) { + return 129; + } else if (operating_class == 2) { + return 64; + } else if (operating_class == 3) { + return 42; + } } else if (regulatory_domain == REG_DOMAIN_WW) { if (operating_class == 1) { // TODO we dont support this yet, but it is used as test value @@ -388,11 +432,13 @@ uint32_t ws_common_latency_estimate_get(protocol_interface_info_entry_t *cur) if (network_size <= NETWORK_SIZE_SMALL) { // handles also NETWORK_SIZE_CERTIFICATE - latency = 8000; + latency = 4000; } else if (network_size <= NETWORK_SIZE_MEDIUM) { + latency = 8000; + } else if (network_size <= NETWORK_SIZE_LARGE) { latency = 16000; } else { - latency = 32000; + latency = 24000; } return latency; @@ -405,22 +451,11 @@ uint32_t ws_common_datarate_get(protocol_interface_info_entry_t *cur) uint32_t ws_common_network_size_estimate_get(protocol_interface_info_entry_t *cur) { - uint32_t network_size_estimate = 0; - uint8_t network_size = cur->ws_info->cfg->gen.network_size; + uint32_t network_size_estimate = 100; - if (network_size == NETWORK_SIZE_AUTOMATIC) { - network_size = cur->ws_info->pan_information.pan_size / 100; - } - - if (network_size <= NETWORK_SIZE_SMALL) { - // tens of devices (now 30), handles also NETWORK_SIZE_CERTIFICATE - network_size_estimate = 30; - } else if (network_size <= NETWORK_SIZE_MEDIUM) { - // hundreds of devices (now 300) - network_size_estimate = 300; - } else { - // huge amount of devices (now 1000) - network_size_estimate = 1000; + if ((cur->ws_info->cfg->gen.network_size != NETWORK_SIZE_AUTOMATIC) && + (cur->ws_info->cfg->gen.network_size != NETWORK_SIZE_CERTIFICATE)) { + network_size_estimate = cur->ws_info->cfg->gen.network_size * 100; } return network_size_estimate; diff --git a/source/6LoWPAN/ws/ws_common.h b/source/6LoWPAN/ws/ws_common.h index 3aa154c052..08d726ee6b 100644 --- a/source/6LoWPAN/ws/ws_common.h +++ b/source/6LoWPAN/ws/ws_common.h @@ -82,6 +82,7 @@ typedef struct ws_info_s { trickle_params_t trickle_params_pan_discovery; uint8_t rpl_state; // state from rpl_event_t uint8_t pas_requests; // Amount of PAN solicits sent + uint8_t eapol_tx_index; parent_info_t parent_info[WS_PARENT_LIST_SIZE]; parent_info_list_t parent_list_free; parent_info_list_t parent_list_reserved; @@ -112,7 +113,7 @@ typedef struct ws_info_s { #ifdef HAVE_WS -int8_t ws_generate_channel_list(uint32_t *channel_mask, uint16_t number_of_channels, uint8_t regulatory_domain); +int8_t ws_generate_channel_list(uint32_t *channel_mask, uint16_t number_of_channels, uint8_t regulatory_domain, uint8_t operating_class); uint32_t ws_decode_channel_spacing(uint8_t channel_spacing); diff --git a/source/6LoWPAN/ws/ws_common_defines.h b/source/6LoWPAN/ws/ws_common_defines.h index d2797f8e80..749a5aa1fa 100644 --- a/source/6LoWPAN/ws/ws_common_defines.h +++ b/source/6LoWPAN/ws/ws_common_defines.h @@ -236,9 +236,12 @@ typedef struct ws_bs_ie { #define WS_NEIGHBOR_TEMPORARY_LINK_MIN_TIMEOUT_SMALL 260 #define WS_NEIGHBOR_NUD_TIMEOUT WS_NEIGHBOR_LINK_TIMEOUT / 2 +#define WS_EAPOL_TEMPORARY_ENTRY_SMALL_TIMEOUT 330 +#define WS_EAPOL_TEMPORARY_ENTRY_MEDIUM_TIMEOUT WS_EAPOL_TEMPORARY_ENTRY_SMALL_TIMEOUT +#define WS_EAPOL_TEMPORARY_ENTRY_LARGE_TIMEOUT 750 + #define WS_NEIGHBOR_ETX_SAMPLE_MAX 3 #define WS_NEIGHBOR_FIRST_ETX_SAMPLE_MIN_COUNT 3 //This can't be bigger than WS_NEIGHBOR_ETX_SAMPLE_MAX -#define WS_NEIGHBOUR_MAX_CANDIDATE_PROBE 5 #define WS_PROBE_INIT_BASE_SECONDS 8 @@ -295,6 +298,34 @@ typedef struct ws_bs_ie { */ #define WS_TACK_MAX_MS 5 + +/* WS requires at least 19 MAC retransmissions (total 1+19=20 attempts). Default 802.15.4 macMaxFrameRetries is 3 (total 1+3=4 attempts). + * At least 4 channel retries must be used: (Initial channel + WS_NUMBER_OF_CHANNEL_RETRIES) * MAC attempts = (1+4)*4=20 attempts + * + * Valid settings could be for example: + * WS_MAX_FRAME_RETRIES WS_NUMBER_OF_CHANNEL_RETRIES Total attempts + * 0 19 1+0*1+19=20 + * 1 9 1+1*1+9=20 + * 2 6 1+2*1+6=21 + * 3 4 1+3*1+4=20 + * + */ +#define WS_MAX_FRAME_RETRIES 3 +#define WS_NUMBER_OF_CHANNEL_RETRIES 4 + + +#if (1 + WS_MAX_FRAME_RETRIES) * (1 + WS_NUMBER_OF_CHANNEL_RETRIES) < 20 +#warning "MAX frame retries set too low" +#endif + +/* + * Automatic CCA threshold: default threshold and range in dBm. + */ +#define CCA_DEFAULT_DBM -60 +#define CCA_HIGH_LIMIT -60 +#define CCA_LOW_LIMIT -100 + + /* * Config new version consistent filter period in 100ms periods */ diff --git a/source/6LoWPAN/ws/ws_config.h b/source/6LoWPAN/ws/ws_config.h index b2a9bd18c9..6b00d6004c 100644 --- a/source/6LoWPAN/ws/ws_config.h +++ b/source/6LoWPAN/ws/ws_config.h @@ -31,14 +31,18 @@ #define WS_RPL_DIO_DOUBLING_SMALL 2 #define WS_RPL_DIO_REDUNDANCY_SMALL 0 -#define WS_RPL_DIO_IMIN_MEDIUM 15 -#define WS_RPL_DIO_DOUBLING_MEDIUM 5 +#define WS_RPL_DIO_IMIN_MEDIUM 17 +#define WS_RPL_DIO_DOUBLING_MEDIUM 3 #define WS_RPL_DIO_REDUNDANCY_MEDIUM 10 -#define WS_RPL_DIO_IMIN_LARGE 19 -#define WS_RPL_DIO_DOUBLING_LARGE 1 +#define WS_RPL_DIO_IMIN_LARGE 18 +#define WS_RPL_DIO_DOUBLING_LARGE 3 #define WS_RPL_DIO_REDUNDANCY_LARGE 10 // May need some tuning still +#define WS_RPL_DIO_IMIN_XLARGE 18 +#define WS_RPL_DIO_DOUBLING_XLARGE 4 +#define WS_RPL_DIO_REDUNDANCY_XLARGE 10 // May need some tuning still + #define WS_RPL_DIO_IMIN_AUTOMATIC 14 #define WS_RPL_DIO_DOUBLING_AUTOMATIC 3 #define WS_RPL_DIO_REDUNDANCY_AUTOMATIC 0 @@ -46,6 +50,10 @@ #define WS_RPL_MIN_HOP_RANK_INCREASE 196 #define WS_RPL_MAX_HOP_RANK_INCREASE 2048 +#define WS_DHCP_ADDRESS_LIFETIME_SMALL 2*3600 // small networks less than devices 100 +#define WS_DHCP_ADDRESS_LIFETIME_MEDIUM 12*3600 // Medium size networks from 100 - 1000 device networks +#define WS_DHCP_ADDRESS_LIFETIME_LARGE 24*3600 // Large size networks 1000 + device networks + #define WS_CERTIFICATE_RPL_MIN_HOP_RANK_INCREASE 128 #define WS_CERTIFICATE_RPL_MAX_HOP_RANK_INCREASE 0 @@ -64,7 +72,10 @@ // RPL version number update intervall // after restart version numbers are increased faster and then slowed down when network is stable #define RPL_VERSION_LIFETIME 12*3600 -#define RPL_VERSION_LIFETIME_RESTART 3600 +#define RPL_VERSION_LIFETIME_RESTART_SMALL 3600 +#define RPL_VERSION_LIFETIME_RESTART_MEDIUM 2*3600 +#define RPL_VERSION_LIFETIME_RESTART_LARGE 4*3600 +#define RPL_VERSION_LIFETIME_RESTART_EXTRA_LARGE 8*3600 /* Border router connection lost timeout * @@ -81,6 +92,8 @@ #define PAN_VERSION_LARGE_NETWORK_TIMEOUT 90*60 +#define PAN_VERSION_XLARGE_NETWORK_TIMEOUT 120*60 + /* Routing Cost Weighting factor */ #define PRC_WEIGHT_FACTOR 256 @@ -153,10 +166,11 @@ extern uint8_t DEVICE_MIN_SENS; /* * MAC frame counter NVM storing configuration */ -#define FRAME_COUNTER_STORE_INTERVAL 60 // Time interval (on seconds) between frame counter store operations -#define FRAME_COUNTER_STORE_TRIGGER 5 // Delay (on seconds) before storing, when storing of frame counters is triggered -#define FRAME_COUNTER_INCREMENT 1000 // How much frame counter is incremented on start up -#define FRAME_COUNTER_STORE_THRESHOLD 800 // How much frame counter must increment before it is stored +#define FRAME_COUNTER_STORE_INTERVAL 60 // Time interval (on seconds) between checking if frame counter storing is needed +#define FRAME_COUNTER_STORE_FORCE_INTERVAL (3600 * 20) // Time interval (on seconds) before frame counter storing is forced (if no other storing operations triggered) +#define FRAME_COUNTER_STORE_TRIGGER 5 // Delay (on seconds) before storing, when storing of frame counters is triggered +#define FRAME_COUNTER_INCREMENT 1000 // How much frame counter is incremented on start up +#define FRAME_COUNTER_STORE_THRESHOLD 800 // How much frame counter must increment before it is stored /* @@ -199,10 +213,10 @@ extern uint8_t DEVICE_MIN_SENS; #define SEC_PROT_TIMER_EXPIRATIONS 2 // Number of retries -// Maximum number of simultaneous EAP-TLS negotiations -#define MAX_SIMULTANEOUS_EAP_TLS_NEGOTIATIONS_SMALL 3 -#define MAX_SIMULTANEOUS_EAP_TLS_NEGOTIATIONS_MEDIUM 20 -#define MAX_SIMULTANEOUS_EAP_TLS_NEGOTIATIONS_LARGE 50 +// Maximum number of simultaneous security negotiations +#define MAX_SIMULTANEOUS_SECURITY_NEGOTIATIONS_SMALL 3 +#define MAX_SIMULTANEOUS_SECURITY_NEGOTIATIONS_MEDIUM 20 +#define MAX_SIMULTANEOUS_SECURITY_NEGOTIATIONS_LARGE 50 /* * Security protocol timer configuration parameters @@ -218,4 +232,33 @@ extern uint8_t DEVICE_MIN_SENS; #define DEFAULT_GTK_MAX_MISMATCH 64 // 64 minutes #define DEFAULT_GTK_NEW_INSTALL_REQUIRED 80 // 80 percent of GTK lifetime --> 24 days +/* + * Security protocol initial EAPOL-key parameters + */ + +// How long the wait is before the first initial EAPOL-key retry +#define DEFAULT_INITIAL_KEY_RETRY_TIMER 120 +#define NONE_INITIAL_KEY_RETRY_TIMER 0 + +// Small network Default trickle values for sending of initial EAPOL-key +#define SMALL_NW_INITIAL_KEY_TRICKLE_IMIN_SECS 360 /* 6 to 8.3 minutes */ +#define SMALL_NW_INITIAL_KEY_TRICKLE_IMAX_SECS 500 + +// Small network Default trickle values for sending of initial EAPOL-key +#define MEDIUM_NW_INITIAL_KEY_TRICKLE_IMIN_SECS 360 /* 6 to 12 minutes */ +#define MEDIUM_NW_INITIAL_KEY_TRICKLE_IMAX_SECS 720 + +// Large network trickle values for sending of initial EAPOL-key +#define LARGE_NW_INITIAL_KEY_TRICKLE_IMIN_SECS 600 /* 10 to 20 minutes */ +#define LARGE_NW_INITIAL_KEY_TRICKLE_IMAX_SECS 1200 +#define LARGE_NW_INITIAL_KEY_RETRY_COUNT 4 + +// Very slow network values for sending of initial EAPOL-key +#define EXTRA_LARGE_NW_INITIAL_KEY_TRICKLE_IMIN_SECS 600 /* 10 to 20 minutes */ +#define EXTRA_LARGE_NW_INITIAL_KEY_TRICKLE_IMAX_SECS 1200 +#define EXTRA_LARGE_NW_INITIAL_KEY_RETRY_COUNT 4 + +// How many times sending of initial EAPOL-key is retried +#define DEFAULT_INITIAL_KEY_RETRY_COUNT 2 + #endif /* WS_CONFIG_H_ */ diff --git a/source/6LoWPAN/ws/ws_eapol_pdu.c b/source/6LoWPAN/ws/ws_eapol_pdu.c index ffe83c4a48..f20530d466 100644 --- a/source/6LoWPAN/ws/ws_eapol_pdu.c +++ b/source/6LoWPAN/ws/ws_eapol_pdu.c @@ -31,6 +31,7 @@ #include "6LoWPAN/MAC/mpx_api.h" #include "6LoWPAN/ws/ws_config.h" #include "6LoWPAN/ws/ws_eapol_pdu.h" +#include "6LoWPAN/ws/ws_llc.h" #ifdef HAVE_WS @@ -49,6 +50,7 @@ typedef NS_LIST_HEAD(eapol_pdu_msdu_t, link) eapol_pdu_msdu_list_t; typedef struct { uint8_t priority; + bool filter_requsted: 1; ws_eapol_pdu_address_check *addr_check; ws_eapol_pdu_receive *receive; ns_list_link_t link; @@ -147,6 +149,7 @@ int8_t ws_eapol_pdu_cb_register(protocol_interface_info_entry_t *interface_ptr, new_cb->priority = cb_data->priority; new_cb->addr_check = cb_data->addr_check; new_cb->receive = cb_data->receive; + new_cb->filter_requsted = cb_data->filter_requsted; ns_list_foreach(eapol_pdu_recv_cb_t, entry, &eapol_pdu_data->recv_cb_list) { if (new_cb->priority <= entry->priority) { @@ -307,6 +310,11 @@ static void ws_eapol_pdu_mpx_data_indication(const mpx_api_t *api, const struct ns_list_foreach(eapol_pdu_recv_cb_t, entry, &eapol_pdu_data->recv_cb_list) { if (entry->addr_check(eapol_pdu_data->interface_ptr, data->SrcAddr) >= 0) { + if (entry->filter_requsted && !ws_llc_eapol_relay_forward_filter(eapol_pdu_data->interface_ptr, data->SrcAddr, data->DSN, data->timestamp)) { + tr_info("EAPOL relay filter drop"); + return; + } + entry->receive(eapol_pdu_data->interface_ptr, data->SrcAddr, data->msdu_ptr, data->msduLength); break; } diff --git a/source/6LoWPAN/ws/ws_eapol_pdu.h b/source/6LoWPAN/ws/ws_eapol_pdu.h index 75f4ef4074..c385e9313c 100644 --- a/source/6LoWPAN/ws/ws_eapol_pdu.h +++ b/source/6LoWPAN/ws/ws_eapol_pdu.h @@ -99,6 +99,7 @@ typedef enum { typedef struct { eapol_pdu_recv_prior_t priority; /**< Priority: high, medium or low */ + bool filter_requsted: 1; /**< True when EAPOL temporary filter requsted, false for normal functionality */ ws_eapol_pdu_address_check *addr_check; /**< Address check callback */ ws_eapol_pdu_receive *receive; /**< PDU receive callback */ } eapol_pdu_recv_cb_data_t; diff --git a/source/6LoWPAN/ws/ws_eapol_relay.c b/source/6LoWPAN/ws/ws_eapol_relay.c index 367181bfcc..a5a83c3ec3 100644 --- a/source/6LoWPAN/ws/ws_eapol_relay.c +++ b/source/6LoWPAN/ws/ws_eapol_relay.c @@ -53,6 +53,7 @@ static void ws_eapol_relay_socket_cb(void *cb); static const eapol_pdu_recv_cb_data_t eapol_pdu_recv_cb_data = { .priority = EAPOL_PDU_RECV_LOW_PRIORITY, + .filter_requsted = true, .addr_check = ws_eapol_relay_eapol_pdu_address_check, .receive = ws_eapol_relay_eapol_pdu_receive }; diff --git a/source/6LoWPAN/ws/ws_empty_functions.c b/source/6LoWPAN/ws/ws_empty_functions.c index e03e811d63..f9e4e97195 100644 --- a/source/6LoWPAN/ws/ws_empty_functions.c +++ b/source/6LoWPAN/ws/ws_empty_functions.c @@ -25,6 +25,7 @@ #include "6LoWPAN/ws/ws_common.h" #include "ws_management_api.h" +#include "ns_time_api.h" #ifndef HAVE_WS int ws_management_node_init( @@ -392,4 +393,9 @@ int ws_statistics_stop(int8_t interface_id) return -1; } +void ns_time_api_system_time_callback_set(ns_time_api_system_time_callback callback) +{ + (void) callback; +} + #endif // no HAVE_WS diff --git a/source/6LoWPAN/ws/ws_llc.h b/source/6LoWPAN/ws/ws_llc.h index 33891f05a3..fd3b010501 100644 --- a/source/6LoWPAN/ws/ws_llc.h +++ b/source/6LoWPAN/ws/ws_llc.h @@ -78,11 +78,18 @@ typedef struct llc_neighbour_req { struct ws_neighbor_class_entry *ws_neighbor; /**< Wi-sun Neighbor information entry. */ } llc_neighbour_req_t; +typedef struct eapol_temporary_info_s { + uint8_t eapol_rx_relay_filter; /*!< seconds for dropping duplicate id */ + uint8_t last_rx_mac_sequency; /*!< Only compared when Timer is active */ + uint16_t eapol_timeout; /*!< EAPOL relay Temporary entry lifetime */ +} eapol_temporary_info_t; + /** * Neighbor temporary structure for storage FHSS data before create a real Neighbour info */ typedef struct ws_neighbor_temp_class_s { struct ws_neighbor_class_entry neigh_info_list; /*!< Allocated hopping info array*/ + eapol_temporary_info_t eapol_temp_info; uint8_t mac64[8]; uint8_t mpduLinkQuality; int8_t signal_dbm; @@ -217,6 +224,10 @@ void ws_llc_set_pan_information_pointer(struct protocol_interface_info_entry *in */ void ws_llc_hopping_schedule_config(struct protocol_interface_info_entry *interface, struct ws_hopping_schedule_s *hopping_schedule); +void ws_llc_timer_seconds(struct protocol_interface_info_entry *interface, uint16_t seconds_update); + +bool ws_llc_eapol_relay_forward_filter(struct protocol_interface_info_entry *interface, const uint8_t *joiner_eui64, uint8_t mac_sequency, uint32_t rx_timestamp); + ws_neighbor_temp_class_t *ws_llc_get_multicast_temp_entry(struct protocol_interface_info_entry *interface, const uint8_t *mac64); void ws_llc_free_multicast_temp_entry(struct protocol_interface_info_entry *interface, ws_neighbor_temp_class_t *neighbor); diff --git a/source/6LoWPAN/ws/ws_llc_data_service.c b/source/6LoWPAN/ws/ws_llc_data_service.c index adef723d0c..73f468a27c 100644 --- a/source/6LoWPAN/ws/ws_llc_data_service.c +++ b/source/6LoWPAN/ws/ws_llc_data_service.c @@ -36,6 +36,7 @@ #include "6LoWPAN/ws/ws_llc.h" #include "6LoWPAN/ws/ws_mpx_header.h" #include "6LoWPAN/ws/ws_pae_controller.h" +#include "6LoWPAN/ws/ws_cfg_settings.h" #include "Security/PANA/pana_eap_header.h" #include "Security/eapol/eapol_helper.h" #include "Service_Libs/etx/etx.h" @@ -78,10 +79,13 @@ typedef struct { typedef struct { uint8_t dst_address[8]; /**< Destination address */ + uint16_t pan_id; /**< Destination Pan-Id */ unsigned messsage_type: 3; /**< Frame type to UTT */ unsigned mpx_id: 5; /**< MPX sequence */ bool ack_requested: 1; /**< ACK requested */ + bool eapol_temporary: 1; /**< EAPOL TX entry index used */ unsigned dst_address_type: 2; /**< Destination address type */ + unsigned src_address_type: 2; /**< Source address type */ uint8_t msg_handle; /**< LLC genetaed unique MAC handle */ uint8_t mpx_user_handle; /**< This MPX user defined handle */ ns_ie_iovec_t ie_vector_list[3]; /**< IE vectors: 1 for Header's, 1 for Payload and for MPX payload */ @@ -95,12 +99,17 @@ typedef struct { typedef NS_LIST_HEAD(llc_message_t, link) llc_message_list_t; -#define MAX_NEIGH_TEMPORRY_MULTICAST_SIZE 5 +#define MAX_NEIGH_TEMPORARY_MULTICAST_SIZE 5 +#define MAX_NEIGH_TEMPORRY_EAPOL_SIZE 30 +#define MAX_NEIGH_TEMPORAY_LIST_SIZE (MAX_NEIGH_TEMPORARY_MULTICAST_SIZE + MAX_NEIGH_TEMPORRY_EAPOL_SIZE) typedef struct { - ws_neighbor_temp_class_t neighbour_temporary_table[MAX_NEIGH_TEMPORRY_MULTICAST_SIZE]; - ws_neighbor_temp_list_t active_temp_neigh; + ws_neighbor_temp_class_t neighbour_temporary_table[MAX_NEIGH_TEMPORAY_LIST_SIZE]; + ws_neighbor_temp_list_t active_multicast_temp_neigh; + ws_neighbor_temp_list_t active_eapol_temp_neigh; ws_neighbor_temp_list_t free_temp_neigh; + llc_message_list_t llc_eap_pending_list; /**< Active Message list */ + bool active_eapol_session: 1; /**< Indicating active EAPOL message */ } temp_entriest_t; typedef struct { @@ -131,7 +140,8 @@ static llc_message_t *llc_message_discover_by_mac_handle(uint8_t handle, llc_mes static llc_message_t *llc_message_discover_by_mpx_id(uint8_t handle, llc_message_list_t *list); static llc_message_t *llc_message_discover_mpx_user_id(uint8_t handle, uint16_t user_id, llc_message_list_t *list); static void llc_message_free(llc_message_t *message, llc_data_base_t *llc_base); -static llc_message_t *llc_message_allocate(uint16_t ie_buffer_size, llc_data_base_t *llc_base, bool mpx_user); +static void llc_message_id_allocate(llc_message_t *message, llc_data_base_t *llc_base, bool mpx_user); +static llc_message_t *llc_message_allocate(uint16_t ie_buffer_size, llc_data_base_t *llc_base); /** LLC interface sepesific local functions */ static llc_data_base_t *ws_llc_discover_by_interface(struct protocol_interface_info_entry *interface); @@ -151,6 +161,11 @@ static void ws_llc_mpx_init(mpx_class_t *mpx_class); static void ws_llc_temp_neigh_info_table_reset(temp_entriest_t *base); static ws_neighbor_temp_class_t *ws_allocate_multicast_temp_entry(temp_entriest_t *base, const uint8_t *mac64); +static ws_neighbor_temp_class_t *ws_llc_discover_eapol_temp_entry(temp_entriest_t *base, const uint8_t *mac64); +static void ws_llc_release_eapol_temp_entry(temp_entriest_t *base, const uint8_t *mac64); +static ws_neighbor_temp_class_t *ws_allocate_eapol_temp_entry(temp_entriest_t *base, const uint8_t *mac64); + +static void ws_llc_mpx_eapol_send(llc_data_base_t *base, llc_message_t *message); /** Discover Message by message handle id */ static llc_message_t *llc_message_discover_by_mac_handle(uint8_t handle, llc_message_list_t *list) @@ -202,18 +217,8 @@ static void llc_message_free(llc_message_t *message, llc_data_base_t *llc_base) llc_base->llc_message_list_size--; } -static llc_message_t *llc_message_allocate(uint16_t ie_buffer_size, llc_data_base_t *llc_base, bool mpx_user) +static void llc_message_id_allocate(llc_message_t *message, llc_data_base_t *llc_base, bool mpx_user) { - if (llc_base->llc_message_list_size >= LLC_MESSAGE_QUEUE_LIST_SIZE_MAX) { - return NULL; - } - - llc_message_t *message = ns_dyn_mem_temporary_alloc(sizeof(llc_message_t) + ie_buffer_size); - if (!message) { - return NULL; - } - message->ack_requested = false; - //Guarantee while (1) { if (llc_message_discover_by_mac_handle(llc_base->mac_handle_base, &llc_base->llc_message_list)) { @@ -237,8 +242,20 @@ static llc_message_t *llc_message_allocate(uint16_t ie_buffer_size, llc_data_bas if (mpx_user) { message->mpx_id = llc_base->mpx_data_base.mpx_id++; } - llc_base->llc_message_list_size++; - ns_list_add_to_end(&llc_base->llc_message_list, message); +} + +static llc_message_t *llc_message_allocate(uint16_t ie_buffer_size, llc_data_base_t *llc_base) +{ + if (llc_base->llc_message_list_size >= LLC_MESSAGE_QUEUE_LIST_SIZE_MAX) { + return NULL; + } + + llc_message_t *message = ns_dyn_mem_temporary_alloc(sizeof(llc_message_t) + ie_buffer_size); + if (!message) { + return NULL; + } + message->ack_requested = false; + message->eapol_temporary = false; return message; } @@ -375,12 +392,14 @@ static llc_data_base_t *ws_llc_base_allocate(void) } memset(base, 0, sizeof(llc_data_base_t)); memset(temp_entries, 0, sizeof(temp_entriest_t)); - ns_list_init(&temp_entries->active_temp_neigh); + ns_list_init(&temp_entries->active_multicast_temp_neigh); + ns_list_init(&temp_entries->active_eapol_temp_neigh); ns_list_init(&temp_entries->free_temp_neigh); - + ns_list_init(&temp_entries->llc_eap_pending_list); base->temp_entries = temp_entries; ns_list_init(&base->llc_message_list); + ns_list_add_to_end(&llc_data_base_list, base); return base; } @@ -403,6 +422,19 @@ static void ws_llc_mac_confirm_cb(const mac_api_t *api, const mcps_data_conf_t * uint8_t messsage_type = message->messsage_type; uint8_t mpx_user_handle = message->mpx_user_handle; + if (message->eapol_temporary) { + //Clear + ws_bootstrap_eapol_tx_temporary_clear(interface); + + if (data->status == MLME_SUCCESS || data->status == MLME_NO_DATA) { + //Update timeout + ws_neighbor_temp_class_t *temp_entry = ws_llc_discover_eapol_temp_entry(base->temp_entries, message->dst_address); + if (temp_entry) { + //Update Temporary Lifetime + temp_entry->eapol_temp_info.eapol_timeout = interface->ws_info->cfg->timing.temp_eapol_min_timeout + 1; + } + } + } //ETX update if (message->ack_requested && messsage_type == WS_FT_DATA) { llc_neighbour_req_t neighbor_info; @@ -417,7 +449,7 @@ static void ws_llc_mac_confirm_cb(const mac_api_t *api, const mcps_data_conf_t * } if (message->dst_address_type == MAC_ADDR_MODE_64_BIT && base->ws_neighbor_info_request_cb(interface, message->dst_address, &neighbor_info, false)) { - etx_transm_attempts_update(interface->id, 1 + data->tx_retries, success, neighbor_info.neighbor->index); + etx_transm_attempts_update(interface->id, 1 + data->tx_retries, success, neighbor_info.neighbor->index, neighbor_info.neighbor->mac64); //TODO discover RSL from Enchanced ACK Header IE elements ws_utt_ie_t ws_utt; if (ws_wh_utt_read(conf_data->headerIeList, conf_data->headerIeListLength, &ws_utt)) { @@ -450,6 +482,7 @@ static void ws_llc_mac_confirm_cb(const mac_api_t *api, const mcps_data_conf_t * mpx_user_id = MPX_LOWPAN_ENC_USER_ID; } else { mpx_user_id = MPX_KEY_MANAGEMENT_ENC_USER_ID; + base->temp_entries->active_eapol_session = false; } user_cb = ws_llc_mpx_user_discover(&base->mpx_data_base, mpx_user_id); @@ -459,6 +492,16 @@ static void ws_llc_mac_confirm_cb(const mac_api_t *api, const mcps_data_conf_t * data_conf.msduHandle = mpx_user_handle; user_cb->data_confirm(&base->mpx_data_base.mpx_api, &data_conf); } + + if (messsage_type == WS_FT_EAPOL) { + message = ns_list_get_first(&base->temp_entries->llc_eap_pending_list); + if (message) { + //Start A pending EAPOL + ns_list_remove(&base->temp_entries->llc_eap_pending_list, message); + ws_llc_mpx_eapol_send(base, message); + } + } + return; } //Async message Confirmation @@ -487,14 +530,299 @@ static void ws_llc_ack_data_req_ext(const mac_api_t *api, mcps_ack_data_payload_ ws_wh_rsl_write(ptr, ws_neighbor_class_rsl_from_dbm_calculate(rssi)); } -/** WS LLC MAC data extension indication */ -static void ws_llc_mac_indication_cb(const mac_api_t *api, const mcps_data_ind_t *data, const mcps_data_ie_list_t *ie_ext) + +static llc_data_base_t *ws_llc_mpx_frame_common_validates(const mac_api_t *api, const mcps_data_ind_t *data, ws_utt_ie_t ws_utt) { llc_data_base_t *base = ws_llc_discover_by_mac(api); + if (!base) { + return NULL; + } + + if (!base->ie_params.gtkhash && ws_utt.message_type == WS_FT_DATA) { + return NULL; + } + + if (data->SrcAddrMode != ADDR_802_15_4_LONG) { + return NULL; + } + + protocol_interface_info_entry_t *interface = base->interface_ptr; + + if (interface->mac_parameters->pan_id != 0xffff && data->SrcPANId != interface->mac_parameters->pan_id) { + //Drop wrong PAN-id messages in this phase. + return NULL; + } + + return base; + +} + +static mpx_user_t *ws_llc_mpx_header_parse(llc_data_base_t *base, const mcps_data_ie_list_t *ie_ext, mpx_msg_t *mpx_frame, mac_payload_IE_t *mpx_ie) +{ + + mpx_ie->id = MAC_PAYLOAD_MPX_IE_GROUP_ID; + if (mac_ie_payload_discover(ie_ext->payloadIeList, ie_ext->payloadIeListLength, mpx_ie) < 1) { + // NO MPX + return NULL; + } + //Validate MPX header + if (!ws_llc_mpx_header_frame_parse(mpx_ie->content_ptr, mpx_ie->length, mpx_frame)) { + return NULL; + } + + if (mpx_frame->transfer_type != MPX_FT_FULL_FRAME) { + return NULL; //Support only FULL Frame's + } + + // Discover MPX handler + mpx_user_t *user_cb = ws_llc_mpx_user_discover(&base->mpx_data_base, mpx_frame->multiplex_id); + if (!user_cb || !user_cb->data_ind) { + return NULL; + } + + return user_cb; +} + + +static void ws_llc_data_indication_cb(const mac_api_t *api, const mcps_data_ind_t *data, const mcps_data_ie_list_t *ie_ext, ws_utt_ie_t ws_utt) +{ + llc_data_base_t *base = ws_llc_mpx_frame_common_validates(api, data, ws_utt); if (!base) { return; } + //Discover MPX header and handler + mac_payload_IE_t mpx_ie; + mpx_msg_t mpx_frame; + mpx_user_t *user_cb = ws_llc_mpx_header_parse(base, ie_ext, &mpx_frame, &mpx_ie); + if (!user_cb) { + return; + } + + mac_payload_IE_t ws_wp_nested; + ws_us_ie_t us_ie; + bool us_ie_inline = false; + bool bs_ie_inline = false; + ws_wp_nested.id = WS_WP_NESTED_IE; + ws_bs_ie_t ws_bs_ie; + if (mac_ie_payload_discover(ie_ext->payloadIeList, ie_ext->payloadIeListLength, &ws_wp_nested) > 2) { + us_ie_inline = ws_wp_nested_us_read(ws_wp_nested.content_ptr, ws_wp_nested.length, &us_ie); + bs_ie_inline = ws_wp_nested_bs_read(ws_wp_nested.content_ptr, ws_wp_nested.length, &ws_bs_ie); + } + + 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 + return; + } + + //Free Old temporary entry + if (data->Key.SecurityLevel) { + ws_llc_release_eapol_temp_entry(base->temp_entries, data->SrcAddr); + } + + llc_neighbour_req_t neighbor_info; + bool multicast; + bool request_new_entry; + if (data->DstAddrMode == ADDR_802_15_4_LONG) { + multicast = false; + request_new_entry = us_ie_inline; + } else { + multicast = true; + request_new_entry = false; + } + + if (!base->ws_neighbor_info_request_cb(interface, data->SrcAddr, &neighbor_info, request_new_entry)) { + if (!multicast) { + //tr_debug("Drop message no neighbor"); + return; + } else { + //Allocate temporary entry + ws_neighbor_temp_class_t *temp_entry = ws_allocate_multicast_temp_entry(base->temp_entries, data->SrcAddr); + neighbor_info.ws_neighbor = &temp_entry->neigh_info_list; + //Storage Signal info for future ETX update possibility + temp_entry->mpduLinkQuality = data->mpduLinkQuality; + temp_entry->signal_dbm = data->signal_dbm; + } + } + + if (!multicast && !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); + } + //Update BS if it is part of message + if (bs_ie_inline) { + ws_neighbor_class_neighbor_broadcast_schedule_set(neighbor_info.ws_neighbor, &ws_bs_ie); + } + + //Update BT if it is part of message + ws_bt_ie_t ws_bt; + if (ws_wh_bt_read(ie_ext->headerIeList, ie_ext->headerIeListLength, &ws_bt)) { + ws_neighbor_class_neighbor_broadcast_time_info_update(neighbor_info.ws_neighbor, &ws_bt, data->timestamp); + if (neighbor_info.neighbor && neighbor_info.neighbor->link_role == PRIORITY_PARENT_NEIGHBOUR) { + ns_fhss_ws_set_parent(interface->ws_info->fhss_api, neighbor_info.neighbor->mac64, &neighbor_info.ws_neighbor->fhss_data.bc_timing_info, false); + } + } + + if (data->DstAddrMode == ADDR_802_15_4_LONG) { + neighbor_info.ws_neighbor->unicast_data_rx = true; + } + + // Calculate RSL for all UDATA packages heard + ws_neighbor_class_rsl_in_calculate(neighbor_info.ws_neighbor, data->signal_dbm); + + if (neighbor_info.neighbor) { + //Refresh ETX dbm + etx_lqi_dbm_update(interface->id, data->mpduLinkQuality, data->signal_dbm, neighbor_info.neighbor->index, neighbor_info.neighbor->mac64); + if (data->Key.SecurityLevel) { + //SET trusted state + mac_neighbor_table_trusted_neighbor(mac_neighbor_info(interface), neighbor_info.neighbor, true); + } + } + + mcps_data_ind_t data_ind = *data; + if (!neighbor_info.neighbor) { + data_ind.Key.SecurityLevel = 0; //Mark unknow device + } + data_ind.msdu_ptr = mpx_frame.frame_ptr; + data_ind.msduLength = mpx_frame.frame_length; + user_cb->data_ind(&base->mpx_data_base.mpx_api, &data_ind); + +} + +static void ws_llc_eapol_indication_cb(const mac_api_t *api, const mcps_data_ind_t *data, const mcps_data_ie_list_t *ie_ext, ws_utt_ie_t ws_utt) +{ + llc_data_base_t *base = ws_llc_mpx_frame_common_validates(api, data, ws_utt); + if (!base) { + return; + } + + if (data->DstAddrMode != ADDR_802_15_4_LONG) { + return; + } + + //Discover MPX header and handler + mac_payload_IE_t mpx_ie; + mpx_msg_t mpx_frame; + mpx_user_t *user_cb = ws_llc_mpx_header_parse(base, ie_ext, &mpx_frame, &mpx_ie); + if (!user_cb) { + return; + } + + mac_payload_IE_t ws_wp_nested; + ws_us_ie_t us_ie; + bool us_ie_inline = false; + bool bs_ie_inline = false; + ws_wp_nested.id = WS_WP_NESTED_IE; + ws_bs_ie_t ws_bs_ie; + if (mac_ie_payload_discover(ie_ext->payloadIeList, ie_ext->payloadIeListLength, &ws_wp_nested) > 2) { + us_ie_inline = ws_wp_nested_us_read(ws_wp_nested.content_ptr, ws_wp_nested.length, &us_ie); + bs_ie_inline = ws_wp_nested_bs_read(ws_wp_nested.content_ptr, ws_wp_nested.length, &ws_bs_ie); + } + + 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 + return; + } + + llc_neighbour_req_t neighbor_info; + + if (!base->ws_neighbor_info_request_cb(interface, data->SrcAddr, &neighbor_info, false)) { + //Allocate temporary entry + ws_neighbor_temp_class_t *temp_entry = ws_allocate_eapol_temp_entry(base->temp_entries, data->SrcAddr); + if (!temp_entry) { + tr_warn("EAPOL temp pool empty"); + return; + } + //Update Temporary Lifetime + temp_entry->eapol_temp_info.eapol_timeout = interface->ws_info->cfg->timing.temp_eapol_min_timeout + 1; + + neighbor_info.ws_neighbor = &temp_entry->neigh_info_list; + //Storage Signal info for future ETX update possibility + temp_entry->mpduLinkQuality = data->mpduLinkQuality; + temp_entry->signal_dbm = data->signal_dbm; + } + 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); + } + //Update BS if it is part of message + if (bs_ie_inline) { + ws_neighbor_class_neighbor_broadcast_schedule_set(neighbor_info.ws_neighbor, &ws_bs_ie); + } + + //Discover and write Auhtenticator EUI-64 + if (ws_wh_ea_read(ie_ext->headerIeList, ie_ext->headerIeListLength, auth_eui64)) { + ws_pae_controller_border_router_addr_write(base->interface_ptr, auth_eui64); + } + + //Update BT if it is part of message + ws_bt_ie_t ws_bt; + if (ws_wh_bt_read(ie_ext->headerIeList, ie_ext->headerIeListLength, &ws_bt)) { + ws_neighbor_class_neighbor_broadcast_time_info_update(neighbor_info.ws_neighbor, &ws_bt, data->timestamp); + if (neighbor_info.neighbor) { + ws_bootstrap_eapol_parent_synch(interface, &neighbor_info); + } + } + + + mcps_data_ind_t data_ind = *data; + data_ind.msdu_ptr = mpx_frame.frame_ptr; + data_ind.msduLength = mpx_frame.frame_length; + user_cb->data_ind(&base->mpx_data_base.mpx_api, &data_ind); +} + +static void ws_llc_asynch_indication(const mac_api_t *api, const mcps_data_ind_t *data, const mcps_data_ie_list_t *ie_ext, ws_utt_ie_t ws_utt) +{ + llc_data_base_t *base = ws_llc_discover_by_mac(api); + if (!base || !base->asynch_ind) { + return; + } + + //Asynch Message + + mac_payload_IE_t ws_wp_nested; + + ws_wp_nested.id = WS_WP_NESTED_IE; + if (mac_ie_payload_discover(ie_ext->payloadIeList, ie_ext->payloadIeListLength, &ws_wp_nested) < 2) { + // NO WS_WP_NESTED_IE Payload + return; + } + + switch (ws_utt.message_type) { + case WS_FT_PAN_ADVERT: + case WS_FT_PAN_CONF: + case WS_FT_PAN_CONF_SOL: + ws_llc_release_eapol_temp_entry(base->temp_entries, data->SrcAddr); + break; + default: + break; + } + + mcps_data_ie_list_t asynch_ie_list; + asynch_ie_list.headerIeList = ie_ext->headerIeList, + asynch_ie_list.headerIeListLength = ie_ext->headerIeListLength; + asynch_ie_list.payloadIeList = ws_wp_nested.content_ptr; + asynch_ie_list.payloadIeListLength = ws_wp_nested.length; + base->asynch_ind(base->interface_ptr, data, &asynch_ie_list, ws_utt.message_type); +} + +/** WS LLC MAC data extension indication */ +static void ws_llc_mac_indication_cb(const mac_api_t *api, const mcps_data_ind_t *data, const mcps_data_ie_list_t *ie_ext) +{ + + //Discover Header WH_IE_UTT_TYPE ws_utt_ie_t ws_utt; if (!ws_wh_utt_read(ie_ext->headerIeList, ie_ext->headerIeListLength, &ws_utt)) { @@ -502,166 +830,20 @@ static void ws_llc_mac_indication_cb(const mac_api_t *api, const mcps_data_ind_t return; } - protocol_interface_info_entry_t *interface = base->interface_ptr; - if (!base->ie_params.gtkhash && ws_utt.message_type == WS_FT_DATA) { + if (ws_utt.message_type < WS_FT_DATA) { + ws_llc_asynch_indication(api, data, ie_ext, ws_utt); return; } - //Discover 2 Payload Heder - if (ws_utt.message_type == WS_FT_DATA || ws_utt.message_type == WS_FT_EAPOL) { - - if (data->SrcAddrMode != ADDR_802_15_4_LONG) { - return; - } - - if (interface->mac_parameters->pan_id != 0xffff && data->SrcPANId != interface->mac_parameters->pan_id) { - //Drop wrong PAN-id messages in this phase. - return; - } - - mpx_user_t *user_cb; - mac_payload_IE_t mpx_ie; - mpx_ie.id = MAC_PAYLOAD_MPX_IE_GROUP_ID; - if (mac_ie_payload_discover(ie_ext->payloadIeList, ie_ext->payloadIeListLength, &mpx_ie) < 1) { - // NO MPX - return; - } - //Validate MPX header - mpx_msg_t mpx_frame; - if (!ws_llc_mpx_header_frame_parse(mpx_ie.content_ptr, mpx_ie.length, &mpx_frame)) { - return; - } - - if (mpx_frame.transfer_type != MPX_FT_FULL_FRAME) { - return; //Support only FULL Frame's - } - - mac_payload_IE_t ws_wp_nested; - ws_us_ie_t us_ie; - bool us_ie_inline = false; - bool bs_ie_inline = false; - ws_wp_nested.id = WS_WP_NESTED_IE; - ws_bs_ie_t ws_bs_ie; - if (mac_ie_payload_discover(ie_ext->payloadIeList, ie_ext->payloadIeListLength, &ws_wp_nested) > 2) { - us_ie_inline = ws_wp_nested_us_read(ws_wp_nested.content_ptr, ws_wp_nested.length, &us_ie); - bs_ie_inline = ws_wp_nested_bs_read(ws_wp_nested.content_ptr, ws_wp_nested.length, &ws_bs_ie); - } - - //Validate Unicast shedule Channel Plan - if (us_ie_inline && !ws_bootstrap_validate_channel_plan(&us_ie, interface)) { - //Channel plan configuration mismatch - return; - } - - llc_neighbour_req_t neighbor_info; - bool multicast; - bool request_new_entry; - if (data->DstAddrMode == ADDR_802_15_4_LONG) { - multicast = false; - request_new_entry = us_ie_inline; - } else { - multicast = true; - request_new_entry = false; - } - - if (!base->ws_neighbor_info_request_cb(interface, data->SrcAddr, &neighbor_info, request_new_entry)) { - if (!multicast || ws_utt.message_type == WS_FT_EAPOL) { - //tr_debug("Drop message no neighbor"); - return; - } else { - //Allocate temporary entry - ws_neighbor_temp_class_t *temp_entry = ws_allocate_multicast_temp_entry(base->temp_entries, data->SrcAddr); - neighbor_info.ws_neighbor = &temp_entry->neigh_info_list; - //Storage Signal info for future ETX update possibility - temp_entry->mpduLinkQuality = data->mpduLinkQuality; - temp_entry->signal_dbm = data->signal_dbm; - } - } - - 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); - } - //Update BS if it is part of message - if (bs_ie_inline) { - ws_neighbor_class_neighbor_broadcast_schedule_set(neighbor_info.ws_neighbor, &ws_bs_ie); - } - - if (ws_utt.message_type == WS_FT_EAPOL) { - uint8_t auth_eui64[8]; - //Discover and write Auhtenticator EUI-64 - if (ws_wh_ea_read(ie_ext->headerIeList, ie_ext->headerIeListLength, auth_eui64)) { - ws_pae_controller_border_router_addr_write(base->interface_ptr, auth_eui64); - } - } - - - //Update BT if it is part of message - ws_bt_ie_t ws_bt; - if (ws_wh_bt_read(ie_ext->headerIeList, ie_ext->headerIeListLength, &ws_bt)) { - ws_neighbor_class_neighbor_broadcast_time_info_update(neighbor_info.ws_neighbor, &ws_bt, data->timestamp); - if (neighbor_info.neighbor) { - if (neighbor_info.neighbor->link_role == PRIORITY_PARENT_NEIGHBOUR) { - // We have broadcast schedule set up set the broadcast parent schedule - ns_fhss_ws_set_parent(interface->ws_info->fhss_api, neighbor_info.neighbor->mac64, &neighbor_info.ws_neighbor->fhss_data.bc_timing_info, false); - } else if (ws_utt.message_type == WS_FT_EAPOL) { - ws_bootstrap_eapol_parent_synch(interface, &neighbor_info); - } - } - } - - if (ws_utt.message_type == WS_FT_DATA) { - - if (data->DstAddrMode == ADDR_802_15_4_LONG) { - neighbor_info.ws_neighbor->unicast_data_rx = true; - } - - // Calculate RSL for all UDATA packages heard - ws_neighbor_class_rsl_in_calculate(neighbor_info.ws_neighbor, data->signal_dbm); - - if (neighbor_info.neighbor) { - //Refresh ETX dbm - etx_lqi_dbm_update(interface->id, data->mpduLinkQuality, data->signal_dbm, neighbor_info.neighbor->index); - if (data->Key.SecurityLevel) { - //SET trusted state - mac_neighbor_table_trusted_neighbor(mac_neighbor_info(interface), neighbor_info.neighbor, true); - } - } - } - - - // Discover MPX - user_cb = ws_llc_mpx_user_discover(&base->mpx_data_base, mpx_frame.multiplex_id); - if (user_cb && user_cb->data_ind) { - mcps_data_ind_t data_ind = *data; - if (!neighbor_info.neighbor) { - data_ind.Key.SecurityLevel = 0; //Mark unknow device - } - data_ind.msdu_ptr = mpx_frame.frame_ptr; - data_ind.msduLength = mpx_frame.frame_length; - user_cb->data_ind(&base->mpx_data_base.mpx_api, &data_ind); - } + if (ws_utt.message_type == WS_FT_DATA) { + ws_llc_data_indication_cb(api, data, ie_ext, ws_utt); return; } - //Asynch Message - if (ws_utt.message_type < WS_FT_DATA && base->asynch_ind) { - mac_payload_IE_t ws_wp_nested; - - ws_wp_nested.id = WS_WP_NESTED_IE; - if (mac_ie_payload_discover(ie_ext->payloadIeList, ie_ext->payloadIeListLength, &ws_wp_nested) < 2) { - // NO WS_WP_NESTED_IE Payload - return; - } - - mcps_data_ie_list_t asynch_ie_list; - asynch_ie_list.headerIeList = ie_ext->headerIeList, - asynch_ie_list.headerIeListLength = ie_ext->headerIeListLength; - asynch_ie_list.payloadIeList = ws_wp_nested.content_ptr; - asynch_ie_list.payloadIeListLength = ws_wp_nested.length; - base->asynch_ind(interface, data, &asynch_ie_list, ws_utt.message_type); + if (ws_utt.message_type == WS_FT_EAPOL) { + ws_llc_eapol_indication_cb(api, data, ie_ext, ws_utt); + return; } - } static uint16_t ws_mpx_header_size_get(llc_data_base_t *base, uint16_t user_id) @@ -720,18 +902,21 @@ static bool ws_eapol_handshake_first_msg(uint8_t *pdu, uint16_t length, protocol return false; } -static void ws_llc_mpx_data_request(const mpx_api_t *api, const struct mcps_data_req_s *data, uint16_t user_id) +static void ws_llc_lowpan_mpx_header_set(llc_message_t *message, uint16_t user_id) { - llc_data_base_t *base = ws_llc_discover_by_mpx(api); - if (!base) { - return; - } - - mpx_user_t *user_cb = ws_llc_mpx_user_discover(&base->mpx_data_base, user_id); - if (!user_cb || !user_cb->data_confirm || !user_cb->data_ind) { - return; - } + uint8_t *ptr = (uint8_t *)message->ie_vector_list[1].ieBase; + ptr += message->ie_vector_list[1].iovLen; + ptr = mac_ie_payload_base_write(ptr, MAC_PAYLOAD_MPX_IE_GROUP_ID, message->ie_vector_list[2].iovLen + 3); + mpx_msg_t mpx_header; + mpx_header.transfer_type = MPX_FT_FULL_FRAME; + mpx_header.transaction_id = message->mpx_id; + mpx_header.multiplex_id = user_id; + ptr = ws_llc_mpx_header_write(ptr, &mpx_header); + message->ie_vector_list[1].iovLen = ptr - (uint8_t *)message->ie_vector_list[1].ieBase; +} +static void ws_llc_lowpan_mpx_data_request(llc_data_base_t *base, mpx_user_t *user_cb, const struct mcps_data_req_s *data) +{ wh_ie_sub_list_t ie_header_mask; memset(&ie_header_mask, 0, sizeof(wh_ie_sub_list_t)); @@ -739,25 +924,17 @@ static void ws_llc_mpx_data_request(const mpx_api_t *api, const struct mcps_data memset(&nested_wp_id, 0, sizeof(wp_nested_ie_sub_list_t)); ie_header_mask.utt_ie = true; - if (user_id == MPX_LOWPAN_ENC_USER_ID) { - ie_header_mask.bt_ie = true; - if (base->ie_params.vendor_header_length) { - ie_header_mask.vh_ie = true; - } + ie_header_mask.bt_ie = true; + if (base->ie_params.vendor_header_length) { + ie_header_mask.vh_ie = true; + } - if (base->ie_params.vendor_payload_length) { - nested_wp_id.vp_ie = true; - } - - if (!data->TxAckReq) { - nested_wp_id.bs_ie = true; - } - - } else if (user_id == MPX_KEY_MANAGEMENT_ENC_USER_ID) { - ie_header_mask.bt_ie = ws_eapol_relay_state_active(base->interface_ptr); - ie_header_mask.ea_ie = ws_eapol_handshake_first_msg(data->msdu, data->msduLength, base->interface_ptr); - nested_wp_id.bs_ie = ie_header_mask.ea_ie; + if (base->ie_params.vendor_payload_length) { + nested_wp_id.vp_ie = true; + } + if (!data->TxAckReq) { + nested_wp_id.bs_ie = true; } nested_wp_id.us_ie = true; @@ -773,7 +950,7 @@ static void ws_llc_mpx_data_request(const mpx_api_t *api, const struct mcps_data over_head_size += 5; //MPX FuLL frame 3 bytes + IE header 2 bytes //Allocate Message - llc_message_t *message = llc_message_allocate(over_head_size, base, true); + llc_message_t *message = llc_message_allocate(over_head_size, base); if (!message) { mcps_data_conf_t data_conf; memset(&data_conf, 0, sizeof(mcps_data_conf_t)); @@ -782,6 +959,12 @@ static void ws_llc_mpx_data_request(const mpx_api_t *api, const struct mcps_data user_cb->data_confirm(&base->mpx_data_base.mpx_api, &data_conf); return; } + + //Add To active list + llc_message_id_allocate(message, base, true); + base->llc_message_list_size++; + ns_list_add_to_end(&base->llc_message_list, message); + mcps_data_req_t data_req; message->mpx_user_handle = data->msduHandle; message->ack_requested = data->TxAckReq; @@ -802,11 +985,7 @@ static void ws_llc_mpx_data_request(const mpx_api_t *api, const struct mcps_data } uint8_t *ptr = ws_message_buffer_ptr_get(message); - if (user_id == MPX_LOWPAN_ENC_USER_ID) { - message->messsage_type = WS_FT_DATA; - } else { - message->messsage_type = WS_FT_EAPOL; - } + message->messsage_type = WS_FT_DATA; message->ie_vector_list[0].ieBase = ptr; //Write UTT @@ -816,19 +995,149 @@ static void ws_llc_mpx_data_request(const mpx_api_t *api, const struct mcps_data ptr = ws_wh_bt_write(ptr); } - if (user_id == MPX_LOWPAN_ENC_USER_ID) { - if (ie_header_mask.vh_ie) { - ptr = ws_wh_vh_write(ptr, base->ie_params.vendor_header_data, base->ie_params.vendor_header_length); - } - } else if (user_id == MPX_KEY_MANAGEMENT_ENC_USER_ID) { - if (ie_header_mask.ea_ie) { - uint8_t eapol_auth_eui64[8]; - ws_pae_controller_border_router_addr_read(base->interface_ptr, eapol_auth_eui64); - ptr = ws_wh_ea_write(ptr, eapol_auth_eui64); + if (ie_header_mask.vh_ie) { + ptr = ws_wh_vh_write(ptr, base->ie_params.vendor_header_data, base->ie_params.vendor_header_length); + } + + message->ie_vector_list[0].iovLen = ie_header_length; + message->ie_ext.headerIeVectorList = &message->ie_vector_list[0]; + message->ie_ext.headerIovLength = 1; + message->ie_ext.payloadIeVectorList = &message->ie_vector_list[1]; + message->ie_ext.payloadIovLength = 2; + message->ie_vector_list[1].ieBase = ptr; + + if (nested_ie_length) { + ptr = ws_wp_base_write(ptr, nested_ie_length); + //Write unicast schedule + ptr = ws_wp_nested_hopping_schedule_write(ptr, base->ie_params.hopping_schedule, true); + + if (nested_wp_id.bs_ie) { + //Write Broadcastcast schedule + ptr = ws_wp_nested_hopping_schedule_write(ptr, base->ie_params.hopping_schedule, false); } } + // SET Payload IE Length + message->ie_vector_list[1].iovLen = ptr - (uint8_t *)message->ie_vector_list[1].ieBase; + message->ie_vector_list[2].ieBase = data->msdu; + message->ie_vector_list[2].iovLen = data->msduLength; + + ws_llc_lowpan_mpx_header_set(message, MPX_LOWPAN_ENC_USER_ID); + + base->interface_ptr->mac_api->mcps_data_req_ext(base->interface_ptr->mac_api, &data_req, &message->ie_ext, NULL); +} + +static bool ws_llc_eapol_temp_entry_set(llc_data_base_t *base, const uint8_t *mac64) +{ + //Discover Temporary entry + ws_neighbor_temp_class_t *temp_neigh = ws_llc_discover_eapol_temp_entry(base->temp_entries, mac64); + + if (!temp_neigh) { + return false; + } + ws_neighbor_class_entry_t *entry = ws_bootstrap_eapol_tx_temporary_set(base->interface_ptr, mac64); + if (!entry) { + return false; + } + *entry = temp_neigh->neigh_info_list; + return true; + +} + + +static void ws_llc_eapol_data_req_init(mcps_data_req_t *data_req, llc_message_t *message) +{ + memset(data_req, 0, sizeof(mcps_data_req_t)); + data_req->TxAckReq = message->ack_requested; + data_req->DstPANId = message->pan_id; + data_req->SrcAddrMode = message->src_address_type; + if (!data_req->TxAckReq) { + data_req->PanIdSuppressed = false; + data_req->DstAddrMode = MAC_ADDR_MODE_NONE; + } else { + data_req->PanIdSuppressed = true; + data_req->DstAddrMode = message->dst_address_type; + memcpy(data_req->DstAddr, message->dst_address, 8); + } + data_req->msdu = NULL; + data_req->msduLength = 0; + data_req->msduHandle = message->msg_handle; + + ws_llc_lowpan_mpx_header_set(message, MPX_KEY_MANAGEMENT_ENC_USER_ID); +} + +static void ws_llc_mpx_eapol_send(llc_data_base_t *base, llc_message_t *message) +{ + mcps_data_req_t data_req; + llc_message_id_allocate(message, base, true); + base->llc_message_list_size++; + ns_list_add_to_end(&base->llc_message_list, message); + message->eapol_temporary = ws_llc_eapol_temp_entry_set(base, message->dst_address); + ws_llc_eapol_data_req_init(&data_req, message); + base->temp_entries->active_eapol_session = true; + base->interface_ptr->mac_api->mcps_data_req_ext(base->interface_ptr->mac_api, &data_req, &message->ie_ext, NULL); +} + + +static void ws_llc_mpx_eapol_request(llc_data_base_t *base, mpx_user_t *user_cb, const struct mcps_data_req_s *data) +{ + wh_ie_sub_list_t ie_header_mask; + memset(&ie_header_mask, 0, sizeof(wh_ie_sub_list_t)); + + wp_nested_ie_sub_list_t nested_wp_id; + memset(&nested_wp_id, 0, sizeof(wp_nested_ie_sub_list_t)); + ie_header_mask.utt_ie = true; + ie_header_mask.bt_ie = ws_eapol_relay_state_active(base->interface_ptr); + ie_header_mask.ea_ie = ws_eapol_handshake_first_msg(data->msdu, data->msduLength, base->interface_ptr); + nested_wp_id.bs_ie = ie_header_mask.ea_ie; + + + nested_wp_id.us_ie = true; + + uint16_t ie_header_length = ws_wh_headers_length(ie_header_mask, &base->ie_params); + uint16_t nested_ie_length = ws_wp_nested_message_length(nested_wp_id, &base->ie_params); + + uint16_t over_head_size = ie_header_length; + if (nested_ie_length) { + over_head_size += nested_ie_length + 2; + } + //Mpx header size + over_head_size += 5; //MPX FuLL frame 3 bytes + IE header 2 bytes + + //Allocate Message + llc_message_t *message = llc_message_allocate(over_head_size, base); + if (!message) { + mcps_data_conf_t data_conf; + memset(&data_conf, 0, sizeof(mcps_data_conf_t)); + data_conf.msduHandle = data->msduHandle; + data_conf.status = MLME_TRANSACTION_OVERFLOW; + user_cb->data_confirm(&base->mpx_data_base.mpx_api, &data_conf); + return; + } + message->mpx_user_handle = data->msduHandle; + message->ack_requested = data->TxAckReq; + + message->src_address_type = data->SrcAddrMode; + memcpy(message->dst_address, data->DstAddr, 8); + message->dst_address_type = data->DstAddrMode; + message->pan_id = data->DstPANId; + message->messsage_type = WS_FT_EAPOL; + + uint8_t *ptr = ws_message_buffer_ptr_get(message); + + message->ie_vector_list[0].ieBase = ptr; + //Write UTT + ptr = ws_wh_utt_write(ptr, message->messsage_type); + if (ie_header_mask.bt_ie) { + ptr = ws_wh_bt_write(ptr); + } + + if (ie_header_mask.ea_ie) { + uint8_t eapol_auth_eui64[8]; + ws_pae_controller_border_router_addr_read(base->interface_ptr, eapol_auth_eui64); + ptr = ws_wh_ea_write(ptr, eapol_auth_eui64); + } message->ie_vector_list[0].iovLen = ie_header_length; message->ie_ext.headerIeVectorList = &message->ie_vector_list[0]; @@ -848,18 +1157,38 @@ static void ws_llc_mpx_data_request(const mpx_api_t *api, const struct mcps_data } } - - ptr = mac_ie_payload_base_write(ptr, MAC_PAYLOAD_MPX_IE_GROUP_ID, data->msduLength + 3); - mpx_msg_t mpx_header; - mpx_header.transfer_type = MPX_FT_FULL_FRAME; - mpx_header.transaction_id = message->mpx_id; - mpx_header.multiplex_id = user_id; - ptr = ws_llc_mpx_header_write(ptr, &mpx_header); + // SET Payload IE Length message->ie_vector_list[1].iovLen = ptr - (uint8_t *)message->ie_vector_list[1].ieBase; message->ie_vector_list[2].ieBase = data->msdu; message->ie_vector_list[2].iovLen = data->msduLength; - base->interface_ptr->mac_api->mcps_data_req_ext(base->interface_ptr->mac_api, &data_req, &message->ie_ext, NULL); + if (base->temp_entries->active_eapol_session) { + //Move to pending list + ns_list_add_to_end(&base->temp_entries->llc_eap_pending_list, message); + } else { + ws_llc_mpx_eapol_send(base, message); + } + +} + + +static void ws_llc_mpx_data_request(const mpx_api_t *api, const struct mcps_data_req_s *data, uint16_t user_id) +{ + llc_data_base_t *base = ws_llc_discover_by_mpx(api); + if (!base) { + return; + } + + mpx_user_t *user_cb = ws_llc_mpx_user_discover(&base->mpx_data_base, user_id); + if (!user_cb || !user_cb->data_confirm || !user_cb->data_ind) { + return; + } + + if (user_id == MPX_KEY_MANAGEMENT_ENC_USER_ID) { + ws_llc_mpx_eapol_request(base, user_cb, data); + } else if (user_id == MPX_LOWPAN_ENC_USER_ID) { + ws_llc_lowpan_mpx_data_request(base, user_cb, data); + } } @@ -932,6 +1261,12 @@ static void ws_llc_clean(llc_data_base_t *base) base->interface_ptr->mac_api->mcps_purge_req(base->interface_ptr->mac_api, &purge_req); } + + ns_list_foreach_safe(llc_message_t, message, &base->temp_entries->llc_eap_pending_list) { + ns_list_remove(&base->temp_entries->llc_eap_pending_list, message); + ns_dyn_mem_free(message); + } + base->temp_entries->active_eapol_session = false; memset(&base->ie_params, 0, sizeof(llc_ie_params_t)); ws_llc_temp_neigh_info_table_reset(base->temp_entries); @@ -940,18 +1275,19 @@ static void ws_llc_clean(llc_data_base_t *base) static void ws_llc_temp_neigh_info_table_reset(temp_entriest_t *base) { //Empty active list - ns_list_init(&base->active_temp_neigh); + ns_list_init(&base->active_multicast_temp_neigh); + ns_list_init(&base->active_eapol_temp_neigh); ns_list_init(&base->free_temp_neigh); //Add to free list to full - for (int i = 0; i < MAX_NEIGH_TEMPORRY_MULTICAST_SIZE; i++) { + for (int i = 0; i < MAX_NEIGH_TEMPORAY_LIST_SIZE; i++) { ns_list_add_to_end(&base->free_temp_neigh, &base->neighbour_temporary_table[i]); } } -static ws_neighbor_temp_class_t *ws_llc_discover_temp_entry(temp_entriest_t *base, const uint8_t *mac64) +static ws_neighbor_temp_class_t *ws_llc_discover_mc_temp_entry(temp_entriest_t *base, const uint8_t *mac64) { - ns_list_foreach_safe(ws_neighbor_temp_class_t, entry, &base->active_temp_neigh) { + ns_list_foreach(ws_neighbor_temp_class_t, entry, &base->active_multicast_temp_neigh) { if (memcmp(entry->mac64, mac64, 8) == 0) { return entry; } @@ -959,6 +1295,27 @@ static ws_neighbor_temp_class_t *ws_llc_discover_temp_entry(temp_entriest_t *bas return NULL; } +static ws_neighbor_temp_class_t *ws_llc_discover_eapol_temp_entry(temp_entriest_t *base, const uint8_t *mac64) +{ + ns_list_foreach(ws_neighbor_temp_class_t, entry, &base->active_eapol_temp_neigh) { + if (memcmp(entry->mac64, mac64, 8) == 0) { + return entry; + } + } + return NULL; +} + +static void ws_llc_release_eapol_temp_entry(temp_entriest_t *base, const uint8_t *mac64) +{ + ws_neighbor_temp_class_t *neighbor = ws_llc_discover_eapol_temp_entry(base, mac64); + if (!neighbor) { + return; + } + + ns_list_remove(&base->active_eapol_temp_neigh, neighbor); + ns_list_add_to_end(&base->free_temp_neigh, neighbor); +} + ws_neighbor_temp_class_t *ws_llc_get_multicast_temp_entry(protocol_interface_info_entry_t *interface, const uint8_t *mac64) { llc_data_base_t *base = ws_llc_discover_by_interface(interface); @@ -966,38 +1323,72 @@ ws_neighbor_temp_class_t *ws_llc_get_multicast_temp_entry(protocol_interface_inf return NULL; } - return ws_llc_discover_temp_entry(base->temp_entries, mac64); + return ws_llc_discover_mc_temp_entry(base->temp_entries, mac64); } +static void ws_init_temporary_neigh_data(ws_neighbor_temp_class_t *entry, const uint8_t *mac64) +{ + //Clear Old data + memset(&entry->neigh_info_list, 0, sizeof(ws_neighbor_class_entry_t)); + entry->neigh_info_list.rsl_in = RSL_UNITITIALIZED; + entry->neigh_info_list.rsl_out = RSL_UNITITIALIZED; + memcpy(entry->mac64, mac64, 8); + entry->eapol_temp_info.eapol_rx_relay_filter = 0; +} + static ws_neighbor_temp_class_t *ws_allocate_multicast_temp_entry(temp_entriest_t *base, const uint8_t *mac64) { - ws_neighbor_temp_class_t *entry = ws_llc_discover_temp_entry(base, mac64); + ws_neighbor_temp_class_t *entry = ws_llc_discover_mc_temp_entry(base, mac64); if (entry) { - ns_list_remove(&base->active_temp_neigh, entry); - ns_list_add_to_start(&base->active_temp_neigh, entry); + ns_list_remove(&base->active_multicast_temp_neigh, entry); + ns_list_add_to_start(&base->active_multicast_temp_neigh, entry); return entry; } - entry = ns_list_get_first(&base->free_temp_neigh); + if (ns_list_count(&base->active_multicast_temp_neigh) < MAX_NEIGH_TEMPORARY_MULTICAST_SIZE) { + entry = ns_list_get_first(&base->free_temp_neigh); + } if (entry) { ns_list_remove(&base->free_temp_neigh, entry); } else { //Replace last entry and put it to first - entry = ns_list_get_last(&base->active_temp_neigh); - ns_list_remove(&base->active_temp_neigh, entry); + entry = ns_list_get_last(&base->active_multicast_temp_neigh); + ns_list_remove(&base->active_multicast_temp_neigh, entry); } //Add to list - ns_list_add_to_start(&base->active_temp_neigh, entry); + ns_list_add_to_start(&base->active_multicast_temp_neigh, entry); //Clear Old data - memset(&entry->neigh_info_list, 0, sizeof(ws_neighbor_class_entry_t)); - entry->neigh_info_list.rsl_in = RSL_UNITITIALIZED; - entry->neigh_info_list.rsl_out = RSL_UNITITIALIZED; - memcpy(entry->mac64, mac64, 8); + ws_init_temporary_neigh_data(entry, mac64); + return entry; +} + +static ws_neighbor_temp_class_t *ws_allocate_eapol_temp_entry(temp_entriest_t *base, const uint8_t *mac64) +{ + + ws_neighbor_temp_class_t *entry = ws_llc_discover_eapol_temp_entry(base, mac64); + if (entry) { + //TODO referesh Timer here + return entry; + } + + if (ns_list_count(&base->active_eapol_temp_neigh) < MAX_NEIGH_TEMPORRY_EAPOL_SIZE) { + entry = ns_list_get_first(&base->free_temp_neigh); + } + + if (!entry) { + return NULL; + } + + ns_list_remove(&base->free_temp_neigh, entry); + //Add to list + ns_list_add_to_start(&base->active_eapol_temp_neigh, entry); + //Clear Old data + ws_init_temporary_neigh_data(entry, mac64); return entry; } @@ -1007,7 +1398,7 @@ void ws_llc_free_multicast_temp_entry(protocol_interface_info_entry_t *cur, ws_n if (!base) { return; } - ns_list_remove(&base->temp_entries->active_temp_neigh, neighbor); + ns_list_remove(&base->temp_entries->active_multicast_temp_neigh, neighbor); ns_list_add_to_end(&base->temp_entries->free_temp_neigh, neighbor); } @@ -1096,15 +1487,21 @@ int8_t ws_llc_asynch_request(struct protocol_interface_info_entry *interface, as } //Allocate LLC message pointer - llc_message_t *message = llc_message_allocate(total_length, base, false); + llc_message_t *message = llc_message_allocate(total_length, base); if (!message) { if (base->asynch_confirm) { base->asynch_confirm(interface, request->message_type); } return 0; } + + //Add To active list + llc_message_id_allocate(message, base, false); + base->llc_message_list_size++; + ns_list_add_to_end(&base->llc_message_list, message); message->messsage_type = request->message_type; + mcps_data_req_t data_req; memset(&data_req, 0, sizeof(mcps_data_req_t)); data_req.SeqNumSuppressed = true; @@ -1253,4 +1650,60 @@ void ws_llc_hopping_schedule_config(struct protocol_interface_info_entry *interf } base->ie_params.hopping_schedule = hopping_schedule; } + +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); + if (!base) { + return; + } + + ns_list_foreach_safe(ws_neighbor_temp_class_t, entry, &base->temp_entries->active_eapol_temp_neigh) { + if (entry->eapol_temp_info.eapol_timeout <= seconds_update) { + ns_list_remove(&base->temp_entries->active_eapol_temp_neigh, entry); + ns_list_add_to_end(&base->temp_entries->free_temp_neigh, entry); + } else { + entry->eapol_temp_info.eapol_timeout -= seconds_update; + if (entry->eapol_temp_info.eapol_rx_relay_filter == 0) { + //No active filter period + continue; + } + + //Update filter time + if (entry->eapol_temp_info.eapol_rx_relay_filter <= seconds_update) { + entry->eapol_temp_info.eapol_rx_relay_filter = 0; + } else { + entry->eapol_temp_info.eapol_rx_relay_filter -= seconds_update; + } + } + } +} + +bool ws_llc_eapol_relay_forward_filter(struct protocol_interface_info_entry *interface, const uint8_t *joiner_eui64, uint8_t mac_sequency, uint32_t rx_timestamp) +{ + llc_data_base_t *base = ws_llc_discover_by_interface(interface); + if (!base) { + return false; + } + + ws_neighbor_temp_class_t *neighbor = ws_llc_discover_eapol_temp_entry(base->temp_entries, joiner_eui64); + if (!neighbor) { + llc_neighbour_req_t neighbor_info; + //Discover here Normal Neighbour + if (!base->ws_neighbor_info_request_cb(interface, joiner_eui64, &neighbor_info, false)) { + return false; + } + return ws_neighbor_class_neighbor_duplicate_packet_check(neighbor_info.ws_neighbor, mac_sequency, rx_timestamp); + } + + if (neighbor->eapol_temp_info.eapol_rx_relay_filter && neighbor->eapol_temp_info.last_rx_mac_sequency == mac_sequency) { + return false; + } + neighbor->eapol_temp_info.last_rx_mac_sequency = mac_sequency; + neighbor->eapol_temp_info.eapol_rx_relay_filter = 6; //Activate 5-5.99 seconds filter time + return true; + +} + + #endif diff --git a/source/6LoWPAN/ws/ws_management_api.c b/source/6LoWPAN/ws/ws_management_api.c index cd4ce0cd80..ef9e9cffbd 100644 --- a/source/6LoWPAN/ws/ws_management_api.c +++ b/source/6LoWPAN/ws/ws_management_api.c @@ -41,9 +41,11 @@ int ws_management_node_init( protocol_interface_info_entry_t *cur; cur = protocol_stack_interface_info_get_by_id(interface_id); + if (interface_id >= 0 && (!cur || !ws_info(cur))) { return -1; } + if (!network_name_ptr || !fhss_timer_ptr) { return -2; } @@ -70,7 +72,9 @@ int ws_management_node_init( return -4; } - cur->ws_info->fhss_timer_ptr = fhss_timer_ptr; + if (cur && ws_info(cur)) { + cur->ws_info->fhss_timer_ptr = fhss_timer_ptr; + } return 0; } @@ -398,7 +402,7 @@ int ws_management_channel_plan_set( protocol_interface_info_entry_t *cur; cur = protocol_stack_interface_info_get_by_id(interface_id); - if (interface_id >= 0 && (!cur || !ws_info(cur))) { + if (!cur || !ws_info(cur)) { return -1; } cur->ws_info->hopping_schdule.channel_plan = channel_plan; diff --git a/source/6LoWPAN/ws/ws_neighbor_class.c b/source/6LoWPAN/ws/ws_neighbor_class.c index 7e4e7eedc0..214c46f871 100644 --- a/source/6LoWPAN/ws/ws_neighbor_class.c +++ b/source/6LoWPAN/ws/ws_neighbor_class.c @@ -322,5 +322,32 @@ void ws_neighbor_class_rsl_out_calculate(ws_neighbor_class_entry_t *ws_neighbor, return; } + +bool ws_neighbor_class_neighbor_duplicate_packet_check(ws_neighbor_class_entry_t *ws_neighbor, uint8_t mac_dsn, uint32_t rx_timestamp) +{ + if (ws_neighbor->last_DSN != mac_dsn) { + // New packet allways accepted + ws_neighbor->last_DSN = mac_dsn; + return true; + } + + if (!ws_neighbor->unicast_data_rx) { + // No unicast info stored always accepted + return true; + } + + rx_timestamp -= ws_neighbor->fhss_data.uc_timing_info.utt_rx_timestamp; + rx_timestamp /= 1000000; //Convert to s + + //Compare only when last rx timestamp is less than 5 seconds + if (rx_timestamp < 5) { + //Packet is sent too fast filter it out + return false; + } + + return true; +} + + #endif /* HAVE_WS */ diff --git a/source/6LoWPAN/ws/ws_neighbor_class.h b/source/6LoWPAN/ws/ws_neighbor_class.h index c381b43f50..f470a25a8b 100644 --- a/source/6LoWPAN/ws/ws_neighbor_class.h +++ b/source/6LoWPAN/ws/ws_neighbor_class.h @@ -28,6 +28,7 @@ typedef struct ws_neighbor_class_entry { uint16_t rsl_in; /*!< RSL EWMA heard from neighbour*/ uint16_t rsl_out; /*!< RSL EWMA heard by neighbour*/ uint16_t routing_cost; /*!< ETX to border Router. */ + uint8_t last_DSN; bool candidate_parent: 1; bool broadcast_timing_info_stored: 1; bool broadcast_shedule_info_stored: 1; @@ -181,4 +182,6 @@ void ws_neighbor_class_rsl_in_calculate(ws_neighbor_class_entry_t *ws_neighbor, */ void ws_neighbor_class_rsl_out_calculate(ws_neighbor_class_entry_t *ws_neighbor, uint8_t rsl_reported); +bool ws_neighbor_class_neighbor_duplicate_packet_check(ws_neighbor_class_entry_t *ws_neighbor, uint8_t mac_dsn, uint32_t rx_timestamp); + #endif /* WS_NEIGHBOR_CLASS_H_ */ diff --git a/source/6LoWPAN/ws/ws_pae_auth.c b/source/6LoWPAN/ws/ws_pae_auth.c index df50aea726..077c3ae580 100644 --- a/source/6LoWPAN/ws/ws_pae_auth.c +++ b/source/6LoWPAN/ws/ws_pae_auth.c @@ -28,6 +28,7 @@ #include "eventOS_scheduler.h" #include "eventOS_event_timer.h" #include "ns_address.h" +#include "Service_Libs/utils/ns_file.h" #include "NWK_INTERFACE/Include/protocol.h" #include "6LoWPAN/ws/ws_config.h" #include "Security/protocols/sec_prot_cfg.h" @@ -46,6 +47,8 @@ #include "6LoWPAN/ws/ws_pae_timers.h" #include "6LoWPAN/ws/ws_pae_auth.h" #include "6LoWPAN/ws/ws_pae_lib.h" +#include "6LoWPAN/ws/ws_pae_time.h" +#include "6LoWPAN/ws/ws_pae_key_storage.h" #ifdef HAVE_WS #ifdef HAVE_PAE_AUTH @@ -56,16 +59,18 @@ #define PAE_TASKLET_EVENT 2 #define PAE_TASKLET_TIMER 3 -// Wait for for supplicant to indicate activity (e.g. to send a message) -#define WAIT_FOR_AUTHENTICATION_TICKS 5 * 60 * 10 // 5 minutes - +/* Wait for supplicant to indicate activity (e.g. to send a message) when + authentication is ongoing */ +#define WAIT_FOR_AUTHENTICATION_TICKS 2 * 60 * 10 // 2 minutes +// Wait after authentication has completed before supplicant entry goes inactive +#define WAIT_AFTER_AUTHENTICATION_TICKS 15 * 10 // 15 seconds /* If EAP-TLS is delayed due to simultaneous negotiations limit, defines how long to wait for previous negotiation to complete */ #define EAP_TLS_NEGOTIATION_TRIGGER_TIMEOUT 60 * 10 // 60 seconds // Default for maximum number of supplicants -#define SUPPLICANT_MAX_NUMBER 1000 +#define SUPPLICANT_MAX_NUMBER 5000 /* Default for number of supplicants to purge per garbage collect call from nanostack monitor */ @@ -76,21 +81,23 @@ typedef struct { ns_list_link_t link; /**< Link */ + uint16_t pan_id; /**< PAN ID */ + char network_name[33]; /**< Network name */ kmp_service_t *kmp_service; /**< KMP service */ protocol_interface_info_entry_t *interface_ptr; /**< Interface pointer */ ws_pae_auth_gtk_hash_set *hash_set; /**< GTK hash set callback */ ws_pae_auth_nw_key_insert *nw_key_insert; /**< Key insert callback */ + ws_pae_auth_nw_keys_remove *nw_keys_remove; /**< Network keys remove callback */ ws_pae_auth_nw_key_index_set *nw_key_index_set; /**< Key index set callback */ + ws_pae_auth_nw_info_updated *nw_info_updated; /**< Security keys network info updated callback */ supp_list_t active_supp_list; /**< List of active supplicants */ - supp_list_t inactive_supp_list; /**< List of inactive supplicants */ arm_event_storage_t *timer; /**< Timer */ - sec_prot_gtk_keys_t *gtks; /**< GTKs */ sec_prot_gtk_keys_t *next_gtks; /**< Next GTKs */ const sec_prot_certs_t *certs; /**< Certificates */ + sec_prot_keys_nw_info_t *sec_keys_nw_info; /**< Security keys network information */ sec_timer_cfg_t *sec_timer_cfg; /**< Timer configuration */ sec_prot_cfg_t *sec_prot_cfg; /**< Protocol Configuration */ uint16_t supp_max_number; /**< Max number of stored supplicants */ - uint16_t slow_timer_seconds; /**< Slow timer seconds */ bool timer_running : 1; /**< Timer is running */ bool gtk_new_inst_req_exp : 1; /**< GTK new install required timer expired */ bool gtk_new_act_time_exp: 1; /**< GTK new activation time expired */ @@ -119,15 +126,15 @@ static void ws_pae_auth_kmp_api_create_indication(kmp_api_t *kmp, kmp_type_e typ static void ws_pae_auth_kmp_api_finished_indication(kmp_api_t *kmp, kmp_result_e result, kmp_sec_keys_t *sec_keys); static void ws_pae_auth_next_kmp_trigger(pae_auth_t *pae_auth, supp_entry_t *supp_entry); static kmp_type_e ws_pae_auth_next_protocol_get(pae_auth_t *pae_auth, supp_entry_t *supp_entry); -static kmp_api_t *ws_pae_auth_kmp_create_and_start(kmp_service_t *service, kmp_type_e type, supp_entry_t *supp_entry, sec_prot_cfg_t *cfg); +static kmp_api_t *ws_pae_auth_kmp_create_and_start(kmp_service_t *service, kmp_type_e type, supp_entry_t *supp_entry, sec_prot_cfg_t *prot_cfg, sec_timer_cfg_t *timer_cfg); static void ws_pae_auth_kmp_api_finished(kmp_api_t *kmp); static int8_t tasklet_id = -1; static NS_LIST_DEFINE(pae_auth_list, pae_auth_t, link); -int8_t ws_pae_auth_init(protocol_interface_info_entry_t *interface_ptr, sec_prot_gtk_keys_t *gtks, sec_prot_gtk_keys_t *next_gtks, const sec_prot_certs_t *certs, sec_timer_cfg_t *sec_timer_cfg, sec_prot_cfg_t *sec_prot_cfg) +int8_t ws_pae_auth_init(protocol_interface_info_entry_t *interface_ptr, sec_prot_gtk_keys_t *next_gtks, const sec_prot_certs_t *certs, sec_timer_cfg_t *sec_timer_cfg, sec_prot_cfg_t *sec_prot_cfg, sec_prot_keys_nw_info_t *sec_keys_nw_info) { - if (!interface_ptr || !gtks || !certs) { + if (!interface_ptr || !next_gtks || !certs || !sec_timer_cfg || !sec_prot_cfg || !sec_keys_nw_info) { return -1; } @@ -140,23 +147,25 @@ int8_t ws_pae_auth_init(protocol_interface_info_entry_t *interface_ptr, sec_prot return -1; } + + memset(&pae_auth->network_name, 0, 33); + pae_auth->pan_id = 0xffff; pae_auth->interface_ptr = interface_ptr; ws_pae_lib_supp_list_init(&pae_auth->active_supp_list); - ws_pae_lib_supp_list_init(&pae_auth->inactive_supp_list); pae_auth->timer = NULL; pae_auth->hash_set = NULL; pae_auth->nw_key_insert = NULL; + pae_auth->nw_keys_remove = NULL; pae_auth->nw_key_index_set = NULL; - pae_auth->gtks = gtks; pae_auth->next_gtks = next_gtks; pae_auth->certs = certs; + pae_auth->sec_keys_nw_info = sec_keys_nw_info; pae_auth->sec_timer_cfg = sec_timer_cfg; pae_auth->sec_prot_cfg = sec_prot_cfg; pae_auth->supp_max_number = SUPPLICANT_MAX_NUMBER; - pae_auth->slow_timer_seconds = 0; pae_auth->gtk_new_inst_req_exp = false; pae_auth->gtk_new_act_time_exp = false; @@ -254,7 +263,7 @@ int8_t ws_pae_auth_delete(protocol_interface_info_entry_t *interface_ptr) return 0; } -void ws_pae_auth_cb_register(protocol_interface_info_entry_t *interface_ptr, ws_pae_auth_gtk_hash_set *hash_set, ws_pae_auth_nw_key_insert *nw_key_insert, ws_pae_auth_nw_key_index_set *nw_key_index_set) +void ws_pae_auth_cb_register(protocol_interface_info_entry_t *interface_ptr, ws_pae_auth_gtk_hash_set *hash_set, ws_pae_auth_nw_key_insert *nw_key_insert, ws_pae_auth_nw_key_index_set *nw_key_index_set, ws_pae_auth_nw_info_updated *nw_info_updated) { if (!interface_ptr) { return; @@ -268,6 +277,7 @@ void ws_pae_auth_cb_register(protocol_interface_info_entry_t *interface_ptr, ws_ pae_auth->hash_set = hash_set; pae_auth->nw_key_insert = nw_key_insert; pae_auth->nw_key_index_set = nw_key_index_set; + pae_auth->nw_info_updated = nw_info_updated; } void ws_pae_auth_start(protocol_interface_info_entry_t *interface_ptr) @@ -282,15 +292,17 @@ void ws_pae_auth_start(protocol_interface_info_entry_t *interface_ptr) } // Checks if there is predefined active key - int8_t index = sec_prot_keys_gtk_status_active_get(pae_auth->gtks); + int8_t index = sec_prot_keys_gtk_status_active_get(pae_auth->sec_keys_nw_info->gtks); if (index < 0) { // If there is no key, inserts a new one ws_pae_auth_gtk_key_insert(pae_auth); - index = sec_prot_keys_gtk_install_order_first_index_get(pae_auth->gtks); + index = sec_prot_keys_gtk_install_order_first_index_get(pae_auth->sec_keys_nw_info->gtks); ws_pae_auth_active_gtk_set(pae_auth, index); } else { ws_pae_auth_active_gtk_set(pae_auth, index); } + // Update keys to NVM as needed + pae_auth->nw_info_updated(pae_auth->interface_ptr); // Inserts keys and updates GTK hash on stack ws_pae_auth_network_keys_from_gtks_set(pae_auth); @@ -331,13 +343,15 @@ int8_t ws_pae_auth_nw_key_index_update(protocol_interface_info_entry_t *interfac int8_t ws_pae_auth_node_keys_remove(protocol_interface_info_entry_t *interface_ptr, uint8_t *eui_64) { + int8_t ret_value = -1; + if (!interface_ptr) { - return -1; + return ret_value; } pae_auth_t *pae_auth = ws_pae_auth_get(interface_ptr); if (!pae_auth) { - return -1; + return ret_value; } // Checks if supplicant is active @@ -348,20 +362,16 @@ int8_t ws_pae_auth_node_keys_remove(protocol_interface_info_entry_t *interface_p sec_prot_keys_pmk_delete(&supp->sec_keys); sec_prot_keys_ptk_delete(&supp->sec_keys); supp->access_revoked = true; - tr_info("Access revoked; keys removed, eui-64: %s", trace_array(supp->addr.eui_64, 8)); - return 0; + tr_info("Access revoked; keys removed, eui-64: %s", trace_array(eui_64, 8)); + ret_value = 0; } - // Checks if supplicant is inactive - supp = ws_pae_lib_supp_list_entry_eui_64_get(&pae_auth->inactive_supp_list, eui_64); - if (supp) { - // Deletes supplicant - tr_info("Access revoked; deleted, eui-64: %s", trace_array(supp->addr.eui_64, 8)); - ws_pae_lib_supp_list_remove(&pae_auth->inactive_supp_list, supp); - return 0; + if (ws_pae_key_storage_supp_delete(pae_auth, eui_64)) { + tr_info("Access revoked; key store deleted, eui-64: %s", trace_array(eui_64, 8)); + ret_value = 0; } - return -1; + return ret_value; } int8_t ws_pae_auth_node_access_revoke_start(protocol_interface_info_entry_t *interface_ptr) @@ -376,7 +386,7 @@ int8_t ws_pae_auth_node_access_revoke_start(protocol_interface_info_entry_t *int } // Gets active GTK - int8_t active_index = sec_prot_keys_gtk_status_active_get(pae_auth->gtks); + int8_t active_index = sec_prot_keys_gtk_status_active_get(pae_auth->sec_keys_nw_info->gtks); if (active_index >= 0) { // As default removes other keys than active @@ -384,22 +394,24 @@ int8_t ws_pae_auth_node_access_revoke_start(protocol_interface_info_entry_t *int uint32_t revocation_lifetime = ws_pae_timers_gtk_revocation_lifetime_get(pae_auth->sec_timer_cfg); - uint32_t active_lifetime = sec_prot_keys_gtk_lifetime_get(pae_auth->gtks, active_index); + uint32_t active_lifetime = sec_prot_keys_gtk_lifetime_get(pae_auth->sec_keys_nw_info->gtks, active_index); + + uint64_t current_time = ws_pae_current_time_get(); // If active GTK lifetime is larger than revocation lifetime decrements active GTK lifetime if (active_lifetime > revocation_lifetime) { - sec_prot_keys_gtk_lifetime_decrement(pae_auth->gtks, active_index, active_lifetime - revocation_lifetime); + sec_prot_keys_gtk_lifetime_decrement(pae_auth->sec_keys_nw_info->gtks, active_index, current_time, active_lifetime - revocation_lifetime); tr_info("Access revocation start, GTK active index: %i, revoked lifetime: %"PRIu32"", active_index, revocation_lifetime); } else { // Otherwise decrements lifetime of the GTK to be installed after the active one - int8_t second_index = sec_prot_keys_gtk_install_order_second_index_get(pae_auth->gtks); + int8_t second_index = sec_prot_keys_gtk_install_order_second_index_get(pae_auth->sec_keys_nw_info->gtks); if (second_index >= 0) { // Second GTK revocation lifetime is the active GTK lifetime added with revocation time uint32_t second_revocation_lifetime = active_lifetime + revocation_lifetime; - uint32_t second_lifetime = sec_prot_keys_gtk_lifetime_get(pae_auth->gtks, second_index); + uint32_t second_lifetime = sec_prot_keys_gtk_lifetime_get(pae_auth->sec_keys_nw_info->gtks, second_index); if (second_lifetime > second_revocation_lifetime) { - sec_prot_keys_gtk_lifetime_decrement(pae_auth->gtks, second_index, second_lifetime - second_revocation_lifetime); + sec_prot_keys_gtk_lifetime_decrement(pae_auth->sec_keys_nw_info->gtks, second_index, current_time, second_lifetime - second_revocation_lifetime); tr_info("Access revocation start, GTK second active index: %i, revoked lifetime: %"PRIu32"", second_index, second_revocation_lifetime); } // Removes other keys than active and GTK to be installed next @@ -408,11 +420,11 @@ int8_t ws_pae_auth_node_access_revoke_start(protocol_interface_info_entry_t *int } // Deletes other GTKs - int8_t last_index = sec_prot_keys_gtk_install_order_last_index_get(pae_auth->gtks); + int8_t last_index = sec_prot_keys_gtk_install_order_last_index_get(pae_auth->sec_keys_nw_info->gtks); while (last_index >= 0 && last_index != not_removed_index) { tr_info("Access revocation GTK clear index: %i", last_index); - sec_prot_keys_gtk_clear(pae_auth->gtks, last_index); - last_index = sec_prot_keys_gtk_install_order_last_index_get(pae_auth->gtks); + sec_prot_keys_gtk_clear(pae_auth->sec_keys_nw_info->gtks, last_index); + last_index = sec_prot_keys_gtk_install_order_last_index_get(pae_auth->sec_keys_nw_info->gtks); } } @@ -420,6 +432,9 @@ int8_t ws_pae_auth_node_access_revoke_start(protocol_interface_info_entry_t *int ws_pae_auth_gtk_key_insert(pae_auth); ws_pae_auth_network_keys_from_gtks_set(pae_auth); + // Update keys to NVM as needed + pae_auth->nw_info_updated(pae_auth->interface_ptr); + return 0; } @@ -452,22 +467,69 @@ void ws_pae_auth_forced_gc(protocol_interface_info_entry_t *interface_ptr) /* Purge in maximum five entries from supplicant list (starting from oldest one) per call to the function (called by nanostack monitor) */ - ws_pae_lib_supp_list_purge(&pae_auth->active_supp_list, &pae_auth->inactive_supp_list, 0, SUPPLICANT_NUMBER_TO_PURGE); + ws_pae_lib_supp_list_purge(&pae_auth->active_supp_list, 0, SUPPLICANT_NUMBER_TO_PURGE); +} + +int8_t ws_pae_auth_nw_info_set(protocol_interface_info_entry_t *interface_ptr, uint16_t pan_id, char *network_name) +{ + if (!interface_ptr || !network_name) { + return -1; + } + + pae_auth_t *pae_auth = ws_pae_auth_get(interface_ptr); + if (!pae_auth) { + return -1; + } + + // On authenticator pan_id is always selected locally and is always valid for keys + if (pae_auth->sec_keys_nw_info->key_pan_id != pan_id) { + pae_auth->sec_keys_nw_info->key_pan_id = pan_id; + pae_auth->sec_keys_nw_info->updated = true; + } + + bool update_keys = false; + if (pae_auth->pan_id != 0xffff && pae_auth->pan_id != pan_id) { + update_keys = true; + } + pae_auth->pan_id = pan_id; + + if (strlen((char *) &pae_auth->network_name) > 0 && strcmp((char *) &pae_auth->network_name, network_name) != 0) { + update_keys = true; + } + strcpy((char *) &pae_auth->network_name, network_name); + + if (!update_keys) { + return 0; + } + + if (pae_auth->nw_keys_remove) { + pae_auth->nw_keys_remove(pae_auth->interface_ptr); + } + + ws_pae_auth_network_keys_from_gtks_set(pae_auth); + + int8_t index = sec_prot_keys_gtk_status_active_get(pae_auth->sec_keys_nw_info->gtks); + if (index >= 0) { + // Sets active key index + ws_pae_auth_network_key_index_set(pae_auth, index); + } + + return 0; } static int8_t ws_pae_auth_network_keys_from_gtks_set(pae_auth_t *pae_auth) { // Authenticator keys are always fresh - sec_prot_keys_gtk_status_all_fresh_set(pae_auth->gtks); + sec_prot_keys_gtk_status_all_fresh_set(pae_auth->sec_keys_nw_info->gtks); if (pae_auth->hash_set) { uint8_t gtk_hash[32]; - sec_prot_keys_gtks_hash_generate(pae_auth->gtks, gtk_hash); + sec_prot_keys_gtks_hash_generate(pae_auth->sec_keys_nw_info->gtks, gtk_hash); pae_auth->hash_set(pae_auth->interface_ptr, gtk_hash); } if (pae_auth->nw_key_insert) { - pae_auth->nw_key_insert(pae_auth->interface_ptr, pae_auth->gtks); + pae_auth->nw_key_insert(pae_auth->interface_ptr, pae_auth->sec_keys_nw_info->gtks); } return 0; @@ -475,12 +537,12 @@ static int8_t ws_pae_auth_network_keys_from_gtks_set(pae_auth_t *pae_auth) static int8_t ws_pae_auth_active_gtk_set(pae_auth_t *pae_auth, uint8_t index) { - return sec_prot_keys_gtk_status_active_set(pae_auth->gtks, index); + return sec_prot_keys_gtk_status_active_set(pae_auth->sec_keys_nw_info->gtks, index); } static int8_t ws_pae_auth_gtk_clear(pae_auth_t *pae_auth, uint8_t index) { - return sec_prot_keys_gtk_clear(pae_auth->gtks, index); + return sec_prot_keys_gtk_clear(pae_auth->sec_keys_nw_info->gtks, index); } static int8_t ws_pae_auth_network_key_index_set(pae_auth_t *pae_auth, uint8_t index) @@ -499,7 +561,6 @@ static void ws_pae_auth_free(pae_auth_t *pae_auth) } ws_pae_lib_supp_list_delete(&pae_auth->active_supp_list); - ws_pae_lib_supp_list_delete(&pae_auth->inactive_supp_list); kmp_socket_if_unregister(pae_auth->kmp_service); @@ -582,7 +643,7 @@ void ws_pae_auth_fast_timer(uint16_t ticks) } // Updates KMP timers - bool running = ws_pae_lib_supp_list_timer_update(&pae_auth->active_supp_list, &pae_auth->inactive_supp_list, ticks, kmp_service_timer_if_timeout); + bool running = ws_pae_lib_supp_list_timer_update(pae_auth, &pae_auth->active_supp_list, ticks, kmp_service_timer_if_timeout); if (!running) { ws_pae_auth_timer_stop(pae_auth); } @@ -594,22 +655,26 @@ void ws_pae_auth_slow_timer(uint16_t seconds) ns_list_foreach(pae_auth_t, pae_auth, &pae_auth_list) { // Gets index of currently active GTK - int8_t active_index = sec_prot_keys_gtk_status_active_get(pae_auth->gtks); + int8_t active_index = sec_prot_keys_gtk_status_active_get(pae_auth->sec_keys_nw_info->gtks); + + uint64_t current_time = ws_pae_current_time_get(); for (uint8_t i = 0; i < GTK_NUM; i++) { - if (!sec_prot_keys_gtk_is_set(pae_auth->gtks, i)) { + if (!sec_prot_keys_gtk_is_set(pae_auth->sec_keys_nw_info->gtks, i)) { continue; } - uint32_t timer_seconds = sec_prot_keys_gtk_lifetime_decrement(pae_auth->gtks, i, seconds); + uint32_t timer_seconds = sec_prot_keys_gtk_lifetime_decrement(pae_auth->sec_keys_nw_info->gtks, i, current_time, seconds); if (active_index == i) { if (!pae_auth->gtk_new_inst_req_exp) { pae_auth->gtk_new_inst_req_exp = ws_pae_timers_gtk_new_install_required(pae_auth->sec_timer_cfg, timer_seconds); if (pae_auth->gtk_new_inst_req_exp) { - int8_t second_index = sec_prot_keys_gtk_install_order_second_index_get(pae_auth->gtks); + int8_t second_index = sec_prot_keys_gtk_install_order_second_index_get(pae_auth->sec_keys_nw_info->gtks); if (second_index < 0) { tr_info("GTK new install required active index: %i, time: %"PRIu32", system time: %"PRIu32"", active_index, timer_seconds, protocol_core_monotonic_time / 10); ws_pae_auth_gtk_key_insert(pae_auth); ws_pae_auth_network_keys_from_gtks_set(pae_auth); + // Update keys to NVM as needed + pae_auth->nw_info_updated(pae_auth->interface_ptr); } else { tr_info("GTK new install already done; second index: %i, time: %"PRIu32", system time: %"PRIu32"", second_index, timer_seconds, protocol_core_monotonic_time / 10); } @@ -626,6 +691,8 @@ void ws_pae_auth_slow_timer(uint16_t seconds) } pae_auth->gtk_new_inst_req_exp = false; pae_auth->gtk_new_act_time_exp = false; + // Update keys to NVM as needed + pae_auth->nw_info_updated(pae_auth->interface_ptr); } } } @@ -634,22 +701,22 @@ void ws_pae_auth_slow_timer(uint16_t seconds) tr_info("GTK expired index: %i, system time: %"PRIu32"", i, protocol_core_monotonic_time / 10); ws_pae_auth_gtk_clear(pae_auth, i); ws_pae_auth_network_keys_from_gtks_set(pae_auth); + // Update keys to NVM as needed + pae_auth->nw_info_updated(pae_auth->interface_ptr); } } - pae_auth->slow_timer_seconds += seconds; - if (pae_auth->slow_timer_seconds > 60) { - ws_pae_lib_supp_list_slow_timer_update(&pae_auth->active_supp_list, pae_auth->sec_timer_cfg, pae_auth->slow_timer_seconds); - ws_pae_lib_supp_list_slow_timer_update(&pae_auth->inactive_supp_list, pae_auth->sec_timer_cfg, pae_auth->slow_timer_seconds); - pae_auth->slow_timer_seconds = 0; - } + ws_pae_lib_supp_list_slow_timer_update(&pae_auth->active_supp_list, seconds); } + + // Update key storage timer + ws_pae_key_storage_timer(seconds); } static void ws_pae_auth_gtk_key_insert(pae_auth_t *pae_auth) { // Gets index to install the key - uint8_t install_index = sec_prot_keys_gtk_install_index_get(pae_auth->gtks); + uint8_t install_index = sec_prot_keys_gtk_install_index_get(pae_auth->sec_keys_nw_info->gtks); // Key to install uint8_t gtk_value[GTK_LEN]; @@ -671,24 +738,24 @@ static void ws_pae_auth_gtk_key_insert(pae_auth_t *pae_auth) // Gets latest installed key lifetime and adds GTK expire offset to it uint32_t lifetime = pae_auth->sec_timer_cfg->gtk_expire_offset; - int8_t last_index = sec_prot_keys_gtk_install_order_last_index_get(pae_auth->gtks); + int8_t last_index = sec_prot_keys_gtk_install_order_last_index_get(pae_auth->sec_keys_nw_info->gtks); if (last_index >= 0) { - lifetime += sec_prot_keys_gtk_lifetime_get(pae_auth->gtks, last_index); + lifetime += sec_prot_keys_gtk_lifetime_get(pae_auth->sec_keys_nw_info->gtks, last_index); } // Installs the new key - sec_prot_keys_gtk_clear(pae_auth->gtks, install_index); - sec_prot_keys_gtk_set(pae_auth->gtks, install_index, gtk_value, lifetime); + sec_prot_keys_gtk_clear(pae_auth->sec_keys_nw_info->gtks, install_index); + sec_prot_keys_gtk_set(pae_auth->sec_keys_nw_info->gtks, install_index, gtk_value, lifetime); // Authenticator keys are always fresh - sec_prot_keys_gtk_status_all_fresh_set(pae_auth->gtks); + sec_prot_keys_gtk_status_all_fresh_set(pae_auth->sec_keys_nw_info->gtks); tr_info("GTK install new index: %i, lifetime: %"PRIu32" system time: %"PRIu32"", install_index, lifetime, protocol_core_monotonic_time / 10); } static int8_t ws_pae_auth_new_gtk_activate(pae_auth_t *pae_auth) { - int8_t new_active_index = sec_prot_keys_gtk_install_order_second_index_get(pae_auth->gtks); + int8_t new_active_index = sec_prot_keys_gtk_install_order_second_index_get(pae_auth->sec_keys_nw_info->gtks); if (new_active_index >= 0) { ws_pae_auth_active_gtk_set(pae_auth, new_active_index); } @@ -717,8 +784,6 @@ static int8_t ws_pae_auth_timer_if_start(kmp_service_t *service, kmp_api_t *kmp) return -1; } - ws_pae_lib_supp_list_to_active(&pae_auth->active_supp_list, &pae_auth->inactive_supp_list, supp_entry); - ws_pae_lib_kmp_timer_start(&supp_entry->kmp_list, entry); return 0; } @@ -798,26 +863,27 @@ static kmp_api_t *ws_pae_auth_kmp_incoming_ind(kmp_service_t *service, kmp_type_ supp_entry_t *supp_entry = ws_pae_lib_supp_list_entry_eui_64_get(&pae_auth->active_supp_list, kmp_address_eui_64_get(addr)); if (!supp_entry) { - // Find supplicant from list of inactive supplicants - supp_entry = ws_pae_lib_supp_list_entry_eui_64_get(&pae_auth->inactive_supp_list, kmp_address_eui_64_get(addr)); + // Checks if active supplicant list has space for new supplicants + if (ws_pae_lib_supp_list_active_limit_reached(&pae_auth->active_supp_list, pae_auth->sec_prot_cfg->sec_max_ongoing_authentication)) { + tr_debug("PAE: active limit reached, eui-64: %s", trace_array(kmp_address_eui_64_get(addr), 8)); + return NULL; + } + // Find supplicant from key storage + supp_entry = ws_pae_key_storage_supp_read(pae_auth, kmp_address_eui_64_get(addr), pae_auth->sec_keys_nw_info->gtks, pae_auth->certs); if (supp_entry) { // Move supplicant to active list - ws_pae_lib_supp_list_to_active(&pae_auth->active_supp_list, &pae_auth->inactive_supp_list, supp_entry); + tr_debug("PAE: to active, eui-64: %s", trace_array(supp_entry->addr.eui_64, 8)); + ns_list_add_to_start(&pae_auth->active_supp_list, supp_entry); } } // If does not exists add it to list if (!supp_entry) { - // Checks if maximum number of supplicants is reached and purge supplicant list (starting from oldest one) - ws_pae_lib_supp_list_purge(&pae_auth->active_supp_list, &pae_auth->inactive_supp_list, pae_auth->supp_max_number, 0); - supp_entry = ws_pae_lib_supp_list_add(&pae_auth->active_supp_list, addr); if (!supp_entry) { return 0; } - sec_prot_keys_init(&supp_entry->sec_keys, pae_auth->gtks, pae_auth->certs); - // Fixes the address of the supplicant to keys - sec_prot_keys_ptk_eui_64_write(&supp_entry->sec_keys, kmp_address_eui_64_get(addr)); + sec_prot_keys_init(&supp_entry->sec_keys, pae_auth->sec_keys_nw_info->gtks, pae_auth->certs); } else { // Updates relay address kmp_address_copy(&supp_entry->addr, addr); @@ -833,7 +899,7 @@ static kmp_api_t *ws_pae_auth_kmp_incoming_ind(kmp_service_t *service, kmp_type_ } // Create a new KMP for initial eapol-key - kmp = kmp_api_create(service, type + IEEE_802_1X_INITIAL_KEY, pae_auth->sec_prot_cfg); + kmp = kmp_api_create(service, type + IEEE_802_1X_INITIAL_KEY, pae_auth->sec_prot_cfg, pae_auth->sec_timer_cfg); if (!kmp) { return 0; @@ -913,10 +979,11 @@ static void ws_pae_auth_next_kmp_trigger(pae_auth_t *pae_auth, supp_entry_t *sup kmp_type_e next_type = ws_pae_auth_next_protocol_get(pae_auth, supp_entry); if (next_type == KMP_TYPE_NONE) { + // Supplicant goes inactive after 15 seconds + ws_pae_lib_supp_timer_ticks_set(supp_entry, WAIT_AFTER_AUTHENTICATION_TICKS); // All done return; } else { - kmp_api_t *api = ws_pae_lib_kmp_list_type_get(&supp_entry->kmp_list, next_type); if (api != NULL) { /* For other types than GTK, only one ongoing negotiation at the same time, @@ -947,7 +1014,7 @@ static void ws_pae_auth_next_kmp_trigger(pae_auth_t *pae_auth, supp_entry_t *sup } // Create new instance - kmp_api_t *new_kmp = ws_pae_auth_kmp_create_and_start(pae_auth->kmp_service, next_type, supp_entry, pae_auth->sec_prot_cfg); + kmp_api_t *new_kmp = ws_pae_auth_kmp_create_and_start(pae_auth->kmp_service, next_type, supp_entry, pae_auth->sec_prot_cfg, pae_auth->sec_timer_cfg); if (!new_kmp) { return; } @@ -960,7 +1027,7 @@ static void ws_pae_auth_next_kmp_trigger(pae_auth_t *pae_auth, supp_entry_t *sup return; } // Create TLS instance */ - if (ws_pae_auth_kmp_create_and_start(pae_auth->kmp_service, TLS_PROT, supp_entry, pae_auth->sec_prot_cfg) == NULL) { + if (ws_pae_auth_kmp_create_and_start(pae_auth->kmp_service, TLS_PROT, supp_entry, pae_auth->sec_prot_cfg, pae_auth->sec_timer_cfg) == NULL) { ws_pae_lib_kmp_list_delete(&supp_entry->kmp_list, new_kmp); return; } @@ -1027,11 +1094,10 @@ static kmp_type_e ws_pae_auth_next_protocol_get(pae_auth_t *pae_auth, supp_entry return next_type; } - -static kmp_api_t *ws_pae_auth_kmp_create_and_start(kmp_service_t *service, kmp_type_e type, supp_entry_t *supp_entry, sec_prot_cfg_t *cfg) +static kmp_api_t *ws_pae_auth_kmp_create_and_start(kmp_service_t *service, kmp_type_e type, supp_entry_t *supp_entry, sec_prot_cfg_t *prot_cfg, sec_timer_cfg_t *timer_cfg) { // Create KMP instance for new authentication - kmp_api_t *kmp = kmp_api_create(service, type, cfg); + kmp_api_t *kmp = kmp_api_create(service, type, prot_cfg, timer_cfg); if (!kmp) { return NULL; @@ -1084,7 +1150,6 @@ static void ws_pae_auth_kmp_api_finished(kmp_api_t *kmp) tr_info("PAE next KMP trigger, eui-64: %s", trace_array(retry_supp->addr.eui_64, 8)); ws_pae_auth_next_kmp_trigger(pae_auth, retry_supp); } - } #endif /* HAVE_PAE_AUTH */ diff --git a/source/6LoWPAN/ws/ws_pae_auth.h b/source/6LoWPAN/ws/ws_pae_auth.h index 5bf680f4ab..db84db0656 100644 --- a/source/6LoWPAN/ws/ws_pae_auth.h +++ b/source/6LoWPAN/ws/ws_pae_auth.h @@ -43,18 +43,18 @@ * \param local_port local port * \param remote_addr remote address * \param remote_port remote port - * \param gtks group keys * \param next_gtks next group keys to be used * \param cert_chain certificate chain * \param timer_settings timer settings * \param sec_timer_cfg timer configuration * \param sec_prot_cfg protocol configuration + * \param sec_keys_nw_info security keys network information * * \return < 0 failure * \return >= 0 success * */ -int8_t ws_pae_auth_init(protocol_interface_info_entry_t *interface_ptr, sec_prot_gtk_keys_t *gtks, sec_prot_gtk_keys_t *next_gtks, const sec_prot_certs_t *certs, sec_timer_cfg_t *sec_timer_cfg, sec_prot_cfg_t *sec_prot_cfg); +int8_t ws_pae_auth_init(protocol_interface_info_entry_t *interface_ptr, sec_prot_gtk_keys_t *next_gtks, const sec_prot_certs_t *certs, sec_timer_cfg_t *sec_timer_cfg, sec_prot_cfg_t *sec_prot_cfg, sec_prot_keys_nw_info_t *sec_keys_nw_info); /** * ws_pae_auth_addresses_set set relay addresses @@ -168,6 +168,19 @@ int8_t ws_pae_auth_node_limit_set(protocol_interface_info_entry_t *interface_ptr */ void ws_pae_auth_forced_gc(protocol_interface_info_entry_t *interface_ptr); +/** + * ws_pae_auth_nw_info_set set network information + * + * \param interface_ptr interface + * \param pan_id PAD ID + * \param network_name network name + * + * \return < 0 failure + * \return >= 0 success + * + */ +int8_t ws_pae_auth_nw_info_set(protocol_interface_info_entry_t *interface_ptr, uint16_t pan_id, char *network_name); + /** * ws_pae_auth_gtk_hash_set GTK hash set callback * @@ -189,6 +202,14 @@ typedef void ws_pae_auth_gtk_hash_set(protocol_interface_info_entry_t *interface */ typedef int8_t ws_pae_auth_nw_key_insert(protocol_interface_info_entry_t *interface_ptr, sec_prot_gtk_keys_t *gtks); +/** + * ws_pae_auth_nw_keys_remove remove network keys callback + * + * \param interface_ptr interface + * + */ +typedef void ws_pae_auth_nw_keys_remove(protocol_interface_info_entry_t *interface_ptr); + /** * ws_pae_auth_nw_key_index_set network send key index set callback * @@ -198,6 +219,14 @@ typedef int8_t ws_pae_auth_nw_key_insert(protocol_interface_info_entry_t *interf */ typedef void ws_pae_auth_nw_key_index_set(protocol_interface_info_entry_t *interface_ptr, uint8_t index); +/** + * ws_pae_auth_nw_info_updated security keys network information updated + * + * \param interface_ptr interface + * + */ +typedef void ws_pae_auth_nw_info_updated(protocol_interface_info_entry_t *interface_ptr); + /** * ws_pae_auth_cb_register register PAE authenticator callbacks * @@ -205,9 +234,10 @@ typedef void ws_pae_auth_nw_key_index_set(protocol_interface_info_entry_t *inter * \param hash_set GTK hash set callback * \param nw_key_insert network key index callback * \param nw_key_index_set network send key index callback + * \param nw_info_updated network keys updated callback * */ -void ws_pae_auth_cb_register(protocol_interface_info_entry_t *interface_ptr, ws_pae_auth_gtk_hash_set *hash_set, ws_pae_auth_nw_key_insert *nw_key_insert, ws_pae_auth_nw_key_index_set *nw_key_index_set); +void ws_pae_auth_cb_register(protocol_interface_info_entry_t *interface_ptr, ws_pae_auth_gtk_hash_set *hash_set, ws_pae_auth_nw_key_insert *nw_key_insert, ws_pae_auth_nw_key_index_set *nw_key_index_set, ws_pae_auth_nw_info_updated *nw_info_updated); #else @@ -215,10 +245,11 @@ void ws_pae_auth_cb_register(protocol_interface_info_entry_t *interface_ptr, ws_ #define ws_pae_auth_timing_adjust(timing) #define ws_pae_auth_addresses_set(interface_ptr, local_port, remote_addr, remote_port) 1 #define ws_pae_auth_delete NULL -#define ws_pae_auth_cb_register(interface_ptr, hash_set, nw_key_insert, nw_key_index_set) {(void) hash_set;} +#define ws_pae_auth_cb_register(interface_ptr, hash_set, nw_key_insert, nw_key_index_set, nw_info_updated) {(void) hash_set;} #define ws_pae_auth_start(interface_ptr) #define ws_pae_auth_gtks_updated NULL #define ws_pae_auth_nw_key_index_update NULL +#define ws_pae_auth_nw_info_set NULL #define ws_pae_auth_node_keys_remove(interface_ptr, eui64) -1 #define ws_pae_auth_node_access_revoke_start(interface_ptr) #define ws_pae_auth_node_limit_set(interface_ptr, limit) diff --git a/source/6LoWPAN/ws/ws_pae_controller.c b/source/6LoWPAN/ws/ws_pae_controller.c index cf73b0a9da..05eb06983b 100644 --- a/source/6LoWPAN/ws/ws_pae_controller.c +++ b/source/6LoWPAN/ws/ws_pae_controller.c @@ -24,6 +24,7 @@ #include "fhss_config.h" #include "ns_address.h" #include "ws_management_api.h" +#include "Service_Libs/utils/ns_file.h" #include "NWK_INTERFACE/Include/protocol.h" #include "6LoWPAN/ws/ws_config.h" #include "6LoWPAN/ws/ws_cfg_settings.h" @@ -36,6 +37,8 @@ #include "6LoWPAN/ws/ws_pae_auth.h" #include "6LoWPAN/ws/ws_pae_nvm_store.h" #include "6LoWPAN/ws/ws_pae_nvm_data.h" +#include "6LoWPAN/ws/ws_pae_time.h" +#include "6LoWPAN/ws/ws_pae_key_storage.h" #include "mbedtls/sha256.h" #ifdef HAVE_WS @@ -49,6 +52,7 @@ typedef int8_t ws_pae_br_addr_read(protocol_interface_info_entry_t *interface_pt typedef void ws_pae_gtks_updated(protocol_interface_info_entry_t *interface_ptr); typedef int8_t ws_pae_gtk_hash_update(protocol_interface_info_entry_t *interface_ptr, uint8_t *gtkhash); typedef int8_t ws_pae_nw_key_index_update(protocol_interface_info_entry_t *interface_ptr, uint8_t index); +typedef int8_t ws_pae_nw_info_set(protocol_interface_info_entry_t *interface_ptr, uint16_t pan_id, char *network_name); typedef struct { uint8_t gtk[GTK_LEN]; /**< GTK key */ @@ -63,15 +67,17 @@ typedef struct { uint8_t br_eui_64[8]; /**< Border router EUI-64 */ sec_prot_gtk_keys_t gtks; /**< GTKs */ sec_prot_gtk_keys_t next_gtks; /**< Next GTKs */ + sec_prot_keys_nw_info_t sec_keys_nw_info; /**< Security keys network information */ int8_t gtk_index; /**< GTK index */ uint8_t gtkhash[32]; /**< GTK hashes */ sec_prot_certs_t certs; /**< Certificates */ nw_key_t nw_key[GTK_NUM]; /**< Currently active network keys (on MAC) */ - char *network_name; /**< Network name for GAK generation */ - uint16_t frame_cnt_store_timer; /**< Timer for storing frame counter value */ + uint16_t frame_cnt_store_timer; /**< Timer to check if storing of frame counter value is needed */ + uint32_t frame_cnt_store_force_timer; /**< Timer to force storing of frame counter, if no other updates */ frame_counters_t frame_counters; /**< Frame counters */ sec_timer_cfg_t sec_timer_cfg; /**< Timer configuration (configuration set values) */ sec_prot_cfg_t sec_prot_cfg; /**< Configuration */ + uint32_t restart_cnt; /**< Re-start counter */ protocol_interface_info_entry_t *interface_ptr; /**< List link entry */ ws_pae_controller_auth_completed *auth_completed; /**< Authentication completed callback, continue bootstrap */ ws_pae_controller_nw_key_set *nw_key_set; /**< Key set callback */ @@ -80,6 +86,8 @@ typedef struct { ws_pae_controller_nw_frame_counter_set *nw_frame_counter_set; /**< Frame counter set callback */ ws_pae_controller_nw_frame_counter_read *nw_frame_counter_read; /**< Frame counter read callback */ ws_pae_controller_pan_ver_increment *pan_ver_increment; /**< PAN version increment callback */ + ws_pae_controller_nw_info_updated *nw_info_updated; /**< Network information updated callback */ + ws_pae_controller_auth_next_target *auth_next_target; /**< Authentication next target callback */ ws_pae_delete *pae_delete; /**< PAE delete callback */ ws_pae_timer *pae_fast_timer; /**< PAE fast timer callback */ ws_pae_timer *pae_slow_timer; /**< PAE slow timer callback */ @@ -88,7 +96,8 @@ typedef struct { ws_pae_gtks_updated *pae_gtks_updated; /**< PAE GTKs updated */ ws_pae_gtk_hash_update *pae_gtk_hash_update; /**< PAE GTK HASH update */ ws_pae_nw_key_index_update *pae_nw_key_index_update; /**< PAE NW key index update */ - nvm_tlv_entry_t *pae_nvm_buffer; /**< Buffer For PAE NVM write operation*/ + ws_pae_nw_info_set *pae_nw_info_set; /**< PAE security key network info set */ + uint8_t pae_nvm_buffer[PAE_NVM_DEFAULT_BUFFER_SIZE]; /**< Buffer for PAE NVM read and write operations */ bool gtks_set : 1; /**< GTKs are set */ bool gtkhash_set : 1; /**< GTK hashes are set */ bool key_index_set : 1; /**< NW key index is set */ @@ -101,12 +110,14 @@ typedef struct { bool ext_cert_valid_enabled : 1; /**< Extended certificate validation enabled */ } pae_controller_config_t; +static void ws_pae_controller_keys_nw_info_init(sec_prot_keys_nw_info_t *sec_keys_nw_info, sec_prot_gtk_keys_t *gtks); +static void ws_pae_controller_nw_info_updated_check(protocol_interface_info_entry_t *interface_ptr); static pae_controller_t *ws_pae_controller_get(protocol_interface_info_entry_t *interface_ptr); static void ws_pae_controller_frame_counter_timer(uint16_t seconds, pae_controller_t *entry); static void ws_pae_controller_frame_counter_timer_trigger(uint16_t seconds, pae_controller_t *entry); static void ws_pae_controller_frame_counter_store(pae_controller_t *entry, bool use_threshold); -static void ws_pae_controller_nvm_frame_counter_write(nvm_tlv_entry_t *tlv_entry); -static int8_t ws_pae_controller_nvm_frame_counter_read(frame_counters_t *counters); +static void ws_pae_controller_nvm_frame_counter_write(nvm_tlv_t *tlv_entry); +static int8_t ws_pae_controller_nvm_frame_counter_read(uint32_t *restart_cnt, uint64_t *stored_time, frame_counters_t *counters); static pae_controller_t *ws_pae_controller_get_or_create(int8_t interface_id); static void ws_pae_controller_gtk_hash_set(protocol_interface_info_entry_t *interface_ptr, uint8_t *gtkhash); static int8_t ws_pae_controller_nw_key_check_and_insert(protocol_interface_info_entry_t *interface_ptr, sec_prot_gtk_keys_t *gtks); @@ -114,12 +125,19 @@ static void ws_pae_controller_active_nw_key_clear(nw_key_t *nw_key); static void ws_pae_controller_active_nw_key_set(protocol_interface_info_entry_t *cur, uint8_t index); static int8_t ws_pae_controller_gak_from_gtk(uint8_t *gak, uint8_t *gtk, char *network_name); static void ws_pae_controller_frame_counter_store_and_nw_keys_remove(protocol_interface_info_entry_t *interface_ptr, pae_controller_t *controller, bool use_threshold); +#ifdef HAVE_PAE_AUTH static void ws_pae_controller_nw_key_index_check_and_set(protocol_interface_info_entry_t *interface_ptr, uint8_t index); +#endif static void ws_pae_controller_data_init(pae_controller_t *controller); -static void ws_pae_controller_frame_counter_read(pae_controller_t *controller); +static int8_t ws_pae_controller_frame_counter_read(pae_controller_t *controller); static void ws_pae_controller_frame_counter_reset(frame_counters_t *frame_counters); +static int8_t ws_pae_controller_nw_info_read(pae_controller_t *controller, sec_prot_gtk_keys_t *gtks); +static int8_t ws_pae_controller_nvm_nw_info_write(protocol_interface_info_entry_t *interface_ptr, uint16_t pan_id, char *network_name, sec_prot_gtk_keys_t *gtks); +static int8_t ws_pae_controller_nvm_nw_info_read(protocol_interface_info_entry_t *interface_ptr, uint16_t *pan_id, char *network_name, sec_prot_gtk_keys_t *gtks); + static const char *FRAME_COUNTER_FILE = FRAME_COUNTER_FILE_NAME; +static const char *NW_INFO_FILE = NW_INFO_FILE_NAME; static NS_LIST_DEFINE(pae_controller_list, pae_controller_t, link); @@ -129,26 +147,6 @@ pae_controller_config_t pae_controller_config = { .ext_cert_valid_enabled = false }; -#if !defined(HAVE_PAE_SUPP) && !defined(HAVE_PAE_AUTH) - -static void ws_pae_controller_test_keys_set(sec_prot_gtk_keys_t *gtks) -{ - uint8_t gtk[GTK_LEN]; - - // Test data - for (int i = 0; i < GTK_LEN; i++) { - gtk[i] = 0xcf - i; - } - - sec_prot_keys_gtk_set(gtks, 0, gtk, GTK_DEFAULT_LIFETIME); -} - -#else - -#define ws_pae_controller_test_keys_set(gtks); - -#endif - int8_t ws_pae_controller_authenticate(protocol_interface_info_entry_t *interface_ptr) { pae_controller_t *controller = ws_pae_controller_get(interface_ptr); @@ -168,16 +166,9 @@ int8_t ws_pae_controller_authenticate(protocol_interface_info_entry_t *interface return 0; } - if (ws_pae_supp_authenticate(controller->interface_ptr, controller->target_pan_id, controller->target_eui_64) < 0) { + if (ws_pae_supp_authenticate(controller->interface_ptr, controller->target_pan_id, controller->target_eui_64, controller->sec_keys_nw_info.network_name) < 0) { controller->auth_completed(interface_ptr, AUTH_RESULT_ERR_UNSPEC, controller->target_eui_64); } - -#else - ws_pae_controller_test_keys_set(&controller->gtks); - ws_pae_controller_nw_key_check_and_insert(interface_ptr, &controller->gtks); - ws_pae_controller_nw_key_index_check_and_set(interface_ptr, 0); - - controller->auth_completed(interface_ptr, AUTH_RESULT_OK); #endif return 0; @@ -216,20 +207,6 @@ int8_t ws_pae_controller_authenticator_start(protocol_interface_info_entry_t *in return -1; } -#ifdef HAVE_PAE_AUTH - if (sec_prot_keys_gtks_are_updated(&controller->gtks)) { - ws_pae_auth_gtks_updated(interface_ptr); - if (controller->gtk_index >= 0) { - controller->pae_nw_key_index_update(interface_ptr, controller->gtk_index); - } - sec_prot_keys_gtks_updated_reset(&controller->gtks); - } -#else - ws_pae_controller_test_keys_set(&controller->gtks); - ws_pae_controller_nw_key_check_and_insert(interface_ptr, &controller->gtks); - ws_pae_controller_nw_key_index_check_and_set(interface_ptr, 0); -#endif - if (ws_pae_auth_addresses_set(interface_ptr, local_port, remote_addr, remote_port) < 0) { return -1; } @@ -238,14 +215,14 @@ int8_t ws_pae_controller_authenticator_start(protocol_interface_info_entry_t *in ws_pae_auth_node_limit_set(controller->interface_ptr, pae_controller_config.node_limit); } - ws_pae_auth_cb_register(interface_ptr, ws_pae_controller_gtk_hash_set, ws_pae_controller_nw_key_check_and_insert, ws_pae_controller_nw_key_index_check_and_set); + ws_pae_auth_cb_register(interface_ptr, ws_pae_controller_gtk_hash_set, ws_pae_controller_nw_key_check_and_insert, ws_pae_controller_nw_key_index_check_and_set, ws_pae_controller_nw_info_updated_check); ws_pae_auth_start(interface_ptr); return 0; } -int8_t ws_pae_controller_cb_register(protocol_interface_info_entry_t *interface_ptr, ws_pae_controller_auth_completed *completed, ws_pae_controller_nw_key_set *nw_key_set, ws_pae_controller_nw_key_clear *nw_key_clear, ws_pae_controller_nw_send_key_index_set *nw_send_key_index_set, ws_pae_controller_nw_frame_counter_set *nw_frame_counter_set, ws_pae_controller_nw_frame_counter_read *nw_frame_counter_read, ws_pae_controller_pan_ver_increment *pan_ver_increment) +int8_t ws_pae_controller_cb_register(protocol_interface_info_entry_t *interface_ptr, ws_pae_controller_auth_completed *completed, ws_pae_controller_auth_next_target *auth_next_target, ws_pae_controller_nw_key_set *nw_key_set, ws_pae_controller_nw_key_clear *nw_key_clear, ws_pae_controller_nw_send_key_index_set *nw_send_key_index_set, ws_pae_controller_nw_frame_counter_set *nw_frame_counter_set, ws_pae_controller_nw_frame_counter_read *nw_frame_counter_read, ws_pae_controller_pan_ver_increment *pan_ver_increment, ws_pae_controller_nw_info_updated *nw_info_updated) { if (!interface_ptr) { return -1; @@ -263,7 +240,8 @@ int8_t ws_pae_controller_cb_register(protocol_interface_info_entry_t *interface_ controller->nw_frame_counter_set = nw_frame_counter_set; controller->nw_frame_counter_read = nw_frame_counter_read; controller->pan_ver_increment = pan_ver_increment; - + controller->nw_info_updated = nw_info_updated; + controller->auth_next_target = auth_next_target; return 0; } @@ -284,6 +262,20 @@ int8_t ws_pae_controller_set_target(protocol_interface_info_entry_t *interface_p return 0; } +static void ws_pae_controller_keys_nw_info_init(sec_prot_keys_nw_info_t *sec_keys_nw_info, sec_prot_gtk_keys_t *gtks) +{ + if (!sec_keys_nw_info) { + return; + } + + memset(sec_keys_nw_info, 0, sizeof(sec_prot_keys_nw_info_t)); + + sec_keys_nw_info->gtks = gtks; + sec_keys_nw_info->new_pan_id = 0xFFFF; + sec_keys_nw_info->key_pan_id = 0xFFFF; + sec_keys_nw_info->updated = false; +} + int8_t ws_pae_controller_nw_info_set(protocol_interface_info_entry_t *interface_ptr, uint16_t pan_id, char *network_name) { (void) pan_id; @@ -298,12 +290,44 @@ int8_t ws_pae_controller_nw_info_set(protocol_interface_info_entry_t *interface_ return -1; } - controller->network_name = network_name; + // Network name has been modified + if (network_name && strncmp(controller->sec_keys_nw_info.network_name, network_name, 33) != 0) { + strncpy(controller->sec_keys_nw_info.network_name, network_name, 32); + controller->sec_keys_nw_info.updated = true; + } - return ws_pae_supp_nw_info_set(interface_ptr, pan_id, network_name); + // PAN ID has been modified + if (pan_id != 0xffff && pan_id != controller->sec_keys_nw_info.new_pan_id) { + controller->sec_keys_nw_info.new_pan_id = pan_id; + controller->sec_keys_nw_info.updated = true; + } + + if (controller->pae_nw_info_set) { + controller->pae_nw_info_set(interface_ptr, pan_id, network_name); + } + + return 0; } -int8_t ws_pae_controller_nw_key_valid(protocol_interface_info_entry_t *interface_ptr) +static void ws_pae_controller_nw_info_updated_check(protocol_interface_info_entry_t *interface_ptr) +{ + if (!interface_ptr) { + return; + } + + pae_controller_t *controller = ws_pae_controller_get(interface_ptr); + if (!controller) { + return; + } + + if (controller->sec_keys_nw_info.updated || sec_prot_keys_gtks_are_updated(controller->sec_keys_nw_info.gtks)) { + ws_pae_controller_nvm_nw_info_write(interface_ptr, controller->sec_keys_nw_info.key_pan_id, controller->sec_keys_nw_info.network_name, controller->sec_keys_nw_info.gtks); + controller->sec_keys_nw_info.updated = false; + sec_prot_keys_gtks_updated_reset(controller->sec_keys_nw_info.gtks); + } +} + +int8_t ws_pae_controller_nw_key_valid(protocol_interface_info_entry_t *interface_ptr, uint8_t *br_iid) { if (!interface_ptr) { return -1; @@ -314,7 +338,7 @@ int8_t ws_pae_controller_nw_key_valid(protocol_interface_info_entry_t *interface return -1; } - return ws_pae_supp_nw_key_valid(interface_ptr); + return ws_pae_supp_nw_key_valid(interface_ptr, br_iid); } static int8_t ws_pae_controller_nw_key_check_and_insert(protocol_interface_info_entry_t *interface_ptr, sec_prot_gtk_keys_t *gtks) @@ -366,21 +390,21 @@ static int8_t ws_pae_controller_nw_key_check_and_insert(protocol_interface_info_ sec_prot_keys_gtk_hash_generate(gtk, gtkhash); tr_info("NW key set: %i, hash: %s", i, trace_array(gtkhash, 8)); uint8_t gak[GTK_LEN]; - if (ws_pae_controller_gak_from_gtk(gak, gtk, controller->network_name) >= 0) { + if (ws_pae_controller_gak_from_gtk(gak, gtk, controller->sec_keys_nw_info.network_name) >= 0) { // Install the new network key derived from GTK and network name (GAK) to MAC controller->nw_key_set(interface_ptr, i, i, gak); nw_key[i].installed = true; ret = 0; #ifdef EXTRA_DEBUG_INFO - tr_info("NW name: %s", controller->network_name); - size_t nw_name_len = strlen(controller->network_name); - tr_info("NW name: %s", trace_array((uint8_t *)controller->network_name, nw_name_len)); + tr_info("NW name: %s", controller->sec_keys_nw_info.network_name); + size_t nw_name_len = strlen(controller->sec_keys_nw_info.network_name); + tr_info("NW name: %s", trace_array((uint8_t *)controller->sec_keys_nw_info.network_name, nw_name_len)); tr_info("GTK: %s", trace_array(gtk, 16)); tr_info("GAK: %s", trace_array(gak, 16)); #endif } else { - tr_error("GAK generation failed network name: %s", controller->network_name); + tr_error("GAK generation failed network name: %s", controller->sec_keys_nw_info.network_name); continue; } @@ -512,6 +536,7 @@ static void ws_pae_controller_frame_counter_store_and_nw_keys_remove(protocol_in } } +#ifdef HAVE_PAE_AUTH static void ws_pae_controller_nw_key_index_check_and_set(protocol_interface_info_entry_t *interface_ptr, uint8_t index) { pae_controller_t *controller = ws_pae_controller_get(interface_ptr); @@ -534,6 +559,7 @@ static void ws_pae_controller_nw_key_index_check_and_set(protocol_interface_info controller->key_index_set = true; } } +#endif static void ws_pae_controller_active_nw_key_set(protocol_interface_info_entry_t *cur, uint8_t index) { @@ -564,11 +590,9 @@ int8_t ws_pae_controller_init(protocol_interface_info_entry_t *interface_ptr) } pae_controller_t *controller = ns_dyn_mem_alloc(sizeof(pae_controller_t)); - void *pae_nvm_buffer = ws_pae_buffer_allocate(); - if (!controller || !pae_nvm_buffer) { + if (!controller) { ns_dyn_mem_free(controller); - ns_dyn_mem_free(pae_nvm_buffer); return -1; } @@ -579,7 +603,9 @@ int8_t ws_pae_controller_init(protocol_interface_info_entry_t *interface_ptr) controller->nw_send_key_index_set = NULL; controller->nw_frame_counter_set = NULL; controller->pan_ver_increment = NULL; - controller->pae_nvm_buffer = pae_nvm_buffer; + controller->nw_info_updated = NULL; + controller->auth_next_target = NULL; + memset(&controller->sec_timer_cfg, 0, sizeof(ws_sec_timer_cfg_t)); memset(&controller->sec_prot_cfg, 0, sizeof(sec_prot_cfg_t)); @@ -603,7 +629,15 @@ int8_t ws_pae_controller_configure(protocol_interface_info_entry_t *interface_pt controller->sec_prot_cfg.sec_prot_trickle_params.k = 0; controller->sec_prot_cfg.sec_prot_trickle_params.TimerExpirations = sec_prot_cfg->sec_prot_trickle_timer_exp; controller->sec_prot_cfg.sec_prot_retry_timeout = sec_prot_cfg->sec_prot_retry_timeout * 10; + controller->sec_prot_cfg.sec_max_ongoing_authentication = sec_prot_cfg->sec_max_ongoing_authentication; + + controller->sec_prot_cfg.initial_key_retry_delay = sec_prot_cfg->initial_key_retry_delay; + controller->sec_prot_cfg.initial_key_trickle_params.Imin = sec_prot_cfg->initial_key_imin; + controller->sec_prot_cfg.initial_key_trickle_params.Imax = sec_prot_cfg->initial_key_imax; + controller->sec_prot_cfg.initial_key_trickle_params.k = 0; + controller->sec_prot_cfg.initial_key_trickle_params.TimerExpirations = 2; + controller->sec_prot_cfg.initial_key_retry_cnt = sec_prot_cfg->initial_key_retry_cnt; } if (sec_timer_cfg) { @@ -613,7 +647,6 @@ int8_t ws_pae_controller_configure(protocol_interface_info_entry_t *interface_pt return 0; } - static void ws_pae_controller_data_init(pae_controller_t *controller) { memset(controller->target_eui_64, 0, 8); @@ -634,29 +667,43 @@ static void ws_pae_controller_data_init(pae_controller_t *controller) controller->pae_gtks_updated = NULL; controller->pae_gtk_hash_update = NULL; controller->pae_nw_key_index_update = NULL; + controller->pae_nw_info_set = NULL; controller->gtks_set = false; controller->gtkhash_set = false; controller->key_index_set = false; controller->frame_counter_read = false; controller->gtk_index = -1; - controller->network_name = NULL; controller->frame_cnt_store_timer = FRAME_COUNTER_STORE_INTERVAL; + controller->frame_cnt_store_force_timer = FRAME_COUNTER_STORE_FORCE_INTERVAL; + controller->restart_cnt = 0; ws_pae_controller_frame_counter_reset(&controller->frame_counters); sec_prot_keys_gtks_init(&controller->gtks); sec_prot_keys_gtks_init(&controller->next_gtks); sec_prot_certs_init(&controller->certs); sec_prot_certs_ext_certificate_validation_set(&controller->certs, pae_controller_config.ext_cert_valid_enabled); + ws_pae_controller_keys_nw_info_init(&controller->sec_keys_nw_info, &controller->gtks); } -static void ws_pae_controller_frame_counter_read(pae_controller_t *controller) +static int8_t ws_pae_controller_frame_counter_read(pae_controller_t *controller) { + int8_t ret_value = 0; + if (controller->frame_counter_read) { - return; + return ret_value; } controller->frame_counter_read = true; + uint64_t stored_time = 0; + // Read frame counters - if (ws_pae_controller_nvm_frame_counter_read(&controller->frame_counters) >= 0) { + if (ws_pae_controller_nvm_frame_counter_read(&controller->restart_cnt, &stored_time, &controller->frame_counters) >= 0) { + // Current time is not valid + if (ws_pae_current_time_set(stored_time) < 0) { + ret_value = -1; + } + // This is used to ensure that PMK replay counters are fresh after each re-start. + controller->restart_cnt++; + bool updated = false; // Checks frame counters for (uint8_t index = 0; index < GTK_NUM; index++) { @@ -673,10 +720,12 @@ static void ws_pae_controller_frame_counter_read(pae_controller_t *controller) } if (updated) { // Writes incremented frame counters - ws_pae_nvm_store_frame_counter_tlv_create(controller->pae_nvm_buffer, &controller->frame_counters); - ws_pae_controller_nvm_frame_counter_write(controller->pae_nvm_buffer); + ws_pae_nvm_store_frame_counter_tlv_create((nvm_tlv_t *) &controller->pae_nvm_buffer, controller->restart_cnt, &controller->frame_counters); + ws_pae_controller_nvm_frame_counter_write((nvm_tlv_t *) &controller->pae_nvm_buffer); } } + + return ret_value; } static void ws_pae_controller_frame_counter_reset(frame_counters_t *frame_counters) @@ -689,6 +738,53 @@ static void ws_pae_controller_frame_counter_reset(frame_counters_t *frame_counte } } +static int8_t ws_pae_controller_nw_info_read(pae_controller_t *controller, sec_prot_gtk_keys_t *gtks) +{ + if (ws_pae_controller_nvm_nw_info_read(controller->interface_ptr, &controller->sec_keys_nw_info.key_pan_id, controller->sec_keys_nw_info.network_name, gtks) < 0) { + // If no stored GTKs and network info (pan_id and network name) exits + return -1; + } + + // Sets also new pan_id used for pan_id set by bootstrap + controller->sec_keys_nw_info.new_pan_id = controller->sec_keys_nw_info.key_pan_id; + + return 0; +} + +static int8_t ws_pae_controller_nvm_nw_info_write(protocol_interface_info_entry_t *interface_ptr, uint16_t pan_id, char *network_name, sec_prot_gtk_keys_t *gtks) +{ + nvm_tlv_t *tlv = ws_pae_controller_nvm_tlv_get(interface_ptr); + if (!tlv) { + return -1; + } + + ws_pae_nvm_store_nw_info_tlv_create(tlv, pan_id, network_name, gtks); + + ws_pae_nvm_store_tlv_file_write(NW_INFO_FILE, tlv); + + return 0; +} + +static int8_t ws_pae_controller_nvm_nw_info_read(protocol_interface_info_entry_t *interface_ptr, uint16_t *pan_id, char *network_name, sec_prot_gtk_keys_t *gtks) +{ + nvm_tlv_t *tlv_entry = ws_pae_controller_nvm_tlv_get(interface_ptr); + if (!tlv_entry) { + return -1; + } + + ws_pae_nvm_store_generic_tlv_create(tlv_entry, PAE_NVM_NW_INFO_TAG, PAE_NVM_NW_INFO_LEN); + + if (ws_pae_nvm_store_tlv_file_read(NW_INFO_FILE, tlv_entry) < 0) { + return -1; + } + + if (ws_pae_nvm_store_nw_info_tlv_read(tlv_entry, pan_id, network_name, gtks) < 0) { + return -1; + } + + return 0; +} + int8_t ws_pae_controller_supp_init(protocol_interface_info_entry_t *interface_ptr) { pae_controller_t *controller = ws_pae_controller_get(interface_ptr); @@ -696,7 +792,7 @@ int8_t ws_pae_controller_supp_init(protocol_interface_info_entry_t *interface_pt return -1; } - if (ws_pae_supp_init(controller->interface_ptr, &controller->certs, &controller->sec_timer_cfg, &controller->sec_prot_cfg) < 0) { + if (ws_pae_supp_init(controller->interface_ptr, &controller->certs, &controller->sec_timer_cfg, &controller->sec_prot_cfg, &controller->sec_keys_nw_info) < 0) { return -1; } @@ -707,10 +803,14 @@ int8_t ws_pae_controller_supp_init(protocol_interface_info_entry_t *interface_pt controller->pae_br_addr_read = ws_pae_supp_border_router_addr_read; controller->pae_gtk_hash_update = ws_pae_supp_gtk_hash_update; controller->pae_nw_key_index_update = ws_pae_supp_nw_key_index_update; + controller->pae_nw_info_set = NULL; - ws_pae_supp_cb_register(controller->interface_ptr, controller->auth_completed, ws_pae_controller_nw_key_check_and_insert, ws_pae_controller_active_nw_key_set, ws_pae_controller_gtk_hash_ptr_get); + ws_pae_supp_cb_register(controller->interface_ptr, controller->auth_completed, controller->auth_next_target, ws_pae_controller_nw_key_check_and_insert, ws_pae_controller_active_nw_key_set, ws_pae_controller_gtk_hash_ptr_get, ws_pae_controller_nw_info_updated_check); ws_pae_controller_frame_counter_read(controller); + ws_pae_controller_nw_info_read(controller, controller->sec_keys_nw_info.gtks); + // Set active key back to fresh so that it can be used again after re-start + sec_prot_keys_gtk_status_active_to_fresh_set(&controller->gtks); return 0; } @@ -722,7 +822,7 @@ int8_t ws_pae_controller_auth_init(protocol_interface_info_entry_t *interface_pt return -1; } - if (ws_pae_auth_init(controller->interface_ptr, &controller->gtks, &controller->next_gtks, &controller->certs, &controller->sec_timer_cfg, &controller->sec_prot_cfg) < 0) { + if (ws_pae_auth_init(controller->interface_ptr, &controller->next_gtks, &controller->certs, &controller->sec_timer_cfg, &controller->sec_prot_cfg, &controller->sec_keys_nw_info) < 0) { return -1; } @@ -731,8 +831,45 @@ int8_t ws_pae_controller_auth_init(protocol_interface_info_entry_t *interface_pt controller->pae_slow_timer = ws_pae_auth_slow_timer; controller->pae_gtks_updated = ws_pae_auth_gtks_updated; controller->pae_nw_key_index_update = ws_pae_auth_nw_key_index_update; + controller->pae_nw_info_set = ws_pae_auth_nw_info_set; - ws_pae_controller_frame_counter_read(controller); + sec_prot_gtk_keys_t *read_gtks_to = controller->sec_keys_nw_info.gtks; + if (ws_pae_controller_frame_counter_read(controller) < 0) { + tr_error("Stored key material invalid"); + // Key material invalid, do not read GTKs or any other security data + read_gtks_to = NULL; + } + +#ifdef HAVE_PAE_AUTH + if (sec_prot_keys_gtks_are_updated(&controller->gtks)) { + // If application has set GTK keys prepare those for use + ws_pae_auth_gtks_updated(interface_ptr); + if (controller->gtk_index >= 0) { + controller->pae_nw_key_index_update(interface_ptr, controller->gtk_index); + } + sec_prot_keys_gtks_updated_reset(&controller->gtks); + } +#endif + + if (ws_pae_controller_nw_info_read(controller, read_gtks_to) >= 0) { + /* If network information i.e pan_id and network name exists updates bootstrap with it, + (in case already configured by application then no changes are made) */ + if (controller->nw_info_updated) { + controller->nw_info_updated(interface_ptr, controller->sec_keys_nw_info.key_pan_id, controller->sec_keys_nw_info.network_name); + } + if (!read_gtks_to || sec_prot_keys_gtk_count(read_gtks_to) == 0) { + // Key material invalid or GTKs are expired, delete GTKs from NVM + ws_pae_controller_nvm_nw_info_write(controller->interface_ptr, controller->sec_keys_nw_info.key_pan_id, controller->sec_keys_nw_info.network_name, NULL); + } + } + + ws_pae_key_storage_init(); + if (read_gtks_to) { + ws_pae_key_storage_read(controller->restart_cnt); + } else { + // Key material invalid, delete key storage + ws_pae_key_storage_remove(); + } return 0; } @@ -747,6 +884,15 @@ int8_t ws_pae_controller_stop(protocol_interface_info_entry_t *interface_ptr) // Stores frame counters and removes network keys from PAE controller and MAC ws_pae_controller_frame_counter_store_and_nw_keys_remove(interface_ptr, controller, false); + // Store security key network info if it has been modified + ws_pae_controller_nw_info_updated_check(interface_ptr); + + // Store key storage if it has been modified + ws_pae_key_storage_store(); + + // Delete key storage + ws_pae_key_storage_delete(); + // If PAE has been initialized, deletes it if (controller->pae_delete) { controller->pae_delete(interface_ptr); @@ -775,7 +921,6 @@ int8_t ws_pae_controller_delete(protocol_interface_info_entry_t *interface_ptr) } ns_list_remove(&pae_controller_list, controller); - ns_dyn_mem_free(controller->pae_nvm_buffer); ns_dyn_mem_free(controller); return 0; @@ -1028,6 +1173,10 @@ int8_t ws_pae_controller_gtk_update(int8_t interface_id, uint8_t *gtk[GTK_NUM]) } } + // Sets active key + int8_t index = sec_prot_keys_gtk_install_order_first_index_get(&controller->gtks); + sec_prot_keys_gtk_status_active_set(&controller->gtks, index); + // Notifies PAE authenticator that GTKs have been updated */ if (controller->pae_gtks_updated) { controller->pae_gtks_updated(controller->interface_ptr); @@ -1234,6 +1383,13 @@ static void ws_pae_controller_frame_counter_timer(uint16_t seconds, pae_controll entry->frame_cnt_store_timer = FRAME_COUNTER_STORE_INTERVAL; ws_pae_controller_frame_counter_store(entry, true); } + + if (entry->frame_cnt_store_force_timer > seconds) { + entry->frame_cnt_store_force_timer -= seconds; + } else { + entry->frame_cnt_store_force_timer = 0; + ws_pae_controller_frame_counter_store(entry, true); + } } static void ws_pae_controller_frame_counter_timer_trigger(uint16_t seconds, pae_controller_t *entry) @@ -1287,33 +1443,38 @@ static void ws_pae_controller_frame_counter_store(pae_controller_t *entry, bool } } - if (update_needed) { + if (update_needed || entry->frame_cnt_store_force_timer == 0) { tr_debug("Write frame counters: system time %"PRIu32"", protocol_core_monotonic_time / 10); // Writes modified frame counters - ws_pae_nvm_store_frame_counter_tlv_create(entry->pae_nvm_buffer, &entry->frame_counters); - ws_pae_controller_nvm_frame_counter_write(entry->pae_nvm_buffer); + ws_pae_nvm_store_frame_counter_tlv_create((nvm_tlv_t *) &entry->pae_nvm_buffer, entry->restart_cnt, &entry->frame_counters); + ws_pae_controller_nvm_frame_counter_write((nvm_tlv_t *) &entry->pae_nvm_buffer); + + // Reset force interval when ever values are stored + entry->frame_cnt_store_force_timer = FRAME_COUNTER_STORE_FORCE_INTERVAL; } } -static int8_t ws_pae_controller_nvm_frame_counter_read(frame_counters_t *counters) +static int8_t ws_pae_controller_nvm_frame_counter_read(uint32_t *restart_cnt, uint64_t *stored_time, frame_counters_t *counters) { - nvm_tlv_list_t tlv_list; - ns_list_init(&tlv_list); - - if (ws_pae_nvm_store_tlv_file_read(FRAME_COUNTER_FILE, &tlv_list) < 0) { + nvm_tlv_t *tlv = ws_pae_nvm_store_generic_tlv_allocate_and_create( + PAE_NVM_FRAME_COUNTER_TAG, PAE_NVM_FRAME_COUNTER_LEN); + if (!tlv) { return -1; } - int8_t result = -1; - ns_list_foreach_safe(nvm_tlv_entry_t, entry, &tlv_list) { - if (ws_pae_nvm_store_frame_counter_tlv_read(entry, counters) >= 0) { - result = 0; - } - ns_list_remove(&tlv_list, entry); - ns_dyn_mem_free(entry); + if (ws_pae_nvm_store_tlv_file_read(FRAME_COUNTER_FILE, tlv) < 0) { + ws_pae_nvm_store_generic_tlv_free(tlv); + return -1; } - return result; + if (ws_pae_nvm_store_frame_counter_tlv_read(tlv, restart_cnt, stored_time, counters) < 0) { + ws_pae_nvm_store_generic_tlv_free(tlv); + return -1; + } + + ws_pae_nvm_store_generic_tlv_free(tlv); + + return 0; } static pae_controller_t *ws_pae_controller_get(protocol_interface_info_entry_t *interface_ptr) @@ -1346,22 +1507,19 @@ static pae_controller_t *ws_pae_controller_get_or_create(int8_t interface_id) return controller; } -nvm_tlv_entry_t *ws_pae_controller_nvm_tlv_get(protocol_interface_info_entry_t *interface_ptr) +nvm_tlv_t *ws_pae_controller_nvm_tlv_get(protocol_interface_info_entry_t *interface_ptr) { pae_controller_t *controller = ws_pae_controller_get(interface_ptr); if (!controller) { return NULL; } - return controller->pae_nvm_buffer; + return (nvm_tlv_t *) &controller->pae_nvm_buffer; } -static void ws_pae_controller_nvm_frame_counter_write(nvm_tlv_entry_t *tlv_entry) +static void ws_pae_controller_nvm_frame_counter_write(nvm_tlv_t *tlv_entry) { - nvm_tlv_list_t tlv_list; - ns_list_init(&tlv_list); - ns_list_add_to_end(&tlv_list, tlv_entry); - ws_pae_nvm_store_tlv_file_write(FRAME_COUNTER_FILE, &tlv_list); + ws_pae_nvm_store_tlv_file_write(FRAME_COUNTER_FILE, tlv_entry); } diff --git a/source/6LoWPAN/ws/ws_pae_controller.h b/source/6LoWPAN/ws/ws_pae_controller.h index 9a16b769d1..2f7e01e6df 100644 --- a/source/6LoWPAN/ws/ws_pae_controller.h +++ b/source/6LoWPAN/ws/ws_pae_controller.h @@ -249,12 +249,13 @@ int8_t ws_pae_controller_nw_info_set(protocol_interface_info_entry_t *interface_ * ws_pae_controller_nw_key_valid network key is valid i.e. used successfully on bootstrap * * \param interface_ptr interface + * \param br_iid border router IID for which the keys are valid * * \return < 0 failure * \return >= 0 success * */ -int8_t ws_pae_controller_nw_key_valid(protocol_interface_info_entry_t *interface_ptr); +int8_t ws_pae_controller_nw_key_valid(protocol_interface_info_entry_t *interface_ptr, uint8_t *br_iid); /** * ws_pae_controller_border_router_addr_write write border router address @@ -278,7 +279,7 @@ int8_t ws_pae_controller_border_router_addr_write(protocol_interface_info_entry_ * \return >= 0 success * */ -int8_t ws_pae_controller_border_router_addr_read(protocol_interface_info_entry_t *interface_ptr, uint8_t *eui_64); +int8_t ws_pae_controller_border_router_addr_read(protocol_interface_info_entry_t *interface_ptr, uint8_t *iid); /** * ws_pae_controller_gtk_update update GTKs (test interface) @@ -492,6 +493,18 @@ typedef void ws_pae_controller_nw_frame_counter_read(protocol_interface_info_ent */ typedef void ws_pae_controller_auth_completed(protocol_interface_info_entry_t *interface_ptr, auth_result_e result, uint8_t *target_eui_64); +/** + * ws_pae_controller_auth_next_target get next target to attempt authentication + * + * \param interface_ptr interface + * \param previous_eui_64 EUI-64 of previous target + * \param pan_id pan id + * + * \return EUI-64 of the next target or previous target if new one not available + * + */ +typedef const uint8_t *ws_pae_controller_auth_next_target(protocol_interface_info_entry_t *interface_ptr, const uint8_t *previous_eui_64, uint16_t *pan_id); + /** * ws_pae_controller_pan_ver_increment PAN version increment callback * @@ -500,23 +513,35 @@ typedef void ws_pae_controller_auth_completed(protocol_interface_info_entry_t *i */ typedef void ws_pae_controller_pan_ver_increment(protocol_interface_info_entry_t *interface_ptr); +/** + * ws_pae_controller_nw_info_updated network information is updated (read from memory) + * + * \param interface_ptr interface + * \param pan_id PAN ID + * \param network_name network name + * + */ +typedef void ws_pae_controller_nw_info_updated(protocol_interface_info_entry_t *interface_ptr, uint16_t pan_id, char *network_name); + /** * ws_pae_controller_cb_register register PEA controller callbacks * * \param interface_ptr interface * \param completed authentication completed callback + * \param next_target authentication next target callback * \param nw_key_set network key set callback * \param nw_key_clear network key clear callback * \param nw_send_key_index_set network send key index set callback * \param nw_frame_counter_set network frame counter set callback * \param nw_frame_counter_read network frame counter read callback * \param pan_ver_increment PAN version increment callback + * \param nw_info_updated network information updated callback * * \return < 0 failure * \return >= 0 success * */ -int8_t ws_pae_controller_cb_register(protocol_interface_info_entry_t *interface_ptr, ws_pae_controller_auth_completed *completed, ws_pae_controller_nw_key_set *nw_key_set, ws_pae_controller_nw_key_clear *nw_key_clear, ws_pae_controller_nw_send_key_index_set *nw_send_key_index_set, ws_pae_controller_nw_frame_counter_set *nw_frame_counter_set, ws_pae_controller_nw_frame_counter_read *nw_frame_counter_read, ws_pae_controller_pan_ver_increment *pan_ver_increment); +int8_t ws_pae_controller_cb_register(protocol_interface_info_entry_t *interface_ptr, ws_pae_controller_auth_completed *completed, ws_pae_controller_auth_next_target *auth_next_target, ws_pae_controller_nw_key_set *nw_key_set, ws_pae_controller_nw_key_clear *nw_key_clear, ws_pae_controller_nw_send_key_index_set *nw_send_key_index_set, ws_pae_controller_nw_frame_counter_set *nw_frame_counter_set, ws_pae_controller_nw_frame_counter_read *nw_frame_counter_read, ws_pae_controller_pan_ver_increment *pan_ver_increment, ws_pae_controller_nw_info_updated *nw_info_updated); /** * ws_pae_controller_fast_timer PAE controller fast timer call @@ -534,7 +559,7 @@ void ws_pae_controller_fast_timer(uint16_t ticks); */ void ws_pae_controller_slow_timer(uint16_t seconds); -struct nvm_tlv_entry *ws_pae_controller_nvm_tlv_get(protocol_interface_info_entry_t *interface_ptr); +struct nvm_tlv *ws_pae_controller_nvm_tlv_get(protocol_interface_info_entry_t *interface_ptr); /** * ws_pae_controller_forced_gc PAE controller garbage cleanup callback diff --git a/source/6LoWPAN/ws/ws_pae_key_storage.c b/source/6LoWPAN/ws/ws_pae_key_storage.c new file mode 100644 index 0000000000..b50dfb0302 --- /dev/null +++ b/source/6LoWPAN/ws/ws_pae_key_storage.c @@ -0,0 +1,1002 @@ +/* + * 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 +#include "ns_types.h" +#include "ns_list.h" +#include "ns_trace.h" +#include "nsdynmemLIB.h" +#include "fhss_config.h" +#include "NWK_INTERFACE/Include/protocol.h" +#include "6LoWPAN/ws/ws_config.h" +#include "Security/protocols/sec_prot_cfg.h" +#include "Security/kmp/kmp_addr.h" +#include "Security/kmp/kmp_api.h" +#include "Security/kmp/kmp_socket_if.h" +#include "Security/protocols/sec_prot_certs.h" +#include "Security/protocols/sec_prot_keys.h" +#include "6LoWPAN/ws/ws_cfg_settings.h" +#include "6LoWPAN/ws/ws_pae_controller.h" +#include "6LoWPAN/ws/ws_pae_timers.h" +#include "6LoWPAN/ws/ws_pae_auth.h" +#include "6LoWPAN/ws/ws_pae_lib.h" +#include "6LoWPAN/ws/ws_pae_nvm_store.h" +#include "6LoWPAN/ws/ws_pae_nvm_data.h" +#include "6LoWPAN/ws/ws_pae_time.h" +#include "6LoWPAN/ws/ws_pae_key_storage.h" + +#ifdef HAVE_WS + +#define TRACE_GROUP "wsks" + +#define KEY_STORAGE_INDEX_FILE "key_storage_index" +#define KEY_STORAGE_FILE "key_storage_00" +#define KEY_STORAGE_FILE_LEN sizeof(KEY_STORAGE_FILE) + +// Storage array header size +#define STORAGE_ARRAY_HEADER_LEN sizeof(key_storage_nvm_tlv_entry_t) + +// Update the key storage reference time on write operations, if entry reference time differs more than a day +#define KEY_STORAGE_REF_TIME_UPDATE_THRESHOLD 86400 + +/* Force key storage reference time update, if reference time differs more 31 days */ +#define KEY_STORAGE_REF_TIME_UPDATE_FORCE_THRESHOLD GTK_DEFAULT_LIFETIME + 86400 + +typedef enum { + WRITE_SET = 0, + TIME_SET, + PMK_CNT_SET, + PMK_SET, + PTK_SET, + EUI64_SET, + PTKEUI64_SET, + GTKHASH_SET, + GTKHASH4WH_SET, + PMKLTIME_SET, + PTKLTIME_SET, +} field_set_t; + +#define FIELD_SET(field) (field_set | (1 << field)) +#define FIELD_IS_SET(field) (field_set & (1 << field)) + +typedef struct { + ns_list_link_t link; /**< Link */ + const void *instance; /**< Instance; for support of multiple authenticators */ + key_storage_nvm_tlv_entry_t *storage_array_handle; /**< Key storage array handle (NVM header + array) */ + sec_prot_keys_storage_t *storage_array; /**< Key storage array */ + uint16_t size; /**< Array size in bytes */ + uint16_t entries; /**< Entries in array */ + uint16_t free_entries; /**< Free entries in array */ + bool allocated : 1; /**< Allocated */ + bool modified : 1; /**< Array modified */ +} key_storage_array_t; + +typedef struct { + uint8_t settings_set; /**< Settings set, do not use defaults */ + uint8_t storages_empty; /**< Number of empty i.e. to be allocated storages */ + uint16_t storage_default_size; /**< Default size for storages */ + uint16_t replace_index; /**< Index to replace when storages are full */ + uint64_t store_bitfield; /**< Bitfield of stored files */ + uint16_t store_timer_timeout; /**< Storing timing timeout */ + uint16_t store_timer; /**< Storing timer */ + uint32_t restart_cnt; /**< Re-start counter */ +} key_storage_params_t; + +static key_storage_params_t key_storage_params; + +static NS_LIST_DEFINE(key_storage_array_list, key_storage_array_t, link); + +static int8_t ws_pae_key_storage_allocate(const void *instance, uint16_t key_storage_size, void *storage); +static void ws_pae_key_storage_clear(key_storage_array_t *key_storage_array); +static void ws_pae_key_storage_list_all_free(void); +static sec_prot_keys_storage_t *ws_pae_key_storage_get(const void *instance, const uint8_t *eui64, key_storage_array_t **key_storage_array, bool return_free); +static sec_prot_keys_storage_t *ws_pae_key_storage_replace(const void *instance, key_storage_array_t **key_storage_array); +static void ws_pae_key_storage_trace(uint16_t field_set, sec_prot_keys_storage_t *key_storage, key_storage_array_t *key_storage_array); +static void ws_pae_key_storage_timer_expiry_set(void); +static int8_t ws_pae_key_storage_array_time_update_entry(uint64_t time_difference, sec_prot_keys_storage_t *storage_array_entry); +static int8_t ws_pae_key_storage_array_time_check_and_update_all(key_storage_array_t *key_storage_array, bool modified); +static int8_t ws_pae_key_storage_array_counters_check_and_update_all(key_storage_array_t *key_storage_array); +static int8_t ws_pae_key_storage_array_lifetime_update(uint32_t time_difference, uint16_t *lifetime); +static int8_t ws_pae_key_storage_array_lifetime_get(uint32_t time_difference, uint16_t short_lifetime, uint32_t *lifetime); +static void ws_pae_key_storage_array_pmk_invalid(sec_prot_keys_storage_t *storage_array); +static void ws_pae_key_storage_array_ptk_invalid(sec_prot_keys_storage_t *storage_array); + +static void ws_pae_key_storage_filename_set(char *file_name, uint8_t file_number) +{ + // Name is "key_storage_00" where 00 is replaced by file number + strcpy(file_name, KEY_STORAGE_FILE); + file_name[12] = (file_number / 10) + 'A'; // 0 is ASCII 'A', 1='B',..., F='P' + file_name[13] = (file_number % 10) + 'A'; // same as above +} + +int8_t ws_pae_key_storage_memory_set(uint8_t key_storages_number, const uint16_t *key_storage_size, void **key_storages) +{ + for (uint8_t index = 0; index < key_storages_number; index++) { + if (ws_pae_key_storage_allocate(NULL, key_storage_size[index], (sec_prot_keys_storage_t *) key_storages[index]) < 0) { + return -1; + } + } + + key_storage_params.storages_empty = 0; + + return 0; +} + +int8_t ws_pae_key_storage_settings_set(uint8_t alloc_max_number, uint16_t alloc_size, uint16_t storing_interval) +{ + key_storage_params.settings_set = true; + key_storage_params.storages_empty = alloc_max_number; + key_storage_params.storage_default_size = alloc_size; + key_storage_params.store_timer = storing_interval; + key_storage_params.store_timer_timeout = storing_interval; + + return 0; +} + +void ws_pae_key_storage_init(void) +{ + if (!key_storage_params.settings_set) { + key_storage_params.storages_empty = DEFAULT_NUMBER_OF_STORAGES; + key_storage_params.storage_default_size = STORAGE_ARRAY_HEADER_LEN + (sizeof(sec_prot_keys_storage_t) * DEFAULT_NUMBER_OF_ENTRIES_IN_ONE_STORAGE); + key_storage_params.store_timer = DEFAULT_STORING_INTERVAL; + key_storage_params.store_timer_timeout = DEFAULT_STORING_INTERVAL; + } + key_storage_params.replace_index = 0; + key_storage_params.store_bitfield = 0, + key_storage_params.restart_cnt = 0; +} + +void ws_pae_key_storage_delete(void) +{ + ws_pae_key_storage_list_all_free(); +} + +static int8_t ws_pae_key_storage_allocate(const void *instance, uint16_t key_storage_size, void *new_storage_array) +{ + key_storage_array_t *key_storage_array = ns_dyn_mem_alloc(sizeof(key_storage_array_t)); + if (!key_storage_array) { + return -1; + } + + if (new_storage_array == NULL) { + key_storage_array->storage_array_handle = ns_dyn_mem_alloc(key_storage_size); + if (!key_storage_array->storage_array_handle) { + return -1; + } + key_storage_array->allocated = true; + } else { + key_storage_array->storage_array_handle = new_storage_array; + key_storage_array->allocated = false; + } + key_storage_array->storage_array = (sec_prot_keys_storage_t *)(((uint8_t *)key_storage_array->storage_array_handle) + STORAGE_ARRAY_HEADER_LEN); + key_storage_array->size = key_storage_size; + key_storage_array->entries = (key_storage_size - STORAGE_ARRAY_HEADER_LEN) / sizeof(sec_prot_keys_storage_t); + key_storage_array->free_entries = key_storage_array->entries; + key_storage_array->instance = instance; + key_storage_array->modified = false; + + ws_pae_nvm_store_key_storage_tlv_create((nvm_tlv_t *) key_storage_array->storage_array_handle, key_storage_array->size); + + ws_pae_key_storage_clear(key_storage_array); + + ns_list_add_to_end(&key_storage_array_list, key_storage_array); + + tr_info("KeyS new %s, array: %p entries: %i", key_storage_array->allocated ? "allocated" : "static", (void *) key_storage_array->storage_array, key_storage_array->entries); + + return 0; +} + +static void ws_pae_key_storage_clear(key_storage_array_t *key_storage_array) +{ + key_storage_array->storage_array_handle->reference_time = ws_pae_current_time_get(); + key_storage_array->storage_array_handle->reference_restart_cnt = key_storage_params.restart_cnt; + + sec_prot_keys_storage_t *storage_array = (sec_prot_keys_storage_t *) key_storage_array->storage_array; + // Set all entries empty + for (uint16_t index = 0; index < key_storage_array->entries; index++) { + if (key_storage_array->allocated) { + memset(&storage_array[index], 0, sizeof(sec_prot_keys_storage_t)); + } + storage_array[index].eui_64_set = false; + } +} + +static void ws_pae_key_storage_list_all_free(void) +{ + ns_list_foreach_safe(key_storage_array_t, entry, &key_storage_array_list) { + if (entry->allocated) { + ns_dyn_mem_free(entry->storage_array_handle); + } + ns_list_remove(&key_storage_array_list, entry); + ns_dyn_mem_free(entry); + } +} + +static sec_prot_keys_storage_t *ws_pae_key_storage_get(const void *instance, const uint8_t *eui64, key_storage_array_t **key_storage_array, bool return_free) +{ + sec_prot_keys_storage_t *free_key_storage = NULL; + *key_storage_array = NULL; + uint16_t free_index = 0; + + ns_list_foreach(key_storage_array_t, entry, &key_storage_array_list) { + // Checks whether storage is for this authenticator + if (entry->instance != NULL && entry->instance != instance) { + tr_info("KeyS get instance other"); + continue; + } + // Checks entries in storage array + sec_prot_keys_storage_t *storage_array = (sec_prot_keys_storage_t *) entry->storage_array; + for (uint16_t index = 0; index < entry->entries; index++) { + if (!storage_array[index].eui_64_set) { + // Stores free array entry and initiates data on it to zero + if (return_free && free_key_storage == NULL) { + *key_storage_array = entry; + free_key_storage = &storage_array[index]; + memset(&storage_array[index], 0, sizeof(sec_prot_keys_storage_t)); + free_index = index; + } + continue; + } + // Searches for matching entry + if (memcmp(&storage_array[index].ptk_eui_64, eui64, 8) == 0) { + *key_storage_array = entry; + // If not already reserved for authenticator instance, reserve array for it + entry->instance = instance; + tr_info("KeyS get array: %p i: %i eui64: %s", (void *) entry->storage_array, index, tr_array(eui64, 8)); + return &storage_array[index]; + } + } + } + + // If not already reserved for authenticator instance, reserve array for it + if (free_key_storage != NULL && (*key_storage_array)->instance == NULL) { + (*key_storage_array)->instance = instance; + } + + tr_info("KeyS get array %s: %p i: %i free: %p eui64: %s", *key_storage_array ? "" : "(not alloc)", *key_storage_array ? (void *)(*key_storage_array)->storage_array : NULL, *key_storage_array ? free_index : 0, (void *)free_key_storage, tr_array(eui64, 8)); + // If matching entry is not found, returns free entry + return free_key_storage; +} + +bool ws_pae_key_storage_supp_delete(const void *instance, const uint8_t *eui64) +{ + (void) instance; + + bool deleted = false; + + ns_list_foreach(key_storage_array_t, entry, &key_storage_array_list) { + // Checks entries in storage array + sec_prot_keys_storage_t *storage_array = (sec_prot_keys_storage_t *) entry->storage_array; + for (uint16_t index = 0; index < entry->entries; index++) { + if (!storage_array[index].eui_64_set) { + continue; + } + // Searches for matching entry + if (memcmp(&storage_array[index].ptk_eui_64, eui64, 8) == 0) { + memset(&storage_array[index], 0, sizeof(sec_prot_keys_storage_t)); + tr_info("KeyS delete array: %p i: %i eui64: %s", (void *) entry->storage_array, index, tr_array(eui64, 8)); + entry->modified = true; + deleted = true; + } + } + } + + if (deleted) { + // Trigger storing to NVM right away to keep the stored data in sync + ws_pae_key_storage_timer_expiry_set(); + } + + return deleted; +} + +static sec_prot_keys_storage_t *ws_pae_key_storage_replace(const void *instance, key_storage_array_t **key_storage_array) +{ + uint16_t replace_index = key_storage_params.replace_index; + sec_prot_keys_storage_t *storage_array = NULL; + uint16_t storage_array_index = 0; + + ns_list_foreach(key_storage_array_t, entry, &key_storage_array_list) { + // Checks whether storage is for this authenticator + if (entry->instance != instance) { + continue; + } + // Finds correct key storage array + if (replace_index >= entry->entries) { + replace_index -= entry->entries; + continue; + } + if (key_storage_array) { + *key_storage_array = entry; + } + // Sets array and index and sets replace index to next + storage_array = (sec_prot_keys_storage_t *) entry->storage_array; + storage_array_index = replace_index; + key_storage_params.replace_index++; + + tr_info("KeyS replace array: %p i: %i eui64: %s", (void *) entry->storage_array, replace_index, tr_array(storage_array[replace_index].ptk_eui_64, 8)); + } + + // If replace index is not found it means that index has gone past the last entry + if (storage_array == NULL) { + /* Gets first key storage array and sets the array and sets index to zero and sets + (next) replace index to first */ + key_storage_array_t *key_storage_array_entry = ns_list_get_first(&key_storage_array_list); + if (key_storage_array_entry == NULL) { + return NULL; + } + if (key_storage_array) { + *key_storage_array = key_storage_array_entry; + } + storage_array = (sec_prot_keys_storage_t *) key_storage_array_entry->storage_array; + storage_array_index = 0; + key_storage_params.replace_index = 1; + + tr_info("KeyS replace array: %p i: %i eui64: %s", (void *) key_storage_array_entry->storage_array, storage_array_index, tr_array(key_storage_array_entry->storage_array[storage_array_index].ptk_eui_64, 8)); + } + + // Deletes any previous data + memset(&storage_array[storage_array_index], 0, sizeof(sec_prot_keys_storage_t)); + + return &storage_array[storage_array_index]; +} + +int8_t ws_pae_key_storage_supp_write(const void *instance, supp_entry_t *pae_supp) +{ + uint8_t *eui_64 = pae_supp->addr.eui_64; + + key_storage_array_t *key_storage_array; + sec_prot_keys_storage_t *key_storage = ws_pae_key_storage_get(instance, eui_64, &key_storage_array, true); + + // If cannot find existing or empty storage and there is room for storages tries to allocate more storage + if (key_storage == NULL && key_storage_params.storages_empty > 0) { + if (ws_pae_key_storage_allocate(instance, key_storage_params.storage_default_size, NULL) >= 0) { + key_storage_params.storages_empty--; + key_storage = ws_pae_key_storage_get(instance, eui_64, &key_storage_array, true); + } + } + + // If still cannot find empty storage, replaces old one + if (key_storage == NULL) { + key_storage = ws_pae_key_storage_replace(instance, &key_storage_array); + } + + // On failure exit + if (key_storage == NULL) { + return -1; + } + + // Calculate time difference between storage array reference time and current time + uint32_t time_difference; + if (ws_pae_time_diff_calc(ws_pae_current_time_get(), key_storage_array->storage_array_handle->reference_time, &time_difference, false) < 0) { + tr_error("KeyS write time err: %"PRIi64", ref: %"PRIi64", diff: %"PRIi32, ws_pae_current_time_get(), key_storage_array->storage_array_handle->reference_time, time_difference); + return -1; + } + + sec_prot_keys_t *sec_keys = &pae_supp->sec_keys; + + // If replay counter is near to exhaust delete PMK and PTK to refresh the counter + if (sec_keys->pmk_key_replay_cnt_set && (sec_keys->pmk_key_replay_cnt & PMK_KEY_REPLAY_CNT_LIMIT_MASK) >= PMK_KEY_REPLAY_CNT_LIMIT) { + tr_error("KeyS write PMK cnt limit eui64: %s", tr_array(eui_64, 8)); + sec_prot_keys_ptk_delete(&pae_supp->sec_keys); + sec_prot_keys_pmk_delete(&pae_supp->sec_keys); + } + + uint16_t field_set = 1 << WRITE_SET; + + if (key_storage->pmk_key_replay_cnt_set != sec_keys->pmk_key_replay_cnt_set || + key_storage->pmk_key_replay_cnt != sec_keys->pmk_key_replay_cnt) { + /* Does not set modified variable since counter updates are never stored to NVM. + Instead counter is increased on re-start. */ + key_storage->pmk_key_replay_cnt = sec_keys->pmk_key_replay_cnt & PMK_KEY_REPLAY_CNT_LIMIT_MASK; + key_storage->pmk_key_replay_cnt_set = sec_keys->pmk_key_replay_cnt_set; + field_set |= 1 << PMK_CNT_SET; + } + + if (key_storage->pmk_set != sec_keys->pmk_set || + memcmp(key_storage->pmk, sec_keys->pmk, PMK_LEN) != 0) { + key_storage_array->modified = true; + key_storage->pmk_set = sec_keys->pmk_set; + memcpy(key_storage->pmk, sec_keys->pmk, PMK_LEN); + field_set |= 1 << PMK_SET; + } + + if (key_storage->ptk_set != sec_keys->ptk_set || + memcmp(key_storage->ptk, sec_keys->ptk, PTK_LEN) != 0) { + key_storage_array->modified = true; + key_storage->ptk_set = sec_keys->ptk_set; + memcpy(key_storage->ptk, sec_keys->ptk, PTK_LEN); + field_set |= 1 << PTK_SET; + } + + if (key_storage->eui_64_set != true || + memcmp(key_storage->ptk_eui_64, eui_64, 8) != 0) { + key_storage_array->modified = true; + key_storage->eui_64_set = true; + memcpy(key_storage->ptk_eui_64, eui_64, 8); + field_set |= 1 << EUI64_SET; + } + + if (key_storage->ptk_eui_64_set != sec_keys->ptk_eui_64_set) { + key_storage_array->modified = true; + key_storage->ptk_eui_64_set = sec_keys->ptk_eui_64_set; + field_set |= 1 << PTKEUI64_SET; + } + + if (key_storage->ins_gtk_hash_set != sec_keys->ins_gtk_hash_set || + memcmp(key_storage->ins_gtk_hash, sec_keys->ins_gtk_hash, sizeof(sec_keys->ins_gtk_hash)) != 0) { + key_storage_array->modified = true; + key_storage->ins_gtk_hash_set = sec_keys->ins_gtk_hash_set; + memcpy(key_storage->ins_gtk_hash, sec_keys->ins_gtk_hash, sizeof(sec_keys->ins_gtk_hash)); + field_set |= 1 << GTKHASH_SET; + } + if (key_storage->ins_gtk_4wh_hash_set != sec_keys->ins_gtk_hash_set) { + key_storage->ins_gtk_4wh_hash_set = sec_keys->ins_gtk_hash_set; + field_set |= 1 << GTKHASH4WH_SET; + } + + if (sec_keys->pmk_set) { + // PMK lifetime is: time difference between reference and current time + lifetime + uint64_t pmk_lifetime = time_difference + sec_keys->pmk_lifetime; + if (pmk_lifetime > SEC_MAXIMUM_LIFETIME) { + pmk_lifetime = 0; + } + uint16_t short_time = ws_pae_time_to_short_convert(pmk_lifetime); + // Compares the time from active supplicant entry to stored one, and if time + if (!key_storage->pmk_lifetime_set || !ws_pae_time_from_short_time_compare(key_storage->pmk_lifetime, short_time)) { + key_storage_array->modified = true; + key_storage->pmk_lifetime_set = true; + key_storage->pmk_lifetime = short_time; + field_set |= 1 << PMKLTIME_SET; + } + } else { + key_storage->pmk_lifetime_set = false; + key_storage->pmk_lifetime = 0; + field_set |= 1 << PMKLTIME_SET; + } + + if (sec_keys->ptk_set) { + // PTK lifetime is: time difference between reference and current time + lifetime + uint64_t ptk_lifetime = time_difference + sec_keys->ptk_lifetime; + if (ptk_lifetime > SEC_MAXIMUM_LIFETIME) { + ptk_lifetime = 0; + } + uint16_t short_time = ws_pae_time_to_short_convert(ptk_lifetime); + if (!key_storage->ptk_lifetime_set || !ws_pae_time_from_short_time_compare(key_storage->ptk_lifetime, short_time)) { + key_storage_array->modified = true; + key_storage->ptk_lifetime_set = true; + key_storage->ptk_lifetime = short_time; + field_set |= 1 << PTKLTIME_SET; + } + } else { + key_storage->ptk_lifetime_set = false; + key_storage->ptk_lifetime = 0; + field_set |= 1 << PTKLTIME_SET; + } + + ws_pae_key_storage_trace(field_set, key_storage, key_storage_array); + + return 0; +} + +supp_entry_t *ws_pae_key_storage_supp_read(const void *instance, const uint8_t *eui_64, sec_prot_gtk_keys_t *gtks, const sec_prot_certs_t *certs) +{ + key_storage_array_t *key_storage_array; + sec_prot_keys_storage_t *key_storage = ws_pae_key_storage_get(instance, eui_64, &key_storage_array, false); + if (key_storage == NULL) { + return NULL; + } + + uint8_t pmk_invalid = false; + uint8_t ptk_invalid = false; + + uint16_t field_set = 0; + + // Calculate time difference between storage array reference time and current time + uint32_t time_difference; + if (ws_pae_time_diff_calc(ws_pae_current_time_get(), key_storage_array->storage_array_handle->reference_time, &time_difference, false) < 0) { + tr_error("KeyS read time err"); + pmk_invalid = true; + field_set |= 1 << TIME_SET; + } + + uint32_t pmk_lifetime = 0; + uint32_t ptk_lifetime = 0; + + if (!pmk_invalid) { + // Calculate PMK lifetime + if (ws_pae_key_storage_array_lifetime_get(time_difference, key_storage->pmk_lifetime, &pmk_lifetime) < 0) { + // PMK expired, all keys are invalid + pmk_invalid = true; + ptk_invalid = true; + field_set |= 1 << TIME_SET; + } + field_set |= 1 << PMKLTIME_SET; + } + + if (!pmk_invalid) { + // Calculate PTK lifetime + if (ws_pae_key_storage_array_lifetime_get(time_difference, key_storage->ptk_lifetime, &ptk_lifetime) < 0) { + // PMK expired, invalidate PTK related fields, PMK is still valid + ptk_invalid = true; + field_set |= 1 << TIME_SET; + } + field_set |= 1 << PTKLTIME_SET; + } + + supp_entry_t *pae_supp = ns_dyn_mem_temporary_alloc(sizeof(supp_entry_t)); + if (!pae_supp) { + return NULL; + } + ws_pae_lib_supp_init(pae_supp); + + // Adds relay address data + kmp_address_init(KMP_ADDR_EUI_64_AND_IP, &pae_supp->addr, key_storage->ptk_eui_64); + + sec_prot_keys_t *sec_keys = &pae_supp->sec_keys; + sec_prot_keys_init(sec_keys, gtks, certs); + + // PMK is invalid, do not retrieve any security key data + if (pmk_invalid) { + ws_pae_key_storage_trace(field_set, key_storage, key_storage_array); + return pae_supp; + } + + // Set PMK security key data + if (key_storage->pmk_key_replay_cnt_set) { + // LSB 16 bits is the replay counter + sec_keys->pmk_key_replay_cnt = key_storage->pmk_key_replay_cnt; + + uint32_t restart_cnt_diff; + if (key_storage_params.restart_cnt >= key_storage_array->storage_array_handle->reference_restart_cnt) { + restart_cnt_diff = key_storage_params.restart_cnt - key_storage_array->storage_array_handle->reference_restart_cnt; + } else { + restart_cnt_diff = key_storage_params.restart_cnt; + } + // MSB 32 bits is the restart count + sec_keys->pmk_key_replay_cnt |= ((uint64_t) restart_cnt_diff) << 32; + field_set |= 1 << PMK_CNT_SET; + } else { + sec_keys->pmk_key_replay_cnt = 0; + } + sec_keys->pmk_key_replay_cnt_set = key_storage->pmk_key_replay_cnt_set; + + memcpy(sec_keys->pmk, key_storage->pmk, PMK_LEN); + sec_keys->pmk_set = key_storage->pmk_set; + + field_set |= ((uint16_t)sec_keys->pmk_set) << PMK_SET; + + sec_keys->pmk_lifetime = pmk_lifetime; + + field_set |= 1 << PMKLTIME_SET; + + // PTK is invalid, do not retrieve any PTK security key data + if (ptk_invalid) { + ws_pae_key_storage_trace(field_set, key_storage, key_storage_array); + return pae_supp; + } + + // Set PTK security key data + memcpy(sec_keys->ptk, key_storage->ptk, PTK_LEN); + sec_keys->ptk_set = key_storage->ptk_set; + + field_set |= ((uint16_t)sec_keys->ptk_set) << PTK_SET; + + memcpy(sec_keys->ptk_eui_64, key_storage->ptk_eui_64, 8); + sec_keys->ptk_eui_64_set = key_storage->ptk_eui_64_set; + + field_set |= ((uint16_t) sec_keys->ptk_eui_64_set) << PTKEUI64_SET; + + memcpy(sec_keys->ins_gtk_hash, key_storage->ins_gtk_hash, sizeof(sec_keys->ins_gtk_hash)); + sec_keys->ins_gtk_hash_set = key_storage->ins_gtk_hash_set; + sec_keys->ins_gtk_4wh_hash_set = sec_keys->ins_gtk_hash_set; + + field_set |= ((uint16_t) sec_keys->ins_gtk_hash_set) << GTKHASH_SET; + field_set |= ((uint16_t) sec_keys->ins_gtk_4wh_hash_set) << GTKHASH4WH_SET; + + sec_keys->ptk_lifetime = ptk_lifetime; + + field_set |= 1 << PTKLTIME_SET; + + ws_pae_key_storage_trace(field_set, key_storage, key_storage_array); + + return pae_supp; +} + +static void ws_pae_key_storage_trace(uint16_t field_set, sec_prot_keys_storage_t *key_storage, key_storage_array_t *key_storage_array) +{ + tr_info("KeyS %s %s%"PRIi64" %"PRIi64" %s%s%i %s%s%s%s%s %s%s%i %i %s%i %i", + FIELD_IS_SET(WRITE_SET) ? "write" : "read", + FIELD_IS_SET(TIME_SET) ? "TIME " : "", FIELD_IS_SET(TIME_SET) ? ws_pae_current_time_get() : 0, FIELD_IS_SET(TIME_SET) ? key_storage_array->storage_array_handle->reference_time : 0, + FIELD_IS_SET(PMK_SET) ? "PMK " : "", + FIELD_IS_SET(PMK_CNT_SET) ? "PMK CNT " : "", key_storage->pmk_key_replay_cnt, + FIELD_IS_SET(PTK_SET) ? "PTK " : "", + FIELD_IS_SET(EUI64_SET) ? "EUI64 " : "", + FIELD_IS_SET(PTKEUI64_SET) ? "PTKEUI64 " : "", + FIELD_IS_SET(GTKHASH_SET) ? "GTKHASH " : "", tr_array((uint8_t *)key_storage->ins_gtk_hash, 8), + FIELD_IS_SET(GTKHASH4WH_SET) ? "GTKHASH4WH " : "", + FIELD_IS_SET(PMKLTIME_SET) ? "PMKLTIME " : "", STIME_TIME_GET(key_storage->pmk_lifetime), STIME_FORMAT_GET(key_storage->pmk_lifetime), + FIELD_IS_SET(PTKLTIME_SET) ? "PTKLTIME " : "", STIME_TIME_GET(key_storage->ptk_lifetime), STIME_FORMAT_GET(key_storage->ptk_lifetime) + ); +} + +int8_t ws_pae_key_storage_store(void) +{ + uint8_t entry_offset = 0; + uint64_t store_bitfield = 0; + + ns_list_foreach(key_storage_array_t, entry, &key_storage_array_list) { + // Bitfield is set for all entries (also that are non-modified in this write) + store_bitfield |= ((uint64_t) 1) << entry_offset; + + /* Checks whether array reference time needs to be updated */ + int8_t ret_value = ws_pae_key_storage_array_time_check_and_update_all(entry, entry->modified); + if (ret_value == 1) { + entry->modified = true; + } else if (ret_value < 0) { + // On error clears the whole array + ws_pae_key_storage_clear(entry); + entry->modified = true; + } + + /* On large network there could be different time thresholds for entries full / all updated + and half empty entries/not all updated where it is likely that data will still be modified */ + if (!entry->modified) { + entry_offset++; + // If not pending for storing; skips file write + continue; + } + + char filename[KEY_STORAGE_FILE_LEN]; + ws_pae_key_storage_filename_set(filename, entry_offset); + tr_info("KeyS write array: %p file: %s", (void *) entry->storage_array, filename); + nvm_tlv_t *tlv = (nvm_tlv_t *) entry->storage_array_handle; + ws_pae_nvm_store_tlv_file_write(filename, tlv); + + // No longer pending for storing + entry->modified = false; + entry_offset++; + } + + if (key_storage_params.store_bitfield != store_bitfield) { + key_storage_params.store_bitfield = store_bitfield; + nvm_tlv_t *tlv = ws_pae_nvm_store_generic_tlv_allocate_and_create( + PAE_NVM_KEY_STORAGE_INDEX_TAG, PAE_NVM_KEY_STORAGE_INDEX_LEN); + ws_pae_nvm_store_key_storage_index_tlv_create(tlv, key_storage_params.store_bitfield); + ws_pae_nvm_store_tlv_file_write(KEY_STORAGE_INDEX_FILE, tlv); + ws_pae_nvm_store_generic_tlv_free(tlv); + } + + return 0; +} + +void ws_pae_key_storage_read(uint32_t restart_cnt) +{ + key_storage_params.store_bitfield = 0; + key_storage_params.restart_cnt = restart_cnt; + + nvm_tlv_t *tlv = ws_pae_nvm_store_generic_tlv_allocate_and_create( + PAE_NVM_KEY_STORAGE_INDEX_TAG, PAE_NVM_KEY_STORAGE_INDEX_LEN); + + if (ws_pae_nvm_store_tlv_file_read(KEY_STORAGE_INDEX_FILE, tlv) < 0) { + ws_pae_nvm_store_generic_tlv_free(tlv); + return; + } + + uint64_t store_bitfield; + if (ws_pae_nvm_store_key_storage_index_tlv_read(tlv, &store_bitfield) >= 0) { + key_storage_params.store_bitfield = store_bitfield; + } + + ws_pae_nvm_store_generic_tlv_free(tlv); + + if (key_storage_params.store_bitfield == 0) { + return; + } + + tr_info("KeyS init store bitf: %"PRIx64, store_bitfield); + + key_storage_array_t *key_storage_array = ns_list_get_first(&key_storage_array_list); + key_storage_array_t *key_storage_array_prev = NULL; + + for (uint8_t entry_offset = 0; entry_offset < 64; entry_offset++) { + // There are no more fields + if (store_bitfield == 0) { + break; + } + + if (key_storage_array == NULL && key_storage_params.storages_empty > 0) { + if (ws_pae_key_storage_allocate(NULL, key_storage_params.storage_default_size, NULL) >= 0) { + key_storage_params.storages_empty--; + } + } + + if (key_storage_array_prev != NULL) { + key_storage_array = ns_list_get_next(&key_storage_array_list, key_storage_array_prev); + } else if (key_storage_array == NULL) { + key_storage_array = ns_list_get_first(&key_storage_array_list); + } + + if (key_storage_array == NULL) { + break; + } + key_storage_array_prev = key_storage_array; + + // If set on bitfield read + if ((store_bitfield & (((uint64_t) 1) << entry_offset)) == 0) { + continue; + } + store_bitfield &= ~(((uint64_t) 1) << entry_offset); + + tlv = (nvm_tlv_t *) key_storage_array->storage_array_handle; + ws_pae_nvm_store_key_storage_tlv_create(tlv, key_storage_array->size); + + char filename[KEY_STORAGE_FILE_LEN]; + ws_pae_key_storage_filename_set(filename, entry_offset); + + tr_info("KeyS init read array: %p file: %s", (void *) key_storage_array->storage_array, filename); + if (ws_pae_nvm_store_tlv_file_read(filename, tlv) < 0) { + ws_pae_key_storage_clear(key_storage_array); + // On error, re-use current one + key_storage_array_prev = NULL; + continue; + } + + bool read_error = false; + if (ws_pae_nvm_store_key_storage_tlv_read(tlv, key_storage_array->size) < 0) { + ws_pae_key_storage_clear(key_storage_array); + read_error = true; + } + + if (read_error) { + // On error, re-use current one + key_storage_array_prev = NULL; + continue; + } + + // Calculate time difference between storage array reference time and current time + uint32_t time_difference; + if (ws_pae_time_diff_calc(ws_pae_current_time_get(), key_storage_array->storage_array_handle->reference_time, &time_difference, false) < 0) { + tr_error("KeyS read array time err: %"PRIi64", ref: %"PRIi64", diff: %"PRIi32, ws_pae_current_time_get(), key_storage_array->storage_array_handle->reference_time, time_difference); + ws_pae_key_storage_clear(key_storage_array); + } + + // Checks and updates PMK counters + if (ws_pae_key_storage_array_counters_check_and_update_all(key_storage_array) < 0) { + tr_error("KeyS read array cnt err"); + // On error clears the whole array + ws_pae_key_storage_clear(key_storage_array); + } + + // Entry set, go to next + key_storage_array = NULL; + } +} + +void ws_pae_key_storage_remove(void) +{ + nvm_tlv_t *tlv = ws_pae_nvm_store_generic_tlv_allocate_and_create( + PAE_NVM_KEY_STORAGE_INDEX_TAG, PAE_NVM_KEY_STORAGE_INDEX_LEN); + + uint64_t store_bitfield = 0; + if (ws_pae_nvm_store_tlv_file_read(KEY_STORAGE_INDEX_FILE, tlv) >= 0) { + ws_pae_nvm_store_key_storage_index_tlv_read(tlv, &store_bitfield); + } + ws_pae_nvm_store_generic_tlv_free(tlv); + + ws_pae_nvm_store_tlv_file_remove(KEY_STORAGE_INDEX_FILE); + + tr_info("KeyS remove store bitf: %"PRIx64, store_bitfield); + + if (store_bitfield == 0) { + return; + } + + for (uint8_t entry_offset = 0; entry_offset < 64; entry_offset++) { + // If set on bitfield delete + if ((store_bitfield & (((uint64_t) 1) << entry_offset)) == 0) { + continue; + } + + char filename[KEY_STORAGE_FILE_LEN]; + ws_pae_key_storage_filename_set(filename, entry_offset); + + tr_info("KeyS remove file: %s", filename); + ws_pae_nvm_store_tlv_file_remove(filename); + } +} + +void ws_pae_key_storage_timer(uint16_t seconds) +{ + if (key_storage_params.store_timer > seconds) { + key_storage_params.store_timer -= seconds; + } else { + key_storage_params.store_timer = key_storage_params.store_timer_timeout; + ws_pae_key_storage_store(); + } + + ws_pae_current_time_update(seconds); +} + +static void ws_pae_key_storage_timer_expiry_set(void) +{ + // Expire in 30 seconds + key_storage_params.store_timer = 30; +} + +uint16_t ws_pae_key_storage_storing_interval_get(void) +{ + return key_storage_params.store_timer_timeout; +} + +static int8_t ws_pae_key_storage_array_time_update_entry(uint64_t time_difference, sec_prot_keys_storage_t *storage_array_entry) +{ + if (storage_array_entry->pmk_lifetime_set) { +#ifdef EXTRA_DEBUG_INFO + tr_debug("KeyS time update diff: %"PRIi64" PMK OLD t: %i %i eui64: %s", time_difference, STIME_TIME_GET(storage_array_entry->pmk_lifetime), STIME_FORMAT_GET(storage_array_entry->pmk_lifetime), tr_array(storage_array_entry->ptk_eui_64, 8)); +#endif + // Calculate new PMK lifetime + if (ws_pae_key_storage_array_lifetime_update(time_difference, &storage_array_entry->pmk_lifetime) < 0) { + tr_info("KeyS time update PMK expired diff: %"PRIi64" t: %i %i eui64: %s", time_difference, STIME_TIME_GET(storage_array_entry->pmk_lifetime), STIME_FORMAT_GET(storage_array_entry->pmk_lifetime), tr_array(storage_array_entry->ptk_eui_64, 8)); + // PMK expired, whole entry is invalid + ws_pae_key_storage_array_pmk_invalid(storage_array_entry); + return -1; + } +#ifdef EXTRA_DEBUG_INFO + tr_debug("KeyS time update PMK NEW t: %i %i", STIME_TIME_GET(storage_array_entry->pmk_lifetime), STIME_FORMAT_GET(storage_array_entry->pmk_lifetime)); +#endif + } + + if (storage_array_entry->pmk_lifetime_set) { +#ifdef EXTRA_DEBUG_INFO + tr_debug("KeyS time update diff: %"PRIi64" PTK OLD t: %i %i eui64: %s", time_difference, STIME_TIME_GET(storage_array_entry->ptk_lifetime), STIME_FORMAT_GET(storage_array_entry->ptk_lifetime), tr_array(storage_array_entry->ptk_eui_64, 8)); +#endif + // Calculate new PTK lifetime + if (ws_pae_key_storage_array_lifetime_update(time_difference, &storage_array_entry->ptk_lifetime) < 0) { + tr_info("KeyS time update PTK expired diff: %"PRIi64" t: %i %i eui64: %s", time_difference, STIME_TIME_GET(storage_array_entry->ptk_lifetime), STIME_FORMAT_GET(storage_array_entry->ptk_lifetime), tr_array(storage_array_entry->ptk_eui_64, 8)); + // PTK is invalid, invalidate PTK related fields + ws_pae_key_storage_array_ptk_invalid(storage_array_entry); + // PMK is still valid + return 0; + } +#ifdef EXTRA_DEBUG_INFO + tr_debug("KeyS time update PTK NEW t: %i %i", STIME_TIME_GET(storage_array_entry->ptk_lifetime), STIME_FORMAT_GET(storage_array_entry->ptk_lifetime)); +#endif + } + return 0; +} + +static int8_t ws_pae_key_storage_array_time_check_and_update_all(key_storage_array_t *key_storage_array, bool modified) +{ + uint64_t reference_time = key_storage_array->storage_array_handle->reference_time; + uint64_t current_time = ws_pae_current_time_get(); + + uint32_t time_difference; + if (ws_pae_time_diff_calc(current_time, reference_time, &time_difference, false) < 0) { + tr_error("KeyS array time all err: %"PRIi64", ref: %"PRIi64", diff: %"PRIi32, ws_pae_current_time_get(), reference_time, time_difference); + return -1; + } + + if (modified) { + // Updates once a day on write + if (time_difference < KEY_STORAGE_REF_TIME_UPDATE_THRESHOLD) { + return 0; + } + } else if (time_difference < KEY_STORAGE_REF_TIME_UPDATE_FORCE_THRESHOLD) { + // Or every 31 days also when no other writes triggered + return 0; + } + + // Checks entries in storage array + sec_prot_keys_storage_t *storage_array = (sec_prot_keys_storage_t *) key_storage_array->storage_array; + for (uint16_t index = 0; index < key_storage_array->entries; index++) { + if (!storage_array[index].eui_64_set) { + continue; + } + // Updates lifetimes on the entry + ws_pae_key_storage_array_time_update_entry(time_difference, &storage_array[index]); + } + + // Entries are now on current time; update reference time + key_storage_array->storage_array_handle->reference_time = current_time; + return 1; +} + +static int8_t ws_pae_key_storage_array_counters_check_and_update_all(key_storage_array_t *key_storage_array) +{ + // Checks entries in storage array + sec_prot_keys_storage_t *storage_array = (sec_prot_keys_storage_t *) key_storage_array->storage_array; + for (uint16_t index = 0; index < key_storage_array->entries; index++) { + if (!storage_array[index].eui_64_set) { + continue; + } + + // GTK 4WH hash information is not stored to NVM and might be obsolete (changing it does not trigger NVM write) + storage_array[index].ins_gtk_4wh_hash_set = 0; + + if (!storage_array[index].pmk_key_replay_cnt_set) { + continue; + } + + // Sanity check for replay counter + if (storage_array[index].pmk_key_replay_cnt >= PMK_KEY_REPLAY_CNT_LIMIT) { + ws_pae_key_storage_array_pmk_invalid(&storage_array[index]); + ws_pae_key_storage_array_ptk_invalid(&storage_array[index]); + continue; + } + + /* Resets replay counter (lower part). When generating 64bit replay counter used on EAPOL, + re-start count is set to replay counter MSB 32bits. So the lower part of the counter + is always fresh after re-start. Thus, each power cycle of device has LSB 32bits of replay + counter space to use. In practice uses only LSB 16bits since counter is limited to 60000, + before generating new PMK. */ + storage_array[index].pmk_key_replay_cnt = 0; + } + + return 0; +} + +static int8_t ws_pae_key_storage_array_lifetime_update(uint32_t time_difference, uint16_t *lifetime) +{ + uint32_t entry_lifetime = ws_pae_time_from_short_convert(*lifetime); + *lifetime = 0; + + // If lifetime has expired, return failure + if (time_difference >= entry_lifetime) { + return -1; + } + entry_lifetime -= time_difference; + *lifetime = ws_pae_time_to_short_convert(entry_lifetime); + // If conversion results zero lifetime return failure + if (*lifetime == 0) { + return -1; + } + + // Lifetime is valid + return 0; +} + +static int8_t ws_pae_key_storage_array_lifetime_get(uint32_t time_difference, uint16_t short_lifetime, uint32_t *lifetime) +{ + *lifetime = ws_pae_time_from_short_convert(short_lifetime); + + // If lifetime has expired, return failure + if (time_difference >= *lifetime) { + return -1; + } + *lifetime -= time_difference; + + return 0; +} + +static void ws_pae_key_storage_array_pmk_invalid(sec_prot_keys_storage_t *storage_array) +{ + memset(storage_array, 0, sizeof(sec_prot_keys_storage_t)); +} + +static void ws_pae_key_storage_array_ptk_invalid(sec_prot_keys_storage_t *storage_array) +{ + memset(storage_array->ptk, 0, PTK_LEN); + storage_array->ptk_set = false; + storage_array->ptk_eui_64_set = false; + memset(storage_array->ins_gtk_hash, 0, sizeof(storage_array->ins_gtk_hash)); + storage_array->ins_gtk_hash_set = false; + storage_array->ptk_lifetime = 0; +} + +#endif /* HAVE_WS */ + diff --git a/source/6LoWPAN/ws/ws_pae_key_storage.h b/source/6LoWPAN/ws/ws_pae_key_storage.h new file mode 100644 index 0000000000..b411620018 --- /dev/null +++ b/source/6LoWPAN/ws/ws_pae_key_storage.h @@ -0,0 +1,164 @@ +/* + * Copyright (c) 2020, Arm Limited and affiliates. + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef WS_PAE_KEY_STORAGE_H_ +#define WS_PAE_KEY_STORAGE_H_ + +/* + * Port access entity key storage functions. + * + */ + +// Number of storages i.e. records in NVM +#define DEFAULT_NUMBER_OF_STORAGES 50 + +// Number of entries stored in a storage i.e. one record in NVM +#define DEFAULT_NUMBER_OF_ENTRIES_IN_ONE_STORAGE 100 + +// Interval to check if storage has been modified and needs to be updated to NVM +#define DEFAULT_STORING_INTERVAL 3600 + +struct supp_entry_s; +struct sec_prot_gtk_keys_s; +struct sec_prot_certs_s; + +/** + * ws_pae_key_storage_memory_set sets memory used for key storages + * + * This functions can be used to set memory used by key storage. When memory areas + * are set, module does not allocate memory internally from heap. + * + * \param key_storages_number number of memory areas + * \param key_storage_size array of memory area sizes + * \param key_storages array of memory area start pointers + * + * \return < 0 failure + * \return >= 0 success + * + */ +int8_t ws_pae_key_storage_memory_set(uint8_t key_storages_number, const uint16_t *key_storage_size, void **key_storages); + +/** + * ws_pae_key_storage_memory_set sets key storage settings + * + * Allocation max number and allocation size sets the settings that are used when key storage + * memory is allocated dynamically from heap. These settings must be set before (first) interface + * up and shall not be set if key storage memory is set by ws_pae_key_storage_memory_set() call. + * + * \param alloc_max_number maximum number of allocation made to dynamic memory + * \param alloc_size size of each allocation + * \param storing_interval interval in which the check to store to NVM is made + * + * \return < 0 failure + * \return >= 0 success + * + */ +int8_t ws_pae_key_storage_settings_set(uint8_t alloc_max_number, uint16_t alloc_size, uint16_t storing_interval); + +/** + * ws_pae_key_storage_init init key storage + * + */ +void ws_pae_key_storage_init(void); + +/** + * ws_pae_key_storage_init delete key storage + * + */ +void ws_pae_key_storage_delete(void); + +/** + * ws_pae_key_storage_store store to NVM + * + * Checks whether key storage data has been updated and stores to NVM. + * + * \return < 0 failure + * \return >= 0 success + * + */ +int8_t ws_pae_key_storage_store(void); + +/** + * ws_pae_key_storage_read read from NVM + * + * Reads key storage data from NVM. + * + */ +void ws_pae_key_storage_read(uint32_t restart_cnt); + +/** + * ws_pae_key_storage_remove remove storage from NVM + * + * Removes key storage data from NVM. + * + */ +void ws_pae_key_storage_remove(void); + +/** + * ws_pae_key_storage_supp_write writes supplicant entry to key storage + * + * \param instance instance + * \param pae_supp supplicant entry + * + * \return < 0 failure + * \return >= 0 success + * + */ +int8_t ws_pae_key_storage_supp_write(const void *instance, struct supp_entry_s *pae_supp); + +/** + * ws_pae_key_storage_supp_read reads supplicant entry from key storage + * + * \param instance instance + * \param eui_64 EUI-64 of the supplicant + * \param gtks GTK keys + * \param cert_chain certificates + * + * \return supplicant entry or NULL if supplicant entry does not exits + * + */ +struct supp_entry_s *ws_pae_key_storage_supp_read(const void *instance, const uint8_t *eui_64, struct sec_prot_gtk_keys_s *gtks, const struct sec_prot_certs_s *certs); + +/** + * ws_pae_key_storage_supp_delete delete supplicant entry from key storage + * + * \param instance instance + * \param eui_64 EUI-64 of the supplicant + * + * \return true entry was deleted + * \return false entry was not deleted + * + */ +bool ws_pae_key_storage_supp_delete(const void *instance, const uint8_t *eui64); + +/** + * ws_pae_key_storage_timer key storage timers + * + * \param seconds Seconds passed + * + */ +void ws_pae_key_storage_timer(uint16_t seconds); + +/** + * ws_pae_key_storage_storing_interval_get gets key storage storing interval + * + * \return storing interval in seconds + * + */ +uint16_t ws_pae_key_storage_storing_interval_get(void); + +#endif /* WS_PAE_KEY_STORAGE_H_ */ diff --git a/source/6LoWPAN/ws/ws_pae_lib.c b/source/6LoWPAN/ws/ws_pae_lib.c index 4394ee1dc8..d47aff8a8f 100644 --- a/source/6LoWPAN/ws/ws_pae_lib.c +++ b/source/6LoWPAN/ws/ws_pae_lib.c @@ -26,13 +26,14 @@ #include "NWK_INTERFACE/Include/protocol.h" #include "6LoWPAN/ws/ws_cfg_settings.h" #include "6LoWPAN/ws/ws_config.h" -#include "6LoWPAN/ws/ws_pae_timers.h" #include "Security/protocols/sec_prot_cfg.h" +#include "6LoWPAN/ws/ws_pae_timers.h" #include "Security/kmp/kmp_addr.h" #include "Security/kmp/kmp_api.h" #include "Security/protocols/sec_prot_certs.h" #include "Security/protocols/sec_prot_keys.h" #include "6LoWPAN/ws/ws_pae_lib.h" +#include "6LoWPAN/ws/ws_pae_key_storage.h" #ifdef HAVE_WS @@ -126,6 +127,16 @@ kmp_entry_t *ws_pae_lib_kmp_list_entry_get(kmp_list_t *kmp_list, kmp_api_t *kmp) return 0; } +bool ws_pae_lib_kmp_list_empty(kmp_list_t *kmp_list) +{ + return ns_list_is_empty(kmp_list); +} + +uint8_t ws_pae_lib_kmp_list_count(kmp_list_t *kmp_list) +{ + return ns_list_count(kmp_list); +} + void ws_pae_lib_kmp_timer_start(kmp_list_t *kmp_list, kmp_entry_t *entry) { if (ns_list_get_first(kmp_list) != entry) { @@ -171,7 +182,7 @@ void ws_pae_lib_supp_list_init(supp_list_t *supp_list) supp_entry_t *ws_pae_lib_supp_list_add(supp_list_t *supp_list, const kmp_addr_t *addr) { - supp_entry_t *entry = ns_dyn_mem_alloc(sizeof(supp_entry_t)); + supp_entry_t *entry = ns_dyn_mem_temporary_alloc(sizeof(supp_entry_t)); if (!entry) { return NULL; @@ -215,33 +226,32 @@ void ws_pae_lib_supp_list_delete(supp_list_t *supp_list) } } -bool ws_pae_lib_supp_list_timer_update(supp_list_t *active_supp_list, supp_list_t *inactive_supp_list, uint16_t ticks, ws_pae_lib_kmp_timer_timeout timeout) +bool ws_pae_lib_supp_list_timer_update(void *instance, supp_list_t *active_supp_list, uint16_t ticks, ws_pae_lib_kmp_timer_timeout timeout) { bool timer_running = false; ns_list_foreach_safe(supp_entry_t, entry, active_supp_list) { - bool running = ws_pae_lib_supp_timer_update(entry, ticks, timeout); + bool running = ws_pae_lib_supp_timer_update(instance, entry, ticks, timeout); if (running) { timer_running = true; } else { - ws_pae_lib_supp_list_to_inactive(active_supp_list, inactive_supp_list, entry); + ws_pae_lib_supp_list_to_inactive(instance, active_supp_list, entry); } } return timer_running; } -void ws_pae_lib_supp_list_slow_timer_update(supp_list_t *supp_list, sec_timer_cfg_t *timer_settings, uint16_t seconds) +void ws_pae_lib_supp_list_slow_timer_update(supp_list_t *supp_list, uint16_t seconds) { ns_list_foreach(supp_entry_t, entry, supp_list) { - if (sec_prot_keys_pmk_lifetime_decrement(&entry->sec_keys, timer_settings->pmk_lifetime, seconds)) { + if (sec_prot_keys_pmk_lifetime_decrement(&entry->sec_keys, seconds)) { tr_info("PMK and PTK expired, eui-64: %s, system time: %"PRIu32"", trace_array(entry->addr.eui_64, 8), protocol_core_monotonic_time / 10); } - if (sec_prot_keys_ptk_lifetime_decrement(&entry->sec_keys, timer_settings->ptk_lifetime, seconds)) { + if (sec_prot_keys_ptk_lifetime_decrement(&entry->sec_keys, seconds)) { tr_info("PTK expired, eui-64: %s, system time: %"PRIu32"", trace_array(entry->addr.eui_64, 8), protocol_core_monotonic_time / 10); } } - } void ws_pae_lib_supp_init(supp_entry_t *entry) @@ -251,6 +261,7 @@ void ws_pae_lib_supp_init(supp_entry_t *entry) memset(&entry->sec_keys, 0, sizeof(sec_prot_keys_t)); entry->ticks = 0; entry->retry_ticks = 0; + entry->store_ticks = ws_pae_key_storage_storing_interval_get() * 1000; entry->active = true; entry->access_revoked = false; } @@ -260,7 +271,7 @@ void ws_pae_lib_supp_delete(supp_entry_t *entry) ws_pae_lib_kmp_list_free(&entry->kmp_list); } -bool ws_pae_lib_supp_timer_update(supp_entry_t *entry, uint16_t ticks, ws_pae_lib_kmp_timer_timeout timeout) +bool ws_pae_lib_supp_timer_update(void *instance, supp_entry_t *entry, uint16_t ticks, ws_pae_lib_kmp_timer_timeout timeout) { // Updates KMP timers and calls timeout callback bool keep_timer_running = ws_pae_lib_kmp_timer_update(&entry->kmp_list, ticks, timeout); @@ -286,6 +297,19 @@ bool ws_pae_lib_supp_timer_update(supp_entry_t *entry, uint16_t ticks, ws_pae_li entry->retry_ticks = 0; } + if (!instance) { + return keep_timer_running; + } + + // Updates retry timer + if (entry->store_ticks > ticks) { + entry->store_ticks -= ticks; + } else { + tr_info("PAE active entry key storage update timeout"); + ws_pae_key_storage_supp_write(instance, entry); + entry->store_ticks = ws_pae_key_storage_storing_interval_get() * 1000; + } + return keep_timer_running; } @@ -326,7 +350,7 @@ void ws_pae_lib_supp_list_to_active(supp_list_t *active_supp_list, supp_list_t * entry->addr.type = KMP_ADDR_EUI_64_AND_IP; } -void ws_pae_lib_supp_list_to_inactive(supp_list_t *active_supp_list, supp_list_t *inactive_supp_list, supp_entry_t *entry) +void ws_pae_lib_supp_list_to_inactive(void *instance, supp_list_t *active_supp_list, supp_entry_t *entry) { if (!entry->active) { return; @@ -340,34 +364,28 @@ void ws_pae_lib_supp_list_to_inactive(supp_list_t *active_supp_list, supp_list_t return; } - ns_list_remove(active_supp_list, entry); - ns_list_add_to_start(inactive_supp_list, entry); + // Store to key storage + ws_pae_key_storage_supp_write(instance, entry); - entry->active = false; - entry->ticks = 0; - - // Removes relay address data - entry->addr.type = KMP_ADDR_EUI_64; - entry->addr.port = 0; - memset(entry->addr.relay_address, 0, 16); + // Remove supplicant entry + ws_pae_lib_supp_list_remove(active_supp_list, entry); } -void ws_pae_lib_supp_list_purge(supp_list_t *active_supp_list, supp_list_t *inactive_supp_list, uint16_t max_number, uint8_t max_purge) +void ws_pae_lib_supp_list_purge(supp_list_t *active_supp_list, uint16_t max_number, uint8_t max_purge) { uint16_t active_supp = ns_list_count(active_supp_list); - uint16_t inactive_supp = ns_list_count(inactive_supp_list); - if (active_supp + inactive_supp > max_number) { - uint16_t remove_count = active_supp + inactive_supp - max_number; + if (active_supp > max_number) { + uint16_t remove_count = active_supp - max_number; if (max_purge > 0 && remove_count > max_purge) { remove_count = max_purge; } - // Remove entries from inactive list - ns_list_foreach_safe(supp_entry_t, entry, inactive_supp_list) { - if (remove_count > 0) { - tr_info("Inactive supplicant removed, eui-64: %s", trace_array(kmp_address_eui_64_get(&entry->addr), 8)); - ws_pae_lib_supp_list_remove(inactive_supp_list, entry); + // Remove entries from active list if there are no active KMPs ongoing for the entry + ns_list_foreach_safe(supp_entry_t, entry, active_supp_list) { + if (remove_count > 0 && ws_pae_lib_kmp_list_empty(&entry->kmp_list)) { + tr_info("Active supplicant removed, eui-64: %s", trace_array(kmp_address_eui_64_get(&entry->addr), 8)); + ws_pae_lib_supp_list_remove(active_supp_list, entry); remove_count--; } else { break; @@ -376,6 +394,16 @@ void ws_pae_lib_supp_list_purge(supp_list_t *active_supp_list, supp_list_t *inac } } +bool ws_pae_lib_supp_list_active_limit_reached(supp_list_t *active_supp_list, uint16_t max_number) +{ + uint16_t active_supp = ns_list_count(active_supp_list); + if (active_supp > max_number) { + return true; + } + + return false; +} + uint16_t ws_pae_lib_supp_list_kmp_count(supp_list_t *supp_list, kmp_type_e type) { uint16_t kmp_count = 0; diff --git a/source/6LoWPAN/ws/ws_pae_lib.h b/source/6LoWPAN/ws/ws_pae_lib.h index b045fd00fd..eed138e74c 100644 --- a/source/6LoWPAN/ws/ws_pae_lib.h +++ b/source/6LoWPAN/ws/ws_pae_lib.h @@ -31,12 +31,13 @@ typedef struct { typedef NS_LIST_HEAD(kmp_entry_t, link) kmp_list_t; -typedef struct { +typedef struct supp_entry_s { kmp_list_t kmp_list; /**< Ongoing KMP negotiations */ kmp_addr_t addr; /**< EUI-64 (Relay IP address, Relay port) */ sec_prot_keys_t sec_keys; /**< Security keys */ uint32_t ticks; /**< Ticks */ uint16_t retry_ticks; /**< Retry ticks */ + uint16_t store_ticks; /**< NVM store ticks */ bool active : 1; /**< Is active */ bool access_revoked : 1; /**< Nodes access is revoked */ ns_list_link_t link; /**< Link */ @@ -123,6 +124,27 @@ kmp_api_t *ws_pae_lib_kmp_list_instance_id_get(kmp_list_t *kmp_list, uint8_t ins */ kmp_entry_t *ws_pae_lib_kmp_list_entry_get(kmp_list_t *kmp_list, kmp_api_t *kmp); +/** + * ws_pae_lib_kmp_list_empty checks whether KMP list is empty + * + * \param kmp_list KMP list + * + * \return true list is empty + * \return false list is not empty + * + */ +bool ws_pae_lib_kmp_list_empty(kmp_list_t *kmp_list); + +/** + * ws_pae_lib_kmp_list_count counts entries on KMP list + * + * \param kmp_list KMP list + * + * \return count of entries on the list + * + */ +uint8_t ws_pae_lib_kmp_list_count(kmp_list_t *kmp_list); + /** * ws_pae_lib_kmp_timer_start starts KMP timer * @@ -215,6 +237,7 @@ void ws_pae_lib_supp_list_delete(supp_list_t *supp_list); /** * ws_pae_lib_supp_list_timer_update updates timers on supplicant list * + * \param instance Instance * \param active_supp_list list of active supplicants * \param inactive_supp_list list of inactive supplicants * \param ticks timer ticks @@ -223,17 +246,16 @@ void ws_pae_lib_supp_list_delete(supp_list_t *supp_list); * \return true timer needs still to be running * \return false timer can be stopped */ -bool ws_pae_lib_supp_list_timer_update(supp_list_t *active_supp_list, supp_list_t *inactive_supp_list, uint16_t ticks, ws_pae_lib_kmp_timer_timeout timeout); +bool ws_pae_lib_supp_list_timer_update(void *instance, supp_list_t *active_supp_list, uint16_t ticks, ws_pae_lib_kmp_timer_timeout timeout); /** * ws_pae_lib_supp_list_slow_timer_update updates slow timer on supplicant list * * \param supp_list list of supplicants - * \param timer_settings timer settings * \param seconds seconds * */ -void ws_pae_lib_supp_list_slow_timer_update(supp_list_t *supp_list, sec_timer_cfg_t *timer_settings, uint16_t seconds); +void ws_pae_lib_supp_list_slow_timer_update(supp_list_t *supp_list, uint16_t seconds); /** * ws_pae_lib_supp_list_timer_update updates supplicant timers @@ -245,7 +267,7 @@ void ws_pae_lib_supp_list_slow_timer_update(supp_list_t *supp_list, sec_timer_cf * \return true timer needs still to be running * \return false timer can be stopped */ -bool ws_pae_lib_supp_timer_update(supp_entry_t *entry, uint16_t ticks, ws_pae_lib_kmp_timer_timeout timeout); +bool ws_pae_lib_supp_timer_update(void *instance, supp_entry_t *entry, uint16_t ticks, ws_pae_lib_kmp_timer_timeout timeout); /** * ws_pae_lib_supp_init initiates supplicant entry @@ -304,24 +326,34 @@ void ws_pae_lib_supp_list_to_active(supp_list_t *active_supp_list, supp_list_t * /** * ws_pae_lib_supp_list_to_inactive move supplicant to inactive supplicants list * + * \param instance Instance * \param active_supp_list list of active supplicants - * \param inactive_supp_list list of inactive supplicants * \param entry supplicant entry * */ -void ws_pae_lib_supp_list_to_inactive(supp_list_t *active_supp_list, supp_list_t *inactive_supp_list, supp_entry_t *entry); +void ws_pae_lib_supp_list_to_inactive(void *instance, supp_list_t *active_supp_list, supp_entry_t *entry); /** * ws_pae_lib_supp_list_purge purge inactive supplicants list * * \param active_supp_list list of active supplicants - * \param inactive_supp_list list of inactive supplicants * \param max_number maximum number of supplicant entries, can be set to 0 in combination with max_purge * to free list entries even when maximum number supplicant entries has not been reached * \param max_purge maximum number of supplicants to purge in one call, 0 means not limited * */ -void ws_pae_lib_supp_list_purge(supp_list_t *active_supp_list, supp_list_t *inactive_supp_list, uint16_t max_number, uint8_t max_purge); +void ws_pae_lib_supp_list_purge(supp_list_t *active_supp_list, uint16_t max_number, uint8_t max_purge); + +/** + * ws_pae_lib_supp_list_limit_reached_check check if active supplicant list limit has been reached + * + * \param active_supp_list list of active supplicants + * \param max_number maximum number of supplicant entries + * + * \return true limit has been reached + * \return false limit has not been reached + */ +bool ws_pae_lib_supp_list_active_limit_reached(supp_list_t *active_supp_list, uint16_t max_number); /** * ws_pae_lib_supp_list_kmp_count counts the number of KMPs of a certain type in a list of supplicants diff --git a/source/6LoWPAN/ws/ws_pae_nvm_data.c b/source/6LoWPAN/ws/ws_pae_nvm_data.c index 7f833430a6..3212240af8 100644 --- a/source/6LoWPAN/ws/ws_pae_nvm_data.c +++ b/source/6LoWPAN/ws/ws_pae_nvm_data.c @@ -24,38 +24,50 @@ #include "common_functions.h" #include "6LoWPAN/ws/ws_config.h" #include "ns_file_system.h" +#include "NWK_INTERFACE/Include/protocol.h" +#include "Service_Libs/utils/ns_file.h" #include "Security/protocols/sec_prot_certs.h" #include "Security/protocols/sec_prot_keys.h" #include "6LoWPAN/ws/ws_pae_nvm_store.h" #include "6LoWPAN/ws/ws_pae_nvm_data.h" +#include "6LoWPAN/ws/ws_pae_controller.h" +#include "6LoWPAN/ws/ws_pae_time.h" #ifdef HAVE_WS #define TRACE_GROUP "wsnv" -#define PAE_NVM_NW_INFO_TAG 1 -#define PAE_NVM_KEYS_TAG 2 -#define PAE_NVM_FRAME_COUNTER_TAG 3 - -// pan_id (2) + network name (33) + (GTK set (1) + GTK lifetime (4) + GTK (16)) * 4 -#define PAE_NVM_NW_INFO_LEN 2 + 33 + (1 + 4 + GTK_LEN) * GTK_NUM - -// PTK EUI-64 set (1) + PTK EUI-64 (8) + PMK set (1) + PMK (32) + PMK replay counter (8) + PTK set (1) + PTK (48) -#define PAE_NVM_KEYS_LEN 1 + 8 + 1 + PMK_LEN + 8 + 1 + PTK_LEN - -// (frame counter set (1) + GTK (16) + frame counter (4)) * 4 -#define PAE_NVM_FRAME_COUNTER_LEN (1 + GTK_LEN + 4) * GTK_NUM - #define PAE_NVM_FIELD_NOT_SET 0 // Field is not present #define PAE_NVM_FIELD_SET 1 // Field is present -nvm_tlv_entry_t *ws_pae_buffer_allocate(void) +void ws_pae_nvm_store_generic_tlv_create(nvm_tlv_t *tlv_entry, uint16_t tag, uint16_t length) { - //Allocate worts case buffer - return ns_dyn_mem_temporary_alloc(sizeof(nvm_tlv_entry_t) + PAE_NVM_NW_INFO_LEN); + tlv_entry->tag = tag; + tlv_entry->len = length; } -void ws_pae_nvm_store_nw_info_tlv_create(nvm_tlv_entry_t *tlv_entry, uint16_t pan_id, char *nw_name, sec_prot_gtk_keys_t *gtks) +nvm_tlv_t *ws_pae_nvm_store_generic_tlv_allocate_and_create(uint16_t tag, uint16_t length) +{ + nvm_tlv_t *tlv_entry = ns_dyn_mem_alloc(length + sizeof(nvm_tlv_t)); + if (!tlv_entry) { + return NULL; + } + tlv_entry->tag = tag; + tlv_entry->len = length; + + return tlv_entry; +} + +void ws_pae_nvm_store_generic_tlv_free(nvm_tlv_t *tlv_entry) +{ + if (!tlv_entry) { + return; + } + + ns_dyn_mem_free(tlv_entry); +} + +void ws_pae_nvm_store_nw_info_tlv_create(nvm_tlv_t *tlv_entry, uint16_t pan_id, char *nw_name, sec_prot_gtk_keys_t *gtks) { int len; tlv_entry->tag = PAE_NVM_NW_INFO_TAG; @@ -75,19 +87,31 @@ void ws_pae_nvm_store_nw_info_tlv_create(nvm_tlv_entry_t *tlv_entry, uint16_t pa memcpy((char *)tlv, nw_name, len); tlv += 33; + uint64_t current_time = ws_pae_current_time_get(); + for (uint8_t i = 0; i < GTK_NUM; i++) { - if (sec_prot_keys_gtk_is_set(gtks, i)) { + if (gtks && sec_prot_keys_gtk_is_set(gtks, i)) { *tlv++ = PAE_NVM_FIELD_SET; // GTK is set - uint32_t lifetime = sec_prot_keys_gtk_lifetime_get(gtks, i); - tlv = common_write_32_bit(lifetime, tlv); + + uint64_t expirytime = sec_prot_keys_gtk_exptime_from_lifetime_get(gtks, i, current_time); + // Sets stored expiration time to GTKs; no need to update anymore to NVM if not changed + sec_prot_keys_gtk_expirytime_set(gtks, i, expirytime); + + tlv = common_write_64_bit(expirytime, tlv); + + uint8_t status = sec_prot_keys_gtk_status_get(gtks, i); + *tlv++ = status; + + uint8_t install_order = sec_prot_keys_gtk_install_order_get(gtks, i); + *tlv++ = install_order; uint8_t *gtk = sec_prot_keys_gtk_get(gtks, i); memcpy(tlv, gtk, GTK_LEN); tlv += GTK_LEN; } else { *tlv++ = PAE_NVM_FIELD_NOT_SET; // GTK is not set - memset(tlv, 0, 4 + GTK_LEN); - tlv += 4 + GTK_LEN; + memset(tlv, 0, 8 + 1 + 1 + GTK_LEN); + tlv += 8 + 1 + 1 + GTK_LEN; } } @@ -95,9 +119,9 @@ void ws_pae_nvm_store_nw_info_tlv_create(nvm_tlv_entry_t *tlv_entry, uint16_t pa } -int8_t ws_pae_nvm_store_nw_info_tlv_read(nvm_tlv_entry_t *tlv_entry, uint16_t *pan_id, char *nw_name, sec_prot_gtk_keys_t *gtks) +int8_t ws_pae_nvm_store_nw_info_tlv_read(nvm_tlv_t *tlv_entry, uint16_t *pan_id, char *nw_name, sec_prot_gtk_keys_t *gtks) { - if (!tlv_entry || !pan_id || !nw_name || !gtks) { + if (!tlv_entry || !pan_id || !nw_name) { return -1; } @@ -107,31 +131,60 @@ int8_t ws_pae_nvm_store_nw_info_tlv_read(nvm_tlv_entry_t *tlv_entry, uint16_t *p uint8_t *tlv = ((uint8_t *) &tlv_entry->tag) + NVM_TLV_FIXED_LEN; - *pan_id = common_read_16_bit(tlv); + if (*pan_id == 0xffff) { + // If application has not set pan_id read it from NVM + *pan_id = common_read_16_bit(tlv); + } tlv += 2; - memset(nw_name, 0, 33); - strncpy(nw_name, (char *) tlv, 32); + if (strlen(nw_name) == 0) { + // If application has not set network name read it from NVM + memset(nw_name, 0, 33); + strncpy(nw_name, (char *) tlv, 32); + } tlv += 33; - for (uint8_t i = 0; i < GTK_NUM; i++) { - if (*tlv++ == PAE_NVM_FIELD_SET) { /* GTK is set */ - uint32_t lifetime = common_read_32_bit(tlv); - tlv += 4; - sec_prot_keys_gtk_set(gtks, i, tlv, lifetime); - tlv += GTK_LEN; - } else { - tlv += 4 + GTK_LEN; + uint64_t current_time = ws_pae_current_time_get(); + + tr_debug("NVM NW_INFO current time: %"PRIi64, current_time); + + if (gtks && sec_prot_keys_gtk_count(gtks) == 0) { + // If application has not set GTKs read them from NVM + for (uint8_t i = 0; i < GTK_NUM; i++) { + if (*tlv++ == PAE_NVM_FIELD_SET) { /* GTK is set */ + uint64_t expirytime = common_read_64_bit(tlv); + uint32_t lifetime = 0; + if (ws_pae_time_diff_calc(current_time, expirytime, &lifetime, true) < 0) { + tlv += 8 + 1 + 1 + GTK_LEN; + tr_debug("GTK index %i, expired expiry time: %"PRIi64", lifetime: %"PRIi32, i, expirytime, lifetime); + continue; + } + tlv += 8; + + uint8_t status = *tlv++; + + uint8_t install_order = *tlv++; + + tr_debug("GTK index: %i, status: %i, install order %i, expiry time: %"PRIi64", lifetime: %"PRIi32, i, status, install_order, expirytime, lifetime); + + sec_prot_keys_gtk_set(gtks, i, tlv, lifetime); + sec_prot_keys_gtk_expirytime_set(gtks, i, expirytime); + tlv += GTK_LEN; + sec_prot_keys_gtk_status_set(gtks, i, status); + sec_prot_keys_gtk_install_order_set(gtks, i, install_order); + } else { + tlv += 8 + 1 + 1 + GTK_LEN; + } } + sec_prot_keys_gtks_updated_reset(gtks); } - sec_prot_keys_gtks_updated_reset(gtks); tr_debug("NVM NW_INFO read PAN ID %i name: %s", *pan_id, nw_name); return 0; } -void ws_pae_nvm_store_keys_tlv_create(nvm_tlv_entry_t *tlv_entry, sec_prot_keys_t *sec_keys) +void ws_pae_nvm_store_keys_tlv_create(nvm_tlv_t *tlv_entry, sec_prot_keys_t *sec_keys) { tlv_entry->tag = PAE_NVM_KEYS_TAG; tlv_entry->len = PAE_NVM_KEYS_LEN; @@ -151,10 +204,12 @@ void ws_pae_nvm_store_keys_tlv_create(nvm_tlv_entry_t *tlv_entry, sec_prot_keys_ uint8_t *pmk = sec_prot_keys_pmk_get(sec_keys); if (pmk) { *tlv++ = PAE_NVM_FIELD_SET; + uint32_t lifetime = sec_prot_keys_pmk_lifetime_get(sec_keys); + tlv = common_write_32_bit(lifetime, tlv); memcpy(tlv, pmk, PMK_LEN); } else { *tlv++ = PAE_NVM_FIELD_NOT_SET; - memset(tlv, 0, PMK_LEN); + memset(tlv, 0, 4 + PMK_LEN); } tlv += PMK_LEN; @@ -164,18 +219,19 @@ void ws_pae_nvm_store_keys_tlv_create(nvm_tlv_entry_t *tlv_entry, sec_prot_keys_ uint8_t *ptk = sec_prot_keys_ptk_get(sec_keys); if (ptk) { *tlv++ = PAE_NVM_FIELD_SET; + uint32_t lifetime = sec_prot_keys_ptk_lifetime_get(sec_keys); + tlv = common_write_32_bit(lifetime, tlv); memcpy(tlv, ptk, PTK_LEN); } else { *tlv++ = PAE_NVM_FIELD_NOT_SET; - memset(tlv, 0, PTK_LEN); + memset(tlv, 0, 4 + PTK_LEN); } tlv += PTK_LEN; tr_debug("NVM KEYS write"); - } -int8_t ws_pae_nvm_store_keys_tlv_read(nvm_tlv_entry_t *tlv_entry, sec_prot_keys_t *sec_keys) +int8_t ws_pae_nvm_store_keys_tlv_read(nvm_tlv_t *tlv_entry, sec_prot_keys_t *sec_keys) { if (!tlv_entry || !sec_keys) { return -1; @@ -195,7 +251,11 @@ int8_t ws_pae_nvm_store_keys_tlv_read(nvm_tlv_entry_t *tlv_entry, sec_prot_keys_ // PMK set if (*tlv++ == PAE_NVM_FIELD_SET) { - sec_prot_keys_pmk_write(sec_keys, tlv); + uint32_t lifetime = common_read_32_bit(tlv); + tlv += 4; + sec_prot_keys_pmk_write(sec_keys, tlv, lifetime); + } else { + tlv += 4; } tlv += PMK_LEN; @@ -205,7 +265,11 @@ int8_t ws_pae_nvm_store_keys_tlv_read(nvm_tlv_entry_t *tlv_entry, sec_prot_keys_ // PTK set if (*tlv++ == PAE_NVM_FIELD_SET) { - sec_prot_keys_ptk_write(sec_keys, tlv); + uint32_t lifetime = common_read_32_bit(tlv); + tlv += 4; + sec_prot_keys_ptk_write(sec_keys, tlv, lifetime); + } else { + tlv += 4; } tlv += PTK_LEN; @@ -217,13 +281,18 @@ int8_t ws_pae_nvm_store_keys_tlv_read(nvm_tlv_entry_t *tlv_entry, sec_prot_keys_ return 0; } -void ws_pae_nvm_store_frame_counter_tlv_create(nvm_tlv_entry_t *tlv_entry, frame_counters_t *counters) +void ws_pae_nvm_store_frame_counter_tlv_create(nvm_tlv_t *tlv_entry, uint32_t restart_cnt, frame_counters_t *counters) { tlv_entry->tag = PAE_NVM_FRAME_COUNTER_TAG; tlv_entry->len = PAE_NVM_FRAME_COUNTER_LEN; uint8_t *tlv = ((uint8_t *) &tlv_entry->tag) + NVM_TLV_FIXED_LEN; + tlv = common_write_32_bit(restart_cnt, tlv); + + uint64_t stored_time = ws_pae_current_time_get(); + tlv = common_write_64_bit(stored_time, tlv); + for (uint8_t index = 0; index < GTK_NUM; index++) { if (!counters->counter[index].set) { *tlv++ = PAE_NVM_FIELD_NOT_SET; @@ -240,7 +309,7 @@ void ws_pae_nvm_store_frame_counter_tlv_create(nvm_tlv_entry_t *tlv_entry, frame tr_debug("NVM FRAME COUNTER write"); } -int8_t ws_pae_nvm_store_frame_counter_tlv_read(nvm_tlv_entry_t *tlv_entry, frame_counters_t *counters) +int8_t ws_pae_nvm_store_frame_counter_tlv_read(nvm_tlv_t *tlv_entry, uint32_t *restart_cnt, uint64_t *stored_time, frame_counters_t *counters) { if (!tlv_entry || !counters) { return -1; @@ -252,6 +321,12 @@ int8_t ws_pae_nvm_store_frame_counter_tlv_read(nvm_tlv_entry_t *tlv_entry, frame uint8_t *tlv = ((uint8_t *) &tlv_entry->tag) + NVM_TLV_FIXED_LEN; + *restart_cnt = common_read_32_bit(tlv); + tlv += 4; + + *stored_time = common_read_64_bit(tlv); + tlv += 8; + for (uint8_t index = 0; index < GTK_NUM; index++) { // Frame counter not set if (*tlv++ == PAE_NVM_FIELD_NOT_SET) { @@ -272,5 +347,61 @@ int8_t ws_pae_nvm_store_frame_counter_tlv_read(nvm_tlv_entry_t *tlv_entry, frame return 0; } +void ws_pae_nvm_store_key_storage_index_tlv_create(nvm_tlv_t *tlv_entry, uint64_t bitfield) +{ + tlv_entry->tag = PAE_NVM_KEY_STORAGE_INDEX_TAG; + tlv_entry->len = PAE_NVM_KEY_STORAGE_INDEX_LEN; + + uint8_t *tlv = ((uint8_t *) &tlv_entry->tag) + NVM_TLV_FIXED_LEN; + + tlv = common_write_64_bit(bitfield, tlv); + + tr_debug("NVM KEY STORAGE INDEX write"); +} + +int8_t ws_pae_nvm_store_key_storage_index_tlv_read(nvm_tlv_t *tlv_entry, uint64_t *bitfield) +{ + if (!tlv_entry || !bitfield) { + return -1; + } + + if (tlv_entry->tag != PAE_NVM_KEY_STORAGE_INDEX_TAG || tlv_entry->len != PAE_NVM_KEY_STORAGE_INDEX_LEN) { + return -1; + } + + uint8_t *tlv = ((uint8_t *) &tlv_entry->tag) + NVM_TLV_FIXED_LEN; + *bitfield = common_read_64_bit(tlv); + tlv += 8; + + tr_debug("NVM KEY STORAGE INDEX read"); + + return 0; +} + +void ws_pae_nvm_store_key_storage_tlv_create(nvm_tlv_t *tlv_entry, uint16_t length) +{ + memset(tlv_entry, 0, sizeof(key_storage_nvm_tlv_entry_t)); + + tlv_entry->tag = PAE_NVM_KEY_STORAGE_TAG; + tlv_entry->len = length - sizeof(nvm_tlv_t); + + tr_debug("NVM KEY STORAGE create"); +} + +int8_t ws_pae_nvm_store_key_storage_tlv_read(nvm_tlv_t *tlv_entry, uint16_t length) +{ + if (!tlv_entry || !length) { + return -1; + } + + if (tlv_entry->tag != PAE_NVM_KEY_STORAGE_TAG || tlv_entry->len != length - sizeof(nvm_tlv_t)) { + return -1; + } + + tr_debug("NVM KEY STORAGE read"); + + return 0; +} + #endif /* HAVE_WS */ diff --git a/source/6LoWPAN/ws/ws_pae_nvm_data.h b/source/6LoWPAN/ws/ws_pae_nvm_data.h index 86ebedad80..c55d56412b 100644 --- a/source/6LoWPAN/ws/ws_pae_nvm_data.h +++ b/source/6LoWPAN/ws/ws_pae_nvm_data.h @@ -24,10 +24,52 @@ * */ +// file names +#define NW_INFO_FILE_NAME "pae_nw_info" +#define KEYS_FILE_NAME "pae_keys" +#define FRAME_COUNTER_FILE_NAME "pae_frame_counter" + +#define PAE_NVM_NW_INFO_TAG 1 +#define PAE_NVM_KEYS_TAG 2 +#define PAE_NVM_FRAME_COUNTER_TAG 3 +#define PAE_NVM_KEY_STORAGE_INDEX_TAG 4 +#define PAE_NVM_KEY_STORAGE_TAG 5 + +// pan_id (2) + network name (33) + (GTK set (1) + GTK expiry timestamp (8) + status (1) + install order (1) + GTK (16)) * 4 +#define PAE_NVM_NW_INFO_LEN 2 + 33 + (1 + 8 + 1 + 1 + GTK_LEN) * GTK_NUM + +// PTK EUI-64 set (1) + PTK EUI-64 (8) + PMK set (1) + PMK lifetime (4) + PMK (32) + PMK replay counter (8) + PTK set (1) + PTK lifetime (4) + PTK (48) +#define PAE_NVM_KEYS_LEN 1 + 8 + 1 + 4 + PMK_LEN + 8 + 1 + 4 + PTK_LEN + +// restart counter + stored time + (frame counter set (1) + GTK (16) + frame counter (4)) * 4 +#define PAE_NVM_FRAME_COUNTER_LEN 4 + 8 + (1 + GTK_LEN + 4) * GTK_NUM + +#define PAE_NVM_DEFAULT_BUFFER_SIZE sizeof(nvm_tlv_t) + PAE_NVM_NW_INFO_LEN + +// key storage index bitfield (8) +#define PAE_NVM_KEY_STORAGE_INDEX_LEN 8 + +/** + * ws_pae_nvm_store_generic_tlv_create create NVM generic storage TLV + * + * \param tlv_entry TLV entry + * \param tag tag + * \param length length of the (whole) entry + * + * \return < 0 failure + * \return >= 0 success + * + */ +void ws_pae_nvm_store_generic_tlv_create(nvm_tlv_t *tlv_entry, uint16_t tag, uint16_t length); + +nvm_tlv_t *ws_pae_nvm_store_generic_tlv_allocate_and_create(uint16_t tag, uint16_t length); + +void ws_pae_nvm_store_generic_tlv_free(nvm_tlv_t *tlv_entry); + /** * ws_pae_nvm_store_nw_info_tlv_create create NVM network info TLV * - * \param tlv_entry TLV entry pointer + * \param tlv_entry TLV * \param pan_id PAN ID * \param nw_name network name * \param gtks GTK keys @@ -35,12 +77,12 @@ * \return TLV entry or NULL * */ -void ws_pae_nvm_store_nw_info_tlv_create(nvm_tlv_entry_t *tlv_entry, uint16_t pan_id, char *nw_name, sec_prot_gtk_keys_t *gtks); +void ws_pae_nvm_store_nw_info_tlv_create(nvm_tlv_t *tlv_entry, uint16_t pan_id, char *nw_name, sec_prot_gtk_keys_t *gtks); /** * ws_pae_nvm_store_nw_info_tlv_read read from NVM network info TLV * - * \param tlv_entry TLV entry + * \param tlv_entry TLV * \param pan_id PAN ID * \param nw_name network name * \param gtks GTK keys @@ -49,50 +91,101 @@ void ws_pae_nvm_store_nw_info_tlv_create(nvm_tlv_entry_t *tlv_entry, uint16_t pa * \return >= 0 success * */ -int8_t ws_pae_nvm_store_nw_info_tlv_read(nvm_tlv_entry_t *tlv_entry, uint16_t *pan_id, char *nw_name, sec_prot_gtk_keys_t *gtks); +int8_t ws_pae_nvm_store_nw_info_tlv_read(nvm_tlv_t *tlv_entry, uint16_t *pan_id, char *nw_name, sec_prot_gtk_keys_t *gtks); /** * ws_pae_nvm_store_keys_tlv_create create NVM keys TLV * - * \param tlv_entry TLV entry buffer pointer + * \param tlv_entry TLV * \param sec_keys security keys * */ -void ws_pae_nvm_store_keys_tlv_create(nvm_tlv_entry_t *tlv_entry, sec_prot_keys_t *sec_keys); +void ws_pae_nvm_store_keys_tlv_create(nvm_tlv_t *tlv_entry, sec_prot_keys_t *sec_keys); /** * ws_pae_nvm_store_nw_info_tlv_read read from NVM keys TLV * - * \param tlv_entry TLV entry + * \param tlv_entry TLV * \param sec_keys security keys * * \return < 0 failure * \return >= 0 success * */ -int8_t ws_pae_nvm_store_keys_tlv_read(nvm_tlv_entry_t *tlv_entry, sec_prot_keys_t *sec_keys); +int8_t ws_pae_nvm_store_keys_tlv_read(nvm_tlv_t *tlv_entry, sec_prot_keys_t *sec_keys); /** * ws_pae_nvm_store_frame_counter_tlv_create create NVM frame counter TLV * - * \param tlv_entry TLV entry buffer pointer + * \param tlv_entry TLV buffer pointer + * \param restart_cnt re-start counter * \param counters frame counters * */ -void ws_pae_nvm_store_frame_counter_tlv_create(nvm_tlv_entry_t *tlv_entry, frame_counters_t *counters); +void ws_pae_nvm_store_frame_counter_tlv_create(nvm_tlv_t *tlv_entry, uint32_t restart_cnt, frame_counters_t *counters); /** * ws_pae_nvm_store_frame_counter_tlv_read read from NVM frame counter TLV * - * \param tlv_entry TLV entry + * \param tlv_entry TLV + * \param restart_cnt re-start counter + * \param stored_time stored timestampt * \param counters frame counters * * \return < 0 failure * \return >= 0 success * */ -int8_t ws_pae_nvm_store_frame_counter_tlv_read(nvm_tlv_entry_t *tlv_entry, frame_counters_t *counters); +int8_t ws_pae_nvm_store_frame_counter_tlv_read(nvm_tlv_t *tlv_entry, uint32_t *restart_cnt, uint64_t *stored_time, frame_counters_t *counters); -nvm_tlv_entry_t *ws_pae_buffer_allocate(void); +/** + * ws_pae_nvm_store_key_storage_index_tlv_create create NVM key storage index TLV + * + * \param tlv_entry TLV entry + * \param bitfield index of filenames + * + * \return < 0 failure + * \return >= 0 success + * + */ +void ws_pae_nvm_store_key_storage_index_tlv_create(nvm_tlv_t *tlv_entry, uint64_t bitfield); + +/** + * ws_pae_nvm_store_key_storage_index_tlv_read read NVM key storage index TLV + * + * \param tlv_entry TLV entry + * \param bitfield index of filenames + * + * \return < 0 failure + * \return >= 0 success + * + */ +int8_t ws_pae_nvm_store_key_storage_index_tlv_read(nvm_tlv_t *tlv_entry, uint64_t *bitfield); + +/** + * ws_pae_nvm_store_key_storage_tlv_create create NVM key storage TLV + * + * \param tlv_entry TLV entry + * \param length length of the (whole) entry + * + * \return < 0 failure + * \return >= 0 success + * + */ +void ws_pae_nvm_store_key_storage_tlv_create(nvm_tlv_t *tlv_entry, uint16_t length); + +/** + * ws_pae_nvm_store_key_storage_tlv_read read NVM key storage TLV + * + * \param tlv_entry TLV entry + * \param length length of the (whole) entry + * + * \return < 0 failure + * \return >= 0 success + * + */ +int8_t ws_pae_nvm_store_key_storage_tlv_read(nvm_tlv_t *tlv_entry, uint16_t length); + +nvm_tlv_t *ws_pae_buffer_allocate(void); #endif /* WS_PAE_NVM_DATA_H_ */ diff --git a/source/6LoWPAN/ws/ws_pae_nvm_store.c b/source/6LoWPAN/ws/ws_pae_nvm_store.c index aa873bdf86..b4a9108bca 100644 --- a/source/6LoWPAN/ws/ws_pae_nvm_store.c +++ b/source/6LoWPAN/ws/ws_pae_nvm_store.c @@ -17,7 +17,6 @@ #include "nsconfig.h" #include -#include #include "ns_types.h" #include "ns_list.h" #include "ns_trace.h" @@ -25,9 +24,11 @@ #include "common_functions.h" #include "6LoWPAN/ws/ws_config.h" #include "ns_file_system.h" +#include "Service_Libs/utils/ns_file.h" #include "Security/protocols/sec_prot_certs.h" #include "Security/protocols/sec_prot_keys.h" #include "6LoWPAN/ws/ws_pae_nvm_store.h" +#include "ns_file_system.h" #ifdef HAVE_WS @@ -39,10 +40,10 @@ static uint16_t ws_pae_nvm_store_path_len_get(const char *file_name); static const char *ws_pae_nvm_store_get_root_path(void); static int8_t ws_pae_nvm_store_root_path_valid(void); static int8_t ws_pae_nvm_store_create_path(char *fast_data_path, const char *file_name); -static int8_t ws_pae_nvm_store_write(const char *file_name, nvm_tlv_list_t *tlv_list); -static int8_t ws_pae_nvm_store_read(const char *file_name, nvm_tlv_list_t *tlv_list); +static int8_t ws_pae_nvm_store_write(const char *file_name, nvm_tlv_t *tlv); +static int8_t ws_pae_nvm_store_read(const char *file_name, nvm_tlv_t *tlv); -int8_t ws_pae_nvm_store_tlv_file_write(const char *file, nvm_tlv_list_t *tlv_list) +int8_t ws_pae_nvm_store_tlv_file_write(const char *file, nvm_tlv_t *tlv) { if (!ws_pae_nvm_store_root_path_valid()) { return PAE_NVM_FILE_ROOT_PATH_INVALID; @@ -54,10 +55,10 @@ int8_t ws_pae_nvm_store_tlv_file_write(const char *file, nvm_tlv_list_t *tlv_lis ws_pae_nvm_store_create_path(nw_info_path, file); - return ws_pae_nvm_store_write(nw_info_path, tlv_list); + return ws_pae_nvm_store_write(nw_info_path, tlv); } -int8_t ws_pae_nvm_store_tlv_file_read(const char *file, nvm_tlv_list_t *tlv_list) +int8_t ws_pae_nvm_store_tlv_file_read(const char *file, nvm_tlv_t *tlv) { if (!ws_pae_nvm_store_root_path_valid()) { return PAE_NVM_FILE_ROOT_PATH_INVALID; @@ -69,7 +70,27 @@ int8_t ws_pae_nvm_store_tlv_file_read(const char *file, nvm_tlv_list_t *tlv_list ws_pae_nvm_store_create_path(nw_info_path, file); - return ws_pae_nvm_store_read(nw_info_path, tlv_list); + return ws_pae_nvm_store_read(nw_info_path, tlv); +} + +int8_t ws_pae_nvm_store_tlv_file_remove(const char *file) +{ + if (!ws_pae_nvm_store_root_path_valid()) { + return PAE_NVM_FILE_ROOT_PATH_INVALID; + } + + uint16_t path_len = ws_pae_nvm_store_path_len_get(file); + + char nw_info_path[path_len]; + + ws_pae_nvm_store_create_path(nw_info_path, file); + + int ret = ns_fremove(nw_info_path); + if (ret < 0) { + return -1; + } + + return 0; } static const char *ws_pae_nvm_store_get_root_path(void) @@ -106,104 +127,49 @@ static int8_t ws_pae_nvm_store_create_path(char *data_path, const char *file_nam return 0; } -static int8_t ws_pae_nvm_store_write(const char *file_name, nvm_tlv_list_t *tlv_list) +static int8_t ws_pae_nvm_store_write(const char *file_name, nvm_tlv_t *tlv) { - FILE *fp = fopen(file_name, "w"); + if (!file_name || !tlv) { + return -1; + } + + NS_FILE *fp = ns_fopen(file_name, "w"); if (fp == NULL) { tr_error("NVM open error: %s", file_name); return PAE_NVM_FILE_CANNOT_OPEN; } - uint16_t list_count = ns_list_count(tlv_list); - size_t n_bytes = fwrite(&list_count, 1, sizeof(uint16_t), fp); - if (n_bytes != sizeof(uint16_t)) { - tr_warning("NVM TLV list count write error"); - fclose(fp); - return PAE_NVM_FILE_WRITE_ERROR; - } - - bool failure = false; - - ns_list_foreach(nvm_tlv_entry_t, entry, tlv_list) { - n_bytes = fwrite(&entry->tag, 1, entry->len + NVM_TLV_FIXED_LEN, fp); - if (n_bytes != (size_t) entry->len + NVM_TLV_FIXED_LEN) { - failure = true; - break; - } - } - - fclose(fp); - if (failure) { + size_t n_bytes = ns_fwrite(fp, tlv, tlv->len + sizeof(nvm_tlv_t)); + ns_fclose(fp); + if (n_bytes != tlv->len + sizeof(nvm_tlv_t)) { tr_error("NVM write error %s", file_name); return PAE_NVM_FILE_WRITE_ERROR; - } else { - return PAE_NVM_FILE_SUCCESS; } + + return PAE_NVM_FILE_SUCCESS; } -static int8_t ws_pae_nvm_store_read(const char *file_name, nvm_tlv_list_t *tlv_list) +static int8_t ws_pae_nvm_store_read(const char *file_name, nvm_tlv_t *tlv) { - FILE *fp = fopen(file_name, "r"); + if (!file_name || !tlv) { + return -1; + } + + NS_FILE *fp = ns_fopen(file_name, "r"); if (fp == NULL) { tr_warning("File not found: %s", file_name); return PAE_NVM_FILE_CANNOT_OPEN; } - uint16_t list_count; - size_t n_bytes = fread(&list_count, 1, sizeof(uint16_t), fp); - if (n_bytes != sizeof(uint16_t)) { - tr_warning("NVM TLV list count read error %s", file_name); - fclose(fp); + size_t n_bytes = ns_fread(fp, tlv, tlv->len + sizeof(nvm_tlv_t)); + ns_fclose(fp); + if (n_bytes != tlv->len + sizeof(nvm_tlv_t)) { + tr_warning("File not found or cannot be read: %s", file_name); return PAE_NVM_FILE_READ_ERROR; } - bool failure = false; - - while (list_count-- > 0) { - nvm_tlv_entry_t entry_header; - memset(&entry_header, 0, sizeof(nvm_tlv_entry_t)); - n_bytes = fread(&entry_header.tag, 1, NVM_TLV_FIXED_LEN, fp); - if (n_bytes != NVM_TLV_FIXED_LEN) { - failure = true; - break; - } - uint16_t len = entry_header.len; - - nvm_tlv_entry_t *entry = ns_dyn_mem_temporary_alloc(sizeof(nvm_tlv_entry_t) + len); - if (!entry) { - failure = true; - break; - } - - memcpy(&entry->tag, &entry_header.tag, NVM_TLV_FIXED_LEN); - - if (len > 0) { - uint8_t *data_ptr = ((uint8_t *)&entry->tag) + NVM_TLV_FIXED_LEN; - n_bytes = fread(data_ptr, 1, len, fp); - if (n_bytes != len) { - ns_dyn_mem_free(entry); - failure = true; - break; - } - } - - ns_list_add_to_end(tlv_list, entry); - } - - fclose(fp); - - if (failure) { - ns_list_foreach_safe(nvm_tlv_entry_t, entry, tlv_list) { - ns_list_remove(tlv_list, entry); - ns_dyn_mem_free(entry); - } - tr_error("NVM read error %s", file_name); - return PAE_NVM_FILE_READ_ERROR; - } else { - return PAE_NVM_FILE_SUCCESS; // return how many bytes was written. - } + return PAE_NVM_FILE_SUCCESS; } - #endif /* HAVE_WS */ diff --git a/source/6LoWPAN/ws/ws_pae_nvm_store.h b/source/6LoWPAN/ws/ws_pae_nvm_store.h index 84838ef6f3..fb741da833 100644 --- a/source/6LoWPAN/ws/ws_pae_nvm_store.h +++ b/source/6LoWPAN/ws/ws_pae_nvm_store.h @@ -24,22 +24,6 @@ * */ -// tag + length -#define NVM_TLV_FIXED_LEN 4 - -// file names -#define NW_INFO_FILE_NAME "pae_nw_info" -#define KEYS_FILE_NAME "pae_keys" -#define FRAME_COUNTER_FILE_NAME "pae_frame_counter" - -typedef struct nvm_tlv_entry { - ns_list_link_t link; /**< Link */ - uint16_t tag; /**< Unique tag */ - uint16_t len; /**< Number of the bytes after the length field */ -} nvm_tlv_entry_t; - -typedef NS_LIST_HEAD(nvm_tlv_entry_t, link) nvm_tlv_list_t; - #define PAE_NVM_FILE_SUCCESS 0 #define PAE_NVM_FILE_READ_ERROR -1 #define PAE_NVM_FILE_WRITE_ERROR -2 @@ -49,28 +33,53 @@ typedef NS_LIST_HEAD(nvm_tlv_entry_t, link) nvm_tlv_list_t; #define PAE_NVM_FILE_PARAMETER_INVALID -6 #define PAE_NVM_FILE_REMOVE_ERROR -7 +typedef struct nvm_tlv { + uint16_t tag; /**< Unique tag */ + uint16_t len; /**< Number of the bytes after the length field */ +} nvm_tlv_t; + +typedef struct { + nvm_tlv_t nvm_tlv; /**< NVM TLV */ + uint64_t reference_time; /**< Reference time used for timers (set when file is created) */ + uint32_t reference_restart_cnt; /**< Reference re-start counter set when file is created) */ +} key_storage_nvm_tlv_entry_t; + +// tag + length +#define NVM_TLV_FIXED_LEN sizeof(nvm_tlv_t) + /** * ws_pae_nvm_store_tlv_file_write write a list of TLVs to file * * \param file file name - * \param tlv_list TLV list + * \param tlv TLV * * \return < 0 failure * \return >= 0 success * */ -int8_t ws_pae_nvm_store_tlv_file_write(const char *file, nvm_tlv_list_t *tlv_list); +int8_t ws_pae_nvm_store_tlv_file_write(const char *file, nvm_tlv_t *tlv); /** * ws_pae_nvm_store_tlv_file_read read a list of TLVs from file * * \param file file name - * \param tlv_list TLV list + * \param tlv TLV * * \return < 0 failure * \return >= 0 success * */ -int8_t ws_pae_nvm_store_tlv_file_read(const char *file, nvm_tlv_list_t *tlv_list); +int8_t ws_pae_nvm_store_tlv_file_read(const char *file, nvm_tlv_t *tlv); + +/** + * ws_pae_nvm_store_tlv_file_remove delete a file + * + * \param file file name + * + * \return < 0 failure + * \return >= 0 success + * + */ +int8_t ws_pae_nvm_store_tlv_file_remove(const char *file); #endif /* WS_PAE_NVM_STORE_H_ */ diff --git a/source/6LoWPAN/ws/ws_pae_supp.c b/source/6LoWPAN/ws/ws_pae_supp.c index a9e955366e..7954010d50 100644 --- a/source/6LoWPAN/ws/ws_pae_supp.c +++ b/source/6LoWPAN/ws/ws_pae_supp.c @@ -28,6 +28,7 @@ #include "eventOS_scheduler.h" #include "eventOS_event_timer.h" #include "ns_address.h" +#include "Service_Libs/utils/ns_file.h" #include "NWK_INTERFACE/Include/protocol.h" #include "RPL/rpl_protocol.h" #include "RPL/rpl_control.h" @@ -48,6 +49,7 @@ #include "6LoWPAN/ws/ws_pae_timers.h" #include "6LoWPAN/ws/ws_pae_supp.h" #include "6LoWPAN/ws/ws_pae_lib.h" +#include "6LoWPAN/ws/ws_pae_time.h" #include "6LoWPAN/ws/ws_pae_nvm_store.h" #include "6LoWPAN/ws/ws_pae_nvm_data.h" #include "6LoWPAN/MAC/mpx_api.h" @@ -79,31 +81,25 @@ #define INITIAL_KEY_TIMER_MIN 3 #define INITIAL_KEY_TIMER_MAX 30 -typedef struct { - char network_name[33]; /**< Network name for keys */ - sec_prot_gtk_keys_t *gtks; /**< Link to GTKs */ - uint16_t new_pan_id; /**< new PAN ID indicated by bootstrap */ - uint16_t key_pan_id; /**< PAN ID for keys */ - bool updated : 1; /**< Network info has been updated */ -} sec_prot_keys_nw_info_t; - typedef struct { ns_list_link_t link; /**< Link */ kmp_service_t *kmp_service; /**< KMP service */ protocol_interface_info_entry_t *interface_ptr; /**< Interface */ ws_pae_supp_auth_completed *auth_completed; /**< Authentication completed callback, continue bootstrap */ + ws_pae_supp_auth_next_target *auth_next_target; /**< Authentication next target callback */ ws_pae_supp_nw_key_insert *nw_key_insert; /**< Key insert callback */ ws_pae_supp_nw_key_index_set *nw_key_index_set; /**< Key index set callback */ ws_pae_supp_gtk_hash_ptr_get *gtk_hash_ptr_get; /**< Get pointer to GTK hash storage callback */ + ws_pae_supp_nw_info_updated *nw_info_updated; /**< Security keys network info updated callback */ supp_entry_t entry; /**< Supplicant data */ kmp_addr_t target_addr; /**< EAPOL target (parent) address */ uint16_t initial_key_timer; /**< Timer to trigger initial EAPOL-Key */ uint16_t initial_key_retry_timer; /**< Timer to trigger initial EAPOL-Key 1st retry */ trickle_t auth_trickle_timer; /**< Trickle timer for re-sending initial EAPOL-key or for GTK mismatch */ trickle_params_t auth_trickle_params; /**< Trickle parameters for initial EAPOL-key or for GTK mismatch */ - sec_prot_gtk_keys_t gtks; /**< GTKs */ - uint8_t new_br_eui_64[8]; /**< Border router EUI-64 indicated by bootstrap */ - sec_prot_keys_nw_info_t sec_keys_nw_info; /**< Security keys network information */ + uint8_t new_br_eui_64[8]; /**< Border router EUI-64 indicated by bootstrap after bootstrap start */ + uint8_t comp_br_eui_64[8]; /**< Border router EUI-64 indicated by bootstrap after bootstrap completed */ + sec_prot_keys_nw_info_t *sec_keys_nw_info; /**< Security keys network information */ sec_timer_cfg_t *sec_timer_cfg; /**< Timer configuration */ sec_prot_cfg_t *sec_prot_cfg; /**< Protocol Configuration */ uint8_t nw_keys_used_cnt; /**< How many times bootstrap has been tried with current keys */ @@ -111,47 +107,26 @@ typedef struct { bool auth_trickle_running : 1; /**< Initial EAPOL-Key Trickle timer running */ bool auth_requested : 1; /**< Authentication has been requested by the bootstrap */ bool timer_running : 1; /**< Timer is running */ - bool new_br_eui_64_set : 1; /**< Border router address has been set */ + bool new_br_eui_64_set : 1; /**< Border router address has been set after bootstrap start */ bool new_br_eui_64_fresh : 1; /**< Border router address is fresh (set during this authentication attempt) */ - bool entry_address_active: 1; + bool comp_br_eui_64_set : 1; /**< Border router address has been set after bootstrap completed */ + bool entry_address_active: 1; /**< EAPOL target address is set */ + bool tx_failure_on_initial_key: 1; /**< TX failure has happened on initial EAPOL-key sequence */ } pae_supp_t; -// How many times sending of initial EAPOL-key is retried -#define INITIAL_KEY_RETRY_COUNT 2 - // How many times sending of initial EAPOL-key is initiated on key update #define KEY_UPDATE_RETRY_COUNT 3 #define LIFETIME_MISMATCH_RETRY_COUNT 1 /* No retries */ -// How long the wait is before the first initial EAPOL-key retry -#define DEFAULT_INITIAL_KEY_RETRY_TIMER 120 -#define NONE_INITIAL_KEY_RETRY_TIMER 0 - -// Default trickle values for sending of initial EAPOL-key -#define DEFAULT_TRICKLE_IMIN_SECS 360 /* 6 to 12 minutes */ -#define DEFAULT_TRICKLE_IMAX_SECS 720 - -// Very slow network values for sending of initial EAPOL-key -#define VERY_SLOW_NW_TRICKLE_IMIN_SECS 600 /* 10 to 60 minutes */ -#define VERY_SLOW_NW_TRICKLE_IMAX_SECS 3600 - // Trickle timer on how long to wait response after last retry before failing authentication #define LAST_INTERVAL_TRICKLE_IMIN_SECS 240 /* 4 minutes */ #define LAST_INTERVAL_TRICKLE_IMAX_SECS 240 -static trickle_params_t initial_eapol_key_trickle_params = { - .Imin = DEFAULT_TRICKLE_IMIN_SECS, /* 360 second; ticks are 1 second */ - .Imax = DEFAULT_TRICKLE_IMAX_SECS, /* 720 second */ - .k = 0, /* infinity - no consistency checking */ - .TimerExpirations = 2 -}; - static void ws_pae_supp_free(pae_supp_t *pae_supp); static void ws_pae_supp_authenticate_response(pae_supp_t *pae_supp, auth_result_e result); static int8_t ws_pae_supp_initial_key_send(pae_supp_t *pae_supp); static void ws_pae_supp_nvm_update(pae_supp_t *pae_supp); -static int8_t ws_pae_supp_nw_keys_valid_check(pae_supp_t *pae_supp, uint16_t pan_id); -static int8_t ws_pae_supp_nvm_nw_info_write(pae_supp_t *pae_supp); +static int8_t ws_pae_supp_nw_keys_valid_check(pae_supp_t *pae_supp, uint16_t pan_id, char *dest_network_name); static int8_t ws_pae_supp_nvm_keys_write(pae_supp_t *pae_supp); static pae_supp_t *ws_pae_supp_get(protocol_interface_info_entry_t *interface_ptr); static int8_t ws_pae_supp_event_send(kmp_service_t *service, void *data); @@ -182,16 +157,15 @@ static void ws_pae_supp_kmp_api_finished(kmp_api_t *kmp); static const eapol_pdu_recv_cb_data_t eapol_pdu_recv_cb_data = { .priority = EAPOL_PDU_RECV_HIGH_PRIORITY, + .filter_requsted = false, .addr_check = ws_pae_supp_eapol_pdu_address_check, .receive = kmp_eapol_pdu_if_receive }; -static const char *NW_INFO_FILE = NW_INFO_FILE_NAME; static const char *KEYS_FILE = KEYS_FILE_NAME; static int8_t tasklet_id = -1; static NS_LIST_DEFINE(pae_supp_list, pae_supp_t, link); -static uint8_t timing_value = 0; // Timing value set based e.g. on network size static void ws_pae_supp_address_set(pae_supp_t *pae_supp, kmp_addr_t *address) { @@ -209,33 +183,35 @@ static bool ws_pae_supp_address_is_set(pae_supp_t *pae_supp) return pae_supp->entry_address_active; } -int8_t ws_pae_supp_authenticate(protocol_interface_info_entry_t *interface_ptr, uint16_t dest_pan_id, uint8_t *dest_eui_64) +int8_t ws_pae_supp_authenticate(protocol_interface_info_entry_t *interface_ptr, uint16_t dest_pan_id, uint8_t *dest_eui_64, char *dest_network_name) { pae_supp_t *pae_supp = ws_pae_supp_get(interface_ptr); if (!pae_supp) { return -1; } - if (ws_pae_supp_nw_keys_valid_check(pae_supp, dest_pan_id) >= 0) { + if (ws_pae_supp_nw_keys_valid_check(pae_supp, dest_pan_id, dest_network_name) >= 0) { pae_supp->auth_completed(interface_ptr, AUTH_RESULT_OK, NULL); return 0; } // Delete GTKs - sec_prot_keys_gtks_init(pae_supp->sec_keys_nw_info.gtks); + sec_prot_keys_gtks_init(pae_supp->sec_keys_nw_info->gtks); - /* PAN ID has changed, delete key data associated with border router + /* Network name or PAN ID has changed, delete key data associated with border router i.e PMK, PTK, EA-IE data (border router EUI-64) */ - if (pae_supp->sec_keys_nw_info.key_pan_id != 0xFFFF && pae_supp->sec_keys_nw_info.key_pan_id != dest_pan_id) { + if (strcmp(pae_supp->sec_keys_nw_info->network_name, dest_network_name) != 0 || + (pae_supp->sec_keys_nw_info->key_pan_id != 0xFFFF && pae_supp->sec_keys_nw_info->key_pan_id != dest_pan_id)) { sec_prot_keys_pmk_delete(&pae_supp->entry.sec_keys); sec_prot_keys_ptk_delete(&pae_supp->entry.sec_keys); sec_prot_keys_ptk_eui_64_delete(&pae_supp->entry.sec_keys); } - pae_supp->sec_keys_nw_info.key_pan_id = dest_pan_id; + pae_supp->sec_keys_nw_info->key_pan_id = dest_pan_id; // Prepare to receive new border router address pae_supp->new_br_eui_64_fresh = false; + pae_supp->comp_br_eui_64_set = false; // Stores target/parent address kmp_address_init(KMP_ADDR_EUI_64, &pae_supp->target_addr, dest_eui_64); @@ -255,29 +231,6 @@ int8_t ws_pae_supp_authenticate(protocol_interface_info_entry_t *interface_ptr, return 1; } -int8_t ws_pae_supp_nw_info_set(protocol_interface_info_entry_t *interface_ptr, uint16_t pan_id, char *network_name) -{ - pae_supp_t *pae_supp = ws_pae_supp_get(interface_ptr); - if (!pae_supp) { - return -1; - } - - // PAN ID has been modified - if (pan_id != 0xffff && pan_id != pae_supp->sec_keys_nw_info.new_pan_id) { - pae_supp->sec_keys_nw_info.new_pan_id = pan_id; - pae_supp->sec_keys_nw_info.updated = true; - } - - // Network name has been modified - if (network_name && strncmp(pae_supp->sec_keys_nw_info.network_name, network_name, 33) != 0) { - strncpy(pae_supp->sec_keys_nw_info.network_name, network_name, 32); - pae_supp->sec_keys_nw_info.updated = true; - } - - - return 0; -} - int8_t ws_pae_supp_border_router_addr_write(protocol_interface_info_entry_t *interface_ptr, const uint8_t *eui_64) { pae_supp_t *pae_supp = ws_pae_supp_get(interface_ptr); @@ -299,9 +252,14 @@ int8_t ws_pae_supp_border_router_addr_read(protocol_interface_info_entry_t *inte return -1; } + // Check if there is border router EUI-64 on used on 4WH PTK generation uint8_t *br_eui_64 = sec_prot_keys_ptk_eui_64_get(&pae_supp->entry.sec_keys); if (!br_eui_64) { - return -1; + // Check if there is border router EUI-64 indicated by the bootstrap when bootstrap completed + if (!pae_supp->comp_br_eui_64_set) { + return -1; + } + br_eui_64 = pae_supp->comp_br_eui_64; } memcpy(eui_64, br_eui_64, 8); @@ -309,14 +267,31 @@ int8_t ws_pae_supp_border_router_addr_read(protocol_interface_info_entry_t *inte return 0; } -int8_t ws_pae_supp_nw_key_valid(protocol_interface_info_entry_t *interface_ptr) +int8_t ws_pae_supp_nw_key_valid(protocol_interface_info_entry_t *interface_ptr, uint8_t *br_iid) { pae_supp_t *pae_supp = ws_pae_supp_get(interface_ptr); if (!pae_supp) { return -1; } - tr_info("NW key valid"); + tr_info("NW key valid indication"); + + // Store border router EUI-64 received on bootstrap complete + memcpy(pae_supp->comp_br_eui_64, br_iid, 8); + pae_supp->comp_br_eui_64[0] ^= 0x02; + pae_supp->comp_br_eui_64_set = true; + + // Get the EUI-64 used on 4WH handshake PTK generation + uint8_t *ptk_eui_64 = sec_prot_keys_ptk_eui_64_get(&pae_supp->entry.sec_keys); + + /* If border router EUI-64 received on bootstrap complete does not match to + EUI-64 stored with keys, delete keys */ + if (memcmp(ptk_eui_64, pae_supp->comp_br_eui_64, 8) != 0) { + tr_warn("Delete keys: PTK EUI-64 %s does not match to BR EUI-64 %s", tr_array(ptk_eui_64, 8), tr_array(pae_supp->comp_br_eui_64, 8)); + sec_prot_keys_pmk_delete(&pae_supp->entry.sec_keys); + sec_prot_keys_ptk_delete(&pae_supp->entry.sec_keys); + sec_prot_keys_ptk_eui_64_delete(&pae_supp->entry.sec_keys); + } // Stored keys are valid pae_supp->nw_keys_used_cnt = 0; @@ -335,7 +310,7 @@ static int8_t ws_pae_supp_gtk_hash_mismatch_check(pae_supp_t *pae_supp) } // Check GTK hashes and initiate EAPOL procedure if mismatch is detected */ - gtk_mismatch_e mismatch = sec_prot_keys_gtks_hash_update(&pae_supp->gtks, gtkhash); + gtk_mismatch_e mismatch = sec_prot_keys_gtks_hash_update(pae_supp->sec_keys_nw_info->gtks, gtkhash); if (mismatch != GTK_NO_MISMATCH) { return -1; } @@ -352,7 +327,7 @@ int8_t ws_pae_supp_gtk_hash_update(protocol_interface_info_entry_t *interface_pt } // Check GTK hashes and initiate EAPOL procedure if mismatch is detected */ - gtk_mismatch_e mismatch = sec_prot_keys_gtks_hash_update(&pae_supp->gtks, gtkhash); + gtk_mismatch_e mismatch = sec_prot_keys_gtks_hash_update(pae_supp->sec_keys_nw_info->gtks, gtkhash); if (mismatch > GTK_NO_MISMATCH) { tr_info("GTK hash update %s %s %s %s", trace_array(>khash[0], 8), @@ -379,7 +354,7 @@ int8_t ws_pae_supp_gtk_hash_update(protocol_interface_info_entry_t *interface_pt } // Modify keys - pae_supp->nw_key_insert(pae_supp->interface_ptr, pae_supp->sec_keys_nw_info.gtks); + pae_supp->nw_key_insert(pae_supp->interface_ptr, pae_supp->sec_keys_nw_info->gtks); return 0; } @@ -391,7 +366,7 @@ int8_t ws_pae_supp_nw_key_index_update(protocol_interface_info_entry_t *interfac return -1; } - if (sec_prot_keys_gtk_status_active_set(&pae_supp->gtks, index) >= 0) { + if (sec_prot_keys_gtk_status_active_set(pae_supp->sec_keys_nw_info->gtks, index) >= 0) { pae_supp->nw_key_index_set(interface_ptr, index); } else { tr_info("NW send key index: %i, no changes", index + 1); @@ -407,7 +382,7 @@ int8_t ws_pae_supp_gtks_set(protocol_interface_info_entry_t *interface_ptr, sec_ return -1; } - pae_supp->gtks = *gtks; + *pae_supp->sec_keys_nw_info->gtks = *gtks; return 0; } @@ -427,12 +402,8 @@ int8_t ws_pae_supp_eapol_target_remove(protocol_interface_info_entry_t *interfac static void ws_pae_supp_nvm_update(pae_supp_t *pae_supp) { - // Check if NW info or GTKs have been changed - if (pae_supp->sec_keys_nw_info.updated || sec_prot_keys_gtks_are_updated(pae_supp->sec_keys_nw_info.gtks)) { - ws_pae_supp_nvm_nw_info_write(pae_supp); - pae_supp->sec_keys_nw_info.updated = false; - sec_prot_keys_gtks_updated_reset(pae_supp->sec_keys_nw_info.gtks); - } + // Indicate to PAE controller that NW info or GTKs may have been changed + pae_supp->nw_info_updated(pae_supp->interface_ptr); // Check if pairwise security keys have been changed if (sec_prot_keys_are_updated(&pae_supp->entry.sec_keys)) { @@ -441,75 +412,30 @@ static void ws_pae_supp_nvm_update(pae_supp_t *pae_supp) } } -static int8_t ws_pae_supp_nvm_nw_info_write(pae_supp_t *pae_supp) -{ - nvm_tlv_entry_t *tlv_entry = ws_pae_controller_nvm_tlv_get(pae_supp->interface_ptr); - if (!tlv_entry) { - return -1; - } - - nvm_tlv_list_t tlv_list; - ns_list_init(&tlv_list); - - ws_pae_nvm_store_nw_info_tlv_create(tlv_entry, pae_supp->sec_keys_nw_info.key_pan_id, - pae_supp->sec_keys_nw_info.network_name, - &pae_supp->gtks); - ns_list_add_to_end(&tlv_list, tlv_entry); - - ws_pae_nvm_store_tlv_file_write(NW_INFO_FILE, &tlv_list); - - return 0; -} - -static int8_t ws_pae_supp_nvm_nw_info_read(pae_supp_t *pae_supp) -{ - nvm_tlv_list_t tlv_list; - ns_list_init(&tlv_list); - - ws_pae_nvm_store_tlv_file_read(NW_INFO_FILE, &tlv_list); - - ns_list_foreach_safe(nvm_tlv_entry_t, entry, &tlv_list) { - ws_pae_nvm_store_nw_info_tlv_read(entry, &pae_supp->sec_keys_nw_info.key_pan_id, - pae_supp->sec_keys_nw_info.network_name, - &pae_supp->gtks); - ns_list_remove(&tlv_list, entry); - ns_dyn_mem_free(entry); - } - - return 0; -} - static int8_t ws_pae_supp_nvm_keys_write(pae_supp_t *pae_supp) { - nvm_tlv_entry_t *tlv_entry = ws_pae_controller_nvm_tlv_get(pae_supp->interface_ptr); - if (!tlv_entry) { + nvm_tlv_t *tlv = ws_pae_controller_nvm_tlv_get(pae_supp->interface_ptr); + if (!tlv) { return -1; } - nvm_tlv_list_t tlv_list; - ns_list_init(&tlv_list); - - ws_pae_nvm_store_keys_tlv_create(tlv_entry, &pae_supp->entry.sec_keys); - ns_list_add_to_end(&tlv_list, tlv_entry); - - ws_pae_nvm_store_tlv_file_write(KEYS_FILE, &tlv_list); + ws_pae_nvm_store_keys_tlv_create(tlv, &pae_supp->entry.sec_keys); + ws_pae_nvm_store_tlv_file_write(KEYS_FILE, tlv); return 0; } static int8_t ws_pae_supp_nvm_keys_read(pae_supp_t *pae_supp) { - nvm_tlv_list_t tlv_list; - ns_list_init(&tlv_list); - - ws_pae_nvm_store_tlv_file_read(KEYS_FILE, &tlv_list); - - ns_list_foreach_safe(nvm_tlv_entry_t, entry, &tlv_list) { - ws_pae_nvm_store_keys_tlv_read(entry, &pae_supp->entry.sec_keys); - ns_list_remove(&tlv_list, entry); - ns_dyn_mem_free(entry); + nvm_tlv_t *tlv = ws_pae_controller_nvm_tlv_get(pae_supp->interface_ptr); + if (!tlv) { + return -1; } - + ws_pae_nvm_store_generic_tlv_create(tlv, PAE_NVM_KEYS_TAG, PAE_NVM_KEYS_LEN); + if (ws_pae_nvm_store_tlv_file_read(KEYS_FILE_NAME, tlv) < 0) { + return -1; + } + ws_pae_nvm_store_keys_tlv_read(tlv, &pae_supp->entry.sec_keys); return 0; } @@ -562,29 +488,31 @@ static int8_t ws_pae_supp_initial_key_send(pae_supp_t *pae_supp) return 0; } -static int8_t ws_pae_supp_nw_keys_valid_check(pae_supp_t *pae_supp, uint16_t pan_id) +static int8_t ws_pae_supp_nw_keys_valid_check(pae_supp_t *pae_supp, uint16_t pan_id, char *dest_network_name) { // Checks how many times authentication has been tried with current network keys if (pae_supp->nw_keys_used_cnt >= STORED_KEYS_MAXIMUM_USE_COUNT) { tr_debug("Keys not valid, delete GTKs"); // Delete GTKs - sec_prot_keys_gtks_init(pae_supp->sec_keys_nw_info.gtks); - sec_prot_keys_gtks_updated_set(pae_supp->sec_keys_nw_info.gtks); + sec_prot_keys_gtks_init(pae_supp->sec_keys_nw_info->gtks); + sec_prot_keys_gtks_updated_set(pae_supp->sec_keys_nw_info->gtks); ws_pae_supp_nvm_update(pae_supp); pae_supp->nw_keys_used_cnt = 0; return -1; } - /* Checks if keys match to PAN ID and that needed keys exists (PMK, PTK and a GTK), - and calls inserts function that will update the network keys as needed */ - if ((pan_id == pae_supp->sec_keys_nw_info.key_pan_id) && - (sec_prot_keys_gtk_count(pae_supp->sec_keys_nw_info.gtks) > 0) && + /* Checks if keys match to network name and PAN ID and that needed keys exists (PMK, + PTK and a GTK), and calls inserts function that will update the network keys as + needed */ + if ((strcmp(dest_network_name, pae_supp->sec_keys_nw_info->network_name) == 0 && + pan_id == pae_supp->sec_keys_nw_info->key_pan_id) && + (sec_prot_keys_gtk_count(pae_supp->sec_keys_nw_info->gtks) > 0) && (sec_prot_keys_pmk_get(&pae_supp->entry.sec_keys) != NULL) && (sec_prot_keys_ptk_get(&pae_supp->entry.sec_keys) != NULL)) { tr_debug("Existing keys used, counter %i", pae_supp->nw_keys_used_cnt); - if (pae_supp->nw_key_insert(pae_supp->interface_ptr, pae_supp->sec_keys_nw_info.gtks) >= 0) { + if (pae_supp->nw_key_insert(pae_supp->interface_ptr, pae_supp->sec_keys_nw_info->gtks) >= 0) { tr_debug("Keys inserted"); } pae_supp->nw_keys_used_cnt++; @@ -595,21 +523,7 @@ static int8_t ws_pae_supp_nw_keys_valid_check(pae_supp_t *pae_supp, uint16_t pan } } -static void ws_pae_supp_keys_nw_info_init(sec_prot_keys_nw_info_t *sec_keys_nw_info, sec_prot_gtk_keys_t *gtks) -{ - if (!sec_keys_nw_info) { - return; - } - - memset(sec_keys_nw_info, 0, sizeof(sec_prot_keys_nw_info_t)); - - sec_keys_nw_info->gtks = gtks; - sec_keys_nw_info->new_pan_id = 0xFFFF; - sec_keys_nw_info->key_pan_id = 0xFFFF; - sec_keys_nw_info->updated = false; -} - -void ws_pae_supp_cb_register(protocol_interface_info_entry_t *interface_ptr, ws_pae_supp_auth_completed *completed, ws_pae_supp_nw_key_insert *nw_key_insert, ws_pae_supp_nw_key_index_set *nw_key_index_set, ws_pae_supp_gtk_hash_ptr_get *gtk_hash_ptr_get) +void ws_pae_supp_cb_register(protocol_interface_info_entry_t *interface_ptr, ws_pae_supp_auth_completed *completed, ws_pae_supp_auth_next_target *auth_next_target, ws_pae_supp_nw_key_insert *nw_key_insert, ws_pae_supp_nw_key_index_set *nw_key_index_set, ws_pae_supp_gtk_hash_ptr_get *gtk_hash_ptr_get, ws_pae_supp_nw_info_updated *nw_info_updated) { pae_supp_t *pae_supp = ws_pae_supp_get(interface_ptr); if (!pae_supp) { @@ -617,12 +531,14 @@ void ws_pae_supp_cb_register(protocol_interface_info_entry_t *interface_ptr, ws_ } pae_supp->auth_completed = completed; + pae_supp->auth_next_target = auth_next_target; pae_supp->nw_key_insert = nw_key_insert; pae_supp->nw_key_index_set = nw_key_index_set; pae_supp->gtk_hash_ptr_get = gtk_hash_ptr_get; + pae_supp->nw_info_updated = nw_info_updated; } -int8_t ws_pae_supp_init(protocol_interface_info_entry_t *interface_ptr, const sec_prot_certs_t *certs, sec_timer_cfg_t *sec_timer_cfg, sec_prot_cfg_t *sec_prot_cfg) +int8_t ws_pae_supp_init(protocol_interface_info_entry_t *interface_ptr, const sec_prot_certs_t *certs, sec_timer_cfg_t *sec_timer_cfg, sec_prot_cfg_t *sec_prot_cfg, sec_prot_keys_nw_info_t *sec_keys_nw_info) { if (!interface_ptr) { return -1; @@ -639,13 +555,15 @@ int8_t ws_pae_supp_init(protocol_interface_info_entry_t *interface_ptr, const se pae_supp->interface_ptr = interface_ptr; pae_supp->auth_completed = NULL; + pae_supp->auth_next_target = NULL; pae_supp->nw_key_insert = NULL; pae_supp->nw_key_index_set = NULL; pae_supp->gtk_hash_ptr_get = NULL; pae_supp->initial_key_timer = 0; pae_supp->initial_key_retry_timer = 0; pae_supp->nw_keys_used_cnt = 0; - pae_supp->initial_key_retry_cnt = INITIAL_KEY_RETRY_COUNT; + pae_supp->initial_key_retry_cnt = DEFAULT_INITIAL_KEY_RETRY_COUNT; + pae_supp->sec_keys_nw_info = sec_keys_nw_info; pae_supp->sec_timer_cfg = sec_timer_cfg; pae_supp->sec_prot_cfg = sec_prot_cfg; pae_supp->auth_trickle_running = false; @@ -653,16 +571,15 @@ int8_t ws_pae_supp_init(protocol_interface_info_entry_t *interface_ptr, const se pae_supp->timer_running = false; pae_supp->new_br_eui_64_set = false; pae_supp->new_br_eui_64_fresh = false; + pae_supp->comp_br_eui_64_set = false; pae_supp->entry_address_active = false; ws_pae_lib_supp_init(&pae_supp->entry); - ws_pae_supp_keys_nw_info_init(&pae_supp->sec_keys_nw_info, &pae_supp->gtks); - kmp_address_init(KMP_ADDR_EUI_64, &pae_supp->target_addr, 0); - sec_prot_keys_gtks_init(&pae_supp->gtks); - sec_prot_keys_init(&pae_supp->entry.sec_keys, &pae_supp->gtks, certs); + sec_prot_keys_gtks_init(pae_supp->sec_keys_nw_info->gtks); + sec_prot_keys_init(&pae_supp->entry.sec_keys, pae_supp->sec_keys_nw_info->gtks, certs); memset(pae_supp->new_br_eui_64, 0, 8); pae_supp->kmp_service = kmp_service_create(); @@ -721,7 +638,6 @@ int8_t ws_pae_supp_init(protocol_interface_info_entry_t *interface_ptr, const se goto error; } - ws_pae_supp_nvm_nw_info_read(pae_supp); ws_pae_supp_nvm_keys_read(pae_supp); ns_list_add_to_end(&pae_supp_list, pae_supp); @@ -840,7 +756,7 @@ void ws_pae_supp_fast_timer(uint16_t ticks) } // Updates KMP timers and supplicant authentication ongoing timer - bool running = ws_pae_lib_supp_timer_update(&pae_supp->entry, ticks, kmp_service_timer_if_timeout); + bool running = ws_pae_lib_supp_timer_update(NULL, &pae_supp->entry, ticks, kmp_service_timer_if_timeout); // Checks whether timer needs to be active if (!ws_pae_supp_authentication_ongoing(pae_supp) && !running) { @@ -881,6 +797,15 @@ void ws_pae_supp_slow_timer(uint16_t seconds) // Checks if trickle timer expires if (trickle_timer(&pae_supp->auth_trickle_timer, &pae_supp->auth_trickle_params, seconds)) { if (pae_supp->initial_key_retry_cnt > 0) { + // On initial EAPOL-key TX failure, check for other parents + if (pae_supp->auth_requested && pae_supp->tx_failure_on_initial_key) { + // Returns same target if no other valid targets found + const uint8_t *next_target = pae_supp->auth_next_target(pae_supp->interface_ptr, kmp_address_eui_64_get(&pae_supp->target_addr), &pae_supp->sec_keys_nw_info->key_pan_id); + kmp_address_eui_64_set(&pae_supp->target_addr, next_target); + ws_pae_supp_address_set(pae_supp, &pae_supp->target_addr); + } + pae_supp->tx_failure_on_initial_key = false; + // Sends initial EAPOL-key if (ws_pae_supp_initial_key_send(pae_supp) < 0) { tr_info("EAPOL-Key send failed"); } @@ -895,7 +820,12 @@ void ws_pae_supp_slow_timer(uint16_t seconds) tr_info("GTKs do not match to GTK hash"); retry = true; } - ws_pae_supp_authenticate_response(pae_supp, AUTH_RESULT_ERR_UNSPEC); + auth_result_e result = AUTH_RESULT_ERR_UNSPEC; + if (pae_supp->tx_failure_on_initial_key) { + result = AUTH_RESULT_ERR_TX_NO_ACK; + pae_supp->tx_failure_on_initial_key = false; + } + ws_pae_supp_authenticate_response(pae_supp, result); if (retry) { // Start trickle timer to try re-authentication ws_pae_supp_initial_key_update_trickle_timer_start(pae_supp, KEY_UPDATE_RETRY_COUNT); @@ -921,10 +851,11 @@ void ws_pae_supp_slow_timer(uint16_t seconds) // Decrements GTK lifetimes for (uint8_t i = 0; i < GTK_NUM; i++) { - if (!sec_prot_keys_gtk_is_set(&pae_supp->gtks, i)) { + if (!sec_prot_keys_gtk_is_set(pae_supp->sec_keys_nw_info->gtks, i)) { continue; } - sec_prot_keys_gtk_lifetime_decrement(&pae_supp->gtks, i, seconds); + uint64_t current_time = ws_pae_current_time_get(); + sec_prot_keys_gtk_lifetime_decrement(pae_supp->sec_keys_nw_info->gtks, i, current_time, seconds); } if (pae_supp->initial_key_timer > 0) { @@ -932,7 +863,7 @@ void ws_pae_supp_slow_timer(uint16_t seconds) pae_supp->initial_key_timer -= seconds; } else { pae_supp->initial_key_timer = 0; - + pae_supp->tx_failure_on_initial_key = false; // Sends initial EAPOL-Key message if (ws_pae_supp_initial_key_send(pae_supp) < 0) { tr_info("EAPOL-Key send failed"); @@ -946,46 +877,40 @@ void ws_pae_supp_slow_timer(uint16_t seconds) static void ws_pae_supp_initial_trickle_timer_start(pae_supp_t *pae_supp) { - pae_supp->auth_trickle_params = initial_eapol_key_trickle_params; + /* Starts trickle for initial EAPOL-key. Default sequence has fixed delay of 2 minutes, + * one re-transmit interval, last re-transmit interval transmit time and a wait time + * for the authenticator to answer the last re-transmit. + * + * Interval I [6,12] minutes. Sequence: + * + * fixed 2 minutes delay + I + last I transmit time t + wait for answer [2,4] minutes + * + * There are two retries. Minimum time that sequence takes before authentication failure + * is 16 minutes and maximum is 30 minutes. + * + * + * Extremely slow network + * + * Starts trickle for initial EAPOL-key, Interval I [10,60] minutes. Sequence: + * I + last I transmit time t + wait for answer [2,4] minutes + * There are two retries. Minimum time that sequence takes before authentication failure + * is 22 minutes and maximum is 124 minutes. + */ + pae_supp->auth_trickle_params = pae_supp->sec_prot_cfg->initial_key_trickle_params; + pae_supp->initial_key_retry_timer = pae_supp->sec_prot_cfg->initial_key_retry_delay; - // Very fast, medium and slow network - if (timing_value < 25) { - /* Starts trickle for initial EAPOL-key. Sequence has fixed delay of 2 minutes, - * one re-transmit interval, last re-transmit interval transmit time and a wait time - * for the authenticator to answer the last re-transmit. - * - * Interval I [6,12] minutes. Sequence: - * - * fixed 2 minutes delay + I + last I transmit time t + wait for answer [2,4] minutes - * - * There are two retries. Minimum time that sequence takes before authentication failure - * is 16 minutes and maximum is 30 minutes. - */ - pae_supp->initial_key_retry_timer = DEFAULT_INITIAL_KEY_RETRY_TIMER; // 2 minutes - } else { - /* Extremely slow network - * - * Starts trickle for initial EAPOL-key, Interval I [10,60] minutes. Sequence: - * I + last I transmit time t + wait for answer [2,4] minutes - * There are two retries. Minimum time that sequence takes before authentication failure - * is 22 minutes and maximum is 124 minutes. - */ - pae_supp->auth_trickle_params.Imin = VERY_SLOW_NW_TRICKLE_IMIN_SECS; - pae_supp->auth_trickle_params.Imax = VERY_SLOW_NW_TRICKLE_IMAX_SECS; - pae_supp->initial_key_retry_timer = NONE_INITIAL_KEY_RETRY_TIMER; // 0 seconds - } trickle_start(&pae_supp->auth_trickle_timer, &pae_supp->auth_trickle_params); tr_info("Initial EAPOL-Key trickle I: [%i,%i] %i, t: %i", pae_supp->auth_trickle_params.Imin, pae_supp->auth_trickle_params.Imax, pae_supp->auth_trickle_timer.I, pae_supp->auth_trickle_timer.t); pae_supp->auth_trickle_running = true; - pae_supp->initial_key_retry_cnt = INITIAL_KEY_RETRY_COUNT; + pae_supp->initial_key_retry_cnt = pae_supp->sec_prot_cfg->initial_key_retry_cnt; } static void ws_pae_supp_initial_last_interval_trickle_timer_start(pae_supp_t *pae_supp) { // Starts trickle last to wait response after last retry before failing authentication - pae_supp->auth_trickle_params = initial_eapol_key_trickle_params; pae_supp->auth_trickle_params.Imin = LAST_INTERVAL_TRICKLE_IMIN_SECS; pae_supp->auth_trickle_params.Imax = LAST_INTERVAL_TRICKLE_IMAX_SECS; + pae_supp->auth_trickle_params.k = 0; pae_supp->auth_trickle_params.TimerExpirations = 1; // Set I to [iMin,iMax] (4 to 4 minutes) -> t is [I/2 - I] (2 minutes to 4 minutes) trickle_start(&pae_supp->auth_trickle_timer, &pae_supp->auth_trickle_params); @@ -1213,7 +1138,7 @@ static kmp_api_t *ws_pae_supp_kmp_incoming_ind(kmp_service_t *service, kmp_type_ static kmp_api_t *ws_pae_supp_kmp_create_and_start(kmp_service_t *service, kmp_type_e type, pae_supp_t *pae_supp) { // Create new instance - kmp_api_t *kmp = kmp_api_create(service, type, pae_supp->sec_prot_cfg); + kmp_api_t *kmp = kmp_api_create(service, type, pae_supp->sec_prot_cfg, pae_supp->sec_timer_cfg); if (!kmp) { return NULL; } @@ -1308,7 +1233,12 @@ static void ws_pae_supp_kmp_api_finished_indication(kmp_api_t *kmp, kmp_result_e that bootstrap can decide if EAPOL target should be changed */ else if (type > IEEE_802_1X_INITIAL_KEY && result == KMP_RESULT_ERR_TX_NO_ACK) { tr_info("Initial EAPOL-Key TX failure, target: %s", trace_array(kmp_address_eui_64_get(&pae_supp->entry.addr), 8)); - ws_pae_supp_authenticate_response(pae_supp, AUTH_RESULT_ERR_TX_NO_ACK); + /* Fails authentication only if other authentication protocols are not yet + started by authenticator */ + if (ws_pae_lib_kmp_list_count(&pae_supp->entry.kmp_list) <= 1) { + // Continues with trickle but selects different parent + pae_supp->tx_failure_on_initial_key = true; + } } } diff --git a/source/6LoWPAN/ws/ws_pae_supp.h b/source/6LoWPAN/ws/ws_pae_supp.h index 3bfbc095c5..7bd2017061 100644 --- a/source/6LoWPAN/ws/ws_pae_supp.h +++ b/source/6LoWPAN/ws/ws_pae_supp.h @@ -40,12 +40,13 @@ * \param cert_chain certificate chain * \param sec_timer_cfg timer configuration * \param sec_prot_cfg protocol configuration + * \param sec_keys_nw_info security keys network information * * \return < 0 failure * \return >= 0 success * */ -int8_t ws_pae_supp_init(protocol_interface_info_entry_t *interface_ptr, const sec_prot_certs_t *certs, sec_timer_cfg_t *sec_timer_cfg, sec_prot_cfg_t *sec_prot_cfg); +int8_t ws_pae_supp_init(protocol_interface_info_entry_t *interface_ptr, const sec_prot_certs_t *certs, sec_timer_cfg_t *sec_timer_cfg, sec_prot_cfg_t *sec_prot_cfg, sec_prot_keys_nw_info_t *sec_keys_nw_info); /** * ws_pae_supp_delete deletes PAE supplicant @@ -80,26 +81,14 @@ void ws_pae_supp_slow_timer(uint16_t seconds); * \param interface_ptr interface * \param dest_pan_id EAPOL target PAN ID * \param dest_eui_64 EAPOL target + * \param dest_network_name EAPOL target network name * * \return < 0 failure * \return 0 authentication done, continue * \return > 0 authentication started * */ -int8_t ws_pae_supp_authenticate(protocol_interface_info_entry_t *interface_ptr, uint16_t dest_pan_id, uint8_t *dest_eui_64); - -/** - * ws_pae_supp_nw_info_set set network information - * - * \param interface_ptr interface - * \param pan_id PAD ID - * \param network_name network name - * - * \return < 0 failure - * \return >= 0 success - * - */ -int8_t ws_pae_supp_nw_info_set(protocol_interface_info_entry_t *interface_ptr, uint16_t pan_id, char *network_name); +int8_t ws_pae_supp_authenticate(protocol_interface_info_entry_t *interface_ptr, uint16_t dest_pan_id, uint8_t *dest_eui_64, char *dest_network_name); /** * ws_pae_supp_border_router_addr_write write border router address @@ -129,12 +118,13 @@ int8_t ws_pae_supp_border_router_addr_read(protocol_interface_info_entry_t *inte * ws_pae_supp_nw_key_valid network key is valid i.e. used successfully on bootstrap * * \param interface_ptr interface + * \param br_iid border router IID for which the keys are valid * * \return < 0 failure * \return >= 0 success * */ -int8_t ws_pae_supp_nw_key_valid(protocol_interface_info_entry_t *interface_ptr); +int8_t ws_pae_supp_nw_key_valid(protocol_interface_info_entry_t *interface_ptr, uint8_t *br_iid); /** * ws_pae_supp_gtk_hash_update GTK hash has been updated (on PAN configuration) @@ -202,6 +192,17 @@ typedef void ws_pae_supp_nw_key_index_set(protocol_interface_info_entry_t *inter */ typedef void ws_pae_supp_auth_completed(protocol_interface_info_entry_t *interface_ptr, auth_result_e result, uint8_t *target_eui_64); +/** + * ws_pae_supp_auth_next_target get next target to attempt authentication + * + * \param interface_ptr interface + * \param previous_eui_64 EUI-64 of previous target + * + * \return EUI-64 of the next target or previous target if new one not available + * + */ +typedef const uint8_t *ws_pae_supp_auth_next_target(protocol_interface_info_entry_t *interface_ptr, const uint8_t *previous_eui_64, uint16_t *pan_id); + /** * ws_pae_supp_nw_key_insert network key insert callback * @@ -224,6 +225,14 @@ typedef int8_t ws_pae_supp_nw_key_insert(protocol_interface_info_entry_t *interf */ typedef uint8_t *ws_pae_supp_gtk_hash_ptr_get(protocol_interface_info_entry_t *interface_ptr); +/** + * ws_pae_supp_nw_info_updated security keys network information updated + * + * \param interface_ptr interface + * + */ +typedef void ws_pae_supp_nw_info_updated(protocol_interface_info_entry_t *interface_ptr); + /** * ws_pae_supp_cb_register register PEA supplicant callbacks * @@ -231,9 +240,10 @@ typedef uint8_t *ws_pae_supp_gtk_hash_ptr_get(protocol_interface_info_entry_t *i * \param completed authentication completed callback * \param nw_key_insert network key index callback * \param nw_key_index_set network send key index callback + * \param nw_info_updated security keys network information updated callback * */ -void ws_pae_supp_cb_register(protocol_interface_info_entry_t *interface_ptr, ws_pae_supp_auth_completed *completed, ws_pae_supp_nw_key_insert *nw_key_insert, ws_pae_supp_nw_key_index_set *nw_key_index_set, ws_pae_supp_gtk_hash_ptr_get *gtk_hash_ptr_get); +void ws_pae_supp_cb_register(protocol_interface_info_entry_t *interface_ptr, ws_pae_supp_auth_completed *completed, ws_pae_supp_auth_next_target *auth_next_target, ws_pae_supp_nw_key_insert *nw_key_insert, ws_pae_supp_nw_key_index_set *nw_key_index_set, ws_pae_supp_gtk_hash_ptr_get *gtk_hash_ptr_get, ws_pae_supp_nw_info_updated *nw_info_updated); #else @@ -241,7 +251,6 @@ void ws_pae_supp_cb_register(protocol_interface_info_entry_t *interface_ptr, ws_ #define ws_pae_supp_delete NULL #define ws_pae_supp_timing_adjust(timing) 1 #define ws_pae_supp_cb_register(interface_ptr, completed, nw_key_insert, nw_key_index_set) -#define ws_pae_supp_nw_info_set(interface_ptr, pan_id, network_name) -1 #define ws_pae_supp_nw_key_valid(interface_ptr) -1 #define ws_pae_supp_fast_timer NULL #define ws_pae_supp_slow_timer NULL diff --git a/source/6LoWPAN/ws/ws_pae_time.c b/source/6LoWPAN/ws/ws_pae_time.c new file mode 100644 index 0000000000..ad60f3d0e2 --- /dev/null +++ b/source/6LoWPAN/ws/ws_pae_time.c @@ -0,0 +1,190 @@ +/* + * Copyright (c) 2020, Arm Limited and affiliates. + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "nsconfig.h" +#include +#include "ns_types.h" +#include "ns_list.h" +#include "ns_trace.h" +#include "ns_time_api.h" +#include "6LoWPAN/ws/ws_config.h" +#include "6LoWPAN/ws/ws_pae_time.h" +#include "Security/protocols/sec_prot_certs.h" +#include "Security/protocols/sec_prot_keys.h" + +#ifdef HAVE_WS + +#define TRACE_GROUP "wst" + +// Wednesday, January 1, 2020 0:00:00 GMT +#define CURRENT_TIME_INIT_VALUE 1577836800 + +// Increment two hours in addition to maximum storing interval +#define CURRENT_TIME_INCREMENT_VALUE (2 * 3600) + +static uint64_t current_time = CURRENT_TIME_INIT_VALUE; +static ns_time_api_system_time_callback *system_time_callback = NULL; + +uint16_t ws_pae_time_to_short_convert(uint32_t time) +{ + uint16_t short_time; + time_format_t format; + + if (time < STIME_TIME_MAX) { + short_time = time; + format = TIME_FORMAT_SECONDS; + } else if (time < (STIME_TIME_MAX * 60)) { + short_time = time / 60; + format = TIME_FORMAT_MINUTES; + } else if (time < (STIME_TIME_MAX * 3600)) { + short_time = time / 3600; + format = TIME_FORMAT_HOURS; + } else { + short_time = time / 86400; + format = TIME_FORMAT_DAYS; + } + + short_time |= ((uint16_t) format) << STIME_TIME_BITS; + + return short_time; +} + +uint32_t ws_pae_time_from_short_convert(uint16_t short_time) +{ + uint32_t time; + + time_format_t format = short_time >> STIME_TIME_BITS; + + short_time &= STIME_TIME_MASK; + + if (format == TIME_FORMAT_SECONDS) { + time = short_time; + } else if (format == TIME_FORMAT_MINUTES) { + time = short_time * 60; + } else if (format == TIME_FORMAT_HOURS) { + time = short_time * 3600; + } else { + time = short_time * 86400; + } + + return time; +} + +bool ws_pae_time_from_short_time_compare(uint16_t short_time1, uint16_t short_time2) +{ + uint32_t time1 = ws_pae_time_from_short_convert(short_time1); + uint32_t time2 = ws_pae_time_from_short_convert(short_time2); + + // Calculate difference + uint32_t difference; + if (time1 > time2) { + difference = time1 - time2; + } else { + difference = time2 - time1; + } + + // Allow variable difference to be regarded as same based on format + if (STIME_FORMAT_GET(short_time1) == TIME_FORMAT_DAYS || STIME_FORMAT_GET(short_time2) == TIME_FORMAT_DAYS) { + if (difference > 2 * 24 * 3600) { // Two days + return false; + } + } else if (STIME_FORMAT_GET(short_time1) == TIME_FORMAT_HOURS || STIME_FORMAT_GET(short_time2) == TIME_FORMAT_HOURS) { + if (difference > 2 * 3600) { // Two hours + return false; + } + } else if (STIME_FORMAT_GET(short_time1) == TIME_FORMAT_MINUTES || STIME_FORMAT_GET(short_time2) == TIME_FORMAT_MINUTES) { + if (difference > 5 * 60) { // 5 minutes + return false; + } + } else { + if (difference > 10) { // 10 seconds + return false; + } + } + + return true; +} + +int8_t ws_pae_time_diff_calc(uint64_t curr_time, uint64_t comp_time, uint32_t *time_diff, bool future) +{ + int32_t difference; + *time_diff = 0; + // Comparison time is in future + if (curr_time < comp_time) { + if (!future) { + // Do not allow times in future + return -1; + } + difference = comp_time - curr_time; + } else { + // Comparison time is in past + if (future) { + // Do not allow times in past + return -1; + } + difference = curr_time - comp_time; + } + + // If difference is more two years time is invalid + if (difference > SEC_MAXIMUM_LIFETIME) { + return -1; + } + + *time_diff = difference; + + return 0; +} + +uint64_t ws_pae_current_time_get(void) +{ + if (system_time_callback) { + return system_time_callback(); + } + + return current_time; +} + +void ws_pae_current_time_update(uint16_t seconds) +{ + current_time += seconds; +} + +int8_t ws_pae_current_time_set(uint64_t time) +{ + current_time = time; + + if (system_time_callback) { + uint64_t system_time = system_time_callback(); + // System time has gone backwards + if (system_time < current_time || system_time > current_time + SYSTEM_TIME_MAXIMUM_DIFF) { + tr_error("FATAL: system time less than reference time or more than 12 months in future: %"PRIi64" reference time: %"PRIi64, system_time, current_time); + return -1; + } + } else { + current_time += FRAME_COUNTER_STORE_FORCE_INTERVAL + CURRENT_TIME_INCREMENT_VALUE; + } + + return 0; +} + +void ns_time_api_system_time_callback_set(ns_time_api_system_time_callback callback) +{ + system_time_callback = callback; +} + +#endif /* HAVE_WS */ + diff --git a/source/6LoWPAN/ws/ws_pae_time.h b/source/6LoWPAN/ws/ws_pae_time.h new file mode 100644 index 0000000000..12655e2c2a --- /dev/null +++ b/source/6LoWPAN/ws/ws_pae_time.h @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2020, Arm Limited and affiliates. + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef WS_PAE_TIME_H_ +#define WS_PAE_TIME_H_ + +/* + * Port access entity time functions. + * + */ + +typedef enum { + TIME_FORMAT_SECONDS = 0, + TIME_FORMAT_MINUTES, + TIME_FORMAT_HOURS, + TIME_FORMAT_DAYS, +} time_format_t; + +#define STIME_TIME_BITS 14 +#define STIME_TIME_MAX 0x3FFF +#define STIME_TIME_MASK STIME_TIME_MAX + +#define STIME_FORMAT_GET(stime) (stime >> STIME_TIME_BITS) +#define STIME_TIME_GET(stime) (stime & STIME_TIME_MASK) + +// Maximum difference in stored and indicated system time +#define SYSTEM_TIME_MAXIMUM_DIFF (60 * 60 * 24 * 30 * 12) + +/** + * ws_pae_time_to_short_convert convert time to short format + * + * \param time time in seconds to convert + * + * \return < 0 failure + * \return >= 0 success + * + */ +uint16_t ws_pae_time_to_short_convert(uint32_t time); + +/** + * ws_pae_time_from_short_convert convert short time to time format + * + * \param short_time short_time to convert + * + * \return time in seconds + * + */ +uint32_t ws_pae_time_from_short_convert(uint16_t short_time); + +/** + * ws_pae_time_from_short_time_compare compare two times in short format + * + * \param short_time1 time 1 to compare + * \param short_time1 time 2 to compare + * + * \return true times are equal + * \return false times are not equal + * + */ +bool ws_pae_time_from_short_time_compare(uint16_t short_time1, uint16_t short_time2); + +/** + * ws_pae_time_diff_calc calculates difference between two times + * + * \param curr_time current time + * \param comp_time time which is compared + * \param time_diff returns time difference + * \param future compared time should in future + * + * \return < 0 failure + * \return >= 0 success + * + */ +int8_t ws_pae_time_diff_calc(uint64_t curr_time, uint64_t comp_time, uint32_t *time_diff, bool future); + +/** + * ws_pae_current_time_get gets current time + * + * \return current time in seconds after 1970 + * + */ +uint64_t ws_pae_current_time_get(void); + +/** + * ws_pae_current_time_get updates current time + * + * \param seconds seconds to be added to current time + * + */ +void ws_pae_current_time_update(uint16_t seconds); + +/** + * ws_pae_current_time_set sets current time + * + * \param time new time + * + * \return < 0 failure + * \return >= 0 success + */ +int8_t ws_pae_current_time_set(uint64_t time); + +#endif /* WS_PAE_KEY_STORAGE_H_ */ diff --git a/source/6LoWPAN/ws/ws_pae_timers.c b/source/6LoWPAN/ws/ws_pae_timers.c index fd3f02e621..a07d0e6deb 100644 --- a/source/6LoWPAN/ws/ws_pae_timers.c +++ b/source/6LoWPAN/ws/ws_pae_timers.c @@ -26,6 +26,7 @@ #include "NWK_INTERFACE/Include/protocol.h" #include "6LoWPAN/ws/ws_config.h" #include "6LoWPAN/ws/ws_cfg_settings.h" +#include "Security/protocols/sec_prot_cfg.h" #include "6LoWPAN/ws/ws_pae_timers.h" #ifdef HAVE_WS diff --git a/source/6LoWPAN/ws/ws_pae_timers.h b/source/6LoWPAN/ws/ws_pae_timers.h index ec792996a0..7b8f58052d 100644 --- a/source/6LoWPAN/ws/ws_pae_timers.h +++ b/source/6LoWPAN/ws/ws_pae_timers.h @@ -18,18 +18,6 @@ #ifndef WS_PAE_TIMERS_H_ #define WS_PAE_TIMERS_H_ -typedef struct sec_timer_cfg_s { - uint32_t gtk_expire_offset; /* GTK lifetime; GTK_EXPIRE_OFFSET (seconds) */ - uint32_t pmk_lifetime; /* PMK lifetime (seconds) */ - uint32_t ptk_lifetime; /* PTK lifetime (seconds) */ - uint16_t gtk_new_act_time; /* GTK_NEW_ACTIVATION_TIME (1/X of expire offset) */ - uint16_t revocat_lifetime_reduct; /* REVOCATION_LIFETIME_REDUCTION (reduction of lifetime) */ - uint16_t gtk_request_imin; /* GTK_REQUEST_IMIN (seconds) */ - uint16_t gtk_request_imax; /* GTK_REQUEST_IMAX (seconds) */ - uint16_t gtk_max_mismatch; /* GTK_MAX_MISMATCH (seconds) */ - uint8_t gtk_new_install_req; /* GTK_NEW_INSTALL_REQUIRED (percent of GTK lifetime) */ -} sec_timer_cfg_t; - /** * ws_pae_timers_settings_init initializes timer settings structure * diff --git a/source/6LoWPAN/ws/ws_test_api.c b/source/6LoWPAN/ws/ws_test_api.c index f7ea71de08..16f9c5926a 100644 --- a/source/6LoWPAN/ws/ws_test_api.c +++ b/source/6LoWPAN/ws/ws_test_api.c @@ -23,7 +23,9 @@ #include #include "fhss_config.h" #include "ws_management_api.h" +#include "mac_api.h" #include "NWK_INTERFACE/Include/protocol.h" +#include "6LoWPAN/MAC/mac_helper.h" #include "6LoWPAN/ws/ws_config.h" #include "6LoWPAN/ws/ws_common.h" #include "6LoWPAN/ws/ws_bbr_api_internal.h" diff --git a/source/Common_Protocols/icmpv6.c b/source/Common_Protocols/icmpv6.c index b94b55d52a..c6d3efd81c 100644 --- a/source/Common_Protocols/icmpv6.c +++ b/source/Common_Protocols/icmpv6.c @@ -1714,7 +1714,11 @@ buffer_t *icmpv6_build_na(protocol_interface_info_entry_t *cur, bool solicited, buf->info = (buffer_info_t)(B_DIR_DOWN | B_FROM_ICMP | B_TO_ICMP); buf->interface = cur; - tr_info("Build NA"); + if (aro) { + tr_info("Build NA ARO"); + } else { + tr_info("Build NA"); + } return (buf); } diff --git a/source/Core/include/ns_monitor.h b/source/Core/include/ns_monitor.h index 6ed6d3a9e4..2d98feb2de 100644 --- a/source/Core/include/ns_monitor.h +++ b/source/Core/include/ns_monitor.h @@ -35,5 +35,10 @@ void ns_monitor_timer(uint16_t seconds); int ns_monitor_heap_gc_threshold_set(uint8_t percentage_high, uint8_t percentage_critical); +int ns_monitor_packet_ingress_rate_limit_by_memory(uint8_t free_heap_percentage); + +bool ns_monitor_packet_allocation_allowed(void); + + #endif // _NS_MONITOR_H diff --git a/source/Core/ns_monitor.c b/source/Core/ns_monitor.c index 54d6ecacea..17a46eb623 100644 --- a/source/Core/ns_monitor.c +++ b/source/Core/ns_monitor.c @@ -62,6 +62,8 @@ typedef struct ns_monitor__s { static ns_monitor_t *ns_monitor_ptr = NULL; +static uint8_t ns_dyn_mem_rate_limiting_threshold_percentage = 0; // Percentage of free memory required to allow routing + typedef void (ns_maintenance_gc_cb)(bool full_gc); /* @@ -189,3 +191,31 @@ int ns_monitor_heap_gc_threshold_set(uint8_t percentage_high, uint8_t percentage return -1; } + +int ns_monitor_packet_ingress_rate_limit_by_memory(uint8_t free_heap_percentage) +{ + if (free_heap_percentage < 100) { + ns_dyn_mem_rate_limiting_threshold_percentage = free_heap_percentage; + return 0; + } + + return -1; +} + +bool ns_monitor_packet_allocation_allowed(void) +{ + // If there is no packets to forward this should not be blocked. + // There should be cleanup routine enabled that will remove unneeded memory to prevent locks + // this could trigger a function to clean packets from routing and allow newest packets + + const mem_stat_t *ns_dyn_mem_stat = ns_dyn_mem_get_mem_stat(); + + if (ns_dyn_mem_stat && ns_dyn_mem_rate_limiting_threshold_percentage) { + if (ns_dyn_mem_stat->heap_sector_allocated_bytes > ns_dyn_mem_stat->heap_sector_size / 100 * (100 - ns_dyn_mem_rate_limiting_threshold_percentage)) { + // Packet allocation not allowed as memory is running low. + return false; + } + } + return true; +} + diff --git a/source/MAC/IEEE802_15_4/mac_cca_threshold.c b/source/MAC/IEEE802_15_4/mac_cca_threshold.c new file mode 100644 index 0000000000..33b9b27410 --- /dev/null +++ b/source/MAC/IEEE802_15_4/mac_cca_threshold.c @@ -0,0 +1,142 @@ +/* + * Copyright (c) 2020, Arm Limited and affiliates. + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "string.h" +#include "nsconfig.h" +#include "ns_types.h" +#include "ns_trace.h" +#include "nsdynmemLIB.h" +#include "MAC/IEEE802_15_4/mac_defines.h" +#include "MAC/IEEE802_15_4/mac_cca_threshold.h" + +#define TRACE_GROUP "mcth" + +int8_t mac_cca_thr_init(protocol_interface_rf_mac_setup_s *rf_ptr, uint8_t number_of_channels, int8_t default_dbm, int8_t high_limit, int8_t low_limit) +{ + // No changes + if (rf_ptr->cca_threshold && + (number_of_channels == rf_ptr->cca_threshold->number_of_channels) && + (default_dbm == rf_ptr->cca_threshold->default_dbm) && + (high_limit == rf_ptr->cca_threshold->high_limit) && + (low_limit == rf_ptr->cca_threshold->low_limit)) { + return -1; + } + // Validate given dBm range. Default must be in between high and low limit. + if ((default_dbm > high_limit) || (default_dbm < low_limit)) { + return -1; + } + mac_cca_thr_deinit(rf_ptr); + rf_ptr->cca_threshold = ns_dyn_mem_alloc(sizeof(mac_cca_threshold_s)); + if (!rf_ptr->cca_threshold) { + return -1; + } + rf_ptr->cca_threshold->ch_thresholds = ns_dyn_mem_alloc(number_of_channels); + if (!rf_ptr->cca_threshold->ch_thresholds) { + ns_dyn_mem_free(rf_ptr->cca_threshold); + rf_ptr->cca_threshold = 0; + return -1; + } + memset(rf_ptr->cca_threshold->ch_thresholds, default_dbm, number_of_channels); + rf_ptr->cca_threshold->high_limit = high_limit; + rf_ptr->cca_threshold->low_limit = low_limit; + rf_ptr->cca_threshold->default_dbm = default_dbm; + rf_ptr->cca_threshold->number_of_channels = number_of_channels; + tr_info("Initialized CCA threshold: %u, %i, %i, %i", number_of_channels, default_dbm, high_limit, low_limit); + return 0; +} + +int8_t mac_cca_thr_deinit(protocol_interface_rf_mac_setup_s *rf_ptr) +{ + if (!rf_ptr->cca_threshold) { + return -1; + } + ns_dyn_mem_free(rf_ptr->cca_threshold->ch_thresholds); + ns_dyn_mem_free(rf_ptr->cca_threshold); + rf_ptr->cca_threshold = 0; + return 0; +} + +int8_t mac_cca_thr_get_dbm(protocol_interface_rf_mac_setup_s *rf_ptr, uint8_t channel) +{ + if (!rf_ptr->cca_threshold) { + return CCA_FAILED_DBM; + } + // If channel is unknown, use default threshold + if (channel > (rf_ptr->cca_threshold->number_of_channels - 1)) { + return rf_ptr->cca_threshold->default_dbm; + } + return rf_ptr->cca_threshold->ch_thresholds[channel]; +} + +static int8_t mac_cca_thr_set_dbm(protocol_interface_rf_mac_setup_s *rf_ptr, uint8_t channel, int8_t dbm) +{ + if (rf_ptr->cca_threshold->ch_thresholds[channel] != dbm) { + rf_ptr->cca_threshold->ch_thresholds[channel] = dbm; + return 0; + } + return -1; +} + +static int8_t mac_cca_thr_update_channel_threshold(protocol_interface_rf_mac_setup_s *rf_ptr, uint8_t channel, int8_t dbm) +{ + // Already on low limit + if (rf_ptr->cca_threshold->ch_thresholds[channel] == rf_ptr->cca_threshold->low_limit) { + return -1; + } + // Already using lower threshold + if (rf_ptr->cca_threshold->ch_thresholds[channel] <= (dbm - CCA_THRESHOLD_STEP)) { + return -1; + } + // Do not set below configured low limit + if ((dbm - CCA_THRESHOLD_STEP) < rf_ptr->cca_threshold->low_limit) { + return mac_cca_thr_set_dbm(rf_ptr, channel, rf_ptr->cca_threshold->low_limit); + } + return mac_cca_thr_set_dbm(rf_ptr, channel, dbm - CCA_THRESHOLD_STEP); +} + +static int8_t mac_cca_thr_channel_failed(protocol_interface_rf_mac_setup_s *rf_ptr, uint8_t channel) +{ + // Already on high limit + if (rf_ptr->cca_threshold->ch_thresholds[channel] == rf_ptr->cca_threshold->high_limit) { + return -1; + } + // Do not set above configured high limit + if ((rf_ptr->cca_threshold->ch_thresholds[channel] + CCA_THRESHOLD_STEP) > rf_ptr->cca_threshold->high_limit) { + return mac_cca_thr_set_dbm(rf_ptr, channel, rf_ptr->cca_threshold->high_limit); + } + return mac_cca_thr_set_dbm(rf_ptr, channel, rf_ptr->cca_threshold->ch_thresholds[channel] + CCA_THRESHOLD_STEP); +} + +int8_t mac_cca_threshold_update(protocol_interface_rf_mac_setup_s *rf_ptr, uint8_t channel, int8_t dbm) +{ + if (!rf_ptr->cca_threshold) { + return -1; + } + if (channel > (rf_ptr->cca_threshold->number_of_channels - 1)) { + return -1; + } + if (dbm == CCA_FAILED_DBM) { + if (mac_cca_thr_channel_failed(rf_ptr, channel)) { + return -1; + } + } else { + if (mac_cca_thr_update_channel_threshold(rf_ptr, channel, dbm)) { + return -1; + } + } + tr_debug("Channel %u CCA threshold to %i", channel, rf_ptr->cca_threshold->ch_thresholds[channel]); + return 0; +} diff --git a/source/MAC/IEEE802_15_4/mac_cca_threshold.h b/source/MAC/IEEE802_15_4/mac_cca_threshold.h new file mode 100644 index 0000000000..a2081ba588 --- /dev/null +++ b/source/MAC/IEEE802_15_4/mac_cca_threshold.h @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2020, Arm Limited and affiliates. + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef MAC_CCA_THRESHOLD_H_ +#define MAC_CCA_THRESHOLD_H_ + +#define CCA_THRESHOLD_STEP 1 +#define CCA_FAILED_DBM 0x7F + +typedef struct mac_cca_threshold { + int8_t *ch_thresholds; + int8_t high_limit; + int8_t low_limit; + int8_t default_dbm; + uint8_t number_of_channels; +} mac_cca_threshold_s; + +/** + * @brief Initialize automatic CCA threshold. + * @param rf_ptr Pointer to MAC instance. + * @param number_of_channels Number of MAC channels. + * @param default_dbm Default threshold. + * @param high_limit Highest allowed CCA threshold. + * @param low_limit Lowest allowed CCA threshold. + * @return 0 Success, negative Failed. + */ +int8_t mac_cca_thr_init(protocol_interface_rf_mac_setup_s *rf_ptr, uint8_t number_of_channels, int8_t default_dbm, int8_t high_limit, int8_t low_limit); + +/** + * @brief Deinitialize automatic CCA threshold. + * @param rf_ptr Pointer to MAC instance. + * @return 0 Success, negative Not found. + */ +int8_t mac_cca_thr_deinit(protocol_interface_rf_mac_setup_s *rf_ptr); + +/** + * @brief Read CCA threshold of specific channel. + * @param channel Channel. + * @return CCA threshold (dBm), CCA_FAILED_DBM Feature not enabled. + */ +int8_t mac_cca_thr_get_dbm(protocol_interface_rf_mac_setup_s *rf_ptr, uint8_t channel); + +/** + * @brief Update CCA threshold of specific channel. + * @param channel Channel. + * @param dbm CCA threshold (dBm). + * @return 0 Updated, negative Already using this value. + */ +int8_t mac_cca_threshold_update(protocol_interface_rf_mac_setup_s *rf_ptr, uint8_t channel, int8_t dbm); + +#endif /* MAC_CCA_THRESHOLD_H_ */ diff --git a/source/MAC/IEEE802_15_4/mac_data_buffer.h b/source/MAC/IEEE802_15_4/mac_data_buffer.h index a7de899bbb..4888cc816d 100644 --- a/source/MAC/IEEE802_15_4/mac_data_buffer.h +++ b/source/MAC/IEEE802_15_4/mac_data_buffer.h @@ -91,11 +91,13 @@ typedef struct mac_pre_build_frame { uint8_t csma_periods_left; uint8_t fhss_retry_count; uint8_t fhss_cca_retry_count; + uint16_t initial_tx_channel; uint32_t tx_time; bool upper_layer_request: 1; bool mac_allocated_payload_ptr: 1; bool asynch_request: 1; bool message_builded: 1; + bool DSN_allocated: 1; unsigned security_mic_len: 5; //Max possible lengths 0, 4, 8, 16 bytes unsigned priority: 2; struct mac_pre_build_frame *next; //Pointer for queue purpose diff --git a/source/MAC/IEEE802_15_4/mac_defines.h b/source/MAC/IEEE802_15_4/mac_defines.h index 28c2e62cfe..ff67616990 100644 --- a/source/MAC/IEEE802_15_4/mac_defines.h +++ b/source/MAC/IEEE802_15_4/mac_defines.h @@ -276,6 +276,7 @@ typedef struct protocol_interface_rf_mac_setup { struct arm_device_driver_list *tun_extension_rf_driver; /* End of API Control */ struct mlme_scan_conf_s *mac_mlme_scan_resp; + struct mac_cca_threshold *cca_threshold; //beacon_join_priority_tx_cb *beacon_join_priority_tx_cb_ptr; struct mac_statistics_s *mac_statistics; /* FHSS API*/ diff --git a/source/MAC/IEEE802_15_4/mac_mcps_sap.c b/source/MAC/IEEE802_15_4/mac_mcps_sap.c index d7c9aa9ef8..ee16dc8670 100644 --- a/source/MAC/IEEE802_15_4/mac_mcps_sap.c +++ b/source/MAC/IEEE802_15_4/mac_mcps_sap.c @@ -34,6 +34,7 @@ #include "fhss_api.h" #include "platform/arm_hal_interrupt.h" #include "common_functions.h" +#include "Core/include/ns_monitor.h" #include "MAC/IEEE802_15_4/sw_mac_internal.h" #include "MAC/IEEE802_15_4/mac_defines.h" @@ -45,6 +46,7 @@ #include "MAC/IEEE802_15_4/mac_mcps_sap.h" #include "MAC/IEEE802_15_4/mac_header_helper_functions.h" #include "MAC/IEEE802_15_4/mac_indirect_data.h" +#include "MAC/IEEE802_15_4/mac_cca_threshold.h" #include "MAC/rf_driver_storage.h" #include "sw_mac.h" @@ -74,8 +76,6 @@ static void mac_pd_data_confirm_failure_handle(protocol_interface_rf_mac_setup_s static int8_t mac_tasklet_event_handler = -1; -static ns_mem_heap_size_t ns_dyn_mem_rate_limiting_threshold = 0xFFFFFFFF; - /** * Get PHY time stamp. * @@ -1196,6 +1196,9 @@ static void mac_mcps_sap_data_tasklet(arm_event_s *event) case MAC_MLME_SCAN_CONFIRM_HANDLER: mac_mlme_scan_confirmation_handle((protocol_interface_rf_mac_setup_s *) event->data_ptr); break; + case MAC_CCA_THR_UPDATE: + mac_cca_threshold_update((protocol_interface_rf_mac_setup_s *) event->data_ptr, event->event_data >> 8, (int8_t) event->event_data); + break; case MAC_SAP_TRIG_TX: mac_clear_active_event((protocol_interface_rf_mac_setup_s *) event->data_ptr, MAC_SAP_TRIG_TX); mac_mcps_trig_buffer_from_queue((protocol_interface_rf_mac_setup_s *) event->data_ptr); @@ -1221,7 +1224,9 @@ mac_pre_build_frame_t *mcps_sap_prebuild_frame_buffer_get(uint16_t payload_size) return NULL; } memset(buffer, 0, sizeof(mac_pre_build_frame_t)); + buffer->initial_tx_channel = 0xffff; buffer->aux_header.frameCounter = 0xffffffff; + buffer->DSN_allocated = false; if (payload_size) { //Mac interlnal payload allocate buffer->mac_payload = ns_dyn_mem_temporary_alloc(payload_size); @@ -1498,7 +1503,10 @@ static void mcps_generic_sequence_number_allocate(protocol_interface_rf_mac_setu switch (buffer->fcf_dsn.frametype) { case MAC_FRAME_CMD: case MAC_FRAME_DATA: - buffer->fcf_dsn.DSN = mac_mlme_set_new_sqn(rf_ptr); + if (!buffer->DSN_allocated) { + buffer->fcf_dsn.DSN = mac_mlme_set_new_sqn(rf_ptr); + buffer->DSN_allocated = true; + } break; case MAC_FRAME_BEACON: buffer->fcf_dsn.DSN = mac_mlme_set_new_beacon_sqn(rf_ptr); @@ -2126,8 +2134,8 @@ void mcps_sap_pre_parsed_frame_buffer_free(mac_pre_parsed_frame_t *buf) mac_pre_parsed_frame_t *mcps_sap_pre_parsed_frame_buffer_get(const uint8_t *data_ptr, uint16_t frame_length) { // check that system has enough space to handle the new packet - const mem_stat_t *ns_dyn_mem_stat = ns_dyn_mem_get_mem_stat(); - if (ns_dyn_mem_stat && ns_dyn_mem_stat->heap_sector_allocated_bytes > ns_dyn_mem_rate_limiting_threshold) { + if (!ns_monitor_packet_allocation_allowed()) { + // stack can not handle new packets for routing return NULL; } @@ -2251,6 +2259,25 @@ void mcps_sap_trig_tx(void *mac_ptr) } } +void mac_cca_threshold_event_send(protocol_interface_rf_mac_setup_s *rf_ptr, uint8_t channel, int16_t dbm) +{ + // Return if feature is not initialized + if (!rf_ptr->cca_threshold) { + return; + } + uint16_t data = channel << 8 | (uint8_t) dbm; + arm_event_s event = { + .receiver = mac_tasklet_event_handler, + .sender = 0, + .event_id = 0, + .event_data = data, + .data_ptr = rf_ptr, + .event_type = MAC_CCA_THR_UPDATE, + .priority = ARM_LIB_LOW_PRIORITY_EVENT, + }; + + eventOS_event_send(&event); +} void mac_generic_event_trig(uint8_t event_type, void *mac_ptr, bool low_latency) { @@ -2363,18 +2390,6 @@ uint8_t mcps_sap_purge_reg_handler(protocol_interface_rf_mac_setup_s *rf_mac_set return confirmation.status; } -int mcps_packet_ingress_rate_limit_by_memory(uint8_t free_heap_percentage) -{ - const mem_stat_t *ns_dyn_mem_stat = ns_dyn_mem_get_mem_stat(); - - if (ns_dyn_mem_stat && free_heap_percentage < 100) { - ns_dyn_mem_rate_limiting_threshold = ns_dyn_mem_stat->heap_sector_size / 100 * (100 - free_heap_percentage); - return 0; - } - - return -1; -} - void mcps_pending_packet_counter_update_check(protocol_interface_rf_mac_setup_s *rf_mac_setup, mac_pre_build_frame_t *buffer) { if (buffer->fcf_dsn.securityEnabled) { diff --git a/source/MAC/IEEE802_15_4/mac_mcps_sap.h b/source/MAC/IEEE802_15_4/mac_mcps_sap.h index de61fe8b91..1a84004141 100644 --- a/source/MAC/IEEE802_15_4/mac_mcps_sap.h +++ b/source/MAC/IEEE802_15_4/mac_mcps_sap.h @@ -56,6 +56,7 @@ typedef enum { #define MAC_MLME_SCAN_CONFIRM_HANDLER 6 #define MAC_SAP_TRIG_TX 7 #define MCPS_SAP_DATA_ACK_CNF_EVENT 8 +#define MAC_CCA_THR_UPDATE 9 // Default number of CSMA-CA periods #define MAC_DEFAULT_NUMBER_OF_CSMA_PERIODS 1 @@ -142,4 +143,6 @@ uint32_t mac_mcps_sap_get_phy_timestamp(struct protocol_interface_rf_mac_setup * void mcps_pending_packet_counter_update_check(struct protocol_interface_rf_mac_setup *rf_mac_setup, mac_pre_build_frame_t *buffer); +void mac_cca_threshold_event_send(struct protocol_interface_rf_mac_setup *rf_mac_setup, uint8_t channel, int16_t dbm); + #endif /* MAC_IEEE802_15_4_MAC_MCPS_SAP_H_ */ diff --git a/source/MAC/IEEE802_15_4/mac_mlme.c b/source/MAC/IEEE802_15_4/mac_mlme.c index 8ea8f3355c..901ef01071 100644 --- a/source/MAC/IEEE802_15_4/mac_mlme.c +++ b/source/MAC/IEEE802_15_4/mac_mlme.c @@ -48,6 +48,7 @@ #include "MAC/IEEE802_15_4/mac_timer.h" #include "MAC/IEEE802_15_4/mac_pd_sap.h" #include "MAC/IEEE802_15_4/mac_mcps_sap.h" +#include "MAC/IEEE802_15_4/mac_cca_threshold.h" #include "MAC/virtual_rf/virtual_rf_defines.h" #include "MAC/rf_driver_storage.h" @@ -668,14 +669,50 @@ static int8_t mac_mlme_set_ack_wait_duration(protocol_interface_rf_mac_setup_s * return 0; } +static void mac_mlme_trig_pending_ack(protocol_interface_rf_mac_setup_s *rf_mac_setup, mlme_device_descriptor_t *device_ptr) +{ + platform_enter_critical(); + if (rf_mac_setup->mac_ack_tx_active && !rf_mac_setup->ack_tx_possible && + device_ptr->PANId == rf_mac_setup->enhanced_ack_buffer.DstPANId) { + + //Compare address for pending neigbour add + if (rf_mac_setup->enhanced_ack_buffer.fcf_dsn.DstAddrMode == MAC_ADDR_MODE_16_BIT) { + uint16_t short_id = common_read_16_bit(rf_mac_setup->enhanced_ack_buffer.DstAddr); + if (short_id == device_ptr->ShortAddress) { + rf_mac_setup->ack_tx_possible = true; + } + } else if (rf_mac_setup->enhanced_ack_buffer.fcf_dsn.DstAddrMode == MAC_ADDR_MODE_64_BIT) { + if (memcmp(device_ptr->ExtAddress, rf_mac_setup->enhanced_ack_buffer.DstAddr, 8) == 0) { + rf_mac_setup->ack_tx_possible = true; + } + } + } + platform_exit_critical(); +} + static int8_t mac_mlme_device_description_set(protocol_interface_rf_mac_setup_s *rf_mac_setup, const mlme_set_t *set_req) { if (set_req->value_size != sizeof(mlme_device_descriptor_t)) { return -1; } + if (mac_sec_mib_device_description_set(set_req->attr_index, (mlme_device_descriptor_t *) set_req->value_pointer, rf_mac_setup) != 0) { + return -1; + } - return mac_sec_mib_device_description_set(set_req->attr_index, (mlme_device_descriptor_t *) set_req->value_pointer, rf_mac_setup); + mac_mlme_trig_pending_ack(rf_mac_setup, (mlme_device_descriptor_t *) set_req->value_pointer); + return 0; +} + +static int8_t mac_mlme_device_pending_ack_trig(protocol_interface_rf_mac_setup_s *rf_mac_setup, const mlme_set_t *set_req) +{ + + if (set_req->value_size != sizeof(mlme_device_descriptor_t)) { + return -1; + } + mac_mlme_trig_pending_ack(rf_mac_setup, (mlme_device_descriptor_t *) set_req->value_pointer); + + return 0; } static int8_t mac_mlme_key_description_set(protocol_interface_rf_mac_setup_s *rf_mac_setup, const mlme_set_t *set_req) @@ -754,6 +791,8 @@ int8_t mac_mlme_set_req(protocol_interface_rf_mac_setup_s *rf_mac_setup, const m return mac_mlme_set_ack_wait_duration(rf_mac_setup, set_req); case macDeviceTable: return mac_mlme_device_description_set(rf_mac_setup, set_req); + case macDevicePendingAckTrig: + return mac_mlme_device_pending_ack_trig(rf_mac_setup, set_req); case macKeyTable: return mac_mlme_key_description_set(rf_mac_setup, set_req); case macDefaultKeySource: @@ -768,6 +807,10 @@ int8_t mac_mlme_set_req(protocol_interface_rf_mac_setup_s *rf_mac_setup, const m memcpy(rf_mac_setup->coord_long_address, set_req->value_pointer, 8); } return 0; + case macCCAThresholdStart: + pu8 = (uint8_t *) set_req->value_pointer; + mac_cca_thr_init(rf_mac_setup, *pu8, *((int8_t *)pu8 + 1), *((int8_t *)pu8 + 2), *((int8_t *)pu8 + 3)); + return 0; case mac802_15_4Mode: pu8 = (uint8_t *) set_req->value_pointer; if (rf_mac_setup->current_mac_mode == *pu8) { @@ -1059,6 +1102,7 @@ void mac_mlme_data_base_deallocate(struct protocol_interface_rf_mac_setup *rf_ma ns_dyn_mem_free(rf_mac->mac_beacon_payload); mac_sec_mib_deinit(rf_mac); + mac_cca_thr_deinit(rf_mac); ns_dyn_mem_free(rf_mac); } } diff --git a/source/MAC/IEEE802_15_4/mac_pd_sap.c b/source/MAC/IEEE802_15_4/mac_pd_sap.c index 09952b9b10..ec34ef77ae 100644 --- a/source/MAC/IEEE802_15_4/mac_pd_sap.c +++ b/source/MAC/IEEE802_15_4/mac_pd_sap.c @@ -34,6 +34,7 @@ #include "MAC/IEEE802_15_4/mac_mlme.h" #include "MAC/IEEE802_15_4/mac_filter.h" #include "MAC/IEEE802_15_4/mac_mcps_sap.h" +#include "MAC/IEEE802_15_4/mac_cca_threshold.h" #include "MAC/rf_driver_storage.h" /* Define TX Timeot Period */ @@ -45,7 +46,7 @@ #define MIN_FHSS_CSMA_PERIOD_US 5000 static int8_t mac_data_interface_tx_done_cb(protocol_interface_rf_mac_setup_s *rf_ptr, phy_link_tx_status_e status, uint8_t cca_retry, uint8_t tx_retry); -static void mac_sap_cca_fail_cb(protocol_interface_rf_mac_setup_s *rf_ptr); +static void mac_sap_cca_fail_cb(protocol_interface_rf_mac_setup_s *rf_ptr, uint16_t failed_channel); void mac_csma_param_init(protocol_interface_rf_mac_setup_s *rf_mac_setup) { @@ -273,7 +274,7 @@ void mac_pd_sap_state_machine(protocol_interface_rf_mac_setup_s *rf_mac_setup) if (rf_mac_setup->mac_tx_result == MAC_TIMER_CCA) { if (rf_mac_setup->rf_csma_extension_supported) { - mac_sap_cca_fail_cb(rf_mac_setup); + mac_sap_cca_fail_cb(rf_mac_setup, 0xffff); return; } @@ -328,7 +329,7 @@ void mac_pd_sap_state_machine(protocol_interface_rf_mac_setup_s *rf_mac_setup) } } -static void mac_sap_cca_fail_cb(protocol_interface_rf_mac_setup_s *rf_ptr) +static void mac_sap_cca_fail_cb(protocol_interface_rf_mac_setup_s *rf_ptr, uint16_t failed_channel) { if (rf_ptr->mac_ack_tx_active) { if (rf_ptr->active_pd_data_request) { @@ -340,6 +341,11 @@ static void mac_sap_cca_fail_cb(protocol_interface_rf_mac_setup_s *rf_ptr) if (rf_ptr->mac_cca_retry > rf_ptr->macMaxCSMABackoffs || (rf_ptr->active_pd_data_request && rf_ptr->active_pd_data_request->asynch_request)) { //Send MAC_CCA_FAIL mac_tx_done_state_set(rf_ptr, MAC_CCA_FAIL); + if (failed_channel != 0xffff && rf_ptr->active_pd_data_request) { + if (failed_channel == rf_ptr->active_pd_data_request->initial_tx_channel) { + mac_cca_threshold_event_send(rf_ptr, failed_channel, CCA_FAILED_DBM); + } + } } else { timer_mac_stop(rf_ptr); mac_csma_BE_update(rf_ptr); @@ -414,7 +420,7 @@ static void mac_data_ack_tx_finish(protocol_interface_rf_mac_setup_s *rf_ptr) mcps_pending_packet_counter_update_check(rf_ptr, rf_ptr->active_pd_data_request); //GEN TX failure - mac_sap_cca_fail_cb(rf_ptr); + mac_sap_cca_fail_cb(rf_ptr, 0xffff); } } @@ -442,6 +448,11 @@ static int8_t mac_data_interface_tx_done_cb(protocol_interface_rf_mac_setup_s *r } if (mac_data_asynch_channel_switch(rf_ptr, rf_ptr->active_pd_data_request)) { + rf_ptr->active_pd_data_request->initial_tx_channel = rf_ptr->mac_channel; + int8_t channel_cca_threshold = mac_cca_thr_get_dbm(rf_ptr, rf_ptr->mac_channel); + if (CCA_FAILED_DBM != channel_cca_threshold) { + rf_ptr->dev_driver->phy_driver->extension(PHY_EXTENSION_SET_CHANNEL_CCA_THRESHOLD, (uint8_t *)&channel_cca_threshold); + } return PHY_TX_ALLOWED; } @@ -458,7 +469,7 @@ static int8_t mac_data_interface_tx_done_cb(protocol_interface_rf_mac_setup_s *r rf_ptr->dev_driver->phy_driver->phy_tail_length, active_buf->tx_time); // When FHSS TX handle returns -1, transmission of the packet is currently not allowed -> restart CCA timer if (tx_handle_retval == -1) { - mac_sap_cca_fail_cb(rf_ptr); + mac_sap_cca_fail_cb(rf_ptr, 0xffff); return PHY_TX_NOT_ALLOWED; } // When FHSS TX handle returns -3, we are trying to transmit broadcast packet on unicast channel -> push back @@ -470,6 +481,13 @@ static int8_t mac_data_interface_tx_done_cb(protocol_interface_rf_mac_setup_s *r mac_tx_done_state_set(rf_ptr, MAC_UNKNOWN_DESTINATION); return PHY_TX_NOT_ALLOWED; } + if (rf_ptr->mac_cca_retry == 0 && rf_ptr->active_pd_data_request) { + rf_ptr->active_pd_data_request->initial_tx_channel = rf_ptr->mac_channel; + } + int8_t channel_cca_threshold = mac_cca_thr_get_dbm(rf_ptr, rf_ptr->mac_channel); + if (CCA_FAILED_DBM != channel_cca_threshold) { + rf_ptr->dev_driver->phy_driver->extension(PHY_EXTENSION_SET_CHANNEL_CCA_THRESHOLD, (uint8_t *)&channel_cca_threshold); + } if (active_buf->csma_periods_left > 0) { active_buf->csma_periods_left--; active_buf->tx_time += rf_ptr->multi_cca_interval; @@ -501,7 +519,7 @@ static int8_t mac_data_interface_tx_done_cb(protocol_interface_rf_mac_setup_s *r rf_ptr->mac_tx_retry += tx_retry; timer_mac_stop(rf_ptr); } - + uint16_t failed_channel = rf_ptr->mac_channel; if (rf_ptr->fhss_api && rf_ptr->active_pd_data_request->asynch_request == false) { /* waiting_ack == false allows FHSS to change back to RX channel after transmission * tx_completed == true allows FHSS to delete stored failure handles @@ -543,7 +561,7 @@ static int8_t mac_data_interface_tx_done_cb(protocol_interface_rf_mac_setup_s *r break; case PHY_LINK_CCA_FAIL: - mac_sap_cca_fail_cb(rf_ptr); + mac_sap_cca_fail_cb(rf_ptr, failed_channel); break; case PHY_LINK_CCA_OK: @@ -788,10 +806,16 @@ static int8_t mac_pd_sap_generate_ack(protocol_interface_rf_mac_setup_s *rf_ptr, return -1; } - if (mac_sec_mib_device_description_get(rf_ptr, rf_ptr->enhanced_ack_buffer.DstAddr, rf_ptr->enhanced_ack_buffer.fcf_dsn.DstAddrMode, rf_ptr->enhanced_ack_buffer.DstPANId)) { + + if (rf_ptr->enhanced_ack_buffer.fcf_dsn.securityEnabled == 0 || rf_ptr->enhanced_ack_buffer.aux_header.securityLevel == 0) { + //Unsecured data will be acked immediately rf_ptr->ack_tx_possible = true; } else { - rf_ptr->ack_tx_possible = false; + if (mac_sec_mib_device_description_get(rf_ptr, rf_ptr->enhanced_ack_buffer.DstAddr, rf_ptr->enhanced_ack_buffer.fcf_dsn.DstAddrMode, rf_ptr->enhanced_ack_buffer.DstPANId)) { + rf_ptr->ack_tx_possible = true; + } else { + rf_ptr->ack_tx_possible = false; + } } return mcps_generic_ack_build(rf_ptr, true); @@ -898,7 +922,7 @@ int8_t mac_pd_sap_data_cb(void *identifier, arm_phy_sap_msg_t *message) if (pd_data_ind->data_len < 3) { return -1; } - + mac_cca_threshold_event_send(rf_ptr, rf_ptr->mac_channel, pd_data_ind->dbm); mac_fcf_sequence_t fcf_read; const uint8_t *ptr = mac_header_parse_fcf_dsn(&fcf_read, pd_data_ind->data_ptr); diff --git a/source/MAC/IEEE802_15_4/mac_security_mib.c b/source/MAC/IEEE802_15_4/mac_security_mib.c index abe65d668b..0897b78bb9 100644 --- a/source/MAC/IEEE802_15_4/mac_security_mib.c +++ b/source/MAC/IEEE802_15_4/mac_security_mib.c @@ -295,21 +295,6 @@ int8_t mac_sec_mib_device_description_set(uint8_t atribute_index, mlme_device_de *device_ptr = *device_descriptor; - if (rf_mac_setup->mac_ack_tx_active && !rf_mac_setup->ack_tx_possible && - device_ptr->PANId == rf_mac_setup->enhanced_ack_buffer.DstPANId) { - - //Compare address for pending neigbour add - if (rf_mac_setup->enhanced_ack_buffer.fcf_dsn.DstAddrMode == MAC_ADDR_MODE_16_BIT) { - uint16_t short_id = common_read_16_bit(rf_mac_setup->enhanced_ack_buffer.DstAddr); - if (short_id == device_ptr->ShortAddress) { - rf_mac_setup->ack_tx_possible = true; - } - } else if (rf_mac_setup->enhanced_ack_buffer.fcf_dsn.DstAddrMode == MAC_ADDR_MODE_64_BIT) { - if (memcmp(device_ptr->ExtAddress, rf_mac_setup->enhanced_ack_buffer.DstAddr, 8) == 0) { - rf_mac_setup->ack_tx_possible = true; - } - } - } platform_exit_critical(); return 0; diff --git a/source/MAC/ethernet/ethernet_mac_api.c b/source/MAC/ethernet/ethernet_mac_api.c index 228ad7b553..fb4d9d2176 100644 --- a/source/MAC/ethernet/ethernet_mac_api.c +++ b/source/MAC/ethernet/ethernet_mac_api.c @@ -22,6 +22,7 @@ #include "nsdynmemLIB.h" #include "common_functions.h" #include "MAC/rf_driver_storage.h" +#include "Core/include/ns_monitor.h" typedef struct eth_mac_internal_s { eth_mac_api_t *mac_api; @@ -269,6 +270,11 @@ static int8_t eth_mac_net_phy_rx(const uint8_t *data_ptr, uint16_t data_len, uin return -1; } + if (!ns_monitor_packet_allocation_allowed()) { + // stack can not handle new packets for routing + return -1; + } + eth_data_ind_t *data_ind = ns_dyn_mem_temporary_alloc(sizeof(eth_data_ind_t)); if (!data_ind) { return -1; diff --git a/source/MAC/serial/serial_mac_api.c b/source/MAC/serial/serial_mac_api.c index 469635208c..b3ffa24bea 100644 --- a/source/MAC/serial/serial_mac_api.c +++ b/source/MAC/serial/serial_mac_api.c @@ -23,6 +23,7 @@ #include "common_functions.h" #include "ns_trace.h" #include "MAC/rf_driver_storage.h" +#include "Core/include/ns_monitor.h" #define TRACE_GROUP "seMa" @@ -317,10 +318,16 @@ static int8_t serial_mac_net_phy_rx(const uint8_t *data_ptr, uint16_t data_len, (void)link_quality; (void) dbm; + if (!ns_monitor_packet_allocation_allowed()) { + // stack can not handle new packets for routing + return -1; + } + serial_data_ind_t *data_ind = ns_dyn_mem_temporary_alloc(sizeof(serial_data_ind_t)); if (!data_ind) { return -1; } + data_ind->msdu = ns_dyn_mem_temporary_alloc(data_len); if (!data_ind->msdu) { ns_dyn_mem_free(data_ind); diff --git a/source/RPL/rpl_control.c b/source/RPL/rpl_control.c index d555eb8124..37eacc4345 100644 --- a/source/RPL/rpl_control.c +++ b/source/RPL/rpl_control.c @@ -391,7 +391,7 @@ static void rpl_control_addr_notifier(struct protocol_interface_info_entry *inte } } -static void rpl_control_etx_change_callback(int8_t nwk_id, uint16_t previous_etx, uint16_t current_etx, uint8_t attribute_index) +static void rpl_control_etx_change_callback(int8_t nwk_id, uint16_t previous_etx, uint16_t current_etx, uint8_t attribute_index, const uint8_t *mac64) { protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(nwk_id); @@ -405,14 +405,29 @@ static void rpl_control_etx_change_callback(int8_t nwk_id, uint16_t previous_et uint16_t delay = rpl_policy_etx_change_parent_selection_delay(domain); tr_debug("Triggering parent selection due to ETX %s on neigh index %u, etx %u", better ? "better" : "worse", attribute_index, current_etx); rpl_dodag_t *dodag = NULL; + //Define Link Local Address + uint8_t ll_parent_address[16]; + memcpy(ll_parent_address, ADDR_LINK_LOCAL_PREFIX, 8); + memcpy(ll_parent_address + 8, mac64, 8); + ll_parent_address[8] ^= 2; ns_list_foreach(rpl_instance_t, instance, &domain->instances) { - if (better) { - dodag = rpl_instance_current_dodag(instance); - } - rpl_instance_trigger_parent_selection(instance, delay, dodag); + if (rpl_instance_am_root(instance)) { rpl_downward_paths_invalidate(instance); + } else { + if (better) { + //Only react here for candidate updates and when DODAG version is configured + if (rpl_instance_address_is_candidate(instance, ll_parent_address, 0)) { + dodag = rpl_instance_current_dodag(instance); + if (dodag) { + rpl_instance_trigger_parent_selection(instance, delay, dodag); + } + } + } else if (rpl_instance_address_is_parent(instance, ll_parent_address)) { + //Quick reaction for selected parent only + rpl_instance_trigger_parent_selection(instance, delay, NULL); + } } } } @@ -1886,6 +1901,11 @@ static void rpl_domain_print(const rpl_domain_t *domain, route_print_fn_t *print } } +uint16_t rpl_control_route_table_get(struct rpl_instance *instance, uint8_t *prefix, rpl_route_info_t *output_table, uint16_t output_table_len) +{ + return rpl_downward_route_table_get(instance, prefix, output_table, output_table_len); +} + void rpl_control_print(route_print_fn_t *print_fn) { unsigned t = protocol_core_monotonic_time % 10; diff --git a/source/RPL/rpl_control.h b/source/RPL/rpl_control.h index 613d47eb05..5b9f6c26cf 100644 --- a/source/RPL/rpl_control.h +++ b/source/RPL/rpl_control.h @@ -44,6 +44,10 @@ typedef void rpl_prefix_callback_t(struct prefix_entry_t *prefix, void *handle, typedef bool rpl_new_parent_callback_t(uint8_t *ll_parent_address, void *handle, struct rpl_instance *instance, uint16_t candidate_rank); +typedef struct rpl_route_info { + uint8_t node[8]; /* IID of parent in parent child relation table */ + uint8_t parent[8]; /* IID of child in parent child relation table */ +} rpl_route_info_t; typedef struct rpl_domain { NS_LIST_HEAD_INCOMPLETE(struct rpl_instance) instances; @@ -186,6 +190,7 @@ ipv6_route_predicate_fn_t *rpl_control_get_route_predicate(rpl_domain_t *domain, /* Diagnostic APIs */ void rpl_control_print(route_print_fn_t *print_fn); +uint16_t rpl_control_route_table_get(struct rpl_instance *instance, uint8_t *prefix, rpl_route_info_t *output_table, uint16_t output_table_len); struct rpl_instance *rpl_control_enumerate_instances(rpl_domain_t *domain, struct rpl_instance *instance); struct rpl_instance *rpl_control_lookup_instance(rpl_domain_t *domain, uint8_t instance_id, const uint8_t *dodagid); diff --git a/source/RPL/rpl_downward.c b/source/RPL/rpl_downward.c index 34ca3cf6b7..e97416c752 100644 --- a/source/RPL/rpl_downward.c +++ b/source/RPL/rpl_downward.c @@ -1754,6 +1754,52 @@ void rpl_downward_print_instance(rpl_instance_t *instance, route_print_fn_t *pri } } +uint16_t rpl_downward_route_table_get(rpl_instance_t *instance, uint8_t *prefix, rpl_route_info_t *output_table, uint16_t output_table_len) +{ + uint16_t index = 0; + + if (!prefix || !output_table || !output_table_len) { + return 0; + } + if (ns_list_is_empty(&instance->dao_targets)) { + return 0; + } + if (!rpl_instance_am_root(instance)) { + // Question should this be available also for non roots in storing mode + return 0; + } + +#ifdef HAVE_RPL_ROOT + rpl_downward_compute_paths(instance); + + ns_list_foreach(rpl_dao_target_t, target, &instance->dao_targets) { + if (memcmp(target->prefix, prefix, 8) != 0) { + continue; + } + + if (target->root) { + /* Target has root structure + * We take the first transit only from table as simple topology is needed + */ + rpl_dao_root_transit_t *transit = ns_list_get_first(&target->info.root.transits); + if (transit) { + memcpy(output_table->node, &target->prefix[8], 8); + memcpy(output_table->parent, &transit->transit[8], 8); + + index++; + if (index == output_table_len) { + //table is full + return index; + } + output_table++; + } + } + /* We dont put non roots to list so border router is not visible as a node in list*/ + } +#endif + return index; +} + rpl_dao_target_t *rpl_instance_get_active_target_confirmation(rpl_instance_t *instance) { ns_list_foreach_safe(rpl_dao_target_t, n, &instance->dao_targets) { diff --git a/source/RPL/rpl_downward.h b/source/RPL/rpl_downward.h index b2b8faa5c8..c7cd66f27f 100644 --- a/source/RPL/rpl_downward.h +++ b/source/RPL/rpl_downward.h @@ -27,6 +27,7 @@ struct rpl_dao_root_transit; void rpl_downward_dao_slow_timer(struct rpl_instance *instance, uint16_t seconds); void rpl_downward_dao_timer(struct rpl_instance *instance, uint16_t ticks); void rpl_downward_print_instance(struct rpl_instance *instance, route_print_fn_t *print_fn); +uint16_t rpl_downward_route_table_get(rpl_instance_t *instance, uint8_t *prefix, rpl_route_info_t *output_table, uint16_t output_table_len); void rpl_downward_convert_dodag_preferences_to_dao_path_control(struct rpl_dodag *dodag); void rpl_downward_process_dao_parent_changes(struct rpl_instance *instance); diff --git a/source/Security/kmp/kmp_api.c b/source/Security/kmp/kmp_api.c index 345e9ba9fc..d3a61fe867 100644 --- a/source/Security/kmp/kmp_api.c +++ b/source/Security/kmp/kmp_api.c @@ -99,7 +99,7 @@ static void kmp_sec_prot_receive_disable(sec_prot_t *prot); #define kmp_api_get_from_prot(prot) (kmp_api_t *)(((uint8_t *)prot) - offsetof(kmp_api_t, sec_prot)); -kmp_api_t *kmp_api_create(kmp_service_t *service, kmp_type_e type, sec_prot_cfg_t *cfg) +kmp_api_t *kmp_api_create(kmp_service_t *service, kmp_type_e type, sec_prot_cfg_t *prot_cfg, sec_timer_cfg_t *timer_cfg) { if (!service) { return 0; @@ -151,7 +151,8 @@ kmp_api_t *kmp_api_create(kmp_service_t *service, kmp_type_e type, sec_prot_cfg_ kmp->sec_prot.addr_get = kmp_sec_prot_eui64_addr_get; kmp->sec_prot.type_get = kmp_sec_prot_by_type_get; kmp->sec_prot.receive_disable = kmp_sec_prot_receive_disable; - kmp->sec_prot.cfg = cfg; + kmp->sec_prot.prot_cfg = prot_cfg; + kmp->sec_prot.timer_cfg = timer_cfg; if (sec_prot->init(&kmp->sec_prot) < 0) { ns_dyn_mem_free(kmp); diff --git a/source/Security/kmp/kmp_api.h b/source/Security/kmp/kmp_api.h index 062b36b4ad..10f36528bd 100644 --- a/source/Security/kmp/kmp_api.h +++ b/source/Security/kmp/kmp_api.h @@ -125,12 +125,13 @@ typedef void kmp_api_finished(kmp_api_t *kmp); * * \param service KMP service * \param type KMP type - * \param cfg configuration + * \param prot_cfg protocol configuration + * \param timer_cfg timer configuration * * \return KMP instance or NULL * */ -kmp_api_t *kmp_api_create(kmp_service_t *service, kmp_type_e type, sec_prot_cfg_t *cfg); +kmp_api_t *kmp_api_create(kmp_service_t *service, kmp_type_e type, sec_prot_cfg_t *prot_cfg, sec_timer_cfg_t *timer_cfg); /** * kmp_api_start start KMP api diff --git a/source/Security/protocols/eap_tls_sec_prot/auth_eap_tls_sec_prot.c b/source/Security/protocols/eap_tls_sec_prot/auth_eap_tls_sec_prot.c index e8118585ad..2fd7d96b65 100644 --- a/source/Security/protocols/eap_tls_sec_prot/auth_eap_tls_sec_prot.c +++ b/source/Security/protocols/eap_tls_sec_prot/auth_eap_tls_sec_prot.c @@ -189,7 +189,7 @@ static int8_t auth_eap_tls_sec_prot_receive(sec_prot_t *prot, void *pdu, uint16_ // Call state machine prot->state_machine(prot); // Resets trickle timer to give time for supplicant to answer - sec_prot_timer_trickle_start(&data->common, &prot->cfg->sec_prot_trickle_params); + sec_prot_timer_trickle_start(&data->common, &prot->prot_cfg->sec_prot_trickle_params); data->init_key_cnt++; } // Filters repeated initial EAPOL-key messages @@ -297,7 +297,7 @@ static void auth_eap_tls_sec_prot_timer_timeout(sec_prot_t *prot, uint16_t ticks } sec_prot_timer_timeout_handle(prot, &data->common, - &prot->cfg->sec_prot_trickle_params, ticks); + &prot->prot_cfg->sec_prot_trickle_params, ticks); } static void auth_eap_tls_sec_prot_tls_create_indication(sec_prot_t *tls_prot) @@ -421,7 +421,7 @@ static void auth_eap_tls_sec_prot_state_machine(sec_prot_t *prot) auth_eap_tls_sec_prot_message_send(prot, EAP_REQ, EAP_IDENTITY, EAP_TLS_EXCHANGE_NONE); // Start trickle timer to re-send if no response - sec_prot_timer_trickle_start(&data->common, &prot->cfg->sec_prot_trickle_params); + sec_prot_timer_trickle_start(&data->common, &prot->prot_cfg->sec_prot_trickle_params); sec_prot_state_set(prot, &data->common, EAP_TLS_STATE_RESPONSE_ID); break; @@ -445,7 +445,7 @@ static void auth_eap_tls_sec_prot_state_machine(sec_prot_t *prot) auth_eap_tls_sec_prot_message_send(prot, EAP_REQ, EAP_TLS, EAP_TLS_EXCHANGE_START); // Start trickle timer to re-send if no response - sec_prot_timer_trickle_start(&data->common, &prot->cfg->sec_prot_trickle_params); + sec_prot_timer_trickle_start(&data->common, &prot->prot_cfg->sec_prot_trickle_params); sec_prot_state_set(prot, &data->common, EAP_TLS_STATE_RESPONSE_START); break; @@ -527,7 +527,7 @@ static void auth_eap_tls_sec_prot_state_machine(sec_prot_t *prot) auth_eap_tls_sec_prot_message_send(prot, EAP_REQ, EAP_TLS, EAP_TLS_EXCHANGE_ONGOING); // Start trickle timer to re-send if no response - sec_prot_timer_trickle_start(&data->common, &prot->cfg->sec_prot_trickle_params); + sec_prot_timer_trickle_start(&data->common, &prot->prot_cfg->sec_prot_trickle_params); } else { // TLS done, indicate success to peer if (data->tls_result == EAP_TLS_RESULT_HANDSHAKE_OVER) { diff --git a/source/Security/protocols/eap_tls_sec_prot/supp_eap_tls_sec_prot.c b/source/Security/protocols/eap_tls_sec_prot/supp_eap_tls_sec_prot.c index c7c935242d..b7df2d6eb6 100644 --- a/source/Security/protocols/eap_tls_sec_prot/supp_eap_tls_sec_prot.c +++ b/source/Security/protocols/eap_tls_sec_prot/supp_eap_tls_sec_prot.c @@ -404,7 +404,7 @@ static void supp_eap_tls_sec_prot_state_machine(sec_prot_t *prot) } // Set retry timeout based on network size - data->common.ticks = prot->cfg->sec_prot_retry_timeout; + data->common.ticks = prot->prot_cfg->sec_prot_retry_timeout; // Store sequence ID supp_eap_tls_sec_prot_seq_id_update(prot); @@ -449,7 +449,7 @@ static void supp_eap_tls_sec_prot_state_machine(sec_prot_t *prot) supp_eap_tls_sec_prot_seq_id_update(prot); sec_prot_state_set(prot, &data->common, EAP_TLS_STATE_REQUEST); - data->common.ticks = prot->cfg->sec_prot_retry_timeout; + data->common.ticks = prot->prot_cfg->sec_prot_retry_timeout; // Initialize TLS protocol if (supp_eap_tls_sec_prot_init_tls(prot) < 0) { @@ -483,7 +483,7 @@ static void supp_eap_tls_sec_prot_state_machine(sec_prot_t *prot) // Store sequence ID if (supp_eap_tls_sec_prot_seq_id_update(prot)) { // When receiving a new sequence number, adds more time for re-send if no response - data->common.ticks = prot->cfg->sec_prot_retry_timeout; + data->common.ticks = prot->prot_cfg->sec_prot_retry_timeout; } // All fragments received for a message diff --git a/source/Security/protocols/fwh_sec_prot/auth_fwh_sec_prot.c b/source/Security/protocols/fwh_sec_prot/auth_fwh_sec_prot.c index b43ca5e58f..285a75db8e 100644 --- a/source/Security/protocols/fwh_sec_prot/auth_fwh_sec_prot.c +++ b/source/Security/protocols/fwh_sec_prot/auth_fwh_sec_prot.c @@ -66,6 +66,7 @@ typedef struct { fwh_sec_prot_msg_e recv_msg; /**< Received message */ uint8_t nonce[EAPOL_KEY_NONCE_LEN]; /**< Authenticator nonce */ uint8_t new_ptk[PTK_LEN]; /**< PTK (384 bits) */ + uint8_t remote_eui64[8]; /**< Remote EUI-64 used to calculate PTK */ void *recv_pdu; /**< received pdu */ uint16_t recv_size; /**< received pdu size */ } fwh_sec_prot_int_t; @@ -265,14 +266,20 @@ static int8_t auth_fwh_sec_prot_message_send(sec_prot_t *prot, fwh_sec_prot_msg_ switch (msg) { case FWH_MESSAGE_1: - sec_prot_keys_pmk_replay_cnt_increment(prot->sec_keys); + if (!sec_prot_keys_pmk_replay_cnt_increment(prot->sec_keys)) { + ns_dyn_mem_free(kde_start); + return 1; + } eapol_pdu.msg.key.replay_counter = sec_prot_keys_pmk_replay_cnt_get(prot->sec_keys); eapol_pdu.msg.key.key_information.key_ack = true; eapol_pdu.msg.key.key_length = EAPOL_KEY_LEN; eapol_pdu.msg.key.key_nonce = data->nonce; break; case FWH_MESSAGE_3: - sec_prot_keys_pmk_replay_cnt_increment(prot->sec_keys); + if (!sec_prot_keys_pmk_replay_cnt_increment(prot->sec_keys)) { + ns_dyn_mem_free(kde_start); + return -1; + } eapol_pdu.msg.key.replay_counter = sec_prot_keys_pmk_replay_cnt_get(prot->sec_keys); eapol_pdu.msg.key.key_information.install = true; eapol_pdu.msg.key.key_information.key_ack = true; @@ -306,7 +313,7 @@ static int8_t auth_fwh_sec_prot_message_send(sec_prot_t *prot, fwh_sec_prot_msg_ static void auth_fwh_sec_prot_timer_timeout(sec_prot_t *prot, uint16_t ticks) { fwh_sec_prot_int_t *data = fwh_sec_prot_get(prot); - sec_prot_timer_timeout_handle(prot, &data->common, &prot->cfg->sec_prot_trickle_params, ticks); + sec_prot_timer_timeout_handle(prot, &data->common, &prot->prot_cfg->sec_prot_trickle_params, ticks); } static void auth_fwh_sec_prot_state_machine(sec_prot_t *prot) @@ -343,7 +350,7 @@ static void auth_fwh_sec_prot_state_machine(sec_prot_t *prot) auth_fwh_sec_prot_message_send(prot, FWH_MESSAGE_1); // Start trickle timer to re-send if no response - sec_prot_timer_trickle_start(&data->common, &prot->cfg->sec_prot_trickle_params); + sec_prot_timer_trickle_start(&data->common, &prot->prot_cfg->sec_prot_trickle_params); sec_prot_state_set(prot, &data->common, FWH_STATE_MESSAGE_2); break; @@ -371,7 +378,7 @@ static void auth_fwh_sec_prot_state_machine(sec_prot_t *prot) auth_fwh_sec_prot_message_send(prot, FWH_MESSAGE_3); // Start trickle timer to re-send if no response - sec_prot_timer_trickle_start(&data->common, &prot->cfg->sec_prot_trickle_params); + sec_prot_timer_trickle_start(&data->common, &prot->prot_cfg->sec_prot_trickle_params); sec_prot_state_set(prot, &data->common, FWH_STATE_MESSAGE_4); } @@ -391,12 +398,16 @@ static void auth_fwh_sec_prot_state_machine(sec_prot_t *prot) } // PTK is fresh for installing any GTKs sec_prot_keys_ptk_installed_gtk_hash_clear_all(prot->sec_keys); + /* Store the hash for to-be installed GTK as used for the PTK, on 4WH + this stores only the hash in NVM and does not affect otherwise */ + sec_prot_keys_ptk_installed_gtk_hash_set(prot->sec_keys, true); // If GTK was inserted set it valid sec_prot_keys_gtkl_from_gtk_insert_index_set(prot->sec_keys); // Reset PTK mismatch sec_prot_keys_ptk_mismatch_reset(prot->sec_keys); // Update PTK - sec_prot_keys_ptk_write(prot->sec_keys, data->new_ptk); + sec_prot_keys_ptk_write(prot->sec_keys, data->new_ptk, prot->timer_cfg->ptk_lifetime); + sec_prot_keys_ptk_eui_64_write(prot->sec_keys, data->remote_eui64); sec_prot_state_set(prot, &data->common, FWH_STATE_FINISH); } break; @@ -427,9 +438,7 @@ static int8_t auth_fwh_sec_prot_ptk_generate(sec_prot_t *prot, sec_prot_keys_t * fwh_sec_prot_int_t *data = fwh_sec_prot_get(prot); uint8_t local_eui64[8]; - uint8_t remote_eui64[8]; - - prot->addr_get(prot, local_eui64, remote_eui64); + prot->addr_get(prot, local_eui64, data->remote_eui64); uint8_t *remote_nonce = data->recv_eapol_pdu.msg.key.key_nonce; if (!remote_nonce) { @@ -438,7 +447,7 @@ static int8_t auth_fwh_sec_prot_ptk_generate(sec_prot_t *prot, sec_prot_keys_t * } uint8_t *pmk = sec_prot_keys_pmk_get(sec_keys); - sec_prot_lib_ptk_calc(pmk, local_eui64, remote_eui64, data->nonce, remote_nonce, data->new_ptk); + sec_prot_lib_ptk_calc(pmk, local_eui64, data->remote_eui64, data->nonce, remote_nonce, data->new_ptk); return 0; } diff --git a/source/Security/protocols/fwh_sec_prot/supp_fwh_sec_prot.c b/source/Security/protocols/fwh_sec_prot/supp_fwh_sec_prot.c index e5a44e18b8..ef3e9bd991 100644 --- a/source/Security/protocols/fwh_sec_prot/supp_fwh_sec_prot.c +++ b/source/Security/protocols/fwh_sec_prot/supp_fwh_sec_prot.c @@ -139,7 +139,7 @@ static int8_t supp_fwh_sec_prot_init(sec_prot_t *prot) sec_prot_init(&data->common); sec_prot_state_set(prot, &data->common, FWH_STATE_INIT); - data->common.ticks = prot->cfg->sec_prot_retry_timeout; + data->common.ticks = prot->prot_cfg->sec_prot_retry_timeout; data->msg3_received = false; data->msg3_retry_wait = false; data->recv_replay_cnt = 0; @@ -337,7 +337,7 @@ static void supp_fwh_sec_prot_state_machine(sec_prot_t *prot) if (sec_prot_result_ok_check(&data->common)) { // Send 4WH message 2 supp_fwh_sec_prot_message_send(prot, FWH_MESSAGE_2); - data->common.ticks = prot->cfg->sec_prot_retry_timeout; + data->common.ticks = prot->prot_cfg->sec_prot_retry_timeout; sec_prot_state_set(prot, &data->common, FWH_STATE_MESSAGE_3); } else { // Ready to be deleted @@ -365,7 +365,7 @@ static void supp_fwh_sec_prot_state_machine(sec_prot_t *prot) // Send 4WH message 2 supp_fwh_sec_prot_message_send(prot, FWH_MESSAGE_2); - data->common.ticks = prot->cfg->sec_prot_retry_timeout; + data->common.ticks = prot->prot_cfg->sec_prot_retry_timeout; return; } else if (data->recv_msg != FWH_MESSAGE_3) { return; @@ -392,7 +392,7 @@ static void supp_fwh_sec_prot_state_machine(sec_prot_t *prot) // Sends 4WH Message 4 supp_fwh_sec_prot_message_send(prot, FWH_MESSAGE_4); - data->common.ticks = prot->cfg->sec_prot_retry_timeout; + data->common.ticks = prot->prot_cfg->sec_prot_retry_timeout; sec_prot_state_set(prot, &data->common, FWH_STATE_FINISH); break; @@ -409,7 +409,7 @@ static void supp_fwh_sec_prot_state_machine(sec_prot_t *prot) tr_info("4WH: finish, wait Message 3 retry"); - sec_prot_keys_ptk_write(prot->sec_keys, data->new_ptk); + sec_prot_keys_ptk_write(prot->sec_keys, data->new_ptk, prot->timer_cfg->ptk_lifetime); sec_prot_keys_ptk_eui_64_write(prot->sec_keys, data->remote_eui64); data->common.ticks = 60 * 10; // 60 seconds diff --git a/source/Security/protocols/gkh_sec_prot/auth_gkh_sec_prot.c b/source/Security/protocols/gkh_sec_prot/auth_gkh_sec_prot.c index 9c1b47d01d..7d736ae95b 100644 --- a/source/Security/protocols/gkh_sec_prot/auth_gkh_sec_prot.c +++ b/source/Security/protocols/gkh_sec_prot/auth_gkh_sec_prot.c @@ -226,7 +226,10 @@ static int8_t auth_gkh_sec_prot_message_send(sec_prot_t *prot, gkh_sec_prot_msg_ switch (msg) { case GKH_MESSAGE_1: - sec_prot_keys_pmk_replay_cnt_increment(prot->sec_keys); + if (!sec_prot_keys_pmk_replay_cnt_increment(prot->sec_keys)) { + ns_dyn_mem_free(kde_start); + return -1; + } eapol_pdu.msg.key.replay_counter = sec_prot_keys_pmk_replay_cnt_get(prot->sec_keys); eapol_pdu.msg.key.key_information.key_ack = true; eapol_pdu.msg.key.key_information.key_mic = true; @@ -258,7 +261,7 @@ static int8_t auth_gkh_sec_prot_message_send(sec_prot_t *prot, gkh_sec_prot_msg_ static void auth_gkh_sec_prot_timer_timeout(sec_prot_t *prot, uint16_t ticks) { gkh_sec_prot_int_t *data = gkh_sec_prot_get(prot); - sec_prot_timer_timeout_handle(prot, &data->common, &prot->cfg->sec_prot_trickle_params, ticks); + sec_prot_timer_timeout_handle(prot, &data->common, &prot->prot_cfg->sec_prot_trickle_params, ticks); } static void auth_gkh_sec_prot_state_machine(sec_prot_t *prot) @@ -283,16 +286,16 @@ static void auth_gkh_sec_prot_state_machine(sec_prot_t *prot) // KMP-CREATE.confirm prot->create_conf(prot, SEC_RESULT_OK); - // Sends 4WH Message 1 + // Sends GKH Message 1 auth_gkh_sec_prot_message_send(prot, GKH_MESSAGE_1); // Start trickle timer to re-send if no response - sec_prot_timer_trickle_start(&data->common, &prot->cfg->sec_prot_trickle_params); + sec_prot_timer_trickle_start(&data->common, &prot->prot_cfg->sec_prot_trickle_params); sec_prot_state_set(prot, &data->common, GKH_STATE_MESSAGE_2); // Store the hash for to-be installed GTK as used for the PTK - sec_prot_keys_ptk_installed_gtk_hash_set(prot->sec_keys); + sec_prot_keys_ptk_installed_gtk_hash_set(prot->sec_keys, false); break; // Wait GKH message 2 diff --git a/source/Security/protocols/key_sec_prot/key_sec_prot.c b/source/Security/protocols/key_sec_prot/key_sec_prot.c index daa07af371..ad75cf5853 100644 --- a/source/Security/protocols/key_sec_prot/key_sec_prot.c +++ b/source/Security/protocols/key_sec_prot/key_sec_prot.c @@ -268,6 +268,7 @@ static int8_t key_sec_prot_receive(sec_prot_t *prot, void *pdu, uint16_t size) // Checks if supplicant indicates that it has valid PMK uint8_t remote_keyid[KEYID_LEN]; if (kde_pmkid_read(kde, kde_len, remote_keyid) >= 0) { + tr_debug("recv PMKID: %s", trace_array(remote_keyid, 16)); uint8_t pmkid[PMKID_LEN]; if (sec_prot_lib_pmkid_generate(prot, pmkid, true) >= 0) { if (memcmp(remote_keyid, pmkid, PMKID_LEN) == 0) { @@ -278,6 +279,7 @@ static int8_t key_sec_prot_receive(sec_prot_t *prot, void *pdu, uint16_t size) // Checks if supplicant indicates that it has valid PTK if (kde_ptkid_read(kde, kde_len, remote_keyid) >= 0) { + tr_debug("recv PTKID: %s", trace_array(remote_keyid, 16)); uint8_t ptkid[PTKID_LEN]; if (sec_prot_lib_ptkid_generate(prot, ptkid, true) >= 0) { if (memcmp(remote_keyid, ptkid, PTKID_LEN) == 0) { diff --git a/source/Security/protocols/sec_prot.h b/source/Security/protocols/sec_prot.h index 556d769f6b..c6ebae78a9 100644 --- a/source/Security/protocols/sec_prot.h +++ b/source/Security/protocols/sec_prot.h @@ -268,7 +268,8 @@ struct sec_prot_s { sec_prot_receive_disable *receive_disable; /**< Disable receiving of messages */ sec_prot_keys_t *sec_keys; /**< Security keys storage pointer */ - sec_prot_cfg_t *cfg; /**< Configuration pointer */ + sec_prot_cfg_t *prot_cfg; /**< Security protocol configuration pointer */ + sec_timer_cfg_t *timer_cfg; /**< Security timer configuration pointer */ uint8_t header_size; /**< Header size */ sec_prot_int_data_t *data; /**< Protocol internal data */ }; diff --git a/source/Security/protocols/sec_prot_certs.h b/source/Security/protocols/sec_prot_certs.h index e9a25ece84..9a204aaa09 100644 --- a/source/Security/protocols/sec_prot_certs.h +++ b/source/Security/protocols/sec_prot_certs.h @@ -54,7 +54,7 @@ typedef struct { typedef NS_LIST_HEAD(cert_chain_entry_t, link) cert_chain_list_t; typedef NS_LIST_HEAD(cert_revocat_list_entry_t, link) cert_revocat_lists_t; -typedef struct { +typedef struct sec_prot_certs_s { cert_chain_entry_t own_cert_chain; /**< Own certificate chain */ cert_chain_list_t trusted_cert_chain_list; /**< Trusted certificate chain lists */ cert_revocat_lists_t cert_revocat_lists; /**< Certificate Revocation Lists */ diff --git a/source/Security/protocols/sec_prot_cfg.h b/source/Security/protocols/sec_prot_cfg.h index fa2a88dafb..f0a118b7c1 100644 --- a/source/Security/protocols/sec_prot_cfg.h +++ b/source/Security/protocols/sec_prot_cfg.h @@ -24,6 +24,23 @@ typedef struct sec_prot_cfg_s { trickle_params_t sec_prot_trickle_params; uint16_t sec_prot_retry_timeout; uint16_t sec_max_ongoing_authentication; + uint16_t initial_key_retry_delay; + trickle_params_t initial_key_trickle_params; + uint8_t initial_key_retry_cnt; } sec_prot_cfg_t; +/* Security timer configuration settings */ + +typedef struct sec_timer_cfg_s { + uint32_t gtk_expire_offset; /* GTK lifetime; GTK_EXPIRE_OFFSET (seconds) */ + uint32_t pmk_lifetime; /* PMK lifetime (seconds) */ + uint32_t ptk_lifetime; /* PTK lifetime (seconds) */ + uint16_t gtk_new_act_time; /* GTK_NEW_ACTIVATION_TIME (1/X of expire offset) */ + uint16_t revocat_lifetime_reduct; /* REVOCATION_LIFETIME_REDUCTION (reduction of lifetime) */ + uint16_t gtk_request_imin; /* GTK_REQUEST_IMIN (seconds) */ + uint16_t gtk_request_imax; /* GTK_REQUEST_IMAX (seconds) */ + uint16_t gtk_max_mismatch; /* GTK_MAX_MISMATCH (seconds) */ + uint8_t gtk_new_install_req; /* GTK_NEW_INSTALL_REQUIRED (percent of GTK lifetime) */ +} sec_timer_cfg_t; + #endif /* SEC_PROT_CONF_H_ */ diff --git a/source/Security/protocols/sec_prot_keys.c b/source/Security/protocols/sec_prot_keys.c index c420a5823f..d7071e9323 100644 --- a/source/Security/protocols/sec_prot_keys.c +++ b/source/Security/protocols/sec_prot_keys.c @@ -56,8 +56,8 @@ sec_prot_keys_t *sec_prot_keys_create(sec_prot_gtk_keys_t *gtks, const sec_prot_ void sec_prot_keys_init(sec_prot_keys_t *sec_keys, sec_prot_gtk_keys_t *gtks, const sec_prot_certs_t *certs) { memset(sec_keys, 0, sizeof(sec_prot_keys_t)); - sec_keys->pmk_lifetime = PMK_LIFETIME_INSTALL; - sec_keys->ptk_lifetime = PTK_LIFETIME_INSTALL; + sec_keys->pmk_lifetime = 0; + sec_keys->ptk_lifetime = 0; sec_keys->pmk_key_replay_cnt = 0; sec_keys->gtks = gtks; sec_keys->certs = certs; @@ -101,12 +101,12 @@ void sec_prot_keys_gtks_delete(sec_prot_gtk_keys_t *gtks) ns_dyn_mem_free(gtks); } -void sec_prot_keys_pmk_write(sec_prot_keys_t *sec_keys, uint8_t *pmk) +void sec_prot_keys_pmk_write(sec_prot_keys_t *sec_keys, uint8_t *pmk, uint32_t pmk_lifetime) { memcpy(sec_keys->pmk, pmk, PMK_LEN); sec_keys->pmk_key_replay_cnt = 0; sec_keys->pmk_key_replay_cnt_set = false; - sec_keys->pmk_lifetime = PMK_LIFETIME_INSTALL; + sec_keys->pmk_lifetime = pmk_lifetime; sec_keys->pmk_set = true; sec_keys->updated = true; } @@ -116,7 +116,7 @@ void sec_prot_keys_pmk_delete(sec_prot_keys_t *sec_keys) memset(sec_keys->pmk, 0, PMK_LEN); sec_keys->pmk_key_replay_cnt = 0; sec_keys->pmk_key_replay_cnt_set = false; - sec_keys->pmk_lifetime = PMK_LIFETIME_INSTALL; + sec_keys->pmk_lifetime = 0; sec_keys->pmk_set = false; sec_keys->updated = true; } @@ -130,6 +130,15 @@ uint8_t *sec_prot_keys_pmk_get(sec_prot_keys_t *sec_keys) return sec_keys->pmk; } +uint32_t sec_prot_keys_pmk_lifetime_get(sec_prot_keys_t *sec_keys) +{ + if (!sec_keys->pmk_set) { + return 0; + } + + return sec_keys->pmk_lifetime; +} + uint64_t sec_prot_keys_pmk_replay_cnt_get(sec_prot_keys_t *sec_keys) { return sec_keys->pmk_key_replay_cnt; @@ -140,15 +149,20 @@ void sec_prot_keys_pmk_replay_cnt_set(sec_prot_keys_t *sec_keys, uint64_t counte sec_keys->pmk_key_replay_cnt_set = true; sec_keys->pmk_key_replay_cnt = counter; } - -void sec_prot_keys_pmk_replay_cnt_increment(sec_prot_keys_t *sec_keys) +bool sec_prot_keys_pmk_replay_cnt_increment(sec_prot_keys_t *sec_keys) { // Start from zero i.e. does not increment on first call if (!sec_keys->pmk_key_replay_cnt_set) { sec_keys->pmk_key_replay_cnt_set = true; - return; + return true; + } + // If counter is near to exhaust return error (ignores MSB 32bits which are re-start counter) + if ((sec_keys->pmk_key_replay_cnt & PMK_KEY_REPLAY_CNT_LIMIT_MASK) > PMK_KEY_REPLAY_CNT_LIMIT) { + sec_keys->pmk_key_replay_cnt |= 0xFFFF; // Invalidate counter; will result removal of keys + return false; } sec_keys->pmk_key_replay_cnt++; + return true; } bool sec_prot_keys_pmk_replay_cnt_compare(uint64_t received_counter, sec_prot_keys_t *sec_keys) @@ -179,16 +193,12 @@ bool sec_prot_keys_pmk_mismatch_is_set(sec_prot_keys_t *sec_keys) return sec_keys->pmk_mismatch; } -bool sec_prot_keys_pmk_lifetime_decrement(sec_prot_keys_t *sec_keys, uint32_t default_lifetime, uint8_t seconds) +bool sec_prot_keys_pmk_lifetime_decrement(sec_prot_keys_t *sec_keys, uint8_t seconds) { if (!sec_keys->pmk_set) { return false; } - if (sec_keys->pmk_lifetime == PMK_LIFETIME_INSTALL) { - sec_keys->pmk_lifetime = default_lifetime; - } - if (sec_keys->pmk_lifetime > seconds) { sec_keys->pmk_lifetime -= seconds; } else { @@ -202,10 +212,10 @@ bool sec_prot_keys_pmk_lifetime_decrement(sec_prot_keys_t *sec_keys, uint32_t de return false; } -void sec_prot_keys_ptk_write(sec_prot_keys_t *sec_keys, uint8_t *ptk) +void sec_prot_keys_ptk_write(sec_prot_keys_t *sec_keys, uint8_t *ptk, uint32_t ptk_lifetime) { memcpy(sec_keys->ptk, ptk, PTK_LEN); - sec_keys->ptk_lifetime = PTK_LIFETIME_INSTALL; + sec_keys->ptk_lifetime = ptk_lifetime; sec_keys->ptk_set = true; sec_keys->updated = true; } @@ -213,7 +223,7 @@ void sec_prot_keys_ptk_write(sec_prot_keys_t *sec_keys, uint8_t *ptk) void sec_prot_keys_ptk_delete(sec_prot_keys_t *sec_keys) { memset(sec_keys->ptk, 0, PTK_LEN); - sec_keys->ptk_lifetime = PTK_LIFETIME_INSTALL; + sec_keys->ptk_lifetime = 0; sec_keys->ptk_set = false; sec_keys->updated = true; } @@ -227,6 +237,15 @@ uint8_t *sec_prot_keys_ptk_get(sec_prot_keys_t *sec_keys) return sec_keys->ptk; } +uint32_t sec_prot_keys_ptk_lifetime_get(sec_prot_keys_t *sec_keys) +{ + if (!sec_keys->ptk_set) { + return 0; + } + + return sec_keys->ptk_lifetime; +} + void sec_prot_keys_ptk_mismatch_set(sec_prot_keys_t *sec_keys) { sec_keys->ptk_mismatch = true; @@ -265,16 +284,12 @@ void sec_prot_keys_ptk_eui_64_delete(sec_prot_keys_t *sec_keys) sec_keys->updated = true; } -bool sec_prot_keys_ptk_lifetime_decrement(sec_prot_keys_t *sec_keys, uint32_t default_lifetime, uint8_t seconds) +bool sec_prot_keys_ptk_lifetime_decrement(sec_prot_keys_t *sec_keys, uint8_t seconds) { if (!sec_keys->ptk_set) { return false; } - if (sec_keys->ptk_lifetime == PTK_LIFETIME_INSTALL) { - sec_keys->ptk_lifetime = default_lifetime; - } - if (sec_keys->ptk_lifetime > seconds) { sec_keys->ptk_lifetime -= seconds; } else { @@ -380,8 +395,11 @@ int8_t sec_prot_keys_gtk_insert_index_from_gtkl_get(sec_prot_keys_t *sec_keys) // Checks all keys for (uint8_t i = 0; i < GTK_NUM; i++) { - if (sec_prot_keys_gtk_status_is_live(sec_keys->gtks, i)) { - // If key is live, but not indicated on GTKL inserts it + if (sec_prot_keys_gtk_status_is_live(sec_keys->gtks, i) || + sec_prot_keys_gtk_status_get(sec_keys->gtks, i) == GTK_STATUS_OLD) { + /* If key is live, but not indicated on GTKL inserts it. Also old keys indicated + still on GTK hash are inserted, since supplicants do not know the status of the + key and might need the key for receive (only) from not updated neighbors */ if (!sec_prot_keys_gtkl_gtk_is_live(sec_keys, i)) { sec_prot_keys_gtk_insert_index_set(sec_keys, i); return i; @@ -438,6 +456,8 @@ int8_t sec_prot_keys_gtk_clear(sec_prot_gtk_keys_t *gtks, uint8_t index) gtks->gtk[index].status = GTK_STATUS_NEW; memset(gtks->gtk[index].key, 0, GTK_LEN); + gtks->updated = true; + sec_prot_keys_gtk_install_order_update(gtks); return 0; @@ -470,7 +490,7 @@ uint32_t sec_prot_keys_gtk_lifetime_get(sec_prot_gtk_keys_t *gtks, uint8_t index return gtks->gtk[index].lifetime; } -uint32_t sec_prot_keys_gtk_lifetime_decrement(sec_prot_gtk_keys_t *gtks, uint8_t index, uint16_t seconds) +uint32_t sec_prot_keys_gtk_lifetime_decrement(sec_prot_gtk_keys_t *gtks, uint8_t index, uint64_t current_time, uint16_t seconds) { if (gtks->gtk[index].lifetime > seconds) { gtks->gtk[index].lifetime -= seconds; @@ -478,9 +498,44 @@ uint32_t sec_prot_keys_gtk_lifetime_decrement(sec_prot_gtk_keys_t *gtks, uint8_t gtks->gtk[index].lifetime = 0; } + // Calculates expiration timestamp for GTK from current time and lifetime + uint64_t expirytime = current_time + gtks->gtk[index].lifetime; + uint64_t diff; + // Compares calculated timestamp to stored one + if (gtks->gtk[index].expirytime >= expirytime) { + diff = gtks->gtk[index].expirytime - expirytime; + } else { + diff = expirytime - gtks->gtk[index].expirytime; + } + // If timestamps differ for more than 5 minutes marks field as updated (and stores to NVM) + if (diff > 300) { + gtks->updated = true; + } + return gtks->gtk[index].lifetime; } +uint64_t sec_prot_keys_gtk_exptime_from_lifetime_get(sec_prot_gtk_keys_t *gtks, uint8_t index, uint64_t current_time) +{ + if (index >= GTK_NUM || !gtks->gtk[index].set) { + return 0; + } + + uint32_t lifetime = gtks->gtk[index].lifetime; + return current_time + lifetime; +} + +int8_t sec_prot_keys_gtk_expirytime_set(sec_prot_gtk_keys_t *gtks, uint8_t index, uint64_t expirytime) +{ + if (index >= GTK_NUM || !gtks->gtk[index].set) { + return -1; + } + + gtks->gtk[index].expirytime = expirytime; + + return 0; +} + bool sec_prot_keys_gtks_are_updated(sec_prot_gtk_keys_t *gtks) { return gtks->updated; @@ -505,6 +560,7 @@ void sec_prot_keys_gtk_status_fresh_set(sec_prot_gtk_keys_t *gtks, uint8_t index // Active key remains as active, old keys are never reused if (gtks->gtk[index].status < GTK_STATUS_FRESH) { gtks->gtk[index].status = GTK_STATUS_FRESH; + gtks->updated = true; } } @@ -528,9 +584,11 @@ int8_t sec_prot_keys_gtk_status_active_set(sec_prot_gtk_keys_t *gtks, uint8_t in // Sets previously active key old if (gtks->gtk[i].status == GTK_STATUS_ACTIVE) { gtks->gtk[i].status = GTK_STATUS_OLD; + gtks->updated = true; } } gtks->gtk[index].status = GTK_STATUS_ACTIVE; + gtks->updated = true; return 0; } @@ -548,6 +606,16 @@ int8_t sec_prot_keys_gtk_status_active_get(sec_prot_gtk_keys_t *gtks) return -1; } +int8_t sec_prot_keys_gtk_status_active_to_fresh_set(sec_prot_gtk_keys_t *gtks) +{ + int8_t index = sec_prot_keys_gtk_status_active_get(gtks); + if (index < 0) { + return -1; + } + + return sec_prot_keys_gtk_status_set(gtks, index, GTK_STATUS_FRESH); +} + bool sec_prot_keys_gtk_status_is_live(sec_prot_gtk_keys_t *gtks, uint8_t index) { if (index >= GTK_NUM || !gtks->gtk[index].set) { @@ -567,9 +635,36 @@ void sec_prot_keys_gtk_status_new_set(sec_prot_gtk_keys_t *gtks, uint8_t index) return; } + if (gtks->gtk[index].status != GTK_STATUS_NEW) { + gtks->updated = true; + } + gtks->gtk[index].status = GTK_STATUS_NEW; } +uint8_t sec_prot_keys_gtk_status_get(sec_prot_gtk_keys_t *gtks, uint8_t index) +{ + if (index >= GTK_NUM || !gtks->gtk[index].set) { + return 0; + } + + return gtks->gtk[index].status; +} + +int8_t sec_prot_keys_gtk_status_set(sec_prot_gtk_keys_t *gtks, uint8_t index, uint8_t status) +{ + if (index >= GTK_NUM || !gtks->gtk[index].set) { + return -1; + } + + if (gtks->gtk[index].status != status) { + gtks->updated = true; + } + + gtks->gtk[index].status = status; + return 0; +} + void sec_prot_keys_gtks_hash_generate(sec_prot_gtk_keys_t *gtks, uint8_t *gtkhash) { memset(gtkhash, 0, GTK_ALL_HASHES_LEN); @@ -758,6 +853,9 @@ void sec_prot_keys_gtk_install_order_update(sec_prot_gtk_keys_t *gtks) uint8_t new_install_order = 0; for (uint8_t i = 0; i < GTK_NUM; i++) { if (ordered_indexes[i] >= 0) { + if (gtks->gtk[ordered_indexes[i]].install_order != new_install_order) { + gtks->updated = true; + } gtks->gtk[ordered_indexes[i]].install_order = new_install_order++; } } @@ -786,6 +884,29 @@ int8_t sec_prot_keys_gtk_install_index_get(sec_prot_gtk_keys_t *gtks) return install_index; } +uint8_t sec_prot_keys_gtk_install_order_get(sec_prot_gtk_keys_t *gtks, uint8_t index) +{ + if (index >= GTK_NUM || !gtks->gtk[index].set) { + return 0; + } + + return gtks->gtk[index].install_order; +} + +int8_t sec_prot_keys_gtk_install_order_set(sec_prot_gtk_keys_t *gtks, uint8_t index, uint8_t install_order) +{ + if (index >= GTK_NUM || !gtks->gtk[index].set) { + return -1; + } + if (gtks->gtk[index].install_order != install_order) { + gtks->updated = true; + } + + gtks->gtk[index].install_order = install_order; + return 0; +} + + uint8_t sec_prot_keys_gtk_count(sec_prot_gtk_keys_t *gtks) { uint8_t count = 0; @@ -802,12 +923,13 @@ uint8_t sec_prot_keys_gtk_count(sec_prot_gtk_keys_t *gtks) void sec_prot_keys_ptk_installed_gtk_hash_clear_all(sec_prot_keys_t *sec_keys) { for (uint8_t index = 0; index < GTK_NUM; index++) { - memset(sec_keys->ins_gtk_hash[sec_keys->gtk_set_index].hash, 0, INS_GTK_HASH_LEN); + memset(sec_keys->ins_gtk_hash[index].hash, 0, INS_GTK_HASH_LEN); } sec_keys->ins_gtk_hash_set = 0; + sec_keys->ins_gtk_4wh_hash_set = 0; } -void sec_prot_keys_ptk_installed_gtk_hash_set(sec_prot_keys_t *sec_keys) +void sec_prot_keys_ptk_installed_gtk_hash_set(sec_prot_keys_t *sec_keys, bool is_4wh) { if (sec_keys->gtk_set_index >= 0) { uint8_t *gtk = sec_prot_keys_gtk_get(sec_keys->gtks, sec_keys->gtk_set_index); @@ -824,12 +946,22 @@ void sec_prot_keys_ptk_installed_gtk_hash_set(sec_prot_keys_t *sec_keys) */ memcpy(sec_keys->ins_gtk_hash[sec_keys->gtk_set_index].hash, gtk_hash, INS_GTK_HASH_LEN); sec_keys->ins_gtk_hash_set |= (1 << sec_keys->gtk_set_index); + /* If used on 4WH will store the hash in case GKH is initiated later for the + * same index as 4WH (likely to happen if just GTK update is made). This allows + * that NVM storage does not need to be updated since hash is already stored. */ + if (is_4wh) { + sec_keys->ins_gtk_4wh_hash_set |= (1 << sec_keys->gtk_set_index); + } else { + sec_keys->ins_gtk_4wh_hash_set &= ~(1 << sec_keys->gtk_set_index); + } } } bool sec_prot_keys_ptk_installed_gtk_hash_mismatch_check(sec_prot_keys_t *sec_keys, uint8_t gtk_index) { - if ((sec_keys->ins_gtk_hash_set & (1 << sec_keys->gtk_set_index)) == 0) { + // If not set or the key has been inserted by 4WH then there is no mismatch + if ((sec_keys->ins_gtk_hash_set & (1 << sec_keys->gtk_set_index)) == 0 || + (sec_keys->ins_gtk_hash_set & (1 << sec_keys->gtk_set_index)) == 1) { return false; } diff --git a/source/Security/protocols/sec_prot_keys.h b/source/Security/protocols/sec_prot_keys.h index 9df422934b..06302519d2 100644 --- a/source/Security/protocols/sec_prot_keys.h +++ b/source/Security/protocols/sec_prot_keys.h @@ -41,7 +41,7 @@ #define PTKID_LEN 16 #define KEYID_LEN 16 -#define GTK_DEFAULT_LIFETIME 60 * 60 * 24 * 30 // 30 days +#define GTK_DEFAULT_LIFETIME (60 * 60 * 24 * 30) // 30 days #define GTK_EXPIRE_MISMATCH_TIME 60 // Supplicant GTK expire time mismatch occurs if GTK expires before this time #define GTK_STATUS_NEW 0 // New GTK, can transition to fresh @@ -56,18 +56,22 @@ #define GTK_ALL_HASHES_LEN GTK_HASH_LEN * GTK_NUM #define INS_GTK_HASH_LEN 2 -#define PMK_LIFETIME_INSTALL 0xFFFFF -#define PTK_LIFETIME_INSTALL 0xFFFFF +// Limit is 60000 (of 65536) +#define PMK_KEY_REPLAY_CNT_LIMIT 60000 // Upper limit for PMK replay counter +#define PMK_KEY_REPLAY_CNT_LIMIT_MASK 0xFFFF // Upper limit mask + +#define SEC_MAXIMUM_LIFETIME (60 * 60 * 24 * 30 * 24) // Maximum life time for PMK, PTK, GTKs etc. is two years typedef struct { uint8_t key[GTK_LEN]; /**< Group Transient Key (128 bits) */ + uint64_t expirytime; /**< GTK expiry time on storage */ uint32_t lifetime; /**< GTK lifetime in seconds */ unsigned status : 2; /**< Group Transient Key status */ unsigned install_order : 2; /**< Order in which GTK keys are added */ bool set: 1; /**< Group Transient Key set (valid value) */ } gtk_key_t; -typedef struct { +typedef struct sec_prot_gtk_keys_s { gtk_key_t gtk[GTK_NUM]; /**< 4 Group Transient Keys */ bool updated: 1; /**< Group Transient Keys has been updated */ } sec_prot_gtk_keys_t; @@ -90,6 +94,7 @@ typedef struct { uint8_t gtkl; /**< Remote GTKL information */ int8_t gtk_set_index; /**< Index of GTK to set */ unsigned ins_gtk_hash_set: 4; /**< Hash for inserted GTKs for a PTK set */ + unsigned ins_gtk_4wh_hash_set: 4; /**< Hash for inserted GTKs for a PTK set for a 4WH */ bool pmk_set: 1; /**< Pairwise Master Key set */ bool ptk_set: 1; /**< Pairwise Transient Key set */ bool pmk_key_replay_cnt_set: 1; /**< Pairwise Master Key replay counter set */ @@ -111,6 +116,35 @@ typedef struct { frame_counter_t counter[GTK_NUM]; /**< Frame counter for each GTK key */ } frame_counters_t; +// Authenticator supplicant security key data +typedef struct { + uint8_t pmk[PMK_LEN]; /**< Pairwise Master Key (256 bits) */ + uint8_t ptk[PTK_LEN]; /**< Pairwise Transient Key (384 bits) */ + uint8_t ptk_eui_64[8]; /**< Remote EUI-64 used to derive PTK or NULL */ + sec_prot_gtk_hash_t ins_gtk_hash[GTK_NUM]; /**< Hashes for inserted GTKs for a PTK */ + uint16_t pmk_key_replay_cnt; /**< Pairwise Master Key replay counter */ + uint16_t pmk_lifetime; /**< PMK lifetime (short time format) */ + uint16_t ptk_lifetime; /**< PTK lifetime (short time format) */ + unsigned ins_gtk_hash_set: 4; /**< Hash for inserted GTKs for a PTK set */ + unsigned ins_gtk_4wh_hash_set: 4; /**< Hash for inserted GTKs for a PTK set for a 4WH */ + bool pmk_set: 1; /**< Pairwise Master Key set */ + bool ptk_set: 1; /**< Pairwise Transient Key set */ + bool pmk_lifetime_set: 1; /**< PMK lifetime (short time format) */ + bool ptk_lifetime_set: 1; /**< PTK lifetime (short time format) */ + bool pmk_key_replay_cnt_set: 1; /**< Pairwise Master Key replay counter set */ + bool ptk_eui_64_set: 1; /**< Remote EUI-64 used to derive PTK is set */ + bool eui_64_set: 1; /**< Remote EUI-64 is set */ +} sec_prot_keys_storage_t; + +// Security keys (GTKs) and needed network information +typedef struct { + char network_name[33]; /**< Network name for keys */ + sec_prot_gtk_keys_t *gtks; /**< Link to GTKs */ + uint16_t new_pan_id; /**< new PAN ID indicated by bootstrap */ + uint16_t key_pan_id; /**< PAN ID for keys */ + bool updated : 1; /**< Network info has been updated */ +} sec_prot_keys_nw_info_t; + /* * GTK mismatch types, list is ordered according to priority of mismatch i.e. if there * are both hash and lifetime mismatch, hash has greater priority @@ -178,9 +212,10 @@ void sec_prot_keys_gtks_delete(sec_prot_gtk_keys_t *gtks); * * \param sec_keys security keys * \param pmk Pairwise Master Key + * \param pmk_lifetime PMK lifetime * */ -void sec_prot_keys_pmk_write(sec_prot_keys_t *sec_keys, uint8_t *pmk); +void sec_prot_keys_pmk_write(sec_prot_keys_t *sec_keys, uint8_t *pmk, uint32_t pmk_lifetime); /** * sec_prot_keys_pmk_delete deletes PMK @@ -200,6 +235,16 @@ void sec_prot_keys_pmk_delete(sec_prot_keys_t *sec_keys); */ uint8_t *sec_prot_keys_pmk_get(sec_prot_keys_t *sec_keys); +/** + * sec_prot_keys_pmk_lifetime_get Pairwise Master Key lifetime + * + * \param sec_keys security keys + * + * \return PMK lifetime + * + */ +uint32_t sec_prot_keys_pmk_lifetime_get(sec_prot_keys_t *sec_keys); + /** * sec_prot_keys_pmk_replay_cnt_get gets PMK replay counter value * @@ -224,8 +269,11 @@ void sec_prot_keys_pmk_replay_cnt_set(sec_prot_keys_t *sec_keys, uint64_t counte * * \param sec_keys security keys * + * \return TRUE counter was incremented + * \return FALSE counter increment failed + * */ -void sec_prot_keys_pmk_replay_cnt_increment(sec_prot_keys_t *sec_keys); +bool sec_prot_keys_pmk_replay_cnt_increment(sec_prot_keys_t *sec_keys); /** * sec_prot_keys_pmk_replay_cnt_compare compares received replay counter value to PMK replay counter @@ -269,23 +317,23 @@ bool sec_prot_keys_pmk_mismatch_is_set(sec_prot_keys_t *sec_keys); * sec_prot_keys_pmk_lifetime_decrement decrements PMK lifetime * * \param sec_keys security keys - * \param default_lifetime default lifetime for PMK * \param seconds elapsed seconds * * \return true PMK expired and deleted both PMK and PTK * \return false PMK not expired * */ -bool sec_prot_keys_pmk_lifetime_decrement(sec_prot_keys_t *sec_keys, uint32_t default_lifetime, uint8_t seconds); +bool sec_prot_keys_pmk_lifetime_decrement(sec_prot_keys_t *sec_keys, uint8_t seconds); /** * sec_prot_keys_ptk_write writes Pairwise Transient Key * * \param sec_keys security keys * \param ptk Pairwise Transient Key + * \param ptk_lifetime PTK lifetime * */ -void sec_prot_keys_ptk_write(sec_prot_keys_t *sec_keys, uint8_t *ptk); +void sec_prot_keys_ptk_write(sec_prot_keys_t *sec_keys, uint8_t *ptk, uint32_t ptk_lifetime); /** * sec_prot_keys_ptk_delete deletes PTK @@ -305,6 +353,16 @@ void sec_prot_keys_ptk_delete(sec_prot_keys_t *sec_keys); */ uint8_t *sec_prot_keys_ptk_get(sec_prot_keys_t *sec_keys); +/** + * sec_prot_keys_ptk_lifetime_get gets Pairwise Transient Key lifetime + * + * \param sec_keys security keys + * + * \return PTK lifetime + * + */ +uint32_t sec_prot_keys_ptk_lifetime_get(sec_prot_keys_t *sec_keys); + /** * sec_prot_keys_ptk_mismatch_set set PTK mismatch * @@ -362,14 +420,13 @@ void sec_prot_keys_ptk_eui_64_delete(sec_prot_keys_t *sec_keys); * sec_prot_keys_ptk_lifetime_decrement decrements PTK lifetime * * \param sec_keys security keys - * \param default_lifetime default lifetime for PTK * \param seconds elapsed seconds * * \return true PTK expired and deleted * \return false PTK not expired * */ -bool sec_prot_keys_ptk_lifetime_decrement(sec_prot_keys_t *sec_keys, uint32_t default_lifetime, uint8_t seconds); +bool sec_prot_keys_ptk_lifetime_decrement(sec_prot_keys_t *sec_keys, uint8_t seconds); /** * sec_prot_keys_are_updated returns security keys have been updated flag @@ -556,12 +613,38 @@ uint32_t sec_prot_keys_gtk_lifetime_get(sec_prot_gtk_keys_t *gtks, uint8_t index * * \param gtks GTK keys * \param index index for GTK + * \param current_time current timestamp * \param seconds elapsed seconds * * \return new GTK lifetime * */ -uint32_t sec_prot_keys_gtk_lifetime_decrement(sec_prot_gtk_keys_t *gtks, uint8_t index, uint16_t seconds); +uint32_t sec_prot_keys_gtk_lifetime_decrement(sec_prot_gtk_keys_t *gtks, uint8_t index, uint64_t current_time, uint16_t seconds); + +/** + * sec_prot_keys_gtk_exptime_from_lifetime_get converts GTK lifetime to expiry time. + * + * \param gtks GTK keys + * \param index index for GTK + * \param current_time current time + * + * \return expiry time + * + */ +uint64_t sec_prot_keys_gtk_exptime_from_lifetime_get(sec_prot_gtk_keys_t *gtks, uint8_t index, uint64_t current_time); + +/** + * sec_prot_keys_gtk_expirytime_set sets GTK expiry time + * + * \param gtks GTK keys + * \param index index for GTK + * \param expirytime expiry time + * + * \return < 0 failure + * \return >= 0 success + * + */ +int8_t sec_prot_keys_gtk_expirytime_set(sec_prot_gtk_keys_t *gtks, uint8_t index, uint64_t expirytime); /** * sec_prot_keys_gtks_are_updated returns GTKs have been updated flag @@ -631,6 +714,17 @@ int8_t sec_prot_keys_gtk_status_active_set(sec_prot_gtk_keys_t *gtks, uint8_t in */ int8_t sec_prot_keys_gtk_status_active_get(sec_prot_gtk_keys_t *gtks); +/** + * sec_prot_keys_gtk_status_active_to_fresh_set sets active GTK to fresh GTK + * + * \param gtks GTK keys + * + * \return < 0 failure + * \return >= 0 success + * + */ +int8_t sec_prot_keys_gtk_status_active_to_fresh_set(sec_prot_gtk_keys_t *gtks); + /** * sec_prot_keys_gtk_status_is_live checks whether GTK is active * @@ -642,6 +736,30 @@ int8_t sec_prot_keys_gtk_status_active_get(sec_prot_gtk_keys_t *gtks); */ bool sec_prot_keys_gtk_status_is_live(sec_prot_gtk_keys_t *gtks, uint8_t index); +/** + * sec_prot_keys_gtk_status_get gets GTK status + * + * \param gtks GTK keys + * \param index index + * + * \return GTK status + * + */ +uint8_t sec_prot_keys_gtk_status_get(sec_prot_gtk_keys_t *gtks, uint8_t index); + +/** + * sec_prot_keys_gtk_status_get sets GTK status + * + * \param gtks GTK keys + * \param index index + * \param status status + * + * \return < 0 failure + * \return >= 0 success + * + */ +int8_t sec_prot_keys_gtk_status_set(sec_prot_gtk_keys_t *gtks, uint8_t index, uint8_t status); + /** * sec_prot_keys_gtks_hash_generate generate GTK hash based on all GTKs * @@ -761,6 +879,30 @@ void sec_prot_keys_gtk_install_order_update(sec_prot_gtk_keys_t *gtks); */ int8_t sec_prot_keys_gtk_install_index_get(sec_prot_gtk_keys_t *gtks); +/** + * sec_prot_keys_gtk_install_order_get gets GTK install order + * + * \param gtks GTK keys + * \param index index + * + * \return GTK install order + * + */ +uint8_t sec_prot_keys_gtk_install_order_get(sec_prot_gtk_keys_t *gtks, uint8_t gtk_index); + +/** + * sec_prot_keys_gtk_install_order_set sets GTK install order + * + * \param gtks GTK keys + * \param index index + * \param install_order GTK install order + * + * \return < 0 failure + * \return >= 0 success + * + */ +int8_t sec_prot_keys_gtk_install_order_set(sec_prot_gtk_keys_t *gtks, uint8_t gtk_index, uint8_t install_order); + /** * sec_prot_keys_gtk_count counts GTK keys * @@ -784,9 +926,10 @@ void sec_prot_keys_ptk_installed_gtk_hash_clear_all(sec_prot_keys_t *sec_keys); * to supplicant using the current PTK * * \param sec_keys security keys + * \param is_4wh set by 4WH * */ -void sec_prot_keys_ptk_installed_gtk_hash_set(sec_prot_keys_t *sec_keys); +void sec_prot_keys_ptk_installed_gtk_hash_set(sec_prot_keys_t *sec_keys, bool is_4wh); /** * sec_prot_keys_ptk_installed_gtk_hash_set check if PTK is being used to store new GTK for the index diff --git a/source/Security/protocols/sec_prot_lib.c b/source/Security/protocols/sec_prot_lib.c index 0987054d6b..1df7d5dac3 100644 --- a/source/Security/protocols/sec_prot_lib.c +++ b/source/Security/protocols/sec_prot_lib.c @@ -274,6 +274,12 @@ int8_t sec_prot_lib_ptk_calc(const uint8_t *pmk, const uint8_t *eui64_1, const u memcpy(ptk, result, PTK_LEN); +#ifdef EXTRA_DEBUG_INFO + tr_debug("PTK EUI: %s %s", trace_array(eui64_1, 8), trace_array(eui64_2, 8)); + tr_debug("PTK NONCE: %s %s", trace_array(nonce1, 32), trace_array(nonce2, 32)); + tr_debug("PTK: %s:%s", trace_array(ptk, PTK_LEN / 2), trace_array(ptk + PTK_LEN / 2, PTK_LEN / 2)); +#endif + return 0; } @@ -469,7 +475,7 @@ int8_t sec_prot_lib_ptkid_generate(sec_prot_t *prot, uint8_t *ptkid, bool is_aut { uint8_t local_eui64[8]; prot->addr_get(prot, local_eui64, NULL); - uint8_t *ptk = sec_prot_keys_pmk_get(prot->sec_keys); + uint8_t *ptk = sec_prot_keys_ptk_get(prot->sec_keys); if (!ptk) { return -1; } @@ -524,7 +530,10 @@ uint8_t *sec_prot_remote_eui_64_addr_get(sec_prot_t *prot) if (prot->sec_keys && prot->sec_keys->ptk_eui_64_set) { return prot->sec_keys->ptk_eui_64; } else { - return NULL; + static uint8_t remote_eui64[8]; + memset(remote_eui64, 0, 8); + prot->addr_get(prot, NULL, (uint8_t *) &remote_eui64); + return remote_eui64; } } diff --git a/source/Security/protocols/tls_sec_prot/tls_sec_prot.c b/source/Security/protocols/tls_sec_prot/tls_sec_prot.c index ad07fd1ca1..d4b8c549ae 100644 --- a/source/Security/protocols/tls_sec_prot/tls_sec_prot.c +++ b/source/Security/protocols/tls_sec_prot/tls_sec_prot.c @@ -69,15 +69,20 @@ typedef struct { bool timer_running : 1; /**< TLS timer running */ bool finished : 1; /**< TLS finished */ bool calculating : 1; /**< TLS is calculating */ +#ifdef SERVER_TLS_EC_CALC_QUEUE bool queued : 1; /**< TLS is queued */ +#endif bool library_init : 1; /**< TLS library has been initialized */ tls_sec_prot_lib_int_t *tls_sec_inst; /**< TLS security library storage, SHALL BE THE LAST FIELD */ } tls_sec_prot_int_t; +// TLS server EC queue is currently disabled, since EC calculation is made on server in one go +#ifdef SERVER_TLS_EC_CALC_QUEUE typedef struct { ns_list_link_t link; /**< Link */ sec_prot_t *prot; /**< Protocol instance */ } tls_sec_prot_queue_t; +#endif static uint16_t tls_sec_prot_size(void); static int8_t client_tls_sec_prot_init(sec_prot_t *prot); @@ -102,15 +107,22 @@ static int8_t tls_sec_prot_tls_get_timer(void *handle); static int8_t tls_sec_prot_tls_configure_and_connect(sec_prot_t *prot, bool is_server); +#ifdef SERVER_TLS_EC_CALC_QUEUE static bool tls_sec_prot_queue_check(sec_prot_t *prot); static bool tls_sec_prot_queue_process(sec_prot_t *prot); static void tls_sec_prot_queue_remove(sec_prot_t *prot); +#else +#define tls_sec_prot_queue_process(prot) true +#define tls_sec_prot_queue_remove(prot) +#endif /* SERVER_TLS_EC_CALC_QUEUE */ static uint16_t tls_sec_prot_send_buffer_size_get(sec_prot_t *prot); #define tls_sec_prot_get(prot) (tls_sec_prot_int_t *) &prot->data +#ifdef SERVER_TLS_EC_CALC_QUEUE static NS_LIST_DEFINE(tls_sec_prot_queue, tls_sec_prot_queue_t, link); +#endif int8_t client_tls_sec_prot_register(kmp_service_t *service) { @@ -168,7 +180,9 @@ static int8_t client_tls_sec_prot_init(sec_prot_t *prot) data->fin_timer_timeout = false; data->timer_running = false; data->calculating = false; +#ifdef SERVER_TLS_EC_CALC_QUEUE data->queued = false; +#endif data->library_init = false; return 0; } @@ -198,7 +212,9 @@ static int8_t server_tls_sec_prot_init(sec_prot_t *prot) data->fin_timer_timeout = false; data->timer_running = false; data->calculating = false; +#ifdef SERVER_TLS_EC_CALC_QUEUE data->queued = false; +#endif data->library_init = false; return 0; } @@ -281,7 +297,11 @@ static void tls_sec_prot_timer_timeout(sec_prot_t *prot, uint16_t ticks) if (data->fin_timer_timeout) { data->fin_timer_timeout = false; prot->state_machine(prot); - } else if (data->calculating || data->queued) { + } else if (data->calculating +#ifdef SERVER_TLS_EC_CALC_QUEUE + || data->queued +#endif + ) { prot->state_machine(prot); } } @@ -355,7 +375,7 @@ static void client_tls_sec_prot_state_machine(sec_prot_t *prot) data->calculating = false; if (sec_prot_result_ok_check(&data->common)) { - sec_prot_keys_pmk_write(prot->sec_keys, data->new_pmk); + sec_prot_keys_pmk_write(prot->sec_keys, data->new_pmk, prot->timer_cfg->pmk_lifetime); } // KMP-FINISHED.indication, @@ -385,7 +405,9 @@ static void server_tls_sec_prot_state_machine(sec_prot_t *prot) { tls_sec_prot_int_t *data = tls_sec_prot_get(prot); int8_t result; +#ifdef SERVER_TLS_EC_CALC_QUEUE bool client_hello = false; +#endif switch (sec_prot_state_get(&data->common)) { case TLS_STATE_INIT: @@ -400,7 +422,9 @@ static void server_tls_sec_prot_state_machine(sec_prot_t *prot) case TLS_STATE_CLIENT_HELLO: tr_debug("TLS: start, eui-64: %s", trace_array(sec_prot_remote_eui_64_addr_get(prot), 8)); +#ifdef SERVER_TLS_EC_CALC_QUEUE client_hello = true; +#endif sec_prot_state_set(prot, &data->common, TLS_STATE_CREATE_RESP); @@ -430,6 +454,7 @@ static void server_tls_sec_prot_state_machine(sec_prot_t *prot) break; case TLS_STATE_PROCESS: +#ifdef SERVER_TLS_EC_CALC_QUEUE // If not client hello, reserves slot on TLS queue if (!client_hello && !tls_sec_prot_queue_check(prot)) { data->queued = true; @@ -437,6 +462,7 @@ static void server_tls_sec_prot_state_machine(sec_prot_t *prot) } else { data->queued = false; } +#endif result = tls_sec_prot_lib_process((tls_security_t *) &data->tls_sec_inst); @@ -468,7 +494,7 @@ static void server_tls_sec_prot_state_machine(sec_prot_t *prot) data->calculating = false; if (sec_prot_result_ok_check(&data->common)) { - sec_prot_keys_pmk_write(prot->sec_keys, data->new_pmk); + sec_prot_keys_pmk_write(prot->sec_keys, data->new_pmk, prot->timer_cfg->pmk_lifetime); } // KMP-FINISHED.indication, @@ -636,6 +662,7 @@ static int8_t tls_sec_prot_tls_configure_and_connect(sec_prot_t *prot, bool is_s return 0; } +#ifdef SERVER_TLS_EC_CALC_QUEUE static bool tls_sec_prot_queue_check(sec_prot_t *prot) { bool queue_add = true; @@ -703,6 +730,7 @@ static void tls_sec_prot_queue_remove(sec_prot_t *prot) } } } +#endif static uint16_t tls_sec_prot_send_buffer_size_get(sec_prot_t *prot) { diff --git a/source/Service_Libs/etx/etx.c b/source/Service_Libs/etx/etx.c index 639490981a..76b7c7d203 100644 --- a/source/Service_Libs/etx/etx.c +++ b/source/Service_Libs/etx/etx.c @@ -37,9 +37,14 @@ #define TRACE_GROUP "etx" +typedef struct { + uint8_t attribute_index; + const uint8_t *mac64; +} ext_neigh_info_t; + static uint16_t etx_current_calc(uint16_t etx, uint8_t accumulated_failures); static uint16_t etx_dbm_lqi_calc(uint8_t lqi, int8_t dbm); -static void etx_value_change_callback_needed_check(uint16_t etx, uint16_t *stored_diff_etx, uint8_t accumulated_failures, uint8_t attribute_index); +static void etx_value_change_callback_needed_check(uint16_t etx, uint16_t *stored_diff_etx, uint8_t accumulated_failures, ext_neigh_info_t *etx_neigh_info); static void etx_accum_failures_callback_needed_check(etx_storage_t *entry, uint8_t attribute_index); static void etx_cache_entry_init(uint8_t attribute_index); @@ -90,7 +95,7 @@ static ext_info_t etx_info = { .interface_id = -1 }; -static void etx_calculation(etx_storage_t *entry, uint16_t attempts, uint8_t acks_rx, uint8_t attribute_index) +static void etx_calculation(etx_storage_t *entry, uint16_t attempts, uint8_t acks_rx, ext_neigh_info_t *etx_neigh_info) { if (etx_info.hysteresis && !entry->stored_diff_etx) { if (entry->etx_samples >= etx_info.init_etx_sample_count) { @@ -130,9 +135,9 @@ static void etx_calculation(etx_storage_t *entry, uint16_t attempts, uint8_t ack entry->etx = etx; if (entry->etx_samples >= etx_info.init_etx_sample_count) { - etx_cache_entry_init(attribute_index); + etx_cache_entry_init(etx_neigh_info->attribute_index); // Checks if ETX value change callback is needed - etx_value_change_callback_needed_check(entry->etx, &(entry->stored_diff_etx), entry->accumulated_failures, attribute_index); + etx_value_change_callback_needed_check(entry->etx, &(entry->stored_diff_etx), entry->accumulated_failures, etx_neigh_info); } } @@ -203,7 +208,7 @@ static etx_sample_storage_t *etx_cache_sample_update(uint8_t attribute_index, ui * \param addr_type address type, ADDR_802_15_4_SHORT or ADDR_802_15_4_LONG * \param addr_ptr PAN ID with 802.15.4 address */ -void etx_transm_attempts_update(int8_t interface_id, uint8_t attempts, bool success, uint8_t attribute_index) +void etx_transm_attempts_update(int8_t interface_id, uint8_t attempts, bool success, uint8_t attribute_index, const uint8_t *mac64_addr_ptr) { uint8_t accumulated_failures; // Gets table entry @@ -212,6 +217,10 @@ void etx_transm_attempts_update(int8_t interface_id, uint8_t attempts, bool succ return; } + ext_neigh_info_t etx_neigh_info; + etx_neigh_info.attribute_index = attribute_index; + etx_neigh_info.mac64 = mac64_addr_ptr; + if (entry->etx_samples < 7) { entry->etx_samples++; } @@ -225,7 +234,7 @@ void etx_transm_attempts_update(int8_t interface_id, uint8_t attempts, bool succ return; } - etx_calculation(entry, storage->attempts_count, storage->received_acks, attribute_index); + etx_calculation(entry, storage->attempts_count, storage->received_acks, &etx_neigh_info); if (entry->etx_samples < 7 && !success) { entry->etx_samples = 7; //Stop Probing to failure @@ -254,7 +263,7 @@ void etx_transm_attempts_update(int8_t interface_id, uint8_t attempts, bool succ if (entry->etx) { if (success) { - etx_calculation(entry, attempts + accumulated_failures, 1, attribute_index); + etx_calculation(entry, attempts + accumulated_failures, 1, &etx_neigh_info); } } } @@ -268,35 +277,42 @@ void etx_transm_attempts_update(int8_t interface_id, uint8_t attempts, bool succ * \param remote_incoming_idr Remote incoming IDR * \param mac64_addr_ptr long MAC address */ -void etx_remote_incoming_idr_update(int8_t interface_id, uint8_t remote_incoming_idr, uint8_t attribute_index) +void etx_remote_incoming_idr_update(int8_t interface_id, uint8_t remote_incoming_idr, uint8_t attribute_index, const uint8_t *mac64_addr_ptr) { etx_storage_t *entry = etx_storage_entry_get(interface_id, attribute_index); - - if (entry) { - // If ETX has been set - if (entry->etx) { - // If hysteresis is set stores ETX value to enable comparison - if (etx_info.hysteresis && !entry->stored_diff_etx) { - entry->stored_diff_etx = entry->etx; - } - // remote EXT = remote incoming IDR^2 (12 bit fraction) - uint32_t remote_ext = ((uint32_t)remote_incoming_idr * remote_incoming_idr) << 2; - - // ETX = 7/8 * current ETX + 1/8 * remote ETX */ - uint32_t etx = entry->etx - (entry->etx >> ETX_MOVING_AVERAGE_FRACTION); - etx += remote_ext >> ETX_MOVING_AVERAGE_FRACTION; - - if (etx > 0xffff) { - entry->etx = 0xffff; - } else { - entry->etx = etx; - } - - // Checks if ETX value change callback is needed - etx_value_change_callback_needed_check(entry->etx, &(entry->stored_diff_etx), entry->accumulated_failures, attribute_index); - } - entry->remote_incoming_idr = remote_incoming_idr; + if (!entry) { + return; } + + ext_neigh_info_t etx_neigh_info; + etx_neigh_info.attribute_index = attribute_index; + etx_neigh_info.mac64 = mac64_addr_ptr; + + + // If ETX has been set + if (entry->etx) { + // If hysteresis is set stores ETX value to enable comparison + if (etx_info.hysteresis && !entry->stored_diff_etx) { + entry->stored_diff_etx = entry->etx; + } + // remote EXT = remote incoming IDR^2 (12 bit fraction) + uint32_t remote_ext = ((uint32_t)remote_incoming_idr * remote_incoming_idr) << 2; + + // ETX = 7/8 * current ETX + 1/8 * remote ETX */ + uint32_t etx = entry->etx - (entry->etx >> ETX_MOVING_AVERAGE_FRACTION); + etx += remote_ext >> ETX_MOVING_AVERAGE_FRACTION; + + if (etx > 0xffff) { + entry->etx = 0xffff; + } else { + entry->etx = etx; + } + + // Checks if ETX value change callback is needed + etx_value_change_callback_needed_check(entry->etx, &(entry->stored_diff_etx), entry->accumulated_failures, &etx_neigh_info); + } + entry->remote_incoming_idr = remote_incoming_idr; + } /** @@ -442,14 +458,18 @@ static uint16_t etx_current_calc(uint16_t etx, uint8_t accumulated_failures) * * \return 0x0100 to 0xFFFF local incoming IDR value (8 bit fraction) */ -uint16_t etx_lqi_dbm_update(int8_t interface_id, uint8_t lqi, int8_t dbm, uint8_t attribute_index) +uint16_t etx_lqi_dbm_update(int8_t interface_id, uint8_t lqi, int8_t dbm, uint8_t attribute_index, const uint8_t *mac64_addr_ptr) { uint32_t local_incoming_idr = 0; uint32_t etx = 0; etx_storage_t *entry = etx_storage_entry_get(interface_id, attribute_index); + if (entry) { + ext_neigh_info_t etx_neigh_info; + etx_neigh_info.attribute_index = attribute_index; + etx_neigh_info.mac64 = mac64_addr_ptr; // If local ETX is not set calculate it based on LQI and dBm if (!entry->etx) { etx = etx_dbm_lqi_calc(lqi, dbm); @@ -458,7 +478,7 @@ uint16_t etx_lqi_dbm_update(int8_t interface_id, uint8_t lqi, int8_t dbm, uint8_ entry->tmp_etx = true; if (etx_info.callback_ptr) { etx_info.callback_ptr(etx_info.interface_id, 0, entry->etx >> 4, - attribute_index); + attribute_index, mac64_addr_ptr); } } // If local ETX has been calculated without remote incoming IDR and @@ -474,7 +494,7 @@ uint16_t etx_lqi_dbm_update(int8_t interface_id, uint8_t lqi, int8_t dbm, uint8_ entry->etx = etx >> 12; local_incoming_idr >>= 4; - etx_value_change_callback_needed_check(entry->etx, &(entry->stored_diff_etx), entry->accumulated_failures, attribute_index); + etx_value_change_callback_needed_check(entry->etx, &(entry->stored_diff_etx), entry->accumulated_failures, &etx_neigh_info); } } @@ -721,7 +741,7 @@ uint8_t etx_accum_failures_callback_register(nwk_interface_id nwk_id, int8_t int * * \return ETX value (12 bit fraction) */ -static void etx_value_change_callback_needed_check(uint16_t etx, uint16_t *stored_diff_etx, uint8_t accumulated_failures, uint8_t attribute_index) +static void etx_value_change_callback_needed_check(uint16_t etx, uint16_t *stored_diff_etx, uint8_t accumulated_failures, ext_neigh_info_t *etx_neigh_info) { uint16_t current_etx; bool callback = false; @@ -747,7 +767,7 @@ static void etx_value_change_callback_needed_check(uint16_t etx, uint16_t *store // Calls callback function if (callback) { - etx_info.callback_ptr(etx_info.interface_id, (*stored_diff_etx) >> 4, current_etx >> 4, attribute_index); + etx_info.callback_ptr(etx_info.interface_id, (*stored_diff_etx) >> 4, current_etx >> 4, etx_neigh_info->attribute_index, etx_neigh_info->mac64); *stored_diff_etx = current_etx; } } @@ -782,7 +802,7 @@ static void etx_accum_failures_callback_needed_check(etx_storage_t *entry, uint8 * \param mac64_addr_ptr long MAC address * */ -void etx_neighbor_remove(int8_t interface_id, uint8_t attribute_index) +void etx_neighbor_remove(int8_t interface_id, uint8_t attribute_index, const uint8_t *mac64_addr_ptr) { //tr_debug("Remove attribute %u", attribute_index); @@ -795,7 +815,8 @@ void etx_neighbor_remove(int8_t interface_id, uint8_t attribute_index) if (!stored_diff_etx) { stored_diff_etx = 0xffff; } - etx_info.callback_ptr(etx_info.interface_id, stored_diff_etx, 0xffff, attribute_index); + + etx_info.callback_ptr(etx_info.interface_id, stored_diff_etx, 0xffff, attribute_index, mac64_addr_ptr); } if (etx_info.cache_sample_requested) { @@ -829,7 +850,10 @@ void etx_cache_timer(int8_t interface_id, uint16_t seconds_update) etx_sample_storage_t *storage = etx_info.etx_cache_storage_list + neighbour->index; if (etx_update_possible(storage, etx_entry, seconds_update)) { - etx_calculation(etx_entry, storage->attempts_count, storage->received_acks, neighbour->index); + ext_neigh_info_t etx_neigh_info; + etx_neigh_info.attribute_index = neighbour->index; + etx_neigh_info.mac64 = neighbour->mac64; + etx_calculation(etx_entry, storage->attempts_count, storage->received_acks, &etx_neigh_info); } } diff --git a/source/Service_Libs/etx/etx.h b/source/Service_Libs/etx/etx.h index c785cc5c98..a1c40b2694 100644 --- a/source/Service_Libs/etx/etx.h +++ b/source/Service_Libs/etx/etx.h @@ -76,8 +76,9 @@ typedef struct etx_sample_storage_s { * \param attempts number of attempts to send message * \param success was message sending successful * \param attribute_index Neighbour attribute index + * \param mac64_addr_ptr Neighbour MAC64 */ -void etx_transm_attempts_update(int8_t interface_id, uint8_t attempts, bool success, uint8_t attribute_index); +void etx_transm_attempts_update(int8_t interface_id, uint8_t attempts, bool success, uint8_t attribute_index, const uint8_t *mac64_addr_ptr); /** * \brief A function to update ETX value based on remote incoming IDR @@ -88,8 +89,9 @@ void etx_transm_attempts_update(int8_t interface_id, uint8_t attempts, bool succ * \param interface_id Interface identifier * \param remote_incoming_idr Remote incoming IDR * \param attribute_index Neighbour attribute index + * \param mac64_addr_ptr Neighbour MAC64 */ -void etx_remote_incoming_idr_update(int8_t interface_id, uint8_t remote_incoming_idr, uint8_t attribute_index); +void etx_remote_incoming_idr_update(int8_t interface_id, uint8_t remote_incoming_idr, uint8_t attribute_index, const uint8_t *mac64_addr_ptr); /** * \brief A function to read ETX value @@ -139,10 +141,11 @@ uint16_t etx_local_etx_read(int8_t interface_id, uint8_t attribute_index); * \param lqi link quality indicator * \param dbm measured dBm * \param attribute_index Neighbour attribute index + * \param mac64_addr_ptr Neighbour MAC64 * * \return 0x0100 to 0xFFFF local incoming IDR value (8 bit fraction) */ -uint16_t etx_lqi_dbm_update(int8_t interface_id, uint8_t lqi, int8_t dbm, uint8_t attribute_index); +uint16_t etx_lqi_dbm_update(int8_t interface_id, uint8_t lqi, int8_t dbm, uint8_t attribute_index, const uint8_t *mac64_addr_ptr); /** * \brief A function callback that indicates ETX value change @@ -154,9 +157,10 @@ uint16_t etx_lqi_dbm_update(int8_t interface_id, uint8_t lqi, int8_t dbm, uint8_ * \param previous_etx ETX value to what the current ETX was compared (8 bit fraction) * \param current_etx current ETX value (8 bit fraction) * \param attribute_index Neighbour attribute index + * \param mac64_addr_ptr Pointer to MAC64 for given etx update * */ -typedef void (etx_value_change_handler_t)(int8_t nwk_id, uint16_t previous_etx, uint16_t current_etx, uint8_t attribute_index); +typedef void (etx_value_change_handler_t)(int8_t nwk_id, uint16_t previous_etx, uint16_t current_etx, uint8_t attribute_index, const uint8_t *mac64_addr_ptr); /** * \brief A function callback that indicates the number of accumulated TX failures @@ -232,9 +236,10 @@ uint8_t etx_accum_failures_callback_register(nwk_interface_id nwk_id, int8_t int * if that is set. * * \param attribute_index Neighbour attribute index + * \param mac64_addr_ptr Neighbour MAC64 * */ -void etx_neighbor_remove(int8_t interface_id, uint8_t attribute_index); +void etx_neighbor_remove(int8_t interface_id, uint8_t attribute_index, const uint8_t *mac64_addr_ptr); /** * \brief A function for update cached ETX calculation diff --git a/source/Service_Libs/fhss/fhss_test_api.c b/source/Service_Libs/fhss/fhss_test_api.c index 7b1e696ea0..02e63af682 100644 --- a/source/Service_Libs/fhss/fhss_test_api.c +++ b/source/Service_Libs/fhss/fhss_test_api.c @@ -44,3 +44,18 @@ int8_t fhss_set_optimal_packet_length(const fhss_api_t *fhss_api, uint16_t packe #endif return 0; } + +int8_t fhss_set_number_of_channel_retries(const fhss_api_t *fhss_api, uint8_t number_of_channel_retries) +{ + (void) fhss_api; + (void) number_of_channel_retries; +#ifdef HAVE_WS + fhss_structure_t *fhss_structure = fhss_get_object_with_api(fhss_api); + if (!fhss_structure || !fhss_structure->ws) { + return -1; + } + fhss_structure->ws->fhss_configuration.config_parameters.number_of_channel_retries = number_of_channel_retries; + tr_debug("Setting number of channel retries to: %u", number_of_channel_retries); +#endif + return 0; +} diff --git a/source/Service_Libs/fhss/fhss_ws.c b/source/Service_Libs/fhss/fhss_ws.c index 1d29e70c2a..80c3f90d14 100644 --- a/source/Service_Libs/fhss/fhss_ws.c +++ b/source/Service_Libs/fhss/fhss_ws.c @@ -750,16 +750,18 @@ static bool fhss_ws_data_tx_fail_callback(const fhss_api_t *api, uint8_t handle, if (fhss_structure->fhss_state == FHSS_UNSYNCHRONIZED) { return false; } - // Use channel retries only for data frames if (FHSS_DATA_FRAME != frame_type) { return false; } - + // Channel retries are disabled + if (!fhss_structure->ws->fhss_configuration.config_parameters.number_of_channel_retries) { + return false; + } fhss_failed_tx_t *fhss_failed_tx = fhss_failed_handle_find(fhss_structure, handle); if (fhss_failed_tx) { fhss_failed_tx->retries_done++; - if (fhss_failed_tx->retries_done >= WS_NUMBER_OF_CHANNEL_RETRIES) { + if (fhss_failed_tx->retries_done >= fhss_structure->ws->fhss_configuration.config_parameters.number_of_channel_retries) { // No more retries. Return false to stop retransmitting. fhss_failed_handle_remove(fhss_structure, handle); return false; @@ -966,6 +968,19 @@ int fhss_ws_configuration_set(fhss_structure_t *fhss_structure, const fhss_ws_co if (channel_count <= 0) { return -1; } + + if (fhss_structure->number_of_channels < channel_count || + (channel_count_uc && fhss_structure->number_of_uc_channels < channel_count_uc)) { + // Channel amount changed to largeneed to reallocate channel table + ns_dyn_mem_free(fhss_structure->ws->tr51_channel_table); + fhss_structure->ws->tr51_channel_table = NULL; + ns_dyn_mem_free(fhss_structure->ws->tr51_output_table); + fhss_structure->ws->tr51_output_table = NULL; + + if (fhss_ws_manage_channel_table_allocation(fhss_structure, channel_count_uc > channel_count ? channel_count_uc : channel_count)) { + return -1; + } + } platform_enter_critical(); if (fhss_configuration->ws_uc_channel_function == WS_FIXED_CHANNEL || fhss_configuration->fhss_uc_dwell_interval == 0) { fhss_stop_timer(fhss_structure, fhss_unicast_handler); diff --git a/source/Service_Libs/fhss/fhss_ws.h b/source/Service_Libs/fhss/fhss_ws.h index c3d31fa67e..f4d27c1bff 100644 --- a/source/Service_Libs/fhss/fhss_ws.h +++ b/source/Service_Libs/fhss/fhss_ws.h @@ -17,10 +17,6 @@ #ifndef FHSS_WS_H_ #define FHSS_WS_H_ -/* WS requires at least 19 MAC retransmissions (total 1+19=20 attempts). 802.15.4 macMaxFrameRetries is 3 (total 1+3=4 attempts). - * At least 4 channel retries must be used: (Initial channel + WS_NUMBER_OF_CHANNEL_RETRIES) * MAC attempts = (1+4)*4=20 attempts - */ -#define WS_NUMBER_OF_CHANNEL_RETRIES 4 // TX slot length is optimised to this packet length #define OPTIMAL_PACKET_LENGTH 500 // Default TX/RX slot length in milliseconds. Is used when datarate is not given by PHY. diff --git a/source/Service_Libs/mac_neighbor_table/mac_neighbor_table.c b/source/Service_Libs/mac_neighbor_table/mac_neighbor_table.c index 3f1960fb5b..1969159277 100644 --- a/source/Service_Libs/mac_neighbor_table/mac_neighbor_table.c +++ b/source/Service_Libs/mac_neighbor_table/mac_neighbor_table.c @@ -101,6 +101,10 @@ void mac_neighbor_table_neighbor_timeout_update(mac_neighbor_table_t *table_clas ns_list_foreach_safe(mac_neighbor_table_entry_t, cur, &table_class->neighbour_list) { if (cur->lifetime > time_update) { + if (cur->lifetime == 0xffffffff && cur->link_lifetime == 0xffffffff) { + continue; //Infinite Lifetime too not touch + } + cur->lifetime -= time_update; if (!table_class->user_nud_notify_cb || table_class->active_nud_process > ACTIVE_NUD_PROCESS_MAX || cur->nud_active || !cur->rx_on_idle) { continue; diff --git a/source/Service_Libs/mdns/fnet/fnet_stack/port/compiler/fnet_comp_config.h b/source/Service_Libs/mdns/fnet/fnet_stack/port/compiler/fnet_comp_config.h index cf878c5aa1..81732fbf62 100644 --- a/source/Service_Libs/mdns/fnet/fnet_stack/port/compiler/fnet_comp_config.h +++ b/source/Service_Libs/mdns/fnet/fnet_stack/port/compiler/fnet_comp_config.h @@ -94,10 +94,6 @@ #elif defined(__clang__) #define FNET_CFG_COMP_CLANG (1) #define FNET_COMP_STR "CLANG" - /* Keil uVision compiler using armcc. */ - #elif defined(__CC_ARM) - #define FNET_CFG_COMP_UV (1) - #define FNET_COMP_STR "UV" /* GNU GCC */ #elif defined(__GNUC__) #define FNET_CFG_COMP_GNUC (1) diff --git a/source/Service_Libs/utils/ns_conf.c b/source/Service_Libs/utils/ns_conf.c index 54ebbbe8a8..93de03ce43 100644 --- a/source/Service_Libs/utils/ns_conf.c +++ b/source/Service_Libs/utils/ns_conf.c @@ -29,5 +29,5 @@ int ns_conf_gc_threshold_set(uint8_t percentage_high, uint8_t percentage_critica int ns_conf_packet_ingress_rate_limit_by_mem(uint8_t free_heap_percentage) { - return mcps_packet_ingress_rate_limit_by_memory(free_heap_percentage); + return ns_monitor_packet_ingress_rate_limit_by_memory(free_heap_percentage); } diff --git a/source/Service_Libs/utils/ns_file.h b/source/Service_Libs/utils/ns_file.h new file mode 100644 index 0000000000..8ba32133a6 --- /dev/null +++ b/source/Service_Libs/utils/ns_file.h @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2017, Arm Limited and affiliates. + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _NS_FILE_H_ +#define _NS_FILE_H_ + +/** + * \file ns_file.h + * \brief Nanostack file handling API. + */ + +#include "ns_file_system.h" + +/** + * File open + * + * Depending on underlying file system file open for read for non-existing + * files can return success. In that case file read will fail. + * + * \param filename filename + * \param mode can be either "r" or "w" + * + * \return file handle + * \return NULL on error + * + */ +NS_FILE ns_fopen(const char *filename, const char *mode); + +/** + * File close + * + * \param handle file handle + * + * \return 0 on success + * \return < 0 in case of errors + * + */ +int ns_fclose(NS_FILE *ns_handle); + +/** + * File remove + * + * \param filename filename + * + * \return 0 on success + * \return < 0 in case of errors + * + */ +int ns_fremove(const char *filename); + +/** + * File write + * + * Write is not stream write. The whole file is written from start to end + * and if function is called again, previous file content is replaced with + * new content. + * + * \param handle file handle + * \param buffer buffer + * \param buffer buffer size + * + * \return bytes written + * + */ +size_t ns_fwrite(NS_FILE *ns_handle, const void *buffer, size_t size); + +/** + * File read + * + * Read is not stream read. The whole file is read from start to end + * and if function is called again, read is started from start again. + * + * \param handle file handle + * \param buffer buffer + * \param size buffer size + * + * \return bytes written + * + */ +size_t ns_fread(NS_FILE *ns_handle, void *buffer, size_t size); + +/** + * File size callback + * + * Reads file size. + * + * \param handle file handle + * \param size file size + * + * \return 0 on success + * \return < 0 in case of reading file size is not supported + * + */ +int ns_fsize(NS_FILE *ns_handle, size_t *size); + +#endif /* _NS_FILE_SYSTEM_H_ */ diff --git a/source/Service_Libs/utils/ns_file_system.c b/source/Service_Libs/utils/ns_file_system.c index 5ea3cca5fd..a7202ccdd0 100644 --- a/source/Service_Libs/utils/ns_file_system.c +++ b/source/Service_Libs/utils/ns_file_system.c @@ -16,12 +16,21 @@ */ #include +#include #include "ns_types.h" #include "nsdynmemLIB.h" #include "ns_file_system.h" +#include "ns_file.h" static char *file_system_root; +static ns_file_open file_open_cb = NULL; +static ns_file_close file_close_cb = NULL; +static ns_file_remove file_remove_cb = NULL; +static ns_file_write file_write_cb = NULL; +static ns_file_read file_read_cb = NULL; +static ns_file_size file_size_cb = NULL; + int ns_file_system_set_root_path(const char *root_path) { char *new_root_path; @@ -50,3 +59,99 @@ char *ns_file_system_get_root_path(void) { return file_system_root; } + +void ns_file_system_callbacks_set(ns_file_open open, ns_file_close close, ns_file_remove remove, ns_file_write write, ns_file_read read, ns_file_size size) +{ + file_open_cb = open; + file_close_cb = close; + file_remove_cb = remove; + file_write_cb = write; + file_read_cb = read; + file_size_cb = size; +} + +NS_FILE ns_fopen(const char *file_name, const char *mode) +{ + if (!file_name || !mode || (*mode != 'r' && *mode != 'w')) { + return NULL; + } + + if (file_open_cb) { + return file_open_cb(file_name, mode); + } + + FILE *file = fopen(file_name, mode); + if (file == NULL) { + return NULL; + } + + return (NS_FILE) file; +} + +int ns_fclose(NS_FILE *ns_handle) +{ + if (!ns_handle) { + return -1; + } + + if (file_close_cb) { + return file_close_cb(ns_handle); + } + fclose((FILE *) ns_handle); + return 0; +} + +int ns_fremove(const char *file_name) +{ + if (file_remove_cb) { + return file_remove_cb(file_name); + } + + if (!file_name) { + return -1; + } + + return remove(file_name); +} + +size_t ns_fwrite(NS_FILE *ns_handle, const void *buffer, size_t size) +{ + if (!ns_handle || !buffer || size == 0) { + return 0; + } + + if (file_write_cb) { + return file_write_cb(ns_handle, buffer, size); + } + + rewind((FILE *) ns_handle); + return fwrite(buffer, 1, size, (FILE *) ns_handle); +} + +size_t ns_fread(NS_FILE *ns_handle, void *buffer, size_t size) +{ + if (!ns_handle || !buffer || size == 0) { + return 0; + } + + if (file_read_cb) { + return file_read_cb(ns_handle, buffer, size); + } + + rewind((FILE *) ns_handle); + return fread(buffer, 1, size, (FILE *) ns_handle); +} + +int ns_fsize(NS_FILE *ns_handle, size_t *size) +{ + if (!ns_handle || !size) { + return 0; + } + + if (file_size_cb) { + return file_size_cb(ns_handle, size); + } + + fseek((FILE *) ns_handle, 0L, SEEK_END); + return ftell((FILE *) ns_handle); +} diff --git a/source/nsconfig.h b/source/nsconfig.h index 9a6db864a2..dff8a5622d 100644 --- a/source/nsconfig.h +++ b/source/nsconfig.h @@ -24,10 +24,6 @@ #include "ns_types.h" -#ifdef __CC_ARM -#pragma diag_suppress 546 // transfer of control bypasses initialization -#endif - #define __ns_cfg_header(x) #x #define _ns_cfg_header(x) __ns_cfg_header(configs/cfg_##x.h) #define ns_cfg_header(x) _ns_cfg_header(x) diff --git a/sources.mk b/sources.mk index 3998833c3b..e364c49b84 100644 --- a/sources.mk +++ b/sources.mk @@ -34,7 +34,9 @@ SRCS += \ source/6LoWPAN/ws/ws_pae_lib.c \ source/6LoWPAN/ws/ws_pae_nvm_data.c \ source/6LoWPAN/ws/ws_pae_nvm_store.c \ + source/6LoWPAN/ws/ws_pae_time.c \ source/6LoWPAN/ws/ws_pae_timers.c \ + source/6LoWPAN/ws/ws_pae_key_storage.c \ source/6LoWPAN/ws/ws_eapol_relay.c \ source/6LoWPAN/ws/ws_eapol_auth_relay.c \ source/6LoWPAN/ws/ws_eapol_relay_lib.c \ @@ -79,6 +81,7 @@ SRCS += \ source/MAC/IEEE802_15_4/mac_timer.c \ source/MAC/IEEE802_15_4/sw_mac.c \ source/MAC/IEEE802_15_4/mac_fhss_callbacks.c \ + source/MAC/IEEE802_15_4/mac_cca_threshold.c \ source/MAC/ethernet/ethernet_mac_api.c \ source/MAC/serial/serial_mac_api.c \ source/MAC/virtual_rf/virtual_rf_client.c \