]> rtime.felk.cvut.cz Git - pes-rpp/rpp-lwip.git/blob - src/api/sockets.c
32c3752b7ee96009b42e4ce476e6e40211586568
[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
55 #include <string.h>
56
57 #define NUM_SOCKETS MEMP_NUM_NETCONN
58
59 /** Contains all internal pointers and states used for a socket */
60 struct lwip_socket {
61   /** sockets currently are built on netconns, each socket has one netconn */
62   struct netconn *conn;
63   /** data that was left from the previous read */
64   struct netbuf *lastdata;
65   /** offset in the data that was left from the previous read */
66   u16_t lastoffset;
67   /** number of times data was received, set by event_callback(),
68       tested by the receive and select functions */
69   s16_t rcvevent;
70   /** number of times data was received, set by event_callback(),
71       tested by select */
72   u16_t sendevent;
73   /** socket flags (currently, only used for O_NONBLOCK) */
74   u16_t flags;
75   /** last error that occurred on this socket */
76   int err;
77 };
78
79 /** Description for a task waiting in select */
80 struct lwip_select_cb {
81   /** Pointer to the next waiting task */
82   struct lwip_select_cb *next;
83   /** readset passed to select */
84   fd_set *readset;
85   /** writeset passed to select */
86   fd_set *writeset;
87   /** unimplemented: exceptset passed to select */
88   fd_set *exceptset;
89   /** don't signal the same semaphore twice: set to 1 when signalled */
90   int sem_signalled;
91   /** semaphore to wake up a task waiting for select */
92   sys_sem_t sem;
93 };
94
95 /** This struct is used to pass data to the set/getsockopt_internal
96  * functions running in tcpip_thread context (only a void* is allowed) */
97 struct lwip_setgetsockopt_data {
98   /** socket struct for which to change options */
99   struct lwip_socket *sock;
100   /** socket index for which to change options */
101   int s;
102   /** level of the option to process */
103   int level;
104   /** name of the option to process */
105   int optname;
106   /** set: value to set the option to
107     * get: value of the option is stored here */
108   void *optval;
109   /** size of *optval */
110   socklen_t *optlen;
111   /** if an error occures, it is temporarily stored here */
112   err_t err;
113 };
114
115 /** The global array of available sockets */
116 static struct lwip_socket sockets[NUM_SOCKETS];
117 /** The global list of tasks waiting for select */
118 static struct lwip_select_cb *select_cb_list;
119
120 /** Semaphore protecting the sockets array */
121 static sys_sem_t socksem;
122 /** Semaphore protecting select_cb_list */
123 static sys_sem_t selectsem;
124
125 /** Table to quickly map an lwIP error (err_t) to a socket error
126   * by using -err as an index */
127 static const int err_to_errno_table[] = {
128   0,             /* ERR_OK          0      No error, everything OK. */
129   ENOMEM,        /* ERR_MEM        -1      Out of memory error.     */
130   ENOBUFS,       /* ERR_BUF        -2      Buffer error.            */
131   ETIMEDOUT,     /* ERR_TIMEOUT    -3      Timeout                  */
132   EHOSTUNREACH,  /* ERR_RTE        -4      Routing problem.         */
133   ECONNABORTED,  /* ERR_ABRT       -5      Connection aborted.      */
134   ECONNRESET,    /* ERR_RST        -6      Connection reset.        */
135   ESHUTDOWN,     /* ERR_CLSD       -7      Connection closed.       */
136   ENOTCONN,      /* ERR_CONN       -8      Not connected.           */
137   EINVAL,        /* ERR_VAL        -9      Illegal value.           */
138   EIO,           /* ERR_ARG        -10     Illegal argument.        */
139   EADDRINUSE,    /* ERR_USE        -11     Address in use.          */
140   -1,            /* ERR_IF         -12     Low-level netif error    */
141   -1,            /* ERR_ISCONN     -13     Already connected.       */
142   EINPROGRESS    /* ERR_INPROGRESS -14     Operation in progress    */
143 };
144
145 #define ERR_TO_ERRNO_TABLE_SIZE \
146   (sizeof(err_to_errno_table)/sizeof(err_to_errno_table[0]))
147
148 #define err_to_errno(err) \
149   ((unsigned)(-(err)) < ERR_TO_ERRNO_TABLE_SIZE ? \
150     err_to_errno_table[-(err)] : EIO)
151
152 #ifdef ERRNO
153 #ifndef set_errno
154 #define set_errno(err) errno = (err)
155 #endif
156 #else
157 #define set_errno(err)
158 #endif
159
160 #define sock_set_errno(sk, e) do { \
161   sk->err = (e); \
162   set_errno(sk->err); \
163 } while (0)
164
165 /* Forward delcaration of some functions */
166 static void event_callback(struct netconn *conn, enum netconn_evt evt, u16_t len);
167 static void lwip_getsockopt_internal(void *arg);
168 static void lwip_setsockopt_internal(void *arg);
169
170 /**
171  * Initialize this module. This function has to be called before any other
172  * functions in this module!
173  */
174 void
175 lwip_socket_init(void)
176 {
177   socksem   = sys_sem_new(1);
178   selectsem = sys_sem_new(1);
179 }
180
181 /**
182  * Map a externally used socket index to the internal socket representation.
183  *
184  * @param s externally used socket index
185  * @return struct lwip_socket for the socket or NULL if not found
186  */
187 static struct lwip_socket *
188 get_socket(int s)
189 {
190   struct lwip_socket *sock;
191
192   if ((s < 0) || (s >= NUM_SOCKETS)) {
193     LWIP_DEBUGF(SOCKETS_DEBUG, ("get_socket(%d): invalid\n", s));
194     set_errno(EBADF);
195     return NULL;
196   }
197
198   sock = &sockets[s];
199
200   if (!sock->conn) {
201     LWIP_DEBUGF(SOCKETS_DEBUG, ("get_socket(%d): not active\n", s));
202     set_errno(EBADF);
203     return NULL;
204   }
205
206   return sock;
207 }
208
209 /**
210  * Allocate a new socket for a given netconn.
211  *
212  * @param newconn the netconn for which to allocate a socket
213  * @return the index of the new socket; -1 on error
214  */
215 static int
216 alloc_socket(struct netconn *newconn)
217 {
218   int i;
219
220   /* Protect socket array */
221   sys_sem_wait(socksem);
222
223   /* allocate a new socket identifier */
224   for (i = 0; i < NUM_SOCKETS; ++i) {
225     if (!sockets[i].conn) {
226       sockets[i].conn       = newconn;
227       sockets[i].lastdata   = NULL;
228       sockets[i].lastoffset = 0;
229       sockets[i].rcvevent   = 0;
230       sockets[i].sendevent  = 1; /* TCP send buf is empty */
231       sockets[i].flags      = 0;
232       sockets[i].err        = 0;
233       sys_sem_signal(socksem);
234       return i;
235     }
236   }
237   sys_sem_signal(socksem);
238   return -1;
239 }
240
241 /* Below this, the well-known socket functions are implemented.
242  * Use google.com or opengroup.org to get a good description :-)
243  *
244  * Exceptions are documented!
245  */
246
247 int
248 lwip_accept(int s, struct sockaddr *addr, socklen_t *addrlen)
249 {
250   struct lwip_socket *sock, *nsock;
251   struct netconn *newconn;
252   struct ip_addr naddr;
253   u16_t port;
254   int newsock;
255   struct sockaddr_in sin;
256   err_t err;
257
258   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d)...\n", s));
259   sock = get_socket(s);
260   if (!sock)
261     return -1;
262
263   if ((sock->flags & O_NONBLOCK) && (sock->rcvevent <= 0)) {
264     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d): returning EWOULDBLOCK\n", s));
265     sock_set_errno(sock, EWOULDBLOCK);
266     return -1;
267   }
268
269   /* wait for a new connection */
270   err = netconn_accept(sock->conn, &newconn);
271   if (err != ERR_OK) {
272     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d): netconn_acept failed, err=%d\n", s, err));
273     sock_set_errno(sock, err_to_errno(err));
274     return -1;
275   }
276   LWIP_ASSERT("newconn != NULL", newconn != NULL);
277
278   /* get the IP address and port of the remote host */
279   err = netconn_peer(newconn, &naddr, &port);
280   if (err != ERR_OK) {
281     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d): netconn_peer failed, err=%d\n", s, err));
282     netconn_delete(newconn);
283     sock_set_errno(sock, err_to_errno(err));
284     return -1;
285   }
286
287   /* Note that POSIX only requires us to check addr is non-NULL. addrlen must
288    * not be NULL if addr is valid.
289    */
290   if (NULL != addr) {
291     LWIP_ASSERT("addr valid but addrlen NULL", addrlen != NULL);
292     memset(&sin, 0, sizeof(sin));
293     sin.sin_len = sizeof(sin);
294     sin.sin_family = AF_INET;
295     sin.sin_port = htons(port);
296     sin.sin_addr.s_addr = naddr.addr;
297
298     if (*addrlen > sizeof(sin))
299       *addrlen = sizeof(sin);
300
301     MEMCPY(addr, &sin, *addrlen);
302   }
303
304   newsock = alloc_socket(newconn);
305   if (newsock == -1) {
306     netconn_delete(newconn);
307     sock_set_errno(sock, ENFILE);
308     return -1;
309   }
310   LWIP_ASSERT("invalid socket index", (newsock >= 0) && (newsock < NUM_SOCKETS));
311   newconn->callback = event_callback;
312   nsock = &sockets[newsock];
313   LWIP_ASSERT("invalid socket pointer", nsock != NULL);
314
315   sys_sem_wait(socksem);
316   /* See event_callback: If data comes in right away after an accept, even
317    * though the server task might not have created a new socket yet.
318    * In that case, newconn->socket is counted down (newconn->socket--),
319    * so nsock->rcvevent is >= 1 here!
320    */
321   nsock->rcvevent += -1 - newconn->socket;
322   newconn->socket = newsock;
323   sys_sem_signal(socksem);
324
325   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d) returning new sock=%d addr=", s, newsock));
326   ip_addr_debug_print(SOCKETS_DEBUG, &naddr);
327   LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F"\n", port));
328
329   sock_set_errno(sock, 0);
330   return newsock;
331 }
332
333 int
334 lwip_bind(int s, const struct sockaddr *name, socklen_t namelen)
335 {
336   struct lwip_socket *sock;
337   struct ip_addr local_addr;
338   u16_t local_port;
339   err_t err;
340
341   sock = get_socket(s);
342   if (!sock)
343     return -1;
344
345   LWIP_ERROR("lwip_bind: invalid address", ((namelen == sizeof(struct sockaddr_in)) &&
346              ((((const struct sockaddr_in *)name)->sin_family) == AF_INET)),
347              sock_set_errno(sock, err_to_errno(ERR_ARG)); return -1;);
348
349   local_addr.addr = ((const struct sockaddr_in *)name)->sin_addr.s_addr;
350   local_port = ((const struct sockaddr_in *)name)->sin_port;
351
352   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d, addr=", s));
353   ip_addr_debug_print(SOCKETS_DEBUG, &local_addr);
354   LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F")\n", ntohs(local_port)));
355
356   err = netconn_bind(sock->conn, &local_addr, ntohs(local_port));
357
358   if (err != ERR_OK) {
359     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d) failed, err=%d\n", s, err));
360     sock_set_errno(sock, err_to_errno(err));
361     return -1;
362   }
363
364   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d) succeeded\n", s));
365   sock_set_errno(sock, 0);
366   return 0;
367 }
368
369 int
370 lwip_close(int s)
371 {
372   struct lwip_socket *sock;
373
374   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_close(%d)\n", s));
375
376   sock = get_socket(s);
377   if (!sock) {
378     return -1;
379   }
380
381   netconn_delete(sock->conn);
382
383   sys_sem_wait(socksem);
384   if (sock->lastdata) {
385     netbuf_delete(sock->lastdata);
386   }
387   sock->lastdata   = NULL;
388   sock->lastoffset = 0;
389   sock->conn       = NULL;
390   sock_set_errno(sock, 0);
391   sys_sem_signal(socksem);
392   return 0;
393 }
394
395 int
396 lwip_connect(int s, const struct sockaddr *name, socklen_t namelen)
397 {
398   struct lwip_socket *sock;
399   err_t err;
400
401   sock = get_socket(s);
402   if (!sock)
403     return -1;
404
405   LWIP_ERROR("lwip_connect: invalid address", ((namelen == sizeof(struct sockaddr_in)) &&
406              ((((const struct sockaddr_in *)name)->sin_family) == AF_INET)),
407              sock_set_errno(sock, err_to_errno(ERR_ARG)); return -1;);
408
409   if (((const struct sockaddr_in *)name)->sin_family == AF_UNSPEC) {
410     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d, AF_UNSPEC)\n", s));
411     err = netconn_disconnect(sock->conn);
412   } else {
413     struct ip_addr remote_addr;
414     u16_t remote_port;
415
416     remote_addr.addr = ((const struct sockaddr_in *)name)->sin_addr.s_addr;
417     remote_port = ((const struct sockaddr_in *)name)->sin_port;
418
419     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d, addr=", s));
420     ip_addr_debug_print(SOCKETS_DEBUG, &remote_addr);
421     LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F")\n", ntohs(remote_port)));
422
423     err = netconn_connect(sock->conn, &remote_addr, ntohs(remote_port));
424   }
425
426   if (err != ERR_OK) {
427     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d) failed, err=%d\n", s, err));
428     sock_set_errno(sock, err_to_errno(err));
429     return -1;
430   }
431
432   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d) succeeded\n", s));
433   sock_set_errno(sock, 0);
434   return 0;
435 }
436
437 /**
438  * Set a socket into listen mode.
439  * The socket may not have been used for another connection previously.
440  *
441  * @param s the socket to set to listening mode
442  * @param backlog (ATTENTION: need TCP_LISTEN_BACKLOG=1)
443  * @return 0 on success, non-zero on failure
444  */
445 int
446 lwip_listen(int s, int backlog)
447 {
448   struct lwip_socket *sock;
449   err_t err;
450
451   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_listen(%d, backlog=%d)\n", s, backlog));
452
453   sock = get_socket(s);
454   if (!sock)
455     return -1;
456
457   /* limit the "backlog" parameter to fit in an u8_t */
458   if (backlog < 0) {
459     backlog = 0;
460   }
461   if (backlog > 0xff) {
462     backlog = 0xff;
463   }
464
465   err = netconn_listen_with_backlog(sock->conn, backlog);
466
467   if (err != ERR_OK) {
468     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_listen(%d) failed, err=%d\n", s, err));
469     sock_set_errno(sock, err_to_errno(err));
470     return -1;
471   }
472
473   sock_set_errno(sock, 0);
474   return 0;
475 }
476
477 int
478 lwip_recvfrom(int s, void *mem, size_t len, int flags,
479         struct sockaddr *from, socklen_t *fromlen)
480 {
481   struct lwip_socket *sock;
482   struct netbuf      *buf;
483   u16_t               buflen, copylen;
484   int                 off = 0;
485   struct ip_addr     *addr;
486   u16_t               port;
487   u8_t                done = 0;
488   err_t               err;
489
490   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d, %p, %"SZT_F", 0x%x, ..)\n", s, mem, len, flags));
491   sock = get_socket(s);
492   if (!sock)
493     return -1;
494
495   do {
496     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: top while sock->lastdata=%p\n", (void*)sock->lastdata));
497     /* Check if there is data left from the last recv operation. */
498     if (sock->lastdata) {
499       buf = sock->lastdata;
500     } else {
501       /* If this is non-blocking call, then check first */
502       if (((flags & MSG_DONTWAIT) || (sock->flags & O_NONBLOCK)) && 
503           (sock->rcvevent <= 0)) {
504         if (off > 0) {
505           /* already received data, return that */
506           sock_set_errno(sock, 0);
507           return off;
508         }
509         LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): returning EWOULDBLOCK\n", s));
510         sock_set_errno(sock, EWOULDBLOCK);
511         return -1;
512       }
513
514       /* No data was left from the previous operation, so we try to get
515          some from the network. */
516       err = netconn_recv(sock->conn, &buf);
517       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: netconn_recv err=%d, netbuf=%p\n",
518         err, (void*)buf));
519
520       if (err != ERR_OK) {
521         if (off > 0) {
522           /* already received data, return that */
523           sock_set_errno(sock, 0);
524           return off;
525         }
526         /* We should really do some error checking here. */
527         LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): buf == NULL, error is \"%s\"!\n",
528           s, lwip_strerr(err)));
529         sock_set_errno(sock, err_to_errno(err));
530         return 0;
531       }
532       LWIP_ASSERT("buf != NULL", buf != NULL);
533       sock->lastdata = buf;
534     }
535
536     buflen = netbuf_len(buf);
537     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: buflen=%"U16_F" len=%"SZT_F" off=%d sock->lastoffset=%"U16_F"\n",
538       buflen, len, off, sock->lastoffset));
539
540     buflen -= sock->lastoffset;
541
542     if (len > buflen) {
543       copylen = buflen;
544     } else {
545       copylen = (u16_t)len;
546     }
547
548     /* copy the contents of the received buffer into
549     the supplied memory pointer mem */
550     netbuf_copy_partial(buf, (u8_t*)mem + off, copylen, sock->lastoffset);
551
552     off += copylen;
553
554     if (netconn_type(sock->conn) == NETCONN_TCP) {
555       LWIP_ASSERT("invalid copylen, len would underflow", len >= copylen);
556       len -= copylen;
557       if ( (len <= 0) || 
558            (buf->p->flags & PBUF_FLAG_PUSH) || 
559            (sock->rcvevent <= 0) || 
560            ((flags & MSG_PEEK)!=0)) {
561         done = 1;
562       }
563     } else {
564       done = 1;
565     }
566
567     /* Check to see from where the data was.*/
568     if (done) {
569       if (from && fromlen) {
570         struct sockaddr_in sin;
571
572         if (netconn_type(sock->conn) == NETCONN_TCP) {
573           addr = (struct ip_addr*)&(sin.sin_addr.s_addr);
574           netconn_getaddr(sock->conn, addr, &port, 0);
575         } else {
576           addr = netbuf_fromaddr(buf);
577           port = netbuf_fromport(buf);
578         }
579
580         memset(&sin, 0, sizeof(sin));
581         sin.sin_len = sizeof(sin);
582         sin.sin_family = AF_INET;
583         sin.sin_port = htons(port);
584         sin.sin_addr.s_addr = addr->addr;
585
586         if (*fromlen > sizeof(sin)) {
587           *fromlen = sizeof(sin);
588         }
589
590         MEMCPY(from, &sin, *fromlen);
591
592         LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): addr=", s));
593         ip_addr_debug_print(SOCKETS_DEBUG, addr);
594         LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F" len=%d\n", port, off));
595       } else {
596   #if SOCKETS_DEBUG
597         struct sockaddr_in sin;
598
599         if (netconn_type(sock->conn) == NETCONN_TCP) {
600           addr = (struct ip_addr*)&(sin.sin_addr.s_addr);
601           netconn_getaddr(sock->conn, addr, &port, 0);
602         } else {
603           addr = netbuf_fromaddr(buf);
604           port = netbuf_fromport(buf);
605         }
606
607         LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): addr=", s));
608         ip_addr_debug_print(SOCKETS_DEBUG, addr);
609         LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F" len=%d\n", port, off));
610   #endif /*  SOCKETS_DEBUG */
611       }
612     }
613
614     /* If we don't peek the incoming message... */
615     if ((flags & MSG_PEEK)==0) {
616       /* If this is a TCP socket, check if there is data left in the
617          buffer. If so, it should be saved in the sock structure for next
618          time around. */
619       if ((netconn_type(sock->conn) == NETCONN_TCP) && (buflen - copylen > 0)) {
620         sock->lastdata = buf;
621         sock->lastoffset += copylen;
622         LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: lastdata now netbuf=%p\n", (void*)buf));
623       } else {
624         sock->lastdata = NULL;
625         sock->lastoffset = 0;
626         LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: deleting netbuf=%p\n", (void*)buf));
627         netbuf_delete(buf);
628       }
629     }
630   } while (!done);
631
632   sock_set_errno(sock, 0);
633   return off;
634 }
635
636 int
637 lwip_read(int s, void *mem, size_t len)
638 {
639   return lwip_recvfrom(s, mem, len, 0, NULL, NULL);
640 }
641
642 int
643 lwip_recv(int s, void *mem, size_t len, int flags)
644 {
645   return lwip_recvfrom(s, mem, len, flags, NULL, NULL);
646 }
647
648 int
649 lwip_send(int s, const void *data, size_t size, int flags)
650 {
651   struct lwip_socket *sock;
652   err_t err;
653
654   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_send(%d, data=%p, size=%"SZT_F", flags=0x%x)\n",
655                               s, data, size, flags));
656
657   sock = get_socket(s);
658   if (!sock)
659     return -1;
660
661   if (sock->conn->type != NETCONN_TCP) {
662 #if (LWIP_UDP || LWIP_RAW)
663     return lwip_sendto(s, data, size, flags, NULL, 0);
664 #else
665     sock_set_errno(sock, err_to_errno(ERR_ARG));
666     return -1;
667 #endif /* (LWIP_UDP || LWIP_RAW) */
668   }
669
670   err = netconn_write(sock->conn, data, size, NETCONN_COPY | ((flags & MSG_MORE)?NETCONN_MORE:0));
671
672   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_send(%d) err=%d size=%"SZT_F"\n", s, err, size));
673   sock_set_errno(sock, err_to_errno(err));
674   return (err == ERR_OK ? (int)size : -1);
675 }
676
677 int
678 lwip_sendto(int s, const void *data, size_t size, int flags,
679        const struct sockaddr *to, socklen_t tolen)
680 {
681   struct lwip_socket *sock;
682   struct ip_addr remote_addr;
683   err_t err;
684   u16_t short_size;
685 #if !LWIP_TCPIP_CORE_LOCKING
686   struct netbuf buf;
687   u16_t remote_port;
688 #endif
689
690   sock = get_socket(s);
691   if (!sock)
692     return -1;
693
694   if (sock->conn->type == NETCONN_TCP) {
695 #if LWIP_TCP
696     return lwip_send(s, data, size, flags);
697 #else
698     sock_set_errno(sock, err_to_errno(ERR_ARG));
699     return -1;
700 #endif /* LWIP_TCP */
701   }
702
703   LWIP_ASSERT("lwip_sendto: size must fit in u16_t", size <= 0xffff);
704   short_size = (u16_t)size;
705   LWIP_ERROR("lwip_sendto: invalid address", (((to == NULL) && (tolen == 0)) ||
706              ((tolen == sizeof(struct sockaddr_in)) &&
707              ((((const struct sockaddr_in *)to)->sin_family) == AF_INET))),
708              sock_set_errno(sock, err_to_errno(ERR_ARG)); return -1;);
709
710 #if LWIP_TCPIP_CORE_LOCKING
711   /* Should only be consider like a sample or a simple way to experiment this option (no check of "to" field...) */
712   { struct pbuf* p;
713   
714     p = pbuf_alloc(PBUF_TRANSPORT, 0, PBUF_REF);
715     if (p == NULL) {
716       err = ERR_MEM;
717     } else {
718       p->payload = (void*)data;
719       p->len = p->tot_len = short_size;
720       
721       remote_addr.addr = ((const struct sockaddr_in *)to)->sin_addr.s_addr;
722       
723       LOCK_TCPIP_CORE();
724       if (sock->conn->type==NETCONN_RAW) {
725         err = sock->conn->err = raw_sendto(sock->conn->pcb.raw, p, &remote_addr);
726       } else {
727         err = sock->conn->err = udp_sendto(sock->conn->pcb.udp, p, &remote_addr, ntohs(((const struct sockaddr_in *)to)->sin_port));
728       }
729       UNLOCK_TCPIP_CORE();
730       
731       pbuf_free(p);
732     }
733   }
734 #else
735   /* initialize a buffer */
736   buf.p = buf.ptr = NULL;
737   if (to) {
738     remote_addr.addr = ((const struct sockaddr_in *)to)->sin_addr.s_addr;
739     remote_port      = ntohs(((const struct sockaddr_in *)to)->sin_port);
740     buf.addr         = &remote_addr;
741     buf.port         = remote_port;
742   } else {
743     remote_addr.addr = 0;
744     remote_port      = 0;
745     buf.addr         = NULL;
746     buf.port         = 0;
747   }
748
749   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_sendto(%d, data=%p, short_size=%d"U16_F", flags=0x%x to=",
750               s, data, short_size, flags));
751   ip_addr_debug_print(SOCKETS_DEBUG, &remote_addr);
752   LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F"\n", remote_port));
753
754   /* make the buffer point to the data that should be sent */
755 #if LWIP_NETIF_TX_SINGLE_PBUF
756   /* Allocate a new netbuf and copy the data into it. */
757   if (netbuf_alloc(&buf, short_size) == NULL) {
758     err = ERR_MEM;
759   } else {
760     err = netbuf_take(&buf, data, short_size);
761   }
762 #else /* LWIP_NETIF_TX_SINGLE_PBUF */
763   err = netbuf_ref(&buf, data, short_size);
764 #endif /* LWIP_NETIF_TX_SINGLE_PBUF */
765   if (err == ERR_OK) {
766     /* send the data */
767     err = netconn_send(sock->conn, &buf);
768   }
769
770   /* deallocated the buffer */
771   netbuf_free(&buf);
772 #endif /* LWIP_TCPIP_CORE_LOCKING */
773   sock_set_errno(sock, err_to_errno(err));
774   return (err == ERR_OK ? short_size : -1);
775 }
776
777 int
778 lwip_socket(int domain, int type, int protocol)
779 {
780   struct netconn *conn;
781   int i;
782
783   LWIP_UNUSED_ARG(domain);
784
785   /* create a netconn */
786   switch (type) {
787   case SOCK_RAW:
788     conn = netconn_new_with_proto_and_callback(NETCONN_RAW, (u8_t)protocol, event_callback);
789     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_RAW, %d) = ",
790                                  domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol));
791     break;
792   case SOCK_DGRAM:
793     conn = netconn_new_with_callback( (protocol == IPPROTO_UDPLITE) ?
794                  NETCONN_UDPLITE : NETCONN_UDP, event_callback);
795     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_DGRAM, %d) = ",
796                                  domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol));
797     break;
798   case SOCK_STREAM:
799     conn = netconn_new_with_callback(NETCONN_TCP, event_callback);
800     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_STREAM, %d) = ",
801                                  domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol));
802     break;
803   default:
804     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%d, %d/UNKNOWN, %d) = -1\n",
805                                  domain, type, protocol));
806     set_errno(EINVAL);
807     return -1;
808   }
809
810   if (!conn) {
811     LWIP_DEBUGF(SOCKETS_DEBUG, ("-1 / ENOBUFS (could not create netconn)\n"));
812     set_errno(ENOBUFS);
813     return -1;
814   }
815
816   i = alloc_socket(conn);
817
818   if (i == -1) {
819     netconn_delete(conn);
820     set_errno(ENFILE);
821     return -1;
822   }
823   conn->socket = i;
824   LWIP_DEBUGF(SOCKETS_DEBUG, ("%d\n", i));
825   set_errno(0);
826   return i;
827 }
828
829 int
830 lwip_write(int s, const void *data, size_t size)
831 {
832   return lwip_send(s, data, size, 0);
833 }
834
835 /**
836  * Go through the readset and writeset lists and see which socket of the sockets
837  * set in the sets has events. On return, readset, writeset and exceptset have
838  * the sockets enabled that had events.
839  *
840  * exceptset is not used for now!!!
841  *
842  * @param maxfdp1 the highest socket index in the sets
843  * @param readset in: set of sockets to check for read events;
844  *                out: set of sockets that had read events
845  * @param writeset in: set of sockets to check for write events;
846  *                 out: set of sockets that had write events
847  * @param exceptset not yet implemented
848  * @return number of sockets that had events (read+write)
849  */
850 static int
851 lwip_selscan(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset)
852 {
853   int i, nready = 0;
854   fd_set lreadset, lwriteset, lexceptset;
855   struct lwip_socket *p_sock;
856   
857   FD_ZERO(&lreadset);
858   FD_ZERO(&lwriteset);
859   FD_ZERO(&lexceptset);
860   
861   /* Go through each socket in each list to count number of sockets which
862   currently match */
863   for(i = 0; i < maxfdp1; i++) {
864     if (FD_ISSET(i, readset)) {
865       /* See if netconn of this socket is ready for read */
866       p_sock = get_socket(i);
867       if (p_sock && (p_sock->lastdata || (p_sock->rcvevent > 0))) {
868         FD_SET(i, &lreadset);
869         LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_selscan: fd=%d ready for reading\n", i));
870         nready++;
871       }
872     }
873     if (FD_ISSET(i, writeset)) {
874       /* See if netconn of this socket is ready for write */
875       p_sock = get_socket(i);
876       if (p_sock && p_sock->sendevent) {
877         FD_SET(i, &lwriteset);
878         LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_selscan: fd=%d ready for writing\n", i));
879         nready++;
880       }
881     }
882   }
883   *readset = lreadset;
884   *writeset = lwriteset;
885   FD_ZERO(exceptset);
886   
887   return nready;
888 }
889
890
891 /**
892  * Processing exceptset is not yet implemented.
893  */
894 int
895 lwip_select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset,
896                struct timeval *timeout)
897 {
898   int i;
899   int nready;
900   fd_set lreadset, lwriteset, lexceptset;
901   u32_t msectimeout;
902   struct lwip_select_cb select_cb;
903   struct lwip_select_cb *p_selcb;
904
905   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select(%d, %p, %p, %p, tvsec=%ld tvusec=%ld)\n",
906                   maxfdp1, (void *)readset, (void *) writeset, (void *) exceptset,
907                   timeout ? (long)timeout->tv_sec : (long)-1,
908                   timeout ? (long)timeout->tv_usec : (long)-1));
909
910   select_cb.next = 0;
911   select_cb.readset = readset;
912   select_cb.writeset = writeset;
913   select_cb.exceptset = exceptset;
914   select_cb.sem_signalled = 0;
915
916   /* Protect ourselves searching through the list */
917   sys_sem_wait(selectsem);
918
919   if (readset)
920     lreadset = *readset;
921   else
922     FD_ZERO(&lreadset);
923   if (writeset)
924     lwriteset = *writeset;
925   else
926     FD_ZERO(&lwriteset);
927   if (exceptset)
928     lexceptset = *exceptset;
929   else
930     FD_ZERO(&lexceptset);
931
932   /* Go through each socket in each list to count number of sockets which
933      currently match */
934   nready = lwip_selscan(maxfdp1, &lreadset, &lwriteset, &lexceptset);
935
936   /* If we don't have any current events, then suspend if we are supposed to */
937   if (!nready) {
938     if (timeout && timeout->tv_sec == 0 && timeout->tv_usec == 0) {
939       sys_sem_signal(selectsem);
940       if (readset)
941         FD_ZERO(readset);
942       if (writeset)
943         FD_ZERO(writeset);
944       if (exceptset)
945         FD_ZERO(exceptset);
946   
947       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select: no timeout, returning 0\n"));
948       set_errno(0);
949   
950       return 0;
951     }
952     
953     /* add our semaphore to list */
954     /* We don't actually need any dynamic memory. Our entry on the
955      * list is only valid while we are in this function, so it's ok
956      * to use local variables */
957     
958     select_cb.sem = sys_sem_new(0);
959     /* Note that we are still protected */
960     /* Put this select_cb on top of list */
961     select_cb.next = select_cb_list;
962     select_cb_list = &select_cb;
963     
964     /* Now we can safely unprotect */
965     sys_sem_signal(selectsem);
966     
967     /* Now just wait to be woken */
968     if (timeout == 0)
969       /* Wait forever */
970       msectimeout = 0;
971     else {
972       msectimeout =  ((timeout->tv_sec * 1000) + ((timeout->tv_usec + 500)/1000));
973       if(msectimeout == 0)
974         msectimeout = 1;
975     }
976     
977     i = sys_sem_wait_timeout(select_cb.sem, msectimeout);
978     
979     /* Take us off the list */
980     sys_sem_wait(selectsem);
981     if (select_cb_list == &select_cb)
982       select_cb_list = select_cb.next;
983     else
984       for (p_selcb = select_cb_list; p_selcb; p_selcb = p_selcb->next) {
985         if (p_selcb->next == &select_cb) {
986           p_selcb->next = select_cb.next;
987           break;
988         }
989       }
990     
991     sys_sem_signal(selectsem);
992     
993     sys_sem_free(select_cb.sem);
994     if (i == SYS_ARCH_TIMEOUT)  {
995       /* Timeout */
996       if (readset)
997         FD_ZERO(readset);
998       if (writeset)
999         FD_ZERO(writeset);
1000       if (exceptset)
1001         FD_ZERO(exceptset);
1002   
1003       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select: timeout expired\n"));
1004       set_errno(0);
1005   
1006       return 0;
1007     }
1008     
1009     if (readset)
1010       lreadset = *readset;
1011     else
1012       FD_ZERO(&lreadset);
1013     if (writeset)
1014       lwriteset = *writeset;
1015     else
1016       FD_ZERO(&lwriteset);
1017     if (exceptset)
1018       lexceptset = *exceptset;
1019     else
1020       FD_ZERO(&lexceptset);
1021     
1022     /* See what's set */
1023     nready = lwip_selscan(maxfdp1, &lreadset, &lwriteset, &lexceptset);
1024   } else
1025     sys_sem_signal(selectsem);
1026   
1027   if (readset)
1028     *readset = lreadset;
1029   if (writeset)
1030     *writeset = lwriteset;
1031   if (exceptset)
1032     *exceptset = lexceptset;
1033   
1034   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select: nready=%d\n", nready));
1035   set_errno(0);
1036   
1037   return nready;
1038 }
1039
1040 /**
1041  * Callback registered in the netconn layer for each socket-netconn.
1042  * Processes recvevent (data available) and wakes up tasks waiting for select.
1043  */
1044 static void
1045 event_callback(struct netconn *conn, enum netconn_evt evt, u16_t len)
1046 {
1047   int s;
1048   struct lwip_socket *sock;
1049   struct lwip_select_cb *scb;
1050
1051   LWIP_UNUSED_ARG(len);
1052
1053   /* Get socket */
1054   if (conn) {
1055     s = conn->socket;
1056     if (s < 0) {
1057       /* Data comes in right away after an accept, even though
1058        * the server task might not have created a new socket yet.
1059        * Just count down (or up) if that's the case and we
1060        * will use the data later. Note that only receive events
1061        * can happen before the new socket is set up. */
1062       sys_sem_wait(socksem);
1063       if (conn->socket < 0) {
1064         if (evt == NETCONN_EVT_RCVPLUS) {
1065           conn->socket--;
1066         }
1067         sys_sem_signal(socksem);
1068         return;
1069       }
1070       s = conn->socket;
1071       sys_sem_signal(socksem);
1072     }
1073
1074     sock = get_socket(s);
1075     if (!sock) {
1076       return;
1077     }
1078   } else {
1079     return;
1080   }
1081
1082   sys_sem_wait(selectsem);
1083   /* Set event as required */
1084   switch (evt) {
1085     case NETCONN_EVT_RCVPLUS:
1086       sock->rcvevent++;
1087       break;
1088     case NETCONN_EVT_RCVMINUS:
1089       sock->rcvevent--;
1090       break;
1091     case NETCONN_EVT_SENDPLUS:
1092       sock->sendevent = 1;
1093       break;
1094     case NETCONN_EVT_SENDMINUS:
1095       sock->sendevent = 0;
1096       break;
1097     default:
1098       LWIP_ASSERT("unknown event", 0);
1099       break;
1100   }
1101   sys_sem_signal(selectsem);
1102
1103   /* Now decide if anyone is waiting for this socket */
1104   /* NOTE: This code is written this way to protect the select link list
1105      but to avoid a deadlock situation by releasing socksem before
1106      signalling for the select. This means we need to go through the list
1107      multiple times ONLY IF a select was actually waiting. We go through
1108      the list the number of waiting select calls + 1. This list is
1109      expected to be small. */
1110   while (1) {
1111     sys_sem_wait(selectsem);
1112     for (scb = select_cb_list; scb; scb = scb->next) {
1113       if (scb->sem_signalled == 0) {
1114         /* Test this select call for our socket */
1115         if (scb->readset && FD_ISSET(s, scb->readset))
1116           if (sock->rcvevent > 0)
1117             break;
1118         if (scb->writeset && FD_ISSET(s, scb->writeset))
1119           if (sock->sendevent)
1120             break;
1121       }
1122     }
1123     if (scb) {
1124       scb->sem_signalled = 1;
1125       sys_sem_signal(scb->sem);
1126       sys_sem_signal(selectsem);
1127     } else {
1128       sys_sem_signal(selectsem);
1129       break;
1130     }
1131   }
1132 }
1133
1134 /**
1135  * Unimplemented: Close one end of a full-duplex connection.
1136  * Currently, the full connection is closed.
1137  */
1138 int
1139 lwip_shutdown(int s, int how)
1140 {
1141   LWIP_UNUSED_ARG(how);
1142   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_shutdown(%d, how=%d)\n", s, how));
1143   return lwip_close(s); /* XXX temporary hack until proper implementation */
1144 }
1145
1146 static int
1147 lwip_getaddrname(int s, struct sockaddr *name, socklen_t *namelen, u8_t local)
1148 {
1149   struct lwip_socket *sock;
1150   struct sockaddr_in sin;
1151   struct ip_addr naddr;
1152
1153   sock = get_socket(s);
1154   if (!sock)
1155     return -1;
1156
1157   memset(&sin, 0, sizeof(sin));
1158   sin.sin_len = sizeof(sin);
1159   sin.sin_family = AF_INET;
1160
1161   /* get the IP address and port */
1162   netconn_getaddr(sock->conn, &naddr, &sin.sin_port, local);
1163
1164   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getaddrname(%d, addr=", s));
1165   ip_addr_debug_print(SOCKETS_DEBUG, &naddr);
1166   LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F")\n", sin.sin_port));
1167
1168   sin.sin_port = htons(sin.sin_port);
1169   sin.sin_addr.s_addr = naddr.addr;
1170
1171   if (*namelen > sizeof(sin))
1172     *namelen = sizeof(sin);
1173
1174   MEMCPY(name, &sin, *namelen);
1175   sock_set_errno(sock, 0);
1176   return 0;
1177 }
1178
1179 int
1180 lwip_getpeername(int s, struct sockaddr *name, socklen_t *namelen)
1181 {
1182   return lwip_getaddrname(s, name, namelen, 0);
1183 }
1184
1185 int
1186 lwip_getsockname(int s, struct sockaddr *name, socklen_t *namelen)
1187 {
1188   return lwip_getaddrname(s, name, namelen, 1);
1189 }
1190
1191 int
1192 lwip_getsockopt(int s, int level, int optname, void *optval, socklen_t *optlen)
1193 {
1194   err_t err = ERR_OK;
1195   struct lwip_socket *sock = get_socket(s);
1196   struct lwip_setgetsockopt_data data;
1197
1198   if (!sock)
1199     return -1;
1200
1201   if ((NULL == optval) || (NULL == optlen)) {
1202     sock_set_errno(sock, EFAULT);
1203     return -1;
1204   }
1205
1206   /* Do length and type checks for the various options first, to keep it readable. */
1207   switch (level) {
1208    
1209 /* Level: SOL_SOCKET */
1210   case SOL_SOCKET:
1211     switch (optname) {
1212        
1213     case SO_ACCEPTCONN:
1214     case SO_BROADCAST:
1215     /* UNIMPL case SO_DEBUG: */
1216     /* UNIMPL case SO_DONTROUTE: */
1217     case SO_ERROR:
1218     case SO_KEEPALIVE:
1219     /* UNIMPL case SO_CONTIMEO: */
1220     /* UNIMPL case SO_SNDTIMEO: */
1221 #if LWIP_SO_RCVTIMEO
1222     case SO_RCVTIMEO:
1223 #endif /* LWIP_SO_RCVTIMEO */
1224 #if LWIP_SO_RCVBUF
1225     case SO_RCVBUF:
1226 #endif /* LWIP_SO_RCVBUF */
1227     /* UNIMPL case SO_OOBINLINE: */
1228     /* UNIMPL case SO_SNDBUF: */
1229     /* UNIMPL case SO_RCVLOWAT: */
1230     /* UNIMPL case SO_SNDLOWAT: */
1231 #if SO_REUSE
1232     case SO_REUSEADDR:
1233     case SO_REUSEPORT:
1234 #endif /* SO_REUSE */
1235     case SO_TYPE:
1236     /* UNIMPL case SO_USELOOPBACK: */
1237       if (*optlen < sizeof(int)) {
1238         err = EINVAL;
1239       }
1240       break;
1241
1242     case SO_NO_CHECK:
1243       if (*optlen < sizeof(int)) {
1244         err = EINVAL;
1245       }
1246 #if LWIP_UDP
1247       if ((sock->conn->type != NETCONN_UDP) ||
1248           ((udp_flags(sock->conn->pcb.udp) & UDP_FLAGS_UDPLITE) != 0)) {
1249         /* this flag is only available for UDP, not for UDP lite */
1250         err = EAFNOSUPPORT;
1251       }
1252 #endif /* LWIP_UDP */
1253       break;
1254
1255     default:
1256       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, UNIMPL: optname=0x%x, ..)\n",
1257                                   s, optname));
1258       err = ENOPROTOOPT;
1259     }  /* switch (optname) */
1260     break;
1261                      
1262 /* Level: IPPROTO_IP */
1263   case IPPROTO_IP:
1264     switch (optname) {
1265     /* UNIMPL case IP_HDRINCL: */
1266     /* UNIMPL case IP_RCVDSTADDR: */
1267     /* UNIMPL case IP_RCVIF: */
1268     case IP_TTL:
1269     case IP_TOS:
1270       if (*optlen < sizeof(int)) {
1271         err = EINVAL;
1272       }
1273       break;
1274 #if LWIP_IGMP
1275     case IP_MULTICAST_TTL:
1276       if (*optlen < sizeof(u8_t)) {
1277         err = EINVAL;
1278       }
1279       break;
1280     case IP_MULTICAST_IF:
1281       if (*optlen < sizeof(struct in_addr)) {
1282         err = EINVAL;
1283       }
1284       break;
1285 #endif /* LWIP_IGMP */
1286
1287     default:
1288       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, UNIMPL: optname=0x%x, ..)\n",
1289                                   s, optname));
1290       err = ENOPROTOOPT;
1291     }  /* switch (optname) */
1292     break;
1293          
1294 #if LWIP_TCP
1295 /* Level: IPPROTO_TCP */
1296   case IPPROTO_TCP:
1297     if (*optlen < sizeof(int)) {
1298       err = EINVAL;
1299       break;
1300     }
1301     
1302     /* If this is no TCP socket, ignore any options. */
1303     if (sock->conn->type != NETCONN_TCP)
1304       return 0;
1305
1306     switch (optname) {
1307     case TCP_NODELAY:
1308     case TCP_KEEPALIVE:
1309 #if LWIP_TCP_KEEPALIVE
1310     case TCP_KEEPIDLE:
1311     case TCP_KEEPINTVL:
1312     case TCP_KEEPCNT:
1313 #endif /* LWIP_TCP_KEEPALIVE */
1314       break;
1315        
1316     default:
1317       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_TCP, UNIMPL: optname=0x%x, ..)\n",
1318                                   s, optname));
1319       err = ENOPROTOOPT;
1320     }  /* switch (optname) */
1321     break;
1322 #endif /* LWIP_TCP */
1323 #if LWIP_UDP && LWIP_UDPLITE
1324 /* Level: IPPROTO_UDPLITE */
1325   case IPPROTO_UDPLITE:
1326     if (*optlen < sizeof(int)) {
1327       err = EINVAL;
1328       break;
1329     }
1330     
1331     /* If this is no UDP lite socket, ignore any options. */
1332     if (sock->conn->type != NETCONN_UDPLITE)
1333       return 0;
1334
1335     switch (optname) {
1336     case UDPLITE_SEND_CSCOV:
1337     case UDPLITE_RECV_CSCOV:
1338       break;
1339        
1340     default:
1341       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_UDPLITE, UNIMPL: optname=0x%x, ..)\n",
1342                                   s, optname));
1343       err = ENOPROTOOPT;
1344     }  /* switch (optname) */
1345     break;
1346 #endif /* LWIP_UDP && LWIP_UDPLITE*/
1347 /* UNDEFINED LEVEL */
1348   default:
1349       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, level=0x%x, UNIMPL: optname=0x%x, ..)\n",
1350                                   s, level, optname));
1351       err = ENOPROTOOPT;
1352   }  /* switch */
1353
1354    
1355   if (err != ERR_OK) {
1356     sock_set_errno(sock, err);
1357     return -1;
1358   }
1359
1360   /* Now do the actual option processing */
1361   data.sock = sock;
1362   data.level = level;
1363   data.optname = optname;
1364   data.optval = optval;
1365   data.optlen = optlen;
1366   data.err = err;
1367   tcpip_callback(lwip_getsockopt_internal, &data);
1368   sys_arch_sem_wait(sock->conn->op_completed, 0);
1369   /* maybe lwip_getsockopt_internal has changed err */
1370   err = data.err;
1371
1372   sock_set_errno(sock, err);
1373   return err ? -1 : 0;
1374 }
1375
1376 static void
1377 lwip_getsockopt_internal(void *arg)
1378 {
1379   struct lwip_socket *sock;
1380 #ifdef LWIP_DEBUG
1381   int s;
1382 #endif /* LWIP_DEBUG */
1383   int level, optname;
1384   void *optval;
1385   struct lwip_setgetsockopt_data *data;
1386
1387   LWIP_ASSERT("arg != NULL", arg != NULL);
1388
1389   data = (struct lwip_setgetsockopt_data*)arg;
1390   sock = data->sock;
1391 #ifdef LWIP_DEBUG
1392   s = data->s;
1393 #endif /* LWIP_DEBUG */
1394   level = data->level;
1395   optname = data->optname;
1396   optval = data->optval;
1397
1398   switch (level) {
1399    
1400 /* Level: SOL_SOCKET */
1401   case SOL_SOCKET:
1402     switch (optname) {
1403
1404     /* The option flags */
1405     case SO_ACCEPTCONN:
1406     case SO_BROADCAST:
1407     /* UNIMPL case SO_DEBUG: */
1408     /* UNIMPL case SO_DONTROUTE: */
1409     case SO_KEEPALIVE:
1410     /* UNIMPL case SO_OOBINCLUDE: */
1411 #if SO_REUSE
1412     case SO_REUSEADDR:
1413     case SO_REUSEPORT:
1414 #endif /* SO_REUSE */
1415     /*case SO_USELOOPBACK: UNIMPL */
1416       *(int*)optval = sock->conn->pcb.ip->so_options & optname;
1417       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, optname=0x%x, ..) = %s\n",
1418                                   s, optname, (*(int*)optval?"on":"off")));
1419       break;
1420
1421     case SO_TYPE:
1422       switch (NETCONNTYPE_GROUP(sock->conn->type)) {
1423       case NETCONN_RAW:
1424         *(int*)optval = SOCK_RAW;
1425         break;
1426       case NETCONN_TCP:
1427         *(int*)optval = SOCK_STREAM;
1428         break;
1429       case NETCONN_UDP:
1430         *(int*)optval = SOCK_DGRAM;
1431         break;
1432       default: /* unrecognized socket type */
1433         *(int*)optval = sock->conn->type;
1434         LWIP_DEBUGF(SOCKETS_DEBUG,
1435                     ("lwip_getsockopt(%d, SOL_SOCKET, SO_TYPE): unrecognized socket type %d\n",
1436                     s, *(int *)optval));
1437       }  /* switch (sock->conn->type) */
1438       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, SO_TYPE) = %d\n",
1439                   s, *(int *)optval));
1440       break;
1441
1442     case SO_ERROR:
1443       /* only overwrite if ERR_OK before */
1444       if (sock->err == 0) {
1445         sock_set_errno(sock, err_to_errno(sock->conn->last_err));
1446       } 
1447       *(int *)optval = sock->err;
1448       sock->err = 0;
1449       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, SO_ERROR) = %d\n",
1450                   s, *(int *)optval));
1451       break;
1452
1453 #if LWIP_SO_RCVTIMEO
1454     case SO_RCVTIMEO:
1455       *(int *)optval = sock->conn->recv_timeout;
1456       break;
1457 #endif /* LWIP_SO_RCVTIMEO */
1458 #if LWIP_SO_RCVBUF
1459     case SO_RCVBUF:
1460       *(int *)optval = sock->conn->recv_bufsize;
1461       break;
1462 #endif /* LWIP_SO_RCVBUF */
1463 #if LWIP_UDP
1464     case SO_NO_CHECK:
1465       *(int*)optval = (udp_flags(sock->conn->pcb.udp) & UDP_FLAGS_NOCHKSUM) ? 1 : 0;
1466       break;
1467 #endif /* LWIP_UDP*/
1468     }  /* switch (optname) */
1469     break;
1470
1471 /* Level: IPPROTO_IP */
1472   case IPPROTO_IP:
1473     switch (optname) {
1474     case IP_TTL:
1475       *(int*)optval = sock->conn->pcb.ip->ttl;
1476       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_TTL) = %d\n",
1477                   s, *(int *)optval));
1478       break;
1479     case IP_TOS:
1480       *(int*)optval = sock->conn->pcb.ip->tos;
1481       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_TOS) = %d\n",
1482                   s, *(int *)optval));
1483       break;
1484 #if LWIP_IGMP
1485     case IP_MULTICAST_TTL:
1486       *(u8_t*)optval = sock->conn->pcb.ip->ttl;
1487       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_MULTICAST_TTL) = %d\n",
1488                   s, *(int *)optval));
1489       break;
1490     case IP_MULTICAST_IF:
1491       ((struct in_addr*) optval)->s_addr = sock->conn->pcb.udp->multicast_ip.addr;
1492       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_MULTICAST_IF) = 0x%"X32_F"\n",
1493                   s, *(u32_t *)optval));
1494       break;
1495 #endif /* LWIP_IGMP */
1496     }  /* switch (optname) */
1497     break;
1498
1499 #if LWIP_TCP
1500 /* Level: IPPROTO_TCP */
1501   case IPPROTO_TCP:
1502     switch (optname) {
1503     case TCP_NODELAY:
1504       *(int*)optval = tcp_nagle_disabled(sock->conn->pcb.tcp);
1505       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_TCP, TCP_NODELAY) = %s\n",
1506                   s, (*(int*)optval)?"on":"off") );
1507       break;
1508     case TCP_KEEPALIVE:
1509       *(int*)optval = (int)sock->conn->pcb.tcp->keep_idle;
1510       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, TCP_KEEPALIVE) = %d\n",
1511                   s, *(int *)optval));
1512       break;
1513
1514 #if LWIP_TCP_KEEPALIVE
1515     case TCP_KEEPIDLE:
1516       *(int*)optval = (int)(sock->conn->pcb.tcp->keep_idle/1000);
1517       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, TCP_KEEPIDLE) = %d\n",
1518                   s, *(int *)optval));
1519       break;
1520     case TCP_KEEPINTVL:
1521       *(int*)optval = (int)(sock->conn->pcb.tcp->keep_intvl/1000);
1522       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, TCP_KEEPINTVL) = %d\n",
1523                   s, *(int *)optval));
1524       break;
1525     case TCP_KEEPCNT:
1526       *(int*)optval = (int)sock->conn->pcb.tcp->keep_cnt;
1527       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, TCP_KEEPCNT) = %d\n",
1528                   s, *(int *)optval));
1529       break;
1530 #endif /* LWIP_TCP_KEEPALIVE */
1531
1532     }  /* switch (optname) */
1533     break;
1534 #endif /* LWIP_TCP */
1535 #if LWIP_UDP && LWIP_UDPLITE
1536   /* Level: IPPROTO_UDPLITE */
1537   case IPPROTO_UDPLITE:
1538     switch (optname) {
1539     case UDPLITE_SEND_CSCOV:
1540       *(int*)optval = sock->conn->pcb.udp->chksum_len_tx;
1541       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_UDPLITE, UDPLITE_SEND_CSCOV) = %d\n",
1542                   s, (*(int*)optval)) );
1543       break;
1544     case UDPLITE_RECV_CSCOV:
1545       *(int*)optval = sock->conn->pcb.udp->chksum_len_rx;
1546       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_UDPLITE, UDPLITE_RECV_CSCOV) = %d\n",
1547                   s, (*(int*)optval)) );
1548       break;
1549     }  /* switch (optname) */
1550     break;
1551 #endif /* LWIP_UDP */
1552   } /* switch (level) */
1553   sys_sem_signal(sock->conn->op_completed);
1554 }
1555
1556 int
1557 lwip_setsockopt(int s, int level, int optname, const void *optval, socklen_t optlen)
1558 {
1559   struct lwip_socket *sock = get_socket(s);
1560   int err = ERR_OK;
1561   struct lwip_setgetsockopt_data data;
1562
1563   if (!sock)
1564     return -1;
1565
1566   if (NULL == optval) {
1567     sock_set_errno(sock, EFAULT);
1568     return -1;
1569   }
1570
1571   /* Do length and type checks for the various options first, to keep it readable. */
1572   switch (level) {
1573
1574 /* Level: SOL_SOCKET */
1575   case SOL_SOCKET:
1576     switch (optname) {
1577
1578     case SO_BROADCAST:
1579     /* UNIMPL case SO_DEBUG: */
1580     /* UNIMPL case SO_DONTROUTE: */
1581     case SO_KEEPALIVE:
1582     /* UNIMPL case case SO_CONTIMEO: */
1583     /* UNIMPL case case SO_SNDTIMEO: */
1584 #if LWIP_SO_RCVTIMEO
1585     case SO_RCVTIMEO:
1586 #endif /* LWIP_SO_RCVTIMEO */
1587 #if LWIP_SO_RCVBUF
1588     case SO_RCVBUF:
1589 #endif /* LWIP_SO_RCVBUF */
1590     /* UNIMPL case SO_OOBINLINE: */
1591     /* UNIMPL case SO_SNDBUF: */
1592     /* UNIMPL case SO_RCVLOWAT: */
1593     /* UNIMPL case SO_SNDLOWAT: */
1594 #if SO_REUSE
1595     case SO_REUSEADDR:
1596     case SO_REUSEPORT:
1597 #endif /* SO_REUSE */
1598     /* UNIMPL case SO_USELOOPBACK: */
1599       if (optlen < sizeof(int)) {
1600         err = EINVAL;
1601       }
1602       break;
1603     case SO_NO_CHECK:
1604       if (optlen < sizeof(int)) {
1605         err = EINVAL;
1606       }
1607 #if LWIP_UDP
1608       if ((sock->conn->type != NETCONN_UDP) ||
1609           ((udp_flags(sock->conn->pcb.udp) & UDP_FLAGS_UDPLITE) != 0)) {
1610         /* this flag is only available for UDP, not for UDP lite */
1611         err = EAFNOSUPPORT;
1612       }
1613 #endif /* LWIP_UDP */
1614       break;
1615     default:
1616       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, SOL_SOCKET, UNIMPL: optname=0x%x, ..)\n",
1617                   s, optname));
1618       err = ENOPROTOOPT;
1619     }  /* switch (optname) */
1620     break;
1621
1622 /* Level: IPPROTO_IP */
1623   case IPPROTO_IP:
1624     switch (optname) {
1625     /* UNIMPL case IP_HDRINCL: */
1626     /* UNIMPL case IP_RCVDSTADDR: */
1627     /* UNIMPL case IP_RCVIF: */
1628     case IP_TTL:
1629     case IP_TOS:
1630       if (optlen < sizeof(int)) {
1631         err = EINVAL;
1632       }
1633       break;
1634 #if LWIP_IGMP
1635     case IP_MULTICAST_TTL:
1636       if (optlen < sizeof(u8_t)) {
1637         err = EINVAL;
1638       }
1639       if (NETCONNTYPE_GROUP(sock->conn->type) != NETCONN_UDP) {
1640         err = EAFNOSUPPORT;
1641       }
1642       break;
1643     case IP_MULTICAST_IF:
1644       if (optlen < sizeof(struct in_addr)) {
1645         err = EINVAL;
1646       }
1647       if (NETCONNTYPE_GROUP(sock->conn->type) != NETCONN_UDP) {
1648         err = EAFNOSUPPORT;
1649       }
1650       break;
1651     case IP_ADD_MEMBERSHIP:
1652     case IP_DROP_MEMBERSHIP:
1653       if (optlen < sizeof(struct ip_mreq)) {
1654         err = EINVAL;
1655       }
1656       if (NETCONNTYPE_GROUP(sock->conn->type) != NETCONN_UDP) {
1657         err = EAFNOSUPPORT;
1658       }
1659       break;
1660 #endif /* LWIP_IGMP */
1661       default:
1662         LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IP, UNIMPL: optname=0x%x, ..)\n",
1663                     s, optname));
1664         err = ENOPROTOOPT;
1665     }  /* switch (optname) */
1666     break;
1667
1668 #if LWIP_TCP
1669 /* Level: IPPROTO_TCP */
1670   case IPPROTO_TCP:
1671     if (optlen < sizeof(int)) {
1672       err = EINVAL;
1673       break;
1674     }
1675
1676     /* If this is no TCP socket, ignore any options. */
1677     if (sock->conn->type != NETCONN_TCP)
1678       return 0;
1679
1680     switch (optname) {
1681     case TCP_NODELAY:
1682     case TCP_KEEPALIVE:
1683 #if LWIP_TCP_KEEPALIVE
1684     case TCP_KEEPIDLE:
1685     case TCP_KEEPINTVL:
1686     case TCP_KEEPCNT:
1687 #endif /* LWIP_TCP_KEEPALIVE */
1688       break;
1689
1690     default:
1691       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, UNIMPL: optname=0x%x, ..)\n",
1692                   s, optname));
1693       err = ENOPROTOOPT;
1694     }  /* switch (optname) */
1695     break;
1696 #endif /* LWIP_TCP */
1697 #if LWIP_UDP && LWIP_UDPLITE
1698 /* Level: IPPROTO_UDPLITE */
1699   case IPPROTO_UDPLITE:
1700     if (optlen < sizeof(int)) {
1701       err = EINVAL;
1702       break;
1703     }
1704
1705     /* If this is no UDP lite socket, ignore any options. */
1706     if (sock->conn->type != NETCONN_UDPLITE)
1707       return 0;
1708
1709     switch (optname) {
1710     case UDPLITE_SEND_CSCOV:
1711     case UDPLITE_RECV_CSCOV:
1712       break;
1713
1714     default:
1715       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_UDPLITE, UNIMPL: optname=0x%x, ..)\n",
1716                   s, optname));
1717       err = ENOPROTOOPT;
1718     }  /* switch (optname) */
1719     break;
1720 #endif /* LWIP_UDP && LWIP_UDPLITE */
1721 /* UNDEFINED LEVEL */
1722   default:
1723     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, level=0x%x, UNIMPL: optname=0x%x, ..)\n",
1724                 s, level, optname));
1725     err = ENOPROTOOPT;
1726   }  /* switch (level) */
1727
1728
1729   if (err != ERR_OK) {
1730     sock_set_errno(sock, err);
1731     return -1;
1732   }
1733
1734
1735   /* Now do the actual option processing */
1736   data.sock = sock;
1737   data.level = level;
1738   data.optname = optname;
1739   data.optval = (void*)optval;
1740   data.optlen = &optlen;
1741   data.err = err;
1742   tcpip_callback(lwip_setsockopt_internal, &data);
1743   sys_arch_sem_wait(sock->conn->op_completed, 0);
1744   /* maybe lwip_setsockopt_internal has changed err */
1745   err = data.err;
1746
1747   sock_set_errno(sock, err);
1748   return err ? -1 : 0;
1749 }
1750
1751 static void
1752 lwip_setsockopt_internal(void *arg)
1753 {
1754   struct lwip_socket *sock;
1755 #ifdef LWIP_DEBUG
1756   int s;
1757 #endif /* LWIP_DEBUG */
1758   int level, optname;
1759   const void *optval;
1760   struct lwip_setgetsockopt_data *data;
1761
1762   LWIP_ASSERT("arg != NULL", arg != NULL);
1763
1764   data = (struct lwip_setgetsockopt_data*)arg;
1765   sock = data->sock;
1766 #ifdef LWIP_DEBUG
1767   s = data->s;
1768 #endif /* LWIP_DEBUG */
1769   level = data->level;
1770   optname = data->optname;
1771   optval = data->optval;
1772
1773   switch (level) {
1774
1775 /* Level: SOL_SOCKET */
1776   case SOL_SOCKET:
1777     switch (optname) {
1778
1779     /* The option flags */
1780     case SO_BROADCAST:
1781     /* UNIMPL case SO_DEBUG: */
1782     /* UNIMPL case SO_DONTROUTE: */
1783     case SO_KEEPALIVE:
1784     /* UNIMPL case SO_OOBINCLUDE: */
1785 #if SO_REUSE
1786     case SO_REUSEADDR:
1787     case SO_REUSEPORT:
1788 #endif /* SO_REUSE */
1789     /* UNIMPL case SO_USELOOPBACK: */
1790       if (*(int*)optval) {
1791         sock->conn->pcb.ip->so_options |= optname;
1792       } else {
1793         sock->conn->pcb.ip->so_options &= ~optname;
1794       }
1795       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, SOL_SOCKET, optname=0x%x, ..) -> %s\n",
1796                   s, optname, (*(int*)optval?"on":"off")));
1797       break;
1798 #if LWIP_SO_RCVTIMEO
1799     case SO_RCVTIMEO:
1800       sock->conn->recv_timeout = ( *(int*)optval );
1801       break;
1802 #endif /* LWIP_SO_RCVTIMEO */
1803 #if LWIP_SO_RCVBUF
1804     case SO_RCVBUF:
1805       sock->conn->recv_bufsize = ( *(int*)optval );
1806       break;
1807 #endif /* LWIP_SO_RCVBUF */
1808 #if LWIP_UDP
1809     case SO_NO_CHECK:
1810       if (*(int*)optval) {
1811         udp_setflags(sock->conn->pcb.udp, udp_flags(sock->conn->pcb.udp) | UDP_FLAGS_NOCHKSUM);
1812       } else {
1813         udp_setflags(sock->conn->pcb.udp, udp_flags(sock->conn->pcb.udp) & ~UDP_FLAGS_NOCHKSUM);
1814       }
1815       break;
1816 #endif /* LWIP_UDP */
1817     }  /* switch (optname) */
1818     break;
1819
1820 /* Level: IPPROTO_IP */
1821   case IPPROTO_IP:
1822     switch (optname) {
1823     case IP_TTL:
1824       sock->conn->pcb.ip->ttl = (u8_t)(*(int*)optval);
1825       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IP, IP_TTL, ..) -> %d\n",
1826                   s, sock->conn->pcb.ip->ttl));
1827       break;
1828     case IP_TOS:
1829       sock->conn->pcb.ip->tos = (u8_t)(*(int*)optval);
1830       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IP, IP_TOS, ..)-> %d\n",
1831                   s, sock->conn->pcb.ip->tos));
1832       break;
1833 #if LWIP_IGMP
1834     case IP_MULTICAST_TTL:
1835       sock->conn->pcb.udp->ttl = (u8_t)(*(u8_t*)optval);
1836       break;
1837     case IP_MULTICAST_IF:
1838       sock->conn->pcb.udp->multicast_ip.addr = ((struct in_addr*) optval)->s_addr;
1839       break;
1840     case IP_ADD_MEMBERSHIP:
1841     case IP_DROP_MEMBERSHIP:
1842       {
1843         /* If this is a TCP or a RAW socket, ignore these options. */
1844         struct ip_mreq *imr = (struct ip_mreq *)optval;
1845         if(optname == IP_ADD_MEMBERSHIP){
1846           data->err = igmp_joingroup((struct ip_addr*)&(imr->imr_interface.s_addr), (struct ip_addr*)&(imr->imr_multiaddr.s_addr));
1847         } else {
1848           data->err = igmp_leavegroup((struct ip_addr*)&(imr->imr_interface.s_addr), (struct ip_addr*)&(imr->imr_multiaddr.s_addr));
1849         }
1850         if(data->err != ERR_OK) {
1851           data->err = EADDRNOTAVAIL;
1852         }
1853       }
1854       break;
1855 #endif /* LWIP_IGMP */
1856     }  /* switch (optname) */
1857     break;
1858
1859 #if LWIP_TCP
1860 /* Level: IPPROTO_TCP */
1861   case IPPROTO_TCP:
1862     switch (optname) {
1863     case TCP_NODELAY:
1864       if (*(int*)optval) {
1865         tcp_nagle_disable(sock->conn->pcb.tcp);
1866       } else {
1867         tcp_nagle_enable(sock->conn->pcb.tcp);
1868       }
1869       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_NODELAY) -> %s\n",
1870                   s, (*(int *)optval)?"on":"off") );
1871       break;
1872     case TCP_KEEPALIVE:
1873       sock->conn->pcb.tcp->keep_idle = (u32_t)(*(int*)optval);
1874       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPALIVE) -> %"U32_F"\n",
1875                   s, sock->conn->pcb.tcp->keep_idle));
1876       break;
1877
1878 #if LWIP_TCP_KEEPALIVE
1879     case TCP_KEEPIDLE:
1880       sock->conn->pcb.tcp->keep_idle = 1000*(u32_t)(*(int*)optval);
1881       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPIDLE) -> %"U32_F"\n",
1882                   s, sock->conn->pcb.tcp->keep_idle));
1883       break;
1884     case TCP_KEEPINTVL:
1885       sock->conn->pcb.tcp->keep_intvl = 1000*(u32_t)(*(int*)optval);
1886       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPINTVL) -> %"U32_F"\n",
1887                   s, sock->conn->pcb.tcp->keep_intvl));
1888       break;
1889     case TCP_KEEPCNT:
1890       sock->conn->pcb.tcp->keep_cnt = (u32_t)(*(int*)optval);
1891       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPCNT) -> %"U32_F"\n",
1892                   s, sock->conn->pcb.tcp->keep_cnt));
1893       break;
1894 #endif /* LWIP_TCP_KEEPALIVE */
1895
1896     }  /* switch (optname) */
1897     break;
1898 #endif /* LWIP_TCP*/
1899 #if LWIP_UDP && LWIP_UDPLITE
1900   /* Level: IPPROTO_UDPLITE */
1901   case IPPROTO_UDPLITE:
1902     switch (optname) {
1903     case UDPLITE_SEND_CSCOV:
1904       if ((*(int*)optval != 0) && (*(int*)optval < 8)) {
1905         /* don't allow illegal values! */
1906         sock->conn->pcb.udp->chksum_len_tx = 8;
1907       } else {
1908         sock->conn->pcb.udp->chksum_len_tx = *(int*)optval;
1909       }
1910       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_UDPLITE, UDPLITE_SEND_CSCOV) -> %d\n",
1911                   s, (*(int*)optval)) );
1912       break;
1913     case UDPLITE_RECV_CSCOV:
1914       if ((*(int*)optval != 0) && (*(int*)optval < 8)) {
1915         /* don't allow illegal values! */
1916         sock->conn->pcb.udp->chksum_len_rx = 8;
1917       } else {
1918         sock->conn->pcb.udp->chksum_len_rx = *(int*)optval;
1919       }
1920       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_UDPLITE, UDPLITE_RECV_CSCOV) -> %d\n",
1921                   s, (*(int*)optval)) );
1922       break;
1923     }  /* switch (optname) */
1924     break;
1925 #endif /* LWIP_UDP */
1926   }  /* switch (level) */
1927   sys_sem_signal(sock->conn->op_completed);
1928 }
1929
1930 int
1931 lwip_ioctl(int s, long cmd, void *argp)
1932 {
1933   struct lwip_socket *sock = get_socket(s);
1934   u16_t buflen = 0;
1935   s16_t recv_avail;
1936
1937   if (!sock)
1938     return -1;
1939
1940   switch (cmd) {
1941   case FIONREAD:
1942     if (!argp) {
1943       sock_set_errno(sock, EINVAL);
1944       return -1;
1945     }
1946
1947     SYS_ARCH_GET(sock->conn->recv_avail, recv_avail);
1948     if (recv_avail < 0)
1949       recv_avail = 0;
1950     *((u16_t*)argp) = (u16_t)recv_avail;
1951
1952     /* Check if there is data left from the last recv operation. /maq 041215 */
1953     if (sock->lastdata) {
1954       buflen = netbuf_len(sock->lastdata);
1955       buflen -= sock->lastoffset;
1956
1957       *((u16_t*)argp) += buflen;
1958     }
1959
1960     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(%d, FIONREAD, %p) = %"U16_F"\n", s, argp, *((u16_t*)argp)));
1961     sock_set_errno(sock, 0);
1962     return 0;
1963
1964   case FIONBIO:
1965     if (argp && *(u32_t*)argp)
1966       sock->flags |= O_NONBLOCK;
1967     else
1968       sock->flags &= ~O_NONBLOCK;
1969     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(%d, FIONBIO, %d)\n", s, !!(sock->flags & O_NONBLOCK)));
1970     sock_set_errno(sock, 0);
1971     return 0;
1972
1973   default:
1974     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(%d, UNIMPL: 0x%lx, %p)\n", s, cmd, argp));
1975     sock_set_errno(sock, ENOSYS); /* not yet implemented */
1976     return -1;
1977   } /* switch (cmd) */
1978 }
1979
1980 #endif /* LWIP_SOCKET */