feat(lwip): update lwip component from idf

This commit is contained in:
yuanjm
2019-12-17 10:31:03 +08:00
committed by dongheng
parent b2ca002f47
commit b89d8a7ab2
45 changed files with 1863 additions and 450 deletions

View File

@ -217,6 +217,7 @@ coap_free_endpoint(coap_endpoint_t *ep) {
/* define struct in6_pktinfo and struct in_pktinfo if not available
FIXME: check with configure
*/
#if 0 //update lwip and have conflict. Later will update COAP.
struct in6_pktinfo {
struct in6_addr ipi6_addr; /* src/dst IPv6 address */
unsigned int ipi6_ifindex; /* send/recv interface index */
@ -228,6 +229,7 @@ struct in_pktinfo {
struct in_addr ipi_addr;
};
#endif
#endif
#if defined(WITH_POSIX) && !defined(SOL_IP)
/* Solaris expects level IPPROTO_IP for ancillary data. */

View File

@ -26,7 +26,7 @@
#define HAVE_MALLOC
#define HAVE_ARPA_INET_H
#define IP_PKTINFO IP_MULTICAST_IF
//#define IP_PKTINFO IP_MULTICAST_IF
#define IPV6_PKTINFO IPV6_V6ONLY
#define PACKAGE_NAME "libcoap-posix"

View File

@ -49,6 +49,8 @@ extern int wifi_nvs_init(void);
extern esp_err_t esp_pthread_init(void);
extern void phy_get_bb_evm(void);
extern void uart_div_modify(uint8_t uart_no, uint16_t DivLatchValue);
/*Only for calling esp_wifi_set_ps can compile successfully */
uint32_t LwipTimOutLim = 0;
static inline int should_load(uint32_t load_addr)
{

View File

@ -40,7 +40,7 @@
#define ESP_TASKD_EVENT_PRIO (ESP_TASK_PRIO_MAX - 5)
#define ESP_TASKD_EVENT_STACK (CONFIG_ESP_SYSTEM_EVENT_TASK_STACK_SIZE + TASK_EXTRA_STACK_SIZE)
#define ESP_TASK_TCPIP_PRIO (ESP_TASK_PRIO_MAX - 7)
#define ESP_TASK_TCPIP_STACK (CONFIG_LWIP_TCPIP_TASK_STACK_SIZE + TASK_EXTRA_STACK_SIZE)
#define ESP_TASK_TCPIP_STACK (CONFIG_LWIP_TCPIP_TASK_STACK_SIZE)
#define ESP_TASK_MAIN_PRIO (ESP_TASK_PRIO_MIN + 1)
#define ESP_TASK_MAIN_STACK (CONFIG_ESP_MAIN_TASK_STACK_SIZE + TASK_EXTRA_STACK_SIZE)

View File

@ -16,6 +16,10 @@ config FREERTOS_ENABLE_REENT
The configuration will enable newlib.
config FREERTOS_NO_AFFINITY
hex
default 0x7FFFFFFF
config FREERTOS_HZ
int "Tick rate (Hz)"
range 1 1000

View File

@ -1,13 +1,15 @@
idf_build_get_property(target IDF_TARGET)
set(include_dirs
include/apps
include/apps/sntp
lwip/src/include
port/esp32/include
port/esp32/include/arch
port/${target}/include
port/${target}/include/arch
)
set(srcs
"apps/dhcpserver/dhcpserver.c"
"apps/multi-threads/sockets_mt.c"
"apps/ping/esp_ping.c"
"apps/ping/ping.c"
"apps/ping/ping_sock.c"
@ -85,12 +87,16 @@ set(srcs
"lwip/src/netif/ppp/upap.c"
"lwip/src/netif/ppp/utils.c"
"lwip/src/netif/ppp/vj.c"
"port/esp32/vfs_lwip.c"
"port/esp32/debug/lwip_debug.c"
"port/esp32/freertos/sys_arch.c"
"port/esp32/netif/dhcp_state.c"
"port/esp32/netif/nettestif.c"
"port/esp32/netif/wlanif.c")
"port/${target}/vfs_lwip.c"
"port/${target}/debug/lwip_debug.c"
"port/${target}/freertos/sys_arch.c"
"port/${target}/netif/dhcp_state.c"
"port/${target}/netif/wlanif.c")
if(CONFIG_IDF_TARGET_ESP32)
list(APPEND srcs
"port/${target}/netif/nettestif.c")
endif()
if(CONFIG_LWIP_PPP_SUPPORT)
list(APPEND srcs
@ -130,11 +136,15 @@ if(CONFIG_ETH_ENABLED)
list(APPEND srcs "port/esp32/netif/ethernetif.c")
endif()
if(CONFIG_LWIP_SOCKET_MULTITHREAD)
set(COMPONENT_OBJEXCLUDE lwip/src/api/sockets.c)
endif()
idf_component_register(SRCS "${srcs}"
INCLUDE_DIRS "${include_dirs}"
LDFRAGMENTS linker.lf
REQUIRES vfs esp_wifi
PRIV_REQUIRES ${priv_requires} esp_eth tcpip_adapter nvs_flash)
REQUIRES vfs
PRIV_REQUIRES ${priv_requires} tcpip_adapter nvs_flash)
# lots of LWIP source files evaluate macros that check address of stack variables
target_compile_options(${COMPONENT_LIB} PRIVATE -Wno-address)

View File

@ -124,6 +124,24 @@ menu "LWIP"
help
Enabling this option allows LWIP statistics
config LWIP_SOCKET_MULTITHREAD
bool "LWIP socket supports multithread"
default y
help
Enable the option can enable LWIP socket multithread and all
function will be thread safe.
config SET_SOLINGER_DEFAULT
bool "set socket SO_LINGER default"
default y
depends on LWIP_SOCKET_MULTITHREAD
help
The function is only used by socket multi-thread.
Enable this option can set the target socket to enable the "SO_LINGER" and config timeout to be "0" when it is created.
It means that if close the socket, all send queue will be dropped, so heap memory can be collected immediately,
but some packets which are waiting to be sent will lost.
config LWIP_ETHARP_TRUST_IP_MAC
bool "Enable LWIP ARP trust"
default n
@ -484,7 +502,7 @@ menu "LWIP"
config LWIP_TCPIP_TASK_STACK_SIZE
int "TCP/IP Task Stack Size"
default 3072
default 2048
# for high log levels, tcpip_adapter API calls can end up
# a few calls deep and logging there can trigger a stack overflow
range 2048 65536 if LOG_DEFAULT_LEVEL < 4
@ -593,6 +611,12 @@ menu "LWIP"
endmenu # LWIP RAW API
config LWIP_IPV6
bool "Enable IPv6"
default n
help
Enable IPV6
menu "SNTP"
config LWIP_DHCP_MAX_NTP_SERVERS

View File

@ -0,0 +1,826 @@
// Copyright 2018-2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "lwip/opt.h"
#ifdef SOCKETS_MT
#define SOCKETS_MT_DISABLE_SHUTDOWN
#include "lwip/priv/api_msg.h"
/* disable all LWIP socket API when compiling LWIP raw socket */
#undef lwip_accept
#undef lwip_bind
#undef lwip_shutdown
#undef lwip_getpeername
#undef lwip_getsockname
#undef lwip_setsockopt
#undef lwip_getsockopt
#undef lwip_close
#undef lwip_connect
#undef lwip_listen
#undef lwip_recv
#undef lwip_recvfrom
#undef lwip_send
#undef lwip_sendmsg
#undef lwip_sendto
#undef lwip_socket
#undef lwip_select
#undef lwip_ioctlsocket
#define lwip_accept lwip_accept_esp
#define lwip_bind lwip_bind_esp
#define lwip_shutdown lwip_shutdown_esp
#define lwip_getpeername lwip_getpeername_esp
#define lwip_getsockname lwip_getsockname_esp
#define lwip_setsockopt lwip_setsockopt_esp
#define lwip_getsockopt lwip_getsockopt_esp
#define lwip_close lwip_closesocket_esp
#define lwip_connect lwip_connect_esp
#define lwip_listen lwip_listen_esp
#define lwip_recv lwip_recv_esp
#define lwip_recvfrom lwip_recvfrom_esp
#define lwip_send lwip_send_esp
#define lwip_sendmsg lwip_sendmsg_esp
#define lwip_sendto lwip_sendto_esp
#define lwip_socket lwip_socket_esp
#define lwip_select lwip_select_esp
#define lwip_ioctlsocket lwip_ioctl_esp
#undef lwip_read
#undef lwip_write
#undef lwip_writev
#undef lwip_close
#undef closesocket
#undef lwip_fcntl
#undef lwip_ioctl
#define lwip_read lwip_read_esp
#define lwip_write lwip_write_esp
#define lwip_writev lwip_writev_esp
#define lwip_close lwip_close_esp
#define lwip_fcntl lwip_fcntl_esp
#define lwip_ioctl lwip_ioctl_esp
#include "../../lwip/src/api/sockets.c"
/* disable macros to enable LWIP function */
#undef lwip_accept
#undef lwip_bind
#undef lwip_shutdown
#undef lwip_getpeername
#undef lwip_getsockname
#undef lwip_setsockopt
#undef lwip_getsockopt
#undef lwip_close
#undef lwip_connect
#undef lwip_listen
#undef lwip_recv
#undef lwip_recvfrom
#undef lwip_send
#undef lwip_sendmsg
#undef lwip_sendto
#undef lwip_socket
#undef lwip_select
#undef lwip_ioctlsocket
#undef lwip_read
#undef lwip_write
#undef lwip_writev
#undef lwip_close
#undef closesocket
#undef lwip_fcntl
#undef lwip_ioctl
/********************************************************************/
#define LWIP_SYNC_MT_SLEEP_MS 10
#define SOCK_MT_DEBUG_LEVEL 255
typedef struct socket_conn_sync {
struct tcpip_api_call_data call;
struct netconn *conn;
} socket_conn_sync_t;
typedef int (*lwip_io_mt_fn)(int, int );
/* Use about 2 bit */
#define SOCK_MT_STATE_SOCK 0
#define SOCK_MT_STATE_ACCEPT 1
#define SOCK_MT_STATE_CONNECT 2
#define SOCK_MT_STATE_SEND 3
#define SOCK_MT_STATE_ILL 4
#define SOCK_MT_LOCK_SEND (1 << 0)
#define SOCK_MT_LOCK_RECV (1 << 1)
#define SOCK_MT_LOCK_IOCTL (1 << 2)
#define SOCK_MT_LOCK_MIN SOCK_MT_LOCK_SEND
#define SOCK_MT_LOCK_MAX SOCK_MT_LOCK_IOCTL
#define SOCK_MT_SELECT_RECV (1 << 0)
#define SOCK_MT_SELECT_SEND (1 << 1)
typedef struct _sock_mt {
uint8_t opened : 1;
uint8_t state : 2;
uint8_t select : 2;
uint8_t lock : 3;
} sock_mt_t;
#if (SOCK_MT_DEBUG_LEVEL < 16)
#define SOCK_MT_DEBUG(level, ...) \
if (level >= SOCK_MT_DEBUG_LEVEL) \
printf(__VA_ARGS__);
#else
#define SOCK_MT_DEBUG(level, ...)
#endif
#define SOCK_MT_ENTER_CHECK(s, l, st) \
{ \
if (_sock_lock(s, l) != ERR_OK) \
return -1; \
if (st != SOCK_MT_STATE_ILL) \
_sock_set_state(s, st); \
}
#define SOCK_MT_EXIT_CHECK(s, l, st) \
{ \
if (st != SOCK_MT_STATE_ILL) \
_sock_set_state(s, SOCK_MT_STATE_SOCK); \
if (_sock_unlock(s, l) != ERR_OK) \
return -1; \
}
static volatile sock_mt_t DRAM_ATTR sockets_mt[NUM_SOCKETS];
static inline void _sock_mt_init(int s)
{
memset((void *)&sockets_mt[s - LWIP_SOCKET_OFFSET], 0, sizeof(sock_mt_t));
}
static inline int _sock_is_opened(int s)
{
return sockets_mt[s - LWIP_SOCKET_OFFSET].opened != 0;
}
static inline void _sock_set_open(int s, int opened)
{
SYS_ARCH_DECL_PROTECT(lev);
SYS_ARCH_PROTECT(lev);
sockets_mt[s - LWIP_SOCKET_OFFSET].opened = opened;
SYS_ARCH_UNPROTECT(lev);
}
static inline void _sock_set_state(int s, int state)
{
SYS_ARCH_DECL_PROTECT(lev);
SYS_ARCH_PROTECT(lev);
sockets_mt[s - LWIP_SOCKET_OFFSET].state = state;
SYS_ARCH_UNPROTECT(lev);
}
static inline int _sock_get_state(int s)
{
return sockets_mt[s - LWIP_SOCKET_OFFSET].state;
}
static inline int _sock_get_select(int s, int select)
{
return sockets_mt[s - LWIP_SOCKET_OFFSET].select & select;
}
static int inline _sock_is_lock(int s, int l)
{
return sockets_mt[s - LWIP_SOCKET_OFFSET].lock & l;
}
static int inline _sock_next_lock(int lock)
{
return lock << 1;
}
static void inline _sock_set_select(int s, int select)
{
SYS_ARCH_DECL_PROTECT(lev);
SYS_ARCH_PROTECT(lev);
sockets_mt[s - LWIP_SOCKET_OFFSET].select |= select;
SYS_ARCH_UNPROTECT(lev);
}
static void inline _sock_reset_select(int s, int select)
{
SYS_ARCH_DECL_PROTECT(lev);
SYS_ARCH_PROTECT(lev);
sockets_mt[s - LWIP_SOCKET_OFFSET].select &= ~select;
SYS_ARCH_UNPROTECT(lev);
}
static int _sock_try_lock(int s, int l)
{
int ret = ERR_OK;
SYS_ARCH_DECL_PROTECT(lev);
if (!_sock_is_opened(s)) {
ret = ERR_CLSD;
goto exit;
}
if (sockets_mt[s - LWIP_SOCKET_OFFSET].lock & l) {
ret = ERR_INPROGRESS;
goto exit;
}
SYS_ARCH_PROTECT(lev);
sockets_mt[s - LWIP_SOCKET_OFFSET].lock |= l;
SYS_ARCH_UNPROTECT(lev);
exit:
return ret;
}
static int _sock_lock(int s, int l)
{
int ret = ERR_OK;
if (tryget_socket_unconn_nouse(s) == NULL)
return -1;
SOCK_MT_DEBUG(1, "s %d l %d enter ", s, l);
while (1) {
ret = _sock_try_lock(s, l);
if (ret != ERR_INPROGRESS)
break;
vTaskDelay(1);
}
SOCK_MT_DEBUG(1, "OK %d\n", ret);
return ret;
}
static int _sock_unlock(int s, int l)
{
int ret = 0;
SYS_ARCH_DECL_PROTECT(lev);
SOCK_MT_DEBUG(1, "s %d l %d exit ", s, l);
SYS_ARCH_PROTECT(lev);
sockets_mt[s - LWIP_SOCKET_OFFSET].lock &= ~l;
SYS_ARCH_UNPROTECT(lev);
if (!_sock_is_opened(s)) {
ret = ERR_CLSD;
goto exit;
}
exit:
SOCK_MT_DEBUG(1, "OK %d\n", ret);
return ret;
}
static int lwip_enter_mt_select(int s, fd_set *read_set, fd_set *write_set)
{
int i;
if (s > NUM_SOCKETS + LWIP_SOCKET_OFFSET || s < LWIP_SOCKET_OFFSET)
return -1;
for (i = 0; i < s; i++) {
if(FD_ISSET(i, read_set) || FD_ISSET(i, write_set))
if (tryget_socket_unconn_nouse(i) == NULL)
goto failed1;
if (FD_ISSET(i, read_set)) {
err_t err;
_sock_set_select(i, SOCK_MT_SELECT_RECV);
err = _sock_lock(i, SOCK_MT_LOCK_RECV);
if (err != ERR_OK) {
goto failed2;
}
}
if (FD_ISSET(i, write_set)) {
err_t err;
_sock_set_select(i, SOCK_MT_SELECT_SEND);
err = _sock_lock(i, SOCK_MT_LOCK_SEND);
if (err != ERR_OK) {
goto failed3;
}
}
}
return 0;
failed3:
_sock_unlock(i, SOCK_MT_LOCK_SEND);
_sock_reset_select(i, SOCK_MT_SELECT_SEND);
failed2:
if (FD_ISSET(i, read_set)) {
_sock_unlock(i, SOCK_MT_LOCK_RECV);
_sock_reset_select(i, SOCK_MT_SELECT_RECV);
}
failed1:
for (i--; i >=0; i--) {
if (FD_ISSET(i, read_set) ) {
_sock_unlock(i, SOCK_MT_LOCK_RECV);
_sock_reset_select(i, SOCK_MT_SELECT_RECV);
}
if (FD_ISSET(i, write_set)) {
_sock_unlock(i, SOCK_MT_LOCK_SEND);
_sock_reset_select(i, SOCK_MT_SELECT_SEND);
}
}
return -1;
}
static void lwip_exit_mt_select(int s, fd_set *read_set, fd_set *write_set)
{
int i;
for (i = 0; i < s; i++) {
if (FD_ISSET(i, read_set)) {
_sock_unlock(i, SOCK_MT_LOCK_RECV);
_sock_reset_select(i, SOCK_MT_SELECT_RECV);
}
if (FD_ISSET(i, write_set)) {
_sock_unlock(i, SOCK_MT_LOCK_SEND);
_sock_reset_select(i, SOCK_MT_SELECT_SEND);
}
}
}
static err_t lwip_do_sync_accept(struct tcpip_api_call_data *call)
{
socket_conn_sync_t *sync = (socket_conn_sync_t *)call;
struct netconn *conn = sync->conn;
SYS_ARCH_DECL_PROTECT(lev);
SYS_ARCH_PROTECT(lev);
if (sys_mbox_valid(&conn->acceptmbox))
sys_mbox_trypost(&conn->acceptmbox, NULL);
conn->state = NETCONN_NONE;
SYS_ARCH_UNPROTECT(lev);
return ERR_OK;
}
static err_t lwip_do_sync_send(struct tcpip_api_call_data *call)
{
socket_conn_sync_t *sync = (socket_conn_sync_t *)call;
struct netconn *conn = sync->conn;
SYS_ARCH_DECL_PROTECT(lev);
SYS_ARCH_PROTECT(lev);
if (conn->current_msg) {
conn->current_msg->err = ERR_OK;
if (sys_sem_valid(conn->current_msg->op_completed_sem))
sys_sem_signal(conn->current_msg->op_completed_sem);
conn->current_msg = NULL;
}
conn->state = NETCONN_NONE;
SYS_ARCH_UNPROTECT(lev);
return ERR_OK;
}
static err_t lwip_do_sync_recv_state(struct tcpip_api_call_data *call)
{
socket_conn_sync_t *sync = (socket_conn_sync_t *)call;
struct netconn *conn = sync->conn;
SYS_ARCH_DECL_PROTECT(lev);
SYS_ARCH_PROTECT(lev);
SOCK_MT_DEBUG(1, "sync recv %d\n", conn->socket);
if (sys_mbox_valid(&conn->recvmbox))
sys_mbox_trypost(&conn->recvmbox, NULL);
conn->state = NETCONN_NONE;
SYS_ARCH_UNPROTECT(lev);
return ERR_OK;
}
static err_t lwip_do_sync_select_state(struct tcpip_api_call_data *call)
{
socket_conn_sync_t *sync = (socket_conn_sync_t *)call;
struct netconn *conn = sync->conn;
SYS_ARCH_DECL_PROTECT(lev);
SYS_ARCH_PROTECT(lev);
event_callback(conn, NETCONN_EVT_ERROR, 0);
conn->state = NETCONN_NONE;
SYS_ARCH_UNPROTECT(lev);
return ERR_OK;
}
static void lwip_sync_state_mt(int s)
{
struct lwip_sock *sock = tryget_socket_unconn_nouse(s);
int state = _sock_get_state(s);
socket_conn_sync_t sync = {
.conn = sock->conn,
};
SOCK_MT_DEBUG(1, "sync state %d\n", state);
switch (state) {
case SOCK_MT_STATE_ACCEPT :
tcpip_api_call(lwip_do_sync_accept, &sync.call);
break;
case SOCK_MT_STATE_CONNECT:
case SOCK_MT_STATE_SEND :
tcpip_api_call(lwip_do_sync_send, &sync.call);
break;
default :
break;
}
}
static void lwip_sync_recv_mt(int s)
{
struct lwip_sock *sock = tryget_socket_unconn_nouse(s);
socket_conn_sync_t sync = {
.conn = sock->conn,
};
tcpip_api_call(lwip_do_sync_recv_state, &sync.call);
}
static void lwip_sync_select_mt(int s)
{
struct lwip_sock *sock = tryget_socket_unconn_nouse(s);
socket_conn_sync_t sync = {
.conn = sock->conn,
};
tcpip_api_call(lwip_do_sync_select_state, &sync.call);
}
static void lwip_sync_mt(int s, int how)
{
int lock = SOCK_MT_LOCK_MIN;
do {
if (_sock_is_lock(s, lock)) {
int need_wait = 0;
if (!_sock_get_select(s, SOCK_MT_SELECT_RECV | SOCK_MT_SELECT_SEND)) {
switch (lock) {
case SOCK_MT_LOCK_SEND:
lwip_sync_state_mt(s);
need_wait = 1;
break;
case SOCK_MT_LOCK_RECV:
lwip_sync_recv_mt(s);
need_wait = 1;
break;
default :
break;
}
} else {
lwip_sync_select_mt(s);
need_wait = 1;
}
if (need_wait)
sys_delay_ms(LWIP_SYNC_MT_SLEEP_MS);
} else
lock = _sock_next_lock(lock);
} while (lock < SOCK_MT_LOCK_MAX);
}
#if SET_SOLINGER_DEFAULT
#if LWIP_SO_LINGER
static void lwip_socket_set_so_link(int s, int linger)
{
struct lwip_sock *sock = tryget_socket_unconn_nouse(s);
if (sock) {
/*
* linker:
* -1: nothing
* 0: free sent_buf immediately
*/
sock->conn->linger = linger;
}
}
#else
#error "LWIP_SO_LINGER must be enable"
#endif /* LWIP_SO_LINGER */
#else /* SET_SOLINGER_DEFAULT */
#define lwip_socket_set_so_link(_s, _linger)
#endif /* SET_SOLINGER_DEFAULT */
int lwip_socket(int domain, int type, int protocol)
{
int s;
s = lwip_socket_esp(domain, type, protocol);
if (s < 0)
return -1;
lwip_socket_set_so_link(s, 0);
_sock_mt_init(s);
_sock_set_open(s, 1);
return s;
}
int lwip_bind(int s, const struct sockaddr *name, socklen_t namelen)
{
int ret;
SOCK_MT_ENTER_CHECK(s, SOCK_MT_LOCK_SEND, SOCK_MT_STATE_ILL);
ret = lwip_bind_esp(s, name, namelen);
SOCK_MT_EXIT_CHECK(s, SOCK_MT_LOCK_SEND, SOCK_MT_STATE_ILL);
return ret;
}
int lwip_connect(int s, const struct sockaddr *name, socklen_t namelen)
{
int ret;
SOCK_MT_ENTER_CHECK(s, SOCK_MT_LOCK_SEND, SOCK_MT_STATE_CONNECT);
ret = lwip_connect_esp(s, name, namelen);
SOCK_MT_EXIT_CHECK(s, SOCK_MT_LOCK_SEND, SOCK_MT_STATE_CONNECT);
return ret;
}
int lwip_listen(int s, int backlog)
{
int ret;
SOCK_MT_ENTER_CHECK(s, SOCK_MT_LOCK_SEND, SOCK_MT_STATE_ILL);
lwip_socket_set_so_link(s, -1);
ret = lwip_listen_esp(s, backlog);
SOCK_MT_EXIT_CHECK(s, SOCK_MT_LOCK_SEND, SOCK_MT_STATE_ILL);
return ret;
}
int lwip_accept(int s, struct sockaddr *addr, socklen_t *addrlen)
{
int ret;
SOCK_MT_ENTER_CHECK(s, SOCK_MT_LOCK_SEND, SOCK_MT_STATE_ACCEPT)
lwip_socket_set_so_link(s, -1);
ret = lwip_accept_esp(s, addr, addrlen);
SOCK_MT_EXIT_CHECK(s, SOCK_MT_LOCK_SEND, SOCK_MT_STATE_ACCEPT);
if (ret < 0)
return -1;
lwip_socket_set_so_link(ret, 0);
_sock_mt_init(ret);
_sock_set_open(ret, 1);
return ret;
}
int lwip_getpeername(int s, struct sockaddr *name, socklen_t *namelen)
{
int ret;
SOCK_MT_ENTER_CHECK(s, SOCK_MT_LOCK_IOCTL, SOCK_MT_STATE_ILL);
ret = lwip_getpeername_esp(s, name, namelen);
SOCK_MT_EXIT_CHECK(s, SOCK_MT_LOCK_IOCTL, SOCK_MT_STATE_ILL);
return ret;
}
int lwip_getsockname(int s, struct sockaddr *name, socklen_t *namelen)
{
int ret;
SOCK_MT_ENTER_CHECK(s, SOCK_MT_LOCK_IOCTL, SOCK_MT_STATE_ILL);
ret = lwip_getsockname_esp(s, name, namelen);
SOCK_MT_EXIT_CHECK(s, SOCK_MT_LOCK_IOCTL, SOCK_MT_STATE_ILL);
return ret;
}
int lwip_setsockopt(int s, int level, int optname, const void *optval, socklen_t optlen)
{
int ret;
SOCK_MT_ENTER_CHECK(s, SOCK_MT_LOCK_IOCTL, SOCK_MT_STATE_ILL);
ret = lwip_setsockopt_esp(s, level, optname, optval, optlen);
SOCK_MT_EXIT_CHECK(s, SOCK_MT_LOCK_IOCTL, SOCK_MT_STATE_ILL);
return ret;
}
int lwip_getsockopt(int s, int level, int optname, void *optval, socklen_t *optlen)
{
int ret;
if (tryget_socket_unconn_nouse(s) == NULL)
return -1;
if (optname == SO_ERROR) {
int retval = 0;
if (!_sock_is_opened(s))
retval = ENOTCONN;
if (retval) {
*(int *)optval = retval;
return 0;
}
}
SOCK_MT_ENTER_CHECK(s, SOCK_MT_LOCK_IOCTL, SOCK_MT_STATE_ILL);
ret = lwip_getsockopt_esp(s, level, optname, optval, optlen);
SOCK_MT_EXIT_CHECK(s, SOCK_MT_LOCK_IOCTL, SOCK_MT_STATE_ILL);
return ret;
}
int lwip_ioctl(int s, long cmd, void *argp)
{
int ret;
SOCK_MT_ENTER_CHECK(s, SOCK_MT_LOCK_IOCTL, SOCK_MT_STATE_ILL)
ret = lwip_ioctl_esp(s, cmd, argp);
SOCK_MT_EXIT_CHECK(s, SOCK_MT_LOCK_IOCTL, SOCK_MT_STATE_ILL);
return ret;
}
int lwip_sendto(int s, const void *data, size_t size, int flags,
const struct sockaddr *to, socklen_t tolen)
{
int ret;
SOCK_MT_ENTER_CHECK(s, SOCK_MT_LOCK_SEND, SOCK_MT_STATE_SEND);
ret = lwip_sendto_esp(s, data, size, flags, to, tolen);
SOCK_MT_EXIT_CHECK(s, SOCK_MT_LOCK_SEND, SOCK_MT_STATE_SEND);
return ret;
}
int lwip_send(int s, const void *data, size_t size, int flags)
{
int ret;
SOCK_MT_ENTER_CHECK(s, SOCK_MT_LOCK_SEND, SOCK_MT_STATE_SEND);
ret = lwip_send_esp(s, data, size, flags);
SOCK_MT_EXIT_CHECK(s, SOCK_MT_LOCK_SEND, SOCK_MT_STATE_SEND);
return ret;
}
int lwip_recvfrom(int s, void *mem, size_t len, int flags,
struct sockaddr *from, socklen_t *fromlen)
{
int ret;
SOCK_MT_ENTER_CHECK(s, SOCK_MT_LOCK_RECV, SOCK_MT_STATE_ILL);
ret = lwip_recvfrom_esp(s, mem, len, flags, from, fromlen);
SOCK_MT_EXIT_CHECK(s, SOCK_MT_LOCK_RECV, SOCK_MT_STATE_ILL);
return ret;
}
int lwip_recv(int s, void *mem, size_t len, int flags)
{
return lwip_recvfrom(s, mem, len, flags, NULL, NULL);
}
int lwip_read(int s, void *mem, size_t len)
{
return lwip_recvfrom(s, mem, len, 0, NULL, NULL);
}
int lwip_write(int s, const void *data, size_t size)
{
return lwip_send(s, data, size, 0);
}
int lwip_fcntl(int s, int cmd, int val)
{
int ret;
SOCK_MT_ENTER_CHECK(s, SOCK_MT_LOCK_IOCTL, SOCK_MT_STATE_ILL);
ret = lwip_fcntl_esp(s, cmd, val);
SOCK_MT_EXIT_CHECK(s, SOCK_MT_LOCK_IOCTL, SOCK_MT_STATE_ILL);
return ret;
}
int lwip_shutdown(int s, int how)
{
return 0;
}
int lwip_close(int s)
{
int ret;
SYS_ARCH_DECL_PROTECT(lev);
if (tryget_socket_unconn_nouse(s) == NULL)
return -1;
SYS_ARCH_PROTECT(lev);
if (_sock_is_opened(s)) {
_sock_set_open(s, 0);
SYS_ARCH_UNPROTECT(lev);
} else {
SYS_ARCH_UNPROTECT(lev);
return -1;
}
lwip_sync_mt(s, SHUT_RDWR);
ret = lwip_close_esp(s);
return ret;
}
int lwip_select(int maxfdp1, fd_set *readset, fd_set *writeset,
fd_set *exceptset, struct timeval *timeout)
{
int ret;
fd_set read_set, write_set;
if (readset)
MEMCPY(&read_set, readset, sizeof(fd_set));
else
FD_ZERO(&read_set);
if (writeset)
MEMCPY(&write_set, writeset, sizeof(fd_set));
else
FD_ZERO(&write_set);
ret = lwip_enter_mt_select(maxfdp1, &read_set, &write_set);
if (ret)
return ret;
ret = lwip_select_esp(maxfdp1, readset, writeset, exceptset, timeout);
lwip_exit_mt_select(maxfdp1, &read_set, &write_set);
return ret;
}
#endif

View File

@ -112,13 +112,15 @@ static int esp_ping_receive(esp_ping_t *ep)
struct sockaddr_in *from4 = (struct sockaddr_in *)&from;
inet_addr_to_ip4addr(ip_2_ip4(&ep->recv_addr), &from4->sin_addr);
IP_SET_TYPE_VAL(ep->recv_addr, IPADDR_TYPE_V4);
} else {
}
#if LWIP_IPV6
else {
// IPv6
struct sockaddr_in6 *from6 = (struct sockaddr_in6 *)&from;
inet6_addr_to_ip6addr(ip_2_ip6(&ep->recv_addr), &from6->sin6_addr);
IP_SET_TYPE_VAL(ep->recv_addr, IPADDR_TYPE_V6);
}
#endif
// Currently we only process IPv4
if (IP_IS_V4_VAL(ep->recv_addr)) {
struct ip_hdr *iphdr = (struct ip_hdr *)buf;
@ -236,12 +238,18 @@ esp_err_t esp_ping_new_session(const esp_ping_config_t *config, const esp_ping_c
d[i] = 'A' + i;
}
/* create socket */
if (IP_IS_V4(&config->target_addr) || ip6_addr_isipv4mappedipv6(ip_2_ip6(&config->target_addr))) {
#if LWIP_IPV4 && LWIP_IPV6
if (IP_IS_V4(&config->target_addr) || ip6_addr_isipv4mappedipv6(ip_2_ip6(&config->target_addr))) {
ep->sock = socket(AF_INET, SOCK_RAW, IP_PROTO_ICMP);
} else {
ep->sock = socket(AF_INET6, SOCK_RAW, IP6_NEXTH_ICMP6);
}
#else
if (IP_IS_V4(&config->target_addr)) {
ep->sock = socket(AF_INET, SOCK_RAW, IP_PROTO_ICMP);
} else {
ep->sock = socket(AF_INET6, SOCK_RAW, IP6_NEXTH_ICMP6);
}
#endif
PING_CHECK(ep->sock > 0, "create socket failed: %d", err, ESP_FAIL, ep->sock);
struct timeval timeout;
@ -259,11 +267,13 @@ esp_err_t esp_ping_new_session(const esp_ping_config_t *config, const esp_ping_c
to4->sin_family = AF_INET;
inet_addr_from_ip4addr(&to4->sin_addr, ip_2_ip4(&config->target_addr));
}
#if LWIP_IPV6
if (IP_IS_V6(&config->target_addr)) {
struct sockaddr_in6 *to6 = (struct sockaddr_in6 *)&ep->target_addr;
to6->sin6_family = AF_INET6;
inet6_addr_from_ip6addr(&to6->sin6_addr, ip_2_ip6(&config->target_addr));
}
#endif
/* return ping handle to user */
*hdl_out = (esp_ping_handle_t)ep;
return ESP_OK;

View File

@ -7,8 +7,8 @@ COMPONENT_ADD_INCLUDEDIRS := \
include/apps \
include/apps/sntp \
lwip/src/include \
port/esp32/include \
port/esp32/include/arch
port/esp8266/include \
port/esp8266/include/arch
COMPONENT_SRCDIRS := \
apps/dhcpserver \
@ -21,15 +21,21 @@ COMPONENT_SRCDIRS := \
lwip/src/core/ipv4 \
lwip/src/core/ipv6 \
lwip/src/netif \
port/esp32 \
port/esp32/freertos \
port/esp32/netif \
port/esp32/debug
port/esp8266 \
port/esp8266/freertos \
port/esp8266/netif \
port/esp8266/debug
ifndef CONFIG_IDF_TARGET_ESP32
COMPONENT_OBJEXCLUDE := port/esp32/netif/ethernetif.o
COMPONENT_OBJEXCLUDE := port/esp8266/netif/ethernetif.o
endif
ifdef CONFIG_LWIP_SOCKET_MULTITHREAD
COMPONENT_SRCDIRS += apps/multi-threads
COMPONENT_OBJEXCLUDE += lwip/src/api/sockets.o
endif
ifdef CONFIG_LWIP_PPP_SUPPORT
COMPONENT_SRCDIRS += lwip/src/netif/ppp lwip/src/netif/ppp/polarssl
endif

View File

@ -77,6 +77,11 @@ typedef struct {
* @brief Default ping configuration
*
*/
#if LWIP_IPV4 && LWIP_IPV6
#define PING_TARGET_ADDR ip_addr_any_type
#else
#define PING_TARGET_ADDR ip_addr_any
#endif
#define ESP_PING_DEFAULT_CONFIG() \
{ \
.count = 5, \
@ -84,7 +89,7 @@ typedef struct {
.timeout_ms = 1000, \
.data_size = 56, \
.tos = 0, \
.target_addr = ip_addr_any_type, \
.target_addr = PING_TARGET_ADDR, \
.task_stack_size = 2048, \
.task_prio = 2, \
}

View File

@ -1,87 +1,4 @@
[mapping:lwip]
archive: liblwip.a
entries:
if LWIP_IRAM_OPTIMIZATION = y:
sockets:get_socket (noflash_text)
sockets:tryget_socket (noflash_text)
sockets:tryget_socket_unconn (noflash_text)
sockets:sock_inc_used (noflash_text)
sockets:tryget_socket_unconn_nouse (noflash_text)
sockets:tryget_socket_unconn_locked (noflash_text)
sockets:done_socket (noflash_text)
sockets:lwip_recvfrom (noflash_text)
sockets:lwip_recv_tcp (noflash_text)
sockets:lwip_recv_tcp_from (noflash_text)
sockets:lwip_recvfrom_udp_raw (noflash_text)
sockets:lwip_send (noflash_text)
sockets:lwip_sendto (noflash_text)
sockets:event_callback (noflash_text)
sockets:lwip_select (noflash_text)
sockets:select_check_waiters (noflash_text)
api_lib:netconn_apimsg (noflash_text)
api_lib:netconn_recv_data (noflash_text)
api_lib:netconn_tcp_recvd_msg (noflash_text)
api_lib:netconn_tcp_recvd (noflash_text)
api_lib:netconn_recv_data_tcp (noflash_text)
api_lib:netconn_recv_tcp_pbuf_flags (noflash_text)
api_lib:netconn_recv_udp_raw_netbuf_flags (noflash_text)
api_lib:netconn_recv (noflash_text)
api_lib:netconn_sendto (noflash_text)
api_lib:netconn_send (noflash_text)
api_lib:netconn_write_partly (noflash_text)
api_lib:netconn_write_vectors_partly (noflash_text)
api_msg:lwip_netconn_do_send (noflash_text)
api_msg:lwip_netconn_do_write (noflash_text)
netbuf:netbuf_alloc (noflash_text)
netbuf:netbuf_free (noflash_text)
tcpip:tcpip_thread (noflash_text)
tcpip:tcpip_thread_handle_msg (noflash_text)
tcpip:tcpip_inpkt (noflash_text)
tcpip:tcpip_input (noflash_text)
tcpip:tcpip_callback (noflash_text)
tcpip:tcpip_try_callback (noflash_text)
tcpip:tcpip_send_msg_wait_sem (noflash_text)
inet_chksum:inet_cksum_pseudo_base (noflash_text)
inet_chksum:inet_chksum_pseudo (noflash_text)
etharp:etharp_output_to_arp_index (noflash_text)
etharp:etharp_output (noflash_text)
ip4_addr:ip4_addr_isbroadcast_u32 (noflash_text)
ip4:ip4_route_src_hook (noflash_text)
ip4:ip4_route_src (noflash_text)
ip4:ip4_route (noflash_text)
ip4:ip4_input (noflash_text)
ip4:ip4_output_if (noflash_text)
ip4:ip4_output_if_opt (noflash_text)
ip4:ip4_output_if_src (noflash_text)
ip4:ip4_output_if_opt_src (noflash_text)
ip4:ip4_output (noflash_text)
pbuf:pbuf_alloc (noflash_text)
pbuf:pbuf_add_header_impl (noflash_text)
pbuf:pbuf_add_header (noflash_text)
pbuf:pbuf_remove_header (noflash_text)
pbuf:pbuf_header_impl (noflash_text)
pbuf:pbuf_header (noflash_text)
pbuf:pbuf_free (noflash_text)
timeouts:sys_timeouts_mbox_fetch (noflash_text)
udp:udp_input_local_match (noflash_text)
udp:udp_input (noflash_text)
udp:udp_send (noflash_text)
udp:udp_sendto (noflash_text)
udp:udp_sendto_if (noflash_text)
udp:udp_sendto_if_src (noflash_text)
ethernet:ethernet_input (noflash_text)
ethernet:ethernet_output (noflash_text)
sys_arch:sys_mutex_lock (noflash_text)
sys_arch:sys_mutex_unlock (noflash_text)
sys_arch:sys_sem_signal (noflash_text)
sys_arch:sys_arch_sem_wait (noflash_text)
sys_arch:sys_mbox_post (noflash_text)
sys_arch:sys_mbox_trypost (noflash_text)
sys_arch:sys_arch_mbox_fetch (noflash_text)
ethernetif:ethernet_low_level_output (noflash_text)
ethernetif:ethernetif_input (noflash_text)
wlanif:low_level_output (noflash_text)
wlanif:wlanif_input (noflash_text)
else:
* (default)
* (iram_bss)

View File

@ -1,245 +0,0 @@
/**
* @file
* Ethernet Interface Skeleton
*
*/
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
#include "lwip/opt.h"
#include "lwip/def.h"
#include "lwip/mem.h"
#include "lwip/pbuf.h"
#include "lwip/stats.h"
#include "lwip/snmp.h"
#include "lwip/ethip6.h"
#include "netif/etharp.h"
#include "netif/wlanif.h"
#include <stdio.h>
#include <string.h>
#include "tcpip_adapter.h"
/**
* In this function, the hardware should be initialized.
* Called from ethernetif_init().
*
* @param netif the already initialized lwip network interface structure
* for this ethernetif
*/
static void
low_level_init(struct netif *netif)
{
/* set MAC hardware address length */
netif->hwaddr_len = ETHARP_HWADDR_LEN;
/* set MAC hardware address */
/* maximum transfer unit */
netif->mtu = 1500;
/* device capabilities */
/* don't set NETIF_FLAG_ETHARP if this device is not an ethernet one */
netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_LINK_UP;
#if ESP_LWIP
#if LWIP_IGMP
netif->flags |= NETIF_FLAG_IGMP;
#endif
#endif
#if !ESP_L2_TO_L3_COPY
netif->l2_buffer_free_notify = esp_wifi_internal_free_rx_buffer;
#endif
}
/**
* This function should do the actual transmission of the packet. The packet is
* contained in the pbuf that is passed to the function. This pbuf
* might be chained.
*
* @param netif the lwip network interface structure for this ethernetif
* @param p the MAC packet to send (e.g. IP packet including MAC addresses and type)
* @return ERR_OK if the packet could be sent
* an err_t value if the packet couldn't be sent
*
* @note Returning ERR_MEM here if a DMA queue of your MAC is full can lead to
* strange results. You might consider waiting for space in the DMA queue
* to become availale since the stack doesn't retry to send a packet
* dropped because of memory failure (except for the TCP timers).
*/
static err_t ESP_IRAM_ATTR
low_level_output(struct netif *netif, struct pbuf *p)
{
wifi_interface_t wifi_if = tcpip_adapter_get_esp_if(netif);
struct pbuf *q = p;
err_t ret;
if (wifi_if >= ESP_IF_MAX) {
return ERR_IF;
}
if(q->next == NULL) {
ret = esp_wifi_internal_tx(wifi_if, q->payload, q->len);
} else {
LWIP_DEBUGF(PBUF_DEBUG, ("low_level_output: pbuf is a list, application may has bug"));
q = pbuf_alloc(PBUF_RAW_TX, p->tot_len, PBUF_RAM);
if (q != NULL) {
q->l2_owner = NULL;
pbuf_copy(q, p);
} else {
return ERR_MEM;
}
ret = esp_wifi_internal_tx(wifi_if, q->payload, q->len);
pbuf_free(q);
}
return ret;
}
/**
* This function should be called when a packet is ready to be read
* from the interface. It uses the function low_level_input() that
* should handle the actual reception of bytes from the network
* interface. Then the type of the received packet is determined and
* the appropriate input function is called.
*
* @param netif the lwip network interface structure for this ethernetif
*/
void ESP_IRAM_ATTR
wlanif_input(struct netif *netif, void *buffer, u16_t len, void* eb)
{
struct pbuf *p;
if(!buffer || !netif_is_up(netif)) {
if (eb) {
esp_wifi_internal_free_rx_buffer(eb);
}
return;
}
#if (ESP_L2_TO_L3_COPY == 1)
p = pbuf_alloc(PBUF_RAW, len, PBUF_RAM);
if (p == NULL) {
esp_wifi_internal_free_rx_buffer(eb);
return;
}
p->l2_owner = NULL;
memcpy(p->payload, buffer, len);
esp_wifi_internal_free_rx_buffer(eb);
#else
p = pbuf_alloc(PBUF_RAW, len, PBUF_REF);
if (p == NULL){
esp_wifi_internal_free_rx_buffer(eb);
return;
}
p->payload = buffer;
p->l2_owner = netif;
p->l2_buf = eb;
#endif
/* full packet send to tcpip_thread to process */
if (netif->input(p, netif) != ERR_OK) {
LWIP_DEBUGF(NETIF_DEBUG, ("ethernetif_input: IP input error\n"));
pbuf_free(p);
}
}
/**
* Should be called at the beginning of the program to set up the
* network interface. It calls the function low_level_init() to do the
* actual setup of the hardware.
*
* This function should be passed as a parameter to netif_add().
*
* @param netif the lwip network interface structure for this ethernetif
* @return ERR_OK if the loopif is initialized
* ERR_MEM if private data couldn't be allocated
* any other err_t on error
*/
err_t
wlanif_init(struct netif *netif)
{
LWIP_ASSERT("netif != NULL", (netif != NULL));
#if LWIP_NETIF_HOSTNAME
/* Initialize interface hostname */
#if ESP_LWIP
netif->hostname = CONFIG_LWIP_LOCAL_HOSTNAME;
#else
netif->hostname = "lwip";
#endif
#endif /* LWIP_NETIF_HOSTNAME */
/*
* Initialize the snmp variables and counters inside the struct netif.
* The last argument should be replaced with your link speed, in units
* of bits per second.
*/
NETIF_INIT_SNMP(netif, snmp_ifType_ethernet_csmacd, 100);
/* We directly use etharp_output() here to save a function call.
* You can instead declare your own function an call etharp_output()
* from it if you have to do some checks before sending (e.g. if link
* is available...) */
netif->output = etharp_output;
#if LWIP_IPV6
netif->output_ip6 = ethip6_output;
#endif /* LWIP_IPV6 */
netif->linkoutput = low_level_output;
/* initialize the hardware */
low_level_init(netif);
return ERR_OK;
}
err_t wlanif_init_sta(struct netif *netif) {
netif->name[0] = 's';
netif->name[1] = 't';
return wlanif_init(netif);
}
err_t wlanif_init_ap(struct netif *netif) {
netif->name[0] = 'a';
netif->name[1] = 'p';
return wlanif_init(netif);
}

View File

@ -23,10 +23,14 @@
#include "lwip/memp.h"
#include "esp_log.h"
#if LWIP_IPV4 && LWIP_IPV6
#define DBG_LWIP_IP_SHOW(info, ip) ESP_LWIP_LOGI("%s type=%d ip=%x", (info), (ip).type, (ip).u_addr.ip4.addr)
#else
#define DBG_LWIP_IP_SHOW(info, ip) ESP_LWIP_LOGI("%s ip=%x", (info), (ip).addr)
#endif
#define DBG_LWIP_IP_PCB_SHOW(pcb) \
DBG_LWIP_IP_SHOW("local ip", (pcb)->local_ip);\
DBG_LWIP_IP_SHOW("remote ip", (pcb)->local_ip);\
DBG_LWIP_IP_SHOW("remote ip", (pcb)->remote_ip);\
ESP_LWIP_LOGI("so_options=%x, tos=%d ttl=%d", (pcb)->so_options, (pcb)->tos, (pcb)->ttl)
#define DBG_LWIP_SEG_SHOW(seg) while(seg) { ESP_LWIP_LOGI("\tseg=%p next=%p pbuf=%p flags=%x", (seg), (seg)->next, (seg)->p, (seg)->flags); (seg)=(seg)->next;}
@ -186,11 +190,13 @@ void dbg_lwip_stats_show(void)
LINK_STATS_DISPLAY();
MEM_STATS_DISPLAY();
SYS_STATS_DISPLAY();
#if LWIP_IPV6
IP6_STATS_DISPLAY();
ICMP6_STATS_DISPLAY();
IP6_FRAG_STATS_DISPLAY();
MLD6_STATS_DISPLAY();
ND6_STATS_DISPLAY();
#endif
}
#if (ESP_STATS_MEM == 1)

View File

@ -41,10 +41,12 @@
#include <sys/types.h>
#include <sys/select.h>
#include "esp_task.h"
#include "esp_libc.h"
#include "esp_system.h"
#include "sdkconfig.h"
#include "sntp.h"
#include "netif/dhcp_state.h"
#include "driver/soc.h"
/* Enable all Espressif-only options */
@ -100,6 +102,16 @@
*/
#define MEM_ALIGNMENT 4
#define mem_clib_free(s) heap_caps_free(s)
#define mem_clib_malloc(s) heap_caps_malloc(s, MALLOC_CAP_8BIT)
#define mem_clib_calloc(n, s) heap_caps_calloc(n, s, MALLOC_CAP_8BIT)
/**
* @brief System
*/
#define SYS_ARCH_DECL_PROTECT(_lev) esp_irqflag_t _lev
#define SYS_ARCH_PROTECT(_lev) _lev = soc_save_local_irq()
#define SYS_ARCH_UNPROTECT(_lev) soc_restore_local_irq(_lev)
/*
------------------------------------------------
---------- Internal Memory Pool Sizes ----------
@ -386,6 +398,13 @@
---------- Pbuf options ----------
----------------------------------
*/
/**
* PBUF_LINK_ENCAPSULATION_HLEN: the number of bytes that should be allocated
* for an additional encapsulation header before ethernet headers (e.g. 802.11)
*/
#define PBUF_LINK_ENCAPSULATION_HLEN 36u
#define LWIP_SUPPORT_CUSTOM_PBUF 1
/*
------------------------------------------------
@ -548,6 +567,13 @@
*/
#define LWIP_SO_RCVBUF CONFIG_LWIP_SO_RCVBUF
/**
* LWIP_SO_LINGER==1: Enable SO_LINGER processing.
*/
#define LWIP_SO_LINGER 1
#define SET_SOLINGER_DEFAULT CONFIG_SET_SOLINGER_DEFAULT
/**
* SO_REUSE==1: Enable SO_REUSEADDR option.
* This option is set via menuconfig.
@ -668,7 +694,7 @@
/**
* LWIP_IPV6==1: Enable IPv6
*/
#define LWIP_IPV6 1
#define LWIP_IPV6 CONFIG_LWIP_IPV6
/*
---------------------------------------
@ -766,7 +792,9 @@
#define LWIP_SOCKET_OFFSET (FD_SETSIZE - CONFIG_LWIP_MAX_SOCKETS)
/* Enable all Espressif-only options */
#ifdef CONFIG_LWIP_SOCKET_MULTITHREAD
#define SOCKETS_MT
#endif
#define ESP_LWIP 1
#define ESP_LWIP_ARP 1
#define ESP_PER_SOC_TCP_WND 0
@ -774,7 +802,7 @@
#define ESP_THREAD_SAFE_DEBUG LWIP_DBG_OFF
#define ESP_DHCP 1
#define ESP_DNS 1
#define ESP_IPV6_AUTOCONFIG 1
#define ESP_IPV6_AUTOCONFIG LWIP_IPV6
#define ESP_PERF 0
#define ESP_RANDOM_TCP_PORT 1
#define ESP_IP4_ATON 1
@ -793,7 +821,7 @@
#define ESP_AUTO_IP 1
#define ESP_PBUF 1
#define ESP_PPP 1
#define ESP_IPV6 1
#define ESP_IPV6 LWIP_IPV6
#define ESP_SOCKET 1
#define ESP_LWIP_SELECT 1
@ -820,6 +848,16 @@
#define LWIP_DEBUG LWIP_DBG_OFF
#define TCP_DEBUG LWIP_DBG_OFF
#define ESP_TCP_TXRX_PBUF_DEBUG LWIP_DBG_OFF
#define LWIP_SEND_DATA_TO_WIFI 1
#define LWIP_RESEND_DATA_TO_WIFI_WHEN_WIFI_SEND_FAILED 2
#define LWIP_RECV_DATA_FROM_WIFI 3
#define LWIP_RETRY_DATA_WHEN_RECV_ACK_TIMEOUT 4
#define LWIP_FETCH_DATA_AT_TCPIP_THREAD 5
#define WIFI_SEND_DATA_FAILED 6
void tcp_print_status(int status, void* p, uint32_t tmp1, uint32_t tmp2, uint32_t tmp3);
#define CHECKSUM_CHECK_UDP 0
#define CHECKSUM_CHECK_IP 0

View File

@ -16,24 +16,6 @@
#ifndef _WLAN_LWIP_IF_H_
#define _WLAN_LWIP_IF_H_
#include "esp_wifi.h"
#include "esp_private/wifi.h"
#include "lwip/err.h"
#ifdef __cplusplus
extern "C" {
#endif
err_t wlanif_init_ap(struct netif *netif);
err_t wlanif_init_sta(struct netif *netif);
void wlanif_input(struct netif *netif, void *buffer, u16_t len, void* eb);
wifi_interface_t wifi_get_interface(void *dev);
void netif_reg_addr_change_cb(void* cb);
#ifdef __cplusplus
}

View File

@ -31,6 +31,7 @@ static const char *interface_key[] = {"IF_STA", "IF_AP", "IF_ETH", "IF_TEST"};
_Static_assert(sizeof(interface_key) / sizeof(char*) == TCPIP_ADAPTER_IF_MAX,
"Number interface keys differs from number of interfaces");
typedef nvs_handle nvs_handle_t;
bool dhcp_ip_addr_restore(void *netif)
{
nvs_handle_t nvs;

View File

@ -0,0 +1,629 @@
/**
* @file
* Ethernet Interface Skeleton
*
*/
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
#include <string.h>
#include "lwip/pbuf.h"
#include "lwip/ethip6.h"
#include "netif/etharp.h"
#include "esp_libc.h"
#include "esp_wifi.h"
#include "esp_aio.h"
#include "tcpip_adapter.h"
#include "freertos/semphr.h"
#include "lwip/tcpip.h"
#include "stdlib.h"
#include "esp8266/eagle_soc.h"
int ieee80211_output_pbuf(esp_aio_t *aio);
int8_t wifi_get_netif(uint8_t fd);
void wifi_station_set_default_hostname(uint8_t* hwaddr);
#define IFNAME0 'e'
#define IFNAME1 'n'
#if ESP_TCP
typedef struct pbuf_send_list {
struct pbuf_send_list* next;
struct pbuf* p;
int aiofd;
int err_cnt;
} pbuf_send_list_t;
static pbuf_send_list_t* pbuf_list_head = NULL;
static int pbuf_send_list_num = 0;
#endif
static int low_level_send_cb(esp_aio_t* aio);
#if ESP_TCP_TXRX_PBUF_DEBUG
void tcp_print_status(int status, void* buf, uint32_t tmp1, uint32_t tmp2, uint32_t tmp3)
{
struct pbuf* p = (struct pbuf*)buf;
if (p->tot_len < 50) {
return;
}
uint32_t i;
i = *((unsigned char*)p->payload + 12);
if (i == 0x08) { /*ipv4*/
i = *((unsigned char*)p->payload + 13);
if (i == 0) {
i = *((unsigned char*)p->payload + 23);
if (i == 0x06) { /*tcp*/
i = *((unsigned char*)p->payload + 16);
i <<= 8;
i += *((unsigned char*)p->payload + 17);
if (i >= 40) { /*tcp data*/
uint32_t len, seq, ack, srcport, destport, flags;
wifi_tx_status_t *tx_result = (wifi_tx_status_t *)(&tmp1);
len = i;
i = *((unsigned char*)p->payload + 38);
i <<= 8;
i += *((unsigned char*)p->payload + 39);
i <<= 8;
i += *((unsigned char*)p->payload + 40);
i <<= 8;
i += *((unsigned char*)p->payload + 41);
seq = i;
i = *((unsigned char*)p->payload + 42);
i <<= 8;
i += *((unsigned char*)p->payload + 43);
i <<= 8;
i += *((unsigned char*)p->payload + 44);
i <<= 8;
i += *((unsigned char*)p->payload + 45);
ack = i;
i = *((unsigned char*)p->payload + 34);
i <<= 8;
i += *((unsigned char*)p->payload + 35);
srcport = i;
i = *((unsigned char*)p->payload + 36);
i <<= 8;
i += *((unsigned char*)p->payload + 37);
destport = i;
flags = *((unsigned char *)p->payload+47);
switch (status) {
case LWIP_SEND_DATA_TO_WIFI:
LWIP_DEBUGF(ESP_TCP_TXRX_PBUF_DEBUG, ("@@ Tx - L:%u, S:%u, A:%u, SP:%u, DP:%u, F:%x\n", len, seq, ack, srcport, destport, flags));
break;
case LWIP_RESEND_DATA_TO_WIFI_WHEN_WIFI_SEND_FAILED:
LWIP_DEBUGF(ESP_TCP_TXRX_PBUF_DEBUG, ("@@ Cache Tx - L:%u, S:%u, A:%u, SP:%u, DP:%u, F:%x\n", len, seq, ack, srcport, destport, flags));
break;
case LWIP_RECV_DATA_FROM_WIFI:
LWIP_DEBUGF(ESP_TCP_TXRX_PBUF_DEBUG, ("@@ WiFi Rx - L:%u, S:%u, A:%u, SP:%u, DP:%u, F:%x\n", len, seq, ack, srcport, destport, flags));
break;
case LWIP_RETRY_DATA_WHEN_RECV_ACK_TIMEOUT:
LWIP_DEBUGF(ESP_TCP_TXRX_PBUF_DEBUG, ("@@ TCP RTY - rtime:%d, rto:%d, L:%u, S:%u, A:%u, SP:%u, DP:%u, F:%x\n", tmp1, tmp2, len, seq, ack, srcport, destport, flags));
return;
case LWIP_FETCH_DATA_AT_TCPIP_THREAD:
LWIP_DEBUGF(ESP_TCP_TXRX_PBUF_DEBUG, ("@@ eth Rx - L:%u, S:%u, A:%u, SP:%u, DP:%u, F:%x\n", len, seq, ack, srcport, destport, flags));
break;
case WIFI_SEND_DATA_FAILED:
LWIP_DEBUGF(ESP_TCP_TXRX_PBUF_DEBUG, ("@@ WiFi Tx Fail - result:%d, src:%d, lrc:%d, rate:%d, L:%u, S:%u, A:%u, SP:%u, DP:%u, F:%x\n",\
tx_result->wifi_tx_result, tx_result->wifi_tx_src, tx_result->wifi_tx_lrc, tx_result->wifi_tx_rate, len, seq, ack, srcport, destport, flags));
break;
default:
LWIP_DEBUGF(ESP_TCP_TXRX_PBUF_DEBUG, ("@@ status:%d, L:%u, S:%u, A:%u, SP:%u, DP:%u, F:%x, tmp1:%d, tmp2:%d, tmp3:%d\n",\
status, len, seq, ack, srcport, destport, flags, tmp1, tmp2, tmp3));
break;
}
}
}
}
}
}
#endif
#if ESP_TCP
static inline bool check_pbuf_to_insert(struct pbuf* p)
{
uint8_t* buf = (uint8_t*)p->payload;
/*Check if pbuf is tcp ip*/
if (buf[12] == 0x08 && buf[13] == 0x00 && buf[23] == 0x06) {
return true;
}
return false;
}
static void insert_to_list(int fd, struct pbuf* p)
{
pbuf_send_list_t* tmp_pbuf_list1;
pbuf_send_list_t* tmp_pbuf_list2;
if (pbuf_send_list_num > (TCP_SND_QUEUELEN * MEMP_NUM_TCP_PCB + MEMP_NUM_TCP_PCB)) {
return;
}
if (!check_pbuf_to_insert(p)) {
return;
}
LWIP_DEBUGF(PBUF_CACHE_DEBUG, ("Insert %p,%d\n", p, pbuf_send_list_num));
if (pbuf_list_head == NULL) {
tmp_pbuf_list1 = (pbuf_send_list_t*)malloc(sizeof(pbuf_send_list_t));
if (!tmp_pbuf_list1) {
LWIP_DEBUGF(PBUF_CACHE_DEBUG, ("no memory malloc pbuf list error\n"));
return;
}
pbuf_ref(p);
tmp_pbuf_list1->aiofd = fd;
tmp_pbuf_list1->p = p;
tmp_pbuf_list1->next = NULL;
tmp_pbuf_list1->err_cnt = 0;
pbuf_list_head = tmp_pbuf_list1;
pbuf_send_list_num++;
return;
}
tmp_pbuf_list1 = pbuf_list_head;
tmp_pbuf_list2 = tmp_pbuf_list1;
while (tmp_pbuf_list1 != NULL) {
if (tmp_pbuf_list1->p == p) {
tmp_pbuf_list1->err_cnt ++;
return;
}
tmp_pbuf_list2 = tmp_pbuf_list1;
tmp_pbuf_list1 = tmp_pbuf_list2->next;
}
tmp_pbuf_list1 = (pbuf_send_list_t*)malloc(sizeof(pbuf_send_list_t));
if (!tmp_pbuf_list1) {
LWIP_DEBUGF(PBUF_CACHE_DEBUG, ("no memory malloc pbuf list error\n"));
return;
}
pbuf_ref(p);
tmp_pbuf_list1->aiofd = fd;
tmp_pbuf_list1->p = p;
tmp_pbuf_list1->next = NULL;
tmp_pbuf_list1->err_cnt = 0;
tmp_pbuf_list2->next = tmp_pbuf_list1;
pbuf_send_list_num++;
}
void send_from_list()
{
pbuf_send_list_t* tmp_pbuf_list1;
while (pbuf_list_head != NULL) {
if (pbuf_list_head->p->ref == 1) {
tmp_pbuf_list1 = pbuf_list_head->next;
LWIP_DEBUGF(PBUF_CACHE_DEBUG, ("Delete %p,%d\n", pbuf_list_head->p, pbuf_send_list_num));
pbuf_free(pbuf_list_head->p);
free(pbuf_list_head);
pbuf_send_list_num--;
pbuf_list_head = tmp_pbuf_list1;
} else {
esp_aio_t aio;
esp_err_t err;
aio.fd = (int)pbuf_list_head->aiofd;
aio.pbuf = pbuf_list_head->p->payload;
aio.len = pbuf_list_head->p->len;
aio.cb = low_level_send_cb;
aio.arg = pbuf_list_head->p;
aio.ret = 0;
err = ieee80211_output_pbuf(aio);
#if ESP_TCP_TXRX_PBUF_DEBUG
tcp_print_status(LWIP_RESEND_DATA_TO_WIFI_WHEN_WIFI_SEND_FAILED, (void*)pbuf_list_head->p, 0 ,0, 0);
#endif
tmp_pbuf_list1 = pbuf_list_head->next;
if (err == ERR_MEM) {
pbuf_list_head->err_cnt++;
if (pbuf_list_head->err_cnt >= 3) {
LWIP_DEBUGF(PBUF_CACHE_DEBUG, ("Delete %p,%d\n", pbuf_list_head->p, pbuf_send_list_num));
pbuf_free(pbuf_list_head->p);
free(pbuf_list_head);
pbuf_send_list_num--;
pbuf_list_head = tmp_pbuf_list1;
}
return;
} else if (err == ERR_OK) {
LWIP_DEBUGF(PBUF_CACHE_DEBUG, ("Delete %p,%d\n", pbuf_list_head->p, pbuf_send_list_num));
free(pbuf_list_head);
pbuf_send_list_num--;
pbuf_list_head = tmp_pbuf_list1;
} else {
LWIP_DEBUGF(PBUF_CACHE_DEBUG, ("Delete %p,%d\n", pbuf_list_head->p, pbuf_send_list_num));
pbuf_free(pbuf_list_head->p);
free(pbuf_list_head);
pbuf_send_list_num--;
pbuf_list_head = tmp_pbuf_list1;
}
}
}
}
#endif
/**
* In this function, the hardware should be initialized.
* Called from ethernetif_init().
*
* @param netif the already initialized lwip network interface structure
* for this ethernetif
*/
static void low_level_init(struct netif* netif)
{
if (netif == NULL) {
LWIP_DEBUGF(NETIF_DEBUG, ("low_level_init: netif is NULL\n"));
return;
}
/* set MAC hardware address length */
netif->hwaddr_len = ETHARP_HWADDR_LEN;
/* maximum transfer unit */
netif->mtu = 1500;
/* device capabilities */
/* don't set NETIF_FLAG_ETHARP if this device is not an ethernet one */
netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_LINK_UP;
#if LWIP_IGMP
netif->flags |= NETIF_FLAG_IGMP;
#endif
/* Do whatever else is needed to initialize interface. */
}
/*
* @brief LWIP low-level AI/O sending callback function, it is to free pbuf
*
* @param aio AI/O control block pointer
*
* @return 0 meaning successs
*/
static int low_level_send_cb(esp_aio_t* aio)
{
struct pbuf* pbuf = aio->arg;
#if ESP_TCP_TXRX_PBUF_DEBUG
wifi_tx_status_t* status = (wifi_tx_status_t*) & (aio->ret);
if (TX_STATUS_SUCCESS != status->wifi_tx_result) {
uint8_t* buf = (uint8_t*)pbuf->payload;
/*Check if pbuf is tcp ip*/
if (buf[12] == 0x08 && buf[13] == 0x00 && buf[23] == 0x06) {
tcp_print_status(WIFI_SEND_DATA_FAILED, (void*)pbuf, aio->ret ,0, 0);
}
}
#endif
#if ESP_TCP
wifi_tx_status_t* status = (wifi_tx_status_t*) & (aio->ret);
if ((TX_STATUS_SUCCESS != status->wifi_tx_result) && check_pbuf_to_insert(pbuf)) {
uint8_t* buf = (uint8_t*)pbuf->payload;
struct eth_hdr ethhdr;
if (*(buf - 17) & 0x01) { //From DS
memcpy(&ethhdr.dest, buf - 2, ETH_HWADDR_LEN);
memcpy(&ethhdr.src, buf - 2 - ETH_HWADDR_LEN, ETH_HWADDR_LEN);
} else if (*(buf - 17) & 0x02) { //To DS
memcpy(&ethhdr.dest, buf - 2 - ETH_HWADDR_LEN - ETH_HWADDR_LEN, ETH_HWADDR_LEN);
memcpy(&ethhdr.src, buf - 2, 6);
} else {
pbuf_free(pbuf);
return 0;
}
memcpy(buf, &ethhdr, (ETH_HWADDR_LEN + ETH_HWADDR_LEN));
LWIP_DEBUGF(PBUF_CACHE_DEBUG, ("Send packet fail: result:%d, LRC:%d, SRC:%d, RATE:%d",
status->wifi_tx_result, status->wifi_tx_lrc, status->wifi_tx_src, status->wifi_tx_rate));
insert_to_list(aio->fd, aio->arg);
}
#endif
pbuf_free(pbuf);
return 0;
}
/*
* @brief transform custom pbuf to LWIP core pbuf, LWIP may use input custom pbuf
* to send ARP data directly
*
* @param pbuf LWIP pbuf pointer
*
* @return LWIP pbuf pointer which it not "PBUF_FLAG_IS_CUSTOM" attribute
*/
static inline struct pbuf* ethernetif_transform_pbuf(struct pbuf* pbuf)
{
struct pbuf* p;
if (!(pbuf->flags & PBUF_FLAG_IS_CUSTOM) && IS_DRAM(pbuf->payload)) {
/*
* Add ref to pbuf to avoid it to be freed by upper layer.
*/
pbuf_ref(pbuf);
return pbuf;
}
p = pbuf_alloc(PBUF_RAW, pbuf->len, PBUF_RAM);
if (!p) {
return NULL;
}
if (IS_IRAM(p->payload)) {
LWIP_DEBUGF(NETIF_DEBUG, ("low_level_output: data in IRAM\n"));
pbuf_free(p);
return NULL;
}
memcpy(p->payload, pbuf->payload, pbuf->len);
/*
* The input pbuf(named "pbuf") should not be freed, becasue it will be
* freed by upper layer.
*
* The output pbuf(named "p") should not be freed either, becasue it will
* be freed at callback function "low_level_send_cb".
*/
return p;
}
/**
* This function should do the actual transmission of the packet. The packet is
* contained in the pbuf that is passed to the function. This pbuf
* might be chained.
*
* @param netif the lwip network interface structure for this ethernetif
* @param p the MAC packet to send (e.g. IP packet including MAC addresses and type)
* @return ERR_OK if the packet could be sent
* an int8_t value if the packet couldn't be sent
*
* @note Returning ERR_MEM here if a DMA queue of your MAC is full can lead to
* strange results. You might consider waiting for space in the DMA queue
* to become availale since the stack doesn't retry to send a packet
* dropped because of memory failure (except for the TCP timers).
*/
static int8_t low_level_output(struct netif* netif, struct pbuf* p)
{
esp_aio_t aio;
int8_t err = ERR_OK;
if (netif == NULL) {
LWIP_DEBUGF(NETIF_DEBUG, ("low_level_output: netif is NULL\n"));
return ERR_ARG;
}
if (!netif_is_up(netif)) {
LWIP_DEBUGF(NETIF_DEBUG, ("low_level_output: netif is not up\n"));
return ERR_RTE;
}
#if ETH_PAD_SIZE
pbuf_header(p, -ETH_PAD_SIZE); /* drop the padding word */
#endif
p = ethernetif_transform_pbuf(p);
if (!p) {
LWIP_DEBUGF(NETIF_DEBUG, ("low_level_output: lack memory\n"));
return ERR_OK;
}
aio.fd = (int)netif->state;
aio.pbuf = p->payload;
aio.len = p->len;
aio.cb = low_level_send_cb;
aio.arg = p;
aio.ret = 0;
#if ESP_TCP_TXRX_PBUF_DEBUG
tcp_print_status(LWIP_SEND_DATA_TO_WIFI, (void*)p, 0 ,0, 0);
#endif
/*
* we use "SOCK_RAW" to create socket, so all input/output datas include full ethernet
* header, meaning we should not pass target low-level address here.
*/
err = ieee80211_output_pbuf(&aio);
if (err != ERR_OK) {
if (err == ERR_MEM) {
#if ESP_TCP
insert_to_list(aio.fd, p);
#endif
err = ERR_OK;
}
pbuf_free(p);
}
// signal that packet should be sent();
#if ETH_PAD_SIZE
pbuf_header(p, ETH_PAD_SIZE); /* reclaim the padding word */
#endif
#if LWIP_STATS
LINK_STATS_INC(link.xmit);
#endif
return err;
}
/**
* This function should be called when a packet is ready to be read
* from the interface. It uses the function low_level_input() that
* should handle the actual reception of bytes from the network
* interface. Then the type of the received packet is determined and
* the appropriate input function is called.
*
* @param netif the lwip network interface structure for this ethernetif
*/
void ethernetif_input(struct netif* netif, struct pbuf* p)
{
struct eth_hdr* ethhdr;
if (p == NULL) {
LWIP_DEBUGF(NETIF_DEBUG, ("ethernetif_input: pbuf is NULL\n"));
goto _exit;
}
if (p->payload == NULL) {
LWIP_DEBUGF(NETIF_DEBUG, ("ethernetif_input: payload is NULL\n"));
pbuf_free(p);
goto _exit;
}
if (netif == NULL) {
LWIP_DEBUGF(NETIF_DEBUG, ("ethernetif_input: netif is NULL\n"));
pbuf_free(p);
goto _exit;
}
if (!(netif->flags & NETIF_FLAG_LINK_UP)) {
LWIP_DEBUGF(NETIF_DEBUG, ("ethernetif_input: netif is not up\n"));
pbuf_free(p);
p = NULL;
goto _exit;
}
/* points to packet payload, which starts with an Ethernet header */
ethhdr = p->payload;
switch (htons(ethhdr->type)) {
/* IP or ARP packet? */
case ETHTYPE_IP:
case ETHTYPE_IPV6:
case ETHTYPE_ARP:
#if PPPOE_SUPPORT
/* PPPoE packet? */
case ETHTYPE_PPPOEDISC:
case ETHTYPE_PPPOE:
#endif /* PPPOE_SUPPORT */
/* full packet send to tcpip_thread to process */
if (netif->input(p, netif) != ERR_OK) {
LWIP_DEBUGF(NETIF_DEBUG, ("ethernetif_input: IP input error\n"));
pbuf_free(p);
p = NULL;
}
break;
default:
pbuf_free(p);
p = NULL;
break;
}
_exit:
;
}
/**
* Should be called at the beginning of the program to set up the
* network interface. It calls the function low_level_init() to do the
* actual setup of the hardware.
*
* This function should be passed as a parameter to netif_add().
*
* @param netif the lwip network interface structure for this ethernetif
* @return ERR_OK if the loopif is initialized
* ERR_MEM if private data couldn't be allocated
* any other int8_t on error
*/
int8_t ethernetif_init(struct netif* netif)
{
if (netif == NULL) {
LWIP_DEBUGF(NETIF_DEBUG, ("ethernetif_init: netif is NULL\n"));
}
#if LWIP_NETIF_HOSTNAME
/* Initialize interface hostname */
#if ESP_LWIP
netif->hostname = CONFIG_LWIP_LOCAL_HOSTNAME;
#else
netif->hostname = "lwip";
#endif
#endif /* LWIP_NETIF_HOSTNAME */
/*
* Initialize the snmp variables and counters inside the struct netif.
* The last argument should be replaced with your link speed, in units
* of bits per second.
*/
netif->name[0] = IFNAME0;
netif->name[1] = IFNAME1;
/* We directly use etharp_output() here to save a function call.
* You can instead declare your own function an call etharp_output()
* from it if you have to do some checks before sending (e.g. if link
* is available...) */
netif->output = etharp_output;
#if LWIP_IPV6
netif->output_ip6 = ethip6_output;
#endif /* LWIP_IPV6 */
netif->linkoutput = low_level_output;
/* initialize the hardware */
low_level_init(netif);
return ERR_OK;
}

View File

@ -21,35 +21,28 @@
#include "esp_vfs.h"
#include "esp_vfs_dev.h"
#include "esp_attr.h"
#include "esp8266/uart_struct.h"
#include "lwip/sockets.h"
#include "sdkconfig.h"
#include "lwip/sys.h"
_Static_assert(MAX_FDS >= CONFIG_LWIP_MAX_SOCKETS, "MAX_FDS < CONFIG_LWIP_MAX_SOCKETS");
static void lwip_stop_socket_select(void *sem)
static void lwip_stop_socket_select()
{
sys_sem_signal(sem); //socket_select will return
sys_sem_signal(sys_thread_sem_get()); //socket_select will return
}
static void lwip_stop_socket_select_isr(void *sem, BaseType_t *woken)
static void lwip_stop_socket_select_isr(BaseType_t *woken)
{
if (sys_sem_signal_isr(sem) && woken) {
if (sys_sem_signal_isr(sys_thread_sem_get()) && woken) {
*woken = pdTRUE;
}
}
static void *lwip_get_socket_select_semaphore(void)
static int lwip_fcntl_r_wrapper(int fd, int cmd, va_list args)
{
/* Calling this from the same process as select() will ensure that the semaphore won't be allocated from
* ISR (lwip_stop_socket_select_isr).
*/
return (void *) sys_thread_sem_get();
}
static int lwip_fcntl_r_wrapper(int fd, int cmd, int arg)
{
return lwip_fcntl(fd, cmd, arg);
return lwip_fcntl(fd, cmd, va_arg(args, int));
}
static int lwip_ioctl_r_wrapper(int fd, int cmd, va_list args)
@ -69,7 +62,6 @@ void esp_vfs_lwip_sockets_register(void)
.fcntl = &lwip_fcntl_r_wrapper,
.ioctl = &lwip_ioctl_r_wrapper,
.socket_select = &lwip_select,
.get_socket_select_semaphore = &lwip_get_socket_select_semaphore,
.stop_socket_select = &lwip_stop_socket_select,
.stop_socket_select_isr = &lwip_stop_socket_select_isr,
};

View File

@ -142,5 +142,5 @@
#endif
#ifndef PATH_MAX
#define PATH_MAX 4096
#define PATH_MAX 1024
#endif

View File

@ -27,6 +27,7 @@
#include "task.h"
#include "driver/soc.h"
#include "limits.h"
#include "sdkconfig.h"
#ifdef CONFIG_ESP8266_TIME_SYSCALL_USE_FRC1
@ -35,6 +36,20 @@
static uint64_t s_boot_time;
#if defined(WITH_RTC) || defined(WITH_FRC)
// stores the start time of the slew
static uint64_t adjtime_start = 0;
// is how many microseconds total to slew
static int64_t adjtime_total_correction = 0;
#define ADJTIME_CORRECTION_FACTOR 6
static uint64_t get_time_since_boot(void);
#endif
// Offset between FRC timer and the RTC.
// Initialized after reset or light sleep.
#if defined(WITH_RTC) && defined(WITH_FRC)
uint64_t s_microseconds_offset;
#endif
static inline void set_boot_time(uint64_t time_us)
{
esp_irqflag_t flag;
@ -56,6 +71,103 @@ static inline uint64_t get_boot_time()
return result;
}
// This function gradually changes boot_time to the correction value and immediately updates it.
static uint64_t adjust_boot_time(void)
{
uint64_t boot_time = get_boot_time();
if ((boot_time == 0) || (get_time_since_boot() < adjtime_start)) {
adjtime_start = 0;
}
if (adjtime_start > 0) {
uint64_t since_boot = get_time_since_boot();
// If to call this function once per second, then (since_boot - adjtime_start) will be 1_000_000 (1 second),
// and the correction will be equal to (1_000_000us >> 6) = 15_625 us.
// The minimum possible correction step can be (64us >> 6) = 1us.
// Example: if the time error is 1 second, then it will be compensate for 1 sec / 0,015625 = 64 seconds.
int64_t correction = (since_boot >> ADJTIME_CORRECTION_FACTOR) - (adjtime_start >> ADJTIME_CORRECTION_FACTOR);
if (correction > 0) {
adjtime_start = since_boot;
if (adjtime_total_correction < 0) {
if ((adjtime_total_correction + correction) >= 0) {
boot_time = boot_time + adjtime_total_correction;
adjtime_start = 0;
} else {
adjtime_total_correction += correction;
boot_time -= correction;
}
} else {
if ((adjtime_total_correction - correction) <= 0) {
boot_time = boot_time + adjtime_total_correction;
adjtime_start = 0;
} else {
adjtime_total_correction -= correction;
boot_time += correction;
}
}
set_boot_time(boot_time);
}
}
return boot_time;
}
#if defined( WITH_FRC ) || defined( WITH_RTC )
static uint64_t get_time_since_boot(void)
{
uint64_t microseconds = 0;
#ifdef WITH_FRC
#ifdef WITH_RTC
microseconds = s_microseconds_offset + esp_timer_get_time();
#else
microseconds = esp_timer_get_time();
#endif // WITH_RTC
#elif defined(WITH_RTC)
microseconds = get_rtc_time_us();
#endif // WITH_FRC
return microseconds;
}
#endif // defined( WITH_FRC ) || defined( WITH_RTC
int adjtime(const struct timeval *delta, struct timeval *outdelta)
{
#if defined( WITH_FRC ) || defined( WITH_RTC )
esp_irqflag_t flag;
if(delta != NULL){
int64_t sec = delta->tv_sec;
int64_t usec = delta->tv_usec;
if(llabs(sec) > ((INT_MAX / 1000000L) - 1L)) {
return -1;
}
/*
* If adjusting the system clock by adjtime () is already done during the second call adjtime (),
* and the delta of the second call is not NULL, the earlier tuning is stopped,
* but the already completed part of the adjustment is not canceled.
*/
flag = soc_save_local_irq();
// If correction is already in progress (adjtime_start != 0), then apply accumulated corrections.
adjust_boot_time();
adjtime_start = get_time_since_boot();
adjtime_total_correction = sec * 1000000L + usec;
soc_restore_local_irq(flag);
}
if(outdelta != NULL){
flag = soc_save_local_irq();
adjust_boot_time();
if (adjtime_start != 0) {
outdelta->tv_sec = adjtime_total_correction / 1000000L;
outdelta->tv_usec = adjtime_total_correction % 1000000L;
} else {
outdelta->tv_sec = 0;
outdelta->tv_usec = 0;
}
soc_restore_local_irq(flag);
}
return 0;
#else
return -1;
#endif
}
int _gettimeofday_r(struct _reent* r, struct timeval* tv, void* tz)
{
(void) tz;

View File

@ -2,6 +2,7 @@ menu "PThreads"
config ENABLE_PTHREAD
bool "Enable Pthread"
default y
help
Enable this option and then pthread is to be used.

View File

@ -127,11 +127,12 @@ typedef struct {
#define ESP_ERR_TCPIP_ADAPTER_NO_MEM ESP_ERR_TCPIP_ADAPTER_BASE + 0x06
#define ESP_ERR_TCPIP_ADAPTER_DHCP_NOT_STOPPED ESP_ERR_TCPIP_ADAPTER_BASE + 0x07
/* TODO: add Ethernet interface */
/* @brief On-chip network interfaces */
typedef enum {
TCPIP_ADAPTER_IF_STA = 0, /**< TCP-IP adatpter station interface */
TCPIP_ADAPTER_IF_AP, /**< TCP-IP adatpter soft-AP interface */
TCPIP_ADAPTER_IF_ETH, /**< TCP-IP adatpter ethernet interface */
TCPIP_ADAPTER_IF_STA = 0, /**< Wi-Fi STA (station) interface */
TCPIP_ADAPTER_IF_AP, /**< Wi-Fi soft-AP interface */
TCPIP_ADAPTER_IF_ETH, /**< Ethernet interface */
TCPIP_ADAPTER_IF_TEST, /**< tcpip stack test interface */
TCPIP_ADAPTER_IF_MAX
} tcpip_adapter_if_t;
@ -660,6 +661,15 @@ esp_err_t tcpip_adapter_set_default_wifi_handlers();
*/
esp_err_t tcpip_adapter_clear_default_wifi_handlers();
/**
* @brief Search nefit index through netif interface
* @param[in] tcpip_if Interface to search for netif index
* @return
* - netif_index on success
* - -1 if an invalid parameter is supplied
*/
int tcpip_adapter_get_netif_index(tcpip_adapter_if_t tcpip_if);
#ifdef __cplusplus
}
#endif

View File

@ -1223,28 +1223,6 @@ esp_err_t tcpip_adapter_get_netif(tcpip_adapter_if_t tcpip_if, void ** netif)
return ESP_OK;
}
struct netif* ip4_route_src_hook(const ip4_addr_t* dest, const ip4_addr_t* src)
{
extern struct netif *netif_list;
struct netif *netif = NULL;
/* destination IP is broadcast IP? */
if ((src != NULL) && !ip4_addr_isany(src)) {
/* iterate through netifs */
for (netif = netif_list; netif != NULL; netif = netif->next) {
/* is the netif up, does it have a link and a valid address? */
if (netif_is_up(netif) && netif_is_link_up(netif) && !ip4_addr_isany_val(*netif_ip4_addr(netif))) {
/* source IP matches? */
if (ip4_addr_cmp(src, netif_ip4_addr(netif))) {
/* return netif on which to forward IP packet */
return netif;
}
}
}
}
return netif;
}
bool tcpip_adapter_is_netif_up(tcpip_adapter_if_t tcpip_if)
{
if (esp_netif[tcpip_if] != NULL && netif_is_up(esp_netif[tcpip_if])) {
@ -1254,4 +1232,12 @@ bool tcpip_adapter_is_netif_up(tcpip_adapter_if_t tcpip_if)
}
}
int tcpip_adapter_get_netif_index(tcpip_adapter_if_t tcpip_if)
{
if (tcpip_if >= TCPIP_ADAPTER_IF_MAX || esp_netif[tcpip_if] == NULL) {
return -1;
}
return netif_get_index(esp_netif[tcpip_if]);
}
#endif /* CONFIG_TCPIP_LWIP */

View File

@ -2,14 +2,14 @@ menu "Virtual file system"
config USING_ESP_VFS
bool "Using espressif VFS"
default n
default y
help
Enable this option, espressif VFS can be used. Users can use APIs like "open", "read", "write"
and so on to operate I/O device which is registered.
config SUPPRESS_SELECT_DEBUG_OUTPUT
bool "Suppress select() related debug outputs"
default y
default n
depends on USING_ESP_VFS
help
Select() related functions might produce an unconveniently lot of
@ -19,7 +19,7 @@ config SUPPRESS_SELECT_DEBUG_OUTPUT
config SUPPORT_TERMIOS
bool "Add support for termios.h"
default y
default n
depends on USING_ESP_VFS
help
Disabling this option can save memory when the support for termios.h is not required.

View File

@ -19,6 +19,7 @@
#include <stddef.h>
#include <stdarg.h>
#include <unistd.h>
#include <utime.h>
#include "freertos/FreeRTOS.h"
#include "freertos/semphr.h"
#include "esp_err.h"
@ -27,6 +28,7 @@
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/termios.h>
#include <sys/poll.h>
#include <dirent.h>
#include <string.h>
#include "sdkconfig.h"
@ -379,6 +381,21 @@ void esp_vfs_select_triggered(SemaphoreHandle_t *signal_sem);
*/
void esp_vfs_select_triggered_isr(SemaphoreHandle_t *signal_sem, BaseType_t *woken);
/**
* @brief Implements the VFS layer for synchronous I/O multiplexing by poll()
*
* The implementation is based on esp_vfs_select. The parameters and return values are compatible with POSIX poll().
*
* @param fds Pointer to the array containing file descriptors and events poll() should consider.
* @param nfds Number of items in the array fds.
* @param timeout Poll() should wait at least timeout milliseconds. If the value is 0 then it should return
* immediately. If the value is -1 then it should wait (block) until the event occurs.
*
* @return A positive return value indicates the number of file descriptors that have been selected. The 0
* return value indicates a timed-out poll. -1 is return on failure and errno is set accordingly.
*
*/
int esp_vfs_poll(struct pollfd *fds, int nfds, int timeout);
#ifdef __cplusplus
} // extern "C"
#endif

View File

@ -1096,3 +1096,80 @@ int tcsendbreak(int fd, int duration)
return ret;
}
#endif // CONFIG_SUPPORT_TERMIOS
int esp_vfs_poll(struct pollfd *fds, int nfds, int timeout)
{
struct timeval tv = {
// timeout is in milliseconds
.tv_sec = timeout / 1000,
.tv_usec = (timeout % 1000) * 1000,
};
int max_fd = -1;
fd_set readfds;
fd_set writefds;
fd_set errorfds;
struct _reent* r = __getreent();
int ret = 0;
if (fds == NULL) {
__errno_r(r) = ENOENT;
return -1;
}
FD_ZERO(&readfds);
FD_ZERO(&writefds);
FD_ZERO(&errorfds);
for (int i = 0; i < nfds; ++i) {
fds[i].revents = 0;
if (fds[i].fd < 0) {
// revents should remain 0 and events ignored (according to the documentation of poll()).
continue;
}
if (fds[i].fd >= MAX_FDS) {
fds[i].revents |= POLLNVAL;
++ret;
continue;
}
if (fds[i].events & (POLLIN | POLLRDNORM | POLLRDBAND | POLLPRI)) {
FD_SET(fds[i].fd, &readfds);
FD_SET(fds[i].fd, &errorfds);
max_fd = MAX(max_fd, fds[i].fd);
}
if (fds[i].events & (POLLOUT | POLLWRNORM | POLLWRBAND)) {
FD_SET(fds[i].fd, &writefds);
FD_SET(fds[i].fd, &errorfds);
max_fd = MAX(max_fd, fds[i].fd);
}
}
const int select_ret = esp_vfs_select(max_fd + 1, &readfds, &writefds, &errorfds, timeout < 0 ? NULL: &tv);
if (select_ret > 0) {
ret += select_ret;
for (int i = 0; i < nfds; ++i) {
if (FD_ISSET(fds[i].fd, &readfds)) {
fds[i].revents |= POLLIN;
}
if (FD_ISSET(fds[i].fd, &writefds)) {
fds[i].revents |= POLLOUT;
}
if (FD_ISSET(fds[i].fd, &errorfds)) {
fds[i].revents |= POLLERR;
}
}
} else {
ret = select_ret;
// keeping the errno from select()
}
return ret;
}

View File

@ -61,7 +61,7 @@ static void openssl_client_task(void* p)
SSL_CTX* ctx;
SSL* ssl;
int socket;
int sockfd;
struct sockaddr_in sock_addr;
struct hostent* entry = NULL;
int recv_bytes = 0;
@ -108,9 +108,9 @@ static void openssl_client_task(void* p)
SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL);
printf("create socket ......");
socket = socket(AF_INET, SOCK_STREAM, 0);
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (socket < 0) {
if (sockfd < 0) {
printf("failed\n");
goto failed3;
}
@ -122,7 +122,7 @@ static void openssl_client_task(void* p)
sock_addr.sin_family = AF_INET;
sock_addr.sin_addr.s_addr = 0;
sock_addr.sin_port = htons(OPENSSL_CLIENT_LOCAL_TCP_PORT);
ret = bind(socket, (struct sockaddr*)&sock_addr, sizeof(sock_addr));
ret = bind(sockfd, (struct sockaddr*)&sock_addr, sizeof(sock_addr));
if (ret) {
printf("failed\n");
@ -136,7 +136,7 @@ static void openssl_client_task(void* p)
sock_addr.sin_family = AF_INET;
sock_addr.sin_addr.s_addr = ((struct in_addr*)(entry->h_addr))->s_addr;
sock_addr.sin_port = htons(CONFIG_TARGET_PORT_NUMBER);
ret = connect(socket, (struct sockaddr*)&sock_addr, sizeof(sock_addr));
ret = connect(sockfd, (struct sockaddr*)&sock_addr, sizeof(sock_addr));
if (ret) {
printf("failed\n");
@ -155,7 +155,7 @@ static void openssl_client_task(void* p)
printf("OK\n");
SSL_set_fd(ssl, socket);
SSL_set_fd(ssl, sockfd);
printf("SSL connected to %s port %d ......", CONFIG_TARGET_DOMAIN, CONFIG_TARGET_PORT_NUMBER);
ret = SSL_connect(ssl);
@ -198,7 +198,7 @@ failed7:
failed6:
failed5:
failed4:
close(socket);
close(sockfd);
failed3:
failed2:
SSL_CTX_free(ctx);

View File

@ -46,7 +46,7 @@ static void openssl_task(void *p)
SSL_CTX *ctx;
SSL *ssl;
int socket;
int sockfd;
struct sockaddr_in sock_addr;
struct hostent *entry = NULL;
@ -80,9 +80,9 @@ static void openssl_task(void *p)
SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, NULL);
ESP_LOGI(TAG, "create socket ......");
socket = socket(AF_INET, SOCK_STREAM, 0);
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (socket < 0) {
if (sockfd < 0) {
ESP_LOGI(TAG, "failed");
goto failed2;
}
@ -94,7 +94,7 @@ static void openssl_task(void *p)
sock_addr.sin_family = AF_INET;
sock_addr.sin_addr.s_addr = 0;
sock_addr.sin_port = htons(OPENSSL_DEMO_LOCAL_TCP_PORT);
ret = bind(socket, (struct sockaddr *)&sock_addr, sizeof(sock_addr));
ret = bind(sockfd, (struct sockaddr *)&sock_addr, sizeof(sock_addr));
if (ret) {
ESP_LOGI(TAG, "failed");
@ -108,7 +108,7 @@ static void openssl_task(void *p)
sock_addr.sin_family = AF_INET;
sock_addr.sin_addr.s_addr = ((struct in_addr *)(entry->h_addr))->s_addr;
sock_addr.sin_port = htons(OPENSSL_DEMO_TARGET_TCP_PORT);
ret = connect(socket, (struct sockaddr *)&sock_addr, sizeof(sock_addr));
ret = connect(sockfd, (struct sockaddr *)&sock_addr, sizeof(sock_addr));
if (ret) {
ESP_LOGI(TAG, "failed\n");
@ -127,7 +127,7 @@ static void openssl_task(void *p)
ESP_LOGI(TAG, "OK");
SSL_set_fd(ssl, socket);
SSL_set_fd(ssl, sockfd);
ESP_LOGI(TAG, "SSL connected to %s port %d ......", OPENSSL_DEMO_TARGET_NAME, OPENSSL_DEMO_TARGET_TCP_PORT);
ret = SSL_connect(ssl);
@ -169,7 +169,7 @@ failed6:
failed5:
failed4:
failed3:
close(socket);
close(sockfd);
failed2:
SSL_CTX_free(ctx);
failed1:

View File

@ -18,6 +18,7 @@
#include "protocol_examples_common.h"
#include "nvs.h"
#include "nvs_flash.h"
#include "tcpip_adapter.h"
#include "lwip/err.h"
#include "lwip/sockets.h"
@ -161,9 +162,10 @@ err:
static int create_multicast_ipv6_socket()
{
struct sockaddr_in6 saddr = { 0 };
int netif_index;
struct in6_addr if_inaddr = { 0 };
struct ip6_addr if_ipaddr = { 0 };
struct ip6_mreq v6imreq = { 0 };
struct ipv6_mreq v6imreq = { 0 };
int sock = -1;
int err = 0;
@ -201,9 +203,14 @@ static int create_multicast_ipv6_socket()
}
#endif
// search for netif index
netif_index = tcpip_adapter_get_netif_index(TCPIP_ADAPTER_IF_STA);
if(netif_index < 0) {
ESP_LOGE(V6TAG, "Failed to get netif index");
goto err;
}
// Assign the multicast source interface, via its IP
err = setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_IF, &if_inaddr,
sizeof(struct in6_addr));
err = setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_IF, &netif_index,sizeof(uint8_t));
if (err < 0) {
ESP_LOGE(V6TAG, "Failed to set IPV6_MULTICAST_IF. Error %d", errno);
goto err;
@ -231,13 +238,6 @@ static int create_multicast_ipv6_socket()
// this is also a listening socket, so add it to the multicast
// group for listening...
// Configure source interface
#if USE_DEFAULT_IF
v6imreq.imr_interface.s_addr = IPADDR_ANY;
#else
inet6_addr_from_ip6addr(&v6imreq.ipv6mr_interface, &if_ipaddr);
#endif
#ifdef CONFIG_EXAMPLE_IPV6
// Configure multicast address to listen to
err = inet6_aton(MULTICAST_IPV6_ADDR, &v6imreq.ipv6mr_multiaddr);
@ -251,9 +251,10 @@ static int create_multicast_ipv6_socket()
if (!ip6_addr_ismulticast(&multi_addr)) {
ESP_LOGW(V6TAG, "Configured IPV6 multicast address '%s' is not a valid multicast address. This will probably not work.", MULTICAST_IPV6_ADDR);
}
// Configure source interface
v6imreq.ipv6mr_interface = (unsigned int)netif_index;
err = setsockopt(sock, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP,
&v6imreq, sizeof(struct ip6_mreq));
&v6imreq, sizeof(struct ipv6_mreq));
if (err < 0) {
ESP_LOGE(V6TAG, "Failed to set IPV6_ADD_MEMBERSHIP. Error %d", errno);
goto err;