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