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