esp-idf/components/esp_netif/lwip/esp_netif_lwip.c
Sudeep Mohanty a9fda54d39 esp_hw_support/esp_system: Re-evaluate header inclusions and include directories
This commit updates the visibility of various header files and cleans up
some unnecessary inclusions. Also, this commit removes certain header
include paths which were maintained for backward compatibility.
2022-03-07 11:18:08 +05:30

2166 lines
71 KiB
C

/*
* SPDX-FileCopyrightText: 2019-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <string.h>
#include <lwip/ip_addr.h>
#include <lwip/sockets.h>
#include "esp_check.h"
#include "esp_netif_lwip_internal.h"
#include "esp_netif.h"
#include "esp_netif_private.h"
#include "esp_random.h"
#if CONFIG_ESP_NETIF_TCPIP_LWIP
#include "lwip/tcpip.h"
#include "lwip/dhcp.h"
#include "lwip/ip_addr.h"
#include "lwip/ip6_addr.h"
#include "lwip/mld6.h"
#include "lwip/nd6.h"
#include "lwip/priv/tcpip_priv.h"
#include "lwip/netif.h"
#if LWIP_DNS /* don't build if not configured for use in lwipopts.h */
#include "lwip/dns.h"
#endif
#if CONFIG_LWIP_HOOK_TCP_ISN_DEFAULT
#include "lwip_default_hooks.h"
#endif
#include "esp_netif_lwip_ppp.h"
#include "esp_netif_lwip_slip.h"
#include "dhcpserver/dhcpserver.h"
#include "dhcpserver/dhcpserver_options.h"
#include "esp_event.h"
#include "esp_log.h"
//
// This is the main module implementing lwip interaction with esp-netif
//
#define ESP_NETIF_HOSTNAME_MAX_SIZE 32
/**
* @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 || CONFIG_LWIP_SLIP_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 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)
#if CONFIG_ESP_NETIF_L2_TAP
/**
* @brief Transmit timeout when multiple accesses to network driver
*/
#define ESP_NETIF_TX_TIMEOUT 250
#endif
//
// Internal types
//
typedef enum esp_netif_action {
ESP_NETIF_UNDEF,
ESP_NETIF_STARTED,
ESP_NETIF_STOPPED,
} esp_netif_action_t;
//
// Internal variables for this module
//
extern sys_thread_t g_lwip_task;
static const char *TAG = "esp_netif_lwip";
static bool tcpip_initialized = false;
static esp_netif_t *s_last_default_esp_netif = NULL;
#if !LWIP_TCPIP_CORE_LOCKING
static sys_sem_t api_sync_sem = NULL;
static sys_sem_t api_lock_sem = NULL;
/**
* @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);
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(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
};
#if !LWIP_TCPIP_CORE_LOCKING
if (g_lwip_task != xTaskGetCurrentTaskHandle()) {
ESP_LOGD(TAG, "check: remote, if=%p fn=%p\n", netif, fn);
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);
return msg.ret;
}
#endif /* !LWIP_TCPIP_CORE_LOCKING */
ESP_LOGD(TAG, "check: local, if=%p fn=%p\n", netif, fn);
return fn(&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(esp_netif_t *esp_netif)
{
if (_IS_NETIF_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);
}
}
/**
* @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_action_t action = (esp_netif_action_t)msg->data;
ESP_LOGD(TAG, "%s %p", __func__, esp_netif);
switch (action) {
case ESP_NETIF_STARTED:
{
// 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(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(s_last_default_esp_netif);
}
}
break;
default:
case ESP_NETIF_STOPPED:
{
s_last_default_esp_netif = NULL;
esp_netif_list_lock();
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);
}
esp_netif_list_unlock();
if (s_last_default_esp_netif && esp_netif_is_netif_up(s_last_default_esp_netif)) {
esp_netif_set_default_netif(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)
*/
static esp_err_t esp_netif_update_default_netif(esp_netif_t *esp_netif, esp_netif_action_t action)
{
return esp_netif_lwip_ipc_call(esp_netif_update_default_netif_lwip, esp_netif, (void*)action);
}
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);
}
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_netif->state;
}
void* esp_netif_get_netif_impl(esp_netif_t *esp_netif)
{
// get impl ptr only for vanilla lwip impl (ppp_pcb not supported)
if (esp_netif && !_IS_NETIF_POINT2POINT_TYPE(esp_netif, PPP_LWIP_NETIF)) {
return esp_netif->lwip_netif;
}
return NULL;
}
esp_err_t esp_netif_init(void)
{
if (tcpip_initialized == false) {
tcpip_initialized = true;
#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
tcpip_init(NULL, NULL);
ESP_LOGD(TAG, "LwIP stack has been initialized");
}
#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 (tcpip_initialized == true) {
/* deinit of LwIP not supported:
* do not deinit semaphores and states,
* so init could be called multiple times
*
tcpip_initialized = false;
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 (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));
// 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;
}
// 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 (cfg->base->flags & ESP_NETIF_FLAG_IS_SLIP) {
#if CONFIG_LWIP_SLIP_SUPPORT
esp_netif->related_data = esp_netif_new_slip(esp_netif, esp_netif_stack_config);
if (esp_netif->related_data == NULL) {
return ESP_ERR_ESP_NETIF_INIT_FAILED;
}
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 esp_netif itself
esp_netif->netif_handle = esp_netif;
#else
LOG_NETIF_DISABLED_AND_DO("SLIP", 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;
}
esp_netif_t *esp_netif_new(const esp_netif_config_t *esp_netif_config)
{
// 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(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 NULL;
}
// 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 %d bytes (fee heap size %d)", sizeof(struct esp_netif_obj),
esp_get_free_heap_size());
return NULL;
}
#if CONFIG_ESP_NETIF_L2_TAP
esp_netif->transmit_mutex = xSemaphoreCreateMutex();
if (!esp_netif->transmit_mutex) {
ESP_LOGE(TAG, "Failed to create L2 TAP transmit mutex");
free(esp_netif);
return NULL;
}
#endif // CONFIG_ESP_NETIF_L2_TAP
// 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 %d bytes (fee heap size %d)", sizeof(esp_netif_ip_info_t),
esp_get_free_heap_size());
free(esp_netif);
return NULL;
}
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 %d bytes (fee heap size %d)", sizeof(esp_netif_ip_info_t),
esp_get_free_heap_size());
free(esp_netif->ip_info);
free(esp_netif);
return NULL;
}
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 %d bytes (fee heap size %d)", sizeof(struct netif),
esp_get_free_heap_size());
free(esp_netif->ip_info_old);
free(esp_netif->ip_info);
free(esp_netif);
return NULL;
}
lwip_netif->state = esp_netif;
esp_netif->lwip_netif = lwip_netif;
esp_netif_add_to_list(esp_netif);
// 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_destroy(esp_netif);
return NULL;
}
return esp_netif;
}
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);
}
}
static esp_err_t esp_netif_lwip_add(esp_netif_t *esp_netif)
{
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;
}
}
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 %d", err);
return ESP_ERR_ESP_NETIF_INIT_FAILED;
}
#else
LOG_NETIF_DISABLED_AND_DO("PPP", return ESP_ERR_NOT_SUPPORTED);
#endif
}
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,
esp_netif, esp_netif->lwip_init_fn, tcpip_input)) {
esp_netif_lwip_remove(esp_netif);
return ESP_ERR_ESP_NETIF_IF_NOT_READY;
}
return ESP_OK;
}
static void esp_netif_destroy_related(esp_netif_t *esp_netif)
{
if (_IS_NETIF_POINT2POINT_TYPE(esp_netif, PPP_LWIP_NETIF)) {
#if CONFIG_PPP_SUPPORT
esp_netif_destroy_ppp(esp_netif->related_data);
#endif
} else if (_IS_NETIF_POINT2POINT_TYPE(esp_netif, SLIP_LWIP_NETIF)) {
#if CONFIG_LWIP_SLIP_SUPPORT
esp_netif_destroy_slip(esp_netif->related_data);
#endif
}
}
void esp_netif_destroy(esp_netif_t *esp_netif)
{
if (esp_netif) {
esp_netif_remove_from_list(esp_netif);
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);
#if CONFIG_ESP_NETIF_L2_TAP
vSemaphoreDelete(esp_netif->transmit_mutex);
#endif // CONFIG_ESP_NETIF_L2_TAP
if (s_last_default_esp_netif == esp_netif) {
// clear last default netif if it happens to be this just destroyed interface
s_last_default_esp_netif = NULL;
}
free(esp_netif);
}
}
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;
}
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;
}
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;
}
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_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 CONFIG_ESP_NETIF_L2_TAP
esp_err_t esp_netif_transmit_hook_attach(esp_netif_t *esp_netif, void *hook_fn)
{
esp_err_t ret = ESP_FAIL;
if (esp_netif != NULL) {
if (esp_netif->transmit_hook == NULL) { // if hook function is not assigned
esp_netif->transmit_hook = hook_fn;
ret = ESP_OK;
} else if (esp_netif->transmit_hook == hook_fn) { // indicate OK when trying to assign the same hook function
ret = ESP_OK;
}
} else {
ret = ESP_ERR_INVALID_ARG;
}
return ret;
}
esp_err_t esp_netif_post_transmit_hook_attach(esp_netif_t *esp_netif, void *hook_fn)
{
esp_err_t ret = ESP_FAIL;
if (esp_netif != NULL) {
if (esp_netif->post_transmit_hook == NULL) { // if hook function is not assigned
esp_netif->post_transmit_hook = hook_fn;
ret = ESP_OK;
} else if (esp_netif->post_transmit_hook == hook_fn) { // indicate OK when trying to assign the same hook function
ret = ESP_OK;
}
} else {
ret = ESP_ERR_INVALID_ARG;
}
return ret;
}
esp_err_t esp_netif_recv_hook_attach(esp_netif_t *esp_netif, void *hook_fn)
{
esp_err_t ret = ESP_FAIL;
if (esp_netif != NULL) {
if (esp_netif->receive_hook == NULL) { // if hook function is not assigned
esp_netif->receive_hook = hook_fn;
ret = ESP_OK;
} else if (esp_netif->receive_hook == hook_fn) { // indicate OK when trying to assign the same hook function
ret = ESP_OK;
}
} else {
ret = ESP_ERR_INVALID_ARG;
}
return ret;
}
esp_err_t esp_netif_transmit_hook_detach(esp_netif_t *esp_netif)
{
if (esp_netif != NULL) {
esp_netif->transmit_hook = NULL;
return ESP_OK;
}
return ESP_ERR_INVALID_ARG;
}
esp_err_t esp_netif_post_transmit_hook_detach(esp_netif_t *esp_netif)
{
if (esp_netif != NULL) {
esp_netif->post_transmit_hook = NULL;
return ESP_OK;
}
return ESP_ERR_INVALID_ARG;
}
esp_err_t esp_netif_recv_hook_detach(esp_netif_t *esp_netif)
{
if (esp_netif != NULL) {
esp_netif->receive_hook = NULL;
return ESP_OK;
}
return ESP_ERR_INVALID_ARG;
}
#endif // CONFIG_ESP_NETIF_L2_TAP
#if ESP_DHCPS
static void esp_netif_dhcps_cb(uint8_t ip[4], uint8_t mac[6])
{
ip_event_ap_staipassigned_t evt = { 0 };
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 station, 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_send_internal(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->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);
ESP_ERROR_CHECK(esp_netif_config_sanity_check(esp_netif));
ESP_ERROR_CHECK(esp_netif_lwip_add(esp_netif));
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 (_IS_NETIF_POINT2POINT_TYPE(esp_netif, SLIP_LWIP_NETIF)) {
#if CONFIG_LWIP_SLIP_SUPPORT
esp_netif_start_slip(esp_netif);
#endif
}
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);
}
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_cb);
dhcps_set_option_info(SUBNET_MASK, (void*)&lwip_netmask, sizeof(lwip_netmask));
dhcps_start(p_netif, lwip_ip);
esp_netif->dhcps_status = ESP_NETIF_DHCP_STARTED;
ESP_LOGD(TAG, "DHCP server started successfully");
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 (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);
}
}
}
}
esp_netif_update_default_netif(esp_netif, ESP_NETIF_STARTED);
return ESP_OK;
}
esp_err_t esp_netif_start(esp_netif_t *esp_netif)
{
if (_IS_NETIF_POINT2POINT_TYPE(esp_netif, PPP_LWIP_NETIF)) {
#if CONFIG_PPP_SUPPORT
// No need to start PPP interface in lwip thread
esp_err_t ret = esp_netif_start_ppp(esp_netif);
if (ret == ESP_OK) {
esp_netif_update_default_netif(esp_netif, ESP_NETIF_STARTED);
}
return ret;
#endif
}
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;
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
dhcps_stop(lwip_netif); // TODO(IDF-1099): dhcps checks status by its self
if (ESP_NETIF_DHCP_STOPPED != esp_netif->dhcps_status) {
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) {
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);
}
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)
{
if (_IS_NETIF_POINT2POINT_TYPE(esp_netif, PPP_LWIP_NETIF)) {
#if CONFIG_PPP_SUPPORT
// No need to stop PPP interface in lwip thread
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
} else if (_IS_NETIF_POINT2POINT_TYPE(esp_netif, SLIP_LWIP_NETIF)) {
#if CONFIG_LWIP_SLIP_SUPPORT
// No need to stop SLIP interface in lwip thread
esp_err_t ret = esp_netif_stop_slip(esp_netif);
if (ret == ESP_OK) {
esp_netif_update_default_netif(esp_netif, ESP_NETIF_STOPPED);
}
return ret;
#endif
}
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);
}
esp_err_t esp_netif_transmit(esp_netif_t *esp_netif, void* data, size_t len)
{
esp_err_t ret;
#if CONFIG_ESP_NETIF_L2_TAP
if (xSemaphoreTake(esp_netif->transmit_mutex, pdMS_TO_TICKS(ESP_NETIF_TX_TIMEOUT)) == pdFALSE) {
return ESP_FAIL;
}
if (esp_netif->transmit_hook != NULL) {
void *p_data = data;
esp_netif->transmit_hook(esp_netif, &p_data, &len);
ret = (esp_netif->driver_transmit)(esp_netif->driver_handle, p_data, len);
if (esp_netif->post_transmit_hook != NULL) {
esp_netif->post_transmit_hook(esp_netif, p_data, len);
}
xSemaphoreGive(esp_netif->transmit_mutex);
return ret;
}
#endif // CONFIG_ESP_NETIF_L2_TAP
ret = (esp_netif->driver_transmit)(esp_netif->driver_handle, data, len);
#if CONFIG_ESP_NETIF_L2_TAP
xSemaphoreGive(esp_netif->transmit_mutex);
#endif // CONFIG_ESP_NETIF_L2_TAP
return ret;
}
esp_err_t esp_netif_transmit_wrap(esp_netif_t *esp_netif, void *data, size_t len, void *pbuf)
{
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)
{
#if CONFIG_ESP_NETIF_L2_TAP
if (esp_netif->receive_hook != NULL) {
esp_netif->receive_hook(esp_netif, buffer, &len);
// The receive_hook function may alter original frame (then keeps the len > 0) or it may take full control over the frame and sets len to 0 to
// not be populated further
if (len > 0) {
esp_netif->lwip_input_fn(esp_netif->netif_handle, buffer, len, eb);
}
} else {
#endif // CONFIG_ESP_NETIF_L2_TAP
esp_netif->lwip_input_fn(esp_netif->netif_handle, buffer, len, eb);
#if CONFIG_ESP_NETIF_L2_TAP
}
#endif // CONFIG_ESP_NETIF_L2_TAP
return ESP_OK;
}
//
// DHCP:
//
static esp_err_t esp_netif_start_ip_lost_timer(esp_netif_t *esp_netif);
static void esp_netif_dhcpc_cb(struct netif *netif)
{
if (!netif) {
ESP_LOGD(TAG, "null netif=%p", netif);
return;
}
ESP_LOGD(TAG, "%s lwip-netif:%p", __func__, netif);
esp_netif_t *esp_netif = esp_netif_get_handle_from_netif_impl(netif);
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
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)) ) {
ip_event_got_ip_t evt = {
.esp_netif = esp_netif,
.if_index = -1, // invalid index, handle used
.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;
}
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_send_internal(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);
}
} 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,
.if_index = -1,
};
int ret;
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_send_internal(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) && !ip4_addr_isany_val(ip_info_old->ip)) {
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=%x",
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 stoped");
return ESP_ERR_ESP_NETIF_DHCP_ALREADY_STOPPED;
}
ESP_LOGD(TAG, "dhcp client stop successfully");
esp_netif->dhcpc_status = ESP_NETIF_DHCP_STOPPED;
LWIP_DHCP_IP_ADDR_ERASE(esp_netif);
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 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;
}
dhcp_set_cb(p_netif, esp_netif_dhcpc_cb);
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)
#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_cb);
dhcps_set_option_info(SUBNET_MASK, (void*)&lwip_netmask, sizeof(lwip_netmask));
dhcps_start(p_netif, lwip_ip);
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 (p_netif != NULL) {
dhcps_stop(p_netif);
} else {
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 stoped");
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;
/* 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);
netif_set_up(lwip_netif);
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) {
dhcp_stop(esp_netif->lwip_netif);
esp_netif->dhcpc_status = ESP_NETIF_DHCP_INIT;
esp_netif_reset_ip_info(esp_netif);
}
#if CONFIG_LWIP_IPV6
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
netif_set_addr(lwip_netif, IP4_ADDR_ANY4, IP4_ADDR_ANY4, IP4_ADDR_ANY4);
netif_set_down(lwip_netif);
if (esp_netif->flags & ESP_NETIF_DHCP_CLIENT) {
esp_netif_start_ip_lost_timer(esp_netif);
}
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;
}
}
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) || ip4_addr_isany_val(ip_info->netmask) || ip4_addr_isany_val(ip_info->gw))) {
ip_event_t evt_id = esp_netif->get_ip_event;
ip_event_got_ip_t evt = { .esp_netif = esp_netif, .if_index = -1, .ip_changed = false};
int ret;
if (memcmp(ip_info, esp_netif->ip_info_old, sizeof(esp_netif_ip_info_t))) {
evt.ip_changed = true;
}
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_send_internal(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)
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, "%s esp_netif:%p", __func__, esp_netif);
if (esp_netif == NULL) {
return ESP_ERR_ESP_NETIF_INVALID_PARAMS;
}
if (!dns) {
ESP_LOGD(TAG, "set dns null dns");
return ESP_ERR_ESP_NETIF_INVALID_PARAMS;
}
if (ip4_addr_isany_val(dns->ip.u_addr.ip4)) {
ESP_LOGD(TAG, "set dns invalid dns");
return ESP_ERR_ESP_NETIF_INVALID_PARAMS;
}
ESP_LOGD(TAG, "set dns if=%p type=%d dns=%x", esp_netif, type, dns->ip.u_addr.ip4.addr);
ip_addr_t *lwip_ip = (ip_addr_t*)&dns->ip;
#if CONFIG_LWIP_IPV6 && LWIP_IPV4
lwip_ip->type = IPADDR_TYPE_V4;
#endif
if (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(lwip_ip);
}
#else
LOG_NETIF_DISABLED_AND_DO("DHCP Server", return ESP_ERR_NOT_SUPPORTED);
#endif
} else {
dns_setserver(type, lwip_ip);
}
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)
{
if (_IS_NETIF_ANY_POINT2POINT_TYPE(esp_netif)) {
return ESP_ERR_NOT_SUPPORTED;
}
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, "%s esp_netif:%p", __func__, esp_netif);
if (!dns) {
ESP_LOGE(TAG, "%s: dns_info cannot be NULL", __func__);
return ESP_ERR_ESP_NETIF_INVALID_PARAMS;
}
if (esp_netif->flags & ESP_NETIF_DHCP_SERVER) {
#if ESP_DHCPS
ip4_addr_t dns_ip = dhcps_dns_getserver();
memcpy(&dns->ip.u_addr.ip4, &dns_ip, sizeof(ip4_addr_t));
#else
LOG_NETIF_DISABLED_AND_DO("DHCP Server", return ESP_ERR_NOT_SUPPORTED);
#endif
} else {
const ip_addr_t* dns_ip = NULL;
dns_ip = dns_getserver(type);
if(dns_ip != NULL) {
memcpy(&dns->ip, dns_ip, sizeof(ip_addr_t));
}
}
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)
{
if (_IS_NETIF_ANY_POINT2POINT_TYPE(esp_netif)) {
const ip_addr_t *dns_ip = dns_getserver(type);
if (dns_ip == IP_ADDR_ANY) {
return ESP_ERR_ESP_NETIF_DNS_NOT_CONFIGURED;
}
#if CONFIG_LWIP_IPV6
memcpy(&dns->ip.u_addr.ip4, &dns_ip->u_addr.ip4, sizeof(ip4_addr_t));
#else
memcpy(&dns->ip.u_addr.ip4, &dns_ip->addr, sizeof(ip4_addr_t));
#endif
return ESP_OK;
}
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
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_nd6_cb(struct netif *p_netif, uint8_t ip_index)
{
ESP_LOGD(TAG, "%s lwip-netif:%p", __func__, p_netif);
if (!p_netif) {
ESP_LOGD(TAG, "esp_netif_nd6_cb called with null p_netif");
return;
}
esp_netif_ip6_info_t ip6_info;
ip6_addr_t lwip_ip6_info;
//notify event
ip_event_got_ip6_t evt = { .esp_netif = p_netif->state, .if_index = -1, .ip_index = ip_index };
ip6_addr_set(&lwip_ip6_info, ip_2_ip6(&p_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 */
memcpy(&evt.ip6_info, &ip6_info, sizeof(esp_netif_ip6_info_t));
int ret = esp_event_send_internal(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);
nd6_set_cb(p_netif, esp_netif_nd6_cb);
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;
}
}
#if ESP_DHCPS
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)
{
void *opt_info = dhcps_option_info(opt_id, opt_len);
if (esp_netif == NULL) {
return ESP_ERR_ESP_NETIF_IF_NOT_READY;
}
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: {
memcpy(opt_info, opt_val, opt_len);
break;
}
case REQUESTED_IP_ADDRESS: {
esp_netif_ip_info_t info;
uint32_t softap_ip = 0;
uint32_t start_ip = 0;
uint32_t 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);
softap_ip = htonl(info.ip.addr);
start_ip = htonl(poll->start_ip.addr);
end_ip = htonl(poll->end_ip.addr);
/*config ip information can't contain local ip*/
if ((start_ip <= softap_ip) && (softap_ip <= end_ip)) {
return ESP_ERR_ESP_NETIF_INVALID_PARAMS;
}
/*config ip information must be in the same segment as the local ip*/
softap_ip >>= 8;
if ((start_ip >> 8 != softap_ip)
|| (end_ip >> 8 != softap_ip)) {
return ESP_ERR_ESP_NETIF_INVALID_PARAMS;
}
if (end_ip - start_ip > DHCPS_MAX_LEASE) {
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;
}
default:
break;
}
dhcps_set_option_info(opt_id, opt_info, opt_len);
} else {
return ESP_ERR_ESP_NETIF_INVALID_PARAMS;
}
return ESP_OK;
}
#endif
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 *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;
}
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(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;
}
netif_index_to_name(netif_get_index(esp_netif->lwip_netif), name);
return ESP_OK;
}
#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");
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, .if_index = -1, .ip_index = index};
evt.ip6_info.ip = addr->addr;
ESP_RETURN_ON_ERROR(esp_event_send_internal(IP_EVENT, IP_EVENT_GOT_IP6, &evt, sizeof(evt), 0), TAG,
"Failed to post IP_EVENT_GOT_IP6");
return error;
}
esp_err_t esp_netif_add_ip6_address(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)
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
#endif /* CONFIG_ESP_NETIF_TCPIP_LWIP */