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