]> rtime.felk.cvut.cz Git - pes-rpp/rpp-lwip.git/blob - src/api/sockets.c
81cbf24ee36ef3bd9cb575b3c6ab687e93b9c1b7
[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.raw->remote_ip;
918         if (NETCONNTYPE_GROUP(sock->conn->type) == NETCONN_RAW) {
919           remote_port = 0;
920         } else {
921           remote_port = sock->conn->pcb.udp->remote_port;
922         }
923       }
924
925       LOCK_TCPIP_CORE();
926       if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_RAW) {
927         err = sock->conn->last_err = raw_sendto(sock->conn->pcb.raw, p, ipX_2_ip(remote_addr));
928       } else {
929 #if LWIP_UDP
930 #if LWIP_CHECKSUM_ON_COPY && LWIP_NETIF_TX_SINGLE_PBUF
931         err = sock->conn->last_err = udp_sendto_chksum(sock->conn->pcb.udp, p,
932           ipX_2_ip(remote_addr), remote_port, 1, chksum);
933 #else /* LWIP_CHECKSUM_ON_COPY && LWIP_NETIF_TX_SINGLE_PBUF */
934         err = sock->conn->last_err = udp_sendto(sock->conn->pcb.udp, p,
935           ipX_2_ip(remote_addr), remote_port);
936 #endif /* LWIP_CHECKSUM_ON_COPY && LWIP_NETIF_TX_SINGLE_PBUF */
937 #else /* LWIP_UDP */
938         err = ERR_ARG;
939 #endif /* LWIP_UDP */
940       }
941       UNLOCK_TCPIP_CORE();
942       
943       pbuf_free(p);
944     } else {
945       err = ERR_MEM;
946     }
947   }
948 #else /* LWIP_TCPIP_CORE_LOCKING */
949   /* initialize a buffer */
950   buf.p = buf.ptr = NULL;
951 #if LWIP_CHECKSUM_ON_COPY
952   buf.flags = 0;
953 #endif /* LWIP_CHECKSUM_ON_COPY */
954   if (to) {
955     SOCKADDR_TO_IPXADDR_PORT((to->sa_family) == AF_INET6, to, &buf.addr, remote_port);
956   } else {
957     remote_port = 0;
958     ipX_addr_set_any(NETCONNTYPE_ISIPV6(netconn_type(sock->conn)), &buf.addr);
959   }
960   netbuf_fromport(&buf) = remote_port;
961
962
963   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_sendto(%d, data=%p, short_size=%"U16_F", flags=0x%x to=",
964               s, data, short_size, flags));
965   ipX_addr_debug_print(NETCONNTYPE_ISIPV6(netconn_type(sock->conn)),
966     SOCKETS_DEBUG, &buf.addr);
967   LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F"\n", remote_port));
968
969   /* make the buffer point to the data that should be sent */
970 #if LWIP_NETIF_TX_SINGLE_PBUF
971   /* Allocate a new netbuf and copy the data into it. */
972   if (netbuf_alloc(&buf, short_size) == NULL) {
973     err = ERR_MEM;
974   } else {
975 #if LWIP_CHECKSUM_ON_COPY
976     if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_RAW) {
977       u16_t chksum = LWIP_CHKSUM_COPY(buf.p->payload, data, short_size);
978       netbuf_set_chksum(&buf, chksum);
979       err = ERR_OK;
980     } else
981 #endif /* LWIP_CHECKSUM_ON_COPY */
982     {
983       err = netbuf_take(&buf, data, short_size);
984     }
985   }
986 #else /* LWIP_NETIF_TX_SINGLE_PBUF */
987   err = netbuf_ref(&buf, data, short_size);
988 #endif /* LWIP_NETIF_TX_SINGLE_PBUF */
989   if (err == ERR_OK) {
990     /* send the data */
991     err = netconn_send(sock->conn, &buf);
992   }
993
994   /* deallocated the buffer */
995   netbuf_free(&buf);
996 #endif /* LWIP_TCPIP_CORE_LOCKING */
997   sock_set_errno(sock, err_to_errno(err));
998   return (err == ERR_OK ? short_size : -1);
999 }
1000
1001 int
1002 lwip_socket(int domain, int type, int protocol)
1003 {
1004   struct netconn *conn;
1005   int i;
1006
1007 #if !LWIP_IPV6
1008   LWIP_UNUSED_ARG(domain); /* @todo: check this */
1009 #endif /* LWIP_IPV6 */
1010
1011   /* create a netconn */
1012   switch (type) {
1013   case SOCK_RAW:
1014     conn = netconn_new_with_proto_and_callback(DOMAIN_TO_NETCONN_TYPE(domain, NETCONN_RAW),
1015                                                (u8_t)protocol, event_callback);
1016     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_RAW, %d) = ",
1017                                  domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol));
1018     break;
1019   case SOCK_DGRAM:
1020     conn = netconn_new_with_callback(DOMAIN_TO_NETCONN_TYPE(domain,
1021                  ((protocol == IPPROTO_UDPLITE) ? NETCONN_UDPLITE : NETCONN_UDP)) ,
1022                  event_callback);
1023     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_DGRAM, %d) = ",
1024                                  domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol));
1025     break;
1026   case SOCK_STREAM:
1027     conn = netconn_new_with_callback(DOMAIN_TO_NETCONN_TYPE(domain, NETCONN_TCP), event_callback);
1028     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_STREAM, %d) = ",
1029                                  domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol));
1030     if (conn != NULL) {
1031       /* Prevent automatic window updates, we do this on our own! */
1032       netconn_set_noautorecved(conn, 1);
1033     }
1034     break;
1035   default:
1036     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%d, %d/UNKNOWN, %d) = -1\n",
1037                                  domain, type, protocol));
1038     set_errno(EINVAL);
1039     return -1;
1040   }
1041
1042   if (!conn) {
1043     LWIP_DEBUGF(SOCKETS_DEBUG, ("-1 / ENOBUFS (could not create netconn)\n"));
1044     set_errno(ENOBUFS);
1045     return -1;
1046   }
1047
1048   i = alloc_socket(conn, 0);
1049
1050   if (i == -1) {
1051     netconn_delete(conn);
1052     set_errno(ENFILE);
1053     return -1;
1054   }
1055   conn->socket = i;
1056   LWIP_DEBUGF(SOCKETS_DEBUG, ("%d\n", i));
1057   set_errno(0);
1058   return i;
1059 }
1060
1061 int
1062 lwip_write(int s, const void *data, size_t size)
1063 {
1064   return lwip_send(s, data, size, 0);
1065 }
1066
1067 /**
1068  * Go through the readset and writeset lists and see which socket of the sockets
1069  * set in the sets has events. On return, readset, writeset and exceptset have
1070  * the sockets enabled that had events.
1071  *
1072  * exceptset is not used for now!!!
1073  *
1074  * @param maxfdp1 the highest socket index in the sets
1075  * @param readset_in:    set of sockets to check for read events
1076  * @param writeset_in:   set of sockets to check for write events
1077  * @param exceptset_in:  set of sockets to check for error events
1078  * @param readset_out:   set of sockets that had read events
1079  * @param writeset_out:  set of sockets that had write events
1080  * @param exceptset_out: set os sockets that had error events
1081  * @return number of sockets that had events (read/write/exception) (>= 0)
1082  */
1083 static int
1084 lwip_selscan(int maxfdp1, fd_set *readset_in, fd_set *writeset_in, fd_set *exceptset_in,
1085              fd_set *readset_out, fd_set *writeset_out, fd_set *exceptset_out)
1086 {
1087   int i, nready = 0;
1088   fd_set lreadset, lwriteset, lexceptset;
1089   struct lwip_sock *sock;
1090   SYS_ARCH_DECL_PROTECT(lev);
1091
1092   FD_ZERO(&lreadset);
1093   FD_ZERO(&lwriteset);
1094   FD_ZERO(&lexceptset);
1095
1096   /* Go through each socket in each list to count number of sockets which
1097      currently match */
1098   for(i = 0; i < maxfdp1; i++) {
1099     void* lastdata = NULL;
1100     s16_t rcvevent = 0;
1101     u16_t sendevent = 0;
1102     u16_t errevent = 0;
1103     /* First get the socket's status (protected)... */
1104     SYS_ARCH_PROTECT(lev);
1105     sock = tryget_socket(i);
1106     if (sock != NULL) {
1107       lastdata = sock->lastdata;
1108       rcvevent = sock->rcvevent;
1109       sendevent = sock->sendevent;
1110       errevent = sock->errevent;
1111     }
1112     SYS_ARCH_UNPROTECT(lev);
1113     /* ... then examine it: */
1114     /* See if netconn of this socket is ready for read */
1115     if (readset_in && FD_ISSET(i, readset_in) && ((lastdata != NULL) || (rcvevent > 0))) {
1116       FD_SET(i, &lreadset);
1117       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_selscan: fd=%d ready for reading\n", i));
1118       nready++;
1119     }
1120     /* See if netconn of this socket is ready for write */
1121     if (writeset_in && FD_ISSET(i, writeset_in) && (sendevent != 0)) {
1122       FD_SET(i, &lwriteset);
1123       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_selscan: fd=%d ready for writing\n", i));
1124       nready++;
1125     }
1126     /* See if netconn of this socket had an error */
1127     if (exceptset_in && FD_ISSET(i, exceptset_in) && (errevent != 0)) {
1128       FD_SET(i, &lexceptset);
1129       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_selscan: fd=%d ready for exception\n", i));
1130       nready++;
1131     }
1132   }
1133   /* copy local sets to the ones provided as arguments */
1134   *readset_out = lreadset;
1135   *writeset_out = lwriteset;
1136   *exceptset_out = lexceptset;
1137
1138   LWIP_ASSERT("nready >= 0", nready >= 0);
1139   return nready;
1140 }
1141
1142 /**
1143  * Processing exceptset is not yet implemented.
1144  */
1145 int
1146 lwip_select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset,
1147             struct timeval *timeout)
1148 {
1149   u32_t waitres = 0;
1150   int nready;
1151   fd_set lreadset, lwriteset, lexceptset;
1152   u32_t msectimeout;
1153   struct lwip_select_cb select_cb;
1154   err_t err;
1155   int i;
1156   SYS_ARCH_DECL_PROTECT(lev);
1157
1158   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select(%d, %p, %p, %p, tvsec=%"S32_F" tvusec=%"S32_F")\n",
1159                   maxfdp1, (void *)readset, (void *) writeset, (void *) exceptset,
1160                   timeout ? (s32_t)timeout->tv_sec : (s32_t)-1,
1161                   timeout ? (s32_t)timeout->tv_usec : (s32_t)-1));
1162
1163   /* Go through each socket in each list to count number of sockets which
1164      currently match */
1165   nready = lwip_selscan(maxfdp1, readset, writeset, exceptset, &lreadset, &lwriteset, &lexceptset);
1166
1167   /* If we don't have any current events, then suspend if we are supposed to */
1168   if (!nready) {
1169     if (timeout && timeout->tv_sec == 0 && timeout->tv_usec == 0) {
1170       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select: no timeout, returning 0\n"));
1171       /* This is OK as the local fdsets are empty and nready is zero,
1172          or we would have returned earlier. */
1173       goto return_copy_fdsets;
1174     }
1175
1176     /* None ready: add our semaphore to list:
1177        We don't actually need any dynamic memory. Our entry on the
1178        list is only valid while we are in this function, so it's ok
1179        to use local variables. */
1180
1181     select_cb.next = NULL;
1182     select_cb.prev = NULL;
1183     select_cb.readset = readset;
1184     select_cb.writeset = writeset;
1185     select_cb.exceptset = exceptset;
1186     select_cb.sem_signalled = 0;
1187     err = sys_sem_new(&select_cb.sem, 0);
1188     if (err != ERR_OK) {
1189       /* failed to create semaphore */
1190       set_errno(ENOMEM);
1191       return -1;
1192     }
1193
1194     /* Protect the select_cb_list */
1195     SYS_ARCH_PROTECT(lev);
1196
1197     /* Put this select_cb on top of list */
1198     select_cb.next = select_cb_list;
1199     if (select_cb_list != NULL) {
1200       select_cb_list->prev = &select_cb;
1201     }
1202     select_cb_list = &select_cb;
1203     /* Increasing this counter tells even_callback that the list has changed. */
1204     select_cb_ctr++;
1205
1206     /* Now we can safely unprotect */
1207     SYS_ARCH_UNPROTECT(lev);
1208
1209     /* Increase select_waiting for each socket we are interested in */
1210     for(i = 0; i < maxfdp1; i++) {
1211       if ((readset && FD_ISSET(i, readset)) ||
1212           (writeset && FD_ISSET(i, writeset)) ||
1213           (exceptset && FD_ISSET(i, exceptset))) {
1214         struct lwip_sock *sock = tryget_socket(i);
1215         LWIP_ASSERT("sock != NULL", sock != NULL);
1216         SYS_ARCH_PROTECT(lev);
1217         sock->select_waiting++;
1218         LWIP_ASSERT("sock->select_waiting > 0", sock->select_waiting > 0);
1219         SYS_ARCH_UNPROTECT(lev);
1220       }
1221     }
1222
1223     /* Call lwip_selscan again: there could have been events between
1224        the last scan (whithout us on the list) and putting us on the list! */
1225     nready = lwip_selscan(maxfdp1, readset, writeset, exceptset, &lreadset, &lwriteset, &lexceptset);
1226     if (!nready) {
1227       /* Still none ready, just wait to be woken */
1228       if (timeout == 0) {
1229         /* Wait forever */
1230         msectimeout = 0;
1231       } else {
1232         msectimeout =  ((timeout->tv_sec * 1000) + ((timeout->tv_usec + 500)/1000));
1233         if (msectimeout == 0) {
1234           /* Wait 1ms at least (0 means wait forever) */
1235           msectimeout = 1;
1236         }
1237       }
1238
1239       waitres = sys_arch_sem_wait(&select_cb.sem, msectimeout);
1240     }
1241     /* Increase select_waiting for each socket we are interested in */
1242     for(i = 0; i < maxfdp1; i++) {
1243       if ((readset && FD_ISSET(i, readset)) ||
1244           (writeset && FD_ISSET(i, writeset)) ||
1245           (exceptset && FD_ISSET(i, exceptset))) {
1246         struct lwip_sock *sock = tryget_socket(i);
1247         LWIP_ASSERT("sock != NULL", sock != NULL);
1248         SYS_ARCH_PROTECT(lev);
1249         sock->select_waiting--;
1250         LWIP_ASSERT("sock->select_waiting >= 0", sock->select_waiting >= 0);
1251         SYS_ARCH_UNPROTECT(lev);
1252       }
1253     }
1254     /* Take us off the list */
1255     SYS_ARCH_PROTECT(lev);
1256     if (select_cb.next != NULL) {
1257       select_cb.next->prev = select_cb.prev;
1258     }
1259     if (select_cb_list == &select_cb) {
1260       LWIP_ASSERT("select_cb.prev == NULL", select_cb.prev == NULL);
1261       select_cb_list = select_cb.next;
1262     } else {
1263       LWIP_ASSERT("select_cb.prev != NULL", select_cb.prev != NULL);
1264       select_cb.prev->next = select_cb.next;
1265     }
1266     /* Increasing this counter tells even_callback that the list has changed. */
1267     select_cb_ctr++;
1268     SYS_ARCH_UNPROTECT(lev);
1269
1270     sys_sem_free(&select_cb.sem);
1271     if (waitres == SYS_ARCH_TIMEOUT)  {
1272       /* Timeout */
1273       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select: timeout expired\n"));
1274       /* This is OK as the local fdsets are empty and nready is zero,
1275          or we would have returned earlier. */
1276       goto return_copy_fdsets;
1277     }
1278
1279     /* See what's set */
1280     nready = lwip_selscan(maxfdp1, readset, writeset, exceptset, &lreadset, &lwriteset, &lexceptset);
1281   }
1282
1283   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select: nready=%d\n", nready));
1284 return_copy_fdsets:
1285   set_errno(0);
1286   if (readset) {
1287     *readset = lreadset;
1288   }
1289   if (writeset) {
1290     *writeset = lwriteset;
1291   }
1292   if (exceptset) {
1293     *exceptset = lexceptset;
1294   }
1295   return nready;
1296 }
1297
1298 /**
1299  * Callback registered in the netconn layer for each socket-netconn.
1300  * Processes recvevent (data available) and wakes up tasks waiting for select.
1301  */
1302 static void
1303 event_callback(struct netconn *conn, enum netconn_evt evt, u16_t len)
1304 {
1305   int s;
1306   struct lwip_sock *sock;
1307   struct lwip_select_cb *scb;
1308   int last_select_cb_ctr;
1309   SYS_ARCH_DECL_PROTECT(lev);
1310
1311   LWIP_UNUSED_ARG(len);
1312
1313   /* Get socket */
1314   if (conn) {
1315     s = conn->socket;
1316     if (s < 0) {
1317       /* Data comes in right away after an accept, even though
1318        * the server task might not have created a new socket yet.
1319        * Just count down (or up) if that's the case and we
1320        * will use the data later. Note that only receive events
1321        * can happen before the new socket is set up. */
1322       SYS_ARCH_PROTECT(lev);
1323       if (conn->socket < 0) {
1324         if (evt == NETCONN_EVT_RCVPLUS) {
1325           conn->socket--;
1326         }
1327         SYS_ARCH_UNPROTECT(lev);
1328         return;
1329       }
1330       s = conn->socket;
1331       SYS_ARCH_UNPROTECT(lev);
1332     }
1333
1334     sock = get_socket(s);
1335     if (!sock) {
1336       return;
1337     }
1338   } else {
1339     return;
1340   }
1341
1342   SYS_ARCH_PROTECT(lev);
1343   /* Set event as required */
1344   switch (evt) {
1345     case NETCONN_EVT_RCVPLUS:
1346       sock->rcvevent++;
1347       break;
1348     case NETCONN_EVT_RCVMINUS:
1349       sock->rcvevent--;
1350       break;
1351     case NETCONN_EVT_SENDPLUS:
1352       sock->sendevent = 1;
1353       break;
1354     case NETCONN_EVT_SENDMINUS:
1355       sock->sendevent = 0;
1356       break;
1357     case NETCONN_EVT_ERROR:
1358       sock->errevent = 1;
1359       break;
1360     default:
1361       LWIP_ASSERT("unknown event", 0);
1362       break;
1363   }
1364
1365   if (sock->select_waiting == 0) {
1366     /* noone is waiting for this socket, no need to check select_cb_list */
1367     SYS_ARCH_UNPROTECT(lev);
1368     return;
1369   }
1370
1371   /* Now decide if anyone is waiting for this socket */
1372   /* NOTE: This code goes through the select_cb_list list multiple times
1373      ONLY IF a select was actually waiting. We go through the list the number
1374      of waiting select calls + 1. This list is expected to be small. */
1375
1376   /* At this point, SYS_ARCH is still protected! */
1377 again:
1378   for (scb = select_cb_list; scb != NULL; scb = scb->next) {
1379     if (scb->sem_signalled == 0) {
1380       /* semaphore not signalled yet */
1381       int do_signal = 0;
1382       /* Test this select call for our socket */
1383       if (sock->rcvevent > 0) {
1384         if (scb->readset && FD_ISSET(s, scb->readset)) {
1385           do_signal = 1;
1386         }
1387       }
1388       if (sock->sendevent != 0) {
1389         if (!do_signal && scb->writeset && FD_ISSET(s, scb->writeset)) {
1390           do_signal = 1;
1391         }
1392       }
1393       if (sock->errevent != 0) {
1394         if (!do_signal && scb->exceptset && FD_ISSET(s, scb->exceptset)) {
1395           do_signal = 1;
1396         }
1397       }
1398       if (do_signal) {
1399         scb->sem_signalled = 1;
1400         /* Don't call SYS_ARCH_UNPROTECT() before signaling the semaphore, as this might
1401            lead to the select thread taking itself off the list, invalidagin the semaphore. */
1402         sys_sem_signal(&scb->sem);
1403       }
1404     }
1405     /* unlock interrupts with each step */
1406     last_select_cb_ctr = select_cb_ctr;
1407     SYS_ARCH_UNPROTECT(lev);
1408     /* this makes sure interrupt protection time is short */
1409     SYS_ARCH_PROTECT(lev);
1410     if (last_select_cb_ctr != select_cb_ctr) {
1411       /* someone has changed select_cb_list, restart at the beginning */
1412       goto again;
1413     }
1414   }
1415   SYS_ARCH_UNPROTECT(lev);
1416 }
1417
1418 /**
1419  * Unimplemented: Close one end of a full-duplex connection.
1420  * Currently, the full connection is closed.
1421  */
1422 int
1423 lwip_shutdown(int s, int how)
1424 {
1425   struct lwip_sock *sock;
1426   err_t err;
1427   u8_t shut_rx = 0, shut_tx = 0;
1428
1429   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_shutdown(%d, how=%d)\n", s, how));
1430
1431   sock = get_socket(s);
1432   if (!sock) {
1433     return -1;
1434   }
1435
1436   if (sock->conn != NULL) {
1437     if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_TCP) {
1438       sock_set_errno(sock, EOPNOTSUPP);
1439       return EOPNOTSUPP;
1440     }
1441   } else {
1442     sock_set_errno(sock, ENOTCONN);
1443     return ENOTCONN;
1444   }
1445
1446   if (how == SHUT_RD) {
1447     shut_rx = 1;
1448   } else if (how == SHUT_WR) {
1449     shut_tx = 1;
1450   } else if(how == SHUT_RDWR) {
1451     shut_rx = 1;
1452     shut_tx = 1;
1453   } else {
1454     sock_set_errno(sock, EINVAL);
1455     return EINVAL;
1456   }
1457   err = netconn_shutdown(sock->conn, shut_rx, shut_tx);
1458
1459   sock_set_errno(sock, err_to_errno(err));
1460   return (err == ERR_OK ? 0 : -1);
1461 }
1462
1463 static int
1464 lwip_getaddrname(int s, struct sockaddr *name, socklen_t *namelen, u8_t local)
1465 {
1466   struct lwip_sock *sock;
1467   union sockaddr_aligned saddr;
1468   ipX_addr_t naddr;
1469   u16_t port;
1470
1471   sock = get_socket(s);
1472   if (!sock) {
1473     return -1;
1474   }
1475
1476   /* get the IP address and port */
1477   /* @todo: this does not work for IPv6, yet */
1478   netconn_getaddr(sock->conn, ipX_2_ip(&naddr), &port, local);
1479   IPXADDR_PORT_TO_SOCKADDR(NETCONNTYPE_ISIPV6(netconn_type(sock->conn)),
1480     &saddr, &naddr, port);
1481
1482   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getaddrname(%d, addr=", s));
1483   ipX_addr_debug_print(NETCONNTYPE_ISIPV6(netconn_type(sock->conn)),
1484     SOCKETS_DEBUG, &naddr);
1485   LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F")\n", port));
1486
1487   if (*namelen > saddr.sa.sa_len) {
1488     *namelen = saddr.sa.sa_len;
1489   }
1490   MEMCPY(name, &saddr, *namelen);
1491
1492   sock_set_errno(sock, 0);
1493   return 0;
1494 }
1495
1496 int
1497 lwip_getpeername(int s, struct sockaddr *name, socklen_t *namelen)
1498 {
1499   return lwip_getaddrname(s, name, namelen, 0);
1500 }
1501
1502 int
1503 lwip_getsockname(int s, struct sockaddr *name, socklen_t *namelen)
1504 {
1505   return lwip_getaddrname(s, name, namelen, 1);
1506 }
1507
1508 int
1509 lwip_getsockopt(int s, int level, int optname, void *optval, socklen_t *optlen)
1510 {
1511   err_t err = ERR_OK;
1512   struct lwip_sock *sock = get_socket(s);
1513   struct lwip_setgetsockopt_data data;
1514
1515   if (!sock) {
1516     return -1;
1517   }
1518
1519   if ((NULL == optval) || (NULL == optlen)) {
1520     sock_set_errno(sock, EFAULT);
1521     return -1;
1522   }
1523
1524   /* Do length and type checks for the various options first, to keep it readable. */
1525   switch (level) {
1526    
1527 /* Level: SOL_SOCKET */
1528   case SOL_SOCKET:
1529     switch (optname) {
1530        
1531     case SO_ACCEPTCONN:
1532     case SO_BROADCAST:
1533     /* UNIMPL case SO_DEBUG: */
1534     /* UNIMPL case SO_DONTROUTE: */
1535     case SO_ERROR:
1536     case SO_KEEPALIVE:
1537     /* UNIMPL case SO_CONTIMEO: */
1538     /* UNIMPL case SO_SNDTIMEO: */
1539 #if LWIP_SO_RCVTIMEO
1540     case SO_RCVTIMEO:
1541 #endif /* LWIP_SO_RCVTIMEO */
1542 #if LWIP_SO_RCVBUF
1543     case SO_RCVBUF:
1544 #endif /* LWIP_SO_RCVBUF */
1545     /* UNIMPL case SO_OOBINLINE: */
1546     /* UNIMPL case SO_SNDBUF: */
1547     /* UNIMPL case SO_RCVLOWAT: */
1548     /* UNIMPL case SO_SNDLOWAT: */
1549 #if SO_REUSE
1550     case SO_REUSEADDR:
1551     case SO_REUSEPORT:
1552 #endif /* SO_REUSE */
1553     case SO_TYPE:
1554     /* UNIMPL case SO_USELOOPBACK: */
1555       if (*optlen < sizeof(int)) {
1556         err = EINVAL;
1557       }
1558       break;
1559
1560     case SO_NO_CHECK:
1561       if (*optlen < sizeof(int)) {
1562         err = EINVAL;
1563       }
1564 #if LWIP_UDP
1565       if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_UDP ||
1566           ((udp_flags(sock->conn->pcb.udp) & UDP_FLAGS_UDPLITE) != 0)) {
1567         /* this flag is only available for UDP, not for UDP lite */
1568         err = EAFNOSUPPORT;
1569       }
1570 #endif /* LWIP_UDP */
1571       break;
1572
1573     default:
1574       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, UNIMPL: optname=0x%x, ..)\n",
1575                                   s, optname));
1576       err = ENOPROTOOPT;
1577     }  /* switch (optname) */
1578     break;
1579                      
1580 /* Level: IPPROTO_IP */
1581   case IPPROTO_IP:
1582     switch (optname) {
1583     /* UNIMPL case IP_HDRINCL: */
1584     /* UNIMPL case IP_RCVDSTADDR: */
1585     /* UNIMPL case IP_RCVIF: */
1586     case IP_TTL:
1587     case IP_TOS:
1588       if (*optlen < sizeof(int)) {
1589         err = EINVAL;
1590       }
1591       break;
1592 #if LWIP_IGMP
1593     case IP_MULTICAST_TTL:
1594       if (*optlen < sizeof(u8_t)) {
1595         err = EINVAL;
1596       }
1597       break;
1598     case IP_MULTICAST_IF:
1599       if (*optlen < sizeof(struct in_addr)) {
1600         err = EINVAL;
1601       }
1602       break;
1603     case IP_MULTICAST_LOOP:
1604       if (*optlen < sizeof(u8_t)) {
1605         err = EINVAL;
1606       }
1607       if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_UDP) {
1608         err = EAFNOSUPPORT;
1609       }
1610       break;
1611 #endif /* LWIP_IGMP */
1612
1613     default:
1614       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, UNIMPL: optname=0x%x, ..)\n",
1615                                   s, optname));
1616       err = ENOPROTOOPT;
1617     }  /* switch (optname) */
1618     break;
1619          
1620 #if LWIP_TCP
1621 /* Level: IPPROTO_TCP */
1622   case IPPROTO_TCP:
1623     if (*optlen < sizeof(int)) {
1624       err = EINVAL;
1625       break;
1626     }
1627     
1628     /* If this is no TCP socket, ignore any options. */
1629     if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_TCP)
1630       return 0;
1631
1632     switch (optname) {
1633     case TCP_NODELAY:
1634     case TCP_KEEPALIVE:
1635 #if LWIP_TCP_KEEPALIVE
1636     case TCP_KEEPIDLE:
1637     case TCP_KEEPINTVL:
1638     case TCP_KEEPCNT:
1639 #endif /* LWIP_TCP_KEEPALIVE */
1640       break;
1641        
1642     default:
1643       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_TCP, UNIMPL: optname=0x%x, ..)\n",
1644                                   s, optname));
1645       err = ENOPROTOOPT;
1646     }  /* switch (optname) */
1647     break;
1648 #endif /* LWIP_TCP */
1649 #if LWIP_UDP && LWIP_UDPLITE
1650 /* Level: IPPROTO_UDPLITE */
1651   case IPPROTO_UDPLITE:
1652     if (*optlen < sizeof(int)) {
1653       err = EINVAL;
1654       break;
1655     }
1656     
1657     /* If this is no UDP lite socket, ignore any options. */
1658     if (!NETCONNTYPE_ISUDPLITE(netconn_type(sock->conn))) {
1659       return 0;
1660     }
1661
1662     switch (optname) {
1663     case UDPLITE_SEND_CSCOV:
1664     case UDPLITE_RECV_CSCOV:
1665       break;
1666        
1667     default:
1668       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_UDPLITE, UNIMPL: optname=0x%x, ..)\n",
1669                                   s, optname));
1670       err = ENOPROTOOPT;
1671     }  /* switch (optname) */
1672     break;
1673 #endif /* LWIP_UDP && LWIP_UDPLITE*/
1674 /* UNDEFINED LEVEL */
1675   default:
1676       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, level=0x%x, UNIMPL: optname=0x%x, ..)\n",
1677                                   s, level, optname));
1678       err = ENOPROTOOPT;
1679   }  /* switch */
1680
1681    
1682   if (err != ERR_OK) {
1683     sock_set_errno(sock, err);
1684     return -1;
1685   }
1686
1687   /* Now do the actual option processing */
1688   data.sock = sock;
1689 #ifdef LWIP_DEBUG
1690   data.s = s;
1691 #endif /* LWIP_DEBUG */
1692   data.level = level;
1693   data.optname = optname;
1694   data.optval = optval;
1695   data.optlen = optlen;
1696   data.err = err;
1697   tcpip_callback(lwip_getsockopt_internal, &data);
1698   sys_arch_sem_wait(&sock->conn->op_completed, 0);
1699   /* maybe lwip_getsockopt_internal has changed err */
1700   err = data.err;
1701
1702   sock_set_errno(sock, err);
1703   return err ? -1 : 0;
1704 }
1705
1706 static void
1707 lwip_getsockopt_internal(void *arg)
1708 {
1709   struct lwip_sock *sock;
1710 #ifdef LWIP_DEBUG
1711   int s;
1712 #endif /* LWIP_DEBUG */
1713   int level, optname;
1714   void *optval;
1715   struct lwip_setgetsockopt_data *data;
1716
1717   LWIP_ASSERT("arg != NULL", arg != NULL);
1718
1719   data = (struct lwip_setgetsockopt_data*)arg;
1720   sock = data->sock;
1721 #ifdef LWIP_DEBUG
1722   s = data->s;
1723 #endif /* LWIP_DEBUG */
1724   level = data->level;
1725   optname = data->optname;
1726   optval = data->optval;
1727
1728   switch (level) {
1729
1730 /* Level: SOL_SOCKET */
1731   case SOL_SOCKET:
1732     switch (optname) {
1733
1734     /* The option flags */
1735     case SO_ACCEPTCONN:
1736     case SO_BROADCAST:
1737     /* UNIMPL case SO_DEBUG: */
1738     /* UNIMPL case SO_DONTROUTE: */
1739     case SO_KEEPALIVE:
1740     /* UNIMPL case SO_OOBINCLUDE: */
1741 #if SO_REUSE
1742     case SO_REUSEADDR:
1743     case SO_REUSEPORT:
1744 #endif /* SO_REUSE */
1745     /*case SO_USELOOPBACK: UNIMPL */
1746       *(int*)optval = sock->conn->pcb.ip->so_options & optname;
1747       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, optname=0x%x, ..) = %s\n",
1748                                   s, optname, (*(int*)optval?"on":"off")));
1749       break;
1750
1751     case SO_TYPE:
1752       switch (NETCONNTYPE_GROUP(netconn_type(sock->conn))) {
1753       case NETCONN_RAW:
1754         *(int*)optval = SOCK_RAW;
1755         break;
1756       case NETCONN_TCP:
1757         *(int*)optval = SOCK_STREAM;
1758         break;
1759       case NETCONN_UDP:
1760         *(int*)optval = SOCK_DGRAM;
1761         break;
1762       default: /* unrecognized socket type */
1763         *(int*)optval = netconn_type(sock->conn);
1764         LWIP_DEBUGF(SOCKETS_DEBUG,
1765                     ("lwip_getsockopt(%d, SOL_SOCKET, SO_TYPE): unrecognized socket type %d\n",
1766                     s, *(int *)optval));
1767       }  /* switch (netconn_type(sock->conn)) */
1768       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, SO_TYPE) = %d\n",
1769                   s, *(int *)optval));
1770       break;
1771
1772     case SO_ERROR:
1773       /* only overwrite ERR_OK or tempoary errors */
1774       if ((sock->err == 0) || (sock->err == EINPROGRESS)) {
1775         sock_set_errno(sock, err_to_errno(sock->conn->last_err));
1776       } 
1777       *(int *)optval = sock->err;
1778       sock->err = 0;
1779       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, SO_ERROR) = %d\n",
1780                   s, *(int *)optval));
1781       break;
1782
1783 #if LWIP_SO_RCVTIMEO
1784     case SO_RCVTIMEO:
1785       *(int *)optval = netconn_get_recvtimeout(sock->conn);
1786       break;
1787 #endif /* LWIP_SO_RCVTIMEO */
1788 #if LWIP_SO_RCVBUF
1789     case SO_RCVBUF:
1790       *(int *)optval = netconn_get_recvbufsize(sock->conn);
1791       break;
1792 #endif /* LWIP_SO_RCVBUF */
1793 #if LWIP_UDP
1794     case SO_NO_CHECK:
1795       *(int*)optval = (udp_flags(sock->conn->pcb.udp) & UDP_FLAGS_NOCHKSUM) ? 1 : 0;
1796       break;
1797 #endif /* LWIP_UDP*/
1798     default:
1799       LWIP_ASSERT("unhandled optname", 0);
1800       break;
1801     }  /* switch (optname) */
1802     break;
1803
1804 /* Level: IPPROTO_IP */
1805   case IPPROTO_IP:
1806     switch (optname) {
1807     case IP_TTL:
1808       *(int*)optval = sock->conn->pcb.ip->ttl;
1809       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_TTL) = %d\n",
1810                   s, *(int *)optval));
1811       break;
1812     case IP_TOS:
1813       *(int*)optval = sock->conn->pcb.ip->tos;
1814       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_TOS) = %d\n",
1815                   s, *(int *)optval));
1816       break;
1817 #if LWIP_IGMP
1818     case IP_MULTICAST_TTL:
1819       *(u8_t*)optval = sock->conn->pcb.ip->ttl;
1820       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_MULTICAST_TTL) = %d\n",
1821                   s, *(int *)optval));
1822       break;
1823     case IP_MULTICAST_IF:
1824       inet_addr_from_ipaddr((struct in_addr*)optval, &sock->conn->pcb.udp->multicast_ip);
1825       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_MULTICAST_IF) = 0x%"X32_F"\n",
1826                   s, *(u32_t *)optval));
1827       break;
1828     case IP_MULTICAST_LOOP:
1829       if ((sock->conn->pcb.udp->flags & UDP_FLAGS_MULTICAST_LOOP) != 0) {
1830         *(u8_t*)optval = 1;
1831       } else {
1832         *(u8_t*)optval = 0;
1833       }
1834       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_MULTICAST_LOOP) = %d\n",
1835                   s, *(int *)optval));
1836       break;
1837 #endif /* LWIP_IGMP */
1838     default:
1839       LWIP_ASSERT("unhandled optname", 0);
1840       break;
1841     }  /* switch (optname) */
1842     break;
1843
1844 #if LWIP_TCP
1845 /* Level: IPPROTO_TCP */
1846   case IPPROTO_TCP:
1847     switch (optname) {
1848     case TCP_NODELAY:
1849       *(int*)optval = tcp_nagle_disabled(sock->conn->pcb.tcp);
1850       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_TCP, TCP_NODELAY) = %s\n",
1851                   s, (*(int*)optval)?"on":"off") );
1852       break;
1853     case TCP_KEEPALIVE:
1854       *(int*)optval = (int)sock->conn->pcb.tcp->keep_idle;
1855       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, TCP_KEEPALIVE) = %d\n",
1856                   s, *(int *)optval));
1857       break;
1858
1859 #if LWIP_TCP_KEEPALIVE
1860     case TCP_KEEPIDLE:
1861       *(int*)optval = (int)(sock->conn->pcb.tcp->keep_idle/1000);
1862       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, TCP_KEEPIDLE) = %d\n",
1863                   s, *(int *)optval));
1864       break;
1865     case TCP_KEEPINTVL:
1866       *(int*)optval = (int)(sock->conn->pcb.tcp->keep_intvl/1000);
1867       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, TCP_KEEPINTVL) = %d\n",
1868                   s, *(int *)optval));
1869       break;
1870     case TCP_KEEPCNT:
1871       *(int*)optval = (int)sock->conn->pcb.tcp->keep_cnt;
1872       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, TCP_KEEPCNT) = %d\n",
1873                   s, *(int *)optval));
1874       break;
1875 #endif /* LWIP_TCP_KEEPALIVE */
1876     default:
1877       LWIP_ASSERT("unhandled optname", 0);
1878       break;
1879     }  /* switch (optname) */
1880     break;
1881 #endif /* LWIP_TCP */
1882 #if LWIP_UDP && LWIP_UDPLITE
1883   /* Level: IPPROTO_UDPLITE */
1884   case IPPROTO_UDPLITE:
1885     switch (optname) {
1886     case UDPLITE_SEND_CSCOV:
1887       *(int*)optval = sock->conn->pcb.udp->chksum_len_tx;
1888       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_UDPLITE, UDPLITE_SEND_CSCOV) = %d\n",
1889                   s, (*(int*)optval)) );
1890       break;
1891     case UDPLITE_RECV_CSCOV:
1892       *(int*)optval = sock->conn->pcb.udp->chksum_len_rx;
1893       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_UDPLITE, UDPLITE_RECV_CSCOV) = %d\n",
1894                   s, (*(int*)optval)) );
1895       break;
1896     default:
1897       LWIP_ASSERT("unhandled optname", 0);
1898       break;
1899     }  /* switch (optname) */
1900     break;
1901 #endif /* LWIP_UDP */
1902   default:
1903     LWIP_ASSERT("unhandled level", 0);
1904     break;
1905   } /* switch (level) */
1906   sys_sem_signal(&sock->conn->op_completed);
1907 }
1908
1909 int
1910 lwip_setsockopt(int s, int level, int optname, const void *optval, socklen_t optlen)
1911 {
1912   struct lwip_sock *sock = get_socket(s);
1913   err_t err = ERR_OK;
1914   struct lwip_setgetsockopt_data data;
1915
1916   if (!sock) {
1917     return -1;
1918   }
1919
1920   if (NULL == optval) {
1921     sock_set_errno(sock, EFAULT);
1922     return -1;
1923   }
1924
1925   /* Do length and type checks for the various options first, to keep it readable. */
1926   switch (level) {
1927
1928 /* Level: SOL_SOCKET */
1929   case SOL_SOCKET:
1930     switch (optname) {
1931
1932     case SO_BROADCAST:
1933     /* UNIMPL case SO_DEBUG: */
1934     /* UNIMPL case SO_DONTROUTE: */
1935     case SO_KEEPALIVE:
1936     /* UNIMPL case case SO_CONTIMEO: */
1937     /* UNIMPL case case SO_SNDTIMEO: */
1938 #if LWIP_SO_RCVTIMEO
1939     case SO_RCVTIMEO:
1940 #endif /* LWIP_SO_RCVTIMEO */
1941 #if LWIP_SO_RCVBUF
1942     case SO_RCVBUF:
1943 #endif /* LWIP_SO_RCVBUF */
1944     /* UNIMPL case SO_OOBINLINE: */
1945     /* UNIMPL case SO_SNDBUF: */
1946     /* UNIMPL case SO_RCVLOWAT: */
1947     /* UNIMPL case SO_SNDLOWAT: */
1948 #if SO_REUSE
1949     case SO_REUSEADDR:
1950     case SO_REUSEPORT:
1951 #endif /* SO_REUSE */
1952     /* UNIMPL case SO_USELOOPBACK: */
1953       if (optlen < sizeof(int)) {
1954         err = EINVAL;
1955       }
1956       break;
1957     case SO_NO_CHECK:
1958       if (optlen < sizeof(int)) {
1959         err = EINVAL;
1960       }
1961 #if LWIP_UDP
1962       if ((NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_UDP) ||
1963           ((udp_flags(sock->conn->pcb.udp) & UDP_FLAGS_UDPLITE) != 0)) {
1964         /* this flag is only available for UDP, not for UDP lite */
1965         err = EAFNOSUPPORT;
1966       }
1967 #endif /* LWIP_UDP */
1968       break;
1969     default:
1970       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, SOL_SOCKET, UNIMPL: optname=0x%x, ..)\n",
1971                   s, optname));
1972       err = ENOPROTOOPT;
1973     }  /* switch (optname) */
1974     break;
1975
1976 /* Level: IPPROTO_IP */
1977   case IPPROTO_IP:
1978     switch (optname) {
1979     /* UNIMPL case IP_HDRINCL: */
1980     /* UNIMPL case IP_RCVDSTADDR: */
1981     /* UNIMPL case IP_RCVIF: */
1982     case IP_TTL:
1983     case IP_TOS:
1984       if (optlen < sizeof(int)) {
1985         err = EINVAL;
1986       }
1987       break;
1988 #if LWIP_IGMP
1989     case IP_MULTICAST_TTL:
1990       if (optlen < sizeof(u8_t)) {
1991         err = EINVAL;
1992       }
1993       if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_UDP) {
1994         err = EAFNOSUPPORT;
1995       }
1996       break;
1997     case IP_MULTICAST_IF:
1998       if (optlen < sizeof(struct in_addr)) {
1999         err = EINVAL;
2000       }
2001       if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_UDP) {
2002         err = EAFNOSUPPORT;
2003       }
2004       break;
2005     case IP_MULTICAST_LOOP:
2006       if (optlen < sizeof(u8_t)) {
2007         err = EINVAL;
2008       }
2009       if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_UDP) {
2010         err = EAFNOSUPPORT;
2011       }
2012       break;
2013     case IP_ADD_MEMBERSHIP:
2014     case IP_DROP_MEMBERSHIP:
2015       if (optlen < sizeof(struct ip_mreq)) {
2016         err = EINVAL;
2017       }
2018       if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_UDP) {
2019         err = EAFNOSUPPORT;
2020       }
2021       break;
2022 #endif /* LWIP_IGMP */
2023       default:
2024         LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IP, UNIMPL: optname=0x%x, ..)\n",
2025                     s, optname));
2026         err = ENOPROTOOPT;
2027     }  /* switch (optname) */
2028     break;
2029
2030 #if LWIP_TCP
2031 /* Level: IPPROTO_TCP */
2032   case IPPROTO_TCP:
2033     if (optlen < sizeof(int)) {
2034       err = EINVAL;
2035       break;
2036     }
2037
2038     /* If this is no TCP socket, ignore any options. */
2039     if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_TCP)
2040       return 0;
2041
2042     switch (optname) {
2043     case TCP_NODELAY:
2044     case TCP_KEEPALIVE:
2045 #if LWIP_TCP_KEEPALIVE
2046     case TCP_KEEPIDLE:
2047     case TCP_KEEPINTVL:
2048     case TCP_KEEPCNT:
2049 #endif /* LWIP_TCP_KEEPALIVE */
2050       break;
2051
2052     default:
2053       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, UNIMPL: optname=0x%x, ..)\n",
2054                   s, optname));
2055       err = ENOPROTOOPT;
2056     }  /* switch (optname) */
2057     break;
2058 #endif /* LWIP_TCP */
2059 #if LWIP_UDP && LWIP_UDPLITE
2060 /* Level: IPPROTO_UDPLITE */
2061   case IPPROTO_UDPLITE:
2062     if (optlen < sizeof(int)) {
2063       err = EINVAL;
2064       break;
2065     }
2066
2067     /* If this is no UDP lite socket, ignore any options. */
2068     if (!NETCONNTYPE_ISUDPLITE(netconn_type(sock->conn)))
2069       return 0;
2070
2071     switch (optname) {
2072     case UDPLITE_SEND_CSCOV:
2073     case UDPLITE_RECV_CSCOV:
2074       break;
2075
2076     default:
2077       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_UDPLITE, UNIMPL: optname=0x%x, ..)\n",
2078                   s, optname));
2079       err = ENOPROTOOPT;
2080     }  /* switch (optname) */
2081     break;
2082 #endif /* LWIP_UDP && LWIP_UDPLITE */
2083 /* UNDEFINED LEVEL */
2084   default:
2085     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, level=0x%x, UNIMPL: optname=0x%x, ..)\n",
2086                 s, level, optname));
2087     err = ENOPROTOOPT;
2088   }  /* switch (level) */
2089
2090
2091   if (err != ERR_OK) {
2092     sock_set_errno(sock, err);
2093     return -1;
2094   }
2095
2096
2097   /* Now do the actual option processing */
2098   data.sock = sock;
2099 #ifdef LWIP_DEBUG
2100   data.s = s;
2101 #endif /* LWIP_DEBUG */
2102   data.level = level;
2103   data.optname = optname;
2104   data.optval = (void*)optval;
2105   data.optlen = &optlen;
2106   data.err = err;
2107   tcpip_callback(lwip_setsockopt_internal, &data);
2108   sys_arch_sem_wait(&sock->conn->op_completed, 0);
2109   /* maybe lwip_setsockopt_internal has changed err */
2110   err = data.err;
2111
2112   sock_set_errno(sock, err);
2113   return err ? -1 : 0;
2114 }
2115
2116 static void
2117 lwip_setsockopt_internal(void *arg)
2118 {
2119   struct lwip_sock *sock;
2120 #ifdef LWIP_DEBUG
2121   int s;
2122 #endif /* LWIP_DEBUG */
2123   int level, optname;
2124   const void *optval;
2125   struct lwip_setgetsockopt_data *data;
2126
2127   LWIP_ASSERT("arg != NULL", arg != NULL);
2128
2129   data = (struct lwip_setgetsockopt_data*)arg;
2130   sock = data->sock;
2131 #ifdef LWIP_DEBUG
2132   s = data->s;
2133 #endif /* LWIP_DEBUG */
2134   level = data->level;
2135   optname = data->optname;
2136   optval = data->optval;
2137
2138   switch (level) {
2139
2140 /* Level: SOL_SOCKET */
2141   case SOL_SOCKET:
2142     switch (optname) {
2143
2144     /* The option flags */
2145     case SO_BROADCAST:
2146     /* UNIMPL case SO_DEBUG: */
2147     /* UNIMPL case SO_DONTROUTE: */
2148     case SO_KEEPALIVE:
2149     /* UNIMPL case SO_OOBINCLUDE: */
2150 #if SO_REUSE
2151     case SO_REUSEADDR:
2152     case SO_REUSEPORT:
2153 #endif /* SO_REUSE */
2154     /* UNIMPL case SO_USELOOPBACK: */
2155       if (*(int*)optval) {
2156         sock->conn->pcb.ip->so_options |= optname;
2157       } else {
2158         sock->conn->pcb.ip->so_options &= ~optname;
2159       }
2160       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, SOL_SOCKET, optname=0x%x, ..) -> %s\n",
2161                   s, optname, (*(int*)optval?"on":"off")));
2162       break;
2163 #if LWIP_SO_RCVTIMEO
2164     case SO_RCVTIMEO:
2165       netconn_set_recvtimeout(sock->conn, *(int*)optval);
2166       break;
2167 #endif /* LWIP_SO_RCVTIMEO */
2168 #if LWIP_SO_RCVBUF
2169     case SO_RCVBUF:
2170       netconn_set_recvbufsize(sock->conn, *(int*)optval);
2171       break;
2172 #endif /* LWIP_SO_RCVBUF */
2173 #if LWIP_UDP
2174     case SO_NO_CHECK:
2175       if (*(int*)optval) {
2176         udp_setflags(sock->conn->pcb.udp, udp_flags(sock->conn->pcb.udp) | UDP_FLAGS_NOCHKSUM);
2177       } else {
2178         udp_setflags(sock->conn->pcb.udp, udp_flags(sock->conn->pcb.udp) & ~UDP_FLAGS_NOCHKSUM);
2179       }
2180       break;
2181 #endif /* LWIP_UDP */
2182     default:
2183       LWIP_ASSERT("unhandled optname", 0);
2184       break;
2185     }  /* switch (optname) */
2186     break;
2187
2188 /* Level: IPPROTO_IP */
2189   case IPPROTO_IP:
2190     switch (optname) {
2191     case IP_TTL:
2192       sock->conn->pcb.ip->ttl = (u8_t)(*(int*)optval);
2193       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IP, IP_TTL, ..) -> %d\n",
2194                   s, sock->conn->pcb.ip->ttl));
2195       break;
2196     case IP_TOS:
2197       sock->conn->pcb.ip->tos = (u8_t)(*(int*)optval);
2198       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IP, IP_TOS, ..)-> %d\n",
2199                   s, sock->conn->pcb.ip->tos));
2200       break;
2201 #if LWIP_IGMP
2202     case IP_MULTICAST_TTL:
2203       sock->conn->pcb.udp->ttl = (u8_t)(*(u8_t*)optval);
2204       break;
2205     case IP_MULTICAST_IF:
2206       inet_addr_to_ipaddr(&sock->conn->pcb.udp->multicast_ip, (struct in_addr*)optval);
2207       break;
2208     case IP_MULTICAST_LOOP:
2209       if (*(u8_t*)optval) {
2210         udp_setflags(sock->conn->pcb.udp, udp_flags(sock->conn->pcb.udp) | UDP_FLAGS_MULTICAST_LOOP);
2211       } else {
2212         udp_setflags(sock->conn->pcb.udp, udp_flags(sock->conn->pcb.udp) & ~UDP_FLAGS_MULTICAST_LOOP);
2213       }
2214       break;
2215     case IP_ADD_MEMBERSHIP:
2216     case IP_DROP_MEMBERSHIP:
2217       {
2218         /* If this is a TCP or a RAW socket, ignore these options. */
2219         struct ip_mreq *imr = (struct ip_mreq *)optval;
2220         ip_addr_t if_addr;
2221         ip_addr_t multi_addr;
2222         inet_addr_to_ipaddr(&if_addr, &imr->imr_interface);
2223         inet_addr_to_ipaddr(&multi_addr, &imr->imr_multiaddr);
2224         if(optname == IP_ADD_MEMBERSHIP){
2225           data->err = igmp_joingroup(&if_addr, &multi_addr);
2226         } else {
2227           data->err = igmp_leavegroup(&if_addr, &multi_addr);
2228         }
2229         if(data->err != ERR_OK) {
2230           data->err = EADDRNOTAVAIL;
2231         }
2232       }
2233       break;
2234 #endif /* LWIP_IGMP */
2235     default:
2236       LWIP_ASSERT("unhandled optname", 0);
2237       break;
2238     }  /* switch (optname) */
2239     break;
2240
2241 #if LWIP_TCP
2242 /* Level: IPPROTO_TCP */
2243   case IPPROTO_TCP:
2244     switch (optname) {
2245     case TCP_NODELAY:
2246       if (*(int*)optval) {
2247         tcp_nagle_disable(sock->conn->pcb.tcp);
2248       } else {
2249         tcp_nagle_enable(sock->conn->pcb.tcp);
2250       }
2251       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_NODELAY) -> %s\n",
2252                   s, (*(int *)optval)?"on":"off") );
2253       break;
2254     case TCP_KEEPALIVE:
2255       sock->conn->pcb.tcp->keep_idle = (u32_t)(*(int*)optval);
2256       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPALIVE) -> %"U32_F"\n",
2257                   s, sock->conn->pcb.tcp->keep_idle));
2258       break;
2259
2260 #if LWIP_TCP_KEEPALIVE
2261     case TCP_KEEPIDLE:
2262       sock->conn->pcb.tcp->keep_idle = 1000*(u32_t)(*(int*)optval);
2263       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPIDLE) -> %"U32_F"\n",
2264                   s, sock->conn->pcb.tcp->keep_idle));
2265       break;
2266     case TCP_KEEPINTVL:
2267       sock->conn->pcb.tcp->keep_intvl = 1000*(u32_t)(*(int*)optval);
2268       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPINTVL) -> %"U32_F"\n",
2269                   s, sock->conn->pcb.tcp->keep_intvl));
2270       break;
2271     case TCP_KEEPCNT:
2272       sock->conn->pcb.tcp->keep_cnt = (u32_t)(*(int*)optval);
2273       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPCNT) -> %"U32_F"\n",
2274                   s, sock->conn->pcb.tcp->keep_cnt));
2275       break;
2276 #endif /* LWIP_TCP_KEEPALIVE */
2277     default:
2278       LWIP_ASSERT("unhandled optname", 0);
2279       break;
2280     }  /* switch (optname) */
2281     break;
2282 #endif /* LWIP_TCP*/
2283 #if LWIP_UDP && LWIP_UDPLITE
2284   /* Level: IPPROTO_UDPLITE */
2285   case IPPROTO_UDPLITE:
2286     switch (optname) {
2287     case UDPLITE_SEND_CSCOV:
2288       if ((*(int*)optval != 0) && ((*(int*)optval < 8)) || (*(int*)optval > 0xffff)) {
2289         /* don't allow illegal values! */
2290         sock->conn->pcb.udp->chksum_len_tx = 8;
2291       } else {
2292         sock->conn->pcb.udp->chksum_len_tx = (u16_t)*(int*)optval;
2293       }
2294       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_UDPLITE, UDPLITE_SEND_CSCOV) -> %d\n",
2295                   s, (*(int*)optval)) );
2296       break;
2297     case UDPLITE_RECV_CSCOV:
2298       if ((*(int*)optval != 0) && ((*(int*)optval < 8)) || (*(int*)optval > 0xffff)) {
2299         /* don't allow illegal values! */
2300         sock->conn->pcb.udp->chksum_len_rx = 8;
2301       } else {
2302         sock->conn->pcb.udp->chksum_len_rx = (u16_t)*(int*)optval;
2303       }
2304       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_UDPLITE, UDPLITE_RECV_CSCOV) -> %d\n",
2305                   s, (*(int*)optval)) );
2306       break;
2307     default:
2308       LWIP_ASSERT("unhandled optname", 0);
2309       break;
2310     }  /* switch (optname) */
2311     break;
2312 #endif /* LWIP_UDP */
2313   default:
2314     LWIP_ASSERT("unhandled level", 0);
2315     break;
2316   }  /* switch (level) */
2317   sys_sem_signal(&sock->conn->op_completed);
2318 }
2319
2320 int
2321 lwip_ioctl(int s, long cmd, void *argp)
2322 {
2323   struct lwip_sock *sock = get_socket(s);
2324   u8_t val;
2325 #if LWIP_SO_RCVBUF
2326   u16_t buflen = 0;
2327   s16_t recv_avail;
2328 #endif /* LWIP_SO_RCVBUF */
2329
2330   if (!sock) {
2331     return -1;
2332   }
2333
2334   switch (cmd) {
2335 #if LWIP_SO_RCVBUF || LWIP_FIONREAD_LINUXMODE
2336   case FIONREAD:
2337     if (!argp) {
2338       sock_set_errno(sock, EINVAL);
2339       return -1;
2340     }
2341 #if LWIP_FIONREAD_LINUXMODE
2342     if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_TCP) {
2343       struct pbuf *p;
2344       if (sock->lastdata) {
2345         p = ((struct netbuf *)sock->lastdata)->p;
2346       } else {
2347         struct netbuf *rxbuf;
2348         err_t err;
2349         if (sock->rcvevent <= 0) {
2350           *((u16_t*)argp) = 0;
2351         } else {
2352           err = netconn_recv(sock->conn, &rxbuf);
2353           if (err != ERR_OK) {
2354             *((u16_t*)argp) = 0;
2355           } else {
2356             sock->lastdata = rxbuf;
2357             *((u16_t*)argp) = rxbuf->p->tot_len;
2358           }
2359         }
2360       }
2361       return 0;
2362     }
2363 #endif /* LWIP_FIONREAD_LINUXMODE */
2364
2365 #if LWIP_SO_RCVBUF
2366     /* we come here if either LWIP_FIONREAD_LINUXMODE==0 or this is a TCP socket */
2367     SYS_ARCH_GET(sock->conn->recv_avail, recv_avail);
2368     if (recv_avail < 0) {
2369       recv_avail = 0;
2370     }
2371     *((u16_t*)argp) = (u16_t)recv_avail;
2372
2373     /* Check if there is data left from the last recv operation. /maq 041215 */
2374     if (sock->lastdata) {
2375       struct pbuf *p = (struct pbuf *)sock->lastdata;
2376       if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_TCP) {
2377         p = ((struct netbuf *)p)->p;
2378       }
2379       buflen = p->tot_len;
2380       buflen -= sock->lastoffset;
2381
2382       *((u16_t*)argp) += buflen;
2383     }
2384
2385     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(%d, FIONREAD, %p) = %"U16_F"\n", s, argp, *((u16_t*)argp)));
2386     sock_set_errno(sock, 0);
2387     return 0;
2388 #else /* LWIP_SO_RCVBUF */
2389     break;
2390 #endif /* LWIP_SO_RCVBUF */
2391 #endif /* LWIP_SO_RCVBUF || LWIP_FIONREAD_LINUXMODE */
2392
2393   case FIONBIO:
2394     val = 0;
2395     if (argp && *(u32_t*)argp) {
2396       val = 1;
2397     }
2398     netconn_set_nonblocking(sock->conn, val);
2399     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(%d, FIONBIO, %d)\n", s, val));
2400     sock_set_errno(sock, 0);
2401     return 0;
2402
2403   default:
2404     break;
2405   } /* switch (cmd) */
2406   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(%d, UNIMPL: 0x%lx, %p)\n", s, cmd, argp));
2407   sock_set_errno(sock, ENOSYS); /* not yet implemented */
2408   return -1;
2409 }
2410
2411 /** A minimal implementation of fcntl.
2412  * Currently only the commands F_GETFL and F_SETFL are implemented.
2413  * Only the flag O_NONBLOCK is implemented.
2414  */
2415 int
2416 lwip_fcntl(int s, int cmd, int val)
2417 {
2418   struct lwip_sock *sock = get_socket(s);
2419   int ret = -1;
2420
2421   if (!sock || !sock->conn) {
2422     return -1;
2423   }
2424
2425   switch (cmd) {
2426   case F_GETFL:
2427     ret = netconn_is_nonblocking(sock->conn) ? O_NONBLOCK : 0;
2428     break;
2429   case F_SETFL:
2430     if ((val & ~O_NONBLOCK) == 0) {
2431       /* only O_NONBLOCK, all other bits are zero */
2432       netconn_set_nonblocking(sock->conn, val & O_NONBLOCK);
2433       ret = 0;
2434     }
2435     break;
2436   default:
2437     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_fcntl(%d, UNIMPL: %d, %d)\n", s, cmd, val));
2438     break;
2439   }
2440   return ret;
2441 }
2442
2443 #endif /* LWIP_SOCKET */