Merge pull request #10624 from artokin/prepare_for_mbedos513

Nanostack release for Mbed OS 5.13
pull/10656/head
Martin Kojtal 2019-05-23 11:16:56 +01:00 committed by GitHub
commit b2abfc3529
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
138 changed files with 6590 additions and 1362 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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": {

View File

@ -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/).
![](docs/img/thread_certified.png)
mbed OS is now a Thread Certified Component. Using IPv6 with 6LoWPAN as the foundation, Thread technology provides a low-power, self-healing mesh network designed for the home.
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

View File

@ -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).
*

View File

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

View File

@ -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_ */

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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);
}
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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);
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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);
}
}

View File

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

View File

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

View File

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

View File

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

View File

@ -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(&gtkhash[0], 8),
trace_array(&gtkhash[8], 8),
trace_array(&gtkhash[16], 8),
trace_array(&gtkhash[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 */

View File

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

View File

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

View File

@ -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_ */

View File

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

View File

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

View File

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

View File

@ -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(&gtkhash[0], 8),
trace_array(&gtkhash[8], 8),
trace_array(&gtkhash[16], 8),
trace_array(&gtkhash[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, &gtk_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);
}
}

View File

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

View File

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

View File

@ -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_ */

View File

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

View File

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

View File

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

View File

@ -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]);

View File

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

View File

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

View File

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

View File

@ -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_ */

View File

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

View File

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

View File

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

View File

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

View File

@ -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_ */

View File

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

View File

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

View File

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

View File

@ -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]) {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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);
}

View File

@ -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_ */

View File

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

View File

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

View File

@ -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_ */

View File

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

View File

@ -29,7 +29,7 @@
*/
typedef enum {
INVALID_KMP_TYPE = 0,
KMP_TYPE_NONE = 0,
IEEE_802_1X_MKA = 1,
IEEE_802_11_4WH = 6,

View File

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

View File

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

View File

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

View File

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

View File

@ -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_ */

View File

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

View File

@ -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, &gtk_index);
uint8_t *gtk = sec_prot_keys_get_gtk_to_insert(prot->sec_keys, &gtk_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;
}

View File

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

View File

@ -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, &gtk_index);
uint8_t *gtk = sec_prot_keys_get_gtk_to_insert(prot->sec_keys, &gtk_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);

View File

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

View File

@ -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, &gtkl) >= 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