xref: /minix3/minix/lib/liblwip/dist/src/api/sockets.c (revision e4dbab1e5368dc2124168836ba46a7d3ff6414b0)
1 /**
2  * @file
3  * Sockets BSD-Like API module
4  *
5  * @defgroup socket Socket API
6  * @ingroup sequential_api
7  * BSD-style socket API.\n
8  * Thread-safe, to be called from non-TCPIP threads only.\n
9  * Can be activated by defining @ref LWIP_SOCKET to 1.\n
10  * Header is in posix/sys/socket.h\b
11  */
12 
13 /*
14  * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
15  * All rights reserved.
16  *
17  * Redistribution and use in source and binary forms, with or without modification,
18  * are permitted provided that the following conditions are met:
19  *
20  * 1. Redistributions of source code must retain the above copyright notice,
21  *    this list of conditions and the following disclaimer.
22  * 2. Redistributions in binary form must reproduce the above copyright notice,
23  *    this list of conditions and the following disclaimer in the documentation
24  *    and/or other materials provided with the distribution.
25  * 3. The name of the author may not be used to endorse or promote products
26  *    derived from this software without specific prior written permission.
27  *
28  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
29  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
30  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
31  * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
32  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
33  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
34  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
35  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
36  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
37  * OF SUCH DAMAGE.
38  *
39  * This file is part of the lwIP TCP/IP stack.
40  *
41  * Author: Adam Dunkels <adam@sics.se>
42  *
43  * Improved by Marc Boucher <marc@mbsi.ca> and David Haas <dhaas@alum.rpi.edu>
44  *
45  */
46 
47 #include "lwip/opt.h"
48 
49 #if LWIP_SOCKET /* don't build if not configured for use in lwipopts.h */
50 
51 #include "lwip/sockets.h"
52 #include "lwip/priv/sockets_priv.h"
53 #include "lwip/api.h"
54 #include "lwip/sys.h"
55 #include "lwip/igmp.h"
56 #include "lwip/inet.h"
57 #include "lwip/tcp.h"
58 #include "lwip/raw.h"
59 #include "lwip/udp.h"
60 #include "lwip/memp.h"
61 #include "lwip/pbuf.h"
62 #include "lwip/priv/tcpip_priv.h"
63 #if LWIP_CHECKSUM_ON_COPY
64 #include "lwip/inet_chksum.h"
65 #endif
66 
67 #include <string.h>
68 
69 /* If the netconn API is not required publicly, then we include the necessary
70    files here to get the implementation */
71 #if !LWIP_NETCONN
72 #undef LWIP_NETCONN
73 #define LWIP_NETCONN 1
74 #include "api_msg.c"
75 #include "api_lib.c"
76 #include "netbuf.c"
77 #undef LWIP_NETCONN
78 #define LWIP_NETCONN 0
79 #endif
80 
81 #if LWIP_IPV4
82 #define IP4ADDR_PORT_TO_SOCKADDR(sin, ipaddr, port) do { \
83       (sin)->sin_len = sizeof(struct sockaddr_in); \
84       (sin)->sin_family = AF_INET; \
85       (sin)->sin_port = lwip_htons((port)); \
86       inet_addr_from_ip4addr(&(sin)->sin_addr, ipaddr); \
87       memset((sin)->sin_zero, 0, SIN_ZERO_LEN); }while(0)
88 #define SOCKADDR4_TO_IP4ADDR_PORT(sin, ipaddr, port) do { \
89     inet_addr_to_ip4addr(ip_2_ip4(ipaddr), &((sin)->sin_addr)); \
90     (port) = lwip_ntohs((sin)->sin_port); }while(0)
91 #endif /* LWIP_IPV4 */
92 
93 #if LWIP_IPV6
94 #define IP6ADDR_PORT_TO_SOCKADDR(sin6, ipaddr, port) do { \
95       (sin6)->sin6_len = sizeof(struct sockaddr_in6); \
96       (sin6)->sin6_family = AF_INET6; \
97       (sin6)->sin6_port = lwip_htons((port)); \
98       (sin6)->sin6_flowinfo = 0; \
99       inet6_addr_from_ip6addr(&(sin6)->sin6_addr, ipaddr); \
100       (sin6)->sin6_scope_id = ip6_addr_zone(ipaddr); }while(0)
101 #define SOCKADDR6_TO_IP6ADDR_PORT(sin6, ipaddr, port) do { \
102     inet6_addr_to_ip6addr(ip_2_ip6(ipaddr), &((sin6)->sin6_addr)); \
103     if (ip6_addr_has_scope(ip_2_ip6(ipaddr), IP6_UNKNOWN)) { \
104       ip6_addr_set_zone(ip_2_ip6(ipaddr), (u8_t)((sin6)->sin6_scope_id)); \
105     } \
106     (port) = lwip_ntohs((sin6)->sin6_port); }while(0)
107 #endif /* LWIP_IPV6 */
108 
109 #if LWIP_IPV4 && LWIP_IPV6
110 static void sockaddr_to_ipaddr_port(const struct sockaddr* sockaddr, ip_addr_t* ipaddr, u16_t* port);
111 
112 #define IS_SOCK_ADDR_LEN_VALID(namelen)  (((namelen) == sizeof(struct sockaddr_in)) || \
113                                          ((namelen) == sizeof(struct sockaddr_in6)))
114 #define IS_SOCK_ADDR_TYPE_VALID(name)    (((name)->sa_family == AF_INET) || \
115                                          ((name)->sa_family == AF_INET6))
116 #define SOCK_ADDR_TYPE_MATCH(name, sock) \
117        ((((name)->sa_family == AF_INET) && !(NETCONNTYPE_ISIPV6((sock)->conn->type))) || \
118        (((name)->sa_family == AF_INET6) && (NETCONNTYPE_ISIPV6((sock)->conn->type))))
119 #define IPADDR_PORT_TO_SOCKADDR(sockaddr, ipaddr, port) do { \
120     if (IP_IS_V6(ipaddr)) { \
121       IP6ADDR_PORT_TO_SOCKADDR((struct sockaddr_in6*)(void*)(sockaddr), ip_2_ip6(ipaddr), port); \
122     } else { \
123       IP4ADDR_PORT_TO_SOCKADDR((struct sockaddr_in*)(void*)(sockaddr), ip_2_ip4(ipaddr), port); \
124     } } while(0)
125 #define SOCKADDR_TO_IPADDR_PORT(sockaddr, ipaddr, port) sockaddr_to_ipaddr_port(sockaddr, ipaddr, &(port))
126 #define DOMAIN_TO_NETCONN_TYPE(domain, type) (((domain) == AF_INET) ? \
127   (type) : (enum netconn_type)((type) | NETCONN_TYPE_IPV6))
128 #elif LWIP_IPV6 /* LWIP_IPV4 && LWIP_IPV6 */
129 #define IS_SOCK_ADDR_LEN_VALID(namelen)  ((namelen) == sizeof(struct sockaddr_in6))
130 #define IS_SOCK_ADDR_TYPE_VALID(name)    ((name)->sa_family == AF_INET6)
131 #define SOCK_ADDR_TYPE_MATCH(name, sock) 1
132 #define IPADDR_PORT_TO_SOCKADDR(sockaddr, ipaddr, port) \
133         IP6ADDR_PORT_TO_SOCKADDR((struct sockaddr_in6*)(void*)(sockaddr), ip_2_ip6(ipaddr), port)
134 #define SOCKADDR_TO_IPADDR_PORT(sockaddr, ipaddr, port) \
135         SOCKADDR6_TO_IP6ADDR_PORT((const struct sockaddr_in6*)(const void*)(sockaddr), ipaddr, port)
136 #define DOMAIN_TO_NETCONN_TYPE(domain, netconn_type) (netconn_type)
137 #else /*-> LWIP_IPV4: LWIP_IPV4 && LWIP_IPV6 */
138 #define IS_SOCK_ADDR_LEN_VALID(namelen)  ((namelen) == sizeof(struct sockaddr_in))
139 #define IS_SOCK_ADDR_TYPE_VALID(name)    ((name)->sa_family == AF_INET)
140 #define SOCK_ADDR_TYPE_MATCH(name, sock) 1
141 #define IPADDR_PORT_TO_SOCKADDR(sockaddr, ipaddr, port) \
142         IP4ADDR_PORT_TO_SOCKADDR((struct sockaddr_in*)(void*)(sockaddr), ip_2_ip4(ipaddr), port)
143 #define SOCKADDR_TO_IPADDR_PORT(sockaddr, ipaddr, port) \
144         SOCKADDR4_TO_IP4ADDR_PORT((const struct sockaddr_in*)(const void*)(sockaddr), ipaddr, port)
145 #define DOMAIN_TO_NETCONN_TYPE(domain, netconn_type) (netconn_type)
146 #endif /* LWIP_IPV6 */
147 
148 #define IS_SOCK_ADDR_TYPE_VALID_OR_UNSPEC(name)    (((name)->sa_family == AF_UNSPEC) || \
149                                                     IS_SOCK_ADDR_TYPE_VALID(name))
150 #define SOCK_ADDR_TYPE_MATCH_OR_UNSPEC(name, sock) (((name)->sa_family == AF_UNSPEC) || \
151                                                     SOCK_ADDR_TYPE_MATCH(name, sock))
152 #define IS_SOCK_ADDR_ALIGNED(name)      ((((mem_ptr_t)(name)) % 4) == 0)
153 
154 
155 #define LWIP_SOCKOPT_CHECK_OPTLEN(optlen, opttype) do { if ((optlen) < sizeof(opttype)) { return EINVAL; }}while(0)
156 #define LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, optlen, opttype) do { \
157   LWIP_SOCKOPT_CHECK_OPTLEN(optlen, opttype); \
158   if ((sock)->conn == NULL) { return EINVAL; } }while(0)
159 #define LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, optlen, opttype) do { \
160   LWIP_SOCKOPT_CHECK_OPTLEN(optlen, opttype); \
161   if (((sock)->conn == NULL) || ((sock)->conn->pcb.tcp == NULL)) { return EINVAL; } }while(0)
162 #define LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, opttype, netconntype) do { \
163   LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, optlen, opttype); \
164   if (NETCONNTYPE_GROUP(netconn_type((sock)->conn)) != netconntype) { return ENOPROTOOPT; } }while(0)
165 
166 
167 #define LWIP_SETGETSOCKOPT_DATA_VAR_REF(name)     API_VAR_REF(name)
168 #define LWIP_SETGETSOCKOPT_DATA_VAR_DECLARE(name) API_VAR_DECLARE(struct lwip_setgetsockopt_data, name)
169 #define LWIP_SETGETSOCKOPT_DATA_VAR_FREE(name)    API_VAR_FREE(MEMP_SOCKET_SETGETSOCKOPT_DATA, name)
170 #if LWIP_MPU_COMPATIBLE
171 #define LWIP_SETGETSOCKOPT_DATA_VAR_ALLOC(name, sock) do { \
172   name = (struct lwip_setgetsockopt_data *)memp_malloc(MEMP_SOCKET_SETGETSOCKOPT_DATA); \
173   if (name == NULL) { \
174     sock_set_errno(sock, ENOMEM); \
175     return -1; \
176   } }while(0)
177 #else /* LWIP_MPU_COMPATIBLE */
178 #define LWIP_SETGETSOCKOPT_DATA_VAR_ALLOC(name, sock)
179 #endif /* LWIP_MPU_COMPATIBLE */
180 
181 #if LWIP_SO_SNDRCVTIMEO_NONSTANDARD
182 #define LWIP_SO_SNDRCVTIMEO_OPTTYPE int
183 #define LWIP_SO_SNDRCVTIMEO_SET(optval, val) (*(int *)(optval) = (val))
184 #define LWIP_SO_SNDRCVTIMEO_GET_MS(optval)   ((s32_t)*(const int*)(optval))
185 #else
186 #define LWIP_SO_SNDRCVTIMEO_OPTTYPE struct timeval
187 #define LWIP_SO_SNDRCVTIMEO_SET(optval, val)  do { \
188   s32_t loc = (val); \
189   ((struct timeval *)(optval))->tv_sec = (loc) / 1000U; \
190   ((struct timeval *)(optval))->tv_usec = ((loc) % 1000U) * 1000U; }while(0)
191 #define LWIP_SO_SNDRCVTIMEO_GET_MS(optval) ((((const struct timeval *)(optval))->tv_sec * 1000U) + (((const struct timeval *)(optval))->tv_usec / 1000U))
192 #endif
193 
194 #define NUM_SOCKETS MEMP_NUM_NETCONN
195 
196 /** This is overridable for the rare case where more than 255 threads
197  * select on the same socket...
198  */
199 #ifndef SELWAIT_T
200 #define SELWAIT_T u8_t
201 #endif
202 
203 union lwip_sock_lastdata {
204   struct netbuf *netbuf;
205   struct pbuf *pbuf;
206 };
207 
208 /** Contains all internal pointers and states used for a socket */
209 struct lwip_sock {
210   /** sockets currently are built on netconns, each socket has one netconn */
211   struct netconn *conn;
212   /** last error that occurred on this socket */
213   int err;
214   /** data that was left from the previous read */
215   union lwip_sock_lastdata lastdata;
216 #if LWIP_SOCKET_SELECT
217   /** number of times data was received, set by event_callback(),
218       tested by the receive and select functions */
219   s16_t rcvevent;
220   /** number of times data was ACKed (free send buffer), set by event_callback(),
221       tested by select */
222   u16_t sendevent;
223   /** error happened for this socket, set by event_callback(), tested by select */
224   u16_t errevent;
225   /** counter of how many threads are waiting for this socket using select */
226   SELWAIT_T select_waiting;
227 #endif /* LWIP_SOCKET_SELECT */
228 #if LWIP_NETCONN_FULLDUPLEX
229   /* counter of how many threads are using a struct lwip_sock (not the 'int') */
230   u8_t fd_used;
231   /* status of pending close/delete actions */
232   u8_t fd_free_pending;
233 #define LWIP_SOCK_FD_FREE_TCP  1
234 #define LWIP_SOCK_FD_FREE_FREE 2
235 #endif
236 };
237 
238 #if LWIP_NETCONN_SEM_PER_THREAD
239 #define SELECT_SEM_T        sys_sem_t*
240 #define SELECT_SEM_PTR(sem) (sem)
241 #else /* LWIP_NETCONN_SEM_PER_THREAD */
242 #define SELECT_SEM_T        sys_sem_t
243 #define SELECT_SEM_PTR(sem) (&(sem))
244 #endif /* LWIP_NETCONN_SEM_PER_THREAD */
245 
246 /** Description for a task waiting in select */
247 struct lwip_select_cb {
248   /** Pointer to the next waiting task */
249   struct lwip_select_cb *next;
250   /** Pointer to the previous waiting task */
251   struct lwip_select_cb *prev;
252   /** readset passed to select */
253   fd_set *readset;
254   /** writeset passed to select */
255   fd_set *writeset;
256   /** unimplemented: exceptset passed to select */
257   fd_set *exceptset;
258   /** don't signal the same semaphore twice: set to 1 when signalled */
259   int sem_signalled;
260   /** semaphore to wake up a task waiting for select */
261   SELECT_SEM_T sem;
262 };
263 
264 /** A struct sockaddr replacement that has the same alignment as sockaddr_in/
265  *  sockaddr_in6 if instantiated.
266  */
267 union sockaddr_aligned {
268    struct sockaddr sa;
269 #if LWIP_IPV6
270    struct sockaddr_in6 sin6;
271 #endif /* LWIP_IPV6 */
272 #if LWIP_IPV4
273    struct sockaddr_in sin;
274 #endif /* LWIP_IPV4 */
275 };
276 
277 #if LWIP_IGMP
278 /* Define the number of IPv4 multicast memberships, default is one per socket */
279 #ifndef LWIP_SOCKET_MAX_MEMBERSHIPS
280 #define LWIP_SOCKET_MAX_MEMBERSHIPS NUM_SOCKETS
281 #endif
282 
283 /* This is to keep track of IP_ADD_MEMBERSHIP calls to drop the membership when
284    a socket is closed */
285 struct lwip_socket_multicast_pair {
286   /** the socket */
287   struct lwip_sock* sock;
288   /** the interface address */
289   ip4_addr_t if_addr;
290   /** the group address */
291   ip4_addr_t multi_addr;
292 };
293 
294 struct lwip_socket_multicast_pair socket_ipv4_multicast_memberships[LWIP_SOCKET_MAX_MEMBERSHIPS];
295 
296 static int  lwip_socket_register_membership(int s, const ip4_addr_t *if_addr, const ip4_addr_t *multi_addr);
297 static void lwip_socket_unregister_membership(int s, const ip4_addr_t *if_addr, const ip4_addr_t *multi_addr);
298 static void lwip_socket_drop_registered_memberships(int s);
299 #endif /* LWIP_IGMP */
300 
301 /** The global array of available sockets */
302 static struct lwip_sock sockets[NUM_SOCKETS];
303 /** The global list of tasks waiting for select */
304 static struct lwip_select_cb *select_cb_list;
305 /** This counter is increased from lwip_select when the list is changed
306     and checked in event_callback to see if it has changed. */
307 static volatile int select_cb_ctr;
308 
309 #define sock_set_errno(sk, e) do { \
310   const int sockerr = (e); \
311   sk->err = sockerr; \
312   set_errno(sockerr); \
313 } while (0)
314 
315 /* Forward declaration of some functions */
316 #if LWIP_SOCKET_SELECT
317 static void event_callback(struct netconn *conn, enum netconn_evt evt, u16_t len);
318 #define DEFAULT_SOCKET_EVENTCB event_callback
319 #else
320 #define DEFAULT_SOCKET_EVENTCB NULL
321 #endif
322 #if !LWIP_TCPIP_CORE_LOCKING
323 static void lwip_getsockopt_callback(void *arg);
324 static void lwip_setsockopt_callback(void *arg);
325 #endif
326 static int lwip_getsockopt_impl(int s, int level, int optname, void *optval, socklen_t *optlen);
327 static int lwip_setsockopt_impl(int s, int level, int optname, const void *optval, socklen_t optlen);
328 static void free_socket(struct lwip_sock *sock, int is_tcp);
329 
330 #if LWIP_IPV4 && LWIP_IPV6
331 static void
332 sockaddr_to_ipaddr_port(const struct sockaddr* sockaddr, ip_addr_t* ipaddr, u16_t* port)
333 {
334   if ((sockaddr->sa_family) == AF_INET6) {
335     SOCKADDR6_TO_IP6ADDR_PORT((const struct sockaddr_in6*)(const void*)(sockaddr), ipaddr, *port);
336     ipaddr->type = IPADDR_TYPE_V6;
337   } else {
338     SOCKADDR4_TO_IP4ADDR_PORT((const struct sockaddr_in*)(const void*)(sockaddr), ipaddr, *port);
339     ipaddr->type = IPADDR_TYPE_V4;
340   }
341 }
342 #endif /* LWIP_IPV4 && LWIP_IPV6 */
343 
344 /** LWIP_NETCONN_SEM_PER_THREAD==1: initialize thread-local semaphore */
345 void
346 lwip_socket_thread_init(void)
347 {
348   netconn_thread_init();
349 }
350 
351 /** LWIP_NETCONN_SEM_PER_THREAD==1: destroy thread-local semaphore */
352 void
353 lwip_socket_thread_cleanup(void)
354 {
355   netconn_thread_cleanup();
356 }
357 
358 #if LWIP_NETCONN_FULLDUPLEX
359 /* Thread-safe increment of sock->fd_used, with overflow check */
360 static void
361 sock_inc_used(struct lwip_sock *sock)
362 {
363   LWIP_ASSERT("sock != NULL", sock != NULL);
364   SYS_ARCH_INC(sock->fd_used, 1);
365   LWIP_ASSERT("sock->fd_used != 0", sock->fd_used != 0);
366 }
367 
368 /* In full-duplex mode,sock->fd_used != 0 prevents a socket descriptor from being
369  * released (and possibly reused) when used from more than one thread
370  * (e.g. read-while-write or close-while-write, etc)
371  * This function is called at the end of functions using (try)get_socket*().
372  */
373 static void
374 done_socket(struct lwip_sock *sock)
375 {
376   SYS_ARCH_DECL_PROTECT(lev);
377 
378   LWIP_ASSERT("sock != NULL", sock != NULL);
379 
380   SYS_ARCH_PROTECT(lev);
381   LWIP_ASSERT("sock->fd_used > 0", sock->fd_used > 0);
382   if (--sock->fd_used == 0) {
383     if (sock->fd_free_pending) {
384       /* free the socket */
385       sock->fd_used = 1;
386       free_socket(sock, sock->fd_free_pending & LWIP_SOCK_FD_FREE_TCP);
387     }
388   }
389   SYS_ARCH_UNPROTECT(lev);
390 }
391 #else /* LWIP_NETCONN_FULLDUPLEX */
392 #define sock_inc_used(sock)
393 #define done_socket(sock)
394 #endif /* LWIP_NETCONN_FULLDUPLEX */
395 
396 /* Translate a socket 'int' into a pointer (only fails if the index is invalid) */
397 static struct lwip_sock *
398 tryget_socket_unconn(int fd)
399 {
400   int s = fd - LWIP_SOCKET_OFFSET;
401   if ((s < 0) || (s >= NUM_SOCKETS)) {
402     LWIP_DEBUGF(SOCKETS_DEBUG, ("tryget_socket_unconn(%d): invalid\n", fd));
403     return NULL;
404   }
405   sock_inc_used(&sockets[s]);
406   return &sockets[s];
407 }
408 
409 /**
410  * Same as get_socket but doesn't set errno
411  *
412  * @param fd externally used socket index
413  * @return struct lwip_sock for the socket or NULL if not found
414  */
415 static struct lwip_sock *
416 tryget_socket(int fd)
417 {
418   struct lwip_sock *sock = tryget_socket_unconn(fd);
419   if (sock != NULL) {
420     if (sock->conn) {
421       return sock;
422     }
423     done_socket(sock);
424   }
425   return NULL;
426 }
427 
428 /**
429  * Map a externally used socket index to the internal socket representation.
430  *
431  * @param fd externally used socket index
432  * @return struct lwip_sock for the socket or NULL if not found
433  */
434 static struct lwip_sock *
435 get_socket(int fd)
436 {
437   struct lwip_sock *sock = tryget_socket(fd);
438   if (!sock) {
439     if ((fd < LWIP_SOCKET_OFFSET) || (fd >= (LWIP_SOCKET_OFFSET + NUM_SOCKETS))) {
440       LWIP_DEBUGF(SOCKETS_DEBUG, ("get_socket(%d): invalid\n", fd));
441     }
442     set_errno(EBADF);
443     return NULL;
444   }
445   return sock;
446 }
447 
448 /**
449  * Allocate a new socket for a given netconn.
450  *
451  * @param newconn the netconn for which to allocate a socket
452  * @param accepted 1 if socket has been created by accept(),
453  *                 0 if socket has been created by socket()
454  * @return the index of the new socket; -1 on error
455  */
456 static int
457 alloc_socket(struct netconn *newconn, int accepted)
458 {
459   int i;
460   SYS_ARCH_DECL_PROTECT(lev);
461   LWIP_UNUSED_ARG(accepted);
462 
463   /* allocate a new socket identifier */
464   for (i = 0; i < NUM_SOCKETS; ++i) {
465     /* Protect socket array */
466     SYS_ARCH_PROTECT(lev);
467     if (!sockets[i].conn) {
468 #if LWIP_NETCONN_FULLDUPLEX
469       if (sockets[i].fd_used) {
470         continue;
471       }
472       sockets[i].fd_used    = 1;
473       sockets[i].fd_free_pending = 0;
474 #endif
475       sockets[i].conn       = newconn;
476       /* The socket is not yet known to anyone, so no need to protect
477          after having marked it as used. */
478       SYS_ARCH_UNPROTECT(lev);
479       sockets[i].lastdata.pbuf = NULL;
480 #if LWIP_SOCKET_SELECT
481       LWIP_ASSERT("sockets[i].select_waiting == 0", sockets[i].select_waiting == 0);
482       sockets[i].rcvevent   = 0;
483       /* TCP sendbuf is empty, but the socket is not yet writable until connected
484        * (unless it has been created by accept()). */
485       sockets[i].sendevent  = (NETCONNTYPE_GROUP(newconn->type) == NETCONN_TCP ? (accepted != 0) : 1);
486       sockets[i].errevent   = 0;
487 #endif /* LWIP_SOCKET_SELECT */
488       sockets[i].err        = 0;
489       return i + LWIP_SOCKET_OFFSET;
490     }
491     SYS_ARCH_UNPROTECT(lev);
492   }
493   return -1;
494 }
495 
496 /** Free a socket. The socket's netconn must have been
497  * delete before!
498  *
499  * @param sock the socket to free
500  * @param is_tcp != 0 for TCP sockets, used to free lastdata
501  */
502 static void
503 free_socket(struct lwip_sock *sock, int is_tcp)
504 {
505   union lwip_sock_lastdata lastdata;
506   SYS_ARCH_DECL_PROTECT(lev);
507 
508   /* Protect socket array */
509   SYS_ARCH_PROTECT(lev);
510 
511 #if LWIP_NETCONN_FULLDUPLEX
512   LWIP_ASSERT("sock->fd_used > 0", sock->fd_used > 0);
513   if (--sock->fd_used > 0) {
514     sock->fd_free_pending = LWIP_SOCK_FD_FREE_FREE | is_tcp ? LWIP_SOCK_FD_FREE_TCP : 0;
515     SYS_ARCH_UNPROTECT(lev);
516     return;
517   }
518 #endif
519 
520   lastdata         = sock->lastdata;
521   sock->lastdata.pbuf = NULL;
522   sock->err        = 0;
523   sock->conn = NULL;
524   SYS_ARCH_UNPROTECT(lev);
525   /* don't use 'sock' after this line, as another task might have allocated it */
526 
527   if (lastdata.pbuf != NULL) {
528     if (is_tcp) {
529       pbuf_free(lastdata.pbuf);
530     } else {
531       netbuf_delete(lastdata.netbuf);
532     }
533   }
534 }
535 
536 /* Below this, the well-known socket functions are implemented.
537  * Use google.com or opengroup.org to get a good description :-)
538  *
539  * Exceptions are documented!
540  */
541 
542 int
543 lwip_accept(int s, struct sockaddr *addr, socklen_t *addrlen)
544 {
545   struct lwip_sock *sock, *nsock;
546   struct netconn *newconn;
547   ip_addr_t naddr;
548   u16_t port = 0;
549   int newsock;
550   err_t err;
551   int recvevent;
552   SYS_ARCH_DECL_PROTECT(lev);
553 
554   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d)...\n", s));
555   sock = get_socket(s);
556   if (!sock) {
557     return -1;
558   }
559 
560   /* wait for a new connection */
561   err = netconn_accept(sock->conn, &newconn);
562   if (err != ERR_OK) {
563     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d): netconn_acept failed, err=%d\n", s, err));
564     if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_TCP) {
565       sock_set_errno(sock, EOPNOTSUPP);
566     } else if (err == ERR_CLSD) {
567       sock_set_errno(sock, EINVAL);
568     } else {
569       sock_set_errno(sock, err_to_errno(err));
570     }
571     done_socket(sock);
572     return -1;
573   }
574   LWIP_ASSERT("newconn != NULL", newconn != NULL);
575 
576   newsock = alloc_socket(newconn, 1);
577   if (newsock == -1) {
578     netconn_delete(newconn);
579     sock_set_errno(sock, ENFILE);
580     done_socket(sock);
581     return -1;
582   }
583   LWIP_ASSERT("invalid socket index", (newsock >= LWIP_SOCKET_OFFSET) && (newsock < NUM_SOCKETS + LWIP_SOCKET_OFFSET));
584   nsock = &sockets[newsock - LWIP_SOCKET_OFFSET];
585 
586   /* See event_callback: If data comes in right away after an accept, even
587    * though the server task might not have created a new socket yet.
588    * In that case, newconn->socket is counted down (newconn->socket--),
589    * so nsock->rcvevent is >= 1 here!
590    */
591   SYS_ARCH_PROTECT(lev);
592   recvevent = (s16_t)(-1 - newconn->socket);
593   newconn->socket = newsock;
594   SYS_ARCH_UNPROTECT(lev);
595 
596   if (newconn->callback) {
597     while(recvevent > 0) {
598       recvevent--;
599       newconn->callback(newconn, NETCONN_EVT_RCVPLUS, 0);
600     }
601   }
602 
603   /* Note that POSIX only requires us to check addr is non-NULL. addrlen must
604    * not be NULL if addr is valid.
605    */
606   if ((addr != NULL) && (addrlen != NULL)) {
607     union sockaddr_aligned tempaddr;
608     /* get the IP address and port of the remote host */
609     err = netconn_peer(newconn, &naddr, &port);
610     if (err != ERR_OK) {
611       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d): netconn_peer failed, err=%d\n", s, err));
612       netconn_delete(newconn);
613       free_socket(nsock, 1);
614       sock_set_errno(sock, err_to_errno(err));
615       done_socket(sock);
616       return -1;
617     }
618 
619     IPADDR_PORT_TO_SOCKADDR(&tempaddr, &naddr, port);
620     if (*addrlen > tempaddr.sa.sa_len) {
621       *addrlen = tempaddr.sa.sa_len;
622     }
623     MEMCPY(addr, &tempaddr, *addrlen);
624 
625     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d) returning new sock=%d addr=", s, newsock));
626     ip_addr_debug_print_val(SOCKETS_DEBUG, naddr);
627     LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F"\n", port));
628   } else {
629     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d) returning new sock=%d", s, newsock));
630   }
631 
632   sock_set_errno(sock, 0);
633   done_socket(sock);
634   done_socket(nsock);
635   return newsock;
636 }
637 
638 int
639 lwip_bind(int s, const struct sockaddr *name, socklen_t namelen)
640 {
641   struct lwip_sock *sock;
642   ip_addr_t local_addr;
643   u16_t local_port;
644   err_t err;
645 
646   sock = get_socket(s);
647   if (!sock) {
648     return -1;
649   }
650 
651   if (!SOCK_ADDR_TYPE_MATCH(name, sock)) {
652     /* sockaddr does not match socket type (IPv4/IPv6) */
653     sock_set_errno(sock, err_to_errno(ERR_VAL));
654     done_socket(sock);
655     return -1;
656   }
657 
658   /* check size, family and alignment of 'name' */
659   LWIP_ERROR("lwip_bind: invalid address", (IS_SOCK_ADDR_LEN_VALID(namelen) &&
660              IS_SOCK_ADDR_TYPE_VALID(name) && IS_SOCK_ADDR_ALIGNED(name)),
661              sock_set_errno(sock, err_to_errno(ERR_ARG)); return -1;);
662   LWIP_UNUSED_ARG(namelen);
663 
664   SOCKADDR_TO_IPADDR_PORT(name, &local_addr, local_port);
665   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d, addr=", s));
666   ip_addr_debug_print_val(SOCKETS_DEBUG, local_addr);
667   LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F")\n", local_port));
668 
669 #if LWIP_IPV4 && LWIP_IPV6
670   /* Dual-stack: Unmap IPv4 mapped IPv6 addresses */
671   if (IP_IS_V6_VAL(local_addr) && ip6_addr_isipv4mappedipv6(ip_2_ip6(&local_addr))) {
672     unmap_ipv4_mapped_ipv6(ip_2_ip4(&local_addr), ip_2_ip6(&local_addr));
673     IP_SET_TYPE_VAL(local_addr, IPADDR_TYPE_V4);
674   }
675 #endif /* LWIP_IPV4 && LWIP_IPV6 */
676 
677   err = netconn_bind(sock->conn, &local_addr, local_port);
678 
679   if (err != ERR_OK) {
680     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d) failed, err=%d\n", s, err));
681     sock_set_errno(sock, err_to_errno(err));
682     done_socket(sock);
683     return -1;
684   }
685 
686   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d) succeeded\n", s));
687   sock_set_errno(sock, 0);
688   done_socket(sock);
689   return 0;
690 }
691 
692 int
693 lwip_close(int s)
694 {
695   struct lwip_sock *sock;
696   int is_tcp = 0;
697   err_t err;
698 
699   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_close(%d)\n", s));
700 
701   sock = get_socket(s);
702   if (!sock) {
703     return -1;
704   }
705 
706   if (sock->conn != NULL) {
707     is_tcp = NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP;
708   } else {
709     LWIP_ASSERT("sock->lastdata == NULL", sock->lastdata.pbuf == NULL);
710   }
711 
712 #if LWIP_IGMP
713   /* drop all possibly joined IGMP memberships */
714   lwip_socket_drop_registered_memberships(s);
715 #endif /* LWIP_IGMP */
716 
717   err = netconn_delete(sock->conn);
718   if (err != ERR_OK) {
719     sock_set_errno(sock, err_to_errno(err));
720     done_socket(sock);
721     return -1;
722   }
723 
724   free_socket(sock, is_tcp);
725   set_errno(0);
726   return 0;
727 }
728 
729 int
730 lwip_connect(int s, const struct sockaddr *name, socklen_t namelen)
731 {
732   struct lwip_sock *sock;
733   err_t err;
734 
735   sock = get_socket(s);
736   if (!sock) {
737     return -1;
738   }
739 
740   if (!SOCK_ADDR_TYPE_MATCH_OR_UNSPEC(name, sock)) {
741     /* sockaddr does not match socket type (IPv4/IPv6) */
742     sock_set_errno(sock, err_to_errno(ERR_VAL));
743     done_socket(sock);
744     return -1;
745   }
746 
747   LWIP_UNUSED_ARG(namelen);
748   if (name->sa_family == AF_UNSPEC) {
749     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d, AF_UNSPEC)\n", s));
750     err = netconn_disconnect(sock->conn);
751   } else {
752     ip_addr_t remote_addr;
753     u16_t remote_port;
754 
755     /* check size, family and alignment of 'name' */
756     LWIP_ERROR("lwip_connect: invalid address", IS_SOCK_ADDR_LEN_VALID(namelen) &&
757                IS_SOCK_ADDR_TYPE_VALID_OR_UNSPEC(name) && IS_SOCK_ADDR_ALIGNED(name),
758                sock_set_errno(sock, err_to_errno(ERR_ARG)); return -1;);
759 
760     SOCKADDR_TO_IPADDR_PORT(name, &remote_addr, remote_port);
761     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d, addr=", s));
762     ip_addr_debug_print_val(SOCKETS_DEBUG, remote_addr);
763     LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F")\n", remote_port));
764 
765 #if LWIP_IPV4 && LWIP_IPV6
766     /* Dual-stack: Unmap IPv4 mapped IPv6 addresses */
767     if (IP_IS_V6_VAL(remote_addr) && ip6_addr_isipv4mappedipv6(ip_2_ip6(&remote_addr))) {
768       unmap_ipv4_mapped_ipv6(ip_2_ip4(&remote_addr), ip_2_ip6(&remote_addr));
769       IP_SET_TYPE_VAL(remote_addr, IPADDR_TYPE_V4);
770     }
771 #endif /* LWIP_IPV4 && LWIP_IPV6 */
772 
773     err = netconn_connect(sock->conn, &remote_addr, remote_port);
774   }
775 
776   if (err != ERR_OK) {
777     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d) failed, err=%d\n", s, err));
778     sock_set_errno(sock, err_to_errno(err));
779     done_socket(sock);
780     return -1;
781   }
782 
783   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d) succeeded\n", s));
784   sock_set_errno(sock, 0);
785   done_socket(sock);
786   return 0;
787 }
788 
789 /**
790  * Set a socket into listen mode.
791  * The socket may not have been used for another connection previously.
792  *
793  * @param s the socket to set to listening mode
794  * @param backlog (ATTENTION: needs TCP_LISTEN_BACKLOG=1)
795  * @return 0 on success, non-zero on failure
796  */
797 int
798 lwip_listen(int s, int backlog)
799 {
800   struct lwip_sock *sock;
801   err_t err;
802 
803   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_listen(%d, backlog=%d)\n", s, backlog));
804 
805   sock = get_socket(s);
806   if (!sock) {
807     return -1;
808   }
809 
810   /* limit the "backlog" parameter to fit in an u8_t */
811   backlog = LWIP_MIN(LWIP_MAX(backlog, 0), 0xff);
812 
813   err = netconn_listen_with_backlog(sock->conn, (u8_t)backlog);
814 
815   if (err != ERR_OK) {
816     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_listen(%d) failed, err=%d\n", s, err));
817     if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_TCP) {
818       sock_set_errno(sock, EOPNOTSUPP);
819     } else {
820       sock_set_errno(sock, err_to_errno(err));
821     }
822     done_socket(sock);
823     return -1;
824   }
825 
826   sock_set_errno(sock, 0);
827   done_socket(sock);
828   return 0;
829 }
830 
831 /* Helper function to loop over receiving pbufs from netconn
832  * until "len" bytes are received or we're otherwise done.
833  */
834 static int
835 lwip_recv_tcp(struct lwip_sock *sock, void *mem, size_t len, int flags)
836 {
837   u8_t apiflags = NETCONN_NOAUTORCVD;
838   int recvd = 0;
839   int recv_left = len;
840 
841   LWIP_ASSERT("no socket given", sock != NULL);
842   LWIP_ASSERT("this should be checked internally", NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP);
843 
844   if (flags & MSG_DONTWAIT) {
845     apiflags = NETCONN_DONTBLOCK;
846   } else {
847     apiflags = 0;
848   }
849 
850   do {
851     struct pbuf *p;
852     err_t err;
853     u16_t copylen;
854 
855     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recv_tcp: top while sock->lastdata=%p\n", (void*)sock->lastdata.pbuf));
856     /* Check if there is data left from the last recv operation. */
857     if (sock->lastdata.pbuf) {
858       p = sock->lastdata.pbuf;
859     } else {
860       /* No data was left from the previous operation, so we try to get
861          some from the network. */
862       err = netconn_recv_tcp_pbuf_flags(sock->conn, &p, apiflags);
863       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recv_tcp: netconn_recv err=%d, pbuf=%p\n",
864         err, (void*)p));
865 
866       if (err != ERR_OK) {
867         if (recvd > 0) {
868           /* already received data, return that (this trusts in getting the same error from
869              netconn layer again next time netconn_recv is called) */
870           if (err == ERR_CLSD) {
871             /* closed but already received data, ensure select gets the FIN, too */
872             if (sock->conn->callback != NULL) {
873               sock->conn->callback(sock->conn, NETCONN_EVT_RCVPLUS, 0);
874             }
875           }
876           goto lwip_recv_tcp_done;
877         }
878         /* We should really do some error checking here. */
879         LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recv_tcp: p == NULL, error is \"%s\"!\n",
880           lwip_strerr(err)));
881         sock_set_errno(sock, err_to_errno(err));
882         if (err == ERR_CLSD) {
883           return 0;
884         } else {
885           return -1;
886         }
887       }
888       LWIP_ASSERT("p != NULL", p != NULL);
889       sock->lastdata.pbuf = p;
890     }
891 
892     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recv_tcp: buflen=%"U16_F" recv_left=%d off=%d\n",
893        p->tot_len, recv_left, recvd));
894 
895     if (recv_left > p->tot_len) {
896       copylen = p->tot_len;
897     } else {
898       copylen = (u16_t)recv_left;
899     }
900 
901     /* copy the contents of the received buffer into
902     the supplied memory pointer mem */
903     pbuf_copy_partial(p, (u8_t*)mem + recvd, copylen, 0);
904 
905     recvd += copylen;
906 
907     /* TCP combines multiple pbufs for one recv */
908     LWIP_ASSERT("invalid copylen, len would underflow", recv_left >= copylen);
909     recv_left -= copylen;
910 
911     /* Unless we peek the incoming message... */
912     if ((flags & MSG_PEEK) == 0) {
913       /* ... check if there is data left in the pbuf */
914       LWIP_ASSERT("invalid copylen", p->tot_len >= copylen);
915       if (p->tot_len - copylen > 0) {
916         /* If so, it should be saved in the sock structure for the next recv call.
917            We store the pbuf but hide/free the consumed data: */
918         sock->lastdata.pbuf = pbuf_free_header(p, copylen);
919         LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recv_tcp: lastdata now pbuf=%p\n", (void*)sock->lastdata.pbuf));
920       } else {
921         sock->lastdata.pbuf = NULL;
922         LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recv_tcp: deleting pbuf=%p\n", (void*)p));
923         pbuf_free(p);
924       }
925     }
926     /* once we have some data to return, only add more if we don't need to wait */
927     apiflags |= NETCONN_DONTBLOCK;
928     /* @todo: do we need to support peeking more than one pbuf? */
929   } while ((recv_left > 0) || (flags & MSG_PEEK));
930 lwip_recv_tcp_done:
931   if (recvd > 0) {
932     /* ensure window update after copying all data */
933     netconn_tcp_recvd(sock->conn, recvd);
934   }
935   sock_set_errno(sock, 0);
936   return recvd;
937 }
938 
939 /* Convert a netbuf's address data to struct sockaddr */
940 static void
941 lwip_sock_make_addr(struct netconn *conn, ip_addr_t *fromaddr, u16_t port,
942                     struct sockaddr *from, socklen_t *fromlen)
943 {
944   union sockaddr_aligned saddr;
945 
946   LWIP_UNUSED_ARG(conn);
947 
948 #if LWIP_IPV4 && LWIP_IPV6
949   /* Dual-stack: Map IPv4 addresses to IPv4 mapped IPv6 */
950   if (NETCONNTYPE_ISIPV6(netconn_type(conn)) && IP_IS_V4(fromaddr)) {
951     ip4_2_ipv4_mapped_ipv6(ip_2_ip6(fromaddr), ip_2_ip4(fromaddr));
952     IP_SET_TYPE(fromaddr, IPADDR_TYPE_V6);
953   }
954 #endif /* LWIP_IPV4 && LWIP_IPV6 */
955 
956   LWIP_DEBUGF(SOCKETS_DEBUG, (" addr="));
957   IPADDR_PORT_TO_SOCKADDR(&saddr, fromaddr, port);
958   ip_addr_debug_print(SOCKETS_DEBUG, fromaddr);
959   LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F"", port));
960   if (from && fromlen)
961   {
962     if (*fromlen > saddr.sa.sa_len) {
963       *fromlen = saddr.sa.sa_len;
964     }
965     MEMCPY(from, &saddr, *fromlen);
966   }
967 }
968 
969 int
970 lwip_recvfrom(int s, void *mem, size_t len, int flags,
971               struct sockaddr *from, socklen_t *fromlen)
972 {
973   struct lwip_sock *sock;
974   int              ret;
975 
976   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d, %p, %"SZT_F", 0x%x, ..)\n", s, mem, len, flags));
977   sock = get_socket(s);
978   if (!sock) {
979     return -1;
980   }
981   if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) {
982     ret = lwip_recv_tcp(sock, mem, len, flags);
983 #if !SOCKETS_DEBUG
984     if (from && fromlen)
985 #endif /* !SOCKETS_DEBUG */
986     {
987       /* get remote addr/port from tcp_pcb */
988       u16_t port;
989       ip_addr_t tmpaddr;
990       netconn_getaddr(sock->conn, &tmpaddr, &port, 0);
991       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d):", s));
992       lwip_sock_make_addr(sock->conn, &tmpaddr, port, from, fromlen);
993       LWIP_DEBUGF(SOCKETS_DEBUG, (" len=%d\n", ret));
994     }
995     done_socket(sock);
996     return ret;
997   } else {
998     struct netbuf    *buf;
999     u16_t            buflen, copylen;
1000     err_t            err;
1001     u8_t             apiflags;
1002     /* UDP / RAW */
1003     if (flags & MSG_DONTWAIT) {
1004       apiflags = NETCONN_DONTBLOCK;
1005     } else {
1006       apiflags = 0;
1007     }
1008 
1009     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom[UDP/RAW]: top sock->lastdata=%p\n", (void*)sock->lastdata.netbuf));
1010     /* Check if there is data left from the last recv operation. */
1011     buf = sock->lastdata.netbuf;
1012     if (buf == NULL) {
1013       /* No data was left from the previous operation, so we try to get
1014          some from the network. */
1015       err = netconn_recv_udp_raw_netbuf_flags(sock->conn, &buf, apiflags);
1016       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom[UDP/RAW]: netconn_recv err=%d, netbuf=%p\n",
1017         err, (void*)buf));
1018 
1019       if (err != ERR_OK) {
1020         LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom[UDP/RAW](%d): buf == NULL, error is \"%s\"!\n",
1021           s, lwip_strerr(err)));
1022         sock_set_errno(sock, err_to_errno(err));
1023         done_socket(sock);
1024         return -1;
1025       }
1026       LWIP_ASSERT("buf != NULL", buf != NULL);
1027       sock->lastdata.netbuf = buf;
1028     }
1029 
1030     buflen = buf->p->tot_len;
1031     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: buflen=%"U16_F" len=%"SZT_F"\n",
1032       buflen, len));
1033 
1034     if (len > buflen) {
1035       copylen = buflen;
1036     } else {
1037       copylen = (u16_t)len;
1038     }
1039 
1040     /* copy the contents of the received buffer into
1041     the supplied memory pointer mem */
1042     pbuf_copy_partial(buf->p, (u8_t*)mem, copylen, 0);
1043     ret = copylen;
1044 
1045     /* Check to see from where the data was.*/
1046 #if !SOCKETS_DEBUG
1047     if (from && fromlen)
1048 #endif /* !SOCKETS_DEBUG */
1049     {
1050       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d):", s));
1051       lwip_sock_make_addr(sock->conn, netbuf_fromaddr(buf), netbuf_fromport(buf), from, fromlen);
1052       LWIP_DEBUGF(SOCKETS_DEBUG, (" len=%d\n", ret));
1053     }
1054 
1055     /* If we don't peek the incoming message: zero lastdata pointer and free the netbuf */
1056     if ((flags & MSG_PEEK) == 0) {
1057       sock->lastdata.netbuf = NULL;
1058       netbuf_delete(buf);
1059     }
1060   }
1061 
1062   sock_set_errno(sock, 0);
1063   done_socket(sock);
1064   return ret;
1065 }
1066 
1067 int
1068 lwip_read(int s, void *mem, size_t len)
1069 {
1070   return lwip_recvfrom(s, mem, len, 0, NULL, NULL);
1071 }
1072 
1073 int
1074 lwip_recv(int s, void *mem, size_t len, int flags)
1075 {
1076   return lwip_recvfrom(s, mem, len, flags, NULL, NULL);
1077 }
1078 
1079 int
1080 lwip_send(int s, const void *data, size_t size, int flags)
1081 {
1082   struct lwip_sock *sock;
1083   err_t err;
1084   u8_t write_flags;
1085   size_t written;
1086 
1087   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_send(%d, data=%p, size=%"SZT_F", flags=0x%x)\n",
1088                               s, data, size, flags));
1089 
1090   sock = get_socket(s);
1091   if (!sock) {
1092     return -1;
1093   }
1094 
1095   if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_TCP) {
1096 #if (LWIP_UDP || LWIP_RAW)
1097     done_socket(sock);
1098     return lwip_sendto(s, data, size, flags, NULL, 0);
1099 #else /* (LWIP_UDP || LWIP_RAW) */
1100     sock_set_errno(sock, err_to_errno(ERR_ARG));
1101     done_socket(sock);
1102     return -1;
1103 #endif /* (LWIP_UDP || LWIP_RAW) */
1104   }
1105 
1106   write_flags = NETCONN_COPY |
1107     ((flags & MSG_MORE)     ? NETCONN_MORE      : 0) |
1108     ((flags & MSG_DONTWAIT) ? NETCONN_DONTBLOCK : 0);
1109   written = 0;
1110   err = netconn_write_partly(sock->conn, data, size, write_flags, &written);
1111 
1112   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_send(%d) err=%d written=%"SZT_F"\n", s, err, written));
1113   sock_set_errno(sock, err_to_errno(err));
1114   done_socket(sock);
1115   return (err == ERR_OK ? (int)written : -1);
1116 }
1117 
1118 int
1119 lwip_sendmsg(int s, const struct msghdr *msg, int flags)
1120 {
1121   struct lwip_sock *sock;
1122   int i;
1123 #if LWIP_TCP
1124   u8_t write_flags;
1125   size_t written;
1126 #endif
1127   int size = 0;
1128   err_t err = ERR_OK;
1129 
1130   sock = get_socket(s);
1131   if (!sock) {
1132     return -1;
1133   }
1134 
1135   LWIP_ERROR("lwip_sendmsg: invalid msghdr", msg != NULL,
1136              sock_set_errno(sock, err_to_errno(ERR_ARG)); return -1;);
1137   LWIP_ERROR("lwip_sendmsg: invalid msghdr iov", msg->msg_iov != NULL,
1138              sock_set_errno(sock, err_to_errno(ERR_ARG)); return -1;);
1139   LWIP_ERROR("lwip_sendmsg: maximum iovs exceeded", (msg->msg_iovlen > 0) && (msg->msg_iovlen <= IOV_MAX),
1140              sock_set_errno(sock, EMSGSIZE); return -1;);
1141   LWIP_ERROR("lwip_sendmsg: unsupported flags", ((flags == 0) || (flags == MSG_NOSIGNAL)),
1142              sock_set_errno(sock, EOPNOTSUPP); return -1;);
1143 
1144   LWIP_UNUSED_ARG(msg->msg_control);
1145   LWIP_UNUSED_ARG(msg->msg_controllen);
1146   LWIP_UNUSED_ARG(msg->msg_flags);
1147 
1148   if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) {
1149 #if LWIP_TCP
1150     write_flags = NETCONN_COPY |
1151     ((flags & MSG_MORE)     ? NETCONN_MORE      : 0) |
1152     ((flags & MSG_DONTWAIT) ? NETCONN_DONTBLOCK : 0);
1153 
1154     written = 0;
1155     err = netconn_write_vectors_partly(sock->conn, (struct netvector *)msg->msg_iov, (u16_t)msg->msg_iovlen, write_flags, &written);
1156     sock_set_errno(sock, err_to_errno(err));
1157     done_socket(sock);
1158     return (err == ERR_OK ? (int)written : -1);
1159 #else /* LWIP_TCP */
1160     sock_set_errno(sock, err_to_errno(ERR_ARG));
1161     done_socket(sock);
1162     return -1;
1163 #endif /* LWIP_TCP */
1164   }
1165   /* else, UDP and RAW NETCONNs */
1166 #if LWIP_UDP || LWIP_RAW
1167   {
1168     struct netbuf chain_buf;
1169 
1170     LWIP_UNUSED_ARG(flags);
1171     LWIP_ERROR("lwip_sendmsg: invalid msghdr name", (((msg->msg_name == NULL) && (msg->msg_namelen == 0)) ||
1172                IS_SOCK_ADDR_LEN_VALID(msg->msg_namelen)) ,
1173                sock_set_errno(sock, err_to_errno(ERR_ARG)); return -1;);
1174 
1175     /* initialize chain buffer with destination */
1176     memset(&chain_buf, 0, sizeof(struct netbuf));
1177     if (msg->msg_name) {
1178       u16_t remote_port;
1179       SOCKADDR_TO_IPADDR_PORT((const struct sockaddr *)msg->msg_name, &chain_buf.addr, remote_port);
1180       netbuf_fromport(&chain_buf) = remote_port;
1181     }
1182 #if LWIP_NETIF_TX_SINGLE_PBUF
1183     for (i = 0; i < msg->msg_iovlen; i++) {
1184       size += msg->msg_iov[i].iov_len;
1185       if ((msg->msg_iov[i].iov_len > INT_MAX) || (size < (int)msg->msg_iov[i].iov_len)) {
1186         /* overflow */
1187         goto sendmsg_emsgsize;
1188       }
1189     }
1190     if (size > 0xFFFF) {
1191       /* overflow */
1192       goto sendmsg_emsgsize;
1193     }
1194     /* Allocate a new netbuf and copy the data into it. */
1195     if (netbuf_alloc(&chain_buf, (u16_t)size) == NULL) {
1196        err = ERR_MEM;
1197     } else {
1198       /* flatten the IO vectors */
1199       size_t offset = 0;
1200       for (i = 0; i < msg->msg_iovlen; i++) {
1201         MEMCPY(&((u8_t*)chain_buf.p->payload)[offset], msg->msg_iov[i].iov_base, msg->msg_iov[i].iov_len);
1202         offset += msg->msg_iov[i].iov_len;
1203       }
1204 #if LWIP_CHECKSUM_ON_COPY
1205       {
1206         /* This can be improved by using LWIP_CHKSUM_COPY() and aggregating the checksum for each IO vector */
1207         u16_t chksum = ~inet_chksum_pbuf(chain_buf.p);
1208         netbuf_set_chksum(&chain_buf, chksum);
1209       }
1210 #endif /* LWIP_CHECKSUM_ON_COPY */
1211       err = ERR_OK;
1212     }
1213 #else /* LWIP_NETIF_TX_SINGLE_PBUF */
1214     /* create a chained netbuf from the IO vectors. NOTE: we assemble a pbuf chain
1215        manually to avoid having to allocate, chain, and delete a netbuf for each iov */
1216     for (i = 0; i < msg->msg_iovlen; i++) {
1217       struct pbuf *p;
1218       if (msg->msg_iov[i].iov_len > 0xFFFF) {
1219         /* overflow */
1220         goto sendmsg_emsgsize;
1221       }
1222       p = pbuf_alloc(PBUF_TRANSPORT, 0, PBUF_REF);
1223       if (p == NULL) {
1224         err = ERR_MEM; /* let netbuf_delete() cleanup chain_buf */
1225         break;
1226       }
1227       p->payload = msg->msg_iov[i].iov_base;
1228       p->len = p->tot_len = (u16_t)msg->msg_iov[i].iov_len;
1229       /* netbuf empty, add new pbuf */
1230       if (chain_buf.p == NULL) {
1231         chain_buf.p = chain_buf.ptr = p;
1232         /* add pbuf to existing pbuf chain */
1233       } else {
1234         if (chain_buf.p->tot_len + p->len > 0xffff) {
1235           /* overflow */
1236           pbuf_free(p);
1237           goto sendmsg_emsgsize;
1238         }
1239         pbuf_cat(chain_buf.p, p);
1240       }
1241     }
1242     /* save size of total chain */
1243     if (err == ERR_OK) {
1244       size = netbuf_len(&chain_buf);
1245     }
1246 #endif /* LWIP_NETIF_TX_SINGLE_PBUF */
1247 
1248     if (err == ERR_OK) {
1249 #if LWIP_IPV4 && LWIP_IPV6
1250       /* Dual-stack: Unmap IPv4 mapped IPv6 addresses */
1251       if (IP_IS_V6_VAL(chain_buf.addr) && ip6_addr_isipv4mappedipv6(ip_2_ip6(&chain_buf.addr))) {
1252         unmap_ipv4_mapped_ipv6(ip_2_ip4(&chain_buf.addr), ip_2_ip6(&chain_buf.addr));
1253         IP_SET_TYPE_VAL(chain_buf.addr, IPADDR_TYPE_V4);
1254       }
1255 #endif /* LWIP_IPV4 && LWIP_IPV6 */
1256 
1257       /* send the data */
1258       err = netconn_send(sock->conn, &chain_buf);
1259     }
1260 
1261     /* deallocated the buffer */
1262     netbuf_free(&chain_buf);
1263 
1264     sock_set_errno(sock, err_to_errno(err));
1265     done_socket(sock);
1266     return (err == ERR_OK ? size : -1);
1267 sendmsg_emsgsize:
1268     sock_set_errno(sock, EMSGSIZE);
1269     netbuf_free(&chain_buf);
1270     done_socket(sock);
1271     return -1;
1272   }
1273 #else /* LWIP_UDP || LWIP_RAW */
1274   sock_set_errno(sock, err_to_errno(ERR_ARG));
1275   done_socket(sock);
1276   return -1;
1277 #endif /* LWIP_UDP || LWIP_RAW */
1278 }
1279 
1280 int
1281 lwip_sendto(int s, const void *data, size_t size, int flags,
1282        const struct sockaddr *to, socklen_t tolen)
1283 {
1284   struct lwip_sock *sock;
1285   err_t err;
1286   u16_t short_size;
1287   u16_t remote_port;
1288   struct netbuf buf;
1289 
1290   sock = get_socket(s);
1291   if (!sock) {
1292     return -1;
1293   }
1294 
1295   if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) {
1296 #if LWIP_TCP
1297     done_socket(sock);
1298     return lwip_send(s, data, size, flags);
1299 #else /* LWIP_TCP */
1300     LWIP_UNUSED_ARG(flags);
1301     sock_set_errno(sock, err_to_errno(ERR_ARG));
1302     done_socket(sock);
1303     return -1;
1304 #endif /* LWIP_TCP */
1305   }
1306 
1307   if (size > 0xFFFF) {
1308     /* cannot fit into one datagram (at least for us) */
1309     sock_set_errno(sock, EMSGSIZE);
1310     done_socket(sock);
1311     return -1;
1312   }
1313   short_size = (u16_t)size;
1314   LWIP_ERROR("lwip_sendto: invalid address", (((to == NULL) && (tolen == 0)) ||
1315              (IS_SOCK_ADDR_LEN_VALID(tolen) &&
1316              IS_SOCK_ADDR_TYPE_VALID(to) && IS_SOCK_ADDR_ALIGNED(to))),
1317              sock_set_errno(sock, err_to_errno(ERR_ARG)); return -1;);
1318   LWIP_UNUSED_ARG(tolen);
1319 
1320   /* initialize a buffer */
1321   buf.p = buf.ptr = NULL;
1322 #if LWIP_CHECKSUM_ON_COPY
1323   buf.flags = 0;
1324 #endif /* LWIP_CHECKSUM_ON_COPY */
1325   if (to) {
1326     SOCKADDR_TO_IPADDR_PORT(to, &buf.addr, remote_port);
1327   } else {
1328     remote_port = 0;
1329     ip_addr_set_any(NETCONNTYPE_ISIPV6(netconn_type(sock->conn)), &buf.addr);
1330   }
1331   netbuf_fromport(&buf) = remote_port;
1332 
1333 
1334   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_sendto(%d, data=%p, short_size=%"U16_F", flags=0x%x to=",
1335               s, data, short_size, flags));
1336   ip_addr_debug_print(SOCKETS_DEBUG, &buf.addr);
1337   LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F"\n", remote_port));
1338 
1339   /* make the buffer point to the data that should be sent */
1340 #if LWIP_NETIF_TX_SINGLE_PBUF
1341   /* Allocate a new netbuf and copy the data into it. */
1342   if (netbuf_alloc(&buf, short_size) == NULL) {
1343     err = ERR_MEM;
1344   } else {
1345 #if LWIP_CHECKSUM_ON_COPY
1346     if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_RAW) {
1347       u16_t chksum = LWIP_CHKSUM_COPY(buf.p->payload, data, short_size);
1348       netbuf_set_chksum(&buf, chksum);
1349     } else
1350 #endif /* LWIP_CHECKSUM_ON_COPY */
1351     {
1352       MEMCPY(buf.p->payload, data, short_size);
1353     }
1354     err = ERR_OK;
1355   }
1356 #else /* LWIP_NETIF_TX_SINGLE_PBUF */
1357   err = netbuf_ref(&buf, data, short_size);
1358 #endif /* LWIP_NETIF_TX_SINGLE_PBUF */
1359   if (err == ERR_OK) {
1360 #if LWIP_IPV4 && LWIP_IPV6
1361     /* Dual-stack: Unmap IPv4 mapped IPv6 addresses */
1362     if (IP_IS_V6_VAL(buf.addr) && ip6_addr_isipv4mappedipv6(ip_2_ip6(&buf.addr))) {
1363       unmap_ipv4_mapped_ipv6(ip_2_ip4(&buf.addr), ip_2_ip6(&buf.addr));
1364       IP_SET_TYPE_VAL(buf.addr, IPADDR_TYPE_V4);
1365     }
1366 #endif /* LWIP_IPV4 && LWIP_IPV6 */
1367 
1368     /* send the data */
1369     err = netconn_send(sock->conn, &buf);
1370   }
1371 
1372   /* deallocated the buffer */
1373   netbuf_free(&buf);
1374 
1375   sock_set_errno(sock, err_to_errno(err));
1376   done_socket(sock);
1377   return (err == ERR_OK ? short_size : -1);
1378 }
1379 
1380 int
1381 lwip_socket(int domain, int type, int protocol)
1382 {
1383   struct netconn *conn;
1384   int i;
1385 
1386   LWIP_UNUSED_ARG(domain); /* @todo: check this */
1387 
1388   /* create a netconn */
1389   switch (type) {
1390   case SOCK_RAW:
1391     conn = netconn_new_with_proto_and_callback(DOMAIN_TO_NETCONN_TYPE(domain, NETCONN_RAW),
1392                                                (u8_t)protocol, DEFAULT_SOCKET_EVENTCB);
1393     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_RAW, %d) = ",
1394                                  domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol));
1395     break;
1396   case SOCK_DGRAM:
1397     conn = netconn_new_with_callback(DOMAIN_TO_NETCONN_TYPE(domain,
1398                  ((protocol == IPPROTO_UDPLITE) ? NETCONN_UDPLITE : NETCONN_UDP)) ,
1399                  DEFAULT_SOCKET_EVENTCB);
1400     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_DGRAM, %d) = ",
1401                                  domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol));
1402     break;
1403   case SOCK_STREAM:
1404     conn = netconn_new_with_callback(DOMAIN_TO_NETCONN_TYPE(domain, NETCONN_TCP), DEFAULT_SOCKET_EVENTCB);
1405     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_STREAM, %d) = ",
1406                                  domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol));
1407     break;
1408   default:
1409     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%d, %d/UNKNOWN, %d) = -1\n",
1410                                  domain, type, protocol));
1411     set_errno(EINVAL);
1412     return -1;
1413   }
1414 
1415   if (!conn) {
1416     LWIP_DEBUGF(SOCKETS_DEBUG, ("-1 / ENOBUFS (could not create netconn)\n"));
1417     set_errno(ENOBUFS);
1418     return -1;
1419   }
1420 
1421   i = alloc_socket(conn, 0);
1422 
1423   if (i == -1) {
1424     netconn_delete(conn);
1425     set_errno(ENFILE);
1426     return -1;
1427   }
1428   conn->socket = i;
1429   done_socket(&sockets[i - LWIP_SOCKET_OFFSET]);
1430   LWIP_DEBUGF(SOCKETS_DEBUG, ("%d\n", i));
1431   set_errno(0);
1432   return i;
1433 }
1434 
1435 int
1436 lwip_write(int s, const void *data, size_t size)
1437 {
1438   return lwip_send(s, data, size, 0);
1439 }
1440 
1441 int
1442 lwip_writev(int s, const struct iovec *iov, int iovcnt)
1443 {
1444   struct msghdr msg;
1445 
1446   msg.msg_name = NULL;
1447   msg.msg_namelen = 0;
1448   /* Hack: we have to cast via number to cast from 'const' pointer to non-const.
1449      Blame the opengroup standard for this inconsistency. */
1450   msg.msg_iov = LWIP_CONST_CAST(struct iovec *, iov);
1451   msg.msg_iovlen = iovcnt;
1452   msg.msg_control = NULL;
1453   msg.msg_controllen = 0;
1454   msg.msg_flags = 0;
1455   return lwip_sendmsg(s, &msg, 0);
1456 }
1457 
1458 #if LWIP_SOCKET_SELECT
1459 /**
1460  * Go through the readset and writeset lists and see which socket of the sockets
1461  * set in the sets has events. On return, readset, writeset and exceptset have
1462  * the sockets enabled that had events.
1463  *
1464  * @param maxfdp1 the highest socket index in the sets
1465  * @param readset_in    set of sockets to check for read events
1466  * @param writeset_in   set of sockets to check for write events
1467  * @param exceptset_in  set of sockets to check for error events
1468  * @param readset_out   set of sockets that had read events
1469  * @param writeset_out  set of sockets that had write events
1470  * @param exceptset_out set os sockets that had error events
1471  * @return number of sockets that had events (read/write/exception) (>= 0)
1472  */
1473 static int
1474 lwip_selscan(int maxfdp1, fd_set *readset_in, fd_set *writeset_in, fd_set *exceptset_in,
1475              fd_set *readset_out, fd_set *writeset_out, fd_set *exceptset_out)
1476 {
1477   int i, nready = 0;
1478   fd_set lreadset, lwriteset, lexceptset;
1479   struct lwip_sock *sock;
1480   SYS_ARCH_DECL_PROTECT(lev);
1481 
1482   FD_ZERO(&lreadset);
1483   FD_ZERO(&lwriteset);
1484   FD_ZERO(&lexceptset);
1485 
1486   /* Go through each socket in each list to count number of sockets which
1487      currently match */
1488   for (i = LWIP_SOCKET_OFFSET; i < maxfdp1; i++) {
1489     /* if this FD is not in the set, continue */
1490     if (!(readset_in && FD_ISSET(i, readset_in)) &&
1491         !(writeset_in && FD_ISSET(i, writeset_in)) &&
1492         !(exceptset_in && FD_ISSET(i, exceptset_in))) {
1493       continue;
1494     }
1495     /* First get the socket's status (protected)... */
1496     SYS_ARCH_PROTECT(lev);
1497     sock = tryget_socket_unconn(i);
1498     if (sock != NULL) {
1499       void* lastdata = sock->lastdata.pbuf;
1500       s16_t rcvevent = sock->rcvevent;
1501       u16_t sendevent = sock->sendevent;
1502       u16_t errevent = sock->errevent;
1503       SYS_ARCH_UNPROTECT(lev);
1504 
1505       /* ... then examine it: */
1506       /* See if netconn of this socket is ready for read */
1507       if (readset_in && FD_ISSET(i, readset_in) && ((lastdata != NULL) || (rcvevent > 0))) {
1508         FD_SET(i, &lreadset);
1509         LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_selscan: fd=%d ready for reading\n", i));
1510         nready++;
1511       }
1512       /* See if netconn of this socket is ready for write */
1513       if (writeset_in && FD_ISSET(i, writeset_in) && (sendevent != 0)) {
1514         FD_SET(i, &lwriteset);
1515         LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_selscan: fd=%d ready for writing\n", i));
1516         nready++;
1517       }
1518       /* See if netconn of this socket had an error */
1519       if (exceptset_in && FD_ISSET(i, exceptset_in) && (errevent != 0)) {
1520         FD_SET(i, &lexceptset);
1521         LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_selscan: fd=%d ready for exception\n", i));
1522         nready++;
1523       }
1524       done_socket(sock);
1525     } else {
1526       SYS_ARCH_UNPROTECT(lev);
1527       /* no a valid open socket */
1528       return -1;
1529     }
1530   }
1531   /* copy local sets to the ones provided as arguments */
1532   *readset_out = lreadset;
1533   *writeset_out = lwriteset;
1534   *exceptset_out = lexceptset;
1535 
1536   LWIP_ASSERT("nready >= 0", nready >= 0);
1537   return nready;
1538 }
1539 
1540 #if LWIP_NETCONN_FULLDUPLEX
1541 /* Mark all of the set sockets in one of the three fdsets passed to select as used.
1542  * All sockets are marked (and later unmarked), whether they are open or not.
1543  * This is OK as lwip_selscan aborts select when non-open sockets are found.
1544  */
1545 static void
1546 lwip_select_inc_sockets_used_set(int maxfdp, fd_set *fdset, fd_set *used_sockets)
1547 {
1548   SYS_ARCH_DECL_PROTECT(lev);
1549   if (fdset) {
1550     int i;
1551     for (i = LWIP_SOCKET_OFFSET; i < maxfdp; i++) {
1552       /* if this FD is in the set, lock it (unless already done) */
1553       if (FD_ISSET(i, fdset) && !FD_ISSET(i, used_sockets)) {
1554         struct lwip_sock *sock;
1555         SYS_ARCH_PROTECT(lev);
1556         sock = tryget_socket_unconn(i);
1557         if (sock != NULL) {
1558           sock_inc_used(sock);
1559           FD_SET(i, used_sockets);
1560         }
1561         SYS_ARCH_UNPROTECT(lev);
1562       }
1563     }
1564   }
1565 }
1566 
1567 /* Mark all sockets passed to select as used to prevent them from being freed
1568  * from other threads while select is running.
1569  * Marked sockets are added to 'used_sockets' to mark them only once an be able
1570  * to unmark them correctly.
1571  */
1572 static void
1573 lwip_select_inc_sockets_used(int maxfdp, fd_set *fdset1, fd_set *fdset2, fd_set *fdset3, fd_set *used_sockets)
1574 {
1575   FD_ZERO(used_sockets);
1576   lwip_select_inc_sockets_used_set(maxfdp, fdset1, used_sockets);
1577   lwip_select_inc_sockets_used_set(maxfdp, fdset2, used_sockets);
1578   lwip_select_inc_sockets_used_set(maxfdp, fdset3, used_sockets);
1579 }
1580 
1581 /* Let go all sockets that were marked as used when starting select */
1582 static void
1583 lwip_select_dec_sockets_used(int maxfdp, fd_set *used_sockets)
1584 {
1585   int i;
1586   for (i = LWIP_SOCKET_OFFSET; i < maxfdp; i++) {
1587     /* if this FD is not in the set, continue */
1588     if (FD_ISSET(i, used_sockets)) {
1589       struct lwip_sock *sock = tryget_socket_unconn(i);
1590       LWIP_ASSERT("socket gone at the end of select", sock != NULL);
1591       if (sock != NULL) {
1592         done_socket(sock);
1593       }
1594     }
1595   }
1596 }
1597 #else /* LWIP_NETCONN_FULLDUPLEX */
1598 #define lwip_select_inc_sockets_used(maxfdp1, readset, writeset, exceptset, used_sockets)
1599 #define lwip_select_dec_sockets_used(maxfdp1, used_sockets)
1600 #endif /* LWIP_NETCONN_FULLDUPLEX */
1601 
1602 int
1603 lwip_select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset,
1604             struct timeval *timeout)
1605 {
1606   u32_t waitres = 0;
1607   int nready;
1608   fd_set lreadset, lwriteset, lexceptset;
1609   u32_t msectimeout;
1610   struct lwip_select_cb select_cb;
1611   int i;
1612   int maxfdp2;
1613 #if LWIP_NETCONN_SEM_PER_THREAD
1614   int waited = 0;
1615 #endif
1616 #if LWIP_NETCONN_FULLDUPLEX
1617   fd_set used_sockets;
1618 #endif
1619   SYS_ARCH_DECL_PROTECT(lev);
1620 
1621   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select(%d, %p, %p, %p, tvsec=%"S32_F" tvusec=%"S32_F")\n",
1622                   maxfdp1, (void *)readset, (void *) writeset, (void *) exceptset,
1623                   timeout ? (s32_t)timeout->tv_sec : (s32_t)-1,
1624                   timeout ? (s32_t)timeout->tv_usec : (s32_t)-1));
1625 
1626   if ((maxfdp1 < 0) || (maxfdp1 > (FD_SETSIZE + LWIP_SOCKET_OFFSET))) {
1627     set_errno(EINVAL);
1628     return -1;
1629   }
1630 
1631   lwip_select_inc_sockets_used(maxfdp1, readset, writeset, exceptset, &used_sockets);
1632 
1633   /* Go through each socket in each list to count number of sockets which
1634      currently match */
1635   nready = lwip_selscan(maxfdp1, readset, writeset, exceptset, &lreadset, &lwriteset, &lexceptset);
1636 
1637   if (nready < 0) {
1638     set_errno(EBADF);
1639     return -1;
1640   }
1641 
1642   /* If we don't have any current events, then suspend if we are supposed to */
1643   if (!nready) {
1644     if (timeout && timeout->tv_sec == 0 && timeout->tv_usec == 0) {
1645       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select: no timeout, returning 0\n"));
1646       /* This is OK as the local fdsets are empty and nready is zero,
1647          or we would have returned earlier. */
1648       goto return_copy_fdsets;
1649     }
1650 
1651     /* None ready: add our semaphore to list:
1652        We don't actually need any dynamic memory. Our entry on the
1653        list is only valid while we are in this function, so it's ok
1654        to use local variables. */
1655 
1656     select_cb.next = NULL;
1657     select_cb.prev = NULL;
1658     select_cb.readset = readset;
1659     select_cb.writeset = writeset;
1660     select_cb.exceptset = exceptset;
1661     select_cb.sem_signalled = 0;
1662 #if LWIP_NETCONN_SEM_PER_THREAD
1663     select_cb.sem = LWIP_NETCONN_THREAD_SEM_GET();
1664 #else /* LWIP_NETCONN_SEM_PER_THREAD */
1665     if (sys_sem_new(&select_cb.sem, 0) != ERR_OK) {
1666       /* failed to create semaphore */
1667       set_errno(ENOMEM);
1668       lwip_select_dec_sockets_used(maxfdp1, &used_sockets);
1669       return -1;
1670     }
1671 #endif /* LWIP_NETCONN_SEM_PER_THREAD */
1672 
1673     /* Protect the select_cb_list */
1674     SYS_ARCH_PROTECT(lev);
1675 
1676     /* Put this select_cb on top of list */
1677     select_cb.next = select_cb_list;
1678     if (select_cb_list != NULL) {
1679       select_cb_list->prev = &select_cb;
1680     }
1681     select_cb_list = &select_cb;
1682     /* Increasing this counter tells event_callback that the list has changed. */
1683     select_cb_ctr++;
1684 
1685     /* Now we can safely unprotect */
1686     SYS_ARCH_UNPROTECT(lev);
1687 
1688     /* Increase select_waiting for each socket we are interested in */
1689     maxfdp2 = maxfdp1;
1690     for (i = LWIP_SOCKET_OFFSET; i < maxfdp1; i++) {
1691       if ((readset && FD_ISSET(i, readset)) ||
1692           (writeset && FD_ISSET(i, writeset)) ||
1693           (exceptset && FD_ISSET(i, exceptset))) {
1694         struct lwip_sock *sock;
1695         SYS_ARCH_PROTECT(lev);
1696         sock = tryget_socket_unconn(i);
1697         if (sock != NULL) {
1698           sock->select_waiting++;
1699           LWIP_ASSERT("sock->select_waiting > 0", sock->select_waiting > 0);
1700           done_socket(sock);
1701         } else {
1702           /* Not a valid socket */
1703           nready = -1;
1704           maxfdp2 = i;
1705           SYS_ARCH_UNPROTECT(lev);
1706           break;
1707         }
1708         SYS_ARCH_UNPROTECT(lev);
1709       }
1710     }
1711 
1712     if (nready >= 0) {
1713       /* Call lwip_selscan again: there could have been events between
1714          the last scan (without us on the list) and putting us on the list! */
1715       nready = lwip_selscan(maxfdp1, readset, writeset, exceptset, &lreadset, &lwriteset, &lexceptset);
1716       if (!nready) {
1717         /* Still none ready, just wait to be woken */
1718         if (timeout == 0) {
1719           /* Wait forever */
1720           msectimeout = 0;
1721         } else {
1722           msectimeout =  ((timeout->tv_sec * 1000) + ((timeout->tv_usec + 500)/1000));
1723           if (msectimeout == 0) {
1724             /* Wait 1ms at least (0 means wait forever) */
1725             msectimeout = 1;
1726           }
1727         }
1728 
1729         waitres = sys_arch_sem_wait(SELECT_SEM_PTR(select_cb.sem), msectimeout);
1730 #if LWIP_NETCONN_SEM_PER_THREAD
1731         waited = 1;
1732 #endif
1733       }
1734     }
1735 
1736     /* Decrease select_waiting for each socket we are interested in */
1737     for (i = LWIP_SOCKET_OFFSET; i < maxfdp2; i++) {
1738       if ((readset && FD_ISSET(i, readset)) ||
1739           (writeset && FD_ISSET(i, writeset)) ||
1740           (exceptset && FD_ISSET(i, exceptset))) {
1741         struct lwip_sock *sock;
1742         SYS_ARCH_PROTECT(lev);
1743         sock = tryget_socket_unconn(i);
1744         if (sock != NULL) {
1745           /* for now, handle select_waiting==0... */
1746           LWIP_ASSERT("sock->select_waiting > 0", sock->select_waiting > 0);
1747           if (sock->select_waiting > 0) {
1748             sock->select_waiting--;
1749           }
1750           done_socket(sock);
1751         } else {
1752           /* Not a valid socket */
1753           nready = -1;
1754         }
1755         SYS_ARCH_UNPROTECT(lev);
1756       }
1757     }
1758     /* Take us off the list */
1759     SYS_ARCH_PROTECT(lev);
1760     if (select_cb.next != NULL) {
1761       select_cb.next->prev = select_cb.prev;
1762     }
1763     if (select_cb_list == &select_cb) {
1764       LWIP_ASSERT("select_cb.prev == NULL", select_cb.prev == NULL);
1765       select_cb_list = select_cb.next;
1766     } else {
1767       LWIP_ASSERT("select_cb.prev != NULL", select_cb.prev != NULL);
1768       select_cb.prev->next = select_cb.next;
1769     }
1770     /* Increasing this counter tells event_callback that the list has changed. */
1771     select_cb_ctr++;
1772     SYS_ARCH_UNPROTECT(lev);
1773 
1774 #if LWIP_NETCONN_SEM_PER_THREAD
1775     if (select_cb.sem_signalled && (!waited || (waitres == SYS_ARCH_TIMEOUT))) {
1776       /* don't leave the thread-local semaphore signalled */
1777       sys_arch_sem_wait(select_cb.sem, 1);
1778     }
1779 #else /* LWIP_NETCONN_SEM_PER_THREAD */
1780     sys_sem_free(&select_cb.sem);
1781 #endif /* LWIP_NETCONN_SEM_PER_THREAD */
1782 
1783     if (nready < 0) {
1784       /* This happens when a socket got closed while waiting */
1785       set_errno(EBADF);
1786       lwip_select_dec_sockets_used(maxfdp1, &used_sockets);
1787       return -1;
1788     }
1789 
1790     if (waitres == SYS_ARCH_TIMEOUT) {
1791       /* Timeout */
1792       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select: timeout expired\n"));
1793       /* This is OK as the local fdsets are empty and nready is zero,
1794          or we would have returned earlier. */
1795       goto return_copy_fdsets;
1796     }
1797 
1798     /* See what's set */
1799     nready = lwip_selscan(maxfdp1, readset, writeset, exceptset, &lreadset, &lwriteset, &lexceptset);
1800   }
1801 
1802   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select: nready=%d\n", nready));
1803 return_copy_fdsets:
1804   lwip_select_dec_sockets_used(maxfdp1, &used_sockets);
1805   set_errno(0);
1806   if (readset) {
1807     *readset = lreadset;
1808   }
1809   if (writeset) {
1810     *writeset = lwriteset;
1811   }
1812   if (exceptset) {
1813     *exceptset = lexceptset;
1814   }
1815   return nready;
1816 }
1817 
1818 /**
1819  * Callback registered in the netconn layer for each socket-netconn.
1820  * Processes recvevent (data available) and wakes up tasks waiting for select.
1821  */
1822 static void
1823 event_callback(struct netconn *conn, enum netconn_evt evt, u16_t len)
1824 {
1825   int s;
1826   struct lwip_sock *sock;
1827   struct lwip_select_cb *scb;
1828   int last_select_cb_ctr;
1829   SYS_ARCH_DECL_PROTECT(lev);
1830 
1831   LWIP_UNUSED_ARG(len);
1832 
1833   /* Get socket */
1834   if (conn) {
1835     s = conn->socket;
1836     if (s < 0) {
1837       /* Data comes in right away after an accept, even though
1838        * the server task might not have created a new socket yet.
1839        * Just count down (or up) if that's the case and we
1840        * will use the data later. Note that only receive events
1841        * can happen before the new socket is set up. */
1842       SYS_ARCH_PROTECT(lev);
1843       if (conn->socket < 0) {
1844         if (evt == NETCONN_EVT_RCVPLUS) {
1845           /* conn->socket is -1 on initialization
1846              lwip_accept adjusts sock->recvevent if conn->socket < -1 */
1847           conn->socket--;
1848         }
1849         SYS_ARCH_UNPROTECT(lev);
1850         return;
1851       }
1852       s = conn->socket;
1853       SYS_ARCH_UNPROTECT(lev);
1854     }
1855 
1856     sock = get_socket(s);
1857     if (!sock) {
1858       return;
1859     }
1860   } else {
1861     return;
1862   }
1863 
1864   SYS_ARCH_PROTECT(lev);
1865   /* Set event as required */
1866   switch (evt) {
1867     case NETCONN_EVT_RCVPLUS:
1868       sock->rcvevent++;
1869       break;
1870     case NETCONN_EVT_RCVMINUS:
1871       sock->rcvevent--;
1872       break;
1873     case NETCONN_EVT_SENDPLUS:
1874       sock->sendevent = 1;
1875       break;
1876     case NETCONN_EVT_SENDMINUS:
1877       sock->sendevent = 0;
1878       break;
1879     case NETCONN_EVT_ERROR:
1880       sock->errevent = 1;
1881       break;
1882     default:
1883       LWIP_ASSERT("unknown event", 0);
1884       break;
1885   }
1886 
1887   if (sock->select_waiting == 0) {
1888     /* noone is waiting for this socket, no need to check select_cb_list */
1889     SYS_ARCH_UNPROTECT(lev);
1890     done_socket(sock);
1891     return;
1892   }
1893 
1894   /* Now decide if anyone is waiting for this socket */
1895   /* NOTE: This code goes through the select_cb_list list multiple times
1896      ONLY IF a select was actually waiting. We go through the list the number
1897      of waiting select calls + 1. This list is expected to be small. */
1898 
1899   /* At this point, SYS_ARCH is still protected! */
1900 again:
1901   for (scb = select_cb_list; scb != NULL; scb = scb->next) {
1902     /* remember the state of select_cb_list to detect changes */
1903     last_select_cb_ctr = select_cb_ctr;
1904     if (scb->sem_signalled == 0) {
1905       /* semaphore not signalled yet */
1906       int do_signal = 0;
1907       /* Test this select call for our socket */
1908       if (sock->rcvevent > 0) {
1909         if (scb->readset && FD_ISSET(s, scb->readset)) {
1910           do_signal = 1;
1911         }
1912       }
1913       if (sock->sendevent != 0) {
1914         if (!do_signal && scb->writeset && FD_ISSET(s, scb->writeset)) {
1915           do_signal = 1;
1916         }
1917       }
1918       if (sock->errevent != 0) {
1919         if (!do_signal && scb->exceptset && FD_ISSET(s, scb->exceptset)) {
1920           do_signal = 1;
1921         }
1922       }
1923       if (do_signal) {
1924         scb->sem_signalled = 1;
1925         /* Don't call SYS_ARCH_UNPROTECT() before signaling the semaphore, as this might
1926            lead to the select thread taking itself off the list, invalidating the semaphore. */
1927         sys_sem_signal(SELECT_SEM_PTR(scb->sem));
1928       }
1929     }
1930     /* unlock interrupts with each step */
1931     SYS_ARCH_UNPROTECT(lev);
1932     /* this makes sure interrupt protection time is short */
1933     SYS_ARCH_PROTECT(lev);
1934     if (last_select_cb_ctr != select_cb_ctr) {
1935       /* someone has changed select_cb_list, restart at the beginning */
1936       goto again;
1937     }
1938   }
1939   SYS_ARCH_UNPROTECT(lev);
1940   done_socket(sock);
1941 }
1942 #endif /* LWIP_SOCKET_SELECT */
1943 
1944 /**
1945  * Close one end of a full-duplex connection.
1946  */
1947 int
1948 lwip_shutdown(int s, int how)
1949 {
1950   struct lwip_sock *sock;
1951   err_t err;
1952   u8_t shut_rx = 0, shut_tx = 0;
1953 
1954   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_shutdown(%d, how=%d)\n", s, how));
1955 
1956   sock = get_socket(s);
1957   if (!sock) {
1958     return -1;
1959   }
1960 
1961   if (sock->conn != NULL) {
1962     if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_TCP) {
1963       sock_set_errno(sock, EOPNOTSUPP);
1964       done_socket(sock);
1965       return -1;
1966     }
1967   } else {
1968     sock_set_errno(sock, ENOTCONN);
1969     done_socket(sock);
1970     return -1;
1971   }
1972 
1973   if (how == SHUT_RD) {
1974     shut_rx = 1;
1975   } else if (how == SHUT_WR) {
1976     shut_tx = 1;
1977   } else if (how == SHUT_RDWR) {
1978     shut_rx = 1;
1979     shut_tx = 1;
1980   } else {
1981     sock_set_errno(sock, EINVAL);
1982     done_socket(sock);
1983     return -1;
1984   }
1985   err = netconn_shutdown(sock->conn, shut_rx, shut_tx);
1986 
1987   sock_set_errno(sock, err_to_errno(err));
1988   done_socket(sock);
1989   return (err == ERR_OK ? 0 : -1);
1990 }
1991 
1992 static int
1993 lwip_getaddrname(int s, struct sockaddr *name, socklen_t *namelen, u8_t local)
1994 {
1995   struct lwip_sock *sock;
1996   union sockaddr_aligned saddr;
1997   ip_addr_t naddr;
1998   u16_t port;
1999   err_t err;
2000 
2001   sock = get_socket(s);
2002   if (!sock) {
2003     return -1;
2004   }
2005 
2006   /* get the IP address and port */
2007   err = netconn_getaddr(sock->conn, &naddr, &port, local);
2008   if (err != ERR_OK) {
2009     sock_set_errno(sock, err_to_errno(err));
2010     done_socket(sock);
2011     return -1;
2012   }
2013 
2014 #if LWIP_IPV4 && LWIP_IPV6
2015   /* Dual-stack: Map IPv4 addresses to IPv4 mapped IPv6 */
2016   if (NETCONNTYPE_ISIPV6(netconn_type(sock->conn)) &&
2017       IP_IS_V4_VAL(naddr)) {
2018     ip4_2_ipv4_mapped_ipv6(ip_2_ip6(&naddr), ip_2_ip4(&naddr));
2019     IP_SET_TYPE_VAL(naddr, IPADDR_TYPE_V6);
2020   }
2021 #endif /* LWIP_IPV4 && LWIP_IPV6 */
2022 
2023   IPADDR_PORT_TO_SOCKADDR(&saddr, &naddr, port);
2024 
2025   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getaddrname(%d, addr=", s));
2026   ip_addr_debug_print_val(SOCKETS_DEBUG, naddr);
2027   LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F")\n", port));
2028 
2029   if (*namelen > saddr.sa.sa_len) {
2030     *namelen = saddr.sa.sa_len;
2031   }
2032   MEMCPY(name, &saddr, *namelen);
2033 
2034   sock_set_errno(sock, 0);
2035   done_socket(sock);
2036   return 0;
2037 }
2038 
2039 int
2040 lwip_getpeername(int s, struct sockaddr *name, socklen_t *namelen)
2041 {
2042   return lwip_getaddrname(s, name, namelen, 0);
2043 }
2044 
2045 int
2046 lwip_getsockname(int s, struct sockaddr *name, socklen_t *namelen)
2047 {
2048   return lwip_getaddrname(s, name, namelen, 1);
2049 }
2050 
2051 int
2052 lwip_getsockopt(int s, int level, int optname, void *optval, socklen_t *optlen)
2053 {
2054   int err;
2055   struct lwip_sock *sock = get_socket(s);
2056 #if !LWIP_TCPIP_CORE_LOCKING
2057   err_t cberr;
2058   LWIP_SETGETSOCKOPT_DATA_VAR_DECLARE(data);
2059 #endif /* !LWIP_TCPIP_CORE_LOCKING */
2060 
2061   if (!sock) {
2062     return -1;
2063   }
2064 
2065   if ((NULL == optval) || (NULL == optlen)) {
2066     sock_set_errno(sock, EFAULT);
2067     done_socket(sock);
2068     return -1;
2069   }
2070 
2071 #if LWIP_TCPIP_CORE_LOCKING
2072   /* core-locking can just call the -impl function */
2073   LOCK_TCPIP_CORE();
2074   err = lwip_getsockopt_impl(s, level, optname, optval, optlen);
2075   UNLOCK_TCPIP_CORE();
2076 
2077 #else /* LWIP_TCPIP_CORE_LOCKING */
2078 
2079 #if LWIP_MPU_COMPATIBLE
2080   /* MPU_COMPATIBLE copies the optval data, so check for max size here */
2081   if (*optlen > LWIP_SETGETSOCKOPT_MAXOPTLEN) {
2082     sock_set_errno(sock, ENOBUFS);
2083     done_socket(sock);
2084     return -1;
2085   }
2086 #endif /* LWIP_MPU_COMPATIBLE */
2087 
2088   LWIP_SETGETSOCKOPT_DATA_VAR_ALLOC(data, sock);
2089   LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).s = s;
2090   LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).level = level;
2091   LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optname = optname;
2092   LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optlen = *optlen;
2093 #if !LWIP_MPU_COMPATIBLE
2094   LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optval.p = optval;
2095 #endif /* !LWIP_MPU_COMPATIBLE */
2096   LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).err = 0;
2097 #if LWIP_NETCONN_SEM_PER_THREAD
2098   LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).completed_sem = LWIP_NETCONN_THREAD_SEM_GET();
2099 #else
2100   LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).completed_sem = &sock->conn->op_completed;
2101 #endif
2102   cberr = tcpip_callback(lwip_getsockopt_callback, &LWIP_SETGETSOCKOPT_DATA_VAR_REF(data));
2103   if (cberr != ERR_OK) {
2104     LWIP_SETGETSOCKOPT_DATA_VAR_FREE(data);
2105     sock_set_errno(sock, err_to_errno(cberr));
2106     done_socket(sock);
2107     return -1;
2108   }
2109   sys_arch_sem_wait((sys_sem_t*)(LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).completed_sem), 0);
2110 
2111   /* write back optlen and optval */
2112   *optlen = LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optlen;
2113 #if LWIP_MPU_COMPATIBLE
2114   MEMCPY(optval, LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optval,
2115     LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optlen);
2116 #endif /* LWIP_MPU_COMPATIBLE */
2117 
2118   /* maybe lwip_getsockopt_internal has changed err */
2119   err = LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).err;
2120   LWIP_SETGETSOCKOPT_DATA_VAR_FREE(data);
2121 #endif /* LWIP_TCPIP_CORE_LOCKING */
2122 
2123   sock_set_errno(sock, err);
2124   done_socket(sock);
2125   return err ? -1 : 0;
2126 }
2127 
2128 #if !LWIP_TCPIP_CORE_LOCKING
2129 /** lwip_getsockopt_callback: only used without CORE_LOCKING
2130  * to get into the tcpip_thread
2131  */
2132 static void
2133 lwip_getsockopt_callback(void *arg)
2134 {
2135   struct lwip_setgetsockopt_data *data;
2136   LWIP_ASSERT("arg != NULL", arg != NULL);
2137   data = (struct lwip_setgetsockopt_data*)arg;
2138 
2139   data->err = lwip_getsockopt_impl(data->s, data->level, data->optname,
2140 #if LWIP_MPU_COMPATIBLE
2141     data->optval,
2142 #else /* LWIP_MPU_COMPATIBLE */
2143     data->optval.p,
2144 #endif /* LWIP_MPU_COMPATIBLE */
2145     &data->optlen);
2146 
2147   sys_sem_signal((sys_sem_t*)(data->completed_sem));
2148 }
2149 #endif  /* LWIP_TCPIP_CORE_LOCKING */
2150 
2151 /** lwip_getsockopt_impl: the actual implementation of getsockopt:
2152  * same argument as lwip_getsockopt, either called directly or through callback
2153  */
2154 static int
2155 lwip_getsockopt_impl(int s, int level, int optname, void *optval, socklen_t *optlen)
2156 {
2157   int err = 0;
2158   struct lwip_sock *sock = tryget_socket(s);
2159   if (!sock) {
2160     return EBADF;
2161   }
2162 
2163   switch (level) {
2164 
2165 /* Level: SOL_SOCKET */
2166   case SOL_SOCKET:
2167     switch (optname) {
2168 
2169 #if LWIP_TCP
2170     case SO_ACCEPTCONN:
2171       LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, *optlen, int);
2172       if (NETCONNTYPE_GROUP(sock->conn->type) != NETCONN_TCP) {
2173         done_socket(sock);
2174         return ENOPROTOOPT;
2175       }
2176       if ((sock->conn->pcb.tcp != NULL) && (sock->conn->pcb.tcp->state == LISTEN)) {
2177         *(int*)optval = 1;
2178       } else {
2179         *(int*)optval = 0;
2180       }
2181       break;
2182 #endif /* LWIP_TCP */
2183 
2184     /* The option flags */
2185     case SO_BROADCAST:
2186     case SO_KEEPALIVE:
2187 #if SO_REUSE
2188     case SO_REUSEADDR:
2189 #endif /* SO_REUSE */
2190       LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, *optlen, int);
2191       *(int*)optval = ip_get_option(sock->conn->pcb.ip, optname);
2192       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, optname=0x%x, ..) = %s\n",
2193                                   s, optname, (*(int*)optval?"on":"off")));
2194       break;
2195 
2196     case SO_TYPE:
2197       LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, *optlen, int);
2198       switch (NETCONNTYPE_GROUP(netconn_type(sock->conn))) {
2199       case NETCONN_RAW:
2200         *(int*)optval = SOCK_RAW;
2201         break;
2202       case NETCONN_TCP:
2203         *(int*)optval = SOCK_STREAM;
2204         break;
2205       case NETCONN_UDP:
2206         *(int*)optval = SOCK_DGRAM;
2207         break;
2208       default: /* unrecognized socket type */
2209         *(int*)optval = netconn_type(sock->conn);
2210         LWIP_DEBUGF(SOCKETS_DEBUG,
2211                     ("lwip_getsockopt(%d, SOL_SOCKET, SO_TYPE): unrecognized socket type %d\n",
2212                     s, *(int *)optval));
2213       }  /* switch (netconn_type(sock->conn)) */
2214       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, SO_TYPE) = %d\n",
2215                   s, *(int *)optval));
2216       break;
2217 
2218     case SO_ERROR:
2219       LWIP_SOCKOPT_CHECK_OPTLEN(*optlen, int);
2220       /* only overwrite ERR_OK or temporary errors */
2221       if (((sock->err == 0) || (sock->err == EINPROGRESS)) && (sock->conn != NULL)) {
2222         sock_set_errno(sock, err_to_errno(sock->conn->last_err));
2223       }
2224       *(int *)optval = sock->err;
2225       sock->err = 0;
2226       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, SO_ERROR) = %d\n",
2227                   s, *(int *)optval));
2228       break;
2229 
2230 #if LWIP_SO_SNDTIMEO
2231     case SO_SNDTIMEO:
2232       LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, *optlen, LWIP_SO_SNDRCVTIMEO_OPTTYPE);
2233       LWIP_SO_SNDRCVTIMEO_SET(optval, netconn_get_sendtimeout(sock->conn));
2234       break;
2235 #endif /* LWIP_SO_SNDTIMEO */
2236 #if LWIP_SO_RCVTIMEO
2237     case SO_RCVTIMEO:
2238       LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, *optlen, LWIP_SO_SNDRCVTIMEO_OPTTYPE);
2239       LWIP_SO_SNDRCVTIMEO_SET(optval, netconn_get_recvtimeout(sock->conn));
2240       break;
2241 #endif /* LWIP_SO_RCVTIMEO */
2242 #if LWIP_SO_RCVBUF
2243     case SO_RCVBUF:
2244       LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, *optlen, int);
2245       *(int *)optval = netconn_get_recvbufsize(sock->conn);
2246       break;
2247 #endif /* LWIP_SO_RCVBUF */
2248 #if LWIP_SO_LINGER
2249     case SO_LINGER:
2250       {
2251         s16_t conn_linger;
2252         struct linger* linger = (struct linger*)optval;
2253         LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, *optlen, struct linger);
2254         conn_linger = sock->conn->linger;
2255         if (conn_linger >= 0) {
2256           linger->l_onoff = 1;
2257           linger->l_linger = (int)conn_linger;
2258         } else {
2259           linger->l_onoff = 0;
2260           linger->l_linger = 0;
2261         }
2262       }
2263       break;
2264 #endif /* LWIP_SO_LINGER */
2265 #if LWIP_UDP
2266     case SO_NO_CHECK:
2267       LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, *optlen, int, NETCONN_UDP);
2268 #if LWIP_UDPLITE
2269       if ((udp_flags(sock->conn->pcb.udp) & UDP_FLAGS_UDPLITE) != 0) {
2270         /* this flag is only available for UDP, not for UDP lite */
2271         done_socket(sock);
2272         return EAFNOSUPPORT;
2273       }
2274 #endif /* LWIP_UDPLITE */
2275       *(int*)optval = (udp_flags(sock->conn->pcb.udp) & UDP_FLAGS_NOCHKSUM) ? 1 : 0;
2276       break;
2277 #endif /* LWIP_UDP*/
2278     default:
2279       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, UNIMPL: optname=0x%x, ..)\n",
2280                   s, optname));
2281       err = ENOPROTOOPT;
2282       break;
2283     }  /* switch (optname) */
2284     break;
2285 
2286 /* Level: IPPROTO_IP */
2287   case IPPROTO_IP:
2288     switch (optname) {
2289     case IP_TTL:
2290       LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, *optlen, int);
2291       *(int*)optval = sock->conn->pcb.ip->ttl;
2292       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_TTL) = %d\n",
2293                   s, *(int *)optval));
2294       break;
2295     case IP_TOS:
2296       LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, *optlen, int);
2297       *(int*)optval = sock->conn->pcb.ip->tos;
2298       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_TOS) = %d\n",
2299                   s, *(int *)optval));
2300       break;
2301 #if LWIP_IPV4 && LWIP_MULTICAST_TX_OPTIONS
2302     case IP_MULTICAST_TTL:
2303       LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, *optlen, u8_t);
2304       if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_UDP) {
2305         done_socket(sock);
2306         return ENOPROTOOPT;
2307       }
2308       *(u8_t*)optval = udp_get_multicast_ttl(sock->conn->pcb.udp);
2309       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_MULTICAST_TTL) = %d\n",
2310                   s, *(int *)optval));
2311       break;
2312     case IP_MULTICAST_IF:
2313       LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, *optlen, struct in_addr);
2314       if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_UDP) {
2315         done_socket(sock);
2316         return ENOPROTOOPT;
2317       }
2318       inet_addr_from_ip4addr((struct in_addr*)optval, udp_get_multicast_netif_addr(sock->conn->pcb.udp));
2319       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_MULTICAST_IF) = 0x%"X32_F"\n",
2320                   s, *(u32_t *)optval));
2321       break;
2322     case IP_MULTICAST_LOOP:
2323       LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, *optlen, u8_t);
2324       if ((sock->conn->pcb.udp->flags & UDP_FLAGS_MULTICAST_LOOP) != 0) {
2325         *(u8_t*)optval = 1;
2326       } else {
2327         *(u8_t*)optval = 0;
2328       }
2329       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_MULTICAST_LOOP) = %d\n",
2330                   s, *(int *)optval));
2331       break;
2332 #endif /* LWIP_IPV4 && LWIP_MULTICAST_TX_OPTIONS */
2333     default:
2334       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, UNIMPL: optname=0x%x, ..)\n",
2335                   s, optname));
2336       err = ENOPROTOOPT;
2337       break;
2338     }  /* switch (optname) */
2339     break;
2340 
2341 #if LWIP_TCP
2342 /* Level: IPPROTO_TCP */
2343   case IPPROTO_TCP:
2344     /* Special case: all IPPROTO_TCP option take an int */
2345     LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, *optlen, int, NETCONN_TCP);
2346     if (sock->conn->pcb.tcp->state == LISTEN) {
2347       done_socket(sock);
2348       return EINVAL;
2349     }
2350     switch (optname) {
2351     case TCP_NODELAY:
2352       *(int*)optval = tcp_nagle_disabled(sock->conn->pcb.tcp);
2353       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_TCP, TCP_NODELAY) = %s\n",
2354                   s, (*(int*)optval)?"on":"off") );
2355       break;
2356     case TCP_KEEPALIVE:
2357       *(int*)optval = (int)sock->conn->pcb.tcp->keep_idle;
2358       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_TCP, TCP_KEEPALIVE) = %d\n",
2359                   s, *(int *)optval));
2360       break;
2361 
2362 #if LWIP_TCP_KEEPALIVE
2363     case TCP_KEEPIDLE:
2364       *(int*)optval = (int)(sock->conn->pcb.tcp->keep_idle/1000);
2365       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_TCP, TCP_KEEPIDLE) = %d\n",
2366                   s, *(int *)optval));
2367       break;
2368     case TCP_KEEPINTVL:
2369       *(int*)optval = (int)(sock->conn->pcb.tcp->keep_intvl/1000);
2370       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_TCP, TCP_KEEPINTVL) = %d\n",
2371                   s, *(int *)optval));
2372       break;
2373     case TCP_KEEPCNT:
2374       *(int*)optval = (int)sock->conn->pcb.tcp->keep_cnt;
2375       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_TCP, TCP_KEEPCNT) = %d\n",
2376                   s, *(int *)optval));
2377       break;
2378 #endif /* LWIP_TCP_KEEPALIVE */
2379     default:
2380       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_TCP, UNIMPL: optname=0x%x, ..)\n",
2381                   s, optname));
2382       err = ENOPROTOOPT;
2383       break;
2384     }  /* switch (optname) */
2385     break;
2386 #endif /* LWIP_TCP */
2387 
2388 #if LWIP_IPV6
2389 /* Level: IPPROTO_IPV6 */
2390   case IPPROTO_IPV6:
2391     switch (optname) {
2392     case IPV6_V6ONLY:
2393       LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, *optlen, int);
2394       *(int*)optval = (netconn_get_ipv6only(sock->conn) ? 1 : 0);
2395       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IPV6, IPV6_V6ONLY) = %d\n",
2396                   s, *(int *)optval));
2397       break;
2398     default:
2399       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IPV6, UNIMPL: optname=0x%x, ..)\n",
2400                   s, optname));
2401       err = ENOPROTOOPT;
2402       break;
2403     }  /* switch (optname) */
2404     break;
2405 #endif /* LWIP_IPV6 */
2406 
2407 #if LWIP_UDP && LWIP_UDPLITE
2408   /* Level: IPPROTO_UDPLITE */
2409   case IPPROTO_UDPLITE:
2410     /* Special case: all IPPROTO_UDPLITE option take an int */
2411     LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, *optlen, int);
2412     /* If this is no UDP lite socket, ignore any options. */
2413     if (!NETCONNTYPE_ISUDPLITE(netconn_type(sock->conn))) {
2414       done_socket(sock);
2415       return ENOPROTOOPT;
2416     }
2417     switch (optname) {
2418     case UDPLITE_SEND_CSCOV:
2419       *(int*)optval = sock->conn->pcb.udp->chksum_len_tx;
2420       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_UDPLITE, UDPLITE_SEND_CSCOV) = %d\n",
2421                   s, (*(int*)optval)) );
2422       break;
2423     case UDPLITE_RECV_CSCOV:
2424       *(int*)optval = sock->conn->pcb.udp->chksum_len_rx;
2425       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_UDPLITE, UDPLITE_RECV_CSCOV) = %d\n",
2426                   s, (*(int*)optval)) );
2427       break;
2428     default:
2429       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_UDPLITE, UNIMPL: optname=0x%x, ..)\n",
2430                   s, optname));
2431       err = ENOPROTOOPT;
2432       break;
2433     }  /* switch (optname) */
2434     break;
2435 #endif /* LWIP_UDP */
2436   /* Level: IPPROTO_RAW */
2437   case IPPROTO_RAW:
2438     switch (optname) {
2439 #if LWIP_IPV6 && LWIP_RAW
2440     case IPV6_CHECKSUM:
2441       LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, *optlen, int, NETCONN_RAW);
2442       if (sock->conn->pcb.raw->chksum_reqd == 0) {
2443         *(int *)optval = -1;
2444       } else {
2445         *(int *)optval = sock->conn->pcb.raw->chksum_offset;
2446       }
2447       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_RAW, IPV6_CHECKSUM) = %d\n",
2448                   s, (*(int*)optval)) );
2449       break;
2450 #endif /* LWIP_IPV6 && LWIP_RAW */
2451     default:
2452       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_RAW, UNIMPL: optname=0x%x, ..)\n",
2453                   s, optname));
2454       err = ENOPROTOOPT;
2455       break;
2456     }  /* switch (optname) */
2457     break;
2458   default:
2459     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, level=0x%x, UNIMPL: optname=0x%x, ..)\n",
2460                                 s, level, optname));
2461     err = ENOPROTOOPT;
2462     break;
2463   } /* switch (level) */
2464 
2465   done_socket(sock);
2466   return err;
2467 }
2468 
2469 int
2470 lwip_setsockopt(int s, int level, int optname, const void *optval, socklen_t optlen)
2471 {
2472   int err = 0;
2473   struct lwip_sock *sock = get_socket(s);
2474 #if !LWIP_TCPIP_CORE_LOCKING
2475   err_t cberr;
2476   LWIP_SETGETSOCKOPT_DATA_VAR_DECLARE(data);
2477 #endif /* !LWIP_TCPIP_CORE_LOCKING */
2478 
2479   if (!sock) {
2480     return -1;
2481   }
2482 
2483   if (NULL == optval) {
2484     sock_set_errno(sock, EFAULT);
2485     done_socket(sock);
2486     return -1;
2487   }
2488 
2489 #if LWIP_TCPIP_CORE_LOCKING
2490   /* core-locking can just call the -impl function */
2491   LOCK_TCPIP_CORE();
2492   err = lwip_setsockopt_impl(s, level, optname, optval, optlen);
2493   UNLOCK_TCPIP_CORE();
2494 
2495 #else /* LWIP_TCPIP_CORE_LOCKING */
2496 
2497 #if LWIP_MPU_COMPATIBLE
2498   /* MPU_COMPATIBLE copies the optval data, so check for max size here */
2499   if (optlen > LWIP_SETGETSOCKOPT_MAXOPTLEN) {
2500     sock_set_errno(sock, ENOBUFS);
2501     done_socket(sock);
2502     return -1;
2503   }
2504 #endif /* LWIP_MPU_COMPATIBLE */
2505 
2506   LWIP_SETGETSOCKOPT_DATA_VAR_ALLOC(data, sock);
2507   LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).s = s;
2508   LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).level = level;
2509   LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optname = optname;
2510   LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optlen = optlen;
2511 #if LWIP_MPU_COMPATIBLE
2512   MEMCPY(LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optval, optval, optlen);
2513 #else /* LWIP_MPU_COMPATIBLE */
2514   LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optval.pc = (const void*)optval;
2515 #endif /* LWIP_MPU_COMPATIBLE */
2516   LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).err = 0;
2517 #if LWIP_NETCONN_SEM_PER_THREAD
2518   LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).completed_sem = LWIP_NETCONN_THREAD_SEM_GET();
2519 #else
2520   LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).completed_sem = &sock->conn->op_completed;
2521 #endif
2522   cberr = tcpip_callback(lwip_setsockopt_callback, &LWIP_SETGETSOCKOPT_DATA_VAR_REF(data));
2523   if (cberr != ERR_OK) {
2524     LWIP_SETGETSOCKOPT_DATA_VAR_FREE(data);
2525     sock_set_errno(sock, err_to_errno(cberr));
2526     done_socket(sock);
2527     return -1;
2528   }
2529   sys_arch_sem_wait((sys_sem_t*)(LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).completed_sem), 0);
2530 
2531   /* maybe lwip_getsockopt_internal has changed err */
2532   err = LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).err;
2533   LWIP_SETGETSOCKOPT_DATA_VAR_FREE(data);
2534 #endif  /* LWIP_TCPIP_CORE_LOCKING */
2535 
2536   sock_set_errno(sock, err);
2537   done_socket(sock);
2538   return err ? -1 : 0;
2539 }
2540 
2541 #if !LWIP_TCPIP_CORE_LOCKING
2542 /** lwip_setsockopt_callback: only used without CORE_LOCKING
2543  * to get into the tcpip_thread
2544  */
2545 static void
2546 lwip_setsockopt_callback(void *arg)
2547 {
2548   struct lwip_setgetsockopt_data *data;
2549   LWIP_ASSERT("arg != NULL", arg != NULL);
2550   data = (struct lwip_setgetsockopt_data*)arg;
2551 
2552   data->err = lwip_setsockopt_impl(data->s, data->level, data->optname,
2553 #if LWIP_MPU_COMPATIBLE
2554     data->optval,
2555 #else /* LWIP_MPU_COMPATIBLE */
2556     data->optval.pc,
2557 #endif /* LWIP_MPU_COMPATIBLE */
2558     data->optlen);
2559 
2560   sys_sem_signal((sys_sem_t*)(data->completed_sem));
2561 }
2562 #endif  /* LWIP_TCPIP_CORE_LOCKING */
2563 
2564 /** lwip_setsockopt_impl: the actual implementation of setsockopt:
2565  * same argument as lwip_setsockopt, either called directly or through callback
2566  */
2567 static int
2568 lwip_setsockopt_impl(int s, int level, int optname, const void *optval, socklen_t optlen)
2569 {
2570   int err = 0;
2571   struct lwip_sock *sock = tryget_socket(s);
2572   if (!sock) {
2573     return EBADF;
2574   }
2575 
2576   switch (level) {
2577 
2578 /* Level: SOL_SOCKET */
2579   case SOL_SOCKET:
2580     switch (optname) {
2581 
2582     /* SO_ACCEPTCONN is get-only */
2583 
2584     /* The option flags */
2585     case SO_BROADCAST:
2586     case SO_KEEPALIVE:
2587 #if SO_REUSE
2588     case SO_REUSEADDR:
2589 #endif /* SO_REUSE */
2590       LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, optlen, int);
2591       if (*(const int*)optval) {
2592         ip_set_option(sock->conn->pcb.ip, optname);
2593       } else {
2594         ip_reset_option(sock->conn->pcb.ip, optname);
2595       }
2596       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, SOL_SOCKET, optname=0x%x, ..) -> %s\n",
2597                   s, optname, (*(const int*)optval?"on":"off")));
2598       break;
2599 
2600     /* SO_TYPE is get-only */
2601     /* SO_ERROR is get-only */
2602 
2603 #if LWIP_SO_SNDTIMEO
2604     case SO_SNDTIMEO:
2605       LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, optlen, LWIP_SO_SNDRCVTIMEO_OPTTYPE);
2606       netconn_set_sendtimeout(sock->conn, LWIP_SO_SNDRCVTIMEO_GET_MS(optval));
2607       break;
2608 #endif /* LWIP_SO_SNDTIMEO */
2609 #if LWIP_SO_RCVTIMEO
2610     case SO_RCVTIMEO:
2611       LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, optlen, LWIP_SO_SNDRCVTIMEO_OPTTYPE);
2612       netconn_set_recvtimeout(sock->conn, (int)LWIP_SO_SNDRCVTIMEO_GET_MS(optval));
2613       break;
2614 #endif /* LWIP_SO_RCVTIMEO */
2615 #if LWIP_SO_RCVBUF
2616     case SO_RCVBUF:
2617       LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, optlen, int);
2618       netconn_set_recvbufsize(sock->conn, *(const int*)optval);
2619       break;
2620 #endif /* LWIP_SO_RCVBUF */
2621 #if LWIP_SO_LINGER
2622     case SO_LINGER:
2623       {
2624         const struct linger* linger = (const struct linger*)optval;
2625         LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, optlen, struct linger);
2626         if (linger->l_onoff) {
2627           int lingersec = linger->l_linger;
2628           if (lingersec < 0) {
2629             done_socket(sock);
2630             return EINVAL;
2631           }
2632           if (lingersec > 0xFFFF) {
2633             lingersec = 0xFFFF;
2634           }
2635           sock->conn->linger = (s16_t)lingersec;
2636         } else {
2637           sock->conn->linger = -1;
2638         }
2639       }
2640       break;
2641 #endif /* LWIP_SO_LINGER */
2642 #if LWIP_UDP
2643     case SO_NO_CHECK:
2644       LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, int, NETCONN_UDP);
2645 #if LWIP_UDPLITE
2646       if ((udp_flags(sock->conn->pcb.udp) & UDP_FLAGS_UDPLITE) != 0) {
2647         /* this flag is only available for UDP, not for UDP lite */
2648         done_socket(sock);
2649         return EAFNOSUPPORT;
2650       }
2651 #endif /* LWIP_UDPLITE */
2652       if (*(const int*)optval) {
2653         udp_setflags(sock->conn->pcb.udp, udp_flags(sock->conn->pcb.udp) | UDP_FLAGS_NOCHKSUM);
2654       } else {
2655         udp_setflags(sock->conn->pcb.udp, udp_flags(sock->conn->pcb.udp) & ~UDP_FLAGS_NOCHKSUM);
2656       }
2657       break;
2658 #endif /* LWIP_UDP */
2659     default:
2660       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, SOL_SOCKET, UNIMPL: optname=0x%x, ..)\n",
2661                   s, optname));
2662       err = ENOPROTOOPT;
2663       break;
2664     }  /* switch (optname) */
2665     break;
2666 
2667 /* Level: IPPROTO_IP */
2668   case IPPROTO_IP:
2669     switch (optname) {
2670     case IP_TTL:
2671       LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, optlen, int);
2672       sock->conn->pcb.ip->ttl = (u8_t)(*(const int*)optval);
2673       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IP, IP_TTL, ..) -> %d\n",
2674                   s, sock->conn->pcb.ip->ttl));
2675       break;
2676     case IP_TOS:
2677       LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, optlen, int);
2678       sock->conn->pcb.ip->tos = (u8_t)(*(const int*)optval);
2679       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IP, IP_TOS, ..)-> %d\n",
2680                   s, sock->conn->pcb.ip->tos));
2681       break;
2682 #if LWIP_IPV4 && LWIP_MULTICAST_TX_OPTIONS
2683     case IP_MULTICAST_TTL:
2684       LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, u8_t, NETCONN_UDP);
2685       udp_set_multicast_ttl(sock->conn->pcb.udp, (u8_t)(*(const u8_t*)optval));
2686       break;
2687     case IP_MULTICAST_IF:
2688       {
2689         ip4_addr_t if_addr;
2690         LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, struct in_addr, NETCONN_UDP);
2691         inet_addr_to_ip4addr(&if_addr, (const struct in_addr*)optval);
2692         udp_set_multicast_netif_addr(sock->conn->pcb.udp, &if_addr);
2693       }
2694       break;
2695     case IP_MULTICAST_LOOP:
2696       LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, u8_t, NETCONN_UDP);
2697       if (*(const u8_t*)optval) {
2698         udp_setflags(sock->conn->pcb.udp, udp_flags(sock->conn->pcb.udp) | UDP_FLAGS_MULTICAST_LOOP);
2699       } else {
2700         udp_setflags(sock->conn->pcb.udp, udp_flags(sock->conn->pcb.udp) & ~UDP_FLAGS_MULTICAST_LOOP);
2701       }
2702       break;
2703 #endif /* LWIP_IPV4 && LWIP_MULTICAST_TX_OPTIONS */
2704 #if LWIP_IGMP
2705     case IP_ADD_MEMBERSHIP:
2706     case IP_DROP_MEMBERSHIP:
2707       {
2708         /* If this is a TCP or a RAW socket, ignore these options. */
2709         /* @todo: assign membership to this socket so that it is dropped when closing the socket */
2710         err_t igmp_err;
2711         const struct ip_mreq *imr = (const struct ip_mreq *)optval;
2712         ip4_addr_t if_addr;
2713         ip4_addr_t multi_addr;
2714         LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, struct ip_mreq, NETCONN_UDP);
2715         inet_addr_to_ip4addr(&if_addr, &imr->imr_interface);
2716         inet_addr_to_ip4addr(&multi_addr, &imr->imr_multiaddr);
2717         if (optname == IP_ADD_MEMBERSHIP) {
2718           if (!lwip_socket_register_membership(s, &if_addr, &multi_addr)) {
2719             /* cannot track membership (out of memory) */
2720             err = ENOMEM;
2721             igmp_err = ERR_OK;
2722           } else {
2723             igmp_err = igmp_joingroup(&if_addr, &multi_addr);
2724           }
2725         } else {
2726           igmp_err = igmp_leavegroup(&if_addr, &multi_addr);
2727           lwip_socket_unregister_membership(s, &if_addr, &multi_addr);
2728         }
2729         if (igmp_err != ERR_OK) {
2730           err = EADDRNOTAVAIL;
2731         }
2732       }
2733       break;
2734 #endif /* LWIP_IGMP */
2735     default:
2736       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IP, UNIMPL: optname=0x%x, ..)\n",
2737                   s, optname));
2738       err = ENOPROTOOPT;
2739       break;
2740     }  /* switch (optname) */
2741     break;
2742 
2743 #if LWIP_TCP
2744 /* Level: IPPROTO_TCP */
2745   case IPPROTO_TCP:
2746     /* Special case: all IPPROTO_TCP option take an int */
2747     LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, int, NETCONN_TCP);
2748     if (sock->conn->pcb.tcp->state == LISTEN) {
2749       done_socket(sock);
2750       return EINVAL;
2751     }
2752     switch (optname) {
2753     case TCP_NODELAY:
2754       if (*(const int*)optval) {
2755         tcp_nagle_disable(sock->conn->pcb.tcp);
2756       } else {
2757         tcp_nagle_enable(sock->conn->pcb.tcp);
2758       }
2759       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_NODELAY) -> %s\n",
2760                   s, (*(const int *)optval)?"on":"off") );
2761       break;
2762     case TCP_KEEPALIVE:
2763       sock->conn->pcb.tcp->keep_idle = (u32_t)(*(const int*)optval);
2764       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPALIVE) -> %"U32_F"\n",
2765                   s, sock->conn->pcb.tcp->keep_idle));
2766       break;
2767 
2768 #if LWIP_TCP_KEEPALIVE
2769     case TCP_KEEPIDLE:
2770       sock->conn->pcb.tcp->keep_idle = 1000*(u32_t)(*(const int*)optval);
2771       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPIDLE) -> %"U32_F"\n",
2772                   s, sock->conn->pcb.tcp->keep_idle));
2773       break;
2774     case TCP_KEEPINTVL:
2775       sock->conn->pcb.tcp->keep_intvl = 1000*(u32_t)(*(const int*)optval);
2776       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPINTVL) -> %"U32_F"\n",
2777                   s, sock->conn->pcb.tcp->keep_intvl));
2778       break;
2779     case TCP_KEEPCNT:
2780       sock->conn->pcb.tcp->keep_cnt = (u32_t)(*(const int*)optval);
2781       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPCNT) -> %"U32_F"\n",
2782                   s, sock->conn->pcb.tcp->keep_cnt));
2783       break;
2784 #endif /* LWIP_TCP_KEEPALIVE */
2785     default:
2786       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, UNIMPL: optname=0x%x, ..)\n",
2787                   s, optname));
2788       err = ENOPROTOOPT;
2789       break;
2790     }  /* switch (optname) */
2791     break;
2792 #endif /* LWIP_TCP*/
2793 
2794 #if LWIP_IPV6
2795 /* Level: IPPROTO_IPV6 */
2796   case IPPROTO_IPV6:
2797     switch (optname) {
2798     case IPV6_V6ONLY:
2799       LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, int, NETCONN_TCP);
2800       if (*(const int*)optval) {
2801         netconn_set_ipv6only(sock->conn, 1);
2802       } else {
2803         netconn_set_ipv6only(sock->conn, 0);
2804       }
2805       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IPV6, IPV6_V6ONLY, ..) -> %d\n",
2806                   s, (netconn_get_ipv6only(sock->conn) ? 1 : 0)));
2807       break;
2808     default:
2809       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IPV6, UNIMPL: optname=0x%x, ..)\n",
2810                   s, optname));
2811       err = ENOPROTOOPT;
2812       break;
2813     }  /* switch (optname) */
2814     break;
2815 #endif /* LWIP_IPV6 */
2816 
2817 #if LWIP_UDP && LWIP_UDPLITE
2818   /* Level: IPPROTO_UDPLITE */
2819   case IPPROTO_UDPLITE:
2820     /* Special case: all IPPROTO_UDPLITE option take an int */
2821     LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, optlen, int);
2822     /* If this is no UDP lite socket, ignore any options. */
2823     if (!NETCONNTYPE_ISUDPLITE(netconn_type(sock->conn))) {
2824       done_socket(sock);
2825       return ENOPROTOOPT;
2826     }
2827     switch (optname) {
2828     case UDPLITE_SEND_CSCOV:
2829       if ((*(const int*)optval != 0) && ((*(const int*)optval < 8) || (*(const int*)optval > 0xffff))) {
2830         /* don't allow illegal values! */
2831         sock->conn->pcb.udp->chksum_len_tx = 8;
2832       } else {
2833         sock->conn->pcb.udp->chksum_len_tx = (u16_t)*(const int*)optval;
2834       }
2835       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_UDPLITE, UDPLITE_SEND_CSCOV) -> %d\n",
2836                   s, (*(const int*)optval)) );
2837       break;
2838     case UDPLITE_RECV_CSCOV:
2839       if ((*(const int*)optval != 0) && ((*(const int*)optval < 8) || (*(const int*)optval > 0xffff))) {
2840         /* don't allow illegal values! */
2841         sock->conn->pcb.udp->chksum_len_rx = 8;
2842       } else {
2843         sock->conn->pcb.udp->chksum_len_rx = (u16_t)*(const int*)optval;
2844       }
2845       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_UDPLITE, UDPLITE_RECV_CSCOV) -> %d\n",
2846                   s, (*(const int*)optval)) );
2847       break;
2848     default:
2849       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_UDPLITE, UNIMPL: optname=0x%x, ..)\n",
2850                   s, optname));
2851       err = ENOPROTOOPT;
2852       break;
2853     }  /* switch (optname) */
2854     break;
2855 #endif /* LWIP_UDP */
2856   /* Level: IPPROTO_RAW */
2857   case IPPROTO_RAW:
2858     switch (optname) {
2859 #if LWIP_IPV6 && LWIP_RAW
2860     case IPV6_CHECKSUM:
2861       /* It should not be possible to disable the checksum generation with ICMPv6
2862        * as per RFC 3542 chapter 3.1 */
2863       if(sock->conn->pcb.raw->protocol == IPPROTO_ICMPV6) {
2864         done_socket(sock);
2865         return EINVAL;
2866       }
2867 
2868       LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, int, NETCONN_RAW);
2869       if (*(const int *)optval < 0) {
2870         sock->conn->pcb.raw->chksum_reqd = 0;
2871       } else if (*(const int *)optval & 1) {
2872         /* Per RFC3542, odd offsets are not allowed */
2873         done_socket(sock);
2874         return EINVAL;
2875       } else {
2876         sock->conn->pcb.raw->chksum_reqd = 1;
2877         sock->conn->pcb.raw->chksum_offset = (u16_t)*(const int *)optval;
2878       }
2879       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_RAW, IPV6_CHECKSUM, ..) -> %d\n",
2880                   s, sock->conn->pcb.raw->chksum_reqd));
2881       break;
2882 #endif /* LWIP_IPV6 && LWIP_RAW */
2883     default:
2884       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_RAW, UNIMPL: optname=0x%x, ..)\n",
2885                                   s, optname));
2886       err = ENOPROTOOPT;
2887       break;
2888     }  /* switch (optname) */
2889     break;
2890   default:
2891     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, level=0x%x, UNIMPL: optname=0x%x, ..)\n",
2892                 s, level, optname));
2893     err = ENOPROTOOPT;
2894     break;
2895   }  /* switch (level) */
2896 
2897   done_socket(sock);
2898   return err;
2899 }
2900 
2901 int
2902 lwip_ioctl(int s, long cmd, void *argp)
2903 {
2904   struct lwip_sock *sock = get_socket(s);
2905   u8_t val;
2906 #if LWIP_SO_RCVBUF
2907   int recv_avail;
2908 #endif /* LWIP_SO_RCVBUF */
2909 
2910   if (!sock) {
2911     return -1;
2912   }
2913 
2914   switch (cmd) {
2915 #if LWIP_SO_RCVBUF || LWIP_FIONREAD_LINUXMODE
2916   case FIONREAD:
2917     if (!argp) {
2918       sock_set_errno(sock, EINVAL);
2919       done_socket(sock);
2920       return -1;
2921     }
2922 #if LWIP_FIONREAD_LINUXMODE
2923     if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_TCP) {
2924       struct netbuf *nb;
2925       if (sock->lastdata.netbuf) {
2926         nb = sock->lastdata.netbuf;
2927         *((int*)argp) = nb->p->tot_len;
2928       } else {
2929         struct netbuf *rxbuf;
2930         err_t err = netconn_recv_udp_raw_netbuf_flags(sock->conn, &rxbuf, NETCONN_DONTBLOCK);
2931         if (err != ERR_OK) {
2932           *((int*)argp) = 0;
2933         } else {
2934           sock->lastdata.netbuf = rxbuf;
2935           *((int*)argp) = rxbuf->p->tot_len;
2936         }
2937       }
2938       done_socket(sock);
2939       return 0;
2940     }
2941 #endif /* LWIP_FIONREAD_LINUXMODE */
2942 
2943 #if LWIP_SO_RCVBUF
2944     /* we come here if either LWIP_FIONREAD_LINUXMODE==0 or this is a TCP socket */
2945     SYS_ARCH_GET(sock->conn->recv_avail, recv_avail);
2946     if (recv_avail < 0) {
2947       recv_avail = 0;
2948     }
2949 
2950     /* Check if there is data left from the last recv operation. /maq 041215 */
2951     if (sock->lastdata.netbuf) {
2952       if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_TCP) {
2953         recv_avail += sock->lastdata.pbuf->tot_len;
2954       } else {
2955         recv_avail += sock->lastdata.netbuf->p->tot_len;
2956       }
2957     }
2958     *((int*)argp) = recv_avail;
2959 
2960     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(%d, FIONREAD, %p) = %"U16_F"\n", s, argp, *((u16_t*)argp)));
2961     sock_set_errno(sock, 0);
2962     done_socket(sock);
2963     return 0;
2964 #else /* LWIP_SO_RCVBUF */
2965     break;
2966 #endif /* LWIP_SO_RCVBUF */
2967 #endif /* LWIP_SO_RCVBUF || LWIP_FIONREAD_LINUXMODE */
2968 
2969   case (long)FIONBIO:
2970     val = 0;
2971     if (argp && *(u32_t*)argp) {
2972       val = 1;
2973     }
2974     netconn_set_nonblocking(sock->conn, val);
2975     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(%d, FIONBIO, %d)\n", s, val));
2976     sock_set_errno(sock, 0);
2977     done_socket(sock);
2978     return 0;
2979 
2980   default:
2981     break;
2982   } /* switch (cmd) */
2983   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(%d, UNIMPL: 0x%lx, %p)\n", s, cmd, argp));
2984   sock_set_errno(sock, ENOSYS); /* not yet implemented */
2985   done_socket(sock);
2986   return -1;
2987 }
2988 
2989 /** A minimal implementation of fcntl.
2990  * Currently only the commands F_GETFL and F_SETFL are implemented.
2991  * Only the flag O_NONBLOCK is implemented.
2992  */
2993 int
2994 lwip_fcntl(int s, int cmd, int val)
2995 {
2996   struct lwip_sock *sock = get_socket(s);
2997   int ret = -1;
2998 
2999   if (!sock) {
3000     return -1;
3001   }
3002 
3003   switch (cmd) {
3004   case F_GETFL:
3005     ret = netconn_is_nonblocking(sock->conn) ? O_NONBLOCK : 0;
3006     sock_set_errno(sock, 0);
3007     break;
3008   case F_SETFL:
3009     if ((val & ~O_NONBLOCK) == 0) {
3010       /* only O_NONBLOCK, all other bits are zero */
3011       netconn_set_nonblocking(sock->conn, val & O_NONBLOCK);
3012       ret = 0;
3013       sock_set_errno(sock, 0);
3014     } else {
3015       sock_set_errno(sock, ENOSYS); /* not yet implemented */
3016     }
3017     break;
3018   default:
3019     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_fcntl(%d, UNIMPL: %d, %d)\n", s, cmd, val));
3020     sock_set_errno(sock, ENOSYS); /* not yet implemented */
3021     break;
3022   }
3023   done_socket(sock);
3024   return ret;
3025 }
3026 
3027 #if LWIP_IGMP
3028 /** Register a new IGMP membership. On socket close, the membership is dropped automatically.
3029  *
3030  * ATTENTION: this function is called from tcpip_thread (or under CORE_LOCK).
3031  *
3032  * @return 1 on success, 0 on failure
3033  */
3034 static int
3035 lwip_socket_register_membership(int s, const ip4_addr_t *if_addr, const ip4_addr_t *multi_addr)
3036 {
3037   struct lwip_sock *sock = get_socket(s);
3038   int i;
3039 
3040   if (!sock) {
3041     return 0;
3042   }
3043 
3044   for (i = 0; i < LWIP_SOCKET_MAX_MEMBERSHIPS; i++) {
3045     if (socket_ipv4_multicast_memberships[i].sock == NULL) {
3046       socket_ipv4_multicast_memberships[i].sock = sock;
3047       ip4_addr_copy(socket_ipv4_multicast_memberships[i].if_addr, *if_addr);
3048       ip4_addr_copy(socket_ipv4_multicast_memberships[i].multi_addr, *multi_addr);
3049       done_socket(sock);
3050       return 1;
3051     }
3052   }
3053   done_socket(sock);
3054   return 0;
3055 }
3056 
3057 /** Unregister a previously registered membership. This prevents dropping the membership
3058  * on socket close.
3059  *
3060  * ATTENTION: this function is called from tcpip_thread (or under CORE_LOCK).
3061  */
3062 static void
3063 lwip_socket_unregister_membership(int s, const ip4_addr_t *if_addr, const ip4_addr_t *multi_addr)
3064 {
3065   struct lwip_sock *sock = get_socket(s);
3066   int i;
3067 
3068   if (!sock) {
3069     return;
3070   }
3071 
3072   for (i = 0; i < LWIP_SOCKET_MAX_MEMBERSHIPS; i++) {
3073     if ((socket_ipv4_multicast_memberships[i].sock == sock) &&
3074         ip4_addr_cmp(&socket_ipv4_multicast_memberships[i].if_addr, if_addr) &&
3075         ip4_addr_cmp(&socket_ipv4_multicast_memberships[i].multi_addr, multi_addr)) {
3076       socket_ipv4_multicast_memberships[i].sock = NULL;
3077       ip4_addr_set_zero(&socket_ipv4_multicast_memberships[i].if_addr);
3078       ip4_addr_set_zero(&socket_ipv4_multicast_memberships[i].multi_addr);
3079       break;
3080     }
3081   }
3082   done_socket(sock);
3083 }
3084 
3085 /** Drop all memberships of a socket that were not dropped explicitly via setsockopt.
3086  *
3087  * ATTENTION: this function is NOT called from tcpip_thread (or under CORE_LOCK).
3088  */
3089 static void
3090 lwip_socket_drop_registered_memberships(int s)
3091 {
3092   struct lwip_sock *sock = get_socket(s);
3093   int i;
3094 
3095   if (!sock) {
3096     return;
3097   }
3098 
3099   for (i = 0; i < LWIP_SOCKET_MAX_MEMBERSHIPS; i++) {
3100     if (socket_ipv4_multicast_memberships[i].sock == sock) {
3101       ip_addr_t multi_addr, if_addr;
3102       ip_addr_copy_from_ip4(multi_addr, socket_ipv4_multicast_memberships[i].multi_addr);
3103       ip_addr_copy_from_ip4(if_addr, socket_ipv4_multicast_memberships[i].if_addr);
3104       socket_ipv4_multicast_memberships[i].sock = NULL;
3105       ip4_addr_set_zero(&socket_ipv4_multicast_memberships[i].if_addr);
3106       ip4_addr_set_zero(&socket_ipv4_multicast_memberships[i].multi_addr);
3107 
3108       netconn_join_leave_group(sock->conn, &multi_addr, &if_addr, NETCONN_LEAVE);
3109     }
3110   }
3111   done_socket(sock);
3112 }
3113 #endif /* LWIP_IGMP */
3114 #endif /* LWIP_SOCKET */
3115