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