1 /**
2  * @file
3  * Sockets BSD-Like API module
4  *
5  */
6 
7 /*
8  * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
9  * All rights reserved.
10  *
11  * Redistribution and use in source and binary forms, with or without modification,
12  * are permitted provided that the following conditions are met:
13  *
14  * 1. Redistributions of source code must retain the above copyright notice,
15  *    this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright notice,
17  *    this list of conditions and the following disclaimer in the documentation
18  *    and/or other materials provided with the distribution.
19  * 3. The name of the author may not be used to endorse or promote products
20  *    derived from this software without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
23  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
24  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
25  * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
26  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
27  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
30  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
31  * OF SUCH DAMAGE.
32  *
33  * This file is part of the lwIP TCP/IP stack.
34  *
35  * Author: Adam Dunkels <adam@sics.se>
36  *
37  * Improved by Marc Boucher <marc@mbsi.ca> and David Haas <dhaas@alum.rpi.edu>
38  *
39  */
40 
41 #include "lwip/opt.h"
42 
43 #if LWIP_SOCKET /* don't build if not configured for use in lwipopts.h */
44 
45 #include "lwip/sockets.h"
46 #include "lwip/api.h"
47 #include "lwip/sys.h"
48 #include "lwip/igmp.h"
49 #include "lwip/inet.h"
50 #include "lwip/tcp.h"
51 #include "lwip/raw.h"
52 #include "lwip/udp.h"
53 #include "lwip/tcpip.h"
54 #include "lwip/pbuf.h"
55 #if LWIP_CHECKSUM_ON_COPY
56 #include "lwip/inet_chksum.h"
57 #endif
58 
59 #include <string.h>
60 
61 #define NUM_SOCKETS MEMP_NUM_NETCONN
62 
63 /** Contains all internal pointers and states used for a socket */
64 struct lwip_sock {
65   /** sockets currently are built on netconns, each socket has one netconn */
66   struct netconn *conn;
67   /** data that was left from the previous read */
68   void *lastdata;
69   /** offset in the data that was left from the previous read */
70   u16_t lastoffset;
71   /** number of times data was received, set by event_callback(),
72       tested by the receive and select functions */
73   s16_t rcvevent;
74   /** number of times data was ACKed (free send buffer), set by event_callback(),
75       tested by select */
76   u16_t sendevent;
77   /** error happened for this socket, set by event_callback(), tested by select */
78   u16_t errevent;
79   /** last error that occurred on this socket */
80   int err;
81   /** counter of how many threads are waiting for this socket using select */
82   int select_waiting;
83 };
84 
85 /** Description for a task waiting in select */
86 struct lwip_select_cb {
87   /** Pointer to the next waiting task */
88   struct lwip_select_cb *next;
89   /** Pointer to the previous waiting task */
90   struct lwip_select_cb *prev;
91   /** readset passed to select */
92   fd_set *readset;
93   /** writeset passed to select */
94   fd_set *writeset;
95   /** unimplemented: exceptset passed to select */
96   fd_set *exceptset;
97   /** don't signal the same semaphore twice: set to 1 when signalled */
98   int sem_signalled;
99   /** semaphore to wake up a task waiting for select */
100   sys_sem_t sem;
101 };
102 
103 /** This struct is used to pass data to the set/getsockopt_internal
104  * functions running in tcpip_thread context (only a void* is allowed) */
105 struct lwip_setgetsockopt_data {
106   /** socket struct for which to change options */
107   struct lwip_sock *sock;
108 #ifdef LWIP_DEBUG
109   /** socket index for which to change options */
110   int s;
111 #endif /* LWIP_DEBUG */
112   /** level of the option to process */
113   int level;
114   /** name of the option to process */
115   int optname;
116   /** set: value to set the option to
117     * get: value of the option is stored here */
118   void *optval;
119   /** size of *optval */
120   socklen_t *optlen;
121   /** if an error occures, it is temporarily stored here */
122   err_t err;
123 };
124 
125 /** The global array of available sockets */
126 static struct lwip_sock sockets[NUM_SOCKETS];
127 /** The global list of tasks waiting for select */
128 static struct lwip_select_cb *select_cb_list;
129 /** This counter is increased from lwip_select when the list is chagned
130     and checked in event_callback to see if it has changed. */
131 static volatile int select_cb_ctr;
132 
133 /** Table to quickly map an lwIP error (err_t) to a socket error
134   * by using -err as an index */
135 static const int err_to_errno_table[] = {
136   0,             /* ERR_OK          0      No error, everything OK. */
137   ENOMEM,        /* ERR_MEM        -1      Out of memory error.     */
138   ENOBUFS,       /* ERR_BUF        -2      Buffer error.            */
139   EWOULDBLOCK,   /* ERR_TIMEOUT    -3      Timeout                  */
140   EHOSTUNREACH,  /* ERR_RTE        -4      Routing problem.         */
141   EINPROGRESS,   /* ERR_INPROGRESS -5      Operation in progress    */
142   EINVAL,        /* ERR_VAL        -6      Illegal value.           */
143   EWOULDBLOCK,   /* ERR_WOULDBLOCK -7      Operation would block.   */
144   EADDRINUSE,    /* ERR_USE        -8      Address in use.          */
145   EALREADY,      /* ERR_ISCONN     -9      Already connected.       */
146   ECONNABORTED,  /* ERR_ABRT       -10     Connection aborted.      */
147   ECONNRESET,    /* ERR_RST        -11     Connection reset.        */
148   ENOTCONN,      /* ERR_CLSD       -12     Connection closed.       */
149   ENOTCONN,      /* ERR_CONN       -13     Not connected.           */
150   EIO,           /* ERR_ARG        -14     Illegal argument.        */
151   -1,            /* ERR_IF         -15     Low-level netif error    */
152 };
153 
154 #define ERR_TO_ERRNO_TABLE_SIZE \
155   (sizeof(err_to_errno_table)/sizeof(err_to_errno_table[0]))
156 
157 #define err_to_errno(err) \
158   ((unsigned)(-(err)) < ERR_TO_ERRNO_TABLE_SIZE ? \
159     err_to_errno_table[-(err)] : EIO)
160 
161 #ifdef ERRNO
162 #ifndef set_errno
163 #define set_errno(err) errno = (err)
164 #endif
165 #else /* ERRNO */
166 #define set_errno(err)
167 #endif /* ERRNO */
168 
169 #define sock_set_errno(sk, e) do { \
170   sk->err = (e); \
171   set_errno(sk->err); \
172 } while (0)
173 
174 /* Forward delcaration of some functions */
175 static void event_callback(struct netconn *conn, enum netconn_evt evt, u16_t len);
176 static void lwip_getsockopt_internal(void *arg);
177 static void lwip_setsockopt_internal(void *arg);
178 
179 /**
180  * Initialize this module. This function has to be called before any other
181  * functions in this module!
182  */
183 void
184 lwip_socket_init(void)
185 {
186 }
187 
188 /**
189  * Map a externally used socket index to the internal socket representation.
190  *
191  * @param s externally used socket index
192  * @return struct lwip_sock for the socket or NULL if not found
193  */
194 static struct lwip_sock *
195 get_socket(int s)
196 {
197   struct lwip_sock *sock;
198 
199   if ((s < 0) || (s >= NUM_SOCKETS)) {
200     LWIP_DEBUGF(SOCKETS_DEBUG, ("get_socket(%d): invalid\n", s));
201     set_errno(EBADF);
202     return NULL;
203   }
204 
205   sock = &sockets[s];
206 
207   if (!sock->conn) {
208     LWIP_DEBUGF(SOCKETS_DEBUG, ("get_socket(%d): not active\n", s));
209     set_errno(EBADF);
210     return NULL;
211   }
212 
213   return sock;
214 }
215 
216 /**
217  * Same as get_socket but doesn't set errno
218  *
219  * @param s externally used socket index
220  * @return struct lwip_sock for the socket or NULL if not found
221  */
222 static struct lwip_sock *
223 tryget_socket(int s)
224 {
225   if ((s < 0) || (s >= NUM_SOCKETS)) {
226     return NULL;
227   }
228   if (!sockets[s].conn) {
229     return NULL;
230   }
231   return &sockets[s];
232 }
233 
234 /**
235  * Allocate a new socket for a given netconn.
236  *
237  * @param newconn the netconn for which to allocate a socket
238  * @param accepted 1 if socket has been created by accept(),
239  *                 0 if socket has been created by socket()
240  * @return the index of the new socket; -1 on error
241  */
242 static int
243 alloc_socket(struct netconn *newconn, int accepted)
244 {
245   int i;
246   SYS_ARCH_DECL_PROTECT(lev);
247 
248   /* allocate a new socket identifier */
249   for (i = 0; i < NUM_SOCKETS; ++i) {
250     /* Protect socket array */
251     SYS_ARCH_PROTECT(lev);
252     if (!sockets[i].conn) {
253       sockets[i].conn       = newconn;
254       /* The socket is not yet known to anyone, so no need to protect
255          after having marked it as used. */
256       SYS_ARCH_UNPROTECT(lev);
257       sockets[i].lastdata   = NULL;
258       sockets[i].lastoffset = 0;
259       sockets[i].rcvevent   = 0;
260       /* TCP sendbuf is empty, but the socket is not yet writable until connected
261        * (unless it has been created by accept()). */
262       sockets[i].sendevent  = (newconn->type == NETCONN_TCP ? (accepted != 0) : 1);
263       sockets[i].errevent   = 0;
264       sockets[i].err        = 0;
265       sockets[i].select_waiting = 0;
266       return i;
267     }
268     SYS_ARCH_UNPROTECT(lev);
269   }
270   return -1;
271 }
272 
273 /** Free a socket. The socket's netconn must have been
274  * delete before!
275  *
276  * @param sock the socket to free
277  * @param is_tcp != 0 for TCP sockets, used to free lastdata
278  */
279 static void
280 free_socket(struct lwip_sock *sock, int is_tcp)
281 {
282   void *lastdata;
283   SYS_ARCH_DECL_PROTECT(lev);
284 
285   lastdata         = sock->lastdata;
286   sock->lastdata   = NULL;
287   sock->lastoffset = 0;
288   sock->err        = 0;
289 
290   /* Protect socket array */
291   SYS_ARCH_PROTECT(lev);
292   sock->conn       = NULL;
293   SYS_ARCH_UNPROTECT(lev);
294   /* don't use 'sock' after this line, as another task might have allocated it */
295 
296   if (lastdata != NULL) {
297     if (is_tcp) {
298       pbuf_free((struct pbuf *)lastdata);
299     } else {
300       netbuf_delete((struct netbuf *)lastdata);
301     }
302   }
303 }
304 
305 /* Below this, the well-known socket functions are implemented.
306  * Use google.com or opengroup.org to get a good description :-)
307  *
308  * Exceptions are documented!
309  */
310 
311 int
312 lwip_accept(int s, struct sockaddr *addr, socklen_t *addrlen)
313 {
314   struct lwip_sock *sock, *nsock;
315   struct netconn *newconn;
316   ip_addr_t naddr;
317   u16_t port;
318   int newsock;
319   struct sockaddr_in sin;
320   err_t err;
321   SYS_ARCH_DECL_PROTECT(lev);
322 
323   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d)...\n", s));
324   sock = get_socket(s);
325   if (!sock) {
326     return -1;
327   }
328 
329   if (netconn_is_nonblocking(sock->conn) && (sock->rcvevent <= 0)) {
330     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d): returning EWOULDBLOCK\n", s));
331     sock_set_errno(sock, EWOULDBLOCK);
332     return -1;
333   }
334 
335   /* wait for a new connection */
336   err = netconn_accept(sock->conn, &newconn);
337   if (err != ERR_OK) {
338     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d): netconn_acept failed, err=%d\n", s, err));
339     if (netconn_type(sock->conn) != NETCONN_TCP) {
340       sock_set_errno(sock, EOPNOTSUPP);
341       return EOPNOTSUPP;
342     }
343     sock_set_errno(sock, err_to_errno(err));
344     return -1;
345   }
346   LWIP_ASSERT("newconn != NULL", newconn != NULL);
347   /* Prevent automatic window updates, we do this on our own! */
348   netconn_set_noautorecved(newconn, 1);
349 
350   /* get the IP address and port of the remote host */
351   err = netconn_peer(newconn, &naddr, &port);
352   if (err != ERR_OK) {
353     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d): netconn_peer failed, err=%d\n", s, err));
354     netconn_delete(newconn);
355     sock_set_errno(sock, err_to_errno(err));
356     return -1;
357   }
358 
359   /* Note that POSIX only requires us to check addr is non-NULL. addrlen must
360    * not be NULL if addr is valid.
361    */
362   if (NULL != addr) {
363     LWIP_ASSERT("addr valid but addrlen NULL", addrlen != NULL);
364     memset(&sin, 0, sizeof(sin));
365     sin.sin_len = sizeof(sin);
366     sin.sin_family = AF_INET;
367     sin.sin_port = htons(port);
368     inet_addr_from_ipaddr(&sin.sin_addr, &naddr);
369 
370     if (*addrlen > sizeof(sin))
371       *addrlen = sizeof(sin);
372 
373     MEMCPY(addr, &sin, *addrlen);
374   }
375 
376   newsock = alloc_socket(newconn, 1);
377   if (newsock == -1) {
378     netconn_delete(newconn);
379     sock_set_errno(sock, ENFILE);
380     return -1;
381   }
382   LWIP_ASSERT("invalid socket index", (newsock >= 0) && (newsock < NUM_SOCKETS));
383   LWIP_ASSERT("newconn->callback == event_callback", newconn->callback == event_callback);
384   nsock = &sockets[newsock];
385 
386   /* See event_callback: If data comes in right away after an accept, even
387    * though the server task might not have created a new socket yet.
388    * In that case, newconn->socket is counted down (newconn->socket--),
389    * so nsock->rcvevent is >= 1 here!
390    */
391   SYS_ARCH_PROTECT(lev);
392   nsock->rcvevent += (s16_t)(-1 - newconn->socket);
393   newconn->socket = newsock;
394   SYS_ARCH_UNPROTECT(lev);
395 
396   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d) returning new sock=%d addr=", s, newsock));
397   ip_addr_debug_print(SOCKETS_DEBUG, &naddr);
398   LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F"\n", port));
399 
400   sock_set_errno(sock, 0);
401   return newsock;
402 }
403 
404 int
405 lwip_bind(int s, const struct sockaddr *name, socklen_t namelen)
406 {
407   struct lwip_sock *sock;
408   ip_addr_t local_addr;
409   u16_t local_port;
410   err_t err;
411   const struct sockaddr_in *name_in;
412 
413   sock = get_socket(s);
414   if (!sock) {
415     return -1;
416   }
417 
418   /* check size, familiy and alignment of 'name' */
419   LWIP_ERROR("lwip_bind: invalid address", ((namelen == sizeof(struct sockaddr_in)) &&
420              ((name->sa_family) == AF_INET) && ((((mem_ptr_t)name) % 4) == 0)),
421              sock_set_errno(sock, err_to_errno(ERR_ARG)); return -1;);
422   name_in = (const struct sockaddr_in *)(void*)name;
423 
424   inet_addr_to_ipaddr(&local_addr, &name_in->sin_addr);
425   local_port = name_in->sin_port;
426 
427   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d, addr=", s));
428   ip_addr_debug_print(SOCKETS_DEBUG, &local_addr);
429   LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F")\n", ntohs(local_port)));
430 
431   err = netconn_bind(sock->conn, &local_addr, ntohs(local_port));
432 
433   if (err != ERR_OK) {
434     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d) failed, err=%d\n", s, err));
435     sock_set_errno(sock, err_to_errno(err));
436     return -1;
437   }
438 
439   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d) succeeded\n", s));
440   sock_set_errno(sock, 0);
441   return 0;
442 }
443 
444 int
445 lwip_close(int s)
446 {
447   struct lwip_sock *sock;
448   int is_tcp = 0;
449 
450   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_close(%d)\n", s));
451 
452   sock = get_socket(s);
453   if (!sock) {
454     return -1;
455   }
456 
457   if(sock->conn != NULL) {
458     is_tcp = netconn_type(sock->conn) == NETCONN_TCP;
459   } else {
460     LWIP_ASSERT("sock->lastdata == NULL", sock->lastdata == NULL);
461   }
462 
463   netconn_delete(sock->conn);
464 
465   free_socket(sock, is_tcp);
466   set_errno(0);
467   return 0;
468 }
469 
470 int
471 lwip_connect(int s, const struct sockaddr *name, socklen_t namelen)
472 {
473   struct lwip_sock *sock;
474   err_t err;
475   const struct sockaddr_in *name_in;
476 
477   sock = get_socket(s);
478   if (!sock) {
479     return -1;
480   }
481 
482   /* check size, familiy and alignment of 'name' */
483   LWIP_ERROR("lwip_connect: invalid address", ((namelen == sizeof(struct sockaddr_in)) &&
484              ((name->sa_family) == AF_INET) && ((((mem_ptr_t)name) % 4) == 0)),
485              sock_set_errno(sock, err_to_errno(ERR_ARG)); return -1;);
486   name_in = (const struct sockaddr_in *)(void*)name;
487 
488   if (name_in->sin_family == AF_UNSPEC) {
489     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d, AF_UNSPEC)\n", s));
490     err = netconn_disconnect(sock->conn);
491   } else {
492     ip_addr_t remote_addr;
493     u16_t remote_port;
494 
495     inet_addr_to_ipaddr(&remote_addr, &name_in->sin_addr);
496     remote_port = name_in->sin_port;
497 
498     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d, addr=", s));
499     ip_addr_debug_print(SOCKETS_DEBUG, &remote_addr);
500     LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F")\n", ntohs(remote_port)));
501 
502     err = netconn_connect(sock->conn, &remote_addr, ntohs(remote_port));
503   }
504 
505   if (err != ERR_OK) {
506     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d) failed, err=%d\n", s, err));
507     sock_set_errno(sock, err_to_errno(err));
508     return -1;
509   }
510 
511   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d) succeeded\n", s));
512   sock_set_errno(sock, 0);
513   return 0;
514 }
515 
516 /**
517  * Set a socket into listen mode.
518  * The socket may not have been used for another connection previously.
519  *
520  * @param s the socket to set to listening mode
521  * @param backlog (ATTENTION: needs TCP_LISTEN_BACKLOG=1)
522  * @return 0 on success, non-zero on failure
523  */
524 int
525 lwip_listen(int s, int backlog)
526 {
527   struct lwip_sock *sock;
528   err_t err;
529 
530   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_listen(%d, backlog=%d)\n", s, backlog));
531 
532   sock = get_socket(s);
533   if (!sock) {
534     return -1;
535   }
536 
537   /* limit the "backlog" parameter to fit in an u8_t */
538   backlog = LWIP_MIN(LWIP_MAX(backlog, 0), 0xff);
539 
540   err = netconn_listen_with_backlog(sock->conn, (u8_t)backlog);
541 
542   if (err != ERR_OK) {
543     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_listen(%d) failed, err=%d\n", s, err));
544     if (netconn_type(sock->conn) != NETCONN_TCP) {
545       sock_set_errno(sock, EOPNOTSUPP);
546       return EOPNOTSUPP;
547     }
548     sock_set_errno(sock, err_to_errno(err));
549     return -1;
550   }
551 
552   sock_set_errno(sock, 0);
553   return 0;
554 }
555 
556 int
557 lwip_recvfrom(int s, void *mem, size_t len, int flags,
558         struct sockaddr *from, socklen_t *fromlen)
559 {
560   struct lwip_sock *sock;
561   void             *buf = NULL;
562   struct pbuf      *p;
563   u16_t            buflen, copylen;
564   int              off = 0;
565   ip_addr_t        *addr;
566   u16_t            port;
567   u8_t             done = 0;
568   err_t            err;
569 
570   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d, %p, %"SZT_F", 0x%x, ..)\n", s, mem, len, flags));
571   sock = get_socket(s);
572   if (!sock) {
573     return -1;
574   }
575 
576   do {
577     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: top while sock->lastdata=%p\n", sock->lastdata));
578     /* Check if there is data left from the last recv operation. */
579     if (sock->lastdata) {
580       buf = sock->lastdata;
581     } else {
582       /* If this is non-blocking call, then check first */
583       if (((flags & MSG_DONTWAIT) || netconn_is_nonblocking(sock->conn)) &&
584           (sock->rcvevent <= 0)) {
585         if (off > 0) {
586           /* update receive window */
587           netconn_recved(sock->conn, (u32_t)off);
588           /* already received data, return that */
589           sock_set_errno(sock, 0);
590           return off;
591         }
592         LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): returning EWOULDBLOCK\n", s));
593         sock_set_errno(sock, EWOULDBLOCK);
594         return -1;
595       }
596 
597       /* No data was left from the previous operation, so we try to get
598          some from the network. */
599       if (netconn_type(sock->conn) == NETCONN_TCP) {
600         err = netconn_recv_tcp_pbuf(sock->conn, (struct pbuf **)&buf);
601       } else {
602         err = netconn_recv(sock->conn, (struct netbuf **)&buf);
603       }
604       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: netconn_recv err=%d, netbuf=%p\n",
605         err, buf));
606 
607       if (err != ERR_OK) {
608         if (off > 0) {
609           /* update receive window */
610           netconn_recved(sock->conn, (u32_t)off);
611           /* already received data, return that */
612           sock_set_errno(sock, 0);
613           return off;
614         }
615         /* We should really do some error checking here. */
616         LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): buf == NULL, error is \"%s\"!\n",
617           s, lwip_strerr(err)));
618         sock_set_errno(sock, err_to_errno(err));
619         if (err == ERR_CLSD) {
620           return 0;
621         } else {
622           return -1;
623         }
624       }
625       LWIP_ASSERT("buf != NULL", buf != NULL);
626       sock->lastdata = buf;
627     }
628 
629     if (netconn_type(sock->conn) == NETCONN_TCP) {
630       p = (struct pbuf *)buf;
631     } else {
632       p = ((struct netbuf *)buf)->p;
633     }
634     buflen = p->tot_len;
635     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: buflen=%"U16_F" len=%"SZT_F" off=%d sock->lastoffset=%"U16_F"\n",
636       buflen, len, off, sock->lastoffset));
637 
638     buflen -= sock->lastoffset;
639 
640     if (len > buflen) {
641       copylen = buflen;
642     } else {
643       copylen = (u16_t)len;
644     }
645 
646     /* copy the contents of the received buffer into
647     the supplied memory pointer mem */
648     pbuf_copy_partial(p, (u8_t*)mem + off, copylen, sock->lastoffset);
649 
650     off += copylen;
651 
652     if (netconn_type(sock->conn) == NETCONN_TCP) {
653       LWIP_ASSERT("invalid copylen, len would underflow", len >= copylen);
654       len -= copylen;
655       if ( (len <= 0) ||
656            (p->flags & PBUF_FLAG_PUSH) ||
657            (sock->rcvevent <= 0) ||
658            ((flags & MSG_PEEK)!=0)) {
659         done = 1;
660       }
661     } else {
662       done = 1;
663     }
664 
665     /* Check to see from where the data was.*/
666     if (done) {
667       ip_addr_t fromaddr;
668       if (from && fromlen) {
669         struct sockaddr_in sin;
670 
671         if (netconn_type(sock->conn) == NETCONN_TCP) {
672           addr = &fromaddr;
673           netconn_getaddr(sock->conn, addr, &port, 0);
674         } else {
675           addr = netbuf_fromaddr((struct netbuf *)buf);
676           port = netbuf_fromport((struct netbuf *)buf);
677         }
678 
679         memset(&sin, 0, sizeof(sin));
680         sin.sin_len = sizeof(sin);
681         sin.sin_family = AF_INET;
682         sin.sin_port = htons(port);
683         inet_addr_from_ipaddr(&sin.sin_addr, addr);
684 
685         if (*fromlen > sizeof(sin)) {
686           *fromlen = sizeof(sin);
687         }
688 
689         MEMCPY(from, &sin, *fromlen);
690 
691         LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): addr=", s));
692         ip_addr_debug_print(SOCKETS_DEBUG, addr);
693         LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F" len=%d\n", port, off));
694       } else {
695 #if SOCKETS_DEBUG
696         if (netconn_type(sock->conn) == NETCONN_TCP) {
697           addr = &fromaddr;
698           netconn_getaddr(sock->conn, addr, &port, 0);
699         } else {
700           addr = netbuf_fromaddr((struct netbuf *)buf);
701           port = netbuf_fromport((struct netbuf *)buf);
702         }
703 
704         LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): addr=", s));
705         ip_addr_debug_print(SOCKETS_DEBUG, addr);
706         LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F" len=%d\n", port, off));
707 #endif /*  SOCKETS_DEBUG */
708       }
709     }
710 
711     /* If we don't peek the incoming message... */
712     if ((flags & MSG_PEEK) == 0) {
713       /* If this is a TCP socket, check if there is data left in the
714          buffer. If so, it should be saved in the sock structure for next
715          time around. */
716       if ((netconn_type(sock->conn) == NETCONN_TCP) && (buflen - copylen > 0)) {
717         sock->lastdata = buf;
718         sock->lastoffset += copylen;
719         LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: lastdata now netbuf=%p\n", buf));
720       } else {
721         sock->lastdata = NULL;
722         sock->lastoffset = 0;
723         LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: deleting netbuf=%p\n", buf));
724         if (netconn_type(sock->conn) == NETCONN_TCP) {
725           pbuf_free((struct pbuf *)buf);
726         } else {
727           netbuf_delete((struct netbuf *)buf);
728         }
729       }
730     }
731   } while (!done);
732 
733   if (off > 0) {
734     /* update receive window */
735     netconn_recved(sock->conn, (u32_t)off);
736   }
737   sock_set_errno(sock, 0);
738   return off;
739 }
740 
741 int
742 lwip_read(int s, void *mem, size_t len)
743 {
744   return lwip_recvfrom(s, mem, len, 0, NULL, NULL);
745 }
746 
747 int
748 lwip_recv(int s, void *mem, size_t len, int flags)
749 {
750   return lwip_recvfrom(s, mem, len, flags, NULL, NULL);
751 }
752 
753 int
754 lwip_send(int s, const void *data, size_t size, int flags)
755 {
756   struct lwip_sock *sock;
757   err_t err;
758   u8_t write_flags;
759   size_t written;
760 
761   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_send(%d, data=%p, size=%"SZT_F", flags=0x%x)\n",
762                               s, data, size, flags));
763 
764   sock = get_socket(s);
765   if (!sock) {
766     return -1;
767   }
768 
769   if (sock->conn->type != NETCONN_TCP) {
770 #if (LWIP_UDP || LWIP_RAW)
771     return lwip_sendto(s, data, size, flags, NULL, 0);
772 #else /* (LWIP_UDP || LWIP_RAW) */
773     sock_set_errno(sock, err_to_errno(ERR_ARG));
774     return -1;
775 #endif /* (LWIP_UDP || LWIP_RAW) */
776   }
777 
778   write_flags = NETCONN_COPY |
779     ((flags & MSG_MORE)     ? NETCONN_MORE      : 0) |
780     ((flags & MSG_DONTWAIT) ? NETCONN_DONTBLOCK : 0);
781   written = 0;
782   err = netconn_write_partly(sock->conn, data, size, write_flags, &written);
783 
784   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_send(%d) err=%d written=%"SZT_F"\n", s, err, written));
785   sock_set_errno(sock, err_to_errno(err));
786   return (err == ERR_OK ? (int)written : -1);
787 }
788 
789 int
790 lwip_sendto(int s, const void *data, size_t size, int flags,
791        const struct sockaddr *to, socklen_t tolen)
792 {
793   struct lwip_sock *sock;
794   err_t err;
795   u16_t short_size;
796   const struct sockaddr_in *to_in;
797   u16_t remote_port;
798 #if !LWIP_TCPIP_CORE_LOCKING
799   struct netbuf buf;
800 #endif
801 
802   sock = get_socket(s);
803   if (!sock) {
804     return -1;
805   }
806 
807   if (sock->conn->type == NETCONN_TCP) {
808 #if LWIP_TCP
809     return lwip_send(s, data, size, flags);
810 #else /* LWIP_TCP */
811     LWIP_UNUSED_ARG(flags);
812     sock_set_errno(sock, err_to_errno(ERR_ARG));
813     return -1;
814 #endif /* LWIP_TCP */
815   }
816 
817   /* @todo: split into multiple sendto's? */
818   LWIP_ASSERT("lwip_sendto: size must fit in u16_t", size <= 0xffff);
819   short_size = (u16_t)size;
820   LWIP_ERROR("lwip_sendto: invalid address", (((to == NULL) && (tolen == 0)) ||
821              ((tolen == sizeof(struct sockaddr_in)) &&
822              ((to->sa_family) == AF_INET) && ((((mem_ptr_t)to) % 4) == 0))),
823              sock_set_errno(sock, err_to_errno(ERR_ARG)); return -1;);
824   to_in = (const struct sockaddr_in *)(void*)to;
825 
826 #if LWIP_TCPIP_CORE_LOCKING
827   /* Should only be consider like a sample or a simple way to experiment this option (no check of "to" field...) */
828   {
829     struct pbuf* p;
830     ip_addr_t *remote_addr;
831 
832 #if LWIP_NETIF_TX_SINGLE_PBUF
833     p = pbuf_alloc(PBUF_TRANSPORT, short_size, PBUF_RAM);
834     if (p != NULL) {
835 #if LWIP_CHECKSUM_ON_COPY
836       u16_t chksum = 0;
837       if (sock->conn->type != NETCONN_RAW) {
838         chksum = LWIP_CHKSUM_COPY(p->payload, data, short_size);
839       } else
840 #endif /* LWIP_CHECKSUM_ON_COPY */
841       MEMCPY(p->payload, data, size);
842 #else /* LWIP_NETIF_TX_SINGLE_PBUF */
843     p = pbuf_alloc(PBUF_TRANSPORT, short_size, PBUF_REF);
844     if (p != NULL) {
845       p->payload = (void*)data;
846 #endif /* LWIP_NETIF_TX_SINGLE_PBUF */
847 
848       if (to_in != NULL) {
849         inet_addr_to_ipaddr_p(remote_addr, &to_in->sin_addr);
850         remote_port = ntohs(to_in->sin_port);
851       } else {
852         remote_addr = &sock->conn->pcb.ip->remote_ip;
853 #if LWIP_UDP
854         if (NETCONNTYPE_GROUP(sock->conn->type) == NETCONN_UDP) {
855           remote_port = sock->conn->pcb.udp->remote_port;
856         } else
857 #endif /* LWIP_UDP */
858         {
859           remote_port = 0;
860         }
861       }
862 
863       LOCK_TCPIP_CORE();
864       if (netconn_type(sock->conn) == NETCONN_RAW) {
865 #if LWIP_RAW
866         err = sock->conn->last_err = raw_sendto(sock->conn->pcb.raw, p, remote_addr);
867 #else /* LWIP_RAW */
868         err = ERR_ARG;
869 #endif /* LWIP_RAW */
870       }
871 #if LWIP_UDP && LWIP_RAW
872       else
873 #endif /* LWIP_UDP && LWIP_RAW */
874       {
875 #if LWIP_UDP
876 #if LWIP_CHECKSUM_ON_COPY && LWIP_NETIF_TX_SINGLE_PBUF
877         err = sock->conn->last_err = udp_sendto_chksum(sock->conn->pcb.udp, p,
878           remote_addr, remote_port, 1, chksum);
879 #else /* LWIP_CHECKSUM_ON_COPY && LWIP_NETIF_TX_SINGLE_PBUF */
880         err = sock->conn->last_err = udp_sendto(sock->conn->pcb.udp, p,
881           remote_addr, remote_port);
882 #endif /* LWIP_CHECKSUM_ON_COPY && LWIP_NETIF_TX_SINGLE_PBUF */
883 #else /* LWIP_UDP */
884         err = ERR_ARG;
885 #endif /* LWIP_UDP */
886       }
887       UNLOCK_TCPIP_CORE();
888 
889       pbuf_free(p);
890     } else {
891       err = ERR_MEM;
892     }
893   }
894 #else /* LWIP_TCPIP_CORE_LOCKING */
895   /* initialize a buffer */
896   buf.p = buf.ptr = NULL;
897 #if LWIP_CHECKSUM_ON_COPY
898   buf.flags = 0;
899 #endif /* LWIP_CHECKSUM_ON_COPY */
900   if (to) {
901     inet_addr_to_ipaddr(&buf.addr, &to_in->sin_addr);
902     remote_port           = ntohs(to_in->sin_port);
903     netbuf_fromport(&buf) = remote_port;
904   } else {
905     remote_port           = 0;
906     ip_addr_set_any(&buf.addr);
907     netbuf_fromport(&buf) = 0;
908   }
909 
910   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_sendto(%d, data=%p, short_size=%"U16_F", flags=0x%x to=",
911               s, data, short_size, flags));
912   ip_addr_debug_print(SOCKETS_DEBUG, &buf.addr);
913   LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F"\n", remote_port));
914 
915   /* make the buffer point to the data that should be sent */
916 #if LWIP_NETIF_TX_SINGLE_PBUF
917   /* Allocate a new netbuf and copy the data into it. */
918   if (netbuf_alloc(&buf, short_size) == NULL) {
919     err = ERR_MEM;
920   } else {
921 #if LWIP_CHECKSUM_ON_COPY
922     if (sock->conn->type != NETCONN_RAW) {
923       u16_t chksum = LWIP_CHKSUM_COPY(buf.p->payload, data, short_size);
924       netbuf_set_chksum(&buf, chksum);
925       err = ERR_OK;
926     } else
927 #endif /* LWIP_CHECKSUM_ON_COPY */
928     {
929       err = netbuf_take(&buf, data, short_size);
930     }
931   }
932 #else /* LWIP_NETIF_TX_SINGLE_PBUF */
933   err = netbuf_ref(&buf, data, short_size);
934 #endif /* LWIP_NETIF_TX_SINGLE_PBUF */
935   if (err == ERR_OK) {
936     /* send the data */
937     err = netconn_send(sock->conn, &buf);
938   }
939 
940   /* deallocated the buffer */
941   netbuf_free(&buf);
942 #endif /* LWIP_TCPIP_CORE_LOCKING */
943   sock_set_errno(sock, err_to_errno(err));
944   return (err == ERR_OK ? short_size : -1);
945 }
946 
947 int
948 lwip_socket(int domain, int type, int protocol)
949 {
950   struct netconn *conn;
951   int i;
952 
953   LWIP_UNUSED_ARG(domain);
954 
955   /* create a netconn */
956   switch (type) {
957   case SOCK_RAW:
958     conn = netconn_new_with_proto_and_callback(NETCONN_RAW, (u8_t)protocol, event_callback);
959     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_RAW, %d) = ",
960                                  domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol));
961     break;
962   case SOCK_DGRAM:
963     conn = netconn_new_with_callback( (protocol == IPPROTO_UDPLITE) ?
964                  NETCONN_UDPLITE : NETCONN_UDP, event_callback);
965     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_DGRAM, %d) = ",
966                                  domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol));
967     break;
968   case SOCK_STREAM:
969     conn = netconn_new_with_callback(NETCONN_TCP, event_callback);
970     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_STREAM, %d) = ",
971                                  domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol));
972     if (conn != NULL) {
973       /* Prevent automatic window updates, we do this on our own! */
974       netconn_set_noautorecved(conn, 1);
975     }
976     break;
977   default:
978     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%d, %d/UNKNOWN, %d) = -1\n",
979                                  domain, type, protocol));
980     set_errno(EINVAL);
981     return -1;
982   }
983 
984   if (!conn) {
985     LWIP_DEBUGF(SOCKETS_DEBUG, ("-1 / ENOBUFS (could not create netconn)\n"));
986     set_errno(ENOBUFS);
987     return -1;
988   }
989 
990   i = alloc_socket(conn, 0);
991 
992   if (i == -1) {
993     netconn_delete(conn);
994     set_errno(ENFILE);
995     return -1;
996   }
997   conn->socket = i;
998   LWIP_DEBUGF(SOCKETS_DEBUG, ("%d\n", i));
999   set_errno(0);
1000   return i;
1001 }
1002 
1003 int
1004 lwip_write(int s, const void *data, size_t size)
1005 {
1006   return lwip_send(s, data, size, 0);
1007 }
1008 
1009 /**
1010  * Go through the readset and writeset lists and see which socket of the sockets
1011  * set in the sets has events. On return, readset, writeset and exceptset have
1012  * the sockets enabled that had events.
1013  *
1014  * exceptset is not used for now!!!
1015  *
1016  * @param maxfdp1 the highest socket index in the sets
1017  * @param readset_in:    set of sockets to check for read events
1018  * @param writeset_in:   set of sockets to check for write events
1019  * @param exceptset_in:  set of sockets to check for error events
1020  * @param readset_out:   set of sockets that had read events
1021  * @param writeset_out:  set of sockets that had write events
1022  * @param exceptset_out: set os sockets that had error events
1023  * @return number of sockets that had events (read/write/exception) (>= 0)
1024  */
1025 static int
1026 lwip_selscan(int maxfdp1, fd_set *readset_in, fd_set *writeset_in, fd_set *exceptset_in,
1027              fd_set *readset_out, fd_set *writeset_out, fd_set *exceptset_out)
1028 {
1029   int i, nready = 0;
1030   fd_set lreadset, lwriteset, lexceptset;
1031   struct lwip_sock *sock;
1032   SYS_ARCH_DECL_PROTECT(lev);
1033 
1034   FD_ZERO(&lreadset);
1035   FD_ZERO(&lwriteset);
1036   FD_ZERO(&lexceptset);
1037 
1038   /* Go through each socket in each list to count number of sockets which
1039      currently match */
1040   for(i = 0; i < maxfdp1; i++) {
1041     void* lastdata = NULL;
1042     s16_t rcvevent = 0;
1043     u16_t sendevent = 0;
1044     u16_t errevent = 0;
1045     /* First get the socket's status (protected)... */
1046     SYS_ARCH_PROTECT(lev);
1047     sock = tryget_socket(i);
1048     if (sock != NULL) {
1049       lastdata = sock->lastdata;
1050       rcvevent = sock->rcvevent;
1051       sendevent = sock->sendevent;
1052       errevent = sock->errevent;
1053     }
1054     SYS_ARCH_UNPROTECT(lev);
1055     /* ... then examine it: */
1056     /* See if netconn of this socket is ready for read */
1057     if (readset_in && FD_ISSET(i, readset_in) && ((lastdata != NULL) || (rcvevent > 0))) {
1058       FD_SET(i, &lreadset);
1059       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_selscan: fd=%d ready for reading\n", i));
1060       nready++;
1061     }
1062     /* See if netconn of this socket is ready for write */
1063     if (writeset_in && FD_ISSET(i, writeset_in) && (sendevent != 0)) {
1064       FD_SET(i, &lwriteset);
1065       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_selscan: fd=%d ready for writing\n", i));
1066       nready++;
1067     }
1068     /* See if netconn of this socket had an error */
1069     if (exceptset_in && FD_ISSET(i, exceptset_in) && (errevent != 0)) {
1070       FD_SET(i, &lexceptset);
1071       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_selscan: fd=%d ready for exception\n", i));
1072       nready++;
1073     }
1074   }
1075   /* copy local sets to the ones provided as arguments */
1076   *readset_out = lreadset;
1077   *writeset_out = lwriteset;
1078   *exceptset_out = lexceptset;
1079 
1080   LWIP_ASSERT("nready >= 0", nready >= 0);
1081   return nready;
1082 }
1083 
1084 /**
1085  * Processing exceptset is not yet implemented.
1086  */
1087 int
1088 lwip_select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset,
1089             struct timeval *timeout)
1090 {
1091   u32_t waitres = 0;
1092   int nready;
1093   fd_set lreadset, lwriteset, lexceptset;
1094   u32_t msectimeout;
1095   struct lwip_select_cb select_cb;
1096   err_t err;
1097   int i;
1098   SYS_ARCH_DECL_PROTECT(lev);
1099 
1100   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select(%d, %p, %p, %p, tvsec=%"S32_F" tvusec=%"S32_F")\n",
1101                   maxfdp1, (void *)readset, (void *) writeset, (void *) exceptset,
1102                   timeout ? (s32_t)timeout->tv_sec : (s32_t)-1,
1103                   timeout ? (s32_t)timeout->tv_usec : (s32_t)-1));
1104 
1105   /* Go through each socket in each list to count number of sockets which
1106      currently match */
1107   nready = lwip_selscan(maxfdp1, readset, writeset, exceptset, &lreadset, &lwriteset, &lexceptset);
1108 
1109   /* If we don't have any current events, then suspend if we are supposed to */
1110   if (!nready) {
1111     if (timeout && timeout->tv_sec == 0 && timeout->tv_usec == 0) {
1112       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select: no timeout, returning 0\n"));
1113       /* This is OK as the local fdsets are empty and nready is zero,
1114          or we would have returned earlier. */
1115       goto return_copy_fdsets;
1116     }
1117 
1118     /* None ready: add our semaphore to list:
1119        We don't actually need any dynamic memory. Our entry on the
1120        list is only valid while we are in this function, so it's ok
1121        to use local variables. */
1122 
1123     select_cb.next = NULL;
1124     select_cb.prev = NULL;
1125     select_cb.readset = readset;
1126     select_cb.writeset = writeset;
1127     select_cb.exceptset = exceptset;
1128     select_cb.sem_signalled = 0;
1129     err = sys_sem_new(&select_cb.sem, 0);
1130     if (err != ERR_OK) {
1131       /* failed to create semaphore */
1132       set_errno(ENOMEM);
1133       return -1;
1134     }
1135 
1136     /* Protect the select_cb_list */
1137     SYS_ARCH_PROTECT(lev);
1138 
1139     /* Put this select_cb on top of list */
1140     select_cb.next = select_cb_list;
1141     if (select_cb_list != NULL) {
1142       select_cb_list->prev = &select_cb;
1143     }
1144     select_cb_list = &select_cb;
1145     /* Increasing this counter tells even_callback that the list has changed. */
1146     select_cb_ctr++;
1147 
1148     /* Now we can safely unprotect */
1149     SYS_ARCH_UNPROTECT(lev);
1150 
1151     /* Increase select_waiting for each socket we are interested in */
1152     for(i = 0; i < maxfdp1; i++) {
1153       if ((readset && FD_ISSET(i, readset)) ||
1154           (writeset && FD_ISSET(i, writeset)) ||
1155           (exceptset && FD_ISSET(i, exceptset))) {
1156         struct lwip_sock *sock = tryget_socket(i);
1157         LWIP_ASSERT("sock != NULL", sock != NULL);
1158         SYS_ARCH_PROTECT(lev);
1159         sock->select_waiting++;
1160         LWIP_ASSERT("sock->select_waiting > 0", sock->select_waiting > 0);
1161         SYS_ARCH_UNPROTECT(lev);
1162       }
1163     }
1164 
1165     /* Call lwip_selscan again: there could have been events between
1166        the last scan (whithout us on the list) and putting us on the list! */
1167     nready = lwip_selscan(maxfdp1, readset, writeset, exceptset, &lreadset, &lwriteset, &lexceptset);
1168     if (!nready) {
1169       /* Still none ready, just wait to be woken */
1170       if (timeout == 0) {
1171         /* Wait forever */
1172         msectimeout = 0;
1173       } else {
1174         msectimeout =  ((timeout->tv_sec * 1000) + ((timeout->tv_usec + 500)/1000));
1175         if (msectimeout == 0) {
1176           /* Wait 1ms at least (0 means wait forever) */
1177           msectimeout = 1;
1178         }
1179       }
1180 
1181       waitres = sys_arch_sem_wait(&select_cb.sem, msectimeout);
1182     }
1183     /* Increase select_waiting for each socket we are interested in */
1184     for(i = 0; i < maxfdp1; i++) {
1185       if ((readset && FD_ISSET(i, readset)) ||
1186           (writeset && FD_ISSET(i, writeset)) ||
1187           (exceptset && FD_ISSET(i, exceptset))) {
1188         struct lwip_sock *sock = tryget_socket(i);
1189         LWIP_ASSERT("sock != NULL", sock != NULL);
1190         SYS_ARCH_PROTECT(lev);
1191         sock->select_waiting--;
1192         LWIP_ASSERT("sock->select_waiting >= 0", sock->select_waiting >= 0);
1193         SYS_ARCH_UNPROTECT(lev);
1194       }
1195     }
1196     /* Take us off the list */
1197     SYS_ARCH_PROTECT(lev);
1198     if (select_cb.next != NULL) {
1199       select_cb.next->prev = select_cb.prev;
1200     }
1201     if (select_cb_list == &select_cb) {
1202       LWIP_ASSERT("select_cb.prev == NULL", select_cb.prev == NULL);
1203       select_cb_list = select_cb.next;
1204     } else {
1205       LWIP_ASSERT("select_cb.prev != NULL", select_cb.prev != NULL);
1206       select_cb.prev->next = select_cb.next;
1207     }
1208     /* Increasing this counter tells even_callback that the list has changed. */
1209     select_cb_ctr++;
1210     SYS_ARCH_UNPROTECT(lev);
1211 
1212     sys_sem_free(&select_cb.sem);
1213     if (waitres == SYS_ARCH_TIMEOUT)  {
1214       /* Timeout */
1215       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select: timeout expired\n"));
1216       /* This is OK as the local fdsets are empty and nready is zero,
1217          or we would have returned earlier. */
1218       goto return_copy_fdsets;
1219     }
1220 
1221     /* See what's set */
1222     nready = lwip_selscan(maxfdp1, readset, writeset, exceptset, &lreadset, &lwriteset, &lexceptset);
1223   }
1224 
1225   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select: nready=%d\n", nready));
1226 return_copy_fdsets:
1227   set_errno(0);
1228   if (readset) {
1229     *readset = lreadset;
1230   }
1231   if (writeset) {
1232     *writeset = lwriteset;
1233   }
1234   if (exceptset) {
1235     *exceptset = lexceptset;
1236   }
1237 
1238 
1239   return nready;
1240 }
1241 
1242 /**
1243  * Callback registered in the netconn layer for each socket-netconn.
1244  * Processes recvevent (data available) and wakes up tasks waiting for select.
1245  */
1246 static void
1247 event_callback(struct netconn *conn, enum netconn_evt evt, u16_t len)
1248 {
1249   int s;
1250   struct lwip_sock *sock;
1251   struct lwip_select_cb *scb;
1252   int last_select_cb_ctr;
1253   SYS_ARCH_DECL_PROTECT(lev);
1254 
1255   LWIP_UNUSED_ARG(len);
1256 
1257   /* Get socket */
1258   if (conn) {
1259     s = conn->socket;
1260     if (s < 0) {
1261       /* Data comes in right away after an accept, even though
1262        * the server task might not have created a new socket yet.
1263        * Just count down (or up) if that's the case and we
1264        * will use the data later. Note that only receive events
1265        * can happen before the new socket is set up. */
1266       SYS_ARCH_PROTECT(lev);
1267       if (conn->socket < 0) {
1268         if (evt == NETCONN_EVT_RCVPLUS) {
1269           conn->socket--;
1270         }
1271         SYS_ARCH_UNPROTECT(lev);
1272         return;
1273       }
1274       s = conn->socket;
1275       SYS_ARCH_UNPROTECT(lev);
1276     }
1277 
1278     sock = get_socket(s);
1279     if (!sock) {
1280       return;
1281     }
1282   } else {
1283     return;
1284   }
1285 
1286   SYS_ARCH_PROTECT(lev);
1287   /* Set event as required */
1288   switch (evt) {
1289     case NETCONN_EVT_RCVPLUS:
1290       sock->rcvevent++;
1291       break;
1292     case NETCONN_EVT_RCVMINUS:
1293       sock->rcvevent--;
1294       break;
1295     case NETCONN_EVT_SENDPLUS:
1296       sock->sendevent = 1;
1297       break;
1298     case NETCONN_EVT_SENDMINUS:
1299       sock->sendevent = 0;
1300       break;
1301     case NETCONN_EVT_ERROR:
1302       sock->errevent = 1;
1303       break;
1304     default:
1305       LWIP_ASSERT("unknown event", 0);
1306       break;
1307   }
1308 
1309   if (sock->select_waiting == 0) {
1310     /* noone is waiting for this socket, no need to check select_cb_list */
1311     SYS_ARCH_UNPROTECT(lev);
1312     return;
1313   }
1314 
1315   /* Now decide if anyone is waiting for this socket */
1316   /* NOTE: This code goes through the select_cb_list list multiple times
1317      ONLY IF a select was actually waiting. We go through the list the number
1318      of waiting select calls + 1. This list is expected to be small. */
1319 
1320   /* At this point, SYS_ARCH is still protected! */
1321 again:
1322   for (scb = select_cb_list; scb != NULL; scb = scb->next) {
1323     if (scb->sem_signalled == 0) {
1324       /* semaphore not signalled yet */
1325       int do_signal = 0;
1326       /* Test this select call for our socket */
1327       if (sock->rcvevent > 0) {
1328         if (scb->readset && FD_ISSET(s, scb->readset)) {
1329           do_signal = 1;
1330         }
1331       }
1332       if (sock->sendevent != 0) {
1333         if (!do_signal && scb->writeset && FD_ISSET(s, scb->writeset)) {
1334           do_signal = 1;
1335         }
1336       }
1337       if (sock->errevent != 0) {
1338         if (!do_signal && scb->exceptset && FD_ISSET(s, scb->exceptset)) {
1339           do_signal = 1;
1340         }
1341       }
1342       if (do_signal) {
1343         scb->sem_signalled = 1;
1344         /* Don't call SYS_ARCH_UNPROTECT() before signaling the semaphore, as this might
1345            lead to the select thread taking itself off the list, invalidagin the semaphore. */
1346         sys_sem_signal(&scb->sem);
1347       }
1348     }
1349     /* unlock interrupts with each step */
1350     last_select_cb_ctr = select_cb_ctr;
1351     SYS_ARCH_UNPROTECT(lev);
1352     /* this makes sure interrupt protection time is short */
1353     SYS_ARCH_PROTECT(lev);
1354     if (last_select_cb_ctr != select_cb_ctr) {
1355       /* someone has changed select_cb_list, restart at the beginning */
1356       goto again;
1357     }
1358   }
1359   SYS_ARCH_UNPROTECT(lev);
1360 }
1361 
1362 /**
1363  * Unimplemented: Close one end of a full-duplex connection.
1364  * Currently, the full connection is closed.
1365  */
1366 int
1367 lwip_shutdown(int s, int how)
1368 {
1369   struct lwip_sock *sock;
1370   err_t err;
1371   u8_t shut_rx = 0, shut_tx = 0;
1372 
1373   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_shutdown(%d, how=%d)\n", s, how));
1374 
1375   sock = get_socket(s);
1376   if (!sock) {
1377     return -1;
1378   }
1379 
1380   if (sock->conn != NULL) {
1381     if (netconn_type(sock->conn) != NETCONN_TCP) {
1382       sock_set_errno(sock, EOPNOTSUPP);
1383       return EOPNOTSUPP;
1384     }
1385   } else {
1386     sock_set_errno(sock, ENOTCONN);
1387     return ENOTCONN;
1388   }
1389 
1390   if (how == SHUT_RD) {
1391     shut_rx = 1;
1392   } else if (how == SHUT_WR) {
1393     shut_tx = 1;
1394   } else if(how == SHUT_RDWR) {
1395     shut_rx = 1;
1396     shut_tx = 1;
1397   } else {
1398     sock_set_errno(sock, EINVAL);
1399     return EINVAL;
1400   }
1401   err = netconn_shutdown(sock->conn, shut_rx, shut_tx);
1402 
1403   sock_set_errno(sock, err_to_errno(err));
1404   return (err == ERR_OK ? 0 : -1);
1405 }
1406 
1407 static int
1408 lwip_getaddrname(int s, struct sockaddr *name, socklen_t *namelen, u8_t local)
1409 {
1410   struct lwip_sock *sock;
1411   struct sockaddr_in sin;
1412   ip_addr_t naddr;
1413 
1414   sock = get_socket(s);
1415   if (!sock) {
1416     return -1;
1417   }
1418 
1419   memset(&sin, 0, sizeof(sin));
1420   sin.sin_len = sizeof(sin);
1421   sin.sin_family = AF_INET;
1422 
1423   /* get the IP address and port */
1424   netconn_getaddr(sock->conn, &naddr, &sin.sin_port, local);
1425 
1426   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getaddrname(%d, addr=", s));
1427   ip_addr_debug_print(SOCKETS_DEBUG, &naddr);
1428   LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F")\n", sin.sin_port));
1429 
1430   sin.sin_port = htons(sin.sin_port);
1431   inet_addr_from_ipaddr(&sin.sin_addr, &naddr);
1432 
1433   if (*namelen > sizeof(sin)) {
1434     *namelen = sizeof(sin);
1435   }
1436 
1437   MEMCPY(name, &sin, *namelen);
1438   sock_set_errno(sock, 0);
1439   return 0;
1440 }
1441 
1442 int
1443 lwip_getpeername(int s, struct sockaddr *name, socklen_t *namelen)
1444 {
1445   return lwip_getaddrname(s, name, namelen, 0);
1446 }
1447 
1448 int
1449 lwip_getsockname(int s, struct sockaddr *name, socklen_t *namelen)
1450 {
1451   return lwip_getaddrname(s, name, namelen, 1);
1452 }
1453 
1454 int
1455 lwip_getsockopt(int s, int level, int optname, void *optval, socklen_t *optlen)
1456 {
1457   err_t err = ERR_OK;
1458   struct lwip_sock *sock = get_socket(s);
1459   struct lwip_setgetsockopt_data data;
1460 
1461   if (!sock) {
1462     return -1;
1463   }
1464 
1465   if ((NULL == optval) || (NULL == optlen)) {
1466     sock_set_errno(sock, EFAULT);
1467     return -1;
1468   }
1469 
1470   /* Do length and type checks for the various options first, to keep it readable. */
1471   switch (level) {
1472 
1473 /* Level: SOL_SOCKET */
1474   case SOL_SOCKET:
1475     switch (optname) {
1476 
1477     case SO_ACCEPTCONN:
1478     case SO_BROADCAST:
1479     /* UNIMPL case SO_DEBUG: */
1480     /* UNIMPL case SO_DONTROUTE: */
1481     case SO_ERROR:
1482     case SO_KEEPALIVE:
1483     /* UNIMPL case SO_CONTIMEO: */
1484 #if LWIP_SO_SNDTIMEO
1485     case SO_SNDTIMEO:
1486 #endif /* LWIP_SO_SNDTIMEO */
1487 #if LWIP_SO_RCVTIMEO
1488     case SO_RCVTIMEO:
1489 #endif /* LWIP_SO_RCVTIMEO */
1490 #if LWIP_SO_RCVBUF
1491     case SO_RCVBUF:
1492 #endif /* LWIP_SO_RCVBUF */
1493     /* UNIMPL case SO_OOBINLINE: */
1494     /* UNIMPL case SO_SNDBUF: */
1495     /* UNIMPL case SO_RCVLOWAT: */
1496     /* UNIMPL case SO_SNDLOWAT: */
1497 #if SO_REUSE
1498     case SO_REUSEADDR:
1499     case SO_REUSEPORT:
1500 #endif /* SO_REUSE */
1501     case SO_TYPE:
1502     /* UNIMPL case SO_USELOOPBACK: */
1503       if (*optlen < sizeof(int)) {
1504         err = EINVAL;
1505       }
1506       break;
1507 
1508     case SO_NO_CHECK:
1509       if (*optlen < sizeof(int)) {
1510         err = EINVAL;
1511       }
1512 #if LWIP_UDP
1513       if ((sock->conn->type != NETCONN_UDP) ||
1514           ((udp_flags(sock->conn->pcb.udp) & UDP_FLAGS_UDPLITE) != 0)) {
1515         /* this flag is only available for UDP, not for UDP lite */
1516         err = EAFNOSUPPORT;
1517       }
1518 #endif /* LWIP_UDP */
1519       break;
1520 
1521     default:
1522       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, UNIMPL: optname=0x%x, ..)\n",
1523                                   s, optname));
1524       err = ENOPROTOOPT;
1525     }  /* switch (optname) */
1526     break;
1527 
1528 /* Level: IPPROTO_IP */
1529   case IPPROTO_IP:
1530     switch (optname) {
1531     /* UNIMPL case IP_HDRINCL: */
1532     /* UNIMPL case IP_RCVDSTADDR: */
1533     /* UNIMPL case IP_RCVIF: */
1534     case IP_TTL:
1535     case IP_TOS:
1536       if (*optlen < sizeof(int)) {
1537         err = EINVAL;
1538       }
1539       break;
1540 #if LWIP_IGMP
1541     case IP_MULTICAST_TTL:
1542       if (*optlen < sizeof(u8_t)) {
1543         err = EINVAL;
1544       }
1545       break;
1546     case IP_MULTICAST_IF:
1547       if (*optlen < sizeof(struct in_addr)) {
1548         err = EINVAL;
1549       }
1550       break;
1551     case IP_MULTICAST_LOOP:
1552       if (*optlen < sizeof(u8_t)) {
1553         err = EINVAL;
1554       }
1555       if (NETCONNTYPE_GROUP(sock->conn->type) != NETCONN_UDP) {
1556         err = EAFNOSUPPORT;
1557       }
1558       break;
1559 #endif /* LWIP_IGMP */
1560 
1561     default:
1562       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, UNIMPL: optname=0x%x, ..)\n",
1563                                   s, optname));
1564       err = ENOPROTOOPT;
1565     }  /* switch (optname) */
1566     break;
1567 
1568 #if LWIP_TCP
1569 /* Level: IPPROTO_TCP */
1570   case IPPROTO_TCP:
1571     if (*optlen < sizeof(int)) {
1572       err = EINVAL;
1573       break;
1574     }
1575 
1576     /* If this is no TCP socket, ignore any options. */
1577     if (sock->conn->type != NETCONN_TCP)
1578       return 0;
1579 
1580     switch (optname) {
1581     case TCP_NODELAY:
1582     case TCP_KEEPALIVE:
1583 #if LWIP_TCP_KEEPALIVE
1584     case TCP_KEEPIDLE:
1585     case TCP_KEEPINTVL:
1586     case TCP_KEEPCNT:
1587 #endif /* LWIP_TCP_KEEPALIVE */
1588       break;
1589 
1590     default:
1591       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_TCP, UNIMPL: optname=0x%x, ..)\n",
1592                                   s, optname));
1593       err = ENOPROTOOPT;
1594     }  /* switch (optname) */
1595     break;
1596 #endif /* LWIP_TCP */
1597 #if LWIP_UDP && LWIP_UDPLITE
1598 /* Level: IPPROTO_UDPLITE */
1599   case IPPROTO_UDPLITE:
1600     if (*optlen < sizeof(int)) {
1601       err = EINVAL;
1602       break;
1603     }
1604 
1605     /* If this is no UDP lite socket, ignore any options. */
1606     if (sock->conn->type != NETCONN_UDPLITE) {
1607       return 0;
1608     }
1609 
1610     switch (optname) {
1611     case UDPLITE_SEND_CSCOV:
1612     case UDPLITE_RECV_CSCOV:
1613       break;
1614 
1615     default:
1616       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_UDPLITE, UNIMPL: optname=0x%x, ..)\n",
1617                                   s, optname));
1618       err = ENOPROTOOPT;
1619     }  /* switch (optname) */
1620     break;
1621 #endif /* LWIP_UDP && LWIP_UDPLITE*/
1622 /* UNDEFINED LEVEL */
1623   default:
1624       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, level=0x%x, UNIMPL: optname=0x%x, ..)\n",
1625                                   s, level, optname));
1626       err = ENOPROTOOPT;
1627   }  /* switch */
1628 
1629 
1630   if (err != ERR_OK) {
1631     sock_set_errno(sock, err);
1632     return -1;
1633   }
1634 
1635   /* Now do the actual option processing */
1636   data.sock = sock;
1637 #ifdef LWIP_DEBUG
1638   data.s = s;
1639 #endif /* LWIP_DEBUG */
1640   data.level = level;
1641   data.optname = optname;
1642   data.optval = optval;
1643   data.optlen = optlen;
1644   data.err = err;
1645   tcpip_callback(lwip_getsockopt_internal, &data);
1646   sys_arch_sem_wait(&sock->conn->op_completed, 0);
1647   /* maybe lwip_getsockopt_internal has changed err */
1648   err = data.err;
1649 
1650   sock_set_errno(sock, err);
1651   return err ? -1 : 0;
1652 }
1653 
1654 static void
1655 lwip_getsockopt_internal(void *arg)
1656 {
1657   struct lwip_sock *sock;
1658 #ifdef LWIP_DEBUG
1659   int s;
1660 #endif /* LWIP_DEBUG */
1661   int level, optname;
1662   void *optval;
1663   struct lwip_setgetsockopt_data *data;
1664 
1665   LWIP_ASSERT("arg != NULL", arg != NULL);
1666 
1667   data = (struct lwip_setgetsockopt_data*)arg;
1668   sock = data->sock;
1669 #ifdef LWIP_DEBUG
1670   s = data->s;
1671 #endif /* LWIP_DEBUG */
1672   level = data->level;
1673   optname = data->optname;
1674   optval = data->optval;
1675 
1676   switch (level) {
1677 
1678 /* Level: SOL_SOCKET */
1679   case SOL_SOCKET:
1680     switch (optname) {
1681 
1682     /* The option flags */
1683     case SO_ACCEPTCONN:
1684     case SO_BROADCAST:
1685     /* UNIMPL case SO_DEBUG: */
1686     /* UNIMPL case SO_DONTROUTE: */
1687     case SO_KEEPALIVE:
1688     /* UNIMPL case SO_OOBINCLUDE: */
1689 #if SO_REUSE
1690     case SO_REUSEADDR:
1691     case SO_REUSEPORT:
1692 #endif /* SO_REUSE */
1693     /*case SO_USELOOPBACK: UNIMPL */
1694       *(int*)optval = ip_get_option(sock->conn->pcb.ip, optname);
1695       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, optname=0x%x, ..) = %s\n",
1696                                   s, optname, (*(int*)optval?"on":"off")));
1697       break;
1698 
1699     case SO_TYPE:
1700       switch (NETCONNTYPE_GROUP(sock->conn->type)) {
1701       case NETCONN_RAW:
1702         *(int*)optval = SOCK_RAW;
1703         break;
1704       case NETCONN_TCP:
1705         *(int*)optval = SOCK_STREAM;
1706         break;
1707       case NETCONN_UDP:
1708         *(int*)optval = SOCK_DGRAM;
1709         break;
1710       default: /* unrecognized socket type */
1711         *(int*)optval = sock->conn->type;
1712         LWIP_DEBUGF(SOCKETS_DEBUG,
1713                     ("lwip_getsockopt(%d, SOL_SOCKET, SO_TYPE): unrecognized socket type %d\n",
1714                     s, *(int *)optval));
1715       }  /* switch (sock->conn->type) */
1716       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, SO_TYPE) = %d\n",
1717                   s, *(int *)optval));
1718       break;
1719 
1720     case SO_ERROR:
1721       /* only overwrite ERR_OK or tempoary errors */
1722       if ((sock->err == 0) || (sock->err == EINPROGRESS)) {
1723         sock_set_errno(sock, err_to_errno(sock->conn->last_err));
1724       }
1725       *(int *)optval = sock->err;
1726       sock->err = 0;
1727       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, SO_ERROR) = %d\n",
1728                   s, *(int *)optval));
1729       break;
1730 
1731 #if LWIP_SO_SNDTIMEO
1732     case SO_SNDTIMEO:
1733       *(int *)optval = netconn_get_sendtimeout(sock->conn);
1734       break;
1735 #endif /* LWIP_SO_SNDTIMEO */
1736 #if LWIP_SO_RCVTIMEO
1737     case SO_RCVTIMEO:
1738       *(int *)optval = netconn_get_recvtimeout(sock->conn);
1739       break;
1740 #endif /* LWIP_SO_RCVTIMEO */
1741 #if LWIP_SO_RCVBUF
1742     case SO_RCVBUF:
1743       *(int *)optval = netconn_get_recvbufsize(sock->conn);
1744       break;
1745 #endif /* LWIP_SO_RCVBUF */
1746 #if LWIP_UDP
1747     case SO_NO_CHECK:
1748       *(int*)optval = (udp_flags(sock->conn->pcb.udp) & UDP_FLAGS_NOCHKSUM) ? 1 : 0;
1749       break;
1750 #endif /* LWIP_UDP*/
1751     default:
1752       LWIP_ASSERT("unhandled optname", 0);
1753       break;
1754     }  /* switch (optname) */
1755     break;
1756 
1757 /* Level: IPPROTO_IP */
1758   case IPPROTO_IP:
1759     switch (optname) {
1760     case IP_TTL:
1761       *(int*)optval = sock->conn->pcb.ip->ttl;
1762       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_TTL) = %d\n",
1763                   s, *(int *)optval));
1764       break;
1765     case IP_TOS:
1766       *(int*)optval = sock->conn->pcb.ip->tos;
1767       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_TOS) = %d\n",
1768                   s, *(int *)optval));
1769       break;
1770 #if LWIP_IGMP
1771     case IP_MULTICAST_TTL:
1772       *(u8_t*)optval = sock->conn->pcb.ip->ttl;
1773       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_MULTICAST_TTL) = %d\n",
1774                   s, *(int *)optval));
1775       break;
1776     case IP_MULTICAST_IF:
1777       inet_addr_from_ipaddr((struct in_addr*)optval, &sock->conn->pcb.udp->multicast_ip);
1778       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_MULTICAST_IF) = 0x%"X32_F"\n",
1779                   s, *(u32_t *)optval));
1780       break;
1781     case IP_MULTICAST_LOOP:
1782       if ((sock->conn->pcb.udp->flags & UDP_FLAGS_MULTICAST_LOOP) != 0) {
1783         *(u8_t*)optval = 1;
1784       } else {
1785         *(u8_t*)optval = 0;
1786       }
1787       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_MULTICAST_LOOP) = %d\n",
1788                   s, *(int *)optval));
1789       break;
1790 #endif /* LWIP_IGMP */
1791     default:
1792       LWIP_ASSERT("unhandled optname", 0);
1793       break;
1794     }  /* switch (optname) */
1795     break;
1796 
1797 #if LWIP_TCP
1798 /* Level: IPPROTO_TCP */
1799   case IPPROTO_TCP:
1800     switch (optname) {
1801     case TCP_NODELAY:
1802       *(int*)optval = tcp_nagle_disabled(sock->conn->pcb.tcp);
1803       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_TCP, TCP_NODELAY) = %s\n",
1804                   s, (*(int*)optval)?"on":"off") );
1805       break;
1806     case TCP_KEEPALIVE:
1807       *(int*)optval = (int)sock->conn->pcb.tcp->keep_idle;
1808       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, TCP_KEEPALIVE) = %d\n",
1809                   s, *(int *)optval));
1810       break;
1811 
1812 #if LWIP_TCP_KEEPALIVE
1813     case TCP_KEEPIDLE:
1814       *(int*)optval = (int)(sock->conn->pcb.tcp->keep_idle/1000);
1815       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, TCP_KEEPIDLE) = %d\n",
1816                   s, *(int *)optval));
1817       break;
1818     case TCP_KEEPINTVL:
1819       *(int*)optval = (int)(sock->conn->pcb.tcp->keep_intvl/1000);
1820       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, TCP_KEEPINTVL) = %d\n",
1821                   s, *(int *)optval));
1822       break;
1823     case TCP_KEEPCNT:
1824       *(int*)optval = (int)sock->conn->pcb.tcp->keep_cnt;
1825       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, TCP_KEEPCNT) = %d\n",
1826                   s, *(int *)optval));
1827       break;
1828 #endif /* LWIP_TCP_KEEPALIVE */
1829     default:
1830       LWIP_ASSERT("unhandled optname", 0);
1831       break;
1832     }  /* switch (optname) */
1833     break;
1834 #endif /* LWIP_TCP */
1835 #if LWIP_UDP && LWIP_UDPLITE
1836   /* Level: IPPROTO_UDPLITE */
1837   case IPPROTO_UDPLITE:
1838     switch (optname) {
1839     case UDPLITE_SEND_CSCOV:
1840       *(int*)optval = sock->conn->pcb.udp->chksum_len_tx;
1841       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_UDPLITE, UDPLITE_SEND_CSCOV) = %d\n",
1842                   s, (*(int*)optval)) );
1843       break;
1844     case UDPLITE_RECV_CSCOV:
1845       *(int*)optval = sock->conn->pcb.udp->chksum_len_rx;
1846       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_UDPLITE, UDPLITE_RECV_CSCOV) = %d\n",
1847                   s, (*(int*)optval)) );
1848       break;
1849     default:
1850       LWIP_ASSERT("unhandled optname", 0);
1851       break;
1852     }  /* switch (optname) */
1853     break;
1854 #endif /* LWIP_UDP */
1855   default:
1856     LWIP_ASSERT("unhandled level", 0);
1857     break;
1858   } /* switch (level) */
1859   sys_sem_signal(&sock->conn->op_completed);
1860 }
1861 
1862 int
1863 lwip_setsockopt(int s, int level, int optname, const void *optval, socklen_t optlen)
1864 {
1865   struct lwip_sock *sock = get_socket(s);
1866   err_t err = ERR_OK;
1867   struct lwip_setgetsockopt_data data;
1868 
1869   if (!sock) {
1870     return -1;
1871   }
1872 
1873   if (NULL == optval) {
1874     sock_set_errno(sock, EFAULT);
1875     return -1;
1876   }
1877 
1878   /* Do length and type checks for the various options first, to keep it readable. */
1879   switch (level) {
1880 
1881 /* Level: SOL_SOCKET */
1882   case SOL_SOCKET:
1883     switch (optname) {
1884 
1885     case SO_BROADCAST:
1886     /* UNIMPL case SO_DEBUG: */
1887     /* UNIMPL case SO_DONTROUTE: */
1888     case SO_KEEPALIVE:
1889     /* UNIMPL case case SO_CONTIMEO: */
1890 #if LWIP_SO_SNDTIMEO
1891     case SO_SNDTIMEO:
1892 #endif /* LWIP_SO_SNDTIMEO */
1893 #if LWIP_SO_RCVTIMEO
1894     case SO_RCVTIMEO:
1895 #endif /* LWIP_SO_RCVTIMEO */
1896 #if LWIP_SO_RCVBUF
1897     case SO_RCVBUF:
1898 #endif /* LWIP_SO_RCVBUF */
1899     /* UNIMPL case SO_OOBINLINE: */
1900     /* UNIMPL case SO_SNDBUF: */
1901     /* UNIMPL case SO_RCVLOWAT: */
1902     /* UNIMPL case SO_SNDLOWAT: */
1903 #if SO_REUSE
1904     case SO_REUSEADDR:
1905     case SO_REUSEPORT:
1906 #endif /* SO_REUSE */
1907     /* UNIMPL case SO_USELOOPBACK: */
1908       if (optlen < sizeof(int)) {
1909         err = EINVAL;
1910       }
1911       break;
1912     case SO_NO_CHECK:
1913       if (optlen < sizeof(int)) {
1914         err = EINVAL;
1915       }
1916 #if LWIP_UDP
1917       if ((sock->conn->type != NETCONN_UDP) ||
1918           ((udp_flags(sock->conn->pcb.udp) & UDP_FLAGS_UDPLITE) != 0)) {
1919         /* this flag is only available for UDP, not for UDP lite */
1920         err = EAFNOSUPPORT;
1921       }
1922 #endif /* LWIP_UDP */
1923       break;
1924     default:
1925       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, SOL_SOCKET, UNIMPL: optname=0x%x, ..)\n",
1926                   s, optname));
1927       err = ENOPROTOOPT;
1928     }  /* switch (optname) */
1929     break;
1930 
1931 /* Level: IPPROTO_IP */
1932   case IPPROTO_IP:
1933     switch (optname) {
1934     /* UNIMPL case IP_HDRINCL: */
1935     /* UNIMPL case IP_RCVDSTADDR: */
1936     /* UNIMPL case IP_RCVIF: */
1937     case IP_TTL:
1938     case IP_TOS:
1939       if (optlen < sizeof(int)) {
1940         err = EINVAL;
1941       }
1942       break;
1943 #if LWIP_IGMP
1944     case IP_MULTICAST_TTL:
1945       if (optlen < sizeof(u8_t)) {
1946         err = EINVAL;
1947       }
1948       if (NETCONNTYPE_GROUP(sock->conn->type) != NETCONN_UDP) {
1949         err = EAFNOSUPPORT;
1950       }
1951       break;
1952     case IP_MULTICAST_IF:
1953       if (optlen < sizeof(struct in_addr)) {
1954         err = EINVAL;
1955       }
1956       if (NETCONNTYPE_GROUP(sock->conn->type) != NETCONN_UDP) {
1957         err = EAFNOSUPPORT;
1958       }
1959       break;
1960     case IP_MULTICAST_LOOP:
1961       if (optlen < sizeof(u8_t)) {
1962         err = EINVAL;
1963       }
1964       if (NETCONNTYPE_GROUP(sock->conn->type) != NETCONN_UDP) {
1965         err = EAFNOSUPPORT;
1966       }
1967       break;
1968     case IP_ADD_MEMBERSHIP:
1969     case IP_DROP_MEMBERSHIP:
1970       if (optlen < sizeof(struct ip_mreq)) {
1971         err = EINVAL;
1972       }
1973       if (NETCONNTYPE_GROUP(sock->conn->type) != NETCONN_UDP) {
1974         err = EAFNOSUPPORT;
1975       }
1976       break;
1977 #endif /* LWIP_IGMP */
1978       default:
1979         LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IP, UNIMPL: optname=0x%x, ..)\n",
1980                     s, optname));
1981         err = ENOPROTOOPT;
1982     }  /* switch (optname) */
1983     break;
1984 
1985 #if LWIP_TCP
1986 /* Level: IPPROTO_TCP */
1987   case IPPROTO_TCP:
1988     if (optlen < sizeof(int)) {
1989       err = EINVAL;
1990       break;
1991     }
1992 
1993     /* If this is no TCP socket, ignore any options. */
1994     if (sock->conn->type != NETCONN_TCP)
1995       return 0;
1996 
1997     switch (optname) {
1998     case TCP_NODELAY:
1999     case TCP_KEEPALIVE:
2000 #if LWIP_TCP_KEEPALIVE
2001     case TCP_KEEPIDLE:
2002     case TCP_KEEPINTVL:
2003     case TCP_KEEPCNT:
2004 #endif /* LWIP_TCP_KEEPALIVE */
2005       break;
2006 
2007     default:
2008       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, UNIMPL: optname=0x%x, ..)\n",
2009                   s, optname));
2010       err = ENOPROTOOPT;
2011     }  /* switch (optname) */
2012     break;
2013 #endif /* LWIP_TCP */
2014 #if LWIP_UDP && LWIP_UDPLITE
2015 /* Level: IPPROTO_UDPLITE */
2016   case IPPROTO_UDPLITE:
2017     if (optlen < sizeof(int)) {
2018       err = EINVAL;
2019       break;
2020     }
2021 
2022     /* If this is no UDP lite socket, ignore any options. */
2023     if (sock->conn->type != NETCONN_UDPLITE)
2024       return 0;
2025 
2026     switch (optname) {
2027     case UDPLITE_SEND_CSCOV:
2028     case UDPLITE_RECV_CSCOV:
2029       break;
2030 
2031     default:
2032       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_UDPLITE, UNIMPL: optname=0x%x, ..)\n",
2033                   s, optname));
2034       err = ENOPROTOOPT;
2035     }  /* switch (optname) */
2036     break;
2037 #endif /* LWIP_UDP && LWIP_UDPLITE */
2038 /* UNDEFINED LEVEL */
2039   default:
2040     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, level=0x%x, UNIMPL: optname=0x%x, ..)\n",
2041                 s, level, optname));
2042     err = ENOPROTOOPT;
2043   }  /* switch (level) */
2044 
2045 
2046   if (err != ERR_OK) {
2047     sock_set_errno(sock, err);
2048     return -1;
2049   }
2050 
2051 
2052   /* Now do the actual option processing */
2053   data.sock = sock;
2054 #ifdef LWIP_DEBUG
2055   data.s = s;
2056 #endif /* LWIP_DEBUG */
2057   data.level = level;
2058   data.optname = optname;
2059   data.optval = (void*)optval;
2060   data.optlen = &optlen;
2061   data.err = err;
2062   tcpip_callback(lwip_setsockopt_internal, &data);
2063   sys_arch_sem_wait(&sock->conn->op_completed, 0);
2064   /* maybe lwip_setsockopt_internal has changed err */
2065   err = data.err;
2066 
2067   sock_set_errno(sock, err);
2068   return err ? -1 : 0;
2069 }
2070 
2071 static void
2072 lwip_setsockopt_internal(void *arg)
2073 {
2074   struct lwip_sock *sock;
2075 #ifdef LWIP_DEBUG
2076   int s;
2077 #endif /* LWIP_DEBUG */
2078   int level, optname;
2079   const void *optval;
2080   struct lwip_setgetsockopt_data *data;
2081 
2082   LWIP_ASSERT("arg != NULL", arg != NULL);
2083 
2084   data = (struct lwip_setgetsockopt_data*)arg;
2085   sock = data->sock;
2086 #ifdef LWIP_DEBUG
2087   s = data->s;
2088 #endif /* LWIP_DEBUG */
2089   level = data->level;
2090   optname = data->optname;
2091   optval = data->optval;
2092 
2093   switch (level) {
2094 
2095 /* Level: SOL_SOCKET */
2096   case SOL_SOCKET:
2097     switch (optname) {
2098 
2099     /* The option flags */
2100     case SO_BROADCAST:
2101     /* UNIMPL case SO_DEBUG: */
2102     /* UNIMPL case SO_DONTROUTE: */
2103     case SO_KEEPALIVE:
2104     /* UNIMPL case SO_OOBINCLUDE: */
2105 #if SO_REUSE
2106     case SO_REUSEADDR:
2107     case SO_REUSEPORT:
2108 #endif /* SO_REUSE */
2109     /* UNIMPL case SO_USELOOPBACK: */
2110       if (*(int*)optval) {
2111         ip_set_option(sock->conn->pcb.ip, optname);
2112       } else {
2113         ip_reset_option(sock->conn->pcb.ip, optname);
2114       }
2115       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, SOL_SOCKET, optname=0x%x, ..) -> %s\n",
2116                   s, optname, (*(int*)optval?"on":"off")));
2117       break;
2118 #if LWIP_SO_SNDTIMEO
2119     case SO_SNDTIMEO:
2120       netconn_set_sendtimeout(sock->conn, (s32_t)*(int*)optval);
2121       break;
2122 #endif /* LWIP_SO_SNDTIMEO */
2123 #if LWIP_SO_RCVTIMEO
2124     case SO_RCVTIMEO:
2125       netconn_set_recvtimeout(sock->conn, *(int*)optval);
2126       break;
2127 #endif /* LWIP_SO_RCVTIMEO */
2128 #if LWIP_SO_RCVBUF
2129     case SO_RCVBUF:
2130       netconn_set_recvbufsize(sock->conn, *(int*)optval);
2131       break;
2132 #endif /* LWIP_SO_RCVBUF */
2133 #if LWIP_UDP
2134     case SO_NO_CHECK:
2135       if (*(int*)optval) {
2136         udp_setflags(sock->conn->pcb.udp, udp_flags(sock->conn->pcb.udp) | UDP_FLAGS_NOCHKSUM);
2137       } else {
2138         udp_setflags(sock->conn->pcb.udp, udp_flags(sock->conn->pcb.udp) & ~UDP_FLAGS_NOCHKSUM);
2139       }
2140       break;
2141 #endif /* LWIP_UDP */
2142     default:
2143       LWIP_ASSERT("unhandled optname", 0);
2144       break;
2145     }  /* switch (optname) */
2146     break;
2147 
2148 /* Level: IPPROTO_IP */
2149   case IPPROTO_IP:
2150     switch (optname) {
2151     case IP_TTL:
2152       sock->conn->pcb.ip->ttl = (u8_t)(*(int*)optval);
2153       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IP, IP_TTL, ..) -> %d\n",
2154                   s, sock->conn->pcb.ip->ttl));
2155       break;
2156     case IP_TOS:
2157       sock->conn->pcb.ip->tos = (u8_t)(*(int*)optval);
2158       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IP, IP_TOS, ..)-> %d\n",
2159                   s, sock->conn->pcb.ip->tos));
2160       break;
2161 #if LWIP_IGMP
2162     case IP_MULTICAST_TTL:
2163       sock->conn->pcb.udp->ttl = (u8_t)(*(u8_t*)optval);
2164       break;
2165     case IP_MULTICAST_IF:
2166       inet_addr_to_ipaddr(&sock->conn->pcb.udp->multicast_ip, (struct in_addr*)optval);
2167       break;
2168     case IP_MULTICAST_LOOP:
2169       if (*(u8_t*)optval) {
2170         udp_setflags(sock->conn->pcb.udp, udp_flags(sock->conn->pcb.udp) | UDP_FLAGS_MULTICAST_LOOP);
2171       } else {
2172         udp_setflags(sock->conn->pcb.udp, udp_flags(sock->conn->pcb.udp) & ~UDP_FLAGS_MULTICAST_LOOP);
2173       }
2174       break;
2175     case IP_ADD_MEMBERSHIP:
2176     case IP_DROP_MEMBERSHIP:
2177       {
2178         /* If this is a TCP or a RAW socket, ignore these options. */
2179         struct ip_mreq *imr = (struct ip_mreq *)optval;
2180         ip_addr_t if_addr;
2181         ip_addr_t multi_addr;
2182         inet_addr_to_ipaddr(&if_addr, &imr->imr_interface);
2183         inet_addr_to_ipaddr(&multi_addr, &imr->imr_multiaddr);
2184         if(optname == IP_ADD_MEMBERSHIP){
2185           data->err = igmp_joingroup(&if_addr, &multi_addr);
2186         } else {
2187           data->err = igmp_leavegroup(&if_addr, &multi_addr);
2188         }
2189         if(data->err != ERR_OK) {
2190           data->err = EADDRNOTAVAIL;
2191         }
2192       }
2193       break;
2194 #endif /* LWIP_IGMP */
2195     default:
2196       LWIP_ASSERT("unhandled optname", 0);
2197       break;
2198     }  /* switch (optname) */
2199     break;
2200 
2201 #if LWIP_TCP
2202 /* Level: IPPROTO_TCP */
2203   case IPPROTO_TCP:
2204     switch (optname) {
2205     case TCP_NODELAY:
2206       if (*(int*)optval) {
2207         tcp_nagle_disable(sock->conn->pcb.tcp);
2208       } else {
2209         tcp_nagle_enable(sock->conn->pcb.tcp);
2210       }
2211       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_NODELAY) -> %s\n",
2212                   s, (*(int *)optval)?"on":"off") );
2213       break;
2214     case TCP_KEEPALIVE:
2215       sock->conn->pcb.tcp->keep_idle = (u32_t)(*(int*)optval);
2216       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPALIVE) -> %"U32_F"\n",
2217                   s, sock->conn->pcb.tcp->keep_idle));
2218       break;
2219 
2220 #if LWIP_TCP_KEEPALIVE
2221     case TCP_KEEPIDLE:
2222       sock->conn->pcb.tcp->keep_idle = 1000*(u32_t)(*(int*)optval);
2223       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPIDLE) -> %"U32_F"\n",
2224                   s, sock->conn->pcb.tcp->keep_idle));
2225       break;
2226     case TCP_KEEPINTVL:
2227       sock->conn->pcb.tcp->keep_intvl = 1000*(u32_t)(*(int*)optval);
2228       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPINTVL) -> %"U32_F"\n",
2229                   s, sock->conn->pcb.tcp->keep_intvl));
2230       break;
2231     case TCP_KEEPCNT:
2232       sock->conn->pcb.tcp->keep_cnt = (u32_t)(*(int*)optval);
2233       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPCNT) -> %"U32_F"\n",
2234                   s, sock->conn->pcb.tcp->keep_cnt));
2235       break;
2236 #endif /* LWIP_TCP_KEEPALIVE */
2237     default:
2238       LWIP_ASSERT("unhandled optname", 0);
2239       break;
2240     }  /* switch (optname) */
2241     break;
2242 #endif /* LWIP_TCP*/
2243 #if LWIP_UDP && LWIP_UDPLITE
2244   /* Level: IPPROTO_UDPLITE */
2245   case IPPROTO_UDPLITE:
2246     switch (optname) {
2247     case UDPLITE_SEND_CSCOV:
2248       if ((*(int*)optval != 0) && ((*(int*)optval < 8) || (*(int*)optval > 0xffff))) {
2249         /* don't allow illegal values! */
2250         sock->conn->pcb.udp->chksum_len_tx = 8;
2251       } else {
2252         sock->conn->pcb.udp->chksum_len_tx = (u16_t)*(int*)optval;
2253       }
2254       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_UDPLITE, UDPLITE_SEND_CSCOV) -> %d\n",
2255                   s, (*(int*)optval)) );
2256       break;
2257     case UDPLITE_RECV_CSCOV:
2258       if ((*(int*)optval != 0) && ((*(int*)optval < 8) || (*(int*)optval > 0xffff))) {
2259         /* don't allow illegal values! */
2260         sock->conn->pcb.udp->chksum_len_rx = 8;
2261       } else {
2262         sock->conn->pcb.udp->chksum_len_rx = (u16_t)*(int*)optval;
2263       }
2264       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_UDPLITE, UDPLITE_RECV_CSCOV) -> %d\n",
2265                   s, (*(int*)optval)) );
2266       break;
2267     default:
2268       LWIP_ASSERT("unhandled optname", 0);
2269       break;
2270     }  /* switch (optname) */
2271     break;
2272 #endif /* LWIP_UDP */
2273   default:
2274     LWIP_ASSERT("unhandled level", 0);
2275     break;
2276   }  /* switch (level) */
2277   sys_sem_signal(&sock->conn->op_completed);
2278 }
2279 
2280 int
2281 lwip_ioctl(int s, long cmd, void *argp)
2282 {
2283   struct lwip_sock *sock = get_socket(s);
2284   u8_t val;
2285 #if LWIP_SO_RCVBUF
2286   u16_t buflen = 0;
2287   s16_t recv_avail;
2288 #endif /* LWIP_SO_RCVBUF */
2289 
2290   if (!sock) {
2291     return -1;
2292   }
2293 
2294   switch (cmd) {
2295 #if LWIP_SO_RCVBUF
2296   case FIONREAD:
2297     if (!argp) {
2298       sock_set_errno(sock, EINVAL);
2299       return -1;
2300     }
2301 
2302     SYS_ARCH_GET(sock->conn->recv_avail, recv_avail);
2303     if (recv_avail < 0) {
2304       recv_avail = 0;
2305     }
2306     *((u16_t*)argp) = (u16_t)recv_avail;
2307 
2308     /* Check if there is data left from the last recv operation. /maq 041215 */
2309     if (sock->lastdata) {
2310       struct pbuf *p = (struct pbuf *)sock->lastdata;
2311       if (netconn_type(sock->conn) != NETCONN_TCP) {
2312         p = ((struct netbuf *)p)->p;
2313       }
2314       buflen = p->tot_len;
2315       buflen -= sock->lastoffset;
2316 
2317       *((u16_t*)argp) += buflen;
2318     }
2319 
2320     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(%d, FIONREAD, %p) = %"U16_F"\n", s, argp, *((u16_t*)argp)));
2321     sock_set_errno(sock, 0);
2322     return 0;
2323 #endif /* LWIP_SO_RCVBUF */
2324 
2325   case FIONBIO:
2326     val = 0;
2327     if (argp && *(u32_t*)argp) {
2328       val = 1;
2329     }
2330     netconn_set_nonblocking(sock->conn, val);
2331     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(%d, FIONBIO, %d)\n", s, val));
2332     sock_set_errno(sock, 0);
2333     return 0;
2334 
2335   default:
2336     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(%d, UNIMPL: 0x%lx, %p)\n", s, cmd, argp));
2337     sock_set_errno(sock, ENOSYS); /* not yet implemented */
2338     return -1;
2339   } /* switch (cmd) */
2340 }
2341 
2342 /** A minimal implementation of fcntl.
2343  * Currently only the commands F_GETFL and F_SETFL are implemented.
2344  * Only the flag O_NONBLOCK is implemented.
2345  */
2346 int
2347 lwip_fcntl(int s, int cmd, int val)
2348 {
2349   struct lwip_sock *sock = get_socket(s);
2350   int ret = -1;
2351 
2352   if (!sock || !sock->conn) {
2353     return -1;
2354   }
2355 
2356   switch (cmd) {
2357   case F_GETFL:
2358     ret = netconn_is_nonblocking(sock->conn) ? O_NONBLOCK : 0;
2359     break;
2360   case F_SETFL:
2361     if ((val & ~O_NONBLOCK) == 0) {
2362       /* only O_NONBLOCK, all other bits are zero */
2363       netconn_set_nonblocking(sock->conn, val & O_NONBLOCK);
2364       ret = 0;
2365     }
2366     break;
2367   default:
2368     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_fcntl(%d, UNIMPL: %d, %d)\n", s, cmd, val));
2369     break;
2370   }
2371   return ret;
2372 }
2373 
2374 #endif /* LWIP_SOCKET */
2375