static struct udp_pcb *pcb_dhcps = NULL;
static ip4_addr_t broadcast_dhcps;
static ip4_addr_t server_address;
+static ip4_addr_t dns_server = {0};
static ip4_addr_t client_address; //added
static ip4_addr_t client_address_plus;
static bool renew = false;
static dhcps_lease_t dhcps_poll;
-static dhcps_offer_t dhcps_offer = 0xFF;
static dhcps_time_t dhcps_lease_time = DHCPS_LEASE_TIME_DEF; //minute
+static dhcps_offer_t dhcps_offer = 0xFF;
+static dhcps_offer_t dhcps_dns = 0xFF;
/******************************************************************************
* FunctionName : dhcps_option_info
break;
+ case DOMAIN_NAME_SERVER:
+ if (opt_len == sizeof(dhcps_offer_t)) {
+ option_arg = &dhcps_dns;
+ }
+
+ break;
+
default:
break;
}
return option_arg;
}
+/******************************************************************************
+ * FunctionName : dhcps_set_option_info
+ * Description : set the DHCP message option info
+ * Parameters : op_id -- DHCP message option id
+ * opt_info -- DHCP message option info
+ * opt_len -- DHCP message option length
+ * Returns : none
+*******************************************************************************/
+void dhcps_set_option_info(u8_t op_id, void *opt_info, u32_t opt_len)
+{
+ if (opt_info == NULL) {
+ return;
+ }
+ switch (op_id) {
+ case IP_ADDRESS_LEASE_TIME:
+ if (opt_len == sizeof(dhcps_time_t)) {
+ dhcps_lease_time = *(dhcps_time_t *)opt_info;
+ }
+
+ break;
+
+ case REQUESTED_IP_ADDRESS:
+ if (opt_len == sizeof(dhcps_lease_t)) {
+ dhcps_poll = *(dhcps_lease_t *)opt_info;
+ }
+
+ break;
+
+ case ROUTER_SOLICITATION_ADDRESS:
+ if (opt_len == sizeof(dhcps_offer_t)) {
+ dhcps_offer = *(dhcps_offer_t *)opt_info;
+ }
+
+ break;
+
+ case DOMAIN_NAME_SERVER:
+ if (opt_len == sizeof(dhcps_offer_t)) {
+ dhcps_dns = *(dhcps_offer_t *)opt_info;
+ }
+ break;
+
+ default:
+ break;
+ }
+ return;
+}
+
/******************************************************************************
* FunctionName : node_insert_to_list
* Description : insert the node to the list
}
}
-#ifdef USE_DNS
*optptr++ = DHCP_OPTION_DNS_SERVER;
*optptr++ = 4;
- *optptr++ = ip4_addr1(&ipadd);
- *optptr++ = ip4_addr2(&ipadd);
- *optptr++ = ip4_addr3(&ipadd);
- *optptr++ = ip4_addr4(&ipadd);
-#endif
+ if (dhcps_dns_enabled(dhcps_dns)) {
+ *optptr++ = ip4_addr1(&dns_server);
+ *optptr++ = ip4_addr2(&dns_server);
+ *optptr++ = ip4_addr3(&dns_server);
+ *optptr++ = ip4_addr4(&dns_server);
+ }else {
+ *optptr++ = ip4_addr1(&ipadd);
+ *optptr++ = ip4_addr2(&ipadd);
+ *optptr++ = ip4_addr3(&ipadd);
+ *optptr++ = ip4_addr4(&ipadd);
+ }
#ifdef CLASS_B_NET
*optptr++ = DHCP_OPTION_BROADCAST_ADDRESS;
return ret;
}
+
+/******************************************************************************
+ * FunctionName : dhcps_dns_setserver
+ * Description : set DNS server address for dhcpserver
+ * Parameters : dnsserver -- The DNS server address
+ * Returns : none
+*******************************************************************************/
+void
+dhcps_dns_setserver(const ip_addr_t *dnsserver)
+{
+ if (dnsserver != NULL) {
+ dns_server = *(ip_2_ip4(dnsserver));
+ } else {
+ dns_server = *(ip_2_ip4(IP_ADDR_ANY));
+ }
+}
+
+/******************************************************************************
+ * FunctionName : dhcps_dns_getserver
+ * Description : get DNS server address for dhcpserver
+ * Parameters : none
+ * Returns : ip4_addr_t
+*******************************************************************************/
+ip4_addr_t
+dhcps_dns_getserver()
+{
+ return dns_server;
+}
#endif
#endif /* LWIP_DNS_STRICMP */
/**
- * Initialize the resolver: set up the UDP pcb and configure the default server
- * (if DNS_SERVER_ADDRESS is set).
+ * Initialize the resolver: set up the UDP pcb and configure the fallback dns server
+ * (if FALLBACK_DNS_SERVER_ADDRESS is set).
*/
void
dns_init(void)
{
-#ifdef DNS_SERVER_ADDRESS
+#ifdef FALLBACK_DNS_SERVER_ADDRESS
/* initialize default DNS server address */
ip_addr_t dnsserver;
- DNS_SERVER_ADDRESS(&dnsserver);
- dns_setserver(0, &dnsserver);
-#endif /* DNS_SERVER_ADDRESS */
+ FALLBACK_DNS_SERVER_ADDRESS(&dnsserver);
+ dnsserver.type = IPADDR_TYPE_V4;
+ dns_setserver(DNS_FALLBACK_SERVER_INDEX, &dnsserver);
+#endif /* FALLBACK_DNS_SERVER_ADDRESS */
LWIP_ASSERT("sanity check SIZEOF_DNS_QUERY",
sizeof(struct dns_query) == SIZEOF_DNS_QUERY);
}
}
+void
+dns_clear_servers(bool keep_fallback)
+{
+ u8_t numdns = 0;
+
+ for (numdns = 0; numdns < DNS_MAX_SERVERS; numdns ++) {
+ if (keep_fallback && numdns == DNS_FALLBACK_SERVER_INDEX) {
+ continue;
+ }
+
+ dns_setserver(numdns, NULL);
+ }
+}
+
+
/**
* Obtain one of the currently configured DNS server.
*
(u16_t)(entry->server_idx), entry->name));
LWIP_ASSERT("dns server out of array", entry->server_idx < DNS_MAX_SERVERS);
if (ip_addr_isany_val(dns_servers[entry->server_idx])) {
- /* DNS server not valid anymore, e.g. PPP netif has been shut down */
- /* call specified callback function if provided */
- dns_call_found(idx, NULL);
- /* flush this entry */
- entry->state = DNS_STATE_UNUSED;
return ERR_OK;
}
case DNS_STATE_ASKING:
if (--entry->tmr == 0) {
if (++entry->retries == DNS_MAX_RETRIES) {
+ /* skip DNS servers with zero address */
+ while ((entry->server_idx + 1 < DNS_MAX_SERVERS) && ip_addr_isany_val(dns_servers[entry->server_idx + 1])) {
+ entry->server_idx++;
+ }
+
if ((entry->server_idx + 1 < DNS_MAX_SERVERS) && !ip_addr_isany_val(dns_servers[entry->server_idx + 1])) {
/* change of server */
entry->server_idx++;
return dns_gethostbyname_addrtype(hostname, addr, found, callback_arg, LWIP_DNS_ADDRTYPE_DEFAULT);
}
+static bool dns_server_is_set (void)
+{
+ int i = 0;
+ for (i = 0;i < DNS_MAX_SERVERS; i++) {
+ if (!ip_addr_isany_val(dns_servers[i])) {
+ return true;
+ }
+ }
+ return false;
+}
+
/** Like dns_gethostbyname, but returned address type can be controlled:
* @param dns_addrtype: - LWIP_DNS_ADDRTYPE_IPV4_IPV6: try to resolve IPv4 first, try IPv6 if IPv4 fails only
* - LWIP_DNS_ADDRTYPE_IPV6_IPV4: try to resolve IPv6 first, try IPv4 if IPv6 fails only
#endif /* LWIP_IPV4 && LWIP_IPV6 */
/* prevent calling found callback if no server is set, return error instead */
- if (ip_addr_isany_val(dns_servers[0])) {
+
+ if (dns_server_is_set() == false) {
return ERR_VAL;
}
/* DNS servers */
for (n = 0; (n < DNS_MAX_SERVERS) && dhcp_option_given(dhcp, DHCP_OPTION_IDX_DNS_SERVER + n); n++) {
ip_addr_t dns_addr;
+ if (n == DNS_FALLBACK_SERVER_INDEX) {
+ continue;
+ }
ip_addr_set_ip4_u32(&dns_addr, htonl(dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_DNS_SERVER + n)));
dns_setserver(n, &dns_addr);
}
#define __DHCPS_H__
#include "lwip/ip_addr.h"
-//#include "esp_common.h"
-#define USE_DNS
typedef struct dhcps_state{
s16_t state;
enum dhcps_offer_option{
OFFER_START = 0x00,
OFFER_ROUTER = 0x01,
+ OFFER_DNS = 0x02,
OFFER_END
};
typedef u8_t dhcps_offer_t;
typedef struct {
- dhcps_offer_t dhcps_offer;
- dhcps_time_t dhcps_time;
- dhcps_lease_t dhcps_poll;
+ dhcps_offer_t dhcps_offer;
+ dhcps_offer_t dhcps_dns;
+ dhcps_time_t dhcps_time;
+ dhcps_lease_t dhcps_poll;
} dhcps_options_t;
-#define dhcps_router_enabled(offer) ((offer & OFFER_ROUTER) != 0)
+static inline bool dhcps_router_enabled (dhcps_offer_t offer)
+{
+ return (offer & OFFER_ROUTER) != 0;
+}
+
+static inline bool dhcps_dns_enabled (dhcps_offer_t offer)
+{
+ return (offer & OFFER_DNS) != 0;
+}
void dhcps_start(struct netif *netif, ip4_addr_t ip);
void dhcps_stop(struct netif *netif);
void *dhcps_option_info(u8_t op_id, u32_t opt_len);
+void dhcps_set_option_info(u8_t op_id, void *opt_info, u32_t opt_len);
bool dhcp_search_ip_on_mac(u8_t *mac, ip4_addr_t *ip);
+void dhcps_dns_setserver(const ip_addr_t *dnsserver);
+ip4_addr_t dhcps_dns_getserver();
#endif
void dns_init(void);
void dns_tmr(void);
void dns_setserver(u8_t numdns, const ip_addr_t *dnsserver);
+void dns_clear_servers(bool keep_fallback);
ip_addr_t dns_getserver(u8_t numdns);
err_t dns_gethostbyname(const char *hostname, ip_addr_t *addr,
dns_found_callback found, void *callback_arg);
*/
#define LWIP_DNS 1
+#define DNS_MAX_SERVERS 3
+#define DNS_FALLBACK_SERVER_INDEX (DNS_MAX_SERVERS - 1)
+
/*
---------------------------------
---------- UDP options ----------
TCPIP_ADAPTER_IF_MAX
} tcpip_adapter_if_t;
+/*type of DNS server*/
+typedef enum {
+ TCPIP_ADAPTER_DNS_MAIN= 0, /**DNS main server address*/
+ TCPIP_ADAPTER_DNS_BACKUP, /**DNS backup server address,for STA only,support soft-AP in future*/
+ TCPIP_ADAPTER_DNS_FALLBACK, /**DNS fallback server address,for STA only*/
+ TCPIP_ADAPTER_DNS_MAX /**Max DNS */
+} tcpip_adapter_dns_type_t;
+
+/*info of DNS server*/
+typedef struct {
+ ip_addr_t ip;
+} tcpip_adapter_dns_info_t;
+
/* status of DHCP client or DHCP server */
typedef enum {
TCPIP_ADAPTER_DHCP_INIT = 0, /**< DHCP client/server in initial state */
} tcpip_adapter_option_mode_t;
typedef enum{
+ TCPIP_ADAPTER_DOMAIN_NAME_SERVER = 6, /**< domain name server */
TCPIP_ADAPTER_ROUTER_SOLICITATION_ADDRESS = 32, /**< solicitation router address */
TCPIP_ADAPTER_REQUESTED_IP_ADDRESS = 50, /**< request IP address pool */
TCPIP_ADAPTER_IP_ADDRESS_LEASE_TIME = 51, /**< request IP address lease time */
tcpip_adapter_if_t tcpip_if;
tcpip_adapter_ip_info_t *ip_info;
uint8_t *mac;
- const char *hostname;
+ void *data;
} tcpip_adapter_api_msg_t;
+typedef struct tcpip_adapter_dns_param_s {
+ tcpip_adapter_dns_type_t dns_type;
+ tcpip_adapter_dns_info_t *dns_info;
+} tcpip_adapter_dns_param_t;
+
#define TCPIP_ADAPTER_TRHEAD_SAFE 1
#define TCPIP_ADAPTER_IPC_LOCAL 0
#define TCPIP_ADAPTER_IPC_REMOTE 1
-#define TCPIP_ADAPTER_IPC_CALL(_if, _mac, _ip, _hostname, _fn) do {\
+#define TCPIP_ADAPTER_IPC_CALL(_if, _mac, _ip, _data, _fn) do {\
tcpip_adapter_api_msg_t msg;\
if (tcpip_inited == false) {\
ESP_LOGE(TAG, "tcpip_adapter is not initialized!");\
}\
memset(&msg, 0, sizeof(msg));\
msg.tcpip_if = (_if);\
- msg.mac = (_mac);\
- msg.ip_info = (_ip);\
- msg.hostname = (_hostname);\
+ msg.mac = (uint8_t*)(_mac);\
+ msg.ip_info = (tcpip_adapter_ip_info_t*)(_ip);\
+ msg.data = (void*)(_data);\
msg.api_fn = (_fn);\
if (TCPIP_ADAPTER_IPC_REMOTE == tcpip_adapter_ipc_check(&msg)) {\
ESP_LOGD(TAG, "check: remote, if=%d fn=%p\n", (_if), (_fn));\
*/
esp_err_t tcpip_adapter_set_ip_info(tcpip_adapter_if_t tcpip_if, tcpip_adapter_ip_info_t *ip_info);
+/**
+ * @brief Set DNS Server's information
+ *
+ * There has an DNS Server information copy in adapter library, set DNS Server for appointed interface and type.
+ *
+ * 1.In station mode, if dhcp client is enabled, then only the fallback DNS server can be set(TCPIP_ADAPTER_DNS_FALLBACK).
+ * Fallback DNS server is only used if no DNS servers are set via DHCP.
+ * If dhcp client is disabled, then need to set main/backup dns server(TCPIP_ADAPTER_DNS_MAIN, TCPIP_ADAPTER_DNS_BACKUP).
+ *
+ * 2.In soft-AP mode, the DNS Server's main dns server offered to the station is the IP address of soft-AP,
+ * if the application don't want to use the IP address of soft-AP, they can set the main dns server.
+ *
+ * This function is mainly used for setting static or Fallback DNS Server.
+ *
+ * @param[in] tcpip_if: the interface which we want to set DNS Server information
+ * @param[in] type: the type of DNS Server,including TCPIP_ADAPTER_DNS_MAIN, TCPIP_ADAPTER_DNS_BACKUP, TCPIP_ADAPTER_DNS_FALLBACK
+ * @param[in] dns: the DNS Server address to be set
+ *
+ * @return
+ * - ESP_OK on success
+ * - ESP_ERR_TCPIP_ADAPTER_INVALID_PARAMS invalid params
+ */
+esp_err_t tcpip_adapter_set_dns_info(tcpip_adapter_if_t tcpip_if, tcpip_adapter_dns_type_t type, tcpip_adapter_dns_info_t *dns);
+
+/**
+ * @brief Get DNS Server's information
+ *
+ * When set the DNS Server information successfully, can get the DNS Server's information via the appointed tcpip_if and type
+ *
+ * This function is mainly used for getting DNS Server information.
+ *
+ * @param[in] tcpip_if: the interface which we want to get DNS Server information
+ * @param[in] type: the type of DNS Server,including TCPIP_ADAPTER_DNS_MAIN, TCPIP_ADAPTER_DNS_BACKUP, TCPIP_ADAPTER_DNS_FALLBACK
+ * @param[in] dns: the DNS Server address to be get
+ *
+ * @return
+ * - ESP_OK on success
+ * - ESP_ERR_TCPIP_ADAPTER_INVALID_PARAMS invalid params
+ */
+esp_err_t tcpip_adapter_get_dns_info(tcpip_adapter_if_t tcpip_if, tcpip_adapter_dns_type_t type, tcpip_adapter_dns_info_t *dns);
+
/**
* @brief Get interface's old IP information
*
static esp_err_t tcpip_adapter_up_api(tcpip_adapter_api_msg_t * msg);
static esp_err_t tcpip_adapter_down_api(tcpip_adapter_api_msg_t * msg);
static esp_err_t tcpip_adapter_set_ip_info_api(tcpip_adapter_api_msg_t * msg);
+static esp_err_t tcpip_adapter_set_dns_info_api(tcpip_adapter_api_msg_t * msg);
+static esp_err_t tcpip_adapter_get_dns_info_api(tcpip_adapter_api_msg_t * msg);
static esp_err_t tcpip_adapter_create_ip6_linklocal_api(tcpip_adapter_api_msg_t * msg);
static esp_err_t tcpip_adapter_dhcps_start_api(tcpip_adapter_api_msg_t * msg);
static esp_err_t tcpip_adapter_dhcps_stop_api(tcpip_adapter_api_msg_t * msg);
static bool tcpip_inited = false;
static sys_sem_t api_lock_sem = NULL;
extern sys_thread_t g_lwip_task;
-
#define TAG "tcpip_adapter"
static void tcpip_adapter_api_cb(void* api_msg)
return ESP_ERR_TCPIP_ADAPTER_DHCP_NOT_STOPPED;
}
#if LWIP_DNS /* don't build if not configured for use in lwipopts.h */
- u8_t numdns = 0;
- for (numdns = 0; numdns < DNS_MAX_SERVERS; numdns ++) {
- dns_setserver(numdns, NULL);
- }
+ dns_clear_servers(true);
#endif
}
break;
}
case ROUTER_SOLICITATION_ADDRESS: {
- *(uint8_t *)opt_val = (*(uint8_t *)opt_info) & OFFER_ROUTER;
+ if ((*(uint8_t *)opt_info) & OFFER_ROUTER) {
+ *(uint8_t *)opt_val = 1;
+ } else {
+ *(uint8_t *)opt_val = 0;
+ }
+ break;
+ }
+ case DOMAIN_NAME_SERVER: {
+ if ((*(uint8_t *)opt_info) & OFFER_DNS) {
+ *(uint8_t *)opt_val = 1;
+ } else {
+ *(uint8_t *)opt_val = 0;
+ }
break;
}
default:
break;
}
case ROUTER_SOLICITATION_ADDRESS: {
- *(uint8_t *)opt_info = (*(uint8_t *)opt_val) & OFFER_ROUTER;
+ if (*(uint8_t *)opt_val) {
+ *(uint8_t *)opt_info |= OFFER_ROUTER;
+ } else {
+ *(uint8_t *)opt_info &= ((~OFFER_ROUTER)&0xFF);
+ }
+ break;
+ }
+ case DOMAIN_NAME_SERVER: {
+ if (*(uint8_t *)opt_val) {
+ *(uint8_t *)opt_info |= OFFER_DNS;
+ } else {
+ *(uint8_t *)opt_info &= ((~OFFER_DNS)&0xFF);
+ }
break;
}
+
default:
break;
}
+ dhcps_set_option_info(opt_id, opt_info,opt_len);
+ } else {
+ return ESP_ERR_TCPIP_ADAPTER_INVALID_PARAMS;
+ }
+
+ return ESP_OK;
+}
+
+esp_err_t tcpip_adapter_set_dns_info(tcpip_adapter_if_t tcpip_if, tcpip_adapter_dns_type_t type, tcpip_adapter_dns_info_t *dns)
+{
+ tcpip_adapter_dns_param_t dns_param;
+
+ dns_param.dns_type = type;
+ dns_param.dns_info = dns;
+
+ TCPIP_ADAPTER_IPC_CALL(tcpip_if, type, 0, &dns_param, tcpip_adapter_set_dns_info_api);
+
+ if (tcpip_if >= TCPIP_ADAPTER_IF_MAX) {
+ ESP_LOGD(TAG, "set dns invalid if=%d", tcpip_if);
+ return ESP_ERR_TCPIP_ADAPTER_INVALID_PARAMS;
+ }
+
+ if (!dns) {
+ ESP_LOGD(TAG, "set dns null dns");
+ return ESP_ERR_TCPIP_ADAPTER_INVALID_PARAMS;
+ }
+
+ if (type >= TCPIP_ADAPTER_DNS_MAX) {
+ ESP_LOGD(TAG, "set dns invalid type=%d", type);
+ return ESP_ERR_TCPIP_ADAPTER_INVALID_PARAMS;
+ }
+
+ if (ip4_addr_isany_val(dns->ip.u_addr.ip4)) {
+ ESP_LOGD(TAG, "set dns invalid dns");
+ return ESP_ERR_TCPIP_ADAPTER_INVALID_PARAMS;
+ }
+
+ ESP_LOGD(TAG, "set dns if=%d type=%d dns=%x", tcpip_if, type, dns->ip.u_addr.ip4.addr);
+ dns->ip.type = IPADDR_TYPE_V4;
+
+ if (tcpip_if == TCPIP_ADAPTER_IF_STA || tcpip_if == TCPIP_ADAPTER_IF_ETH) {
+ dns_setserver(type, &(dns->ip));
} else {
+ if (type != TCPIP_ADAPTER_DNS_MAIN) {
+ ESP_LOGD(TAG, "set dns invalid type");
+ return ESP_ERR_TCPIP_ADAPTER_INVALID_PARAMS;
+ } else {
+ dhcps_dns_setserver(&(dns->ip));
+ }
+ }
+
+ return ESP_OK;
+}
+
+static esp_err_t tcpip_adapter_set_dns_info_api(tcpip_adapter_api_msg_t * msg)
+{
+ tcpip_adapter_dns_param_t *dns_param = (tcpip_adapter_dns_param_t*)msg->data;
+
+ return tcpip_adapter_set_dns_info(msg->tcpip_if, dns_param->dns_type, dns_param->dns_info);
+}
+
+esp_err_t tcpip_adapter_get_dns_info(tcpip_adapter_if_t tcpip_if, tcpip_adapter_dns_type_t type, tcpip_adapter_dns_info_t *dns)
+{
+ tcpip_adapter_dns_param_t dns_param;
+
+ dns_param.dns_type = type;
+ dns_param.dns_info = dns;
+
+ TCPIP_ADAPTER_IPC_CALL(tcpip_if, type, 0, &dns_param, tcpip_adapter_get_dns_info_api);
+ if (!dns) {
+ ESP_LOGD(TAG, "get dns null dns");
+ return ESP_ERR_TCPIP_ADAPTER_INVALID_PARAMS;
+ }
+
+ if (type >= TCPIP_ADAPTER_DNS_MAX) {
+ ESP_LOGD(TAG, "get dns invalid type=%d", type);
return ESP_ERR_TCPIP_ADAPTER_INVALID_PARAMS;
}
+
+ if (tcpip_if >= TCPIP_ADAPTER_IF_MAX) {
+ ESP_LOGD(TAG, "get dns invalid tcpip_if=%d",tcpip_if);
+ return ESP_ERR_TCPIP_ADAPTER_INVALID_PARAMS;
+ }
+
+ if (tcpip_if == TCPIP_ADAPTER_IF_STA || tcpip_if == TCPIP_ADAPTER_IF_ETH) {
+ dns->ip = dns_getserver(type);
+ } else {
+ dns->ip.u_addr.ip4 = dhcps_dns_getserver();
+ }
return ESP_OK;
}
+static esp_err_t tcpip_adapter_get_dns_info_api(tcpip_adapter_api_msg_t * msg)
+{
+ tcpip_adapter_dns_param_t *dns_param = (tcpip_adapter_dns_param_t*)msg->data;
+
+ return tcpip_adapter_get_dns_info(msg->tcpip_if, dns_param->dns_type, dns_param->dns_info);
+}
+
esp_err_t tcpip_adapter_dhcps_get_status(tcpip_adapter_if_t tcpip_if, tcpip_adapter_dhcp_status_t *status)
{
*status = dhcps_status;
struct netif *p_netif = esp_netif[tcpip_if];
tcpip_adapter_reset_ip_info(tcpip_if);
+#if LWIP_DNS
+ dns_clear_servers(true);
+#endif
if (p_netif != NULL) {
if (netif_is_up(p_netif)) {
static esp_err_t tcpip_adapter_set_hostname_api(tcpip_adapter_api_msg_t * msg)
{
- return tcpip_adapter_set_hostname(msg->tcpip_if, msg->hostname);
+ const char *hostname = (char*) msg->data;
+
+ return tcpip_adapter_set_hostname(msg->tcpip_if, hostname);
}
esp_err_t tcpip_adapter_get_hostname(tcpip_adapter_if_t tcpip_if, const char **hostname)