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.


added lwip
[palacios.git] / palacios / 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 <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   u16_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   EHOSTUNREACH,  /* ERR_RTE        -3      Routing problem.         */
132   ECONNABORTED,  /* ERR_ABRT       -4      Connection aborted.      */
133   ECONNRESET,    /* ERR_RST        -5      Connection reset.        */
134   ESHUTDOWN,     /* ERR_CLSD       -6      Connection closed.       */
135   ENOTCONN,      /* ERR_CONN       -7      Not connected.           */
136   EINVAL,        /* ERR_VAL        -8      Illegal value.           */
137   EIO,           /* ERR_ARG        -9      Illegal argument.        */
138   EADDRINUSE,    /* ERR_USE        -10     Address in use.          */
139   -1,            /* ERR_IF         -11     Low-level netif error    */
140   -1,            /* ERR_ISCONN     -12     Already connected.       */
141   ETIMEDOUT,     /* ERR_TIMEOUT    -13     Timeout                  */
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 #define set_errno(err) errno = (err)
154 #else
155 #define set_errno(err)
156 #endif
157
158 #define sock_set_errno(sk, e) do { \
159   sk->err = (e); \
160   set_errno(sk->err); \
161 } while (0)
162
163 /* Forward delcaration of some functions */
164 static void event_callback(struct netconn *conn, enum netconn_evt evt, u16_t len);
165 static void lwip_getsockopt_internal(void *arg);
166 static void lwip_setsockopt_internal(void *arg);
167
168 /**
169  * Initialize this module. This function has to be called before any other
170  * functions in this module!
171  */
172 void
173 lwip_socket_init(void)
174 {
175   socksem   = sys_sem_new(1);
176   selectsem = sys_sem_new(1);
177 }
178
179 /**
180  * Map a externally used socket index to the internal socket representation.
181  *
182  * @param s externally used socket index
183  * @return struct lwip_socket for the socket or NULL if not found
184  */
185 static struct lwip_socket *
186 get_socket(int s)
187 {
188   struct lwip_socket *sock;
189
190   if ((s < 0) || (s >= NUM_SOCKETS)) {
191     LWIP_DEBUGF(SOCKETS_DEBUG, ("get_socket(%d): invalid\n", s));
192     set_errno(EBADF);
193     return NULL;
194   }
195
196   sock = &sockets[s];
197
198   if (!sock->conn) {
199     LWIP_DEBUGF(SOCKETS_DEBUG, ("get_socket(%d): not active\n", s));
200     set_errno(EBADF);
201     return NULL;
202   }
203
204   return sock;
205 }
206
207 /**
208  * Allocate a new socket for a given netconn.
209  *
210  * @param newconn the netconn for which to allocate a socket
211  * @return the index of the new socket; -1 on error
212  */
213 static int
214 alloc_socket(struct netconn *newconn)
215 {
216   int i;
217
218   /* Protect socket array */
219   sys_sem_wait(socksem);
220
221   /* allocate a new socket identifier */
222   for (i = 0; i < NUM_SOCKETS; ++i) {
223     if (!sockets[i].conn) {
224       sockets[i].conn       = newconn;
225       sockets[i].lastdata   = NULL;
226       sockets[i].lastoffset = 0;
227       sockets[i].rcvevent   = 0;
228       sockets[i].sendevent  = 1; /* TCP send buf is empty */
229       sockets[i].flags      = 0;
230       sockets[i].err        = 0;
231       sys_sem_signal(socksem);
232       return i;
233     }
234   }
235   sys_sem_signal(socksem);
236   return -1;
237 }
238
239 /* Below this, the well-known socket functions are implemented.
240  * Use google.com or opengroup.org to get a good description :-)
241  *
242  * Exceptions are documented!
243  */
244
245 int
246 lwip_accept(int s, struct sockaddr *addr, socklen_t *addrlen)
247 {
248   struct lwip_socket *sock, *nsock;
249   struct netconn *newconn;
250   struct ip_addr naddr;
251   u16_t port;
252   int newsock;
253   struct sockaddr_in sin;
254   err_t err;
255
256   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d)...\n", s));
257   sock = get_socket(s);
258   if (!sock)
259     return -1;
260
261   newconn = netconn_accept(sock->conn);
262   if (!newconn) {
263     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d) failed, err=%d\n", s, sock->conn->err));
264     sock_set_errno(sock, err_to_errno(sock->conn->err));
265     return -1;
266   }
267
268   /* get the IP address and port of the remote host */
269   err = netconn_peer(newconn, &naddr, &port);
270   if (err != ERR_OK) {
271     netconn_delete(newconn);
272     sock_set_errno(sock, err_to_errno(err));
273     return -1;
274   }
275
276   memset(&sin, 0, sizeof(sin));
277   sin.sin_len = sizeof(sin);
278   sin.sin_family = AF_INET;
279   sin.sin_port = htons(port);
280   sin.sin_addr.s_addr = naddr.addr;
281
282   if (*addrlen > sizeof(sin))
283     *addrlen = sizeof(sin);
284
285   SMEMCPY(addr, &sin, *addrlen);
286
287   newsock = alloc_socket(newconn);
288   if (newsock == -1) {
289     netconn_delete(newconn);
290     sock_set_errno(sock, ENFILE);
291     return -1;
292   }
293   LWIP_ASSERT("invalid socket index", (newsock >= 0) && (newsock < NUM_SOCKETS));
294   newconn->callback = event_callback;
295   nsock = &sockets[newsock];
296   LWIP_ASSERT("invalid socket pointer", nsock != NULL);
297
298   sys_sem_wait(socksem);
299   /* See event_callback: If data comes in right away after an accept, even
300    * though the server task might not have created a new socket yet.
301    * In that case, newconn->socket is counted down (newconn->socket--),
302    * so nsock->rcvevent is >= 1 here!
303    */
304   nsock->rcvevent += -1 - newconn->socket;
305   newconn->socket = newsock;
306   sys_sem_signal(socksem);
307
308   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d) returning new sock=%d addr=", s, newsock));
309   ip_addr_debug_print(SOCKETS_DEBUG, &naddr);
310   LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%u\n", port));
311
312   sock_set_errno(sock, 0);
313   return newsock;
314 }
315
316 int
317 lwip_bind(int s, struct sockaddr *name, socklen_t namelen)
318 {
319   struct lwip_socket *sock;
320   struct ip_addr local_addr;
321   u16_t local_port;
322   err_t err;
323
324   sock = get_socket(s);
325   if (!sock)
326     return -1;
327
328   LWIP_ERROR("lwip_bind: invalid address", ((namelen == sizeof(struct sockaddr_in)) &&
329              ((((struct sockaddr_in *)name)->sin_family) == AF_INET)),
330              sock_set_errno(sock, err_to_errno(ERR_ARG)); return -1;);
331
332   local_addr.addr = ((struct sockaddr_in *)name)->sin_addr.s_addr;
333   local_port = ((struct sockaddr_in *)name)->sin_port;
334
335   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d, addr=", s));
336   ip_addr_debug_print(SOCKETS_DEBUG, &local_addr);
337   LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%u)\n", ntohs(local_port)));
338
339   err = netconn_bind(sock->conn, &local_addr, ntohs(local_port));
340
341   if (err != ERR_OK) {
342     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d) failed, err=%d\n", s, err));
343     sock_set_errno(sock, err_to_errno(err));
344     return -1;
345   }
346
347   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d) succeeded\n", s));
348   sock_set_errno(sock, 0);
349   return 0;
350 }
351
352 int
353 lwip_close(int s)
354 {
355   struct lwip_socket *sock;
356
357   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_close(%d)\n", s));
358
359   sock = get_socket(s);
360   if (!sock) {
361     return -1;
362   }
363
364   netconn_delete(sock->conn);
365
366   sys_sem_wait(socksem);
367   if (sock->lastdata) {
368     netbuf_delete(sock->lastdata);
369   }
370   sock->lastdata   = NULL;
371   sock->lastoffset = 0;
372   sock->conn       = NULL;
373   sock_set_errno(sock, 0);
374   sys_sem_signal(socksem);
375   return 0;
376 }
377
378 int
379 lwip_connect(int s, const struct sockaddr *name, socklen_t namelen)
380 {
381   struct lwip_socket *sock;
382   err_t err;
383
384   sock = get_socket(s);
385   if (!sock)
386     return -1;
387
388   LWIP_ERROR("lwip_connect: invalid address", ((namelen == sizeof(struct sockaddr_in)) &&
389              ((((struct sockaddr_in *)name)->sin_family) == AF_INET)),
390              sock_set_errno(sock, err_to_errno(ERR_ARG)); return -1;);
391
392   if (((struct sockaddr_in *)name)->sin_family == AF_UNSPEC) {
393     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d, AF_UNSPEC)\n", s));
394     err = netconn_disconnect(sock->conn);
395   } else {
396     struct ip_addr remote_addr;
397     u16_t remote_port;
398
399     remote_addr.addr = ((struct sockaddr_in *)name)->sin_addr.s_addr;
400     remote_port = ((struct sockaddr_in *)name)->sin_port;
401
402     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d, addr=", s));
403     ip_addr_debug_print(SOCKETS_DEBUG, &remote_addr);
404     LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%u)\n", ntohs(remote_port)));
405
406     err = netconn_connect(sock->conn, &remote_addr, ntohs(remote_port));
407   }
408
409   if (err != ERR_OK) {
410     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d) failed, err=%d\n", s, err));
411     sock_set_errno(sock, err_to_errno(err));
412     return -1;
413   }
414
415   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d) succeeded\n", s));
416   sock_set_errno(sock, 0);
417   return 0;
418 }
419
420 /**
421  * Set a socket into listen mode.
422  * The socket may not have been used for another connection previously.
423  *
424  * @param s the socket to set to listening mode
425  * @param backlog (ATTENTION: need TCP_LISTEN_BACKLOG=1)
426  * @return 0 on success, non-zero on failure
427  */
428 int
429 lwip_listen(int s, int backlog)
430 {
431   struct lwip_socket *sock;
432   err_t err;
433
434   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_listen(%d, backlog=%d)\n", s, backlog));
435
436   sock = get_socket(s);
437   if (!sock)
438     return -1;
439
440   /* limit the "backlog" parameter to fit in an u8_t */
441   if (backlog < 0) {
442     backlog = 0;
443   }
444   if (backlog > 0xff) {
445     backlog = 0xff;
446   }
447
448   err = netconn_listen_with_backlog(sock->conn, backlog);
449
450   if (err != ERR_OK) {
451     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_listen(%d) failed, err=%d\n", s, err));
452     sock_set_errno(sock, err_to_errno(err));
453     return -1;
454   }
455
456   sock_set_errno(sock, 0);
457   return 0;
458 }
459
460 int
461 lwip_recvfrom(int s, void *mem, int len, unsigned int flags,
462         struct sockaddr *from, socklen_t *fromlen)
463 {
464   struct lwip_socket *sock;
465   struct netbuf      *buf;
466   u16_t               buflen, copylen, off = 0;
467   struct ip_addr     *addr;
468   u16_t               port;
469   u8_t                done = 0;
470
471   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d, %p, %d, 0x%x, ..)\n", s, mem, len, flags));
472   sock = get_socket(s);
473   if (!sock)
474     return -1;
475
476   do {
477     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: top while sock->lastdata=%p\n", (void*)sock->lastdata));
478     /* Check if there is data left from the last recv operation. */
479     if (sock->lastdata) {
480       buf = sock->lastdata;
481     } else {
482       /* If this is non-blocking call, then check first */
483       if (((flags & MSG_DONTWAIT) || (sock->flags & O_NONBLOCK)) && !sock->rcvevent) {
484         LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): returning EWOULDBLOCK\n", s));
485         sock_set_errno(sock, EWOULDBLOCK);
486         return -1;
487       }
488
489       /* No data was left from the previous operation, so we try to get
490       some from the network. */
491       sock->lastdata = buf = netconn_recv(sock->conn);
492       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: netconn_recv netbuf=%p\n", (void*)buf));
493
494       if (!buf) {
495         /* We should really do some error checking here. */
496         LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): buf == NULL!\n", s));
497         sock_set_errno(sock, (((sock->conn->pcb.ip!=NULL) && (sock->conn->err==ERR_OK))?ETIMEDOUT:err_to_errno(sock->conn->err)));
498         return 0;
499       }
500     }
501
502     buflen = netbuf_len(buf);
503     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: buflen=%d len=%d off=%d sock->lastoffset=%d\n", buflen, len, off, sock->lastoffset));
504
505     buflen -= sock->lastoffset;
506
507     if (len > buflen) {
508       copylen = buflen;
509     } else {
510       copylen = len;
511     }
512
513     /* copy the contents of the received buffer into
514     the supplied memory pointer mem */
515     netbuf_copy_partial(buf, (u8_t*)mem + off, copylen, sock->lastoffset);
516
517     off += copylen;
518
519     if (netconn_type(sock->conn) == NETCONN_TCP) {
520       len -= copylen;
521       if ( (len <= 0) || (buf->p->flags & PBUF_FLAG_PUSH) || !sock->rcvevent) {
522         done = 1;
523       }
524     } else {
525       done = 1;
526     }
527
528     /* If we don't peek the incoming message... */
529     if ((flags & MSG_PEEK)==0) {
530       /* If this is a TCP socket, check if there is data left in the
531          buffer. If so, it should be saved in the sock structure for next
532          time around. */
533       if ((sock->conn->type == NETCONN_TCP) && (buflen - copylen > 0)) {
534         sock->lastdata = buf;
535         sock->lastoffset += copylen;
536         LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: lastdata now netbuf=%p\n", (void*)buf));
537       } else {
538         sock->lastdata = NULL;
539         sock->lastoffset = 0;
540         LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: deleting netbuf=%p\n", (void*)buf));
541         netbuf_delete(buf);
542       }
543     } else {
544       done = 1;
545     }
546   } while (!done);
547
548   /* Check to see from where the data was.*/
549   if (from && fromlen) {
550     struct sockaddr_in sin;
551
552     if (netconn_type(sock->conn) == NETCONN_TCP) {
553       addr = (struct ip_addr*)&(sin.sin_addr.s_addr);
554       netconn_getaddr(sock->conn, addr, &port, 0);
555     } else {
556       addr = netbuf_fromaddr(buf);
557       port = netbuf_fromport(buf);
558     }
559
560     memset(&sin, 0, sizeof(sin));
561     sin.sin_len = sizeof(sin);
562     sin.sin_family = AF_INET;
563     sin.sin_port = htons(port);
564     sin.sin_addr.s_addr = addr->addr;
565
566     if (*fromlen > sizeof(sin))
567       *fromlen = sizeof(sin);
568
569     SMEMCPY(from, &sin, *fromlen);
570
571     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): addr=", s));
572     ip_addr_debug_print(SOCKETS_DEBUG, addr);
573     LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%u len=%u\n", port, off));
574   } else {
575 #if SOCKETS_DEBUG
576     struct sockaddr_in sin;
577
578     if (netconn_type(sock->conn) == NETCONN_TCP) {
579       addr = (struct ip_addr*)&(sin.sin_addr.s_addr);
580       netconn_getaddr(sock->conn, addr, &port, 0);
581     } else {
582       addr = netbuf_fromaddr(buf);
583       port = netbuf_fromport(buf);
584     }
585
586     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): addr=", s));
587     ip_addr_debug_print(SOCKETS_DEBUG, addr);
588     LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%u len=%u\n", port, off));
589 #endif /*  SOCKETS_DEBUG */
590   }
591
592   sock_set_errno(sock, 0);
593   return off;
594 }
595
596 int
597 lwip_read(int s, void *mem, int len)
598 {
599   return lwip_recvfrom(s, mem, len, 0, NULL, NULL);
600 }
601
602 int
603 lwip_recv(int s, void *mem, int len, unsigned int flags)
604 {
605   return lwip_recvfrom(s, mem, len, flags, NULL, NULL);
606 }
607
608 int
609 lwip_send(int s, const void *data, int size, unsigned int flags)
610 {
611   struct lwip_socket *sock;
612   err_t err;
613
614   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_send(%d, data=%p, size=%d, flags=0x%x)\n",
615                               s, data, size, flags));
616
617   sock = get_socket(s);
618   if (!sock)
619     return -1;
620
621   if (sock->conn->type!=NETCONN_TCP) {
622 #if (LWIP_UDP || LWIP_RAW)
623     return lwip_sendto(s, data, size, flags, NULL, 0);
624 #else
625     sock_set_errno(sock, err_to_errno(ERR_ARG));
626     return -1;
627 #endif /* (LWIP_UDP || LWIP_RAW) */
628   }
629
630   err = netconn_write(sock->conn, data, size, NETCONN_COPY | ((flags & MSG_MORE)?NETCONN_MORE:0));
631
632   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_send(%d) err=%d size=%d\n", s, err, size));
633   sock_set_errno(sock, err_to_errno(err));
634   return (err==ERR_OK?size:-1);
635 }
636
637 int
638 lwip_sendto(int s, const void *data, int size, unsigned int flags,
639        struct sockaddr *to, socklen_t tolen)
640 {
641   struct lwip_socket *sock;
642   struct ip_addr remote_addr;
643   int err;
644 #if !LWIP_TCPIP_CORE_LOCKING
645   struct netbuf buf;
646   u16_t remote_port;
647 #endif
648
649   sock = get_socket(s);
650   if (!sock)
651     return -1;
652
653   if (sock->conn->type==NETCONN_TCP) {
654 #if LWIP_TCP
655     return lwip_send(s, data, size, flags);
656 #else
657     sock_set_errno(sock, err_to_errno(ERR_ARG));
658     return -1;
659 #endif /* LWIP_TCP */
660   }
661
662   LWIP_ASSERT("lwip_sendto: size must fit in u16_t",
663               ((size >= 0) && (size <= 0xffff)));
664   LWIP_ERROR("lwip_sendto: invalid address", (((to == NULL) && (tolen == 0)) ||
665              ((tolen == sizeof(struct sockaddr_in)) &&
666              ((((struct sockaddr_in *)to)->sin_family) == AF_INET))),
667              sock_set_errno(sock, err_to_errno(ERR_ARG)); return -1;);
668
669 #if LWIP_TCPIP_CORE_LOCKING
670   /* Should only be consider like a sample or a simple way to experiment this option (no check of "to" field...) */
671   { struct pbuf* p;
672   
673     p = pbuf_alloc(PBUF_TRANSPORT, 0, PBUF_REF);
674     if (p == NULL) {
675       err = ERR_MEM;
676     } else {
677       p->payload = (void*)data;
678       p->len = p->tot_len = size;
679       
680       remote_addr.addr = ((struct sockaddr_in *)to)->sin_addr.s_addr;
681       
682       LOCK_TCPIP_CORE();
683       if (sock->conn->type==NETCONN_RAW) {
684         err = sock->conn->err = raw_sendto(sock->conn->pcb.raw, p, &remote_addr);
685       } else {
686         err = sock->conn->err = udp_sendto(sock->conn->pcb.udp, p, &remote_addr, ntohs(((struct sockaddr_in *)to)->sin_port));
687       }
688       UNLOCK_TCPIP_CORE();
689       
690       pbuf_free(p);
691     }
692   }
693 #else
694   /* initialize a buffer */
695   buf.p = buf.ptr = NULL;
696   if (to) {
697     remote_addr.addr = ((struct sockaddr_in *)to)->sin_addr.s_addr;
698     remote_port      = ntohs(((struct sockaddr_in *)to)->sin_port);
699     buf.addr         = &remote_addr;
700     buf.port         = remote_port;
701   } else {
702     remote_addr.addr = 0;
703     remote_port      = 0;
704     buf.addr         = NULL;
705     buf.port         = 0;
706   }
707
708   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_sendto(%d, data=%p, size=%d, flags=0x%x to=",
709               s, data, size, flags));
710   ip_addr_debug_print(SOCKETS_DEBUG, &remote_addr);
711   LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%u\n", remote_port));
712     
713   /* make the buffer point to the data that should be sent */
714   if ((err = netbuf_ref(&buf, data, size)) == ERR_OK) {
715     /* send the data */
716     err = netconn_send(sock->conn, &buf);
717   }
718
719   /* deallocated the buffer */
720   if (buf.p != NULL) {
721     pbuf_free(buf.p);
722   }
723 #endif /* LWIP_TCPIP_CORE_LOCKING */
724   sock_set_errno(sock, err_to_errno(err));
725   return (err==ERR_OK?size:-1);
726 }
727
728 int
729 lwip_socket(int domain, int type, int protocol)
730 {
731   struct netconn *conn;
732   int i;
733
734   LWIP_UNUSED_ARG(domain);
735
736   /* create a netconn */
737   switch (type) {
738   case SOCK_RAW:
739     conn = netconn_new_with_proto_and_callback(NETCONN_RAW, (u8_t)protocol, event_callback);
740     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_RAW, %d) = ",
741                                  domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol));
742     break;
743   case SOCK_DGRAM:
744     conn = netconn_new_with_callback( (protocol == IPPROTO_UDPLITE) ?
745                  NETCONN_UDPLITE : NETCONN_UDP, event_callback);
746     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_DGRAM, %d) = ",
747                                  domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol));
748     break;
749   case SOCK_STREAM:
750     conn = netconn_new_with_callback(NETCONN_TCP, event_callback);
751     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_STREAM, %d) = ",
752                                  domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol));
753     break;
754   default:
755     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%d, %d/UNKNOWN, %d) = -1\n",
756                                  domain, type, protocol));
757     set_errno(EINVAL);
758     return -1;
759   }
760
761   if (!conn) {
762     LWIP_DEBUGF(SOCKETS_DEBUG, ("-1 / ENOBUFS (could not create netconn)\n"));
763     set_errno(ENOBUFS);
764     return -1;
765   }
766
767   i = alloc_socket(conn);
768
769   if (i == -1) {
770     netconn_delete(conn);
771     set_errno(ENFILE);
772     return -1;
773   }
774   conn->socket = i;
775   LWIP_DEBUGF(SOCKETS_DEBUG, ("%d\n", i));
776   set_errno(0);
777   return i;
778 }
779
780 int
781 lwip_write(int s, const void *data, int size)
782 {
783   return lwip_send(s, data, size, 0);
784 }
785
786 /**
787  * Go through the readset and writeset lists and see which socket of the sockets
788  * set in the sets has events. On return, readset, writeset and exceptset have
789  * the sockets enabled that had events.
790  *
791  * exceptset is not used for now!!!
792  *
793  * @param maxfdp1 the highest socket index in the sets
794  * @param readset in: set of sockets to check for read events;
795  *                out: set of sockets that had read events
796  * @param writeset in: set of sockets to check for write events;
797  *                 out: set of sockets that had write events
798  * @param exceptset not yet implemented
799  * @return number of sockets that had events (read+write)
800  */
801 static int
802 lwip_selscan(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset)
803 {
804   int i, nready = 0;
805   fd_set lreadset, lwriteset, lexceptset;
806   struct lwip_socket *p_sock;
807   
808   FD_ZERO(&lreadset);
809   FD_ZERO(&lwriteset);
810   FD_ZERO(&lexceptset);
811   
812   /* Go through each socket in each list to count number of sockets which
813   currently match */
814   for(i = 0; i < maxfdp1; i++) {
815     if (FD_ISSET(i, readset)) {
816       /* See if netconn of this socket is ready for read */
817       p_sock = get_socket(i);
818       if (p_sock && (p_sock->lastdata || p_sock->rcvevent)) {
819         FD_SET(i, &lreadset);
820         LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_selscan: fd=%d ready for reading\n", i));
821         nready++;
822       }
823     }
824     if (FD_ISSET(i, writeset)) {
825       /* See if netconn of this socket is ready for write */
826       p_sock = get_socket(i);
827       if (p_sock && p_sock->sendevent) {
828         FD_SET(i, &lwriteset);
829         LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_selscan: fd=%d ready for writing\n", i));
830         nready++;
831       }
832     }
833   }
834   *readset = lreadset;
835   *writeset = lwriteset;
836   FD_ZERO(exceptset);
837   
838   return nready;
839 }
840
841
842 /**
843  * Processing exceptset is not yet implemented.
844  */
845 int
846 lwip_select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset,
847                struct timeval *timeout)
848 {
849   int i;
850   int nready;
851   fd_set lreadset, lwriteset, lexceptset;
852   u32_t msectimeout;
853   struct lwip_select_cb select_cb;
854   struct lwip_select_cb *p_selcb;
855
856   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select(%d, %p, %p, %p, tvsec=%ld tvusec=%ld)\n",
857                   maxfdp1, (void *)readset, (void *) writeset, (void *) exceptset,
858                   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 */