Palacios Public Git Repository

To checkout Palacios execute

  git clone http://v3vee.org/palacios/palacios.web/palacios.git
This will give you the master branch. You probably want the devel branch or one of the release branches. To switch to the devel branch, simply execute
  cd palacios
  git checkout --track -b devel origin/devel
The other branches are similar.


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