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.


Add lwip files, for test, not compilable version
[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 "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",
859                   maxfdp1, (void *)readset, (void *) writeset, (void *) exceptset,
860                   timeout ? timeout->tv_sec : -1L, timeout ? timeout->tv_usec : -1L));
861
862   select_cb.next = 0;
863   select_cb.readset = readset;
864   select_cb.writeset = writeset;
865   select_cb.exceptset = exceptset;
866   select_cb.sem_signalled = 0;
867
868   /* Protect ourselves searching through the list */
869   sys_sem_wait(selectsem);
870
871   if (readset)
872     lreadset = *readset;
873   else
874     FD_ZERO(&lreadset);
875   if (writeset)
876     lwriteset = *writeset;
877   else
878     FD_ZERO(&lwriteset);
879   if (exceptset)
880     lexceptset = *exceptset;
881   else
882     FD_ZERO(&lexceptset);
883
884   /* Go through each socket in each list to count number of sockets which
885      currently match */
886   nready = lwip_selscan(maxfdp1, &lreadset, &lwriteset, &lexceptset);
887
888   /* If we don't have any current events, then suspend if we are supposed to */
889   if (!nready) {
890     if (timeout && timeout->tv_sec == 0 && timeout->tv_usec == 0) {
891       sys_sem_signal(selectsem);
892       if (readset)
893         FD_ZERO(readset);
894       if (writeset)
895         FD_ZERO(writeset);
896       if (exceptset)
897         FD_ZERO(exceptset);
898   
899       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select: no timeout, returning 0\n"));
900       set_errno(0);
901   
902       return 0;
903     }
904     
905     /* add our semaphore to list */
906     /* We don't actually need any dynamic memory. Our entry on the
907      * list is only valid while we are in this function, so it's ok
908      * to use local variables */
909     
910     select_cb.sem = sys_sem_new(0);
911     /* Note that we are still protected */
912     /* Put this select_cb on top of list */
913     select_cb.next = select_cb_list;
914     select_cb_list = &select_cb;
915     
916     /* Now we can safely unprotect */
917     sys_sem_signal(selectsem);
918     
919     /* Now just wait to be woken */
920     if (timeout == 0)
921       /* Wait forever */
922       msectimeout = 0;
923     else {
924       msectimeout =  ((timeout->tv_sec * 1000) + ((timeout->tv_usec + 500)/1000));
925       if(msectimeout == 0)
926         msectimeout = 1;
927     }
928     
929     i = sys_sem_wait_timeout(select_cb.sem, msectimeout);
930     
931     /* Take us off the list */
932     sys_sem_wait(selectsem);
933     if (select_cb_list == &select_cb)
934       select_cb_list = select_cb.next;
935     else
936       for (p_selcb = select_cb_list; p_selcb; p_selcb = p_selcb->next) {
937         if (p_selcb->next == &select_cb) {
938           p_selcb->next = select_cb.next;
939           break;
940         }
941       }
942     
943     sys_sem_signal(selectsem);
944     
945     sys_sem_free(select_cb.sem);
946     if (i == 0)  {
947       /* Timeout */
948       if (readset)
949         FD_ZERO(readset);
950       if (writeset)
951         FD_ZERO(writeset);
952       if (exceptset)
953         FD_ZERO(exceptset);
954   
955       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select: timeout expired\n"));
956       set_errno(0);
957   
958       return 0;
959     }
960     
961     if (readset)
962       lreadset = *readset;
963     else
964       FD_ZERO(&lreadset);
965     if (writeset)
966       lwriteset = *writeset;
967     else
968       FD_ZERO(&lwriteset);
969     if (exceptset)
970       lexceptset = *exceptset;
971     else
972       FD_ZERO(&lexceptset);
973     
974     /* See what's set */
975     nready = lwip_selscan(maxfdp1, &lreadset, &lwriteset, &lexceptset);
976   } else
977     sys_sem_signal(selectsem);
978   
979   if (readset)
980     *readset = lreadset;
981   if (writeset)
982     *writeset = lwriteset;
983   if (exceptset)
984     *exceptset = lexceptset;
985   
986   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select: nready=%d\n", nready));
987   set_errno(0);
988   
989   return nready;
990 }
991
992 /**
993  * Callback registered in the netconn layer for each socket-netconn.
994  * Processes recvevent (data available) and wakes up tasks waiting for select.
995  */
996 static void
997 event_callback(struct netconn *conn, enum netconn_evt evt, u16_t len)
998 {
999   int s;
1000   struct lwip_socket *sock;
1001   struct lwip_select_cb *scb;
1002
1003   LWIP_UNUSED_ARG(len);
1004
1005   /* Get socket */
1006   if (conn) {
1007     s = conn->socket;
1008     if (s < 0) {
1009       /* Data comes in right away after an accept, even though
1010        * the server task might not have created a new socket yet.
1011        * Just count down (or up) if that's the case and we
1012        * will use the data later. Note that only receive events
1013        * can happen before the new socket is set up. */
1014       sys_sem_wait(socksem);
1015       if (conn->socket < 0) {
1016         if (evt == NETCONN_EVT_RCVPLUS) {
1017           conn->socket--;
1018         }
1019         sys_sem_signal(socksem);
1020         return;
1021       }
1022       sys_sem_signal(socksem);
1023     }
1024
1025     sock = get_socket(s);
1026     if (!sock) {
1027       return;
1028     }
1029   } else {
1030     return;
1031   }
1032
1033   sys_sem_wait(selectsem);
1034   /* Set event as required */
1035   switch (evt) {
1036     case NETCONN_EVT_RCVPLUS:
1037       sock->rcvevent++;
1038       break;
1039     case NETCONN_EVT_RCVMINUS:
1040       sock->rcvevent--;
1041       break;
1042     case NETCONN_EVT_SENDPLUS:
1043       sock->sendevent = 1;
1044       break;
1045     case NETCONN_EVT_SENDMINUS:
1046       sock->sendevent = 0;
1047       break;
1048     default:
1049       LWIP_ASSERT("unknown event", 0);
1050       break;
1051   }
1052   sys_sem_signal(selectsem);
1053
1054   /* Now decide if anyone is waiting for this socket */
1055   /* NOTE: This code is written this way to protect the select link list
1056      but to avoid a deadlock situation by releasing socksem before
1057      signalling for the select. This means we need to go through the list
1058      multiple times ONLY IF a select was actually waiting. We go through
1059      the list the number of waiting select calls + 1. This list is
1060      expected to be small. */
1061   while (1) {
1062     sys_sem_wait(selectsem);
1063     for (scb = select_cb_list; scb; scb = scb->next) {
1064       if (scb->sem_signalled == 0) {
1065         /* Test this select call for our socket */
1066         if (scb->readset && FD_ISSET(s, scb->readset))
1067           if (sock->rcvevent)
1068             break;
1069         if (scb->writeset && FD_ISSET(s, scb->writeset))
1070           if (sock->sendevent)
1071             break;
1072       }
1073     }
1074     if (scb) {
1075       scb->sem_signalled = 1;
1076       sys_sem_signal(selectsem);
1077       sys_sem_signal(scb->sem);
1078     } else {
1079       sys_sem_signal(selectsem);
1080       break;
1081     }
1082   }
1083 }
1084
1085 /**
1086  * Unimplemented: Close one end of a full-duplex connection.
1087  * Currently, the full connection is closed.
1088  */
1089 int
1090 lwip_shutdown(int s, int how)
1091 {
1092   LWIP_UNUSED_ARG(how);
1093   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_shutdown(%d, how=%d)\n", s, how));
1094   return lwip_close(s); /* XXX temporary hack until proper implementation */
1095 }
1096
1097 static int
1098 lwip_getaddrname(int s, struct sockaddr *name, socklen_t *namelen, u8_t local)
1099 {
1100   struct lwip_socket *sock;
1101   struct sockaddr_in sin;
1102   struct ip_addr naddr;
1103
1104   sock = get_socket(s);
1105   if (!sock)
1106     return -1;
1107
1108   memset(&sin, 0, sizeof(sin));
1109   sin.sin_len = sizeof(sin);
1110   sin.sin_family = AF_INET;
1111
1112   /* get the IP address and port */
1113   netconn_getaddr(sock->conn, &naddr, &sin.sin_port, local);
1114
1115   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getaddrname(%d, addr=", s));
1116   ip_addr_debug_print(SOCKETS_DEBUG, &naddr);
1117   LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%d)\n", sin.sin_port));
1118
1119   sin.sin_port = htons(sin.sin_port);
1120   sin.sin_addr.s_addr = naddr.addr;
1121
1122   if (*namelen > sizeof(sin))
1123     *namelen = sizeof(sin);
1124
1125   SMEMCPY(name, &sin, *namelen);
1126   sock_set_errno(sock, 0);
1127   return 0;
1128 }
1129
1130 int
1131 lwip_getpeername(int s, struct sockaddr *name, socklen_t *namelen)
1132 {
1133   return lwip_getaddrname(s, name, namelen, 0);
1134 }
1135
1136 int
1137 lwip_getsockname(int s, struct sockaddr *name, socklen_t *namelen)
1138 {
1139   return lwip_getaddrname(s, name, namelen, 1);
1140 }
1141
1142 int
1143 lwip_getsockopt(int s, int level, int optname, void *optval, socklen_t *optlen)
1144 {
1145   err_t err = ERR_OK;
1146   struct lwip_socket *sock = get_socket(s);
1147   struct lwip_setgetsockopt_data data;
1148
1149   if (!sock)
1150     return -1;
1151
1152   if ((NULL == optval) || (NULL == optlen)) {
1153     sock_set_errno(sock, EFAULT);
1154     return -1;
1155   }
1156
1157   /* Do length and type checks for the various options first, to keep it readable. */
1158   switch (level) {
1159    
1160 /* Level: SOL_SOCKET */
1161   case SOL_SOCKET:
1162     switch (optname) {
1163        
1164     case SO_ACCEPTCONN:
1165     case SO_BROADCAST:
1166     /* UNIMPL case SO_DEBUG: */
1167     /* UNIMPL case SO_DONTROUTE: */
1168     case SO_ERROR:
1169     case SO_KEEPALIVE:
1170     /* UNIMPL case SO_CONTIMEO: */
1171     /* UNIMPL case SO_SNDTIMEO: */
1172 #if LWIP_SO_RCVTIMEO
1173     case SO_RCVTIMEO:
1174 #endif /* LWIP_SO_RCVTIMEO */
1175 #if LWIP_SO_RCVBUF
1176     case SO_RCVBUF:
1177 #endif /* LWIP_SO_RCVBUF */
1178     /* UNIMPL case SO_OOBINLINE: */
1179     /* UNIMPL case SO_SNDBUF: */
1180     /* UNIMPL case SO_RCVLOWAT: */
1181     /* UNIMPL case SO_SNDLOWAT: */
1182 #if SO_REUSE
1183     case SO_REUSEADDR:
1184     case SO_REUSEPORT:
1185 #endif /* SO_REUSE */
1186     case SO_TYPE:
1187     /* UNIMPL case SO_USELOOPBACK: */
1188       if (*optlen < sizeof(int)) {
1189         err = EINVAL;
1190       }
1191       break;
1192
1193     case SO_NO_CHECK:
1194       if (*optlen < sizeof(int)) {
1195         err = EINVAL;
1196       }
1197 #if LWIP_UDP
1198       if ((sock->conn->type != NETCONN_UDP) ||
1199           ((udp_flags(sock->conn->pcb.udp) & UDP_FLAGS_UDPLITE) != 0)) {
1200         /* this flag is only available for UDP, not for UDP lite */
1201         err = EAFNOSUPPORT;
1202       }
1203 #endif /* LWIP_UDP */
1204       break;
1205
1206     default:
1207       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, UNIMPL: optname=0x%x, ..)\n",
1208                                   s, optname));
1209       err = ENOPROTOOPT;
1210     }  /* switch (optname) */
1211     break;
1212                      
1213 /* Level: IPPROTO_IP */
1214   case IPPROTO_IP:
1215     switch (optname) {
1216     /* UNIMPL case IP_HDRINCL: */
1217     /* UNIMPL case IP_RCVDSTADDR: */
1218     /* UNIMPL case IP_RCVIF: */
1219     case IP_TTL:
1220     case IP_TOS:
1221       if (*optlen < sizeof(int)) {
1222         err = EINVAL;
1223       }
1224       break;
1225 #if LWIP_IGMP
1226     case IP_MULTICAST_TTL:
1227       if (*optlen < sizeof(u8_t)) {
1228         err = EINVAL;
1229       }
1230       break;
1231     case IP_MULTICAST_IF:
1232       if (*optlen < sizeof(struct in_addr)) {
1233         err = EINVAL;
1234       }
1235       break;
1236 #endif /* LWIP_IGMP */
1237
1238     default:
1239       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, UNIMPL: optname=0x%x, ..)\n",
1240                                   s, optname));
1241       err = ENOPROTOOPT;
1242     }  /* switch (optname) */
1243     break;
1244          
1245 #if LWIP_TCP
1246 /* Level: IPPROTO_TCP */
1247   case IPPROTO_TCP:
1248     if (*optlen < sizeof(int)) {
1249       err = EINVAL;
1250       break;
1251     }
1252     
1253     /* If this is no TCP socket, ignore any options. */
1254     if (sock->conn->type != NETCONN_TCP)
1255       return 0;
1256
1257     switch (optname) {
1258     case TCP_NODELAY:
1259     case TCP_KEEPALIVE:
1260 #if LWIP_TCP_KEEPALIVE
1261     case TCP_KEEPIDLE:
1262     case TCP_KEEPINTVL:
1263     case TCP_KEEPCNT:
1264 #endif /* LWIP_TCP_KEEPALIVE */
1265       break;
1266        
1267     default:
1268       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_TCP, UNIMPL: optname=0x%x, ..)\n",
1269                                   s, optname));
1270       err = ENOPROTOOPT;
1271     }  /* switch (optname) */
1272     break;
1273 #endif /* LWIP_TCP */
1274 #if LWIP_UDP && LWIP_UDPLITE
1275 /* Level: IPPROTO_UDPLITE */
1276   case IPPROTO_UDPLITE:
1277     if (*optlen < sizeof(int)) {
1278       err = EINVAL;
1279       break;
1280     }
1281     
1282     /* If this is no UDP lite socket, ignore any options. */
1283     if (sock->conn->type != NETCONN_UDPLITE)
1284       return 0;
1285
1286     switch (optname) {
1287     case UDPLITE_SEND_CSCOV:
1288     case UDPLITE_RECV_CSCOV:
1289       break;
1290        
1291     default:
1292       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_UDPLITE, UNIMPL: optname=0x%x, ..)\n",
1293                                   s, optname));
1294       err = ENOPROTOOPT;
1295     }  /* switch (optname) */
1296     break;
1297 #endif /* LWIP_UDP && LWIP_UDPLITE*/
1298 /* UNDEFINED LEVEL */
1299   default:
1300       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, level=0x%x, UNIMPL: optname=0x%x, ..)\n",
1301                                   s, level, optname));
1302       err = ENOPROTOOPT;
1303   }  /* switch */
1304
1305    
1306   if (err != ERR_OK) {
1307     sock_set_errno(sock, err);
1308     return -1;
1309   }
1310
1311   /* Now do the actual option processing */
1312   data.sock = sock;
1313   data.level = level;
1314   data.optname = optname;
1315   data.optval = optval;
1316   data.optlen = optlen;
1317   data.err = err;
1318   tcpip_callback(lwip_getsockopt_internal, &data);
1319   sys_arch_sem_wait(sock->conn->op_completed, 0);
1320   /* maybe lwip_getsockopt_internal has changed err */
1321   err = data.err;
1322
1323   sock_set_errno(sock, err);
1324   return err ? -1 : 0;
1325 }
1326
1327 static void
1328 lwip_getsockopt_internal(void *arg)
1329 {
1330   struct lwip_socket *sock;
1331 #ifdef LWIP_DEBUG
1332   int s;
1333 #endif /* LWIP_DEBUG */
1334   int level, optname;
1335   void *optval;
1336   struct lwip_setgetsockopt_data *data;
1337
1338   LWIP_ASSERT("arg != NULL", arg != NULL);
1339
1340   data = (struct lwip_setgetsockopt_data*)arg;
1341   sock = data->sock;
1342 #ifdef LWIP_DEBUG
1343   s = data->s;
1344 #endif /* LWIP_DEBUG */
1345   level = data->level;
1346   optname = data->optname;
1347   optval = data->optval;
1348
1349   switch (level) {
1350    
1351 /* Level: SOL_SOCKET */
1352   case SOL_SOCKET:
1353     switch (optname) {
1354
1355     /* The option flags */
1356     case SO_ACCEPTCONN:
1357     case SO_BROADCAST:
1358     /* UNIMPL case SO_DEBUG: */
1359     /* UNIMPL case SO_DONTROUTE: */
1360     case SO_KEEPALIVE:
1361     /* UNIMPL case SO_OOBINCLUDE: */
1362 #if SO_REUSE
1363     case SO_REUSEADDR:
1364     case SO_REUSEPORT:
1365 #endif /* SO_REUSE */
1366     /*case SO_USELOOPBACK: UNIMPL */
1367       *(int*)optval = sock->conn->pcb.ip->so_options & optname;
1368       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, optname=0x%x, ..) = %s\n",
1369                                   s, optname, (*(int*)optval?"on":"off")));
1370       break;
1371
1372     case SO_TYPE:
1373       switch (NETCONNTYPE_GROUP(sock->conn->type)) {
1374       case NETCONN_RAW:
1375         *(int*)optval = SOCK_RAW;
1376         break;
1377       case NETCONN_TCP:
1378         *(int*)optval = SOCK_STREAM;
1379         break;
1380       case NETCONN_UDP:
1381         *(int*)optval = SOCK_DGRAM;
1382         break;
1383       default: /* unrecognized socket type */
1384         *(int*)optval = sock->conn->type;
1385         LWIP_DEBUGF(SOCKETS_DEBUG,
1386                     ("lwip_getsockopt(%d, SOL_SOCKET, SO_TYPE): unrecognized socket type %d\n",
1387                     s, *(int *)optval));
1388       }  /* switch (sock->conn->type) */
1389       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, SO_TYPE) = %d\n",
1390                   s, *(int *)optval));
1391       break;
1392
1393     case SO_ERROR:
1394       if (sock->err == 0) {
1395         sock_set_errno(sock, err_to_errno(sock->conn->err));
1396       } 
1397       *(int *)optval = sock->err;
1398       sock->err = 0;
1399       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, SO_ERROR) = %d\n",
1400                   s, *(int *)optval));
1401       break;
1402
1403 #if LWIP_SO_RCVTIMEO
1404     case SO_RCVTIMEO:
1405       *(int *)optval = sock->conn->recv_timeout;
1406       break;
1407 #endif /* LWIP_SO_RCVTIMEO */
1408 #if LWIP_SO_RCVBUF
1409     case SO_RCVBUF:
1410       *(int *)optval = sock->conn->recv_bufsize;
1411       break;
1412 #endif /* LWIP_SO_RCVBUF */
1413 #if LWIP_UDP
1414     case SO_NO_CHECK:
1415       *(int*)optval = (udp_flags(sock->conn->pcb.udp) & UDP_FLAGS_NOCHKSUM) ? 1 : 0;
1416       break;
1417 #endif /* LWIP_UDP*/
1418     }  /* switch (optname) */
1419     break;
1420
1421 /* Level: IPPROTO_IP */
1422   case IPPROTO_IP:
1423     switch (optname) {
1424     case IP_TTL:
1425       *(int*)optval = sock->conn->pcb.ip->ttl;
1426       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_TTL) = %d\n",
1427                   s, *(int *)optval));
1428       break;
1429     case IP_TOS:
1430       *(int*)optval = sock->conn->pcb.ip->tos;
1431       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_TOS) = %d\n",
1432                   s, *(int *)optval));
1433       break;
1434 #if LWIP_IGMP
1435     case IP_MULTICAST_TTL:
1436       *(u8_t*)optval = sock->conn->pcb.ip->ttl;
1437       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_MULTICAST_TTL) = %d\n",
1438                   s, *(int *)optval));
1439       break;
1440     case IP_MULTICAST_IF:
1441       ((struct in_addr*) optval)->s_addr = sock->conn->pcb.udp->multicast_ip.addr;
1442       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_MULTICAST_IF) = 0x%x\n",
1443                   s, *(u32_t *)optval));
1444       break;
1445 #endif /* LWIP_IGMP */
1446     }  /* switch (optname) */
1447     break;
1448
1449 #if LWIP_TCP
1450 /* Level: IPPROTO_TCP */
1451   case IPPROTO_TCP:
1452     switch (optname) {
1453     case TCP_NODELAY:
1454       *(int*)optval = (sock->conn->pcb.tcp->flags & TF_NODELAY);
1455       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_TCP, TCP_NODELAY) = %s\n",
1456                   s, (*(int*)optval)?"on":"off") );
1457       break;
1458     case TCP_KEEPALIVE:
1459       *(int*)optval = (int)sock->conn->pcb.tcp->keep_idle;
1460       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, TCP_KEEPALIVE) = %d\n",
1461                   s, *(int *)optval));
1462       break;
1463
1464 #if LWIP_TCP_KEEPALIVE
1465     case TCP_KEEPIDLE:
1466       *(int*)optval = (int)(sock->conn->pcb.tcp->keep_idle/1000);
1467       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, TCP_KEEPIDLE) = %d\n",
1468                   s, *(int *)optval));
1469       break;
1470     case TCP_KEEPINTVL:
1471       *(int*)optval = (int)(sock->conn->pcb.tcp->keep_intvl/1000);
1472       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, TCP_KEEPINTVL) = %d\n",
1473                   s, *(int *)optval));
1474       break;
1475     case TCP_KEEPCNT:
1476       *(int*)optval = (int)sock->conn->pcb.tcp->keep_cnt;
1477       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, TCP_KEEPCNT) = %d\n",
1478                   s, *(int *)optval));
1479       break;
1480 #endif /* LWIP_TCP_KEEPALIVE */
1481
1482     }  /* switch (optname) */
1483     break;
1484 #endif /* LWIP_TCP */
1485 #if LWIP_UDP && LWIP_UDPLITE
1486   /* Level: IPPROTO_UDPLITE */
1487   case IPPROTO_UDPLITE:
1488     switch (optname) {
1489     case UDPLITE_SEND_CSCOV:
1490       *(int*)optval = sock->conn->pcb.udp->chksum_len_tx;
1491       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_UDPLITE, UDPLITE_SEND_CSCOV) = %d\n",
1492                   s, (*(int*)optval)) );
1493       break;
1494     case UDPLITE_RECV_CSCOV:
1495       *(int*)optval = sock->conn->pcb.udp->chksum_len_rx;
1496       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_UDPLITE, UDPLITE_RECV_CSCOV) = %d\n",
1497                   s, (*(int*)optval)) );
1498       break;
1499     }  /* switch (optname) */
1500     break;
1501 #endif /* LWIP_UDP */
1502   } /* switch (level) */
1503   sys_sem_signal(sock->conn->op_completed);
1504 }
1505
1506 int
1507 lwip_setsockopt(int s, int level, int optname, const void *optval, socklen_t optlen)
1508 {
1509   struct lwip_socket *sock = get_socket(s);
1510   int err = ERR_OK;
1511   struct lwip_setgetsockopt_data data;
1512
1513   if (!sock)
1514     return -1;
1515
1516   if (NULL == optval) {
1517     sock_set_errno(sock, EFAULT);
1518     return -1;
1519   }
1520
1521   /* Do length and type checks for the various options first, to keep it readable. */
1522   switch (level) {
1523
1524 /* Level: SOL_SOCKET */
1525   case SOL_SOCKET:
1526     switch (optname) {
1527
1528     case SO_BROADCAST:
1529     /* UNIMPL case SO_DEBUG: */
1530     /* UNIMPL case SO_DONTROUTE: */
1531     case SO_KEEPALIVE:
1532     /* UNIMPL case case SO_CONTIMEO: */
1533     /* UNIMPL case case SO_SNDTIMEO: */
1534 #if LWIP_SO_RCVTIMEO
1535     case SO_RCVTIMEO:
1536 #endif /* LWIP_SO_RCVTIMEO */
1537 #if LWIP_SO_RCVBUF
1538     case SO_RCVBUF:
1539 #endif /* LWIP_SO_RCVBUF */
1540     /* UNIMPL case SO_OOBINLINE: */
1541     /* UNIMPL case SO_SNDBUF: */
1542     /* UNIMPL case SO_RCVLOWAT: */
1543     /* UNIMPL case SO_SNDLOWAT: */
1544 #if SO_REUSE
1545     case SO_REUSEADDR:
1546     case SO_REUSEPORT:
1547 #endif /* SO_REUSE */
1548     /* UNIMPL case SO_USELOOPBACK: */
1549       if (optlen < sizeof(int)) {
1550         err = EINVAL;
1551       }
1552       break;
1553     case SO_NO_CHECK:
1554       if (optlen < sizeof(int)) {
1555         err = EINVAL;
1556       }
1557 #if LWIP_UDP
1558       if ((sock->conn->type != NETCONN_UDP) ||
1559           ((udp_flags(sock->conn->pcb.udp) & UDP_FLAGS_UDPLITE) != 0)) {
1560         /* this flag is only available for UDP, not for UDP lite */
1561         err = EAFNOSUPPORT;
1562       }
1563 #endif /* LWIP_UDP */
1564       break;
1565     default:
1566       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, SOL_SOCKET, UNIMPL: optname=0x%x, ..)\n",
1567                   s, optname));
1568       err = ENOPROTOOPT;
1569     }  /* switch (optname) */
1570     break;
1571
1572 /* Level: IPPROTO_IP */
1573   case IPPROTO_IP:
1574     switch (optname) {
1575     /* UNIMPL case IP_HDRINCL: */
1576     /* UNIMPL case IP_RCVDSTADDR: */
1577     /* UNIMPL case IP_RCVIF: */
1578     case IP_TTL:
1579     case IP_TOS:
1580       if (optlen < sizeof(int)) {
1581         err = EINVAL;
1582       }
1583       break;
1584 #if LWIP_IGMP
1585     case IP_MULTICAST_TTL:
1586       if (optlen < sizeof(u8_t)) {
1587         err = EINVAL;
1588       }
1589       if (NETCONNTYPE_GROUP(sock->conn->type) != NETCONN_UDP) {
1590         err = EAFNOSUPPORT;
1591       }
1592       break;
1593     case IP_MULTICAST_IF:
1594       if (optlen < sizeof(struct in_addr)) {
1595         err = EINVAL;
1596       }
1597       if (NETCONNTYPE_GROUP(sock->conn->type) != NETCONN_UDP) {
1598         err = EAFNOSUPPORT;
1599       }
1600       break;
1601     case IP_ADD_MEMBERSHIP:
1602     case IP_DROP_MEMBERSHIP:
1603       if (optlen < sizeof(struct ip_mreq)) {
1604         err = EINVAL;
1605       }
1606       if (NETCONNTYPE_GROUP(sock->conn->type) != NETCONN_UDP) {
1607         err = EAFNOSUPPORT;
1608       }
1609       break;
1610 #endif /* LWIP_IGMP */
1611       default:
1612         LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IP, UNIMPL: optname=0x%x, ..)\n",
1613                     s, optname));
1614         err = ENOPROTOOPT;
1615     }  /* switch (optname) */
1616     break;
1617
1618 #if LWIP_TCP
1619 /* Level: IPPROTO_TCP */
1620   case IPPROTO_TCP:
1621     if (optlen < sizeof(int)) {
1622       err = EINVAL;
1623       break;
1624     }
1625
1626     /* If this is no TCP socket, ignore any options. */
1627     if (sock->conn->type != NETCONN_TCP)
1628       return 0;
1629
1630     switch (optname) {
1631     case TCP_NODELAY:
1632     case TCP_KEEPALIVE:
1633 #if LWIP_TCP_KEEPALIVE
1634     case TCP_KEEPIDLE:
1635     case TCP_KEEPINTVL:
1636     case TCP_KEEPCNT:
1637 #endif /* LWIP_TCP_KEEPALIVE */
1638       break;
1639
1640     default:
1641       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, UNIMPL: optname=0x%x, ..)\n",
1642                   s, optname));
1643       err = ENOPROTOOPT;
1644     }  /* switch (optname) */
1645     break;
1646 #endif /* LWIP_TCP */
1647 #if LWIP_UDP && LWIP_UDPLITE
1648 /* Level: IPPROTO_UDPLITE */
1649   case IPPROTO_UDPLITE:
1650     if (optlen < sizeof(int)) {
1651       err = EINVAL;
1652       break;
1653     }
1654
1655     /* If this is no UDP lite socket, ignore any options. */
1656     if (sock->conn->type != NETCONN_UDPLITE)
1657       return 0;
1658
1659     switch (optname) {
1660     case UDPLITE_SEND_CSCOV:
1661     case UDPLITE_RECV_CSCOV:
1662       break;
1663
1664     default:
1665       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_UDPLITE, UNIMPL: optname=0x%x, ..)\n",
1666                   s, optname));
1667       err = ENOPROTOOPT;
1668     }  /* switch (optname) */
1669     break;
1670 #endif /* LWIP_UDP && LWIP_UDPLITE */
1671 /* UNDEFINED LEVEL */
1672   default:
1673     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, level=0x%x, UNIMPL: optname=0x%x, ..)\n",
1674                 s, level, optname));
1675     err = ENOPROTOOPT;
1676   }  /* switch (level) */
1677
1678
1679   if (err != ERR_OK) {
1680     sock_set_errno(sock, err);
1681     return -1;
1682   }
1683
1684
1685   /* Now do the actual option processing */
1686   data.sock = sock;
1687   data.level = level;
1688   data.optname = optname;
1689   data.optval = (void*)optval;
1690   data.optlen = &optlen;
1691   data.err = err;
1692   tcpip_callback(lwip_setsockopt_internal, &data);
1693   sys_arch_sem_wait(sock->conn->op_completed, 0);
1694   /* maybe lwip_setsockopt_internal has changed err */
1695   err = data.err;
1696
1697   sock_set_errno(sock, err);
1698   return err ? -1 : 0;
1699 }
1700
1701 static void
1702 lwip_setsockopt_internal(void *arg)
1703 {
1704   struct lwip_socket *sock;
1705 #ifdef LWIP_DEBUG
1706   int s;
1707 #endif /* LWIP_DEBUG */
1708   int level, optname;
1709   const void *optval;
1710   struct lwip_setgetsockopt_data *data;
1711
1712   LWIP_ASSERT("arg != NULL", arg != NULL);
1713
1714   data = (struct lwip_setgetsockopt_data*)arg;
1715   sock = data->sock;
1716 #ifdef LWIP_DEBUG
1717   s = data->s;
1718 #endif /* LWIP_DEBUG */
1719   level = data->level;
1720   optname = data->optname;
1721   optval = data->optval;
1722
1723   switch (level) {
1724
1725 /* Level: SOL_SOCKET */
1726   case SOL_SOCKET:
1727     switch (optname) {
1728
1729     /* The option flags */
1730     case SO_BROADCAST:
1731     /* UNIMPL case SO_DEBUG: */
1732     /* UNIMPL case SO_DONTROUTE: */
1733     case SO_KEEPALIVE:
1734     /* UNIMPL case SO_OOBINCLUDE: */
1735 #if SO_REUSE
1736     case SO_REUSEADDR:
1737     case SO_REUSEPORT:
1738 #endif /* SO_REUSE */
1739     /* UNIMPL case SO_USELOOPBACK: */
1740       if (*(int*)optval) {
1741         sock->conn->pcb.ip->so_options |= optname;
1742       } else {
1743         sock->conn->pcb.ip->so_options &= ~optname;
1744       }
1745       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, SOL_SOCKET, optname=0x%x, ..) -> %s\n",
1746                   s, optname, (*(int*)optval?"on":"off")));
1747       break;
1748 #if LWIP_SO_RCVTIMEO
1749     case SO_RCVTIMEO:
1750       sock->conn->recv_timeout = ( *(int*)optval );
1751       break;
1752 #endif /* LWIP_SO_RCVTIMEO */
1753 #if LWIP_SO_RCVBUF
1754     case SO_RCVBUF:
1755       sock->conn->recv_bufsize = ( *(int*)optval );
1756       break;
1757 #endif /* LWIP_SO_RCVBUF */
1758 #if LWIP_UDP
1759     case SO_NO_CHECK:
1760       if (*(int*)optval) {
1761         udp_setflags(sock->conn->pcb.udp, udp_flags(sock->conn->pcb.udp) | UDP_FLAGS_NOCHKSUM);
1762       } else {
1763         udp_setflags(sock->conn->pcb.udp, udp_flags(sock->conn->pcb.udp) & ~UDP_FLAGS_NOCHKSUM);
1764       }
1765       break;
1766 #endif /* LWIP_UDP */
1767     }  /* switch (optname) */
1768     break;
1769
1770 /* Level: IPPROTO_IP */
1771   case IPPROTO_IP:
1772     switch (optname) {
1773     case IP_TTL:
1774       sock->conn->pcb.ip->ttl = (u8_t)(*(int*)optval);
1775       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IP, IP_TTL, ..) -> %u\n",
1776                   s, sock->conn->pcb.ip->ttl));
1777       break;
1778     case IP_TOS:
1779       sock->conn->pcb.ip->tos = (u8_t)(*(int*)optval);
1780       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IP, IP_TOS, ..)-> %u\n",
1781                   s, sock->conn->pcb.ip->tos));
1782       break;
1783 #if LWIP_IGMP
1784     case IP_MULTICAST_TTL:
1785       sock->conn->pcb.udp->ttl = (u8_t)(*(u8_t*)optval);
1786       break;
1787     case IP_MULTICAST_IF:
1788       sock->conn->pcb.udp->multicast_ip.addr = ((struct in_addr*) optval)->s_addr;
1789       break;
1790     case IP_ADD_MEMBERSHIP:
1791     case IP_DROP_MEMBERSHIP:
1792       {
1793         /* If this is a TCP or a RAW socket, ignore these options. */
1794         struct ip_mreq *imr = (struct ip_mreq *)optval;
1795         if(optname == IP_ADD_MEMBERSHIP){
1796           data->err = igmp_joingroup((struct ip_addr*)&(imr->imr_interface.s_addr), (struct ip_addr*)&(imr->imr_multiaddr.s_addr));
1797         } else {
1798           data->err = igmp_leavegroup((struct ip_addr*)&(imr->imr_interface.s_addr), (struct ip_addr*)&(imr->imr_multiaddr.s_addr));
1799         }
1800         if(data->err != ERR_OK) {
1801           data->err = EADDRNOTAVAIL;
1802         }
1803       }
1804       break;
1805 #endif /* LWIP_IGMP */
1806     }  /* switch (optname) */
1807     break;
1808
1809 #if LWIP_TCP
1810 /* Level: IPPROTO_TCP */
1811   case IPPROTO_TCP:
1812     switch (optname) {
1813     case TCP_NODELAY:
1814       if (*(int*)optval) {
1815         sock->conn->pcb.tcp->flags |= TF_NODELAY;
1816       } else {
1817         sock->conn->pcb.tcp->flags &= ~TF_NODELAY;
1818       }
1819       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_NODELAY) -> %s\n",
1820                   s, (*(int *)optval)?"on":"off") );
1821       break;
1822     case TCP_KEEPALIVE:
1823       sock->conn->pcb.tcp->keep_idle = (u32_t)(*(int*)optval);
1824       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPALIVE) -> %lu\n",
1825                   s, sock->conn->pcb.tcp->keep_idle));
1826       break;
1827
1828 #if LWIP_TCP_KEEPALIVE
1829     case TCP_KEEPIDLE:
1830       sock->conn->pcb.tcp->keep_idle = 1000*(u32_t)(*(int*)optval);
1831       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPIDLE) -> %lu\n",
1832                   s, sock->conn->pcb.tcp->keep_idle));
1833       break;
1834     case TCP_KEEPINTVL:
1835       sock->conn->pcb.tcp->keep_intvl = 1000*(u32_t)(*(int*)optval);
1836       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPINTVL) -> %lu\n",
1837                   s, sock->conn->pcb.tcp->keep_intvl));
1838       break;
1839     case TCP_KEEPCNT:
1840       sock->conn->pcb.tcp->keep_cnt = (u32_t)(*(int*)optval);
1841       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPCNT) -> %lu\n",
1842                   s, sock->conn->pcb.tcp->keep_cnt));
1843       break;
1844 #endif /* LWIP_TCP_KEEPALIVE */
1845
1846     }  /* switch (optname) */
1847     break;
1848 #endif /* LWIP_TCP*/
1849 #if LWIP_UDP && LWIP_UDPLITE
1850   /* Level: IPPROTO_UDPLITE */
1851   case IPPROTO_UDPLITE:
1852     switch (optname) {
1853     case UDPLITE_SEND_CSCOV:
1854       if ((*(int*)optval != 0) && (*(int*)optval < 8)) {
1855         /* don't allow illegal values! */
1856         sock->conn->pcb.udp->chksum_len_tx = 8;
1857       } else {
1858         sock->conn->pcb.udp->chksum_len_tx = *(int*)optval;
1859       }
1860       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_UDPLITE, UDPLITE_SEND_CSCOV) -> %d\n",
1861                   s, (*(int*)optval)) );
1862       break;
1863     case UDPLITE_RECV_CSCOV:
1864       if ((*(int*)optval != 0) && (*(int*)optval < 8)) {
1865         /* don't allow illegal values! */
1866         sock->conn->pcb.udp->chksum_len_rx = 8;
1867       } else {
1868         sock->conn->pcb.udp->chksum_len_rx = *(int*)optval;
1869       }
1870       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_UDPLITE, UDPLITE_RECV_CSCOV) -> %d\n",
1871                   s, (*(int*)optval)) );
1872       break;
1873     }  /* switch (optname) */
1874     break;
1875 #endif /* LWIP_UDP */
1876   }  /* switch (level) */
1877   sys_sem_signal(sock->conn->op_completed);
1878 }
1879
1880 int
1881 lwip_ioctl(int s, long cmd, void *argp)
1882 {
1883   struct lwip_socket *sock = get_socket(s);
1884   u16_t buflen = 0;
1885
1886   if (!sock)
1887     return -1;
1888
1889   switch (cmd) {
1890   case FIONREAD:
1891     if (!argp) {
1892       sock_set_errno(sock, EINVAL);
1893       return -1;
1894     }
1895
1896     SYS_ARCH_GET(sock->conn->recv_avail, *((u16_t*)argp));
1897
1898     /* Check if there is data left from the last recv operation. /maq 041215 */
1899     if (sock->lastdata) {
1900       buflen = netbuf_len(sock->lastdata);
1901       buflen -= sock->lastoffset;
1902
1903       *((u16_t*)argp) += buflen;
1904     }
1905
1906     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(%d, FIONREAD, %p) = %u\n", s, argp, *((u16_t*)argp)));
1907     sock_set_errno(sock, 0);
1908     return 0;
1909
1910   case FIONBIO:
1911     if (argp && *(u32_t*)argp)
1912       sock->flags |= O_NONBLOCK;
1913     else
1914       sock->flags &= ~O_NONBLOCK;
1915     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(%d, FIONBIO, %d)\n", s, !!(sock->flags & O_NONBLOCK)));
1916     sock_set_errno(sock, 0);
1917     return 0;
1918
1919   default:
1920     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(%d, UNIMPL: 0x%lx, %p)\n", s, cmd, argp));
1921     sock_set_errno(sock, ENOSYS); /* not yet implemented */
1922     return -1;
1923   } /* switch (cmd) */
1924 }
1925
1926 #endif /* LWIP_SOCKET */