diff --git a/connectivity/nanostack/sal-stack-nanostack/nanostack/dhcp_service_api.h b/connectivity/nanostack/sal-stack-nanostack/nanostack/dhcp_service_api.h index e4759a59515..1a3be195aa1 100644 --- a/connectivity/nanostack/sal-stack-nanostack/nanostack/dhcp_service_api.h +++ b/connectivity/nanostack/sal-stack-nanostack/nanostack/dhcp_service_api.h @@ -109,6 +109,15 @@ typedef int (dhcp_service_receive_req_cb)(uint16_t instance_id, uint32_t msg_tr_ typedef int (dhcp_service_receive_resp_cb)(uint16_t instance_id, void *ptr, uint8_t msg_name, uint8_t *msg_ptr, uint16_t msg_len); +/** + * \brief Neighbour table update callback this is called for DHCP relay and server link local responses. + * + * \param interface interface where address is got + * \param ll_addr Link local which neighbour must be guarantee. + * + */ +typedef void (dhcp_relay_neighbour_cb)(int8_t interface, uint8_t ll_addr[static 16]); + /** * \brief Initialize a new DHCP service instance. @@ -235,5 +244,16 @@ void dhcp_service_req_remove_all(void *msg_class_ptr); */ bool dhcp_service_timer_tick(uint16_t ticks); +/** + * \brief Register callback which is called when Relay or server RX direct message. + * + * \param interface_id Interface id for registed callback. + * \param notify_cb callback pointer + * + * \return 0, if everything went fine. + * \return -1, if error occurred. + */ +int dhcp_service_link_local_rx_cb_set(int8_t interface_id, dhcp_relay_neighbour_cb *notify_cb); + #endif //DHCP_SERVICE_API_H_ diff --git a/connectivity/nanostack/sal-stack-nanostack/nanostack/mlme.h b/connectivity/nanostack/sal-stack-nanostack/nanostack/mlme.h index ee6a244172f..859457d1611 100644 --- a/connectivity/nanostack/sal-stack-nanostack/nanostack/mlme.h +++ b/connectivity/nanostack/sal-stack-nanostack/nanostack/mlme.h @@ -267,7 +267,6 @@ typedef enum { macEdfeForceStop = 0xf2, /*< Use this command for Data wait timeout at LLC: Mac stop Edfe session data wait and enable normal FHSS mode */ macSetDataWhitening = 0xf3, /*< Enable or disable data whitening, boolean true for enable, false for disable */ macCCAThresholdStart = 0xf4, /*< Start automatic CCA threshold */ - macDevicePendingAckTrig = 0xf5, /*< Trig Pending ACK for Accepted Data packet for temporary neighbour */ mac802_15_4Mode = 0xf6, /*= 0 success + * + */ +int ws_bbr_radius_timing_set(int8_t interface_id, bbr_radius_timing_t *timing); + +/** + * Get RADIUS timing information + * + * Function sets RADIUS timing information from Border Router. + * + * \param interface_id Network interface ID. + * \param timing Timing information + * + * \return < 0 failure + * \return >= 0 success + * + */ +int ws_bbr_radius_timing_get(int8_t interface_id, bbr_radius_timing_t *timing); + +/** + * Validate RADIUS timing information + * + * Function validates RADIUS timing information. + * + * \param interface_id Network interface ID. + * \param timing Timing information + * + * \return < 0 failure + * \return >= 0 success + * + */ +int ws_bbr_radius_timing_validate(int8_t interface_id, bbr_radius_timing_t *timing); + +/** + * \brief A function to set DNS query results to border router + * + * Border router distributes these query results in DHCP Solicit responses to + * all the devices joining to the Wi-SUN mesh network. + * + * Border router keeps these forever, but if application does not update these in regular interval + * The address might stop working. So periodic keep alive is required. + * + * These cached query results will become available in the Wi-SUN interface. + * + * This function can be called multiple times. + * if domain name matches a existing entry address is updated. + * If domain name is set to NULL entire list is cleared + * if address is set to NULL the Domain name is removed from the list. + * + * \param interface_id Network interface ID. + * \param address The address of the DNS query result. + * \param domain_name_ptr Domain name matching the address + * + * \return < 0 failure + * \return >= 0 success + */ +int ws_bbr_dns_query_result_set(int8_t interface_id, const uint8_t address[16], char *domain_name_ptr); + #endif /* WS_BBR_API_H_ */ diff --git a/connectivity/nanostack/sal-stack-nanostack/nanostack/ws_management_api.h b/connectivity/nanostack/sal-stack-nanostack/nanostack/ws_management_api.h index 8d155595cdb..a5feb762874 100644 --- a/connectivity/nanostack/sal-stack-nanostack/nanostack/ws_management_api.h +++ b/connectivity/nanostack/sal-stack-nanostack/nanostack/ws_management_api.h @@ -30,6 +30,7 @@ #include "ns_types.h" #include "net_interface.h" /* Declaration for channel_list_s. */ +#include "fhss_config.h" #ifdef __cplusplus extern "C" { @@ -112,6 +113,8 @@ typedef struct ws_stack_info { uint8_t rsl_out; /** parent RSSI in measured RSSI value calculated using EWMA specified by Wi-SUN from range of -174 (0) to +80 (254) dBm.*/ uint8_t rsl_in; + /** Device RF minimum sensitivity configuration. lowest level of radio signal strength packet heard. Range of -174 (0) to +80 (254) dBm*/ + uint8_t device_min_sens; /** ETX To border router */ uint16_t routing_cost; /** Network PAN ID */ @@ -614,6 +617,30 @@ int ws_stack_info_get( int8_t interface_id, ws_stack_info_t *info_ptr); +/** + * Set minimum RF sensitivity acceptable for the parent selection + * + * Set radio signal minimum sensitivity level acceptable for parent selection. + * Range of -174 (0) to +80 (254) dBm. + * + * If device_min_sens is set to 0 then automatic adjustment is done by the stack. + * + * Setting a value that is not suitable for Radio might prevent the device joining to the network. + * + * NOTE: Currently lower EAPOL parents are accepted if there is no parents higher than + * DEVICE_MIN_SENS + CAND_PARENT_THRESHOLD + CAND_PARENT_HYSTERESIS + * NOTE: Currently not using this value to limit parents as it is only RECOMENDED in specification. + * + * \param interface_id Network interface ID. + * \param device_min_sens value used in the parent selections. + * + * \return 0 Success. + * \return <0 Failure. + */ +int ws_device_min_sens_set( + int8_t interface_id, + uint8_t device_min_sens); + #ifdef __cplusplus } #endif diff --git a/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/MAC/mac_helper.c b/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/MAC/mac_helper.c index ab5961f5f2a..86fc64ebde5 100644 --- a/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/MAC/mac_helper.c +++ b/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/MAC/mac_helper.c @@ -947,21 +947,6 @@ void mac_helper_devicetable_direct_set(struct mac_api_s *mac_api, const mlme_dev mac_api->mlme_req(mac_api, MLME_SET, &set_req); } -void mac_helper_devicetable_ack_trig(const mlme_device_descriptor_t *device_desc, protocol_interface_info_entry_t *cur) -{ - if (!cur->mac_api) { - return; - } - - mlme_set_t set_req; - set_req.attr = macDevicePendingAckTrig; - set_req.attr_index = 0; - set_req.value_pointer = (void *)device_desc; - set_req.value_size = sizeof(mlme_device_descriptor_t); - cur->mac_api->mlme_req(cur->mac_api, MLME_SET, &set_req); -} - - int8_t mac_helper_mac_mlme_max_retry_set(int8_t interface_id, uint8_t mac_retry_set) { protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(interface_id); diff --git a/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/MAC/mac_helper.h b/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/MAC/mac_helper.h index 8c9c651cd1f..fd1eb19d868 100644 --- a/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/MAC/mac_helper.h +++ b/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/MAC/mac_helper.h @@ -128,8 +128,6 @@ void mac_helper_devicetable_set(const mlme_device_descriptor_t *device_dec, stru void mac_helper_devicetable_direct_set(struct mac_api_s *mac_api, const mlme_device_descriptor_t *device_desc, uint8_t attribute_index); -void mac_helper_devicetable_ack_trig(const mlme_device_descriptor_t *device_desc, struct protocol_interface_info_entry *cur); - 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); diff --git a/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_bbr_api.c b/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_bbr_api.c index 878c431f512..eedd4ea6236 100644 --- a/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_bbr_api.c +++ b/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_bbr_api.c @@ -19,6 +19,7 @@ #include "nsconfig.h" #include "ns_types.h" #include "ns_trace.h" +#include "nsdynmemLIB.h" #include "net_interface.h" #include "socket_api.h" #include "eventOS_event.h" @@ -41,6 +42,9 @@ #include "6LoWPAN/ws/ws_pae_controller.h" #include "DHCPv6_Server/DHCPv6_server_service.h" #include "DHCPv6_client/dhcpv6_client_api.h" +#include "libDHCPv6/libDHCPv6_vendordata.h" +#include "libNET/src/net_dns_internal.h" + #include "ws_bbr_api.h" @@ -73,6 +77,9 @@ static uint8_t current_global_prefix[16] = {0}; // DHCP requires 16 bytes prefix static uint32_t bbr_delay_timer = BBR_CHECK_INTERVAL; // initial delay. static uint32_t global_prefix_unavailable_timer = 0; // initial delay. +static uint8_t *dhcp_vendor_data_ptr = NULL; +static uint8_t dhcp_vendor_data_len = 0; + static rpl_dodag_conf_t rpl_conf = { // Lifetime values .default_lifetime = 120, @@ -88,6 +95,17 @@ static rpl_dodag_conf_t rpl_conf = { .dio_redundancy_constant = WS_RPL_DIO_REDUNDANCY_SMALL }; +typedef struct dns_resolution { + /** Resolved address for the domain*/ + uint8_t address[16]; + /** Domain name string */ + char *domain_name; +} dns_resolution_t; + +#define MAX_DNS_RESOLUTIONS 4 + +static dns_resolution_t pre_resolved_dns_queries[MAX_DNS_RESOLUTIONS] = {0}; + static void ws_bbr_rpl_version_timer_start(protocol_interface_info_entry_t *cur, uint8_t version) { // Set the next timeout value for version update @@ -364,6 +382,48 @@ static bool wisun_dhcp_address_add_cb(int8_t interfaceId, dhcp_address_cache_upd return true; } +static void ws_bbr_dhcp_server_dns_info_update(protocol_interface_info_entry_t *cur, uint8_t *global_id) +{ + //add DNS server information to DHCP server that is learned from the backbone interface. + uint8_t dns_server_address[16]; + uint8_t *dns_search_list_ptr = NULL; + uint8_t dns_search_list_len = 0; + (void)cur; + if (net_dns_server_get(backbone_interface_id, dns_server_address, &dns_search_list_ptr, &dns_search_list_len, 0) == 0) { + /*Only supporting one DNS server address*/ + DHCPv6_server_service_set_dns_server(cur->id, global_id, dns_server_address, dns_search_list_ptr, dns_search_list_len); + } + + //TODO Generate vendor data in Wi-SUN network include the cached DNS query results in some sort of TLV format + int vendor_data_len = 0; + for (int n = 0; n < MAX_DNS_RESOLUTIONS; n++) { + if (pre_resolved_dns_queries[n].domain_name != NULL) { + vendor_data_len += net_dns_option_vendor_option_data_dns_query_length(pre_resolved_dns_queries[n].domain_name); + } + } + if (vendor_data_len) { + ns_dyn_mem_free(dhcp_vendor_data_ptr); + dhcp_vendor_data_ptr = ns_dyn_mem_alloc(vendor_data_len); + if (!dhcp_vendor_data_ptr) { + tr_warn("Vendor info set fail"); + return; + } + dhcp_vendor_data_len = vendor_data_len; + } + if (dhcp_vendor_data_ptr) { + // Write vendor data + uint8_t *ptr = dhcp_vendor_data_ptr; + for (int n = 0; n < MAX_DNS_RESOLUTIONS; n++) { + if (pre_resolved_dns_queries[n].domain_name != NULL) { + ptr = net_dns_option_vendor_option_data_dns_query_write(ptr, pre_resolved_dns_queries[n].address, pre_resolved_dns_queries[n].domain_name); + tr_info("set DNS query result for %s, addr: %s", pre_resolved_dns_queries[n].domain_name, tr_ipv6(pre_resolved_dns_queries[n].address)); + } + } + } + + DHCPv6_server_service_set_vendor_data(cur->id, global_id, ARM_ENTERPRISE_NUMBER, dhcp_vendor_data_ptr, dhcp_vendor_data_len); +} + static void ws_bbr_dhcp_server_start(protocol_interface_info_entry_t *cur, uint8_t *global_id, uint32_t dhcp_address_lifetime) { uint8_t ll[16]; @@ -384,6 +444,8 @@ static void ws_bbr_dhcp_server_start(protocol_interface_info_entry_t *cur, uint8 //SEt max value for not limiting address allocation DHCPv6_server_service_set_max_clients_accepts_count(cur->id, global_id, MAX_SUPPORTED_ADDRESS_LIST_SIZE); + ws_bbr_dhcp_server_dns_info_update(cur, global_id); + ws_dhcp_client_address_request(cur, global_id, ll); } static void ws_bbr_dhcp_server_stop(protocol_interface_info_entry_t *cur, uint8_t *global_id) @@ -570,6 +632,7 @@ static void ws_bbr_rpl_status_check(protocol_interface_info_entry_t *cur) // Add also global prefix and route to RPL rpl_control_update_dodag_route(protocol_6lowpan_rpl_root_dodag, current_global_prefix, 64, 0, WS_ROUTE_LIFETIME, false); } + ws_bbr_dhcp_server_dns_info_update(cur, current_global_prefix); } } void ws_bbr_pan_version_increase(protocol_interface_info_entry_t *cur) @@ -1137,3 +1200,115 @@ int ws_bbr_radius_shared_secret_get(int8_t interface_id, uint16_t *shared_secret return -1; #endif } + +int ws_bbr_radius_timing_set(int8_t interface_id, bbr_radius_timing_t *timing) +{ +#ifdef HAVE_WS_BORDER_ROUTER + return ws_pae_controller_radius_timing_set(interface_id, timing); +#else + (void) interface_id; + (void) timing; + return -1; +#endif +} + +int ws_bbr_radius_timing_get(int8_t interface_id, bbr_radius_timing_t *timing) +{ +#ifdef HAVE_WS_BORDER_ROUTER + return ws_pae_controller_radius_timing_get(interface_id, timing); +#else + (void) interface_id; + (void) timing; + return -1; +#endif +} + +int ws_bbr_radius_timing_validate(int8_t interface_id, bbr_radius_timing_t *timing) +{ +#ifdef HAVE_WS_BORDER_ROUTER + return ws_pae_controller_radius_timing_validate(interface_id, timing); +#else + (void) interface_id; + (void) timing; + return -1; +#endif +} + +int ws_bbr_dns_query_result_set(int8_t interface_id, const uint8_t address[16], char *domain_name_ptr) +{ +#ifdef HAVE_WS_BORDER_ROUTER + protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(interface_id); + if (!cur) { + return -1; + } + + /* This information is only stored to the DHCPv6 server where it is distributed to the network + * + * Border router stores a list of these entries and includes a function to parse and generate the vendor data output + * + * This is included in the vendor extension where the format is decided by the vendor + */ + + // Delete all entries + if (!domain_name_ptr) { + for (int n = 0; n < MAX_DNS_RESOLUTIONS; n++) { + // Delete all entries + memset(pre_resolved_dns_queries[n].address, 0, 16); + ns_dyn_mem_free(pre_resolved_dns_queries[n].domain_name); + pre_resolved_dns_queries[n].domain_name = NULL; + } + goto update_information; + } + + // Update existing entries or delete + for (int n = 0; n < MAX_DNS_RESOLUTIONS; n++) { + if (pre_resolved_dns_queries[n].domain_name != NULL && + strcasecmp(pre_resolved_dns_queries[n].domain_name, domain_name_ptr) == 0) { + // Matching query updated + if (address) { + // Update address + memcpy(pre_resolved_dns_queries[n].address, address, 16); + } else { + // delete entry + memset(pre_resolved_dns_queries[n].address, 0, 16); + ns_dyn_mem_free(pre_resolved_dns_queries[n].domain_name); + pre_resolved_dns_queries[n].domain_name = NULL; + } + goto update_information; + } + } + + if (address && domain_name_ptr) { + // Store new entry to the list + for (int n = 0; n < MAX_DNS_RESOLUTIONS; n++) { + if (pre_resolved_dns_queries[n].domain_name == NULL) { + // Free entry found + pre_resolved_dns_queries[n].domain_name = ns_dyn_mem_alloc(strlen(domain_name_ptr) + 1); + if (!pre_resolved_dns_queries[n].domain_name) { + // Out of memory + return -2; + } + memcpy(pre_resolved_dns_queries[n].address, address, 16); + strcpy(pre_resolved_dns_queries[n].domain_name, domain_name_ptr); + goto update_information; + } + } + // No room to store new field + return -3; + } + +update_information: + if (memcmp(current_global_prefix, ADDR_UNSPECIFIED, 8) == 0) { + // Not in active state so changes are activated after start + return 0; + } + + ws_bbr_dhcp_server_dns_info_update(cur, current_global_prefix); + return 0; +#else + (void) interface_id; + (void) address; + (void) domain_name_ptr; + return -1; +#endif +} diff --git a/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_bootstrap.c b/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_bootstrap.c index 6bd10d5aa61..808acb7bf2c 100644 --- a/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_bootstrap.c +++ b/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_bootstrap.c @@ -63,7 +63,9 @@ #include "Service_Libs/nd_proxy/nd_proxy.h" #include "Service_Libs/blacklist/blacklist.h" #include "platform/topo_trace.h" +#include "dhcp_service_api.h" #include "libDHCPv6/libDHCPv6.h" +#include "libDHCPv6/libDHCPv6_vendordata.h" #include "DHCPv6_client/dhcpv6_client_api.h" #include "ws_management_api.h" #include "net_rpl.h" @@ -72,6 +74,7 @@ #include "6LoWPAN/ws/ws_eapol_pdu.h" #include "6LoWPAN/ws/ws_eapol_auth_relay.h" #include "6LoWPAN/ws/ws_eapol_relay.h" +#include "libNET/src/net_dns_internal.h" #define TRACE_GROUP "wsbs" @@ -136,14 +139,37 @@ mac_neighbor_table_entry_t *ws_bootstrap_mac_neighbor_add(struct protocol_interf } // TODO only call these for new neighbour mlme_device_descriptor_t device_desc; - neighbor->lifetime = WS_NEIGHBOR_LINK_TIMEOUT; - neighbor->link_lifetime = WS_NEIGHBOR_LINK_TIMEOUT; - tr_debug("Added new neighbor %s : index:%u", trace_array(src64, 8), neighbor->index); + neighbor->lifetime = WS_NEIGHBOUR_TEMPORARY_ENTRY_LIFETIME; + neighbor->link_lifetime = WS_NEIGHBOUR_TEMPORARY_ENTRY_LIFETIME; mac_helper_device_description_write(interface, &device_desc, neighbor->mac64, neighbor->mac16, 0, false); mac_helper_devicetable_set(&device_desc, interface, neighbor->index, interface->mac_parameters->mac_default_key_index, true); + return neighbor; } +void ws_bootstrap_neighbor_set_stable(struct protocol_interface_info_entry *interface, const uint8_t *src64) +{ + mac_neighbor_table_entry_t *neighbor = mac_neighbor_table_address_discover(mac_neighbor_info(interface), src64, MAC_ADDR_MODE_64_BIT); + + if (neighbor && neighbor->link_lifetime != WS_NEIGHBOR_LINK_TIMEOUT) { + neighbor->lifetime = WS_NEIGHBOR_LINK_TIMEOUT; + neighbor->link_lifetime = WS_NEIGHBOR_LINK_TIMEOUT; + tr_info("Added new neighbor %s : index:%u", trace_array(src64, 8), neighbor->index); + } +} + +void ws_bootstrap_mac_neighbor_short_time_set(struct protocol_interface_info_entry *interface, const uint8_t *src64, uint32_t valid_time) +{ + mac_neighbor_table_entry_t *neighbor = mac_neighbor_table_address_discover(mac_neighbor_info(interface), src64, MAC_ADDR_MODE_64_BIT); + + if (neighbor && neighbor->link_lifetime != WS_NEIGHBOR_LINK_TIMEOUT) { + //mlme_device_descriptor_t device_desc; + neighbor->lifetime = valid_time; + neighbor->link_lifetime = valid_time; + tr_debug("Set short response neighbor %s : index:%u", trace_array(src64, 8), neighbor->index); + } +} + static void ws_bootstrap_neighbor_delete(struct protocol_interface_info_entry *interface, mac_neighbor_table_entry_t *entry_ptr) { mac_helper_devicetable_remove(interface->mac_api, entry_ptr->index, entry_ptr->mac64); @@ -161,6 +187,7 @@ static void ws_bootstap_eapol_neigh_entry_allocate(struct protocol_interface_inf if (!mac_entry) { return; } + ws_bootstrap_neighbor_set_stable(interface, mac_64); mac_entry->lifetime = 0xffffffff; mac_entry->link_lifetime = 0xffffffff; ws_neighbor_class_entry_t *ws_neigh = ws_neighbor_class_entry_get(&interface->ws_info->neighbor_storage, mac_entry->index); @@ -170,14 +197,6 @@ static void ws_bootstap_eapol_neigh_entry_allocate(struct protocol_interface_inf interface->ws_info->eapol_tx_index = mac_entry->index; } -void ws_bootstrap_eapol_rx_temporary_set(struct protocol_interface_info_entry *interface, const uint8_t *src64) -{ - mlme_device_descriptor_t device_desc; - - mac_helper_device_description_write(interface, &device_desc, src64, 0xffff, 0, false); - mac_helper_devicetable_ack_trig(&device_desc, interface); -} - ws_neighbor_class_entry_t *ws_bootstrap_eapol_tx_temporary_set(struct protocol_interface_info_entry *interface, const uint8_t *src64) { mlme_device_descriptor_t device_desc; @@ -838,6 +857,97 @@ bool ws_bootstrap_nd_ns_transmit(protocol_interface_info_entry_t *cur, ipv6_neig return true; } +static void ws_bootstrap_dhcp_neighbour_update_cb(int8_t interface_id, uint8_t ll_addr[static 16]) +{ + if (memcmp(ll_addr, ADDR_LINK_LOCAL_PREFIX, 8)) { + return; + } + + protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(interface_id); + if (!cur) { + return; + } + + uint8_t mac64[8]; + memcpy(mac64, ll_addr + 8, 8); + mac64[0] ^= 2; + ws_bootstrap_mac_neighbor_short_time_set(cur, mac64, WS_NEIGHBOUR_DHCP_ENTRY_LIFETIME); +} + +static void ws_bootstrap_dhcp_info_notify_cb(int8_t interface, dhcp_option_notify_t *options, dhcp_server_notify_info_t *server_info) +{ + protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(interface); + if (!cur) { + return; + } + uint8_t server_ll64[16]; + memcpy(server_ll64, ADDR_LINK_LOCAL_PREFIX, 8); + + if (server_info->duid_length == 8) { + memcpy(server_ll64 + 8, server_info->duid, 8); + } else { + server_ll64[8] = server_info->duid[0]; + server_ll64[9] = server_info->duid[1]; + server_ll64[10] = server_info->duid[2]; + server_ll64[11] = 0xff; + server_ll64[12] = 0xfe; + server_ll64[13] = server_info->duid[3]; + server_ll64[14] = server_info->duid[4]; + server_ll64[15] = server_info->duid[5]; + } + server_ll64[8] ^= 2; + + switch (options->option_type) { + case DHCPV6_OPTION_VENDOR_SPECIFIC_INFO: + if (options->option.vendor_spesific.enterprise_number != ARM_ENTERPRISE_NUMBER) { + break; + } + while (options->option.vendor_spesific.data_length) { + uint16_t option_type; + char *domain; + uint8_t *address; + uint16_t option_len; + option_len = net_dns_option_vendor_option_data_get_next(options->option.vendor_spesific.data, options->option.vendor_spesific.data_length, &option_type); + tr_debug("DHCP vendor specific data type:%u length %d", option_type, option_len); + //tr_debug("DHCP vendor specific data %s", trace_array(options->option.vendor_spesific.data, options->option.vendor_spesific.data_length)); + + if (option_len == 0) { + // Option fields were corrupted + break; + } + if (option_type == ARM_DHCP_VENDOR_DATA_DNS_QUERY_RESULT) { + // Process ARM DNS query result + domain = NULL; + address = NULL; + if (net_dns_option_vendor_option_data_dns_query_read(options->option.vendor_spesific.data, options->option.vendor_spesific.data_length, &address, &domain) > 0 || + domain || address) { + // Valid ARM DNS query entry + net_dns_query_result_set(interface, address, domain, server_info->life_time); + } + } + + options->option.vendor_spesific.data_length -= option_len; + options->option.vendor_spesific.data += option_len; + } + break; + + case DHCPV6_OPTION_DNS_SERVERS: + while (options->option.generic.data_length) { + net_dns_server_address_set(interface, server_ll64, options->option.generic.data, server_info->life_time); + options->option.generic.data_length -= 16; + options->option.generic.data += 16; + } + break; + case DHCPV6_OPTION_DOMAIN_LIST: + net_dns_server_search_list_set(interface, server_ll64, options->option.generic.data, options->option.generic.data_length, server_info->life_time); + break; + default: + break; + } + +} + + static int8_t ws_bootstrap_up(protocol_interface_info_entry_t *cur) { int8_t ret_val = -1; @@ -886,8 +996,10 @@ static int8_t ws_bootstrap_up(protocol_interface_info_entry_t *cur) cur->if_ns_transmit = ws_bootstrap_nd_ns_transmit; dhcp_client_init(cur->id, DHCPV6_DUID_HARDWARE_IEEE_802_NETWORKS_TYPE); + dhcp_service_link_local_rx_cb_set(cur->id, ws_bootstrap_dhcp_neighbour_update_cb); 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); + dhcp_client_option_notification_cb_set(cur->id, ws_bootstrap_dhcp_info_notify_cb); ws_nud_table_reset(cur); @@ -1434,12 +1546,13 @@ static void ws_bootstrap_pan_config_analyse(struct protocol_interface_info_entry if (!neighbour_pointer_valid) { return; } + ws_bootstrap_neighbor_set_stable(cur, data->SrcAddr); } if (neighbour_pointer_valid) { etx_lqi_dbm_update(cur->id, data->mpduLinkQuality, data->signal_dbm, neighbor_info.neighbor->index, neighbor_info.neighbor->mac64); //Update Neighbor Broadcast and Unicast Parameters - ws_neighbor_class_neighbor_unicast_time_info_update(neighbor_info.ws_neighbor, ws_utt, data->timestamp); + ws_neighbor_class_neighbor_unicast_time_info_update(neighbor_info.ws_neighbor, ws_utt, data->timestamp, (uint8_t *) data->SrcAddr); ws_neighbor_class_neighbor_unicast_schedule_set(neighbor_info.ws_neighbor, ws_us, &cur->ws_info->hopping_schdule); ws_neighbor_class_neighbor_broadcast_time_info_update(neighbor_info.ws_neighbor, &ws_bt_ie, data->timestamp); ws_neighbor_class_neighbor_broadcast_schedule_set(neighbor_info.ws_neighbor, &ws_bs_ie); @@ -1484,7 +1597,11 @@ static void ws_bootstrap_pan_config_analyse(struct protocol_interface_info_entry tr_info("Updated PAN configuration own:%d, heard:%d", cur->ws_info->pan_information.pan_version, pan_version); // restart PAN version timer - cur->ws_info->pan_timeout_timer = cur->ws_info->cfg->timing.pan_timeout; + //Check Here Do we have a selected Primary parent + if (!cur->ws_info->configuration_learned || cur->ws_info->rpl_state == RPL_EVENT_DAO_DONE) { + cur->ws_info->pan_timeout_timer = cur->ws_info->cfg->timing.pan_timeout; + } + cur->ws_info->pan_information.pan_version = pan_version; ws_pae_controller_gtk_hash_update(cur, gtkhash_ptr); @@ -1523,7 +1640,7 @@ static void ws_bootstrap_pan_config_solicit_analyse(struct protocol_interface_in llc_neighbour_req_t neighbor_info; if (ws_bootstrap_neighbor_info_request(cur, data->SrcAddr, &neighbor_info, false)) { etx_lqi_dbm_update(cur->id, data->mpduLinkQuality, data->signal_dbm, neighbor_info.neighbor->index, neighbor_info.neighbor->mac64); - ws_neighbor_class_neighbor_unicast_time_info_update(neighbor_info.ws_neighbor, ws_utt, data->timestamp); + ws_neighbor_class_neighbor_unicast_time_info_update(neighbor_info.ws_neighbor, ws_utt, data->timestamp, (uint8_t *) data->SrcAddr); ws_neighbor_class_neighbor_unicast_schedule_set(neighbor_info.ws_neighbor, ws_us, &cur->ws_info->hopping_schdule); } @@ -1603,6 +1720,10 @@ bool ws_bootstrap_validate_channel_function(ws_us_ie_t *ws_us, ws_bs_ie_t *ws_bs static void ws_bootstrap_asynch_ind(struct protocol_interface_info_entry *cur, const struct mcps_data_ind_s *data, const struct mcps_data_ie_list *ie_ext, uint8_t message_type) { + // Store weakest heard packet RSSI + if (cur->ws_info->weakest_received_rssi > data->signal_dbm) { + cur->ws_info->weakest_received_rssi = data->signal_dbm; + } if (data->SrcAddrMode != MAC_ADDR_MODE_64_BIT) { // Not from long address @@ -1691,7 +1812,7 @@ static void ws_bootstrap_neighbor_table_clean(struct protocol_interface_info_ent { uint8_t ll_target[16]; - if (mac_neighbor_info(interface)->neighbour_list_size <= mac_neighbor_info(interface)->list_total_size - WS_NON_CHILD_NEIGHBOUR_COUNT) { + if (mac_neighbor_info(interface)->neighbour_list_size <= mac_neighbor_info(interface)->list_total_size - ws_common_temporary_entry_size(mac_neighbor_info(interface)->list_total_size)) { // Enough neighbor entries return; } @@ -1707,6 +1828,10 @@ static void ws_bootstrap_neighbor_table_clean(struct protocol_interface_info_ent continue; } + if (cur->link_lifetime != WS_NEIGHBOR_LINK_TIMEOUT) { + continue; + } + if (cur->link_role == PRIORITY_PARENT_NEIGHBOUR) { //This is our primary parent we cannot delete continue; @@ -1834,7 +1959,7 @@ static bool ws_neighbor_entry_nud_notify(mac_neighbor_table_entry_t *entry_ptr, ws_neighbor_class_entry_t *ws_neighbor = ws_neighbor_class_entry_get(&cur->ws_info->neighbor_storage, entry_ptr->index); etx_storage_t *etx_entry = etx_storage_entry_get(cur->id, entry_ptr->index); - if (!entry_ptr->trusted_device || !ws_neighbor || !etx_entry || ws_neighbor->negative_aro_send) { + if (!entry_ptr->trusted_device || !ws_neighbor || !etx_entry || ws_neighbor->negative_aro_send || entry_ptr->link_lifetime != WS_NEIGHBOR_LINK_TIMEOUT) { return false; } @@ -2515,6 +2640,7 @@ static bool ws_rpl_new_parent_callback(uint8_t *ll_parent_address, void *handle, bool create_ok = ws_bootstrap_neighbor_info_request(cur, entry->mac64, &neigh_buffer, true); if (create_ok) { ws_neighbor_class_entry_t *ws_neigh = neigh_buffer.ws_neighbor; + ws_bootstrap_neighbor_set_stable(cur, entry->mac64); //Copy fhss temporary data *ws_neigh = entry->neigh_info_list; //ETX Create here @@ -2613,6 +2739,7 @@ static void ws_bootstrap_start_discovery(protocol_interface_info_entry_t *cur) cur->nwk_nd_re_scan_count = 0; cur->ws_info->configuration_learned = false; cur->ws_info->pan_timeout_timer = 0; + cur->ws_info->weakest_received_rssi = 0; // Clear learned neighbours ws_bootstrap_neighbor_list_clean(cur); @@ -3226,8 +3353,8 @@ static int8_t ws_bootstrap_neighbor_set(protocol_interface_info_entry_t *cur, pa ns_list_add_to_end(&cur->ws_info->parent_list_free, parent_ptr); return -1; } - - ws_neighbor_class_neighbor_unicast_time_info_update(neighbor_info.ws_neighbor, &parent_ptr->ws_utt, parent_ptr->timestamp); + ws_bootstrap_neighbor_set_stable(cur, parent_ptr->addr); + ws_neighbor_class_neighbor_unicast_time_info_update(neighbor_info.ws_neighbor, &parent_ptr->ws_utt, parent_ptr->timestamp, parent_ptr->addr); ws_neighbor_class_neighbor_unicast_schedule_set(neighbor_info.ws_neighbor, &parent_ptr->ws_us, &cur->ws_info->hopping_schdule); return 0; } @@ -3374,6 +3501,11 @@ void ws_bootstrap_state_machine(protocol_interface_info_entry_t *cur) cur->ws_info->trickle_pcs_running = false; cur->ws_info->trickle_pc_consistency_block_period = 0; ws_fhss_configure(cur, false); + int8_t new_default = cur->ws_info->weakest_received_rssi - 1; + if ((new_default < CCA_DEFAULT_DBM) && (new_default >= CCA_LOW_LIMIT) && (new_default <= CCA_HIGH_LIMIT)) { + // Restart automatic CCA threshold using weakest received RSSI as new default + mac_helper_start_auto_cca_threshold(cur->id, cur->ws_info->hopping_schdule.number_of_channels, cur->ws_info->weakest_received_rssi - 1, CCA_HIGH_LIMIT, CCA_LOW_LIMIT); + } ws_bootstrap_start_authentication(cur); break; case ER_RPL_SCAN: @@ -3535,6 +3667,7 @@ int ws_bootstrap_get_info(protocol_interface_info_entry_t *cur, struct ws_stack_ info_ptr->rsl_out = ws_neighbour->rsl_out; info_ptr->routing_cost = ws_neighbour->routing_cost; } + info_ptr->device_min_sens = DEVICE_MIN_SENS; if (ws_bootstrap_state_discovery(cur)) { info_ptr->join_state = 1; } else if (ws_bootstrap_state_authenticate(cur)) { diff --git a/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_bootstrap.h b/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_bootstrap.h index d936c23ce6a..7be0655ca3c 100644 --- a/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_bootstrap.h +++ b/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_bootstrap.h @@ -86,14 +86,16 @@ bool ws_bootstrap_validate_channel_plan(struct ws_us_ie *ws_us, struct protocol_ bool ws_bootstrap_validate_channel_function(struct ws_us_ie *ws_us, struct ws_bs_ie *ws_bs); -void ws_bootstrap_eapol_rx_temporary_set(struct protocol_interface_info_entry *interface, const uint8_t *src64); - struct ws_neighbor_class_entry *ws_bootstrap_eapol_tx_temporary_set(struct protocol_interface_info_entry *interface, const uint8_t *src64); void ws_bootstrap_eapol_tx_temporary_clear(struct protocol_interface_info_entry *interface); +void ws_bootstrap_neighbor_set_stable(struct protocol_interface_info_entry *interface, const uint8_t *src64); + int ws_bootstrap_get_info(protocol_interface_info_entry_t *cur, struct ws_stack_info *info_ptr); +void ws_bootstrap_mac_neighbor_short_time_set(struct protocol_interface_info_entry *interface, const uint8_t *src64, uint32_t valid_time); + #else #define ws_bootstrap_init(interface_id, bootstrap_mode) (-1) @@ -101,10 +103,12 @@ int ws_bootstrap_get_info(protocol_interface_info_entry_t *cur, struct ws_stack_ #define ws_bootstrap_restart(cur) #define ws_bootstrap_neighbor_remove(cur, ll_address) #define ws_bootstrap_aro_failure(cur, ll_address) +#define ws_bootstrap_neighbor_set_stable(interface, src64) #define ws_bootstrap_primary_parent_update(interface, neighbor) #define ws_bootstrap_secondary_parent_update(interface) #define ws_bootstrap_get_info(cur, info_ptr) + #endif //HAVE_WS #endif /* WS_BOOTSTRAP_H_ */ diff --git a/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_common.c b/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_common.c index 841ce15dab8..b1d734a77a2 100644 --- a/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_common.c +++ b/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_common.c @@ -379,12 +379,21 @@ void ws_common_neighbor_remove(protocol_interface_info_entry_t *cur, const uint8 ws_bootstrap_neighbor_remove(cur, ll_address); } - +uint8_t ws_common_temporary_entry_size(uint8_t mac_table_size) +{ + if (mac_table_size >= 128) { + return (WS_RPL_CANDIDATE_PARENT_COUNT + WS_LARGE_TEMPORARY_NEIGHBOUR_ENTRIES); + } else if (mac_table_size >= 64) { + return (WS_RPL_CANDIDATE_PARENT_COUNT + WS_MEDIUM_TEMPORARY_NEIGHBOUR_ENTRIES); + } else { + return (WS_RPL_CANDIDATE_PARENT_COUNT + WS_SMALL_TEMPORARY_NEIGHBOUR_ENTRIES); + } +} uint8_t ws_common_allow_child_registration(protocol_interface_info_entry_t *interface, const uint8_t *eui64) { uint8_t child_count = 0; - uint8_t max_child_count = mac_neighbor_info(interface)->list_total_size - WS_NON_CHILD_NEIGHBOUR_COUNT; + uint8_t max_child_count = mac_neighbor_info(interface)->list_total_size - ws_common_temporary_entry_size(mac_neighbor_info(interface)->list_total_size); // Test API to limit child count if (test_max_child_count_override != 0xffff) { @@ -422,6 +431,7 @@ uint8_t ws_common_allow_child_registration(protocol_interface_info_entry_t *inte tr_warn("Child registration not allowed %d/%d, max:%d", child_count, max_child_count, mac_neighbor_info(interface)->list_total_size); return ARO_FULL; } + ws_bootstrap_neighbor_set_stable(interface, eui64); tr_info("Child registration allowed %d/%d, max:%d", child_count, max_child_count, mac_neighbor_info(interface)->list_total_size); return ARO_SUCCESS; } diff --git a/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_common.h b/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_common.h index 4dadf81b365..96a425c1308 100644 --- a/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_common.h +++ b/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_common.h @@ -83,6 +83,8 @@ typedef struct ws_info_s { uint8_t rpl_state; // state from rpl_event_t uint8_t pas_requests; // Amount of PAN solicits sent uint8_t eapol_tx_index; + uint8_t device_min_sens; // Device min sensitivity set by the application + int8_t weakest_received_rssi; // Weakest received signal (dBm) parent_info_t parent_info[WS_PARENT_LIST_SIZE]; parent_info_list_t parent_list_free; parent_info_list_t parent_list_reserved; @@ -155,6 +157,7 @@ void ws_common_primary_parent_update(protocol_interface_info_entry_t *interface, void ws_common_secondary_parent_update(protocol_interface_info_entry_t *interface); +uint8_t ws_common_temporary_entry_size(uint8_t mac_table_size); #define ws_info(cur) ((cur)->ws_info) #else #define ws_info(cur) ((ws_info_t *) NULL) diff --git a/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_common_defines.h b/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_common_defines.h index f6f5e5cca84..58f570f8715 100644 --- a/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_common_defines.h +++ b/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_common_defines.h @@ -240,6 +240,9 @@ typedef struct ws_bs_ie { #define WS_FAN_VERSION_1_0 1 #define WS_NEIGHBOR_LINK_TIMEOUT 2200 + +#define WS_NEIGHBOUR_TEMPORARY_ENTRY_LIFETIME 5 +#define WS_NEIGHBOUR_DHCP_ENTRY_LIFETIME 60 #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 @@ -342,7 +345,7 @@ typedef struct ws_bs_ie { // With FHSS we need to check CCA twice on TX channel #define WS_NUMBER_OF_CSMA_PERIODS 2 // Interval between two CCA checks -#define WS_CSMA_MULTI_CCA_INTERVAL 1000 +#define WS_CSMA_MULTI_CCA_INTERVAL 2000 /* Default FHSS timing information * diff --git a/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_config.h b/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_config.h index 62a338ea0d0..589724fda8a 100644 --- a/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_config.h +++ b/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_config.h @@ -153,9 +153,10 @@ extern uint8_t DEVICE_MIN_SENS; * Amount of ND reply entries left * rest are used as child count, but is related to neighbour table size */ -#define WS_RPL_CANDIDATE_PARENT_COUNT 3 // Largest possible value -#define WS_TEMPORARY_NEIGHBOUR_ENTRIES 7 -#define WS_NON_CHILD_NEIGHBOUR_COUNT (WS_RPL_CANDIDATE_PARENT_COUNT + WS_TEMPORARY_NEIGHBOUR_ENTRIES) +#define WS_RPL_CANDIDATE_PARENT_COUNT 3 +#define WS_SMALL_TEMPORARY_NEIGHBOUR_ENTRIES 7 +#define WS_MEDIUM_TEMPORARY_NEIGHBOUR_ENTRIES 12 +#define WS_LARGE_TEMPORARY_NEIGHBOUR_ENTRIES 22 /* * Neighbour blacklist timers @@ -265,4 +266,18 @@ extern uint8_t DEVICE_MIN_SENS; // How many times sending of initial EAPOL-key is retried #define DEFAULT_INITIAL_KEY_RETRY_COUNT 2 +/* + * RADIUS client retry timer defaults + */ +#define RADIUS_CLIENT_RETRY_IMIN 20 // First retry minimum 1 seconds +#define RADIUS_CLIENT_RETRY_IMAX 30 // First retry maximum 3 seconds +#define RADIUS_CLIENT_TIMER_EXPIRATIONS 3 // Number of retries is three + +/* + * EAP-TLS fragment length + * + * Configures both EAP-TLS and the RADIUS client (Framed-MTU on RFC 2864) + */ +#define EAP_TLS_FRAGMENT_LEN_VALUE 600 // EAP-TLS fragment length + #endif /* WS_CONFIG_H_ */ diff --git a/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_eapol_relay.c b/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_eapol_relay.c index a5a83c3ec3e..0bc7a5a472e 100644 --- a/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_eapol_relay.c +++ b/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_eapol_relay.c @@ -66,11 +66,14 @@ int8_t ws_eapol_relay_start(protocol_interface_info_entry_t *interface_ptr, uint return -1; } - if (ws_eapol_relay_get(interface_ptr)) { + eapol_relay_t *eapol_relay = ws_eapol_relay_get(interface_ptr); + + if (eapol_relay) { + memcpy(&eapol_relay->remote_addr.address, remote_addr, 16); return 0; } - eapol_relay_t *eapol_relay = ns_dyn_mem_alloc(sizeof(eapol_relay_t)); + eapol_relay = ns_dyn_mem_alloc(sizeof(eapol_relay_t)); if (!eapol_relay) { return -1; } diff --git a/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_empty_functions.c b/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_empty_functions.c index bc3d4ec2e39..942eb00e404 100644 --- a/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_empty_functions.c +++ b/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_empty_functions.c @@ -413,4 +413,13 @@ int ws_stack_info_get(int8_t interface_id, ws_stack_info_t *info_ptr) return -1; } +int ws_device_min_sens_set( + int8_t interface_id, + uint8_t device_min_sens) +{ + (void) interface_id; + (void) device_min_sens; + return -1; +} + #endif // no HAVE_WS diff --git a/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_llc_data_service.c b/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_llc_data_service.c index c9ffe9c1d40..d20f9980c9e 100644 --- a/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_llc_data_service.c +++ b/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_llc_data_service.c @@ -100,7 +100,7 @@ typedef struct { typedef NS_LIST_HEAD(llc_message_t, link) llc_message_list_t; #define MAX_NEIGH_TEMPORARY_MULTICAST_SIZE 5 -#define MAX_NEIGH_TEMPORRY_EAPOL_SIZE 30 +#define MAX_NEIGH_TEMPORRY_EAPOL_SIZE 20 #define MAX_NEIGH_TEMPORAY_LIST_SIZE (MAX_NEIGH_TEMPORARY_MULTICAST_SIZE + MAX_NEIGH_TEMPORRY_EAPOL_SIZE) typedef struct { @@ -465,10 +465,16 @@ static void ws_llc_mac_confirm_cb(const mac_api_t *api, const mcps_data_conf_t * } } //ETX update + llc_neighbour_req_t neighbor_info; + neighbor_info.ws_neighbor = NULL; + neighbor_info.neighbor = NULL; if (message->ack_requested && messsage_type == WS_FT_DATA) { - llc_neighbour_req_t neighbor_info; + bool success = false; + if (message->dst_address_type == MAC_ADDR_MODE_64_BIT) { + base->ws_neighbor_info_request_cb(interface, message->dst_address, &neighbor_info, false); + } switch (data->status) { case MLME_SUCCESS: case MLME_TX_NO_ACK: @@ -477,7 +483,7 @@ static void ws_llc_mac_confirm_cb(const mac_api_t *api, const mcps_data_conf_t * success = true; } - if (message->dst_address_type == MAC_ADDR_MODE_64_BIT && base->ws_neighbor_info_request_cb(interface, message->dst_address, &neighbor_info, false)) { + if (neighbor_info.ws_neighbor && neighbor_info.neighbor && neighbor_info.neighbor->link_lifetime == WS_NEIGHBOR_LINK_TIMEOUT) { etx_transm_attempts_update(interface->id, 1 + data->tx_retries, success, neighbor_info.neighbor->index, neighbor_info.neighbor->mac64); //TODO discover RSL from Enchanced ACK Header IE elements ws_utt_ie_t ws_utt; @@ -487,7 +493,7 @@ static void ws_llc_mac_confirm_cb(const mac_api_t *api, const mcps_data_conf_t * neighbor_info.neighbor->lifetime = neighbor_info.neighbor->link_lifetime; } - ws_neighbor_class_neighbor_unicast_time_info_update(neighbor_info.ws_neighbor, &ws_utt, data->timestamp); + ws_neighbor_class_neighbor_unicast_time_info_update(neighbor_info.ws_neighbor, &ws_utt, data->timestamp, neighbor_info.neighbor->mac64); } int8_t rsl; @@ -500,6 +506,7 @@ static void ws_llc_mac_confirm_cb(const mac_api_t *api, const mcps_data_conf_t * default: break; } + } //Free message llc_message_free(message, base); @@ -529,6 +536,12 @@ static void ws_llc_mac_confirm_cb(const mac_api_t *api, const mcps_data_conf_t * ns_list_remove(&base->temp_entries->llc_eap_pending_list, message); ws_llc_mpx_eapol_send(base, message); } + } else { + if (neighbor_info.ws_neighbor && neighbor_info.neighbor && neighbor_info.neighbor->link_lifetime != WS_NEIGHBOR_LINK_TIMEOUT) { + //Remove temp neighbour + tr_debug("Remove Temp Entry by TX confirm"); + mac_neighbor_table_neighbor_remove(mac_neighbor_info(interface), neighbor_info.neighbor); + } } return; @@ -689,7 +702,7 @@ static void ws_llc_data_indication_cb(const mac_api_t *api, const mcps_data_ind_ return; } - ws_neighbor_class_neighbor_unicast_time_info_update(neighbor_info.ws_neighbor, &ws_utt, data->timestamp); + ws_neighbor_class_neighbor_unicast_time_info_update(neighbor_info.ws_neighbor, &ws_utt, data->timestamp, (uint8_t *) data->SrcAddr); if (us_ie_inline) { ws_neighbor_class_neighbor_unicast_schedule_set(neighbor_info.ws_neighbor, &us_ie, &interface->ws_info->hopping_schdule); } @@ -711,7 +724,8 @@ static void ws_llc_data_indication_cb(const mac_api_t *api, const mcps_data_ind_ neighbor_info.ws_neighbor->unicast_data_rx = true; } - // Calculate RSL for all UDATA packages heard + // Calculate RSL for all UDATA packets heard + ws_neighbor_class_rf_sensitivity_calculate(interface->ws_info->device_min_sens, data->signal_dbm); ws_neighbor_class_rsl_in_calculate(neighbor_info.ws_neighbor, data->signal_dbm); if (neighbor_info.neighbor) { @@ -795,7 +809,7 @@ static void ws_llc_eapol_indication_cb(const mac_api_t *api, const mcps_data_ind temp_entry->signal_dbm = data->signal_dbm; } uint8_t auth_eui64[8]; - ws_neighbor_class_neighbor_unicast_time_info_update(neighbor_info.ws_neighbor, &ws_utt, data->timestamp); + ws_neighbor_class_neighbor_unicast_time_info_update(neighbor_info.ws_neighbor, &ws_utt, data->timestamp, (uint8_t *) data->SrcAddr); if (us_ie_inline) { ws_neighbor_class_neighbor_unicast_schedule_set(neighbor_info.ws_neighbor, &us_ie, &interface->ws_info->hopping_schdule); } diff --git a/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_management_api.c b/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_management_api.c index a3246435582..5215f2c8d9c 100644 --- a/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_management_api.c +++ b/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_management_api.c @@ -741,4 +741,18 @@ int ws_stack_info_get(int8_t interface_id, ws_stack_info_t *info_ptr) return ws_bootstrap_get_info(cur, info_ptr); } +int ws_device_min_sens_set( + int8_t interface_id, + uint8_t device_min_sens) +{ + protocol_interface_info_entry_t *cur; + cur = protocol_stack_interface_info_get_by_id(interface_id); + if (!cur || !ws_info(cur)) { + return -1; + } + DEVICE_MIN_SENS = device_min_sens; + ws_info(cur)->device_min_sens = device_min_sens; + return 0; +} + #endif // HAVE_WS diff --git a/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_neighbor_class.c b/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_neighbor_class.c index eedb016240d..4cafc622a7a 100644 --- a/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_neighbor_class.c +++ b/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_neighbor_class.c @@ -89,8 +89,44 @@ void ws_neighbor_class_entry_remove(ws_neighbor_class_t *class_data, uint8_t att } } -void ws_neighbor_class_neighbor_unicast_time_info_update(ws_neighbor_class_entry_t *ws_neighbor, ws_utt_ie_t *ws_utt, uint32_t timestamp) +#ifdef FEA_TRACE_SUPPORT +static int own_ceil(float value) { + int ivalue = (int)value; + if (value == (float)ivalue) { + return ivalue; + } + return ivalue + 1; +} + +static void ws_neighbor_calculate_ufsi_drift(ws_neighbor_class_entry_t *ws_neighbor, ws_utt_ie_t *ws_utt, uint32_t timestamp, uint8_t address[8]) +{ + if (ws_neighbor->fhss_data.uc_timing_info.utt_rx_timestamp && ws_neighbor->fhss_data.uc_timing_info.ufsi) { + uint32_t seq_length = 0x10000; + if (ws_neighbor->fhss_data.uc_timing_info.unicast_channel_function == WS_TR51CF) { + seq_length = ws_neighbor->fhss_data.uc_timing_info.unicast_number_of_channels; + } + // Convert 24-bit UFSI to real time before drift calculation + uint32_t time_since_seq_start_prev_ms = own_ceil((float)((uint64_t)ws_neighbor->fhss_data.uc_timing_info.ufsi * seq_length * ws_neighbor->fhss_data.uc_timing_info.unicast_dwell_interval) / 0x1000000); + uint32_t time_since_seq_start_cur_ms = own_ceil((float)((uint64_t)ws_utt->ufsi * seq_length * ws_neighbor->fhss_data.uc_timing_info.unicast_dwell_interval) / 0x1000000); + uint32_t time_since_last_ufsi_us = timestamp - ws_neighbor->fhss_data.uc_timing_info.utt_rx_timestamp; + uint32_t ufsi_diff_ms = time_since_seq_start_cur_ms - time_since_seq_start_prev_ms; + int32_t ufsi_drift_ms = (int32_t)(time_since_last_ufsi_us / 1000 - ufsi_diff_ms); + // Only trace if there is significant error + if (ufsi_drift_ms < -5 || ufsi_drift_ms > 5) { + tr_debug("UFSI updated: %s, drift: %"PRIi32"ms in %"PRIu32" seconds", trace_array(address, 8), ufsi_drift_ms, time_since_last_ufsi_us / 1000000); + } + } +} +#endif + +void ws_neighbor_class_neighbor_unicast_time_info_update(ws_neighbor_class_entry_t *ws_neighbor, ws_utt_ie_t *ws_utt, uint32_t timestamp, uint8_t address[8]) +{ +#ifdef FEA_TRACE_SUPPORT + ws_neighbor_calculate_ufsi_drift(ws_neighbor, ws_utt, timestamp, address); +#else + (void) address; +#endif ws_neighbor->fhss_data.uc_timing_info.utt_rx_timestamp = timestamp; ws_neighbor->fhss_data.uc_timing_info.ufsi = ws_utt->ufsi; } @@ -245,8 +281,13 @@ void ws_neighbor_class_neighbor_broadcast_schedule_set(ws_neighbor_class_entry_t ws_neighbor->fhss_data.bc_timing_info.broadcast_schedule_id = ws_bs_ie->broadcast_schedule_identifier; } -void ws_neighbor_class_rf_sensitivity_calculate(uint8_t rsl_heard) +void ws_neighbor_class_rf_sensitivity_calculate(uint8_t dev_min_sens_config, int8_t dbm_heard) { + if (dev_min_sens_config != 0) { + // Automatic mode disabled + return; + } + uint8_t rsl_heard = ws_neighbor_class_rsl_from_dbm_calculate(dbm_heard); if (DEVICE_MIN_SENS > rsl_heard) { // We are hearing packet with lower than min_sens dynamically learn the sensitivity DEVICE_MIN_SENS = rsl_heard; @@ -285,8 +326,6 @@ static void ws_neighbor_class_parent_set_analyze(ws_neighbor_class_entry_t *ws_n void ws_neighbor_class_rsl_in_calculate(ws_neighbor_class_entry_t *ws_neighbor, int8_t dbm_heard) { uint8_t rsl = ws_neighbor_class_rsl_from_dbm_calculate(dbm_heard); - // Calculate minimum sensitivity from heard packets. - ws_neighbor_class_rf_sensitivity_calculate(rsl); if (ws_neighbor->rsl_in == RSL_UNITITIALIZED) { ws_neighbor->rsl_in = rsl << WS_RSL_SCALING; } diff --git a/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_neighbor_class.h b/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_neighbor_class.h index e1ebf048232..aa63fa181f8 100644 --- a/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_neighbor_class.h +++ b/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_neighbor_class.h @@ -106,7 +106,7 @@ void ws_neighbor_class_entry_remove(ws_neighbor_class_t *class_data, uint8_t att * \param timestamp timestamp for received data * */ -void ws_neighbor_class_neighbor_unicast_time_info_update(ws_neighbor_class_entry_t *ws_neighbor, ws_utt_ie_t *ws_utt, uint32_t timestamp); +void ws_neighbor_class_neighbor_unicast_time_info_update(ws_neighbor_class_entry_t *ws_neighbor, ws_utt_ie_t *ws_utt, uint32_t timestamp, uint8_t address[8]); /** * ws_neighbor_class_neighbor_unicast_schedule_set a function for update neighbor unicast shedule information @@ -146,7 +146,7 @@ void ws_neighbor_class_neighbor_broadcast_schedule_set(ws_neighbor_class_entry_t * \param rsl_heard; rsl_heard heard from Radio * */ -void ws_neighbor_class_rf_sensitivity_calculate(uint8_t rsl_heard); +void ws_neighbor_class_rf_sensitivity_calculate(uint8_t dev_min_sens_config, int8_t dbm_heard); /** * ws_neighbor_class_rsl_from_dbm_calculate diff --git a/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_pae_auth.c b/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_pae_auth.c index b435270c771..448127abb78 100644 --- a/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_pae_auth.c +++ b/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_pae_auth.c @@ -94,6 +94,7 @@ typedef struct { ws_pae_auth_nw_info_updated *nw_info_updated; /**< Security keys network info updated callback */ ws_pae_auth_ip_addr_get *ip_addr_get; /**< IP address get callback */ supp_list_t active_supp_list; /**< List of active supplicants */ + shared_comp_list_t shared_comp_list; /**< Shared component list */ arm_event_storage_t *timer; /**< Timer */ sec_prot_gtk_keys_t *next_gtks; /**< Next GTKs */ const sec_prot_certs_t *certs; /**< Certificates */ @@ -121,6 +122,8 @@ static int8_t ws_pae_auth_timer_if_start(kmp_service_t *service, kmp_api_t *kmp) static int8_t ws_pae_auth_timer_if_stop(kmp_service_t *service, kmp_api_t *kmp); static int8_t ws_pae_auth_timer_start(pae_auth_t *pae_auth); static int8_t ws_pae_auth_timer_stop(pae_auth_t *pae_auth); +static int8_t ws_pae_auth_shared_comp_add(kmp_service_t *service, kmp_shared_comp_t *data); +static int8_t ws_pae_auth_shared_comp_remove(kmp_service_t *service, kmp_shared_comp_t *data); static bool ws_pae_auth_timer_running(pae_auth_t *pae_auth); static void ws_pae_auth_kmp_service_addr_get(kmp_service_t *service, kmp_api_t *kmp, kmp_addr_t *local_addr, kmp_addr_t *remote_addr); static void ws_pae_auth_kmp_service_ip_addr_get(kmp_service_t *service, kmp_api_t *kmp, uint8_t *address); @@ -156,6 +159,7 @@ int8_t ws_pae_auth_init(protocol_interface_info_entry_t *interface_ptr, sec_prot pae_auth->pan_id = 0xffff; pae_auth->interface_ptr = interface_ptr; ws_pae_lib_supp_list_init(&pae_auth->active_supp_list); + ws_pae_lib_shared_comp_list_init(&pae_auth->shared_comp_list); pae_auth->timer = NULL; pae_auth->hash_set = NULL; @@ -192,6 +196,10 @@ int8_t ws_pae_auth_init(protocol_interface_info_entry_t *interface_ptr, sec_prot goto error; } + if (kmp_service_shared_comp_if_register(pae_auth->kmp_service, ws_pae_auth_shared_comp_add, ws_pae_auth_shared_comp_remove)) { + goto error; + } + if (auth_key_sec_prot_register(pae_auth->kmp_service) < 0) { goto error; } @@ -594,6 +602,8 @@ static void ws_pae_auth_free(pae_auth_t *pae_auth) return; } + ws_pae_lib_shared_comp_list_free(&pae_auth->shared_comp_list); + ws_pae_lib_supp_list_delete(&pae_auth->active_supp_list); kmp_socket_if_unregister(pae_auth->kmp_service); @@ -741,6 +751,8 @@ void ws_pae_auth_slow_timer(uint16_t seconds) } ws_pae_lib_supp_list_slow_timer_update(&pae_auth->active_supp_list, seconds); + + ws_pae_lib_shared_comp_list_timeout(&pae_auth->shared_comp_list, seconds); } // Update key storage timer @@ -837,6 +849,26 @@ static int8_t ws_pae_auth_timer_if_stop(kmp_service_t *service, kmp_api_t *kmp) return 0; } +static int8_t ws_pae_auth_shared_comp_add(kmp_service_t *service, kmp_shared_comp_t *data) +{ + pae_auth_t *pae_auth = ws_pae_auth_by_kmp_service_get(service); + if (!pae_auth) { + return -1; + } + + return ws_pae_lib_shared_comp_list_add(&pae_auth->shared_comp_list, data); +} + +static int8_t ws_pae_auth_shared_comp_remove(kmp_service_t *service, kmp_shared_comp_t *data) +{ + pae_auth_t *pae_auth = ws_pae_auth_by_kmp_service_get(service); + if (!pae_auth) { + return -1; + } + + return ws_pae_lib_shared_comp_list_remove(&pae_auth->shared_comp_list, data); +} + static int8_t ws_pae_auth_timer_start(pae_auth_t *pae_auth) { pae_auth->timer_running = true; @@ -948,7 +980,7 @@ static kmp_api_t *ws_pae_auth_kmp_incoming_ind(kmp_service_t *service, uint8_t m kmp_type_e kmp_type_to_search = type; // If radius is enabled, route EAP-TLS to radius EAP-TLS - if (pae_auth->sec_cfg->radius_cfg.radius_addr_set && type == IEEE_802_1X_MKA) { + if (pae_auth->sec_cfg->radius_cfg != NULL && pae_auth->sec_cfg->radius_cfg->radius_addr_set && type == IEEE_802_1X_MKA) { kmp_type_to_search = RADIUS_IEEE_802_1X_MKA; } @@ -1118,7 +1150,7 @@ static kmp_type_e ws_pae_auth_next_protocol_get(pae_auth_t *pae_auth, supp_entry if (sec_keys->pmk_mismatch) { sec_keys->ptk_mismatch = true; // start EAP-TLS towards supplicant - if (pae_auth->sec_cfg->radius_cfg.radius_addr_set) { + if (pae_auth->sec_cfg->radius_cfg != NULL && pae_auth->sec_cfg->radius_cfg->radius_addr_set) { next_type = RADIUS_IEEE_802_1X_MKA; } else { next_type = IEEE_802_1X_MKA; diff --git a/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_pae_controller.c b/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_pae_controller.c index 80b72e5231c..e222d825da2 100644 --- a/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_pae_controller.c +++ b/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_pae_controller.c @@ -24,6 +24,7 @@ #include "fhss_config.h" #include "ns_address.h" #include "ws_management_api.h" +#include "ws_bbr_api.h" #include "Service_Libs/utils/ns_file.h" #include "NWK_INTERFACE/Include/protocol.h" #include "6LoWPAN/ws/ws_config.h" @@ -106,6 +107,7 @@ typedef struct { } pae_controller_t; typedef struct { + sec_radius_cfg_t *radius_cfg; /**< Radius configuration settings */ uint16_t node_limit; /**< Max number of stored supplicants */ bool node_limit_set : 1; /**< Node limit set */ bool ext_cert_valid_enabled : 1; /**< Extended certificate validation enabled */ @@ -146,13 +148,12 @@ static const char *NW_INFO_FILE = NW_INFO_FILE_NAME; static NS_LIST_DEFINE(pae_controller_list, pae_controller_t, link); pae_controller_config_t pae_controller_config = { + .radius_cfg = NULL, .node_limit = 0, .node_limit_set = false, .ext_cert_valid_enabled = false }; -sec_radius_cfg_t *pae_controller_radius_settings; - int8_t ws_pae_controller_authenticate(protocol_interface_info_entry_t *interface_ptr) { pae_controller_t *controller = ws_pae_controller_get(interface_ptr); @@ -217,16 +218,16 @@ int8_t ws_pae_controller_authenticator_start(protocol_interface_info_entry_t *in return -1; } - if (pae_controller_radius_settings) { - // If either address or password is set, both must be set - if (controller->sec_cfg.radius_cfg.radius_addr_set || controller->sec_cfg.radius_cfg.radius_shared_secret_len > 0) { - if (!controller->sec_cfg.radius_cfg.radius_addr_set) { + // If either radius address or password is set, both must be set + if (controller->sec_cfg.radius_cfg != NULL) { + if (controller->sec_cfg.radius_cfg->radius_addr_set || controller->sec_cfg.radius_cfg->radius_shared_secret_len > 0) { + if (!controller->sec_cfg.radius_cfg->radius_addr_set) { return -1; } - if (controller->sec_cfg.radius_cfg.radius_shared_secret_len == 0) { + if (controller->sec_cfg.radius_cfg->radius_shared_secret_len == 0) { return -1; } - if (ws_pae_auth_radius_address_set(interface_ptr, controller->sec_cfg.radius_cfg.radius_addr) < 0) { + if (ws_pae_auth_radius_address_set(interface_ptr, controller->sec_cfg.radius_cfg->radius_addr) < 0) { return -1; } } @@ -704,9 +705,7 @@ int8_t ws_pae_controller_configure(protocol_interface_info_entry_t *interface_pt ws_pae_timers_settings_init(&controller->sec_cfg.timer_cfg, sec_timer_cfg); } - if (pae_controller_radius_settings) { - controller->sec_cfg.radius_cfg = *pae_controller_radius_settings; - } + controller->sec_cfg.radius_cfg = pae_controller_config.radius_cfg; return 0; } @@ -1171,36 +1170,59 @@ int8_t ws_pae_controller_certificate_revocation_list_remove(const arm_cert_revoc return ret; } +sec_radius_cfg_t *ws_pae_controller_radius_config_get(void) +{ + if (pae_controller_config.radius_cfg != NULL) { + return pae_controller_config.radius_cfg; + } + + pae_controller_config.radius_cfg = ns_dyn_mem_alloc(sizeof(sec_radius_cfg_t)); + if (pae_controller_config.radius_cfg == NULL) { + return NULL; + } + + pae_controller_config.radius_cfg->radius_retry_trickle_params.Imin = RADIUS_CLIENT_RETRY_IMIN; + pae_controller_config.radius_cfg->radius_retry_trickle_params.Imax = RADIUS_CLIENT_RETRY_IMAX; + pae_controller_config.radius_cfg->radius_retry_trickle_params.k = 0; + pae_controller_config.radius_cfg->radius_retry_trickle_params.TimerExpirations = RADIUS_CLIENT_TIMER_EXPIRATIONS; + + pae_controller_config.radius_cfg->radius_addr_set = false; + pae_controller_config.radius_cfg->radius_shared_secret_len = 0; + pae_controller_config.radius_cfg->radius_shared_secret = NULL; + + return pae_controller_config.radius_cfg; +} + int8_t ws_pae_controller_radius_address_set(int8_t interface_id, const uint8_t *address) { - pae_controller_t *controller = ws_pae_controller_get_or_create(interface_id); + sec_radius_cfg_t *radius_cfg = ws_pae_controller_radius_config_get(); + if (radius_cfg == NULL) { + return -1; + } - // If remote address is not set, clear radius information - if (!address) { - if (pae_controller_radius_settings != NULL) { - pae_controller_radius_settings->radius_addr_set = false; - } - if (controller) { - ws_pae_controller_configure(controller->interface_ptr, NULL, NULL); - } + if (address != NULL) { + memcpy(radius_cfg->radius_addr, address, 16); + radius_cfg->radius_addr_set = true; + } else { + radius_cfg->radius_addr_set = false; + } + + pae_controller_t *controller = ws_pae_controller_get_or_create(interface_id); + if (!controller) { return 0; } - if (pae_controller_radius_settings == NULL) { - pae_controller_radius_settings = ns_dyn_mem_alloc(sizeof(sec_radius_cfg_t)); - if (!pae_controller_radius_settings) { - return -1; - } - memset(pae_controller_radius_settings, 0, sizeof(sec_radius_cfg_t)); + if (ws_pae_controller_configure(controller->interface_ptr, NULL, NULL) < 0) { + return -1; } - memcpy(pae_controller_radius_settings->radius_addr, address, 16); - pae_controller_radius_settings->radius_addr_set = true; - if (controller) { - ws_pae_controller_configure(controller->interface_ptr, NULL, NULL); - if (ws_pae_auth_radius_address_set(controller->interface_ptr, controller->sec_cfg.radius_cfg.radius_addr) < 0) { - return -1; - } + if (!radius_cfg->radius_addr_set) { + return 0; + } + + if (ws_pae_auth_radius_address_set(controller->interface_ptr, radius_cfg->radius_addr) < 0) { + // If not set here since authenticator not created, then set on authenticator initialization + return 0; } return 0; @@ -1214,54 +1236,84 @@ int8_t ws_pae_controller_radius_address_get(int8_t interface_id, uint8_t *addres return -1; } - if (pae_controller_radius_settings == NULL || !pae_controller_radius_settings->radius_addr_set) { + sec_radius_cfg_t *radius_cfg = ws_pae_controller_radius_config_get(); + if (radius_cfg == NULL) { + return -1; + } + + if (!radius_cfg->radius_addr_set) { return -1; } - memcpy(address, pae_controller_radius_settings->radius_addr, 16); + memcpy(address, radius_cfg->radius_addr, 16); + return 0; } int8_t ws_pae_controller_radius_shared_secret_set(int8_t interface_id, const uint16_t shared_secret_len, const uint8_t *shared_secret) { + sec_radius_cfg_t *radius_cfg = ws_pae_controller_radius_config_get(); + if (radius_cfg == NULL) { + return -1; + } + + radius_cfg->radius_shared_secret = shared_secret; + radius_cfg->radius_shared_secret_len = shared_secret_len; + pae_controller_t *controller = ws_pae_controller_get_or_create(interface_id); + if (controller) { + ws_pae_controller_configure(controller->interface_ptr, NULL, NULL); + } - // If shared secret is not set, clear radius information - if (shared_secret_len == 0 || !shared_secret) { - if (pae_controller_radius_settings != NULL) { - memset(pae_controller_radius_settings->radius_shared_secret, 0, pae_controller_radius_settings->radius_shared_secret_len); - pae_controller_radius_settings->radius_shared_secret_len = 0; - } - if (controller) { - ws_pae_controller_configure(controller->interface_ptr, NULL, NULL); - } - return 0; + return 0; +} + +int8_t ws_pae_controller_radius_shared_secret_get(int8_t interface_id, uint16_t *shared_secret_len, uint8_t *shared_secret) +{ + (void) interface_id; + + if (shared_secret_len == NULL) { + return -1; + } + + sec_radius_cfg_t *radius_cfg = ws_pae_controller_radius_config_get(); + if (radius_cfg == NULL) { + return -1; } - if (pae_controller_radius_settings == NULL) { - pae_controller_radius_settings = ns_dyn_mem_alloc(sizeof(sec_radius_cfg_t)); - if (!pae_controller_radius_settings) { - return -1; + uint16_t length = radius_cfg->radius_shared_secret_len; + if (shared_secret != NULL) { + if (length > *shared_secret_len) { + length = *shared_secret_len; + } + if (length > 0 && radius_cfg->radius_shared_secret != NULL) { + memcpy(shared_secret, radius_cfg->radius_shared_secret, length); } - memset(pae_controller_radius_settings, 0, sizeof(sec_radius_cfg_t)); } - if (pae_controller_radius_settings->radius_shared_secret != NULL && - pae_controller_radius_settings->radius_shared_secret_len != shared_secret_len) { - ns_dyn_mem_free(pae_controller_radius_settings->radius_shared_secret); - pae_controller_radius_settings->radius_shared_secret = NULL; + *shared_secret_len = length; + + return 0; +} + +int8_t ws_pae_controller_radius_timing_set(int8_t interface_id, bbr_radius_timing_t *timing) +{ + (void) interface_id; + + if (timing == NULL) { + return -1; } - if (pae_controller_radius_settings->radius_shared_secret == NULL) { - pae_controller_radius_settings->radius_shared_secret = ns_dyn_mem_alloc(shared_secret_len); - if (pae_controller_radius_settings->radius_shared_secret == NULL) { - return -1; - } + sec_radius_cfg_t *radius_cfg = ws_pae_controller_radius_config_get(); + if (radius_cfg == NULL) { + return -1; } - memcpy(pae_controller_radius_settings->radius_shared_secret, shared_secret, shared_secret_len); - pae_controller_radius_settings->radius_shared_secret_len = shared_secret_len; + radius_cfg->radius_retry_trickle_params.Imin = timing->radius_retry_imin; + radius_cfg->radius_retry_trickle_params.Imax = timing->radius_retry_imax; + radius_cfg->radius_retry_trickle_params.TimerExpirations = timing->radius_retry_count; + pae_controller_t *controller = ws_pae_controller_get_or_create(interface_id); if (controller) { ws_pae_controller_configure(controller->interface_ptr, NULL, NULL); } @@ -1269,28 +1321,45 @@ int8_t ws_pae_controller_radius_shared_secret_set(int8_t interface_id, const uin return 0; } -int8_t ws_pae_controller_radius_shared_secret_get(int8_t interface_id, uint16_t *shared_secret_len, uint8_t *shared_secret) +int8_t ws_pae_controller_radius_timing_get(int8_t interface_id, bbr_radius_timing_t *timing) { (void) interface_id; - if (shared_secret_len == NULL) { + if (timing == NULL) { return -1; } - uint16_t length = 0; - if (pae_controller_radius_settings != NULL) { - length = pae_controller_radius_settings->radius_shared_secret_len; - if (shared_secret != NULL) { - if (length > *shared_secret_len) { - length = *shared_secret_len; - } - if (length > 0 && pae_controller_radius_settings->radius_shared_secret != NULL) { - memcpy(shared_secret, pae_controller_radius_settings->radius_shared_secret, length); - } - } + if (pae_controller_config.radius_cfg == NULL) { + timing->radius_retry_imin = RADIUS_CLIENT_RETRY_IMIN; + timing->radius_retry_imax = RADIUS_CLIENT_RETRY_IMAX; + timing->radius_retry_count = RADIUS_CLIENT_TIMER_EXPIRATIONS; + return 0; } - *shared_secret_len = length; + sec_radius_cfg_t *radius_cfg = ws_pae_controller_radius_config_get(); + if (radius_cfg == NULL) { + return -1; + } + + timing->radius_retry_imin = radius_cfg->radius_retry_trickle_params.Imin; + timing->radius_retry_imax = radius_cfg->radius_retry_trickle_params.Imax; + timing->radius_retry_count = radius_cfg->radius_retry_trickle_params.TimerExpirations; + + return 0; +} + +int8_t ws_pae_controller_radius_timing_validate(int8_t interface_id, bbr_radius_timing_t *timing) +{ + (void) interface_id; + + if (timing == NULL) { + return -1; + } + + if (timing->radius_retry_imin == 0 || timing->radius_retry_imax == 0 || + timing->radius_retry_imin > timing->radius_retry_imax) { + return -1; + } return 0; } diff --git a/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_pae_controller.h b/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_pae_controller.h index 93c3abdd34e..2b619ccf922 100644 --- a/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_pae_controller.h +++ b/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_pae_controller.h @@ -30,6 +30,7 @@ typedef enum { struct nvm_tlv_entry; struct ws_sec_timer_cfg_s; struct ws_sec_prot_cfg_s; +struct bbr_radius_timing; /** * ws_pae_controller_set_target sets EAPOL target for PAE supplicant @@ -282,6 +283,42 @@ int8_t ws_pae_controller_radius_shared_secret_set(int8_t interface_id, const uin */ int8_t ws_pae_controller_radius_shared_secret_get(int8_t interface_id, uint16_t *shared_secret_len, uint8_t *shared_secret); +/** + * ws_pae_controller_radius_timing_set set radius timing information + * + * \param interface_id interface identifier + * \param timing timing information + * + * \return < 0 failure + * \return >= 0 success + * + */ +int8_t ws_pae_controller_radius_timing_set(int8_t interface_id, struct bbr_radius_timing *timing); + +/** + * ws_pae_controller_radius_timing_get get radius timing information + * + * \param interface_id interface identifier + * \param timing timing information + * + * \return < 0 failure + * \return >= 0 success + * + */ +int8_t ws_pae_controller_radius_timing_get(int8_t interface_id, struct bbr_radius_timing *timing); + +/** + * ws_pae_controller_radius_timing_validate validate radius timing information + * + * \param interface_id interface identifier + * \param timing timing information + * + * \return < 0 failure + * \return >= 0 success + * + */ +int8_t ws_pae_controller_radius_timing_validate(int8_t interface_id, struct bbr_radius_timing *timing); + /** * ws_pae_controller_nw_info_set set network information * diff --git a/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_pae_lib.c b/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_pae_lib.c index 52ceaaba6a2..3f9ab10b37f 100644 --- a/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_pae_lib.c +++ b/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_pae_lib.c @@ -448,4 +448,64 @@ supp_entry_t *ws_pae_lib_supp_list_entry_retry_timer_get(supp_list_t *supp_list) return retry_supp; } +int8_t ws_pae_lib_shared_comp_list_init(shared_comp_list_t *comp_list) +{ + ns_list_init(comp_list); + return 0; +} + +int8_t ws_pae_lib_shared_comp_list_free(shared_comp_list_t *comp_list) +{ + ns_list_foreach_safe(shared_comp_entry_t, entry, comp_list) { + if (entry->data->delete) { + entry->data->delete (); + } + ns_list_remove(comp_list, entry); + ns_dyn_mem_free(entry); + } + return 0; +} + +int8_t ws_pae_lib_shared_comp_list_add(shared_comp_list_t *comp_list, kmp_shared_comp_t *data) +{ + ns_list_foreach(shared_comp_entry_t, entry, comp_list) { + if (entry->data == data) { + return -1; + } + } + + shared_comp_entry_t *entry = ns_dyn_mem_alloc(sizeof(shared_comp_entry_t)); + if (!entry) { + return -1; + } + entry->data = data; + ns_list_add_to_end(comp_list, entry); + + return 0; +} + +int8_t ws_pae_lib_shared_comp_list_remove(shared_comp_list_t *comp_list, kmp_shared_comp_t *data) +{ + ns_list_foreach(shared_comp_entry_t, entry, comp_list) { + if (entry->data == data) { + ns_list_remove(comp_list, entry); + ns_dyn_mem_free(entry); + return 0; + } + } + + return 0; +} + +int8_t ws_pae_lib_shared_comp_list_timeout(shared_comp_list_t *comp_list, uint16_t ticks) +{ + ns_list_foreach(shared_comp_entry_t, entry, comp_list) { + if (entry->data->timeout) { + entry->data->timeout(ticks); + } + } + + return 0; +} + #endif /* HAVE_WS */ diff --git a/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_pae_lib.h b/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_pae_lib.h index 5058e3e3640..dc9a0b67b56 100644 --- a/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_pae_lib.h +++ b/connectivity/nanostack/sal-stack-nanostack/source/6LoWPAN/ws/ws_pae_lib.h @@ -45,6 +45,13 @@ typedef struct supp_entry_s { typedef NS_LIST_HEAD(supp_entry_t, link) supp_list_t; +typedef struct { + kmp_shared_comp_t *data; /**< KMP shared component data */ + ns_list_link_t link; /**< Link */ +} shared_comp_entry_t; + +typedef NS_LIST_HEAD(shared_comp_entry_t, link) shared_comp_list_t; + /** * ws_pae_lib_kmp_list_init initializes KMP list * @@ -388,4 +395,62 @@ kmp_api_t *ws_pae_lib_supp_list_kmp_receive_check(supp_list_t *supp_list, const */ supp_entry_t *ws_pae_lib_supp_list_entry_retry_timer_get(supp_list_t *supp_list); +/** + * ws_pae_lib_shared_comp_list_init init shared component list + * + * \param comp_list component list + * + * \return < 0 failure + * \return >= 0 success + * + */ +int8_t ws_pae_lib_shared_comp_list_init(shared_comp_list_t *comp_list); + +/** + * ws_pae_lib_shared_comp_list_free free shared component list + * + * \param comp_list component list + * + * \return < 0 failure + * \return >= 0 success + * + */ +int8_t ws_pae_lib_shared_comp_list_free(shared_comp_list_t *comp_list); + +/** + * ws_pae_lib_shared_comp_list_add add to shared component list + * + * \param comp_list component list + * \param data shared component + * + * \return < 0 failure + * \return >= 0 success + * + */ +int8_t ws_pae_lib_shared_comp_list_add(shared_comp_list_t *comp_list, kmp_shared_comp_t *data); + +/** + * ws_pae_lib_shared_comp_list_remove remove from shared component list + * + * \param comp_list component list + * \param data shared component + * + * \return < 0 failure + * \return >= 0 success + * + */ +int8_t ws_pae_lib_shared_comp_list_remove(shared_comp_list_t *comp_list, kmp_shared_comp_t *data); + +/** + * ws_pae_lib_shared_comp_list_timeout timeout to shared component list + * + * \param comp_list component list + * \param ticks elapsed time in seconds + * + * \return < 0 failure + * \return >= 0 success + * + */ +int8_t ws_pae_lib_shared_comp_list_timeout(shared_comp_list_t *comp_list, uint16_t ticks); + #endif /* WS_PAE_AUTH_H_ */ diff --git a/connectivity/nanostack/sal-stack-nanostack/source/Common_Protocols/icmpv6.c b/connectivity/nanostack/sal-stack-nanostack/source/Common_Protocols/icmpv6.c index 7433f2640b6..1f8beaf6a32 100644 --- a/connectivity/nanostack/sal-stack-nanostack/source/Common_Protocols/icmpv6.c +++ b/connectivity/nanostack/sal-stack-nanostack/source/Common_Protocols/icmpv6.c @@ -46,6 +46,7 @@ #include "6LoWPAN/Bootstraps/protocol_6lowpan.h" #include "6LoWPAN/ws/ws_common_defines.h" #include "6LoWPAN/ws/ws_common.h" +#include "libNET/src/net_dns_internal.h" #define TRACE_GROUP "icmp" @@ -638,6 +639,21 @@ if_address_entry_t *icmpv6_slaac_address_add(protocol_interface_info_entry_t *cu } #ifdef HAVE_IPV6_ND + +static uint8_t icmpv6_dns_search_list_remove_pad(uint8_t *data_ptr, uint8_t length) +{ + while (length) { + + if (data_ptr[length - 2] && data_ptr[length - 1] == 0) { + break; + } else if (data_ptr[length - 2] == 0 && data_ptr[length - 1] == 0) { + length--; + } + } + + return length; +} + static buffer_t *icmpv6_ra_handler(buffer_t *buf) { protocol_interface_info_entry_t *cur; @@ -868,13 +884,11 @@ static buffer_t *icmpv6_ra_handler(buffer_t *buf) uint32_t dns_lifetime = common_read_32_bit(dptr + 2); // 2 x reserved uint8_t *dns_search_list = dptr + 6; uint8_t dns_search_list_len = length - 8; // Length includes type and length - - tr_info("DNS Search List: %s Lifetime: %lu", trace_array(dns_search_list, dns_search_list_len), (unsigned long) dns_lifetime); - // TODO Add DNS server to DNS information storage. - // dns_search_list_storage(cur, buf->src_sa.address, dns_search_list, dns_search_list_len, dns_lifetime); - (void)dns_search_list; - (void)dns_search_list_len; - (void)dns_lifetime; + //Cut Padding + dns_search_list_len = icmpv6_dns_search_list_remove_pad(dns_search_list, dns_search_list_len); + //tr_info("DNS Search List: %s Lifetime: %lu", trace_array(dns_search_list, dns_search_list_len), (unsigned long) dns_lifetime); + // Add DNS server to DNS information storage. + net_dns_server_search_list_set(cur->id, buf->src_sa.address, dns_search_list, dns_search_list_len, dns_lifetime); } else if (type == ICMPV6_OPT_RECURSIVE_DNS_SERVER) { uint8_t dns_length = length / 8; @@ -887,11 +901,9 @@ static buffer_t *icmpv6_ra_handler(buffer_t *buf) uint32_t dns_lifetime = common_read_32_bit(dptr + 2); // 2 x reserved for (int n = 0; n < dns_count; n++) { uint8_t *dns_srv_addr = dptr + 6 + n * 16; - tr_info("DNS Server: %s Lifetime: %lu", trace_ipv6(dns_srv_addr), (unsigned long) dns_lifetime); - // TODO Add DNS server to DNS information storage. - // dns_server_storage(cur, buf->src_sa.address, dns_srv_addr, dns_lifetime); - (void)dns_srv_addr; - (void)dns_lifetime; + //tr_info("DNS Server: %s Lifetime: %lu", trace_ipv6(dns_srv_addr), (unsigned long) dns_lifetime); + // Add DNS server to DNS information storage. + net_dns_server_address_set(cur->id, buf->src_sa.address, dns_srv_addr, dns_lifetime); } } else if (type == ICMPV6_OPT_6LOWPAN_CONTEXT) { nd_ra_process_lowpan_context_option(cur, dptr - 2); diff --git a/connectivity/nanostack/sal-stack-nanostack/source/DHCPv6_Server/DHCPv6_Server_service.c b/connectivity/nanostack/sal-stack-nanostack/source/DHCPv6_Server/DHCPv6_Server_service.c index a7755034a9d..8784c634d25 100644 --- a/connectivity/nanostack/sal-stack-nanostack/source/DHCPv6_Server/DHCPv6_Server_service.c +++ b/connectivity/nanostack/sal-stack-nanostack/source/DHCPv6_Server/DHCPv6_Server_service.c @@ -115,12 +115,29 @@ int DHCPv6_server_respond_client(dhcpv6_gua_server_entry_s *serverBase, dhcpv6_r } response->responseLength = libdhcpv6_address_reply_message_len(replyPacket->clientDUID.duid_length, replyPacket->serverDUID.duid_length, 0, replyPacket->rapidCommit, address_allocated); + //Calculate DNS LIST and Vendor data lengths here + response->responseLength += libdhcpv6_dns_server_message_sizes(serverBase); + response->responseLength += libdhcpv6_vendor_data_message_sizes(serverBase); + response->responsePtr = ns_dyn_mem_temporary_alloc(response->responseLength); if (response->responsePtr) { + uint8_t *ptr = response->responsePtr; + //Write Generic data at beginning + ptr = libdhcpv6_header_write(ptr, DHCPV6_REPLY_TYPE, replyPacket->transaction_ID); + ptr = libdhcpv6_duid_option_write(ptr, DHCPV6_SERVER_ID_OPTION, &replyPacket->serverDUID); //16 + ptr = libdhcpv6_duid_option_write(ptr, DHCPV6_CLIENT_ID_OPTION, &replyPacket->clientDUID); //16 if (address_allocated) { - libdhcpv6_reply_message_write(response->responsePtr, replyPacket, &nonTemporalAddress, NULL); + ptr = libdhcpv6_identity_association_option_write(ptr, replyPacket->iaId, replyPacket->T0, replyPacket->T1, true); + ptr = libdhcpv6_ia_address_option_write(ptr, nonTemporalAddress.requestedAddress, nonTemporalAddress.preferredLifeTime, nonTemporalAddress.validLifeTime); + //Write DNS LIST and Vendor data here + ptr = libdhcpv6_dns_server_message_writes(serverBase, ptr); + ptr = libdhcpv6_vendor_data_message_writes(serverBase, ptr); } else { - libdhcpv6_reply_message_write(response->responsePtr, replyPacket, NULL, NULL); + ptr = libdhcpv6_identity_association_option_write_with_status(ptr, replyPacket->iaId, replyPacket->T0, replyPacket->T1, DHCPV6_STATUS_NO_ADDR_AVAILABLE_CODE); + } + + if (replyPacket->rapidCommit) { + ptr = libdhcpv6_rapid_commit_option_write(ptr); } return 0; } @@ -407,6 +424,71 @@ int DHCPv6_server_service_set_address_validlifetime(int8_t interface, uint8_t gu return 0; } + +int DHCPv6_server_service_set_dns_server(int8_t interface, uint8_t guaPrefix[static 16], uint8_t dns_server_address[static 16], uint8_t *dns_search_list_ptr, uint8_t dns_search_list_len) +{ + dhcpv6_gua_server_entry_s *serverInfo = libdhcpv6_server_data_get_by_prefix_and_interfaceid(interface, guaPrefix); + if (!serverInfo) { + return -1; + } + + dhcpv6_dns_server_data_t *dns_entry = libdhcpv6_dns_server_allocate(serverInfo, dns_server_address); + if (!dns_entry) { + return -1; + } + + if (dns_entry->search_list_length != dns_search_list_len) { + ns_dyn_mem_free(dns_entry->search_list); + dns_entry->search_list = NULL; + dns_entry->search_list_length = 0; + if (dns_search_list_len) { + dns_entry->search_list = ns_dyn_mem_alloc(dns_search_list_len); + if (dns_entry->search_list) { + dns_entry->search_list_length = dns_search_list_len; + } + } + } + + if (dns_entry->search_list_length) { + //Copy Search List to allocated buffer + memcpy(dns_entry->search_list, dns_search_list_ptr, dns_entry->search_list_length); + } + + return 0; +} + +int DHCPv6_server_service_set_vendor_data(int8_t interface, uint8_t guaPrefix[static 16], uint32_t enterprise_number, uint8_t *dhcp_vendor_data_ptr, uint8_t dhcp_vendor_data_len) +{ + dhcpv6_gua_server_entry_s *serverInfo = libdhcpv6_server_data_get_by_prefix_and_interfaceid(interface, guaPrefix); + if (!serverInfo) { + return -1; + } + + dhcpv6_vendor_data_t *vendor_data_entry = libdhcpv6_vendor_data_allocate(serverInfo, enterprise_number); + + if (!vendor_data_entry) { + return -1; + } + + if (vendor_data_entry->vendor_data_length != dhcp_vendor_data_len) { + ns_dyn_mem_free(vendor_data_entry->vendor_data); + vendor_data_entry->vendor_data = NULL; + vendor_data_entry->vendor_data_length = 0; + if (dhcp_vendor_data_len) { + vendor_data_entry->vendor_data = ns_dyn_mem_alloc(dhcp_vendor_data_len); + if (vendor_data_entry->vendor_data) { + vendor_data_entry->vendor_data_length = dhcp_vendor_data_len; + } + } + } + + if (vendor_data_entry->vendor_data_length) { + //Copy Venfor Data to allocated buffer + memcpy(vendor_data_entry->vendor_data, dhcp_vendor_data_ptr, vendor_data_entry->vendor_data_length); + } + return 0; +} + #else int DHCPv6_server_service_init(int8_t interface, uint8_t guaPrefix[static 16], uint8_t serverDUID[static 8], uint16_t serverDUIDType) diff --git a/connectivity/nanostack/sal-stack-nanostack/source/DHCPv6_Server/DHCPv6_server_service.h b/connectivity/nanostack/sal-stack-nanostack/source/DHCPv6_Server/DHCPv6_server_service.h index 8f8616f4f41..024a46acdec 100644 --- a/connectivity/nanostack/sal-stack-nanostack/source/DHCPv6_Server/DHCPv6_server_service.h +++ b/connectivity/nanostack/sal-stack-nanostack/source/DHCPv6_Server/DHCPv6_server_service.h @@ -89,6 +89,11 @@ int DHCPv6_server_service_set_max_clients_accepts_count(int8_t interface, uint8_ * /param validLifeTimne in seconds */ int DHCPv6_server_service_set_address_validlifetime(int8_t interface, uint8_t guaPrefix[static 16], uint32_t validLifeTimne); + +int DHCPv6_server_service_set_dns_server(int8_t interface, uint8_t guaPrefix[static 16], uint8_t dns_server_address[static 16], uint8_t *dns_search_list_ptr, uint8_t dns_search_list_len); + +int DHCPv6_server_service_set_vendor_data(int8_t interface, uint8_t guaPrefix[static 16], uint32_t enterprise_number, uint8_t *dhcp_vendor_data_ptr, uint8_t dhcp_vendor_data_len); + #else #define DHCPv6_server_service_delete(interface, guaPrefix, delete_gua_addresses) #endif diff --git a/connectivity/nanostack/sal-stack-nanostack/source/DHCPv6_client/dhcpv6_client_api.h b/connectivity/nanostack/sal-stack-nanostack/source/DHCPv6_client/dhcpv6_client_api.h index ccfc6c1ddf8..57025e76efd 100644 --- a/connectivity/nanostack/sal-stack-nanostack/source/DHCPv6_client/dhcpv6_client_api.h +++ b/connectivity/nanostack/sal-stack-nanostack/source/DHCPv6_client/dhcpv6_client_api.h @@ -79,8 +79,48 @@ void dhcp_client_delete(int8_t interface); */ typedef void (dhcp_client_global_adress_cb)(int8_t interface, uint8_t dhcp_addr[static 16], uint8_t prefix[static 16], bool register_status); +typedef struct dhcp_server_notify_info { + uint16_t duid_type; + uint16_t duid_length; + uint32_t life_time; + uint8_t *duid; +} dhcp_server_notify_info_t; + + +typedef struct dhcp_gen_option { + uint16_t data_length; + uint8_t *data; +} dhcp_gen_option_t; + +typedef struct dhcp_vendor_spesific_option { + uint32_t enterprise_number; + uint16_t data_length; + uint8_t *data; +} dhcp_vendor_spesific_option_t; + +typedef struct dhcp_option_notify_s { + uint8_t option_type; + union { + dhcp_gen_option_t generic; + dhcp_vendor_spesific_option_t vendor_spesific; + } option; +} dhcp_option_notify_t; + +/* give dhcp Client server Optional options notication + * + * /param interface interface id + * /param option_type Type of option + * /param option_data data of options. + * /param option_length length of option. + * /param server_info info inclu DUID and Life-time for notify options + * + */ +typedef void (dhcp_client_options_notify_cb)(int8_t interface, dhcp_option_notify_t *options, dhcp_server_notify_info_t *server_info); + 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); +int dhcp_client_option_notification_cb_set(int8_t interface, dhcp_client_options_notify_cb *notify_cb); + /* Renew all leased adddresses might be used when short address changes * * /param interface interface where address is got diff --git a/connectivity/nanostack/sal-stack-nanostack/source/DHCPv6_client/dhcpv6_client_service.c b/connectivity/nanostack/sal-stack-nanostack/source/DHCPv6_client/dhcpv6_client_service.c index a8cecf6d8d2..559b6ccf1d2 100644 --- a/connectivity/nanostack/sal-stack-nanostack/source/DHCPv6_client/dhcpv6_client_service.c +++ b/connectivity/nanostack/sal-stack-nanostack/source/DHCPv6_client/dhcpv6_client_service.c @@ -33,6 +33,7 @@ typedef struct { dhcp_client_global_adress_cb *global_address_cb; + dhcp_client_options_notify_cb *option_information_cb; uint16_t service_instance; uint16_t relay_instance; uint16_t sol_timeout; @@ -152,6 +153,17 @@ void dhcp_client_solicit_timeout_set(int8_t interface, uint16_t timeout, uint16_ return; } +int dhcp_client_option_notification_cb_set(int8_t interface, dhcp_client_options_notify_cb *notify_cb) +{ + dhcp_client_class_t *dhcp_client = dhcpv6_client_entry_discover(interface); + if (!dhcp_client) { + return -1; + } + dhcp_client->option_information_cb = notify_cb; + return 0; + +} + void dhcp_relay_agent_enable(int8_t interface, uint8_t border_router_address[static 16]) { dhcp_client_class_t *dhcp_client = dhcpv6_client_entry_discover(interface); @@ -215,6 +227,67 @@ void dhcpv6_client_send_error_cb(dhcpv6_client_server_data_t *srv_data_ptr) } +static void dhcp_vendor_information_notify(uint8_t *ptr, uint16_t data_len, dhcp_client_class_t *dhcp_client, dhcpv6_client_server_data_t *srv_data_ptr) +{ + if (!dhcp_client->option_information_cb) { + return; + } + + if (!srv_data_ptr->iaNontemporalAddress.validLifetime) { + return; //Valid Lifetime zero + } + + dhcp_option_notify_t dhcp_option; + + uint16_t type, length; + bool valid_optional_options; + + dhcp_server_notify_info_t server_info; + server_info.life_time = srv_data_ptr->iaNontemporalAddress.validLifetime; + server_info.duid = srv_data_ptr->serverDUID.duid + 2; // Skip the type + server_info.duid_type = srv_data_ptr->serverDUID.type; + server_info.duid_length = srv_data_ptr->serverDUID.duid_length - 2;// remove the type + + while (data_len >= 4) { + type = common_read_16_bit(ptr); + ptr += 2; + length = common_read_16_bit(ptr); + ptr += 2; + data_len -= 4; + if (data_len < length) { + return; + } + valid_optional_options = false; + //Accept only listed items below with validated lengths + if ((type == DHCPV6_OPTION_VENDOR_SPECIFIC_INFO || type == DHCPV6_OPTION_VENDOR_CLASS) && data_len >= 4) { + valid_optional_options = true; + //Parse enterprise number + dhcp_option.option.vendor_spesific.enterprise_number = common_read_32_bit(ptr); + ptr += 4; + data_len -= 4; + length -= 4; + dhcp_option.option.vendor_spesific.data = ptr; + dhcp_option.option.vendor_spesific.data_length = length; + + + } else if (type == DHCPV6_OPTION_DNS_SERVERS && (length >= 16 && ((length % 16) == 0))) { + valid_optional_options = true; + dhcp_option.option.generic.data = ptr; + dhcp_option.option.generic.data_length = length; + } else if (type == DHCPV6_OPTION_DOMAIN_LIST) { + valid_optional_options = true; + dhcp_option.option.generic.data = ptr; + dhcp_option.option.generic.data_length = length; + } + if (valid_optional_options) { + dhcp_option.option_type = type; + dhcp_client->option_information_cb(dhcp_client->interface, &dhcp_option, &server_info); + } + data_len -= length; + ptr += length; + } +} + /* solication responce received for either global address or routter id assignment */ int dhcp_solicit_resp_cb(uint16_t instance_id, void *ptr, uint8_t msg_name, uint8_t *msg_ptr, uint16_t msg_len) { @@ -310,6 +383,10 @@ int dhcp_solicit_resp_cb(uint16_t instance_id, void *ptr, uint8_t msg_name, uin 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); } + + //Optional Options notify from Reply + dhcp_vendor_information_notify(msg_ptr, msg_len, dhcp_client, srv_data_ptr); + return RET_MSG_ACCEPTED; error_exit: dhcpv6_client_send_error_cb(srv_data_ptr); diff --git a/connectivity/nanostack/sal-stack-nanostack/source/MAC/IEEE802_15_4/mac_defines.h b/connectivity/nanostack/sal-stack-nanostack/source/MAC/IEEE802_15_4/mac_defines.h index 5052ad5d4ea..26f51cd520c 100644 --- a/connectivity/nanostack/sal-stack-nanostack/source/MAC/IEEE802_15_4/mac_defines.h +++ b/connectivity/nanostack/sal-stack-nanostack/source/MAC/IEEE802_15_4/mac_defines.h @@ -204,7 +204,6 @@ typedef struct protocol_interface_rf_mac_setup { bool macBroadcastDisabled: 1; bool scan_active: 1; bool rf_csma_extension_supported: 1; - bool ack_tx_possible: 1; uint16_t mac_short_address; uint16_t pan_id; uint8_t mac64[8]; diff --git a/connectivity/nanostack/sal-stack-nanostack/source/MAC/IEEE802_15_4/mac_mcps_sap.c b/connectivity/nanostack/sal-stack-nanostack/source/MAC/IEEE802_15_4/mac_mcps_sap.c index 22b8061c881..2a814d3fd0e 100644 --- a/connectivity/nanostack/sal-stack-nanostack/source/MAC/IEEE802_15_4/mac_mcps_sap.c +++ b/connectivity/nanostack/sal-stack-nanostack/source/MAC/IEEE802_15_4/mac_mcps_sap.c @@ -1883,6 +1883,9 @@ int8_t mcps_generic_ack_build(protocol_interface_rf_mac_setup_s *rf_ptr, bool in //Remember to update security counter here! key_desc = mac_frame_security_key_get(rf_ptr, buffer); if (!key_desc) { +#ifdef __linux__ + tr_debug("Drop a ACK missing key desc"); +#endif buffer->status = MLME_UNAVAILABLE_KEY; return -2; } @@ -1890,6 +1893,9 @@ int8_t mcps_generic_ack_build(protocol_interface_rf_mac_setup_s *rf_ptr, bool in buffer->aux_header.frameCounter = mac_sec_mib_key_outgoing_frame_counter_get(rf_ptr, key_desc); } if (!mac_frame_security_parameters_init(&ccm_ptr, rf_ptr, buffer, key_desc)) { +#ifdef __linux__ + tr_debug("Drop a ACK ignored by security init"); +#endif return -2; } if (init_build) { @@ -1921,6 +1927,9 @@ int8_t mcps_generic_ack_build(protocol_interface_rf_mac_setup_s *rf_ptr, bool in mac_sec_mib_key_outgoing_frame_counter_decrement(rf_ptr, key_desc); ccm_free(&ccm_ptr); } +#ifdef __linux__ + tr_debug("Drop a ACK send by frame too long %u", frame_length); +#endif return -1; } @@ -1932,7 +1941,7 @@ int8_t mcps_generic_ack_build(protocol_interface_rf_mac_setup_s *rf_ptr, bool in tx_buf->ack_len = frame_length; uint8_t *mhr_start = ptr; - buffer->tx_time = mac_mcps_sap_get_phy_timestamp(rf_ptr) + 300; //Send 300 us later + buffer->tx_time = mac_mcps_sap_get_phy_timestamp(rf_ptr) + 1000; // 1ms delay before Ack ptr = mac_generic_packet_write(rf_ptr, ptr, buffer); @@ -2092,6 +2101,11 @@ static int8_t mcps_pd_data_cca_trig(protocol_interface_rf_mac_setup_s *rf_ptr, m if (rf_ptr->active_pd_data_request) { mac_csma_backoff_start(rf_ptr); } +#ifdef __linux__ + if (buffer->fcf_dsn.frametype == MAC_FRAME_ACK) { + tr_debug("Drop ACK by CCA request"); + } +#endif platform_exit_critical(); return -1; } diff --git a/connectivity/nanostack/sal-stack-nanostack/source/MAC/IEEE802_15_4/mac_mlme.c b/connectivity/nanostack/sal-stack-nanostack/source/MAC/IEEE802_15_4/mac_mlme.c index e1e2e4d3438..8229e29f3f3 100644 --- a/connectivity/nanostack/sal-stack-nanostack/source/MAC/IEEE802_15_4/mac_mlme.c +++ b/connectivity/nanostack/sal-stack-nanostack/source/MAC/IEEE802_15_4/mac_mlme.c @@ -673,50 +673,13 @@ static int8_t mac_mlme_set_ack_wait_duration(protocol_interface_rf_mac_setup_s * return 0; } -static void mac_mlme_trig_pending_ack(protocol_interface_rf_mac_setup_s *rf_mac_setup, mlme_device_descriptor_t *device_ptr) -{ - platform_enter_critical(); - if (rf_mac_setup->mac_ack_tx_active && !rf_mac_setup->ack_tx_possible && - device_ptr->PANId == rf_mac_setup->enhanced_ack_buffer.DstPANId) { - - //Compare address for pending neigbour add - if (rf_mac_setup->enhanced_ack_buffer.fcf_dsn.DstAddrMode == MAC_ADDR_MODE_16_BIT) { - uint16_t short_id = common_read_16_bit(rf_mac_setup->enhanced_ack_buffer.DstAddr); - if (short_id == device_ptr->ShortAddress) { - rf_mac_setup->ack_tx_possible = true; - } - } else if (rf_mac_setup->enhanced_ack_buffer.fcf_dsn.DstAddrMode == MAC_ADDR_MODE_64_BIT) { - if (memcmp(device_ptr->ExtAddress, rf_mac_setup->enhanced_ack_buffer.DstAddr, 8) == 0) { - rf_mac_setup->ack_tx_possible = true; - } - } - } - platform_exit_critical(); -} - static int8_t mac_mlme_device_description_set(protocol_interface_rf_mac_setup_s *rf_mac_setup, const mlme_set_t *set_req) { if (set_req->value_size != sizeof(mlme_device_descriptor_t)) { return -1; } - if (mac_sec_mib_device_description_set(set_req->attr_index, (mlme_device_descriptor_t *) set_req->value_pointer, rf_mac_setup) != 0) { - return -1; - } - - mac_mlme_trig_pending_ack(rf_mac_setup, (mlme_device_descriptor_t *) set_req->value_pointer); - return 0; -} - -static int8_t mac_mlme_device_pending_ack_trig(protocol_interface_rf_mac_setup_s *rf_mac_setup, const mlme_set_t *set_req) -{ - - if (set_req->value_size != sizeof(mlme_device_descriptor_t)) { - return -1; - } - mac_mlme_trig_pending_ack(rf_mac_setup, (mlme_device_descriptor_t *) set_req->value_pointer); - - return 0; + return mac_sec_mib_device_description_set(set_req->attr_index, (mlme_device_descriptor_t *) set_req->value_pointer, rf_mac_setup); } static int8_t mac_mlme_key_description_set(protocol_interface_rf_mac_setup_s *rf_mac_setup, const mlme_set_t *set_req) @@ -795,8 +758,6 @@ int8_t mac_mlme_set_req(protocol_interface_rf_mac_setup_s *rf_mac_setup, const m return mac_mlme_set_ack_wait_duration(rf_mac_setup, set_req); case macDeviceTable: return mac_mlme_device_description_set(rf_mac_setup, set_req); - case macDevicePendingAckTrig: - return mac_mlme_device_pending_ack_trig(rf_mac_setup, set_req); case macKeyTable: return mac_mlme_key_description_set(rf_mac_setup, set_req); case macDefaultKeySource: @@ -1659,6 +1620,7 @@ int8_t mac_mlme_rf_channel_change(protocol_interface_rf_mac_setup_s *rf_mac_setu if (new_channel == rf_mac_setup->mac_channel) { return 0; } + platform_enter_critical(); if (rf_mac_setup->dev_driver->phy_driver->extension(PHY_EXTENSION_SET_CHANNEL, &new_channel) == 0) { rf_mac_setup->mac_channel = new_channel; diff --git a/connectivity/nanostack/sal-stack-nanostack/source/MAC/IEEE802_15_4/mac_pd_sap.c b/connectivity/nanostack/sal-stack-nanostack/source/MAC/IEEE802_15_4/mac_pd_sap.c index 799205ceb0e..6b36a7f7d69 100644 --- a/connectivity/nanostack/sal-stack-nanostack/source/MAC/IEEE802_15_4/mac_pd_sap.c +++ b/connectivity/nanostack/sal-stack-nanostack/source/MAC/IEEE802_15_4/mac_pd_sap.c @@ -453,37 +453,18 @@ static int8_t mac_data_interface_tx_done_cb(protocol_interface_rf_mac_setup_s *r if (status == PHY_LINK_CCA_PREPARE) { - if (rf_ptr->mac_ack_tx_active) { - //Accept direct non crypted acks and crypted only if neighbor is at list - if (rf_ptr->ack_tx_possible) { -#ifdef TIMING_TOOL_TRACES - tr_info("%u TX_start %u", mac_mcps_sap_get_phy_timestamp(rf_ptr), rf_ptr->mac_channel); -#endif - return PHY_TX_ALLOWED; - } - - //Compare time to started time - if (mac_mcps_sap_get_phy_timestamp(rf_ptr) - rf_ptr->enhanced_ack_handler_timestamp > ENHANCED_ACK_NEIGHBOUR_POLL_MAX_TIME_US || mcps_generic_ack_build(rf_ptr, false) != 0) { - mac_data_ack_tx_finish(rf_ptr); - } - - return PHY_TX_NOT_ALLOWED; - } - if (rf_ptr->mac_edfe_tx_active) { - return PHY_TX_ALLOWED; + if (rf_ptr->mac_ack_tx_active || rf_ptr->mac_edfe_tx_active) { + goto VALIDATE_TX_TIME; } if (mac_data_asynch_channel_switch(rf_ptr, rf_ptr->active_pd_data_request)) { -#ifdef TIMING_TOOL_TRACES - tr_info("%u TX_start %u", mac_mcps_sap_get_phy_timestamp(rf_ptr), rf_ptr->mac_channel); -#endif rf_ptr->active_pd_data_request->initial_tx_channel = rf_ptr->mac_channel; int8_t channel_cca_threshold = mac_cca_thr_get_dbm(rf_ptr, rf_ptr->mac_channel); if (CCA_FAILED_DBM != channel_cca_threshold) { rf_ptr->dev_driver->phy_driver->extension(PHY_EXTENSION_SET_CHANNEL_CCA_THRESHOLD, (uint8_t *)&channel_cca_threshold); } - return PHY_TX_ALLOWED; + goto VALIDATE_TX_TIME; } if (rf_ptr->fhss_api) { @@ -525,10 +506,19 @@ static int8_t mac_data_interface_tx_done_cb(protocol_interface_rf_mac_setup_s *r return PHY_RESTART_CSMA; } } +VALIDATE_TX_TIME: + if (rf_ptr->active_pd_data_request && rf_ptr->active_pd_data_request->tx_time && !rf_ptr->mac_ack_tx_active && !rf_ptr->mac_edfe_tx_active) { + int32_t tx_time_error_us = mac_mcps_sap_get_phy_timestamp(rf_ptr) - rf_ptr->active_pd_data_request->tx_time; + // Positive error means that TX is too late. Do not allow transmit if transmission is delayed over 5ms + if (tx_time_error_us > 5000) { + mac_sap_cca_fail_cb(rf_ptr, 0xffff); + return PHY_TX_NOT_ALLOWED; + } + } #ifdef TIMING_TOOL_TRACES tr_info("%u TX_start %u", mac_mcps_sap_get_phy_timestamp(rf_ptr), rf_ptr->mac_channel); #endif - return 0; + return PHY_TX_ALLOWED; } if (rf_ptr->mac_ack_tx_active) { @@ -851,6 +841,9 @@ static int8_t mac_pd_sap_generate_ack(protocol_interface_rf_mac_setup_s *rf_ptr, return 0; } if (rf_ptr->mac_ack_tx_active) { +#ifdef __linux__ + tr_debug("Drop a New ack by pending request"); +#endif return -1; } @@ -863,18 +856,6 @@ static int8_t mac_pd_sap_generate_ack(protocol_interface_rf_mac_setup_s *rf_ptr, return -1; } - - if (rf_ptr->enhanced_ack_buffer.fcf_dsn.securityEnabled == 0 || rf_ptr->enhanced_ack_buffer.aux_header.securityLevel == 0) { - //Unsecured data will be acked immediately - rf_ptr->ack_tx_possible = true; - } else { - if (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; - } - } - return mcps_generic_ack_build(rf_ptr, true); } @@ -909,11 +890,17 @@ static mac_pre_parsed_frame_t *mac_pd_sap_allocate_receive_buffer(protocol_inter if (fcf_read->frametype != FC_ACK_FRAME) { if (!ns_monitor_packet_allocation_allowed()) { // stack can not handle new packets for routing +#ifdef __linux__ + tr_debug("Packet ingress drop buffer allocation"); +#endif return NULL; } } mac_pre_parsed_frame_t *buffer = mcps_sap_pre_parsed_frame_buffer_get(pd_data_ind->data_ptr, pd_data_ind->data_len); if (!buffer) { +#ifdef __linux__ + tr_debug("macPD buffer allocate fail %u", pd_data_ind->data_len); +#endif return NULL; } //Copy Pre Parsed values @@ -1004,6 +991,9 @@ int8_t mac_pd_sap_data_cb(void *identifier, arm_phy_sap_msg_t *message) arm_pd_sap_generic_ind_t *pd_data_ind = &(message->message.generic_data_ind); mac_pre_parsed_frame_t *buffer = NULL; if (pd_data_ind->data_len == 0) { +#ifdef TIMING_TOOL_TRACES + tr_info("Collission at RF?"); +#endif goto ERROR_HANDLER; } @@ -1027,9 +1017,13 @@ int8_t mac_pd_sap_data_cb(void *identifier, arm_phy_sap_msg_t *message) goto ERROR_HANDLER; } if (!mac_pd_sap_rx_filter(pd_data_ind->data_ptr, &fcf_read, rf_ptr->mac_frame_filters, rf_ptr->mac64, rf_ptr->mac_short_address, rf_ptr->pan_id)) { + pd_data_ind->data_len = 0; // Do not update RX drop in that case goto ERROR_HANDLER; } if (mac_pd_sap_generate_ack(rf_ptr, &fcf_read, pd_data_ind)) { +#ifdef __linux__ + tr_debug("Drop a Data by ignored ACK generation"); +#endif goto ERROR_HANDLER; } if (buffer) { diff --git a/connectivity/nanostack/sal-stack-nanostack/source/NWK_INTERFACE/protocol_core.c b/connectivity/nanostack/sal-stack-nanostack/source/NWK_INTERFACE/protocol_core.c index 279bc7f0df6..168293a4b78 100644 --- a/connectivity/nanostack/sal-stack-nanostack/source/NWK_INTERFACE/protocol_core.c +++ b/connectivity/nanostack/sal-stack-nanostack/source/NWK_INTERFACE/protocol_core.c @@ -83,6 +83,7 @@ #include "Service_Libs/load_balance/load_balance_api.h" #include "Service_Libs/pan_blacklist/pan_blacklist_api.h" #include "Service_Libs/etx/etx.h" +#include "libNET/src/net_dns_internal.h" #include "mac_api.h" #include "ethernet_mac_api.h" @@ -304,6 +305,8 @@ void core_timer_event_handle(uint16_t ticksUpdate) ipv6_destination_cache_timer(seconds); ipv6_frag_timer(seconds); cipv6_frag_timer(seconds); + net_dns_timer_seconds(seconds); + #ifdef HAVE_WS ws_pae_controller_slow_timer(seconds); #endif diff --git a/connectivity/nanostack/sal-stack-nanostack/source/Security/kmp/kmp_api.c b/connectivity/nanostack/sal-stack-nanostack/source/Security/kmp/kmp_api.c index e175d9a851f..19be4a7f7a3 100644 --- a/connectivity/nanostack/sal-stack-nanostack/source/Security/kmp/kmp_api.c +++ b/connectivity/nanostack/sal-stack-nanostack/source/Security/kmp/kmp_api.c @@ -64,6 +64,7 @@ typedef NS_LIST_HEAD(kmp_sec_prot_entry_t, link) kmp_sec_prot_list_t; typedef struct { uint8_t instance_id; /**< Message interface instance identifier */ uint8_t header_size; /**< Message interface header size */ + uint8_t number_of_conn; /**< Message interface number of connections */ kmp_service_msg_if_send *send; /**< Message interface callback to send KMP frames */ ns_list_link_t link; /**< Link */ } kmp_msg_if_entry_t; @@ -71,17 +72,19 @@ typedef struct { typedef NS_LIST_HEAD(kmp_msg_if_entry_t, link) kmp_msg_if_list_t; struct kmp_service_s { - kmp_sec_prot_list_t sec_prot_list; /**< Security protocols list */ - kmp_msg_if_list_t msg_if_list; /**< Message interface 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_ip_addr_get *ip_addr_get; /**< Callback to get IP addresses related to KMP */ - kmp_service_api_get *api_get; /**< Callback to get KMP API from a service */ - kmp_service_timer_if_start *timer_start; /**< Callback to start timer */ - kmp_service_timer_if_stop *timer_stop; /**< Callback to stop timer */ - kmp_service_event_if_event_send *event_send; /**< Callback to send event */ - ns_list_link_t link; /**< Link */ + kmp_sec_prot_list_t sec_prot_list; /**< Security protocols list */ + kmp_msg_if_list_t msg_if_list; /**< Message interface 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_ip_addr_get *ip_addr_get; /**< Callback to get IP addresses related to KMP */ + kmp_service_api_get *api_get; /**< Callback to get KMP API from a service */ + kmp_service_timer_if_start *timer_start; /**< Callback to start timer */ + kmp_service_timer_if_stop *timer_stop; /**< Callback to stop timer */ + kmp_service_event_if_event_send *event_send; /**< Callback to send event */ + kmp_service_shared_comp_add *shared_comp_add; /**< Callback to shared component add */ + kmp_service_shared_comp_remove *shared_comp_remove; /**< Callback to shared component remove */ + ns_list_link_t link; /**< Link */ }; typedef struct { @@ -100,8 +103,11 @@ 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); static void kmp_api_sec_prot_finished(sec_prot_t *prot); static int8_t kmp_sec_prot_send(sec_prot_t *prot, void *pdu, uint16_t size); +static int8_t kmp_sec_prot_conn_send(sec_prot_t *prot, void *pdu, uint16_t size, uint8_t conn_number, uint8_t flags); static void kmp_sec_prot_timer_start(sec_prot_t *prot); static void kmp_sec_prot_timer_stop(sec_prot_t *prot); +static int8_t kmp_sec_prot_shared_comp_add(sec_prot_t *prot, shared_comp_data_t *data); +static int8_t kmp_sec_prot_shared_comp_remove(sec_prot_t *prot, shared_comp_data_t *data); static void kmp_sec_prot_state_machine_call(sec_prot_t *prot); static void kmp_sec_prot_eui64_addr_get(sec_prot_t *prot, uint8_t *local_eui64, uint8_t *remote_eui64); static void kmp_sec_prot_ip_addr_get(sec_prot_t *prot, uint8_t *address); @@ -157,13 +163,17 @@ kmp_api_t *kmp_api_create(kmp_service_t *service, kmp_type_e type, uint8_t msg_i kmp->sec_prot.header_size = msg_if_entry->header_size; kmp->sec_prot.receive_peer_hdr_size = msg_if_entry->header_size; + kmp->sec_prot.number_of_conn = msg_if_entry->number_of_conn; kmp->sec_prot.create_conf = kmp_api_sec_prot_create_confirm; kmp->sec_prot.create_ind = kmp_api_sec_prot_create_indication; kmp->sec_prot.finished_ind = kmp_api_sec_prot_finished_indication; kmp->sec_prot.finished = kmp_api_sec_prot_finished; kmp->sec_prot.send = kmp_sec_prot_send; + kmp->sec_prot.conn_send = kmp_sec_prot_conn_send; kmp->sec_prot.timer_start = kmp_sec_prot_timer_start; kmp->sec_prot.timer_stop = kmp_sec_prot_timer_stop; + kmp->sec_prot.shared_comp_add = kmp_sec_prot_shared_comp_add; + kmp->sec_prot.shared_comp_remove = kmp_sec_prot_shared_comp_remove; kmp->sec_prot.state_machine_call = kmp_sec_prot_state_machine_call; kmp->sec_prot.addr_get = kmp_sec_prot_eui64_addr_get; kmp->sec_prot.ip_addr_get = kmp_sec_prot_ip_addr_get; @@ -237,6 +247,11 @@ static void kmp_api_sec_prot_finished(sec_prot_t *prot) } static int8_t kmp_sec_prot_send(sec_prot_t *prot, void *pdu, uint16_t size) +{ + return kmp_sec_prot_conn_send(prot, pdu, size, 0, 0); +} + +static int8_t kmp_sec_prot_conn_send(sec_prot_t *prot, void *pdu, uint16_t size, uint8_t conn_number, uint8_t flags) { kmp_api_t *kmp = kmp_api_get_from_prot(prot); @@ -256,7 +271,7 @@ static int8_t kmp_sec_prot_send(sec_prot_t *prot, void *pdu, uint16_t size) int8_t result = -1; if (msg_if_entry->send) { - result = msg_if_entry->send(kmp->service, prot->msg_if_instance_id, kmp_id, kmp->addr, pdu, size, kmp->instance_identifier); + result = msg_if_entry->send(kmp->service, prot->msg_if_instance_id, kmp_id, kmp->addr, pdu, size, kmp->instance_identifier, conn_number, flags); } if (result < 0) { @@ -269,6 +284,7 @@ static int8_t kmp_sec_prot_send(sec_prot_t *prot, void *pdu, uint16_t size) static void kmp_sec_prot_timer_start(sec_prot_t *prot) { kmp_api_t *kmp = kmp_api_get_from_prot(prot); + kmp->timer_start_pending = false; if (kmp->service->timer_start(kmp->service, kmp) < 0) { kmp->timer_start_pending = true; @@ -278,10 +294,33 @@ static void kmp_sec_prot_timer_start(sec_prot_t *prot) static void kmp_sec_prot_timer_stop(sec_prot_t *prot) { kmp_api_t *kmp = kmp_api_get_from_prot(prot); + kmp->service->timer_stop(kmp->service, kmp); kmp->timer_start_pending = false; } +static int8_t kmp_sec_prot_shared_comp_add(sec_prot_t *prot, shared_comp_data_t *data) +{ + kmp_api_t *kmp = kmp_api_get_from_prot(prot); + + if (kmp->service->shared_comp_add == NULL) { + return -1; + } + kmp->service->shared_comp_add(kmp->service, (kmp_shared_comp_t *) data); + return 0; +} + +static int8_t kmp_sec_prot_shared_comp_remove(sec_prot_t *prot, shared_comp_data_t *data) +{ + kmp_api_t *kmp = kmp_api_get_from_prot(prot); + + if (kmp->service->shared_comp_add == NULL) { + return -1; + } + kmp->service->shared_comp_remove(kmp->service, (kmp_shared_comp_t *) data); + return 0; +} + static void kmp_sec_prot_eui64_addr_get(sec_prot_t *prot, uint8_t *local_eui64, uint8_t *remote_eui64) { kmp_api_t *kmp = kmp_api_get_from_prot(prot); @@ -444,6 +483,8 @@ kmp_service_t *kmp_service_create(void) service->tx_status_ind = 0; service->addr_get = 0; service->api_get = 0; + service->shared_comp_add = NULL; + service->shared_comp_remove = NULL; ns_list_add_to_start(&kmp_service_list, service); @@ -496,7 +537,7 @@ int8_t kmp_service_cb_register(kmp_service_t *service, kmp_service_incoming_ind return 0; } -int8_t kmp_service_msg_if_register(kmp_service_t *service, uint8_t instance_id, kmp_service_msg_if_send *send, uint8_t header_size) +int8_t kmp_service_msg_if_register(kmp_service_t *service, uint8_t instance_id, kmp_service_msg_if_send *send, uint8_t header_size, uint8_t number_of_conn) { if (!service) { return -1; @@ -533,11 +574,12 @@ int8_t kmp_service_msg_if_register(kmp_service_t *service, uint8_t instance_id, entry->instance_id = instance_id; entry->send = send; entry->header_size = header_size; + entry->number_of_conn = number_of_conn; return 0; } -int8_t kmp_service_msg_if_receive(kmp_service_t *service, uint8_t instance_id, kmp_type_e type, const kmp_addr_t *addr, void *pdu, uint16_t size) +int8_t kmp_service_msg_if_receive(kmp_service_t *service, uint8_t instance_id, kmp_type_e type, const kmp_addr_t *addr, void *pdu, uint16_t size, uint8_t connection_num) { if (!service) { return -1; @@ -553,7 +595,14 @@ int8_t kmp_service_msg_if_receive(kmp_service_t *service, uint8_t instance_id, k return -1; } - int8_t ret = kmp->sec_prot.receive(&kmp->sec_prot, pdu, size); + int8_t ret = -1; + if (kmp->sec_prot.receive != NULL) { + ret = kmp->sec_prot.receive(&kmp->sec_prot, pdu, size); + } + if (kmp->sec_prot.conn_receive != NULL) { + ret = kmp->sec_prot.conn_receive(&kmp->sec_prot, pdu, size, connection_num); + } + return ret; } @@ -642,6 +691,17 @@ int8_t kmp_service_timer_if_register(kmp_service_t *service, kmp_service_timer_i return 0; } +int8_t kmp_service_shared_comp_if_register(kmp_service_t *service, kmp_service_shared_comp_add add, kmp_service_shared_comp_remove remove) +{ + if (!service) { + return -1; + } + + service->shared_comp_add = add; + service->shared_comp_remove = remove; + return 0; +} + void kmp_service_event_if_event(kmp_service_t *service, void *data) { (void) service; diff --git a/connectivity/nanostack/sal-stack-nanostack/source/Security/kmp/kmp_api.h b/connectivity/nanostack/sal-stack-nanostack/source/Security/kmp/kmp_api.h index f51a1405886..fa945eb4805 100644 --- a/connectivity/nanostack/sal-stack-nanostack/source/Security/kmp/kmp_api.h +++ b/connectivity/nanostack/sal-stack-nanostack/source/Security/kmp/kmp_api.h @@ -59,6 +59,9 @@ typedef enum { KMP_TX_ERR_UNSPEC = -2, // Other reason } kmp_tx_status_e; +// On message interface send, do not deallocate pdu buffer +#define MSG_IF_SEND_FLAG_NO_DEALLOC 0x01 + typedef void kmp_sec_keys_t; typedef struct sec_prot_s sec_prot_t; typedef struct kmp_api_s kmp_api_t; @@ -367,12 +370,13 @@ int8_t kmp_service_cb_register(kmp_service_t *service, kmp_service_incoming_ind * \param addr address * \param pdu pdu * \param size pdu size + * \param conn_number connection number (0 for default) * * \return < 0 failure * \return >= 0 success * */ -int8_t kmp_service_msg_if_receive(kmp_service_t *service, uint8_t instance_id, kmp_type_e kmp_id, const kmp_addr_t *addr, void *pdu, uint16_t size); +int8_t kmp_service_msg_if_receive(kmp_service_t *service, uint8_t instance_id, kmp_type_e kmp_id, const kmp_addr_t *addr, void *pdu, uint16_t size, uint8_t conn_number); /** * kmp_service_msg_if_send send a message @@ -384,12 +388,14 @@ int8_t kmp_service_msg_if_receive(kmp_service_t *service, uint8_t instance_id, k * \param pdu pdu * \param size pdu size * \param tx_identifier TX identifier + * \param conn_number connection number (0 for default) + * \param flags flags * * \return < 0 failure * \return >= 0 success * */ -typedef int8_t kmp_service_msg_if_send(kmp_service_t *service, uint8_t instance_id, kmp_type_e type, const kmp_addr_t *addr, void *pdu, uint16_t size, uint8_t tx_identifier); +typedef int8_t kmp_service_msg_if_send(kmp_service_t *service, uint8_t instance_id, kmp_type_e type, const kmp_addr_t *addr, void *pdu, uint16_t size, uint8_t tx_identifier, uint8_t conn_number, uint8_t flags); /** * kmp_service_msg_if_register registers message interface @@ -398,12 +404,13 @@ typedef int8_t kmp_service_msg_if_send(kmp_service_t *service, uint8_t instance_ * \param instance_id message interface instance identifier * \param send KMP PDU send callback * \param header_size header size + * \param number_of_conn number of connections * * \return < 0 failure * \return >= 0 success * */ -int8_t kmp_service_msg_if_register(kmp_service_t *service, uint8_t instance_id, kmp_service_msg_if_send *send, uint8_t header_size); +int8_t kmp_service_msg_if_register(kmp_service_t *service, uint8_t instance_id, kmp_service_msg_if_send *send, uint8_t header_size, uint8_t number_of_conn); /** * kmp_service_tx_status tx status indication @@ -467,6 +474,7 @@ int8_t kmp_service_sec_protocol_unregister(kmp_service_t *service, kmp_type_e ty * kmp_service_timer_if_timeout timer timeout * * \param service KMP instance + * \param ticks Ticks * */ void kmp_service_timer_if_timeout(kmp_api_t *kmp, uint16_t ticks); @@ -508,6 +516,68 @@ typedef int8_t kmp_service_timer_if_stop(kmp_service_t *service, kmp_api_t *kmp) */ int8_t kmp_service_timer_if_register(kmp_service_t *service, kmp_service_timer_if_start start, kmp_service_timer_if_stop stop); +/** + * kmp_service_shared_comp_timer_timeout shared component timer timeout + * + * \param ticks timer ticks + * + * \return < 0 failure + * \return >= 0 success + * + */ +typedef int8_t kmp_service_shared_comp_timer_timeout(uint16_t ticks); + +/** + * kmp_service_shared_comp_delete shared component delete + * + * \return < 0 failure + * \return >= 0 success + * + */ +typedef int8_t kmp_service_shared_comp_delete(void); + +typedef struct { + kmp_service_shared_comp_timer_timeout *timeout; + kmp_service_shared_comp_delete *delete; +} kmp_shared_comp_t; + +/** + * kmp_service_shared_comp_add add shared component + * + * \param service KMP service + * \param data shared component data + * + * \return < 0 failure + * \return >= 0 success + * + */ +typedef int8_t kmp_service_shared_comp_add(kmp_service_t *service, kmp_shared_comp_t *data); + +/** + * kmp_service_shared_comp_remove remove shared component + * + * \param service KMP service + * \param data shared component data + * + * \return < 0 failure + * \return >= 0 success + * + */ +typedef int8_t kmp_service_shared_comp_remove(kmp_service_t *service, kmp_shared_comp_t *data); + +/** + * kmp_service_shared_comp_if_register register a continuous timer interface to KMP service + * + * \param service KMP service + * \param add shared component + * \param remove remove shared component + * + * \return < 0 failure + * \return >= 0 success + * + */ +int8_t kmp_service_shared_comp_if_register(kmp_service_t *service, kmp_service_shared_comp_add add, kmp_service_shared_comp_remove remove); + /** * kmp_service_event_if_event event callback * diff --git a/connectivity/nanostack/sal-stack-nanostack/source/Security/kmp/kmp_eapol_pdu_if.c b/connectivity/nanostack/sal-stack-nanostack/source/Security/kmp/kmp_eapol_pdu_if.c index f12bc517b97..afcae84571b 100644 --- a/connectivity/nanostack/sal-stack-nanostack/source/Security/kmp/kmp_eapol_pdu_if.c +++ b/connectivity/nanostack/sal-stack-nanostack/source/Security/kmp/kmp_eapol_pdu_if.c @@ -49,7 +49,7 @@ 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, uint8_t instance_id, 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_send(kmp_service_t *service, uint8_t instance_id, kmp_type_e kmp_id, const kmp_addr_t *addr, void *pdu, uint16_t size, uint8_t tx_identifier, uint8_t conn_number, uint8_t flags); 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) @@ -72,7 +72,7 @@ int8_t kmp_eapol_pdu_if_register(kmp_service_t *service, protocol_interface_info eapol_pdu_if->kmp_service = service; eapol_pdu_if->interface_ptr = interface_ptr; - if (kmp_service_msg_if_register(service, 0, kmp_eapol_pdu_if_send, EAPOL_PDU_IF_HEADER_SIZE) < 0) { + if (kmp_service_msg_if_register(service, 0, kmp_eapol_pdu_if_send, EAPOL_PDU_IF_HEADER_SIZE, 0) < 0) { ns_dyn_mem_free(eapol_pdu_if); return -1; } @@ -92,17 +92,19 @@ int8_t kmp_eapol_pdu_if_unregister(kmp_service_t *service) if (entry->kmp_service == service) { ns_list_remove(&kmp_eapol_pdu_if_list, entry); ns_dyn_mem_free(entry); - kmp_service_msg_if_register(service, 0, NULL, 0); + kmp_service_msg_if_register(service, 0, NULL, 0, 0); } } return 0; } -static int8_t kmp_eapol_pdu_if_send(kmp_service_t *service, uint8_t instance_id, 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_send(kmp_service_t *service, uint8_t instance_id, kmp_type_e kmp_id, const kmp_addr_t *addr, void *pdu, uint16_t size, uint8_t tx_identifier, uint8_t conn_number, uint8_t flags) { (void) instance_id; // Only one instance of eapol interface possible + (void) conn_number; // Only one connection of eapol interface possible - if (!service || !addr || !pdu) { + // No flags supported + if (!service || !addr || !pdu || flags) { return -1; } @@ -159,7 +161,7 @@ int8_t kmp_eapol_pdu_if_receive(protocol_interface_info_entry_t *interface_ptr, return -1; } - int8_t ret = kmp_service_msg_if_receive(service, 0, type, &addr, data_pdu, data_pdu_size); + int8_t ret = kmp_service_msg_if_receive(service, 0, type, &addr, data_pdu, data_pdu_size, 0); return ret; } diff --git a/connectivity/nanostack/sal-stack-nanostack/source/Security/kmp/kmp_socket_if.c b/connectivity/nanostack/sal-stack-nanostack/source/Security/kmp/kmp_socket_if.c index 66c78b10392..6197e4304d2 100644 --- a/connectivity/nanostack/sal-stack-nanostack/source/Security/kmp/kmp_socket_if.c +++ b/connectivity/nanostack/sal-stack-nanostack/source/Security/kmp/kmp_socket_if.c @@ -39,19 +39,20 @@ #define TRACE_GROUP "kmsi" -#define SOCKET_IF_HEADER_SIZE 27 +#define SOCKET_IF_HEADER_SIZE 27 +#define INSTANCE_SOCKETS_NUMBER 3 typedef struct { kmp_service_t *kmp_service; /**< KMP service */ uint8_t instance_id; /**< Instance identifier */ bool relay; /**< Interface is relay interface */ ns_address_t remote_addr; /**< Remote address */ - int8_t socket_id; /**< Socket ID */ - bool socket_id_set; /**< Socket ID is set */ + int8_t socket_id[INSTANCE_SOCKETS_NUMBER]; /**< Socket ID */ + unsigned socket_id_in_use : 4; /**< Socket ID is in use */ ns_list_link_t link; /**< Link */ } kmp_socket_if_t; -static int8_t kmp_socket_if_send(kmp_service_t *service, uint8_t instance_id, kmp_type_e kmp_id, const kmp_addr_t *addr, void *pdu, uint16_t size, uint8_t tx_identifier); +static int8_t kmp_socket_if_send(kmp_service_t *service, uint8_t instance_id, kmp_type_e kmp_id, const kmp_addr_t *addr, void *pdu, uint16_t size, uint8_t tx_identifier, uint8_t connection_num, uint8_t flags); static void kmp_socket_if_socket_cb(void *ptr); static NS_LIST_DEFINE(kmp_socket_if_list, kmp_socket_if_t, link); @@ -78,7 +79,10 @@ int8_t kmp_socket_if_register(kmp_service_t *service, uint8_t *instance_id, bool return -1; } memset(socket_if, 0, sizeof(kmp_socket_if_t)); - socket_if->socket_id = -1; + for (uint8_t socket_num = 0; socket_num < INSTANCE_SOCKETS_NUMBER; socket_num++) { + socket_if->socket_id[socket_num] = -1; + } + socket_if->socket_id_in_use = 1; new_socket_if_allocated = true; } @@ -87,7 +91,7 @@ int8_t kmp_socket_if_register(kmp_service_t *service, uint8_t *instance_id, bool if (*instance_id == 0) { socket_if->instance_id = kmp_socket_if_instance_id++; if (socket_if->instance_id == 0) { - socket_if->instance_id++; + socket_if->instance_id = kmp_socket_if_instance_id++; } *instance_id = socket_if->instance_id; } @@ -104,14 +108,19 @@ int8_t kmp_socket_if_register(kmp_service_t *service, uint8_t *instance_id, bool memcpy(&socket_if->remote_addr.address, remote_addr, 16); socket_if->remote_addr.identifier = remote_port; - if (socket_if->socket_id < 0 || address_changed) { - if (socket_if->socket_id >= 0) { - socket_close(socket_if->socket_id); - } - socket_if->socket_id = socket_open(IPV6_NH_UDP, local_port, &kmp_socket_if_socket_cb); - if (socket_if->socket_id < 0) { - ns_dyn_mem_free(socket_if); - return -1; + for (uint8_t socket_num = 0; socket_num < INSTANCE_SOCKETS_NUMBER; socket_num++) { + if (socket_if->socket_id_in_use & (1 << socket_num)) { + + if ((socket_if->socket_id[socket_num] < 1) || address_changed) { + if (socket_if->socket_id[socket_num] >= 0) { + socket_close(socket_if->socket_id[socket_num]); + } + socket_if->socket_id[socket_num] = socket_open(IPV6_NH_UDP, local_port, &kmp_socket_if_socket_cb); + if (socket_if->socket_id[socket_num] < 0) { + ns_dyn_mem_free(socket_if); + return -1; + } + } } } @@ -120,7 +129,12 @@ int8_t kmp_socket_if_register(kmp_service_t *service, uint8_t *instance_id, bool header_size = SOCKET_IF_HEADER_SIZE; } - if (kmp_service_msg_if_register(service, *instance_id, kmp_socket_if_send, header_size) < 0) { + if (kmp_service_msg_if_register(service, *instance_id, kmp_socket_if_send, header_size, INSTANCE_SOCKETS_NUMBER) < 0) { + for (uint8_t socket_num = 0; socket_num < INSTANCE_SOCKETS_NUMBER; socket_num++) { + if (socket_if->socket_id[socket_num] >= 0) { + socket_close(socket_if->socket_id[socket_num]); + } + } ns_dyn_mem_free(socket_if); return -1; } @@ -141,15 +155,19 @@ int8_t kmp_socket_if_unregister(kmp_service_t *service) ns_list_foreach_safe(kmp_socket_if_t, entry, &kmp_socket_if_list) { if (entry->kmp_service == service) { ns_list_remove(&kmp_socket_if_list, entry); - socket_close(entry->socket_id); - kmp_service_msg_if_register(service, entry->instance_id, NULL, 0); + for (uint8_t socket_num = 0; socket_num < INSTANCE_SOCKETS_NUMBER; socket_num++) { + if (entry->socket_id[socket_num] >= 0) { + socket_close(entry->socket_id[socket_num]); + } + } + kmp_service_msg_if_register(service, entry->instance_id, NULL, 0, 0); ns_dyn_mem_free(entry); } } return 0; } -static int8_t kmp_socket_if_send(kmp_service_t *service, uint8_t instance_id, kmp_type_e kmp_id, const kmp_addr_t *addr, void *pdu, uint16_t size, uint8_t tx_identifier) +static int8_t kmp_socket_if_send(kmp_service_t *service, uint8_t instance_id, kmp_type_e kmp_id, const kmp_addr_t *addr, void *pdu, uint16_t size, uint8_t tx_identifier, uint8_t connection_num, uint8_t flags) { (void) tx_identifier; @@ -157,6 +175,10 @@ static int8_t kmp_socket_if_send(kmp_service_t *service, uint8_t instance_id, km return -1; } + if (connection_num >= INSTANCE_SOCKETS_NUMBER) { + return -1; + } + kmp_socket_if_t *socket_if = NULL; ns_list_foreach(kmp_socket_if_t, entry, &kmp_socket_if_list) { @@ -181,7 +203,26 @@ static int8_t kmp_socket_if_send(kmp_service_t *service, uint8_t instance_id, km *ptr = kmp_id; } - socket_sendto(socket_if->socket_id, &socket_if->remote_addr, pdu, size); + int8_t socket_id = -1; + if ((socket_if->socket_id_in_use & (1 << connection_num)) && socket_if->socket_id[connection_num] >= 0) { + socket_id = socket_if->socket_id[connection_num]; + } else { + if (socket_if->socket_id[connection_num] < 0) { + socket_if->socket_id[connection_num] = socket_open(IPV6_NH_UDP, 0, &kmp_socket_if_socket_cb); + } + if (socket_if->socket_id[connection_num] < 0) { + return -1; + } + socket_if->socket_id_in_use |= (1 << connection_num); + } + + socket_sendto(socket_id, &socket_if->remote_addr, pdu, size); + + // Deallocate unless flags deny it + if (flags & MSG_IF_SEND_FLAG_NO_DEALLOC) { + return 0; + } + ns_dyn_mem_free(pdu); return 0; @@ -196,11 +237,15 @@ static void kmp_socket_if_socket_cb(void *ptr) } kmp_socket_if_t *socket_if = NULL; + uint8_t connection_num = 0; ns_list_foreach(kmp_socket_if_t, entry, &kmp_socket_if_list) { - if (entry->socket_id == cb_data->socket_id) { - socket_if = entry; - break; + for (uint8_t socket_num = 0; socket_num < INSTANCE_SOCKETS_NUMBER; socket_num++) { + if (entry->socket_id[socket_num] == cb_data->socket_id) { + socket_if = entry; + connection_num = socket_num; + break; + } } } @@ -237,7 +282,7 @@ static void kmp_socket_if_socket_cb(void *ptr) cb_data->d_len -= SOCKET_IF_HEADER_SIZE; } - kmp_service_msg_if_receive(socket_if->kmp_service, socket_if->instance_id, type, &addr, data_ptr, cb_data->d_len); + kmp_service_msg_if_receive(socket_if->kmp_service, socket_if->instance_id, type, &addr, data_ptr, cb_data->d_len, connection_num); ns_dyn_mem_free(pdu); } diff --git a/connectivity/nanostack/sal-stack-nanostack/source/Security/protocols/eap_tls_sec_prot/eap_tls_sec_prot_lib.c b/connectivity/nanostack/sal-stack-nanostack/source/Security/protocols/eap_tls_sec_prot/eap_tls_sec_prot_lib.c index 1513f99cb0f..9592059724d 100644 --- a/connectivity/nanostack/sal-stack-nanostack/source/Security/protocols/eap_tls_sec_prot/eap_tls_sec_prot_lib.c +++ b/connectivity/nanostack/sal-stack-nanostack/source/Security/protocols/eap_tls_sec_prot/eap_tls_sec_prot_lib.c @@ -177,7 +177,7 @@ uint8_t *eap_tls_sec_prot_lib_message_build(uint8_t eap_code, uint8_t eap_type, uint8_t *data_ptr = NULL; // Write EAP-TLS data (from EAP-TLS flags field onward) - if (tls_send->data) { + if (tls_send != NULL && tls_send->data) { data_ptr = eap_tls_sec_prot_lib_fragment_write(tls_send->data + TLS_HEAD_LEN, tls_send->total_len, tls_send->handled_len, &eap_len, flags); } @@ -201,8 +201,8 @@ static int8_t eap_tls_sec_prot_lib_ack_update(tls_data_t *tls) return false; } - if (tls->handled_len + TLS_FRAGMENT_LEN < tls->total_len) { - tls->handled_len += TLS_FRAGMENT_LEN; + if (tls->handled_len + EAP_TLS_FRAGMENT_LEN_VALUE < tls->total_len) { + tls->handled_len += EAP_TLS_FRAGMENT_LEN_VALUE; return false; } @@ -236,8 +236,8 @@ static uint8_t *eap_tls_sec_prot_lib_fragment_write(uint8_t *data, uint16_t tota data_begin[0] = *flags; } - if (total_len - handled_len > TLS_FRAGMENT_LEN) { - *message_len += TLS_FRAGMENT_LEN; + if (total_len - handled_len > EAP_TLS_FRAGMENT_LEN_VALUE) { + *message_len += EAP_TLS_FRAGMENT_LEN_VALUE; if (handled_len == 0) { data_begin -= 4; // length diff --git a/connectivity/nanostack/sal-stack-nanostack/source/Security/protocols/eap_tls_sec_prot/eap_tls_sec_prot_lib.h b/connectivity/nanostack/sal-stack-nanostack/source/Security/protocols/eap_tls_sec_prot/eap_tls_sec_prot_lib.h index 285e617d643..6af3687869c 100644 --- a/connectivity/nanostack/sal-stack-nanostack/source/Security/protocols/eap_tls_sec_prot/eap_tls_sec_prot_lib.h +++ b/connectivity/nanostack/sal-stack-nanostack/source/Security/protocols/eap_tls_sec_prot/eap_tls_sec_prot_lib.h @@ -54,7 +54,6 @@ typedef struct { uint16_t handled_len; /**< Handled length of the data buffer (e.g. acked by other end) */ } tls_data_t; -#define TLS_FRAGMENT_LEN 1100 //EAP-TLS fragment length #define TLS_HEAD_LEN 5 //EAP-TLS flags and EAP-TLS length extern const uint8_t eap_msg_trace[4][10]; diff --git a/connectivity/nanostack/sal-stack-nanostack/source/Security/protocols/eap_tls_sec_prot/radius_eap_tls_sec_prot.c b/connectivity/nanostack/sal-stack-nanostack/source/Security/protocols/eap_tls_sec_prot/radius_eap_tls_sec_prot.c index 2c85d85378d..7018d56c98a 100644 --- a/connectivity/nanostack/sal-stack-nanostack/source/Security/protocols/eap_tls_sec_prot/radius_eap_tls_sec_prot.c +++ b/connectivity/nanostack/sal-stack-nanostack/source/Security/protocols/eap_tls_sec_prot/radius_eap_tls_sec_prot.c @@ -65,20 +65,23 @@ typedef enum { // How many times initial EAPOL-key is accepted on wait for identity response state #define INITIAL_EAPOL_KEY_MAX_COUNT 2 +// How long to wait RADIUS client to proceed with handshake (RADIUS server to answer) +#define RADIUS_EAP_TLS_CLIENT_TIMEOUT 60 * 10 // 60 seconds + typedef struct { - sec_prot_common_t common; /**< Common data */ - sec_prot_t *radius_client_prot; /**< RADIUS client security protocol */ - sec_prot_receive *radius_client_send; /**< RADIUS client security protocol send (receive from peer) */ - eapol_pdu_t recv_eapol_pdu; /**< Received EAPOL PDU */ - tls_data_t tls_send; /**< EAP-TLS send buffer */ - uint16_t recv_eap_msg_len; /**< Received EAP message length */ - uint8_t *recv_eap_msg; /**< Received EAP message */ - uint16_t burst_filt_timer; /**< Burst filter timer */ - uint8_t eap_id_seq; /**< EAP sequence */ - uint8_t recv_eap_id_seq; /**< Last received EAP sequence */ - uint8_t eap_code; /**< Received EAP code */ - uint8_t eap_type; /**< Received EAP type */ - uint8_t init_key_cnt; /**< How many time initial EAPOL-key has been received */ + sec_prot_common_t common; /**< Common data */ + sec_prot_t *radius_client_prot; /**< RADIUS client security protocol */ + sec_prot_receive *radius_client_send; /**< RADIUS client security protocol send (receive from peer) */ + sec_prot_delete *radius_client_deleted; /**< RADIUS client security protocol peer deleted (notify to peer that radius EAP-TLS deleted) */ + eapol_pdu_t recv_eapol_pdu; /**< Received EAPOL PDU */ + uint16_t recv_eap_msg_len; /**< Received EAP message length */ + uint8_t *recv_eap_msg; /**< Received EAP message */ + uint16_t burst_filt_timer; /**< Burst filter timer */ + uint8_t eap_id_seq; /**< EAP sequence */ + uint8_t recv_eap_id_seq; /**< Last received EAP sequence */ + uint8_t eap_code; /**< Received EAP code */ + uint8_t eap_type; /**< Received EAP type */ + uint8_t init_key_cnt; /**< How many time initial EAPOL-key has been received */ } radius_eap_tls_sec_prot_int_t; static uint16_t radius_eap_tls_sec_prot_size(void); @@ -88,15 +91,18 @@ static void radius_eap_tls_sec_prot_create_request(sec_prot_t *prot, sec_prot_ke static void radius_eap_tls_sec_prot_delete(sec_prot_t *prot); static int8_t radius_eap_tls_sec_prot_receive(sec_prot_t *prot, void *pdu, uint16_t size); static int8_t radius_eap_tls_sec_prot_radius_client_receive(sec_prot_t *radius_client, void *pdu, uint16_t size); +static void radius_eap_tls_sec_prot_eap_tls_msg_free(sec_prot_t *prot); static int8_t radius_eap_tls_sec_prot_radius_eap_message_forward(sec_prot_t *prot, uint8_t *eap_code); +static int8_t radius_eap_tls_sec_prot_radius_eap_message_retry(sec_prot_t *prot); static void radius_eap_tls_sec_prot_state_machine(sec_prot_t *prot); static int8_t radius_eap_tls_sec_prot_message_handle(sec_prot_t *prot, uint8_t *data_ptr, uint16_t *length); -static int8_t radius_eap_tls_sec_prot_message_send(sec_prot_t *prot, uint8_t eap_code, uint8_t eap_type, uint8_t tls_state); +static int8_t radius_eap_tls_sec_prot_message_send(sec_prot_t *prot, uint8_t eap_code, uint8_t eap_type); static void radius_eap_tls_sec_prot_timer_timeout(sec_prot_t *prot, uint16_t ticks); static int8_t radius_eap_tls_sec_prot_init_radius_client(sec_prot_t *prot); +static void radius_eap_tls_sec_prot_radius_client_deleted(sec_prot_t *prot); static void radius_eap_tls_sec_prot_seq_id_update(sec_prot_t *prot); @@ -126,6 +132,7 @@ static int8_t radius_eap_tls_sec_prot_init(sec_prot_t *prot) prot->create_resp = 0; prot->receive = radius_eap_tls_sec_prot_receive; prot->receive_peer = radius_eap_tls_sec_prot_radius_client_receive; + prot->peer_deleted = radius_eap_tls_sec_prot_radius_client_deleted; prot->delete = radius_eap_tls_sec_prot_delete; prot->state_machine = radius_eap_tls_sec_prot_state_machine; prot->timer_timeout = radius_eap_tls_sec_prot_timer_timeout; @@ -142,7 +149,6 @@ static int8_t radius_eap_tls_sec_prot_init(sec_prot_t *prot) data->recv_eap_id_seq = 0; data->eap_code = 0; data->eap_type = 0; - eap_tls_sec_prot_lib_message_init(&data->tls_send); data->init_key_cnt = 0; return 0; } @@ -150,7 +156,10 @@ static int8_t radius_eap_tls_sec_prot_init(sec_prot_t *prot) static void radius_eap_tls_sec_prot_delete(sec_prot_t *prot) { radius_eap_tls_sec_prot_int_t *data = eap_tls_sec_prot_get(prot); - eap_tls_sec_prot_lib_message_free(&data->tls_send); + + if (data->recv_eap_msg != NULL) { + ns_dyn_mem_free(data->recv_eap_msg); + } } static void radius_eap_tls_sec_prot_create_request(sec_prot_t *prot, sec_prot_keys_t *sec_keys) @@ -242,30 +251,13 @@ static int8_t radius_eap_tls_sec_prot_message_handle(sec_prot_t *prot, uint8_t * return EAP_TLS_MSG_CONTINUE; } -static int8_t radius_eap_tls_sec_prot_message_send(sec_prot_t *prot, uint8_t eap_code, uint8_t eap_type, uint8_t tls_state) +static int8_t radius_eap_tls_sec_prot_message_send(sec_prot_t *prot, uint8_t eap_code, uint8_t eap_type) { radius_eap_tls_sec_prot_int_t *data = eap_tls_sec_prot_get(prot); uint8_t flags = 0xff; - // EAP-TLS flags field is always present during TLS exchange - if (tls_state == EAP_TLS_EXCHANGE_ONGOING) { - flags = 0x00; - } - - if (eap_code == EAP_REQ) { - if (eap_type == EAP_TLS && tls_state == EAP_TLS_EXCHANGE_START) { - eap_tls_sec_prot_lib_message_allocate(&data->tls_send, TLS_HEAD_LEN, 0); - flags = EAP_TLS_START; - } - } else if (eap_code == EAP_SUCCESS || eap_code == EAP_FAILURE) { - // Send Success and Failure with same identifier as received in EAP Response - data->eap_id_seq = data->recv_eap_id_seq; - } else { - return -1; - } - uint16_t eapol_pdu_size; - uint8_t *eapol_decoded_data = eap_tls_sec_prot_lib_message_build(eap_code, eap_type, &flags, data->eap_id_seq, prot->header_size, &data->tls_send, &eapol_pdu_size); + uint8_t *eapol_decoded_data = eap_tls_sec_prot_lib_message_build(eap_code, eap_type, &flags, data->eap_id_seq, prot->header_size, NULL, &eapol_pdu_size); if (!eapol_decoded_data) { return -1; } @@ -327,7 +319,23 @@ static int8_t radius_eap_tls_sec_prot_radius_eap_message_forward(sec_prot_t *pro eap_type == EAP_IDENTITY ? "IDENTITY" : "TLS", data->eap_id_seq, flags, eapol_pdu_size, trace_array(sec_prot_remote_eui_64_addr_get(prot), 8)); - if (prot->send(prot, data->recv_eap_msg, eapol_pdu_size + prot->header_size) < 0) { + if (prot->conn_send(prot, data->recv_eap_msg, eapol_pdu_size + prot->header_size, 0, SEC_PROT_SEND_FLAG_NO_DEALLOC) < 0) { + return -1; + } + data->recv_eap_msg_len = eapol_pdu_size + prot->header_size; + + return 0; +} + +static int8_t radius_eap_tls_sec_prot_radius_eap_message_retry(sec_prot_t *prot) +{ + radius_eap_tls_sec_prot_int_t *data = eap_tls_sec_prot_get(prot); + + if (data->recv_eap_msg == NULL || data->recv_eap_msg_len == 0) { + return -1; + } + + if (prot->conn_send(prot, data->recv_eap_msg, data->recv_eap_msg_len, 0, SEC_PROT_SEND_FLAG_NO_DEALLOC) < 0) { return -1; } @@ -357,6 +365,10 @@ static int8_t radius_eap_tls_sec_prot_radius_client_receive(sec_prot_t *radius_c radius_eap_tls_sec_prot_int_t *data = eap_tls_sec_prot_get(prot); + if (data->recv_eap_msg != NULL) { + ns_dyn_mem_free(data->recv_eap_msg); + } + data->recv_eap_msg_len = size; data->recv_eap_msg = pdu; @@ -365,6 +377,18 @@ static int8_t radius_eap_tls_sec_prot_radius_client_receive(sec_prot_t *radius_c return 0; } +static void radius_eap_tls_sec_prot_eap_tls_msg_free(sec_prot_t *prot) +{ + radius_eap_tls_sec_prot_int_t *data = eap_tls_sec_prot_get(prot); + + if (data->recv_eap_msg != NULL) { + ns_dyn_mem_free(data->recv_eap_msg); + } + + data->recv_eap_msg = NULL; + data->recv_eap_msg_len = 0; +} + static int8_t radius_eap_tls_sec_prot_init_radius_client(sec_prot_t *prot) { radius_eap_tls_sec_prot_int_t *data = eap_tls_sec_prot_get(prot); @@ -377,10 +401,22 @@ static int8_t radius_eap_tls_sec_prot_init_radius_client(sec_prot_t *prot) return -1; } data->radius_client_send = data->radius_client_prot->receive_peer; + data->radius_client_deleted = data->radius_client_prot->peer_deleted; return 0; } +static void radius_eap_tls_sec_prot_radius_client_deleted(sec_prot_t *prot) +{ + radius_eap_tls_sec_prot_int_t *data = eap_tls_sec_prot_get(prot); + + tr_debug("EAP-TLS: client deleted"); + + data->radius_client_prot = NULL; + data->radius_client_send = NULL; + data->radius_client_deleted = NULL; +} + static void radius_eap_tls_sec_prot_state_machine(sec_prot_t *prot) { radius_eap_tls_sec_prot_int_t *data = eap_tls_sec_prot_get(prot); @@ -390,14 +426,14 @@ static void radius_eap_tls_sec_prot_state_machine(sec_prot_t *prot) // EAP-TLS authenticator state machine switch (sec_prot_state_get(&data->common)) { case EAP_TLS_STATE_INIT: - tr_info("EAP-TLS init"); + tr_info("EAP-TLS: init"); sec_prot_state_set(prot, &data->common, EAP_TLS_STATE_CREATE_REQ); prot->timer_start(prot); break; // Wait KMP-CREATE.request case EAP_TLS_STATE_CREATE_REQ: - tr_info("EAP-TLS start, eui-64: %s", trace_array(sec_prot_remote_eui_64_addr_get(prot), 8)); + tr_info("EAP-TLS: start, eui-64: %s", trace_array(sec_prot_remote_eui_64_addr_get(prot), 8)); // Set default timeout for the total maximum length of the negotiation sec_prot_default_timeout_set(&data->common); @@ -409,7 +445,7 @@ static void radius_eap_tls_sec_prot_state_machine(sec_prot_t *prot) radius_eap_tls_sec_prot_seq_id_update(prot); // Sends EAP request, Identity - radius_eap_tls_sec_prot_message_send(prot, EAP_REQ, EAP_IDENTITY, EAP_TLS_EXCHANGE_NONE); + radius_eap_tls_sec_prot_message_send(prot, EAP_REQ, EAP_IDENTITY); // Start trickle timer to re-send if no response sec_prot_timer_trickle_start(&data->common, &prot->sec_cfg->prot_cfg.sec_prot_trickle_params); @@ -423,7 +459,7 @@ static void radius_eap_tls_sec_prot_state_machine(sec_prot_t *prot) // On timeout if (sec_prot_result_timeout_check(&data->common)) { // Re-sends EAP request, Identity - radius_eap_tls_sec_prot_message_send(prot, EAP_REQ, EAP_IDENTITY, EAP_TLS_EXCHANGE_NONE); + radius_eap_tls_sec_prot_message_send(prot, EAP_REQ, EAP_IDENTITY); return; } @@ -432,13 +468,22 @@ static void radius_eap_tls_sec_prot_state_machine(sec_prot_t *prot) return; } - tr_info("EAP-TLS EAP response id, eui-64: %s", trace_array(sec_prot_remote_eui_64_addr_get(prot), 8)); + tr_info("EAP-TLS: EAP response id, eui-64: %s", trace_array(sec_prot_remote_eui_64_addr_get(prot), 8)); if (radius_eap_tls_sec_prot_init_radius_client(prot) < 0) { tr_error("EAP-TLS: radius client init failed"); return; } + // Free EAP request buffer since answer received and retries not needed + radius_eap_tls_sec_prot_eap_tls_msg_free(prot); + + // Stop trickle timer, radius client will continue + sec_prot_timer_trickle_stop(&data->common); + + // Set timeout to wait for RADIUS client to continue + data->common.ticks = RADIUS_EAP_TLS_CLIENT_TIMEOUT; + // Send to radius client data->radius_client_send(data->radius_client_prot, (void *) &data->recv_eapol_pdu, length); @@ -450,11 +495,11 @@ static void radius_eap_tls_sec_prot_state_machine(sec_prot_t *prot) // On timeout if (sec_prot_result_timeout_check(&data->common)) { - // Do nothing for now + // Do nothing (trickle timer not running, so should not happen) return; } - tr_info("EAP-TLS EAP request, eui-64: %s", trace_array(sec_prot_remote_eui_64_addr_get(prot), 8)); + tr_info("EAP-TLS: EAP request, eui-64: %s", trace_array(sec_prot_remote_eui_64_addr_get(prot), 8)); uint8_t eap_code; if (radius_eap_tls_sec_prot_radius_eap_message_forward(prot, &eap_code) < 0) { @@ -470,6 +515,9 @@ static void radius_eap_tls_sec_prot_state_machine(sec_prot_t *prot) sec_prot_state_set(prot, &data->common, EAP_TLS_STATE_FINISH); } + // Start trickle timer to re-send if no response + sec_prot_timer_trickle_start(&data->common, &prot->sec_cfg->prot_cfg.sec_prot_trickle_params); + sec_prot_state_set(prot, &data->common, EAP_TLS_STATE_EAP_RESPONSE); break; @@ -478,17 +526,29 @@ static void radius_eap_tls_sec_prot_state_machine(sec_prot_t *prot) // On timeout if (sec_prot_result_timeout_check(&data->common)) { - // Do nothing for now + tr_debug("EAP-TLS: retry EAP request, eui-64: %s", trace_array(sec_prot_remote_eui_64_addr_get(prot), 8)); + if (radius_eap_tls_sec_prot_radius_eap_message_retry(prot) < 0) { + tr_error("EAP-TLS: retry msg send error"); + } return; } - tr_info("EAP-TLS EAP response, eui-64: %s", trace_array(sec_prot_remote_eui_64_addr_get(prot), 8)); + tr_info("EAP-TLS: EAP response, eui-64: %s", trace_array(sec_prot_remote_eui_64_addr_get(prot), 8)); // Handle EAP response if (radius_eap_tls_sec_prot_message_handle(prot, data_ptr, &length) != EAP_TLS_MSG_CONTINUE) { return; } + // Free EAP request buffer since answer received and retries not needed + radius_eap_tls_sec_prot_eap_tls_msg_free(prot); + + // Stop trickle timer, radius client will continue + sec_prot_timer_trickle_stop(&data->common); + + // Set timeout to wait for RADIUS client to continue + data->common.ticks = RADIUS_EAP_TLS_CLIENT_TIMEOUT; + // Send to radius client data->radius_client_send(data->radius_client_prot, (void *) &data->recv_eapol_pdu, length); @@ -507,6 +567,12 @@ static void radius_eap_tls_sec_prot_state_machine(sec_prot_t *prot) case EAP_TLS_STATE_FINISHED: { uint8_t *remote_eui_64 = sec_prot_remote_eui_64_addr_get(prot); tr_info("EAP-TLS finished, eui-64: %s", remote_eui_64 ? trace_array(sec_prot_remote_eui_64_addr_get(prot), 8) : "not set"); + + // Indicate to radius client peer protocol that radius EAP-TLS has been deleted + if (data->radius_client_deleted) { + data->radius_client_deleted(data->radius_client_prot); + } + prot->timer_stop(prot); prot->finished(prot); break; diff --git a/connectivity/nanostack/sal-stack-nanostack/source/Security/protocols/radius_sec_prot/avp_helper.h b/connectivity/nanostack/sal-stack-nanostack/source/Security/protocols/radius_sec_prot/avp_helper.h index 1fdd5bb54e3..8687a112fa4 100644 --- a/connectivity/nanostack/sal-stack-nanostack/source/Security/protocols/radius_sec_prot/avp_helper.h +++ b/connectivity/nanostack/sal-stack-nanostack/source/Security/protocols/radius_sec_prot/avp_helper.h @@ -46,8 +46,8 @@ // EUI-64 in ascii string: 00-11-..-77 #define STATION_ID_LEN 16 + 7 -// MTU value TBD -#define FRAMED_MTU 1400 +// MTU value is set by EAP-TLS fragment length +#define FRAMED_MTU EAP_TLS_FRAGMENT_LEN_VALUE #define NAS_PORT 1 diff --git a/connectivity/nanostack/sal-stack-nanostack/source/Security/protocols/radius_sec_prot/radius_client_sec_prot.c b/connectivity/nanostack/sal-stack-nanostack/source/Security/protocols/radius_sec_prot/radius_client_sec_prot.c index a181cf0dd3c..a8dc175b7b8 100644 --- a/connectivity/nanostack/sal-stack-nanostack/source/Security/protocols/radius_sec_prot/radius_client_sec_prot.c +++ b/connectivity/nanostack/sal-stack-nanostack/source/Security/protocols/radius_sec_prot/radius_client_sec_prot.c @@ -75,12 +75,17 @@ typedef enum { #define MS_MPPE_RECV_KEY_SALT_LEN 2 #define MS_MPPE_RECV_KEY_BLOCK_LEN 16 +#define RADIUS_CONN_NUMBER 3 +#define RADIUS_ID_RANGE_SIZE 10 +#define RADIUS_ID_RANGE_NUM (255 / RADIUS_ID_RANGE_SIZE) - 1 + typedef struct radius_client_sec_prot_lib_int_s radius_client_sec_prot_lib_int_t; typedef struct { sec_prot_common_t common; /**< Common data */ sec_prot_t *radius_eap_tls_prot; /**< Radius EAP-TLS security protocol */ sec_prot_receive *radius_eap_tls_send; /**< Radius EAP-TLS security protocol send (receive from peer) */ + sec_prot_delete *radius_eap_tls_deleted; /**< Radius EAP-TLS security protocol peer deleted (notify to peer that radius client deleted) */ uint8_t radius_eap_tls_header_size; /**< Radius EAP-TLS header size */ uint8_t new_pmk[PMK_LEN]; /**< New Pair Wise Master Key */ uint16_t recv_eap_msg_len; /**< Received EAP message length */ @@ -91,34 +96,46 @@ typedef struct { uint8_t *identity; /**< Supplicant EAP identity */ uint8_t radius_code; /**< Radius code that was received */ uint8_t radius_identifier; /**< Radius identifier that was last sent */ + uint8_t radius_id_conn_num; /**< Radius identifier connection number (socket instance) */ + uint8_t radius_id_range; /**< Radius identifier range */ uint8_t request_authenticator[16]; /**< Radius request authenticator that was last sent */ uint8_t state_len; /**< Radius state length that was last received */ uint8_t *state; /**< Radius state that was last received */ uint8_t remote_eui_64_hash[8]; /**< Remote EUI-64 hash used for calling station id */ bool remote_eui_64_hash_set : 1; /**< Remote EUI-64 hash used for calling station id set */ bool new_pmk_set : 1; /**< New Pair Wise Master Key set */ + bool radius_id_range_set : 1; /**< Radius identifier start value set */ } radius_client_sec_prot_int_t; typedef struct { - uint8_t radius_client_identifier; /**< Radius client identifier */ + uint8_t radius_identifier_timer[RADIUS_CONN_NUMBER][RADIUS_ID_RANGE_NUM]; + shared_comp_data_t comp_data; /**< Shared component data (timer, delete) */ uint8_t local_eui64_hash[8]; /**< Local EUI-64 hash used for called stations id */ uint8_t hash_random[16]; /**< Random used to generate local and remote EUI-64 hashes */ bool local_eui64_hash_set : 1; /**< Local EUI-64 hash used for called stations id set */ bool hash_random_set : 1; /**< Random used to generate local and remote EUI-64 hashes set */ + bool radius_id_timer_running : 1; /**> Radius identifier timer running */ } radius_client_sec_prot_shared_t; static uint16_t radius_client_sec_prot_size(void); static int8_t radius_client_sec_prot_init(sec_prot_t *prot); +static int8_t radius_client_sec_prot_shared_data_timeout(uint16_t ticks); +static void radius_identifier_timer_value_set(uint8_t conn_num, uint8_t id_range, uint8_t value); +static int8_t radius_client_sec_prot_shared_data_delete(void); +static void radius_identifier_timer_value_set(uint8_t conn_num, uint8_t id_range, uint8_t value); static void radius_client_sec_prot_create_response(sec_prot_t *prot, sec_prot_result_e result); static void radius_client_sec_prot_delete(sec_prot_t *prot); static int8_t radius_client_sec_prot_receive_check(sec_prot_t *prot, const void *pdu, uint16_t size); static int8_t radius_client_sec_prot_init_radius_eap_tls(sec_prot_t *prot); +static void radius_client_sec_prot_radius_eap_tls_deleted(sec_prot_t *prot); static uint16_t radius_client_sec_prot_eap_avps_handle(uint16_t avp_length, uint8_t *avp_ptr, uint8_t *copy_to_ptr); -static int8_t radius_client_sec_prot_receive(sec_prot_t *prot, void *pdu, uint16_t size); +static int8_t radius_client_sec_prot_receive(sec_prot_t *prot, void *pdu, uint16_t size, uint8_t conn_number); static int8_t radius_client_sec_prot_radius_eap_receive(sec_prot_t *prot, void *pdu, uint16_t size); static void radius_client_sec_prot_allocate_and_create_radius_message(sec_prot_t *prot); static int8_t radius_client_sec_prot_radius_msg_send(sec_prot_t *prot); -static uint8_t radius_client_sec_prot_identifier_allocate(void); +static void radius_client_sec_prot_radius_msg_free(sec_prot_t *prot); +static uint8_t radius_client_sec_prot_identifier_allocate(sec_prot_t *prot, uint8_t value); +static void radius_client_sec_prot_identifier_free(sec_prot_t *prot); static uint8_t radius_client_sec_prot_hex_to_ascii(uint8_t value); static int8_t radius_client_sec_prot_eui_64_hash_generate(uint8_t *eui_64, uint8_t *hashed_eui_64); static void radius_client_sec_prot_station_id_generate(uint8_t *eui_64, uint8_t *station_id_ptr); @@ -152,12 +169,55 @@ static uint16_t radius_client_sec_prot_size(void) return sizeof(radius_client_sec_prot_int_t); } +static int8_t radius_client_sec_prot_shared_data_timeout(uint16_t ticks) +{ + if (shared_data == NULL || !shared_data->radius_id_timer_running) { + return -1; + } + + bool timer_running = false; + + for (uint8_t conn_num = 0; conn_num < RADIUS_CONN_NUMBER; conn_num++) { + for (uint8_t id_range = 0; id_range < RADIUS_ID_RANGE_NUM; id_range++) { + if (shared_data->radius_identifier_timer[conn_num][id_range] > ticks) { + shared_data->radius_identifier_timer[conn_num][id_range] -= ticks; + timer_running = true; + } else { + shared_data->radius_identifier_timer[conn_num][id_range] = 0; + } + } + } + + if (!timer_running) { + shared_data->radius_id_timer_running = false; + } + + return 0; +} + +static void radius_identifier_timer_value_set(uint8_t conn_num, uint8_t id_range, uint8_t value) +{ + shared_data->radius_identifier_timer[conn_num][id_range] = value; + shared_data->radius_id_timer_running = true; +} + +static int8_t radius_client_sec_prot_shared_data_delete(void) +{ + if (shared_data == NULL) { + return -1; + } + ns_dyn_mem_free(shared_data); + shared_data = NULL; + return 0; +} + static int8_t radius_client_sec_prot_init(sec_prot_t *prot) { prot->create_req = NULL; prot->create_resp = radius_client_sec_prot_create_response; - prot->receive = radius_client_sec_prot_receive; + prot->conn_receive = radius_client_sec_prot_receive; prot->receive_peer = radius_client_sec_prot_radius_eap_receive; + prot->peer_deleted = radius_client_sec_prot_radius_eap_tls_deleted; prot->delete = radius_client_sec_prot_delete; prot->state_machine = radius_client_sec_prot_state_machine; prot->timer_timeout = radius_client_sec_prot_timer_timeout; @@ -192,11 +252,14 @@ static int8_t radius_client_sec_prot_init(sec_prot_t *prot) if (!shared_data) { return -1; } - shared_data->radius_client_identifier = 0; - memset(shared_data->local_eui64_hash, 0, 8); - memset(shared_data->hash_random, 0, 16); + memset(shared_data, 0, sizeof(radius_client_sec_prot_shared_t)); shared_data->local_eui64_hash_set = false; shared_data->hash_random_set = false; + shared_data->radius_id_timer_running = false; + // Add as shared component to enable timers and delete + shared_data->comp_data.timeout = radius_client_sec_prot_shared_data_timeout; + shared_data->comp_data.delete = radius_client_sec_prot_shared_data_delete; + prot->shared_comp_add(prot, &shared_data->comp_data); } return 0; @@ -256,10 +319,22 @@ static int8_t radius_client_sec_prot_init_radius_eap_tls(sec_prot_t *prot) } data->radius_eap_tls_header_size = data->radius_eap_tls_prot->receive_peer_hdr_size; data->radius_eap_tls_send = data->radius_eap_tls_prot->receive_peer; + data->radius_eap_tls_deleted = data->radius_eap_tls_prot->peer_deleted; return 0; } +static void radius_client_sec_prot_radius_eap_tls_deleted(sec_prot_t *prot) +{ + radius_client_sec_prot_int_t *data = radius_client_sec_prot_get(prot); + + tr_info("Radius: EAP-TLS deleted"); + + data->radius_eap_tls_prot = NULL; + data->radius_eap_tls_send = NULL; + data->radius_eap_tls_deleted = NULL; +} + static uint16_t radius_client_sec_prot_eap_avps_handle(uint16_t avp_length, uint8_t *avp_ptr, uint8_t *copy_to_ptr) { // Calculate EAP AVPs length and copy EAP AVPs to continuous buffer if buffer is give @@ -290,8 +365,10 @@ static uint16_t radius_client_sec_prot_eap_avps_handle(uint16_t avp_length, uint return eap_len; } -static int8_t radius_client_sec_prot_receive(sec_prot_t *prot, void *pdu, uint16_t size) +static int8_t radius_client_sec_prot_receive(sec_prot_t *prot, void *pdu, uint16_t size, uint8_t conn_number) { + (void) conn_number; + radius_client_sec_prot_int_t *data = radius_client_sec_prot_get(prot); if (size < RADIUS_MSG_FIXED_LENGTH) { @@ -312,6 +389,10 @@ static int8_t radius_client_sec_prot_receive(sec_prot_t *prot, void *pdu, uint16 uint16_t length = common_read_16_bit(radius_msg_ptr); radius_msg_ptr += 2; + if (length < RADIUS_MSG_FIXED_LENGTH) { + return -1; + } + // Store response authenticator uint8_t recv_response_authenticator[16]; memcpy(recv_response_authenticator, radius_msg_ptr, 16); @@ -333,11 +414,23 @@ static int8_t radius_client_sec_prot_receive(sec_prot_t *prot, void *pdu, uint16 return -1; } - uint16_t avp_length = length - RADIUS_MSG_FIXED_LENGTH; + // Response authenticator matches, start validating radius EAP-TLS specific fields + data->recv_eap_msg = NULL; + data->recv_eap_msg_len = 0; + + uint16_t avp_length = 0; + if (length >= RADIUS_MSG_FIXED_LENGTH) { + avp_length = length - RADIUS_MSG_FIXED_LENGTH; + } uint8_t *message_authenticator = avp_message_authenticator_read(radius_msg_ptr, avp_length); - if (message_authenticator == NULL) { + if (message_authenticator == NULL || avp_length == 0) { tr_error("No message authenticator"); + // Message does not have radius EAP-TLS specific fields + data->radius_code = code; + prot->state_machine(prot); + + return 0; } // Store message authenticator @@ -415,7 +508,9 @@ static int8_t radius_client_sec_prot_receive(sec_prot_t *prot, void *pdu, uint16 if (radius_client_sec_prot_ms_mppe_recv_key_pmk_decrypt(prot, recv_key, recv_key_len - AVP_FIXED_LEN, data->request_authenticator, data->new_pmk) >= 0) { data->new_pmk_set = true; +#ifdef EXTRA_DEBUG_INFO tr_info("RADIUS PMK: %s %s", tr_array(data->new_pmk, 16), tr_array(data->new_pmk + 16, 16)); +#endif } } } @@ -442,9 +537,43 @@ static int8_t radius_client_sec_prot_radius_eap_receive(sec_prot_t *prot, void * return 0; } -static uint8_t radius_client_sec_prot_identifier_allocate(void) +static uint8_t radius_client_sec_prot_identifier_allocate(sec_prot_t *prot, uint8_t value) +{ + radius_client_sec_prot_int_t *data = radius_client_sec_prot_get(prot); + + if (!data->radius_id_range_set || value >= (data->radius_id_range * RADIUS_ID_RANGE_SIZE) + RADIUS_ID_RANGE_SIZE) { + for (uint8_t conn_num = 0; conn_num < RADIUS_CONN_NUMBER; conn_num++) { + for (uint8_t id_range = 0; id_range < RADIUS_ID_RANGE_NUM; id_range++) { + if (shared_data->radius_identifier_timer[conn_num][id_range] == 0) { + // If range has been already reserved + if (data->radius_id_range_set) { + // Set previous range to timeout in 5 seconds + radius_identifier_timer_value_set(data->radius_id_conn_num, data->radius_id_range, 5); + } + // Set timeout for new range to 60 seconds + radius_identifier_timer_value_set(conn_num, id_range, 60); + data->radius_id_conn_num = conn_num; + data->radius_id_range = id_range; + data->radius_id_range_set = true; + return id_range * RADIUS_ID_RANGE_SIZE; + } + } + } + } else { + radius_identifier_timer_value_set(data->radius_id_conn_num, data->radius_id_range, 60); + return value + 1; + } + + return 0; +} + +static void radius_client_sec_prot_identifier_free(sec_prot_t *prot) { - return shared_data->radius_client_identifier++; + radius_client_sec_prot_int_t *data = radius_client_sec_prot_get(prot); + + if (data->radius_id_range_set) { + radius_identifier_timer_value_set(data->radius_id_conn_num, data->radius_id_range, 5); + } } static uint8_t radius_client_sec_prot_eui_64_hash_get(sec_prot_t *prot, uint8_t *local_eui_64_hash, uint8_t *remote_eui_64_hash, bool remote_eui_64_hash_set) @@ -524,7 +653,7 @@ static void radius_client_sec_prot_allocate_and_create_radius_message(sec_prot_t uint8_t *radius_msg_start_ptr = radius_msg_ptr; *radius_msg_ptr++ = RADIUS_ACCESS_REQUEST; // code - data->radius_identifier = radius_client_sec_prot_identifier_allocate(); + data->radius_identifier = radius_client_sec_prot_identifier_allocate(prot, data->radius_identifier); *radius_msg_ptr++ = data->radius_identifier; // identifier radius_msg_ptr = common_write_16_bit(radius_msg_length, radius_msg_ptr); // length @@ -604,15 +733,25 @@ static int8_t radius_client_sec_prot_radius_msg_send(sec_prot_t *prot) return -1; } - if (prot->send(prot, data->send_radius_msg, data->send_radius_msg_len) < 0) { + if (prot->conn_send(prot, data->send_radius_msg, data->send_radius_msg_len, data->radius_id_conn_num, SEC_PROT_SEND_FLAG_NO_DEALLOC) < 0) { return -1; } - data->send_radius_msg = NULL; - data->send_radius_msg_len = 0; return 0; } +static void radius_client_sec_prot_radius_msg_free(sec_prot_t *prot) +{ + radius_client_sec_prot_int_t *data = radius_client_sec_prot_get(prot); + + if (data->send_radius_msg != NULL) { + ns_dyn_mem_free(data->send_radius_msg); + } + + data->send_radius_msg = NULL; + data->send_radius_msg_len = 0; +} + static int8_t radius_client_sec_prot_eui_64_hash_generate(uint8_t *eui_64, uint8_t *hashed_eui_64) { int8_t ret_val = 0; @@ -678,12 +817,13 @@ static void radius_client_sec_prot_station_id_generate(uint8_t *eui_64, uint8_t static int8_t radius_client_sec_prot_message_authenticator_calc(sec_prot_t *prot, uint16_t msg_len, uint8_t *msg_ptr, uint8_t *auth_ptr) { - const uint8_t *key = prot->sec_cfg->radius_cfg.radius_shared_secret; - uint16_t key_len = prot->sec_cfg->radius_cfg.radius_shared_secret_len; - if (prot->sec_cfg->radius_cfg.radius_shared_secret_len == 0) { + if (prot->sec_cfg->radius_cfg->radius_shared_secret == NULL || prot->sec_cfg->radius_cfg->radius_shared_secret_len == 0) { return -1; } + const uint8_t *key = prot->sec_cfg->radius_cfg->radius_shared_secret; + uint16_t key_len = prot->sec_cfg->radius_cfg->radius_shared_secret_len; + #ifndef MBEDTLS_MD5_C tr_error("FATAL: MD5 MBEDTLS_MD5_C not enabled"); #endif @@ -698,9 +838,13 @@ static int8_t radius_client_sec_prot_message_authenticator_calc(sec_prot_t *prot static int8_t radius_client_sec_prot_response_authenticator_calc(sec_prot_t *prot, uint16_t msg_len, uint8_t *msg_ptr, uint8_t *auth_ptr) { #ifdef MBEDTLS_MD5_C - const uint8_t *key = prot->sec_cfg->radius_cfg.radius_shared_secret; - uint16_t key_len = prot->sec_cfg->radius_cfg.radius_shared_secret_len; - if (prot->sec_cfg->radius_cfg.radius_shared_secret_len == 0) { + if (prot->sec_cfg->radius_cfg->radius_shared_secret == NULL || prot->sec_cfg->radius_cfg->radius_shared_secret_len == 0) { + return -1; + } + + const uint8_t *key = prot->sec_cfg->radius_cfg->radius_shared_secret; + uint16_t key_len = prot->sec_cfg->radius_cfg->radius_shared_secret_len; + if (prot->sec_cfg->radius_cfg->radius_shared_secret_len == 0) { return -1; } @@ -747,9 +891,13 @@ static int8_t radius_client_sec_prot_response_authenticator_calc(sec_prot_t *pro static int8_t radius_client_sec_prot_ms_mppe_recv_key_pmk_decrypt(sec_prot_t *prot, uint8_t *recv_key, uint8_t recv_key_len, uint8_t *request_authenticator, uint8_t *pmk_ptr) { #ifdef MBEDTLS_MD5_C - const uint8_t *key = prot->sec_cfg->radius_cfg.radius_shared_secret; - uint16_t key_len = prot->sec_cfg->radius_cfg.radius_shared_secret_len; - if (prot->sec_cfg->radius_cfg.radius_shared_secret_len == 0) { + if (prot->sec_cfg->radius_cfg->radius_shared_secret == NULL || prot->sec_cfg->radius_cfg->radius_shared_secret_len == 0) { + return -1; + } + + const uint8_t *key = prot->sec_cfg->radius_cfg->radius_shared_secret; + uint16_t key_len = prot->sec_cfg->radius_cfg->radius_shared_secret_len; + if (prot->sec_cfg->radius_cfg->radius_shared_secret_len == 0) { return -1; } @@ -852,8 +1000,7 @@ static void radius_client_sec_prot_timer_timeout(sec_prot_t *prot, uint16_t tick { radius_client_sec_prot_int_t *data = radius_client_sec_prot_get(prot); - sec_prot_timer_timeout_handle(prot, &data->common, - &prot->sec_cfg->prot_cfg.sec_prot_trickle_params, ticks); + sec_prot_timer_timeout_handle(prot, &data->common, &prot->sec_cfg->radius_cfg->radius_retry_trickle_params, ticks); } static void radius_client_sec_prot_state_machine(sec_prot_t *prot) @@ -862,14 +1009,14 @@ static void radius_client_sec_prot_state_machine(sec_prot_t *prot) switch (sec_prot_state_get(&data->common)) { case RADIUS_STATE_INIT: - tr_debug("Radius: init"); + tr_info("Radius: init"); sec_prot_state_set(prot, &data->common, RADIUS_STATE_STATE_RESPONSE_ID); prot->timer_start(prot); break; // Wait EAP response, Identity (starts RADIUS Client protocol) case RADIUS_STATE_STATE_RESPONSE_ID: - tr_debug("Radius: start, eui-64: %s", trace_array(sec_prot_remote_eui_64_addr_get(prot), 8)); + tr_info("Radius: start, eui-64: %s", trace_array(sec_prot_remote_eui_64_addr_get(prot), 8)); // Set default timeout for the total maximum length of the negotiation sec_prot_default_timeout_set(&data->common); @@ -899,14 +1046,14 @@ static void radius_client_sec_prot_state_machine(sec_prot_t *prot) break; case RADIUS_STATE_SEND_INITIAL_ACCESS_REQUEST: - tr_debug("Radius: send initial access request, eui-64: %s", trace_array(sec_prot_remote_eui_64_addr_get(prot), 8)); + tr_info("Radius: send initial access request, eui-64: %s", trace_array(sec_prot_remote_eui_64_addr_get(prot), 8)); if (radius_client_sec_prot_radius_msg_send(prot) < 0) { tr_error("Radius: msg send error"); } // Start trickle timer to re-send if no response - sec_prot_timer_trickle_start(&data->common, &prot->sec_cfg->prot_cfg.sec_prot_trickle_params); + sec_prot_timer_trickle_start(&data->common, &prot->sec_cfg->radius_cfg->radius_retry_trickle_params); sec_prot_state_set(prot, &data->common, RADIUS_STATE_ACCESS_ACCEPT_REJECT_CHALLENGE); break; @@ -915,14 +1062,32 @@ static void radius_client_sec_prot_state_machine(sec_prot_t *prot) // On timeout if (sec_prot_result_timeout_check(&data->common)) { - // Do nothing for now + tr_info("Radius: retry access request, eui-64: %s", trace_array(sec_prot_remote_eui_64_addr_get(prot), 8)); + if (radius_client_sec_prot_radius_msg_send(prot) < 0) { + tr_error("Radius: retry msg send error"); + } return; } - tr_debug("Radius: received access accept/reject/challenge, eui-64: %s", trace_array(sec_prot_remote_eui_64_addr_get(prot), 8)); + tr_info("Radius: received access accept/reject/challenge, eui-64: %s", trace_array(sec_prot_remote_eui_64_addr_get(prot), 8)); + + // Free radius access-request buffer since answer received and retries not needed + radius_client_sec_prot_radius_msg_free(prot); + + // Stop trickle timer, EAP-TLS will continue and on reject/accept negotiation will end + sec_prot_timer_trickle_stop(&data->common); + + // Set timeout to wait for EAP-TLS to continue + data->common.ticks = prot->sec_cfg->prot_cfg.sec_prot_retry_timeout; // Send to radius EAP-TLS - data->radius_eap_tls_send(data->radius_eap_tls_prot, (void *) data->recv_eap_msg, data->recv_eap_msg_len); + if (data->radius_eap_tls_send && data->radius_eap_tls_prot && data->recv_eap_msg && data->recv_eap_msg_len > 0) { + data->radius_eap_tls_send(data->radius_eap_tls_prot, (void *) data->recv_eap_msg, data->recv_eap_msg_len); + } else { + if (data->recv_eap_msg) { + ns_dyn_mem_free(data->recv_eap_msg); + } + } data->recv_eap_msg = NULL; data->recv_eap_msg_len = 0; @@ -945,11 +1110,14 @@ static void radius_client_sec_prot_state_machine(sec_prot_t *prot) // On timeout if (sec_prot_result_timeout_check(&data->common)) { - // Do nothing for now + tr_info("Radius: retry access request, eui-64: %s", trace_array(sec_prot_remote_eui_64_addr_get(prot), 8)); + if (radius_client_sec_prot_radius_msg_send(prot) < 0) { + tr_error("Radius: retry msg send error"); + } return; } - tr_debug("Radius: send access request, eui-64: %s", trace_array(sec_prot_remote_eui_64_addr_get(prot), 8)); + tr_info("Radius: send access request, eui-64: %s", trace_array(sec_prot_remote_eui_64_addr_get(prot), 8)); radius_client_sec_prot_allocate_and_create_radius_message(prot); @@ -957,11 +1125,14 @@ static void radius_client_sec_prot_state_machine(sec_prot_t *prot) tr_error("Radius: msg send error"); } + // Start trickle timer to re-send if no response + sec_prot_timer_trickle_start(&data->common, &prot->sec_cfg->radius_cfg->radius_retry_trickle_params); + sec_prot_state_set(prot, &data->common, RADIUS_STATE_ACCESS_ACCEPT_REJECT_CHALLENGE); break; case RADIUS_STATE_FINISH: - tr_debug("Radius: finish, eui-64: %s", trace_array(sec_prot_remote_eui_64_addr_get(prot), 8)); + tr_info("Radius: finish, eui-64: %s", trace_array(sec_prot_remote_eui_64_addr_get(prot), 8)); if (sec_prot_result_ok_check(&data->common)) { sec_prot_keys_pmk_write(prot->sec_keys, data->new_pmk, prot->sec_cfg->timer_cfg.pmk_lifetime); @@ -980,7 +1151,14 @@ static void radius_client_sec_prot_state_machine(sec_prot_t *prot) case RADIUS_STATE_FINISHED: { uint8_t *remote_eui_64 = sec_prot_remote_eui_64_addr_get(prot); - tr_debug("Radius: finished, eui-64: %s", remote_eui_64 ? trace_array(remote_eui_64, 8) : "not set"); + tr_info("Radius: finished, eui-64: %s", remote_eui_64 ? trace_array(remote_eui_64, 8) : "not set"); + + radius_client_sec_prot_identifier_free(prot); + + // Indicate to radius EAP-TLS peer protocol that radius client has been deleted + if (data->radius_eap_tls_deleted) { + data->radius_eap_tls_deleted(data->radius_eap_tls_prot); + } prot->timer_stop(prot); prot->finished(prot); diff --git a/connectivity/nanostack/sal-stack-nanostack/source/Security/protocols/sec_prot.h b/connectivity/nanostack/sal-stack-nanostack/source/Security/protocols/sec_prot.h index 3c7724124ee..565ad5148a5 100644 --- a/connectivity/nanostack/sal-stack-nanostack/source/Security/protocols/sec_prot.h +++ b/connectivity/nanostack/sal-stack-nanostack/source/Security/protocols/sec_prot.h @@ -61,6 +61,9 @@ typedef enum { SEC_PROT_TX_ERR_UNSPEC = -2, // Other reason } sec_prot_tx_status_e; +// On security protocol send, do not deallocate pdu buffer +#define SEC_PROT_SEND_FLAG_NO_DEALLOC 0x01 + /** * sec_prot_create_request KMP-CREATE.request to security protocol * @@ -128,6 +131,7 @@ typedef void sec_prot_finished_send(sec_prot_t *prot); * \param prot protocol * \param pdu pdu * \param size pdu size + * \param conn_number connection number * * \return < 0 failure * \return >= 0 success @@ -148,6 +152,35 @@ 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_conn_receive receive a message for a connection number + * + * \param prot protocol + * \param pdu pdu + * \param size pdu size + * \param conn_number connection number + * + * \return < 0 failure + * \return >= 0 success + * + */ +typedef int8_t sec_prot_conn_receive(sec_prot_t *prot, void *pdu, uint16_t size, uint8_t conn_number); + +/** + * sec_prot_conn_send send a message for a connection number and/or with flags + * + * \param prot protocol + * \param pdu pdu + * \param size pdu size + * \param conn_number connection number + * \param flags flags + * + * \return < 0 failure + * \return >= 0 success + * + */ +typedef int8_t sec_prot_conn_send(sec_prot_t *prot, void *pdu, uint16_t size, uint8_t conn_number, uint8_t flags); + /** * sec_prot_tx_status_ind tx status indication * @@ -184,6 +217,14 @@ typedef void sec_prot_state_machine(sec_prot_t *prot); */ typedef void sec_prot_state_machine_call(sec_prot_t *prot); +/** + * sec_prot_cont_timer_timeout cont timer timeout + * + * \param ticks timer ticks + * + */ +typedef void sec_prot_cont_timer_timeout(uint16_t ticks); + /** * sec_prot_timer_start start timer * @@ -209,6 +250,55 @@ typedef void sec_prot_timer_stop(sec_prot_t *prot); */ typedef void sec_prot_timer_timeout(sec_prot_t *prot, uint16_t ticks); +/** + * sec_prot_shared_comp_timer_timeout shared component timer timeout + * + * \param ticks timer ticks + * + * \return < 0 failure + * \return >= 0 success + * + */ +typedef int8_t sec_prot_shared_comp_timer_timeout(uint16_t ticks); + +/** + * sec_prot_shared_comp_delete shared component delete + * + * \return < 0 failure + * \return >= 0 success + * + */ +typedef int8_t sec_prot_shared_comp_delete(void); + +typedef struct { + sec_prot_shared_comp_timer_timeout *timeout; + sec_prot_shared_comp_delete *delete; +} shared_comp_data_t; + +/** + * sec_prot_shared_comp_add add shared component + * + * \param prot protocol + * \param data shared component data + * + * \return < 0 failure + * \return >= 0 success + * + */ +typedef int8_t sec_prot_shared_comp_add(sec_prot_t *prot, shared_comp_data_t *data); + +/** + * sec_prot_shared_comp_remove remove shared component + * + * \param prot protocol + * \param data shared component data + * + * \return < 0 failure + * \return >= 0 success + * + */ +typedef int8_t sec_prot_shared_comp_remove(sec_prot_t *prot, shared_comp_data_t *data); + /** * sec_prot_eui64_addr_get gets EUI-64 addresses * @@ -277,7 +367,10 @@ struct sec_prot_s { sec_prot_send *send; /**< Protocol send */ sec_prot_receive *receive; /**< Protocol receive */ + sec_prot_conn_send *conn_send; /**< Protocol connection send */ + sec_prot_conn_receive *conn_receive; /**< Protocol connection receive */ sec_prot_receive *receive_peer; /**< Protocol receive from peer (used by peer protocol for send) */ + sec_prot_delete *peer_deleted; /**< Protocol peer has been deleted (notifies that peer no longer exists */ sec_prot_tx_status_ind *tx_status_ind; /**< TX status indication */ @@ -290,6 +383,9 @@ struct sec_prot_s { sec_prot_timer_stop *timer_stop; /**< Stop timer */ sec_prot_timer_timeout *timer_timeout; /**< Timer timeout */ + sec_prot_shared_comp_add *shared_comp_add; /**< Shared component add */ + sec_prot_shared_comp_remove *shared_comp_remove; /**< Shared component remove */ + sec_prot_eui64_addr_get *addr_get; /**< Gets EUI-64 addresses */ sec_prot_ip_addr_get *ip_addr_get; /**< Gets IP address */ sec_prot_by_type_get *type_get; /**< Gets security protocol by type */ @@ -300,6 +396,7 @@ struct sec_prot_s { sec_cfg_t *sec_cfg; /**< Security configuration configuration pointer */ uint8_t header_size; /**< Header size */ uint8_t receive_peer_hdr_size; /**< Receive from peer header size */ + uint8_t number_of_conn; /**< Number of connections */ uint8_t msg_if_instance_id; /**< Message interface instance identifier */ sec_prot_int_data_t *data; /**< Protocol internal data */ }; diff --git a/connectivity/nanostack/sal-stack-nanostack/source/Security/protocols/sec_prot_cfg.h b/connectivity/nanostack/sal-stack-nanostack/source/Security/protocols/sec_prot_cfg.h index b7bed75d1fc..dd75e2c226d 100644 --- a/connectivity/nanostack/sal-stack-nanostack/source/Security/protocols/sec_prot_cfg.h +++ b/connectivity/nanostack/sal-stack-nanostack/source/Security/protocols/sec_prot_cfg.h @@ -47,15 +47,16 @@ typedef struct sec_timer_cfg_s { typedef struct sec_radius_cfg_s { uint8_t radius_addr[16]; /**< Radius server IPv6 address */ - uint8_t *radius_shared_secret; /**< Radius shared secret */ + const uint8_t *radius_shared_secret; /**< Radius shared secret */ uint16_t radius_shared_secret_len; /**< Radius shared secret length */ + trickle_params_t radius_retry_trickle_params; /**< Radius retry trickle params */ bool radius_addr_set : 1; /**< Radius server address is set */ } sec_radius_cfg_t; typedef struct sec_cfg_s { sec_prot_cfg_t prot_cfg; sec_timer_cfg_t timer_cfg; - sec_radius_cfg_t radius_cfg; + sec_radius_cfg_t *radius_cfg; } sec_cfg_t; #endif /* SEC_PROT_CONF_H_ */ diff --git a/connectivity/nanostack/sal-stack-nanostack/source/Service_Libs/fhss/fhss_ws.c b/connectivity/nanostack/sal-stack-nanostack/source/Service_Libs/fhss/fhss_ws.c index d37ff27a77f..78cb5154d57 100644 --- a/connectivity/nanostack/sal-stack-nanostack/source/Service_Libs/fhss/fhss_ws.c +++ b/connectivity/nanostack/sal-stack-nanostack/source/Service_Libs/fhss/fhss_ws.c @@ -419,7 +419,7 @@ static uint32_t fhss_ws_calculate_ufsi(fhss_structure_t *fhss_structure, uint32_ cur_slot--; uint32_t remaining_time_ms = 0; if (fhss_structure->ws->unicast_timer_running == true) { - remaining_time_ms = US_TO_MS(get_remaining_slots_us(fhss_structure, fhss_unicast_handler, MS_TO_US(dwell_time) - NS_TO_US(dwell_time * fhss_structure->ws->drift_per_millisecond_ns))); + remaining_time_ms = US_TO_MS(get_remaining_slots_us(fhss_structure, fhss_unicast_handler, MS_TO_US(dwell_time) - NS_TO_US((int64_t)(fhss_structure->ws->drift_per_millisecond_ns * dwell_time)))); } uint32_t time_to_tx = 0; uint32_t cur_time = fhss_structure->callbacks.read_timestamp(fhss_structure->fhss_api); @@ -859,13 +859,13 @@ static uint32_t fhss_ws_get_retry_period_callback(const fhss_api_t *api, uint8_t if (!fhss_structure) { return return_value; } - // We don't know the broadcast schedule, use large backoff with MAC retries + // We don't know the broadcast schedule, use randomised large backoff with MAC retries if (fhss_structure->ws->broadcast_timer_running == false) { - return 100000; + return (uint32_t) randLIB_get_random_in_range(20000, 45000); } // We don't know the TX/RX slots, use randomised large backoff with MAC retries if (fhss_structure->own_hop == 0xff) { - return ((uint32_t) randLIB_get_random_in_range(50, 150) * 1000); + return (uint32_t) randLIB_get_random_in_range(20000, 45000); } if (fhss_structure->ws->is_on_bc_channel == true) { return return_value; @@ -980,7 +980,6 @@ int fhss_ws_set_parent(fhss_structure_t *fhss_structure, const uint8_t eui64[8], if (fhss_structure->ws->fhss_configuration.ws_bc_channel_function == WS_TR51CF) { fhss_structure->ws->bc_slot %= fhss_structure->number_of_channels; } - platform_exit_critical(); //TODO: support multiple parents fhss_structure->ws->parent_bc_info = bc_timing_info; if (prev_synchronization_time && fhss_structure->ws->fhss_configuration.ws_bc_channel_function != WS_FIXED_CHANNEL) { @@ -993,11 +992,15 @@ int fhss_ws_set_parent(fhss_structure_t *fhss_structure, const uint8_t eui64[8], } else if (drift_per_ms_tmp < -MAX_DRIFT_COMPENSATION_STEP) { drift_per_ms_tmp = -MAX_DRIFT_COMPENSATION_STEP; } + // Timer drift is unpredictable with linux platform. Do not set drift compensation +#ifndef __linux__ fhss_structure->ws->drift_per_millisecond_ns += drift_per_ms_tmp; +#endif fhss_stats_update(fhss_structure, STATS_FHSS_DRIFT_COMP, NS_TO_US((int64_t)(fhss_structure->ws->drift_per_millisecond_ns * bc_timing_info->broadcast_dwell_interval))); } tr_debug("synch to parent: %s, drift: %"PRIi32"ms in %"PRIu64" seconds, compensation: %"PRIi32"ns per ms", trace_array(eui64, 8), true_bc_interval_offset - own_bc_interval_offset + ((int32_t)(fhss_structure->ws->bc_slot - own_bc_slot) * bc_timing_info->broadcast_interval), US_TO_S(time_since_last_synch_us), fhss_structure->ws->drift_per_millisecond_ns); } + platform_exit_critical(); fhss_stats_update(fhss_structure, STATS_FHSS_SYNCH_INTERVAL, US_TO_S(time_since_last_synch_us)); return 0; } diff --git a/connectivity/nanostack/sal-stack-nanostack/source/libDHCPv6/dhcp_service_api.c b/connectivity/nanostack/sal-stack-nanostack/source/libDHCPv6/dhcp_service_api.c index 47c09ec5e26..c720a14c01b 100644 --- a/connectivity/nanostack/sal-stack-nanostack/source/libDHCPv6/dhcp_service_api.c +++ b/connectivity/nanostack/sal-stack-nanostack/source/libDHCPv6/dhcp_service_api.c @@ -86,10 +86,18 @@ typedef struct { } msg_tr_t; typedef NS_LIST_HEAD(msg_tr_t, link) tr_list_t; +typedef struct { + dhcp_relay_neighbour_cb *recv_notify_cb; + int8_t interface_id; + ns_list_link_t link; +} relay_notify_t; +typedef NS_LIST_HEAD(relay_notify_t, link) relay_notify_list_t; + typedef struct { ns_address_t src_address; server_instance_list_t srv_list; relay_instance_list_t relay_list; + relay_notify_list_t notify_list; tr_list_t tr_list; int8_t dhcp_server_socket; int8_t dhcp_client_socket; @@ -134,6 +142,7 @@ bool dhcp_service_allocate(void) if (dhcp_service) { ns_list_init(&dhcp_service->srv_list); ns_list_init(&dhcp_service->relay_list); + ns_list_init(&dhcp_service->notify_list); ns_list_init(&dhcp_service->tr_list); dhcp_service->dhcp_client_socket = -1; dhcp_service->dhcp_server_socket = -1; @@ -255,6 +264,16 @@ static uint16_t dhcp_service_relay_interface_get(int8_t interface_id) return 0; } +static relay_notify_t *dhcp_service_notify_find(int8_t interface_id) +{ + relay_notify_t *result = NULL; + ns_list_foreach(relay_notify_t, cur_ptr, &dhcp_service->notify_list) { + if (cur_ptr->interface_id == interface_id) { + result = cur_ptr; + } + } + return result; +} static relay_instance_t *dhcp_service_relay_find(uint16_t instance_id) @@ -294,6 +313,8 @@ void recv_dhcp_server_msg(void *cb_res) if (sckt_data->event_type != SOCKET_DATA || sckt_data->d_len < 4) { return; } + relay_notify_t *neigh_notify = NULL; + tr_debug("dhcp Server recv request"); msg_tr_ptr = dhcp_tr_create(); msg_ptr = ns_dyn_mem_temporary_alloc(sckt_data->d_len); @@ -322,6 +343,9 @@ void recv_dhcp_server_msg(void *cb_res) } else if (msg_type == DHCPV6_RELAY_REPLY) { tr_error("Relay reply drop at server"); goto cleanup; + } else { + //Search only for direct messages here + neigh_notify = dhcp_service_notify_find(sckt_data->interface_id); } //TODO use real function from lib also call validity check @@ -331,6 +355,11 @@ void recv_dhcp_server_msg(void *cb_res) tr_error("Malformed packet"); goto cleanup; } + + if (neigh_notify && neigh_notify->recv_notify_cb) { + neigh_notify->recv_notify_cb(sckt_data->interface_id, msg_tr_ptr->addr.address); + } + msg_tr_ptr->socket = sckt_data->socket_id; // call all receivers until found. ns_list_foreach(server_instance_t, cur_ptr, &dhcp_service->srv_list) { @@ -451,6 +480,12 @@ void recv_dhcp_relay_msg(void *cb_res) libdhcpv6_dhcp_relay_msg_write(relay_frame, DHCPV6_RELAY_FORWARD, 0, src_address.address, gp_address); libdhcpv6_dhcp_option_header_write(relay_frame + 34, msg_len); + //Update Neighbour table if necessary + relay_notify_t *neigh_notify = dhcp_service_notify_find(sckt_data->interface_id); + if (neigh_notify && neigh_notify->recv_notify_cb) { + neigh_notify->recv_notify_cb(sckt_data->interface_id, src_address.address); + } + //Copy DST address memcpy(src_address.address, relay_srv->server_address, 16); src_address.type = ADDRESS_IPV6; @@ -884,6 +919,31 @@ bool dhcp_service_timer_tick(uint16_t ticks) } return activeTimerNeed; } + +int dhcp_service_link_local_rx_cb_set(int8_t interface_id, dhcp_relay_neighbour_cb *notify_cb) +{ + if (dhcp_service == NULL) { + return -1; + } + + relay_notify_t *notify_srv = dhcp_service_notify_find(interface_id); + if (notify_srv) { + notify_srv->recv_notify_cb = notify_cb; + return 0; + } + + + notify_srv = ns_dyn_mem_alloc(sizeof(relay_notify_t)); + if (!notify_srv) { + return -1; + } + ns_list_add_to_start(&dhcp_service->notify_list, notify_srv); + + notify_srv->recv_notify_cb = notify_cb; + notify_srv->interface_id = interface_id; + return 0; +} + #else uint16_t dhcp_service_init(int8_t interface_id, dhcp_instance_type_e instance_type, dhcp_service_receive_req_cb *receive_req_cb) { @@ -948,4 +1008,11 @@ void dhcp_service_req_remove_all(void *msg_class_ptr) (void)msg_class_ptr; } +int dhcp_service_link_local_rx_cb_set(int8_t interface_id, dhcp_relay_neighbour_cb *notify_cb) +{ + (void) interface_id; + (void) notify_cb; + return -1; +} + #endif diff --git a/connectivity/nanostack/sal-stack-nanostack/source/libDHCPv6/libDHCPv6.c b/connectivity/nanostack/sal-stack-nanostack/source/libDHCPv6/libDHCPv6.c index 7b021aba399..722e41f46e1 100644 --- a/connectivity/nanostack/sal-stack-nanostack/source/libDHCPv6/libDHCPv6.c +++ b/connectivity/nanostack/sal-stack-nanostack/source/libDHCPv6/libDHCPv6.c @@ -234,6 +234,10 @@ dhcpv6_client_server_data_t *libdhcpv6_nonTemporal_validate_class_pointer(void * return NULL; } +uint16_t libdhcpv6_vendor_option_size(uint16_t vendor_data_length) +{ + return vendor_data_length + 8; // ID Type 2, length 2 ,Enterpise number 4 +} uint16_t libdhcpv6_duid_option_size(uint16_t duidLength) { @@ -324,15 +328,6 @@ uint8_t *libdhcpv6_rapid_commit_option_write(uint8_t *ptr) return ptr; } -uint8_t *libdhcvp6_vendor_specific_option_write(uint8_t *ptr, uint8_t *data, uint16_t dataLength) -{ - ptr = common_write_16_bit(DHCPV6_OPTION_VENDOR_SPECIFIC_INFO, ptr); - ptr = common_write_16_bit(dataLength, ptr); - memcpy(ptr, data, dataLength); - ptr += dataLength; - return ptr; -} - uint8_t *libdhcvp6_request_option_write(uint8_t *ptr, uint8_t optionCnt, uint16_t *optionPtr) { uint16_t optionLength = libdhcvp6_request_option_size(optionCnt); @@ -840,31 +835,6 @@ uint8_t *libdhcpv6_generic_nontemporal_address_message_write(uint8_t *ptr, dhcpv return ptr; } - -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) -{ - ptr = libdhcpv6_header_write(ptr, DHCPV6_REPLY_TYPE, replyPacket->transaction_ID); - ptr = libdhcpv6_duid_option_write(ptr, DHCPV6_SERVER_ID_OPTION, &replyPacket->serverDUID); //16 - ptr = libdhcpv6_duid_option_write(ptr, DHCPV6_CLIENT_ID_OPTION, &replyPacket->clientDUID); //16 - - if (nonTemporalAddress) { - ptr = libdhcpv6_identity_association_option_write(ptr, replyPacket->iaId, replyPacket->T0, replyPacket->T1, true); - ptr = libdhcpv6_ia_address_option_write(ptr, nonTemporalAddress->requestedAddress, nonTemporalAddress->preferredLifeTime, nonTemporalAddress->validLifeTime); - } else { - ptr = libdhcpv6_identity_association_option_write_with_status(ptr, replyPacket->iaId, replyPacket->T0, replyPacket->T1, DHCPV6_STATUS_NO_ADDR_AVAILABLE_CODE); - } - - if (vendorData) { - ptr = libdhcvp6_vendor_specific_option_write(ptr, vendorData->vendorData, vendorData->vendorDataLength); - } - - if (replyPacket->rapidCommit) { - ptr = libdhcpv6_rapid_commit_option_write(ptr); - } - - return ptr; -} - uint16_t libdhcpv6_solication_message_length(uint16_t clientDUIDLength, bool addressDefined, uint8_t requestOptionCount) { uint16_t length = 0; diff --git a/connectivity/nanostack/sal-stack-nanostack/source/libDHCPv6/libDHCPv6.h b/connectivity/nanostack/sal-stack-nanostack/source/libDHCPv6/libDHCPv6.h index c495a18fe44..dd2bd6309fe 100644 --- a/connectivity/nanostack/sal-stack-nanostack/source/libDHCPv6/libDHCPv6.h +++ b/connectivity/nanostack/sal-stack-nanostack/source/libDHCPv6/libDHCPv6.h @@ -217,9 +217,13 @@ typedef struct dhcpv6_relay_msg { #define DHCPV6_OPTION_IA_PREFIX_DELEGATION_MIN_LENGTH 0x000c /** Identity Association END */ +#define DHCPV6_OPTION_VENDOR_CLASS 0x0010 #define DHCPV6_OPTION_VENDOR_SPECIFIC_INFO 0x0011 /** SEQUENCYID, RouterIDMask 32-bit*/ +#define DHCPV6_OPTION_DNS_SERVERS 0x0017 +#define DHCPV6_OPTION_DOMAIN_LIST 0x0018 + #define DHCPV6_STATUS_CODE_OPTION 0x000d #define DHCPV6_STATUS_CODE_OPTION_LEN 0x0002 #define DHCPV6_STATUS_NO_ADDR_AVAILABLE_CODE 0x0002 @@ -277,6 +281,7 @@ 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_vendor_option_size(uint16_t vendor_data_length); 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); @@ -287,7 +292,6 @@ uint16_t libdhcpv6_address_reply_message_len(uint16_t clientDUIDLength, uint16_t #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_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); @@ -327,17 +331,6 @@ uint8_t *libdhcpv6_elapsed_time_option_write(uint8_t *ptr, uint16_t elapsedTime) */ uint8_t *libdhcpv6_rapid_commit_option_write(uint8_t *ptr); -/** - * This Function write dhcpv6 thread requested vendor spesific data - * - * \param ptr pointer where option will be writed - * \param data Vendor Data - * \param dataLength Vendor Data length - * - * return incremented pointer after write - */ -uint8_t *libdhcvp6_vendor_specific_option_write(uint8_t *ptr, uint8_t *data, uint16_t dataLength); - /** * This Function write dhcpv6 request option write * @@ -379,6 +372,6 @@ int libdhcpv6_solication_message_options_validate(uint8_t *ptr, uint16_t data_le 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); +bool libdhcpv6_relay_msg_read(uint8_t *ptr, uint16_t length, dhcpv6_relay_msg_t *relay_msg); #endif /* LIBDHCPV6_H_ */ diff --git a/connectivity/nanostack/sal-stack-nanostack/source/libDHCPv6/libDHCPv6_server.c b/connectivity/nanostack/sal-stack-nanostack/source/libDHCPv6/libDHCPv6_server.c index f3c0ccba8c6..d324c812691 100644 --- a/connectivity/nanostack/sal-stack-nanostack/source/libDHCPv6/libDHCPv6_server.c +++ b/connectivity/nanostack/sal-stack-nanostack/source/libDHCPv6/libDHCPv6_server.c @@ -58,6 +58,8 @@ static dhcpv6_gua_server_entry_s *libdhcpv6_server_entry_allocate(void) entry->removeCb = NULL; entry->addCb = NULL; ns_list_init(&entry->allocatedAddressList); + ns_list_init(&entry->dnsServerList); + ns_list_init(&entry->vendorDataList); return entry; } @@ -338,6 +340,20 @@ void libdhcpv6_gua_server_free_by_prefix_and_interfaceid(uint8_t *prefix, int8_t ns_list_remove(&serverInfo->allocatedAddressList, cur); ns_dyn_mem_free(cur); } + + ns_list_foreach_safe(dhcpv6_dns_server_data_t, cur, &serverInfo->dnsServerList) { + //DNS Server Info Remove + ns_list_remove(&serverInfo->dnsServerList, cur); + ns_dyn_mem_free(cur->search_list); + ns_dyn_mem_free(cur); + } + + ns_list_foreach_safe(dhcpv6_vendor_data_t, cur, &serverInfo->vendorDataList) { + ns_list_remove(&serverInfo->vendorDataList, cur); + ns_dyn_mem_free(cur->vendor_data); + 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); @@ -494,5 +510,119 @@ dhcpv6_allocated_address_t *libdhcpv6_address_allocated_list_scan(dhcpv6_gua_ser return newEntry; } +dhcpv6_dns_server_data_t *libdhcpv6_dns_server_discover(dhcpv6_gua_server_entry_s *serverInfo, const uint8_t *address) +{ + ns_list_foreach(dhcpv6_dns_server_data_t, cur, &serverInfo->dnsServerList) { + if (memcmp(cur->server_address, address, 16) == 0) { + return cur; + } + } + return NULL; +} + +dhcpv6_dns_server_data_t *libdhcpv6_dns_server_allocate(dhcpv6_gua_server_entry_s *serverInfo, const uint8_t *address) +{ + dhcpv6_dns_server_data_t *entry = libdhcpv6_dns_server_discover(serverInfo, address); + if (entry) { + return entry; + } + + entry = ns_dyn_mem_alloc(sizeof(dhcpv6_dns_server_data_t)); + if (!entry) { + return NULL; + } + ns_list_add_to_end(&serverInfo->dnsServerList, entry); + memcpy(entry->server_address, address, 16); + entry->search_list = NULL; + entry->search_list_length = 0; + return entry; +} + +dhcpv6_vendor_data_t *libdhcpv6_vendor_data_discover(dhcpv6_gua_server_entry_s *serverInfo, uint32_t enterprise_number) +{ + ns_list_foreach(dhcpv6_vendor_data_t, cur, &serverInfo->vendorDataList) { + if (cur->enterprise_number == enterprise_number) { + return cur; + } + } + return NULL; +} + +dhcpv6_vendor_data_t *libdhcpv6_vendor_data_allocate(dhcpv6_gua_server_entry_s *serverInfo, uint32_t enterprise_number) +{ + dhcpv6_vendor_data_t *entry = libdhcpv6_vendor_data_discover(serverInfo, enterprise_number); + + if (entry) { + return entry; + } + + entry = ns_dyn_mem_alloc(sizeof(dhcpv6_vendor_data_t)); + if (!entry) { + return NULL; + } + ns_list_add_to_end(&serverInfo->vendorDataList, entry); + entry->enterprise_number = enterprise_number; + entry->vendor_data = NULL; + entry->vendor_data_length = 0; + return entry; +} + + +uint16_t libdhcpv6_dns_server_message_sizes(dhcpv6_gua_server_entry_s *serverInfo) +{ + uint16_t message_size = 0; + ns_list_foreach(dhcpv6_dns_server_data_t, cur, &serverInfo->dnsServerList) { + message_size += 4 + 16; //Type Length + address // + //Search List part + message_size += 4 + cur->search_list_length; //Type Length + search_list_length + } + return message_size; +} + +uint16_t libdhcpv6_vendor_data_message_sizes(dhcpv6_gua_server_entry_s *serverInfo) +{ + uint16_t message_size = 0; + ns_list_foreach(dhcpv6_vendor_data_t, cur, &serverInfo->vendorDataList) { + message_size += 4 + 4 + cur->vendor_data_length; //Type + Length + enterprise + vendor_data_length + } + return message_size; +} + +uint8_t *libdhcpv6_dns_server_message_writes(dhcpv6_gua_server_entry_s *serverInfo, uint8_t *ptr) +{ + ns_list_foreach(dhcpv6_dns_server_data_t, cur, &serverInfo->dnsServerList) { + //Write first DNS Server info + ptr = common_write_16_bit(DHCPV6_OPTION_DNS_SERVERS, ptr); + ptr = common_write_16_bit(16, ptr); //Length + memcpy(ptr, cur->server_address, 16); + ptr += 16; + + ptr = common_write_16_bit(DHCPV6_OPTION_DOMAIN_LIST, ptr); + ptr = common_write_16_bit(cur->search_list_length, ptr); //Length + if (cur->search_list_length) { + memcpy(ptr, cur->search_list, cur->search_list_length); + ptr += cur->search_list_length; + } + } + return ptr; +} + +uint8_t *libdhcpv6_vendor_data_message_writes(dhcpv6_gua_server_entry_s *serverInfo, uint8_t *ptr) +{ + ns_list_foreach(dhcpv6_vendor_data_t, cur, &serverInfo->vendorDataList) { + + uint16_t length = cur->vendor_data_length + 4; + ptr = common_write_16_bit(DHCPV6_OPTION_VENDOR_SPECIFIC_INFO, ptr); + ptr = common_write_16_bit(length, ptr); //Length + ptr = common_write_32_bit(cur->enterprise_number, ptr); + if (cur->vendor_data_length) { + memcpy(ptr, cur->vendor_data, cur->vendor_data_length); + ptr += cur->vendor_data_length; + } + } + return ptr; +} + + #endif diff --git a/connectivity/nanostack/sal-stack-nanostack/source/libDHCPv6/libDHCPv6_server.h b/connectivity/nanostack/sal-stack-nanostack/source/libDHCPv6/libDHCPv6_server.h index 3b4c0643e2e..3ea3e5f2abb 100644 --- a/connectivity/nanostack/sal-stack-nanostack/source/libDHCPv6/libDHCPv6_server.h +++ b/connectivity/nanostack/sal-stack-nanostack/source/libDHCPv6/libDHCPv6_server.h @@ -45,6 +45,20 @@ typedef struct dhcpv6_allocated_address_entry_s { ns_list_link_t link; /*!< List link entry */ } dhcpv6_allocated_address_entry_t; +typedef struct dhcpv6_dns_server_data_s { + uint8_t server_address[16]; + uint8_t *search_list; + uint8_t search_list_length; + ns_list_link_t link; /*!< List link entry */ +} dhcpv6_dns_server_data_t; + +typedef struct dhcpv6_vendor_data_s { + uint32_t enterprise_number; + uint8_t *vendor_data; + uint8_t vendor_data_length; + ns_list_link_t link; /*!< List link entry */ +} dhcpv6_vendor_data_t; + typedef struct dhcpv6_allocated_address_s { uint8_t nonTemporalAddress[16]; @@ -58,6 +72,8 @@ typedef struct dhcpv6_allocated_address_s { } dhcpv6_allocated_address_t; typedef NS_LIST_HEAD(dhcpv6_allocated_address_entry_t, link) dhcpv6_allocated_address_list_t; +typedef NS_LIST_HEAD(dhcpv6_dns_server_data_t, link) dhcpv6_dns_server_list_t; +typedef NS_LIST_HEAD(dhcpv6_vendor_data_t, link) dhcpv6_vendor_data_list_t; typedef struct dhcp_address_cache_update { uint8_t *allocatedAddress; @@ -84,6 +100,8 @@ typedef struct dhcpv6_gua_server_entry_s { dhcp_address_prefer_remove_cb *removeCb; dhcp_address_add_notify_cb *addCb; dhcpv6_allocated_address_list_t allocatedAddressList; + dhcpv6_dns_server_list_t dnsServerList; + dhcpv6_vendor_data_list_t vendorDataList; dhcpv6_allocated_address_t tempAddressEntry; ns_list_link_t link; /*!< List link entry */ } dhcpv6_gua_server_entry_s; @@ -99,6 +117,14 @@ dhcpv6_gua_server_entry_s *libdhcpv6_server_data_get_by_prefix_and_interfaceid(i dhcpv6_gua_server_entry_s *libdhcpv6_server_data_get_by_prefix_and_socketinstance(uint16_t socketInstance, uint8_t *prefixPtr); dhcpv6_allocated_address_t *libdhcpv6_address_allocated_list_scan(dhcpv6_gua_server_entry_s *serverInfo, uint8_t *euid64, uint16_t linkType, uint32_t iaID, uint32_t T0, uint32_t T1, bool allocateNew); void libdhcpv6_allocated_address_write(uint8_t *ptr, dhcpv6_allocated_address_entry_t *address, dhcpv6_gua_server_entry_s *serverInfo); +dhcpv6_dns_server_data_t *libdhcpv6_dns_server_discover(dhcpv6_gua_server_entry_s *serverInfo, const uint8_t *address); +dhcpv6_dns_server_data_t *libdhcpv6_dns_server_allocate(dhcpv6_gua_server_entry_s *serverInfo, const uint8_t *address); +dhcpv6_vendor_data_t *libdhcpv6_vendor_data_discover(dhcpv6_gua_server_entry_s *serverInfo, uint32_t enterprise_number); +dhcpv6_vendor_data_t *libdhcpv6_vendor_data_allocate(dhcpv6_gua_server_entry_s *serverInfo, uint32_t enterprise_number); +uint16_t libdhcpv6_dns_server_message_sizes(dhcpv6_gua_server_entry_s *serverInfo); +uint16_t libdhcpv6_vendor_data_message_sizes(dhcpv6_gua_server_entry_s *serverInfo); +uint8_t *libdhcpv6_dns_server_message_writes(dhcpv6_gua_server_entry_s *serverInfo, uint8_t *ptr); +uint8_t *libdhcpv6_vendor_data_message_writes(dhcpv6_gua_server_entry_s *serverInfo, uint8_t *ptr); #else #define libdhcpv6_gua_server_list_empty() true #define libdhcpv6_server_data_get_by_prefix_and_interfaceid(interfaceId, prefixPtr) NULL diff --git a/connectivity/nanostack/sal-stack-nanostack/source/libDHCPv6/libDHCPv6_vendordata.c b/connectivity/nanostack/sal-stack-nanostack/source/libDHCPv6/libDHCPv6_vendordata.c new file mode 100644 index 00000000000..2854517d5e3 --- /dev/null +++ b/connectivity/nanostack/sal-stack-nanostack/source/libDHCPv6/libDHCPv6_vendordata.c @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2020, Arm Limited and affiliates. + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "nsconfig.h" +#include "ns_types.h" +#include "ns_trace.h" +#include +#include "common_functions.h" +#include "libDHCPv6.h" +#include "libDHCPv6_vendordata.h" + +#define TRACE_GROUP "vend" + + +/* DHCPv6 vendor options to distribute ARM vendor data*/ + +uint16_t net_dns_option_vendor_option_data_dns_query_length(char *domain) +{ + return 4 + 16 + strlen(domain) + 1; +} + +uint8_t *net_dns_option_vendor_option_data_dns_query_write(uint8_t *ptr, uint8_t *address, char *domain) +{ + int domain_len = strlen(domain); + int length = 16 + domain_len + 1; + + ptr = common_write_16_bit(ARM_DHCP_VENDOR_DATA_DNS_QUERY_RESULT, ptr); + ptr = common_write_16_bit(length, ptr); + memcpy(ptr, address, 16); + ptr += 16; + memcpy(ptr, domain, domain_len + 1); + ptr += domain_len + 1; + return ptr; +} + +uint16_t net_dns_option_vendor_option_data_get_next(uint8_t *ptr, uint16_t length, uint16_t *type) +{ + uint16_t option_len; + + if (length < 4) { + // Corrupted + return 0; + } + if (type) { + *type = common_read_16_bit(ptr); + } + + option_len = common_read_16_bit(ptr + 2); + if (option_len + 4 > length) { + // Corrupted + return 0; + } + + return option_len + 4; +} + +uint16_t net_dns_option_vendor_option_data_dns_query_read(uint8_t *ptr, uint16_t length, uint8_t **address, char **domain) +{ + uint16_t option_len; + option_len = common_read_16_bit(ptr + 2); + + if (length < 4 + 16 + 1) { + // Corrupted as there is no room for all fields + return 0; + } + if (option_len < 17) { + // Corrupted as not enough room in field + return 0; + } + if (*(ptr + 4 + option_len - 1) != 0) { + // Not nul terminated string for domain + return 0; + } + + if (common_read_16_bit(ptr) != ARM_DHCP_VENDOR_DATA_DNS_QUERY_RESULT) { + return 0; + } + + if (address) { + *address = ptr + 4; + } + if (domain) { + *domain = (char *)(ptr + 4 + 16); + } + return option_len; +} diff --git a/connectivity/nanostack/sal-stack-nanostack/source/libDHCPv6/libDHCPv6_vendordata.h b/connectivity/nanostack/sal-stack-nanostack/source/libDHCPv6/libDHCPv6_vendordata.h new file mode 100644 index 00000000000..1a1ef44f7f6 --- /dev/null +++ b/connectivity/nanostack/sal-stack-nanostack/source/libDHCPv6/libDHCPv6_vendordata.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2020, Arm Limited and affiliates. + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef LIBDHCPV6_VENDOR_DATA_H_ +#define LIBDHCPV6_VENDOR_DATA_H_ + + +/*ARM enterprise number used to identify ARM generated Vendor data options*/ +#define ARM_ENTERPRISE_NUMBER 4128 + +/* ARM Defined vendor data option to distribute DNS query results through DHCP server + * Format + * + * uint8_t address[16] + * domain string nul terminated. + * + * multiple results must be in separated vendor option data fields + * */ +#define ARM_DHCP_VENDOR_DATA_DNS_QUERY_RESULT 297 + +/* DHCPv6 vendor options to distribute ARM vendor data*/ + +uint16_t net_dns_option_vendor_option_data_dns_query_length(char *domain); +uint8_t *net_dns_option_vendor_option_data_dns_query_write(uint8_t *ptr, uint8_t *address, char *domain); + +uint16_t net_dns_option_vendor_option_data_get_next(uint8_t *ptr, uint16_t length, uint16_t *type); +uint16_t net_dns_option_vendor_option_data_dns_query_read(uint8_t *ptr, uint16_t length, uint8_t **address, char **domain); + + +#endif /* LIBDHCPV6_VENDOR_DATA_H_ */ diff --git a/connectivity/nanostack/sal-stack-nanostack/source/libNET/src/net_dns.c b/connectivity/nanostack/sal-stack-nanostack/source/libNET/src/net_dns.c new file mode 100644 index 00000000000..b7c7c3eec5f --- /dev/null +++ b/connectivity/nanostack/sal-stack-nanostack/source/libNET/src/net_dns.c @@ -0,0 +1,330 @@ +/* + * Copyright (c) 2020, Arm Limited and affiliates. + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "nsconfig.h" +#include "ns_types.h" +#include "ns_trace.h" +#include +#include "net_dns_internal.h" +#include "net_interface.h" +#include "NWK_INTERFACE/Include/protocol.h" +#include "nsdynmemLIB.h" +#include "ns_list.h" +#include "libNET/src/net_dns_internal.h" +#define TRACE_GROUP "Ndns" + + +typedef struct dns_server_info { + uint8_t address[16]; + uint8_t dns_server_address[16]; + uint32_t lifetime; + uint8_t *dns_search_list_ptr; + uint16_t dns_search_list_len; + int8_t interface_id; + ns_list_link_t link; +} dns_server_info_t; + +static NS_LIST_DEFINE(dns_server_list, dns_server_info_t, link); + +typedef struct dns_query { + uint8_t address[16]; + char *domain_str; + uint32_t lifetime; + int8_t interface_id; + ns_list_link_t link; +} dns_query_t; + +static NS_LIST_DEFINE(dns_query_list, dns_query_t, link); + +static dns_server_info_t *dns_server_info_find(int8_t interface_id, const uint8_t address[16]) +{ + dns_server_info_t *this = NULL; + ns_list_foreach(dns_server_info_t, cur_ptr, &dns_server_list) { + if (interface_id != -1 && cur_ptr->interface_id != interface_id) { + continue; + } + if (address && memcmp(cur_ptr->address, address, 16) == 0) { + this = cur_ptr; + break; + } + } + return this; +} + +static dns_server_info_t *dns_server_info_create(int8_t interface_id, const uint8_t address[16]) +{ + dns_server_info_t *this = ns_dyn_mem_alloc(sizeof(dns_server_info_t)); + + if (!this) { + return NULL; + } + + memset(this, 0, sizeof(dns_server_info_t)); + this->interface_id = interface_id; + memcpy(this->address, address, 16); + ns_list_add_to_start(&dns_server_list, this); + tr_debug("Create DNS entry for %s", trace_ipv6(address)); + + return this; +} + +static void dns_server_info_delete(dns_server_info_t *this) +{ + if (!this) { + return; + } + + tr_debug("delete DNS entry for %s", trace_ipv6(this->address)); + ns_list_remove(&dns_server_list, this); + ns_dyn_mem_free(this->dns_search_list_ptr); + ns_dyn_mem_free(this); +} + + +int8_t net_dns_server_address_set(int8_t interface_id, const uint8_t address[16], const uint8_t dns_server_address[16], uint32_t lifetime) +{ + dns_server_info_t *info_ptr; + + if (!address || interface_id < 0) { + return -1; + } + info_ptr = dns_server_info_find(interface_id, address); + + if (!dns_server_address || lifetime == 0) { + // Delete the entry + dns_server_info_delete(info_ptr); + return 0; + } + + if (!info_ptr) { + info_ptr = dns_server_info_create(interface_id, address); + } + info_ptr->lifetime = lifetime; + memcpy(info_ptr->dns_server_address, dns_server_address, 16); + tr_info("DNS Server: %s from: %s Lifetime: %lu", trace_ipv6(info_ptr->dns_server_address), trace_ipv6(info_ptr->address), (unsigned long) info_ptr->lifetime); + return 0; +} + +int8_t net_dns_server_search_list_set(int8_t interface_id, const uint8_t address[16], uint8_t *dns_search_list_ptr, uint8_t dns_search_list_len, uint32_t lifetime) +{ + dns_server_info_t *info_ptr; + + if (!address || interface_id < 0) { + return -1; + } + info_ptr = dns_server_info_find(interface_id, address); + + if (info_ptr && (!dns_search_list_ptr || lifetime == 0)) { + // remove search list information + tr_debug("DNS Search List clear"); + ns_dyn_mem_free(info_ptr->dns_search_list_ptr); + info_ptr->dns_search_list_ptr = NULL; + info_ptr->dns_search_list_len = 0; + return 0; + } + + if (!info_ptr) { + info_ptr = dns_server_info_create(interface_id, address); + if (!info_ptr) { + return -1; + } + info_ptr->lifetime = lifetime; + } + + if (info_ptr->dns_search_list_ptr && info_ptr->dns_search_list_len != dns_search_list_len) { + ns_dyn_mem_free(info_ptr->dns_search_list_ptr); + info_ptr->dns_search_list_ptr = NULL; + } + + if (!info_ptr->dns_search_list_ptr) { + info_ptr->dns_search_list_ptr = ns_dyn_mem_alloc(dns_search_list_len); + } + + if (!info_ptr->dns_search_list_ptr) { + return -2; + } + + memcpy(info_ptr->dns_search_list_ptr, dns_search_list_ptr, dns_search_list_len); + info_ptr->dns_search_list_len = dns_search_list_len; + tr_info("DNS Search List: %s Lifetime: %lu", trace_array(info_ptr->dns_search_list_ptr, info_ptr->dns_search_list_len), (unsigned long) info_ptr->lifetime); + + return 0; +} + +int8_t net_dns_server_get(int8_t interface_id, uint8_t dns_server_address[16], uint8_t **dns_search_list_ptr, uint8_t *dns_search_list_len, uint8_t index) +{ + dns_server_info_t *info_ptr = NULL; + uint8_t n = 0; + ns_list_foreach(dns_server_info_t, cur_ptr, &dns_server_list) { + if (interface_id != -1 && cur_ptr->interface_id != interface_id) { + continue; + } + if (index == n) { + info_ptr = cur_ptr; + break; + } + n++; + } + + if (!info_ptr) { + return -1; + } + if (dns_server_address) { + memcpy(dns_server_address, info_ptr->dns_server_address, 16); + } + if (dns_search_list_ptr) { + *dns_search_list_ptr = info_ptr->dns_search_list_ptr; + } + if (dns_search_list_len) { + *dns_search_list_len = info_ptr->dns_search_list_len; + } + return 0; +} + +/** + * Storage for DNS query results + */ + +static dns_query_t *dns_query_result_find(int8_t interface_id, const char *domain_str) +{ + dns_query_t *this = NULL; + ns_list_foreach(dns_query_t, cur_ptr, &dns_query_list) { + if (interface_id != -1 && cur_ptr->interface_id != interface_id) { + continue; + } + if (strcasecmp(cur_ptr->domain_str, domain_str) == 0) { + this = cur_ptr; + break; + } + } + return this; +} + +static dns_query_t *dns_query_result_create(int8_t interface_id, const char *domain_str) +{ + dns_query_t *this = NULL; + + if (!domain_str) { + return NULL; + } + this = ns_dyn_mem_alloc(sizeof(dns_query_t)); + if (!this) { + return NULL; + } + memset(this, 0, sizeof(dns_query_t)); + + this->domain_str = ns_dyn_mem_alloc(strlen(domain_str) + 1); + if (!this->domain_str) { + ns_dyn_mem_free(this); + return NULL; + } + this->interface_id = interface_id; + strcpy(this->domain_str, domain_str); + //tr_debug("Create DNS query entry for %s", this->domain_str); + ns_list_add_to_start(&dns_query_list, this); + return this; +} + +static void dns_query_result_delete(dns_query_t *this) +{ + if (!this) { + return; + } + + tr_debug("Delete DNS query entry for %s", this->domain_str); + ns_list_remove(&dns_query_list, this); + ns_dyn_mem_free(this->domain_str); + ns_dyn_mem_free(this); +} + +int8_t net_dns_query_result_set(int8_t interface_id, const uint8_t address[16], const char *domain_name_ptr, uint32_t lifetime) +{ + dns_query_t *this; + + if (!domain_name_ptr || interface_id < 0) { + return -1; + } + this = dns_query_result_find(interface_id, domain_name_ptr); + + if (!address || lifetime == 0) { + // Delete the entry + dns_query_result_delete(this); + return 0; + } + + if (!this) { + this = dns_query_result_create(interface_id, domain_name_ptr); + } + + if (!this) { + return -2; + } + // update address and lifetime also to old query results + memcpy(this->address, address, 16); + this->lifetime = lifetime; + tr_info("DNS query set: %s address %s Lifetime: %lu", this->domain_str, trace_ipv6(this->address), (unsigned long) this->lifetime); + + return 0; +} + +int8_t net_dns_query_result_get(int8_t interface_id, uint8_t address[16], const char *domain_name_ptr) +{ + dns_query_t *this; + + if (!domain_name_ptr) { + return -1; + } + this = dns_query_result_find(interface_id, domain_name_ptr); + + if (!this) { + return -1; + } + if (address) { + memcpy(address, this->address, 16); + } + + return 0; +} + +/** + * Generic timeout handler for all interfaces and entries. + */ +void net_dns_timer_seconds(uint32_t seconds) +{ + ns_list_foreach_safe(dns_query_t, cur_ptr, &dns_query_list) { + if (cur_ptr->lifetime == 0xffffffff) { + continue; + } + if (cur_ptr->lifetime <= seconds) { + dns_query_result_delete(cur_ptr); + continue; + } + cur_ptr->lifetime -= seconds; + } + + ns_list_foreach_safe(dns_server_info_t, cur_ptr, &dns_server_list) { + if (cur_ptr->lifetime == 0xffffffff) { + continue; + } + if (cur_ptr->lifetime <= seconds) { + dns_server_info_delete(cur_ptr); + continue; + } + cur_ptr->lifetime -= seconds; + } + return; +} diff --git a/connectivity/nanostack/sal-stack-nanostack/source/libNET/src/net_dns_internal.h b/connectivity/nanostack/sal-stack-nanostack/source/libNET/src/net_dns_internal.h new file mode 100644 index 00000000000..bd58dbb51b2 --- /dev/null +++ b/connectivity/nanostack/sal-stack-nanostack/source/libNET/src/net_dns_internal.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2020, Arm Limited and affiliates. + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef NET_DNS_INTERNAL_H_ +#define NET_DNS_INTERNAL_H_ + +/** + * These functions are used to store DNS server related information + * IF DNS information is learned from IPv6 Router advertisements + * or from the DHCPv6 elements + * + * Address is the link local address of the default router or DHCPv6 server address + */ + +int8_t net_dns_server_address_set(int8_t interface_id, const uint8_t address[16], const uint8_t dns_server_address[16], uint32_t lifetime); +int8_t net_dns_server_search_list_set(int8_t interface_id, const uint8_t address[16], uint8_t *dns_search_list_ptr, uint8_t dns_search_list_len, uint32_t lifetime); + +int8_t net_dns_server_get(int8_t interface_id, uint8_t dns_server_address[16], uint8_t **dns_search_list_ptr, uint8_t *dns_search_list_len, uint8_t index); + +/** + * Storage for DNS query results + */ + +int8_t net_dns_query_result_set(int8_t interface_id, const uint8_t address[16], const char *domain_name_ptr, uint32_t lifetime); + +int8_t net_dns_query_result_get(int8_t interface_id, uint8_t address[16], const char *domain_name_ptr); + +/** + * Generic timeout handler for all interfaces and entries. + */ +void net_dns_timer_seconds(uint32_t seconds); + +#endif /* NET_DNS_INTERNAL_H_ */ diff --git a/connectivity/nanostack/sal-stack-nanostack/source/libNET/src/ns_net.c b/connectivity/nanostack/sal-stack-nanostack/source/libNET/src/ns_net.c index ed35581c5e7..b863aa29922 100644 --- a/connectivity/nanostack/sal-stack-nanostack/source/libNET/src/ns_net.c +++ b/connectivity/nanostack/sal-stack-nanostack/source/libNET/src/ns_net.c @@ -61,6 +61,7 @@ #include "Security/Common/sec_lib_definitions.h" #include "ipv6_stack/protocol_ipv6.h" #include "ipv6_stack/ipv6_routing_table.h" +#include "libNET/src/net_dns_internal.h" #include "net_thread_test.h" #include "6LoWPAN/Thread/thread_common.h" #include "6LoWPAN/Thread/thread_routing.h" @@ -656,6 +657,24 @@ int8_t arm_net_address_delete_from_interface(int8_t interface_id, const uint8_t return addr_delete(cur, address); } +/* DNS cache functions + */ +int8_t arm_net_dns_server_get(int8_t interface_id, uint8_t address[16], uint8_t **dns_search_list_ptr, uint8_t *dns_search_list_len, uint8_t index) +{ + return net_dns_server_get(interface_id, address, dns_search_list_ptr, dns_search_list_len, index); +} + +int8_t arm_net_dns_query_result_set(int8_t interface_id, const uint8_t address[16], const char *domain_name_ptr, uint32_t lifetime) +{ + return net_dns_query_result_set(interface_id, address, domain_name_ptr, lifetime); +} + +int8_t arm_net_dns_query_result_get(int8_t interface_id, uint8_t address[16], char *domain_name_ptr) +{ + return net_dns_query_result_get(interface_id, address, domain_name_ptr); +} + + int8_t arm_net_route_add(const uint8_t *prefix, uint8_t prefix_len, const uint8_t *next_hop, uint32_t lifetime, uint8_t metric, int8_t interface_id) { ipv6_route_t *entry; @@ -682,7 +701,6 @@ int8_t arm_net_route_delete(const uint8_t *prefix, uint8_t prefix_len, const uin return ipv6_route_delete(prefix, prefix_len, interface_id, next_hop, ROUTE_USER); } - int8_t arm_nwk_interface_ethernet_init(eth_mac_api_t *api, const char *interface_name_ptr) { #ifdef HAVE_ETHERNET diff --git a/connectivity/nanostack/sal-stack-nanostack/sources.mk b/connectivity/nanostack/sal-stack-nanostack/sources.mk index 97b4113c207..2d895e803a7 100644 --- a/connectivity/nanostack/sal-stack-nanostack/sources.mk +++ b/connectivity/nanostack/sal-stack-nanostack/sources.mk @@ -67,6 +67,7 @@ SRCS += \ source/libNET/src/net_mle.c \ source/libNET/src/net_rpl.c \ source/libNET/src/net_load_balance.c \ + source/libNET/src/net_dns.c \ source/libNET/src/ns_net.c \ source/libNET/src/socket_api.c \ source/libNET/src/multicast_api.c \ @@ -204,6 +205,7 @@ SRCS += \ source/DHCPv6_client/dhcpv6_client_service.c \ source/libDHCPv6/dhcp_service_api.c \ source/libDHCPv6/libDHCPv6.c \ + source/libDHCPv6/libDHCPv6_vendordata.c \ source/libDHCPv6/libDHCPv6_server.c \ source/Service_Libs/utils/ns_crc.c \ source/Service_Libs/utils/isqrt.c \