]> git.karo-electronics.de Git - karo-tx-redboot.git/blob - packages/net/lwip_tcpip/v2_0/src/api/sockets.c
7c636c64d3b1e5a0b95bed16e7576ec8bb6e453d
[karo-tx-redboot.git] / packages / net / lwip_tcpip / v2_0 / src / api / sockets.c
1 /*
2  * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without modification,
6  * are permitted provided that the following conditions are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright notice,
9  *    this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright notice,
11  *    this list of conditions and the following disclaimer in the documentation
12  *    and/or other materials provided with the distribution.
13  * 3. The name of the author may not be used to endorse or promote products
14  *    derived from this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
19  * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
21  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
24  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
25  * OF SUCH DAMAGE.
26  *
27  * This file is part of the lwIP TCP/IP stack.
28  *
29  * Author: Adam Dunkels <adam@sics.se>
30  *
31  * Improved by Marc Boucher <marc@mbsi.ca> and David Haas <dhaas@alum.rpi.edu>
32  *
33  */
34
35 #include "lwip/opt.h"
36 #include "lwip/api.h"
37 #include "lwip/arch.h"
38 #include "lwip/sys.h"
39
40 #define LWIP_TIMEVAL_PRIVATE
41 #include "lwip/sockets.h"
42
43 #define NUM_SOCKETS MEMP_NUM_NETCONN
44
45 struct lwip_socket {
46   struct netconn *conn;
47   struct netbuf *lastdata;
48   u16_t lastoffset;
49   u16_t rcvevent;
50   u16_t sendevent;
51   u16_t  flags;
52   int err;
53 };
54
55 struct lwip_select_cb
56 {
57     struct lwip_select_cb *next;
58     fd_set *readset;
59     fd_set *writeset;
60     fd_set *exceptset;
61     int sem_signalled;
62     sys_sem_t sem;
63 };
64
65 static struct lwip_socket sockets[NUM_SOCKETS];
66 static struct lwip_select_cb *select_cb_list = 0;
67
68 static sys_sem_t socksem = 0;
69 static sys_sem_t selectsem = 0;
70
71 static void
72 event_callback(struct netconn *conn, enum netconn_evt evt, u16_t len);
73
74 static int err_to_errno_table[11] = {
75     0,      /* ERR_OK    0      No error, everything OK. */
76     ENOMEM,    /* ERR_MEM  -1      Out of memory error.     */
77     ENOBUFS,    /* ERR_BUF  -2      Buffer error.            */
78     ECONNABORTED,  /* ERR_ABRT -3      Connection aborted.      */
79     ECONNRESET,    /* ERR_RST  -4      Connection reset.        */
80     ESHUTDOWN,    /* ERR_CLSD -5      Connection closed.       */
81     ENOTCONN,    /* ERR_CONN -6      Not connected.           */
82     EINVAL,    /* ERR_VAL  -7      Illegal value.           */
83     EIO,    /* ERR_ARG  -8      Illegal argument.        */
84     EHOSTUNREACH,  /* ERR_RTE  -9      Routing problem.         */
85     EADDRINUSE    /* ERR_USE  -10     Address in use.          */
86 };
87
88 #define err_to_errno(err) \
89   ((err) < (sizeof(err_to_errno_table)/sizeof(int))) ? \
90     err_to_errno_table[-(err)] : EIO
91
92 #ifdef ERRNO
93 #define set_errno(err) errno = (err)
94 #else
95 #define set_errno(err)
96 #endif
97
98 #define sock_set_errno(sk, e) do { \
99       sk->err = (e); \
100       set_errno(sk->err); \
101 } while (0)
102
103
104 static struct lwip_socket *
105 get_socket(int s)
106 {
107   struct lwip_socket *sock;
108
109   if ((s < 0) || (s > NUM_SOCKETS)) {
110     LWIP_DEBUGF(SOCKETS_DEBUG, ("get_socket(%d): invalid\n", s));
111     set_errno(EBADF);
112     return NULL;
113   }
114
115   sock = &sockets[s];
116
117   if (!sock->conn) {
118     LWIP_DEBUGF(SOCKETS_DEBUG, ("get_socket(%d): not active\n", s));
119     set_errno(EBADF);
120     return NULL;
121   }
122
123   return sock;
124 }
125
126 static int
127 alloc_socket(struct netconn *newconn)
128 {
129   int i;
130
131   if (!socksem)
132       socksem = sys_sem_new(1);
133
134   /* Protect socket array */
135   sys_sem_wait(socksem);
136
137   /* allocate a new socket identifier */
138   for(i = 0; i < NUM_SOCKETS; ++i) {
139     if (!sockets[i].conn) {
140       sockets[i].conn = newconn;
141       sockets[i].lastdata = NULL;
142       sockets[i].lastoffset = 0;
143       sockets[i].rcvevent = 0;
144       sockets[i].sendevent = 1; /* TCP send buf is empty */
145       sockets[i].flags = 0;
146       sockets[i].err = 0;
147       sys_sem_signal(socksem);
148       return i;
149     }
150   }
151   sys_sem_signal(socksem);
152   return -1;
153 }
154
155 int
156 lwip_accept(int s, struct sockaddr *addr, socklen_t *addrlen)
157 {
158   struct lwip_socket *sock;
159   struct netconn *newconn;
160   struct ip_addr naddr;
161   u16_t port;
162   int newsock;
163   struct sockaddr_in sin;
164
165   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d)...\n", s));
166   sock = get_socket(s);
167   if (!sock) {
168     set_errno(EBADF);
169     return -1;
170   }
171
172   newconn = netconn_accept(sock->conn);
173
174   /* get the IP address and port of the remote host */
175   netconn_peer(newconn, &naddr, &port);
176
177   memset(&sin, 0, sizeof(sin));
178   sin.sin_len = sizeof(sin);
179   sin.sin_family = AF_INET;
180   sin.sin_port = htons(port);
181   sin.sin_addr.s_addr = naddr.addr;
182
183   if (*addrlen > sizeof(sin))
184       *addrlen = sizeof(sin);
185
186   memcpy(addr, &sin, *addrlen);
187
188   newsock = alloc_socket(newconn);
189   if (newsock == -1) {
190     netconn_delete(newconn);
191   sock_set_errno(sock, ENOBUFS);
192   return -1;
193   }
194   newconn->callback = event_callback;
195   sock = get_socket(newsock);
196
197   sys_sem_wait(socksem);
198   sock->rcvevent += -1 - newconn->socket;
199   newconn->socket = newsock;
200   sys_sem_signal(socksem);
201
202   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d) returning new sock=%d addr=", s, newsock));
203   ip_addr_debug_print(SOCKETS_DEBUG, &naddr);
204   LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%u\n", port));
205
206   sock_set_errno(sock, 0);
207   return newsock;
208 }
209
210 int
211 lwip_bind(int s, struct sockaddr *name, socklen_t namelen)
212 {
213   struct lwip_socket *sock;
214   struct ip_addr local_addr;
215   u16_t local_port;
216   err_t err;
217
218   sock = get_socket(s);
219   if (!sock) {
220     set_errno(EBADF);
221     return -1;
222   }
223
224   local_addr.addr = ((struct sockaddr_in *)name)->sin_addr.s_addr;
225   local_port = ((struct sockaddr_in *)name)->sin_port;
226
227   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d, addr=", s));
228   ip_addr_debug_print(SOCKETS_DEBUG, &local_addr);
229   LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%u)\n", ntohs(local_port)));
230
231   err = netconn_bind(sock->conn, &local_addr, ntohs(local_port));
232
233   if (err != ERR_OK) {
234     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d) failed, err=%d\n", s, err));
235     sock_set_errno(sock, err_to_errno(err));
236     return -1;
237   }
238
239   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d) succeeded\n", s));
240   sock_set_errno(sock, 0);
241   return 0;
242 }
243
244 int
245 lwip_close(int s)
246 {
247   struct lwip_socket *sock;
248
249   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_close(%d)\n", s));
250   if (!socksem)
251       socksem = sys_sem_new(1);
252
253   /* We cannot allow multiple closes of the same socket. */
254   sys_sem_wait(socksem);
255
256   sock = get_socket(s);
257   if (!sock) {
258       sys_sem_signal(socksem);
259       set_errno(EBADF);
260       return -1;
261   }
262
263   netconn_delete(sock->conn);
264   if (sock->lastdata) {
265     netbuf_delete(sock->lastdata);
266   }
267   sock->lastdata = NULL;
268   sock->lastoffset = 0;
269   sock->conn = NULL;
270   sys_sem_signal(socksem);
271   sock_set_errno(sock, 0);
272   return 0;
273 }
274
275 int
276 lwip_connect(int s, struct sockaddr *name, socklen_t namelen)
277 {
278   struct lwip_socket *sock;
279   err_t err;
280
281   sock = get_socket(s);
282   if (!sock) {
283     set_errno(EBADF);
284     return -1;
285   }
286
287   if (((struct sockaddr_in *)name)->sin_family == AF_UNSPEC) {
288     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d, AF_UNSPEC)\n", s));
289     err = netconn_disconnect(sock->conn);
290   } else {
291     struct ip_addr remote_addr;
292     u16_t remote_port;
293
294     remote_addr.addr = ((struct sockaddr_in *)name)->sin_addr.s_addr;
295     remote_port = ((struct sockaddr_in *)name)->sin_port;
296
297     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d, addr=", s));
298     ip_addr_debug_print(SOCKETS_DEBUG, &remote_addr);
299     LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%u)\n", ntohs(remote_port)));
300
301     err = netconn_connect(sock->conn, &remote_addr, ntohs(remote_port));
302    }
303
304   if (err != ERR_OK) {
305     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d) failed, err=%d\n", s, err));
306     sock_set_errno(sock, err_to_errno(err));
307     return -1;
308   }
309
310   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d) succeeded\n", s));
311   sock_set_errno(sock, 0);
312   return 0;
313 }
314
315 int
316 lwip_listen(int s, int backlog)
317 {
318   struct lwip_socket *sock;
319   err_t err;
320
321   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_listen(%d, backlog=%d)\n", s, backlog));
322   sock = get_socket(s);
323   if (!sock) {
324     set_errno(EBADF);
325     return -1;
326   }
327
328   err = netconn_listen(sock->conn);
329
330   if (err != ERR_OK) {
331     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_listen(%d) failed, err=%d\n", s, err));
332     sock_set_errno(sock, err_to_errno(err));
333     return -1;
334   }
335
336   sock_set_errno(sock, 0);
337   return 0;
338 }
339
340 int
341 lwip_recvfrom(int s, void *mem, int len, unsigned int flags,
342         struct sockaddr *from, socklen_t *fromlen)
343 {
344   struct lwip_socket *sock;
345   struct netbuf *buf;
346   u16_t buflen, copylen;
347   struct ip_addr *addr;
348   u16_t port;
349
350
351   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d, %p, %d, 0x%x, ..)\n", s, mem, len, flags));
352   sock = get_socket(s);
353   if (!sock) {
354     set_errno(EBADF);
355     return -1;
356   }
357
358   /* Check if there is data left from the last recv operation. */
359   if (sock->lastdata) {
360     buf = sock->lastdata;
361   } else {
362     /* If this is non-blocking call, then check first */
363     if (((flags & MSG_DONTWAIT) || (sock->flags & O_NONBLOCK))
364   && !sock->rcvevent)
365     {
366       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): returning EWOULDBLOCK\n", s));
367       sock_set_errno(sock, EWOULDBLOCK);
368       return -1;
369     }
370
371     /* No data was left from the previous operation, so we try to get
372        some from the network. */
373     buf = netconn_recv(sock->conn);
374
375     if (!buf) {
376       /* We should really do some error checking here. */
377       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): buf == NULL!\n", s));
378       sock_set_errno(sock, 0);
379       return 0;
380     }
381   }
382
383   buflen = netbuf_len(buf);
384
385   buflen -= sock->lastoffset;
386
387   if (len > buflen) {
388     copylen = buflen;
389   } else {
390     copylen = len;
391   }
392
393   /* copy the contents of the received buffer into
394      the supplied memory pointer mem */
395   netbuf_copy_partial(buf, mem, copylen, sock->lastoffset);
396
397   /* Check to see from where the data was. */
398   if (from && fromlen) {
399     struct sockaddr_in sin;
400
401     addr = netbuf_fromaddr(buf);
402     port = netbuf_fromport(buf);
403
404     memset(&sin, 0, sizeof(sin));
405     sin.sin_len = sizeof(sin);
406     sin.sin_family = AF_INET;
407     sin.sin_port = htons(port);
408     sin.sin_addr.s_addr = addr->addr;
409
410     if (*fromlen > sizeof(sin))
411       *fromlen = sizeof(sin);
412
413     memcpy(from, &sin, *fromlen);
414
415     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): addr=", s));
416     ip_addr_debug_print(SOCKETS_DEBUG, addr);
417     LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%u len=%u\n", port, copylen));
418   } else {
419 #if SOCKETS_DEBUG > 0
420     addr = netbuf_fromaddr(buf);
421     port = netbuf_fromport(buf);
422
423     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): addr=", s));
424     ip_addr_debug_print(SOCKETS_DEBUG, addr);
425     LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%u len=%u\n", port, copylen));
426 #endif
427
428   }
429
430   /* If this is a TCP socket, check if there is data left in the
431      buffer. If so, it should be saved in the sock structure for next
432      time around. */
433   if (netconn_type(sock->conn) == NETCONN_TCP && buflen - copylen > 0) {
434     sock->lastdata = buf;
435     sock->lastoffset += copylen;
436   } else {
437     sock->lastdata = NULL;
438     sock->lastoffset = 0;
439     netbuf_delete(buf);
440   }
441
442
443   sock_set_errno(sock, 0);
444   return copylen;
445 }
446
447 int
448 lwip_read(int s, void *mem, int len)
449 {
450   return lwip_recvfrom(s, mem, len, 0, NULL, NULL);
451 }
452
453 int
454 lwip_recv(int s, void *mem, int len, unsigned int flags)
455 {
456   return lwip_recvfrom(s, mem, len, flags, NULL, NULL);
457 }
458
459 int
460 lwip_send(int s, void *data, int size, unsigned int flags)
461 {
462   struct lwip_socket *sock;
463   struct netbuf *buf;
464   err_t err;
465
466   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_send(%d, data=%p, size=%d, flags=0x%x)\n", s, data, size, flags));
467
468   sock = get_socket(s);
469   if (!sock) {
470     set_errno(EBADF);
471     return -1;
472   }
473
474   switch (netconn_type(sock->conn)) {
475   case NETCONN_RAW:
476   case NETCONN_UDP:
477   case NETCONN_UDPLITE:
478   case NETCONN_UDPNOCHKSUM:
479     /* create a buffer */
480     buf = netbuf_new();
481
482     if (!buf) {
483       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_send(%d) ENOBUFS\n", s));
484       sock_set_errno(sock, ENOBUFS);
485       return -1;
486     }
487
488     /* make the buffer point to the data that should
489        be sent */
490     netbuf_ref(buf, data, size);
491
492     /* send the data */
493     err = netconn_send(sock->conn, buf);
494
495     /* deallocated the buffer */
496     netbuf_delete(buf);
497     break;
498   case NETCONN_TCP:
499     err = netconn_write(sock->conn, data, size, NETCONN_COPY);
500     break;
501   default:
502     err = ERR_ARG;
503     break;
504   }
505   if (err != ERR_OK) {
506     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_send(%d) err=%d\n", s, err));
507     sock_set_errno(sock, err_to_errno(err));
508     return -1;
509   }
510
511   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_send(%d) ok size=%d\n", s, size));
512   sock_set_errno(sock, 0);
513   return size;
514 }
515
516 int
517 lwip_sendto(int s, void *data, int size, unsigned int flags,
518        struct sockaddr *to, socklen_t tolen)
519 {
520   struct lwip_socket *sock;
521   struct ip_addr remote_addr, addr;
522   u16_t remote_port, port;
523   int ret,connected;
524
525   sock = get_socket(s);
526   if (!sock) {
527     set_errno(EBADF);
528     return -1;
529   }
530
531   /* get the peer if currently connected */
532   connected = (netconn_peer(sock->conn, &addr, &port) == ERR_OK);
533
534   remote_addr.addr = ((struct sockaddr_in *)to)->sin_addr.s_addr;
535   remote_port = ((struct sockaddr_in *)to)->sin_port;
536
537   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_sendto(%d, data=%p, size=%d, flags=0x%x to=", s, data, size, flags));
538   ip_addr_debug_print(SOCKETS_DEBUG, &remote_addr);
539   LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%u\n", ntohs(remote_port)));
540
541   netconn_connect(sock->conn, &remote_addr, ntohs(remote_port));
542
543   ret = lwip_send(s, data, size, flags);
544
545   /* reset the remote address and port number
546      of the connection */
547   if (connected)
548     netconn_connect(sock->conn, &addr, port);
549   else
550   netconn_disconnect(sock->conn);
551   return ret;
552 }
553
554 int
555 lwip_socket(int domain, int type, int protocol)
556 {
557   struct netconn *conn;
558   int i;
559
560   /* create a netconn */
561   switch (type) {
562   case SOCK_RAW:
563     conn = netconn_new_with_proto_and_callback(NETCONN_RAW, protocol, event_callback);
564     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_RAW, %d) = ", domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol));
565     break;
566   case SOCK_DGRAM:
567     conn = netconn_new_with_callback(NETCONN_UDP, event_callback);
568     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_DGRAM, %d) = ", domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol));
569     break;
570   case SOCK_STREAM:
571     conn = netconn_new_with_callback(NETCONN_TCP, event_callback);
572     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_STREAM, %d) = ", domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol));
573     break;
574   default:
575     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%d, %d/UNKNOWN, %d) = -1\n", domain, type, protocol));
576     set_errno(EINVAL);
577     return -1;
578   }
579
580   if (!conn) {
581     LWIP_DEBUGF(SOCKETS_DEBUG, ("-1 / ENOBUFS (could not create netconn)\n"));
582     set_errno(ENOBUFS);
583     return -1;
584   }
585
586   i = alloc_socket(conn);
587
588   if (i == -1) {
589     netconn_delete(conn);
590   set_errno(ENOBUFS);
591   return -1;
592   }
593   conn->socket = i;
594   LWIP_DEBUGF(SOCKETS_DEBUG, ("%d\n", i));
595   set_errno(0);
596   return i;
597 }
598
599 int
600 lwip_write(int s, void *data, int size)
601 {
602    return lwip_send(s, data, size, 0);
603 }
604
605
606 static int
607 lwip_selscan(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset)
608 {
609     int i, nready = 0;
610     fd_set lreadset, lwriteset, lexceptset;
611     struct lwip_socket *p_sock;
612
613     FD_ZERO(&lreadset);
614     FD_ZERO(&lwriteset);
615     FD_ZERO(&lexceptset);
616
617     /* Go through each socket in each list to count number of sockets which
618        currently match */
619     for(i = 0; i < maxfdp1; i++)
620     {
621         if (FD_ISSET(i, readset))
622         {
623             /* See if netconn of this socket is ready for read */
624             p_sock = get_socket(i);
625             if (p_sock && (p_sock->lastdata || p_sock->rcvevent))
626             {
627                 FD_SET(i, &lreadset);
628                 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_selscan: fd=%d ready for reading\n", i));
629                 nready++;
630             }
631         }
632         if (FD_ISSET(i, writeset))
633         {
634             /* See if netconn of this socket is ready for write */
635             p_sock = get_socket(i);
636             if (p_sock && p_sock->sendevent)
637             {
638                 FD_SET(i, &lwriteset);
639                 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_selscan: fd=%d ready for writing\n", i));
640                 nready++;
641             }
642         }
643     }
644     *readset = lreadset;
645     *writeset = lwriteset;
646     FD_ZERO(exceptset);
647
648     return nready;
649 }
650
651
652
653 int
654 lwip_select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset,
655                struct timeval *timeout)
656 {
657     int i;
658     int nready;
659     fd_set lreadset, lwriteset, lexceptset;
660     u32_t msectimeout;
661     struct lwip_select_cb select_cb;
662     struct lwip_select_cb *p_selcb;
663
664     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select(%d, %p, %p, %p, tvsec=%ld tvusec=%ld)\n", maxfdp1, (void *)readset, (void *) writeset, (void *) exceptset, timeout ? timeout->tv_sec : -1L, timeout ? timeout->tv_usec : -1L));
665
666     select_cb.next = 0;
667     select_cb.readset = readset;
668     select_cb.writeset = writeset;
669     select_cb.exceptset = exceptset;
670     select_cb.sem_signalled = 0;
671
672     /* Protect ourselves searching through the list */
673     if (!selectsem)
674         selectsem = sys_sem_new(1);
675     sys_sem_wait(selectsem);
676
677     if (readset)
678         lreadset = *readset;
679     else
680         FD_ZERO(&lreadset);
681     if (writeset)
682         lwriteset = *writeset;
683     else
684         FD_ZERO(&lwriteset);
685     if (exceptset)
686         lexceptset = *exceptset;
687     else
688         FD_ZERO(&lexceptset);
689
690     /* Go through each socket in each list to count number of sockets which
691        currently match */
692     nready = lwip_selscan(maxfdp1, &lreadset, &lwriteset, &lexceptset);
693
694     /* If we don't have any current events, then suspend if we are supposed to */
695     if (!nready)
696     {
697         if (timeout && timeout->tv_sec == 0 && timeout->tv_usec == 0)
698         {
699             sys_sem_signal(selectsem);
700             if (readset)
701                 FD_ZERO(readset);
702             if (writeset)
703                 FD_ZERO(writeset);
704             if (exceptset)
705                 FD_ZERO(exceptset);
706
707             LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select: no timeout, returning 0\n"));
708             set_errno(0);
709
710             return 0;
711         }
712
713         /* add our semaphore to list */
714         /* We don't actually need any dynamic memory. Our entry on the
715          * list is only valid while we are in this function, so it's ok
716          * to use local variables */
717
718         select_cb.sem = sys_sem_new(0);
719         /* Note that we are still protected */
720         /* Put this select_cb on top of list */
721         select_cb.next = select_cb_list;
722         select_cb_list = &select_cb;
723
724         /* Now we can safely unprotect */
725         sys_sem_signal(selectsem);
726
727         /* Now just wait to be woken */
728         if (timeout == 0)
729             /* Wait forever */
730             msectimeout = 0;
731         else
732             msectimeout =  ((timeout->tv_sec * 1000) + ((timeout->tv_usec + 500)/1000));
733
734         i = sys_sem_wait_timeout(select_cb.sem, msectimeout);
735
736         /* Take us off the list */
737         sys_sem_wait(selectsem);
738         if (select_cb_list == &select_cb)
739             select_cb_list = select_cb.next;
740         else
741             for (p_selcb = select_cb_list; p_selcb; p_selcb = p_selcb->next)
742                 if (p_selcb->next == &select_cb)
743                 {
744                     p_selcb->next = select_cb.next;
745                     break;
746                 }
747
748         sys_sem_signal(selectsem);
749
750         sys_sem_free(select_cb.sem);
751         if (i == 0)             /* Timeout */
752         {
753             if (readset)
754                 FD_ZERO(readset);
755             if (writeset)
756                 FD_ZERO(writeset);
757             if (exceptset)
758                 FD_ZERO(exceptset);
759
760             LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select: timeout expired\n"));
761             set_errno(0);
762
763             return 0;
764         }
765
766         if (readset)
767             lreadset = *readset;
768         else
769             FD_ZERO(&lreadset);
770         if (writeset)
771             lwriteset = *writeset;
772         else
773             FD_ZERO(&lwriteset);
774         if (exceptset)
775             lexceptset = *exceptset;
776         else
777             FD_ZERO(&lexceptset);
778
779         /* See what's set */
780         nready = lwip_selscan(maxfdp1, &lreadset, &lwriteset, &lexceptset);
781     }
782     else
783         sys_sem_signal(selectsem);
784
785     if (readset)
786         *readset = lreadset;
787     if (writeset)
788         *writeset = lwriteset;
789     if (exceptset)
790         *exceptset = lexceptset;
791
792     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select: nready=%d\n", nready));
793     set_errno(0);
794
795     return nready;
796 }
797
798
799 static void
800 event_callback(struct netconn *conn, enum netconn_evt evt, u16_t len)
801 {
802     int s;
803     struct lwip_socket *sock;
804     struct lwip_select_cb *scb;
805
806     /* Get socket */
807     if (conn)
808     {
809         s = conn->socket;
810         if (s < 0)
811         {
812             /* Data comes in right away after an accept, even though
813              * the server task might not have created a new socket yet.
814              * Just count down (or up) if that's the case and we
815              * will use the data later. Note that only receive events
816              * can happen before the new socket is set up. */
817             if (evt == NETCONN_EVT_RCVPLUS)
818                 conn->socket--;
819             return;
820         }
821
822         sock = get_socket(s);
823         if (!sock)
824             return;
825     }
826     else
827         return;
828
829     if (!selectsem)
830         selectsem = sys_sem_new(1);
831
832     sys_sem_wait(selectsem);
833     /* Set event as required */
834     switch (evt)
835     {
836       case NETCONN_EVT_RCVPLUS:
837         sock->rcvevent++;
838         break;
839       case NETCONN_EVT_RCVMINUS:
840         sock->rcvevent--;
841         break;
842       case NETCONN_EVT_SENDPLUS:
843         sock->sendevent = 1;
844         break;
845       case NETCONN_EVT_SENDMINUS:
846         sock->sendevent = 0;
847         break;
848     }
849     sys_sem_signal(selectsem);
850
851     /* Now decide if anyone is waiting for this socket */
852     /* NOTE: This code is written this way to protect the select link list
853        but to avoid a deadlock situation by releasing socksem before
854        signalling for the select. This means we need to go through the list
855        multiple times ONLY IF a select was actually waiting. We go through
856        the list the number of waiting select calls + 1. This list is
857        expected to be small. */
858     while (1)
859     {
860         sys_sem_wait(selectsem);
861         for (scb = select_cb_list; scb; scb = scb->next)
862         {
863             if (scb->sem_signalled == 0)
864             {
865                 /* Test this select call for our socket */
866                 if (scb->readset && FD_ISSET(s, scb->readset))
867                     if (sock->rcvevent)
868                         break;
869                 if (scb->writeset && FD_ISSET(s, scb->writeset))
870                     if (sock->sendevent)
871                         break;
872             }
873         }
874         if (scb)
875         {
876             scb->sem_signalled = 1;
877             sys_sem_signal(selectsem);
878             sys_sem_signal(scb->sem);
879         } else {
880             sys_sem_signal(selectsem);
881             break;
882         }
883     }
884
885 }
886
887
888
889
890 int lwip_shutdown(int s, int how)
891 {
892   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_shutdown(%d, how=%d)\n", s, how));
893   return lwip_close(s); /* XXX temporary hack until proper implementation */
894 }
895
896 int lwip_getpeername (int s, struct sockaddr *name, socklen_t *namelen)
897 {
898   struct lwip_socket *sock;
899   struct sockaddr_in sin;
900   struct ip_addr naddr;
901
902   sock = get_socket(s);
903   if (!sock) {
904     set_errno(EBADF);
905     return -1;
906   }
907
908   memset(&sin, 0, sizeof(sin));
909   sin.sin_len = sizeof(sin);
910   sin.sin_family = AF_INET;
911
912   /* get the IP address and port of the remote host */
913   netconn_peer(sock->conn, &naddr, &sin.sin_port);
914
915   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getpeername(%d, addr=", s));
916   ip_addr_debug_print(SOCKETS_DEBUG, &naddr);
917   LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%d)\n", sin.sin_port));
918
919   sin.sin_port = htons(sin.sin_port);
920   sin.sin_addr.s_addr = naddr.addr;
921
922   if (*namelen > sizeof(sin))
923       *namelen = sizeof(sin);
924
925   memcpy(name, &sin, *namelen);
926   sock_set_errno(sock, 0);
927   return 0;
928 }
929
930 int lwip_getsockname (int s, struct sockaddr *name, socklen_t *namelen)
931 {
932   struct lwip_socket *sock;
933   struct sockaddr_in sin;
934   struct ip_addr *naddr;
935
936   sock = get_socket(s);
937   if (!sock) {
938     set_errno(EBADF);
939     return -1;
940   }
941
942   memset(&sin, 0, sizeof(sin));
943   sin.sin_len = sizeof(sin);
944   sin.sin_family = AF_INET;
945
946   /* get the IP address and port of the remote host */
947   netconn_addr(sock->conn, &naddr, &sin.sin_port);
948
949   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockname(%d, addr=", s));
950   ip_addr_debug_print(SOCKETS_DEBUG, naddr);
951   LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%d)\n", sin.sin_port));
952
953   sin.sin_port = htons(sin.sin_port);
954   sin.sin_addr.s_addr = naddr->addr;
955
956   if (*namelen > sizeof(sin))
957       *namelen = sizeof(sin);
958
959   memcpy(name, &sin, *namelen);
960   sock_set_errno(sock, 0);
961   return 0;
962 }
963
964 int lwip_getsockopt (int s, int level, int optname, void *optval, socklen_t *optlen)
965 {
966   int err = 0;
967   struct lwip_socket *sock = get_socket(s);
968
969   if(!sock) {
970         set_errno(EBADF);
971     return -1;
972   }
973
974   if( NULL == optval || NULL == optlen ) {
975     sock_set_errno( sock, EFAULT );
976     return -1;
977   }
978
979   /* Do length and type checks for the various options first, to keep it readable. */
980   switch( level ) {
981    
982 /* Level: SOL_SOCKET */
983   case SOL_SOCKET:
984       switch(optname) {
985          
986       case SO_ACCEPTCONN:
987       case SO_BROADCAST:
988       /* UNIMPL case SO_DEBUG: */
989       /* UNIMPL case SO_DONTROUTE: */
990       case SO_ERROR:
991       case SO_KEEPALIVE:
992       /* UNIMPL case SO_OOBINLINE: */
993       /* UNIMPL case SO_RCVBUF: */
994       /* UNIMPL case SO_SNDBUF: */
995       /* UNIMPL case SO_RCVLOWAT: */
996       /* UNIMPL case SO_SNDLOWAT: */
997 #if SO_REUSE
998       case SO_REUSEADDR:
999       case SO_REUSEPORT:
1000 #endif /* SO_REUSE */
1001       case SO_TYPE:
1002       /* UNIMPL case SO_USELOOPBACK: */
1003         if( *optlen < sizeof(int) ) {
1004           err = EINVAL;
1005         }
1006           break;
1007
1008       default:
1009         LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, UNIMPL: optname=0x%x, ..)\n", s, optname));
1010         err = ENOPROTOOPT;
1011       }  /* switch */
1012       break;
1013                      
1014 /* Level: IPPROTO_IP */
1015   case IPPROTO_IP:
1016       switch(optname) {
1017       /* UNIMPL case IP_HDRINCL: */
1018       /* UNIMPL case IP_RCVDSTADDR: */
1019       /* UNIMPL case IP_RCVIF: */
1020       case IP_TTL:
1021       case IP_TOS:
1022         if( *optlen < sizeof(int) ) {
1023           err = EINVAL;
1024         }
1025         break;
1026
1027       default:
1028         LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, UNIMPL: optname=0x%x, ..)\n", s, optname));
1029         err = ENOPROTOOPT;
1030       }  /* switch */
1031       break;
1032          
1033 /* Level: IPPROTO_TCP */
1034   case IPPROTO_TCP:
1035       if( *optlen < sizeof(int) ) {
1036         err = EINVAL;
1037         break;
1038     }
1039       
1040       /* If this is no TCP socket, ignore any options. */
1041       if ( sock->conn->type != NETCONN_TCP ) return 0;
1042
1043       switch( optname ) {
1044       case TCP_NODELAY:
1045       case TCP_KEEPALIVE:
1046         break;
1047          
1048       default:
1049         LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_TCP, UNIMPL: optname=0x%x, ..)\n", s, optname));
1050         err = ENOPROTOOPT;
1051       }  /* switch */
1052       break;
1053
1054 /* UNDEFINED LEVEL */
1055   default:
1056       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, level=0x%x, UNIMPL: optname=0x%x, ..)\n", s, level, optname));
1057       err = ENOPROTOOPT;
1058   }  /* switch */
1059
1060    
1061   if( 0 != err ) {
1062     sock_set_errno(sock, err);
1063     return -1;
1064   }
1065    
1066
1067
1068   /* Now do the actual option processing */
1069
1070   switch(level) {
1071    
1072 /* Level: SOL_SOCKET */
1073   case SOL_SOCKET:
1074     switch( optname ) {
1075
1076     /* The option flags */
1077     case SO_ACCEPTCONN:
1078     case SO_BROADCAST:
1079     /* UNIMPL case SO_DEBUG: */
1080     /* UNIMPL case SO_DONTROUTE: */
1081     case SO_KEEPALIVE:
1082     /* UNIMPL case SO_OOBINCLUDE: */
1083 #if SO_REUSE
1084     case SO_REUSEADDR:
1085     case SO_REUSEPORT:
1086 #endif /* SO_REUSE */
1087     /*case SO_USELOOPBACK: UNIMPL */
1088       *(int*)optval = sock->conn->pcb.tcp->so_options & optname;
1089       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, optname=0x%x, ..) = %s\n", s, optname, (*(int*)optval?"on":"off")));
1090       break;
1091
1092     case SO_TYPE:
1093       switch (sock->conn->type) {
1094       case NETCONN_RAW:
1095         *(int*)optval = SOCK_RAW;
1096         break;
1097       case NETCONN_TCP:
1098         *(int*)optval = SOCK_STREAM;
1099         break;
1100       case NETCONN_UDP:
1101       case NETCONN_UDPLITE:
1102       case NETCONN_UDPNOCHKSUM:
1103         *(int*)optval = SOCK_DGRAM;
1104         break;
1105       default: /* unrecognized socket type */
1106         *(int*)optval = sock->conn->type;
1107         LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, SO_TYPE): unrecognized socket type %d\n", s, *(int *)optval));
1108       }  /* switch */
1109       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, SO_TYPE) = %d\n", s, *(int *)optval));
1110       break;
1111
1112     case SO_ERROR:
1113       *(int *)optval = sock->err;
1114       sock->err = 0;
1115       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, SO_ERROR) = %d\n", s, *(int *)optval));
1116       break;
1117     }  /* switch */
1118     break;
1119
1120 /* Level: IPPROTO_IP */
1121   case IPPROTO_IP:
1122     switch( optname ) {
1123     case IP_TTL:
1124       *(int*)optval = sock->conn->pcb.tcp->ttl;
1125       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_TTL) = %d\n", s, *(int *)optval));
1126       break;
1127     case IP_TOS:
1128       *(int*)optval = sock->conn->pcb.tcp->tos;
1129       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_TOS) = %d\n", s, *(int *)optval));
1130       break;
1131     }  /* switch */
1132     break;
1133
1134 /* Level: IPPROTO_TCP */
1135   case IPPROTO_TCP:
1136     switch( optname ) {
1137     case TCP_NODELAY:
1138       *(int*)optval = (sock->conn->pcb.tcp->flags & TF_NODELAY);
1139       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_TCP, TCP_NODELAY) = %s\n", s, (*(int*)optval)?"on":"off") );
1140       break;
1141     case TCP_KEEPALIVE:
1142       *(int*)optval = sock->conn->pcb.tcp->keepalive;
1143       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, TCP_KEEPALIVE) = %d\n", s, *(int *)optval));
1144       break;
1145     }  /* switch */
1146     break;
1147   }
1148
1149
1150   sock_set_errno(sock, err);
1151   return err ? -1 : 0;
1152 }
1153
1154 int lwip_setsockopt (int s, int level, int optname, const void *optval, socklen_t optlen)
1155 {
1156   struct lwip_socket *sock = get_socket(s);
1157   int err = 0;
1158
1159   if(!sock) {
1160         set_errno(EBADF);
1161     return -1;
1162   }
1163
1164   if( NULL == optval ) {
1165     sock_set_errno( sock, EFAULT );
1166     return -1;
1167   }
1168
1169
1170   /* Do length and type checks for the various options first, to keep it readable. */
1171   switch( level ) {
1172
1173 /* Level: SOL_SOCKET */
1174   case SOL_SOCKET:
1175     switch(optname) {
1176
1177     case SO_BROADCAST:
1178     /* UNIMPL case SO_DEBUG: */
1179     /* UNIMPL case SO_DONTROUTE: */
1180     case SO_KEEPALIVE:
1181     /* UNIMPL case SO_OOBINLINE: */
1182     /* UNIMPL case SO_RCVBUF: */
1183     /* UNIMPL case SO_SNDBUF: */
1184     /* UNIMPL case SO_RCVLOWAT: */
1185     /* UNIMPL case SO_SNDLOWAT: */
1186 #if SO_REUSE
1187     case SO_REUSEADDR:
1188     case SO_REUSEPORT:
1189 #endif /* SO_REUSE */
1190     /* UNIMPL case SO_USELOOPBACK: */
1191       if( optlen < sizeof(int) ) {
1192         err = EINVAL;
1193       }
1194       break;
1195     default:
1196       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, SOL_SOCKET, UNIMPL: optname=0x%x, ..)\n", s, optname));
1197       err = ENOPROTOOPT;
1198     }  /* switch */
1199     break;
1200
1201 /* Level: IPPROTO_IP */
1202   case IPPROTO_IP:
1203     switch(optname) {
1204     /* UNIMPL case IP_HDRINCL: */
1205     /* UNIMPL case IP_RCVDSTADDR: */
1206     /* UNIMPL case IP_RCVIF: */
1207     case IP_TTL:
1208     case IP_TOS:
1209       if( optlen < sizeof(int) ) {
1210         err = EINVAL;
1211       }
1212         break;
1213       default:
1214       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IP, UNIMPL: optname=0x%x, ..)\n", s, optname));
1215       err = ENOPROTOOPT;
1216     }  /* switch */
1217     break;
1218
1219 /* Level: IPPROTO_TCP */
1220   case IPPROTO_TCP:
1221     if( optlen < sizeof(int) ) {
1222       err = EINVAL;
1223         break;
1224     }
1225
1226     /* If this is no TCP socket, ignore any options. */
1227     if ( sock->conn->type != NETCONN_TCP ) return 0;
1228
1229     switch( optname ) {
1230     case TCP_NODELAY:
1231     case TCP_KEEPALIVE:
1232       break;
1233
1234     default:
1235       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, UNIMPL: optname=0x%x, ..)\n", s, optname));
1236       err = ENOPROTOOPT;
1237     }  /* switch */
1238     break;
1239
1240 /* UNDEFINED LEVEL */      
1241   default:
1242     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, level=0x%x, UNIMPL: optname=0x%x, ..)\n", s, level, optname));
1243     err = ENOPROTOOPT;
1244   }  /* switch */
1245
1246
1247   if( 0 != err ) {
1248     sock_set_errno(sock, err);
1249     return -1;
1250   }
1251
1252
1253
1254   /* Now do the actual option processing */
1255
1256   switch(level) {
1257
1258 /* Level: SOL_SOCKET */
1259   case SOL_SOCKET:
1260     switch(optname) {
1261
1262     /* The option flags */
1263     case SO_BROADCAST:
1264     /* UNIMPL case SO_DEBUG: */
1265     /* UNIMPL case SO_DONTROUTE: */
1266     case SO_KEEPALIVE:
1267     /* UNIMPL case SO_OOBINCLUDE: */
1268 #if SO_REUSE
1269     case SO_REUSEADDR:
1270     case SO_REUSEPORT:
1271 #endif /* SO_REUSE */
1272     /* UNIMPL case SO_USELOOPBACK: */
1273       if ( *(int*)optval ) {
1274         sock->conn->pcb.tcp->so_options |= optname;
1275       } else {
1276         sock->conn->pcb.tcp->so_options &= ~optname;
1277       }
1278       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, SOL_SOCKET, optname=0x%x, ..) -> %s\n", s, optname, (*(int*)optval?"on":"off")));
1279       break;
1280     }  /* switch */
1281     break;
1282
1283 /* Level: IPPROTO_IP */
1284   case IPPROTO_IP:
1285     switch( optname ) {
1286     case IP_TTL:
1287       sock->conn->pcb.tcp->ttl = (u8_t)(*(int*)optval);
1288       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IP, IP_TTL, ..) -> %u\n", s, sock->conn->pcb.tcp->ttl));
1289       break;
1290     case IP_TOS:
1291       sock->conn->pcb.tcp->tos = (u8_t)(*(int*)optval);
1292       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IP, IP_TOS, ..)-> %u\n", s, sock->conn->pcb.tcp->tos));
1293       break;
1294     }  /* switch */
1295     break;
1296
1297 /* Level: IPPROTO_TCP */
1298   case IPPROTO_TCP:
1299     switch( optname ) {
1300     case TCP_NODELAY:
1301       if ( *(int*)optval ) {
1302         sock->conn->pcb.tcp->flags |= TF_NODELAY;
1303       } else {
1304         sock->conn->pcb.tcp->flags &= ~TF_NODELAY;
1305       }
1306       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_NODELAY) -> %s\n", s, (*(int *)optval)?"on":"off") );
1307       break;
1308     case TCP_KEEPALIVE:
1309       sock->conn->pcb.tcp->keepalive = (u32_t)(*(int*)optval);
1310       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPALIVE) -> %u\n", s, sock->conn->pcb.tcp->keepalive));
1311       break;
1312     }  /* switch */
1313     break;
1314   }  /* switch */
1315
1316   sock_set_errno(sock, err);
1317   return err ? -1 : 0;
1318 }
1319
1320 int lwip_ioctl(int s, long cmd, void *argp)
1321 {
1322   struct lwip_socket *sock = get_socket(s);
1323
1324   if(!sock) {
1325         set_errno(EBADF);
1326     return -1;
1327   }
1328
1329   switch (cmd) {
1330   case FIONREAD:
1331     if (!argp) {
1332       sock_set_errno(sock, EINVAL);
1333       return -1;
1334     }
1335
1336     *((u16_t*)argp) = sock->conn->recv_avail;
1337
1338     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(%d, FIONREAD, %p) = %u\n", s, argp, *((u16_t*)argp)));
1339     sock_set_errno(sock, 0);
1340     return 0;
1341
1342   case FIONBIO:
1343     if (argp && *(u32_t*)argp)
1344       sock->flags |= O_NONBLOCK;
1345     else
1346       sock->flags &= ~O_NONBLOCK;
1347     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(%d, FIONBIO, %d)\n", s, !!(sock->flags & O_NONBLOCK)));
1348     sock_set_errno(sock, 0);
1349     return 0;
1350
1351   default:
1352     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(%d, UNIMPL: 0x%lx, %p)\n", s, cmd, argp));
1353     sock_set_errno(sock, ENOSYS); /* not yet implemented */
1354     return -1;
1355   }
1356 }
1357