diff --git a/nanostack/mlme.h b/nanostack/mlme.h index cfb17e2983..da61200881 100644 --- a/nanostack/mlme.h +++ b/nanostack/mlme.h @@ -264,6 +264,7 @@ typedef enum { macAutoRequestKeyIndex = 0x7b, /*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; +} diff --git a/source/6LoWPAN/MAC/mac_helper.h b/source/6LoWPAN/MAC/mac_helper.h index 3cee017539..3e6ac27897 100644 --- a/source/6LoWPAN/MAC/mac_helper.h +++ b/source/6LoWPAN/MAC/mac_helper.h @@ -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 diff --git a/source/6LoWPAN/Thread/thread_bootstrap.c b/source/6LoWPAN/Thread/thread_bootstrap.c index 92db3f0b3c..84d0609fb2 100644 --- a/source/6LoWPAN/Thread/thread_bootstrap.c +++ b/source/6LoWPAN/Thread/thread_bootstrap.c @@ -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"); } } diff --git a/source/6LoWPAN/Thread/thread_mle_message_handler.c b/source/6LoWPAN/Thread/thread_mle_message_handler.c index 68df5ed719..a8253c5f8e 100644 --- a/source/6LoWPAN/Thread/thread_mle_message_handler.c +++ b/source/6LoWPAN/Thread/thread_mle_message_handler.c @@ -514,7 +514,7 @@ static void thread_parse_annoucement(protocol_interface_info_entry_t *cur, mle_m channel_page = ptr[0]; channel = common_read_16_bit(&ptr[1]); - if (linkConfiguration->timestamp == timestamp) { + if (linkConfiguration && linkConfiguration->timestamp == timestamp) { // We received same timestamp tr_debug("Same timestamp"); return; @@ -527,7 +527,7 @@ static void thread_parse_annoucement(protocol_interface_info_entry_t *cur, mle_m } - if (linkConfiguration->timestamp > timestamp) { + if (linkConfiguration && linkConfiguration->timestamp > timestamp) { // We received older time stamp we just announce back to originator channel thread_bootstrap_announce_send(cur, linkConfiguration->channel_page, linkConfiguration->rfChannel, linkConfiguration->panId, linkConfiguration->timestamp, channel); return; diff --git a/source/6LoWPAN/adaptation_interface.c b/source/6LoWPAN/adaptation_interface.c index eca2559836..0758ed4d12 100644 --- a/source/6LoWPAN/adaptation_interface.c +++ b/source/6LoWPAN/adaptation_interface.c @@ -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; } } diff --git a/source/6LoWPAN/ws/ws_bbr_api.c b/source/6LoWPAN/ws/ws_bbr_api.c index f01c07b110..390de43932 100644 --- a/source/6LoWPAN/ws/ws_bbr_api.c +++ b/source/6LoWPAN/ws/ws_bbr_api.c @@ -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; diff --git a/source/6LoWPAN/ws/ws_bbr_api_internal.h b/source/6LoWPAN/ws/ws_bbr_api_internal.h index 6dfef0b321..5da59eabcf 100644 --- a/source/6LoWPAN/ws/ws_bbr_api_internal.h +++ b/source/6LoWPAN/ws/ws_bbr_api_internal.h @@ -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 diff --git a/source/6LoWPAN/ws/ws_bootstrap.c b/source/6LoWPAN/ws/ws_bootstrap.c index cc651f1033..f620e4d574 100644 --- a/source/6LoWPAN/ws/ws_bootstrap.c +++ b/source/6LoWPAN/ws/ws_bootstrap.c @@ -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 diff --git a/source/6LoWPAN/ws/ws_common.c b/source/6LoWPAN/ws/ws_common.c index cb2970ec1b..449a4d8e0d 100644 --- a/source/6LoWPAN/ws/ws_common.c +++ b/source/6LoWPAN/ws/ws_common.c @@ -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; diff --git a/source/6LoWPAN/ws/ws_common.h b/source/6LoWPAN/ws/ws_common.h index 6a89708fe6..a901d08b27 100644 --- a/source/6LoWPAN/ws/ws_common.h +++ b/source/6LoWPAN/ws/ws_common.h @@ -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) diff --git a/source/6LoWPAN/ws/ws_common_defines.h b/source/6LoWPAN/ws/ws_common_defines.h index 4be2964e1e..f9f07fe701 100644 --- a/source/6LoWPAN/ws/ws_common_defines.h +++ b/source/6LoWPAN/ws/ws_common_defines.h @@ -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 */ diff --git a/source/6LoWPAN/ws/ws_config.h b/source/6LoWPAN/ws/ws_config.h index ee05b7fb44..9ff0007021 100644 --- a/source/6LoWPAN/ws/ws_config.h +++ b/source/6LoWPAN/ws/ws_config.h @@ -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_ */ diff --git a/source/6LoWPAN/ws/ws_eapol_pdu.c b/source/6LoWPAN/ws/ws_eapol_pdu.c index 64cac4dd57..ffe83c4a48 100644 --- a/source/6LoWPAN/ws/ws_eapol_pdu.c +++ b/source/6LoWPAN/ws/ws_eapol_pdu.c @@ -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); diff --git a/source/6LoWPAN/ws/ws_eapol_pdu.h b/source/6LoWPAN/ws/ws_eapol_pdu.h index fc99e08285..75f4ef4074 100644 --- a/source/6LoWPAN/ws/ws_eapol_pdu.h +++ b/source/6LoWPAN/ws/ws_eapol_pdu.h @@ -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_ */ diff --git a/source/6LoWPAN/ws/ws_eapol_relay.c b/source/6LoWPAN/ws/ws_eapol_relay.c index 269ad38d6d..367181bfcc 100644 --- a/source/6LoWPAN/ws/ws_eapol_relay.c +++ b/source/6LoWPAN/ws/ws_eapol_relay.c @@ -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); } } diff --git a/source/6LoWPAN/ws/ws_llc_data_service.c b/source/6LoWPAN/ws/ws_llc_data_service.c index 93cb585445..00523518eb 100644 --- a/source/6LoWPAN/ws/ws_llc_data_service.c +++ b/source/6LoWPAN/ws/ws_llc_data_service.c @@ -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; diff --git a/source/6LoWPAN/ws/ws_management_api.c b/source/6LoWPAN/ws/ws_management_api.c index f718951e61..e8be8dac51 100644 --- a/source/6LoWPAN/ws/ws_management_api.c +++ b/source/6LoWPAN/ws/ws_management_api.c @@ -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; diff --git a/source/6LoWPAN/ws/ws_pae_auth.c b/source/6LoWPAN/ws/ws_pae_auth.c index e4ec775a39..aeac106531 100644 --- a/source/6LoWPAN/ws/ws_pae_auth.c +++ b/source/6LoWPAN/ws/ws_pae_auth.c @@ -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; } diff --git a/source/6LoWPAN/ws/ws_pae_controller.c b/source/6LoWPAN/ws/ws_pae_controller.c index 11e2c455cb..6db0877be7 100644 --- a/source/6LoWPAN/ws/ws_pae_controller.c +++ b/source/6LoWPAN/ws/ws_pae_controller.c @@ -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); diff --git a/source/6LoWPAN/ws/ws_pae_controller.h b/source/6LoWPAN/ws/ws_pae_controller.h index 717ca11258..eb58253976 100644 --- a/source/6LoWPAN/ws/ws_pae_controller.h +++ b/source/6LoWPAN/ws/ws_pae_controller.h @@ -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 diff --git a/source/6LoWPAN/ws/ws_pae_lib.c b/source/6LoWPAN/ws/ws_pae_lib.c index d27c63b055..22d95b8086 100644 --- a/source/6LoWPAN/ws/ws_pae_lib.c +++ b/source/6LoWPAN/ws/ws_pae_lib.c @@ -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) { diff --git a/source/6LoWPAN/ws/ws_pae_lib.h b/source/6LoWPAN/ws/ws_pae_lib.h index 69b4a7aeda..90ba148126 100644 --- a/source/6LoWPAN/ws/ws_pae_lib.h +++ b/source/6LoWPAN/ws/ws_pae_lib.h @@ -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 * diff --git a/source/6LoWPAN/ws/ws_pae_nvm_data.c b/source/6LoWPAN/ws/ws_pae_nvm_data.c index 7cb2f42af8..d7f2d23861 100644 --- a/source/6LoWPAN/ws/ws_pae_nvm_data.c +++ b/source/6LoWPAN/ws/ws_pae_nvm_data.c @@ -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"); diff --git a/source/6LoWPAN/ws/ws_pae_nvm_data.h b/source/6LoWPAN/ws/ws_pae_nvm_data.h index ce763d7844..86ebedad80 100644 --- a/source/6LoWPAN/ws/ws_pae_nvm_data.h +++ b/source/6LoWPAN/ws/ws_pae_nvm_data.h @@ -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); diff --git a/source/6LoWPAN/ws/ws_pae_supp.c b/source/6LoWPAN/ws/ws_pae_supp.c index 6d22e3e9a8..452f5993ae 100644 --- a/source/6LoWPAN/ws/ws_pae_supp.c +++ b/source/6LoWPAN/ws/ws_pae_supp.c @@ -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 */ diff --git a/source/6LoWPAN/ws/ws_pae_supp.h b/source/6LoWPAN/ws/ws_pae_supp.h index 24de962fe3..bc8fc0f011 100644 --- a/source/6LoWPAN/ws/ws_pae_supp.h +++ b/source/6LoWPAN/ws/ws_pae_supp.h @@ -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 diff --git a/source/Common_Protocols/icmpv6.c b/source/Common_Protocols/icmpv6.c index d842055a9f..5222fde768 100644 --- a/source/Common_Protocols/icmpv6.c +++ b/source/Common_Protocols/icmpv6.c @@ -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); } } diff --git a/source/DHCPv6_Server/DHCPv6_Server_service.c b/source/DHCPv6_Server/DHCPv6_Server_service.c index 7e172f7fde..bd606db11f 100644 --- a/source/DHCPv6_Server/DHCPv6_Server_service.c +++ b/source/DHCPv6_Server/DHCPv6_Server_service.c @@ -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 * * diff --git a/source/DHCPv6_Server/DHCPv6_server_service.h b/source/DHCPv6_Server/DHCPv6_server_service.h index d8c45e7327..2a236ad254 100644 --- a/source/DHCPv6_Server/DHCPv6_server_service.h +++ b/source/DHCPv6_Server/DHCPv6_server_service.h @@ -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. * diff --git a/source/DHCPv6_client/dhcpv6_client_api.h b/source/DHCPv6_client/dhcpv6_client_api.h index 60c2ff7f52..ccfc6c1ddf 100644 --- a/source/DHCPv6_client/dhcpv6_client_api.h +++ b/source/DHCPv6_client/dhcpv6_client_api.h @@ -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 * diff --git a/source/DHCPv6_client/dhcpv6_client_service.c b/source/DHCPv6_client/dhcpv6_client_service.c index af57e49c5c..a8cecf6d8d 100644 --- a/source/DHCPv6_client/dhcpv6_client_service.c +++ b/source/DHCPv6_client/dhcpv6_client_service.c @@ -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; diff --git a/source/MAC/IEEE802_15_4/mac_defines.h b/source/MAC/IEEE802_15_4/mac_defines.h index 119c2c2efa..7d53459545 100644 --- a/source/MAC/IEEE802_15_4/mac_defines.h +++ b/source/MAC/IEEE802_15_4/mac_defines.h @@ -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; diff --git a/source/MAC/IEEE802_15_4/mac_mcps_sap.c b/source/MAC/IEEE802_15_4/mac_mcps_sap.c index 74c30b16b3..a97570675a 100644 --- a/source/MAC/IEEE802_15_4/mac_mcps_sap.c +++ b/source/MAC/IEEE802_15_4/mac_mcps_sap.c @@ -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. }**/ diff --git a/source/MAC/IEEE802_15_4/mac_mlme.c b/source/MAC/IEEE802_15_4/mac_mlme.c index d0925f97f8..5d1f5e48c9 100644 --- a/source/MAC/IEEE802_15_4/mac_mlme.c +++ b/source/MAC/IEEE802_15_4/mac_mlme.c @@ -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; diff --git a/source/MAC/IEEE802_15_4/mac_pd_sap.c b/source/MAC/IEEE802_15_4/mac_pd_sap.c index 1e0a09865f..a7a5cc2a89 100644 --- a/source/MAC/IEEE802_15_4/mac_pd_sap.c +++ b/source/MAC/IEEE802_15_4/mac_pd_sap.c @@ -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; diff --git a/source/MAC/IEEE802_15_4/mac_security_mib.c b/source/MAC/IEEE802_15_4/mac_security_mib.c index b023c32cdf..8b22875a96 100644 --- a/source/MAC/IEEE802_15_4/mac_security_mib.c +++ b/source/MAC/IEEE802_15_4/mac_security_mib.c @@ -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); } } diff --git a/source/MAC/IEEE802_15_4/mac_security_mib.h b/source/MAC/IEEE802_15_4/mac_security_mib.h index 9ca75cd5b8..86648e7f5c 100644 --- a/source/MAC/IEEE802_15_4/mac_security_mib.h +++ b/source/MAC/IEEE802_15_4/mac_security_mib.h @@ -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); diff --git a/source/NWK_INTERFACE/Include/protocol_stats.h b/source/NWK_INTERFACE/Include/protocol_stats.h index 47d000816c..e8ee77f2ca 100644 --- a/source/NWK_INTERFACE/Include/protocol_stats.h +++ b/source/NWK_INTERFACE/Include/protocol_stats.h @@ -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; diff --git a/source/NWK_INTERFACE/protocol_stats.c b/source/NWK_INTERFACE/protocol_stats.c index 2576c1be52..aedec1cbae 100644 --- a/source/NWK_INTERFACE/protocol_stats.c +++ b/source/NWK_INTERFACE/protocol_stats.c @@ -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; } } } diff --git a/source/RPL/rpl_control.h b/source/RPL/rpl_control.h index 17290fddc0..7569bac944 100644 --- a/source/RPL/rpl_control.h +++ b/source/RPL/rpl_control.h @@ -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); diff --git a/source/RPL/rpl_downward.c b/source/RPL/rpl_downward.c index 188f144a45..607cca6168 100644 --- a/source/RPL/rpl_downward.c +++ b/source/RPL/rpl_downward.c @@ -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); } } diff --git a/source/RPL/rpl_mrhof.c b/source/RPL/rpl_mrhof.c index ea52ee2507..bfff5aa000 100644 --- a/source/RPL/rpl_mrhof.c +++ b/source/RPL/rpl_mrhof.c @@ -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) { diff --git a/source/RPL/rpl_upward.c b/source/RPL/rpl_upward.c index 4bd186d369..d3e4720b04 100644 --- a/source/RPL/rpl_upward.c +++ b/source/RPL/rpl_upward.c @@ -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); diff --git a/source/Security/eapol/kde_helper.c b/source/Security/eapol/kde_helper.c index 042c42a649..13be8926ce 100644 --- a/source/Security/eapol/kde_helper.c +++ b/source/Security/eapol/kde_helper.c @@ -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; } diff --git a/source/Security/kmp/kmp_api.c b/source/Security/kmp/kmp_api.c index 3ca8bc2e6a..a95802ec4d 100644 --- a/source/Security/kmp/kmp_api.c +++ b/source/Security/kmp/kmp_api.c @@ -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) { diff --git a/source/Security/kmp/kmp_api.h b/source/Security/kmp/kmp_api.h index c690aa9ec9..411d982bb2 100644 --- a/source/Security/kmp/kmp_api.h +++ b/source/Security/kmp/kmp_api.h @@ -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 * diff --git a/source/Security/kmp/kmp_eapol_pdu_if.c b/source/Security/kmp/kmp_eapol_pdu_if.c index 3424fd3eda..2b8a6616d4 100644 --- a/source/Security/kmp/kmp_eapol_pdu_if.c +++ b/source/Security/kmp/kmp_eapol_pdu_if.c @@ -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 */ diff --git a/source/Security/kmp/kmp_socket_if.c b/source/Security/kmp/kmp_socket_if.c index 8bb7f262ba..6b905d5791 100644 --- a/source/Security/kmp/kmp_socket_if.c +++ b/source/Security/kmp/kmp_socket_if.c @@ -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; } diff --git a/source/Security/protocols/eap_tls_sec_prot/eap_tls_sec_prot_lib.c b/source/Security/protocols/eap_tls_sec_prot/eap_tls_sec_prot_lib.c index 40e4b9ea0a..d6ca43c18d 100644 --- a/source/Security/protocols/eap_tls_sec_prot/eap_tls_sec_prot_lib.c +++ b/source/Security/protocols/eap_tls_sec_prot/eap_tls_sec_prot_lib.c @@ -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; } diff --git a/source/Security/protocols/eap_tls_sec_prot/supp_eap_tls_sec_prot.c b/source/Security/protocols/eap_tls_sec_prot/supp_eap_tls_sec_prot.c index 8d73f22f38..b80a43cc40 100644 --- a/source/Security/protocols/eap_tls_sec_prot/supp_eap_tls_sec_prot.c +++ b/source/Security/protocols/eap_tls_sec_prot/supp_eap_tls_sec_prot.c @@ -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); } diff --git a/source/Security/protocols/key_sec_prot/key_sec_prot.c b/source/Security/protocols/key_sec_prot/key_sec_prot.c index 901c54feda..ba56a7566c 100644 --- a/source/Security/protocols/key_sec_prot/key_sec_prot.c +++ b/source/Security/protocols/key_sec_prot/key_sec_prot.c @@ -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; } diff --git a/source/Security/protocols/key_sec_prot/key_sec_prot.h b/source/Security/protocols/key_sec_prot/key_sec_prot.h index 9cb00897f9..e059ab7bc0 100644 --- a/source/Security/protocols/key_sec_prot/key_sec_prot.h +++ b/source/Security/protocols/key_sec_prot/key_sec_prot.h @@ -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_ */ diff --git a/source/Security/protocols/sec_prot.h b/source/Security/protocols/sec_prot.h index 59929a7217..49d28f7d1e 100644 --- a/source/Security/protocols/sec_prot.h +++ b/source/Security/protocols/sec_prot.h @@ -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 */ diff --git a/source/Security/protocols/sec_prot_keys.c b/source/Security/protocols/sec_prot_keys.c index ccb287a127..9a0d4c8a43 100644 --- a/source/Security/protocols/sec_prot_keys.c +++ b/source/Security/protocols/sec_prot_keys.c @@ -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; diff --git a/source/Security/protocols/sec_prot_keys.h b/source/Security/protocols/sec_prot_keys.h index 1653810b5d..4a14fc2b6f 100644 --- a/source/Security/protocols/sec_prot_keys.h +++ b/source/Security/protocols/sec_prot_keys.h @@ -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 * diff --git a/source/Security/protocols/tls_sec_prot/tls_sec_prot_lib.c b/source/Security/protocols/tls_sec_prot/tls_sec_prot_lib.c index 03e2f5cf72..6f236bcf1f 100644 --- a/source/Security/protocols/tls_sec_prot/tls_sec_prot_lib.c +++ b/source/Security/protocols/tls_sec_prot/tls_sec_prot_lib.c @@ -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) { diff --git a/source/libDHCPv6/libDHCPv6.c b/source/libDHCPv6/libDHCPv6.c index 86fa88345c..7b021aba39 100644 --- a/source/libDHCPv6/libDHCPv6.c +++ b/source/libDHCPv6/libDHCPv6.c @@ -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; diff --git a/source/libDHCPv6/libDHCPv6.h b/source/libDHCPv6/libDHCPv6.h index e3cb612826..c495a18fe4 100644 --- a/source/libDHCPv6/libDHCPv6.h +++ b/source/libDHCPv6/libDHCPv6.h @@ -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); diff --git a/source/libDHCPv6/libDHCPv6_server.c b/source/libDHCPv6/libDHCPv6_server.c index 69cd434737..2f19eb70a4 100644 --- a/source/libDHCPv6/libDHCPv6_server.c +++ b/source/libDHCPv6/libDHCPv6_server.c @@ -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); } } diff --git a/source/libDHCPv6/libDHCPv6_server.h b/source/libDHCPv6/libDHCPv6_server.h index 02977f3b07..ba17b340f5 100644 --- a/source/libDHCPv6/libDHCPv6_server.h +++ b/source/libDHCPv6/libDHCPv6_server.h @@ -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);