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