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