esp-idf/components/esp_netif/lwip/esp_netif_lwip.c
David Cermak 6acdb384f6 fix(esp_netif): Restore DNS servers per netif when setting it default
Introducing config option `CONFIG_ESP_NETIF_SET_DNS_PER_DEFAULT_NETIF`
to overcome LWIP limitation of using global DNS server info.
This config option enables LWIP callbacks to collect per netif DNS
server info and then restores global DNS servers of whichever network
interface is selected as default.

LWIP submodule update: git log --oneline aa4f6e78..3a3d1fb3
- dns: Allow storing dnsserver per netif (espressif/esp-lwip@3a3d1fb3)
2024-07-04 10:37:22 +02:00

2773 lines
93 KiB
C

/*
* SPDX-FileCopyrightText: 2019-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <string.h>
#include <inttypes.h>
#include <lwip/ip_addr.h>
#include <lwip/sockets.h>
#include "esp_compiler.h"
#include "esp_check.h"
#include "esp_netif_lwip_internal.h"
#include "lwip/esp_netif_net_stack.h"
#include "esp_netif.h"
#include "esp_netif_private.h"
#include "esp_random.h"
#include "esp_system.h"
#include "lwip/tcpip.h"
#include "lwip/dhcp.h"
#include "lwip/ip_addr.h"
#include "lwip/ip6_addr.h"
#include "lwip/mld6.h"
#include "lwip/prot/mld6.h"
#include "lwip/nd6.h"
#include "lwip/snmp.h"
#include "lwip/priv/tcpip_priv.h"
#include "lwip/netif.h"
#include "lwip/etharp.h"
#if CONFIG_ESP_NETIF_BRIDGE_EN
#include "netif/bridgeif.h"
#endif // CONFIG_ESP_NETIF_BRIDGE_EN
#if LWIP_DNS /* don't build if not configured for use in lwipopts.h */
#include "lwip/dns.h"
#endif // LWIP_DNS
#if CONFIG_LWIP_HOOK_TCP_ISN_DEFAULT
#include "lwip_default_hooks.h"
#endif // CONFIG_LWIP_HOOK_TCP_ISN_DEFAULT
#include "esp_netif_lwip_ppp.h"
#if ESP_DHCPS
#include "dhcpserver/dhcpserver.h"
#include "dhcpserver/dhcpserver_options.h"
#endif
#include "netif/dhcp_state.h"
#include "esp_event.h"
#include "esp_log.h"
#if IP_NAPT
#include "lwip/lwip_napt.h"
#endif
//
// This is the main module implementing lwip interaction with esp-netif
//
#define ESP_NETIF_HOSTNAME_MAX_SIZE 32
#define DHCP_CB_CHANGE (LWIP_NSC_IPV4_SETTINGS_CHANGED | LWIP_NSC_IPV4_ADDRESS_CHANGED | LWIP_NSC_IPV4_GATEWAY_CHANGED | LWIP_NSC_IPV4_NETMASK_CHANGED)
/**
* @brief lwip thread safe tcpip function utility macros
*/
#define _RUN_IN_LWIP_TASK(function, netif, param) { return esp_netif_lwip_ipc_call(function, netif, (void *)(param)); }
/**
* @brief macros to check netif related data to evaluate interface type
*/
#if CONFIG_PPP_SUPPORT
#define _IS_NETIF_ANY_POINT2POINT_TYPE(netif) (netif->related_data && netif->related_data->is_point2point)
#else
#define _IS_NETIF_ANY_POINT2POINT_TYPE(netif) false
#endif
#define _RUN_IN_LWIP_TASK_IF_SUPPORTED(function, netif, param) \
{ \
if (_IS_NETIF_ANY_POINT2POINT_TYPE(netif)) { \
return ESP_ERR_NOT_SUPPORTED; \
} \
return esp_netif_lwip_ipc_call(function, netif, (void *)(param)); \
}
/**
* @brief Utility macros to convert esp-ip addresses (both IPv6+IPv4 versions unconditionally)
* and lwip-ip addresses (contain only enabled portion of the address for each IP stack)
*/
#if LWIP_IPV4 && LWIP_IPV6
#define ESPIP_TO_IP(espip, ip) memcpy((ip), (espip), sizeof(ip_addr_t));
#define IP_TO_ESPIP(ip, espip) memcpy((espip), (ip), sizeof(ip_addr_t));
#elif LWIP_IPV4
#define ESPIP_TO_IP(espip, ip) memcpy((ip), &((espip)->u_addr.ip4), sizeof(ip_addr_t));
#define IP_TO_ESPIP(ip, espip) do { memcpy(&((espip)->u_addr.ip4), (ip), sizeof(ip4_addr_t)); \
(espip)->type = ESP_IPADDR_TYPE_V4; \
} while(0)
#elif LWIP_IPV6
#define ESPIP_TO_IP(espip, ip) memcpy((ip), &((espip)->u_addr.ip6), sizeof(ip_addr_t));
#define IP_TO_ESPIP(ip, espip) do { memcpy(&((espip)->u_addr.ip6), (ip), sizeof(ip6_addr_t)); \
(espip)->type = ESP_IPADDR_TYPE_V6; \
} while(0)
#endif
/**
* @brief If netif protocol not enabled in menuconfig, log the error and return appropriate code indicating failure
*/
#define LOG_NETIF_DISABLED_AND_DO(proto, action) \
do { \
ESP_LOGE(TAG, "%s not supported, please enable it in lwIP component configuration", proto); \
action; \
} while(0)
//
// Internal variables for this module
//
static const char *TAG = "esp_netif_lwip";
#if LWIP_ESP_NETIF_DATA
static u8_t lwip_netif_client_id = 0xff;
#endif
static esp_netif_t *s_last_default_esp_netif = NULL;
static bool s_is_last_default_esp_netif_overridden = false;
static netif_ext_callback_t netif_callback = { .callback_fn = NULL, .next = NULL };
#if LWIP_IPV4
static void esp_netif_internal_dhcpc_cb(struct netif *netif);
#endif
#if LWIP_IPV6
static void esp_netif_internal_nd6_cb(struct netif *p_netif, uint8_t ip_index);
static void netif_set_mldv6_flag(esp_netif_t *netif);
static void netif_unset_mldv6_flag(esp_netif_t *netif);
#endif /* LWIP_IPV6 */
static esp_err_t esp_netif_destroy_api(esp_netif_api_msg_t *msg);
static void netif_callback_fn(struct netif* netif, netif_nsc_reason_t reason, const netif_ext_callback_args_t* args)
{
#if LWIP_IPV4
if (reason & DHCP_CB_CHANGE) {
esp_netif_internal_dhcpc_cb(netif);
}
#endif /* LWIP_IPV4 */
#if LWIP_IPV6
if ((reason & LWIP_NSC_IPV6_ADDR_STATE_CHANGED) && (args != NULL)) {
s8_t addr_idx = args->ipv6_addr_state_changed.addr_index;
if (!(args->ipv6_addr_state_changed.old_state & IP6_ADDR_VALID) &&
netif_ip6_addr_state(netif, addr_idx) & IP6_ADDR_VALID) {
/* address is valid -> call the callback function */
esp_netif_internal_nd6_cb(netif, addr_idx);
}
}
#endif /* #if LWIP_IPV6 */
}
#ifdef CONFIG_LWIP_GARP_TMR_INTERVAL
static void netif_send_garp(void *arg)
{
struct netif *netif = arg;
if (!ip4_addr_cmp(netif_ip4_addr(netif), IP4_ADDR_ANY4)) { // Send GARP requests only if we have a valid IP
etharp_gratuitous(netif);
}
sys_timeout(CONFIG_LWIP_GARP_TMR_INTERVAL*1000, netif_send_garp, netif);
}
static void netif_set_garp_flag(struct netif *netif)
{
sys_timeout(CONFIG_LWIP_GARP_TMR_INTERVAL*1000, netif_send_garp, netif);
}
static void netif_unset_garp_flag(struct netif *netif)
{
sys_untimeout(netif_send_garp, netif);
}
#endif // CONFIG_LWIP_GARP_TMR_INTERVAL
#if !LWIP_TCPIP_CORE_LOCKING
static sys_sem_t api_sync_sem = NULL;
static sys_sem_t api_lock_sem = NULL;
#endif
/**
* @brief Api callback from tcpip thread used to call esp-netif
* function in lwip task context
*/
static void esp_netif_api_cb(void *api_msg)
{
esp_netif_api_msg_t *msg = (esp_netif_api_msg_t *)api_msg;
if (!msg || !msg->api_fn) {
ESP_LOGD(TAG, "null msg/api_fn");
return;
}
msg->ret = msg->api_fn(msg);
ESP_LOGD(TAG, "call api in lwip: ret=0x%x, give sem", msg->ret);
#if !LWIP_TCPIP_CORE_LOCKING
sys_sem_signal(&api_sync_sem);
#endif
}
/**
* @brief Initiates a tcpip remote call if called from another task
* or calls the function directly if executed from lwip task
*/
static inline esp_err_t esp_netif_lwip_ipc_call_msg(esp_netif_api_msg_t *msg)
{
if (!sys_thread_tcpip(LWIP_CORE_LOCK_QUERY_HOLDER)) {
ESP_LOGD(TAG, "check: remote, if=%p fn=%p", msg->esp_netif, msg->api_fn);
#if LWIP_TCPIP_CORE_LOCKING
tcpip_send_msg_wait_sem((tcpip_callback_fn)esp_netif_api_cb, msg, NULL);
#else
sys_arch_sem_wait(&api_lock_sem, 0);
tcpip_send_msg_wait_sem((tcpip_callback_fn)esp_netif_api_cb, msg, &api_sync_sem);
sys_sem_signal(&api_lock_sem);
#endif /* LWIP_TCPIP_CORE_LOCKING */
return msg->ret;
}
ESP_LOGD(TAG, "check: local, if=%p fn=%p", msg->esp_netif, msg->api_fn);
return msg->api_fn(msg);
}
static inline esp_err_t esp_netif_lwip_ipc_call(esp_netif_api_fn fn, esp_netif_t* netif, void *data)
{
esp_netif_api_msg_t msg = {
.esp_netif = netif,
.data = data,
.api_fn = fn
};
return esp_netif_lwip_ipc_call_msg(&msg);
}
static inline esp_err_t esp_netif_lwip_ipc_call_fn(esp_netif_api_fn fn, esp_netif_callback_fn user_fn, void *ctx)
{
esp_netif_api_msg_t msg = {
.user_fn = user_fn,
.data = ctx,
.api_fn = fn
};
return esp_netif_lwip_ipc_call_msg(&msg);
}
static inline esp_err_t esp_netif_lwip_ipc_call_get_netif(esp_netif_api_fn fn, esp_netif_t **netif, void *ctx)
{
esp_netif_api_msg_t msg = {
.p_esp_netif = netif,
.data = ctx,
.api_fn = fn
};
return esp_netif_lwip_ipc_call_msg(&msg);
}
static inline esp_err_t esp_netif_lwip_ipc_no_args(esp_netif_api_fn fn)
{
esp_netif_api_msg_t msg = {
.api_fn = fn
};
return esp_netif_lwip_ipc_call_msg(&msg);
}
/**
* @brief Check if supplied esp_netif handle is active, i.e. available within registered interfaces
* as it might have already been destroyed. Returns the supplied handle if active, nullptr otherwise
*
* @param esp_netif handle to check if available in the list of registered interfaces
* @return esp_netif handle if available, or NULL if it wasn't found
*/
static esp_netif_t* esp_netif_is_active(esp_netif_t *arg)
{
// looking for the netif in the list of registered interfaces
// as it might have already been destroyed
if (esp_netif_is_netif_listed(arg)) {
return arg;
}
return NULL;
}
/**
* @brief This function sets default netif no matter which implementation used
*
* @param esp_netif handle to network interface
*
* @note: This function must be called from lwip thread
*/
static void esp_netif_set_default_netif_internal(esp_netif_t *esp_netif)
{
if (ESP_NETIF_IS_POINT2POINT_TYPE(esp_netif, PPP_LWIP_NETIF)) {
#if CONFIG_PPP_SUPPORT
esp_netif_ppp_set_default_netif(esp_netif->netif_handle);
#endif
} else {
netif_set_default(esp_netif->lwip_netif);
}
#ifdef CONFIG_ESP_NETIF_SET_DNS_PER_DEFAULT_NETIF
for (int i = 0; i < DNS_MAX_SERVERS; ++i) {
dns_setserver(i, &esp_netif->dns[i]);
}
#endif
}
/**
* @brief tcpip thread version of esp_netif_update_default_netif
*
* @note This function and all functions called from this must be called from lwip task context
*/
static esp_err_t esp_netif_update_default_netif_lwip(esp_netif_api_msg_t *msg)
{
esp_netif_t *esp_netif = msg->esp_netif;
esp_netif_route_prio_action_t action = (esp_netif_route_prio_action_t)msg->data;
ESP_LOGD(TAG, "%s %p", __func__, esp_netif);
if (s_is_last_default_esp_netif_overridden && action != ESP_NETIF_SET_DEFAULT) {
// check if manually configured default interface hasn't been destroyed
s_last_default_esp_netif = esp_netif_is_active(s_last_default_esp_netif);
if (s_last_default_esp_netif != NULL) {
return ESP_OK; // still valid -> don't update default netif
}
// invalid -> reset the manual override and perform auto update
s_is_last_default_esp_netif_overridden = false;
}
switch (action) {
case ESP_NETIF_SET_DEFAULT:
s_last_default_esp_netif = esp_netif;
s_is_last_default_esp_netif_overridden = true;
esp_netif_set_default_netif_internal(s_last_default_esp_netif);
break;
case ESP_NETIF_STARTED:
case ESP_NETIF_GOT_IP:
{
// check if previously default interface hasn't been destroyed in the meantime
s_last_default_esp_netif = esp_netif_is_active(s_last_default_esp_netif);
if (s_last_default_esp_netif && esp_netif_is_netif_up(s_last_default_esp_netif)
&& (s_last_default_esp_netif->route_prio > esp_netif->route_prio)) {
esp_netif_set_default_netif_internal(s_last_default_esp_netif);
} else if (esp_netif_is_netif_up(esp_netif)) {
s_last_default_esp_netif = esp_netif;
esp_netif_set_default_netif_internal(s_last_default_esp_netif);
}
}
break;
default:
case ESP_NETIF_STOPPED:
case ESP_NETIF_LOST_IP:
{
s_last_default_esp_netif = NULL;
esp_netif_t *netif = esp_netif_next_unsafe(NULL);
while (netif) {
if (esp_netif_is_netif_up(netif)) {
if (s_last_default_esp_netif && esp_netif_is_netif_up(s_last_default_esp_netif)) {
if (netif->route_prio > s_last_default_esp_netif->route_prio) {
s_last_default_esp_netif = netif;
} // else not needed, as the s_last_default_esp_netif is correct
} else {
// s_last_default is either not set or down, current netif is up
s_last_default_esp_netif = netif;
}
}
netif = esp_netif_next_unsafe(netif);
}
if (s_last_default_esp_netif && esp_netif_is_netif_up(s_last_default_esp_netif)) {
esp_netif_set_default_netif_internal(s_last_default_esp_netif);
}
}
break;
}
return ESP_OK;
}
/**
* @brief This function sets default routing netif based on priorities of all interfaces which are up
*
* @param esp_netif current interface which just updated state
* @param action updating action (on-off)
*/
esp_err_t esp_netif_update_default_netif(esp_netif_t *esp_netif, esp_netif_route_prio_action_t action)
{
return esp_netif_lwip_ipc_call(esp_netif_update_default_netif_lwip, esp_netif, (void*)action);
}
esp_err_t esp_netif_set_default_netif(esp_netif_t *esp_netif)
{
return esp_netif_update_default_netif(esp_netif, ESP_NETIF_SET_DEFAULT);
}
esp_netif_t *esp_netif_get_default_netif(void)
{
return s_last_default_esp_netif;
}
static inline esp_netif_t* lwip_get_esp_netif(struct netif *netif)
{
#if LWIP_ESP_NETIF_DATA
return (esp_netif_t*)netif_get_client_data(netif, lwip_netif_client_id);
#else
return (esp_netif_t*)netif->state;
#endif
}
static inline void lwip_set_esp_netif(struct netif *netif, esp_netif_t* esp_netif)
{
#if LWIP_ESP_NETIF_DATA
netif_set_client_data(netif, lwip_netif_client_id, esp_netif);
#else
netif->state = esp_netif;
#endif
}
#if CONFIG_ESP_NETIF_BRIDGE_EN
esp_err_t esp_netif_bridge_add_port(esp_netif_t *esp_netif_br, esp_netif_t *esp_netif_port)
{
if (ERR_OK != bridgeif_add_port(esp_netif_br->lwip_netif, esp_netif_port->lwip_netif)) {
return ESP_FAIL;
}
return ESP_OK;
}
esp_err_t esp_netif_bridge_fdb_add(esp_netif_t *esp_netif_br, uint8_t *addr, uint64_t ports_mask)
{
bridgeif_portmask_t ports = (bridgeif_portmask_t)ports_mask;
if (ports_mask & ESP_NETIF_BR_FDW_CPU) {
ports |= 1 << BRIDGEIF_MAX_PORTS;
}
if (ERR_OK != bridgeif_fdb_add(esp_netif_br->lwip_netif, (const struct eth_addr *)addr, ports)) {
return ESP_FAIL;
}
return ESP_OK;
}
esp_err_t esp_netif_bridge_fdb_remove(esp_netif_t *esp_netif_br, uint8_t *addr)
{
if (ERR_OK != bridgeif_fdb_remove(esp_netif_br->lwip_netif, (const struct eth_addr *)addr)) {
return ESP_FAIL;
}
return ESP_OK;
}
#endif // CONFIG_ESP_NETIF_BRIDGE_EN
#if CONFIG_LWIP_IPV4
void esp_netif_set_ip4_addr(esp_ip4_addr_t *addr, uint8_t a, uint8_t b, uint8_t c, uint8_t d)
{
ip4_addr_t *address = (ip4_addr_t*)addr;
IP4_ADDR(address, a, b, c, d);
}
char * esp_ip4addr_ntoa(const esp_ip4_addr_t *addr, char *buf, int buflen)
{
return ip4addr_ntoa_r((ip4_addr_t *)addr, buf, buflen);
}
uint32_t esp_ip4addr_aton(const char *addr)
{
return ipaddr_addr(addr);
}
#endif
esp_err_t esp_netif_str_to_ip4(const char *src, esp_ip4_addr_t *dst)
{
if (src == NULL || dst == NULL) {
return ESP_ERR_INVALID_ARG;
}
int err = inet_pton(AF_INET, src, dst);
return err == 1 ? ESP_OK : ESP_FAIL;
}
esp_err_t esp_netif_str_to_ip6(const char *src, esp_ip6_addr_t *dst)
{
if (src == NULL || dst == NULL) {
return ESP_ERR_INVALID_ARG;
}
int err = inet_pton(AF_INET6, src, dst);
return err == 1 ? ESP_OK : ESP_FAIL;
}
esp_netif_iodriver_handle esp_netif_get_io_driver(esp_netif_t *esp_netif)
{
return esp_netif->driver_handle;
}
esp_netif_t* esp_netif_get_handle_from_netif_impl(void *dev)
{
// ppp_pcb ptr would never get to app code, so this function only works with vanilla lwip impl
struct netif *lwip_netif = dev;
return lwip_get_esp_netif(lwip_netif);
}
void* esp_netif_get_netif_impl(esp_netif_t *esp_netif)
{
if (esp_netif) {
return esp_netif->lwip_netif;
}
return NULL;
}
#if CONFIG_ESP_NETIF_SET_DNS_PER_DEFAULT_NETIF
static void store_dnsserver_info(struct netif* netif, u8_t numdns, const ip_addr_t *dnsserver)
{
if (netif == NULL) {
return;
}
esp_netif_t *esp_netif = lwip_get_esp_netif(netif);
if (esp_netif == NULL || !esp_netif_is_netif_listed(esp_netif)) {
return;
}
if (!ip_addr_isany(dnsserver)) {
ip_addr_copy(esp_netif->dns[numdns], *dnsserver);
} else {
ip_addr_copy(esp_netif->dns[numdns], *IP_ADDR_ANY);
}
}
#endif
static void tcpip_init_done(void *arg)
{
sys_sem_t *init_sem = arg;
#if LWIP_ESP_NETIF_DATA
if (lwip_netif_client_id == 0xFF) {
lwip_netif_client_id = netif_alloc_client_data_id();
}
#endif
sys_sem_signal(init_sem);
}
esp_err_t esp_netif_init(void)
{
if (!sys_thread_tcpip(LWIP_CORE_IS_TCPIP_INITIALIZED)) {
#if CONFIG_LWIP_HOOK_TCP_ISN_DEFAULT
uint8_t rand_buf[16];
/*
* This is early startup code where WiFi/BT is yet to be enabled and hence
* relevant entropy source is not available. However, bootloader enables
* SAR ADC based entropy source at its initialization, and our requirement
* of random bytes is pretty small (16), so we can assume that following
* API will provide sufficiently random data.
*/
esp_fill_random(rand_buf, sizeof(rand_buf));
lwip_init_tcp_isn(esp_log_timestamp(), rand_buf);
#endif
sys_sem_t init_sem;
if (sys_sem_new(&init_sem, 0) != ERR_OK) {
ESP_LOGE(TAG, "esp netif cannot create tcpip_init semaphore");
return ESP_FAIL;
}
#if LWIP_TCPIP_CORE_LOCKING
/* TCPIP thread is not initialized yet,
* pretend that the calling thread is holder
* to correctly set up the TCPIP task */
sys_thread_tcpip(LWIP_CORE_LOCK_MARK_HOLDER);
#endif
tcpip_init(tcpip_init_done, &init_sem);
sys_sem_wait(&init_sem);
sys_sem_free(&init_sem);
ESP_LOGD(TAG, "LwIP stack has been initialized");
#if CONFIG_ESP_NETIF_SET_DNS_PER_DEFAULT_NETIF
if (dns_setserver_callback(store_dnsserver_info) != ERR_OK) {
ESP_LOGE(TAG, "Feiled to configure DNS set server callback");
return ESP_FAIL;
}
#endif
}
#if !LWIP_TCPIP_CORE_LOCKING
if (!api_sync_sem) {
if (ERR_OK != sys_sem_new(&api_sync_sem, 0)) {
ESP_LOGE(TAG, "esp netif api sync sem init fail");
return ESP_FAIL;
}
}
if (!api_lock_sem) {
if (ERR_OK != sys_sem_new(&api_lock_sem, 1)) {
ESP_LOGE(TAG, "esp netif api lock sem init fail");
return ESP_FAIL;
}
}
#endif
ESP_LOGD(TAG, "esp-netif has been successfully initialized");
return ESP_OK;
}
esp_err_t esp_netif_deinit(void)
{
if (sys_thread_tcpip(LWIP_CORE_IS_TCPIP_INITIALIZED)) {
/* deinit of LwIP not supported:
* do not deinit semaphores and states,
* so init could be called multiple times
*
sys_sem_free(&api_sync_sem);
sys_sem_free(&api_lock_sem);
*/
return ESP_ERR_NOT_SUPPORTED;
}
return ESP_ERR_INVALID_STATE;
}
static esp_err_t esp_netif_init_configuration(esp_netif_t *esp_netif, const esp_netif_config_t *cfg)
{
// Basic esp_netif and lwip is a mandatory configuration and cannot be updated after esp_netif_new()
if (cfg == NULL || cfg->base == NULL || cfg->stack == NULL) {
return ESP_ERR_ESP_NETIF_INVALID_PARAMS;
}
// Configure general esp-netif properties
memcpy(esp_netif->mac, cfg->base->mac, NETIF_MAX_HWADDR_LEN);
#if CONFIG_LWIP_IPV4
if (cfg->base->ip_info == NULL) {
ip4_addr_set_zero(&esp_netif->ip_info->ip);
ip4_addr_set_zero(&esp_netif->ip_info->gw);
ip4_addr_set_zero(&esp_netif->ip_info->netmask);
} else {
memcpy(esp_netif->ip_info, cfg->base->ip_info, sizeof(esp_netif_ip_info_t));
}
memcpy(esp_netif->ip_info_old, esp_netif->ip_info, sizeof(esp_netif_ip_info_t));
#endif
// Setup main config parameters
esp_netif->lost_ip_event = cfg->base->lost_ip_event;
esp_netif->get_ip_event = cfg->base->get_ip_event;
esp_netif->flags = cfg->base->flags;
if (cfg->base->if_key) {
esp_netif->if_key = strdup(cfg->base->if_key);
}
if (cfg->base->if_desc) {
esp_netif->if_desc = strdup(cfg->base->if_desc);
}
if (cfg->base->route_prio) {
esp_netif->route_prio = cfg->base->route_prio;
}
#if CONFIG_ESP_NETIF_BRIDGE_EN
// Setup bridge configuration if the interface is to be bridge
if (cfg->base->flags & ESP_NETIF_FLAG_IS_BRIDGE) {
if (cfg->base->bridge_info != NULL) {
esp_netif->max_fdb_dyn_entries = cfg->base->bridge_info->max_fdb_dyn_entries;
esp_netif->max_fdb_sta_entries = cfg->base->bridge_info->max_fdb_sta_entries;
esp_netif->max_ports = cfg->base->bridge_info->max_ports;
} else {
return ESP_ERR_ESP_NETIF_INVALID_PARAMS;
}
}
#endif // CONFIG_ESP_NETIF_BRIDGE_EN
// Install network stack functions -- connects netif and L3 stack
const esp_netif_netstack_config_t *esp_netif_stack_config = cfg->stack;
if (cfg->base->flags & ESP_NETIF_FLAG_IS_PPP) {
#if CONFIG_PPP_SUPPORT
esp_netif->related_data = esp_netif_new_ppp(esp_netif, esp_netif_stack_config);
if (esp_netif->related_data == NULL) {
return ESP_ERR_ESP_NETIF_INIT_FAILED;
}
esp_netif->lwip_input_fn = esp_netif_stack_config->lwip_ppp.input_fn;
// Make the netif handle (used for tcpip input function) the ppp_netif
esp_netif->netif_handle = esp_netif->related_data;
#else
LOG_NETIF_DISABLED_AND_DO("PPP", return ESP_ERR_NOT_SUPPORTED);
#endif
} else {
if (esp_netif_stack_config-> lwip.init_fn) {
esp_netif->lwip_init_fn = esp_netif_stack_config->lwip.init_fn;
}
if (esp_netif_stack_config->lwip.input_fn) {
esp_netif->lwip_input_fn = esp_netif_stack_config->lwip.input_fn;
}
// Make the netif handle (used for tcpip input function) the lwip_netif itself
esp_netif->netif_handle = esp_netif->lwip_netif;
}
// Install IO functions only if provided -- connects driver and netif
// this configuration could be updated after esp_netif_new(), typically in post_attach callback
if (cfg->driver) {
const esp_netif_driver_ifconfig_t *esp_netif_driver_config = cfg->driver;
if (esp_netif_driver_config->handle) {
esp_netif->driver_handle = esp_netif_driver_config->handle;
}
if (esp_netif_driver_config->transmit) {
esp_netif->driver_transmit = esp_netif_driver_config->transmit;
}
if (esp_netif_driver_config->transmit_wrap) {
esp_netif->driver_transmit_wrap = esp_netif_driver_config->transmit_wrap;
}
if (esp_netif_driver_config->driver_free_rx_buffer) {
esp_netif->driver_free_rx_buffer = esp_netif_driver_config->driver_free_rx_buffer;
}
}
return ESP_OK;
}
static esp_err_t tcpip_exec_api(esp_netif_api_msg_t *msg)
{
return msg->user_fn(msg->data);
}
esp_err_t esp_netif_tcpip_exec(esp_netif_callback_fn fn, void*ctx)
{
return esp_netif_lwip_ipc_call_fn(tcpip_exec_api, fn, ctx);
}
static esp_err_t esp_netif_new_api(esp_netif_api_msg_t *msg)
{
const esp_netif_config_t *esp_netif_config = msg->data;
// mandatory configuration must be provided when creating esp_netif object
if (esp_netif_config == NULL ||
esp_netif_config->base->if_key == NULL ||
NULL != esp_netif_get_handle_from_ifkey_unsafe(esp_netif_config->base->if_key)) {
ESP_LOGE(TAG, "%s: Failed to configure netif with config=%p (config or if_key is NULL or duplicate key)",
__func__, esp_netif_config);
return ESP_FAIL;
}
#if ESP_DHCPS
// DHCP server and client cannot be configured together
if((esp_netif_config->base->flags & ESP_NETIF_DHCP_SERVER) &&
(esp_netif_config->base->flags & ESP_NETIF_DHCP_CLIENT)) {
ESP_LOGE(TAG, "%s: Failed to configure netif with config=%p (DHCP server and client cannot be configured together)",
__func__, esp_netif_config);
return ESP_FAIL;
}
#endif
// Create parent esp-netif object
esp_netif_t *esp_netif = calloc(1, sizeof(struct esp_netif_obj));
if (!esp_netif) {
ESP_LOGE(TAG, "Failed to allocate %" PRIu32 " bytes (free heap size %" PRIu32 ")", (uint32_t)sizeof(struct esp_netif_obj),
esp_get_free_heap_size());
return ESP_FAIL;
}
// Create ip info
esp_netif_ip_info_t *ip_info = calloc(1, sizeof(esp_netif_ip_info_t));
if (!ip_info) {
ESP_LOGE(TAG, "Failed to allocate %" PRIu32 " bytes (free heap size %" PRIu32 ")", (uint32_t)sizeof(esp_netif_ip_info_t),
esp_get_free_heap_size());
free(esp_netif);
return ESP_FAIL;
}
esp_netif->ip_info = ip_info;
// creating another ip info (to store old ip)
ip_info = calloc(1, sizeof(esp_netif_ip_info_t));
if (!ip_info) {
ESP_LOGE(TAG, "Failed to allocate %" PRIu32 " bytes (free heap size %" PRIu32 ")", (uint32_t)sizeof(esp_netif_ip_info_t),
esp_get_free_heap_size());
free(esp_netif->ip_info);
free(esp_netif);
return ESP_FAIL;
}
esp_netif->ip_info_old = ip_info;
// Create underlying lwip netif
struct netif * lwip_netif = calloc(1, sizeof(struct netif));
if (!lwip_netif) {
ESP_LOGE(TAG, "Failed to allocate %" PRIu32 " bytes (free heap size %" PRIu32 ")", (uint32_t)sizeof(struct netif),
esp_get_free_heap_size());
free(esp_netif->ip_info_old);
free(esp_netif->ip_info);
free(esp_netif);
return ESP_FAIL;
}
esp_netif->lwip_netif = lwip_netif;
esp_netif_add_to_list_unsafe(esp_netif);
#if ESP_DHCPS
// Create DHCP server structure
if (esp_netif_config->base->flags & ESP_NETIF_DHCP_SERVER) {
esp_netif->dhcps = dhcps_new();
if (esp_netif->dhcps == NULL) {
ESP_LOGE(TAG, "Failed to create dhcp server handle");
esp_netif_api_msg_t to_destroy = { .esp_netif = esp_netif};
esp_netif_destroy_api(&to_destroy);
return ESP_FAIL;
}
}
#endif
// Configure the created object with provided configuration
esp_err_t ret = esp_netif_init_configuration(esp_netif, esp_netif_config);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Initial configuration of esp_netif failed with %d", ret);
esp_netif_api_msg_t to_destroy = { .esp_netif = esp_netif};
esp_netif_destroy_api(&to_destroy);
return ESP_FAIL;
}
lwip_set_esp_netif(lwip_netif, esp_netif);
if (netif_callback.callback_fn == NULL ) {
netif_add_ext_callback(&netif_callback, netif_callback_fn);
}
*msg->p_esp_netif = esp_netif;
return ESP_OK;
}
esp_netif_t *esp_netif_new(const esp_netif_config_t *config)
{
esp_netif_t *netif = NULL;
esp_netif_lwip_ipc_call_get_netif(esp_netif_new_api, &netif, (void *)config);
return netif;
}
static esp_err_t get_handle_from_ifkey_api(esp_netif_api_msg_t *msg)
{
*msg->p_esp_netif = esp_netif_get_handle_from_ifkey_unsafe(msg->data);
return ESP_OK;
}
esp_netif_t *esp_netif_get_handle_from_ifkey(const char *if_key)
{
esp_netif_t *netif = NULL;
esp_netif_lwip_ipc_call_get_netif(get_handle_from_ifkey_api, &netif, (void*)if_key);
return netif;
}
typedef struct find_if_api {
esp_netif_find_predicate_t fn;
void *ctx;
} find_if_api_t;
static esp_err_t esp_netif_find_if_api(esp_netif_api_msg_t *msg)
{
find_if_api_t *find_if_api = msg->data;
esp_netif_t *esp_netif = NULL;
while ((esp_netif = esp_netif_next_unsafe(esp_netif)) != NULL) {
if (find_if_api->fn(esp_netif, find_if_api->ctx)) {
*msg->p_esp_netif = esp_netif;
return ESP_OK;
}
}
return ESP_FAIL;
}
esp_netif_t *esp_netif_find_if(esp_netif_find_predicate_t fn, void *ctx)
{
esp_netif_t *netif = NULL;
find_if_api_t find_if_api = { .fn = fn, .ctx = ctx };
if (esp_netif_lwip_ipc_call_get_netif(esp_netif_find_if_api, &netif, &find_if_api) == ESP_OK) {
return netif;
}
return NULL;
}
static void esp_netif_lwip_remove(esp_netif_t *esp_netif)
{
if (esp_netif->lwip_netif) {
if (netif_is_up(esp_netif->lwip_netif)) {
netif_set_down(esp_netif->lwip_netif);
}
netif_remove(esp_netif->lwip_netif);
#if ESP_GRATUITOUS_ARP
if (esp_netif->flags & ESP_NETIF_FLAG_GARP) {
netif_unset_garp_flag(esp_netif->lwip_netif);
}
#endif
#if ESP_MLDV6_REPORT && LWIP_IPV6
if (esp_netif->flags & ESP_NETIF_FLAG_MLDV6_REPORT) {
netif_unset_mldv6_flag(esp_netif);
}
#endif
if (esp_netif->flags & ESP_NETIF_DHCP_CLIENT) {
#if CONFIG_LWIP_IPV4
dhcp_cleanup(esp_netif->lwip_netif);
#endif
}
}
}
static esp_err_t esp_netif_lwip_add(esp_netif_t *esp_netif)
{
ESP_COMPILER_DIAGNOSTIC_PUSH_IGNORE("-Wanalyzer-malloc-leak"); // False-positive detection. TODO GCC-366
if (esp_netif->lwip_netif == NULL) {
esp_netif->lwip_netif = calloc(1, sizeof(struct netif));
if (esp_netif->lwip_netif == NULL) {
return ESP_ERR_NO_MEM;
}
}
ESP_COMPILER_DIAGNOSTIC_POP("-Wanalyzer-malloc-leak");
if (esp_netif->flags & ESP_NETIF_FLAG_IS_PPP) {
#if CONFIG_PPP_SUPPORT
err_t err = esp_netif->lwip_init_fn(NULL);
if (err != ERR_OK) {
ESP_LOGE(TAG, "Init netif failed with %" PRId8 "", err);
return ESP_ERR_ESP_NETIF_INIT_FAILED;
}
#else
LOG_NETIF_DISABLED_AND_DO("PPP", return ESP_ERR_NOT_SUPPORTED);
#endif
}
#if CONFIG_ESP_NETIF_BRIDGE_EN
if (esp_netif->flags & ESP_NETIF_FLAG_IS_BRIDGE) {
bridgeif_initdata_t bridge_initdata = {
.max_fdb_dynamic_entries = esp_netif->max_fdb_dyn_entries,
.max_fdb_static_entries = esp_netif->max_fdb_sta_entries,
.max_ports = esp_netif->max_ports
};
memcpy(&bridge_initdata.ethaddr, esp_netif->mac, ETH_HWADDR_LEN);
if (NULL == netif_add(esp_netif->lwip_netif, (struct ip4_addr*)&esp_netif->ip_info->ip,
(struct ip4_addr*)&esp_netif->ip_info->netmask, (struct ip4_addr*)&esp_netif->ip_info->gw,
&bridge_initdata, esp_netif->lwip_init_fn, tcpip_input)) {
esp_netif_lwip_remove(esp_netif);
return ESP_ERR_ESP_NETIF_IF_NOT_READY;
}
} else {
#endif // CONFIG_ESP_NETIF_BRIDGE_EN
if (NULL == netif_add(esp_netif->lwip_netif,
#if CONFIG_LWIP_IPV4
(struct ip4_addr*)&esp_netif->ip_info->ip,
(struct ip4_addr*)&esp_netif->ip_info->netmask,
(struct ip4_addr*)&esp_netif->ip_info->gw,
#endif
esp_netif, esp_netif->lwip_init_fn, tcpip_input)) {
esp_netif_lwip_remove(esp_netif);
return ESP_ERR_ESP_NETIF_IF_NOT_READY;
}
#if CONFIG_ESP_NETIF_BRIDGE_EN
}
#endif // CONFIG_ESP_NETIF_BRIDGE_EN
lwip_set_esp_netif(esp_netif->lwip_netif, esp_netif);
return ESP_OK;
}
static void esp_netif_destroy_related(esp_netif_t *esp_netif)
{
if (ESP_NETIF_IS_POINT2POINT_TYPE(esp_netif, PPP_LWIP_NETIF)) {
#if CONFIG_PPP_SUPPORT
esp_netif_destroy_ppp(esp_netif->related_data);
#endif
}
}
static esp_err_t esp_netif_destroy_api(esp_netif_api_msg_t *msg)
{
esp_netif_t *esp_netif = msg->esp_netif;
esp_netif_remove_from_list_unsafe(esp_netif);
if (esp_netif_get_nr_of_ifs() == 0) {
netif_remove_ext_callback(&netif_callback);
netif_callback.callback_fn = NULL;
}
free(esp_netif->ip_info);
free(esp_netif->ip_info_old);
free(esp_netif->if_key);
free(esp_netif->if_desc);
esp_netif_lwip_remove(esp_netif);
esp_netif_destroy_related(esp_netif);
free(esp_netif->lwip_netif);
free(esp_netif->hostname);
esp_netif_update_default_netif(esp_netif, ESP_NETIF_STOPPED);
#if ESP_DHCPS
dhcps_delete(esp_netif->dhcps);
#endif
free(esp_netif);
return ESP_OK;
}
void esp_netif_destroy(esp_netif_t *esp_netif)
{
if (esp_netif == NULL) {
return;
}
esp_netif_lwip_ipc_call(esp_netif_destroy_api, esp_netif, NULL);
}
esp_err_t esp_netif_attach(esp_netif_t *esp_netif, esp_netif_iodriver_handle driver_handle)
{
esp_netif_driver_base_t *base_driver = driver_handle;
esp_netif->driver_handle = driver_handle;
if (base_driver->post_attach) {
esp_err_t ret = base_driver->post_attach(esp_netif, driver_handle);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Post-attach callback of driver(%p) failed with %d", driver_handle, ret);
return ESP_ERR_ESP_NETIF_DRIVER_ATTACH_FAILED;
}
}
return ESP_OK;
}
esp_err_t esp_netif_set_driver_config(esp_netif_t *esp_netif,
const esp_netif_driver_ifconfig_t *driver_config)
{
if (esp_netif == NULL || driver_config == NULL) {
return ESP_ERR_ESP_NETIF_INVALID_PARAMS;
}
esp_netif->driver_handle = driver_config->handle;
esp_netif->driver_transmit = driver_config->transmit;
esp_netif->driver_transmit_wrap = driver_config->transmit_wrap;
esp_netif->driver_free_rx_buffer = driver_config->driver_free_rx_buffer;
return ESP_OK;
}
#if CONFIG_LWIP_IPV4
static esp_err_t esp_netif_reset_ip_info(esp_netif_t *esp_netif)
{
ip4_addr_set_zero(&(esp_netif->ip_info->ip));
ip4_addr_set_zero(&(esp_netif->ip_info->gw));
ip4_addr_set_zero(&(esp_netif->ip_info->netmask));
return ESP_OK;
}
#endif
esp_err_t esp_netif_set_mac_api(esp_netif_api_msg_t *msg)
{
uint8_t *mac = msg->data;
esp_netif_t* esp_netif = msg->esp_netif;
memcpy(esp_netif->mac, mac, NETIF_MAX_HWADDR_LEN);
memcpy(esp_netif->lwip_netif->hwaddr, mac, NETIF_MAX_HWADDR_LEN);
return ESP_OK;
}
esp_err_t esp_netif_set_mac(esp_netif_t *esp_netif, uint8_t mac[])
{
if (esp_netif == NULL || esp_netif->lwip_netif == NULL) {
return ESP_ERR_ESP_NETIF_IF_NOT_READY;
}
if (_IS_NETIF_ANY_POINT2POINT_TYPE(esp_netif)) {
return ESP_ERR_NOT_SUPPORTED;
}
return esp_netif_lwip_ipc_call(esp_netif_set_mac_api, esp_netif, mac);
}
esp_err_t esp_netif_get_mac(esp_netif_t *esp_netif, uint8_t mac[])
{
if (esp_netif == NULL || esp_netif->lwip_netif == NULL) {
return ESP_ERR_ESP_NETIF_IF_NOT_READY;
}
if (_IS_NETIF_ANY_POINT2POINT_TYPE(esp_netif)) {
return ESP_ERR_NOT_SUPPORTED;
}
if (esp_netif_is_netif_up(esp_netif)) {
memcpy(mac, esp_netif->lwip_netif->hwaddr, NETIF_MAX_HWADDR_LEN);
return ESP_OK;
}
memcpy(mac, esp_netif->mac, NETIF_MAX_HWADDR_LEN);
return ESP_OK;
}
#if ESP_DHCPS
static void esp_netif_dhcps_cb(void* arg, uint8_t ip[4], uint8_t mac[6])
{
esp_netif_t *esp_netif = arg;
ESP_LOGD(TAG, "%s esp_netif:%p", __func__, esp_netif);
ip_event_ap_staipassigned_t evt = { .esp_netif = esp_netif };
memcpy((char *)&evt.ip.addr, (char *)ip, sizeof(evt.ip.addr));
memcpy((char *)&evt.mac, mac, sizeof(evt.mac));
ESP_LOGI(TAG, "DHCP server assigned IP to a client, IP is: " IPSTR, IP2STR(&evt.ip));
ESP_LOGD(TAG, "Client's MAC: %x:%x:%x:%x:%x:%x", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
int ret = esp_event_post(IP_EVENT, IP_EVENT_AP_STAIPASSIGNED, &evt, sizeof(evt), 0);
if (ESP_OK != ret) {
ESP_LOGE(TAG, "dhcps cb: failed to post IP_EVENT_AP_STAIPASSIGNED (%x)", ret);
}
}
#endif
static esp_err_t esp_netif_config_sanity_check(const esp_netif_t * esp_netif)
{
if (esp_netif == NULL) {
ESP_LOGE(TAG, "Cannot start esp_netif: esp_netif must not be null");
return ESP_ERR_INVALID_STATE;
}
if ((!(esp_netif->flags & ESP_NETIF_FLAG_IS_BRIDGE) && (esp_netif->driver_transmit == NULL ||
esp_netif->driver_handle == NULL || esp_netif->lwip_input_fn == NULL)) ||
esp_netif->lwip_init_fn == NULL) {
ESP_LOGE(TAG, "Cannot start esp_netif: Missing mandatory configuration:\n"
"esp_netif->driver_transmit: %p, esp_netif->driver_handle:%p, "
"esp_netif->lwip_input_fn: %p, esp_netif->lwip_init_fn:%p",
esp_netif->driver_transmit, esp_netif->driver_handle,
esp_netif->lwip_input_fn, esp_netif->lwip_init_fn);
return ESP_ERR_INVALID_STATE;
}
return ESP_OK;
}
static esp_err_t esp_netif_start_api(esp_netif_api_msg_t *msg)
{
esp_netif_t * esp_netif = msg->esp_netif;
ESP_LOGD(TAG, "%s %p", __func__, esp_netif);
if (ESP_NETIF_IS_POINT2POINT_TYPE(esp_netif, PPP_LWIP_NETIF)) {
#if CONFIG_PPP_SUPPORT
return esp_netif_start_ppp(esp_netif);
#endif
}
ESP_ERROR_CHECK(esp_netif_config_sanity_check(esp_netif));
ESP_ERROR_CHECK(esp_netif_lwip_add(esp_netif));
#if ESP_IPV6_AUTOCONFIG
esp_netif->lwip_netif->ip6_autoconfig_enabled = 1;
#endif
if (esp_netif->flags&ESP_NETIF_FLAG_GARP) {
#if ESP_GRATUITOUS_ARP
netif_set_garp_flag(esp_netif->lwip_netif);
#else
ESP_LOGW(TAG,"CONFIG_LWIP_ESP_GRATUITOUS_ARP not enabled, but esp-netif configured with ESP_NETIF_FLAG_GARP");
#endif
}
struct netif *p_netif = esp_netif->lwip_netif;
if (esp_netif->flags&ESP_NETIF_FLAG_AUTOUP) {
ESP_LOGD(TAG, "%s Setting the lwip netif%p UP", __func__, p_netif);
netif_set_up(p_netif);
netif_set_link_up(p_netif);
}
if (esp_netif->flags & ESP_NETIF_DHCP_SERVER) {
#if ESP_DHCPS
if (esp_netif->dhcps_status == ESP_NETIF_DHCP_INIT) {
if (p_netif != NULL && netif_is_up(p_netif)) {
esp_netif_ip_info_t *default_ip = esp_netif->ip_info;
ip4_addr_t lwip_ip;
ip4_addr_t lwip_netmask;
memcpy(&lwip_ip, &default_ip->ip, sizeof(struct ip4_addr));
memcpy(&lwip_netmask, &default_ip->netmask, sizeof(struct ip4_addr));
dhcps_set_new_lease_cb(esp_netif->dhcps, esp_netif_dhcps_cb, esp_netif);
dhcps_set_option_info(esp_netif->dhcps, SUBNET_MASK, (void*)&lwip_netmask, sizeof(lwip_netmask));
if (dhcps_start(esp_netif->dhcps, p_netif, lwip_ip) != ERR_OK) {
ESP_LOGE(TAG, "DHCP server cannot be started");
esp_netif->dhcps_status = ESP_NETIF_DHCP_INIT;
return ESP_ERR_ESP_NETIF_DHCPS_START_FAILED;
}
esp_netif->dhcps_status = ESP_NETIF_DHCP_STARTED;
ESP_LOGI(TAG, "DHCP server started on interface %s with IP: " IPSTR, esp_netif->if_key, IP2STR(&lwip_ip));
esp_netif_update_default_netif(esp_netif, ESP_NETIF_STARTED);
return ESP_OK;
} else {
ESP_LOGD(TAG, "DHCP server re init");
esp_netif->dhcps_status = ESP_NETIF_DHCP_INIT;
return ESP_OK;
}
} else if (esp_netif->dhcps_status == ESP_NETIF_DHCP_STARTED) {
ESP_LOGD(TAG, "DHCP server already started");
return ESP_ERR_ESP_NETIF_DHCP_ALREADY_STARTED;
}
return ESP_OK;
#else
LOG_NETIF_DISABLED_AND_DO("DHCP Server", return ESP_ERR_NOT_SUPPORTED);
#endif
} else if (esp_netif->flags & ESP_NETIF_DHCP_CLIENT) {
#if CONFIG_LWIP_IPV4
if (esp_netif->dhcpc_status != ESP_NETIF_DHCP_STARTED) {
if (p_netif != NULL) {
struct dhcp *dhcp_data = NULL;
dhcp_data = netif_dhcp_data(p_netif);
if (dhcp_data == NULL) {
dhcp_data = (struct dhcp *)malloc(sizeof(struct dhcp));
if (dhcp_data == NULL) {
return ESP_ERR_NO_MEM;
}
dhcp_set_struct(p_netif, dhcp_data);
}
}
}
#else
LOG_NETIF_DISABLED_AND_DO("IPv4's DHCP Client", return ESP_ERR_NOT_SUPPORTED);
#endif
}
// For netifs with (active) DHCP client: we update the default netif after getting a valid IP
if (!((esp_netif->flags & ESP_NETIF_DHCP_CLIENT) && esp_netif->dhcpc_status != ESP_NETIF_DHCP_STOPPED)) {
esp_netif_update_default_netif(esp_netif, ESP_NETIF_STARTED);
}
return ESP_OK;
}
esp_err_t esp_netif_start(esp_netif_t *esp_netif)
{
return esp_netif_lwip_ipc_call(esp_netif_start_api, esp_netif, NULL);
}
static esp_err_t esp_netif_stop_api(esp_netif_api_msg_t *msg)
{
esp_netif_t *esp_netif = msg->esp_netif;
if (ESP_NETIF_IS_POINT2POINT_TYPE(esp_netif, PPP_LWIP_NETIF)) {
#if CONFIG_PPP_SUPPORT
esp_err_t ret = esp_netif_stop_ppp(esp_netif->related_data);
if (ret == ESP_OK) {
esp_netif_update_default_netif(esp_netif, ESP_NETIF_STOPPED);
}
return ret;
#endif
}
struct netif *lwip_netif = esp_netif->lwip_netif;
if (lwip_netif == NULL) {
return ESP_ERR_ESP_NETIF_IF_NOT_READY;
}
if (!netif_is_up(lwip_netif)) {
esp_netif_lwip_remove(esp_netif);
return ESP_ERR_ESP_NETIF_IF_NOT_READY;
}
if (esp_netif->flags & ESP_NETIF_DHCP_SERVER) {
#if ESP_DHCPS
if (dhcps_stop(esp_netif->dhcps, lwip_netif) != ERR_OK ||
esp_netif->dhcps_status != ESP_NETIF_DHCP_STOPPED) {
esp_netif->dhcps_status = ESP_NETIF_DHCP_INIT;
}
#else
LOG_NETIF_DISABLED_AND_DO("DHCP Server", return ESP_ERR_NOT_SUPPORTED);
#endif
} else if (esp_netif->flags & ESP_NETIF_DHCP_CLIENT) {
#if CONFIG_LWIP_IPV4
dhcp_release(lwip_netif);
dhcp_stop(lwip_netif);
dhcp_cleanup(lwip_netif);
esp_netif->dhcpc_status = ESP_NETIF_DHCP_INIT;
esp_netif_reset_ip_info(esp_netif);
#else
LOG_NETIF_DISABLED_AND_DO("IPv4's DHCP Client", return ESP_ERR_NOT_SUPPORTED);
#endif
}
netif_set_down(lwip_netif);
esp_netif_lwip_remove(esp_netif);
esp_netif_update_default_netif(esp_netif, ESP_NETIF_STOPPED);
return ESP_OK;
}
esp_err_t esp_netif_stop(esp_netif_t *esp_netif)
{
return esp_netif_lwip_ipc_call(esp_netif_stop_api, esp_netif, NULL);
}
void esp_netif_netstack_buf_ref(void *pbuf)
{
pbuf_ref(pbuf);
}
void esp_netif_netstack_buf_free(void *pbuf)
{
pbuf_free(pbuf);
}
//
// IO translate functions
//
void esp_netif_free_rx_buffer(void *h, void* buffer)
{
esp_netif_t *esp_netif = h;
esp_netif->driver_free_rx_buffer(esp_netif->driver_handle, buffer);
}
#ifdef CONFIG_ESP_NETIF_REPORT_DATA_TRAFFIC
static esp_err_t esp_netif_tx_rx_event_api(esp_netif_api_msg_t *msg)
{
bool enable = (bool)msg->data;
esp_netif_t *esp_netif = msg->esp_netif;
if (esp_netif == NULL) {
ESP_LOGE(TAG, "Invalid esp_netif");
return ESP_ERR_ESP_NETIF_INVALID_PARAMS;
}
ESP_LOGD(TAG, "%s esp_netif:%p", __func__, esp_netif);
esp_netif->tx_rx_events_enabled = enable;
return ESP_OK;
}
#endif
esp_err_t esp_netif_tx_rx_event_enable(esp_netif_t *esp_netif)
{
#ifdef CONFIG_ESP_NETIF_REPORT_DATA_TRAFFIC
return esp_netif_lwip_ipc_call(esp_netif_tx_rx_event_api, esp_netif, (void*)true /* Enable */);
#else
return ESP_FAIL;
#endif
}
esp_err_t esp_netif_tx_rx_event_disable(esp_netif_t *esp_netif)
{
#ifdef CONFIG_ESP_NETIF_REPORT_DATA_TRAFFIC
return esp_netif_lwip_ipc_call(esp_netif_tx_rx_event_api, esp_netif, (void*)false /* Disable */);
#else
return ESP_FAIL;
#endif
}
esp_err_t esp_netif_transmit(esp_netif_t *esp_netif, void* data, size_t len)
{
#ifdef CONFIG_ESP_NETIF_REPORT_DATA_TRAFFIC
if (unlikely(esp_netif->tx_rx_events_enabled)) {
ip_event_tx_rx_t evt = {
.esp_netif = esp_netif,
.len = len,
.dir = ESP_NETIF_TX,
};
esp_event_post(IP_EVENT, IP_EVENT_TX_RX, &evt, sizeof(evt), 0);
}
#endif
return (esp_netif->driver_transmit)(esp_netif->driver_handle, data, len);
}
esp_err_t esp_netif_transmit_wrap(esp_netif_t *esp_netif, void *data, size_t len, void *pbuf)
{
#ifdef CONFIG_ESP_NETIF_REPORT_DATA_TRAFFIC
if (unlikely(esp_netif->tx_rx_events_enabled)) {
ip_event_tx_rx_t evt = {
.esp_netif = esp_netif,
.len = len,
.dir = ESP_NETIF_TX,
};
esp_event_post(IP_EVENT, IP_EVENT_TX_RX, &evt, sizeof(evt), 0);
}
#endif
return (esp_netif->driver_transmit_wrap)(esp_netif->driver_handle, data, len, pbuf);
}
esp_err_t esp_netif_receive(esp_netif_t *esp_netif, void *buffer, size_t len, void *eb)
{
#ifdef CONFIG_ESP_NETIF_REPORT_DATA_TRAFFIC
if (unlikely(esp_netif->tx_rx_events_enabled)) {
ip_event_tx_rx_t evt = {
.esp_netif = esp_netif,
.len = len,
.dir = ESP_NETIF_RX,
};
esp_event_post(IP_EVENT, IP_EVENT_TX_RX, &evt, sizeof(evt), 0);
}
#endif
#ifdef CONFIG_ESP_NETIF_RECEIVE_REPORT_ERRORS
return esp_netif->lwip_input_fn(esp_netif->netif_handle, buffer, len, eb);
#else
esp_netif->lwip_input_fn(esp_netif->netif_handle, buffer, len, eb);
return ESP_OK;
#endif
}
#if CONFIG_LWIP_IPV4
static esp_err_t esp_netif_start_ip_lost_timer(esp_netif_t *esp_netif);
//
// DHCP:
//
static void esp_netif_internal_dhcpc_cb(struct netif *netif)
{
esp_netif_t *esp_netif;
ESP_LOGD(TAG, "%s lwip-netif:%p", __func__, netif);
if (netif == NULL || (esp_netif = lwip_get_esp_netif(netif)) == NULL) {
// internal pointer hasn't been configured yet (probably in the interface init_fn())
return;
}
esp_netif_ip_info_t *ip_info = esp_netif->ip_info;
esp_netif_ip_info_t *ip_info_old = esp_netif->ip_info_old;
if ( !ip4_addr_cmp(ip_2_ip4(&netif->ip_addr), IP4_ADDR_ANY4) ) {
//check whether IP is changed (or if we're an PPP interface)
if ( (!ip4_addr_cmp(ip_2_ip4(&netif->ip_addr), (&ip_info->ip)) ||
!ip4_addr_cmp(ip_2_ip4(&netif->netmask), (&ip_info->netmask)) ||
!ip4_addr_cmp(ip_2_ip4(&netif->gw), (&ip_info->gw)))
// post IP event for PPP interfaces even if IP hasn't changed
|| (_IS_NETIF_ANY_POINT2POINT_TYPE(esp_netif))) {
ip_event_got_ip_t evt = {
.esp_netif = esp_netif,
.ip_changed = false,
};
ip_event_t evt_id = esp_netif_get_event_id(esp_netif, ESP_NETIF_IP_EVENT_GOT_IP);
int ret;
ip4_addr_set(&ip_info->ip, ip_2_ip4(&netif->ip_addr));
ip4_addr_set(&ip_info->netmask, ip_2_ip4(&netif->netmask));
ip4_addr_set(&ip_info->gw, ip_2_ip4(&netif->gw));
//notify event
if (memcmp(ip_info, ip_info_old, sizeof(esp_netif_ip_info_t))) {
evt.ip_changed = true;
}
esp_netif_update_default_netif(esp_netif, ESP_NETIF_GOT_IP);
memcpy(&evt.ip_info, ip_info, sizeof(esp_netif_ip_info_t));
memcpy(ip_info_old, ip_info, sizeof(esp_netif_ip_info_t));
ESP_LOGD(TAG, "if%p ip changed=%d", esp_netif, evt.ip_changed);
ret = esp_event_post(IP_EVENT, evt_id, &evt, sizeof(evt), 0);
if (ESP_OK != ret) {
ESP_LOGE(TAG, "dhcpc cb: failed to post got ip event (%x)", ret);
}
#ifdef CONFIG_LWIP_DHCP_RESTORE_LAST_IP
dhcp_ip_addr_store(netif);
#endif /* CONFIG_LWIP_DHCP_RESTORE_LAST_IP */
} else {
ESP_LOGD(TAG, "if%p ip unchanged", esp_netif);
}
} else {
if (!ip4_addr_cmp(&ip_info->ip, IP4_ADDR_ANY4)) {
esp_netif_start_ip_lost_timer(esp_netif);
}
}
}
static void esp_netif_ip_lost_timer(void *arg)
{
esp_netif_t *esp_netif = esp_netif_is_active(arg);
if (esp_netif == NULL) {
ESP_LOGD(TAG, "%s esp_netif=%p not active any more", __func__, arg);
return;
}
ESP_LOGD(TAG, "%s esp_netif:%p", __func__, esp_netif);
esp_netif->timer_running = false;
struct netif *netif = esp_netif->lwip_netif;
if ( (!netif) || (netif && ip4_addr_cmp(ip_2_ip4(&netif->ip_addr), IP4_ADDR_ANY4))) {
ip_event_got_ip_t evt = {
.esp_netif = esp_netif,
};
int ret;
esp_netif_update_default_netif(esp_netif, ESP_NETIF_LOST_IP);
ESP_LOGD(TAG, "if%p ip lost tmr: raise ip lost event", esp_netif);
memset(esp_netif->ip_info_old, 0, sizeof(esp_netif_ip_info_t));
if (esp_netif->lost_ip_event) {
ret = esp_event_post(IP_EVENT, esp_netif->lost_ip_event,
&evt, sizeof(evt), 0);
if (ESP_OK != ret) {
ESP_LOGE(TAG, "ip lost timer: failed to post lost ip event (%x)", ret);
}
}
} else {
ESP_LOGD(TAG, "if%p ip lost tmr: no need raise ip lost event", esp_netif);
}
}
static esp_err_t esp_netif_start_ip_lost_timer(esp_netif_t *esp_netif)
{
esp_netif_ip_info_t *ip_info_old = esp_netif->ip_info;
struct netif *netif = esp_netif->lwip_netif;
ESP_LOGD(TAG, "%s esp_netif:%p", __func__, esp_netif);
if (esp_netif->timer_running) {
ESP_LOGD(TAG, "if%p start ip lost tmr: already started", esp_netif);
return ESP_OK;
}
if ( netif && (CONFIG_ESP_NETIF_IP_LOST_TIMER_INTERVAL > 0)) {
esp_netif->timer_running = true;
sys_timeout(CONFIG_ESP_NETIF_IP_LOST_TIMER_INTERVAL * 1000, esp_netif_ip_lost_timer, (void *)esp_netif);
ESP_LOGD(TAG, "if%p start ip lost tmr: interval=%d", esp_netif, CONFIG_ESP_NETIF_IP_LOST_TIMER_INTERVAL);
return ESP_OK;
}
ESP_LOGD(TAG, "if%p start ip lost tmr: no need start because netif=%p interval=%d ip=%" PRIx32,
esp_netif, netif, (CONFIG_ESP_NETIF_IP_LOST_TIMER_INTERVAL), ip_info_old->ip.addr);
return ESP_OK;
}
static esp_err_t esp_netif_dhcpc_stop_api(esp_netif_api_msg_t *msg)
{
esp_netif_t *esp_netif = msg->esp_netif;
ESP_LOGD(TAG, "%s esp_netif:%p", __func__, esp_netif);
if (esp_netif == NULL) {
ESP_LOGE(TAG, "dhcp client stop called with NULL api");
return ESP_ERR_ESP_NETIF_INVALID_PARAMS;
}
if (esp_netif->dhcpc_status == ESP_NETIF_DHCP_STARTED) {
struct netif *p_netif = esp_netif->lwip_netif;
if (p_netif != NULL) {
dhcp_stop(p_netif);
esp_netif_reset_ip_info(esp_netif);
esp_netif_start_ip_lost_timer(esp_netif);
} else {
ESP_LOGD(TAG, "dhcp client if not ready");
return ESP_ERR_ESP_NETIF_IF_NOT_READY;
}
} else if (esp_netif->dhcpc_status == ESP_NETIF_DHCP_STOPPED) {
ESP_LOGD(TAG, "dhcp client already stopped");
return ESP_ERR_ESP_NETIF_DHCP_ALREADY_STOPPED;
}
ESP_LOGD(TAG, "dhcp client stop successfully");
esp_netif->dhcpc_status = ESP_NETIF_DHCP_STOPPED;
#ifdef CONFIG_LWIP_DHCP_RESTORE_LAST_IP
dhcp_ip_addr_erase(esp_netif->lwip_netif);
#endif /* CONFIG_LWIP_DHCP_RESTORE_LAST_IP */
return ESP_OK;
}
esp_err_t esp_netif_dhcpc_stop(esp_netif_t *esp_netif) _RUN_IN_LWIP_TASK_IF_SUPPORTED(esp_netif_dhcpc_stop_api, esp_netif, NULL)
static 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);
}
}
static esp_err_t esp_netif_dhcpc_start_api(esp_netif_api_msg_t *msg)
{
esp_netif_t *esp_netif = msg->esp_netif;
ESP_LOGD(TAG, "%s esp_netif:%p", __func__, esp_netif);
if (!esp_netif) {
return ESP_ERR_INVALID_ARG;
}
if (esp_netif->dhcpc_status == ESP_NETIF_DHCP_STARTED) {
ESP_LOGD(TAG, "dhcp client already started");
return ESP_ERR_ESP_NETIF_DHCP_ALREADY_STARTED;
}
struct netif *p_netif = esp_netif->lwip_netif;
esp_netif_reset_ip_info(esp_netif);
#if LWIP_DNS
dns_clear_servers(true);
#endif
if (p_netif != NULL) {
if (netif_is_up(p_netif)) {
ip_addr_set_zero(&p_netif->ip_addr);
ip_addr_set_zero(&p_netif->netmask);
ip_addr_set_zero(&p_netif->gw);
esp_netif_start_ip_lost_timer(esp_netif);
} else {
ESP_LOGD(TAG, "dhcp client re init");
esp_netif->dhcpc_status = ESP_NETIF_DHCP_INIT;
return ESP_OK;
}
ESP_LOGD(TAG, "starting dhcp client");
if (dhcp_start(p_netif) != ERR_OK) {
ESP_LOGE(TAG, "dhcp client start failed");
return ESP_ERR_ESP_NETIF_DHCPC_START_FAILED;
}
esp_netif->dhcpc_status = ESP_NETIF_DHCP_STARTED;
return ESP_OK;
} else {
ESP_LOGD(TAG, "dhcp client re init");
esp_netif->dhcpc_status = ESP_NETIF_DHCP_INIT;
return ESP_OK;
}
}
esp_err_t esp_netif_dhcpc_start(esp_netif_t *esp_netif) _RUN_IN_LWIP_TASK_IF_SUPPORTED(esp_netif_dhcpc_start_api, esp_netif, NULL)
#endif /* CONFIG_LWIP_IPV4 */
#if ESP_DHCPS
esp_err_t esp_netif_dhcps_get_status(esp_netif_t *esp_netif, esp_netif_dhcp_status_t *status)
{
if (!esp_netif || (esp_netif->flags & ESP_NETIF_DHCP_CLIENT) || _IS_NETIF_ANY_POINT2POINT_TYPE(esp_netif)) {
return ESP_ERR_INVALID_ARG;
}
*status = esp_netif->dhcps_status;
return ESP_OK;
}
#endif
esp_err_t esp_netif_dhcpc_get_status(esp_netif_t *esp_netif, esp_netif_dhcp_status_t *status)
{
if (!esp_netif || (esp_netif->flags & ESP_NETIF_DHCP_SERVER) || _IS_NETIF_ANY_POINT2POINT_TYPE(esp_netif)) {
return ESP_ERR_INVALID_ARG;
}
*status = esp_netif->dhcpc_status;
return ESP_OK;
}
#if ESP_DHCPS
static esp_err_t esp_netif_dhcps_start_api(esp_netif_api_msg_t *msg)
{
esp_netif_t *esp_netif = msg->esp_netif;
ESP_LOGD(TAG, "%s esp_netif:%p", __func__, esp_netif);
if (!esp_netif) {
return ESP_ERR_INVALID_ARG;
}
if (esp_netif->dhcps_status == ESP_NETIF_DHCP_STARTED) {
ESP_LOGD(TAG, "dhcp server already started");
return ESP_ERR_ESP_NETIF_DHCP_ALREADY_STARTED;
}
struct netif *p_netif = esp_netif->lwip_netif;
if (p_netif != NULL && netif_is_up(p_netif)) {
esp_netif_ip_info_t *default_ip = esp_netif->ip_info;
ip4_addr_t lwip_ip;
ip4_addr_t lwip_netmask;
memcpy(&lwip_ip, &default_ip->ip, sizeof(struct ip4_addr));
memcpy(&lwip_netmask, &default_ip->netmask, sizeof(struct ip4_addr));
dhcps_set_new_lease_cb(esp_netif->dhcps, esp_netif_dhcps_cb, esp_netif);
dhcps_set_option_info(esp_netif->dhcps, SUBNET_MASK, (void*)&lwip_netmask, sizeof(lwip_netmask));
if (dhcps_start(esp_netif->dhcps, p_netif, lwip_ip) != ERR_OK) {
ESP_LOGE(TAG, "DHCP server cannot be started");
esp_netif->dhcps_status = ESP_NETIF_DHCP_INIT;
return ESP_ERR_ESP_NETIF_DHCPS_START_FAILED;
}
esp_netif->dhcps_status = ESP_NETIF_DHCP_STARTED;
ESP_LOGD(TAG, "DHCP server started successfully");
return ESP_OK;
} else {
ESP_LOGD(TAG, "dhcp server re init");
esp_netif->dhcps_status = ESP_NETIF_DHCP_INIT;
return ESP_OK;
}
}
esp_err_t esp_netif_dhcps_start(esp_netif_t *esp_netif) _RUN_IN_LWIP_TASK_IF_SUPPORTED(esp_netif_dhcps_start_api, esp_netif, NULL)
static esp_err_t esp_netif_dhcps_stop_api(esp_netif_api_msg_t *msg)
{
esp_netif_t *esp_netif = msg->esp_netif;
ESP_LOGD(TAG, "%s esp_netif:%p", __func__, esp_netif);
if (!esp_netif) {
return ESP_ERR_INVALID_ARG;
}
struct netif *p_netif = esp_netif->lwip_netif;
if (esp_netif->dhcps_status == ESP_NETIF_DHCP_STARTED) {
if (dhcps_stop(esp_netif->dhcps, p_netif) != ERR_OK) {
ESP_LOGD(TAG, "dhcp server if not ready");
return ESP_ERR_ESP_NETIF_IF_NOT_READY;
}
} else if (esp_netif->dhcps_status == ESP_NETIF_DHCP_STOPPED) {
ESP_LOGD(TAG, "dhcp server already stopped");
return ESP_ERR_ESP_NETIF_DHCP_ALREADY_STOPPED;
}
ESP_LOGD(TAG, "dhcp server stop successfully");
esp_netif->dhcps_status = ESP_NETIF_DHCP_STOPPED;
return ESP_OK;
}
esp_err_t esp_netif_dhcps_stop(esp_netif_t *esp_netif) _RUN_IN_LWIP_TASK_IF_SUPPORTED(esp_netif_dhcps_stop_api, esp_netif, NULL)
#endif
static esp_err_t esp_netif_set_hostname_api(esp_netif_api_msg_t *msg)
{
esp_netif_t *esp_netif = msg->esp_netif;
const char *hostname = msg->data;
ESP_LOGD(TAG, "%s esp_netif:%p hostname %s", __func__, esp_netif, hostname);
if (!esp_netif) {
return ESP_ERR_INVALID_ARG;
}
#if LWIP_NETIF_HOSTNAME
struct netif *p_netif = esp_netif->lwip_netif;
if (strlen(hostname) > ESP_NETIF_HOSTNAME_MAX_SIZE) {
return ESP_ERR_ESP_NETIF_INVALID_PARAMS;
}
if (p_netif != NULL) {
if (esp_netif->hostname) {
free(esp_netif->hostname);
}
esp_netif->hostname = strdup(hostname);
if (esp_netif->hostname == NULL) {
p_netif->hostname = CONFIG_LWIP_LOCAL_HOSTNAME;
return ESP_ERR_NO_MEM;
}
p_netif->hostname = esp_netif->hostname;
return ESP_OK;
} else {
return ESP_ERR_ESP_NETIF_IF_NOT_READY;
}
#else
return ESP_ERR_ESP_NETIF_IF_NOT_READY;
#endif
}
esp_err_t esp_netif_set_hostname(esp_netif_t *esp_netif, const char *hostname) _RUN_IN_LWIP_TASK_IF_SUPPORTED(esp_netif_set_hostname_api, esp_netif, hostname)
esp_err_t esp_netif_get_hostname(esp_netif_t *esp_netif, const char **hostname)
{
ESP_LOGD(TAG, "%s esp_netif:%p", __func__, esp_netif);
if (!esp_netif || _IS_NETIF_ANY_POINT2POINT_TYPE(esp_netif)) {
return ESP_ERR_INVALID_ARG;
}
#if LWIP_NETIF_HOSTNAME
struct netif *p_netif = esp_netif->lwip_netif;
if (p_netif != NULL && p_netif->hostname != NULL) {
*hostname = p_netif->hostname;
return ESP_OK;
} else {
return ESP_ERR_ESP_NETIF_IF_NOT_READY;
}
#else
return ESP_ERR_ESP_NETIF_IF_NOT_READY;
#endif
}
static esp_err_t esp_netif_up_api(esp_netif_api_msg_t *msg)
{
esp_netif_t *esp_netif = msg->esp_netif;
ESP_LOGD(TAG, "%s esp_netif:%p", __func__, esp_netif);
if (!esp_netif) {
return ESP_ERR_INVALID_STATE;
}
struct netif *lwip_netif = esp_netif->lwip_netif;
#if CONFIG_LWIP_IPV4
/* use last obtained ip, or static ip */
netif_set_addr(lwip_netif, (ip4_addr_t*)&esp_netif->ip_info->ip, (ip4_addr_t*)&esp_netif->ip_info->netmask, (ip4_addr_t*)&esp_netif->ip_info->gw);
#endif
netif_set_up(lwip_netif);
netif_set_link_up(lwip_netif);
// For netifs with (active) DHCP client: we update the default netif after getting a valid IP
if (!((esp_netif->flags & ESP_NETIF_DHCP_CLIENT) && esp_netif->dhcpc_status != ESP_NETIF_DHCP_STOPPED)) {
esp_netif_update_default_netif(esp_netif, ESP_NETIF_STARTED);
}
return ESP_OK;
}
esp_err_t esp_netif_up(esp_netif_t *esp_netif) _RUN_IN_LWIP_TASK(esp_netif_up_api, esp_netif, NULL)
static esp_err_t esp_netif_down_api(esp_netif_api_msg_t *msg)
{
esp_netif_t *esp_netif = msg->esp_netif;
ESP_LOGD(TAG, "%s esp_netif:%p", __func__, esp_netif);
if (!esp_netif) {
return ESP_ERR_INVALID_STATE;
}
struct netif *lwip_netif = esp_netif->lwip_netif;
if (esp_netif->flags & ESP_NETIF_DHCP_CLIENT && esp_netif->dhcpc_status == ESP_NETIF_DHCP_STARTED) {
#if CONFIG_LWIP_IPV4
dhcp_stop(esp_netif->lwip_netif);
esp_netif->dhcpc_status = ESP_NETIF_DHCP_INIT;
esp_netif_reset_ip_info(esp_netif);
#endif
}
#if CONFIG_LWIP_IPV6
#if ESP_MLDV6_REPORT
if (esp_netif->flags & ESP_NETIF_FLAG_MLDV6_REPORT) {
netif_unset_mldv6_flag(esp_netif);
}
#endif
for(int8_t i = 0 ;i < LWIP_IPV6_NUM_ADDRESSES ;i++) {
netif_ip6_addr_set(lwip_netif, i, IP6_ADDR_ANY6);
netif_ip6_addr_set_valid_life(lwip_netif, i, 0);
netif_ip6_addr_set_pref_life(lwip_netif, i, 0);
netif_ip6_addr_set_state(lwip_netif, i, IP6_ADDR_INVALID);
}
#endif
#if CONFIG_LWIP_IPV4
netif_set_addr(lwip_netif, IP4_ADDR_ANY4, IP4_ADDR_ANY4, IP4_ADDR_ANY4);
#endif
netif_set_down(lwip_netif);
netif_set_link_down(lwip_netif);
if (esp_netif->flags & ESP_NETIF_DHCP_CLIENT) {
#if CONFIG_LWIP_IPV4
esp_netif_start_ip_lost_timer(esp_netif);
#endif
}
esp_netif_update_default_netif(esp_netif, ESP_NETIF_STOPPED);
return ESP_OK;
}
esp_err_t esp_netif_down(esp_netif_t *esp_netif) _RUN_IN_LWIP_TASK(esp_netif_down_api, esp_netif, NULL)
bool esp_netif_is_netif_up(esp_netif_t *esp_netif)
{
ESP_LOGV(TAG, "%s esp_netif:%p", __func__, esp_netif);
if (esp_netif != NULL && esp_netif->lwip_netif != NULL) {
if (_IS_NETIF_ANY_POINT2POINT_TYPE(esp_netif)) {
// ppp implementation uses netif_set_link_up/down to update link state
return netif_is_link_up(esp_netif->lwip_netif);
}
// esp-netif handlers and drivers take care to set_netif_up/down on link state update
return netif_is_up(esp_netif->lwip_netif);
} else {
return false;
}
}
#if CONFIG_LWIP_IPV4
esp_err_t esp_netif_get_old_ip_info(esp_netif_t *esp_netif, esp_netif_ip_info_t *ip_info)
{
ESP_LOGD(TAG, "%s esp_netif:%p", __func__, esp_netif);
if (esp_netif == NULL || ip_info == NULL) {
return ESP_ERR_INVALID_ARG;
}
memcpy(ip_info, esp_netif->ip_info_old, sizeof(esp_netif_ip_info_t));
return ESP_OK;
}
esp_err_t esp_netif_get_ip_info(esp_netif_t *esp_netif, esp_netif_ip_info_t *ip_info)
{
ESP_LOGD(TAG, "%s esp_netif:%p", __func__, esp_netif);
if (esp_netif == NULL || ip_info == NULL) {
return ESP_ERR_INVALID_ARG;
}
struct netif *p_netif = esp_netif->lwip_netif;
if (p_netif != NULL && netif_is_up(p_netif)) {
ip4_addr_set(&ip_info->ip, ip_2_ip4(&p_netif->ip_addr));
ip4_addr_set(&ip_info->netmask, ip_2_ip4(&p_netif->netmask));
ip4_addr_set(&ip_info->gw, ip_2_ip4(&p_netif->gw));
return ESP_OK;
}
memcpy(ip_info, esp_netif->ip_info, sizeof(esp_netif_ip_info_t));
return ESP_OK;
}
bool esp_netif_is_valid_static_ip(esp_netif_ip_info_t *ip_info)
{
if (!(ip4_addr_isany_val(ip_info->ip) || ip4_addr_isany_val(ip_info->netmask))) {
// let's assume valid ip_info is when none of ip and netmask is 'any' address (zeros)
return true;
}
return false;
}
static esp_err_t esp_netif_set_ip_old_info_api(esp_netif_api_msg_t *msg)
{
esp_netif_t *esp_netif = msg->esp_netif;
const esp_netif_ip_info_t *ip_info = msg->data;
ESP_LOGD(TAG, "%s esp_netif:%p", __func__, esp_netif);
if (esp_netif == NULL || ip_info == NULL) {
return ESP_ERR_INVALID_STATE;
}
memcpy(msg->esp_netif->ip_info_old, msg->data, sizeof(esp_netif_ip_info_t));
return ESP_OK;
}
esp_err_t esp_netif_set_old_ip_info(esp_netif_t *esp_netif, const esp_netif_ip_info_t *ip_info) _RUN_IN_LWIP_TASK_IF_SUPPORTED(esp_netif_set_ip_old_info_api, esp_netif, ip_info)
static esp_err_t esp_netif_set_ip_info_api(esp_netif_api_msg_t *msg)
{
esp_netif_t *esp_netif = msg->esp_netif;
const esp_netif_ip_info_t *ip_info = msg->data;
ESP_LOGD(TAG, "%s esp_netif:%p", __func__, esp_netif);
if (esp_netif == NULL || ip_info == NULL) {
return ESP_ERR_INVALID_STATE;
}
if (esp_netif->flags & ESP_NETIF_DHCP_SERVER) {
if (esp_netif->dhcps_status != ESP_NETIF_DHCP_STOPPED) {
return ESP_ERR_ESP_NETIF_DHCP_NOT_STOPPED;
}
} else if (esp_netif->flags & ESP_NETIF_DHCP_CLIENT) {
if (esp_netif->dhcpc_status != ESP_NETIF_DHCP_STOPPED) {
return ESP_ERR_ESP_NETIF_DHCP_NOT_STOPPED;
}
#if LWIP_DNS /* don't build if not configured for use in lwipopts.h */
dns_clear_servers(true);
#endif
}
ip4_addr_copy(esp_netif->ip_info->ip, ip_info->ip);
ip4_addr_copy(esp_netif->ip_info->gw, ip_info->gw);
ip4_addr_copy(esp_netif->ip_info->netmask, ip_info->netmask);
struct netif *p_netif = esp_netif->lwip_netif;
if (p_netif != NULL && netif_is_up(p_netif)) {
netif_set_addr(p_netif, (ip4_addr_t*)&ip_info->ip, (ip4_addr_t*)&ip_info->netmask, (ip4_addr_t*)&ip_info->gw);
if (ESP_NETIF_FLAG_EVENT_IP_MODIFIED & esp_netif->flags) {
if (!ip4_addr_isany_val(ip_info->ip)) {
ip_event_t evt_id = esp_netif->get_ip_event;
ip_event_got_ip_t evt = { .esp_netif = esp_netif, .ip_changed = false};
int ret;
if (memcmp(ip_info, esp_netif->ip_info_old, sizeof(esp_netif_ip_info_t))) {
evt.ip_changed = true;
}
esp_netif_update_default_netif(esp_netif, ESP_NETIF_GOT_IP);
memcpy(&evt.ip_info, ip_info, sizeof(esp_netif_ip_info_t));
memcpy(esp_netif->ip_info_old, ip_info, sizeof(esp_netif_ip_info_t));
ret = esp_event_post(IP_EVENT, evt_id, &evt, sizeof(evt), 0);
if (ESP_OK != ret) {
ESP_LOGE(TAG, "set ip info: failed to post got ip event (%x)", ret);
}
ESP_LOGD(TAG, "if%p netif set static ip: ip changed=%d", esp_netif, evt.ip_changed);
}
}
}
return ESP_OK;
}
esp_err_t esp_netif_set_ip_info(esp_netif_t *esp_netif, const esp_netif_ip_info_t *ip_info) _RUN_IN_LWIP_TASK_IF_SUPPORTED(esp_netif_set_ip_info_api, esp_netif, ip_info)
#endif /* CONFIG_LWIP_IPV4 */
struct array_mac_ip_t {
int num;
esp_netif_pair_mac_ip_t *mac_ip_pair;
};
#if CONFIG_LWIP_DHCPS
static esp_err_t esp_netif_dhcps_get_clients_by_mac_api(esp_netif_api_msg_t *msg)
{
esp_netif_t *netif = msg->esp_netif;
struct array_mac_ip_t *mac_ip_list = msg->data;
for (int i = 0; i < mac_ip_list->num; i++) {
dhcp_search_ip_on_mac(netif->dhcps, mac_ip_list->mac_ip_pair[i].mac, (ip4_addr_t*)&mac_ip_list->mac_ip_pair[i].ip);
}
return ESP_OK;
}
#endif // CONFIG_LWIP_DHCPS
esp_err_t esp_netif_dhcps_get_clients_by_mac(esp_netif_t *esp_netif, int num, esp_netif_pair_mac_ip_t *mac_ip_pair)
{
#if CONFIG_LWIP_DHCPS
if (esp_netif == NULL || esp_netif->dhcps == NULL || num < 0 || mac_ip_pair == NULL) {
return ESP_ERR_ESP_NETIF_INVALID_PARAMS;
}
struct array_mac_ip_t array_mac_ip = { num, mac_ip_pair };
return esp_netif_lwip_ipc_call(esp_netif_dhcps_get_clients_by_mac_api, esp_netif, (void *)&array_mac_ip);
#else
return ESP_ERR_NOT_SUPPORTED;
#endif // CONFIG_LWIP_DHCPS
}
static esp_err_t esp_netif_set_dns_info_api(esp_netif_api_msg_t *msg)
{
esp_netif_t *esp_netif = msg->esp_netif;
esp_netif_dns_param_t *dns_param = msg->data;
esp_netif_dns_type_t type = dns_param->dns_type;
esp_netif_dns_info_t *dns = dns_param->dns_info;
ESP_LOGD(TAG, "esp_netif_set_dns_info: if=%p type=%d dns=%" PRIx32, esp_netif, type, dns->ip.u_addr.ip4.addr);
ip_addr_t lwip_ip = {};
ESPIP_TO_IP(&dns->ip, &lwip_ip);
if (esp_netif && esp_netif->flags & ESP_NETIF_DHCP_SERVER) {
#if ESP_DHCPS
// if DHCP server configured to set DNS in dhcps API
if (type != ESP_NETIF_DNS_MAIN) {
ESP_LOGD(TAG, "set dns invalid type");
return ESP_ERR_ESP_NETIF_INVALID_PARAMS;
} else {
dhcps_dns_setserver(esp_netif->dhcps, &lwip_ip);
}
#else
LOG_NETIF_DISABLED_AND_DO("DHCP Server", return ESP_ERR_NOT_SUPPORTED);
#endif
} else {
#ifdef CONFIG_ESP_NETIF_SET_DNS_PER_DEFAULT_NETIF
if (esp_netif) {
store_dnsserver_info(esp_netif->lwip_netif, type, &lwip_ip);
}
if (esp_netif == s_last_default_esp_netif || // if this is the default one -> need to update global DNS servers
esp_netif == NULL) { // if the netif ptr is set to NULL -> we explicitly require the update
dns_setserver(type, &lwip_ip);
}
#else
dns_setserver(type, &lwip_ip);
#endif
}
return ESP_OK;
}
esp_err_t esp_netif_set_dns_info(esp_netif_t *esp_netif, esp_netif_dns_type_t type, esp_netif_dns_info_t *dns)
{
#ifndef CONFIG_ESP_NETIF_SET_DNS_PER_DEFAULT_NETIF
if (esp_netif == NULL) {
return ESP_ERR_ESP_NETIF_INVALID_PARAMS;
}
#endif
if (dns == NULL) {
ESP_LOGD(TAG, "set dns null dns");
return ESP_ERR_ESP_NETIF_INVALID_PARAMS;
}
if (ESP_IP_IS_ANY(dns->ip)) {
ESP_LOGD(TAG, "set dns invalid dns");
return ESP_ERR_ESP_NETIF_INVALID_PARAMS;
}
esp_netif_dns_param_t dns_param = {
.dns_type = type,
.dns_info = dns
};
return esp_netif_lwip_ipc_call(esp_netif_set_dns_info_api, esp_netif, (void *)&dns_param);
}
static esp_err_t esp_netif_get_dns_info_api(esp_netif_api_msg_t *msg)
{
esp_netif_t *esp_netif = msg->esp_netif;
esp_netif_dns_param_t *dns_param = msg->data;
esp_netif_dns_type_t type = dns_param->dns_type;
esp_netif_dns_info_t *dns = dns_param->dns_info;
ESP_LOGD(TAG, "esp_netif_get_dns_info: esp_netif=%p type=%d", esp_netif, type);
if (esp_netif && esp_netif->flags & ESP_NETIF_DHCP_SERVER) {
#if ESP_DHCPS
ip4_addr_t dns_ip;
dhcps_dns_getserver(esp_netif->dhcps, &dns_ip);
memcpy(&dns->ip.u_addr.ip4, &dns_ip, sizeof(ip4_addr_t));
dns->ip.type = ESP_IPADDR_TYPE_V4;
#else
LOG_NETIF_DISABLED_AND_DO("DHCP Server", return ESP_ERR_NOT_SUPPORTED);
#endif
} else {
const ip_addr_t* dns_ip = NULL;
#ifdef CONFIG_ESP_NETIF_SET_DNS_PER_DEFAULT_NETIF
if (esp_netif == NULL) { // by setting esp_netif to NULL we require the global DNS server entry
dns_ip = dns_getserver(type);
} else {
dns_ip = &esp_netif->dns[type];
}
#else
dns_ip = dns_getserver(type);
#endif
if(dns_ip != NULL) {
IP_TO_ESPIP(dns_ip, &dns->ip);
}
}
return ESP_OK;
}
esp_err_t esp_netif_get_dns_info(esp_netif_t *esp_netif, esp_netif_dns_type_t type, esp_netif_dns_info_t *dns)
{
#ifndef CONFIG_ESP_NETIF_SET_DNS_PER_DEFAULT_NETIF
if (esp_netif == NULL) {
return ESP_ERR_ESP_NETIF_INVALID_PARAMS;
}
#endif
if (dns == NULL) {
ESP_LOGE(TAG, "%s: dns_info cannot be NULL", __func__);
return ESP_ERR_ESP_NETIF_INVALID_PARAMS;
}
esp_netif_dns_param_t dns_param = {
.dns_type = type,
.dns_info = dns
};
return esp_netif_lwip_ipc_call(esp_netif_get_dns_info_api, esp_netif, (void *)&dns_param);
}
#if CONFIG_LWIP_IPV6
#ifdef CONFIG_LWIP_MLDV6_TMR_INTERVAL
static void netif_send_mldv6(void *arg)
{
esp_netif_t *esp_netif = arg;
esp_netif->mldv6_report_timer_started = false;
if (!netif_is_up(esp_netif->lwip_netif)) {
return;
}
mld6_report_groups(esp_netif->lwip_netif);
esp_netif->mldv6_report_timer_started = true;
sys_timeout(CONFIG_LWIP_MLDV6_TMR_INTERVAL*1000, netif_send_mldv6, esp_netif);
}
static void netif_set_mldv6_flag(esp_netif_t *esp_netif)
{
if (!netif_is_up(esp_netif->lwip_netif) || esp_netif->mldv6_report_timer_started) {
return;
}
esp_netif->mldv6_report_timer_started = true;
sys_timeout(CONFIG_LWIP_MLDV6_TMR_INTERVAL*1000, netif_send_mldv6, esp_netif);
}
static void netif_unset_mldv6_flag(esp_netif_t *esp_netif)
{
if (esp_netif->mldv6_report_timer_started) {
esp_netif->mldv6_report_timer_started = false;
sys_untimeout(netif_send_mldv6, esp_netif);
}
}
#endif
esp_ip6_addr_type_t esp_netif_ip6_get_addr_type(esp_ip6_addr_t* ip6_addr)
{
ip6_addr_t* lwip_ip6_info = (ip6_addr_t*)ip6_addr;
if (ip6_addr_isglobal(lwip_ip6_info)) {
return ESP_IP6_ADDR_IS_GLOBAL;
} else if (ip6_addr_islinklocal(lwip_ip6_info)) {
return ESP_IP6_ADDR_IS_LINK_LOCAL;
} else if (ip6_addr_issitelocal(lwip_ip6_info)) {
return ESP_IP6_ADDR_IS_SITE_LOCAL;
} else if (ip6_addr_isuniquelocal(lwip_ip6_info)) {
return ESP_IP6_ADDR_IS_UNIQUE_LOCAL;
} else if (ip6_addr_isipv4mappedipv6(lwip_ip6_info)) {
return ESP_IP6_ADDR_IS_IPV4_MAPPED_IPV6;
}
return ESP_IP6_ADDR_IS_UNKNOWN;
}
static void esp_netif_internal_nd6_cb(struct netif *netif, uint8_t ip_index)
{
esp_netif_t *esp_netif;
ESP_LOGD(TAG, "%s lwip-netif:%p", __func__, netif);
if (netif == NULL || (esp_netif = lwip_get_esp_netif(netif)) == NULL) {
// internal pointer hasn't been configured yet (probably in the interface init_fn())
return;
}
esp_netif_ip6_info_t ip6_info;
ip6_addr_t lwip_ip6_info;
ip_event_got_ip6_t evt = { .esp_netif = esp_netif, .ip_index = ip_index };
ip6_addr_set(&lwip_ip6_info, ip_2_ip6(&netif->ip6_addr[ip_index]));
#if LWIP_IPV6_SCOPES
memcpy(&ip6_info.ip, &lwip_ip6_info, sizeof(esp_ip6_addr_t));
#else
memcpy(&ip6_info.ip, &lwip_ip6_info, sizeof(ip6_addr_t));
ip6_info.ip.zone = 0; // zero out zone, as not used in lwip
#endif /* LWIP_IPV6_SCOPES */
if (esp_netif->flags&ESP_NETIF_FLAG_MLDV6_REPORT) {
#if ESP_MLDV6_REPORT
netif_set_mldv6_flag(esp_netif);
#else
ESP_LOGW(TAG,"CONFIG_LWIP_ESP_MLDV6_REPORT not enabled, but esp-netif configured with ESP_NETIF_FLAG_MLDV6_REPORT");
#endif
}
esp_netif_update_default_netif(esp_netif, ESP_NETIF_GOT_IP);
memcpy(&evt.ip6_info, &ip6_info, sizeof(esp_netif_ip6_info_t));
int ret = esp_event_post(IP_EVENT, IP_EVENT_GOT_IP6, &evt, sizeof(evt), 0);
if (ESP_OK != ret) {
ESP_LOGE(TAG, "nd6 cb: failed to post IP_EVENT_GOT_IP6 (%x)", ret);
}
}
static esp_err_t esp_netif_create_ip6_linklocal_api(esp_netif_api_msg_t *msg)
{
esp_netif_t *esp_netif = msg->esp_netif;
ESP_LOGV(TAG, "%s esp-netif:%p", __func__, esp_netif);
struct netif *p_netif = esp_netif->lwip_netif;
if (p_netif != NULL && netif_is_up(p_netif)) {
netif_create_ip6_linklocal_address(p_netif, 1);
return ESP_OK;
} else {
return ESP_FAIL;
}
}
esp_err_t esp_netif_create_ip6_linklocal(esp_netif_t *esp_netif) _RUN_IN_LWIP_TASK_IF_SUPPORTED(esp_netif_create_ip6_linklocal_api, esp_netif, NULL)
esp_err_t esp_netif_get_ip6_linklocal(esp_netif_t *esp_netif, esp_ip6_addr_t *if_ip6)
{
ESP_LOGV(TAG, "%s esp-netif:%p", __func__, esp_netif);
if (esp_netif == NULL || if_ip6 == NULL || _IS_NETIF_ANY_POINT2POINT_TYPE(esp_netif)) {
return ESP_ERR_ESP_NETIF_INVALID_PARAMS;
}
struct netif *p_netif = esp_netif->lwip_netif;
if (p_netif != NULL && netif_is_up(p_netif) && ip6_addr_ispreferred(netif_ip6_addr_state(p_netif, 0))) {
memcpy(if_ip6, &p_netif->ip6_addr[0], sizeof(ip6_addr_t));
} else {
return ESP_FAIL;
}
return ESP_OK;
}
esp_err_t esp_netif_get_ip6_global(esp_netif_t *esp_netif, esp_ip6_addr_t *if_ip6)
{
ESP_LOGV(TAG, "%s esp-netif:%p", __func__, esp_netif);
if (esp_netif == NULL || if_ip6 == NULL) {
return ESP_ERR_ESP_NETIF_INVALID_PARAMS;
}
int i;
struct netif *p_netif = esp_netif->lwip_netif;
if (p_netif != NULL && netif_is_up(p_netif)) {
for (i = 1; i < LWIP_IPV6_NUM_ADDRESSES; i++) {
if (ip6_addr_ispreferred(netif_ip6_addr_state(p_netif, i)) &&
ip6_addr_isglobal(netif_ip6_addr(p_netif, i))) {
memcpy(if_ip6, &p_netif->ip6_addr[i], sizeof(ip6_addr_t));
return ESP_OK;
}
}
}
return ESP_FAIL;
}
int esp_netif_get_all_ip6(esp_netif_t *esp_netif, esp_ip6_addr_t if_ip6[])
{
ESP_LOGV(TAG, "%s esp-netif:%p", __func__, esp_netif);
if (esp_netif == NULL || if_ip6 == NULL) {
return 0;
}
int addr_count = 0;
struct netif *p_netif = esp_netif->lwip_netif;
if (p_netif != NULL && netif_is_up(p_netif)) {
for (int i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) {
if (!ip_addr_cmp(&p_netif->ip6_addr[i], IP6_ADDR_ANY)) {
memcpy(&if_ip6[addr_count++], &p_netif->ip6_addr[i], sizeof(ip6_addr_t));
}
}
}
return addr_count;
}
#endif
esp_netif_flags_t esp_netif_get_flags(esp_netif_t *esp_netif)
{
return esp_netif->flags;
}
const char *esp_netif_get_ifkey(esp_netif_t *esp_netif)
{
return esp_netif->if_key;
}
const char *esp_netif_get_desc(esp_netif_t *esp_netif)
{
return esp_netif->if_desc;
}
int esp_netif_get_route_prio(esp_netif_t *esp_netif)
{
if (esp_netif == NULL) {
return -1;
}
return esp_netif->route_prio;
}
int32_t esp_netif_get_event_id(esp_netif_t *esp_netif, esp_netif_ip_event_type_t event_type)
{
switch(event_type) {
case ESP_NETIF_IP_EVENT_GOT_IP:
return esp_netif->get_ip_event;
case ESP_NETIF_IP_EVENT_LOST_IP:
return esp_netif->lost_ip_event;
default:
return -1;
}
}
struct dhcp_params {
esp_netif_dhcp_option_mode_t op;
esp_netif_dhcp_option_id_t id;
void *val;
uint32_t len;
};
#if ESP_DHCPS
esp_err_t esp_netif_dhcps_option_api(esp_netif_api_msg_t *msg)
{
esp_netif_t *esp_netif = msg->esp_netif;
struct dhcp_params *opt = msg->data;
void *opt_info = dhcps_option_info(esp_netif->dhcps, opt->id, opt->len);
esp_netif_dhcp_status_t dhcps_status = esp_netif->dhcps_status;
if (opt_info == NULL || opt->val == NULL) {
return ESP_ERR_ESP_NETIF_INVALID_PARAMS;
}
if (opt->op == ESP_NETIF_OP_GET) {
if (dhcps_status == ESP_NETIF_DHCP_STOPPED) {
return ESP_ERR_ESP_NETIF_DHCP_ALREADY_STOPPED;
}
switch (opt->id) {
case IP_ADDRESS_LEASE_TIME: {
*(uint32_t *)opt->val = *(uint32_t *)opt_info;
break;
}
case ESP_NETIF_SUBNET_MASK:
case REQUESTED_IP_ADDRESS: {
memcpy(opt->val, opt_info, opt->len);
break;
}
case ROUTER_SOLICITATION_ADDRESS: {
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;
}
} else if (opt->op == ESP_NETIF_OP_SET) {
if (dhcps_status == ESP_NETIF_DHCP_STARTED) {
return ESP_ERR_ESP_NETIF_DHCP_ALREADY_STARTED;
}
switch (opt->id) {
case IP_ADDRESS_LEASE_TIME: {
if (*(uint32_t *)opt->val != 0) {
*(uint32_t *)opt_info = *(uint32_t *)opt->val;
} else {
*(uint32_t *)opt_info = DHCPS_LEASE_TIME_DEF;
}
break;
}
case ESP_NETIF_SUBNET_MASK: {
esp_netif_ip_info_t *default_ip = esp_netif->ip_info;
ip4_addr_t *config_netmask = (ip4_addr_t *)opt->val;
if (!memcmp(&default_ip->netmask, config_netmask, sizeof(struct ip4_addr))) {
ESP_LOGE(TAG, "Please use esp_netif_set_ip_info interface to configure subnet mask");
/*
* This API directly changes the subnet mask of dhcp server
* but the subnet mask of the network interface has not changed
* If you need to change the subnet mask of dhcp server
* you need to change the subnet mask of the network interface first.
* If the subnet mask of dhcp server is changed
* and the subnet mask of network interface is inconsistent
* with the subnet mask of dhcp sever, it may lead to the failure of sending packets.
* If want to configure the subnet mask of dhcp server
* please use esp_netif_set_ip_info to change the subnet mask of network interface first.
*/
return ESP_ERR_ESP_NETIF_INVALID_PARAMS;
}
memcpy(opt_info, opt->val, opt->len);
break;
}
case REQUESTED_IP_ADDRESS: {
esp_netif_ip_info_t info;
uint32_t server_ip = 0;
uint32_t start_ip = 0;
uint32_t end_ip = 0;
uint32_t range_start_ip = 0;
uint32_t range_end_ip = 0;
dhcps_lease_t *poll = opt->val;
if (poll->enable) {
memset(&info, 0x00, sizeof(esp_netif_ip_info_t));
esp_netif_get_ip_info(esp_netif, &info);
server_ip = htonl(info.ip.addr);
range_start_ip = server_ip & htonl(info.netmask.addr);
range_end_ip = range_start_ip | ~htonl(info.netmask.addr);
if (server_ip == range_start_ip || server_ip == range_end_ip) {
return ESP_ERR_ESP_NETIF_INVALID_PARAMS;
}
start_ip = htonl(poll->start_ip.addr);
end_ip = htonl(poll->end_ip.addr);
/*config ip information can't contain local ip*/
if ((server_ip >= start_ip) && (server_ip <= end_ip)) {
return ESP_ERR_ESP_NETIF_INVALID_PARAMS;
}
/*config ip information must be in the same segment as the local ip*/
if (start_ip <= range_start_ip || start_ip >= range_end_ip) {
return ESP_ERR_ESP_NETIF_INVALID_PARAMS;
}
if (end_ip <= range_start_ip || end_ip >= range_end_ip) {
return ESP_ERR_ESP_NETIF_INVALID_PARAMS;
}
/*The number of configured ip is less than DHCPS_MAX_LEASE*/
if ((end_ip - start_ip + 1 > DHCPS_MAX_LEASE) || (start_ip >= end_ip)) {
return ESP_ERR_ESP_NETIF_INVALID_PARAMS;
}
}
memcpy(opt_info, opt->val, opt->len);
break;
}
case ROUTER_SOLICITATION_ADDRESS: {
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;
}
case ESP_NETIF_CAPTIVEPORTAL_URI: {
opt_info = (char *)opt->val;
break;
}
default:
break;
}
dhcps_set_option_info(esp_netif->dhcps, opt->id, opt_info, opt->len);
} else {
return ESP_ERR_ESP_NETIF_INVALID_PARAMS;
}
return ESP_OK;
}
esp_err_t esp_netif_dhcps_option(esp_netif_t *esp_netif, esp_netif_dhcp_option_mode_t opt_op, esp_netif_dhcp_option_id_t opt_id, void *opt_val,
uint32_t opt_len)
{
if (esp_netif == NULL || esp_netif->dhcps == NULL) {
return ESP_ERR_ESP_NETIF_IF_NOT_READY;
}
struct dhcp_params opts = { .op = opt_op, .id = opt_id, .len = opt_len, .val = opt_val };
return esp_netif_lwip_ipc_call(esp_netif_dhcps_option_api, esp_netif, &opts);
}
#endif // ESP_DHCPS
#if CONFIG_LWIP_IPV4
esp_err_t esp_netif_dhcpc_option_api(esp_netif_api_msg_t *msg)
{
esp_netif_t *esp_netif = msg->esp_netif;
struct dhcp_params *opt = msg->data;
struct dhcp *dhcp = netif_dhcp_data(esp_netif->lwip_netif);
if (dhcp == NULL || opt->val == NULL) {
return ESP_ERR_ESP_NETIF_INVALID_PARAMS;
}
if (opt->op == ESP_NETIF_OP_GET) {
if (esp_netif->dhcpc_status == ESP_NETIF_DHCP_STOPPED) {
return ESP_ERR_ESP_NETIF_DHCP_ALREADY_STOPPED;
}
switch (opt->id) {
case ESP_NETIF_IP_REQUEST_RETRY_TIME:
if (opt->len == sizeof(dhcp->tries)) {
*(uint8_t *)opt->val = dhcp->tries;
}
break;
#if ESP_DHCP && !ESP_DHCP_DISABLE_VENDOR_CLASS_IDENTIFIER
case ESP_NETIF_VENDOR_SPECIFIC_INFO:
return dhcp_get_vendor_specific_information(opt->len, opt->val);
#endif
default:
return ESP_ERR_ESP_NETIF_INVALID_PARAMS;
}
} else if (opt->op == ESP_NETIF_OP_SET) {
if (esp_netif->dhcpc_status == ESP_NETIF_DHCP_STARTED) {
return ESP_ERR_ESP_NETIF_DHCP_ALREADY_STARTED;
}
switch (opt->id) {
case ESP_NETIF_IP_REQUEST_RETRY_TIME:
if (opt->len == sizeof(dhcp->tries)) {
dhcp->tries = *(uint8_t *)opt->val;
}
break;
#if ESP_DHCP && !ESP_DHCP_DISABLE_VENDOR_CLASS_IDENTIFIER
case ESP_NETIF_VENDOR_CLASS_IDENTIFIER:
return dhcp_set_vendor_class_identifier(opt->len, opt->val);
#endif
default:
return ESP_ERR_ESP_NETIF_INVALID_PARAMS;
}
} else {
return ESP_ERR_ESP_NETIF_INVALID_PARAMS;
}
return ESP_OK;
}
esp_err_t esp_netif_dhcpc_option(esp_netif_t *esp_netif, esp_netif_dhcp_option_mode_t opt_op, esp_netif_dhcp_option_id_t opt_id, void *opt_val,
uint32_t opt_len)
{
if (esp_netif == NULL || esp_netif->lwip_netif == NULL) {
return ESP_ERR_ESP_NETIF_IF_NOT_READY;
}
struct dhcp_params opts = { .op = opt_op, .id = opt_id, .len = opt_len, .val = opt_val };
return esp_netif_lwip_ipc_call(esp_netif_dhcpc_option_api, esp_netif, &opts);
}
#endif /* CONFIG_LWIP_IPV4 */
int esp_netif_get_netif_impl_index(esp_netif_t *esp_netif)
{
if (esp_netif == NULL || esp_netif->lwip_netif == NULL) {
return -1;
}
return netif_get_index(esp_netif->lwip_netif);
}
esp_err_t esp_netif_get_netif_impl_name_api(esp_netif_api_msg_t *msg)
{
struct netif* netif = msg->esp_netif->lwip_netif;
netif_index_to_name(netif_get_index(netif), msg->data);
return ESP_OK;
}
esp_err_t esp_netif_get_netif_impl_name(esp_netif_t *esp_netif, char* name)
{
ESP_LOGD(TAG, "%s esp_netif:%p", __func__, esp_netif);
if (esp_netif == NULL || esp_netif->lwip_netif == NULL) {
return ESP_ERR_ESP_NETIF_INVALID_PARAMS;
}
return esp_netif_lwip_ipc_call(esp_netif_get_netif_impl_name_api, esp_netif, name);
}
#if IP_NAPT
static esp_err_t esp_netif_napt_control_api(esp_netif_api_msg_t *msg)
{
bool enable = (bool)msg->data;
esp_netif_t *esp_netif = msg->esp_netif;
ESP_LOGD(TAG, "%s esp_netif:%p", __func__, esp_netif);
/* Check if the interface is up */
if (!netif_is_up(esp_netif->lwip_netif)) {
return ESP_FAIL;
}
if (enable) {
/* Disable napt on all other interface */
esp_netif_t *netif = esp_netif_next_unsafe(NULL);
while (netif) {
if (netif != esp_netif && netif->lwip_netif->napt == 1) {
ip_napt_enable_netif(netif->lwip_netif, 0); // Fails only if netif is down
ESP_LOGW(TAG, "napt disabled on esp_netif:%p", esp_netif);
}
netif = esp_netif_next_unsafe(netif);
}
int ret = ip_napt_enable_netif(esp_netif->lwip_netif, 1);
if (ret == 0) {
return ESP_FAIL;
}
return ESP_OK;
} else {
ip_napt_enable_netif(esp_netif->lwip_netif, 0); // Fails only if netif is down
ESP_LOGD(TAG, "napt disabled on esp_netif:%p", esp_netif);
return ESP_OK;
}
}
#endif // !IP_NAPT
esp_err_t esp_netif_napt_enable(esp_netif_t *esp_netif)
{
#if !IP_NAPT
return ESP_ERR_NOT_SUPPORTED;
#else
return esp_netif_lwip_ipc_call(esp_netif_napt_control_api, esp_netif, (void*)true /* Enable */);
#endif /* IP_NAPT */
}
typedef struct {
u8_t authtype;
const char *user;
const char *passwd;
} set_auth_msg_t;
static esp_err_t esp_netif_ppp_set_auth_api(esp_netif_api_msg_t *msg)
{
set_auth_msg_t *params = msg->data;
return esp_netif_ppp_set_auth_internal(msg->esp_netif, params->authtype, params->user, params->passwd);
}
esp_err_t esp_netif_ppp_set_auth(esp_netif_t *esp_netif, esp_netif_auth_type_t authtype, const char *user, const char *passwd)
{
set_auth_msg_t msg = { .authtype = authtype, .user = user, .passwd = passwd };
return esp_netif_lwip_ipc_call(esp_netif_ppp_set_auth_api, esp_netif, &msg);
#if PPP_AUTH_SUPPORT
lwip_peer2peer_ctx_t *ppp_ctx = (lwip_peer2peer_ctx_t *)netif->related_data;
assert(ppp_ctx->base.netif_type == PPP_LWIP_NETIF);
pppapi_set_auth(ppp_ctx->ppp, authtype, user, passwd);
return ESP_OK;
#else
ESP_LOGE(TAG, "%s failed: No authorisation enabled in menuconfig", __func__);
return ESP_ERR_ESP_NETIF_IF_NOT_READY;
#endif
}
esp_err_t esp_netif_napt_disable(esp_netif_t *esp_netif)
{
#if !IP_NAPT
return ESP_ERR_NOT_SUPPORTED;
#else
return esp_netif_lwip_ipc_call(esp_netif_napt_control_api, esp_netif, (void*)false /* Disable */);
#endif /* IP_NAPT */
}
#if MIB2_STATS
static esp_err_t esp_netif_set_link_speed_api(esp_netif_api_msg_t *msg)
{
uint32_t speed = *((uint32_t*)msg->data);
esp_err_t error = ESP_OK;
ESP_LOGD(TAG, "%s esp_netif:%p", __func__, msg->esp_netif);
NETIF_INIT_SNMP(msg->esp_netif->lwip_netif, snmp_ifType_ethernet_csmacd, speed);
LWIP_UNUSED_ARG(speed); // Maybe unused if SNMP disabled
return error;
}
esp_err_t esp_netif_set_link_speed(esp_netif_t *esp_netif, uint32_t speed)
_RUN_IN_LWIP_TASK(esp_netif_set_link_speed_api, esp_netif, &speed)
#else
esp_err_t esp_netif_set_link_speed(esp_netif_t *esp_netif, uint32_t speed)
{
// link speed is used only to collect interface related statistics (if MIB2_STATS enabled)
return ESP_OK;
}
#endif /* MIB2_STATS */
#if CONFIG_LWIP_IPV6
static esp_err_t esp_netif_join_ip6_multicast_group_api(esp_netif_api_msg_t *msg)
{
esp_ip6_addr_t *addr = (esp_ip6_addr_t *)msg->data;
esp_err_t error = ESP_OK;
ip6_addr_t ip6addr;
ESP_LOGD(TAG, "%s esp_netif:%p", __func__, msg->esp_netif);
memcpy(ip6addr.addr, addr->addr, sizeof(ip6addr.addr));
#if LWIP_IPV6_SCOPES
ip6addr.zone = 0;
#endif
if (mld6_joingroup_netif(msg->esp_netif->lwip_netif, &ip6addr) != ERR_OK) {
error = ESP_ERR_ESP_NETIF_MLD6_FAILED;
ESP_LOGE(TAG, "failed to join ip6 multicast group");
}
return error;
}
esp_err_t esp_netif_join_ip6_multicast_group(esp_netif_t *esp_netif, const esp_ip6_addr_t *addr)
_RUN_IN_LWIP_TASK(esp_netif_join_ip6_multicast_group_api, esp_netif, addr)
static esp_err_t esp_netif_leave_ip6_multicast_group_api(esp_netif_api_msg_t *msg)
{
esp_ip6_addr_t *addr = (esp_ip6_addr_t *)msg->data;
ip6_addr_t ip6addr;
ESP_LOGD(TAG, "%s esp_netif:%p", __func__, msg->esp_netif);
memcpy(ip6addr.addr, addr->addr, sizeof(ip6addr.addr));
#if LWIP_IPV6_SCOPES
ip6addr.zone = 0;
#endif
ESP_RETURN_ON_FALSE(mld6_leavegroup_netif(msg->esp_netif->lwip_netif, &ip6addr) == ERR_OK,
ESP_ERR_ESP_NETIF_MLD6_FAILED, TAG, "Failed to leave ip6 multicast group");
return ESP_OK;
}
esp_err_t esp_netif_leave_ip6_multicast_group(esp_netif_t *esp_netif, const esp_ip6_addr_t *addr)
_RUN_IN_LWIP_TASK(esp_netif_leave_ip6_multicast_group_api, esp_netif, addr)
static esp_err_t esp_netif_add_ip6_address_api(esp_netif_api_msg_t *msg)
{
ip_event_add_ip6_t *addr = (ip_event_add_ip6_t *)msg->data;
ip6_addr_t ip6addr;
esp_err_t error = ESP_OK;
int8_t index = -1;
ESP_LOGD(TAG, "%s esp_netif:%p", __func__, msg->esp_netif);
memcpy(ip6addr.addr, addr->addr.addr, sizeof(ip6addr.addr));
#if LWIP_IPV6_SCOPES
ip6addr.zone = 0;
#endif
err_t err = netif_add_ip6_address(msg->esp_netif->lwip_netif, &ip6addr, &index);
ESP_RETURN_ON_FALSE(err == ERR_OK && index >= 0, ESP_ERR_ESP_NETIF_IP6_ADDR_FAILED, TAG,
"Failed to add ip6 address");
esp_netif_update_default_netif(msg->esp_netif, ESP_NETIF_GOT_IP);
netif_ip6_addr_set_state(msg->esp_netif->lwip_netif, index,
addr->preferred ? IP6_ADDR_PREFERRED : IP6_ADDR_DEPRECATED);
ip_event_got_ip6_t evt = {.esp_netif = msg->esp_netif, .ip_index = index};
evt.ip6_info.ip = addr->addr;
ESP_RETURN_ON_ERROR(esp_event_post(IP_EVENT, IP_EVENT_GOT_IP6, &evt, sizeof(evt), 0), TAG,
"Failed to post IP_EVENT_GOT_IP6");
return error;
}
static esp_err_t esp_netif_add_ip6_address_priv(esp_netif_t *esp_netif, const ip_event_add_ip6_t *addr)
_RUN_IN_LWIP_TASK(esp_netif_add_ip6_address_api, esp_netif, addr)
esp_err_t esp_netif_add_ip6_address(esp_netif_t *esp_netif, const esp_ip6_addr_t addr, bool preferred)
{
const ip_event_add_ip6_t addr_evt = {.addr = addr, .preferred = preferred};
return esp_netif_add_ip6_address_priv(esp_netif, &addr_evt);
}
static esp_err_t esp_netif_remove_ip6_address_api(esp_netif_api_msg_t *msg)
{
esp_ip6_addr_t *addr = (esp_ip6_addr_t *)msg->data;
ip6_addr_t ip6addr;
ESP_LOGD(TAG, "%s esp_netif:%p", __func__, msg->esp_netif);
memcpy(ip6addr.addr, addr->addr, sizeof(ip6addr.addr));
#if LWIP_IPV6_SCOPES
ip6addr.zone = 0;
#endif
int8_t index = netif_get_ip6_addr_match(msg->esp_netif->lwip_netif, &ip6addr);
if (index != -1) {
netif_ip6_addr_set_state(msg->esp_netif->lwip_netif, index, IP6_ADDR_INVALID);
}
return ESP_OK;
}
esp_err_t esp_netif_remove_ip6_address(esp_netif_t *esp_netif, const esp_ip6_addr_t *addr)
_RUN_IN_LWIP_TASK(esp_netif_remove_ip6_address_api, esp_netif, addr)
#endif // CONFIG_LWIP_IPV6