Squashed 'features/nanostack/sal-stack-nanostack/' changes from 0824752..9b3e144

9b3e144 Removed kde_helper test files
451ac95 Merge branch 'release_internal' into release_external
d9976cf Merge branch 'master' into release_internal
0a6fb58 RPL parent update handle update
59b145b Fixed Ifdown / UP sequence and and discovery state set own hop to 0xff.
9103d68 Fixed dwell time, clock drift and timing accuracy values
56831ad Wi-sun BBR Slaac Ula support fix
add63fe Modified advertisiement trickle handling to remove congestion
7683bef Added storing of all MAC frame counters to NVM
b8a4f8d MAC ACK handler update:
ba09c34 Added adaptation layer TX queue size statistic
2fe2a6c MAC update:
6d288ce MAC security update:
c870b76 Added skipping of fragment length to EAP-TLS protocol and other improvements
561280b Wi-sun Discovery update:
5b153f4 DHCPv6 Client and Server update
ab849c6 Corrected skipping of other elements than KDEs on EAPOL key frames
61ebe10 Removed RPL version number increment.
b423c46 RPL parent select update
7d2f967 Corrected setting of test GTK on supplicant
454faf6 Do not balck list neighbour if link fail to ARO.
8120b37 Wi-sun RPL candidate accept update
ebe0dad fixed bbr for ULA prefix to real prefix change
bb42fad Added Network size setup for certificate test
9a7849b Fixed uninitilized fixed channel use case for test purpose.
bca8b0f Disabled check for certificate valid from field
2a5ae7c Fixed eapol target selection sort algorithm
9b283cb Fixed FHSS configuration API
76089cb Fixed ASYNCH message send for fixed channel setup.
0c94982 When starting bootstrap clear candidate parent list
6c25cf5 Dynamic min lifetime for temporary neighbour.
0b7c87a Retry timeout based on NW size is set after receiving identity
7ec9ef1 Corrected supplicant and controller authentication result causes
f5a00a0 Fixed DHCPv6 prefix update case
e06c8b2 Nanostack: sync with mbed os
ffe9351 Refactored the EAPOL target scanning
0880162 Added target EUI-64 to authentication result callback
c110c19 Added tx failure cause to initial EAPOL-key security protocol

git-subtree-dir: features/nanostack/sal-stack-nanostack
git-subtree-split: 9b3e144f5b519955837117a544168f06192b16a0
pull/11889/head
Jarkko Paso 2019-11-18 15:08:32 +02:00
parent 3e6cb31659
commit 0b6ccc5816
63 changed files with 2030 additions and 840 deletions

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
macDeviceDescriptionPanIDUpdate = 0xf7, /*<Thread pending link update case this will update device descrioton list pan-id to new one*/
macTXPower = 0xf8, /*<TX output power*/
macCCAThreshold = 0xf9, /*<CCA threshold*/
macMultiCSMAParameters = 0xfa, /*<Multi CSMA parameters*/

View File

@ -70,7 +70,9 @@ typedef struct nwk_stats_t {
/* ETX */
uint16_t etx_1st_parent; /**< Primary parent ETX. */
uint16_t etx_2nd_parent; /**< Secondary parent ETX. */
/* MAC */
uint16_t adapt_layer_tx_queue_size; /**< Adaptation layer direct TX queue size. */
uint16_t adapt_layer_tx_queue_peak; /**< Adaptation layer direct TX queue size peak. */
} nwk_stats_t;
/**

View File

@ -79,6 +79,7 @@ extern "C" {
#define NETWORK_SIZE_SMALL 0x01
#define NETWORK_SIZE_MEDIUM 0x08
#define NETWORK_SIZE_LARGE 0x10
#define NETWORK_SIZE_CERTIFICATE 0xFF
/** Temporary API change flag. this will be removed when new version of API is implemented on applications
@ -246,9 +247,10 @@ int ws_management_fhss_timing_configure(
* Change the default configuration for Wi-SUN FHSS operation.
* if application defined is used the behaviour is undefined
*
*
* \param interface_id Network interface ID.
* \param channel_function Unicast channel function.
* \param fixed_channel Used channel when channel function is fixed channel. If 0xFFFF, randomly chosen channel is used.
* \param fixed_channel Used channel when channel function is fixed channel.
* \param dwell_interval Used dwell interval when channel function is TR51 or DH1.
*
* \return 0, Init OK.
@ -266,9 +268,10 @@ int ws_management_fhss_unicast_channel_function_configure(
* Change the default configuration for Wi-SUN FHSS operation.
* if application defined is used the behaviour is undefined
*
*
* \param interface_id Network interface ID.
* \param channel_function Broadcast channel function.
* \param fixed_channel Used channel when channel function is fixed channel. If 0xFFFF, randomly chosen channel is used.
* \param fixed_channel Used channel when channel function is fixed channel.
* \param dwell_interval Broadcast channel dwell interval.
* \param broadcast_interval Broadcast interval.
*

View File

@ -837,26 +837,47 @@ int8_t mac_helper_link_frame_counter_read(int8_t interface_id, uint32_t *seq_ptr
if (!cur || !cur->mac_api || !seq_ptr) {
return -1;
}
mlme_get_t get_req;
get_req.attr = macFrameCounter;
get_req.attr_index = cur->mac_parameters->mac_default_key_attribute_id;
cur->mac_api->mlme_req(cur->mac_api, MLME_GET, &get_req);
*seq_ptr = cur->mac_parameters->security_frame_counter;
return 0;
return mac_helper_key_link_frame_counter_read(interface_id, seq_ptr, cur->mac_parameters->mac_default_key_attribute_id);
}
int8_t mac_helper_link_frame_counter_set(int8_t interface_id, uint32_t seq_ptr)
{
protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(interface_id);
if (!cur || !cur->mac_api) {
return -1;
}
return mac_helper_key_link_frame_counter_set(interface_id, seq_ptr, cur->mac_parameters->mac_default_key_attribute_id);
}
int8_t mac_helper_key_link_frame_counter_read(int8_t interface_id, uint32_t *seq_ptr, uint8_t descriptor)
{
protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(interface_id);
if (!cur || !cur->mac_api || !seq_ptr) {
return -1;
}
mlme_get_t get_req;
get_req.attr = macFrameCounter;
get_req.attr_index = descriptor;
cur->mac_api->mlme_req(cur->mac_api, MLME_GET, &get_req);
*seq_ptr = cur->mac_parameters->security_frame_counter;
return 0;
}
int8_t mac_helper_key_link_frame_counter_set(int8_t interface_id, uint32_t seq_ptr, uint8_t descriptor)
{
protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(interface_id);
if (!cur || !cur->mac_api) {
return -1;
}
mlme_set_t set_req;
set_req.attr = macFrameCounter;
set_req.attr_index = cur->mac_parameters->mac_default_key_attribute_id;
set_req.attr_index = descriptor;
set_req.value_pointer = &seq_ptr;
set_req.value_size = 4;
cur->mac_api->mlme_req(cur->mac_api, MLME_SET, &set_req);
@ -929,3 +950,20 @@ int8_t mac_helper_mac_mlme_max_retry_set(int8_t interface_id, uint8_t mac_retry_
return 0;
}
int8_t mac_helper_mac_device_description_pan_id_update(int8_t interface_id, uint16_t pan_id)
{
protocol_interface_info_entry_t *cur;
cur = protocol_stack_interface_info_get_by_id(interface_id);
if (!cur || !cur->mac_api) {
return -1;
}
mlme_set_t set_req;
set_req.attr = macDeviceDescriptionPanIDUpdate;
set_req.attr_index = 0;
set_req.value_pointer = &pan_id;
set_req.value_size = sizeof(pan_id);
cur->mac_api->mlme_req(cur->mac_api, MLME_SET, &set_req);
return 0;
}

View File

@ -115,6 +115,10 @@ int8_t mac_helper_link_frame_counter_read(int8_t interface_id, uint32_t *seq_ptr
int8_t mac_helper_link_frame_counter_set(int8_t interface_id, uint32_t seq_ptr);
int8_t mac_helper_key_link_frame_counter_read(int8_t interface_id, uint32_t *seq_ptr, uint8_t descriptor);
int8_t mac_helper_key_link_frame_counter_set(int8_t interface_id, uint32_t seq_ptr, uint8_t descriptor);
void mac_helper_devicetable_remove(struct mac_api_s *mac_api, uint8_t attribute_index, uint8_t *mac64);
void mac_helper_device_description_write(struct protocol_interface_info_entry *cur, mlme_device_descriptor_t *device_desc, uint8_t *mac64, uint16_t mac16, uint32_t frame_counter, bool exempt);
@ -122,4 +126,6 @@ void mac_helper_device_description_write(struct protocol_interface_info_entry *c
void mac_helper_devicetable_set(const mlme_device_descriptor_t *device_dec, struct protocol_interface_info_entry *cur, uint8_t attribute_index, uint8_t keyID, bool force_set);
int8_t mac_helper_mac_mlme_max_retry_set(int8_t interface_id, uint8_t mac_retry_set);
int8_t mac_helper_mac_device_description_pan_id_update(int8_t interface_id, uint16_t pan_id);
#endif // MAC_HELPER_H

View File

@ -755,6 +755,8 @@ int thread_link_configuration_activate(protocol_interface_info_entry_t *cur, lin
return -1;
}
mac_helper_mac_device_description_pan_id_update(cur->id, linkConfiguration->panId);
thread_configuration_thread_activate(cur, linkConfiguration);
thread_configuration_security_activate(cur, linkConfiguration);
thread_configuration_6lowpan_activate(cur);
@ -899,7 +901,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_init(cur->id, DHCPV6_DUID_HARDWARE_EUI64_TYPE);
dhcp_client_configure(cur->id, false, false, false);
thread_management_client_init(cur->id);
thread_bootstrap_address_registration_init();
@ -2886,7 +2888,7 @@ void thread_bootstrap_network_prefixes_process(protocol_interface_info_entry_t *
thread_addr_write_mesh_local_16(addr, curBorderRouter->routerID, cur->thread_info);
/* Do not allow multiple DHCP solicits from one prefix => delete previous */
dhcp_client_global_address_delete(cur->id, NULL, curPrefix->servicesPrefix);
if (dhcp_client_get_global_address(cur->id, addr, curPrefix->servicesPrefix, cur->mac, DHCPV6_DUID_HARDWARE_EUI64_TYPE, thread_dhcp_client_gua_error_cb) == 0) {
if (dhcp_client_get_global_address(cur->id, addr, curPrefix->servicesPrefix, thread_dhcp_client_gua_error_cb) == 0) {
tr_debug("GP Address Requested");
}
}

View File

@ -514,7 +514,7 @@ static void thread_parse_annoucement(protocol_interface_info_entry_t *cur, mle_m
channel_page = ptr[0];
channel = common_read_16_bit(&ptr[1]);
if (linkConfiguration->timestamp == timestamp) {
if (linkConfiguration && linkConfiguration->timestamp == timestamp) {
// We received same timestamp
tr_debug("Same timestamp");
return;
@ -527,7 +527,7 @@ static void thread_parse_annoucement(protocol_interface_info_entry_t *cur, mle_m
}
if (linkConfiguration->timestamp > timestamp) {
if (linkConfiguration && linkConfiguration->timestamp > timestamp) {
// We received older time stamp we just announce back to originator channel
thread_bootstrap_announce_send(cur, linkConfiguration->channel_page, linkConfiguration->rfChannel, linkConfiguration->panId, linkConfiguration->timestamp, channel);
return;

View File

@ -92,6 +92,7 @@ typedef struct {
fragmenter_tx_entry_t active_unicast_tx_buf; //Current active direct unicast tx process
fragmenter_tx_entry_t active_broadcast_tx_buf; //Current active direct broadcast tx process
buffer_list_t directTxQueue; //Waiting free tx process
uint16_t directTxQueue_size;
uint16_t indirect_big_packet_threshold;
uint16_t max_indirect_big_packets_total;
uint16_t max_indirect_small_packets_per_child;
@ -216,6 +217,8 @@ static void lowpan_adaptation_tx_queue_write(fragmenter_interface_t *interface_p
} else {
ns_list_add_to_end(&interface_ptr->directTxQueue, buf);
}
interface_ptr->directTxQueue_size++;
protocol_stats_update(STATS_AL_TX_QUEUE_SIZE, interface_ptr->directTxQueue_size);
}
static buffer_t *lowpan_adaptation_tx_queue_read(fragmenter_interface_t *interface_ptr, protocol_interface_info_entry_t *cur)
@ -231,6 +234,8 @@ static buffer_t *lowpan_adaptation_tx_queue_read(fragmenter_interface_t *interfa
} else if ((buf->link_specific.ieee802_15_4.requestAck && !interface_ptr->active_unicast_tx_buf.buf)
|| (!buf->link_specific.ieee802_15_4.requestAck && !interface_ptr->active_broadcast_tx_buf.buf)) {
ns_list_remove(&interface_ptr->directTxQueue, buf);
interface_ptr->directTxQueue_size--;
protocol_stats_update(STATS_AL_TX_QUEUE_SIZE, interface_ptr->directTxQueue_size);
return buf;
}
}

View File

@ -37,6 +37,7 @@
#include "6LoWPAN/ws/ws_bbr_api_internal.h"
#include "6LoWPAN/ws/ws_pae_controller.h"
#include "DHCPv6_Server/DHCPv6_server_service.h"
#include "DHCPv6_client/dhcpv6_client_api.h"
#include "ws_bbr_api.h"
@ -44,6 +45,8 @@
#define RPL_INSTANCE_ID 1
static uint8_t current_instance_id = RPL_INSTANCE_ID;
#ifdef HAVE_WS_BORDER_ROUTER
#define WS_ULA_LIFETIME 24*3600
@ -59,7 +62,8 @@
static int8_t backbone_interface_id = -1; // BBR backbone information
static uint16_t configuration = 0;
static uint8_t static_dodag_prefix[8] = {0xfd, 0x00, 0x61, 0x72, 0x6d};
static uint8_t static_dodag_prefix[8] = {0xfd, 0x00, 0x72, 0x83, 0x7e};
static uint8_t static_dodag_id_prefix[8] = {0xfd, 0x00, 0x61, 0x72, 0x6d};
static uint8_t current_dodag_id[16] = {0};
static uint8_t current_local_prefix[8] = {0};
static uint8_t current_global_prefix[8] = {0};
@ -71,17 +75,17 @@ static rpl_dodag_conf_t rpl_conf = {
.default_lifetime = 120,
.lifetime_unit = 60,
.objective_code_point = 1, // MRHOF algorithm used
.authentication = 0,
.authentication = false,
.path_control_size = 7,
.dag_max_rank_increase = 2048,
.min_hop_rank_increase = 196,
.dag_max_rank_increase = WS_RPL_MAX_HOP_RANK_INCREASE,
.min_hop_rank_increase = WS_RPL_MIN_HOP_RANK_INCREASE,
// DIO configuration
.dio_interval_min = WS_RPL_DIO_IMIN,
.dio_interval_doublings = WS_RPL_DIO_DOUBLING,
.dio_redundancy_constant = WS_RPL_DIO_REDUNDANCY
};
void ws_bbr_rpl_config(uint8_t imin, uint8_t doubling, uint8_t redundancy)
void ws_bbr_rpl_config(uint8_t imin, uint8_t doubling, uint8_t redundancy, uint16_t dag_max_rank_increase, uint16_t min_hop_rank_increase)
{
if (imin == 0 || doubling == 0) {
// use default values
@ -89,15 +93,22 @@ void ws_bbr_rpl_config(uint8_t imin, uint8_t doubling, uint8_t redundancy)
doubling = WS_RPL_DIO_DOUBLING;
redundancy = WS_RPL_DIO_REDUNDANCY;
}
if (rpl_conf.dio_interval_min == imin &&
rpl_conf.dio_interval_doublings == doubling &&
rpl_conf.dio_redundancy_constant == redundancy) {
rpl_conf.dio_redundancy_constant == redundancy &&
rpl_conf.dag_max_rank_increase == dag_max_rank_increase &&
rpl_conf.min_hop_rank_increase == min_hop_rank_increase) {
// Same values no update needed
return;
}
rpl_conf.dio_interval_min = imin;
rpl_conf.dio_interval_doublings = doubling;
rpl_conf.dio_redundancy_constant = redundancy;
rpl_conf.dag_max_rank_increase = dag_max_rank_increase;
rpl_conf.min_hop_rank_increase = min_hop_rank_increase;
if (protocol_6lowpan_rpl_root_dodag) {
rpl_control_update_dodag_config(protocol_6lowpan_rpl_root_dodag, &rpl_conf);
rpl_control_increment_dodag_version(protocol_6lowpan_rpl_root_dodag);
@ -112,9 +123,10 @@ static void ws_bbr_rpl_root_start(uint8_t *dodag_id)
if (protocol_6lowpan_rpl_root_dodag) {
rpl_control_delete_dodag_root(protocol_6lowpan_rpl_domain, protocol_6lowpan_rpl_root_dodag);
protocol_6lowpan_rpl_root_dodag = NULL;
current_instance_id++;
}
protocol_6lowpan_rpl_root_dodag = rpl_control_create_dodag_root(protocol_6lowpan_rpl_domain, RPL_INSTANCE_ID, dodag_id, &rpl_conf, rpl_conf.min_hop_rank_increase, RPL_GROUNDED | RPL_MODE_NON_STORING | RPL_DODAG_PREF(0));
protocol_6lowpan_rpl_root_dodag = rpl_control_create_dodag_root(protocol_6lowpan_rpl_domain, current_instance_id, dodag_id, &rpl_conf, rpl_conf.min_hop_rank_increase, RPL_GROUNDED | RPL_MODE_NON_STORING | RPL_DODAG_PREF(0));
if (!protocol_6lowpan_rpl_root_dodag) {
tr_err("RPL dodag init failed");
return;
@ -129,6 +141,7 @@ static void ws_bbr_rpl_root_stop(void)
if (protocol_6lowpan_rpl_root_dodag) {
rpl_control_delete_dodag_root(protocol_6lowpan_rpl_domain, protocol_6lowpan_rpl_root_dodag);
protocol_6lowpan_rpl_root_dodag = NULL;
current_instance_id++;
}
memset(current_local_prefix, 0, 8);
memset(current_global_prefix, 0, 8);
@ -162,6 +175,24 @@ int ws_border_router_proxy_state_update(int8_t caller_interface_id, int8_t handl
return 0;
}
static if_address_entry_t *ws_bbr_slaac_generate(protocol_interface_info_entry_t *cur, uint8_t *ula_prefix)
{
if_address_entry_t *add_entry = icmpv6_slaac_address_add(cur, ula_prefix, 64, 0xffffffff, 0xffffffff, true, SLAAC_IID_FIXED);
if (!add_entry) {
tr_err("ula create failed");
return NULL;
}
addr_policy_table_add_entry(ula_prefix, 64, 2, WS_NON_PREFFRED_LABEL);
return add_entry;
}
static void ws_bbr_slaac_remove(protocol_interface_info_entry_t *cur, uint8_t *ula_prefix)
{
icmpv6_slaac_prefix_update(cur, ula_prefix, 64, 0, 0);
addr_policy_table_delete_entry(ula_prefix, 64);
}
static int ws_bbr_static_dodagid_create(protocol_interface_info_entry_t *cur)
{
if (memcmp(current_dodag_id, ADDR_UNSPECIFIED, 16) != 0) {
@ -169,14 +200,13 @@ static int ws_bbr_static_dodagid_create(protocol_interface_info_entry_t *cur)
return 0;
}
// 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, 0xffffffff, true, SLAAC_IID_FIXED);
if_address_entry_t *add_entry = ws_bbr_slaac_generate(cur, static_dodag_id_prefix);
if (!add_entry) {
tr_err("dodagid create failed");
return -1;
}
memcpy(current_dodag_id, add_entry->address, 16);
tr_info("BBR generate DODAGID %s", trace_ipv6(current_dodag_id));
addr_policy_table_add_entry(static_dodag_prefix, 64, 2, WS_NON_PREFFRED_LABEL);
return 0;
}
@ -211,7 +241,7 @@ static void ws_bbr_dodag_get(uint8_t *local_prefix_ptr, uint8_t *global_prefix_p
memset(global_prefix_ptr, 0, 8);
// By default static dodagID prefix is used as local prefix
memcpy(local_prefix_ptr, current_dodag_id, 8);
memcpy(local_prefix_ptr, static_dodag_prefix, 8);
ws_bbr_bb_static_prefix_get(local_prefix_ptr);
if (arm_net_address_get(backbone_interface_id, ADDR_IPV6_GP, global_address) != 0) {
@ -285,8 +315,13 @@ static void ws_bbr_dhcp_server_start(protocol_interface_info_entry_t *cur, uint8
}
static void ws_bbr_dhcp_server_stop(protocol_interface_info_entry_t *cur, uint8_t *global_id)
{
tr_debug("DHCP server deactivate %s", trace_ipv6(global_id));
uint8_t temp_address[16];
memcpy(temp_address, global_id, 8);
memset(temp_address + 8, 0, 8);
tr_debug("DHCP server deactivate %s", trace_ipv6(temp_address));
DHCPv6_server_service_delete(cur->id, global_id, false);
//Delete Client
dhcp_client_global_address_delete(cur->id, NULL, temp_address);
}
@ -342,9 +377,16 @@ static void ws_bbr_rpl_status_check(protocol_interface_info_entry_t *cur)
// Start static ULA prefix and routing always
if (memcmp(current_local_prefix, ADDR_UNSPECIFIED, 8) != 0) {
// Remove Old ULA prefix
ws_bbr_slaac_remove(cur, current_local_prefix);
rpl_control_update_dodag_prefix(protocol_6lowpan_rpl_root_dodag, current_local_prefix, 64, PIO_A, 0, 0, true);
memset(current_local_prefix, 0, 8);
}
if (memcmp(local_prefix, ADDR_UNSPECIFIED, 8) != 0) {
if (!ws_bbr_slaac_generate(cur, local_prefix)) {
return;
}
tr_info("RPL Local prefix activate %s", trace_ipv6_prefix(local_prefix, 64));
rpl_control_update_dodag_prefix(protocol_6lowpan_rpl_root_dodag, local_prefix, 64, PIO_A, WS_ULA_LIFETIME, WS_ULA_LIFETIME, false);
memcpy(current_local_prefix, local_prefix, 8);
@ -354,7 +396,7 @@ static void ws_bbr_rpl_status_check(protocol_interface_info_entry_t *cur)
/*
* Check if backup ULA prefix is needed
*/
if (memcmp(global_prefix, ADDR_UNSPECIFIED, 8) == 0) {
if ((configuration & BBR_ULA_C) == 0 && memcmp(global_prefix, ADDR_UNSPECIFIED, 8) == 0) {
//Global prefix not available count if backup ULA should be created
global_prefix_unavailable_timer += BBR_CHECK_INTERVAL;
tr_debug("Check for backup prefix %"PRIu32"", global_prefix_unavailable_timer);
@ -479,13 +521,6 @@ void ws_bbr_seconds_timer(protocol_interface_info_entry_t *cur, uint32_t seconds
if (cur->ws_info->network_size_config == NETWORK_SIZE_AUTOMATIC) {
ws_common_network_size_configure(cur, cur->ws_info->pan_information.pan_size);
}
// We update the RPL version in same time to allow nodes to reselect parent
// As configuration is made so that devices cant move downward in dodag this allows it
// Version number update is only done if DoDAG MAX Rank Increase parameter is 0
if (rpl_conf.dag_max_rank_increase == 0 && cur->ws_info->pan_information.pan_version && cur->ws_info->pan_information.pan_version % RPL_VERSION_LIFETIME / cur->ws_info->pan_version_timer == 0) {
// Third the rate of configuration version change at default 5 hours
rpl_control_increment_dodag_version(protocol_6lowpan_rpl_root_dodag);
}
}
}
@ -510,7 +545,7 @@ uint16_t ws_bbr_pan_size(protocol_interface_info_entry_t *cur)
prefix_ptr = current_local_prefix;
}
rpl_control_get_instance_dao_target_count(cur->rpl_domain, RPL_INSTANCE_ID, NULL, prefix_ptr, &result);
rpl_control_get_instance_dao_target_count(cur->rpl_domain, current_instance_id, NULL, prefix_ptr, &result);
if (result > 0) {
// remove the Border router from the PAN size
result--;
@ -581,6 +616,7 @@ void ws_bbr_stop(int8_t interface_id)
rpl_control_delete_dodag_root(protocol_6lowpan_rpl_domain, protocol_6lowpan_rpl_root_dodag);
protocol_6lowpan_rpl_root_dodag = NULL;
current_instance_id++;
#else
(void)interface_id;
@ -593,7 +629,7 @@ int ws_bbr_configure(int8_t interface_id, uint16_t options)
(void)interface_id;
if (protocol_6lowpan_rpl_root_dodag &&
options != configuration) {
//Configuration changed delete previus setup
//Configuration changed delete previous setup
ws_bbr_rpl_root_stop();
}
configuration = options;

View File

@ -27,7 +27,7 @@ void ws_bbr_seconds_timer(protocol_interface_info_entry_t *cur, uint32_t seconds
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);
void ws_bbr_rpl_config(uint8_t imin, uint8_t doubling, uint8_t redundancy, uint16_t dag_max_rank_increase, uint16_t min_hop_rank_increase);
bool ws_bbr_ready_to_start(protocol_interface_info_entry_t *cur);
@ -36,7 +36,7 @@ bool ws_bbr_ready_to_start(protocol_interface_info_entry_t *cur);
#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, dag_max_rank_increase, min_hop_rank_increase)
#define ws_bbr_ready_to_start(cur) true
#endif //HAVE_WS_BORDER_ROUTER

View File

@ -76,9 +76,9 @@
static void ws_bootstrap_event_handler(arm_event_s *event);
static void ws_bootstrap_state_change(protocol_interface_info_entry_t *cur, icmp_state_t nwk_bootstrap_state);
//static bool ws_bootstrap_state_active(struct protocol_interface_info_entry *cur);
//static bool ws_bootstrap_state_wait_rpl(struct protocol_interface_info_entry *cur);
static bool ws_bootstrap_state_discovery(struct protocol_interface_info_entry *cur);
static bool ws_bootstrap_state_active(struct protocol_interface_info_entry *cur);
static bool ws_bootstrap_state_wait_rpl(struct protocol_interface_info_entry *cur);
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);
static bool ws_bootstrap_neighbor_info_request(struct protocol_interface_info_entry *interface, const uint8_t *mac_64, llc_neighbour_req_t *neighbor_buffer, bool request_new);
@ -90,15 +90,19 @@ static void ws_bootstrap_mac_security_enable(protocol_interface_info_entry_t *cu
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_nw_frame_counter_read(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_nw_frame_counter_set(protocol_interface_info_entry_t *cur, uint32_t counter, uint8_t slot);
static void ws_bootstrap_nw_frame_counter_read(protocol_interface_info_entry_t *cur, uint32_t *counter, uint8_t slot);
static void ws_bootstrap_authentication_completed(protocol_interface_info_entry_t *cur, auth_result_e result, uint8_t *target_eui_64);
static void ws_bootstrap_pan_version_increment(protocol_interface_info_entry_t *cur);
static ws_nud_table_entry_t *ws_nud_entry_discover(protocol_interface_info_entry_t *cur, void *neighbor);
static void ws_nud_entry_remove(protocol_interface_info_entry_t *cur, mac_neighbor_table_entry_t *entry_ptr);
static bool ws_neighbor_entry_nud_notify(mac_neighbor_table_entry_t *entry_ptr, void *user_data);
static bool ws_rpl_dio_new_parent_accept(struct protocol_interface_info_entry *interface);
static void ws_bootstrap_candidate_table_reset(protocol_interface_info_entry_t *cur);
static parent_info_t *ws_bootstrap_candidate_parent_get(struct protocol_interface_info_entry *cur, const uint8_t *addr, bool create);
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*/
@ -417,7 +421,7 @@ static int8_t ws_fhss_initialize(protocol_interface_info_entry_t *cur)
{
fhss_api_t *fhss_api = ns_sw_mac_get_fhss_api(cur->mac_api);
if (!fhss_api) {
if (!fhss_api || (fhss_api && cur->ws_info->fhss_owner)) {
// When FHSS doesn't exist yet, create one
fhss_ws_configuration_t fhss_configuration;
memset(&fhss_configuration, 0, sizeof(fhss_ws_configuration_t));
@ -434,12 +438,25 @@ static int8_t ws_fhss_initialize(protocol_interface_info_entry_t *cur)
fhss_configuration.fhss_bc_dwell_interval = cur->ws_info->fhss_bc_dwell_interval;
fhss_configuration.fhss_broadcast_interval = cur->ws_info->fhss_bc_interval;
fhss_api = ns_fhss_ws_create(&fhss_configuration, cur->ws_info->fhss_timer_ptr);
if (!fhss_api) {
tr_error("fhss create failed");
return -1;
fhss_api = ns_fhss_ws_create(&fhss_configuration, cur->ws_info->fhss_timer_ptr);
if (!fhss_api) {
tr_error("fhss create failed");
return -1;
}
ns_sw_mac_fhss_register(cur->mac_api, fhss_api);
cur->ws_info->fhss_owner = true;
} else {
//Configuration set
ns_fhss_ws_configuration_set(cur->ws_info->fhss_api, &fhss_configuration);
if (cur->bootsrap_mode == ARM_NWK_BOOTSRAP_MODE_6LoWPAN_BORDER_ROUTER) {
ns_fhss_ws_set_hop_count(cur->ws_info->fhss_api, 0);
} else {
//Clear OWN HOP
ns_fhss_ws_set_hop_count(cur->ws_info->fhss_api, 0xff);
}
}
ns_sw_mac_fhss_register(cur->mac_api, fhss_api);
} else {
// Read defaults from the configuration to help FHSS testing
const fhss_ws_configuration_t *fhss_configuration = ns_fhss_ws_configuration_get(fhss_api);
@ -453,6 +470,8 @@ static int8_t ws_fhss_initialize(protocol_interface_info_entry_t *cur)
cur->ws_info->fhss_bc_dwell_interval = fhss_configuration->fhss_bc_dwell_interval;
cur->ws_info->fhss_bc_interval = fhss_configuration->fhss_broadcast_interval;
cur->ws_info->fhss_uc_dwell_interval = fhss_configuration->fhss_uc_dwell_interval;
cur->ws_info->fhss_bc_fixed_channel = fhss_configuration->broadcast_fixed_channel;
cur->ws_info->fhss_uc_fixed_channel = fhss_configuration->unicast_fixed_channel;
}
return 0;
}
@ -510,16 +529,15 @@ static int8_t ws_fhss_discovery_configure(protocol_interface_info_entry_t *cur)
memcpy(&fhss_configuration, ns_fhss_ws_configuration_get(cur->ws_info->fhss_api), sizeof(fhss_ws_configuration_t));
}
fhss_configuration.fhss_uc_dwell_interval = 0;
fhss_configuration.ws_uc_channel_function = WS_FIXED_CHANNEL;
fhss_configuration.ws_bc_channel_function = WS_FIXED_CHANNEL;
fhss_configuration.fhss_bc_dwell_interval = 0;
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);
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);
ns_fhss_ws_set_hop_count(cur->ws_info->fhss_api, 0xff);
ws_bootstrap_llc_hopping_update(cur, &fhss_configuration);
return 0;
@ -591,7 +609,7 @@ void ws_bootstrap_eapol_parent_synch(struct protocol_interface_info_entry *cur,
return;
}
if (memcmp(neighbor_info->neighbor->mac64, cur->ws_info->parent_info.addr, 8)) {
if (ws_bootstrap_candidate_parent_get(cur, neighbor_info->neighbor->mac64, false) == NULL) {
return;
}
@ -755,13 +773,15 @@ static int8_t ws_bootstrap_up(protocol_interface_info_entry_t *cur)
/*Replace NS handler to disable multicast address queries */
cur->if_ns_transmit = ws_bootstrap_nd_ns_transmit;
dhcp_client_init(cur->id);
dhcp_client_init(cur->id, DHCPV6_DUID_HARDWARE_IEEE_802_NETWORKS_TYPE);
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);
ws_nud_table_reset(cur);
ws_bootstrap_candidate_table_reset(cur);
blacklist_params_set(
WS_BLACKLIST_ENTRY_LIFETIME,
WS_BLACKLIST_TIMER_MAX_TIMEOUT,
@ -796,6 +816,7 @@ static int8_t ws_bootstrap_down(protocol_interface_info_entry_t *cur)
ws_eapol_relay_delete(cur);
ws_eapol_auth_relay_delete(cur);
ws_pae_controller_stop(cur);
ws_bootstrap_candidate_table_reset(cur);
blacklist_clear();
return nwk_6lowpan_down(cur);
@ -859,7 +880,7 @@ static bool ws_bootstrap_network_name_matches(const struct mcps_data_ie_list *ie
static void ws_bootstrap_pan_advertisement_analyse_active(struct protocol_interface_info_entry *cur, ws_pan_information_t *pan_information)
{
/* TODO In Active state
/* In Active state
*
* A consistent transmission is defined as a PAN Advertisement received by a node with PAN ID and
* NETNAME-IE / Network Name matching that of the receiving node, and with a PAN-IE / Routing Cost
@ -874,18 +895,207 @@ static void ws_bootstrap_pan_advertisement_analyse_active(struct protocol_interf
*
*/
if (pan_information->routing_cost >= cur->ws_info->pan_information.routing_cost) {
#ifdef WISUN_1_0_ERRATA_FIX
// All messages are considered as consistent only Solicit will cause inconsistent
trickle_consistent_heard(&cur->ws_info->trickle_pan_advertisement);
#else
// Wi-SUN 1.0 specified functionality, causes extra inconsistencies when we hear higher rank advertisements
if (pan_information->routing_cost >= ws_bootstrap_routing_cost_calculate(cur)) {
trickle_consistent_heard(&cur->ws_info->trickle_pan_advertisement);
} else {
trickle_inconsistent_heard(&cur->ws_info->trickle_pan_advertisement, &cur->ws_info->trickle_params_pan_discovery);
}
#endif
}
// automatic network size adjustment
if (cur->ws_info->network_size_config == NETWORK_SIZE_AUTOMATIC &&
cur->bootsrap_mode != ARM_NWK_BOOTSRAP_MODE_6LoWPAN_BORDER_ROUTER &&
cur->ws_info->pan_information.pan_size != pan_information->pan_size) {
ws_common_network_size_configure(cur, pan_information->pan_size);
static parent_info_t *ws_bootstrap_candidate_parent_get_best(protocol_interface_info_entry_t *cur)
{
ns_list_foreach_safe(parent_info_t, entry, &cur->ws_info->parent_list_reserved) {
tr_info("candidate list a:%s panid:%x cost:%d size:%d rssi:%d age:%"PRIu32, trace_array(entry->addr, 8), entry->pan_id, entry->pan_information.routing_cost, entry->pan_information.pan_size, entry->signal_dbm, protocol_core_monotonic_time - entry->age);
}
return ns_list_get_first(&cur->ws_info->parent_list_reserved);
}
static void ws_bootstrap_candidate_parent_store(parent_info_t *parent, const struct mcps_data_ind_s *data, ws_utt_ie_t *ws_utt, ws_us_ie_t *ws_us, ws_pan_information_t *pan_information)
{
parent->ws_utt = *ws_utt;
// Saved from unicast IE
parent->ws_us = *ws_us;
// Saved from Pan information, do not overwrite pan_version as it is not valid here
parent->pan_information.pan_size = pan_information->pan_size;
parent->pan_information.routing_cost = pan_information->routing_cost;
parent->pan_information.use_parent_bs = pan_information->use_parent_bs;
parent->pan_information.rpl_routing_method = pan_information->rpl_routing_method;
parent->pan_information.version = pan_information->version;
// Saved from message
parent->timestamp = data->timestamp;
parent->pan_id = data->SrcPANId;
parent->link_quality = data->mpduLinkQuality;
parent->signal_dbm = data->signal_dbm;
memcpy(parent->addr, data->SrcAddr, 8);
parent->age = protocol_core_monotonic_time;
}
static void ws_bootstrap_candidate_table_reset(protocol_interface_info_entry_t *cur)
{
//Empty active list
ns_list_foreach_safe(parent_info_t, entry, &cur->ws_info->parent_list_free) {
ns_list_remove(&cur->ws_info->parent_list_free, entry);
}
//Empty free list
ns_list_foreach_safe(parent_info_t, entry, &cur->ws_info->parent_list_reserved) {
ns_list_remove(&cur->ws_info->parent_list_reserved, entry);
}
//Add to free list to full
for (int i = 0; i < WS_PARENT_LIST_SIZE; i++) {
ns_list_add_to_end(&cur->ws_info->parent_list_free, &cur->ws_info->parent_info[i]);
}
}
static parent_info_t *ws_bootstrap_candidate_parent_allocate(protocol_interface_info_entry_t *cur, const uint8_t *addr)
{
parent_info_t *entry = ns_list_get_first(&cur->ws_info->parent_list_free);
if (entry) {
memcpy(entry->addr, addr, 8);
ns_list_remove(&cur->ws_info->parent_list_free, entry);
ns_list_add_to_end(&cur->ws_info->parent_list_reserved, entry);
} else {
// If there is no free entries always allocate the last one of reserved as it is the worst
entry = ns_list_get_last(&cur->ws_info->parent_list_reserved);
}
return entry;
}
static void ws_bootstrap_candidate_parent_free(protocol_interface_info_entry_t *cur, uint8_t *addr)
{
ns_list_foreach_safe(parent_info_t, entry, &cur->ws_info->parent_list_reserved) {
if (memcmp(entry->addr, addr, 8) == 0) {
ns_list_remove(&cur->ws_info->parent_list_reserved, entry);
ns_list_add_to_end(&cur->ws_info->parent_list_free, entry);
return;
}
}
}
static parent_info_t *ws_bootstrap_candidate_parent_get(struct protocol_interface_info_entry *cur, const uint8_t *addr, bool create)
{
ns_list_foreach_safe(parent_info_t, entry, &cur->ws_info->parent_list_reserved) {
if (memcmp(entry->addr, addr, 8) == 0) {
return entry;
}
}
if (create) {
return ws_bootstrap_candidate_parent_allocate(cur, addr);
}
return NULL;
}
static bool ws_bootstrap_candidate_parent_compare(parent_info_t *p1, parent_info_t *p2)
{
// Return true if P2 is better
// signal lower than threshold for both
// pan_cost
// signal quality
if (ws_neighbor_class_rsl_from_dbm_calculate(p1->signal_dbm) < (DEVICE_MIN_SENS + CAND_PARENT_THRESHOLD + CAND_PARENT_HYSTERISIS) &&
ws_neighbor_class_rsl_from_dbm_calculate(p2->signal_dbm) > (DEVICE_MIN_SENS + CAND_PARENT_THRESHOLD + CAND_PARENT_HYSTERISIS)) {
// above threshold is always better than not.
return true;
}
if (ws_neighbor_class_rsl_from_dbm_calculate(p2->signal_dbm) < (DEVICE_MIN_SENS + CAND_PARENT_THRESHOLD + CAND_PARENT_HYSTERISIS) &&
ws_neighbor_class_rsl_from_dbm_calculate(p1->signal_dbm) > (DEVICE_MIN_SENS + CAND_PARENT_THRESHOLD + CAND_PARENT_HYSTERISIS)) {
// P2 is less than threshold and P1 is larger so P1 is always better.
return false;
}
// Select the lowest PAN cost
uint16_t p1_pan_cost = (p1->pan_information.routing_cost / PRC_WEIGHT_FACTOR) + (p1->pan_information.pan_size / PS_WEIGHT_FACTOR);
uint16_t p2_pan_cost = (p2->pan_information.routing_cost / PRC_WEIGHT_FACTOR) + (p2->pan_information.pan_size / PS_WEIGHT_FACTOR);
if (p1_pan_cost > p2_pan_cost) {
return true;
} else if (p1_pan_cost < p2_pan_cost) {
return false;
}
// If pan cost is the same then we select the one we hear highest
if (p1->signal_dbm < p2->signal_dbm) {
return true;
}
return false;
}
static void ws_bootstrap_candidate_list_clean(struct protocol_interface_info_entry *cur, uint8_t pan_max, uint32_t current_time, uint16_t pan_id)
{
int pan_count = 0;
ns_list_foreach_safe(parent_info_t, entry, &cur->ws_info->parent_list_reserved) {
if ((current_time - entry->age) > WS_PARENT_LIST_MAX_AGE) {
ns_list_remove(&cur->ws_info->parent_list_reserved, entry);
ns_list_add_to_end(&cur->ws_info->parent_list_free, entry);
continue;
}
if (entry->pan_id == pan_id) {
// Same panid if there is more than limited amount free those
pan_count++;
if (pan_count > pan_max) {
ns_list_remove(&cur->ws_info->parent_list_reserved, entry);
ns_list_add_to_end(&cur->ws_info->parent_list_free, entry);
continue;
}
}
}
}
static void ws_bootstrap_candidate_parent_sort(struct protocol_interface_info_entry *cur, parent_info_t *new_entry)
{
ns_list_foreach_safe(parent_info_t, entry, &cur->ws_info->parent_list_reserved) {
if (entry == new_entry) {
// own entry skip it
continue;
}
if (ws_bootstrap_candidate_parent_compare(entry, new_entry)) {
// New entry is better
//tr_debug("candidate list new is better");
ns_list_remove(&cur->ws_info->parent_list_reserved, new_entry);
ns_list_add_before(&cur->ws_info->parent_list_reserved, entry, new_entry);
return;
}
}
}
static void ws_bootstrap_pan_information_store(struct protocol_interface_info_entry *cur, const struct mcps_data_ind_s *data, ws_utt_ie_t *ws_utt, ws_us_ie_t *ws_us, ws_pan_information_t *pan_information)
{
parent_info_t *new_entry;
/* Have List of 20 heard neighbours
* Order those as best based on pan cost
* In single pan order based on signal quality
* in single PAN limit the amount of devices to 5
* If there is no advertisement heard for last hour Clear the neigbour.
*/
// Discovery state processing
//tr_info("neighbour: addr:%s panid:%x signal:%d", trace_array(data->SrcAddr, 8), data->SrcPANId, data->signal_dbm);
// Clean old entries
ws_bootstrap_candidate_list_clean(cur, WS_PARENT_LIST_MAX_PAN_IN_DISCOVERY, protocol_core_monotonic_time, data->SrcPANId);
new_entry = ws_bootstrap_candidate_parent_get(cur, data->SrcAddr, true);
if (!new_entry) {
tr_warn("neighbour creation fail");
return;
}
// Safe the information
ws_bootstrap_candidate_parent_store(new_entry, data, ws_utt, ws_us, pan_information);
// set to the correct place in list
ws_bootstrap_candidate_parent_sort(cur, new_entry);
return;
}
static void ws_bootstrap_pan_advertisement_analyse(struct protocol_interface_info_entry *cur, const struct mcps_data_ind_s *data, const struct mcps_data_ie_list *ie_ext, ws_utt_ie_t *ws_utt, ws_us_ie_t *ws_us)
@ -899,99 +1109,39 @@ static void ws_bootstrap_pan_advertisement_analyse(struct protocol_interface_inf
return;
}
// if in active scan state
if (!ws_bootstrap_state_discovery(cur)) {
if (data->SrcPANId != cur->ws_info->network_pan_id) {
return;
}
}
// Check pan flags so that it is valid
if (!pan_information.rpl_routing_method) {
// NOT RPL routing
tr_warn("Not supported routing");
//tr_warn("Not supported routing");
return;
}
/* TODO smart neighbour process
*
* Unsecure packet we cant trust the device?
*
* This message is received from tens of devices and we must select the best parent
*
* We save the best parent and create entry when we have selected the EAPOL target
*
*/
// Store heard pans and possible candidate parents
ws_bootstrap_pan_information_store(cur, data, ws_utt, ws_us, &pan_information);
// Save route cost for all neighbours
if (!(ws_bootstrap_state_active(cur) ||
ws_bootstrap_state_wait_rpl(cur))) {
// During discovery/eapol/config learn we dont do further processing for advertisements
return;
}
// Active state processing
//tr_debug("Advertisement active");
// In active operation less neighbours per pan is allowed
ws_bootstrap_candidate_list_clean(cur, WS_PARENT_LIST_MAX_PAN_IN_ACTIVE, protocol_core_monotonic_time, data->SrcPANId);
// Check if valid PAN
if (data->SrcPANId != cur->ws_info->network_pan_id) {
return;
}
// Save route cost for all known neighbors
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;
}
// Save the best network parent
if (ws_bootstrap_state_discovery(cur)) {
// Discovery state processing
tr_info("potential parent addr:%s panid:%x signal:%d", trace_array(data->SrcAddr, 8), data->SrcPANId, data->signal_dbm);
// This parent is selected and used for authentication.
if (memcmp(cur->ws_info->parent_info.addr, ADDR_UNSPECIFIED, 8) != 0) {
// if we dont have higher than threshold signal only signal level decides parent
if (ws_neighbor_class_rsl_from_dbm_calculate(cur->ws_info->parent_info.signal_dbm) < (DEVICE_MIN_SENS + CAND_PARENT_THRESHOLD + CAND_PARENT_HYSTERISIS) &&
ws_neighbor_class_rsl_from_dbm_calculate(data->signal_dbm) > ws_neighbor_class_rsl_from_dbm_calculate(cur->ws_info->parent_info.signal_dbm)) {
// automatically select the best quality link from the below threshold
goto parent_selected;
}
// Drop if signal quality is not good enough
if (ws_neighbor_class_rsl_from_dbm_calculate(data->signal_dbm) < (DEVICE_MIN_SENS + CAND_PARENT_THRESHOLD + CAND_PARENT_HYSTERISIS)) {
tr_info("EAPOL target dropped Link quality too low");
return;
}
// Select the lowest PAN cost
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 %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 %d < %d current", data->signal_dbm, cur->ws_info->parent_info.signal_dbm);
return;
}
}
parent_selected:
// Parent valid store information
cur->ws_info->parent_info.ws_utt = *ws_utt;
// Saved from unicast IE
cur->ws_info->parent_info.ws_us = *ws_us;
// Saved from Pan information, do not overwrite pan_version as it is not valid here
cur->ws_info->parent_info.pan_information.pan_size = pan_information.pan_size;
cur->ws_info->parent_info.pan_information.routing_cost = pan_information.routing_cost;
cur->ws_info->parent_info.pan_information.use_parent_bs = pan_information.use_parent_bs;
cur->ws_info->parent_info.pan_information.rpl_routing_method = pan_information.rpl_routing_method;
cur->ws_info->parent_info.pan_information.version = pan_information.version;
// Saved from message
cur->ws_info->parent_info.timestamp = data->timestamp;
cur->ws_info->parent_info.pan_id = data->SrcPANId;
cur->ws_info->parent_info.link_quality = data->mpduLinkQuality;
cur->ws_info->parent_info.signal_dbm = data->signal_dbm;
memcpy(cur->ws_info->parent_info.addr, data->SrcAddr, 8);
tr_info("New parent addr:%s panid:%x signal:%d", trace_array(cur->ws_info->parent_info.addr, 8), cur->ws_info->parent_info.pan_id, cur->ws_info->parent_info.signal_dbm);
return;
}
// Active state processing
ws_bootstrap_pan_advertisement_analyse_active(cur, &pan_information);
// Learn latest network information
@ -1000,13 +1150,18 @@ parent_selected:
ws_bootsrap_create_ll_address(ll_address, neighbor_info.neighbor->mac64);
if (rpl_control_is_dodag_parent(cur, ll_address)) {
// automatic network size adjustment learned
if (cur->ws_info->network_size_config == NETWORK_SIZE_AUTOMATIC &&
cur->ws_info->pan_information.pan_size != pan_information.pan_size) {
ws_common_network_size_configure(cur, pan_information.pan_size);
}
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;
}
}
}
@ -1026,6 +1181,16 @@ static void ws_bootstrap_pan_advertisement_solicit_analyse(struct protocol_inter
* a PAN Advertisement Solicit with NETNAME-IE / Network Name matching that configured on the receiving node.
*/
trickle_consistent_heard(&cur->ws_info->trickle_pan_advertisement_solicit);
/*
* Optimized PAN discovery to select faster the parent if we hear solicit from someone else
*/
if (ws_bootstrap_state_discovery(cur) &&
cur->bootsrap_state_machine_cnt > cur->ws_info->trickle_params_pan_discovery.Imin + 50) {
cur->bootsrap_state_machine_cnt = cur->ws_info->trickle_params_pan_discovery.Imin + randLIB_get_8bit() % 50;
tr_info("Making parent selection in %d s", (uint32_t)(cur->bootsrap_state_machine_cnt / 10));
}
}
@ -1192,18 +1357,6 @@ static void ws_bootstrap_pan_config_solicit_analyse(struct protocol_interface_in
*/
trickle_inconsistent_heard(&cur->ws_info->trickle_pan_config, &cur->ws_info->trickle_params_pan_discovery);
}
static bool ws_bootstrap_network_found(protocol_interface_info_entry_t *cur)
{
tr_debug("analyze network discovery result");
// This parent is used for authentication to the network
if (memcmp(cur->ws_info->parent_info.addr, ADDR_UNSPECIFIED, 8) == 0) {
// No parent found yet
return false;
}
return true;
}
static bool ws_channel_plan_zero_compare(ws_channel_plan_zero_t *rx_plan, ws_hopping_schedule_t *hopping_schdule)
{
if (rx_plan->operation_class != hopping_schdule->operating_class) {
@ -1286,7 +1439,7 @@ static void ws_bootstrap_asynch_ind(struct protocol_interface_info_entry *cur, c
switch (message_type) {
case WS_FT_PAN_ADVERT:
// Analyse Advertisement
tr_info("received ADVERT Src:%s rssi:%d", trace_array(data->SrcAddr, 8), data->signal_dbm);
tr_info("received ADVERT Src:%s panid:%x rssi:%d", trace_array(data->SrcAddr, 8), data->SrcPANId, data->signal_dbm);
ws_bootstrap_pan_advertisement_analyse(cur, data, ie_ext, &ws_utt, &ws_us);
break;
case WS_FT_PAN_ADVERT_SOL:
@ -1370,8 +1523,13 @@ static void ws_bootstrap_neighbor_table_clean(struct protocol_interface_info_ent
//Read current timestamp
uint32_t time_from_last_unicast_shedule = ws_time_from_last_unicast_traffic(current_time_stamp, ws_neighbor);
if (time_from_last_unicast_shedule > WS_NEIGHBOR_TEMPORARY_LINK_MIN_TIMEOUT) {
uint32_t min_timeout;
if (interface->ws_info->network_size_config == NETWORK_SIZE_LARGE) {
min_timeout = WS_NEIGHBOR_TEMPORARY_LINK_MIN_TIMEOUT_LARGE;
} else {
min_timeout = WS_NEIGHBOR_TEMPORARY_LINK_MIN_TIMEOUT_SMALL;
}
if (time_from_last_unicast_shedule > min_timeout) {
//Accept only Enough Old Device
if (!neighbor_entry_ptr) {
//Accept first compare
@ -1436,13 +1594,13 @@ static bool ws_rpl_dio_new_parent_accept(struct protocol_interface_info_entry *i
uint16_t parent_candidate_size = rpl_control_parent_candidate_list_size(interface, false);
//TODO check bootstarap state for review
//if we have enough candidates at list do not accept new multicast neighbours
if (parent_candidate_size > WS_NEIGHBOUR_MAX_CANDIDATE_PROBE) {
if (parent_candidate_size > interface->ws_info->rpl_parent_candidate_max) {
return false;
}
parent_candidate_size = rpl_control_parent_candidate_list_size(interface, true);
//If we have already enough parent selected Candidates count is bigger tahn 4
if (parent_candidate_size >= 2) {
//If we have already enough parent selected Candidates count is bigger than configured
if (parent_candidate_size >= interface->ws_info->rpl_selected_parent_max) {
return false;
}
@ -1771,7 +1929,6 @@ int ws_bootstrap_neighbor_remove(protocol_interface_info_entry_t *cur, const uin
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;
@ -1811,23 +1968,6 @@ static void ws_bootstrap_fhss_activate(protocol_interface_info_entry_t *cur)
return;
}
static void ws_bootstrap_network_information_learn(protocol_interface_info_entry_t *cur)
{
tr_debug("learn network information from parent");
// Start following network broadcast timing schedules
// Regulatory domain saving? cant change?
// Save network information
cur->ws_info->network_pan_id = cur->ws_info->parent_info.pan_id;
cur->ws_info->pan_information = cur->ws_info->parent_info.pan_information;
cur->ws_info->pan_information.pan_version = 0; // This is learned from actual configuration
// TODO create parent neighbour table entry for unicast schedule to enable authentication
return;
}
static void ws_bootstrap_network_configuration_learn(protocol_interface_info_entry_t *cur)
{
tr_debug("Start using PAN configuration");
@ -1926,7 +2066,7 @@ static void ws_bootstrap_rpl_callback(rpl_event_t event, void *handle)
*
*/
} else if (event == RPL_EVENT_DAO_PARENT_SWITCH) {
} else if (event == RPL_EVENT_DAO_PARENT_ADD) {
ws_address_registration_update(cur);
}
cur->ws_info->rpl_state = event;
@ -1953,7 +2093,7 @@ static void ws_dhcp_client_global_adress_cb(int8_t interface, uint8_t dhcp_addr[
void ws_dhcp_client_address_request(protocol_interface_info_entry_t *cur, uint8_t *prefix, uint8_t *parent_link_local)
{
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) {
if (dhcp_client_get_global_address(cur->id, parent_link_local, prefix, ws_dhcp_client_global_adress_cb) != 0) {
tr_error("DHCPp client request fail");
}
}
@ -2106,16 +2246,19 @@ static void ws_bootstrap_pan_version_increment(protocol_interface_info_entry_t *
static void ws_bootstrap_start_discovery(protocol_interface_info_entry_t *cur)
{
tr_debug("router discovery start");
// Remove network keys from MAC
ws_pae_controller_nw_keys_remove(cur);
ws_bootstrap_state_change(cur, ER_ACTIVE_SCAN);
cur->nwk_nd_re_scan_count = 0;
cur->ws_info->configuration_learned = false;
cur->ws_info->pan_version_timeout_timer = 0;
// Clear parent info
memset(cur->ws_info->parent_info.addr, 0, 8);
// Clear learned neighbours
ws_bootstrap_neighbor_list_clean(cur);
// Clear learned candidate parents
ws_bootstrap_candidate_table_reset(cur);
// Clear RPL information
rpl_control_free_domain_instances_from_interface(cur);
// Clear EAPOL relay address
@ -2151,6 +2294,7 @@ static void ws_bootstrap_start_discovery(protocol_interface_info_entry_t *cur)
cur->ws_info->trickle_pan_advertisement_solicit.I, cur->ws_info->trickle_pan_advertisement_solicit.t, cur->ws_info->trickle_pan_advertisement_solicit.now, cur->ws_info->trickle_pan_advertisement_solicit.c);
cur->bootsrap_state_machine_cnt = time_to_solicit + cur->ws_info->trickle_params_pan_discovery.Imin + randLIB_get_8bit() % 50;
tr_info("Making parent selection in %d s", (uint32_t)(cur->bootsrap_state_machine_cnt / 10));
}
// Start authentication
@ -2184,23 +2328,34 @@ static void ws_bootstrap_nw_key_index_set(protocol_interface_info_entry_t *cur,
mac_helper_security_auto_request_key_index_set(cur, index, index + 1);
}
static void ws_bootstrap_nw_frame_counter_set(protocol_interface_info_entry_t *cur, uint32_t counter)
static void ws_bootstrap_nw_frame_counter_set(protocol_interface_info_entry_t *cur, uint32_t counter, uint8_t slot)
{
// Set frame counter
mac_helper_link_frame_counter_set(cur->id, counter);
mac_helper_key_link_frame_counter_set(cur->id, counter, slot);
}
static void ws_bootstrap_nw_frame_counter_read(protocol_interface_info_entry_t *cur, uint32_t *counter)
static void ws_bootstrap_nw_frame_counter_read(protocol_interface_info_entry_t *cur, uint32_t *counter, uint8_t slot)
{
// Read frame counter
mac_helper_link_frame_counter_read(cur->id, counter);
mac_helper_key_link_frame_counter_read(cur->id, counter, slot);
}
static void ws_bootstrap_authentication_completed(protocol_interface_info_entry_t *cur, bool success)
static void ws_bootstrap_authentication_completed(protocol_interface_info_entry_t *cur, auth_result_e result, uint8_t *target_eui_64)
{
if (success) {
(void) target_eui_64;
if (result == AUTH_RESULT_OK) {
tr_debug("authentication success");
ws_bootstrap_event_configuration_start(cur);
} else if (result == AUTH_RESULT_ERR_TX_NO_ACK) {
// eapol parent selected is not working
tr_debug("authentication TX failed");
ws_bootstrap_candidate_parent_free(cur, target_eui_64);
// Go back for network scanning
ws_bootstrap_state_change(cur, ER_ACTIVE_SCAN);
cur->bootsrap_state_machine_cnt = randLIB_get_random_in_range(10, cur->ws_info->trickle_params_pan_discovery.Imin >> 1);
tr_info("Making parent selection in %d s", (uint32_t)(cur->bootsrap_state_machine_cnt / 10));
} else {
tr_debug("authentication failed");
// What else to do to start over again...
@ -2217,9 +2372,6 @@ static void ws_bootstrap_start_configuration_learn(protocol_interface_info_entry
ws_bootstrap_state_change(cur, ER_SCAN);
cur->ws_info->configuration_learned = false;
// Clear parent info
memset(cur->ws_info->parent_info.addr, 0, 8);
// Clear all temporary information
ws_bootstrap_ip_stack_reset(cur);
@ -2268,6 +2420,19 @@ void ws_bootstrap_configuration_trickle_reset(protocol_interface_info_entry_t *c
trickle_inconsistent_heard(&cur->ws_info->trickle_pan_config, &cur->ws_info->trickle_params_pan_discovery);
}
static void ws_set_asynch_channel_list(protocol_interface_info_entry_t *cur, asynch_request_t *async_req)
{
memset(&async_req->channel_list, 0, sizeof(channel_list_s));
if (cur->ws_info->fhss_uc_channel_function == WS_FIXED_CHANNEL) {
//SET 1 Channel only
uint16_t channel_number = cur->ws_info->fhss_uc_fixed_channel;
async_req->channel_list.channel_mask[0 + (channel_number / 32)] = (1 << (channel_number % 32));
} else {
ws_generate_channel_list(async_req->channel_list.channel_mask, cur->ws_info->hopping_schdule.number_of_channels, cur->ws_info->hopping_schdule.regulatory_domain);
}
async_req->channel_list.channel_page = CHANNEL_PAGE_10;
}
static void ws_bootstrap_pan_advert_solicit(protocol_interface_info_entry_t *cur)
{
@ -2279,9 +2444,9 @@ static void ws_bootstrap_pan_advert_solicit(protocol_interface_info_entry_t *cur
async_req.wp_requested_nested_ie_list.us_ie = true;
async_req.wp_requested_nested_ie_list.net_name_ie = true;
ws_generate_channel_list(async_req.channel_list.channel_mask, cur->ws_info->hopping_schdule.number_of_channels, cur->ws_info->hopping_schdule.regulatory_domain);
ws_set_asynch_channel_list(cur, &async_req);
async_req.channel_list.channel_page = CHANNEL_PAGE_10;
async_req.security.SecurityLevel = 0;
ws_llc_asynch_request(cur, &async_req);
@ -2297,9 +2462,7 @@ static void ws_bootstrap_pan_config_solicit(protocol_interface_info_entry_t *cur
async_req.wp_requested_nested_ie_list.us_ie = true;
async_req.wp_requested_nested_ie_list.net_name_ie = true;
ws_generate_channel_list(async_req.channel_list.channel_mask, cur->ws_info->hopping_schdule.number_of_channels, cur->ws_info->hopping_schdule.regulatory_domain);
async_req.channel_list.channel_page = CHANNEL_PAGE_10;
ws_set_asynch_channel_list(cur, &async_req);
async_req.security.SecurityLevel = 0;
ws_llc_asynch_request(cur, &async_req);
@ -2376,9 +2539,7 @@ static void ws_bootstrap_pan_advert(protocol_interface_info_entry_t *cur)
async_req.wp_requested_nested_ie_list.pan_ie = true;
async_req.wp_requested_nested_ie_list.net_name_ie = true;
ws_generate_channel_list(async_req.channel_list.channel_mask, cur->ws_info->hopping_schdule.number_of_channels, cur->ws_info->hopping_schdule.regulatory_domain);
async_req.channel_list.channel_page = CHANNEL_PAGE_10;
ws_set_asynch_channel_list(cur, &async_req);
async_req.security.SecurityLevel = 0;
if (cur->bootsrap_mode == ARM_NWK_BOOTSRAP_MODE_6LoWPAN_BORDER_ROUTER) {
@ -2409,9 +2570,8 @@ static void ws_bootstrap_pan_config(protocol_interface_info_entry_t *cur)
async_req.wp_requested_nested_ie_list.gtkhash_ie = true;
async_req.wp_requested_nested_ie_list.vp_ie = true;
ws_generate_channel_list(async_req.channel_list.channel_mask, cur->ws_info->hopping_schdule.number_of_channels, cur->ws_info->hopping_schdule.regulatory_domain);
ws_set_asynch_channel_list(cur, &async_req);
async_req.channel_list.channel_page = CHANNEL_PAGE_10;
async_req.security.SecurityLevel = mac_helper_default_security_level_get(cur);
async_req.security.KeyIdMode = mac_helper_default_security_key_id_mode_get(cur);
async_req.security.KeyIndex = mac_helper_default_key_index_get(cur);
@ -2551,7 +2711,6 @@ static void ws_bootstrap_event_handler(arm_event_s *event)
}
}
/*
* State machine
*
@ -2559,27 +2718,35 @@ static void ws_bootstrap_event_handler(arm_event_s *event)
void ws_bootstrap_network_scan_process(protocol_interface_info_entry_t *cur)
{
if (!ws_bootstrap_network_found(cur)) {
parent_info_t *selected_parent_ptr;
tr_debug("analyze network discovery result");
selected_parent_ptr = ws_bootstrap_candidate_parent_get_best(cur);
if (!selected_parent_ptr) {
// Next check will be after one trickle
cur->bootsrap_state_machine_cnt += cur->ws_info->trickle_params_pan_discovery.Imin + randLIB_get_8bit() % 50;
tr_info("Making parent selection in %d s", (uint32_t)(cur->bootsrap_state_machine_cnt / 10));
return;
}
tr_info("select network");
tr_info("selected parent:%s panid %u", trace_array(selected_parent_ptr->addr, 8), selected_parent_ptr->pan_id);
// Add EAPOL neighbour
cur->ws_info->network_pan_id = selected_parent_ptr->pan_id;
cur->ws_info->pan_information = selected_parent_ptr->pan_information;
cur->ws_info->pan_information.pan_version = 0; // This is learned from actual configuration
ws_bootstrap_fhss_activate(cur);
llc_neighbour_req_t neighbor_info;
if (!ws_bootstrap_neighbor_info_request(cur, cur->ws_info->parent_info.addr, &neighbor_info, true)) {
if (!ws_bootstrap_neighbor_info_request(cur, selected_parent_ptr->addr, &neighbor_info, true)) {
return;
}
ws_neighbor_class_neighbor_unicast_time_info_update(neighbor_info.ws_neighbor, &cur->ws_info->parent_info.ws_utt, cur->ws_info->parent_info.timestamp);
ws_neighbor_class_neighbor_unicast_schedule_set(neighbor_info.ws_neighbor, &cur->ws_info->parent_info.ws_us);
ws_neighbor_class_neighbor_unicast_time_info_update(neighbor_info.ws_neighbor, &selected_parent_ptr->ws_utt, selected_parent_ptr->timestamp);
ws_neighbor_class_neighbor_unicast_schedule_set(neighbor_info.ws_neighbor, &selected_parent_ptr->ws_us);
ws_bootstrap_network_information_learn(cur);
ws_bootstrap_fhss_activate(cur);
ws_pae_controller_set_target(cur, cur->ws_info->parent_info.pan_id, cur->ws_info->parent_info.addr); // temporary!!! store since auth
ws_pae_controller_set_target(cur, selected_parent_ptr->pan_id, selected_parent_ptr->addr); // temporary!!! store since auth
ws_bootstrap_event_authentication_start(cur);
return;
}
@ -2618,31 +2785,15 @@ void ws_bootstrap_rpl_wait_process(protocol_interface_info_entry_t *cur)
/*
static bool ws_bootstrap_state_active(struct protocol_interface_info_entry *cur)
{
if(cur->nwk_bootstrap_state == ER_BOOTSRAP_DONE) {
return true;
}
return false;
}
static bool ws_bootstrap_state_configure(struct protocol_interface_info_entry *cur)
{
// Think about the state value
if(cur->nwk_bootstrap_state == ER_SCAN) {
if (cur->nwk_bootstrap_state == ER_SCAN) {
return true;
}
return false;
}
static bool ws_bootstrap_state_wait_rpl(struct protocol_interface_info_entry *cur)
{
// Think about the state value
if(cur->nwk_bootstrap_state == ER_RPL_SCAN) {
return true;
}
return false;
}
*/
static bool ws_bootstrap_state_discovery(struct protocol_interface_info_entry *cur)
{
@ -2652,6 +2803,22 @@ static bool ws_bootstrap_state_discovery(struct protocol_interface_info_entry *c
return false;
}
static bool ws_bootstrap_state_active(struct protocol_interface_info_entry *cur)
{
if (cur->nwk_bootstrap_state == ER_BOOTSRAP_DONE) {
return true;
}
return false;
}
static bool ws_bootstrap_state_wait_rpl(struct protocol_interface_info_entry *cur)
{
// Think about the state value
if (cur->nwk_bootstrap_state == ER_RPL_SCAN) {
return true;
}
return false;
}
static void ws_bootstrap_state_change(protocol_interface_info_entry_t *cur, icmp_state_t nwk_bootstrap_state)
{
cur->bootsrap_state_machine_cnt = 1;
@ -2712,9 +2879,6 @@ void ws_bootstrap_trickle_timer(protocol_interface_info_entry_t *cur, uint16_t t
if (cur->ws_info->pas_requests >= PCS_MAX) {
// if MAX PCS sent restart discovery
// Remove network keys from MAC
ws_pae_controller_nw_keys_remove(cur);
// Trickle is reseted when entering to discovery from state 3
trickle_inconsistent_heard(&cur->ws_info->trickle_pan_advertisement_solicit, &cur->ws_info->trickle_params_pan_discovery);
ws_bootstrap_event_discovery_start(cur);
@ -2796,7 +2960,6 @@ void ws_bootstrap_etx_accelerate(protocol_interface_info_entry_t *interface, mac
neigh->nud_active = true;
//Push NS to send
ws_nud_active_timer(interface, 0);
}
#endif //HAVE_WS

View File

@ -288,6 +288,9 @@ int8_t ws_common_allocate_and_init(protocol_interface_info_entry_t *cur)
ns_list_init(&cur->ws_info->active_nud_process);
ns_list_init(&cur->ws_info->free_nud_entries);
ns_list_init(&cur->ws_info->parent_list_free);
ns_list_init(&cur->ws_info->parent_list_reserved);
cur->ws_info->pan_information.use_parent_bs = true;
cur->ws_info->pan_information.rpl_routing_method = true;
cur->ws_info->pan_information.version = WS_FAN_VERSION_1_0;
@ -295,8 +298,14 @@ int8_t ws_common_allocate_and_init(protocol_interface_info_entry_t *cur)
cur->ws_info->hopping_schdule.regulatory_domain = REG_DOMAIN_EU;
cur->ws_info->hopping_schdule.operating_mode = OPERATING_MODE_3;
cur->ws_info->hopping_schdule.operating_class = 2;
// Clock drift value 255 indicates that information is not provided
cur->ws_info->hopping_schdule.clock_drift = 255;
// Timing accuracy is given from 0 to 2.55msec with 10usec resolution
cur->ws_info->hopping_schdule.timing_accurancy = 100;
ws_common_regulatory_domain_config(cur);
cur->ws_info->network_size_config = NETWORK_SIZE_MEDIUM;
cur->ws_info->rpl_parent_candidate_max = WS_RPL_PARENT_CANDIDATE_MAX;
cur->ws_info->rpl_selected_parent_max = WS_RPL_SELECTED_PARENT_MAX;
ws_common_network_size_configure(cur, 200); // defaults to medium network size
// Set defaults for the device. user can modify these.
@ -326,9 +335,11 @@ void ws_common_network_size_configure(protocol_interface_info_entry_t *cur, uint
// doublings:3 (128s)
// redundancy; 0 Disabled
if (cur->ws_info->network_size_config == NETWORK_SIZE_AUTOMATIC) {
ws_bbr_rpl_config(14, 3, 0);
ws_bbr_rpl_config(14, 3, 0, WS_RPL_MAX_HOP_RANK_INCREASE, WS_RPL_MIN_HOP_RANK_INCREASE);
} else if (cur->ws_info->network_size_config == NETWORK_SIZE_CERTIFICATE) {
ws_bbr_rpl_config(0, 0, 0, WS_CERTIFICATE_RPL_MAX_HOP_RANK_INCREASE, WS_CERTIFICATE_RPL_MIN_HOP_RANK_INCREASE);
} else {
ws_bbr_rpl_config(0, 0, 0);
ws_bbr_rpl_config(0, 0, 0, WS_RPL_MAX_HOP_RANK_INCREASE, WS_RPL_MIN_HOP_RANK_INCREASE);
}
ws_pae_controller_timing_adjust(1); // Fast and reactive network
} else if (network_size < 300) {
@ -338,7 +349,7 @@ void ws_common_network_size_configure(protocol_interface_info_entry_t *cur, uint
// imin: 15 (32s)
// doublings:5 (960s)
// redundancy; 10
ws_bbr_rpl_config(15, 5, 10);
ws_bbr_rpl_config(15, 5, 10, WS_RPL_MAX_HOP_RANK_INCREASE, WS_RPL_MIN_HOP_RANK_INCREASE);
ws_pae_controller_timing_adjust(9); // medium limited network
} else {
// Configure the Wi-SUN discovery trickle parameters
@ -347,7 +358,7 @@ void ws_common_network_size_configure(protocol_interface_info_entry_t *cur, uint
// imin: 19 (524s, 9 min)
// doublings:1 (1048s, 17 min)
// redundancy; 10 May need some tuning still
ws_bbr_rpl_config(19, 1, 10);
ws_bbr_rpl_config(19, 1, 10, WS_RPL_MAX_HOP_RANK_INCREASE, WS_RPL_MIN_HOP_RANK_INCREASE);
ws_pae_controller_timing_adjust(24); // Very slow and high latency network
}
return;
@ -376,9 +387,12 @@ 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)
void ws_common_aro_failure(protocol_interface_info_entry_t *cur, const uint8_t *ll_address, bool cache_full)
{
tr_warn("ARO registration Failure %s", trace_ipv6(ll_address));
if (cache_full) {
blacklist_update(ll_address, false);
}
ws_bootstrap_aro_failure(cur, ll_address);
}
@ -435,7 +449,7 @@ bool ws_common_negative_aro_mark(protocol_interface_info_entry_t *interface, con
}
ws_neighbor_class_entry_t *ws_neighbor = ws_neighbor_class_entry_get(&interface->ws_info->neighbor_storage, neighbour->index);
ws_neighbor->negative_aro_send = true;
neighbour->lifetime = WS_NEIGHBOR_TEMPORARY_LINK_MIN_TIMEOUT; //Remove anyway if Packet is freed before MAC push
neighbour->lifetime = WS_NEIGHBOR_TEMPORARY_LINK_MIN_TIMEOUT_SMALL; //Remove anyway if Packet is freed before MAC push
return true;
}
@ -453,7 +467,7 @@ void ws_common_etx_validate(protocol_interface_info_entry_t *interface, mac_neig
uint32_t ws_common_version_lifetime_get(uint8_t config)
{
uint32_t lifetime;
if (config == NETWORK_SIZE_SMALL) {
if (config == NETWORK_SIZE_SMALL || config == NETWORK_SIZE_CERTIFICATE) {
lifetime = PAN_VERSION_SMALL_NETWORK_LIFETIME;
} else if (config == NETWORK_SIZE_MEDIUM) {
lifetime = PAN_VERSION_MEDIUM_NETWORK_LIFETIME;
@ -468,7 +482,7 @@ uint32_t ws_common_version_lifetime_get(uint8_t config)
uint32_t ws_common_version_timeout_get(uint8_t config)
{
uint32_t lifetime;
if (config == NETWORK_SIZE_SMALL) {
if (config == NETWORK_SIZE_SMALL || config == NETWORK_SIZE_CERTIFICATE) {
lifetime = PAN_VERSION_SMALL_NETWORK_TIMEOUT;
} else if (config == NETWORK_SIZE_MEDIUM) {
lifetime = PAN_VERSION_MEDIUM_NETWORK_TIMEOUT;

View File

@ -25,6 +25,7 @@
#include "fhss_config.h"
#include "net_fhss.h"
#include "NWK_INTERFACE/Include/protocol.h"
#include "6LoWPAN/ws/ws_config.h"
#include "6LoWPAN/ws/ws_common_defines.h"
#include "6LoWPAN/ws/ws_neighbor_class.h"
#include "Service_Libs/mac_neighbor_table/mac_neighbor_table.h"
@ -36,16 +37,20 @@ struct ws_pan_information_s;
struct ws_neighbor_class_s;
typedef struct parent_info_s {
uint16_t pan_id; /**< PAN ID */
uint8_t addr[8]; /**< address */
uint8_t link_quality; /**< LQI value measured during reception of the MPDU */
int8_t signal_dbm; /**< This extension for normal IEEE 802.15.4 Data indication */
uint16_t pan_id; /**< PAN ID */
uint8_t addr[8]; /**< address */
uint8_t link_quality; /**< LQI value measured during reception of the MPDU */
int8_t signal_dbm; /**< This extension for normal IEEE 802.15.4 Data indication */
ws_pan_information_t pan_information;
ws_utt_ie_t ws_utt;
ws_us_ie_t ws_us;
uint32_t timestamp; /**< Timestamp when packet was received */
ws_utt_ie_t ws_utt;
ws_us_ie_t ws_us;
uint32_t timestamp; /**< Timestamp when packet was received */
uint32_t age; /**< Age of entry in 100ms ticks */
ns_list_link_t link;
} parent_info_t;
typedef NS_LIST_HEAD(parent_info_t, link) parent_info_list_t;
typedef struct ws_nud_table_entry {
void *neighbor_info;
uint16_t timer; /*!< Timer which resolution is 100ms*/
@ -67,9 +72,13 @@ typedef struct ws_info_s {
trickle_t trickle_pan_advertisement;
trickle_params_t trickle_params_pan_discovery;
uint8_t network_size_config; // configuration for network size selection of application.
uint16_t rpl_parent_candidate_max;
uint16_t rpl_selected_parent_max;
uint8_t rpl_state; // state from rpl_event_t
uint8_t pas_requests; // Amount of PAN solicits sent
parent_info_t parent_info;
parent_info_t parent_info[WS_PARENT_LIST_SIZE];
parent_info_list_t parent_list_free;
parent_info_list_t parent_list_reserved;
uint32_t pan_version_timer; /**< border router version udate timeout */
uint32_t pan_version_timeout_timer; /**< routers will fallback to previous state after this */
uint8_t gtkhash[32];
@ -78,6 +87,7 @@ typedef struct ws_info_s {
bool trickle_pa_running: 1;
bool trickle_pcs_running: 1;
bool trickle_pc_running: 1;
bool fhss_owner: 1;
// default fhss parameters for this device
uint8_t fhss_uc_dwell_interval;
uint8_t fhss_bc_dwell_interval;
@ -116,7 +126,7 @@ void ws_common_fast_timer(protocol_interface_info_entry_t *cur, uint16_t ticks);
void ws_common_neighbor_update(protocol_interface_info_entry_t *cur, const uint8_t *ll_address);
void ws_common_aro_failure(protocol_interface_info_entry_t *cur, const uint8_t *ll_address);
void ws_common_aro_failure(protocol_interface_info_entry_t *cur, const uint8_t *ll_address, bool cache_full);
void ws_common_neighbor_remove(protocol_interface_info_entry_t *cur, const uint8_t *ll_address);
@ -136,7 +146,7 @@ uint32_t ws_common_version_timeout_get(uint8_t config);
#define ws_info(cur) ((ws_info_t *) NULL)
#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_aro_failure(cur, ll_address, cache_full)
#define ws_common_neighbor_remove(cur, ll_address)
#define ws_common_fast_timer(cur, ticks) ((void) 0)
#define ws_common_allow_child_registration(cur, eui64) (false)

View File

@ -186,7 +186,8 @@ typedef struct ws_bs_ie {
#define WS_FAN_VERSION_1_0 1
#define WS_NEIGHBOR_LINK_TIMEOUT 2200
#define WS_NEIGHBOR_TEMPORARY_LINK_MIN_TIMEOUT 120
#define WS_NEIGHBOR_TEMPORARY_LINK_MIN_TIMEOUT_LARGE 520
#define WS_NEIGHBOR_TEMPORARY_LINK_MIN_TIMEOUT_SMALL 260
#define WS_NEIGHBOR_NUD_TIMEOUT WS_NEIGHBOR_LINK_TIMEOUT / 2
#define WS_NEIGBOR_ETX_SAMPLE_MAX 3
@ -206,6 +207,12 @@ typedef struct ws_bs_ie {
#define WS_ETX_MIN_WAIT_TIME 60
#define WS_RPL_PARENT_CANDIDATE_MAX 5
#define WS_RPL_SELECTED_PARENT_MAX 2
#define WS_CERTIFICATE_RPL_PARENT_CANDIDATE_MAX 8
#define WS_CERTIFICATE_RPL_SELECTED_PARENT_MAX 3
/**
* Wi-sun spesific non-preferred prefix policy label
*/

View File

@ -31,6 +31,11 @@
#define WS_RPL_DIO_DOUBLING 2
#define WS_RPL_DIO_REDUNDANCY 0
#define WS_RPL_MIN_HOP_RANK_INCREASE 196
#define WS_RPL_MAX_HOP_RANK_INCREASE 2048
#define WS_CERTIFICATE_RPL_MIN_HOP_RANK_INCREASE 128
#define WS_CERTIFICATE_RPL_MAX_HOP_RANK_INCREASE 0
/* Border router version change interval
*
@ -130,6 +135,7 @@ extern uint8_t DEVICE_MIN_SENS;
* MAC frame counter NVM storing configuration
*/
#define FRAME_COUNTER_STORE_INTERVAL 60 // Time interval (on seconds) between frame counter store operations
#define FRAME_COUNTER_STORE_TRIGGER 5 // Delay (on seconds) before storing, when storing of frame counters is triggered
#define FRAME_COUNTER_INCREMENT 1000 // How much frame counter is incremented on start up
#define FRAME_COUNTER_STORE_THRESHOLD 800 // How much frame counter must increment before it is stored
@ -141,4 +147,20 @@ extern uint8_t DEVICE_MIN_SENS;
#define WS_MAX_DAO_INITIAL_TIMEOUT 400 // With 40s initial value exponentially increasing
#define WS_MIN_DIO_MULTICAST_CONFIG_ADVERTISMENT_COUNT 10 // Define 10 multicast advertisment when learn config or learn config update
/*
* Candidate parent list parameters
*/
#define WS_PARENT_LIST_SIZE 10
#define WS_PARENT_LIST_MAX_AGE 3600*10 // 1 hour in 100ms ticks
#define WS_PARENT_LIST_MAX_PAN_IN_DISCOVERY 5 // During discovery state how many neighbours per pan
#define WS_PARENT_LIST_MAX_PAN_IN_ACTIVE 2 // During active state two nodes per pan is allowed
/*
* Modifications for base specification.
*
* ERRATA changes after 1.0 specification release.
*/
#define WISUN_1_0_ERRATA_FIX
#endif /* WS_CONFIG_H_ */

View File

@ -37,9 +37,11 @@
#define TRACE_GROUP "wsep"
typedef struct {
uint8_t handle;
void *data_ptr;
void *buffer;
ws_eapol_pdu_tx_status *tx_status;
uint8_t tx_identifier;
uint8_t handle;
ns_list_link_t link;
} eapol_pdu_msdu_t;
@ -180,7 +182,7 @@ int8_t ws_eapol_pdu_cb_unregister(protocol_interface_info_entry_t *interface_ptr
return -1;
}
int8_t ws_eapol_pdu_send_to_mpx(protocol_interface_info_entry_t *interface_ptr, const uint8_t *eui_64, void *data, uint16_t size, void *buffer)
int8_t ws_eapol_pdu_send_to_mpx(protocol_interface_info_entry_t *interface_ptr, const uint8_t *eui_64, void *data, uint16_t size, void *buffer, ws_eapol_pdu_tx_status *tx_status, uint8_t tx_identifier)
{
eapol_pdu_data_t *eapol_pdu_data = ws_eapol_pdu_data_get(interface_ptr);
@ -198,6 +200,8 @@ 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->tx_status = tx_status;
msdu_entry->tx_identifier = tx_identifier;
ns_list_add_to_start(&eapol_pdu_data->msdu_list, msdu_entry);
memcpy(data_request.DstAddr, eui_64, 8);
@ -265,6 +269,15 @@ static void ws_eapol_pdu_mpx_data_confirm(const mpx_api_t *api, const struct mcp
ns_list_foreach(eapol_pdu_msdu_t, msdu, &eapol_pdu_data->msdu_list) {
if (msdu->handle == data->msduHandle) {
if (msdu->tx_status) {
eapol_pdu_tx_status_e status = EAPOL_PDU_TX_ERR_UNSPEC;
if (data->status == MLME_SUCCESS) {
status = EAPOL_PDU_TX_OK;
} else if (data->status == MLME_TX_NO_ACK) {
status = EAPOL_PDU_TX_ERR_TX_NO_ACK;
}
msdu->tx_status(eapol_pdu_data->interface_ptr, status, msdu->tx_identifier);
}
ns_dyn_mem_free(msdu->buffer);
ns_list_remove(&eapol_pdu_data->msdu_list, msdu);
ns_dyn_mem_free(msdu);

View File

@ -127,6 +127,22 @@ int8_t ws_eapol_pdu_cb_register(protocol_interface_info_entry_t *interface_ptr,
*/
int8_t ws_eapol_pdu_cb_unregister(protocol_interface_info_entry_t *interface_ptr, const eapol_pdu_recv_cb_data_t *cb_data);
typedef enum {
EAPOL_PDU_TX_OK = 0, // Successful
EAPOL_PDU_TX_ERR_TX_NO_ACK = -1, // No acknowledge was received
EAPOL_PDU_TX_ERR_UNSPEC = -2, // Other reason
} eapol_pdu_tx_status_e;
/**
* ws_eapol_pdu_tx_status will be called when TX status is known
*
* \param interface_ptr interface
* \param tx_status tx status
* \param tx_identifier tx identifier
*
*/
typedef int8_t ws_eapol_pdu_tx_status(protocol_interface_info_entry_t *interface_ptr, eapol_pdu_tx_status_e tx_status, uint8_t tx_identifier);
/**
* ws_eapol_pdu_send_to_mpx send EAPOL PDU to MPX
*
@ -135,11 +151,13 @@ int8_t ws_eapol_pdu_cb_unregister(protocol_interface_info_entry_t *interface_ptr
* \param data EAPOL PDU
* \param size PDU size
* \param buffer pointer to allocated buffer
* \param tx_status tx status callback
* \param tx_identifier tx identifier
*
* \return < 0 failure
* \return >= 0 success
*
*/
int8_t ws_eapol_pdu_send_to_mpx(protocol_interface_info_entry_t *interface_ptr, const uint8_t *eui_64, void *data, uint16_t size, void *buffer);
int8_t ws_eapol_pdu_send_to_mpx(protocol_interface_info_entry_t *interface_ptr, const uint8_t *eui_64, void *data, uint16_t size, void *buffer, ws_eapol_pdu_tx_status tx_status, uint8_t tx_identifier);
#endif /* WS_EAPOL_PDU_H_ */

View File

@ -183,7 +183,7 @@ static void ws_eapol_relay_socket_cb(void *cb)
}
//First 8 byte is EUID64 and rsr payload
if (ws_eapol_pdu_send_to_mpx(eapol_relay->interface_ptr, socket_pdu, socket_pdu + 8, cb_data->d_len - 8, socket_pdu) < 0) {
if (ws_eapol_pdu_send_to_mpx(eapol_relay->interface_ptr, socket_pdu, socket_pdu + 8, cb_data->d_len - 8, socket_pdu, NULL, 0) < 0) {
ns_dyn_mem_free(socket_pdu);
}
}

View File

@ -514,6 +514,11 @@ static void ws_llc_mac_indication_cb(const mac_api_t *api, const mcps_data_ind_t
return;
}
if (interface->mac_parameters->pan_id != 0xffff && data->SrcPANId != interface->mac_parameters->pan_id) {
//Drop wrong PAN-id messages in this phase.
return;
}
mpx_user_t *user_cb;
mac_payload_IE_t mpx_ie;
mpx_ie.id = MAC_PAYLOAD_MPX_IE_GROUP_ID;

View File

@ -136,18 +136,35 @@ int ws_management_network_size_set(
if (!cur || !ws_info(cur)) {
return -1;
}
if (network_size > NETWORK_SIZE_LARGE) {
return -2;
}
//Store old setup if new is not accepted
uint8_t old_setup = ws_info(cur)->network_size_config;
ws_info(cur)->network_size_config = network_size;
uint16_t rpl_parent_candidate_max;
uint16_t rpl_selected_parent_max;
if (network_size == NETWORK_SIZE_CERTIFICATE) {
rpl_parent_candidate_max = WS_CERTIFICATE_RPL_PARENT_CANDIDATE_MAX;
rpl_selected_parent_max = WS_CERTIFICATE_RPL_SELECTED_PARENT_MAX;
} else {
rpl_parent_candidate_max = WS_RPL_PARENT_CANDIDATE_MAX;
rpl_selected_parent_max = WS_RPL_SELECTED_PARENT_MAX;
}
if (network_size == NETWORK_SIZE_LARGE) {
ws_common_network_size_configure(cur, 5000);
} else if (network_size == NETWORK_SIZE_MEDIUM) {
ws_common_network_size_configure(cur, 200);
} else {
} else if (network_size == NETWORK_SIZE_SMALL) {
ws_common_network_size_configure(cur, 10);
} else if (network_size == NETWORK_SIZE_CERTIFICATE) {
ws_common_network_size_configure(cur, 0);
} else {
ws_info(cur)->network_size_config = old_setup;
return -2;
}
cur->ws_info->rpl_parent_candidate_max = rpl_parent_candidate_max;
cur->ws_info->rpl_selected_parent_max = rpl_selected_parent_max;
return 0;
}
@ -241,8 +258,20 @@ int ws_management_fhss_unicast_channel_function_configure(
channel_function != WS_TR51CF) {
return -2;
}
if (channel_function == WS_FIXED_CHANNEL && fixed_channel == 0xffff) {
fixed_channel = 0;
tr_warn("Fixed channel not configured. Set to 0");
}
cur->ws_info->fhss_uc_channel_function = channel_function;
cur->ws_info->fhss_uc_fixed_channel = fixed_channel;
if (cur->ws_info->fhss_uc_channel_function == WS_FIXED_CHANNEL) {
cur->ws_info->fhss_uc_fixed_channel = fixed_channel;
} else {
cur->ws_info->fhss_uc_fixed_channel = 0xffff;
}
cur->ws_info->fhss_uc_dwell_interval = dwell_interval;
// if settings change reset_restart for the settings needed
@ -273,8 +302,19 @@ int ws_management_fhss_broadcast_channel_function_configure(
channel_function != WS_TR51CF) {
return -2;
}
if (channel_function == WS_FIXED_CHANNEL && fixed_channel == 0xffff) {
fixed_channel = 0;
tr_warn("Fixed channel not configured. Set to 0");
}
cur->ws_info->fhss_bc_channel_function = channel_function;
cur->ws_info->fhss_bc_fixed_channel = fixed_channel;
if (cur->ws_info->fhss_bc_channel_function == WS_FIXED_CHANNEL) {
cur->ws_info->fhss_bc_fixed_channel = fixed_channel;
} else {
cur->ws_info->fhss_bc_fixed_channel = 0xffff;
}
cur->ws_info->fhss_bc_dwell_interval = dwell_interval;
cur->ws_info->fhss_bc_interval = broadcast_interval;

View File

@ -159,7 +159,7 @@ int8_t ws_pae_auth_init(protocol_interface_info_entry_t *interface_ptr, sec_prot
goto error;
}
if (kmp_service_cb_register(pae_auth->kmp_service, ws_pae_auth_kmp_incoming_ind, ws_pae_auth_kmp_service_addr_get, ws_pae_auth_kmp_service_api_get)) {
if (kmp_service_cb_register(pae_auth->kmp_service, ws_pae_auth_kmp_incoming_ind, NULL, ws_pae_auth_kmp_service_addr_get, ws_pae_auth_kmp_service_api_get)) {
goto error;
}
@ -171,7 +171,7 @@ int8_t ws_pae_auth_init(protocol_interface_info_entry_t *interface_ptr, sec_prot
goto error;
}
if (key_sec_prot_register(pae_auth->kmp_service) < 0) {
if (auth_key_sec_prot_register(pae_auth->kmp_service) < 0) {
goto error;
}

View File

@ -48,18 +48,11 @@ typedef int8_t ws_pae_gtk_hash_update(protocol_interface_info_entry_t *interface
typedef int8_t ws_pae_nw_key_index_update(protocol_interface_info_entry_t *interface_ptr, uint8_t index);
typedef struct {
uint8_t hash[8]; /**< GTK hash for the key */
uint8_t gtk[GTK_LEN]; /**< GTK key */
bool set : 1; /**< Key has been set */
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 {
uint8_t hash[8]; /**< GTK hash for the frame counter */
uint32_t frame_counter; /**< Frame counter */
uint8_t index; /**< Index */
bool set : 1; /**< Value has been set */
} stored_frame_counter_t;
typedef struct {
ns_list_link_t link; /**< Link */
uint8_t target_eui_64[8]; /**< EAPOL target */
@ -70,10 +63,10 @@ typedef struct {
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) */
nw_key_t nw_key[GTK_NUM]; /**< Currently active network keys (on MAC) */
char *network_name; /**< Network name for GAK generation */
uint16_t frame_cnt_store_timer; /**< Timer for storing frame counter value */
stored_frame_counter_t stored_frame_counter; /**< Stored frame counter */
frame_counters_t frame_counters; /**< Frame counters */
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 */
@ -105,9 +98,10 @@ typedef struct {
static pae_controller_t *ws_pae_controller_get(protocol_interface_info_entry_t *interface_ptr);
static void ws_pae_controller_frame_counter_timer(uint16_t seconds, pae_controller_t *entry);
static void ws_pae_controller_frame_counter_store(pae_controller_t *entry);
static void ws_pae_controller_frame_counter_timer_trigger(uint16_t seconds, pae_controller_t *entry);
static void ws_pae_controller_frame_counter_store(pae_controller_t *entry, bool use_threshold);
static void ws_pae_controller_nvm_frame_counter_write(nvm_tlv_entry_t *tlv_entry);
static int8_t ws_pae_controller_nvm_frame_counter_read(uint8_t *index, uint8_t *hash, uint32_t *frame_counter);
static int8_t ws_pae_controller_nvm_frame_counter_read(frame_counters_t *counters);
static pae_controller_t *ws_pae_controller_get_or_create(int8_t interface_id);
static void ws_pae_controller_gtk_hash_set(protocol_interface_info_entry_t *interface_ptr, uint8_t *gtkhash);
static int8_t ws_pae_controller_nw_key_check_and_insert(protocol_interface_info_entry_t *interface_ptr, sec_prot_gtk_keys_t *gtks);
@ -117,9 +111,7 @@ static int8_t ws_pae_controller_gak_from_gtk(uint8_t *gak, uint8_t *gtk, char *n
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 void ws_pae_controller_frame_counter_read(pae_controller_t *controller);
static void ws_pae_controller_frame_counter_reset(stored_frame_counter_t *counter);
static uint32_t ws_pae_controller_frame_counter_get(stored_frame_counter_t *counter, uint8_t index, uint8_t *key_hash);
static void ws_pae_controller_frame_counter_write(pae_controller_t *controller, uint8_t index, uint8_t *key_hash, uint32_t curr_counter);
static void ws_pae_controller_frame_counter_reset(frame_counters_t *frame_counters);
static const char *FRAME_COUNTER_FILE = FRAME_COUNTER_FILE_NAME;
@ -164,13 +156,14 @@ int8_t ws_pae_controller_authenticate(protocol_interface_info_entry_t *interface
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);
ws_pae_supp_gtks_set(controller->interface_ptr, &controller->gtks);
}
controller->auth_completed(interface_ptr, true);
controller->auth_completed(interface_ptr, AUTH_RESULT_OK, NULL);
return 0;
}
if (ws_pae_supp_authenticate(controller->interface_ptr, controller->target_pan_id, controller->target_eui_64) < 0) {
controller->auth_completed(interface_ptr, false);
controller->auth_completed(interface_ptr, AUTH_RESULT_ERR_UNSPEC, controller->target_eui_64);
}
#else
@ -178,7 +171,7 @@ int8_t ws_pae_controller_authenticate(protocol_interface_info_entry_t *interface
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);
controller->auth_completed(interface_ptr, AUTH_RESULT_OK);
#endif
return 0;
@ -320,63 +313,86 @@ int8_t ws_pae_controller_nw_key_valid(protocol_interface_info_entry_t *interface
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;
return -1;
}
uint8_t gtkhash[GTK_ALL_HASHES_LEN];
sec_prot_keys_gtks_hash_generate(gtks, gtkhash);
int8_t ret = -1;
// Adds, removes and updates network keys to MAC based on new GTKs
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);
// Gets GTK for the index (new, modified or none)
uint8_t *gtk = sec_prot_keys_gtk_get(gtks, i);
// If network key is set and GTK key is not set or not the same, removes network key
if (nw_key[i].set && (!gtk || memcmp(nw_key[i].gtk, gtk, GTK_LEN) != 0)) {
// Removes key from MAC if installed
if (nw_key[i].installed) {
controller->nw_key_clear(interface_ptr, i);
nw_key[i].installed = false;
}
nw_key[i].installed = false;
nw_key[i].set = false;
tr_info("NW key remove: %i", i);
}
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) {
// If GTK key is not set, continues to next GTK
if (!gtk) {
continue;
}
memcpy(nw_key[i].hash, gtk_hash_ptr, GTK_HASH_LEN);
// Network key is set and installed, all done
if (nw_key[i].set && nw_key[i].installed) {
continue;
}
// If network key is not set, stores the new GTK key to network key
if (!nw_key[i].set) {
nw_key[i].set = true;
nw_key[i].installed = false;
memcpy(nw_key[i].gtk, gtk, GTK_LEN);
}
// If network key has not been installed, installs it and updates frame counter as needed
if (!nw_key[i].installed) {
uint8_t gtkhash[GTK_HASH_LEN];
sec_prot_keys_gtk_hash_generate(gtk, gtkhash);
tr_info("NW key set: %i, hash: %s", i, trace_array(gtkhash, 8));
uint8_t gak[GTK_LEN];
if (ws_pae_controller_gak_from_gtk(gak, gtk, controller->network_name) >= 0) {
// Install the new network key derived from GTK and network name (GAK) to MAC
controller->nw_key_set(interface_ptr, i, i, gak);
tr_info("NW: %s", controller->network_name);
tr_info("NW: %s", trace_array((uint8_t *)controller->network_name, 20));
tr_info("GTK: %s", trace_array(gtk, 16));
tr_info("GAK: %s", trace_array(gak, 16));
nw_key[i].installed = true;
if (hash_matches != 0) {
nw_key[i].fresh = true;
}
ret = 0;
} else {
tr_error("GAK generation failed network name: %s", controller->network_name);
continue;
}
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;
// If frame counter value has been stored for the network key, updates the frame counter if needed
if (controller->frame_counters.counter[i].set &&
memcmp(gtk, controller->frame_counters.counter[i].gtk, GTK_LEN) == 0) {
// Read current counter from MAC
uint32_t curr_frame_counter;
controller->nw_frame_counter_read(controller->interface_ptr, &curr_frame_counter, i);
// If stored frame counter is greater than MAC counter
if (controller->frame_counters.counter[i].frame_counter > curr_frame_counter) {
tr_debug("Frame counter set: %i, stored %"PRIu32" current: %"PRIu32"", i, controller->frame_counters.counter[i].frame_counter, curr_frame_counter);
curr_frame_counter = controller->frame_counters.counter[i].frame_counter;
// Updates MAC frame counter
controller->nw_frame_counter_set(controller->interface_ptr, curr_frame_counter, i);
}
}
/* Trigger storing of frame counters; there is 5 seconds delay to give time for the
other keys to be inserted, so that frame counters for several keys are updated on
a same time. */
ws_pae_controller_frame_counter_timer_trigger(FRAME_COUNTER_STORE_TRIGGER, controller);
}
gtk_hash_ptr += GTK_HASH_LEN;
}
return ret;
@ -385,8 +401,8 @@ static int8_t ws_pae_controller_nw_key_check_and_insert(protocol_interface_info_
static void ws_pae_controller_active_nw_key_clear(nw_key_t *nw_key)
{
memset(nw_key, 0, sizeof(nw_key_t));
nw_key->set = false;
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)
@ -463,9 +479,12 @@ void ws_pae_controller_nw_keys_remove(protocol_interface_info_entry_t *interface
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)) {
if (nw_key[i].set) {
tr_info("NW key remove: %i", i);
controller->nw_key_clear(interface_ptr, i);
if (nw_key[i].installed) {
controller->nw_key_clear(interface_ptr, i);
}
nw_key[i].set = false;
nw_key[i].installed = false;
}
}
@ -482,14 +501,6 @@ static void ws_pae_controller_nw_key_index_check_and_set(protocol_interface_info
tr_info("NW send key index set: %i", index + 1);
controller->nw_send_key_index_set(interface_ptr, index);
controller->gtk_index = index;
uint32_t frame_counter = ws_pae_controller_frame_counter_get(&controller->stored_frame_counter, index, controller->nw_key[index].hash);
if (frame_counter) {
controller->nw_frame_counter_set(interface_ptr, frame_counter);
}
tr_info("NW frame counter set: %"PRIu32"", frame_counter);
ws_pae_controller_frame_counter_write(controller, index, controller->nw_key[index].hash, frame_counter);
}
// Do not update PAN version for initial key index set
@ -510,22 +521,13 @@ static void ws_pae_controller_active_nw_key_set(protocol_interface_info_entry_t
}
if (controller->nw_send_key_index_set) {
/* Checks if frame counters needs to be stored for the new GTK that is taken into
use; this is the last check that stored counters are in sync before activating key */
ws_pae_controller_frame_counter_store(controller, true);
// Activates key on MAC
controller->nw_send_key_index_set(controller->interface_ptr, index);
tr_info("NW send key index set: %i", index + 1);
// If index has changed and the key for the index is fresh get frame counter
if (controller->gtk_index != index && controller->nw_key[index].fresh) {
uint32_t frame_counter = ws_pae_controller_frame_counter_get(&controller->stored_frame_counter, index, controller->nw_key[index].hash);
if (frame_counter) {
controller->nw_frame_counter_set(cur, frame_counter);
}
tr_info("NW frame counter set: %"PRIu32"", frame_counter);
ws_pae_controller_frame_counter_write(controller, index, controller->nw_key[index].hash, frame_counter);
}
controller->gtk_index = index;
controller->nw_key[index].fresh = false;
}
}
@ -590,7 +592,7 @@ static void ws_pae_controller_data_init(pae_controller_t *controller)
controller->gtk_index = -1;
controller->network_name = NULL;
controller->frame_cnt_store_timer = FRAME_COUNTER_STORE_INTERVAL;
ws_pae_controller_frame_counter_reset(&controller->stored_frame_counter);
ws_pae_controller_frame_counter_reset(&controller->frame_counters);
sec_prot_keys_gtks_init(&controller->gtks);
sec_prot_keys_gtks_init(&controller->next_gtks);
sec_prot_certs_init(&controller->certs);
@ -600,49 +602,35 @@ static void ws_pae_controller_data_init(pae_controller_t *controller)
static void ws_pae_controller_frame_counter_read(pae_controller_t *controller)
{
stored_frame_counter_t *counter = &controller->stored_frame_counter;
// If not already, read frame counter and check if index and hash matches
if (!counter->set && ws_pae_controller_nvm_frame_counter_read(&counter->index, counter->hash, &counter->frame_counter) >= 0) {
counter->frame_counter += FRAME_COUNTER_INCREMENT;
counter->set = true;
tr_debug("Read frame counter: %"PRIu32", index %i, hash %s, system time: %"PRIu32"", counter->frame_counter, counter->index, trace_array(counter->hash, 8), protocol_core_monotonic_time / 10);
// Write incremented frame counter
ws_pae_nvm_store_frame_counter_tlv_create(controller->pae_nvm_buffer, counter->index, counter->hash, counter->frame_counter);
ws_pae_controller_nvm_frame_counter_write(controller->pae_nvm_buffer);
// Read frame counters
if (ws_pae_controller_nvm_frame_counter_read(&controller->frame_counters) >= 0) {
bool updated = false;
// Checks frame counters
for (uint8_t index = 0; index < GTK_NUM; index++) {
if (controller->frame_counters.counter[index].set) {
// Increments frame counters
controller->frame_counters.counter[index].frame_counter += FRAME_COUNTER_INCREMENT;
tr_info("Read frame counter: index %i value %"PRIu32"", index, controller->frame_counters.counter[index].frame_counter);
updated = true;
}
}
if (updated) {
// Writes incremented frame counters
ws_pae_nvm_store_frame_counter_tlv_create(controller->pae_nvm_buffer, &controller->frame_counters);
ws_pae_controller_nvm_frame_counter_write(controller->pae_nvm_buffer);
//ws_pae_controller_frame_counter_write(controller, &controller->frame_counters);
}
}
}
static void ws_pae_controller_frame_counter_reset(stored_frame_counter_t *counter)
static void ws_pae_controller_frame_counter_reset(frame_counters_t *frame_counters)
{
memset(counter->hash, 0, GTK_HASH_LEN);
counter->frame_counter = 0;
counter->index = -1;
counter->set = false;
}
static uint32_t ws_pae_controller_frame_counter_get(stored_frame_counter_t *counter, uint8_t index, uint8_t *key_hash)
{
uint32_t frame_counter = 0;
// If both index and hash matches uses the stored frame counter
if (counter->set && counter->index == index && memcmp(counter->hash, key_hash, GTK_HASH_LEN) == 0) {
frame_counter = counter->frame_counter;
}
return frame_counter;
}
static void ws_pae_controller_frame_counter_write(pae_controller_t *controller, uint8_t index, uint8_t *key_hash, uint32_t curr_frame_counter)
{
stored_frame_counter_t *counter = &controller->stored_frame_counter;
// If index or hash changes, or frame counter has been incremented by the threshold updates frame counter
if (!counter->set || counter->index != index || memcmp(key_hash, counter->hash, 8) != 0 || curr_frame_counter > counter->frame_counter + FRAME_COUNTER_STORE_THRESHOLD) {
ws_pae_nvm_store_frame_counter_tlv_create(controller->pae_nvm_buffer, index, key_hash, curr_frame_counter);
ws_pae_controller_nvm_frame_counter_write(controller->pae_nvm_buffer);
counter->index = index;
counter->frame_counter = curr_frame_counter;
memcpy(counter->hash, key_hash, GTK_HASH_LEN);
counter->set = true;
tr_debug("Stored frame counter: %"PRIu32", index %i, hash %s, system time: %"PRIu32"", curr_frame_counter, index, trace_array(key_hash, 8), protocol_core_monotonic_time / 10);
for (uint8_t index = 0; index < GTK_NUM; index++) {
memset(frame_counters->counter[index].gtk, 0, GTK_LEN);
frame_counters->counter[index].frame_counter = 0;
frame_counters->counter[index].set = false;
}
}
@ -702,7 +690,7 @@ int8_t ws_pae_controller_stop(protocol_interface_info_entry_t *interface_ptr)
}
// Stores frame counter
ws_pae_controller_frame_counter_store(controller);
ws_pae_controller_frame_counter_store(controller, false);
// Removes network keys from PAE controller and MAC
ws_pae_controller_nw_keys_remove(interface_ptr);
@ -965,7 +953,7 @@ int8_t ws_pae_controller_border_router_addr_read(protocol_interface_info_entry_t
return 0;
}
int8_t ws_pae_controller_gtk_update(int8_t interface_id, uint8_t *gtk[4])
int8_t ws_pae_controller_gtk_update(int8_t interface_id, uint8_t *gtk[GTK_NUM])
{
if (!gtk) {
return -1;
@ -989,6 +977,7 @@ int8_t ws_pae_controller_gtk_update(int8_t interface_id, uint8_t *gtk[4])
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) {
controller->gtks_set = true;
tr_info("GTK set index: %i, lifetime %"PRIu32", system time: %"PRIu32"", i, lifetime, protocol_core_monotonic_time / 10);
}
}
@ -1002,7 +991,7 @@ int8_t ws_pae_controller_gtk_update(int8_t interface_id, uint8_t *gtk[4])
return 0;
}
int8_t ws_pae_controller_next_gtk_update(int8_t interface_id, uint8_t *gtk[4])
int8_t ws_pae_controller_next_gtk_update(int8_t interface_id, uint8_t *gtk[GTK_NUM])
{
if (!gtk) {
return -1;
@ -1212,7 +1201,6 @@ void ws_pae_controller_slow_timer(uint16_t seconds)
if (entry->pae_slow_timer) {
entry->pae_slow_timer(seconds);
}
ws_pae_controller_frame_counter_timer(seconds, entry);
}
}
@ -1223,26 +1211,63 @@ static void ws_pae_controller_frame_counter_timer(uint16_t seconds, pae_controll
entry->frame_cnt_store_timer -= seconds;
} else {
entry->frame_cnt_store_timer = FRAME_COUNTER_STORE_INTERVAL;
ws_pae_controller_frame_counter_store(entry);
ws_pae_controller_frame_counter_store(entry, true);
}
}
static void ws_pae_controller_frame_counter_store(pae_controller_t *entry)
static void ws_pae_controller_frame_counter_timer_trigger(uint16_t seconds, pae_controller_t *entry)
{
// Gets index of active GTK
int8_t active_index = entry->gtk_index;
if (active_index >= 0) {
// Gets hash of the key
uint8_t *hash = entry->nw_key[active_index].hash;
uint32_t curr_frame_counter;
entry->nw_frame_counter_read(entry->interface_ptr, &curr_frame_counter);
ws_pae_controller_frame_counter_write(entry, active_index, hash, curr_frame_counter);
if (entry->frame_cnt_store_timer > seconds) {
entry->frame_cnt_store_timer = seconds;
}
}
static int8_t ws_pae_controller_nvm_frame_counter_read(uint8_t *index, uint8_t *hash, uint32_t *frame_counter)
static void ws_pae_controller_frame_counter_store(pae_controller_t *entry, bool use_threshold)
{
bool update_needed = false;
for (int i = 0; i < GTK_NUM; i++) {
/* If network key is set, checks if frame counter needs to be updated to NVM
* Note! The frame counters for non-installed keys (previous frame counters) are not changed.
* This is because GTKs are removed e.g. if PAN configuration is not heard/cannot be
* de-crypted during a bootstrap. If BR later installs previous keys using 4WH/GKH, the
* frame counters will be still valid.
*/
if (entry->nw_key[i].installed) {
// Reads frame counter for the key
uint32_t curr_frame_counter;
entry->nw_frame_counter_read(entry->interface_ptr, &curr_frame_counter, i);
// If frame counter for the network key has already been stored
if (entry->frame_counters.counter[i].set &&
memcmp(entry->nw_key[i].gtk, entry->frame_counters.counter[i].gtk, GTK_LEN) == 0) {
// If threshold check is disabled or frame counter has advanced for the threshold value, stores the new value
if (!use_threshold ||
curr_frame_counter > entry->frame_counters.counter[i].frame_counter + FRAME_COUNTER_STORE_THRESHOLD) {
entry->frame_counters.counter[i].frame_counter = curr_frame_counter;
update_needed = true;
tr_debug("Stored updated frame counter: index %i value %"PRIu32"", i, curr_frame_counter);
}
} else {
// For new or modified network keys, stores the frame counter value
entry->frame_counters.counter[i].set = true;
memcpy(entry->frame_counters.counter[i].gtk, entry->nw_key[i].gtk, GTK_LEN);
entry->frame_counters.counter[i].frame_counter = curr_frame_counter;
update_needed = true;
tr_debug("Stored new frame counter: index %i value %"PRIu32"", i, curr_frame_counter);
}
}
}
if (update_needed) {
tr_debug("Write frame counters: system time %"PRIu32"", protocol_core_monotonic_time / 10);
// Writes modified frame counters
ws_pae_nvm_store_frame_counter_tlv_create(entry->pae_nvm_buffer, &entry->frame_counters);
ws_pae_controller_nvm_frame_counter_write(entry->pae_nvm_buffer);
}
}
static int8_t ws_pae_controller_nvm_frame_counter_read(frame_counters_t *counters)
{
nvm_tlv_list_t tlv_list;
ns_list_init(&tlv_list);
@ -1253,7 +1278,7 @@ static int8_t ws_pae_controller_nvm_frame_counter_read(uint8_t *index, uint8_t *
int8_t result = -1;
ns_list_foreach_safe(nvm_tlv_entry_t, entry, &tlv_list) {
if (ws_pae_nvm_store_frame_counter_tlv_read(entry, index, hash, frame_counter) >= 0) {
if (ws_pae_nvm_store_frame_counter_tlv_read(entry, counters) >= 0) {
result = 0;
}
ns_list_remove(&tlv_list, entry);

View File

@ -20,7 +20,15 @@
#ifdef HAVE_WS
typedef enum {
AUTH_RESULT_OK = 0, // Successful
AUTH_RESULT_ERR_NO_MEM = -1, // No memory
AUTH_RESULT_ERR_TX_NO_ACK = -2, // No acknowledge was received
AUTH_RESULT_ERR_UNSPEC = -3 // Other reason
} auth_result_e;
struct nvm_tlv_entry;
/**
* ws_pae_controller_set_target sets EAPOL target for PAE supplicant
*
@ -467,9 +475,10 @@ typedef void ws_pae_controller_nw_send_key_index_set(protocol_interface_info_ent
*
* \param interface_ptr interface
* \param counter frame counter
* \param slot key slot (MAC key descriptor), from 0 to 4
*
*/
typedef void ws_pae_controller_nw_frame_counter_set(protocol_interface_info_entry_t *interface_ptr, uint32_t counter);
typedef void ws_pae_controller_nw_frame_counter_set(protocol_interface_info_entry_t *interface_ptr, uint32_t counter, uint8_t slot);
/**
* ws_pae_controller_nw_frame_counter_read network frame counter read callback
@ -478,16 +487,17 @@ typedef void ws_pae_controller_nw_frame_counter_set(protocol_interface_info_entr
* \param counter frame counter
*
*/
typedef void ws_pae_controller_nw_frame_counter_read(protocol_interface_info_entry_t *interface_ptr, uint32_t *counter);
typedef void ws_pae_controller_nw_frame_counter_read(protocol_interface_info_entry_t *interface_ptr, uint32_t *counter, uint8_t slot);
/**
* ws_pae_controller_auth_completed authentication completed callback
*
* \param interface_ptr interface
* \param success true if authentication was successful
* \param result result, either ok or failure reason
* \param target_eui_64 EAPOL target in case of failure or NULL
*
*/
typedef void ws_pae_controller_auth_completed(protocol_interface_info_entry_t *interface_ptr, bool success);
typedef void ws_pae_controller_auth_completed(protocol_interface_info_entry_t *interface_ptr, auth_result_e result, uint8_t *target_eui_64);
/**
* ws_pae_controller_pan_ver_increment PAN version increment callback

View File

@ -93,6 +93,17 @@ kmp_api_t *ws_pae_lib_kmp_list_type_get(kmp_list_t *kmp_list, kmp_type_e type)
return kmp;
}
kmp_api_t *ws_pae_lib_kmp_list_instance_id_get(kmp_list_t *kmp_list, uint8_t instance_id)
{
ns_list_foreach(kmp_entry_t, cur, kmp_list) {
if (kmp_api_instance_id_get(cur->kmp) == instance_id) {
return cur->kmp;
}
}
return NULL;
}
void ws_pae_lib_kmp_list_free(kmp_list_t *kmp_list)
{
ns_list_foreach_safe(kmp_entry_t, cur, kmp_list) {

View File

@ -88,7 +88,7 @@ int8_t ws_pae_lib_kmp_list_delete(kmp_list_t *kmp_list, kmp_api_t *kmp);
void ws_pae_lib_kmp_list_free(kmp_list_t *kmp_list);
/**
* ws_pae_lib_kmp_list_type_get gets KMP entry from KMP list based on KMP type
* ws_pae_lib_kmp_list_type_get gets KMP from KMP list based on KMP type
*
* \param kmp_list KMP list
* \param type type
@ -99,6 +99,18 @@ void ws_pae_lib_kmp_list_free(kmp_list_t *kmp_list);
*/
kmp_api_t *ws_pae_lib_kmp_list_type_get(kmp_list_t *kmp_list, kmp_type_e type);
/**
* ws_pae_lib_kmp_list_instance_id_get gets KMP from KMP list based on instance identifier
*
* \param kmp_list KMP list
* \param instance_id instance identifier
*
* \return KMP on success
* \return NULL on failure
*
*/
kmp_api_t *ws_pae_lib_kmp_list_instance_id_get(kmp_list_t *kmp_list, uint8_t instance_id);
/**
* ws_pae_lib_kmp_list_entry_get gets KMP entry from KMP list based on KMP
*

View File

@ -43,8 +43,11 @@
// PTK EUI-64 set (1) + PTK EUI-64 (8) + PMK set (1) + PMK (32) + PMK replay counter (8) + PTK set (1) + PTK (48)
#define PAE_NVM_KEYS_LEN 1 + 8 + 1 + PMK_LEN + 8 + 1 + PTK_LEN
// GTK hash (8), frame counter (4), index (1)
#define PAE_NVM_FRAME_COUNTER_LEN 8 + 4 + 1
// (frame counter set (1) + GTK (16) + frame counter (4)) * 4
#define PAE_NVM_FRAME_COUNTER_LEN (1 + GTK_LEN + 4) * GTK_NUM
#define PAE_NVM_FIELD_NOT_SET 0 // Field is not present
#define PAE_NVM_FIELD_SET 1 // Field is present
nvm_tlv_entry_t *ws_pae_buffer_allocate(void)
{
@ -68,7 +71,7 @@ void ws_pae_nvm_store_nw_info_tlv_create(nvm_tlv_entry_t *tlv_entry, uint16_t pa
for (uint8_t i = 0; i < GTK_NUM; i++) {
if (sec_prot_keys_gtk_is_set(gtks, i)) {
*tlv++ = 1; // GTK is set
*tlv++ = PAE_NVM_FIELD_SET; // GTK is set
uint32_t lifetime = sec_prot_keys_gtk_lifetime_get(gtks, i);
tlv = common_write_32_bit(lifetime, tlv);
@ -76,7 +79,7 @@ void ws_pae_nvm_store_nw_info_tlv_create(nvm_tlv_entry_t *tlv_entry, uint16_t pa
memcpy(tlv, gtk, GTK_LEN);
tlv += GTK_LEN;
} else {
*tlv++ = 0; // GTK is not set
*tlv++ = PAE_NVM_FIELD_NOT_SET; // GTK is not set
memset(tlv, 0, 4 + GTK_LEN);
tlv += 4 + GTK_LEN;
}
@ -106,7 +109,7 @@ int8_t ws_pae_nvm_store_nw_info_tlv_read(nvm_tlv_entry_t *tlv_entry, uint16_t *p
tlv += 33;
for (uint8_t i = 0; i < GTK_NUM; i++) {
if (*tlv++ == 1) { /* GTK is set */
if (*tlv++ == PAE_NVM_FIELD_SET) { /* GTK is set */
uint32_t lifetime = common_read_32_bit(tlv);
tlv += 4;
sec_prot_keys_gtk_set(gtks, i, tlv, lifetime);
@ -131,20 +134,20 @@ void ws_pae_nvm_store_keys_tlv_create(nvm_tlv_entry_t *tlv_entry, sec_prot_keys_
uint8_t *eui_64 = sec_prot_keys_ptk_eui_64_get(sec_keys);
if (eui_64) {
*tlv++ = 1;
*tlv++ = PAE_NVM_FIELD_SET;
memcpy(tlv, eui_64, 8);
} else {
*tlv++ = 0;
*tlv++ = PAE_NVM_FIELD_NOT_SET;
memset(tlv, 0, 8);
}
tlv += 8;
uint8_t *pmk = sec_prot_keys_pmk_get(sec_keys);
if (pmk) {
*tlv++ = 1;
*tlv++ = PAE_NVM_FIELD_SET;
memcpy(tlv, pmk, PMK_LEN);
} else {
*tlv++ = 0;
*tlv++ = PAE_NVM_FIELD_NOT_SET;
memset(tlv, 0, PMK_LEN);
}
tlv += PMK_LEN;
@ -154,10 +157,10 @@ void ws_pae_nvm_store_keys_tlv_create(nvm_tlv_entry_t *tlv_entry, sec_prot_keys_
uint8_t *ptk = sec_prot_keys_ptk_get(sec_keys);
if (ptk) {
*tlv++ = 1;
*tlv++ = PAE_NVM_FIELD_SET;
memcpy(tlv, ptk, PTK_LEN);
} else {
*tlv++ = 0;
*tlv++ = PAE_NVM_FIELD_NOT_SET;
memset(tlv, 0, PTK_LEN);
}
tlv += PTK_LEN;
@ -179,13 +182,13 @@ int8_t ws_pae_nvm_store_keys_tlv_read(nvm_tlv_entry_t *tlv_entry, sec_prot_keys_
uint8_t *tlv = ((uint8_t *) &tlv_entry->tag) + NVM_TLV_FIXED_LEN;
// EUI-64 set */
if (*tlv++ == 1) {
if (*tlv++ == PAE_NVM_FIELD_SET) {
sec_prot_keys_ptk_eui_64_write(sec_keys, tlv);
}
tlv += 8;
// PMK set
if (*tlv++ == 1) {
if (*tlv++ == PAE_NVM_FIELD_SET) {
sec_prot_keys_pmk_write(sec_keys, tlv);
}
tlv += PMK_LEN;
@ -195,7 +198,7 @@ int8_t ws_pae_nvm_store_keys_tlv_read(nvm_tlv_entry_t *tlv_entry, sec_prot_keys_
sec_prot_keys_pmk_replay_cnt_set(sec_keys, counter);
// PTK set
if (*tlv++ == 1) {
if (*tlv++ == PAE_NVM_FIELD_SET) {
sec_prot_keys_ptk_write(sec_keys, tlv);
}
@ -208,25 +211,32 @@ int8_t ws_pae_nvm_store_keys_tlv_read(nvm_tlv_entry_t *tlv_entry, sec_prot_keys_
return 0;
}
void ws_pae_nvm_store_frame_counter_tlv_create(nvm_tlv_entry_t *tlv_entry, uint8_t index, uint8_t *hash, uint32_t frame_counter)
void ws_pae_nvm_store_frame_counter_tlv_create(nvm_tlv_entry_t *tlv_entry, frame_counters_t *counters)
{
tlv_entry->tag = PAE_NVM_FRAME_COUNTER_TAG;
tlv_entry->len = PAE_NVM_FRAME_COUNTER_LEN;
uint8_t *tlv = ((uint8_t *) &tlv_entry->tag) + NVM_TLV_FIXED_LEN;
memcpy(tlv, hash, GTK_HASH_LEN);
tlv += GTK_HASH_LEN;
tlv = common_write_32_bit(frame_counter, tlv);
*tlv = index;
for (uint8_t index = 0; index < GTK_NUM; index++) {
if (!counters->counter[index].set) {
*tlv++ = PAE_NVM_FIELD_NOT_SET;
memset(tlv, 0, GTK_LEN + 4);
tlv += GTK_LEN + 4;
continue;
}
*tlv++ = PAE_NVM_FIELD_SET;
memcpy(tlv, counters->counter[index].gtk, GTK_LEN);
tlv += GTK_LEN;
tlv = common_write_32_bit(counters->counter[index].frame_counter, tlv);
}
tr_debug("NVM FRAME COUNTER write");
}
int8_t ws_pae_nvm_store_frame_counter_tlv_read(nvm_tlv_entry_t *tlv_entry, uint8_t *index, uint8_t *hash, uint32_t *frame_counter)
int8_t ws_pae_nvm_store_frame_counter_tlv_read(nvm_tlv_entry_t *tlv_entry, frame_counters_t *counters)
{
if (!tlv_entry || !frame_counter) {
if (!tlv_entry || !counters) {
return -1;
}
@ -236,11 +246,20 @@ int8_t ws_pae_nvm_store_frame_counter_tlv_read(nvm_tlv_entry_t *tlv_entry, uint8
uint8_t *tlv = ((uint8_t *) &tlv_entry->tag) + NVM_TLV_FIXED_LEN;
memcpy(hash, tlv, GTK_HASH_LEN);
tlv += GTK_HASH_LEN;
*frame_counter = common_read_32_bit(tlv);
tlv += 4;
*index = *tlv;
for (uint8_t index = 0; index < GTK_NUM; index++) {
// Frame counter not set
if (*tlv++ == PAE_NVM_FIELD_NOT_SET) {
counters->counter[index].set = false;
tlv += GTK_LEN + 4;
continue;
}
// Frame counter is set, read GTK key and counter values
counters->counter[index].set = true;
memcpy(counters->counter[index].gtk, tlv, GTK_LEN);
tlv += GTK_LEN;
counters->counter[index].frame_counter = common_read_32_bit(tlv);
tlv += 4;
}
tr_debug("NVM FRAME COUNTER read");

View File

@ -76,27 +76,22 @@ int8_t ws_pae_nvm_store_keys_tlv_read(nvm_tlv_entry_t *tlv_entry, sec_prot_keys_
* ws_pae_nvm_store_frame_counter_tlv_create create NVM frame counter TLV
*
* \param tlv_entry TLV entry buffer pointer
* \param index index
* \param hash hash
* \param frame_counter frame counter
*
* \param counters frame counters
*
*/
void ws_pae_nvm_store_frame_counter_tlv_create(nvm_tlv_entry_t *tlv_entry, uint8_t index, uint8_t *hash, uint32_t frame_counter);
void ws_pae_nvm_store_frame_counter_tlv_create(nvm_tlv_entry_t *tlv_entry, frame_counters_t *counters);
/**
* ws_pae_nvm_store_frame_counter_tlv_read read from NVM frame counter TLV
*
* \param tlv_entry TLV entry
* \param index index
* \param hash hash
* \param frame_counter frame counter
* \param counters frame counters
*
* \return < 0 failure
* \return >= 0 success
*
*/
int8_t ws_pae_nvm_store_frame_counter_tlv_read(nvm_tlv_entry_t *tlv_entry, uint8_t *index, uint8_t *hash, uint32_t *frame_counter);
int8_t ws_pae_nvm_store_frame_counter_tlv_read(nvm_tlv_entry_t *tlv_entry, frame_counters_t *counters);
nvm_tlv_entry_t *ws_pae_buffer_allocate(void);

View File

@ -99,7 +99,7 @@ typedef struct {
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; /**< Initial EAPOL-Key Trickle timer running */
bool auth_requested : 1; /**< Authentication has been requested */
bool auth_requested : 1; /**< Authentication has been requested by the bootstrap */
bool timer_running : 1; /**< Timer is running */
bool new_br_eui_64_set : 1; /**< Border router address has been set */
bool new_br_eui_64_fresh : 1; /**< Border router address is fresh (set during this authentication attempt) */
@ -117,7 +117,7 @@ static trickle_params_t initial_eapol_key_trickle_params = {
};
static void ws_pae_supp_free(pae_supp_t *pae_supp);
static void ws_pae_supp_authenticate_response(pae_supp_t *pae_supp, bool success);
static void ws_pae_supp_authenticate_response(pae_supp_t *pae_supp, auth_result_e result);
static int8_t ws_pae_supp_initial_key_send(pae_supp_t *pae_supp);
static void ws_pae_supp_nvm_update(pae_supp_t *pae_supp);
static int8_t ws_pae_supp_nw_keys_valid_check(pae_supp_t *pae_supp, uint16_t pan_id);
@ -134,6 +134,7 @@ static bool ws_pae_supp_timer_running(pae_supp_t *pae_supp);
static void ws_pae_supp_kmp_service_addr_get(kmp_service_t *service, kmp_api_t *kmp, kmp_addr_t *local_addr, kmp_addr_t *remote_addr);
static kmp_api_t *ws_pae_supp_kmp_service_api_get(kmp_service_t *service, kmp_api_t *kmp, kmp_type_e type);
static kmp_api_t *ws_pae_supp_kmp_incoming_ind(kmp_service_t *service, kmp_type_e type, const kmp_addr_t *addr);
static kmp_api_t *ws_pae_supp_kmp_tx_status_ind(kmp_service_t *service, uint8_t instance_id);
static kmp_api_t *ws_pae_supp_kmp_create_and_start(kmp_service_t *service, kmp_type_e type, pae_supp_t *pae_supp);
static int8_t ws_pae_supp_eapol_pdu_address_check(protocol_interface_info_entry_t *interface_ptr, const uint8_t *eui_64);
static int8_t ws_pae_supp_parent_eui_64_get(protocol_interface_info_entry_t *interface_ptr, uint8_t *eui_64);
@ -143,6 +144,7 @@ static void ws_pae_supp_kmp_api_create_indication(kmp_api_t *kmp, kmp_type_e typ
static void ws_pae_supp_kmp_api_finished_indication(kmp_api_t *kmp, kmp_result_e result, kmp_sec_keys_t *sec_keys);
static void ws_pae_supp_kmp_api_finished(kmp_api_t *kmp);
static const eapol_pdu_recv_cb_data_t eapol_pdu_recv_cb_data = {
.priority = EAPOL_PDU_RECV_HIGH_PRIORITY,
.addr_check = ws_pae_supp_eapol_pdu_address_check,
@ -179,7 +181,7 @@ int8_t ws_pae_supp_authenticate(protocol_interface_info_entry_t *interface_ptr,
}
if (ws_pae_supp_nw_keys_valid_check(pae_supp, dest_pan_id) >= 0) {
pae_supp->auth_completed(interface_ptr, true);
pae_supp->auth_completed(interface_ptr, AUTH_RESULT_OK, NULL);
return 0;
}
@ -354,6 +356,18 @@ int8_t ws_pae_supp_nw_key_index_update(protocol_interface_info_entry_t *interfac
return 0;
}
int8_t ws_pae_supp_gtks_set(protocol_interface_info_entry_t *interface_ptr, sec_prot_gtk_keys_t *gtks)
{
pae_supp_t *pae_supp = ws_pae_supp_get(interface_ptr);
if (!pae_supp) {
return -1;
}
pae_supp->gtks = *gtks;
return 0;
}
int8_t ws_pae_supp_eapol_target_remove(protocol_interface_info_entry_t *interface_ptr)
{
pae_supp_t *pae_supp = ws_pae_supp_get(interface_ptr);
@ -381,8 +395,6 @@ static void ws_pae_supp_nvm_update(pae_supp_t *pae_supp)
ws_pae_supp_nvm_keys_write(pae_supp);
sec_prot_keys_updated_reset(&pae_supp->entry.sec_keys);
}
}
static int8_t ws_pae_supp_nvm_nw_info_write(pae_supp_t *pae_supp)
@ -457,12 +469,16 @@ static int8_t ws_pae_supp_nvm_keys_read(pae_supp_t *pae_supp)
return 0;
}
static void ws_pae_supp_authenticate_response(pae_supp_t *pae_supp, bool success)
static void ws_pae_supp_authenticate_response(pae_supp_t *pae_supp, auth_result_e result)
{
pae_supp->auth_trickle_running = false;
if (pae_supp->auth_requested && pae_supp->auth_completed) {
pae_supp->auth_requested = false;
pae_supp->auth_completed(pae_supp->interface_ptr, success);
uint8_t *target_eui_64 = NULL;
if (result != AUTH_RESULT_OK) {
target_eui_64 = pae_supp->target_addr.eui_64;
}
pae_supp->auth_completed(pae_supp->interface_ptr, result, target_eui_64);
}
}
@ -605,7 +621,7 @@ int8_t ws_pae_supp_init(protocol_interface_info_entry_t *interface_ptr, const se
goto error;
}
if (kmp_service_cb_register(pae_supp->kmp_service, ws_pae_supp_kmp_incoming_ind, ws_pae_supp_kmp_service_addr_get, ws_pae_supp_kmp_service_api_get) < 0) {
if (kmp_service_cb_register(pae_supp->kmp_service, ws_pae_supp_kmp_incoming_ind, ws_pae_supp_kmp_tx_status_ind, ws_pae_supp_kmp_service_addr_get, ws_pae_supp_kmp_service_api_get) < 0) {
goto error;
}
@ -625,7 +641,7 @@ int8_t ws_pae_supp_init(protocol_interface_info_entry_t *interface_ptr, const se
goto error;
}
if (key_sec_prot_register(pae_supp->kmp_service) < 0) {
if (supp_key_sec_prot_register(pae_supp->kmp_service) < 0) {
goto error;
}
@ -788,7 +804,7 @@ void ws_pae_supp_fast_timer(uint16_t ticks)
if (!pae_supp->initial_key_timer && !pae_supp->auth_trickle_running && !running) {
tr_debug("PAE idle");
// If not already completed, restart bootstrap
ws_pae_supp_authenticate_response(pae_supp, false);
ws_pae_supp_authenticate_response(pae_supp, AUTH_RESULT_ERR_UNSPEC);
ws_pae_supp_timer_stop(pae_supp);
}
@ -808,7 +824,7 @@ void ws_pae_supp_slow_timer(uint16_t seconds)
}
// 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);
ws_pae_supp_authenticate_response(pae_supp, AUTH_RESULT_ERR_UNSPEC);
}
}
@ -1087,7 +1103,7 @@ static void ws_pae_supp_kmp_api_create_confirm(kmp_api_t *kmp, kmp_result_e resu
// KMP-CREATE.request has failed, authentication error
if (result != KMP_RESULT_OK) {
ws_pae_supp_authenticate_response(pae_supp, false);
ws_pae_supp_authenticate_response(pae_supp, AUTH_RESULT_ERR_UNSPEC);
}
}
@ -1115,14 +1131,24 @@ 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);
}
/* When 4WH or GKH completes inserts keys and indicates authentication completed
(if not alredy indicated) */
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);
ws_pae_supp_authenticate_response(pae_supp, AUTH_RESULT_OK);
}
/* If initial EAPOL-key message sending fails to tx no acknowledge, indicates failure so
that bootstrap can decide if EAPOL target should be changed */
else if (type > IEEE_802_1X_INITIAL_KEY && result == KMP_RESULT_ERR_TX_NO_ACK) {
tr_info("Initial EAPOL-Key TX failure, target: %s", trace_array(kmp_address_eui_64_get(&pae_supp->entry.addr), 8));
ws_pae_supp_authenticate_response(pae_supp, AUTH_RESULT_ERR_TX_NO_ACK);
}
}
static void ws_pae_supp_kmp_api_finished(kmp_api_t *kmp)
@ -1137,6 +1163,21 @@ static void ws_pae_supp_kmp_api_finished(kmp_api_t *kmp)
ws_pae_lib_kmp_list_delete(&pae_supp->entry.kmp_list, kmp);
}
static kmp_api_t *ws_pae_supp_kmp_tx_status_ind(kmp_service_t *service, uint8_t instance_id)
{
pae_supp_t *pae_supp = ws_pae_supp_by_kmp_service_get(service);
if (!pae_supp) {
return NULL;
}
kmp_api_t *kmp = ws_pae_lib_kmp_list_instance_id_get(&pae_supp->entry.kmp_list, instance_id);
if (!kmp) {
return NULL;
}
return kmp;
}
#endif /* HAVE_PAE_SUPP */
#endif /* HAVE_WS */

View File

@ -182,6 +182,18 @@ int8_t ws_pae_supp_gtk_hash_update(protocol_interface_info_entry_t *interface_pt
*/
int8_t ws_pae_supp_nw_key_index_update(protocol_interface_info_entry_t *interface_ptr, uint8_t index);
/**
* ws_pae_supp_gtks_set set supplicant GTKs
*
* \param interface_ptr interface
* \param gtks GTKs
*
* \return < 0 failure
* \return >= 0 success
*
*/
int8_t ws_pae_supp_gtks_set(protocol_interface_info_entry_t *interface_ptr, sec_prot_gtk_keys_t *gtks);
/**
* ws_pae_supp_eapol_target_remove remove EAPOL target set using authentication start
*
@ -206,10 +218,11 @@ typedef void ws_pae_supp_nw_key_index_set(protocol_interface_info_entry_t *inter
* ws_pae_supp_auth_completed authentication completed callback
*
* \param interface_ptr interface
* \param success true if authentication was successful
* \param result result, either ok or failure reason
* \param target_eui_64 EAPOL target in case of failure or NULL
*
*/
typedef void ws_pae_supp_auth_completed(protocol_interface_info_entry_t *interface_ptr, bool success);
typedef void ws_pae_supp_auth_completed(protocol_interface_info_entry_t *interface_ptr, auth_result_e result, uint8_t *target_eui_64);
/**
* ws_pae_supp_nw_key_insert network key insert callback
@ -249,6 +262,7 @@ void ws_pae_supp_cb_register(protocol_interface_info_entry_t *interface_ptr, ws_
#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
#define ws_pae_supp_gtks_set(interface_ptr, gtks)
#define ws_pae_supp_eapol_target_remove(interface_ptr)
#endif

View File

@ -356,7 +356,7 @@ static void icmpv6_na_wisun_aro_handler(protocol_interface_info_entry_t *cur_int
(void)life_time;
if (nd_status != ARO_SUCCESS) {
ws_common_aro_failure(cur_interface, src_addr);
ws_common_aro_failure(cur_interface, src_addr, true);
}
}
@ -1389,7 +1389,7 @@ static void icmpv6_aro_cb(buffer_t *buf, uint8_t status)
}
rpl_control_address_register_done(buf->interface, ll_address, status);
if (status != SOCKET_TX_DONE) {
ws_common_aro_failure(buf->interface, ll_address);
ws_common_aro_failure(buf->interface, ll_address, false);
}
}

View File

@ -90,7 +90,11 @@ int DHCPv6_server_respond_client(dhcpv6_gua_server_entry_s *serverBase, dhcpv6_r
dhcpv6_alloacted_address_entry_t *dhcp_allocated_address;
dhcpv6_ia_non_temporal_address_s nonTemporalAddress;
bool address_allocated = false;
dhcp_allocated_address = libdhcpv6_address_allocated_list_scan(serverBase, replyPacket->clientDUID.linkID, replyPacket->clientDUID.linkType, dhcp_ia_non_temporal_params->iaId, dhcp_ia_non_temporal_params->T0, dhcp_ia_non_temporal_params->T1, allocateNew);
//Validate Client DUID
dhcp_link_options_params_t clientDUID;
if (libdhcpv6_get_link_address_from_duid(replyPacket->clientDUID.duid, replyPacket->clientDUID.duid_length, replyPacket->clientDUID.type, &clientDUID) == 0) {
dhcp_allocated_address = libdhcpv6_address_allocated_list_scan(serverBase, clientDUID.link_id, clientDUID.link_type, dhcp_ia_non_temporal_params->iaId, dhcp_ia_non_temporal_params->T0, dhcp_ia_non_temporal_params->T1, allocateNew);
}
if (dhcp_allocated_address) {
address_allocated = true;
nonTemporalAddress.requestedAddress = dhcp_allocated_address->nonTemporalAddress;
@ -110,7 +114,7 @@ int DHCPv6_server_respond_client(dhcpv6_gua_server_entry_s *serverBase, dhcpv6_r
}
}
response->responseLength = libdhcpv6_address_reply_message_len(replyPacket->clientDUID.linkType, replyPacket->serverDUID.linkType, 0, replyPacket->rapidCommit, address_allocated);
response->responseLength = libdhcpv6_address_reply_message_len(replyPacket->clientDUID.duid_length, replyPacket->serverDUID.duid_length, 0, replyPacket->rapidCommit, address_allocated);
response->responsePtr = ns_dyn_mem_temporary_alloc(response->responseLength);
if (response->responsePtr) {
if (address_allocated) {
@ -141,16 +145,13 @@ int DHCPV6_server_service_request_handler(uint16_t instance_id, uint32_t msg_tr_
if (serverBase) {
//Here Allocate address
replyPacket.rapidCommit = libdhcpv6_rapid_commit_option_at_packet(msg_ptr, msg_len);
replyPacket.serverDUID.linkID = serverBase->serverDUID;
replyPacket.serverDUID.linkType = serverBase->serverLinkType;
replyPacket.serverDUID = serverBase->serverDUID;
replyPacket.T0 = dhcp_ia_non_temporal_params.T0;
replyPacket.T1 = dhcp_ia_non_temporal_params.T1;
replyPacket.iaId = dhcp_ia_non_temporal_params.iaId;
replyPacket.transaction_ID = msg_tr_id;
uint16_t duid_length = libdhcpv6_duid_option_size(replyPacket.clientDUID.linkType);
duid_length -= 8;
tr_debug("Response dhcp sol %s clientDUID", trace_array(replyPacket.clientDUID.linkID, duid_length));
tr_debug("Response dhcp sol %s clientDUID", trace_array(replyPacket.clientDUID.duid, replyPacket.clientDUID.duid_length));
//Check First Current list
if (DHCPv6_server_respond_client(serverBase, &replyPacket, &dhcp_ia_non_temporal_params, &responseBuf, true) == 0) {
@ -173,10 +174,7 @@ int DHCPV6_server_service_request_handler(uint16_t instance_id, uint32_t msg_tr_
// Discover SERVER
serverBase = libdhcpv6_server_data_get_by_prefix_and_socketinstance(instance_id, dhcp_ia_non_temporal_params.nonTemporalAddress);
if (serverBase) {
dhcp_link_options_params_t serverInfoDui;
serverInfoDui.linkID = serverBase->serverDUID;
serverInfoDui.linkType = serverBase->serverLinkType;
if (libdhcpv6_compare_DUID(&serverInfoDui, &replyPacket.serverDUID) == 0) {
if (libdhcpv6_compare_DUID(&serverBase->serverDUID, &replyPacket.serverDUID) == 0) {
replyPacket.rapidCommit = libdhcpv6_rapid_commit_option_at_packet(msg_ptr, msg_len);
replyPacket.T0 = dhcp_ia_non_temporal_params.T0;
replyPacket.T1 = dhcp_ia_non_temporal_params.T1;
@ -339,6 +337,25 @@ void DHCPv6_server_service_callback_set(int8_t interface, uint8_t guaPrefix[stat
serverInfo->removeCb = remove_cb;
}
int DHCPv6_server_service_duid_update(int8_t interface, uint8_t guaPrefix[static 16], uint8_t *duid_ptr, uint16_t duid_type, uint8_t duid_length)
{
//Validate length and type
if (!libdhcpv6_duid_length_validate(duid_type, duid_length)) {
return -1;
}
dhcpv6_gua_server_entry_s *serverInfo = libdhcpv6_server_data_get_by_prefix_and_interfaceid(interface, guaPrefix);
if (!serverInfo) {
return -1;
}
return libdhcpv6_server_duid_set(serverInfo, duid_ptr, duid_type, duid_length);
}
/* SET max accepted clients to server, Default is 200
*
*

View File

@ -45,6 +45,7 @@ int DHCPv6_server_service_init(int8_t interface, uint8_t guaPrefix[static 16], u
void DHCPv6_server_service_callback_set(int8_t interface, uint8_t guaPrefix[static 16], dhcp_address_prefer_remove_cb *remove_cb, dhcp_address_add_notify_cb *add_cb);
int DHCPv6_server_service_duid_update(int8_t interface, uint8_t guaPrefix[static 16], uint8_t *duid_ptr, uint16_t duid_type, uint8_t duid_length);
/* Delete dhcp thread dhcp router ID server.
*

View File

@ -32,9 +32,10 @@
* if only one thread instance is supported this is needed to call only once.
*
* /param interface interface id of this instance.
* /param link_type DHCPV6_DUID_HARDWARE_IEEE_802_NETWORKS_TYPE, DHCPV6_DUID_HARDWARE_EUI64_TYPE or DHCPV6_DUID_HARDWARE_EUI48_TYPE
*
*/
void dhcp_client_init(int8_t interface);
void dhcp_client_init(int8_t interface, uint16_t link_type);
/* Set configurations for DHCP client
*
@ -72,15 +73,13 @@ void dhcp_client_delete(int8_t interface);
* /param interface interface where address is got
* /param dhcp_addr dhcp server ML16 address where address is registered.
* /param prefix dhcp server ML16 address where address is registered.
* /param mac64 64 bit mac address for identifieng client.
* /param link_type Link hardware type.
* /param error_cb error callback that is called if address cannot be created or becomes invalid.
* /param register_status true if address registered.
*
*/
typedef void (dhcp_client_global_adress_cb)(int8_t interface, uint8_t dhcp_addr[static 16], uint8_t prefix[static 16], bool register_status);
int dhcp_client_get_global_address(int8_t interface, uint8_t dhcp_addr[static 16], uint8_t prefix[static 16], uint8_t mac64[static 8], uint16_t link_type, dhcp_client_global_adress_cb *error_cb);
int dhcp_client_get_global_address(int8_t interface, uint8_t dhcp_addr[static 16], uint8_t prefix[static 16], dhcp_client_global_adress_cb *error_cb);
/* Renew all leased adddresses might be used when short address changes
*

View File

@ -39,57 +39,128 @@ typedef struct {
uint16_t sol_max_rt;
uint8_t sol_max_rc;
uint8_t libDhcp_instance;
dhcp_duid_options_params_t duid;
int8_t interface;
bool renew_uses_solicit: 1;
bool one_instance_interface: 1;
bool no_address_hint: 1;
ns_list_link_t link; /*!< List link entry */
} dhcp_client_class_t;
static dhcp_client_class_t dhcp_client;
static NS_LARGE NS_LIST_DEFINE(dhcp_client_list, dhcp_client_class_t, link);
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)
{
// No support for multible instances yet.
dhcp_client.service_instance = dhcp_service_init(interface, DHCP_INSTANCE_CLIENT, NULL);
dhcp_client.interface = interface;
dhcp_client.libDhcp_instance = libdhcpv6_nonTemporal_entry_get_unique_instance_id();
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;
static dhcp_client_class_t *dhcpv6_client_entry_allocate(int8_t interface, uint8_t duid_length)
{
dhcp_client_class_t *entry = ns_dyn_mem_alloc(sizeof(dhcp_client_class_t));
uint8_t *duid = ns_dyn_mem_alloc(duid_length);
if (!entry || !duid) {
ns_dyn_mem_free(entry);
ns_dyn_mem_free(duid);
return NULL;
}
memset(entry, 0, sizeof(dhcp_client_class_t));
entry->interface = interface;
entry->service_instance = dhcp_service_init(interface, DHCP_INSTANCE_CLIENT, NULL);
entry->libDhcp_instance = libdhcpv6_nonTemporal_entry_get_unique_instance_id();
entry->duid.duid = duid;
entry->duid.duid_length = duid_length;
entry->duid.type = DHCPV6_DUID_LINK_LAYER_TYPE;
ns_list_add_to_end(&dhcp_client_list, entry);
return entry;
}
//Discover DHCPv6 client
static dhcp_client_class_t *dhcpv6_client_entry_discover(int8_t interface)
{
ns_list_foreach(dhcp_client_class_t, cur, &dhcp_client_list) {
//Check All allocated address in this module
if (cur->interface == interface) {
return cur;
}
}
return NULL;
}
void dhcp_client_init(int8_t interface, uint16_t link_type)
{
protocol_interface_info_entry_t *interface_ptr = protocol_stack_interface_info_get_by_id(interface);
if (!interface_ptr) {
return;
}
dhcp_client_class_t *dhcp_client = dhcpv6_client_entry_discover(interface);
if (dhcp_client) {
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;
dhcp_client->service_instance = dhcp_service_init(interface, DHCP_INSTANCE_CLIENT, NULL);
dhcp_client->libDhcp_instance = libdhcpv6_nonTemporal_entry_get_unique_instance_id();
return;
}
//Allocate new
//define DUID-LL length based on MAC64 or MAC48
dhcp_client = dhcpv6_client_entry_allocate(interface, libdhcpv6_duid_linktype_size(link_type) + 2);
if (!dhcp_client) {
return;
}
uint8_t *ptr = dhcp_client->duid.duid;
ptr = common_write_16_bit(link_type, ptr);
memcpy(ptr, interface_ptr->mac, libdhcpv6_duid_linktype_size(link_type));
//Define DUID
}
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;
dhcp_client_class_t *dhcp_client = dhcpv6_client_entry_discover(interface);
if (!dhcp_client) {
return;
}
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)
{
// Set the default retry values for SOLICIT and RENEW messages.
(void)interface;
dhcp_client.sol_timeout = timeout;
dhcp_client.sol_max_rt = max_rt;
dhcp_client.sol_max_rc = max_rc;
dhcp_client_class_t *dhcp_client = dhcpv6_client_entry_discover(interface);
if (!dhcp_client) {
return;
}
dhcp_client->sol_timeout = timeout;
dhcp_client->sol_max_rt = max_rt;
dhcp_client->sol_max_rc = max_rc;
return;
}
void dhcp_relay_agent_enable(int8_t interface, uint8_t border_router_address[static 16])
{
dhcp_client.relay_instance = dhcp_service_init(interface, DHCP_INTANCE_RELAY_AGENT, NULL);
dhcp_service_relay_instance_enable(dhcp_client.relay_instance, border_router_address);
dhcp_client_class_t *dhcp_client = dhcpv6_client_entry_discover(interface);
if (!dhcp_client) {
return;
}
dhcp_client->relay_instance = dhcp_service_init(interface, DHCP_INTANCE_RELAY_AGENT, NULL);
dhcp_service_relay_instance_enable(dhcp_client->relay_instance, border_router_address);
}
void dhcp_client_delete(int8_t interface)
@ -97,7 +168,13 @@ void dhcp_client_delete(int8_t interface)
protocol_interface_info_entry_t *cur = NULL;
dhcpv6_client_server_data_t *srv_data_ptr;
uint8_t temporary_address[16];
dhcp_service_delete(dhcp_client.service_instance);
dhcp_client_class_t *dhcp_client = dhcpv6_client_entry_discover(interface);
if (!dhcp_client) {
return;
}
dhcp_service_delete(dhcp_client->service_instance);
cur = protocol_stack_interface_info_get_by_id(interface);
@ -107,7 +184,7 @@ void dhcp_client_delete(int8_t interface)
}
do {
srv_data_ptr = 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 != NULL) {
tr_debug("Free DHCPv6 Client\n");
memcpy(temporary_address, srv_data_ptr->iaNontemporalAddress.addressPrefix, 16);
@ -117,7 +194,7 @@ void dhcp_client_delete(int8_t interface)
}
} while (srv_data_ptr != NULL);
dhcp_client.service_instance = 0;
dhcp_client->service_instance = 0;
return;
}
@ -125,10 +202,14 @@ void dhcp_client_delete(int8_t interface)
void dhcpv6_client_send_error_cb(dhcpv6_client_server_data_t *srv_data_ptr)
{
if (srv_data_ptr != NULL) {
dhcp_client_class_t *dhcp_client = dhcpv6_client_entry_discover(srv_data_ptr->interfaceId);
if (!dhcp_client) {
return;
}
// error for Global address
if (dhcp_client.global_address_cb != NULL) {
dhcp_client.global_address_cb(dhcp_client.interface, srv_data_ptr->server_address, srv_data_ptr->iaNontemporalAddress.addressPrefix, false);
if (dhcp_client->global_address_cb != NULL) {
dhcp_client->global_address_cb(dhcp_client->interface, srv_data_ptr->server_address, srv_data_ptr->iaNontemporalAddress.addressPrefix, false);
}
}
}
@ -138,9 +219,8 @@ void dhcpv6_client_send_error_cb(dhcpv6_client_server_data_t *srv_data_ptr)
int dhcp_solicit_resp_cb(uint16_t instance_id, void *ptr, uint8_t msg_name, uint8_t *msg_ptr, uint16_t msg_len)
{
dhcp_ia_non_temporal_params_t dhcp_ia_non_temporal_params;
dhcp_link_options_params_t clientId;
dhcp_link_options_params_t serverId;
dhcp_link_options_params_t interfaceId;
dhcp_duid_options_params_t clientId;
dhcp_duid_options_params_t serverId;
dhcpv6_client_server_data_t *srv_data_ptr = NULL;
(void)instance_id;
@ -153,6 +233,13 @@ int dhcp_solicit_resp_cb(uint16_t instance_id, void *ptr, uint8_t msg_name, uin
goto error_exit;
}
dhcp_client_class_t *dhcp_client = dhcpv6_client_entry_discover(srv_data_ptr->interfaceId);
if (!dhcp_client) {
tr_error("No DHCPv6 client avilabale");
goto error_exit;
}
//Clear Active Transaction state
srv_data_ptr->transActionId = 0;
@ -178,16 +265,33 @@ int dhcp_solicit_resp_cb(uint16_t instance_id, void *ptr, uint8_t msg_name, uin
goto error_exit;
}
interfaceId.linkID = srv_data_ptr->clientId;
interfaceId.linkType = srv_data_ptr->clientLinkIdType;
if (libdhcpv6_compare_DUID(&interfaceId, &clientId) != 0) {
if (libdhcpv6_compare_DUID(&srv_data_ptr->clientDUID, &clientId) != 0) {
tr_error("Not Valid Client Id");
goto error_exit;
}
if (dhcp_client.one_instance_interface && memcmp(srv_data_ptr->iaNontemporalAddress.addressPrefix, dhcp_ia_non_temporal_params.nonTemporalAddress, 16)) {
//Allocate dynamically new Server DUID if needed
if (!srv_data_ptr->serverDynamic_DUID || serverId.duid_length > srv_data_ptr->dyn_server_duid_length) {
//Allocate dynamic new bigger
srv_data_ptr->dyn_server_duid_length = 0;
ns_dyn_mem_free(srv_data_ptr->serverDynamic_DUID);
srv_data_ptr->serverDynamic_DUID = ns_dyn_mem_alloc(serverId.duid_length);
if (!srv_data_ptr->serverDynamic_DUID) {
tr_error("Dynamic DUID alloc fail");
goto error_exit;
}
srv_data_ptr->dyn_server_duid_length = serverId.duid_length;
}
protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(dhcp_client.interface);
//Copy Server DUID
srv_data_ptr->serverDUID.duid = srv_data_ptr->serverDynamic_DUID;
srv_data_ptr->serverDUID.type = serverId.type;
srv_data_ptr->serverDUID.duid_length = serverId.duid_length;
memcpy(srv_data_ptr->serverDUID.duid, serverId.duid, serverId.duid_length);
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);
}
@ -196,17 +300,15 @@ int dhcp_solicit_resp_cb(uint16_t instance_id, void *ptr, uint8_t msg_name, uin
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;
memcpy(srv_data_ptr->serverLinkId, serverId.linkID, 8);
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;
bool status = 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, status);
if (dhcp_client->global_address_cb) {
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:
@ -214,7 +316,7 @@ error_exit:
return RET_MSG_ACCEPTED;
}
int dhcp_client_get_global_address(int8_t interface, uint8_t dhcp_addr[static 16], uint8_t prefix[static 16], uint8_t mac64[static 8], uint16_t link_type, dhcp_client_global_adress_cb *error_cb)
int dhcp_client_get_global_address(int8_t interface, uint8_t dhcp_addr[static 16], uint8_t prefix[static 16], dhcp_client_global_adress_cb *error_cb)
{
dhcpv6_solication_base_packet_s solPacket = {0};
@ -222,53 +324,67 @@ int dhcp_client_get_global_address(int8_t interface, uint8_t dhcp_addr[static 16
uint32_t payload_len;
dhcpv6_client_server_data_t *srv_data_ptr;
bool add_prefix;
dhcp_client_class_t *dhcp_client = dhcpv6_client_entry_discover(interface);
if (mac64 == NULL || dhcp_addr == NULL) {
if (dhcp_addr == NULL || !dhcp_client) {
tr_error("Invalid parameters");
return -1;
}
if (!prefix || dhcp_client.one_instance_interface) {
if (!prefix || dhcp_client->one_instance_interface) {
//NULL Definition will only check That Interface is not generated
srv_data_ptr = 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 (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);
if (memcmp(srv_data_ptr->iaNontemporalAddress.addressPrefix, prefix, 8) == 0) {
return 0;
}
return 0;
protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(interface);
if (!cur) {
return -1;
}
dhcp_service_req_remove_all(srv_data_ptr);// remove all pending retransmissions
addr_deprecate(cur, srv_data_ptr->iaNontemporalAddress.addressPrefix);
srv_data_ptr->iaNonTemporalStructValid = false;
memcpy(srv_data_ptr->iaNontemporalAddress.addressPrefix, prefix, 8);
goto dhcp_address_get;
} else if (dhcp_client_server_address_update(interface, prefix, dhcp_addr) == 0) {
//DHCP server address OK
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);
tr_debug("GEN new Dhcpv6 client %u", dhcp_client->libDhcp_instance);
srv_data_ptr = libdhcvp6_nontemporalAddress_server_data_allocate(interface, dhcp_client->libDhcp_instance, prefix, dhcp_addr);
if (!srv_data_ptr) {
tr_error("OOM srv_data_ptr");
return -1;
}
//SET DUID
srv_data_ptr->clientDUID = dhcp_client->duid;
dhcp_address_get:
if (!prefix || dhcp_client.no_address_hint) {
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_len = libdhcpv6_solication_message_length(srv_data_ptr->clientDUID.duid_length, add_prefix, 0);
payload_ptr = ns_dyn_mem_temporary_alloc(payload_len);
@ -278,17 +394,16 @@ int dhcp_client_get_global_address(int8_t interface, uint8_t dhcp_addr[static 16
return -1;
}
dhcp_client.global_address_cb = error_cb; //TODO Only supporting one instance globaly if we need more for different instances needs code.
dhcp_client->global_address_cb = error_cb; //TODO Only supporting one instance globaly if we need more for different instances needs code.
srv_data_ptr->GlobalAddress = true;
// Build solicit
solPacket.clientDUID.linkID = mac64;
solPacket.clientDUID.linkType = link_type;
solPacket.clientDUID = srv_data_ptr->clientDUID;
solPacket.iaID = srv_data_ptr->IAID;
solPacket.messageType = DHCPV6_SOLICATION_TYPE;
solPacket.transActionId = libdhcpv6_txid_get();
/*Non Temporal Address */
if (prefix && !dhcp_client.no_address_hint) {
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);
@ -297,16 +412,16 @@ int dhcp_client_get_global_address(int8_t interface, uint8_t dhcp_addr[static 16
}
// send solicit
srv_data_ptr->transActionId = dhcp_service_send_req(dhcp_client.service_instance, 0, srv_data_ptr, dhcp_addr, payload_ptr, payload_len, dhcp_solicit_resp_cb);
srv_data_ptr->transActionId = dhcp_service_send_req(dhcp_client->service_instance, 0, srv_data_ptr, dhcp_addr, payload_ptr, payload_len, dhcp_solicit_resp_cb);
if (srv_data_ptr->transActionId == 0) {
ns_dyn_mem_free(payload_ptr);
libdhcvp6_nontemporalAddress_server_data_free(srv_data_ptr);
return -1;
}
srv_data_ptr->iaNonTemporalStructValid = false;
if (dhcp_client.sol_timeout != 0) {
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);
dhcp_service_set_retry_timers(srv_data_ptr->transActionId, dhcp_client->sol_timeout, dhcp_client->sol_max_rt, dhcp_client->sol_max_rc);
}
return 0;
@ -314,17 +429,18 @@ int dhcp_client_get_global_address(int8_t interface, uint8_t dhcp_addr[static 16
int dhcp_client_server_address_update(int8_t interface, uint8_t *prefix, uint8_t server_address[static 16])
{
dhcpv6_client_server_data_t *srv_data_ptr = NULL;
if (dhcp_client.interface != interface) {
dhcp_client_class_t *dhcp_client = dhcpv6_client_entry_discover(interface);
if (!dhcp_client) {
tr_debug("Interface not match");
return -1;
}
dhcpv6_client_server_data_t *srv_data_ptr = NULL;
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);
} 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;
@ -353,17 +469,19 @@ void dhcp_client_global_address_delete(int8_t interface, uint8_t *dhcp_addr, uin
{
protocol_interface_info_entry_t *cur;
dhcpv6_client_server_data_t *srv_data_ptr;
dhcp_client_class_t *dhcp_client;
(void) dhcp_addr;
srv_data_ptr = libdhcpv6_nonTemporal_entry_get_by_prefix(interface, prefix);
cur = protocol_stack_interface_info_get_by_id(interface);
dhcp_client = dhcpv6_client_entry_discover(interface);
if (cur == NULL || srv_data_ptr == NULL) {
if (cur == NULL || srv_data_ptr == NULL || !dhcp_client) {
return;
}
dhcp_service_req_remove_all(srv_data_ptr);// remove all pending retransmissions
if (dhcp_client.one_instance_interface) {
if (dhcp_client->one_instance_interface) {
addr_deprecate(cur, srv_data_ptr->iaNontemporalAddress.addressPrefix);
} else {
addr_delete(cur, srv_data_ptr->iaNontemporalAddress.addressPrefix);
@ -375,14 +493,18 @@ void dhcp_client_global_address_delete(int8_t interface, uint8_t *dhcp_addr, uin
void dhcpv6_renew(protocol_interface_info_entry_t *interface, if_address_entry_t *addr, if_address_callback_t reason)
{
dhcp_link_options_params_t serverLink;
uint8_t *payload_ptr;
uint32_t payload_len;
dhcp_client_class_t *dhcp_client = dhcpv6_client_entry_discover(interface->id);
if (!dhcp_client) {
return;
}
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);
srv_data_ptr = libdhcpv6_nonTemporal_entry_get_by_instance(dhcp_client->libDhcp_instance);
}
if (srv_data_ptr == NULL) {
@ -405,7 +527,7 @@ 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, !dhcp_client.no_address_hint);
payload_len = libdhcpv6_address_request_message_len(srv_data_ptr->clientDUID.duid_length, srv_data_ptr->serverDUID.duid_length, 0, !dhcp_client->no_address_hint);
payload_ptr = ns_dyn_mem_temporary_alloc(payload_len);
if (payload_ptr == NULL) {
if (addr) {
@ -416,8 +538,7 @@ void dhcpv6_renew(protocol_interface_info_entry_t *interface, if_address_entry_t
}
dhcpv6_solication_base_packet_s packetReq = {
.messageType = DHCPV6_RENEW_TYPE,
.clientDUID.linkID = srv_data_ptr->clientId,
.clientDUID.linkType = srv_data_ptr->clientLinkIdType,
.clientDUID = srv_data_ptr->clientDUID,
.requestedOptionCnt = 0,
.iaID = srv_data_ptr->IAID,
.timerT0 = srv_data_ptr->T0,
@ -425,32 +546,31 @@ void dhcpv6_renew(protocol_interface_info_entry_t *interface, if_address_entry_t
.requestedOptionList = NULL,
};
if (dhcp_client.renew_uses_solicit) {
if (dhcp_client->renew_uses_solicit) {
packetReq.messageType = DHCPV6_SOLICATION_TYPE;
}
serverLink.linkID = srv_data_ptr->serverLinkId;
serverLink.linkType = srv_data_ptr->serverLinkType;
if (dhcp_client.no_address_hint && dhcp_client.renew_uses_solicit) {
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);
libdhcpv6_generic_nontemporal_address_message_write(payload_ptr, &packetReq, NULL, &srv_data_ptr->serverDUID);
} 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);
libdhcpv6_generic_nontemporal_address_message_write(payload_ptr, &packetReq, &nonTemporalAddress, &srv_data_ptr->serverDUID);
}
// send solicit
uint8_t *server_address = dhcp_service_relay_global_addres_get(dhcp_client.relay_instance);
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);
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);
if (addr) {
@ -458,9 +578,9 @@ void dhcpv6_renew(protocol_interface_info_entry_t *interface, if_address_entry_t
}
tr_error("DHCP renew send failed");
}
if (packetReq.messageType == DHCPV6_SOLICATION_TYPE && dhcp_client.sol_timeout != 0) {
if (packetReq.messageType == DHCPV6_SOLICATION_TYPE && 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);
dhcp_service_set_retry_timers(srv_data_ptr->transActionId, dhcp_client->sol_timeout, dhcp_client->sol_max_rt, dhcp_client->sol_max_rc);
}
tr_info("DHCP renew send OK");
}
@ -470,7 +590,6 @@ static bool dhcpv6_client_set_address(int8_t interface_id, dhcpv6_client_server_
protocol_interface_info_entry_t *cur = NULL;
if_address_entry_t *address_entry = NULL;
uint32_t renewTimer;
cur = protocol_stack_interface_info_get_by_id(interface_id);
if (!cur) {
return false;

View File

@ -39,6 +39,7 @@ typedef enum mac_event_t {
MAC_TIMER_CCA,
MAC_TX_FAIL,
MAC_TX_TIMEOUT,
MAC_ACK_SECURITY_FAIL,
MAC_UNKNOWN_DESTINATION,
MAC_TX_PRECOND_FAIL
} mac_event_t;

View File

@ -572,9 +572,9 @@ static uint8_t mac_data_interface_decrypt_packet(mac_pre_parsed_frame_t *b, mlme
} else {
if (!b->neigh_info) {
if (rf_mac_setup->mac_security_bypass_unknow_device && (b->fcf_dsn.SrcAddrMode == MAC_ADDR_MODE_64_BIT
&& security_params->SecurityLevel > AES_SECURITY_LEVEL_ENC)) {
security_by_pass = true;
if (SrcPANId == rf_mac_setup->pan_id && rf_mac_setup->mac_security_bypass_unknow_device &&
(b->fcf_dsn.SrcAddrMode == MAC_ADDR_MODE_64_BIT && security_params->SecurityLevel > AES_SECURITY_LEVEL_ENC)) {
security_by_pass = true;//Accept by pass only from same PAN-ID
} else {
return MLME_UNSUPPORTED_SECURITY;
}
@ -723,7 +723,7 @@ static int8_t mac_data_sap_rx_handler(mac_pre_parsed_frame_t *buf, protocol_inte
/* Parse security part */
mac_header_security_components_read(buf, &data_ind->Key);
buf->neigh_info = mac_sec_mib_device_description_get(rf_mac_setup, data_ind->SrcAddr, data_ind->SrcAddrMode);
buf->neigh_info = mac_sec_mib_device_description_get(rf_mac_setup, data_ind->SrcAddr, data_ind->SrcAddrMode, data_ind->SrcPANId);
if (buf->fcf_dsn.securityEnabled) {
status = mac_data_interface_decrypt_packet(buf, &data_ind->Key);
if (status != MLME_SUCCESS) {
@ -846,7 +846,8 @@ static int8_t mac_command_sap_rx_handler(mac_pre_parsed_frame_t *buf, protocol_i
//Read address and pan-id
mac_header_get_src_address(&buf->fcf_dsn, mac_header_message_start_pointer(buf), temp_src_address);
uint8_t address_mode = buf->fcf_dsn.SrcAddrMode;
buf->neigh_info = mac_sec_mib_device_description_get(rf_mac_setup, temp_src_address, address_mode);
uint16_t pan_id = mac_header_get_src_panid(&buf->fcf_dsn, mac_header_message_start_pointer(buf), rf_mac_setup->pan_id);
buf->neigh_info = mac_sec_mib_device_description_get(rf_mac_setup, temp_src_address, address_mode, pan_id);
//Decrypt Packet if secured
if (buf->fcf_dsn.securityEnabled) {
mac_header_security_components_read(buf, &security_params);
@ -1082,18 +1083,21 @@ static int8_t mac_ack_sap_rx_handler(mac_pre_parsed_frame_t *buf, protocol_inter
memset(SrcAddr, 0, 8);
memset(&key, 0, sizeof(mlme_security_t));
mac_header_get_src_address(&buf->fcf_dsn, mac_header_message_start_pointer(buf), SrcAddr);
uint16_t pan_id = mac_header_get_src_panid(&buf->fcf_dsn, mac_header_message_start_pointer(buf), rf_mac_setup->pan_id);
/* Parse security part */
mac_header_security_components_read(buf, &key);
buf->neigh_info = mac_sec_mib_device_description_get(rf_mac_setup, SrcAddr, buf->fcf_dsn.SrcAddrMode);
buf->neigh_info = mac_sec_mib_device_description_get(rf_mac_setup, SrcAddr, buf->fcf_dsn.SrcAddrMode, pan_id);
if (buf->fcf_dsn.securityEnabled) {
uint8_t status = mac_data_interface_decrypt_packet(buf, &key);
if (status != MLME_SUCCESS) {
rf_mac_setup->mac_tx_result = MAC_ACK_SECURITY_FAIL;
return -1;
}
}
if (buf->mac_payload_length && !mac_payload_information_elements_parse(buf)) {
rf_mac_setup->mac_tx_result = MAC_ACK_SECURITY_FAIL;
return -1;
}
@ -1144,6 +1148,7 @@ static void mac_pd_data_ack_handler(mac_pre_parsed_frame_t *buf)
//Do not forward ACK payload but Accept ACK
mcps_sap_pre_parsed_frame_buffer_free(buf);
buf = NULL;
}
rf_mac_setup->active_pd_data_request = NULL;
@ -1276,7 +1281,7 @@ static bool mac_frame_security_parameters_init(ccm_globals_t *ccm_ptr, protocol_
} else {
//Discover device descriptor only unicast packet which need ack
if (buffer->fcf_dsn.DstAddrMode && buffer->fcf_dsn.ackRequested) {
device_description = mac_sec_mib_device_description_get(rf_ptr, buffer->DstAddr, buffer->fcf_dsn.DstAddrMode);
device_description = mac_sec_mib_device_description_get(rf_ptr, buffer->DstAddr, buffer->fcf_dsn.DstAddrMode, buffer->DstPANId);
if (!device_description) {
buffer->status = MLME_UNAVAILABLE_KEY;
return false;
@ -1348,6 +1353,8 @@ static void mac_common_data_confirmation_handle(protocol_interface_rf_mac_setup_
buf->status = MLME_TRANSACTION_EXPIRED;
} else if (m_event == MAC_UNKNOWN_DESTINATION) {
buf->status = MLME_UNAVAILABLE_KEY;
} else if (m_event == MAC_ACK_SECURITY_FAIL) {
buf->status = MLME_TX_NO_ACK;
}/** else if (m_event == MAC_TX_PRECOND_FAIL) {
* Nothing to do, status already set to buf->status.
}**/

View File

@ -542,6 +542,9 @@ static int8_t mac_mlme_16bit_set(protocol_interface_rf_mac_setup_s *rf_mac_setup
case macTransactionPersistenceTime:
//TODO: check this also
break;
case macDeviceDescriptionPanIDUpdate:
mac_sec_mib_device_description_pan_update(rf_mac_setup, value);
break;
default:
return -1;

View File

@ -429,7 +429,7 @@ static int8_t mac_data_interface_tx_done_cb(protocol_interface_rf_mac_setup_s *r
if (rf_ptr->mac_ack_tx_active) {
//Accept direct non crypted acks and crypted only if neighbor is at list
if (rf_ptr->ack_tx_possible || mac_sec_mib_device_description_get(rf_ptr, rf_ptr->enhanced_ack_buffer.DstAddr, rf_ptr->enhanced_ack_buffer.fcf_dsn.DstAddrMode)) {
if (rf_ptr->ack_tx_possible || mac_sec_mib_device_description_get(rf_ptr, rf_ptr->enhanced_ack_buffer.DstAddr, rf_ptr->enhanced_ack_buffer.fcf_dsn.DstAddrMode, rf_ptr->enhanced_ack_buffer.DstPANId)) {
return PHY_TX_ALLOWED;
}
@ -772,7 +772,7 @@ static int8_t mac_pd_sap_generate_ack(protocol_interface_rf_mac_setup_s *rf_ptr,
return -1;
}
if (rf_ptr->enhanced_ack_buffer.aux_header.securityLevel == 0 || mac_sec_mib_device_description_get(rf_ptr, rf_ptr->enhanced_ack_buffer.DstAddr, rf_ptr->enhanced_ack_buffer.fcf_dsn.DstAddrMode)) {
if (rf_ptr->enhanced_ack_buffer.aux_header.securityLevel == 0 || mac_sec_mib_device_description_get(rf_ptr, rf_ptr->enhanced_ack_buffer.DstAddr, rf_ptr->enhanced_ack_buffer.fcf_dsn.DstAddrMode, rf_ptr->enhanced_ack_buffer.DstPANId)) {
rf_ptr->ack_tx_possible = true;
} else {
rf_ptr->ack_tx_possible = false;

View File

@ -115,7 +115,7 @@ static void mac_sec_mib_frame_counter_key_buffer_free(protocol_interface_rf_mac_
rf_mac_setup->secFrameCounterPerKey = false;
}
static mlme_device_descriptor_t *mac_sec_mib_device_description_get_by_mac16(protocol_interface_rf_mac_setup_s *rf_mac_setup, uint16_t mac16)
static mlme_device_descriptor_t *mac_sec_mib_device_description_get_by_mac16(protocol_interface_rf_mac_setup_s *rf_mac_setup, uint16_t mac16, uint16_t pan_id)
{
mlme_device_descriptor_t *device_table = rf_mac_setup->device_description_table;
@ -124,7 +124,7 @@ static mlme_device_descriptor_t *mac_sec_mib_device_description_get_by_mac16(pro
}
for (int i = 0; i < rf_mac_setup->device_description_table_size; i++) {
if (device_table->ShortAddress == mac16) {
if ((pan_id == 0xffff || device_table->PANId == pan_id) && device_table->ShortAddress == mac16) {
return device_table;
}
device_table++;
@ -133,7 +133,7 @@ static mlme_device_descriptor_t *mac_sec_mib_device_description_get_by_mac16(pro
return NULL;
}
static mlme_device_descriptor_t *mac_sec_mib_device_description_get_by_mac64(protocol_interface_rf_mac_setup_s *rf_mac_setup, const uint8_t *mac64)
static mlme_device_descriptor_t *mac_sec_mib_device_description_get_by_mac64(protocol_interface_rf_mac_setup_s *rf_mac_setup, const uint8_t *mac64, uint16_t pan_id)
{
mlme_device_descriptor_t *device_table = rf_mac_setup->device_description_table;
@ -142,8 +142,10 @@ static mlme_device_descriptor_t *mac_sec_mib_device_description_get_by_mac64(pro
}
for (int i = 0; i < rf_mac_setup->device_description_table_size; i++) {
if (memcmp(device_table->ExtAddress, mac64, 8) == 0) {
return device_table;
if ((pan_id == 0xffff || device_table->PANId == pan_id)) {
if (memcmp(device_table->ExtAddress, mac64, 8) == 0) {
return device_table;
}
}
device_table++;
}
@ -365,14 +367,30 @@ mlme_device_descriptor_t *mac_sec_mib_device_description_get_attribute_index(pro
return rf_mac_setup->device_description_table + attribute_index;
}
mlme_device_descriptor_t *mac_sec_mib_device_description_get(protocol_interface_rf_mac_setup_s *rf_mac_setup, const uint8_t *address, uint8_t type)
void mac_sec_mib_device_description_pan_update(protocol_interface_rf_mac_setup_s *rf_mac_setup, uint16_t pan_id)
{
mlme_device_descriptor_t *device_table = rf_mac_setup->device_description_table;
if (!device_table) {
return;
}
for (int i = 0; i < rf_mac_setup->device_description_table_size; i++) {
device_table->PANId = pan_id;
device_table++;
}
}
mlme_device_descriptor_t *mac_sec_mib_device_description_get(protocol_interface_rf_mac_setup_s *rf_mac_setup, const uint8_t *address, uint8_t type, uint16_t pan_id)
{
if (rf_mac_setup) {
if (type == MAC_ADDR_MODE_16_BIT) {
uint16_t short_id = common_read_16_bit(address);
return mac_sec_mib_device_description_get_by_mac16(rf_mac_setup, short_id);
return mac_sec_mib_device_description_get_by_mac16(rf_mac_setup, short_id, pan_id);
} else if (type == MAC_ADDR_MODE_64_BIT) {
return mac_sec_mib_device_description_get_by_mac64(rf_mac_setup, address);
return mac_sec_mib_device_description_get_by_mac64(rf_mac_setup, address, pan_id);
}
}

View File

@ -51,7 +51,9 @@ int8_t mac_sec_mib_key_description_set(uint8_t atribute_index, mlme_key_descript
mlme_device_descriptor_t *mac_sec_mib_device_description_get_attribute_index(struct protocol_interface_rf_mac_setup *rf_mac_setup, uint8_t attribute_index);
mlme_device_descriptor_t *mac_sec_mib_device_description_get(struct protocol_interface_rf_mac_setup *rf_mac_setup, const uint8_t *address, uint8_t type);
mlme_device_descriptor_t *mac_sec_mib_device_description_get(struct protocol_interface_rf_mac_setup *rf_mac_setup, const uint8_t *address, uint8_t type, uint16_t pan_id);
void mac_sec_mib_device_description_pan_update(struct protocol_interface_rf_mac_setup *rf_mac_setup, uint16_t pan_id);
uint8_t mac_mib_device_descption_attribute_get_by_descriptor(struct protocol_interface_rf_mac_setup *rf_mac_setup, mlme_device_descriptor_t *descriptor);

View File

@ -44,6 +44,7 @@ typedef enum {
STATS_BUFFER_HEADROOM_FAIL,
STATS_ETX_1ST_PARENT,
STATS_ETX_2ND_PARENT,
STATS_AL_TX_QUEUE_SIZE
} nwk_stats_type_t;

View File

@ -146,6 +146,12 @@ void protocol_stats_update(nwk_stats_type_t type, uint16_t update_val)
case STATS_ETX_2ND_PARENT:
nwk_stats_ptr->etx_2nd_parent = update_val;
break;
case STATS_AL_TX_QUEUE_SIZE:
nwk_stats_ptr->adapt_layer_tx_queue_size = update_val;
if (nwk_stats_ptr->adapt_layer_tx_queue_size > nwk_stats_ptr->adapt_layer_tx_queue_peak) {
nwk_stats_ptr->adapt_layer_tx_queue_peak = nwk_stats_ptr->adapt_layer_tx_queue_size;
}
break;
}
}
}

View File

@ -35,7 +35,7 @@ typedef enum rpl_event {
RPL_EVENT_DAO_DONE, /* Simplistic trigger for bootstrap advance - a DAO registration completed */
RPL_EVENT_LOCAL_REPAIR_START, /* RPL start scanning new parent by multicast DIS user can disable beacon request responser here*/
RPL_EVENT_LOCAL_REPAIR_NO_MORE_DIS, /* RPL not sending DIS anymore user can report bootstrap error */
RPL_EVENT_DAO_PARENT_SWITCH, /* RPL indicate that DAO downward Parent state have been updated */
RPL_EVENT_DAO_PARENT_ADD, /* RPL indicate that DAO downward Parent has been added */
} rpl_event_t;
typedef void rpl_domain_callback_t(rpl_event_t event, void *handle);

View File

@ -192,20 +192,18 @@ static bool rpl_instance_parent_selection_ready(rpl_instance_t *instance)
void rpl_downward_neighbour_gone(rpl_instance_t *instance, rpl_neighbour_t *neighbour)
{
if (neighbour->dao_path_control == 0) {
return;
}
neighbour->old_dao_path_control = neighbour->dao_path_control;
neighbour->dao_path_control = 0;
rpl_downward_process_dao_parent_changes(instance);
// Currently don't need to do anything - caller is expected to
// trigger parent selection, which will do everything required.
(void) instance;
(void) neighbour;
}
void rpl_downward_process_dao_parent_changes(rpl_instance_t *instance)
{
uint8_t mop = rpl_instance_mop(instance);
bool storing;
switch (mop) {
switch (rpl_instance_mop(instance)) {
case RPL_MODE_NON_STORING:
storing = false;
break;
@ -219,6 +217,7 @@ void rpl_downward_process_dao_parent_changes(rpl_instance_t *instance)
bool bits_removed = false;
uint8_t bits_added = 0;
ns_list_foreach(rpl_neighbour_t, neighbour, &instance->candidate_neighbours) {
if (neighbour->old_dao_path_control != neighbour->dao_path_control) {
if (neighbour->old_dao_path_control & ~ neighbour->dao_path_control) {
@ -230,11 +229,21 @@ void rpl_downward_process_dao_parent_changes(rpl_instance_t *instance)
}
}
}
tr_debug("removed=%x, added=%x", bits_removed, bits_added);
if (!(bits_removed || bits_added)) {
return;
}
tr_debug("removed=%x, added=%x", bits_removed, bits_added);
ns_list_foreach(rpl_neighbour_t, neighbour, &instance->candidate_neighbours) {
if (neighbour->dao_path_control != 0 && neighbour->old_dao_path_control == 0) {
//Candidate has become a DAO parent
rpl_control_event(instance->domain, RPL_EVENT_DAO_PARENT_ADD);
break;
}
}
if (storing) {
/* XXX more complicated - No-Paths to people losing stuff, etc.
* Need to think a bit about what each parent would have had.
@ -253,8 +262,8 @@ void rpl_downward_process_dao_parent_changes(rpl_instance_t *instance)
}
}
}
//GENERATE PARENT Update event
rpl_control_event(instance->domain, RPL_EVENT_DAO_PARENT_SWITCH);
//Trig DAO allways after change
rpl_instance_dao_trigger(instance, 0);
}
}

View File

@ -198,6 +198,13 @@ static rpl_neighbour_t *rpl_mrhof_select_best_parent(rpl_instance_t *instance, c
/* We can use this to simplify some logic */
if (prev_preferred) {
prev_preferred_path_cost = rpl_mrhof_path_cost_through_neighbour(prev_preferred);
// Path cost might be not much worse than alternate parents, but it might push
// us over our DAGMaxRankIncrease limit. In that case, makes sense to treat
// the path cost as "infinite", allowing immediate switch to an alternative,
// defeating hysteresis.
if (prev_preferred_path_cost > prev_preferred->dodag_version->hard_rank_limit) {
prev_preferred_path_cost = RPL_RANK_INFINITE;
}
}
ns_list_foreach(rpl_neighbour_t, c, &instance->candidate_neighbours) {

View File

@ -81,6 +81,12 @@ uint16_t nrpl_dag_rank(const rpl_dodag_t *dodag, uint16_t rank)
return rank == RPL_RANK_INFINITE ? rank : rank / dodag->config.min_hop_rank_increase;
}
uint16_t nrpl_rank(const rpl_dodag_t *dodag, uint16_t dag_rank)
{
uint32_t rank = (uint32_t) dag_rank * dodag->config.min_hop_rank_increase;
return rank < RPL_RANK_INFINITE ? rank : RPL_RANK_INFINITE;
}
/* Silly function needed because RPL HbH option includes dagrank directly */
rpl_cmp_t rpl_rank_compare_dagrank_rank(const rpl_dodag_t *dodag, uint16_t dag_rank_a, uint16_t b)
{
@ -1566,7 +1572,27 @@ void rpl_instance_dio_trigger(rpl_instance_t *instance, protocol_interface_info_
/* When we advertise a new lowest rank, need to re-evaluate our rank limits */
if (rank < dodag_version->lowest_advertised_rank) {
dodag_version->lowest_advertised_rank = rank;
#if 0
// Standard RFC 6550 behaviour
dodag_version->hard_rank_limit = rpl_rank_add(rank, dodag->config.dag_max_rank_increase);
#else
// Round up hard limit - DAGRank interpretation. Contrary to wording of RFC 6550 8.2.2.4.3,
// but needed to cope reasonably with Wi-SUN insisting on DAGMaxRankIncrease of 0.
// Interpret that as a request to not increase DAGRank, rather than Rank.
//
// Example, if DAGMaxRankIncrease is 0, MinHopRankIncrease is 0x80, and our advertised
// 0xC0, then we permit up to 0xFF, which doesn't increase DAGRank. If DAGMaxRankIncrease
// is 0x80, then we permit can go form 0xC0 to 0x17F, increasing DAGRank by 1, even though
// it's a Rank increase of 0xBF. Fractional parts of DAGMaxRankIncrease are ignored.
uint16_t dagrank = nrpl_dag_rank(dodag, rank);
uint16_t dagmaxinc = nrpl_dag_rank(dodag, dodag->config.dag_max_rank_increase);
uint16_t dagmax = rpl_rank_add(dagrank, dagmaxinc);
if (dagmax == RPL_RANK_INFINITE) {
dodag_version->hard_rank_limit = RPL_RANK_INFINITE;
} else {
dodag_version->hard_rank_limit = nrpl_rank(dodag, 1 + dagmax) - 1;
}
#endif
}
rpl_dodag_version_limit_greediness(dodag_version, rank);

View File

@ -108,8 +108,8 @@ static const uint8_t *kde_search(const uint8_t *ptr, uint16_t len, const uint8_t
while (len >= KDE_MIN_LEN) {
uint16_t kde_len = ptr[1] + KDE_FIXED_LEN;
// Type shall be 0xdd and length shall be at least 6 */
if (ptr[KDE_TYPE_INDEX] != 0xdd || kde_len < KDE_MIN_LEN || kde_len > len) {
// For the type 0xdd the length shall be at least 6 */
if ((ptr[KDE_TYPE_INDEX] == 0xdd && kde_len < KDE_MIN_LEN) || kde_len > len) {
return NULL;
}

View File

@ -45,6 +45,7 @@ struct kmp_api_s {
kmp_type_e type; /**< KMP type */
kmp_addr_t *addr; /**< Supplicant EUI-64, Relay IP address, Relay port */
kmp_service_t *service; /**< KMP service */
uint8_t instance_identifier; /**< KMP instance identifier, incremented when created, from 0 to 255 */
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 */
@ -62,6 +63,7 @@ typedef NS_LIST_HEAD(kmp_sec_prot_entry_t, link) kmp_sec_prot_list_t;
struct kmp_service_s {
kmp_sec_prot_list_t sec_prot_list; /**< Security protocols list */
kmp_service_incoming_ind *incoming_ind; /**< Callback to application to indicate incoming KMP frame */
kmp_service_tx_status_ind *tx_status_ind; /**< Callback to application to indicate TX status */
kmp_service_addr_get *addr_get; /**< Callback to get addresses related to KMP */
kmp_service_api_get *api_get; /**< Callback to get KMP API from a service */
kmp_service_msg_if_send *send; /**< Callback to send KMP frames */
@ -79,6 +81,9 @@ typedef struct {
static NS_LIST_DEFINE(kmp_service_list, kmp_service_t, link);
// KMP instance identifier value
static uint8_t kmp_instance_identifier = 0;
static void kmp_api_sec_prot_create_confirm(sec_prot_t *prot, sec_prot_result_e result);
static void kmp_api_sec_prot_create_indication(sec_prot_t *prot);
static void kmp_api_sec_prot_finished_indication(sec_prot_t *prot, sec_prot_result_e result, sec_prot_keys_t *sec_keys);
@ -125,6 +130,7 @@ kmp_api_t *kmp_api_create(kmp_service_t *service, kmp_type_e type)
kmp->create_ind = 0;
kmp->finished_ind = 0;
kmp->finished = 0;
kmp->instance_identifier = kmp_instance_identifier++;
kmp->addr = 0;
kmp->service = service;
kmp->timer_start_pending = false;
@ -212,7 +218,7 @@ static int8_t kmp_sec_prot_send(sec_prot_t *prot, void *pdu, uint16_t size)
int8_t result = -1;
if (kmp->service->send) {
result = kmp->service->send(kmp->service, kmp_id, kmp->addr, pdu, size);
result = kmp->service->send(kmp->service, kmp_id, kmp->addr, pdu, size, kmp->instance_identifier);
}
if (result < 0) {
@ -348,6 +354,11 @@ void *kmp_api_data_get(kmp_api_t *kmp)
return kmp->app_data_ptr;
}
uint8_t kmp_api_instance_id_get(kmp_api_t *kmp)
{
return kmp->instance_identifier;
}
void kmp_api_addr_set(kmp_api_t *kmp, kmp_addr_t *addr)
{
kmp->addr = addr;
@ -367,6 +378,7 @@ kmp_service_t *kmp_service_create(void)
ns_list_init(&service->sec_prot_list);
service->incoming_ind = 0;
service->tx_status_ind = 0;
service->addr_get = 0;
service->api_get = 0;
service->send = 0;
@ -405,13 +417,14 @@ static void kmp_sec_prot_state_machine_call(sec_prot_t *prot)
kmp->service->event_send(kmp->service, prot);
}
int8_t kmp_service_cb_register(kmp_service_t *service, kmp_service_incoming_ind *incoming_ind, kmp_service_addr_get *addr_get, kmp_service_api_get *api_get)
int8_t kmp_service_cb_register(kmp_service_t *service, kmp_service_incoming_ind *incoming_ind, kmp_service_tx_status_ind *tx_status_ind, kmp_service_addr_get *addr_get, kmp_service_api_get *api_get)
{
if (!service) {
return -1;
}
service->incoming_ind = incoming_ind;
service->tx_status_ind = tx_status_ind;
service->addr_get = addr_get;
service->api_get = api_get;
@ -450,6 +463,36 @@ int8_t kmp_service_msg_if_receive(kmp_service_t *service, kmp_type_e type, const
return ret;
}
int8_t kmp_service_tx_status_indication(kmp_service_t *service, kmp_tx_status_e tx_status, uint8_t tx_identifier)
{
if (!service || !service->tx_status_ind) {
return -1;
}
// Application can use the tx_identifier to match the TX status indication to kmp
kmp_api_t *kmp = (kmp_api_t *) service->tx_status_ind(service, tx_identifier);
if (!kmp) {
return -1;
}
// Security protocol has disabled message receiving or tx status indication is not set
if (kmp->receive_disable || !kmp->sec_prot.tx_status_ind) {
return -1;
}
sec_prot_tx_status_e sec_prot_tx_status;
if (tx_status == KMP_TX_OK) {
sec_prot_tx_status = SEC_PROT_TX_OK;
} else if (tx_status == KMP_TX_ERR_TX_NO_ACK) {
sec_prot_tx_status = SEC_PROT_TX_ERR_TX_NO_ACK;
} else {
sec_prot_tx_status = SEC_PROT_TX_ERR_UNSPEC;
}
int8_t ret = kmp->sec_prot.tx_status_ind(&kmp->sec_prot, sec_prot_tx_status);
return ret;
}
int8_t kmp_service_sec_protocol_register(kmp_service_t *service, kmp_type_e type, kmp_sec_prot_size *size, kmp_sec_prot_init *init)
{
if (!service) {

View File

@ -43,12 +43,18 @@ typedef enum {
IEEE_802_11_GKH_KEY = 17
} kmp_type_e;
typedef enum {
KMP_RESULT_OK = 0, // Successful
KMP_RESULT_ERR_NO_MEM = -1, // No memory
KMP_RESULT_ERR_TX_NO_ACK = -2, // No acknowledge was received
KMP_RESULT_ERR_UNSPEC = -3 // Other reason
} kmp_result_e;
typedef enum {
KMP_RESULT_OK = 0,
KMP_RESULT_ERR_NO_MEM = -1,
KMP_RESULT_ERR_UNSPEC = -2
} kmp_result_e;
KMP_TX_OK = 0, // Successful
KMP_TX_ERR_TX_NO_ACK = -1, // No acknowledge was received
KMP_TX_ERR_UNSPEC = -2, // Other reason
} kmp_tx_status_e;
typedef void kmp_sec_keys_t;
typedef struct sec_prot_s sec_prot_t;
@ -201,6 +207,16 @@ void kmp_api_data_set(kmp_api_t *kmp, void *data);
*/
void *kmp_api_data_get(kmp_api_t *kmp);
/**
* kmp_api_id_get get KMP instance identifier
*
* \param kmp instance
*
* \return instance identifier
*
*/
uint8_t kmp_api_instance_id_get(kmp_api_t *kmp);
/**
* kmp_api_addr_set set address
*
@ -262,6 +278,17 @@ int8_t kmp_service_delete(kmp_service_t *service);
*/
typedef kmp_api_t *kmp_service_incoming_ind(kmp_service_t *service, kmp_type_e type, const kmp_addr_t *addr);
/**
* kmp_service_tx_status_ind Notifies application about TX status
*
* \param service KMP service
* \param instance_id KMP instance identifier
*
* \return KMP instance or NULL
*
*/
typedef kmp_api_t *kmp_service_tx_status_ind(kmp_service_t *service, uint8_t instance_id);
/**
* kmp_service_addr_get gets addressing information related to KMP
*
@ -290,13 +317,15 @@ typedef kmp_api_t *kmp_service_api_get(kmp_service_t *service, kmp_api_t *kmp, k
*
* \param service KMP service
* \param incoming_ind incoming message callback
* \param tx_status tx status callback
* \param addr_get gets addressing information callback
* \param api_get gets KMP API from KMP service
*
* \return < 0 failure
* \return >= 0 success
*
*/
int8_t kmp_service_cb_register(kmp_service_t *service, kmp_service_incoming_ind *incoming_ind, kmp_service_addr_get *addr_get, kmp_service_api_get *api_get);
int8_t kmp_service_cb_register(kmp_service_t *service, kmp_service_incoming_ind *incoming_ind, kmp_service_tx_status_ind *tx_status_ind, kmp_service_addr_get *addr_get, kmp_service_api_get *api_get);
/**
* kmp_service_msg_if_receive receive a message
@ -321,12 +350,13 @@ int8_t kmp_service_msg_if_receive(kmp_service_t *service, kmp_type_e kmp_id, con
* \param addr address
* \param pdu pdu
* \param size pdu size
* \param tx_identifier TX identifier
*
* \return < 0 failure
* \return >= 0 success
*
*/
typedef int8_t kmp_service_msg_if_send(kmp_service_t *service, kmp_type_e type, const kmp_addr_t *addr, void *pdu, uint16_t size);
typedef int8_t kmp_service_msg_if_send(kmp_service_t *service, kmp_type_e type, const kmp_addr_t *addr, void *pdu, uint16_t size, uint8_t tx_identifier);
/**
* kmp_service_msg_if_register registers message interface
@ -341,6 +371,19 @@ typedef int8_t kmp_service_msg_if_send(kmp_service_t *service, kmp_type_e type,
*/
int8_t kmp_service_msg_if_register(kmp_service_t *service, kmp_service_msg_if_send *send, uint8_t header_size);
/**
* kmp_service_tx_status tx status indication
*
* \param service KMP service
* \param tx_status tx status
* \param tx_identifier tx identifier
*
* \return < 0 failure
* \return >= 0 success
*
*/
int8_t kmp_service_tx_status_indication(kmp_service_t *service, kmp_tx_status_e tx_status, uint8_t tx_identifier);
/**
* kmp_sec_prot_size security protocol data size
*

View File

@ -48,7 +48,8 @@ typedef struct {
static NS_LIST_DEFINE(kmp_eapol_pdu_if_list, kmp_eapol_pdu_if_t, link);
static int8_t kmp_eapol_pdu_if_send(kmp_service_t *service, kmp_type_e kmp_id, const kmp_addr_t *addr, void *pdu, uint16_t size);
static int8_t kmp_eapol_pdu_if_send(kmp_service_t *service, kmp_type_e kmp_id, const kmp_addr_t *addr, void *pdu, uint16_t size, uint8_t tx_identifier);
static int8_t kmp_eapol_pdu_if_tx_status(protocol_interface_info_entry_t *interface_ptr, eapol_pdu_tx_status_e tx_status, uint8_t tx_identifier);
int8_t kmp_eapol_pdu_if_register(kmp_service_t *service, protocol_interface_info_entry_t *interface_ptr)
{
@ -96,7 +97,7 @@ int8_t kmp_eapol_pdu_if_unregister(kmp_service_t *service)
return 0;
}
static int8_t kmp_eapol_pdu_if_send(kmp_service_t *service, kmp_type_e kmp_id, const kmp_addr_t *addr, void *pdu, uint16_t size)
static int8_t kmp_eapol_pdu_if_send(kmp_service_t *service, kmp_type_e kmp_id, const kmp_addr_t *addr, void *pdu, uint16_t size, uint8_t tx_identifier)
{
if (!service || !addr || !pdu) {
return -1;
@ -123,7 +124,7 @@ static int8_t kmp_eapol_pdu_if_send(kmp_service_t *service, kmp_type_e kmp_id, c
uint8_t *ptr = pdu;
*ptr = kmp_id;
int8_t ret = ws_eapol_pdu_send_to_mpx(interface_ptr, eui_64, pdu, size, pdu);
int8_t ret = ws_eapol_pdu_send_to_mpx(interface_ptr, eui_64, pdu, size, pdu, kmp_eapol_pdu_if_tx_status, tx_identifier);
return ret;
}
@ -160,5 +161,35 @@ int8_t kmp_eapol_pdu_if_receive(protocol_interface_info_entry_t *interface_ptr,
return ret;
}
static int8_t kmp_eapol_pdu_if_tx_status(protocol_interface_info_entry_t *interface_ptr, eapol_pdu_tx_status_e tx_status, uint8_t tx_identifier)
{
kmp_service_t *service = NULL;
ns_list_foreach(kmp_eapol_pdu_if_t, entry, &kmp_eapol_pdu_if_list) {
if (entry->interface_ptr == interface_ptr) {
service = entry->kmp_service;
break;
}
}
if (!service) {
return -1;
}
kmp_tx_status_e kmp_tx_status;
if (tx_status == EAPOL_PDU_TX_OK) {
kmp_tx_status = KMP_TX_OK;
} else if (tx_status == EAPOL_PDU_TX_ERR_TX_NO_ACK) {
kmp_tx_status = KMP_TX_ERR_TX_NO_ACK;
} else {
kmp_tx_status = KMP_TX_ERR_UNSPEC;
}
int8_t ret = kmp_service_tx_status_indication(service, kmp_tx_status, tx_identifier);
return ret;
}
#endif /* HAVE_WS */

View File

@ -47,7 +47,7 @@ typedef struct {
ns_list_link_t link; /**< Link */
} kmp_socket_if_t;
static int8_t kmp_socket_if_send(kmp_service_t *service, kmp_type_e kmp_id, const kmp_addr_t *addr, void *pdu, uint16_t size);
static int8_t kmp_socket_if_send(kmp_service_t *service, kmp_type_e kmp_id, const kmp_addr_t *addr, void *pdu, uint16_t size, uint8_t tx_identifier);
static void kmp_socket_if_socket_cb(void *ptr);
static NS_LIST_DEFINE(kmp_socket_if_list, kmp_socket_if_t, link);
@ -108,8 +108,10 @@ int8_t kmp_socket_if_unregister(kmp_service_t *service)
return 0;
}
static int8_t kmp_socket_if_send(kmp_service_t *service, kmp_type_e kmp_id, const kmp_addr_t *addr, void *pdu, uint16_t size)
static int8_t kmp_socket_if_send(kmp_service_t *service, kmp_type_e kmp_id, const kmp_addr_t *addr, void *pdu, uint16_t size, uint8_t tx_identifier)
{
(void) tx_identifier;
if (!service || !pdu || !addr) {
return -1;
}

View File

@ -119,7 +119,16 @@ int8_t eap_tls_sec_prot_lib_message_handle(uint8_t *data, uint16_t length, bool
data += 4;
}
result = EAP_TLS_MSG_MORE_FRAG;
} else if (data[0] == 0) {
} else if (data[0] == 0 || data[0] == EAP_TLS_FRAGMENT_LENGTH) {
// Skip fragment length if present
if (data[0] & EAP_TLS_FRAGMENT_LENGTH) {
if (length < 5) {
tr_error("EAP-TLS: decode error");
return EAP_TLS_MSG_DECODE_ERROR;
}
length -= 4;
data += 4;
}
// Last (or only) fragment or fragment acknowledge. If sending data
// updates acknowledged fragments.
if (new_seq_id && eap_tls_sec_prot_lib_ack_update(tls_send)) {
@ -132,10 +141,15 @@ int8_t eap_tls_sec_prot_lib_message_handle(uint8_t *data, uint16_t length, bool
length -= 1; // EAP-TLS flags
data += 1;
// No further processing for EAP-TLS start
if (result == EAP_TLS_MSG_START) {
return EAP_TLS_MSG_START;
}
// TLS data not included
if (length == 0) {
if (new_seq_id && result == EAP_TLS_MSG_CONTINUE) {
// If received only EAP-TLS header fails, and is not start,
// If received only EAP-TLS header fails, and is not
// fragment acknowledge or last frame
result = EAP_TLS_MSG_FAIL;
}

View File

@ -415,8 +415,8 @@ static void supp_eap_tls_sec_prot_state_machine(sec_prot_t *prot)
return;
}
// Set default timeout for the total maximum length of the negotiation
sec_prot_default_timeout_set(&data->common);
// Set retry timeout based on network size
data->common.ticks = retry_timeout;
// Store sequence ID
supp_eap_tls_sec_prot_seq_id_update(prot);
@ -466,6 +466,9 @@ static void supp_eap_tls_sec_prot_state_machine(sec_prot_t *prot)
// Initialize TLS protocol
if (supp_eap_tls_sec_prot_init_tls(prot) < 0) {
tr_error("TLS init failed");
// If fatal error terminates EAP-TLS
sec_prot_result_set(&data->common, SEC_RESULT_ERROR);
sec_prot_state_set(prot, &data->common, EAP_TLS_STATE_FINISH);
return;
}
// Request TLS to start (send client hello)
@ -508,7 +511,12 @@ static void supp_eap_tls_sec_prot_state_machine(sec_prot_t *prot)
}
} else {
data->wait_tls = false;
if (!data->tls_send.data || data->tls_result == EAP_TLS_RESULT_HANDSHAKE_FATAL_ERROR) {
if (data->tls_result == EAP_TLS_RESULT_HANDSHAKE_FATAL_ERROR) {
// If fatal error terminates EAP-TLS (TLS init has failed)
sec_prot_result_set(&data->common, SEC_RESULT_ERROR);
sec_prot_state_set(prot, &data->common, EAP_TLS_STATE_FINISH);
return;
} else if (!data->tls_send.data) {
// If no more data send response, TLS EAP (empty)
eap_tls_sec_prot_lib_message_allocate(&data->tls_send, TLS_HEAD_LEN, 0);
}

View File

@ -39,40 +39,67 @@
#define TRACE_GROUP "ksep"
#define KEY_SEC_FINISHED_TIMEOUT 1 // Finishes right away
typedef enum {
KEY_INIT = 0,
KEY_CREATE_REQ,
KEY_CREATE_RESP,
KEY_FINISH,
KEY_STATE_INIT = SEC_STATE_INIT,
KEY_STATE_CREATE_REQ = SEC_STATE_CREATE_REQ,
KEY_STATE_CREATE_RESP = SEC_STATE_CREATE_RESP,
KEY_STATE_TX_DONE = SEC_STATE_FIRST,
KEY_STATE_INITIAL_KEY_RECEIVED,
KEY_STATE_FINISH = SEC_STATE_FINISH,
KEY_STATE_FINISHED = SEC_STATE_FINISHED
} key_sec_prot_state_e;
typedef struct {
key_sec_prot_state_e state; /**< Protocol state machine state */
sec_prot_result_e result; /**< Result for ongoing negotiation */
sec_prot_common_t common; /**< Common data */
} key_sec_prot_int_t;
static uint16_t key_sec_prot_size(void);
static int8_t key_sec_prot_init(sec_prot_t *prot);
static int8_t supp_key_sec_prot_init(sec_prot_t *prot);
static int8_t auth_key_sec_prot_init(sec_prot_t *prot);
static void key_sec_prot_create_request(sec_prot_t *prot, sec_prot_keys_t *sec_keys);
static void key_sec_prot_create_response(sec_prot_t *prot, sec_prot_result_e result);
static void key_sec_prot_delete(sec_prot_t *prot);
static int8_t key_sec_prot_initial_key_send(sec_prot_t *prot, sec_prot_keys_t *sec_keys);
static int8_t key_sec_prot_receive(sec_prot_t *prot, void *pdu, uint16_t size);
static void key_sec_prot_state_machine(sec_prot_t *prot);
static int8_t key_sec_prot_tx_status_ind(sec_prot_t *prot, sec_prot_tx_status_e tx_status);
static void key_sec_prot_timer_timeout(sec_prot_t *prot, uint16_t ticks);
static void supp_key_sec_prot_state_machine(sec_prot_t *prot);
static void auth_key_sec_prot_state_machine(sec_prot_t *prot);
#define key_sec_prot_get(prot) (key_sec_prot_int_t *) &prot->data
int8_t key_sec_prot_register(kmp_service_t *service)
int8_t supp_key_sec_prot_register(kmp_service_t *service)
{
if (!service) {
return -1;
}
if (kmp_service_sec_protocol_register(service, IEEE_802_1X_MKA_KEY, key_sec_prot_size, key_sec_prot_init) < 0) {
if (kmp_service_sec_protocol_register(service, IEEE_802_1X_MKA_KEY, key_sec_prot_size, supp_key_sec_prot_init) < 0) {
return -1;
}
if (kmp_service_sec_protocol_register(service, IEEE_802_11_GKH_KEY, key_sec_prot_size, key_sec_prot_init) < 0) {
if (kmp_service_sec_protocol_register(service, IEEE_802_11_GKH_KEY, key_sec_prot_size, supp_key_sec_prot_init) < 0) {
return -1;
}
return 0;
}
int8_t auth_key_sec_prot_register(kmp_service_t *service)
{
if (!service) {
return -1;
}
if (kmp_service_sec_protocol_register(service, IEEE_802_1X_MKA_KEY, key_sec_prot_size, auth_key_sec_prot_init) < 0) {
return -1;
}
if (kmp_service_sec_protocol_register(service, IEEE_802_11_GKH_KEY, key_sec_prot_size, auth_key_sec_prot_init) < 0) {
return -1;
}
@ -84,32 +111,60 @@ static uint16_t key_sec_prot_size(void)
return sizeof(key_sec_prot_int_t);
}
static int8_t key_sec_prot_init(sec_prot_t *prot)
static int8_t supp_key_sec_prot_init(sec_prot_t *prot)
{
prot->create_req = key_sec_prot_create_request;
prot->create_resp = key_sec_prot_create_response;
prot->receive = key_sec_prot_receive;
prot->tx_status_ind = key_sec_prot_tx_status_ind;
prot->delete = key_sec_prot_delete;
prot->state_machine = key_sec_prot_state_machine;
prot->state_machine = supp_key_sec_prot_state_machine;
prot->timer_timeout = key_sec_prot_timer_timeout;
key_sec_prot_int_t *data = key_sec_prot_get(prot);
data->state = KEY_INIT;
data->result = SEC_RESULT_OK;
sec_prot_init(&data->common);
sec_prot_state_set(prot, &data->common, KEY_STATE_INIT);
return 0;
}
static int8_t auth_key_sec_prot_init(sec_prot_t *prot)
{
prot->create_resp = key_sec_prot_create_response;
prot->receive = key_sec_prot_receive;
prot->delete = key_sec_prot_delete;
prot->state_machine = auth_key_sec_prot_state_machine;
prot->timer_timeout = key_sec_prot_timer_timeout;
key_sec_prot_int_t *data = key_sec_prot_get(prot);
sec_prot_init(&data->common);
sec_prot_state_set(prot, &data->common, KEY_STATE_INIT);
return 0;
}
static void key_sec_prot_delete(sec_prot_t *prot)
{
// No op at the moment
(void) prot;
}
static void key_sec_prot_create_request(sec_prot_t *prot, sec_prot_keys_t *sec_keys)
{
key_sec_prot_int_t *data = key_sec_prot_get(prot);
(void) sec_keys;
prot->state_machine_call(prot);
}
static void key_sec_prot_create_response(sec_prot_t *prot, sec_prot_result_e result)
{
key_sec_prot_int_t *data = key_sec_prot_get(prot);
sec_prot_state_set(prot, &data->common, KEY_STATE_CREATE_RESP);
sec_prot_result_set(&data->common, result);
prot->state_machine_call(prot);
}
static int8_t key_sec_prot_initial_key_send(sec_prot_t *prot, sec_prot_keys_t *sec_keys)
{
uint8_t result = 0;
uint16_t kde_len = KDE_GTKL_LEN;
uint8_t *pmk = sec_prot_keys_pmk_get(sec_keys);
@ -134,7 +189,7 @@ static void key_sec_prot_create_request(sec_prot_t *prot, sec_prot_keys_t *sec_k
uint8_t *kde_start = ns_dyn_mem_temporary_alloc(kde_len);
if (!kde_start) {
return;
return -1;
}
uint8_t *kde_end = kde_start;
@ -157,41 +212,35 @@ static void key_sec_prot_create_request(sec_prot_t *prot, sec_prot_keys_t *sec_k
uint16_t eapol_pdu_size = eapol_pdu_key_frame_init(&eapol_pdu, kde_len, kde_start);
uint8_t *eapol_decoded_data = ns_dyn_mem_temporary_alloc(eapol_pdu_size + prot->header_size); // In future fill with data that defines eapol message
if (!eapol_decoded_data) {
data->result = SEC_RESULT_ERR_NO_MEM;
} else {
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 = 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;
}
result = -1;
goto initial_key_exit;
}
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 = 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) {
result = -1;
}
initial_key_exit:
ns_dyn_mem_free(kde_start);
data->state = KEY_CREATE_REQ;
prot->state_machine_call(prot);
}
static void key_sec_prot_create_response(sec_prot_t *prot, sec_prot_result_e result)
{
key_sec_prot_int_t *data = key_sec_prot_get(prot);
data->state = KEY_CREATE_RESP;
data->result = result;
prot->state_machine_call(prot);
return result;
}
static int8_t key_sec_prot_receive(sec_prot_t *prot, void *pdu, uint16_t size)
{
eapol_pdu_t eapol_pdu;
key_sec_prot_int_t *data = key_sec_prot_get(prot);
sec_prot_result_e result = SEC_RESULT_OK;
tr_info("Initial EAPOL-Key recv, eui-64: %s", trace_array(sec_prot_remote_eui_64_addr_get(prot), 8));
@ -248,45 +297,131 @@ static int8_t key_sec_prot_receive(sec_prot_t *prot, void *pdu, uint16_t size)
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);
result = SEC_RESULT_ERROR;
}
sec_prot_result_set(&data->common, result);
prot->state_machine(prot);
if (result != SEC_RESULT_OK) {
return -1;
}
return 0;
}
static void key_sec_prot_state_machine(sec_prot_t *prot)
static int8_t key_sec_prot_tx_status_ind(sec_prot_t *prot, sec_prot_tx_status_e tx_status)
{
key_sec_prot_int_t *data = key_sec_prot_get(prot);
// Mixes currently supplicant and authenticator states
switch (data->state) {
case KEY_INIT:
// empty
break;
case KEY_CREATE_REQ:
// KMP-CREATE.confirm
prot->create_conf(prot, data->result);
// Indicates TX failure
if (tx_status == SEC_PROT_TX_ERR_TX_NO_ACK) {
sec_prot_result_set(&data->common, KMP_RESULT_ERR_TX_NO_ACK);
} else if (tx_status != SEC_PROT_TX_OK) {
// Indicates other failure
sec_prot_result_set(&data->common, KMP_RESULT_ERR_UNSPEC);
}
prot->state_machine_call(prot);
return 0;
}
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);
static void key_sec_prot_timer_timeout(sec_prot_t *prot, uint16_t ticks)
{
key_sec_prot_int_t *data = key_sec_prot_get(prot);
sec_prot_timer_timeout_handle(prot, &data->common, NULL, ticks);
}
static void supp_key_sec_prot_state_machine(sec_prot_t *prot)
{
key_sec_prot_int_t *data = key_sec_prot_get(prot);
switch (sec_prot_state_get(&data->common)) {
case KEY_STATE_INIT:
tr_info("Initial-key init");
sec_prot_state_set(prot, &data->common, KEY_STATE_CREATE_REQ);
prot->timer_start(prot);
break;
case KEY_STATE_CREATE_REQ:
// KMP-CREATE.confirm
prot->create_conf(prot, sec_prot_result_get(&data->common));
// Send initial-key message
if (key_sec_prot_initial_key_send(prot, prot->sec_keys) < 0) {
// Error on sending, ready to be deleted
sec_prot_state_set(prot, &data->common, KEY_STATE_FINISH);
return;
}
// Ready to be deleted
// Waits for TX acknowledge
sec_prot_state_set(prot, &data->common, KEY_STATE_TX_DONE);
break;
case KEY_STATE_TX_DONE:
sec_prot_state_set(prot, &data->common, KEY_STATE_FINISH);
break;
case KEY_STATE_FINISH:
// KMP-FINISHED.indication,
prot->finished_ind(prot, sec_prot_result_get(&data->common), 0);
sec_prot_state_set(prot, &data->common, KEY_STATE_FINISHED);
data->common.ticks = KEY_SEC_FINISHED_TIMEOUT;
break;
case KEY_STATE_FINISHED:
tr_info("Initial-key finished");
prot->timer_stop(prot);
prot->finished(prot);
break;
case KEY_CREATE_RESP:
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);
default:
break;
}
}
static void auth_key_sec_prot_state_machine(sec_prot_t *prot)
{
key_sec_prot_int_t *data = key_sec_prot_get(prot);
switch (sec_prot_state_get(&data->common)) {
case KEY_STATE_INIT:
tr_info("Initial-key init");
sec_prot_state_set(prot, &data->common, KEY_STATE_INITIAL_KEY_RECEIVED);
prot->timer_start(prot);
break;
case KEY_STATE_INITIAL_KEY_RECEIVED:
if (!sec_prot_result_ok_check(&data->common)) {
// Goes right away to finished
sec_prot_state_set(prot, &data->common, KEY_STATE_FINISHED);
return;
}
// Ready to be deleted
// Send KMP-CREATE.indication
prot->create_ind(prot);
sec_prot_state_set(prot, &data->common, KEY_STATE_CREATE_RESP);
break;
case KEY_STATE_CREATE_RESP:
// Goes to finish state right away
sec_prot_state_set(prot, &data->common, KEY_STATE_FINISH);
break;
case KEY_STATE_FINISH:
// KMP-FINISHED.indication,
prot->finished_ind(prot, sec_prot_result_get(&data->common), 0);
sec_prot_state_set(prot, &data->common, KEY_STATE_FINISHED);
data->common.ticks = KEY_SEC_FINISHED_TIMEOUT;
break;
case KEY_STATE_FINISHED: {
tr_info("Initial-key finished, eui-64: %s", trace_array(sec_prot_remote_eui_64_addr_get(prot), 8));
prot->finished(prot);
break;
}
default:
break;
}

View File

@ -26,13 +26,23 @@
*/
/**
* key_sec_prot_register register EAPOL-Key protocol to KMP service
* supp_key_sec_prot_register register supplicant EAPOL-Key protocol to KMP service
*
* \param service KMP service
*
* \return < 0 failure
* \return >= 0 success
*/
int8_t key_sec_prot_register(kmp_service_t *service);
int8_t supp_key_sec_prot_register(kmp_service_t *service);
/**
* auth_key_sec_prot_register register authenticator EAPOL-Key protocol to KMP service
*
* \param service KMP service
*
* \return < 0 failure
* \return >= 0 success
*/
int8_t auth_key_sec_prot_register(kmp_service_t *service);
#endif /* KEY_SEC_PROT_H_ */

View File

@ -30,9 +30,11 @@
typedef enum {
SEC_RESULT_OK = 0,
SEC_RESULT_ERR_NO_MEM = -1,
SEC_RESULT_TIMEOUT = -2,
SEC_RESULT_ERROR = -3,
SEC_RESULT_CONF_ERROR = -4
SEC_RESULT_ERR_TX_NO_ACK = -2,
SEC_RESULT_ERR_UNSPEC = -3,
SEC_RESULT_TIMEOUT = -4,
SEC_RESULT_ERROR = -5,
SEC_RESULT_CONF_ERROR = -6
} sec_prot_result_e;
typedef enum {
@ -50,6 +52,12 @@ typedef enum {
SEC_PROT_TYPE_TLS
} sec_prot_type_e;
typedef enum {
SEC_PROT_TX_OK = 0, // Successful
SEC_PROT_TX_ERR_TX_NO_ACK = -1, // No acknowledge was received
SEC_PROT_TX_ERR_UNSPEC = -2, // Other reason
} sec_prot_tx_status_e;
/**
* sec_prot_create_request KMP-CREATE.request to security protocol
*
@ -137,6 +145,18 @@ typedef int8_t sec_prot_receive(sec_prot_t *prot, void *pdu, uint16_t size);
*/
typedef int8_t sec_prot_send(sec_prot_t *prot, void *pdu, uint16_t size);
/**
* sec_prot_tx_status_ind tx status indication
*
* \param prot protocol
* \param tx_status tx status
*
* \return < 0 failure
* \return >= 0 success
*
*/
typedef int8_t sec_prot_tx_status_ind(sec_prot_t *prot, sec_prot_tx_status_e tx_status);
/**
* sec_prot_delete delete the protocol data
*
@ -232,6 +252,7 @@ struct sec_prot_s {
sec_prot_send *send; /**< Protocol send */
sec_prot_receive *receive; /**< Protocol receive */
sec_prot_tx_status_ind *tx_status_ind; /**< TX status indication */
sec_prot_delete *delete; /**< Protocol delete */

View File

@ -581,6 +581,11 @@ void sec_prot_keys_gtks_hash_generate(sec_prot_gtk_keys_t *gtks, uint8_t *gtkhas
}
}
void sec_prot_keys_gtk_hash_generate(uint8_t *gtk, uint8_t *gtk_hash)
{
sec_prot_lib_gtkhash_generate(gtk, gtk_hash);
}
gtk_mismatch_e sec_prot_keys_gtks_hash_update(sec_prot_gtk_keys_t *gtks, uint8_t *gtkhash)
{
uint8_t *gtk_hash_ptr = gtkhash;

View File

@ -92,6 +92,17 @@ typedef struct {
bool ptk_mismatch: 1; /**< Remote PTK mismatch reported */
} sec_prot_keys_t;
// Frame counter data
typedef struct {
uint8_t gtk[GTK_LEN]; /**< GTK of the frame counter */
uint32_t frame_counter; /**< Frame counter */
bool set : 1; /**< Value has been set */
} frame_counter_t;
typedef struct {
frame_counter_t counter[GTK_NUM]; /**< Frame counter for each GTK key */
} frame_counters_t;
/*
* GTK mismatch types, list is ordered according to priority of mismatch i.e. if there
* are both hash and lifetime mismatch, hash has greater priority
@ -632,6 +643,15 @@ bool sec_prot_keys_gtk_status_is_live(sec_prot_gtk_keys_t *gtks, uint8_t index);
*/
void sec_prot_keys_gtks_hash_generate(sec_prot_gtk_keys_t *gtks, uint8_t *gtk_hash);
/**
* sec_prot_keys_gtk_hash_generate generate GTK hash for a GTK
*
* \param gtk GTK key
* \param gtk_hash GTK hash for a GTK
*
*/
void sec_prot_keys_gtk_hash_generate(uint8_t *gtk, uint8_t *gtk_hash);
/**
* sec_prot_keys_gtks_hash_update update GTKs based on GTK hash
*

View File

@ -487,6 +487,10 @@ static int tls_sec_prot_lib_x509_crt_verify(void *ctx, mbedtls_x509_crt *crt, in
if (crt->sig_pk != MBEDTLS_PK_ECDSA) {
tr_error("Invalid signature pk algorithm");
}
if (*flags & MBEDTLS_X509_BADCERT_FUTURE) {
tr_info("Certificate time future");
*flags &= ~MBEDTLS_X509_BADCERT_FUTURE;
}
// Verify client/server certificate of the chain
if (certificate_depth == 0) {

View File

@ -38,16 +38,23 @@ static NS_LARGE NS_LIST_DEFINE(dhcpv6_client_nonTemporal_list, dhcpv6_client_ser
static dhcpv6_client_server_data_t *libdhcvp6_nontemporalAddress_entry_allocate(void)
{
dhcpv6_client_server_data_t *newEntry = ns_dyn_mem_alloc(sizeof(dhcpv6_client_server_data_t));
if (newEntry) {
newEntry->T0 = 0;
newEntry->T1 = 0;
newEntry->reNewTimer = 0;
newEntry->iaNonTemporalStructValid = false;
newEntry->GlobalAddress = false;
newEntry->useServerAddress = false;
newEntry->iaNontemporalAddress.preferredTime = 0;
newEntry->iaNontemporalAddress.validLifetime = 0;
uint8_t *temporary_duid = ns_dyn_mem_alloc(16); //Support DUID-LL, DUID-LLP and DUID-UUID by default
if (!newEntry || !temporary_duid) {
ns_dyn_mem_free(newEntry);
ns_dyn_mem_free(temporary_duid);
return NULL;
}
newEntry->T0 = 0;
newEntry->T1 = 0;
newEntry->reNewTimer = 0;
newEntry->iaNonTemporalStructValid = false;
newEntry->GlobalAddress = false;
newEntry->useServerAddress = false;
newEntry->iaNontemporalAddress.preferredTime = 0;
newEntry->iaNontemporalAddress.validLifetime = 0;
newEntry->dyn_server_duid_length = 16;
newEntry->serverDynamic_DUID = temporary_duid;
return newEntry;
}
@ -123,35 +130,34 @@ uint32_t libdhcpv6_renew_time_define(dhcpv6_client_server_data_t *addresInfo)
return renewTimer;
}
dhcpv6_client_server_data_t *libdhcvp6_nontemporalAddress_server_data_allocate(int8_t interfaceId, uint8_t instanceId, uint8_t *duiId, uint16_t duiLinkType, uint8_t *nonTemporalPrefix, uint8_t *serverIPv6Address)
dhcpv6_client_server_data_t *libdhcvp6_nontemporalAddress_server_data_allocate(int8_t interfaceId, uint8_t instanceId, uint8_t *nonTemporalPrefix, uint8_t *serverIPv6Address)
{
uint32_t iaId;
uint8_t *ptr;
dhcpv6_client_server_data_t *new_entry = NULL;
if (duiId) {
//allocate new Entry
iaId = libdhcpv6_IAID_generate();
new_entry = libdhcvp6_nontemporalAddress_entry_allocate();
if (new_entry) {
new_entry->IAID = iaId;
new_entry->interfaceId = interfaceId;
new_entry->instanceId = instanceId;
//save Cliet ID
memcpy(new_entry->clientId, duiId, 8);
new_entry->clientLinkIdType = duiLinkType;
if (serverIPv6Address) {
memcpy(new_entry->server_address, serverIPv6Address, 16);
new_entry->useServerAddress = true;
}
if (nonTemporalPrefix) {
uint8_t *ptr = new_entry->iaNontemporalAddress.addressPrefix;
memcpy(ptr, nonTemporalPrefix, 8);
memset((ptr + 8), 0, 8);
new_entry->iaNonTemporalStructValid = true;
new_entry->iaNontemporalAddress.preferredTime = 0;
new_entry->iaNontemporalAddress.validLifetime = 0;
}
ns_list_add_to_end(&dhcpv6_client_nonTemporal_list, new_entry);
//allocate new Entry
iaId = libdhcpv6_IAID_generate();
new_entry = libdhcvp6_nontemporalAddress_entry_allocate();
if (new_entry) {
new_entry->IAID = iaId;
new_entry->interfaceId = interfaceId;
new_entry->instanceId = instanceId;
new_entry->serverDUID.duid = NULL;
new_entry->serverDUID.duid_length = 0;
if (serverIPv6Address) {
memcpy(new_entry->server_address, serverIPv6Address, 16);
new_entry->useServerAddress = true;
}
if (nonTemporalPrefix) {
ptr = new_entry->iaNontemporalAddress.addressPrefix;
memcpy(ptr, nonTemporalPrefix, 8);
memset((ptr + 8), 0, 8);
new_entry->iaNonTemporalStructValid = true;
new_entry->iaNontemporalAddress.preferredTime = 0;
new_entry->iaNontemporalAddress.validLifetime = 0;
}
ns_list_add_to_end(&dhcpv6_client_nonTemporal_list, new_entry);
}
return new_entry;
}
@ -160,6 +166,7 @@ void libdhcvp6_nontemporalAddress_server_data_free(dhcpv6_client_server_data_t *
{
if (removedEntry) {
ns_list_remove(&dhcpv6_client_nonTemporal_list, removedEntry);
ns_dyn_mem_free(removedEntry->serverDynamic_DUID);
ns_dyn_mem_free(removedEntry);
}
}
@ -228,26 +235,19 @@ dhcpv6_client_server_data_t *libdhcpv6_nonTemporal_validate_class_pointer(void *
}
uint16_t libdhcpv6_duid_option_size(uint16_t linkType)
uint16_t libdhcpv6_duid_option_size(uint16_t duidLength)
{
uint16_t length = 8; // Type & Length header part *2
if (linkType == DHCPV6_DUID_HARDWARE_EUI64_TYPE ||
linkType == DHCPV6_DUID_HARDWARE_IEEE_802_NETWORKS_TYPE) {
length += 8;
} else {
length += 6;
}
return length;
return duidLength + 6; //ID Type 2, length 2 ,Duid Type 2 + duid data
}
uint16_t libdhcpv6_client_data_option_size(uint16_t linkType)
uint8_t libdhcpv6_duid_linktype_size(uint16_t linkType)
{
uint16_t optionLength = 4;
optionLength += libdhcpv6_duid_option_size(linkType);
optionLength += libdhcpv6_ia_address_option_size();
optionLength += libdhcpv6_client_last_transaction_time_option_size();
return optionLength;
if (linkType == DHCPV6_DUID_HARDWARE_EUI64_TYPE ||
linkType == DHCPV6_DUID_HARDWARE_IEEE_802_NETWORKS_TYPE) {
return 8;
}
return 6;
}
uint16_t libdhcvp6_request_option_size(uint8_t optionCnt)
@ -345,18 +345,14 @@ uint8_t *libdhcvp6_request_option_write(uint8_t *ptr, uint8_t optionCnt, uint16_
return ptr;
}
uint8_t *libdhcpv6_duid_option_write(uint8_t *ptr, uint16_t duidRole, const dhcp_link_options_params_t *duid)
uint8_t *libdhcpv6_duid_option_write(uint8_t *ptr, uint16_t duidRole, const dhcp_duid_options_params_t *duid)
{
uint16_t length = libdhcpv6_duid_option_size(duid->linkType);
length -= 4; //Cut normal option header out
uint16_t length = duid->duid_length + 2;
ptr = common_write_16_bit(duidRole, ptr);
ptr = common_write_16_bit(length, ptr);
ptr = common_write_16_bit(DHCPV6_DUID_LINK_LAYER_TYPE, ptr);
ptr = common_write_16_bit(duid->linkType, ptr);
length -= 4; //Cut normal option header out
memcpy(ptr, duid->linkID, length);
ptr += length;
ptr = common_write_16_bit(duid->type, ptr);
memcpy(ptr, duid->duid, duid->duid_length);
ptr += duid->duid_length;
return ptr;
}
@ -460,25 +456,23 @@ int libdhcpv6_message_option_discover(uint8_t *ptr, uint16_t data_len, uint16_t
return -1;
}
int libdhcpv6_compare_DUID(dhcp_link_options_params_t *targetId, dhcp_link_options_params_t *parsedId)
int libdhcpv6_compare_DUID(dhcp_duid_options_params_t *targetId, dhcp_duid_options_params_t *parsedId)
{
if (targetId->linkType == parsedId->linkType) {
uint8_t cmpLen;
if (targetId->linkType == DHCPV6_DUID_HARDWARE_EUI64_TYPE ||
targetId->linkType == DHCPV6_DUID_HARDWARE_IEEE_802_NETWORKS_TYPE) {
//Compare Current Interface EUID64
cmpLen = 8;
} else {
cmpLen = 6;
}
if (memcmp(targetId->linkID, parsedId->linkID, cmpLen) == 0) {
return 0;
}
if (targetId->type != parsedId->type) {
return -1;
}
return -1;
if (targetId->duid_length != parsedId->duid_length) {
return -1;
}
if (memcmp(targetId->duid, parsedId->duid, targetId->duid_length) != 0) {
return -1;
}
return 0;
}
int libdhcpv6_reply_message_option_validate(dhcp_link_options_params_t *clientId, dhcp_link_options_params_t *serverId, dhcp_ia_non_temporal_params_t *dhcp_ia_non_temporal_params, uint8_t *ptr, uint16_t data_length)
int libdhcpv6_reply_message_option_validate(dhcp_duid_options_params_t *clientId, dhcp_duid_options_params_t *serverId, dhcp_ia_non_temporal_params_t *dhcp_ia_non_temporal_params, uint8_t *ptr, uint16_t data_length)
{
/**
* Solication Message Should Include Next Options:
@ -503,7 +497,7 @@ int libdhcpv6_reply_message_option_validate(dhcp_link_options_params_t *clientId
return 0;
}
int libdhcpv6_advertisment_message_option_validate(dhcp_link_options_params_t *clientId, dhcp_link_options_params_t *serverId, dhcp_ia_non_temporal_params_t *dhcp_ia_non_temporal_params, uint8_t *ptr, uint16_t data_length)
int libdhcpv6_advertisment_message_option_validate(dhcp_duid_options_params_t *clientId, dhcp_duid_options_params_t *serverId, dhcp_ia_non_temporal_params_t *dhcp_ia_non_temporal_params, uint8_t *ptr, uint16_t data_length)
{
/**
* Solication Message Should Include Next Options:
@ -528,7 +522,7 @@ int libdhcpv6_advertisment_message_option_validate(dhcp_link_options_params_t *c
return 0;
}
#ifdef HAVE_DHCPV6_SERVER
int libdhcpv6_renew_message_options_validate(uint8_t *ptr, uint16_t data_length, dhcp_link_options_params_t *clientLinkData, dhcp_link_options_params_t *serverLinkData, dhcp_ia_non_temporal_params_t *dhcp_ia_non_temporal_params)
int libdhcpv6_renew_message_options_validate(uint8_t *ptr, uint16_t data_length, dhcp_duid_options_params_t *clientLinkData, dhcp_duid_options_params_t *serverLinkData, dhcp_ia_non_temporal_params_t *dhcp_ia_non_temporal_params)
{
/**
@ -565,7 +559,7 @@ int libdhcpv6_renew_message_options_validate(uint8_t *ptr, uint16_t data_length,
int libdhcpv6_solication_message_options_validate(uint8_t *ptr, uint16_t data_length, dhcp_link_options_params_t *clientLink, dhcp_ia_non_temporal_params_t *dhcp_ia_non_temporal_params)
int libdhcpv6_solication_message_options_validate(uint8_t *ptr, uint16_t data_length, dhcp_duid_options_params_t *clientLink, dhcp_ia_non_temporal_params_t *dhcp_ia_non_temporal_params)
{
/**
* Solication Message Should Include Next Options:
@ -620,34 +614,102 @@ bool libdhcpv6_rapid_commit_option_at_packet(uint8_t *ptr, uint16_t length)
return retVal;
}
int libdhcpv6_get_duid_by_selected_type_id_opt(uint8_t *ptr, uint16_t data_length, uint16_t type, dhcp_link_options_params_t *params)
bool libdhcpv6_duid_length_validate(uint16_t duid_type, uint16_t duid_length)
{
uint16_t min_length;
switch (duid_type) {
case DHCPV6_DUID_LINK_LAYER_PLUS_TIME_TYPE:
//hardware type (16 bits) + time (32 bits) +link layer address (variable length 1 min)
min_length = 7; //Link Time Time
break;
case DHCPV6_DUID_EN_TYPE: //enterprise-number (32-bits) +identifier (variable length 1 min)
min_length = 5;
break;
case DHCPV6_DUID_LINK_LAYER_TYPE:
//hardware type (16 bits) + link layer address (variable length 1 min)
min_length = 3; //Type 2 and MiN DUI-id 1
break;
case DHCPV6_DUID_UUID_TYPE:
//UUID (128-bits)
if (duid_length != 16) {
return false;
}
min_length = 16;
break;
default://Unsupported type set length to inpossible
min_length = 0xffff;
break;
}
//Validate min and MAX length
if (min_length > duid_length || min_length == 0xffff) {
//Too short
return false;
}
if (duid_length > 128 - min_length) {
//Too Long
return false;
}
return true;
}
int libdhcpv6_get_duid_by_selected_type_id_opt(uint8_t *ptr, uint16_t data_length, uint16_t type, dhcp_duid_options_params_t *params)
{
dhcp_options_msg_t option_msg;
/** Verify DHCPV6_CLIENT_ID_OPTION */
if (libdhcpv6_message_option_discover(ptr, data_length, type, &option_msg) == 0) {
if (option_msg.len >= DHCPV6_SERVER_ID_MAC48_OPTION_LEN) {
uint8_t *t_ptr = option_msg.msg_ptr;
type = common_read_16_bit(t_ptr);
t_ptr += 2;
params->linkType = common_read_16_bit(t_ptr);
t_ptr += 2;
if (type == DHCPV6_DUID_LINK_LAYER_TYPE) {
params->linkID = t_ptr;
if ((params->linkType == DHCPV6_DUID_HARDWARE_EUI48_TYPE) && (option_msg.len == DHCPV6_SERVER_ID_MAC48_OPTION_LEN)) {
return 0;
} else if ((params->linkType == DHCPV6_DUID_HARDWARE_EUI64_TYPE) && (option_msg.len == DHCPV6_SERVER_ID_MAC64_OPTION_LEN)) {
return 0;
} else if ((params->linkType == DHCPV6_DUID_HARDWARE_IEEE_802_NETWORKS_TYPE) && (option_msg.len == DHCPV6_SERVER_ID_MAC64_OPTION_LEN)) {
return 0;
}
}
}
if (libdhcpv6_message_option_discover(ptr, data_length, type, &option_msg) != 0) {
return -1;
}
return -1;
if (option_msg.len < 5) {
return -1;
}
uint8_t *t_ptr = option_msg.msg_ptr;
params->type = common_read_16_bit(t_ptr);
t_ptr += 2;
params->duid = t_ptr;
params->duid_length = option_msg.len - 2;
//Validate types and lengths
if (!libdhcpv6_duid_length_validate(params->type, params->duid_length)) {
return -1;
}
return 0;
}
int libdhcpv6_get_link_address_from_duid(uint8_t *ptr, uint16_t data_length, uint16_t type, dhcp_link_options_params_t *params)
{
if ((type != DHCPV6_DUID_LINK_LAYER_TYPE && type != DHCPV6_DUID_LINK_LAYER_PLUS_TIME_TYPE) || data_length < 8) {
return -1;
}
params->link_type = common_read_16_bit(ptr);
ptr += 2;
data_length -= 2;
if (type == DHCPV6_DUID_LINK_LAYER_PLUS_TIME_TYPE) {
params->link_time = common_read_32_bit(ptr);
ptr += 4;
data_length -= 4;
} else {
params->link_time = 0;
}
if (libdhcpv6_duid_linktype_size(params->link_type) > data_length) {
return -1;
}
params->link_id = ptr;
return 0;
}
int libdhcpv6_get_IA_address(uint8_t *ptr, uint16_t data_length, dhcp_ia_non_temporal_params_t *params)
{
dhcp_options_msg_t option_msg;
@ -708,26 +770,26 @@ int libdhcpv6_get_IA_address(uint8_t *ptr, uint16_t data_length, dhcp_ia_non_tem
return -1;
}
uint16_t libdhcpv6_address_request_message_len(uint16_t clientLinkType, uint16_t serverLinkType, uint8_t requstOptionCnt, bool add_address)
uint16_t libdhcpv6_address_request_message_len(uint16_t clientDUIDLength, uint16_t serverDUIDLength, uint8_t requstOptionCnt, bool add_address)
{
uint16_t length = 0;
length += libdhcpv6_header_size();
length += libdhcpv6_elapsed_time_option_size();
length += libdhcpv6_duid_option_size(clientLinkType);
length += libdhcpv6_duid_option_size(serverLinkType);
length += libdhcpv6_duid_option_size(clientDUIDLength);
length += libdhcpv6_duid_option_size(serverDUIDLength);
length += libdhcvp6_request_option_size(requstOptionCnt);
length += libdhcpv6_rapid_commit_option_size();
length += libdhcpv6_non_temporal_address_size(add_address);
return length;
}
#ifdef HAVE_DHCPV6_SERVER
uint16_t libdhcpv6_address_reply_message_len(uint16_t clientLinkType, uint16_t serverLinkType, uint16_t vendorDataLen, bool rapidCommon, bool status)
uint16_t libdhcpv6_address_reply_message_len(uint16_t clientDUIDLength, uint16_t serverDUIDLength, uint16_t vendorDataLen, bool rapidCommon, bool status)
{
uint16_t length = 0;
length += libdhcpv6_header_size();
length += libdhcpv6_duid_option_size(clientLinkType);
length += libdhcpv6_duid_option_size(serverLinkType);
length += libdhcpv6_duid_option_size(clientDUIDLength);
length += libdhcpv6_duid_option_size(serverDUIDLength);
if (rapidCommon) {
length += libdhcpv6_rapid_commit_option_size();
}
@ -747,7 +809,7 @@ uint16_t libdhcpv6_address_reply_message_len(uint16_t clientLinkType, uint16_t s
}
#endif
uint8_t *libdhcpv6_generic_nontemporal_address_message_write(uint8_t *ptr, dhcpv6_solication_base_packet_s *packet, dhcpv6_ia_non_temporal_address_s *nonTemporalAddress, dhcp_link_options_params_t *serverLink)
uint8_t *libdhcpv6_generic_nontemporal_address_message_write(uint8_t *ptr, dhcpv6_solication_base_packet_s *packet, dhcpv6_ia_non_temporal_address_s *nonTemporalAddress, dhcp_duid_options_params_t *serverLink)
{
bool add_address = false;
if (nonTemporalAddress) {
@ -803,13 +865,13 @@ uint8_t *libdhcpv6_reply_message_write(uint8_t *ptr, dhcpv6_reply_packet_s *repl
return ptr;
}
uint16_t libdhcpv6_solication_message_length(uint16_t clientLinkType, bool addressDefined, uint8_t requestOptionCount)
uint16_t libdhcpv6_solication_message_length(uint16_t clientDUIDLength, bool addressDefined, uint8_t requestOptionCount)
{
uint16_t length = 0;
length += libdhcpv6_header_size();
length += libdhcpv6_elapsed_time_option_size();
length += libdhcpv6_rapid_commit_option_size();
length += libdhcpv6_duid_option_size(clientLinkType);
length += libdhcpv6_duid_option_size(clientDUIDLength);
length += libdhcpv6_non_temporal_address_size(addressDefined);
length += libdhcvp6_request_option_size(requestOptionCount);
return length;

View File

@ -26,10 +26,18 @@
#include "ns_list.h"
typedef struct dhcp_duid_options_params {
uint16_t type;
uint16_t duid_length;
uint8_t *duid;
} dhcp_duid_options_params_t;
typedef struct {
uint16_t linkType;
uint8_t *linkID;
uint16_t link_type;
uint32_t link_time;
uint8_t *link_id;
} dhcp_link_options_params_t;
typedef struct {
uint16_t type;
uint16_t len;
@ -49,8 +57,8 @@ typedef struct {
} dhcpv6_ia_non_temporal_address_s;
typedef struct {
dhcp_link_options_params_t clientDUID;
dhcp_link_options_params_t serverDUID;
dhcp_duid_options_params_t clientDUID;
dhcp_duid_options_params_t serverDUID;
uint32_t transaction_ID;
uint32_t iaId;
uint32_t T0;
@ -66,7 +74,7 @@ typedef struct {
typedef struct {
uint8_t messageType;
uint32_t transActionId;
dhcp_link_options_params_t clientDUID;
dhcp_duid_options_params_t clientDUID;
uint32_t iaID;
uint32_t timerT0;
uint32_t timerT1;
@ -93,19 +101,19 @@ typedef struct dhcpv6_ia_nontemp_addres_entry_t {
typedef struct dhcpv6_client_server_entry_s {
int8_t interfaceId;
uint8_t instanceId; // instance identifying specific client
uint8_t dyn_server_duid_length;
bool useServerAddress; //This indicate
bool iaNonTemporalStructValid;
bool GlobalAddress;
uint8_t server_address[16];
uint8_t serverLinkId[8];
uint16_t serverLinkType;
uint8_t clientId[8];
uint16_t clientLinkIdType;
uint8_t *serverDynamic_DUID;
uint32_t T0;
uint32_t T1;
uint32_t IAID; //Take random for that
uint32_t transActionId; //Client save this and use for get
uint32_t reNewTimer;
dhcp_duid_options_params_t clientDUID;
dhcp_duid_options_params_t serverDUID;
dhcpv6_ia_nontemp_addres_entry_t iaNontemporalAddress; // Dynamical Part
ns_list_link_t link; /*!< List link entry */
} dhcpv6_client_server_data_t;
@ -188,7 +196,10 @@ typedef struct dhcpv6_relay_msg {
#define DHCPV6_SERVER_ID_MAC64_OPTION_LEN 0x000c
/** Server Identifier END */
/** Common for server and Client Identifier option */
#define DHCPV6_DUID_LINK_LAYER_PLUS_TIME_TYPE 0x0001
#define DHCPV6_DUID_EN_TYPE 0x0002
#define DHCPV6_DUID_LINK_LAYER_TYPE 0x0003
#define DHCPV6_DUID_UUID_TYPE 0x0004
#define DHCPV6_DUID_HARDWARE_IEEE_802_NETWORKS_TYPE 0x0006
#define DHCPV6_DUID_HARDWARE_EUI64_TYPE 0x001b
#define DHCPV6_DUID_HARDWARE_EUI48_TYPE 0x0001
@ -226,7 +237,7 @@ typedef struct dhcpv6_relay_msg {
/** DHCPv6 client Nontemporal address and server data allocate, free and search */
dhcpv6_client_server_data_t *libdhcvp6_nontemporalAddress_server_data_allocate(int8_t interfaceId, uint8_t instanceId, uint8_t *duiId, uint16_t duiLinkType, uint8_t *nonTemporalPrefix, uint8_t *serverIPv6Address);
dhcpv6_client_server_data_t *libdhcvp6_nontemporalAddress_server_data_allocate(int8_t interfaceId, uint8_t instanceId, uint8_t *nonTemporalPrefix, uint8_t *serverIPv6Address);
void libdhcvp6_nontemporalAddress_server_data_free(dhcpv6_client_server_data_t *removedEntry);
uint32_t libdhcpv6_renew_time_define(dhcpv6_client_server_data_t *addresInfo);
@ -262,26 +273,29 @@ int libdhcpv6_message_option_discover(uint8_t *ptr, uint16_t data_len, uint16_t
#define libdhcpv6_client_last_transaction_time_option_size() 8
/** Dynamic Option lengths */
uint16_t libdhcpv6_duid_option_size(uint16_t linkType);
uint16_t libdhcpv6_duid_option_size(uint16_t duidLength);
uint8_t libdhcpv6_duid_linktype_size(uint16_t linkType);
uint16_t libdhcvp6_request_option_size(uint8_t optionCnt);
uint16_t libdhcpv6_non_temporal_address_size(bool addressDefined);
uint16_t libdhcpv6_solication_message_length(uint16_t clientLinkType, bool addressDefined, uint8_t requestOptionCount);
uint16_t libdhcpv6_address_request_message_len(uint16_t clientLinkType, uint16_t serverLinkType, uint8_t requstOptionCnt, bool add_address);
uint16_t libdhcpv6_solication_message_length(uint16_t clientDUIDLength, bool addressDefined, uint8_t requestOptionCount);
uint16_t libdhcpv6_address_request_message_len(uint16_t clientDUIDLength, uint16_t serverDUIDLength, uint8_t requstOptionCnt, bool add_address);
#ifdef HAVE_DHCPV6_SERVER
uint16_t libdhcpv6_address_reply_message_len(uint16_t clientLinkType, uint16_t serverLinkType, uint16_t vendorDataLen, bool rapidCommon, bool status);
uint16_t libdhcpv6_address_reply_message_len(uint16_t clientDUIDLength, uint16_t serverDUIDLength, uint16_t vendorDataLen, bool rapidCommon, bool status);
#else
#define libdhcpv6_address_reply_message_len(clientLinkType, serverLinkType, vendorDataLen, rapidCommon, status) 0
#define libdhcpv6_address_reply_message_len(clientDUIDLength, serverDUIDLength, vendorDataLen, rapidCommon, status) 0
#endif
uint8_t *libdhcpv6_generic_nontemporal_address_message_write(uint8_t *ptr, dhcpv6_solication_base_packet_s *packet, dhcpv6_ia_non_temporal_address_s *nonTemporalAddress, dhcp_link_options_params_t *serverLink);
uint8_t *libdhcpv6_generic_nontemporal_address_message_write(uint8_t *ptr, dhcpv6_solication_base_packet_s *packet, dhcpv6_ia_non_temporal_address_s *nonTemporalAddress, dhcp_duid_options_params_t *serverLink);
uint8_t *libdhcpv6_reply_message_write(uint8_t *ptr, dhcpv6_reply_packet_s *replyPacket, dhcpv6_ia_non_temporal_address_s *nonTemporalAddress, dhcpv6_vendor_data_packet_s *vendorData);
uint8_t *libdhcpv6_dhcp_relay_msg_write(uint8_t *ptr, uint8_t type, uint8_t hop_limit, uint8_t *peer_addres, uint8_t *link_address);
uint8_t *libdhcpv6_dhcp_option_header_write(uint8_t *ptr, uint16_t length);
int libdhcpv6_get_IA_address(uint8_t *ptr, uint16_t data_length, dhcp_ia_non_temporal_params_t *params);
int libdhcpv6_get_duid_by_selected_type_id_opt(uint8_t *ptr, uint16_t data_length, uint16_t type, dhcp_link_options_params_t *params);
int libdhcpv6_compare_DUID(dhcp_link_options_params_t *targetId, dhcp_link_options_params_t *parsedId);
int libdhcpv6_get_duid_by_selected_type_id_opt(uint8_t *ptr, uint16_t data_length, uint16_t type, dhcp_duid_options_params_t *params);
bool libdhcpv6_duid_length_validate(uint16_t duid_type, uint16_t duid_length);
int libdhcpv6_get_link_address_from_duid(uint8_t *ptr, uint16_t data_length, uint16_t type, dhcp_link_options_params_t *params);
int libdhcpv6_compare_DUID(dhcp_duid_options_params_t *targetId, dhcp_duid_options_params_t *parsedId);
/**
* This Function write dhcpv6 basic header
@ -346,23 +360,23 @@ uint8_t *libdhcvp6_request_option_write(uint8_t *ptr, uint8_t optionCnt, uint16_
*
* return incremented pointer after write
*/
uint8_t *libdhcpv6_duid_option_write(uint8_t *ptr, uint16_t duidRole, const dhcp_link_options_params_t *duid);
uint8_t *libdhcpv6_duid_option_write(uint8_t *ptr, uint16_t duidRole, const dhcp_duid_options_params_t *duid);
uint8_t *libdhcpv6_ia_address_option_write(uint8_t *ptr, const uint8_t *addressPtr, uint32_t preferredValidLifeTime, uint32_t validLifeTime);
uint8_t *libdhcpv6_identity_association_option_write(uint8_t *ptr, uint32_t iaID, uint32_t TimerT1, uint32_t TimerT2, bool withAddress);
uint8_t *libdhcpv6_identity_association_option_write_with_status(uint8_t *ptr, uint32_t iaID, uint32_t TimerT1, uint32_t TimerT2, uint16_t status);
uint8_t *libdhcpv6_status_code_write(uint8_t *ptr, uint16_t statusCode);
uint8_t *libdhcpv6_prefix_delegation_info_option_write(uint8_t *ptr, uint32_t iaId);
int libdhcpv6_reply_message_option_validate(dhcp_link_options_params_t *clientId, dhcp_link_options_params_t *serverId, dhcp_ia_non_temporal_params_t *dhcp_ia_non_temporal_params, uint8_t *ptr, uint16_t data_length);
int libdhcpv6_reply_message_option_validate(dhcp_duid_options_params_t *clientId, dhcp_duid_options_params_t *serverId, dhcp_ia_non_temporal_params_t *dhcp_ia_non_temporal_params, uint8_t *ptr, uint16_t data_length);
#ifdef HAVE_DHCPV6_SERVER
int libdhcpv6_renew_message_options_validate(uint8_t *ptr, uint16_t data_length, dhcp_link_options_params_t *clientLinkData, dhcp_link_options_params_t *serverLinkData, dhcp_ia_non_temporal_params_t *dhcp_ia_non_temporal_params);
int libdhcpv6_solication_message_options_validate(uint8_t *ptr, uint16_t data_length, dhcp_link_options_params_t *clientLink, dhcp_ia_non_temporal_params_t *dhcp_ia_non_temporal_params);
int libdhcpv6_renew_message_options_validate(uint8_t *ptr, uint16_t data_length, dhcp_duid_options_params_t *clientLinkData, dhcp_duid_options_params_t *serverLinkData, dhcp_ia_non_temporal_params_t *dhcp_ia_non_temporal_params);
int libdhcpv6_solication_message_options_validate(uint8_t *ptr, uint16_t data_length, dhcp_duid_options_params_t *clientLink, dhcp_ia_non_temporal_params_t *dhcp_ia_non_temporal_params);
#else
#define libdhcpv6_renew_message_options_validate(ptr, data_length, clientLinkData, serverLinkData, dhcp_ia_non_temporal_params) -1
#define libdhcpv6_solication_message_options_validate(ptr, data_length, clientLink, dhcp_ia_non_temporal_params) -1
#endif
int libdhcpv6_advertisment_message_option_validate(dhcp_link_options_params_t *clientId, dhcp_link_options_params_t *serverId, dhcp_ia_non_temporal_params_t *dhcp_ia_non_temporal_params, uint8_t *ptr, uint16_t data_length);
int libdhcpv6_advertisment_message_option_validate(dhcp_duid_options_params_t *clientId, dhcp_duid_options_params_t *serverId, dhcp_ia_non_temporal_params_t *dhcp_ia_non_temporal_params, uint8_t *ptr, uint16_t data_length);
bool libdhcpv6_rapid_commit_option_at_packet(uint8_t *ptr, uint16_t length);
bool libdhcpv6_time_elapsed_option_at_packet(uint8_t *ptr, uint16_t length);
bool libdhcpv6_relay_msg_read(uint8_t *ptr, uint16_t length, dhcpv6_relay_msg_t *relay_msg);

View File

@ -41,16 +41,22 @@ bool libdhcpv6_gua_server_list_empty(void)
static dhcpv6_gua_server_entry_s *libdhcpv6_server_entry_allocate(void)
{
dhcpv6_gua_server_entry_s *entry = ns_dyn_mem_alloc(sizeof(dhcpv6_gua_server_entry_s));
if (entry) {
entry->clientIdSequence = 0;
entry->enableAddressAutonous = true;
entry->clientIdDefaultSuffics = 0x0000000;
entry->maxSuppertedClients = 200;
entry->validLifetime = 7200;
entry->removeCb = NULL;
entry->addCb = NULL;
ns_list_init(&entry->allocatedAddressList);
uint8_t *server_duid_ptr = ns_dyn_mem_alloc(16);// Allocate 128-bit DUID-UUID by default it cover DUID-LL and DUID-LLTP also
if (!entry || !server_duid_ptr) {
ns_dyn_mem_free(entry);
ns_dyn_mem_free(server_duid_ptr);
return NULL;
}
entry->serverDynamic_DUID = server_duid_ptr;
entry->serverDynamic_DUID_length = 16;
entry->clientIdSequence = 0;
entry->enableAddressAutonous = true;
entry->clientIdDefaultSuffics = 0x0000000;
entry->maxSuppertedClients = 200;
entry->validLifetime = 7200;
entry->removeCb = NULL;
entry->addCb = NULL;
ns_list_init(&entry->allocatedAddressList);
return entry;
}
static void libdhcpv6_address_generate(dhcpv6_gua_server_entry_s *serverInfo, dhcpv6_alloacted_address_entry_t *entry)
@ -141,19 +147,58 @@ dhcpv6_gua_server_entry_s *libdhcpv6_server_data_get_by_prefix_and_socketinstanc
return NULL;
}
int libdhcpv6_server_duid_set(dhcpv6_gua_server_entry_s *server_info, uint8_t *duid_ptr, uint16_t duid_type, uint8_t duid_length)
{
//Allocate dynamically new Server DUID if needed
if (duid_length > server_info->serverDynamic_DUID_length) {
//Allocate dynamic new bigger
uint8_t *new_ptr = ns_dyn_mem_alloc(duid_length);
if (!new_ptr) {
return -1;
}
server_info->serverDynamic_DUID_length = duid_length;
ns_dyn_mem_free(server_info->serverDynamic_DUID);
server_info->serverDynamic_DUID = new_ptr;
}
//SET DUID
server_info->serverDUID.duid = server_info->serverDynamic_DUID;
memcpy(server_info->serverDUID.duid, duid_ptr, duid_length);
server_info->serverDUID.duid_length = duid_length;
server_info->serverDUID.type = duid_type;
return 0;
}
dhcpv6_gua_server_entry_s *libdhcpv6_gua_server_allocate(uint8_t *prefix, int8_t interfaceId, uint8_t *serverDUID, uint16_t serverDUIDType)
{
dhcpv6_gua_server_entry_s *entry = libdhcpv6_server_data_get_by_prefix_and_interfaceid(interfaceId, prefix);
if (entry == NULL) {
entry = libdhcpv6_server_entry_allocate();
if (entry) {
memcpy(entry->guaPrefix, prefix, 8);
memcpy(entry->serverDUID, serverDUID, 8);
entry->serverLinkType = serverDUIDType;
entry->interfaceId = interfaceId;
ns_list_add_to_end(&dhcpv6_gua_server_list, entry);
if (!entry) {
return NULL;
}
//Generate Server DUID-LL by default
uint8_t *ptr;
uint8_t duid_ll[16];
uint8_t duid_length;
ptr = duid_ll;
duid_length = libdhcpv6_duid_linktype_size(serverDUIDType) + 2;
ptr = common_write_16_bit(serverDUIDType, ptr);
memcpy(ptr, serverDUID, libdhcpv6_duid_linktype_size(serverDUIDType));
//SET DUID
if (libdhcpv6_server_duid_set(entry, duid_ll, DHCPV6_DUID_LINK_LAYER_TYPE, duid_length) != 0) {
ns_dyn_mem_free(entry->serverDynamic_DUID);
ns_dyn_mem_free(entry);
return NULL;
}
memcpy(entry->guaPrefix, prefix, 8);
entry->interfaceId = interfaceId;
ns_list_add_to_end(&dhcpv6_gua_server_list, entry);
}
return entry;
}
@ -168,6 +213,7 @@ void libdhcpv6_gua_server_free_by_prefix_and_interfaceid(uint8_t *prefix, int8_t
ns_dyn_mem_free(cur);
}
ns_list_remove(&dhcpv6_gua_server_list, serverInfo);
ns_dyn_mem_free(serverInfo->serverDynamic_DUID);
ns_dyn_mem_free(serverInfo);
}
}

View File

@ -26,6 +26,8 @@
#ifdef HAVE_DHCPV6_SERVER
#include "ns_list.h"
#include "libDHCPv6/libDHCPv6.h"
typedef void (dhcp_address_prefer_remove_cb)(int8_t interfaceId, uint8_t *targetAddress, void *prefix_info);
typedef struct dhcpv6_alloacted_address_entry_s {
@ -59,17 +61,18 @@ typedef struct dhcp_address_cache_update {
typedef bool (dhcp_address_add_notify_cb)(int8_t interfaceId, dhcp_address_cache_update_t *address_info, void *route_src);
typedef struct dhcpv6_gua_server_entry_s {
int8_t interfaceId;
bool enableAddressAutonous;
uint16_t socketInstance_id;
uint8_t guaPrefix[8];
uint8_t serverDUID[8];
uint16_t serverLinkType;
uint32_t maxSuppertedClients;
uint32_t clientIdDefaultSuffics;
uint32_t clientIdSequence; /*!< Define */
uint32_t validLifetime;
dhcp_address_prefer_remove_cb *removeCb;
int8_t interfaceId;
bool enableAddressAutonous;
uint16_t socketInstance_id;
uint8_t guaPrefix[8];
uint8_t serverDynamic_DUID_length;
uint32_t maxSuppertedClients;
uint32_t clientIdDefaultSuffics;
uint32_t clientIdSequence; /*!< Define */
uint32_t validLifetime;
dhcp_duid_options_params_t serverDUID;
uint8_t *serverDynamic_DUID;
dhcp_address_prefer_remove_cb *removeCb;
dhcp_address_add_notify_cb *addCb;
dhcpv6_alloacted_address_list_t allocatedAddressList;
ns_list_link_t link; /*!< List link entry */
@ -77,6 +80,7 @@ typedef struct dhcpv6_gua_server_entry_s {
bool libdhcpv6_gua_server_list_empty(void);
dhcpv6_gua_server_entry_s *libdhcpv6_gua_server_allocate(uint8_t *prefix, int8_t interfaceId, uint8_t *serverDUID, uint16_t serverDUIDType);
int libdhcpv6_server_duid_set(dhcpv6_gua_server_entry_s *server_info, uint8_t *duid_ptr, uint16_t duid_type, uint8_t duid_length);
void libdhcpv6_gua_server_free_by_prefix_and_interfaceid(uint8_t *prefix, int8_t interfaceId);
void libdhcpv6_gua_servers_time_update(uint32_t timeUpdateInSeconds);
void libdhcpv6_address_rm_from_allocated_list(dhcpv6_gua_server_entry_s *serverInfo, const uint8_t *address);