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