Merge commit '0b6ccc5816e44df9fe89c476514cb7043dfb483b'

* commit '0b6ccc5816e44df9fe89c476514cb7043dfb483b':
  Squashed 'features/nanostack/sal-stack-nanostack/' changes from 0824752..9b3e144
pull/11889/head
Jarkko Paso 2019-11-18 15:08:32 +02:00
commit 12d4497ab7
62 changed files with 2028 additions and 838 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

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