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