mirror of https://github.com/ARMmbed/mbed-os.git
Merge pull request #10624 from artokin/prepare_for_mbedos513
Nanostack release for Mbed OS 5.13pull/10656/head
commit
b2abfc3529
|
@ -79,7 +79,6 @@ extern void (*fhss_bc_switch)(void);
|
|||
#define MAC_TYPE_ACK (2)
|
||||
#define MAC_TYPE_COMMAND (3)
|
||||
#define MAC_DATA_PENDING 0x10
|
||||
#define MAC_FRAME_VERSION_2 (2)
|
||||
#define FC_DST_MODE 0x0C
|
||||
#define FC_SRC_MODE 0xC0
|
||||
#define FC_DST_ADDR_NONE 0x00
|
||||
|
@ -99,8 +98,6 @@ extern void (*fhss_bc_switch)(void);
|
|||
#define CS_SELECT() {rf->CS = 0;}
|
||||
#define CS_RELEASE() {rf->CS = 1;}
|
||||
|
||||
extern const uint8_t ADDR_UNSPECIFIED[16];
|
||||
|
||||
typedef enum {
|
||||
RF_MODE_NORMAL = 0,
|
||||
RF_MODE_SNIFFER = 1
|
||||
|
@ -183,6 +180,7 @@ static void rf_backup_timer_stop(void);
|
|||
static void rf_rx_ready_handler(void);
|
||||
static uint32_t read_irq_status(void);
|
||||
static bool rf_rx_filter(uint8_t *mac_header, uint8_t *mac_64bit_addr, uint8_t *mac_16bit_addr, uint8_t *pan_id);
|
||||
static void rf_cca_timer_start(uint32_t slots);
|
||||
|
||||
static RFPins *rf;
|
||||
static phy_device_driver_s device_driver;
|
||||
|
@ -210,6 +208,7 @@ static uint8_t s2lp_MAC[8];
|
|||
static rf_mode_e rf_mode = RF_MODE_NORMAL;
|
||||
static bool rf_update_config = false;
|
||||
static uint16_t cur_packet_len = 0xffff;
|
||||
static uint32_t receiver_ready_timestamp;
|
||||
|
||||
/* Channel configurations for sub-GHz */
|
||||
static phy_rf_channel_configuration_s phy_subghz = {
|
||||
|
@ -748,16 +747,26 @@ static void rf_start_tx(void)
|
|||
rf_backup_timer_start(MAX_PACKET_SENDING_TIME);
|
||||
}
|
||||
|
||||
static int rf_cca_check(void)
|
||||
{
|
||||
uint32_t time_from_receiver_ready = rf_get_timestamp() - receiver_ready_timestamp;
|
||||
if (time_from_receiver_ready < RSSI_SETTLING_TIME) {
|
||||
wait_us(RSSI_SETTLING_TIME - time_from_receiver_ready);
|
||||
}
|
||||
return (rf_read_register(LINK_QUALIF1) & CARRIER_SENSE);
|
||||
}
|
||||
|
||||
static void rf_cca_timer_interrupt(void)
|
||||
{
|
||||
if (device_driver.phy_tx_done_cb(rf_radio_driver_id, mac_tx_handle, PHY_LINK_CCA_PREPARE, 0, 0) != 0) {
|
||||
int8_t status = device_driver.phy_tx_done_cb(rf_radio_driver_id, mac_tx_handle, PHY_LINK_CCA_PREPARE, 0, 0);
|
||||
if (status == PHY_TX_NOT_ALLOWED) {
|
||||
rf_flush_tx_fifo();
|
||||
if (rf_state == RF_CSMA_STARTED) {
|
||||
rf_state = RF_IDLE;
|
||||
}
|
||||
return;
|
||||
}
|
||||
if ((cca_enabled == true) && ((rf_state != RF_CSMA_STARTED && rf_state != RF_IDLE) || (read_irq_status() & (1 << SYNC_WORD)) || (rf_read_register(LINK_QUALIF1) & CARRIER_SENSE))) {
|
||||
if ((cca_enabled == true) && ((rf_state != RF_CSMA_STARTED && rf_state != RF_IDLE) || (read_irq_status() & (1 << SYNC_WORD)) || rf_cca_check())) {
|
||||
if (rf_state == RF_CSMA_STARTED) {
|
||||
rf_state = RF_IDLE;
|
||||
}
|
||||
|
@ -767,9 +776,23 @@ static void rf_cca_timer_interrupt(void)
|
|||
device_driver.phy_tx_done_cb(rf_radio_driver_id, mac_tx_handle, PHY_LINK_CCA_FAIL, 0, 0);
|
||||
}
|
||||
} else {
|
||||
rf_start_tx();
|
||||
rf_state = RF_TX_STARTED;
|
||||
TEST_TX_STARTED
|
||||
if (status == PHY_RESTART_CSMA) {
|
||||
if (device_driver.phy_tx_done_cb) {
|
||||
device_driver.phy_tx_done_cb(rf_radio_driver_id, mac_tx_handle, PHY_LINK_CCA_OK, 0, 0);
|
||||
}
|
||||
if (tx_time) {
|
||||
uint32_t backoff_time = tx_time - rf_get_timestamp();
|
||||
// Max. time to TX can be 65ms, otherwise time has passed already -> send immediately
|
||||
if (backoff_time > 65000) {
|
||||
backoff_time = 1;
|
||||
}
|
||||
rf_cca_timer_start(backoff_time);
|
||||
}
|
||||
} else {
|
||||
rf_start_tx();
|
||||
rf_state = RF_TX_STARTED;
|
||||
TEST_TX_STARTED
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -931,6 +954,8 @@ static void rf_sync_detected_handler(void)
|
|||
rf_state = RF_RX_STARTED;
|
||||
TEST_RX_STARTED
|
||||
rf_disable_interrupt(SYNC_WORD);
|
||||
rf_enable_interrupt(RX_FIFO_ALMOST_FULL);
|
||||
rf_enable_interrupt(RX_DATA_READY);
|
||||
rf_backup_timer_start(MAX_PACKET_SENDING_TIME);
|
||||
}
|
||||
|
||||
|
@ -953,15 +978,14 @@ static void rf_receive(uint8_t rx_channel)
|
|||
rf_rx_channel = rf_new_channel = rx_channel;
|
||||
}
|
||||
rf_send_command(S2LP_CMD_RX);
|
||||
rf_poll_state_change(S2LP_STATE_RX);
|
||||
rf_enable_interrupt(SYNC_WORD);
|
||||
rf_enable_interrupt(RX_FIFO_ALMOST_FULL);
|
||||
rf_enable_interrupt(RX_DATA_READY);
|
||||
rf_enable_interrupt(RX_FIFO_UNF_OVF);
|
||||
rx_data_length = 0;
|
||||
if (rf_state != RF_CSMA_STARTED) {
|
||||
rf_state = RF_IDLE;
|
||||
}
|
||||
rf_poll_state_change(S2LP_STATE_RX);
|
||||
receiver_ready_timestamp = rf_get_timestamp();
|
||||
rf_unlock();
|
||||
}
|
||||
|
||||
|
@ -1158,14 +1182,25 @@ int8_t NanostackRfPhys2lp::rf_register()
|
|||
error("Multiple registrations of NanostackRfPhyAtmel not supported");
|
||||
return -1;
|
||||
}
|
||||
if (memcmp(_mac_addr, ADDR_UNSPECIFIED, 8) == 0) {
|
||||
|
||||
if (!_mac_set) {
|
||||
#ifdef AT24MAC
|
||||
int ret = _mac.read_eui64((void *)s2lp_MAC);
|
||||
if (ret < 0) {
|
||||
rf = NULL;
|
||||
rf_unlock();
|
||||
return -1;
|
||||
}
|
||||
#else
|
||||
randLIB_seed_random();
|
||||
randLIB_get_n_bytes_random(s2lp_MAC, 8);
|
||||
s2lp_MAC[0] |= 2; //Set Local Bit
|
||||
s2lp_MAC[0] &= ~1; //Clear multicast bit
|
||||
tr_info("Generated random MAC %s", trace_array(s2lp_MAC, 8));
|
||||
#endif
|
||||
set_mac_address(s2lp_MAC);
|
||||
tr_info("MAC address: %s", trace_array(_mac_addr, 8));
|
||||
}
|
||||
|
||||
rf = _rf;
|
||||
|
||||
int8_t radio_id = rf_device_register(_mac_addr);
|
||||
|
@ -1188,12 +1223,20 @@ void NanostackRfPhys2lp::rf_unregister()
|
|||
rf_unlock();
|
||||
}
|
||||
|
||||
NanostackRfPhys2lp::NanostackRfPhys2lp(PinName spi_sdi, PinName spi_sdo, PinName spi_sclk, PinName spi_cs, PinName spi_sdn,
|
||||
NanostackRfPhys2lp::NanostackRfPhys2lp(PinName spi_sdi, PinName spi_sdo, PinName spi_sclk, PinName spi_cs, PinName spi_sdn
|
||||
#ifdef TEST_GPIOS_ENABLED
|
||||
PinName spi_test1, PinName spi_test2, PinName spi_test3, PinName spi_test4, PinName spi_test5,
|
||||
,PinName spi_test1, PinName spi_test2, PinName spi_test3, PinName spi_test4, PinName spi_test5
|
||||
#endif //TEST_GPIOS_ENABLED
|
||||
PinName spi_gpio0, PinName spi_gpio1, PinName spi_gpio2, PinName spi_gpio3)
|
||||
: _mac_addr(), _rf(NULL), _mac_set(false),
|
||||
,PinName spi_gpio0, PinName spi_gpio1, PinName spi_gpio2, PinName spi_gpio3
|
||||
#ifdef AT24MAC
|
||||
,PinName i2c_sda, PinName i2c_scl
|
||||
#endif //AT24MAC
|
||||
)
|
||||
:
|
||||
#ifdef AT24MAC
|
||||
_mac(i2c_sda, i2c_scl),
|
||||
#endif //AT24MAC
|
||||
_mac_addr(), _rf(NULL), _mac_set(false),
|
||||
_spi_sdi(spi_sdi), _spi_sdo(spi_sdo), _spi_sclk(spi_sclk), _spi_cs(spi_cs), _spi_sdn(spi_sdn),
|
||||
#ifdef TEST_GPIOS_ENABLED
|
||||
_spi_test1(spi_test1), _spi_test2(spi_test2), _spi_test3(spi_test3), _spi_test4(spi_test4), _spi_test5(spi_test5),
|
||||
|
@ -1236,20 +1279,6 @@ static bool rf_panid_filter_common(uint8_t *panid_start, uint8_t *pan_id, uint8_
|
|||
return retval;
|
||||
}
|
||||
|
||||
static bool rf_panid_v2_filter(uint8_t *ptr, uint8_t *pan_id, uint8_t dst_mode, uint8_t src_mode, uint8_t seq_compressed, uint8_t panid_compressed, uint8_t frame_type)
|
||||
{
|
||||
if ((dst_mode == FC_DST_ADDR_NONE) && (frame_type == MAC_TYPE_DATA || frame_type == MAC_TYPE_COMMAND)) {
|
||||
return true;
|
||||
}
|
||||
if ((dst_mode == FC_DST_64_BITS) && (src_mode == FC_SRC_64_BITS) && panid_compressed) {
|
||||
return true;
|
||||
}
|
||||
if (seq_compressed) {
|
||||
ptr--;
|
||||
}
|
||||
return rf_panid_filter_common(ptr, pan_id, frame_type);
|
||||
}
|
||||
|
||||
static bool rf_panid_v1_v0_filter(uint8_t *ptr, uint8_t *pan_id, uint8_t frame_type)
|
||||
{
|
||||
return rf_panid_filter_common(ptr, pan_id, frame_type);
|
||||
|
@ -1298,17 +1327,6 @@ static bool rf_addr_filter_common(uint8_t *ptr, uint8_t addr_mode, uint8_t *mac_
|
|||
return retval;
|
||||
}
|
||||
|
||||
static bool rf_addr_v2_filter(uint8_t *ptr, uint8_t *mac_64bit_addr, uint8_t *mac_16bit_addr, uint8_t dst_mode, uint8_t seq_compressed, uint8_t panid_compressed)
|
||||
{
|
||||
if (seq_compressed) {
|
||||
ptr--;
|
||||
}
|
||||
if (panid_compressed) {
|
||||
ptr -= 2;
|
||||
}
|
||||
return rf_addr_filter_common(ptr, dst_mode, mac_64bit_addr, mac_16bit_addr);
|
||||
}
|
||||
|
||||
static bool rf_addr_v1_v0_filter(uint8_t *ptr, uint8_t *mac_64bit_addr, uint8_t *mac_16bit_addr, uint8_t dst_mode)
|
||||
{
|
||||
return rf_addr_filter_common(ptr, dst_mode, mac_64bit_addr, mac_16bit_addr);
|
||||
|
@ -1317,19 +1335,9 @@ static bool rf_addr_v1_v0_filter(uint8_t *ptr, uint8_t *mac_64bit_addr, uint8_t
|
|||
static bool rf_rx_filter(uint8_t *mac_header, uint8_t *mac_64bit_addr, uint8_t *mac_16bit_addr, uint8_t *pan_id)
|
||||
{
|
||||
uint8_t dst_mode = (mac_header[1] & FC_DST_MODE);
|
||||
uint8_t src_mode = (mac_header[1] & FC_SRC_MODE);
|
||||
uint8_t seq_compressed = ((mac_header[1] & FC_SEQUENCE_COMPRESSION) >> SHIFT_SEQ_COMP_FIELD);
|
||||
uint8_t panid_compressed = ((mac_header[0] & FC_PAN_ID_COMPRESSION) >> SHIFT_PANID_COMP_FIELD);
|
||||
uint8_t frame_type = mac_header[0] & MAC_FRAME_TYPE_MASK;
|
||||
uint8_t version = ((mac_header[1] & VERSION_FIELD_MASK) >> SHIFT_VERSION_FIELD);
|
||||
if (version == MAC_FRAME_VERSION_2) {
|
||||
if (!rf_panid_v2_filter(mac_header + OFFSET_DST_PAN_ID, pan_id, dst_mode, src_mode, seq_compressed, panid_compressed, frame_type)) {
|
||||
return false;
|
||||
}
|
||||
if (!rf_addr_v2_filter(mac_header + OFFSET_DST_ADDR, mac_64bit_addr, mac_16bit_addr, dst_mode, seq_compressed, panid_compressed)) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (version != MAC_FRAME_VERSION_2) {
|
||||
if (!rf_panid_v1_v0_filter(mac_header + OFFSET_DST_PAN_ID, pan_id, frame_type)) {
|
||||
return false;
|
||||
}
|
||||
|
@ -1474,11 +1482,15 @@ static void rf_print_registers(void)
|
|||
#if MBED_CONF_S2LP_PROVIDE_DEFAULT
|
||||
NanostackRfPhy &NanostackRfPhy::get_default_instance()
|
||||
{
|
||||
static NanostackRfPhys2lp rf_phy(S2LP_SPI_SDI, S2LP_SPI_SDO, S2LP_SPI_SCLK, S2LP_SPI_CS, S2LP_SPI_SDN,
|
||||
static NanostackRfPhys2lp rf_phy(S2LP_SPI_SDI, S2LP_SPI_SDO, S2LP_SPI_SCLK, S2LP_SPI_CS, S2LP_SPI_SDN
|
||||
#ifdef TEST_GPIOS_ENABLED
|
||||
S2LP_SPI_TEST1, S2LP_SPI_TEST2, S2LP_SPI_TEST3, S2LP_SPI_TEST4, S2LP_SPI_TEST5,
|
||||
,S2LP_SPI_TEST1, S2LP_SPI_TEST2, S2LP_SPI_TEST3, S2LP_SPI_TEST4, S2LP_SPI_TEST5
|
||||
#endif //TEST_GPIOS_ENABLED
|
||||
S2LP_SPI_GPIO0, S2LP_SPI_GPIO1, S2LP_SPI_GPIO2, S2LP_SPI_GPIO3);
|
||||
,S2LP_SPI_GPIO0, S2LP_SPI_GPIO1, S2LP_SPI_GPIO2, S2LP_SPI_GPIO3
|
||||
#ifdef AT24MAC
|
||||
,S2LP_I2C_SDA, S2LP_I2C_SCL
|
||||
#endif //AT24MAC
|
||||
);
|
||||
return rf_phy;
|
||||
}
|
||||
#endif // MBED_CONF_S2LP_PROVIDE_DEFAULT
|
||||
|
|
|
@ -0,0 +1,72 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2019 ARM Limited. All rights reserved.
|
||||
* 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 "NanostackRfPhys2lp.h"
|
||||
#include "at24mac_s2lp.h"
|
||||
|
||||
|
||||
#if DEVICE_I2C
|
||||
#ifdef AT24MAC
|
||||
|
||||
/* Device addressing */
|
||||
#define AT24MAC_EEPROM_ADDRESS (0x0A<<4)
|
||||
#define AT24MAC_RW_PROTECT_ADDRESS (0x06<<4)
|
||||
#define AT24MAC_SERIAL_ADDRESS (0x0B<<4)
|
||||
|
||||
/* Known memory blocks */
|
||||
#define AT24MAC_SERIAL_OFFSET (0x80)
|
||||
#define AT24MAC_EUI64_OFFSET (0x98)
|
||||
#define AT24MAC_EUI48_OFFSET (0x9A)
|
||||
|
||||
#define SERIAL_LEN 16
|
||||
#define EUI64_LEN 8
|
||||
#define EUI48_LEN 6
|
||||
|
||||
using namespace mbed;
|
||||
|
||||
AT24Mac_s2lp::AT24Mac_s2lp(PinName sda, PinName scl) : _i2c(sda, scl)
|
||||
{
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
int AT24Mac_s2lp::read_serial(void *buf)
|
||||
{
|
||||
char offset = AT24MAC_SERIAL_OFFSET;
|
||||
if (_i2c.write(AT24MAC_SERIAL_ADDRESS, &offset, 1, true)) {
|
||||
return -1; //No ACK
|
||||
}
|
||||
return _i2c.read(AT24MAC_SERIAL_ADDRESS, (char *)buf, SERIAL_LEN);
|
||||
}
|
||||
|
||||
int AT24Mac_s2lp::read_eui64(void *buf)
|
||||
{
|
||||
char offset = AT24MAC_EUI64_OFFSET;
|
||||
if (_i2c.write(AT24MAC_SERIAL_ADDRESS, &offset, 1, true)) {
|
||||
return -1; //No ACK
|
||||
}
|
||||
return _i2c.read(AT24MAC_SERIAL_ADDRESS, (char *)buf, EUI64_LEN);
|
||||
}
|
||||
|
||||
int AT24Mac_s2lp::read_eui48(void *buf)
|
||||
{
|
||||
char offset = AT24MAC_EUI48_OFFSET;
|
||||
if (_i2c.write(AT24MAC_SERIAL_ADDRESS, &offset, 1, true)) {
|
||||
return -1; //No ACK
|
||||
}
|
||||
return _i2c.read(AT24MAC_SERIAL_ADDRESS, (char *)buf, EUI48_LEN);
|
||||
}
|
||||
|
||||
#endif /* AT24MAC */
|
||||
#endif /* DEVICE_I2C */
|
|
@ -0,0 +1,71 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2019 ARM Limited. All rights reserved.
|
||||
* 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 AT24MAC_S2LP_H
|
||||
#define AT24MAC_S2LP_H
|
||||
|
||||
#include "PinNames.h"
|
||||
|
||||
#if DEVICE_I2C
|
||||
#ifdef AT24MAC
|
||||
|
||||
#include "I2C.h"
|
||||
#include "drivers/DigitalInOut.h"
|
||||
#include "platform/mbed_wait_api.h"
|
||||
|
||||
/*
|
||||
* AT24MAC drivers.
|
||||
*
|
||||
* This is a EEPROM chip designed to contain factory programmed read-only EUI-64 or EUI-48,
|
||||
* a 128bit serial number and some user programmable EEPROM.
|
||||
*
|
||||
* AT24MAC602 contains EUI-64, use read_eui64()
|
||||
* AT24MAC402 contains EUI-64, use read_eui48()
|
||||
*
|
||||
* NOTE: You cannot use both EUI-64 and EUI-48. Chip contains only one of those.
|
||||
*/
|
||||
|
||||
class AT24Mac_s2lp {
|
||||
public:
|
||||
AT24Mac_s2lp(PinName sda, PinName scl);
|
||||
|
||||
/**
|
||||
* Read unique serial number from chip.
|
||||
* \param buf pointer to write serial number to. Must have space for 16 bytes.
|
||||
* \return zero on success, negative number on failure
|
||||
*/
|
||||
int read_serial(void *buf);
|
||||
|
||||
/**
|
||||
* Read EUI-64 from chip.
|
||||
* \param buf pointer to write EUI-64 to. Must have space for 8 bytes.
|
||||
* \return zero on success, negative number on failure
|
||||
*/
|
||||
int read_eui64(void *buf);
|
||||
|
||||
/**
|
||||
* Read EUI-48 from chip.
|
||||
* \param buf pointer to write EUI-48 to. Must have space for 6 bytes.
|
||||
* \return zero on success, negative number on failure
|
||||
*/
|
||||
int read_eui48(void *buf);
|
||||
|
||||
private:
|
||||
mbed::I2C _i2c;
|
||||
};
|
||||
|
||||
#endif /* AT24MAC */
|
||||
#endif /* DEVICE_I2C */
|
||||
#endif /* AT24MAC_S2LP_H */
|
|
@ -25,6 +25,7 @@ extern "C" {
|
|||
#define VERSION 0xC1
|
||||
#define FIFO_SIZE 128
|
||||
#define SPI_HEADER_LENGTH 2
|
||||
#define RSSI_SETTLING_TIME 250
|
||||
|
||||
#define S2LP_GPIO0 0
|
||||
#define S2LP_GPIO1 1
|
||||
|
|
|
@ -28,6 +28,42 @@
|
|||
// Uncomment to use testing gpios attached to TX/RX processes
|
||||
//#define TEST_GPIOS_ENABLED
|
||||
|
||||
#if defined(TARGET_MTB_STM_S2LP)
|
||||
#if !defined(S2LP_SPI_SDI)
|
||||
#define S2LP_SPI_SDI PA_7
|
||||
#endif
|
||||
#if !defined(S2LP_SPI_SDO)
|
||||
#define S2LP_SPI_SDO PA_6
|
||||
#endif
|
||||
#if !defined(S2LP_SPI_SCLK)
|
||||
#define S2LP_SPI_SCLK PA_5
|
||||
#endif
|
||||
#if !defined(S2LP_SPI_CS)
|
||||
#define S2LP_SPI_CS PC_0
|
||||
#endif
|
||||
#if !defined(S2LP_SPI_SDN)
|
||||
#define S2LP_SPI_SDN PF_13
|
||||
#endif
|
||||
#if !defined(S2LP_SPI_GPIO0)
|
||||
#define S2LP_SPI_GPIO0 PA_3
|
||||
#endif
|
||||
#if !defined(S2LP_SPI_GPIO1)
|
||||
#define S2LP_SPI_GPIO1 PC_3
|
||||
#endif
|
||||
#if !defined(S2LP_SPI_GPIO2)
|
||||
#define S2LP_SPI_GPIO2 PF_3
|
||||
#endif
|
||||
#if !defined(S2LP_SPI_GPIO3)
|
||||
#define S2LP_SPI_GPIO3 PF_10
|
||||
#endif
|
||||
#if !defined(S2LP_I2C_SDA)
|
||||
#define S2LP_I2C_SDA PB_7
|
||||
#endif
|
||||
#if !defined(S2LP_I2C_SCL)
|
||||
#define S2LP_I2C_SCL PB_6
|
||||
#endif
|
||||
#define AT24MAC
|
||||
#else
|
||||
#if !defined(S2LP_SPI_SDI)
|
||||
#define S2LP_SPI_SDI D11
|
||||
#endif
|
||||
|
@ -70,17 +106,23 @@
|
|||
#if !defined(S2LP_SPI_GPIO3)
|
||||
#define S2LP_SPI_GPIO3 A5
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include "at24mac_s2lp.h"
|
||||
|
||||
class RFPins;
|
||||
|
||||
class NanostackRfPhys2lp : public NanostackRfPhy {
|
||||
public:
|
||||
NanostackRfPhys2lp(PinName spi_sdi, PinName spi_sdo,
|
||||
PinName spi_sclk, PinName spi_cs, PinName spi_sdn,
|
||||
NanostackRfPhys2lp(PinName spi_sdi, PinName spi_sdo, PinName spi_sclk, PinName spi_cs, PinName spi_sdn
|
||||
#ifdef TEST_GPIOS_ENABLED
|
||||
PinName spi_test1, PinName spi_test2, PinName spi_test3, PinName spi_test4, PinName spi_test5,
|
||||
,PinName spi_test1, PinName spi_test2, PinName spi_test3, PinName spi_test4, PinName spi_test5
|
||||
#endif //TEST_GPIOS_ENABLED
|
||||
PinName spi_gpio0, PinName spi_gpio1, PinName spi_gpio2, PinName spi_gpio3);
|
||||
,PinName spi_gpio0, PinName spi_gpio1, PinName spi_gpio2, PinName spi_gpio3
|
||||
#ifdef AT24MAC
|
||||
,PinName i2c_sda, PinName i2c_scl
|
||||
#endif //AT24MAC
|
||||
);
|
||||
virtual ~NanostackRfPhys2lp();
|
||||
virtual int8_t rf_register();
|
||||
virtual void rf_unregister();
|
||||
|
@ -88,6 +130,9 @@ public:
|
|||
virtual void set_mac_address(uint8_t *mac);
|
||||
|
||||
private:
|
||||
#ifdef AT24MAC
|
||||
AT24Mac_s2lp _mac;
|
||||
#endif //AT24MAC
|
||||
uint8_t _mac_addr[8];
|
||||
RFPins *_rf;
|
||||
bool _mac_set;
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
"requires": ["nanostack"],
|
||||
"config": {
|
||||
"heap-size": {
|
||||
"help": "Nanostack's heap size [bytes: 0-65534]",
|
||||
"help": "Nanostack's heap size [bytes: 0-4294967295]",
|
||||
"value": 32500
|
||||
},
|
||||
"use-malloc-for-heap": {
|
||||
|
|
|
@ -1,17 +1,39 @@
|
|||
ARM IPV6/6LoWPAN stack.
|
||||
ARM Mesh networking stack
|
||||
=======================
|
||||
|
||||
This repository contains the ARM IPv6/6LoWPAN/Thread Stack for mbed OS.
|
||||
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
|
||||
|
||||
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).
|
||||
|
||||
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
|
||||
|
||||
This networking stack is using standard 6LoWPAN and uses:
|
||||
|
||||
* Neighbor Discovery Protocol ([RFC4861](https://tools.ietf.org/html/rfc4861)) to locate other devices in the mesh network.
|
||||
* Mesh-Link-Establishment ([draft-kelsey-intarea-mesh-link-establishment-06](https://tools.ietf.org/html/draft-kelsey-intarea-mesh-link-establishment-06)) is used for establishing and configuring secure radio links.
|
||||
|
||||
##Thread
|
||||
Thread is standardized by [Thread group](https://www.threadgroup.org/).
|
||||
|
||||

|
||||
|
||||
mbed OS is now a Thread Certified Component. Using IPv6 with 6LoWPAN as the foundation, Thread technology provides a low-power, self-healing mesh network designed for the home.
|
||||
|
||||
The documentation is hosted in [here](https://os.mbed.com/docs/v5.6/tutorials/6lowpan-mesh.html).
|
||||
##Wi-SUN
|
||||
Wi-SUN (Smart Utility Networks) specification is standardized by [Wi-SUN Alliance](https://www.wi-sun.org/).
|
||||
|
||||
On mbed OS, usage is through [mbed Mesh API](https://os.mbed.com/docs/v5.6/reference/mesh.html) and [Socket API](https://os.mbed.com/docs/v5.6/reference/network-socket.html).
|
||||
|
||||
To see, how the 6LoWPAN Stack works, check the example application [mbed-os-example-mesh-minimal](https://github.com/ARMmbed/mbed-os-example-mesh-minimal).
|
||||
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
|
||||
|
||||
|
|
|
@ -133,6 +133,16 @@ uint16_t dhcp_service_init(int8_t interface_id, dhcp_instance_type_e instance_ty
|
|||
*/
|
||||
void dhcp_service_relay_instance_enable(uint16_t instance, uint8_t *server_address);
|
||||
|
||||
/**
|
||||
* \brief Get DHCPv6 Relay Agent address pointer.
|
||||
*
|
||||
* \param instance The instance ID of the registered server.
|
||||
*
|
||||
* \return NULL when address is not available
|
||||
* {
|
||||
*/
|
||||
uint8_t *dhcp_service_relay_global_addres_get(uint16_t instance);
|
||||
|
||||
|
||||
/**
|
||||
* \brief Deletes a server instance.
|
||||
|
@ -188,6 +198,15 @@ uint32_t dhcp_service_send_req(uint16_t instance_id, uint8_t options, void *ptr,
|
|||
*/
|
||||
void dhcp_service_set_retry_timers(uint32_t msg_tr_id, uint16_t timeout_init, uint16_t timeout_max, uint8_t retrans_max);
|
||||
|
||||
/**
|
||||
* \brief Update DHCP service server address to active tx process.
|
||||
*
|
||||
* \param msg_tr_id The message transaction ID.
|
||||
* \param server_address New destination address to server / relay Agent.
|
||||
*
|
||||
*/
|
||||
void dhcp_service_update_server_address(uint32_t msg_tr_id, uint8_t *server_address);
|
||||
|
||||
/**
|
||||
* \brief Stops transactions for a message (retransmissions).
|
||||
*
|
||||
|
|
|
@ -143,13 +143,13 @@ typedef int16_t fhss_synch_state_set(const fhss_api_t *api, fhss_states fhss_sta
|
|||
typedef uint32_t fhss_read_timestamp(const fhss_api_t *api);
|
||||
|
||||
/**
|
||||
* @brief Get retransmission period. FHSS uses different retry periods for different destinations.
|
||||
* @brief Get additional retransmission period. FHSS uses different retry periods depending on destination or channel availability.
|
||||
* @param api FHSS instance.
|
||||
* @param destination_address Destination MAC address.
|
||||
* @param phy_mtu PHY MTU size.
|
||||
* @return Retransmission period.
|
||||
* @return Retransmission period in microsecond which should be added to normal backoff period.
|
||||
*/
|
||||
typedef uint16_t fhss_get_retry_period(const fhss_api_t *api, uint8_t *destination_address, uint16_t phy_mtu);
|
||||
typedef uint32_t fhss_get_retry_period(const fhss_api_t *api, uint8_t *destination_address, uint16_t phy_mtu);
|
||||
|
||||
/**
|
||||
* @brief Write synchronization info to given pointer.
|
||||
|
|
|
@ -264,6 +264,7 @@ typedef enum {
|
|||
macAutoRequestKeyIndex = 0x7b, /*<The index of the key used for automatic data*/
|
||||
macDefaultKeySource = 0x7c, /*<Default key source*/
|
||||
//NON standard extension
|
||||
macMultiCSMAParameters = 0xfa, /*<Multi CSMA parameters*/
|
||||
macRfConfiguration = 0xfb, /*<RF channel configuration parameters*/
|
||||
macAcceptByPassUnknowDevice = 0xfc, /*< Accept data trough MAC if packet is data can be authenticated by group key nad MIC. Security enforsment point must be handled carefully these packets */
|
||||
macLoadBalancingBeaconTx = 0xfd, /*< Trig Beacon from load balance module periodic */
|
||||
|
@ -499,4 +500,14 @@ typedef struct mlme_poll_conf_s {
|
|||
uint8_t status; /**< Status of Poll operation */
|
||||
} mlme_poll_conf_t;
|
||||
|
||||
/**
|
||||
* @brief struct mlme_multi_csma_ca_param_s Set multi CSMA-CA parameters
|
||||
*
|
||||
* Non standard extension to perform CCA multiple times before transmission
|
||||
*/
|
||||
typedef struct mlme_multi_csma_ca_s {
|
||||
uint8_t number_of_csma_ca_periods; /**< Number of CSMA-CA periods */
|
||||
uint16_t multi_cca_interval; /**< Length of the additional CSMA-CA period(s) in microseconds */
|
||||
} mlme_multi_csma_ca_param_t;
|
||||
|
||||
#endif /* MLME_H_ */
|
||||
|
|
|
@ -51,6 +51,40 @@ int8_t arm_nwk_ipv6_frag_mru(uint16_t frag_mru);
|
|||
*/
|
||||
int8_t arm_nwk_ipv6_max_cache_entries(uint16_t max_entries);
|
||||
|
||||
/**
|
||||
* \brief Configure destination cache.
|
||||
*
|
||||
* Set destination cache maximum entry count, thresholds where amount of entries is kept during operation and lifetime.
|
||||
*
|
||||
* Note: This must be called before arm_nwk_interface_lowpan_init()
|
||||
*
|
||||
* \param max_entries Maximum number of entries allowed in destination cache at any time.
|
||||
* \param short_term_threshold Amount of cache entries kept in memory in short term. Must be less than max_entries.
|
||||
* \param long_term_threshold Amount of entries kept in memory over long period of time. Must be less than short_term_threshold.
|
||||
* \param lifetime Lifetime of cache entry, must be over 120 seconds
|
||||
*
|
||||
* \return 0 Change OK.
|
||||
* \return <0 Change invalid - unable to change the maximum for cache.
|
||||
*/
|
||||
int8_t arm_nwk_ipv6_destination_cache_configure(uint16_t max_entries, uint16_t short_term_threshold, uint16_t long_term_threshold, uint16_t lifetime);
|
||||
|
||||
/**
|
||||
* \brief Configure neighbour cache.
|
||||
*
|
||||
* Set neighbour cache maximum entry count, thresholds where amount of entries is kept during operation and lifetime.
|
||||
*
|
||||
* Note: This must be called before arm_nwk_interface_lowpan_init()
|
||||
*
|
||||
* \param max_entries Maximum number of entries allowed in neighbour cache at any time.
|
||||
* \param short_term_threshold Amount of cache entries kept in memory in short term. Must be less than max_entries.
|
||||
* \param long_term_threshold Amount of entries kept in memory over long period of time. Must be less than short_term_threshold.
|
||||
* \param lifetime Lifetime of cache entry, must be over 120 seconds
|
||||
*
|
||||
* \return 0 Change OK.
|
||||
* \return <0 Change invalid - unable to change the maximum for cache.
|
||||
*/
|
||||
int8_t arm_nwk_ipv6_neighbour_cache_configure(uint16_t max_entries, uint16_t short_term_threshold, uint16_t long_term_threshold, uint16_t lifetime);
|
||||
|
||||
/**
|
||||
* \brief Configure automatic flow label calculation.
|
||||
*
|
||||
|
|
|
@ -241,6 +241,19 @@ int thread_test_version_set(int8_t interface_id, uint8_t version);
|
|||
*/
|
||||
int thread_test_router_selection_jitter_set(int8_t interface_id, uint32_t jitter);
|
||||
|
||||
/**
|
||||
* \brief Set Thread PBBR status response override.
|
||||
*
|
||||
* \param interface_id Network Interface
|
||||
* \param dua_status expected dua response value from PBBR
|
||||
* \param dua_count number of times dua_response is repeated
|
||||
* \param ba_failure_count number of times bba failure is repeated
|
||||
*
|
||||
* \return 0, OK
|
||||
* \return <0 Error
|
||||
*/
|
||||
int thread_test_pbbr_response_override_set(int8_t interface_id, uint8_t dua_status, uint8_t dua_count, uint8_t ba_failure_count);
|
||||
|
||||
/**
|
||||
* \brief Sets the thread MIN_DELAY_TIMER default value.
|
||||
*
|
||||
|
|
|
@ -113,9 +113,9 @@ int ws_test_active_key_set(int8_t interface_id, uint8_t index);
|
|||
* Pairwise Transient Key (PTK) lifetimes.
|
||||
*
|
||||
* \param interface_id Network interface ID.
|
||||
* \param gtk_lifetime GTK lifetime in minutes
|
||||
* \param pmk_lifetime PMK lifetime in minutes
|
||||
* \param ptk_lifetime PTK lifetime in minutes
|
||||
* \param gtk_lifetime GTK lifetime in minutes or zero if value is not changed
|
||||
* \param pmk_lifetime PMK lifetime in minutes or zero if value is not changed
|
||||
* \param ptk_lifetime PTK lifetime in minutes or zero if value is not changed
|
||||
*
|
||||
* \return 0 Lifetimes are set
|
||||
* \return <0 Lifetime set has failed
|
||||
|
@ -135,9 +135,10 @@ int ws_test_key_lifetime_set(
|
|||
* maximum mismatch time in minutes.
|
||||
*
|
||||
* \param interface_id Network interface ID.
|
||||
* \param revocat_lifetime_reduct GTK Revocation Lifetime Reduction (1 / value * GTK lifetime)
|
||||
* \param new_activation_time GTK New Activation Time (1 / value * GTK lifetime)
|
||||
* \param max_mismatch GTK maximum mismatch in minutes
|
||||
* \param revocat_lifetime_reduct GTK Revocation Lifetime Reduction (1 / value * GTK lifetime) or zero if value is not changed
|
||||
* \param new_activation_time GTK New Activation Time (1 / value * GTK lifetime) or zero if value is not changed
|
||||
* \param new_install_req GTK New Install Required (percent * GTK lifetime) or zero if value is not changed
|
||||
* \param max_mismatch GTK maximum mismatch in minutes or zero if value is not changed
|
||||
*
|
||||
* \return 0 Lifetimes are set
|
||||
* \return <0 Lifetime set has failed.
|
||||
|
@ -146,9 +147,26 @@ int ws_test_gtk_time_settings_set(
|
|||
int8_t interface_id,
|
||||
uint8_t revocat_lifetime_reduct,
|
||||
uint8_t new_activation_time,
|
||||
uint8_t new_install_req,
|
||||
uint32_t max_mismatch
|
||||
);
|
||||
|
||||
/**
|
||||
* Sets Next Group Transient Keys used during GTK life cycle
|
||||
*
|
||||
* Sets next Group Transient Keys (GTKs) used during GTK life cycle. Up to four
|
||||
* GTKs can be set (GTKs from index 0 to 3). When next GTK(s) are set, border
|
||||
* router inserts GTKs from the next GTK list into use during GTK update
|
||||
* procedure.
|
||||
*
|
||||
* \param interface_id Network interface ID.
|
||||
* \param gtk GTK array, if GTK is not set, pointer for the index shall be NULL.
|
||||
*
|
||||
* \return 0 GTKs are set
|
||||
* \return <0 GTK set has failed
|
||||
*/
|
||||
int ws_test_next_gtk_set(int8_t interface_id, uint8_t *gtk[4]);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -29,6 +29,11 @@
|
|||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** PHY_LINK_CCA_PREPARE status definitions */
|
||||
#define PHY_TX_NOT_ALLOWED -1 /**< TX not allowed. Do not continue to CCA process. */
|
||||
#define PHY_TX_ALLOWED 0 /**< TX allowed. Continue to CCA process. */
|
||||
#define PHY_RESTART_CSMA 1 /**< Restart CSMA-CA timer. CSMA-CA period must be calculated using given backoff time (PHY_EXTENSION_SET_CSMA_PARAMETERS) */
|
||||
|
||||
/** Interface states */
|
||||
typedef enum {
|
||||
PHY_INTERFACE_RESET, /**< Reset PHY driver and set to idle. */
|
||||
|
@ -45,9 +50,16 @@ typedef enum {
|
|||
PHY_LINK_TX_SUCCESS, /**< MAC TX complete. MAC will a make decision to enter wait ACK or TX done state. */
|
||||
PHY_LINK_TX_FAIL, /**< Link TX process fail. */
|
||||
PHY_LINK_CCA_FAIL, /**< RF link CCA process fail. */
|
||||
PHY_LINK_CCA_PREPARE, /**< RX Tx timeout prepare operation like channel switch to Tx channel from Receive one If operation fail must return not zero*/
|
||||
PHY_LINK_CCA_OK, /**< RF link CCA process ok. */
|
||||
PHY_LINK_CCA_PREPARE, /**< Prepare for CCA after CSMA-CA: changes to CCA channel and gives permission to TX. See PHY_LINK_CCA_PREPARE status definitions for return values */
|
||||
} phy_link_tx_status_e;
|
||||
|
||||
/** MAC filtering modes. Set corresponding bit to 1 (1 << MAC_FRAME_VERSION_X) in PHY_EXTENSION_FILTERING_SUPPORT request when PHY can handle the filtering of this frame type.
|
||||
* NOTE: Currently MAC supports filtering and Acking only 802.15.4-2015 frames. Any other frame version must be filtered and Acked by PHY with either HW or SW solution. */
|
||||
typedef enum {
|
||||
MAC_FRAME_VERSION_2 = 2 /**< 802.15.4-2015 */
|
||||
} phy_link_filters_e;
|
||||
|
||||
/** Extension types */
|
||||
typedef enum {
|
||||
PHY_EXTENSION_CTRL_PENDING_BIT, /**< Control MAC pending bit for indirect data. */
|
||||
|
@ -64,7 +76,8 @@ typedef enum {
|
|||
PHY_EXTENSION_GET_TIMESTAMP, /**< Read 32-bit constant monotonic time stamp in us */
|
||||
PHY_EXTENSION_SET_CSMA_PARAMETERS, /**< CSMA parameter's are given by phy_csma_params_t structure remember type cast uint8_t pointer to structure type*/
|
||||
PHY_EXTENSION_GET_SYMBOLS_PER_SECOND, /**< Read Symbols per seconds which will help to convert symbol time to real time */
|
||||
PHY_EXTENSION_SET_RF_CONFIGURATION /**< Set RF configuration using phy_rf_channel_parameters_s structure */
|
||||
PHY_EXTENSION_SET_RF_CONFIGURATION, /**< Set RF configuration using phy_rf_channel_parameters_s structure */
|
||||
PHY_EXTENSION_FILTERING_SUPPORT /**< Return filtering modes that can be supported by the PHY driver. See phy_link_filters_e */
|
||||
} phy_extension_type_e;
|
||||
|
||||
/** Address types */
|
||||
|
|
|
@ -83,6 +83,7 @@ typedef struct link_configuration {
|
|||
uint8_t version; /**< current protocol version*/
|
||||
uint16_t rfChannel; /**< current rf channel*/
|
||||
uint8_t securityPolicy; /**< Commission Security Policy*/
|
||||
uint8_t securityPolicyExt; /**< Additional Security Policy byte*/
|
||||
uint64_t timestamp;/**< commissioning data set timestamp. [48 bit timestamp seconds]-[15 bit timestamp ticks]-[U bit] */
|
||||
} link_configuration_s;
|
||||
|
||||
|
|
|
@ -45,6 +45,36 @@
|
|||
*/
|
||||
int ws_bbr_start(int8_t interface_id, int8_t backbone_interface_id);
|
||||
|
||||
/**
|
||||
* Border router configuration options
|
||||
*/
|
||||
#define BBR_ULA_C 0x0001 /**< Static ULA prefix created automatically */
|
||||
#define BBR_GUA_C 0x0002 /**< Routable prefix is learned from the backbone */
|
||||
#define BBR_GUA_ROUTE 0x0004 /**< More specific route is added for GUA prefix */
|
||||
#define BBR_GUA_SLAAC 0x0008 /**< Use SLAAC addressing in routable prefix */
|
||||
#define BBR_GUA_WAIT 0x0010 /**< Wait backbone availability before starting RPL dodag */
|
||||
#define BBR_BB_WAIT 0x0020 /**< Wait backbone availability before starting Wi-SUN network */
|
||||
/**
|
||||
* Configure border router features.
|
||||
*
|
||||
* \param interface_id interface ID of the Wi-SUN network
|
||||
* \param options Options configured to Border router
|
||||
* BBR_ULA_C Configure Mesh local ULA prefix with SLAAC address (default)
|
||||
* BBR_GUA_C Configure GUA/ULA prefix from backbone to RPL (default)
|
||||
* BBR_GUA_ROUTE Add more specific route for GUA (default)
|
||||
* BBR_GUA_SLAAC Use SLAAC address generation in GUA prefix
|
||||
* BBR_GUA_WAIT Start RPL root only when GUA is available
|
||||
* BBR_BB_WAIT Start Wi-SUN network only when backbone is ready
|
||||
*
|
||||
* By default Wi-SUN network is started and is treated as separate interface even if backbone is not available.
|
||||
*
|
||||
* Default route RPL options when backbone is set up. RPL root is always Grounded
|
||||
*
|
||||
* \return 0 on success
|
||||
* \return <0 in case of errors
|
||||
*
|
||||
*/
|
||||
int ws_bbr_configure(int8_t interface_id, uint16_t options);
|
||||
/**
|
||||
* Stop backbone Border router.
|
||||
*
|
||||
|
|
|
@ -339,6 +339,26 @@ int8_t mac_helper_security_default_key_set(protocol_interface_info_entry_t *inte
|
|||
return 0;
|
||||
}
|
||||
|
||||
int8_t mac_helper_security_default_recv_key_set(protocol_interface_info_entry_t *interface, const uint8_t *key, uint8_t id, uint8_t keyid_mode)
|
||||
{
|
||||
if (id == 0 || keyid_mode > 3) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
mac_helper_keytable_descriptor_set(interface->mac_api, key, id, interface->mac_parameters->mac_default_key_attribute_id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int8_t mac_helper_security_auto_request_key_index_set(protocol_interface_info_entry_t *interface, uint8_t id)
|
||||
{
|
||||
if (id == 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
mac_helper_pib_8bit_set(interface, macAutoRequestKeyIndex, id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int8_t mac_helper_security_pairwisekey_set(protocol_interface_info_entry_t *interface, const uint8_t *key, const uint8_t *mac_64, uint8_t key_attribute)
|
||||
{
|
||||
|
@ -374,6 +394,33 @@ int8_t mac_helper_security_prev_key_set(protocol_interface_info_entry_t *interfa
|
|||
|
||||
}
|
||||
|
||||
int8_t mac_helper_security_key_to_descriptor_set(protocol_interface_info_entry_t *interface, const uint8_t *key, uint8_t id, uint8_t descriptor)
|
||||
{
|
||||
if (id == 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
mac_helper_keytable_descriptor_set(interface->mac_api, key, id, descriptor);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int8_t mac_helper_security_key_descriptor_clear(protocol_interface_info_entry_t *interface, uint8_t descriptor)
|
||||
{
|
||||
if (!interface->mac_api) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
mlme_set_t set_req;
|
||||
mlme_key_descriptor_entry_t key_description;
|
||||
memset(&key_description, 0, sizeof(mlme_key_descriptor_entry_t));
|
||||
|
||||
set_req.attr = macKeyTable;
|
||||
set_req.value_pointer = &key_description;
|
||||
set_req.value_size = sizeof(mlme_key_descriptor_entry_t);
|
||||
set_req.attr_index = descriptor;
|
||||
interface->mac_api->mlme_req(interface->mac_api, MLME_SET, &set_req);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void mac_helper_security_key_swap_next_to_default(protocol_interface_info_entry_t *interface)
|
||||
{
|
||||
|
|
|
@ -67,10 +67,18 @@ uint8_t mac_helper_default_key_index_get(struct protocol_interface_info_entry *i
|
|||
|
||||
int8_t mac_helper_security_default_key_set(struct protocol_interface_info_entry *interface, const uint8_t *key, uint8_t id, uint8_t keyid_mode);
|
||||
|
||||
int8_t mac_helper_security_default_recv_key_set(struct protocol_interface_info_entry *interface, const uint8_t *key, uint8_t id, uint8_t keyid_mode);
|
||||
|
||||
int8_t mac_helper_security_auto_request_key_index_set(struct protocol_interface_info_entry *interface, uint8_t id);
|
||||
|
||||
int8_t mac_helper_security_next_key_set(struct protocol_interface_info_entry *interface, uint8_t *key, uint8_t id, uint8_t keyid_mode);
|
||||
|
||||
int8_t mac_helper_security_prev_key_set(struct protocol_interface_info_entry *interface, uint8_t *key, uint8_t id, uint8_t keyid_mode);
|
||||
|
||||
int8_t mac_helper_security_key_to_descriptor_set(struct protocol_interface_info_entry *interface, const uint8_t *key, uint8_t id, uint8_t descriptor);
|
||||
|
||||
int8_t mac_helper_security_key_descriptor_clear(struct protocol_interface_info_entry *interface, uint8_t descriptor);
|
||||
|
||||
void mac_helper_security_key_swap_next_to_default(struct protocol_interface_info_entry *interface);
|
||||
|
||||
int8_t mac_helper_security_pairwisekey_set(struct protocol_interface_info_entry *interface, const uint8_t *key, const uint8_t *mac_64, uint8_t key_attribute);
|
||||
|
|
|
@ -926,7 +926,7 @@ bool nd_ns_aro_handler(protocol_interface_info_entry_t *cur_interface, const uin
|
|||
|
||||
/* TODO - check hard upper limit on registrations? */
|
||||
if (ws_info(cur_interface) &&
|
||||
!ws_common_allow_child_registration(cur_interface)) {
|
||||
!ws_common_allow_child_registration(cur_interface, aro_out->eui64)) {
|
||||
aro_out->present = true;
|
||||
aro_out->status = ARO_FULL;
|
||||
return true;
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
#ifdef HAVE_THREAD_V2
|
||||
|
||||
void thread_address_registration_init(void);
|
||||
bool thread_address_registration_running(void);
|
||||
void thread_address_registration_deinit(void);
|
||||
|
||||
void thread_address_registration_timer_set(protocol_interface_info_entry_t *interface, uint16_t dua_delay_seconds, uint16_t mlr_refresh_seconds);
|
||||
|
@ -41,6 +42,7 @@ void thread_address_registration_timer(protocol_interface_info_entry_t *interfac
|
|||
#else
|
||||
|
||||
#define thread_address_registration_init(void)
|
||||
#define thread_address_registration_running(void)
|
||||
#define thread_address_registration_deinit(void)
|
||||
|
||||
#define thread_address_registration_timer_set(interface, dua_delay_seconds, mlr_refresh_seconds);
|
||||
|
|
|
@ -517,6 +517,34 @@ static int thread_border_relay_to_leader_cb(int8_t service_id, uint8_t source_ad
|
|||
}
|
||||
|
||||
#ifdef HAVE_THREAD_BORDER_ROUTER
|
||||
static bool thread_bbr_default_route_exists(struct protocol_interface_info_entry *cur, uint8_t prefix_ptr[8])
|
||||
{
|
||||
uint16_t rloc16 = mac_helper_mac16_address_get(cur);
|
||||
ns_list_foreach(thread_network_data_prefix_cache_entry_t, prefix, &cur->thread_info->networkDataStorage.localPrefixList) {
|
||||
|
||||
if (prefix_ptr &&
|
||||
(prefix->servicesPrefixLen != 64 ||
|
||||
memcmp(prefix_ptr, prefix->servicesPrefix, 8) != 0)) {
|
||||
// Only matching prefixes are counted
|
||||
continue;
|
||||
}
|
||||
|
||||
ns_list_foreach(thread_network_server_data_entry_t, br, &prefix->borderRouterList) {
|
||||
if (br->routerID == 0xfffe) {
|
||||
continue;
|
||||
}
|
||||
if (!br->P_default_route) {
|
||||
continue;
|
||||
}
|
||||
if (rloc16 != br->routerID) {
|
||||
// different default route exists
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool thread_bbr_i_host_prefix(struct protocol_interface_info_entry *cur, uint8_t prefix_ptr[8], uint8_t *br_count, bool *i_am_lowest)
|
||||
{
|
||||
bool i_host_this_prefix = false;
|
||||
|
@ -600,14 +628,15 @@ static void thread_bbr_network_data_send(thread_bbr_t *this, uint8_t prefix[8],
|
|||
this->br_info_published = true;
|
||||
}
|
||||
|
||||
static void thread_bbr_routing_enable(thread_bbr_t *this)
|
||||
static void thread_bbr_routing_enable(thread_bbr_t *this, bool multicast_routing_enabled)
|
||||
{
|
||||
if (this->routing_enabled) {
|
||||
return;
|
||||
}
|
||||
tr_info("br: enable routing");
|
||||
// Start multicast proxying
|
||||
multicast_fwd_set_forwarding(this->interface_id, true);
|
||||
// We do not enable multicast forwarding as there is other default router present in network
|
||||
multicast_fwd_set_forwarding(this->interface_id, multicast_routing_enabled);
|
||||
this->routing_enabled = true;
|
||||
}
|
||||
|
||||
|
@ -663,7 +692,13 @@ static void thread_bbr_status_check(thread_bbr_t *this, uint32_t seconds)
|
|||
|
||||
// Check from network data are we currently BR or not and change routing state
|
||||
if (this->br_hosted) {
|
||||
thread_bbr_routing_enable(this);
|
||||
|
||||
//If there is a default router present in any prefix other than us we do not forward multicast
|
||||
//This prevents multicasts to different interfaces where Thread Mesh is forwarder
|
||||
bool forward_multicast = !thread_bbr_default_route_exists(cur, NULL);
|
||||
thread_extension_bbr_mcast_fwd_check(cur->id, &forward_multicast);
|
||||
|
||||
thread_bbr_routing_enable(this, forward_multicast);
|
||||
} else {
|
||||
thread_bbr_routing_disable(this);
|
||||
}
|
||||
|
@ -896,6 +931,15 @@ int8_t thread_bbr_init(int8_t interface_id, uint16_t external_commisssioner_port
|
|||
return 0;
|
||||
}
|
||||
|
||||
int8_t thread_bbr_get_commissioner_service(int8_t interface_id)
|
||||
{
|
||||
thread_bbr_t *this = thread_bbr_find_by_interface(interface_id);
|
||||
if (!this) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return this->br_service_id;
|
||||
}
|
||||
void thread_bbr_delete(int8_t interface_id)
|
||||
{
|
||||
thread_bbr_t *this = thread_bbr_find_by_interface(interface_id);
|
||||
|
@ -1100,8 +1144,11 @@ int thread_bbr_start(int8_t interface_id, int8_t backbone_interface_id)
|
|||
// By default multicast forwarding is not enabled as it causes multicast loops
|
||||
multicast_fwd_set_forwarding(this->interface_id, false);
|
||||
|
||||
// Adjust BBR neighbor and destination cache size
|
||||
arm_nwk_ipv6_max_cache_entries(THREAD_BBR_IPV6_DESTINATION_CACHE_SIZE);
|
||||
// Configure BBR neighbour cache parameters
|
||||
arm_nwk_ipv6_neighbour_cache_configure(THREAD_BBR_IPV6_NEIGHBOUR_CACHE_SIZE,
|
||||
THREAD_BBR_IPV6_NEIGHBOUR_CACHE_SHORT_TERM,
|
||||
THREAD_BBR_IPV6_NEIGHBOUR_CACHE_LONG_TERM,
|
||||
THREAD_BBR_IPV6_NEIGHBOUR_CACHE_LIFETIME);
|
||||
|
||||
thread_extension_bbr_init(interface_id, backbone_interface_id);
|
||||
|
||||
|
@ -1125,6 +1172,7 @@ int thread_bbr_timeout_set(int8_t interface_id, uint32_t timeout_a, uint32_t tim
|
|||
#endif // HAVE_THREAD_BORDER_ROUTER
|
||||
}
|
||||
|
||||
|
||||
int thread_bbr_prefix_set(int8_t interface_id, uint8_t *prefix)
|
||||
{
|
||||
(void) interface_id;
|
||||
|
@ -1159,8 +1207,6 @@ int thread_bbr_validation_interface_address_set(int8_t interface_id, const uint8
|
|||
#endif // HAVE_THREAD_BORDER_ROUTER
|
||||
}
|
||||
|
||||
|
||||
|
||||
void thread_bbr_stop(int8_t interface_id)
|
||||
{
|
||||
(void) interface_id;
|
||||
|
|
|
@ -66,6 +66,13 @@ void thread_bbr_seconds_timer(int8_t interface_id, uint32_t tics);
|
|||
* \param interface_id current interface id
|
||||
*/
|
||||
int thread_bbr_commissioner_proxy_service_update(int8_t interface_id);
|
||||
/**
|
||||
* \brief get commissioner service id to add new services
|
||||
*
|
||||
* \param interface_id current interface id
|
||||
* \return service id or 0 if invalid
|
||||
*/
|
||||
int8_t thread_bbr_get_commissioner_service(int8_t interface_id);
|
||||
|
||||
#else
|
||||
#define thread_bbr_init(interface_id, external_commisssioner_port)
|
||||
|
|
|
@ -888,6 +888,7 @@ void thread_interface_init(protocol_interface_info_entry_t *cur)
|
|||
thread_discovery_reset(cur->id);
|
||||
thread_routing_set_mesh_callbacks(cur);
|
||||
dhcp_client_init(cur->id);
|
||||
dhcp_client_configure(cur->id, false, false, false);
|
||||
thread_management_client_init(cur->id);
|
||||
thread_address_registration_init();
|
||||
cur->mpl_seed_id_mode = MULTICAST_MPL_SEED_ID_MAC_SHORT;
|
||||
|
@ -945,6 +946,31 @@ static void thread_interface_bootsrap_mode_init(protocol_interface_info_entry_t
|
|||
tr_debug("Set End node Mode");
|
||||
cur->thread_info->thread_device_mode = THREAD_DEVICE_MODE_END_DEVICE;
|
||||
}
|
||||
|
||||
if (cur->thread_info->thread_device_mode == THREAD_DEVICE_MODE_ROUTER) {
|
||||
// set router neighbour cache
|
||||
ipv6_neighbour_cache_configure(THREAD_ROUTER_IPV6_NEIGHBOUR_CACHE_SIZE,
|
||||
THREAD_ROUTER_IPV6_NEIGHBOUR_CACHE_SHORT_TERM,
|
||||
THREAD_ROUTER_IPV6_NEIGHBOUR_CACHE_LONG_TERM,
|
||||
THREAD_ROUTER_IPV6_NEIGHBOUR_CACHE_LIFETIME);
|
||||
// set router destination cache
|
||||
ipv6_destination_cache_configure(THREAD_ROUTER_IPV6_DESTINATION_CACHE_SIZE,
|
||||
THREAD_ROUTER_IPV6_DESTINATION_CACHE_SHORT_TERM,
|
||||
THREAD_ROUTER_IPV6_DESTINATION_CACHE_LONG_TERM,
|
||||
THREAD_ROUTER_IPV6_DESTINATION_CACHE_LIFETIME);
|
||||
} else {
|
||||
// device is some sort of end device
|
||||
ipv6_neighbour_cache_configure(THREAD_END_DEVICE_IPV6_NEIGHBOUR_CACHE_SIZE,
|
||||
THREAD_END_DEVICE_IPV6_NEIGHBOUR_CACHE_SHORT_TERM,
|
||||
THREAD_END_DEVICE_IPV6_NEIGHBOUR_CACHE_LONG_TERM,
|
||||
THREAD_END_DEVICE_IPV6_NEIGHBOUR_CACHE_LIFETIME);
|
||||
|
||||
ipv6_destination_cache_configure(THREAD_END_DEVICE_IPV6_DESTINATION_CACHE_SIZE,
|
||||
THREAD_END_DEVICE_IPV6_DESTINATION_CACHE_SHORT_TERM,
|
||||
THREAD_END_DEVICE_IPV6_DESTINATION_CACHE_LONG_TERM,
|
||||
THREAD_END_DEVICE_IPV6_DESTINATION_CACHE_LIFETIME);
|
||||
}
|
||||
|
||||
cur->thread_info->thread_attached_state = THREAD_STATE_NETWORK_DISCOVER;
|
||||
}
|
||||
|
||||
|
@ -2540,7 +2566,7 @@ int thread_bootstrap_network_data_process(protocol_interface_info_entry_t *cur,
|
|||
} else {
|
||||
tr_debug("SLAAC address set as NOT preferred.");
|
||||
}
|
||||
addr_set_preferred_lifetime(cur, e, genericService.P_preferred ? 0xfffffffff : 0);
|
||||
addr_set_preferred_lifetime(cur, e, genericService.P_preferred ? 0xffffffff : 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -988,11 +988,7 @@ void thread_seconds_timer(protocol_interface_info_entry_t *cur, uint32_t ticks)
|
|||
thread_resolution_client_timer(cur->id, ticks);
|
||||
thread_key_switch_timer(cur, ticks);
|
||||
thread_child_update_req_timer(cur, ticks);
|
||||
|
||||
if (!thread_bootstrap_should_register_address(cur)) {
|
||||
/* Only FTD refreshes the address registration timer */
|
||||
thread_address_registration_timer(cur, ticks);
|
||||
}
|
||||
thread_address_registration_timer(cur, ticks);
|
||||
|
||||
if (thread_attach_ready(cur) != 0) {
|
||||
return;
|
||||
|
|
|
@ -192,6 +192,7 @@ typedef struct thread_connectivity_s {
|
|||
typedef struct thread_parent_info_s {
|
||||
uint8_t mac64[8];
|
||||
uint16_t shortAddress;
|
||||
uint16_t version;
|
||||
uint8_t router_id;
|
||||
uint8_t pathCostToLeader;
|
||||
bool childUpdatePending: 1;
|
||||
|
|
|
@ -326,11 +326,34 @@
|
|||
*/
|
||||
#define THREAD_BBR_ROUTER_ID_REQUEST_STATUS THREAD_COAP_STATUS_TLV_HAVE_CHILD_ID_REQUEST
|
||||
|
||||
/*
|
||||
* Number of destination and neighbor cache entries assuming 250 thread devices (worst case) connecting to cloud service.
|
||||
/* Border Router IPv6 neighbour and destination cache configuration
|
||||
* Number of neighbor cache entries assuming 250 thread devices (worst case) connecting to cloud service.
|
||||
* Six entries reserved for backbone devices.
|
||||
*/
|
||||
#define THREAD_BBR_IPV6_DESTINATION_CACHE_SIZE 256
|
||||
#define THREAD_BBR_IPV6_NEIGHBOUR_CACHE_SIZE 256
|
||||
#define THREAD_BBR_IPV6_NEIGHBOUR_CACHE_SHORT_TERM 128
|
||||
#define THREAD_BBR_IPV6_NEIGHBOUR_CACHE_LONG_TERM 32
|
||||
#define THREAD_BBR_IPV6_NEIGHBOUR_CACHE_LIFETIME 600
|
||||
|
||||
/* Router IPv6 neighbour and destination cache configuration */
|
||||
#define THREAD_ROUTER_IPV6_NEIGHBOUR_CACHE_SIZE 128
|
||||
#define THREAD_ROUTER_IPV6_NEIGHBOUR_CACHE_SHORT_TERM 64
|
||||
#define THREAD_ROUTER_IPV6_NEIGHBOUR_CACHE_LONG_TERM 8
|
||||
#define THREAD_ROUTER_IPV6_NEIGHBOUR_CACHE_LIFETIME 600
|
||||
#define THREAD_ROUTER_IPV6_DESTINATION_CACHE_SIZE 32
|
||||
#define THREAD_ROUTER_IPV6_DESTINATION_CACHE_SHORT_TERM 16
|
||||
#define THREAD_ROUTER_IPV6_DESTINATION_CACHE_LONG_TERM 4
|
||||
#define THREAD_ROUTER_IPV6_DESTINATION_CACHE_LIFETIME 600
|
||||
|
||||
/* End device IPv6 neighbour and destination cache configuration */
|
||||
#define THREAD_END_DEVICE_IPV6_NEIGHBOUR_CACHE_SIZE 32
|
||||
#define THREAD_END_DEVICE_IPV6_NEIGHBOUR_CACHE_SHORT_TERM 16
|
||||
#define THREAD_END_DEVICE_IPV6_NEIGHBOUR_CACHE_LONG_TERM 4
|
||||
#define THREAD_END_DEVICE_IPV6_NEIGHBOUR_CACHE_LIFETIME 600
|
||||
#define THREAD_END_DEVICE_IPV6_DESTINATION_CACHE_SIZE 16
|
||||
#define THREAD_END_DEVICE_IPV6_DESTINATION_CACHE_SHORT_TERM 8
|
||||
#define THREAD_END_DEVICE_IPV6_DESTINATION_CACHE_LONG_TERM 4
|
||||
#define THREAD_END_DEVICE_IPV6_DESTINATION_CACHE_LIFETIME 600
|
||||
|
||||
/*
|
||||
* Timeout to solicit address from DHCP if previous request fails.
|
||||
|
|
|
@ -49,6 +49,7 @@ void thread_extension_mtd_service_register(protocol_interface_info_entry_t *cur)
|
|||
void thread_extension_network_data_process(struct protocol_interface_info_entry *cur);
|
||||
int thread_extension_primary_bbr_get(struct protocol_interface_info_entry *cur, uint8_t *addr_ptr, uint8_t *seq_ptr, uint32_t *timer1_ptr, uint32_t *timer2_ptr);
|
||||
void thread_extension_address_registration(struct protocol_interface_info_entry *interface, const uint8_t *addr, const uint8_t *child_mac64, bool refresh_child_entry, bool duplicate_child_detected);
|
||||
void thread_extension_child_address_registration_response_process(struct protocol_interface_info_entry *interface);
|
||||
void thread_extension_dua_address_generate(protocol_interface_info_entry_t *cur, const uint8_t *domain_prefix, uint8_t domain_prefix_len);
|
||||
void thread_extension_aloc_generate(struct protocol_interface_info_entry *cur);
|
||||
bool thread_extension_aloc_map(protocol_interface_info_entry_t *cur, uint16_t *addr16);
|
||||
|
@ -62,11 +63,13 @@ int thread_extension_service_init(protocol_interface_info_entry_t *cur);
|
|||
void thread_extension_addr_ntf_send(struct protocol_interface_info_entry *cur, uint8_t *destination_address, const uint8_t *addr_data_ptr, uint8_t bbr_status);
|
||||
#ifdef HAVE_THREAD_ROUTER
|
||||
bool thread_extension_joining_enabled(int8_t interface_id);
|
||||
bool thread_extension_is_reed_upgrade_allowed(protocol_interface_info_entry_t *cur);
|
||||
uint8_t thread_extension_discover_response_len(protocol_interface_info_entry_t *cur);
|
||||
uint8_t *thread_extension_discover_response_write(protocol_interface_info_entry_t *cur, uint8_t *ptr);
|
||||
|
||||
#else
|
||||
#define thread_extension_joining_enabled(interface_id) (false)
|
||||
#define thread_extension_is_reed_upgrade_allowed(cur) (true)
|
||||
#define thread_extension_discover_response_len(cur) (0)
|
||||
#define thread_extension_discover_response_write(cur, ptr) (ptr)
|
||||
#endif //HAVE_THREAD_ROUTER
|
||||
|
@ -78,10 +81,12 @@ uint8_t *thread_extension_discover_response_write(protocol_interface_info_entry_
|
|||
#define thread_extension_network_data_process(cur) ((void) 0)
|
||||
#define thread_extension_primary_bbr_get(cur,addr_ptr,seq_ptr,timer1_ptr, timer2_ptr) (-1)
|
||||
#define thread_extension_address_registration(interface,addr,child_mac64,refresh_child_entry,duplicate_child_detected) ((void) 0)
|
||||
#define thread_extension_child_address_registration_response_process(interface) ((void) 0)
|
||||
#define thread_extension_aloc_generate(cur) ((void) 0)
|
||||
#define thread_extension_aloc_map(cur, addr16) (false)
|
||||
#define thread_extension_mcast_subscrition_change(interface) ((void) 0)
|
||||
#define thread_extension_enabled(cur) (false)
|
||||
#define thread_extension_is_reed_upgrade_allowed(cur) (true)
|
||||
#define thread_extension_version_check(version) (false)
|
||||
#define thread_extension_discover_response_read(nwk_info, discover_response_tlv, data_ptr, data_len) ((void) 0)
|
||||
#define thread_extension_discover_response_tlv_write(data, version, securityPolicy) ((void) 0)
|
||||
|
|
|
@ -47,7 +47,6 @@ typedef struct thread_pbbr_dua_info {
|
|||
} thread_pbbr_dua_info_t;
|
||||
|
||||
#if defined(HAVE_THREAD_V2) && defined(HAVE_THREAD_BORDER_ROUTER)
|
||||
|
||||
int8_t thread_extension_bbr_init(int8_t interface_id, int8_t backbone_interface_id);
|
||||
void thread_extension_bbr_delete(int8_t interface_id);
|
||||
bool thread_extension_bbr_nd_query_process(protocol_interface_info_entry_t *cur, const uint8_t *target_addr, uint16_t rloc);
|
||||
|
@ -58,6 +57,10 @@ int thread_extension_bbr_address_set(int8_t interface_id, const uint8_t *addr_pt
|
|||
void thread_extension_bbr_route_update(protocol_interface_info_entry_t *cur);
|
||||
int thread_extension_bbr_prefix_set(int8_t interface_id, uint8_t *prefix);
|
||||
void thread_extension_bbr_old_partition_data_clean(int8_t interface_id);
|
||||
void thread_extension_bbr_status_override_get(uint8_t *dua_status, uint8_t *dua_count, uint8_t *ba_failure_count);
|
||||
void thread_extension_bbr_status_override_set(uint8_t dua_status, uint8_t dua_count, uint8_t ba_failure_count);
|
||||
void thread_extension_status_override_count_set(uint8_t value);
|
||||
void thread_extension_bbr_mcast_fwd_check(int8_t interface_id, bool *multicast_fwd);
|
||||
|
||||
|
||||
#else
|
||||
|
@ -72,6 +75,10 @@ void thread_extension_bbr_old_partition_data_clean(int8_t interface_id);
|
|||
#define thread_extension_bbr_sequence_number_set(interface_id, seq_number) (-1)
|
||||
#define thread_extension_bbr_prefix_set(interface_id, prefix) 0
|
||||
#define thread_extension_bbr_old_partition_data_clean(interface_id)
|
||||
#define thread_extension_bbr_status_override_get(dua_status, dua_count, ba_failure_count);
|
||||
#define thread_extension_bbr_status_override_set(dua_status, dua_count, ba_failure_count);
|
||||
#define thread_extension_status_override_count_set(value)
|
||||
#define thread_extension_bbr_mcast_fwd_check(interface_id, multicast_fwd)
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
|
||||
/*
|
||||
* Copyright (c) 2017-2019, Arm Limited and affiliates.
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
|
@ -38,6 +39,7 @@ extern "C" {
|
|||
#define thread_extension_bootstrap_free(cur);
|
||||
#define thread_extension_bootstrap_device_certificate_set(cur, device_certificate_ptr, device_certificate_len, priv_key_ptr, priv_key_len) (-1)
|
||||
#define thread_extension_bootstrap_network_certificate_set(cur, domain_certificate_ptr, domain_certificate_len) (-1)
|
||||
#define thread_extension_bootstrap_network_certificate_available(cur) (false)
|
||||
#define thread_extension_bootstrap_network_private_key_set(cur, priv_key_ptr, priv_key_len) (-1)
|
||||
#define thread_extension_bootstrap_thread_name_set(cur, thread_name) (-1)
|
||||
#define thread_extension_bootstrap_commission_start(cur, parent_address, port, done_cb) (-1)
|
||||
|
|
|
@ -897,6 +897,7 @@ static void thread_mle_child_request_receive_cb(int8_t interface_id, mle_message
|
|||
parent->shortAddress = scan_result->shortAddress;
|
||||
parent->router_id = (scan_result->shortAddress >> 10);
|
||||
memcpy(parent->mac64, scan_result->mac64, 8);
|
||||
parent->version = scan_result->version;
|
||||
//Check Network Data TLV
|
||||
if (networkDataTlv.tlvType == MLE_TYPE_NETWORK_DATA) {
|
||||
thread_bootstrap_network_data_save(cur, &leaderData, networkDataTlv.dataPtr, networkDataTlv.tlvLen);
|
||||
|
|
|
@ -58,6 +58,7 @@
|
|||
#include "thread_network_synch.h"
|
||||
#include "thread_network_data_lib.h"
|
||||
#include "thread_joiner_application.h"
|
||||
#include "thread_extension.h"
|
||||
#include "6LoWPAN/Thread/thread_extension_bootstrap.h"
|
||||
#include "mac_api.h"
|
||||
#include "6LoWPAN/MAC/mac_helper.h"
|
||||
|
@ -318,6 +319,7 @@ static link_configuration_s *link_configuration_create(void)
|
|||
}
|
||||
memset(this, 0, sizeof(link_configuration_s));
|
||||
this->securityPolicy = SECURITY_POLICY_ALL_SECURITY; // Set all default values ('1') for security policy flags
|
||||
this->securityPolicyExt = SECURITY_POLICY_ALL_SECURITY; // Set all default values
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -345,6 +347,7 @@ static void link_configuration_copy(link_configuration_s *this, link_configurati
|
|||
this->panId = configuration_ptr->panId;
|
||||
this->rfChannel = configuration_ptr->rfChannel;
|
||||
this->securityPolicy = configuration_ptr->securityPolicy;
|
||||
this->securityPolicyExt = configuration_ptr->securityPolicyExt;
|
||||
this->timestamp = configuration_ptr->timestamp;
|
||||
return;
|
||||
}
|
||||
|
@ -396,10 +399,14 @@ static int link_configuration_update(link_configuration_s *link_configuration, u
|
|||
if (thread_meshcop_tlv_find(msg_ptr, msg_len, MESHCOP_TLV_PSKC, &ptr) >= 16) {
|
||||
memcpy(link_configuration->PSKc, ptr, 16);
|
||||
}
|
||||
|
||||
if (thread_meshcop_tlv_find(msg_ptr, msg_len, MESHCOP_TLV_SECURITY_POLICY, &ptr) >= 3) {
|
||||
uint16_t tlv_len = thread_meshcop_tlv_find(msg_ptr, msg_len, MESHCOP_TLV_SECURITY_POLICY, &ptr);
|
||||
if (tlv_len >= 3) {
|
||||
link_configuration->securityPolicyExt = SECURITY_POLICY_ALL_SECURITY;
|
||||
link_configuration->securityPolicy = ptr[2];
|
||||
link_configuration->key_rotation = common_read_16_bit(ptr);
|
||||
if (tlv_len > 3) {
|
||||
link_configuration->securityPolicyExt = ptr[3];
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -512,8 +519,8 @@ static void device_configuration_validate(device_configuration_s *this)
|
|||
this->vendor_stack_version[1] = (uint8_t)(THREAD_ARM_OUI >> 8);
|
||||
this->vendor_stack_version[2] = (uint8_t)(THREAD_ARM_OUI);
|
||||
this->vendor_stack_version[3] = (uint8_t)(THREAD_BUILD_NUMBER >> 4);
|
||||
this->vendor_stack_version[4] = (uint8_t)(((THREAD_BUILD_NUMBER & 0x0f) << 4) || THREAD_REVISION_NUMBER);
|
||||
this->vendor_stack_version[5] = (uint8_t)((THREAD_VERSION_MIN << 4) || THREAD_VERSION_MAJ);
|
||||
this->vendor_stack_version[4] = (uint8_t)(((THREAD_BUILD_NUMBER & 0x0f) << 4) | THREAD_REVISION_NUMBER);
|
||||
this->vendor_stack_version[5] = (uint8_t)((THREAD_VERSION_MIN << 4) | THREAD_VERSION_MAJ);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -710,7 +717,7 @@ static void configuration_set_copy_mandatory(configuration_set_t *destination_pt
|
|||
tr_debug("mandatory TLVs needed: %s", trace_array(tlv_list, tlv_list_len));
|
||||
configuration_set_add_fields(destination_ptr, source_ptr->data, source_ptr->length, tlv_list, tlv_list_len);
|
||||
}
|
||||
static void configuration_set_generate(configuration_set_t *destination_ptr, link_configuration_s *configuration_ptr)
|
||||
static void configuration_set_generate(int8_t interface_id, configuration_set_t *destination_ptr, link_configuration_s *configuration_ptr)
|
||||
{
|
||||
uint8_t *response_ptr;
|
||||
|
||||
|
@ -733,11 +740,18 @@ static void configuration_set_generate(configuration_set_t *destination_ptr, lin
|
|||
response_ptr = thread_tmfcop_tlv_data_write(response_ptr, MESHCOP_TLV_PSKC, 16, configuration_ptr->PSKc);
|
||||
response_ptr = thread_tmfcop_tlv_data_write(response_ptr, MESHCOP_TLV_NETWORK_NAME, stringlen((char *)&configuration_ptr->name, 16), configuration_ptr->name);
|
||||
*response_ptr++ = MESHCOP_TLV_SECURITY_POLICY; // type
|
||||
*response_ptr++ = 3; // length
|
||||
response_ptr = common_write_16_bit(configuration_ptr->key_rotation, response_ptr);
|
||||
*response_ptr++ = configuration_ptr->securityPolicy;
|
||||
protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(interface_id);
|
||||
if (thread_extension_version_check(thread_info(cur)->version)) {
|
||||
*response_ptr++ = 4; // length
|
||||
response_ptr = common_write_16_bit(configuration_ptr->key_rotation, response_ptr);
|
||||
*response_ptr++ = configuration_ptr->securityPolicy;
|
||||
*response_ptr++ = configuration_ptr->securityPolicyExt;
|
||||
} else {
|
||||
*response_ptr++ = 3; // length
|
||||
response_ptr = common_write_16_bit(configuration_ptr->key_rotation, response_ptr);
|
||||
*response_ptr++ = configuration_ptr->securityPolicy;
|
||||
}
|
||||
response_ptr = thread_tmfcop_tlv_data_write_uint64(response_ptr, MESHCOP_TLV_ACTIVE_TIME_STAMP, configuration_ptr->timestamp);
|
||||
|
||||
destination_ptr->length = response_ptr - destination_ptr->data;
|
||||
}
|
||||
|
||||
|
@ -859,7 +873,7 @@ int thread_joiner_application_init(int8_t interface_id, device_configuration_s *
|
|||
//If no master key or PSKc set we assume not valid configuration for thread network others may be possible to be 0
|
||||
//This allows some configurations to be set statically for testing purposes
|
||||
this->configuration_valid = true;
|
||||
configuration_set_generate(this->active_configuration_ptr, this->configuration_ptr);
|
||||
configuration_set_generate(this->interface_id, this->active_configuration_ptr, this->configuration_ptr);
|
||||
}
|
||||
}
|
||||
// Always load link configuration from bootstrap state machine. NVM overrides Static configuration
|
||||
|
@ -1533,7 +1547,7 @@ int thread_joiner_application_link_configuration_store(int8_t interface_id, link
|
|||
}
|
||||
|
||||
thread_joiner_application_validate_settings(this);// Generate all random information
|
||||
configuration_set_generate(this->active_configuration_ptr, link_config);
|
||||
configuration_set_generate(this->interface_id, this->active_configuration_ptr, link_config);
|
||||
link_configuration_update(this->configuration_ptr, this->active_configuration_ptr->data, this->active_configuration_ptr->length);
|
||||
this->configuration_ptr->key_sequence = link_config->key_sequence;
|
||||
this->configuration_valid = true;
|
||||
|
|
|
@ -744,6 +744,7 @@ static bool thread_address_registration_tlv_check(protocol_interface_info_entry_
|
|||
}
|
||||
}
|
||||
}
|
||||
thread_extension_child_address_registration_response_process(cur);
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
|
|
|
@ -67,6 +67,7 @@
|
|||
#include "6LoWPAN/Thread/thread_tmfcop_lib.h"
|
||||
#include "6LoWPAN/Thread/thread_nvm_store.h"
|
||||
#include "6LoWPAN/Thread/thread_neighbor_class.h"
|
||||
#include "6LoWPAN/Thread/thread_extension_bootstrap.h"
|
||||
#include "thread_management_if.h"
|
||||
#include "Common_Protocols/ipv6.h"
|
||||
#include "Common_Protocols/icmpv6.h"
|
||||
|
@ -1484,6 +1485,12 @@ void thread_router_bootstrap_mle_receive_cb(int8_t interface_id, mle_message_t *
|
|||
return;
|
||||
}
|
||||
|
||||
// check if security policy prevents sending of parent response
|
||||
if (!thread_extension_is_reed_upgrade_allowed(cur)) {
|
||||
tr_debug("Security policy prevents parent response; drop packet");
|
||||
return;
|
||||
}
|
||||
|
||||
if (thread_am_reed(cur)) {
|
||||
// If we are in REED mode and receive PARENT_REQ from our parent, don't send response.
|
||||
if (thread_router_parent_address_check(cur, mle_msg->packet_src_address)) {
|
||||
|
@ -1597,8 +1604,14 @@ void thread_router_bootstrap_mle_receive_cb(int8_t interface_id, mle_message_t *
|
|||
return;
|
||||
}
|
||||
|
||||
// If we are in REED mode and receive child ID request from our parent, call connection error.
|
||||
// check if security policy prevents sending of child id response
|
||||
if (!thread_extension_is_reed_upgrade_allowed(cur)) {
|
||||
tr_debug("Security policy prevents child id response; drop packet");
|
||||
return;
|
||||
}
|
||||
|
||||
if (thread_am_reed(cur)) {
|
||||
// If we are in REED mode and receive child ID request from our parent, call connection error.
|
||||
if (thread_router_parent_address_check(cur, mle_msg->packet_src_address)) {
|
||||
tr_debug("Child ID req from own parent -> connection error");
|
||||
entry_temp = mac_neighbor_entry_get_by_ll64(mac_neighbor_info(cur), mle_msg->packet_src_address, false, NULL);
|
||||
|
@ -2226,6 +2239,10 @@ bool thread_router_bootstrap_reed_upgrade(protocol_interface_info_entry_t *cur)
|
|||
return false;
|
||||
}
|
||||
|
||||
if (!thread_extension_is_reed_upgrade_allowed(cur)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (thread_am_router(cur)) {
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -49,6 +49,7 @@
|
|||
#include "6LoWPAN/Thread/thread_discovery.h"
|
||||
#include "6LoWPAN/Thread/thread_nvm_store.h"
|
||||
#include "6LoWPAN/Thread/thread_extension_bootstrap.h"
|
||||
#include "6LoWPAN/Thread/thread_extension_bbr.h"
|
||||
#include "6LoWPAN/Thread/thread_neighbor_class.h"
|
||||
#include "MLE/mle.h"
|
||||
#include "thread_meshcop_lib.h"
|
||||
|
@ -639,6 +640,23 @@ int thread_test_version_set(int8_t interface_id, uint8_t version)
|
|||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
int thread_test_pbbr_response_override_set(int8_t interface_id, uint8_t dua_status, uint8_t dua_count, uint8_t ba_failure_count)
|
||||
{
|
||||
#ifdef HAVE_THREAD
|
||||
(void)interface_id;
|
||||
thread_extension_bbr_status_override_set(dua_status, dua_count, ba_failure_count);
|
||||
return 0;
|
||||
|
||||
#else
|
||||
(void)interface_id;
|
||||
(void)dua_status;
|
||||
(void)dua_count;
|
||||
(void)ba_failure_count;
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
int thread_test_router_selection_jitter_set(int8_t interface_id, uint32_t jitter)
|
||||
{
|
||||
#ifdef HAVE_THREAD
|
||||
|
|
|
@ -35,8 +35,11 @@
|
|||
#include "net_rpl.h"
|
||||
#include "Service_Libs/nd_proxy/nd_proxy.h"
|
||||
#include "6LoWPAN/ws/ws_bbr_api_internal.h"
|
||||
#include "6LoWPAN/ws/ws_pae_controller.h"
|
||||
#include "DHCPv6_Server/DHCPv6_server_service.h"
|
||||
|
||||
#include "ws_bbr_api.h"
|
||||
|
||||
#define TRACE_GROUP "wsbs"
|
||||
|
||||
#define RPL_INSTANCE_ID 1
|
||||
|
@ -49,6 +52,7 @@
|
|||
*
|
||||
*/
|
||||
static int8_t backbone_interface_id = -1; // BBR backbone information
|
||||
static uint16_t configuration = BBR_ULA_C | BBR_GUA_C | BBR_GUA_ROUTE;
|
||||
|
||||
static uint8_t static_dodag_prefix[8] = {0xfd, 0x00, 0x61, 0x72, 0x6d};
|
||||
static uint8_t static_ula_address[16] = {0};
|
||||
|
@ -109,15 +113,10 @@ static void ws_bbr_rpl_root_start(uint8_t *dodag_id)
|
|||
tr_err("RPL dodag init failed");
|
||||
return;
|
||||
}
|
||||
memcpy(static_dodag_id, dodag_id, 16);
|
||||
|
||||
// RPL memory limits set larger for Border router
|
||||
rpl_control_set_memory_limits(64 * 1024, 0);
|
||||
|
||||
uint8_t t_flags = PIO_A;
|
||||
|
||||
rpl_control_update_dodag_prefix(protocol_6lowpan_rpl_root_dodag, dodag_id, 64, t_flags, 7200, 7200, false);
|
||||
rpl_control_update_dodag_route(protocol_6lowpan_rpl_root_dodag, dodag_id, 64, 0x18, 7200, false);
|
||||
// Save configured static id to check for changes later
|
||||
memcpy(static_dodag_id, dodag_id, 16);
|
||||
}
|
||||
|
||||
static void ws_bbr_rpl_root_stop(void)
|
||||
|
@ -130,6 +129,17 @@ static void ws_bbr_rpl_root_stop(void)
|
|||
memset(global_dodag_id, 0, 16);
|
||||
}
|
||||
|
||||
static void ws_bbr_ula_prefix_enable(uint8_t *dodag_id)
|
||||
{
|
||||
tr_info("RPL ula prefix start");
|
||||
|
||||
uint8_t t_flags = PIO_A;
|
||||
|
||||
rpl_control_update_dodag_prefix(protocol_6lowpan_rpl_root_dodag, dodag_id, 64, t_flags, 7200, 7200, false);
|
||||
rpl_control_update_dodag_route(protocol_6lowpan_rpl_root_dodag, dodag_id, 64, 0x18, 7200, false);
|
||||
}
|
||||
|
||||
|
||||
static int ws_border_router_proxy_validate(int8_t interface_id, uint8_t *address)
|
||||
{
|
||||
|
||||
|
@ -170,12 +180,13 @@ static int ws_bbr_static_ula_create(protocol_interface_info_entry_t *cur)
|
|||
tr_info("BBR generate ula prefix");
|
||||
|
||||
// This address is only used if no other address available.
|
||||
if_address_entry_t *add_entry = icmpv6_slaac_address_add(cur, static_dodag_prefix, 64, 0xffffffff, 0, true, SLAAC_IID_FIXED);
|
||||
if_address_entry_t *add_entry = icmpv6_slaac_address_add(cur, static_dodag_prefix, 64, 0xffffffff, 0xffffffff, true, SLAAC_IID_FIXED);
|
||||
if (!add_entry) {
|
||||
return -1;
|
||||
}
|
||||
memcpy(static_ula_address, add_entry->address, 16);
|
||||
tr_info("BBR generate ula prefix addr %s", trace_ipv6(static_ula_address));
|
||||
addr_policy_table_add_entry(static_dodag_prefix, 64, 2, WS_NON_PREFFRED_LABEL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -266,6 +277,32 @@ 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)
|
||||
{
|
||||
uint8_t ll[16];
|
||||
memcpy(ll, ADDR_LINK_LOCAL_PREFIX, 8);
|
||||
memcpy(&ll[8], cur->mac, 8);
|
||||
ll[8] ^= 2;
|
||||
|
||||
tr_debug("DHCP server activate %s", trace_ipv6(global_id));
|
||||
|
||||
if (DHCPv6_server_service_init(cur->id, global_id, cur->mac, DHCPV6_DUID_HARDWARE_IEEE_802_NETWORKS_TYPE) != 0) {
|
||||
tr_error("DHCPv6 Server create fail");
|
||||
return;
|
||||
}
|
||||
DHCPv6_server_service_callback_set(cur->id, global_id, NULL, wisun_dhcp_address_add_cb);
|
||||
|
||||
DHCPv6_server_service_set_address_autonous_flag(cur->id, global_id, true);
|
||||
DHCPv6_server_service_set_address_validlifetime(cur->id, global_id, 7200);
|
||||
|
||||
ws_dhcp_client_address_request(cur, global_id, ll);
|
||||
}
|
||||
static void ws_bbr_dhcp_server_stop(protocol_interface_info_entry_t *cur, uint8_t *global_id)
|
||||
{
|
||||
tr_debug("DHCP server deactivate %s", trace_ipv6(global_id));
|
||||
DHCPv6_server_service_delete(cur->id, global_id, false);
|
||||
|
||||
}
|
||||
|
||||
static void ws_bbr_rpl_status_check(protocol_interface_info_entry_t *cur)
|
||||
{
|
||||
|
@ -277,56 +314,73 @@ static void ws_bbr_rpl_status_check(protocol_interface_info_entry_t *cur)
|
|||
|
||||
ws_bbr_dodag_get(cur, static_id, global_id);
|
||||
|
||||
// Check if we need to wait for Global ID
|
||||
if (configuration & BBR_GUA_WAIT) {
|
||||
if (memcmp(global_dodag_id, ADDR_UNSPECIFIED, 16) == 0 &&
|
||||
memcmp(global_id, ADDR_UNSPECIFIED, 16) == 0) {
|
||||
// We need to wait for Global connectivity to start anything
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (memcmp(static_dodag_id, static_id, 16) != 0) {
|
||||
// Static id updated or first setup
|
||||
ws_bbr_rpl_root_start(static_id);
|
||||
if (configuration & BBR_ULA_C) {
|
||||
// Start static ULA prefix and routing always
|
||||
ws_bbr_ula_prefix_enable(static_id);
|
||||
}
|
||||
}
|
||||
|
||||
if (memcmp(global_dodag_id, global_id, 16) != 0) {
|
||||
// Global prefix changed
|
||||
if (memcmp(global_dodag_id, ADDR_UNSPECIFIED, 16) != 0) {
|
||||
// TODO remove old global prefix
|
||||
tr_info("RPL GUA deactivate %s", trace_ipv6(global_dodag_id));
|
||||
|
||||
rpl_control_update_dodag_prefix(protocol_6lowpan_rpl_root_dodag, static_dodag_id, 64, PIO_A, 7200, 7200, false);
|
||||
rpl_control_update_dodag_route(protocol_6lowpan_rpl_root_dodag, static_dodag_id, 64, 0x18, 7200, false);
|
||||
|
||||
// Old backbone information is deleted after 120 seconds
|
||||
rpl_control_update_dodag_route(protocol_6lowpan_rpl_root_dodag, NULL, 0, 0, 120, true);
|
||||
rpl_control_update_dodag_prefix(protocol_6lowpan_rpl_root_dodag, global_dodag_id, 64, 0, 120, 0, true);
|
||||
rpl_control_update_dodag_route(protocol_6lowpan_rpl_root_dodag, global_dodag_id, 64, 0, 120, true);
|
||||
rpl_control_update_dodag_route(protocol_6lowpan_rpl_root_dodag, NULL, 0, 0, 0, true);
|
||||
rpl_control_update_dodag_prefix(protocol_6lowpan_rpl_root_dodag, global_dodag_id, 64, 0, 0, 0, true);
|
||||
rpl_control_update_dodag_route(protocol_6lowpan_rpl_root_dodag, global_dodag_id, 64, 0, 0, true);
|
||||
ipv6_route_add_with_info(global_dodag_id, 64, backbone_interface_id, NULL, ROUTE_THREAD_BBR, NULL, 0, 120, 0);
|
||||
DHCPv6_server_service_delete(cur->id, global_dodag_id, false);
|
||||
|
||||
// Set old addresses to deferred and timeout
|
||||
ws_dhcp_client_address_delete(cur, global_dodag_id);
|
||||
ws_bbr_dhcp_server_stop(cur, global_dodag_id);
|
||||
}
|
||||
// TODO add global prefix
|
||||
if (memcmp(global_id, ADDR_UNSPECIFIED, 16) != 0) {
|
||||
//DHCPv6 Server set here
|
||||
//Interface LL64 address
|
||||
uint8_t ll[16];
|
||||
memcpy(ll, ADDR_LINK_LOCAL_PREFIX, 8);
|
||||
memcpy(&ll[8], cur->mac, 8);
|
||||
ll[8] ^= 2;
|
||||
|
||||
if (DHCPv6_server_service_init(cur->id, global_id, cur->mac, DHCPV6_DUID_HARDWARE_IEEE_802_NETWORKS_TYPE) != 0) {
|
||||
tr_error("DHCPv6 Server create fail");
|
||||
return;
|
||||
}
|
||||
DHCPv6_server_service_callback_set(cur->id, global_id, NULL, wisun_dhcp_address_add_cb);
|
||||
|
||||
DHCPv6_server_service_set_address_autonous_flag(cur->id, global_id, true);
|
||||
DHCPv6_server_service_set_address_validlifetime(cur->id, global_id, 7200);
|
||||
|
||||
tr_info("RPL GUA activate %s", trace_ipv6(global_id));
|
||||
ws_dhcp_client_address_request(cur, global_id, ll);
|
||||
//DHCPv6 Server flags set 0 by default
|
||||
uint8_t t_flags = 0;
|
||||
|
||||
// Add default route to RPL
|
||||
rpl_control_update_dodag_route(protocol_6lowpan_rpl_root_dodag, NULL, 0, 0, 7200, false);
|
||||
rpl_control_update_dodag_prefix(protocol_6lowpan_rpl_root_dodag, static_dodag_id, 64, PIO_A, 7200, 0, false);
|
||||
rpl_control_update_dodag_route(protocol_6lowpan_rpl_root_dodag, static_dodag_id, 64, 0x18, 7200, false);
|
||||
rpl_control_update_dodag_prefix(protocol_6lowpan_rpl_root_dodag, global_id, 64, 0, 7200, 7200, false);
|
||||
rpl_control_update_dodag_route(protocol_6lowpan_rpl_root_dodag, global_id, 64, 0, 7200, false);
|
||||
// Enable default routing to backbone
|
||||
ipv6_route_add_with_info(global_id, 64, backbone_interface_id, NULL, ROUTE_THREAD_BBR, NULL, 0, 0xffffffff, 0);
|
||||
|
||||
if (configuration & BBR_GUA_SLAAC) {
|
||||
// GUA prefix is using SLAAC so no DHCP started and set correct flags for prefix
|
||||
t_flags = PIO_A;
|
||||
icmpv6_slaac_address_add(cur, global_id, 64, 0xffffffff, 0xffffffff, true, SLAAC_IID_FIXED);
|
||||
} else {
|
||||
ws_bbr_dhcp_server_start(cur, global_id);
|
||||
}
|
||||
|
||||
if (configuration & BBR_GUA_C) {
|
||||
// Add also global prefix and route to RPL
|
||||
uint32_t valid_lifetime;
|
||||
if (t_flags & PIO_A) {
|
||||
valid_lifetime = 7200;
|
||||
} else {
|
||||
valid_lifetime = 0;
|
||||
}
|
||||
|
||||
rpl_control_update_dodag_prefix(protocol_6lowpan_rpl_root_dodag, global_id, 64, t_flags, valid_lifetime, valid_lifetime, false);
|
||||
|
||||
}
|
||||
if (configuration & BBR_GUA_ROUTE) {
|
||||
// Add also global prefix and route to RPL
|
||||
rpl_control_update_dodag_route(protocol_6lowpan_rpl_root_dodag, global_id, 64, 0, 7200, false);
|
||||
}
|
||||
|
||||
}
|
||||
memcpy(global_dodag_id, global_id, 16);
|
||||
rpl_control_increment_dodag_version(protocol_6lowpan_rpl_root_dodag);
|
||||
|
@ -420,12 +474,44 @@ uint16_t ws_bbr_pan_size(protocol_interface_info_entry_t *cur)
|
|||
if (test_pan_size_override != 0xffff) {
|
||||
return test_pan_size_override;
|
||||
}
|
||||
//
|
||||
const uint8_t *prefix_ptr;
|
||||
if ((configuration & (BBR_ULA_C | BBR_GUA_C)) == BBR_GUA_C) {
|
||||
//Use just GUA Prefix
|
||||
prefix_ptr = global_dodag_id;
|
||||
|
||||
rpl_control_get_instance_dao_target_count(cur->rpl_domain, RPL_INSTANCE_ID, NULL, &result);
|
||||
} else {
|
||||
//Use ULA for indentifier
|
||||
prefix_ptr = static_dodag_id;
|
||||
}
|
||||
|
||||
rpl_control_get_instance_dao_target_count(cur->rpl_domain, RPL_INSTANCE_ID, NULL, prefix_ptr, &result);
|
||||
return result;
|
||||
}
|
||||
|
||||
bool ws_bbr_ready_to_start(protocol_interface_info_entry_t *cur)
|
||||
{
|
||||
|
||||
(void)cur;
|
||||
uint8_t global_address[16];
|
||||
|
||||
if (backbone_interface_id < 0) {
|
||||
// No need to wait for backbone
|
||||
return true;
|
||||
}
|
||||
|
||||
if ((configuration & BBR_BB_WAIT) != BBR_BB_WAIT) {
|
||||
// No need to wait for backbone
|
||||
return true;
|
||||
}
|
||||
|
||||
if (arm_net_address_get(backbone_interface_id, ADDR_IPV6_GP, global_address) != 0) {
|
||||
// No global prefix available
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif //HAVE_WS_BORDER_ROUTER
|
||||
|
||||
/* Public APIs
|
||||
|
@ -471,18 +557,44 @@ void ws_bbr_stop(int8_t interface_id)
|
|||
(void)interface_id;
|
||||
#endif
|
||||
}
|
||||
int ws_bbr_configure(int8_t interface_id, uint16_t options)
|
||||
{
|
||||
#ifdef HAVE_WS_BORDER_ROUTER
|
||||
|
||||
(void)interface_id;
|
||||
if (protocol_6lowpan_rpl_root_dodag &&
|
||||
options != configuration) {
|
||||
//Configuration changed delete previus setup
|
||||
ws_bbr_rpl_root_stop();
|
||||
}
|
||||
configuration = options;
|
||||
return 0;
|
||||
#else
|
||||
(void)interface_id;
|
||||
(void)options;
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
int ws_bbr_node_keys_remove(int8_t interface_id, uint8_t *eui64)
|
||||
{
|
||||
(void) interface_id;
|
||||
(void) eui64;
|
||||
|
||||
#ifdef HAVE_WS_BORDER_ROUTER
|
||||
return ws_pae_controller_node_keys_remove(interface_id, eui64);
|
||||
#else
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
int ws_bbr_node_access_revoke_start(int8_t interface_id)
|
||||
{
|
||||
(void) interface_id;
|
||||
|
||||
#ifdef HAVE_WS_BORDER_ROUTER
|
||||
return ws_pae_controller_node_access_revoke_start(interface_id);
|
||||
#else
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -29,13 +29,15 @@ uint16_t ws_bbr_pan_size(protocol_interface_info_entry_t *cur);
|
|||
|
||||
void ws_bbr_rpl_config(uint8_t imin, uint8_t doubling, uint8_t redundancy);
|
||||
|
||||
bool ws_bbr_ready_to_start(protocol_interface_info_entry_t *cur);
|
||||
|
||||
|
||||
#else
|
||||
|
||||
#define ws_bbr_seconds_timer( cur, seconds)
|
||||
#define ws_bbr_pan_size(cur) 0
|
||||
#define ws_bbr_rpl_config( imin, doubling, redundancy);
|
||||
#define ws_bbr_rpl_config( imin, doubling, redundancy)
|
||||
#define ws_bbr_ready_to_start(cur) true
|
||||
|
||||
#endif //HAVE_WS_BORDER_ROUTER
|
||||
|
||||
|
|
|
@ -85,8 +85,21 @@ static uint16_t ws_bootstrap_routing_cost_calculate(protocol_interface_info_entr
|
|||
static uint16_t ws_bootstrap_rank_get(protocol_interface_info_entry_t *cur);
|
||||
static uint16_t ws_bootstrap_min_rank_inc_get(protocol_interface_info_entry_t *cur);
|
||||
|
||||
static void ws_bootstrap_key_insert(protocol_interface_info_entry_t *cur, uint8_t gtk_index, uint8_t *gtk);
|
||||
static void ws_bootstrap_mac_security_enable(protocol_interface_info_entry_t *cur);
|
||||
static void ws_bootstrap_nw_key_set(protocol_interface_info_entry_t *cur, uint8_t operation, uint8_t index, uint8_t *key);
|
||||
static void ws_bootstrap_nw_key_clear(protocol_interface_info_entry_t *cur, uint8_t slot);
|
||||
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);
|
||||
static void ws_bootstrap_authentication_completed(protocol_interface_info_entry_t *cur, bool success);
|
||||
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);
|
||||
|
||||
typedef enum {
|
||||
WS_PARENT_SOFT_SYNCH = 0, /**< let FHSS make decision if synchronization is needed*/
|
||||
WS_PARENT_HARD_SYNCH, /**< Synch FHSS with latest synch information*/
|
||||
WS_EAPOL_PARENT_SYNCH, /**< Broadcast synch with EAPOL parent*/
|
||||
} ws_parent_synch_e;
|
||||
|
||||
mac_neighbor_table_entry_t *ws_bootstrap_mac_neighbor_add(struct protocol_interface_info_entry *interface, const uint8_t *src64)
|
||||
|
||||
|
@ -142,6 +155,9 @@ static void ws_bootstrap_address_notification_cb(struct protocol_interface_info_
|
|||
} else if (reason == ADDR_CALLBACK_DELETED) {
|
||||
// What to do?
|
||||
// Go through address list and check if there is global address still available
|
||||
//Discover prefix policy
|
||||
addr_policy_remove_by_label(WS_NON_PREFFRED_LABEL);
|
||||
|
||||
interface->global_address_available = false;
|
||||
ns_list_foreach(if_address_entry_t, addr_str, &interface->ip_addresses) {
|
||||
if (addr_ipv6_scope(addr_str->address, interface) > IPV6_SCOPE_LINK_LOCAL) {
|
||||
|
@ -150,8 +166,14 @@ static void ws_bootstrap_address_notification_cb(struct protocol_interface_info_
|
|||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
tr_debug("Address notification addr: %s reason: %d", trace_ipv6(addr->address), reason);
|
||||
} else if (reason == ADDR_CALLBACK_TIMER) {
|
||||
tr_debug("Address Re registration %s", trace_ipv6(addr->address));
|
||||
|
||||
if (!interface->ws_info->address_registration_event_active) {
|
||||
interface->ws_info->address_registration_event_active = true;
|
||||
tr_info("Register ARO");
|
||||
ws_bootsrap_event_trig(WS_ADDRESS_ADDED, interface->bootStrapId, ARM_LIB_LOW_PRIORITY_EVENT, NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -170,6 +192,21 @@ static int ws_bootstrap_tasklet_init(protocol_interface_info_entry_t *cur)
|
|||
|
||||
return 0;
|
||||
}
|
||||
static void ws_nwk_event_post(protocol_interface_info_entry_t *cur, arm_nwk_interface_status_type_e posted_event)
|
||||
{
|
||||
arm_event_s event = {
|
||||
.receiver = cur->net_start_tasklet,
|
||||
.sender = protocol_read_tasklet_id(), /**< Event sender Tasklet ID */
|
||||
.event_type = ARM_LIB_NWK_INTERFACE_EVENT,
|
||||
.event_data = posted_event,
|
||||
.event_id = (int8_t) cur->id,
|
||||
.data_ptr = NULL,
|
||||
.priority = ARM_LIB_LOW_PRIORITY_EVENT,
|
||||
};
|
||||
if (eventOS_event_send(&event) != 0) {
|
||||
tr_error("nwk_net_event_post(): event send failed");
|
||||
}
|
||||
}
|
||||
|
||||
static int8_t ws_bootsrap_event_trig(ws_bootsrap_event_type_e event_type, int8_t interface_id, arm_library_event_priority_e priority, void *event_data)
|
||||
{
|
||||
|
@ -218,21 +255,32 @@ static ws_nud_table_entry_t *ws_nud_entry_get_free(protocol_interface_info_entry
|
|||
|
||||
void ws_nud_entry_remove_active(protocol_interface_info_entry_t *cur, void *neighbor)
|
||||
{
|
||||
ns_list_foreach(ws_nud_table_entry_t, entry, &cur->ws_info->active_nud_process) {
|
||||
if (entry->neighbor_info == neighbor) {
|
||||
mac_neighbor_table_entry_t *mac_neighbor = neighbor;
|
||||
ns_list_remove(&cur->ws_info->active_nud_process, entry);
|
||||
ns_list_add_to_end(&cur->ws_info->free_nud_entries, entry);
|
||||
if (mac_neighbor->nud_active) {
|
||||
mac_neighbor_table_neighbor_refresh(mac_neighbor_info(cur), mac_neighbor, mac_neighbor->link_lifetime);
|
||||
}
|
||||
ws_nud_table_entry_t *entry = ws_nud_entry_discover(cur, neighbor);
|
||||
|
||||
mac_neighbor_table_neighbor_connected(mac_neighbor_info(cur), mac_neighbor);
|
||||
return;
|
||||
if (entry) {
|
||||
mac_neighbor_table_entry_t *mac_neighbor = neighbor;
|
||||
ns_list_remove(&cur->ws_info->active_nud_process, entry);
|
||||
ns_list_add_to_end(&cur->ws_info->free_nud_entries, entry);
|
||||
if (mac_neighbor->nud_active) {
|
||||
mac_neighbor_table_neighbor_refresh(mac_neighbor_info(cur), mac_neighbor, mac_neighbor->link_lifetime);
|
||||
}
|
||||
|
||||
mac_neighbor_table_neighbor_connected(mac_neighbor_info(cur), mac_neighbor);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static ws_nud_table_entry_t *ws_nud_entry_discover(protocol_interface_info_entry_t *cur, void *neighbor)
|
||||
{
|
||||
ns_list_foreach(ws_nud_table_entry_t, entry, &cur->ws_info->active_nud_process) {
|
||||
if (entry->neighbor_info == neighbor) {
|
||||
return entry;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static void ws_nud_state_clean(protocol_interface_info_entry_t *cur, ws_nud_table_entry_t *entry)
|
||||
{
|
||||
mac_neighbor_table_entry_t *neighbor = entry->neighbor_info;
|
||||
|
@ -244,6 +292,14 @@ static void ws_nud_state_clean(protocol_interface_info_entry_t *cur, ws_nud_tabl
|
|||
}
|
||||
}
|
||||
|
||||
static void ws_nud_entry_remove(protocol_interface_info_entry_t *cur, mac_neighbor_table_entry_t *entry_ptr)
|
||||
{
|
||||
ws_nud_table_entry_t *nud_entry = ws_nud_entry_discover(cur, entry_ptr);
|
||||
if (nud_entry) {
|
||||
ws_nud_state_clean(cur, nud_entry);
|
||||
}
|
||||
}
|
||||
|
||||
static bool ws_nud_message_build(protocol_interface_info_entry_t *cur, mac_neighbor_table_entry_t *neighbor)
|
||||
{
|
||||
//Send NS
|
||||
|
@ -444,8 +500,6 @@ static int8_t ws_fhss_discovery_configure(protocol_interface_info_entry_t *cur)
|
|||
fhss_configuration.fhss_broadcast_interval = 0;
|
||||
uint8_t tmp_uc_fixed_channel = ws_randomize_fixed_channel(cur->ws_info->fhss_uc_fixed_channel, cur->ws_info->hopping_schdule.number_of_channels);
|
||||
uint8_t tmp_bc_fixed_channel = ws_randomize_fixed_channel(cur->ws_info->fhss_bc_fixed_channel, cur->ws_info->hopping_schdule.number_of_channels);
|
||||
memset(fhss_configuration.channel_mask, 0, sizeof(uint32_t) * 8);
|
||||
channel_list_set_channel(fhss_configuration.channel_mask, tmp_uc_fixed_channel, true);
|
||||
fhss_configuration.unicast_fixed_channel = tmp_uc_fixed_channel;
|
||||
fhss_configuration.broadcast_fixed_channel = tmp_bc_fixed_channel;
|
||||
ns_fhss_ws_configuration_set(cur->ws_info->fhss_api, &fhss_configuration);
|
||||
|
@ -477,7 +531,7 @@ static int8_t ws_fhss_enable(protocol_interface_info_entry_t *cur)
|
|||
/* Sets the parent and broadcast schedule we are following
|
||||
*
|
||||
*/
|
||||
static void ws_bootstrap_primary_parent_set(struct protocol_interface_info_entry *cur, llc_neighbour_req_t *neighbor_info, bool force_synch)
|
||||
static void ws_bootstrap_primary_parent_set(struct protocol_interface_info_entry *cur, llc_neighbour_req_t *neighbor_info, ws_parent_synch_e synch_req)
|
||||
{
|
||||
|
||||
fhss_ws_configuration_t fhss_configuration;
|
||||
|
@ -490,7 +544,9 @@ static void ws_bootstrap_primary_parent_set(struct protocol_interface_info_entry
|
|||
|
||||
// Learning broadcast network configuration
|
||||
if (neighbor_info->ws_neighbor->broadcast_shedule_info_stored) {
|
||||
ws_fhss_set_defaults(cur, &fhss_configuration);
|
||||
if (synch_req != WS_EAPOL_PARENT_SYNCH) {
|
||||
ws_fhss_set_defaults(cur, &fhss_configuration);
|
||||
}
|
||||
fhss_configuration.ws_bc_channel_function = (fhss_ws_channel_functions)neighbor_info->ws_neighbor->fhss_data.bc_timing_info.broadcast_channel_function;
|
||||
if (fhss_configuration.ws_bc_channel_function == WS_FIXED_CHANNEL) {
|
||||
cur->ws_info->hopping_schdule.bc_fixed_channel = neighbor_info->ws_neighbor->fhss_data.bc_timing_info.fixed_channel;
|
||||
|
@ -500,18 +556,36 @@ static void ws_bootstrap_primary_parent_set(struct protocol_interface_info_entry
|
|||
fhss_configuration.fhss_bc_dwell_interval = neighbor_info->ws_neighbor->fhss_data.bc_timing_info.broadcast_dwell_interval;
|
||||
fhss_configuration.fhss_broadcast_interval = neighbor_info->ws_neighbor->fhss_data.bc_timing_info.broadcast_interval;
|
||||
fhss_configuration.broadcast_fixed_channel = cur->ws_info->fhss_bc_fixed_channel;
|
||||
|
||||
neighbor_info->ws_neighbor->synch_done = true;
|
||||
}
|
||||
|
||||
ns_fhss_ws_configuration_set(cur->ws_info->fhss_api, &fhss_configuration);
|
||||
|
||||
// We have broadcast schedule set up set the broadcast parent schedule
|
||||
ns_fhss_ws_set_parent(cur->ws_info->fhss_api, neighbor_info->neighbor->mac64, &neighbor_info->ws_neighbor->fhss_data.bc_timing_info, force_synch);
|
||||
ns_fhss_ws_set_parent(cur->ws_info->fhss_api, neighbor_info->neighbor->mac64, &neighbor_info->ws_neighbor->fhss_data.bc_timing_info, synch_req != WS_PARENT_SOFT_SYNCH);
|
||||
|
||||
// Update LLC to follow updated fhss settings
|
||||
ws_bootstrap_llc_hopping_update(cur, &fhss_configuration);
|
||||
}
|
||||
|
||||
void ws_bootstrap_eapol_parent_synch(struct protocol_interface_info_entry *cur, llc_neighbour_req_t *neighbor_info)
|
||||
{
|
||||
if (cur->ws_info->configuration_learned || !neighbor_info->ws_neighbor->broadcast_shedule_info_stored || !neighbor_info->ws_neighbor->broadcast_timing_info_stored) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (memcmp(neighbor_info->neighbor->mac64, cur->ws_info->parent_info.addr, 8)) {
|
||||
return;
|
||||
}
|
||||
|
||||
//Store Brodacst Shedule
|
||||
if (!neighbor_info->ws_neighbor->synch_done) {
|
||||
ws_bootstrap_primary_parent_set(cur, neighbor_info, WS_EAPOL_PARENT_SYNCH);
|
||||
} else {
|
||||
ns_fhss_ws_set_parent(cur->ws_info->fhss_api, neighbor_info->neighbor->mac64, &neighbor_info->ws_neighbor->fhss_data.bc_timing_info, false);
|
||||
}
|
||||
}
|
||||
|
||||
static void ws_bootstrap_ll_address_validate(struct protocol_interface_info_entry *cur)
|
||||
{
|
||||
// Configure EUI64 for MAC if missing
|
||||
|
@ -572,10 +646,13 @@ uint16_t ws_etx_read(protocol_interface_info_entry_t *interface, addrtype_t addr
|
|||
}
|
||||
} else {
|
||||
|
||||
if (!ws_neighbour || !etx_entry || etx_entry->etx_samples < 1 ||
|
||||
!ws_neighbour->candidate_parent) {
|
||||
if (!ws_neighbour || !etx_entry || etx_entry->etx_samples < 1 /*||
|
||||
!ws_neighbour->candidate_parent*/) {
|
||||
// if RSL value is not good enough candidate parent flag is removed and device not accepted as parent
|
||||
//tr_debug("ws_etx_read not valid parent");
|
||||
if (etx_entry && etx_entry->etx_samples) {
|
||||
tr_debug("ws_etx_read not valid %u RSL IN(%u), %u RSL out(%u)", ws_neighbor_class_rsl_in_get(ws_neighbour), ws_neighbour->rsl_in, ws_neighbor_class_rsl_out_get(ws_neighbour), ws_neighbour->rsl_out);
|
||||
}
|
||||
return 0xffff;
|
||||
}
|
||||
|
||||
|
@ -589,6 +666,7 @@ uint16_t ws_etx_read(protocol_interface_info_entry_t *interface, addrtype_t addr
|
|||
} else {
|
||||
if (!ws_neighbour->broadcast_timing_info_stored) {
|
||||
//Global shedule is stored already
|
||||
tr_debug("ws_etx_read not valid NO BTI");
|
||||
return 0xffff;
|
||||
}
|
||||
}
|
||||
|
@ -598,10 +676,6 @@ uint16_t ws_etx_read(protocol_interface_info_entry_t *interface, addrtype_t addr
|
|||
if (etx == 0) {
|
||||
return 0xffff;
|
||||
}
|
||||
if (etx > 0x800) {
|
||||
// Wi-SUN section 6.2.3.1.6.1 says ETX can only be maximum of 1024 (8*128) in RPL units, ie 8.0.
|
||||
etx = 0x800;
|
||||
}
|
||||
|
||||
//tr_debug("ws_etx_read etx:%d", etx);
|
||||
return etx;
|
||||
|
@ -624,7 +698,8 @@ static int8_t ws_bootstrap_up(protocol_interface_info_entry_t *cur)
|
|||
return -3;
|
||||
}
|
||||
|
||||
|
||||
//Enable Power bootup timer setup
|
||||
cur->ws_info->power_up_setup = true;
|
||||
// Save FHSS api
|
||||
cur->ws_info->fhss_api = ns_sw_mac_get_fhss_api(cur->mac_api);
|
||||
|
||||
|
@ -642,14 +717,16 @@ static int8_t ws_bootstrap_up(protocol_interface_info_entry_t *cur)
|
|||
/* Disable SLLAO send/mandatory receive with the ARO */
|
||||
cur->ipv6_neighbour_cache.use_eui64_as_slla_in_aro = true;
|
||||
/* Omit sending of NA if ARO SUCCESS */
|
||||
cur->ipv6_neighbour_cache.omit_aro_success = true;
|
||||
cur->ipv6_neighbour_cache.omit_na_aro_success = true;
|
||||
/* Omit sending of NA and consider ACK to be success */
|
||||
cur->ipv6_neighbour_cache.omit_na = true;
|
||||
// do not process AROs from NA. This is overriden by Wi-SUN specific failure handling
|
||||
cur->ipv6_neighbour_cache.recv_na_aro = false;
|
||||
/* Disable NUD Probes */
|
||||
cur->ipv6_neighbour_cache.send_nud_probes = false;
|
||||
cur->ipv6_neighbour_cache.probe_avoided_routers = true;
|
||||
dhcp_client_init(cur->id);
|
||||
dhcp_client_configure(cur->id, true); //RENEW uses SOLICIT
|
||||
dhcp_client_configure(cur->id, true, true, true); //RENEW uses SOLICIT, Interface will use 1 instance for address get, IAID address hint is not used.
|
||||
dhcp_client_solicit_timeout_set(cur->id, WS_DHCP_SOLICIT_TIMEOUT, WS_DHCP_SOLICIT_MAX_RT, WS_DHCP_SOLICIT_MAX_RC);
|
||||
|
||||
|
||||
|
@ -819,6 +896,7 @@ static void ws_bootstrap_pan_advertisement_analyse(struct protocol_interface_inf
|
|||
|
||||
// Save route cost for all neighbours
|
||||
llc_neighbour_req_t neighbor_info;
|
||||
neighbor_info.neighbor = NULL;
|
||||
if (ws_bootstrap_neighbor_info_request(cur, data->SrcAddr, &neighbor_info, false)) {
|
||||
neighbor_info.ws_neighbor->routing_cost = pan_information.routing_cost;
|
||||
}
|
||||
|
@ -848,14 +926,14 @@ static void ws_bootstrap_pan_advertisement_analyse(struct protocol_interface_inf
|
|||
uint16_t pan_cost = (pan_information.routing_cost / PRC_WEIGHT_FACTOR) + (pan_information.pan_size / PS_WEIGHT_FACTOR);
|
||||
uint16_t current_pan_cost = (cur->ws_info->parent_info.pan_information.routing_cost / PRC_WEIGHT_FACTOR) + (cur->ws_info->parent_info.pan_information.pan_size / PS_WEIGHT_FACTOR);
|
||||
if (current_pan_cost < pan_cost) {
|
||||
tr_info("EAPOL target dropped Higher Pan cost");
|
||||
tr_info("EAPOL target dropped Higher Pan cost %u > %u current", pan_cost, current_pan_cost);
|
||||
return;
|
||||
}
|
||||
|
||||
// If pan cost is the same then we select the one we hear highest
|
||||
if (current_pan_cost == pan_cost &&
|
||||
cur->ws_info->parent_info.signal_dbm > data->signal_dbm) {
|
||||
tr_info("EAPOL target dropped Lower link quality");
|
||||
tr_info("EAPOL target dropped Lower link quality %u < %u current", data->signal_dbm, cur->ws_info->parent_info.signal_dbm);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -895,12 +973,16 @@ parent_selected:
|
|||
ws_bootstrap_pan_advertisement_analyse_active(cur, &pan_information);
|
||||
|
||||
// Learn latest network information
|
||||
if (cur->bootsrap_mode != ARM_NWK_BOOTSRAP_MODE_6LoWPAN_BORDER_ROUTER) {
|
||||
cur->ws_info->pan_information.pan_size = pan_information.pan_size;
|
||||
cur->ws_info->pan_information.routing_cost = pan_information.routing_cost;
|
||||
cur->ws_info->pan_information.rpl_routing_method = pan_information.rpl_routing_method;
|
||||
cur->ws_info->pan_information.use_parent_bs = pan_information.use_parent_bs;
|
||||
cur->ws_info->pan_information.version = pan_information.version;
|
||||
if (cur->bootsrap_mode != ARM_NWK_BOOTSRAP_MODE_6LoWPAN_BORDER_ROUTER && neighbor_info.neighbor) {
|
||||
|
||||
if (neighbor_info.neighbor->link_role == PRIORITY_PARENT_NEIGHBOUR) {
|
||||
cur->ws_info->pan_information.pan_size = pan_information.pan_size;
|
||||
cur->ws_info->pan_information.routing_cost = pan_information.routing_cost;
|
||||
cur->ws_info->pan_information.rpl_routing_method = pan_information.rpl_routing_method;
|
||||
cur->ws_info->pan_information.use_parent_bs = pan_information.use_parent_bs;
|
||||
cur->ws_info->pan_information.version = pan_information.version;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -930,7 +1012,6 @@ static void ws_bootstrap_pan_config_analyse(struct protocol_interface_info_entry
|
|||
ws_bs_ie_t ws_bs_ie;
|
||||
uint8_t *gtkhash_ptr;
|
||||
|
||||
|
||||
if (data->SrcPANId != cur->ws_info->network_pan_id) {
|
||||
tr_debug("Wrong PAN id r:%u own:%u", data->SrcPANId, cur->ws_info->network_pan_id);
|
||||
return;
|
||||
|
@ -986,19 +1067,26 @@ static void ws_bootstrap_pan_config_analyse(struct protocol_interface_info_entry
|
|||
ws_neighbor_class_neighbor_broadcast_schedule_set(neighbor_info.ws_neighbor, &ws_bs_ie);
|
||||
|
||||
if (cur->ws_info->configuration_learned) {
|
||||
// received version is lower se we need to reset the trickle
|
||||
tr_info("PAN Config analyse own:%d, heard:%d", cur->ws_info->pan_information.pan_version, pan_version);
|
||||
if (cur->ws_info->pan_information.pan_version == pan_version) {
|
||||
// Same version heard so it is consistent
|
||||
trickle_consistent_heard(&cur->ws_info->trickle_pan_config);
|
||||
if (neighbor_info.neighbor->link_role == PRIORITY_PARENT_NEIGHBOUR) {
|
||||
ws_bootstrap_primary_parent_set(cur, &neighbor_info, WS_PARENT_SOFT_SYNCH);
|
||||
}
|
||||
// no need to process more
|
||||
return;
|
||||
} else {
|
||||
tr_info("different pan version heard");
|
||||
// received version is different so we need to reset the trickle
|
||||
trickle_inconsistent_heard(&cur->ws_info->trickle_pan_config, &cur->ws_info->trickle_params_pan_discovery);
|
||||
if (neighbor_info.neighbor->link_role == PRIORITY_PARENT_NEIGHBOUR) {
|
||||
ws_bootstrap_primary_parent_set(cur, &neighbor_info, WS_PARENT_HARD_SYNCH);
|
||||
}
|
||||
if (common_serial_number_greater_16(cur->ws_info->pan_information.pan_version, pan_version)) {
|
||||
// older version heard ignoring the message
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
if (cur->bootsrap_mode == ARM_NWK_BOOTSRAP_MODE_6LoWPAN_BORDER_ROUTER) {
|
||||
|
@ -1006,28 +1094,18 @@ static void ws_bootstrap_pan_config_analyse(struct protocol_interface_info_entry
|
|||
return;
|
||||
}
|
||||
|
||||
if (cur->ws_info->configuration_learned) {
|
||||
bool old_version = cur->ws_info->pan_information.pan_version == pan_version;
|
||||
if (neighbor_info.neighbor->link_role == PRIORITY_PARENT_NEIGHBOUR) {
|
||||
// RPL priority parent configuration we must update FHSS data
|
||||
//Update synch to primary parent allways to update broadcast shedule and timing
|
||||
ws_bootstrap_primary_parent_set(cur, &neighbor_info, !old_version);
|
||||
}
|
||||
|
||||
if (old_version) {
|
||||
// No new information
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Learn new information from border router
|
||||
* Learn new information from neighbor
|
||||
*/
|
||||
tr_info("Updated PAN configuration heard");
|
||||
tr_info("Updated PAN configuration own:%d, heard:%d", cur->ws_info->pan_information.pan_version, pan_version);
|
||||
|
||||
// restart PAN version timer
|
||||
cur->ws_info->pan_version_timeout_timer = PAN_VERSION_TIMEOUT;
|
||||
cur->ws_info->pan_information.pan_version = pan_version;
|
||||
memcpy(cur->ws_info->gtkhash, gtkhash_ptr, 32);
|
||||
|
||||
ws_pae_controller_gtk_hash_update(cur, gtkhash_ptr);
|
||||
|
||||
ws_pae_controller_nw_key_index_update(cur, data->Key.KeyIndex - 1);
|
||||
|
||||
if (!cur->ws_info->configuration_learned) {
|
||||
// Generate own hopping schedules Follow first parent broadcast and plans and also use same unicast dwell
|
||||
|
@ -1036,7 +1114,7 @@ static void ws_bootstrap_pan_config_analyse(struct protocol_interface_info_entry
|
|||
// return to state machine after 1-2 s
|
||||
cur->bootsrap_state_machine_cnt = randLIB_get_random_in_range(10, 20);
|
||||
// enable frequency hopping for unicast channel and start listening first neighbour
|
||||
ws_bootstrap_primary_parent_set(cur, &neighbor_info, true);
|
||||
ws_bootstrap_primary_parent_set(cur, &neighbor_info, WS_PARENT_HARD_SYNCH);
|
||||
// set neighbor as priority parent clear if there is others
|
||||
protocol_6lowpan_neighbor_priority_clear_all(cur->id, PRIORITY_1ST);
|
||||
neighbor_info.neighbor->link_role = PRIORITY_PARENT_NEIGHBOUR;
|
||||
|
@ -1060,13 +1138,13 @@ 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, true)) {
|
||||
return;
|
||||
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);
|
||||
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);
|
||||
}
|
||||
|
||||
etx_lqi_dbm_update(cur->id, data->mpduLinkQuality, data->signal_dbm, neighbor_info.neighbor->index);
|
||||
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);
|
||||
|
||||
|
||||
/*
|
||||
* A consistent transmission is defined as a PAN Configuration Solicit with
|
||||
|
@ -1175,19 +1253,19 @@ static void ws_bootstrap_asynch_ind(struct protocol_interface_info_entry *cur, c
|
|||
switch (message_type) {
|
||||
case WS_FT_PAN_ADVERT:
|
||||
// Analyse Advertisement
|
||||
tr_debug("received ADVERT");
|
||||
tr_info("received ADVERT Src:%s rssi:%d", trace_array(data->SrcAddr, 8), data->signal_dbm);
|
||||
ws_bootstrap_pan_advertisement_analyse(cur, data, ie_ext, &ws_utt, &ws_us);
|
||||
break;
|
||||
case WS_FT_PAN_ADVERT_SOL:
|
||||
tr_debug("received ADVERT SOL");
|
||||
tr_info("received ADVERT SOL Src:%s rssi:%d", trace_array(data->SrcAddr, 8), data->signal_dbm);
|
||||
ws_bootstrap_pan_advertisement_solicit_analyse(cur, data, &ws_utt, &ws_us);
|
||||
break;
|
||||
case WS_FT_PAN_CONF:
|
||||
tr_debug("received CONFIG");
|
||||
tr_info("received CONFIG Src:%s rssi:%d", trace_array(data->SrcAddr, 8), data->signal_dbm);
|
||||
ws_bootstrap_pan_config_analyse(cur, data, ie_ext, &ws_utt, &ws_us);
|
||||
break;
|
||||
default:
|
||||
tr_debug("received CONFIG SOL");
|
||||
tr_info("received CONFIG SOL Src:%s rssi:%d", trace_array(data->SrcAddr, 8), data->signal_dbm);
|
||||
ws_bootstrap_pan_config_solicit_analyse(cur, data, &ws_utt, &ws_us);
|
||||
break;
|
||||
}
|
||||
|
@ -1221,19 +1299,32 @@ static void ws_bootstrap_neighbor_table_clean(struct protocol_interface_info_ent
|
|||
continue;
|
||||
}
|
||||
|
||||
if (ipv6_neighbour_has_registered_by_eui64(&interface->ipv6_neighbour_cache, cur->mac64)) {
|
||||
// We have registered entry so we have been selected as parent
|
||||
continue;
|
||||
if (cur->trusted_device) {
|
||||
|
||||
if (ipv6_neighbour_has_registered_by_eui64(&interface->ipv6_neighbour_cache, cur->mac64)) {
|
||||
// We have registered entry so we have been selected as parent
|
||||
continue;
|
||||
}
|
||||
|
||||
memcpy(ll_target + 8, cur->mac64, 8);
|
||||
ll_target[8] ^= 2;
|
||||
|
||||
if (rpl_control_is_dodag_parent(interface, ll_target)) {
|
||||
// Possible parent is limited to 3 by default?
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
memcpy(ll_target + 8, cur->mac64, 8);
|
||||
ll_target[8] ^= 2;
|
||||
|
||||
if (rpl_control_is_dodag_parent(interface, ll_target)) {
|
||||
// Possible parent is limited to 3 by default?
|
||||
continue;
|
||||
|
||||
if (cur->trusted_device) {
|
||||
neighbor_entry_ptr = cur;
|
||||
} else {
|
||||
if (cur->link_lifetime - cur->lifetime > WS_NEIGHBOR_NOT_TRUSTED_LINK_TIMEOUT) {
|
||||
//Accept only Enough Old not trusted Device
|
||||
neighbor_entry_ptr = cur;
|
||||
}
|
||||
}
|
||||
neighbor_entry_ptr = cur;
|
||||
}
|
||||
if (neighbor_entry_ptr) {
|
||||
tr_info("dropped oldest neighbour %s", trace_array(neighbor_entry_ptr->mac64, 8));
|
||||
|
@ -1299,6 +1390,10 @@ static void ws_neighbor_entry_remove_notify(mac_neighbor_table_entry_t *entry_pt
|
|||
protocol_6lowpan_release_short_link_address_from_neighcache(cur, entry_ptr->mac16);
|
||||
protocol_6lowpan_release_long_link_address_from_neighcache(cur, entry_ptr->mac64);
|
||||
}
|
||||
|
||||
//NUD Process Clear Here
|
||||
ws_nud_entry_remove(cur, entry_ptr);
|
||||
|
||||
ws_bootstrap_neighbor_delete(cur, entry_ptr->index);
|
||||
}
|
||||
|
||||
|
@ -1387,6 +1482,13 @@ int ws_bootstrap_init(int8_t interface_id, net_6lowpan_mode_e bootstrap_mode)
|
|||
if (!etx_storage_list_allocate(cur->id, buffer.device_decription_table_size)) {
|
||||
return -1;
|
||||
}
|
||||
if (!etx_cached_etx_parameter_set(WS_ETX_MIN_WAIT_TIME, WS_ETX_MIN_SAMPLE_COUNT)) {
|
||||
etx_storage_list_allocate(cur->id, 0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
etx_max_update_set(WS_ETX_MAX_UPDATE);
|
||||
|
||||
if (blacklist_init() != 0) {
|
||||
tr_err("MLE blacklist init failed.");
|
||||
return -1;
|
||||
|
@ -1452,7 +1554,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_key_insert) < 0) {
|
||||
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_pan_version_increment) < 0) {
|
||||
ret_val = -4;
|
||||
goto init_fail;
|
||||
}
|
||||
|
@ -1542,26 +1644,32 @@ int ws_bootstrap_set_rf_config(protocol_interface_info_entry_t *cur, phy_rf_chan
|
|||
set_request.value_pointer = &ack_wait_symbols;
|
||||
set_request.value_size = sizeof(ack_wait_symbols);
|
||||
cur->mac_api->mlme_req(cur->mac_api, MLME_SET, &set_request);
|
||||
// Set multi CSMA-CA configuration
|
||||
mlme_multi_csma_ca_param_t multi_csma_params = {WS_NUMBER_OF_CSMA_PERIODS, WS_CSMA_MULTI_CCA_INTERVAL};
|
||||
set_request.attr = macMultiCSMAParameters;
|
||||
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);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ws_bootstrap_neighbor_remove(protocol_interface_info_entry_t *cur, const uint8_t *ll_address)
|
||||
{
|
||||
tr_warn("ARO registration Failure %s", trace_ipv6(ll_address));
|
||||
|
||||
blacklist_update(ll_address, false);
|
||||
rpl_control_neighbor_delete(cur, ll_address);
|
||||
|
||||
mac_neighbor_table_entry_t *mac_neighbor = mac_neighbor_entry_get_by_ll64(mac_neighbor_info(cur), ll_address, false, NULL);
|
||||
|
||||
if (mac_neighbor) {
|
||||
ws_bootstrap_neighbor_delete(cur, mac_neighbor->index);
|
||||
// TODO Add to blacklist
|
||||
mac_neighbor_table_neighbor_remove(mac_neighbor_info(cur), mac_neighbor);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int ws_bootstrap_aro_failure(protocol_interface_info_entry_t *cur, const uint8_t *ll_address)
|
||||
{
|
||||
blacklist_update(ll_address, false);
|
||||
rpl_control_neighbor_delete(cur, ll_address);
|
||||
ws_bootstrap_neighbor_remove(cur, ll_address);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ws_bootstrap_mac_activate(protocol_interface_info_entry_t *cur, uint16_t channel, uint16_t panid, bool coordinator)
|
||||
{
|
||||
|
@ -1592,6 +1700,7 @@ static void ws_bootstrap_fhss_activate(protocol_interface_info_entry_t *cur)
|
|||
tr_debug("MAC init");
|
||||
mac_helper_pib_boolean_set(cur, macRxOnWhenIdle, true);
|
||||
cur->lowpan_info &= ~INTERFACE_NWK_CONF_MAC_RX_OFF_IDLE;
|
||||
ws_bootstrap_mac_security_enable(cur);
|
||||
ws_bootstrap_mac_activate(cur, cur->ws_info->fhss_uc_fixed_channel, cur->ws_info->network_pan_id, true);
|
||||
return;
|
||||
}
|
||||
|
@ -1619,7 +1728,8 @@ static void ws_bootstrap_network_configuration_learn(protocol_interface_info_ent
|
|||
|
||||
// Timing information can be modified here
|
||||
ws_llc_set_pan_information_pointer(cur, &cur->ws_info->pan_information);
|
||||
ws_llc_set_gtkhash(cur, cur->ws_info->gtkhash);
|
||||
uint8_t *gtkhash = ws_pae_controller_gtk_hash_ptr_get(cur);
|
||||
ws_llc_set_gtkhash(cur, gtkhash);
|
||||
// TODO update own fhss schedules we are starting to follow first parent
|
||||
|
||||
return;
|
||||
|
@ -1728,31 +1838,11 @@ static void ws_dhcp_client_global_adress_cb(int8_t interface, uint8_t dhcp_addr[
|
|||
tr_debug("DHCPv6 %s status %u", trace_ipv6(dhcp_addr), register_status);
|
||||
}
|
||||
|
||||
static bool ws_address_entry_available(uint8_t *prefixPtr, if_address_list_t *list)
|
||||
{
|
||||
bool addressReady = false;
|
||||
ns_list_foreach(if_address_entry_t, entry, list) {
|
||||
if (prefixPtr) {
|
||||
if (memcmp(entry->address, prefixPtr, 8) == 0) {
|
||||
addressReady = true;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if (entry->source == ADDR_SOURCE_DHCP) {
|
||||
addressReady = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return addressReady;
|
||||
}
|
||||
|
||||
void ws_dhcp_client_address_request(protocol_interface_info_entry_t *cur, uint8_t *prefix, uint8_t *parent_link_local)
|
||||
{
|
||||
if (!ws_address_entry_available(prefix, &cur->ip_addresses)) {
|
||||
if (dhcp_client_get_global_address(cur->id, parent_link_local, prefix, cur->mac, DHCPV6_DUID_HARDWARE_IEEE_802_NETWORKS_TYPE, ws_dhcp_client_global_adress_cb) != 0) {
|
||||
tr_error("DHCPp client request fail");
|
||||
}
|
||||
if (dhcp_client_get_global_address(cur->id, parent_link_local, prefix, cur->mac, DHCPV6_DUID_HARDWARE_IEEE_802_NETWORKS_TYPE, ws_dhcp_client_global_adress_cb) != 0) {
|
||||
tr_error("DHCPp client request fail");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1778,24 +1868,30 @@ static void ws_rpl_prefix_callback(prefix_entry_t *prefix, void *handle, uint8_t
|
|||
* from a prefix advertised by a parent.
|
||||
*/
|
||||
if (prefix->options & PIO_A) {
|
||||
if (icmpv6_slaac_prefix_update(cur, prefix->prefix, prefix->prefix_len, prefix->lifetime, prefix->preftime) != 0) {
|
||||
ipv6_interface_slaac_handler(cur, prefix->prefix, prefix->prefix_len, prefix->lifetime, prefix->preftime);
|
||||
|
||||
if (parent_link_local) {
|
||||
if (icmpv6_slaac_prefix_update(cur, prefix->prefix, prefix->prefix_len, prefix->lifetime, prefix->preftime) != 0) {
|
||||
ipv6_interface_slaac_handler(cur, prefix->prefix, prefix->prefix_len, prefix->lifetime, prefix->preftime);
|
||||
/*
|
||||
* Give SLAAC addresses a different label and low precedence to indicate that
|
||||
* they probably shouldn't be used for external traffic. SLAAC use in Wi-SUN is non-standard,
|
||||
* and we use it for mesh-local traffic we should prefer any DHCP-assigned addresses
|
||||
* for talking to the outside world
|
||||
*
|
||||
*/
|
||||
addr_policy_table_add_entry(prefix->prefix, prefix->prefix_len, 2, WS_NON_PREFFRED_LABEL);
|
||||
}
|
||||
} else {
|
||||
icmpv6_slaac_prefix_update(cur, prefix->prefix, prefix->prefix_len, 0, 0);
|
||||
}
|
||||
} else if (prefix->prefix_len) {
|
||||
if (prefix->preftime == 0) {
|
||||
// Delete all pending transactions from DHCP
|
||||
// TODO this also deletes the address even when lifetime would allow it to be present
|
||||
dhcp_client_global_address_delete(cur->id, NULL, prefix->prefix);
|
||||
} else {
|
||||
// Create new address using DHCP
|
||||
// Create new address using DHCP
|
||||
if (parent_link_local) {
|
||||
ws_dhcp_client_address_request(cur, prefix->prefix, parent_link_local);
|
||||
}
|
||||
// If we have addresses generated we update the lifetimes always
|
||||
ns_list_foreach(if_address_entry_t, entry, &cur->ip_addresses) {
|
||||
if (entry->prefix_len == prefix->prefix_len && bitsequal(entry->address, prefix->prefix, prefix->prefix_len)) {
|
||||
entry->preferred_lifetime = prefix->preftime;
|
||||
entry->valid_lifetime = prefix->lifetime;
|
||||
}
|
||||
} else {
|
||||
/* Deprecate address and remove client */
|
||||
tr_debug("Prefix invalidation %s", trace_ipv6(prefix->prefix));
|
||||
dhcp_client_global_address_delete(cur->id, NULL, prefix->prefix);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1839,10 +1935,13 @@ static void ws_bootstrap_advertise_start(protocol_interface_info_entry_t *cur)
|
|||
{
|
||||
cur->ws_info->trickle_pa_running = true;
|
||||
trickle_start(&cur->ws_info->trickle_pan_advertisement, &cur->ws_info->trickle_params_pan_discovery);
|
||||
trickle_inconsistent_heard(&cur->ws_info->trickle_pan_advertisement, &cur->ws_info->trickle_params_pan_discovery);
|
||||
cur->ws_info->trickle_pc_running = true;
|
||||
trickle_start(&cur->ws_info->trickle_pan_config, &cur->ws_info->trickle_params_pan_discovery);
|
||||
trickle_inconsistent_heard(&cur->ws_info->trickle_pan_config, &cur->ws_info->trickle_params_pan_discovery);
|
||||
}
|
||||
|
||||
static void ws_bootstrap_pan_version_increment(protocol_interface_info_entry_t *cur)
|
||||
{
|
||||
cur->ws_info->pan_version_timer = 1;
|
||||
}
|
||||
|
||||
// Start network scan
|
||||
|
@ -1870,7 +1969,19 @@ static void ws_bootstrap_start_discovery(protocol_interface_info_entry_t *cur)
|
|||
// Reset advertisement solicit trickle to start discovering network
|
||||
cur->ws_info->trickle_pas_running = true;
|
||||
trickle_start(&cur->ws_info->trickle_pan_advertisement_solicit, &cur->ws_info->trickle_params_pan_discovery);
|
||||
trickle_inconsistent_heard(&cur->ws_info->trickle_pan_advertisement_solicit, &cur->ws_info->trickle_params_pan_discovery);
|
||||
if (cur->ws_info->power_up_setup) {
|
||||
cur->ws_info->power_up_setup = false;
|
||||
tr_debug("PAS init I %u and t %u", cur->ws_info->trickle_pan_advertisement_solicit.I, cur->ws_info->trickle_pan_advertisement_solicit.t);
|
||||
} else {
|
||||
trickle_inconsistent_heard(&cur->ws_info->trickle_pan_advertisement_solicit, &cur->ws_info->trickle_params_pan_discovery);
|
||||
}
|
||||
|
||||
if ((cur->lowpan_info & INTERFACE_NWK_BOOTSRAP_ACTIVE) != INTERFACE_NWK_BOOTSRAP_ACTIVE) {
|
||||
// we have sent bootstrap ready event and now
|
||||
// restarted discovery so bootstrap down event is sent
|
||||
cur->lowpan_info |= INTERFACE_NWK_BOOTSRAP_ACTIVE;
|
||||
ws_nwk_event_post(cur, ARM_NWK_NWK_CONNECTION_DOWN);
|
||||
}
|
||||
|
||||
// Discovery statemachine is checkked after two trickle interval
|
||||
cur->bootsrap_state_machine_cnt = 2 * cur->ws_info->trickle_params_pan_discovery.Imin + randLIB_get_8bit() % 50;
|
||||
|
@ -1879,25 +1990,38 @@ static void ws_bootstrap_start_discovery(protocol_interface_info_entry_t *cur)
|
|||
// Start authentication
|
||||
static void ws_bootstrap_start_authentication(protocol_interface_info_entry_t *cur)
|
||||
{
|
||||
tr_debug("authentication start");
|
||||
// Set PAN ID and network name to controller
|
||||
ws_pae_controller_nw_info_set(cur, cur->ws_info->network_pan_id, cur->ws_info->network_name);
|
||||
|
||||
ws_pae_controller_authenticate(cur);
|
||||
}
|
||||
|
||||
|
||||
static void ws_bootstrap_key_insert(protocol_interface_info_entry_t *cur, uint8_t gtk_index, uint8_t *gtk)
|
||||
static void ws_bootstrap_mac_security_enable(protocol_interface_info_entry_t *cur)
|
||||
{
|
||||
// Convert GTK to Group AES Key (GAK)
|
||||
mac_helper_default_security_level_set(cur, AES_SECURITY_LEVEL_ENC_MIC64);
|
||||
mac_helper_default_security_key_id_mode_set(cur, MAC_KEY_ID_MODE_IDX);
|
||||
}
|
||||
|
||||
// Verify HASH etc.
|
||||
static void ws_bootstrap_nw_key_set(protocol_interface_info_entry_t *cur, uint8_t slot, uint8_t index, uint8_t *key)
|
||||
{
|
||||
mac_helper_security_key_to_descriptor_set(cur, key, index + 1, slot);
|
||||
}
|
||||
|
||||
// Check index, for now only reacts to keys of index 0
|
||||
if (gtk_index == 0) {
|
||||
mac_helper_security_key_clean(cur);
|
||||
mac_helper_default_security_level_set(cur, AES_SECURITY_LEVEL_ENC_MIC64);
|
||||
mac_helper_default_security_key_id_mode_set(cur, MAC_KEY_ID_MODE_IDX);
|
||||
//Set Keys
|
||||
mac_helper_security_default_key_set(cur, gtk, gtk_index + 1, MAC_KEY_ID_MODE_IDX);
|
||||
}
|
||||
static void ws_bootstrap_nw_key_clear(protocol_interface_info_entry_t *cur, uint8_t slot)
|
||||
{
|
||||
mac_helper_security_key_descriptor_clear(cur, slot);
|
||||
}
|
||||
|
||||
static void ws_bootstrap_nw_key_index_set(protocol_interface_info_entry_t *cur, uint8_t index)
|
||||
{
|
||||
// Set send key
|
||||
mac_helper_security_auto_request_key_index_set(cur, index + 1);
|
||||
}
|
||||
|
||||
static void ws_bootstrap_nw_frame_counter_set(protocol_interface_info_entry_t *cur, uint32_t counter)
|
||||
{
|
||||
// Set frame counter
|
||||
mac_helper_link_frame_counter_set(cur->id, counter);
|
||||
}
|
||||
|
||||
static void ws_bootstrap_authentication_completed(protocol_interface_info_entry_t *cur, bool success)
|
||||
|
@ -1955,7 +2079,7 @@ void ws_bootstrap_event_configuration_start(protocol_interface_info_entry_t *cur
|
|||
}
|
||||
void ws_bootstrap_event_authentication_start(protocol_interface_info_entry_t *cur)
|
||||
{
|
||||
ws_bootsrap_event_trig(WS_AUTHENTICATION_START, cur->bootStrapId, ARM_LIB_LOW_PRIORITY_EVENT, NULL);
|
||||
ws_bootstrap_state_change(cur, ER_PANA_AUTH);
|
||||
}
|
||||
void ws_bootstrap_event_operation_start(protocol_interface_info_entry_t *cur)
|
||||
{
|
||||
|
@ -2155,6 +2279,13 @@ static void ws_bootstrap_event_handler(arm_event_s *event)
|
|||
|
||||
if (cur->bootsrap_mode == ARM_NWK_BOOTSRAP_MODE_6LoWPAN_BORDER_ROUTER) {
|
||||
tr_debug("Border router start network");
|
||||
|
||||
if (!ws_bbr_ready_to_start(cur)) {
|
||||
// Wi-SUN not started yet we wait for Border router permission
|
||||
ws_bootstrap_state_change(cur, ER_WAIT_RESTART);
|
||||
cur->nwk_nd_re_scan_count = randLIB_get_random_in_range(40, 100);
|
||||
return;
|
||||
}
|
||||
ws_pae_controller_auth_init(cur);
|
||||
|
||||
// Randomize fixed channels. Only used if channel plan is fixed.
|
||||
|
@ -2167,7 +2298,9 @@ static void ws_bootstrap_event_handler(arm_event_s *event)
|
|||
cur->ws_info->pan_information.rpl_routing_method = true;
|
||||
cur->ws_info->pan_information.use_parent_bs = true;
|
||||
cur->ws_info->pan_information.version = WS_FAN_VERSION_1_0;
|
||||
ws_llc_set_gtkhash(cur, cur->ws_info->gtkhash);
|
||||
|
||||
uint8_t *gtkhash = ws_pae_controller_gtk_hash_ptr_get(cur);
|
||||
ws_llc_set_gtkhash(cur, gtkhash);
|
||||
cur->ws_info->pan_version_timer = PAN_VERSION_LIFETIME;
|
||||
|
||||
// Set default parameters for FHSS when starting a discovery
|
||||
|
@ -2187,6 +2320,9 @@ static void ws_bootstrap_event_handler(arm_event_s *event)
|
|||
// Set authenticator relay to port 10253 and PAE to 10254 (and to own ll address)
|
||||
ws_eapol_auth_relay_start(cur, EAPOL_RELAY_SOCKET_PORT, ll_addr, PAE_AUTH_SOCKET_PORT);
|
||||
|
||||
// Set PAN ID and network name to controller
|
||||
ws_pae_controller_nw_info_set(cur, cur->ws_info->network_pan_id, cur->ws_info->network_name);
|
||||
|
||||
// Set PAE port to 10254 and authenticator relay to 10253 (and to own ll address)
|
||||
ws_pae_controller_authenticator_start(cur, PAE_AUTH_SOCKET_PORT, ll_addr, EAPOL_RELAY_SOCKET_PORT);
|
||||
break;
|
||||
|
@ -2199,21 +2335,6 @@ static void ws_bootstrap_event_handler(arm_event_s *event)
|
|||
// Start network scan
|
||||
ws_bootstrap_start_discovery(cur);
|
||||
break;
|
||||
case WS_AUTHENTICATION_START:
|
||||
tr_info("authentication start");
|
||||
// only advert sol stopped as we might be doing re authentication
|
||||
cur->ws_info->trickle_pas_running = false;
|
||||
//Add Test ecurity key and security level's
|
||||
|
||||
|
||||
// Advertisements stopped during the EAPOL
|
||||
cur->ws_info->trickle_pa_running = false;
|
||||
cur->ws_info->trickle_pc_running = false;
|
||||
cur->ws_info->trickle_pas_running = false;
|
||||
cur->ws_info->trickle_pcs_running = false;
|
||||
|
||||
ws_bootstrap_start_authentication(cur);
|
||||
break;
|
||||
|
||||
case WS_CONFIGURATION_START:
|
||||
tr_info("Configuration start");
|
||||
|
@ -2375,10 +2496,15 @@ static void ws_bootstrap_state_change(protocol_interface_info_entry_t *cur, icmp
|
|||
cur->bootsrap_state_machine_cnt = 1;
|
||||
cur->nwk_bootstrap_state = nwk_bootstrap_state;
|
||||
}
|
||||
|
||||
void ws_bootstrap_state_machine(protocol_interface_info_entry_t *cur)
|
||||
{
|
||||
|
||||
switch (cur->nwk_bootstrap_state) {
|
||||
case ER_WAIT_RESTART:
|
||||
tr_debug("WS SM:Wait for startup");
|
||||
ws_bootstrap_event_discovery_start(cur);
|
||||
break;
|
||||
case ER_ACTIVE_SCAN:
|
||||
tr_debug("WS SM:Active Scan");
|
||||
ws_bootstrap_network_scan_process(cur);
|
||||
|
@ -2387,6 +2513,19 @@ void ws_bootstrap_state_machine(protocol_interface_info_entry_t *cur)
|
|||
tr_debug("WS SM:configuration Scan");
|
||||
ws_bootstrap_configure_process(cur);
|
||||
break;
|
||||
case ER_PANA_AUTH:
|
||||
tr_info("authentication start");
|
||||
// only advert sol stopped as we might be doing re authentication
|
||||
cur->ws_info->trickle_pas_running = false;
|
||||
//Add Test ecurity key and security level's
|
||||
// Advertisements stopped during the EAPOL
|
||||
cur->ws_info->trickle_pa_running = false;
|
||||
cur->ws_info->trickle_pc_running = false;
|
||||
cur->ws_info->trickle_pas_running = false;
|
||||
cur->ws_info->trickle_pcs_running = false;
|
||||
|
||||
ws_bootstrap_start_authentication(cur);
|
||||
break;
|
||||
case ER_RPL_SCAN:
|
||||
tr_debug("WS SM:Wait RPL to contact DODAG root");
|
||||
ws_bootstrap_rpl_wait_process(cur);
|
||||
|
@ -2396,10 +2535,8 @@ void ws_bootstrap_state_machine(protocol_interface_info_entry_t *cur)
|
|||
// Bootstrap_done event to application
|
||||
nwk_bootsrap_state_update(ARM_NWK_BOOTSTRAP_READY, cur);
|
||||
break;
|
||||
|
||||
default:
|
||||
tr_warn("WS SM:Invalid state %d", cur->nwk_bootstrap_state);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2416,7 +2553,10 @@ void ws_bootstrap_trickle_timer(protocol_interface_info_entry_t *cur, uint16_t t
|
|||
// send PAN Configuration solicit
|
||||
if (cur->ws_info->pas_requests > PCS_MAX) {
|
||||
// if MAX PCS sent restart discovery
|
||||
tr_debug("Restart???");
|
||||
|
||||
// Remove network keys from MAC
|
||||
ws_pae_controller_nw_keys_remove(cur);
|
||||
|
||||
ws_bootstrap_event_discovery_start(cur);
|
||||
return;
|
||||
}
|
||||
|
@ -2459,7 +2599,12 @@ void ws_primary_parent_update(protocol_interface_info_entry_t *interface, mac_ne
|
|||
llc_neighbour_req_t neighbor_info;
|
||||
neighbor_info.neighbor = neighbor;
|
||||
neighbor_info.ws_neighbor = ws_neighbor_class_entry_get(&interface->ws_info->neighbor_storage, neighbor->index);
|
||||
ws_bootstrap_primary_parent_set(interface, &neighbor_info, true);
|
||||
ws_bootstrap_primary_parent_set(interface, &neighbor_info, WS_PARENT_HARD_SYNCH);
|
||||
uint8_t link_local_address[16];
|
||||
memcpy(link_local_address, ADDR_LINK_LOCAL_PREFIX, 8);
|
||||
memcpy(link_local_address + 8, neighbor->mac64, 8);
|
||||
link_local_address[8] ^= 2;
|
||||
dhcp_client_server_address_update(interface->id, NULL, link_local_address);
|
||||
|
||||
ws_secondary_parent_update(interface);
|
||||
}
|
||||
|
|
|
@ -23,7 +23,6 @@ typedef enum {
|
|||
WS_INIT_EVENT = 0, /**< tasklet initializion event*/
|
||||
WS_DISCOVERY_START, /**< discovery start*/
|
||||
WS_CONFIGURATION_START, /**< configuration learn start*/
|
||||
WS_AUTHENTICATION_START, /**< authentication start*/
|
||||
WS_OPERATION_START, /**< active operation start*/
|
||||
WS_ROUTING_READY, /**< RPL routing connected to BR*/
|
||||
WS_ADDRESS_ADDED /**< Address added to IF*/
|
||||
|
@ -31,6 +30,8 @@ typedef enum {
|
|||
|
||||
#ifdef HAVE_WS
|
||||
|
||||
struct llc_neighbour_req;
|
||||
|
||||
int ws_bootstrap_init(int8_t interface_id, net_6lowpan_mode_e bootstrap_mode);
|
||||
|
||||
void ws_bootstrap_state_machine(protocol_interface_info_entry_t *cur);
|
||||
|
@ -41,6 +42,8 @@ int ws_bootstrap_set_rf_config(protocol_interface_info_entry_t *cur, phy_rf_chan
|
|||
|
||||
int ws_bootstrap_neighbor_remove(protocol_interface_info_entry_t *cur, const uint8_t *ll_address);
|
||||
|
||||
int ws_bootstrap_aro_failure(protocol_interface_info_entry_t *cur, const uint8_t *ll_address);
|
||||
|
||||
/*State machine transactions*/
|
||||
void ws_bootstrap_event_discovery_start(protocol_interface_info_entry_t *cur);
|
||||
|
||||
|
@ -72,12 +75,15 @@ void ws_dhcp_client_address_delete(protocol_interface_info_entry_t *cur, uint8_t
|
|||
|
||||
bool ws_eapol_relay_state_active(protocol_interface_info_entry_t *cur);
|
||||
|
||||
void ws_bootstrap_eapol_parent_synch(struct protocol_interface_info_entry *cur, struct llc_neighbour_req *neighbor_info);
|
||||
|
||||
#else
|
||||
|
||||
#define ws_bootstrap_init(interface_id, bootstrap_mode) (-1)
|
||||
#define ws_bootstrap_state_machine(cur)
|
||||
#define ws_bootstrap_restart(cur)
|
||||
#define ws_bootstrap_neighbor_remove(cur, ll_address)
|
||||
#define ws_bootstrap_aro_failure(cur, ll_address)
|
||||
#define ws_primary_parent_update(interface, neighbor)
|
||||
#define ws_secondary_parent_update(interface)
|
||||
|
||||
|
|
|
@ -274,6 +274,7 @@ int8_t ws_common_allocate_and_init(protocol_interface_info_entry_t *cur)
|
|||
cur->ws_info->hopping_schdule.operating_mode = OPERATING_MODE_3;
|
||||
cur->ws_info->hopping_schdule.operating_class = 2;
|
||||
ws_common_regulatory_domain_config(cur);
|
||||
cur->ws_info->network_size_config = NETWORK_SIZE_AUTOMATIC;
|
||||
ws_common_network_size_configure(cur, 10); // defaults to small network size
|
||||
|
||||
// Set defaults for the device. user can modify these.
|
||||
|
@ -302,7 +303,12 @@ void ws_common_network_size_configure(protocol_interface_info_entry_t *cur, uint
|
|||
// imin: 14 (16s)
|
||||
// doublings:3 (128s)
|
||||
// redundancy; 0 Disabled
|
||||
ws_bbr_rpl_config(0, 0, 0);// set the default values
|
||||
if (cur->ws_info->network_size_config == NETWORK_SIZE_AUTOMATIC) {
|
||||
ws_bbr_rpl_config(14, 3, 0);
|
||||
} else {
|
||||
ws_bbr_rpl_config(0, 0, 0);
|
||||
}
|
||||
|
||||
} else if (network_size < 300) {
|
||||
// Configure the Wi-SUN discovery trickle parameters
|
||||
cur->ws_info->trickle_params_pan_discovery = trickle_params_pan_discovery_medium;
|
||||
|
@ -348,11 +354,19 @@ void ws_common_neighbor_update(protocol_interface_info_entry_t *cur, const uint8
|
|||
|
||||
void ws_common_aro_failure(protocol_interface_info_entry_t *cur, const uint8_t *ll_address)
|
||||
{
|
||||
//Neighbor connectected update
|
||||
tr_warn("ARO registration Failure %s", trace_ipv6(ll_address));
|
||||
ws_bootstrap_aro_failure(cur, ll_address);
|
||||
}
|
||||
|
||||
void ws_common_neighbor_remove(protocol_interface_info_entry_t *cur, const uint8_t *ll_address)
|
||||
{
|
||||
tr_debug("neighbor remove %s", trace_ipv6(ll_address));
|
||||
ws_bootstrap_neighbor_remove(cur, ll_address);
|
||||
}
|
||||
|
||||
bool ws_common_allow_child_registration(protocol_interface_info_entry_t *interface)
|
||||
|
||||
|
||||
bool ws_common_allow_child_registration(protocol_interface_info_entry_t *interface, const uint8_t *eui64)
|
||||
{
|
||||
uint8_t child_count = 0;
|
||||
uint8_t max_child_count = mac_neighbor_info(interface)->list_total_size - WS_NON_CHILD_NEIGHBOUR_COUNT;
|
||||
|
@ -362,6 +376,12 @@ bool ws_common_allow_child_registration(protocol_interface_info_entry_t *interfa
|
|||
max_child_count = test_max_child_count_override;
|
||||
}
|
||||
|
||||
//Validate Is EUI64 already allocated for any address
|
||||
if (ipv6_neighbour_has_registered_by_eui64(&interface->ipv6_neighbour_cache, eui64)) {
|
||||
tr_info("Child registration from old child");
|
||||
return true;
|
||||
}
|
||||
|
||||
ns_list_foreach_safe(mac_neighbor_table_entry_t, cur, &mac_neighbor_info(interface)->neighbour_list) {
|
||||
|
||||
if (ipv6_neighbour_has_registered_by_eui64(&interface->ipv6_neighbour_cache, cur->mac64)) {
|
||||
|
|
|
@ -79,6 +79,7 @@ typedef struct ws_info_s {
|
|||
bool trickle_pa_running: 1;
|
||||
bool trickle_pcs_running: 1;
|
||||
bool trickle_pc_running: 1;
|
||||
bool power_up_setup: 1;
|
||||
// default fhss parameters for this device
|
||||
uint8_t fhss_uc_dwell_interval;
|
||||
uint8_t fhss_bc_dwell_interval;
|
||||
|
@ -118,7 +119,9 @@ void ws_common_neighbor_update(protocol_interface_info_entry_t *cur, const uint8
|
|||
|
||||
void ws_common_aro_failure(protocol_interface_info_entry_t *cur, const uint8_t *ll_address);
|
||||
|
||||
bool ws_common_allow_child_registration(protocol_interface_info_entry_t *cur);
|
||||
void ws_common_neighbor_remove(protocol_interface_info_entry_t *cur, const uint8_t *ll_address);
|
||||
|
||||
bool ws_common_allow_child_registration(protocol_interface_info_entry_t *cur, const uint8_t *eui64);
|
||||
|
||||
#define ws_info(cur) ((cur)->ws_info)
|
||||
#else
|
||||
|
@ -126,8 +129,9 @@ bool ws_common_allow_child_registration(protocol_interface_info_entry_t *cur);
|
|||
#define ws_common_seconds_timer(cur, seconds)
|
||||
#define ws_common_neighbor_update(cur, ll_address) ((void) 0)
|
||||
#define ws_common_aro_failure(cur, ll_address)
|
||||
#define ws_common_neighbor_remove(cur, ll_address)
|
||||
#define ws_common_fast_timer(cur, ticks) ((void) 0)
|
||||
#define ws_common_allow_child_registration(cur) (false)
|
||||
#define ws_common_allow_child_registration(cur, eui64) (false)
|
||||
|
||||
|
||||
#endif //HAVE_WS
|
||||
|
|
|
@ -186,6 +186,7 @@ typedef struct ws_bs_ie {
|
|||
#define WS_FAN_VERSION_1_0 1
|
||||
|
||||
#define WS_NEIGHBOR_LINK_TIMEOUT 2200
|
||||
#define WS_NEIGHBOR_NOT_TRUSTED_LINK_TIMEOUT 60
|
||||
#define WS_NEIGHBOR_NUD_TIMEOUT WS_NEIGHBOR_LINK_TIMEOUT / 2
|
||||
|
||||
#define WS_NEIGBOR_ETX_SAMPLE_MAX 3
|
||||
|
@ -198,6 +199,18 @@ typedef struct ws_bs_ie {
|
|||
|
||||
#define WS_NUD_RANDOM_COMPARE (WS_NUD_RAND_PROBABILITY*WS_NUD_RANDOM_SAMPLE_LENGTH) / 100
|
||||
|
||||
#define WS_ETX_MIN_SAMPLE_COUNT 4
|
||||
|
||||
#define WS_ETX_MAX_UPDATE 1024
|
||||
|
||||
#define WS_ETX_MIN_WAIT_TIME 60
|
||||
|
||||
/**
|
||||
* Wi-sun spesific non-preferred prefix policy label
|
||||
*/
|
||||
|
||||
#define WS_NON_PREFFRED_LABEL 36
|
||||
|
||||
/*
|
||||
* Threshold (referenced to DEVICE_MIN_SENS) above which a neighbor node may be considered for inclusion into candidate parent set
|
||||
*/
|
||||
|
@ -226,6 +239,11 @@ typedef struct ws_bs_ie {
|
|||
*/
|
||||
#define WS_TACK_MAX_MS 5
|
||||
|
||||
// With FHSS we need to check CCA twice on TX channel
|
||||
#define WS_NUMBER_OF_CSMA_PERIODS 2
|
||||
// Interval between two CCA checks
|
||||
#define WS_CSMA_MULTI_CCA_INTERVAL 1000
|
||||
|
||||
/* Default FHSS timing information
|
||||
*
|
||||
*/
|
||||
|
|
|
@ -27,8 +27,8 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#define WS_RPL_DIO_IMIN 14
|
||||
#define WS_RPL_DIO_DOUBLING 3
|
||||
#define WS_RPL_DIO_IMIN 15
|
||||
#define WS_RPL_DIO_DOUBLING 2
|
||||
#define WS_RPL_DIO_REDUNDANCY 0
|
||||
|
||||
|
||||
|
|
|
@ -197,12 +197,15 @@ int8_t ws_eapol_pdu_send_to_mpx(protocol_interface_info_entry_t *interface_ptr,
|
|||
}
|
||||
msdu_entry->data_ptr = data;
|
||||
msdu_entry->buffer = buffer;
|
||||
msdu_entry->handle = eapol_pdu_data->msdu_handle++;
|
||||
msdu_entry->handle = eapol_pdu_data->msdu_handle;
|
||||
ns_list_add_to_start(&eapol_pdu_data->msdu_list, msdu_entry);
|
||||
|
||||
memcpy(data_request.DstAddr, eui_64, 8);
|
||||
data_request.msdu = data;
|
||||
data_request.msduLength = size;
|
||||
data_request.msduHandle = eapol_pdu_data->msdu_handle;
|
||||
|
||||
eapol_pdu_data->msdu_handle++;
|
||||
|
||||
eapol_pdu_data->mpx_api->mpx_data_request(eapol_pdu_data->mpx_api, &data_request, eapol_pdu_data->mpx_user_id);
|
||||
return 0;
|
||||
|
|
|
@ -181,5 +181,12 @@ int ws_test_gtk_time_settings_set(int8_t interface_id, uint8_t revocat_lifetime_
|
|||
return -1;
|
||||
}
|
||||
|
||||
#endif // no HAVE_WS
|
||||
int ws_test_next_gtk_set(int8_t interface_id, uint8_t *gtk[4])
|
||||
{
|
||||
(void) interface_id;
|
||||
(void) gtk;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
#endif // no HAVE_WS
|
||||
|
|
|
@ -36,6 +36,8 @@
|
|||
#include "6LoWPAN/ws/ws_llc.h"
|
||||
#include "6LoWPAN/ws/ws_mpx_header.h"
|
||||
#include "6LoWPAN/ws/ws_pae_controller.h"
|
||||
#include "Security/PANA/pana_eap_header.h"
|
||||
#include "Security/eapol/eapol_helper.h"
|
||||
#include "Service_Libs/etx/etx.h"
|
||||
#include "fhss_ws_extension.h"
|
||||
|
||||
|
@ -511,9 +513,12 @@ static void ws_llc_mac_indication_cb(const mac_api_t *api, const mcps_data_ind_t
|
|||
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);
|
||||
}
|
||||
|
||||
llc_neighbour_req_t neighbor_info;
|
||||
|
@ -534,8 +539,12 @@ static void ws_llc_mac_indication_cb(const mac_api_t *api, const mcps_data_ind_t
|
|||
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);
|
||||
}
|
||||
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)) {
|
||||
|
@ -543,6 +552,8 @@ static void ws_llc_mac_indication_cb(const mac_api_t *api, const mcps_data_ind_t
|
|||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -617,6 +628,37 @@ static uint16_t ws_mpx_header_size_get(llc_data_base_t *base, uint16_t user_id)
|
|||
return header_size;
|
||||
}
|
||||
|
||||
static bool ws_eapol_handshake_first_msg(uint8_t *pdu, uint16_t length, protocol_interface_info_entry_t *cur)
|
||||
{
|
||||
if (!ws_eapol_relay_state_active(cur)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
eapol_pdu_t eapol_pdu;
|
||||
uint8_t kmp_type = *pdu++;
|
||||
length--;
|
||||
if (!eapol_parse_pdu_header(pdu, length, &eapol_pdu)) {
|
||||
return false;
|
||||
}
|
||||
if (eapol_pdu.packet_type == EAPOL_EAP_TYPE) {
|
||||
if (eapol_pdu.msg.eap.eap_code == EAP_REQ && eapol_pdu.msg.eap.type == EAP_IDENTITY) {
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
|
||||
uint8_t key_mask = eapol_pdu_key_mask_get(&eapol_pdu);
|
||||
if (kmp_type == 6 && key_mask == KEY_INFO_KEY_ACK) {
|
||||
//FWK first message validation
|
||||
return true;
|
||||
} else if (kmp_type == 7 && key_mask == (KEY_INFO_KEY_ACK | KEY_INFO_KEY_MIC | KEY_INFO_SECURED_KEY_FRAME)) {
|
||||
//GWK first message validation
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
llc_data_base_t *base = ws_llc_discover_by_mpx(api);
|
||||
|
@ -646,11 +688,9 @@ static void ws_llc_mpx_data_request(const mpx_api_t *api, const struct mcps_data
|
|||
nested_wp_id.vp_ie = true;
|
||||
}
|
||||
} else if (user_id == MPX_KEY_MANAGEMENT_ENC_USER_ID) {
|
||||
|
||||
if (*data->msdu == 1) { //Only when KMP_ID is 1
|
||||
ie_header_mask.ea_ie = ws_eapol_relay_state_active(base->interface_ptr);
|
||||
ie_header_mask.bt_ie = ie_header_mask.ea_ie;
|
||||
}
|
||||
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;
|
||||
|
||||
}
|
||||
|
||||
|
@ -735,6 +775,11 @@ static void ws_llc_mpx_data_request(const mpx_api_t *api, const struct mcps_data
|
|||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -138,7 +138,6 @@ uint8_t ws_neighbor_class_rssi_from_dbm_calculate(int8_t dbm_heard)
|
|||
{
|
||||
if (DEVICE_MIN_SENS > dbm_heard) {
|
||||
// We are hearing packet with lower than min_sens dynamically learn the sensitivity
|
||||
tr_info("heard packet below min sensitivity");
|
||||
DEVICE_MIN_SENS = dbm_heard;
|
||||
}
|
||||
return dbm_heard - DEVICE_MIN_SENS;
|
||||
|
|
|
@ -31,6 +31,7 @@ typedef struct ws_neighbor_class_entry {
|
|||
bool candidate_parent: 1;
|
||||
bool broadcast_timing_info_stored: 1;
|
||||
bool broadcast_shedule_info_stored: 1;
|
||||
bool synch_done : 1;
|
||||
} ws_neighbor_class_entry_t;
|
||||
|
||||
/**
|
||||
|
@ -147,7 +148,7 @@ uint8_t ws_neighbor_class_rssi_from_dbm_calculate(int8_t dbm_heard);
|
|||
*
|
||||
*/
|
||||
#define ws_neighbor_class_rsl_in_get(ws_neighbour) (ws_neighbour->rsl_in >> WS_RSL_SCALING)
|
||||
#define ws_neighbor_class_rsl_out_get(ws_neighbour) (ws_neighbour->rsl_in >> WS_RSL_SCALING)
|
||||
#define ws_neighbor_class_rsl_out_get(ws_neighbour) (ws_neighbour->rsl_out >> WS_RSL_SCALING)
|
||||
|
||||
/**
|
||||
* ws_neighbor_class_neighbor_broadcast_schedule_set a function for update neighbor broadcast shedule information
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
|
||||
#include "nsconfig.h"
|
||||
#include <string.h>
|
||||
#include <randLIB.h>
|
||||
#include "ns_types.h"
|
||||
#include "ns_list.h"
|
||||
#include "ns_trace.h"
|
||||
|
@ -39,6 +40,7 @@
|
|||
#include "Security/protocols/fwh_sec_prot/auth_fwh_sec_prot.h"
|
||||
#include "Security/protocols/gkh_sec_prot/auth_gkh_sec_prot.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"
|
||||
|
||||
|
@ -54,23 +56,43 @@
|
|||
// Wait for for supplicant to indicate activity (e.g. to send a message)
|
||||
#define WAIT_FOR_AUTHENTICATION_TICKS 5 * 60 * 10 // 5 minutes
|
||||
|
||||
// Maximum number of simultaneous EAP-TLS negotiations
|
||||
#define MAX_SIMULTANEOUS_EAP_TLS_NEGOTIATIONS 3
|
||||
|
||||
/* 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
|
||||
|
||||
typedef struct {
|
||||
ns_list_link_t link; /**< Link */
|
||||
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_key_index_set *nw_key_index_set; /**< Key index set 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 */
|
||||
bool timer_running; /**< Timer is running */
|
||||
timer_settings_t *timer_settings; /**< Timer settings */
|
||||
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 */
|
||||
} pae_auth_t;
|
||||
|
||||
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);
|
||||
static int8_t ws_pae_auth_network_key_index_set(pae_auth_t *pae_auth, uint8_t index);
|
||||
static void ws_pae_auth_free(pae_auth_t *pae_auth);
|
||||
static pae_auth_t *ws_pae_auth_get(protocol_interface_info_entry_t *interface_ptr);
|
||||
static pae_auth_t *ws_pae_auth_by_kmp_service_get(kmp_service_t *service);
|
||||
static int8_t ws_pae_auth_event_send(kmp_service_t *service, void *data);
|
||||
static void ws_pae_auth_tasklet_handler(arm_event_s *event);
|
||||
static void ws_pae_auth_gtk_key_insert(pae_auth_t *pae_auth);
|
||||
static int8_t ws_pae_auth_new_gtk_activate(pae_auth_t *pae_auth);
|
||||
static int8_t ws_pae_auth_timer_if_start(kmp_service_t *service, kmp_api_t *kmp);
|
||||
static int8_t ws_pae_auth_timer_if_stop(kmp_service_t *service, kmp_api_t *kmp);
|
||||
static int8_t ws_pae_auth_timer_start(pae_auth_t *pae_auth);
|
||||
|
@ -82,13 +104,15 @@ static kmp_api_t *ws_pae_auth_kmp_incoming_ind(kmp_service_t *service, kmp_type_
|
|||
static void ws_pae_auth_kmp_api_create_confirm(kmp_api_t *kmp, kmp_result_e result);
|
||||
static void ws_pae_auth_kmp_api_create_indication(kmp_api_t *kmp, kmp_type_e type, kmp_addr_t *addr);
|
||||
static void ws_pae_auth_kmp_api_finished_indication(kmp_api_t *kmp, kmp_result_e result, kmp_sec_keys_t *sec_keys);
|
||||
static void ws_pae_auth_next_kmp_trigger(pae_auth_t *pae_auth, supp_entry_t *supp_entry);
|
||||
static kmp_type_e ws_pae_auth_next_protocol_get(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);
|
||||
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, const sec_prot_certs_t *certs)
|
||||
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, timer_settings_t *timer_settings)
|
||||
{
|
||||
if (!interface_ptr || !gtks || !certs) {
|
||||
return -1;
|
||||
|
@ -108,8 +132,17 @@ int8_t ws_pae_auth_init(protocol_interface_info_entry_t *interface_ptr, sec_prot
|
|||
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_key_index_set = NULL;
|
||||
|
||||
pae_auth->gtks = gtks;
|
||||
pae_auth->next_gtks = next_gtks;
|
||||
pae_auth->certs = certs;
|
||||
pae_auth->timer_settings = timer_settings;
|
||||
pae_auth->slow_timer_seconds = 0;
|
||||
pae_auth->gtk_new_inst_req_exp = false;
|
||||
pae_auth->gtk_new_act_time_exp = false;
|
||||
|
||||
pae_auth->kmp_service = kmp_service_create();
|
||||
if (!pae_auth->kmp_service) {
|
||||
|
@ -205,6 +238,212 @@ 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)
|
||||
{
|
||||
if (!interface_ptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
pae_auth_t *pae_auth = ws_pae_auth_get(interface_ptr);
|
||||
if (!pae_auth) {
|
||||
return;
|
||||
}
|
||||
|
||||
pae_auth->hash_set = hash_set;
|
||||
pae_auth->nw_key_insert = nw_key_insert;
|
||||
pae_auth->nw_key_index_set = nw_key_index_set;
|
||||
}
|
||||
|
||||
void ws_pae_auth_start(protocol_interface_info_entry_t *interface_ptr)
|
||||
{
|
||||
if (!interface_ptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
pae_auth_t *pae_auth = ws_pae_auth_get(interface_ptr);
|
||||
if (!pae_auth) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Checks if there is predefined active key
|
||||
int8_t index = sec_prot_keys_gtk_status_active_get(pae_auth->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);
|
||||
ws_pae_auth_active_gtk_set(pae_auth, index);
|
||||
} else {
|
||||
ws_pae_auth_active_gtk_set(pae_auth, index);
|
||||
}
|
||||
|
||||
// Inserts keys and updates GTK hash on stack
|
||||
ws_pae_auth_network_keys_from_gtks_set(pae_auth);
|
||||
|
||||
// Sets active key index
|
||||
ws_pae_auth_network_key_index_set(pae_auth, index);
|
||||
}
|
||||
|
||||
void ws_pae_auth_gtks_updated(protocol_interface_info_entry_t *interface_ptr)
|
||||
{
|
||||
if (!interface_ptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
pae_auth_t *pae_auth = ws_pae_auth_get(interface_ptr);
|
||||
if (!pae_auth) {
|
||||
return;
|
||||
}
|
||||
|
||||
ws_pae_auth_network_keys_from_gtks_set(pae_auth);
|
||||
}
|
||||
|
||||
int8_t ws_pae_auth_nw_key_index_update(protocol_interface_info_entry_t *interface_ptr, uint8_t index)
|
||||
{
|
||||
if (!interface_ptr) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
pae_auth_t *pae_auth = ws_pae_auth_get(interface_ptr);
|
||||
if (!pae_auth) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
ws_pae_auth_active_gtk_set(pae_auth, index);
|
||||
ws_pae_auth_network_key_index_set(pae_auth, index);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int8_t ws_pae_auth_node_keys_remove(protocol_interface_info_entry_t *interface_ptr, uint8_t *eui_64)
|
||||
{
|
||||
if (!interface_ptr) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
pae_auth_t *pae_auth = ws_pae_auth_get(interface_ptr);
|
||||
if (!pae_auth) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Checks if supplicant is active
|
||||
supp_entry_t *supp = ws_pae_lib_supp_list_entry_eui_64_get(&pae_auth->active_supp_list, eui_64);
|
||||
|
||||
if (supp) {
|
||||
// Deletes keys and marks as revoked
|
||||
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(kmp_address_eui_64_get(supp->addr), 8));
|
||||
return 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(kmp_address_eui_64_get(supp->addr), 8));
|
||||
ws_pae_lib_supp_list_remove(&pae_auth->inactive_supp_list, supp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int8_t ws_pae_auth_node_access_revoke_start(protocol_interface_info_entry_t *interface_ptr)
|
||||
{
|
||||
if (!interface_ptr) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
pae_auth_t *pae_auth = ws_pae_auth_get(interface_ptr);
|
||||
if (!pae_auth) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Gets active GTK
|
||||
int8_t active_index = sec_prot_keys_gtk_status_active_get(pae_auth->gtks);
|
||||
|
||||
if (active_index >= 0) {
|
||||
// As default removes other keys than active
|
||||
int8_t not_removed_index = active_index;
|
||||
|
||||
uint32_t revocation_lifetime = ws_pae_timers_gtk_revocation_lifetime_get(pae_auth->timer_settings);
|
||||
|
||||
uint32_t active_lifetime = sec_prot_keys_gtk_lifetime_get(pae_auth->gtks, active_index);
|
||||
|
||||
// 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);
|
||||
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);
|
||||
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);
|
||||
if (second_lifetime > second_revocation_lifetime) {
|
||||
sec_prot_keys_gtk_lifetime_decrement(pae_auth->gtks, second_index, 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
|
||||
not_removed_index = second_index;
|
||||
}
|
||||
}
|
||||
|
||||
// Deletes other GTKs
|
||||
int8_t last_index = sec_prot_keys_gtk_install_order_last_index_get(pae_auth->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);
|
||||
}
|
||||
}
|
||||
|
||||
// Adds new GTK
|
||||
ws_pae_auth_gtk_key_insert(pae_auth);
|
||||
ws_pae_auth_network_keys_from_gtks_set(pae_auth);
|
||||
|
||||
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);
|
||||
|
||||
if (pae_auth->hash_set) {
|
||||
uint8_t gtk_hash[32];
|
||||
sec_prot_keys_gtks_hash_generate(pae_auth->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);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
static int8_t ws_pae_auth_network_key_index_set(pae_auth_t *pae_auth, uint8_t index)
|
||||
{
|
||||
if (pae_auth->nw_key_index_set) {
|
||||
pae_auth->nw_key_index_set(pae_auth->interface_ptr, index);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ws_pae_auth_free(pae_auth_t *pae_auth)
|
||||
{
|
||||
if (!pae_auth) {
|
||||
|
@ -287,7 +526,7 @@ static void ws_pae_auth_tasklet_handler(arm_event_s *event)
|
|||
}
|
||||
}
|
||||
|
||||
void ws_pae_auth_timer(uint16_t ticks)
|
||||
void ws_pae_auth_fast_timer(uint16_t ticks)
|
||||
{
|
||||
ns_list_foreach(pae_auth_t, pae_auth, &pae_auth_list) {
|
||||
if (!ws_pae_auth_timer_running(pae_auth)) {
|
||||
|
@ -302,6 +541,111 @@ void ws_pae_auth_timer(uint16_t ticks)
|
|||
}
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
for (uint8_t i = 0; i < GTK_NUM; i++) {
|
||||
if (!sec_prot_keys_gtk_is_set(pae_auth->gtks, i)) {
|
||||
continue;
|
||||
}
|
||||
uint32_t timer_seconds = sec_prot_keys_gtk_lifetime_decrement(pae_auth->gtks, i, 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->timer_settings, 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);
|
||||
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);
|
||||
} 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!pae_auth->gtk_new_act_time_exp) {
|
||||
pae_auth->gtk_new_act_time_exp = ws_pae_timers_gtk_new_activation_time(pae_auth->timer_settings, timer_seconds);
|
||||
if (pae_auth->gtk_new_act_time_exp) {
|
||||
int8_t new_active_index = ws_pae_auth_new_gtk_activate(pae_auth);
|
||||
tr_info("GTK new activation time active index: %i, time: %"PRIu32", new index: %i, system time: %"PRIu32"", active_index, timer_seconds, new_active_index, protocol_core_monotonic_time / 10);
|
||||
if (new_active_index >= 0) {
|
||||
ws_pae_auth_network_key_index_set(pae_auth, new_active_index);
|
||||
}
|
||||
pae_auth->gtk_new_inst_req_exp = false;
|
||||
pae_auth->gtk_new_act_time_exp = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (timer_seconds == 0) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
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->timer_settings, pae_auth->slow_timer_seconds);
|
||||
ws_pae_lib_supp_list_slow_timer_update(&pae_auth->inactive_supp_list, pae_auth->timer_settings, pae_auth->slow_timer_seconds);
|
||||
pae_auth->slow_timer_seconds = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
// Key to install
|
||||
uint8_t gtk_value[GTK_LEN];
|
||||
|
||||
// Checks if next GTK values are set and gets first GTK to install
|
||||
int8_t next_gtk_index = sec_prot_keys_gtk_install_order_first_index_get(pae_auth->next_gtks);
|
||||
if (next_gtk_index >= 0) {
|
||||
// Gets GTK value
|
||||
uint8_t *gtk = sec_prot_keys_gtk_get(pae_auth->next_gtks, next_gtk_index);
|
||||
memcpy(gtk_value, gtk, GTK_LEN);
|
||||
// Sets same key back to next GTKs but as the last key to be installed
|
||||
sec_prot_keys_gtk_clear(pae_auth->next_gtks, next_gtk_index);
|
||||
sec_prot_keys_gtk_set(pae_auth->next_gtks, next_gtk_index, gtk_value, 0);
|
||||
} else {
|
||||
randLIB_get_n_bytes_random(gtk_value, GTK_LEN);
|
||||
}
|
||||
|
||||
// Gets latest installed key lifetime and adds GTK expire offset to it
|
||||
uint32_t lifetime = pae_auth->timer_settings->gtk_expire_offset;
|
||||
int8_t last_index = sec_prot_keys_gtk_install_order_last_index_get(pae_auth->gtks);
|
||||
if (last_index >= 0) {
|
||||
lifetime += sec_prot_keys_gtk_lifetime_get(pae_auth->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);
|
||||
|
||||
// Authenticator keys are always fresh
|
||||
sec_prot_keys_gtk_status_all_fresh_set(pae_auth->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);
|
||||
if (new_active_index >= 0) {
|
||||
ws_pae_auth_active_gtk_set(pae_auth, new_active_index);
|
||||
}
|
||||
|
||||
return new_active_index;
|
||||
}
|
||||
|
||||
static int8_t ws_pae_auth_timer_if_start(kmp_service_t *service, kmp_api_t *kmp)
|
||||
{
|
||||
pae_auth_t *pae_auth = ws_pae_auth_by_kmp_service_get(service);
|
||||
|
@ -363,19 +707,16 @@ static bool ws_pae_auth_timer_running(pae_auth_t *pae_auth)
|
|||
|
||||
static void ws_pae_auth_kmp_service_addr_get(kmp_service_t *service, kmp_api_t *kmp, kmp_addr_t *local_addr, kmp_addr_t *remote_addr)
|
||||
{
|
||||
(void) service;
|
||||
pae_auth_t *pae_auth = ws_pae_auth_by_kmp_service_get(service);
|
||||
if (!pae_auth) {
|
||||
return;
|
||||
}
|
||||
|
||||
#if 0
|
||||
// Get own EUI-64
|
||||
link_layer_address_s mac_params;
|
||||
if (arm_nwk_mac_address_read(pae_auth->interface_ptr->id, &mac_params) >= 0) {
|
||||
kmp_address_eui_64_set(local_addr, mac_params.mac_long);
|
||||
}
|
||||
#endif
|
||||
|
||||
// For now fixed since not yet support for EA-IE in supplicants
|
||||
uint8_t addr[8] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08};
|
||||
kmp_address_eui_64_set(local_addr, addr);
|
||||
|
||||
// Get supplicant address
|
||||
supp_entry_t *entry = kmp_api_data_get(kmp);
|
||||
|
@ -422,6 +763,8 @@ static kmp_api_t *ws_pae_auth_kmp_incoming_ind(kmp_service_t *service, kmp_type_
|
|||
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));
|
||||
} else {
|
||||
// Updates relay address
|
||||
kmp_address_copy(supp_entry->addr, addr);
|
||||
|
@ -498,64 +841,116 @@ static void ws_pae_auth_kmp_api_finished_indication(kmp_api_t *kmp, kmp_result_e
|
|||
// Should not be possible
|
||||
return;
|
||||
}
|
||||
kmp_service_t *service = kmp_api_service_get(kmp);
|
||||
pae_auth_t *pae_auth = ws_pae_auth_by_kmp_service_get(service);
|
||||
if (!pae_auth) {
|
||||
// Should not be possible
|
||||
return;
|
||||
}
|
||||
|
||||
// Gets type
|
||||
kmp_type_e type = kmp_api_type_get(kmp);
|
||||
ws_pae_auth_next_kmp_trigger(pae_auth, supp_entry);
|
||||
}
|
||||
|
||||
if (type > IEEE_802_1X_INITIAL_KEY) {
|
||||
// For EAPOL-key, start EAP-TLS towards supplicant
|
||||
type = IEEE_802_1X_MKA;
|
||||
tr_debug("PAE start EAP-TLS, eui-64: %s", trace_array(kmp_address_eui_64_get(supp_entry->addr), 8));
|
||||
} else if (type == IEEE_802_1X_MKA) {
|
||||
// After EAP-TLS start 4WH towards supplicant
|
||||
type = IEEE_802_11_4WH;
|
||||
// Insert GTK0
|
||||
sec_prot_keys_gtk_insert_index_set(supp_entry->sec_keys.gtks, 0);
|
||||
tr_debug("PAE start 4WH, eui-64: %s", trace_array(kmp_address_eui_64_get(supp_entry->addr), 8));
|
||||
} else if (type == IEEE_802_11_4WH) {
|
||||
// After 4WH start GKH towards supplicant
|
||||
type = IEEE_802_11_GKH;
|
||||
// Insert GTK1
|
||||
sec_prot_keys_gtk_insert_index_set(supp_entry->sec_keys.gtks, 1);
|
||||
tr_debug("PAE start GKH, eui-64: %s", trace_array(kmp_address_eui_64_get(supp_entry->addr), 8));
|
||||
} else if (type == IEEE_802_11_GKH) {
|
||||
tr_debug("PAE authenticated, eui-64: %s", trace_array(kmp_address_eui_64_get(supp_entry->addr), 8));
|
||||
// After GKH end
|
||||
static void ws_pae_auth_next_kmp_trigger(pae_auth_t *pae_auth, supp_entry_t *supp_entry)
|
||||
{
|
||||
// Disables KMP retry timer
|
||||
supp_entry->retry_ticks = 0;
|
||||
|
||||
// Get next protocol based on what keys supplicant has
|
||||
kmp_type_e next_type = ws_pae_auth_next_protocol_get(supp_entry);
|
||||
|
||||
if (next_type == KMP_TYPE_NONE) {
|
||||
// All done
|
||||
return;
|
||||
}
|
||||
|
||||
// Increases waiting time for supplicant authentication
|
||||
ws_pae_lib_supp_timer_ticks_set(supp_entry, WAIT_FOR_AUTHENTICATION_TICKS);
|
||||
|
||||
kmp_service_t *service = kmp_api_service_get(kmp);
|
||||
pae_auth_t *pae_auth = ws_pae_auth_by_kmp_service_get(service);
|
||||
if (!pae_auth) {
|
||||
return;
|
||||
if (next_type == IEEE_802_1X_MKA) {
|
||||
/* For EAP-TLS, limits the number of ongoing negotiations. If limit
|
||||
is reached, authenticator does not initiate EAP-TLS right away.
|
||||
If previous EAP-TLS negotiation completes before negotiation
|
||||
trigger timeout, authenticator initiates EAP-TLS towards
|
||||
supplicant. Otherwise supplicant must re-send initial EAPOL-Key
|
||||
to try again using its trickle schedule */
|
||||
uint16_t ongoing_eap_tls_cnt = ws_pae_lib_supp_list_kmp_count(&pae_auth->active_supp_list, IEEE_802_1X_MKA);
|
||||
if (ongoing_eap_tls_cnt >= MAX_SIMULTANEOUS_EAP_TLS_NEGOTIATIONS) {
|
||||
supp_entry->retry_ticks = EAP_TLS_NEGOTIATION_TRIGGER_TIMEOUT;
|
||||
tr_info("EAP-TLS max ongoing reached, count %i, delayed: eui-64: %s", ongoing_eap_tls_cnt, trace_array(kmp_address_eui_64_get(supp_entry->addr), 8));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Create new instance
|
||||
kmp_api_t *new_kmp = ws_pae_auth_kmp_create_and_start(pae_auth->kmp_service, type, supp_entry);
|
||||
kmp_api_t *new_kmp = ws_pae_auth_kmp_create_and_start(pae_auth->kmp_service, next_type, supp_entry);
|
||||
if (!new_kmp) {
|
||||
return;
|
||||
}
|
||||
|
||||
// For EAP-TLS create also TLS in addition to EAP-TLS
|
||||
if (type == IEEE_802_1X_MKA) {
|
||||
if (next_type == IEEE_802_1X_MKA) {
|
||||
if (ws_pae_lib_kmp_list_type_get(&supp_entry->kmp_list, TLS_PROT) != NULL) {
|
||||
// TLS already exists, wait for it to be deleted
|
||||
ws_pae_lib_kmp_list_delete(&supp_entry->kmp_list, new_kmp);
|
||||
return;
|
||||
}
|
||||
// Create TLS instance */
|
||||
if (ws_pae_auth_kmp_create_and_start(service, TLS_PROT, supp_entry) == NULL) {
|
||||
if (ws_pae_auth_kmp_create_and_start(pae_auth->kmp_service, TLS_PROT, supp_entry) == NULL) {
|
||||
ws_pae_lib_kmp_list_delete(&supp_entry->kmp_list, new_kmp);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
kmp_api_create_request(new_kmp, type, supp_entry->addr, &supp_entry->sec_keys);
|
||||
kmp_api_create_request(new_kmp, next_type, supp_entry->addr, &supp_entry->sec_keys);
|
||||
}
|
||||
|
||||
static kmp_type_e ws_pae_auth_next_protocol_get(supp_entry_t *supp_entry)
|
||||
{
|
||||
kmp_type_e next_type = KMP_TYPE_NONE;
|
||||
sec_prot_keys_t *sec_keys = &supp_entry->sec_keys;
|
||||
|
||||
// Supplicant has indicated that PMK is not valid
|
||||
if (sec_keys->pmk_mismatch) {
|
||||
sec_keys->ptk_mismatch = true;
|
||||
// start EAP-TLS towards supplicant
|
||||
next_type = IEEE_802_1X_MKA;
|
||||
tr_info("PAE start EAP-TLS, eui-64: %s", trace_array(kmp_address_eui_64_get(supp_entry->addr), 8));
|
||||
} else if (sec_keys->ptk_mismatch) {
|
||||
// start 4WH towards supplicant
|
||||
next_type = IEEE_802_11_4WH;
|
||||
tr_info("PAE start 4WH, eui-64: %s", trace_array(kmp_address_eui_64_get(supp_entry->addr), 8));
|
||||
}
|
||||
|
||||
int8_t gtk_index = -1;
|
||||
if (next_type != IEEE_802_1X_MKA) {
|
||||
// Checks if GTK needs to be inserted
|
||||
gtk_index = sec_prot_keys_gtk_insert_index_from_gtkl_get(sec_keys);
|
||||
|
||||
// For 4WH insert always a key, in case no other then active
|
||||
if (next_type == IEEE_802_11_4WH && gtk_index < 0) {
|
||||
gtk_index = sec_prot_keys_gtk_status_active_get(sec_keys->gtks);
|
||||
}
|
||||
}
|
||||
|
||||
if (gtk_index >= 0) {
|
||||
if (next_type == KMP_TYPE_NONE && gtk_index >= 0) {
|
||||
// Update just GTK
|
||||
next_type = IEEE_802_11_GKH;
|
||||
tr_info("PAE start GKH, eui-64: %s", trace_array(kmp_address_eui_64_get(supp_entry->addr), 8));
|
||||
}
|
||||
|
||||
tr_info("PAE update GTK index: %i, eui-64: %s", gtk_index, trace_array(kmp_address_eui_64_get(supp_entry->addr), 8));
|
||||
}
|
||||
|
||||
if (next_type == KMP_TYPE_NONE) {
|
||||
tr_info("PAE authenticated, eui-64: %s", trace_array(kmp_address_eui_64_get(supp_entry->addr), 8));
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
// Create KMP instance for new authentication
|
||||
|
@ -594,8 +989,25 @@ static void ws_pae_auth_kmp_api_finished(kmp_api_t *kmp)
|
|||
return;
|
||||
}
|
||||
|
||||
pae_auth_t *pae_auth = NULL;
|
||||
supp_entry_t *retry_supp = NULL;
|
||||
// When EAP-TLS completes check if there are other supplicants that have requested it lately
|
||||
if (kmp_api_type_get(kmp) == IEEE_802_1X_MKA) {
|
||||
kmp_service_t *service = kmp_api_service_get(kmp);
|
||||
pae_auth = ws_pae_auth_by_kmp_service_get(service);
|
||||
if (pae_auth) {
|
||||
retry_supp = ws_pae_lib_supp_list_entry_retry_timer_get(&pae_auth->active_supp_list);
|
||||
}
|
||||
}
|
||||
|
||||
// Delete KMP
|
||||
ws_pae_lib_kmp_list_delete(&supp_entry->kmp_list, kmp);
|
||||
|
||||
if (retry_supp) {
|
||||
tr_info("PAE next KMP trigger, eui-64: %s", trace_array(kmp_address_eui_64_get(retry_supp->addr), 8));
|
||||
ws_pae_auth_next_kmp_trigger(pae_auth, retry_supp);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif /* HAVE_PAE_AUTH */
|
||||
|
|
|
@ -44,13 +44,15 @@
|
|||
* \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
|
||||
*
|
||||
* \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, const sec_prot_certs_t *certs);
|
||||
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, timer_settings_t *timer_settings);
|
||||
|
||||
/**
|
||||
* ws_pae_auth_addresses_set set relay addresses
|
||||
|
@ -78,19 +80,126 @@ int8_t ws_pae_auth_addresses_set(protocol_interface_info_entry_t *interface_ptr,
|
|||
int8_t ws_pae_auth_delete(protocol_interface_info_entry_t *interface_ptr);
|
||||
|
||||
/**
|
||||
* ws_pae_auth_timer PAE authenticator timer call
|
||||
* ws_pae_auth_fast_timer PAE authenticator fast timer call
|
||||
*
|
||||
* \param ticks elapsed ticks
|
||||
*
|
||||
*/
|
||||
void ws_pae_auth_timer(uint16_t ticks);
|
||||
void ws_pae_auth_fast_timer(uint16_t ticks);
|
||||
|
||||
/**
|
||||
* ws_pae_auth_slow_timer PAE authenticator slow call
|
||||
*
|
||||
* \param seconds elapsed seconds
|
||||
*
|
||||
*/
|
||||
void ws_pae_auth_slow_timer(uint16_t seconds);
|
||||
|
||||
/**
|
||||
* ws_pae_auth_start start PAE authenticator
|
||||
*
|
||||
* \param interface_ptr interface
|
||||
*
|
||||
*/
|
||||
void ws_pae_auth_start(protocol_interface_info_entry_t *interface_ptr);
|
||||
|
||||
/**
|
||||
* ws_pae_auth_gtks_updated indicates that GTKs has been updated
|
||||
*
|
||||
* \param interface_ptr interface
|
||||
*
|
||||
*/
|
||||
void ws_pae_auth_gtks_updated(protocol_interface_info_entry_t *interface_ptr);
|
||||
|
||||
/**
|
||||
* ws_pae_auth_gtks_updated indicates that key index has been updated
|
||||
*
|
||||
* \param interface_ptr interface
|
||||
* \param index key index
|
||||
*
|
||||
* \return < 0 failure
|
||||
* \return >= 0 success
|
||||
*
|
||||
*/
|
||||
int8_t ws_pae_auth_nw_key_index_update(protocol_interface_info_entry_t *interface_ptr, uint8_t index);
|
||||
|
||||
/**
|
||||
* ws_pae_auth_node_keys_remove removes nodes keys
|
||||
*
|
||||
* \param interface_ptr interface
|
||||
* \param eui64 node's EUI-64
|
||||
*
|
||||
* \return < 0 failure
|
||||
* \return >= 0 success
|
||||
*
|
||||
*/
|
||||
int8_t ws_pae_auth_node_keys_remove(protocol_interface_info_entry_t *interface_ptr, uint8_t *eui64);
|
||||
|
||||
/**
|
||||
* ws_pae_auth_node_access_revoke_start start node's access revoke
|
||||
*
|
||||
* \param interface_ptr interface
|
||||
*
|
||||
* \return < 0 failure
|
||||
* \return >= 0 success
|
||||
*
|
||||
*/
|
||||
int8_t ws_pae_auth_node_access_revoke_start(protocol_interface_info_entry_t *interface_ptr);
|
||||
|
||||
/**
|
||||
* ws_pae_auth_gtk_hash_set GTK hash set callback
|
||||
*
|
||||
* \param interface_ptr interface
|
||||
* \param gtkhash GTK hash, 32 bytes
|
||||
*
|
||||
*/
|
||||
typedef void ws_pae_auth_gtk_hash_set(protocol_interface_info_entry_t *interface_ptr, uint8_t *gtkhash);
|
||||
|
||||
/**
|
||||
* ws_pae_auth_nw_key_insert network key insert callback
|
||||
*
|
||||
* \param interface_ptr interface
|
||||
* \param gtks group keys
|
||||
*
|
||||
* \return < 0 failure
|
||||
* \return >= 0 success
|
||||
*
|
||||
*/
|
||||
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_key_index_set network send key index set callback
|
||||
*
|
||||
* \param interface_ptr interface
|
||||
* \param index network send key index
|
||||
*
|
||||
*/
|
||||
typedef void ws_pae_auth_nw_key_index_set(protocol_interface_info_entry_t *interface_ptr, uint8_t index);
|
||||
|
||||
/**
|
||||
* ws_pae_auth_cb_register register PAE authenticator callbacks
|
||||
*
|
||||
* \param interface_ptr interface
|
||||
* \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
|
||||
*
|
||||
*/
|
||||
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);
|
||||
|
||||
#else
|
||||
|
||||
#define ws_pae_auth_init(interface_ptr, gtks, certs) 1
|
||||
#define ws_pae_auth_init(interface_ptr, gtks, next_gtks, certs, timer_settings) 1
|
||||
#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_timer 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_start(interface_ptr)
|
||||
#define ws_pae_auth_gtks_updated NULL
|
||||
#define ws_pae_auth_nw_key_index_update 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_fast_timer NULL
|
||||
#define ws_pae_auth_slow_timer NULL
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
@ -28,8 +28,10 @@
|
|||
#include "6LoWPAN/ws/ws_pae_controller.h"
|
||||
#include "Security/protocols/sec_prot_certs.h"
|
||||
#include "Security/protocols/sec_prot_keys.h"
|
||||
#include "6LoWPAN/ws/ws_pae_timers.h"
|
||||
#include "6LoWPAN/ws/ws_pae_supp.h"
|
||||
#include "6LoWPAN/ws/ws_pae_auth.h"
|
||||
#include "mbedtls/sha256.h"
|
||||
|
||||
#ifdef HAVE_WS
|
||||
|
||||
|
@ -39,76 +41,110 @@ typedef int8_t ws_pae_delete(protocol_interface_info_entry_t *interface_ptr);
|
|||
typedef void ws_pae_timer(uint16_t ticks);
|
||||
typedef int8_t ws_pae_br_addr_write(protocol_interface_info_entry_t *interface_ptr, const uint8_t *eui_64);
|
||||
typedef int8_t ws_pae_br_addr_read(protocol_interface_info_entry_t *interface_ptr, uint8_t *eui_64);
|
||||
|
||||
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 struct {
|
||||
ns_list_link_t link; /**< Link */
|
||||
uint8_t target_eui_64[8]; /**< EAPOL target */
|
||||
uint16_t target_pan_id; /**< EAPOL target PAN ID */
|
||||
uint8_t br_eui_64[8]; /**< Border router EUI-64 */
|
||||
sec_prot_gtk_keys_t gtks; /**< GTKs */
|
||||
sec_prot_certs_t certs; /**< Certificates */
|
||||
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_key_insert *key_insert; /**< Key insert callback */
|
||||
ws_pae_delete *pae_delete; /**< PAE delete callback */
|
||||
ws_pae_timer *pae_timer; /**< PAE timer callback */
|
||||
ws_pae_br_addr_write *pae_br_addr_write; /**< PAE Border router EUI-64 write callback */
|
||||
ws_pae_br_addr_read *pae_br_addr_read; /**< PAE Border router EUI-64 read callback */
|
||||
uint8_t hash[8]; /**< GTK hash for the key */
|
||||
bool installed : 1; /**< Key has been installed on MAC */
|
||||
bool fresh : 1; /**< Key is fresh i.e. not used on sending */
|
||||
} nw_key_t;
|
||||
|
||||
typedef struct {
|
||||
ns_list_link_t link; /**< Link */
|
||||
uint8_t target_eui_64[8]; /**< EAPOL target */
|
||||
uint16_t target_pan_id; /**< EAPOL target PAN ID */
|
||||
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 */
|
||||
int8_t gtk_index; /**< GTK index */
|
||||
uint8_t gtkhash[32]; /**< GTK hashes */
|
||||
sec_prot_certs_t certs; /**< Certificates */
|
||||
nw_key_t nw_key[4]; /**< Currently active network keys (on MAC) */
|
||||
char *network_name; /**< Network name for GAK generation */
|
||||
timer_settings_t timer_settings; /**< Timer settings */
|
||||
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 */
|
||||
ws_pae_controller_nw_key_clear *nw_key_clear; /**< Key clear callback */
|
||||
ws_pae_controller_nw_send_key_index_set *nw_send_key_index_set; /**< Send key index set callback */
|
||||
ws_pae_controller_nw_frame_counter_set *nw_frame_counter_set; /**< Frame counter set callback */
|
||||
ws_pae_controller_pan_ver_increment *pan_ver_increment; /**< PAN version increment 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 */
|
||||
ws_pae_br_addr_write *pae_br_addr_write; /**< PAE Border router EUI-64 write callback */
|
||||
ws_pae_br_addr_read *pae_br_addr_read; /**< PAE Border router EUI-64 read callback */
|
||||
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 */
|
||||
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 */
|
||||
} pae_controller_t;
|
||||
|
||||
static void ws_pae_controller_test_keys_set(sec_prot_gtk_keys_t *gtks);
|
||||
static pae_controller_t *ws_pae_controller_get(protocol_interface_info_entry_t *interface_ptr);
|
||||
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);
|
||||
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_nw_key_index_check_and_set(protocol_interface_info_entry_t *interface_ptr, uint8_t index);
|
||||
static void ws_pae_controller_data_init(pae_controller_t *controller);
|
||||
|
||||
static NS_LIST_DEFINE(pae_controller_list, pae_controller_t, link);
|
||||
|
||||
#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[2][GTK_LEN];
|
||||
uint8_t gtk[GTK_LEN];
|
||||
|
||||
// Test data
|
||||
for (int i = 0; i < GTK_LEN; i++) {
|
||||
gtk[0][i] = 0xcf - i;
|
||||
gtk[1][i] = 0xef - i;
|
||||
gtk[i] = 0xcf - i;
|
||||
}
|
||||
|
||||
sec_prot_keys_gtk_set(gtks, 0, gtk[0]);
|
||||
sec_prot_keys_gtk_set(gtks, 1, gtk[1]);
|
||||
|
||||
sec_prot_keys_gtkl_set(gtks, 0xFF);
|
||||
|
||||
sec_prot_keys_gtk_insert_index_set(gtks, 0);
|
||||
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)
|
||||
{
|
||||
if (!interface_ptr) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
pae_controller_t *controller = ws_pae_controller_get(interface_ptr);
|
||||
if (!controller) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ws_pae_supp_authenticate(controller->interface_ptr, controller->target_pan_id, controller->target_eui_64) == PAE_SUPP_NOT_ENABLED) {
|
||||
// Already authenticated
|
||||
ws_pae_controller_test_keys_set(&controller->gtks);
|
||||
|
||||
uint8_t index;
|
||||
uint8_t *gtk = sec_prot_keys_get_gtk_to_insert(&controller->gtks, &index);
|
||||
|
||||
controller->key_insert(controller->interface_ptr, index, gtk);
|
||||
#ifdef HAVE_PAE_SUPP
|
||||
// In case test keys are set uses those and does not initiate authentication
|
||||
if (controller->gtks_set) {
|
||||
if (sec_prot_keys_gtks_are_updated(&controller->gtks)) {
|
||||
ws_pae_controller_nw_key_check_and_insert(controller->interface_ptr, &controller->gtks);
|
||||
sec_prot_keys_gtks_updated_reset(&controller->gtks);
|
||||
}
|
||||
controller->auth_completed(interface_ptr, true);
|
||||
return 0;
|
||||
}
|
||||
|
||||
///////////
|
||||
// For now fixed since not yet support for EA-IE
|
||||
const uint8_t addr[8] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08};
|
||||
if (controller->pae_br_addr_write) {
|
||||
controller->pae_br_addr_write(interface_ptr, addr);
|
||||
if (ws_pae_supp_authenticate(controller->interface_ptr, controller->target_pan_id, controller->target_eui_64) < 0) {
|
||||
controller->auth_completed(interface_ptr, false);
|
||||
}
|
||||
////////////////
|
||||
|
||||
#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, true);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -127,21 +163,32 @@ 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);
|
||||
|
||||
uint8_t index;
|
||||
uint8_t *gtk = sec_prot_keys_get_gtk_to_insert(&controller->gtks, &index);
|
||||
|
||||
controller->key_insert(controller->interface_ptr, index, gtk);
|
||||
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;
|
||||
}
|
||||
|
||||
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_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_key_insert *key_insert)
|
||||
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_pan_ver_increment *pan_ver_increment)
|
||||
{
|
||||
if (!interface_ptr) {
|
||||
return -1;
|
||||
|
@ -153,7 +200,11 @@ int8_t ws_pae_controller_cb_register(protocol_interface_info_entry_t *interface_
|
|||
}
|
||||
|
||||
controller->auth_completed = completed;
|
||||
controller->key_insert = key_insert;
|
||||
controller->nw_key_set = nw_key_set;
|
||||
controller->nw_key_clear = nw_key_clear;
|
||||
controller->nw_send_key_index_set = nw_send_key_index_set;
|
||||
controller->nw_frame_counter_set = nw_frame_counter_set;
|
||||
controller->pan_ver_increment = pan_ver_increment;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -189,6 +240,8 @@ int8_t ws_pae_controller_nw_info_set(protocol_interface_info_entry_t *interface_
|
|||
return -1;
|
||||
}
|
||||
|
||||
controller->network_name = network_name;
|
||||
|
||||
return ws_pae_supp_nw_info_set(interface_ptr, pan_id, network_name);
|
||||
}
|
||||
|
||||
|
@ -206,6 +259,202 @@ int8_t ws_pae_controller_nw_key_valid(protocol_interface_info_entry_t *interface
|
|||
return ws_pae_supp_nw_key_valid(interface_ptr);
|
||||
}
|
||||
|
||||
static int8_t ws_pae_controller_nw_key_check_and_insert(protocol_interface_info_entry_t *interface_ptr, sec_prot_gtk_keys_t *gtks)
|
||||
{
|
||||
int8_t ret = -1;
|
||||
|
||||
pae_controller_t *controller = ws_pae_controller_get(interface_ptr);
|
||||
if (!controller) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint8_t gtkhash[GTK_ALL_HASHES_LEN];
|
||||
sec_prot_keys_gtks_hash_generate(gtks, gtkhash);
|
||||
|
||||
nw_key_t *nw_key = controller->nw_key;
|
||||
|
||||
// Delete old keys
|
||||
uint8_t *gtk_hash_ptr = gtkhash;
|
||||
for (uint8_t i = 0; i < GTK_NUM; i++) {
|
||||
// If hash is not set for a key
|
||||
if (sec_prot_keys_gtk_hash_empty(gtk_hash_ptr)) {
|
||||
// Deletes the key if it is set
|
||||
if (!sec_prot_keys_gtk_hash_empty(nw_key[i].hash)) {
|
||||
tr_info("NW key remove: %i", i);
|
||||
controller->nw_key_clear(interface_ptr, i);
|
||||
nw_key[i].installed = false;
|
||||
}
|
||||
}
|
||||
gtk_hash_ptr += GTK_HASH_LEN;
|
||||
}
|
||||
|
||||
// Insert new keys
|
||||
gtk_hash_ptr = gtkhash;
|
||||
for (uint8_t i = 0; i < GTK_NUM; i++) {
|
||||
// If hash is set for a key
|
||||
if (!sec_prot_keys_gtk_hash_empty(gtk_hash_ptr)) {
|
||||
int hash_matches = memcmp(gtk_hash_ptr, nw_key[i].hash, GTK_HASH_LEN);
|
||||
// If the hash does not match (not set or modified) or not installed
|
||||
if (hash_matches != 0 || !nw_key[i].installed) {
|
||||
|
||||
memcpy(nw_key[i].hash, gtk_hash_ptr, GTK_HASH_LEN);
|
||||
|
||||
nw_key[i].installed = true;
|
||||
if (hash_matches != 0) {
|
||||
nw_key[i].fresh = true;
|
||||
}
|
||||
|
||||
uint8_t *gtk = sec_prot_keys_gtk_get(gtks, i);
|
||||
tr_info("NW key set: %i, hash: %s", i, trace_array(nw_key[i].hash, 8));
|
||||
uint8_t gak[GTK_LEN];
|
||||
if (ws_pae_controller_gak_from_gtk(gak, gtk, controller->network_name) >= 0) {
|
||||
controller->nw_key_set(interface_ptr, i, i, gak);
|
||||
ret = 0;
|
||||
} else {
|
||||
tr_error("GAK generation failed network name: %s", controller->network_name);
|
||||
ret = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
gtk_hash_ptr += GTK_HASH_LEN;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void ws_pae_controller_active_nw_key_clear(nw_key_t *nw_key)
|
||||
{
|
||||
memset(nw_key, 0, sizeof(nw_key_t));
|
||||
nw_key->installed = false;
|
||||
nw_key->fresh = false;
|
||||
}
|
||||
|
||||
static int8_t ws_pae_controller_gak_from_gtk(uint8_t *gak, uint8_t *gtk, char *network_name)
|
||||
{
|
||||
#if defined(HAVE_PAE_SUPP) || defined(HAVE_PAE_AUTH)
|
||||
uint8_t network_name_len = strlen(network_name);
|
||||
if (network_name_len == 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
uint8_t input[network_name_len + GTK_LEN];
|
||||
memcpy(input, network_name, network_name_len);
|
||||
memcpy(input + network_name_len, gtk, GTK_LEN);
|
||||
|
||||
int8_t ret_val = 0;
|
||||
|
||||
mbedtls_sha256_context ctx;
|
||||
|
||||
mbedtls_sha256_init(&ctx);
|
||||
|
||||
if (mbedtls_sha256_starts_ret(&ctx, 0) != 0) {
|
||||
ret_val = -1;
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (mbedtls_sha256_update_ret(&ctx, input, network_name_len + GTK_LEN) != 0) {
|
||||
ret_val = -1;
|
||||
goto error;
|
||||
}
|
||||
|
||||
uint8_t output[32];
|
||||
|
||||
if (mbedtls_sha256_finish_ret(&ctx, output) != 0) {
|
||||
ret_val = -1;
|
||||
goto error;
|
||||
}
|
||||
|
||||
memcpy(gak, &output[0], 16);
|
||||
|
||||
error:
|
||||
mbedtls_sha256_free(&ctx);
|
||||
|
||||
return ret_val;
|
||||
#else
|
||||
(void) network_name;
|
||||
memcpy(gak, gtk, 16);
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
int8_t ws_pae_controller_nw_key_index_update(protocol_interface_info_entry_t *interface_ptr, uint8_t index)
|
||||
{
|
||||
pae_controller_t *controller = ws_pae_controller_get(interface_ptr);
|
||||
if (!controller) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (controller->pae_nw_key_index_update) {
|
||||
controller->pae_nw_key_index_update(interface_ptr, index);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ws_pae_controller_nw_keys_remove(protocol_interface_info_entry_t *interface_ptr)
|
||||
{
|
||||
pae_controller_t *controller = ws_pae_controller_get(interface_ptr);
|
||||
if (!controller) {
|
||||
return;
|
||||
}
|
||||
|
||||
tr_info("NW keys remove");
|
||||
|
||||
nw_key_t *nw_key = controller->nw_key;
|
||||
for (uint8_t i = 0; i < GTK_NUM; i++) {
|
||||
// Deletes the key if it is set
|
||||
if (!sec_prot_keys_gtk_hash_empty(nw_key[i].hash)) {
|
||||
tr_info("NW key remove: %i", i);
|
||||
controller->nw_key_clear(interface_ptr, i);
|
||||
nw_key[i].installed = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
if (!controller) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (controller->nw_send_key_index_set) {
|
||||
tr_info("NW send key index set: %i", index + 1);
|
||||
controller->nw_send_key_index_set(interface_ptr, index);
|
||||
controller->nw_frame_counter_set(interface_ptr, 0);
|
||||
}
|
||||
|
||||
// Do not update PAN version for initial key index set
|
||||
if (controller->key_index_set) {
|
||||
if (controller->pan_ver_increment) {
|
||||
controller->pan_ver_increment(interface_ptr);
|
||||
}
|
||||
} else {
|
||||
controller->key_index_set = true;
|
||||
}
|
||||
}
|
||||
|
||||
static void ws_pae_controller_active_nw_key_set(protocol_interface_info_entry_t *cur, uint8_t index)
|
||||
{
|
||||
pae_controller_t *controller = ws_pae_controller_get(cur);
|
||||
if (!controller) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (controller->nw_send_key_index_set) {
|
||||
controller->nw_send_key_index_set(controller->interface_ptr, index);
|
||||
|
||||
// If index has changed and the key for the index is fresh reset frame counter
|
||||
if (controller->gtk_index != index && controller->nw_key[index].fresh) {
|
||||
controller->nw_frame_counter_set(cur, 0);
|
||||
}
|
||||
|
||||
controller->gtk_index = index;
|
||||
controller->nw_key[index].fresh = false;
|
||||
}
|
||||
}
|
||||
|
||||
int8_t ws_pae_controller_init(protocol_interface_info_entry_t *interface_ptr)
|
||||
{
|
||||
if (!interface_ptr) {
|
||||
|
@ -221,75 +470,97 @@ int8_t ws_pae_controller_init(protocol_interface_info_entry_t *interface_ptr)
|
|||
return -1;
|
||||
}
|
||||
|
||||
memset(controller->target_eui_64, 0, 8);
|
||||
memset(controller->br_eui_64, 0, 8);
|
||||
controller->interface_ptr = interface_ptr;
|
||||
controller->auth_completed = NULL;
|
||||
controller->key_insert = NULL;
|
||||
controller->pae_delete = NULL;
|
||||
controller->pae_timer = NULL;
|
||||
controller->pae_br_addr_write = NULL;
|
||||
controller->pae_br_addr_read = NULL;
|
||||
controller->nw_key_set = NULL;
|
||||
controller->nw_key_clear = NULL;
|
||||
controller->nw_send_key_index_set = NULL;
|
||||
controller->nw_frame_counter_set = NULL;
|
||||
controller->pan_ver_increment = NULL;
|
||||
|
||||
sec_prot_keys_gtks_init(&controller->gtks);
|
||||
sec_prot_certs_init(&controller->certs);
|
||||
ws_pae_controller_data_init(controller);
|
||||
|
||||
ns_list_add_to_end(&pae_controller_list, controller);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ws_pae_controller_data_init(pae_controller_t *controller)
|
||||
{
|
||||
memset(controller->target_eui_64, 0, 8);
|
||||
memset(controller->br_eui_64, 0, 8);
|
||||
memset(controller->gtkhash, 0, 32);
|
||||
|
||||
ws_pae_controller_active_nw_key_clear(&controller->nw_key[0]);
|
||||
ws_pae_controller_active_nw_key_clear(&controller->nw_key[1]);
|
||||
ws_pae_controller_active_nw_key_clear(&controller->nw_key[2]);
|
||||
ws_pae_controller_active_nw_key_clear(&controller->nw_key[3]);
|
||||
|
||||
controller->target_pan_id = 0xffff;
|
||||
controller->pae_delete = NULL;
|
||||
controller->pae_fast_timer = NULL;
|
||||
controller->pae_slow_timer = NULL;
|
||||
controller->pae_br_addr_write = NULL;
|
||||
controller->pae_br_addr_read = NULL;
|
||||
controller->pae_gtks_updated = NULL;
|
||||
controller->pae_gtk_hash_update = NULL;
|
||||
controller->pae_nw_key_index_update = NULL;
|
||||
controller->gtks_set = false;
|
||||
controller->gtkhash_set = false;
|
||||
controller->key_index_set = false;
|
||||
controller->gtk_index = -1;
|
||||
controller->network_name = NULL;
|
||||
sec_prot_keys_gtks_init(&controller->gtks);
|
||||
sec_prot_keys_gtks_init(&controller->next_gtks);
|
||||
sec_prot_certs_init(&controller->certs);
|
||||
ws_pae_timers_settings_init(&controller->timer_settings);
|
||||
}
|
||||
|
||||
int8_t ws_pae_controller_supp_init(protocol_interface_info_entry_t *interface_ptr)
|
||||
{
|
||||
if (!interface_ptr) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
pae_controller_t *controller = ws_pae_controller_get(interface_ptr);
|
||||
if (!controller) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ws_pae_supp_init(controller->interface_ptr, &controller->certs) < 0) {
|
||||
if (ws_pae_supp_init(controller->interface_ptr, &controller->certs, &controller->timer_settings) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
controller->pae_delete = ws_pae_supp_delete;
|
||||
controller->pae_timer = ws_pae_supp_timer;
|
||||
controller->pae_fast_timer = ws_pae_supp_fast_timer;
|
||||
controller->pae_slow_timer = ws_pae_supp_slow_timer;
|
||||
controller->pae_br_addr_write = ws_pae_supp_border_router_addr_write;
|
||||
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;
|
||||
|
||||
ws_pae_supp_cb_register(controller->interface_ptr, controller->auth_completed, controller->key_insert);
|
||||
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);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int8_t ws_pae_controller_auth_init(protocol_interface_info_entry_t *interface_ptr)
|
||||
{
|
||||
if (!interface_ptr) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
pae_controller_t *controller = ws_pae_controller_get(interface_ptr);
|
||||
if (!controller) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ws_pae_auth_init(controller->interface_ptr, &controller->gtks, &controller->certs) < 0) {
|
||||
if (ws_pae_auth_init(controller->interface_ptr, &controller->gtks, &controller->next_gtks, &controller->certs, &controller->timer_settings) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
controller->pae_delete = ws_pae_auth_delete;
|
||||
controller->pae_timer = ws_pae_auth_timer;
|
||||
controller->pae_fast_timer = ws_pae_auth_fast_timer;
|
||||
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;
|
||||
|
||||
return 0;
|
||||
}
|
||||
int8_t ws_pae_controller_stop(protocol_interface_info_entry_t *interface_ptr)
|
||||
{
|
||||
if (!interface_ptr) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
pae_controller_t *controller = ws_pae_controller_get(interface_ptr);
|
||||
if (!controller) {
|
||||
return -1;
|
||||
|
@ -300,6 +571,12 @@ int8_t ws_pae_controller_stop(protocol_interface_info_entry_t *interface_ptr)
|
|||
controller->pae_delete(interface_ptr);
|
||||
}
|
||||
|
||||
// Free data
|
||||
sec_prot_certs_delete(&controller->certs);
|
||||
|
||||
// Init controller data
|
||||
ws_pae_controller_data_init(controller);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -317,9 +594,6 @@ int8_t ws_pae_controller_delete(protocol_interface_info_entry_t *interface_ptr)
|
|||
}
|
||||
|
||||
ns_list_remove(&pae_controller_list, controller);
|
||||
|
||||
sec_prot_certs_delete(&controller->certs);
|
||||
|
||||
ns_dyn_mem_free(controller);
|
||||
|
||||
return 0;
|
||||
|
@ -327,29 +601,135 @@ int8_t ws_pae_controller_delete(protocol_interface_info_entry_t *interface_ptr)
|
|||
|
||||
int8_t ws_pae_controller_certificate_chain_set(const arm_certificate_chain_entry_s *new_chain)
|
||||
{
|
||||
if (!new_chain) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
ns_list_foreach(pae_controller_t, entry, &pae_controller_list) {
|
||||
// Delete previous information
|
||||
sec_prot_certs_delete(&entry->certs);
|
||||
|
||||
// Adds a trusted certificate from index 0
|
||||
if (new_chain->cert_chain[0]) {
|
||||
cert_chain_entry_t *root_ca_chain = sec_prot_certs_chain_entry_create();
|
||||
sec_prot_certs_cert_set(root_ca_chain, 0, (uint8_t *) new_chain->cert_chain[0], new_chain->cert_len[0]);
|
||||
sec_prot_certs_chain_list_add(&entry->certs.trusted_cert_chain_list, root_ca_chain);
|
||||
}
|
||||
|
||||
if (new_chain->cert_chain[1] && new_chain->key_chain[1]) {
|
||||
sec_prot_certs_cert_set(&entry->certs.own_cert_chain, 0, (uint8_t *) new_chain->cert_chain[1], new_chain->cert_len[1]);
|
||||
uint8_t key_len = strlen((char *) new_chain->key_chain[1]) + 1;
|
||||
sec_prot_certs_priv_key_set(&entry->certs.own_cert_chain, (uint8_t *) new_chain->key_chain[1], key_len);
|
||||
// Adds own certificate chain from indexes 1 to 3
|
||||
for (uint8_t i = 1; i < SEC_PROT_CERT_CHAIN_DEPTH; i++) {
|
||||
if (new_chain->cert_chain[i]) {
|
||||
sec_prot_certs_cert_set(&entry->certs.own_cert_chain, i - 1, (uint8_t *) new_chain->cert_chain[i], new_chain->cert_len[i]);
|
||||
if (new_chain->key_chain[i]) {
|
||||
// Will be the key from top certificate in chain after all certificates are added
|
||||
uint8_t key_len = strlen((char *) new_chain->key_chain[i]) + 1;
|
||||
sec_prot_certs_priv_key_set(&entry->certs.own_cert_chain, (uint8_t *) new_chain->key_chain[i], key_len);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int8_t ws_pae_controller_trusted_certificate_add(const arm_certificate_entry_s *cert)
|
||||
{
|
||||
if (!cert) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int8_t ret = -1;
|
||||
|
||||
ns_list_foreach(pae_controller_t, entry, &pae_controller_list) {
|
||||
cert_chain_entry_t *trusted_cert = sec_prot_certs_chain_entry_create();
|
||||
sec_prot_certs_cert_set(trusted_cert, 0, (uint8_t *) cert->cert, cert->cert_len);
|
||||
|
||||
if (sec_prot_certs_chain_list_entry_find(&entry->certs.trusted_cert_chain_list, trusted_cert)) {
|
||||
sec_prot_certs_chain_entry_delete(trusted_cert);
|
||||
continue;
|
||||
}
|
||||
sec_prot_certs_chain_list_add(&entry->certs.trusted_cert_chain_list, trusted_cert);
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int8_t ws_pae_controller_trusted_certificate_remove(const arm_certificate_entry_s *cert)
|
||||
{
|
||||
if (!cert) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int8_t ret = -1;
|
||||
|
||||
cert_chain_entry_t *trusted_cert = sec_prot_certs_chain_entry_create();
|
||||
sec_prot_certs_cert_set(trusted_cert, 0, (uint8_t *) cert->cert, cert->cert_len);
|
||||
|
||||
ns_list_foreach(pae_controller_t, entry, &pae_controller_list) {
|
||||
cert_chain_entry_t *removed_cert = sec_prot_certs_chain_list_entry_find(&entry->certs.trusted_cert_chain_list, trusted_cert);
|
||||
if (removed_cert) {
|
||||
sec_prot_certs_chain_list_entry_delete(&entry->certs.trusted_cert_chain_list, removed_cert);
|
||||
ret = 0;
|
||||
}
|
||||
}
|
||||
|
||||
sec_prot_certs_chain_entry_delete(trusted_cert);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int8_t ws_pae_controller_certificate_revocation_list_add(const arm_cert_revocation_list_entry_s *crl)
|
||||
{
|
||||
if (!crl) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int8_t ret = -1;
|
||||
|
||||
ns_list_foreach(pae_controller_t, entry, &pae_controller_list) {
|
||||
cert_revocat_list_entry_t *cert_revoc_list = sec_prot_certs_revocat_list_entry_create();
|
||||
sec_prot_certs_revocat_list_set(cert_revoc_list, crl->crl, crl->crl_len);
|
||||
|
||||
if (sec_prot_certs_revocat_lists_entry_find(&entry->certs.cert_revocat_lists, cert_revoc_list)) {
|
||||
sec_prot_certs_revocat_list_entry_delete(cert_revoc_list);
|
||||
continue;
|
||||
}
|
||||
|
||||
sec_prot_certs_revocat_lists_add(&entry->certs.cert_revocat_lists, cert_revoc_list);
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int8_t ws_pae_controller_certificate_revocation_list_remove(const arm_cert_revocation_list_entry_s *crl)
|
||||
{
|
||||
if (!crl) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int8_t ret = -1;
|
||||
|
||||
cert_revocat_list_entry_t *cert_revoc_list = sec_prot_certs_revocat_list_entry_create();
|
||||
sec_prot_certs_revocat_list_set(cert_revoc_list, crl->crl, crl->crl_len);
|
||||
|
||||
ns_list_foreach(pae_controller_t, entry, &pae_controller_list) {
|
||||
cert_revocat_list_entry_t *removed_cert_revoc_list = sec_prot_certs_revocat_lists_entry_find(&entry->certs.cert_revocat_lists, cert_revoc_list);
|
||||
if (removed_cert_revoc_list) {
|
||||
sec_prot_certs_revocat_lists_entry_delete(&entry->certs.cert_revocat_lists, removed_cert_revoc_list);
|
||||
ret = 0;
|
||||
}
|
||||
}
|
||||
|
||||
sec_prot_certs_revocat_list_entry_delete(cert_revoc_list);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int8_t ws_pae_controller_border_router_addr_write(protocol_interface_info_entry_t *interface_ptr, const uint8_t *eui_64)
|
||||
{
|
||||
if (!interface_ptr || !eui_64) {
|
||||
if (!eui_64) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -365,12 +745,11 @@ int8_t ws_pae_controller_border_router_addr_write(protocol_interface_info_entry_
|
|||
}
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
int8_t ws_pae_controller_border_router_addr_read(protocol_interface_info_entry_t *interface_ptr, uint8_t *eui_64)
|
||||
{
|
||||
if (!interface_ptr || !eui_64) {
|
||||
if (!eui_64) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -388,11 +767,197 @@ int8_t ws_pae_controller_border_router_addr_read(protocol_interface_info_entry_t
|
|||
return 0;
|
||||
}
|
||||
|
||||
void ws_pae_controller_timer(uint16_t ticks)
|
||||
int8_t ws_pae_controller_gtk_update(int8_t interface_id, uint8_t *gtk[4])
|
||||
{
|
||||
if (!gtk) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
pae_controller_t *controller = ws_pae_controller_get_or_create(interface_id);
|
||||
if (!controller) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Removes keys set as not used
|
||||
for (uint8_t i = 0; i < GTK_NUM; i++) {
|
||||
if (!gtk[i]) {
|
||||
sec_prot_keys_gtk_clear(&controller->gtks, i);
|
||||
}
|
||||
}
|
||||
|
||||
// Inserts new keys
|
||||
for (uint8_t i = 0; i < GTK_NUM; i++) {
|
||||
if (gtk[i]) {
|
||||
uint32_t lifetime = sec_prot_keys_gtk_install_order_last_lifetime_get(&controller->gtks);
|
||||
lifetime += controller->timer_settings.gtk_expire_offset;
|
||||
if (sec_prot_keys_gtk_set(&controller->gtks, i, gtk[i], lifetime) >= 0) {
|
||||
tr_info("GTK set index: %i, lifetime %"PRIu32", system time: %"PRIu32"", i, lifetime, protocol_core_monotonic_time / 10);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Notifies PAE authenticator that GTKs have been updated */
|
||||
if (controller->pae_gtks_updated) {
|
||||
controller->pae_gtks_updated(controller->interface_ptr);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int8_t ws_pae_controller_next_gtk_update(int8_t interface_id, uint8_t *gtk[4])
|
||||
{
|
||||
if (!gtk) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
pae_controller_t *controller = ws_pae_controller_get_or_create(interface_id);
|
||||
if (!controller) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Inserts new keys and removed keys set as not used
|
||||
for (uint8_t i = 0; i < GTK_NUM; i++) {
|
||||
if (gtk[i]) {
|
||||
sec_prot_keys_gtk_set(&controller->next_gtks, i, gtk[i], 0);
|
||||
} else {
|
||||
sec_prot_keys_gtk_clear(&controller->next_gtks, i);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int8_t ws_pae_controller_active_key_update(int8_t interface_id, uint8_t index)
|
||||
{
|
||||
pae_controller_t *controller = ws_pae_controller_get_or_create(interface_id);
|
||||
if (!controller) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
controller->gtk_index = index;
|
||||
|
||||
if (controller->pae_nw_key_index_update) {
|
||||
controller->pae_nw_key_index_update(controller->interface_ptr, index);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int8_t ws_pae_controller_key_lifetime_update(int8_t interface_id, uint32_t gtk_lifetime, uint32_t pmk_lifetime, uint32_t ptk_lifetime)
|
||||
{
|
||||
pae_controller_t *controller = ws_pae_controller_get_or_create(interface_id);
|
||||
if (!controller) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
ws_pae_timers_lifetime_set(&controller->timer_settings, gtk_lifetime, pmk_lifetime, ptk_lifetime);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int8_t ws_pae_controller_gtk_time_settings_update(int8_t interface_id, uint8_t revocat_lifetime_reduct, uint8_t new_activation_time, uint8_t new_install_req, uint32_t max_mismatch)
|
||||
{
|
||||
pae_controller_t *controller = ws_pae_controller_get_or_create(interface_id);
|
||||
if (!controller) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
ws_pae_timers_gtk_time_settings_set(&controller->timer_settings, revocat_lifetime_reduct, new_activation_time, new_install_req, max_mismatch);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int8_t ws_pae_controller_node_keys_remove(int8_t interface_id, uint8_t *eui_64)
|
||||
{
|
||||
#ifndef HAVE_PAE_AUTH
|
||||
(void) eui_64;
|
||||
#endif
|
||||
|
||||
pae_controller_t *controller = ws_pae_controller_get_or_create(interface_id);
|
||||
if (!controller) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return ws_pae_auth_node_keys_remove(controller->interface_ptr, eui_64);
|
||||
}
|
||||
|
||||
int8_t ws_pae_controller_node_access_revoke_start(int8_t interface_id)
|
||||
{
|
||||
pae_controller_t *controller = ws_pae_controller_get_or_create(interface_id);
|
||||
if (!controller) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
ws_pae_auth_node_access_revoke_start(controller->interface_ptr);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void ws_pae_controller_gtk_hash_set(protocol_interface_info_entry_t *interface_ptr, uint8_t *gtkhash)
|
||||
{
|
||||
pae_controller_t *controller = ws_pae_controller_get(interface_ptr);
|
||||
if (!controller) {
|
||||
return;
|
||||
}
|
||||
|
||||
memcpy(controller->gtkhash, gtkhash, 32);
|
||||
|
||||
tr_info("GTK hash set %s %s %s %s",
|
||||
trace_array(>khash[0], 8),
|
||||
trace_array(>khash[8], 8),
|
||||
trace_array(>khash[16], 8),
|
||||
trace_array(>khash[24], 8));
|
||||
|
||||
// Do not update PAN version for initial hash set
|
||||
if (controller->gtkhash_set) {
|
||||
if (controller->pan_ver_increment) {
|
||||
controller->pan_ver_increment(interface_ptr);
|
||||
}
|
||||
} else {
|
||||
controller->gtkhash_set = true;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t *ws_pae_controller_gtk_hash_ptr_get(protocol_interface_info_entry_t *interface_ptr)
|
||||
{
|
||||
pae_controller_t *controller = ws_pae_controller_get(interface_ptr);
|
||||
if (!controller) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return controller->gtkhash;
|
||||
}
|
||||
|
||||
int8_t ws_pae_controller_gtk_hash_update(protocol_interface_info_entry_t *interface_ptr, uint8_t *gtkhash)
|
||||
{
|
||||
pae_controller_t *controller = ws_pae_controller_get(interface_ptr);
|
||||
if (!controller) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
memcpy(controller->gtkhash, gtkhash, 32);
|
||||
|
||||
if (controller->pae_gtk_hash_update) {
|
||||
return controller->pae_gtk_hash_update(interface_ptr, gtkhash);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ws_pae_controller_fast_timer(uint16_t ticks)
|
||||
{
|
||||
ns_list_foreach(pae_controller_t, entry, &pae_controller_list) {
|
||||
if (entry->pae_timer) {
|
||||
entry->pae_timer(ticks);
|
||||
if (entry->pae_fast_timer) {
|
||||
entry->pae_fast_timer(ticks);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ws_pae_controller_slow_timer(uint16_t seconds)
|
||||
{
|
||||
ns_list_foreach(pae_controller_t, entry, &pae_controller_list) {
|
||||
if (entry->pae_slow_timer) {
|
||||
entry->pae_slow_timer(seconds);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -408,5 +973,24 @@ static pae_controller_t *ws_pae_controller_get(protocol_interface_info_entry_t *
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static pae_controller_t *ws_pae_controller_get_or_create(int8_t interface_id)
|
||||
{
|
||||
protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(interface_id);
|
||||
if (!cur) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pae_controller_t *controller = ws_pae_controller_get(cur);
|
||||
|
||||
if (!controller) {
|
||||
if (ws_pae_controller_init(cur) < 0) {
|
||||
return NULL;
|
||||
}
|
||||
controller = ws_pae_controller_get(cur);
|
||||
}
|
||||
|
||||
return controller;
|
||||
}
|
||||
|
||||
#endif /* HAVE_WS */
|
||||
|
||||
|
|
|
@ -124,6 +124,50 @@ int8_t ws_pae_controller_delete(protocol_interface_info_entry_t *interface_ptr);
|
|||
*/
|
||||
int8_t ws_pae_controller_certificate_chain_set(const arm_certificate_chain_entry_s *chain);
|
||||
|
||||
/**
|
||||
* ws_pae_controller_trusted_certificate_add add trusted certificate
|
||||
*
|
||||
* \param cert trusted certificate
|
||||
*
|
||||
* \return < 0 failure
|
||||
* \return >= 0 success
|
||||
*
|
||||
*/
|
||||
int8_t ws_pae_controller_trusted_certificate_add(const arm_certificate_entry_s *cert);
|
||||
|
||||
/**
|
||||
* ws_pae_controller_trusted_certificate_remove remove trusted certificate
|
||||
*
|
||||
* \param cert trusted certificate
|
||||
*
|
||||
* \return < 0 failure
|
||||
* \return >= 0 success
|
||||
*
|
||||
*/
|
||||
int8_t ws_pae_controller_trusted_certificate_remove(const arm_certificate_entry_s *cert);
|
||||
|
||||
/**
|
||||
* ws_pae_controller_certificate_revocation_list_add add certification revocation list
|
||||
*
|
||||
* \param crl certification revocation list
|
||||
*
|
||||
* \return < 0 failure
|
||||
* \return >= 0 success
|
||||
*
|
||||
*/
|
||||
int8_t ws_pae_controller_certificate_revocation_list_add(const arm_cert_revocation_list_entry_s *crl);
|
||||
|
||||
/**
|
||||
* ws_pae_controller_certificate_revocation_list_remove remove certification revocation list
|
||||
*
|
||||
* \param crl certification revocation list
|
||||
*
|
||||
* \return < 0 failure
|
||||
* \return >= 0 success
|
||||
*
|
||||
*/
|
||||
int8_t ws_pae_controller_certificate_revocation_list_remove(const arm_cert_revocation_list_entry_s *crl);
|
||||
|
||||
/**
|
||||
* ws_pae_controller_nw_info_set set network information
|
||||
*
|
||||
|
@ -173,14 +217,172 @@ int8_t ws_pae_controller_border_router_addr_write(protocol_interface_info_entry_
|
|||
int8_t ws_pae_controller_border_router_addr_read(protocol_interface_info_entry_t *interface_ptr, uint8_t *eui_64);
|
||||
|
||||
/**
|
||||
* ws_pae_controller_key_insert new GTK key available callback
|
||||
* ws_pae_controller_gtk_update update GTKs (test interface)
|
||||
*
|
||||
* \param interface_ptr interface
|
||||
* \param gtk_index index of the new GTK key
|
||||
* \param gtk new GTK key
|
||||
* \param interface_id interface identifier
|
||||
* \param gtk GTK array, if GTK is not set, pointer for the index shall be NULL.
|
||||
*
|
||||
* \return < 0 failure
|
||||
* \return >= 0 success
|
||||
*
|
||||
*/
|
||||
typedef void ws_pae_controller_key_insert(protocol_interface_info_entry_t *interface_ptr, uint8_t gtk_index, uint8_t *gtk);
|
||||
int8_t ws_pae_controller_gtk_update(int8_t interface_id, uint8_t *gtk[4]);
|
||||
|
||||
/**
|
||||
* ws_pae_controller_next_gtk_update update next GTKs used during GTK lifecycle (test interface)
|
||||
*
|
||||
* \param interface_id interface identifier
|
||||
* \param gtk GTK array, if GTK is not set, pointer for the index shall be NULL.
|
||||
*
|
||||
* \return < 0 failure
|
||||
* \return >= 0 success
|
||||
*
|
||||
*/
|
||||
int8_t ws_pae_controller_next_gtk_update(int8_t interface_id, uint8_t *gtk[4]);
|
||||
|
||||
/**
|
||||
* ws_pae_controller_key_lifetime_update update key lifetime
|
||||
*
|
||||
* \param interface_id interface identifier
|
||||
* \param gtk_lifetime GTK lifetime
|
||||
* \param pmk_lifetime PMK lifetime
|
||||
* \param ptk_lifetime PTK lifetime
|
||||
*
|
||||
* \return < 0 failure
|
||||
* \return >= 0 success
|
||||
*
|
||||
*/
|
||||
int8_t ws_pae_controller_key_lifetime_update(int8_t interface_id, uint32_t gtk_lifetime, uint32_t pmk_lifetime, uint32_t ptk_lifetime);
|
||||
|
||||
/**
|
||||
* ws_pae_controller_gtk_time_settings_update update GTK time settings
|
||||
*
|
||||
* \param interface_id interface identifier
|
||||
* \param revocat_lifetime_reduct revocation lifetime reduction
|
||||
* \param new_activation_time new activation time
|
||||
* \param new_install_req new install required
|
||||
* \param max_mismatch max mismatch time
|
||||
*
|
||||
* \return < 0 failure
|
||||
* \return >= 0 success
|
||||
*
|
||||
*/
|
||||
int8_t ws_pae_controller_gtk_time_settings_update(int8_t interface_id, uint8_t revocat_lifetime_reduct, uint8_t new_activation_time, uint8_t new_install_req, uint32_t max_mismatch);
|
||||
|
||||
/**
|
||||
* ws_pae_controller_node_keys_remove remove node's keys
|
||||
*
|
||||
* \param interface_id interface identifier
|
||||
* \param eui-64 EUI-64
|
||||
*
|
||||
* \return < 0 failure
|
||||
* \return >= 0 success
|
||||
*
|
||||
*/
|
||||
int8_t ws_pae_controller_node_keys_remove(int8_t interface_id, uint8_t *eui_64);
|
||||
|
||||
/**
|
||||
* ws_pae_controller_node_access_revoke_start start node's access revoke
|
||||
*
|
||||
* \param interface_id interface identifier
|
||||
*
|
||||
* \return < 0 failure
|
||||
* \return >= 0 success
|
||||
*
|
||||
*/
|
||||
int8_t ws_pae_controller_node_access_revoke_start(int8_t interface_id);
|
||||
|
||||
/**
|
||||
* ws_pae_controller_active_key_update update active key (test interface)
|
||||
*
|
||||
* \param interface_id interface identifier
|
||||
* \param index GTK index
|
||||
*
|
||||
* \return < 0 failure
|
||||
* \return >= 0 success
|
||||
*
|
||||
*/
|
||||
int8_t ws_pae_controller_active_key_update(int8_t interface_id, uint8_t index);
|
||||
|
||||
/**
|
||||
* ws_pae_controller_gtk_hash_ptr_get get pointer to GTK hash storage
|
||||
*
|
||||
* \param interface_ptr interface
|
||||
*
|
||||
* \return pointer to GTK has storage or NULL
|
||||
*
|
||||
*/
|
||||
uint8_t *ws_pae_controller_gtk_hash_ptr_get(protocol_interface_info_entry_t *interface_ptr);
|
||||
|
||||
/**
|
||||
* ws_pae_controller_gtk_hash_update GTK hash has been updated (on PAN configuration)
|
||||
*
|
||||
* \param interface_ptr interface
|
||||
* \param gtkhash new GTK hash
|
||||
*
|
||||
* \return < 0 failure
|
||||
* \return >= 0 success
|
||||
*
|
||||
*/
|
||||
int8_t ws_pae_controller_gtk_hash_update(protocol_interface_info_entry_t *interface_ptr, uint8_t *gtkhash);
|
||||
|
||||
/**
|
||||
* ws_pae_controller_nw_key_index_update key index been updated (on PAN configuration)
|
||||
*
|
||||
* \param interface_ptr interface
|
||||
* \param index key index
|
||||
*
|
||||
* \return < 0 failure
|
||||
* \return >= 0 success
|
||||
*
|
||||
*/
|
||||
int8_t ws_pae_controller_nw_key_index_update(protocol_interface_info_entry_t *interface_ptr, uint8_t index);
|
||||
|
||||
/**
|
||||
* ws_pae_controller_nw_keys_remove remove network keys
|
||||
*
|
||||
* \param interface_ptr interface
|
||||
*
|
||||
*/
|
||||
void ws_pae_controller_nw_keys_remove(protocol_interface_info_entry_t *interface_ptr);
|
||||
|
||||
/**
|
||||
* ws_pae_controller_nw_key_insert network key insert callback
|
||||
*
|
||||
* \param interface_ptr interface
|
||||
* \param slot key slot (MAC key descriptor), from 0 to 4
|
||||
* \param index index of the new network key
|
||||
* \param key new key
|
||||
*
|
||||
*/
|
||||
typedef void ws_pae_controller_nw_key_set(protocol_interface_info_entry_t *interface_ptr, uint8_t slot, uint8_t index, uint8_t *key);
|
||||
|
||||
/**
|
||||
* ws_pae_controller_nw_key_clear network key clear callback
|
||||
*
|
||||
* \param interface_ptr interface
|
||||
* \param slot key slot (MAC key descriptor), from 0 to 4
|
||||
*
|
||||
*/
|
||||
typedef void ws_pae_controller_nw_key_clear(protocol_interface_info_entry_t *interface_ptr, uint8_t slot);
|
||||
|
||||
/**
|
||||
* ws_pae_controller_nw_send_key_index_set network send key index set callback
|
||||
*
|
||||
* \param interface_ptr interface
|
||||
* \param index index of the key to be used on sending
|
||||
*
|
||||
*/
|
||||
typedef void ws_pae_controller_nw_send_key_index_set(protocol_interface_info_entry_t *interface_ptr, uint8_t index);
|
||||
|
||||
/**
|
||||
* ws_pae_controller_nw_frame_counter_set network frame counter set callback
|
||||
*
|
||||
* \param interface_ptr interface
|
||||
* \param counter frame counter
|
||||
*
|
||||
*/
|
||||
typedef void ws_pae_controller_nw_frame_counter_set(protocol_interface_info_entry_t *interface_ptr, uint32_t counter);
|
||||
|
||||
/**
|
||||
* ws_pae_controller_auth_completed authentication completed callback
|
||||
|
@ -191,26 +393,47 @@ typedef void ws_pae_controller_key_insert(protocol_interface_info_entry_t *inter
|
|||
*/
|
||||
typedef void ws_pae_controller_auth_completed(protocol_interface_info_entry_t *interface_ptr, bool success);
|
||||
|
||||
/**
|
||||
* ws_pae_controller_pan_ver_increment PAN version increment callback
|
||||
*
|
||||
* \param interface_ptr interface
|
||||
*
|
||||
*/
|
||||
typedef void ws_pae_controller_pan_ver_increment(protocol_interface_info_entry_t *interface_ptr);
|
||||
|
||||
/**
|
||||
* ws_pae_controller_cb_register register PEA controller callbacks
|
||||
*
|
||||
* \param interface_ptr interface
|
||||
* \param completed authentication completed callback
|
||||
* \param key_insert GTK key insert 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 pan_ver_increment PAN version increment 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_key_insert *key_insert);
|
||||
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_pan_ver_increment *pan_ver_increment);
|
||||
|
||||
/**
|
||||
* ws_pae_controller_timer PAE controller timer call
|
||||
* ws_pae_controller_fast_timer PAE controller fast timer call
|
||||
*
|
||||
* \param ticks elapsed ticks
|
||||
*
|
||||
*/
|
||||
void ws_pae_controller_timer(uint16_t ticks);
|
||||
void ws_pae_controller_fast_timer(uint16_t ticks);
|
||||
|
||||
|
||||
/**
|
||||
* ws_pae_controller_slow_timer PAE controller slow timer call
|
||||
*
|
||||
* \param seconds elapsed seconds
|
||||
*
|
||||
*/
|
||||
void ws_pae_controller_slow_timer(uint16_t seconds);
|
||||
|
||||
#else
|
||||
|
||||
|
@ -222,14 +445,16 @@ void ws_pae_controller_timer(uint16_t ticks);
|
|||
#define ws_pae_controller_border_router_addr_write(interface_ptr, eui_64) -1
|
||||
#define ws_pae_controller_border_router_addr_read(interface_ptr, eui_64) -1
|
||||
|
||||
#define ws_pae_controller_gtk_set(interface_id, gtk) -1
|
||||
#define ws_pae_controller_next_gtks_update(interface_id, gtk) -1
|
||||
|
||||
#define ws_pae_controller_init(interface_ptr) 1
|
||||
#define ws_pae_controller_supp_init(interface_ptr) 1
|
||||
#define ws_pae_controller_auth_init(interface_ptr) 1
|
||||
|
||||
#define ws_pae_controller_stop(interface_ptr)
|
||||
#define ws_pae_controller_delete(interface_ptr)
|
||||
#define ws_pae_controller_cb_register(interface_ptr, completed, key_insert) 1
|
||||
#define ws_pae_controller_timer(ticks)
|
||||
#define ws_pae_controller_cb_register(interface_ptr, completed, nw_key_set, nw_key_clear, nw_send_key_index_set, pan_ver_increment) 1
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
#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_timers.h"
|
||||
#include "6LoWPAN/ws/ws_pae_lib.h"
|
||||
|
||||
#ifdef HAVE_WS
|
||||
|
@ -208,13 +209,28 @@ bool ws_pae_lib_supp_list_timer_update(supp_list_t *active_supp_list, supp_list_
|
|||
return timer_running;
|
||||
}
|
||||
|
||||
void ws_pae_lib_supp_list_slow_timer_update(supp_list_t *supp_list, timer_settings_t *timer_settings, 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)) {
|
||||
tr_info("PMK and PTK expired, eui-64: %s, system time: %"PRIu32"", trace_array(kmp_address_eui_64_get(entry->addr), 8), protocol_core_monotonic_time / 10);
|
||||
}
|
||||
if (sec_prot_keys_ptk_lifetime_decrement(&entry->sec_keys, timer_settings->ptk_lifetime, seconds)) {
|
||||
tr_info("PTK expired, eui-64: %s, system time: %"PRIu32"", trace_array(kmp_address_eui_64_get(entry->addr), 8), protocol_core_monotonic_time / 10);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void ws_pae_lib_supp_init(supp_entry_t *entry)
|
||||
{
|
||||
ws_pae_lib_kmp_list_init(&entry->kmp_list);
|
||||
entry->addr = 0;
|
||||
memset(&entry->sec_keys, 0, sizeof(sec_prot_keys_t));
|
||||
entry->ticks = 0;
|
||||
entry->retry_ticks = 0;
|
||||
entry->active = true;
|
||||
entry->access_revoked = false;
|
||||
}
|
||||
|
||||
void ws_pae_lib_supp_delete(supp_entry_t *entry)
|
||||
|
@ -235,9 +251,20 @@ bool ws_pae_lib_supp_timer_update(supp_entry_t *entry, uint16_t ticks, ws_pae_li
|
|||
entry->ticks -= ticks;
|
||||
} else {
|
||||
entry->ticks = 0;
|
||||
entry->retry_ticks = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Updates retry timer
|
||||
if (entry->retry_ticks > ticks) {
|
||||
entry->retry_ticks -= ticks;
|
||||
} else {
|
||||
if (entry->retry_ticks > 0) {
|
||||
tr_info("EAP-TLS max ongoing delay timeout eui-64: %s", trace_array(kmp_address_eui_64_get(entry->addr), 8));
|
||||
}
|
||||
entry->retry_ticks = 0;
|
||||
}
|
||||
|
||||
return keep_timer_running;
|
||||
}
|
||||
|
||||
|
@ -274,6 +301,12 @@ void ws_pae_lib_supp_list_to_inactive(supp_list_t *active_supp_list, supp_list_t
|
|||
|
||||
tr_debug("PAE: to inactive, eui-64: %s", trace_array(kmp_address_eui_64_get(entry->addr), 8));
|
||||
|
||||
if (entry->access_revoked) {
|
||||
tr_info("Access revoked; deleted, eui-64: %s", trace_array(kmp_address_eui_64_get(entry->addr), 8));
|
||||
ws_pae_lib_supp_list_remove(active_supp_list, entry);
|
||||
return;
|
||||
}
|
||||
|
||||
ns_list_remove(active_supp_list, entry);
|
||||
ns_list_add_to_start(inactive_supp_list, entry);
|
||||
|
||||
|
@ -286,4 +319,35 @@ void ws_pae_lib_supp_list_to_inactive(supp_list_t *active_supp_list, supp_list_t
|
|||
entry->addr = addr;
|
||||
}
|
||||
|
||||
uint16_t ws_pae_lib_supp_list_kmp_count(supp_list_t *supp_list, kmp_type_e type)
|
||||
{
|
||||
uint16_t kmp_count = 0;
|
||||
|
||||
ns_list_foreach(supp_entry_t, entry, supp_list) {
|
||||
ns_list_foreach(kmp_entry_t, kmp_entry, &entry->kmp_list) {
|
||||
if (kmp_api_type_get(kmp_entry->kmp) == type) {
|
||||
kmp_count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return kmp_count;
|
||||
}
|
||||
|
||||
supp_entry_t *ws_pae_lib_supp_list_entry_retry_timer_get(supp_list_t *supp_list)
|
||||
{
|
||||
supp_entry_t *retry_supp = NULL;
|
||||
|
||||
ns_list_foreach(supp_entry_t, entry, supp_list) {
|
||||
// Finds entry with shortest timeout i.e. oldest one
|
||||
if (entry->retry_ticks > 0) {
|
||||
if (!retry_supp || retry_supp->retry_ticks > entry->retry_ticks) {
|
||||
retry_supp = entry;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return retry_supp;
|
||||
}
|
||||
|
||||
#endif /* HAVE_WS */
|
||||
|
|
|
@ -18,6 +18,11 @@
|
|||
#ifndef WS_PAE_LIB_H_
|
||||
#define WS_PAE_LIB_H_
|
||||
|
||||
/*
|
||||
* Port access entity library functions.
|
||||
*
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
kmp_api_t *kmp; /**< KMP API */
|
||||
bool timer_running; /**< Timer running inside KMP */
|
||||
|
@ -31,7 +36,9 @@ typedef struct {
|
|||
kmp_addr_t *addr; /**< EUI-64 (Relay IP address, Relay port) */
|
||||
sec_prot_keys_t sec_keys; /**< Security keys */
|
||||
uint32_t ticks; /**< Ticks */
|
||||
bool active; /**< Is active */
|
||||
uint16_t retry_ticks; /**< Retry ticks */
|
||||
bool active : 1; /**< Is active */
|
||||
bool access_revoked : 1; /**< Nodes access is revoked */
|
||||
ns_list_link_t link; /**< Link */
|
||||
} supp_entry_t;
|
||||
|
||||
|
@ -144,11 +151,6 @@ typedef void ws_pae_lib_kmp_timer_timeout(kmp_api_t *kmp, uint16_t ticks);
|
|||
*/
|
||||
bool ws_pae_lib_kmp_timer_update(kmp_list_t *kmp_list, uint16_t ticks, ws_pae_lib_kmp_timer_timeout timeout);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* ws_pae_lib_supp_list_init initiates supplicant list
|
||||
*
|
||||
|
@ -211,6 +213,16 @@ 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);
|
||||
|
||||
/**
|
||||
* 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, timer_settings_t *timer_settings, uint16_t seconds);
|
||||
|
||||
/**
|
||||
* ws_pae_lib_supp_list_timer_update updates supplicant timers
|
||||
*
|
||||
|
@ -268,4 +280,25 @@ void ws_pae_lib_supp_list_to_active(supp_list_t *active_supp_list, supp_list_t *
|
|||
*/
|
||||
void ws_pae_lib_supp_list_to_inactive(supp_list_t *active_supp_list, supp_list_t *inactive_supp_list, supp_entry_t *entry);
|
||||
|
||||
/**
|
||||
* ws_pae_lib_supp_list_kmp_count counts the number of KMPs of a certain type in a list of supplicants
|
||||
*
|
||||
* \param supp_list list of supplicants
|
||||
* \param type KMP type
|
||||
*
|
||||
* \return number of KMPs in the supplicant list
|
||||
*
|
||||
*/
|
||||
uint16_t ws_pae_lib_supp_list_kmp_count(supp_list_t *supp_list, kmp_type_e type);
|
||||
|
||||
/**
|
||||
* ws_pae_lib_supp_list_entry_retry_timer_get checks if some supplicant has retry timer running
|
||||
*
|
||||
* \param supp_list list of supplicants
|
||||
*
|
||||
* \return supplicant with retry timer running or NULL if no supplicants with timer running
|
||||
*
|
||||
*/
|
||||
supp_entry_t *ws_pae_lib_supp_list_entry_retry_timer_get(supp_list_t *supp_list);
|
||||
|
||||
#endif /* WS_PAE_AUTH_H_ */
|
||||
|
|
|
@ -104,8 +104,7 @@ int8_t ws_pae_nvm_store_nw_info_tlv_read(nvm_tlv_entry_t *tlv_entry, uint16_t *p
|
|||
if (*tlv++ == 1) { /* GTK is set */
|
||||
uint32_t lifetime = common_read_32_bit(tlv);
|
||||
tlv += 4;
|
||||
sec_prot_keys_gtk_set(gtks, i, tlv);
|
||||
sec_prot_keys_gtk_lifetime_set(gtks, i, lifetime);
|
||||
sec_prot_keys_gtk_set(gtks, i, tlv, lifetime);
|
||||
tlv += GTK_LEN;
|
||||
} else {
|
||||
tlv += 4 + GTK_LEN;
|
||||
|
|
|
@ -18,6 +18,12 @@
|
|||
#ifndef WS_PAE_NVM_DATA_H_
|
||||
#define WS_PAE_NVM_DATA_H_
|
||||
|
||||
/*
|
||||
* Port access entity non-volatile memory (NVM) data module. Module is used
|
||||
* to create and parse PAE NVM data TLVs.
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* ws_pae_nvm_store_nw_info_tlv_create create NVM network info TLV
|
||||
*
|
||||
|
|
|
@ -18,6 +18,12 @@
|
|||
#ifndef WS_PAE_NVM_STORE_H_
|
||||
#define WS_PAE_NVM_STORE_H_
|
||||
|
||||
/*
|
||||
* Port access entity non-volatile memory (NVM) storage module. Module is used
|
||||
* to write and read PAE NVM data TLVs to/from filesystem.
|
||||
*
|
||||
*/
|
||||
|
||||
// tag + length
|
||||
#define NVM_TLV_FIXED_LEN 4
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
|
||||
#include "nsconfig.h"
|
||||
#include <string.h>
|
||||
#include <randLIB.h>
|
||||
#include "ns_types.h"
|
||||
#include "ns_list.h"
|
||||
#include "ns_trace.h"
|
||||
|
@ -41,6 +42,7 @@
|
|||
#include "Security/protocols/fwh_sec_prot/supp_fwh_sec_prot.h"
|
||||
#include "Security/protocols/gkh_sec_prot/supp_gkh_sec_prot.h"
|
||||
#include "6LoWPAN/ws/ws_pae_controller.h"
|
||||
#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_nvm_store.h"
|
||||
|
@ -59,10 +61,17 @@
|
|||
#define PAE_TASKLET_TIMER 3
|
||||
|
||||
// Wait for for authenticator to continue with authentication (e.g. after EAP-TLS to initiate 4WH)
|
||||
#define WAIT_FOR_AUTHENTICATION_TICKS 30 * 10 // 30 seconds
|
||||
#define WAIT_FOR_AUTHENTICATION_TICKS 30 * 10 // 30 seconds
|
||||
|
||||
// Wait for re-authentication after GTK update
|
||||
#define WAIT_FOR_REAUTHENTICATION_TICKS 120 * 10 // 120 seconds
|
||||
|
||||
// How many times in maximum stored keys are used for authentication
|
||||
#define STORED_KEYS_MAXIMUM_USE_COUNT 2
|
||||
#define STORED_KEYS_MAXIMUM_USE_COUNT 2
|
||||
|
||||
// Delay for sending the initial EAPOL-Key
|
||||
#define INITIAL_KEY_TIMER_MIN 3
|
||||
#define INITIAL_KEY_TIMER_MAX 30
|
||||
|
||||
const char *NW_INFO_FILE = "pae_nw_info";
|
||||
const char *KEYS_FILE = "pae_keys";
|
||||
|
@ -70,7 +79,8 @@ const char *KEYS_FILE = "pae_keys";
|
|||
typedef struct {
|
||||
char network_name[33]; /**< Network name for keys */
|
||||
sec_prot_gtk_keys_t *gtks; /**< Link to GTKs */
|
||||
uint16_t pan_id; /**< PAN ID for keys */
|
||||
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;
|
||||
|
||||
|
@ -79,27 +89,33 @@ typedef struct {
|
|||
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_key_insert *key_insert; /**< Key insert 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 */
|
||||
supp_entry_t entry; /**< Supplicant data */
|
||||
kmp_addr_t target_addr; /**< EAPOL target (parent) address */
|
||||
trickle_t auth_trickle_timer; /**< Trickle timer for re-sending initial EAPOL-key */
|
||||
uint16_t initial_key_timer; /**< Timer to trigger initial EAPOL-Key */
|
||||
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 */
|
||||
uint8_t ptk_eui_64[8]; /**< Border router EUI-64 used on PTK generation */
|
||||
sec_prot_keys_nw_info_t sec_keys_nw_info; /**< Security keys network information */
|
||||
timer_settings_t *timer_settings; /**< Timer settings */
|
||||
uint8_t nw_keys_used_cnt; /**< How many times bootstrap has been tried with current keys */
|
||||
bool auth_trickle_running : 1; /**< Trickle timer running */
|
||||
bool auth_trickle_running : 1; /**< Initial EAPOL-Key Trickle timer running */
|
||||
bool auth_requested : 1; /**< Authentication has been requested */
|
||||
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_fresh : 1; /**< Border router address is fresh (set during this authentication attempt) */
|
||||
} pae_supp_t;
|
||||
|
||||
// Wi-SUN specification states initial retransmission to be around 5 minutes and maximum 60 minutes
|
||||
static const trickle_params_t auth_trickle_params = {
|
||||
.Imin = 30 * 10, /* 30s; ticks are 100ms */
|
||||
.Imax = 60 * 10, /* 60s */
|
||||
.k = 0, /* infinity - no consistency checking */
|
||||
.TimerExpirations = 3
|
||||
|
||||
#define TRICKLE_IMIN_180_SECS 180
|
||||
|
||||
static trickle_params_t initial_eapol_key_trickle_params = {
|
||||
.Imin = TRICKLE_IMIN_180_SECS, /* 180 second; ticks are 1 second */
|
||||
.Imax = TRICKLE_IMIN_180_SECS << 1, /* 360 second */
|
||||
.k = 0, /* infinity - no consistency checking */
|
||||
.TimerExpirations = 3
|
||||
};
|
||||
|
||||
static void ws_pae_supp_free(pae_supp_t *pae_supp);
|
||||
|
@ -122,6 +138,7 @@ static kmp_api_t *ws_pae_supp_kmp_service_api_get(kmp_service_t *service, kmp_ap
|
|||
static kmp_api_t *ws_pae_supp_kmp_incoming_ind(kmp_service_t *service, kmp_type_e type, const kmp_addr_t *addr);
|
||||
static kmp_api_t *ws_pae_supp_kmp_create_and_start(kmp_service_t *service, kmp_type_e type, pae_supp_t *pae_supp);
|
||||
static int8_t ws_pae_supp_eapol_pdu_address_check(protocol_interface_info_entry_t *interface_ptr, const uint8_t *eui_64);
|
||||
static int8_t ws_pae_supp_parent_eui_64_get(protocol_interface_info_entry_t *interface_ptr, uint8_t *eui_64);
|
||||
|
||||
static void ws_pae_supp_kmp_api_create_confirm(kmp_api_t *kmp, kmp_result_e result);
|
||||
static void ws_pae_supp_kmp_api_create_indication(kmp_api_t *kmp, kmp_type_e type, kmp_addr_t *addr);
|
||||
|
@ -152,29 +169,33 @@ int8_t ws_pae_supp_authenticate(protocol_interface_info_entry_t *interface_ptr,
|
|||
// Delete GTKs
|
||||
sec_prot_keys_gtks_init(pae_supp->sec_keys_nw_info.gtks);
|
||||
|
||||
/* 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) {
|
||||
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;
|
||||
|
||||
// Prepare to receive new border router address
|
||||
pae_supp->new_br_eui_64_set = false;
|
||||
pae_supp->new_br_eui_64_fresh = false;
|
||||
|
||||
// Stores target/parent address
|
||||
kmp_address_init(KMP_ADDR_EUI_64, &pae_supp->target_addr, dest_eui_64);
|
||||
// Sets target address in use
|
||||
pae_supp->entry.addr = (kmp_addr_t *) &pae_supp->target_addr;
|
||||
|
||||
// Sends initial EAPOL-Key message
|
||||
if (ws_pae_supp_initial_key_send(pae_supp) < 0) {
|
||||
pae_supp->auth_completed(interface_ptr, false);
|
||||
}
|
||||
pae_supp->auth_requested = true;
|
||||
|
||||
// Starts trickle
|
||||
trickle_start(&pae_supp->auth_trickle_timer, &auth_trickle_params);
|
||||
pae_supp->auth_trickle_running = true;
|
||||
// Randomizes the sending of initial EAPOL-Key messsage
|
||||
pae_supp->initial_key_timer = randLIB_get_random_in_range(INITIAL_KEY_TIMER_MIN, INITIAL_KEY_TIMER_MAX);
|
||||
|
||||
// Starts supplicant timer
|
||||
ws_pae_supp_timer_start(pae_supp);
|
||||
|
||||
pae_supp->auth_requested = true;
|
||||
|
||||
tr_debug("PAE active");
|
||||
tr_debug("PAE active, timer %i", pae_supp->initial_key_timer);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
@ -187,8 +208,8 @@ int8_t ws_pae_supp_nw_info_set(protocol_interface_info_entry_t *interface_ptr, u
|
|||
}
|
||||
|
||||
// PAN ID has been modified
|
||||
if (pan_id != 0xffff && pan_id != pae_supp->sec_keys_nw_info.pan_id) {
|
||||
pae_supp->sec_keys_nw_info.pan_id = pan_id;
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -211,6 +232,7 @@ int8_t ws_pae_supp_border_router_addr_write(protocol_interface_info_entry_t *int
|
|||
|
||||
memcpy(pae_supp->new_br_eui_64, eui_64, 8);
|
||||
pae_supp->new_br_eui_64_set = true;
|
||||
pae_supp->new_br_eui_64_fresh = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -222,11 +244,12 @@ int8_t ws_pae_supp_border_router_addr_read(protocol_interface_info_entry_t *inte
|
|||
return -1;
|
||||
}
|
||||
|
||||
if (!pae_supp->entry.sec_keys.ptk_eui_64 || !pae_supp->entry.sec_keys.ptk_eui_64_set) {
|
||||
uint8_t *br_eui_64 = sec_prot_keys_ptk_eui_64_get(&pae_supp->entry.sec_keys);
|
||||
if (!br_eui_64) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
memcpy(eui_64, pae_supp->entry.sec_keys.ptk_eui_64, 8);
|
||||
memcpy(eui_64, br_eui_64, 8);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -238,6 +261,8 @@ int8_t ws_pae_supp_nw_key_valid(protocol_interface_info_entry_t *interface_ptr)
|
|||
return -1;
|
||||
}
|
||||
|
||||
tr_info("NW key valid");
|
||||
|
||||
// Stored keys are valid
|
||||
pae_supp->nw_keys_used_cnt = 0;
|
||||
|
||||
|
@ -247,6 +272,69 @@ int8_t ws_pae_supp_nw_key_valid(protocol_interface_info_entry_t *interface_ptr)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int8_t ws_pae_supp_gtk_hash_update(protocol_interface_info_entry_t *interface_ptr, uint8_t *gtkhash)
|
||||
{
|
||||
pae_supp_t *pae_supp = ws_pae_supp_get(interface_ptr);
|
||||
if (!pae_supp) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// 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);
|
||||
if (mismatch > GTK_NO_MISMATCH) {
|
||||
tr_info("GTK hash update %s %s %s %s",
|
||||
trace_array(>khash[0], 8),
|
||||
trace_array(>khash[8], 8),
|
||||
trace_array(>khash[16], 8),
|
||||
trace_array(>khash[24], 8));
|
||||
|
||||
// Mismatch, initiate EAPOL
|
||||
if (!pae_supp->auth_trickle_running) {
|
||||
uint8_t timer_expirations = 3;
|
||||
// For GTK lifetime mismatch send only once
|
||||
if (mismatch == GTK_LIFETIME_MISMATCH) {
|
||||
timer_expirations = 1;
|
||||
}
|
||||
|
||||
pae_supp->auth_trickle_params.Imin = pae_supp->timer_settings->gtk_request_imin;
|
||||
pae_supp->auth_trickle_params.Imax = pae_supp->timer_settings->gtk_request_imax;
|
||||
pae_supp->auth_trickle_params.k = 0;
|
||||
pae_supp->auth_trickle_params.TimerExpirations = timer_expirations;
|
||||
|
||||
// Starts trickle
|
||||
trickle_start(&pae_supp->auth_trickle_timer, &pae_supp->auth_trickle_params);
|
||||
pae_supp->auth_trickle_running = true;
|
||||
|
||||
// Starts supplicant timer
|
||||
ws_pae_supp_timer_start(pae_supp);
|
||||
|
||||
tr_info("GTK update start imin: %i, imax: %i, max mismatch: %i, tr time: %i", pae_supp->timer_settings->gtk_request_imin, pae_supp->timer_settings->gtk_request_imax, pae_supp->timer_settings->gtk_max_mismatch, pae_supp->auth_trickle_timer.t);
|
||||
}
|
||||
}
|
||||
|
||||
// Modify keys
|
||||
pae_supp->nw_key_insert(pae_supp->interface_ptr, pae_supp->sec_keys_nw_info.gtks);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int8_t ws_pae_supp_nw_key_index_update(protocol_interface_info_entry_t *interface_ptr, uint8_t index)
|
||||
{
|
||||
pae_supp_t *pae_supp = ws_pae_supp_get(interface_ptr);
|
||||
if (!pae_supp) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (sec_prot_keys_gtk_status_active_set(&pae_supp->gtks, index) >= 0) {
|
||||
tr_info("NW send key index set: %i", index + 1);
|
||||
pae_supp->nw_key_index_set(interface_ptr, index);
|
||||
} else {
|
||||
tr_info("NW send key index: %i, no changes", index + 1);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ws_pae_supp_nvm_update(pae_supp_t *pae_supp)
|
||||
{
|
||||
// Check if NW info or GTKs have been changed
|
||||
|
@ -268,7 +356,7 @@ static int8_t ws_pae_supp_nvm_nw_info_write(pae_supp_t *pae_supp)
|
|||
nvm_tlv_list_t tlv_list;
|
||||
ns_list_init(&tlv_list);
|
||||
|
||||
nvm_tlv_entry_t *tlv_entry = ws_pae_nvm_store_nw_info_tlv_create(pae_supp->sec_keys_nw_info.pan_id,
|
||||
nvm_tlv_entry_t *tlv_entry = ws_pae_nvm_store_nw_info_tlv_create(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);
|
||||
|
@ -288,7 +376,7 @@ static int8_t ws_pae_supp_nvm_nw_info_read(pae_supp_t *pae_supp)
|
|||
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.pan_id,
|
||||
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);
|
||||
|
@ -340,11 +428,29 @@ static void ws_pae_supp_authenticate_response(pae_supp_t *pae_supp, bool success
|
|||
|
||||
static int8_t ws_pae_supp_initial_key_send(pae_supp_t *pae_supp)
|
||||
{
|
||||
if (!pae_supp->auth_requested) {
|
||||
// If not making initial authentication updates target (RPL parent) for each EAPOL-key message
|
||||
uint8_t parent_eui_64[8];
|
||||
if (ws_pae_supp_parent_eui_64_get(pae_supp->interface_ptr, parent_eui_64) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Stores target/parent address
|
||||
kmp_address_init(KMP_ADDR_EUI_64, &pae_supp->target_addr, parent_eui_64);
|
||||
// Sets parent address in use
|
||||
pae_supp->entry.addr = (kmp_addr_t *) &pae_supp->target_addr;
|
||||
|
||||
ws_pae_lib_supp_timer_ticks_set(&pae_supp->entry, WAIT_FOR_REAUTHENTICATION_TICKS);
|
||||
tr_info("PAE wait for auth seconds: %i", WAIT_FOR_REAUTHENTICATION_TICKS / 10);
|
||||
}
|
||||
|
||||
kmp_api_t *kmp = ws_pae_supp_kmp_create_and_start(pae_supp->kmp_service, IEEE_802_1X_MKA_KEY, pae_supp);
|
||||
if (!kmp) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
tr_info("EAPOL target: %s", trace_array(kmp_address_eui_64_get(pae_supp->entry.addr), 8));
|
||||
|
||||
kmp_api_create_request(kmp, IEEE_802_1X_MKA_KEY, pae_supp->entry.addr, &pae_supp->entry.sec_keys);
|
||||
|
||||
return 0;
|
||||
|
@ -365,34 +471,21 @@ static int8_t ws_pae_supp_nw_keys_valid_check(pae_supp_t *pae_supp, uint16_t pan
|
|||
return -1;
|
||||
}
|
||||
|
||||
// First attempt to authenticate, checks if keys exists
|
||||
if (pae_supp->nw_keys_used_cnt == 0 && pan_id == pae_supp->sec_keys_nw_info.pan_id) {
|
||||
sec_prot_gtk_keys_t *gtks = pae_supp->sec_keys_nw_info.gtks;
|
||||
|
||||
bool key_inserted = false;
|
||||
|
||||
for (uint8_t i = 0; i < GTK_NUM; i++) {
|
||||
uint8_t *gtk = sec_prot_keys_gtk_get(gtks, i);
|
||||
if (gtk) {
|
||||
// Insert also non-live keys since GTK hash information not yet received
|
||||
pae_supp->key_insert(pae_supp->interface_ptr, i, gtk);
|
||||
key_inserted = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (key_inserted) {
|
||||
tr_debug("Keys inserted");
|
||||
pae_supp->nw_keys_used_cnt++;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (pae_supp->nw_keys_used_cnt == 0) {
|
||||
return -1;
|
||||
} else {
|
||||
/* 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) &&
|
||||
(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) {
|
||||
tr_debug("Keys inserted");
|
||||
}
|
||||
pae_supp->nw_keys_used_cnt++;
|
||||
return 0;
|
||||
} else {
|
||||
pae_supp->nw_keys_used_cnt = 0;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -405,10 +498,12 @@ static void ws_pae_supp_keys_nw_info_init(sec_prot_keys_nw_info_t *sec_keys_nw_i
|
|||
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_key_insert *key_insert)
|
||||
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)
|
||||
{
|
||||
pae_supp_t *pae_supp = ws_pae_supp_get(interface_ptr);
|
||||
if (!pae_supp) {
|
||||
|
@ -416,10 +511,11 @@ void ws_pae_supp_cb_register(protocol_interface_info_entry_t *interface_ptr, ws_
|
|||
}
|
||||
|
||||
pae_supp->auth_completed = completed;
|
||||
pae_supp->key_insert = key_insert;
|
||||
pae_supp->nw_key_insert = nw_key_insert;
|
||||
pae_supp->nw_key_index_set = nw_key_index_set;
|
||||
}
|
||||
|
||||
int8_t ws_pae_supp_init(protocol_interface_info_entry_t *interface_ptr, const sec_prot_certs_t *certs)
|
||||
int8_t ws_pae_supp_init(protocol_interface_info_entry_t *interface_ptr, const sec_prot_certs_t *certs, timer_settings_t *timer_settings)
|
||||
{
|
||||
if (!interface_ptr) {
|
||||
return -1;
|
||||
|
@ -435,10 +531,17 @@ 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 = 0;
|
||||
pae_supp->key_insert = 0;
|
||||
pae_supp->auth_trickle_running = false;
|
||||
pae_supp->auth_completed = NULL;
|
||||
pae_supp->nw_key_insert = NULL;
|
||||
pae_supp->nw_key_index_set = NULL;
|
||||
pae_supp->initial_key_timer = 0;
|
||||
pae_supp->nw_keys_used_cnt = 0;
|
||||
pae_supp->timer_settings = timer_settings;
|
||||
pae_supp->auth_trickle_running = false;
|
||||
pae_supp->auth_requested = false;
|
||||
pae_supp->timer_running = false;
|
||||
pae_supp->new_br_eui_64_set = false;
|
||||
pae_supp->new_br_eui_64_fresh = false;
|
||||
|
||||
ws_pae_lib_supp_init(&pae_supp->entry);
|
||||
|
||||
|
@ -449,8 +552,6 @@ int8_t ws_pae_supp_init(protocol_interface_info_entry_t *interface_ptr, const se
|
|||
sec_prot_keys_gtks_init(&pae_supp->gtks);
|
||||
sec_prot_keys_init(&pae_supp->entry.sec_keys, &pae_supp->gtks, certs);
|
||||
memset(pae_supp->new_br_eui_64, 0, 8);
|
||||
memset(pae_supp->ptk_eui_64, 0, 8);
|
||||
sec_prot_keys_ptk_eui_64_set(&pae_supp->entry.sec_keys, pae_supp->ptk_eui_64);
|
||||
|
||||
pae_supp->kmp_service = kmp_service_create();
|
||||
if (!pae_supp->kmp_service) {
|
||||
|
@ -619,29 +720,18 @@ static void ws_pae_supp_tasklet_handler(arm_event_s *event)
|
|||
}
|
||||
}
|
||||
|
||||
void ws_pae_supp_timer(uint16_t ticks)
|
||||
void ws_pae_supp_fast_timer(uint16_t ticks)
|
||||
{
|
||||
ns_list_foreach(pae_supp_t, pae_supp, &pae_supp_list) {
|
||||
if (!ws_pae_supp_timer_running(pae_supp)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Checks whether initial EAPOL-Key message needs to be re-send
|
||||
if (pae_supp->auth_trickle_running) {
|
||||
if (trickle_timer(&pae_supp->auth_trickle_timer, &auth_trickle_params, ticks)) {
|
||||
ws_pae_supp_initial_key_send(pae_supp);
|
||||
}
|
||||
// Maximum number of trickle expires, authentication fails
|
||||
if (!trickle_running(&pae_supp->auth_trickle_timer, &auth_trickle_params)) {
|
||||
ws_pae_supp_authenticate_response(pae_supp, false);
|
||||
}
|
||||
}
|
||||
|
||||
// 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);
|
||||
|
||||
// Checks whether timer needs to be active
|
||||
if (!pae_supp->auth_trickle_running && !running) {
|
||||
if (!pae_supp->initial_key_timer && !pae_supp->auth_trickle_running && !running) {
|
||||
|
||||
tr_debug("PAE idle");
|
||||
// Sets target/parent address to null
|
||||
|
@ -655,6 +745,48 @@ void ws_pae_supp_timer(uint16_t ticks)
|
|||
}
|
||||
}
|
||||
|
||||
void ws_pae_supp_slow_timer(uint16_t seconds)
|
||||
{
|
||||
ns_list_foreach(pae_supp_t, pae_supp, &pae_supp_list) {
|
||||
|
||||
// Checks whether initial EAPOL-Key message needs to be re-send or new GTK request to be sent
|
||||
if (pae_supp->auth_trickle_running) {
|
||||
if (trickle_timer(&pae_supp->auth_trickle_timer, &pae_supp->auth_trickle_params, seconds)) {
|
||||
ws_pae_supp_initial_key_send(pae_supp);
|
||||
}
|
||||
// Maximum number of trickle expires, authentication fails
|
||||
if (!trickle_running(&pae_supp->auth_trickle_timer, &pae_supp->auth_trickle_params)) {
|
||||
ws_pae_supp_authenticate_response(pae_supp, false);
|
||||
}
|
||||
}
|
||||
|
||||
// Decrements GTK lifetimes
|
||||
for (uint8_t i = 0; i < GTK_NUM; i++) {
|
||||
if (!sec_prot_keys_gtk_is_set(&pae_supp->gtks, i)) {
|
||||
continue;
|
||||
}
|
||||
sec_prot_keys_gtk_lifetime_decrement(&pae_supp->gtks, i, seconds);
|
||||
}
|
||||
|
||||
if (pae_supp->initial_key_timer > 0) {
|
||||
if (pae_supp->initial_key_timer > seconds) {
|
||||
pae_supp->initial_key_timer -= seconds;
|
||||
} else {
|
||||
pae_supp->initial_key_timer = 0;
|
||||
|
||||
// Sends initial EAPOL-Key message
|
||||
ws_pae_supp_initial_key_send(pae_supp);
|
||||
|
||||
// Starts trickle
|
||||
pae_supp->auth_trickle_params = initial_eapol_key_trickle_params;
|
||||
trickle_start(&pae_supp->auth_trickle_timer, &pae_supp->auth_trickle_params);
|
||||
pae_supp->auth_trickle_running = true;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int8_t ws_pae_supp_timer_if_start(kmp_service_t *service, kmp_api_t *kmp)
|
||||
{
|
||||
pae_supp_t *pae_supp = ws_pae_supp_by_kmp_service_get(service);
|
||||
|
@ -720,21 +852,38 @@ static int8_t ws_pae_supp_eapol_pdu_address_check(protocol_interface_info_entry_
|
|||
}
|
||||
}
|
||||
|
||||
// Get parent
|
||||
uint8_t parent_eui_64[8];
|
||||
if (ws_pae_supp_parent_eui_64_get(interface_ptr, parent_eui_64) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Message from RPL parent, route to self
|
||||
if (memcmp(parent_eui_64, eui_64, 8) == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int8_t ws_pae_supp_parent_eui_64_get(protocol_interface_info_entry_t *interface_ptr, uint8_t *eui_64)
|
||||
{
|
||||
rpl_dodag_info_t dodag_info;
|
||||
if (!interface_ptr->rpl_domain) {
|
||||
return -1;
|
||||
}
|
||||
struct rpl_instance *instance = rpl_control_enumerate_instances(interface_ptr->rpl_domain, NULL);
|
||||
if (instance && rpl_control_read_dodag_info(instance, &dodag_info)) {
|
||||
// Get parent
|
||||
const uint8_t *parent_ll_addr = rpl_control_preferred_parent_addr(instance, false);
|
||||
|
||||
// Message from RPL parent, route to self
|
||||
if (parent_ll_addr && memcmp(&parent_ll_addr[8], eui_64, 8) == 0) {
|
||||
if (parent_ll_addr) {
|
||||
memcpy(eui_64, &parent_ll_addr[8], 8);
|
||||
eui_64[0] |= 0x02;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void ws_pae_supp_kmp_service_addr_get(kmp_service_t *service, kmp_api_t *kmp, kmp_addr_t *local_addr, kmp_addr_t *remote_addr)
|
||||
|
@ -752,13 +901,23 @@ static void ws_pae_supp_kmp_service_addr_get(kmp_service_t *service, kmp_api_t *
|
|||
kmp_address_eui_64_set(local_addr, mac_params.mac_long);
|
||||
}
|
||||
|
||||
if (pae_supp->new_br_eui_64_set) {
|
||||
// BR address has been received during authentication attempt
|
||||
if (pae_supp->new_br_eui_64_fresh) {
|
||||
kmp_address_eui_64_set(remote_addr, pae_supp->new_br_eui_64);
|
||||
} else if (pae_supp->entry.sec_keys.ptk_eui_64_set) {
|
||||
kmp_address_eui_64_set(remote_addr, pae_supp->entry.sec_keys.ptk_eui_64);
|
||||
} else {
|
||||
memset(remote_addr, 0, 8);
|
||||
tr_error("No border router EUI-64");
|
||||
uint8_t *eui_64 = sec_prot_keys_ptk_eui_64_get(&pae_supp->entry.sec_keys);
|
||||
// BR address is set on security keys (confirmed using 4WH)
|
||||
if (eui_64) {
|
||||
kmp_address_eui_64_set(remote_addr, eui_64);
|
||||
} else {
|
||||
// For initial EAPOL key, if BR address has been received during previous attempt, generate PMKID using it
|
||||
if (pae_supp->new_br_eui_64_set && kmp_api_type_get(kmp) >= IEEE_802_1X_INITIAL_KEY) {
|
||||
kmp_address_eui_64_set(remote_addr, pae_supp->new_br_eui_64);
|
||||
} else {
|
||||
memset(remote_addr, 0, sizeof(kmp_addr_t));
|
||||
tr_error("No border router EUI-64");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -897,18 +1056,12 @@ static void ws_pae_supp_kmp_api_finished_indication(kmp_api_t *kmp, kmp_result_e
|
|||
ws_pae_lib_supp_timer_ticks_set(&pae_supp->entry, WAIT_FOR_AUTHENTICATION_TICKS);
|
||||
}
|
||||
|
||||
sec_prot_keys_t *keys = sec_keys;
|
||||
// Key is to be inserted
|
||||
if (keys) {
|
||||
uint8_t gtk_index;
|
||||
uint8_t *gtk = sec_prot_keys_get_gtk_to_insert(keys->gtks, >k_index);
|
||||
if (gtk) {
|
||||
pae_supp->key_insert(pae_supp->interface_ptr, gtk_index, gtk);
|
||||
sec_prot_keys_gtk_insert_index_clear(keys->gtks);
|
||||
}
|
||||
}
|
||||
|
||||
if ((type == IEEE_802_11_4WH || type == IEEE_802_11_GKH) && result == KMP_RESULT_OK) {
|
||||
if (sec_keys) {
|
||||
sec_prot_keys_t *keys = sec_keys;
|
||||
pae_supp->nw_key_insert(pae_supp->interface_ptr, keys->gtks);
|
||||
}
|
||||
|
||||
ws_pae_supp_authenticate_response(pae_supp, true);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -38,12 +38,13 @@
|
|||
*
|
||||
* \param interface_ptr interface
|
||||
* \param cert_chain certificate chain
|
||||
* \param timer_settings timer settings
|
||||
*
|
||||
* \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);
|
||||
int8_t ws_pae_supp_init(protocol_interface_info_entry_t *interface_ptr, const sec_prot_certs_t *certs, timer_settings_t *timer_settings);
|
||||
|
||||
/**
|
||||
* ws_pae_supp_delete deletes PAE supplicant
|
||||
|
@ -57,12 +58,20 @@ int8_t ws_pae_supp_init(protocol_interface_info_entry_t *interface_ptr, const se
|
|||
int8_t ws_pae_supp_delete(protocol_interface_info_entry_t *interface_ptr);
|
||||
|
||||
/**
|
||||
* ws_pae_supp_timer PAE supplicant timer call
|
||||
* ws_pae_supp_fast_timer PAE supplicant fast timer call
|
||||
*
|
||||
* \param ticks elapsed ticks
|
||||
*
|
||||
*/
|
||||
void ws_pae_supp_timer(uint16_t ticks);
|
||||
void ws_pae_supp_fast_timer(uint16_t ticks);
|
||||
|
||||
/**
|
||||
* ws_pae_supp_slow_timer PAE supplicant slow timer call
|
||||
*
|
||||
* \param ticks elapsed seconds
|
||||
*
|
||||
*/
|
||||
void ws_pae_supp_slow_timer(uint16_t seconds);
|
||||
|
||||
/**
|
||||
* ws_pae_supp_authenticate start EAPOL authentication
|
||||
|
@ -126,6 +135,39 @@ int8_t ws_pae_supp_border_router_addr_read(protocol_interface_info_entry_t *inte
|
|||
*/
|
||||
int8_t ws_pae_supp_nw_key_valid(protocol_interface_info_entry_t *interface_ptr);
|
||||
|
||||
/**
|
||||
* ws_pae_supp_gtk_hash_update GTK hash has been updated (on PAN configuration)
|
||||
*
|
||||
* \param interface_ptr interface
|
||||
* \param gtkhash GTK hash, 32 bytes
|
||||
*
|
||||
* \return < 0 failure
|
||||
* \return >= 0 success
|
||||
*
|
||||
*/
|
||||
int8_t ws_pae_supp_gtk_hash_update(protocol_interface_info_entry_t *interface_ptr, uint8_t *gtkhash);
|
||||
|
||||
/**
|
||||
* ws_pae_supp_nw_key_index_update key index been updated (on PAN configuration)
|
||||
*
|
||||
* \param interface_ptr interface
|
||||
* \param index key index
|
||||
*
|
||||
* \return < 0 failure
|
||||
* \return >= 0 success
|
||||
*
|
||||
*/
|
||||
int8_t ws_pae_supp_nw_key_index_update(protocol_interface_info_entry_t *interface_ptr, uint8_t index);
|
||||
|
||||
/**
|
||||
* ws_pae_supp_nw_key_index_set network send key index set callback
|
||||
*
|
||||
* \param interface_ptr interface
|
||||
* \param index network send key index
|
||||
*
|
||||
*/
|
||||
typedef void ws_pae_supp_nw_key_index_set(protocol_interface_info_entry_t *interface_ptr, uint8_t index);
|
||||
|
||||
/**
|
||||
* ws_pae_supp_auth_completed authentication completed callback
|
||||
*
|
||||
|
@ -136,36 +178,42 @@ int8_t ws_pae_supp_nw_key_valid(protocol_interface_info_entry_t *interface_ptr);
|
|||
typedef void ws_pae_supp_auth_completed(protocol_interface_info_entry_t *interface_ptr, bool success);
|
||||
|
||||
/**
|
||||
* ws_pae_supp_key_insert new GTK key available
|
||||
* ws_pae_supp_nw_key_insert network key insert callback
|
||||
*
|
||||
* \param interface_ptr interface
|
||||
* \param gtk_index index of the new GTK key
|
||||
* \param gtk new GTK key
|
||||
* \param gtks group keys
|
||||
*
|
||||
* \return < 0 failure
|
||||
* \return >= 0 success
|
||||
*
|
||||
*/
|
||||
typedef void ws_pae_supp_key_insert(protocol_interface_info_entry_t *interface_ptr, uint8_t gtk_index, uint8_t *gtk);
|
||||
typedef int8_t ws_pae_supp_nw_key_insert(protocol_interface_info_entry_t *interface_ptr, sec_prot_gtk_keys_t *gtks);
|
||||
|
||||
/**
|
||||
* ws_pae_supp_cb_register register PEA supplicant callbacks
|
||||
*
|
||||
* \param interface_ptr interface
|
||||
* \param completed authentication completed callback
|
||||
* \param key_insert GTK key insert callback
|
||||
* \param nw_key_insert network key index callback
|
||||
* \param nw_key_index_set network send key index callback
|
||||
*
|
||||
*/
|
||||
void ws_pae_supp_cb_register(protocol_interface_info_entry_t *interface_ptr, ws_pae_supp_auth_completed *completed, ws_pae_supp_key_insert *key_insert);
|
||||
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);
|
||||
|
||||
#else
|
||||
|
||||
#define ws_pae_supp_init(interface_ptr, certs) 1
|
||||
#define ws_pae_supp_init(interface_ptr, certs, timer_settings) 1
|
||||
#define ws_pae_supp_delete NULL
|
||||
#define ws_pae_supp_cb_register(interface_ptr, completed, key_insert)
|
||||
#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_timer NULL
|
||||
#define ws_pae_supp_fast_timer NULL
|
||||
#define ws_pae_supp_slow_timer NULL
|
||||
#define ws_pae_supp_authenticate(interface_ptr, dest_pan_id, dest_eui_64) PAE_SUPP_NOT_ENABLED
|
||||
#define ws_pae_supp_border_router_addr_write NULL
|
||||
#define ws_pae_supp_border_router_addr_read NULL
|
||||
#define ws_pae_supp_gtk_hash_update NULL
|
||||
#define ws_pae_supp_nw_key_index_update NULL
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
@ -0,0 +1,177 @@
|
|||
/*
|
||||
* Copyright (c) 2016-2018, Arm Limited and affiliates.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "nsconfig.h"
|
||||
#include <string.h>
|
||||
#include "ns_types.h"
|
||||
#include "ns_list.h"
|
||||
#include "ns_trace.h"
|
||||
#include "nsdynmemLIB.h"
|
||||
#include "fhss_config.h"
|
||||
#include "NWK_INTERFACE/Include/protocol.h"
|
||||
#include "6LoWPAN/ws/ws_config.h"
|
||||
#include "6LoWPAN/ws/ws_pae_timers.h"
|
||||
|
||||
#ifdef HAVE_WS
|
||||
|
||||
#define TRACE_GROUP "wspt"
|
||||
|
||||
#define SECONDS_IN_DAY 24 * 60 * 60
|
||||
#define SECONDS_IN_MONTH 30 * SECONDS_IN_DAY
|
||||
#define SECONDS_IN_MINUTE 60
|
||||
|
||||
#define DEFAULT_GTK_EXPIRE_OFFSET 43200 // 30 days
|
||||
#define DEFAULT_PMK_LIFETIME 4 // 4 months
|
||||
#define DEFAULT_PTK_LIFETIME 2 // 2 months
|
||||
#define DEFAULT_GTK_NEW_ACTIVATION_TIME 720 // default 1/720 * 30 days --> 60 minutes
|
||||
#define DEFAULT_REVOCATION_LIFETIME_REDUCTION 30 // default 1/30 * 30 days --> 1 day
|
||||
#define DEFAULT_GTK_REQUEST_IMIN 4 // 4 minutes
|
||||
#define DEFAULT_GTK_REQUEST_IMAX 64 // 64 minutes
|
||||
#define DEFAULT_GTK_MAX_MISMATCH 64 // 64 minutes
|
||||
#define DEFAULT_GTK_NEW_INSTALL_REQUIRED 80 // 80 percent of GTK lifetime --> 24 days
|
||||
|
||||
static void ws_pae_timers_calculate(timer_settings_t *timer_settings);
|
||||
|
||||
void ws_pae_timers_settings_init(timer_settings_t *timer_settings)
|
||||
{
|
||||
timer_settings->gtk_expire_offset = DEFAULT_GTK_EXPIRE_OFFSET * SECONDS_IN_MINUTE;
|
||||
timer_settings->pmk_lifetime = DEFAULT_PMK_LIFETIME * SECONDS_IN_MONTH;
|
||||
timer_settings->ptk_lifetime = DEFAULT_PTK_LIFETIME * SECONDS_IN_MONTH;
|
||||
timer_settings->gtk_new_act_time = DEFAULT_GTK_NEW_ACTIVATION_TIME;
|
||||
timer_settings->revocat_lifetime_reduct = DEFAULT_REVOCATION_LIFETIME_REDUCTION;
|
||||
timer_settings->gtk_request_imin = DEFAULT_GTK_REQUEST_IMIN * SECONDS_IN_MINUTE;
|
||||
timer_settings->gtk_request_imax = DEFAULT_GTK_REQUEST_IMAX * SECONDS_IN_MINUTE;
|
||||
timer_settings->gtk_max_mismatch = DEFAULT_GTK_MAX_MISMATCH * SECONDS_IN_MINUTE;
|
||||
timer_settings->gtk_new_install_req = DEFAULT_GTK_NEW_INSTALL_REQUIRED;
|
||||
}
|
||||
|
||||
void ws_pae_timers_lifetime_set(timer_settings_t *timer_settings, uint32_t gtk_lifetime, uint32_t pmk_lifetime, uint32_t ptk_lifetime)
|
||||
{
|
||||
if (gtk_lifetime) {
|
||||
timer_settings->gtk_expire_offset = gtk_lifetime * 60;
|
||||
}
|
||||
if (pmk_lifetime) {
|
||||
timer_settings->pmk_lifetime = pmk_lifetime * 60;
|
||||
}
|
||||
if (ptk_lifetime) {
|
||||
timer_settings->ptk_lifetime = ptk_lifetime * 60;
|
||||
}
|
||||
ws_pae_timers_calculate(timer_settings);
|
||||
}
|
||||
|
||||
void ws_pae_timers_gtk_time_settings_set(timer_settings_t *timer_settings, uint8_t revocat_lifetime_reduct, uint8_t new_activation_time, uint8_t new_install_req, uint32_t max_mismatch)
|
||||
{
|
||||
if (revocat_lifetime_reduct) {
|
||||
timer_settings->revocat_lifetime_reduct = revocat_lifetime_reduct;
|
||||
}
|
||||
if (new_activation_time) {
|
||||
timer_settings->gtk_new_act_time = new_activation_time;
|
||||
}
|
||||
if (new_install_req) {
|
||||
timer_settings->gtk_new_install_req = new_install_req;
|
||||
}
|
||||
if (max_mismatch) {
|
||||
timer_settings->gtk_max_mismatch = max_mismatch * 60;
|
||||
}
|
||||
ws_pae_timers_calculate(timer_settings);
|
||||
}
|
||||
|
||||
static void ws_pae_timers_calculate(timer_settings_t *timer_settings)
|
||||
{
|
||||
// Calculate GTK_NEW_INSTALL_REQUIRED < 100 * (1 - 1 / REVOCATION_LIFETIME_REDUCTION)
|
||||
uint8_t calc_gtk_new_install_req = 100 - (100 / timer_settings->revocat_lifetime_reduct);
|
||||
|
||||
if (timer_settings->gtk_expire_offset < 3600) {
|
||||
// For very short GTKs give some more time to distribute the new GTK key to network, tune this if needed
|
||||
calc_gtk_new_install_req = calc_gtk_new_install_req * 60 / 100;
|
||||
}
|
||||
|
||||
if (timer_settings->gtk_new_install_req > calc_gtk_new_install_req) {
|
||||
tr_info("GTK new install required adjusted %i", calc_gtk_new_install_req);
|
||||
timer_settings->gtk_new_install_req = calc_gtk_new_install_req;
|
||||
}
|
||||
|
||||
// Verify that GTK request Imin and Imax are sensible when compared to revocation lifetime
|
||||
timer_settings->gtk_request_imin = DEFAULT_GTK_REQUEST_IMIN * SECONDS_IN_MINUTE;
|
||||
timer_settings->gtk_request_imax = DEFAULT_GTK_REQUEST_IMAX * SECONDS_IN_MINUTE;
|
||||
|
||||
uint32_t gtk_revocation_lifetime = timer_settings->gtk_expire_offset / timer_settings->revocat_lifetime_reduct;
|
||||
uint32_t new_activation_time = timer_settings->gtk_expire_offset / timer_settings->gtk_new_act_time;
|
||||
|
||||
uint32_t time_to_update = gtk_revocation_lifetime;
|
||||
if (gtk_revocation_lifetime > new_activation_time) {
|
||||
time_to_update = gtk_revocation_lifetime - new_activation_time;
|
||||
}
|
||||
|
||||
tr_info("Key timers revocation lifetime: %"PRIu32", new activation time: %"PRIu32", max mismatch %i, time to update: %"PRIu32"", gtk_revocation_lifetime, new_activation_time, timer_settings->gtk_max_mismatch, time_to_update);
|
||||
|
||||
// If time to update results smaller GTK request Imax use it for calculation otherwise use GTK max mismatch
|
||||
if (time_to_update < timer_settings->gtk_max_mismatch) {
|
||||
// If time to update is smaller than GTK request Imax update GTK request values
|
||||
if (timer_settings->gtk_request_imax > time_to_update) {
|
||||
timer_settings->gtk_request_imin = time_to_update / 4;
|
||||
timer_settings->gtk_request_imax = time_to_update / 2;
|
||||
tr_info("GTK request timers adjusted Imin: %i, Imax: %i", timer_settings->gtk_request_imin, timer_settings->gtk_request_imax);
|
||||
}
|
||||
} else if (timer_settings->gtk_request_imax > timer_settings->gtk_max_mismatch) {
|
||||
// If GTK request Imax is larger than GTK max mismatch update GTK request values
|
||||
|
||||
// For small GTK max mismatch times, scale the Imin to be larger than default 4 / 64;
|
||||
uint16_t scaler;
|
||||
if (timer_settings->gtk_max_mismatch < 50) {
|
||||
scaler = 10;
|
||||
} else if (timer_settings->gtk_max_mismatch > 600) {
|
||||
scaler = 1;
|
||||
} else {
|
||||
// About 1 minute mismatch, results 37 seconds Imin and 60 seconds Imax
|
||||
scaler = (600 - timer_settings->gtk_max_mismatch) / 54;
|
||||
}
|
||||
|
||||
timer_settings->gtk_request_imin = timer_settings->gtk_max_mismatch * scaler * DEFAULT_GTK_REQUEST_IMIN / DEFAULT_GTK_REQUEST_IMAX;
|
||||
timer_settings->gtk_request_imax = timer_settings->gtk_max_mismatch;
|
||||
tr_info("GTK request timers adjusted Imin: %i, Imax: %i", timer_settings->gtk_request_imin, timer_settings->gtk_request_imax);
|
||||
}
|
||||
}
|
||||
|
||||
bool ws_pae_timers_gtk_new_install_required(timer_settings_t *timer_settings, uint32_t seconds)
|
||||
{
|
||||
uint32_t gtk_new_install_req_seconds = timer_settings->gtk_expire_offset - timer_settings->gtk_new_install_req * timer_settings->gtk_expire_offset / 100;
|
||||
|
||||
if (seconds < gtk_new_install_req_seconds) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool ws_pae_timers_gtk_new_activation_time(timer_settings_t *timer_settings, uint32_t seconds)
|
||||
{
|
||||
uint32_t gtk_gtk_new_activation_time_seconds = timer_settings->gtk_expire_offset / timer_settings->gtk_new_act_time;
|
||||
|
||||
if (seconds < gtk_gtk_new_activation_time_seconds) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t ws_pae_timers_gtk_revocation_lifetime_get(timer_settings_t *timer_settings)
|
||||
{
|
||||
return timer_settings->gtk_expire_offset / timer_settings->revocat_lifetime_reduct;
|
||||
}
|
||||
|
||||
#endif /* HAVE_WS */
|
|
@ -0,0 +1,98 @@
|
|||
/*
|
||||
* Copyright (c) 2019, 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_TIMERS_H_
|
||||
#define WS_PAE_TIMERS_H_
|
||||
|
||||
typedef struct {
|
||||
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)
|
||||
} timer_settings_t;
|
||||
|
||||
/**
|
||||
* ws_pae_timers_settings_init initializes timer settings structure
|
||||
*
|
||||
* \param timer_settings timer settings
|
||||
*
|
||||
*/
|
||||
void ws_pae_timers_settings_init(timer_settings_t *timer_settings);
|
||||
|
||||
/**
|
||||
* ws_pae_timers_lifetime_set sets GTK, PTK and PTK lifetimes
|
||||
*
|
||||
* \param timer_settings timer settings
|
||||
* \param gtk_lifetime GTK lifetime
|
||||
* \param pmk_lifetime PMK lifetime
|
||||
* \param ptk_lifetime PTK lifetime
|
||||
*
|
||||
*/
|
||||
void ws_pae_timers_lifetime_set(timer_settings_t *timer_settings, uint32_t gtk_lifetime, uint32_t pmk_lifetime, uint32_t ptk_lifetime);
|
||||
|
||||
/**
|
||||
* ws_pae_timers_gtk_time_settings_set sets GTK, PTK and PTK lifetimes
|
||||
*
|
||||
* \param timer_settings timer settings
|
||||
* \param revocat_lifetime_reduct revocation lifetime reduction
|
||||
* \param new_activation_time new activation time
|
||||
* \param new_install_req new install required
|
||||
* \param max_mismatch max mismatch
|
||||
*
|
||||
*/
|
||||
void ws_pae_timers_gtk_time_settings_set(timer_settings_t *timer_settings, uint8_t revocat_lifetime_reduct, uint8_t new_activation_time, uint8_t new_install_req, uint32_t max_mismatch);
|
||||
|
||||
/**
|
||||
* ws_pae_timers_gtk_new_install_required GTK new install required check
|
||||
*
|
||||
* \param timer_settings timer settings
|
||||
* \param seconds elapsed seconds
|
||||
*
|
||||
* \return true new GTK install required expired
|
||||
* \return false GTK install not required
|
||||
*
|
||||
*/
|
||||
bool ws_pae_timers_gtk_new_install_required(timer_settings_t *timer_settings, uint32_t seconds);
|
||||
|
||||
/**
|
||||
* ws_pae_timers_gtk_new_activation_time GTK new activation time
|
||||
*
|
||||
* \param timer_settings timer settings
|
||||
* \param seconds elapsed seconds
|
||||
*
|
||||
* \return true GTK new activation time expired
|
||||
* \return false GTK new activation time not expired
|
||||
*
|
||||
*/
|
||||
bool ws_pae_timers_gtk_new_activation_time(timer_settings_t *timer_settings, uint32_t seconds);
|
||||
|
||||
/**
|
||||
* ws_pae_timers_gtk_revocation_lifetime_get GTK revocation lifetime get
|
||||
*
|
||||
* \param timer_settings timer settings
|
||||
*
|
||||
* \return GTK revocation lifetime
|
||||
*
|
||||
*/
|
||||
uint32_t ws_pae_timers_gtk_revocation_lifetime_get(timer_settings_t *timer_settings);
|
||||
|
||||
#endif /* WS_PAE_TIMERS_H_ */
|
|
@ -25,6 +25,7 @@
|
|||
#include "6LoWPAN/ws/ws_config.h"
|
||||
#include "6LoWPAN/ws/ws_common.h"
|
||||
#include "6LoWPAN/ws/ws_bbr_api_internal.h"
|
||||
#include "6LoWPAN/ws/ws_pae_controller.h"
|
||||
#include "randLIB.h"
|
||||
|
||||
#include "ns_trace.h"
|
||||
|
@ -60,7 +61,7 @@ int ws_test_gtk_set(int8_t interface_id, uint8_t *gtk[4])
|
|||
(void) interface_id;
|
||||
(void) gtk;
|
||||
|
||||
return 0;
|
||||
return ws_pae_controller_gtk_update(interface_id, gtk);
|
||||
}
|
||||
|
||||
int ws_test_active_key_set(int8_t interface_id, uint8_t index)
|
||||
|
@ -68,7 +69,7 @@ int ws_test_active_key_set(int8_t interface_id, uint8_t index)
|
|||
(void) interface_id;
|
||||
(void) index;
|
||||
|
||||
return 0;
|
||||
return ws_pae_controller_active_key_update(interface_id, index);
|
||||
}
|
||||
|
||||
int ws_test_key_lifetime_set(int8_t interface_id, uint32_t gtk_lifetime, uint32_t pmk_lifetime, uint32_t ptk_lifetime)
|
||||
|
@ -78,17 +79,27 @@ int ws_test_key_lifetime_set(int8_t interface_id, uint32_t gtk_lifetime, uint32_
|
|||
(void) pmk_lifetime;
|
||||
(void) ptk_lifetime;
|
||||
|
||||
return 0;
|
||||
return ws_pae_controller_key_lifetime_update(interface_id, gtk_lifetime, pmk_lifetime, ptk_lifetime);
|
||||
}
|
||||
|
||||
int ws_test_gtk_time_settings_set(int8_t interface_id, uint8_t revocat_lifetime_reduct, uint8_t new_activation_time, uint32_t max_mismatch)
|
||||
int ws_test_gtk_time_settings_set(int8_t interface_id, uint8_t revocat_lifetime_reduct, uint8_t new_activation_time, uint8_t new_install_req, uint32_t max_mismatch)
|
||||
{
|
||||
(void) interface_id;
|
||||
(void) revocat_lifetime_reduct;
|
||||
(void) new_activation_time;
|
||||
(void) new_install_req;
|
||||
(void) max_mismatch;
|
||||
|
||||
return 0;
|
||||
|
||||
return ws_pae_controller_gtk_time_settings_update(interface_id, revocat_lifetime_reduct, new_activation_time, new_install_req, max_mismatch);
|
||||
}
|
||||
|
||||
int ws_test_next_gtk_set(int8_t interface_id, uint8_t *gtk[4])
|
||||
{
|
||||
(void) interface_id;
|
||||
(void) gtk;
|
||||
|
||||
return ws_pae_controller_next_gtk_update(interface_id, gtk);
|
||||
}
|
||||
|
||||
#endif // HAVE_WS
|
||||
|
|
|
@ -325,12 +325,12 @@ static buffer_t *icmpv6_echo_request_handler(buffer_t *buf)
|
|||
|
||||
if (addr_is_ipv6_multicast(buf->dst_sa.address)) {
|
||||
const uint8_t *ipv6_ptr;
|
||||
memcpy(buf->dst_sa.address, buf->src_sa.address, 16);
|
||||
ipv6_ptr = addr_select_source(cur, buf->dst_sa.address, 0);
|
||||
if (!ipv6_ptr) {
|
||||
tr_debug("No address");
|
||||
return buffer_free(buf);
|
||||
}
|
||||
memcpy(buf->dst_sa.address, buf->src_sa.address, 16);
|
||||
memcpy(buf->src_sa.address, ipv6_ptr, 16);
|
||||
} else {
|
||||
memswap(buf->dst_sa.address, buf->src_sa.address, 16);
|
||||
|
@ -570,16 +570,8 @@ int icmpv6_slaac_prefix_update(struct protocol_interface_info_entry *cur, const
|
|||
//Validate first current list If prefix is already defined adress
|
||||
ns_list_foreach_safe(if_address_entry_t, e, &cur->ip_addresses) {
|
||||
if (e->source == ADDR_SOURCE_SLAAC && (e->prefix_len == prefix_len) && bitsequal(e->address, prefix_ptr, prefix_len)) {
|
||||
//Update Current lifetimes (see RFC 4862 for rules detail)
|
||||
if (valid_lifetime > (2 * 60 * 60) || valid_lifetime > e->valid_lifetime) {
|
||||
addr_set_valid_lifetime(cur, e, valid_lifetime);
|
||||
} else if (e->valid_lifetime <= (2 * 60 * 60)) {
|
||||
//NOT Update Valid Lifetime
|
||||
} else {
|
||||
addr_set_valid_lifetime(cur, e, 2 * 60 * 60);
|
||||
}
|
||||
|
||||
addr_set_preferred_lifetime(cur, e, preferred_lifetime);
|
||||
addr_lifetime_update(cur, e, valid_lifetime, preferred_lifetime, 2 * 60 * 60);
|
||||
ret_val = 0;
|
||||
}
|
||||
}
|
||||
|
@ -1320,6 +1312,63 @@ uint8_t *icmpv6_write_mtu_option(uint32_t mtu, uint8_t *dptr)
|
|||
return dptr;
|
||||
}
|
||||
|
||||
void ack_receive_cb(struct buffer *buffer_ptr, uint8_t status)
|
||||
{
|
||||
/*icmpv6_na_handler functionality based on ACK*/
|
||||
ipv6_neighbour_t *neighbour_entry;
|
||||
uint8_t ll_target[16];
|
||||
|
||||
if (status != SOCKET_TX_DONE) {
|
||||
/*NS failed*/
|
||||
return;
|
||||
}
|
||||
|
||||
if (buffer_ptr->dst_sa.addr_type == ADDR_IPV6) {
|
||||
/*Full IPv6 address*/
|
||||
memcpy(ll_target, buffer_ptr->dst_sa.address, 16);
|
||||
} else if (buffer_ptr->dst_sa.addr_type == ADDR_802_15_4_LONG) {
|
||||
// Build link local address from long MAC address
|
||||
memcpy(ll_target, ADDR_LINK_LOCAL_PREFIX, 8);
|
||||
memcpy(ll_target + 8, &buffer_ptr->dst_sa.address[2], 8);
|
||||
ll_target[8] ^= 2;
|
||||
} else {
|
||||
tr_warn("wrong address %d %s", buffer_ptr->dst_sa.addr_type, trace_array(buffer_ptr->dst_sa.address, 16));
|
||||
return;
|
||||
}
|
||||
|
||||
neighbour_entry = ipv6_neighbour_lookup(&buffer_ptr->interface->ipv6_neighbour_cache, ll_target);
|
||||
if (neighbour_entry) {
|
||||
ipv6_neighbour_update_from_na(&buffer_ptr->interface->ipv6_neighbour_cache, neighbour_entry, NA_S, buffer_ptr->dst_sa.addr_type, buffer_ptr->dst_sa.address);
|
||||
}
|
||||
|
||||
if (ws_info(buffer_ptr->interface)) {
|
||||
ws_common_neighbor_update(buffer_ptr->interface, ll_target);
|
||||
}
|
||||
}
|
||||
void ack_remove_neighbour_cb(struct buffer *buffer_ptr, uint8_t status)
|
||||
{
|
||||
/*icmpv6_na_handler functionality based on ACK*/
|
||||
uint8_t ll_target[16];
|
||||
(void)status;
|
||||
|
||||
if (buffer_ptr->dst_sa.addr_type == ADDR_IPV6) {
|
||||
/*Full IPv6 address*/
|
||||
memcpy(ll_target, buffer_ptr->dst_sa.address, 16);
|
||||
} else if (buffer_ptr->dst_sa.addr_type == ADDR_802_15_4_LONG) {
|
||||
// Build link local address from long MAC address
|
||||
memcpy(ll_target, ADDR_LINK_LOCAL_PREFIX, 8);
|
||||
memcpy(ll_target + 8, &buffer_ptr->dst_sa.address[2], 8);
|
||||
ll_target[8] ^= 2;
|
||||
} else {
|
||||
tr_warn("wrong address %d %s", buffer_ptr->dst_sa.addr_type, trace_array(buffer_ptr->dst_sa.address, 16));
|
||||
return;
|
||||
}
|
||||
if (ws_info(buffer_ptr->interface)) {
|
||||
ws_common_neighbor_remove(buffer_ptr->interface, ll_target);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
buffer_t *icmpv6_build_ns(protocol_interface_info_entry_t *cur, const uint8_t target_addr[16], const uint8_t *prompting_src_addr, bool unicast, bool unspecified_source, const aro_t *aro)
|
||||
{
|
||||
if (!cur || addr_is_ipv6_multicast(target_addr)) {
|
||||
|
@ -1394,10 +1443,15 @@ buffer_t *icmpv6_build_ns(protocol_interface_info_entry_t *cur, const uint8_t ta
|
|||
}
|
||||
/* If ARO Success sending is omitted, MAC ACK is used instead */
|
||||
/* Setting callback for receiving ACK from adaptation layer */
|
||||
if (aro && cur->ipv6_neighbour_cache.omit_aro_success) {
|
||||
if (aro && cur->ipv6_neighbour_cache.omit_na_aro_success) {
|
||||
buf->ack_receive_cb = rpl_control_address_register_done;
|
||||
}
|
||||
}
|
||||
if (unicast && (!aro && cur->ipv6_neighbour_cache.omit_na)) {
|
||||
/*MAC ACK is processed as success response*/
|
||||
buf->ack_receive_cb = ack_receive_cb;
|
||||
}
|
||||
|
||||
buf->src_sa.addr_type = ADDR_IPV6;
|
||||
|
||||
/* NS packets are implicitly on-link. If we ever find ourselves sending an
|
||||
|
@ -1530,11 +1584,16 @@ buffer_t *icmpv6_build_na(protocol_interface_info_entry_t *cur, bool solicited,
|
|||
|
||||
tr_debug("Build NA");
|
||||
|
||||
/* Check if ARO status == success, then sending can be omitted with flag */
|
||||
if (aro && cur->ipv6_neighbour_cache.omit_aro_success && aro->status == ARO_SUCCESS) {
|
||||
tr_debug("Omit success reply");
|
||||
/* Check if ARO response and status == success, then sending can be omitted with flag */
|
||||
if (aro && cur->ipv6_neighbour_cache.omit_na_aro_success && aro->status == ARO_SUCCESS) {
|
||||
tr_debug("Omit NA ARO success");
|
||||
return NULL;
|
||||
}
|
||||
/* All other than ARO NA messages are omitted and MAC ACK is considered as success */
|
||||
if (!tllao_required && (!aro && cur->ipv6_neighbour_cache.omit_na)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
buffer_t *buf = buffer_get(8 + 16 + 16 + 16); /* fixed, target addr, target ll addr, aro */
|
||||
if (!buf) {
|
||||
|
@ -1616,6 +1675,11 @@ buffer_t *icmpv6_build_na(protocol_interface_info_entry_t *cur, bool solicited,
|
|||
memcpy(ptr, aro->eui64, 8);
|
||||
ptr += 8;
|
||||
}
|
||||
if (ws_info(cur) && aro && aro->status != ARO_SUCCESS) {
|
||||
/*If Aro failed we will kill the neigbour after we have succeeded in sending message*/
|
||||
buf->ack_receive_cb = ack_remove_neighbour_cb;
|
||||
}
|
||||
|
||||
//Force Next Hop is destination
|
||||
ipv6_buffer_route_to(buf, buf->dst_sa.address, cur);
|
||||
|
||||
|
|
|
@ -35,9 +35,11 @@ prefix_entry_t *icmpv6_prefix_add(prefix_list_t *list, const uint8_t *prefixPtr,
|
|||
|
||||
entry = icmpv6_prefix_compare(list, prefixPtr, prefix_len);
|
||||
if (entry) {
|
||||
entry->options = flags;
|
||||
entry->lifetime = lifeTime;
|
||||
entry->preftime = prefTime;
|
||||
if (flags != 0xff) {
|
||||
entry->options = flags;
|
||||
entry->lifetime = lifeTime;
|
||||
entry->preftime = prefTime;
|
||||
}
|
||||
return entry;
|
||||
}
|
||||
|
||||
|
|
|
@ -156,6 +156,7 @@ void addr_fast_timer(struct protocol_interface_info_entry *cur, uint_fast16_t ti
|
|||
void addr_slow_timer(struct protocol_interface_info_entry *cur, uint_fast16_t seconds);
|
||||
struct if_address_entry *addr_add(struct protocol_interface_info_entry *cur, const uint8_t address[__static 16], uint_fast8_t prefix_len, if_address_source_t source, uint32_t valid_lifetime, uint32_t preferred_lifetime, bool skip_dad);
|
||||
int_fast8_t addr_delete(struct protocol_interface_info_entry *cur, const uint8_t address[__static 16]);
|
||||
int_fast8_t addr_deprecate(struct protocol_interface_info_entry *cur, const uint8_t address[__static 16]);
|
||||
void addr_delete_matching(struct protocol_interface_info_entry *cur, const uint8_t *prefix, uint8_t prefix_len, if_address_source_t source);
|
||||
void addr_delete_entry(struct protocol_interface_info_entry *cur, if_address_entry_t *addr);
|
||||
void addr_set_non_preferred(struct protocol_interface_info_entry *cur, if_address_source_t source);
|
||||
|
@ -166,6 +167,8 @@ void addr_cb(struct protocol_interface_info_entry *interface, if_address_entry_t
|
|||
void addr_set_valid_lifetime(struct protocol_interface_info_entry *interface, if_address_entry_t *entry, uint32_t valid_lifetime);
|
||||
void addr_set_preferred_lifetime(struct protocol_interface_info_entry *interface, if_address_entry_t *entry, uint32_t preferred_lifetime);
|
||||
|
||||
void addr_lifetime_update(struct protocol_interface_info_entry *interface, if_address_entry_t *address, uint32_t valid_lifetime, uint32_t preferred_lifetime, uint32_t threshold);
|
||||
|
||||
int_fast8_t addr_policy_table_add_entry(const uint8_t *prefix, uint8_t len, uint8_t precedence, uint8_t label);
|
||||
int_fast8_t addr_policy_table_delete_entry(const uint8_t *prefix, uint8_t len);
|
||||
uint8_t addr_len_from_type(addrtype_t addr_type);
|
||||
|
@ -178,6 +181,8 @@ struct if_address_entry *addr_get_entry(const struct protocol_interface_info_ent
|
|||
bool addr_is_assigned_to_interface(const struct protocol_interface_info_entry *interface, const uint8_t addr[__static 16]);
|
||||
bool addr_is_tentative_for_interface(const struct protocol_interface_info_entry *interface, const uint8_t addr[__static 16]);
|
||||
|
||||
void addr_policy_remove_by_label(uint8_t label);
|
||||
|
||||
void addr_duplicate_detected(struct protocol_interface_info_entry *interface, const uint8_t addr[__static 16]);
|
||||
|
||||
struct if_group_entry *addr_add_group(struct protocol_interface_info_entry *interface, const uint8_t group[__static 16]);
|
||||
|
|
|
@ -690,6 +690,13 @@ const uint8_t *addr_select_source(protocol_interface_info_entry_t *interface, co
|
|||
}
|
||||
}
|
||||
|
||||
/* Rule 9 select most precated one */
|
||||
if (policy_SA->precedence > policy_SB->precedence) {
|
||||
PREFER_SA;
|
||||
} else if (policy_SB->precedence > policy_SA->precedence) {
|
||||
PREFER_SB;
|
||||
}
|
||||
|
||||
/* Tie */
|
||||
PREFER_SA;
|
||||
}
|
||||
|
@ -858,6 +865,7 @@ void addr_fast_timer(protocol_interface_info_entry_t *cur, uint_fast16_t ticks)
|
|||
}
|
||||
#endif
|
||||
} else {
|
||||
addr->addr_reg_done = 0;
|
||||
addr_cb(cur, addr, ADDR_CALLBACK_TIMER);
|
||||
}
|
||||
|
||||
|
@ -1002,6 +1010,19 @@ int_fast8_t addr_delete(protocol_interface_info_entry_t *cur, const uint8_t addr
|
|||
return -1;
|
||||
}
|
||||
|
||||
int_fast8_t addr_deprecate(protocol_interface_info_entry_t *cur, const uint8_t address[static 16])
|
||||
{
|
||||
ns_list_foreach(if_address_entry_t, e, &cur->ip_addresses) {
|
||||
if (memcmp(e->address, address, 16) == 0) {
|
||||
tr_debug("Deprecate address %s", trace_ipv6(e->address));
|
||||
addr_lifetime_update(cur, e, 0, 0, 30 * 60); //Accept max 30 min lifetime
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
void addr_delete_matching(protocol_interface_info_entry_t *cur, const uint8_t *prefix, uint8_t prefix_len, if_address_source_t source)
|
||||
{
|
||||
ns_list_foreach_safe(if_address_entry_t, e, &cur->ip_addresses) {
|
||||
|
@ -1091,6 +1112,20 @@ void addr_set_preferred_lifetime(protocol_interface_info_entry_t *interface, if_
|
|||
}
|
||||
}
|
||||
|
||||
void addr_lifetime_update(protocol_interface_info_entry_t *interface, if_address_entry_t *address, uint32_t valid_lifetime, uint32_t preferred_lifetime, uint32_t threshold)
|
||||
{
|
||||
//Update Current lifetimes (see RFC 4862 for rules detail)
|
||||
if (valid_lifetime > threshold || valid_lifetime > address->valid_lifetime) {
|
||||
addr_set_valid_lifetime(interface, address, valid_lifetime);
|
||||
} else if (address->valid_lifetime <= threshold) {
|
||||
//NOT Update Valid Lifetime
|
||||
} else {
|
||||
addr_set_valid_lifetime(interface, address, threshold);
|
||||
}
|
||||
|
||||
addr_set_preferred_lifetime(interface, address, preferred_lifetime);
|
||||
}
|
||||
|
||||
void memswap(uint8_t *restrict a, uint8_t *restrict b, uint_fast8_t len)
|
||||
{
|
||||
while (len--) {
|
||||
|
@ -1398,6 +1433,21 @@ int8_t addr_interface_select_source(protocol_interface_info_entry_t *cur, uint8_
|
|||
return ret_val;
|
||||
}
|
||||
|
||||
void addr_policy_remove_by_label(uint8_t label)
|
||||
{
|
||||
ns_list_foreach_safe(addr_policy_table_entry_t, entry, &addr_policy_table) {
|
||||
if (entry->label == label) {
|
||||
/*
|
||||
* Remove label policy if no local address matches"
|
||||
*/
|
||||
if (!protocol_interface_any_address_match(entry->prefix, entry->prefix_len)) {
|
||||
ns_list_remove(&addr_policy_table, entry);
|
||||
ns_dyn_mem_free(entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This last function must always be compiled with tracing enabled
|
||||
#ifndef FEA_TRACE_SUPPORT
|
||||
#define FEA_TRACE_SUPPORT 1
|
||||
|
|
|
@ -272,7 +272,7 @@ void DHCPv6_server_service_timeout_cb(uint32_t timeUpdateInSeconds)
|
|||
* /param guaPrefix Prefix which will be removed
|
||||
* /param delete_gua_addresses Whether or not assigned addresses with the prefix should be removed from the interface.
|
||||
*/
|
||||
void DHCPv6_server_service_delete(int8_t interface, uint8_t guaPrefix[static 16], bool delete_gua_addresses)
|
||||
void DHCPv6_server_service_delete(int8_t interface, uint8_t guaPrefix[static 8], bool delete_gua_addresses)
|
||||
{
|
||||
dhcpv6_gua_server_entry_s *serverInfo = libdhcpv6_server_data_get_by_prefix_and_interfaceid(interface, guaPrefix);
|
||||
if (serverInfo) {
|
||||
|
@ -390,7 +390,7 @@ int DHCPv6_server_service_init(int8_t interface, uint8_t guaPrefix[static 16], u
|
|||
|
||||
return -1;
|
||||
}
|
||||
void DHCPv6_server_service_delete(int8_t interface, uint8_t guaPrefix[static 16], bool delete_gua_addresses)
|
||||
void DHCPv6_server_service_delete(int8_t interface, uint8_t guaPrefix[static 8], bool delete_gua_addresses)
|
||||
{
|
||||
(void) interface;
|
||||
(void) guaPrefix;
|
||||
|
|
|
@ -54,7 +54,7 @@ void DHCPv6_server_service_callback_set(int8_t interface, uint8_t guaPrefix[stat
|
|||
* /param guaPrefix Prefix which will be removed
|
||||
* /param delete_gua_addresses Whether or not assigned addresses with the prefix should be removed from the interface.
|
||||
*/
|
||||
void DHCPv6_server_service_delete(int8_t interface, uint8_t guaPrefix[static 16], bool delete_gua_addresses);
|
||||
void DHCPv6_server_service_delete(int8_t interface, uint8_t guaPrefix[static 8], bool delete_gua_addresses);
|
||||
|
||||
|
||||
void DHCPv6_server_service_timeout_cb(uint32_t timeUpdateInSeconds);
|
||||
|
|
|
@ -38,9 +38,12 @@ void dhcp_client_init(int8_t interface);
|
|||
|
||||
/* Set configurations for DHCP client
|
||||
*
|
||||
* /param interface Client Inteface ID
|
||||
* /param renew_uses_solicit Instead of renew message SOLICIT is used.
|
||||
* /param one_client_for_this_interface True Interface use oneinstance for allocate address
|
||||
* /param no_address_hint IAID use address at Solicit
|
||||
*/
|
||||
void dhcp_client_configure(int8_t interface, bool renew_uses_solicit);
|
||||
void dhcp_client_configure(int8_t interface, bool renew_uses_solicit, bool one_client_for_this_interface, bool no_address_hint);
|
||||
|
||||
/* Set Timeout parameters for SOLICIT transactions
|
||||
*
|
||||
|
@ -92,11 +95,13 @@ void dhcp_client_global_address_renew(int8_t interface);
|
|||
* /param prefix dhcp server ML16 address where address is registered.
|
||||
*
|
||||
*/
|
||||
void dhcp_client_global_address_delete(int8_t interface, uint8_t dhcp_addr[static 16], uint8_t prefix[static 16]);
|
||||
void dhcp_client_global_address_delete(int8_t interface, uint8_t *dhcp_addr, uint8_t prefix[static 16]);
|
||||
|
||||
|
||||
void dhcp_relay_agent_enable(int8_t interface, uint8_t border_router_address[static 16]);
|
||||
|
||||
int dhcp_client_server_address_update(int8_t interface, uint8_t prefix[static 16], uint8_t server_address[static 16]);
|
||||
|
||||
|
||||
|
||||
#endif /* DHCPV6_CLIENT_API_H_ */
|
||||
|
|
|
@ -41,11 +41,14 @@ typedef struct {
|
|||
uint8_t libDhcp_instance;
|
||||
int8_t interface;
|
||||
bool renew_uses_solicit: 1;
|
||||
bool one_instance_interface: 1;
|
||||
bool no_address_hint: 1;
|
||||
} dhcp_client_class_t;
|
||||
|
||||
static dhcp_client_class_t dhcp_client;
|
||||
|
||||
void dhcpv6_client_set_address(int8_t interface_id, dhcpv6_client_server_data_t *srv_data_ptr);
|
||||
static bool dhcpv6_client_set_address(int8_t interface_id, dhcpv6_client_server_data_t *srv_data_ptr);
|
||||
void dhcpv6_renew(protocol_interface_info_entry_t *interface, if_address_entry_t *addr, if_address_callback_t reason);
|
||||
|
||||
|
||||
void dhcp_client_init(int8_t interface)
|
||||
|
@ -57,14 +60,19 @@ void dhcp_client_init(int8_t interface)
|
|||
dhcp_client.sol_timeout = 0;
|
||||
dhcp_client.sol_max_rt = 0;
|
||||
dhcp_client.sol_max_rc = 0;
|
||||
dhcp_client.renew_uses_solicit = false;
|
||||
dhcp_client.one_instance_interface = false;
|
||||
dhcp_client.no_address_hint = false;
|
||||
|
||||
return;
|
||||
}
|
||||
void dhcp_client_configure(int8_t interface, bool renew_uses_solicit)
|
||||
void dhcp_client_configure(int8_t interface, bool renew_uses_solicit, bool one_client_for_this_interface, bool no_address_hint)
|
||||
{
|
||||
// Set true if RENEW is not used and SOLICIT sent instead.
|
||||
(void)interface;
|
||||
dhcp_client.renew_uses_solicit = renew_uses_solicit;
|
||||
dhcp_client.one_instance_interface = one_client_for_this_interface;
|
||||
dhcp_client.no_address_hint = no_address_hint;
|
||||
}
|
||||
|
||||
void dhcp_client_solicit_timeout_set(int8_t interface, uint16_t timeout, uint16_t max_rt, uint8_t max_rc)
|
||||
|
@ -170,6 +178,14 @@ int dhcp_solicit_resp_cb(uint16_t instance_id, void *ptr, uint8_t msg_name, uin
|
|||
goto error_exit;
|
||||
}
|
||||
|
||||
if (dhcp_client.one_instance_interface && memcmp(srv_data_ptr->iaNontemporalAddress.addressPrefix, dhcp_ia_non_temporal_params.nonTemporalAddress, 16)) {
|
||||
|
||||
protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(dhcp_client.interface);
|
||||
if (cur) {
|
||||
addr_deprecate(cur, srv_data_ptr->iaNontemporalAddress.addressPrefix);
|
||||
}
|
||||
}
|
||||
|
||||
memcpy(srv_data_ptr->iaNontemporalAddress.addressPrefix, dhcp_ia_non_temporal_params.nonTemporalAddress, 16);
|
||||
srv_data_ptr->iaNontemporalAddress.preferredTime = dhcp_ia_non_temporal_params.preferredValidLifeTime;
|
||||
srv_data_ptr->iaNontemporalAddress.validLifetime = dhcp_ia_non_temporal_params.validLifeTime;
|
||||
|
@ -177,13 +193,13 @@ int dhcp_solicit_resp_cb(uint16_t instance_id, void *ptr, uint8_t msg_name, uin
|
|||
srv_data_ptr->serverLinkType = serverId.linkType;
|
||||
srv_data_ptr->T0 = dhcp_ia_non_temporal_params.T0;
|
||||
srv_data_ptr->T1 = dhcp_ia_non_temporal_params.T1;
|
||||
srv_data_ptr->iaNonTemporalStructValid = true;
|
||||
|
||||
dhcpv6_client_set_address(dhcp_client.interface, srv_data_ptr);
|
||||
|
||||
bool status = dhcpv6_client_set_address(dhcp_client.interface, srv_data_ptr);
|
||||
|
||||
|
||||
if (dhcp_client.global_address_cb) {
|
||||
dhcp_client.global_address_cb(dhcp_client.interface, srv_data_ptr->server_address, srv_data_ptr->iaNontemporalAddress.addressPrefix, true);
|
||||
dhcp_client.global_address_cb(dhcp_client.interface, srv_data_ptr->server_address, srv_data_ptr->iaNontemporalAddress.addressPrefix, status);
|
||||
}
|
||||
return RET_MSG_ACCEPTED;
|
||||
error_exit:
|
||||
|
@ -198,20 +214,36 @@ int dhcp_client_get_global_address(int8_t interface, uint8_t dhcp_addr[static 16
|
|||
uint8_t *payload_ptr;
|
||||
uint32_t payload_len;
|
||||
dhcpv6_client_server_data_t *srv_data_ptr;
|
||||
bool add_prefix;
|
||||
|
||||
if (mac64 == NULL || dhcp_addr == NULL) {
|
||||
tr_error("Invalid parameters");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!prefix) {
|
||||
if (!prefix || dhcp_client.one_instance_interface) {
|
||||
//NULL Definition will only check That Interface is not generated
|
||||
if (libdhcpv6_nonTemporal_entry_get_by_instance(dhcp_client.libDhcp_instance)) {
|
||||
srv_data_ptr = libdhcpv6_nonTemporal_entry_get_by_instance(dhcp_client.libDhcp_instance);
|
||||
if (srv_data_ptr) {
|
||||
//Already Created to same interface
|
||||
if (dhcp_client.one_instance_interface && prefix) {
|
||||
if (srv_data_ptr->iaNonTemporalStructValid) {
|
||||
if (memcmp(srv_data_ptr->iaNontemporalAddress.addressPrefix, prefix, 8)) {
|
||||
//Request new address direct from Server if prefix is new
|
||||
srv_data_ptr->iaNonTemporalStructValid = false;
|
||||
dhcpv6_renew(protocol_stack_interface_info_get_by_id(interface), NULL, ADDR_CALLBACK_TIMER);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
} else if (dhcp_client_server_address_update(interface, prefix, dhcp_addr) == 0) {
|
||||
//No need for allocate new
|
||||
return 0;
|
||||
}
|
||||
|
||||
tr_debug("GEN new Dhcpv6 client %u", dhcp_client.libDhcp_instance);
|
||||
srv_data_ptr = libdhcvp6_nontemporalAddress_server_data_allocate(interface, dhcp_client.libDhcp_instance, mac64, link_type, prefix, dhcp_addr);
|
||||
|
||||
if (!srv_data_ptr) {
|
||||
|
@ -219,7 +251,15 @@ int dhcp_client_get_global_address(int8_t interface, uint8_t dhcp_addr[static 16
|
|||
return -1;
|
||||
}
|
||||
|
||||
payload_len = libdhcpv6_solication_message_length(link_type, prefix != NULL, 0);
|
||||
|
||||
if (!prefix || dhcp_client.no_address_hint) {
|
||||
add_prefix = false;
|
||||
} else {
|
||||
add_prefix = prefix != NULL;
|
||||
}
|
||||
|
||||
payload_len = libdhcpv6_solication_message_length(link_type, add_prefix, 0);
|
||||
|
||||
|
||||
payload_ptr = ns_dyn_mem_temporary_alloc(payload_len);
|
||||
if (!payload_ptr) {
|
||||
|
@ -238,7 +278,7 @@ int dhcp_client_get_global_address(int8_t interface, uint8_t dhcp_addr[static 16
|
|||
solPacket.transActionId = libdhcpv6_txid_get();
|
||||
/*Non Temporal Address */
|
||||
|
||||
if (prefix) {
|
||||
if (prefix && !dhcp_client.no_address_hint) {
|
||||
dhcpv6_ia_non_temporal_address_s nonTemporalAddress = {0};
|
||||
nonTemporalAddress.requestedAddress = prefix;
|
||||
libdhcpv6_generic_nontemporal_address_message_write(payload_ptr, &solPacket, &nonTemporalAddress, NULL);
|
||||
|
@ -253,6 +293,7 @@ int dhcp_client_get_global_address(int8_t interface, uint8_t dhcp_addr[static 16
|
|||
libdhcvp6_nontemporalAddress_server_data_free(srv_data_ptr);
|
||||
return -1;
|
||||
}
|
||||
srv_data_ptr->iaNonTemporalStructValid = false;
|
||||
if (dhcp_client.sol_timeout != 0) {
|
||||
// Default retry values are modified from specification update to message
|
||||
dhcp_service_set_retry_timers(srv_data_ptr->transActionId, dhcp_client.sol_timeout, dhcp_client.sol_max_rt, dhcp_client.sol_max_rc);
|
||||
|
@ -261,13 +302,44 @@ int dhcp_client_get_global_address(int8_t interface, uint8_t dhcp_addr[static 16
|
|||
return 0;
|
||||
}
|
||||
|
||||
int dhcp_client_server_address_update(int8_t interface, uint8_t prefix[static 16], uint8_t server_address[static 16])
|
||||
{
|
||||
dhcpv6_client_server_data_t *srv_data_ptr = NULL;
|
||||
|
||||
if (dhcp_client.interface != interface) {
|
||||
tr_debug("Interface not match");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (prefix) {
|
||||
srv_data_ptr = libdhcpv6_nonTemporal_entry_get_by_prefix(interface, prefix);
|
||||
} else if (dhcp_client.one_instance_interface) {
|
||||
srv_data_ptr = libdhcpv6_nonTemporal_entry_get_by_instance(dhcp_client.libDhcp_instance);
|
||||
}
|
||||
if (!srv_data_ptr) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (memcmp(srv_data_ptr->server_address, server_address, 16) == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
memcpy(srv_data_ptr->server_address, server_address, 16);
|
||||
if (!srv_data_ptr->iaNonTemporalStructValid) {
|
||||
dhcp_service_update_server_address(srv_data_ptr->transActionId, server_address);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void dhcp_client_global_address_renew(int8_t interface)
|
||||
{
|
||||
(void)interface;
|
||||
return;
|
||||
}
|
||||
|
||||
void dhcp_client_global_address_delete(int8_t interface, uint8_t dhcp_addr[static 16], uint8_t prefix[static 16])
|
||||
void dhcp_client_global_address_delete(int8_t interface, uint8_t *dhcp_addr, uint8_t prefix[static 16])
|
||||
{
|
||||
protocol_interface_info_entry_t *cur;
|
||||
dhcpv6_client_server_data_t *srv_data_ptr;
|
||||
|
@ -276,33 +348,35 @@ void dhcp_client_global_address_delete(int8_t interface, uint8_t dhcp_addr[stati
|
|||
srv_data_ptr = libdhcpv6_nonTemporal_entry_get_by_prefix(interface, prefix);
|
||||
cur = protocol_stack_interface_info_get_by_id(interface);
|
||||
|
||||
do {
|
||||
if (cur == NULL || srv_data_ptr == NULL) {
|
||||
return;
|
||||
}
|
||||
dhcp_service_req_remove(srv_data_ptr->transActionId);// remove all pending retransmissions
|
||||
tr_debug("Deleting address: %s", trace_ipv6(srv_data_ptr->iaNontemporalAddress.addressPrefix));
|
||||
if (cur == NULL || srv_data_ptr == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
dhcp_service_req_remove(srv_data_ptr->transActionId);// remove all pending retransmissions
|
||||
if (dhcp_client.one_instance_interface) {
|
||||
addr_deprecate(cur, srv_data_ptr->iaNontemporalAddress.addressPrefix);
|
||||
} else {
|
||||
addr_delete(cur, srv_data_ptr->iaNontemporalAddress.addressPrefix);
|
||||
}
|
||||
|
||||
libdhcvp6_nontemporalAddress_server_data_free(srv_data_ptr);
|
||||
srv_data_ptr = libdhcpv6_nonTemporal_entry_get_by_prefix(interface, prefix);
|
||||
} while (srv_data_ptr);
|
||||
|
||||
return;
|
||||
libdhcvp6_nontemporalAddress_server_data_free(srv_data_ptr);
|
||||
}
|
||||
|
||||
void dhcpv6_renew(protocol_interface_info_entry_t *interface, if_address_entry_t *addr, if_address_callback_t reason)
|
||||
{
|
||||
dhcpv6_ia_non_temporal_address_s nonTemporalAddress = {0};
|
||||
|
||||
dhcp_link_options_params_t serverLink;
|
||||
uint8_t *payload_ptr;
|
||||
uint32_t payload_len;
|
||||
dhcpv6_client_server_data_t *srv_data_ptr = libdhcpv6_nonTemporal_entry_get_by_prefix(interface->id, addr->address);
|
||||
dhcpv6_client_server_data_t *srv_data_ptr;
|
||||
if (addr) {
|
||||
srv_data_ptr = libdhcpv6_nonTemporal_entry_get_by_prefix(interface->id, addr->address);
|
||||
} else {
|
||||
srv_data_ptr = libdhcpv6_nonTemporal_entry_get_by_instance(dhcp_client.libDhcp_instance);
|
||||
}
|
||||
|
||||
if (srv_data_ptr == NULL) {
|
||||
tr_warn("Dhcp address lost");
|
||||
return ;
|
||||
return;
|
||||
}
|
||||
if (reason == ADDR_CALLBACK_INVALIDATED) {
|
||||
dhcp_service_req_remove(srv_data_ptr->transActionId);//stop retransmissions of renew
|
||||
|
@ -315,10 +389,12 @@ void dhcpv6_renew(protocol_interface_info_entry_t *interface, if_address_entry_t
|
|||
return;
|
||||
}
|
||||
|
||||
payload_len = libdhcpv6_address_request_message_len(srv_data_ptr->clientLinkIdType, srv_data_ptr->serverLinkType, 0);
|
||||
payload_len = libdhcpv6_address_request_message_len(srv_data_ptr->clientLinkIdType, srv_data_ptr->serverLinkType, 0, !dhcp_client.no_address_hint);
|
||||
payload_ptr = ns_dyn_mem_temporary_alloc(payload_len);
|
||||
if (payload_ptr == NULL) {
|
||||
addr->state_timer = 200; //Retry after 20 seconds
|
||||
if (addr) {
|
||||
addr->state_timer = 200; //Retry after 20 seconds
|
||||
}
|
||||
tr_error("Out of memory");
|
||||
return ;
|
||||
}
|
||||
|
@ -337,18 +413,33 @@ void dhcpv6_renew(protocol_interface_info_entry_t *interface, if_address_entry_t
|
|||
packetReq.messageType = DHCPV6_SOLICATION_TYPE;
|
||||
}
|
||||
|
||||
// Set Address information
|
||||
nonTemporalAddress.requestedAddress = srv_data_ptr->iaNontemporalAddress.addressPrefix;
|
||||
nonTemporalAddress.preferredLifeTime = srv_data_ptr->iaNontemporalAddress.preferredTime;
|
||||
nonTemporalAddress.validLifeTime = srv_data_ptr->iaNontemporalAddress.validLifetime;
|
||||
|
||||
serverLink.linkID = srv_data_ptr->serverLinkId;
|
||||
serverLink.linkType = srv_data_ptr->serverLinkType;
|
||||
libdhcpv6_generic_nontemporal_address_message_write(payload_ptr, &packetReq, &nonTemporalAddress, &serverLink);
|
||||
if (dhcp_client.no_address_hint && dhcp_client.renew_uses_solicit) {
|
||||
packetReq.timerT0 = 0;
|
||||
packetReq.timerT1 = 0;
|
||||
libdhcpv6_generic_nontemporal_address_message_write(payload_ptr, &packetReq, NULL, &serverLink);
|
||||
} else {
|
||||
// Set Address information
|
||||
dhcpv6_ia_non_temporal_address_s nonTemporalAddress = {0};
|
||||
nonTemporalAddress.requestedAddress = srv_data_ptr->iaNontemporalAddress.addressPrefix;
|
||||
nonTemporalAddress.preferredLifeTime = srv_data_ptr->iaNontemporalAddress.preferredTime;
|
||||
nonTemporalAddress.validLifeTime = srv_data_ptr->iaNontemporalAddress.validLifetime;
|
||||
libdhcpv6_generic_nontemporal_address_message_write(payload_ptr, &packetReq, &nonTemporalAddress, &serverLink);
|
||||
}
|
||||
// send solicit
|
||||
srv_data_ptr->transActionId = dhcp_service_send_req(dhcp_client.service_instance, 0, srv_data_ptr, srv_data_ptr->server_address, payload_ptr, payload_len, dhcp_solicit_resp_cb);
|
||||
uint8_t *server_address = dhcp_service_relay_global_addres_get(dhcp_client.relay_instance);
|
||||
if (!server_address) {
|
||||
server_address = srv_data_ptr->server_address;
|
||||
}
|
||||
|
||||
srv_data_ptr->transActionId = dhcp_service_send_req(dhcp_client.service_instance, 0, srv_data_ptr, server_address, payload_ptr, payload_len, dhcp_solicit_resp_cb);
|
||||
if (srv_data_ptr->transActionId == 0) {
|
||||
ns_dyn_mem_free(payload_ptr);
|
||||
addr->state_timer = 200; //Retry after 20 seconds
|
||||
if (addr) {
|
||||
addr->state_timer = 200; //Retry after 20 seconds
|
||||
}
|
||||
tr_error("DHCP renew send failed");
|
||||
}
|
||||
if (packetReq.messageType == DHCPV6_SOLICATION_TYPE && dhcp_client.sol_timeout != 0) {
|
||||
|
@ -357,7 +448,7 @@ void dhcpv6_renew(protocol_interface_info_entry_t *interface, if_address_entry_t
|
|||
}
|
||||
}
|
||||
|
||||
void dhcpv6_client_set_address(int8_t interface_id, dhcpv6_client_server_data_t *srv_data_ptr)
|
||||
static bool dhcpv6_client_set_address(int8_t interface_id, dhcpv6_client_server_data_t *srv_data_ptr)
|
||||
{
|
||||
protocol_interface_info_entry_t *cur = NULL;
|
||||
if_address_entry_t *address_entry = NULL;
|
||||
|
@ -365,10 +456,11 @@ void dhcpv6_client_set_address(int8_t interface_id, dhcpv6_client_server_data_t
|
|||
|
||||
cur = protocol_stack_interface_info_get_by_id(interface_id);
|
||||
if (!cur) {
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
renewTimer = libdhcpv6_renew_time_define(srv_data_ptr);
|
||||
|
||||
srv_data_ptr->iaNonTemporalStructValid = true;
|
||||
address_entry = addr_get_entry(cur, srv_data_ptr->iaNontemporalAddress.addressPrefix);
|
||||
if (address_entry == NULL) {
|
||||
// create new
|
||||
|
@ -380,8 +472,10 @@ void dhcpv6_client_set_address(int8_t interface_id, dhcpv6_client_server_data_t
|
|||
|
||||
if (address_entry == NULL) {
|
||||
tr_error("Address add failed");
|
||||
return;
|
||||
srv_data_ptr->iaNonTemporalStructValid = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (renewTimer) {
|
||||
// translate seconds to 100ms ticks
|
||||
if (renewTimer < 0xffffffff / 10) {
|
||||
|
@ -392,6 +486,7 @@ void dhcpv6_client_set_address(int8_t interface_id, dhcpv6_client_server_data_t
|
|||
}
|
||||
address_entry->state_timer = renewTimer;
|
||||
address_entry->cb = dhcpv6_renew;
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -192,6 +192,7 @@ typedef struct protocol_interface_rf_mac_setup {
|
|||
unsigned macCurrentBE: 4;
|
||||
uint8_t macMaxCSMABackoffs;
|
||||
uint8_t backoff_period_in_10us; // max 2550us - it's 320us for standard 250kbps
|
||||
uint8_t mac_frame_filters;
|
||||
/* MAC channel parameters */
|
||||
channel_list_s mac_channel_list;
|
||||
uint8_t scan_duration; //Needed???
|
||||
|
@ -219,6 +220,8 @@ typedef struct protocol_interface_rf_mac_setup {
|
|||
uint16_t mac_ack_wait_duration;
|
||||
uint8_t mac_mlme_retry_max;
|
||||
uint8_t aUnitBackoffPeriod;
|
||||
uint8_t number_of_csma_ca_periods; /**< Number of CSMA-CA periods */
|
||||
uint16_t multi_cca_interval; /**< Length of the additional CSMA-CA period(s) in microseconds */
|
||||
/* Indirect queue parameters */
|
||||
struct mac_pre_build_frame *indirect_pd_data_request_queue;
|
||||
arm_event_t mac_mcps_timer_event;
|
||||
|
|
|
@ -267,6 +267,9 @@ const uint8_t *mac_header_parse_fcf_dsn(mac_fcf_sequence_t *header, const uint8_
|
|||
} else {
|
||||
header->DSN = 0;
|
||||
}
|
||||
//Check PanID presents at header
|
||||
header->DstPanPresents = mac_dst_panid_present(header);
|
||||
header->SrcPanPresents = mac_src_panid_present(header);
|
||||
return ptr;
|
||||
|
||||
}
|
||||
|
|
|
@ -362,8 +362,6 @@ static int8_t mac_virtual_data_req_handler(protocol_interface_rf_mac_setup_s *rf
|
|||
}
|
||||
|
||||
mac_header_parse_fcf_dsn(&buffer->fcf_dsn, data_ptr);
|
||||
buffer->fcf_dsn.DstPanPresents = mac_dst_panid_present(&buffer->fcf_dsn);
|
||||
buffer->fcf_dsn.SrcPanPresents = mac_src_panid_present(&buffer->fcf_dsn);
|
||||
// Use MAC sequence as handle
|
||||
buffer->msduHandle = buffer->fcf_dsn.DSN;
|
||||
memcpy(buffer->mac_payload, data_ptr, data_length);
|
||||
|
@ -982,11 +980,6 @@ static void mac_data_interface_frame_handler(mac_pre_parsed_frame_t *buf)
|
|||
mcps_sap_pre_parsed_frame_buffer_free(buf);
|
||||
return;
|
||||
}
|
||||
|
||||
if (mac_filter_modify_link_quality(rf_mac_setup->mac_interface_id, buf) == 1) {
|
||||
mcps_sap_pre_parsed_frame_buffer_free(buf);
|
||||
return;
|
||||
}
|
||||
/* push data to stack if sniffer mode is enabled */
|
||||
if (rf_mac_setup->macProminousMode) {
|
||||
mac_nap_tun_data_handler(buf, rf_mac_setup);
|
||||
|
@ -1423,13 +1416,20 @@ static void mcps_data_confirm_handle(protocol_interface_rf_mac_setup_s *rf_ptr,
|
|||
// FHSS checks if this failed buffer needs to be pushed back to TX queue and retransmitted
|
||||
if ((rf_ptr->mac_tx_result == MAC_TX_FAIL) || (rf_ptr->mac_tx_result == MAC_CCA_FAIL)) {
|
||||
if (rf_ptr->fhss_api->data_tx_fail(rf_ptr->fhss_api, buffer->msduHandle, mac_convert_frame_type_to_fhss(buffer->fcf_dsn.frametype)) == true) {
|
||||
|
||||
if (rf_ptr->mac_tx_result == MAC_TX_FAIL) {
|
||||
buffer->fhss_retry_count += 1 + rf_ptr->mac_tx_status.retry;
|
||||
} else {
|
||||
buffer->fhss_retry_count += rf_ptr->mac_tx_status.retry;
|
||||
}
|
||||
buffer->fhss_cca_retry_count += rf_ptr->mac_tx_status.cca_cnt;
|
||||
mcps_sap_pd_req_queue_write(rf_ptr, buffer);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
confirm.cca_retries = rf_ptr->mac_tx_status.cca_cnt;
|
||||
confirm.tx_retries = rf_ptr->mac_tx_status.retry;
|
||||
confirm.cca_retries = rf_ptr->mac_tx_status.cca_cnt + buffer->fhss_cca_retry_count;
|
||||
confirm.tx_retries = rf_ptr->mac_tx_status.retry + buffer->fhss_retry_count;
|
||||
mac_common_data_confirmation_handle(rf_ptr, buffer);
|
||||
confirm.msduHandle = buffer->msduHandle;
|
||||
confirm.status = buffer->status;
|
||||
|
@ -1600,9 +1600,8 @@ static int8_t mcps_generic_packet_build(protocol_interface_rf_mac_setup_s *rf_pt
|
|||
return 0;
|
||||
}
|
||||
|
||||
int8_t mcps_generic_ack_build(protocol_interface_rf_mac_setup_s *rf_ptr, const mac_fcf_sequence_t *fcf, const uint8_t *data_ptr, const mcps_ack_data_payload_t *ack_payload, uint32_t rx_time)
|
||||
int8_t mcps_generic_ack_build(protocol_interface_rf_mac_setup_s *rf_ptr, const mac_fcf_sequence_t *fcf, const uint8_t *data_ptr, const mcps_ack_data_payload_t *ack_payload)
|
||||
{
|
||||
(void)rx_time;
|
||||
phy_device_driver_s *dev_driver = rf_ptr->dev_driver->phy_driver;
|
||||
dev_driver_tx_buffer_s *tx_buf = &rf_ptr->dev_driver_tx_buffer;
|
||||
|
||||
|
@ -1740,7 +1739,7 @@ int8_t mcps_generic_ack_build(protocol_interface_rf_mac_setup_s *rf_ptr, const m
|
|||
rf_ptr->dev_driver->phy_driver->extension(PHY_EXTENSION_SET_CSMA_PARAMETERS, (uint8_t *) &csma_params);
|
||||
if (rf_ptr->active_pd_data_request) {
|
||||
timer_mac_stop(rf_ptr);
|
||||
mac_pd_sap_set_phy_tx_time(rf_ptr, 0, false);
|
||||
mac_pd_abort_active_tx(rf_ptr);
|
||||
}
|
||||
return mcps_pd_data_cca_trig(rf_ptr, buffer);
|
||||
}
|
||||
|
@ -1828,6 +1827,13 @@ static int8_t mcps_pd_data_cca_trig(protocol_interface_rf_mac_setup_s *rf_ptr, m
|
|||
}
|
||||
cca_enabled = true;
|
||||
}
|
||||
// Use double CCA check with FHSS for data packets only
|
||||
if (rf_ptr->fhss_api && !rf_ptr->mac_ack_tx_active && !rf_ptr->active_pd_data_request->asynch_request) {
|
||||
if ((buffer->tx_time - (rf_ptr->multi_cca_interval * (rf_ptr->number_of_csma_ca_periods - 1))) > mac_mcps_sap_get_phy_timestamp(rf_ptr)) {
|
||||
buffer->csma_periods_left = rf_ptr->number_of_csma_ca_periods - 1;
|
||||
buffer->tx_time -= (rf_ptr->multi_cca_interval * (rf_ptr->number_of_csma_ca_periods - 1));
|
||||
}
|
||||
}
|
||||
mac_pd_sap_set_phy_tx_time(rf_ptr, buffer->tx_time, cca_enabled);
|
||||
if (mac_plme_cca_req(rf_ptr) != 0) {
|
||||
if (buffer->fcf_dsn.frametype == MAC_FRAME_ACK) {
|
||||
|
|
|
@ -57,6 +57,11 @@ typedef enum {
|
|||
#define MAC_SAP_TRIG_TX 7
|
||||
#define MCPS_SAP_DATA_ACK_CNF_EVENT 8
|
||||
|
||||
// Default number of CSMA-CA periods
|
||||
#define MAC_DEFAULT_NUMBER_OF_CSMA_PERIODS 1
|
||||
// Interval between two CCA checks
|
||||
#define MAC_DEFAULT_CSMA_MULTI_CCA_INTERVAL 1000
|
||||
|
||||
/**
|
||||
* @brief struct mac_aux_security_header_t MAC auxiliarity security header structure
|
||||
* INTERNAL use only
|
||||
|
@ -126,6 +131,9 @@ typedef struct mac_pre_build_frame {
|
|||
uint8_t *mac_payload;
|
||||
uint8_t status;
|
||||
uint8_t asynch_channel;
|
||||
uint8_t csma_periods_left;
|
||||
uint8_t fhss_retry_count;
|
||||
uint8_t fhss_cca_retry_count;
|
||||
uint32_t tx_time;
|
||||
bool upper_layer_request;
|
||||
bool mac_allocated_payload_ptr: 1;
|
||||
|
@ -206,6 +214,6 @@ uint8_t mcps_sap_purge_reg_handler(struct protocol_interface_rf_mac_setup *rf_ma
|
|||
|
||||
int8_t mcps_pd_data_rebuild(struct protocol_interface_rf_mac_setup *rf_ptr, mac_pre_build_frame_t *buffer);
|
||||
|
||||
int8_t mcps_generic_ack_build(struct protocol_interface_rf_mac_setup *rf_ptr, const mac_fcf_sequence_t *fcf, const uint8_t *data_ptr, const mcps_ack_data_payload_t *ack_payload, uint32_t rx_time);
|
||||
int8_t mcps_generic_ack_build(struct protocol_interface_rf_mac_setup *rf_ptr, const mac_fcf_sequence_t *fcf, const uint8_t *data_ptr, const mcps_ack_data_payload_t *ack_payload);
|
||||
|
||||
#endif /* MAC_IEEE802_15_4_MAC_MCPS_SAP_H_ */
|
||||
|
|
|
@ -582,7 +582,7 @@ static int8_t mac_mlme_8bit_set(protocol_interface_rf_mac_setup_s *rf_mac_setup,
|
|||
break;
|
||||
|
||||
case macMinBE:
|
||||
if (value > rf_mac_setup->macMaxBE) {
|
||||
if (value < rf_mac_setup->macMaxBE) {
|
||||
rf_mac_setup->macMinBE = value;
|
||||
}
|
||||
break;
|
||||
|
@ -724,6 +724,16 @@ static int8_t mac_mlme_handle_set_values(protocol_interface_rf_mac_setup_s *rf_m
|
|||
return -1;
|
||||
}
|
||||
|
||||
static int8_t mac_mlme_set_multi_csma_parameters(protocol_interface_rf_mac_setup_s *rf_mac_setup, const mlme_set_t *set_req)
|
||||
{
|
||||
mlme_multi_csma_ca_param_t multi_csma_params;
|
||||
memcpy(&multi_csma_params, set_req->value_pointer, sizeof(mlme_multi_csma_ca_param_t));
|
||||
rf_mac_setup->multi_cca_interval = multi_csma_params.multi_cca_interval;
|
||||
rf_mac_setup->number_of_csma_ca_periods = multi_csma_params.number_of_csma_ca_periods;
|
||||
tr_debug("Multi CSMA-CA, interval: %u, periods %u", rf_mac_setup->multi_cca_interval, rf_mac_setup->number_of_csma_ca_periods);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int8_t mac_mlme_set_req(protocol_interface_rf_mac_setup_s *rf_mac_setup, const mlme_set_t *set_req)
|
||||
{
|
||||
if (!set_req || !rf_mac_setup || !rf_mac_setup->dev_driver || !rf_mac_setup->dev_driver->phy_driver) {
|
||||
|
@ -749,6 +759,8 @@ 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 macMultiCSMAParameters:
|
||||
return mac_mlme_set_multi_csma_parameters(rf_mac_setup, set_req);
|
||||
case macRfConfiguration:
|
||||
rf_mac_setup->dev_driver->phy_driver->extension(PHY_EXTENSION_SET_RF_CONFIGURATION, (uint8_t *) set_req->value_pointer);
|
||||
mac_mlme_set_symbol_rate(rf_mac_setup);
|
||||
|
@ -1072,6 +1084,8 @@ protocol_interface_rf_mac_setup_s *mac_mlme_data_base_allocate(uint8_t *mac64, a
|
|||
entry->mac_interface_id = -1;
|
||||
entry->dev_driver = dev_driver;
|
||||
entry->aUnitBackoffPeriod = 20; //This can be different in some Platform 20 comes from 12-symbol turnaround and 8 symbol CCA read
|
||||
entry->number_of_csma_ca_periods = MAC_DEFAULT_NUMBER_OF_CSMA_PERIODS;
|
||||
entry->multi_cca_interval = MAC_DEFAULT_CSMA_MULTI_CCA_INTERVAL;
|
||||
|
||||
if (mac_sec_mib_init(entry, storage_sizes) != 0) {
|
||||
mac_mlme_data_base_deallocate(entry);
|
||||
|
@ -1140,6 +1154,10 @@ protocol_interface_rf_mac_setup_s *mac_mlme_data_base_allocate(uint8_t *mac64, a
|
|||
bool rf_support = false;
|
||||
dev_driver->phy_driver->extension(PHY_EXTENSION_DYNAMIC_RF_SUPPORTED, (uint8_t *)&rf_support);
|
||||
entry->rf_csma_extension_supported = rf_support;
|
||||
dev_driver->phy_driver->extension(PHY_EXTENSION_FILTERING_SUPPORT, (uint8_t *)&entry->mac_frame_filters);
|
||||
if (entry->mac_frame_filters & (1 << MAC_FRAME_VERSION_2)) {
|
||||
tr_debug("PHY supports 802.15.4-2015 frame filtering");
|
||||
}
|
||||
mac_mlme_set_symbol_rate(entry);
|
||||
|
||||
//How many 10us ticks backoff period is for waiting 20symbols which is typically 10 bytes time
|
||||
|
|
|
@ -41,7 +41,7 @@
|
|||
// Measured 3750us with 1280 byte secured packet from calculating TX time to starting CSMA timer on PHY.
|
||||
// Typically varies from 500us to several milliseconds depending on packet size and the platform.
|
||||
// MAC should learn and make this dynamic by sending first few packets with predefined CSMA period.
|
||||
#define MIN_FHSS_CSMA_PERIOD_US 4000
|
||||
#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);
|
||||
|
@ -83,6 +83,10 @@ void mac_csma_backoff_start(protocol_interface_rf_mac_setup_s *rf_mac_setup)
|
|||
|
||||
uint32_t mac_csma_backoff_get(protocol_interface_rf_mac_setup_s *rf_mac_setup)
|
||||
{
|
||||
// Use minimum allowed CSMA-CA for asynch frames
|
||||
if (rf_mac_setup->active_pd_data_request->asynch_request) {
|
||||
return MIN_FHSS_CSMA_PERIOD_US;
|
||||
}
|
||||
uint8_t backoff = mac_csma_random_backoff_get(rf_mac_setup);
|
||||
uint32_t backoff_in_us;
|
||||
//Multiple aUnitBackoffPeriod symbol time
|
||||
|
@ -101,6 +105,13 @@ uint32_t mac_csma_backoff_get(protocol_interface_rf_mac_setup_s *rf_mac_setup)
|
|||
if (backoff_in_us < MIN_FHSS_CSMA_PERIOD_US) {
|
||||
backoff_in_us += MIN_FHSS_CSMA_PERIOD_US;
|
||||
}
|
||||
// Backoff must be long enough to make multiple CCA checks
|
||||
if (backoff_in_us < (uint32_t)(rf_mac_setup->multi_cca_interval * (rf_mac_setup->number_of_csma_ca_periods - 1))) {
|
||||
backoff_in_us += ((rf_mac_setup->multi_cca_interval * (rf_mac_setup->number_of_csma_ca_periods - 1)) - backoff_in_us);
|
||||
}
|
||||
if (rf_mac_setup->mac_tx_retry) {
|
||||
backoff_in_us += rf_mac_setup->fhss_api->get_retry_period(rf_mac_setup->fhss_api, rf_mac_setup->active_pd_data_request->DstAddr, rf_mac_setup->dev_driver->phy_driver->phy_MTU);
|
||||
}
|
||||
}
|
||||
return backoff_in_us;
|
||||
}
|
||||
|
@ -199,6 +210,20 @@ int8_t mac_pd_sap_req(protocol_interface_rf_mac_setup_s *rf_mac_setup)
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* Abort active PHY transmission.
|
||||
*
|
||||
* \param rf_mac_setup pointer to MAC.
|
||||
*
|
||||
*/
|
||||
void mac_pd_abort_active_tx(protocol_interface_rf_mac_setup_s *rf_mac_setup)
|
||||
{
|
||||
phy_csma_params_t csma_params;
|
||||
// Set TX time to 0 to abort current transmission
|
||||
csma_params.backoff_time = 0;
|
||||
rf_mac_setup->dev_driver->phy_driver->extension(PHY_EXTENSION_SET_CSMA_PARAMETERS, (uint8_t *) &csma_params);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set PHY TX time.
|
||||
*
|
||||
|
@ -227,6 +252,9 @@ void mac_pd_sap_set_phy_tx_time(protocol_interface_rf_mac_setup_s *rf_mac_setup,
|
|||
*/
|
||||
static uint32_t mac_pd_sap_get_phy_rx_time(protocol_interface_rf_mac_setup_s *rf_mac_setup)
|
||||
{
|
||||
if (!rf_mac_setup->rf_csma_extension_supported) {
|
||||
return 0;
|
||||
}
|
||||
uint8_t rx_time_buffer[4];
|
||||
rf_mac_setup->dev_driver->phy_driver->extension(PHY_EXTENSION_READ_RX_TIME, rx_time_buffer);
|
||||
return common_read_32_bit(rx_time_buffer);
|
||||
|
@ -341,6 +369,10 @@ static void mac_sap_no_ack_cb(protocol_interface_rf_mac_setup_s *rf_ptr)
|
|||
rf_ptr->mac_cca_retry = 0;
|
||||
rf_ptr->mac_tx_retry++; //Update retry counter
|
||||
mac_csma_param_init(rf_ptr);
|
||||
// Increase current backoff exponent when retry count grows
|
||||
for (int retry_index = rf_ptr->mac_tx_retry; retry_index > 0; retry_index--) {
|
||||
mac_csma_BE_update(rf_ptr);
|
||||
}
|
||||
rf_ptr->mac_tx_status.retry++;
|
||||
/*Send retry using random interval*/
|
||||
if (mcps_pd_data_rebuild(rf_ptr, rf_ptr->active_pd_data_request)) {
|
||||
|
@ -387,17 +419,17 @@ static int8_t mac_data_interface_tx_done_cb(protocol_interface_rf_mac_setup_s *r
|
|||
if (status == PHY_LINK_CCA_PREPARE) {
|
||||
|
||||
if (rf_ptr->mac_ack_tx_active) {
|
||||
return 0;
|
||||
return PHY_TX_ALLOWED;
|
||||
}
|
||||
|
||||
if (mac_data_asynch_channel_switch(rf_ptr, rf_ptr->active_pd_data_request)) {
|
||||
return 0;
|
||||
return PHY_TX_ALLOWED;
|
||||
}
|
||||
|
||||
if (rf_ptr->fhss_api) {
|
||||
mac_pre_build_frame_t *active_buf = rf_ptr->active_pd_data_request;
|
||||
if (!active_buf) {
|
||||
return -1;
|
||||
return PHY_TX_NOT_ALLOWED;
|
||||
}
|
||||
|
||||
// Change to destination channel and write synchronization info to Beacon frames here
|
||||
|
@ -408,16 +440,22 @@ static int8_t mac_data_interface_tx_done_cb(protocol_interface_rf_mac_setup_s *r
|
|||
// 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);
|
||||
return -2;
|
||||
return PHY_TX_NOT_ALLOWED;
|
||||
}
|
||||
// When FHSS TX handle returns -3, we are trying to transmit broadcast packet on unicast channel -> push back
|
||||
// to queue by using CCA fail event
|
||||
if (tx_handle_retval == -3) {
|
||||
mac_tx_done_state_set(rf_ptr, MAC_CCA_FAIL);
|
||||
return -3;
|
||||
return PHY_TX_NOT_ALLOWED;
|
||||
} else if (tx_handle_retval == -2) {
|
||||
mac_tx_done_state_set(rf_ptr, MAC_UNKNOWN_DESTINATION);
|
||||
return -2;
|
||||
return PHY_TX_NOT_ALLOWED;
|
||||
}
|
||||
if (active_buf->csma_periods_left > 0) {
|
||||
active_buf->csma_periods_left--;
|
||||
active_buf->tx_time += rf_ptr->multi_cca_interval;
|
||||
mac_pd_sap_set_phy_tx_time(rf_ptr, active_buf->tx_time, true);
|
||||
return PHY_RESTART_CSMA;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -479,6 +517,9 @@ static int8_t mac_data_interface_tx_done_cb(protocol_interface_rf_mac_setup_s *r
|
|||
mac_sap_cca_fail_cb(rf_ptr);
|
||||
break;
|
||||
|
||||
case PHY_LINK_CCA_OK:
|
||||
break;
|
||||
|
||||
case PHY_LINK_TX_FAIL:
|
||||
mac_sap_no_ack_cb(rf_ptr);
|
||||
break;
|
||||
|
@ -531,7 +572,7 @@ static int8_t mac_data_interface_tx_done_by_ack_cb(protocol_interface_rf_mac_set
|
|||
return 0;
|
||||
}
|
||||
|
||||
static bool mac_pd_sap_ack_validation(protocol_interface_rf_mac_setup_s *rf_ptr, mac_fcf_sequence_t *fcf_dsn, const uint8_t *data_ptr)
|
||||
static bool mac_pd_sap_ack_validation(protocol_interface_rf_mac_setup_s *rf_ptr, const mac_fcf_sequence_t *fcf_dsn, const uint8_t *data_ptr)
|
||||
{
|
||||
if (!rf_ptr->active_pd_data_request || !rf_ptr->active_pd_data_request->fcf_dsn.ackRequested) {
|
||||
return false; //No active Data request anymore or no ACK request for current TX
|
||||
|
@ -587,10 +628,227 @@ static bool mac_pd_sap_ack_validation(protocol_interface_rf_mac_setup_s *rf_ptr,
|
|||
return true;
|
||||
}
|
||||
|
||||
static int8_t mac_pd_sap_validate_fcf(protocol_interface_rf_mac_setup_s *rf_ptr, const mac_fcf_sequence_t *fcf_read, arm_pd_sap_generic_ind_t *pd_data_ind)
|
||||
{
|
||||
switch (fcf_read->frametype) {
|
||||
case FC_DATA_FRAME:
|
||||
if (fcf_read->SrcAddrMode == MAC_ADDR_MODE_NONE) {
|
||||
return -1;
|
||||
} else if (fcf_read->DstAddrMode == MAC_ADDR_MODE_NONE && fcf_read->frameVersion != MAC_FRAME_VERSION_2015) {
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
case FC_BEACON_FRAME:
|
||||
if (fcf_read->SrcAddrMode == MAC_ADDR_MODE_NONE || fcf_read->DstAddrMode != MAC_ADDR_MODE_NONE) {
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
case FC_ACK_FRAME:
|
||||
// Only accept version 2015 Acks
|
||||
if (fcf_read->frameVersion != MAC_FRAME_VERSION_2015) {
|
||||
return -1;
|
||||
}
|
||||
//Validate Ack doesn't request Ack
|
||||
if (fcf_read->ackRequested) {
|
||||
return -1;
|
||||
}
|
||||
//Validate ACK
|
||||
if (!mac_pd_sap_ack_validation(rf_ptr, fcf_read, pd_data_ind->data_ptr)) {
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
case FC_CMD_FRAME:
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool mac_pd_sap_panid_filter_common(const uint8_t *mac_header, const mac_fcf_sequence_t *fcf_read, uint16_t own_pan_id)
|
||||
{
|
||||
// Beacon frames shouldn't be dropped as they might be used by load balancing
|
||||
if (fcf_read->frametype == MAC_FRAME_BEACON) {
|
||||
return true;
|
||||
}
|
||||
if (own_pan_id == 0xffff) {
|
||||
return true;
|
||||
}
|
||||
uint16_t dst_pan_id = mac_header_get_dst_panid(fcf_read, mac_header, 0xffff);
|
||||
if (dst_pan_id == 0xffff) {
|
||||
return true;
|
||||
}
|
||||
if (own_pan_id == dst_pan_id) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool mac_pd_sap_panid_v2_filter(const uint8_t *ptr, const mac_fcf_sequence_t *fcf_read, uint16_t pan_id)
|
||||
{
|
||||
if ((fcf_read->DstAddrMode == MAC_ADDR_MODE_NONE) && (fcf_read->frametype == FC_DATA_FRAME || fcf_read->frametype == FC_CMD_FRAME)) {
|
||||
return true;
|
||||
}
|
||||
if ((fcf_read->DstAddrMode == MAC_ADDR_MODE_64_BIT) && (fcf_read->SrcAddrMode == MAC_ADDR_MODE_64_BIT) && fcf_read->intraPan) {
|
||||
return true;
|
||||
}
|
||||
return mac_pd_sap_panid_filter_common(ptr, fcf_read, pan_id);
|
||||
}
|
||||
|
||||
static bool mac_pd_sap_addr_filter_common(const uint8_t *mac_header, const mac_fcf_sequence_t *fcf_read, uint8_t *mac_64bit_addr, uint16_t mac_16bit_addr)
|
||||
{
|
||||
uint8_t cmp_table[8] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
|
||||
uint8_t dst_addr[8];
|
||||
mac_header_get_dst_address(fcf_read, mac_header, dst_addr);
|
||||
|
||||
switch (fcf_read->DstAddrMode) {
|
||||
case MAC_ADDR_MODE_16_BIT:
|
||||
if (!memcmp(dst_addr, cmp_table, 2)) {
|
||||
return true;
|
||||
}
|
||||
uint8_t temp[2];
|
||||
common_write_16_bit(mac_16bit_addr, temp);
|
||||
if (!memcmp(temp, dst_addr, 2)) {
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case MAC_ADDR_MODE_64_BIT:
|
||||
if (!memcmp(dst_addr, cmp_table, 8)) {
|
||||
return true;
|
||||
}
|
||||
if (!memcmp(mac_64bit_addr, dst_addr, 8)) {
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case MAC_ADDR_MODE_NONE:
|
||||
return true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool mac_pd_sap_addr_v2_filter(const uint8_t *mac_header, const mac_fcf_sequence_t *fcf_read, uint8_t *mac_64bit_addr, uint16_t mac_16bit_addr)
|
||||
{
|
||||
return mac_pd_sap_addr_filter_common(mac_header, fcf_read, mac_64bit_addr, mac_16bit_addr);
|
||||
}
|
||||
|
||||
static bool mac_pd_sap_rx_filter(const uint8_t *mac_header, const mac_fcf_sequence_t *fcf_read, uint8_t phy_filter_mask, uint8_t *mac_64bit_addr, uint16_t mac_16bit_addr, uint16_t pan_id)
|
||||
{
|
||||
uint8_t version = fcf_read->frameVersion;
|
||||
|
||||
if (version == MAC_FRAME_VERSION_2015 && !(phy_filter_mask & (1 << MAC_FRAME_VERSION_2))) {
|
||||
if (!mac_pd_sap_panid_v2_filter(mac_header, fcf_read, pan_id)) {
|
||||
return false;
|
||||
}
|
||||
if (!mac_pd_sap_addr_v2_filter(mac_header, fcf_read, mac_64bit_addr, mac_16bit_addr)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static int8_t mac_pd_sap_generate_ack(protocol_interface_rf_mac_setup_s *rf_ptr, const mac_fcf_sequence_t *fcf_read, arm_pd_sap_generic_ind_t *pd_data_ind)
|
||||
{
|
||||
//Generate ACK when Extension is enabled and ACK is requested only for version 2 frames.
|
||||
if (!rf_ptr->mac_extension_enabled || !fcf_read->ackRequested || (fcf_read->frameVersion != MAC_FRAME_VERSION_2015)) {
|
||||
return 0;
|
||||
}
|
||||
if (rf_ptr->mac_ack_tx_active) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
mcps_ack_data_payload_t ack_payload;
|
||||
mac_api_t *mac_api = get_sw_mac_api(rf_ptr);
|
||||
mac_api->enhanced_ack_data_req_cb(mac_api, &ack_payload, pd_data_ind->dbm, pd_data_ind->link_quality);
|
||||
//Calculate Delta time
|
||||
|
||||
return mcps_generic_ack_build(rf_ptr, fcf_read, pd_data_ind->data_ptr, &ack_payload);
|
||||
}
|
||||
|
||||
static mac_pre_parsed_frame_t *mac_pd_sap_allocate_receive_buffer(protocol_interface_rf_mac_setup_s *rf_ptr, const mac_fcf_sequence_t *fcf_read, arm_pd_sap_generic_ind_t *pd_data_ind)
|
||||
{
|
||||
mac_pre_parsed_frame_t *buffer = mcps_sap_pre_parsed_frame_buffer_get(pd_data_ind->data_ptr, pd_data_ind->data_len);
|
||||
if (!buffer) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//Copy Pre Parsed values
|
||||
buffer->fcf_dsn = *fcf_read;
|
||||
buffer->timestamp = mac_pd_sap_get_phy_rx_time(rf_ptr);
|
||||
buffer->ack_pendinfg_status = mac_data_interface_read_last_ack_pending_status(rf_ptr);
|
||||
/* Set default flags */
|
||||
buffer->dbm = pd_data_ind->dbm;
|
||||
buffer->LQI = pd_data_ind->link_quality;
|
||||
buffer->mac_class_ptr = rf_ptr;
|
||||
return buffer;
|
||||
}
|
||||
|
||||
static int8_t mac_pd_sap_parse_length_fields(mac_pre_parsed_frame_t *buffer, arm_pd_sap_generic_ind_t *pd_data_ind, const uint8_t *parse_ptr)
|
||||
{
|
||||
if (buffer->fcf_dsn.frametype > FC_CMD_FRAME) {
|
||||
return -1;
|
||||
}
|
||||
buffer->mac_header_length = parse_ptr - pd_data_ind->data_ptr;
|
||||
int16_t length = pd_data_ind->data_len;
|
||||
buffer->mac_header_length += mac_header_address_length(&buffer->fcf_dsn);
|
||||
length -= buffer->mac_header_length;
|
||||
if (length < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
buffer->mac_payload_length = (buffer->frameLength - buffer->mac_header_length);
|
||||
|
||||
if (buffer->fcf_dsn.securityEnabled) {
|
||||
//Read KEYID Mode
|
||||
uint8_t key_id_mode, security_level, mic_len;
|
||||
uint8_t *security_ptr = &buffer->buf[buffer->mac_header_length];
|
||||
uint8_t auxBaseHeader = *security_ptr;
|
||||
key_id_mode = (auxBaseHeader >> 3) & 3;
|
||||
security_level = auxBaseHeader & 7;
|
||||
|
||||
switch (key_id_mode) {
|
||||
case MAC_KEY_ID_MODE_IMPLICIT:
|
||||
if (security_level) {
|
||||
buffer->security_aux_header_length = 5;
|
||||
} else {
|
||||
buffer->security_aux_header_length = 1;
|
||||
}
|
||||
break;
|
||||
case MAC_KEY_ID_MODE_IDX:
|
||||
buffer->security_aux_header_length = 6;
|
||||
break;
|
||||
case MAC_KEY_ID_MODE_SRC4_IDX:
|
||||
buffer->security_aux_header_length = 10;
|
||||
break;
|
||||
default:
|
||||
buffer->security_aux_header_length = 14;
|
||||
break;
|
||||
}
|
||||
|
||||
length -= buffer->security_aux_header_length;
|
||||
mic_len = mac_security_mic_length_get(security_level);
|
||||
|
||||
length -= mic_len;
|
||||
|
||||
//Verify that data length is not negative
|
||||
if (length < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
buffer->mac_payload_length -= (buffer->security_aux_header_length + mic_len);
|
||||
}
|
||||
//Do not accept command frame with length 0
|
||||
if (buffer->fcf_dsn.frametype == FC_CMD_FRAME && length == 0) {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int8_t mac_pd_sap_data_cb(void *identifier, arm_phy_sap_msg_t *message)
|
||||
{
|
||||
protocol_interface_rf_mac_setup_s *rf_ptr = (protocol_interface_rf_mac_setup_s *)identifier;
|
||||
mac_pre_parsed_frame_t *buffer = NULL;
|
||||
|
||||
if (!rf_ptr || !message) {
|
||||
return -1;
|
||||
|
@ -601,184 +859,55 @@ int8_t mac_pd_sap_data_cb(void *identifier, arm_phy_sap_msg_t *message)
|
|||
}
|
||||
|
||||
if (message->id == MAC15_4_PD_SAP_DATA_IND) {
|
||||
const uint8_t *ptr;
|
||||
arm_pd_sap_generic_ind_t *pd_data_ind = &(message->message.generic_data_ind);
|
||||
|
||||
if (pd_data_ind->data_len < 3) {
|
||||
return -1;
|
||||
}
|
||||
ptr = pd_data_ind->data_ptr;
|
||||
|
||||
uint32_t time_stamp = 0;
|
||||
if (rf_ptr->rf_csma_extension_supported) {
|
||||
time_stamp = mac_pd_sap_get_phy_rx_time(rf_ptr);
|
||||
}
|
||||
mac_fcf_sequence_t fcf_read;
|
||||
ptr = mac_header_parse_fcf_dsn(&fcf_read, ptr);
|
||||
//Check PanID presents at header
|
||||
fcf_read.DstPanPresents = mac_dst_panid_present(&fcf_read);
|
||||
fcf_read.SrcPanPresents = mac_src_panid_present(&fcf_read);
|
||||
int16_t length = pd_data_ind->data_len;
|
||||
if (!rf_ptr->macProminousMode) {
|
||||
const uint8_t *ptr = mac_header_parse_fcf_dsn(&fcf_read, pd_data_ind->data_ptr);
|
||||
|
||||
//Unsupported Frame
|
||||
if (fcf_read.frametype > FC_CMD_FRAME || (fcf_read.frametype == FC_ACK_FRAME && fcf_read.frameVersion != MAC_FRAME_VERSION_2015)) {
|
||||
mac_pre_parsed_frame_t *buffer = mac_pd_sap_allocate_receive_buffer(rf_ptr, &fcf_read, pd_data_ind);
|
||||
if (buffer && mac_filter_modify_link_quality(rf_ptr->mac_interface_id, buffer) == 1) {
|
||||
goto ERROR_HANDLER;
|
||||
}
|
||||
if (!rf_ptr->macProminousMode) {
|
||||
if (mac_pd_sap_validate_fcf(rf_ptr, &fcf_read, pd_data_ind)) {
|
||||
goto ERROR_HANDLER;
|
||||
}
|
||||
|
||||
switch (fcf_read.frametype) {
|
||||
case FC_DATA_FRAME:
|
||||
if (fcf_read.SrcAddrMode == MAC_ADDR_MODE_NONE) {
|
||||
return -1;
|
||||
} else if (fcf_read.DstAddrMode == MAC_ADDR_MODE_NONE && fcf_read.frameVersion != MAC_FRAME_VERSION_2015) {
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
case FC_BEACON_FRAME:
|
||||
if (fcf_read.SrcAddrMode == MAC_ADDR_MODE_NONE || fcf_read.DstAddrMode != MAC_ADDR_MODE_NONE) {
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
case FC_ACK_FRAME:
|
||||
//Validate here that we are waiting ack
|
||||
if (fcf_read.ackRequested) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
//Validate ACK
|
||||
if (!mac_pd_sap_ack_validation(rf_ptr, &fcf_read, pd_data_ind->data_ptr)) {
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
if (!mac_pd_sap_rx_filter(pd_data_ind->data_ptr, &fcf_read, rf_ptr->mac_frame_filters, rf_ptr->mac64, rf_ptr->mac_short_address, rf_ptr->pan_id)) {
|
||||
goto ERROR_HANDLER;
|
||||
}
|
||||
|
||||
//Generate ACK when Extension is enabled and ACK is requested
|
||||
if (rf_ptr->mac_extension_enabled && fcf_read.ackRequested && fcf_read.frameVersion == MAC_FRAME_VERSION_2015) {
|
||||
//SEND ACK here
|
||||
if (rf_ptr->mac_ack_tx_active) {
|
||||
return -1;
|
||||
if (mac_pd_sap_generate_ack(rf_ptr, &fcf_read, pd_data_ind)) {
|
||||
goto ERROR_HANDLER;
|
||||
}
|
||||
if (buffer) {
|
||||
if (mac_pd_sap_parse_length_fields(buffer, pd_data_ind, ptr)) {
|
||||
goto ERROR_HANDLER;
|
||||
}
|
||||
|
||||
mcps_ack_data_payload_t ack_payload;
|
||||
mac_api_t *mac_api = get_sw_mac_api(rf_ptr);
|
||||
mac_api->enhanced_ack_data_req_cb(mac_api, &ack_payload, pd_data_ind->dbm, pd_data_ind->link_quality);
|
||||
//Calculate Delta time
|
||||
|
||||
if (mcps_generic_ack_build(rf_ptr, &fcf_read, pd_data_ind->data_ptr, &ack_payload, time_stamp) != 0) {
|
||||
return -1;
|
||||
if (!mac_header_information_elements_parse(buffer)) {
|
||||
goto ERROR_HANDLER;
|
||||
}
|
||||
if (buffer->fcf_dsn.frametype == FC_ACK_FRAME) {
|
||||
if (mac_data_interface_tx_done_by_ack_cb(rf_ptr, buffer)) {
|
||||
mcps_sap_pre_parsed_frame_buffer_free(buffer);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
buffer = mcps_sap_pre_parsed_frame_buffer_get(pd_data_ind->data_ptr, pd_data_ind->data_len);
|
||||
|
||||
if (!buffer) {
|
||||
sw_mac_stats_update(rf_ptr, STAT_MAC_RX_DROP, 0);
|
||||
return -3;
|
||||
}
|
||||
|
||||
//Copy Pre Parsed values
|
||||
buffer->fcf_dsn = fcf_read;
|
||||
buffer->timestamp = time_stamp;
|
||||
|
||||
buffer->ack_pendinfg_status = mac_data_interface_read_last_ack_pending_status(rf_ptr);
|
||||
|
||||
|
||||
// Upward direction functions assume no headroom and are trusting that removed bytes are still valid.
|
||||
// see mac.c:655
|
||||
|
||||
/* Set default flags */
|
||||
buffer->dbm = pd_data_ind->dbm;
|
||||
buffer->LQI = pd_data_ind->link_quality;
|
||||
buffer->mac_class_ptr = rf_ptr;
|
||||
//Dnamic calculation for FCF + SEQ parse
|
||||
buffer->mac_header_length = ptr - pd_data_ind->data_ptr;
|
||||
|
||||
if (!rf_ptr->macProminousMode) {
|
||||
|
||||
if (buffer->fcf_dsn.frametype > FC_CMD_FRAME) {
|
||||
goto ERROR_HANDLER;
|
||||
}
|
||||
|
||||
buffer->mac_header_length += mac_header_address_length(&buffer->fcf_dsn);
|
||||
|
||||
length -= buffer->mac_header_length;
|
||||
|
||||
if (length < 0) {
|
||||
goto ERROR_HANDLER;
|
||||
}
|
||||
|
||||
buffer->mac_payload_length = (buffer->frameLength - buffer->mac_header_length);
|
||||
|
||||
if (buffer->fcf_dsn.securityEnabled) {
|
||||
//Read KEYID Mode
|
||||
uint8_t key_id_mode, security_level, mic_len;
|
||||
uint8_t *security_ptr = &buffer->buf[buffer->mac_header_length];
|
||||
uint8_t auxBaseHeader = *security_ptr;
|
||||
key_id_mode = (auxBaseHeader >> 3) & 3;
|
||||
security_level = auxBaseHeader & 7;
|
||||
|
||||
switch (key_id_mode) {
|
||||
case MAC_KEY_ID_MODE_IMPLICIT:
|
||||
if (security_level) {
|
||||
buffer->security_aux_header_length = 5;
|
||||
} else {
|
||||
buffer->security_aux_header_length = 1;
|
||||
}
|
||||
break;
|
||||
case MAC_KEY_ID_MODE_IDX:
|
||||
buffer->security_aux_header_length = 6;
|
||||
break;
|
||||
case MAC_KEY_ID_MODE_SRC4_IDX:
|
||||
buffer->security_aux_header_length = 10;
|
||||
break;
|
||||
default:
|
||||
buffer->security_aux_header_length = 14;
|
||||
break;
|
||||
}
|
||||
|
||||
length -= buffer->security_aux_header_length;
|
||||
mic_len = mac_security_mic_length_get(security_level);
|
||||
|
||||
length -= mic_len;
|
||||
|
||||
//Verify that data length is not negative
|
||||
if (length < 0) {
|
||||
goto ERROR_HANDLER;
|
||||
}
|
||||
|
||||
buffer->mac_payload_length -= (buffer->security_aux_header_length + mic_len);
|
||||
}
|
||||
|
||||
//Do not accept command frame with length 0
|
||||
if (fcf_read.frametype == FC_CMD_FRAME && length == 0) {
|
||||
goto ERROR_HANDLER;
|
||||
}
|
||||
|
||||
//Parse IE Elements
|
||||
if (!mac_header_information_elements_parse(buffer)) {
|
||||
goto ERROR_HANDLER;
|
||||
}
|
||||
}
|
||||
|
||||
if (!rf_ptr->macProminousMode && buffer->fcf_dsn.frametype == FC_ACK_FRAME) {
|
||||
if (mac_data_interface_tx_done_by_ack_cb(rf_ptr, buffer)) {
|
||||
mcps_sap_pre_parsed_frame_buffer_free(buffer);
|
||||
}
|
||||
if (mcps_sap_pd_ind(buffer) == 0) {
|
||||
return 0;
|
||||
} else {
|
||||
if (mcps_sap_pd_ind(buffer) == 0) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
ERROR_HANDLER:
|
||||
mcps_sap_pre_parsed_frame_buffer_free(buffer);
|
||||
sw_mac_stats_update(rf_ptr, STAT_MAC_RX_DROP, 0);
|
||||
return -1;
|
||||
|
||||
|
||||
} else if (message->id == MAC15_4_PD_SAP_DATA_TX_CONFIRM) {
|
||||
arm_pd_sap_15_4_confirm_with_params_t *pd_data_cnf = &(message->message.mac15_4_pd_sap_confirm);
|
||||
return mac_data_interface_tx_done_cb(rf_ptr, pd_data_cnf->status, pd_data_cnf->cca_retry, pd_data_cnf->tx_retry);
|
||||
|
|
|
@ -39,6 +39,8 @@ int8_t mac_pd_sap_req(struct protocol_interface_rf_mac_setup *rf_mac_setup);
|
|||
|
||||
int8_t mac_plme_cca_req(struct protocol_interface_rf_mac_setup *rf_mac_setup);
|
||||
|
||||
void mac_pd_abort_active_tx(struct protocol_interface_rf_mac_setup *rf_mac_setup);
|
||||
|
||||
void mac_pd_sap_set_phy_tx_time(struct protocol_interface_rf_mac_setup *rf_mac_setup, uint32_t tx_time, bool cca_enabled);
|
||||
|
||||
void mac_pd_sap_rf_low_level_function_set(void *mac_ptr, void *driver);
|
||||
|
|
|
@ -33,6 +33,7 @@
|
|||
#include "Service_Libs/Trickle/trickle.h"
|
||||
#include "6LoWPAN/MAC/mac_helper.h"
|
||||
#include "6LoWPAN/Thread/thread_common.h"
|
||||
#include "6LoWPAN/ws/ws_common.h"
|
||||
#include "MPL/mpl.h"
|
||||
|
||||
#define TRACE_GROUP "mpl"
|
||||
|
@ -1105,7 +1106,8 @@ static buffer_t *mpl_exthdr_provider(buffer_t *buf, ipv6_exthdr_stage_t stage, i
|
|||
|
||||
/* "Compress" seed ID if it's the IPv6 source address */
|
||||
/* (For Thread, also compress if source is the 16-bit address) */
|
||||
if (seed_id_len == 16 && addr_ipv6_equal(seed_id, buf->src_sa.address)) {
|
||||
/* (For Wi-sun, not support seed id address compression */
|
||||
if (!ws_info(buf->interface) && seed_id_len == 16 && addr_ipv6_equal(seed_id, buf->src_sa.address)) {
|
||||
seed_id_len = 0;
|
||||
} else if (seed_id_len == 2 && thread_addr_is_mesh_local_16(buf->src_sa.address, buf->interface) &&
|
||||
seed_id[0] == buf->src_sa.address[14] && seed_id[1] == buf->src_sa.address[15]) {
|
||||
|
|
|
@ -121,6 +121,7 @@ typedef enum icmp_state {
|
|||
ER_BOOTSTRAP_SCAN_FAIL,
|
||||
ER_BOOTSTRAP_LEADER_UP,
|
||||
ER_BOOTSTRAP_NEW_FRAGMENT_START,
|
||||
ER_WAIT_RESTART,
|
||||
ER_RPL_LOCAL_REPAIR,
|
||||
} icmp_state_t;
|
||||
|
||||
|
@ -514,4 +515,5 @@ extern void protocol_core_dhcpv6_allocated_address_remove(protocol_interface_inf
|
|||
extern void nwk_bootsrap_state_update(arm_nwk_interface_status_type_e posted_event, protocol_interface_info_entry_t *cur);
|
||||
void bootsrap_next_state_kick(icmp_state_t new_state, protocol_interface_info_entry_t *cur);
|
||||
int8_t protocol_interface_address_compare(const uint8_t *addr);
|
||||
bool protocol_interface_any_address_match(const uint8_t *prefix, uint8_t prefix_len);
|
||||
#endif /* _NS_PROTOCOL_H */
|
||||
|
|
|
@ -81,6 +81,7 @@
|
|||
#include "6LoWPAN/Fragmentation/cipv6_fragmenter.h"
|
||||
#include "Service_Libs/load_balance/load_balance_api.h"
|
||||
#include "Service_Libs/pan_blacklist/pan_blacklist_api.h"
|
||||
#include "Service_Libs/etx/etx.h"
|
||||
|
||||
#include "mac_api.h"
|
||||
#include "ethernet_mac_api.h"
|
||||
|
@ -260,6 +261,7 @@ void core_timer_event_handle(uint16_t ticksUpdate)
|
|||
if (cur->nwk_wpan_nvm_api) {
|
||||
cur->nwk_wpan_nvm_api->nvm_params_update_cb(cur->nwk_wpan_nvm_api, false);
|
||||
}
|
||||
etx_cache_timer(cur->id, seconds);
|
||||
}
|
||||
} else if (cur->nwk_id == IF_IPV6) {
|
||||
//Slow Pointer Update
|
||||
|
@ -300,6 +302,9 @@ void core_timer_event_handle(uint16_t ticksUpdate)
|
|||
ipv6_destination_cache_timer(seconds);
|
||||
ipv6_frag_timer(seconds);
|
||||
cipv6_frag_timer(seconds);
|
||||
#ifdef HAVE_WS
|
||||
ws_pae_controller_slow_timer(seconds);
|
||||
#endif
|
||||
protocol_6lowpan_mle_timer(seconds);
|
||||
/* This limit bad behaviour device's MLE link reject generation */
|
||||
|
||||
|
@ -339,7 +344,7 @@ void core_timer_event_handle(uint16_t ticksUpdate)
|
|||
icmpv6_radv_timer(ticksUpdate);
|
||||
protocol_core_security_tick_update(ticksUpdate);
|
||||
#ifdef HAVE_WS
|
||||
ws_pae_controller_timer(ticksUpdate);
|
||||
ws_pae_controller_fast_timer(ticksUpdate);
|
||||
#endif
|
||||
platform_enter_critical();
|
||||
protocol_core_timer_info.core_timer_event = false;
|
||||
|
@ -1135,3 +1140,27 @@ int8_t protocol_interface_address_compare(const uint8_t *addr)
|
|||
return -1;
|
||||
}
|
||||
|
||||
static bool protocol_address_prefix_cmp(protocol_interface_info_entry_t *interface, const uint8_t *prefix, uint8_t prefix_len)
|
||||
{
|
||||
ns_list_foreach(if_address_entry_t, adr, &interface->ip_addresses) {
|
||||
if (bitsequal(adr->address, prefix, prefix_len)) {
|
||||
/* Prefix stil used at list so stop checking */
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool protocol_interface_any_address_match(const uint8_t *prefix, uint8_t prefix_len)
|
||||
{
|
||||
ns_list_foreach(protocol_interface_info_entry_t, cur, &protocol_interface_info_list) {
|
||||
|
||||
if (protocol_address_prefix_cmp(cur, prefix, prefix_len)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -151,17 +151,6 @@ static void rpl_control_publish_own_addresses(rpl_domain_t *domain, rpl_instance
|
|||
}
|
||||
}
|
||||
|
||||
static void rpl_control_publish_own_address(rpl_domain_t *domain, const if_address_entry_t *addr)
|
||||
{
|
||||
ns_list_foreach(rpl_instance_t, instance, &domain->instances) {
|
||||
if (!rpl_instance_am_root(instance)) {
|
||||
uint32_t descriptor = 0;
|
||||
bool want_descriptor = rpl_policy_target_descriptor_for_own_address(domain, addr->address, addr->source, addr->data, &descriptor);
|
||||
rpl_instance_publish_dao_target(instance, addr->address, 128, addr->valid_lifetime, true, want_descriptor, descriptor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void rpl_control_publish_host_address(rpl_domain_t *domain, const uint8_t addr[16], uint32_t lifetime)
|
||||
{
|
||||
ns_list_foreach(rpl_instance_t, instance, &domain->instances) {
|
||||
|
@ -260,10 +249,6 @@ static void rpl_control_addr_notifier(struct protocol_interface_info_entry *inte
|
|||
}
|
||||
|
||||
switch (reason) {
|
||||
case ADDR_CALLBACK_DAD_COMPLETE:
|
||||
case ADDR_CALLBACK_REFRESHED:
|
||||
rpl_control_publish_own_address(interface->rpl_domain, addr);
|
||||
break;
|
||||
case ADDR_CALLBACK_DELETED:
|
||||
rpl_control_unpublish_address(interface->rpl_domain, addr->address);
|
||||
break;
|
||||
|
@ -345,11 +330,7 @@ void rpl_control_set_domain_on_interface(protocol_interface_info_entry_t *cur, r
|
|||
cur->rpl_domain = domain;
|
||||
addr_add_group(cur, ADDR_LINK_LOCAL_ALL_RPL_NODES);
|
||||
}
|
||||
ns_list_foreach(if_address_entry_t, addr, &cur->ip_addresses) {
|
||||
if (!addr_is_ipv6_link_local(addr->address)) {
|
||||
rpl_control_publish_own_address(domain, addr);
|
||||
}
|
||||
}
|
||||
|
||||
if (downstream) {
|
||||
domain->non_storing_downstream_interface = cur->id;
|
||||
}
|
||||
|
@ -690,8 +671,9 @@ static void rpl_control_process_prefix_options(protocol_interface_info_entry_t *
|
|||
bool router_addr_set = false;
|
||||
|
||||
rpl_neighbour_t *pref_parent = rpl_instance_preferred_parent(instance);
|
||||
|
||||
// const rpl_dodag_conf_t *conf = rpl_dodag_get_config(dodag);
|
||||
if (neighbour == pref_parent) {
|
||||
rpl_dodag_update_unpublished_dio_prefix_start(dodag);
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
const uint8_t *ptr = rpl_control_find_option(start, end - start, RPL_PREFIX_INFO_OPTION, 30);
|
||||
|
@ -735,6 +717,9 @@ static void rpl_control_process_prefix_options(protocol_interface_info_entry_t *
|
|||
|
||||
start = ptr + 32;
|
||||
}
|
||||
if (neighbour == pref_parent) {
|
||||
rpl_dodag_update_unpublished_dio_prefix_finish(dodag);
|
||||
}
|
||||
}
|
||||
|
||||
void rpl_control_process_prefix_option(prefix_entry_t *prefix, protocol_interface_info_entry_t *cur)
|
||||
|
@ -894,10 +879,6 @@ malformed:
|
|||
if (!instance) {
|
||||
return buffer_free(buf);
|
||||
}
|
||||
|
||||
if ((g_mop_prf & RPL_MODE_MASK) != RPL_MODE_NO_DOWNWARD) {
|
||||
rpl_control_publish_own_addresses(domain, instance);
|
||||
}
|
||||
}
|
||||
|
||||
/* Lookup any existing neighbour entry */
|
||||
|
@ -1156,7 +1137,7 @@ void rpl_control_transmit_dio(rpl_domain_t *domain, protocol_interface_info_entr
|
|||
} else {
|
||||
prefix->options &= ~ PIO_R;
|
||||
|
||||
if (rpl_dodag_mop(dodag) == RPL_MODE_NON_STORING) {
|
||||
if (rpl_dodag_mop(dodag) == RPL_MODE_NON_STORING && prefix->lifetime != 0) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
@ -1194,7 +1175,7 @@ void rpl_control_transmit_dio(rpl_domain_t *domain, protocol_interface_info_entr
|
|||
ns_list_foreach_safe(prefix_entry_t, prefix, prefixes) {
|
||||
/* See equivalent checks in length calculation above */
|
||||
if ((prefix->options & (PIO_L | RPL_PIO_PUBLISHED)) == PIO_L ||
|
||||
(!(prefix->options & PIO_R) && rpl_dodag_mop(dodag) == RPL_MODE_NON_STORING)) {
|
||||
(!(prefix->options & PIO_R) && rpl_dodag_mop(dodag) == RPL_MODE_NON_STORING && prefix->lifetime != 0)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -1207,6 +1188,14 @@ void rpl_control_transmit_dio(rpl_domain_t *domain, protocol_interface_info_entr
|
|||
common_write_32_bit(0, ptr + 12); // reserved
|
||||
memcpy(ptr + 16, prefix->prefix, 16);
|
||||
ptr += 32;
|
||||
/* Transmitting a multicast DIO decrements the hold count for 0 lifetime prefixes */
|
||||
if (dst == NULL && (prefix->options & RPL_PIO_AGE)) {
|
||||
int hold_count = prefix->options & RPL_PIO_HOLD_MASK;
|
||||
if (hold_count) {
|
||||
hold_count--;
|
||||
prefix->options = (prefix->options & ~RPL_PIO_HOLD_MASK) | hold_count;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ns_list_foreach_safe(rpl_dio_route_t, route, routes) {
|
||||
|
@ -1616,6 +1605,7 @@ void rpl_control_slow_timer(uint16_t seconds)
|
|||
|
||||
ns_list_foreach(rpl_domain_t, domain, &rpl_domains) {
|
||||
ns_list_foreach_safe(rpl_instance_t, instance, &domain->instances) {
|
||||
rpl_control_publish_own_addresses(domain, instance);
|
||||
rpl_instance_slow_timer(instance, seconds);
|
||||
rpl_downward_dao_slow_timer(instance, seconds);
|
||||
/* We purge one item from each instance, so as not to favour one domain or instance */
|
||||
|
@ -1654,13 +1644,14 @@ rpl_instance_t *rpl_control_lookup_instance(rpl_domain_t *domain, uint8_t instan
|
|||
return rpl_lookup_instance(domain, instance_id, dodagid);
|
||||
}
|
||||
|
||||
bool rpl_control_get_instance_dao_target_count(rpl_domain_t *domain, uint8_t instance_id, const uint8_t *dodagid, uint16_t *target_count)
|
||||
bool rpl_control_get_instance_dao_target_count(rpl_domain_t *domain, uint8_t instance_id, const uint8_t *dodagid, const uint8_t *prefix, uint16_t *target_count)
|
||||
{
|
||||
rpl_instance_t *instance = rpl_lookup_instance(domain, instance_id, dodagid);
|
||||
if (!instance) {
|
||||
return false;
|
||||
}
|
||||
*target_count = rpl_upward_read_dao_target_list_size(instance);
|
||||
|
||||
*target_count = rpl_upward_read_dao_target_list_size(instance, prefix);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -160,7 +160,7 @@ void rpl_control_print(route_print_fn_t *print_fn);
|
|||
|
||||
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);
|
||||
bool rpl_control_get_instance_dao_target_count(rpl_domain_t *domain, uint8_t instance_id, const uint8_t *dodagid, uint16_t *target_count);
|
||||
bool rpl_control_get_instance_dao_target_count(rpl_domain_t *domain, uint8_t instance_id, const uint8_t *dodagid, const uint8_t *prefix, uint16_t *target_count);
|
||||
bool rpl_control_read_dodag_info(const struct rpl_instance *instance, struct rpl_dodag_info_t *dodag_info);
|
||||
const rpl_dodag_conf_t *rpl_control_get_dodag_config(const struct rpl_instance *instance);
|
||||
const uint8_t *rpl_control_preferred_parent_addr(const struct rpl_instance *instance, bool global);
|
||||
|
|
|
@ -345,8 +345,9 @@ void rpl_instance_publish_dao_target(rpl_instance_t *instance, const uint8_t *pr
|
|||
{
|
||||
rpl_dao_target_t *target = rpl_instance_lookup_published_dao_target(instance, prefix, prefix_len);
|
||||
if (target) {
|
||||
int diff = target->lifetime > valid_lifetime ? target->lifetime - valid_lifetime : valid_lifetime - target->lifetime;
|
||||
target->lifetime = valid_lifetime;
|
||||
if (!own) {
|
||||
if (!own && diff > 60) {
|
||||
/* For non-owned targets, publish triggers a refresh */
|
||||
rpl_downward_target_refresh(target);
|
||||
rpl_instance_dao_trigger(instance, 0);
|
||||
|
@ -590,7 +591,7 @@ void rpl_instance_send_address_registration(protocol_interface_info_entry_t *int
|
|||
|
||||
aro.status = ARO_SUCCESS;
|
||||
aro.present = true;
|
||||
aro.lifetime = addr->valid_lifetime;
|
||||
aro.lifetime = (addr->valid_lifetime / 60) + 1;
|
||||
memcpy(aro.eui64, interface->mac, 8);
|
||||
|
||||
// go through neighbour list, and send to all assigned parents.
|
||||
|
|
|
@ -932,6 +932,33 @@ const prefix_list_t *rpl_dodag_get_prefix_list(const rpl_dodag_t *dodag)
|
|||
{
|
||||
return &dodag->prefixes;
|
||||
}
|
||||
|
||||
/* Called before updating all prefixes in a DIO */
|
||||
void rpl_dodag_update_unpublished_dio_prefix_start(rpl_dodag_t *dodag)
|
||||
{
|
||||
/* Clear age flags - will use as a marker for entries being in the DIO */
|
||||
ns_list_foreach(prefix_entry_t, entry, &dodag->prefixes) {
|
||||
if (!(entry->options & RPL_PIO_PUBLISHED)) {
|
||||
entry->options &= ~RPL_PIO_AGE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Called after updating all prefixes in a DIO */
|
||||
void rpl_dodag_update_unpublished_dio_prefix_finish(rpl_dodag_t *dodag)
|
||||
{
|
||||
/* Any remaining non-published entries that don't have the age flag
|
||||
* set are not being sent by parent any more, so we should stop sending
|
||||
* too, except for the minimimum count requirement on 0 lifetime.
|
||||
*/
|
||||
ns_list_foreach_safe(prefix_entry_t, entry, &dodag->prefixes) {
|
||||
if ((entry->options & (RPL_PIO_PUBLISHED | RPL_PIO_AGE | RPL_PIO_HOLD_MASK)) == 0) {
|
||||
rpl_dodag_delete_dio_prefix(dodag, entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
prefix_entry_t *rpl_dodag_update_dio_prefix(rpl_dodag_t *dodag, const uint8_t *prefix, uint8_t prefix_len, uint8_t flags, uint32_t lifetime, uint32_t preftime, bool publish, bool age)
|
||||
{
|
||||
/* Don't let them set funny flags - we won't propagate them either.
|
||||
|
@ -948,20 +975,30 @@ prefix_entry_t *rpl_dodag_update_dio_prefix(rpl_dodag_t *dodag, const uint8_t *p
|
|||
flags |= RPL_PIO_AGE;
|
||||
}
|
||||
|
||||
if (lifetime == 0) {
|
||||
flags |= RPL_MAX_FINAL_RTR_ADVERTISEMENTS;
|
||||
}
|
||||
|
||||
prefix_entry_t *entry = icmpv6_prefix_add(&dodag->prefixes, prefix, prefix_len, lifetime, preftime, flags);
|
||||
prefix_entry_t *entry = icmpv6_prefix_add(&dodag->prefixes, prefix, prefix_len, lifetime, preftime, 0xff);
|
||||
/* icmpv6_prefix_add indicates a new entry by leaving options set to 0xFF */
|
||||
if (entry) {
|
||||
/* Newly-seen zero lifetimes should be advertised at least a few times -
|
||||
* count this down in the RPL_PIO_HOLD_COUNT field
|
||||
*/
|
||||
if (lifetime == 0 && (entry->options == 0xFF || entry->lifetime != 0)) {
|
||||
flags |= RPL_MAX_FINAL_RTR_ADVERTISEMENTS;
|
||||
}
|
||||
entry->options = flags;
|
||||
entry->lifetime = lifetime;
|
||||
entry->preftime = preftime;
|
||||
}
|
||||
return entry;
|
||||
}
|
||||
|
||||
void rpl_dodag_delete_dio_prefix(rpl_dodag_t *dodag, prefix_entry_t *prefix)
|
||||
{
|
||||
rpl_instance_t *instance = dodag->instance;
|
||||
|
||||
if (instance && instance->domain->prefix_cb) {
|
||||
instance->domain->prefix_cb(prefix, instance->domain->cb_handle, NULL);
|
||||
}
|
||||
|
||||
ns_list_remove(&dodag->prefixes, prefix);
|
||||
ns_dyn_mem_free(prefix);
|
||||
}
|
||||
|
@ -984,7 +1021,11 @@ static void rpl_dodag_age_prefixes(rpl_dodag_t *dodag, uint16_t seconds)
|
|||
prefix->lifetime -= seconds;
|
||||
} else {
|
||||
prefix->lifetime = 0;
|
||||
if ((prefix->options & RPL_PIO_HOLD_MASK) == 0) {
|
||||
/* Only delete on timeout if we're publishing - otherwise we will
|
||||
* keep advertising until we see our parent stop advertising it - deletion
|
||||
* is handled in rpl_control_process_prefix_options.
|
||||
*/
|
||||
if ((prefix->options & (RPL_PIO_PUBLISHED | RPL_PIO_HOLD_MASK)) == RPL_PIO_PUBLISHED) {
|
||||
rpl_dodag_delete_dio_prefix(dodag, prefix);
|
||||
}
|
||||
}
|
||||
|
@ -1742,8 +1783,19 @@ void rpl_upward_print_instance(rpl_instance_t *instance, route_print_fn_t *print
|
|||
}
|
||||
}
|
||||
|
||||
uint16_t rpl_upward_read_dao_target_list_size(const rpl_instance_t *instance)
|
||||
uint16_t rpl_upward_read_dao_target_list_size(const rpl_instance_t *instance, const uint8_t *target_prefix)
|
||||
{
|
||||
|
||||
if (target_prefix) {
|
||||
uint16_t registered_address_count = 0;
|
||||
ns_list_foreach(rpl_dao_target_t, target, &instance->dao_targets) {
|
||||
if (bitsequal(target->prefix, target_prefix, 64)) {
|
||||
registered_address_count++;
|
||||
}
|
||||
}
|
||||
return registered_address_count;
|
||||
}
|
||||
|
||||
return ns_list_count(&instance->dao_targets);
|
||||
}
|
||||
|
||||
|
|
|
@ -112,6 +112,8 @@ rpl_dio_route_t *rpl_dodag_update_dio_route(rpl_dodag_t *dodag, const uint8_t *p
|
|||
void rpl_dodag_delete_dio_route(rpl_dodag_t *dodag, rpl_dio_route_t *route);
|
||||
const rpl_dio_route_list_t *rpl_dodag_get_route_list(const rpl_dodag_t *dodag);
|
||||
|
||||
void rpl_dodag_update_unpublished_dio_prefix_start(rpl_dodag_t *dodag);
|
||||
void rpl_dodag_update_unpublished_dio_prefix_finish(rpl_dodag_t *dodag);
|
||||
prefix_entry_t *rpl_dodag_update_dio_prefix(rpl_dodag_t *dodag, const uint8_t *prefix, uint8_t prefix_len, uint8_t flags, uint32_t lifetime, uint32_t preftime, bool publish, bool age);
|
||||
void rpl_dodag_delete_dio_prefix(rpl_dodag_t *dodag, prefix_entry_t *prefix);
|
||||
const prefix_list_t *rpl_dodag_get_prefix_list(const rpl_dodag_t *dodag);
|
||||
|
@ -143,5 +145,5 @@ void rpl_instance_run_parent_selection(rpl_instance_t *instance);
|
|||
void rpl_upward_print_instance(rpl_instance_t *instance, route_print_fn_t *print_fn);
|
||||
|
||||
bool rpl_upward_read_dodag_info(const rpl_instance_t *instance, struct rpl_dodag_info_t *dodag_info);
|
||||
uint16_t rpl_upward_read_dao_target_list_size(const rpl_instance_t *instance);
|
||||
uint16_t rpl_upward_read_dao_target_list_size(const rpl_instance_t *instance, const uint8_t *target_prefix);
|
||||
#endif /* RPL_UPWARD_H_ */
|
||||
|
|
|
@ -1161,7 +1161,7 @@ buffer_t *tls_client_up(buffer_t *buf, sec_suite_t *tls_suite)
|
|||
if (tls_header_ptr) {
|
||||
if (tls_header_ptr->type == TLS_HANDSHAKE && (tls_heap != 0)) {
|
||||
tr_debug("Type:Handshake");
|
||||
if ((tls_suite->state == TLS_CHANGE_CHIPHER)) {
|
||||
if (tls_suite->state == TLS_CHANGE_CHIPHER) {
|
||||
if (tls_header_ptr->length < 32) {
|
||||
tr_debug("Too short Chiher Text");
|
||||
} else if ((algo_ok & 0x20) && (tls_suite->state == PRF_CALC)) {
|
||||
|
@ -1477,7 +1477,7 @@ buffer_t *tls_server_up(buffer_t *buf, sec_suite_t *tls_suite)
|
|||
if (tls_header_ptr) {
|
||||
if (tls_header_ptr->type == TLS_HANDSHAKE && (tls_heap != 0)) {
|
||||
tr_debug("Type:Handshake");
|
||||
if ((tls_suite->state == TLS_CHANGE_CHIPHER)) {
|
||||
if (tls_suite->state == TLS_CHANGE_CHIPHER) {
|
||||
if (tls_header_ptr->length < 32) {
|
||||
tr_debug("Too short Chiher Text");
|
||||
} else if ((algo_ok & 0x20) && (tls_suite->state == PRF_CALC)) {
|
||||
|
|
|
@ -274,5 +274,25 @@ uint16_t eapol_pdu_key_frame_init(eapol_pdu_t *eapol_pdu, uint16_t data_length,
|
|||
|
||||
}
|
||||
|
||||
uint8_t eapol_pdu_key_mask_get(eapol_pdu_t *eapol_pdu)
|
||||
{
|
||||
uint8_t key_mask = 0;
|
||||
|
||||
if (eapol_pdu->msg.key.key_information.install) {
|
||||
key_mask |= KEY_INFO_INSTALL;
|
||||
}
|
||||
if (eapol_pdu->msg.key.key_information.key_ack) {
|
||||
key_mask |= KEY_INFO_KEY_ACK;
|
||||
}
|
||||
if (eapol_pdu->msg.key.key_information.key_mic) {
|
||||
key_mask |= KEY_INFO_KEY_MIC;
|
||||
}
|
||||
if (eapol_pdu->msg.key.key_information.secured_key_frame) {
|
||||
key_mask |= KEY_INFO_SECURED_KEY_FRAME;
|
||||
}
|
||||
|
||||
return key_mask;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
@ -18,15 +18,16 @@
|
|||
#ifndef EAPOL_HELPER_H_
|
||||
#define EAPOL_HELPER_H_
|
||||
|
||||
#define EAPOL_PROTOCOL_VERSION 3
|
||||
#define EAPOL_EAP_TYPE 0
|
||||
#define EAPOL_KEY_TYPE 3
|
||||
#define EAPOL_KEY_NONCE_LEN 32
|
||||
#define EAPOL_KEY_MIC_LEN 16
|
||||
#define EAPOL_PROTOCOL_VERSION 3
|
||||
#define EAPOL_EAP_TYPE 0
|
||||
#define EAPOL_KEY_TYPE 3
|
||||
#define EAPOL_KEY_NONCE_LEN 32
|
||||
#define EAPOL_KEY_MIC_LEN 16
|
||||
#define EAPOL_KEY_LEN 16
|
||||
|
||||
#define EAPOL_BASE_LENGTH 4 //Protocol version 1 byte, Packet type 1 byte, packet length 2 byte
|
||||
#define EAPOL_BASE_LENGTH 4 //Protocol version 1 byte, Packet type 1 byte, packet length 2 byte
|
||||
|
||||
#define EAPOL_KEY_FRAME_BASE_SIZE 95
|
||||
#define EAPOL_KEY_FRAME_BASE_SIZE 95
|
||||
|
||||
struct eap_header_t;
|
||||
|
||||
|
@ -96,4 +97,18 @@ uint16_t eapol_pdu_key_frame_init(eapol_pdu_t *eapol_pdu, uint16_t data_length,
|
|||
|
||||
void eapol_write_key_packet_mic(uint8_t *eapol_pdu, uint8_t *mic);
|
||||
|
||||
#define KEY_INFO_INSTALL 0x01
|
||||
#define KEY_INFO_KEY_ACK 0x02
|
||||
#define KEY_INFO_KEY_MIC 0x04
|
||||
#define KEY_INFO_SECURED_KEY_FRAME 0x08
|
||||
|
||||
/**
|
||||
* eapol_pdu_key_mask_get gets masked EAPOL-Key message bits
|
||||
*
|
||||
* \param eapol_pdu EAPOL PDU
|
||||
*
|
||||
* \return mask
|
||||
*/
|
||||
uint8_t eapol_pdu_key_mask_get(eapol_pdu_t *eapol_pdu);
|
||||
|
||||
#endif /* EAPOL_HELPER_H_ */
|
||||
|
|
|
@ -37,23 +37,24 @@
|
|||
#define TRACE_GROUP "kmap"
|
||||
|
||||
struct kmp_api_s {
|
||||
void *app_data_ptr; /**< Opaque pointer for application data */
|
||||
kmp_api_create_confirm *create_conf; /**< KMP-CREATE.confirm callback */
|
||||
kmp_api_create_indication *create_ind; /**< KMP-CREATE.indication callback */
|
||||
kmp_api_finished_indication *finished_ind; /**< KMP-FINISHED.indication callback */
|
||||
kmp_api_finished *finished; /**< Finished i.e. ready to be deleted callback */
|
||||
kmp_type_e type; /**< KMP type */
|
||||
kmp_addr_t *addr; /**< Supplicant EUI-64, Relay IP address, Relay port */
|
||||
kmp_service_t *service; /**< KMP service */
|
||||
bool timer_start_pending; /**< Timer is pending to start */
|
||||
sec_prot_t sec_prot; /**< Security protocol interface */
|
||||
void *app_data_ptr; /**< Opaque pointer for application data */
|
||||
kmp_api_create_confirm *create_conf; /**< KMP-CREATE.confirm callback */
|
||||
kmp_api_create_indication *create_ind; /**< KMP-CREATE.indication callback */
|
||||
kmp_api_finished_indication *finished_ind; /**< KMP-FINISHED.indication callback */
|
||||
kmp_api_finished *finished; /**< Finished i.e. ready to be deleted callback */
|
||||
kmp_type_e type; /**< KMP type */
|
||||
kmp_addr_t *addr; /**< Supplicant EUI-64, Relay IP address, Relay port */
|
||||
kmp_service_t *service; /**< KMP service */
|
||||
bool timer_start_pending : 1; /**< Timer is pending to start */
|
||||
bool receive_disable : 1; /**< Receiving disabled, do not route messages anymore */
|
||||
sec_prot_t sec_prot; /**< Security protocol interface */
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
kmp_type_e type; /**< Security protocol type callback */
|
||||
kmp_sec_prot_size *size; /**< Security protocol data size callback */
|
||||
kmp_sec_prot_init *init; /**< Security protocol init */
|
||||
ns_list_link_t link; /**< Link */
|
||||
kmp_type_e type; /**< Security protocol type callback */
|
||||
kmp_sec_prot_size *size; /**< Security protocol data size callback */
|
||||
kmp_sec_prot_init *init; /**< Security protocol init */
|
||||
ns_list_link_t link; /**< Link */
|
||||
} kmp_sec_prot_entry_t;
|
||||
|
||||
typedef NS_LIST_HEAD(kmp_sec_prot_entry_t, link) kmp_sec_prot_list_t;
|
||||
|
@ -88,6 +89,7 @@ static void kmp_sec_prot_timer_stop(sec_prot_t *prot);
|
|||
static void kmp_sec_prot_state_machine_call(sec_prot_t *prot);
|
||||
static void kmp_sec_prot_eui64_addr_get(sec_prot_t *prot, uint8_t *local_eui64, uint8_t *remote_eui64);
|
||||
static sec_prot_t *kmp_sec_prot_by_type_get(sec_prot_t *prot, uint8_t type);
|
||||
static void kmp_sec_prot_receive_disable(sec_prot_t *prot);
|
||||
|
||||
#define kmp_api_get_from_prot(prot) (kmp_api_t *)(((uint8_t *)prot) - offsetof(kmp_api_t, sec_prot));
|
||||
|
||||
|
@ -126,6 +128,7 @@ kmp_api_t *kmp_api_create(kmp_service_t *service, kmp_type_e type)
|
|||
kmp->addr = 0;
|
||||
kmp->service = service;
|
||||
kmp->timer_start_pending = false;
|
||||
kmp->receive_disable = false;
|
||||
|
||||
memset(&kmp->sec_prot, 0, sec_size);
|
||||
|
||||
|
@ -140,6 +143,7 @@ kmp_api_t *kmp_api_create(kmp_service_t *service, kmp_type_e type)
|
|||
kmp->sec_prot.state_machine_call = kmp_sec_prot_state_machine_call;
|
||||
kmp->sec_prot.addr_get = kmp_sec_prot_eui64_addr_get;
|
||||
kmp->sec_prot.type_get = kmp_sec_prot_by_type_get;
|
||||
kmp->sec_prot.receive_disable = kmp_sec_prot_receive_disable;
|
||||
|
||||
if (sec_prot->init(&kmp->sec_prot) < 0) {
|
||||
ns_dyn_mem_free(kmp);
|
||||
|
@ -279,6 +283,12 @@ static sec_prot_t *kmp_sec_prot_by_type_get(sec_prot_t *prot, uint8_t type)
|
|||
return &kmp_by_type->sec_prot;
|
||||
}
|
||||
|
||||
static void kmp_sec_prot_receive_disable(sec_prot_t *prot)
|
||||
{
|
||||
kmp_api_t *kmp = kmp_api_get_from_prot(prot);
|
||||
kmp->receive_disable = true;
|
||||
}
|
||||
|
||||
void kmp_api_delete(kmp_api_t *kmp)
|
||||
{
|
||||
if (kmp->sec_prot.delete) {
|
||||
|
@ -312,9 +322,9 @@ kmp_type_e kmp_api_type_from_id_get(uint8_t kmp_id)
|
|||
case IEEE_802_11_4WH:
|
||||
return IEEE_802_11_4WH;
|
||||
case IEEE_802_11_GKH:
|
||||
return IEEE_802_1X_MKA;
|
||||
return IEEE_802_11_GKH;
|
||||
default:
|
||||
return INVALID_KMP_TYPE;
|
||||
return KMP_TYPE_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -426,6 +436,11 @@ int8_t kmp_service_msg_if_receive(kmp_service_t *service, kmp_type_e type, const
|
|||
return -1;
|
||||
}
|
||||
|
||||
// Security protocol has disables message receiving
|
||||
if (kmp->receive_disable) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int8_t ret = kmp->sec_prot.receive(&kmp->sec_prot, pdu, size);
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
*/
|
||||
|
||||
typedef enum {
|
||||
INVALID_KMP_TYPE = 0,
|
||||
KMP_TYPE_NONE = 0,
|
||||
|
||||
IEEE_802_1X_MKA = 1,
|
||||
IEEE_802_11_4WH = 6,
|
||||
|
|
|
@ -151,7 +151,7 @@ int8_t kmp_eapol_pdu_if_receive(protocol_interface_info_entry_t *interface_ptr,
|
|||
void *data_pdu = &eapol_kmp_pdu->kmp_data;
|
||||
|
||||
kmp_type_e type = kmp_api_type_from_id_get(eapol_kmp_pdu->kmp_id);
|
||||
if (type == INVALID_KMP_TYPE) {
|
||||
if (type == KMP_TYPE_NONE) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
|
|
@ -180,7 +180,7 @@ static void kmp_socket_if_socket_cb(void *ptr)
|
|||
data_ptr += 8;
|
||||
|
||||
kmp_type_e type = kmp_api_type_from_id_get(*data_ptr++);
|
||||
if (type == INVALID_KMP_TYPE) {
|
||||
if (type == KMP_TYPE_NONE) {
|
||||
ns_dyn_mem_free(pdu);
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -60,6 +60,7 @@ typedef struct {
|
|||
tls_data_t tls_send; /**< EAP-TLS send buffer */
|
||||
tls_data_t tls_recv; /**< EAP-TLS receive buffer */
|
||||
uint8_t eap_id_seq; /**< EAP sequence */
|
||||
uint8_t recv_eap_id_seq; /**< Last received EAP sequence */
|
||||
uint8_t eap_code; /**< Received EAP code */
|
||||
uint8_t eap_type; /**< Received EAP type */
|
||||
int8_t tls_result; /**< Result of TLS operation */
|
||||
|
@ -72,7 +73,7 @@ static const trickle_params_t eap_tls_trickle_params = {
|
|||
.Imin = 200, /* 20s; ticks are 100ms */
|
||||
.Imax = 450, /* 45s */
|
||||
.k = 0, /* infinity - no consistency checking */
|
||||
.TimerExpirations = 4
|
||||
.TimerExpirations = 2
|
||||
};
|
||||
|
||||
static uint16_t auth_eap_tls_sec_prot_size(void);
|
||||
|
@ -129,6 +130,7 @@ static int8_t auth_eap_tls_sec_prot_init(sec_prot_t *prot)
|
|||
|
||||
data->tls_prot = NULL;
|
||||
data->eap_id_seq = 0;
|
||||
data->recv_eap_id_seq = 0;
|
||||
data->eap_code = 0;
|
||||
data->eap_type = 0;
|
||||
eap_tls_sec_prot_lib_message_init(&data->tls_recv);
|
||||
|
@ -188,21 +190,32 @@ static int8_t auth_eap_tls_sec_prot_message_handle(sec_prot_t *prot)
|
|||
uint16_t length = data->recv_eapol_pdu.msg.eap.length;
|
||||
|
||||
bool new_seq_id = false;
|
||||
// Confirmation that supplicant has received the message, proceed with protocol
|
||||
if (data->recv_eapol_pdu.msg.eap.id_seq == data->eap_id_seq) {
|
||||
bool old_seq_id = false;
|
||||
|
||||
// Already received sequence ID is received again, ignore
|
||||
if (data->recv_eapol_pdu.msg.eap.id_seq < data->eap_id_seq) {
|
||||
old_seq_id = true;
|
||||
} else if (data->recv_eapol_pdu.msg.eap.id_seq == data->eap_id_seq) {
|
||||
// Confirmation that supplicant has received the message, proceed with protocol
|
||||
data->recv_eap_id_seq = data->recv_eapol_pdu.msg.eap.id_seq;
|
||||
data->eap_id_seq++;
|
||||
new_seq_id = true;
|
||||
}
|
||||
|
||||
tr_debug("recv EAP %s type %s id %i flags %x len %i", eap_msg_trace[data->eap_code - 1],
|
||||
data->eap_type == EAP_IDENTITY ? "IDENTITY" : "TLS", data->recv_eapol_pdu.msg.eap.id_seq,
|
||||
length >= 6 ? data_ptr[0] : 0, length);
|
||||
tr_info("EAP-TLS: recv %s type %s id %i flags %x len %i, eui-64 %s", eap_msg_trace[data->eap_code - 1],
|
||||
data->eap_type == EAP_IDENTITY ? "IDENTITY" : "TLS", data->recv_eapol_pdu.msg.eap.id_seq,
|
||||
length >= 6 ? data_ptr[0] : 0, length, trace_array(sec_prot_remote_eui_64_addr_get(prot), 8));
|
||||
|
||||
if (old_seq_id) {
|
||||
return EAP_TLS_MSG_DECODE_ERROR;
|
||||
}
|
||||
|
||||
if (data->eap_type == EAP_IDENTITY) {
|
||||
return EAP_TLS_MSG_IDENTITY;
|
||||
}
|
||||
|
||||
if (!data_ptr || length < 6) {
|
||||
tr_error("EAP-TLS: decode error");
|
||||
return EAP_TLS_MSG_DECODE_ERROR;
|
||||
}
|
||||
|
||||
|
@ -226,16 +239,23 @@ static int8_t auth_eap_tls_sec_prot_message_send(sec_prot_t *prot, uint8_t eap_c
|
|||
eap_tls_sec_prot_lib_message_allocate(&data->tls_send, TLS_HEAD_LEN, 0);
|
||||
flags = EAP_TLS_START;
|
||||
}
|
||||
} else if (eap_code != EAP_SUCCESS && eap_code != EAP_FAILURE) {
|
||||
} else if (eap_code == EAP_SUCCESS || eap_code == EAP_FAILURE) {
|
||||
// Send Success and Failure with same identifier as received in EAP Response
|
||||
data->eap_id_seq = data->recv_eap_id_seq;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
|
||||
uint16_t eapol_pdu_size;
|
||||
uint8_t *eapol_decoded_data = eap_tls_sec_prot_lib_message_build(eap_code, eap_type, flags, data->eap_id_seq, prot->header_size, &data->tls_send, &eapol_pdu_size);
|
||||
uint8_t *eapol_decoded_data = eap_tls_sec_prot_lib_message_build(eap_code, eap_type, &flags, data->eap_id_seq, prot->header_size, &data->tls_send, &eapol_pdu_size);
|
||||
if (!eapol_decoded_data) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
tr_info("EAP-TLS: send %s type %s id %i flags %x len %i, eui-64: %s", eap_msg_trace[eap_code - 1],
|
||||
eap_type == EAP_IDENTITY ? "IDENTITY" : "TLS", data->eap_id_seq, flags, eapol_pdu_size,
|
||||
trace_array(sec_prot_remote_eui_64_addr_get(prot), 8));
|
||||
|
||||
if (prot->send(prot, eapol_decoded_data, eapol_pdu_size + prot->header_size) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
@ -267,10 +287,13 @@ static void auth_eap_tls_sec_prot_tls_finished_indication(sec_prot_t *tls_prot,
|
|||
|
||||
if (result == SEC_RESULT_OK) {
|
||||
data->tls_result = EAP_TLS_RESULT_HANDSHAKE_OVER;
|
||||
tr_info("EAP-TLS: handshake success");
|
||||
} else if (result == SEC_RESULT_CONF_ERROR) {
|
||||
data->tls_result = EAP_TLS_RESULT_HANDSHAKE_FATAL_ERROR;
|
||||
tr_error("EAP-TLS: handshake fatal error");
|
||||
} else {
|
||||
data->tls_result = EAP_TLS_RESULT_HANDSHAKE_FAILED;
|
||||
tr_error("EAP-TLS: handshake failed");
|
||||
}
|
||||
|
||||
data->tls_ongoing = false;
|
||||
|
@ -328,12 +351,7 @@ static void auth_eap_tls_sec_prot_init_tls(sec_prot_t *prot)
|
|||
|
||||
static void auth_eap_tls_sec_prot_delete_tls(sec_prot_t *prot)
|
||||
{
|
||||
eap_tls_sec_prot_int_t *data = eap_tls_sec_prot_get(prot);
|
||||
// If initialized, TLS terminates on its own
|
||||
if (data->tls_prot) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Triggers TLS to terminate if it is not already terminating by its own
|
||||
sec_prot_t *tls_prot = prot->type_get(prot, SEC_PROT_TYPE_TLS);
|
||||
if (tls_prot) {
|
||||
tls_prot->finished_send(tls_prot);
|
||||
|
@ -353,7 +371,7 @@ static void auth_eap_tls_sec_prot_state_machine(sec_prot_t *prot)
|
|||
|
||||
// Wait KMP-CREATE.request
|
||||
case EAP_TLS_STATE_CREATE_REQ:
|
||||
tr_debug("EAP-TLS start");
|
||||
tr_info("EAP-TLS start, eui-64: %s", trace_array(sec_prot_remote_eui_64_addr_get(prot), 8));
|
||||
|
||||
prot->timer_start(prot);
|
||||
|
||||
|
@ -387,9 +405,6 @@ static void auth_eap_tls_sec_prot_state_machine(sec_prot_t *prot)
|
|||
return;
|
||||
}
|
||||
|
||||
// Increment sequence ID
|
||||
//auth_eap_tls_sec_prot_seq_id_update(prot);
|
||||
|
||||
// Sends EAP request, TLS EAP start
|
||||
auth_eap_tls_sec_prot_message_send(prot, EAP_REQ, EAP_TLS, EAP_TLS_EXCHANGE_START);
|
||||
|
||||
|
@ -477,6 +492,8 @@ static void auth_eap_tls_sec_prot_state_machine(sec_prot_t *prot)
|
|||
} else {
|
||||
// TLS done, indicate success to peer
|
||||
if (data->tls_result == EAP_TLS_RESULT_HANDSHAKE_OVER) {
|
||||
// Supplicant PMK is now valid
|
||||
sec_prot_keys_pmk_mismatch_reset(prot->sec_keys);
|
||||
// Sends EAP success
|
||||
auth_eap_tls_sec_prot_message_send(prot, EAP_SUCCESS, 0, EAP_TLS_EXCHANGE_NONE);
|
||||
} else {
|
||||
|
@ -491,13 +508,12 @@ static void auth_eap_tls_sec_prot_state_machine(sec_prot_t *prot)
|
|||
break;
|
||||
|
||||
case EAP_TLS_STATE_FINISH:
|
||||
tr_debug("EAP-TLS finish");
|
||||
tr_info("EAP-TLS finish, eui-64: %s", trace_array(sec_prot_remote_eui_64_addr_get(prot), 8));
|
||||
|
||||
// KMP-FINISHED.indication,
|
||||
prot->finished_ind(prot, sec_prot_result_get(&data->common), prot->sec_keys);
|
||||
|
||||
sec_prot_state_set(prot, &data->common, EAP_TLS_STATE_FINISHED);
|
||||
data->common.ticks = 10 * 10;
|
||||
break;
|
||||
|
||||
case EAP_TLS_STATE_FINISHED:
|
||||
|
|
|
@ -88,6 +88,7 @@ int8_t eap_tls_sec_prot_lib_message_handle(uint8_t *data, uint16_t length, bool
|
|||
// Handles the length field
|
||||
if (data[0] & EAP_TLS_FRAGMENT_LENGTH) {
|
||||
if (length < 5) {
|
||||
tr_error("EAP-TLS: decode error");
|
||||
return EAP_TLS_MSG_DECODE_ERROR;
|
||||
}
|
||||
|
||||
|
@ -138,19 +139,16 @@ int8_t eap_tls_sec_prot_lib_message_handle(uint8_t *data, uint16_t length, bool
|
|||
return result;
|
||||
}
|
||||
|
||||
uint8_t *eap_tls_sec_prot_lib_message_build(uint8_t eap_code, uint8_t eap_type, uint8_t flags, uint8_t eap_id_seq, uint8_t header_size, tls_data_t *tls_send, uint16_t *length)
|
||||
uint8_t *eap_tls_sec_prot_lib_message_build(uint8_t eap_code, uint8_t eap_type, uint8_t *flags, uint8_t eap_id_seq, uint8_t header_size, tls_data_t *tls_send, uint16_t *length)
|
||||
{
|
||||
uint16_t eap_len = 4;
|
||||
uint8_t *data_ptr = NULL;
|
||||
|
||||
// Write EAP-TLS data (from EAP-TLS flags field onward)
|
||||
if (tls_send->data) {
|
||||
data_ptr = eap_tls_sec_prot_lib_fragment_write(tls_send->data + TLS_HEAD_LEN, tls_send->total_len, tls_send->handled_len, &eap_len, &flags);
|
||||
data_ptr = eap_tls_sec_prot_lib_fragment_write(tls_send->data + TLS_HEAD_LEN, tls_send->total_len, tls_send->handled_len, &eap_len, flags);
|
||||
}
|
||||
|
||||
tr_debug("send EAP %s type %s id %i flags %x len %i", eap_msg_trace[eap_code - 1],
|
||||
eap_type == EAP_IDENTITY ? "IDENTITY" : "TLS", eap_id_seq, flags, eap_len);
|
||||
|
||||
eapol_pdu_t eapol_pdu;
|
||||
|
||||
*length = eapol_pdu_eap_frame_init(&eapol_pdu, eap_code, eap_id_seq, eap_type, eap_len, data_ptr);
|
||||
|
|
|
@ -117,6 +117,6 @@ int8_t eap_tls_sec_prot_lib_message_handle(uint8_t *data, uint16_t length, bool
|
|||
* \return pointer to message to be sent or NULL in case of failure
|
||||
*
|
||||
*/
|
||||
uint8_t *eap_tls_sec_prot_lib_message_build(uint8_t eap_code, uint8_t eap_type, uint8_t flags, uint8_t eap_id_seq, uint8_t header_size, tls_data_t *tls_send, uint16_t *length);
|
||||
uint8_t *eap_tls_sec_prot_lib_message_build(uint8_t eap_code, uint8_t eap_type, uint8_t *flags, uint8_t eap_id_seq, uint8_t header_size, tls_data_t *tls_send, uint16_t *length);
|
||||
|
||||
#endif /* EAP_TLS_SEC_PROT_H_ */
|
||||
|
|
|
@ -53,12 +53,16 @@ typedef enum {
|
|||
EAP_TLS_STATE_FINISHED = SEC_STATE_FINISHED
|
||||
} eap_tls_sec_prot_state_e;
|
||||
|
||||
// Filters EAP re-transmission bursts that arrive with same EAP sequence number
|
||||
#define BURST_FILTER_TIMER_TIMEOUT 5 * 10
|
||||
|
||||
typedef struct {
|
||||
sec_prot_common_t common; /**< Common data */
|
||||
sec_prot_t *tls_prot; /**< TLS security protocol */
|
||||
eapol_pdu_t recv_eapol_pdu; /**< Received EAPOL PDU */
|
||||
tls_data_t tls_send; /**< EAP-TLS send buffer */
|
||||
tls_data_t tls_recv; /**< EAP-TLS receive buffer */
|
||||
uint16_t burst_filt_timer; /**< Burst filter timer */
|
||||
uint8_t eap_id_seq; /**< EAP sequence */
|
||||
uint8_t eap_code; /**< Received EAP code */
|
||||
uint8_t eap_type; /**< Received EAP type */
|
||||
|
@ -72,7 +76,7 @@ static const trickle_params_t eap_tls_trickle_params = {
|
|||
.Imin = 200, /* 20s; ticks are 100ms */
|
||||
.Imax = 450, /* 45s */
|
||||
.k = 0, /* infinity - no consistency checking */
|
||||
.TimerExpirations = 4
|
||||
.TimerExpirations = 2
|
||||
};
|
||||
|
||||
static uint16_t supp_eap_tls_sec_prot_size(void);
|
||||
|
@ -127,6 +131,7 @@ static int8_t supp_eap_tls_sec_prot_init(sec_prot_t *prot)
|
|||
sec_prot_state_set(prot, &data->common, EAP_TLS_STATE_INIT);
|
||||
|
||||
data->tls_prot = NULL;
|
||||
data->burst_filt_timer = 0;
|
||||
data->eap_id_seq = 0;
|
||||
data->eap_code = 0;
|
||||
data->eap_type = 0;
|
||||
|
@ -186,14 +191,29 @@ static int8_t supp_eap_tls_sec_prot_message_handle(sec_prot_t *prot)
|
|||
uint8_t *data_ptr = data->recv_eapol_pdu.msg.eap.data_ptr;
|
||||
uint16_t length = data->recv_eapol_pdu.msg.eap.length;
|
||||
|
||||
uint8_t new_seq_id = false;
|
||||
if (data->recv_eapol_pdu.msg.eap.id_seq > data->eap_id_seq) {
|
||||
new_seq_id = true;
|
||||
}
|
||||
tr_info("EAP-TLS recv %s type %s id %i flags %x len %i", eap_msg_trace[data->eap_code - 1],
|
||||
data->eap_type == EAP_IDENTITY ? "IDENTITY" : "TLS", data->recv_eapol_pdu.msg.eap.id_seq,
|
||||
length >= 6 ? data_ptr[0] : 0, length);
|
||||
|
||||
tr_debug("recv EAP %s type %s id %i flags %x len %i", eap_msg_trace[data->eap_code - 1],
|
||||
data->eap_type == EAP_IDENTITY ? "IDENTITY" : "TLS", data->recv_eapol_pdu.msg.eap.id_seq,
|
||||
length >= 6 ? data_ptr[0] : 0, length);
|
||||
uint8_t new_seq_id = false;
|
||||
// New sequence identifier received
|
||||
if (data->recv_eapol_pdu.msg.eap.id_seq > data->eap_id_seq) {
|
||||
data->burst_filt_timer = BURST_FILTER_TIMER_TIMEOUT;
|
||||
new_seq_id = true;
|
||||
} else if (data->recv_eapol_pdu.msg.eap.id_seq == data->eap_id_seq) {
|
||||
if (data->burst_filt_timer > 0) {
|
||||
/* If retransmission arrives when burst filter timer is running, ignores it
|
||||
and starts timer again */
|
||||
data->burst_filt_timer = BURST_FILTER_TIMER_TIMEOUT;
|
||||
return EAP_TLS_MSG_DECODE_ERROR;
|
||||
} else {
|
||||
// If retransmission arrives after timeout, starts timer again
|
||||
data->burst_filt_timer = BURST_FILTER_TIMER_TIMEOUT;
|
||||
}
|
||||
} else if (data->recv_eapol_pdu.msg.eap.id_seq < data->eap_id_seq) {
|
||||
// Already received sequence ID is received again, ignore
|
||||
return EAP_TLS_MSG_DECODE_ERROR;
|
||||
}
|
||||
|
||||
if (data->eap_type == EAP_IDENTITY) {
|
||||
return EAP_TLS_MSG_IDENTITY;
|
||||
|
@ -233,11 +253,14 @@ static int8_t supp_eap_tls_sec_prot_message_send(sec_prot_t *prot, uint8_t eap_c
|
|||
}
|
||||
|
||||
uint16_t eapol_pdu_size;
|
||||
uint8_t *eapol_decoded_data = eap_tls_sec_prot_lib_message_build(eap_code, eap_type, flags, data->eap_id_seq, prot->header_size, &data->tls_send, &eapol_pdu_size);
|
||||
uint8_t *eapol_decoded_data = eap_tls_sec_prot_lib_message_build(eap_code, eap_type, &flags, data->eap_id_seq, prot->header_size, &data->tls_send, &eapol_pdu_size);
|
||||
if (!eapol_decoded_data) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
tr_info("EAP-TLS: send %s type %s id %i flags %x len %i", eap_msg_trace[eap_code - 1],
|
||||
eap_type == EAP_IDENTITY ? "IDENTITY" : "TLS", data->eap_id_seq, flags, eapol_pdu_size);
|
||||
|
||||
if (prot->send(prot, eapol_decoded_data, eapol_pdu_size + prot->header_size) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
@ -248,6 +271,13 @@ static int8_t supp_eap_tls_sec_prot_message_send(sec_prot_t *prot, uint8_t eap_c
|
|||
static void supp_eap_tls_sec_prot_timer_timeout(sec_prot_t *prot, uint16_t ticks)
|
||||
{
|
||||
eap_tls_sec_prot_int_t *data = eap_tls_sec_prot_get(prot);
|
||||
|
||||
if (data->burst_filt_timer > ticks) {
|
||||
data->burst_filt_timer -= ticks;
|
||||
} else {
|
||||
data->burst_filt_timer = 0;
|
||||
}
|
||||
|
||||
sec_prot_timer_timeout_handle(prot, &data->common, &eap_tls_trickle_params, ticks);
|
||||
}
|
||||
|
||||
|
@ -278,11 +308,14 @@ static void supp_eap_tls_sec_prot_tls_finished_indication(sec_prot_t *tls_prot,
|
|||
|
||||
if (result == SEC_RESULT_OK) {
|
||||
data->tls_result = EAP_TLS_RESULT_HANDSHAKE_OVER;
|
||||
tr_info("EAP-TLS: handshake success");
|
||||
} else if (result == SEC_RESULT_CONF_ERROR) {
|
||||
data->tls_result = EAP_TLS_RESULT_HANDSHAKE_FATAL_ERROR;
|
||||
tr_error("EAP-TLS: handshake fatal error");
|
||||
} else {
|
||||
// On failure has sent ALERT
|
||||
data->tls_result = EAP_TLS_RESULT_HANDSHAKE_FAILED;
|
||||
tr_error("EAP-TLS: handshake failed");
|
||||
}
|
||||
|
||||
data->tls_ongoing = false;
|
||||
|
@ -340,12 +373,7 @@ static void supp_eap_tls_sec_prot_init_tls(sec_prot_t *prot)
|
|||
|
||||
static void supp_eap_tls_sec_prot_delete_tls(sec_prot_t *prot)
|
||||
{
|
||||
eap_tls_sec_prot_int_t *data = eap_tls_sec_prot_get(prot);
|
||||
// If initialized, TLS terminates on its own
|
||||
if (data->tls_prot) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Triggers TLS to terminate if it is not already terminating by its own
|
||||
sec_prot_t *tls_prot = prot->type_get(prot, SEC_PROT_TYPE_TLS);
|
||||
if (tls_prot) {
|
||||
tls_prot->finished_send(tls_prot);
|
||||
|
@ -374,7 +402,7 @@ static void supp_eap_tls_sec_prot_state_machine(sec_prot_t *prot)
|
|||
// Store sequence ID
|
||||
supp_eap_tls_sec_prot_seq_id_update(prot);
|
||||
|
||||
tr_debug("EAP-TLS start");
|
||||
tr_info("EAP-TLS start");
|
||||
|
||||
prot->timer_start(prot);
|
||||
|
||||
|
@ -402,8 +430,8 @@ static void supp_eap_tls_sec_prot_state_machine(sec_prot_t *prot)
|
|||
case EAP_TLS_STATE_REQUEST_TLS_EAP:
|
||||
// On timeout
|
||||
if (sec_prot_result_timeout_check(&data->common)) {
|
||||
// Re-send EAP response, Identity
|
||||
supp_eap_tls_sec_prot_message_send(prot, EAP_RESPONSE, EAP_IDENTITY, EAP_TLS_EXCHANGE_NONE);
|
||||
/* Waits for next trickle expire. If trickle expirations reach the limit,
|
||||
terminates EAP-TLS */
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -435,8 +463,8 @@ static void supp_eap_tls_sec_prot_state_machine(sec_prot_t *prot)
|
|||
case EAP_TLS_STATE_REQUEST:
|
||||
// On timeout
|
||||
if (sec_prot_result_timeout_check(&data->common)) {
|
||||
// Re-send EAP response
|
||||
supp_eap_tls_sec_prot_message_send(prot, EAP_RESPONSE, EAP_TLS, EAP_TLS_EXCHANGE_ONGOING);
|
||||
/* Waits for next trickle expire. If trickle expirations reach the limit,
|
||||
terminates EAP-TLS */
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -488,7 +516,7 @@ static void supp_eap_tls_sec_prot_state_machine(sec_prot_t *prot)
|
|||
break;
|
||||
|
||||
case EAP_TLS_STATE_FINISH:
|
||||
tr_debug("EAP-TLS finish");
|
||||
tr_info("EAP-TLS finish");
|
||||
|
||||
// KMP-FINISHED.indication,
|
||||
prot->finished_ind(prot, sec_prot_result_get(&data->common), prot->sec_keys);
|
||||
|
|
|
@ -155,12 +155,18 @@ static int8_t auth_fwh_sec_prot_receive(sec_prot_t *prot, void *pdu, uint16_t si
|
|||
// Get message
|
||||
data->recv_msg = auth_fwh_sec_prot_message_get(&data->recv_eapol_pdu, prot->sec_keys);
|
||||
if (data->recv_msg != FWH_MESSAGE_UNKNOWN) {
|
||||
tr_info("4WH: recv %s, eui-64: %s", data->recv_msg == FWH_MESSAGE_2 ? "Message 2" : "Message 4", trace_array(sec_prot_remote_eui_64_addr_get(prot), 8));
|
||||
|
||||
// Call state machine
|
||||
data->recv_pdu = pdu;
|
||||
data->recv_size = size;
|
||||
prot->state_machine(prot);
|
||||
} else {
|
||||
tr_error("4WH: recv error, eui-64: %s", trace_array(sec_prot_remote_eui_64_addr_get(prot), 8));
|
||||
}
|
||||
ret_val = 0;
|
||||
} else {
|
||||
tr_error("4WH: recv error, eui-64: %s", trace_array(sec_prot_remote_eui_64_addr_get(prot), 8));
|
||||
}
|
||||
|
||||
memset(&data->recv_eapol_pdu, 0, sizeof(eapol_pdu_t));
|
||||
|
@ -180,7 +186,7 @@ static fwh_sec_prot_msg_e auth_fwh_sec_prot_message_get(eapol_pdu_t *eapol_pdu,
|
|||
return FWH_MESSAGE_UNKNOWN;
|
||||
}
|
||||
|
||||
uint8_t key_mask = sec_prot_lib_key_mask_get(eapol_pdu);
|
||||
uint8_t key_mask = eapol_pdu_key_mask_get(eapol_pdu);
|
||||
|
||||
switch (key_mask) {
|
||||
case KEY_INFO_KEY_MIC:
|
||||
|
@ -191,7 +197,7 @@ static fwh_sec_prot_msg_e auth_fwh_sec_prot_message_get(eapol_pdu_t *eapol_pdu,
|
|||
break;
|
||||
case KEY_INFO_KEY_MIC | KEY_INFO_SECURED_KEY_FRAME:
|
||||
// Only accept message from supplicant with expected replay counter
|
||||
if (eapol_pdu->msg.key.replay_counter == sec_prot_keys_pmk_replay_cnt_get(sec_keys)) {
|
||||
if (eapol_pdu->msg.key.replay_counter == sec_prot_keys_pmk_replay_cnt_get(sec_keys)) {
|
||||
msg = FWH_MESSAGE_4;
|
||||
}
|
||||
break;
|
||||
|
@ -241,14 +247,14 @@ static int8_t auth_fwh_sec_prot_message_send(sec_prot_t *prot, fwh_sec_prot_msg_
|
|||
break;
|
||||
case FWH_MESSAGE_3: {
|
||||
uint8_t gtk_index;
|
||||
uint8_t *gtk = sec_prot_keys_get_gtk_to_insert(prot->sec_keys->gtks, >k_index);
|
||||
uint8_t *gtk = sec_prot_keys_get_gtk_to_insert(prot->sec_keys, >k_index);
|
||||
if (gtk) {
|
||||
kde_end = kde_gtk_write(kde_end, gtk_index, gtk);
|
||||
|
||||
uint32_t gtk_lifetime = sec_prot_keys_gtk_lifetime_get(prot->sec_keys->gtks, gtk_index);
|
||||
kde_end = kde_lifetime_write(kde_end, gtk_lifetime);
|
||||
}
|
||||
uint8_t gtkl = sec_prot_keys_gtkl_get(prot->sec_keys->gtks);
|
||||
uint8_t gtkl = sec_prot_keys_fresh_gtkl_get(prot->sec_keys->gtks);
|
||||
kde_end = kde_gtkl_write(kde_end, gtkl);
|
||||
kde_padding_write(kde_end, kde_start + kde_len);
|
||||
}
|
||||
|
@ -267,7 +273,7 @@ static int8_t auth_fwh_sec_prot_message_send(sec_prot_t *prot, fwh_sec_prot_msg_
|
|||
sec_prot_keys_pmk_replay_cnt_increment(prot->sec_keys);
|
||||
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 = 32;
|
||||
eapol_pdu.msg.key.key_length = EAPOL_KEY_LEN;
|
||||
eapol_pdu.msg.key.key_nonce = data->nonce;
|
||||
break;
|
||||
case FWH_MESSAGE_3:
|
||||
|
@ -279,7 +285,7 @@ static int8_t auth_fwh_sec_prot_message_send(sec_prot_t *prot, fwh_sec_prot_msg_
|
|||
eapol_pdu.msg.key.key_information.secured_key_frame = true;
|
||||
eapol_pdu.msg.key.key_information.encrypted_key_data = true;
|
||||
eapol_pdu.msg.key.key_nonce = data->nonce;
|
||||
eapol_pdu.msg.key.key_length = 32;
|
||||
eapol_pdu.msg.key.key_length = EAPOL_KEY_LEN;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
@ -293,6 +299,8 @@ static int8_t auth_fwh_sec_prot_message_send(sec_prot_t *prot, fwh_sec_prot_msg_
|
|||
return -1;
|
||||
}
|
||||
|
||||
tr_info("4WH: send %s, eui-64: %s", msg == FWH_MESSAGE_1 ? "Message 1" : "Message 3", trace_array(sec_prot_remote_eui_64_addr_get(prot), 8));
|
||||
|
||||
if (prot->send(prot, eapol_pdu_frame, eapol_pdu_size + prot->header_size) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
@ -319,7 +327,7 @@ static void auth_fwh_sec_prot_state_machine(sec_prot_t *prot)
|
|||
|
||||
// Wait KMP-CREATE.request
|
||||
case FWH_STATE_CREATE_REQ:
|
||||
tr_debug("4WH start");
|
||||
tr_info("4WH: start, eui-64: %s", trace_array(sec_prot_remote_eui_64_addr_get(prot), 8));
|
||||
|
||||
uint8_t *pmk = sec_prot_keys_pmk_get(prot->sec_keys);
|
||||
if (!pmk) { // If PMK is not set fails
|
||||
|
@ -383,13 +391,18 @@ static void auth_fwh_sec_prot_state_machine(sec_prot_t *prot)
|
|||
return;
|
||||
}
|
||||
|
||||
// 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_state_set(prot, &data->common, FWH_STATE_FINISH);
|
||||
}
|
||||
break;
|
||||
|
||||
case FWH_STATE_FINISH:
|
||||
tr_debug("4WH finish");
|
||||
tr_info("4WH: finish, eui-64: %s", trace_array(sec_prot_remote_eui_64_addr_get(prot), 8));
|
||||
|
||||
// KMP-FINISHED.indication,
|
||||
prot->finished_ind(prot, sec_prot_result_get(&data->common), 0);
|
||||
|
@ -417,6 +430,7 @@ static int8_t auth_fwh_sec_prot_ptk_generate(sec_prot_t *prot, sec_prot_keys_t *
|
|||
|
||||
uint8_t *remote_nonce = data->recv_eapol_pdu.msg.key.key_nonce;
|
||||
if (!remote_nonce) {
|
||||
tr_error("SNonce invalid");
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
|
|
@ -47,6 +47,7 @@ typedef enum {
|
|||
FWH_STATE_CREATE_IND = SEC_STATE_CREATE_IND,
|
||||
FWH_STATE_MESSAGE_1 = SEC_STATE_FIRST,
|
||||
FWH_STATE_MESSAGE_3,
|
||||
FWH_STATE_MESSAGE_3_RETRY_WAIT,
|
||||
FWH_STATE_CREATE_RESP_SUPP_RETRY,
|
||||
FWH_STATE_FINISH = SEC_STATE_FINISH,
|
||||
FWH_STATE_FINISHED = SEC_STATE_FINISHED
|
||||
|
@ -76,22 +77,18 @@ typedef struct {
|
|||
void *recv_pdu; /**< received pdu */
|
||||
uint16_t recv_size; /**< received pdu size */
|
||||
uint64_t recv_replay_cnt; /**< received replay counter */
|
||||
bool msg3_received : 1; /**< Valid Message 3 has been received */
|
||||
bool msg3_retry_wait : 1; /**< Waiting for Message 3 retry */
|
||||
bool recv_replay_cnt_set : 1; /**< received replay counter set */
|
||||
} fwh_sec_prot_int_t;
|
||||
|
||||
static const trickle_params_t fwh_trickle_params = {
|
||||
.Imin = 50, /* 5000ms; ticks are 100ms */
|
||||
.Imax = 150, /* 15000ms */
|
||||
.k = 0, /* infinity - no consistency checking */
|
||||
.TimerExpirations = 4
|
||||
};
|
||||
|
||||
static uint16_t supp_fwh_sec_prot_size(void);
|
||||
static int8_t supp_fwh_sec_prot_init(sec_prot_t *prot);
|
||||
|
||||
static void supp_fwh_sec_prot_create_response(sec_prot_t *prot, sec_prot_result_e result);
|
||||
static void supp_fwh_sec_prot_delete(sec_prot_t *prot);
|
||||
static int8_t supp_fwh_sec_prot_receive(sec_prot_t *prot, void *pdu, uint16_t size);
|
||||
static fwh_sec_prot_msg_e supp_fwh_sec_prot_message_get(eapol_pdu_t *eapol_pdu, sec_prot_keys_t *sec_keys);
|
||||
static fwh_sec_prot_msg_e supp_fwh_sec_prot_message_get(sec_prot_t *prot, eapol_pdu_t *eapol_pdu);
|
||||
static void supp_fwh_sec_prot_state_machine(sec_prot_t *prot);
|
||||
|
||||
static int8_t supp_fwh_sec_prot_message_send(sec_prot_t *prot, fwh_sec_prot_msg_e msg);
|
||||
|
@ -101,6 +98,7 @@ static int8_t supp_fwh_sec_prot_ptk_generate(sec_prot_t *prot, sec_prot_keys_t *
|
|||
static int8_t supp_fwh_sec_prot_mic_validate(sec_prot_t *prot);
|
||||
|
||||
static void supp_fwh_sec_prot_recv_replay_counter_store(sec_prot_t *prot);
|
||||
static bool supp_fwh_sec_prot_recv_replay_cnt_compare(uint64_t received_counter, sec_prot_t *prot);
|
||||
static void supp_fwh_sec_prot_anonce_store(sec_prot_t *prot);
|
||||
static int8_t supp_fwh_sec_prot_anonce_validate(sec_prot_t *prot);
|
||||
static void supp_fwh_sec_prot_security_replay_counter_update(sec_prot_t *prot);
|
||||
|
@ -141,6 +139,10 @@ static int8_t supp_fwh_sec_prot_init(sec_prot_t *prot)
|
|||
sec_prot_state_set(prot, &data->common, FWH_STATE_INIT);
|
||||
|
||||
data->common.ticks = 30 * 10; // 30 seconds
|
||||
data->msg3_received = false;
|
||||
data->msg3_retry_wait = false;
|
||||
data->recv_replay_cnt = 0;
|
||||
data->recv_replay_cnt_set = false;
|
||||
|
||||
uint8_t eui64[8] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08};
|
||||
sec_prot_lib_nonce_init(data->snonce, eui64, 1000);
|
||||
|
@ -171,14 +173,20 @@ static int8_t supp_fwh_sec_prot_receive(sec_prot_t *prot, void *pdu, uint16_t si
|
|||
// Decoding is successful
|
||||
if (eapol_parse_pdu_header(pdu, size, &data->recv_eapol_pdu)) {
|
||||
// Get message
|
||||
data->recv_msg = supp_fwh_sec_prot_message_get(&data->recv_eapol_pdu, prot->sec_keys);
|
||||
data->recv_msg = supp_fwh_sec_prot_message_get(prot, &data->recv_eapol_pdu);
|
||||
if (data->recv_msg != FWH_MESSAGE_UNKNOWN) {
|
||||
tr_info("4WH: recv %s", data->recv_msg == FWH_MESSAGE_1 ? "Message 1" : "Message 3");
|
||||
|
||||
// Call state machine
|
||||
data->recv_pdu = pdu;
|
||||
data->recv_size = size;
|
||||
prot->state_machine(prot);
|
||||
} else {
|
||||
tr_error("4WH: recv error");
|
||||
}
|
||||
ret_val = 0;
|
||||
} else {
|
||||
tr_error("4WH: recv error");
|
||||
}
|
||||
|
||||
memset(&data->recv_eapol_pdu, 0, sizeof(eapol_pdu_t));
|
||||
|
@ -189,7 +197,7 @@ static int8_t supp_fwh_sec_prot_receive(sec_prot_t *prot, void *pdu, uint16_t si
|
|||
return ret_val;
|
||||
}
|
||||
|
||||
static fwh_sec_prot_msg_e supp_fwh_sec_prot_message_get(eapol_pdu_t *eapol_pdu, sec_prot_keys_t *sec_keys)
|
||||
static fwh_sec_prot_msg_e supp_fwh_sec_prot_message_get(sec_prot_t *prot, eapol_pdu_t *eapol_pdu)
|
||||
{
|
||||
fwh_sec_prot_msg_e msg = FWH_MESSAGE_UNKNOWN;
|
||||
|
||||
|
@ -198,23 +206,33 @@ static fwh_sec_prot_msg_e supp_fwh_sec_prot_message_get(eapol_pdu_t *eapol_pdu,
|
|||
return FWH_MESSAGE_UNKNOWN;
|
||||
}
|
||||
|
||||
uint8_t key_mask = sec_prot_lib_key_mask_get(eapol_pdu);
|
||||
uint8_t key_mask = eapol_pdu_key_mask_get(eapol_pdu);
|
||||
|
||||
switch (key_mask) {
|
||||
// Message 1
|
||||
case KEY_INFO_KEY_ACK:
|
||||
// Must have valid replay counter
|
||||
if (eapol_pdu->msg.key.replay_counter > sec_prot_keys_pmk_replay_cnt_get(sec_keys)) {
|
||||
/* Must have valid replay counter, both larger for PMK and larger that is used on
|
||||
* the four way handshake session (note: PMK replay counter is not updated for Message 1
|
||||
* but session specific counter is)
|
||||
*/
|
||||
if (sec_prot_keys_pmk_replay_cnt_compare(eapol_pdu->msg.key.replay_counter, prot->sec_keys) &&
|
||||
supp_fwh_sec_prot_recv_replay_cnt_compare(eapol_pdu->msg.key.replay_counter, prot)) {
|
||||
msg = FWH_MESSAGE_1;
|
||||
} else {
|
||||
tr_error("4WH: invalid replay counter %"PRId64, eapol_pdu->msg.key.replay_counter);
|
||||
}
|
||||
break;
|
||||
// Message 3
|
||||
case KEY_INFO_INSTALL | KEY_INFO_KEY_ACK | KEY_INFO_KEY_MIC | KEY_INFO_SECURED_KEY_FRAME:
|
||||
// Must have valid replay counter
|
||||
if (eapol_pdu->msg.key.replay_counter > sec_prot_keys_pmk_replay_cnt_get(sec_keys)) {
|
||||
if (sec_prot_keys_pmk_replay_cnt_compare(eapol_pdu->msg.key.replay_counter, prot->sec_keys)) {
|
||||
if (eapol_pdu->msg.key.key_information.encrypted_key_data) {
|
||||
// This should include the GTK KDE, Lifetime KDE and GTKL KDE.
|
||||
// At least some of them should be present
|
||||
msg = FWH_MESSAGE_3;
|
||||
}
|
||||
} else {
|
||||
tr_error("4WH: invalid replay counter %"PRId64, eapol_pdu->msg.key.replay_counter);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
@ -256,6 +274,8 @@ static int8_t supp_fwh_sec_prot_message_send(sec_prot_t *prot, fwh_sec_prot_msg_
|
|||
return -1;
|
||||
}
|
||||
|
||||
tr_info("4WH: send %s", msg == FWH_MESSAGE_2 ? "Message 2" : "Message 4");
|
||||
|
||||
if (prot->send(prot, eapol_pdu_frame, eapol_pdu_size + prot->header_size) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
@ -266,7 +286,7 @@ static int8_t supp_fwh_sec_prot_message_send(sec_prot_t *prot, fwh_sec_prot_msg_
|
|||
static void supp_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, &fwh_trickle_params, ticks);
|
||||
sec_prot_timer_timeout_handle(prot, &data->common, NULL, ticks);
|
||||
}
|
||||
|
||||
static void supp_fwh_sec_prot_state_machine(sec_prot_t *prot)
|
||||
|
@ -291,7 +311,7 @@ static void supp_fwh_sec_prot_state_machine(sec_prot_t *prot)
|
|||
return;
|
||||
}
|
||||
|
||||
tr_debug("4WH start");
|
||||
tr_info("4WH: start");
|
||||
|
||||
// Store authenticator nonce for check when 4WH Message 3 is received
|
||||
supp_fwh_sec_prot_anonce_store(prot);
|
||||
|
@ -335,9 +355,13 @@ static void supp_fwh_sec_prot_state_machine(sec_prot_t *prot)
|
|||
if (supp_fwh_sec_prot_ptk_generate(prot, prot->sec_keys) < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
supp_fwh_sec_prot_recv_replay_counter_store(prot);
|
||||
|
||||
// Send 4WH message 2
|
||||
supp_fwh_sec_prot_message_send(prot, FWH_MESSAGE_2);
|
||||
data->common.ticks = 30 * 10; // 30 seconds
|
||||
return;
|
||||
} else if (data->recv_msg != FWH_MESSAGE_3) {
|
||||
return;
|
||||
}
|
||||
|
@ -359,6 +383,7 @@ static void supp_fwh_sec_prot_state_machine(sec_prot_t *prot)
|
|||
|
||||
supp_fwh_sec_prot_recv_replay_counter_store(prot);
|
||||
supp_fwh_sec_prot_security_replay_counter_update(prot);
|
||||
data->msg3_received = true;
|
||||
|
||||
// Sends 4WH Message 4
|
||||
supp_fwh_sec_prot_message_send(prot, FWH_MESSAGE_4);
|
||||
|
@ -367,19 +392,37 @@ static void supp_fwh_sec_prot_state_machine(sec_prot_t *prot)
|
|||
break;
|
||||
|
||||
case FWH_STATE_FINISH:
|
||||
tr_debug("4WH finish");
|
||||
if (data->msg3_retry_wait) {
|
||||
tr_info("4WH: Message 3 retry timeout");
|
||||
sec_prot_state_set(prot, &data->common, FWH_STATE_FINISHED);
|
||||
return;
|
||||
}
|
||||
|
||||
// KMP-FINISHED.indication
|
||||
sec_prot_keys_ptk_write(prot->sec_keys, data->new_ptk);
|
||||
sec_prot_keys_ptk_eui_64_write(prot->sec_keys, data->remote_eui64);
|
||||
prot->finished_ind(prot, sec_prot_result_get(&data->common), prot->sec_keys);
|
||||
sec_prot_state_set(prot, &data->common, FWH_STATE_FINISHED);
|
||||
// If Message 3 has been received updates key data and waits for Message 3 retry
|
||||
if (data->msg3_received) {
|
||||
data->msg3_retry_wait = true;
|
||||
|
||||
tr_info("4WH: finish, wait Message 3 retry");
|
||||
|
||||
sec_prot_keys_ptk_write(prot->sec_keys, data->new_ptk);
|
||||
sec_prot_keys_ptk_eui_64_write(prot->sec_keys, data->remote_eui64);
|
||||
|
||||
data->common.ticks = 60 * 10; // 60 seconds
|
||||
// KMP-FINISHED.indication
|
||||
prot->finished_ind(prot, sec_prot_result_get(&data->common), prot->sec_keys);
|
||||
sec_prot_state_set(prot, &data->common, FWH_STATE_MESSAGE_3_RETRY_WAIT);
|
||||
} else {
|
||||
tr_info("4WH: finish");
|
||||
// KMP-FINISHED.indication
|
||||
prot->finished_ind(prot, sec_prot_result_get(&data->common), prot->sec_keys);
|
||||
sec_prot_state_set(prot, &data->common, FWH_STATE_FINISHED);
|
||||
}
|
||||
break;
|
||||
|
||||
case FWH_STATE_FINISHED:
|
||||
case FWH_STATE_MESSAGE_3_RETRY_WAIT:
|
||||
if (sec_prot_result_timeout_check(&data->common)) {
|
||||
prot->timer_stop(prot);
|
||||
prot->finished(prot);
|
||||
tr_info("4WH: Message 3 retry timeout");
|
||||
sec_prot_state_set(prot, &data->common, FWH_STATE_FINISHED);
|
||||
} else {
|
||||
if (data->recv_msg != FWH_MESSAGE_3) {
|
||||
return;
|
||||
|
@ -403,25 +446,15 @@ static void supp_fwh_sec_prot_state_machine(sec_prot_t *prot)
|
|||
supp_fwh_sec_prot_recv_replay_counter_store(prot);
|
||||
supp_fwh_sec_prot_security_replay_counter_update(prot);
|
||||
|
||||
tr_debug("4WH start again");
|
||||
tr_info("4WH: send Message 4 again");
|
||||
|
||||
// Send KMP-CREATE.indication
|
||||
prot->create_ind(prot);
|
||||
sec_prot_state_set(prot, &data->common, FWH_STATE_CREATE_RESP_SUPP_RETRY);
|
||||
supp_fwh_sec_prot_message_send(prot, FWH_MESSAGE_4);
|
||||
}
|
||||
break;
|
||||
|
||||
// Special case for second receiving of 4WH message 3
|
||||
case FWH_STATE_CREATE_RESP_SUPP_RETRY:
|
||||
if (sec_prot_result_ok_check(&data->common)) {
|
||||
// Send 4WH message 4
|
||||
supp_fwh_sec_prot_message_send(prot, FWH_MESSAGE_4);
|
||||
data->common.ticks = 30 * 10; // 30 seconds
|
||||
sec_prot_state_set(prot, &data->common, FWH_STATE_FINISH);
|
||||
} else {
|
||||
// Ready to be deleted
|
||||
sec_prot_state_set(prot, &data->common, FWH_STATE_FINISHED);
|
||||
}
|
||||
case FWH_STATE_FINISHED:
|
||||
prot->timer_stop(prot);
|
||||
prot->finished(prot);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -438,7 +471,8 @@ static int8_t supp_fwh_sec_prot_ptk_generate(sec_prot_t *prot, sec_prot_keys_t *
|
|||
|
||||
uint8_t *remote_nonce = data->recv_eapol_pdu.msg.key.key_nonce;
|
||||
if (!remote_nonce) {
|
||||
return 1;
|
||||
tr_error("No ANonce");
|
||||
return -1;
|
||||
}
|
||||
|
||||
uint8_t *pmk = sec_prot_keys_pmk_get(sec_keys);
|
||||
|
@ -457,6 +491,21 @@ static void supp_fwh_sec_prot_recv_replay_counter_store(sec_prot_t *prot)
|
|||
{
|
||||
fwh_sec_prot_int_t *data = fwh_sec_prot_get(prot);
|
||||
data->recv_replay_cnt = data->recv_eapol_pdu.msg.key.replay_counter;
|
||||
data->recv_replay_cnt_set = true;
|
||||
}
|
||||
|
||||
static bool supp_fwh_sec_prot_recv_replay_cnt_compare(uint64_t received_counter, sec_prot_t *prot)
|
||||
{
|
||||
fwh_sec_prot_int_t *data = fwh_sec_prot_get(prot);
|
||||
// If previous value is set must be greater
|
||||
if (data->recv_replay_cnt_set && received_counter > data->recv_replay_cnt) {
|
||||
return true;
|
||||
} else if (!data->recv_replay_cnt_set && received_counter >= data->recv_replay_cnt) {
|
||||
// Otherwise allows also same value e.g. zero
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void supp_fwh_sec_prot_anonce_store(sec_prot_t *prot)
|
||||
|
@ -469,6 +518,7 @@ static int8_t supp_fwh_sec_prot_anonce_validate(sec_prot_t *prot)
|
|||
{
|
||||
fwh_sec_prot_int_t *data = fwh_sec_prot_get(prot);
|
||||
if (memcmp(data->anonce, data->recv_eapol_pdu.msg.key.key_nonce, EAPOL_KEY_NONCE_LEN) != 0) {
|
||||
tr_error("ANonce invalid");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
|
@ -508,7 +558,7 @@ static int8_t supp_fwh_kde_handle(sec_prot_t *prot)
|
|||
|
||||
case FWH_MESSAGE_3:
|
||||
// If a valid new GTK value present, insert it
|
||||
if (sec_prot_lib_gtk_read(kde, kde_len, prot->sec_keys->gtks) < 0) {
|
||||
if (sec_prot_lib_gtk_read(kde, kde_len, prot->sec_keys) < 0) {
|
||||
goto error;
|
||||
}
|
||||
break;
|
||||
|
@ -521,6 +571,7 @@ static int8_t supp_fwh_kde_handle(sec_prot_t *prot)
|
|||
return 0;
|
||||
|
||||
error:
|
||||
tr_error("Invalid KDEs");
|
||||
ns_dyn_mem_free(kde);
|
||||
return -1;
|
||||
}
|
||||
|
|
|
@ -139,12 +139,18 @@ static int8_t auth_gkh_sec_prot_receive(sec_prot_t *prot, void *pdu, uint16_t si
|
|||
if (eapol_parse_pdu_header(pdu, size, &data->recv_eapol_pdu)) {
|
||||
// Get message
|
||||
if (auth_gkh_sec_prot_message_get(&data->recv_eapol_pdu, prot->sec_keys) != GKH_MESSAGE_UNKNOWN) {
|
||||
tr_info("GKH: recv Message 2, eui-64: %s", trace_array(sec_prot_remote_eui_64_addr_get(prot), 8));
|
||||
|
||||
// Call state machine
|
||||
data->recv_pdu = pdu;
|
||||
data->recv_size = size;
|
||||
prot->state_machine(prot);
|
||||
} else {
|
||||
tr_error("GKH: recv error, eui-64: %s", trace_array(sec_prot_remote_eui_64_addr_get(prot), 8));
|
||||
}
|
||||
ret_val = 0;
|
||||
} else {
|
||||
tr_error("GKH: recv error, eui-64: %s", trace_array(sec_prot_remote_eui_64_addr_get(prot), 8));
|
||||
}
|
||||
|
||||
memset(&data->recv_eapol_pdu, 0, sizeof(eapol_pdu_t));
|
||||
|
@ -163,7 +169,7 @@ static gkh_sec_prot_msg_e auth_gkh_sec_prot_message_get(eapol_pdu_t *eapol_pdu,
|
|||
return GKH_MESSAGE_UNKNOWN;
|
||||
}
|
||||
|
||||
uint8_t key_mask = sec_prot_lib_key_mask_get(eapol_pdu);
|
||||
uint8_t key_mask = eapol_pdu_key_mask_get(eapol_pdu);
|
||||
|
||||
switch (key_mask) {
|
||||
case KEY_INFO_KEY_MIC | KEY_INFO_SECURED_KEY_FRAME:
|
||||
|
@ -204,14 +210,14 @@ static int8_t auth_gkh_sec_prot_message_send(sec_prot_t *prot, gkh_sec_prot_msg_
|
|||
switch (msg) {
|
||||
case GKH_MESSAGE_1: {
|
||||
uint8_t gtk_index;
|
||||
uint8_t *gtk = sec_prot_keys_get_gtk_to_insert(prot->sec_keys->gtks, >k_index);
|
||||
uint8_t *gtk = sec_prot_keys_get_gtk_to_insert(prot->sec_keys, >k_index);
|
||||
if (gtk) {
|
||||
kde_end = kde_gtk_write(kde_end, gtk_index, gtk);
|
||||
|
||||
uint32_t gtk_lifetime = sec_prot_keys_gtk_lifetime_get(prot->sec_keys->gtks, gtk_index);
|
||||
kde_end = kde_lifetime_write(kde_end, gtk_lifetime);
|
||||
}
|
||||
uint8_t gtkl = sec_prot_keys_gtkl_get(prot->sec_keys->gtks);
|
||||
uint8_t gtkl = sec_prot_keys_fresh_gtkl_get(prot->sec_keys->gtks);
|
||||
kde_end = kde_gtkl_write(kde_end, gtkl);
|
||||
kde_padding_write(kde_end, kde_start + kde_len);
|
||||
}
|
||||
|
@ -245,6 +251,8 @@ static int8_t auth_gkh_sec_prot_message_send(sec_prot_t *prot, gkh_sec_prot_msg_
|
|||
return -1;
|
||||
}
|
||||
|
||||
tr_info("GKH: send Message 1, eui-64: %s", trace_array(sec_prot_remote_eui_64_addr_get(prot), 8));
|
||||
|
||||
if (prot->send(prot, eapol_pdu_frame, eapol_pdu_size + prot->header_size) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
@ -270,7 +278,7 @@ static void auth_gkh_sec_prot_state_machine(sec_prot_t *prot)
|
|||
|
||||
// Wait KMP-CREATE.request
|
||||
case GKH_STATE_CREATE_REQ:
|
||||
tr_debug("GKH start");
|
||||
tr_info("GKH start, eui-64: %s", trace_array(sec_prot_remote_eui_64_addr_get(prot), 8));
|
||||
|
||||
prot->timer_start(prot);
|
||||
|
||||
|
@ -296,12 +304,15 @@ static void auth_gkh_sec_prot_state_machine(sec_prot_t *prot)
|
|||
if (auth_gkh_sec_prot_mic_validate(prot) < 0) {
|
||||
return;
|
||||
}
|
||||
// Set inserted GTK valid
|
||||
sec_prot_keys_gtkl_from_gtk_insert_index_set(prot->sec_keys);
|
||||
|
||||
sec_prot_state_set(prot, &data->common, GKH_STATE_FINISH);
|
||||
}
|
||||
break;
|
||||
|
||||
case GKH_STATE_FINISH:
|
||||
tr_debug("GKH finish");
|
||||
tr_info("GKH finish, eui-64: %s", trace_array(sec_prot_remote_eui_64_addr_get(prot), 8));
|
||||
|
||||
// KMP-FINISHED.indication,
|
||||
prot->finished_ind(prot, sec_prot_result_get(&data->common), 0);
|
||||
|
|
|
@ -142,12 +142,18 @@ static int8_t supp_gkh_sec_prot_receive(sec_prot_t *prot, void *pdu, uint16_t si
|
|||
if (eapol_parse_pdu_header(pdu, size, &data->recv_eapol_pdu)) {
|
||||
// Get message
|
||||
if (supp_gkh_sec_prot_message_get(&data->recv_eapol_pdu, prot->sec_keys) != GKH_MESSAGE_UNKNOWN) {
|
||||
tr_info("GKH: recv Message 1");
|
||||
|
||||
// Call state machine
|
||||
data->recv_pdu = pdu;
|
||||
data->recv_size = size;
|
||||
prot->state_machine(prot);
|
||||
} else {
|
||||
tr_error("GKH: recv error");
|
||||
}
|
||||
ret_val = 0;
|
||||
} else {
|
||||
tr_error("GKH: recv error");
|
||||
}
|
||||
|
||||
memset(&data->recv_eapol_pdu, 0, sizeof(eapol_pdu_t));
|
||||
|
@ -166,16 +172,18 @@ static gkh_sec_prot_msg_e supp_gkh_sec_prot_message_get(eapol_pdu_t *eapol_pdu,
|
|||
return GKH_MESSAGE_UNKNOWN;
|
||||
}
|
||||
|
||||
uint8_t key_mask = sec_prot_lib_key_mask_get(eapol_pdu);
|
||||
uint8_t key_mask = eapol_pdu_key_mask_get(eapol_pdu);
|
||||
|
||||
switch (key_mask) {
|
||||
case KEY_INFO_KEY_ACK | KEY_INFO_KEY_MIC | KEY_INFO_SECURED_KEY_FRAME:
|
||||
// Must have valid replay counter
|
||||
if (eapol_pdu->msg.key.replay_counter > sec_prot_keys_pmk_replay_cnt_get(sec_keys)) {
|
||||
if (sec_prot_keys_pmk_replay_cnt_compare(eapol_pdu->msg.key.replay_counter, sec_keys)) {
|
||||
if (eapol_pdu->msg.key.key_information.encrypted_key_data) {
|
||||
// This should include the GTK KDE, Lifetime KDE and GTKL KDE.
|
||||
msg = GKH_MESSAGE_1;
|
||||
}
|
||||
} else {
|
||||
tr_error("GKH: invalid replay counter %"PRId64, eapol_pdu->msg.key.replay_counter);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
@ -207,6 +215,8 @@ static int8_t supp_gkh_sec_prot_message_send(sec_prot_t *prot, gkh_sec_prot_msg_
|
|||
return -1;
|
||||
}
|
||||
|
||||
tr_info("GKH: send Message 2");
|
||||
|
||||
if (prot->send(prot, eapol_pdu_frame, eapol_pdu_size + prot->header_size) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
@ -304,15 +314,11 @@ static int8_t supp_gkh_kde_handle(sec_prot_t *prot)
|
|||
}
|
||||
|
||||
// If a valid new GTK value present, insert it
|
||||
int8_t ret = sec_prot_lib_gtk_read(kde, kde_len, prot->sec_keys->gtks);
|
||||
int8_t ret = sec_prot_lib_gtk_read(kde, kde_len, prot->sec_keys);
|
||||
|
||||
ns_dyn_mem_free(kde);
|
||||
|
||||
if (ret < 0 || sec_prot_keys_gtk_insert_index_get(prot->sec_keys->gtks) < 0) {
|
||||
return -1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif /* HAVE_WS */
|
||||
|
|
|
@ -113,13 +113,23 @@ static void key_sec_prot_create_request(sec_prot_t *prot, sec_prot_keys_t *sec_k
|
|||
uint16_t kde_len = KDE_GTKL_LEN;
|
||||
|
||||
uint8_t *pmk = sec_prot_keys_pmk_get(sec_keys);
|
||||
uint8_t pmkid[PMKID_LEN];
|
||||
if (pmk) {
|
||||
kde_len += KDE_PMKID_LEN;
|
||||
if (sec_prot_lib_pmkid_generate(prot, pmkid, false) >= 0) {
|
||||
kde_len += KDE_PMKID_LEN;
|
||||
} else {
|
||||
pmk = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t *ptk = sec_prot_keys_ptk_get(sec_keys);
|
||||
uint8_t ptkid[PTKID_LEN];
|
||||
if (ptk) {
|
||||
kde_len += KDE_PTKID_LEN;
|
||||
if (sec_prot_lib_ptkid_generate(prot, ptkid, false) >= 0) {
|
||||
kde_len += KDE_PTKID_LEN;
|
||||
} else {
|
||||
ptk = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t *kde_start = ns_dyn_mem_temporary_alloc(kde_len);
|
||||
|
@ -130,20 +140,14 @@ static void key_sec_prot_create_request(sec_prot_t *prot, sec_prot_keys_t *sec_k
|
|||
uint8_t *kde_end = kde_start;
|
||||
|
||||
if (pmk) {
|
||||
uint8_t pmkid[PMKID_LEN];
|
||||
if (sec_prot_lib_pmkid_generate(prot, pmkid, true) >= 0) {
|
||||
kde_end = kde_pmkid_write(kde_end, pmkid);
|
||||
}
|
||||
kde_end = kde_pmkid_write(kde_end, pmkid);
|
||||
}
|
||||
|
||||
if (ptk) {
|
||||
uint8_t ptkid[PTKID_LEN];
|
||||
if (sec_prot_lib_ptkid_generate(prot, ptkid, true) >= 0) {
|
||||
kde_end = kde_ptkid_write(kde_end, ptkid);
|
||||
}
|
||||
kde_end = kde_ptkid_write(kde_end, ptkid);
|
||||
}
|
||||
|
||||
uint8_t gtkl = sec_prot_keys_gtkl_get(sec_keys->gtks);
|
||||
uint8_t gtkl = sec_prot_keys_fresh_gtkl_get(sec_keys->gtks);
|
||||
kde_end = kde_gtkl_write(kde_end, gtkl);
|
||||
|
||||
kde_len = kde_end - kde_start;
|
||||
|
@ -157,14 +161,15 @@ static void key_sec_prot_create_request(sec_prot_t *prot, sec_prot_keys_t *sec_k
|
|||
if (!eapol_decoded_data) {
|
||||
data->result = SEC_RESULT_ERR_NO_MEM;
|
||||
} else {
|
||||
//Test Data
|
||||
eapol_pdu.msg.key.key_information.install = false;
|
||||
eapol_pdu.msg.key.key_information.pairwise_key = false;
|
||||
eapol_pdu.msg.key.key_information.request = true;
|
||||
eapol_pdu.msg.key.replay_counter = 10;
|
||||
eapol_pdu.msg.key.key_length = 32;
|
||||
eapol_pdu.msg.key.replay_counter = 0;
|
||||
eapol_pdu.msg.key.key_length = 0;
|
||||
eapol_write_pdu_frame(eapol_decoded_data + prot->header_size, &eapol_pdu);
|
||||
|
||||
tr_info("Initial EAPOL-Key send, PMKID %s PTKID %s GTKL %x", pmk ? "set" : "not set", ptk ? "set" : "not set", gtkl);
|
||||
|
||||
if (prot->send(prot, eapol_decoded_data, eapol_pdu_size + prot->header_size) < 0) {
|
||||
data->result = SEC_RESULT_ERR_NO_MEM;
|
||||
}
|
||||
|
@ -187,11 +192,67 @@ static void key_sec_prot_create_response(sec_prot_t *prot, sec_prot_result_e res
|
|||
static int8_t key_sec_prot_receive(sec_prot_t *prot, void *pdu, uint16_t size)
|
||||
{
|
||||
eapol_pdu_t eapol_pdu;
|
||||
|
||||
tr_info("Initial EAPOL-Key recv, eui-64: %s", trace_array(sec_prot_remote_eui_64_addr_get(prot), 8));
|
||||
|
||||
// Decoding is successful
|
||||
if (eapol_parse_pdu_header(pdu, size, &eapol_pdu)) {
|
||||
if (eapol_pdu.packet_type != EAPOL_KEY_TYPE) {
|
||||
tr_info("not EAPOL-Key packet");
|
||||
prot->finished(prot);
|
||||
return -1;
|
||||
}
|
||||
|
||||
uint16_t kde_len;
|
||||
uint8_t *kde = sec_prot_lib_message_handle(prot->sec_keys->ptk, &kde_len, &eapol_pdu);
|
||||
if (!kde) {
|
||||
tr_error("no KDEs");
|
||||
prot->finished(prot);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Default assumption is that PMK and PTK are not valid
|
||||
prot->sec_keys->pmk_mismatch = true;
|
||||
prot->sec_keys->ptk_mismatch = true;
|
||||
|
||||
// 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) {
|
||||
uint8_t pmkid[PMKID_LEN];
|
||||
if (sec_prot_lib_pmkid_generate(prot, pmkid, true) >= 0) {
|
||||
if (memcmp(remote_keyid, pmkid, PMKID_LEN) == 0) {
|
||||
prot->sec_keys->pmk_mismatch = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Checks if supplicant indicates that it has valid PTK
|
||||
if (kde_ptkid_read(kde, kde_len, remote_keyid) >= 0) {
|
||||
uint8_t ptkid[PTKID_LEN];
|
||||
if (sec_prot_lib_ptkid_generate(prot, ptkid, true) >= 0) {
|
||||
if (memcmp(remote_keyid, ptkid, PTKID_LEN) == 0) {
|
||||
prot->sec_keys->ptk_mismatch = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Get the GTKL that supplicant indicates
|
||||
uint8_t gtkl;
|
||||
if (kde_gtkl_read(kde, kde_len, >kl) >= 0) {
|
||||
prot->sec_keys->gtkl = gtkl;
|
||||
} else {
|
||||
tr_error("no GTKL");
|
||||
return -1;
|
||||
}
|
||||
|
||||
tr_info("PMK %s PTK %s GTKL %x", prot->sec_keys->pmk_mismatch ? "not live" : "live", prot->sec_keys->ptk_mismatch ? "not live" : "live", gtkl);
|
||||
|
||||
ns_dyn_mem_free(kde);
|
||||
|
||||
prot->create_ind(prot);
|
||||
return 0;
|
||||
} else {
|
||||
tr_error("Invalid");
|
||||
// No error handling yet, indicate just that ready to be deleted
|
||||
prot->finished(prot);
|
||||
return -1;
|
||||
|
@ -208,8 +269,6 @@ static void key_sec_prot_state_machine(sec_prot_t *prot)
|
|||
// empty
|
||||
break;
|
||||
case KEY_CREATE_REQ:
|
||||
tr_debug("initial EAPOL-Key send");
|
||||
|
||||
// KMP-CREATE.confirm
|
||||
prot->create_conf(prot, data->result);
|
||||
|
||||
|
@ -221,8 +280,6 @@ static void key_sec_prot_state_machine(sec_prot_t *prot)
|
|||
prot->finished(prot);
|
||||
break;
|
||||
case KEY_CREATE_RESP:
|
||||
tr_debug("initial EAPOL-Key receive");
|
||||
|
||||
if (data->result == SEC_RESULT_OK) {
|
||||
// KMP-FINISHED.indication, no meaning for eapol-key, just completes transfer
|
||||
prot->finished_ind(prot, SEC_RESULT_OK, 0);
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue