Ethernet for Nucleo and Disco board STM32F746 works with gcc and arm. IAC is untested

Dependents:   STM32F746_iothub_client_sample_mqtt DISCO-F746NG_Ethernet Nucleo_F746ZG_Ethernet thethingsiO-DISCO_F746NG-mqtt ... more

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers sockets.c Source File

sockets.c

Go to the documentation of this file.
00001 /**
00002  * @file
00003  * Sockets BSD-Like API module
00004  *
00005  */
00006 
00007 /*
00008  * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
00009  * All rights reserved.
00010  *
00011  * Redistribution and use in source and binary forms, with or without modification,
00012  * are permitted provided that the following conditions are met:
00013  *
00014  * 1. Redistributions of source code must retain the above copyright notice,
00015  *    this list of conditions and the following disclaimer.
00016  * 2. Redistributions in binary form must reproduce the above copyright notice,
00017  *    this list of conditions and the following disclaimer in the documentation
00018  *    and/or other materials provided with the distribution.
00019  * 3. The name of the author may not be used to endorse or promote products
00020  *    derived from this software without specific prior written permission.
00021  *
00022  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
00023  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
00024  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
00025  * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
00026  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
00027  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00028  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
00029  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
00030  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
00031  * OF SUCH DAMAGE.
00032  *
00033  * This file is part of the lwIP TCP/IP stack.
00034  *
00035  * Author: Adam Dunkels <adam@sics.se>
00036  *
00037  * Improved by Marc Boucher <marc@mbsi.ca> and David Haas <dhaas@alum.rpi.edu>
00038  *
00039  */
00040 
00041 #include "lwip/opt.h"
00042 
00043 #if LWIP_SOCKET /* don't build if not configured for use in lwipopts.h */
00044 
00045 #include "lwip/sockets.h"
00046 #include "lwip/api.h"
00047 #include "lwip/sys.h"
00048 #include "lwip/igmp.h"
00049 #include "lwip/inet.h"
00050 #include "lwip/tcp.h"
00051 #include "lwip/raw.h"
00052 #include "lwip/udp.h"
00053 #include "lwip/tcpip.h"
00054 #include "lwip/pbuf.h"
00055 #if LWIP_CHECKSUM_ON_COPY
00056 #include "lwip/inet_chksum.h"
00057 #endif
00058 
00059 #include <string.h>
00060 
00061 #define NUM_SOCKETS MEMP_NUM_NETCONN
00062 
00063 /** Contains all internal pointers and states used for a socket */
00064 struct lwip_sock {
00065   /** sockets currently are built on netconns, each socket has one netconn */
00066   struct netconn *conn;
00067   /** data that was left from the previous read */
00068   void *lastdata;
00069   /** offset in the data that was left from the previous read */
00070   u16_t lastoffset;
00071   /** number of times data was received, set by event_callback(),
00072       tested by the receive and select functions */
00073   s16_t rcvevent;
00074   /** number of times data was ACKed (free send buffer), set by event_callback(),
00075       tested by select */
00076   u16_t sendevent;
00077   /** error happened for this socket, set by event_callback(), tested by select */
00078   u16_t errevent;
00079   /** last error that occurred on this socket */
00080   int err;
00081   /** counter of how many threads are waiting for this socket using select */
00082   int select_waiting;
00083 };
00084 
00085 /** Description for a task waiting in select */
00086 struct lwip_select_cb {
00087   /** Pointer to the next waiting task */
00088   struct lwip_select_cb *next;
00089   /** Pointer to the previous waiting task */
00090   struct lwip_select_cb *prev;
00091   /** readset passed to select */
00092   fd_set *readset;
00093   /** writeset passed to select */
00094   fd_set *writeset;
00095   /** unimplemented: exceptset passed to select */
00096   fd_set *exceptset;
00097   /** don't signal the same semaphore twice: set to 1 when signalled */
00098   int sem_signalled;
00099   /** semaphore to wake up a task waiting for select */
00100   sys_sem_t sem;
00101 };
00102 
00103 /** This struct is used to pass data to the set/getsockopt_internal
00104  * functions running in tcpip_thread context (only a void* is allowed) */
00105 struct lwip_setgetsockopt_data {
00106   /** socket struct for which to change options */
00107   struct lwip_sock *sock;
00108 #ifdef LWIP_DEBUG
00109   /** socket index for which to change options */
00110   int s;
00111 #endif /* LWIP_DEBUG */
00112   /** level of the option to process */
00113   int level;
00114   /** name of the option to process */
00115   int optname;
00116   /** set: value to set the option to
00117     * get: value of the option is stored here */
00118   void *optval;
00119   /** size of *optval */
00120   socklen_t *optlen;
00121   /** if an error occures, it is temporarily stored here */
00122   err_t err;
00123 };
00124 
00125 /** The global array of available sockets */
00126 static struct lwip_sock sockets[NUM_SOCKETS];
00127 /** The global list of tasks waiting for select */
00128 static struct lwip_select_cb *select_cb_list;
00129 /** This counter is increased from lwip_select when the list is chagned
00130     and checked in event_callback to see if it has changed. */
00131 static volatile int select_cb_ctr;
00132 
00133 /** Table to quickly map an lwIP error (err_t) to a socket error
00134   * by using -err as an index */
00135 static const int err_to_errno_table[] = {
00136   0,             /* ERR_OK          0      No error, everything OK. */
00137   ENOMEM,        /* ERR_MEM        -1      Out of memory error.     */
00138   ENOBUFS,       /* ERR_BUF        -2      Buffer error.            */
00139   EWOULDBLOCK,   /* ERR_TIMEOUT    -3      Timeout                  */
00140   EHOSTUNREACH,  /* ERR_RTE        -4      Routing problem.         */
00141   EINPROGRESS,   /* ERR_INPROGRESS -5      Operation in progress    */
00142   EINVAL,        /* ERR_VAL        -6      Illegal value.           */
00143   EWOULDBLOCK,   /* ERR_WOULDBLOCK -7      Operation would block.   */
00144   EADDRINUSE,    /* ERR_USE        -8      Address in use.          */
00145   EALREADY,      /* ERR_ISCONN     -9      Already connected.       */
00146   ECONNABORTED,  /* ERR_ABRT       -10     Connection aborted.      */
00147   ECONNRESET,    /* ERR_RST        -11     Connection reset.        */
00148   ENOTCONN,      /* ERR_CLSD       -12     Connection closed.       */
00149   ENOTCONN,      /* ERR_CONN       -13     Not connected.           */
00150   EIO,           /* ERR_ARG        -14     Illegal argument.        */
00151   -1,            /* ERR_IF         -15     Low-level netif error    */
00152 };
00153 
00154 #define ERR_TO_ERRNO_TABLE_SIZE \
00155   (sizeof(err_to_errno_table)/sizeof(err_to_errno_table[0]))
00156 
00157 #define err_to_errno(err) \
00158   ((unsigned)(-(err)) < ERR_TO_ERRNO_TABLE_SIZE ? \
00159     err_to_errno_table[-(err)] : EIO)
00160 
00161 #ifdef ERRNO
00162 #if defined(TOOLCHAIN_ARM_STD)
00163 static int errno;
00164 #endif
00165 #ifndef set_errno
00166 #define set_errno(err) errno = (err)
00167 #endif
00168 #else /* ERRNO */
00169 #define set_errno(err)
00170 #endif /* ERRNO */
00171 
00172 #define sock_set_errno(sk, e) do { \
00173   sk->err = (e); \
00174   set_errno(sk->err); \
00175 } while (0)
00176 
00177 /* Forward delcaration of some functions */
00178 static void event_callback(struct netconn *conn, enum netconn_evt evt, u16_t len);
00179 static void lwip_getsockopt_internal(void *arg);
00180 static void lwip_setsockopt_internal(void *arg);
00181 
00182 /**
00183  * Initialize this module. This function has to be called before any other
00184  * functions in this module!
00185  */
00186 void
00187 lwip_socket_init(void)
00188 {
00189 }
00190 
00191 /**
00192  * Map a externally used socket index to the internal socket representation.
00193  *
00194  * @param s externally used socket index
00195  * @return struct lwip_sock for the socket or NULL if not found
00196  */
00197 static struct lwip_sock *
00198 get_socket(int s)
00199 {
00200   struct lwip_sock *sock;
00201 
00202   if ((s < 0) || (s >= NUM_SOCKETS)) {
00203     LWIP_DEBUGF(SOCKETS_DEBUG, ("get_socket(%d): invalid\n", s));
00204     set_errno(EBADF);
00205     return NULL;
00206   }
00207 
00208   sock = &sockets[s];
00209 
00210   if (!sock->conn) {
00211     LWIP_DEBUGF(SOCKETS_DEBUG, ("get_socket(%d): not active\n", s));
00212     set_errno(EBADF);
00213     return NULL;
00214   }
00215 
00216   return sock;
00217 }
00218 
00219 /**
00220  * Same as get_socket but doesn't set errno
00221  *
00222  * @param s externally used socket index
00223  * @return struct lwip_sock for the socket or NULL if not found
00224  */
00225 static struct lwip_sock *
00226 tryget_socket(int s)
00227 {
00228   if ((s < 0) || (s >= NUM_SOCKETS)) {
00229     return NULL;
00230   }
00231   if (!sockets[s].conn) {
00232     return NULL;
00233   }
00234   return &sockets[s];
00235 }
00236 
00237 /**
00238  * Allocate a new socket for a given netconn.
00239  *
00240  * @param newconn the netconn for which to allocate a socket
00241  * @param accepted 1 if socket has been created by accept(),
00242  *                 0 if socket has been created by socket()
00243  * @return the index of the new socket; -1 on error
00244  */
00245 static int
00246 alloc_socket(struct netconn *newconn, int accepted)
00247 {
00248   int i;
00249   SYS_ARCH_DECL_PROTECT(lev);
00250 
00251   /* allocate a new socket identifier */
00252   for (i = 0; i < NUM_SOCKETS; ++i) {
00253     /* Protect socket array */
00254     SYS_ARCH_PROTECT(lev);
00255     if (!sockets[i].conn) {
00256       sockets[i].conn       = newconn;
00257       /* The socket is not yet known to anyone, so no need to protect
00258          after having marked it as used. */
00259       SYS_ARCH_UNPROTECT(lev);
00260       sockets[i].lastdata   = NULL;
00261       sockets[i].lastoffset = 0;
00262       sockets[i].rcvevent   = 0;
00263       /* TCP sendbuf is empty, but the socket is not yet writable until connected
00264        * (unless it has been created by accept()). */
00265       sockets[i].sendevent  = (newconn->type == NETCONN_TCP ? (accepted != 0) : 1);
00266       sockets[i].errevent   = 0;
00267       sockets[i].err        = 0;
00268       sockets[i].select_waiting = 0;
00269       return i;
00270     }
00271     SYS_ARCH_UNPROTECT(lev);
00272   }
00273   return -1;
00274 }
00275 
00276 /** Free a socket. The socket's netconn must have been
00277  * delete before!
00278  *
00279  * @param sock the socket to free
00280  * @param is_tcp != 0 for TCP sockets, used to free lastdata
00281  */
00282 static void
00283 free_socket(struct lwip_sock *sock, int is_tcp)
00284 {
00285   void *lastdata;
00286   SYS_ARCH_DECL_PROTECT(lev);
00287 
00288   lastdata         = sock->lastdata;
00289   sock->lastdata   = NULL;
00290   sock->lastoffset = 0;
00291   sock->err        = 0;
00292 
00293   /* Protect socket array */
00294   SYS_ARCH_PROTECT(lev);
00295   sock->conn       = NULL;
00296   SYS_ARCH_UNPROTECT(lev);
00297   /* don't use 'sock' after this line, as another task might have allocated it */
00298 
00299   if (lastdata != NULL) {
00300     if (is_tcp) {
00301       pbuf_free((struct pbuf *)lastdata);
00302     } else {
00303       netbuf_delete((struct netbuf *)lastdata);
00304     }
00305   }
00306 }
00307 
00308 /* Below this, the well-known socket functions are implemented.
00309  * Use google.com or opengroup.org to get a good description :-)
00310  *
00311  * Exceptions are documented!
00312  */
00313 
00314 int
00315 lwip_accept(int s, struct sockaddr *addr, socklen_t *addrlen)
00316 {
00317   struct lwip_sock *sock, *nsock;
00318   struct netconn *newconn;
00319   ip_addr_t naddr;
00320   u16_t port;
00321   int newsock;
00322   struct sockaddr_in sin;
00323   err_t err;
00324   SYS_ARCH_DECL_PROTECT(lev);
00325 
00326   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d)...\n", s));
00327   sock = get_socket(s);
00328   if (!sock) {
00329     return -1;
00330   }
00331 
00332   if (netconn_is_nonblocking(sock->conn) && (sock->rcvevent <= 0)) {
00333     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d): returning EWOULDBLOCK\n", s));
00334     sock_set_errno(sock, EWOULDBLOCK);
00335     return -1;
00336   }
00337 
00338   /* wait for a new connection */
00339   err = netconn_accept(sock->conn, &newconn);
00340   if (err != ERR_OK) {
00341     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d): netconn_acept failed, err=%d\n", s, err));
00342     if (netconn_type(sock->conn) != NETCONN_TCP) {
00343       sock_set_errno(sock, EOPNOTSUPP);
00344       return EOPNOTSUPP;
00345     }
00346     sock_set_errno(sock, err_to_errno(err));
00347     return -1;
00348   }
00349 
00350   LWIP_ASSERT("newconn != NULL", newconn != NULL);
00351   /* Prevent automatic window updates, we do this on our own! */
00352   netconn_set_noautorecved(newconn, 1);
00353 
00354   /* get the IP address and port of the remote host */
00355   err = netconn_peer(newconn, &naddr, &port);
00356   if (err != ERR_OK) {
00357     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d): netconn_peer failed, err=%d\n", s, err));
00358     netconn_delete(newconn);
00359     sock_set_errno(sock, err_to_errno(err));
00360     return -1;
00361   }
00362 
00363   /* Note that POSIX only requires us to check addr is non-NULL. addrlen must
00364    * not be NULL if addr is valid.
00365    */
00366   if (NULL != addr) {
00367     LWIP_ASSERT("addr valid but addrlen NULL", addrlen != NULL);
00368     memset(&sin, 0, sizeof(sin));
00369     sin.sin_len = sizeof(sin);
00370     sin.sin_family = AF_INET;
00371     sin.sin_port = htons(port);
00372     inet_addr_from_ipaddr(&sin.sin_addr, &naddr);
00373 
00374     if (*addrlen > sizeof(sin))
00375       *addrlen = sizeof(sin);
00376 
00377     MEMCPY(addr, &sin, *addrlen);
00378   }
00379 
00380   newsock = alloc_socket(newconn, 1);
00381   if (newsock == -1) {
00382     LWIP_DEBUGF(SOCKETS_DEBUG, ("socket: alloc socket failed\n"));
00383     netconn_delete(newconn);
00384     sock_set_errno(sock, ENFILE);
00385     return -1;
00386   }
00387   LWIP_ASSERT("invalid socket index", (newsock >= 0) && (newsock < NUM_SOCKETS));
00388   LWIP_ASSERT("newconn->callback == event_callback", newconn->callback == event_callback);
00389   nsock = &sockets[newsock];
00390 
00391   /* See event_callback: If data comes in right away after an accept, even
00392    * though the server task might not have created a new socket yet.
00393    * In that case, newconn->socket is counted down (newconn->socket--),
00394    * so nsock->rcvevent is >= 1 here!
00395    */
00396   SYS_ARCH_PROTECT(lev);
00397   nsock->rcvevent += (s16_t)(-1 - newconn->socket);
00398   newconn->socket = newsock;
00399   SYS_ARCH_UNPROTECT(lev);
00400 
00401   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d) returning new sock=%d addr= 0x%x\r\n", s, newsock,newconn));
00402   ip_addr_debug_print(SOCKETS_DEBUG, &naddr);
00403   LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F"\n", port));
00404 
00405   sock_set_errno(sock, 0);
00406   return newsock;
00407 }
00408 
00409 int
00410 lwip_bind(int s, const struct sockaddr *name, socklen_t namelen)
00411 {
00412   struct lwip_sock *sock;
00413   ip_addr_t local_addr;
00414   u16_t local_port;
00415   err_t err;
00416   const struct sockaddr_in *name_in;
00417 
00418   sock = get_socket(s);
00419   if (!sock) {
00420     return -1;
00421   }
00422 
00423   /* check size, familiy and alignment of 'name' */
00424   LWIP_ERROR("lwip_bind: invalid address", ((namelen == sizeof(struct sockaddr_in)) &&
00425              ((name->sa_family) == AF_INET) && ((((mem_ptr_t)name) % 4) == 0)),
00426              sock_set_errno(sock, err_to_errno(ERR_ARG)); return -1;);
00427   name_in = (const struct sockaddr_in *)(void*)name;
00428 
00429   inet_addr_to_ipaddr(&local_addr, &name_in->sin_addr);
00430   local_port = name_in->sin_port;
00431 
00432   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d, addr=", s));
00433   ip_addr_debug_print(SOCKETS_DEBUG, &local_addr);
00434   LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F")\n", ntohs(local_port)));
00435 
00436   err = netconn_bind(sock->conn, &local_addr, ntohs(local_port));
00437 
00438   if (err != ERR_OK) {
00439     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d) failed, err=%d\n", s, err));
00440     sock_set_errno(sock, err_to_errno(err));
00441     return -1;
00442   }
00443 
00444   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d) succeeded\n", s));
00445   sock_set_errno(sock, 0);
00446   return 0;
00447 }
00448 
00449 int
00450 lwip_close(int s)
00451 {
00452   struct lwip_sock *sock;
00453   int is_tcp = 0;
00454 
00455   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_close(%d)\n", s));
00456 
00457   sock = get_socket(s);
00458   if (!sock) {
00459     return -1;
00460   }
00461 
00462   if(sock->conn != NULL) {
00463     is_tcp = netconn_type(sock->conn) == NETCONN_TCP;
00464   } else {
00465     LWIP_ASSERT("sock->lastdata == NULL", sock->lastdata == NULL);
00466   }
00467 
00468   netconn_delete(sock->conn);
00469 
00470   free_socket(sock, is_tcp);
00471   set_errno(0);
00472   return 0;
00473 }
00474 
00475 int
00476 lwip_connect(int s, const struct sockaddr *name, socklen_t namelen)
00477 {
00478   struct lwip_sock *sock;
00479   err_t err;
00480   const struct sockaddr_in *name_in;
00481 
00482   sock = get_socket(s);
00483   if (!sock) {
00484     return -1;
00485   }
00486 
00487   /* check size, familiy and alignment of 'name' */
00488   LWIP_ERROR("lwip_connect: invalid address", ((namelen == sizeof(struct sockaddr_in)) &&
00489              ((name->sa_family) == AF_INET) && ((((mem_ptr_t)name) % 4) == 0)),
00490              sock_set_errno(sock, err_to_errno(ERR_ARG)); return -1;);
00491   name_in = (const struct sockaddr_in *)(void*)name;
00492 
00493   if (name_in->sin_family == AF_UNSPEC) {
00494     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d, AF_UNSPEC)\n", s));
00495     err = netconn_disconnect(sock->conn);
00496   } else {
00497     ip_addr_t remote_addr;
00498     u16_t remote_port;
00499 
00500     inet_addr_to_ipaddr(&remote_addr, &name_in->sin_addr);
00501     remote_port = name_in->sin_port;
00502 
00503     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d, addr=", s));
00504     ip_addr_debug_print(SOCKETS_DEBUG, &remote_addr);
00505     LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F")\n", ntohs(remote_port)));
00506 
00507     err = netconn_connect(sock->conn, &remote_addr, ntohs(remote_port));
00508   }
00509 
00510   if (err != ERR_OK) {
00511     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d) failed, err=%d\n", s, err));
00512     sock_set_errno(sock, err_to_errno(err));
00513     return -1;
00514   }
00515 
00516   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d) succeeded\n", s));
00517   sock_set_errno(sock, 0);
00518   return 0;
00519 }
00520 
00521 /**
00522  * Set a socket into listen mode.
00523  * The socket may not have been used for another connection previously.
00524  *
00525  * @param s the socket to set to listening mode
00526  * @param backlog (ATTENTION: needs TCP_LISTEN_BACKLOG=1)
00527  * @return 0 on success, non-zero on failure
00528  */
00529 int
00530 lwip_listen(int s, int backlog)
00531 {
00532   struct lwip_sock *sock;
00533   err_t err;
00534 
00535   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_listen(%d, backlog=%d)\n", s, backlog));
00536 
00537   sock = get_socket(s);
00538   if (!sock) {
00539     return -1;
00540   }
00541 
00542   /* limit the "backlog" parameter to fit in an u8_t */
00543   backlog = LWIP_MIN(LWIP_MAX(backlog, 0), 0xff);
00544 
00545   err = netconn_listen_with_backlog(sock->conn, (u8_t)backlog);
00546 
00547   if (err != ERR_OK) {
00548     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_listen(%d) failed, err=%d\n", s, err));
00549     if (netconn_type(sock->conn) != NETCONN_TCP) {
00550       sock_set_errno(sock, EOPNOTSUPP);
00551       return EOPNOTSUPP;
00552     }
00553     sock_set_errno(sock, err_to_errno(err));
00554     return -1;
00555   }
00556 
00557   sock_set_errno(sock, 0);
00558   return 0;
00559 }
00560 
00561 int
00562 lwip_recvfrom(int s, void *mem, size_t len, int flags,
00563         struct sockaddr *from, socklen_t *fromlen)
00564 {
00565   struct lwip_sock *sock;
00566   void             *buf = NULL;
00567   struct pbuf      *p;
00568   u16_t            buflen, copylen;
00569   int              off = 0;
00570   ip_addr_t        *addr;
00571   u16_t            port;
00572   u8_t             done = 0;
00573   err_t            err;
00574   sys_prot_t       lev;
00575 
00576   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d, %p, %"SZT_F", 0x%x, ..)\n", s, mem, len, flags));
00577   sock = get_socket(s);
00578   if (!sock) {
00579     return -1;
00580   }
00581 
00582   do {
00583     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: top while sock->lastdata=%p\n", sock->lastdata));
00584     /* Check if there is data left from the last recv operation. */
00585     if (sock->lastdata) {
00586       buf = sock->lastdata;
00587     } else {
00588       /* If this is non-blocking call, then check first */
00589       if (((flags & MSG_DONTWAIT) || netconn_is_nonblocking(sock->conn)) &&
00590           (sock->rcvevent <= 0)) {
00591         if (off > 0) {
00592           /* update receive window */
00593           LWIP_DEBUGF(SOCKETS_DEBUG, ("-lwip_recvfrom: from mailbox 0x%x\n", &sock->conn->recvmbox));
00594           netconn_recved(sock->conn, (u32_t)off);
00595           /* already received data, return that */
00596           sock_set_errno(sock, 0);
00597           return off;
00598         }
00599         LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): returning EWOULDBLOCK\n", s));
00600         sock_set_errno(sock, EWOULDBLOCK);
00601         return -1;
00602       }
00603 
00604       /* No data was left from the previous operation, so we try to get
00605          some from the network. */
00606       if (netconn_type(sock->conn) == NETCONN_TCP) {
00607         LWIP_DEBUGF(SOCKETS_DEBUG, ("--lwip_recvfrom: from mailbox 0x%x\n", &sock->conn->recvmbox));
00608         err = netconn_recv_tcp_pbuf(sock->conn, (struct pbuf **)&buf);
00609       } else {
00610         LWIP_DEBUGF(SOCKETS_DEBUG, ("---lwip_recvfrom: from mailbox 0x%x\n", &sock->conn->recvmbox));
00611         err = netconn_recv(sock->conn, (struct netbuf **)&buf);
00612       }
00613       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: netconn_recv err=%d, netbuf=%p\n",
00614         err, buf));
00615 
00616       if (err != ERR_OK) {
00617         if (off > 0) {
00618                /* update receive window */
00619                LWIP_DEBUGF(SOCKETS_DEBUG, ("----lwip_recvfrom: from mailbox 0x%x\n", &sock->conn->recvmbox));
00620                netconn_recved(sock->conn, (u32_t)off);
00621                /* already received data, return that */
00622                sock_set_errno(sock, 0);
00623                // workaround begin
00624                SYS_ARCH_PROTECT(lev);
00625                sock->rcvevent++; /* signal one more receive event for NULL */
00626                SYS_ARCH_UNPROTECT(lev);
00627                // workaround end
00628                return off;
00629         }
00630         /* We should really do some error checking here. */
00631         LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): buf == NULL, error is \"%s\"!\n",
00632           s, lwip_strerr(err)));
00633         sock_set_errno(sock, err_to_errno(err));
00634         if (err == ERR_CLSD) {
00635           return 0;
00636         } else {
00637           return -1;
00638         }
00639       }
00640       LWIP_ASSERT("buf != NULL", buf != NULL);
00641       sock->lastdata = buf;
00642     }
00643 
00644     if (netconn_type(sock->conn) == NETCONN_TCP) {
00645       p = (struct pbuf *)buf;
00646     } else {
00647       p = ((struct netbuf *)buf)->p;
00648     }
00649     buflen = p->tot_len;
00650     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: buflen=%"U16_F" len=%"SZT_F" off=%d sock->lastoffset=%"U16_F"\n",
00651       buflen, len, off, sock->lastoffset));
00652 
00653     buflen -= sock->lastoffset;
00654 
00655     if (len > buflen) {
00656       copylen = buflen;
00657     } else {
00658       copylen = (u16_t)len;
00659     }
00660 
00661     /* copy the contents of the received buffer into
00662     the supplied memory pointer mem */
00663     pbuf_copy_partial(p, (u8_t*)mem + off, copylen, sock->lastoffset);
00664 
00665     off += copylen;
00666 
00667     if (netconn_type(sock->conn) == NETCONN_TCP) {
00668       LWIP_ASSERT("invalid copylen, len would underflow", len >= copylen);
00669       len -= copylen;
00670       if ( (len <= 0) ||
00671            (p->flags & PBUF_FLAG_PUSH) ||
00672            (sock->rcvevent <= 0) ||
00673            ((flags & MSG_PEEK)!=0)) {
00674         done = 1;
00675       }
00676     } else {
00677       done = 1;
00678     }
00679 
00680     /* Check to see from where the data was.*/
00681     if (done) {
00682       ip_addr_t fromaddr;
00683       if (from && fromlen) {
00684         struct sockaddr_in sin;
00685 
00686         if (netconn_type(sock->conn) == NETCONN_TCP) {
00687           addr = &fromaddr;
00688           netconn_getaddr(sock->conn, addr, &port, 0);
00689         } else {
00690           addr = netbuf_fromaddr((struct netbuf *)buf);
00691           port = netbuf_fromport((struct netbuf *)buf);
00692         }
00693 
00694         memset(&sin, 0, sizeof(sin));
00695         sin.sin_len = sizeof(sin);
00696         sin.sin_family = AF_INET;
00697         sin.sin_port = htons(port);
00698         inet_addr_from_ipaddr(&sin.sin_addr, addr);
00699 
00700         if (*fromlen > sizeof(sin)) {
00701           *fromlen = sizeof(sin);
00702         }
00703 
00704         MEMCPY(from, &sin, *fromlen);
00705 
00706         LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): addr=", s));
00707         ip_addr_debug_print(SOCKETS_DEBUG, addr);
00708         LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F" len=%d\n", port, off));
00709       } else {
00710 #if SOCKETS_DEBUG
00711         if (netconn_type(sock->conn) == NETCONN_TCP) {
00712           addr = &fromaddr;
00713           netconn_getaddr(sock->conn, addr, &port, 0);
00714         } else {
00715           addr = netbuf_fromaddr((struct netbuf *)buf);
00716           port = netbuf_fromport((struct netbuf *)buf);
00717         }
00718 
00719         LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): addr=", s));
00720         ip_addr_debug_print(SOCKETS_DEBUG, addr);
00721         LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F" len=%d\n", port, off));
00722 #endif /*  SOCKETS_DEBUG */
00723       }
00724     }
00725 
00726     /* If we don't peek the incoming message... */
00727     if ((flags & MSG_PEEK) == 0) {
00728       /* If this is a TCP socket, check if there is data left in the
00729          buffer. If so, it should be saved in the sock structure for next
00730          time around. */
00731       if ((netconn_type(sock->conn) == NETCONN_TCP) && (buflen - copylen > 0)) {
00732         sock->lastdata = buf;
00733         sock->lastoffset += copylen;
00734         LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: lastdata now netbuf=%p\n", buf));
00735       } else {
00736         sock->lastdata = NULL;
00737         sock->lastoffset = 0;
00738         LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: deleting netbuf=%p\n", buf));
00739         if (netconn_type(sock->conn) == NETCONN_TCP) {
00740           pbuf_free((struct pbuf *)buf);
00741         } else {
00742           netbuf_delete((struct netbuf *)buf);
00743         }
00744       }
00745     }
00746   } while (!done);
00747 
00748   if (off > 0) {
00749     /* update receive window */
00750     LWIP_DEBUGF(SOCKETS_DEBUG, ("-----lwip_recvfrom: from mailbox 0x%x\n", &sock->conn->recvmbox));
00751     netconn_recved(sock->conn, (u32_t)off);
00752   }
00753   sock_set_errno(sock, 0);
00754   return off;
00755 }
00756 
00757 int
00758 lwip_read(int s, void *mem, size_t len)
00759 {
00760   return lwip_recvfrom(s, mem, len, 0, NULL, NULL);
00761 }
00762 
00763 int
00764 lwip_recv(int s, void *mem, size_t len, int flags)
00765 {
00766   return lwip_recvfrom(s, mem, len, flags, NULL, NULL);
00767 }
00768 
00769 int
00770 lwip_send(int s, const void *data, size_t size, int flags)
00771 {
00772   struct lwip_sock *sock;
00773   err_t err;
00774   u8_t write_flags;
00775   size_t written;
00776 
00777   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_send(%d, data=%p, size=%"SZT_F", flags=0x%x)\n",
00778                               s, data, size, flags));
00779 
00780   sock = get_socket(s);
00781   if (!sock) {
00782     return -1;
00783   }
00784 
00785   if (sock->conn->type != NETCONN_TCP) {
00786 #if (LWIP_UDP || LWIP_RAW)
00787     return lwip_sendto (s, data, size, flags, NULL, 0);
00788 #else /* (LWIP_UDP || LWIP_RAW) */
00789     sock_set_errno(sock, err_to_errno(ERR_ARG));
00790     return -1;
00791 #endif /* (LWIP_UDP || LWIP_RAW) */
00792   }
00793 
00794   write_flags = NETCONN_COPY |
00795     ((flags & MSG_MORE)     ? NETCONN_MORE      : 0) |
00796     ((flags & MSG_DONTWAIT) ? NETCONN_DONTBLOCK : 0);
00797   written = 0;
00798   err = netconn_write_partly(sock->conn, data, size, write_flags, &written);
00799 
00800   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_send(%d) err=%d written=%"SZT_F"\n", s, err, written));
00801   sock_set_errno(sock, err_to_errno(err));
00802   return (err == ERR_OK ? (int)written : -1);
00803 }
00804 
00805 int
00806 lwip_sendto (int s, const void *data, size_t size, int flags,
00807        const struct sockaddr *to, socklen_t tolen)
00808 {
00809   struct lwip_sock *sock;
00810   err_t err;
00811   u16_t short_size;
00812   const struct sockaddr_in *to_in;
00813   u16_t remote_port;
00814 #if !LWIP_TCPIP_CORE_LOCKING
00815   struct netbuf buf;
00816 #endif
00817 
00818   sock = get_socket(s);
00819   if (!sock) {
00820     return -1;
00821   }
00822 
00823   if (sock->conn->type == NETCONN_TCP) {
00824 #if LWIP_TCP
00825     return lwip_send(s, data, size, flags);
00826 #else /* LWIP_TCP */
00827     LWIP_UNUSED_ARG(flags);
00828     sock_set_errno(sock, err_to_errno(ERR_ARG));
00829     return -1;
00830 #endif /* LWIP_TCP */
00831   }
00832 
00833   /* @todo: split into multiple sendto's? */
00834   LWIP_ASSERT("lwip_sendto: size must fit in u16_t", size <= 0xffff);
00835   short_size = (u16_t)size;
00836   LWIP_ERROR("lwip_sendto: invalid address", (((to == NULL) && (tolen == 0)) ||
00837              ((tolen == sizeof(struct sockaddr_in)) &&
00838              ((to->sa_family) == AF_INET) && ((((mem_ptr_t)to) % 4) == 0))),
00839              sock_set_errno(sock, err_to_errno(ERR_ARG)); return -1;);
00840   to_in = (const struct sockaddr_in *)(void*)to;
00841 
00842 #if LWIP_TCPIP_CORE_LOCKING
00843   /* Should only be consider like a sample or a simple way to experiment this option (no check of "to" field...) */
00844   {
00845     struct pbuf* p;
00846     ip_addr_t *remote_addr;
00847 
00848 #if LWIP_NETIF_TX_SINGLE_PBUF
00849     p = pbuf_alloc(PBUF_TRANSPORT, short_size, PBUF_RAM);
00850     if (p != NULL) {
00851 #if LWIP_CHECKSUM_ON_COPY
00852       u16_t chksum = 0;
00853       if (sock->conn->type != NETCONN_RAW) {
00854         chksum = LWIP_CHKSUM_COPY(p->payload, data, short_size);
00855       } else
00856 #endif /* LWIP_CHECKSUM_ON_COPY */
00857       MEMCPY(p->payload, data, size);
00858 #else /* LWIP_NETIF_TX_SINGLE_PBUF */
00859     p = pbuf_alloc(PBUF_TRANSPORT, short_size, PBUF_REF);
00860     if (p != NULL) {
00861       p->payload = (void*)data;
00862 #endif /* LWIP_NETIF_TX_SINGLE_PBUF */
00863 
00864       if (to_in != NULL) {
00865         inet_addr_to_ipaddr_p(remote_addr, &to_in->sin_addr);
00866         remote_port = ntohs(to_in->sin_port);
00867       } else {
00868         remote_addr = &sock->conn->pcb.ip->remote_ip;
00869 #if LWIP_UDP
00870         if (NETCONNTYPE_GROUP(sock->conn->type) == NETCONN_UDP) {
00871           remote_port = sock->conn->pcb.udp->remote_port;
00872         } else
00873 #endif /* LWIP_UDP */
00874         {
00875           remote_port = 0;
00876         }
00877       }
00878 
00879       LOCK_TCPIP_CORE();
00880       if (netconn_type(sock->conn) == NETCONN_RAW) {
00881 #if LWIP_RAW
00882         err = sock->conn->last_err = raw_sendto(sock->conn->pcb.raw, p, remote_addr);
00883 #else /* LWIP_RAW */
00884         err = ERR_ARG;
00885 #endif /* LWIP_RAW */
00886       }
00887 #if LWIP_UDP && LWIP_RAW
00888       else
00889 #endif /* LWIP_UDP && LWIP_RAW */
00890       {
00891 #if LWIP_UDP
00892 #if LWIP_CHECKSUM_ON_COPY && LWIP_NETIF_TX_SINGLE_PBUF
00893         err = sock->conn->last_err = udp_sendto_chksum(sock->conn->pcb.udp, p,
00894           remote_addr, remote_port, 1, chksum);
00895 #else /* LWIP_CHECKSUM_ON_COPY && LWIP_NETIF_TX_SINGLE_PBUF */
00896         err = sock->conn->last_err = udp_sendto(sock->conn->pcb.udp, p,
00897           remote_addr, remote_port);
00898 #endif /* LWIP_CHECKSUM_ON_COPY && LWIP_NETIF_TX_SINGLE_PBUF */
00899 #else /* LWIP_UDP */
00900         err = ERR_ARG;
00901 #endif /* LWIP_UDP */
00902       }
00903       UNLOCK_TCPIP_CORE();
00904 
00905       pbuf_free(p);
00906     } else {
00907       err = ERR_MEM;
00908     }
00909   }
00910 #else /* LWIP_TCPIP_CORE_LOCKING */
00911   /* initialize a buffer */
00912   buf.p = buf.ptr = NULL;
00913 #if LWIP_CHECKSUM_ON_COPY
00914   buf.flags = 0;
00915 #endif /* LWIP_CHECKSUM_ON_COPY */
00916   if (to) {
00917     inet_addr_to_ipaddr(&buf.addr, &to_in->sin_addr);
00918     remote_port           = ntohs(to_in->sin_port);
00919     netbuf_fromport(&buf) = remote_port;
00920   } else {
00921     remote_port           = 0;
00922     ip_addr_set_any(&buf.addr);
00923     netbuf_fromport(&buf) = 0;
00924   }
00925 
00926   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_sendto(%d, data=%p, short_size=%"U16_F", flags=0x%x to=",
00927               s, data, short_size, flags));
00928   ip_addr_debug_print(SOCKETS_DEBUG, &buf.addr);
00929   LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F"\n", remote_port));
00930 
00931   /* make the buffer point to the data that should be sent */
00932 #if LWIP_NETIF_TX_SINGLE_PBUF
00933   /* Allocate a new netbuf and copy the data into it. */
00934   if (netbuf_alloc(&buf, short_size) == NULL) {
00935     err = ERR_MEM;
00936   } else {
00937 #if LWIP_CHECKSUM_ON_COPY
00938     if (sock->conn->type != NETCONN_RAW) {
00939       u16_t chksum = LWIP_CHKSUM_COPY(buf.p->payload, data, short_size);
00940       netbuf_set_chksum(&buf, chksum);
00941       err = ERR_OK;
00942     } else
00943 #endif /* LWIP_CHECKSUM_ON_COPY */
00944     {
00945       err = netbuf_take(&buf, data, short_size);
00946     }
00947   }
00948 #else /* LWIP_NETIF_TX_SINGLE_PBUF */
00949   err = netbuf_ref(&buf, data, short_size);
00950 #endif /* LWIP_NETIF_TX_SINGLE_PBUF */
00951   if (err == ERR_OK) {
00952     /* send the data */
00953     err = netconn_send(sock->conn, &buf);
00954   }
00955 
00956   /* deallocated the buffer */
00957   netbuf_free(&buf);
00958 #endif /* LWIP_TCPIP_CORE_LOCKING */
00959   sock_set_errno(sock, err_to_errno(err));
00960   return (err == ERR_OK ? short_size : -1);
00961 }
00962 
00963 int
00964 lwip_socket(int domain, int type, int protocol)
00965 {
00966   struct netconn *conn;
00967   int i;
00968 
00969   LWIP_UNUSED_ARG(domain);
00970 
00971   /* create a netconn */
00972   switch (type) {
00973   case SOCK_RAW:
00974     conn = netconn_new_with_proto_and_callback(NETCONN_RAW, (u8_t)protocol, event_callback);
00975     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_RAW, %d) = ",
00976                                  domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol));
00977     break;
00978   case SOCK_DGRAM:
00979     conn = netconn_new_with_callback( (protocol == IPPROTO_UDPLITE) ?
00980                  NETCONN_UDPLITE : NETCONN_UDP, event_callback);
00981     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_DGRAM, %d) = ",
00982                                  domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol));
00983     break;
00984   case SOCK_STREAM:
00985     conn = netconn_new_with_callback(NETCONN_TCP, event_callback);
00986     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_STREAM, %d) = ",
00987                                  domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol));
00988     if (conn != NULL) {
00989       /* Prevent automatic window updates, we do this on our own! */
00990       netconn_set_noautorecved(conn, 1);
00991     }
00992     break;
00993   default:
00994     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%d, %d/UNKNOWN, %d) = -1\n",
00995                                  domain, type, protocol));
00996     set_errno(EINVAL);
00997     return -1;
00998   }
00999 
01000   if (!conn) {
01001     LWIP_DEBUGF(SOCKETS_DEBUG, ("-1 / ENOBUFS (could not create netconn)\n"));
01002     set_errno(ENOBUFS);
01003     return -1;
01004   }
01005 
01006   i = alloc_socket(conn, 0);
01007 
01008   if (i == -1) {
01009     netconn_delete(conn);
01010     set_errno(ENFILE);
01011     return -1;
01012   }
01013   conn->socket = i;
01014   LWIP_DEBUGF(SOCKETS_DEBUG, ("%d\n", i));
01015   set_errno(0);
01016   return i;
01017 }
01018 
01019 int
01020 lwip_write(int s, const void *data, size_t size)
01021 {
01022   return lwip_send(s, data, size, 0);
01023 }
01024 
01025 /**
01026  * Go through the readset and writeset lists and see which socket of the sockets
01027  * set in the sets has events. On return, readset, writeset and exceptset have
01028  * the sockets enabled that had events.
01029  *
01030  * exceptset is not used for now!!!
01031  *
01032  * @param maxfdp1 the highest socket index in the sets
01033  * @param readset_in:    set of sockets to check for read events
01034  * @param writeset_in:   set of sockets to check for write events
01035  * @param exceptset_in:  set of sockets to check for error events
01036  * @param readset_out:   set of sockets that had read events
01037  * @param writeset_out:  set of sockets that had write events
01038  * @param exceptset_out: set os sockets that had error events
01039  * @return number of sockets that had events (read/write/exception) (>= 0)
01040  */
01041 static int
01042 lwip_selscan(int maxfdp1, fd_set *readset_in, fd_set *writeset_in, fd_set *exceptset_in,
01043              fd_set *readset_out, fd_set *writeset_out, fd_set *exceptset_out)
01044 {
01045   int i, nready = 0;
01046   fd_set lreadset, lwriteset, lexceptset;
01047   struct lwip_sock *sock;
01048   SYS_ARCH_DECL_PROTECT(lev);
01049 
01050   FD_ZERO(&lreadset);
01051   FD_ZERO(&lwriteset);
01052   FD_ZERO(&lexceptset);
01053 
01054   /* Go through each socket in each list to count number of sockets which
01055      currently match */
01056   for(i = 0; i < maxfdp1; i++) {
01057     void* lastdata = NULL;
01058     s16_t rcvevent = 0;
01059     u16_t sendevent = 0;
01060     u16_t errevent = 0;
01061     /* First get the socket's status (protected)... */
01062     SYS_ARCH_PROTECT(lev);
01063     sock = tryget_socket(i);
01064     if (sock != NULL) {
01065       lastdata = sock->lastdata;
01066       rcvevent = sock->rcvevent;
01067       sendevent = sock->sendevent;
01068       errevent = sock->errevent;
01069     }
01070     SYS_ARCH_UNPROTECT(lev);
01071     /* ... then examine it: */
01072     /* See if netconn of this socket is ready for read */
01073     if (readset_in && FD_ISSET(i, readset_in) && ((lastdata != NULL) || (rcvevent > 0))) {
01074       FD_SET(i, &lreadset);
01075       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_selscan: fd=%d ready for reading\n", i));
01076       nready++;
01077     }
01078     /* See if netconn of this socket is ready for write */
01079     if (writeset_in && FD_ISSET(i, writeset_in) && (sendevent != 0)) {
01080       FD_SET(i, &lwriteset);
01081       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_selscan: fd=%d ready for writing\n", i));
01082       nready++;
01083     }
01084     /* See if netconn of this socket had an error */
01085     if (exceptset_in && FD_ISSET(i, exceptset_in) && (errevent != 0)) {
01086       FD_SET(i, &lexceptset);
01087       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_selscan: fd=%d ready for exception\n", i));
01088       nready++;
01089     }
01090   }
01091   /* copy local sets to the ones provided as arguments */
01092   *readset_out = lreadset;
01093   *writeset_out = lwriteset;
01094   *exceptset_out = lexceptset;
01095 
01096   LWIP_ASSERT("nready >= 0", nready >= 0);
01097   return nready;
01098 }
01099 
01100 /**
01101  * Processing exceptset is not yet implemented.
01102  */
01103 int
01104 lwip_select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset,
01105             struct timeval *timeout)
01106 {
01107   u32_t waitres = 0;
01108   int nready;
01109   fd_set lreadset, lwriteset, lexceptset;
01110   u32_t msectimeout;
01111   struct lwip_select_cb select_cb;
01112   err_t err;
01113   int i;
01114   SYS_ARCH_DECL_PROTECT(lev);
01115 
01116   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select(%d, %p, %p, %p, tvsec=%"S32_F" tvusec=%"S32_F")\n",
01117                   maxfdp1, (void *)readset, (void *) writeset, (void *) exceptset,
01118                   timeout ? (s32_t)timeout->tv_sec : (s32_t)-1,
01119                   timeout ? (s32_t)timeout->tv_usec : (s32_t)-1));
01120 
01121   /* Go through each socket in each list to count number of sockets which
01122      currently match */
01123   nready = lwip_selscan(maxfdp1, readset, writeset, exceptset, &lreadset, &lwriteset, &lexceptset);
01124 
01125   /* If we don't have any current events, then suspend if we are supposed to */
01126   if (!nready) {
01127     if (timeout && timeout->tv_sec == 0 && timeout->tv_usec == 0) {
01128       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select: no timeout, returning 0\n"));
01129       /* This is OK as the local fdsets are empty and nready is zero,
01130          or we would have returned earlier. */
01131       goto return_copy_fdsets;
01132     }
01133 
01134     /* None ready: add our semaphore to list:
01135        We don't actually need any dynamic memory. Our entry on the
01136        list is only valid while we are in this function, so it's ok
01137        to use local variables. */
01138 
01139     select_cb.next = NULL;
01140     select_cb.prev = NULL;
01141     select_cb.readset = readset;
01142     select_cb.writeset = writeset;
01143     select_cb.exceptset = exceptset;
01144     select_cb.sem_signalled = 0;
01145     err = sys_sem_new(&select_cb.sem, 0);
01146     if (err != ERR_OK) {
01147       /* failed to create semaphore */
01148       set_errno(ENOMEM);
01149       return -1;
01150     }
01151 
01152     /* Protect the select_cb_list */
01153     SYS_ARCH_PROTECT(lev);
01154 
01155     /* Put this select_cb on top of list */
01156     select_cb.next = select_cb_list;
01157     if (select_cb_list != NULL) {
01158       select_cb_list->prev = &select_cb;
01159     }
01160     select_cb_list = &select_cb;
01161     /* Increasing this counter tells even_callback that the list has changed. */
01162     select_cb_ctr++;
01163 
01164     /* Now we can safely unprotect */
01165     SYS_ARCH_UNPROTECT(lev);
01166 
01167     /* Increase select_waiting for each socket we are interested in */
01168     for(i = 0; i < maxfdp1; i++) {
01169       if ((readset && FD_ISSET(i, readset)) ||
01170           (writeset && FD_ISSET(i, writeset)) ||
01171           (exceptset && FD_ISSET(i, exceptset))) {
01172         struct lwip_sock *sock = tryget_socket(i);
01173         LWIP_ASSERT("sock != NULL", sock != NULL);
01174         SYS_ARCH_PROTECT(lev);
01175         sock->select_waiting++;
01176         LWIP_ASSERT("sock->select_waiting > 0", sock->select_waiting > 0);
01177         SYS_ARCH_UNPROTECT(lev);
01178       }
01179     }
01180 
01181     /* Call lwip_selscan again: there could have been events between
01182        the last scan (whithout us on the list) and putting us on the list! */
01183     nready = lwip_selscan(maxfdp1, readset, writeset, exceptset, &lreadset, &lwriteset, &lexceptset);
01184     if (!nready) {
01185       /* Still none ready, just wait to be woken */
01186       if (timeout == 0) {
01187         /* Wait forever */
01188         msectimeout = 0;
01189       } else {
01190         msectimeout =  ((timeout->tv_sec * 1000) + ((timeout->tv_usec + 500)/1000));
01191         if (msectimeout == 0) {
01192           /* Wait 1ms at least (0 means wait forever) */
01193           msectimeout = 1;
01194         }
01195       }
01196 
01197       waitres = sys_arch_sem_wait(&select_cb.sem, msectimeout);
01198     }
01199     /* Increase select_waiting for each socket we are interested in */
01200     for(i = 0; i < maxfdp1; i++) {
01201       if ((readset && FD_ISSET(i, readset)) ||
01202           (writeset && FD_ISSET(i, writeset)) ||
01203           (exceptset && FD_ISSET(i, exceptset))) {
01204         struct lwip_sock *sock = tryget_socket(i);
01205         LWIP_ASSERT("sock != NULL", sock != NULL);
01206         SYS_ARCH_PROTECT(lev);
01207         sock->select_waiting--;
01208         LWIP_ASSERT("sock->select_waiting >= 0", sock->select_waiting >= 0);
01209         SYS_ARCH_UNPROTECT(lev);
01210       }
01211     }
01212     /* Take us off the list */
01213     SYS_ARCH_PROTECT(lev);
01214     if (select_cb.next != NULL) {
01215       select_cb.next->prev = select_cb.prev;
01216     }
01217     if (select_cb_list == &select_cb) {
01218       LWIP_ASSERT("select_cb.prev == NULL", select_cb.prev == NULL);
01219       select_cb_list = select_cb.next;
01220     } else {
01221       LWIP_ASSERT("select_cb.prev != NULL", select_cb.prev != NULL);
01222       select_cb.prev->next = select_cb.next;
01223     }
01224     /* Increasing this counter tells even_callback that the list has changed. */
01225     select_cb_ctr++;
01226     SYS_ARCH_UNPROTECT(lev);
01227 
01228     sys_sem_free(&select_cb.sem);
01229     if (waitres == SYS_ARCH_TIMEOUT)  {
01230       /* Timeout */
01231       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select: timeout expired\n"));
01232       /* This is OK as the local fdsets are empty and nready is zero,
01233          or we would have returned earlier. */
01234       goto return_copy_fdsets;
01235     }
01236 
01237     /* See what's set */
01238     nready = lwip_selscan(maxfdp1, readset, writeset, exceptset, &lreadset, &lwriteset, &lexceptset);
01239   }
01240 
01241   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select: nready=%d\n", nready));
01242 return_copy_fdsets:
01243   set_errno(0);
01244   if (readset) {
01245     *readset = lreadset;
01246   }
01247   if (writeset) {
01248     *writeset = lwriteset;
01249   }
01250   if (exceptset) {
01251     *exceptset = lexceptset;
01252   }
01253 
01254 
01255   return nready;
01256 }
01257 
01258 /**
01259  * Callback registered in the netconn layer for each socket-netconn.
01260  * Processes recvevent (data available) and wakes up tasks waiting for select.
01261  */
01262 static void
01263 event_callback(struct netconn *conn, enum netconn_evt evt, u16_t len)
01264 {
01265   int s;
01266   struct lwip_sock *sock;
01267   struct lwip_select_cb *scb;
01268   int last_select_cb_ctr;
01269   SYS_ARCH_DECL_PROTECT(lev);
01270 
01271   LWIP_UNUSED_ARG(len);
01272 
01273   /* Get socket */
01274   if (conn) {
01275     s = conn->socket;
01276     if (s < 0) {
01277       /* Data comes in right away after an accept, even though
01278        * the server task might not have created a new socket yet.
01279        * Just count down (or up) if that's the case and we
01280        * will use the data later. Note that only receive events
01281        * can happen before the new socket is set up. */
01282       SYS_ARCH_PROTECT(lev);
01283       if (conn->socket < 0) {
01284         if (evt == NETCONN_EVT_RCVPLUS) {
01285           conn->socket--;
01286         }
01287         SYS_ARCH_UNPROTECT(lev);
01288         return;
01289       }
01290       s = conn->socket;
01291       SYS_ARCH_UNPROTECT(lev);
01292     }
01293 
01294     sock = get_socket(s);
01295     if (!sock) {
01296       return;
01297     }
01298   } else {
01299     return;
01300   }
01301 
01302   SYS_ARCH_PROTECT(lev);
01303   /* Set event as required */
01304   switch (evt) {
01305     case NETCONN_EVT_RCVPLUS:
01306       sock->rcvevent++;
01307       break;
01308     case NETCONN_EVT_RCVMINUS:
01309       sock->rcvevent--;
01310       break;
01311     case NETCONN_EVT_SENDPLUS:
01312       sock->sendevent = 1;
01313       break;
01314     case NETCONN_EVT_SENDMINUS:
01315       sock->sendevent = 0;
01316       break;
01317     case NETCONN_EVT_ERROR:
01318       sock->errevent = 1;
01319       break;
01320     default:
01321       LWIP_ASSERT("unknown event", 0);
01322       break;
01323   }
01324 
01325   if (sock->select_waiting == 0) {
01326     /* noone is waiting for this socket, no need to check select_cb_list */
01327     SYS_ARCH_UNPROTECT(lev);
01328     return;
01329   }
01330 
01331   /* Now decide if anyone is waiting for this socket */
01332   /* NOTE: This code goes through the select_cb_list list multiple times
01333      ONLY IF a select was actually waiting. We go through the list the number
01334      of waiting select calls + 1. This list is expected to be small. */
01335 
01336   /* At this point, SYS_ARCH is still protected! */
01337 again:
01338   for (scb = select_cb_list; scb != NULL; scb = scb->next) {
01339     if (scb->sem_signalled == 0) {
01340       /* semaphore not signalled yet */
01341       int do_signal = 0;
01342       /* Test this select call for our socket */
01343       if (sock->rcvevent > 0) {
01344         if (scb->readset && FD_ISSET(s, scb->readset)) {
01345           do_signal = 1;
01346         }
01347       }
01348       if (sock->sendevent != 0) {
01349         if (!do_signal && scb->writeset && FD_ISSET(s, scb->writeset)) {
01350           do_signal = 1;
01351         }
01352       }
01353       if (sock->errevent != 0) {
01354         if (!do_signal && scb->exceptset && FD_ISSET(s, scb->exceptset)) {
01355           do_signal = 1;
01356         }
01357       }
01358       if (do_signal) {
01359         scb->sem_signalled = 1;
01360         /* Don't call SYS_ARCH_UNPROTECT() before signaling the semaphore, as this might
01361            lead to the select thread taking itself off the list, invalidagin the semaphore. */
01362         sys_sem_signal(&scb->sem);
01363       }
01364     }
01365     /* unlock interrupts with each step */
01366     last_select_cb_ctr = select_cb_ctr;
01367     SYS_ARCH_UNPROTECT(lev);
01368     /* this makes sure interrupt protection time is short */
01369     SYS_ARCH_PROTECT(lev);
01370     if (last_select_cb_ctr != select_cb_ctr) {
01371       /* someone has changed select_cb_list, restart at the beginning */
01372       goto again;
01373     }
01374   }
01375   SYS_ARCH_UNPROTECT(lev);
01376 }
01377 
01378 /**
01379  * Unimplemented: Close one end of a full-duplex connection.
01380  * Currently, the full connection is closed.
01381  */
01382 int
01383 lwip_shutdown(int s, int how)
01384 {
01385   struct lwip_sock *sock;
01386   err_t err;
01387   u8_t shut_rx = 0, shut_tx = 0;
01388 
01389   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_shutdown(%d, how=%d)\n", s, how));
01390 
01391   sock = get_socket(s);
01392   if (!sock) {
01393     return -1;
01394   }
01395 
01396   if (sock->conn != NULL) {
01397     if (netconn_type(sock->conn) != NETCONN_TCP) {
01398       sock_set_errno(sock, EOPNOTSUPP);
01399       return EOPNOTSUPP;
01400     }
01401   } else {
01402     sock_set_errno(sock, ENOTCONN);
01403     return ENOTCONN;
01404   }
01405 
01406   if (how == SHUT_RD) {
01407     shut_rx = 1;
01408   } else if (how == SHUT_WR) {
01409     shut_tx = 1;
01410   } else if(how == SHUT_RDWR) {
01411     shut_rx = 1;
01412     shut_tx = 1;
01413   } else {
01414     sock_set_errno(sock, EINVAL);
01415     return EINVAL;
01416   }
01417   err = netconn_shutdown(sock->conn, shut_rx, shut_tx);
01418 
01419   sock_set_errno(sock, err_to_errno(err));
01420   return (err == ERR_OK ? 0 : -1);
01421 }
01422 
01423 static int
01424 lwip_getaddrname(int s, struct sockaddr *name, socklen_t *namelen, u8_t local)
01425 {
01426   struct lwip_sock *sock;
01427   struct sockaddr_in sin;
01428   ip_addr_t naddr;
01429 
01430   sock = get_socket(s);
01431   if (!sock) {
01432     return -1;
01433   }
01434 
01435   memset(&sin, 0, sizeof(sin));
01436   sin.sin_len = sizeof(sin);
01437   sin.sin_family = AF_INET;
01438 
01439   /* get the IP address and port */
01440   netconn_getaddr(sock->conn, &naddr, &sin.sin_port, local);
01441 
01442   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getaddrname(%d, addr=", s));
01443   ip_addr_debug_print(SOCKETS_DEBUG, &naddr);
01444   LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F")\n", sin.sin_port));
01445 
01446   sin.sin_port = htons(sin.sin_port);
01447   inet_addr_from_ipaddr(&sin.sin_addr, &naddr);
01448 
01449   if (*namelen > sizeof(sin)) {
01450     *namelen = sizeof(sin);
01451   }
01452 
01453   MEMCPY(name, &sin, *namelen);
01454   sock_set_errno(sock, 0);
01455   return 0;
01456 }
01457 
01458 int
01459 lwip_getpeername(int s, struct sockaddr *name, socklen_t *namelen)
01460 {
01461   return lwip_getaddrname(s, name, namelen, 0);
01462 }
01463 
01464 int
01465 lwip_getsockname(int s, struct sockaddr *name, socklen_t *namelen)
01466 {
01467   return lwip_getaddrname(s, name, namelen, 1);
01468 }
01469 
01470 int
01471 lwip_getsockopt(int s, int level, int optname, void *optval, socklen_t *optlen)
01472 {
01473   err_t err = ERR_OK;
01474   struct lwip_sock *sock = get_socket(s);
01475   struct lwip_setgetsockopt_data data;
01476 
01477   if (!sock) {
01478     return -1;
01479   }
01480 
01481   if ((NULL == optval) || (NULL == optlen)) {
01482     sock_set_errno(sock, EFAULT);
01483     return -1;
01484   }
01485 
01486   /* Do length and type checks for the various options first, to keep it readable. */
01487   switch (level) {
01488 
01489 /* Level: SOL_SOCKET */
01490   case SOL_SOCKET:
01491     switch (optname) {
01492 
01493     case SO_ACCEPTCONN:
01494     case SO_BROADCAST:
01495     /* UNIMPL case SO_DEBUG: */
01496     /* UNIMPL case SO_DONTROUTE: */
01497     case SO_ERROR:
01498     case SO_KEEPALIVE:
01499     /* UNIMPL case SO_CONTIMEO: */
01500 #if LWIP_SO_SNDTIMEO
01501     case SO_SNDTIMEO:
01502 #endif /* LWIP_SO_SNDTIMEO */
01503 #if LWIP_SO_RCVTIMEO
01504     case SO_RCVTIMEO:
01505 #endif /* LWIP_SO_RCVTIMEO */
01506 #if LWIP_SO_RCVBUF
01507     case SO_RCVBUF:
01508 #endif /* LWIP_SO_RCVBUF */
01509     /* UNIMPL case SO_OOBINLINE: */
01510     /* UNIMPL case SO_SNDBUF: */
01511     /* UNIMPL case SO_RCVLOWAT: */
01512     /* UNIMPL case SO_SNDLOWAT: */
01513 #if SO_REUSE
01514     case SO_REUSEADDR:
01515     case SO_REUSEPORT:
01516 #endif /* SO_REUSE */
01517     case SO_TYPE:
01518     /* UNIMPL case SO_USELOOPBACK: */
01519       if (*optlen < sizeof(int)) {
01520         err = EINVAL;
01521       }
01522       break;
01523 
01524     case SO_NO_CHECK:
01525       if (*optlen < sizeof(int)) {
01526         err = EINVAL;
01527       }
01528 #if LWIP_UDP
01529       if ((sock->conn->type != NETCONN_UDP) ||
01530           ((udp_flags(sock->conn->pcb.udp) & UDP_FLAGS_UDPLITE) != 0)) {
01531         /* this flag is only available for UDP, not for UDP lite */
01532         err = EAFNOSUPPORT;
01533       }
01534 #endif /* LWIP_UDP */
01535       break;
01536 
01537     default:
01538       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, UNIMPL: optname=0x%x, ..)\n",
01539                                   s, optname));
01540       err = ENOPROTOOPT;
01541     }  /* switch (optname) */
01542     break;
01543 
01544 /* Level: IPPROTO_IP */
01545   case IPPROTO_IP:
01546     switch (optname) {
01547     /* UNIMPL case IP_HDRINCL: */
01548     /* UNIMPL case IP_RCVDSTADDR: */
01549     /* UNIMPL case IP_RCVIF: */
01550     case IP_TTL:
01551     case IP_TOS:
01552       if (*optlen < sizeof(int)) {
01553         err = EINVAL;
01554       }
01555       break;
01556 #if LWIP_IGMP
01557     case IP_MULTICAST_TTL:
01558       if (*optlen < sizeof(u8_t)) {
01559         err = EINVAL;
01560       }
01561       break;
01562     case IP_MULTICAST_IF:
01563       if (*optlen < sizeof(struct in_addr)) {
01564         err = EINVAL;
01565       }
01566       break;
01567     case IP_MULTICAST_LOOP:
01568       if (*optlen < sizeof(u8_t)) {
01569         err = EINVAL;
01570       }
01571       if (NETCONNTYPE_GROUP(sock->conn->type) != NETCONN_UDP) {
01572         err = EAFNOSUPPORT;
01573       }
01574       break;
01575 #endif /* LWIP_IGMP */
01576 
01577     default:
01578       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, UNIMPL: optname=0x%x, ..)\n",
01579                                   s, optname));
01580       err = ENOPROTOOPT;
01581     }  /* switch (optname) */
01582     break;
01583 
01584 #if LWIP_TCP
01585 /* Level: IPPROTO_TCP */
01586   case IPPROTO_TCP:
01587     if (*optlen < sizeof(int)) {
01588       err = EINVAL;
01589       break;
01590     }
01591 
01592     /* If this is no TCP socket, ignore any options. */
01593     if (sock->conn->type != NETCONN_TCP)
01594       return 0;
01595 
01596     switch (optname) {
01597     case TCP_NODELAY:
01598     case TCP_KEEPALIVE:
01599 #if LWIP_TCP_KEEPALIVE
01600     case TCP_KEEPIDLE:
01601     case TCP_KEEPINTVL:
01602     case TCP_KEEPCNT:
01603 #endif /* LWIP_TCP_KEEPALIVE */
01604       break;
01605 
01606     default:
01607       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_TCP, UNIMPL: optname=0x%x, ..)\n",
01608                                   s, optname));
01609       err = ENOPROTOOPT;
01610     }  /* switch (optname) */
01611     break;
01612 #endif /* LWIP_TCP */
01613 #if LWIP_UDP && LWIP_UDPLITE
01614 /* Level: IPPROTO_UDPLITE */
01615   case IPPROTO_UDPLITE:
01616     if (*optlen < sizeof(int)) {
01617       err = EINVAL;
01618       break;
01619     }
01620 
01621     /* If this is no UDP lite socket, ignore any options. */
01622     if (sock->conn->type != NETCONN_UDPLITE) {
01623       return 0;
01624     }
01625 
01626     switch (optname) {
01627     case UDPLITE_SEND_CSCOV:
01628     case UDPLITE_RECV_CSCOV:
01629       break;
01630 
01631     default:
01632       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_UDPLITE, UNIMPL: optname=0x%x, ..)\n",
01633                                   s, optname));
01634       err = ENOPROTOOPT;
01635     }  /* switch (optname) */
01636     break;
01637 #endif /* LWIP_UDP && LWIP_UDPLITE*/
01638 /* UNDEFINED LEVEL */
01639   default:
01640       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, level=0x%x, UNIMPL: optname=0x%x, ..)\n",
01641                                   s, level, optname));
01642       err = ENOPROTOOPT;
01643   }  /* switch */
01644 
01645 
01646   if (err != ERR_OK) {
01647     sock_set_errno(sock, err);
01648     return -1;
01649   }
01650 
01651   /* Now do the actual option processing */
01652   data.sock = sock;
01653 #ifdef LWIP_DEBUG
01654   data.s = s;
01655 #endif /* LWIP_DEBUG */
01656   data.level = level;
01657   data.optname = optname;
01658   data.optval = optval;
01659   data.optlen = optlen;
01660   data.err = err;
01661   tcpip_callback(lwip_getsockopt_internal, &data);
01662   sys_arch_sem_wait(&sock->conn->op_completed, 0);
01663   /* maybe lwip_getsockopt_internal has changed err */
01664   err = data.err;
01665 
01666   sock_set_errno(sock, err);
01667   return err ? -1 : 0;
01668 }
01669 
01670 static void
01671 lwip_getsockopt_internal(void *arg)
01672 {
01673   struct lwip_sock *sock;
01674 #ifdef LWIP_DEBUG
01675   int s;
01676 #endif /* LWIP_DEBUG */
01677   int level, optname;
01678   void *optval;
01679   struct lwip_setgetsockopt_data *data;
01680 
01681   LWIP_ASSERT("arg != NULL", arg != NULL);
01682 
01683   data = (struct lwip_setgetsockopt_data*)arg;
01684   sock = data->sock;
01685 #ifdef LWIP_DEBUG
01686   s = data->s;
01687 #endif /* LWIP_DEBUG */
01688   level = data->level;
01689   optname = data->optname;
01690   optval = data->optval;
01691 
01692   switch (level) {
01693 
01694 /* Level: SOL_SOCKET */
01695   case SOL_SOCKET:
01696     switch (optname) {
01697 
01698     /* The option flags */
01699     case SO_ACCEPTCONN:
01700     case SO_BROADCAST:
01701     /* UNIMPL case SO_DEBUG: */
01702     /* UNIMPL case SO_DONTROUTE: */
01703     case SO_KEEPALIVE:
01704     /* UNIMPL case SO_OOBINCLUDE: */
01705 #if SO_REUSE
01706     case SO_REUSEADDR:
01707     case SO_REUSEPORT:
01708 #endif /* SO_REUSE */
01709     /*case SO_USELOOPBACK: UNIMPL */
01710       *(int*)optval = ip_get_option(sock->conn->pcb.ip, optname);
01711       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, optname=0x%x, ..) = %s\n",
01712                                   s, optname, (*(int*)optval?"on":"off")));
01713       break;
01714 
01715     case SO_TYPE:
01716       switch (NETCONNTYPE_GROUP(sock->conn->type)) {
01717       case NETCONN_RAW:
01718         *(int*)optval = SOCK_RAW;
01719         break;
01720       case NETCONN_TCP:
01721         *(int*)optval = SOCK_STREAM;
01722         break;
01723       case NETCONN_UDP:
01724         *(int*)optval = SOCK_DGRAM;
01725         break;
01726       default: /* unrecognized socket type */
01727         *(int*)optval = sock->conn->type;
01728         LWIP_DEBUGF(SOCKETS_DEBUG,
01729                     ("lwip_getsockopt(%d, SOL_SOCKET, SO_TYPE): unrecognized socket type %d\n",
01730                     s, *(int *)optval));
01731       }  /* switch (sock->conn->type) */
01732       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, SO_TYPE) = %d\n",
01733                   s, *(int *)optval));
01734       break;
01735 
01736     case SO_ERROR:
01737       /* only overwrite ERR_OK or tempoary errors */
01738       if ((sock->err == 0) || (sock->err == EINPROGRESS)) {
01739         sock_set_errno(sock, err_to_errno(sock->conn->last_err));
01740       }
01741       *(int *)optval = sock->err;
01742       sock->err = 0;
01743       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, SO_ERROR) = %d\n",
01744                   s, *(int *)optval));
01745       break;
01746 
01747 #if LWIP_SO_SNDTIMEO
01748     case SO_SNDTIMEO:
01749       *(int *)optval = netconn_get_sendtimeout(sock->conn);
01750       break;
01751 #endif /* LWIP_SO_SNDTIMEO */
01752 #if LWIP_SO_RCVTIMEO
01753     case SO_RCVTIMEO:
01754       *(int *)optval = netconn_get_recvtimeout(sock->conn);
01755       break;
01756 #endif /* LWIP_SO_RCVTIMEO */
01757 #if LWIP_SO_RCVBUF
01758     case SO_RCVBUF:
01759       *(int *)optval = netconn_get_recvbufsize(sock->conn);
01760       break;
01761 #endif /* LWIP_SO_RCVBUF */
01762 #if LWIP_UDP
01763     case SO_NO_CHECK:
01764       *(int*)optval = (udp_flags(sock->conn->pcb.udp) & UDP_FLAGS_NOCHKSUM) ? 1 : 0;
01765       break;
01766 #endif /* LWIP_UDP*/
01767     default:
01768       LWIP_ASSERT("unhandled optname", 0);
01769       break;
01770     }  /* switch (optname) */
01771     break;
01772 
01773 /* Level: IPPROTO_IP */
01774   case IPPROTO_IP:
01775     switch (optname) {
01776     case IP_TTL:
01777       *(int*)optval = sock->conn->pcb.ip->ttl;
01778       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_TTL) = %d\n",
01779                   s, *(int *)optval));
01780       break;
01781     case IP_TOS:
01782       *(int*)optval = sock->conn->pcb.ip->tos;
01783       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_TOS) = %d\n",
01784                   s, *(int *)optval));
01785       break;
01786 #if LWIP_IGMP
01787     case IP_MULTICAST_TTL:
01788       *(u8_t*)optval = sock->conn->pcb.ip->ttl;
01789       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_MULTICAST_TTL) = %d\n",
01790                   s, *(int *)optval));
01791       break;
01792     case IP_MULTICAST_IF:
01793       inet_addr_from_ipaddr((struct in_addr*)optval, &sock->conn->pcb.udp->multicast_ip);
01794       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_MULTICAST_IF) = 0x%"X32_F"\n",
01795                   s, *(u32_t *)optval));
01796       break;
01797     case IP_MULTICAST_LOOP:
01798       if ((sock->conn->pcb.udp->flags & UDP_FLAGS_MULTICAST_LOOP) != 0) {
01799         *(u8_t*)optval = 1;
01800       } else {
01801         *(u8_t*)optval = 0;
01802       }
01803       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_MULTICAST_LOOP) = %d\n",
01804                   s, *(int *)optval));
01805       break;
01806 #endif /* LWIP_IGMP */
01807     default:
01808       LWIP_ASSERT("unhandled optname", 0);
01809       break;
01810     }  /* switch (optname) */
01811     break;
01812 
01813 #if LWIP_TCP
01814 /* Level: IPPROTO_TCP */
01815   case IPPROTO_TCP:
01816     switch (optname) {
01817     case TCP_NODELAY:
01818       *(int*)optval = tcp_nagle_disabled(sock->conn->pcb.tcp);
01819       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_TCP, TCP_NODELAY) = %s\n",
01820                   s, (*(int*)optval)?"on":"off") );
01821       break;
01822     case TCP_KEEPALIVE:
01823       *(int*)optval = (int)sock->conn->pcb.tcp->keep_idle;
01824       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, TCP_KEEPALIVE) = %d\n",
01825                   s, *(int *)optval));
01826       break;
01827 
01828 #if LWIP_TCP_KEEPALIVE
01829     case TCP_KEEPIDLE:
01830       *(int*)optval = (int)(sock->conn->pcb.tcp->keep_idle/1000);
01831       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, TCP_KEEPIDLE) = %d\n",
01832                   s, *(int *)optval));
01833       break;
01834     case TCP_KEEPINTVL:
01835       *(int*)optval = (int)(sock->conn->pcb.tcp->keep_intvl/1000);
01836       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, TCP_KEEPINTVL) = %d\n",
01837                   s, *(int *)optval));
01838       break;
01839     case TCP_KEEPCNT:
01840       *(int*)optval = (int)sock->conn->pcb.tcp->keep_cnt;
01841       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, TCP_KEEPCNT) = %d\n",
01842                   s, *(int *)optval));
01843       break;
01844 #endif /* LWIP_TCP_KEEPALIVE */
01845     default:
01846       LWIP_ASSERT("unhandled optname", 0);
01847       break;
01848     }  /* switch (optname) */
01849     break;
01850 #endif /* LWIP_TCP */
01851 #if LWIP_UDP && LWIP_UDPLITE
01852   /* Level: IPPROTO_UDPLITE */
01853   case IPPROTO_UDPLITE:
01854     switch (optname) {
01855     case UDPLITE_SEND_CSCOV:
01856       *(int*)optval = sock->conn->pcb.udp->chksum_len_tx;
01857       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_UDPLITE, UDPLITE_SEND_CSCOV) = %d\n",
01858                   s, (*(int*)optval)) );
01859       break;
01860     case UDPLITE_RECV_CSCOV:
01861       *(int*)optval = sock->conn->pcb.udp->chksum_len_rx;
01862       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_UDPLITE, UDPLITE_RECV_CSCOV) = %d\n",
01863                   s, (*(int*)optval)) );
01864       break;
01865     default:
01866       LWIP_ASSERT("unhandled optname", 0);
01867       break;
01868     }  /* switch (optname) */
01869     break;
01870 #endif /* LWIP_UDP */
01871   default:
01872     LWIP_ASSERT("unhandled level", 0);
01873     break;
01874   } /* switch (level) */
01875   sys_sem_signal(&sock->conn->op_completed);
01876 }
01877 
01878 int
01879 lwip_setsockopt(int s, int level, int optname, const void *optval, socklen_t optlen)
01880 {
01881   struct lwip_sock *sock = get_socket(s);
01882   err_t err = ERR_OK;
01883   struct lwip_setgetsockopt_data data;
01884 
01885   if (!sock) {
01886     return -1;
01887   }
01888 
01889   if (NULL == optval) {
01890     sock_set_errno(sock, EFAULT);
01891     return -1;
01892   }
01893 
01894   /* Do length and type checks for the various options first, to keep it readable. */
01895   switch (level) {
01896 
01897 /* Level: SOL_SOCKET */
01898   case SOL_SOCKET:
01899     switch (optname) {
01900 
01901     case SO_BROADCAST:
01902     /* UNIMPL case SO_DEBUG: */
01903     /* UNIMPL case SO_DONTROUTE: */
01904     case SO_KEEPALIVE:
01905     /* UNIMPL case case SO_CONTIMEO: */
01906 #if LWIP_SO_SNDTIMEO
01907     case SO_SNDTIMEO:
01908 #endif /* LWIP_SO_SNDTIMEO */
01909 #if LWIP_SO_RCVTIMEO
01910     case SO_RCVTIMEO:
01911 #endif /* LWIP_SO_RCVTIMEO */
01912 #if LWIP_SO_RCVBUF
01913     case SO_RCVBUF:
01914 #endif /* LWIP_SO_RCVBUF */
01915     /* UNIMPL case SO_OOBINLINE: */
01916     /* UNIMPL case SO_SNDBUF: */
01917     /* UNIMPL case SO_RCVLOWAT: */
01918     /* UNIMPL case SO_SNDLOWAT: */
01919 #if SO_REUSE
01920     case SO_REUSEADDR:
01921     case SO_REUSEPORT:
01922 #endif /* SO_REUSE */
01923     /* UNIMPL case SO_USELOOPBACK: */
01924       if (optlen < sizeof(int)) {
01925         err = EINVAL;
01926       }
01927       break;
01928     case SO_NO_CHECK:
01929       if (optlen < sizeof(int)) {
01930         err = EINVAL;
01931       }
01932 #if LWIP_UDP
01933       if ((sock->conn->type != NETCONN_UDP) ||
01934           ((udp_flags(sock->conn->pcb.udp) & UDP_FLAGS_UDPLITE) != 0)) {
01935         /* this flag is only available for UDP, not for UDP lite */
01936         err = EAFNOSUPPORT;
01937       }
01938 #endif /* LWIP_UDP */
01939       break;
01940     default:
01941       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, SOL_SOCKET, UNIMPL: optname=0x%x, ..)\n",
01942                   s, optname));
01943       err = ENOPROTOOPT;
01944     }  /* switch (optname) */
01945     break;
01946 
01947 /* Level: IPPROTO_IP */
01948   case IPPROTO_IP:
01949     switch (optname) {
01950     /* UNIMPL case IP_HDRINCL: */
01951     /* UNIMPL case IP_RCVDSTADDR: */
01952     /* UNIMPL case IP_RCVIF: */
01953     case IP_TTL:
01954     case IP_TOS:
01955       if (optlen < sizeof(int)) {
01956         err = EINVAL;
01957       }
01958       break;
01959 #if LWIP_IGMP
01960     case IP_MULTICAST_TTL:
01961       if (optlen < sizeof(u8_t)) {
01962         err = EINVAL;
01963       }
01964       if (NETCONNTYPE_GROUP(sock->conn->type) != NETCONN_UDP) {
01965         err = EAFNOSUPPORT;
01966       }
01967       break;
01968     case IP_MULTICAST_IF:
01969       if (optlen < sizeof(struct in_addr)) {
01970         err = EINVAL;
01971       }
01972       if (NETCONNTYPE_GROUP(sock->conn->type) != NETCONN_UDP) {
01973         err = EAFNOSUPPORT;
01974       }
01975       break;
01976     case IP_MULTICAST_LOOP:
01977       if (optlen < sizeof(u8_t)) {
01978         err = EINVAL;
01979       }
01980       if (NETCONNTYPE_GROUP(sock->conn->type) != NETCONN_UDP) {
01981         err = EAFNOSUPPORT;
01982       }
01983       break;
01984     case IP_ADD_MEMBERSHIP:
01985     case IP_DROP_MEMBERSHIP:
01986       if (optlen < sizeof(struct ip_mreq)) {
01987         err = EINVAL;
01988       }
01989       if (NETCONNTYPE_GROUP(sock->conn->type) != NETCONN_UDP) {
01990         err = EAFNOSUPPORT;
01991       }
01992       break;
01993 #endif /* LWIP_IGMP */
01994       default:
01995         LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IP, UNIMPL: optname=0x%x, ..)\n",
01996                     s, optname));
01997         err = ENOPROTOOPT;
01998     }  /* switch (optname) */
01999     break;
02000 
02001 #if LWIP_TCP
02002 /* Level: IPPROTO_TCP */
02003   case IPPROTO_TCP:
02004     if (optlen < sizeof(int)) {
02005       err = EINVAL;
02006       break;
02007     }
02008 
02009     /* If this is no TCP socket, ignore any options. */
02010     if (sock->conn->type != NETCONN_TCP)
02011       return 0;
02012 
02013     switch (optname) {
02014     case TCP_NODELAY:
02015     case TCP_KEEPALIVE:
02016 #if LWIP_TCP_KEEPALIVE
02017     case TCP_KEEPIDLE:
02018     case TCP_KEEPINTVL:
02019     case TCP_KEEPCNT:
02020 #endif /* LWIP_TCP_KEEPALIVE */
02021       break;
02022 
02023     default:
02024       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, UNIMPL: optname=0x%x, ..)\n",
02025                   s, optname));
02026       err = ENOPROTOOPT;
02027     }  /* switch (optname) */
02028     break;
02029 #endif /* LWIP_TCP */
02030 #if LWIP_UDP && LWIP_UDPLITE
02031 /* Level: IPPROTO_UDPLITE */
02032   case IPPROTO_UDPLITE:
02033     if (optlen < sizeof(int)) {
02034       err = EINVAL;
02035       break;
02036     }
02037 
02038     /* If this is no UDP lite socket, ignore any options. */
02039     if (sock->conn->type != NETCONN_UDPLITE)
02040       return 0;
02041 
02042     switch (optname) {
02043     case UDPLITE_SEND_CSCOV:
02044     case UDPLITE_RECV_CSCOV:
02045       break;
02046 
02047     default:
02048       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_UDPLITE, UNIMPL: optname=0x%x, ..)\n",
02049                   s, optname));
02050       err = ENOPROTOOPT;
02051     }  /* switch (optname) */
02052     break;
02053 #endif /* LWIP_UDP && LWIP_UDPLITE */
02054 /* UNDEFINED LEVEL */
02055   default:
02056     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, level=0x%x, UNIMPL: optname=0x%x, ..)\n",
02057                 s, level, optname));
02058     err = ENOPROTOOPT;
02059   }  /* switch (level) */
02060 
02061 
02062   if (err != ERR_OK) {
02063     sock_set_errno(sock, err);
02064     return -1;
02065   }
02066 
02067 
02068   /* Now do the actual option processing */
02069   data.sock = sock;
02070 #ifdef LWIP_DEBUG
02071   data.s = s;
02072 #endif /* LWIP_DEBUG */
02073   data.level = level;
02074   data.optname = optname;
02075   data.optval = (void*)optval;
02076   data.optlen = &optlen;
02077   data.err = err;
02078   tcpip_callback(lwip_setsockopt_internal, &data);
02079   sys_arch_sem_wait(&sock->conn->op_completed, 0);
02080   /* maybe lwip_setsockopt_internal has changed err */
02081   err = data.err;
02082 
02083   sock_set_errno(sock, err);
02084   return err ? -1 : 0;
02085 }
02086 
02087 static void
02088 lwip_setsockopt_internal(void *arg)
02089 {
02090   struct lwip_sock *sock;
02091 #ifdef LWIP_DEBUG
02092   int s;
02093 #endif /* LWIP_DEBUG */
02094   int level, optname;
02095   const void *optval;
02096   struct lwip_setgetsockopt_data *data;
02097 
02098   LWIP_ASSERT("arg != NULL", arg != NULL);
02099 
02100   data = (struct lwip_setgetsockopt_data*)arg;
02101   sock = data->sock;
02102 #ifdef LWIP_DEBUG
02103   s = data->s;
02104 #endif /* LWIP_DEBUG */
02105   level = data->level;
02106   optname = data->optname;
02107   optval = data->optval;
02108 
02109   switch (level) {
02110 
02111 /* Level: SOL_SOCKET */
02112   case SOL_SOCKET:
02113     switch (optname) {
02114 
02115     /* The option flags */
02116     case SO_BROADCAST:
02117     /* UNIMPL case SO_DEBUG: */
02118     /* UNIMPL case SO_DONTROUTE: */
02119     case SO_KEEPALIVE:
02120     /* UNIMPL case SO_OOBINCLUDE: */
02121 #if SO_REUSE
02122     case SO_REUSEADDR:
02123     case SO_REUSEPORT:
02124 #endif /* SO_REUSE */
02125     /* UNIMPL case SO_USELOOPBACK: */
02126       if (*(int*)optval) {
02127         ip_set_option(sock->conn->pcb.ip, optname);
02128       } else {
02129         ip_reset_option(sock->conn->pcb.ip, optname);
02130       }
02131       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, SOL_SOCKET, optname=0x%x, ..) -> %s\n",
02132                   s, optname, (*(int*)optval?"on":"off")));
02133       break;
02134 #if LWIP_SO_SNDTIMEO
02135     case SO_SNDTIMEO:
02136       netconn_set_sendtimeout(sock->conn, (s32_t)*(int*)optval);
02137       break;
02138 #endif /* LWIP_SO_SNDTIMEO */
02139 #if LWIP_SO_RCVTIMEO
02140     case SO_RCVTIMEO:
02141       netconn_set_recvtimeout(sock->conn, *(int*)optval);
02142       break;
02143 #endif /* LWIP_SO_RCVTIMEO */
02144 #if LWIP_SO_RCVBUF
02145     case SO_RCVBUF:
02146       netconn_set_recvbufsize(sock->conn, *(int*)optval);
02147       break;
02148 #endif /* LWIP_SO_RCVBUF */
02149 #if LWIP_UDP
02150     case SO_NO_CHECK:
02151       if (*(int*)optval) {
02152         udp_setflags(sock->conn->pcb.udp, udp_flags(sock->conn->pcb.udp) | UDP_FLAGS_NOCHKSUM);
02153       } else {
02154         udp_setflags(sock->conn->pcb.udp, udp_flags(sock->conn->pcb.udp) & ~UDP_FLAGS_NOCHKSUM);
02155       }
02156       break;
02157 #endif /* LWIP_UDP */
02158     default:
02159       LWIP_ASSERT("unhandled optname", 0);
02160       break;
02161     }  /* switch (optname) */
02162     break;
02163 
02164 /* Level: IPPROTO_IP */
02165   case IPPROTO_IP:
02166     switch (optname) {
02167     case IP_TTL:
02168       sock->conn->pcb.ip->ttl = (u8_t)(*(int*)optval);
02169       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IP, IP_TTL, ..) -> %d\n",
02170                   s, sock->conn->pcb.ip->ttl));
02171       break;
02172     case IP_TOS:
02173       sock->conn->pcb.ip->tos = (u8_t)(*(int*)optval);
02174       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IP, IP_TOS, ..)-> %d\n",
02175                   s, sock->conn->pcb.ip->tos));
02176       break;
02177 #if LWIP_IGMP
02178     case IP_MULTICAST_TTL:
02179       sock->conn->pcb.udp->ttl = (u8_t)(*(u8_t*)optval);
02180       break;
02181     case IP_MULTICAST_IF:
02182       inet_addr_to_ipaddr(&sock->conn->pcb.udp->multicast_ip, (struct in_addr*)optval);
02183       break;
02184     case IP_MULTICAST_LOOP:
02185       if (*(u8_t*)optval) {
02186         udp_setflags(sock->conn->pcb.udp, udp_flags(sock->conn->pcb.udp) | UDP_FLAGS_MULTICAST_LOOP);
02187       } else {
02188         udp_setflags(sock->conn->pcb.udp, udp_flags(sock->conn->pcb.udp) & ~UDP_FLAGS_MULTICAST_LOOP);
02189       }
02190       break;
02191     case IP_ADD_MEMBERSHIP:
02192     case IP_DROP_MEMBERSHIP:
02193       {
02194         /* If this is a TCP or a RAW socket, ignore these options. */
02195         struct ip_mreq *imr = (struct ip_mreq *)optval;
02196         ip_addr_t if_addr;
02197         ip_addr_t multi_addr;
02198         inet_addr_to_ipaddr(&if_addr, &imr->imr_interface);
02199         inet_addr_to_ipaddr(&multi_addr, &imr->imr_multiaddr);
02200         if(optname == IP_ADD_MEMBERSHIP){
02201           data->err = igmp_joingroup(&if_addr, &multi_addr);
02202         } else {
02203           data->err = igmp_leavegroup(&if_addr, &multi_addr);
02204         }
02205         if(data->err != ERR_OK) {
02206           data->err = EADDRNOTAVAIL;
02207         }
02208       }
02209       break;
02210 #endif /* LWIP_IGMP */
02211     default:
02212       LWIP_ASSERT("unhandled optname", 0);
02213       break;
02214     }  /* switch (optname) */
02215     break;
02216 
02217 #if LWIP_TCP
02218 /* Level: IPPROTO_TCP */
02219   case IPPROTO_TCP:
02220     switch (optname) {
02221     case TCP_NODELAY:
02222       if (*(int*)optval) {
02223         tcp_nagle_disable(sock->conn->pcb.tcp);
02224       } else {
02225         tcp_nagle_enable(sock->conn->pcb.tcp);
02226       }
02227       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_NODELAY) -> %s\n",
02228                   s, (*(int *)optval)?"on":"off") );
02229       break;
02230     case TCP_KEEPALIVE:
02231       sock->conn->pcb.tcp->keep_idle = (u32_t)(*(int*)optval);
02232       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPALIVE) -> %"U32_F"\n",
02233                   s, sock->conn->pcb.tcp->keep_idle));
02234       break;
02235 
02236 #if LWIP_TCP_KEEPALIVE
02237     case TCP_KEEPIDLE:
02238       sock->conn->pcb.tcp->keep_idle = 1000*(u32_t)(*(int*)optval);
02239       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPIDLE) -> %"U32_F"\n",
02240                   s, sock->conn->pcb.tcp->keep_idle));
02241       break;
02242     case TCP_KEEPINTVL:
02243       sock->conn->pcb.tcp->keep_intvl = 1000*(u32_t)(*(int*)optval);
02244       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPINTVL) -> %"U32_F"\n",
02245                   s, sock->conn->pcb.tcp->keep_intvl));
02246       break;
02247     case TCP_KEEPCNT:
02248       sock->conn->pcb.tcp->keep_cnt = (u32_t)(*(int*)optval);
02249       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPCNT) -> %"U32_F"\n",
02250                   s, sock->conn->pcb.tcp->keep_cnt));
02251       break;
02252 #endif /* LWIP_TCP_KEEPALIVE */
02253     default:
02254       LWIP_ASSERT("unhandled optname", 0);
02255       break;
02256     }  /* switch (optname) */
02257     break;
02258 #endif /* LWIP_TCP*/
02259 #if LWIP_UDP && LWIP_UDPLITE
02260   /* Level: IPPROTO_UDPLITE */
02261   case IPPROTO_UDPLITE:
02262     switch (optname) {
02263     case UDPLITE_SEND_CSCOV:
02264       if ((*(int*)optval != 0) && ((*(int*)optval < 8) || (*(int*)optval > 0xffff))) {
02265         /* don't allow illegal values! */
02266         sock->conn->pcb.udp->chksum_len_tx = 8;
02267       } else {
02268         sock->conn->pcb.udp->chksum_len_tx = (u16_t)*(int*)optval;
02269       }
02270       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_UDPLITE, UDPLITE_SEND_CSCOV) -> %d\n",
02271                   s, (*(int*)optval)) );
02272       break;
02273     case UDPLITE_RECV_CSCOV:
02274       if ((*(int*)optval != 0) && ((*(int*)optval < 8) || (*(int*)optval > 0xffff))) {
02275         /* don't allow illegal values! */
02276         sock->conn->pcb.udp->chksum_len_rx = 8;
02277       } else {
02278         sock->conn->pcb.udp->chksum_len_rx = (u16_t)*(int*)optval;
02279       }
02280       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_UDPLITE, UDPLITE_RECV_CSCOV) -> %d\n",
02281                   s, (*(int*)optval)) );
02282       break;
02283     default:
02284       LWIP_ASSERT("unhandled optname", 0);
02285       break;
02286     }  /* switch (optname) */
02287     break;
02288 #endif /* LWIP_UDP */
02289   default:
02290     LWIP_ASSERT("unhandled level", 0);
02291     break;
02292   }  /* switch (level) */
02293   sys_sem_signal(&sock->conn->op_completed);
02294 }
02295 
02296 int
02297 lwip_ioctl(int s, long cmd, void *argp)
02298 {
02299   struct lwip_sock *sock = get_socket(s);
02300   u8_t val;
02301 #if LWIP_SO_RCVBUF
02302   u16_t buflen = 0;
02303   s16_t recv_avail;
02304 #endif /* LWIP_SO_RCVBUF */
02305 
02306   if (!sock) {
02307     return -1;
02308   }
02309 
02310   switch (cmd) {
02311 #if LWIP_SO_RCVBUF
02312   case FIONREAD:
02313     if (!argp) {
02314       sock_set_errno(sock, EINVAL);
02315       return -1;
02316     }
02317 
02318     SYS_ARCH_GET(sock->conn->recv_avail, recv_avail);
02319     if (recv_avail < 0) {
02320       recv_avail = 0;
02321     }
02322     *((u16_t*)argp) = (u16_t)recv_avail;
02323 
02324     /* Check if there is data left from the last recv operation. /maq 041215 */
02325     if (sock->lastdata) {
02326       struct pbuf *p = (struct pbuf *)sock->lastdata;
02327       if (netconn_type(sock->conn) != NETCONN_TCP) {
02328         p = ((struct netbuf *)p)->p;
02329       }
02330       buflen = p->tot_len;
02331       buflen -= sock->lastoffset;
02332 
02333       *((u16_t*)argp) += buflen;
02334     }
02335 
02336     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(%d, FIONREAD, %p) = %"U16_F"\n", s, argp, *((u16_t*)argp)));
02337     sock_set_errno(sock, 0);
02338     return 0;
02339 #endif /* LWIP_SO_RCVBUF */
02340 
02341   case FIONBIO:
02342     val = 0;
02343     if (argp && *(u32_t*)argp) {
02344       val = 1;
02345     }
02346     netconn_set_nonblocking(sock->conn, val);
02347     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(%d, FIONBIO, %d)\n", s, val));
02348     sock_set_errno(sock, 0);
02349     return 0;
02350 
02351   default:
02352     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(%d, UNIMPL: 0x%lx, %p)\n", s, cmd, argp));
02353     sock_set_errno(sock, ENOSYS); /* not yet implemented */
02354     return -1;
02355   } /* switch (cmd) */
02356 }
02357 
02358 /** A minimal implementation of fcntl.
02359  * Currently only the commands F_GETFL and F_SETFL are implemented.
02360  * Only the flag O_NONBLOCK is implemented.
02361  */
02362 int
02363 lwip_fcntl(int s, int cmd, int val)
02364 {
02365   struct lwip_sock *sock = get_socket(s);
02366   int ret = -1;
02367 
02368   if (!sock || !sock->conn) {
02369     return -1;
02370   }
02371 
02372   switch (cmd) {
02373   case F_GETFL:
02374     ret = netconn_is_nonblocking(sock->conn) ? O_NONBLOCK : 0;
02375     break;
02376   case F_SETFL:
02377     if ((val & ~O_NONBLOCK) == 0) {
02378       /* only O_NONBLOCK, all other bits are zero */
02379       netconn_set_nonblocking(sock->conn, val & O_NONBLOCK);
02380       ret = 0;
02381     }
02382     break;
02383   default:
02384     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_fcntl(%d, UNIMPL: %d, %d)\n", s, cmd, val));
02385     break;
02386   }
02387   return ret;
02388 }
02389 
02390 #endif /* LWIP_SOCKET */