From 1ad46bb6f1fb40805aa9f72ccb50c87335febed7 Mon Sep 17 00:00:00 2001 From: Arto Kinnunen Date: Fri, 4 Sep 2020 13:53:21 +0300 Subject: [PATCH] Squashed 'features/nanostack/sal-stack-nanostack/' changes from 91acececbd..d879e6db87 d879e6db87 Merge branch 'release_internal' into release_external eef9246079 Fixed network border router timeout recovery and EAPOL relay address fix bac7ca6852 Changed RADIUS MTU and small fixes a9f8b756e1 Addeed support for DHCP vendor data d8f00036f5 DHCPv6 functionality update 7fe04231ed Added DHCPv6 vendor data generation for DNS queries 639f9dbfb2 FHSS: Changed retry backoffs when no BC schedule or TX slots (#2440) git-subtree-dir: features/nanostack/sal-stack-nanostack git-subtree-split: d879e6db8791115ce435d8804238ba38d43e78f8 --- nanostack/ws_bbr_api.h | 3 +- source/6LoWPAN/ws/ws_bbr_api.c | 112 +++++++++++++-- source/6LoWPAN/ws/ws_bootstrap.c | 83 ++++++++++- source/6LoWPAN/ws/ws_config.h | 7 + source/6LoWPAN/ws/ws_eapol_relay.c | 7 +- source/6LoWPAN/ws/ws_pae_controller.c | 3 +- source/Common_Protocols/icmpv6.c | 18 ++- source/DHCPv6_Server/DHCPv6_Server_service.c | 86 +++++++++++- source/DHCPv6_Server/DHCPv6_server_service.h | 5 + source/DHCPv6_client/dhcpv6_client_api.h | 40 ++++++ source/DHCPv6_client/dhcpv6_client_service.c | 77 +++++++++++ source/Security/kmp/kmp_socket_if.c | 2 +- .../eap_tls_sec_prot/eap_tls_sec_prot_lib.c | 8 +- .../eap_tls_sec_prot/eap_tls_sec_prot_lib.h | 1 - .../radius_eap_tls_sec_prot.c | 2 +- .../protocols/radius_sec_prot/avp_helper.h | 4 +- .../radius_sec_prot/radius_client_sec_prot.c | 2 + source/Service_Libs/fhss/fhss_ws.c | 6 +- source/libDHCPv6/libDHCPv6.c | 38 +---- source/libDHCPv6/libDHCPv6.h | 19 +-- source/libDHCPv6/libDHCPv6_server.c | 130 ++++++++++++++++++ source/libDHCPv6/libDHCPv6_server.h | 26 ++++ source/libDHCPv6/libDHCPv6_vendordata.c | 100 ++++++++++++++ source/libDHCPv6/libDHCPv6_vendordata.h | 44 ++++++ source/libNET/src/net_dns.c | 4 +- sources.mk | 1 + 26 files changed, 748 insertions(+), 80 deletions(-) create mode 100644 source/libDHCPv6/libDHCPv6_vendordata.c create mode 100644 source/libDHCPv6/libDHCPv6_vendordata.h diff --git a/nanostack/ws_bbr_api.h b/nanostack/ws_bbr_api.h index bba584aec9..85c4fd3d59 100644 --- a/nanostack/ws_bbr_api.h +++ b/nanostack/ws_bbr_api.h @@ -490,7 +490,8 @@ int ws_bbr_radius_timing_validate(int8_t interface_id, bbr_radius_timing_t *timi * * This function can be called multiple times. * if domain name matches a existing entry address is updated. - * If address and domain name is set to NULL entire list is cleared + * 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. diff --git a/source/6LoWPAN/ws/ws_bbr_api.c b/source/6LoWPAN/ws/ws_bbr_api.c index ae4d377b60..eedd4ea623 100644 --- a/source/6LoWPAN/ws/ws_bbr_api.c +++ b/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,7 @@ #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" @@ -93,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 @@ -368,7 +381,8 @@ static bool wisun_dhcp_address_add_cb(int8_t interfaceId, dhcp_address_cache_upd wisun_bbr_na_send(backbone_interface_id, address_info->allocatedAddress); return true; } -static void ws_bbr_dhcp_server_dns_info_update(protocol_interface_info_entry_t *cur) + +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]; @@ -377,13 +391,37 @@ static void ws_bbr_dhcp_server_dns_info_update(protocol_interface_info_entry_t * (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, dns_server_address, dns_search_list_ptr, dns_search_list_len); + 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 - (void)dhcp_vendor_data_ptr; - (void)dhcp_vendor_data_len; - //DHCPv6_server_service_set_vendor_data(cur->id, dhcp_vendor_data_ptr, dhcp_vendor_data_len); + 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) @@ -406,7 +444,7 @@ 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); + ws_bbr_dhcp_server_dns_info_update(cur, global_id); ws_dhcp_client_address_request(cur, global_id, ll); } @@ -594,7 +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); + ws_bbr_dhcp_server_dns_info_update(cur, current_global_prefix); } } void ws_bbr_pan_version_increase(protocol_interface_info_entry_t *cur) @@ -1200,7 +1238,7 @@ int ws_bbr_dns_query_result_set(int8_t interface_id, const uint8_t address[16], { #ifdef HAVE_WS_BORDER_ROUTER protocol_interface_info_entry_t *cur = protocol_stack_interface_info_get_by_id(interface_id); - if (!cur || !address || !domain_name_ptr) { + if (!cur) { return -1; } @@ -1210,10 +1248,62 @@ int ws_bbr_dns_query_result_set(int8_t interface_id, const uint8_t address[16], * * This is included in the vendor extension where the format is decided by the vendor */ - // TODO search if entry exists replace if address is NULL delete the entry - // TODO This information should expire if not updated by client - ws_bbr_dhcp_server_dns_info_update(cur); + // 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; diff --git a/source/6LoWPAN/ws/ws_bootstrap.c b/source/6LoWPAN/ws/ws_bootstrap.c index a1a490709f..808acb7bf2 100644 --- a/source/6LoWPAN/ws/ws_bootstrap.c +++ b/source/6LoWPAN/ws/ws_bootstrap.c @@ -65,6 +65,7 @@ #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" @@ -73,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" @@ -872,6 +874,80 @@ static void ws_bootstrap_dhcp_neighbour_update_cb(int8_t interface_id, uint8_t l 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; @@ -923,6 +999,7 @@ static int8_t ws_bootstrap_up(protocol_interface_info_entry_t *cur) 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); @@ -1520,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); diff --git a/source/6LoWPAN/ws/ws_config.h b/source/6LoWPAN/ws/ws_config.h index 26009e1bb0..589724fda8 100644 --- a/source/6LoWPAN/ws/ws_config.h +++ b/source/6LoWPAN/ws/ws_config.h @@ -273,4 +273,11 @@ extern uint8_t DEVICE_MIN_SENS; #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/source/6LoWPAN/ws/ws_eapol_relay.c b/source/6LoWPAN/ws/ws_eapol_relay.c index a5a83c3ec3..0bc7a5a472 100644 --- a/source/6LoWPAN/ws/ws_eapol_relay.c +++ b/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/source/6LoWPAN/ws/ws_pae_controller.c b/source/6LoWPAN/ws/ws_pae_controller.c index b11e91cb1b..e222d825da 100644 --- a/source/6LoWPAN/ws/ws_pae_controller.c +++ b/source/6LoWPAN/ws/ws_pae_controller.c @@ -1221,7 +1221,8 @@ int8_t ws_pae_controller_radius_address_set(int8_t interface_id, const uint8_t * } if (ws_pae_auth_radius_address_set(controller->interface_ptr, radius_cfg->radius_addr) < 0) { - return -1; + // If not set here since authenticator not created, then set on authenticator initialization + return 0; } return 0; diff --git a/source/Common_Protocols/icmpv6.c b/source/Common_Protocols/icmpv6.c index 52b8754257..1f8beaf6a3 100644 --- a/source/Common_Protocols/icmpv6.c +++ b/source/Common_Protocols/icmpv6.c @@ -639,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; @@ -869,7 +884,8 @@ 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 - + //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); diff --git a/source/DHCPv6_Server/DHCPv6_Server_service.c b/source/DHCPv6_Server/DHCPv6_Server_service.c index a7755034a9..8784c634d2 100644 --- a/source/DHCPv6_Server/DHCPv6_Server_service.c +++ b/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/source/DHCPv6_Server/DHCPv6_server_service.h b/source/DHCPv6_Server/DHCPv6_server_service.h index 8f8616f4f4..024a46acde 100644 --- a/source/DHCPv6_Server/DHCPv6_server_service.h +++ b/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/source/DHCPv6_client/dhcpv6_client_api.h b/source/DHCPv6_client/dhcpv6_client_api.h index ccfc6c1ddf..57025e76ef 100644 --- a/source/DHCPv6_client/dhcpv6_client_api.h +++ b/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/source/DHCPv6_client/dhcpv6_client_service.c b/source/DHCPv6_client/dhcpv6_client_service.c index a8cecf6d8d..559b6ccf1d 100644 --- a/source/DHCPv6_client/dhcpv6_client_service.c +++ b/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/source/Security/kmp/kmp_socket_if.c b/source/Security/kmp/kmp_socket_if.c index cfecba64d8..6197e4304d 100644 --- a/source/Security/kmp/kmp_socket_if.c +++ b/source/Security/kmp/kmp_socket_if.c @@ -91,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; } diff --git a/source/Security/protocols/eap_tls_sec_prot/eap_tls_sec_prot_lib.c b/source/Security/protocols/eap_tls_sec_prot/eap_tls_sec_prot_lib.c index 5c2f5ee0e4..9592059724 100644 --- a/source/Security/protocols/eap_tls_sec_prot/eap_tls_sec_prot_lib.c +++ b/source/Security/protocols/eap_tls_sec_prot/eap_tls_sec_prot_lib.c @@ -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/source/Security/protocols/eap_tls_sec_prot/eap_tls_sec_prot_lib.h b/source/Security/protocols/eap_tls_sec_prot/eap_tls_sec_prot_lib.h index 78be243eeb..6af3687869 100644 --- a/source/Security/protocols/eap_tls_sec_prot/eap_tls_sec_prot_lib.h +++ b/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 600 //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/source/Security/protocols/eap_tls_sec_prot/radius_eap_tls_sec_prot.c b/source/Security/protocols/eap_tls_sec_prot/radius_eap_tls_sec_prot.c index 33c46eb8ae..7018d56c98 100644 --- a/source/Security/protocols/eap_tls_sec_prot/radius_eap_tls_sec_prot.c +++ b/source/Security/protocols/eap_tls_sec_prot/radius_eap_tls_sec_prot.c @@ -495,7 +495,7 @@ 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; } diff --git a/source/Security/protocols/radius_sec_prot/avp_helper.h b/source/Security/protocols/radius_sec_prot/avp_helper.h index 1fdd5bb54e..8687a112fa 100644 --- a/source/Security/protocols/radius_sec_prot/avp_helper.h +++ b/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/source/Security/protocols/radius_sec_prot/radius_client_sec_prot.c b/source/Security/protocols/radius_sec_prot/radius_client_sec_prot.c index 986397f25f..a8dc175b7b 100644 --- a/source/Security/protocols/radius_sec_prot/radius_client_sec_prot.c +++ b/source/Security/protocols/radius_sec_prot/radius_client_sec_prot.c @@ -508,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 } } } diff --git a/source/Service_Libs/fhss/fhss_ws.c b/source/Service_Libs/fhss/fhss_ws.c index 4af8669e75..78cb5154d5 100644 --- a/source/Service_Libs/fhss/fhss_ws.c +++ b/source/Service_Libs/fhss/fhss_ws.c @@ -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; diff --git a/source/libDHCPv6/libDHCPv6.c b/source/libDHCPv6/libDHCPv6.c index 7b021aba39..722e41f46e 100644 --- a/source/libDHCPv6/libDHCPv6.c +++ b/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/source/libDHCPv6/libDHCPv6.h b/source/libDHCPv6/libDHCPv6.h index c495a18fe4..dd2bd6309f 100644 --- a/source/libDHCPv6/libDHCPv6.h +++ b/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/source/libDHCPv6/libDHCPv6_server.c b/source/libDHCPv6/libDHCPv6_server.c index f3c0ccba8c..d324c81269 100644 --- a/source/libDHCPv6/libDHCPv6_server.c +++ b/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/source/libDHCPv6/libDHCPv6_server.h b/source/libDHCPv6/libDHCPv6_server.h index 3b4c0643e2..3ea3e5f2ab 100644 --- a/source/libDHCPv6/libDHCPv6_server.h +++ b/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/source/libDHCPv6/libDHCPv6_vendordata.c b/source/libDHCPv6/libDHCPv6_vendordata.c new file mode 100644 index 0000000000..2854517d5e --- /dev/null +++ b/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/source/libDHCPv6/libDHCPv6_vendordata.h b/source/libDHCPv6/libDHCPv6_vendordata.h new file mode 100644 index 0000000000..1a1ef44f7f --- /dev/null +++ b/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/source/libNET/src/net_dns.c b/source/libNET/src/net_dns.c index ef71f382fe..b7c7c3eec5 100644 --- a/source/libNET/src/net_dns.c +++ b/source/libNET/src/net_dns.c @@ -115,7 +115,7 @@ int8_t net_dns_server_address_set(int8_t interface_id, const uint8_t address[16] } info_ptr->lifetime = lifetime; memcpy(info_ptr->dns_server_address, dns_server_address, 16); - tr_info("DNS Server: %s Lifetime: %lu", trace_ipv6(info_ptr->dns_server_address), (unsigned long) info_ptr->lifetime); + 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; } @@ -234,7 +234,7 @@ static dns_query_t *dns_query_result_create(int8_t interface_id, const char *dom } this->interface_id = interface_id; strcpy(this->domain_str, domain_str); - tr_debug("Create DNS query entry for %s", this->domain_str); + //tr_debug("Create DNS query entry for %s", this->domain_str); ns_list_add_to_start(&dns_query_list, this); return this; } diff --git a/sources.mk b/sources.mk index 8db71ba294..2d895e803a 100644 --- a/sources.mk +++ b/sources.mk @@ -205,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 \