From 23e5f7663a5e6f0303914c88d794ad88a7514a05 Mon Sep 17 00:00:00 2001 From: qingying00 <1729719432@qq.com> Date: Tue, 29 Jun 2021 10:30:24 +0000 Subject: [PATCH] update components/net/lwip/origin.patch. --- components/net/lwip/origin.patch | 20961 +++-------------------------- 1 file changed, 1750 insertions(+), 19211 deletions(-) diff --git a/components/net/lwip/origin.patch b/components/net/lwip/origin.patch index 1416144..6e2ef17 100644 --- a/components/net/lwip/origin.patch +++ b/components/net/lwip/origin.patch @@ -1,6 +1,6 @@ diff -Nur a/lwip-2.1.2/src/api/api_lib.c b/lwip-2.1.2/src/api/api_lib.c ---- a/lwip-2.1.2/src/api/api_lib.c 2021-05-08 18:13:52.627621024 +0800 -+++ b/lwip-2.1.2/src/api/api_lib.c 2021-04-27 18:56:55.436353467 +0800 +--- a/lwip-2.1.2/src/api/api_lib.c 2021-06-29 15:16:18.792893320 +0800 ++++ b/lwip-2.1.2/src/api/api_lib.c 2021-06-29 15:16:44.624898723 +0800 @@ -146,7 +146,7 @@ * NULL on memory error */ @@ -93,8 +93,8 @@ diff -Nur a/lwip-2.1.2/src/api/api_lib.c b/lwip-2.1.2/src/api/api_lib.c return err; } diff -Nur a/lwip-2.1.2/src/api/api_msg.c b/lwip-2.1.2/src/api/api_msg.c ---- a/lwip-2.1.2/src/api/api_msg.c 2021-05-08 18:13:52.627621024 +0800 -+++ b/lwip-2.1.2/src/api/api_msg.c 2021-05-12 11:14:00.825620058 +0800 +--- a/lwip-2.1.2/src/api/api_msg.c 2021-06-29 15:16:18.792893320 +0800 ++++ b/lwip-2.1.2/src/api/api_msg.c 2021-06-29 15:16:44.624898723 +0800 @@ -184,10 +184,36 @@ return 0; } @@ -272,11 +272,11 @@ diff -Nur a/lwip-2.1.2/src/api/api_msg.c b/lwip-2.1.2/src/api/api_msg.c case NETCONN_RAW: - err = raw_bind(msg->conn->pcb.raw, API_EXPR_REF(msg->msg.bc.ipaddr)); + msg->err = raw_bind(msg->conn->pcb.raw, API_EXPR_REF(msg->msg.bc.ipaddr)); - break; ++ break; +#if PF_PACKET_SOCKET + case NETCONN_PACKET_RAW: + msg->err = raw_packet_bind(msg->conn->pcb.packet_raw, msg->msg.bc.if_idx, msg->msg.bc.port); -+ break; + break; +#endif #endif /* LWIP_RAW */ #if LWIP_UDP @@ -321,10 +321,11 @@ diff -Nur a/lwip-2.1.2/src/api/api_msg.c b/lwip-2.1.2/src/api/api_msg.c if (msg->conn->pcb.tcp == NULL) { /* This may happen when calling netconn_connect() a second time */ -@@ -1540,11 +1624,43 @@ +@@ -1540,11 +1624,44 @@ #if LWIP_RAW case NETCONN_RAW: if (ip_addr_isany(&msg->msg.b->addr) || IP_IS_ANY_TYPE_VAL(msg->msg.b->addr)) { ++#if PF_PACKET_SOCKET + struct ip_hdr *iphdr = NULL; + ip_addr_t dest_addr; + @@ -346,7 +347,7 @@ diff -Nur a/lwip-2.1.2/src/api/api_msg.c b/lwip-2.1.2/src/api/api_msg.c + err = ERR_NODEST; + break; + } -+ ++#endif /* PF_PACKET_SOCKET */ err = raw_send(msg->conn->pcb.raw, msg->msg.b->p); } else { err = raw_sendto(msg->conn->pcb.raw, msg->msg.b->p, &msg->msg.b->addr); @@ -365,7 +366,7 @@ diff -Nur a/lwip-2.1.2/src/api/api_msg.c b/lwip-2.1.2/src/api/api_msg.c #endif #if LWIP_UDP case NETCONN_UDP: -@@ -1868,6 +1984,11 @@ +@@ -1868,6 +1985,11 @@ { struct api_msg *msg = (struct api_msg *)m; @@ -377,7 +378,7 @@ diff -Nur a/lwip-2.1.2/src/api/api_msg.c b/lwip-2.1.2/src/api/api_msg.c if (msg->conn->pcb.ip != NULL) { if (msg->msg.ad.local) { ip_addr_copy(API_EXPR_DEREF(msg->msg.ad.ipaddr), -@@ -1882,10 +2003,18 @@ +@@ -1882,10 +2004,18 @@ #if LWIP_RAW case NETCONN_RAW: if (msg->msg.ad.local) { @@ -399,7 +400,7 @@ diff -Nur a/lwip-2.1.2/src/api/api_msg.c b/lwip-2.1.2/src/api/api_msg.c } break; #endif /* LWIP_RAW */ -@@ -1923,6 +2052,47 @@ +@@ -1923,6 +2053,47 @@ TCPIP_APIMSG_ACK(msg); } @@ -448,8 +449,8 @@ diff -Nur a/lwip-2.1.2/src/api/api_msg.c b/lwip-2.1.2/src/api/api_msg.c * Close or half-shutdown a TCP pcb contained in a netconn * Called from netconn_close diff -Nur a/lwip-2.1.2/src/api/netbuf.c b/lwip-2.1.2/src/api/netbuf.c ---- a/lwip-2.1.2/src/api/netbuf.c 2021-05-08 18:13:52.627621024 +0800 -+++ b/lwip-2.1.2/src/api/netbuf.c 2021-04-27 18:56:55.436353467 +0800 +--- a/lwip-2.1.2/src/api/netbuf.c 2021-06-29 15:16:18.792893320 +0800 ++++ b/lwip-2.1.2/src/api/netbuf.c 2021-06-29 15:16:44.624898723 +0800 @@ -48,7 +48,7 @@ #include "lwip/netbuf.h" @@ -493,843 +494,63 @@ diff -Nur a/lwip-2.1.2/src/api/netbuf.c b/lwip-2.1.2/src/api/netbuf.c return NULL; } diff -Nur a/lwip-2.1.2/src/api/netdb.c b/lwip-2.1.2/src/api/netdb.c ---- a/lwip-2.1.2/src/api/netdb.c 2021-05-08 18:13:52.627621024 +0800 -+++ b/lwip-2.1.2/src/api/netdb.c 2021-04-27 18:56:55.436353467 +0800 -@@ -1,414 +1,417 @@ --/** -- * @file -- * API functions for name resolving -- * -- * @defgroup netdbapi NETDB API -- * @ingroup socket -- */ -- --/* -- * 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: Simon Goldschmidt -- * -- */ -- --#include "lwip/netdb.h" -- --#if LWIP_DNS && LWIP_SOCKET -- --#include "lwip/err.h" --#include "lwip/mem.h" --#include "lwip/memp.h" --#include "lwip/ip_addr.h" --#include "lwip/api.h" --#include "lwip/dns.h" -- --#include /* memset */ --#include /* atoi */ -- --/** helper struct for gethostbyname_r to access the char* buffer */ --struct gethostbyname_r_helper { -- ip_addr_t *addr_list[2]; -- ip_addr_t addr; -- char *aliases; --}; -- --/** h_errno is exported in netdb.h for access by applications. */ --#if LWIP_DNS_API_DECLARE_H_ERRNO +--- a/lwip-2.1.2/src/api/netdb.c 2021-06-29 15:16:18.796893321 +0800 ++++ b/lwip-2.1.2/src/api/netdb.c 2021-06-29 15:16:44.624898723 +0800 +@@ -58,7 +58,7 @@ + + /** h_errno is exported in netdb.h for access by applications. */ + #if LWIP_DNS_API_DECLARE_H_ERRNO -int h_errno; --#endif /* LWIP_DNS_API_DECLARE_H_ERRNO */ -- --/** define "hostent" variables storage: 0 if we use a static (but unprotected) -- * set of variables for lwip_gethostbyname, 1 if we use a local storage */ --#ifndef LWIP_DNS_API_HOSTENT_STORAGE --#define LWIP_DNS_API_HOSTENT_STORAGE 0 --#endif -- --/** define "hostent" variables storage */ --#if LWIP_DNS_API_HOSTENT_STORAGE --#define HOSTENT_STORAGE --#else --#define HOSTENT_STORAGE static --#endif /* LWIP_DNS_API_STATIC_HOSTENT */ -- --/** -- * Returns an entry containing addresses of address family AF_INET -- * for the host with name name. -- * Due to dns_gethostbyname limitations, only one address is returned. -- * -- * @param name the hostname to resolve -- * @return an entry containing addresses of address family AF_INET -- * for the host with name name -- */ --struct hostent * --lwip_gethostbyname(const char *name) --{ -- err_t err; -- ip_addr_t addr; -- -- /* buffer variables for lwip_gethostbyname() */ -- HOSTENT_STORAGE struct hostent s_hostent; -- HOSTENT_STORAGE char *s_aliases; -- HOSTENT_STORAGE ip_addr_t s_hostent_addr; -- HOSTENT_STORAGE ip_addr_t *s_phostent_addr[2]; -- HOSTENT_STORAGE char s_hostname[DNS_MAX_NAME_LENGTH + 1]; -- -- /* query host IP address */ -- err = netconn_gethostbyname(name, &addr); -- if (err != ERR_OK) { -- LWIP_DEBUGF(DNS_DEBUG, ("lwip_gethostbyname(%s) failed, err=%d\n", name, err)); -- h_errno = HOST_NOT_FOUND; -- return NULL; -- } -- -- /* fill hostent */ -- s_hostent_addr = addr; -- s_phostent_addr[0] = &s_hostent_addr; -- s_phostent_addr[1] = NULL; -- strncpy(s_hostname, name, DNS_MAX_NAME_LENGTH); -- s_hostname[DNS_MAX_NAME_LENGTH] = 0; -- s_hostent.h_name = s_hostname; -- s_aliases = NULL; -- s_hostent.h_aliases = &s_aliases; -- s_hostent.h_addrtype = AF_INET; -- s_hostent.h_length = sizeof(ip_addr_t); -- s_hostent.h_addr_list = (char **)&s_phostent_addr; -- --#if DNS_DEBUG -- /* dump hostent */ -- LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_name == %s\n", s_hostent.h_name)); -- LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_aliases == %p\n", (void *)s_hostent.h_aliases)); -- /* h_aliases are always empty */ -- LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_addrtype == %d\n", s_hostent.h_addrtype)); -- LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_length == %d\n", s_hostent.h_length)); -- LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_addr_list == %p\n", (void *)s_hostent.h_addr_list)); -- if (s_hostent.h_addr_list != NULL) { -- u8_t idx; -- for (idx = 0; s_hostent.h_addr_list[idx]; idx++) { -- LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_addr_list[%i] == %p\n", idx, s_hostent.h_addr_list[idx])); -- LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_addr_list[%i]-> == %s\n", idx, ipaddr_ntoa((ip_addr_t *)s_hostent.h_addr_list[idx]))); -- } -- } --#endif /* DNS_DEBUG */ -- --#if LWIP_DNS_API_HOSTENT_STORAGE -- /* this function should return the "per-thread" hostent after copy from s_hostent */ -- return sys_thread_hostent(&s_hostent); --#else -- return &s_hostent; --#endif /* LWIP_DNS_API_HOSTENT_STORAGE */ --} -- --/** -- * Thread-safe variant of lwip_gethostbyname: instead of using a static -- * buffer, this function takes buffer and errno pointers as arguments -- * and uses these for the result. -- * -- * @param name the hostname to resolve -- * @param ret pre-allocated struct where to store the result -- * @param buf pre-allocated buffer where to store additional data -- * @param buflen the size of buf -- * @param result pointer to a hostent pointer that is set to ret on success -- * and set to zero on error -- * @param h_errnop pointer to an int where to store errors (instead of modifying -- * the global h_errno) -- * @return 0 on success, non-zero on error, additional error information -- * is stored in *h_errnop instead of h_errno to be thread-safe -- */ --int --lwip_gethostbyname_r(const char *name, struct hostent *ret, char *buf, -- size_t buflen, struct hostent **result, int *h_errnop) --{ -- err_t err; -- struct gethostbyname_r_helper *h; -- char *hostname; -- size_t namelen; -- int lh_errno; -- -- if (h_errnop == NULL) { -- /* ensure h_errnop is never NULL */ -- h_errnop = &lh_errno; -- } -- -- if (result == NULL) { -- /* not all arguments given */ -- *h_errnop = EINVAL; -- return -1; -- } -- /* first thing to do: set *result to nothing */ -- *result = NULL; -- if ((name == NULL) || (ret == NULL) || (buf == NULL)) { -- /* not all arguments given */ -- *h_errnop = EINVAL; -- return -1; -- } -- -- namelen = strlen(name); -- if (buflen < (sizeof(struct gethostbyname_r_helper) + LWIP_MEM_ALIGN_BUFFER(namelen + 1))) { -- /* buf can't hold the data needed + a copy of name */ -- *h_errnop = ERANGE; -- return -1; -- } -- -- h = (struct gethostbyname_r_helper *)LWIP_MEM_ALIGN(buf); -- hostname = ((char *)h) + sizeof(struct gethostbyname_r_helper); -- -- /* query host IP address */ -- err = netconn_gethostbyname(name, &h->addr); -- if (err != ERR_OK) { -- LWIP_DEBUGF(DNS_DEBUG, ("lwip_gethostbyname(%s) failed, err=%d\n", name, err)); -- *h_errnop = HOST_NOT_FOUND; -- return -1; -- } -- -- /* copy the hostname into buf */ -- MEMCPY(hostname, name, namelen); -- hostname[namelen] = 0; -- -- /* fill hostent */ -- h->addr_list[0] = &h->addr; -- h->addr_list[1] = NULL; -- h->aliases = NULL; -- ret->h_name = hostname; -- ret->h_aliases = &h->aliases; -- ret->h_addrtype = AF_INET; -- ret->h_length = sizeof(ip_addr_t); -- ret->h_addr_list = (char **)&h->addr_list; -- -- /* set result != NULL */ -- *result = ret; -- -- /* return success */ -- return 0; --} -- --/** -- * Frees one or more addrinfo structures returned by getaddrinfo(), along with -- * any additional storage associated with those structures. If the ai_next field -- * of the structure is not null, the entire list of structures is freed. -- * -- * @param ai struct addrinfo to free -- */ --void --lwip_freeaddrinfo(struct addrinfo *ai) --{ -- struct addrinfo *next; -- -- while (ai != NULL) { -- next = ai->ai_next; -- memp_free(MEMP_NETDB, ai); -- ai = next; -- } --} -- --/** -- * Translates the name of a service location (for example, a host name) and/or -- * a service name and returns a set of socket addresses and associated -- * information to be used in creating a socket with which to address the -- * specified service. -- * Memory for the result is allocated internally and must be freed by calling -- * lwip_freeaddrinfo()! -- * -- * Due to a limitation in dns_gethostbyname, only the first address of a -- * host is returned. -- * Also, service names are not supported (only port numbers)! -- * -- * @param nodename descriptive name or address string of the host -- * (may be NULL -> local address) -- * @param servname port number as string of NULL -- * @param hints structure containing input values that set socktype and protocol -- * @param res pointer to a pointer where to store the result (set to NULL on failure) -- * @return 0 on success, non-zero on failure -- * -- * @todo: implement AI_V4MAPPED, AI_ADDRCONFIG -- */ --int --lwip_getaddrinfo(const char *nodename, const char *servname, -- const struct addrinfo *hints, struct addrinfo **res) --{ -- err_t err; -- ip_addr_t addr; -- struct addrinfo *ai; -- struct sockaddr_storage *sa = NULL; -- int port_nr = 0; -- size_t total_size; -- size_t namelen = 0; -- int ai_family; -- -- if (res == NULL) { -- return EAI_FAIL; -- } -- *res = NULL; -- if ((nodename == NULL) && (servname == NULL)) { -- return EAI_NONAME; -- } -- -- if (hints != NULL) { -- ai_family = hints->ai_family; -- if ((ai_family != AF_UNSPEC) --#if LWIP_IPV4 -- && (ai_family != AF_INET) --#endif /* LWIP_IPV4 */ --#if LWIP_IPV6 -- && (ai_family != AF_INET6) --#endif /* LWIP_IPV6 */ -- ) { -- return EAI_FAMILY; -- } -- } else { -- ai_family = AF_UNSPEC; -- } -- -- if (servname != NULL) { -- /* service name specified: convert to port number -- * @todo?: currently, only ASCII integers (port numbers) are supported (AI_NUMERICSERV)! */ -- port_nr = atoi(servname); -- if ((port_nr <= 0) || (port_nr > 0xffff)) { -- return EAI_SERVICE; -- } -- } -- -- if (nodename != NULL) { -- /* service location specified, try to resolve */ -- if ((hints != NULL) && (hints->ai_flags & AI_NUMERICHOST)) { -- /* no DNS lookup, just parse for an address string */ -- if (!ipaddr_aton(nodename, &addr)) { -- return EAI_NONAME; -- } --#if LWIP_IPV4 && LWIP_IPV6 -- if ((IP_IS_V6_VAL(addr) && ai_family == AF_INET) || -- (IP_IS_V4_VAL(addr) && ai_family == AF_INET6)) { -- return EAI_NONAME; -- } --#endif /* LWIP_IPV4 && LWIP_IPV6 */ -- } else { --#if LWIP_IPV4 && LWIP_IPV6 -- /* AF_UNSPEC: prefer IPv4 */ -- u8_t type = NETCONN_DNS_IPV4_IPV6; -- if (ai_family == AF_INET) { -- type = NETCONN_DNS_IPV4; -- } else if (ai_family == AF_INET6) { -- type = NETCONN_DNS_IPV6; -- } --#endif /* LWIP_IPV4 && LWIP_IPV6 */ -- err = netconn_gethostbyname_addrtype(nodename, &addr, type); -- if (err != ERR_OK) { -- return EAI_FAIL; -- } -- } -- } else { -- /* service location specified, use loopback address */ -- if ((hints != NULL) && (hints->ai_flags & AI_PASSIVE)) { -- ip_addr_set_any_val(ai_family == AF_INET6, addr); -- } else { -- ip_addr_set_loopback_val(ai_family == AF_INET6, addr); -- } -- } -- -- total_size = sizeof(struct addrinfo) + sizeof(struct sockaddr_storage); -- if (nodename != NULL) { -- namelen = strlen(nodename); -- if (namelen > DNS_MAX_NAME_LENGTH) { -- /* invalid name length */ -- return EAI_FAIL; -- } -- LWIP_ASSERT("namelen is too long", total_size + namelen + 1 > total_size); -- total_size += namelen + 1; -- } -- /* If this fails, please report to lwip-devel! :-) */ -- LWIP_ASSERT("total_size <= NETDB_ELEM_SIZE: please report this!", -- total_size <= NETDB_ELEM_SIZE); -- ai = (struct addrinfo *)memp_malloc(MEMP_NETDB); -- if (ai == NULL) { -- return EAI_MEMORY; -- } -- memset(ai, 0, total_size); -- /* cast through void* to get rid of alignment warnings */ -- sa = (struct sockaddr_storage *)(void *)((u8_t *)ai + sizeof(struct addrinfo)); -- if (IP_IS_V6_VAL(addr)) { --#if LWIP_IPV6 -- struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *)sa; -- /* set up sockaddr */ -- inet6_addr_from_ip6addr(&sa6->sin6_addr, ip_2_ip6(&addr)); -- sa6->sin6_family = AF_INET6; -- sa6->sin6_len = sizeof(struct sockaddr_in6); -- sa6->sin6_port = lwip_htons((u16_t)port_nr); -- sa6->sin6_scope_id = ip6_addr_zone(ip_2_ip6(&addr)); -- ai->ai_family = AF_INET6; --#endif /* LWIP_IPV6 */ -- } else { --#if LWIP_IPV4 -- struct sockaddr_in *sa4 = (struct sockaddr_in *)sa; -- /* set up sockaddr */ -- inet_addr_from_ip4addr(&sa4->sin_addr, ip_2_ip4(&addr)); -- sa4->sin_family = AF_INET; -- sa4->sin_len = sizeof(struct sockaddr_in); -- sa4->sin_port = lwip_htons((u16_t)port_nr); -- ai->ai_family = AF_INET; --#endif /* LWIP_IPV4 */ -- } -- -- /* set up addrinfo */ -- if (hints != NULL) { -- /* copy socktype & protocol from hints if specified */ -- ai->ai_socktype = hints->ai_socktype; -- ai->ai_protocol = hints->ai_protocol; -- } -- if (nodename != NULL) { -- /* copy nodename to canonname if specified */ -- ai->ai_canonname = ((char *)ai + sizeof(struct addrinfo) + sizeof(struct sockaddr_storage)); -- MEMCPY(ai->ai_canonname, nodename, namelen); -- ai->ai_canonname[namelen] = 0; -- } -- ai->ai_addrlen = sizeof(struct sockaddr_storage); -- ai->ai_addr = (struct sockaddr *)sa; -- -- *res = ai; -- -- return 0; --} -- --#endif /* LWIP_DNS && LWIP_SOCKET */ -+/** -+ * @file -+ * API functions for name resolving -+ * -+ * @defgroup netdbapi NETDB API -+ * @ingroup socket -+ */ -+ -+/* -+ * 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: Simon Goldschmidt -+ * -+ */ -+ -+#include "lwip/netdb.h" -+ -+#if LWIP_DNS && LWIP_SOCKET -+ -+#include "lwip/err.h" -+#include "lwip/mem.h" -+#include "lwip/memp.h" -+#include "lwip/ip_addr.h" -+#include "lwip/api.h" -+#include "lwip/dns.h" -+ -+#include /* memset */ -+#include /* atoi */ -+ -+/** helper struct for gethostbyname_r to access the char* buffer */ -+struct gethostbyname_r_helper { -+ ip_addr_t *addr_list[2]; -+ ip_addr_t addr; -+ char *aliases; -+}; -+ -+/** h_errno is exported in netdb.h for access by applications. */ -+#if LWIP_DNS_API_DECLARE_H_ERRNO +int h_err_no; -+#endif /* LWIP_DNS_API_DECLARE_H_ERRNO */ -+ -+/** define "hostent" variables storage: 0 if we use a static (but unprotected) -+ * set of variables for lwip_gethostbyname, 1 if we use a local storage */ -+#ifndef LWIP_DNS_API_HOSTENT_STORAGE -+#define LWIP_DNS_API_HOSTENT_STORAGE 0 -+#endif -+ -+/** define "hostent" variables storage */ -+#if LWIP_DNS_API_HOSTENT_STORAGE -+#define HOSTENT_STORAGE -+#else -+#define HOSTENT_STORAGE static -+#endif /* LWIP_DNS_API_STATIC_HOSTENT */ -+ -+/** -+ * Returns an entry containing addresses of address family AF_INET -+ * for the host with name name. -+ * Due to dns_gethostbyname limitations, only one address is returned. -+ * -+ * @param name the hostname to resolve -+ * @return an entry containing addresses of address family AF_INET -+ * for the host with name name -+ */ -+struct hostent * -+lwip_gethostbyname(const char *name) -+{ -+ err_t err; -+ ip_addr_t addr; -+ -+ /* buffer variables for lwip_gethostbyname() */ -+ HOSTENT_STORAGE struct hostent s_hostent; -+ HOSTENT_STORAGE char *s_aliases; -+ HOSTENT_STORAGE ip_addr_t s_hostent_addr; -+ HOSTENT_STORAGE ip_addr_t *s_phostent_addr[2]; -+ HOSTENT_STORAGE char s_hostname[DNS_MAX_NAME_LENGTH + 1]; -+ -+ /* query host IP address */ -+ err = netconn_gethostbyname(name, &addr); -+ if (err != ERR_OK) { -+ LWIP_DEBUGF(DNS_DEBUG, ("lwip_gethostbyname(%s) failed, err=%d\n", name, err)); + #endif /* LWIP_DNS_API_DECLARE_H_ERRNO */ + + /** define "hostent" variables storage: 0 if we use a static (but unprotected) +@@ -100,7 +100,7 @@ + err = netconn_gethostbyname(name, &addr); + if (err != ERR_OK) { + LWIP_DEBUGF(DNS_DEBUG, ("lwip_gethostbyname(%s) failed, err=%d\n", name, err)); +- h_errno = HOST_NOT_FOUND; + h_err_no = HOST_NOT_FOUND; -+ return NULL; -+ } -+ -+ /* fill hostent */ -+ s_hostent_addr = addr; -+ s_phostent_addr[0] = &s_hostent_addr; -+ s_phostent_addr[1] = NULL; -+ strncpy(s_hostname, name, DNS_MAX_NAME_LENGTH); -+ s_hostname[DNS_MAX_NAME_LENGTH] = 0; -+ s_hostent.h_name = s_hostname; -+ s_aliases = NULL; -+ s_hostent.h_aliases = &s_aliases; -+ s_hostent.h_addrtype = AF_INET; -+ s_hostent.h_length = sizeof(ip_addr_t); -+ s_hostent.h_addr_list = (char **)&s_phostent_addr; -+ -+#if DNS_DEBUG -+ /* dump hostent */ -+ LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_name == %s\n", s_hostent.h_name)); -+ LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_aliases == %p\n", (void *)s_hostent.h_aliases)); -+ /* h_aliases are always empty */ -+ LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_addrtype == %d\n", s_hostent.h_addrtype)); -+ LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_length == %d\n", s_hostent.h_length)); -+ LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_addr_list == %p\n", (void *)s_hostent.h_addr_list)); -+ if (s_hostent.h_addr_list != NULL) { -+ u8_t idx; -+ for (idx = 0; s_hostent.h_addr_list[idx]; idx++) { -+ LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_addr_list[%i] == %p\n", idx, s_hostent.h_addr_list[idx])); -+ LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_addr_list[%i]-> == %s\n", idx, ipaddr_ntoa((ip_addr_t *)s_hostent.h_addr_list[idx]))); -+ } -+ } -+#endif /* DNS_DEBUG */ -+ -+#if LWIP_DNS_API_HOSTENT_STORAGE -+ /* this function should return the "per-thread" hostent after copy from s_hostent */ -+ return sys_thread_hostent(&s_hostent); -+#else -+ return &s_hostent; -+#endif /* LWIP_DNS_API_HOSTENT_STORAGE */ -+} -+ -+/** -+ * Thread-safe variant of lwip_gethostbyname: instead of using a static -+ * buffer, this function takes buffer and errno pointers as arguments -+ * and uses these for the result. -+ * -+ * @param name the hostname to resolve -+ * @param ret pre-allocated struct where to store the result -+ * @param buf pre-allocated buffer where to store additional data -+ * @param buflen the size of buf -+ * @param result pointer to a hostent pointer that is set to ret on success -+ * and set to zero on error -+ * @param h_errnop pointer to an int where to store errors (instead of modifying -+ * the global h_errno) -+ * @return 0 on success, non-zero on error, additional error information -+ * is stored in *h_errnop instead of h_errno to be thread-safe -+ */ -+int -+lwip_gethostbyname_r(const char *name, struct hostent *ret, char *buf, -+ size_t buflen, struct hostent **result, int *h_errnop) -+{ -+ err_t err; -+ struct gethostbyname_r_helper *h; -+ char *hostname; -+ size_t namelen; -+ int lh_errno; -+ -+ if (h_errnop == NULL) { -+ /* ensure h_errnop is never NULL */ -+ h_errnop = &lh_errno; -+ } -+ -+ if (result == NULL) { -+ /* not all arguments given */ -+ *h_errnop = EINVAL; -+ return -1; -+ } -+ /* first thing to do: set *result to nothing */ -+ *result = NULL; -+ if ((name == NULL) || (ret == NULL) || (buf == NULL)) { -+ /* not all arguments given */ -+ *h_errnop = EINVAL; -+ return -1; -+ } -+ -+ namelen = strlen(name); -+ if (buflen < (sizeof(struct gethostbyname_r_helper) + LWIP_MEM_ALIGN_BUFFER(namelen + 1))) { -+ /* buf can't hold the data needed + a copy of name */ -+ *h_errnop = ERANGE; -+ return -1; -+ } -+ -+ h = (struct gethostbyname_r_helper *)LWIP_MEM_ALIGN(buf); -+ hostname = ((char *)h) + sizeof(struct gethostbyname_r_helper); -+ -+ /* query host IP address */ -+ err = netconn_gethostbyname(name, &h->addr); -+ if (err != ERR_OK) { -+ LWIP_DEBUGF(DNS_DEBUG, ("lwip_gethostbyname(%s) failed, err=%d\n", name, err)); -+ *h_errnop = HOST_NOT_FOUND; -+ return -1; -+ } -+ -+ /* copy the hostname into buf */ -+ MEMCPY(hostname, name, namelen); -+ hostname[namelen] = 0; -+ -+ /* fill hostent */ -+ h->addr_list[0] = &h->addr; -+ h->addr_list[1] = NULL; -+ h->aliases = NULL; -+ ret->h_name = hostname; -+ ret->h_aliases = &h->aliases; -+ ret->h_addrtype = AF_INET; -+ ret->h_length = sizeof(ip_addr_t); -+ ret->h_addr_list = (char **)&h->addr_list; -+ -+ /* set result != NULL */ -+ *result = ret; -+ -+ /* return success */ -+ return 0; -+} -+ -+/** -+ * Frees one or more addrinfo structures returned by getaddrinfo(), along with -+ * any additional storage associated with those structures. If the ai_next field -+ * of the structure is not null, the entire list of structures is freed. -+ * -+ * @param ai struct addrinfo to free -+ */ -+void -+lwip_freeaddrinfo(struct addrinfo *ai) -+{ -+ struct addrinfo *next; -+ -+ while (ai != NULL) { -+ next = ai->ai_next; -+ memp_free(MEMP_NETDB, ai); -+ ai = next; -+ } -+} -+ -+/** -+ * Translates the name of a service location (for example, a host name) and/or -+ * a service name and returns a set of socket addresses and associated -+ * information to be used in creating a socket with which to address the -+ * specified service. -+ * Memory for the result is allocated internally and must be freed by calling -+ * lwip_freeaddrinfo()! -+ * -+ * Due to a limitation in dns_gethostbyname, only the first address of a -+ * host is returned. -+ * Also, service names are not supported (only port numbers)! -+ * -+ * @param nodename descriptive name or address string of the host -+ * (may be NULL -> local address) -+ * @param servname port number as string of NULL -+ * @param hints structure containing input values that set socktype and protocol -+ * @param res pointer to a pointer where to store the result (set to NULL on failure) -+ * @return 0 on success, non-zero on failure -+ * -+ * @todo: implement AI_V4MAPPED, AI_ADDRCONFIG -+ */ -+int -+lwip_getaddrinfo(const char *nodename, const char *servname, -+ const struct addrinfo *hints, struct addrinfo **res) -+{ -+ err_t err; -+ ip_addr_t addr; -+ struct addrinfo *ai; -+ struct sockaddr_storage *sa = NULL; -+ int port_nr = 0; -+ size_t total_size; -+ size_t namelen = 0; -+ int ai_family; -+ -+ if (res == NULL) { -+ return EAI_FAIL; -+ } -+ *res = NULL; -+ if ((nodename == NULL) && (servname == NULL)) { -+ return EAI_NONAME; -+ } -+ -+ if (hints != NULL) { -+ ai_family = hints->ai_family; -+ if ((ai_family != AF_UNSPEC) -+#if LWIP_IPV4 -+ && (ai_family != AF_INET) -+#endif /* LWIP_IPV4 */ -+#if LWIP_IPV6 -+ && (ai_family != AF_INET6) -+#endif /* LWIP_IPV6 */ -+ ) { -+ return EAI_FAMILY; -+ } -+ } else { -+ ai_family = AF_UNSPEC; -+ } -+ -+ if (servname != NULL) { -+ /* service name specified: convert to port number -+ * @todo?: currently, only ASCII integers (port numbers) are supported (AI_NUMERICSERV)! */ -+ port_nr = atoi(servname); -+ if ((port_nr <= 0) || (port_nr > 0xffff)) { -+ return EAI_SERVICE; -+ } -+ } -+ -+ if (nodename != NULL) { -+ /* service location specified, try to resolve */ -+ if ((hints != NULL) && (hints->ai_flags & AI_NUMERICHOST)) { -+ /* no DNS lookup, just parse for an address string */ -+ if (!ipaddr_aton(nodename, &addr)) { -+ return EAI_NONAME; -+ } -+#if LWIP_IPV4 && LWIP_IPV6 -+ if ((IP_IS_V6_VAL(addr) && ai_family == AF_INET) || -+ (IP_IS_V4_VAL(addr) && ai_family == AF_INET6)) { -+ return EAI_NONAME; -+ } -+#endif /* LWIP_IPV4 && LWIP_IPV6 */ -+ } else { -+#if LWIP_IPV4 && LWIP_IPV6 -+ /* AF_UNSPEC: prefer IPv4 */ -+ u8_t type = NETCONN_DNS_IPV4_IPV6; -+ if (ai_family == AF_INET) { -+ type = NETCONN_DNS_IPV4; -+ } else if (ai_family == AF_INET6) { -+ type = NETCONN_DNS_IPV6; -+ } -+#endif /* LWIP_IPV4 && LWIP_IPV6 */ -+ err = netconn_gethostbyname_addrtype(nodename, &addr, type); -+ if (err != ERR_OK) { -+ return EAI_FAIL; -+ } -+ } -+ } else { -+ /* service location specified, use loopback address */ -+ if ((hints != NULL) && (hints->ai_flags & AI_PASSIVE)) { -+ ip_addr_set_any_val(ai_family == AF_INET6, addr); -+ } else { -+ ip_addr_set_loopback_val(ai_family == AF_INET6, addr); -+ } -+ } -+ -+ total_size = sizeof(struct addrinfo) + sizeof(struct sockaddr_storage); -+ if (nodename != NULL) { -+ namelen = strlen(nodename); -+ if (namelen > DNS_MAX_NAME_LENGTH) { -+ /* invalid name length */ -+ return EAI_FAIL; -+ } -+ LWIP_ASSERT("namelen is too long", total_size + namelen + 1 > total_size); -+ total_size += namelen + 1; -+ } -+ /* If this fails, please report to lwip-devel! :-) */ -+ LWIP_ASSERT("total_size <= NETDB_ELEM_SIZE: please report this!", -+ total_size <= NETDB_ELEM_SIZE); -+ ai = (struct addrinfo *)memp_malloc(MEMP_NETDB); -+ if (ai == NULL) { -+ return EAI_MEMORY; -+ } -+ memset(ai, 0, total_size); -+ /* cast through void* to get rid of alignment warnings */ -+ sa = (struct sockaddr_storage *)(void *)((u8_t *)ai + sizeof(struct addrinfo)); -+ if (IP_IS_V6_VAL(addr)) { -+#if LWIP_IPV6 -+ struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *)sa; -+ /* set up sockaddr */ -+ inet6_addr_from_ip6addr(&sa6->sin6_addr, ip_2_ip6(&addr)); -+ sa6->sin6_family = AF_INET6; + return NULL; + } + +@@ -374,10 +374,14 @@ + /* set up sockaddr */ + inet6_addr_from_ip6addr(&sa6->sin6_addr, ip_2_ip6(&addr)); + sa6->sin6_family = AF_INET6; +#if defined(SIN6_LEN) -+ sa6->sin6_len = sizeof(struct sockaddr_in6); + sa6->sin6_len = sizeof(struct sockaddr_in6); +#endif + sa6->sin6_flowinfo = 0; -+ sa6->sin6_port = lwip_htons((u16_t)port_nr); -+ sa6->sin6_scope_id = ip6_addr_zone(ip_2_ip6(&addr)); -+ ai->ai_family = AF_INET6; + sa6->sin6_port = lwip_htons((u16_t)port_nr); + sa6->sin6_scope_id = ip6_addr_zone(ip_2_ip6(&addr)); + ai->ai_family = AF_INET6; + ai->ai_addrlen = sizeof(struct sockaddr_in6); -+#endif /* LWIP_IPV6 */ -+ } else { -+#if LWIP_IPV4 -+ struct sockaddr_in *sa4 = (struct sockaddr_in *)sa; -+ /* set up sockaddr */ -+ inet_addr_from_ip4addr(&sa4->sin_addr, ip_2_ip4(&addr)); -+ sa4->sin_family = AF_INET; -+ sa4->sin_port = lwip_htons((u16_t)port_nr); -+ ai->ai_family = AF_INET; + #endif /* LWIP_IPV6 */ + } else { + #if LWIP_IPV4 +@@ -385,9 +389,9 @@ + /* set up sockaddr */ + inet_addr_from_ip4addr(&sa4->sin_addr, ip_2_ip4(&addr)); + sa4->sin_family = AF_INET; +- sa4->sin_len = sizeof(struct sockaddr_in); + sa4->sin_port = lwip_htons((u16_t)port_nr); + ai->ai_family = AF_INET; + ai->ai_addrlen = sizeof(struct sockaddr_in); -+#endif /* LWIP_IPV4 */ -+ } -+ -+ /* set up addrinfo */ -+ if (hints != NULL) { -+ /* copy socktype & protocol from hints if specified */ -+ ai->ai_socktype = hints->ai_socktype; -+ ai->ai_protocol = hints->ai_protocol; -+ } -+ if (nodename != NULL) { -+ /* copy nodename to canonname if specified */ -+ ai->ai_canonname = ((char *)ai + sizeof(struct addrinfo) + sizeof(struct sockaddr_storage)); -+ MEMCPY(ai->ai_canonname, nodename, namelen); -+ ai->ai_canonname[namelen] = 0; -+ } -+ ai->ai_addr = (struct sockaddr *)sa; -+ -+ *res = ai; -+ -+ return 0; -+} -+ -+#endif /* LWIP_DNS && LWIP_SOCKET */ + #endif /* LWIP_IPV4 */ + } + +@@ -403,7 +407,6 @@ + MEMCPY(ai->ai_canonname, nodename, namelen); + ai->ai_canonname[namelen] = 0; + } +- ai->ai_addrlen = sizeof(struct sockaddr_storage); + ai->ai_addr = (struct sockaddr *)sa; + + *res = ai; diff -Nur a/lwip-2.1.2/src/api/netifapi.c b/lwip-2.1.2/src/api/netifapi.c ---- a/lwip-2.1.2/src/api/netifapi.c 2021-05-08 18:13:52.627621024 +0800 -+++ b/lwip-2.1.2/src/api/netifapi.c 2021-04-27 18:56:55.436353467 +0800 +--- a/lwip-2.1.2/src/api/netifapi.c 2021-06-29 15:16:18.796893321 +0800 ++++ b/lwip-2.1.2/src/api/netifapi.c 2021-06-29 15:16:44.624898723 +0800 @@ -54,6 +54,21 @@ #define NETIFAPI_VAR_ALLOC(name) API_VAR_ALLOC(struct netifapi_msg, MEMP_NETIFAPI_MSG, name, ERR_MEM) #define NETIFAPI_VAR_FREE(name) API_VAR_FREE(MEMP_NETIFAPI_MSG, name) @@ -1436,738 +657,151 @@ diff -Nur a/lwip-2.1.2/src/api/netifapi.c b/lwip-2.1.2/src/api/netifapi.c +} #endif /* LWIP_NETIF_API */ diff -Nur a/lwip-2.1.2/src/api/sockets.c b/lwip-2.1.2/src/api/sockets.c ---- a/lwip-2.1.2/src/api/sockets.c 2021-05-08 18:13:52.627621024 +0800 -+++ b/lwip-2.1.2/src/api/sockets.c 2021-05-12 11:47:42.725008681 +0800 -@@ -1,4160 +1,4849 @@ --/** -- * @file -- * Sockets BSD-Like API module -- */ -- --/* -- * 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 -- * -- * Improved by Marc Boucher and David Haas -- * -- */ -- --#include "lwip/opt.h" -- --#if LWIP_SOCKET /* don't build if not configured for use in lwipopts.h */ -- --#include "lwip/sockets.h" --#include "lwip/priv/sockets_priv.h" --#include "lwip/api.h" --#include "lwip/igmp.h" --#include "lwip/inet.h" --#include "lwip/tcp.h" --#include "lwip/raw.h" --#include "lwip/udp.h" --#include "lwip/memp.h" --#include "lwip/pbuf.h" --#include "lwip/netif.h" --#include "lwip/priv/tcpip_priv.h" --#include "lwip/mld6.h" --#if LWIP_CHECKSUM_ON_COPY --#include "lwip/inet_chksum.h" --#endif -- --#if LWIP_COMPAT_SOCKETS == 2 && LWIP_POSIX_SOCKETS_IO_NAMES --#include --#endif -- --#include -- --#ifdef LWIP_HOOK_FILENAME --#include LWIP_HOOK_FILENAME --#endif -- --/* If the netconn API is not required publicly, then we include the necessary -- files here to get the implementation */ --#if !LWIP_NETCONN --#undef LWIP_NETCONN --#define LWIP_NETCONN 1 --#include "api_msg.c" --#include "api_lib.c" --#include "netbuf.c" --#undef LWIP_NETCONN --#define LWIP_NETCONN 0 --#endif -- --#define API_SELECT_CB_VAR_REF(name) API_VAR_REF(name) --#define API_SELECT_CB_VAR_DECLARE(name) API_VAR_DECLARE(struct lwip_select_cb, name) --#define API_SELECT_CB_VAR_ALLOC(name, retblock) API_VAR_ALLOC_EXT(struct lwip_select_cb, MEMP_SELECT_CB, name, retblock) --#define API_SELECT_CB_VAR_FREE(name) API_VAR_FREE(MEMP_SELECT_CB, name) -- --#if LWIP_IPV4 --#define IP4ADDR_PORT_TO_SOCKADDR(sin, ipaddr, port) do { \ -- (sin)->sin_len = sizeof(struct sockaddr_in); \ -- (sin)->sin_family = AF_INET; \ -- (sin)->sin_port = lwip_htons((port)); \ -- inet_addr_from_ip4addr(&(sin)->sin_addr, ipaddr); \ -- memset((sin)->sin_zero, 0, SIN_ZERO_LEN); }while(0) --#define SOCKADDR4_TO_IP4ADDR_PORT(sin, ipaddr, port) do { \ -- inet_addr_to_ip4addr(ip_2_ip4(ipaddr), &((sin)->sin_addr)); \ -- (port) = lwip_ntohs((sin)->sin_port); }while(0) --#endif /* LWIP_IPV4 */ -- --#if LWIP_IPV6 --#define IP6ADDR_PORT_TO_SOCKADDR(sin6, ipaddr, port) do { \ -- (sin6)->sin6_len = sizeof(struct sockaddr_in6); \ -- (sin6)->sin6_family = AF_INET6; \ -- (sin6)->sin6_port = lwip_htons((port)); \ -- (sin6)->sin6_flowinfo = 0; \ -- inet6_addr_from_ip6addr(&(sin6)->sin6_addr, ipaddr); \ -- (sin6)->sin6_scope_id = ip6_addr_zone(ipaddr); }while(0) --#define SOCKADDR6_TO_IP6ADDR_PORT(sin6, ipaddr, port) do { \ -- inet6_addr_to_ip6addr(ip_2_ip6(ipaddr), &((sin6)->sin6_addr)); \ -- if (ip6_addr_has_scope(ip_2_ip6(ipaddr), IP6_UNKNOWN)) { \ -- ip6_addr_set_zone(ip_2_ip6(ipaddr), (u8_t)((sin6)->sin6_scope_id)); \ -- } \ -- (port) = lwip_ntohs((sin6)->sin6_port); }while(0) --#endif /* LWIP_IPV6 */ -- --#if LWIP_IPV4 && LWIP_IPV6 --static void sockaddr_to_ipaddr_port(const struct sockaddr *sockaddr, ip_addr_t *ipaddr, u16_t *port); -- --#define IS_SOCK_ADDR_LEN_VALID(namelen) (((namelen) == sizeof(struct sockaddr_in)) || \ -- ((namelen) == sizeof(struct sockaddr_in6))) --#define IS_SOCK_ADDR_TYPE_VALID(name) (((name)->sa_family == AF_INET) || \ -- ((name)->sa_family == AF_INET6)) --#define SOCK_ADDR_TYPE_MATCH(name, sock) \ -- ((((name)->sa_family == AF_INET) && !(NETCONNTYPE_ISIPV6((sock)->conn->type))) || \ -- (((name)->sa_family == AF_INET6) && (NETCONNTYPE_ISIPV6((sock)->conn->type)))) --#define IPADDR_PORT_TO_SOCKADDR(sockaddr, ipaddr, port) do { \ -- if (IP_IS_ANY_TYPE_VAL(*ipaddr) || IP_IS_V6_VAL(*ipaddr)) { \ -- IP6ADDR_PORT_TO_SOCKADDR((struct sockaddr_in6*)(void*)(sockaddr), ip_2_ip6(ipaddr), port); \ -- } else { \ -- IP4ADDR_PORT_TO_SOCKADDR((struct sockaddr_in*)(void*)(sockaddr), ip_2_ip4(ipaddr), port); \ -- } } while(0) --#define SOCKADDR_TO_IPADDR_PORT(sockaddr, ipaddr, port) sockaddr_to_ipaddr_port(sockaddr, ipaddr, &(port)) --#define DOMAIN_TO_NETCONN_TYPE(domain, type) (((domain) == AF_INET) ? \ -- (type) : (enum netconn_type)((type) | NETCONN_TYPE_IPV6)) --#elif LWIP_IPV6 /* LWIP_IPV4 && LWIP_IPV6 */ --#define IS_SOCK_ADDR_LEN_VALID(namelen) ((namelen) == sizeof(struct sockaddr_in6)) --#define IS_SOCK_ADDR_TYPE_VALID(name) ((name)->sa_family == AF_INET6) --#define SOCK_ADDR_TYPE_MATCH(name, sock) 1 --#define IPADDR_PORT_TO_SOCKADDR(sockaddr, ipaddr, port) \ -- IP6ADDR_PORT_TO_SOCKADDR((struct sockaddr_in6*)(void*)(sockaddr), ip_2_ip6(ipaddr), port) --#define SOCKADDR_TO_IPADDR_PORT(sockaddr, ipaddr, port) \ -- SOCKADDR6_TO_IP6ADDR_PORT((const struct sockaddr_in6*)(const void*)(sockaddr), ipaddr, port) --#define DOMAIN_TO_NETCONN_TYPE(domain, netconn_type) (netconn_type) --#else /*-> LWIP_IPV4: LWIP_IPV4 && LWIP_IPV6 */ --#define IS_SOCK_ADDR_LEN_VALID(namelen) ((namelen) == sizeof(struct sockaddr_in)) --#define IS_SOCK_ADDR_TYPE_VALID(name) ((name)->sa_family == AF_INET) --#define SOCK_ADDR_TYPE_MATCH(name, sock) 1 --#define IPADDR_PORT_TO_SOCKADDR(sockaddr, ipaddr, port) \ -- IP4ADDR_PORT_TO_SOCKADDR((struct sockaddr_in*)(void*)(sockaddr), ip_2_ip4(ipaddr), port) --#define SOCKADDR_TO_IPADDR_PORT(sockaddr, ipaddr, port) \ -- SOCKADDR4_TO_IP4ADDR_PORT((const struct sockaddr_in*)(const void*)(sockaddr), ipaddr, port) --#define DOMAIN_TO_NETCONN_TYPE(domain, netconn_type) (netconn_type) --#endif /* LWIP_IPV6 */ -- --#define IS_SOCK_ADDR_TYPE_VALID_OR_UNSPEC(name) (((name)->sa_family == AF_UNSPEC) || \ -- IS_SOCK_ADDR_TYPE_VALID(name)) --#define SOCK_ADDR_TYPE_MATCH_OR_UNSPEC(name, sock) (((name)->sa_family == AF_UNSPEC) || \ -- SOCK_ADDR_TYPE_MATCH(name, sock)) --#define IS_SOCK_ADDR_ALIGNED(name) ((((mem_ptr_t)(name)) % 4) == 0) -- -- --#define LWIP_SOCKOPT_CHECK_OPTLEN(sock, optlen, opttype) do { if ((optlen) < sizeof(opttype)) { done_socket(sock); return EINVAL; }}while(0) --#define LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, optlen, opttype) do { \ -- LWIP_SOCKOPT_CHECK_OPTLEN(sock, optlen, opttype); \ -- if ((sock)->conn == NULL) { done_socket(sock); return EINVAL; } }while(0) --#define LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, optlen, opttype) do { \ -- LWIP_SOCKOPT_CHECK_OPTLEN(sock, optlen, opttype); \ -- if (((sock)->conn == NULL) || ((sock)->conn->pcb.tcp == NULL)) { done_socket(sock); return EINVAL; } }while(0) --#define LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, opttype, netconntype) do { \ -- LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, optlen, opttype); \ -- if (NETCONNTYPE_GROUP(netconn_type((sock)->conn)) != netconntype) { done_socket(sock); return ENOPROTOOPT; } }while(0) -- -- --#define LWIP_SETGETSOCKOPT_DATA_VAR_REF(name) API_VAR_REF(name) --#define LWIP_SETGETSOCKOPT_DATA_VAR_DECLARE(name) API_VAR_DECLARE(struct lwip_setgetsockopt_data, name) --#define LWIP_SETGETSOCKOPT_DATA_VAR_FREE(name) API_VAR_FREE(MEMP_SOCKET_SETGETSOCKOPT_DATA, name) --#if LWIP_MPU_COMPATIBLE --#define LWIP_SETGETSOCKOPT_DATA_VAR_ALLOC(name, sock) do { \ -- name = (struct lwip_setgetsockopt_data *)memp_malloc(MEMP_SOCKET_SETGETSOCKOPT_DATA); \ -- if (name == NULL) { \ -- sock_set_errno(sock, ENOMEM); \ -- done_socket(sock); \ -- return -1; \ -- } }while(0) --#else /* LWIP_MPU_COMPATIBLE */ --#define LWIP_SETGETSOCKOPT_DATA_VAR_ALLOC(name, sock) --#endif /* LWIP_MPU_COMPATIBLE */ -- --#if LWIP_SO_SNDRCVTIMEO_NONSTANDARD --#define LWIP_SO_SNDRCVTIMEO_OPTTYPE int --#define LWIP_SO_SNDRCVTIMEO_SET(optval, val) (*(int *)(optval) = (val)) --#define LWIP_SO_SNDRCVTIMEO_GET_MS(optval) ((long)*(const int*)(optval)) --#else --#define LWIP_SO_SNDRCVTIMEO_OPTTYPE struct timeval --#define LWIP_SO_SNDRCVTIMEO_SET(optval, val) do { \ -- u32_t loc = (val); \ -- ((struct timeval *)(optval))->tv_sec = (long)((loc) / 1000U); \ -- ((struct timeval *)(optval))->tv_usec = (long)(((loc) % 1000U) * 1000U); }while(0) --#define LWIP_SO_SNDRCVTIMEO_GET_MS(optval) ((((const struct timeval *)(optval))->tv_sec * 1000) + (((const struct timeval *)(optval))->tv_usec / 1000)) --#endif -- -- --/** A struct sockaddr replacement that has the same alignment as sockaddr_in/ -- * sockaddr_in6 if instantiated. -- */ --union sockaddr_aligned { -- struct sockaddr sa; --#if LWIP_IPV6 -- struct sockaddr_in6 sin6; --#endif /* LWIP_IPV6 */ --#if LWIP_IPV4 -- struct sockaddr_in sin; --#endif /* LWIP_IPV4 */ --}; -- --/* Define the number of IPv4 multicast memberships, default is one per socket */ --#ifndef LWIP_SOCKET_MAX_MEMBERSHIPS --#define LWIP_SOCKET_MAX_MEMBERSHIPS NUM_SOCKETS --#endif -- --#if LWIP_IGMP --/* This is to keep track of IP_ADD_MEMBERSHIP calls to drop the membership when -- a socket is closed */ --struct lwip_socket_multicast_pair { -- /** the socket */ -- struct lwip_sock *sock; -- /** the interface address */ -- ip4_addr_t if_addr; -- /** the group address */ -- ip4_addr_t multi_addr; --}; -- --static struct lwip_socket_multicast_pair socket_ipv4_multicast_memberships[LWIP_SOCKET_MAX_MEMBERSHIPS]; -- --static int lwip_socket_register_membership(int s, const ip4_addr_t *if_addr, const ip4_addr_t *multi_addr); --static void lwip_socket_unregister_membership(int s, const ip4_addr_t *if_addr, const ip4_addr_t *multi_addr); --static void lwip_socket_drop_registered_memberships(int s); --#endif /* LWIP_IGMP */ -- --#if LWIP_IPV6_MLD --/* This is to keep track of IP_JOIN_GROUP calls to drop the membership when -- a socket is closed */ --struct lwip_socket_multicast_mld6_pair { -- /** the socket */ -- struct lwip_sock *sock; -- /** the interface index */ -- u8_t if_idx; -- /** the group address */ -- ip6_addr_t multi_addr; --}; -- --static struct lwip_socket_multicast_mld6_pair socket_ipv6_multicast_memberships[LWIP_SOCKET_MAX_MEMBERSHIPS]; -- --static int lwip_socket_register_mld6_membership(int s, unsigned int if_idx, const ip6_addr_t *multi_addr); --static void lwip_socket_unregister_mld6_membership(int s, unsigned int if_idx, const ip6_addr_t *multi_addr); --static void lwip_socket_drop_registered_mld6_memberships(int s); --#endif /* LWIP_IPV6_MLD */ -- --/** The global array of available sockets */ --static struct lwip_sock sockets[NUM_SOCKETS]; -- --#if LWIP_SOCKET_SELECT || LWIP_SOCKET_POLL --#if LWIP_TCPIP_CORE_LOCKING --/* protect the select_cb_list using core lock */ --#define LWIP_SOCKET_SELECT_DECL_PROTECT(lev) --#define LWIP_SOCKET_SELECT_PROTECT(lev) LOCK_TCPIP_CORE() --#define LWIP_SOCKET_SELECT_UNPROTECT(lev) UNLOCK_TCPIP_CORE() --#else /* LWIP_TCPIP_CORE_LOCKING */ --/* protect the select_cb_list using SYS_LIGHTWEIGHT_PROT */ --#define LWIP_SOCKET_SELECT_DECL_PROTECT(lev) SYS_ARCH_DECL_PROTECT(lev) --#define LWIP_SOCKET_SELECT_PROTECT(lev) SYS_ARCH_PROTECT(lev) --#define LWIP_SOCKET_SELECT_UNPROTECT(lev) SYS_ARCH_UNPROTECT(lev) --/** This counter is increased from lwip_select when the list is changed -- and checked in select_check_waiters to see if it has changed. */ --static volatile int select_cb_ctr; --#endif /* LWIP_TCPIP_CORE_LOCKING */ --/** The global list of tasks waiting for select */ --static struct lwip_select_cb *select_cb_list; --#endif /* LWIP_SOCKET_SELECT || LWIP_SOCKET_POLL */ -- --#define sock_set_errno(sk, e) do { \ -- const int sockerr = (e); \ -- set_errno(sockerr); \ --} while (0) -- --/* Forward declaration of some functions */ --#if LWIP_SOCKET_SELECT || LWIP_SOCKET_POLL --static void event_callback(struct netconn *conn, enum netconn_evt evt, u16_t len); --#define DEFAULT_SOCKET_EVENTCB event_callback --static void select_check_waiters(int s, int has_recvevent, int has_sendevent, int has_errevent); --#else --#define DEFAULT_SOCKET_EVENTCB NULL --#endif --#if !LWIP_TCPIP_CORE_LOCKING --static void lwip_getsockopt_callback(void *arg); --static void lwip_setsockopt_callback(void *arg); --#endif --static int lwip_getsockopt_impl(int s, int level, int optname, void *optval, socklen_t *optlen); --static int lwip_setsockopt_impl(int s, int level, int optname, const void *optval, socklen_t optlen); --static int free_socket_locked(struct lwip_sock *sock, int is_tcp, struct netconn **conn, -- union lwip_sock_lastdata *lastdata); --static void free_socket_free_elements(int is_tcp, struct netconn *conn, union lwip_sock_lastdata *lastdata); -- --#if LWIP_IPV4 && LWIP_IPV6 --static void --sockaddr_to_ipaddr_port(const struct sockaddr *sockaddr, ip_addr_t *ipaddr, u16_t *port) --{ -- if ((sockaddr->sa_family) == AF_INET6) { -- SOCKADDR6_TO_IP6ADDR_PORT((const struct sockaddr_in6 *)(const void *)(sockaddr), ipaddr, *port); -- ipaddr->type = IPADDR_TYPE_V6; -- } else { -- SOCKADDR4_TO_IP4ADDR_PORT((const struct sockaddr_in *)(const void *)(sockaddr), ipaddr, *port); -- ipaddr->type = IPADDR_TYPE_V4; -- } --} --#endif /* LWIP_IPV4 && LWIP_IPV6 */ -- --/** LWIP_NETCONN_SEM_PER_THREAD==1: initialize thread-local semaphore */ --void --lwip_socket_thread_init(void) --{ -- netconn_thread_init(); --} -- --/** LWIP_NETCONN_SEM_PER_THREAD==1: destroy thread-local semaphore */ --void --lwip_socket_thread_cleanup(void) --{ -- netconn_thread_cleanup(); --} -- --#if LWIP_NETCONN_FULLDUPLEX --/* Thread-safe increment of sock->fd_used, with overflow check */ --static int --sock_inc_used(struct lwip_sock *sock) --{ -- int ret; -- SYS_ARCH_DECL_PROTECT(lev); -- -- LWIP_ASSERT("sock != NULL", sock != NULL); -- -- SYS_ARCH_PROTECT(lev); -- if (sock->fd_free_pending) { -- /* prevent new usage of this socket if free is pending */ -- ret = 0; -- } else { -- ++sock->fd_used; -- ret = 1; -- LWIP_ASSERT("sock->fd_used != 0", sock->fd_used != 0); -- } -- SYS_ARCH_UNPROTECT(lev); -- return ret; --} -- --/* Like sock_inc_used(), but called under SYS_ARCH_PROTECT lock. */ --static int --sock_inc_used_locked(struct lwip_sock *sock) --{ -- LWIP_ASSERT("sock != NULL", sock != NULL); -- -- if (sock->fd_free_pending) { -- LWIP_ASSERT("sock->fd_used != 0", sock->fd_used != 0); -- return 0; -- } -- -- ++sock->fd_used; -- LWIP_ASSERT("sock->fd_used != 0", sock->fd_used != 0); -- return 1; --} -- --/* In full-duplex mode,sock->fd_used != 0 prevents a socket descriptor from being -- * released (and possibly reused) when used from more than one thread -- * (e.g. read-while-write or close-while-write, etc) -- * This function is called at the end of functions using (try)get_socket*(). -- */ --static void --done_socket(struct lwip_sock *sock) --{ -- int freed = 0; -- int is_tcp = 0; -- struct netconn *conn = NULL; -- union lwip_sock_lastdata lastdata; -- SYS_ARCH_DECL_PROTECT(lev); -- LWIP_ASSERT("sock != NULL", sock != NULL); -- -- SYS_ARCH_PROTECT(lev); -- LWIP_ASSERT("sock->fd_used > 0", sock->fd_used > 0); -- if (--sock->fd_used == 0) { -- if (sock->fd_free_pending) { -- /* free the socket */ -- sock->fd_used = 1; -- is_tcp = sock->fd_free_pending & LWIP_SOCK_FD_FREE_TCP; -- freed = free_socket_locked(sock, is_tcp, &conn, &lastdata); -- } -- } -- SYS_ARCH_UNPROTECT(lev); -- -- if (freed) { -- free_socket_free_elements(is_tcp, conn, &lastdata); -- } --} -- --#else /* LWIP_NETCONN_FULLDUPLEX */ --#define sock_inc_used(sock) 1 --#define sock_inc_used_locked(sock) 1 --#define done_socket(sock) --#endif /* LWIP_NETCONN_FULLDUPLEX */ -- --/* Translate a socket 'int' into a pointer (only fails if the index is invalid) */ --static struct lwip_sock * --tryget_socket_unconn_nouse(int fd) --{ -- int s = fd - LWIP_SOCKET_OFFSET; -- if ((s < 0) || (s >= NUM_SOCKETS)) { -- LWIP_DEBUGF(SOCKETS_DEBUG, ("tryget_socket_unconn(%d): invalid\n", fd)); -- return NULL; -- } -- return &sockets[s]; --} -- --struct lwip_sock * --lwip_socket_dbg_get_socket(int fd) --{ -- return tryget_socket_unconn_nouse(fd); --} -- --/* Translate a socket 'int' into a pointer (only fails if the index is invalid) */ --static struct lwip_sock * --tryget_socket_unconn(int fd) --{ -- struct lwip_sock *ret = tryget_socket_unconn_nouse(fd); -- if (ret != NULL) { -- if (!sock_inc_used(ret)) { -- return NULL; -- } -- } -- return ret; --} -- --/* Like tryget_socket_unconn(), but called under SYS_ARCH_PROTECT lock. */ --static struct lwip_sock * --tryget_socket_unconn_locked(int fd) --{ -- struct lwip_sock *ret = tryget_socket_unconn_nouse(fd); -- if (ret != NULL) { -- if (!sock_inc_used_locked(ret)) { -- return NULL; -- } -- } -- return ret; --} -- --/** -- * Same as get_socket but doesn't set errno -- * -- * @param fd externally used socket index -- * @return struct lwip_sock for the socket or NULL if not found -- */ --static struct lwip_sock * --tryget_socket(int fd) --{ -- struct lwip_sock *sock = tryget_socket_unconn(fd); -- if (sock != NULL) { -- if (sock->conn) { -- return sock; -- } -- done_socket(sock); -- } -- return NULL; --} -- --/** -- * Map a externally used socket index to the internal socket representation. -- * -- * @param fd externally used socket index -- * @return struct lwip_sock for the socket or NULL if not found -- */ --static struct lwip_sock * --get_socket(int fd) --{ -- struct lwip_sock *sock = tryget_socket(fd); -- if (!sock) { -- if ((fd < LWIP_SOCKET_OFFSET) || (fd >= (LWIP_SOCKET_OFFSET + NUM_SOCKETS))) { -- LWIP_DEBUGF(SOCKETS_DEBUG, ("get_socket(%d): invalid\n", fd)); -- } -- set_errno(EBADF); -- return NULL; -- } -- return sock; --} -- --/** -- * Allocate a new socket for a given netconn. -- * -- * @param newconn the netconn for which to allocate a socket -- * @param accepted 1 if socket has been created by accept(), -- * 0 if socket has been created by socket() -- * @return the index of the new socket; -1 on error -- */ --static int --alloc_socket(struct netconn *newconn, int accepted) --{ -- int i; -- SYS_ARCH_DECL_PROTECT(lev); -- LWIP_UNUSED_ARG(accepted); -- -- /* allocate a new socket identifier */ -- for (i = 0; i < NUM_SOCKETS; ++i) { -- /* Protect socket array */ -- SYS_ARCH_PROTECT(lev); -- if (!sockets[i].conn) { --#if LWIP_NETCONN_FULLDUPLEX -- if (sockets[i].fd_used) { -- SYS_ARCH_UNPROTECT(lev); -- continue; -- } -- sockets[i].fd_used = 1; -- sockets[i].fd_free_pending = 0; --#endif -- sockets[i].conn = newconn; -- /* The socket is not yet known to anyone, so no need to protect -- after having marked it as used. */ -- SYS_ARCH_UNPROTECT(lev); -- sockets[i].lastdata.pbuf = NULL; --#if LWIP_SOCKET_SELECT || LWIP_SOCKET_POLL -- LWIP_ASSERT("sockets[i].select_waiting == 0", sockets[i].select_waiting == 0); -- sockets[i].rcvevent = 0; -- /* TCP sendbuf is empty, but the socket is not yet writable until connected -- * (unless it has been created by accept()). */ -- sockets[i].sendevent = (NETCONNTYPE_GROUP(newconn->type) == NETCONN_TCP ? (accepted != 0) : 1); -- sockets[i].errevent = 0; --#endif /* LWIP_SOCKET_SELECT || LWIP_SOCKET_POLL */ -- return i + LWIP_SOCKET_OFFSET; -- } -- SYS_ARCH_UNPROTECT(lev); -- } -- return -1; --} -- --/** Free a socket (under lock) -- * -- * @param sock the socket to free -- * @param is_tcp != 0 for TCP sockets, used to free lastdata -- * @param conn the socekt's netconn is stored here, must be freed externally -- * @param lastdata lastdata is stored here, must be freed externally -- */ --static int --free_socket_locked(struct lwip_sock *sock, int is_tcp, struct netconn **conn, -- union lwip_sock_lastdata *lastdata) --{ --#if LWIP_NETCONN_FULLDUPLEX -- LWIP_ASSERT("sock->fd_used > 0", sock->fd_used > 0); -- sock->fd_used--; -- if (sock->fd_used > 0) { -- sock->fd_free_pending = LWIP_SOCK_FD_FREE_FREE | (is_tcp ? LWIP_SOCK_FD_FREE_TCP : 0); -- return 0; -- } --#else /* LWIP_NETCONN_FULLDUPLEX */ -- LWIP_UNUSED_ARG(is_tcp); --#endif /* LWIP_NETCONN_FULLDUPLEX */ -- -- *lastdata = sock->lastdata; -- sock->lastdata.pbuf = NULL; -- *conn = sock->conn; -- sock->conn = NULL; -- return 1; --} -- --/** Free a socket's leftover members. -- */ --static void --free_socket_free_elements(int is_tcp, struct netconn *conn, union lwip_sock_lastdata *lastdata) --{ -- if (lastdata->pbuf != NULL) { -- if (is_tcp) { -- pbuf_free(lastdata->pbuf); -- } else { -- netbuf_delete(lastdata->netbuf); -- } -- } -- if (conn != NULL) { -- /* netconn_prepare_delete() has already been called, here we only free the conn */ -- netconn_delete(conn); -- } --} -- --/** Free a socket. The socket's netconn must have been -- * delete before! -- * -- * @param sock the socket to free -- * @param is_tcp != 0 for TCP sockets, used to free lastdata -- */ --static void --free_socket(struct lwip_sock *sock, int is_tcp) --{ -- int freed; -- struct netconn *conn; -- union lwip_sock_lastdata lastdata; -- SYS_ARCH_DECL_PROTECT(lev); -- -- /* Protect socket array */ -- SYS_ARCH_PROTECT(lev); -- -- freed = free_socket_locked(sock, is_tcp, &conn, &lastdata); -- SYS_ARCH_UNPROTECT(lev); -- /* don't use 'sock' after this line, as another task might have allocated it */ -- -- if (freed) { -- free_socket_free_elements(is_tcp, conn, &lastdata); -- } --} -- --/* Below this, the well-known socket functions are implemented. -- * Use google.com or opengroup.org to get a good description :-) -- * -- * Exceptions are documented! -- */ -- --int --lwip_accept(int s, struct sockaddr *addr, socklen_t *addrlen) --{ -- struct lwip_sock *sock, *nsock; -- struct netconn *newconn; -- ip_addr_t naddr; -- u16_t port = 0; -- int newsock; -- err_t err; -- int recvevent; -- SYS_ARCH_DECL_PROTECT(lev); -- -- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d)...\n", s)); -- sock = get_socket(s); -- if (!sock) { -- return -1; -- } -- -- /* wait for a new connection */ -- err = netconn_accept(sock->conn, &newconn); -- if (err != ERR_OK) { -- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d): netconn_acept failed, err=%d\n", s, err)); -- if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_TCP) { -- sock_set_errno(sock, EOPNOTSUPP); -- } else if (err == ERR_CLSD) { -- sock_set_errno(sock, EINVAL); -- } else { -- sock_set_errno(sock, err_to_errno(err)); -- } -- done_socket(sock); -- return -1; -- } -- LWIP_ASSERT("newconn != NULL", newconn != NULL); -- -- newsock = alloc_socket(newconn, 1); -- if (newsock == -1) { -- netconn_delete(newconn); -- sock_set_errno(sock, ENFILE); -- done_socket(sock); -- return -1; -- } -- LWIP_ASSERT("invalid socket index", (newsock >= LWIP_SOCKET_OFFSET) && (newsock < NUM_SOCKETS + LWIP_SOCKET_OFFSET)); -- nsock = &sockets[newsock - LWIP_SOCKET_OFFSET]; -- -- /* See event_callback: If data comes in right away after an accept, even -- * though the server task might not have created a new socket yet. -- * In that case, newconn->socket is counted down (newconn->socket--), -- * so nsock->rcvevent is >= 1 here! -- */ -- SYS_ARCH_PROTECT(lev); -- recvevent = (s16_t)(-1 - newconn->socket); -- newconn->socket = newsock; -- SYS_ARCH_UNPROTECT(lev); -- -- if (newconn->callback) { -- LOCK_TCPIP_CORE(); -- while (recvevent > 0) { -- recvevent--; -- newconn->callback(newconn, NETCONN_EVT_RCVPLUS, 0); -- } -- UNLOCK_TCPIP_CORE(); -- } -- -- /* Note that POSIX only requires us to check addr is non-NULL. addrlen must -- * not be NULL if addr is valid. -- */ -- if ((addr != NULL) && (addrlen != NULL)) { -- union sockaddr_aligned tempaddr; -- /* get the IP address and port of the remote host */ -- err = netconn_peer(newconn, &naddr, &port); -- if (err != ERR_OK) { -- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d): netconn_peer failed, err=%d\n", s, err)); -- netconn_delete(newconn); -- free_socket(nsock, 1); -- sock_set_errno(sock, err_to_errno(err)); -- done_socket(sock); -- return -1; -- } -- -- IPADDR_PORT_TO_SOCKADDR(&tempaddr, &naddr, port); +--- a/lwip-2.1.2/src/api/sockets.c 2021-06-29 15:16:18.796893321 +0800 ++++ b/lwip-2.1.2/src/api/sockets.c 2021-06-29 15:16:44.624898723 +0800 +@@ -54,6 +54,7 @@ + #include "lwip/netif.h" + #include "lwip/priv/tcpip_priv.h" + #include "lwip/mld6.h" ++#include "lwip/dhcp.h" + #if LWIP_CHECKSUM_ON_COPY + #include "lwip/inet_chksum.h" + #endif +@@ -85,9 +86,19 @@ + #define API_SELECT_CB_VAR_ALLOC(name, retblock) API_VAR_ALLOC_EXT(struct lwip_select_cb, MEMP_SELECT_CB, name, retblock) + #define API_SELECT_CB_VAR_FREE(name) API_VAR_FREE(MEMP_SELECT_CB, name) + ++#if !LWIP_LITEOS_COMPAT ++#defeine SIN4_LEN(x) \ ++ (x)->sin_len = sizeof(struct sockaddr_in) ++#defeine SIN6_LEN(x) \ ++ (x)->sin6_len = sizeof(struct sockaddr_in6) ++#else ++#define SIN4_LEN(x) ++#define SIN6_LEN(x) ++#endif /* LWIP_LITEOS_COMPAT */ ++ + #if LWIP_IPV4 + #define IP4ADDR_PORT_TO_SOCKADDR(sin, ipaddr, port) do { \ +- (sin)->sin_len = sizeof(struct sockaddr_in); \ ++ SIN4_LEN(sin); \ + (sin)->sin_family = AF_INET; \ + (sin)->sin_port = lwip_htons((port)); \ + inet_addr_from_ip4addr(&(sin)->sin_addr, ipaddr); \ +@@ -98,8 +109,10 @@ + #endif /* LWIP_IPV4 */ + + #if LWIP_IPV6 ++/* SIN6_LEN macro is to differntiate whether stack is using 4.3BSD or 4.4BSD variants of sockaddr_in6 ++structure */ + #define IP6ADDR_PORT_TO_SOCKADDR(sin6, ipaddr, port) do { \ +- (sin6)->sin6_len = sizeof(struct sockaddr_in6); \ ++ SIN6_LEN(sin6); \ + (sin6)->sin6_family = AF_INET6; \ + (sin6)->sin6_port = lwip_htons((port)); \ + (sin6)->sin6_flowinfo = 0; \ +@@ -283,6 +296,45 @@ + set_errno(sockerr); \ + } while (0) + ++#if LWIP_LITEOS_COMPAT ++#define VALIDATE_GET_RAW_OPTNAME_RET(_sock, _optname) do { \ ++ if ((_sock)->conn != NULL && (NETCONNTYPE_GROUP((_sock)->conn->type) == NETCONN_RAW) && \ ++ (((_optname) != SO_BROADCAST) && ((_optname) != SO_RCVTIMEO) && \ ++ ((_optname) != SO_RCVBUF) && ((_optname) != SO_TYPE) && \ ++ ((_optname) != SO_DONTROUTE) && ((_optname) != SO_BINDTODEVICE))) { \ ++ done_socket(_sock); \ ++ return ENOPROTOOPT; \ ++ } \ ++ } while (0) ++ ++#if PF_PACKET_SOCKET ++#define VALIDATE_SET_PF_PKT_OPTNAME_RET(_s, _sock, _level, _optname) do { \ ++ if ((_level) == SOL_PACKET && ((_optname) != SO_RCVTIMEO && (_optname) != SO_RCVBUF) && \ ++ (_optname) != SO_ATTACH_FILTER && (_optname) != SO_DETACH_FILTER) { \ ++ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, SOL_PACKET, UNIMPL: optname=0x%x, ..)\n", \ ++ (_s), (_optname))); \ ++ done_socket(_sock); \ ++ return ENOPROTOOPT; \ ++ } \ ++ } while (0) ++ ++#define VALIDATE_GET_PF_PKT_OPTNAME_RET(_s,_sock,_level,_optname) do { \ ++ if ((_sock)->conn != NULL && (NETCONNTYPE_GROUP((_sock)->conn->type) == NETCONN_PACKET_RAW) && \ ++ (_level) == SOL_PACKET && ((_optname) != SO_RCVTIMEO && (_optname) != SO_RCVBUF && (_optname) != SO_TYPE)) { \ ++ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%p, SOL_PACKET, UNIMPL: optname=0x%x, ..)\n", \ ++ (_s), (_optname))); \ ++ done_socket(_sock); \ ++ return ENOPROTOOPT; \ ++ } \ ++ } while (0) ++ ++#define VALIDATE_LEVEL_PF_PACKET(_sock,_level) \ ++ if ((_sock)->conn != NULL && ((NETCONNTYPE_GROUP(netconn_type(_sock->conn)) == NETCONN_PACKET_RAW \ ++ && SOL_SOCKET != (_level) && SOL_PACKET != (_level)) || \ ++ (NETCONNTYPE_GROUP((_sock)->conn->type) != NETCONN_PACKET_RAW && SOL_PACKET == (_level)))) ++#endif ++#endif /* LWIP_LITEOS_COMPAT */ ++ + /* Forward declaration of some functions */ + #if LWIP_SOCKET_SELECT || LWIP_SOCKET_POLL + static void event_callback(struct netconn *conn, enum netconn_evt evt, u16_t len); +@@ -489,6 +541,29 @@ + return sock; + } + ++#if LWIP_LITEOS_COMPAT ++/* get numbers of unused sockets */ ++int get_unused_socket_num(void) ++{ ++ int unused = 0, i; ++ SYS_ARCH_DECL_PROTECT(lev); ++ SYS_ARCH_PROTECT(lev); ++ ++ for (i = 0; i < (int)(NUM_SOCKETS); i++) { ++ if (!sockets[i].conn ++#if LWIP_NETCONN_FULLDUPLEX ++ && !sockets[i].fd_used ++#endif ++ ) { ++ unused++; ++ } ++ } ++ ++ SYS_ARCH_UNPROTECT(lev); ++ return unused; ++} ++#endif /* LWIP_LITEOS_COMPAT */ ++ + /** + * Allocate a new socket for a given netconn. + * +@@ -696,8 +771,10 @@ + } + + IPADDR_PORT_TO_SOCKADDR(&tempaddr, &naddr, port); - if (*addrlen > tempaddr.sa.sa_len) { - *addrlen = tempaddr.sa.sa_len; -- } -- MEMCPY(addr, &tempaddr, *addrlen); -- -- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d) returning new sock=%d addr=", s, newsock)); -- ip_addr_debug_print_val(SOCKETS_DEBUG, naddr); -- LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F"\n", port)); -- } else { -- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d) returning new sock=%d", s, newsock)); -- } -- -- sock_set_errno(sock, 0); -- done_socket(sock); -- done_socket(nsock); -- return newsock; --} -- --int --lwip_bind(int s, const struct sockaddr *name, socklen_t namelen) --{ -- struct lwip_sock *sock; -- ip_addr_t local_addr; -- u16_t local_port; -- err_t err; -- -- sock = get_socket(s); -- if (!sock) { -- return -1; -- } -- ++ if (IP_IS_V4_VAL(naddr) && (*addrlen > (int)sizeof(struct sockaddr_in))) { ++ *addrlen = sizeof(struct sockaddr_in); ++ } else if (IP_IS_V6_VAL(naddr) && (*addrlen > (int)sizeof(struct sockaddr_in6))) { ++ *addrlen = sizeof(struct sockaddr_in6); + } + MEMCPY(addr, &tempaddr, *addrlen); + +@@ -722,28 +799,58 @@ + u16_t local_port; + err_t err; + ++#if PF_PACKET_SOCKET ++ const struct sockaddr_ll *name_ll = NULL; ++ u8_t local_if_idx = 0; ++#endif + sock = get_socket(s); + if (!sock) { + return -1; + } + - if (!SOCK_ADDR_TYPE_MATCH(name, sock)) { - /* sockaddr does not match socket type (IPv4/IPv6) */ - sock_set_errno(sock, err_to_errno(ERR_VAL)); @@ -2175,14124 +809,1236 @@ diff -Nur a/lwip-2.1.2/src/api/sockets.c b/lwip-2.1.2/src/api/sockets.c - return -1; - } - -- /* check size, family and alignment of 'name' */ + /* check size, family and alignment of 'name' */ - LWIP_ERROR("lwip_bind: invalid address", (IS_SOCK_ADDR_LEN_VALID(namelen) && -- IS_SOCK_ADDR_TYPE_VALID(name) && IS_SOCK_ADDR_ALIGNED(name)), -- sock_set_errno(sock, err_to_errno(ERR_ARG)); done_socket(sock); return -1;); -- LWIP_UNUSED_ARG(namelen); -- -- SOCKADDR_TO_IPADDR_PORT(name, &local_addr, local_port); -- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d, addr=", s)); -- ip_addr_debug_print_val(SOCKETS_DEBUG, local_addr); -- LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F")\n", local_port)); -- --#if LWIP_IPV4 && LWIP_IPV6 -- /* Dual-stack: Unmap IPv4 mapped IPv6 addresses */ -- if (IP_IS_V6_VAL(local_addr) && ip6_addr_isipv4mappedipv6(ip_2_ip6(&local_addr))) { -- unmap_ipv4_mapped_ipv6(ip_2_ip4(&local_addr), ip_2_ip6(&local_addr)); -- IP_SET_TYPE_VAL(local_addr, IPADDR_TYPE_V4); -- } --#endif /* LWIP_IPV4 && LWIP_IPV6 */ -- -- err = netconn_bind(sock->conn, &local_addr, local_port); -- -- if (err != ERR_OK) { -- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d) failed, err=%d\n", s, err)); -- sock_set_errno(sock, err_to_errno(err)); -- done_socket(sock); -- return -1; -- } -- -- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d) succeeded\n", s)); -- sock_set_errno(sock, 0); -- done_socket(sock); -- return 0; --} -- --int --lwip_close(int s) --{ -- struct lwip_sock *sock; -- int is_tcp = 0; -- err_t err; -- -- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_close(%d)\n", s)); -- -- sock = get_socket(s); -- if (!sock) { -- return -1; -- } -- -- if (sock->conn != NULL) { -- is_tcp = NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP; -- } else { -- LWIP_ASSERT("sock->lastdata == NULL", sock->lastdata.pbuf == NULL); -- } -- --#if LWIP_IGMP -- /* drop all possibly joined IGMP memberships */ -- lwip_socket_drop_registered_memberships(s); --#endif /* LWIP_IGMP */ --#if LWIP_IPV6_MLD -- /* drop all possibly joined MLD6 memberships */ -- lwip_socket_drop_registered_mld6_memberships(s); --#endif /* LWIP_IPV6_MLD */ -- -- err = netconn_prepare_delete(sock->conn); -- if (err != ERR_OK) { -- sock_set_errno(sock, err_to_errno(err)); -- done_socket(sock); -- return -1; -- } -- -- free_socket(sock, is_tcp); -- set_errno(0); -- return 0; --} -- --int --lwip_connect(int s, const struct sockaddr *name, socklen_t namelen) --{ -- struct lwip_sock *sock; -- err_t err; -- -- sock = get_socket(s); -- if (!sock) { -- return -1; -- } -- -- if (!SOCK_ADDR_TYPE_MATCH_OR_UNSPEC(name, sock)) { -- /* sockaddr does not match socket type (IPv4/IPv6) */ -- sock_set_errno(sock, err_to_errno(ERR_VAL)); -- done_socket(sock); -- return -1; -- } -- -- LWIP_UNUSED_ARG(namelen); -- if (name->sa_family == AF_UNSPEC) { -- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d, AF_UNSPEC)\n", s)); -- err = netconn_disconnect(sock->conn); -- } else { -- ip_addr_t remote_addr; -- u16_t remote_port; -- -- /* check size, family and alignment of 'name' */ -- LWIP_ERROR("lwip_connect: invalid address", IS_SOCK_ADDR_LEN_VALID(namelen) && -- IS_SOCK_ADDR_TYPE_VALID_OR_UNSPEC(name) && IS_SOCK_ADDR_ALIGNED(name), -- sock_set_errno(sock, err_to_errno(ERR_ARG)); done_socket(sock); return -1;); -- -- SOCKADDR_TO_IPADDR_PORT(name, &remote_addr, remote_port); -- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d, addr=", s)); -- ip_addr_debug_print_val(SOCKETS_DEBUG, remote_addr); -- LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F")\n", remote_port)); -- --#if LWIP_IPV4 && LWIP_IPV6 -- /* Dual-stack: Unmap IPv4 mapped IPv6 addresses */ -- if (IP_IS_V6_VAL(remote_addr) && ip6_addr_isipv4mappedipv6(ip_2_ip6(&remote_addr))) { -- unmap_ipv4_mapped_ipv6(ip_2_ip4(&remote_addr), ip_2_ip6(&remote_addr)); -- IP_SET_TYPE_VAL(remote_addr, IPADDR_TYPE_V4); -- } --#endif /* LWIP_IPV4 && LWIP_IPV6 */ -- -- err = netconn_connect(sock->conn, &remote_addr, remote_port); -- } -- -- if (err != ERR_OK) { -- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d) failed, err=%d\n", s, err)); -- sock_set_errno(sock, err_to_errno(err)); -- done_socket(sock); -- return -1; -- } -- -- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d) succeeded\n", s)); -- sock_set_errno(sock, 0); -- done_socket(sock); -- return 0; --} -- --/** -- * Set a socket into listen mode. -- * The socket may not have been used for another connection previously. -- * -- * @param s the socket to set to listening mode -- * @param backlog (ATTENTION: needs TCP_LISTEN_BACKLOG=1) -- * @return 0 on success, non-zero on failure -- */ --int --lwip_listen(int s, int backlog) --{ -- struct lwip_sock *sock; -- err_t err; -- -- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_listen(%d, backlog=%d)\n", s, backlog)); -- -- sock = get_socket(s); -- if (!sock) { -- return -1; -- } -- -- /* limit the "backlog" parameter to fit in an u8_t */ -- backlog = LWIP_MIN(LWIP_MAX(backlog, 0), 0xff); -- -- err = netconn_listen_with_backlog(sock->conn, (u8_t)backlog); -- -- if (err != ERR_OK) { -- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_listen(%d) failed, err=%d\n", s, err)); -- if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_TCP) { -- sock_set_errno(sock, EOPNOTSUPP); -- } else { -- sock_set_errno(sock, err_to_errno(err)); -- } -- done_socket(sock); -- return -1; -- } -- -- sock_set_errno(sock, 0); -- done_socket(sock); -- return 0; --} -- --#if LWIP_TCP --/* Helper function to loop over receiving pbufs from netconn -- * until "len" bytes are received or we're otherwise done. -- * Keeps sock->lastdata for peeking or partly copying. -- */ --static ssize_t --lwip_recv_tcp(struct lwip_sock *sock, void *mem, size_t len, int flags) --{ -- u8_t apiflags = NETCONN_NOAUTORCVD; -- ssize_t recvd = 0; -- ssize_t recv_left = (len <= SSIZE_MAX) ? (ssize_t)len : SSIZE_MAX; -- -- LWIP_ASSERT("no socket given", sock != NULL); -- LWIP_ASSERT("this should be checked internally", NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP); -- -- if (flags & MSG_DONTWAIT) { -- apiflags |= NETCONN_DONTBLOCK; -- } -- -- do { -- struct pbuf *p; -- err_t err; -- u16_t copylen; -- -- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recv_tcp: top while sock->lastdata=%p\n", (void *)sock->lastdata.pbuf)); -- /* Check if there is data left from the last recv operation. */ -- if (sock->lastdata.pbuf) { -- p = sock->lastdata.pbuf; -- } else { -- /* No data was left from the previous operation, so we try to get -- some from the network. */ -- err = netconn_recv_tcp_pbuf_flags(sock->conn, &p, apiflags); -- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recv_tcp: netconn_recv err=%d, pbuf=%p\n", -- err, (void *)p)); -- -- if (err != ERR_OK) { -- if (recvd > 0) { -- /* already received data, return that (this trusts in getting the same error from -- netconn layer again next time netconn_recv is called) */ -- goto lwip_recv_tcp_done; -- } -- /* We should really do some error checking here. */ -- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recv_tcp: p == NULL, error is \"%s\"!\n", -- lwip_strerr(err))); -- sock_set_errno(sock, err_to_errno(err)); -- if (err == ERR_CLSD) { -- return 0; -- } else { -- return -1; -- } -- } -- LWIP_ASSERT("p != NULL", p != NULL); -- sock->lastdata.pbuf = p; -- } -- -- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recv_tcp: buflen=%"U16_F" recv_left=%d off=%d\n", -- p->tot_len, (int)recv_left, (int)recvd)); -- -- if (recv_left > p->tot_len) { -- copylen = p->tot_len; -- } else { -- copylen = (u16_t)recv_left; -- } -- if (recvd + copylen < recvd) { -- /* overflow */ -- copylen = (u16_t)(SSIZE_MAX - recvd); -- } -- -- /* copy the contents of the received buffer into -- the supplied memory pointer mem */ -- pbuf_copy_partial(p, (u8_t *)mem + recvd, copylen, 0); -- -- recvd += copylen; -- -- /* TCP combines multiple pbufs for one recv */ -- LWIP_ASSERT("invalid copylen, len would underflow", recv_left >= copylen); -- recv_left -= copylen; -- -- /* Unless we peek the incoming message... */ -- if ((flags & MSG_PEEK) == 0) { -- /* ... check if there is data left in the pbuf */ -- LWIP_ASSERT("invalid copylen", p->tot_len >= copylen); -- if (p->tot_len - copylen > 0) { -- /* If so, it should be saved in the sock structure for the next recv call. -- We store the pbuf but hide/free the consumed data: */ -- sock->lastdata.pbuf = pbuf_free_header(p, copylen); -- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recv_tcp: lastdata now pbuf=%p\n", (void *)sock->lastdata.pbuf)); -- } else { -- sock->lastdata.pbuf = NULL; -- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recv_tcp: deleting pbuf=%p\n", (void *)p)); -- pbuf_free(p); -- } -- } -- /* once we have some data to return, only add more if we don't need to wait */ -- apiflags |= NETCONN_DONTBLOCK | NETCONN_NOFIN; -- /* @todo: do we need to support peeking more than one pbuf? */ -- } while ((recv_left > 0) && !(flags & MSG_PEEK)); --lwip_recv_tcp_done: -- if ((recvd > 0) && !(flags & MSG_PEEK)) { -- /* ensure window update after copying all data */ -- netconn_tcp_recvd(sock->conn, (size_t)recvd); -- } -- sock_set_errno(sock, 0); -- return recvd; --} --#endif -- --/* Convert a netbuf's address data to struct sockaddr */ --static int --lwip_sock_make_addr(struct netconn *conn, ip_addr_t *fromaddr, u16_t port, -- struct sockaddr *from, socklen_t *fromlen) --{ -- int truncated = 0; -- union sockaddr_aligned saddr; -- -- LWIP_UNUSED_ARG(conn); -- -- LWIP_ASSERT("fromaddr != NULL", fromaddr != NULL); -- LWIP_ASSERT("from != NULL", from != NULL); -- LWIP_ASSERT("fromlen != NULL", fromlen != NULL); -- --#if LWIP_IPV4 && LWIP_IPV6 -- /* Dual-stack: Map IPv4 addresses to IPv4 mapped IPv6 */ -- if (NETCONNTYPE_ISIPV6(netconn_type(conn)) && IP_IS_V4(fromaddr)) { -- ip4_2_ipv4_mapped_ipv6(ip_2_ip6(fromaddr), ip_2_ip4(fromaddr)); -- IP_SET_TYPE(fromaddr, IPADDR_TYPE_V6); -- } --#endif /* LWIP_IPV4 && LWIP_IPV6 */ -- -- IPADDR_PORT_TO_SOCKADDR(&saddr, fromaddr, port); -- if (*fromlen < saddr.sa.sa_len) { -- truncated = 1; -- } else if (*fromlen > saddr.sa.sa_len) { -- *fromlen = saddr.sa.sa_len; -- } -- MEMCPY(from, &saddr, *fromlen); -- return truncated; --} -- --#if LWIP_TCP --/* Helper function to get a tcp socket's remote address info */ --static int --lwip_recv_tcp_from(struct lwip_sock *sock, struct sockaddr *from, socklen_t *fromlen, const char *dbg_fn, int dbg_s, ssize_t dbg_ret) --{ -- if (sock == NULL) { -- return 0; -- } -- LWIP_UNUSED_ARG(dbg_fn); -- LWIP_UNUSED_ARG(dbg_s); -- LWIP_UNUSED_ARG(dbg_ret); -- --#if !SOCKETS_DEBUG -- if (from && fromlen) --#endif /* !SOCKETS_DEBUG */ -- { -- /* get remote addr/port from tcp_pcb */ -- u16_t port; -- ip_addr_t tmpaddr; -- netconn_getaddr(sock->conn, &tmpaddr, &port, 0); -- LWIP_DEBUGF(SOCKETS_DEBUG, ("%s(%d): addr=", dbg_fn, dbg_s)); -- ip_addr_debug_print_val(SOCKETS_DEBUG, tmpaddr); -- LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F" len=%d\n", port, (int)dbg_ret)); -- if (from && fromlen) { -- return lwip_sock_make_addr(sock->conn, &tmpaddr, port, from, fromlen); -- } -- } -- return 0; --} --#endif -- --/* Helper function to receive a netbuf from a udp or raw netconn. -- * Keeps sock->lastdata for peeking. -- */ --static err_t --lwip_recvfrom_udp_raw(struct lwip_sock *sock, int flags, struct msghdr *msg, u16_t *datagram_len, int dbg_s) --{ -- struct netbuf *buf; -- u8_t apiflags; -- err_t err; -- u16_t buflen, copylen, copied; -- int i; -- -- LWIP_UNUSED_ARG(dbg_s); -- LWIP_ERROR("lwip_recvfrom_udp_raw: invalid arguments", (msg->msg_iov != NULL) || (msg->msg_iovlen <= 0), return ERR_ARG;); -- -- if (flags & MSG_DONTWAIT) { -- apiflags = NETCONN_DONTBLOCK; -- } else { -- apiflags = 0; -- } -- -- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom_udp_raw[UDP/RAW]: top sock->lastdata=%p\n", (void *)sock->lastdata.netbuf)); -- /* Check if there is data left from the last recv operation. */ -- buf = sock->lastdata.netbuf; -- if (buf == NULL) { -- /* No data was left from the previous operation, so we try to get -- some from the network. */ -- err = netconn_recv_udp_raw_netbuf_flags(sock->conn, &buf, apiflags); -- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom_udp_raw[UDP/RAW]: netconn_recv err=%d, netbuf=%p\n", -- err, (void *)buf)); -- -- if (err != ERR_OK) { -- return err; -- } -- LWIP_ASSERT("buf != NULL", buf != NULL); -- sock->lastdata.netbuf = buf; -- } -- buflen = buf->p->tot_len; -- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom_udp_raw: buflen=%"U16_F"\n", buflen)); -- -- copied = 0; -- /* copy the pbuf payload into the iovs */ -- for (i = 0; (i < msg->msg_iovlen) && (copied < buflen); i++) { -- u16_t len_left = (u16_t)(buflen - copied); -- if (msg->msg_iov[i].iov_len > len_left) { -- copylen = len_left; -- } else { -- copylen = (u16_t)msg->msg_iov[i].iov_len; -- } -- -- /* copy the contents of the received buffer into -- the supplied memory buffer */ -- pbuf_copy_partial(buf->p, (u8_t *)msg->msg_iov[i].iov_base, copylen, copied); -- copied = (u16_t)(copied + copylen); -- } -- -- /* Check to see from where the data was.*/ --#if !SOCKETS_DEBUG -- if (msg->msg_name && msg->msg_namelen) --#endif /* !SOCKETS_DEBUG */ -- { -- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom_udp_raw(%d): addr=", dbg_s)); -- ip_addr_debug_print_val(SOCKETS_DEBUG, *netbuf_fromaddr(buf)); -- LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F" len=%d\n", netbuf_fromport(buf), copied)); -- if (msg->msg_name && msg->msg_namelen) { -- lwip_sock_make_addr(sock->conn, netbuf_fromaddr(buf), netbuf_fromport(buf), -- (struct sockaddr *)msg->msg_name, &msg->msg_namelen); -- } -- } -- -- /* Initialize flag output */ -- msg->msg_flags = 0; -- -- if (msg->msg_control) { -- u8_t wrote_msg = 0; --#if LWIP_NETBUF_RECVINFO -- /* Check if packet info was recorded */ -- if (buf->flags & NETBUF_FLAG_DESTADDR) { -- if (IP_IS_V4(&buf->toaddr)) { --#if LWIP_IPV4 -- if (msg->msg_controllen >= CMSG_SPACE(sizeof(struct in_pktinfo))) { -- struct cmsghdr *chdr = CMSG_FIRSTHDR(msg); /* This will always return a header!! */ -- struct in_pktinfo *pkti = (struct in_pktinfo *)CMSG_DATA(chdr); -- chdr->cmsg_level = IPPROTO_IP; -- chdr->cmsg_type = IP_PKTINFO; -- chdr->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo)); -- pkti->ipi_ifindex = buf->p->if_idx; -- inet_addr_from_ip4addr(&pkti->ipi_addr, ip_2_ip4(netbuf_destaddr(buf))); -- msg->msg_controllen = CMSG_SPACE(sizeof(struct in_pktinfo)); -- wrote_msg = 1; -- } else { -- msg->msg_flags |= MSG_CTRUNC; -- } --#endif /* LWIP_IPV4 */ -- } -- } --#endif /* LWIP_NETBUF_RECVINFO */ -- -- if (!wrote_msg) { -- msg->msg_controllen = 0; -- } -- } -- -- /* If we don't peek the incoming message: zero lastdata pointer and free the netbuf */ -- if ((flags & MSG_PEEK) == 0) { -- sock->lastdata.netbuf = NULL; -- netbuf_delete(buf); -- } -- if (datagram_len) { -- *datagram_len = buflen; -- } -- return ERR_OK; --} -- --ssize_t --lwip_recvfrom(int s, void *mem, size_t len, int flags, -- struct sockaddr *from, socklen_t *fromlen) --{ -- struct lwip_sock *sock; -- ssize_t ret; -- -- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d, %p, %"SZT_F", 0x%x, ..)\n", s, mem, len, flags)); -- sock = get_socket(s); -- if (!sock) { -- return -1; -- } --#if LWIP_TCP -- if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) { -- ret = lwip_recv_tcp(sock, mem, len, flags); -- lwip_recv_tcp_from(sock, from, fromlen, "lwip_recvfrom", s, ret); -- done_socket(sock); -- return ret; -- } else --#endif -- { -- u16_t datagram_len = 0; -- struct iovec vec; -- struct msghdr msg; -- err_t err; -- vec.iov_base = mem; -- vec.iov_len = len; -- msg.msg_control = NULL; -- msg.msg_controllen = 0; -- msg.msg_flags = 0; -- msg.msg_iov = &vec; -- msg.msg_iovlen = 1; -- msg.msg_name = from; -- msg.msg_namelen = (fromlen ? *fromlen : 0); -- err = lwip_recvfrom_udp_raw(sock, flags, &msg, &datagram_len, s); -- if (err != ERR_OK) { -- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom[UDP/RAW](%d): buf == NULL, error is \"%s\"!\n", -- s, lwip_strerr(err))); -- sock_set_errno(sock, err_to_errno(err)); -- done_socket(sock); -- return -1; -- } -- ret = (ssize_t)LWIP_MIN(LWIP_MIN(len, datagram_len), SSIZE_MAX); -- if (fromlen) { -- *fromlen = msg.msg_namelen; -- } -- } -- -- sock_set_errno(sock, 0); -- done_socket(sock); -- return ret; --} -- --ssize_t --lwip_read(int s, void *mem, size_t len) --{ -- return lwip_recvfrom(s, mem, len, 0, NULL, NULL); --} -- --ssize_t --lwip_readv(int s, const struct iovec *iov, int iovcnt) --{ -- struct msghdr msg; -- -- msg.msg_name = NULL; -- msg.msg_namelen = 0; -- /* Hack: we have to cast via number to cast from 'const' pointer to non-const. -- Blame the opengroup standard for this inconsistency. */ -- msg.msg_iov = LWIP_CONST_CAST(struct iovec *, iov); -- msg.msg_iovlen = iovcnt; -- msg.msg_control = NULL; -- msg.msg_controllen = 0; -- msg.msg_flags = 0; -- return lwip_recvmsg(s, &msg, 0); --} -- --ssize_t --lwip_recv(int s, void *mem, size_t len, int flags) --{ -- return lwip_recvfrom(s, mem, len, flags, NULL, NULL); --} -- --ssize_t --lwip_recvmsg(int s, struct msghdr *message, int flags) --{ -- struct lwip_sock *sock; -- int i; -- ssize_t buflen; -- -- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvmsg(%d, message=%p, flags=0x%x)\n", s, (void *)message, flags)); -- LWIP_ERROR("lwip_recvmsg: invalid message pointer", message != NULL, return ERR_ARG;); -- LWIP_ERROR("lwip_recvmsg: unsupported flags", (flags & ~(MSG_PEEK|MSG_DONTWAIT)) == 0, -- set_errno(EOPNOTSUPP); return -1;); -- -- if ((message->msg_iovlen <= 0) || (message->msg_iovlen > IOV_MAX)) { -- set_errno(EMSGSIZE); -- return -1; -- } -- -- sock = get_socket(s); -- if (!sock) { -- return -1; -- } -- -- /* check for valid vectors */ -- buflen = 0; -- for (i = 0; i < message->msg_iovlen; i++) { -- if ((message->msg_iov[i].iov_base == NULL) || ((ssize_t)message->msg_iov[i].iov_len <= 0) || -- ((size_t)(ssize_t)message->msg_iov[i].iov_len != message->msg_iov[i].iov_len) || -- ((ssize_t)(buflen + (ssize_t)message->msg_iov[i].iov_len) <= 0)) { -- sock_set_errno(sock, err_to_errno(ERR_VAL)); -- done_socket(sock); -- return -1; -- } -- buflen = (ssize_t)(buflen + (ssize_t)message->msg_iov[i].iov_len); -- } -- -- if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) { --#if LWIP_TCP -- int recv_flags = flags; -- message->msg_flags = 0; -- /* recv the data */ -- buflen = 0; -- for (i = 0; i < message->msg_iovlen; i++) { -- /* try to receive into this vector's buffer */ -- ssize_t recvd_local = lwip_recv_tcp(sock, message->msg_iov[i].iov_base, message->msg_iov[i].iov_len, recv_flags); -- if (recvd_local > 0) { -- /* sum up received bytes */ -- buflen += recvd_local; -- } -- if ((recvd_local < 0) || (recvd_local < (int)message->msg_iov[i].iov_len) || -- (flags & MSG_PEEK)) { -- /* returned prematurely (or peeking, which might actually be limitated to the first iov) */ -- if (buflen <= 0) { -- /* nothing received at all, propagate the error */ -- buflen = recvd_local; -- } -- break; -- } -- /* pass MSG_DONTWAIT to lwip_recv_tcp() to prevent waiting for more data */ -- recv_flags |= MSG_DONTWAIT; -- } -- if (buflen > 0) { -- /* reset socket error since we have received something */ -- sock_set_errno(sock, 0); -- } -- /* " If the socket is connected, the msg_name and msg_namelen members shall be ignored." */ -- done_socket(sock); -- return buflen; --#else /* LWIP_TCP */ -- sock_set_errno(sock, err_to_errno(ERR_ARG)); -- done_socket(sock); -- return -1; --#endif /* LWIP_TCP */ -- } -- /* else, UDP and RAW NETCONNs */ --#if LWIP_UDP || LWIP_RAW -- { -- u16_t datagram_len = 0; -- err_t err; -- err = lwip_recvfrom_udp_raw(sock, flags, message, &datagram_len, s); -- if (err != ERR_OK) { -- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvmsg[UDP/RAW](%d): buf == NULL, error is \"%s\"!\n", -- s, lwip_strerr(err))); -- sock_set_errno(sock, err_to_errno(err)); -- done_socket(sock); -- return -1; -- } -- if (datagram_len > buflen) { -- message->msg_flags |= MSG_TRUNC; -- } -- -- sock_set_errno(sock, 0); -- done_socket(sock); -- return (int)datagram_len; -- } --#else /* LWIP_UDP || LWIP_RAW */ -- sock_set_errno(sock, err_to_errno(ERR_ARG)); -- done_socket(sock); -- return -1; --#endif /* LWIP_UDP || LWIP_RAW */ --} -- --ssize_t --lwip_send(int s, const void *data, size_t size, int flags) --{ -- struct lwip_sock *sock; -- err_t err; -- u8_t write_flags; -- size_t written; -- -- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_send(%d, data=%p, size=%"SZT_F", flags=0x%x)\n", -- s, data, size, flags)); -- -- sock = get_socket(s); -- if (!sock) { -- return -1; -- } -- -- if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_TCP) { --#if (LWIP_UDP || LWIP_RAW) -- done_socket(sock); -- return lwip_sendto(s, data, size, flags, NULL, 0); --#else /* (LWIP_UDP || LWIP_RAW) */ -- sock_set_errno(sock, err_to_errno(ERR_ARG)); -- done_socket(sock); -- return -1; --#endif /* (LWIP_UDP || LWIP_RAW) */ -- } -- -- write_flags = (u8_t)(NETCONN_COPY | -- ((flags & MSG_MORE) ? NETCONN_MORE : 0) | -- ((flags & MSG_DONTWAIT) ? NETCONN_DONTBLOCK : 0)); -- written = 0; -- err = netconn_write_partly(sock->conn, data, size, write_flags, &written); -- -- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_send(%d) err=%d written=%"SZT_F"\n", s, err, written)); -- sock_set_errno(sock, err_to_errno(err)); -- done_socket(sock); -- /* casting 'written' to ssize_t is OK here since the netconn API limits it to SSIZE_MAX */ -- return (err == ERR_OK ? (ssize_t)written : -1); --} -- --ssize_t --lwip_sendmsg(int s, const struct msghdr *msg, int flags) --{ -- struct lwip_sock *sock; --#if LWIP_TCP -- u8_t write_flags; -- size_t written; --#endif -- err_t err = ERR_OK; -- -- sock = get_socket(s); -- if (!sock) { -- return -1; -- } -- -- LWIP_ERROR("lwip_sendmsg: invalid msghdr", msg != NULL, -- sock_set_errno(sock, err_to_errno(ERR_ARG)); done_socket(sock); return -1;); -- LWIP_ERROR("lwip_sendmsg: invalid msghdr iov", msg->msg_iov != NULL, -- sock_set_errno(sock, err_to_errno(ERR_ARG)); done_socket(sock); return -1;); -- LWIP_ERROR("lwip_sendmsg: maximum iovs exceeded", (msg->msg_iovlen > 0) && (msg->msg_iovlen <= IOV_MAX), -- sock_set_errno(sock, EMSGSIZE); done_socket(sock); return -1;); -- LWIP_ERROR("lwip_sendmsg: unsupported flags", (flags & ~(MSG_DONTWAIT | MSG_MORE)) == 0, -- sock_set_errno(sock, EOPNOTSUPP); done_socket(sock); return -1;); -- -- LWIP_UNUSED_ARG(msg->msg_control); -- LWIP_UNUSED_ARG(msg->msg_controllen); -- LWIP_UNUSED_ARG(msg->msg_flags); -- -- if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) { --#if LWIP_TCP -- write_flags = (u8_t)(NETCONN_COPY | -- ((flags & MSG_MORE) ? NETCONN_MORE : 0) | -- ((flags & MSG_DONTWAIT) ? NETCONN_DONTBLOCK : 0)); -- -- written = 0; -- err = netconn_write_vectors_partly(sock->conn, (struct netvector *)msg->msg_iov, (u16_t)msg->msg_iovlen, write_flags, &written); -- sock_set_errno(sock, err_to_errno(err)); -- done_socket(sock); -- /* casting 'written' to ssize_t is OK here since the netconn API limits it to SSIZE_MAX */ -- return (err == ERR_OK ? (ssize_t)written : -1); --#else /* LWIP_TCP */ -- sock_set_errno(sock, err_to_errno(ERR_ARG)); -- done_socket(sock); -- return -1; --#endif /* LWIP_TCP */ -- } -- /* else, UDP and RAW NETCONNs */ --#if LWIP_UDP || LWIP_RAW -- { -- struct netbuf chain_buf; -- int i; -- ssize_t size = 0; -- -- LWIP_UNUSED_ARG(flags); -- LWIP_ERROR("lwip_sendmsg: invalid msghdr name", (((msg->msg_name == NULL) && (msg->msg_namelen == 0)) || -- IS_SOCK_ADDR_LEN_VALID(msg->msg_namelen)), -- sock_set_errno(sock, err_to_errno(ERR_ARG)); done_socket(sock); return -1;); -- -- /* initialize chain buffer with destination */ -- memset(&chain_buf, 0, sizeof(struct netbuf)); -- if (msg->msg_name) { -- u16_t remote_port; -- SOCKADDR_TO_IPADDR_PORT((const struct sockaddr *)msg->msg_name, &chain_buf.addr, remote_port); -- netbuf_fromport(&chain_buf) = remote_port; -- } --#if LWIP_NETIF_TX_SINGLE_PBUF -- for (i = 0; i < msg->msg_iovlen; i++) { -- size += msg->msg_iov[i].iov_len; -- if ((msg->msg_iov[i].iov_len > INT_MAX) || (size < (int)msg->msg_iov[i].iov_len)) { -- /* overflow */ -- goto sendmsg_emsgsize; -- } -- } -- if (size > 0xFFFF) { -- /* overflow */ -- goto sendmsg_emsgsize; -- } -- /* Allocate a new netbuf and copy the data into it. */ -- if (netbuf_alloc(&chain_buf, (u16_t)size) == NULL) { -- err = ERR_MEM; -- } else { -- /* flatten the IO vectors */ -- size_t offset = 0; -- for (i = 0; i < msg->msg_iovlen; i++) { -- MEMCPY(&((u8_t *)chain_buf.p->payload)[offset], msg->msg_iov[i].iov_base, msg->msg_iov[i].iov_len); -- offset += msg->msg_iov[i].iov_len; -- } --#if LWIP_CHECKSUM_ON_COPY -- { -- /* This can be improved by using LWIP_CHKSUM_COPY() and aggregating the checksum for each IO vector */ -- u16_t chksum = ~inet_chksum_pbuf(chain_buf.p); -- netbuf_set_chksum(&chain_buf, chksum); -- } --#endif /* LWIP_CHECKSUM_ON_COPY */ -- err = ERR_OK; -- } --#else /* LWIP_NETIF_TX_SINGLE_PBUF */ -- /* create a chained netbuf from the IO vectors. NOTE: we assemble a pbuf chain -- manually to avoid having to allocate, chain, and delete a netbuf for each iov */ -- for (i = 0; i < msg->msg_iovlen; i++) { -- struct pbuf *p; -- if (msg->msg_iov[i].iov_len > 0xFFFF) { -- /* overflow */ -- goto sendmsg_emsgsize; -- } -- p = pbuf_alloc(PBUF_TRANSPORT, 0, PBUF_REF); -- if (p == NULL) { -- err = ERR_MEM; /* let netbuf_delete() cleanup chain_buf */ -- break; -- } -- p->payload = msg->msg_iov[i].iov_base; -- p->len = p->tot_len = (u16_t)msg->msg_iov[i].iov_len; -- /* netbuf empty, add new pbuf */ -- if (chain_buf.p == NULL) { -- chain_buf.p = chain_buf.ptr = p; -- /* add pbuf to existing pbuf chain */ -- } else { -- if (chain_buf.p->tot_len + p->len > 0xffff) { -- /* overflow */ -- pbuf_free(p); -- goto sendmsg_emsgsize; -- } -- pbuf_cat(chain_buf.p, p); -- } -- } -- /* save size of total chain */ -- if (err == ERR_OK) { -- size = netbuf_len(&chain_buf); -- } --#endif /* LWIP_NETIF_TX_SINGLE_PBUF */ -- -- if (err == ERR_OK) { --#if LWIP_IPV4 && LWIP_IPV6 -- /* Dual-stack: Unmap IPv4 mapped IPv6 addresses */ -- if (IP_IS_V6_VAL(chain_buf.addr) && ip6_addr_isipv4mappedipv6(ip_2_ip6(&chain_buf.addr))) { -- unmap_ipv4_mapped_ipv6(ip_2_ip4(&chain_buf.addr), ip_2_ip6(&chain_buf.addr)); -- IP_SET_TYPE_VAL(chain_buf.addr, IPADDR_TYPE_V4); -- } --#endif /* LWIP_IPV4 && LWIP_IPV6 */ -- -- /* send the data */ -- err = netconn_send(sock->conn, &chain_buf); -- } -- -- /* deallocated the buffer */ -- netbuf_free(&chain_buf); -- -- sock_set_errno(sock, err_to_errno(err)); -- done_socket(sock); -- return (err == ERR_OK ? size : -1); --sendmsg_emsgsize: -- sock_set_errno(sock, EMSGSIZE); -- netbuf_free(&chain_buf); -- done_socket(sock); -- return -1; -- } --#else /* LWIP_UDP || LWIP_RAW */ -- sock_set_errno(sock, err_to_errno(ERR_ARG)); -- done_socket(sock); -- return -1; --#endif /* LWIP_UDP || LWIP_RAW */ --} -- --ssize_t --lwip_sendto(int s, const void *data, size_t size, int flags, -- const struct sockaddr *to, socklen_t tolen) --{ -- struct lwip_sock *sock; -- err_t err; -- u16_t short_size; -- u16_t remote_port; -- struct netbuf buf; -- -- sock = get_socket(s); -- if (!sock) { -- return -1; -- } -- -- if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) { --#if LWIP_TCP -- done_socket(sock); -- return lwip_send(s, data, size, flags); --#else /* LWIP_TCP */ -- LWIP_UNUSED_ARG(flags); -- sock_set_errno(sock, err_to_errno(ERR_ARG)); -- done_socket(sock); -- return -1; --#endif /* LWIP_TCP */ -- } -- -- if (size > LWIP_MIN(0xFFFF, SSIZE_MAX)) { -- /* cannot fit into one datagram (at least for us) */ -- sock_set_errno(sock, EMSGSIZE); -- done_socket(sock); -- return -1; -- } -- short_size = (u16_t)size; -- LWIP_ERROR("lwip_sendto: invalid address", (((to == NULL) && (tolen == 0)) || -- (IS_SOCK_ADDR_LEN_VALID(tolen) && -- ((to != NULL) && (IS_SOCK_ADDR_TYPE_VALID(to) && IS_SOCK_ADDR_ALIGNED(to))))), -- sock_set_errno(sock, err_to_errno(ERR_ARG)); done_socket(sock); return -1;); -- LWIP_UNUSED_ARG(tolen); -- -- /* initialize a buffer */ -- buf.p = buf.ptr = NULL; --#if LWIP_CHECKSUM_ON_COPY -- buf.flags = 0; --#endif /* LWIP_CHECKSUM_ON_COPY */ -- if (to) { -- SOCKADDR_TO_IPADDR_PORT(to, &buf.addr, remote_port); -- } else { -- remote_port = 0; -- ip_addr_set_any(NETCONNTYPE_ISIPV6(netconn_type(sock->conn)), &buf.addr); -- } -- netbuf_fromport(&buf) = remote_port; -- -- -- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_sendto(%d, data=%p, short_size=%"U16_F", flags=0x%x to=", -- s, data, short_size, flags)); -- ip_addr_debug_print_val(SOCKETS_DEBUG, buf.addr); -- LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F"\n", remote_port)); -- -- /* make the buffer point to the data that should be sent */ --#if LWIP_NETIF_TX_SINGLE_PBUF -- /* Allocate a new netbuf and copy the data into it. */ -- if (netbuf_alloc(&buf, short_size) == NULL) { -- err = ERR_MEM; -- } else { --#if LWIP_CHECKSUM_ON_COPY -- if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_RAW) { -- u16_t chksum = LWIP_CHKSUM_COPY(buf.p->payload, data, short_size); -- netbuf_set_chksum(&buf, chksum); -- } else --#endif /* LWIP_CHECKSUM_ON_COPY */ -- { -- MEMCPY(buf.p->payload, data, short_size); -- } -- err = ERR_OK; -- } --#else /* LWIP_NETIF_TX_SINGLE_PBUF */ -- err = netbuf_ref(&buf, data, short_size); --#endif /* LWIP_NETIF_TX_SINGLE_PBUF */ -- if (err == ERR_OK) { --#if LWIP_IPV4 && LWIP_IPV6 -- /* Dual-stack: Unmap IPv4 mapped IPv6 addresses */ -- if (IP_IS_V6_VAL(buf.addr) && ip6_addr_isipv4mappedipv6(ip_2_ip6(&buf.addr))) { -- unmap_ipv4_mapped_ipv6(ip_2_ip4(&buf.addr), ip_2_ip6(&buf.addr)); -- IP_SET_TYPE_VAL(buf.addr, IPADDR_TYPE_V4); -- } --#endif /* LWIP_IPV4 && LWIP_IPV6 */ -- -- /* send the data */ -- err = netconn_send(sock->conn, &buf); -- } -- -- /* deallocated the buffer */ -- netbuf_free(&buf); -- -- sock_set_errno(sock, err_to_errno(err)); -- done_socket(sock); -- return (err == ERR_OK ? short_size : -1); --} -- --int --lwip_socket(int domain, int type, int protocol) --{ -- struct netconn *conn; -- int i; -- -- LWIP_UNUSED_ARG(domain); /* @todo: check this */ -- -- /* create a netconn */ -- switch (type) { -- case SOCK_RAW: -- conn = netconn_new_with_proto_and_callback(DOMAIN_TO_NETCONN_TYPE(domain, NETCONN_RAW), -- (u8_t)protocol, DEFAULT_SOCKET_EVENTCB); -- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_RAW, %d) = ", -- domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol)); -- break; -- case SOCK_DGRAM: -- conn = netconn_new_with_callback(DOMAIN_TO_NETCONN_TYPE(domain, -- ((protocol == IPPROTO_UDPLITE) ? NETCONN_UDPLITE : NETCONN_UDP)), -- DEFAULT_SOCKET_EVENTCB); -- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_DGRAM, %d) = ", -- domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol)); --#if LWIP_NETBUF_RECVINFO -- if (conn) { -- /* netconn layer enables pktinfo by default, sockets default to off */ -- conn->flags &= ~NETCONN_FLAG_PKTINFO; -- } --#endif /* LWIP_NETBUF_RECVINFO */ -- break; -- case SOCK_STREAM: -- conn = netconn_new_with_callback(DOMAIN_TO_NETCONN_TYPE(domain, NETCONN_TCP), DEFAULT_SOCKET_EVENTCB); -- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_STREAM, %d) = ", -- domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol)); -- break; -- default: -- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%d, %d/UNKNOWN, %d) = -1\n", -- domain, type, protocol)); -- set_errno(EINVAL); -- return -1; -- } -- -- if (!conn) { -- LWIP_DEBUGF(SOCKETS_DEBUG, ("-1 / ENOBUFS (could not create netconn)\n")); -- set_errno(ENOBUFS); -- return -1; -- } -- -- i = alloc_socket(conn, 0); -- -- if (i == -1) { -- netconn_delete(conn); -- set_errno(ENFILE); -- return -1; -- } -- conn->socket = i; -- done_socket(&sockets[i - LWIP_SOCKET_OFFSET]); -- LWIP_DEBUGF(SOCKETS_DEBUG, ("%d\n", i)); -- set_errno(0); -- return i; --} -- --ssize_t --lwip_write(int s, const void *data, size_t size) --{ -- return lwip_send(s, data, size, 0); --} -- --ssize_t --lwip_writev(int s, const struct iovec *iov, int iovcnt) --{ -- struct msghdr msg; -- -- msg.msg_name = NULL; -- msg.msg_namelen = 0; -- /* Hack: we have to cast via number to cast from 'const' pointer to non-const. -- Blame the opengroup standard for this inconsistency. */ -- msg.msg_iov = LWIP_CONST_CAST(struct iovec *, iov); -- msg.msg_iovlen = iovcnt; -- msg.msg_control = NULL; -- msg.msg_controllen = 0; -- msg.msg_flags = 0; -- return lwip_sendmsg(s, &msg, 0); --} -- --#if LWIP_SOCKET_SELECT || LWIP_SOCKET_POLL --/* Add select_cb to select_cb_list. */ --static void --lwip_link_select_cb(struct lwip_select_cb *select_cb) --{ -- LWIP_SOCKET_SELECT_DECL_PROTECT(lev); -- -- /* Protect the select_cb_list */ -- LWIP_SOCKET_SELECT_PROTECT(lev); -- -- /* Put this select_cb on top of list */ -- select_cb->next = select_cb_list; -- if (select_cb_list != NULL) { -- select_cb_list->prev = select_cb; -- } -- select_cb_list = select_cb; --#if !LWIP_TCPIP_CORE_LOCKING -- /* Increasing this counter tells select_check_waiters that the list has changed. */ -- select_cb_ctr++; --#endif -- -- /* Now we can safely unprotect */ -- LWIP_SOCKET_SELECT_UNPROTECT(lev); --} -- --/* Remove select_cb from select_cb_list. */ --static void --lwip_unlink_select_cb(struct lwip_select_cb *select_cb) --{ -- LWIP_SOCKET_SELECT_DECL_PROTECT(lev); -- -- /* Take us off the list */ -- LWIP_SOCKET_SELECT_PROTECT(lev); -- if (select_cb->next != NULL) { -- select_cb->next->prev = select_cb->prev; -- } -- if (select_cb_list == select_cb) { -- LWIP_ASSERT("select_cb->prev == NULL", select_cb->prev == NULL); -- select_cb_list = select_cb->next; -- } else { -- LWIP_ASSERT("select_cb->prev != NULL", select_cb->prev != NULL); -- select_cb->prev->next = select_cb->next; -- } --#if !LWIP_TCPIP_CORE_LOCKING -- /* Increasing this counter tells select_check_waiters that the list has changed. */ -- select_cb_ctr++; --#endif -- LWIP_SOCKET_SELECT_UNPROTECT(lev); --} --#endif /* LWIP_SOCKET_SELECT || LWIP_SOCKET_POLL */ -- --#if LWIP_SOCKET_SELECT --/** -- * Go through the readset and writeset lists and see which socket of the sockets -- * set in the sets has events. On return, readset, writeset and exceptset have -- * the sockets enabled that had events. -- * -- * @param maxfdp1 the highest socket index in the sets -- * @param readset_in set of sockets to check for read events -- * @param writeset_in set of sockets to check for write events -- * @param exceptset_in set of sockets to check for error events -- * @param readset_out set of sockets that had read events -- * @param writeset_out set of sockets that had write events -- * @param exceptset_out set os sockets that had error events -- * @return number of sockets that had events (read/write/exception) (>= 0) -- */ --static int --lwip_selscan(int maxfdp1, fd_set *readset_in, fd_set *writeset_in, fd_set *exceptset_in, -- fd_set *readset_out, fd_set *writeset_out, fd_set *exceptset_out) --{ -- int i, nready = 0; -- fd_set lreadset, lwriteset, lexceptset; -- struct lwip_sock *sock; -- SYS_ARCH_DECL_PROTECT(lev); -- -- FD_ZERO(&lreadset); -- FD_ZERO(&lwriteset); -- FD_ZERO(&lexceptset); -- -- /* Go through each socket in each list to count number of sockets which -- currently match */ -- for (i = LWIP_SOCKET_OFFSET; i < maxfdp1; i++) { -- /* if this FD is not in the set, continue */ -- if (!(readset_in && FD_ISSET(i, readset_in)) && -- !(writeset_in && FD_ISSET(i, writeset_in)) && -- !(exceptset_in && FD_ISSET(i, exceptset_in))) { -- continue; -- } -- /* First get the socket's status (protected)... */ -- SYS_ARCH_PROTECT(lev); -- sock = tryget_socket_unconn_locked(i); -- if (sock != NULL) { -- void *lastdata = sock->lastdata.pbuf; -- s16_t rcvevent = sock->rcvevent; -- u16_t sendevent = sock->sendevent; -- u16_t errevent = sock->errevent; -- SYS_ARCH_UNPROTECT(lev); -- -- /* ... then examine it: */ -- /* See if netconn of this socket is ready for read */ -- if (readset_in && FD_ISSET(i, readset_in) && ((lastdata != NULL) || (rcvevent > 0))) { -- FD_SET(i, &lreadset); -- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_selscan: fd=%d ready for reading\n", i)); -- nready++; -- } -- /* See if netconn of this socket is ready for write */ -- if (writeset_in && FD_ISSET(i, writeset_in) && (sendevent != 0)) { -- FD_SET(i, &lwriteset); -- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_selscan: fd=%d ready for writing\n", i)); -- nready++; -- } -- /* See if netconn of this socket had an error */ -- if (exceptset_in && FD_ISSET(i, exceptset_in) && (errevent != 0)) { -- FD_SET(i, &lexceptset); -- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_selscan: fd=%d ready for exception\n", i)); -- nready++; -- } -- done_socket(sock); -- } else { -- SYS_ARCH_UNPROTECT(lev); -- /* no a valid open socket */ -- return -1; -- } -- } -- /* copy local sets to the ones provided as arguments */ -- *readset_out = lreadset; -- *writeset_out = lwriteset; -- *exceptset_out = lexceptset; -- -- LWIP_ASSERT("nready >= 0", nready >= 0); -- return nready; --} -- --#if LWIP_NETCONN_FULLDUPLEX --/* Mark all of the set sockets in one of the three fdsets passed to select as used. -- * All sockets are marked (and later unmarked), whether they are open or not. -- * This is OK as lwip_selscan aborts select when non-open sockets are found. -- */ --static void --lwip_select_inc_sockets_used_set(int maxfdp, fd_set *fdset, fd_set *used_sockets) --{ -- SYS_ARCH_DECL_PROTECT(lev); -- if (fdset) { -- int i; -- for (i = LWIP_SOCKET_OFFSET; i < maxfdp; i++) { -- /* if this FD is in the set, lock it (unless already done) */ -- if (FD_ISSET(i, fdset) && !FD_ISSET(i, used_sockets)) { -- struct lwip_sock *sock; -- SYS_ARCH_PROTECT(lev); -- sock = tryget_socket_unconn_locked(i); -- if (sock != NULL) { -- /* leave the socket used until released by lwip_select_dec_sockets_used */ -- FD_SET(i, used_sockets); -- } -- SYS_ARCH_UNPROTECT(lev); -- } -- } -- } --} -- --/* Mark all sockets passed to select as used to prevent them from being freed -- * from other threads while select is running. -- * Marked sockets are added to 'used_sockets' to mark them only once an be able -- * to unmark them correctly. -- */ --static void --lwip_select_inc_sockets_used(int maxfdp, fd_set *fdset1, fd_set *fdset2, fd_set *fdset3, fd_set *used_sockets) --{ -- FD_ZERO(used_sockets); -- lwip_select_inc_sockets_used_set(maxfdp, fdset1, used_sockets); -- lwip_select_inc_sockets_used_set(maxfdp, fdset2, used_sockets); -- lwip_select_inc_sockets_used_set(maxfdp, fdset3, used_sockets); --} -- --/* Let go all sockets that were marked as used when starting select */ --static void --lwip_select_dec_sockets_used(int maxfdp, fd_set *used_sockets) --{ -- int i; -- for (i = LWIP_SOCKET_OFFSET; i < maxfdp; i++) { -- /* if this FD is not in the set, continue */ -- if (FD_ISSET(i, used_sockets)) { -- struct lwip_sock *sock = tryget_socket_unconn_nouse(i); -- LWIP_ASSERT("socket gone at the end of select", sock != NULL); -- if (sock != NULL) { -- done_socket(sock); -- } -- } -- } --} --#else /* LWIP_NETCONN_FULLDUPLEX */ --#define lwip_select_inc_sockets_used(maxfdp1, readset, writeset, exceptset, used_sockets) --#define lwip_select_dec_sockets_used(maxfdp1, used_sockets) --#endif /* LWIP_NETCONN_FULLDUPLEX */ -- --int --lwip_select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset, -- struct timeval *timeout) --{ -- u32_t waitres = 0; -- int nready; -- fd_set lreadset, lwriteset, lexceptset; -- u32_t msectimeout; -- int i; -- int maxfdp2; --#if LWIP_NETCONN_SEM_PER_THREAD -- int waited = 0; --#endif --#if LWIP_NETCONN_FULLDUPLEX -- fd_set used_sockets; --#endif -- SYS_ARCH_DECL_PROTECT(lev); -- -- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select(%d, %p, %p, %p, tvsec=%"S32_F" tvusec=%"S32_F")\n", -- maxfdp1, (void *)readset, (void *) writeset, (void *) exceptset, -- timeout ? (s32_t)timeout->tv_sec : (s32_t) - 1, -- timeout ? (s32_t)timeout->tv_usec : (s32_t) - 1)); -- -- if ((maxfdp1 < 0) || (maxfdp1 > LWIP_SELECT_MAXNFDS)) { -- set_errno(EINVAL); -- return -1; -- } -- -- lwip_select_inc_sockets_used(maxfdp1, readset, writeset, exceptset, &used_sockets); -- -- /* Go through each socket in each list to count number of sockets which -- currently match */ -- nready = lwip_selscan(maxfdp1, readset, writeset, exceptset, &lreadset, &lwriteset, &lexceptset); -- -- if (nready < 0) { -- /* one of the sockets in one of the fd_sets was invalid */ -- set_errno(EBADF); -- lwip_select_dec_sockets_used(maxfdp1, &used_sockets); -- return -1; -- } else if (nready > 0) { -- /* one or more sockets are set, no need to wait */ -- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select: nready=%d\n", nready)); -- } else { -- /* If we don't have any current events, then suspend if we are supposed to */ -- if (timeout && timeout->tv_sec == 0 && timeout->tv_usec == 0) { -- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select: no timeout, returning 0\n")); -- /* This is OK as the local fdsets are empty and nready is zero, -- or we would have returned earlier. */ -- } else { -- /* None ready: add our semaphore to list: -- We don't actually need any dynamic memory. Our entry on the -- list is only valid while we are in this function, so it's ok -- to use local variables (unless we're running in MPU compatible -- mode). */ -- API_SELECT_CB_VAR_DECLARE(select_cb); -- API_SELECT_CB_VAR_ALLOC(select_cb, set_errno(ENOMEM); lwip_select_dec_sockets_used(maxfdp1, &used_sockets); return -1); -- memset(&API_SELECT_CB_VAR_REF(select_cb), 0, sizeof(struct lwip_select_cb)); -- -- API_SELECT_CB_VAR_REF(select_cb).readset = readset; -- API_SELECT_CB_VAR_REF(select_cb).writeset = writeset; -- API_SELECT_CB_VAR_REF(select_cb).exceptset = exceptset; --#if LWIP_NETCONN_SEM_PER_THREAD -- API_SELECT_CB_VAR_REF(select_cb).sem = LWIP_NETCONN_THREAD_SEM_GET(); --#else /* LWIP_NETCONN_SEM_PER_THREAD */ -- if (sys_sem_new(&API_SELECT_CB_VAR_REF(select_cb).sem, 0) != ERR_OK) { -- /* failed to create semaphore */ -- set_errno(ENOMEM); -- lwip_select_dec_sockets_used(maxfdp1, &used_sockets); -- API_SELECT_CB_VAR_FREE(select_cb); -- return -1; -- } --#endif /* LWIP_NETCONN_SEM_PER_THREAD */ -- -- lwip_link_select_cb(&API_SELECT_CB_VAR_REF(select_cb)); -- -- /* Increase select_waiting for each socket we are interested in */ -- maxfdp2 = maxfdp1; -- for (i = LWIP_SOCKET_OFFSET; i < maxfdp1; i++) { -- if ((readset && FD_ISSET(i, readset)) || -- (writeset && FD_ISSET(i, writeset)) || -- (exceptset && FD_ISSET(i, exceptset))) { -- struct lwip_sock *sock; -- SYS_ARCH_PROTECT(lev); -- sock = tryget_socket_unconn_locked(i); -- if (sock != NULL) { -- sock->select_waiting++; -- if (sock->select_waiting == 0) { -- /* overflow - too many threads waiting */ -- sock->select_waiting--; -- nready = -1; -- maxfdp2 = i; -- SYS_ARCH_UNPROTECT(lev); -- done_socket(sock); -- set_errno(EBUSY); -- break; -- } -- SYS_ARCH_UNPROTECT(lev); -- done_socket(sock); -- } else { -- /* Not a valid socket */ -- nready = -1; -- maxfdp2 = i; -- SYS_ARCH_UNPROTECT(lev); -- set_errno(EBADF); -- break; -- } -- } -- } -- -- if (nready >= 0) { -- /* Call lwip_selscan again: there could have been events between -- the last scan (without us on the list) and putting us on the list! */ -- nready = lwip_selscan(maxfdp1, readset, writeset, exceptset, &lreadset, &lwriteset, &lexceptset); -- if (!nready) { -- /* Still none ready, just wait to be woken */ -- if (timeout == 0) { -- /* Wait forever */ -- msectimeout = 0; -- } else { -- long msecs_long = ((timeout->tv_sec * 1000) + ((timeout->tv_usec + 500) / 1000)); -- if (msecs_long <= 0) { -- /* Wait 1ms at least (0 means wait forever) */ -- msectimeout = 1; -- } else { -- msectimeout = (u32_t)msecs_long; -- } -- } -- -- waitres = sys_arch_sem_wait(SELECT_SEM_PTR(API_SELECT_CB_VAR_REF(select_cb).sem), msectimeout); --#if LWIP_NETCONN_SEM_PER_THREAD -- waited = 1; --#endif -- } -- } -- -- /* Decrease select_waiting for each socket we are interested in */ -- for (i = LWIP_SOCKET_OFFSET; i < maxfdp2; i++) { -- if ((readset && FD_ISSET(i, readset)) || -- (writeset && FD_ISSET(i, writeset)) || -- (exceptset && FD_ISSET(i, exceptset))) { -- struct lwip_sock *sock; -- SYS_ARCH_PROTECT(lev); -- sock = tryget_socket_unconn_locked(i); -- if (sock != NULL) { -- /* for now, handle select_waiting==0... */ -- LWIP_ASSERT("sock->select_waiting > 0", sock->select_waiting > 0); -- if (sock->select_waiting > 0) { -- sock->select_waiting--; -- } -- SYS_ARCH_UNPROTECT(lev); -- done_socket(sock); -- } else { -- SYS_ARCH_UNPROTECT(lev); -- /* Not a valid socket */ -- nready = -1; -- set_errno(EBADF); -- } -- } -- } -- -- lwip_unlink_select_cb(&API_SELECT_CB_VAR_REF(select_cb)); -- --#if LWIP_NETCONN_SEM_PER_THREAD -- if (API_SELECT_CB_VAR_REF(select_cb).sem_signalled && (!waited || (waitres == SYS_ARCH_TIMEOUT))) { -- /* don't leave the thread-local semaphore signalled */ -- sys_arch_sem_wait(API_SELECT_CB_VAR_REF(select_cb).sem, 1); -- } --#else /* LWIP_NETCONN_SEM_PER_THREAD */ -- sys_sem_free(&API_SELECT_CB_VAR_REF(select_cb).sem); --#endif /* LWIP_NETCONN_SEM_PER_THREAD */ -- API_SELECT_CB_VAR_FREE(select_cb); -- -- if (nready < 0) { -- /* This happens when a socket got closed while waiting */ -- lwip_select_dec_sockets_used(maxfdp1, &used_sockets); -- return -1; -- } -- -- if (waitres == SYS_ARCH_TIMEOUT) { -- /* Timeout */ -- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select: timeout expired\n")); -- /* This is OK as the local fdsets are empty and nready is zero, -- or we would have returned earlier. */ -- } else { -- /* See what's set now after waiting */ -- nready = lwip_selscan(maxfdp1, readset, writeset, exceptset, &lreadset, &lwriteset, &lexceptset); -- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select: nready=%d\n", nready)); -- } -- } -- } -- -- lwip_select_dec_sockets_used(maxfdp1, &used_sockets); -- set_errno(0); -- if (readset) { -- *readset = lreadset; -- } -- if (writeset) { -- *writeset = lwriteset; -- } -- if (exceptset) { -- *exceptset = lexceptset; -- } -- return nready; --} --#endif /* LWIP_SOCKET_SELECT */ -- --#if LWIP_SOCKET_POLL --/** Options for the lwip_pollscan function. */ --enum lwip_pollscan_opts --{ -- /** Clear revents in each struct pollfd. */ -- LWIP_POLLSCAN_CLEAR = 1, -- -- /** Increment select_waiting in each struct lwip_sock. */ -- LWIP_POLLSCAN_INC_WAIT = 2, -- -- /** Decrement select_waiting in each struct lwip_sock. */ -- LWIP_POLLSCAN_DEC_WAIT = 4 --}; -- --/** -- * Update revents in each struct pollfd. -- * Optionally update select_waiting in struct lwip_sock. -- * -- * @param fds array of structures to update -- * @param nfds number of structures in fds -- * @param opts what to update and how -- * @return number of structures that have revents != 0 -- */ --static int --lwip_pollscan(struct pollfd *fds, nfds_t nfds, enum lwip_pollscan_opts opts) --{ -- int nready = 0; -- nfds_t fdi; -- struct lwip_sock *sock; -- SYS_ARCH_DECL_PROTECT(lev); -- -- /* Go through each struct pollfd in the array. */ -- for (fdi = 0; fdi < nfds; fdi++) { -- if ((opts & LWIP_POLLSCAN_CLEAR) != 0) { -- fds[fdi].revents = 0; -- } -- -- /* Negative fd means the caller wants us to ignore this struct. -- POLLNVAL means we already detected that the fd is invalid; -- if another thread has since opened a new socket with that fd, -- we must not use that socket. */ -- if (fds[fdi].fd >= 0 && (fds[fdi].revents & POLLNVAL) == 0) { -- /* First get the socket's status (protected)... */ -- SYS_ARCH_PROTECT(lev); -- sock = tryget_socket_unconn_locked(fds[fdi].fd); -- if (sock != NULL) { -- void* lastdata = sock->lastdata.pbuf; -- s16_t rcvevent = sock->rcvevent; -- u16_t sendevent = sock->sendevent; -- u16_t errevent = sock->errevent; -- -- if ((opts & LWIP_POLLSCAN_INC_WAIT) != 0) { -- sock->select_waiting++; -- if (sock->select_waiting == 0) { -- /* overflow - too many threads waiting */ -- sock->select_waiting--; -- nready = -1; -- SYS_ARCH_UNPROTECT(lev); -- done_socket(sock); -- break; -- } -- } else if ((opts & LWIP_POLLSCAN_DEC_WAIT) != 0) { -- /* for now, handle select_waiting==0... */ -- LWIP_ASSERT("sock->select_waiting > 0", sock->select_waiting > 0); -- if (sock->select_waiting > 0) { -- sock->select_waiting--; -- } -- } -- SYS_ARCH_UNPROTECT(lev); -- done_socket(sock); -- -- /* ... then examine it: */ -- /* See if netconn of this socket is ready for read */ -- if ((fds[fdi].events & POLLIN) != 0 && ((lastdata != NULL) || (rcvevent > 0))) { -- fds[fdi].revents |= POLLIN; -- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_pollscan: fd=%d ready for reading\n", fds[fdi].fd)); -- } -- /* See if netconn of this socket is ready for write */ -- if ((fds[fdi].events & POLLOUT) != 0 && (sendevent != 0)) { -- fds[fdi].revents |= POLLOUT; -- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_pollscan: fd=%d ready for writing\n", fds[fdi].fd)); -- } -- /* See if netconn of this socket had an error */ -- if (errevent != 0) { -- /* POLLERR is output only. */ -- fds[fdi].revents |= POLLERR; -- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_pollscan: fd=%d ready for exception\n", fds[fdi].fd)); -- } -- } else { -- /* Not a valid socket */ -- SYS_ARCH_UNPROTECT(lev); -- /* POLLNVAL is output only. */ -- fds[fdi].revents |= POLLNVAL; -- return -1; -- } -- } -- -- /* Will return the number of structures that have events, -- not the number of events. */ -- if (fds[fdi].revents != 0) { -- nready++; -- } -- } -- -- LWIP_ASSERT("nready >= 0", nready >= 0); -- return nready; --} -- --#if LWIP_NETCONN_FULLDUPLEX --/* Mark all sockets as used. -- * -- * All sockets are marked (and later unmarked), whether they are open or not. -- * This is OK as lwip_pollscan aborts select when non-open sockets are found. -- */ --static void --lwip_poll_inc_sockets_used(struct pollfd *fds, nfds_t nfds) --{ -- nfds_t fdi; -- -- if(fds) { -- /* Go through each struct pollfd in the array. */ -- for (fdi = 0; fdi < nfds; fdi++) { -- /* Increase the reference counter */ -- tryget_socket_unconn(fds[fdi].fd); -- } -- } --} -- --/* Let go all sockets that were marked as used when starting poll */ --static void --lwip_poll_dec_sockets_used(struct pollfd *fds, nfds_t nfds) --{ -- nfds_t fdi; -- -- if(fds) { -- /* Go through each struct pollfd in the array. */ -- for (fdi = 0; fdi < nfds; fdi++) { -- struct lwip_sock *sock = tryget_socket_unconn_nouse(fds[fdi].fd); -- if (sock != NULL) { -- done_socket(sock); -- } -- } -- } --} --#else /* LWIP_NETCONN_FULLDUPLEX */ --#define lwip_poll_inc_sockets_used(fds, nfds) --#define lwip_poll_dec_sockets_used(fds, nfds) --#endif /* LWIP_NETCONN_FULLDUPLEX */ -- --int --lwip_poll(struct pollfd *fds, nfds_t nfds, int timeout) --{ -- u32_t waitres = 0; -- int nready; -- u32_t msectimeout; --#if LWIP_NETCONN_SEM_PER_THREAD -- int waited = 0; --#endif -- -- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_poll(%p, %d, %d)\n", -- (void*)fds, (int)nfds, timeout)); -- LWIP_ERROR("lwip_poll: invalid fds", ((fds != NULL && nfds > 0) || (fds == NULL && nfds == 0)), -- set_errno(EINVAL); return -1;); -- -- lwip_poll_inc_sockets_used(fds, nfds); -- -- /* Go through each struct pollfd to count number of structures -- which currently match */ -- nready = lwip_pollscan(fds, nfds, LWIP_POLLSCAN_CLEAR); -- -- if (nready < 0) { -- lwip_poll_dec_sockets_used(fds, nfds); -- return -1; -- } -- -- /* If we don't have any current events, then suspend if we are supposed to */ -- if (!nready) { -- API_SELECT_CB_VAR_DECLARE(select_cb); -- -- if (timeout == 0) { -- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_poll: no timeout, returning 0\n")); -- goto return_success; -- } -- API_SELECT_CB_VAR_ALLOC(select_cb, set_errno(EAGAIN); lwip_poll_dec_sockets_used(fds, nfds); return -1); -- memset(&API_SELECT_CB_VAR_REF(select_cb), 0, sizeof(struct lwip_select_cb)); -- -- /* None ready: add our semaphore to list: -- We don't actually need any dynamic memory. Our entry on the -- list is only valid while we are in this function, so it's ok -- to use local variables. */ -- -- API_SELECT_CB_VAR_REF(select_cb).poll_fds = fds; -- API_SELECT_CB_VAR_REF(select_cb).poll_nfds = nfds; --#if LWIP_NETCONN_SEM_PER_THREAD -- API_SELECT_CB_VAR_REF(select_cb).sem = LWIP_NETCONN_THREAD_SEM_GET(); --#else /* LWIP_NETCONN_SEM_PER_THREAD */ -- if (sys_sem_new(&API_SELECT_CB_VAR_REF(select_cb).sem, 0) != ERR_OK) { -- /* failed to create semaphore */ -- set_errno(EAGAIN); -- lwip_poll_dec_sockets_used(fds, nfds); -- API_SELECT_CB_VAR_FREE(select_cb); -- return -1; -- } --#endif /* LWIP_NETCONN_SEM_PER_THREAD */ -- -- lwip_link_select_cb(&API_SELECT_CB_VAR_REF(select_cb)); -- -- /* Increase select_waiting for each socket we are interested in. -- Also, check for events again: there could have been events between -- the last scan (without us on the list) and putting us on the list! */ -- nready = lwip_pollscan(fds, nfds, LWIP_POLLSCAN_INC_WAIT); -- -- if (!nready) { -- /* Still none ready, just wait to be woken */ -- if (timeout < 0) { -- /* Wait forever */ -- msectimeout = 0; -- } else { -- /* timeout == 0 would have been handled earlier. */ -- LWIP_ASSERT("timeout > 0", timeout > 0); -- msectimeout = timeout; -- } -- waitres = sys_arch_sem_wait(SELECT_SEM_PTR(API_SELECT_CB_VAR_REF(select_cb).sem), msectimeout); --#if LWIP_NETCONN_SEM_PER_THREAD -- waited = 1; --#endif -- } -- -- /* Decrease select_waiting for each socket we are interested in, -- and check which events occurred while we waited. */ -- nready = lwip_pollscan(fds, nfds, LWIP_POLLSCAN_DEC_WAIT); -- -- lwip_unlink_select_cb(&API_SELECT_CB_VAR_REF(select_cb)); -- --#if LWIP_NETCONN_SEM_PER_THREAD -- if (select_cb.sem_signalled && (!waited || (waitres == SYS_ARCH_TIMEOUT))) { -- /* don't leave the thread-local semaphore signalled */ -- sys_arch_sem_wait(API_SELECT_CB_VAR_REF(select_cb).sem, 1); -- } --#else /* LWIP_NETCONN_SEM_PER_THREAD */ -- sys_sem_free(&API_SELECT_CB_VAR_REF(select_cb).sem); --#endif /* LWIP_NETCONN_SEM_PER_THREAD */ -- API_SELECT_CB_VAR_FREE(select_cb); -- -- if (nready < 0) { -- /* This happens when a socket got closed while waiting */ -- lwip_poll_dec_sockets_used(fds, nfds); -- return -1; -- } -- -- if (waitres == SYS_ARCH_TIMEOUT) { -- /* Timeout */ -- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_poll: timeout expired\n")); -- goto return_success; -- } -- } -- -- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_poll: nready=%d\n", nready)); --return_success: -- lwip_poll_dec_sockets_used(fds, nfds); -- set_errno(0); -- return nready; --} -- --/** -- * Check whether event_callback should wake up a thread waiting in -- * lwip_poll. -- */ --static int --lwip_poll_should_wake(const struct lwip_select_cb *scb, int fd, int has_recvevent, int has_sendevent, int has_errevent) --{ -- nfds_t fdi; -- for (fdi = 0; fdi < scb->poll_nfds; fdi++) { -- const struct pollfd *pollfd = &scb->poll_fds[fdi]; -- if (pollfd->fd == fd) { -- /* Do not update pollfd->revents right here; -- that would be a data race because lwip_pollscan -- accesses revents without protecting. */ -- if (has_recvevent && (pollfd->events & POLLIN) != 0) { -- return 1; -- } -- if (has_sendevent && (pollfd->events & POLLOUT) != 0) { -- return 1; -- } -- if (has_errevent) { -- /* POLLERR is output only. */ -- return 1; -- } -- } -- } -- return 0; --} --#endif /* LWIP_SOCKET_POLL */ -- --#if LWIP_SOCKET_SELECT || LWIP_SOCKET_POLL --/** -- * Callback registered in the netconn layer for each socket-netconn. -- * Processes recvevent (data available) and wakes up tasks waiting for select. -- * -- * @note for LWIP_TCPIP_CORE_LOCKING any caller of this function -- * must have the core lock held when signaling the following events -- * as they might cause select_list_cb to be checked: -- * NETCONN_EVT_RCVPLUS -- * NETCONN_EVT_SENDPLUS -- * NETCONN_EVT_ERROR -- * This requirement will be asserted in select_check_waiters() -- */ --static void --event_callback(struct netconn *conn, enum netconn_evt evt, u16_t len) --{ -- int s, check_waiters; -- struct lwip_sock *sock; -- SYS_ARCH_DECL_PROTECT(lev); -- -- LWIP_UNUSED_ARG(len); -- -- /* Get socket */ -- if (conn) { -- s = conn->socket; -- if (s < 0) { -- /* Data comes in right away after an accept, even though -- * the server task might not have created a new socket yet. -- * Just count down (or up) if that's the case and we -- * will use the data later. Note that only receive events -- * can happen before the new socket is set up. */ -- SYS_ARCH_PROTECT(lev); -- if (conn->socket < 0) { -- if (evt == NETCONN_EVT_RCVPLUS) { -- /* conn->socket is -1 on initialization -- lwip_accept adjusts sock->recvevent if conn->socket < -1 */ -- conn->socket--; -- } -- SYS_ARCH_UNPROTECT(lev); -- return; -- } -- s = conn->socket; -- SYS_ARCH_UNPROTECT(lev); -- } -- -- sock = get_socket(s); -- if (!sock) { -- return; -- } -- } else { -- return; -- } -- -- check_waiters = 1; -- SYS_ARCH_PROTECT(lev); -- /* Set event as required */ -- switch (evt) { -- case NETCONN_EVT_RCVPLUS: -- sock->rcvevent++; -- if (sock->rcvevent > 1) { -- check_waiters = 0; -- } -- break; -- case NETCONN_EVT_RCVMINUS: -- sock->rcvevent--; -- check_waiters = 0; -- break; -- case NETCONN_EVT_SENDPLUS: -- if (sock->sendevent) { -- check_waiters = 0; -- } -- sock->sendevent = 1; -- break; -- case NETCONN_EVT_SENDMINUS: -- sock->sendevent = 0; -- check_waiters = 0; -- break; -- case NETCONN_EVT_ERROR: -- sock->errevent = 1; -- break; -- default: -- LWIP_ASSERT("unknown event", 0); -- break; -- } -- -- if (sock->select_waiting && check_waiters) { -- /* Save which events are active */ -- int has_recvevent, has_sendevent, has_errevent; -- has_recvevent = sock->rcvevent > 0; -- has_sendevent = sock->sendevent != 0; -- has_errevent = sock->errevent != 0; -- SYS_ARCH_UNPROTECT(lev); -- /* Check any select calls waiting on this socket */ -- select_check_waiters(s, has_recvevent, has_sendevent, has_errevent); -- } else { -- SYS_ARCH_UNPROTECT(lev); -- } -- done_socket(sock); --} -- --/** -- * Check if any select waiters are waiting on this socket and its events -- * -- * @note on synchronization of select_cb_list: -- * LWIP_TCPIP_CORE_LOCKING: the select_cb_list must only be accessed while holding -- * the core lock. We do a single pass through the list and signal any waiters. -- * Core lock should already be held when calling here!!!! -- -- * !LWIP_TCPIP_CORE_LOCKING: we use SYS_ARCH_PROTECT but unlock on each iteration -- * of the loop, thus creating a possibility where a thread could modify the -- * select_cb_list during our UNPROTECT/PROTECT. We use a generational counter to -- * detect this change and restart the list walk. The list is expected to be small -- */ --static void select_check_waiters(int s, int has_recvevent, int has_sendevent, int has_errevent) --{ -- struct lwip_select_cb *scb; --#if !LWIP_TCPIP_CORE_LOCKING -- int last_select_cb_ctr; -- SYS_ARCH_DECL_PROTECT(lev); --#endif /* !LWIP_TCPIP_CORE_LOCKING */ -- -- LWIP_ASSERT_CORE_LOCKED(); -- --#if !LWIP_TCPIP_CORE_LOCKING -- SYS_ARCH_PROTECT(lev); --again: -- /* remember the state of select_cb_list to detect changes */ -- last_select_cb_ctr = select_cb_ctr; --#endif /* !LWIP_TCPIP_CORE_LOCKING */ -- for (scb = select_cb_list; scb != NULL; scb = scb->next) { -- if (scb->sem_signalled == 0) { -- /* semaphore not signalled yet */ -- int do_signal = 0; --#if LWIP_SOCKET_POLL -- if (scb->poll_fds != NULL) { -- do_signal = lwip_poll_should_wake(scb, s, has_recvevent, has_sendevent, has_errevent); -- } --#endif /* LWIP_SOCKET_POLL */ --#if LWIP_SOCKET_SELECT && LWIP_SOCKET_POLL -- else --#endif /* LWIP_SOCKET_SELECT && LWIP_SOCKET_POLL */ --#if LWIP_SOCKET_SELECT -- { -- /* Test this select call for our socket */ -- if (has_recvevent) { -- if (scb->readset && FD_ISSET(s, scb->readset)) { -- do_signal = 1; -- } -- } -- if (has_sendevent) { -- if (!do_signal && scb->writeset && FD_ISSET(s, scb->writeset)) { -- do_signal = 1; -- } -- } -- if (has_errevent) { -- if (!do_signal && scb->exceptset && FD_ISSET(s, scb->exceptset)) { -- do_signal = 1; -- } -- } -- } --#endif /* LWIP_SOCKET_SELECT */ -- if (do_signal) { -- scb->sem_signalled = 1; -- /* For !LWIP_TCPIP_CORE_LOCKING, we don't call SYS_ARCH_UNPROTECT() before signaling -- the semaphore, as this might lead to the select thread taking itself off the list, -- invalidating the semaphore. */ -- sys_sem_signal(SELECT_SEM_PTR(scb->sem)); -- } -- } --#if LWIP_TCPIP_CORE_LOCKING -- } --#else -- /* unlock interrupts with each step */ -- SYS_ARCH_UNPROTECT(lev); -- /* this makes sure interrupt protection time is short */ -- SYS_ARCH_PROTECT(lev); -- if (last_select_cb_ctr != select_cb_ctr) { -- /* someone has changed select_cb_list, restart at the beginning */ -- goto again; -- } -- /* remember the state of select_cb_list to detect changes */ -- last_select_cb_ctr = select_cb_ctr; -- } -- SYS_ARCH_UNPROTECT(lev); --#endif --} --#endif /* LWIP_SOCKET_SELECT || LWIP_SOCKET_POLL */ -- --/** -- * Close one end of a full-duplex connection. -- */ --int --lwip_shutdown(int s, int how) --{ -- struct lwip_sock *sock; -- err_t err; -- u8_t shut_rx = 0, shut_tx = 0; -- -- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_shutdown(%d, how=%d)\n", s, how)); -- -- sock = get_socket(s); -- if (!sock) { -- return -1; -- } -- -- if (sock->conn != NULL) { -- if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_TCP) { -- sock_set_errno(sock, EOPNOTSUPP); -- done_socket(sock); -- return -1; -- } -- } else { -- sock_set_errno(sock, ENOTCONN); -- done_socket(sock); -- return -1; -- } -- -- if (how == SHUT_RD) { -- shut_rx = 1; -- } else if (how == SHUT_WR) { -- shut_tx = 1; -- } else if (how == SHUT_RDWR) { -- shut_rx = 1; -- shut_tx = 1; -- } else { -- sock_set_errno(sock, EINVAL); -- done_socket(sock); -- return -1; -- } -- err = netconn_shutdown(sock->conn, shut_rx, shut_tx); -- -- sock_set_errno(sock, err_to_errno(err)); -- done_socket(sock); -- return (err == ERR_OK ? 0 : -1); --} -- --static int --lwip_getaddrname(int s, struct sockaddr *name, socklen_t *namelen, u8_t local) --{ -- struct lwip_sock *sock; -- union sockaddr_aligned saddr; -- ip_addr_t naddr; -- u16_t port; -- err_t err; -- -- sock = get_socket(s); -- if (!sock) { -- return -1; -- } -- -- /* get the IP address and port */ -- err = netconn_getaddr(sock->conn, &naddr, &port, local); -- if (err != ERR_OK) { -- sock_set_errno(sock, err_to_errno(err)); -- done_socket(sock); -- return -1; -- } -- --#if LWIP_IPV4 && LWIP_IPV6 -- /* Dual-stack: Map IPv4 addresses to IPv4 mapped IPv6 */ -- if (NETCONNTYPE_ISIPV6(netconn_type(sock->conn)) && -- IP_IS_V4_VAL(naddr)) { -- ip4_2_ipv4_mapped_ipv6(ip_2_ip6(&naddr), ip_2_ip4(&naddr)); -- IP_SET_TYPE_VAL(naddr, IPADDR_TYPE_V6); -- } --#endif /* LWIP_IPV4 && LWIP_IPV6 */ -- -- IPADDR_PORT_TO_SOCKADDR(&saddr, &naddr, port); -- -- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getaddrname(%d, addr=", s)); -- ip_addr_debug_print_val(SOCKETS_DEBUG, naddr); -- LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F")\n", port)); -- -- if (*namelen > saddr.sa.sa_len) { -- *namelen = saddr.sa.sa_len; -- } -- MEMCPY(name, &saddr, *namelen); -- -- sock_set_errno(sock, 0); -- done_socket(sock); -- return 0; --} -- --int --lwip_getpeername(int s, struct sockaddr *name, socklen_t *namelen) --{ -- return lwip_getaddrname(s, name, namelen, 0); --} -- --int --lwip_getsockname(int s, struct sockaddr *name, socklen_t *namelen) --{ -- return lwip_getaddrname(s, name, namelen, 1); --} -- --int --lwip_getsockopt(int s, int level, int optname, void *optval, socklen_t *optlen) --{ -- int err; -- struct lwip_sock *sock = get_socket(s); --#if !LWIP_TCPIP_CORE_LOCKING -- err_t cberr; -- LWIP_SETGETSOCKOPT_DATA_VAR_DECLARE(data); --#endif /* !LWIP_TCPIP_CORE_LOCKING */ -- -- if (!sock) { -- return -1; -- } -- -- if ((NULL == optval) || (NULL == optlen)) { -- sock_set_errno(sock, EFAULT); -- done_socket(sock); -- return -1; -- } -- --#if LWIP_TCPIP_CORE_LOCKING -- /* core-locking can just call the -impl function */ -- LOCK_TCPIP_CORE(); -- err = lwip_getsockopt_impl(s, level, optname, optval, optlen); -- UNLOCK_TCPIP_CORE(); -- --#else /* LWIP_TCPIP_CORE_LOCKING */ -- --#if LWIP_MPU_COMPATIBLE -- /* MPU_COMPATIBLE copies the optval data, so check for max size here */ -- if (*optlen > LWIP_SETGETSOCKOPT_MAXOPTLEN) { -- sock_set_errno(sock, ENOBUFS); -- done_socket(sock); -- return -1; -- } --#endif /* LWIP_MPU_COMPATIBLE */ -- -- LWIP_SETGETSOCKOPT_DATA_VAR_ALLOC(data, sock); -- LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).s = s; -- LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).level = level; -- LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optname = optname; -- LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optlen = *optlen; --#if !LWIP_MPU_COMPATIBLE -- LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optval.p = optval; --#endif /* !LWIP_MPU_COMPATIBLE */ -- LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).err = 0; --#if LWIP_NETCONN_SEM_PER_THREAD -- LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).completed_sem = LWIP_NETCONN_THREAD_SEM_GET(); --#else -- LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).completed_sem = &sock->conn->op_completed; --#endif -- cberr = tcpip_callback(lwip_getsockopt_callback, &LWIP_SETGETSOCKOPT_DATA_VAR_REF(data)); -- if (cberr != ERR_OK) { -- LWIP_SETGETSOCKOPT_DATA_VAR_FREE(data); -- sock_set_errno(sock, err_to_errno(cberr)); -- done_socket(sock); -- return -1; -- } -- sys_arch_sem_wait((sys_sem_t *)(LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).completed_sem), 0); -- -- /* write back optlen and optval */ -- *optlen = LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optlen; --#if LWIP_MPU_COMPATIBLE -- MEMCPY(optval, LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optval, -- LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optlen); --#endif /* LWIP_MPU_COMPATIBLE */ -- -- /* maybe lwip_getsockopt_internal has changed err */ -- err = LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).err; -- LWIP_SETGETSOCKOPT_DATA_VAR_FREE(data); --#endif /* LWIP_TCPIP_CORE_LOCKING */ -- -- sock_set_errno(sock, err); -- done_socket(sock); -- return err ? -1 : 0; --} -- --#if !LWIP_TCPIP_CORE_LOCKING --/** lwip_getsockopt_callback: only used without CORE_LOCKING -- * to get into the tcpip_thread -- */ --static void --lwip_getsockopt_callback(void *arg) --{ -- struct lwip_setgetsockopt_data *data; -- LWIP_ASSERT("arg != NULL", arg != NULL); -- data = (struct lwip_setgetsockopt_data *)arg; -- -- data->err = lwip_getsockopt_impl(data->s, data->level, data->optname, --#if LWIP_MPU_COMPATIBLE -- data->optval, --#else /* LWIP_MPU_COMPATIBLE */ -- data->optval.p, --#endif /* LWIP_MPU_COMPATIBLE */ -- &data->optlen); -- -- sys_sem_signal((sys_sem_t *)(data->completed_sem)); --} --#endif /* LWIP_TCPIP_CORE_LOCKING */ -- --static int --lwip_sockopt_to_ipopt(int optname) --{ -- /* Map SO_* values to our internal SOF_* values -- * We should not rely on #defines in socket.h -- * being in sync with ip.h. -- */ -- switch (optname) { -- case SO_BROADCAST: -- return SOF_BROADCAST; -- case SO_KEEPALIVE: -- return SOF_KEEPALIVE; -- case SO_REUSEADDR: -- return SOF_REUSEADDR; -- default: -- LWIP_ASSERT("Unknown socket option", 0); -- return 0; -- } --} -- --/** lwip_getsockopt_impl: the actual implementation of getsockopt: -- * same argument as lwip_getsockopt, either called directly or through callback -- */ --static int --lwip_getsockopt_impl(int s, int level, int optname, void *optval, socklen_t *optlen) --{ -- int err = 0; -- struct lwip_sock *sock = tryget_socket(s); -- if (!sock) { -- return EBADF; -- } -- --#ifdef LWIP_HOOK_SOCKETS_GETSOCKOPT -- if (LWIP_HOOK_SOCKETS_GETSOCKOPT(s, sock, level, optname, optval, optlen, &err)) { -- return err; -- } --#endif -- -- switch (level) { -- -- /* Level: SOL_SOCKET */ -- case SOL_SOCKET: -- switch (optname) { -- --#if LWIP_TCP -- case SO_ACCEPTCONN: -- LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, *optlen, int); -- if (NETCONNTYPE_GROUP(sock->conn->type) != NETCONN_TCP) { -- done_socket(sock); -- return ENOPROTOOPT; -- } -- if ((sock->conn->pcb.tcp != NULL) && (sock->conn->pcb.tcp->state == LISTEN)) { -- *(int *)optval = 1; -- } else { -- *(int *)optval = 0; -- } -- break; --#endif /* LWIP_TCP */ -- -- /* The option flags */ -- case SO_BROADCAST: -- case SO_KEEPALIVE: --#if SO_REUSE -- case SO_REUSEADDR: --#endif /* SO_REUSE */ -- if ((optname == SO_BROADCAST) && -- (NETCONNTYPE_GROUP(sock->conn->type) != NETCONN_UDP)) { -- done_socket(sock); -- return ENOPROTOOPT; -- } -- -- optname = lwip_sockopt_to_ipopt(optname); -- -- LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, *optlen, int); -- *(int *)optval = ip_get_option(sock->conn->pcb.ip, optname); -- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, optname=0x%x, ..) = %s\n", -- s, optname, (*(int *)optval ? "on" : "off"))); -- break; -- -- case SO_TYPE: -- LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, *optlen, int); -- switch (NETCONNTYPE_GROUP(netconn_type(sock->conn))) { -- case NETCONN_RAW: -- *(int *)optval = SOCK_RAW; -- break; -- case NETCONN_TCP: -- *(int *)optval = SOCK_STREAM; -- break; -- case NETCONN_UDP: -- *(int *)optval = SOCK_DGRAM; -- break; -- default: /* unrecognized socket type */ -- *(int *)optval = netconn_type(sock->conn); -- LWIP_DEBUGF(SOCKETS_DEBUG, -- ("lwip_getsockopt(%d, SOL_SOCKET, SO_TYPE): unrecognized socket type %d\n", -- s, *(int *)optval)); -- } /* switch (netconn_type(sock->conn)) */ -- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, SO_TYPE) = %d\n", -- s, *(int *)optval)); -- break; -- -- case SO_ERROR: -- LWIP_SOCKOPT_CHECK_OPTLEN(sock, *optlen, int); -- *(int *)optval = err_to_errno(netconn_err(sock->conn)); -- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, SO_ERROR) = %d\n", -- s, *(int *)optval)); -- break; -- --#if LWIP_SO_SNDTIMEO -- case SO_SNDTIMEO: -- LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, *optlen, LWIP_SO_SNDRCVTIMEO_OPTTYPE); -- LWIP_SO_SNDRCVTIMEO_SET(optval, netconn_get_sendtimeout(sock->conn)); -- break; --#endif /* LWIP_SO_SNDTIMEO */ --#if LWIP_SO_RCVTIMEO -- case SO_RCVTIMEO: -- LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, *optlen, LWIP_SO_SNDRCVTIMEO_OPTTYPE); -- LWIP_SO_SNDRCVTIMEO_SET(optval, netconn_get_recvtimeout(sock->conn)); -- break; --#endif /* LWIP_SO_RCVTIMEO */ --#if LWIP_SO_RCVBUF -- case SO_RCVBUF: -- LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, *optlen, int); -- *(int *)optval = netconn_get_recvbufsize(sock->conn); -- break; --#endif /* LWIP_SO_RCVBUF */ --#if LWIP_SO_LINGER -- case SO_LINGER: { -- s16_t conn_linger; -- struct linger *linger = (struct linger *)optval; -- LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, *optlen, struct linger); -- conn_linger = sock->conn->linger; -- if (conn_linger >= 0) { -- linger->l_onoff = 1; -- linger->l_linger = (int)conn_linger; -- } else { -- linger->l_onoff = 0; -- linger->l_linger = 0; -- } -- } -- break; --#endif /* LWIP_SO_LINGER */ --#if LWIP_UDP -- case SO_NO_CHECK: -- LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, *optlen, int, NETCONN_UDP); --#if LWIP_UDPLITE -- if (udp_is_flag_set(sock->conn->pcb.udp, UDP_FLAGS_UDPLITE)) { -- /* this flag is only available for UDP, not for UDP lite */ -- done_socket(sock); -- return EAFNOSUPPORT; -- } --#endif /* LWIP_UDPLITE */ -- *(int *)optval = udp_is_flag_set(sock->conn->pcb.udp, UDP_FLAGS_NOCHKSUM) ? 1 : 0; -- break; --#endif /* LWIP_UDP*/ -- default: -- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, UNIMPL: optname=0x%x, ..)\n", -- s, optname)); -- err = ENOPROTOOPT; -- break; -- } /* switch (optname) */ -- break; -- -- /* Level: IPPROTO_IP */ -- case IPPROTO_IP: -- switch (optname) { -- case IP_TTL: -- LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, *optlen, int); -- *(int *)optval = sock->conn->pcb.ip->ttl; -- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_TTL) = %d\n", -- s, *(int *)optval)); -- break; -- case IP_TOS: -- LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, *optlen, int); -- *(int *)optval = sock->conn->pcb.ip->tos; -- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_TOS) = %d\n", -- s, *(int *)optval)); -- break; --#if LWIP_IPV4 && LWIP_MULTICAST_TX_OPTIONS && LWIP_UDP -- case IP_MULTICAST_TTL: -- LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, *optlen, u8_t); -- if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_UDP) { -- done_socket(sock); -- return ENOPROTOOPT; -- } -- *(u8_t *)optval = udp_get_multicast_ttl(sock->conn->pcb.udp); -- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_MULTICAST_TTL) = %d\n", -- s, *(int *)optval)); -- break; -- case IP_MULTICAST_IF: -- LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, *optlen, struct in_addr); -- if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_UDP) { -- done_socket(sock); -- return ENOPROTOOPT; -- } -- inet_addr_from_ip4addr((struct in_addr *)optval, udp_get_multicast_netif_addr(sock->conn->pcb.udp)); -- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_MULTICAST_IF) = 0x%"X32_F"\n", -- s, *(u32_t *)optval)); -- break; -- case IP_MULTICAST_LOOP: -- LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, *optlen, u8_t); -- if ((sock->conn->pcb.udp->flags & UDP_FLAGS_MULTICAST_LOOP) != 0) { -- *(u8_t *)optval = 1; -- } else { -- *(u8_t *)optval = 0; -- } -- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_MULTICAST_LOOP) = %d\n", -- s, *(int *)optval)); -- break; --#endif /* LWIP_IPV4 && LWIP_MULTICAST_TX_OPTIONS && LWIP_UDP */ -- default: -- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, UNIMPL: optname=0x%x, ..)\n", -- s, optname)); -- err = ENOPROTOOPT; -- break; -- } /* switch (optname) */ -- break; -- --#if LWIP_TCP -- /* Level: IPPROTO_TCP */ -- case IPPROTO_TCP: -- /* Special case: all IPPROTO_TCP option take an int */ -- LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, *optlen, int, NETCONN_TCP); -- if (sock->conn->pcb.tcp->state == LISTEN) { -- done_socket(sock); -- return EINVAL; -- } -- switch (optname) { -- case TCP_NODELAY: -- *(int *)optval = tcp_nagle_disabled(sock->conn->pcb.tcp); -- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_TCP, TCP_NODELAY) = %s\n", -- s, (*(int *)optval) ? "on" : "off") ); -- break; -- case TCP_KEEPALIVE: -- *(int *)optval = (int)sock->conn->pcb.tcp->keep_idle; -- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_TCP, TCP_KEEPALIVE) = %d\n", -- s, *(int *)optval)); -- break; -- --#if LWIP_TCP_KEEPALIVE -- case TCP_KEEPIDLE: -- *(int *)optval = (int)(sock->conn->pcb.tcp->keep_idle / 1000); -- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_TCP, TCP_KEEPIDLE) = %d\n", -- s, *(int *)optval)); -- break; -- case TCP_KEEPINTVL: -- *(int *)optval = (int)(sock->conn->pcb.tcp->keep_intvl / 1000); -- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_TCP, TCP_KEEPINTVL) = %d\n", -- s, *(int *)optval)); -- break; -- case TCP_KEEPCNT: -- *(int *)optval = (int)sock->conn->pcb.tcp->keep_cnt; -- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_TCP, TCP_KEEPCNT) = %d\n", -- s, *(int *)optval)); -- break; --#endif /* LWIP_TCP_KEEPALIVE */ -- default: -- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_TCP, UNIMPL: optname=0x%x, ..)\n", -- s, optname)); -- err = ENOPROTOOPT; -- break; -- } /* switch (optname) */ -- break; --#endif /* LWIP_TCP */ -- --#if LWIP_IPV6 -- /* Level: IPPROTO_IPV6 */ -- case IPPROTO_IPV6: -- switch (optname) { -- case IPV6_V6ONLY: -- LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, *optlen, int); -- *(int *)optval = (netconn_get_ipv6only(sock->conn) ? 1 : 0); -- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IPV6, IPV6_V6ONLY) = %d\n", -- s, *(int *)optval)); -- break; -- default: -- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IPV6, UNIMPL: optname=0x%x, ..)\n", -- s, optname)); -- err = ENOPROTOOPT; -- break; -- } /* switch (optname) */ -- break; --#endif /* LWIP_IPV6 */ -- --#if LWIP_UDP && LWIP_UDPLITE -- /* Level: IPPROTO_UDPLITE */ -- case IPPROTO_UDPLITE: -- /* Special case: all IPPROTO_UDPLITE option take an int */ -- LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, *optlen, int); -- /* If this is no UDP lite socket, ignore any options. */ -- if (!NETCONNTYPE_ISUDPLITE(netconn_type(sock->conn))) { -- done_socket(sock); -- return ENOPROTOOPT; -- } -- switch (optname) { -- case UDPLITE_SEND_CSCOV: -- *(int *)optval = sock->conn->pcb.udp->chksum_len_tx; -- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_UDPLITE, UDPLITE_SEND_CSCOV) = %d\n", -- s, (*(int *)optval)) ); -- break; -- case UDPLITE_RECV_CSCOV: -- *(int *)optval = sock->conn->pcb.udp->chksum_len_rx; -- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_UDPLITE, UDPLITE_RECV_CSCOV) = %d\n", -- s, (*(int *)optval)) ); -- break; -- default: -- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_UDPLITE, UNIMPL: optname=0x%x, ..)\n", -- s, optname)); -- err = ENOPROTOOPT; -- break; -- } /* switch (optname) */ -- break; --#endif /* LWIP_UDP */ -- /* Level: IPPROTO_RAW */ -- case IPPROTO_RAW: -- switch (optname) { --#if LWIP_IPV6 && LWIP_RAW -- case IPV6_CHECKSUM: -- LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, *optlen, int, NETCONN_RAW); -- if (sock->conn->pcb.raw->chksum_reqd == 0) { -- *(int *)optval = -1; -- } else { -- *(int *)optval = sock->conn->pcb.raw->chksum_offset; -- } -- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_RAW, IPV6_CHECKSUM) = %d\n", -- s, (*(int *)optval)) ); -- break; --#endif /* LWIP_IPV6 && LWIP_RAW */ -- default: -- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_RAW, UNIMPL: optname=0x%x, ..)\n", -- s, optname)); -- err = ENOPROTOOPT; -- break; -- } /* switch (optname) */ -- break; -- default: -- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, level=0x%x, UNIMPL: optname=0x%x, ..)\n", -- s, level, optname)); -- err = ENOPROTOOPT; -- break; -- } /* switch (level) */ -- -- done_socket(sock); -- return err; --} -- --int --lwip_setsockopt(int s, int level, int optname, const void *optval, socklen_t optlen) --{ -- int err = 0; -- struct lwip_sock *sock = get_socket(s); --#if !LWIP_TCPIP_CORE_LOCKING -- err_t cberr; -- LWIP_SETGETSOCKOPT_DATA_VAR_DECLARE(data); --#endif /* !LWIP_TCPIP_CORE_LOCKING */ -- -- if (!sock) { -- return -1; -- } -- -- if (NULL == optval) { -- sock_set_errno(sock, EFAULT); -- done_socket(sock); -- return -1; -- } -- --#if LWIP_TCPIP_CORE_LOCKING -- /* core-locking can just call the -impl function */ -- LOCK_TCPIP_CORE(); -- err = lwip_setsockopt_impl(s, level, optname, optval, optlen); -- UNLOCK_TCPIP_CORE(); -- --#else /* LWIP_TCPIP_CORE_LOCKING */ -- --#if LWIP_MPU_COMPATIBLE -- /* MPU_COMPATIBLE copies the optval data, so check for max size here */ -- if (optlen > LWIP_SETGETSOCKOPT_MAXOPTLEN) { -- sock_set_errno(sock, ENOBUFS); -- done_socket(sock); -- return -1; -- } --#endif /* LWIP_MPU_COMPATIBLE */ -- -- LWIP_SETGETSOCKOPT_DATA_VAR_ALLOC(data, sock); -- LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).s = s; -- LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).level = level; -- LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optname = optname; -- LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optlen = optlen; --#if LWIP_MPU_COMPATIBLE -- MEMCPY(LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optval, optval, optlen); --#else /* LWIP_MPU_COMPATIBLE */ -- LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optval.pc = (const void *)optval; --#endif /* LWIP_MPU_COMPATIBLE */ -- LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).err = 0; --#if LWIP_NETCONN_SEM_PER_THREAD -- LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).completed_sem = LWIP_NETCONN_THREAD_SEM_GET(); --#else -- LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).completed_sem = &sock->conn->op_completed; --#endif -- cberr = tcpip_callback(lwip_setsockopt_callback, &LWIP_SETGETSOCKOPT_DATA_VAR_REF(data)); -- if (cberr != ERR_OK) { -- LWIP_SETGETSOCKOPT_DATA_VAR_FREE(data); -- sock_set_errno(sock, err_to_errno(cberr)); -- done_socket(sock); -- return -1; -- } -- sys_arch_sem_wait((sys_sem_t *)(LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).completed_sem), 0); -- -- /* maybe lwip_getsockopt_internal has changed err */ -- err = LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).err; -- LWIP_SETGETSOCKOPT_DATA_VAR_FREE(data); --#endif /* LWIP_TCPIP_CORE_LOCKING */ -- -- sock_set_errno(sock, err); -- done_socket(sock); -- return err ? -1 : 0; --} -- --#if !LWIP_TCPIP_CORE_LOCKING --/** lwip_setsockopt_callback: only used without CORE_LOCKING -- * to get into the tcpip_thread -- */ --static void --lwip_setsockopt_callback(void *arg) --{ -- struct lwip_setgetsockopt_data *data; -- LWIP_ASSERT("arg != NULL", arg != NULL); -- data = (struct lwip_setgetsockopt_data *)arg; -- -- data->err = lwip_setsockopt_impl(data->s, data->level, data->optname, --#if LWIP_MPU_COMPATIBLE -- data->optval, --#else /* LWIP_MPU_COMPATIBLE */ -- data->optval.pc, --#endif /* LWIP_MPU_COMPATIBLE */ -- data->optlen); -- -- sys_sem_signal((sys_sem_t *)(data->completed_sem)); --} --#endif /* LWIP_TCPIP_CORE_LOCKING */ -- --/** lwip_setsockopt_impl: the actual implementation of setsockopt: -- * same argument as lwip_setsockopt, either called directly or through callback -- */ --static int --lwip_setsockopt_impl(int s, int level, int optname, const void *optval, socklen_t optlen) --{ -- int err = 0; -- struct lwip_sock *sock = tryget_socket(s); -- if (!sock) { -- return EBADF; -- } -- --#ifdef LWIP_HOOK_SOCKETS_SETSOCKOPT -- if (LWIP_HOOK_SOCKETS_SETSOCKOPT(s, sock, level, optname, optval, optlen, &err)) { -- return err; -- } --#endif -- -- switch (level) { -- -- /* Level: SOL_SOCKET */ -- case SOL_SOCKET: -- switch (optname) { -- -- /* SO_ACCEPTCONN is get-only */ -- -- /* The option flags */ -- case SO_BROADCAST: -- case SO_KEEPALIVE: --#if SO_REUSE -- case SO_REUSEADDR: --#endif /* SO_REUSE */ -- if ((optname == SO_BROADCAST) && -- (NETCONNTYPE_GROUP(sock->conn->type) != NETCONN_UDP)) { -- done_socket(sock); -- return ENOPROTOOPT; -- } -- -- optname = lwip_sockopt_to_ipopt(optname); -- -- LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, optlen, int); -- if (*(const int *)optval) { -- ip_set_option(sock->conn->pcb.ip, optname); -- } else { -- ip_reset_option(sock->conn->pcb.ip, optname); -- } -- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, SOL_SOCKET, optname=0x%x, ..) -> %s\n", -- s, optname, (*(const int *)optval ? "on" : "off"))); -- break; -- -- /* SO_TYPE is get-only */ -- /* SO_ERROR is get-only */ -- --#if LWIP_SO_SNDTIMEO -- case SO_SNDTIMEO: { -- long ms_long; -- LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, optlen, LWIP_SO_SNDRCVTIMEO_OPTTYPE); -- ms_long = LWIP_SO_SNDRCVTIMEO_GET_MS(optval); -- if (ms_long < 0) { -- done_socket(sock); -- return EINVAL; -- } -- netconn_set_sendtimeout(sock->conn, ms_long); -- break; -- } --#endif /* LWIP_SO_SNDTIMEO */ --#if LWIP_SO_RCVTIMEO -- case SO_RCVTIMEO: { -- long ms_long; -- LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, optlen, LWIP_SO_SNDRCVTIMEO_OPTTYPE); -- ms_long = LWIP_SO_SNDRCVTIMEO_GET_MS(optval); -- if (ms_long < 0) { -- done_socket(sock); -- return EINVAL; -- } -- netconn_set_recvtimeout(sock->conn, (u32_t)ms_long); -- break; -- } --#endif /* LWIP_SO_RCVTIMEO */ --#if LWIP_SO_RCVBUF -- case SO_RCVBUF: -- LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, optlen, int); -- netconn_set_recvbufsize(sock->conn, *(const int *)optval); -- break; --#endif /* LWIP_SO_RCVBUF */ --#if LWIP_SO_LINGER -- case SO_LINGER: { -- const struct linger *linger = (const struct linger *)optval; -- LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, optlen, struct linger); -- if (linger->l_onoff) { -- int lingersec = linger->l_linger; -- if (lingersec < 0) { -- done_socket(sock); -- return EINVAL; -- } -- if (lingersec > 0xFFFF) { -- lingersec = 0xFFFF; -- } -- sock->conn->linger = (s16_t)lingersec; -- } else { -- sock->conn->linger = -1; -- } -- } -- break; --#endif /* LWIP_SO_LINGER */ --#if LWIP_UDP -- case SO_NO_CHECK: -- LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, int, NETCONN_UDP); --#if LWIP_UDPLITE -- if (udp_is_flag_set(sock->conn->pcb.udp, UDP_FLAGS_UDPLITE)) { -- /* this flag is only available for UDP, not for UDP lite */ -- done_socket(sock); -- return EAFNOSUPPORT; -- } --#endif /* LWIP_UDPLITE */ -- if (*(const int *)optval) { -- udp_set_flags(sock->conn->pcb.udp, UDP_FLAGS_NOCHKSUM); -- } else { -- udp_clear_flags(sock->conn->pcb.udp, UDP_FLAGS_NOCHKSUM); -- } -- break; --#endif /* LWIP_UDP */ -- case SO_BINDTODEVICE: { -- const struct ifreq *iface; -- struct netif *n = NULL; -- -- LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, optlen, struct ifreq); -- -- iface = (const struct ifreq *)optval; -- if (iface->ifr_name[0] != 0) { -- n = netif_find(iface->ifr_name); -- if (n == NULL) { -- done_socket(sock); -- return ENODEV; -- } -- } -- -- switch (NETCONNTYPE_GROUP(netconn_type(sock->conn))) { --#if LWIP_TCP -- case NETCONN_TCP: -- tcp_bind_netif(sock->conn->pcb.tcp, n); -- break; --#endif --#if LWIP_UDP -- case NETCONN_UDP: -- udp_bind_netif(sock->conn->pcb.udp, n); -- break; --#endif --#if LWIP_RAW -- case NETCONN_RAW: -- raw_bind_netif(sock->conn->pcb.raw, n); -- break; --#endif -- default: -- LWIP_ASSERT("Unhandled netconn type in SO_BINDTODEVICE", 0); -- break; -- } -- } -- break; -- default: -- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, SOL_SOCKET, UNIMPL: optname=0x%x, ..)\n", -- s, optname)); -- err = ENOPROTOOPT; -- break; -- } /* switch (optname) */ -- break; -- -- /* Level: IPPROTO_IP */ -- case IPPROTO_IP: -- switch (optname) { -- case IP_TTL: -- LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, optlen, int); -- sock->conn->pcb.ip->ttl = (u8_t)(*(const int *)optval); -- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IP, IP_TTL, ..) -> %d\n", -- s, sock->conn->pcb.ip->ttl)); -- break; -- case IP_TOS: -- LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, optlen, int); -- sock->conn->pcb.ip->tos = (u8_t)(*(const int *)optval); -- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IP, IP_TOS, ..)-> %d\n", -- s, sock->conn->pcb.ip->tos)); -- break; --#if LWIP_NETBUF_RECVINFO -- case IP_PKTINFO: -- LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, int, NETCONN_UDP); -- if (*(const int *)optval) { -- sock->conn->flags |= NETCONN_FLAG_PKTINFO; -- } else { -- sock->conn->flags &= ~NETCONN_FLAG_PKTINFO; -- } -- break; --#endif /* LWIP_NETBUF_RECVINFO */ --#if LWIP_IPV4 && LWIP_MULTICAST_TX_OPTIONS && LWIP_UDP -- case IP_MULTICAST_TTL: -- LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, u8_t, NETCONN_UDP); -- udp_set_multicast_ttl(sock->conn->pcb.udp, (u8_t)(*(const u8_t *)optval)); -- break; -- case IP_MULTICAST_IF: { -- ip4_addr_t if_addr; -- LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, struct in_addr, NETCONN_UDP); -- inet_addr_to_ip4addr(&if_addr, (const struct in_addr *)optval); -- udp_set_multicast_netif_addr(sock->conn->pcb.udp, &if_addr); -- } -- break; -- case IP_MULTICAST_LOOP: -- LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, u8_t, NETCONN_UDP); -- if (*(const u8_t *)optval) { -- udp_set_flags(sock->conn->pcb.udp, UDP_FLAGS_MULTICAST_LOOP); -- } else { -- udp_clear_flags(sock->conn->pcb.udp, UDP_FLAGS_MULTICAST_LOOP); -- } -- break; --#endif /* LWIP_IPV4 && LWIP_MULTICAST_TX_OPTIONS && LWIP_UDP */ --#if LWIP_IGMP -- case IP_ADD_MEMBERSHIP: -- case IP_DROP_MEMBERSHIP: { -- /* If this is a TCP or a RAW socket, ignore these options. */ -- err_t igmp_err; -- const struct ip_mreq *imr = (const struct ip_mreq *)optval; -- ip4_addr_t if_addr; -- ip4_addr_t multi_addr; -- LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, struct ip_mreq, NETCONN_UDP); -- inet_addr_to_ip4addr(&if_addr, &imr->imr_interface); -- inet_addr_to_ip4addr(&multi_addr, &imr->imr_multiaddr); -- if (optname == IP_ADD_MEMBERSHIP) { -- if (!lwip_socket_register_membership(s, &if_addr, &multi_addr)) { -- /* cannot track membership (out of memory) */ -- err = ENOMEM; -- igmp_err = ERR_OK; -- } else { -- igmp_err = igmp_joingroup(&if_addr, &multi_addr); -- } -- } else { -- igmp_err = igmp_leavegroup(&if_addr, &multi_addr); -- lwip_socket_unregister_membership(s, &if_addr, &multi_addr); -- } -- if (igmp_err != ERR_OK) { -- err = EADDRNOTAVAIL; -- } -- } -- break; --#endif /* LWIP_IGMP */ -- default: -- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IP, UNIMPL: optname=0x%x, ..)\n", -- s, optname)); -- err = ENOPROTOOPT; -- break; -- } /* switch (optname) */ -- break; -- --#if LWIP_TCP -- /* Level: IPPROTO_TCP */ -- case IPPROTO_TCP: -- /* Special case: all IPPROTO_TCP option take an int */ -- LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, int, NETCONN_TCP); -- if (sock->conn->pcb.tcp->state == LISTEN) { -- done_socket(sock); -- return EINVAL; -- } -- switch (optname) { -- case TCP_NODELAY: -- if (*(const int *)optval) { -- tcp_nagle_disable(sock->conn->pcb.tcp); -- } else { -- tcp_nagle_enable(sock->conn->pcb.tcp); -- } -- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_NODELAY) -> %s\n", -- s, (*(const int *)optval) ? "on" : "off") ); -- break; -- case TCP_KEEPALIVE: -- sock->conn->pcb.tcp->keep_idle = (u32_t)(*(const int *)optval); -- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPALIVE) -> %"U32_F"\n", -- s, sock->conn->pcb.tcp->keep_idle)); -- break; -- --#if LWIP_TCP_KEEPALIVE -- case TCP_KEEPIDLE: -- sock->conn->pcb.tcp->keep_idle = 1000 * (u32_t)(*(const int *)optval); -- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPIDLE) -> %"U32_F"\n", -- s, sock->conn->pcb.tcp->keep_idle)); -- break; -- case TCP_KEEPINTVL: -- sock->conn->pcb.tcp->keep_intvl = 1000 * (u32_t)(*(const int *)optval); -- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPINTVL) -> %"U32_F"\n", -- s, sock->conn->pcb.tcp->keep_intvl)); -- break; -- case TCP_KEEPCNT: -- sock->conn->pcb.tcp->keep_cnt = (u32_t)(*(const int *)optval); -- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPCNT) -> %"U32_F"\n", -- s, sock->conn->pcb.tcp->keep_cnt)); -- break; --#endif /* LWIP_TCP_KEEPALIVE */ -- default: -- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, UNIMPL: optname=0x%x, ..)\n", -- s, optname)); -- err = ENOPROTOOPT; -- break; -- } /* switch (optname) */ -- break; --#endif /* LWIP_TCP*/ -- --#if LWIP_IPV6 -- /* Level: IPPROTO_IPV6 */ -- case IPPROTO_IPV6: -- switch (optname) { -- case IPV6_V6ONLY: -- LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, optlen, int); -- if (*(const int *)optval) { -- netconn_set_ipv6only(sock->conn, 1); -- } else { -- netconn_set_ipv6only(sock->conn, 0); -- } -- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IPV6, IPV6_V6ONLY, ..) -> %d\n", -- s, (netconn_get_ipv6only(sock->conn) ? 1 : 0))); -- break; --#if LWIP_IPV6_MLD -- case IPV6_JOIN_GROUP: -- case IPV6_LEAVE_GROUP: { -- /* If this is a TCP or a RAW socket, ignore these options. */ -- err_t mld6_err; -- struct netif *netif; -- ip6_addr_t multi_addr; -- const struct ipv6_mreq *imr = (const struct ipv6_mreq *)optval; -- LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, struct ipv6_mreq, NETCONN_UDP); -- inet6_addr_to_ip6addr(&multi_addr, &imr->ipv6mr_multiaddr); -- LWIP_ASSERT("Invalid netif index", imr->ipv6mr_interface <= 0xFFu); -- netif = netif_get_by_index((u8_t)imr->ipv6mr_interface); -- if (netif == NULL) { -- err = EADDRNOTAVAIL; -- break; -- } -- -- if (optname == IPV6_JOIN_GROUP) { -- if (!lwip_socket_register_mld6_membership(s, imr->ipv6mr_interface, &multi_addr)) { -- /* cannot track membership (out of memory) */ -- err = ENOMEM; -- mld6_err = ERR_OK; -- } else { -- mld6_err = mld6_joingroup_netif(netif, &multi_addr); -- } -- } else { -- mld6_err = mld6_leavegroup_netif(netif, &multi_addr); -- lwip_socket_unregister_mld6_membership(s, imr->ipv6mr_interface, &multi_addr); -- } -- if (mld6_err != ERR_OK) { -- err = EADDRNOTAVAIL; -- } -- } -- break; --#endif /* LWIP_IPV6_MLD */ -- default: -- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IPV6, UNIMPL: optname=0x%x, ..)\n", -- s, optname)); -- err = ENOPROTOOPT; -- break; -- } /* switch (optname) */ -- break; --#endif /* LWIP_IPV6 */ -- --#if LWIP_UDP && LWIP_UDPLITE -- /* Level: IPPROTO_UDPLITE */ -- case IPPROTO_UDPLITE: -- /* Special case: all IPPROTO_UDPLITE option take an int */ -- LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, optlen, int); -- /* If this is no UDP lite socket, ignore any options. */ -- if (!NETCONNTYPE_ISUDPLITE(netconn_type(sock->conn))) { -- done_socket(sock); -- return ENOPROTOOPT; -- } -- switch (optname) { -- case UDPLITE_SEND_CSCOV: -- if ((*(const int *)optval != 0) && ((*(const int *)optval < 8) || (*(const int *)optval > 0xffff))) { -- /* don't allow illegal values! */ -- sock->conn->pcb.udp->chksum_len_tx = 8; -- } else { -- sock->conn->pcb.udp->chksum_len_tx = (u16_t) * (const int *)optval; -- } -- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_UDPLITE, UDPLITE_SEND_CSCOV) -> %d\n", -- s, (*(const int *)optval)) ); -- break; -- case UDPLITE_RECV_CSCOV: -- if ((*(const int *)optval != 0) && ((*(const int *)optval < 8) || (*(const int *)optval > 0xffff))) { -- /* don't allow illegal values! */ -- sock->conn->pcb.udp->chksum_len_rx = 8; -- } else { -- sock->conn->pcb.udp->chksum_len_rx = (u16_t) * (const int *)optval; -- } -- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_UDPLITE, UDPLITE_RECV_CSCOV) -> %d\n", -- s, (*(const int *)optval)) ); -- break; -- default: -- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_UDPLITE, UNIMPL: optname=0x%x, ..)\n", -- s, optname)); -- err = ENOPROTOOPT; -- break; -- } /* switch (optname) */ -- break; --#endif /* LWIP_UDP */ -- /* Level: IPPROTO_RAW */ -- case IPPROTO_RAW: -- switch (optname) { --#if LWIP_IPV6 && LWIP_RAW -- case IPV6_CHECKSUM: -- /* It should not be possible to disable the checksum generation with ICMPv6 -- * as per RFC 3542 chapter 3.1 */ -- if (sock->conn->pcb.raw->protocol == IPPROTO_ICMPV6) { -- done_socket(sock); -- return EINVAL; -- } -- -- LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, int, NETCONN_RAW); -- if (*(const int *)optval < 0) { -- sock->conn->pcb.raw->chksum_reqd = 0; -- } else if (*(const int *)optval & 1) { -- /* Per RFC3542, odd offsets are not allowed */ -- done_socket(sock); -- return EINVAL; -- } else { -- sock->conn->pcb.raw->chksum_reqd = 1; -- sock->conn->pcb.raw->chksum_offset = (u16_t) * (const int *)optval; -- } -- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_RAW, IPV6_CHECKSUM, ..) -> %d\n", -- s, sock->conn->pcb.raw->chksum_reqd)); -- break; --#endif /* LWIP_IPV6 && LWIP_RAW */ -- default: -- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_RAW, UNIMPL: optname=0x%x, ..)\n", -- s, optname)); -- err = ENOPROTOOPT; -- break; -- } /* switch (optname) */ -- break; -- default: -- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, level=0x%x, UNIMPL: optname=0x%x, ..)\n", -- s, level, optname)); -- err = ENOPROTOOPT; -- break; -- } /* switch (level) */ -- -- done_socket(sock); -- return err; --} -- --int --lwip_ioctl(int s, long cmd, void *argp) --{ -- struct lwip_sock *sock = get_socket(s); -- u8_t val; --#if LWIP_SO_RCVBUF -- int recv_avail; --#endif /* LWIP_SO_RCVBUF */ -- -- if (!sock) { -- return -1; -- } -- -- switch (cmd) { --#if LWIP_SO_RCVBUF || LWIP_FIONREAD_LINUXMODE -- case FIONREAD: -- if (!argp) { -- sock_set_errno(sock, EINVAL); -- done_socket(sock); -- return -1; -- } --#if LWIP_FIONREAD_LINUXMODE -- if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_TCP) { -- struct netbuf *nb; -- if (sock->lastdata.netbuf) { -- nb = sock->lastdata.netbuf; -- *((int *)argp) = nb->p->tot_len; -- } else { -- struct netbuf *rxbuf; -- err_t err = netconn_recv_udp_raw_netbuf_flags(sock->conn, &rxbuf, NETCONN_DONTBLOCK); -- if (err != ERR_OK) { -- *((int *)argp) = 0; -- } else { -- sock->lastdata.netbuf = rxbuf; -- *((int *)argp) = rxbuf->p->tot_len; -- } -- } -- done_socket(sock); -- return 0; -- } --#endif /* LWIP_FIONREAD_LINUXMODE */ -- --#if LWIP_SO_RCVBUF -- /* we come here if either LWIP_FIONREAD_LINUXMODE==0 or this is a TCP socket */ -- SYS_ARCH_GET(sock->conn->recv_avail, recv_avail); -- if (recv_avail < 0) { -- recv_avail = 0; -- } -- -- /* Check if there is data left from the last recv operation. /maq 041215 */ -- if (sock->lastdata.netbuf) { -- if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) { -- recv_avail += sock->lastdata.pbuf->tot_len; -- } else { -- recv_avail += sock->lastdata.netbuf->p->tot_len; -- } -- } -- *((int *)argp) = recv_avail; -- -- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(%d, FIONREAD, %p) = %"U16_F"\n", s, argp, *((u16_t *)argp))); -- sock_set_errno(sock, 0); -- done_socket(sock); -- return 0; --#else /* LWIP_SO_RCVBUF */ -- break; --#endif /* LWIP_SO_RCVBUF */ --#endif /* LWIP_SO_RCVBUF || LWIP_FIONREAD_LINUXMODE */ -- -- case (long)FIONBIO: -- val = 0; -- if (argp && *(int *)argp) { -- val = 1; -- } -- netconn_set_nonblocking(sock->conn, val); -- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(%d, FIONBIO, %d)\n", s, val)); -- sock_set_errno(sock, 0); -- done_socket(sock); -- return 0; -- -- default: -- break; -- } /* switch (cmd) */ -- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(%d, UNIMPL: 0x%lx, %p)\n", s, cmd, argp)); -- sock_set_errno(sock, ENOSYS); /* not yet implemented */ -- done_socket(sock); -- return -1; --} -- --/** A minimal implementation of fcntl. -- * Currently only the commands F_GETFL and F_SETFL are implemented. -- * The flag O_NONBLOCK and access modes are supported for F_GETFL, only -- * the flag O_NONBLOCK is implemented for F_SETFL. -- */ --int --lwip_fcntl(int s, int cmd, int val) --{ -- struct lwip_sock *sock = get_socket(s); -- int ret = -1; -- int op_mode = 0; -- -- if (!sock) { -- return -1; -- } -- -- switch (cmd) { -- case F_GETFL: -- ret = netconn_is_nonblocking(sock->conn) ? O_NONBLOCK : 0; -- sock_set_errno(sock, 0); -- -- if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) { --#if LWIP_TCPIP_CORE_LOCKING -- LOCK_TCPIP_CORE(); --#else -- SYS_ARCH_DECL_PROTECT(lev); -- /* the proper thing to do here would be to get into the tcpip_thread, -- but locking should be OK as well since we only *read* some flags */ -- SYS_ARCH_PROTECT(lev); --#endif --#if LWIP_TCP -- if (sock->conn->pcb.tcp) { -- if (!(sock->conn->pcb.tcp->flags & TF_RXCLOSED)) { -- op_mode |= O_RDONLY; -- } -- if (!(sock->conn->pcb.tcp->flags & TF_FIN)) { -- op_mode |= O_WRONLY; -- } -- } --#endif --#if LWIP_TCPIP_CORE_LOCKING -- UNLOCK_TCPIP_CORE(); --#else -- SYS_ARCH_UNPROTECT(lev); --#endif -- } else { -- op_mode |= O_RDWR; -- } -- -- /* ensure O_RDWR for (O_RDONLY|O_WRONLY) != O_RDWR cases */ -- ret |= (op_mode == (O_RDONLY | O_WRONLY)) ? O_RDWR : op_mode; -- -- break; -- case F_SETFL: -- /* Bits corresponding to the file access mode and the file creation flags [..] that are set in arg shall be ignored */ -- val &= ~(O_RDONLY | O_WRONLY | O_RDWR); -- if ((val & ~O_NONBLOCK) == 0) { -- /* only O_NONBLOCK, all other bits are zero */ -- netconn_set_nonblocking(sock->conn, val & O_NONBLOCK); -- ret = 0; -- sock_set_errno(sock, 0); -- } else { -- sock_set_errno(sock, ENOSYS); /* not yet implemented */ -- } -- break; -- default: -- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_fcntl(%d, UNIMPL: %d, %d)\n", s, cmd, val)); -- sock_set_errno(sock, ENOSYS); /* not yet implemented */ -- break; -- } -- done_socket(sock); -- return ret; --} -- --#if LWIP_COMPAT_SOCKETS == 2 && LWIP_POSIX_SOCKETS_IO_NAMES --int --fcntl(int s, int cmd, ...) --{ -- va_list ap; -- int val; -- -- va_start(ap, cmd); -- val = va_arg(ap, int); -- va_end(ap); -- return lwip_fcntl(s, cmd, val); --} --#endif -- --const char * --lwip_inet_ntop(int af, const void *src, char *dst, socklen_t size) --{ -- const char *ret = NULL; -- int size_int = (int)size; -- if (size_int < 0) { -- set_errno(ENOSPC); -- return NULL; -- } -- switch (af) { --#if LWIP_IPV4 -- case AF_INET: -- ret = ip4addr_ntoa_r((const ip4_addr_t *)src, dst, size_int); -- if (ret == NULL) { -- set_errno(ENOSPC); -- } -- break; --#endif --#if LWIP_IPV6 -- case AF_INET6: -- ret = ip6addr_ntoa_r((const ip6_addr_t *)src, dst, size_int); -- if (ret == NULL) { -- set_errno(ENOSPC); -- } -- break; --#endif -- default: -- set_errno(EAFNOSUPPORT); -- break; -- } -- return ret; --} -- --int --lwip_inet_pton(int af, const char *src, void *dst) --{ -- int err; -- switch (af) { --#if LWIP_IPV4 -- case AF_INET: -- err = ip4addr_aton(src, (ip4_addr_t *)dst); -- break; --#endif --#if LWIP_IPV6 -- case AF_INET6: { -- /* convert into temporary variable since ip6_addr_t might be larger -- than in6_addr when scopes are enabled */ -- ip6_addr_t addr; -- err = ip6addr_aton(src, &addr); -- if (err) { -- memcpy(dst, &addr.addr, sizeof(addr.addr)); -- } -- break; -- } --#endif -- default: -- err = -1; -- set_errno(EAFNOSUPPORT); -- break; -- } -- return err; --} -- --#if LWIP_IGMP --/** Register a new IGMP membership. On socket close, the membership is dropped automatically. -- * -- * ATTENTION: this function is called from tcpip_thread (or under CORE_LOCK). -- * -- * @return 1 on success, 0 on failure -- */ --static int --lwip_socket_register_membership(int s, const ip4_addr_t *if_addr, const ip4_addr_t *multi_addr) --{ -- struct lwip_sock *sock = get_socket(s); -- int i; -- -- if (!sock) { -- return 0; -- } -- -- for (i = 0; i < LWIP_SOCKET_MAX_MEMBERSHIPS; i++) { -- if (socket_ipv4_multicast_memberships[i].sock == NULL) { -- socket_ipv4_multicast_memberships[i].sock = sock; -- ip4_addr_copy(socket_ipv4_multicast_memberships[i].if_addr, *if_addr); -- ip4_addr_copy(socket_ipv4_multicast_memberships[i].multi_addr, *multi_addr); -- done_socket(sock); -- return 1; -- } -- } -- done_socket(sock); -- return 0; --} -- --/** Unregister a previously registered membership. This prevents dropping the membership -- * on socket close. -- * -- * ATTENTION: this function is called from tcpip_thread (or under CORE_LOCK). -- */ --static void --lwip_socket_unregister_membership(int s, const ip4_addr_t *if_addr, const ip4_addr_t *multi_addr) --{ -- struct lwip_sock *sock = get_socket(s); -- int i; -- -- if (!sock) { -- return; -- } -- -- for (i = 0; i < LWIP_SOCKET_MAX_MEMBERSHIPS; i++) { -- if ((socket_ipv4_multicast_memberships[i].sock == sock) && -- ip4_addr_cmp(&socket_ipv4_multicast_memberships[i].if_addr, if_addr) && -- ip4_addr_cmp(&socket_ipv4_multicast_memberships[i].multi_addr, multi_addr)) { -- socket_ipv4_multicast_memberships[i].sock = NULL; -- ip4_addr_set_zero(&socket_ipv4_multicast_memberships[i].if_addr); -- ip4_addr_set_zero(&socket_ipv4_multicast_memberships[i].multi_addr); -- break; -- } -- } -- done_socket(sock); --} -- --/** Drop all memberships of a socket that were not dropped explicitly via setsockopt. -- * -- * ATTENTION: this function is NOT called from tcpip_thread (or under CORE_LOCK). -- */ --static void --lwip_socket_drop_registered_memberships(int s) --{ -- struct lwip_sock *sock = get_socket(s); -- int i; -- -- if (!sock) { -- return; -- } -- -- for (i = 0; i < LWIP_SOCKET_MAX_MEMBERSHIPS; i++) { -- if (socket_ipv4_multicast_memberships[i].sock == sock) { -- ip_addr_t multi_addr, if_addr; -- ip_addr_copy_from_ip4(multi_addr, socket_ipv4_multicast_memberships[i].multi_addr); -- ip_addr_copy_from_ip4(if_addr, socket_ipv4_multicast_memberships[i].if_addr); -- socket_ipv4_multicast_memberships[i].sock = NULL; -- ip4_addr_set_zero(&socket_ipv4_multicast_memberships[i].if_addr); -- ip4_addr_set_zero(&socket_ipv4_multicast_memberships[i].multi_addr); -- -- netconn_join_leave_group(sock->conn, &multi_addr, &if_addr, NETCONN_LEAVE); -- } -- } -- done_socket(sock); --} --#endif /* LWIP_IGMP */ -- --#if LWIP_IPV6_MLD --/** Register a new MLD6 membership. On socket close, the membership is dropped automatically. -- * -- * ATTENTION: this function is called from tcpip_thread (or under CORE_LOCK). -- * -- * @return 1 on success, 0 on failure -- */ --static int --lwip_socket_register_mld6_membership(int s, unsigned int if_idx, const ip6_addr_t *multi_addr) --{ -- struct lwip_sock *sock = get_socket(s); -- int i; -- -- if (!sock) { -- return 0; -- } -- -- for (i = 0; i < LWIP_SOCKET_MAX_MEMBERSHIPS; i++) { -- if (socket_ipv6_multicast_memberships[i].sock == NULL) { -- socket_ipv6_multicast_memberships[i].sock = sock; -- socket_ipv6_multicast_memberships[i].if_idx = (u8_t)if_idx; -- ip6_addr_copy(socket_ipv6_multicast_memberships[i].multi_addr, *multi_addr); -- done_socket(sock); -- return 1; -- } -- } -- done_socket(sock); -- return 0; --} -- --/** Unregister a previously registered MLD6 membership. This prevents dropping the membership -- * on socket close. -- * -- * ATTENTION: this function is called from tcpip_thread (or under CORE_LOCK). -- */ --static void --lwip_socket_unregister_mld6_membership(int s, unsigned int if_idx, const ip6_addr_t *multi_addr) --{ -- struct lwip_sock *sock = get_socket(s); -- int i; -- -- if (!sock) { -- return; -- } -- -- for (i = 0; i < LWIP_SOCKET_MAX_MEMBERSHIPS; i++) { -- if ((socket_ipv6_multicast_memberships[i].sock == sock) && -- (socket_ipv6_multicast_memberships[i].if_idx == if_idx) && -- ip6_addr_cmp(&socket_ipv6_multicast_memberships[i].multi_addr, multi_addr)) { -- socket_ipv6_multicast_memberships[i].sock = NULL; -- socket_ipv6_multicast_memberships[i].if_idx = NETIF_NO_INDEX; -- ip6_addr_set_zero(&socket_ipv6_multicast_memberships[i].multi_addr); -- break; -- } -- } -- done_socket(sock); --} -- --/** Drop all MLD6 memberships of a socket that were not dropped explicitly via setsockopt. -- * -- * ATTENTION: this function is NOT called from tcpip_thread (or under CORE_LOCK). -- */ --static void --lwip_socket_drop_registered_mld6_memberships(int s) --{ -- struct lwip_sock *sock = get_socket(s); -- int i; -- -- if (!sock) { -- return; -- } -- -- for (i = 0; i < LWIP_SOCKET_MAX_MEMBERSHIPS; i++) { -- if (socket_ipv6_multicast_memberships[i].sock == sock) { -- ip_addr_t multi_addr; -- u8_t if_idx; -- -- ip_addr_copy_from_ip6(multi_addr, socket_ipv6_multicast_memberships[i].multi_addr); -- if_idx = socket_ipv6_multicast_memberships[i].if_idx; -- -- socket_ipv6_multicast_memberships[i].sock = NULL; -- socket_ipv6_multicast_memberships[i].if_idx = NETIF_NO_INDEX; -- ip6_addr_set_zero(&socket_ipv6_multicast_memberships[i].multi_addr); -- -- netconn_join_leave_group_netif(sock->conn, &multi_addr, if_idx, NETCONN_LEAVE); -- } -- } -- done_socket(sock); --} --#endif /* LWIP_IPV6_MLD */ -- --#endif /* LWIP_SOCKET */ -+/** -+ * @file -+ * Sockets BSD-Like API module -+ */ -+ -+/* -+ * 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 -+ * -+ * Improved by Marc Boucher and David Haas -+ * -+ */ -+ -+#include "lwip/opt.h" -+ -+#if LWIP_SOCKET /* don't build if not configured for use in lwipopts.h */ -+ -+#include "lwip/sockets.h" -+#include "lwip/priv/sockets_priv.h" -+#include "lwip/api.h" -+#include "lwip/igmp.h" -+#include "lwip/inet.h" -+#include "lwip/tcp.h" -+#include "lwip/raw.h" -+#include "lwip/udp.h" -+#include "lwip/memp.h" -+#include "lwip/pbuf.h" -+#include "lwip/netif.h" -+#include "lwip/priv/tcpip_priv.h" -+#include "lwip/mld6.h" -+#include "lwip/dhcp.h" -+#if LWIP_CHECKSUM_ON_COPY -+#include "lwip/inet_chksum.h" -+#endif -+ -+#if LWIP_COMPAT_SOCKETS == 2 && LWIP_POSIX_SOCKETS_IO_NAMES -+#include -+#endif -+ -+#include -+ -+#ifdef LWIP_HOOK_FILENAME -+#include LWIP_HOOK_FILENAME -+#endif -+ -+/* If the netconn API is not required publicly, then we include the necessary -+ files here to get the implementation */ -+#if !LWIP_NETCONN -+#undef LWIP_NETCONN -+#define LWIP_NETCONN 1 -+#include "api_msg.c" -+#include "api_lib.c" -+#include "netbuf.c" -+#undef LWIP_NETCONN -+#define LWIP_NETCONN 0 -+#endif -+ -+#define API_SELECT_CB_VAR_REF(name) API_VAR_REF(name) -+#define API_SELECT_CB_VAR_DECLARE(name) API_VAR_DECLARE(struct lwip_select_cb, name) -+#define API_SELECT_CB_VAR_ALLOC(name, retblock) API_VAR_ALLOC_EXT(struct lwip_select_cb, MEMP_SELECT_CB, name, retblock) -+#define API_SELECT_CB_VAR_FREE(name) API_VAR_FREE(MEMP_SELECT_CB, name) -+ -+#if !LWIP_LITEOS_COMPAT -+#defeine SIN4_LEN(x) \ -+ (x)->sin_len = sizeof(struct sockaddr_in) -+#defeine SIN6_LEN(x) \ -+ (x)->sin6_len = sizeof(struct sockaddr_in6) -+#else -+#define SIN4_LEN(x) -+#define SIN6_LEN(x) -+#endif /* LWIP_LITEOS_COMPAT */ -+ -+#if LWIP_IPV4 -+#define IP4ADDR_PORT_TO_SOCKADDR(sin, ipaddr, port) do { \ -+ SIN4_LEN(sin); \ -+ (sin)->sin_family = AF_INET; \ -+ (sin)->sin_port = lwip_htons((port)); \ -+ inet_addr_from_ip4addr(&(sin)->sin_addr, ipaddr); \ -+ memset((sin)->sin_zero, 0, SIN_ZERO_LEN); }while(0) -+#define SOCKADDR4_TO_IP4ADDR_PORT(sin, ipaddr, port) do { \ -+ inet_addr_to_ip4addr(ip_2_ip4(ipaddr), &((sin)->sin_addr)); \ -+ (port) = lwip_ntohs((sin)->sin_port); }while(0) -+#endif /* LWIP_IPV4 */ -+ -+#if LWIP_IPV6 -+/* SIN6_LEN macro is to differntiate whether stack is using 4.3BSD or 4.4BSD variants of sockaddr_in6 -+structure */ -+#define IP6ADDR_PORT_TO_SOCKADDR(sin6, ipaddr, port) do { \ -+ SIN6_LEN(sin6); \ -+ (sin6)->sin6_family = AF_INET6; \ -+ (sin6)->sin6_port = lwip_htons((port)); \ -+ (sin6)->sin6_flowinfo = 0; \ -+ inet6_addr_from_ip6addr(&(sin6)->sin6_addr, ipaddr); \ -+ (sin6)->sin6_scope_id = ip6_addr_zone(ipaddr); }while(0) -+#define SOCKADDR6_TO_IP6ADDR_PORT(sin6, ipaddr, port) do { \ -+ inet6_addr_to_ip6addr(ip_2_ip6(ipaddr), &((sin6)->sin6_addr)); \ -+ if (ip6_addr_has_scope(ip_2_ip6(ipaddr), IP6_UNKNOWN)) { \ -+ ip6_addr_set_zone(ip_2_ip6(ipaddr), (u8_t)((sin6)->sin6_scope_id)); \ -+ } \ -+ (port) = lwip_ntohs((sin6)->sin6_port); }while(0) -+#endif /* LWIP_IPV6 */ -+ -+#if LWIP_IPV4 && LWIP_IPV6 -+static void sockaddr_to_ipaddr_port(const struct sockaddr *sockaddr, ip_addr_t *ipaddr, u16_t *port); -+ -+#define IS_SOCK_ADDR_LEN_VALID(namelen) (((namelen) == sizeof(struct sockaddr_in)) || \ -+ ((namelen) == sizeof(struct sockaddr_in6))) -+#define IS_SOCK_ADDR_TYPE_VALID(name) (((name)->sa_family == AF_INET) || \ -+ ((name)->sa_family == AF_INET6)) -+#define SOCK_ADDR_TYPE_MATCH(name, sock) \ -+ ((((name)->sa_family == AF_INET) && !(NETCONNTYPE_ISIPV6((sock)->conn->type))) || \ -+ (((name)->sa_family == AF_INET6) && (NETCONNTYPE_ISIPV6((sock)->conn->type)))) -+#define IPADDR_PORT_TO_SOCKADDR(sockaddr, ipaddr, port) do { \ -+ if (IP_IS_ANY_TYPE_VAL(*ipaddr) || IP_IS_V6_VAL(*ipaddr)) { \ -+ IP6ADDR_PORT_TO_SOCKADDR((struct sockaddr_in6*)(void*)(sockaddr), ip_2_ip6(ipaddr), port); \ -+ } else { \ -+ IP4ADDR_PORT_TO_SOCKADDR((struct sockaddr_in*)(void*)(sockaddr), ip_2_ip4(ipaddr), port); \ -+ } } while(0) -+#define SOCKADDR_TO_IPADDR_PORT(sockaddr, ipaddr, port) sockaddr_to_ipaddr_port(sockaddr, ipaddr, &(port)) -+#define DOMAIN_TO_NETCONN_TYPE(domain, type) (((domain) == AF_INET) ? \ -+ (type) : (enum netconn_type)((type) | NETCONN_TYPE_IPV6)) -+#elif LWIP_IPV6 /* LWIP_IPV4 && LWIP_IPV6 */ -+#define IS_SOCK_ADDR_LEN_VALID(namelen) ((namelen) == sizeof(struct sockaddr_in6)) -+#define IS_SOCK_ADDR_TYPE_VALID(name) ((name)->sa_family == AF_INET6) -+#define SOCK_ADDR_TYPE_MATCH(name, sock) 1 -+#define IPADDR_PORT_TO_SOCKADDR(sockaddr, ipaddr, port) \ -+ IP6ADDR_PORT_TO_SOCKADDR((struct sockaddr_in6*)(void*)(sockaddr), ip_2_ip6(ipaddr), port) -+#define SOCKADDR_TO_IPADDR_PORT(sockaddr, ipaddr, port) \ -+ SOCKADDR6_TO_IP6ADDR_PORT((const struct sockaddr_in6*)(const void*)(sockaddr), ipaddr, port) -+#define DOMAIN_TO_NETCONN_TYPE(domain, netconn_type) (netconn_type) -+#else /*-> LWIP_IPV4: LWIP_IPV4 && LWIP_IPV6 */ -+#define IS_SOCK_ADDR_LEN_VALID(namelen) ((namelen) == sizeof(struct sockaddr_in)) -+#define IS_SOCK_ADDR_TYPE_VALID(name) ((name)->sa_family == AF_INET) -+#define SOCK_ADDR_TYPE_MATCH(name, sock) 1 -+#define IPADDR_PORT_TO_SOCKADDR(sockaddr, ipaddr, port) \ -+ IP4ADDR_PORT_TO_SOCKADDR((struct sockaddr_in*)(void*)(sockaddr), ip_2_ip4(ipaddr), port) -+#define SOCKADDR_TO_IPADDR_PORT(sockaddr, ipaddr, port) \ -+ SOCKADDR4_TO_IP4ADDR_PORT((const struct sockaddr_in*)(const void*)(sockaddr), ipaddr, port) -+#define DOMAIN_TO_NETCONN_TYPE(domain, netconn_type) (netconn_type) -+#endif /* LWIP_IPV6 */ -+ -+#define IS_SOCK_ADDR_TYPE_VALID_OR_UNSPEC(name) (((name)->sa_family == AF_UNSPEC) || \ -+ IS_SOCK_ADDR_TYPE_VALID(name)) -+#define SOCK_ADDR_TYPE_MATCH_OR_UNSPEC(name, sock) (((name)->sa_family == AF_UNSPEC) || \ -+ SOCK_ADDR_TYPE_MATCH(name, sock)) -+#define IS_SOCK_ADDR_ALIGNED(name) ((((mem_ptr_t)(name)) % 4) == 0) -+ -+ -+#define LWIP_SOCKOPT_CHECK_OPTLEN(sock, optlen, opttype) do { if ((optlen) < sizeof(opttype)) { done_socket(sock); return EINVAL; }}while(0) -+#define LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, optlen, opttype) do { \ -+ LWIP_SOCKOPT_CHECK_OPTLEN(sock, optlen, opttype); \ -+ if ((sock)->conn == NULL) { done_socket(sock); return EINVAL; } }while(0) -+#define LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, optlen, opttype) do { \ -+ LWIP_SOCKOPT_CHECK_OPTLEN(sock, optlen, opttype); \ -+ if (((sock)->conn == NULL) || ((sock)->conn->pcb.tcp == NULL)) { done_socket(sock); return EINVAL; } }while(0) -+#define LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, opttype, netconntype) do { \ -+ LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, optlen, opttype); \ -+ if (NETCONNTYPE_GROUP(netconn_type((sock)->conn)) != netconntype) { done_socket(sock); return ENOPROTOOPT; } }while(0) -+ -+ -+#define LWIP_SETGETSOCKOPT_DATA_VAR_REF(name) API_VAR_REF(name) -+#define LWIP_SETGETSOCKOPT_DATA_VAR_DECLARE(name) API_VAR_DECLARE(struct lwip_setgetsockopt_data, name) -+#define LWIP_SETGETSOCKOPT_DATA_VAR_FREE(name) API_VAR_FREE(MEMP_SOCKET_SETGETSOCKOPT_DATA, name) -+#if LWIP_MPU_COMPATIBLE -+#define LWIP_SETGETSOCKOPT_DATA_VAR_ALLOC(name, sock) do { \ -+ name = (struct lwip_setgetsockopt_data *)memp_malloc(MEMP_SOCKET_SETGETSOCKOPT_DATA); \ -+ if (name == NULL) { \ -+ sock_set_errno(sock, ENOMEM); \ -+ done_socket(sock); \ -+ return -1; \ -+ } }while(0) -+#else /* LWIP_MPU_COMPATIBLE */ -+#define LWIP_SETGETSOCKOPT_DATA_VAR_ALLOC(name, sock) -+#endif /* LWIP_MPU_COMPATIBLE */ -+ -+#if LWIP_SO_SNDRCVTIMEO_NONSTANDARD -+#define LWIP_SO_SNDRCVTIMEO_OPTTYPE int -+#define LWIP_SO_SNDRCVTIMEO_SET(optval, val) (*(int *)(optval) = (val)) -+#define LWIP_SO_SNDRCVTIMEO_GET_MS(optval) ((long)*(const int*)(optval)) -+#else -+#define LWIP_SO_SNDRCVTIMEO_OPTTYPE struct timeval -+#define LWIP_SO_SNDRCVTIMEO_SET(optval, val) do { \ -+ u32_t loc = (val); \ -+ ((struct timeval *)(optval))->tv_sec = (long)((loc) / 1000U); \ -+ ((struct timeval *)(optval))->tv_usec = (long)(((loc) % 1000U) * 1000U); }while(0) -+#define LWIP_SO_SNDRCVTIMEO_GET_MS(optval) ((((const struct timeval *)(optval))->tv_sec * 1000) + (((const struct timeval *)(optval))->tv_usec / 1000)) -+#endif -+ -+ -+/** A struct sockaddr replacement that has the same alignment as sockaddr_in/ -+ * sockaddr_in6 if instantiated. -+ */ -+union sockaddr_aligned { -+ struct sockaddr sa; -+#if LWIP_IPV6 -+ struct sockaddr_in6 sin6; -+#endif /* LWIP_IPV6 */ -+#if LWIP_IPV4 -+ struct sockaddr_in sin; -+#endif /* LWIP_IPV4 */ -+}; -+ -+/* Define the number of IPv4 multicast memberships, default is one per socket */ -+#ifndef LWIP_SOCKET_MAX_MEMBERSHIPS -+#define LWIP_SOCKET_MAX_MEMBERSHIPS NUM_SOCKETS -+#endif -+ -+#if LWIP_IGMP -+/* This is to keep track of IP_ADD_MEMBERSHIP calls to drop the membership when -+ a socket is closed */ -+struct lwip_socket_multicast_pair { -+ /** the socket */ -+ struct lwip_sock *sock; -+ /** the interface address */ -+ ip4_addr_t if_addr; -+ /** the group address */ -+ ip4_addr_t multi_addr; -+}; -+ -+static struct lwip_socket_multicast_pair socket_ipv4_multicast_memberships[LWIP_SOCKET_MAX_MEMBERSHIPS]; -+ -+static int lwip_socket_register_membership(int s, const ip4_addr_t *if_addr, const ip4_addr_t *multi_addr); -+static void lwip_socket_unregister_membership(int s, const ip4_addr_t *if_addr, const ip4_addr_t *multi_addr); -+static void lwip_socket_drop_registered_memberships(int s); -+#endif /* LWIP_IGMP */ -+ -+#if LWIP_IPV6_MLD -+/* This is to keep track of IP_JOIN_GROUP calls to drop the membership when -+ a socket is closed */ -+struct lwip_socket_multicast_mld6_pair { -+ /** the socket */ -+ struct lwip_sock *sock; -+ /** the interface index */ -+ u8_t if_idx; -+ /** the group address */ -+ ip6_addr_t multi_addr; -+}; -+ -+static struct lwip_socket_multicast_mld6_pair socket_ipv6_multicast_memberships[LWIP_SOCKET_MAX_MEMBERSHIPS]; -+ -+static int lwip_socket_register_mld6_membership(int s, unsigned int if_idx, const ip6_addr_t *multi_addr); -+static void lwip_socket_unregister_mld6_membership(int s, unsigned int if_idx, const ip6_addr_t *multi_addr); -+static void lwip_socket_drop_registered_mld6_memberships(int s); -+#endif /* LWIP_IPV6_MLD */ -+ -+/** The global array of available sockets */ -+static struct lwip_sock sockets[NUM_SOCKETS]; -+ -+#if LWIP_SOCKET_SELECT || LWIP_SOCKET_POLL -+#if LWIP_TCPIP_CORE_LOCKING -+/* protect the select_cb_list using core lock */ -+#define LWIP_SOCKET_SELECT_DECL_PROTECT(lev) -+#define LWIP_SOCKET_SELECT_PROTECT(lev) LOCK_TCPIP_CORE() -+#define LWIP_SOCKET_SELECT_UNPROTECT(lev) UNLOCK_TCPIP_CORE() -+#else /* LWIP_TCPIP_CORE_LOCKING */ -+/* protect the select_cb_list using SYS_LIGHTWEIGHT_PROT */ -+#define LWIP_SOCKET_SELECT_DECL_PROTECT(lev) SYS_ARCH_DECL_PROTECT(lev) -+#define LWIP_SOCKET_SELECT_PROTECT(lev) SYS_ARCH_PROTECT(lev) -+#define LWIP_SOCKET_SELECT_UNPROTECT(lev) SYS_ARCH_UNPROTECT(lev) -+/** This counter is increased from lwip_select when the list is changed -+ and checked in select_check_waiters to see if it has changed. */ -+static volatile int select_cb_ctr; -+#endif /* LWIP_TCPIP_CORE_LOCKING */ -+/** The global list of tasks waiting for select */ -+static struct lwip_select_cb *select_cb_list; -+#endif /* LWIP_SOCKET_SELECT || LWIP_SOCKET_POLL */ -+ -+#define sock_set_errno(sk, e) do { \ -+ const int sockerr = (e); \ -+ set_errno(sockerr); \ -+} while (0) -+ -+#if LWIP_LITEOS_COMPAT -+#define VALIDATE_GET_RAW_OPTNAME_RET(_sock, _optname) do { \ -+ if ((_sock)->conn != NULL && (NETCONNTYPE_GROUP((_sock)->conn->type) == NETCONN_RAW) && \ -+ (((_optname) != SO_BROADCAST) && ((_optname) != SO_RCVTIMEO) && \ -+ ((_optname) != SO_RCVBUF) && ((_optname) != SO_TYPE) && \ -+ ((_optname) != SO_DONTROUTE) && ((_optname) != SO_BINDTODEVICE))) { \ -+ done_socket(_sock); \ -+ return ENOPROTOOPT; \ -+ } \ -+ } while (0) -+ -+#if PF_PACKET_SOCKET -+#define VALIDATE_SET_PF_PKT_OPTNAME_RET(_s, _sock, _level, _optname) do { \ -+ if ((_level) == SOL_PACKET && ((_optname) != SO_RCVTIMEO && (_optname) != SO_RCVBUF) && \ -+ (_optname) != SO_ATTACH_FILTER && (_optname) != SO_DETACH_FILTER) { \ -+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, SOL_PACKET, UNIMPL: optname=0x%x, ..)\n", \ -+ (_s), (_optname))); \ -+ done_socket(_sock); \ -+ return ENOPROTOOPT; \ -+ } \ -+ } while (0) -+ -+#define VALIDATE_GET_PF_PKT_OPTNAME_RET(_s,_sock,_level,_optname) do { \ -+ if ((_sock)->conn != NULL && (NETCONNTYPE_GROUP((_sock)->conn->type) == NETCONN_PACKET_RAW) && \ -+ (_level) == SOL_PACKET && ((_optname) != SO_RCVTIMEO && (_optname) != SO_RCVBUF && (_optname) != SO_TYPE)) { \ -+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%p, SOL_PACKET, UNIMPL: optname=0x%x, ..)\n", \ -+ (_s), (_optname))); \ -+ done_socket(_sock); \ -+ return ENOPROTOOPT; \ -+ } \ -+ } while (0) -+ -+#define VALIDATE_LEVEL_PF_PACKET(_sock,_level) \ -+ if ((_sock)->conn != NULL && ((NETCONNTYPE_GROUP(netconn_type(_sock->conn)) == NETCONN_PACKET_RAW \ -+ && SOL_SOCKET != (_level) && SOL_PACKET != (_level)) || \ -+ (NETCONNTYPE_GROUP((_sock)->conn->type) != NETCONN_PACKET_RAW && SOL_PACKET == (_level)))) -+#endif -+#endif /* LWIP_LITEOS_COMPAT */ -+ -+/* Forward declaration of some functions */ -+#if LWIP_SOCKET_SELECT || LWIP_SOCKET_POLL -+static void event_callback(struct netconn *conn, enum netconn_evt evt, u16_t len); -+#define DEFAULT_SOCKET_EVENTCB event_callback -+static void select_check_waiters(int s, int has_recvevent, int has_sendevent, int has_errevent); -+#else -+#define DEFAULT_SOCKET_EVENTCB NULL -+#endif -+#if !LWIP_TCPIP_CORE_LOCKING -+static void lwip_getsockopt_callback(void *arg); -+static void lwip_setsockopt_callback(void *arg); -+#endif -+static int lwip_getsockopt_impl(int s, int level, int optname, void *optval, socklen_t *optlen); -+static int lwip_setsockopt_impl(int s, int level, int optname, const void *optval, socklen_t optlen); -+static int free_socket_locked(struct lwip_sock *sock, int is_tcp, struct netconn **conn, -+ union lwip_sock_lastdata *lastdata); -+static void free_socket_free_elements(int is_tcp, struct netconn *conn, union lwip_sock_lastdata *lastdata); -+ -+#if LWIP_IPV4 && LWIP_IPV6 -+static void -+sockaddr_to_ipaddr_port(const struct sockaddr *sockaddr, ip_addr_t *ipaddr, u16_t *port) -+{ -+ if ((sockaddr->sa_family) == AF_INET6) { -+ SOCKADDR6_TO_IP6ADDR_PORT((const struct sockaddr_in6 *)(const void *)(sockaddr), ipaddr, *port); -+ ipaddr->type = IPADDR_TYPE_V6; -+ } else { -+ SOCKADDR4_TO_IP4ADDR_PORT((const struct sockaddr_in *)(const void *)(sockaddr), ipaddr, *port); -+ ipaddr->type = IPADDR_TYPE_V4; -+ } -+} -+#endif /* LWIP_IPV4 && LWIP_IPV6 */ -+ -+/** LWIP_NETCONN_SEM_PER_THREAD==1: initialize thread-local semaphore */ -+void -+lwip_socket_thread_init(void) -+{ -+ netconn_thread_init(); -+} -+ -+/** LWIP_NETCONN_SEM_PER_THREAD==1: destroy thread-local semaphore */ -+void -+lwip_socket_thread_cleanup(void) -+{ -+ netconn_thread_cleanup(); -+} -+ -+#if LWIP_NETCONN_FULLDUPLEX -+/* Thread-safe increment of sock->fd_used, with overflow check */ -+static int -+sock_inc_used(struct lwip_sock *sock) -+{ -+ int ret; -+ SYS_ARCH_DECL_PROTECT(lev); -+ -+ LWIP_ASSERT("sock != NULL", sock != NULL); -+ -+ SYS_ARCH_PROTECT(lev); -+ if (sock->fd_free_pending) { -+ /* prevent new usage of this socket if free is pending */ -+ ret = 0; -+ } else { -+ ++sock->fd_used; -+ ret = 1; -+ LWIP_ASSERT("sock->fd_used != 0", sock->fd_used != 0); -+ } -+ SYS_ARCH_UNPROTECT(lev); -+ return ret; -+} -+ -+/* Like sock_inc_used(), but called under SYS_ARCH_PROTECT lock. */ -+static int -+sock_inc_used_locked(struct lwip_sock *sock) -+{ -+ LWIP_ASSERT("sock != NULL", sock != NULL); -+ -+ if (sock->fd_free_pending) { -+ LWIP_ASSERT("sock->fd_used != 0", sock->fd_used != 0); -+ return 0; -+ } -+ -+ ++sock->fd_used; -+ LWIP_ASSERT("sock->fd_used != 0", sock->fd_used != 0); -+ return 1; -+} -+ -+/* In full-duplex mode,sock->fd_used != 0 prevents a socket descriptor from being -+ * released (and possibly reused) when used from more than one thread -+ * (e.g. read-while-write or close-while-write, etc) -+ * This function is called at the end of functions using (try)get_socket*(). -+ */ -+static void -+done_socket(struct lwip_sock *sock) -+{ -+ int freed = 0; -+ int is_tcp = 0; -+ struct netconn *conn = NULL; -+ union lwip_sock_lastdata lastdata; -+ SYS_ARCH_DECL_PROTECT(lev); -+ LWIP_ASSERT("sock != NULL", sock != NULL); -+ -+ SYS_ARCH_PROTECT(lev); -+ LWIP_ASSERT("sock->fd_used > 0", sock->fd_used > 0); -+ if (--sock->fd_used == 0) { -+ if (sock->fd_free_pending) { -+ /* free the socket */ -+ sock->fd_used = 1; -+ is_tcp = sock->fd_free_pending & LWIP_SOCK_FD_FREE_TCP; -+ freed = free_socket_locked(sock, is_tcp, &conn, &lastdata); -+ } -+ } -+ SYS_ARCH_UNPROTECT(lev); -+ -+ if (freed) { -+ free_socket_free_elements(is_tcp, conn, &lastdata); -+ } -+} -+ -+#else /* LWIP_NETCONN_FULLDUPLEX */ -+#define sock_inc_used(sock) 1 -+#define sock_inc_used_locked(sock) 1 -+#define done_socket(sock) -+#endif /* LWIP_NETCONN_FULLDUPLEX */ -+ -+/* Translate a socket 'int' into a pointer (only fails if the index is invalid) */ -+static struct lwip_sock * -+tryget_socket_unconn_nouse(int fd) -+{ -+ int s = fd - LWIP_SOCKET_OFFSET; -+ if ((s < 0) || (s >= NUM_SOCKETS)) { -+ LWIP_DEBUGF(SOCKETS_DEBUG, ("tryget_socket_unconn(%d): invalid\n", fd)); -+ return NULL; -+ } -+ return &sockets[s]; -+} -+ -+struct lwip_sock * -+lwip_socket_dbg_get_socket(int fd) -+{ -+ return tryget_socket_unconn_nouse(fd); -+} -+ -+/* Translate a socket 'int' into a pointer (only fails if the index is invalid) */ -+static struct lwip_sock * -+tryget_socket_unconn(int fd) -+{ -+ struct lwip_sock *ret = tryget_socket_unconn_nouse(fd); -+ if (ret != NULL) { -+ if (!sock_inc_used(ret)) { -+ return NULL; -+ } -+ } -+ return ret; -+} -+ -+/* Like tryget_socket_unconn(), but called under SYS_ARCH_PROTECT lock. */ -+static struct lwip_sock * -+tryget_socket_unconn_locked(int fd) -+{ -+ struct lwip_sock *ret = tryget_socket_unconn_nouse(fd); -+ if (ret != NULL) { -+ if (!sock_inc_used_locked(ret)) { -+ return NULL; -+ } -+ } -+ return ret; -+} -+ -+/** -+ * Same as get_socket but doesn't set errno -+ * -+ * @param fd externally used socket index -+ * @return struct lwip_sock for the socket or NULL if not found -+ */ -+static struct lwip_sock * -+tryget_socket(int fd) -+{ -+ struct lwip_sock *sock = tryget_socket_unconn(fd); -+ if (sock != NULL) { -+ if (sock->conn) { -+ return sock; -+ } -+ done_socket(sock); -+ } -+ return NULL; -+} -+ -+/** -+ * Map a externally used socket index to the internal socket representation. -+ * -+ * @param fd externally used socket index -+ * @return struct lwip_sock for the socket or NULL if not found -+ */ -+static struct lwip_sock * -+get_socket(int fd) -+{ -+ struct lwip_sock *sock = tryget_socket(fd); -+ if (!sock) { -+ if ((fd < LWIP_SOCKET_OFFSET) || (fd >= (LWIP_SOCKET_OFFSET + NUM_SOCKETS))) { -+ LWIP_DEBUGF(SOCKETS_DEBUG, ("get_socket(%d): invalid\n", fd)); -+ } -+ set_errno(EBADF); -+ return NULL; -+ } -+ return sock; -+} -+ -+#if LWIP_LITEOS_COMPAT -+/* get numbers of unused sockets */ -+int get_unused_socket_num(void) -+{ -+ int unused = 0, i; -+ SYS_ARCH_DECL_PROTECT(lev); -+ SYS_ARCH_PROTECT(lev); -+ -+ for (i = 0; i < (int)(NUM_SOCKETS); i++) { -+ if (!sockets[i].conn -+#if LWIP_NETCONN_FULLDUPLEX -+ && !sockets[i].fd_used -+#endif -+ ) { -+ unused++; -+ } -+ } -+ -+ SYS_ARCH_UNPROTECT(lev); -+ return unused; -+} -+#endif /* LWIP_LITEOS_COMPAT */ -+ -+/** -+ * Allocate a new socket for a given netconn. -+ * -+ * @param newconn the netconn for which to allocate a socket -+ * @param accepted 1 if socket has been created by accept(), -+ * 0 if socket has been created by socket() -+ * @return the index of the new socket; -1 on error -+ */ -+static int -+alloc_socket(struct netconn *newconn, int accepted) -+{ -+ int i; -+ SYS_ARCH_DECL_PROTECT(lev); -+ LWIP_UNUSED_ARG(accepted); -+ -+ /* allocate a new socket identifier */ -+ for (i = 0; i < NUM_SOCKETS; ++i) { -+ /* Protect socket array */ -+ SYS_ARCH_PROTECT(lev); -+ if (!sockets[i].conn) { -+#if LWIP_NETCONN_FULLDUPLEX -+ if (sockets[i].fd_used) { -+ SYS_ARCH_UNPROTECT(lev); -+ continue; -+ } -+ sockets[i].fd_used = 1; -+ sockets[i].fd_free_pending = 0; -+#endif -+ sockets[i].conn = newconn; -+ /* The socket is not yet known to anyone, so no need to protect -+ after having marked it as used. */ -+ SYS_ARCH_UNPROTECT(lev); -+ sockets[i].lastdata.pbuf = NULL; -+#if LWIP_SOCKET_SELECT || LWIP_SOCKET_POLL -+ LWIP_ASSERT("sockets[i].select_waiting == 0", sockets[i].select_waiting == 0); -+ sockets[i].rcvevent = 0; -+ /* TCP sendbuf is empty, but the socket is not yet writable until connected -+ * (unless it has been created by accept()). */ -+ sockets[i].sendevent = (NETCONNTYPE_GROUP(newconn->type) == NETCONN_TCP ? (accepted != 0) : 1); -+ sockets[i].errevent = 0; -+#endif /* LWIP_SOCKET_SELECT || LWIP_SOCKET_POLL */ -+ return i + LWIP_SOCKET_OFFSET; -+ } -+ SYS_ARCH_UNPROTECT(lev); -+ } -+ return -1; -+} -+ -+/** Free a socket (under lock) -+ * -+ * @param sock the socket to free -+ * @param is_tcp != 0 for TCP sockets, used to free lastdata -+ * @param conn the socekt's netconn is stored here, must be freed externally -+ * @param lastdata lastdata is stored here, must be freed externally -+ */ -+static int -+free_socket_locked(struct lwip_sock *sock, int is_tcp, struct netconn **conn, -+ union lwip_sock_lastdata *lastdata) -+{ -+#if LWIP_NETCONN_FULLDUPLEX -+ LWIP_ASSERT("sock->fd_used > 0", sock->fd_used > 0); -+ sock->fd_used--; -+ if (sock->fd_used > 0) { -+ sock->fd_free_pending = LWIP_SOCK_FD_FREE_FREE | (is_tcp ? LWIP_SOCK_FD_FREE_TCP : 0); -+ return 0; -+ } -+#else /* LWIP_NETCONN_FULLDUPLEX */ -+ LWIP_UNUSED_ARG(is_tcp); -+#endif /* LWIP_NETCONN_FULLDUPLEX */ -+ -+ *lastdata = sock->lastdata; -+ sock->lastdata.pbuf = NULL; -+ *conn = sock->conn; -+ sock->conn = NULL; -+ return 1; -+} -+ -+/** Free a socket's leftover members. -+ */ -+static void -+free_socket_free_elements(int is_tcp, struct netconn *conn, union lwip_sock_lastdata *lastdata) -+{ -+ if (lastdata->pbuf != NULL) { -+ if (is_tcp) { -+ pbuf_free(lastdata->pbuf); -+ } else { -+ netbuf_delete(lastdata->netbuf); -+ } -+ } -+ if (conn != NULL) { -+ /* netconn_prepare_delete() has already been called, here we only free the conn */ -+ netconn_delete(conn); -+ } -+} -+ -+/** Free a socket. The socket's netconn must have been -+ * delete before! -+ * -+ * @param sock the socket to free -+ * @param is_tcp != 0 for TCP sockets, used to free lastdata -+ */ -+static void -+free_socket(struct lwip_sock *sock, int is_tcp) -+{ -+ int freed; -+ struct netconn *conn; -+ union lwip_sock_lastdata lastdata; -+ SYS_ARCH_DECL_PROTECT(lev); -+ -+ /* Protect socket array */ -+ SYS_ARCH_PROTECT(lev); -+ -+ freed = free_socket_locked(sock, is_tcp, &conn, &lastdata); -+ SYS_ARCH_UNPROTECT(lev); -+ /* don't use 'sock' after this line, as another task might have allocated it */ -+ -+ if (freed) { -+ free_socket_free_elements(is_tcp, conn, &lastdata); -+ } -+} -+ -+/* Below this, the well-known socket functions are implemented. -+ * Use google.com or opengroup.org to get a good description :-) -+ * -+ * Exceptions are documented! -+ */ -+ -+int -+lwip_accept(int s, struct sockaddr *addr, socklen_t *addrlen) -+{ -+ struct lwip_sock *sock, *nsock; -+ struct netconn *newconn; -+ ip_addr_t naddr; -+ u16_t port = 0; -+ int newsock; -+ err_t err; -+ int recvevent; -+ SYS_ARCH_DECL_PROTECT(lev); -+ -+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d)...\n", s)); -+ sock = get_socket(s); -+ if (!sock) { -+ return -1; -+ } -+ -+ /* wait for a new connection */ -+ err = netconn_accept(sock->conn, &newconn); -+ if (err != ERR_OK) { -+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d): netconn_acept failed, err=%d\n", s, err)); -+ if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_TCP) { -+ sock_set_errno(sock, EOPNOTSUPP); -+ } else if (err == ERR_CLSD) { -+ sock_set_errno(sock, EINVAL); -+ } else { -+ sock_set_errno(sock, err_to_errno(err)); -+ } -+ done_socket(sock); -+ return -1; -+ } -+ LWIP_ASSERT("newconn != NULL", newconn != NULL); -+ -+ newsock = alloc_socket(newconn, 1); -+ if (newsock == -1) { -+ netconn_delete(newconn); -+ sock_set_errno(sock, ENFILE); -+ done_socket(sock); -+ return -1; -+ } -+ LWIP_ASSERT("invalid socket index", (newsock >= LWIP_SOCKET_OFFSET) && (newsock < NUM_SOCKETS + LWIP_SOCKET_OFFSET)); -+ nsock = &sockets[newsock - LWIP_SOCKET_OFFSET]; -+ -+ /* See event_callback: If data comes in right away after an accept, even -+ * though the server task might not have created a new socket yet. -+ * In that case, newconn->socket is counted down (newconn->socket--), -+ * so nsock->rcvevent is >= 1 here! -+ */ -+ SYS_ARCH_PROTECT(lev); -+ recvevent = (s16_t)(-1 - newconn->socket); -+ newconn->socket = newsock; -+ SYS_ARCH_UNPROTECT(lev); -+ -+ if (newconn->callback) { -+ LOCK_TCPIP_CORE(); -+ while (recvevent > 0) { -+ recvevent--; -+ newconn->callback(newconn, NETCONN_EVT_RCVPLUS, 0); -+ } -+ UNLOCK_TCPIP_CORE(); -+ } -+ -+ /* Note that POSIX only requires us to check addr is non-NULL. addrlen must -+ * not be NULL if addr is valid. -+ */ -+ if ((addr != NULL) && (addrlen != NULL)) { -+ union sockaddr_aligned tempaddr; -+ /* get the IP address and port of the remote host */ -+ err = netconn_peer(newconn, &naddr, &port); -+ if (err != ERR_OK) { -+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d): netconn_peer failed, err=%d\n", s, err)); -+ netconn_delete(newconn); -+ free_socket(nsock, 1); -+ sock_set_errno(sock, err_to_errno(err)); -+ done_socket(sock); -+ return -1; -+ } -+ -+ IPADDR_PORT_TO_SOCKADDR(&tempaddr, &naddr, port); -+ if (IP_IS_V4_VAL(naddr) && (*addrlen > (int)sizeof(struct sockaddr_in))) { -+ *addrlen = sizeof(struct sockaddr_in); -+ } else if (IP_IS_V6_VAL(naddr) && (*addrlen > (int)sizeof(struct sockaddr_in6))) { -+ *addrlen = sizeof(struct sockaddr_in6); -+ } -+ MEMCPY(addr, &tempaddr, *addrlen); -+ -+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d) returning new sock=%d addr=", s, newsock)); -+ ip_addr_debug_print_val(SOCKETS_DEBUG, naddr); -+ LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F"\n", port)); -+ } else { -+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d) returning new sock=%d", s, newsock)); -+ } -+ -+ sock_set_errno(sock, 0); -+ done_socket(sock); -+ done_socket(nsock); -+ return newsock; -+} -+ -+int -+lwip_bind(int s, const struct sockaddr *name, socklen_t namelen) -+{ -+ struct lwip_sock *sock; -+ ip_addr_t local_addr; -+ u16_t local_port; -+ err_t err; -+ -+#if PF_PACKET_SOCKET -+ const struct sockaddr_ll *name_ll = NULL; -+ u8_t local_if_idx = 0; -+#endif -+ sock = get_socket(s); -+ if (!sock) { -+ return -1; -+ } -+ -+ /* check size, family and alignment of 'name' */ -+#if PF_PACKET_SOCKET -+ if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) & NETCONN_PACKET_RAW) { -+ name_ll = (const struct sockaddr_ll *)(void*)name; -+ LWIP_ERROR("lwip_bind: invalid address", ((name_ll != NULL)&&(namelen == sizeof(struct sockaddr_ll)) && -+ ((name_ll->sll_family) == PF_PACKET) && IS_SOCK_ADDR_ALIGNED(name) && -+ (name_ll->sll_ifindex <= LWIP_NETIF_IFINDEX_MAX)), sock_set_errno(sock, err_to_errno(ERR_VAL)); -+ done_socket(sock); return -1); -+ -+ ip_addr_set_any_val(IPADDR_TYPE_V4, local_addr); -+ local_port = name_ll->sll_protocol; -+ local_if_idx = (u8_t)name_ll->sll_ifindex; -+ -+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d, ", s)); -+ LWIP_DEBUGF(SOCKETS_DEBUG, (" ifindex=%u proto=%"U16_F")\n", local_if_idx, local_port)); -+ } else -+#endif -+ { -+ LWIP_ERROR("lwip_bind: invalid address", ((name != NULL) && IS_SOCK_ADDR_LEN_VALID(namelen) && -+ IS_SOCK_ADDR_ALIGNED(name)), sock_set_errno(sock, err_to_errno(ERR_VAL)); -+ done_socket(sock); return -1); -+ LWIP_ERROR("lwip_bind: invalid address", -+ (IS_SOCK_ADDR_TYPE_VALID(name)), sock_set_errno(sock, err_to_errno(ERR_AFNOSUPPORT)); -+ done_socket(sock); return -1); -+ -+ if (!SOCK_ADDR_TYPE_MATCH(name, sock)) { -+ /* sockaddr does not match socket type (IPv4/IPv6) */ -+ sock_set_errno(sock, err_to_errno(ERR_VAL)); -+ done_socket(sock); -+ return -1; -+ } -+ -+ /* check size, family and alignment of 'name' */ -+ LWIP_ERROR("lwip_bind: invalid address", (IS_SOCK_ADDR_LEN_VALID(namelen) && -+ IS_SOCK_ADDR_TYPE_VALID(name) && IS_SOCK_ADDR_ALIGNED(name)), -+ sock_set_errno(sock, err_to_errno(ERR_ARG)); done_socket(sock); return -1;); -+ LWIP_UNUSED_ARG(namelen); -+ -+ SOCKADDR_TO_IPADDR_PORT(name, &local_addr, local_port); -+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d, addr=", s)); -+ ip_addr_debug_print_val(SOCKETS_DEBUG, local_addr); -+ LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F")\n", local_port)); -+ } -+ -+#if LWIP_IPV4 && LWIP_IPV6 -+ /* Dual-stack: Unmap IPv4 mapped IPv6 addresses */ -+ if (IP_IS_V6_VAL(local_addr) && ip6_addr_isipv4mappedipv6(ip_2_ip6(&local_addr))) { -+ unmap_ipv4_mapped_ipv6(ip_2_ip4(&local_addr), ip_2_ip6(&local_addr)); -+ IP_SET_TYPE_VAL(local_addr, IPADDR_TYPE_V4); -+ } -+#endif /* LWIP_IPV4 && LWIP_IPV6 */ -+ -+#if PF_PACKET_SOCKET -+ err = netconn_bind(sock->conn, &local_addr, local_port, local_if_idx); -+#else /* PF_PACKET_SOCKET */ -+ err = netconn_bind(sock->conn, &local_addr, local_port); -+#endif -+ -+ if (err != ERR_OK) { -+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d) failed, err=%d\n", s, err)); -+ sock_set_errno(sock, err_to_errno(err)); -+ done_socket(sock); -+ return -1; -+ } -+ -+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d) succeeded\n", s)); -+ sock_set_errno(sock, 0); -+ done_socket(sock); -+ return 0; -+} -+ -+int -+lwip_close(int s) -+{ -+ struct lwip_sock *sock; -+ int is_tcp = 0; -+ err_t err; -+ -+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_close(%d)\n", s)); -+ -+ sock = get_socket(s); -+ if (!sock) { -+ return -1; -+ } -+ -+ if (sock->conn != NULL) { -+ is_tcp = NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP; -+ } else { -+ LWIP_ASSERT("sock->lastdata == NULL", sock->lastdata.pbuf == NULL); -+ } -+ -+#if LWIP_IGMP -+ /* drop all possibly joined IGMP memberships */ -+ lwip_socket_drop_registered_memberships(s); -+#endif /* LWIP_IGMP */ -+#if LWIP_IPV6_MLD -+ /* drop all possibly joined MLD6 memberships */ -+ lwip_socket_drop_registered_mld6_memberships(s); -+#endif /* LWIP_IPV6_MLD */ -+ -+ err = netconn_prepare_delete(sock->conn); -+ if (err != ERR_OK) { -+ sock_set_errno(sock, err_to_errno(err)); -+ done_socket(sock); -+ return -1; -+ } -+ -+ free_socket(sock, is_tcp); -+ set_errno(0); -+ return 0; -+} -+ -+int -+lwip_connect(int s, const struct sockaddr *name, socklen_t namelen) -+{ -+ struct lwip_sock *sock; -+ err_t err; -+ -+ sock = get_socket(s); -+ if (!sock) { -+ return -1; -+ } -+ -+#if PF_PACKET_SOCKET -+ if (NETCONN_PACKET_RAW & NETCONNTYPE_GROUP(netconn_type(sock->conn))) { -+ sock_set_errno(sock, EOPNOTSUPP); -+ done_socket(sock); -+ return -1; -+ } -+#endif -+ -+ if (!SOCK_ADDR_TYPE_MATCH_OR_UNSPEC(name, sock)) { -+ /* sockaddr does not match socket type (IPv4/IPv6) */ -+ sock_set_errno(sock, err_to_errno(ERR_VAL)); -+ done_socket(sock); -+ return -1; -+ } -+ -+ LWIP_UNUSED_ARG(namelen); -+ if (name->sa_family == AF_UNSPEC) { -+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d, AF_UNSPEC)\n", s)); -+ err = netconn_disconnect(sock->conn); -+ } else { -+ ip_addr_t remote_addr; -+ u16_t remote_port; -+ -+ /* check size, family and alignment of 'name' */ -+ LWIP_ERROR("lwip_connect: invalid address", IS_SOCK_ADDR_LEN_VALID(namelen) && -+ IS_SOCK_ADDR_TYPE_VALID_OR_UNSPEC(name) && IS_SOCK_ADDR_ALIGNED(name), -+ sock_set_errno(sock, err_to_errno(ERR_ARG)); done_socket(sock); return -1;); -+ -+ SOCKADDR_TO_IPADDR_PORT(name, &remote_addr, remote_port); -+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d, addr=", s)); -+ ip_addr_debug_print_val(SOCKETS_DEBUG, remote_addr); -+ LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F")\n", remote_port)); -+ -+#if LWIP_IPV4 && LWIP_IPV6 -+ /* Dual-stack: Unmap IPv4 mapped IPv6 addresses */ -+ if (IP_IS_V6_VAL(remote_addr) && ip6_addr_isipv4mappedipv6(ip_2_ip6(&remote_addr))) { -+ unmap_ipv4_mapped_ipv6(ip_2_ip4(&remote_addr), ip_2_ip6(&remote_addr)); -+ IP_SET_TYPE_VAL(remote_addr, IPADDR_TYPE_V4); -+ } -+#endif /* LWIP_IPV4 && LWIP_IPV6 */ -+ -+ err = netconn_connect(sock->conn, &remote_addr, remote_port); -+ } -+ -+ if (err != ERR_OK) { -+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d) failed, err=%d\n", s, err)); -+ sock_set_errno(sock, err_to_errno(err)); -+ done_socket(sock); -+ return -1; -+ } -+ -+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d) succeeded\n", s)); -+ sock_set_errno(sock, 0); -+ done_socket(sock); -+ return 0; -+} -+ -+/** -+ * Set a socket into listen mode. -+ * The socket may not have been used for another connection previously. -+ * -+ * @param s the socket to set to listening mode -+ * @param backlog (ATTENTION: needs TCP_LISTEN_BACKLOG=1) -+ * @return 0 on success, non-zero on failure -+ */ -+int -+lwip_listen(int s, int backlog) -+{ -+ struct lwip_sock *sock; -+ err_t err; -+ -+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_listen(%d, backlog=%d)\n", s, backlog)); -+ -+ sock = get_socket(s); -+ if (!sock) { -+ return -1; -+ } -+ -+ /* limit the "backlog" parameter to fit in an u8_t */ -+ backlog = LWIP_MIN(LWIP_MAX(backlog, 0), 0xff); -+ -+ err = netconn_listen_with_backlog(sock->conn, (u8_t)backlog); -+ -+ if (err != ERR_OK) { -+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_listen(%d) failed, err=%d\n", s, err)); -+ if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_TCP) { -+ sock_set_errno(sock, EOPNOTSUPP); -+ } else { -+ sock_set_errno(sock, err_to_errno(err)); -+ } -+ done_socket(sock); -+ return -1; -+ } -+ -+ sock_set_errno(sock, 0); -+ done_socket(sock); -+ return 0; -+} -+ -+#if LWIP_TCP -+/* Helper function to loop over receiving pbufs from netconn -+ * until "len" bytes are received or we're otherwise done. -+ * Keeps sock->lastdata for peeking or partly copying. -+ */ -+static ssize_t -+lwip_recv_tcp(struct lwip_sock *sock, void *mem, size_t len, int flags) -+{ -+ u8_t apiflags = NETCONN_NOAUTORCVD; -+ ssize_t recvd = 0; -+ ssize_t recv_left = (len <= SSIZE_MAX) ? (ssize_t)len : SSIZE_MAX; -+ -+ LWIP_ASSERT("no socket given", sock != NULL); -+ LWIP_ASSERT("this should be checked internally", NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP); -+ -+ if (flags & MSG_DONTWAIT) { -+ apiflags |= NETCONN_DONTBLOCK; -+ } -+ -+ do { -+ struct pbuf *p; -+ err_t err; -+ u16_t copylen; -+ -+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recv_tcp: top while sock->lastdata=%p\n", (void *)sock->lastdata.pbuf)); -+ /* Check if there is data left from the last recv operation. */ -+ if (sock->lastdata.pbuf) { -+ p = sock->lastdata.pbuf; -+ } else { -+ /* No data was left from the previous operation, so we try to get -+ some from the network. */ -+ err = netconn_recv_tcp_pbuf_flags(sock->conn, &p, apiflags); -+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recv_tcp: netconn_recv err=%d, pbuf=%p\n", -+ err, (void *)p)); -+ -+ if (err != ERR_OK) { -+ if (recvd > 0) { -+ /* already received data, return that (this trusts in getting the same error from -+ netconn layer again next time netconn_recv is called) */ -+ goto lwip_recv_tcp_done; -+ } -+ /* We should really do some error checking here. */ -+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recv_tcp: p == NULL, error is \"%s\"!\n", -+ lwip_strerr(err))); -+ sock_set_errno(sock, err_to_errno(err)); -+ if (err == ERR_CLSD) { -+ return 0; -+ } else { -+ return -1; -+ } -+ } -+ LWIP_ASSERT("p != NULL", p != NULL); -+ sock->lastdata.pbuf = p; -+ } -+ -+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recv_tcp: buflen=%"U16_F" recv_left=%d off=%d\n", -+ p->tot_len, (int)recv_left, (int)recvd)); -+ -+ if (recv_left > p->tot_len) { -+ copylen = p->tot_len; -+ } else { -+ copylen = (u16_t)recv_left; -+ } -+ if (recvd + copylen < recvd) { -+ /* overflow */ -+ copylen = (u16_t)(SSIZE_MAX - recvd); -+ } -+ -+ /* copy the contents of the received buffer into -+ the supplied memory pointer mem */ -+ pbuf_copy_partial(p, (u8_t *)mem + recvd, copylen, 0); -+ -+ recvd += copylen; -+ -+ /* TCP combines multiple pbufs for one recv */ -+ LWIP_ASSERT("invalid copylen, len would underflow", recv_left >= copylen); -+ recv_left -= copylen; -+ -+ /* Unless we peek the incoming message... */ -+ if ((flags & MSG_PEEK) == 0) { -+ /* ... check if there is data left in the pbuf */ -+ LWIP_ASSERT("invalid copylen", p->tot_len >= copylen); -+ if (p->tot_len - copylen > 0) { -+ /* If so, it should be saved in the sock structure for the next recv call. -+ We store the pbuf but hide/free the consumed data: */ -+ sock->lastdata.pbuf = pbuf_free_header(p, copylen); -+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recv_tcp: lastdata now pbuf=%p\n", (void *)sock->lastdata.pbuf)); -+ } else { -+ sock->lastdata.pbuf = NULL; -+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recv_tcp: deleting pbuf=%p\n", (void *)p)); -+ pbuf_free(p); -+ } -+ } -+ /* once we have some data to return, only add more if we don't need to wait */ -+ apiflags |= NETCONN_DONTBLOCK | NETCONN_NOFIN; -+ /* @todo: do we need to support peeking more than one pbuf? */ -+ } while ((recv_left > 0) && !(flags & MSG_PEEK)); -+lwip_recv_tcp_done: -+ if ((recvd > 0) && !(flags & MSG_PEEK)) { -+ /* ensure window update after copying all data */ -+ netconn_tcp_recvd(sock->conn, (size_t)recvd); -+ } -+ sock_set_errno(sock, 0); -+ return recvd; -+} -+#endif -+ -+/* Convert a netbuf's address data to struct sockaddr */ -+static int -+lwip_sock_make_addr(struct netconn *conn, ip_addr_t *fromaddr, u16_t port, -+ struct sockaddr *from, socklen_t *fromlen) -+{ -+ int truncated = 0; -+ union sockaddr_aligned saddr; -+ socklen_t sa_len; -+ -+ LWIP_UNUSED_ARG(conn); -+ -+ LWIP_ASSERT("fromaddr != NULL", fromaddr != NULL); -+ LWIP_ASSERT("from != NULL", from != NULL); -+ LWIP_ASSERT("fromlen != NULL", fromlen != NULL); -+ -+#if LWIP_IPV4 && LWIP_IPV6 -+ /* Dual-stack: Map IPv4 addresses to IPv4 mapped IPv6 */ -+ if (NETCONNTYPE_ISIPV6(netconn_type(conn)) && IP_IS_V4(fromaddr)) { -+ ip4_2_ipv4_mapped_ipv6(ip_2_ip6(fromaddr), ip_2_ip4(fromaddr)); -+ IP_SET_TYPE(fromaddr, IPADDR_TYPE_V6); -+ } -+#endif /* LWIP_IPV4 && LWIP_IPV6 */ -+ -+ IPADDR_PORT_TO_SOCKADDR(&saddr, fromaddr, port); -+#if LWIP_LITEOS_COMPAT -+ if (IP_IS_V4_VAL(*fromaddr)) { -+ sa_len = sizeof(struct sockaddr_in); -+ } else { -+ sa_len = sizeof(struct sockaddr_in6); -+ } -+#else -+ sa_len = saddr.sa.sa_len; -+#endif /* LWIP_LITEOS_COMPAT */ -+ -+ if (*fromlen < sa_len) { -+ truncated = 1; -+ } else if (*fromlen > sa_len) { -+ *fromlen = sa_len; -+ } -+ MEMCPY(from, &saddr, *fromlen); -+ return truncated; -+} -+ -+#if LWIP_TCP -+/* Helper function to get a tcp socket's remote address info */ -+static int -+lwip_recv_tcp_from(struct lwip_sock *sock, struct sockaddr *from, socklen_t *fromlen, const char *dbg_fn, int dbg_s, ssize_t dbg_ret) -+{ -+ if (sock == NULL) { -+ return 0; -+ } -+ LWIP_UNUSED_ARG(dbg_fn); -+ LWIP_UNUSED_ARG(dbg_s); -+ LWIP_UNUSED_ARG(dbg_ret); -+ -+#if !SOCKETS_DEBUG -+ if (from && fromlen) -+#endif /* !SOCKETS_DEBUG */ -+ { -+ /* get remote addr/port from tcp_pcb */ -+ u16_t port; -+ ip_addr_t tmpaddr; -+ netconn_getaddr(sock->conn, &tmpaddr, &port, 0); -+ LWIP_DEBUGF(SOCKETS_DEBUG, ("%s(%d): addr=", dbg_fn, dbg_s)); -+ ip_addr_debug_print_val(SOCKETS_DEBUG, tmpaddr); -+ LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F" len=%d\n", port, (int)dbg_ret)); -+ if (from && fromlen) { -+ return lwip_sock_make_addr(sock->conn, &tmpaddr, port, from, fromlen); -+ } -+ } -+ return 0; -+} -+#endif -+ -+/* Helper function to receive a netbuf from a udp or raw netconn. -+ * Keeps sock->lastdata for peeking. -+ */ -+static err_t -+lwip_recvfrom_udp_raw(struct lwip_sock *sock, int flags, struct msghdr *msg, u16_t *datagram_len, int dbg_s) -+{ -+ struct netbuf *buf; -+ u8_t apiflags; -+ err_t err; -+ u16_t buflen, copylen, copied; -+ int i; -+ -+ LWIP_UNUSED_ARG(dbg_s); -+ LWIP_ERROR("lwip_recvfrom_udp_raw: invalid arguments", (msg->msg_iov != NULL) || (msg->msg_iovlen <= 0), return ERR_ARG;); -+ -+ if (flags & MSG_DONTWAIT) { -+ apiflags = NETCONN_DONTBLOCK; -+ } else { -+ apiflags = 0; -+ } -+ -+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom_udp_raw[UDP/RAW]: top sock->lastdata=%p\n", (void *)sock->lastdata.netbuf)); -+ /* Check if there is data left from the last recv operation. */ -+ buf = sock->lastdata.netbuf; -+ if (buf == NULL) { -+ /* No data was left from the previous operation, so we try to get -+ some from the network. */ -+ err = netconn_recv_udp_raw_netbuf_flags(sock->conn, &buf, apiflags); -+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom_udp_raw[UDP/RAW]: netconn_recv err=%d, netbuf=%p\n", -+ err, (void *)buf)); -+ -+ if (err != ERR_OK) { -+ return err; -+ } -+ LWIP_ASSERT("buf != NULL", buf != NULL); -+ sock->lastdata.netbuf = buf; -+ } -+ buflen = buf->p->tot_len; -+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom_udp_raw: buflen=%"U16_F"\n", buflen)); -+ -+ copied = 0; -+ /* copy the pbuf payload into the iovs */ -+ for (i = 0; (i < msg->msg_iovlen) && (copied < buflen); i++) { -+ u16_t len_left = (u16_t)(buflen - copied); -+ if (msg->msg_iov[i].iov_len > len_left) { -+ copylen = len_left; -+ } else { -+ copylen = (u16_t)msg->msg_iov[i].iov_len; -+ } -+ -+ /* copy the contents of the received buffer into -+ the supplied memory buffer */ -+ pbuf_copy_partial(buf->p, (u8_t *)msg->msg_iov[i].iov_base, copylen, copied); -+ copied = (u16_t)(copied + copylen); -+ } -+ -+ /* Check to see from where the data was.*/ -+#if !SOCKETS_DEBUG -+ if (msg->msg_name && msg->msg_namelen) -+#endif /* !SOCKETS_DEBUG */ -+ { -+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom_udp_raw(%d): addr=", dbg_s)); -+ ip_addr_debug_print_val(SOCKETS_DEBUG, *netbuf_fromaddr(buf)); -+ LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F" len=%d\n", netbuf_fromport(buf), copied)); -+ if (msg->msg_name && msg->msg_namelen) { -+#if PF_PACKET_SOCKET & LWIP_LITEOS_COMPAT -+ struct sockaddr_ll sll; -+ -+ if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) & NETCONN_PACKET_RAW) { -+ if (msg->msg_namelen > sizeof(sll)) { -+ msg->msg_namelen = sizeof(sll); -+ } -+ -+ if (msg->msg_namelen) { -+ (void)memset_s(&sll, sizeof(sll), 0, sizeof(sll)); -+ sll.sll_family = PF_PACKET; -+ sll.sll_protocol = netbuf_fromport(buf); -+ sll.sll_hatype = netbuf_fromhatype(buf); -+ sll.sll_ifindex = netbuf_fromifindex(buf); -+ -+ if (buf->p->flags & PBUF_FLAG_LLBCAST) { -+ sll.sll_pkttype = PACKET_BROADCAST; -+ } else if (buf->p->flags & PBUF_FLAG_LLMCAST) { -+ sll.sll_pkttype = PACKET_MULTICAST; -+ } else if (buf->p->flags & PBUF_FLAG_HOST) { -+ sll.sll_pkttype = PACKET_HOST; -+ } else if (buf->p->flags & PBUF_FLAG_OUTGOING) { -+ sll.sll_pkttype = PACKET_OUTGOING; -+ } else { -+ sll.sll_pkttype = PACKET_OTHERHOST; -+ } -+ -+ (void)memcpy_s(msg->msg_name, msg->msg_namelen, (void *)&sll, msg->msg_namelen); -+ -+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom_udp_raw(%d): hatype=%u", dbg_s, ntohs(sll.sll_hatype))); -+ LWIP_DEBUGF(SOCKETS_DEBUG, (" packet type = %u\n", sll.sll_pkttype)); -+ } -+ } else -+#endif /* PF_PACKET_SOCKET & LWIP_LITEOS_COMPAT */ -+ { -+ lwip_sock_make_addr(sock->conn, netbuf_fromaddr(buf), netbuf_fromport(buf), -+ (struct sockaddr *)msg->msg_name, &msg->msg_namelen); -+ } -+ } -+ } -+ -+ /* Initialize flag output */ -+ msg->msg_flags = 0; -+ -+ if (msg->msg_control) { -+ u8_t wrote_msg = 0; -+#if LWIP_NETBUF_RECVINFO -+ /* Check if packet info was recorded */ -+ if (buf->flags & NETBUF_FLAG_DESTADDR) { -+ if (IP_IS_V4(&buf->toaddr)) { -+#if LWIP_IPV4 -+ if (msg->msg_controllen >= CMSG_SPACE(sizeof(struct in_pktinfo))) { -+ struct cmsghdr *chdr = CMSG_FIRSTHDR(msg); /* This will always return a header!! */ -+ struct in_pktinfo *pkti = (struct in_pktinfo *)CMSG_DATA(chdr); -+ chdr->cmsg_level = IPPROTO_IP; -+ chdr->cmsg_type = IP_PKTINFO; -+ chdr->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo)); -+ pkti->ipi_ifindex = buf->p->if_idx; -+ inet_addr_from_ip4addr(&pkti->ipi_addr, ip_2_ip4(netbuf_destaddr(buf))); -+ msg->msg_controllen = CMSG_SPACE(sizeof(struct in_pktinfo)); -+ wrote_msg = 1; -+ } else { -+ msg->msg_flags |= MSG_CTRUNC; -+ } -+#endif /* LWIP_IPV4 */ -+ } -+ } -+#endif /* LWIP_NETBUF_RECVINFO */ -+ -+ if (!wrote_msg) { -+ msg->msg_controllen = 0; -+ } -+ } -+ -+ /* If we don't peek the incoming message: zero lastdata pointer and free the netbuf */ -+ if ((flags & MSG_PEEK) == 0) { -+ sock->lastdata.netbuf = NULL; -+ netbuf_delete(buf); -+ } -+ if (datagram_len) { -+ *datagram_len = buflen; -+ } -+ return ERR_OK; -+} -+ -+ssize_t -+lwip_recvfrom(int s, void *mem, size_t len, int flags, -+ struct sockaddr *from, socklen_t *fromlen) -+{ -+ struct lwip_sock *sock; -+ ssize_t ret; -+ -+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d, %p, %"SZT_F", 0x%x, ..)\n", s, mem, len, flags)); -+ sock = get_socket(s); -+ if (!sock) { -+ return -1; -+ } -+#if LWIP_TCP -+ if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) { -+ ret = lwip_recv_tcp(sock, mem, len, flags); -+ lwip_recv_tcp_from(sock, from, fromlen, "lwip_recvfrom", s, ret); -+ done_socket(sock); -+ return ret; -+ } else -+#endif -+ { -+ u16_t datagram_len = 0; -+ struct iovec vec; -+ struct msghdr msg; -+ err_t err; -+ vec.iov_base = mem; -+ vec.iov_len = len; -+ msg.msg_control = NULL; -+ msg.msg_controllen = 0; -+ msg.msg_flags = 0; -+ msg.msg_iov = &vec; -+ msg.msg_iovlen = 1; -+ msg.msg_name = from; -+ msg.msg_namelen = (fromlen ? *fromlen : 0); -+ err = lwip_recvfrom_udp_raw(sock, flags, &msg, &datagram_len, s); -+ if (err != ERR_OK) { -+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom[UDP/RAW](%d): buf == NULL, error is \"%s\"!\n", -+ s, lwip_strerr(err))); -+ sock_set_errno(sock, err_to_errno(err)); -+ done_socket(sock); -+ return -1; -+ } -+ ret = (ssize_t)LWIP_MIN(LWIP_MIN(len, datagram_len), SSIZE_MAX); -+ if (fromlen) { -+ *fromlen = msg.msg_namelen; -+ } -+ } -+ -+ sock_set_errno(sock, 0); -+ done_socket(sock); -+ return ret; -+} -+ -+ssize_t -+lwip_read(int s, void *mem, size_t len) -+{ -+ return lwip_recvfrom(s, mem, len, 0, NULL, NULL); -+} -+ -+ssize_t -+lwip_readv(int s, const struct iovec *iov, int iovcnt) -+{ -+ struct msghdr msg; -+ -+ msg.msg_name = NULL; -+ msg.msg_namelen = 0; -+ /* Hack: we have to cast via number to cast from 'const' pointer to non-const. -+ Blame the opengroup standard for this inconsistency. */ -+ msg.msg_iov = LWIP_CONST_CAST(struct iovec *, iov); -+ msg.msg_iovlen = iovcnt; -+ msg.msg_control = NULL; -+ msg.msg_controllen = 0; -+ msg.msg_flags = 0; -+ return lwip_recvmsg(s, &msg, 0); -+} -+ -+ssize_t -+lwip_recv(int s, void *mem, size_t len, int flags) -+{ -+ return lwip_recvfrom(s, mem, len, flags, NULL, NULL); -+} -+ -+ssize_t -+lwip_recvmsg(int s, struct msghdr *message, int flags) -+{ -+ struct lwip_sock *sock; -+ int i; -+ ssize_t buflen; -+ -+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvmsg(%d, message=%p, flags=0x%x)\n", s, (void *)message, flags)); -+ LWIP_ERROR("lwip_recvmsg: invalid message pointer", message != NULL, return ERR_ARG;); -+ LWIP_ERROR("lwip_recvmsg: unsupported flags", (flags & ~(MSG_PEEK|MSG_DONTWAIT)) == 0, -+ set_errno(EOPNOTSUPP); return -1;); -+ -+ if ((message->msg_iovlen <= 0) || (message->msg_iovlen > IOV_MAX)) { -+ set_errno(EMSGSIZE); -+ return -1; -+ } -+ -+ sock = get_socket(s); -+ if (!sock) { -+ return -1; -+ } -+ -+ /* check for valid vectors */ -+ buflen = 0; -+ for (i = 0; i < message->msg_iovlen; i++) { -+ if ((message->msg_iov[i].iov_base == NULL) || ((ssize_t)message->msg_iov[i].iov_len <= 0) || -+ ((size_t)(ssize_t)message->msg_iov[i].iov_len != message->msg_iov[i].iov_len) || -+ ((ssize_t)(buflen + (ssize_t)message->msg_iov[i].iov_len) <= 0)) { -+ sock_set_errno(sock, err_to_errno(ERR_VAL)); -+ done_socket(sock); -+ return -1; -+ } -+ buflen = (ssize_t)(buflen + (ssize_t)message->msg_iov[i].iov_len); -+ } -+ -+ if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) { -+#if LWIP_TCP -+ int recv_flags = flags; -+ message->msg_flags = 0; -+ /* recv the data */ -+ buflen = 0; -+ for (i = 0; i < message->msg_iovlen; i++) { -+ /* try to receive into this vector's buffer */ -+ ssize_t recvd_local = lwip_recv_tcp(sock, message->msg_iov[i].iov_base, message->msg_iov[i].iov_len, recv_flags); -+ if (recvd_local > 0) { -+ /* sum up received bytes */ -+ buflen += recvd_local; -+ } -+ if ((recvd_local < 0) || (recvd_local < (int)message->msg_iov[i].iov_len) || -+ (flags & MSG_PEEK)) { -+ /* returned prematurely (or peeking, which might actually be limitated to the first iov) */ -+ if (buflen <= 0) { -+ /* nothing received at all, propagate the error */ -+ buflen = recvd_local; -+ } -+ break; -+ } -+ /* pass MSG_DONTWAIT to lwip_recv_tcp() to prevent waiting for more data */ -+ recv_flags |= MSG_DONTWAIT; -+ } -+ if (buflen > 0) { -+ /* reset socket error since we have received something */ -+ sock_set_errno(sock, 0); -+ } -+ /* " If the socket is connected, the msg_name and msg_namelen members shall be ignored." */ -+ done_socket(sock); -+ return buflen; -+#else /* LWIP_TCP */ -+ sock_set_errno(sock, err_to_errno(ERR_ARG)); -+ done_socket(sock); -+ return -1; -+#endif /* LWIP_TCP */ -+ } -+ /* else, UDP and RAW NETCONNs */ -+#if LWIP_UDP || LWIP_RAW -+ { -+ u16_t datagram_len = 0; -+ err_t err; -+ err = lwip_recvfrom_udp_raw(sock, flags, message, &datagram_len, s); -+ if (err != ERR_OK) { -+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvmsg[UDP/RAW](%d): buf == NULL, error is \"%s\"!\n", -+ s, lwip_strerr(err))); -+ sock_set_errno(sock, err_to_errno(err)); -+ done_socket(sock); -+ return -1; -+ } -+ if (datagram_len > buflen) { -+ message->msg_flags |= MSG_TRUNC; -+ } -+ -+ sock_set_errno(sock, 0); -+ done_socket(sock); -+ return (int)datagram_len; -+ } -+#else /* LWIP_UDP || LWIP_RAW */ -+ sock_set_errno(sock, err_to_errno(ERR_ARG)); -+ done_socket(sock); -+ return -1; -+#endif /* LWIP_UDP || LWIP_RAW */ -+} -+ -+ssize_t -+lwip_send(int s, const void *data, size_t size, int flags) -+{ -+ struct lwip_sock *sock; -+ err_t err; -+ u8_t write_flags; -+ size_t written; -+ -+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_send(%d, data=%p, size=%"SZT_F", flags=0x%x)\n", -+ s, data, size, flags)); -+ -+ sock = get_socket(s); -+ if (!sock) { -+ return -1; -+ } -+ -+ if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_TCP) { -+#if (LWIP_UDP || LWIP_RAW) -+ done_socket(sock); -+ return lwip_sendto(s, data, size, flags, NULL, 0); -+#else /* (LWIP_UDP || LWIP_RAW) */ -+ sock_set_errno(sock, err_to_errno(ERR_ARG)); -+ done_socket(sock); -+ return -1; -+#endif /* (LWIP_UDP || LWIP_RAW) */ -+ } -+ -+ write_flags = (u8_t)(NETCONN_COPY | -+ ((flags & MSG_MORE) ? NETCONN_MORE : 0) | -+ ((flags & MSG_DONTWAIT) ? NETCONN_DONTBLOCK : 0)); -+ written = 0; -+ err = netconn_write_partly(sock->conn, data, size, write_flags, &written); -+ -+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_send(%d) err=%d written=%"SZT_F"\n", s, err, written)); -+ sock_set_errno(sock, err_to_errno(err)); -+ done_socket(sock); -+ /* casting 'written' to ssize_t is OK here since the netconn API limits it to SSIZE_MAX */ -+ return (err == ERR_OK ? (ssize_t)written : -1); -+} -+ -+ssize_t -+lwip_sendmsg(int s, const struct msghdr *msg, int flags) -+{ -+ struct lwip_sock *sock; -+#if LWIP_TCP -+ u8_t write_flags; -+ size_t written; -+#endif -+ err_t err = ERR_OK; -+ -+ sock = get_socket(s); -+ if (!sock) { -+ return -1; -+ } -+ -+ LWIP_ERROR("lwip_sendmsg: invalid msghdr", msg != NULL, -+ sock_set_errno(sock, err_to_errno(ERR_ARG)); done_socket(sock); return -1;); -+ LWIP_ERROR("lwip_sendmsg: invalid msghdr iov", msg->msg_iov != NULL, -+ sock_set_errno(sock, err_to_errno(ERR_ARG)); done_socket(sock); return -1;); -+ LWIP_ERROR("lwip_sendmsg: maximum iovs exceeded", (msg->msg_iovlen > 0) && (msg->msg_iovlen <= IOV_MAX), -+ sock_set_errno(sock, EMSGSIZE); done_socket(sock); return -1;); -+ LWIP_ERROR("lwip_sendmsg: unsupported flags", (flags & ~(MSG_DONTWAIT | MSG_MORE)) == 0, -+ sock_set_errno(sock, EOPNOTSUPP); done_socket(sock); return -1;); -+ -+ LWIP_UNUSED_ARG(msg->msg_control); -+ LWIP_UNUSED_ARG(msg->msg_controllen); -+ LWIP_UNUSED_ARG(msg->msg_flags); -+ -+ if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) { -+#if LWIP_TCP -+ write_flags = (u8_t)(NETCONN_COPY | -+ ((flags & MSG_MORE) ? NETCONN_MORE : 0) | -+ ((flags & MSG_DONTWAIT) ? NETCONN_DONTBLOCK : 0)); -+ -+ written = 0; -+ err = netconn_write_vectors_partly(sock->conn, (struct netvector *)msg->msg_iov, (u16_t)msg->msg_iovlen, write_flags, &written); -+ sock_set_errno(sock, err_to_errno(err)); -+ done_socket(sock); -+ /* casting 'written' to ssize_t is OK here since the netconn API limits it to SSIZE_MAX */ -+ return (err == ERR_OK ? (ssize_t)written : -1); -+#else /* LWIP_TCP */ -+ sock_set_errno(sock, err_to_errno(ERR_ARG)); -+ done_socket(sock); -+ return -1; -+#endif /* LWIP_TCP */ -+ } -+ /* else, UDP and RAW NETCONNs */ -+#if LWIP_UDP || LWIP_RAW -+ { -+ struct netbuf chain_buf; -+ int i; -+ ssize_t size = 0; -+ -+ LWIP_UNUSED_ARG(flags); -+ LWIP_ERROR("lwip_sendmsg: invalid msghdr name", (((msg->msg_name == NULL) && (msg->msg_namelen == 0)) || -+ IS_SOCK_ADDR_LEN_VALID(msg->msg_namelen)), -+ sock_set_errno(sock, err_to_errno(ERR_ARG)); done_socket(sock); return -1;); -+ -+ /* initialize chain buffer with destination */ -+ memset(&chain_buf, 0, sizeof(struct netbuf)); -+ if (msg->msg_name) { -+ u16_t remote_port; -+ SOCKADDR_TO_IPADDR_PORT((const struct sockaddr *)msg->msg_name, &chain_buf.addr, remote_port); -+ netbuf_fromport(&chain_buf) = remote_port; -+ } -+#if LWIP_NETIF_TX_SINGLE_PBUF -+ for (i = 0; i < msg->msg_iovlen; i++) { -+ size += msg->msg_iov[i].iov_len; -+ if ((msg->msg_iov[i].iov_len > INT_MAX) || (size < (int)msg->msg_iov[i].iov_len)) { -+ /* overflow */ -+ goto sendmsg_emsgsize; -+ } -+ } -+ if (size > 0xFFFF) { -+ /* overflow */ -+ goto sendmsg_emsgsize; -+ } -+ /* Allocate a new netbuf and copy the data into it. */ -+ if (netbuf_alloc(&chain_buf, (u16_t)size, NETCONNTYPE_GROUP(netconn_type(sock->conn))) == NULL) { -+ err = ERR_MEM; -+ } else { -+ /* flatten the IO vectors */ -+ size_t offset = 0; -+ for (i = 0; i < msg->msg_iovlen; i++) { -+ MEMCPY(&((u8_t *)chain_buf.p->payload)[offset], msg->msg_iov[i].iov_base, msg->msg_iov[i].iov_len); -+ offset += msg->msg_iov[i].iov_len; -+ } -+#if LWIP_CHECKSUM_ON_COPY -+ { -+ /* This can be improved by using LWIP_CHKSUM_COPY() and aggregating the checksum for each IO vector */ -+ u16_t chksum = ~inet_chksum_pbuf(chain_buf.p); -+ netbuf_set_chksum(&chain_buf, chksum); -+ } -+#endif /* LWIP_CHECKSUM_ON_COPY */ -+ err = ERR_OK; -+ } -+#else /* LWIP_NETIF_TX_SINGLE_PBUF */ -+ /* create a chained netbuf from the IO vectors. NOTE: we assemble a pbuf chain -+ manually to avoid having to allocate, chain, and delete a netbuf for each iov */ -+ for (i = 0; i < msg->msg_iovlen; i++) { -+ struct pbuf *p; -+ if (msg->msg_iov[i].iov_len > 0xFFFF) { -+ /* overflow */ -+ goto sendmsg_emsgsize; -+ } -+ p = pbuf_alloc(PBUF_TRANSPORT, 0, PBUF_REF); -+ if (p == NULL) { -+ err = ERR_MEM; /* let netbuf_delete() cleanup chain_buf */ -+ break; -+ } -+ p->payload = msg->msg_iov[i].iov_base; -+ p->len = p->tot_len = (u16_t)msg->msg_iov[i].iov_len; -+ /* netbuf empty, add new pbuf */ -+ if (chain_buf.p == NULL) { -+ chain_buf.p = chain_buf.ptr = p; -+ /* add pbuf to existing pbuf chain */ -+ } else { -+ if (chain_buf.p->tot_len + p->len > 0xffff) { -+ /* overflow */ -+ pbuf_free(p); -+ goto sendmsg_emsgsize; -+ } -+ pbuf_cat(chain_buf.p, p); -+ } -+ } -+ /* save size of total chain */ -+ if (err == ERR_OK) { -+ size = netbuf_len(&chain_buf); -+ } -+#endif /* LWIP_NETIF_TX_SINGLE_PBUF */ -+ -+ if (err == ERR_OK) { -+#if LWIP_IPV4 && LWIP_IPV6 -+ /* Dual-stack: Unmap IPv4 mapped IPv6 addresses */ -+ if (IP_IS_V6_VAL(chain_buf.addr) && ip6_addr_isipv4mappedipv6(ip_2_ip6(&chain_buf.addr))) { -+ unmap_ipv4_mapped_ipv6(ip_2_ip4(&chain_buf.addr), ip_2_ip6(&chain_buf.addr)); -+ IP_SET_TYPE_VAL(chain_buf.addr, IPADDR_TYPE_V4); -+ } -+#endif /* LWIP_IPV4 && LWIP_IPV6 */ -+ -+ /* send the data */ -+ err = netconn_send(sock->conn, &chain_buf); -+ } -+ -+ /* deallocated the buffer */ -+ netbuf_free(&chain_buf); -+ -+ sock_set_errno(sock, err_to_errno(err)); -+ done_socket(sock); -+ return (err == ERR_OK ? size : -1); -+sendmsg_emsgsize: -+ sock_set_errno(sock, EMSGSIZE); -+ netbuf_free(&chain_buf); -+ done_socket(sock); -+ return -1; -+ } -+#else /* LWIP_UDP || LWIP_RAW */ -+ sock_set_errno(sock, err_to_errno(ERR_ARG)); -+ done_socket(sock); -+ return -1; -+#endif /* LWIP_UDP || LWIP_RAW */ -+} -+ -+ssize_t -+lwip_sendto(int s, const void *data, size_t size, int flags, -+ const struct sockaddr *to, socklen_t tolen) -+{ -+ struct lwip_sock *sock; -+ err_t err; -+ u16_t short_size; -+ u16_t remote_port = 0; -+ struct netbuf buf; -+#if (PF_PACKET_SOCKET & LWIP_LITEOS_COMPAT) -+ const struct sockaddr_ll *to_ll = NULL; -+#endif -+ const struct sockaddr_in *to_in = NULL; -+ -+ unsigned int acceptable_flags = 0; -+ -+ sock = get_socket(s); -+ if (!sock) { -+ return -1; -+ } -+ -+ if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) { -+#if LWIP_TCP -+ done_socket(sock); -+ return lwip_send(s, data, size, flags); -+#else /* LWIP_TCP */ -+ LWIP_UNUSED_ARG(flags); -+ sock_set_errno(sock, err_to_errno(ERR_ARG)); -+ done_socket(sock); -+ return -1; -+#endif /* LWIP_TCP */ -+ } -+ -+#if PF_PACKET_SOCKET -+ if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) & NETCONN_PACKET_RAW) { -+ to_ll = (const struct sockaddr_ll *)(void *)to; -+ -+ LWIP_ERROR("lwip_sendto: invalid address", (((data != NULL) && (size!=0)) && -+ (((to_ll != NULL) && (tolen == sizeof(struct sockaddr_ll))) && -+ ((to_ll->sll_family) == PF_PACKET) && ((((mem_ptr_t)to_ll) % 4) == 0)) && -+ (to_ll->sll_ifindex <= LWIP_NETIF_IFINDEX_MAX)), -+ sock_set_errno(sock, err_to_errno(ERR_VAL)); -+ done_socket(sock); return -1); -+ -+ LWIP_ERROR("lwip_sendto: invalid address family", ((to_ll->sll_family) == PF_PACKET), -+ sock_set_errno(sock, err_to_errno(ERR_AFNOSUPP)); -+ done_socket(sock); return -1); -+ -+ LWIP_ERROR("lwip_sendto: invalid flags. Should be 0", (flags == 0), -+ sock_set_errno(sock, err_to_errno(ERR_OPNOTSUPP)); -+ done_socket(sock); return -1); -+ -+ if (size > LWIP_MAX_PF_RAW_SEND_SIZE) { -+ sock_set_errno(sock, EMSGSIZE); -+ done_socket(sock); -+ return -1; -+ } -+ } else -+#endif /* PF_PACKET_SOCKET */ -+ { -+ to_in = (const struct sockaddr_in *)(void*)to; -+ acceptable_flags = acceptable_flags | MSG_MORE | MSG_DONTWAIT | MSG_NOSIGNAL; -+ if ((~acceptable_flags) & (unsigned int)flags) { -+ sock_set_errno(sock, err_to_errno(ERR_OPNOTSUPP)); -+ done_socket(sock); -+ return -1; -+ } -+ -+ LWIP_ERROR("lwip_sendto: invalid address", ((data != NULL) && (size!=0) && (flags>=0)), -+ sock_set_errno(sock, err_to_errno(ERR_VAL)); -+ done_socket(sock); return -1); -+ -+ LWIP_ERROR("lwip_sendto: invalid address", (((to_in == NULL) && (tolen == 0)) || -+ (((to_in == NULL) && (tolen != 0)) || IS_SOCK_ADDR_LEN_VALID(tolen))), -+ sock_set_errno(sock, err_to_errno(ERR_VAL)); -+ done_socket(sock); -+ return -1); -+ -+ LWIP_ERROR("lwip_sendto: invalid address", (to == NULL || IS_SOCK_ADDR_TYPE_VALID(to)), -+ sock_set_errno(sock, err_to_errno(ERR_AFNOSUPPORT)); -+ done_socket(sock); -+ return -1); -+ -+ if (size > LWIP_MAX_UDP_RAW_SEND_SIZE) { -+ sock_set_errno(sock, EMSGSIZE); -+ done_socket(sock); -+ return -1; -+ } -+ -+ } -+ short_size = (u16_t)size; -+ LWIP_ERROR("lwip_sendto: invalid address", (((to == NULL) && (tolen == 0)) || -+ (IS_SOCK_ADDR_LEN_VALID(tolen) && -+ ((to != NULL) && (IS_SOCK_ADDR_TYPE_VALID(to) && IS_SOCK_ADDR_ALIGNED(to))))), -+ sock_set_errno(sock, err_to_errno(ERR_ARG)); done_socket(sock); return -1;); -+ LWIP_UNUSED_ARG(tolen); -+ -+ /* initialize a buffer */ -+ buf.p = buf.ptr = NULL; -+#if LWIP_CHECKSUM_ON_COPY -+ buf.flags = 0; -+#endif /* LWIP_CHECKSUM_ON_COPY */ -+#if PF_PACKET_SOCKET -+ buf.netifindex = 0; -+#endif -+ if (to) { -+ SOCKADDR_TO_IPADDR_PORT(to, &buf.addr, remote_port); -+ } else { -+ remote_port = 0; -+ ip_addr_set_any(NETCONNTYPE_ISIPV6(netconn_type(sock->conn)), &buf.addr); -+ } -+ netbuf_fromport(&buf) = remote_port; -+ -+ -+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_sendto(%d, data=%p, short_size=%"U16_F", flags=0x%x to=", -+ s, data, short_size, flags)); -+#if PF_PACKET_SOCKET -+ if (buf.flags & NETBUF_FLAG_IFINDEX) { -+ LWIP_DEBUGF(SOCKETS_DEBUG, (" netifindex = %d\n", buf.netifindex)); -+ } else -+#endif -+ { -+ ip_addr_debug_print_val(SOCKETS_DEBUG, buf.addr); -+ LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F"\n", remote_port)); -+ } -+ /* make the buffer point to the data that should be sent */ -+#if LWIP_NETIF_TX_SINGLE_PBUF -+ /* Allocate a new netbuf and copy the data into it. */ -+ if (netbuf_alloc(&buf, short_size, NETCONNTYPE_GROUP(netconn_type(sock->conn))) == NULL) { -+ err = ERR_MEM; -+ } else { -+#if LWIP_CHECKSUM_ON_COPY -+#if PF_PACKET_SOCKET -+ if ((NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_PACKET_RAW) && -+ (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_RAW)) -+#else -+ if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_RAW) -+#endif -+ { -+ u16_t chksum = LWIP_CHKSUM_COPY(buf.p->payload, data, short_size); -+ netbuf_set_chksum(&buf, chksum); -+ } else -+#endif /* LWIP_CHECKSUM_ON_COPY */ -+ { -+ MEMCPY(buf.p->payload, data, short_size); -+ } -+ err = ERR_OK; -+ } -+#else /* LWIP_NETIF_TX_SINGLE_PBUF */ -+ err = netbuf_ref(&buf, data, short_size); -+#endif /* LWIP_NETIF_TX_SINGLE_PBUF */ -+ if (err == ERR_OK) { -+#if LWIP_IPV4 && LWIP_IPV6 -+ /* Dual-stack: Unmap IPv4 mapped IPv6 addresses */ -+ if (IP_IS_V6_VAL(buf.addr) && ip6_addr_isipv4mappedipv6(ip_2_ip6(&buf.addr))) { -+ unmap_ipv4_mapped_ipv6(ip_2_ip4(&buf.addr), ip_2_ip6(&buf.addr)); -+ IP_SET_TYPE_VAL(buf.addr, IPADDR_TYPE_V4); -+ } -+#endif /* LWIP_IPV4 && LWIP_IPV6 */ -+ -+ /* send the data */ -+ err = netconn_send(sock->conn, &buf); -+ } -+ -+ /* deallocated the buffer */ -+ netbuf_free(&buf); -+ -+ sock_set_errno(sock, err_to_errno(err)); -+ done_socket(sock); -+ return (err == ERR_OK ? short_size : -1); -+} -+ -+int -+lwip_socket(int domain, int type, int protocol) -+{ -+ struct netconn *conn; -+ int i; -+ -+ LWIP_UNUSED_ARG(domain); /* @todo: check this */ -+ LWIP_ERROR("domain invalid\n", (LWIP_IS_VALID_DOMAIN(domain)), -+ set_errno(EAFNOSUPPORT); return -1); -+ -+ LWIP_ERROR("flag invalid\n", !(type & ~SOCK_TYPE_MASK), -+ set_errno(EINVAL); return -1); -+#if PF_PACKET_SOCKET -+ LWIP_ERROR("Invalid socket type for PF_PACKET domain\n", ((domain != PF_PACKET) || (type == SOCK_RAW)), -+ set_errno(ESOCKTNOSUPPORT); return -1); -+#endif -+ -+ /* create a netconn */ -+ switch (type) { -+ case SOCK_RAW: -+#if PF_PACKET_SOCKET -+ if (domain == PF_PACKET) { -+ conn = netconn_new_with_proto_and_callback(DOMAIN_TO_NETCONN_TYPE(domain, NETCONN_PACKET_RAW), -+ (u16_t)protocol, event_callback); -+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_RAW, %d) = ", "PF_PACKET", protocol)); -+ } else -+#endif -+ { -+ conn = netconn_new_with_proto_and_callback(DOMAIN_TO_NETCONN_TYPE(domain, NETCONN_RAW), -+ (u8_t)protocol, DEFAULT_SOCKET_EVENTCB); -+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_RAW, %d) = ", -+ domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol)); -+ } -+ break; -+ case SOCK_DGRAM: -+ conn = netconn_new_with_callback(DOMAIN_TO_NETCONN_TYPE(domain, -+ ((protocol == IPPROTO_UDPLITE) ? NETCONN_UDPLITE : NETCONN_UDP)), -+ DEFAULT_SOCKET_EVENTCB); -+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_DGRAM, %d) = ", -+ domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol)); -+#if LWIP_NETBUF_RECVINFO -+ if (conn) { -+ /* netconn layer enables pktinfo by default, sockets default to off */ -+ conn->flags &= ~NETCONN_FLAG_PKTINFO; -+ } -+#endif /* LWIP_NETBUF_RECVINFO */ -+ break; -+ case SOCK_STREAM: -+ conn = netconn_new_with_callback(DOMAIN_TO_NETCONN_TYPE(domain, NETCONN_TCP), DEFAULT_SOCKET_EVENTCB); -+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_STREAM, %d) = ", -+ domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol)); -+ break; -+ default: -+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%d, %d/UNKNOWN, %d) = -1\n", -+ domain, type, protocol)); -+ set_errno(EINVAL); -+ return -1; -+ } -+ -+ if (!conn) { -+ LWIP_DEBUGF(SOCKETS_DEBUG, ("-1 / ENOBUFS (could not create netconn)\n")); -+ set_errno(ENOBUFS); -+ return -1; -+ } -+ -+ i = alloc_socket(conn, 0); -+ -+ if (i == -1) { -+ netconn_delete(conn); -+ set_errno(ENFILE); -+ return -1; -+ } -+ conn->socket = i; -+ done_socket(&sockets[i - LWIP_SOCKET_OFFSET]); -+ LWIP_DEBUGF(SOCKETS_DEBUG, ("%d\n", i)); -+ set_errno(0); -+ return i; -+} -+ -+ssize_t -+lwip_write(int s, const void *data, size_t size) -+{ -+ return lwip_send(s, data, size, 0); -+} -+ -+ssize_t -+lwip_writev(int s, const struct iovec *iov, int iovcnt) -+{ -+ struct msghdr msg; -+ -+ msg.msg_name = NULL; -+ msg.msg_namelen = 0; -+ /* Hack: we have to cast via number to cast from 'const' pointer to non-const. -+ Blame the opengroup standard for this inconsistency. */ -+ msg.msg_iov = LWIP_CONST_CAST(struct iovec *, iov); -+ msg.msg_iovlen = iovcnt; -+ msg.msg_control = NULL; -+ msg.msg_controllen = 0; -+ msg.msg_flags = 0; -+ return lwip_sendmsg(s, &msg, 0); -+} -+ -+#if LWIP_SOCKET_SELECT || LWIP_SOCKET_POLL -+/* Add select_cb to select_cb_list. */ -+static void -+lwip_link_select_cb(struct lwip_select_cb *select_cb) -+{ -+ LWIP_SOCKET_SELECT_DECL_PROTECT(lev); -+ -+ /* Protect the select_cb_list */ -+ LWIP_SOCKET_SELECT_PROTECT(lev); -+ -+ /* Put this select_cb on top of list */ -+ select_cb->next = select_cb_list; -+ if (select_cb_list != NULL) { -+ select_cb_list->prev = select_cb; -+ } -+ select_cb_list = select_cb; -+#if !LWIP_TCPIP_CORE_LOCKING -+ /* Increasing this counter tells select_check_waiters that the list has changed. */ -+ select_cb_ctr++; -+#endif -+ -+ /* Now we can safely unprotect */ -+ LWIP_SOCKET_SELECT_UNPROTECT(lev); -+} -+ -+/* Remove select_cb from select_cb_list. */ -+static void -+lwip_unlink_select_cb(struct lwip_select_cb *select_cb) -+{ -+ LWIP_SOCKET_SELECT_DECL_PROTECT(lev); -+ -+ /* Take us off the list */ -+ LWIP_SOCKET_SELECT_PROTECT(lev); -+ if (select_cb->next != NULL) { -+ select_cb->next->prev = select_cb->prev; -+ } -+ if (select_cb_list == select_cb) { -+ LWIP_ASSERT("select_cb->prev == NULL", select_cb->prev == NULL); -+ select_cb_list = select_cb->next; -+ } else { -+ LWIP_ASSERT("select_cb->prev != NULL", select_cb->prev != NULL); -+ select_cb->prev->next = select_cb->next; -+ } -+#if !LWIP_TCPIP_CORE_LOCKING -+ /* Increasing this counter tells select_check_waiters that the list has changed. */ -+ select_cb_ctr++; -+#endif -+ LWIP_SOCKET_SELECT_UNPROTECT(lev); -+} -+#endif /* LWIP_SOCKET_SELECT || LWIP_SOCKET_POLL */ -+ -+#if LWIP_SOCKET_SELECT -+/** -+ * Go through the readset and writeset lists and see which socket of the sockets -+ * set in the sets has events. On return, readset, writeset and exceptset have -+ * the sockets enabled that had events. -+ * -+ * @param maxfdp1 the highest socket index in the sets -+ * @param readset_in set of sockets to check for read events -+ * @param writeset_in set of sockets to check for write events -+ * @param exceptset_in set of sockets to check for error events -+ * @param readset_out set of sockets that had read events -+ * @param writeset_out set of sockets that had write events -+ * @param exceptset_out set os sockets that had error events -+ * @return number of sockets that had events (read/write/exception) (>= 0) -+ */ -+static int -+lwip_selscan(int maxfdp1, fd_set *readset_in, fd_set *writeset_in, fd_set *exceptset_in, -+ fd_set *readset_out, fd_set *writeset_out, fd_set *exceptset_out) -+{ -+ int i, nready = 0; -+ fd_set lreadset, lwriteset, lexceptset; -+ struct lwip_sock *sock; -+ SYS_ARCH_DECL_PROTECT(lev); -+ -+ FD_ZERO(&lreadset); -+ FD_ZERO(&lwriteset); -+ FD_ZERO(&lexceptset); -+ -+ /* Go through each socket in each list to count number of sockets which -+ currently match */ -+ for (i = LWIP_SOCKET_OFFSET; i < maxfdp1; i++) { -+ /* if this FD is not in the set, continue */ -+ if (!(readset_in && FD_ISSET(i, readset_in)) && -+ !(writeset_in && FD_ISSET(i, writeset_in)) && -+ !(exceptset_in && FD_ISSET(i, exceptset_in))) { -+ continue; -+ } -+ /* First get the socket's status (protected)... */ -+ SYS_ARCH_PROTECT(lev); -+ sock = tryget_socket_unconn_locked(i); -+ if (sock != NULL) { -+ void *lastdata = sock->lastdata.pbuf; -+ s16_t rcvevent = sock->rcvevent; -+ u16_t sendevent = sock->sendevent; -+ u16_t errevent = sock->errevent; -+ SYS_ARCH_UNPROTECT(lev); -+ -+ /* ... then examine it: */ -+ /* See if netconn of this socket is ready for read */ -+ if (readset_in && FD_ISSET(i, readset_in) && ((lastdata != NULL) || (rcvevent > 0))) { -+ FD_SET(i, &lreadset); -+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_selscan: fd=%d ready for reading\n", i)); -+ nready++; -+ } -+ /* See if netconn of this socket is ready for write */ -+ if (writeset_in && FD_ISSET(i, writeset_in) && (sendevent != 0)) { -+ FD_SET(i, &lwriteset); -+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_selscan: fd=%d ready for writing\n", i)); -+ nready++; -+ } -+ /* See if netconn of this socket had an error */ -+ if (exceptset_in && FD_ISSET(i, exceptset_in) && (errevent != 0)) { -+ FD_SET(i, &lexceptset); -+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_selscan: fd=%d ready for exception\n", i)); -+ nready++; -+ } -+ done_socket(sock); -+ } else { -+ SYS_ARCH_UNPROTECT(lev); -+ /* no a valid open socket */ -+ return -1; -+ } -+ } -+ /* copy local sets to the ones provided as arguments */ -+ *readset_out = lreadset; -+ *writeset_out = lwriteset; -+ *exceptset_out = lexceptset; -+ -+ LWIP_ASSERT("nready >= 0", nready >= 0); -+ return nready; -+} -+ -+#if LWIP_NETCONN_FULLDUPLEX -+/* Mark all of the set sockets in one of the three fdsets passed to select as used. -+ * All sockets are marked (and later unmarked), whether they are open or not. -+ * This is OK as lwip_selscan aborts select when non-open sockets are found. -+ */ -+static void -+lwip_select_inc_sockets_used_set(int maxfdp, fd_set *fdset, fd_set *used_sockets) -+{ -+ SYS_ARCH_DECL_PROTECT(lev); -+ if (fdset) { -+ int i; -+ for (i = LWIP_SOCKET_OFFSET; i < maxfdp; i++) { -+ /* if this FD is in the set, lock it (unless already done) */ -+ if (FD_ISSET(i, fdset) && !FD_ISSET(i, used_sockets)) { -+ struct lwip_sock *sock; -+ SYS_ARCH_PROTECT(lev); -+ sock = tryget_socket_unconn_locked(i); -+ if (sock != NULL) { -+ /* leave the socket used until released by lwip_select_dec_sockets_used */ -+ FD_SET(i, used_sockets); -+ } -+ SYS_ARCH_UNPROTECT(lev); -+ } -+ } -+ } -+} -+ -+/* Mark all sockets passed to select as used to prevent them from being freed -+ * from other threads while select is running. -+ * Marked sockets are added to 'used_sockets' to mark them only once an be able -+ * to unmark them correctly. -+ */ -+static void -+lwip_select_inc_sockets_used(int maxfdp, fd_set *fdset1, fd_set *fdset2, fd_set *fdset3, fd_set *used_sockets) -+{ -+ FD_ZERO(used_sockets); -+ lwip_select_inc_sockets_used_set(maxfdp, fdset1, used_sockets); -+ lwip_select_inc_sockets_used_set(maxfdp, fdset2, used_sockets); -+ lwip_select_inc_sockets_used_set(maxfdp, fdset3, used_sockets); -+} -+ -+/* Let go all sockets that were marked as used when starting select */ -+static void -+lwip_select_dec_sockets_used(int maxfdp, fd_set *used_sockets) -+{ -+ int i; -+ for (i = LWIP_SOCKET_OFFSET; i < maxfdp; i++) { -+ /* if this FD is not in the set, continue */ -+ if (FD_ISSET(i, used_sockets)) { -+ struct lwip_sock *sock = tryget_socket_unconn_nouse(i); -+ LWIP_ASSERT("socket gone at the end of select", sock != NULL); -+ if (sock != NULL) { -+ done_socket(sock); -+ } -+ } -+ } -+} -+#else /* LWIP_NETCONN_FULLDUPLEX */ -+#define lwip_select_inc_sockets_used(maxfdp1, readset, writeset, exceptset, used_sockets) -+#define lwip_select_dec_sockets_used(maxfdp1, used_sockets) -+#endif /* LWIP_NETCONN_FULLDUPLEX */ -+ -+int -+lwip_select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset, -+ struct timeval *timeout) -+{ -+ u32_t waitres = 0; -+ int nready; -+ fd_set lreadset, lwriteset, lexceptset; -+ u32_t msectimeout; -+ int i; -+ int maxfdp2; -+#if LWIP_NETCONN_SEM_PER_THREAD -+ int waited = 0; -+#endif -+#if LWIP_NETCONN_FULLDUPLEX -+ fd_set used_sockets; -+#endif -+ SYS_ARCH_DECL_PROTECT(lev); -+ -+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select(%d, %p, %p, %p, tvsec=%"S32_F" tvusec=%"S32_F")\n", -+ maxfdp1, (void *)readset, (void *) writeset, (void *) exceptset, -+ timeout ? (s32_t)timeout->tv_sec : (s32_t) - 1, -+ timeout ? (s32_t)timeout->tv_usec : (s32_t) - 1)); -+ -+/*if ((maxfdp1 < 0) || (maxfdp1 > LWIP_SELECT_MAXNFDS)) { -+ set_errno(EINVAL); -+ return -1; -+ } -+ */ -+ -+ lwip_select_inc_sockets_used(maxfdp1, readset, writeset, exceptset, &used_sockets); -+ -+ /* Go through each socket in each list to count number of sockets which -+ currently match */ -+ nready = lwip_selscan(maxfdp1, readset, writeset, exceptset, &lreadset, &lwriteset, &lexceptset); -+ -+ if (nready < 0) { -+ /* one of the sockets in one of the fd_sets was invalid */ -+ set_errno(EBADF); -+ lwip_select_dec_sockets_used(maxfdp1, &used_sockets); -+ return -1; -+ } else if (nready > 0) { -+ /* one or more sockets are set, no need to wait */ -+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select: nready=%d\n", nready)); -+ } else { -+ /* If we don't have any current events, then suspend if we are supposed to */ -+ if (timeout && timeout->tv_sec == 0 && timeout->tv_usec == 0) { -+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select: no timeout, returning 0\n")); -+ /* This is OK as the local fdsets are empty and nready is zero, -+ or we would have returned earlier. */ -+ } else { -+ /* None ready: add our semaphore to list: -+ We don't actually need any dynamic memory. Our entry on the -+ list is only valid while we are in this function, so it's ok -+ to use local variables (unless we're running in MPU compatible -+ mode). */ -+ API_SELECT_CB_VAR_DECLARE(select_cb); -+ API_SELECT_CB_VAR_ALLOC(select_cb, set_errno(ENOMEM); lwip_select_dec_sockets_used(maxfdp1, &used_sockets); return -1); -+ memset(&API_SELECT_CB_VAR_REF(select_cb), 0, sizeof(struct lwip_select_cb)); -+ -+ API_SELECT_CB_VAR_REF(select_cb).readset = readset; -+ API_SELECT_CB_VAR_REF(select_cb).writeset = writeset; -+ API_SELECT_CB_VAR_REF(select_cb).exceptset = exceptset; -+#if LWIP_NETCONN_SEM_PER_THREAD -+ API_SELECT_CB_VAR_REF(select_cb).sem = LWIP_NETCONN_THREAD_SEM_GET(); -+#else /* LWIP_NETCONN_SEM_PER_THREAD */ -+ if (sys_sem_new(&API_SELECT_CB_VAR_REF(select_cb).sem, 0) != ERR_OK) { -+ /* failed to create semaphore */ -+ set_errno(ENOMEM); -+ lwip_select_dec_sockets_used(maxfdp1, &used_sockets); -+ API_SELECT_CB_VAR_FREE(select_cb); -+ return -1; -+ } -+#endif /* LWIP_NETCONN_SEM_PER_THREAD */ -+ -+ lwip_link_select_cb(&API_SELECT_CB_VAR_REF(select_cb)); -+ -+ /* Increase select_waiting for each socket we are interested in */ -+ maxfdp2 = maxfdp1; -+ for (i = LWIP_SOCKET_OFFSET; i < maxfdp1; i++) { -+ if ((readset && FD_ISSET(i, readset)) || -+ (writeset && FD_ISSET(i, writeset)) || -+ (exceptset && FD_ISSET(i, exceptset))) { -+ struct lwip_sock *sock; -+ SYS_ARCH_PROTECT(lev); -+ sock = tryget_socket_unconn_locked(i); -+ if (sock != NULL) { -+ sock->select_waiting++; -+ if (sock->select_waiting == 0) { -+ /* overflow - too many threads waiting */ -+ sock->select_waiting--; -+ nready = -1; -+ maxfdp2 = i; -+ SYS_ARCH_UNPROTECT(lev); -+ done_socket(sock); -+ set_errno(EBUSY); -+ break; -+ } -+ SYS_ARCH_UNPROTECT(lev); -+ done_socket(sock); -+ } else { -+ /* Not a valid socket */ -+ nready = -1; -+ maxfdp2 = i; -+ SYS_ARCH_UNPROTECT(lev); -+ set_errno(EBADF); -+ break; -+ } -+ } -+ } -+ -+ if (nready >= 0) { -+ /* Call lwip_selscan again: there could have been events between -+ the last scan (without us on the list) and putting us on the list! */ -+ nready = lwip_selscan(maxfdp1, readset, writeset, exceptset, &lreadset, &lwriteset, &lexceptset); -+ if (!nready) { -+ /* Still none ready, just wait to be woken */ -+ if (timeout == 0) { -+ /* Wait forever */ -+ msectimeout = 0; -+ } else { -+ long msecs_long = ((timeout->tv_sec * 1000) + ((timeout->tv_usec + 500) / 1000)); -+ if (msecs_long <= 0) { -+ /* Wait 1ms at least (0 means wait forever) */ -+ msectimeout = 1; -+ } else { -+ msectimeout = (u32_t)msecs_long; -+ } -+ } -+ -+ waitres = sys_arch_sem_wait(SELECT_SEM_PTR(API_SELECT_CB_VAR_REF(select_cb).sem), msectimeout); -+#if LWIP_NETCONN_SEM_PER_THREAD -+ waited = 1; -+#endif -+ } -+ } -+ -+ /* Decrease select_waiting for each socket we are interested in */ -+ for (i = LWIP_SOCKET_OFFSET; i < maxfdp2; i++) { -+ if ((readset && FD_ISSET(i, readset)) || -+ (writeset && FD_ISSET(i, writeset)) || -+ (exceptset && FD_ISSET(i, exceptset))) { -+ struct lwip_sock *sock; -+ SYS_ARCH_PROTECT(lev); -+ sock = tryget_socket_unconn_locked(i); -+ if (sock != NULL) { -+ /* for now, handle select_waiting==0... */ -+ LWIP_ASSERT("sock->select_waiting > 0", sock->select_waiting > 0); -+ if (sock->select_waiting > 0) { -+ sock->select_waiting--; -+ } -+ SYS_ARCH_UNPROTECT(lev); -+ done_socket(sock); -+ } else { -+ SYS_ARCH_UNPROTECT(lev); -+ /* Not a valid socket */ -+ nready = -1; -+ set_errno(EBADF); -+ } -+ } -+ } -+ -+ lwip_unlink_select_cb(&API_SELECT_CB_VAR_REF(select_cb)); -+ -+#if LWIP_NETCONN_SEM_PER_THREAD -+ if (API_SELECT_CB_VAR_REF(select_cb).sem_signalled && (!waited || (waitres == SYS_ARCH_TIMEOUT))) { -+ /* don't leave the thread-local semaphore signalled */ -+ sys_arch_sem_wait(API_SELECT_CB_VAR_REF(select_cb).sem, 1); -+ } -+#else /* LWIP_NETCONN_SEM_PER_THREAD */ -+ sys_sem_free(&API_SELECT_CB_VAR_REF(select_cb).sem); -+#endif /* LWIP_NETCONN_SEM_PER_THREAD */ -+ API_SELECT_CB_VAR_FREE(select_cb); -+ -+ if (nready < 0) { -+ /* This happens when a socket got closed while waiting */ -+ lwip_select_dec_sockets_used(maxfdp1, &used_sockets); -+ return -1; -+ } -+ -+ if (waitres == SYS_ARCH_TIMEOUT) { -+ /* Timeout */ -+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select: timeout expired\n")); -+ /* This is OK as the local fdsets are empty and nready is zero, -+ or we would have returned earlier. */ -+ } else { -+ /* See what's set now after waiting */ -+ nready = lwip_selscan(maxfdp1, readset, writeset, exceptset, &lreadset, &lwriteset, &lexceptset); -+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select: nready=%d\n", nready)); -+ } -+ } -+ } -+ -+ lwip_select_dec_sockets_used(maxfdp1, &used_sockets); -+ set_errno(0); -+ if (readset) { -+ *readset = lreadset; -+ } -+ if (writeset) { -+ *writeset = lwriteset; -+ } -+ if (exceptset) { -+ *exceptset = lexceptset; -+ } -+ return nready; -+} -+#endif /* LWIP_SOCKET_SELECT */ -+ -+#if LWIP_SOCKET_POLL -+/** Options for the lwip_pollscan function. */ -+enum lwip_pollscan_opts -+{ -+ /** Clear revents in each struct pollfd. */ -+ LWIP_POLLSCAN_CLEAR = 1, -+ -+ /** Increment select_waiting in each struct lwip_sock. */ -+ LWIP_POLLSCAN_INC_WAIT = 2, -+ -+ /** Decrement select_waiting in each struct lwip_sock. */ -+ LWIP_POLLSCAN_DEC_WAIT = 4 -+}; -+ -+/** -+ * Update revents in each struct pollfd. -+ * Optionally update select_waiting in struct lwip_sock. -+ * -+ * @param fds array of structures to update -+ * @param nfds number of structures in fds -+ * @param opts what to update and how -+ * @return number of structures that have revents != 0 -+ */ -+static int -+lwip_pollscan(struct pollfd *fds, nfds_t nfds, enum lwip_pollscan_opts opts) -+{ -+ int nready = 0; -+ nfds_t fdi; -+ struct lwip_sock *sock; -+ SYS_ARCH_DECL_PROTECT(lev); -+ -+ /* Go through each struct pollfd in the array. */ -+ for (fdi = 0; fdi < nfds; fdi++) { -+ if ((opts & LWIP_POLLSCAN_CLEAR) != 0) { -+ fds[fdi].revents = 0; -+ } -+ -+ /* Negative fd means the caller wants us to ignore this struct. -+ POLLNVAL means we already detected that the fd is invalid; -+ if another thread has since opened a new socket with that fd, -+ we must not use that socket. */ -+ if (fds[fdi].fd >= 0 && (fds[fdi].revents & POLLNVAL) == 0) { -+ /* First get the socket's status (protected)... */ -+ SYS_ARCH_PROTECT(lev); -+ sock = tryget_socket_unconn_locked(fds[fdi].fd); -+ if (sock != NULL) { -+ void* lastdata = sock->lastdata.pbuf; -+ s16_t rcvevent = sock->rcvevent; -+ u16_t sendevent = sock->sendevent; -+ u16_t errevent = sock->errevent; -+ -+ if ((opts & LWIP_POLLSCAN_INC_WAIT) != 0) { -+ sock->select_waiting++; -+ if (sock->select_waiting == 0) { -+ /* overflow - too many threads waiting */ -+ sock->select_waiting--; -+ nready = -1; -+ SYS_ARCH_UNPROTECT(lev); -+ done_socket(sock); -+ break; -+ } -+ } else if ((opts & LWIP_POLLSCAN_DEC_WAIT) != 0) { -+ /* for now, handle select_waiting==0... */ -+ LWIP_ASSERT("sock->select_waiting > 0", sock->select_waiting > 0); -+ if (sock->select_waiting > 0) { -+ sock->select_waiting--; -+ } -+ } -+ SYS_ARCH_UNPROTECT(lev); -+ done_socket(sock); -+ -+ /* ... then examine it: */ -+ /* See if netconn of this socket is ready for read */ -+ if ((fds[fdi].events & POLLIN) != 0 && ((lastdata != NULL) || (rcvevent > 0))) { -+ fds[fdi].revents |= POLLIN; -+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_pollscan: fd=%d ready for reading\n", fds[fdi].fd)); -+ } -+ /* See if netconn of this socket is ready for write */ -+ if ((fds[fdi].events & POLLOUT) != 0 && (sendevent != 0)) { -+ fds[fdi].revents |= POLLOUT; -+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_pollscan: fd=%d ready for writing\n", fds[fdi].fd)); -+ } -+ /* See if netconn of this socket had an error */ -+ if (errevent != 0) { -+ /* POLLERR is output only. */ -+ fds[fdi].revents |= POLLERR; -+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_pollscan: fd=%d ready for exception\n", fds[fdi].fd)); -+ } -+ } else { -+ /* Not a valid socket */ -+ SYS_ARCH_UNPROTECT(lev); -+ /* POLLNVAL is output only. */ -+ fds[fdi].revents |= POLLNVAL; -+ return -1; -+ } -+ } -+ -+ /* Will return the number of structures that have events, -+ not the number of events. */ -+ if (fds[fdi].revents != 0) { -+ nready++; -+ } -+ } -+ -+ LWIP_ASSERT("nready >= 0", nready >= 0); -+ return nready; -+} -+ -+#if LWIP_NETCONN_FULLDUPLEX -+/* Mark all sockets as used. -+ * -+ * All sockets are marked (and later unmarked), whether they are open or not. -+ * This is OK as lwip_pollscan aborts select when non-open sockets are found. -+ */ -+static void -+lwip_poll_inc_sockets_used(struct pollfd *fds, nfds_t nfds) -+{ -+ nfds_t fdi; -+ -+ if(fds) { -+ /* Go through each struct pollfd in the array. */ -+ for (fdi = 0; fdi < nfds; fdi++) { -+ /* Increase the reference counter */ -+ tryget_socket_unconn(fds[fdi].fd); -+ } -+ } -+} -+ -+/* Let go all sockets that were marked as used when starting poll */ -+static void -+lwip_poll_dec_sockets_used(struct pollfd *fds, nfds_t nfds) -+{ -+ nfds_t fdi; -+ -+ if(fds) { -+ /* Go through each struct pollfd in the array. */ -+ for (fdi = 0; fdi < nfds; fdi++) { -+ struct lwip_sock *sock = tryget_socket_unconn_nouse(fds[fdi].fd); -+ if (sock != NULL) { -+ done_socket(sock); -+ } -+ } -+ } -+} -+#else /* LWIP_NETCONN_FULLDUPLEX */ -+#define lwip_poll_inc_sockets_used(fds, nfds) -+#define lwip_poll_dec_sockets_used(fds, nfds) -+#endif /* LWIP_NETCONN_FULLDUPLEX */ -+ -+int -+lwip_poll(struct pollfd *fds, nfds_t nfds, int timeout) -+{ -+ u32_t waitres = 0; -+ int nready; -+ u32_t msectimeout; -+#if LWIP_NETCONN_SEM_PER_THREAD -+ int waited = 0; -+#endif -+ -+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_poll(%p, %d, %d)\n", -+ (void*)fds, (int)nfds, timeout)); -+ LWIP_ERROR("lwip_poll: invalid fds", ((fds != NULL && nfds > 0) || (fds == NULL && nfds == 0)), -+ set_errno(EINVAL); return -1;); -+ -+ lwip_poll_inc_sockets_used(fds, nfds); -+ -+ /* Go through each struct pollfd to count number of structures -+ which currently match */ -+ nready = lwip_pollscan(fds, nfds, LWIP_POLLSCAN_CLEAR); -+ -+ if (nready < 0) { -+ lwip_poll_dec_sockets_used(fds, nfds); -+ return -1; -+ } -+ -+ /* If we don't have any current events, then suspend if we are supposed to */ -+ if (!nready) { -+ API_SELECT_CB_VAR_DECLARE(select_cb); -+ -+ if (timeout == 0) { -+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_poll: no timeout, returning 0\n")); -+ goto return_success; -+ } -+ API_SELECT_CB_VAR_ALLOC(select_cb, set_errno(EAGAIN); lwip_poll_dec_sockets_used(fds, nfds); return -1); -+ memset(&API_SELECT_CB_VAR_REF(select_cb), 0, sizeof(struct lwip_select_cb)); -+ -+ /* None ready: add our semaphore to list: -+ We don't actually need any dynamic memory. Our entry on the -+ list is only valid while we are in this function, so it's ok -+ to use local variables. */ -+ -+ API_SELECT_CB_VAR_REF(select_cb).poll_fds = fds; -+ API_SELECT_CB_VAR_REF(select_cb).poll_nfds = nfds; -+#if LWIP_NETCONN_SEM_PER_THREAD -+ API_SELECT_CB_VAR_REF(select_cb).sem = LWIP_NETCONN_THREAD_SEM_GET(); -+#else /* LWIP_NETCONN_SEM_PER_THREAD */ -+ if (sys_sem_new(&API_SELECT_CB_VAR_REF(select_cb).sem, 0) != ERR_OK) { -+ /* failed to create semaphore */ -+ set_errno(EAGAIN); -+ lwip_poll_dec_sockets_used(fds, nfds); -+ API_SELECT_CB_VAR_FREE(select_cb); -+ return -1; -+ } -+#endif /* LWIP_NETCONN_SEM_PER_THREAD */ -+ -+ lwip_link_select_cb(&API_SELECT_CB_VAR_REF(select_cb)); -+ -+ /* Increase select_waiting for each socket we are interested in. -+ Also, check for events again: there could have been events between -+ the last scan (without us on the list) and putting us on the list! */ -+ nready = lwip_pollscan(fds, nfds, LWIP_POLLSCAN_INC_WAIT); -+ -+ if (!nready) { -+ /* Still none ready, just wait to be woken */ -+ if (timeout < 0) { -+ /* Wait forever */ -+ msectimeout = 0; -+ } else { -+ /* timeout == 0 would have been handled earlier. */ -+ LWIP_ASSERT("timeout > 0", timeout > 0); -+ msectimeout = timeout; -+ } -+ waitres = sys_arch_sem_wait(SELECT_SEM_PTR(API_SELECT_CB_VAR_REF(select_cb).sem), msectimeout); -+#if LWIP_NETCONN_SEM_PER_THREAD -+ waited = 1; -+#endif -+ } -+ -+ /* Decrease select_waiting for each socket we are interested in, -+ and check which events occurred while we waited. */ -+ nready = lwip_pollscan(fds, nfds, LWIP_POLLSCAN_DEC_WAIT); -+ -+ lwip_unlink_select_cb(&API_SELECT_CB_VAR_REF(select_cb)); -+ -+#if LWIP_NETCONN_SEM_PER_THREAD -+ if (select_cb.sem_signalled && (!waited || (waitres == SYS_ARCH_TIMEOUT))) { -+ /* don't leave the thread-local semaphore signalled */ -+ sys_arch_sem_wait(API_SELECT_CB_VAR_REF(select_cb).sem, 1); -+ } -+#else /* LWIP_NETCONN_SEM_PER_THREAD */ -+ sys_sem_free(&API_SELECT_CB_VAR_REF(select_cb).sem); -+#endif /* LWIP_NETCONN_SEM_PER_THREAD */ -+ API_SELECT_CB_VAR_FREE(select_cb); -+ -+ if (nready < 0) { -+ /* This happens when a socket got closed while waiting */ -+ lwip_poll_dec_sockets_used(fds, nfds); -+ return -1; -+ } -+ -+ if (waitres == SYS_ARCH_TIMEOUT) { -+ /* Timeout */ -+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_poll: timeout expired\n")); -+ goto return_success; -+ } -+ } -+ -+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_poll: nready=%d\n", nready)); -+return_success: -+ lwip_poll_dec_sockets_used(fds, nfds); -+ set_errno(0); -+ return nready; -+} -+ -+/** -+ * Check whether event_callback should wake up a thread waiting in -+ * lwip_poll. -+ */ -+static int -+lwip_poll_should_wake(const struct lwip_select_cb *scb, int fd, int has_recvevent, int has_sendevent, int has_errevent) -+{ -+ nfds_t fdi; -+ for (fdi = 0; fdi < scb->poll_nfds; fdi++) { -+ const struct pollfd *pollfd = &scb->poll_fds[fdi]; -+ if (pollfd->fd == fd) { -+ /* Do not update pollfd->revents right here; -+ that would be a data race because lwip_pollscan -+ accesses revents without protecting. */ -+ if (has_recvevent && (pollfd->events & POLLIN) != 0) { -+ return 1; -+ } -+ if (has_sendevent && (pollfd->events & POLLOUT) != 0) { -+ return 1; -+ } -+ if (has_errevent) { -+ /* POLLERR is output only. */ -+ return 1; -+ } -+ } -+ } -+ return 0; -+} -+#endif /* LWIP_SOCKET_POLL */ -+ -+#if LWIP_SOCKET_SELECT || LWIP_SOCKET_POLL -+/** -+ * Callback registered in the netconn layer for each socket-netconn. -+ * Processes recvevent (data available) and wakes up tasks waiting for select. -+ * -+ * @note for LWIP_TCPIP_CORE_LOCKING any caller of this function -+ * must have the core lock held when signaling the following events -+ * as they might cause select_list_cb to be checked: -+ * NETCONN_EVT_RCVPLUS -+ * NETCONN_EVT_SENDPLUS -+ * NETCONN_EVT_ERROR -+ * This requirement will be asserted in select_check_waiters() -+ */ -+static void -+event_callback(struct netconn *conn, enum netconn_evt evt, u16_t len) -+{ -+ int s, check_waiters; -+ struct lwip_sock *sock; -+ SYS_ARCH_DECL_PROTECT(lev); -+ -+ LWIP_UNUSED_ARG(len); -+ -+ /* Get socket */ -+ if (conn) { -+ s = conn->socket; -+ if (s < 0) { -+ /* Data comes in right away after an accept, even though -+ * the server task might not have created a new socket yet. -+ * Just count down (or up) if that's the case and we -+ * will use the data later. Note that only receive events -+ * can happen before the new socket is set up. */ -+ SYS_ARCH_PROTECT(lev); -+ if (conn->socket < 0) { -+ if (evt == NETCONN_EVT_RCVPLUS) { -+ /* conn->socket is -1 on initialization -+ lwip_accept adjusts sock->recvevent if conn->socket < -1 */ -+ conn->socket--; -+ } -+ SYS_ARCH_UNPROTECT(lev); -+ return; -+ } -+ s = conn->socket; -+ SYS_ARCH_UNPROTECT(lev); -+ } -+ -+ sock = get_socket(s); -+ if (!sock) { -+ return; -+ } -+ } else { -+ return; -+ } -+ -+ check_waiters = 1; -+ SYS_ARCH_PROTECT(lev); -+ /* Set event as required */ -+ switch (evt) { -+ case NETCONN_EVT_RCVPLUS: -+ sock->rcvevent++; -+ if (sock->rcvevent > 1) { -+ check_waiters = 0; -+ } -+ break; -+ case NETCONN_EVT_RCVMINUS: -+ sock->rcvevent--; -+ check_waiters = 0; -+ break; -+ case NETCONN_EVT_SENDPLUS: -+ if (sock->sendevent) { -+ check_waiters = 0; -+ } -+ sock->sendevent = 1; -+ break; -+ case NETCONN_EVT_SENDMINUS: -+ sock->sendevent = 0; -+ check_waiters = 0; -+ break; -+ case NETCONN_EVT_ERROR: -+ sock->errevent = 1; -+ break; -+ default: -+ LWIP_ASSERT("unknown event", 0); -+ break; -+ } -+ -+ if (sock->select_waiting && check_waiters) { -+ /* Save which events are active */ -+ int has_recvevent, has_sendevent, has_errevent; -+ has_recvevent = sock->rcvevent > 0; -+ has_sendevent = sock->sendevent != 0; -+ has_errevent = sock->errevent != 0; -+ SYS_ARCH_UNPROTECT(lev); -+ /* Check any select calls waiting on this socket */ -+ select_check_waiters(s, has_recvevent, has_sendevent, has_errevent); -+ } else { -+ SYS_ARCH_UNPROTECT(lev); -+ } -+ done_socket(sock); -+} -+ -+/** -+ * Check if any select waiters are waiting on this socket and its events -+ * -+ * @note on synchronization of select_cb_list: -+ * LWIP_TCPIP_CORE_LOCKING: the select_cb_list must only be accessed while holding -+ * the core lock. We do a single pass through the list and signal any waiters. -+ * Core lock should already be held when calling here!!!! -+ -+ * !LWIP_TCPIP_CORE_LOCKING: we use SYS_ARCH_PROTECT but unlock on each iteration -+ * of the loop, thus creating a possibility where a thread could modify the -+ * select_cb_list during our UNPROTECT/PROTECT. We use a generational counter to -+ * detect this change and restart the list walk. The list is expected to be small -+ */ -+static void select_check_waiters(int s, int has_recvevent, int has_sendevent, int has_errevent) -+{ -+ struct lwip_select_cb *scb; -+#if !LWIP_TCPIP_CORE_LOCKING -+ int last_select_cb_ctr; -+ SYS_ARCH_DECL_PROTECT(lev); -+#endif /* !LWIP_TCPIP_CORE_LOCKING */ -+ -+ LWIP_ASSERT_CORE_LOCKED(); -+ -+#if !LWIP_TCPIP_CORE_LOCKING -+ SYS_ARCH_PROTECT(lev); -+again: -+ /* remember the state of select_cb_list to detect changes */ -+ last_select_cb_ctr = select_cb_ctr; -+#endif /* !LWIP_TCPIP_CORE_LOCKING */ -+ for (scb = select_cb_list; scb != NULL; scb = scb->next) { -+ if (scb->sem_signalled == 0) { -+ /* semaphore not signalled yet */ -+ int do_signal = 0; -+#if LWIP_SOCKET_POLL -+ if (scb->poll_fds != NULL) { -+ do_signal = lwip_poll_should_wake(scb, s, has_recvevent, has_sendevent, has_errevent); -+ } -+#endif /* LWIP_SOCKET_POLL */ -+#if LWIP_SOCKET_SELECT && LWIP_SOCKET_POLL -+ else -+#endif /* LWIP_SOCKET_SELECT && LWIP_SOCKET_POLL */ -+#if LWIP_SOCKET_SELECT -+ { -+ /* Test this select call for our socket */ -+ if (has_recvevent) { -+ if (scb->readset && FD_ISSET(s, scb->readset)) { -+ do_signal = 1; -+ } -+ } -+ if (has_sendevent) { -+ if (!do_signal && scb->writeset && FD_ISSET(s, scb->writeset)) { -+ do_signal = 1; -+ } -+ } -+ if (has_errevent) { -+ if (!do_signal && scb->exceptset && FD_ISSET(s, scb->exceptset)) { -+ do_signal = 1; -+ } -+ } -+ } -+#endif /* LWIP_SOCKET_SELECT */ -+ if (do_signal) { -+ scb->sem_signalled = 1; -+ /* For !LWIP_TCPIP_CORE_LOCKING, we don't call SYS_ARCH_UNPROTECT() before signaling -+ the semaphore, as this might lead to the select thread taking itself off the list, -+ invalidating the semaphore. */ -+ sys_sem_signal(SELECT_SEM_PTR(scb->sem)); -+ } -+ } -+#if LWIP_TCPIP_CORE_LOCKING -+ } -+#else -+ /* unlock interrupts with each step */ -+ SYS_ARCH_UNPROTECT(lev); -+ /* this makes sure interrupt protection time is short */ -+ SYS_ARCH_PROTECT(lev); -+ if (last_select_cb_ctr != select_cb_ctr) { -+ /* someone has changed select_cb_list, restart at the beginning */ -+ goto again; -+ } -+ /* remember the state of select_cb_list to detect changes */ -+ last_select_cb_ctr = select_cb_ctr; -+ } -+ SYS_ARCH_UNPROTECT(lev); -+#endif -+} -+#endif /* LWIP_SOCKET_SELECT || LWIP_SOCKET_POLL */ -+ -+/** -+ * Close one end of a full-duplex connection. -+ */ -+int -+lwip_shutdown(int s, int how) -+{ -+ struct lwip_sock *sock; -+ err_t err; -+ u8_t shut_rx = 0, shut_tx = 0; -+ -+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_shutdown(%d, how=%d)\n", s, how)); -+ -+ sock = get_socket(s); -+ if (!sock) { -+ return -1; -+ } -+ -+ if (sock->conn != NULL) { -+ if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_TCP) { -+ sock_set_errno(sock, EOPNOTSUPP); -+ done_socket(sock); -+ return -1; -+ } -+ } else { -+ sock_set_errno(sock, ENOTCONN); -+ done_socket(sock); -+ return -1; -+ } -+ -+ if (how == SHUT_RD) { -+ shut_rx = 1; -+ } else if (how == SHUT_WR) { -+ shut_tx = 1; -+ } else if (how == SHUT_RDWR) { -+ shut_rx = 1; -+ shut_tx = 1; -+ } else { -+ sock_set_errno(sock, EINVAL); -+ done_socket(sock); -+ return -1; -+ } -+ err = netconn_shutdown(sock->conn, shut_rx, shut_tx); -+ -+ sock_set_errno(sock, err_to_errno(err)); -+ done_socket(sock); -+ return (err == ERR_OK ? 0 : -1); -+} -+ -+static int -+lwip_getaddrname(int s, struct sockaddr *name, socklen_t *namelen, u8_t local) -+{ -+ struct lwip_sock *sock; -+ union sockaddr_aligned saddr; -+ ip_addr_t naddr; -+ u16_t port; -+ err_t err; -+ socklen_t sa_len; -+ -+#if PF_PACKET_SOCKET -+ struct sockaddr_ll addr_sin; -+ struct pf_packet_sockaddr_ll sll; -+ socklen_t outlen; -+#endif -+ -+ LWIP_ERROR("lwip_getaddrname: invalid arguments", ((name != NULL) && (namelen != NULL)), -+ set_errno(EINVAL); return -1); -+ -+ sock = get_socket(s); -+ if (!sock) { -+ return -1; -+ } -+ -+#if PF_PACKET_SOCKET -+ if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_PACKET_RAW) { -+ err = netconn_get_sockaddr_pf_packet(sock->conn, &sll, local); -+ if (err != ERR_OK) { -+ sock_set_errno(sock, err_to_errno(err)); -+ done_socket(sock); -+ return -1; -+ } -+ -+ (void)memset_s(&addr_sin, sizeof(struct sockaddr_ll), 0, sizeof(struct sockaddr_ll)); -+ addr_sin.sll_family = PF_PACKET; -+ addr_sin.sll_protocol = sll.sll_protocol; -+ addr_sin.sll_pkttype = 0; -+ addr_sin.sll_ifindex = sll.if_idx; -+ addr_sin.sll_hatype = sll.sll_hatype; -+ addr_sin.sll_halen = sll.sll_halen; -+ -+ if ((sll.sll_halen > 0) && (memcpy_s(addr_sin.sll_addr, addr_sin.sll_halen, sll.sll_addr, sll.sll_halen) != EOK)) { -+ sock_set_errno(sock, err_to_errno(ERR_MEM)); -+ done_socket(sock); -+ return -1; -+ } -+ -+ outlen = sizeof(struct sockaddr_ll); -+ if (outlen > *namelen) { -+ outlen = *namelen; -+ } -+ if (memcpy_s(name, *namelen, &addr_sin, outlen) != EOK) { -+ sock_set_errno(sock, err_to_errno(ERR_MEM)); -+ done_socket(sock); -+ return -1; -+ } -+ *namelen = outlen; -+ done_socket(sock); -+ return 0; -+ } -+#endif /* PF_PACKET_SOCKET */ -+ -+ /* get the IP address and port */ -+ err = netconn_getaddr(sock->conn, &naddr, &port, local); -+ if (err != ERR_OK) { -+ sock_set_errno(sock, err_to_errno(err)); -+ done_socket(sock); -+ return -1; -+ } -+ -+#if LWIP_IPV4 && LWIP_IPV6 -+ /* Dual-stack: Map IPv4 addresses to IPv4 mapped IPv6 */ -+ if (NETCONNTYPE_ISIPV6(netconn_type(sock->conn)) && -+ IP_IS_V4_VAL(naddr)) { -+ ip4_2_ipv4_mapped_ipv6(ip_2_ip6(&naddr), ip_2_ip4(&naddr)); -+ IP_SET_TYPE_VAL(naddr, IPADDR_TYPE_V6); -+ } -+#endif /* LWIP_IPV4 && LWIP_IPV6 */ -+ -+ IPADDR_PORT_TO_SOCKADDR(&saddr, &naddr, port); -+ -+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getaddrname(%d, addr=", s)); -+ ip_addr_debug_print_val(SOCKETS_DEBUG, naddr); -+ LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F")\n", port)); -+ if (IP_IS_V4_VAL(naddr)) { -+ sa_len = sizeof(struct sockaddr_in); -+ } else { -+ sa_len = sizeof(struct sockaddr_in6); -+ } -+ -+ if (*namelen > sa_len) { -+ *namelen = sa_len; -+ } -+ MEMCPY(name, &saddr, *namelen); -+ -+ sock_set_errno(sock, 0); -+ done_socket(sock); -+ return 0; -+} -+ -+int -+lwip_getpeername(int s, struct sockaddr *name, socklen_t *namelen) -+{ -+ return lwip_getaddrname(s, name, namelen, 0); -+} -+ -+int -+lwip_getsockname(int s, struct sockaddr *name, socklen_t *namelen) -+{ -+ return lwip_getaddrname(s, name, namelen, 1); -+} -+ -+int -+lwip_getsockopt(int s, int level, int optname, void *optval, socklen_t *optlen) -+{ -+ int err; -+ struct lwip_sock *sock = get_socket(s); -+#if !LWIP_TCPIP_CORE_LOCKING -+ err_t cberr; -+ LWIP_SETGETSOCKOPT_DATA_VAR_DECLARE(data); -+#endif /* !LWIP_TCPIP_CORE_LOCKING */ -+ -+ if (!sock) { -+ return -1; -+ } -+ -+ if ((NULL == optval) || (NULL == optlen)) { -+ sock_set_errno(sock, EFAULT); -+ done_socket(sock); -+ return -1; -+ } -+ -+#if PF_PACKET_SOCKET -+ VALIDATE_LEVEL_PF_PACKET(sock, level) { -+ sock_set_errno(sock, EINVAL); -+ done_socket(sock); -+ return -1; -+ } -+#endif /* PF_PACKET_SOCKET */ -+ -+#if LWIP_TCPIP_CORE_LOCKING -+ /* core-locking can just call the -impl function */ -+ LOCK_TCPIP_CORE(); -+ err = lwip_getsockopt_impl(s, level, optname, optval, optlen); -+ UNLOCK_TCPIP_CORE(); -+ -+#else /* LWIP_TCPIP_CORE_LOCKING */ -+ -+#if LWIP_MPU_COMPATIBLE -+ /* MPU_COMPATIBLE copies the optval data, so check for max size here */ -+ if (*optlen > LWIP_SETGETSOCKOPT_MAXOPTLEN) { -+ sock_set_errno(sock, ENOBUFS); -+ done_socket(sock); -+ return -1; -+ } -+#endif /* LWIP_MPU_COMPATIBLE */ -+ -+ LWIP_SETGETSOCKOPT_DATA_VAR_ALLOC(data, sock); -+ LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).s = s; -+ LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).level = level; -+ LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optname = optname; -+ LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optlen = *optlen; -+#if !LWIP_MPU_COMPATIBLE -+ LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optval.p = optval; -+#endif /* !LWIP_MPU_COMPATIBLE */ -+ LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).err = 0; -+#if LWIP_NETCONN_SEM_PER_THREAD -+ LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).completed_sem = LWIP_NETCONN_THREAD_SEM_GET(); -+#else -+ LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).completed_sem = &sock->conn->op_completed; -+#endif -+ cberr = tcpip_callback(lwip_getsockopt_callback, &LWIP_SETGETSOCKOPT_DATA_VAR_REF(data)); -+ if (cberr != ERR_OK) { -+ LWIP_SETGETSOCKOPT_DATA_VAR_FREE(data); -+ sock_set_errno(sock, err_to_errno(cberr)); -+ done_socket(sock); -+ return -1; -+ } -+ sys_arch_sem_wait((sys_sem_t *)(LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).completed_sem), 0); -+ -+ /* write back optlen and optval */ -+ *optlen = LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optlen; -+#if LWIP_MPU_COMPATIBLE -+ MEMCPY(optval, LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optval, -+ LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optlen); -+#endif /* LWIP_MPU_COMPATIBLE */ -+ -+ /* maybe lwip_getsockopt_internal has changed err */ -+ err = LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).err; -+ LWIP_SETGETSOCKOPT_DATA_VAR_FREE(data); -+#endif /* LWIP_TCPIP_CORE_LOCKING */ -+ if (err != ERR_OK) { -+ sock_set_errno(sock, err); -+ } -+ done_socket(sock); -+ return err ? -1 : 0; -+} -+ -+#if !LWIP_TCPIP_CORE_LOCKING -+/** lwip_getsockopt_callback: only used without CORE_LOCKING -+ * to get into the tcpip_thread -+ */ -+static void -+lwip_getsockopt_callback(void *arg) -+{ -+ struct lwip_setgetsockopt_data *data; -+ LWIP_ASSERT("arg != NULL", arg != NULL); -+ data = (struct lwip_setgetsockopt_data *)arg; -+ -+ data->err = lwip_getsockopt_impl(data->s, data->level, data->optname, -+#if LWIP_MPU_COMPATIBLE -+ data->optval, -+#else /* LWIP_MPU_COMPATIBLE */ -+ data->optval.p, -+#endif /* LWIP_MPU_COMPATIBLE */ -+ &data->optlen); -+ -+ sys_sem_signal((sys_sem_t *)(data->completed_sem)); -+} -+#endif /* LWIP_TCPIP_CORE_LOCKING */ -+ -+static int -+lwip_sockopt_to_ipopt(int optname) -+{ -+ /* Map SO_* values to our internal SOF_* values -+ * We should not rely on #defines in socket.h -+ * being in sync with ip.h. -+ */ -+ switch (optname) { -+ case SO_BROADCAST: -+ return SOF_BROADCAST; -+ case SO_KEEPALIVE: -+ return SOF_KEEPALIVE; -+ case SO_REUSEADDR: -+ return SOF_REUSEADDR; -+ default: -+ LWIP_ASSERT("Unknown socket option", 0); -+ return 0; -+ } -+} -+ -+/** lwip_getsockopt_impl: the actual implementation of getsockopt: -+ * same argument as lwip_getsockopt, either called directly or through callback -+ */ -+static int -+lwip_getsockopt_impl(int s, int level, int optname, void *optval, socklen_t *optlen) -+{ -+ int err = 0; -+ struct lwip_sock *sock = tryget_socket(s); -+ if (!sock) { -+ return EBADF; -+ } -+ -+#ifdef LWIP_HOOK_SOCKETS_GETSOCKOPT -+ if (LWIP_HOOK_SOCKETS_GETSOCKOPT(s, sock, level, optname, optval, optlen, &err)) { -+ return err; -+ } -+#endif -+ -+ switch (level) { -+ -+ /* Level: SOL_SOCKET */ -+ case SOL_SOCKET: -+#if PF_PACKET_SOCKET -+ case SOL_PACKET: -+ VALIDATE_GET_PF_PKT_OPTNAME_RET(s, sock, level, optname); -+#endif /* PF_PACKET_SOCKET */ -+ VALIDATE_GET_RAW_OPTNAME_RET(sock, optname); -+ switch (optname) { -+ -+#if LWIP_TCP -+ case SO_ACCEPTCONN: -+ LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, *optlen, int); -+ if (NETCONNTYPE_GROUP(sock->conn->type) != NETCONN_TCP) { -+ done_socket(sock); -+ return ENOPROTOOPT; -+ } -+ if ((sock->conn->pcb.tcp != NULL) && (sock->conn->pcb.tcp->state == LISTEN)) { -+ *(int *)optval = 1; -+ } else { -+ *(int *)optval = 0; -+ } -+ break; -+#endif /* LWIP_TCP */ -+ -+ /* The option flags */ -+ case SO_BROADCAST: -+ case SO_KEEPALIVE: -+#if SO_REUSE -+ case SO_REUSEADDR: -+#endif /* SO_REUSE */ -+ if (sock->conn == NULL) { -+ done_socket(sock); -+ return EINVAL; -+ } -+ if ((optname == SO_BROADCAST) && -+ (NETCONNTYPE_GROUP(sock->conn->type) != NETCONN_UDP)) { -+ done_socket(sock); -+ return ENOPROTOOPT; -+ } -+ -+ optname = lwip_sockopt_to_ipopt(optname); -+ -+ LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, *optlen, int); -+ *(int *)optval = ip_get_option(sock->conn->pcb.ip, optname); -+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, optname=0x%x, ..) = %s\n", -+ s, optname, (*(int *)optval ? "on" : "off"))); -+ break; -+ -+ case SO_TYPE: -+ LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, *optlen, int); -+ switch (NETCONNTYPE_GROUP(netconn_type(sock->conn))) { -+#if PF_PACKET_SOCKET -+ case NETCONN_PACKET_RAW: -+#endif -+ case NETCONN_RAW: -+ *(int *)optval = SOCK_RAW; -+ break; -+ case NETCONN_TCP: -+ *(int *)optval = SOCK_STREAM; -+ break; -+ case NETCONN_UDP: -+ *(int *)optval = SOCK_DGRAM; -+ break; -+ default: /* unrecognized socket type */ -+ *(int *)optval = netconn_type(sock->conn); -+#if PF_PACKET_SOCKET -+ LWIP_DEBUGF(SOCKETS_DEBUG, -+ ("lwip_getsockopt(%d, %s, SO_TYPE): unrecognized socket type %d\n", -+ s, (NETCONN_PACKET_RAW != NETCONNTYPE_GROUP(sock->conn->type)) ? "SOL_SOCKET" : "SOL_PACKET", -+ *(int *)optval)); -+#else -+ LWIP_DEBUGF(SOCKETS_DEBUG, -+ ("lwip_getsockopt(%d, SOL_SOCKET, SO_TYPE): unrecognized socket type %d\n", -+ s, *(int *)optval)); -+#endif -+ } /* switch (netconn_type(sock->conn)) */ -+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, SO_TYPE) = %d\n", -+ s, *(int *)optval)); -+ break; -+ -+ case SO_ERROR: -+ LWIP_SOCKOPT_CHECK_OPTLEN(sock, *optlen, int); -+ *(int *)optval = err_to_errno(netconn_err(sock->conn)); -+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, SO_ERROR) = %d\n", -+ s, *(int *)optval)); -+ break; -+ -+#if LWIP_SO_SNDTIMEO -+ case SO_SNDTIMEO: -+ LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, *optlen, LWIP_SO_SNDRCVTIMEO_OPTTYPE); -+ LWIP_SO_SNDRCVTIMEO_SET(optval, netconn_get_sendtimeout(sock->conn)); -+ break; -+#endif /* LWIP_SO_SNDTIMEO */ -+#if LWIP_SO_RCVTIMEO -+ case SO_RCVTIMEO: -+ LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, *optlen, LWIP_SO_SNDRCVTIMEO_OPTTYPE); -+ LWIP_SO_SNDRCVTIMEO_SET(optval, netconn_get_recvtimeout(sock->conn)); -+ break; -+#endif /* LWIP_SO_RCVTIMEO */ -+#if LWIP_SO_RCVBUF -+ case SO_RCVBUF: -+ LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, *optlen, int); -+ *(int *)optval = netconn_get_recvbufsize(sock->conn); -+ break; -+#endif /* LWIP_SO_RCVBUF */ -+#if LWIP_SO_LINGER -+ case SO_LINGER: { -+ s16_t conn_linger; -+ struct linger *linger = (struct linger *)optval; -+ LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, *optlen, struct linger); -+ conn_linger = sock->conn->linger; -+ if (conn_linger >= 0) { -+ linger->l_onoff = 1; -+ linger->l_linger = (int)conn_linger; -+ } else { -+ linger->l_onoff = 0; -+ linger->l_linger = 0; -+ } -+ } -+ break; -+#endif /* LWIP_SO_LINGER */ -+#if LWIP_UDP -+ case SO_NO_CHECK: -+ LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, *optlen, int, NETCONN_UDP); -+#if LWIP_UDPLITE -+ if (udp_is_flag_set(sock->conn->pcb.udp, UDP_FLAGS_UDPLITE)) { -+ /* this flag is only available for UDP, not for UDP lite */ -+ done_socket(sock); -+ return EAFNOSUPPORT; -+ } -+#endif /* LWIP_UDPLITE */ -+ *(int *)optval = udp_is_flag_set(sock->conn->pcb.udp, UDP_FLAGS_NOCHKSUM) ? 1 : 0; -+ break; -+#endif /* LWIP_UDP*/ -+ default: -+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, UNIMPL: optname=0x%x, ..)\n", -+ s, optname)); -+ err = ENOPROTOOPT; -+ break; -+ } /* switch (optname) */ -+ break; -+ -+ /* Level: IPPROTO_IP */ -+ case IPPROTO_IP: -+ switch (optname) { -+ case IP_TTL: -+ LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, *optlen, int); -+ *(int *)optval = sock->conn->pcb.ip->ttl; -+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_TTL) = %d\n", -+ s, *(int *)optval)); -+ break; -+ case IP_TOS: -+ LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, *optlen, int); -+ *(int *)optval = sock->conn->pcb.ip->tos; -+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_TOS) = %d\n", -+ s, *(int *)optval)); -+ break; -+#if LWIP_IPV4 && LWIP_MULTICAST_TX_OPTIONS && LWIP_UDP -+ case IP_MULTICAST_TTL: -+ LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, *optlen, u8_t); -+ if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_UDP) { -+ done_socket(sock); -+ return ENOPROTOOPT; -+ } -+ *(u8_t *)optval = udp_get_multicast_ttl(sock->conn->pcb.udp); -+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_MULTICAST_TTL) = %d\n", -+ s, *(int *)optval)); -+ break; -+ case IP_MULTICAST_IF: -+ LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, *optlen, struct in_addr); -+ if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_UDP) { -+ done_socket(sock); -+ return ENOPROTOOPT; -+ } -+ inet_addr_from_ip4addr((struct in_addr *)optval, udp_get_multicast_netif_addr(sock->conn->pcb.udp)); -+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_MULTICAST_IF) = 0x%"X32_F"\n", -+ s, *(u32_t *)optval)); -+ break; -+ case IP_MULTICAST_LOOP: -+ LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, *optlen, u8_t); -+ if ((sock->conn->pcb.udp->flags & UDP_FLAGS_MULTICAST_LOOP) != 0) { -+ *(u8_t *)optval = 1; -+ } else { -+ *(u8_t *)optval = 0; -+ } -+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_MULTICAST_LOOP) = %d\n", -+ s, *(int *)optval)); -+ break; -+#endif /* LWIP_IPV4 && LWIP_MULTICAST_TX_OPTIONS && LWIP_UDP */ -+ default: -+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, UNIMPL: optname=0x%x, ..)\n", -+ s, optname)); -+ err = ENOPROTOOPT; -+ break; -+ } /* switch (optname) */ -+ break; -+ -+#if LWIP_TCP -+ /* Level: IPPROTO_TCP */ -+ case IPPROTO_TCP: -+ /* Special case: all IPPROTO_TCP option take an int */ -+ LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, *optlen, int, NETCONN_TCP); -+ if (sock->conn->pcb.tcp->state == LISTEN) { -+ done_socket(sock); -+ return EINVAL; -+ } -+ switch (optname) { -+ case TCP_NODELAY: -+ *(int *)optval = tcp_nagle_disabled(sock->conn->pcb.tcp); -+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_TCP, TCP_NODELAY) = %s\n", -+ s, (*(int *)optval) ? "on" : "off") ); -+ break; -+ case TCP_KEEPALIVE: -+ *(int *)optval = (int)sock->conn->pcb.tcp->keep_idle; -+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_TCP, TCP_KEEPALIVE) = %d\n", -+ s, *(int *)optval)); -+ break; -+ -+#if LWIP_TCP_KEEPALIVE -+ case TCP_KEEPIDLE: -+ *(int *)optval = (int)(sock->conn->pcb.tcp->keep_idle / 1000); -+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_TCP, TCP_KEEPIDLE) = %d\n", -+ s, *(int *)optval)); -+ break; -+ case TCP_KEEPINTVL: -+ *(int *)optval = (int)(sock->conn->pcb.tcp->keep_intvl / 1000); -+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_TCP, TCP_KEEPINTVL) = %d\n", -+ s, *(int *)optval)); -+ break; -+ case TCP_KEEPCNT: -+ *(int *)optval = (int)sock->conn->pcb.tcp->keep_cnt; -+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_TCP, TCP_KEEPCNT) = %d\n", -+ s, *(int *)optval)); -+ break; -+#endif /* LWIP_TCP_KEEPALIVE */ -+ default: -+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_TCP, UNIMPL: optname=0x%x, ..)\n", -+ s, optname)); -+ err = ENOPROTOOPT; -+ break; -+ } /* switch (optname) */ -+ break; -+#endif /* LWIP_TCP */ -+ -+#if LWIP_IPV6 -+ /* Level: IPPROTO_IPV6 */ -+ case IPPROTO_IPV6: -+ switch (optname) { -+ case IPV6_V6ONLY: -+ LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, *optlen, int); -+ *(int *)optval = (netconn_get_ipv6only(sock->conn) ? 1 : 0); -+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IPV6, IPV6_V6ONLY) = %d\n", -+ s, *(int *)optval)); -+ break; -+ default: -+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IPV6, UNIMPL: optname=0x%x, ..)\n", -+ s, optname)); -+ err = ENOPROTOOPT; -+ break; -+ } /* switch (optname) */ -+ break; -+#endif /* LWIP_IPV6 */ -+ -+#if LWIP_UDP && LWIP_UDPLITE -+ /* Level: IPPROTO_UDPLITE */ -+ case IPPROTO_UDPLITE: -+ /* Special case: all IPPROTO_UDPLITE option take an int */ -+ LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, *optlen, int); -+ /* If this is no UDP lite socket, ignore any options. */ -+ if (!NETCONNTYPE_ISUDPLITE(netconn_type(sock->conn))) { -+ done_socket(sock); -+ return ENOPROTOOPT; -+ } -+ switch (optname) { -+ case UDPLITE_SEND_CSCOV: -+ *(int *)optval = sock->conn->pcb.udp->chksum_len_tx; -+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_UDPLITE, UDPLITE_SEND_CSCOV) = %d\n", -+ s, (*(int *)optval)) ); -+ break; -+ case UDPLITE_RECV_CSCOV: -+ *(int *)optval = sock->conn->pcb.udp->chksum_len_rx; -+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_UDPLITE, UDPLITE_RECV_CSCOV) = %d\n", -+ s, (*(int *)optval)) ); -+ break; -+ default: -+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_UDPLITE, UNIMPL: optname=0x%x, ..)\n", -+ s, optname)); -+ err = ENOPROTOOPT; -+ break; -+ } /* switch (optname) */ -+ break; -+#endif /* LWIP_UDP */ -+ /* Level: IPPROTO_RAW */ -+ case IPPROTO_RAW: -+ switch (optname) { -+#if LWIP_IPV6 && LWIP_RAW -+ case IPV6_CHECKSUM: -+ LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, *optlen, int, NETCONN_RAW); -+ if (sock->conn->pcb.raw->chksum_reqd == 0) { -+ *(int *)optval = -1; -+ } else { -+ *(int *)optval = sock->conn->pcb.raw->chksum_offset; -+ } -+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_RAW, IPV6_CHECKSUM) = %d\n", -+ s, (*(int *)optval)) ); -+ break; -+#endif /* LWIP_IPV6 && LWIP_RAW */ -+ default: -+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_RAW, UNIMPL: optname=0x%x, ..)\n", -+ s, optname)); -+ err = ENOPROTOOPT; -+ break; -+ } /* switch (optname) */ -+ break; -+ default: -+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, level=0x%x, UNIMPL: optname=0x%x, ..)\n", -+ s, level, optname)); -+ err = ENOPROTOOPT; -+ break; -+ } /* switch (level) */ -+ -+ done_socket(sock); -+ return err; -+} -+ -+int -+lwip_setsockopt(int s, int level, int optname, const void *optval, socklen_t optlen) -+{ -+ int err = 0; -+ struct lwip_sock *sock = get_socket(s); -+#if !LWIP_TCPIP_CORE_LOCKING -+ err_t cberr; -+ LWIP_SETGETSOCKOPT_DATA_VAR_DECLARE(data); -+#endif /* !LWIP_TCPIP_CORE_LOCKING */ -+ -+ if (!sock) { -+ return -1; -+ } -+ -+ if (NULL == optval) { -+ sock_set_errno(sock, EFAULT); -+ done_socket(sock); -+ return -1; -+ } -+ -+#if LWIP_TCPIP_CORE_LOCKING -+ /* core-locking can just call the -impl function */ -+ LOCK_TCPIP_CORE(); -+ err = lwip_setsockopt_impl(s, level, optname, optval, optlen); -+ UNLOCK_TCPIP_CORE(); -+ -+#else /* LWIP_TCPIP_CORE_LOCKING */ -+ -+#if LWIP_MPU_COMPATIBLE -+ /* MPU_COMPATIBLE copies the optval data, so check for max size here */ -+ if (optlen > LWIP_SETGETSOCKOPT_MAXOPTLEN) { -+ sock_set_errno(sock, ENOBUFS); -+ done_socket(sock); -+ return -1; -+ } -+#endif /* LWIP_MPU_COMPATIBLE */ -+ -+ LWIP_SETGETSOCKOPT_DATA_VAR_ALLOC(data, sock); -+ LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).s = s; -+ LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).level = level; -+ LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optname = optname; -+ LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optlen = optlen; -+#if LWIP_MPU_COMPATIBLE -+ MEMCPY(LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optval, optval, optlen); -+#else /* LWIP_MPU_COMPATIBLE */ -+ LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optval.pc = (const void *)optval; -+#endif /* LWIP_MPU_COMPATIBLE */ -+ LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).err = 0; -+#if LWIP_NETCONN_SEM_PER_THREAD -+ LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).completed_sem = LWIP_NETCONN_THREAD_SEM_GET(); -+#else -+ LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).completed_sem = &sock->conn->op_completed; -+#endif -+ cberr = tcpip_callback(lwip_setsockopt_callback, &LWIP_SETGETSOCKOPT_DATA_VAR_REF(data)); -+ if (cberr != ERR_OK) { -+ LWIP_SETGETSOCKOPT_DATA_VAR_FREE(data); -+ sock_set_errno(sock, err_to_errno(cberr)); -+ done_socket(sock); -+ return -1; -+ } -+ sys_arch_sem_wait((sys_sem_t *)(LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).completed_sem), 0); -+ -+ /* maybe lwip_getsockopt_internal has changed err */ -+ err = LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).err; -+ LWIP_SETGETSOCKOPT_DATA_VAR_FREE(data); -+#endif /* LWIP_TCPIP_CORE_LOCKING */ -+ -+ sock_set_errno(sock, err); -+ done_socket(sock); -+ return err ? -1 : 0; -+} -+ -+#if !LWIP_TCPIP_CORE_LOCKING -+/** lwip_setsockopt_callback: only used without CORE_LOCKING -+ * to get into the tcpip_thread -+ */ -+static void -+lwip_setsockopt_callback(void *arg) -+{ -+ struct lwip_setgetsockopt_data *data; -+ LWIP_ASSERT("arg != NULL", arg != NULL); -+ data = (struct lwip_setgetsockopt_data *)arg; -+ -+ data->err = lwip_setsockopt_impl(data->s, data->level, data->optname, -+#if LWIP_MPU_COMPATIBLE -+ data->optval, -+#else /* LWIP_MPU_COMPATIBLE */ -+ data->optval.pc, -+#endif /* LWIP_MPU_COMPATIBLE */ -+ data->optlen); -+ -+ sys_sem_signal((sys_sem_t *)(data->completed_sem)); -+} -+#endif /* LWIP_TCPIP_CORE_LOCKING */ -+ -+/** lwip_setsockopt_impl: the actual implementation of setsockopt: -+ * same argument as lwip_setsockopt, either called directly or through callback -+ */ -+static int -+lwip_setsockopt_impl(int s, int level, int optname, const void *optval, socklen_t optlen) -+{ -+ int err = 0; -+ struct lwip_sock *sock = tryget_socket(s); -+ if (!sock) { -+ return EBADF; -+ } -+ -+#ifdef LWIP_HOOK_SOCKETS_SETSOCKOPT -+ if (LWIP_HOOK_SOCKETS_SETSOCKOPT(s, sock, level, optname, optval, optlen, &err)) { -+ return err; -+ } -+#endif -+ -+ switch (level) { -+ -+ /* Level: SOL_SOCKET */ -+ case SOL_SOCKET: -+ switch (optname) { -+ -+ /* SO_ACCEPTCONN is get-only */ -+ -+ /* The option flags */ -+ case SO_BROADCAST: -+ case SO_KEEPALIVE: -+#if SO_REUSE -+ case SO_REUSEADDR: -+#endif /* SO_REUSE */ -+ if ((optname == SO_BROADCAST) && -+ (NETCONNTYPE_GROUP(sock->conn->type) != NETCONN_UDP)) { -+ done_socket(sock); -+ return ENOPROTOOPT; -+ } -+ -+ optname = lwip_sockopt_to_ipopt(optname); -+ -+ LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, optlen, int); -+ if (*(const int *)optval) { -+ ip_set_option(sock->conn->pcb.ip, optname); -+ } else { -+ ip_reset_option(sock->conn->pcb.ip, optname); -+ } -+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, SOL_SOCKET, optname=0x%x, ..) -> %s\n", -+ s, optname, (*(const int *)optval ? "on" : "off"))); -+ break; -+ -+ /* SO_TYPE is get-only */ -+ /* SO_ERROR is get-only */ -+ -+#if LWIP_SO_SNDTIMEO -+ case SO_SNDTIMEO: { -+ long ms_long; -+ LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, optlen, LWIP_SO_SNDRCVTIMEO_OPTTYPE); -+ ms_long = LWIP_SO_SNDRCVTIMEO_GET_MS(optval); -+ if (ms_long < 0) { -+ done_socket(sock); -+ return EINVAL; -+ } -+ netconn_set_sendtimeout(sock->conn, ms_long); -+ break; -+ } -+#endif /* LWIP_SO_SNDTIMEO */ -+#if LWIP_SO_RCVTIMEO -+ case SO_RCVTIMEO: { -+ long ms_long; -+ LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, optlen, LWIP_SO_SNDRCVTIMEO_OPTTYPE); -+ ms_long = LWIP_SO_SNDRCVTIMEO_GET_MS(optval); -+ if (ms_long < 0) { -+ done_socket(sock); -+ return EINVAL; -+ } -+ netconn_set_recvtimeout(sock->conn, (u32_t)ms_long); -+ break; -+ } -+#endif /* LWIP_SO_RCVTIMEO */ -+#if LWIP_SO_RCVBUF -+ case SO_RCVBUF: -+ LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, optlen, int); -+ netconn_set_recvbufsize(sock->conn, *(const int *)optval); -+ break; -+#endif /* LWIP_SO_RCVBUF */ -+#if LWIP_SO_LINGER -+ case SO_LINGER: { -+ const struct linger *linger = (const struct linger *)optval; -+ LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, optlen, struct linger); -+ if (linger->l_onoff) { -+ int lingersec = linger->l_linger; -+ if (lingersec < 0) { -+ done_socket(sock); -+ return EINVAL; -+ } -+ if (lingersec > 0xFFFF) { -+ lingersec = 0xFFFF; -+ } -+ sock->conn->linger = (s16_t)lingersec; -+ } else { -+ sock->conn->linger = -1; -+ } -+ } -+ break; -+#endif /* LWIP_SO_LINGER */ -+#if LWIP_UDP -+ case SO_NO_CHECK: -+ LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, int, NETCONN_UDP); -+#if LWIP_UDPLITE -+ if (udp_is_flag_set(sock->conn->pcb.udp, UDP_FLAGS_UDPLITE)) { -+ /* this flag is only available for UDP, not for UDP lite */ -+ done_socket(sock); -+ return EAFNOSUPPORT; -+ } -+#endif /* LWIP_UDPLITE */ -+ if (*(const int *)optval) { -+ udp_set_flags(sock->conn->pcb.udp, UDP_FLAGS_NOCHKSUM); -+ } else { -+ udp_clear_flags(sock->conn->pcb.udp, UDP_FLAGS_NOCHKSUM); -+ } -+ break; -+#endif /* LWIP_UDP */ -+ case SO_BINDTODEVICE: { -+ const struct ifreq *iface; -+ struct netif *n = NULL; -+ -+ LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, optlen, struct ifreq); -+ -+ iface = (const struct ifreq *)optval; -+ if (iface->ifr_name[0] != 0) { -+ n = netif_find(iface->ifr_name); -+ if (n == NULL) { -+ done_socket(sock); -+ return ENODEV; -+ } -+ } -+ -+ switch (NETCONNTYPE_GROUP(netconn_type(sock->conn))) { -+#if LWIP_TCP -+ case NETCONN_TCP: -+ tcp_bind_netif(sock->conn->pcb.tcp, n); -+ break; -+#endif -+#if LWIP_UDP -+ case NETCONN_UDP: -+ udp_bind_netif(sock->conn->pcb.udp, n); -+ break; -+#endif -+#if LWIP_RAW -+ case NETCONN_RAW: -+ raw_bind_netif(sock->conn->pcb.raw, n); -+ break; -+#endif -+ default: -+ LWIP_ASSERT("Unhandled netconn type in SO_BINDTODEVICE", 0); -+ break; -+ } -+ } -+ break; -+ default: -+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, SOL_SOCKET, UNIMPL: optname=0x%x, ..)\n", -+ s, optname)); -+ err = ENOPROTOOPT; -+ break; -+ } /* switch (optname) */ -+ break; -+ -+ /* Level: IPPROTO_IP */ -+ case IPPROTO_IP: -+ switch (optname) { -+ case IP_TTL: -+ LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, optlen, int); -+ sock->conn->pcb.ip->ttl = (u8_t)(*(const int *)optval); -+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IP, IP_TTL, ..) -> %d\n", -+ s, sock->conn->pcb.ip->ttl)); -+ break; -+ case IP_TOS: -+ LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, optlen, int); -+ sock->conn->pcb.ip->tos = (u8_t)(*(const int *)optval); -+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IP, IP_TOS, ..)-> %d\n", -+ s, sock->conn->pcb.ip->tos)); -+ break; -+#if LWIP_NETBUF_RECVINFO -+ case IP_PKTINFO: -+ LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, int, NETCONN_UDP); -+ if (*(const int *)optval) { -+ sock->conn->flags |= NETCONN_FLAG_PKTINFO; -+ } else { -+ sock->conn->flags &= ~NETCONN_FLAG_PKTINFO; -+ } -+ break; -+#endif /* LWIP_NETBUF_RECVINFO */ -+#if LWIP_IPV4 && LWIP_MULTICAST_TX_OPTIONS && LWIP_UDP -+ case IP_MULTICAST_TTL: -+ LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, u8_t, NETCONN_UDP); -+ udp_set_multicast_ttl(sock->conn->pcb.udp, (u8_t)(*(const u8_t *)optval)); -+ break; -+ case IP_MULTICAST_IF: { -+ ip4_addr_t if_addr; -+ LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, struct in_addr, NETCONN_UDP); -+ inet_addr_to_ip4addr(&if_addr, (const struct in_addr *)optval); -+ udp_set_multicast_netif_addr(sock->conn->pcb.udp, &if_addr); -+ } -+ break; -+ case IP_MULTICAST_LOOP: -+ LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, u8_t, NETCONN_UDP); -+ if (*(const u8_t *)optval) { -+ udp_set_flags(sock->conn->pcb.udp, UDP_FLAGS_MULTICAST_LOOP); -+ } else { -+ udp_clear_flags(sock->conn->pcb.udp, UDP_FLAGS_MULTICAST_LOOP); -+ } -+ break; -+#endif /* LWIP_IPV4 && LWIP_MULTICAST_TX_OPTIONS && LWIP_UDP */ -+#if LWIP_IGMP -+ case IP_ADD_MEMBERSHIP: -+ case IP_DROP_MEMBERSHIP: { -+ /* If this is a TCP or a RAW socket, ignore these options. */ -+ err_t igmp_err; -+ const struct ip_mreq *imr = (const struct ip_mreq *)optval; -+ ip4_addr_t if_addr; -+ ip4_addr_t multi_addr; -+ LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, struct ip_mreq, NETCONN_UDP); -+ inet_addr_to_ip4addr(&if_addr, &imr->imr_interface); -+ inet_addr_to_ip4addr(&multi_addr, &imr->imr_multiaddr); -+ if (optname == IP_ADD_MEMBERSHIP) { -+ if (!lwip_socket_register_membership(s, &if_addr, &multi_addr)) { -+ /* cannot track membership (out of memory) */ -+ err = ENOMEM; -+ igmp_err = ERR_OK; -+ } else { -+ igmp_err = igmp_joingroup(&if_addr, &multi_addr); -+ } -+ } else { -+ igmp_err = igmp_leavegroup(&if_addr, &multi_addr); -+ lwip_socket_unregister_membership(s, &if_addr, &multi_addr); -+ } -+ if (igmp_err != ERR_OK) { -+ err = EADDRNOTAVAIL; -+ } -+ } -+ break; -+#endif /* LWIP_IGMP */ -+ default: -+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IP, UNIMPL: optname=0x%x, ..)\n", -+ s, optname)); -+ err = ENOPROTOOPT; -+ break; -+ } /* switch (optname) */ -+ break; -+ -+#if LWIP_TCP -+ /* Level: IPPROTO_TCP */ -+ case IPPROTO_TCP: -+ /* Special case: all IPPROTO_TCP option take an int */ -+ LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, int, NETCONN_TCP); -+ if (sock->conn->pcb.tcp->state == LISTEN) { -+ done_socket(sock); -+ return EINVAL; -+ } -+ switch (optname) { -+ case TCP_NODELAY: -+ if (*(const int *)optval) { -+ tcp_nagle_disable(sock->conn->pcb.tcp); -+ } else { -+ tcp_nagle_enable(sock->conn->pcb.tcp); -+ } -+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_NODELAY) -> %s\n", -+ s, (*(const int *)optval) ? "on" : "off") ); -+ break; -+ case TCP_KEEPALIVE: -+ sock->conn->pcb.tcp->keep_idle = (u32_t)(*(const int *)optval); -+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPALIVE) -> %"U32_F"\n", -+ s, sock->conn->pcb.tcp->keep_idle)); -+ break; -+ -+#if LWIP_TCP_KEEPALIVE -+ case TCP_KEEPIDLE: -+ sock->conn->pcb.tcp->keep_idle = 1000 * (u32_t)(*(const int *)optval); -+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPIDLE) -> %"U32_F"\n", -+ s, sock->conn->pcb.tcp->keep_idle)); -+ break; -+ case TCP_KEEPINTVL: -+ sock->conn->pcb.tcp->keep_intvl = 1000 * (u32_t)(*(const int *)optval); -+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPINTVL) -> %"U32_F"\n", -+ s, sock->conn->pcb.tcp->keep_intvl)); -+ break; -+ case TCP_KEEPCNT: -+ sock->conn->pcb.tcp->keep_cnt = (u32_t)(*(const int *)optval); -+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPCNT) -> %"U32_F"\n", -+ s, sock->conn->pcb.tcp->keep_cnt)); -+ break; -+#endif /* LWIP_TCP_KEEPALIVE */ -+ default: -+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, UNIMPL: optname=0x%x, ..)\n", -+ s, optname)); -+ err = ENOPROTOOPT; -+ break; -+ } /* switch (optname) */ -+ break; -+#endif /* LWIP_TCP*/ -+ -+#if LWIP_IPV6 -+ /* Level: IPPROTO_IPV6 */ -+ case IPPROTO_IPV6: -+ switch (optname) { -+ case IPV6_V6ONLY: -+ LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, optlen, int); -+ if (*(const int *)optval) { -+ netconn_set_ipv6only(sock->conn, 1); -+ } else { -+ netconn_set_ipv6only(sock->conn, 0); -+ } -+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IPV6, IPV6_V6ONLY, ..) -> %d\n", -+ s, (netconn_get_ipv6only(sock->conn) ? 1 : 0))); -+ break; -+#if LWIP_IPV6_MLD -+ case IPV6_JOIN_GROUP: -+ case IPV6_LEAVE_GROUP: { -+ /* If this is a TCP or a RAW socket, ignore these options. */ -+ err_t mld6_err; -+ struct netif *netif; -+ ip6_addr_t multi_addr; -+ const struct ipv6_mreq *imr = (const struct ipv6_mreq *)optval; -+ LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, struct ipv6_mreq, NETCONN_UDP); -+ inet6_addr_to_ip6addr(&multi_addr, &imr->ipv6mr_multiaddr); -+ LWIP_ASSERT("Invalid netif index", imr->ipv6mr_interface <= 0xFFu); -+ netif = netif_get_by_index((u8_t)imr->ipv6mr_interface); -+ if (netif == NULL) { -+ err = EADDRNOTAVAIL; -+ break; -+ } -+ -+ if (optname == IPV6_JOIN_GROUP) { -+ if (!lwip_socket_register_mld6_membership(s, imr->ipv6mr_interface, &multi_addr)) { -+ /* cannot track membership (out of memory) */ -+ err = ENOMEM; -+ mld6_err = ERR_OK; -+ } else { -+ mld6_err = mld6_joingroup_netif(netif, &multi_addr); -+ } -+ } else { -+ mld6_err = mld6_leavegroup_netif(netif, &multi_addr); -+ lwip_socket_unregister_mld6_membership(s, imr->ipv6mr_interface, &multi_addr); -+ } -+ if (mld6_err != ERR_OK) { -+ err = EADDRNOTAVAIL; -+ } -+ } -+ break; -+#endif /* LWIP_IPV6_MLD */ -+ default: -+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IPV6, UNIMPL: optname=0x%x, ..)\n", -+ s, optname)); -+ err = ENOPROTOOPT; -+ break; -+ } /* switch (optname) */ -+ break; -+#endif /* LWIP_IPV6 */ -+ -+#if LWIP_UDP && LWIP_UDPLITE -+ /* Level: IPPROTO_UDPLITE */ -+ case IPPROTO_UDPLITE: -+ /* Special case: all IPPROTO_UDPLITE option take an int */ -+ LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, optlen, int); -+ /* If this is no UDP lite socket, ignore any options. */ -+ if (!NETCONNTYPE_ISUDPLITE(netconn_type(sock->conn))) { -+ done_socket(sock); -+ return ENOPROTOOPT; -+ } -+ switch (optname) { -+ case UDPLITE_SEND_CSCOV: -+ if ((*(const int *)optval != 0) && ((*(const int *)optval < 8) || (*(const int *)optval > 0xffff))) { -+ /* don't allow illegal values! */ -+ sock->conn->pcb.udp->chksum_len_tx = 8; -+ } else { -+ sock->conn->pcb.udp->chksum_len_tx = (u16_t) * (const int *)optval; -+ } -+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_UDPLITE, UDPLITE_SEND_CSCOV) -> %d\n", -+ s, (*(const int *)optval)) ); -+ break; -+ case UDPLITE_RECV_CSCOV: -+ if ((*(const int *)optval != 0) && ((*(const int *)optval < 8) || (*(const int *)optval > 0xffff))) { -+ /* don't allow illegal values! */ -+ sock->conn->pcb.udp->chksum_len_rx = 8; -+ } else { -+ sock->conn->pcb.udp->chksum_len_rx = (u16_t) * (const int *)optval; -+ } -+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_UDPLITE, UDPLITE_RECV_CSCOV) -> %d\n", -+ s, (*(const int *)optval)) ); -+ break; -+ default: -+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_UDPLITE, UNIMPL: optname=0x%x, ..)\n", -+ s, optname)); -+ err = ENOPROTOOPT; -+ break; -+ } /* switch (optname) */ -+ break; -+#endif /* LWIP_UDP */ -+ /* Level: IPPROTO_RAW */ -+ case IPPROTO_RAW: -+ switch (optname) { -+#if LWIP_IPV6 && LWIP_RAW -+ case IPV6_CHECKSUM: -+ /* It should not be possible to disable the checksum generation with ICMPv6 -+ * as per RFC 3542 chapter 3.1 */ -+ if (sock->conn->pcb.raw->protocol == IPPROTO_ICMPV6) { -+ done_socket(sock); -+ return EINVAL; -+ } -+ -+ LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, int, NETCONN_RAW); -+ if (*(const int *)optval < 0) { -+ sock->conn->pcb.raw->chksum_reqd = 0; -+ } else if (*(const int *)optval & 1) { -+ /* Per RFC3542, odd offsets are not allowed */ -+ done_socket(sock); -+ return EINVAL; -+ } else { -+ sock->conn->pcb.raw->chksum_reqd = 1; -+ sock->conn->pcb.raw->chksum_offset = (u16_t) * (const int *)optval; -+ } -+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_RAW, IPV6_CHECKSUM, ..) -> %d\n", -+ s, sock->conn->pcb.raw->chksum_reqd)); -+ break; -+#endif /* LWIP_IPV6 && LWIP_RAW */ -+ default: -+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_RAW, UNIMPL: optname=0x%x, ..)\n", -+ s, optname)); -+ err = ENOPROTOOPT; -+ break; -+ } /* switch (optname) */ -+ break; -+ default: -+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, level=0x%x, UNIMPL: optname=0x%x, ..)\n", -+ s, level, optname)); -+ err = ENOPROTOOPT; -+ break; -+ } /* switch (level) */ -+ -+ done_socket(sock); -+ return err; -+} -+ -+#if LWIP_IOCTL_IF -+static u8_t lwip_ioctl_internal_SIOCGIFCONF(struct ifreq *ifr) -+{ -+ struct ifconf *ifc = NULL; -+ struct netif *netif = NULL; -+ struct ifreq ifreq; -+ struct sockaddr_in *sock_in = NULL; -+ int pos; -+ int len; -+ int ret; -+ -+ /* Format the caller's buffer. */ -+ ifc = (struct ifconf*)ifr; -+ len = ifc->ifc_len; -+ -+ /* Loop over the interfaces, and write an info block for each. */ -+ pos = 0; -+ for (netif = netif_list; netif != NULL; netif = netif->next) { -+ if (ifc->ifc_buf == NULL) { -+ pos = (pos + (int)sizeof(struct ifreq)); -+ continue; -+ } -+ -+ if (len < (int)sizeof(ifreq)) { -+ break; -+ } -+ -+ if (memset_s(&ifreq, sizeof(struct ifreq), 0, sizeof(struct ifreq)) != EOK) { -+ return ENOBUFS; -+ } -+ if (netif->link_layer_type == LOOPBACK_IF) { -+ ret = snprintf_s(ifreq.ifr_name, NETIF_NAMESIZE, (NETIF_NAMESIZE - 1), "%s", netif->name); -+ if ((ret <= 0) || (ret >= IFNAMSIZ)) { -+ LWIP_DEBUGF(NETIF_DEBUG, ("lwip_ioctl: snprintf_s ifr_name failed.")); -+ return ENOBUFS; -+ } -+ } else { -+ ret = snprintf_s(ifreq.ifr_name, NETIF_NAMESIZE, NETIF_NAMESIZE - 1, "%s%"U8_F, netif->name, netif->num); -+ if ((ret <= 0) || (ret >= NETIF_NAMESIZE)) { -+ LWIP_DEBUGF(NETIF_DEBUG, ("lwip_ioctl: snprintf_s ifr_name failed.")); -+ return ENOBUFS; -+ } -+ } -+ -+ sock_in = (struct sockaddr_in *)&ifreq.ifr_addr; -+ sock_in->sin_family = AF_INET; -+ sock_in->sin_addr.s_addr = ip_2_ip4(&netif->ip_addr)->addr; -+ if (memcpy_s(ifc->ifc_buf + pos, sizeof(struct ifreq), &ifreq, sizeof(struct ifreq)) != EOK) { -+ return ENOBUFS; -+ } -+ pos += (int)sizeof(struct ifreq); -+ len -= (int)sizeof(struct ifreq); -+ } -+ -+ ifc->ifc_len = pos; -+ -+ return 0; -+} -+ -+static u8_t lwip_ioctl_internal_SIOCGIFADDR(struct ifreq *ifr) -+{ -+ struct netif *netif = NULL; -+ struct sockaddr_in *sock_in = NULL; -+ -+ /* get netif ipaddr */ -+ netif = netif_find(ifr->ifr_name); -+ if (netif == NULL) { -+ return ENODEV; -+ } else { -+ sock_in = (struct sockaddr_in *)&ifr->ifr_addr; -+ sock_in->sin_family = AF_INET; -+ sock_in->sin_addr.s_addr = ip_2_ip4(&netif->ip_addr)->addr; -+ return 0; -+ } -+} -+ -+static u8_t lwip_ioctl_internal_SIOCSIFFLAGS(const struct ifreq *ifr) -+{ -+ struct netif *netif = NULL; -+ -+ /* set netif hw addr */ -+ netif = netif_find(ifr->ifr_name); -+ if (netif == NULL) { -+ return ENODEV; -+ } -+#if LWIP_HAVE_LOOPIF -+ else if (netif->link_layer_type == LOOPBACK_IF) { -+ return EPERM; -+ } -+#endif /* LWIP_HAVE_LOOPIF */ -+ else { -+ if ((ifr->ifr_flags & IFF_UP) && !(netif->flags & NETIF_FLAG_UP)) { -+ (void)netif_set_up(netif); -+ } else if (!(ifr->ifr_flags & IFF_UP) && (netif->flags & NETIF_FLAG_UP)) { -+ (void)netif_set_down(netif); -+ } -+ if ((ifr->ifr_flags & IFF_RUNNING) && !(netif->flags & NETIF_FLAG_LINK_UP)) { -+ (void)netif_set_link_up(netif); -+ } else if (!(ifr->ifr_flags & IFF_RUNNING) && (netif->flags & NETIF_FLAG_LINK_UP)) { -+ (void)netif_set_link_down(netif); -+ } -+ -+ if (ifr->ifr_flags & IFF_BROADCAST) { -+ netif->flags |= NETIF_FLAG_BROADCAST; -+ } else { -+ netif->flags = netif->flags & (~NETIF_FLAG_BROADCAST); -+ } -+ if (ifr->ifr_flags & IFF_NOARP) { -+ netif->flags = (netif->flags & (~NETIF_FLAG_ETHARP)); -+ } else { -+ netif->flags |= NETIF_FLAG_ETHARP; -+ } -+ -+ if (ifr->ifr_flags & IFF_MULTICAST) { -+#if LWIP_IGMP -+ netif->flags |= NETIF_FLAG_IGMP; -+#endif /* LWIP_IGMP */ -+#if LWIP_IPV6 && LWIP_IPV6_MLD -+ netif->flags |= NETIF_FLAG_MLD6; -+#endif /* LWIP_IPV6_MLD */ -+ } -+ else { -+#if LWIP_IGMP -+ netif->flags = (netif->flags & ~NETIF_FLAG_IGMP); -+#endif /* LWIP_IGMP */ -+#if LWIP_IPV6 && LWIP_IPV6_MLD -+ netif->flags = (netif->flags & ~NETIF_FLAG_MLD6); -+#endif /* LWIP_IPV6_MLD */ -+ } -+ -+#if LWIP_DHCP -+ if (ifr->ifr_flags & IFF_DYNAMIC) { -+ (void)dhcp_start(netif); -+ } else { -+ dhcp_stop(netif); -+ dhcp_cleanup(netif); -+ } -+#endif -+ -+ return 0; -+ } -+} -+ -+static u8_t lwip_ioctl_internal_SIOCGIFFLAGS(struct ifreq *ifr) -+{ -+ struct netif *netif = NULL; -+ -+ /* set netif hw addr */ -+ netif = netif_find(ifr->ifr_name); -+ if (netif == NULL) { -+ return ENODEV; -+ } else { -+ if (netif->flags & NETIF_FLAG_UP) { -+ ifr->ifr_flags |= IFF_UP; -+ } else { -+ ifr->ifr_flags &= ~IFF_UP; -+ } -+ if (netif->flags & NETIF_FLAG_LINK_UP) { -+ ifr->ifr_flags |= IFF_RUNNING; -+ } else { -+ ifr->ifr_flags &= ~IFF_RUNNING; -+ } -+ if (netif->flags & NETIF_FLAG_BROADCAST) { -+ ifr->ifr_flags |= IFF_BROADCAST; -+ } else { -+ ifr->ifr_flags &= ~IFF_BROADCAST; -+ } -+ if (netif->flags & NETIF_FLAG_ETHARP) { -+ ifr->ifr_flags &= ~IFF_NOARP; -+ } else { -+ ifr->ifr_flags |= IFF_NOARP; -+ } -+ -+#if LWIP_IGMP || LWIP_IPV6_MLD -+ if ( -+#if LWIP_IGMP -+ (netif->flags & NETIF_FLAG_IGMP) -+#endif /* LWIP_IGMP */ -+#if LWIP_IGMP && LWIP_IPV6_MLD -+ || -+#endif /* LWIP_IGMP && LWIP_IPV6_MLD */ -+#if LWIP_IPV6_MLD -+ (netif->flags & NETIF_FLAG_MLD6) -+#endif /* LWIP_IPV6_MLD */ -+ ) { -+ ifr->ifr_flags = (short)((unsigned short)ifr->ifr_flags | IFF_MULTICAST); -+ } else { -+ ifr->ifr_flags = (short)((unsigned short)ifr->ifr_flags & (~IFF_MULTICAST)); -+ } -+#endif /* LWIP_IGMP || LWIP_IPV6_MLD */ -+ -+#if LWIP_DHCP -+ if (netif->flags & NETIF_FLAG_DHCP) { -+ ifr->ifr_flags = (short)((unsigned short)ifr->ifr_flags | IFF_DYNAMIC); -+ } else { -+ ifr->ifr_flags = (short)((unsigned short)ifr->ifr_flags & (~IFF_DYNAMIC)); -+ } -+#endif -+ -+#if LWIP_HAVE_LOOPIF -+ if (netif->link_layer_type == LOOPBACK_IF) { -+ ifr->ifr_flags |= IFF_LOOPBACK; -+ } -+#endif -+ -+ return 0; -+ } -+} -+ -+static u8_t lwip_ioctl_internal_SIOCGIFNAME(struct ifreq *ifr) -+{ -+ struct netif *netif = NULL; -+ int ret; -+ -+ for (netif = netif_list; netif != NULL; netif = netif->next) { -+ if (ifr->ifr_ifindex == netif->ifindex) { -+ break; -+ } -+ } -+ -+ if (netif == NULL) { -+ return ENODEV; -+ } -+ if (netif->link_layer_type == LOOPBACK_IF) { -+ ret = snprintf_s(ifr->ifr_name, NETIF_NAMESIZE, (NETIF_NAMESIZE - 1), "%s", netif->name); -+ if ((ret <= 0) || (ret >= NETIF_NAMESIZE)) { -+ return ENOBUFS; -+ } -+ } else { -+ ret = snprintf_s(ifr->ifr_name, NETIF_NAMESIZE, (NETIF_NAMESIZE - 1), "%s%"U8_F, netif->name, netif->num); -+ if ((ret <= 0) || (ret >= NETIF_NAMESIZE)) { -+ return ENOBUFS; -+ } -+ } -+ return 0; -+} -+ -+static u8_t lwip_ioctl_internal_SIOCGIFINDEX(struct ifreq *ifr) -+{ -+ struct netif *netif = NULL; -+ netif = netif_find(ifr->ifr_name); -+ if (netif == NULL) { -+ return ENODEV; -+ } -+ ifr->ifr_ifindex = netif->ifindex; -+ return 0; -+} -+#endif /* LWIP_IOCTL_IF */ -+ -+#if LWIP_SO_RCVBUF || LWIP_FIONREAD_LINUXMODE -+static u8_t lwip_ioctl_internal_FIONREAD(struct lwip_sock *sock, void *argp) -+{ -+#if LWIP_SO_RCVBUF -+ int recv_avail; -+#endif -+#if LWIP_FIONREAD_LINUXMODE -+ SYS_ARCH_DECL_PROTECT(lev); -+#endif -+ -+ if (!argp) { -+ return EINVAL; -+ } -+ -+ lwip_sock_lock(sock); -+#if LWIP_FIONREAD_LINUXMODE -+ if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_TCP) { -+ struct netbuf *nb; -+ if (sock->lastdata.netbuf) { -+ nb = sock->lastdata.netbuf; -+ *((int *)argp) = nb->p->tot_len; -+ } else { -+ struct netbuf *rxbuf; -+ err_t err; -+ -+ SYS_ARCH_PROTECT(lev); -+ if (sock->rcvevent <= 0) { -+ *((int*)argp) = 0; -+ SYS_ARCH_UNPROTECT(lev); -+ } else { -+ SYS_ARCH_UNPROTECT(lev); -+ err = netconn_recv_udp_raw_netbuf_flags(sock->conn, &rxbuf, NETCONN_DONTBLOCK); -+ if (err != ERR_OK) { -+ *((int *)argp) = 0; -+ } else { -+ sock->lastdata.netbuf = rxbuf; -+ *((int *)argp) = rxbuf->p->tot_len; -+ } -+ } -+ } -+ -+ lwip_sock_unlock(sock); -+ return 0; -+ } -+#endif /* LWIP_FIONREAD_LINUXMODE */ -+ -+#if LWIP_SO_RCVBUF -+ /* we come here if either LWIP_FIONREAD_LINUXMODE==0 or this is a TCP socket */ -+ SYS_ARCH_GET(sock->conn->recv_avail, recv_avail); -+ if (recv_avail < 0) { -+ recv_avail = 0; -+ } -+ -+ /* Check if there is data left from the last recv operation. /maq 041215 */ -+ if (sock->lastdata.netbuf) { -+ if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) { -+ recv_avail += sock->lastdata.pbuf->tot_len; -+ } else { -+ recv_avail += sock->lastdata.netbuf->p->tot_len; -+ } -+ } -+ *((int *)argp) = recv_avail; -+ -+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(FIONREAD, %p) = %"U16_F"\n", argp, *((u16_t *)argp))); -+ lwip_sock_unlock(sock); -+ return 0; -+#else /* LWIP_SO_RCVBUF */ -+ lwip_sock_unlock(sock); -+ return ENOSYS; -+#endif /* LWIP_SO_RCVBUF */ -+} -+#endif /* LWIP_SO_RCVBUF || LWIP_FIONREAD_LINUXMODE */ -+ -+static u8_t lwip_ioctl_internal_FIONBIO(struct lwip_sock *sock, const void *argp) -+{ -+ u8_t val = 0; -+ SYS_ARCH_DECL_PROTECT(lev); -+ if (argp == NULL) { -+ return EINVAL; -+ } -+ if (*(int *)argp) { -+ val = 1; -+ } -+ SYS_ARCH_PROTECT(lev); -+ netconn_set_nonblocking(sock->conn, val); -+ SYS_ARCH_UNPROTECT(lev); -+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(FIONBIO, %d)\n", val)); -+ return 0; -+} -+ -+static u8_t lwip_ioctl_impl(struct lwip_sock *sock, long cmd, void *argp) -+{ -+ u8_t err = 0; -+#if LWIP_NETIF_ETHTOOL -+ s32_t ret; -+#endif -+#if LWIP_IPV6_DUP_DETECT_ATTEMPTS || LWIP_IOCTL_IPV6DPCTD || LWIP_IOCTL_IF || LWIP_NETIF_ETHTOOL -+ struct ifreq *ifr = (struct ifreq *)argp; -+#endif -+#if LWIP_IOCTL_ROUTE -+ struct rtentry *rmten = (struct rtentry *)argp; -+#endif -+#if LWIP_IPV6_DUP_DETECT_ATTEMPTS || LWIP_IOCTL_IPV6DPCTD || LWIP_IOCTL_ROUTE || LWIP_IOCTL_IF -+ u8_t is_ipv6 = NETCONNTYPE_ISIPV6(sock->conn->type); -+#endif -+ -+ LWIP_ASSERT("no socket given", sock != NULL); -+ -+ switch (cmd) { -+#if LWIP_IOCTL_IF -+ case SIOCGIFCONF: -+ /* Do not allow if socket is AF_INET6 */ -+ if (is_ipv6) { -+ err = EINVAL; -+ } else { -+ err = lwip_ioctl_internal_SIOCGIFCONF(ifr); //add: SIOCGIFCONF -+ } -+ break; -+ case SIOCGIFADDR: -+ if (is_ipv6) { -+ err = EINVAL; -+ } else { -+ err = lwip_ioctl_internal_SIOCGIFADDR(ifr); //add: SIOCGIFADDR -+ } -+ break; -+ case SIOCSIFFLAGS: -+ err = lwip_ioctl_internal_SIOCSIFFLAGS(ifr); //add: SIOCSIFFLAGS -+ break; -+ case SIOCGIFFLAGS: -+ err = lwip_ioctl_internal_SIOCGIFFLAGS(ifr); //add: SIOCSIFFLAGS -+ break; -+ case SIOCGIFNAME: -+ err = lwip_ioctl_internal_SIOCGIFNAME(ifr); //add: SIOCGIFNAME -+ break; -+ /* Need to support the get index through ioctl -+ * As of now the options is restricted to PF_PACKET scenario , so removed the compiler flag Begin -+ */ -+ case SIOCGIFINDEX: -+ err = lwip_ioctl_internal_SIOCGIFINDEX(ifr); //add: SIOCGIFINDEX -+ break; -+#endif /* LWIP_IOCTL_IF */ -+ -+#if LWIP_SO_RCVBUF || LWIP_FIONREAD_LINUXMODE -+ case FIONREAD: -+ err = lwip_ioctl_internal_FIONREAD(sock, argp); -+ break; -+#endif /* LWIP_SO_RCVBUF || LWIP_FIONREAD_LINUXMODE */ -+ -+ case FIONBIO: -+ err = lwip_ioctl_internal_FIONBIO(sock, argp); -+ break; -+ /* -1 should return EINVAL */ -+ case -1: -+ err = EINVAL; -+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl_impl(INVALID: 0x%lx)\n", cmd)); -+ break; -+ default: -+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(UNIMPL: 0x%lx, %p)\n", cmd, argp)); -+ err = ENOSYS; /* not yet implemented */ -+ break; -+ } /* switch (cmd) */ -+ -+ return err; -+} -+ -+int -+lwip_ioctl(int s, long cmd, void *argp) -+{ -+ u8_t err; -+ struct lwip_sock *sock = get_socket(s); -+ if (!sock) { -+ /* get_socket has updated errno */ -+ return -1; -+ } -+ if (argp == NULL) { -+ sock_set_errno(sock, EFAULT); -+ done_socket(sock); -+ return -1; -+ } -+ -+ LOCK_TCPIP_CORE(); -+ err = lwip_ioctl_impl(sock, cmd, argp); -+ UNLOCK_TCPIP_CORE(); -+ if (err != ERR_OK) { -+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(%d, cmd: 0x%lx, %p)\n", s, cmd, argp)); -+ sock_set_errno(sock, err); -+ } -+ done_socket(sock); -+ return (err == 0) ? 0 : -1; -+} -+ -+/** A minimal implementation of fcntl. -+ * Currently only the commands F_GETFL and F_SETFL are implemented. -+ * The flag O_NONBLOCK and access modes are supported for F_GETFL, only -+ * the flag O_NONBLOCK is implemented for F_SETFL. -+ */ -+int -+lwip_fcntl(int s, int cmd, int val) -+{ -+ struct lwip_sock *sock = get_socket(s); -+ int ret = -1; -+ int op_mode = 0; -+ -+ if (!sock) { -+ return -1; -+ } -+ -+ switch (cmd) { -+ case F_GETFL: -+ ret = netconn_is_nonblocking(sock->conn) ? O_NONBLOCK : 0; -+ sock_set_errno(sock, 0); -+ -+ if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) { -+#if LWIP_TCPIP_CORE_LOCKING -+ LOCK_TCPIP_CORE(); -+#else -+ SYS_ARCH_DECL_PROTECT(lev); -+ /* the proper thing to do here would be to get into the tcpip_thread, -+ but locking should be OK as well since we only *read* some flags */ -+ SYS_ARCH_PROTECT(lev); -+#endif -+#if LWIP_TCP -+ if (sock->conn->pcb.tcp) { -+ if (!(sock->conn->pcb.tcp->flags & TF_RXCLOSED)) { -+ op_mode |= O_RDONLY; -+ } -+ if (!(sock->conn->pcb.tcp->flags & TF_FIN)) { -+ op_mode |= O_WRONLY; -+ } -+ } -+#endif -+#if LWIP_TCPIP_CORE_LOCKING -+ UNLOCK_TCPIP_CORE(); -+#else -+ SYS_ARCH_UNPROTECT(lev); -+#endif -+ } else { -+ op_mode |= O_RDWR; -+ } -+ -+ /* ensure O_RDWR for (O_RDONLY|O_WRONLY) != O_RDWR cases */ -+ ret |= (op_mode == (O_RDONLY | O_WRONLY)) ? O_RDWR : op_mode; -+ break; -+ case F_SETFL: -+ /* Bits corresponding to the file access mode and the file creation flags [..] that are set in arg shall be ignored */ -+ val &= ~(O_RDONLY | O_WRONLY | O_RDWR); -+ if ((val & ~O_NONBLOCK) == 0) { -+ /* only O_NONBLOCK, all other bits are zero */ -+ netconn_set_nonblocking(sock->conn, val & O_NONBLOCK); -+ ret = 0; -+ sock_set_errno(sock, 0); -+ } else { -+ sock_set_errno(sock, ENOSYS); /* not yet implemented */ -+ } -+ break; -+ default: -+ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_fcntl(%d, UNIMPL: %d, %d)\n", s, cmd, val)); -+ sock_set_errno(sock, ENOSYS); /* not yet implemented */ -+ break; -+ } -+ done_socket(sock); -+ return ret; -+} -+ -+#if LWIP_COMPAT_SOCKETS == 2 && LWIP_POSIX_SOCKETS_IO_NAMES -+int -+fcntl(int s, int cmd, ...) -+{ -+ va_list ap; -+ int val; -+ -+ va_start(ap, cmd); -+ val = va_arg(ap, int); -+ va_end(ap); -+ return lwip_fcntl(s, cmd, val); -+} -+#endif -+ -+const char * -+lwip_inet_ntop(int af, const void *src, char *dst, socklen_t size) -+{ -+ const char *ret = NULL; -+ int size_int = (int)size; -+ if (size_int < 0) { -+ set_errno(ENOSPC); -+ return NULL; -+ } -+ switch (af) { -+#if LWIP_IPV4 -+ case AF_INET: -+ ret = ip4addr_ntoa_r((const ip4_addr_t *)src, dst, size_int); -+ if (ret == NULL) { -+ set_errno(ENOSPC); -+ } -+ break; -+#endif -+#if LWIP_IPV6 -+ case AF_INET6: -+ ret = ip6addr_ntoa_r((const ip6_addr_t *)src, dst, size_int); -+ if (ret == NULL) { -+ set_errno(ENOSPC); -+ } -+ break; -+#endif -+ default: -+ set_errno(EAFNOSUPPORT); -+ break; -+ } -+ return ret; -+} -+ -+int -+lwip_inet_pton(int af, const char *src, void *dst) -+{ -+ int err; -+ switch (af) { -+#if LWIP_IPV4 -+ case AF_INET: -+ err = ip4addr_aton(src, (ip4_addr_t *)dst); -+ break; -+#endif -+#if LWIP_IPV6 -+ case AF_INET6: { -+ /* convert into temporary variable since ip6_addr_t might be larger -+ than in6_addr when scopes are enabled */ -+ ip6_addr_t addr; -+ err = ip6addr_aton(src, &addr); -+ if (err) { -+ memcpy(dst, &addr.addr, sizeof(addr.addr)); -+ } -+ break; -+ } -+#endif -+ default: -+ err = -1; -+ set_errno(EAFNOSUPPORT); -+ break; -+ } -+ return err; -+} -+ -+#if LWIP_IGMP -+/** Register a new IGMP membership. On socket close, the membership is dropped automatically. -+ * -+ * ATTENTION: this function is called from tcpip_thread (or under CORE_LOCK). -+ * -+ * @return 1 on success, 0 on failure -+ */ -+static int -+lwip_socket_register_membership(int s, const ip4_addr_t *if_addr, const ip4_addr_t *multi_addr) -+{ -+ struct lwip_sock *sock = get_socket(s); -+ int i; -+ -+ if (!sock) { -+ return 0; -+ } -+ -+ for (i = 0; i < LWIP_SOCKET_MAX_MEMBERSHIPS; i++) { -+ if (socket_ipv4_multicast_memberships[i].sock == NULL) { -+ socket_ipv4_multicast_memberships[i].sock = sock; -+ ip4_addr_copy(socket_ipv4_multicast_memberships[i].if_addr, *if_addr); -+ ip4_addr_copy(socket_ipv4_multicast_memberships[i].multi_addr, *multi_addr); -+ done_socket(sock); -+ return 1; -+ } -+ } -+ done_socket(sock); -+ return 0; -+} -+ -+/** Unregister a previously registered membership. This prevents dropping the membership -+ * on socket close. -+ * -+ * ATTENTION: this function is called from tcpip_thread (or under CORE_LOCK). -+ */ -+static void -+lwip_socket_unregister_membership(int s, const ip4_addr_t *if_addr, const ip4_addr_t *multi_addr) -+{ -+ struct lwip_sock *sock = get_socket(s); -+ int i; -+ -+ if (!sock) { -+ return; -+ } -+ -+ for (i = 0; i < LWIP_SOCKET_MAX_MEMBERSHIPS; i++) { -+ if ((socket_ipv4_multicast_memberships[i].sock == sock) && -+ ip4_addr_cmp(&socket_ipv4_multicast_memberships[i].if_addr, if_addr) && -+ ip4_addr_cmp(&socket_ipv4_multicast_memberships[i].multi_addr, multi_addr)) { -+ socket_ipv4_multicast_memberships[i].sock = NULL; -+ ip4_addr_set_zero(&socket_ipv4_multicast_memberships[i].if_addr); -+ ip4_addr_set_zero(&socket_ipv4_multicast_memberships[i].multi_addr); -+ break; -+ } -+ } -+ done_socket(sock); -+} -+ -+/** Drop all memberships of a socket that were not dropped explicitly via setsockopt. -+ * -+ * ATTENTION: this function is NOT called from tcpip_thread (or under CORE_LOCK). -+ */ -+static void -+lwip_socket_drop_registered_memberships(int s) -+{ -+ struct lwip_sock *sock = get_socket(s); -+ int i; -+ -+ if (!sock) { -+ return; -+ } -+ -+ for (i = 0; i < LWIP_SOCKET_MAX_MEMBERSHIPS; i++) { -+ if (socket_ipv4_multicast_memberships[i].sock == sock) { -+ ip_addr_t multi_addr, if_addr; -+ ip_addr_copy_from_ip4(multi_addr, socket_ipv4_multicast_memberships[i].multi_addr); -+ ip_addr_copy_from_ip4(if_addr, socket_ipv4_multicast_memberships[i].if_addr); -+ socket_ipv4_multicast_memberships[i].sock = NULL; -+ ip4_addr_set_zero(&socket_ipv4_multicast_memberships[i].if_addr); -+ ip4_addr_set_zero(&socket_ipv4_multicast_memberships[i].multi_addr); -+ -+ netconn_join_leave_group(sock->conn, &multi_addr, &if_addr, NETCONN_LEAVE); -+ } -+ } -+ done_socket(sock); -+} -+#endif /* LWIP_IGMP */ -+ -+#if LWIP_IPV6_MLD -+/** Register a new MLD6 membership. On socket close, the membership is dropped automatically. -+ * -+ * ATTENTION: this function is called from tcpip_thread (or under CORE_LOCK). -+ * -+ * @return 1 on success, 0 on failure -+ */ -+static int -+lwip_socket_register_mld6_membership(int s, unsigned int if_idx, const ip6_addr_t *multi_addr) -+{ -+ struct lwip_sock *sock = get_socket(s); -+ int i; -+ -+ if (!sock) { -+ return 0; -+ } -+ -+ for (i = 0; i < LWIP_SOCKET_MAX_MEMBERSHIPS; i++) { -+ if (socket_ipv6_multicast_memberships[i].sock == NULL) { -+ socket_ipv6_multicast_memberships[i].sock = sock; -+ socket_ipv6_multicast_memberships[i].if_idx = (u8_t)if_idx; -+ ip6_addr_copy(socket_ipv6_multicast_memberships[i].multi_addr, *multi_addr); -+ done_socket(sock); -+ return 1; -+ } -+ } -+ done_socket(sock); -+ return 0; -+} -+ -+/** Unregister a previously registered MLD6 membership. This prevents dropping the membership -+ * on socket close. -+ * -+ * ATTENTION: this function is called from tcpip_thread (or under CORE_LOCK). -+ */ -+static void -+lwip_socket_unregister_mld6_membership(int s, unsigned int if_idx, const ip6_addr_t *multi_addr) -+{ -+ struct lwip_sock *sock = get_socket(s); -+ int i; -+ -+ if (!sock) { -+ return; -+ } -+ -+ for (i = 0; i < LWIP_SOCKET_MAX_MEMBERSHIPS; i++) { -+ if ((socket_ipv6_multicast_memberships[i].sock == sock) && -+ (socket_ipv6_multicast_memberships[i].if_idx == if_idx) && -+ ip6_addr_cmp(&socket_ipv6_multicast_memberships[i].multi_addr, multi_addr)) { -+ socket_ipv6_multicast_memberships[i].sock = NULL; -+ socket_ipv6_multicast_memberships[i].if_idx = NETIF_NO_INDEX; -+ ip6_addr_set_zero(&socket_ipv6_multicast_memberships[i].multi_addr); -+ break; -+ } -+ } -+ done_socket(sock); -+} -+ -+/** Drop all MLD6 memberships of a socket that were not dropped explicitly via setsockopt. -+ * -+ * ATTENTION: this function is NOT called from tcpip_thread (or under CORE_LOCK). -+ */ -+static void -+lwip_socket_drop_registered_mld6_memberships(int s) -+{ -+ struct lwip_sock *sock = get_socket(s); -+ int i; -+ -+ if (!sock) { -+ return; -+ } -+ -+ for (i = 0; i < LWIP_SOCKET_MAX_MEMBERSHIPS; i++) { -+ if (socket_ipv6_multicast_memberships[i].sock == sock) { -+ ip_addr_t multi_addr; -+ u8_t if_idx; -+ -+ ip_addr_copy_from_ip6(multi_addr, socket_ipv6_multicast_memberships[i].multi_addr); -+ if_idx = socket_ipv6_multicast_memberships[i].if_idx; -+ -+ socket_ipv6_multicast_memberships[i].sock = NULL; -+ socket_ipv6_multicast_memberships[i].if_idx = NETIF_NO_INDEX; -+ ip6_addr_set_zero(&socket_ipv6_multicast_memberships[i].multi_addr); -+ -+ netconn_join_leave_group_netif(sock->conn, &multi_addr, if_idx, NETCONN_LEAVE); -+ } -+ } -+ done_socket(sock); -+} -+#endif /* LWIP_IPV6_MLD */ -+ -+#endif /* LWIP_SOCKET */ -diff -Nur a/lwip-2.1.2/src/apps/tftp/tftp_server.c b/lwip-2.1.2/src/apps/tftp/tftp_server.c ---- a/lwip-2.1.2/src/apps/tftp/tftp_server.c 2021-05-08 18:13:52.631621024 +0800 -+++ b/lwip-2.1.2/src/apps/tftp/tftp_server.c 2021-04-27 18:56:55.436353467 +0800 -@@ -201,7 +201,7 @@ - } - - static void --recv(void *arg, struct udp_pcb *upcb, struct pbuf *p, const ip_addr_t *addr, u16_t port) -+tftp_recv(void *arg, struct udp_pcb *upcb, struct pbuf *p, const ip_addr_t *addr, u16_t port) - { - u16_t *sbuf = (u16_t *) p->payload; - int opcode; -@@ -416,7 +416,7 @@ - tftp_state.last_data = NULL; - tftp_state.upcb = pcb; - -- udp_recv(pcb, recv, NULL); -+ udp_recv(pcb, tftp_recv, NULL); - - return ERR_OK; - } -diff -Nur a/lwip-2.1.2/src/core/ip.c b/lwip-2.1.2/src/core/ip.c ---- a/lwip-2.1.2/src/core/ip.c 2021-05-08 18:13:52.631621024 +0800 -+++ b/lwip-2.1.2/src/core/ip.c 2021-04-28 09:59:01.724615070 +0800 -@@ -122,14 +122,12 @@ - int - ipaddr_aton(const char *cp, ip_addr_t *addr) - { -- if (cp != NULL) { -+ if (cp != NULL && addr != NULL) { - const char *c; - for (c = cp; *c != 0; c++) { - if (*c == ':') { - /* contains a colon: IPv6 address */ -- if (addr) { -- IP_SET_TYPE_VAL(*addr, IPADDR_TYPE_V6); -- } -+ IP_SET_TYPE_VAL(*addr, IPADDR_TYPE_V6); - return ip6addr_aton(cp, ip_2_ip6(addr)); - } else if (*c == '.') { - /* contains a dot: IPv4 address */ -@@ -137,9 +135,7 @@ - } - } - /* call ip4addr_aton as fallback or if IPv4 was found */ -- if (addr) { -- IP_SET_TYPE_VAL(*addr, IPADDR_TYPE_V4); -- } -+ IP_SET_TYPE_VAL(*addr, IPADDR_TYPE_V4); - return ip4addr_aton(cp, ip_2_ip4(addr)); - } - return 0; -@@ -164,4 +160,63 @@ - - #endif /* LWIP_IPV4 && LWIP_IPV6 */ - -+struct netif* -+ip_route_pcb(const ip_addr_t *dest, const struct ip_pcb* pcb) -+{ -+ struct netif *netif = NULL; -+#if LWIP_SO_DONTROUTE -+ rt_scope_t scope = RT_SCOPE_UNIVERSAL; -+ -+ LWIP_ASSERT("Expecting ipaddr to be not NULL ", dest != NULL); -+ if (pcb != NULL) { -+ scope = ip_get_option(pcb, SOF_DONTROUTE) ? RT_SCOPE_LINK : RT_SCOPE_UNIVERSAL; -+ } -+#endif -+ -+ if ((pcb != NULL) && (pcb->netif_idx != NETIF_NO_INDEX)) { -+ return netif_find_by_ifindex(pcb->netif_idx); -+ } -+ -+ if ((pcb == NULL) || IP_IS_ANY_TYPE_VAL(pcb->local_ip)) { -+ /* Don't call ip_route() with IP_ANY_TYPE */ -+ netif = ip_route(IP46_ADDR_ANY(IP_GET_TYPE(dest)), dest); -+ } else { -+ netif = ip_route(&pcb->local_ip, dest); -+ } -+ -+ if (netif == NULL) { -+ return NULL; -+ } -+ -+#if LWIP_SO_DONTROUTE -+ if (netif->scope < scope) { -+ return NULL; -+ } -+#endif -+ return netif; -+} -+ -+#if LWIP_INET_ADDR_FUNC -+in_addr_t inet_addr(const char *cp) -+{ -+ LWIP_ERROR("inet_aton:cp is NULL", (cp != NULL), return (INADDR_NONE)); -+ return ipaddr_addr(cp); -+} -+#endif -+ -+#if LWIP_INET_ATON_FUNC -+int inet_aton(const char *cp, struct in_addr *inp) -+{ -+ LWIP_ERROR("inet_aton:cp is NULL", (cp != NULL), return 0); -+ return ip4addr_aton(cp, (ip4_addr_t *)inp); -+} -+#endif -+ -+#if LWIP_INET_NTOA_FUNC -+char* inet_ntoa(struct in_addr in) -+{ -+ return ip4addr_ntoa((const ip4_addr_t *)&in); -+} -+#endif -+ - #endif /* LWIP_IPV4 || LWIP_IPV6 */ -diff -Nur a/lwip-2.1.2/src/core/ipv6/icmp6.c b/lwip-2.1.2/src/core/ipv6/icmp6.c ---- a/lwip-2.1.2/src/core/ipv6/icmp6.c 2021-05-08 18:13:52.631621024 +0800 -+++ b/lwip-2.1.2/src/core/ipv6/icmp6.c 2021-04-27 18:56:55.440353467 +0800 -@@ -1,425 +1,425 @@ --/** -- * @file -- * -- * IPv6 version of ICMP, as per RFC 4443. -- */ -- --/* -- * Copyright (c) 2010 Inico Technologies Ltd. -- * 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: Ivan Delamer -- * -- * -- * Please coordinate changes and requests with Ivan Delamer -- * -- */ -- --#include "lwip/opt.h" -- --#if LWIP_ICMP6 && LWIP_IPV6 /* don't build if not configured for use in lwipopts.h */ -- --#include "lwip/icmp6.h" --#include "lwip/prot/icmp6.h" --#include "lwip/ip6.h" --#include "lwip/ip6_addr.h" --#include "lwip/inet_chksum.h" --#include "lwip/pbuf.h" --#include "lwip/netif.h" --#include "lwip/nd6.h" --#include "lwip/mld6.h" --#include "lwip/ip.h" --#include "lwip/stats.h" -- --#include -- --#if LWIP_ICMP6_DATASIZE == 0 --#undef LWIP_ICMP6_DATASIZE --#define LWIP_ICMP6_DATASIZE 8 --#endif -- --/* Forward declarations */ --static void icmp6_send_response(struct pbuf *p, u8_t code, u32_t data, u8_t type); --static void icmp6_send_response_with_addrs(struct pbuf *p, u8_t code, u32_t data, -- u8_t type, const ip6_addr_t *src_addr, const ip6_addr_t *dest_addr); --static void icmp6_send_response_with_addrs_and_netif(struct pbuf *p, u8_t code, u32_t data, -- u8_t type, const ip6_addr_t *src_addr, const ip6_addr_t *dest_addr, struct netif *netif); -- -- --/** -- * Process an input ICMPv6 message. Called by ip6_input. -- * -- * Will generate a reply for echo requests. Other messages are forwarded -- * to nd6_input, or mld6_input. -- * -- * @param p the mld packet, p->payload pointing to the icmpv6 header -- * @param inp the netif on which this packet was received -- */ --void --icmp6_input(struct pbuf *p, struct netif *inp) --{ -- struct icmp6_hdr *icmp6hdr; -- struct pbuf *r; -- const ip6_addr_t *reply_src; -- -- ICMP6_STATS_INC(icmp6.recv); -- -- /* Check that ICMPv6 header fits in payload */ -- if (p->len < sizeof(struct icmp6_hdr)) { -- /* drop short packets */ -- pbuf_free(p); -- ICMP6_STATS_INC(icmp6.lenerr); -- ICMP6_STATS_INC(icmp6.drop); -- return; -- } -- -- icmp6hdr = (struct icmp6_hdr *)p->payload; -- --#if CHECKSUM_CHECK_ICMP6 -- IF__NETIF_CHECKSUM_ENABLED(inp, NETIF_CHECKSUM_CHECK_ICMP6) { -- if (ip6_chksum_pseudo(p, IP6_NEXTH_ICMP6, p->tot_len, ip6_current_src_addr(), -- ip6_current_dest_addr()) != 0) { -- /* Checksum failed */ -- pbuf_free(p); -- ICMP6_STATS_INC(icmp6.chkerr); -- ICMP6_STATS_INC(icmp6.drop); -- return; -- } -- } --#endif /* CHECKSUM_CHECK_ICMP6 */ -- -- switch (icmp6hdr->type) { -- case ICMP6_TYPE_NA: /* Neighbor advertisement */ -- case ICMP6_TYPE_NS: /* Neighbor solicitation */ -- case ICMP6_TYPE_RA: /* Router advertisement */ -- case ICMP6_TYPE_RD: /* Redirect */ -- case ICMP6_TYPE_PTB: /* Packet too big */ -- nd6_input(p, inp); -- return; -- case ICMP6_TYPE_RS: --#if LWIP_IPV6_FORWARD -- /* @todo implement router functionality */ --#endif -- break; --#if LWIP_IPV6_MLD -- case ICMP6_TYPE_MLQ: -- case ICMP6_TYPE_MLR: -- case ICMP6_TYPE_MLD: -- mld6_input(p, inp); -- return; --#endif -- case ICMP6_TYPE_EREQ: --#if !LWIP_MULTICAST_PING -- /* multicast destination address? */ -- if (ip6_addr_ismulticast(ip6_current_dest_addr())) { -- /* drop */ -- pbuf_free(p); -- ICMP6_STATS_INC(icmp6.drop); -- return; -- } --#endif /* LWIP_MULTICAST_PING */ -- -- /* Allocate reply. */ -- r = pbuf_alloc(PBUF_IP, p->tot_len, PBUF_RAM); -- if (r == NULL) { -- /* drop */ -- pbuf_free(p); -- ICMP6_STATS_INC(icmp6.memerr); -- return; -- } -- -- /* Copy echo request. */ -- if (pbuf_copy(r, p) != ERR_OK) { -- /* drop */ -- pbuf_free(p); -- pbuf_free(r); -- ICMP6_STATS_INC(icmp6.err); -- return; -- } -- -- /* Determine reply source IPv6 address. */ --#if LWIP_MULTICAST_PING -- if (ip6_addr_ismulticast(ip6_current_dest_addr())) { -- reply_src = ip_2_ip6(ip6_select_source_address(inp, ip6_current_src_addr())); -- if (reply_src == NULL) { -- /* drop */ -- pbuf_free(p); -- pbuf_free(r); -- ICMP6_STATS_INC(icmp6.rterr); -- return; -- } -- } -- else --#endif /* LWIP_MULTICAST_PING */ -- { -- reply_src = ip6_current_dest_addr(); -- } -- -- /* Set fields in reply. */ -- ((struct icmp6_echo_hdr *)(r->payload))->type = ICMP6_TYPE_EREP; -- ((struct icmp6_echo_hdr *)(r->payload))->chksum = 0; --#if CHECKSUM_GEN_ICMP6 -- IF__NETIF_CHECKSUM_ENABLED(inp, NETIF_CHECKSUM_GEN_ICMP6) { -- ((struct icmp6_echo_hdr *)(r->payload))->chksum = ip6_chksum_pseudo(r, -- IP6_NEXTH_ICMP6, r->tot_len, reply_src, ip6_current_src_addr()); -- } --#endif /* CHECKSUM_GEN_ICMP6 */ -- -- /* Send reply. */ -- ICMP6_STATS_INC(icmp6.xmit); -- ip6_output_if(r, reply_src, ip6_current_src_addr(), -- LWIP_ICMP6_HL, 0, IP6_NEXTH_ICMP6, inp); -- pbuf_free(r); -- -- break; -- default: -- ICMP6_STATS_INC(icmp6.proterr); -- ICMP6_STATS_INC(icmp6.drop); -- break; -- } -- -- pbuf_free(p); --} -- -- --/** -- * Send an icmpv6 'destination unreachable' packet. -- * -- * This function must be used only in direct response to a packet that is being -- * received right now. Otherwise, address zones would be lost. -- * -- * @param p the input packet for which the 'unreachable' should be sent, -- * p->payload pointing to the IPv6 header -- * @param c ICMPv6 code for the unreachable type -- */ --void --icmp6_dest_unreach(struct pbuf *p, enum icmp6_dur_code c) --{ -- icmp6_send_response(p, c, 0, ICMP6_TYPE_DUR); --} -- --/** -- * Send an icmpv6 'packet too big' packet. -- * -- * This function must be used only in direct response to a packet that is being -- * received right now. Otherwise, address zones would be lost. -- * -- * @param p the input packet for which the 'packet too big' should be sent, -- * p->payload pointing to the IPv6 header -- * @param mtu the maximum mtu that we can accept -- */ --void --icmp6_packet_too_big(struct pbuf *p, u32_t mtu) --{ -- icmp6_send_response(p, 0, mtu, ICMP6_TYPE_PTB); --} -- --/** -- * Send an icmpv6 'time exceeded' packet. -- * -- * This function must be used only in direct response to a packet that is being -- * received right now. Otherwise, address zones would be lost. -- * -- * @param p the input packet for which the 'time exceeded' should be sent, -- * p->payload pointing to the IPv6 header -- * @param c ICMPv6 code for the time exceeded type -- */ --void --icmp6_time_exceeded(struct pbuf *p, enum icmp6_te_code c) --{ -- icmp6_send_response(p, c, 0, ICMP6_TYPE_TE); --} -- --/** -- * Send an icmpv6 'time exceeded' packet, with explicit source and destination -- * addresses. -- * -- * This function may be used to send a response sometime after receiving the -- * packet for which this response is meant. The provided source and destination -- * addresses are used primarily to retain their zone information. -- * -- * @param p the input packet for which the 'time exceeded' should be sent, -- * p->payload pointing to the IPv6 header -- * @param c ICMPv6 code for the time exceeded type -- * @param src_addr source address of the original packet, with zone information -- * @param dest_addr destination address of the original packet, with zone -- * information -- */ --void --icmp6_time_exceeded_with_addrs(struct pbuf *p, enum icmp6_te_code c, -- const ip6_addr_t *src_addr, const ip6_addr_t *dest_addr) --{ -- icmp6_send_response_with_addrs(p, c, 0, ICMP6_TYPE_TE, src_addr, dest_addr); --} -- --/** -- * Send an icmpv6 'parameter problem' packet. -- * -- * This function must be used only in direct response to a packet that is being -- * received right now. Otherwise, address zones would be lost and the calculated -- * offset would be wrong (calculated against ip6_current_header()). -- * -- * @param p the input packet for which the 'param problem' should be sent, -- * p->payload pointing to the IP header -- * @param c ICMPv6 code for the param problem type -- * @param pointer the pointer to the byte where the parameter is found -- */ --void --icmp6_param_problem(struct pbuf *p, enum icmp6_pp_code c, const void *pointer) --{ -- u32_t pointer_u32 = (u32_t)((const u8_t *)pointer - (const u8_t *)ip6_current_header()); -- icmp6_send_response(p, c, pointer_u32, ICMP6_TYPE_PP); --} -- --/** -- * Send an ICMPv6 packet in response to an incoming packet. -- * The packet is sent *to* ip_current_src_addr() on ip_current_netif(). -- * -- * @param p the input packet for which the response should be sent, -- * p->payload pointing to the IPv6 header -- * @param code Code of the ICMPv6 header -- * @param data Additional 32-bit parameter in the ICMPv6 header -- * @param type Type of the ICMPv6 header -- */ --static void --icmp6_send_response(struct pbuf *p, u8_t code, u32_t data, u8_t type) --{ -- const struct ip6_addr *reply_src, *reply_dest; -- struct netif *netif = ip_current_netif(); -- -- LWIP_ASSERT("icmpv6 packet not a direct response", netif != NULL); -- reply_dest = ip6_current_src_addr(); -- -- /* Select an address to use as source. */ -- reply_src = ip_2_ip6(ip6_select_source_address(netif, reply_dest)); -- if (reply_src == NULL) { -- ICMP6_STATS_INC(icmp6.rterr); -- return; -- } -- icmp6_send_response_with_addrs_and_netif(p, code, data, type, reply_src, reply_dest, netif); --} -- --/** -- * Send an ICMPv6 packet in response to an incoming packet. -- * -- * Call this function if the packet is NOT sent as a direct response to an -- * incoming packet, but rather sometime later (e.g. for a fragment reassembly -- * timeout). The caller must provide the zoned source and destination addresses -- * from the original packet with the src_addr and dest_addr parameters. The -- * reason for this approach is that while the addresses themselves are part of -- * the original packet, their zone information is not, thus possibly resulting -- * in a link-local response being sent over the wrong link. -- * -- * @param p the input packet for which the response should be sent, -- * p->payload pointing to the IPv6 header -- * @param code Code of the ICMPv6 header -- * @param data Additional 32-bit parameter in the ICMPv6 header -- * @param type Type of the ICMPv6 header -- * @param src_addr original source address -- * @param dest_addr original destination address -- */ --static void --icmp6_send_response_with_addrs(struct pbuf *p, u8_t code, u32_t data, u8_t type, -- const ip6_addr_t *src_addr, const ip6_addr_t *dest_addr) --{ -- const struct ip6_addr *reply_src, *reply_dest; -- struct netif *netif; -- -- /* Get the destination address and netif for this ICMP message. */ -- LWIP_ASSERT("must provide both source and destination", src_addr != NULL); -- LWIP_ASSERT("must provide both source and destination", dest_addr != NULL); -- -- /* Special case, as ip6_current_xxx is either NULL, or points -- to a different packet than the one that expired. */ -- IP6_ADDR_ZONECHECK(src_addr); -- IP6_ADDR_ZONECHECK(dest_addr); -- /* Swap source and destination for the reply. */ -- reply_dest = src_addr; -- reply_src = dest_addr; -- netif = ip6_route(reply_src, reply_dest); -- if (netif == NULL) { -- ICMP6_STATS_INC(icmp6.rterr); -- return; -- } -- icmp6_send_response_with_addrs_and_netif(p, code, data, type, reply_src, -- reply_dest, netif); --} -- --/** -- * Send an ICMPv6 packet (with srd/dst address and netif given). -- * -- * @param p the input packet for which the response should be sent, -- * p->payload pointing to the IPv6 header -- * @param code Code of the ICMPv6 header -- * @param data Additional 32-bit parameter in the ICMPv6 header -- * @param type Type of the ICMPv6 header -- * @param reply_src source address of the packet to send -- * @param reply_dest destination address of the packet to send -- * @param netif netif to send the packet -- */ --static void --icmp6_send_response_with_addrs_and_netif(struct pbuf *p, u8_t code, u32_t data, u8_t type, -- const ip6_addr_t *reply_src, const ip6_addr_t *reply_dest, struct netif *netif) --{ -- struct pbuf *q; -- struct icmp6_hdr *icmp6hdr; -- -- /* ICMPv6 header + IPv6 header + data */ -- q = pbuf_alloc(PBUF_IP, sizeof(struct icmp6_hdr) + IP6_HLEN + LWIP_ICMP6_DATASIZE, -- PBUF_RAM); -- if (q == NULL) { -- LWIP_DEBUGF(ICMP_DEBUG, ("icmp_time_exceeded: failed to allocate pbuf for ICMPv6 packet.\n")); -- ICMP6_STATS_INC(icmp6.memerr); -- return; -- } -- LWIP_ASSERT("check that first pbuf can hold icmp 6message", -- (q->len >= (sizeof(struct icmp6_hdr) + IP6_HLEN + LWIP_ICMP6_DATASIZE))); -- -- icmp6hdr = (struct icmp6_hdr *)q->payload; -- icmp6hdr->type = type; -- icmp6hdr->code = code; -- icmp6hdr->data = lwip_htonl(data); -- -- /* copy fields from original packet */ -- SMEMCPY((u8_t *)q->payload + sizeof(struct icmp6_hdr), (u8_t *)p->payload, -- IP6_HLEN + LWIP_ICMP6_DATASIZE); -- -- /* calculate checksum */ -- icmp6hdr->chksum = 0; --#if CHECKSUM_GEN_ICMP6 -- IF__NETIF_CHECKSUM_ENABLED(netif, NETIF_CHECKSUM_GEN_ICMP6) { -- icmp6hdr->chksum = ip6_chksum_pseudo(q, IP6_NEXTH_ICMP6, q->tot_len, -- reply_src, reply_dest); -- } --#endif /* CHECKSUM_GEN_ICMP6 */ -- -- ICMP6_STATS_INC(icmp6.xmit); -- ip6_output_if(q, reply_src, reply_dest, LWIP_ICMP6_HL, 0, IP6_NEXTH_ICMP6, netif); -- pbuf_free(q); --} -- --#endif /* LWIP_ICMP6 && LWIP_IPV6 */ -+/** -+ * @file -+ * -+ * IPv6 version of ICMP, as per RFC 4443. -+ */ -+ -+/* -+ * Copyright (c) 2010 Inico Technologies Ltd. -+ * 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: Ivan Delamer -+ * -+ * -+ * Please coordinate changes and requests with Ivan Delamer -+ * -+ */ -+ -+#include "lwip/opt.h" -+ -+#if LWIP_ICMP6 && LWIP_IPV6 /* don't build if not configured for use in lwipopts.h */ -+ -+#include "lwip/icmp6.h" -+#include "lwip/prot/icmp6.h" -+#include "lwip/ip6.h" -+#include "lwip/ip6_addr.h" -+#include "lwip/inet_chksum.h" -+#include "lwip/pbuf.h" -+#include "lwip/netif.h" -+#include "lwip/nd6.h" -+#include "lwip/mld6.h" -+#include "lwip/ip.h" -+#include "lwip/stats.h" -+ -+#include -+ -+#if LWIP_ICMP6_DATASIZE == 0 -+#undef LWIP_ICMP6_DATASIZE -+#define LWIP_ICMP6_DATASIZE 8 -+#endif -+ -+/* Forward declarations */ -+static void icmp6_send_response(struct pbuf *p, u8_t code, u32_t data, u8_t type); -+static void icmp6_send_response_with_addrs(struct pbuf *p, u8_t code, u32_t data, -+ u8_t type, const ip6_addr_t *src_addr, const ip6_addr_t *dest_addr); -+static void icmp6_send_response_with_addrs_and_netif(struct pbuf *p, u8_t code, u32_t data, -+ u8_t type, const ip6_addr_t *src_addr, const ip6_addr_t *dest_addr, struct netif *netif); -+ -+ -+/** -+ * Process an input ICMPv6 message. Called by ip6_input. -+ * -+ * Will generate a reply for echo requests. Other messages are forwarded -+ * to nd6_input, or mld6_input. -+ * -+ * @param p the mld packet, p->payload pointing to the icmpv6 header -+ * @param inp the netif on which this packet was received -+ */ -+void -+icmp6_input(struct pbuf *p, struct netif *inp) -+{ -+ struct icmpv6_hdr *icmp6hdr; -+ struct pbuf *r; -+ const ip6_addr_t *reply_src; -+ -+ ICMP6_STATS_INC(icmp6.recv); -+ -+ /* Check that ICMPv6 header fits in payload */ -+ if (p->len < sizeof(struct icmpv6_hdr)) { -+ /* drop short packets */ -+ pbuf_free(p); -+ ICMP6_STATS_INC(icmp6.lenerr); -+ ICMP6_STATS_INC(icmp6.drop); -+ return; -+ } -+ -+ icmp6hdr = (struct icmpv6_hdr *)p->payload; -+ -+#if CHECKSUM_CHECK_ICMP6 -+ IF__NETIF_CHECKSUM_ENABLED(inp, NETIF_CHECKSUM_CHECK_ICMP6) { -+ if (ip6_chksum_pseudo(p, IP6_NEXTH_ICMP6, p->tot_len, ip6_current_src_addr(), -+ ip6_current_dest_addr()) != 0) { -+ /* Checksum failed */ -+ pbuf_free(p); -+ ICMP6_STATS_INC(icmp6.chkerr); -+ ICMP6_STATS_INC(icmp6.drop); -+ return; -+ } -+ } -+#endif /* CHECKSUM_CHECK_ICMP6 */ -+ -+ switch (icmp6hdr->type) { -+ case ICMP6_TYPE_NA: /* Neighbor advertisement */ -+ case ICMP6_TYPE_NS: /* Neighbor solicitation */ -+ case ICMP6_TYPE_RA: /* Router advertisement */ -+ case ICMP6_TYPE_RD: /* Redirect */ -+ case ICMP6_TYPE_PTB: /* Packet too big */ -+ nd6_input(p, inp); -+ return; -+ case ICMP6_TYPE_RS: -+#if LWIP_IPV6_FORWARD -+ /* @todo implement router functionality */ -+#endif -+ break; -+#if LWIP_IPV6_MLD -+ case ICMP6_TYPE_MLQ: -+ case ICMP6_TYPE_MLR: -+ case ICMP6_TYPE_MLD: -+ mld6_input(p, inp); -+ return; -+#endif -+ case ICMP6_TYPE_EREQ: -+#if !LWIP_MULTICAST_PING -+ /* multicast destination address? */ -+ if (ip6_addr_ismulticast(ip6_current_dest_addr())) { -+ /* drop */ -+ pbuf_free(p); -+ ICMP6_STATS_INC(icmp6.drop); -+ return; -+ } -+#endif /* LWIP_MULTICAST_PING */ -+ -+ /* Allocate reply. */ -+ r = pbuf_alloc(PBUF_IP, p->tot_len, PBUF_RAM); -+ if (r == NULL) { -+ /* drop */ -+ pbuf_free(p); -+ ICMP6_STATS_INC(icmp6.memerr); -+ return; -+ } -+ -+ /* Copy echo request. */ -+ if (pbuf_copy(r, p) != ERR_OK) { -+ /* drop */ -+ pbuf_free(p); -+ pbuf_free(r); -+ ICMP6_STATS_INC(icmp6.err); -+ return; -+ } -+ -+ /* Determine reply source IPv6 address. */ -+#if LWIP_MULTICAST_PING -+ if (ip6_addr_ismulticast(ip6_current_dest_addr())) { -+ reply_src = ip_2_ip6(ip6_select_source_address(inp, ip6_current_src_addr())); -+ if (reply_src == NULL) { -+ /* drop */ -+ pbuf_free(p); -+ pbuf_free(r); -+ ICMP6_STATS_INC(icmp6.rterr); -+ return; -+ } -+ } -+ else -+#endif /* LWIP_MULTICAST_PING */ -+ { -+ reply_src = ip6_current_dest_addr(); -+ } -+ -+ /* Set fields in reply. */ -+ ((struct icmp6_echo_hdr *)(r->payload))->type = ICMP6_TYPE_EREP; -+ ((struct icmp6_echo_hdr *)(r->payload))->chksum = 0; -+#if CHECKSUM_GEN_ICMP6 -+ IF__NETIF_CHECKSUM_ENABLED(inp, NETIF_CHECKSUM_GEN_ICMP6) { -+ ((struct icmp6_echo_hdr *)(r->payload))->chksum = ip6_chksum_pseudo(r, -+ IP6_NEXTH_ICMP6, r->tot_len, reply_src, ip6_current_src_addr()); -+ } -+#endif /* CHECKSUM_GEN_ICMP6 */ -+ -+ /* Send reply. */ -+ ICMP6_STATS_INC(icmp6.xmit); -+ ip6_output_if(r, reply_src, ip6_current_src_addr(), -+ LWIP_ICMP6_HL, 0, IP6_NEXTH_ICMP6, inp); -+ pbuf_free(r); -+ -+ break; -+ default: -+ ICMP6_STATS_INC(icmp6.proterr); -+ ICMP6_STATS_INC(icmp6.drop); -+ break; -+ } -+ -+ pbuf_free(p); -+} -+ -+ -+/** -+ * Send an icmpv6 'destination unreachable' packet. -+ * -+ * This function must be used only in direct response to a packet that is being -+ * received right now. Otherwise, address zones would be lost. -+ * -+ * @param p the input packet for which the 'unreachable' should be sent, -+ * p->payload pointing to the IPv6 header -+ * @param c ICMPv6 code for the unreachable type -+ */ -+void -+icmp6_dest_unreach(struct pbuf *p, enum icmp6_dur_code c) -+{ -+ icmp6_send_response(p, c, 0, ICMP6_TYPE_DUR); -+} -+ -+/** -+ * Send an icmpv6 'packet too big' packet. -+ * -+ * This function must be used only in direct response to a packet that is being -+ * received right now. Otherwise, address zones would be lost. -+ * -+ * @param p the input packet for which the 'packet too big' should be sent, -+ * p->payload pointing to the IPv6 header -+ * @param mtu the maximum mtu that we can accept -+ */ -+void -+icmp6_packet_too_big(struct pbuf *p, u32_t mtu) -+{ -+ icmp6_send_response(p, 0, mtu, ICMP6_TYPE_PTB); -+} -+ -+/** -+ * Send an icmpv6 'time exceeded' packet. -+ * -+ * This function must be used only in direct response to a packet that is being -+ * received right now. Otherwise, address zones would be lost. -+ * -+ * @param p the input packet for which the 'time exceeded' should be sent, -+ * p->payload pointing to the IPv6 header -+ * @param c ICMPv6 code for the time exceeded type -+ */ -+void -+icmp6_time_exceeded(struct pbuf *p, enum icmp6_te_code c) -+{ -+ icmp6_send_response(p, c, 0, ICMP6_TYPE_TE); -+} -+ -+/** -+ * Send an icmpv6 'time exceeded' packet, with explicit source and destination -+ * addresses. -+ * -+ * This function may be used to send a response sometime after receiving the -+ * packet for which this response is meant. The provided source and destination -+ * addresses are used primarily to retain their zone information. -+ * -+ * @param p the input packet for which the 'time exceeded' should be sent, -+ * p->payload pointing to the IPv6 header -+ * @param c ICMPv6 code for the time exceeded type -+ * @param src_addr source address of the original packet, with zone information -+ * @param dest_addr destination address of the original packet, with zone -+ * information -+ */ -+void -+icmp6_time_exceeded_with_addrs(struct pbuf *p, enum icmp6_te_code c, -+ const ip6_addr_t *src_addr, const ip6_addr_t *dest_addr) -+{ -+ icmp6_send_response_with_addrs(p, c, 0, ICMP6_TYPE_TE, src_addr, dest_addr); -+} -+ -+/** -+ * Send an icmpv6 'parameter problem' packet. -+ * -+ * This function must be used only in direct response to a packet that is being -+ * received right now. Otherwise, address zones would be lost and the calculated -+ * offset would be wrong (calculated against ip6_current_header()). -+ * -+ * @param p the input packet for which the 'param problem' should be sent, -+ * p->payload pointing to the IP header -+ * @param c ICMPv6 code for the param problem type -+ * @param pointer the pointer to the byte where the parameter is found -+ */ -+void -+icmp6_param_problem(struct pbuf *p, enum icmp6_pp_code c, const void *pointer) -+{ -+ u32_t pointer_u32 = (u32_t)((const u8_t *)pointer - (const u8_t *)ip6_current_header()); -+ icmp6_send_response(p, c, pointer_u32, ICMP6_TYPE_PP); -+} -+ -+/** -+ * Send an ICMPv6 packet in response to an incoming packet. -+ * The packet is sent *to* ip_current_src_addr() on ip_current_netif(). -+ * -+ * @param p the input packet for which the response should be sent, -+ * p->payload pointing to the IPv6 header -+ * @param code Code of the ICMPv6 header -+ * @param data Additional 32-bit parameter in the ICMPv6 header -+ * @param type Type of the ICMPv6 header -+ */ -+static void -+icmp6_send_response(struct pbuf *p, u8_t code, u32_t data, u8_t type) -+{ -+ const struct ip6_addr *reply_src, *reply_dest; -+ struct netif *netif = ip_current_netif(); -+ -+ LWIP_ASSERT("icmpv6 packet not a direct response", netif != NULL); -+ reply_dest = ip6_current_src_addr(); -+ -+ /* Select an address to use as source. */ -+ reply_src = ip_2_ip6(ip6_select_source_address(netif, reply_dest)); -+ if (reply_src == NULL) { -+ ICMP6_STATS_INC(icmp6.rterr); -+ return; -+ } -+ icmp6_send_response_with_addrs_and_netif(p, code, data, type, reply_src, reply_dest, netif); -+} -+ -+/** -+ * Send an ICMPv6 packet in response to an incoming packet. -+ * -+ * Call this function if the packet is NOT sent as a direct response to an -+ * incoming packet, but rather sometime later (e.g. for a fragment reassembly -+ * timeout). The caller must provide the zoned source and destination addresses -+ * from the original packet with the src_addr and dest_addr parameters. The -+ * reason for this approach is that while the addresses themselves are part of -+ * the original packet, their zone information is not, thus possibly resulting -+ * in a link-local response being sent over the wrong link. -+ * -+ * @param p the input packet for which the response should be sent, -+ * p->payload pointing to the IPv6 header -+ * @param code Code of the ICMPv6 header -+ * @param data Additional 32-bit parameter in the ICMPv6 header -+ * @param type Type of the ICMPv6 header -+ * @param src_addr original source address -+ * @param dest_addr original destination address -+ */ -+static void -+icmp6_send_response_with_addrs(struct pbuf *p, u8_t code, u32_t data, u8_t type, -+ const ip6_addr_t *src_addr, const ip6_addr_t *dest_addr) -+{ -+ const struct ip6_addr *reply_src, *reply_dest; -+ struct netif *netif; -+ -+ /* Get the destination address and netif for this ICMP message. */ -+ LWIP_ASSERT("must provide both source and destination", src_addr != NULL); -+ LWIP_ASSERT("must provide both source and destination", dest_addr != NULL); -+ -+ /* Special case, as ip6_current_xxx is either NULL, or points -+ to a different packet than the one that expired. */ -+ IP6_ADDR_ZONECHECK(src_addr); -+ IP6_ADDR_ZONECHECK(dest_addr); -+ /* Swap source and destination for the reply. */ -+ reply_dest = src_addr; -+ reply_src = dest_addr; -+ netif = ip6_route(reply_src, reply_dest); -+ if (netif == NULL) { -+ ICMP6_STATS_INC(icmp6.rterr); -+ return; -+ } -+ icmp6_send_response_with_addrs_and_netif(p, code, data, type, reply_src, -+ reply_dest, netif); -+} -+ -+/** -+ * Send an ICMPv6 packet (with srd/dst address and netif given). -+ * -+ * @param p the input packet for which the response should be sent, -+ * p->payload pointing to the IPv6 header -+ * @param code Code of the ICMPv6 header -+ * @param data Additional 32-bit parameter in the ICMPv6 header -+ * @param type Type of the ICMPv6 header -+ * @param reply_src source address of the packet to send -+ * @param reply_dest destination address of the packet to send -+ * @param netif netif to send the packet -+ */ -+static void -+icmp6_send_response_with_addrs_and_netif(struct pbuf *p, u8_t code, u32_t data, u8_t type, -+ const ip6_addr_t *reply_src, const ip6_addr_t *reply_dest, struct netif *netif) -+{ -+ struct pbuf *q; -+ struct icmpv6_hdr *icmp6hdr; -+ -+ /* ICMPv6 header + IPv6 header + data */ -+ q = pbuf_alloc(PBUF_IP, sizeof(struct icmpv6_hdr) + IP6_HLEN + LWIP_ICMP6_DATASIZE, -+ PBUF_RAM); -+ if (q == NULL) { -+ LWIP_DEBUGF(ICMP_DEBUG, ("icmp_time_exceeded: failed to allocate pbuf for ICMPv6 packet.\n")); -+ ICMP6_STATS_INC(icmp6.memerr); -+ return; -+ } -+ LWIP_ASSERT("check that first pbuf can hold icmp 6message", -+ (q->len >= (sizeof(struct icmpv6_hdr) + IP6_HLEN + LWIP_ICMP6_DATASIZE))); -+ -+ icmp6hdr = (struct icmpv6_hdr *)q->payload; -+ icmp6hdr->type = type; -+ icmp6hdr->code = code; -+ icmp6hdr->data = lwip_htonl(data); -+ -+ /* copy fields from original packet */ -+ SMEMCPY((u8_t *)q->payload + sizeof(struct icmpv6_hdr), (u8_t *)p->payload, -+ IP6_HLEN + LWIP_ICMP6_DATASIZE); -+ -+ /* calculate checksum */ -+ icmp6hdr->chksum = 0; -+#if CHECKSUM_GEN_ICMP6 -+ IF__NETIF_CHECKSUM_ENABLED(netif, NETIF_CHECKSUM_GEN_ICMP6) { -+ icmp6hdr->chksum = ip6_chksum_pseudo(q, IP6_NEXTH_ICMP6, q->tot_len, -+ reply_src, reply_dest); -+ } -+#endif /* CHECKSUM_GEN_ICMP6 */ -+ -+ ICMP6_STATS_INC(icmp6.xmit); -+ ip6_output_if(q, reply_src, reply_dest, LWIP_ICMP6_HL, 0, IP6_NEXTH_ICMP6, netif); -+ pbuf_free(q); -+} -+ -+#endif /* LWIP_ICMP6 && LWIP_IPV6 */ -diff -Nur a/lwip-2.1.2/src/core/ipv6/nd6.c b/lwip-2.1.2/src/core/ipv6/nd6.c ---- a/lwip-2.1.2/src/core/ipv6/nd6.c 2021-05-08 18:13:52.631621024 +0800 -+++ b/lwip-2.1.2/src/core/ipv6/nd6.c 2021-04-27 18:56:55.440353467 +0800 -@@ -1,2434 +1,2434 @@ --/** -- * @file -- * -- * Neighbor discovery and stateless address autoconfiguration for IPv6. -- * Aims to be compliant with RFC 4861 (Neighbor discovery) and RFC 4862 -- * (Address autoconfiguration). -- */ -- --/* -- * Copyright (c) 2010 Inico Technologies Ltd. -- * 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: Ivan Delamer -- * -- * -- * Please coordinate changes and requests with Ivan Delamer -- * -- */ -- --#include "lwip/opt.h" -- --#if LWIP_IPV6 /* don't build if not configured for use in lwipopts.h */ -- --#include "lwip/nd6.h" --#include "lwip/priv/nd6_priv.h" --#include "lwip/prot/nd6.h" --#include "lwip/prot/icmp6.h" --#include "lwip/pbuf.h" --#include "lwip/mem.h" --#include "lwip/memp.h" --#include "lwip/ip6.h" --#include "lwip/ip6_addr.h" --#include "lwip/inet_chksum.h" --#include "lwip/netif.h" --#include "lwip/icmp6.h" --#include "lwip/mld6.h" --#include "lwip/dhcp6.h" --#include "lwip/ip.h" --#include "lwip/stats.h" --#include "lwip/dns.h" -- --#include -- --#ifdef LWIP_HOOK_FILENAME --#include LWIP_HOOK_FILENAME --#endif -- --#if LWIP_IPV6_DUP_DETECT_ATTEMPTS > IP6_ADDR_TENTATIVE_COUNT_MASK --#error LWIP_IPV6_DUP_DETECT_ATTEMPTS > IP6_ADDR_TENTATIVE_COUNT_MASK --#endif -- --/* Router tables. */ --struct nd6_neighbor_cache_entry neighbor_cache[LWIP_ND6_NUM_NEIGHBORS]; --struct nd6_destination_cache_entry destination_cache[LWIP_ND6_NUM_DESTINATIONS]; --struct nd6_prefix_list_entry prefix_list[LWIP_ND6_NUM_PREFIXES]; --struct nd6_router_list_entry default_router_list[LWIP_ND6_NUM_ROUTERS]; -- --/* Default values, can be updated by a RA message. */ --u32_t reachable_time = LWIP_ND6_REACHABLE_TIME; --u32_t retrans_timer = LWIP_ND6_RETRANS_TIMER; /* @todo implement this value in timer */ -- --/* Index for cache entries. */ --static u8_t nd6_cached_neighbor_index; --static netif_addr_idx_t nd6_cached_destination_index; -- --/* Multicast address holder. */ --static ip6_addr_t multicast_address; -- --static u8_t nd6_tmr_rs_reduction; -- --/* Static buffer to parse RA packet options */ --union ra_options { -- struct lladdr_option lladdr; -- struct mtu_option mtu; -- struct prefix_option prefix; --#if LWIP_ND6_RDNSS_MAX_DNS_SERVERS -- struct rdnss_option rdnss; --#endif --}; --static union ra_options nd6_ra_buffer; -- --/* Forward declarations. */ --static s8_t nd6_find_neighbor_cache_entry(const ip6_addr_t *ip6addr); --static s8_t nd6_new_neighbor_cache_entry(void); --static void nd6_free_neighbor_cache_entry(s8_t i); --static s16_t nd6_find_destination_cache_entry(const ip6_addr_t *ip6addr); --static s16_t nd6_new_destination_cache_entry(void); --static int nd6_is_prefix_in_netif(const ip6_addr_t *ip6addr, struct netif *netif); --static s8_t nd6_select_router(const ip6_addr_t *ip6addr, struct netif *netif); --static s8_t nd6_get_router(const ip6_addr_t *router_addr, struct netif *netif); --static s8_t nd6_new_router(const ip6_addr_t *router_addr, struct netif *netif); --static s8_t nd6_get_onlink_prefix(const ip6_addr_t *prefix, struct netif *netif); --static s8_t nd6_new_onlink_prefix(const ip6_addr_t *prefix, struct netif *netif); --static s8_t nd6_get_next_hop_entry(const ip6_addr_t *ip6addr, struct netif *netif); --static err_t nd6_queue_packet(s8_t neighbor_index, struct pbuf *q); -- --#define ND6_SEND_FLAG_MULTICAST_DEST 0x01 --#define ND6_SEND_FLAG_ALLNODES_DEST 0x02 --#define ND6_SEND_FLAG_ANY_SRC 0x04 --static void nd6_send_ns(struct netif *netif, const ip6_addr_t *target_addr, u8_t flags); --static void nd6_send_na(struct netif *netif, const ip6_addr_t *target_addr, u8_t flags); --static void nd6_send_neighbor_cache_probe(struct nd6_neighbor_cache_entry *entry, u8_t flags); --#if LWIP_IPV6_SEND_ROUTER_SOLICIT --static err_t nd6_send_rs(struct netif *netif); --#endif /* LWIP_IPV6_SEND_ROUTER_SOLICIT */ -- --#if LWIP_ND6_QUEUEING --static void nd6_free_q(struct nd6_q_entry *q); --#else /* LWIP_ND6_QUEUEING */ --#define nd6_free_q(q) pbuf_free(q) --#endif /* LWIP_ND6_QUEUEING */ --static void nd6_send_q(s8_t i); -- -- --/** -- * A local address has been determined to be a duplicate. Take the appropriate -- * action(s) on the address and the interface as a whole. -- * -- * @param netif the netif that owns the address -- * @param addr_idx the index of the address detected to be a duplicate -- */ --static void --nd6_duplicate_addr_detected(struct netif *netif, s8_t addr_idx) --{ -- -- /* Mark the address as duplicate, but leave its lifetimes alone. If this was -- * a manually assigned address, it will remain in existence as duplicate, and -- * as such be unusable for any practical purposes until manual intervention. -- * If this was an autogenerated address, the address will follow normal -- * expiration rules, and thus disappear once its valid lifetime expires. */ -- netif_ip6_addr_set_state(netif, addr_idx, IP6_ADDR_DUPLICATED); -- --#if LWIP_IPV6_AUTOCONFIG -- /* If the affected address was the link-local address that we use to generate -- * all other addresses, then we should not continue to use those derived -- * addresses either, so mark them as duplicate as well. For autoconfig-only -- * setups, this will make the interface effectively unusable, approaching the -- * intention of RFC 4862 Sec. 5.4.5. @todo implement the full requirements */ -- if (addr_idx == 0) { -- s8_t i; -- for (i = 1; i < LWIP_IPV6_NUM_ADDRESSES; i++) { -- if (!ip6_addr_isinvalid(netif_ip6_addr_state(netif, i)) && -- !netif_ip6_addr_isstatic(netif, i)) { -- netif_ip6_addr_set_state(netif, i, IP6_ADDR_DUPLICATED); -- } -- } -- } --#endif /* LWIP_IPV6_AUTOCONFIG */ --} -- --#if LWIP_IPV6_AUTOCONFIG --/** -- * We received a router advertisement that contains a prefix with the -- * autoconfiguration flag set. Add or update an associated autogenerated -- * address. -- * -- * @param netif the netif on which the router advertisement arrived -- * @param prefix_opt a pointer to the prefix option data -- * @param prefix_addr an aligned copy of the prefix address -- */ --static void --nd6_process_autoconfig_prefix(struct netif *netif, -- struct prefix_option *prefix_opt, const ip6_addr_t *prefix_addr) --{ -- ip6_addr_t ip6addr; -- u32_t valid_life, pref_life; -- u8_t addr_state; -- s8_t i, free_idx; -- -- /* The caller already checks RFC 4862 Sec. 5.5.3 points (a) and (b). We do -- * the rest, starting with checks for (c) and (d) here. */ -- valid_life = lwip_htonl(prefix_opt->valid_lifetime); -- pref_life = lwip_htonl(prefix_opt->preferred_lifetime); -- if (pref_life > valid_life || prefix_opt->prefix_length != 64) { -- return; /* silently ignore this prefix for autoconfiguration purposes */ -- } -- -- /* If an autogenerated address already exists for this prefix, update its -- * lifetimes. An address is considered autogenerated if 1) it is not static -- * (i.e., manually assigned), and 2) there is an advertised autoconfiguration -- * prefix for it (the one we are processing here). This does not necessarily -- * exclude the possibility that the address was actually assigned by, say, -- * DHCPv6. If that distinction becomes important in the future, more state -- * must be kept. As explained elsewhere we also update lifetimes of tentative -- * and duplicate addresses. Skip address slot 0 (the link-local address). */ -- for (i = 1; i < LWIP_IPV6_NUM_ADDRESSES; i++) { -- addr_state = netif_ip6_addr_state(netif, i); -- if (!ip6_addr_isinvalid(addr_state) && !netif_ip6_addr_isstatic(netif, i) && -- ip6_addr_netcmp(prefix_addr, netif_ip6_addr(netif, i))) { -- /* Update the valid lifetime, as per RFC 4862 Sec. 5.5.3 point (e). -- * The valid lifetime will never drop to zero as a result of this. */ -- u32_t remaining_life = netif_ip6_addr_valid_life(netif, i); -- if (valid_life > ND6_2HRS || valid_life > remaining_life) { -- netif_ip6_addr_set_valid_life(netif, i, valid_life); -- } else if (remaining_life > ND6_2HRS) { -- netif_ip6_addr_set_valid_life(netif, i, ND6_2HRS); -- } -- LWIP_ASSERT("bad valid lifetime", !netif_ip6_addr_isstatic(netif, i)); -- /* Update the preferred lifetime. No bounds checks are needed here. In -- * rare cases the advertisement may un-deprecate the address, though. -- * Deprecation is left to the timer code where it is handled anyway. */ -- if (pref_life > 0 && addr_state == IP6_ADDR_DEPRECATED) { -- netif_ip6_addr_set_state(netif, i, IP6_ADDR_PREFERRED); -- } -- netif_ip6_addr_set_pref_life(netif, i, pref_life); -- return; /* there should be at most one matching address */ -- } -- } -- -- /* No autogenerated address exists for this prefix yet. See if we can add a -- * new one. However, if IPv6 autoconfiguration is administratively disabled, -- * do not generate new addresses, but do keep updating lifetimes for existing -- * addresses. Also, when adding new addresses, we must protect explicitly -- * against a valid lifetime of zero, because again, we use that as a special -- * value. The generated address would otherwise expire immediately anyway. -- * Finally, the original link-local address must be usable at all. We start -- * creating addresses even if the link-local address is still in tentative -- * state though, and deal with the fallout of that upon DAD collision. */ -- addr_state = netif_ip6_addr_state(netif, 0); -- if (!netif->ip6_autoconfig_enabled || valid_life == IP6_ADDR_LIFE_STATIC || -- ip6_addr_isinvalid(addr_state) || ip6_addr_isduplicated(addr_state)) { -- return; -- } -- -- /* Construct the new address that we intend to use, and then see if that -- * address really does not exist. It might have been added manually, after -- * all. As a side effect, find a free slot. Note that we cannot use -- * netif_add_ip6_address() here, as it would return ERR_OK if the address -- * already did exist, resulting in that address being given lifetimes. */ -- IP6_ADDR(&ip6addr, prefix_addr->addr[0], prefix_addr->addr[1], -- netif_ip6_addr(netif, 0)->addr[2], netif_ip6_addr(netif, 0)->addr[3]); -- ip6_addr_assign_zone(&ip6addr, IP6_UNICAST, netif); -- -- free_idx = 0; -- for (i = 1; i < LWIP_IPV6_NUM_ADDRESSES; i++) { -- if (!ip6_addr_isinvalid(netif_ip6_addr_state(netif, i))) { -- if (ip6_addr_cmp(&ip6addr, netif_ip6_addr(netif, i))) { -- return; /* formed address already exists */ -- } -- } else if (free_idx == 0) { -- free_idx = i; -- } -- } -- if (free_idx == 0) { -- return; /* no address slots available, try again on next advertisement */ -- } -- -- /* Assign the new address to the interface. */ -- ip_addr_copy_from_ip6(netif->ip6_addr[free_idx], ip6addr); -- netif_ip6_addr_set_valid_life(netif, free_idx, valid_life); -- netif_ip6_addr_set_pref_life(netif, free_idx, pref_life); -- netif_ip6_addr_set_state(netif, free_idx, IP6_ADDR_TENTATIVE); --} --#endif /* LWIP_IPV6_AUTOCONFIG */ -- --/** -- * Process an incoming neighbor discovery message -- * -- * @param p the nd packet, p->payload pointing to the icmpv6 header -- * @param inp the netif on which this packet was received -- */ --void --nd6_input(struct pbuf *p, struct netif *inp) --{ -- u8_t msg_type; -- s8_t i; -- s16_t dest_idx; -- -- ND6_STATS_INC(nd6.recv); -- -- msg_type = *((u8_t *)p->payload); -- switch (msg_type) { -- case ICMP6_TYPE_NA: /* Neighbor Advertisement. */ -- { -- struct na_header *na_hdr; -- struct lladdr_option *lladdr_opt; -- ip6_addr_t target_address; -- -- /* Check that na header fits in packet. */ -- if (p->len < (sizeof(struct na_header))) { -- /* @todo debug message */ -- pbuf_free(p); -- ND6_STATS_INC(nd6.lenerr); -- ND6_STATS_INC(nd6.drop); -- return; -- } -- -- na_hdr = (struct na_header *)p->payload; -- -- /* Create an aligned, zoned copy of the target address. */ -- ip6_addr_copy_from_packed(target_address, na_hdr->target_address); -- ip6_addr_assign_zone(&target_address, IP6_UNICAST, inp); -- -- /* Check a subset of the other RFC 4861 Sec. 7.1.2 requirements. */ -- if (IP6H_HOPLIM(ip6_current_header()) != ND6_HOPLIM || na_hdr->code != 0 || -- ip6_addr_ismulticast(&target_address)) { -- pbuf_free(p); -- ND6_STATS_INC(nd6.proterr); -- ND6_STATS_INC(nd6.drop); -- return; -- } -- -- /* @todo RFC MUST: if IP destination is multicast, Solicited flag is zero */ -- /* @todo RFC MUST: all included options have a length greater than zero */ -- -- /* Unsolicited NA?*/ -- if (ip6_addr_ismulticast(ip6_current_dest_addr())) { -- /* This is an unsolicited NA. -- * link-layer changed? -- * part of DAD mechanism? */ -- --#if LWIP_IPV6_DUP_DETECT_ATTEMPTS -- /* If the target address matches this netif, it is a DAD response. */ -- for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) { -- if (!ip6_addr_isinvalid(netif_ip6_addr_state(inp, i)) && -- !ip6_addr_isduplicated(netif_ip6_addr_state(inp, i)) && -- ip6_addr_cmp(&target_address, netif_ip6_addr(inp, i))) { -- /* We are using a duplicate address. */ -- nd6_duplicate_addr_detected(inp, i); -- -- pbuf_free(p); -- return; -- } -- } --#endif /* LWIP_IPV6_DUP_DETECT_ATTEMPTS */ -- -- /* Check that link-layer address option also fits in packet. */ -- if (p->len < (sizeof(struct na_header) + 2)) { -- /* @todo debug message */ -- pbuf_free(p); -- ND6_STATS_INC(nd6.lenerr); -- ND6_STATS_INC(nd6.drop); -- return; -- } -- -- lladdr_opt = (struct lladdr_option *)((u8_t*)p->payload + sizeof(struct na_header)); -- -- if (p->len < (sizeof(struct na_header) + (lladdr_opt->length << 3))) { -- /* @todo debug message */ -- pbuf_free(p); -- ND6_STATS_INC(nd6.lenerr); -- ND6_STATS_INC(nd6.drop); -- return; -- } -- -- /* This is an unsolicited NA, most likely there was a LLADDR change. */ -- i = nd6_find_neighbor_cache_entry(&target_address); -- if (i >= 0) { -- if (na_hdr->flags & ND6_FLAG_OVERRIDE) { -- MEMCPY(neighbor_cache[i].lladdr, lladdr_opt->addr, inp->hwaddr_len); -- } -- } -- } else { -- /* This is a solicited NA. -- * neighbor address resolution response? -- * neighbor unreachability detection response? */ -- -- /* Find the cache entry corresponding to this na. */ -- i = nd6_find_neighbor_cache_entry(&target_address); -- if (i < 0) { -- /* We no longer care about this target address. drop it. */ -- pbuf_free(p); -- return; -- } -- -- /* Update cache entry. */ -- if ((na_hdr->flags & ND6_FLAG_OVERRIDE) || -- (neighbor_cache[i].state == ND6_INCOMPLETE)) { -- /* Check that link-layer address option also fits in packet. */ -- if (p->len < (sizeof(struct na_header) + 2)) { -- /* @todo debug message */ -- pbuf_free(p); -- ND6_STATS_INC(nd6.lenerr); -- ND6_STATS_INC(nd6.drop); -- return; -- } -- -- lladdr_opt = (struct lladdr_option *)((u8_t*)p->payload + sizeof(struct na_header)); -- -- if (p->len < (sizeof(struct na_header) + (lladdr_opt->length << 3))) { -- /* @todo debug message */ -- pbuf_free(p); -- ND6_STATS_INC(nd6.lenerr); -- ND6_STATS_INC(nd6.drop); -- return; -- } -- -- MEMCPY(neighbor_cache[i].lladdr, lladdr_opt->addr, inp->hwaddr_len); -- } -- -- neighbor_cache[i].netif = inp; -- neighbor_cache[i].state = ND6_REACHABLE; -- neighbor_cache[i].counter.reachable_time = reachable_time; -- -- /* Send queued packets, if any. */ -- if (neighbor_cache[i].q != NULL) { -- nd6_send_q(i); -- } -- } -- -- break; /* ICMP6_TYPE_NA */ -- } -- case ICMP6_TYPE_NS: /* Neighbor solicitation. */ -- { -- struct ns_header *ns_hdr; -- struct lladdr_option *lladdr_opt; -- ip6_addr_t target_address; -- u8_t accepted; -- -- /* Check that ns header fits in packet. */ -- if (p->len < sizeof(struct ns_header)) { -- /* @todo debug message */ -- pbuf_free(p); -- ND6_STATS_INC(nd6.lenerr); -- ND6_STATS_INC(nd6.drop); -- return; -- } -- -- ns_hdr = (struct ns_header *)p->payload; -- -- /* Create an aligned, zoned copy of the target address. */ -- ip6_addr_copy_from_packed(target_address, ns_hdr->target_address); -- ip6_addr_assign_zone(&target_address, IP6_UNICAST, inp); -- -- /* Check a subset of the other RFC 4861 Sec. 7.1.1 requirements. */ -- if (IP6H_HOPLIM(ip6_current_header()) != ND6_HOPLIM || ns_hdr->code != 0 || -- ip6_addr_ismulticast(&target_address)) { -- pbuf_free(p); -- ND6_STATS_INC(nd6.proterr); -- ND6_STATS_INC(nd6.drop); -- return; -- } -- -- /* @todo RFC MUST: all included options have a length greater than zero */ -- /* @todo RFC MUST: if IP source is 'any', destination is solicited-node multicast address */ -- /* @todo RFC MUST: if IP source is 'any', there is no source LL address option */ -- -- /* Check if there is a link-layer address provided. Only point to it if in this buffer. */ -- if (p->len >= (sizeof(struct ns_header) + 2)) { -- lladdr_opt = (struct lladdr_option *)((u8_t*)p->payload + sizeof(struct ns_header)); -- if (p->len < (sizeof(struct ns_header) + (lladdr_opt->length << 3))) { -- lladdr_opt = NULL; -- } -- } else { -- lladdr_opt = NULL; -- } -- -- /* Check if the target address is configured on the receiving netif. */ -- accepted = 0; -- for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; ++i) { -- if ((ip6_addr_isvalid(netif_ip6_addr_state(inp, i)) || -- (ip6_addr_istentative(netif_ip6_addr_state(inp, i)) && -- ip6_addr_isany(ip6_current_src_addr()))) && -- ip6_addr_cmp(&target_address, netif_ip6_addr(inp, i))) { -- accepted = 1; -- break; -- } -- } -- -- /* NS not for us? */ -- if (!accepted) { -- pbuf_free(p); -- return; -- } -- -- /* Check for ANY address in src (DAD algorithm). */ -- if (ip6_addr_isany(ip6_current_src_addr())) { -- /* Sender is validating this address. */ -- for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; ++i) { -- if (!ip6_addr_isinvalid(netif_ip6_addr_state(inp, i)) && -- ip6_addr_cmp(&target_address, netif_ip6_addr(inp, i))) { -- /* Send a NA back so that the sender does not use this address. */ -- nd6_send_na(inp, netif_ip6_addr(inp, i), ND6_FLAG_OVERRIDE | ND6_SEND_FLAG_ALLNODES_DEST); -- if (ip6_addr_istentative(netif_ip6_addr_state(inp, i))) { -- /* We shouldn't use this address either. */ -- nd6_duplicate_addr_detected(inp, i); -- } -- } -- } -- } else { -- /* Sender is trying to resolve our address. */ -- /* Verify that they included their own link-layer address. */ -- if (lladdr_opt == NULL) { -- /* Not a valid message. */ -- pbuf_free(p); -- ND6_STATS_INC(nd6.proterr); -- ND6_STATS_INC(nd6.drop); -- return; -- } -- -- i = nd6_find_neighbor_cache_entry(ip6_current_src_addr()); -- if (i>= 0) { -- /* We already have a record for the solicitor. */ -- if (neighbor_cache[i].state == ND6_INCOMPLETE) { -- neighbor_cache[i].netif = inp; -- MEMCPY(neighbor_cache[i].lladdr, lladdr_opt->addr, inp->hwaddr_len); -- -- /* Delay probe in case we get confirmation of reachability from upper layer (TCP). */ -- neighbor_cache[i].state = ND6_DELAY; -- neighbor_cache[i].counter.delay_time = LWIP_ND6_DELAY_FIRST_PROBE_TIME / ND6_TMR_INTERVAL; -- } -- } else { -- /* Add their IPv6 address and link-layer address to neighbor cache. -- * We will need it at least to send a unicast NA message, but most -- * likely we will also be communicating with this node soon. */ -- i = nd6_new_neighbor_cache_entry(); -- if (i < 0) { -- /* We couldn't assign a cache entry for this neighbor. -- * we won't be able to reply. drop it. */ -- pbuf_free(p); -- ND6_STATS_INC(nd6.memerr); -- return; -- } -- neighbor_cache[i].netif = inp; -- MEMCPY(neighbor_cache[i].lladdr, lladdr_opt->addr, inp->hwaddr_len); -- ip6_addr_set(&(neighbor_cache[i].next_hop_address), ip6_current_src_addr()); -- -- /* Receiving a message does not prove reachability: only in one direction. -- * Delay probe in case we get confirmation of reachability from upper layer (TCP). */ -- neighbor_cache[i].state = ND6_DELAY; -- neighbor_cache[i].counter.delay_time = LWIP_ND6_DELAY_FIRST_PROBE_TIME / ND6_TMR_INTERVAL; -- } -- -- /* Send back a NA for us. Allocate the reply pbuf. */ -- nd6_send_na(inp, &target_address, ND6_FLAG_SOLICITED | ND6_FLAG_OVERRIDE); -- } -- -- break; /* ICMP6_TYPE_NS */ -- } -- case ICMP6_TYPE_RA: /* Router Advertisement. */ -- { -- struct ra_header *ra_hdr; -- u8_t *buffer; /* Used to copy options. */ -- u16_t offset; --#if LWIP_ND6_RDNSS_MAX_DNS_SERVERS -- /* There can be multiple RDNSS options per RA */ -- u8_t rdnss_server_idx = 0; --#endif /* LWIP_ND6_RDNSS_MAX_DNS_SERVERS */ -- -- /* Check that RA header fits in packet. */ -- if (p->len < sizeof(struct ra_header)) { -- /* @todo debug message */ -- pbuf_free(p); -- ND6_STATS_INC(nd6.lenerr); -- ND6_STATS_INC(nd6.drop); -- return; -- } -- -- ra_hdr = (struct ra_header *)p->payload; -- -- /* Check a subset of the other RFC 4861 Sec. 6.1.2 requirements. */ -- if (!ip6_addr_islinklocal(ip6_current_src_addr()) || -- IP6H_HOPLIM(ip6_current_header()) != ND6_HOPLIM || ra_hdr->code != 0) { -- pbuf_free(p); -- ND6_STATS_INC(nd6.proterr); -- ND6_STATS_INC(nd6.drop); -- return; -- } -- -- /* @todo RFC MUST: all included options have a length greater than zero */ -- -- /* If we are sending RS messages, stop. */ --#if LWIP_IPV6_SEND_ROUTER_SOLICIT -- /* ensure at least one solicitation is sent (see RFC 4861, ch. 6.3.7) */ -- if ((inp->rs_count < LWIP_ND6_MAX_MULTICAST_SOLICIT) || -- (nd6_send_rs(inp) == ERR_OK)) { -- inp->rs_count = 0; -- } else { -- inp->rs_count = 1; -- } --#endif /* LWIP_IPV6_SEND_ROUTER_SOLICIT */ -- -- /* Get the matching default router entry. */ -- i = nd6_get_router(ip6_current_src_addr(), inp); -- if (i < 0) { -- /* Create a new router entry. */ -- i = nd6_new_router(ip6_current_src_addr(), inp); -- } -- -- if (i < 0) { -- /* Could not create a new router entry. */ -- pbuf_free(p); -- ND6_STATS_INC(nd6.memerr); -- return; -- } -- -- /* Re-set invalidation timer. */ -- default_router_list[i].invalidation_timer = lwip_htons(ra_hdr->router_lifetime); -- -- /* Re-set default timer values. */ --#if LWIP_ND6_ALLOW_RA_UPDATES -- if (ra_hdr->retrans_timer > 0) { -- retrans_timer = lwip_htonl(ra_hdr->retrans_timer); -- } -- if (ra_hdr->reachable_time > 0) { -- reachable_time = lwip_htonl(ra_hdr->reachable_time); -- } --#endif /* LWIP_ND6_ALLOW_RA_UPDATES */ -- -- /* @todo set default hop limit... */ -- /* ra_hdr->current_hop_limit;*/ -- -- /* Update flags in local entry (incl. preference). */ -- default_router_list[i].flags = ra_hdr->flags; -- --#if LWIP_IPV6_DHCP6 -- /* Trigger DHCPv6 if enabled */ -- dhcp6_nd6_ra_trigger(inp, ra_hdr->flags & ND6_RA_FLAG_MANAGED_ADDR_CONFIG, -- ra_hdr->flags & ND6_RA_FLAG_OTHER_CONFIG); --#endif -- -- /* Offset to options. */ -- offset = sizeof(struct ra_header); -- -- /* Process each option. */ -- while ((p->tot_len - offset) >= 2) { -- u8_t option_type; -- u16_t option_len; -- int option_len8 = pbuf_try_get_at(p, offset + 1); -- if (option_len8 <= 0) { -- /* read beyond end or zero length */ -- goto lenerr_drop_free_return; -- } -- option_len = ((u8_t)option_len8) << 3; -- if (option_len > p->tot_len - offset) { -- /* short packet (option does not fit in) */ -- goto lenerr_drop_free_return; -- } -- if (p->len == p->tot_len) { -- /* no need to copy from contiguous pbuf */ -- buffer = &((u8_t*)p->payload)[offset]; -- } else { -- /* check if this option fits into our buffer */ -- if (option_len > sizeof(nd6_ra_buffer)) { -- option_type = pbuf_get_at(p, offset); -- /* invalid option length */ -- if (option_type != ND6_OPTION_TYPE_RDNSS) { -- goto lenerr_drop_free_return; -- } -- /* we allow RDNSS option to be longer - we'll just drop some servers */ -- option_len = sizeof(nd6_ra_buffer); -- } -- buffer = (u8_t*)&nd6_ra_buffer; -- option_len = pbuf_copy_partial(p, &nd6_ra_buffer, option_len, offset); -- } -- option_type = buffer[0]; -- switch (option_type) { -- case ND6_OPTION_TYPE_SOURCE_LLADDR: -- { -- struct lladdr_option *lladdr_opt; -- if (option_len < sizeof(struct lladdr_option)) { -- goto lenerr_drop_free_return; -- } -- lladdr_opt = (struct lladdr_option *)buffer; -- if ((default_router_list[i].neighbor_entry != NULL) && -- (default_router_list[i].neighbor_entry->state == ND6_INCOMPLETE)) { -- SMEMCPY(default_router_list[i].neighbor_entry->lladdr, lladdr_opt->addr, inp->hwaddr_len); -- default_router_list[i].neighbor_entry->state = ND6_REACHABLE; -- default_router_list[i].neighbor_entry->counter.reachable_time = reachable_time; -- } -- break; -- } -- case ND6_OPTION_TYPE_MTU: -- { -- struct mtu_option *mtu_opt; -- u32_t mtu32; -- if (option_len < sizeof(struct mtu_option)) { -- goto lenerr_drop_free_return; -- } -- mtu_opt = (struct mtu_option *)buffer; -- mtu32 = lwip_htonl(mtu_opt->mtu); -- if ((mtu32 >= 1280) && (mtu32 <= 0xffff)) { --#if LWIP_ND6_ALLOW_RA_UPDATES -- if (inp->mtu) { -- /* don't set the mtu for IPv6 higher than the netif driver supports */ -- inp->mtu6 = LWIP_MIN(inp->mtu, (u16_t)mtu32); -- } else { -- inp->mtu6 = (u16_t)mtu32; -- } --#endif /* LWIP_ND6_ALLOW_RA_UPDATES */ -- } -- break; -- } -- case ND6_OPTION_TYPE_PREFIX_INFO: -- { -- struct prefix_option *prefix_opt; -- ip6_addr_t prefix_addr; -- if (option_len < sizeof(struct prefix_option)) { -- goto lenerr_drop_free_return; -- } -- -- prefix_opt = (struct prefix_option *)buffer; -- -- /* Get a memory-aligned copy of the prefix. */ -- ip6_addr_copy_from_packed(prefix_addr, prefix_opt->prefix); -- ip6_addr_assign_zone(&prefix_addr, IP6_UNICAST, inp); -- -- if (!ip6_addr_islinklocal(&prefix_addr)) { -- if ((prefix_opt->flags & ND6_PREFIX_FLAG_ON_LINK) && -- (prefix_opt->prefix_length == 64)) { -- /* Add to on-link prefix list. */ -- u32_t valid_life; -- s8_t prefix; -- -- valid_life = lwip_htonl(prefix_opt->valid_lifetime); -- -- /* find cache entry for this prefix. */ -- prefix = nd6_get_onlink_prefix(&prefix_addr, inp); -- if (prefix < 0 && valid_life > 0) { -- /* Create a new cache entry. */ -- prefix = nd6_new_onlink_prefix(&prefix_addr, inp); -- } -- if (prefix >= 0) { -- prefix_list[prefix].invalidation_timer = valid_life; -- } -- } --#if LWIP_IPV6_AUTOCONFIG -- if (prefix_opt->flags & ND6_PREFIX_FLAG_AUTONOMOUS) { -- /* Perform processing for autoconfiguration. */ -- nd6_process_autoconfig_prefix(inp, prefix_opt, &prefix_addr); -- } --#endif /* LWIP_IPV6_AUTOCONFIG */ -- } -- -- break; -- } -- case ND6_OPTION_TYPE_ROUTE_INFO: -- /* @todo implement preferred routes. -- struct route_option * route_opt; -- route_opt = (struct route_option *)buffer;*/ -- -- break; --#if LWIP_ND6_RDNSS_MAX_DNS_SERVERS -- case ND6_OPTION_TYPE_RDNSS: -- { -- u8_t num, n; -- u16_t copy_offset = offset + SIZEOF_RDNSS_OPTION_BASE; -- struct rdnss_option * rdnss_opt; -- if (option_len < SIZEOF_RDNSS_OPTION_BASE) { -- goto lenerr_drop_free_return; -- } -- -- rdnss_opt = (struct rdnss_option *)buffer; -- num = (rdnss_opt->length - 1) / 2; -- for (n = 0; (rdnss_server_idx < DNS_MAX_SERVERS) && (n < num); n++) { -- ip_addr_t rdnss_address; -- -- /* Copy directly from pbuf to get an aligned, zoned copy of the prefix. */ -- if (pbuf_copy_partial(p, &rdnss_address, sizeof(ip6_addr_p_t), copy_offset) == sizeof(ip6_addr_p_t)) { -- IP_SET_TYPE_VAL(rdnss_address, IPADDR_TYPE_V6); -- ip6_addr_assign_zone(ip_2_ip6(&rdnss_address), IP6_UNKNOWN, inp); -- -- if (htonl(rdnss_opt->lifetime) > 0) { -- /* TODO implement Lifetime > 0 */ -- dns_setserver(rdnss_server_idx++, &rdnss_address); -- } else { -- /* TODO implement DNS removal in dns.c */ -- u8_t s; -- for (s = 0; s < DNS_MAX_SERVERS; s++) { -- const ip_addr_t *addr = dns_getserver(s); -- if(ip_addr_cmp(addr, &rdnss_address)) { -- dns_setserver(s, NULL); -- } -- } -- } -- } -- } -- break; -- } --#endif /* LWIP_ND6_RDNSS_MAX_DNS_SERVERS */ -- default: -- /* Unrecognized option, abort. */ -- ND6_STATS_INC(nd6.proterr); -- break; -- } -- /* option length is checked earlier to be non-zero to make sure loop ends */ -- offset += 8 * (u8_t)option_len8; -- } -- -- break; /* ICMP6_TYPE_RA */ -- } -- case ICMP6_TYPE_RD: /* Redirect */ -- { -- struct redirect_header *redir_hdr; -- struct lladdr_option *lladdr_opt; -- ip6_addr_t destination_address, target_address; -- -- /* Check that Redir header fits in packet. */ -- if (p->len < sizeof(struct redirect_header)) { -- /* @todo debug message */ -- pbuf_free(p); -- ND6_STATS_INC(nd6.lenerr); -- ND6_STATS_INC(nd6.drop); -- return; -- } -- -- redir_hdr = (struct redirect_header *)p->payload; -- -- /* Create an aligned, zoned copy of the destination address. */ -- ip6_addr_copy_from_packed(destination_address, redir_hdr->destination_address); -- ip6_addr_assign_zone(&destination_address, IP6_UNICAST, inp); -- -- /* Check a subset of the other RFC 4861 Sec. 8.1 requirements. */ -- if (!ip6_addr_islinklocal(ip6_current_src_addr()) || -- IP6H_HOPLIM(ip6_current_header()) != ND6_HOPLIM || -- redir_hdr->code != 0 || ip6_addr_ismulticast(&destination_address)) { -- pbuf_free(p); -- ND6_STATS_INC(nd6.proterr); -- ND6_STATS_INC(nd6.drop); -- return; -- } -- -- /* @todo RFC MUST: IP source address equals first-hop router for destination_address */ -- /* @todo RFC MUST: ICMP target address is either link-local address or same as destination_address */ -- /* @todo RFC MUST: all included options have a length greater than zero */ -- -- if (p->len >= (sizeof(struct redirect_header) + 2)) { -- lladdr_opt = (struct lladdr_option *)((u8_t*)p->payload + sizeof(struct redirect_header)); -- if (p->len < (sizeof(struct redirect_header) + (lladdr_opt->length << 3))) { -- lladdr_opt = NULL; -- } -- } else { -- lladdr_opt = NULL; -- } -- -- /* Find dest address in cache */ -- dest_idx = nd6_find_destination_cache_entry(&destination_address); -- if (dest_idx < 0) { -- /* Destination not in cache, drop packet. */ -- pbuf_free(p); -- return; -- } -- -- /* Create an aligned, zoned copy of the target address. */ -- ip6_addr_copy_from_packed(target_address, redir_hdr->target_address); -- ip6_addr_assign_zone(&target_address, IP6_UNICAST, inp); -- -- /* Set the new target address. */ -- ip6_addr_copy(destination_cache[dest_idx].next_hop_addr, target_address); -- -- /* If Link-layer address of other router is given, try to add to neighbor cache. */ -- if (lladdr_opt != NULL) { -- if (lladdr_opt->type == ND6_OPTION_TYPE_TARGET_LLADDR) { -- i = nd6_find_neighbor_cache_entry(&target_address); -- if (i < 0) { -- i = nd6_new_neighbor_cache_entry(); -- if (i >= 0) { -- neighbor_cache[i].netif = inp; -- MEMCPY(neighbor_cache[i].lladdr, lladdr_opt->addr, inp->hwaddr_len); -- ip6_addr_copy(neighbor_cache[i].next_hop_address, target_address); -- -- /* Receiving a message does not prove reachability: only in one direction. -- * Delay probe in case we get confirmation of reachability from upper layer (TCP). */ -- neighbor_cache[i].state = ND6_DELAY; -- neighbor_cache[i].counter.delay_time = LWIP_ND6_DELAY_FIRST_PROBE_TIME / ND6_TMR_INTERVAL; -- } -- } -- if (i >= 0) { -- if (neighbor_cache[i].state == ND6_INCOMPLETE) { -- MEMCPY(neighbor_cache[i].lladdr, lladdr_opt->addr, inp->hwaddr_len); -- /* Receiving a message does not prove reachability: only in one direction. -- * Delay probe in case we get confirmation of reachability from upper layer (TCP). */ -- neighbor_cache[i].state = ND6_DELAY; -- neighbor_cache[i].counter.delay_time = LWIP_ND6_DELAY_FIRST_PROBE_TIME / ND6_TMR_INTERVAL; -- } -- } -- } -- } -- break; /* ICMP6_TYPE_RD */ -- } -- case ICMP6_TYPE_PTB: /* Packet too big */ -- { -- struct icmp6_hdr *icmp6hdr; /* Packet too big message */ -- struct ip6_hdr *ip6hdr; /* IPv6 header of the packet which caused the error */ -- u32_t pmtu; -- ip6_addr_t destination_address; -- -- /* Check that ICMPv6 header + IPv6 header fit in payload */ -- if (p->len < (sizeof(struct icmp6_hdr) + IP6_HLEN)) { -- /* drop short packets */ -- pbuf_free(p); -- ND6_STATS_INC(nd6.lenerr); -- ND6_STATS_INC(nd6.drop); -- return; -- } -- -- icmp6hdr = (struct icmp6_hdr *)p->payload; -- ip6hdr = (struct ip6_hdr *)((u8_t*)p->payload + sizeof(struct icmp6_hdr)); -- -- /* Create an aligned, zoned copy of the destination address. */ -- ip6_addr_copy_from_packed(destination_address, ip6hdr->dest); -- ip6_addr_assign_zone(&destination_address, IP6_UNKNOWN, inp); -- -- /* Look for entry in destination cache. */ -- dest_idx = nd6_find_destination_cache_entry(&destination_address); -- if (dest_idx < 0) { -- /* Destination not in cache, drop packet. */ -- pbuf_free(p); -- return; -- } -- -- /* Change the Path MTU. */ -- pmtu = lwip_htonl(icmp6hdr->data); -- destination_cache[dest_idx].pmtu = (u16_t)LWIP_MIN(pmtu, 0xFFFF); -- -- break; /* ICMP6_TYPE_PTB */ -- } -- -- default: -- ND6_STATS_INC(nd6.proterr); -- ND6_STATS_INC(nd6.drop); -- break; /* default */ -- } -- -- pbuf_free(p); -- return; --lenerr_drop_free_return: -- ND6_STATS_INC(nd6.lenerr); -- ND6_STATS_INC(nd6.drop); -- pbuf_free(p); --} -- -- --/** -- * Periodic timer for Neighbor discovery functions: -- * -- * - Update neighbor reachability states -- * - Update destination cache entries age -- * - Update invalidation timers of default routers and on-link prefixes -- * - Update lifetimes of our addresses -- * - Perform duplicate address detection (DAD) for our addresses -- * - Send router solicitations -- */ --void --nd6_tmr(void) --{ -- s8_t i; -- struct netif *netif; -- -- /* Process neighbor entries. */ -- for (i = 0; i < LWIP_ND6_NUM_NEIGHBORS; i++) { -- switch (neighbor_cache[i].state) { -- case ND6_INCOMPLETE: -- if ((neighbor_cache[i].counter.probes_sent >= LWIP_ND6_MAX_MULTICAST_SOLICIT) && -- (!neighbor_cache[i].isrouter)) { -- /* Retries exceeded. */ -- nd6_free_neighbor_cache_entry(i); -- } else { -- /* Send a NS for this entry. */ -- neighbor_cache[i].counter.probes_sent++; -- nd6_send_neighbor_cache_probe(&neighbor_cache[i], ND6_SEND_FLAG_MULTICAST_DEST); -- } -- break; -- case ND6_REACHABLE: -- /* Send queued packets, if any are left. Should have been sent already. */ -- if (neighbor_cache[i].q != NULL) { -- nd6_send_q(i); -- } -- if (neighbor_cache[i].counter.reachable_time <= ND6_TMR_INTERVAL) { -- /* Change to stale state. */ -- neighbor_cache[i].state = ND6_STALE; -- neighbor_cache[i].counter.stale_time = 0; -- } else { -- neighbor_cache[i].counter.reachable_time -= ND6_TMR_INTERVAL; -- } -- break; -- case ND6_STALE: -- neighbor_cache[i].counter.stale_time++; -- break; -- case ND6_DELAY: -- if (neighbor_cache[i].counter.delay_time <= 1) { -- /* Change to PROBE state. */ -- neighbor_cache[i].state = ND6_PROBE; -- neighbor_cache[i].counter.probes_sent = 0; -- } else { -- neighbor_cache[i].counter.delay_time--; -- } -- break; -- case ND6_PROBE: -- if ((neighbor_cache[i].counter.probes_sent >= LWIP_ND6_MAX_MULTICAST_SOLICIT) && -- (!neighbor_cache[i].isrouter)) { -- /* Retries exceeded. */ -- nd6_free_neighbor_cache_entry(i); -- } else { -- /* Send a NS for this entry. */ -- neighbor_cache[i].counter.probes_sent++; -- nd6_send_neighbor_cache_probe(&neighbor_cache[i], 0); -- } -- break; -- case ND6_NO_ENTRY: -- default: -- /* Do nothing. */ -- break; -- } -- } -- -- /* Process destination entries. */ -- for (i = 0; i < LWIP_ND6_NUM_DESTINATIONS; i++) { -- destination_cache[i].age++; -- } -- -- /* Process router entries. */ -- for (i = 0; i < LWIP_ND6_NUM_ROUTERS; i++) { -- if (default_router_list[i].neighbor_entry != NULL) { -- /* Active entry. */ -- if (default_router_list[i].invalidation_timer <= ND6_TMR_INTERVAL / 1000) { -- /* No more than 1 second remaining. Clear this entry. Also clear any of -- * its destination cache entries, as per RFC 4861 Sec. 5.3 and 6.3.5. */ -- s8_t j; -- for (j = 0; j < LWIP_ND6_NUM_DESTINATIONS; j++) { -- if (ip6_addr_cmp(&destination_cache[j].next_hop_addr, -- &default_router_list[i].neighbor_entry->next_hop_address)) { -- ip6_addr_set_any(&destination_cache[j].destination_addr); -- } -- } -- default_router_list[i].neighbor_entry->isrouter = 0; -- default_router_list[i].neighbor_entry = NULL; -- default_router_list[i].invalidation_timer = 0; -- default_router_list[i].flags = 0; -- } else { -- default_router_list[i].invalidation_timer -= ND6_TMR_INTERVAL / 1000; -- } -- } -- } -- -- /* Process prefix entries. */ -- for (i = 0; i < LWIP_ND6_NUM_PREFIXES; i++) { -- if (prefix_list[i].netif != NULL) { -- if (prefix_list[i].invalidation_timer <= ND6_TMR_INTERVAL / 1000) { -- /* Entry timed out, remove it */ -- prefix_list[i].invalidation_timer = 0; -- prefix_list[i].netif = NULL; -- } else { -- prefix_list[i].invalidation_timer -= ND6_TMR_INTERVAL / 1000; -- } -- } -- } -- -- /* Process our own addresses, updating address lifetimes and/or DAD state. */ -- NETIF_FOREACH(netif) { -- for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; ++i) { -- u8_t addr_state; --#if LWIP_IPV6_ADDRESS_LIFETIMES -- /* Step 1: update address lifetimes (valid and preferred). */ -- addr_state = netif_ip6_addr_state(netif, i); -- /* RFC 4862 is not entirely clear as to whether address lifetimes affect -- * tentative addresses, and is even less clear as to what should happen -- * with duplicate addresses. We choose to track and update lifetimes for -- * both those types, although for different reasons: -- * - for tentative addresses, the line of thought of Sec. 5.7 combined -- * with the potentially long period that an address may be in tentative -- * state (due to the interface being down) suggests that lifetimes -- * should be independent of external factors which would include DAD; -- * - for duplicate addresses, retiring them early could result in a new -- * but unwanted attempt at marking them as valid, while retiring them -- * late/never could clog up address slots on the netif. -- * As a result, we may end up expiring addresses of either type here. -- */ -- if (!ip6_addr_isinvalid(addr_state) && -- !netif_ip6_addr_isstatic(netif, i)) { -- u32_t life = netif_ip6_addr_valid_life(netif, i); -- if (life <= ND6_TMR_INTERVAL / 1000) { -- /* The address has expired. */ -- netif_ip6_addr_set_valid_life(netif, i, 0); -- netif_ip6_addr_set_pref_life(netif, i, 0); -- netif_ip6_addr_set_state(netif, i, IP6_ADDR_INVALID); -- } else { -- if (!ip6_addr_life_isinfinite(life)) { -- life -= ND6_TMR_INTERVAL / 1000; -- LWIP_ASSERT("bad valid lifetime", life != IP6_ADDR_LIFE_STATIC); -- netif_ip6_addr_set_valid_life(netif, i, life); -- } -- /* The address is still here. Update the preferred lifetime too. */ -- life = netif_ip6_addr_pref_life(netif, i); -- if (life <= ND6_TMR_INTERVAL / 1000) { -- /* This case must also trigger if 'life' was already zero, so as to -- * deal correctly with advertised preferred-lifetime reductions. */ -- netif_ip6_addr_set_pref_life(netif, i, 0); -- if (addr_state == IP6_ADDR_PREFERRED) -- netif_ip6_addr_set_state(netif, i, IP6_ADDR_DEPRECATED); -- } else if (!ip6_addr_life_isinfinite(life)) { -- life -= ND6_TMR_INTERVAL / 1000; -- netif_ip6_addr_set_pref_life(netif, i, life); -- } -- } -- } -- /* The address state may now have changed, so reobtain it next. */ --#endif /* LWIP_IPV6_ADDRESS_LIFETIMES */ -- /* Step 2: update DAD state. */ -- addr_state = netif_ip6_addr_state(netif, i); -- if (ip6_addr_istentative(addr_state)) { -- if ((addr_state & IP6_ADDR_TENTATIVE_COUNT_MASK) >= LWIP_IPV6_DUP_DETECT_ATTEMPTS) { -- /* No NA received in response. Mark address as valid. For dynamic -- * addresses with an expired preferred lifetime, the state is set to -- * deprecated right away. That should almost never happen, though. */ -- addr_state = IP6_ADDR_PREFERRED; --#if LWIP_IPV6_ADDRESS_LIFETIMES -- if (!netif_ip6_addr_isstatic(netif, i) && -- netif_ip6_addr_pref_life(netif, i) == 0) { -- addr_state = IP6_ADDR_DEPRECATED; -- } --#endif /* LWIP_IPV6_ADDRESS_LIFETIMES */ -- netif_ip6_addr_set_state(netif, i, addr_state); -- } else if (netif_is_up(netif) && netif_is_link_up(netif)) { -- /* tentative: set next state by increasing by one */ -- netif_ip6_addr_set_state(netif, i, addr_state + 1); -- /* Send a NS for this address. Use the unspecified address as source -- * address in all cases (RFC 4862 Sec. 5.4.2), not in the least -- * because as it is, we only consider multicast replies for DAD. */ -- nd6_send_ns(netif, netif_ip6_addr(netif, i), -- ND6_SEND_FLAG_MULTICAST_DEST | ND6_SEND_FLAG_ANY_SRC); -- } -- } -- } -- } -- --#if LWIP_IPV6_SEND_ROUTER_SOLICIT -- /* Send router solicitation messages, if necessary. */ -- if (!nd6_tmr_rs_reduction) { -- nd6_tmr_rs_reduction = (ND6_RTR_SOLICITATION_INTERVAL / ND6_TMR_INTERVAL) - 1; -- NETIF_FOREACH(netif) { -- if ((netif->rs_count > 0) && netif_is_up(netif) && -- netif_is_link_up(netif) && -- !ip6_addr_isinvalid(netif_ip6_addr_state(netif, 0)) && -- !ip6_addr_isduplicated(netif_ip6_addr_state(netif, 0))) { -- if (nd6_send_rs(netif) == ERR_OK) { -- netif->rs_count--; -- } -- } -- } -- } else { -- nd6_tmr_rs_reduction--; -- } --#endif /* LWIP_IPV6_SEND_ROUTER_SOLICIT */ -- --} -- --/** Send a neighbor solicitation message for a specific neighbor cache entry -- * -- * @param entry the neightbor cache entry for wich to send the message -- * @param flags one of ND6_SEND_FLAG_* -- */ --static void --nd6_send_neighbor_cache_probe(struct nd6_neighbor_cache_entry *entry, u8_t flags) --{ -- nd6_send_ns(entry->netif, &entry->next_hop_address, flags); --} -- --/** -- * Send a neighbor solicitation message -- * -- * @param netif the netif on which to send the message -- * @param target_addr the IPv6 target address for the ND message -- * @param flags one of ND6_SEND_FLAG_* -- */ --static void --nd6_send_ns(struct netif *netif, const ip6_addr_t *target_addr, u8_t flags) --{ -- struct ns_header *ns_hdr; -- struct pbuf *p; -- const ip6_addr_t *src_addr; -- u16_t lladdr_opt_len; -- -- LWIP_ASSERT("target address is required", target_addr != NULL); -- -- if (!(flags & ND6_SEND_FLAG_ANY_SRC) && -- ip6_addr_isvalid(netif_ip6_addr_state(netif,0))) { -- /* Use link-local address as source address. */ -- src_addr = netif_ip6_addr(netif, 0); -- /* calculate option length (in 8-byte-blocks) */ -- lladdr_opt_len = ((netif->hwaddr_len + 2) + 7) >> 3; -- } else { -- src_addr = IP6_ADDR_ANY6; -- /* Option "MUST NOT be included when the source IP address is the unspecified address." */ -- lladdr_opt_len = 0; -- } -- -- /* Allocate a packet. */ -- p = pbuf_alloc(PBUF_IP, sizeof(struct ns_header) + (lladdr_opt_len << 3), PBUF_RAM); -- if (p == NULL) { -- ND6_STATS_INC(nd6.memerr); -- return; -- } -- -- /* Set fields. */ -- ns_hdr = (struct ns_header *)p->payload; -- -- ns_hdr->type = ICMP6_TYPE_NS; -- ns_hdr->code = 0; -- ns_hdr->chksum = 0; -- ns_hdr->reserved = 0; -- ip6_addr_copy_to_packed(ns_hdr->target_address, *target_addr); -- -- if (lladdr_opt_len != 0) { -- struct lladdr_option *lladdr_opt = (struct lladdr_option *)((u8_t*)p->payload + sizeof(struct ns_header)); -- lladdr_opt->type = ND6_OPTION_TYPE_SOURCE_LLADDR; -- lladdr_opt->length = (u8_t)lladdr_opt_len; -- SMEMCPY(lladdr_opt->addr, netif->hwaddr, netif->hwaddr_len); -- } -- -- /* Generate the solicited node address for the target address. */ -- if (flags & ND6_SEND_FLAG_MULTICAST_DEST) { -- ip6_addr_set_solicitednode(&multicast_address, target_addr->addr[3]); -- ip6_addr_assign_zone(&multicast_address, IP6_MULTICAST, netif); -- target_addr = &multicast_address; -- } -- --#if CHECKSUM_GEN_ICMP6 -- IF__NETIF_CHECKSUM_ENABLED(netif, NETIF_CHECKSUM_GEN_ICMP6) { -- ns_hdr->chksum = ip6_chksum_pseudo(p, IP6_NEXTH_ICMP6, p->len, src_addr, -- target_addr); -- } --#endif /* CHECKSUM_GEN_ICMP6 */ -- -- /* Send the packet out. */ -- ND6_STATS_INC(nd6.xmit); -- ip6_output_if(p, (src_addr == IP6_ADDR_ANY6) ? NULL : src_addr, target_addr, -- ND6_HOPLIM, 0, IP6_NEXTH_ICMP6, netif); -- pbuf_free(p); --} -- --/** -- * Send a neighbor advertisement message -- * -- * @param netif the netif on which to send the message -- * @param target_addr the IPv6 target address for the ND message -- * @param flags one of ND6_SEND_FLAG_* -- */ --static void --nd6_send_na(struct netif *netif, const ip6_addr_t *target_addr, u8_t flags) --{ -- struct na_header *na_hdr; -- struct lladdr_option *lladdr_opt; -- struct pbuf *p; -- const ip6_addr_t *src_addr; -- const ip6_addr_t *dest_addr; -- u16_t lladdr_opt_len; -- -- LWIP_ASSERT("target address is required", target_addr != NULL); -- -- /* Use link-local address as source address. */ -- /* src_addr = netif_ip6_addr(netif, 0); */ -- /* Use target address as source address. */ -- src_addr = target_addr; -- -- /* Allocate a packet. */ -- lladdr_opt_len = ((netif->hwaddr_len + 2) >> 3) + (((netif->hwaddr_len + 2) & 0x07) ? 1 : 0); -- p = pbuf_alloc(PBUF_IP, sizeof(struct na_header) + (lladdr_opt_len << 3), PBUF_RAM); -- if (p == NULL) { -- ND6_STATS_INC(nd6.memerr); -- return; -- } -- -- /* Set fields. */ -- na_hdr = (struct na_header *)p->payload; -- lladdr_opt = (struct lladdr_option *)((u8_t*)p->payload + sizeof(struct na_header)); -- -- na_hdr->type = ICMP6_TYPE_NA; -- na_hdr->code = 0; -- na_hdr->chksum = 0; -- na_hdr->flags = flags & 0xf0; -- na_hdr->reserved[0] = 0; -- na_hdr->reserved[1] = 0; -- na_hdr->reserved[2] = 0; -- ip6_addr_copy_to_packed(na_hdr->target_address, *target_addr); -- -- lladdr_opt->type = ND6_OPTION_TYPE_TARGET_LLADDR; -- lladdr_opt->length = (u8_t)lladdr_opt_len; -- SMEMCPY(lladdr_opt->addr, netif->hwaddr, netif->hwaddr_len); -- -- /* Generate the solicited node address for the target address. */ -- if (flags & ND6_SEND_FLAG_MULTICAST_DEST) { -- ip6_addr_set_solicitednode(&multicast_address, target_addr->addr[3]); -- ip6_addr_assign_zone(&multicast_address, IP6_MULTICAST, netif); -- dest_addr = &multicast_address; -- } else if (flags & ND6_SEND_FLAG_ALLNODES_DEST) { -- ip6_addr_set_allnodes_linklocal(&multicast_address); -- ip6_addr_assign_zone(&multicast_address, IP6_MULTICAST, netif); -- dest_addr = &multicast_address; -- } else { -- dest_addr = ip6_current_src_addr(); -- } -- --#if CHECKSUM_GEN_ICMP6 -- IF__NETIF_CHECKSUM_ENABLED(netif, NETIF_CHECKSUM_GEN_ICMP6) { -- na_hdr->chksum = ip6_chksum_pseudo(p, IP6_NEXTH_ICMP6, p->len, src_addr, -- dest_addr); -- } --#endif /* CHECKSUM_GEN_ICMP6 */ -- -- /* Send the packet out. */ -- ND6_STATS_INC(nd6.xmit); -- ip6_output_if(p, src_addr, dest_addr, -- ND6_HOPLIM, 0, IP6_NEXTH_ICMP6, netif); -- pbuf_free(p); --} -- --#if LWIP_IPV6_SEND_ROUTER_SOLICIT --/** -- * Send a router solicitation message -- * -- * @param netif the netif on which to send the message -- */ --static err_t --nd6_send_rs(struct netif *netif) --{ -- struct rs_header *rs_hdr; -- struct lladdr_option *lladdr_opt; -- struct pbuf *p; -- const ip6_addr_t *src_addr; -- err_t err; -- u16_t lladdr_opt_len = 0; -- -- /* Link-local source address, or unspecified address? */ -- if (ip6_addr_isvalid(netif_ip6_addr_state(netif, 0))) { -- src_addr = netif_ip6_addr(netif, 0); -- } else { -- src_addr = IP6_ADDR_ANY6; -- } -- -- /* Generate the all routers target address. */ -- ip6_addr_set_allrouters_linklocal(&multicast_address); -- ip6_addr_assign_zone(&multicast_address, IP6_MULTICAST, netif); -- -- /* Allocate a packet. */ -- if (src_addr != IP6_ADDR_ANY6) { -- lladdr_opt_len = ((netif->hwaddr_len + 2) >> 3) + (((netif->hwaddr_len + 2) & 0x07) ? 1 : 0); -- } -- p = pbuf_alloc(PBUF_IP, sizeof(struct rs_header) + (lladdr_opt_len << 3), PBUF_RAM); -- if (p == NULL) { -- ND6_STATS_INC(nd6.memerr); -- return ERR_BUF; -- } -- -- /* Set fields. */ -- rs_hdr = (struct rs_header *)p->payload; -- -- rs_hdr->type = ICMP6_TYPE_RS; -- rs_hdr->code = 0; -- rs_hdr->chksum = 0; -- rs_hdr->reserved = 0; -- -- if (src_addr != IP6_ADDR_ANY6) { -- /* Include our hw address. */ -- lladdr_opt = (struct lladdr_option *)((u8_t*)p->payload + sizeof(struct rs_header)); -- lladdr_opt->type = ND6_OPTION_TYPE_SOURCE_LLADDR; -- lladdr_opt->length = (u8_t)lladdr_opt_len; -- SMEMCPY(lladdr_opt->addr, netif->hwaddr, netif->hwaddr_len); -- } -- --#if CHECKSUM_GEN_ICMP6 -- IF__NETIF_CHECKSUM_ENABLED(netif, NETIF_CHECKSUM_GEN_ICMP6) { -- rs_hdr->chksum = ip6_chksum_pseudo(p, IP6_NEXTH_ICMP6, p->len, src_addr, -- &multicast_address); -- } --#endif /* CHECKSUM_GEN_ICMP6 */ -- -- /* Send the packet out. */ -- ND6_STATS_INC(nd6.xmit); -- -- err = ip6_output_if(p, (src_addr == IP6_ADDR_ANY6) ? NULL : src_addr, &multicast_address, -- ND6_HOPLIM, 0, IP6_NEXTH_ICMP6, netif); -- pbuf_free(p); -- -- return err; --} --#endif /* LWIP_IPV6_SEND_ROUTER_SOLICIT */ -- --/** -- * Search for a neighbor cache entry -- * -- * @param ip6addr the IPv6 address of the neighbor -- * @return The neighbor cache entry index that matched, -1 if no -- * entry is found -- */ --static s8_t --nd6_find_neighbor_cache_entry(const ip6_addr_t *ip6addr) --{ -- s8_t i; -- for (i = 0; i < LWIP_ND6_NUM_NEIGHBORS; i++) { -- if (ip6_addr_cmp(ip6addr, &(neighbor_cache[i].next_hop_address))) { -- return i; -- } -- } -- return -1; --} -- --/** -- * Create a new neighbor cache entry. -- * -- * If no unused entry is found, will try to recycle an old entry -- * according to ad-hoc "age" heuristic. -- * -- * @return The neighbor cache entry index that was created, -1 if no -- * entry could be created -- */ --static s8_t --nd6_new_neighbor_cache_entry(void) --{ -- s8_t i; -- s8_t j; -- u32_t time; -- -- -- /* First, try to find an empty entry. */ -- for (i = 0; i < LWIP_ND6_NUM_NEIGHBORS; i++) { -- if (neighbor_cache[i].state == ND6_NO_ENTRY) { -- return i; -- } -- } -- -- /* We need to recycle an entry. in general, do not recycle if it is a router. */ -- -- /* Next, try to find a Stale entry. */ -- for (i = 0; i < LWIP_ND6_NUM_NEIGHBORS; i++) { -- if ((neighbor_cache[i].state == ND6_STALE) && -- (!neighbor_cache[i].isrouter)) { -- nd6_free_neighbor_cache_entry(i); -- return i; -- } -- } -- -- /* Next, try to find a Probe entry. */ -- for (i = 0; i < LWIP_ND6_NUM_NEIGHBORS; i++) { -- if ((neighbor_cache[i].state == ND6_PROBE) && -- (!neighbor_cache[i].isrouter)) { -- nd6_free_neighbor_cache_entry(i); -- return i; -- } -- } -- -- /* Next, try to find a Delayed entry. */ -- for (i = 0; i < LWIP_ND6_NUM_NEIGHBORS; i++) { -- if ((neighbor_cache[i].state == ND6_DELAY) && -- (!neighbor_cache[i].isrouter)) { -- nd6_free_neighbor_cache_entry(i); -- return i; -- } -- } -- -- /* Next, try to find the oldest reachable entry. */ -- time = 0xfffffffful; -- j = -1; -- for (i = 0; i < LWIP_ND6_NUM_NEIGHBORS; i++) { -- if ((neighbor_cache[i].state == ND6_REACHABLE) && -- (!neighbor_cache[i].isrouter)) { -- if (neighbor_cache[i].counter.reachable_time < time) { -- j = i; -- time = neighbor_cache[i].counter.reachable_time; -- } -- } -- } -- if (j >= 0) { -- nd6_free_neighbor_cache_entry(j); -- return j; -- } -- -- /* Next, find oldest incomplete entry without queued packets. */ -- time = 0; -- j = -1; -- for (i = 0; i < LWIP_ND6_NUM_NEIGHBORS; i++) { -- if ( -- (neighbor_cache[i].q == NULL) && -- (neighbor_cache[i].state == ND6_INCOMPLETE) && -- (!neighbor_cache[i].isrouter)) { -- if (neighbor_cache[i].counter.probes_sent >= time) { -- j = i; -- time = neighbor_cache[i].counter.probes_sent; -- } -- } -- } -- if (j >= 0) { -- nd6_free_neighbor_cache_entry(j); -- return j; -- } -- -- /* Next, find oldest incomplete entry with queued packets. */ -- time = 0; -- j = -1; -- for (i = 0; i < LWIP_ND6_NUM_NEIGHBORS; i++) { -- if ((neighbor_cache[i].state == ND6_INCOMPLETE) && -- (!neighbor_cache[i].isrouter)) { -- if (neighbor_cache[i].counter.probes_sent >= time) { -- j = i; -- time = neighbor_cache[i].counter.probes_sent; -- } -- } -- } -- if (j >= 0) { -- nd6_free_neighbor_cache_entry(j); -- return j; -- } -- -- /* No more entries to try. */ -- return -1; --} -- --/** -- * Will free any resources associated with a neighbor cache -- * entry, and will mark it as unused. -- * -- * @param i the neighbor cache entry index to free -- */ --static void --nd6_free_neighbor_cache_entry(s8_t i) --{ -- if ((i < 0) || (i >= LWIP_ND6_NUM_NEIGHBORS)) { -- return; -- } -- if (neighbor_cache[i].isrouter) { -- /* isrouter needs to be cleared before deleting a neighbor cache entry */ -- return; -- } -- -- /* Free any queued packets. */ -- if (neighbor_cache[i].q != NULL) { -- nd6_free_q(neighbor_cache[i].q); -- neighbor_cache[i].q = NULL; -- } -- -- neighbor_cache[i].state = ND6_NO_ENTRY; -- neighbor_cache[i].isrouter = 0; -- neighbor_cache[i].netif = NULL; -- neighbor_cache[i].counter.reachable_time = 0; -- ip6_addr_set_zero(&(neighbor_cache[i].next_hop_address)); --} -- --/** -- * Search for a destination cache entry -- * -- * @param ip6addr the IPv6 address of the destination -- * @return The destination cache entry index that matched, -1 if no -- * entry is found -- */ --static s16_t --nd6_find_destination_cache_entry(const ip6_addr_t *ip6addr) --{ -- s16_t i; -- -- IP6_ADDR_ZONECHECK(ip6addr); -- -- for (i = 0; i < LWIP_ND6_NUM_DESTINATIONS; i++) { -- if (ip6_addr_cmp(ip6addr, &(destination_cache[i].destination_addr))) { -- return i; -- } -- } -- return -1; --} -- --/** -- * Create a new destination cache entry. If no unused entry is found, -- * will recycle oldest entry. -- * -- * @return The destination cache entry index that was created, -1 if no -- * entry was created -- */ --static s16_t --nd6_new_destination_cache_entry(void) --{ -- s16_t i, j; -- u32_t age; -- -- /* Find an empty entry. */ -- for (i = 0; i < LWIP_ND6_NUM_DESTINATIONS; i++) { -- if (ip6_addr_isany(&(destination_cache[i].destination_addr))) { -- return i; -- } -- } -- -- /* Find oldest entry. */ -- age = 0; -- j = LWIP_ND6_NUM_DESTINATIONS - 1; -- for (i = 0; i < LWIP_ND6_NUM_DESTINATIONS; i++) { -- if (destination_cache[i].age > age) { -- j = i; -- } -- } -- -- return j; --} -- --/** -- * Clear the destination cache. -- * -- * This operation may be necessary for consistency in the light of changing -- * local addresses and/or use of the gateway hook. -- */ --void --nd6_clear_destination_cache(void) --{ -- int i; -- -- for (i = 0; i < LWIP_ND6_NUM_DESTINATIONS; i++) { -- ip6_addr_set_any(&destination_cache[i].destination_addr); -- } --} -- --/** -- * Determine whether an address matches an on-link prefix or the subnet of a -- * statically assigned address. -- * -- * @param ip6addr the IPv6 address to match -- * @return 1 if the address is on-link, 0 otherwise -- */ --static int --nd6_is_prefix_in_netif(const ip6_addr_t *ip6addr, struct netif *netif) --{ -- s8_t i; -- -- /* Check to see if the address matches an on-link prefix. */ -- for (i = 0; i < LWIP_ND6_NUM_PREFIXES; i++) { -- if ((prefix_list[i].netif == netif) && -- (prefix_list[i].invalidation_timer > 0) && -- ip6_addr_netcmp(ip6addr, &(prefix_list[i].prefix))) { -- return 1; -- } -- } -- /* Check to see if address prefix matches a manually configured (= static) -- * address. Static addresses have an implied /64 subnet assignment. Dynamic -- * addresses (from autoconfiguration) have no implied subnet assignment, and -- * are thus effectively /128 assignments. See RFC 5942 for more on this. */ -- for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) { -- if (ip6_addr_isvalid(netif_ip6_addr_state(netif, i)) && -- netif_ip6_addr_isstatic(netif, i) && -- ip6_addr_netcmp(ip6addr, netif_ip6_addr(netif, i))) { -- return 1; -- } -- } -- return 0; --} -- --/** -- * Select a default router for a destination. -- * -- * This function is used both for routing and for finding a next-hop target for -- * a packet. In the former case, the given netif is NULL, and the returned -- * router entry must be for a netif suitable for sending packets (up, link up). -- * In the latter case, the given netif is not NULL and restricts router choice. -- * -- * @param ip6addr the destination address -- * @param netif the netif for the outgoing packet, if known -- * @return the default router entry index, or -1 if no suitable -- * router is found -- */ --static s8_t --nd6_select_router(const ip6_addr_t *ip6addr, struct netif *netif) --{ -- struct netif *router_netif; -- s8_t i, j, valid_router; -- static s8_t last_router; -- -- LWIP_UNUSED_ARG(ip6addr); /* @todo match preferred routes!! (must implement ND6_OPTION_TYPE_ROUTE_INFO) */ -- -- /* @todo: implement default router preference */ -- -- /* Look for valid routers. A reachable router is preferred. */ -- valid_router = -1; -- for (i = 0; i < LWIP_ND6_NUM_ROUTERS; i++) { -- /* Is the router netif both set and apppropriate? */ -- if (default_router_list[i].neighbor_entry != NULL) { -- router_netif = default_router_list[i].neighbor_entry->netif; -- if ((router_netif != NULL) && (netif != NULL ? netif == router_netif : -- (netif_is_up(router_netif) && netif_is_link_up(router_netif)))) { -- /* Is the router valid, i.e., reachable or probably reachable as per -- * RFC 4861 Sec. 6.3.6? Note that we will never return a router that -- * has no neighbor cache entry, due to the netif association tests. */ -- if (default_router_list[i].neighbor_entry->state != ND6_INCOMPLETE) { -- /* Is the router known to be reachable? */ -- if (default_router_list[i].neighbor_entry->state == ND6_REACHABLE) { -- return i; /* valid and reachable - done! */ -- } else if (valid_router < 0) { -- valid_router = i; /* valid but not known to be reachable */ -- } -- } -- } -- } -- } -- if (valid_router >= 0) { -- return valid_router; -- } -- -- /* Look for any router for which we have any information at all. */ -- /* last_router is used for round-robin selection of incomplete routers, as -- * recommended in RFC 4861 Sec. 6.3.6 point (2). Advance only when picking a -- * route, to select the same router as next-hop target in the common case. */ -- if ((netif == NULL) && (++last_router >= LWIP_ND6_NUM_ROUTERS)) { -- last_router = 0; -- } -- i = last_router; -- for (j = 0; j < LWIP_ND6_NUM_ROUTERS; j++) { -- if (default_router_list[i].neighbor_entry != NULL) { -- router_netif = default_router_list[i].neighbor_entry->netif; -- if ((router_netif != NULL) && (netif != NULL ? netif == router_netif : -- (netif_is_up(router_netif) && netif_is_link_up(router_netif)))) { -- return i; -- } -- } -- if (++i >= LWIP_ND6_NUM_ROUTERS) { -- i = 0; -- } -- } -- -- /* no suitable router found. */ -- return -1; --} -- --/** -- * Find a router-announced route to the given destination. This route may be -- * based on an on-link prefix or a default router. -- * -- * If a suitable route is found, the returned netif is guaranteed to be in a -- * suitable state (up, link up) to be used for packet transmission. -- * -- * @param ip6addr the destination IPv6 address -- * @return the netif to use for the destination, or NULL if none found -- */ --struct netif * --nd6_find_route(const ip6_addr_t *ip6addr) --{ -- struct netif *netif; -- s8_t i; -- -- /* @todo decide if it makes sense to check the destination cache first */ -- -- /* Check if there is a matching on-link prefix. There may be multiple -- * matches. Pick the first one that is associated with a suitable netif. */ -- for (i = 0; i < LWIP_ND6_NUM_PREFIXES; ++i) { -- netif = prefix_list[i].netif; -- if ((netif != NULL) && ip6_addr_netcmp(&prefix_list[i].prefix, ip6addr) && -- netif_is_up(netif) && netif_is_link_up(netif)) { -- return netif; -- } -- } -- -- /* No on-link prefix match. Find a router that can forward the packet. */ -- i = nd6_select_router(ip6addr, NULL); -- if (i >= 0) { -- LWIP_ASSERT("selected router must have a neighbor entry", -- default_router_list[i].neighbor_entry != NULL); -- return default_router_list[i].neighbor_entry->netif; -- } -- -- return NULL; --} -- --/** -- * Find an entry for a default router. -- * -- * @param router_addr the IPv6 address of the router -- * @param netif the netif on which the router is found, if known -- * @return the index of the router entry, or -1 if not found -- */ --static s8_t --nd6_get_router(const ip6_addr_t *router_addr, struct netif *netif) --{ -- s8_t i; -- -- IP6_ADDR_ZONECHECK_NETIF(router_addr, netif); -- -- /* Look for router. */ -- for (i = 0; i < LWIP_ND6_NUM_ROUTERS; i++) { -- if ((default_router_list[i].neighbor_entry != NULL) && -- ((netif != NULL) ? netif == default_router_list[i].neighbor_entry->netif : 1) && -- ip6_addr_cmp(router_addr, &(default_router_list[i].neighbor_entry->next_hop_address))) { -- return i; -- } -- } -- -- /* router not found. */ -- return -1; --} -- --/** -- * Create a new entry for a default router. -- * -- * @param router_addr the IPv6 address of the router -- * @param netif the netif on which the router is connected, if known -- * @return the index on the router table, or -1 if could not be created -- */ --static s8_t --nd6_new_router(const ip6_addr_t *router_addr, struct netif *netif) --{ -- s8_t router_index; -- s8_t free_router_index; -- s8_t neighbor_index; -- -- IP6_ADDR_ZONECHECK_NETIF(router_addr, netif); -- -- /* Do we have a neighbor entry for this router? */ -- neighbor_index = nd6_find_neighbor_cache_entry(router_addr); -- if (neighbor_index < 0) { -- /* Create a neighbor entry for this router. */ -- neighbor_index = nd6_new_neighbor_cache_entry(); -- if (neighbor_index < 0) { -- /* Could not create neighbor entry for this router. */ -- return -1; -- } -- ip6_addr_set(&(neighbor_cache[neighbor_index].next_hop_address), router_addr); -- neighbor_cache[neighbor_index].netif = netif; -- neighbor_cache[neighbor_index].q = NULL; -- neighbor_cache[neighbor_index].state = ND6_INCOMPLETE; -- neighbor_cache[neighbor_index].counter.probes_sent = 1; -- nd6_send_neighbor_cache_probe(&neighbor_cache[neighbor_index], ND6_SEND_FLAG_MULTICAST_DEST); -- } -- -- /* Mark neighbor as router. */ -- neighbor_cache[neighbor_index].isrouter = 1; -- -- /* Look for empty entry. */ -- free_router_index = LWIP_ND6_NUM_ROUTERS; -- for (router_index = LWIP_ND6_NUM_ROUTERS - 1; router_index >= 0; router_index--) { -- /* check if router already exists (this is a special case for 2 netifs on the same subnet -- - e.g. wifi and cable) */ -- if(default_router_list[router_index].neighbor_entry == &(neighbor_cache[neighbor_index])){ -- return router_index; -- } -- if (default_router_list[router_index].neighbor_entry == NULL) { -- /* remember lowest free index to create a new entry */ -- free_router_index = router_index; -- } -- } -- if (free_router_index < LWIP_ND6_NUM_ROUTERS) { -- default_router_list[free_router_index].neighbor_entry = &(neighbor_cache[neighbor_index]); -- return free_router_index; -- } -- -- /* Could not create a router entry. */ -- -- /* Mark neighbor entry as not-router. Entry might be useful as neighbor still. */ -- neighbor_cache[neighbor_index].isrouter = 0; -- -- /* router not found. */ -- return -1; --} -- --/** -- * Find the cached entry for an on-link prefix. -- * -- * @param prefix the IPv6 prefix that is on-link -- * @param netif the netif on which the prefix is on-link -- * @return the index on the prefix table, or -1 if not found -- */ --static s8_t --nd6_get_onlink_prefix(const ip6_addr_t *prefix, struct netif *netif) --{ -- s8_t i; -- -- /* Look for prefix in list. */ -- for (i = 0; i < LWIP_ND6_NUM_PREFIXES; ++i) { -- if ((ip6_addr_netcmp(&(prefix_list[i].prefix), prefix)) && -- (prefix_list[i].netif == netif)) { -- return i; -- } -- } -- -- /* Entry not available. */ -- return -1; --} -- --/** -- * Creates a new entry for an on-link prefix. -- * -- * @param prefix the IPv6 prefix that is on-link -- * @param netif the netif on which the prefix is on-link -- * @return the index on the prefix table, or -1 if not created -- */ --static s8_t --nd6_new_onlink_prefix(const ip6_addr_t *prefix, struct netif *netif) --{ -- s8_t i; -- -- /* Create new entry. */ -- for (i = 0; i < LWIP_ND6_NUM_PREFIXES; ++i) { -- if ((prefix_list[i].netif == NULL) || -- (prefix_list[i].invalidation_timer == 0)) { -- /* Found empty prefix entry. */ -- prefix_list[i].netif = netif; -- ip6_addr_set(&(prefix_list[i].prefix), prefix); -- return i; -- } -- } -- -- /* Entry not available. */ -- return -1; --} -- --/** -- * Determine the next hop for a destination. Will determine if the -- * destination is on-link, else a suitable on-link router is selected. -- * -- * The last entry index is cached for fast entry search. -- * -- * @param ip6addr the destination address -- * @param netif the netif on which the packet will be sent -- * @return the neighbor cache entry for the next hop, ERR_RTE if no -- * suitable next hop was found, ERR_MEM if no cache entry -- * could be created -- */ --static s8_t --nd6_get_next_hop_entry(const ip6_addr_t *ip6addr, struct netif *netif) --{ --#ifdef LWIP_HOOK_ND6_GET_GW -- const ip6_addr_t *next_hop_addr; --#endif /* LWIP_HOOK_ND6_GET_GW */ -- s8_t i; -- s16_t dst_idx; -- -- IP6_ADDR_ZONECHECK_NETIF(ip6addr, netif); -- --#if LWIP_NETIF_HWADDRHINT -- if (netif->hints != NULL) { -- /* per-pcb cached entry was given */ -- netif_addr_idx_t addr_hint = netif->hints->addr_hint; -- if (addr_hint < LWIP_ND6_NUM_DESTINATIONS) { -- nd6_cached_destination_index = addr_hint; -- } -- } --#endif /* LWIP_NETIF_HWADDRHINT */ -- -- /* Look for ip6addr in destination cache. */ -- if (ip6_addr_cmp(ip6addr, &(destination_cache[nd6_cached_destination_index].destination_addr))) { -- /* the cached entry index is the right one! */ -- /* do nothing. */ -- ND6_STATS_INC(nd6.cachehit); -- } else { -- /* Search destination cache. */ -- dst_idx = nd6_find_destination_cache_entry(ip6addr); -- if (dst_idx >= 0) { -- /* found destination entry. make it our new cached index. */ -- LWIP_ASSERT("type overflow", (size_t)dst_idx < NETIF_ADDR_IDX_MAX); -- nd6_cached_destination_index = (netif_addr_idx_t)dst_idx; -- } else { -- /* Not found. Create a new destination entry. */ -- dst_idx = nd6_new_destination_cache_entry(); -- if (dst_idx >= 0) { -- /* got new destination entry. make it our new cached index. */ -- LWIP_ASSERT("type overflow", (size_t)dst_idx < NETIF_ADDR_IDX_MAX); -- nd6_cached_destination_index = (netif_addr_idx_t)dst_idx; -- } else { -- /* Could not create a destination cache entry. */ -- return ERR_MEM; -- } -- -- /* Copy dest address to destination cache. */ -- ip6_addr_set(&(destination_cache[nd6_cached_destination_index].destination_addr), ip6addr); -- -- /* Now find the next hop. is it a neighbor? */ -- if (ip6_addr_islinklocal(ip6addr) || -- nd6_is_prefix_in_netif(ip6addr, netif)) { -- /* Destination in local link. */ -- destination_cache[nd6_cached_destination_index].pmtu = netif_mtu6(netif); -- ip6_addr_copy(destination_cache[nd6_cached_destination_index].next_hop_addr, destination_cache[nd6_cached_destination_index].destination_addr); --#ifdef LWIP_HOOK_ND6_GET_GW -- } else if ((next_hop_addr = LWIP_HOOK_ND6_GET_GW(netif, ip6addr)) != NULL) { -- /* Next hop for destination provided by hook function. */ -- destination_cache[nd6_cached_destination_index].pmtu = netif->mtu; -- ip6_addr_set(&destination_cache[nd6_cached_destination_index].next_hop_addr, next_hop_addr); --#endif /* LWIP_HOOK_ND6_GET_GW */ -- } else { -- /* We need to select a router. */ -- i = nd6_select_router(ip6addr, netif); -- if (i < 0) { -- /* No router found. */ -- ip6_addr_set_any(&(destination_cache[nd6_cached_destination_index].destination_addr)); -- return ERR_RTE; -- } -- destination_cache[nd6_cached_destination_index].pmtu = netif_mtu6(netif); /* Start with netif mtu, correct through ICMPv6 if necessary */ -- ip6_addr_copy(destination_cache[nd6_cached_destination_index].next_hop_addr, default_router_list[i].neighbor_entry->next_hop_address); -- } -- } -- } -- --#if LWIP_NETIF_HWADDRHINT -- if (netif->hints != NULL) { -- /* per-pcb cached entry was given */ -- netif->hints->addr_hint = nd6_cached_destination_index; -- } --#endif /* LWIP_NETIF_HWADDRHINT */ -- -- /* Look in neighbor cache for the next-hop address. */ -- if (ip6_addr_cmp(&(destination_cache[nd6_cached_destination_index].next_hop_addr), -- &(neighbor_cache[nd6_cached_neighbor_index].next_hop_address))) { -- /* Cache hit. */ -- /* Do nothing. */ -- ND6_STATS_INC(nd6.cachehit); -- } else { -- i = nd6_find_neighbor_cache_entry(&(destination_cache[nd6_cached_destination_index].next_hop_addr)); -- if (i >= 0) { -- /* Found a matching record, make it new cached entry. */ -- nd6_cached_neighbor_index = i; -- } else { -- /* Neighbor not in cache. Make a new entry. */ -- i = nd6_new_neighbor_cache_entry(); -- if (i >= 0) { -- /* got new neighbor entry. make it our new cached index. */ -- nd6_cached_neighbor_index = i; -- } else { -- /* Could not create a neighbor cache entry. */ -- return ERR_MEM; -- } -- -- /* Initialize fields. */ -- ip6_addr_copy(neighbor_cache[i].next_hop_address, -- destination_cache[nd6_cached_destination_index].next_hop_addr); -- neighbor_cache[i].isrouter = 0; -- neighbor_cache[i].netif = netif; -- neighbor_cache[i].state = ND6_INCOMPLETE; -- neighbor_cache[i].counter.probes_sent = 1; -- nd6_send_neighbor_cache_probe(&neighbor_cache[i], ND6_SEND_FLAG_MULTICAST_DEST); -- } -- } -- -- /* Reset this destination's age. */ -- destination_cache[nd6_cached_destination_index].age = 0; -- -- return nd6_cached_neighbor_index; --} -- --/** -- * Queue a packet for a neighbor. -- * -- * @param neighbor_index the index in the neighbor cache table -- * @param q packet to be queued -- * @return ERR_OK if succeeded, ERR_MEM if out of memory -- */ --static err_t --nd6_queue_packet(s8_t neighbor_index, struct pbuf *q) --{ -- err_t result = ERR_MEM; -- struct pbuf *p; -- int copy_needed = 0; --#if LWIP_ND6_QUEUEING -- struct nd6_q_entry *new_entry, *r; --#endif /* LWIP_ND6_QUEUEING */ -- -- if ((neighbor_index < 0) || (neighbor_index >= LWIP_ND6_NUM_NEIGHBORS)) { -- return ERR_ARG; -- } -- -- /* IF q includes a pbuf that must be copied, we have to copy the whole chain -- * into a new PBUF_RAM. See the definition of PBUF_NEEDS_COPY for details. */ -- p = q; -- while (p) { -- if (PBUF_NEEDS_COPY(p)) { -- copy_needed = 1; -- break; -- } -- p = p->next; -- } -- if (copy_needed) { -- /* copy the whole packet into new pbufs */ -- p = pbuf_clone(PBUF_LINK, PBUF_RAM, q); -- while ((p == NULL) && (neighbor_cache[neighbor_index].q != NULL)) { -- /* Free oldest packet (as per RFC recommendation) */ --#if LWIP_ND6_QUEUEING -- r = neighbor_cache[neighbor_index].q; -- neighbor_cache[neighbor_index].q = r->next; -- r->next = NULL; -- nd6_free_q(r); --#else /* LWIP_ND6_QUEUEING */ -- pbuf_free(neighbor_cache[neighbor_index].q); -- neighbor_cache[neighbor_index].q = NULL; --#endif /* LWIP_ND6_QUEUEING */ -- p = pbuf_clone(PBUF_LINK, PBUF_RAM, q); -- } -- } else { -- /* referencing the old pbuf is enough */ -- p = q; -- pbuf_ref(p); -- } -- /* packet was copied/ref'd? */ -- if (p != NULL) { -- /* queue packet ... */ --#if LWIP_ND6_QUEUEING -- /* allocate a new nd6 queue entry */ -- new_entry = (struct nd6_q_entry *)memp_malloc(MEMP_ND6_QUEUE); -- if ((new_entry == NULL) && (neighbor_cache[neighbor_index].q != NULL)) { -- /* Free oldest packet (as per RFC recommendation) */ -- r = neighbor_cache[neighbor_index].q; -- neighbor_cache[neighbor_index].q = r->next; -- r->next = NULL; -- nd6_free_q(r); -- new_entry = (struct nd6_q_entry *)memp_malloc(MEMP_ND6_QUEUE); -- } -- if (new_entry != NULL) { -- new_entry->next = NULL; -- new_entry->p = p; -- if (neighbor_cache[neighbor_index].q != NULL) { -- /* queue was already existent, append the new entry to the end */ -- r = neighbor_cache[neighbor_index].q; -- while (r->next != NULL) { -- r = r->next; -- } -- r->next = new_entry; -- } else { -- /* queue did not exist, first item in queue */ -- neighbor_cache[neighbor_index].q = new_entry; -- } -- LWIP_DEBUGF(LWIP_DBG_TRACE, ("ipv6: queued packet %p on neighbor entry %"S16_F"\n", (void *)p, (s16_t)neighbor_index)); -- result = ERR_OK; -- } else { -- /* the pool MEMP_ND6_QUEUE is empty */ -- pbuf_free(p); -- LWIP_DEBUGF(LWIP_DBG_TRACE, ("ipv6: could not queue a copy of packet %p (out of memory)\n", (void *)p)); -- /* { result == ERR_MEM } through initialization */ -- } --#else /* LWIP_ND6_QUEUEING */ -- /* Queue a single packet. If an older packet is already queued, free it as per RFC. */ -- if (neighbor_cache[neighbor_index].q != NULL) { -- pbuf_free(neighbor_cache[neighbor_index].q); -- } -- neighbor_cache[neighbor_index].q = p; -- LWIP_DEBUGF(LWIP_DBG_TRACE, ("ipv6: queued packet %p on neighbor entry %"S16_F"\n", (void *)p, (s16_t)neighbor_index)); -- result = ERR_OK; --#endif /* LWIP_ND6_QUEUEING */ -- } else { -- LWIP_DEBUGF(LWIP_DBG_TRACE, ("ipv6: could not queue a copy of packet %p (out of memory)\n", (void *)q)); -- /* { result == ERR_MEM } through initialization */ -- } -- -- return result; --} -- --#if LWIP_ND6_QUEUEING --/** -- * Free a complete queue of nd6 q entries -- * -- * @param q a queue of nd6_q_entry to free -- */ --static void --nd6_free_q(struct nd6_q_entry *q) --{ -- struct nd6_q_entry *r; -- LWIP_ASSERT("q != NULL", q != NULL); -- LWIP_ASSERT("q->p != NULL", q->p != NULL); -- while (q) { -- r = q; -- q = q->next; -- LWIP_ASSERT("r->p != NULL", (r->p != NULL)); -- pbuf_free(r->p); -- memp_free(MEMP_ND6_QUEUE, r); -- } --} --#endif /* LWIP_ND6_QUEUEING */ -- --/** -- * Send queued packets for a neighbor -- * -- * @param i the neighbor to send packets to -- */ --static void --nd6_send_q(s8_t i) --{ -- struct ip6_hdr *ip6hdr; -- ip6_addr_t dest; --#if LWIP_ND6_QUEUEING -- struct nd6_q_entry *q; --#endif /* LWIP_ND6_QUEUEING */ -- -- if ((i < 0) || (i >= LWIP_ND6_NUM_NEIGHBORS)) { -- return; -- } -- --#if LWIP_ND6_QUEUEING -- while (neighbor_cache[i].q != NULL) { -- /* remember first in queue */ -- q = neighbor_cache[i].q; -- /* pop first item off the queue */ -- neighbor_cache[i].q = q->next; -- /* Get ipv6 header. */ -- ip6hdr = (struct ip6_hdr *)(q->p->payload); -- /* Create an aligned copy. */ -- ip6_addr_copy_from_packed(dest, ip6hdr->dest); -- /* Restore the zone, if applicable. */ -- ip6_addr_assign_zone(&dest, IP6_UNKNOWN, neighbor_cache[i].netif); -- /* send the queued IPv6 packet */ -- (neighbor_cache[i].netif)->output_ip6(neighbor_cache[i].netif, q->p, &dest); -- /* free the queued IP packet */ -- pbuf_free(q->p); -- /* now queue entry can be freed */ -- memp_free(MEMP_ND6_QUEUE, q); -- } --#else /* LWIP_ND6_QUEUEING */ -- if (neighbor_cache[i].q != NULL) { -- /* Get ipv6 header. */ -- ip6hdr = (struct ip6_hdr *)(neighbor_cache[i].q->payload); -- /* Create an aligned copy. */ -- ip6_addr_copy_from_packed(dest, ip6hdr->dest); -- /* Restore the zone, if applicable. */ -- ip6_addr_assign_zone(&dest, IP6_UNKNOWN, neighbor_cache[i].netif); -- /* send the queued IPv6 packet */ -- (neighbor_cache[i].netif)->output_ip6(neighbor_cache[i].netif, neighbor_cache[i].q, &dest); -- /* free the queued IP packet */ -- pbuf_free(neighbor_cache[i].q); -- neighbor_cache[i].q = NULL; -- } --#endif /* LWIP_ND6_QUEUEING */ --} -- --/** -- * A packet is to be transmitted to a specific IPv6 destination on a specific -- * interface. Check if we can find the hardware address of the next hop to use -- * for the packet. If so, give the hardware address to the caller, which should -- * use it to send the packet right away. Otherwise, enqueue the packet for -- * later transmission while looking up the hardware address, if possible. -- * -- * As such, this function returns one of three different possible results: -- * -- * - ERR_OK with a non-NULL 'hwaddrp': the caller should send the packet now. -- * - ERR_OK with a NULL 'hwaddrp': the packet has been enqueued for later. -- * - not ERR_OK: something went wrong; forward the error upward in the stack. -- * -- * @param netif The lwIP network interface on which the IP packet will be sent. -- * @param q The pbuf(s) containing the IP packet to be sent. -- * @param ip6addr The destination IPv6 address of the packet. -- * @param hwaddrp On success, filled with a pointer to a HW address or NULL (meaning -- * the packet has been queued). -- * @return -- * - ERR_OK on success, ERR_RTE if no route was found for the packet, -- * or ERR_MEM if low memory conditions prohibit sending the packet at all. -- */ --err_t --nd6_get_next_hop_addr_or_queue(struct netif *netif, struct pbuf *q, const ip6_addr_t *ip6addr, const u8_t **hwaddrp) --{ -- s8_t i; -- -- /* Get next hop record. */ -- i = nd6_get_next_hop_entry(ip6addr, netif); -- if (i < 0) { -- /* failed to get a next hop neighbor record. */ -- return i; -- } -- -- /* Now that we have a destination record, send or queue the packet. */ -- if (neighbor_cache[i].state == ND6_STALE) { -- /* Switch to delay state. */ -- neighbor_cache[i].state = ND6_DELAY; -- neighbor_cache[i].counter.delay_time = LWIP_ND6_DELAY_FIRST_PROBE_TIME / ND6_TMR_INTERVAL; -- } -- /* @todo should we send or queue if PROBE? send for now, to let unicast NS pass. */ -- if ((neighbor_cache[i].state == ND6_REACHABLE) || -- (neighbor_cache[i].state == ND6_DELAY) || -- (neighbor_cache[i].state == ND6_PROBE)) { -- -- /* Tell the caller to send out the packet now. */ -- *hwaddrp = neighbor_cache[i].lladdr; -- return ERR_OK; -- } -- -- /* We should queue packet on this interface. */ -- *hwaddrp = NULL; -- return nd6_queue_packet(i, q); --} -- -- --/** -- * Get the Path MTU for a destination. -- * -- * @param ip6addr the destination address -- * @param netif the netif on which the packet will be sent -- * @return the Path MTU, if known, or the netif default MTU -- */ --u16_t --nd6_get_destination_mtu(const ip6_addr_t *ip6addr, struct netif *netif) --{ -- s16_t i; -- -- i = nd6_find_destination_cache_entry(ip6addr); -- if (i >= 0) { -- if (destination_cache[i].pmtu > 0) { -- return destination_cache[i].pmtu; -- } -- } -- -- if (netif != NULL) { -- return netif_mtu6(netif); -- } -- -- return 1280; /* Minimum MTU */ --} -- -- --#if LWIP_ND6_TCP_REACHABILITY_HINTS --/** -- * Provide the Neighbor discovery process with a hint that a -- * destination is reachable. Called by tcp_receive when ACKs are -- * received or sent (as per RFC). This is useful to avoid sending -- * NS messages every 30 seconds. -- * -- * @param ip6addr the destination address which is know to be reachable -- * by an upper layer protocol (TCP) -- */ --void --nd6_reachability_hint(const ip6_addr_t *ip6addr) --{ -- s8_t i; -- s16_t dst_idx; -- -- /* Find destination in cache. */ -- if (ip6_addr_cmp(ip6addr, &(destination_cache[nd6_cached_destination_index].destination_addr))) { -- dst_idx = nd6_cached_destination_index; -- ND6_STATS_INC(nd6.cachehit); -- } else { -- dst_idx = nd6_find_destination_cache_entry(ip6addr); -- } -- if (dst_idx < 0) { -- return; -- } -- -- /* Find next hop neighbor in cache. */ -- if (ip6_addr_cmp(&(destination_cache[dst_idx].next_hop_addr), &(neighbor_cache[nd6_cached_neighbor_index].next_hop_address))) { -- i = nd6_cached_neighbor_index; -- ND6_STATS_INC(nd6.cachehit); -- } else { -- i = nd6_find_neighbor_cache_entry(&(destination_cache[dst_idx].next_hop_addr)); -- } -- if (i < 0) { -- return; -- } -- -- /* For safety: don't set as reachable if we don't have a LL address yet. Misuse protection. */ -- if (neighbor_cache[i].state == ND6_INCOMPLETE || neighbor_cache[i].state == ND6_NO_ENTRY) { -- return; -- } -- -- /* Set reachability state. */ -- neighbor_cache[i].state = ND6_REACHABLE; -- neighbor_cache[i].counter.reachable_time = reachable_time; --} --#endif /* LWIP_ND6_TCP_REACHABILITY_HINTS */ -- --/** -- * Remove all prefix, neighbor_cache and router entries of the specified netif. -- * -- * @param netif points to a network interface -- */ --void --nd6_cleanup_netif(struct netif *netif) --{ -- u8_t i; -- s8_t router_index; -- for (i = 0; i < LWIP_ND6_NUM_PREFIXES; i++) { -- if (prefix_list[i].netif == netif) { -- prefix_list[i].netif = NULL; -- } -- } -- for (i = 0; i < LWIP_ND6_NUM_NEIGHBORS; i++) { -- if (neighbor_cache[i].netif == netif) { -- for (router_index = 0; router_index < LWIP_ND6_NUM_ROUTERS; router_index++) { -- if (default_router_list[router_index].neighbor_entry == &neighbor_cache[i]) { -- default_router_list[router_index].neighbor_entry = NULL; -- default_router_list[router_index].flags = 0; -- } -- } -- neighbor_cache[i].isrouter = 0; -- nd6_free_neighbor_cache_entry(i); -- } -- } -- /* Clear the destination cache, since many entries may now have become -- * invalid for one of several reasons. As destination cache entries have no -- * netif association, use a sledgehammer approach (this can be improved). */ -- nd6_clear_destination_cache(); --} -- --#if LWIP_IPV6_MLD --/** -- * The state of a local IPv6 address entry is about to change. If needed, join -- * or leave the solicited-node multicast group for the address. -- * -- * @param netif The netif that owns the address. -- * @param addr_idx The index of the address. -- * @param new_state The new (IP6_ADDR_) state for the address. -- */ --void --nd6_adjust_mld_membership(struct netif *netif, s8_t addr_idx, u8_t new_state) --{ -- u8_t old_state, old_member, new_member; -- -- old_state = netif_ip6_addr_state(netif, addr_idx); -- -- /* Determine whether we were, and should be, a member of the solicited-node -- * multicast group for this address. For tentative addresses, the group is -- * not joined until the address enters the TENTATIVE_1 (or VALID) state. */ -- old_member = (old_state != IP6_ADDR_INVALID && old_state != IP6_ADDR_DUPLICATED && old_state != IP6_ADDR_TENTATIVE); -- new_member = (new_state != IP6_ADDR_INVALID && new_state != IP6_ADDR_DUPLICATED && new_state != IP6_ADDR_TENTATIVE); -- -- if (old_member != new_member) { -- ip6_addr_set_solicitednode(&multicast_address, netif_ip6_addr(netif, addr_idx)->addr[3]); -- ip6_addr_assign_zone(&multicast_address, IP6_MULTICAST, netif); -- -- if (new_member) { -- mld6_joingroup_netif(netif, &multicast_address); -- } else { -- mld6_leavegroup_netif(netif, &multicast_address); -- } -- } --} --#endif /* LWIP_IPV6_MLD */ -- --/** Netif was added, set up, or reconnected (link up) */ --void --nd6_restart_netif(struct netif *netif) --{ --#if LWIP_IPV6_SEND_ROUTER_SOLICIT -- /* Send Router Solicitation messages (see RFC 4861, ch. 6.3.7). */ -- netif->rs_count = LWIP_ND6_MAX_MULTICAST_SOLICIT; --#endif /* LWIP_IPV6_SEND_ROUTER_SOLICIT */ --} -- --#endif /* LWIP_IPV6 */ -+/** -+ * @file -+ * -+ * Neighbor discovery and stateless address autoconfiguration for IPv6. -+ * Aims to be compliant with RFC 4861 (Neighbor discovery) and RFC 4862 -+ * (Address autoconfiguration). -+ */ -+ -+/* -+ * Copyright (c) 2010 Inico Technologies Ltd. -+ * 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: Ivan Delamer -+ * -+ * -+ * Please coordinate changes and requests with Ivan Delamer -+ * -+ */ -+ -+#include "lwip/opt.h" -+ -+#if LWIP_IPV6 /* don't build if not configured for use in lwipopts.h */ -+ -+#include "lwip/nd6.h" -+#include "lwip/priv/nd6_priv.h" -+#include "lwip/prot/nd6.h" -+#include "lwip/prot/icmp6.h" -+#include "lwip/pbuf.h" -+#include "lwip/mem.h" -+#include "lwip/memp.h" -+#include "lwip/ip6.h" -+#include "lwip/ip6_addr.h" -+#include "lwip/inet_chksum.h" -+#include "lwip/netif.h" -+#include "lwip/icmp6.h" -+#include "lwip/mld6.h" -+#include "lwip/dhcp6.h" -+#include "lwip/ip.h" -+#include "lwip/stats.h" -+#include "lwip/dns.h" -+ -+#include -+ -+#ifdef LWIP_HOOK_FILENAME -+#include LWIP_HOOK_FILENAME -+#endif -+ -+#if LWIP_IPV6_DUP_DETECT_ATTEMPTS > IP6_ADDR_TENTATIVE_COUNT_MASK -+#error LWIP_IPV6_DUP_DETECT_ATTEMPTS > IP6_ADDR_TENTATIVE_COUNT_MASK -+#endif -+ -+/* Router tables. */ -+struct nd6_neighbor_cache_entry neighbor_cache[LWIP_ND6_NUM_NEIGHBORS]; -+struct nd6_destination_cache_entry destination_cache[LWIP_ND6_NUM_DESTINATIONS]; -+struct nd6_prefix_list_entry prefix_list[LWIP_ND6_NUM_PREFIXES]; -+struct nd6_router_list_entry default_router_list[LWIP_ND6_NUM_ROUTERS]; -+ -+/* Default values, can be updated by a RA message. */ -+u32_t reachable_time = LWIP_ND6_REACHABLE_TIME; -+u32_t retrans_timer = LWIP_ND6_RETRANS_TIMER; /* @todo implement this value in timer */ -+ -+/* Index for cache entries. */ -+static u8_t nd6_cached_neighbor_index; -+static netif_addr_idx_t nd6_cached_destination_index; -+ -+/* Multicast address holder. */ -+static ip6_addr_t multicast_address; -+ -+static u8_t nd6_tmr_rs_reduction; -+ -+/* Static buffer to parse RA packet options */ -+union ra_options { -+ struct lladdr_option lladdr; -+ struct mtu_option mtu; -+ struct prefix_option prefix; -+#if LWIP_ND6_RDNSS_MAX_DNS_SERVERS -+ struct rdnss_option rdnss; -+#endif -+}; -+static union ra_options nd6_ra_buffer; -+ -+/* Forward declarations. */ -+static s8_t nd6_find_neighbor_cache_entry(const ip6_addr_t *ip6addr); -+static s8_t nd6_new_neighbor_cache_entry(void); -+static void nd6_free_neighbor_cache_entry(s8_t i); -+static s16_t nd6_find_destination_cache_entry(const ip6_addr_t *ip6addr); -+static s16_t nd6_new_destination_cache_entry(void); -+static int nd6_is_prefix_in_netif(const ip6_addr_t *ip6addr, struct netif *netif); -+static s8_t nd6_select_router(const ip6_addr_t *ip6addr, struct netif *netif); -+static s8_t nd6_get_router(const ip6_addr_t *router_addr, struct netif *netif); -+static s8_t nd6_new_router(const ip6_addr_t *router_addr, struct netif *netif); -+static s8_t nd6_get_onlink_prefix(const ip6_addr_t *prefix, struct netif *netif); -+static s8_t nd6_new_onlink_prefix(const ip6_addr_t *prefix, struct netif *netif); -+static s8_t nd6_get_next_hop_entry(const ip6_addr_t *ip6addr, struct netif *netif); -+static err_t nd6_queue_packet(s8_t neighbor_index, struct pbuf *q); -+ -+#define ND6_SEND_FLAG_MULTICAST_DEST 0x01 -+#define ND6_SEND_FLAG_ALLNODES_DEST 0x02 -+#define ND6_SEND_FLAG_ANY_SRC 0x04 -+static void nd6_send_ns(struct netif *netif, const ip6_addr_t *target_addr, u8_t flags); -+static void nd6_send_na(struct netif *netif, const ip6_addr_t *target_addr, u8_t flags); -+static void nd6_send_neighbor_cache_probe(struct nd6_neighbor_cache_entry *entry, u8_t flags); -+#if LWIP_IPV6_SEND_ROUTER_SOLICIT -+static err_t nd6_send_rs(struct netif *netif); -+#endif /* LWIP_IPV6_SEND_ROUTER_SOLICIT */ -+ -+#if LWIP_ND6_QUEUEING -+static void nd6_free_q(struct nd6_q_entry *q); -+#else /* LWIP_ND6_QUEUEING */ -+#define nd6_free_q(q) pbuf_free(q) -+#endif /* LWIP_ND6_QUEUEING */ -+static void nd6_send_q(s8_t i); -+ -+ -+/** -+ * A local address has been determined to be a duplicate. Take the appropriate -+ * action(s) on the address and the interface as a whole. -+ * -+ * @param netif the netif that owns the address -+ * @param addr_idx the index of the address detected to be a duplicate -+ */ -+static void -+nd6_duplicate_addr_detected(struct netif *netif, s8_t addr_idx) -+{ -+ -+ /* Mark the address as duplicate, but leave its lifetimes alone. If this was -+ * a manually assigned address, it will remain in existence as duplicate, and -+ * as such be unusable for any practical purposes until manual intervention. -+ * If this was an autogenerated address, the address will follow normal -+ * expiration rules, and thus disappear once its valid lifetime expires. */ -+ netif_ip6_addr_set_state(netif, addr_idx, IP6_ADDR_DUPLICATED); -+ -+#if LWIP_IPV6_AUTOCONFIG -+ /* If the affected address was the link-local address that we use to generate -+ * all other addresses, then we should not continue to use those derived -+ * addresses either, so mark them as duplicate as well. For autoconfig-only -+ * setups, this will make the interface effectively unusable, approaching the -+ * intention of RFC 4862 Sec. 5.4.5. @todo implement the full requirements */ -+ if (addr_idx == 0) { -+ s8_t i; -+ for (i = 1; i < LWIP_IPV6_NUM_ADDRESSES; i++) { -+ if (!ip6_addr_isinvalid(netif_ip6_addr_state(netif, i)) && -+ !netif_ip6_addr_isstatic(netif, i)) { -+ netif_ip6_addr_set_state(netif, i, IP6_ADDR_DUPLICATED); -+ } -+ } -+ } -+#endif /* LWIP_IPV6_AUTOCONFIG */ -+} -+ -+#if LWIP_IPV6_AUTOCONFIG -+/** -+ * We received a router advertisement that contains a prefix with the -+ * autoconfiguration flag set. Add or update an associated autogenerated -+ * address. -+ * -+ * @param netif the netif on which the router advertisement arrived -+ * @param prefix_opt a pointer to the prefix option data -+ * @param prefix_addr an aligned copy of the prefix address -+ */ -+static void -+nd6_process_autoconfig_prefix(struct netif *netif, -+ struct prefix_option *prefix_opt, const ip6_addr_t *prefix_addr) -+{ -+ ip6_addr_t ip6addr; -+ u32_t valid_life, pref_life; -+ u8_t addr_state; -+ s8_t i, free_idx; -+ -+ /* The caller already checks RFC 4862 Sec. 5.5.3 points (a) and (b). We do -+ * the rest, starting with checks for (c) and (d) here. */ -+ valid_life = lwip_htonl(prefix_opt->valid_lifetime); -+ pref_life = lwip_htonl(prefix_opt->preferred_lifetime); -+ if (pref_life > valid_life || prefix_opt->prefix_length != 64) { -+ return; /* silently ignore this prefix for autoconfiguration purposes */ -+ } -+ -+ /* If an autogenerated address already exists for this prefix, update its -+ * lifetimes. An address is considered autogenerated if 1) it is not static -+ * (i.e., manually assigned), and 2) there is an advertised autoconfiguration -+ * prefix for it (the one we are processing here). This does not necessarily -+ * exclude the possibility that the address was actually assigned by, say, -+ * DHCPv6. If that distinction becomes important in the future, more state -+ * must be kept. As explained elsewhere we also update lifetimes of tentative -+ * and duplicate addresses. Skip address slot 0 (the link-local address). */ -+ for (i = 1; i < LWIP_IPV6_NUM_ADDRESSES; i++) { -+ addr_state = netif_ip6_addr_state(netif, i); -+ if (!ip6_addr_isinvalid(addr_state) && !netif_ip6_addr_isstatic(netif, i) && -+ ip6_addr_netcmp(prefix_addr, netif_ip6_addr(netif, i))) { -+ /* Update the valid lifetime, as per RFC 4862 Sec. 5.5.3 point (e). -+ * The valid lifetime will never drop to zero as a result of this. */ -+ u32_t remaining_life = netif_ip6_addr_valid_life(netif, i); -+ if (valid_life > ND6_2HRS || valid_life > remaining_life) { -+ netif_ip6_addr_set_valid_life(netif, i, valid_life); -+ } else if (remaining_life > ND6_2HRS) { -+ netif_ip6_addr_set_valid_life(netif, i, ND6_2HRS); -+ } -+ LWIP_ASSERT("bad valid lifetime", !netif_ip6_addr_isstatic(netif, i)); -+ /* Update the preferred lifetime. No bounds checks are needed here. In -+ * rare cases the advertisement may un-deprecate the address, though. -+ * Deprecation is left to the timer code where it is handled anyway. */ -+ if (pref_life > 0 && addr_state == IP6_ADDR_DEPRECATED) { -+ netif_ip6_addr_set_state(netif, i, IP6_ADDR_PREFERRED); -+ } -+ netif_ip6_addr_set_pref_life(netif, i, pref_life); -+ return; /* there should be at most one matching address */ -+ } -+ } -+ -+ /* No autogenerated address exists for this prefix yet. See if we can add a -+ * new one. However, if IPv6 autoconfiguration is administratively disabled, -+ * do not generate new addresses, but do keep updating lifetimes for existing -+ * addresses. Also, when adding new addresses, we must protect explicitly -+ * against a valid lifetime of zero, because again, we use that as a special -+ * value. The generated address would otherwise expire immediately anyway. -+ * Finally, the original link-local address must be usable at all. We start -+ * creating addresses even if the link-local address is still in tentative -+ * state though, and deal with the fallout of that upon DAD collision. */ -+ addr_state = netif_ip6_addr_state(netif, 0); -+ if (!netif->ip6_autoconfig_enabled || valid_life == IP6_ADDR_LIFE_STATIC || -+ ip6_addr_isinvalid(addr_state) || ip6_addr_isduplicated(addr_state)) { -+ return; -+ } -+ -+ /* Construct the new address that we intend to use, and then see if that -+ * address really does not exist. It might have been added manually, after -+ * all. As a side effect, find a free slot. Note that we cannot use -+ * netif_add_ip6_address() here, as it would return ERR_OK if the address -+ * already did exist, resulting in that address being given lifetimes. */ -+ IP6_ADDR(&ip6addr, prefix_addr->addr[0], prefix_addr->addr[1], -+ netif_ip6_addr(netif, 0)->addr[2], netif_ip6_addr(netif, 0)->addr[3]); -+ ip6_addr_assign_zone(&ip6addr, IP6_UNICAST, netif); -+ -+ free_idx = 0; -+ for (i = 1; i < LWIP_IPV6_NUM_ADDRESSES; i++) { -+ if (!ip6_addr_isinvalid(netif_ip6_addr_state(netif, i))) { -+ if (ip6_addr_cmp(&ip6addr, netif_ip6_addr(netif, i))) { -+ return; /* formed address already exists */ -+ } -+ } else if (free_idx == 0) { -+ free_idx = i; -+ } -+ } -+ if (free_idx == 0) { -+ return; /* no address slots available, try again on next advertisement */ -+ } -+ -+ /* Assign the new address to the interface. */ -+ ip_addr_copy_from_ip6(netif->ip6_addr[free_idx], ip6addr); -+ netif_ip6_addr_set_valid_life(netif, free_idx, valid_life); -+ netif_ip6_addr_set_pref_life(netif, free_idx, pref_life); -+ netif_ip6_addr_set_state(netif, free_idx, IP6_ADDR_TENTATIVE); -+} -+#endif /* LWIP_IPV6_AUTOCONFIG */ -+ -+/** -+ * Process an incoming neighbor discovery message -+ * -+ * @param p the nd packet, p->payload pointing to the icmpv6 header -+ * @param inp the netif on which this packet was received -+ */ -+void -+nd6_input(struct pbuf *p, struct netif *inp) -+{ -+ u8_t msg_type; -+ s8_t i; -+ s16_t dest_idx; -+ -+ ND6_STATS_INC(nd6.recv); -+ -+ msg_type = *((u8_t *)p->payload); -+ switch (msg_type) { -+ case ICMP6_TYPE_NA: /* Neighbor Advertisement. */ -+ { -+ struct na_header *na_hdr; -+ struct lladdr_option *lladdr_opt; -+ ip6_addr_t target_address; -+ -+ /* Check that na header fits in packet. */ -+ if (p->len < (sizeof(struct na_header))) { -+ /* @todo debug message */ -+ pbuf_free(p); -+ ND6_STATS_INC(nd6.lenerr); -+ ND6_STATS_INC(nd6.drop); -+ return; -+ } -+ -+ na_hdr = (struct na_header *)p->payload; -+ -+ /* Create an aligned, zoned copy of the target address. */ -+ ip6_addr_copy_from_packed(target_address, na_hdr->target_address); -+ ip6_addr_assign_zone(&target_address, IP6_UNICAST, inp); -+ -+ /* Check a subset of the other RFC 4861 Sec. 7.1.2 requirements. */ -+ if (IP6H_HOPLIM(ip6_current_header()) != ND6_HOPLIM || na_hdr->code != 0 || -+ ip6_addr_ismulticast(&target_address)) { -+ pbuf_free(p); -+ ND6_STATS_INC(nd6.proterr); -+ ND6_STATS_INC(nd6.drop); -+ return; -+ } -+ -+ /* @todo RFC MUST: if IP destination is multicast, Solicited flag is zero */ -+ /* @todo RFC MUST: all included options have a length greater than zero */ -+ -+ /* Unsolicited NA?*/ -+ if (ip6_addr_ismulticast(ip6_current_dest_addr())) { -+ /* This is an unsolicited NA. -+ * link-layer changed? -+ * part of DAD mechanism? */ -+ -+#if LWIP_IPV6_DUP_DETECT_ATTEMPTS -+ /* If the target address matches this netif, it is a DAD response. */ -+ for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) { -+ if (!ip6_addr_isinvalid(netif_ip6_addr_state(inp, i)) && -+ !ip6_addr_isduplicated(netif_ip6_addr_state(inp, i)) && -+ ip6_addr_cmp(&target_address, netif_ip6_addr(inp, i))) { -+ /* We are using a duplicate address. */ -+ nd6_duplicate_addr_detected(inp, i); -+ -+ pbuf_free(p); -+ return; -+ } -+ } -+#endif /* LWIP_IPV6_DUP_DETECT_ATTEMPTS */ -+ -+ /* Check that link-layer address option also fits in packet. */ -+ if (p->len < (sizeof(struct na_header) + 2)) { -+ /* @todo debug message */ -+ pbuf_free(p); -+ ND6_STATS_INC(nd6.lenerr); -+ ND6_STATS_INC(nd6.drop); -+ return; -+ } -+ -+ lladdr_opt = (struct lladdr_option *)((u8_t*)p->payload + sizeof(struct na_header)); -+ -+ if (p->len < (sizeof(struct na_header) + (lladdr_opt->length << 3))) { -+ /* @todo debug message */ -+ pbuf_free(p); -+ ND6_STATS_INC(nd6.lenerr); -+ ND6_STATS_INC(nd6.drop); -+ return; -+ } -+ -+ /* This is an unsolicited NA, most likely there was a LLADDR change. */ -+ i = nd6_find_neighbor_cache_entry(&target_address); -+ if (i >= 0) { -+ if (na_hdr->flags & ND6_FLAG_OVERRIDE) { -+ MEMCPY(neighbor_cache[i].lladdr, lladdr_opt->addr, inp->hwaddr_len); -+ } -+ } -+ } else { -+ /* This is a solicited NA. -+ * neighbor address resolution response? -+ * neighbor unreachability detection response? */ -+ -+ /* Find the cache entry corresponding to this na. */ -+ i = nd6_find_neighbor_cache_entry(&target_address); -+ if (i < 0) { -+ /* We no longer care about this target address. drop it. */ -+ pbuf_free(p); -+ return; -+ } -+ -+ /* Update cache entry. */ -+ if ((na_hdr->flags & ND6_FLAG_OVERRIDE) || -+ (neighbor_cache[i].state == ND6_INCOMPLETE)) { -+ /* Check that link-layer address option also fits in packet. */ -+ if (p->len < (sizeof(struct na_header) + 2)) { -+ /* @todo debug message */ -+ pbuf_free(p); -+ ND6_STATS_INC(nd6.lenerr); -+ ND6_STATS_INC(nd6.drop); -+ return; -+ } -+ -+ lladdr_opt = (struct lladdr_option *)((u8_t*)p->payload + sizeof(struct na_header)); -+ -+ if (p->len < (sizeof(struct na_header) + (lladdr_opt->length << 3))) { -+ /* @todo debug message */ -+ pbuf_free(p); -+ ND6_STATS_INC(nd6.lenerr); -+ ND6_STATS_INC(nd6.drop); -+ return; -+ } -+ -+ MEMCPY(neighbor_cache[i].lladdr, lladdr_opt->addr, inp->hwaddr_len); -+ } -+ -+ neighbor_cache[i].netif = inp; -+ neighbor_cache[i].state = ND6_REACHABLE; -+ neighbor_cache[i].counter.reachable_time = reachable_time; -+ -+ /* Send queued packets, if any. */ -+ if (neighbor_cache[i].q != NULL) { -+ nd6_send_q(i); -+ } -+ } -+ -+ break; /* ICMP6_TYPE_NA */ -+ } -+ case ICMP6_TYPE_NS: /* Neighbor solicitation. */ -+ { -+ struct ns_header *ns_hdr; -+ struct lladdr_option *lladdr_opt; -+ ip6_addr_t target_address; -+ u8_t accepted; -+ -+ /* Check that ns header fits in packet. */ -+ if (p->len < sizeof(struct ns_header)) { -+ /* @todo debug message */ -+ pbuf_free(p); -+ ND6_STATS_INC(nd6.lenerr); -+ ND6_STATS_INC(nd6.drop); -+ return; -+ } -+ -+ ns_hdr = (struct ns_header *)p->payload; -+ -+ /* Create an aligned, zoned copy of the target address. */ -+ ip6_addr_copy_from_packed(target_address, ns_hdr->target_address); -+ ip6_addr_assign_zone(&target_address, IP6_UNICAST, inp); -+ -+ /* Check a subset of the other RFC 4861 Sec. 7.1.1 requirements. */ -+ if (IP6H_HOPLIM(ip6_current_header()) != ND6_HOPLIM || ns_hdr->code != 0 || -+ ip6_addr_ismulticast(&target_address)) { -+ pbuf_free(p); -+ ND6_STATS_INC(nd6.proterr); -+ ND6_STATS_INC(nd6.drop); -+ return; -+ } -+ -+ /* @todo RFC MUST: all included options have a length greater than zero */ -+ /* @todo RFC MUST: if IP source is 'any', destination is solicited-node multicast address */ -+ /* @todo RFC MUST: if IP source is 'any', there is no source LL address option */ -+ -+ /* Check if there is a link-layer address provided. Only point to it if in this buffer. */ -+ if (p->len >= (sizeof(struct ns_header) + 2)) { -+ lladdr_opt = (struct lladdr_option *)((u8_t*)p->payload + sizeof(struct ns_header)); -+ if (p->len < (sizeof(struct ns_header) + (lladdr_opt->length << 3))) { -+ lladdr_opt = NULL; -+ } -+ } else { -+ lladdr_opt = NULL; -+ } -+ -+ /* Check if the target address is configured on the receiving netif. */ -+ accepted = 0; -+ for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; ++i) { -+ if ((ip6_addr_isvalid(netif_ip6_addr_state(inp, i)) || -+ (ip6_addr_istentative(netif_ip6_addr_state(inp, i)) && -+ ip6_addr_isany(ip6_current_src_addr()))) && -+ ip6_addr_cmp(&target_address, netif_ip6_addr(inp, i))) { -+ accepted = 1; -+ break; -+ } -+ } -+ -+ /* NS not for us? */ -+ if (!accepted) { -+ pbuf_free(p); -+ return; -+ } -+ -+ /* Check for ANY address in src (DAD algorithm). */ -+ if (ip6_addr_isany(ip6_current_src_addr())) { -+ /* Sender is validating this address. */ -+ for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; ++i) { -+ if (!ip6_addr_isinvalid(netif_ip6_addr_state(inp, i)) && -+ ip6_addr_cmp(&target_address, netif_ip6_addr(inp, i))) { -+ /* Send a NA back so that the sender does not use this address. */ -+ nd6_send_na(inp, netif_ip6_addr(inp, i), ND6_FLAG_OVERRIDE | ND6_SEND_FLAG_ALLNODES_DEST); -+ if (ip6_addr_istentative(netif_ip6_addr_state(inp, i))) { -+ /* We shouldn't use this address either. */ -+ nd6_duplicate_addr_detected(inp, i); -+ } -+ } -+ } -+ } else { -+ /* Sender is trying to resolve our address. */ -+ /* Verify that they included their own link-layer address. */ -+ if (lladdr_opt == NULL) { -+ /* Not a valid message. */ -+ pbuf_free(p); -+ ND6_STATS_INC(nd6.proterr); -+ ND6_STATS_INC(nd6.drop); -+ return; -+ } -+ -+ i = nd6_find_neighbor_cache_entry(ip6_current_src_addr()); -+ if (i>= 0) { -+ /* We already have a record for the solicitor. */ -+ if (neighbor_cache[i].state == ND6_INCOMPLETE) { -+ neighbor_cache[i].netif = inp; -+ MEMCPY(neighbor_cache[i].lladdr, lladdr_opt->addr, inp->hwaddr_len); -+ -+ /* Delay probe in case we get confirmation of reachability from upper layer (TCP). */ -+ neighbor_cache[i].state = ND6_DELAY; -+ neighbor_cache[i].counter.delay_time = LWIP_ND6_DELAY_FIRST_PROBE_TIME / ND6_TMR_INTERVAL; -+ } -+ } else { -+ /* Add their IPv6 address and link-layer address to neighbor cache. -+ * We will need it at least to send a unicast NA message, but most -+ * likely we will also be communicating with this node soon. */ -+ i = nd6_new_neighbor_cache_entry(); -+ if (i < 0) { -+ /* We couldn't assign a cache entry for this neighbor. -+ * we won't be able to reply. drop it. */ -+ pbuf_free(p); -+ ND6_STATS_INC(nd6.memerr); -+ return; -+ } -+ neighbor_cache[i].netif = inp; -+ MEMCPY(neighbor_cache[i].lladdr, lladdr_opt->addr, inp->hwaddr_len); -+ ip6_addr_set(&(neighbor_cache[i].next_hop_address), ip6_current_src_addr()); -+ -+ /* Receiving a message does not prove reachability: only in one direction. -+ * Delay probe in case we get confirmation of reachability from upper layer (TCP). */ -+ neighbor_cache[i].state = ND6_DELAY; -+ neighbor_cache[i].counter.delay_time = LWIP_ND6_DELAY_FIRST_PROBE_TIME / ND6_TMR_INTERVAL; -+ } -+ -+ /* Send back a NA for us. Allocate the reply pbuf. */ -+ nd6_send_na(inp, &target_address, ND6_FLAG_SOLICITED | ND6_FLAG_OVERRIDE); -+ } -+ -+ break; /* ICMP6_TYPE_NS */ -+ } -+ case ICMP6_TYPE_RA: /* Router Advertisement. */ -+ { -+ struct ra_header *ra_hdr; -+ u8_t *buffer; /* Used to copy options. */ -+ u16_t offset; -+#if LWIP_ND6_RDNSS_MAX_DNS_SERVERS -+ /* There can be multiple RDNSS options per RA */ -+ u8_t rdnss_server_idx = 0; -+#endif /* LWIP_ND6_RDNSS_MAX_DNS_SERVERS */ -+ -+ /* Check that RA header fits in packet. */ -+ if (p->len < sizeof(struct ra_header)) { -+ /* @todo debug message */ -+ pbuf_free(p); -+ ND6_STATS_INC(nd6.lenerr); -+ ND6_STATS_INC(nd6.drop); -+ return; -+ } -+ -+ ra_hdr = (struct ra_header *)p->payload; -+ -+ /* Check a subset of the other RFC 4861 Sec. 6.1.2 requirements. */ -+ if (!ip6_addr_islinklocal(ip6_current_src_addr()) || -+ IP6H_HOPLIM(ip6_current_header()) != ND6_HOPLIM || ra_hdr->code != 0) { -+ pbuf_free(p); -+ ND6_STATS_INC(nd6.proterr); -+ ND6_STATS_INC(nd6.drop); -+ return; -+ } -+ -+ /* @todo RFC MUST: all included options have a length greater than zero */ -+ -+ /* If we are sending RS messages, stop. */ -+#if LWIP_IPV6_SEND_ROUTER_SOLICIT -+ /* ensure at least one solicitation is sent (see RFC 4861, ch. 6.3.7) */ -+ if ((inp->rs_count < LWIP_ND6_MAX_MULTICAST_SOLICIT) || -+ (nd6_send_rs(inp) == ERR_OK)) { -+ inp->rs_count = 0; -+ } else { -+ inp->rs_count = 1; -+ } -+#endif /* LWIP_IPV6_SEND_ROUTER_SOLICIT */ -+ -+ /* Get the matching default router entry. */ -+ i = nd6_get_router(ip6_current_src_addr(), inp); -+ if (i < 0) { -+ /* Create a new router entry. */ -+ i = nd6_new_router(ip6_current_src_addr(), inp); -+ } -+ -+ if (i < 0) { -+ /* Could not create a new router entry. */ -+ pbuf_free(p); -+ ND6_STATS_INC(nd6.memerr); -+ return; -+ } -+ -+ /* Re-set invalidation timer. */ -+ default_router_list[i].invalidation_timer = lwip_htons(ra_hdr->router_lifetime); -+ -+ /* Re-set default timer values. */ -+#if LWIP_ND6_ALLOW_RA_UPDATES -+ if (ra_hdr->retrans_timer > 0) { -+ retrans_timer = lwip_htonl(ra_hdr->retrans_timer); -+ } -+ if (ra_hdr->reachable_time > 0) { -+ reachable_time = lwip_htonl(ra_hdr->reachable_time); -+ } -+#endif /* LWIP_ND6_ALLOW_RA_UPDATES */ -+ -+ /* @todo set default hop limit... */ -+ /* ra_hdr->current_hop_limit;*/ -+ -+ /* Update flags in local entry (incl. preference). */ -+ default_router_list[i].flags = ra_hdr->flags; -+ -+#if LWIP_IPV6_DHCP6 -+ /* Trigger DHCPv6 if enabled */ -+ dhcp6_nd6_ra_trigger(inp, ra_hdr->flags & ND6_RA_FLAG_MANAGED_ADDR_CONFIG, -+ ra_hdr->flags & ND6_RA_FLAG_OTHER_CONFIG); -+#endif -+ -+ /* Offset to options. */ -+ offset = sizeof(struct ra_header); -+ -+ /* Process each option. */ -+ while ((p->tot_len - offset) >= 2) { -+ u8_t option_type; -+ u16_t option_len; -+ int option_len8 = pbuf_try_get_at(p, offset + 1); -+ if (option_len8 <= 0) { -+ /* read beyond end or zero length */ -+ goto lenerr_drop_free_return; -+ } -+ option_len = ((u8_t)option_len8) << 3; -+ if (option_len > p->tot_len - offset) { -+ /* short packet (option does not fit in) */ -+ goto lenerr_drop_free_return; -+ } -+ if (p->len == p->tot_len) { -+ /* no need to copy from contiguous pbuf */ -+ buffer = &((u8_t*)p->payload)[offset]; -+ } else { -+ /* check if this option fits into our buffer */ -+ if (option_len > sizeof(nd6_ra_buffer)) { -+ option_type = pbuf_get_at(p, offset); -+ /* invalid option length */ -+ if (option_type != ND6_OPTION_TYPE_RDNSS) { -+ goto lenerr_drop_free_return; -+ } -+ /* we allow RDNSS option to be longer - we'll just drop some servers */ -+ option_len = sizeof(nd6_ra_buffer); -+ } -+ buffer = (u8_t*)&nd6_ra_buffer; -+ option_len = pbuf_copy_partial(p, &nd6_ra_buffer, option_len, offset); -+ } -+ option_type = buffer[0]; -+ switch (option_type) { -+ case ND6_OPTION_TYPE_SOURCE_LLADDR: -+ { -+ struct lladdr_option *lladdr_opt; -+ if (option_len < sizeof(struct lladdr_option)) { -+ goto lenerr_drop_free_return; -+ } -+ lladdr_opt = (struct lladdr_option *)buffer; -+ if ((default_router_list[i].neighbor_entry != NULL) && -+ (default_router_list[i].neighbor_entry->state == ND6_INCOMPLETE)) { -+ SMEMCPY(default_router_list[i].neighbor_entry->lladdr, lladdr_opt->addr, inp->hwaddr_len); -+ default_router_list[i].neighbor_entry->state = ND6_REACHABLE; -+ default_router_list[i].neighbor_entry->counter.reachable_time = reachable_time; -+ } -+ break; -+ } -+ case ND6_OPTION_TYPE_MTU: -+ { -+ struct mtu_option *mtu_opt; -+ u32_t mtu32; -+ if (option_len < sizeof(struct mtu_option)) { -+ goto lenerr_drop_free_return; -+ } -+ mtu_opt = (struct mtu_option *)buffer; -+ mtu32 = lwip_htonl(mtu_opt->mtu); -+ if ((mtu32 >= 1280) && (mtu32 <= 0xffff)) { -+#if LWIP_ND6_ALLOW_RA_UPDATES -+ if (inp->mtu) { -+ /* don't set the mtu for IPv6 higher than the netif driver supports */ -+ inp->mtu6 = LWIP_MIN(inp->mtu, (u16_t)mtu32); -+ } else { -+ inp->mtu6 = (u16_t)mtu32; -+ } -+#endif /* LWIP_ND6_ALLOW_RA_UPDATES */ -+ } -+ break; -+ } -+ case ND6_OPTION_TYPE_PREFIX_INFO: -+ { -+ struct prefix_option *prefix_opt; -+ ip6_addr_t prefix_addr; -+ if (option_len < sizeof(struct prefix_option)) { -+ goto lenerr_drop_free_return; -+ } -+ -+ prefix_opt = (struct prefix_option *)buffer; -+ -+ /* Get a memory-aligned copy of the prefix. */ -+ ip6_addr_copy_from_packed(prefix_addr, prefix_opt->prefix); -+ ip6_addr_assign_zone(&prefix_addr, IP6_UNICAST, inp); -+ -+ if (!ip6_addr_islinklocal(&prefix_addr)) { -+ if ((prefix_opt->flags & ND6_PREFIX_FLAG_ON_LINK) && -+ (prefix_opt->prefix_length == 64)) { -+ /* Add to on-link prefix list. */ -+ u32_t valid_life; -+ s8_t prefix; -+ -+ valid_life = lwip_htonl(prefix_opt->valid_lifetime); -+ -+ /* find cache entry for this prefix. */ -+ prefix = nd6_get_onlink_prefix(&prefix_addr, inp); -+ if (prefix < 0 && valid_life > 0) { -+ /* Create a new cache entry. */ -+ prefix = nd6_new_onlink_prefix(&prefix_addr, inp); -+ } -+ if (prefix >= 0) { -+ prefix_list[prefix].invalidation_timer = valid_life; -+ } -+ } -+#if LWIP_IPV6_AUTOCONFIG -+ if (prefix_opt->flags & ND6_PREFIX_FLAG_AUTONOMOUS) { -+ /* Perform processing for autoconfiguration. */ -+ nd6_process_autoconfig_prefix(inp, prefix_opt, &prefix_addr); -+ } -+#endif /* LWIP_IPV6_AUTOCONFIG */ -+ } -+ -+ break; -+ } -+ case ND6_OPTION_TYPE_ROUTE_INFO: -+ /* @todo implement preferred routes. -+ struct route_option * route_opt; -+ route_opt = (struct route_option *)buffer;*/ -+ -+ break; -+#if LWIP_ND6_RDNSS_MAX_DNS_SERVERS -+ case ND6_OPTION_TYPE_RDNSS: -+ { -+ u8_t num, n; -+ u16_t copy_offset = offset + SIZEOF_RDNSS_OPTION_BASE; -+ struct rdnss_option * rdnss_opt; -+ if (option_len < SIZEOF_RDNSS_OPTION_BASE) { -+ goto lenerr_drop_free_return; -+ } -+ -+ rdnss_opt = (struct rdnss_option *)buffer; -+ num = (rdnss_opt->length - 1) / 2; -+ for (n = 0; (rdnss_server_idx < DNS_MAX_SERVERS) && (n < num); n++) { -+ ip_addr_t rdnss_address; -+ -+ /* Copy directly from pbuf to get an aligned, zoned copy of the prefix. */ -+ if (pbuf_copy_partial(p, &rdnss_address, sizeof(ip6_addr_p_t), copy_offset) == sizeof(ip6_addr_p_t)) { -+ IP_SET_TYPE_VAL(rdnss_address, IPADDR_TYPE_V6); -+ ip6_addr_assign_zone(ip_2_ip6(&rdnss_address), IP6_UNKNOWN, inp); -+ -+ if (htonl(rdnss_opt->lifetime) > 0) { -+ /* TODO implement Lifetime > 0 */ -+ dns_setserver(rdnss_server_idx++, &rdnss_address); -+ } else { -+ /* TODO implement DNS removal in dns.c */ -+ u8_t s; -+ for (s = 0; s < DNS_MAX_SERVERS; s++) { -+ const ip_addr_t *addr = dns_getserver(s); -+ if(ip_addr_cmp(addr, &rdnss_address)) { -+ dns_setserver(s, NULL); -+ } -+ } -+ } -+ } -+ } -+ break; -+ } -+#endif /* LWIP_ND6_RDNSS_MAX_DNS_SERVERS */ -+ default: -+ /* Unrecognized option, abort. */ -+ ND6_STATS_INC(nd6.proterr); -+ break; -+ } -+ /* option length is checked earlier to be non-zero to make sure loop ends */ -+ offset += 8 * (u8_t)option_len8; -+ } -+ -+ break; /* ICMP6_TYPE_RA */ -+ } -+ case ICMP6_TYPE_RD: /* Redirect */ -+ { -+ struct redirect_header *redir_hdr; -+ struct lladdr_option *lladdr_opt; -+ ip6_addr_t destination_address, target_address; -+ -+ /* Check that Redir header fits in packet. */ -+ if (p->len < sizeof(struct redirect_header)) { -+ /* @todo debug message */ -+ pbuf_free(p); -+ ND6_STATS_INC(nd6.lenerr); -+ ND6_STATS_INC(nd6.drop); -+ return; -+ } -+ -+ redir_hdr = (struct redirect_header *)p->payload; -+ -+ /* Create an aligned, zoned copy of the destination address. */ -+ ip6_addr_copy_from_packed(destination_address, redir_hdr->destination_address); -+ ip6_addr_assign_zone(&destination_address, IP6_UNICAST, inp); -+ -+ /* Check a subset of the other RFC 4861 Sec. 8.1 requirements. */ -+ if (!ip6_addr_islinklocal(ip6_current_src_addr()) || -+ IP6H_HOPLIM(ip6_current_header()) != ND6_HOPLIM || -+ redir_hdr->code != 0 || ip6_addr_ismulticast(&destination_address)) { -+ pbuf_free(p); -+ ND6_STATS_INC(nd6.proterr); -+ ND6_STATS_INC(nd6.drop); -+ return; -+ } -+ -+ /* @todo RFC MUST: IP source address equals first-hop router for destination_address */ -+ /* @todo RFC MUST: ICMP target address is either link-local address or same as destination_address */ -+ /* @todo RFC MUST: all included options have a length greater than zero */ -+ -+ if (p->len >= (sizeof(struct redirect_header) + 2)) { -+ lladdr_opt = (struct lladdr_option *)((u8_t*)p->payload + sizeof(struct redirect_header)); -+ if (p->len < (sizeof(struct redirect_header) + (lladdr_opt->length << 3))) { -+ lladdr_opt = NULL; -+ } -+ } else { -+ lladdr_opt = NULL; -+ } -+ -+ /* Find dest address in cache */ -+ dest_idx = nd6_find_destination_cache_entry(&destination_address); -+ if (dest_idx < 0) { -+ /* Destination not in cache, drop packet. */ -+ pbuf_free(p); -+ return; -+ } -+ -+ /* Create an aligned, zoned copy of the target address. */ -+ ip6_addr_copy_from_packed(target_address, redir_hdr->target_address); -+ ip6_addr_assign_zone(&target_address, IP6_UNICAST, inp); -+ -+ /* Set the new target address. */ -+ ip6_addr_copy(destination_cache[dest_idx].next_hop_addr, target_address); ++#if PF_PACKET_SOCKET ++ if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) & NETCONN_PACKET_RAW) { ++ name_ll = (const struct sockaddr_ll *)(void*)name; ++ LWIP_ERROR("lwip_bind: invalid address", ((name_ll != NULL)&&(namelen == sizeof(struct sockaddr_ll)) && ++ ((name_ll->sll_family) == PF_PACKET) && IS_SOCK_ADDR_ALIGNED(name) && ++ (name_ll->sll_ifindex <= LWIP_NETIF_IFINDEX_MAX)), sock_set_errno(sock, err_to_errno(ERR_VAL)); ++ done_socket(sock); return -1); + -+ /* If Link-layer address of other router is given, try to add to neighbor cache. */ -+ if (lladdr_opt != NULL) { -+ if (lladdr_opt->type == ND6_OPTION_TYPE_TARGET_LLADDR) { -+ i = nd6_find_neighbor_cache_entry(&target_address); -+ if (i < 0) { -+ i = nd6_new_neighbor_cache_entry(); -+ if (i >= 0) { -+ neighbor_cache[i].netif = inp; -+ MEMCPY(neighbor_cache[i].lladdr, lladdr_opt->addr, inp->hwaddr_len); -+ ip6_addr_copy(neighbor_cache[i].next_hop_address, target_address); ++ ip_addr_set_any_val(IPADDR_TYPE_V4, local_addr); ++ local_port = name_ll->sll_protocol; ++ local_if_idx = (u8_t)name_ll->sll_ifindex; + -+ /* Receiving a message does not prove reachability: only in one direction. -+ * Delay probe in case we get confirmation of reachability from upper layer (TCP). */ -+ neighbor_cache[i].state = ND6_DELAY; -+ neighbor_cache[i].counter.delay_time = LWIP_ND6_DELAY_FIRST_PROBE_TIME / ND6_TMR_INTERVAL; -+ } -+ } -+ if (i >= 0) { -+ if (neighbor_cache[i].state == ND6_INCOMPLETE) { -+ MEMCPY(neighbor_cache[i].lladdr, lladdr_opt->addr, inp->hwaddr_len); -+ /* Receiving a message does not prove reachability: only in one direction. -+ * Delay probe in case we get confirmation of reachability from upper layer (TCP). */ -+ neighbor_cache[i].state = ND6_DELAY; -+ neighbor_cache[i].counter.delay_time = LWIP_ND6_DELAY_FIRST_PROBE_TIME / ND6_TMR_INTERVAL; -+ } -+ } -+ } -+ } -+ break; /* ICMP6_TYPE_RD */ -+ } -+ case ICMP6_TYPE_PTB: /* Packet too big */ ++ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d, ", s)); ++ LWIP_DEBUGF(SOCKETS_DEBUG, (" ifindex=%u proto=%"U16_F")\n", local_if_idx, local_port)); ++ } else ++#endif + { -+ struct icmpv6_hdr *icmp6hdr; /* Packet too big message */ -+ struct ip6_hdr *ip6hdr; /* IPv6 header of the packet which caused the error */ -+ u32_t pmtu; -+ ip6_addr_t destination_address; -+ -+ /* Check that ICMPv6 header + IPv6 header fit in payload */ -+ if (p->len < (sizeof(struct icmpv6_hdr) + IP6_HLEN)) { -+ /* drop short packets */ -+ pbuf_free(p); -+ ND6_STATS_INC(nd6.lenerr); -+ ND6_STATS_INC(nd6.drop); -+ return; -+ } -+ -+ icmp6hdr = (struct icmpv6_hdr *)p->payload; -+ ip6hdr = (struct ip6_hdr *)((u8_t*)p->payload + sizeof(struct icmpv6_hdr)); -+ -+ /* Create an aligned, zoned copy of the destination address. */ -+ ip6_addr_copy_from_packed(destination_address, ip6hdr->dest); -+ ip6_addr_assign_zone(&destination_address, IP6_UNKNOWN, inp); -+ -+ /* Look for entry in destination cache. */ -+ dest_idx = nd6_find_destination_cache_entry(&destination_address); -+ if (dest_idx < 0) { -+ /* Destination not in cache, drop packet. */ -+ pbuf_free(p); -+ return; -+ } -+ -+ /* Change the Path MTU. */ -+ pmtu = lwip_htonl(icmp6hdr->data); -+ destination_cache[dest_idx].pmtu = (u16_t)LWIP_MIN(pmtu, 0xFFFF); -+ -+ break; /* ICMP6_TYPE_PTB */ -+ } -+ -+ default: -+ ND6_STATS_INC(nd6.proterr); -+ ND6_STATS_INC(nd6.drop); -+ break; /* default */ -+ } -+ -+ pbuf_free(p); -+ return; -+lenerr_drop_free_return: -+ ND6_STATS_INC(nd6.lenerr); -+ ND6_STATS_INC(nd6.drop); -+ pbuf_free(p); -+} -+ -+ -+/** -+ * Periodic timer for Neighbor discovery functions: -+ * -+ * - Update neighbor reachability states -+ * - Update destination cache entries age -+ * - Update invalidation timers of default routers and on-link prefixes -+ * - Update lifetimes of our addresses -+ * - Perform duplicate address detection (DAD) for our addresses -+ * - Send router solicitations -+ */ -+void -+nd6_tmr(void) -+{ -+ s8_t i; -+ struct netif *netif; -+ -+ /* Process neighbor entries. */ -+ for (i = 0; i < LWIP_ND6_NUM_NEIGHBORS; i++) { -+ switch (neighbor_cache[i].state) { -+ case ND6_INCOMPLETE: -+ if ((neighbor_cache[i].counter.probes_sent >= LWIP_ND6_MAX_MULTICAST_SOLICIT) && -+ (!neighbor_cache[i].isrouter)) { -+ /* Retries exceeded. */ -+ nd6_free_neighbor_cache_entry(i); -+ } else { -+ /* Send a NS for this entry. */ -+ neighbor_cache[i].counter.probes_sent++; -+ nd6_send_neighbor_cache_probe(&neighbor_cache[i], ND6_SEND_FLAG_MULTICAST_DEST); -+ } -+ break; -+ case ND6_REACHABLE: -+ /* Send queued packets, if any are left. Should have been sent already. */ -+ if (neighbor_cache[i].q != NULL) { -+ nd6_send_q(i); -+ } -+ if (neighbor_cache[i].counter.reachable_time <= ND6_TMR_INTERVAL) { -+ /* Change to stale state. */ -+ neighbor_cache[i].state = ND6_STALE; -+ neighbor_cache[i].counter.stale_time = 0; -+ } else { -+ neighbor_cache[i].counter.reachable_time -= ND6_TMR_INTERVAL; -+ } -+ break; -+ case ND6_STALE: -+ neighbor_cache[i].counter.stale_time++; -+ break; -+ case ND6_DELAY: -+ if (neighbor_cache[i].counter.delay_time <= 1) { -+ /* Change to PROBE state. */ -+ neighbor_cache[i].state = ND6_PROBE; -+ neighbor_cache[i].counter.probes_sent = 0; -+ } else { -+ neighbor_cache[i].counter.delay_time--; -+ } -+ break; -+ case ND6_PROBE: -+ if ((neighbor_cache[i].counter.probes_sent >= LWIP_ND6_MAX_MULTICAST_SOLICIT) && -+ (!neighbor_cache[i].isrouter)) { -+ /* Retries exceeded. */ -+ nd6_free_neighbor_cache_entry(i); -+ } else { -+ /* Send a NS for this entry. */ -+ neighbor_cache[i].counter.probes_sent++; -+ nd6_send_neighbor_cache_probe(&neighbor_cache[i], 0); -+ } -+ break; -+ case ND6_NO_ENTRY: -+ default: -+ /* Do nothing. */ -+ break; -+ } -+ } -+ -+ /* Process destination entries. */ -+ for (i = 0; i < LWIP_ND6_NUM_DESTINATIONS; i++) { -+ destination_cache[i].age++; -+ } -+ -+ /* Process router entries. */ -+ for (i = 0; i < LWIP_ND6_NUM_ROUTERS; i++) { -+ if (default_router_list[i].neighbor_entry != NULL) { -+ /* Active entry. */ -+ if (default_router_list[i].invalidation_timer <= ND6_TMR_INTERVAL / 1000) { -+ /* No more than 1 second remaining. Clear this entry. Also clear any of -+ * its destination cache entries, as per RFC 4861 Sec. 5.3 and 6.3.5. */ -+ s8_t j; -+ for (j = 0; j < LWIP_ND6_NUM_DESTINATIONS; j++) { -+ if (ip6_addr_cmp(&destination_cache[j].next_hop_addr, -+ &default_router_list[i].neighbor_entry->next_hop_address)) { -+ ip6_addr_set_any(&destination_cache[j].destination_addr); -+ } -+ } -+ default_router_list[i].neighbor_entry->isrouter = 0; -+ default_router_list[i].neighbor_entry = NULL; -+ default_router_list[i].invalidation_timer = 0; -+ default_router_list[i].flags = 0; -+ } else { -+ default_router_list[i].invalidation_timer -= ND6_TMR_INTERVAL / 1000; -+ } -+ } -+ } -+ -+ /* Process prefix entries. */ -+ for (i = 0; i < LWIP_ND6_NUM_PREFIXES; i++) { -+ if (prefix_list[i].netif != NULL) { -+ if (prefix_list[i].invalidation_timer <= ND6_TMR_INTERVAL / 1000) { -+ /* Entry timed out, remove it */ -+ prefix_list[i].invalidation_timer = 0; -+ prefix_list[i].netif = NULL; -+ } else { -+ prefix_list[i].invalidation_timer -= ND6_TMR_INTERVAL / 1000; -+ } -+ } -+ } -+ -+ /* Process our own addresses, updating address lifetimes and/or DAD state. */ -+ NETIF_FOREACH(netif) { -+ for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; ++i) { -+ u8_t addr_state; -+#if LWIP_IPV6_ADDRESS_LIFETIMES -+ /* Step 1: update address lifetimes (valid and preferred). */ -+ addr_state = netif_ip6_addr_state(netif, i); -+ /* RFC 4862 is not entirely clear as to whether address lifetimes affect -+ * tentative addresses, and is even less clear as to what should happen -+ * with duplicate addresses. We choose to track and update lifetimes for -+ * both those types, although for different reasons: -+ * - for tentative addresses, the line of thought of Sec. 5.7 combined -+ * with the potentially long period that an address may be in tentative -+ * state (due to the interface being down) suggests that lifetimes -+ * should be independent of external factors which would include DAD; -+ * - for duplicate addresses, retiring them early could result in a new -+ * but unwanted attempt at marking them as valid, while retiring them -+ * late/never could clog up address slots on the netif. -+ * As a result, we may end up expiring addresses of either type here. -+ */ -+ if (!ip6_addr_isinvalid(addr_state) && -+ !netif_ip6_addr_isstatic(netif, i)) { -+ u32_t life = netif_ip6_addr_valid_life(netif, i); -+ if (life <= ND6_TMR_INTERVAL / 1000) { -+ /* The address has expired. */ -+ netif_ip6_addr_set_valid_life(netif, i, 0); -+ netif_ip6_addr_set_pref_life(netif, i, 0); -+ netif_ip6_addr_set_state(netif, i, IP6_ADDR_INVALID); -+ } else { -+ if (!ip6_addr_life_isinfinite(life)) { -+ life -= ND6_TMR_INTERVAL / 1000; -+ LWIP_ASSERT("bad valid lifetime", life != IP6_ADDR_LIFE_STATIC); -+ netif_ip6_addr_set_valid_life(netif, i, life); -+ } -+ /* The address is still here. Update the preferred lifetime too. */ -+ life = netif_ip6_addr_pref_life(netif, i); -+ if (life <= ND6_TMR_INTERVAL / 1000) { -+ /* This case must also trigger if 'life' was already zero, so as to -+ * deal correctly with advertised preferred-lifetime reductions. */ -+ netif_ip6_addr_set_pref_life(netif, i, 0); -+ if (addr_state == IP6_ADDR_PREFERRED) -+ netif_ip6_addr_set_state(netif, i, IP6_ADDR_DEPRECATED); -+ } else if (!ip6_addr_life_isinfinite(life)) { -+ life -= ND6_TMR_INTERVAL / 1000; -+ netif_ip6_addr_set_pref_life(netif, i, life); -+ } -+ } -+ } -+ /* The address state may now have changed, so reobtain it next. */ -+#endif /* LWIP_IPV6_ADDRESS_LIFETIMES */ -+ /* Step 2: update DAD state. */ -+ addr_state = netif_ip6_addr_state(netif, i); -+ if (ip6_addr_istentative(addr_state)) { -+ if ((addr_state & IP6_ADDR_TENTATIVE_COUNT_MASK) >= LWIP_IPV6_DUP_DETECT_ATTEMPTS) { -+ /* No NA received in response. Mark address as valid. For dynamic -+ * addresses with an expired preferred lifetime, the state is set to -+ * deprecated right away. That should almost never happen, though. */ -+ addr_state = IP6_ADDR_PREFERRED; -+#if LWIP_IPV6_ADDRESS_LIFETIMES -+ if (!netif_ip6_addr_isstatic(netif, i) && -+ netif_ip6_addr_pref_life(netif, i) == 0) { -+ addr_state = IP6_ADDR_DEPRECATED; -+ } -+#endif /* LWIP_IPV6_ADDRESS_LIFETIMES */ -+ netif_ip6_addr_set_state(netif, i, addr_state); -+ } else if (netif_is_up(netif) && netif_is_link_up(netif)) { -+ /* tentative: set next state by increasing by one */ -+ netif_ip6_addr_set_state(netif, i, addr_state + 1); -+ /* Send a NS for this address. Use the unspecified address as source -+ * address in all cases (RFC 4862 Sec. 5.4.2), not in the least -+ * because as it is, we only consider multicast replies for DAD. */ -+ nd6_send_ns(netif, netif_ip6_addr(netif, i), -+ ND6_SEND_FLAG_MULTICAST_DEST | ND6_SEND_FLAG_ANY_SRC); -+ } -+ } -+ } -+ } ++ LWIP_ERROR("lwip_bind: invalid address", ((name != NULL) && IS_SOCK_ADDR_LEN_VALID(namelen) && ++ IS_SOCK_ADDR_ALIGNED(name)), sock_set_errno(sock, err_to_errno(ERR_VAL)); ++ done_socket(sock); return -1); ++ LWIP_ERROR("lwip_bind: invalid address", ++ (IS_SOCK_ADDR_TYPE_VALID(name)), sock_set_errno(sock, err_to_errno(ERR_AFNOSUPPORT)); ++ done_socket(sock); return -1); + -+#if LWIP_IPV6_SEND_ROUTER_SOLICIT -+ /* Send router solicitation messages, if necessary. */ -+ if (!nd6_tmr_rs_reduction) { -+ nd6_tmr_rs_reduction = (ND6_RTR_SOLICITATION_INTERVAL / ND6_TMR_INTERVAL) - 1; -+ NETIF_FOREACH(netif) { -+ if ((netif->rs_count > 0) && netif_is_up(netif) && -+ netif_is_link_up(netif) && -+ !ip6_addr_isinvalid(netif_ip6_addr_state(netif, 0)) && -+ !ip6_addr_isduplicated(netif_ip6_addr_state(netif, 0))) { -+ if (nd6_send_rs(netif) == ERR_OK) { -+ netif->rs_count--; -+ } -+ } ++ if (!SOCK_ADDR_TYPE_MATCH(name, sock)) { ++ /* sockaddr does not match socket type (IPv4/IPv6) */ ++ sock_set_errno(sock, err_to_errno(ERR_VAL)); ++ done_socket(sock); ++ return -1; + } -+ } else { -+ nd6_tmr_rs_reduction--; -+ } -+#endif /* LWIP_IPV6_SEND_ROUTER_SOLICIT */ -+ -+} -+ -+/** Send a neighbor solicitation message for a specific neighbor cache entry -+ * -+ * @param entry the neightbor cache entry for wich to send the message -+ * @param flags one of ND6_SEND_FLAG_* -+ */ -+static void -+nd6_send_neighbor_cache_probe(struct nd6_neighbor_cache_entry *entry, u8_t flags) -+{ -+ nd6_send_ns(entry->netif, &entry->next_hop_address, flags); -+} -+ -+/** -+ * Send a neighbor solicitation message -+ * -+ * @param netif the netif on which to send the message -+ * @param target_addr the IPv6 target address for the ND message -+ * @param flags one of ND6_SEND_FLAG_* -+ */ -+static void -+nd6_send_ns(struct netif *netif, const ip6_addr_t *target_addr, u8_t flags) -+{ -+ struct ns_header *ns_hdr; -+ struct pbuf *p; -+ const ip6_addr_t *src_addr; -+ u16_t lladdr_opt_len; -+ -+ LWIP_ASSERT("target address is required", target_addr != NULL); -+ -+ if (!(flags & ND6_SEND_FLAG_ANY_SRC) && -+ ip6_addr_isvalid(netif_ip6_addr_state(netif,0))) { -+ /* Use link-local address as source address. */ -+ src_addr = netif_ip6_addr(netif, 0); -+ /* calculate option length (in 8-byte-blocks) */ -+ lladdr_opt_len = ((netif->hwaddr_len + 2) + 7) >> 3; -+ } else { -+ src_addr = IP6_ADDR_ANY6; -+ /* Option "MUST NOT be included when the source IP address is the unspecified address." */ -+ lladdr_opt_len = 0; -+ } -+ -+ /* Allocate a packet. */ -+ p = pbuf_alloc(PBUF_IP, sizeof(struct ns_header) + (lladdr_opt_len << 3), PBUF_RAM); -+ if (p == NULL) { -+ ND6_STATS_INC(nd6.memerr); -+ return; -+ } -+ -+ /* Set fields. */ -+ ns_hdr = (struct ns_header *)p->payload; -+ -+ ns_hdr->type = ICMP6_TYPE_NS; -+ ns_hdr->code = 0; -+ ns_hdr->chksum = 0; -+ ns_hdr->reserved = 0; -+ ip6_addr_copy_to_packed(ns_hdr->target_address, *target_addr); -+ -+ if (lladdr_opt_len != 0) { -+ struct lladdr_option *lladdr_opt = (struct lladdr_option *)((u8_t*)p->payload + sizeof(struct ns_header)); -+ lladdr_opt->type = ND6_OPTION_TYPE_SOURCE_LLADDR; -+ lladdr_opt->length = (u8_t)lladdr_opt_len; -+ SMEMCPY(lladdr_opt->addr, netif->hwaddr, netif->hwaddr_len); -+ } -+ -+ /* Generate the solicited node address for the target address. */ -+ if (flags & ND6_SEND_FLAG_MULTICAST_DEST) { -+ ip6_addr_set_solicitednode(&multicast_address, target_addr->addr[3]); -+ ip6_addr_assign_zone(&multicast_address, IP6_MULTICAST, netif); -+ target_addr = &multicast_address; -+ } -+ -+#if CHECKSUM_GEN_ICMP6 -+ IF__NETIF_CHECKSUM_ENABLED(netif, NETIF_CHECKSUM_GEN_ICMP6) { -+ ns_hdr->chksum = ip6_chksum_pseudo(p, IP6_NEXTH_ICMP6, p->len, src_addr, -+ target_addr); -+ } -+#endif /* CHECKSUM_GEN_ICMP6 */ -+ -+ /* Send the packet out. */ -+ ND6_STATS_INC(nd6.xmit); -+ ip6_output_if(p, (src_addr == IP6_ADDR_ANY6) ? NULL : src_addr, target_addr, -+ ND6_HOPLIM, 0, IP6_NEXTH_ICMP6, netif); -+ pbuf_free(p); -+} -+ -+/** -+ * Send a neighbor advertisement message -+ * -+ * @param netif the netif on which to send the message -+ * @param target_addr the IPv6 target address for the ND message -+ * @param flags one of ND6_SEND_FLAG_* -+ */ -+static void -+nd6_send_na(struct netif *netif, const ip6_addr_t *target_addr, u8_t flags) -+{ -+ struct na_header *na_hdr; -+ struct lladdr_option *lladdr_opt; -+ struct pbuf *p; -+ const ip6_addr_t *src_addr; -+ const ip6_addr_t *dest_addr; -+ u16_t lladdr_opt_len; -+ -+ LWIP_ASSERT("target address is required", target_addr != NULL); -+ -+ /* Use link-local address as source address. */ -+ /* src_addr = netif_ip6_addr(netif, 0); */ -+ /* Use target address as source address. */ -+ src_addr = target_addr; -+ -+ /* Allocate a packet. */ -+ lladdr_opt_len = ((netif->hwaddr_len + 2) >> 3) + (((netif->hwaddr_len + 2) & 0x07) ? 1 : 0); -+ p = pbuf_alloc(PBUF_IP, sizeof(struct na_header) + (lladdr_opt_len << 3), PBUF_RAM); -+ if (p == NULL) { -+ ND6_STATS_INC(nd6.memerr); -+ return; -+ } -+ -+ /* Set fields. */ -+ na_hdr = (struct na_header *)p->payload; -+ lladdr_opt = (struct lladdr_option *)((u8_t*)p->payload + sizeof(struct na_header)); + -+ na_hdr->type = ICMP6_TYPE_NA; -+ na_hdr->code = 0; -+ na_hdr->chksum = 0; -+ na_hdr->flags = flags & 0xf0; -+ na_hdr->reserved[0] = 0; -+ na_hdr->reserved[1] = 0; -+ na_hdr->reserved[2] = 0; -+ ip6_addr_copy_to_packed(na_hdr->target_address, *target_addr); -+ -+ lladdr_opt->type = ND6_OPTION_TYPE_TARGET_LLADDR; -+ lladdr_opt->length = (u8_t)lladdr_opt_len; -+ SMEMCPY(lladdr_opt->addr, netif->hwaddr, netif->hwaddr_len); -+ -+ /* Generate the solicited node address for the target address. */ -+ if (flags & ND6_SEND_FLAG_MULTICAST_DEST) { -+ ip6_addr_set_solicitednode(&multicast_address, target_addr->addr[3]); -+ ip6_addr_assign_zone(&multicast_address, IP6_MULTICAST, netif); -+ dest_addr = &multicast_address; -+ } else if (flags & ND6_SEND_FLAG_ALLNODES_DEST) { -+ ip6_addr_set_allnodes_linklocal(&multicast_address); -+ ip6_addr_assign_zone(&multicast_address, IP6_MULTICAST, netif); -+ dest_addr = &multicast_address; -+ } else { -+ dest_addr = ip6_current_src_addr(); ++ /* check size, family and alignment of 'name' */ ++ LWIP_ERROR("lwip_bind: invalid address", (IS_SOCK_ADDR_LEN_VALID(namelen) && + IS_SOCK_ADDR_TYPE_VALID(name) && IS_SOCK_ADDR_ALIGNED(name)), + sock_set_errno(sock, err_to_errno(ERR_ARG)); done_socket(sock); return -1;); +- LWIP_UNUSED_ARG(namelen); ++ LWIP_UNUSED_ARG(namelen); + +- SOCKADDR_TO_IPADDR_PORT(name, &local_addr, local_port); +- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d, addr=", s)); +- ip_addr_debug_print_val(SOCKETS_DEBUG, local_addr); +- LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F")\n", local_port)); ++ SOCKADDR_TO_IPADDR_PORT(name, &local_addr, local_port); ++ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d, addr=", s)); ++ ip_addr_debug_print_val(SOCKETS_DEBUG, local_addr); ++ LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F")\n", local_port)); + } -+ -+#if CHECKSUM_GEN_ICMP6 -+ IF__NETIF_CHECKSUM_ENABLED(netif, NETIF_CHECKSUM_GEN_ICMP6) { -+ na_hdr->chksum = ip6_chksum_pseudo(p, IP6_NEXTH_ICMP6, p->len, src_addr, -+ dest_addr); + + #if LWIP_IPV4 && LWIP_IPV6 + /* Dual-stack: Unmap IPv4 mapped IPv6 addresses */ +@@ -753,7 +860,11 @@ + } + #endif /* LWIP_IPV4 && LWIP_IPV6 */ + ++#if PF_PACKET_SOCKET ++ err = netconn_bind(sock->conn, &local_addr, local_port, local_if_idx); ++#else /* PF_PACKET_SOCKET */ + err = netconn_bind(sock->conn, &local_addr, local_port); ++#endif + + if (err != ERR_OK) { + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d) failed, err=%d\n", s, err)); +@@ -820,6 +931,14 @@ + return -1; + } + ++#if PF_PACKET_SOCKET ++ if (NETCONN_PACKET_RAW & NETCONNTYPE_GROUP(netconn_type(sock->conn))) { ++ sock_set_errno(sock, EOPNOTSUPP); ++ done_socket(sock); ++ return -1; + } -+#endif /* CHECKSUM_GEN_ICMP6 */ -+ -+ /* Send the packet out. */ -+ ND6_STATS_INC(nd6.xmit); -+ ip6_output_if(p, src_addr, dest_addr, -+ ND6_HOPLIM, 0, IP6_NEXTH_ICMP6, netif); -+ pbuf_free(p); -+} -+ -+#if LWIP_IPV6_SEND_ROUTER_SOLICIT -+/** -+ * Send a router solicitation message -+ * -+ * @param netif the netif on which to send the message -+ */ -+static err_t -+nd6_send_rs(struct netif *netif) -+{ -+ struct rs_header *rs_hdr; -+ struct lladdr_option *lladdr_opt; -+ struct pbuf *p; -+ const ip6_addr_t *src_addr; -+ err_t err; -+ u16_t lladdr_opt_len = 0; ++#endif + -+ /* Link-local source address, or unspecified address? */ -+ if (ip6_addr_isvalid(netif_ip6_addr_state(netif, 0))) { -+ src_addr = netif_ip6_addr(netif, 0); + if (!SOCK_ADDR_TYPE_MATCH_OR_UNSPEC(name, sock)) { + /* sockaddr does not match socket type (IPv4/IPv6) */ + sock_set_errno(sock, err_to_errno(ERR_VAL)); +@@ -1025,6 +1144,7 @@ + { + int truncated = 0; + union sockaddr_aligned saddr; ++ socklen_t sa_len; + + LWIP_UNUSED_ARG(conn); + +@@ -1041,10 +1161,20 @@ + #endif /* LWIP_IPV4 && LWIP_IPV6 */ + + IPADDR_PORT_TO_SOCKADDR(&saddr, fromaddr, port); +- if (*fromlen < saddr.sa.sa_len) { ++#if LWIP_LITEOS_COMPAT ++ if (IP_IS_V4_VAL(*fromaddr)) { ++ sa_len = sizeof(struct sockaddr_in); + } else { -+ src_addr = IP6_ADDR_ANY6; -+ } -+ -+ /* Generate the all routers target address. */ -+ ip6_addr_set_allrouters_linklocal(&multicast_address); -+ ip6_addr_assign_zone(&multicast_address, IP6_MULTICAST, netif); -+ -+ /* Allocate a packet. */ -+ if (src_addr != IP6_ADDR_ANY6) { -+ lladdr_opt_len = ((netif->hwaddr_len + 2) >> 3) + (((netif->hwaddr_len + 2) & 0x07) ? 1 : 0); -+ } -+ p = pbuf_alloc(PBUF_IP, sizeof(struct rs_header) + (lladdr_opt_len << 3), PBUF_RAM); -+ if (p == NULL) { -+ ND6_STATS_INC(nd6.memerr); -+ return ERR_BUF; -+ } -+ -+ /* Set fields. */ -+ rs_hdr = (struct rs_header *)p->payload; -+ -+ rs_hdr->type = ICMP6_TYPE_RS; -+ rs_hdr->code = 0; -+ rs_hdr->chksum = 0; -+ rs_hdr->reserved = 0; -+ -+ if (src_addr != IP6_ADDR_ANY6) { -+ /* Include our hw address. */ -+ lladdr_opt = (struct lladdr_option *)((u8_t*)p->payload + sizeof(struct rs_header)); -+ lladdr_opt->type = ND6_OPTION_TYPE_SOURCE_LLADDR; -+ lladdr_opt->length = (u8_t)lladdr_opt_len; -+ SMEMCPY(lladdr_opt->addr, netif->hwaddr, netif->hwaddr_len); -+ } -+ -+#if CHECKSUM_GEN_ICMP6 -+ IF__NETIF_CHECKSUM_ENABLED(netif, NETIF_CHECKSUM_GEN_ICMP6) { -+ rs_hdr->chksum = ip6_chksum_pseudo(p, IP6_NEXTH_ICMP6, p->len, src_addr, -+ &multicast_address); ++ sa_len = sizeof(struct sockaddr_in6); + } -+#endif /* CHECKSUM_GEN_ICMP6 */ ++#else ++ sa_len = saddr.sa.sa_len; ++#endif /* LWIP_LITEOS_COMPAT */ + -+ /* Send the packet out. */ -+ ND6_STATS_INC(nd6.xmit); ++ if (*fromlen < sa_len) { + truncated = 1; +- } else if (*fromlen > saddr.sa.sa_len) { +- *fromlen = saddr.sa.sa_len; ++ } else if (*fromlen > sa_len) { ++ *fromlen = sa_len; + } + MEMCPY(from, &saddr, *fromlen); + return truncated; +@@ -1146,8 +1276,44 @@ + ip_addr_debug_print_val(SOCKETS_DEBUG, *netbuf_fromaddr(buf)); + LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F" len=%d\n", netbuf_fromport(buf), copied)); + if (msg->msg_name && msg->msg_namelen) { +- lwip_sock_make_addr(sock->conn, netbuf_fromaddr(buf), netbuf_fromport(buf), +- (struct sockaddr *)msg->msg_name, &msg->msg_namelen); ++#if PF_PACKET_SOCKET & LWIP_LITEOS_COMPAT ++ struct sockaddr_ll sll; + -+ err = ip6_output_if(p, (src_addr == IP6_ADDR_ANY6) ? NULL : src_addr, &multicast_address, -+ ND6_HOPLIM, 0, IP6_NEXTH_ICMP6, netif); -+ pbuf_free(p); ++ if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) & NETCONN_PACKET_RAW) { ++ if (msg->msg_namelen > sizeof(sll)) { ++ msg->msg_namelen = sizeof(sll); ++ } + -+ return err; -+} -+#endif /* LWIP_IPV6_SEND_ROUTER_SOLICIT */ ++ if (msg->msg_namelen) { ++ (void)memset_s(&sll, sizeof(sll), 0, sizeof(sll)); ++ sll.sll_family = PF_PACKET; ++ sll.sll_protocol = netbuf_fromport(buf); ++ sll.sll_hatype = netbuf_fromhatype(buf); ++ sll.sll_ifindex = netbuf_fromifindex(buf); + -+/** -+ * Search for a neighbor cache entry -+ * -+ * @param ip6addr the IPv6 address of the neighbor -+ * @return The neighbor cache entry index that matched, -1 if no -+ * entry is found -+ */ -+static s8_t -+nd6_find_neighbor_cache_entry(const ip6_addr_t *ip6addr) -+{ -+ s8_t i; -+ for (i = 0; i < LWIP_ND6_NUM_NEIGHBORS; i++) { -+ if (ip6_addr_cmp(ip6addr, &(neighbor_cache[i].next_hop_address))) { -+ return i; -+ } -+ } -+ return -1; -+} ++ if (buf->p->flags & PBUF_FLAG_LLBCAST) { ++ sll.sll_pkttype = PACKET_BROADCAST; ++ } else if (buf->p->flags & PBUF_FLAG_LLMCAST) { ++ sll.sll_pkttype = PACKET_MULTICAST; ++ } else if (buf->p->flags & PBUF_FLAG_HOST) { ++ sll.sll_pkttype = PACKET_HOST; ++ } else if (buf->p->flags & PBUF_FLAG_OUTGOING) { ++ sll.sll_pkttype = PACKET_OUTGOING; ++ } else { ++ sll.sll_pkttype = PACKET_OTHERHOST; ++ } + -+/** -+ * Create a new neighbor cache entry. -+ * -+ * If no unused entry is found, will try to recycle an old entry -+ * according to ad-hoc "age" heuristic. -+ * -+ * @return The neighbor cache entry index that was created, -1 if no -+ * entry could be created -+ */ -+static s8_t -+nd6_new_neighbor_cache_entry(void) -+{ -+ s8_t i; -+ s8_t j; -+ u32_t time; ++ (void)memcpy_s(msg->msg_name, msg->msg_namelen, (void *)&sll, msg->msg_namelen); + ++ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom_udp_raw(%d): hatype=%u", dbg_s, ntohs(sll.sll_hatype))); ++ LWIP_DEBUGF(SOCKETS_DEBUG, (" packet type = %u\n", sll.sll_pkttype)); ++ } ++ } else ++#endif /* PF_PACKET_SOCKET & LWIP_LITEOS_COMPAT */ ++ { ++ lwip_sock_make_addr(sock->conn, netbuf_fromaddr(buf), netbuf_fromport(buf), ++ (struct sockaddr *)msg->msg_name, &msg->msg_namelen); ++ } + } + } + +@@ -1496,7 +1662,7 @@ + goto sendmsg_emsgsize; + } + /* Allocate a new netbuf and copy the data into it. */ +- if (netbuf_alloc(&chain_buf, (u16_t)size) == NULL) { ++ if (netbuf_alloc(&chain_buf, (u16_t)size, NETCONNTYPE_GROUP(netconn_type(sock->conn))) == NULL) { + err = ERR_MEM; + } else { + /* flatten the IO vectors */ +@@ -1588,8 +1754,14 @@ + struct lwip_sock *sock; + err_t err; + u16_t short_size; +- u16_t remote_port; ++ u16_t remote_port = 0; + struct netbuf buf; ++#if (PF_PACKET_SOCKET & LWIP_LITEOS_COMPAT) ++ const struct sockaddr_ll *to_ll = NULL; ++#endif ++ const struct sockaddr_in *to_in = NULL; + -+ /* First, try to find an empty entry. */ -+ for (i = 0; i < LWIP_ND6_NUM_NEIGHBORS; i++) { -+ if (neighbor_cache[i].state == ND6_NO_ENTRY) { -+ return i; -+ } -+ } ++ unsigned int acceptable_flags = 0; + + sock = get_socket(s); + if (!sock) { +@@ -1608,11 +1780,62 @@ + #endif /* LWIP_TCP */ + } + +- if (size > LWIP_MIN(0xFFFF, SSIZE_MAX)) { +- /* cannot fit into one datagram (at least for us) */ +- sock_set_errno(sock, EMSGSIZE); +- done_socket(sock); +- return -1; ++#if PF_PACKET_SOCKET ++ if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) & NETCONN_PACKET_RAW) { ++ to_ll = (const struct sockaddr_ll *)(void *)to; + -+ /* We need to recycle an entry. in general, do not recycle if it is a router. */ ++ LWIP_ERROR("lwip_sendto: invalid address", (((data != NULL) && (size!=0)) && ++ (((to_ll != NULL) && (tolen == sizeof(struct sockaddr_ll))) && ++ ((to_ll->sll_family) == PF_PACKET) && ((((mem_ptr_t)to_ll) % 4) == 0)) && ++ (to_ll->sll_ifindex <= LWIP_NETIF_IFINDEX_MAX)), ++ sock_set_errno(sock, err_to_errno(ERR_VAL)); ++ done_socket(sock); return -1); + -+ /* Next, try to find a Stale entry. */ -+ for (i = 0; i < LWIP_ND6_NUM_NEIGHBORS; i++) { -+ if ((neighbor_cache[i].state == ND6_STALE) && -+ (!neighbor_cache[i].isrouter)) { -+ nd6_free_neighbor_cache_entry(i); -+ return i; -+ } -+ } ++ LWIP_ERROR("lwip_sendto: invalid address family", ((to_ll->sll_family) == PF_PACKET), ++ sock_set_errno(sock, err_to_errno(ERR_AFNOSUPP)); ++ done_socket(sock); return -1); + -+ /* Next, try to find a Probe entry. */ -+ for (i = 0; i < LWIP_ND6_NUM_NEIGHBORS; i++) { -+ if ((neighbor_cache[i].state == ND6_PROBE) && -+ (!neighbor_cache[i].isrouter)) { -+ nd6_free_neighbor_cache_entry(i); -+ return i; -+ } -+ } ++ LWIP_ERROR("lwip_sendto: invalid flags. Should be 0", (flags == 0), ++ sock_set_errno(sock, err_to_errno(ERR_OPNOTSUPP)); ++ done_socket(sock); return -1); + -+ /* Next, try to find a Delayed entry. */ -+ for (i = 0; i < LWIP_ND6_NUM_NEIGHBORS; i++) { -+ if ((neighbor_cache[i].state == ND6_DELAY) && -+ (!neighbor_cache[i].isrouter)) { -+ nd6_free_neighbor_cache_entry(i); -+ return i; ++ if (size > LWIP_MAX_PF_RAW_SEND_SIZE) { ++ sock_set_errno(sock, EMSGSIZE); ++ done_socket(sock); ++ return -1; + } -+ } -+ -+ /* Next, try to find the oldest reachable entry. */ -+ time = 0xfffffffful; -+ j = -1; -+ for (i = 0; i < LWIP_ND6_NUM_NEIGHBORS; i++) { -+ if ((neighbor_cache[i].state == ND6_REACHABLE) && -+ (!neighbor_cache[i].isrouter)) { -+ if (neighbor_cache[i].counter.reachable_time < time) { -+ j = i; -+ time = neighbor_cache[i].counter.reachable_time; -+ } ++ } else ++#endif /* PF_PACKET_SOCKET */ ++ { ++ to_in = (const struct sockaddr_in *)(void*)to; ++ acceptable_flags = acceptable_flags | MSG_MORE | MSG_DONTWAIT | MSG_NOSIGNAL; ++ if ((~acceptable_flags) & (unsigned int)flags) { ++ sock_set_errno(sock, err_to_errno(ERR_OPNOTSUPP)); ++ done_socket(sock); ++ return -1; + } -+ } -+ if (j >= 0) { -+ nd6_free_neighbor_cache_entry(j); -+ return j; -+ } + -+ /* Next, find oldest incomplete entry without queued packets. */ -+ time = 0; -+ j = -1; -+ for (i = 0; i < LWIP_ND6_NUM_NEIGHBORS; i++) { -+ if ( -+ (neighbor_cache[i].q == NULL) && -+ (neighbor_cache[i].state == ND6_INCOMPLETE) && -+ (!neighbor_cache[i].isrouter)) { -+ if (neighbor_cache[i].counter.probes_sent >= time) { -+ j = i; -+ time = neighbor_cache[i].counter.probes_sent; -+ } -+ } -+ } -+ if (j >= 0) { -+ nd6_free_neighbor_cache_entry(j); -+ return j; -+ } ++ LWIP_ERROR("lwip_sendto: invalid address", ((data != NULL) && (size!=0) && (flags>=0)), ++ sock_set_errno(sock, err_to_errno(ERR_VAL)); ++ done_socket(sock); return -1); + -+ /* Next, find oldest incomplete entry with queued packets. */ -+ time = 0; -+ j = -1; -+ for (i = 0; i < LWIP_ND6_NUM_NEIGHBORS; i++) { -+ if ((neighbor_cache[i].state == ND6_INCOMPLETE) && -+ (!neighbor_cache[i].isrouter)) { -+ if (neighbor_cache[i].counter.probes_sent >= time) { -+ j = i; -+ time = neighbor_cache[i].counter.probes_sent; -+ } -+ } -+ } -+ if (j >= 0) { -+ nd6_free_neighbor_cache_entry(j); -+ return j; -+ } ++ LWIP_ERROR("lwip_sendto: invalid address", (((to_in == NULL) && (tolen == 0)) || ++ (((to_in == NULL) && (tolen != 0)) || IS_SOCK_ADDR_LEN_VALID(tolen))), ++ sock_set_errno(sock, err_to_errno(ERR_VAL)); ++ done_socket(sock); ++ return -1); + -+ /* No more entries to try. */ -+ return -1; -+} ++ LWIP_ERROR("lwip_sendto: invalid address", (to == NULL || IS_SOCK_ADDR_TYPE_VALID(to)), ++ sock_set_errno(sock, err_to_errno(ERR_AFNOSUPPORT)); ++ done_socket(sock); ++ return -1); + -+/** -+ * Will free any resources associated with a neighbor cache -+ * entry, and will mark it as unused. -+ * -+ * @param i the neighbor cache entry index to free -+ */ -+static void -+nd6_free_neighbor_cache_entry(s8_t i) -+{ -+ if ((i < 0) || (i >= LWIP_ND6_NUM_NEIGHBORS)) { -+ return; -+ } -+ if (neighbor_cache[i].isrouter) { -+ /* isrouter needs to be cleared before deleting a neighbor cache entry */ -+ return; -+ } ++ if (size > LWIP_MAX_UDP_RAW_SEND_SIZE) { ++ sock_set_errno(sock, EMSGSIZE); ++ done_socket(sock); ++ return -1; ++ } + -+ /* Free any queued packets. */ -+ if (neighbor_cache[i].q != NULL) { -+ nd6_free_q(neighbor_cache[i].q); -+ neighbor_cache[i].q = NULL; + } + short_size = (u16_t)size; + LWIP_ERROR("lwip_sendto: invalid address", (((to == NULL) && (tolen == 0)) || +@@ -1626,6 +1849,9 @@ + #if LWIP_CHECKSUM_ON_COPY + buf.flags = 0; + #endif /* LWIP_CHECKSUM_ON_COPY */ ++#if PF_PACKET_SOCKET ++ buf.netifindex = 0; ++#endif + if (to) { + SOCKADDR_TO_IPADDR_PORT(to, &buf.addr, remote_port); + } else { +@@ -1637,17 +1863,29 @@ + + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_sendto(%d, data=%p, short_size=%"U16_F", flags=0x%x to=", + s, data, short_size, flags)); +- ip_addr_debug_print_val(SOCKETS_DEBUG, buf.addr); +- LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F"\n", remote_port)); +- ++#if PF_PACKET_SOCKET ++ if (buf.flags & NETBUF_FLAG_IFINDEX) { ++ LWIP_DEBUGF(SOCKETS_DEBUG, (" netifindex = %d\n", buf.netifindex)); ++ } else ++#endif ++ { ++ ip_addr_debug_print_val(SOCKETS_DEBUG, buf.addr); ++ LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F"\n", remote_port)); + } + /* make the buffer point to the data that should be sent */ + #if LWIP_NETIF_TX_SINGLE_PBUF + /* Allocate a new netbuf and copy the data into it. */ +- if (netbuf_alloc(&buf, short_size) == NULL) { ++ if (netbuf_alloc(&buf, short_size, NETCONNTYPE_GROUP(netconn_type(sock->conn))) == NULL) { + err = ERR_MEM; + } else { + #if LWIP_CHECKSUM_ON_COPY +- if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_RAW) { ++#if PF_PACKET_SOCKET ++ if ((NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_PACKET_RAW) && ++ (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_RAW)) ++#else ++ if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_RAW) ++#endif ++ { + u16_t chksum = LWIP_CHKSUM_COPY(buf.p->payload, data, short_size); + netbuf_set_chksum(&buf, chksum); + } else +@@ -1688,14 +1926,32 @@ + int i; + + LWIP_UNUSED_ARG(domain); /* @todo: check this */ ++ LWIP_ERROR("domain invalid\n", (LWIP_IS_VALID_DOMAIN(domain)), ++ set_errno(EAFNOSUPPORT); return -1); + -+ neighbor_cache[i].state = ND6_NO_ENTRY; -+ neighbor_cache[i].isrouter = 0; -+ neighbor_cache[i].netif = NULL; -+ neighbor_cache[i].counter.reachable_time = 0; -+ ip6_addr_set_zero(&(neighbor_cache[i].next_hop_address)); -+} -+ -+/** -+ * Search for a destination cache entry -+ * -+ * @param ip6addr the IPv6 address of the destination -+ * @return The destination cache entry index that matched, -1 if no -+ * entry is found -+ */ -+static s16_t -+nd6_find_destination_cache_entry(const ip6_addr_t *ip6addr) -+{ -+ s16_t i; ++ LWIP_ERROR("flag invalid\n", !(type & ~SOCK_TYPE_MASK), ++ set_errno(EINVAL); return -1); ++#if PF_PACKET_SOCKET ++ LWIP_ERROR("Invalid socket type for PF_PACKET domain\n", ((domain != PF_PACKET) || (type == SOCK_RAW)), ++ set_errno(ESOCKTNOSUPPORT); return -1); ++#endif + + /* create a netconn */ + switch (type) { + case SOCK_RAW: +- conn = netconn_new_with_proto_and_callback(DOMAIN_TO_NETCONN_TYPE(domain, NETCONN_RAW), +- (u8_t)protocol, DEFAULT_SOCKET_EVENTCB); +- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_RAW, %d) = ", ++#if PF_PACKET_SOCKET ++ if (domain == PF_PACKET) { ++ conn = netconn_new_with_proto_and_callback(DOMAIN_TO_NETCONN_TYPE(domain, NETCONN_PACKET_RAW), ++ (u16_t)protocol, event_callback); ++ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_RAW, %d) = ", "PF_PACKET", protocol)); ++ } else ++#endif ++ { ++ conn = netconn_new_with_proto_and_callback(DOMAIN_TO_NETCONN_TYPE(domain, NETCONN_RAW), ++ (u8_t)protocol, DEFAULT_SOCKET_EVENTCB); ++ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_RAW, %d) = ", + domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol)); ++ } + break; + case SOCK_DGRAM: + conn = netconn_new_with_callback(DOMAIN_TO_NETCONN_TYPE(domain, +@@ -1983,10 +2239,11 @@ + timeout ? (s32_t)timeout->tv_sec : (s32_t) - 1, + timeout ? (s32_t)timeout->tv_usec : (s32_t) - 1)); + +- if ((maxfdp1 < 0) || (maxfdp1 > LWIP_SELECT_MAXNFDS)) { ++/*if ((maxfdp1 < 0) || (maxfdp1 > LWIP_SELECT_MAXNFDS)) { + set_errno(EINVAL); + return -1; + } ++ */ + + lwip_select_inc_sockets_used(maxfdp1, readset, writeset, exceptset, &used_sockets); + +@@ -2704,12 +2961,60 @@ + ip_addr_t naddr; + u16_t port; + err_t err; ++ socklen_t sa_len; + -+ IP6_ADDR_ZONECHECK(ip6addr); ++#if PF_PACKET_SOCKET ++ struct sockaddr_ll addr_sin; ++ struct pf_packet_sockaddr_ll sll; ++ socklen_t outlen; ++#endif + -+ for (i = 0; i < LWIP_ND6_NUM_DESTINATIONS; i++) { -+ if (ip6_addr_cmp(ip6addr, &(destination_cache[i].destination_addr))) { -+ return i; ++ LWIP_ERROR("lwip_getaddrname: invalid arguments", ((name != NULL) && (namelen != NULL)), ++ set_errno(EINVAL); return -1); + + sock = get_socket(s); + if (!sock) { + return -1; + } + ++#if PF_PACKET_SOCKET ++ if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_PACKET_RAW) { ++ err = netconn_get_sockaddr_pf_packet(sock->conn, &sll, local); ++ if (err != ERR_OK) { ++ sock_set_errno(sock, err_to_errno(err)); ++ done_socket(sock); ++ return -1; + } -+ } -+ return -1; -+} + -+/** -+ * Create a new destination cache entry. If no unused entry is found, -+ * will recycle oldest entry. -+ * -+ * @return The destination cache entry index that was created, -1 if no -+ * entry was created -+ */ -+static s16_t -+nd6_new_destination_cache_entry(void) -+{ -+ s16_t i, j; -+ u32_t age; ++ (void)memset_s(&addr_sin, sizeof(struct sockaddr_ll), 0, sizeof(struct sockaddr_ll)); ++ addr_sin.sll_family = PF_PACKET; ++ addr_sin.sll_protocol = sll.sll_protocol; ++ addr_sin.sll_pkttype = 0; ++ addr_sin.sll_ifindex = sll.if_idx; ++ addr_sin.sll_hatype = sll.sll_hatype; ++ addr_sin.sll_halen = sll.sll_halen; + -+ /* Find an empty entry. */ -+ for (i = 0; i < LWIP_ND6_NUM_DESTINATIONS; i++) { -+ if (ip6_addr_isany(&(destination_cache[i].destination_addr))) { -+ return i; ++ if ((sll.sll_halen > 0) && (memcpy_s(addr_sin.sll_addr, addr_sin.sll_halen, sll.sll_addr, sll.sll_halen) != EOK)) { ++ sock_set_errno(sock, err_to_errno(ERR_MEM)); ++ done_socket(sock); ++ return -1; + } -+ } + -+ /* Find oldest entry. */ -+ age = 0; -+ j = LWIP_ND6_NUM_DESTINATIONS - 1; -+ for (i = 0; i < LWIP_ND6_NUM_DESTINATIONS; i++) { -+ if (destination_cache[i].age > age) { -+ j = i; ++ outlen = sizeof(struct sockaddr_ll); ++ if (outlen > *namelen) { ++ outlen = *namelen; + } ++ if (memcpy_s(name, *namelen, &addr_sin, outlen) != EOK) { ++ sock_set_errno(sock, err_to_errno(ERR_MEM)); ++ done_socket(sock); ++ return -1; ++ } ++ *namelen = outlen; ++ done_socket(sock); ++ return 0; + } ++#endif /* PF_PACKET_SOCKET */ + -+ return j; -+} -+ -+/** -+ * Clear the destination cache. -+ * -+ * This operation may be necessary for consistency in the light of changing -+ * local addresses and/or use of the gateway hook. -+ */ -+void -+nd6_clear_destination_cache(void) -+{ -+ int i; -+ -+ for (i = 0; i < LWIP_ND6_NUM_DESTINATIONS; i++) { -+ ip6_addr_set_any(&destination_cache[i].destination_addr); -+ } -+} -+ -+/** -+ * Determine whether an address matches an on-link prefix or the subnet of a -+ * statically assigned address. -+ * -+ * @param ip6addr the IPv6 address to match -+ * @return 1 if the address is on-link, 0 otherwise -+ */ -+static int -+nd6_is_prefix_in_netif(const ip6_addr_t *ip6addr, struct netif *netif) -+{ -+ s8_t i; -+ -+ /* Check to see if the address matches an on-link prefix. */ -+ for (i = 0; i < LWIP_ND6_NUM_PREFIXES; i++) { -+ if ((prefix_list[i].netif == netif) && -+ (prefix_list[i].invalidation_timer > 0) && -+ ip6_addr_netcmp(ip6addr, &(prefix_list[i].prefix))) { -+ return 1; -+ } + /* get the IP address and port */ + err = netconn_getaddr(sock->conn, &naddr, &port, local); + if (err != ERR_OK) { +@@ -2732,9 +3037,14 @@ + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getaddrname(%d, addr=", s)); + ip_addr_debug_print_val(SOCKETS_DEBUG, naddr); + LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F")\n", port)); ++ if (IP_IS_V4_VAL(naddr)) { ++ sa_len = sizeof(struct sockaddr_in); ++ } else { ++ sa_len = sizeof(struct sockaddr_in6); + } -+ /* Check to see if address prefix matches a manually configured (= static) -+ * address. Static addresses have an implied /64 subnet assignment. Dynamic -+ * addresses (from autoconfiguration) have no implied subnet assignment, and -+ * are thus effectively /128 assignments. See RFC 5942 for more on this. */ -+ for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) { -+ if (ip6_addr_isvalid(netif_ip6_addr_state(netif, i)) && -+ netif_ip6_addr_isstatic(netif, i) && -+ ip6_addr_netcmp(ip6addr, netif_ip6_addr(netif, i))) { -+ return 1; -+ } + +- if (*namelen > saddr.sa.sa_len) { +- *namelen = saddr.sa.sa_len; ++ if (*namelen > sa_len) { ++ *namelen = sa_len; + } + MEMCPY(name, &saddr, *namelen); + +@@ -2775,6 +3085,14 @@ + return -1; + } + ++#if PF_PACKET_SOCKET ++ VALIDATE_LEVEL_PF_PACKET(sock, level) { ++ sock_set_errno(sock, EINVAL); ++ done_socket(sock); ++ return -1; + } -+ return 0; -+} ++#endif /* PF_PACKET_SOCKET */ + -+/** -+ * Select a default router for a destination. -+ * -+ * This function is used both for routing and for finding a next-hop target for -+ * a packet. In the former case, the given netif is NULL, and the returned -+ * router entry must be for a netif suitable for sending packets (up, link up). -+ * In the latter case, the given netif is not NULL and restricts router choice. -+ * -+ * @param ip6addr the destination address -+ * @param netif the netif for the outgoing packet, if known -+ * @return the default router entry index, or -1 if no suitable -+ * router is found -+ */ -+static s8_t -+nd6_select_router(const ip6_addr_t *ip6addr, struct netif *netif) + #if LWIP_TCPIP_CORE_LOCKING + /* core-locking can just call the -impl function */ + LOCK_TCPIP_CORE(); +@@ -2826,8 +3144,9 @@ + err = LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).err; + LWIP_SETGETSOCKOPT_DATA_VAR_FREE(data); + #endif /* LWIP_TCPIP_CORE_LOCKING */ +- +- sock_set_errno(sock, err); ++ if (err != ERR_OK) { ++ sock_set_errno(sock, err); ++ } + done_socket(sock); + return err ? -1 : 0; + } +@@ -2897,6 +3216,11 @@ + + /* Level: SOL_SOCKET */ + case SOL_SOCKET: ++#if PF_PACKET_SOCKET ++ case SOL_PACKET: ++ VALIDATE_GET_PF_PKT_OPTNAME_RET(s, sock, level, optname); ++#endif /* PF_PACKET_SOCKET */ ++ VALIDATE_GET_RAW_OPTNAME_RET(sock, optname); + switch (optname) { + + #if LWIP_TCP +@@ -2920,6 +3244,10 @@ + #if SO_REUSE + case SO_REUSEADDR: + #endif /* SO_REUSE */ ++ if (sock->conn == NULL) { ++ done_socket(sock); ++ return EINVAL; ++ } + if ((optname == SO_BROADCAST) && + (NETCONNTYPE_GROUP(sock->conn->type) != NETCONN_UDP)) { + done_socket(sock); +@@ -2937,6 +3265,9 @@ + case SO_TYPE: + LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, *optlen, int); + switch (NETCONNTYPE_GROUP(netconn_type(sock->conn))) { ++#if PF_PACKET_SOCKET ++ case NETCONN_PACKET_RAW: ++#endif + case NETCONN_RAW: + *(int *)optval = SOCK_RAW; + break; +@@ -2948,9 +3279,16 @@ + break; + default: /* unrecognized socket type */ + *(int *)optval = netconn_type(sock->conn); ++#if PF_PACKET_SOCKET ++ LWIP_DEBUGF(SOCKETS_DEBUG, ++ ("lwip_getsockopt(%d, %s, SO_TYPE): unrecognized socket type %d\n", ++ s, (NETCONN_PACKET_RAW != NETCONNTYPE_GROUP(sock->conn->type)) ? "SOL_SOCKET" : "SOL_PACKET", ++ *(int *)optval)); ++#else + LWIP_DEBUGF(SOCKETS_DEBUG, + ("lwip_getsockopt(%d, SOL_SOCKET, SO_TYPE): unrecognized socket type %d\n", + s, *(int *)optval)); ++#endif + } /* switch (netconn_type(sock->conn)) */ + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, SO_TYPE) = %d\n", + s, *(int *)optval)); +@@ -3739,92 +4077,450 @@ + return err; + } + +-int +-lwip_ioctl(int s, long cmd, void *argp) ++#if PF_PACKET_SOCKET ++#if LWIP_IOCTL_IF ++static u8_t lwip_ioctl_internal_SIOCGIFCONF(struct ifreq *ifr) +{ -+ struct netif *router_netif; -+ s8_t i, j, valid_router; -+ static s8_t last_router; ++ struct ifconf *ifc = NULL; ++ struct netif *netif = NULL; ++ struct ifreq ifreq; ++ struct sockaddr_in *sock_in = NULL; ++ int pos; ++ int len; ++ int ret; + -+ LWIP_UNUSED_ARG(ip6addr); /* @todo match preferred routes!! (must implement ND6_OPTION_TYPE_ROUTE_INFO) */ ++ /* Format the caller's buffer. */ ++ ifc = (struct ifconf*)ifr; ++ len = ifc->ifc_len; + -+ /* @todo: implement default router preference */ ++ /* Loop over the interfaces, and write an info block for each. */ ++ pos = 0; ++ for (netif = netif_list; netif != NULL; netif = netif->next) { ++ if (ifc->ifc_buf == NULL) { ++ pos = (pos + (int)sizeof(struct ifreq)); ++ continue; ++ } + -+ /* Look for valid routers. A reachable router is preferred. */ -+ valid_router = -1; -+ for (i = 0; i < LWIP_ND6_NUM_ROUTERS; i++) { -+ /* Is the router netif both set and apppropriate? */ -+ if (default_router_list[i].neighbor_entry != NULL) { -+ router_netif = default_router_list[i].neighbor_entry->netif; -+ if ((router_netif != NULL) && (netif != NULL ? netif == router_netif : -+ (netif_is_up(router_netif) && netif_is_link_up(router_netif)))) { -+ /* Is the router valid, i.e., reachable or probably reachable as per -+ * RFC 4861 Sec. 6.3.6? Note that we will never return a router that -+ * has no neighbor cache entry, due to the netif association tests. */ -+ if (default_router_list[i].neighbor_entry->state != ND6_INCOMPLETE) { -+ /* Is the router known to be reachable? */ -+ if (default_router_list[i].neighbor_entry->state == ND6_REACHABLE) { -+ return i; /* valid and reachable - done! */ -+ } else if (valid_router < 0) { -+ valid_router = i; /* valid but not known to be reachable */ -+ } -+ } -+ } ++ if (len < (int)sizeof(ifreq)) { ++ break; + } -+ } -+ if (valid_router >= 0) { -+ return valid_router; -+ } + -+ /* Look for any router for which we have any information at all. */ -+ /* last_router is used for round-robin selection of incomplete routers, as -+ * recommended in RFC 4861 Sec. 6.3.6 point (2). Advance only when picking a -+ * route, to select the same router as next-hop target in the common case. */ -+ if ((netif == NULL) && (++last_router >= LWIP_ND6_NUM_ROUTERS)) { -+ last_router = 0; -+ } -+ i = last_router; -+ for (j = 0; j < LWIP_ND6_NUM_ROUTERS; j++) { -+ if (default_router_list[i].neighbor_entry != NULL) { -+ router_netif = default_router_list[i].neighbor_entry->netif; -+ if ((router_netif != NULL) && (netif != NULL ? netif == router_netif : -+ (netif_is_up(router_netif) && netif_is_link_up(router_netif)))) { -+ return i; -+ } ++ if (memset_s(&ifreq, sizeof(struct ifreq), 0, sizeof(struct ifreq)) != EOK) { ++ return ENOBUFS; + } -+ if (++i >= LWIP_ND6_NUM_ROUTERS) { -+ i = 0; ++ if (netif->link_layer_type == LOOPBACK_IF) { ++ ret = snprintf_s(ifreq.ifr_name, NETIF_NAMESIZE, (NETIF_NAMESIZE - 1), "%s", netif->name); ++ if ((ret <= 0) || (ret >= IFNAMSIZ)) { ++ LWIP_DEBUGF(NETIF_DEBUG, ("lwip_ioctl: snprintf_s ifr_name failed.")); ++ return ENOBUFS; ++ } ++ } else { ++ ret = snprintf_s(ifreq.ifr_name, NETIF_NAMESIZE, NETIF_NAMESIZE - 1, "%s%"U8_F, netif->name, netif->num); ++ if ((ret <= 0) || (ret >= NETIF_NAMESIZE)) { ++ LWIP_DEBUGF(NETIF_DEBUG, ("lwip_ioctl: snprintf_s ifr_name failed.")); ++ return ENOBUFS; ++ } + } -+ } -+ -+ /* no suitable router found. */ -+ return -1; -+} -+ -+/** -+ * Find a router-announced route to the given destination. This route may be -+ * based on an on-link prefix or a default router. -+ * -+ * If a suitable route is found, the returned netif is guaranteed to be in a -+ * suitable state (up, link up) to be used for packet transmission. -+ * -+ * @param ip6addr the destination IPv6 address -+ * @return the netif to use for the destination, or NULL if none found -+ */ -+struct netif * -+nd6_find_route(const ip6_addr_t *ip6addr) -+{ -+ struct netif *netif; -+ s8_t i; + -+ /* @todo decide if it makes sense to check the destination cache first */ -+ -+ /* Check if there is a matching on-link prefix. There may be multiple -+ * matches. Pick the first one that is associated with a suitable netif. */ -+ for (i = 0; i < LWIP_ND6_NUM_PREFIXES; ++i) { -+ netif = prefix_list[i].netif; -+ if ((netif != NULL) && ip6_addr_netcmp(&prefix_list[i].prefix, ip6addr) && -+ netif_is_up(netif) && netif_is_link_up(netif)) { -+ return netif; ++ sock_in = (struct sockaddr_in *)&ifreq.ifr_addr; ++ sock_in->sin_family = AF_INET; ++ sock_in->sin_addr.s_addr = ip_2_ip4(&netif->ip_addr)->addr; ++ if (memcpy_s(ifc->ifc_buf + pos, sizeof(struct ifreq), &ifreq, sizeof(struct ifreq)) != EOK) { ++ return ENOBUFS; + } ++ pos += (int)sizeof(struct ifreq); ++ len -= (int)sizeof(struct ifreq); + } + -+ /* No on-link prefix match. Find a router that can forward the packet. */ -+ i = nd6_select_router(ip6addr, NULL); -+ if (i >= 0) { -+ LWIP_ASSERT("selected router must have a neighbor entry", -+ default_router_list[i].neighbor_entry != NULL); -+ return default_router_list[i].neighbor_entry->netif; -+ } ++ ifc->ifc_len = pos; + -+ return NULL; ++ return 0; +} + -+/** -+ * Find an entry for a default router. -+ * -+ * @param router_addr the IPv6 address of the router -+ * @param netif the netif on which the router is found, if known -+ * @return the index of the router entry, or -1 if not found -+ */ -+static s8_t -+nd6_get_router(const ip6_addr_t *router_addr, struct netif *netif) ++static u8_t lwip_ioctl_internal_SIOCGIFADDR(struct ifreq *ifr) +{ -+ s8_t i; -+ -+ IP6_ADDR_ZONECHECK_NETIF(router_addr, netif); ++ struct netif *netif = NULL; ++ struct sockaddr_in *sock_in = NULL; + -+ /* Look for router. */ -+ for (i = 0; i < LWIP_ND6_NUM_ROUTERS; i++) { -+ if ((default_router_list[i].neighbor_entry != NULL) && -+ ((netif != NULL) ? netif == default_router_list[i].neighbor_entry->netif : 1) && -+ ip6_addr_cmp(router_addr, &(default_router_list[i].neighbor_entry->next_hop_address))) { -+ return i; -+ } ++ /* get netif ipaddr */ ++ netif = netif_find(ifr->ifr_name); ++ if (netif == NULL) { ++ return ENODEV; ++ } else { ++ sock_in = (struct sockaddr_in *)&ifr->ifr_addr; ++ sock_in->sin_family = AF_INET; ++ sock_in->sin_addr.s_addr = ip_2_ip4(&netif->ip_addr)->addr; ++ return 0; + } -+ -+ /* router not found. */ -+ return -1; +} + -+/** -+ * Create a new entry for a default router. -+ * -+ * @param router_addr the IPv6 address of the router -+ * @param netif the netif on which the router is connected, if known -+ * @return the index on the router table, or -1 if could not be created -+ */ -+static s8_t -+nd6_new_router(const ip6_addr_t *router_addr, struct netif *netif) ++static u8_t lwip_ioctl_internal_SIOCSIFFLAGS(const struct ifreq *ifr) +{ -+ s8_t router_index; -+ s8_t free_router_index; -+ s8_t neighbor_index; -+ -+ IP6_ADDR_ZONECHECK_NETIF(router_addr, netif); -+ -+ /* Do we have a neighbor entry for this router? */ -+ neighbor_index = nd6_find_neighbor_cache_entry(router_addr); -+ if (neighbor_index < 0) { -+ /* Create a neighbor entry for this router. */ -+ neighbor_index = nd6_new_neighbor_cache_entry(); -+ if (neighbor_index < 0) { -+ /* Could not create neighbor entry for this router. */ -+ return -1; -+ } -+ ip6_addr_set(&(neighbor_cache[neighbor_index].next_hop_address), router_addr); -+ neighbor_cache[neighbor_index].netif = netif; -+ neighbor_cache[neighbor_index].q = NULL; -+ neighbor_cache[neighbor_index].state = ND6_INCOMPLETE; -+ neighbor_cache[neighbor_index].counter.probes_sent = 1; -+ nd6_send_neighbor_cache_probe(&neighbor_cache[neighbor_index], ND6_SEND_FLAG_MULTICAST_DEST); -+ } -+ -+ /* Mark neighbor as router. */ -+ neighbor_cache[neighbor_index].isrouter = 1; ++ struct netif *netif = NULL; + -+ /* Look for empty entry. */ -+ free_router_index = LWIP_ND6_NUM_ROUTERS; -+ for (router_index = LWIP_ND6_NUM_ROUTERS - 1; router_index >= 0; router_index--) { -+ /* check if router already exists (this is a special case for 2 netifs on the same subnet -+ - e.g. wifi and cable) */ -+ if(default_router_list[router_index].neighbor_entry == &(neighbor_cache[neighbor_index])){ -+ return router_index; -+ } -+ if (default_router_list[router_index].neighbor_entry == NULL) { -+ /* remember lowest free index to create a new entry */ -+ free_router_index = router_index; -+ } ++ /* set netif hw addr */ ++ netif = netif_find(ifr->ifr_name); ++ if (netif == NULL) { ++ return ENODEV; + } -+ if (free_router_index < LWIP_ND6_NUM_ROUTERS) { -+ default_router_list[free_router_index].neighbor_entry = &(neighbor_cache[neighbor_index]); -+ return free_router_index; ++#if LWIP_HAVE_LOOPIF ++ else if (netif->link_layer_type == LOOPBACK_IF) { ++ return EPERM; + } -+ -+ /* Could not create a router entry. */ -+ -+ /* Mark neighbor entry as not-router. Entry might be useful as neighbor still. */ -+ neighbor_cache[neighbor_index].isrouter = 0; -+ -+ /* router not found. */ -+ return -1; -+} -+ -+/** -+ * Find the cached entry for an on-link prefix. -+ * -+ * @param prefix the IPv6 prefix that is on-link -+ * @param netif the netif on which the prefix is on-link -+ * @return the index on the prefix table, or -1 if not found -+ */ -+static s8_t -+nd6_get_onlink_prefix(const ip6_addr_t *prefix, struct netif *netif) -+{ -+ s8_t i; -+ -+ /* Look for prefix in list. */ -+ for (i = 0; i < LWIP_ND6_NUM_PREFIXES; ++i) { -+ if ((ip6_addr_netcmp(&(prefix_list[i].prefix), prefix)) && -+ (prefix_list[i].netif == netif)) { -+ return i; ++#endif /* LWIP_HAVE_LOOPIF */ ++ else { ++ if ((ifr->ifr_flags & IFF_UP) && !(netif->flags & NETIF_FLAG_UP)) { ++ (void)netif_set_up(netif); ++ } else if (!(ifr->ifr_flags & IFF_UP) && (netif->flags & NETIF_FLAG_UP)) { ++ (void)netif_set_down(netif); ++ } ++ if ((ifr->ifr_flags & IFF_RUNNING) && !(netif->flags & NETIF_FLAG_LINK_UP)) { ++ (void)netif_set_link_up(netif); ++ } else if (!(ifr->ifr_flags & IFF_RUNNING) && (netif->flags & NETIF_FLAG_LINK_UP)) { ++ (void)netif_set_link_down(netif); + } -+ } + -+ /* Entry not available. */ -+ return -1; -+} ++ if (ifr->ifr_flags & IFF_BROADCAST) { ++ netif->flags |= NETIF_FLAG_BROADCAST; ++ } else { ++ netif->flags = netif->flags & (~NETIF_FLAG_BROADCAST); ++ } ++ if (ifr->ifr_flags & IFF_NOARP) { ++ netif->flags = (netif->flags & (~NETIF_FLAG_ETHARP)); ++ } else { ++ netif->flags |= NETIF_FLAG_ETHARP; ++ } + -+/** -+ * Creates a new entry for an on-link prefix. -+ * -+ * @param prefix the IPv6 prefix that is on-link -+ * @param netif the netif on which the prefix is on-link -+ * @return the index on the prefix table, or -1 if not created -+ */ -+static s8_t -+nd6_new_onlink_prefix(const ip6_addr_t *prefix, struct netif *netif) -+{ -+ s8_t i; ++ if (ifr->ifr_flags & IFF_MULTICAST) { ++#if LWIP_IGMP ++ netif->flags |= NETIF_FLAG_IGMP; ++#endif /* LWIP_IGMP */ ++#if LWIP_IPV6 && LWIP_IPV6_MLD ++ netif->flags |= NETIF_FLAG_MLD6; ++#endif /* LWIP_IPV6_MLD */ ++ } ++ else { ++#if LWIP_IGMP ++ netif->flags = (netif->flags & ~NETIF_FLAG_IGMP); ++#endif /* LWIP_IGMP */ ++#if LWIP_IPV6 && LWIP_IPV6_MLD ++ netif->flags = (netif->flags & ~NETIF_FLAG_MLD6); ++#endif /* LWIP_IPV6_MLD */ ++ } + -+ /* Create new entry. */ -+ for (i = 0; i < LWIP_ND6_NUM_PREFIXES; ++i) { -+ if ((prefix_list[i].netif == NULL) || -+ (prefix_list[i].invalidation_timer == 0)) { -+ /* Found empty prefix entry. */ -+ prefix_list[i].netif = netif; -+ ip6_addr_set(&(prefix_list[i].prefix), prefix); -+ return i; ++#if LWIP_DHCP ++ if (ifr->ifr_flags & IFF_DYNAMIC) { ++ (void)dhcp_start(netif); ++ } else { ++ dhcp_stop(netif); ++ dhcp_cleanup(netif); + } -+ } ++#endif + -+ /* Entry not available. */ -+ return -1; ++ return 0; ++ } +} + -+/** -+ * Determine the next hop for a destination. Will determine if the -+ * destination is on-link, else a suitable on-link router is selected. -+ * -+ * The last entry index is cached for fast entry search. -+ * -+ * @param ip6addr the destination address -+ * @param netif the netif on which the packet will be sent -+ * @return the neighbor cache entry for the next hop, ERR_RTE if no -+ * suitable next hop was found, ERR_MEM if no cache entry -+ * could be created -+ */ -+static s8_t -+nd6_get_next_hop_entry(const ip6_addr_t *ip6addr, struct netif *netif) ++static u8_t lwip_ioctl_internal_SIOCGIFFLAGS(struct ifreq *ifr) +{ -+#ifdef LWIP_HOOK_ND6_GET_GW -+ const ip6_addr_t *next_hop_addr; -+#endif /* LWIP_HOOK_ND6_GET_GW */ -+ s8_t i; -+ s16_t dst_idx; -+ -+ IP6_ADDR_ZONECHECK_NETIF(ip6addr, netif); -+ -+#if LWIP_NETIF_HWADDRHINT -+ if (netif->hints != NULL) { -+ /* per-pcb cached entry was given */ -+ netif_addr_idx_t addr_hint = netif->hints->addr_hint; -+ if (addr_hint < LWIP_ND6_NUM_DESTINATIONS) { -+ nd6_cached_destination_index = addr_hint; -+ } -+ } -+#endif /* LWIP_NETIF_HWADDRHINT */ ++ struct netif *netif = NULL; + -+ /* Look for ip6addr in destination cache. */ -+ if (ip6_addr_cmp(ip6addr, &(destination_cache[nd6_cached_destination_index].destination_addr))) { -+ /* the cached entry index is the right one! */ -+ /* do nothing. */ -+ ND6_STATS_INC(nd6.cachehit); ++ /* set netif hw addr */ ++ netif = netif_find(ifr->ifr_name); ++ if (netif == NULL) { ++ return ENODEV; + } else { -+ /* Search destination cache. */ -+ dst_idx = nd6_find_destination_cache_entry(ip6addr); -+ if (dst_idx >= 0) { -+ /* found destination entry. make it our new cached index. */ -+ LWIP_ASSERT("type overflow", (size_t)dst_idx < NETIF_ADDR_IDX_MAX); -+ nd6_cached_destination_index = (netif_addr_idx_t)dst_idx; ++ if (netif->flags & NETIF_FLAG_UP) { ++ ifr->ifr_flags |= IFF_UP; + } else { -+ /* Not found. Create a new destination entry. */ -+ dst_idx = nd6_new_destination_cache_entry(); -+ if (dst_idx >= 0) { -+ /* got new destination entry. make it our new cached index. */ -+ LWIP_ASSERT("type overflow", (size_t)dst_idx < NETIF_ADDR_IDX_MAX); -+ nd6_cached_destination_index = (netif_addr_idx_t)dst_idx; -+ } else { -+ /* Could not create a destination cache entry. */ -+ return ERR_MEM; -+ } -+ -+ /* Copy dest address to destination cache. */ -+ ip6_addr_set(&(destination_cache[nd6_cached_destination_index].destination_addr), ip6addr); -+ -+ /* Now find the next hop. is it a neighbor? */ -+ if (ip6_addr_islinklocal(ip6addr) || -+ nd6_is_prefix_in_netif(ip6addr, netif)) { -+ /* Destination in local link. */ -+ destination_cache[nd6_cached_destination_index].pmtu = netif_mtu6(netif); -+ ip6_addr_copy(destination_cache[nd6_cached_destination_index].next_hop_addr, destination_cache[nd6_cached_destination_index].destination_addr); -+#ifdef LWIP_HOOK_ND6_GET_GW -+ } else if ((next_hop_addr = LWIP_HOOK_ND6_GET_GW(netif, ip6addr)) != NULL) { -+ /* Next hop for destination provided by hook function. */ -+ destination_cache[nd6_cached_destination_index].pmtu = netif->mtu; -+ ip6_addr_set(&destination_cache[nd6_cached_destination_index].next_hop_addr, next_hop_addr); -+#endif /* LWIP_HOOK_ND6_GET_GW */ -+ } else { -+ /* We need to select a router. */ -+ i = nd6_select_router(ip6addr, netif); -+ if (i < 0) { -+ /* No router found. */ -+ ip6_addr_set_any(&(destination_cache[nd6_cached_destination_index].destination_addr)); -+ return ERR_RTE; -+ } -+ destination_cache[nd6_cached_destination_index].pmtu = netif_mtu6(netif); /* Start with netif mtu, correct through ICMPv6 if necessary */ -+ ip6_addr_copy(destination_cache[nd6_cached_destination_index].next_hop_addr, default_router_list[i].neighbor_entry->next_hop_address); -+ } ++ ifr->ifr_flags &= ~IFF_UP; ++ } ++ if (netif->flags & NETIF_FLAG_LINK_UP) { ++ ifr->ifr_flags |= IFF_RUNNING; ++ } else { ++ ifr->ifr_flags &= ~IFF_RUNNING; ++ } ++ if (netif->flags & NETIF_FLAG_BROADCAST) { ++ ifr->ifr_flags |= IFF_BROADCAST; ++ } else { ++ ifr->ifr_flags &= ~IFF_BROADCAST; ++ } ++ if (netif->flags & NETIF_FLAG_ETHARP) { ++ ifr->ifr_flags &= ~IFF_NOARP; ++ } else { ++ ifr->ifr_flags |= IFF_NOARP; + } -+ } -+ -+#if LWIP_NETIF_HWADDRHINT -+ if (netif->hints != NULL) { -+ /* per-pcb cached entry was given */ -+ netif->hints->addr_hint = nd6_cached_destination_index; -+ } -+#endif /* LWIP_NETIF_HWADDRHINT */ + -+ /* Look in neighbor cache for the next-hop address. */ -+ if (ip6_addr_cmp(&(destination_cache[nd6_cached_destination_index].next_hop_addr), -+ &(neighbor_cache[nd6_cached_neighbor_index].next_hop_address))) { -+ /* Cache hit. */ -+ /* Do nothing. */ -+ ND6_STATS_INC(nd6.cachehit); -+ } else { -+ i = nd6_find_neighbor_cache_entry(&(destination_cache[nd6_cached_destination_index].next_hop_addr)); -+ if (i >= 0) { -+ /* Found a matching record, make it new cached entry. */ -+ nd6_cached_neighbor_index = i; ++#if LWIP_IGMP || LWIP_IPV6_MLD ++ if ( ++#if LWIP_IGMP ++ (netif->flags & NETIF_FLAG_IGMP) ++#endif /* LWIP_IGMP */ ++#if LWIP_IGMP && LWIP_IPV6_MLD ++ || ++#endif /* LWIP_IGMP && LWIP_IPV6_MLD */ ++#if LWIP_IPV6_MLD ++ (netif->flags & NETIF_FLAG_MLD6) ++#endif /* LWIP_IPV6_MLD */ ++ ) { ++ ifr->ifr_flags = (short)((unsigned short)ifr->ifr_flags | IFF_MULTICAST); + } else { -+ /* Neighbor not in cache. Make a new entry. */ -+ i = nd6_new_neighbor_cache_entry(); -+ if (i >= 0) { -+ /* got new neighbor entry. make it our new cached index. */ -+ nd6_cached_neighbor_index = i; -+ } else { -+ /* Could not create a neighbor cache entry. */ -+ return ERR_MEM; -+ } ++ ifr->ifr_flags = (short)((unsigned short)ifr->ifr_flags & (~IFF_MULTICAST)); ++ } ++#endif /* LWIP_IGMP || LWIP_IPV6_MLD */ + -+ /* Initialize fields. */ -+ ip6_addr_copy(neighbor_cache[i].next_hop_address, -+ destination_cache[nd6_cached_destination_index].next_hop_addr); -+ neighbor_cache[i].isrouter = 0; -+ neighbor_cache[i].netif = netif; -+ neighbor_cache[i].state = ND6_INCOMPLETE; -+ neighbor_cache[i].counter.probes_sent = 1; -+ nd6_send_neighbor_cache_probe(&neighbor_cache[i], ND6_SEND_FLAG_MULTICAST_DEST); ++#if LWIP_DHCP ++ if (netif->flags & NETIF_FLAG_DHCP) { ++ ifr->ifr_flags = (short)((unsigned short)ifr->ifr_flags | IFF_DYNAMIC); ++ } else { ++ ifr->ifr_flags = (short)((unsigned short)ifr->ifr_flags & (~IFF_DYNAMIC)); + } -+ } ++#endif + -+ /* Reset this destination's age. */ -+ destination_cache[nd6_cached_destination_index].age = 0; ++#if LWIP_HAVE_LOOPIF ++ if (netif->link_layer_type == LOOPBACK_IF) { ++ ifr->ifr_flags |= IFF_LOOPBACK; ++ } ++#endif + -+ return nd6_cached_neighbor_index; ++ return 0; ++ } +} + -+/** -+ * Queue a packet for a neighbor. -+ * -+ * @param neighbor_index the index in the neighbor cache table -+ * @param q packet to be queued -+ * @return ERR_OK if succeeded, ERR_MEM if out of memory -+ */ -+static err_t -+nd6_queue_packet(s8_t neighbor_index, struct pbuf *q) ++static u8_t lwip_ioctl_internal_SIOCGIFNAME(struct ifreq *ifr) +{ -+ err_t result = ERR_MEM; -+ struct pbuf *p; -+ int copy_needed = 0; -+#if LWIP_ND6_QUEUEING -+ struct nd6_q_entry *new_entry, *r; -+#endif /* LWIP_ND6_QUEUEING */ -+ -+ if ((neighbor_index < 0) || (neighbor_index >= LWIP_ND6_NUM_NEIGHBORS)) { -+ return ERR_ARG; -+ } ++ struct netif *netif = NULL; ++ int ret; + -+ /* IF q includes a pbuf that must be copied, we have to copy the whole chain -+ * into a new PBUF_RAM. See the definition of PBUF_NEEDS_COPY for details. */ -+ p = q; -+ while (p) { -+ if (PBUF_NEEDS_COPY(p)) { -+ copy_needed = 1; ++ for (netif = netif_list; netif != NULL; netif = netif->next) { ++ if (ifr->ifr_ifindex == netif->ifindex) { + break; + } -+ p = p->next; + } -+ if (copy_needed) { -+ /* copy the whole packet into new pbufs */ -+ p = pbuf_clone(PBUF_LINK, PBUF_RAM, q); -+ while ((p == NULL) && (neighbor_cache[neighbor_index].q != NULL)) { -+ /* Free oldest packet (as per RFC recommendation) */ -+#if LWIP_ND6_QUEUEING -+ r = neighbor_cache[neighbor_index].q; -+ neighbor_cache[neighbor_index].q = r->next; -+ r->next = NULL; -+ nd6_free_q(r); -+#else /* LWIP_ND6_QUEUEING */ -+ pbuf_free(neighbor_cache[neighbor_index].q); -+ neighbor_cache[neighbor_index].q = NULL; -+#endif /* LWIP_ND6_QUEUEING */ -+ p = pbuf_clone(PBUF_LINK, PBUF_RAM, q); -+ } -+ } else { -+ /* referencing the old pbuf is enough */ -+ p = q; -+ pbuf_ref(p); ++ ++ if (netif == NULL) { ++ return ENODEV; + } -+ /* packet was copied/ref'd? */ -+ if (p != NULL) { -+ /* queue packet ... */ -+#if LWIP_ND6_QUEUEING -+ /* allocate a new nd6 queue entry */ -+ new_entry = (struct nd6_q_entry *)memp_malloc(MEMP_ND6_QUEUE); -+ if ((new_entry == NULL) && (neighbor_cache[neighbor_index].q != NULL)) { -+ /* Free oldest packet (as per RFC recommendation) */ -+ r = neighbor_cache[neighbor_index].q; -+ neighbor_cache[neighbor_index].q = r->next; -+ r->next = NULL; -+ nd6_free_q(r); -+ new_entry = (struct nd6_q_entry *)memp_malloc(MEMP_ND6_QUEUE); -+ } -+ if (new_entry != NULL) { -+ new_entry->next = NULL; -+ new_entry->p = p; -+ if (neighbor_cache[neighbor_index].q != NULL) { -+ /* queue was already existent, append the new entry to the end */ -+ r = neighbor_cache[neighbor_index].q; -+ while (r->next != NULL) { -+ r = r->next; -+ } -+ r->next = new_entry; -+ } else { -+ /* queue did not exist, first item in queue */ -+ neighbor_cache[neighbor_index].q = new_entry; -+ } -+ LWIP_DEBUGF(LWIP_DBG_TRACE, ("ipv6: queued packet %p on neighbor entry %"S16_F"\n", (void *)p, (s16_t)neighbor_index)); -+ result = ERR_OK; -+ } else { -+ /* the pool MEMP_ND6_QUEUE is empty */ -+ pbuf_free(p); -+ LWIP_DEBUGF(LWIP_DBG_TRACE, ("ipv6: could not queue a copy of packet %p (out of memory)\n", (void *)p)); -+ /* { result == ERR_MEM } through initialization */ -+ } -+#else /* LWIP_ND6_QUEUEING */ -+ /* Queue a single packet. If an older packet is already queued, free it as per RFC. */ -+ if (neighbor_cache[neighbor_index].q != NULL) { -+ pbuf_free(neighbor_cache[neighbor_index].q); ++ if (netif->link_layer_type == LOOPBACK_IF) { ++ ret = snprintf_s(ifr->ifr_name, NETIF_NAMESIZE, (NETIF_NAMESIZE - 1), "%s", netif->name); ++ if ((ret <= 0) || (ret >= NETIF_NAMESIZE)) { ++ return ENOBUFS; + } -+ neighbor_cache[neighbor_index].q = p; -+ LWIP_DEBUGF(LWIP_DBG_TRACE, ("ipv6: queued packet %p on neighbor entry %"S16_F"\n", (void *)p, (s16_t)neighbor_index)); -+ result = ERR_OK; -+#endif /* LWIP_ND6_QUEUEING */ + } else { -+ LWIP_DEBUGF(LWIP_DBG_TRACE, ("ipv6: could not queue a copy of packet %p (out of memory)\n", (void *)q)); -+ /* { result == ERR_MEM } through initialization */ ++ ret = snprintf_s(ifr->ifr_name, NETIF_NAMESIZE, (NETIF_NAMESIZE - 1), "%s%"U8_F, netif->name, netif->num); ++ if ((ret <= 0) || (ret >= NETIF_NAMESIZE)) { ++ return ENOBUFS; ++ } + } -+ -+ return result; ++ return 0; +} + -+#if LWIP_ND6_QUEUEING -+/** -+ * Free a complete queue of nd6 q entries -+ * -+ * @param q a queue of nd6_q_entry to free -+ */ -+static void -+nd6_free_q(struct nd6_q_entry *q) ++static u8_t lwip_ioctl_internal_SIOCGIFINDEX(struct ifreq *ifr) +{ -+ struct nd6_q_entry *r; -+ LWIP_ASSERT("q != NULL", q != NULL); -+ LWIP_ASSERT("q->p != NULL", q->p != NULL); -+ while (q) { -+ r = q; -+ q = q->next; -+ LWIP_ASSERT("r->p != NULL", (r->p != NULL)); -+ pbuf_free(r->p); -+ memp_free(MEMP_ND6_QUEUE, r); ++ struct netif *netif = NULL; ++ netif = netif_find(ifr->ifr_name); ++ if (netif == NULL) { ++ return ENODEV; + } ++ ifr->ifr_ifindex = netif->ifindex; ++ return 0; +} -+#endif /* LWIP_ND6_QUEUEING */ ++#endif /* LWIP_IOCTL_IF */ ++#endif /* PF_PACKET_SOCKET */ + -+/** -+ * Send queued packets for a neighbor -+ * -+ * @param i the neighbor to send packets to -+ */ -+static void -+nd6_send_q(s8_t i) -+{ -+ struct ip6_hdr *ip6hdr; -+ ip6_addr_t dest; -+#if LWIP_ND6_QUEUEING -+ struct nd6_q_entry *q; -+#endif /* LWIP_ND6_QUEUEING */ ++#if LWIP_SO_RCVBUF || LWIP_FIONREAD_LINUXMODE ++static u8_t lwip_ioctl_internal_FIONREAD(struct lwip_sock *sock, void *argp) + { +- struct lwip_sock *sock = get_socket(s); +- u8_t val; + #if LWIP_SO_RCVBUF + int recv_avail; +-#endif /* LWIP_SO_RCVBUF */ ++#endif ++#if LWIP_FIONREAD_LINUXMODE ++ SYS_ARCH_DECL_PROTECT(lev); ++#endif + +- if (!sock) { +- return -1; ++ if (!argp) { ++ return EINVAL; + } + +- switch (cmd) { +-#if LWIP_SO_RCVBUF || LWIP_FIONREAD_LINUXMODE +- case FIONREAD: +- if (!argp) { +- sock_set_errno(sock, EINVAL); +- done_socket(sock); +- return -1; +- } ++ lwip_sock_lock(sock); + #if LWIP_FIONREAD_LINUXMODE +- if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_TCP) { +- struct netbuf *nb; +- if (sock->lastdata.netbuf) { +- nb = sock->lastdata.netbuf; +- *((int *)argp) = nb->p->tot_len; ++ if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_TCP) { ++ struct netbuf *nb; ++ if (sock->lastdata.netbuf) { ++ nb = sock->lastdata.netbuf; ++ *((int *)argp) = nb->p->tot_len; ++ } else { ++ struct netbuf *rxbuf; ++ err_t err; + -+ if ((i < 0) || (i >= LWIP_ND6_NUM_NEIGHBORS)) { -+ return; -+ } ++ SYS_ARCH_PROTECT(lev); ++ if (sock->rcvevent <= 0) { ++ *((int*)argp) = 0; ++ SYS_ARCH_UNPROTECT(lev); ++ } else { ++ SYS_ARCH_UNPROTECT(lev); ++ err = netconn_recv_udp_raw_netbuf_flags(sock->conn, &rxbuf, NETCONN_DONTBLOCK); ++ if (err != ERR_OK) { ++ *((int *)argp) = 0; + } else { +- struct netbuf *rxbuf; +- err_t err = netconn_recv_udp_raw_netbuf_flags(sock->conn, &rxbuf, NETCONN_DONTBLOCK); +- if (err != ERR_OK) { +- *((int *)argp) = 0; +- } else { +- sock->lastdata.netbuf = rxbuf; +- *((int *)argp) = rxbuf->p->tot_len; +- } ++ sock->lastdata.netbuf = rxbuf; ++ *((int *)argp) = rxbuf->p->tot_len; + } +- done_socket(sock); +- return 0; + } ++ } + -+#if LWIP_ND6_QUEUEING -+ while (neighbor_cache[i].q != NULL) { -+ /* remember first in queue */ -+ q = neighbor_cache[i].q; -+ /* pop first item off the queue */ -+ neighbor_cache[i].q = q->next; -+ /* Get ipv6 header. */ -+ ip6hdr = (struct ip6_hdr *)(q->p->payload); -+ /* Create an aligned copy. */ -+ ip6_addr_copy_from_packed(dest, ip6hdr->dest); -+ /* Restore the zone, if applicable. */ -+ ip6_addr_assign_zone(&dest, IP6_UNKNOWN, neighbor_cache[i].netif); -+ /* send the queued IPv6 packet */ -+ (neighbor_cache[i].netif)->output_ip6(neighbor_cache[i].netif, q->p, &dest); -+ /* free the queued IP packet */ -+ pbuf_free(q->p); -+ /* now queue entry can be freed */ -+ memp_free(MEMP_ND6_QUEUE, q); ++ lwip_sock_unlock(sock); ++ return 0; ++ } + #endif /* LWIP_FIONREAD_LINUXMODE */ + + #if LWIP_SO_RCVBUF +- /* we come here if either LWIP_FIONREAD_LINUXMODE==0 or this is a TCP socket */ +- SYS_ARCH_GET(sock->conn->recv_avail, recv_avail); +- if (recv_avail < 0) { +- recv_avail = 0; +- } ++ /* we come here if either LWIP_FIONREAD_LINUXMODE==0 or this is a TCP socket */ ++ SYS_ARCH_GET(sock->conn->recv_avail, recv_avail); ++ if (recv_avail < 0) { ++ recv_avail = 0; ++ } + +- /* Check if there is data left from the last recv operation. /maq 041215 */ +- if (sock->lastdata.netbuf) { +- if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) { +- recv_avail += sock->lastdata.pbuf->tot_len; +- } else { +- recv_avail += sock->lastdata.netbuf->p->tot_len; +- } +- } +- *((int *)argp) = recv_avail; ++ /* Check if there is data left from the last recv operation. /maq 041215 */ ++ if (sock->lastdata.netbuf) { ++ if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) { ++ recv_avail += sock->lastdata.pbuf->tot_len; ++ } else { ++ recv_avail += sock->lastdata.netbuf->p->tot_len; ++ } ++ } ++ *((int *)argp) = recv_avail; + +- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(%d, FIONREAD, %p) = %"U16_F"\n", s, argp, *((u16_t *)argp))); +- sock_set_errno(sock, 0); +- done_socket(sock); +- return 0; ++ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(FIONREAD, %p) = %"U16_F"\n", argp, *((u16_t *)argp))); ++ lwip_sock_unlock(sock); ++ return 0; + #else /* LWIP_SO_RCVBUF */ +- break; ++ lwip_sock_unlock(sock); ++ return ENOSYS; + #endif /* LWIP_SO_RCVBUF */ ++} + #endif /* LWIP_SO_RCVBUF || LWIP_FIONREAD_LINUXMODE */ + +- case (long)FIONBIO: +- val = 0; +- if (argp && *(int *)argp) { +- val = 1; ++static u8_t lwip_ioctl_internal_FIONBIO(struct lwip_sock *sock, const void *argp) ++{ ++ u8_t val = 0; ++ SYS_ARCH_DECL_PROTECT(lev); ++ if (argp == NULL) { ++ return EINVAL; + } -+#else /* LWIP_ND6_QUEUEING */ -+ if (neighbor_cache[i].q != NULL) { -+ /* Get ipv6 header. */ -+ ip6hdr = (struct ip6_hdr *)(neighbor_cache[i].q->payload); -+ /* Create an aligned copy. */ -+ ip6_addr_copy_from_packed(dest, ip6hdr->dest); -+ /* Restore the zone, if applicable. */ -+ ip6_addr_assign_zone(&dest, IP6_UNKNOWN, neighbor_cache[i].netif); -+ /* send the queued IPv6 packet */ -+ (neighbor_cache[i].netif)->output_ip6(neighbor_cache[i].netif, neighbor_cache[i].q, &dest); -+ /* free the queued IP packet */ -+ pbuf_free(neighbor_cache[i].q); -+ neighbor_cache[i].q = NULL; ++ if (*(int *)argp) { ++ val = 1; + } -+#endif /* LWIP_ND6_QUEUEING */ ++ SYS_ARCH_PROTECT(lev); ++ netconn_set_nonblocking(sock->conn, val); ++ SYS_ARCH_UNPROTECT(lev); ++ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(FIONBIO, %d)\n", val)); ++ return 0; +} + -+/** -+ * A packet is to be transmitted to a specific IPv6 destination on a specific -+ * interface. Check if we can find the hardware address of the next hop to use -+ * for the packet. If so, give the hardware address to the caller, which should -+ * use it to send the packet right away. Otherwise, enqueue the packet for -+ * later transmission while looking up the hardware address, if possible. -+ * -+ * As such, this function returns one of three different possible results: -+ * -+ * - ERR_OK with a non-NULL 'hwaddrp': the caller should send the packet now. -+ * - ERR_OK with a NULL 'hwaddrp': the packet has been enqueued for later. -+ * - not ERR_OK: something went wrong; forward the error upward in the stack. -+ * -+ * @param netif The lwIP network interface on which the IP packet will be sent. -+ * @param q The pbuf(s) containing the IP packet to be sent. -+ * @param ip6addr The destination IPv6 address of the packet. -+ * @param hwaddrp On success, filled with a pointer to a HW address or NULL (meaning -+ * the packet has been queued). -+ * @return -+ * - ERR_OK on success, ERR_RTE if no route was found for the packet, -+ * or ERR_MEM if low memory conditions prohibit sending the packet at all. -+ */ -+err_t -+nd6_get_next_hop_addr_or_queue(struct netif *netif, struct pbuf *q, const ip6_addr_t *ip6addr, const u8_t **hwaddrp) ++static u8_t lwip_ioctl_impl(struct lwip_sock *sock, long cmd, void *argp) +{ -+ s8_t i; -+ -+ /* Get next hop record. */ -+ i = nd6_get_next_hop_entry(ip6addr, netif); -+ if (i < 0) { -+ /* failed to get a next hop neighbor record. */ -+ return i; -+ } ++ u8_t err = 0; ++#if LWIP_NETIF_ETHTOOL ++ s32_t ret; ++#endif ++#if LWIP_IPV6_DUP_DETECT_ATTEMPTS || LWIP_IOCTL_IPV6DPCTD || LWIP_IOCTL_IF || LWIP_NETIF_ETHTOOL ++ struct ifreq *ifr = (struct ifreq *)argp; ++#endif ++#if LWIP_IOCTL_ROUTE ++ struct rtentry *rmten = (struct rtentry *)argp; ++#endif ++#if LWIP_IPV6_DUP_DETECT_ATTEMPTS || LWIP_IOCTL_IPV6DPCTD || LWIP_IOCTL_ROUTE || LWIP_IOCTL_IF ++ u8_t is_ipv6 = NETCONNTYPE_ISIPV6(sock->conn->type); ++#endif + -+ /* Now that we have a destination record, send or queue the packet. */ -+ if (neighbor_cache[i].state == ND6_STALE) { -+ /* Switch to delay state. */ -+ neighbor_cache[i].state = ND6_DELAY; -+ neighbor_cache[i].counter.delay_time = LWIP_ND6_DELAY_FIRST_PROBE_TIME / ND6_TMR_INTERVAL; -+ } -+ /* @todo should we send or queue if PROBE? send for now, to let unicast NS pass. */ -+ if ((neighbor_cache[i].state == ND6_REACHABLE) || -+ (neighbor_cache[i].state == ND6_DELAY) || -+ (neighbor_cache[i].state == ND6_PROBE)) { ++ LWIP_ASSERT("no socket given", sock != NULL); + -+ /* Tell the caller to send out the packet now. */ -+ *hwaddrp = neighbor_cache[i].lladdr; -+ return ERR_OK; -+ } ++ switch (cmd) { ++#if PF_PACKET_SOCKET ++#if LWIP_IOCTL_IF ++ case SIOCGIFCONF: ++ /* Do not allow if socket is AF_INET6 */ ++ if (is_ipv6) { ++ err = EINVAL; ++ } else { ++ err = lwip_ioctl_internal_SIOCGIFCONF(ifr); //add: SIOCGIFCONF + } +- netconn_set_nonblocking(sock->conn, val); +- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(%d, FIONBIO, %d)\n", s, val)); +- sock_set_errno(sock, 0); +- done_socket(sock); +- return 0; ++ break; ++ case SIOCGIFADDR: ++ if (is_ipv6) { ++ err = EINVAL; ++ } else { ++ err = lwip_ioctl_internal_SIOCGIFADDR(ifr); //add: SIOCGIFADDR ++ } ++ break; ++ case SIOCSIFFLAGS: ++ err = lwip_ioctl_internal_SIOCSIFFLAGS(ifr); //add: SIOCSIFFLAGS ++ break; ++ case SIOCGIFFLAGS: ++ err = lwip_ioctl_internal_SIOCGIFFLAGS(ifr); //add: SIOCSIFFLAGS ++ break; ++ case SIOCGIFNAME: ++ err = lwip_ioctl_internal_SIOCGIFNAME(ifr); //add: SIOCGIFNAME ++ break; ++ /* Need to support the get index through ioctl ++ * As of now the options is restricted to PF_PACKET scenario , so removed the compiler flag Begin ++ */ ++ case SIOCGIFINDEX: ++ err = lwip_ioctl_internal_SIOCGIFINDEX(ifr); //add: SIOCGIFINDEX ++ break; ++#endif /* LWIP_IOCTL_IF */ ++#else ++ (void)ifr; ++ (void)is_ipv6; ++#endif /* PF_PACKET_SOCKET */ ++#if LWIP_SO_RCVBUF || LWIP_FIONREAD_LINUXMODE ++ case FIONREAD: ++ err = lwip_ioctl_internal_FIONREAD(sock, argp); ++ break; ++#endif /* LWIP_SO_RCVBUF || LWIP_FIONREAD_LINUXMODE */ + ++ case FIONBIO: ++ err = lwip_ioctl_internal_FIONBIO(sock, argp); ++ break; ++ /* -1 should return EINVAL */ ++ case -1: ++ err = EINVAL; ++ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl_impl(INVALID: 0x%lx)\n", cmd)); ++ break; + default: ++ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(UNIMPL: 0x%lx, %p)\n", cmd, argp)); ++ err = ENOSYS; /* not yet implemented */ + break; + } /* switch (cmd) */ +- LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(%d, UNIMPL: 0x%lx, %p)\n", s, cmd, argp)); +- sock_set_errno(sock, ENOSYS); /* not yet implemented */ + -+ /* We should queue packet on this interface. */ -+ *hwaddrp = NULL; -+ return nd6_queue_packet(i, q); ++ return err; +} + -+ -+/** -+ * Get the Path MTU for a destination. -+ * -+ * @param ip6addr the destination address -+ * @param netif the netif on which the packet will be sent -+ * @return the Path MTU, if known, or the netif default MTU -+ */ -+u16_t -+nd6_get_destination_mtu(const ip6_addr_t *ip6addr, struct netif *netif) ++int ++lwip_ioctl(int s, long cmd, void *argp) +{ -+ s16_t i; -+ -+ i = nd6_find_destination_cache_entry(ip6addr); -+ if (i >= 0) { -+ if (destination_cache[i].pmtu > 0) { -+ return destination_cache[i].pmtu; -+ } ++ u8_t err; ++ struct lwip_sock *sock = get_socket(s); ++ if (!sock) { ++ /* get_socket has updated errno */ ++ return -1; + } -+ -+ if (netif != NULL) { -+ return netif_mtu6(netif); ++ if (argp == NULL) { ++ sock_set_errno(sock, EFAULT); ++ done_socket(sock); ++ return -1; + } + -+ return 1280; /* Minimum MTU */ -+} -+ -+ -+#if LWIP_ND6_TCP_REACHABILITY_HINTS -+/** -+ * Provide the Neighbor discovery process with a hint that a -+ * destination is reachable. Called by tcp_receive when ACKs are -+ * received or sent (as per RFC). This is useful to avoid sending -+ * NS messages every 30 seconds. -+ * -+ * @param ip6addr the destination address which is know to be reachable -+ * by an upper layer protocol (TCP) -+ */ -+void -+nd6_reachability_hint(const ip6_addr_t *ip6addr) ++ LOCK_TCPIP_CORE(); ++ err = lwip_ioctl_impl(sock, cmd, argp); ++ UNLOCK_TCPIP_CORE(); ++ if (err != ERR_OK) { ++ LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(%d, cmd: 0x%lx, %p)\n", s, cmd, argp)); ++ sock_set_errno(sock, err); ++ } + done_socket(sock); +- return -1; ++ return (err == 0) ? 0 : -1; + } + + /** A minimal implementation of fcntl. +@@ -3878,7 +4574,6 @@ + + /* ensure O_RDWR for (O_RDONLY|O_WRONLY) != O_RDWR cases */ + ret |= (op_mode == (O_RDONLY | O_WRONLY)) ? O_RDWR : op_mode; +- + break; + case F_SETFL: + /* Bits corresponding to the file access mode and the file creation flags [..] that are set in arg shall be ignored */ +diff -Nur a/lwip-2.1.2/src/apps/tftp/tftp_server.c b/lwip-2.1.2/src/apps/tftp/tftp_server.c +--- a/lwip-2.1.2/src/apps/tftp/tftp_server.c 2021-06-29 15:16:18.800893322 +0800 ++++ b/lwip-2.1.2/src/apps/tftp/tftp_server.c 2021-06-29 15:16:44.632898725 +0800 +@@ -201,7 +201,7 @@ + } + + static void +-recv(void *arg, struct udp_pcb *upcb, struct pbuf *p, const ip_addr_t *addr, u16_t port) ++tftp_recv(void *arg, struct udp_pcb *upcb, struct pbuf *p, const ip_addr_t *addr, u16_t port) + { + u16_t *sbuf = (u16_t *) p->payload; + int opcode; +@@ -416,7 +416,7 @@ + tftp_state.last_data = NULL; + tftp_state.upcb = pcb; + +- udp_recv(pcb, recv, NULL); ++ udp_recv(pcb, tftp_recv, NULL); + + return ERR_OK; + } +diff -Nur a/lwip-2.1.2/src/core/ip.c b/lwip-2.1.2/src/core/ip.c +--- a/lwip-2.1.2/src/core/ip.c 2021-06-29 15:16:18.804893322 +0800 ++++ b/lwip-2.1.2/src/core/ip.c 2021-06-29 15:16:44.632898725 +0800 +@@ -122,14 +122,12 @@ + int + ipaddr_aton(const char *cp, ip_addr_t *addr) + { +- if (cp != NULL) { ++ if (cp != NULL && addr != NULL) { + const char *c; + for (c = cp; *c != 0; c++) { + if (*c == ':') { + /* contains a colon: IPv6 address */ +- if (addr) { +- IP_SET_TYPE_VAL(*addr, IPADDR_TYPE_V6); +- } ++ IP_SET_TYPE_VAL(*addr, IPADDR_TYPE_V6); + return ip6addr_aton(cp, ip_2_ip6(addr)); + } else if (*c == '.') { + /* contains a dot: IPv4 address */ +@@ -137,9 +135,7 @@ + } + } + /* call ip4addr_aton as fallback or if IPv4 was found */ +- if (addr) { +- IP_SET_TYPE_VAL(*addr, IPADDR_TYPE_V4); +- } ++ IP_SET_TYPE_VAL(*addr, IPADDR_TYPE_V4); + return ip4addr_aton(cp, ip_2_ip4(addr)); + } + return 0; +@@ -164,4 +160,63 @@ + + #endif /* LWIP_IPV4 && LWIP_IPV6 */ + ++struct netif* ++ip_route_pcb(const ip_addr_t *dest, const struct ip_pcb* pcb) +{ -+ s8_t i; -+ s16_t dst_idx; ++ struct netif *netif = NULL; ++#if LWIP_SO_DONTROUTE ++ rt_scope_t scope = RT_SCOPE_UNIVERSAL; + -+ /* Find destination in cache. */ -+ if (ip6_addr_cmp(ip6addr, &(destination_cache[nd6_cached_destination_index].destination_addr))) { -+ dst_idx = nd6_cached_destination_index; -+ ND6_STATS_INC(nd6.cachehit); -+ } else { -+ dst_idx = nd6_find_destination_cache_entry(ip6addr); ++ LWIP_ASSERT("Expecting ipaddr to be not NULL ", dest != NULL); ++ if (pcb != NULL) { ++ scope = ip_get_option(pcb, SOF_DONTROUTE) ? RT_SCOPE_LINK : RT_SCOPE_UNIVERSAL; + } -+ if (dst_idx < 0) { -+ return; ++#endif ++ ++ if ((pcb != NULL) && (pcb->netif_idx != NETIF_NO_INDEX)) { ++ return netif_find_by_ifindex(pcb->netif_idx); + } + -+ /* Find next hop neighbor in cache. */ -+ if (ip6_addr_cmp(&(destination_cache[dst_idx].next_hop_addr), &(neighbor_cache[nd6_cached_neighbor_index].next_hop_address))) { -+ i = nd6_cached_neighbor_index; -+ ND6_STATS_INC(nd6.cachehit); ++ if ((pcb == NULL) || IP_IS_ANY_TYPE_VAL(pcb->local_ip)) { ++ /* Don't call ip_route() with IP_ANY_TYPE */ ++ netif = ip_route(IP46_ADDR_ANY(IP_GET_TYPE(dest)), dest); + } else { -+ i = nd6_find_neighbor_cache_entry(&(destination_cache[dst_idx].next_hop_addr)); ++ netif = ip_route(&pcb->local_ip, dest); + } -+ if (i < 0) { -+ return; ++ ++ if (netif == NULL) { ++ return NULL; + } + -+ /* For safety: don't set as reachable if we don't have a LL address yet. Misuse protection. */ -+ if (neighbor_cache[i].state == ND6_INCOMPLETE || neighbor_cache[i].state == ND6_NO_ENTRY) { -+ return; ++#if LWIP_SO_DONTROUTE ++ if (netif->scope < scope) { ++ return NULL; + } -+ -+ /* Set reachability state. */ -+ neighbor_cache[i].state = ND6_REACHABLE; -+ neighbor_cache[i].counter.reachable_time = reachable_time; ++#endif ++ return netif; +} -+#endif /* LWIP_ND6_TCP_REACHABILITY_HINTS */ + -+/** -+ * Remove all prefix, neighbor_cache and router entries of the specified netif. -+ * -+ * @param netif points to a network interface -+ */ -+void -+nd6_cleanup_netif(struct netif *netif) ++#if LWIP_INET_ADDR_FUNC ++in_addr_t inet_addr(const char *cp) +{ -+ u8_t i; -+ s8_t router_index; -+ for (i = 0; i < LWIP_ND6_NUM_PREFIXES; i++) { -+ if (prefix_list[i].netif == netif) { -+ prefix_list[i].netif = NULL; -+ } -+ } -+ for (i = 0; i < LWIP_ND6_NUM_NEIGHBORS; i++) { -+ if (neighbor_cache[i].netif == netif) { -+ for (router_index = 0; router_index < LWIP_ND6_NUM_ROUTERS; router_index++) { -+ if (default_router_list[router_index].neighbor_entry == &neighbor_cache[i]) { -+ default_router_list[router_index].neighbor_entry = NULL; -+ default_router_list[router_index].flags = 0; -+ } -+ } -+ neighbor_cache[i].isrouter = 0; -+ nd6_free_neighbor_cache_entry(i); -+ } -+ } -+ /* Clear the destination cache, since many entries may now have become -+ * invalid for one of several reasons. As destination cache entries have no -+ * netif association, use a sledgehammer approach (this can be improved). */ -+ nd6_clear_destination_cache(); ++ LWIP_ERROR("inet_aton:cp is NULL", (cp != NULL), return (INADDR_NONE)); ++ return ipaddr_addr(cp); +} ++#endif + -+#if LWIP_IPV6_MLD -+/** -+ * The state of a local IPv6 address entry is about to change. If needed, join -+ * or leave the solicited-node multicast group for the address. -+ * -+ * @param netif The netif that owns the address. -+ * @param addr_idx The index of the address. -+ * @param new_state The new (IP6_ADDR_) state for the address. -+ */ -+void -+nd6_adjust_mld_membership(struct netif *netif, s8_t addr_idx, u8_t new_state) ++#if LWIP_INET_ATON_FUNC ++int inet_aton(const char *cp, struct in_addr *inp) +{ -+ u8_t old_state, old_member, new_member; -+ -+ old_state = netif_ip6_addr_state(netif, addr_idx); -+ -+ /* Determine whether we were, and should be, a member of the solicited-node -+ * multicast group for this address. For tentative addresses, the group is -+ * not joined until the address enters the TENTATIVE_1 (or VALID) state. */ -+ old_member = (old_state != IP6_ADDR_INVALID && old_state != IP6_ADDR_DUPLICATED && old_state != IP6_ADDR_TENTATIVE); -+ new_member = (new_state != IP6_ADDR_INVALID && new_state != IP6_ADDR_DUPLICATED && new_state != IP6_ADDR_TENTATIVE); -+ -+ if (old_member != new_member) { -+ ip6_addr_set_solicitednode(&multicast_address, netif_ip6_addr(netif, addr_idx)->addr[3]); -+ ip6_addr_assign_zone(&multicast_address, IP6_MULTICAST, netif); -+ -+ if (new_member) { -+ mld6_joingroup_netif(netif, &multicast_address); -+ } else { -+ mld6_leavegroup_netif(netif, &multicast_address); -+ } -+ } ++ LWIP_ERROR("inet_aton:cp is NULL", (cp != NULL), return 0); ++ return ip4addr_aton(cp, (ip4_addr_t *)inp); +} -+#endif /* LWIP_IPV6_MLD */ ++#endif + -+/** Netif was added, set up, or reconnected (link up) */ -+void -+nd6_restart_netif(struct netif *netif) ++#if LWIP_INET_NTOA_FUNC ++char* inet_ntoa(struct in_addr in) +{ -+#if LWIP_IPV6_SEND_ROUTER_SOLICIT -+ /* Send Router Solicitation messages (see RFC 4861, ch. 6.3.7). */ -+ netif->rs_count = LWIP_ND6_MAX_MULTICAST_SOLICIT; -+#endif /* LWIP_IPV6_SEND_ROUTER_SOLICIT */ ++ return ip4addr_ntoa((const ip4_addr_t *)&in); +} ++#endif + -+#endif /* LWIP_IPV6 */ + #endif /* LWIP_IPV4 || LWIP_IPV6 */ +diff -Nur a/lwip-2.1.2/src/core/ipv6/icmp6.c b/lwip-2.1.2/src/core/ipv6/icmp6.c +--- a/lwip-2.1.2/src/core/ipv6/icmp6.c 2021-06-29 15:16:18.804893322 +0800 ++++ b/lwip-2.1.2/src/core/ipv6/icmp6.c 2021-06-29 15:16:44.632898725 +0800 +@@ -82,14 +82,14 @@ + void + icmp6_input(struct pbuf *p, struct netif *inp) + { +- struct icmp6_hdr *icmp6hdr; ++ struct icmpv6_hdr *icmp6hdr; + struct pbuf *r; + const ip6_addr_t *reply_src; + + ICMP6_STATS_INC(icmp6.recv); + + /* Check that ICMPv6 header fits in payload */ +- if (p->len < sizeof(struct icmp6_hdr)) { ++ if (p->len < sizeof(struct icmpv6_hdr)) { + /* drop short packets */ + pbuf_free(p); + ICMP6_STATS_INC(icmp6.lenerr); +@@ -97,7 +97,7 @@ + return; + } + +- icmp6hdr = (struct icmp6_hdr *)p->payload; ++ icmp6hdr = (struct icmpv6_hdr *)p->payload; + + #if CHECKSUM_CHECK_ICMP6 + IF__NETIF_CHECKSUM_ENABLED(inp, NETIF_CHECKSUM_CHECK_ICMP6) { +@@ -386,10 +386,10 @@ + const ip6_addr_t *reply_src, const ip6_addr_t *reply_dest, struct netif *netif) + { + struct pbuf *q; +- struct icmp6_hdr *icmp6hdr; ++ struct icmpv6_hdr *icmp6hdr; + + /* ICMPv6 header + IPv6 header + data */ +- q = pbuf_alloc(PBUF_IP, sizeof(struct icmp6_hdr) + IP6_HLEN + LWIP_ICMP6_DATASIZE, ++ q = pbuf_alloc(PBUF_IP, sizeof(struct icmpv6_hdr) + IP6_HLEN + LWIP_ICMP6_DATASIZE, + PBUF_RAM); + if (q == NULL) { + LWIP_DEBUGF(ICMP_DEBUG, ("icmp_time_exceeded: failed to allocate pbuf for ICMPv6 packet.\n")); +@@ -397,15 +397,15 @@ + return; + } + LWIP_ASSERT("check that first pbuf can hold icmp 6message", +- (q->len >= (sizeof(struct icmp6_hdr) + IP6_HLEN + LWIP_ICMP6_DATASIZE))); ++ (q->len >= (sizeof(struct icmpv6_hdr) + IP6_HLEN + LWIP_ICMP6_DATASIZE))); + +- icmp6hdr = (struct icmp6_hdr *)q->payload; ++ icmp6hdr = (struct icmpv6_hdr *)q->payload; + icmp6hdr->type = type; + icmp6hdr->code = code; + icmp6hdr->data = lwip_htonl(data); + + /* copy fields from original packet */ +- SMEMCPY((u8_t *)q->payload + sizeof(struct icmp6_hdr), (u8_t *)p->payload, ++ SMEMCPY((u8_t *)q->payload + sizeof(struct icmpv6_hdr), (u8_t *)p->payload, + IP6_HLEN + LWIP_ICMP6_DATASIZE); + + /* calculate checksum */ +diff -Nur a/lwip-2.1.2/src/core/ipv6/nd6.c b/lwip-2.1.2/src/core/ipv6/nd6.c +--- a/lwip-2.1.2/src/core/ipv6/nd6.c 2021-06-29 15:16:18.804893322 +0800 ++++ b/lwip-2.1.2/src/core/ipv6/nd6.c 2021-06-29 15:16:44.632898725 +0800 +@@ -894,13 +894,13 @@ + } + case ICMP6_TYPE_PTB: /* Packet too big */ + { +- struct icmp6_hdr *icmp6hdr; /* Packet too big message */ ++ struct icmpv6_hdr *icmp6hdr; /* Packet too big message */ + struct ip6_hdr *ip6hdr; /* IPv6 header of the packet which caused the error */ + u32_t pmtu; + ip6_addr_t destination_address; + + /* Check that ICMPv6 header + IPv6 header fit in payload */ +- if (p->len < (sizeof(struct icmp6_hdr) + IP6_HLEN)) { ++ if (p->len < (sizeof(struct icmpv6_hdr) + IP6_HLEN)) { + /* drop short packets */ + pbuf_free(p); + ND6_STATS_INC(nd6.lenerr); +@@ -908,8 +908,8 @@ + return; + } + +- icmp6hdr = (struct icmp6_hdr *)p->payload; +- ip6hdr = (struct ip6_hdr *)((u8_t*)p->payload + sizeof(struct icmp6_hdr)); ++ icmp6hdr = (struct icmpv6_hdr *)p->payload; ++ ip6hdr = (struct ip6_hdr *)((u8_t*)p->payload + sizeof(struct icmpv6_hdr)); + + /* Create an aligned, zoned copy of the destination address. */ + ip6_addr_copy_from_packed(destination_address, ip6hdr->dest); diff -Nur a/lwip-2.1.2/src/core/netif.c b/lwip-2.1.2/src/core/netif.c ---- a/lwip-2.1.2/src/core/netif.c 2021-05-08 18:13:52.631621024 +0800 -+++ b/lwip-2.1.2/src/core/netif.c 2021-04-28 10:00:13.808615418 +0800 +--- a/lwip-2.1.2/src/core/netif.c 2021-06-29 15:16:18.804893322 +0800 ++++ b/lwip-2.1.2/src/core/netif.c 2021-06-29 15:16:44.632898725 +0800 @@ -89,6 +89,8 @@ #if LWIP_IPV6 #include "lwip/nd6.h" @@ -16514,7 +2260,7 @@ diff -Nur a/lwip-2.1.2/src/core/netif.c b/lwip-2.1.2/src/core/netif.c #if LWIP_NETIF_EXT_STATUS_CALLBACK /** * @ingroup netif -@@ -1793,3 +1854,217 @@ +@@ -1793,3 +1854,213 @@ } } #endif /* LWIP_NETIF_EXT_STATUS_CALLBACK */ @@ -16529,12 +2275,6 @@ diff -Nur a/lwip-2.1.2/src/core/netif.c b/lwip-2.1.2/src/core/netif.c + } +#endif + -+#if LWIP_IPV6 -+ if (IP_IS_V6(ipaddr)) { -+ return netif_find_by_ip6addr(ip_2_ip6(ipaddr)); -+ } -+#endif -+ + LWIP_DEBUGF(NETIF_DEBUG, ("netif_find_using_ipaddr: didn't find\n")); + return NULL; +} @@ -16646,6 +2386,8 @@ diff -Nur a/lwip-2.1.2/src/core/netif.c b/lwip-2.1.2/src/core/netif.c +} +#endif /* LWIP_IPV4 */ + ++ ++ +#if LWIP_DHCP +/* + * Close DHCP and set static network. @@ -16733,8 +2475,8 @@ diff -Nur a/lwip-2.1.2/src/core/netif.c b/lwip-2.1.2/src/core/netif.c + return tmp_index; +} diff -Nur a/lwip-2.1.2/src/core/raw.c b/lwip-2.1.2/src/core/raw.c ---- a/lwip-2.1.2/src/core/raw.c 2021-05-08 18:13:52.631621024 +0800 -+++ b/lwip-2.1.2/src/core/raw.c 2021-04-27 18:56:55.440353467 +0800 +--- a/lwip-2.1.2/src/core/raw.c 2021-06-29 15:16:18.804893322 +0800 ++++ b/lwip-2.1.2/src/core/raw.c 2021-06-29 15:16:44.632898725 +0800 @@ -63,7 +63,24 @@ #include @@ -17061,8 +2803,8 @@ diff -Nur a/lwip-2.1.2/src/core/raw.c b/lwip-2.1.2/src/core/raw.c + #endif /* LWIP_RAW */ diff -Nur a/lwip-2.1.2/src/include/lwip/api.h b/lwip-2.1.2/src/include/lwip/api.h ---- a/lwip-2.1.2/src/include/lwip/api.h 2021-05-08 18:13:52.635621024 +0800 -+++ b/lwip-2.1.2/src/include/lwip/api.h 2021-04-27 18:56:55.440353467 +0800 +--- a/lwip-2.1.2/src/include/lwip/api.h 2021-06-29 15:16:18.804893322 +0800 ++++ b/lwip-2.1.2/src/include/lwip/api.h 2021-06-29 15:16:44.632898725 +0800 @@ -48,6 +48,9 @@ #include "lwip/sys.h" #include "lwip/ip_addr.h" @@ -17137,824 +2879,67 @@ diff -Nur a/lwip-2.1.2/src/include/lwip/api.h b/lwip-2.1.2/src/include/lwip/api. +#define netconn_type(conn) ((u32_t)(conn->type)) err_t netconn_getaddr(struct netconn *conn, ip_addr_t *addr, - u16_t *port, u8_t local); -+#if LWIP_LITEOS_COMPAT -+#if PF_PACKET_SOCKET -+struct pf_packet_sockaddr_ll { -+ u16_t sll_protocol; -+ u16_t sll_hatype; -+ u8_t if_idx; -+ u8_t sll_halen; -+ u8_t sll_addr[NETIF_MAX_HWADDR_LEN]; -+}; -+err_t netconn_get_sockaddr_pf_packet(struct netconn *conn, struct pf_packet_sockaddr_ll *ll, u8_t local); -+#endif /* PF_PACKET_SOCKET */ -+#endif /* LWIP_LITEOS_COMPAT */ - /** @ingroup netconn_common */ - #define netconn_peer(c,i,p) netconn_getaddr(c,i,p,0) - /** @ingroup netconn_common */ - #define netconn_addr(c,i,p) netconn_getaddr(c,i,p,1) - -+#if PF_PACKET_SOCKET -+err_t netconn_bind(struct netconn *conn, const ip_addr_t *addr, u16_t port, u8_t ifindex); -+#else - err_t netconn_bind(struct netconn *conn, const ip_addr_t *addr, u16_t port); -+#endif /* PF_PACKET_SOCKET */ -+ - err_t netconn_bind_if(struct netconn *conn, u8_t if_idx); - err_t netconn_connect(struct netconn *conn, const ip_addr_t *addr, u16_t port); - err_t netconn_disconnect (struct netconn *conn); -diff -Nur a/lwip-2.1.2/src/include/lwip/arch.h b/lwip-2.1.2/src/include/lwip/arch.h ---- a/lwip-2.1.2/src/include/lwip/arch.h 2021-05-08 18:13:52.635621024 +0800 -+++ b/lwip-2.1.2/src/include/lwip/arch.h 2021-04-27 18:56:55.440353467 +0800 -@@ -1,393 +1,391 @@ --/** -- * @file -- * Support for different processor and compiler architectures -- */ -- --/* -- * 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 -- * -- */ --#ifndef LWIP_HDR_ARCH_H --#define LWIP_HDR_ARCH_H -- --#ifndef LITTLE_ENDIAN --#define LITTLE_ENDIAN 1234 --#endif -- --#ifndef BIG_ENDIAN --#define BIG_ENDIAN 4321 --#endif -- --#include "arch/cc.h" -- --/** -- * @defgroup compiler_abstraction Compiler/platform abstraction -- * @ingroup sys_layer -- * All defines related to this section must not be placed in lwipopts.h, -- * but in arch/cc.h! -- * If the compiler does not provide memset() this file must include a -- * definition of it, or include a file which defines it. -- * These options cannot be \#defined in lwipopts.h since they are not options -- * of lwIP itself, but options of the lwIP port to your system. -- * @{ -- */ -- --/** Define the byte order of the system. -- * Needed for conversion of network data to host byte order. -- * Allowed values: LITTLE_ENDIAN and BIG_ENDIAN -- */ --#ifndef BYTE_ORDER --#define BYTE_ORDER LITTLE_ENDIAN --#endif -- --/** Define random number generator function of your system */ --#ifdef __DOXYGEN__ --#define LWIP_RAND() ((u32_t)rand()) --#endif -- --/** Platform specific diagnostic output.\n -- * Note the default implementation pulls in printf, which may -- * in turn pull in a lot of standard libary code. In resource-constrained -- * systems, this should be defined to something less resource-consuming. -- */ --#ifndef LWIP_PLATFORM_DIAG --#define LWIP_PLATFORM_DIAG(x) do {printf x;} while(0) --#include --#include --#endif -- --/** Platform specific assertion handling.\n -- * Note the default implementation pulls in printf, fflush and abort, which may -- * in turn pull in a lot of standard libary code. In resource-constrained -- * systems, this should be defined to something less resource-consuming. -- */ --#ifndef LWIP_PLATFORM_ASSERT --#define LWIP_PLATFORM_ASSERT(x) do {printf("Assertion \"%s\" failed at line %d in %s\n", \ -- x, __LINE__, __FILE__); fflush(NULL); abort();} while(0) --#include --#include --#endif -- --/** Define this to 1 in arch/cc.h of your port if you do not want to -- * include stddef.h header to get size_t. You need to typedef size_t -- * by yourself in this case. -- */ --#ifndef LWIP_NO_STDDEF_H --#define LWIP_NO_STDDEF_H 0 --#endif -- --#if !LWIP_NO_STDDEF_H --#include /* for size_t */ --#endif -- --/** Define this to 1 in arch/cc.h of your port if your compiler does not provide -- * the stdint.h header. You need to typedef the generic types listed in -- * lwip/arch.h yourself in this case (u8_t, u16_t...). -- */ --#ifndef LWIP_NO_STDINT_H --#define LWIP_NO_STDINT_H 0 --#endif -- --/* Define generic types used in lwIP */ --#if !LWIP_NO_STDINT_H --#include --/* stdint.h is C99 which should also provide support for 64-bit integers */ --#if !defined(LWIP_HAVE_INT64) && defined(UINT64_MAX) --#define LWIP_HAVE_INT64 1 --#endif --typedef uint8_t u8_t; --typedef int8_t s8_t; --typedef uint16_t u16_t; --typedef int16_t s16_t; --typedef uint32_t u32_t; --typedef int32_t s32_t; --#if LWIP_HAVE_INT64 --typedef uint64_t u64_t; --typedef int64_t s64_t; --#endif --typedef uintptr_t mem_ptr_t; --#endif -- --/** Define this to 1 in arch/cc.h of your port if your compiler does not provide -- * the inttypes.h header. You need to define the format strings listed in -- * lwip/arch.h yourself in this case (X8_F, U16_F...). -- */ --#ifndef LWIP_NO_INTTYPES_H --#define LWIP_NO_INTTYPES_H 0 --#endif -- --/* Define (sn)printf formatters for these lwIP types */ --#if !LWIP_NO_INTTYPES_H --#include --#ifndef X8_F --#define X8_F "02" PRIx8 --#endif --#ifndef U16_F --#define U16_F PRIu16 --#endif --#ifndef S16_F --#define S16_F PRId16 --#endif --#ifndef X16_F --#define X16_F PRIx16 --#endif --#ifndef U32_F --#define U32_F PRIu32 --#endif --#ifndef S32_F --#define S32_F PRId32 --#endif --#ifndef X32_F --#define X32_F PRIx32 --#endif --#ifndef SZT_F --#define SZT_F PRIuPTR --#endif --#endif -- --/** Define this to 1 in arch/cc.h of your port if your compiler does not provide -- * the limits.h header. You need to define the type limits yourself in this case -- * (e.g. INT_MAX, SSIZE_MAX). -- */ --#ifndef LWIP_NO_LIMITS_H --#define LWIP_NO_LIMITS_H 0 --#endif -- --/* Include limits.h? */ --#if !LWIP_NO_LIMITS_H --#include --#endif -- --/* Do we need to define ssize_t? This is a compatibility hack: -- * Unfortunately, this type seems to be unavailable on some systems (even if -- * sys/types or unistd.h are available). -- * Being like that, we define it to 'int' if SSIZE_MAX is not defined. -- */ --#ifdef SSIZE_MAX --/* If SSIZE_MAX is defined, unistd.h should provide the type as well */ --#ifndef LWIP_NO_UNISTD_H --#define LWIP_NO_UNISTD_H 0 --#endif --#if !LWIP_NO_UNISTD_H --#include --#endif --#else /* SSIZE_MAX */ --typedef int ssize_t; --#define SSIZE_MAX INT_MAX --#endif /* SSIZE_MAX */ -- --/* some maximum values needed in lwip code */ --#define LWIP_UINT32_MAX 0xffffffff -- --/** Define this to 1 in arch/cc.h of your port if your compiler does not provide -- * the ctype.h header. If ctype.h is available, a few character functions -- * are mapped to the appropriate functions (lwip_islower, lwip_isdigit...), if -- * not, a private implementation is provided. -- */ --#ifndef LWIP_NO_CTYPE_H --#define LWIP_NO_CTYPE_H 0 --#endif -- --#if LWIP_NO_CTYPE_H --#define lwip_in_range(c, lo, up) ((u8_t)(c) >= (lo) && (u8_t)(c) <= (up)) --#define lwip_isdigit(c) lwip_in_range((c), '0', '9') --#define lwip_isxdigit(c) (lwip_isdigit(c) || lwip_in_range((c), 'a', 'f') || lwip_in_range((c), 'A', 'F')) --#define lwip_islower(c) lwip_in_range((c), 'a', 'z') --#define lwip_isspace(c) ((c) == ' ' || (c) == '\f' || (c) == '\n' || (c) == '\r' || (c) == '\t' || (c) == '\v') --#define lwip_isupper(c) lwip_in_range((c), 'A', 'Z') --#define lwip_tolower(c) (lwip_isupper(c) ? (c) - 'A' + 'a' : c) --#define lwip_toupper(c) (lwip_islower(c) ? (c) - 'a' + 'A' : c) --#else --#include --#define lwip_isdigit(c) isdigit((unsigned char)(c)) --#define lwip_isxdigit(c) isxdigit((unsigned char)(c)) --#define lwip_islower(c) islower((unsigned char)(c)) --#define lwip_isspace(c) isspace((unsigned char)(c)) --#define lwip_isupper(c) isupper((unsigned char)(c)) --#define lwip_tolower(c) tolower((unsigned char)(c)) --#define lwip_toupper(c) toupper((unsigned char)(c)) --#endif -- --/** C++ const_cast(val) equivalent to remove constness from a value (GCC -Wcast-qual) */ --#ifndef LWIP_CONST_CAST --#define LWIP_CONST_CAST(target_type, val) ((target_type)((ptrdiff_t)val)) --#endif -- --/** Get rid of alignment cast warnings (GCC -Wcast-align) */ --#ifndef LWIP_ALIGNMENT_CAST --#define LWIP_ALIGNMENT_CAST(target_type, val) LWIP_CONST_CAST(target_type, val) --#endif -- --/** Get rid of warnings related to pointer-to-numeric and vice-versa casts, -- * e.g. "conversion from 'u8_t' to 'void *' of greater size" -- */ --#ifndef LWIP_PTR_NUMERIC_CAST --#define LWIP_PTR_NUMERIC_CAST(target_type, val) LWIP_CONST_CAST(target_type, val) --#endif -- --/** Avoid warnings/errors related to implicitly casting away packed attributes by doing a explicit cast */ --#ifndef LWIP_PACKED_CAST --#define LWIP_PACKED_CAST(target_type, val) LWIP_CONST_CAST(target_type, val) --#endif -- --/** Allocates a memory buffer of specified size that is of sufficient size to align -- * its start address using LWIP_MEM_ALIGN. -- * You can declare your own version here e.g. to enforce alignment without adding -- * trailing padding bytes (see LWIP_MEM_ALIGN_BUFFER) or your own section placement -- * requirements.\n -- * e.g. if you use gcc and need 32 bit alignment:\n -- * \#define LWIP_DECLARE_MEMORY_ALIGNED(variable_name, size) u8_t variable_name[size] \_\_attribute\_\_((aligned(4)))\n -- * or more portable:\n -- * \#define LWIP_DECLARE_MEMORY_ALIGNED(variable_name, size) u32_t variable_name[(size + sizeof(u32_t) - 1) / sizeof(u32_t)] -- */ --#ifndef LWIP_DECLARE_MEMORY_ALIGNED --#define LWIP_DECLARE_MEMORY_ALIGNED(variable_name, size) u8_t variable_name[LWIP_MEM_ALIGN_BUFFER(size)] --#endif -- --/** Calculate memory size for an aligned buffer - returns the next highest -- * multiple of MEM_ALIGNMENT (e.g. LWIP_MEM_ALIGN_SIZE(3) and -- * LWIP_MEM_ALIGN_SIZE(4) will both yield 4 for MEM_ALIGNMENT == 4). -- */ --#ifndef LWIP_MEM_ALIGN_SIZE --#define LWIP_MEM_ALIGN_SIZE(size) (((size) + MEM_ALIGNMENT - 1U) & ~(MEM_ALIGNMENT-1U)) --#endif -- --/** Calculate safe memory size for an aligned buffer when using an unaligned -- * type as storage. This includes a safety-margin on (MEM_ALIGNMENT - 1) at the -- * start (e.g. if buffer is u8_t[] and actual data will be u32_t*) -- */ --#ifndef LWIP_MEM_ALIGN_BUFFER --#define LWIP_MEM_ALIGN_BUFFER(size) (((size) + MEM_ALIGNMENT - 1U)) --#endif -- --/** Align a memory pointer to the alignment defined by MEM_ALIGNMENT -- * so that ADDR % MEM_ALIGNMENT == 0 -- */ --#ifndef LWIP_MEM_ALIGN --#define LWIP_MEM_ALIGN(addr) ((void *)(((mem_ptr_t)(addr) + MEM_ALIGNMENT - 1) & ~(mem_ptr_t)(MEM_ALIGNMENT-1))) --#endif -- --#ifdef __cplusplus --extern "C" { --#endif -- --/** Packed structs support. -- * Placed BEFORE declaration of a packed struct.\n -- * For examples of packed struct declarations, see include/lwip/prot/ subfolder.\n -- * A port to GCC/clang is included in lwIP, if you use these compilers there is nothing to do here. -- */ --#ifndef PACK_STRUCT_BEGIN --#define PACK_STRUCT_BEGIN --#endif /* PACK_STRUCT_BEGIN */ -- --/** Packed structs support. -- * Placed AFTER declaration of a packed struct.\n -- * For examples of packed struct declarations, see include/lwip/prot/ subfolder.\n -- * A port to GCC/clang is included in lwIP, if you use these compilers there is nothing to do here. -- */ --#ifndef PACK_STRUCT_END --#define PACK_STRUCT_END --#endif /* PACK_STRUCT_END */ -- --/** Packed structs support. -- * Placed between end of declaration of a packed struct and trailing semicolon.\n -- * For examples of packed struct declarations, see include/lwip/prot/ subfolder.\n -- * A port to GCC/clang is included in lwIP, if you use these compilers there is nothing to do here. -- */ --#ifndef PACK_STRUCT_STRUCT --#if defined(__GNUC__) || defined(__clang__) --#define PACK_STRUCT_STRUCT __attribute__((packed)) --#else --#define PACK_STRUCT_STRUCT --#endif --#endif /* PACK_STRUCT_STRUCT */ -- --/** Packed structs support. -- * Wraps u32_t and u16_t members.\n -- * For examples of packed struct declarations, see include/lwip/prot/ subfolder.\n -- * A port to GCC/clang is included in lwIP, if you use these compilers there is nothing to do here. -- */ --#ifndef PACK_STRUCT_FIELD --#define PACK_STRUCT_FIELD(x) x --#endif /* PACK_STRUCT_FIELD */ -- --/** Packed structs support. -- * Wraps u8_t members, where some compilers warn that packing is not necessary.\n -- * For examples of packed struct declarations, see include/lwip/prot/ subfolder.\n -- * A port to GCC/clang is included in lwIP, if you use these compilers there is nothing to do here. -- */ --#ifndef PACK_STRUCT_FLD_8 --#define PACK_STRUCT_FLD_8(x) PACK_STRUCT_FIELD(x) --#endif /* PACK_STRUCT_FLD_8 */ -- --/** Packed structs support. -- * Wraps members that are packed structs themselves, where some compilers warn that packing is not necessary.\n -- * For examples of packed struct declarations, see include/lwip/prot/ subfolder.\n -- * A port to GCC/clang is included in lwIP, if you use these compilers there is nothing to do here. -- */ --#ifndef PACK_STRUCT_FLD_S --#define PACK_STRUCT_FLD_S(x) PACK_STRUCT_FIELD(x) --#endif /* PACK_STRUCT_FLD_S */ -- --/** PACK_STRUCT_USE_INCLUDES==1: Packed structs support using \#include files before and after struct to be packed.\n -- * The file included BEFORE the struct is "arch/bpstruct.h".\n -- * The file included AFTER the struct is "arch/epstruct.h".\n -- * This can be used to implement struct packing on MS Visual C compilers, see -- * the Win32 port in the lwIP contrib repository for reference. -- * For examples of packed struct declarations, see include/lwip/prot/ subfolder.\n -- * A port to GCC/clang is included in lwIP, if you use these compilers there is nothing to do here. -- */ --#ifdef __DOXYGEN__ --#define PACK_STRUCT_USE_INCLUDES --#endif -- --/** Eliminates compiler warning about unused arguments (GCC -Wextra -Wunused). */ --#ifndef LWIP_UNUSED_ARG --#define LWIP_UNUSED_ARG(x) (void)x --#endif /* LWIP_UNUSED_ARG */ -- --/** LWIP_PROVIDE_ERRNO==1: Let lwIP provide ERRNO values and the 'errno' variable. -- * If this is disabled, cc.h must either define 'errno', include , -- * define LWIP_ERRNO_STDINCLUDE to get included or -- * define LWIP_ERRNO_INCLUDE to or equivalent. -- */ --#if defined __DOXYGEN__ --#define LWIP_PROVIDE_ERRNO --#endif -- --/** -- * @} -- */ -- --#ifdef __cplusplus --} --#endif -- --#endif /* LWIP_HDR_ARCH_H */ -+/** -+ * @file -+ * Support for different processor and compiler architectures -+ */ -+ -+/* -+ * 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 -+ * -+ */ -+#ifndef LWIP_HDR_ARCH_H -+#define LWIP_HDR_ARCH_H -+ -+#include -+#include "arch/cc.h" -+ -+/** -+ * @defgroup compiler_abstraction Compiler/platform abstraction -+ * @ingroup sys_layer -+ * All defines related to this section must not be placed in lwipopts.h, -+ * but in arch/cc.h! -+ * If the compiler does not provide memset() this file must include a -+ * definition of it, or include a file which defines it. -+ * These options cannot be \#defined in lwipopts.h since they are not options -+ * of lwIP itself, but options of the lwIP port to your system. -+ * @{ -+ */ -+ -+/** Define the byte order of the system. -+ * Needed for conversion of network data to host byte order. -+ * Allowed values: LITTLE_ENDIAN and BIG_ENDIAN -+ */ -+#ifndef BYTE_ORDER -+#define BYTE_ORDER LITTLE_ENDIAN -+#endif -+ -+/** Define random number generator function of your system */ -+#ifdef __DOXYGEN__ -+#define LWIP_RAND() ((u32_t)rand()) -+#endif -+ -+/** Platform specific diagnostic output.\n -+ * Note the default implementation pulls in printf, which may -+ * in turn pull in a lot of standard libary code. In resource-constrained -+ * systems, this should be defined to something less resource-consuming. -+ */ -+#ifndef LWIP_PLATFORM_DIAG -+#define LWIP_PLATFORM_DIAG(x) do {printf x;} while(0) -+#include -+#include -+#endif -+ -+/** Platform specific assertion handling.\n -+ * Note the default implementation pulls in printf, fflush and abort, which may -+ * in turn pull in a lot of standard libary code. In resource-constrained -+ * systems, this should be defined to something less resource-consuming. -+ */ -+#ifndef LWIP_PLATFORM_ASSERT -+#define LWIP_PLATFORM_ASSERT(x) do {printf("Assertion \"%s\" failed at line %d in %s\n", \ -+ x, __LINE__, __FILE__); fflush(NULL); abort();} while(0) -+#include -+#include -+#endif -+ -+/** Define this to 1 in arch/cc.h of your port if you do not want to -+ * include stddef.h header to get size_t. You need to typedef size_t -+ * by yourself in this case. -+ */ -+#ifndef LWIP_NO_STDDEF_H -+#define LWIP_NO_STDDEF_H 0 -+#endif -+ -+#if !LWIP_NO_STDDEF_H -+#include /* for size_t */ -+#endif -+ -+/** Define this to 1 in arch/cc.h of your port if your compiler does not provide -+ * the stdint.h header. You need to typedef the generic types listed in -+ * lwip/arch.h yourself in this case (u8_t, u16_t...). -+ */ -+#ifndef LWIP_NO_STDINT_H -+#define LWIP_NO_STDINT_H 0 -+#endif -+ -+/* Define generic types used in lwIP */ -+#if !LWIP_NO_STDINT_H -+#include -+/* stdint.h is C99 which should also provide support for 64-bit integers */ -+#if !defined(LWIP_HAVE_INT64) && defined(UINT64_MAX) -+#define LWIP_HAVE_INT64 1 -+#endif -+typedef uint8_t u8_t; -+typedef int8_t s8_t; -+typedef uint16_t u16_t; -+typedef int16_t s16_t; -+typedef uint32_t u32_t; -+typedef int32_t s32_t; -+#if LWIP_HAVE_INT64 -+typedef uint64_t u64_t; -+typedef int64_t s64_t; -+#endif -+typedef uintptr_t mem_ptr_t; -+#endif -+ -+/** Define this to 1 in arch/cc.h of your port if your compiler does not provide -+ * the inttypes.h header. You need to define the format strings listed in -+ * lwip/arch.h yourself in this case (X8_F, U16_F...). -+ */ -+#ifndef LWIP_NO_INTTYPES_H -+#define LWIP_NO_INTTYPES_H 0 -+#endif -+ -+/* Define (sn)printf formatters for these lwIP types */ -+#if !LWIP_NO_INTTYPES_H -+#include -+#ifndef X8_F -+#define X8_F "02" PRIx8 -+#endif -+#if LWIP_LITEOS_COMPAT -+#ifndef U8_F -+#define U8_F PRIu8 -+#endif -+#endif /* LWIP_LITEOS_COMPAT */ -+#ifndef U16_F -+#define U16_F PRIu16 -+#endif -+#ifndef S16_F -+#define S16_F PRId16 -+#endif -+#ifndef X16_F -+#define X16_F PRIx16 -+#endif -+#ifndef U32_F -+#define U32_F PRIu32 -+#endif -+#ifndef S32_F -+#define S32_F PRId32 -+#endif -+#ifndef X32_F -+#define X32_F PRIx32 -+#endif -+#ifndef SZT_F -+#define SZT_F PRIuPTR -+#endif -+#endif -+ -+/** Define this to 1 in arch/cc.h of your port if your compiler does not provide -+ * the limits.h header. You need to define the type limits yourself in this case -+ * (e.g. INT_MAX, SSIZE_MAX). -+ */ -+#ifndef LWIP_NO_LIMITS_H -+#define LWIP_NO_LIMITS_H 0 -+#endif -+ -+/* Include limits.h? */ -+#if !LWIP_NO_LIMITS_H -+#include -+#endif -+ -+/* Do we need to define ssize_t? This is a compatibility hack: -+ * Unfortunately, this type seems to be unavailable on some systems (even if -+ * sys/types or unistd.h are available). -+ * Being like that, we define it to 'int' if SSIZE_MAX is not defined. -+ */ -+#ifdef SSIZE_MAX -+/* If SSIZE_MAX is defined, unistd.h should provide the type as well */ -+#ifndef LWIP_NO_UNISTD_H -+#define LWIP_NO_UNISTD_H 0 -+#endif -+#if !LWIP_NO_UNISTD_H -+#include -+#endif -+#else /* SSIZE_MAX */ -+typedef int ssize_t; -+#define SSIZE_MAX INT_MAX -+#endif /* SSIZE_MAX */ -+ -+/* some maximum values needed in lwip code */ -+#define LWIP_UINT32_MAX 0xffffffff -+ -+/** Define this to 1 in arch/cc.h of your port if your compiler does not provide -+ * the ctype.h header. If ctype.h is available, a few character functions -+ * are mapped to the appropriate functions (lwip_islower, lwip_isdigit...), if -+ * not, a private implementation is provided. -+ */ -+#ifndef LWIP_NO_CTYPE_H -+#define LWIP_NO_CTYPE_H 0 -+#endif -+ -+#if LWIP_NO_CTYPE_H -+#define lwip_in_range(c, lo, up) ((u8_t)(c) >= (lo) && (u8_t)(c) <= (up)) -+#define lwip_isdigit(c) lwip_in_range((c), '0', '9') -+#define lwip_isxdigit(c) (lwip_isdigit(c) || lwip_in_range((c), 'a', 'f') || lwip_in_range((c), 'A', 'F')) -+#define lwip_islower(c) lwip_in_range((c), 'a', 'z') -+#define lwip_isspace(c) ((c) == ' ' || (c) == '\f' || (c) == '\n' || (c) == '\r' || (c) == '\t' || (c) == '\v') -+#define lwip_isupper(c) lwip_in_range((c), 'A', 'Z') -+#define lwip_tolower(c) (lwip_isupper(c) ? (c) - 'A' + 'a' : c) -+#define lwip_toupper(c) (lwip_islower(c) ? (c) - 'a' + 'A' : c) -+#else -+#include -+#define lwip_isdigit(c) isdigit((unsigned char)(c)) -+#define lwip_isxdigit(c) isxdigit((unsigned char)(c)) -+#define lwip_islower(c) islower((unsigned char)(c)) -+#define lwip_isspace(c) isspace((unsigned char)(c)) -+#define lwip_isupper(c) isupper((unsigned char)(c)) -+#define lwip_tolower(c) tolower((unsigned char)(c)) -+#define lwip_toupper(c) toupper((unsigned char)(c)) -+#endif -+ -+/** C++ const_cast(val) equivalent to remove constness from a value (GCC -Wcast-qual) */ -+#ifndef LWIP_CONST_CAST -+#define LWIP_CONST_CAST(target_type, val) ((target_type)((ptrdiff_t)val)) -+#endif -+ -+/** Get rid of alignment cast warnings (GCC -Wcast-align) */ -+#ifndef LWIP_ALIGNMENT_CAST -+#define LWIP_ALIGNMENT_CAST(target_type, val) LWIP_CONST_CAST(target_type, val) -+#endif -+ -+/** Get rid of warnings related to pointer-to-numeric and vice-versa casts, -+ * e.g. "conversion from 'u8_t' to 'void *' of greater size" -+ */ -+#ifndef LWIP_PTR_NUMERIC_CAST -+#define LWIP_PTR_NUMERIC_CAST(target_type, val) LWIP_CONST_CAST(target_type, val) -+#endif -+ -+/** Avoid warnings/errors related to implicitly casting away packed attributes by doing a explicit cast */ -+#ifndef LWIP_PACKED_CAST -+#define LWIP_PACKED_CAST(target_type, val) LWIP_CONST_CAST(target_type, val) -+#endif -+ -+/** Allocates a memory buffer of specified size that is of sufficient size to align -+ * its start address using LWIP_MEM_ALIGN. -+ * You can declare your own version here e.g. to enforce alignment without adding -+ * trailing padding bytes (see LWIP_MEM_ALIGN_BUFFER) or your own section placement -+ * requirements.\n -+ * e.g. if you use gcc and need 32 bit alignment:\n -+ * \#define LWIP_DECLARE_MEMORY_ALIGNED(variable_name, size) u8_t variable_name[size] \_\_attribute\_\_((aligned(4)))\n -+ * or more portable:\n -+ * \#define LWIP_DECLARE_MEMORY_ALIGNED(variable_name, size) u32_t variable_name[(size + sizeof(u32_t) - 1) / sizeof(u32_t)] -+ */ -+#ifndef LWIP_DECLARE_MEMORY_ALIGNED -+#define LWIP_DECLARE_MEMORY_ALIGNED(variable_name, size) u8_t variable_name[LWIP_MEM_ALIGN_BUFFER(size)] -+#endif -+ -+/** Calculate memory size for an aligned buffer - returns the next highest -+ * multiple of MEM_ALIGNMENT (e.g. LWIP_MEM_ALIGN_SIZE(3) and -+ * LWIP_MEM_ALIGN_SIZE(4) will both yield 4 for MEM_ALIGNMENT == 4). -+ */ -+#ifndef LWIP_MEM_ALIGN_SIZE -+#define LWIP_MEM_ALIGN_SIZE(size) (((size) + MEM_ALIGNMENT - 1U) & ~(MEM_ALIGNMENT-1U)) -+#endif -+ -+/** Calculate safe memory size for an aligned buffer when using an unaligned -+ * type as storage. This includes a safety-margin on (MEM_ALIGNMENT - 1) at the -+ * start (e.g. if buffer is u8_t[] and actual data will be u32_t*) -+ */ -+#ifndef LWIP_MEM_ALIGN_BUFFER -+#define LWIP_MEM_ALIGN_BUFFER(size) (((size) + MEM_ALIGNMENT - 1U)) -+#endif -+ -+/** Align a memory pointer to the alignment defined by MEM_ALIGNMENT -+ * so that ADDR % MEM_ALIGNMENT == 0 -+ */ -+#ifndef LWIP_MEM_ALIGN -+#define LWIP_MEM_ALIGN(addr) ((void *)(((mem_ptr_t)(addr) + MEM_ALIGNMENT - 1) & ~(mem_ptr_t)(MEM_ALIGNMENT-1))) -+#endif -+ -+#ifdef __cplusplus -+extern "C" { -+#endif -+ -+/** Packed structs support. -+ * Placed BEFORE declaration of a packed struct.\n -+ * For examples of packed struct declarations, see include/lwip/prot/ subfolder.\n -+ * A port to GCC/clang is included in lwIP, if you use these compilers there is nothing to do here. -+ */ -+#ifndef PACK_STRUCT_BEGIN -+#define PACK_STRUCT_BEGIN -+#endif /* PACK_STRUCT_BEGIN */ -+ -+/** Packed structs support. -+ * Placed AFTER declaration of a packed struct.\n -+ * For examples of packed struct declarations, see include/lwip/prot/ subfolder.\n -+ * A port to GCC/clang is included in lwIP, if you use these compilers there is nothing to do here. -+ */ -+#ifndef PACK_STRUCT_END -+#define PACK_STRUCT_END -+#endif /* PACK_STRUCT_END */ -+ -+/** Packed structs support. -+ * Placed between end of declaration of a packed struct and trailing semicolon.\n -+ * For examples of packed struct declarations, see include/lwip/prot/ subfolder.\n -+ * A port to GCC/clang is included in lwIP, if you use these compilers there is nothing to do here. -+ */ -+#ifndef PACK_STRUCT_STRUCT -+#if defined(__GNUC__) || defined(__clang__) -+#define PACK_STRUCT_STRUCT __attribute__((packed)) + u16_t *port, u8_t local); ++#if LWIP_LITEOS_COMPAT ++#if PF_PACKET_SOCKET ++struct pf_packet_sockaddr_ll { ++ u16_t sll_protocol; ++ u16_t sll_hatype; ++ u8_t if_idx; ++ u8_t sll_halen; ++ u8_t sll_addr[NETIF_MAX_HWADDR_LEN]; ++}; ++err_t netconn_get_sockaddr_pf_packet(struct netconn *conn, struct pf_packet_sockaddr_ll *ll, u8_t local); ++#endif /* PF_PACKET_SOCKET */ ++#endif /* LWIP_LITEOS_COMPAT */ + /** @ingroup netconn_common */ + #define netconn_peer(c,i,p) netconn_getaddr(c,i,p,0) + /** @ingroup netconn_common */ + #define netconn_addr(c,i,p) netconn_getaddr(c,i,p,1) + ++#if PF_PACKET_SOCKET ++err_t netconn_bind(struct netconn *conn, const ip_addr_t *addr, u16_t port, u8_t ifindex); +#else -+#define PACK_STRUCT_STRUCT -+#endif -+#endif /* PACK_STRUCT_STRUCT */ -+ -+/** Packed structs support. -+ * Wraps u32_t and u16_t members.\n -+ * For examples of packed struct declarations, see include/lwip/prot/ subfolder.\n -+ * A port to GCC/clang is included in lwIP, if you use these compilers there is nothing to do here. -+ */ -+#ifndef PACK_STRUCT_FIELD -+#define PACK_STRUCT_FIELD(x) x -+#endif /* PACK_STRUCT_FIELD */ -+ -+/** Packed structs support. -+ * Wraps u8_t members, where some compilers warn that packing is not necessary.\n -+ * For examples of packed struct declarations, see include/lwip/prot/ subfolder.\n -+ * A port to GCC/clang is included in lwIP, if you use these compilers there is nothing to do here. -+ */ -+#ifndef PACK_STRUCT_FLD_8 -+#define PACK_STRUCT_FLD_8(x) PACK_STRUCT_FIELD(x) -+#endif /* PACK_STRUCT_FLD_8 */ -+ -+/** Packed structs support. -+ * Wraps members that are packed structs themselves, where some compilers warn that packing is not necessary.\n -+ * For examples of packed struct declarations, see include/lwip/prot/ subfolder.\n -+ * A port to GCC/clang is included in lwIP, if you use these compilers there is nothing to do here. -+ */ -+#ifndef PACK_STRUCT_FLD_S -+#define PACK_STRUCT_FLD_S(x) PACK_STRUCT_FIELD(x) -+#endif /* PACK_STRUCT_FLD_S */ -+ -+/** PACK_STRUCT_USE_INCLUDES==1: Packed structs support using \#include files before and after struct to be packed.\n -+ * The file included BEFORE the struct is "arch/bpstruct.h".\n -+ * The file included AFTER the struct is "arch/epstruct.h".\n -+ * This can be used to implement struct packing on MS Visual C compilers, see -+ * the Win32 port in the lwIP contrib repository for reference. -+ * For examples of packed struct declarations, see include/lwip/prot/ subfolder.\n -+ * A port to GCC/clang is included in lwIP, if you use these compilers there is nothing to do here. -+ */ -+#ifdef __DOXYGEN__ -+#define PACK_STRUCT_USE_INCLUDES -+#endif -+ -+/** Eliminates compiler warning about unused arguments (GCC -Wextra -Wunused). */ -+#ifndef LWIP_UNUSED_ARG -+#define LWIP_UNUSED_ARG(x) (void)x -+#endif /* LWIP_UNUSED_ARG */ -+ -+/** LWIP_PROVIDE_ERRNO==1: Let lwIP provide ERRNO values and the 'errno' variable. -+ * If this is disabled, cc.h must either define 'errno', include , -+ * define LWIP_ERRNO_STDINCLUDE to get included or -+ * define LWIP_ERRNO_INCLUDE to or equivalent. -+ */ -+#if defined __DOXYGEN__ -+#define LWIP_PROVIDE_ERRNO -+#endif -+ -+/** -+ * @} -+ */ + err_t netconn_bind(struct netconn *conn, const ip_addr_t *addr, u16_t port); ++#endif /* PF_PACKET_SOCKET */ + -+#ifdef __cplusplus -+} + err_t netconn_bind_if(struct netconn *conn, u8_t if_idx); + err_t netconn_connect(struct netconn *conn, const ip_addr_t *addr, u16_t port); + err_t netconn_disconnect (struct netconn *conn); +diff -Nur a/lwip-2.1.2/src/include/lwip/arch.h b/lwip-2.1.2/src/include/lwip/arch.h +--- a/lwip-2.1.2/src/include/lwip/arch.h 2021-06-29 15:16:18.808893323 +0800 ++++ b/lwip-2.1.2/src/include/lwip/arch.h 2021-06-29 15:16:44.632898725 +0800 +@@ -37,14 +37,7 @@ + #ifndef LWIP_HDR_ARCH_H + #define LWIP_HDR_ARCH_H + +-#ifndef LITTLE_ENDIAN +-#define LITTLE_ENDIAN 1234 +-#endif +- +-#ifndef BIG_ENDIAN +-#define BIG_ENDIAN 4321 +-#endif +- ++#include + #include "arch/cc.h" + + /** +@@ -149,6 +142,11 @@ + #ifndef X8_F + #define X8_F "02" PRIx8 + #endif ++#if LWIP_LITEOS_COMPAT ++#ifndef U8_F ++#define U8_F PRIu8 +#endif -+ -+#endif /* LWIP_HDR_ARCH_H */ ++#endif /* LWIP_LITEOS_COMPAT */ + #ifndef U16_F + #define U16_F PRIu16 + #endif diff -Nur a/lwip-2.1.2/src/include/lwip/err.h b/lwip-2.1.2/src/include/lwip/err.h ---- a/lwip-2.1.2/src/include/lwip/err.h 2021-05-08 18:13:52.635621024 +0800 -+++ b/lwip-2.1.2/src/include/lwip/err.h 2021-04-27 18:56:55.440353467 +0800 +--- a/lwip-2.1.2/src/include/lwip/err.h 2021-06-29 15:16:18.808893323 +0800 ++++ b/lwip-2.1.2/src/include/lwip/err.h 2021-06-29 15:16:44.636898726 +0800 @@ -85,9 +85,50 @@ /** Connection closed. */ ERR_CLSD = -15, @@ -18008,8 +2993,8 @@ diff -Nur a/lwip-2.1.2/src/include/lwip/err.h b/lwip-2.1.2/src/include/lwip/err. * a different type for your platform (must be signed). */ #ifdef LWIP_ERR_T diff -Nur a/lwip-2.1.2/src/include/lwip/etharp.h b/lwip-2.1.2/src/include/lwip/etharp.h ---- a/lwip-2.1.2/src/include/lwip/etharp.h 2021-05-08 18:13:52.635621024 +0800 -+++ b/lwip-2.1.2/src/include/lwip/etharp.h 2021-04-27 18:56:55.440353467 +0800 +--- a/lwip-2.1.2/src/include/lwip/etharp.h 2021-06-29 15:16:18.808893323 +0800 ++++ b/lwip-2.1.2/src/include/lwip/etharp.h 2021-06-29 15:16:44.636898726 +0800 @@ -46,6 +46,9 @@ #if LWIP_ARP || LWIP_ETHERNET /* don't build if not configured for use in lwipopts.h */ @@ -18032,8 +3017,8 @@ diff -Nur a/lwip-2.1.2/src/include/lwip/etharp.h b/lwip-2.1.2/src/include/lwip/e /** struct for queueing outgoing packets for unknown address * defined here to be accessed by memp.h diff -Nur a/lwip-2.1.2/src/include/lwip/if_api.h b/lwip-2.1.2/src/include/lwip/if_api.h ---- a/lwip-2.1.2/src/include/lwip/if_api.h 2021-05-08 18:13:52.635621024 +0800 -+++ b/lwip-2.1.2/src/include/lwip/if_api.h 2021-04-27 18:56:55.440353467 +0800 +--- a/lwip-2.1.2/src/include/lwip/if_api.h 2021-06-29 15:16:18.808893323 +0800 ++++ b/lwip-2.1.2/src/include/lwip/if_api.h 2021-06-29 15:16:44.636898726 +0800 @@ -49,10 +49,12 @@ extern "C" { #endif @@ -18048,320 +3033,43 @@ diff -Nur a/lwip-2.1.2/src/include/lwip/if_api.h b/lwip-2.1.2/src/include/lwip/i #if LWIP_COMPAT_SOCKETS #define if_indextoname(ifindex, ifname) lwip_if_indextoname(ifindex,ifname) diff -Nur a/lwip-2.1.2/src/include/lwip/inet.h b/lwip-2.1.2/src/include/lwip/inet.h ---- a/lwip-2.1.2/src/include/lwip/inet.h 2021-05-08 18:13:52.635621024 +0800 -+++ b/lwip-2.1.2/src/include/lwip/inet.h 2021-04-27 18:56:55.440353467 +0800 -@@ -1,169 +1,196 @@ --/** -- * @file -- * This file (together with sockets.h) aims to provide structs and functions from -- * - arpa/inet.h -- * - netinet/in.h -- * -- */ -- --/* -- * 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 -- * -- */ --#ifndef LWIP_HDR_INET_H --#define LWIP_HDR_INET_H -- --#include "lwip/opt.h" --#include "lwip/def.h" --#include "lwip/ip_addr.h" --#include "lwip/ip6_addr.h" -- --#ifdef __cplusplus --extern "C" { --#endif -- --/* If your port already typedef's in_addr_t, define IN_ADDR_T_DEFINED -- to prevent this code from redefining it. */ --#if !defined(in_addr_t) && !defined(IN_ADDR_T_DEFINED) --typedef u32_t in_addr_t; --#endif -- --struct in_addr { -- in_addr_t s_addr; --}; -- --struct in6_addr { -- union { -- u32_t u32_addr[4]; -- u8_t u8_addr[16]; -- } un; --#define s6_addr un.u8_addr --}; -- --/** 255.255.255.255 */ --#define INADDR_NONE IPADDR_NONE --/** 127.0.0.1 */ --#define INADDR_LOOPBACK IPADDR_LOOPBACK --/** 0.0.0.0 */ --#define INADDR_ANY IPADDR_ANY --/** 255.255.255.255 */ --#define INADDR_BROADCAST IPADDR_BROADCAST -- --/** This macro can be used to initialize a variable of type struct in6_addr -- to the IPv6 wildcard address. */ --#define IN6ADDR_ANY_INIT {{{0,0,0,0}}} --/** This macro can be used to initialize a variable of type struct in6_addr -- to the IPv6 loopback address. */ --#define IN6ADDR_LOOPBACK_INIT {{{0,0,0,PP_HTONL(1)}}} +--- a/lwip-2.1.2/src/include/lwip/inet.h 2021-06-29 15:16:18.808893323 +0800 ++++ b/lwip-2.1.2/src/include/lwip/inet.h 2021-06-29 15:16:44.636898726 +0800 +@@ -49,6 +49,7 @@ + extern "C" { + #endif + ++#if !LWIP_LITEOS_COMPAT + /* If your port already typedef's in_addr_t, define IN_ADDR_T_DEFINED + to prevent this code from redefining it. */ + #if !defined(in_addr_t) && !defined(IN_ADDR_T_DEFINED) +@@ -82,8 +83,6 @@ + /** This macro can be used to initialize a variable of type struct in6_addr + to the IPv6 loopback address. */ + #define IN6ADDR_LOOPBACK_INIT {{{0,0,0,PP_HTONL(1)}}} -/** This variable is initialized by the system to contain the wildcard IPv6 address. */ -extern const struct in6_addr in6addr_any; -- --/* Definitions of the bits in an (IPv4) Internet address integer. -- -- On subnets, host and network parts are found according to -- the subnet mask, not these masks. */ --#define IN_CLASSA(a) IP_CLASSA(a) --#define IN_CLASSA_NET IP_CLASSA_NET --#define IN_CLASSA_NSHIFT IP_CLASSA_NSHIFT --#define IN_CLASSA_HOST IP_CLASSA_HOST --#define IN_CLASSA_MAX IP_CLASSA_MAX -- --#define IN_CLASSB(b) IP_CLASSB(b) --#define IN_CLASSB_NET IP_CLASSB_NET --#define IN_CLASSB_NSHIFT IP_CLASSB_NSHIFT --#define IN_CLASSB_HOST IP_CLASSB_HOST --#define IN_CLASSB_MAX IP_CLASSB_MAX -- --#define IN_CLASSC(c) IP_CLASSC(c) --#define IN_CLASSC_NET IP_CLASSC_NET --#define IN_CLASSC_NSHIFT IP_CLASSC_NSHIFT --#define IN_CLASSC_HOST IP_CLASSC_HOST --#define IN_CLASSC_MAX IP_CLASSC_MAX -- --#define IN_CLASSD(d) IP_CLASSD(d) --#define IN_CLASSD_NET IP_CLASSD_NET /* These ones aren't really */ --#define IN_CLASSD_NSHIFT IP_CLASSD_NSHIFT /* net and host fields, but */ --#define IN_CLASSD_HOST IP_CLASSD_HOST /* routing needn't know. */ --#define IN_CLASSD_MAX IP_CLASSD_MAX -- --#define IN_MULTICAST(a) IP_MULTICAST(a) -- --#define IN_EXPERIMENTAL(a) IP_EXPERIMENTAL(a) --#define IN_BADCLASS(a) IP_BADCLASS(a) -- --#define IN_LOOPBACKNET IP_LOOPBACKNET -- -- --#ifndef INET_ADDRSTRLEN --#define INET_ADDRSTRLEN IP4ADDR_STRLEN_MAX --#endif --#if LWIP_IPV6 --#ifndef INET6_ADDRSTRLEN --#define INET6_ADDRSTRLEN IP6ADDR_STRLEN_MAX --#endif --#endif -- --#if LWIP_IPV4 -- --#define inet_addr_from_ip4addr(target_inaddr, source_ipaddr) ((target_inaddr)->s_addr = ip4_addr_get_u32(source_ipaddr)) --#define inet_addr_to_ip4addr(target_ipaddr, source_inaddr) (ip4_addr_set_u32(target_ipaddr, (source_inaddr)->s_addr)) -- --/* directly map this to the lwip internal functions */ --#define inet_addr(cp) ipaddr_addr(cp) --#define inet_aton(cp, addr) ip4addr_aton(cp, (ip4_addr_t*)addr) --#define inet_ntoa(addr) ip4addr_ntoa((const ip4_addr_t*)&(addr)) --#define inet_ntoa_r(addr, buf, buflen) ip4addr_ntoa_r((const ip4_addr_t*)&(addr), buf, buflen) -- --#endif /* LWIP_IPV4 */ -- --#if LWIP_IPV6 --#define inet6_addr_from_ip6addr(target_in6addr, source_ip6addr) {(target_in6addr)->un.u32_addr[0] = (source_ip6addr)->addr[0]; \ -- (target_in6addr)->un.u32_addr[1] = (source_ip6addr)->addr[1]; \ -- (target_in6addr)->un.u32_addr[2] = (source_ip6addr)->addr[2]; \ -- (target_in6addr)->un.u32_addr[3] = (source_ip6addr)->addr[3];} --#define inet6_addr_to_ip6addr(target_ip6addr, source_in6addr) {(target_ip6addr)->addr[0] = (source_in6addr)->un.u32_addr[0]; \ -- (target_ip6addr)->addr[1] = (source_in6addr)->un.u32_addr[1]; \ -- (target_ip6addr)->addr[2] = (source_in6addr)->un.u32_addr[2]; \ -- (target_ip6addr)->addr[3] = (source_in6addr)->un.u32_addr[3]; \ -- ip6_addr_clear_zone(target_ip6addr);} -- --/* directly map this to the lwip internal functions */ --#define inet6_aton(cp, addr) ip6addr_aton(cp, (ip6_addr_t*)addr) --#define inet6_ntoa(addr) ip6addr_ntoa((const ip6_addr_t*)&(addr)) --#define inet6_ntoa_r(addr, buf, buflen) ip6addr_ntoa_r((const ip6_addr_t*)&(addr), buf, buflen) -- --#endif /* LWIP_IPV6 */ -- -- --#ifdef __cplusplus --} --#endif -- --#endif /* LWIP_HDR_INET_H */ -+/** -+ * @file -+ * This file (together with sockets.h) aims to provide structs and functions from -+ * - arpa/inet.h -+ * - netinet/in.h -+ * -+ */ -+ -+/* -+ * 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 -+ * -+ */ -+#ifndef LWIP_HDR_INET_H -+#define LWIP_HDR_INET_H -+ -+#include "lwip/opt.h" -+#include "lwip/def.h" -+#include "lwip/ip_addr.h" -+#include "lwip/ip6_addr.h" -+ -+#ifdef __cplusplus -+extern "C" { -+#endif -+ -+#if !LWIP_LITEOS_COMPAT -+/* If your port already typedef's in_addr_t, define IN_ADDR_T_DEFINED -+ to prevent this code from redefining it. */ -+#if !defined(in_addr_t) && !defined(IN_ADDR_T_DEFINED) -+typedef u32_t in_addr_t; -+#endif -+ -+struct in_addr { -+ in_addr_t s_addr; -+}; -+ -+struct in6_addr { -+ union { -+ u32_t u32_addr[4]; -+ u8_t u8_addr[16]; -+ } un; -+#define s6_addr un.u8_addr -+}; -+ -+/** 255.255.255.255 */ -+#define INADDR_NONE IPADDR_NONE -+/** 127.0.0.1 */ -+#define INADDR_LOOPBACK IPADDR_LOOPBACK -+/** 0.0.0.0 */ -+#define INADDR_ANY IPADDR_ANY -+/** 255.255.255.255 */ -+#define INADDR_BROADCAST IPADDR_BROADCAST -+ -+/** This macro can be used to initialize a variable of type struct in6_addr -+ to the IPv6 wildcard address. */ -+#define IN6ADDR_ANY_INIT {{{0,0,0,0}}} -+/** This macro can be used to initialize a variable of type struct in6_addr -+ to the IPv6 loopback address. */ -+#define IN6ADDR_LOOPBACK_INIT {{{0,0,0,PP_HTONL(1)}}} -+ -+/* Definitions of the bits in an (IPv4) Internet address integer. -+ -+ On subnets, host and network parts are found according to -+ the subnet mask, not these masks. */ -+#define IN_CLASSA(a) IP_CLASSA(a) -+#define IN_CLASSA_NET IP_CLASSA_NET -+#define IN_CLASSA_NSHIFT IP_CLASSA_NSHIFT -+#define IN_CLASSA_HOST IP_CLASSA_HOST -+#define IN_CLASSA_MAX IP_CLASSA_MAX -+ -+#define IN_CLASSB(b) IP_CLASSB(b) -+#define IN_CLASSB_NET IP_CLASSB_NET -+#define IN_CLASSB_NSHIFT IP_CLASSB_NSHIFT -+#define IN_CLASSB_HOST IP_CLASSB_HOST -+#define IN_CLASSB_MAX IP_CLASSB_MAX -+ -+#define IN_CLASSC(c) IP_CLASSC(c) -+#define IN_CLASSC_NET IP_CLASSC_NET -+#define IN_CLASSC_NSHIFT IP_CLASSC_NSHIFT -+#define IN_CLASSC_HOST IP_CLASSC_HOST -+#define IN_CLASSC_MAX IP_CLASSC_MAX -+ -+#define IN_CLASSD(d) IP_CLASSD(d) -+#define IN_CLASSD_NET IP_CLASSD_NET /* These ones aren't really */ -+#define IN_CLASSD_NSHIFT IP_CLASSD_NSHIFT /* net and host fields, but */ -+#define IN_CLASSD_HOST IP_CLASSD_HOST /* routing needn't know. */ -+#define IN_CLASSD_MAX IP_CLASSD_MAX -+ -+#define IN_MULTICAST(a) IP_MULTICAST(a) -+ -+#define IN_EXPERIMENTAL(a) IP_EXPERIMENTAL(a) -+#define IN_BADCLASS(a) IP_BADCLASS(a) -+ -+#define IN_LOOPBACKNET IP_LOOPBACKNET + + /* Definitions of the bits in an (IPv4) Internet address integer. + +@@ -119,7 +118,12 @@ + #define IN_BADCLASS(a) IP_BADCLASS(a) + + #define IN_LOOPBACKNET IP_LOOPBACKNET +#endif /* !LWIP_LITEOS_COMPAT */ -+ + +/** This variable is initialized by the system to contain the wildcard IPv6 address. */ +extern const struct in6_addr in6addr_any; +/** Added new structure for ipv6 loopback as per section 3.9 of rfc 2553/3493 */ +extern const struct in6_addr in6addr_loopback; -+ -+#ifndef INET_ADDRSTRLEN -+#define INET_ADDRSTRLEN IP4ADDR_STRLEN_MAX -+#endif -+#if LWIP_IPV6 -+#ifndef INET6_ADDRSTRLEN -+#define INET6_ADDRSTRLEN IP6ADDR_STRLEN_MAX -+#endif -+#endif -+ -+#if LWIP_IPV4 -+ -+#define inet_addr_from_ip4addr(target_inaddr, source_ipaddr) ((target_inaddr)->s_addr = ip4_addr_get_u32(source_ipaddr)) -+#define inet_addr_to_ip4addr(target_ipaddr, source_inaddr) (ip4_addr_set_u32(target_ipaddr, (source_inaddr)->s_addr)) -+ -+/* directly map this to the lwip internal functions */ + + #ifndef INET_ADDRSTRLEN + #define INET_ADDRSTRLEN IP4ADDR_STRLEN_MAX +@@ -136,14 +140,37 @@ + #define inet_addr_to_ip4addr(target_ipaddr, source_inaddr) (ip4_addr_set_u32(target_ipaddr, (source_inaddr)->s_addr)) + + /* directly map this to the lwip internal functions */ +-#define inet_addr(cp) ipaddr_addr(cp) +#if LWIP_INET_ADDR_FUNC +unsigned int inet_addr(const char *cp); +#else @@ -18371,20 +3079,20 @@ diff -Nur a/lwip-2.1.2/src/include/lwip/inet.h b/lwip-2.1.2/src/include/lwip/ine +#if LWIP_INET_ATON_FUNC +int inet_aton(const char *cp, struct in_addr *addr); +#else -+#define inet_aton(cp, addr) ip4addr_aton(cp, (ip4_addr_t*)addr) + #define inet_aton(cp, addr) ip4addr_aton(cp, (ip4_addr_t*)addr) +#endif + +#if LWIP_INET_NTOA_FUNC +char *inet_ntoa (struct in_addr in); +#else -+#define inet_ntoa(addr) ip4addr_ntoa((const ip4_addr_t*)&(addr)) + #define inet_ntoa(addr) ip4addr_ntoa((const ip4_addr_t*)&(addr)) +#endif + -+#define inet_ntoa_r(addr, buf, buflen) ip4addr_ntoa_r((const ip4_addr_t*)&(addr), buf, buflen) -+ -+#endif /* LWIP_IPV4 */ -+ -+#if LWIP_IPV6 + #define inet_ntoa_r(addr, buf, buflen) ip4addr_ntoa_r((const ip4_addr_t*)&(addr), buf, buflen) + + #endif /* LWIP_IPV4 */ + + #if LWIP_IPV6 +/* current the struct ip6_addr for define LWIP_IPV6_SCOPES 0 */ +#if LWIP_LITEOS_COMPAT +#define inet6_addr_from_ip6addr(target_in6addr, source_ip6addr) { \ @@ -18393,32 +3101,21 @@ diff -Nur a/lwip-2.1.2/src/include/lwip/inet.h b/lwip-2.1.2/src/include/lwip/ine + memcpy((target_ip6addr)->addr, (source_in6addr)->s6_addr, sizeof(struct ip6_addr)); \ + ip6_addr_clear_zone(target_ip6addr);} +#else -+#define inet6_addr_from_ip6addr(target_in6addr, source_ip6addr) {(target_in6addr)->un.u32_addr[0] = (source_ip6addr)->addr[0]; \ -+ (target_in6addr)->un.u32_addr[1] = (source_ip6addr)->addr[1]; \ -+ (target_in6addr)->un.u32_addr[2] = (source_ip6addr)->addr[2]; \ -+ (target_in6addr)->un.u32_addr[3] = (source_ip6addr)->addr[3];} -+#define inet6_addr_to_ip6addr(target_ip6addr, source_in6addr) {(target_ip6addr)->addr[0] = (source_in6addr)->un.u32_addr[0]; \ -+ (target_ip6addr)->addr[1] = (source_in6addr)->un.u32_addr[1]; \ -+ (target_ip6addr)->addr[2] = (source_in6addr)->un.u32_addr[2]; \ -+ (target_ip6addr)->addr[3] = (source_in6addr)->un.u32_addr[3]; \ -+ ip6_addr_clear_zone(target_ip6addr);} + #define inet6_addr_from_ip6addr(target_in6addr, source_ip6addr) {(target_in6addr)->un.u32_addr[0] = (source_ip6addr)->addr[0]; \ + (target_in6addr)->un.u32_addr[1] = (source_ip6addr)->addr[1]; \ + (target_in6addr)->un.u32_addr[2] = (source_ip6addr)->addr[2]; \ +@@ -153,7 +180,7 @@ + (target_ip6addr)->addr[2] = (source_in6addr)->un.u32_addr[2]; \ + (target_ip6addr)->addr[3] = (source_in6addr)->un.u32_addr[3]; \ + ip6_addr_clear_zone(target_ip6addr);} +- +#endif /* LWIP_LITEOS_COMPAT */ -+/* directly map this to the lwip internal functions */ -+#define inet6_aton(cp, addr) ip6addr_aton(cp, (ip6_addr_t*)addr) -+#define inet6_ntoa(addr) ip6addr_ntoa((const ip6_addr_t*)&(addr)) -+#define inet6_ntoa_r(addr, buf, buflen) ip6addr_ntoa_r((const ip6_addr_t*)&(addr), buf, buflen) -+ -+#endif /* LWIP_IPV6 */ -+ -+ -+#ifdef __cplusplus -+} -+#endif -+ -+#endif /* LWIP_HDR_INET_H */ + /* directly map this to the lwip internal functions */ + #define inet6_aton(cp, addr) ip6addr_aton(cp, (ip6_addr_t*)addr) + #define inet6_ntoa(addr) ip6addr_ntoa((const ip6_addr_t*)&(addr)) diff -Nur a/lwip-2.1.2/src/include/lwip/ip_addr.h b/lwip-2.1.2/src/include/lwip/ip_addr.h ---- a/lwip-2.1.2/src/include/lwip/ip_addr.h 2021-05-08 18:13:52.635621024 +0800 -+++ b/lwip-2.1.2/src/include/lwip/ip_addr.h 2021-04-27 18:56:55.440353467 +0800 +--- a/lwip-2.1.2/src/include/lwip/ip_addr.h 2021-06-29 15:16:18.808893323 +0800 ++++ b/lwip-2.1.2/src/include/lwip/ip_addr.h 2021-06-29 15:16:44.636898726 +0800 @@ -158,18 +158,31 @@ /** @ingroup ipaddr */ #define ip_addr_set(dest, src) do{ IP_SET_TYPE(dest, IP_GET_TYPE(src)); if(IP_IS_V6(src)){ \ @@ -18604,8 +3301,8 @@ diff -Nur a/lwip-2.1.2/src/include/lwip/ip_addr.h b/lwip-2.1.2/src/include/lwip/ #define ipaddr_ntoa_r(ipaddr, buf, buflen) ip6addr_ntoa_r(ipaddr, buf, buflen) #define ipaddr_aton(cp, addr) ip6addr_aton(cp, addr) diff -Nur a/lwip-2.1.2/src/include/lwip/ip.h b/lwip-2.1.2/src/include/lwip/ip.h ---- a/lwip-2.1.2/src/include/lwip/ip.h 2021-05-08 18:13:52.635621024 +0800 -+++ b/lwip-2.1.2/src/include/lwip/ip.h 2021-04-27 18:56:55.440353467 +0800 +--- a/lwip-2.1.2/src/include/lwip/ip.h 2021-06-29 15:16:18.808893323 +0800 ++++ b/lwip-2.1.2/src/include/lwip/ip.h 2021-06-29 15:16:44.636898726 +0800 @@ -99,7 +99,10 @@ #define SOF_REUSEADDR 0x04U /* allow local address reuse */ #define SOF_KEEPALIVE 0x08U /* keep connections alive */ @@ -18657,8 +3354,8 @@ diff -Nur a/lwip-2.1.2/src/include/lwip/ip.h b/lwip-2.1.2/src/include/lwip/ip.h (netif) = ip_route(src, dest); \ (ipaddr) = ip_netif_get_local_ip(netif, dest); \ diff -Nur a/lwip-2.1.2/src/include/lwip/netbuf.h b/lwip-2.1.2/src/include/lwip/netbuf.h ---- a/lwip-2.1.2/src/include/lwip/netbuf.h 2021-05-08 18:13:52.635621024 +0800 -+++ b/lwip-2.1.2/src/include/lwip/netbuf.h 2021-04-27 18:56:55.440353467 +0800 +--- a/lwip-2.1.2/src/include/lwip/netbuf.h 2021-06-29 15:16:18.808893323 +0800 ++++ b/lwip-2.1.2/src/include/lwip/netbuf.h 2021-06-29 15:16:44.636898726 +0800 @@ -55,13 +55,22 @@ #define NETBUF_FLAG_DESTADDR 0x01 /** This netbuf includes a checksum */ @@ -18704,300 +3401,56 @@ diff -Nur a/lwip-2.1.2/src/include/lwip/netbuf.h b/lwip-2.1.2/src/include/lwip/n #define netbuf_destaddr(buf) (&((buf)->toaddr)) #define netbuf_set_destaddr(buf, destaddr) ip_addr_set(&((buf)->toaddr), destaddr) diff -Nur a/lwip-2.1.2/src/include/lwip/netdb.h b/lwip-2.1.2/src/include/lwip/netdb.h ---- a/lwip-2.1.2/src/include/lwip/netdb.h 2021-05-08 18:13:52.635621024 +0800 -+++ b/lwip-2.1.2/src/include/lwip/netdb.h 2021-04-27 18:56:55.440353467 +0800 -@@ -1,150 +1,175 @@ --/** -- * @file -- * NETDB API (sockets) -- */ -- --/* -- * 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: Simon Goldschmidt -- * -- */ --#ifndef LWIP_HDR_NETDB_H --#define LWIP_HDR_NETDB_H -- --#include "lwip/opt.h" -- --#if LWIP_DNS && LWIP_SOCKET -- --#include "lwip/arch.h" --#include "lwip/inet.h" --#include "lwip/sockets.h" -- --#ifdef __cplusplus --extern "C" { --#endif -- --/* some rarely used options */ --#ifndef LWIP_DNS_API_DECLARE_H_ERRNO --#define LWIP_DNS_API_DECLARE_H_ERRNO 1 --#endif -- --#ifndef LWIP_DNS_API_DEFINE_ERRORS --#define LWIP_DNS_API_DEFINE_ERRORS 1 --#endif -- --#ifndef LWIP_DNS_API_DEFINE_FLAGS --#define LWIP_DNS_API_DEFINE_FLAGS 1 --#endif -- --#ifndef LWIP_DNS_API_DECLARE_STRUCTS --#define LWIP_DNS_API_DECLARE_STRUCTS 1 --#endif -- --#if LWIP_DNS_API_DEFINE_ERRORS --/** Errors used by the DNS API functions, h_errno can be one of them */ --#define EAI_NONAME 200 --#define EAI_SERVICE 201 --#define EAI_FAIL 202 --#define EAI_MEMORY 203 --#define EAI_FAMILY 204 -- --#define HOST_NOT_FOUND 210 --#define NO_DATA 211 --#define NO_RECOVERY 212 --#define TRY_AGAIN 213 --#endif /* LWIP_DNS_API_DEFINE_ERRORS */ -- --#if LWIP_DNS_API_DEFINE_FLAGS --/* input flags for struct addrinfo */ --#define AI_PASSIVE 0x01 --#define AI_CANONNAME 0x02 --#define AI_NUMERICHOST 0x04 --#define AI_NUMERICSERV 0x08 --#define AI_V4MAPPED 0x10 --#define AI_ALL 0x20 --#define AI_ADDRCONFIG 0x40 --#endif /* LWIP_DNS_API_DEFINE_FLAGS */ -- --#if LWIP_DNS_API_DECLARE_STRUCTS --struct hostent { -- char *h_name; /* Official name of the host. */ -- char **h_aliases; /* A pointer to an array of pointers to alternative host names, -- terminated by a null pointer. */ -- int h_addrtype; /* Address type. */ -- int h_length; /* The length, in bytes, of the address. */ -- char **h_addr_list; /* A pointer to an array of pointers to network addresses (in -- network byte order) for the host, terminated by a null pointer. */ --#define h_addr h_addr_list[0] /* for backward compatibility */ --}; -- --struct addrinfo { -- int ai_flags; /* Input flags. */ -- int ai_family; /* Address family of socket. */ -- int ai_socktype; /* Socket type. */ -- int ai_protocol; /* Protocol of socket. */ -- socklen_t ai_addrlen; /* Length of socket address. */ -- struct sockaddr *ai_addr; /* Socket address of socket. */ -- char *ai_canonname; /* Canonical name of service location. */ -- struct addrinfo *ai_next; /* Pointer to next in list. */ --}; --#endif /* LWIP_DNS_API_DECLARE_STRUCTS */ -- --#define NETDB_ELEM_SIZE (sizeof(struct addrinfo) + sizeof(struct sockaddr_storage) + DNS_MAX_NAME_LENGTH + 1) -- --#if LWIP_DNS_API_DECLARE_H_ERRNO --/* application accessible error code set by the DNS API functions */ --extern int h_errno; --#endif /* LWIP_DNS_API_DECLARE_H_ERRNO*/ -- --struct hostent *lwip_gethostbyname(const char *name); --int lwip_gethostbyname_r(const char *name, struct hostent *ret, char *buf, -- size_t buflen, struct hostent **result, int *h_errnop); --void lwip_freeaddrinfo(struct addrinfo *ai); --int lwip_getaddrinfo(const char *nodename, -- const char *servname, -- const struct addrinfo *hints, -- struct addrinfo **res); -- --#if LWIP_COMPAT_SOCKETS --/** @ingroup netdbapi */ --#define gethostbyname(name) lwip_gethostbyname(name) --/** @ingroup netdbapi */ --#define gethostbyname_r(name, ret, buf, buflen, result, h_errnop) \ -- lwip_gethostbyname_r(name, ret, buf, buflen, result, h_errnop) --/** @ingroup netdbapi */ --#define freeaddrinfo(addrinfo) lwip_freeaddrinfo(addrinfo) --/** @ingroup netdbapi */ --#define getaddrinfo(nodname, servname, hints, res) \ -- lwip_getaddrinfo(nodname, servname, hints, res) --#endif /* LWIP_COMPAT_SOCKETS */ -- --#ifdef __cplusplus --} --#endif -- --#endif /* LWIP_DNS && LWIP_SOCKET */ -- --#endif /* LWIP_HDR_NETDB_H */ -+/** -+ * @file -+ * NETDB API (sockets) -+ */ -+ -+/* -+ * 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: Simon Goldschmidt -+ * -+ */ -+#ifndef LWIP_HDR_NETDB_H -+#define LWIP_HDR_NETDB_H -+ -+#include "lwip/opt.h" -+ +--- a/lwip-2.1.2/src/include/lwip/netdb.h 2021-06-29 15:16:18.808893323 +0800 ++++ b/lwip-2.1.2/src/include/lwip/netdb.h 2021-06-29 15:16:44.636898726 +0800 +@@ -36,6 +36,10 @@ + + #include "lwip/opt.h" + +#if LWIP_LITEOS_COMPAT +#include +#endif + -+#if LWIP_DNS && LWIP_SOCKET -+ -+#include "lwip/arch.h" -+#include "lwip/inet.h" -+#include "lwip/sockets.h" -+ -+#ifdef __cplusplus -+extern "C" { -+#endif -+ -+/* some rarely used options */ -+#ifndef LWIP_DNS_API_DECLARE_H_ERRNO -+#define LWIP_DNS_API_DECLARE_H_ERRNO 1 -+#endif -+ -+#ifndef LWIP_DNS_API_DEFINE_ERRORS -+#define LWIP_DNS_API_DEFINE_ERRORS 1 -+#endif -+ -+#ifndef LWIP_DNS_API_DEFINE_FLAGS -+#define LWIP_DNS_API_DEFINE_FLAGS 1 -+#endif -+ -+#ifndef LWIP_DNS_API_DECLARE_STRUCTS -+#define LWIP_DNS_API_DECLARE_STRUCTS 1 -+#endif -+ + #if LWIP_DNS && LWIP_SOCKET + + #include "lwip/arch.h" +@@ -63,6 +67,7 @@ + #define LWIP_DNS_API_DECLARE_STRUCTS 1 + #endif + +#if !LWIP_LITEOS_COMPAT -+#if LWIP_DNS_API_DEFINE_ERRORS -+/** Errors used by the DNS API functions, h_errno can be one of them */ -+#define EAI_NONAME 200 -+#define EAI_SERVICE 201 -+#define EAI_FAIL 202 -+#define EAI_MEMORY 203 -+#define EAI_FAMILY 204 -+ -+#define HOST_NOT_FOUND 210 -+#define NO_DATA 211 -+#define NO_RECOVERY 212 -+#define TRY_AGAIN 213 -+#endif /* LWIP_DNS_API_DEFINE_ERRORS */ -+ -+#if LWIP_DNS_API_DEFINE_FLAGS -+/* input flags for struct addrinfo */ -+#define AI_PASSIVE 0x01 -+#define AI_CANONNAME 0x02 -+#define AI_NUMERICHOST 0x04 -+#define AI_NUMERICSERV 0x08 -+#define AI_V4MAPPED 0x10 -+#define AI_ALL 0x20 -+#define AI_ADDRCONFIG 0x40 -+#endif /* LWIP_DNS_API_DEFINE_FLAGS */ -+ -+#if LWIP_DNS_API_DECLARE_STRUCTS -+struct hostent { -+ char *h_name; /* Official name of the host. */ -+ char **h_aliases; /* A pointer to an array of pointers to alternative host names, -+ terminated by a null pointer. */ -+ int h_addrtype; /* Address type. */ -+ int h_length; /* The length, in bytes, of the address. */ -+ char **h_addr_list; /* A pointer to an array of pointers to network addresses (in -+ network byte order) for the host, terminated by a null pointer. */ -+#define h_addr h_addr_list[0] /* for backward compatibility */ -+}; -+ -+struct addrinfo { -+ int ai_flags; /* Input flags. */ -+ int ai_family; /* Address family of socket. */ -+ int ai_socktype; /* Socket type. */ -+ int ai_protocol; /* Protocol of socket. */ -+ socklen_t ai_addrlen; /* Length of socket address. */ -+ struct sockaddr *ai_addr; /* Socket address of socket. */ -+ char *ai_canonname; /* Canonical name of service location. */ -+ struct addrinfo *ai_next; /* Pointer to next in list. */ -+}; -+#endif /* LWIP_DNS_API_DECLARE_STRUCTS */ -+ -+ -+#if LWIP_DNS_API_DECLARE_H_ERRNO -+/* application accessible error code set by the DNS API functions */ -+extern int h_errno; -+#endif /* LWIP_DNS_API_DECLARE_H_ERRNO*/ + #if LWIP_DNS_API_DEFINE_ERRORS + /** Errors used by the DNS API functions, h_errno can be one of them */ + #define EAI_NONAME 200 +@@ -112,23 +117,39 @@ + }; + #endif /* LWIP_DNS_API_DECLARE_STRUCTS */ + +-#define NETDB_ELEM_SIZE (sizeof(struct addrinfo) + sizeof(struct sockaddr_storage) + DNS_MAX_NAME_LENGTH + 1) + + #if LWIP_DNS_API_DECLARE_H_ERRNO + /* application accessible error code set by the DNS API functions */ + extern int h_errno; + #endif /* LWIP_DNS_API_DECLARE_H_ERRNO*/ +#endif /* !LWIP_LITEOS_COMPAT */ -+ + +#define NETDB_ELEM_SIZE (sizeof(struct addrinfo) + sizeof(struct sockaddr_storage) + DNS_MAX_NAME_LENGTH + 1) + +#if LWIP_GETHOSTBYNAME || (defined(LWIP_COMPAT_SOCKETS) && (LWIP_COMPAT_SOCKETS != 2)) -+struct hostent *lwip_gethostbyname(const char *name); + struct hostent *lwip_gethostbyname(const char *name); +#endif /* LWIP_GETHOSTBYNAME || (defined(LWIP_COMPAT_SOCKETS) && (LWIP_COMPAT_SOCKETS != 2)) */ +#if (defined(LWIP_COMPAT_SOCKETS) && LWIP_COMPAT_SOCKETS != 2) -+int lwip_gethostbyname_r(const char *name, struct hostent *ret, char *buf, -+ size_t buflen, struct hostent **result, int *h_errnop); + int lwip_gethostbyname_r(const char *name, struct hostent *ret, char *buf, + size_t buflen, struct hostent **result, int *h_errnop); +#endif /* (defined(LWIP_COMPAT_SOCKETS) && LWIP_COMPAT_SOCKETS != 2) */ +#if (defined(LWIP_COMPAT_SOCKETS) && LWIP_COMPAT_SOCKETS != 2) -+void lwip_freeaddrinfo(struct addrinfo *ai); -+int lwip_getaddrinfo(const char *nodename, -+ const char *servname, -+ const struct addrinfo *hints, -+ struct addrinfo **res); + void lwip_freeaddrinfo(struct addrinfo *ai); + int lwip_getaddrinfo(const char *nodename, + const char *servname, + const struct addrinfo *hints, + struct addrinfo **res); +- +-#if LWIP_COMPAT_SOCKETS +#endif /* (defined(LWIP_COMPAT_SOCKETS) && LWIP_COMPAT_SOCKETS != 2) */ +#if LWIP_DNS_REVERSE +int lwip_getnameinfo(const struct sockaddr *sa, @@ -19009,32 +3462,25 @@ diff -Nur a/lwip-2.1.2/src/include/lwip/netdb.h b/lwip-2.1.2/src/include/lwip/ne + int flags); +#endif /* LWIP_DNS_REVERSE */ +#if defined(LWIP_COMPAT_SOCKETS) && LWIP_COMPAT_SOCKETS != 2 -+/** @ingroup netdbapi */ -+#define gethostbyname(name) lwip_gethostbyname(name) -+/** @ingroup netdbapi */ -+#define gethostbyname_r(name, ret, buf, buflen, result, h_errnop) \ -+ lwip_gethostbyname_r(name, ret, buf, buflen, result, h_errnop) -+/** @ingroup netdbapi */ -+#define freeaddrinfo(addrinfo) lwip_freeaddrinfo(addrinfo) -+/** @ingroup netdbapi */ -+#define getaddrinfo(nodname, servname, hints, res) \ -+ lwip_getaddrinfo(nodname, servname, hints, res) + /** @ingroup netdbapi */ + #define gethostbyname(name) lwip_gethostbyname(name) + /** @ingroup netdbapi */ +@@ -139,7 +160,11 @@ + /** @ingroup netdbapi */ + #define getaddrinfo(nodname, servname, hints, res) \ + lwip_getaddrinfo(nodname, servname, hints, res) +-#endif /* LWIP_COMPAT_SOCKETS */ + +/* @ingroup netdbapi */ +#define getnameinfo(sock, sock_size, host, host_len, servname, servname_size, flags) \ + lwip_getnameinfo(sock, sock_size, host, host_len, servname, servname_size, flags) +#endif /* defined(LWIP_COMPAT_SOCKETS) && LWIP_COMPAT_SOCKETS != 2 */ -+ -+#ifdef __cplusplus -+} -+#endif -+ -+#endif /* LWIP_DNS && LWIP_SOCKET */ -+ -+#endif /* LWIP_HDR_NETDB_H */ + + #ifdef __cplusplus + } diff -Nur a/lwip-2.1.2/src/include/lwip/netifapi.h b/lwip-2.1.2/src/include/lwip/netifapi.h ---- a/lwip-2.1.2/src/include/lwip/netifapi.h 2021-05-08 18:13:52.635621024 +0800 -+++ b/lwip-2.1.2/src/include/lwip/netifapi.h 2021-04-27 18:56:55.440353467 +0800 +--- a/lwip-2.1.2/src/include/lwip/netifapi.h 2021-06-29 15:16:18.808893323 +0800 ++++ b/lwip-2.1.2/src/include/lwip/netifapi.h 2021-06-29 15:16:44.636898726 +0800 @@ -73,6 +73,30 @@ const ip4_addr_t *netmask, const ip4_addr_t *gw); #endif /* LWIP_IPV4*/ @@ -19067,8 +3513,8 @@ diff -Nur a/lwip-2.1.2/src/include/lwip/netifapi.h b/lwip-2.1.2/src/include/lwip netifapi_errt_fn errtfunc); diff -Nur a/lwip-2.1.2/src/include/lwip/netif.h b/lwip-2.1.2/src/include/lwip/netif.h ---- a/lwip-2.1.2/src/include/lwip/netif.h 2021-05-08 18:13:52.635621024 +0800 -+++ b/lwip-2.1.2/src/include/lwip/netif.h 2021-04-27 18:56:55.440353467 +0800 +--- a/lwip-2.1.2/src/include/lwip/netif.h 2021-06-29 15:16:18.808893323 +0800 ++++ b/lwip-2.1.2/src/include/lwip/netif.h 2021-06-29 15:16:44.640898726 +0800 @@ -48,6 +48,7 @@ #include "lwip/def.h" #include "lwip/pbuf.h" @@ -19077,7 +3523,7 @@ diff -Nur a/lwip-2.1.2/src/include/lwip/netif.h b/lwip-2.1.2/src/include/lwip/ne #ifdef __cplusplus extern "C" { -@@ -67,7 +68,16 @@ +@@ -67,8 +68,17 @@ * netif can be identified by in APIs. Composed of * 2 chars, 3 (max) digits, and 1 \0 */ @@ -19089,12 +3535,13 @@ diff -Nur a/lwip-2.1.2/src/include/lwip/netif.h b/lwip-2.1.2/src/include/lwip/ne +#endif + +#define NETIF_LOOPBACK_MTU ((16 * 1024) + 20 + 20 + 12) -+ + +/** Type of link layer, these macros should be used for link_layer_type of struct netif */ +#define LOOPBACK_IF 772 - ++#define NETIF_MTU_MIN 1280 /** * @defgroup netif_flags Flags + * @ingroup netif @@ -106,6 +116,17 @@ * Set by the netif driver in its init function. */ #define NETIF_FLAG_MLD6 0x40U @@ -19180,7 +3627,7 @@ diff -Nur a/lwip-2.1.2/src/include/lwip/netif.h b/lwip-2.1.2/src/include/lwip/ne #if LWIP_IPV6_AUTOCONFIG /** is this netif enabled for IPv6 autoconfiguration */ u8_t ip6_autoconfig_enabled; -@@ -387,6 +430,16 @@ +@@ -387,6 +430,15 @@ u16_t loop_cnt_current; #endif /* LWIP_LOOPBACK_MAX_PBUFS */ #endif /* ENABLE_LOOPBACK */ @@ -19191,13 +3638,12 @@ diff -Nur a/lwip-2.1.2/src/include/lwip/netif.h b/lwip-2.1.2/src/include/lwip/ne +#endif +#if LWIP_IPV6 + /** Call back needs to be registered if adaptor requires notification for IPv6 DAD */ -+ lwip_ipv6_addr_event ipv6_addr_event_cb; + u8_t ipv6_flags; +#endif }; #if LWIP_CHECKSUM_CTRL_PER_NETIF -@@ -407,9 +460,15 @@ +@@ -407,9 +459,15 @@ #endif /* LWIP_SINGLE_NETIF */ /** The default network interface. */ extern struct netif *netif_default; @@ -19214,7 +3660,7 @@ diff -Nur a/lwip-2.1.2/src/include/lwip/netif.h b/lwip-2.1.2/src/include/lwip/ne struct netif *netif_add_noaddr(struct netif *netif, void *state, netif_init_fn init, netif_input_fn input); #if LWIP_IPV4 -@@ -429,12 +488,17 @@ +@@ -429,12 +487,17 @@ structure. */ struct netif *netif_find(const char *name); @@ -19233,7 +3679,7 @@ diff -Nur a/lwip-2.1.2/src/include/lwip/netif.h b/lwip-2.1.2/src/include/lwip/ne /** @ingroup netif_ip4 */ #define netif_ip4_addr(netif) ((const ip4_addr_t*)ip_2_ip4(&((netif)->ip_addr))) /** @ingroup netif_ip4 */ -@@ -455,6 +519,9 @@ +@@ -455,6 +518,9 @@ void netif_set_up(struct netif *netif); void netif_set_down(struct netif *netif); @@ -19243,7 +3689,7 @@ diff -Nur a/lwip-2.1.2/src/include/lwip/netif.h b/lwip-2.1.2/src/include/lwip/ne /** @ingroup netif * Ask if an interface is up */ -@@ -512,6 +579,8 @@ +@@ -512,6 +578,8 @@ /** @ingroup netif_ip6 */ #define netif_ip6_addr(netif, i) ((const ip6_addr_t*)ip_2_ip6(&((netif)->ip6_addr[i]))) void netif_ip6_addr_set(struct netif *netif, s8_t addr_idx, const ip6_addr_t *addr6); @@ -19253,8 +3699,8 @@ diff -Nur a/lwip-2.1.2/src/include/lwip/netif.h b/lwip-2.1.2/src/include/lwip/ne #define netif_ip6_addr_state(netif, i) ((netif)->ip6_addr_state[i]) void netif_ip6_addr_set_state(struct netif* netif, s8_t addr_idx, u8_t state); diff -Nur a/lwip-2.1.2/src/include/lwip/opt.h b/lwip-2.1.2/src/include/lwip/opt.h ---- a/lwip-2.1.2/src/include/lwip/opt.h 2021-05-08 18:13:52.635621024 +0800 -+++ b/lwip-2.1.2/src/include/lwip/opt.h 2021-04-27 18:56:55.440353467 +0800 +--- a/lwip-2.1.2/src/include/lwip/opt.h 2021-06-29 15:16:18.808893323 +0800 ++++ b/lwip-2.1.2/src/include/lwip/opt.h 2021-06-29 15:16:44.636898726 +0800 @@ -529,7 +529,7 @@ * (only needed if you use the sequential API, like api_lib.c) */ @@ -19265,8 +3711,8 @@ diff -Nur a/lwip-2.1.2/src/include/lwip/opt.h b/lwip-2.1.2/src/include/lwip/opt. /** diff -Nur a/lwip-2.1.2/src/include/lwip/pbuf.h b/lwip-2.1.2/src/include/lwip/pbuf.h ---- a/lwip-2.1.2/src/include/lwip/pbuf.h 2021-05-08 18:13:52.635621024 +0800 -+++ b/lwip-2.1.2/src/include/lwip/pbuf.h 2021-04-27 18:56:55.440353467 +0800 +--- a/lwip-2.1.2/src/include/lwip/pbuf.h 2021-06-29 15:16:18.808893323 +0800 ++++ b/lwip-2.1.2/src/include/lwip/pbuf.h 2021-06-29 15:16:44.636898726 +0800 @@ -181,7 +181,10 @@ #define PBUF_FLAG_LLMCAST 0x10U /** indicates this pbuf includes a TCP FIN flag */ @@ -19280,1563 +3726,248 @@ diff -Nur a/lwip-2.1.2/src/include/lwip/pbuf.h b/lwip-2.1.2/src/include/lwip/pbu struct pbuf { /** next pbuf in singly linked pbuf chain */ diff -Nur a/lwip-2.1.2/src/include/lwip/priv/api_msg.h b/lwip-2.1.2/src/include/lwip/priv/api_msg.h ---- a/lwip-2.1.2/src/include/lwip/priv/api_msg.h 2021-05-08 18:13:52.639621024 +0800 -+++ b/lwip-2.1.2/src/include/lwip/priv/api_msg.h 2021-04-27 18:56:55.440353467 +0800 +--- a/lwip-2.1.2/src/include/lwip/priv/api_msg.h 2021-06-29 15:16:18.808893323 +0800 ++++ b/lwip-2.1.2/src/include/lwip/priv/api_msg.h 2021-06-29 15:16:44.636898726 +0800 @@ -46,6 +46,7 @@ #include "lwip/igmp.h" #include "lwip/api.h" - #include "lwip/priv/tcpip_priv.h" -+#include "lwip/ip.h" - - #ifdef __cplusplus - extern "C" { -@@ -70,6 +71,14 @@ - #define NETCONN_SHUT_WR 2 - #define NETCONN_SHUT_RDWR (NETCONN_SHUT_RD | NETCONN_SHUT_WR) - -+#if PF_PACKET_SOCKET -+/* Packet Types */ -+#define PACKET_HOST 0 /* To us */ -+#define PACKET_BROADCAST 1 /* To all */ -+#define PACKET_MULTICAST 2 /* To group */ -+#define PACKET_OTHERHOST 3 /* To someone else */ -+#define PACKET_OUTGOING 4 -+#endif - /* IP addresses and port numbers are expected to be in - * the same byte order as in the corresponding pcb. - */ -@@ -88,7 +97,7 @@ - struct netbuf *b; - /** used for lwip_netconn_do_newconn */ - struct { -- u8_t proto; -+ u16_t proto; - } n; - /** used for lwip_netconn_do_bind and lwip_netconn_do_connect */ - struct { -@@ -102,6 +111,12 @@ - u16_t API_MSG_M_DEF(port); - u8_t local; - } ad; -+#if PF_PACKET_SOCKET -+ struct { -+ struct pf_packet_sockaddr_ll API_MSG_M_DEF(ll); -+ u8_t local; -+ } adpkt; -+#endif - /** used for lwip_netconn_do_write */ - struct { - /** current vector to write */ -@@ -205,6 +220,7 @@ - #endif /* TCP_LISTEN_BACKLOG */ - void lwip_netconn_do_write (void *m); - void lwip_netconn_do_getaddr (void *m); -+void lwip_netconn_do_getaddr_pfpkt (void *m); - void lwip_netconn_do_close (void *m); - void lwip_netconn_do_shutdown (void *m); - #if LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD) -@@ -214,6 +230,7 @@ - - #if LWIP_DNS - void lwip_netconn_do_gethostbyname(void *arg); -+void lwip_netconn_do_getnamebyhost(void *arg); - #endif /* LWIP_DNS */ - - struct netconn* netconn_alloc(enum netconn_type t, netconn_callback callback); -@@ -233,6 +250,7 @@ - - typedef void (*netifapi_void_fn)(struct netif *netif); - typedef err_t (*netifapi_errt_fn)(struct netif *netif); -+typedef err_t (*netifapi_arg_fn)(struct netif *netif, void *arg); - - struct netifapi_msg { - struct tcpip_api_call_data call; -@@ -245,9 +263,27 @@ - NETIFAPI_IPADDR_DEF(ip4_addr_t, gw); - #endif /* LWIP_IPV4 */ - void *state; -+ } add; -+ -+ struct { -+ const ip_addr_t *ipaddr; -+ } find_by_ipaddr; -+ struct { -+ const char *name; -+ } find_by_name; -+ struct { -+ unsigned char ifindex; -+ } find_by_ifindex; -+ struct { -+#if LWIP_IPV4 -+ ip4_addr_t *ipaddr; -+ ip4_addr_t *netmask; -+ ip4_addr_t *gw; -+#endif /* LWIP_IPV4 */ -+ void *state; - netif_init_fn init; - netif_input_fn input; -- } add; -+ } add_get; - struct { - netifapi_void_fn voidfunc; - netifapi_errt_fn errtfunc; -diff -Nur a/lwip-2.1.2/src/include/lwip/priv/sockets_priv.h b/lwip-2.1.2/src/include/lwip/priv/sockets_priv.h ---- a/lwip-2.1.2/src/include/lwip/priv/sockets_priv.h 2021-05-08 18:13:52.639621024 +0800 -+++ b/lwip-2.1.2/src/include/lwip/priv/sockets_priv.h 2021-04-27 18:56:55.440353467 +0800 -@@ -49,7 +49,6 @@ - extern "C" { - #endif - --#define NUM_SOCKETS MEMP_NUM_NETCONN - - /** This is overridable for the rare case where more than 255 threads - * select on the same socket... -@@ -69,6 +68,10 @@ - struct netconn *conn; - /** data that was left from the previous read */ - union lwip_sock_lastdata lastdata; -+ /** offset in the data that was left from the previous read */ -+ u16_t lastoffset; -+ /* socket level mutex used for multithread recv support */ -+ sys_mutex_t mutex; - #if LWIP_SOCKET_SELECT || LWIP_SOCKET_POLL - /** number of times data was received, set by event_callback(), - tested by the receive and select functions */ -@@ -158,6 +161,7 @@ - fd_set *exceptset; - #endif /* LWIP_SOCKET_SELECT */ - #if LWIP_SOCKET_POLL -+ - /** fds passed to poll; NULL if select */ - struct pollfd *poll_fds; - /** nfds passed to poll; 0 if select */ -diff -Nur a/lwip-2.1.2/src/include/lwip/prot/icmp6.h b/lwip-2.1.2/src/include/lwip/prot/icmp6.h ---- a/lwip-2.1.2/src/include/lwip/prot/icmp6.h 2021-05-08 18:13:52.639621024 +0800 -+++ b/lwip-2.1.2/src/include/lwip/prot/icmp6.h 2021-04-27 18:56:55.440353467 +0800 -@@ -1,170 +1,170 @@ --/** -- * @file -- * ICMP6 protocol definitions -- */ -- --/* -- * 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 -- * -- */ --#ifndef LWIP_HDR_PROT_ICMP6_H --#define LWIP_HDR_PROT_ICMP6_H -- --#include "lwip/arch.h" -- --#ifdef __cplusplus --extern "C" { --#endif -- --/** ICMP type */ --enum icmp6_type { -- /** Destination unreachable */ -- ICMP6_TYPE_DUR = 1, -- /** Packet too big */ -- ICMP6_TYPE_PTB = 2, -- /** Time exceeded */ -- ICMP6_TYPE_TE = 3, -- /** Parameter problem */ -- ICMP6_TYPE_PP = 4, -- /** Private experimentation */ -- ICMP6_TYPE_PE1 = 100, -- /** Private experimentation */ -- ICMP6_TYPE_PE2 = 101, -- /** Reserved for expansion of error messages */ -- ICMP6_TYPE_RSV_ERR = 127, -- -- /** Echo request */ -- ICMP6_TYPE_EREQ = 128, -- /** Echo reply */ -- ICMP6_TYPE_EREP = 129, -- /** Multicast listener query */ -- ICMP6_TYPE_MLQ = 130, -- /** Multicast listener report */ -- ICMP6_TYPE_MLR = 131, -- /** Multicast listener done */ -- ICMP6_TYPE_MLD = 132, -- /** Router solicitation */ -- ICMP6_TYPE_RS = 133, -- /** Router advertisement */ -- ICMP6_TYPE_RA = 134, -- /** Neighbor solicitation */ -- ICMP6_TYPE_NS = 135, -- /** Neighbor advertisement */ -- ICMP6_TYPE_NA = 136, -- /** Redirect */ -- ICMP6_TYPE_RD = 137, -- /** Multicast router advertisement */ -- ICMP6_TYPE_MRA = 151, -- /** Multicast router solicitation */ -- ICMP6_TYPE_MRS = 152, -- /** Multicast router termination */ -- ICMP6_TYPE_MRT = 153, -- /** Private experimentation */ -- ICMP6_TYPE_PE3 = 200, -- /** Private experimentation */ -- ICMP6_TYPE_PE4 = 201, -- /** Reserved for expansion of informational messages */ -- ICMP6_TYPE_RSV_INF = 255 --}; -- --/** ICMP destination unreachable codes */ --enum icmp6_dur_code { -- /** No route to destination */ -- ICMP6_DUR_NO_ROUTE = 0, -- /** Communication with destination administratively prohibited */ -- ICMP6_DUR_PROHIBITED = 1, -- /** Beyond scope of source address */ -- ICMP6_DUR_SCOPE = 2, -- /** Address unreachable */ -- ICMP6_DUR_ADDRESS = 3, -- /** Port unreachable */ -- ICMP6_DUR_PORT = 4, -- /** Source address failed ingress/egress policy */ -- ICMP6_DUR_POLICY = 5, -- /** Reject route to destination */ -- ICMP6_DUR_REJECT_ROUTE = 6 --}; -- --/** ICMP time exceeded codes */ --enum icmp6_te_code { -- /** Hop limit exceeded in transit */ -- ICMP6_TE_HL = 0, -- /** Fragment reassembly time exceeded */ -- ICMP6_TE_FRAG = 1 --}; -- --/** ICMP parameter code */ --enum icmp6_pp_code { -- /** Erroneous header field encountered */ -- ICMP6_PP_FIELD = 0, -- /** Unrecognized next header type encountered */ -- ICMP6_PP_HEADER = 1, -- /** Unrecognized IPv6 option encountered */ -- ICMP6_PP_OPTION = 2 --}; -- --/** This is the standard ICMP6 header. */ --#ifdef PACK_STRUCT_USE_INCLUDES --# include "arch/bpstruct.h" --#endif --PACK_STRUCT_BEGIN --struct icmp6_hdr { -- PACK_STRUCT_FLD_8(u8_t type); -- PACK_STRUCT_FLD_8(u8_t code); -- PACK_STRUCT_FIELD(u16_t chksum); -- PACK_STRUCT_FIELD(u32_t data); --} PACK_STRUCT_STRUCT; --PACK_STRUCT_END --#ifdef PACK_STRUCT_USE_INCLUDES --# include "arch/epstruct.h" --#endif -- --/** This is the ICMP6 header adapted for echo req/resp. */ --#ifdef PACK_STRUCT_USE_INCLUDES --# include "arch/bpstruct.h" --#endif --PACK_STRUCT_BEGIN --struct icmp6_echo_hdr { -- PACK_STRUCT_FLD_8(u8_t type); -- PACK_STRUCT_FLD_8(u8_t code); -- PACK_STRUCT_FIELD(u16_t chksum); -- PACK_STRUCT_FIELD(u16_t id); -- PACK_STRUCT_FIELD(u16_t seqno); --} PACK_STRUCT_STRUCT; --PACK_STRUCT_END --#ifdef PACK_STRUCT_USE_INCLUDES --# include "arch/epstruct.h" --#endif -- --#ifdef __cplusplus --} --#endif -- --#endif /* LWIP_HDR_PROT_ICMP6_H */ -+/** -+ * @file -+ * ICMP6 protocol definitions -+ */ -+ -+/* -+ * 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 -+ * -+ */ -+#ifndef LWIP_HDR_PROT_ICMP6_H -+#define LWIP_HDR_PROT_ICMP6_H -+ -+#include "lwip/arch.h" -+ -+#ifdef __cplusplus -+extern "C" { -+#endif -+ -+/** ICMP type */ -+enum icmp6_type { -+ /** Destination unreachable */ -+ ICMP6_TYPE_DUR = 1, -+ /** Packet too big */ -+ ICMP6_TYPE_PTB = 2, -+ /** Time exceeded */ -+ ICMP6_TYPE_TE = 3, -+ /** Parameter problem */ -+ ICMP6_TYPE_PP = 4, -+ /** Private experimentation */ -+ ICMP6_TYPE_PE1 = 100, -+ /** Private experimentation */ -+ ICMP6_TYPE_PE2 = 101, -+ /** Reserved for expansion of error messages */ -+ ICMP6_TYPE_RSV_ERR = 127, -+ -+ /** Echo request */ -+ ICMP6_TYPE_EREQ = 128, -+ /** Echo reply */ -+ ICMP6_TYPE_EREP = 129, -+ /** Multicast listener query */ -+ ICMP6_TYPE_MLQ = 130, -+ /** Multicast listener report */ -+ ICMP6_TYPE_MLR = 131, -+ /** Multicast listener done */ -+ ICMP6_TYPE_MLD = 132, -+ /** Router solicitation */ -+ ICMP6_TYPE_RS = 133, -+ /** Router advertisement */ -+ ICMP6_TYPE_RA = 134, -+ /** Neighbor solicitation */ -+ ICMP6_TYPE_NS = 135, -+ /** Neighbor advertisement */ -+ ICMP6_TYPE_NA = 136, -+ /** Redirect */ -+ ICMP6_TYPE_RD = 137, -+ /** Multicast router advertisement */ -+ ICMP6_TYPE_MRA = 151, -+ /** Multicast router solicitation */ -+ ICMP6_TYPE_MRS = 152, -+ /** Multicast router termination */ -+ ICMP6_TYPE_MRT = 153, -+ /** Private experimentation */ -+ ICMP6_TYPE_PE3 = 200, -+ /** Private experimentation */ -+ ICMP6_TYPE_PE4 = 201, -+ /** Reserved for expansion of informational messages */ -+ ICMP6_TYPE_RSV_INF = 255 -+}; -+ -+/** ICMP destination unreachable codes */ -+enum icmp6_dur_code { -+ /** No route to destination */ -+ ICMP6_DUR_NO_ROUTE = 0, -+ /** Communication with destination administratively prohibited */ -+ ICMP6_DUR_PROHIBITED = 1, -+ /** Beyond scope of source address */ -+ ICMP6_DUR_SCOPE = 2, -+ /** Address unreachable */ -+ ICMP6_DUR_ADDRESS = 3, -+ /** Port unreachable */ -+ ICMP6_DUR_PORT = 4, -+ /** Source address failed ingress/egress policy */ -+ ICMP6_DUR_POLICY = 5, -+ /** Reject route to destination */ -+ ICMP6_DUR_REJECT_ROUTE = 6 -+}; -+ -+/** ICMP time exceeded codes */ -+enum icmp6_te_code { -+ /** Hop limit exceeded in transit */ -+ ICMP6_TE_HL = 0, -+ /** Fragment reassembly time exceeded */ -+ ICMP6_TE_FRAG = 1 -+}; -+ -+/** ICMP parameter code */ -+enum icmp6_pp_code { -+ /** Erroneous header field encountered */ -+ ICMP6_PP_FIELD = 0, -+ /** Unrecognized next header type encountered */ -+ ICMP6_PP_HEADER = 1, -+ /** Unrecognized IPv6 option encountered */ -+ ICMP6_PP_OPTION = 2 -+}; -+ -+/** This is the standard ICMP6 header. */ -+#ifdef PACK_STRUCT_USE_INCLUDES -+# include "arch/bpstruct.h" -+#endif -+PACK_STRUCT_BEGIN -+struct icmpv6_hdr { -+ PACK_STRUCT_FLD_8(u8_t type); -+ PACK_STRUCT_FLD_8(u8_t code); -+ PACK_STRUCT_FIELD(u16_t chksum); -+ PACK_STRUCT_FIELD(u32_t data); -+} PACK_STRUCT_STRUCT; -+PACK_STRUCT_END -+#ifdef PACK_STRUCT_USE_INCLUDES -+# include "arch/epstruct.h" -+#endif -+ -+/** This is the ICMP6 header adapted for echo req/resp. */ -+#ifdef PACK_STRUCT_USE_INCLUDES -+# include "arch/bpstruct.h" -+#endif -+PACK_STRUCT_BEGIN -+struct icmp6_echo_hdr { -+ PACK_STRUCT_FLD_8(u8_t type); -+ PACK_STRUCT_FLD_8(u8_t code); -+ PACK_STRUCT_FIELD(u16_t chksum); -+ PACK_STRUCT_FIELD(u16_t id); -+ PACK_STRUCT_FIELD(u16_t seqno); -+} PACK_STRUCT_STRUCT; -+PACK_STRUCT_END -+#ifdef PACK_STRUCT_USE_INCLUDES -+# include "arch/epstruct.h" -+#endif -+ -+#ifdef __cplusplus -+} -+#endif -+ -+#endif /* LWIP_HDR_PROT_ICMP6_H */ -diff -Nur a/lwip-2.1.2/src/include/lwip/prot/ip4.h b/lwip-2.1.2/src/include/lwip/prot/ip4.h ---- a/lwip-2.1.2/src/include/lwip/prot/ip4.h 2021-05-08 18:13:52.639621024 +0800 -+++ b/lwip-2.1.2/src/include/lwip/prot/ip4.h 2021-04-27 18:56:55.440353467 +0800 -@@ -1,131 +1,136 @@ --/** -- * @file -- * IPv4 protocol definitions -- */ -- --/* -- * 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 -- * -- */ --#ifndef LWIP_HDR_PROT_IP4_H --#define LWIP_HDR_PROT_IP4_H -- --#include "lwip/arch.h" --#include "lwip/ip4_addr.h" -- --#ifdef __cplusplus --extern "C" { --#endif -- --/** This is the packed version of ip4_addr_t, -- used in network headers that are itself packed */ --#ifdef PACK_STRUCT_USE_INCLUDES --# include "arch/bpstruct.h" --#endif --PACK_STRUCT_BEGIN --struct ip4_addr_packed { -- PACK_STRUCT_FIELD(u32_t addr); --} PACK_STRUCT_STRUCT; --PACK_STRUCT_END --#ifdef PACK_STRUCT_USE_INCLUDES --# include "arch/epstruct.h" --#endif -- --typedef struct ip4_addr_packed ip4_addr_p_t; -- --/* Size of the IPv4 header. Same as 'sizeof(struct ip_hdr)'. */ --#define IP_HLEN 20 --/* Maximum size of the IPv4 header with options. */ --#define IP_HLEN_MAX 60 -- --#ifdef PACK_STRUCT_USE_INCLUDES --# include "arch/bpstruct.h" --#endif --PACK_STRUCT_BEGIN --/* The IPv4 header */ --struct ip_hdr { -- /* version / header length */ -- PACK_STRUCT_FLD_8(u8_t _v_hl); -- /* type of service */ -- PACK_STRUCT_FLD_8(u8_t _tos); -- /* total length */ -- PACK_STRUCT_FIELD(u16_t _len); -- /* identification */ -- PACK_STRUCT_FIELD(u16_t _id); -- /* fragment offset field */ -- PACK_STRUCT_FIELD(u16_t _offset); --#define IP_RF 0x8000U /* reserved fragment flag */ --#define IP_DF 0x4000U /* don't fragment flag */ --#define IP_MF 0x2000U /* more fragments flag */ --#define IP_OFFMASK 0x1fffU /* mask for fragmenting bits */ -- /* time to live */ -- PACK_STRUCT_FLD_8(u8_t _ttl); -- /* protocol*/ -- PACK_STRUCT_FLD_8(u8_t _proto); -- /* checksum */ -- PACK_STRUCT_FIELD(u16_t _chksum); -- /* source and destination IP addresses */ -- PACK_STRUCT_FLD_S(ip4_addr_p_t src); -- PACK_STRUCT_FLD_S(ip4_addr_p_t dest); --} PACK_STRUCT_STRUCT; --PACK_STRUCT_END --#ifdef PACK_STRUCT_USE_INCLUDES --# include "arch/epstruct.h" --#endif -- --/* Macros to get struct ip_hdr fields: */ --#define IPH_V(hdr) ((hdr)->_v_hl >> 4) --#define IPH_HL(hdr) ((hdr)->_v_hl & 0x0f) --#define IPH_HL_BYTES(hdr) ((u8_t)(IPH_HL(hdr) * 4)) --#define IPH_TOS(hdr) ((hdr)->_tos) --#define IPH_LEN(hdr) ((hdr)->_len) --#define IPH_ID(hdr) ((hdr)->_id) --#define IPH_OFFSET(hdr) ((hdr)->_offset) --#define IPH_OFFSET_BYTES(hdr) ((u16_t)((lwip_ntohs(IPH_OFFSET(hdr)) & IP_OFFMASK) * 8U)) --#define IPH_TTL(hdr) ((hdr)->_ttl) --#define IPH_PROTO(hdr) ((hdr)->_proto) --#define IPH_CHKSUM(hdr) ((hdr)->_chksum) -- --/* Macros to set struct ip_hdr fields: */ --#define IPH_VHL_SET(hdr, v, hl) (hdr)->_v_hl = (u8_t)((((v) << 4) | (hl))) --#define IPH_TOS_SET(hdr, tos) (hdr)->_tos = (tos) --#define IPH_LEN_SET(hdr, len) (hdr)->_len = (len) --#define IPH_ID_SET(hdr, id) (hdr)->_id = (id) --#define IPH_OFFSET_SET(hdr, off) (hdr)->_offset = (off) --#define IPH_TTL_SET(hdr, ttl) (hdr)->_ttl = (u8_t)(ttl) --#define IPH_PROTO_SET(hdr, proto) (hdr)->_proto = (u8_t)(proto) --#define IPH_CHKSUM_SET(hdr, chksum) (hdr)->_chksum = (chksum) -- -- --#ifdef __cplusplus --} --#endif -- --#endif /* LWIP_HDR_PROT_IP4_H */ -+/** -+ * @file -+ * IPv4 protocol definitions -+ */ -+ -+/* -+ * 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 -+ * -+ */ -+#ifndef LWIP_HDR_PROT_IP4_H -+#define LWIP_HDR_PROT_IP4_H -+ -+#include "lwip/arch.h" -+#include "lwip/ip4_addr.h" -+#if LWIP_LITEOS_COMPAT -+#include -+#endif -+ -+#ifdef __cplusplus -+extern "C" { -+#endif -+ -+/** This is the packed version of ip4_addr_t, -+ used in network headers that are itself packed */ -+#ifdef PACK_STRUCT_USE_INCLUDES -+# include "arch/bpstruct.h" -+#endif -+PACK_STRUCT_BEGIN -+struct ip4_addr_packed { -+ PACK_STRUCT_FIELD(u32_t addr); -+} PACK_STRUCT_STRUCT; -+PACK_STRUCT_END -+#ifdef PACK_STRUCT_USE_INCLUDES -+# include "arch/epstruct.h" -+#endif -+ -+typedef struct ip4_addr_packed ip4_addr_p_t; -+ -+/* Size of the IPv4 header. Same as 'sizeof(struct ip_hdr)'. */ -+#define IP_HLEN 20 -+/* Maximum size of the IPv4 header with options. */ -+#define IP_HLEN_MAX 60 -+ -+#ifdef PACK_STRUCT_USE_INCLUDES -+# include "arch/bpstruct.h" -+#endif -+PACK_STRUCT_BEGIN -+/* The IPv4 header */ -+struct ip_hdr { -+ /* version / header length */ -+ PACK_STRUCT_FLD_8(u8_t _v_hl); -+ /* type of service */ -+ PACK_STRUCT_FLD_8(u8_t _tos); -+ /* total length */ -+ PACK_STRUCT_FIELD(u16_t _len); -+ /* identification */ -+ PACK_STRUCT_FIELD(u16_t _id); -+ /* fragment offset field */ -+ PACK_STRUCT_FIELD(u16_t _offset); -+#if !LWIP_LITEOS_COMPAT -+#define IP_RF 0x8000U /* reserved fragment flag */ -+#define IP_DF 0x4000U /* don't fragment flag */ -+#define IP_MF 0x2000U /* more fragments flag */ -+#define IP_OFFMASK 0x1fffU /* mask for fragmenting bits */ -+#endif -+ /* time to live */ -+ PACK_STRUCT_FLD_8(u8_t _ttl); -+ /* protocol*/ -+ PACK_STRUCT_FLD_8(u8_t _proto); -+ /* checksum */ -+ PACK_STRUCT_FIELD(u16_t _chksum); -+ /* source and destination IP addresses */ -+ PACK_STRUCT_FLD_S(ip4_addr_p_t src); -+ PACK_STRUCT_FLD_S(ip4_addr_p_t dest); -+} PACK_STRUCT_STRUCT; -+PACK_STRUCT_END -+#ifdef PACK_STRUCT_USE_INCLUDES -+# include "arch/epstruct.h" -+#endif -+ -+/* Macros to get struct ip_hdr fields: */ -+#define IPH_V(hdr) ((hdr)->_v_hl >> 4) -+#define IPH_HL(hdr) ((hdr)->_v_hl & 0x0f) -+#define IPH_HL_BYTES(hdr) ((u8_t)(IPH_HL(hdr) * 4)) -+#define IPH_TOS(hdr) ((hdr)->_tos) -+#define IPH_LEN(hdr) ((hdr)->_len) -+#define IPH_ID(hdr) ((hdr)->_id) -+#define IPH_OFFSET(hdr) ((hdr)->_offset) -+#define IPH_OFFSET_BYTES(hdr) ((u16_t)((lwip_ntohs(IPH_OFFSET(hdr)) & IP_OFFMASK) * 8U)) -+#define IPH_TTL(hdr) ((hdr)->_ttl) -+#define IPH_PROTO(hdr) ((hdr)->_proto) -+#define IPH_CHKSUM(hdr) ((hdr)->_chksum) -+ -+/* Macros to set struct ip_hdr fields: */ -+#define IPH_VHL_SET(hdr, v, hl) (hdr)->_v_hl = (u8_t)((((v) << 4) | (hl))) -+#define IPH_TOS_SET(hdr, tos) (hdr)->_tos = (tos) -+#define IPH_LEN_SET(hdr, len) (hdr)->_len = (len) -+#define IPH_ID_SET(hdr, id) (hdr)->_id = (id) -+#define IPH_OFFSET_SET(hdr, off) (hdr)->_offset = (off) -+#define IPH_TTL_SET(hdr, ttl) (hdr)->_ttl = (u8_t)(ttl) -+#define IPH_PROTO_SET(hdr, proto) (hdr)->_proto = (u8_t)(proto) -+#define IPH_CHKSUM_SET(hdr, chksum) (hdr)->_chksum = (chksum) -+ -+ -+#ifdef __cplusplus -+} -+#endif -+ -+#endif /* LWIP_HDR_PROT_IP4_H */ -diff -Nur a/lwip-2.1.2/src/include/lwip/raw.h b/lwip-2.1.2/src/include/lwip/raw.h ---- a/lwip-2.1.2/src/include/lwip/raw.h 2021-05-08 18:13:52.635621024 +0800 -+++ b/lwip-2.1.2/src/include/lwip/raw.h 2021-04-27 18:56:55.440353467 +0800 -@@ -47,6 +47,8 @@ - #include "lwip/ip.h" - #include "lwip/ip_addr.h" - #include "lwip/ip6_addr.h" -+#include "lwip/etharp.h" -+#include "lwip/icmp6.h" - - #ifdef __cplusplus - extern "C" { -@@ -57,6 +59,18 @@ - #define RAW_FLAGS_MULTICAST_LOOP 0x04U - - struct raw_pcb; -+extern struct raw_pcb* raw_pcbs; -+ -+#if PF_PACKET_SOCKET -+extern const struct eth_hdr *g_lwip_current_eth_hdr; -+extern const struct netif *g_lwip_current_netif; -+/* Dest MAC add of current ethernet header of RAW packets -+ * received for PF_PACKET family */ -+#define eth_current_hdr() (g_lwip_current_eth_hdr) -+#define eth_current_netif() (g_lwip_current_netif) -+struct raw_pcb* get_packet_raw_pcbs(void); -+struct raw_pcb* get_all_packet_raw_pcbs(void); -+#endif /* PF_PACKET_SOCKET */ + #include "lwip/priv/tcpip_priv.h" ++#include "lwip/ip.h" - /** Function prototype for raw pcb receive callback functions. - * @param arg user supplied argument (raw_pcb.recv_arg) -@@ -77,8 +91,19 @@ - IP_PCB; + #ifdef __cplusplus + extern "C" { +@@ -70,6 +71,14 @@ + #define NETCONN_SHUT_WR 2 + #define NETCONN_SHUT_RDWR (NETCONN_SHUT_RD | NETCONN_SHUT_WR) - struct raw_pcb *next; -- +#if PF_PACKET_SOCKET -+ struct raw_pcb *all_next; -+ u8_t netifindex; -+ -+ union { -+ u16_t eth_proto; /* Ethernet HeaderType/Protocol for Packet sockets */ -+#define raw_proto proto.protocol -+ u8_t protocol; /* IP protocol for AF_INET sockets */ -+ } proto; -+#else -+#define raw_proto protocol - u8_t protocol; ++/* Packet Types */ ++#define PACKET_HOST 0 /* To us */ ++#define PACKET_BROADCAST 1 /* To all */ ++#define PACKET_MULTICAST 2 /* To group */ ++#define PACKET_OTHERHOST 3 /* To someone else */ ++#define PACKET_OUTGOING 4 +#endif - u8_t flags; + /* IP addresses and port numbers are expected to be in + * the same byte order as in the corresponding pcb. + */ +@@ -88,7 +97,7 @@ + struct netbuf *b; + /** used for lwip_netconn_do_newconn */ + struct { +- u8_t proto; ++ u16_t proto; + } n; + /** used for lwip_netconn_do_bind and lwip_netconn_do_connect */ + struct { +@@ -102,6 +111,12 @@ + u16_t API_MSG_M_DEF(port); + u8_t local; + } ad; ++#if PF_PACKET_SOCKET ++ struct { ++ struct pf_packet_sockaddr_ll API_MSG_M_DEF(ll); ++ u8_t local; ++ } adpkt; ++#endif + /** used for lwip_netconn_do_write */ + struct { + /** current vector to write */ +@@ -205,6 +220,7 @@ + #endif /* TCP_LISTEN_BACKLOG */ + void lwip_netconn_do_write (void *m); + void lwip_netconn_do_getaddr (void *m); ++void lwip_netconn_do_getaddr_pfpkt (void *m); + void lwip_netconn_do_close (void *m); + void lwip_netconn_do_shutdown (void *m); + #if LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD) +@@ -214,6 +230,7 @@ - #if LWIP_MULTICAST_TX_OPTIONS -@@ -115,6 +140,14 @@ + #if LWIP_DNS + void lwip_netconn_do_gethostbyname(void *arg); ++void lwip_netconn_do_getnamebyhost(void *arg); + #endif /* LWIP_DNS */ - void raw_recv (struct raw_pcb *pcb, raw_recv_fn recv, void *recv_arg); + struct netconn* netconn_alloc(enum netconn_type t, netconn_callback callback); +@@ -233,6 +250,7 @@ -+#if PF_PACKET_SOCKET -+struct raw_pcb * raw_packet_new (u16_t proto); -+void raw_packet_remove (struct raw_pcb *pcb); -+void raw_packet_input (struct pbuf *p, const struct netif *inp, const struct raw_pcb *from); -+err_t raw_packet_sendto (const struct raw_pcb *pcb, struct pbuf *p, u8_t ifindex); -+err_t raw_packet_bind (struct raw_pcb *pcb, u8_t ifindex, u16_t proto); -+#endif /* PF_PACKET_SOCKET */ -+ - #define raw_flags(pcb) ((pcb)->flags) - #define raw_setflags(pcb,f) ((pcb)->flags = (f)) + typedef void (*netifapi_void_fn)(struct netif *netif); + typedef err_t (*netifapi_errt_fn)(struct netif *netif); ++typedef err_t (*netifapi_arg_fn)(struct netif *netif, void *arg); -diff -Nur a/lwip-2.1.2/src/include/lwip/sockets.h b/lwip-2.1.2/src/include/lwip/sockets.h ---- a/lwip-2.1.2/src/include/lwip/sockets.h 2021-05-08 18:13:52.635621024 +0800 -+++ b/lwip-2.1.2/src/include/lwip/sockets.h 2021-04-27 18:56:55.440353467 +0800 -@@ -1,688 +1,742 @@ --/** -- * @file -- * Socket API (to be used from non-TCPIP threads) -- */ -- --/* -- * 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 -- * -- */ -- -- --#ifndef LWIP_HDR_SOCKETS_H --#define LWIP_HDR_SOCKETS_H -- --#include "lwip/opt.h" -- --#if LWIP_SOCKET /* don't build if not configured for use in lwipopts.h */ -- --#include "lwip/ip_addr.h" --#include "lwip/netif.h" --#include "lwip/err.h" --#include "lwip/inet.h" --#include "lwip/errno.h" -- --#include -- --#ifdef __cplusplus --extern "C" { --#endif -- --/* If your port already typedef's sa_family_t, define SA_FAMILY_T_DEFINED -- to prevent this code from redefining it. */ --#if !defined(sa_family_t) && !defined(SA_FAMILY_T_DEFINED) --typedef u8_t sa_family_t; --#endif --/* If your port already typedef's in_port_t, define IN_PORT_T_DEFINED -- to prevent this code from redefining it. */ --#if !defined(in_port_t) && !defined(IN_PORT_T_DEFINED) --typedef u16_t in_port_t; --#endif -- --#if LWIP_IPV4 --/* members are in network byte order */ --struct sockaddr_in { -- u8_t sin_len; -- sa_family_t sin_family; -- in_port_t sin_port; -- struct in_addr sin_addr; --#define SIN_ZERO_LEN 8 -- char sin_zero[SIN_ZERO_LEN]; --}; --#endif /* LWIP_IPV4 */ -- --#if LWIP_IPV6 --struct sockaddr_in6 { -- u8_t sin6_len; /* length of this structure */ -- sa_family_t sin6_family; /* AF_INET6 */ -- in_port_t sin6_port; /* Transport layer port # */ -- u32_t sin6_flowinfo; /* IPv6 flow information */ -- struct in6_addr sin6_addr; /* IPv6 address */ -- u32_t sin6_scope_id; /* Set of interfaces for scope */ --}; --#endif /* LWIP_IPV6 */ -- --struct sockaddr { -- u8_t sa_len; -- sa_family_t sa_family; -- char sa_data[14]; --}; -- --struct sockaddr_storage { -- u8_t s2_len; -- sa_family_t ss_family; -- char s2_data1[2]; -- u32_t s2_data2[3]; --#if LWIP_IPV6 -- u32_t s2_data3[3]; --#endif /* LWIP_IPV6 */ --}; -- --/* If your port already typedef's socklen_t, define SOCKLEN_T_DEFINED -- to prevent this code from redefining it. */ --#if !defined(socklen_t) && !defined(SOCKLEN_T_DEFINED) --typedef u32_t socklen_t; --#endif -- --#if !defined IOV_MAX --#define IOV_MAX 0xFFFF --#elif IOV_MAX > 0xFFFF --#error "IOV_MAX larger than supported by LwIP" --#endif /* IOV_MAX */ -- --#if !defined(iovec) --struct iovec { -- void *iov_base; -- size_t iov_len; --}; --#endif -- --struct msghdr { -- void *msg_name; -- socklen_t msg_namelen; -- struct iovec *msg_iov; -- int msg_iovlen; -- void *msg_control; -- socklen_t msg_controllen; -- int msg_flags; --}; -- --/* struct msghdr->msg_flags bit field values */ --#define MSG_TRUNC 0x04 --#define MSG_CTRUNC 0x08 -- --/* RFC 3542, Section 20: Ancillary Data */ --struct cmsghdr { -- socklen_t cmsg_len; /* number of bytes, including header */ -- int cmsg_level; /* originating protocol */ -- int cmsg_type; /* protocol-specific type */ --}; --/* Data section follows header and possible padding, typically referred to as -- unsigned char cmsg_data[]; */ -- --/* cmsg header/data alignment. NOTE: we align to native word size (double word --size on 16-bit arch) so structures are not placed at an unaligned address. --16-bit arch needs double word to ensure 32-bit alignment because socklen_t --could be 32 bits. If we ever have cmsg data with a 64-bit variable, alignment --will need to increase long long */ --#define ALIGN_H(size) (((size) + sizeof(long) - 1U) & ~(sizeof(long)-1U)) --#define ALIGN_D(size) ALIGN_H(size) -- --#define CMSG_FIRSTHDR(mhdr) \ -- ((mhdr)->msg_controllen >= sizeof(struct cmsghdr) ? \ -- (struct cmsghdr *)(mhdr)->msg_control : \ -- (struct cmsghdr *)NULL) -- --#define CMSG_NXTHDR(mhdr, cmsg) \ -- (((cmsg) == NULL) ? CMSG_FIRSTHDR(mhdr) : \ -- (((u8_t *)(cmsg) + ALIGN_H((cmsg)->cmsg_len) \ -- + ALIGN_D(sizeof(struct cmsghdr)) > \ -- (u8_t *)((mhdr)->msg_control) + (mhdr)->msg_controllen) ? \ -- (struct cmsghdr *)NULL : \ -- (struct cmsghdr *)((void*)((u8_t *)(cmsg) + \ -- ALIGN_H((cmsg)->cmsg_len))))) -- --#define CMSG_DATA(cmsg) ((void*)((u8_t *)(cmsg) + \ -- ALIGN_D(sizeof(struct cmsghdr)))) -- --#define CMSG_SPACE(length) (ALIGN_D(sizeof(struct cmsghdr)) + \ -- ALIGN_H(length)) -- --#define CMSG_LEN(length) (ALIGN_D(sizeof(struct cmsghdr)) + \ -- length) -- --/* Set socket options argument */ --#define IFNAMSIZ NETIF_NAMESIZE --struct ifreq { -- char ifr_name[IFNAMSIZ]; /* Interface name */ --}; -- --/* Socket protocol types (TCP/UDP/RAW) */ --#define SOCK_STREAM 1 --#define SOCK_DGRAM 2 --#define SOCK_RAW 3 -- --/* -- * Option flags per-socket. These must match the SOF_ flags in ip.h (checked in init.c) -- */ --#define SO_REUSEADDR 0x0004 /* Allow local address reuse */ --#define SO_KEEPALIVE 0x0008 /* keep connections alive */ --#define SO_BROADCAST 0x0020 /* permit to send and to receive broadcast messages (see IP_SOF_BROADCAST option) */ -- -- --/* -- * Additional options, not kept in so_options. -- */ --#define SO_DEBUG 0x0001 /* Unimplemented: turn on debugging info recording */ --#define SO_ACCEPTCONN 0x0002 /* socket has had listen() */ --#define SO_DONTROUTE 0x0010 /* Unimplemented: just use interface addresses */ --#define SO_USELOOPBACK 0x0040 /* Unimplemented: bypass hardware when possible */ --#define SO_LINGER 0x0080 /* linger on close if data present */ --#define SO_DONTLINGER ((int)(~SO_LINGER)) --#define SO_OOBINLINE 0x0100 /* Unimplemented: leave received OOB data in line */ --#define SO_REUSEPORT 0x0200 /* Unimplemented: allow local address & port reuse */ --#define SO_SNDBUF 0x1001 /* Unimplemented: send buffer size */ --#define SO_RCVBUF 0x1002 /* receive buffer size */ --#define SO_SNDLOWAT 0x1003 /* Unimplemented: send low-water mark */ --#define SO_RCVLOWAT 0x1004 /* Unimplemented: receive low-water mark */ --#define SO_SNDTIMEO 0x1005 /* send timeout */ --#define SO_RCVTIMEO 0x1006 /* receive timeout */ --#define SO_ERROR 0x1007 /* get error status and clear */ --#define SO_TYPE 0x1008 /* get socket type */ --#define SO_CONTIMEO 0x1009 /* Unimplemented: connect timeout */ --#define SO_NO_CHECK 0x100a /* don't create UDP checksum */ --#define SO_BINDTODEVICE 0x100b /* bind to device */ -- --/* -- * Structure used for manipulating linger option. -- */ --struct linger { -- int l_onoff; /* option on/off */ -- int l_linger; /* linger time in seconds */ --}; -- --/* -- * Level number for (get/set)sockopt() to apply to socket itself. -- */ --#define SOL_SOCKET 0xfff /* options for socket level */ -- -- --#define AF_UNSPEC 0 --#define AF_INET 2 --#if LWIP_IPV6 --#define AF_INET6 10 --#else /* LWIP_IPV6 */ --#define AF_INET6 AF_UNSPEC --#endif /* LWIP_IPV6 */ --#define PF_INET AF_INET --#define PF_INET6 AF_INET6 --#define PF_UNSPEC AF_UNSPEC -- --#define IPPROTO_IP 0 --#define IPPROTO_ICMP 1 --#define IPPROTO_TCP 6 --#define IPPROTO_UDP 17 --#if LWIP_IPV6 --#define IPPROTO_IPV6 41 --#define IPPROTO_ICMPV6 58 --#endif /* LWIP_IPV6 */ --#define IPPROTO_UDPLITE 136 --#define IPPROTO_RAW 255 -- --/* Flags we can use with send and recv. */ --#define MSG_PEEK 0x01 /* Peeks at an incoming message */ --#define MSG_WAITALL 0x02 /* Unimplemented: Requests that the function block until the full amount of data requested can be returned */ --#define MSG_OOB 0x04 /* Unimplemented: Requests out-of-band data. The significance and semantics of out-of-band data are protocol-specific */ --#define MSG_DONTWAIT 0x08 /* Nonblocking i/o for this operation only */ --#define MSG_MORE 0x10 /* Sender will send more */ --#define MSG_NOSIGNAL 0x20 /* Uninmplemented: Requests not to send the SIGPIPE signal if an attempt to send is made on a stream-oriented socket that is no longer connected. */ -- -- --/* -- * Options for level IPPROTO_IP -- */ --#define IP_TOS 1 --#define IP_TTL 2 --#define IP_PKTINFO 8 -- --#if LWIP_TCP --/* -- * Options for level IPPROTO_TCP -- */ --#define TCP_NODELAY 0x01 /* don't delay send to coalesce packets */ --#define TCP_KEEPALIVE 0x02 /* send KEEPALIVE probes when idle for pcb->keep_idle milliseconds */ --#define TCP_KEEPIDLE 0x03 /* set pcb->keep_idle - Same as TCP_KEEPALIVE, but use seconds for get/setsockopt */ --#define TCP_KEEPINTVL 0x04 /* set pcb->keep_intvl - Use seconds for get/setsockopt */ --#define TCP_KEEPCNT 0x05 /* set pcb->keep_cnt - Use number of probes sent for get/setsockopt */ --#endif /* LWIP_TCP */ -- --#if LWIP_IPV6 --/* -- * Options for level IPPROTO_IPV6 -- */ --#define IPV6_CHECKSUM 7 /* RFC3542: calculate and insert the ICMPv6 checksum for raw sockets. */ --#define IPV6_V6ONLY 27 /* RFC3493: boolean control to restrict AF_INET6 sockets to IPv6 communications only. */ --#endif /* LWIP_IPV6 */ -- --#if LWIP_UDP && LWIP_UDPLITE --/* -- * Options for level IPPROTO_UDPLITE -- */ --#define UDPLITE_SEND_CSCOV 0x01 /* sender checksum coverage */ --#define UDPLITE_RECV_CSCOV 0x02 /* minimal receiver checksum coverage */ --#endif /* LWIP_UDP && LWIP_UDPLITE*/ -- -- --#if LWIP_MULTICAST_TX_OPTIONS --/* -- * Options and types for UDP multicast traffic handling -- */ --#define IP_MULTICAST_TTL 5 --#define IP_MULTICAST_IF 6 --#define IP_MULTICAST_LOOP 7 --#endif /* LWIP_MULTICAST_TX_OPTIONS */ -- --#if LWIP_IGMP --/* -- * Options and types related to multicast membership -- */ --#define IP_ADD_MEMBERSHIP 3 --#define IP_DROP_MEMBERSHIP 4 -- --typedef struct ip_mreq { -- struct in_addr imr_multiaddr; /* IP multicast address of group */ -- struct in_addr imr_interface; /* local IP address of interface */ --} ip_mreq; --#endif /* LWIP_IGMP */ -- --#if LWIP_IPV4 --struct in_pktinfo { -- unsigned int ipi_ifindex; /* Interface index */ -- struct in_addr ipi_addr; /* Destination (from header) address */ --}; --#endif /* LWIP_IPV4 */ -- --#if LWIP_IPV6_MLD --/* -- * Options and types related to IPv6 multicast membership -- */ --#define IPV6_JOIN_GROUP 12 --#define IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP --#define IPV6_LEAVE_GROUP 13 --#define IPV6_DROP_MEMBERSHIP IPV6_LEAVE_GROUP -- --typedef struct ipv6_mreq { -- struct in6_addr ipv6mr_multiaddr; /* IPv6 multicast addr */ -- unsigned int ipv6mr_interface; /* interface index, or 0 */ --} ipv6_mreq; --#endif /* LWIP_IPV6_MLD */ -- --/* -- * The Type of Service provides an indication of the abstract -- * parameters of the quality of service desired. These parameters are -- * to be used to guide the selection of the actual service parameters -- * when transmitting a datagram through a particular network. Several -- * networks offer service precedence, which somehow treats high -- * precedence traffic as more important than other traffic (generally -- * by accepting only traffic above a certain precedence at time of high -- * load). The major choice is a three way tradeoff between low-delay, -- * high-reliability, and high-throughput. -- * The use of the Delay, Throughput, and Reliability indications may -- * increase the cost (in some sense) of the service. In many networks -- * better performance for one of these parameters is coupled with worse -- * performance on another. Except for very unusual cases at most two -- * of these three indications should be set. -- */ --#define IPTOS_TOS_MASK 0x1E --#define IPTOS_TOS(tos) ((tos) & IPTOS_TOS_MASK) --#define IPTOS_LOWDELAY 0x10 --#define IPTOS_THROUGHPUT 0x08 --#define IPTOS_RELIABILITY 0x04 --#define IPTOS_LOWCOST 0x02 --#define IPTOS_MINCOST IPTOS_LOWCOST -- --/* -- * The Network Control precedence designation is intended to be used -- * within a network only. The actual use and control of that -- * designation is up to each network. The Internetwork Control -- * designation is intended for use by gateway control originators only. -- * If the actual use of these precedence designations is of concern to -- * a particular network, it is the responsibility of that network to -- * control the access to, and use of, those precedence designations. -- */ --#define IPTOS_PREC_MASK 0xe0 --#define IPTOS_PREC(tos) ((tos) & IPTOS_PREC_MASK) --#define IPTOS_PREC_NETCONTROL 0xe0 --#define IPTOS_PREC_INTERNETCONTROL 0xc0 --#define IPTOS_PREC_CRITIC_ECP 0xa0 --#define IPTOS_PREC_FLASHOVERRIDE 0x80 --#define IPTOS_PREC_FLASH 0x60 --#define IPTOS_PREC_IMMEDIATE 0x40 --#define IPTOS_PREC_PRIORITY 0x20 --#define IPTOS_PREC_ROUTINE 0x00 -- -- --/* -- * Commands for ioctlsocket(), taken from the BSD file fcntl.h. -- * lwip_ioctl only supports FIONREAD and FIONBIO, for now -- * -- * Ioctl's have the command encoded in the lower word, -- * and the size of any in or out parameters in the upper -- * word. The high 2 bits of the upper word are used -- * to encode the in/out status of the parameter; for now -- * we restrict parameters to at most 128 bytes. -- */ --#if !defined(FIONREAD) || !defined(FIONBIO) --#define IOCPARM_MASK 0x7fU /* parameters must be < 128 bytes */ --#define IOC_VOID 0x20000000UL /* no parameters */ --#define IOC_OUT 0x40000000UL /* copy out parameters */ --#define IOC_IN 0x80000000UL /* copy in parameters */ --#define IOC_INOUT (IOC_IN|IOC_OUT) -- /* 0x20000000 distinguishes new & -- old ioctl's */ --#define _IO(x,y) ((long)(IOC_VOID|((x)<<8)|(y))) -- --#define _IOR(x,y,t) ((long)(IOC_OUT|((sizeof(t)&IOCPARM_MASK)<<16)|((x)<<8)|(y))) -- --#define _IOW(x,y,t) ((long)(IOC_IN|((sizeof(t)&IOCPARM_MASK)<<16)|((x)<<8)|(y))) --#endif /* !defined(FIONREAD) || !defined(FIONBIO) */ -- --#ifndef FIONREAD --#define FIONREAD _IOR('f', 127, unsigned long) /* get # bytes to read */ --#endif --#ifndef FIONBIO --#define FIONBIO _IOW('f', 126, unsigned long) /* set/clear non-blocking i/o */ --#endif -- --/* Socket I/O Controls: unimplemented */ --#ifndef SIOCSHIWAT --#define SIOCSHIWAT _IOW('s', 0, unsigned long) /* set high watermark */ --#define SIOCGHIWAT _IOR('s', 1, unsigned long) /* get high watermark */ --#define SIOCSLOWAT _IOW('s', 2, unsigned long) /* set low watermark */ --#define SIOCGLOWAT _IOR('s', 3, unsigned long) /* get low watermark */ --#define SIOCATMARK _IOR('s', 7, unsigned long) /* at oob mark? */ --#endif -- --/* commands for fnctl */ --#ifndef F_GETFL --#define F_GETFL 3 --#endif --#ifndef F_SETFL --#define F_SETFL 4 --#endif -- --/* File status flags and file access modes for fnctl, -- these are bits in an int. */ --#ifndef O_NONBLOCK --#define O_NONBLOCK 1 /* nonblocking I/O */ --#endif --#ifndef O_NDELAY --#define O_NDELAY O_NONBLOCK /* same as O_NONBLOCK, for compatibility */ --#endif --#ifndef O_RDONLY --#define O_RDONLY 2 --#endif --#ifndef O_WRONLY --#define O_WRONLY 4 --#endif --#ifndef O_RDWR --#define O_RDWR (O_RDONLY|O_WRONLY) --#endif -- --#ifndef SHUT_RD -- #define SHUT_RD 0 -- #define SHUT_WR 1 -- #define SHUT_RDWR 2 --#endif -- --/* FD_SET used for lwip_select */ --#ifndef FD_SET --#undef FD_SETSIZE --/* Make FD_SETSIZE match NUM_SOCKETS in socket.c */ --#define FD_SETSIZE MEMP_NUM_NETCONN --#define LWIP_SELECT_MAXNFDS (FD_SETSIZE + LWIP_SOCKET_OFFSET) --#define FDSETSAFESET(n, code) do { \ -- if (((n) - LWIP_SOCKET_OFFSET < MEMP_NUM_NETCONN) && (((int)(n) - LWIP_SOCKET_OFFSET) >= 0)) { \ -- code; }} while(0) --#define FDSETSAFEGET(n, code) (((n) - LWIP_SOCKET_OFFSET < MEMP_NUM_NETCONN) && (((int)(n) - LWIP_SOCKET_OFFSET) >= 0) ?\ -- (code) : 0) --#define FD_SET(n, p) FDSETSAFESET(n, (p)->fd_bits[((n)-LWIP_SOCKET_OFFSET)/8] = (u8_t)((p)->fd_bits[((n)-LWIP_SOCKET_OFFSET)/8] | (1 << (((n)-LWIP_SOCKET_OFFSET) & 7)))) --#define FD_CLR(n, p) FDSETSAFESET(n, (p)->fd_bits[((n)-LWIP_SOCKET_OFFSET)/8] = (u8_t)((p)->fd_bits[((n)-LWIP_SOCKET_OFFSET)/8] & ~(1 << (((n)-LWIP_SOCKET_OFFSET) & 7)))) --#define FD_ISSET(n,p) FDSETSAFEGET(n, (p)->fd_bits[((n)-LWIP_SOCKET_OFFSET)/8] & (1 << (((n)-LWIP_SOCKET_OFFSET) & 7))) --#define FD_ZERO(p) memset((void*)(p), 0, sizeof(*(p))) -- --typedef struct fd_set --{ -- unsigned char fd_bits [(FD_SETSIZE+7)/8]; --} fd_set; -- --#elif FD_SETSIZE < (LWIP_SOCKET_OFFSET + MEMP_NUM_NETCONN) --#error "external FD_SETSIZE too small for number of sockets" --#else --#define LWIP_SELECT_MAXNFDS FD_SETSIZE --#endif /* FD_SET */ -- --/* poll-related defines and types */ --/* @todo: find a better way to guard the definition of these defines and types if already defined */ --#if !defined(POLLIN) && !defined(POLLOUT) --#define POLLIN 0x1 --#define POLLOUT 0x2 --#define POLLERR 0x4 --#define POLLNVAL 0x8 --/* Below values are unimplemented */ --#define POLLRDNORM 0x10 --#define POLLRDBAND 0x20 --#define POLLPRI 0x40 --#define POLLWRNORM 0x80 --#define POLLWRBAND 0x100 --#define POLLHUP 0x200 --typedef unsigned int nfds_t; --struct pollfd --{ -- int fd; -- short events; -- short revents; --}; --#endif -- --/** LWIP_TIMEVAL_PRIVATE: if you want to use the struct timeval provided -- * by your system, set this to 0 and include in cc.h */ --#ifndef LWIP_TIMEVAL_PRIVATE --#define LWIP_TIMEVAL_PRIVATE 1 --#endif -- --#if LWIP_TIMEVAL_PRIVATE --struct timeval { -- long tv_sec; /* seconds */ -- long tv_usec; /* and microseconds */ --}; --#endif /* LWIP_TIMEVAL_PRIVATE */ -- --#define lwip_socket_init() /* Compatibility define, no init needed. */ --void lwip_socket_thread_init(void); /* LWIP_NETCONN_SEM_PER_THREAD==1: initialize thread-local semaphore */ --void lwip_socket_thread_cleanup(void); /* LWIP_NETCONN_SEM_PER_THREAD==1: destroy thread-local semaphore */ -- --#if LWIP_COMPAT_SOCKETS == 2 --/* This helps code parsers/code completion by not having the COMPAT functions as defines */ --#define lwip_accept accept --#define lwip_bind bind --#define lwip_shutdown shutdown --#define lwip_getpeername getpeername --#define lwip_getsockname getsockname --#define lwip_setsockopt setsockopt --#define lwip_getsockopt getsockopt --#define lwip_close closesocket --#define lwip_connect connect --#define lwip_listen listen --#define lwip_recv recv --#define lwip_recvmsg recvmsg --#define lwip_recvfrom recvfrom --#define lwip_send send --#define lwip_sendmsg sendmsg --#define lwip_sendto sendto --#define lwip_socket socket --#if LWIP_SOCKET_SELECT --#define lwip_select select --#endif --#if LWIP_SOCKET_POLL --#define lwip_poll poll --#endif --#define lwip_ioctl ioctlsocket --#define lwip_inet_ntop inet_ntop --#define lwip_inet_pton inet_pton -- --#if LWIP_POSIX_SOCKETS_IO_NAMES --#define lwip_read read --#define lwip_readv readv --#define lwip_write write --#define lwip_writev writev --#undef lwip_close --#define lwip_close close --#define closesocket(s) close(s) --int fcntl(int s, int cmd, ...); --#undef lwip_ioctl --#define lwip_ioctl ioctl --#define ioctlsocket ioctl --#endif /* LWIP_POSIX_SOCKETS_IO_NAMES */ --#endif /* LWIP_COMPAT_SOCKETS == 2 */ -- --int lwip_accept(int s, struct sockaddr *addr, socklen_t *addrlen); --int lwip_bind(int s, const struct sockaddr *name, socklen_t namelen); --int lwip_shutdown(int s, int how); --int lwip_getpeername (int s, struct sockaddr *name, socklen_t *namelen); --int lwip_getsockname (int s, struct sockaddr *name, socklen_t *namelen); --int lwip_getsockopt (int s, int level, int optname, void *optval, socklen_t *optlen); --int lwip_setsockopt (int s, int level, int optname, const void *optval, socklen_t optlen); -- int lwip_close(int s); --int lwip_connect(int s, const struct sockaddr *name, socklen_t namelen); --int lwip_listen(int s, int backlog); --ssize_t lwip_recv(int s, void *mem, size_t len, int flags); --ssize_t lwip_read(int s, void *mem, size_t len); --ssize_t lwip_readv(int s, const struct iovec *iov, int iovcnt); --ssize_t lwip_recvfrom(int s, void *mem, size_t len, int flags, -- struct sockaddr *from, socklen_t *fromlen); --ssize_t lwip_recvmsg(int s, struct msghdr *message, int flags); --ssize_t lwip_send(int s, const void *dataptr, size_t size, int flags); --ssize_t lwip_sendmsg(int s, const struct msghdr *message, int flags); --ssize_t lwip_sendto(int s, const void *dataptr, size_t size, int flags, -- const struct sockaddr *to, socklen_t tolen); --int lwip_socket(int domain, int type, int protocol); --ssize_t lwip_write(int s, const void *dataptr, size_t size); --ssize_t lwip_writev(int s, const struct iovec *iov, int iovcnt); --#if LWIP_SOCKET_SELECT --int lwip_select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset, -- struct timeval *timeout); --#endif --#if LWIP_SOCKET_POLL --int lwip_poll(struct pollfd *fds, nfds_t nfds, int timeout); --#endif --int lwip_ioctl(int s, long cmd, void *argp); --int lwip_fcntl(int s, int cmd, int val); --const char *lwip_inet_ntop(int af, const void *src, char *dst, socklen_t size); --int lwip_inet_pton(int af, const char *src, void *dst); -- --#if LWIP_COMPAT_SOCKETS --#if LWIP_COMPAT_SOCKETS != 2 --/** @ingroup socket */ --#define accept(s,addr,addrlen) lwip_accept(s,addr,addrlen) --/** @ingroup socket */ --#define bind(s,name,namelen) lwip_bind(s,name,namelen) --/** @ingroup socket */ --#define shutdown(s,how) lwip_shutdown(s,how) --/** @ingroup socket */ --#define getpeername(s,name,namelen) lwip_getpeername(s,name,namelen) --/** @ingroup socket */ --#define getsockname(s,name,namelen) lwip_getsockname(s,name,namelen) --/** @ingroup socket */ --#define setsockopt(s,level,optname,opval,optlen) lwip_setsockopt(s,level,optname,opval,optlen) --/** @ingroup socket */ --#define getsockopt(s,level,optname,opval,optlen) lwip_getsockopt(s,level,optname,opval,optlen) --/** @ingroup socket */ --#define closesocket(s) lwip_close(s) --/** @ingroup socket */ --#define connect(s,name,namelen) lwip_connect(s,name,namelen) --/** @ingroup socket */ --#define listen(s,backlog) lwip_listen(s,backlog) --/** @ingroup socket */ --#define recv(s,mem,len,flags) lwip_recv(s,mem,len,flags) --/** @ingroup socket */ --#define recvmsg(s,message,flags) lwip_recvmsg(s,message,flags) --/** @ingroup socket */ --#define recvfrom(s,mem,len,flags,from,fromlen) lwip_recvfrom(s,mem,len,flags,from,fromlen) --/** @ingroup socket */ --#define send(s,dataptr,size,flags) lwip_send(s,dataptr,size,flags) --/** @ingroup socket */ --#define sendmsg(s,message,flags) lwip_sendmsg(s,message,flags) --/** @ingroup socket */ --#define sendto(s,dataptr,size,flags,to,tolen) lwip_sendto(s,dataptr,size,flags,to,tolen) --/** @ingroup socket */ --#define socket(domain,type,protocol) lwip_socket(domain,type,protocol) --#if LWIP_SOCKET_SELECT --/** @ingroup socket */ --#define select(maxfdp1,readset,writeset,exceptset,timeout) lwip_select(maxfdp1,readset,writeset,exceptset,timeout) --#endif --#if LWIP_SOCKET_POLL --/** @ingroup socket */ --#define poll(fds,nfds,timeout) lwip_poll(fds,nfds,timeout) --#endif --/** @ingroup socket */ --#define ioctlsocket(s,cmd,argp) lwip_ioctl(s,cmd,argp) --/** @ingroup socket */ --#define inet_ntop(af,src,dst,size) lwip_inet_ntop(af,src,dst,size) --/** @ingroup socket */ --#define inet_pton(af,src,dst) lwip_inet_pton(af,src,dst) -- --#if LWIP_POSIX_SOCKETS_IO_NAMES --/** @ingroup socket */ --#define read(s,mem,len) lwip_read(s,mem,len) --/** @ingroup socket */ --#define readv(s,iov,iovcnt) lwip_readv(s,iov,iovcnt) --/** @ingroup socket */ --#define write(s,dataptr,len) lwip_write(s,dataptr,len) --/** @ingroup socket */ --#define writev(s,iov,iovcnt) lwip_writev(s,iov,iovcnt) --/** @ingroup socket */ --#define close(s) lwip_close(s) --/** @ingroup socket */ --#define fcntl(s,cmd,val) lwip_fcntl(s,cmd,val) --/** @ingroup socket */ --#define ioctl(s,cmd,argp) lwip_ioctl(s,cmd,argp) --#endif /* LWIP_POSIX_SOCKETS_IO_NAMES */ --#endif /* LWIP_COMPAT_SOCKETS != 2 */ -- --#endif /* LWIP_COMPAT_SOCKETS */ -- --#ifdef __cplusplus --} --#endif -- --#endif /* LWIP_SOCKET */ -- --#endif /* LWIP_HDR_SOCKETS_H */ -+/** -+ * @file -+ * Socket API (to be used from non-TCPIP threads) -+ */ -+ -+/* -+ * 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 -+ * -+ */ -+ -+ -+#ifndef LWIP_HDR_SOCKETS_H -+#define LWIP_HDR_SOCKETS_H + struct netifapi_msg { + struct tcpip_api_call_data call; +@@ -245,9 +263,27 @@ + NETIFAPI_IPADDR_DEF(ip4_addr_t, gw); + #endif /* LWIP_IPV4 */ + void *state; ++ } add; + -+#include "lwip/opt.h" ++ struct { ++ const ip_addr_t *ipaddr; ++ } find_by_ipaddr; ++ struct { ++ const char *name; ++ } find_by_name; ++ struct { ++ unsigned char ifindex; ++ } find_by_ifindex; ++ struct { ++#if LWIP_IPV4 ++ ip4_addr_t *ipaddr; ++ ip4_addr_t *netmask; ++ ip4_addr_t *gw; ++#endif /* LWIP_IPV4 */ ++ void *state; + netif_init_fn init; + netif_input_fn input; +- } add; ++ } add_get; + struct { + netifapi_void_fn voidfunc; + netifapi_errt_fn errtfunc; +diff -Nur a/lwip-2.1.2/src/include/lwip/priv/sockets_priv.h b/lwip-2.1.2/src/include/lwip/priv/sockets_priv.h +--- a/lwip-2.1.2/src/include/lwip/priv/sockets_priv.h 2021-06-29 15:16:18.808893323 +0800 ++++ b/lwip-2.1.2/src/include/lwip/priv/sockets_priv.h 2021-06-29 15:16:44.636898726 +0800 +@@ -49,7 +49,6 @@ + extern "C" { + #endif + +-#define NUM_SOCKETS MEMP_NUM_NETCONN + + /** This is overridable for the rare case where more than 255 threads + * select on the same socket... +@@ -69,6 +68,10 @@ + struct netconn *conn; + /** data that was left from the previous read */ + union lwip_sock_lastdata lastdata; ++ /** offset in the data that was left from the previous read */ ++ u16_t lastoffset; ++ /* socket level mutex used for multithread recv support */ ++ sys_mutex_t mutex; + #if LWIP_SOCKET_SELECT || LWIP_SOCKET_POLL + /** number of times data was received, set by event_callback(), + tested by the receive and select functions */ +@@ -158,6 +161,7 @@ + fd_set *exceptset; + #endif /* LWIP_SOCKET_SELECT */ + #if LWIP_SOCKET_POLL + -+#if LWIP_SOCKET /* don't build if not configured for use in lwipopts.h */ + /** fds passed to poll; NULL if select */ + struct pollfd *poll_fds; + /** nfds passed to poll; 0 if select */ +diff -Nur a/lwip-2.1.2/src/include/lwip/prot/icmp6.h b/lwip-2.1.2/src/include/lwip/prot/icmp6.h +--- a/lwip-2.1.2/src/include/lwip/prot/icmp6.h 2021-06-29 15:16:18.808893323 +0800 ++++ b/lwip-2.1.2/src/include/lwip/prot/icmp6.h 2021-06-29 15:16:44.636898726 +0800 +@@ -135,7 +135,7 @@ + # include "arch/bpstruct.h" + #endif + PACK_STRUCT_BEGIN +-struct icmp6_hdr { ++struct icmpv6_hdr { + PACK_STRUCT_FLD_8(u8_t type); + PACK_STRUCT_FLD_8(u8_t code); + PACK_STRUCT_FIELD(u16_t chksum); +diff -Nur a/lwip-2.1.2/src/include/lwip/prot/ip4.h b/lwip-2.1.2/src/include/lwip/prot/ip4.h +--- a/lwip-2.1.2/src/include/lwip/prot/ip4.h 2021-06-29 15:16:18.808893323 +0800 ++++ b/lwip-2.1.2/src/include/lwip/prot/ip4.h 2021-06-29 15:16:44.636898726 +0800 +@@ -39,6 +39,9 @@ + + #include "lwip/arch.h" + #include "lwip/ip4_addr.h" ++#if LWIP_LITEOS_COMPAT ++#include ++#endif + + #ifdef __cplusplus + extern "C" { +@@ -81,10 +84,12 @@ + PACK_STRUCT_FIELD(u16_t _id); + /* fragment offset field */ + PACK_STRUCT_FIELD(u16_t _offset); ++#if !LWIP_LITEOS_COMPAT + #define IP_RF 0x8000U /* reserved fragment flag */ + #define IP_DF 0x4000U /* don't fragment flag */ + #define IP_MF 0x2000U /* more fragments flag */ + #define IP_OFFMASK 0x1fffU /* mask for fragmenting bits */ ++#endif + /* time to live */ + PACK_STRUCT_FLD_8(u8_t _ttl); + /* protocol*/ +diff -Nur a/lwip-2.1.2/src/include/lwip/raw.h b/lwip-2.1.2/src/include/lwip/raw.h +--- a/lwip-2.1.2/src/include/lwip/raw.h 2021-06-29 15:16:18.808893323 +0800 ++++ b/lwip-2.1.2/src/include/lwip/raw.h 2021-06-29 15:16:44.640898726 +0800 +@@ -47,6 +47,8 @@ + #include "lwip/ip.h" + #include "lwip/ip_addr.h" + #include "lwip/ip6_addr.h" ++#include "lwip/etharp.h" ++#include "lwip/icmp6.h" + + #ifdef __cplusplus + extern "C" { +@@ -57,6 +59,18 @@ + #define RAW_FLAGS_MULTICAST_LOOP 0x04U + + struct raw_pcb; ++extern struct raw_pcb* raw_pcbs; + -+#include "lwip/ip_addr.h" -+#include "lwip/netif.h" -+#include "lwip/err.h" -+#include "lwip/inet.h" -+#include "lwip/errno.h" ++#if PF_PACKET_SOCKET ++extern const struct eth_hdr *g_lwip_current_eth_hdr; ++extern const struct netif *g_lwip_current_netif; ++/* Dest MAC add of current ethernet header of RAW packets ++ * received for PF_PACKET family */ ++#define eth_current_hdr() (g_lwip_current_eth_hdr) ++#define eth_current_netif() (g_lwip_current_netif) ++struct raw_pcb* get_packet_raw_pcbs(void); ++struct raw_pcb* get_all_packet_raw_pcbs(void); ++#endif /* PF_PACKET_SOCKET */ + + /** Function prototype for raw pcb receive callback functions. + * @param arg user supplied argument (raw_pcb.recv_arg) +@@ -77,8 +91,19 @@ + IP_PCB; + + struct raw_pcb *next; +- ++#if PF_PACKET_SOCKET ++ struct raw_pcb *all_next; ++ u8_t netifindex; + -+#include ++ union { ++ u16_t eth_proto; /* Ethernet HeaderType/Protocol for Packet sockets */ ++#define raw_proto proto.protocol ++ u8_t protocol; /* IP protocol for AF_INET sockets */ ++ } proto; ++#else ++#define raw_proto protocol + u8_t protocol; ++#endif + u8_t flags; + + #if LWIP_MULTICAST_TX_OPTIONS +@@ -115,6 +140,14 @@ + + void raw_recv (struct raw_pcb *pcb, raw_recv_fn recv, void *recv_arg); + ++#if PF_PACKET_SOCKET ++struct raw_pcb * raw_packet_new (u16_t proto); ++void raw_packet_remove (struct raw_pcb *pcb); ++void raw_packet_input (struct pbuf *p, const struct netif *inp, const struct raw_pcb *from); ++err_t raw_packet_sendto (const struct raw_pcb *pcb, struct pbuf *p, u8_t ifindex); ++err_t raw_packet_bind (struct raw_pcb *pcb, u8_t ifindex, u16_t proto); ++#endif /* PF_PACKET_SOCKET */ + + #define raw_flags(pcb) ((pcb)->flags) + #define raw_setflags(pcb,f) ((pcb)->flags = (f)) + +diff -Nur a/lwip-2.1.2/src/include/lwip/sockets.h b/lwip-2.1.2/src/include/lwip/sockets.h +--- a/lwip-2.1.2/src/include/lwip/sockets.h 2021-06-29 15:16:18.808893323 +0800 ++++ b/lwip-2.1.2/src/include/lwip/sockets.h 2021-06-29 15:16:44.636898726 +0800 +@@ -51,10 +51,18 @@ + + #include + +#if LWIP_LITEOS_COMPAT +#include "sys/select.h" +#include "sys/socket.h" @@ -20844,482 +3975,18 @@ diff -Nur a/lwip-2.1.2/src/include/lwip/sockets.h b/lwip-2.1.2/src/include/lwip/ +#include "netinet/tcp.h" +#endif /* LWIP_LITEOS_COMPAT */ + -+#ifdef __cplusplus -+extern "C" { -+#endif -+ + #ifdef __cplusplus + extern "C" { + #endif + +#if !LWIP_LITEOS_COMPAT -+/* If your port already typedef's sa_family_t, define SA_FAMILY_T_DEFINED -+ to prevent this code from redefining it. */ -+#if !defined(sa_family_t) && !defined(SA_FAMILY_T_DEFINED) -+typedef u8_t sa_family_t; -+#endif -+/* If your port already typedef's in_port_t, define IN_PORT_T_DEFINED -+ to prevent this code from redefining it. */ -+#if !defined(in_port_t) && !defined(IN_PORT_T_DEFINED) -+typedef u16_t in_port_t; -+#endif -+ -+#if LWIP_IPV4 -+/* members are in network byte order */ -+struct sockaddr_in { -+ u8_t sin_len; -+ sa_family_t sin_family; -+ in_port_t sin_port; -+ struct in_addr sin_addr; -+#define SIN_ZERO_LEN 8 -+ char sin_zero[SIN_ZERO_LEN]; -+}; -+#endif /* LWIP_IPV4 */ -+ -+#if LWIP_IPV6 -+struct sockaddr_in6 { -+ u8_t sin6_len; /* length of this structure */ -+ sa_family_t sin6_family; /* AF_INET6 */ -+ in_port_t sin6_port; /* Transport layer port # */ -+ u32_t sin6_flowinfo; /* IPv6 flow information */ -+ struct in6_addr sin6_addr; /* IPv6 address */ -+ u32_t sin6_scope_id; /* Set of interfaces for scope */ -+}; -+#endif /* LWIP_IPV6 */ -+ -+struct sockaddr { -+ u8_t sa_len; -+ sa_family_t sa_family; -+ char sa_data[14]; -+}; -+ -+struct sockaddr_storage { -+ u8_t s2_len; -+ sa_family_t ss_family; -+ char s2_data1[2]; -+ u32_t s2_data2[3]; -+#if LWIP_IPV6 -+ u32_t s2_data3[3]; -+#endif /* LWIP_IPV6 */ -+}; -+ -+/* If your port already typedef's socklen_t, define SOCKLEN_T_DEFINED -+ to prevent this code from redefining it. */ -+#if !defined(socklen_t) && !defined(SOCKLEN_T_DEFINED) -+typedef u32_t socklen_t; -+#endif -+ -+#if !defined IOV_MAX -+#define IOV_MAX 0xFFFF -+#elif IOV_MAX > 0xFFFF -+#error "IOV_MAX larger than supported by LwIP" -+#endif /* IOV_MAX */ -+ -+#if !defined(iovec) -+struct iovec { -+ void *iov_base; -+ size_t iov_len; -+}; -+#endif -+ -+struct msghdr { -+ void *msg_name; -+ socklen_t msg_namelen; -+ struct iovec *msg_iov; -+ int msg_iovlen; -+ void *msg_control; -+ socklen_t msg_controllen; -+ int msg_flags; -+}; -+ -+/* struct msghdr->msg_flags bit field values */ -+#define MSG_TRUNC 0x04 -+#define MSG_CTRUNC 0x08 -+ -+/* RFC 3542, Section 20: Ancillary Data */ -+struct cmsghdr { -+ socklen_t cmsg_len; /* number of bytes, including header */ -+ int cmsg_level; /* originating protocol */ -+ int cmsg_type; /* protocol-specific type */ -+}; -+/* Data section follows header and possible padding, typically referred to as -+ unsigned char cmsg_data[]; */ -+ -+/* cmsg header/data alignment. NOTE: we align to native word size (double word -+size on 16-bit arch) so structures are not placed at an unaligned address. -+16-bit arch needs double word to ensure 32-bit alignment because socklen_t -+could be 32 bits. If we ever have cmsg data with a 64-bit variable, alignment -+will need to increase long long */ -+#define ALIGN_H(size) (((size) + sizeof(long) - 1U) & ~(sizeof(long)-1U)) -+#define ALIGN_D(size) ALIGN_H(size) -+ -+#define CMSG_FIRSTHDR(mhdr) \ -+ ((mhdr)->msg_controllen >= sizeof(struct cmsghdr) ? \ -+ (struct cmsghdr *)(mhdr)->msg_control : \ -+ (struct cmsghdr *)NULL) -+ -+#define CMSG_NXTHDR(mhdr, cmsg) \ -+ (((cmsg) == NULL) ? CMSG_FIRSTHDR(mhdr) : \ -+ (((u8_t *)(cmsg) + ALIGN_H((cmsg)->cmsg_len) \ -+ + ALIGN_D(sizeof(struct cmsghdr)) > \ -+ (u8_t *)((mhdr)->msg_control) + (mhdr)->msg_controllen) ? \ -+ (struct cmsghdr *)NULL : \ -+ (struct cmsghdr *)((void*)((u8_t *)(cmsg) + \ -+ ALIGN_H((cmsg)->cmsg_len))))) -+ -+#define CMSG_DATA(cmsg) ((void*)((u8_t *)(cmsg) + \ -+ ALIGN_D(sizeof(struct cmsghdr)))) -+ -+#define CMSG_SPACE(length) (ALIGN_D(sizeof(struct cmsghdr)) + \ -+ ALIGN_H(length)) -+ -+#define CMSG_LEN(length) (ALIGN_D(sizeof(struct cmsghdr)) + \ -+ length) -+ -+/* Set socket options argument */ -+#define IFNAMSIZ NETIF_NAMESIZE -+struct ifreq { -+ char ifr_name[IFNAMSIZ]; /* Interface name */ -+}; -+ -+/* Socket protocol types (TCP/UDP/RAW) */ -+#define SOCK_STREAM 1 -+#define SOCK_DGRAM 2 -+#define SOCK_RAW 3 -+ -+/* -+ * Option flags per-socket. These must match the SOF_ flags in ip.h (checked in init.c) -+ */ -+#define SO_REUSEADDR 0x0004 /* Allow local address reuse */ -+#define SO_KEEPALIVE 0x0008 /* keep connections alive */ -+#define SO_BROADCAST 0x0020 /* permit to send and to receive broadcast messages (see IP_SOF_BROADCAST option) */ -+ -+ -+/* -+ * Additional options, not kept in so_options. -+ */ -+#define SO_DEBUG 0x0001 /* Unimplemented: turn on debugging info recording */ -+#define SO_ACCEPTCONN 0x0002 /* socket has had listen() */ -+#define SO_DONTROUTE 0x0010 /* Unimplemented: just use interface addresses */ -+#define SO_USELOOPBACK 0x0040 /* Unimplemented: bypass hardware when possible */ -+#define SO_LINGER 0x0080 /* linger on close if data present */ -+#define SO_DONTLINGER ((int)(~SO_LINGER)) -+#define SO_OOBINLINE 0x0100 /* Unimplemented: leave received OOB data in line */ -+#define SO_REUSEPORT 0x0200 /* Unimplemented: allow local address & port reuse */ -+#define SO_SNDBUF 0x1001 /* Unimplemented: send buffer size */ -+#define SO_RCVBUF 0x1002 /* receive buffer size */ -+#define SO_SNDLOWAT 0x1003 /* Unimplemented: send low-water mark */ -+#define SO_RCVLOWAT 0x1004 /* Unimplemented: receive low-water mark */ -+#define SO_SNDTIMEO 0x1005 /* send timeout */ -+#define SO_RCVTIMEO 0x1006 /* receive timeout */ -+#define SO_ERROR 0x1007 /* get error status and clear */ -+#define SO_TYPE 0x1008 /* get socket type */ -+#define SO_CONTIMEO 0x1009 /* Unimplemented: connect timeout */ -+#define SO_NO_CHECK 0x100a /* don't create UDP checksum */ -+#define SO_BINDTODEVICE 0x100b /* bind to device */ -+ -+/* -+ * Structure used for manipulating linger option. -+ */ -+struct linger { -+ int l_onoff; /* option on/off */ -+ int l_linger; /* linger time in seconds */ -+}; -+ -+/* -+ * Level number for (get/set)sockopt() to apply to socket itself. -+ */ -+#define SOL_SOCKET 0xfff /* options for socket level */ -+ -+ -+#define AF_UNSPEC 0 -+#define AF_INET 2 -+#if LWIP_IPV6 -+#define AF_INET6 10 -+#else /* LWIP_IPV6 */ -+#define AF_INET6 AF_UNSPEC -+#endif /* LWIP_IPV6 */ -+#define PF_INET AF_INET -+#define PF_INET6 AF_INET6 -+#define PF_UNSPEC AF_UNSPEC -+ -+#define IPPROTO_IP 0 -+#define IPPROTO_ICMP 1 -+#define IPPROTO_TCP 6 -+#define IPPROTO_UDP 17 -+#if LWIP_IPV6 -+#define IPPROTO_IPV6 41 -+#define IPPROTO_ICMPV6 58 -+#endif /* LWIP_IPV6 */ -+#define IPPROTO_UDPLITE 136 -+#define IPPROTO_RAW 255 -+ -+/* Flags we can use with send and recv. */ -+#define MSG_PEEK 0x01 /* Peeks at an incoming message */ -+#define MSG_WAITALL 0x02 /* Unimplemented: Requests that the function block until the full amount of data requested can be returned */ -+#define MSG_OOB 0x04 /* Unimplemented: Requests out-of-band data. The significance and semantics of out-of-band data are protocol-specific */ -+#define MSG_DONTWAIT 0x08 /* Nonblocking i/o for this operation only */ -+#define MSG_MORE 0x10 /* Sender will send more */ -+#define MSG_NOSIGNAL 0x20 /* Uninmplemented: Requests not to send the SIGPIPE signal if an attempt to send is made on a stream-oriented socket that is no longer connected. */ -+ -+ -+/* -+ * Options for level IPPROTO_IP -+ */ -+#define IP_TOS 1 -+#define IP_TTL 2 -+#define IP_PKTINFO 8 -+ -+#if LWIP_TCP -+/* -+ * Options for level IPPROTO_TCP -+ */ -+#define TCP_NODELAY 0x01 /* don't delay send to coalesce packets */ -+#define TCP_KEEPALIVE 0x02 /* send KEEPALIVE probes when idle for pcb->keep_idle milliseconds */ -+#define TCP_KEEPIDLE 0x03 /* set pcb->keep_idle - Same as TCP_KEEPALIVE, but use seconds for get/setsockopt */ -+#define TCP_KEEPINTVL 0x04 /* set pcb->keep_intvl - Use seconds for get/setsockopt */ -+#define TCP_KEEPCNT 0x05 /* set pcb->keep_cnt - Use number of probes sent for get/setsockopt */ -+#endif /* LWIP_TCP */ -+ -+#if LWIP_IPV6 -+/* -+ * Options for level IPPROTO_IPV6 -+ */ -+#define IPV6_CHECKSUM 7 /* RFC3542: calculate and insert the ICMPv6 checksum for raw sockets. */ -+#define IPV6_V6ONLY 27 /* RFC3493: boolean control to restrict AF_INET6 sockets to IPv6 communications only. */ -+#endif /* LWIP_IPV6 */ -+ -+#if LWIP_UDP && LWIP_UDPLITE -+/* -+ * Options for level IPPROTO_UDPLITE -+ */ -+#define UDPLITE_SEND_CSCOV 0x01 /* sender checksum coverage */ -+#define UDPLITE_RECV_CSCOV 0x02 /* minimal receiver checksum coverage */ -+#endif /* LWIP_UDP && LWIP_UDPLITE*/ -+ -+ -+#if LWIP_MULTICAST_TX_OPTIONS -+/* -+ * Options and types for UDP multicast traffic handling -+ */ -+#define IP_MULTICAST_TTL 5 -+#define IP_MULTICAST_IF 6 -+#define IP_MULTICAST_LOOP 7 -+#endif /* LWIP_MULTICAST_TX_OPTIONS */ -+ -+#if LWIP_IGMP -+/* -+ * Options and types related to multicast membership -+ */ -+#define IP_ADD_MEMBERSHIP 3 -+#define IP_DROP_MEMBERSHIP 4 -+ -+typedef struct ip_mreq { -+ struct in_addr imr_multiaddr; /* IP multicast address of group */ -+ struct in_addr imr_interface; /* local IP address of interface */ -+} ip_mreq; -+#endif /* LWIP_IGMP */ -+ -+#if LWIP_IPV4 -+struct in_pktinfo { -+ unsigned int ipi_ifindex; /* Interface index */ -+ struct in_addr ipi_addr; /* Destination (from header) address */ -+}; -+#endif /* LWIP_IPV4 */ -+ -+#if LWIP_IPV6_MLD -+/* -+ * Options and types related to IPv6 multicast membership -+ */ -+#define IPV6_JOIN_GROUP 12 -+#define IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP -+#define IPV6_LEAVE_GROUP 13 -+#define IPV6_DROP_MEMBERSHIP IPV6_LEAVE_GROUP -+ -+typedef struct ipv6_mreq { -+ struct in6_addr ipv6mr_multiaddr; /* IPv6 multicast addr */ -+ unsigned int ipv6mr_interface; /* interface index, or 0 */ -+} ipv6_mreq; -+#endif /* LWIP_IPV6_MLD */ -+ -+/* -+ * The Type of Service provides an indication of the abstract -+ * parameters of the quality of service desired. These parameters are -+ * to be used to guide the selection of the actual service parameters -+ * when transmitting a datagram through a particular network. Several -+ * networks offer service precedence, which somehow treats high -+ * precedence traffic as more important than other traffic (generally -+ * by accepting only traffic above a certain precedence at time of high -+ * load). The major choice is a three way tradeoff between low-delay, -+ * high-reliability, and high-throughput. -+ * The use of the Delay, Throughput, and Reliability indications may -+ * increase the cost (in some sense) of the service. In many networks -+ * better performance for one of these parameters is coupled with worse -+ * performance on another. Except for very unusual cases at most two -+ * of these three indications should be set. -+ */ -+#define IPTOS_TOS_MASK 0x1E -+#define IPTOS_TOS(tos) ((tos) & IPTOS_TOS_MASK) -+#define IPTOS_LOWDELAY 0x10 -+#define IPTOS_THROUGHPUT 0x08 -+#define IPTOS_RELIABILITY 0x04 -+#define IPTOS_LOWCOST 0x02 -+#define IPTOS_MINCOST IPTOS_LOWCOST -+ -+/* -+ * The Network Control precedence designation is intended to be used -+ * within a network only. The actual use and control of that -+ * designation is up to each network. The Internetwork Control -+ * designation is intended for use by gateway control originators only. -+ * If the actual use of these precedence designations is of concern to -+ * a particular network, it is the responsibility of that network to -+ * control the access to, and use of, those precedence designations. -+ */ -+#define IPTOS_PREC_MASK 0xe0 -+#define IPTOS_PREC(tos) ((tos) & IPTOS_PREC_MASK) -+#define IPTOS_PREC_NETCONTROL 0xe0 -+#define IPTOS_PREC_INTERNETCONTROL 0xc0 -+#define IPTOS_PREC_CRITIC_ECP 0xa0 -+#define IPTOS_PREC_FLASHOVERRIDE 0x80 -+#define IPTOS_PREC_FLASH 0x60 -+#define IPTOS_PREC_IMMEDIATE 0x40 -+#define IPTOS_PREC_PRIORITY 0x20 -+#define IPTOS_PREC_ROUTINE 0x00 -+ -+ -+/* -+ * Commands for ioctlsocket(), taken from the BSD file fcntl.h. -+ * lwip_ioctl only supports FIONREAD and FIONBIO, for now -+ * -+ * Ioctl's have the command encoded in the lower word, -+ * and the size of any in or out parameters in the upper -+ * word. The high 2 bits of the upper word are used -+ * to encode the in/out status of the parameter; for now -+ * we restrict parameters to at most 128 bytes. -+ */ -+#if !defined(FIONREAD) || !defined(FIONBIO) -+#define IOCPARM_MASK 0x7fU /* parameters must be < 128 bytes */ -+#define IOC_VOID 0x20000000UL /* no parameters */ -+#define IOC_OUT 0x40000000UL /* copy out parameters */ -+#define IOC_IN 0x80000000UL /* copy in parameters */ -+#define IOC_INOUT (IOC_IN|IOC_OUT) -+ /* 0x20000000 distinguishes new & -+ old ioctl's */ -+#define _IO(x,y) ((long)(IOC_VOID|((x)<<8)|(y))) -+ -+#define _IOR(x,y,t) ((long)(IOC_OUT|((sizeof(t)&IOCPARM_MASK)<<16)|((x)<<8)|(y))) -+ -+#define _IOW(x,y,t) ((long)(IOC_IN|((sizeof(t)&IOCPARM_MASK)<<16)|((x)<<8)|(y))) -+#endif /* !defined(FIONREAD) || !defined(FIONBIO) */ -+ -+#ifndef FIONREAD -+#define FIONREAD _IOR('f', 127, unsigned long) /* get # bytes to read */ -+#endif -+#ifndef FIONBIO -+#define FIONBIO _IOW('f', 126, unsigned long) /* set/clear non-blocking i/o */ -+#endif -+ -+/* Socket I/O Controls: unimplemented */ -+#ifndef SIOCSHIWAT -+#define SIOCSHIWAT _IOW('s', 0, unsigned long) /* set high watermark */ -+#define SIOCGHIWAT _IOR('s', 1, unsigned long) /* get high watermark */ -+#define SIOCSLOWAT _IOW('s', 2, unsigned long) /* set low watermark */ -+#define SIOCGLOWAT _IOR('s', 3, unsigned long) /* get low watermark */ -+#define SIOCATMARK _IOR('s', 7, unsigned long) /* at oob mark? */ -+#endif -+ -+/* commands for fnctl */ -+#ifndef F_GETFL -+#define F_GETFL 3 -+#endif -+#ifndef F_SETFL -+#define F_SETFL 4 -+#endif -+ -+/* File status flags and file access modes for fnctl, -+ these are bits in an int. */ -+#ifndef O_NONBLOCK -+#define O_NONBLOCK 1 /* nonblocking I/O */ -+#endif -+#ifndef O_NDELAY -+#define O_NDELAY O_NONBLOCK /* same as O_NONBLOCK, for compatibility */ -+#endif -+#ifndef O_RDONLY -+#define O_RDONLY 2 -+#endif -+#ifndef O_WRONLY -+#define O_WRONLY 4 -+#endif -+#ifndef O_RDWR -+#define O_RDWR (O_RDONLY|O_WRONLY) -+#endif -+ -+#ifndef SHUT_RD -+ #define SHUT_RD 0 -+ #define SHUT_WR 1 -+ #define SHUT_RDWR 2 -+#endif -+ -+/* FD_SET used for lwip_select */ -+#ifndef FD_SET -+#undef FD_SETSIZE -+/* Make FD_SETSIZE match NUM_SOCKETS in socket.c */ -+#define FD_SETSIZE MEMP_NUM_NETCONN -+#define LWIP_SELECT_MAXNFDS (FD_SETSIZE + LWIP_SOCKET_OFFSET) -+#define FDSETSAFESET(n, code) do { \ -+ if (((n) - LWIP_SOCKET_OFFSET < MEMP_NUM_NETCONN) && (((int)(n) - LWIP_SOCKET_OFFSET) >= 0)) { \ -+ code; }} while(0) -+#define FDSETSAFEGET(n, code) (((n) - LWIP_SOCKET_OFFSET < MEMP_NUM_NETCONN) && (((int)(n) - LWIP_SOCKET_OFFSET) >= 0) ?\ -+ (code) : 0) -+#define FD_SET(n, p) FDSETSAFESET(n, (p)->fd_bits[((n)-LWIP_SOCKET_OFFSET)/8] = (u8_t)((p)->fd_bits[((n)-LWIP_SOCKET_OFFSET)/8] | (1 << (((n)-LWIP_SOCKET_OFFSET) & 7)))) -+#define FD_CLR(n, p) FDSETSAFESET(n, (p)->fd_bits[((n)-LWIP_SOCKET_OFFSET)/8] = (u8_t)((p)->fd_bits[((n)-LWIP_SOCKET_OFFSET)/8] & ~(1 << (((n)-LWIP_SOCKET_OFFSET) & 7)))) -+#define FD_ISSET(n,p) FDSETSAFEGET(n, (p)->fd_bits[((n)-LWIP_SOCKET_OFFSET)/8] & (1 << (((n)-LWIP_SOCKET_OFFSET) & 7))) -+#define FD_ZERO(p) memset((void*)(p), 0, sizeof(*(p))) -+ -+typedef struct fd_set -+{ -+ unsigned char fd_bits [(FD_SETSIZE+7)/8]; -+} fd_set; -+ -+#elif FD_SETSIZE < (LWIP_SOCKET_OFFSET + MEMP_NUM_NETCONN) -+#error "external FD_SETSIZE too small for number of sockets" -+#else -+#define LWIP_SELECT_MAXNFDS FD_SETSIZE -+#endif /* FD_SET */ -+ -+/* poll-related defines and types */ -+/* @todo: find a better way to guard the definition of these defines and types if already defined */ -+#if !defined(POLLIN) && !defined(POLLOUT) -+#define POLLIN 0x1 -+#define POLLOUT 0x2 -+#define POLLERR 0x4 -+#define POLLNVAL 0x8 -+/* Below values are unimplemented */ -+#define POLLRDNORM 0x10 -+#define POLLRDBAND 0x20 -+#define POLLPRI 0x40 -+#define POLLWRNORM 0x80 -+#define POLLWRBAND 0x100 -+#define POLLHUP 0x200 -+typedef unsigned int nfds_t; -+struct pollfd -+{ -+ int fd; -+ short events; -+ short revents; -+}; -+#endif -+ -+/** LWIP_TIMEVAL_PRIVATE: if you want to use the struct timeval provided -+ * by your system, set this to 0 and include in cc.h */ -+#ifndef LWIP_TIMEVAL_PRIVATE -+#define LWIP_TIMEVAL_PRIVATE 1 -+#endif -+ -+#if LWIP_TIMEVAL_PRIVATE -+struct timeval { -+ long tv_sec; /* seconds */ -+ long tv_usec; /* and microseconds */ -+}; -+#endif /* LWIP_TIMEVAL_PRIVATE */ -+ -+#define lwip_socket_init() /* Compatibility define, no init needed. */ + /* If your port already typedef's sa_family_t, define SA_FAMILY_T_DEFINED + to prevent this code from redefining it. */ + #if !defined(sa_family_t) && !defined(SA_FAMILY_T_DEFINED) +@@ -526,9 +534,43 @@ + #endif /* LWIP_TIMEVAL_PRIVATE */ + + #define lwip_socket_init() /* Compatibility define, no init needed. */ +#else /* LWIP_LITEOS_COMPAT */ +#if LWIP_LITEOS_COMPAT +#ifndef TCP_KEEPALIVE @@ -21339,9 +4006,9 @@ diff -Nur a/lwip-2.1.2/src/include/lwip/sockets.h b/lwip-2.1.2/src/include/lwip/ +#endif /* SOCK_TYPE_MASK */ +#endif + -+void lwip_socket_thread_init(void); /* LWIP_NETCONN_SEM_PER_THREAD==1: initialize thread-local semaphore */ -+void lwip_socket_thread_cleanup(void); /* LWIP_NETCONN_SEM_PER_THREAD==1: destroy thread-local semaphore */ -+ + void lwip_socket_thread_init(void); /* LWIP_NETCONN_SEM_PER_THREAD==1: initialize thread-local semaphore */ + void lwip_socket_thread_cleanup(void); /* LWIP_NETCONN_SEM_PER_THREAD==1: destroy thread-local semaphore */ + +#if LWIP_IPV6 +#define LWIP_IS_IPPROTOCOL(protocol) ((protocol) == IPPROTO_IP || (protocol) == IPPROTO_IPV6 || (protocol) == 0) +#if PF_PACKET @@ -21357,38 +4024,23 @@ diff -Nur a/lwip-2.1.2/src/include/lwip/sockets.h b/lwip-2.1.2/src/include/lwip/ +#define LWIP_IS_VALID_DOMAIN(domain) ((domain) == AF_INET) || ((domain) == AF_INET6) +#endif +#endif -+#if LWIP_COMPAT_SOCKETS == 2 -+/* This helps code parsers/code completion by not having the COMPAT functions as defines */ -+#define lwip_accept accept -+#define lwip_bind bind -+#define lwip_shutdown shutdown -+#define lwip_getpeername getpeername -+#define lwip_getsockname getsockname -+#define lwip_setsockopt setsockopt -+#define lwip_getsockopt getsockopt -+#define lwip_close closesocket -+#define lwip_connect connect -+#define lwip_listen listen -+#define lwip_recv recv -+#define lwip_recvmsg recvmsg -+#define lwip_recvfrom recvfrom -+#define lwip_send send -+#define lwip_sendmsg sendmsg -+#define lwip_sendto sendto -+#define lwip_socket socket -+#if LWIP_SOCKET_SELECT -+#define lwip_select select -+#endif + #if LWIP_COMPAT_SOCKETS == 2 + /* This helps code parsers/code completion by not having the COMPAT functions as defines */ + #define lwip_accept accept +@@ -551,6 +593,9 @@ + #if LWIP_SOCKET_SELECT + #define lwip_select select + #endif + +#define lwip_gethostbyname(name) gethostbyname(name) + -+#if LWIP_SOCKET_POLL -+#define lwip_poll poll -+#endif -+#define lwip_ioctl ioctlsocket -+#define lwip_inet_ntop inet_ntop -+#define lwip_inet_pton inet_pton -+ + #if LWIP_SOCKET_POLL + #define lwip_poll poll + #endif +@@ -558,9 +603,18 @@ + #define lwip_inet_ntop inet_ntop + #define lwip_inet_pton inet_pton + +#if LWIP_DNS +#define lwip_gethostbyname(name) gethostbyname(name) +#define lwip_gethostbyname_r gethostbyname_r @@ -21397,138 +4049,25 @@ diff -Nur a/lwip-2.1.2/src/include/lwip/sockets.h b/lwip-2.1.2/src/include/lwip/ +#define lwip_getnameinfo getnameinfo +#endif + -+#if LWIP_POSIX_SOCKETS_IO_NAMES -+#define lwip_read read -+#define lwip_readv readv -+ -+#define lwip_write write -+#define lwip_writev writev -+#undef lwip_close -+#define lwip_close close -+#define closesocket(s) close(s) -+int fcntl(int s, int cmd, ...); -+#undef lwip_ioctl -+#define lwip_ioctl ioctl -+#define ioctlsocket ioctl -+#endif /* LWIP_POSIX_SOCKETS_IO_NAMES */ -+#endif /* LWIP_COMPAT_SOCKETS == 2 */ -+ -+int lwip_accept(int s, struct sockaddr *addr, socklen_t *addrlen); -+int lwip_bind(int s, const struct sockaddr *name, socklen_t namelen); -+int lwip_shutdown(int s, int how); -+int lwip_getpeername (int s, struct sockaddr *name, socklen_t *namelen); -+int lwip_getsockname (int s, struct sockaddr *name, socklen_t *namelen); -+int lwip_getsockopt (int s, int level, int optname, void *optval, socklen_t *optlen); -+int lwip_setsockopt (int s, int level, int optname, const void *optval, socklen_t optlen); -+ int lwip_close(int s); -+int lwip_connect(int s, const struct sockaddr *name, socklen_t namelen); -+int lwip_listen(int s, int backlog); -+ssize_t lwip_recv(int s, void *mem, size_t len, int flags); -+ssize_t lwip_read(int s, void *mem, size_t len); -+ssize_t lwip_readv(int s, const struct iovec *iov, int iovcnt); -+ssize_t lwip_recvfrom(int s, void *mem, size_t len, int flags, -+ struct sockaddr *from, socklen_t *fromlen); -+ssize_t lwip_recvmsg(int s, struct msghdr *message, int flags); -+ssize_t lwip_send(int s, const void *dataptr, size_t size, int flags); -+ssize_t lwip_sendmsg(int s, const struct msghdr *message, int flags); -+ssize_t lwip_sendto(int s, const void *dataptr, size_t size, int flags, -+ const struct sockaddr *to, socklen_t tolen); -+int lwip_socket(int domain, int type, int protocol); -+ssize_t lwip_write(int s, const void *dataptr, size_t size); -+ssize_t lwip_writev(int s, const struct iovec *iov, int iovcnt); -+#if LWIP_SOCKET_SELECT -+int lwip_select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset, -+ struct timeval *timeout); -+#endif -+#if LWIP_SOCKET_POLL -+int lwip_poll(struct pollfd *fds, nfds_t nfds, int timeout); -+#endif -+int lwip_ioctl(int s, long cmd, void *argp); -+int lwip_fcntl(int s, int cmd, int val); -+const char *lwip_inet_ntop(int af, const void *src, char *dst, socklen_t size); -+int lwip_inet_pton(int af, const char *src, void *dst); -+ -+#if LWIP_COMPAT_SOCKETS -+#if LWIP_COMPAT_SOCKETS != 2 -+/** @ingroup socket */ -+#define accept(s,addr,addrlen) lwip_accept(s,addr,addrlen) -+/** @ingroup socket */ -+#define bind(s,name,namelen) lwip_bind(s,name,namelen) -+/** @ingroup socket */ -+#define shutdown(s,how) lwip_shutdown(s,how) -+/** @ingroup socket */ -+#define getpeername(s,name,namelen) lwip_getpeername(s,name,namelen) -+/** @ingroup socket */ -+#define getsockname(s,name,namelen) lwip_getsockname(s,name,namelen) -+/** @ingroup socket */ -+#define setsockopt(s,level,optname,opval,optlen) lwip_setsockopt(s,level,optname,opval,optlen) -+/** @ingroup socket */ -+#define getsockopt(s,level,optname,opval,optlen) lwip_getsockopt(s,level,optname,opval,optlen) -+/** @ingroup socket */ -+#define closesocket(s) lwip_close(s) -+/** @ingroup socket */ -+#define connect(s,name,namelen) lwip_connect(s,name,namelen) -+/** @ingroup socket */ -+#define listen(s,backlog) lwip_listen(s,backlog) -+/** @ingroup socket */ -+#define recv(s,mem,len,flags) lwip_recv(s,mem,len,flags) -+/** @ingroup socket */ -+#define recvmsg(s,message,flags) lwip_recvmsg(s,message,flags) -+/** @ingroup socket */ -+#define recvfrom(s,mem,len,flags,from,fromlen) lwip_recvfrom(s,mem,len,flags,from,fromlen) -+/** @ingroup socket */ -+#define send(s,dataptr,size,flags) lwip_send(s,dataptr,size,flags) -+/** @ingroup socket */ -+#define sendmsg(s,message,flags) lwip_sendmsg(s,message,flags) -+/** @ingroup socket */ -+#define sendto(s,dataptr,size,flags,to,tolen) lwip_sendto(s,dataptr,size,flags,to,tolen) -+/** @ingroup socket */ -+#define socket(domain,type,protocol) lwip_socket(domain,type,protocol) -+#if LWIP_SOCKET_SELECT -+/** @ingroup socket */ -+#define select(maxfdp1,readset,writeset,exceptset,timeout) lwip_select(maxfdp1,readset,writeset,exceptset,timeout) -+#endif -+#if LWIP_SOCKET_POLL -+/** @ingroup socket */ -+#define poll(fds,nfds,timeout) lwip_poll(fds,nfds,timeout) -+#endif -+/** @ingroup socket */ -+#define ioctlsocket(s,cmd,argp) lwip_ioctl(s,cmd,argp) -+/** @ingroup socket */ -+#define inet_ntop(af,src,dst,size) lwip_inet_ntop(af,src,dst,size) -+/** @ingroup socket */ -+#define inet_pton(af,src,dst) lwip_inet_pton(af,src,dst) -+ -+#if LWIP_POSIX_SOCKETS_IO_NAMES -+/** @ingroup socket */ -+#define read(s,mem,len) lwip_read(s,mem,len) -+/** @ingroup socket */ -+#define readv(s,iov,iovcnt) lwip_readv(s,iov,iovcnt) -+/** @ingroup socket */ -+#define write(s,dataptr,len) lwip_write(s,dataptr,len) -+/** @ingroup socket */ -+#define writev(s,iov,iovcnt) lwip_writev(s,iov,iovcnt) -+/** @ingroup socket */ -+#define close(s) lwip_close(s) -+/** @ingroup socket */ -+#define fcntl(s,cmd,val) lwip_fcntl(s,cmd,val) -+/** @ingroup socket */ -+#define ioctl(s,cmd,argp) lwip_ioctl(s,cmd,argp) -+#endif /* LWIP_POSIX_SOCKETS_IO_NAMES */ -+#endif /* LWIP_COMPAT_SOCKETS != 2 */ -+ -+#endif /* LWIP_COMPAT_SOCKETS */ + #if LWIP_POSIX_SOCKETS_IO_NAMES + #define lwip_read read + #define lwip_readv readv + -+#ifdef __cplusplus -+} -+#endif + #define lwip_write write + #define lwip_writev writev + #undef lwip_close +@@ -682,7 +736,7 @@ + #ifdef __cplusplus + } + #endif +- +#endif -+#endif /* LWIP_SOCKET */ -+ -+#endif /* LWIP_HDR_SOCKETS_H */ + #endif /* LWIP_SOCKET */ + + #endif /* LWIP_HDR_SOCKETS_H */ diff -Nur a/lwip-2.1.2/src/include/netif/ifaddrs.h b/lwip-2.1.2/src/include/netif/ifaddrs.h --- a/lwip-2.1.2/src/include/netif/ifaddrs.h 1970-01-01 08:00:00.000000000 +0800 -+++ b/lwip-2.1.2/src/include/netif/ifaddrs.h 2021-04-27 18:56:55.440353467 +0800 ++++ b/lwip-2.1.2/src/include/netif/ifaddrs.h 2021-06-29 15:16:44.640898726 +0800 @@ -0,0 +1,307 @@ +/* + * Copyright (c) Huawei Technologies Co., Ltd. 2019-2020. All rights reserved. @@ -21838,8 +4377,8 @@ diff -Nur a/lwip-2.1.2/src/include/netif/ifaddrs.h b/lwip-2.1.2/src/include/neti +#endif /* (LWIP_IPV4 || LWIP_IPV6) && LWIP_SOCKET */ +#endif /* __LWIP_IFADDRS_H */ diff -Nur a/lwip-2.1.2/src/netif/ethernet.c b/lwip-2.1.2/src/netif/ethernet.c ---- a/lwip-2.1.2/src/netif/ethernet.c 2021-05-08 18:13:52.639621024 +0800 -+++ b/lwip-2.1.2/src/netif/ethernet.c 2021-04-27 18:56:55.444353467 +0800 +--- a/lwip-2.1.2/src/netif/ethernet.c 2021-06-29 15:16:18.812893324 +0800 ++++ b/lwip-2.1.2/src/netif/ethernet.c 2021-06-29 15:16:44.644898727 +0800 @@ -48,7 +48,7 @@ #include "lwip/etharp.h" #include "lwip/ip.h" -- Gitee