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