ON Semiconductor / mbed-os

Dependents:   mbed-TFT-example-NCS36510 mbed-Accelerometer-example-NCS36510 mbed-Accelerometer-example-NCS36510

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers lwip_sockets.c Source File

lwip_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 /**
00042  * @defgroup socket Socket API
00043  * @ingroup threadsafe_api
00044  * BSD-style socket API.\n
00045  * Thread-safe, to be called from non-TCPIP threads only.\n
00046  * Can be activated by defining LWIP_SOCKET to 1.\n
00047  * Header is in posix/sys/socket.h\b
00048  */
00049 
00050 #include "lwip/opt.h"
00051 
00052 #if LWIP_SOCKET /* don't build if not configured for use in lwipopts.h */
00053 
00054 #include "lwip/sockets.h"
00055 #include "lwip/api.h"
00056 #include "lwip/sys.h"
00057 #include "lwip/igmp.h"
00058 #include "lwip/inet.h"
00059 #include "lwip/tcp.h"
00060 #include "lwip/raw.h"
00061 #include "lwip/udp.h"
00062 #include "lwip/memp.h"
00063 #include "lwip/pbuf.h"
00064 #include "lwip/priv/tcpip_priv.h"
00065 #if LWIP_CHECKSUM_ON_COPY
00066 #include "lwip/inet_chksum.h"
00067 #endif
00068 
00069 #include <string.h>
00070 
00071 /* If the netconn API is not required publicly, then we include the necessary
00072    files here to get the implementation */
00073 #if !LWIP_NETCONN
00074 #undef LWIP_NETCONN
00075 #define LWIP_NETCONN 1
00076 #include "api_msg.c"
00077 #include "api_lib.c"
00078 #include "netbuf.c"
00079 #undef LWIP_NETCONN
00080 #define LWIP_NETCONN 0
00081 #endif
00082 
00083 #if LWIP_IPV4
00084 #define IP4ADDR_PORT_TO_SOCKADDR(sin, ipaddr, port) do { \
00085       (sin)->sin_len = sizeof(struct sockaddr_in); \
00086       (sin)->sin_family = AF_INET; \
00087       (sin)->sin_port = htons((port)); \
00088       inet_addr_from_ipaddr(&(sin)->sin_addr, ipaddr); \
00089       memset((sin)->sin_zero, 0, SIN_ZERO_LEN); }while(0)
00090 #define SOCKADDR4_TO_IP4ADDR_PORT(sin, ipaddr, port) do { \
00091     inet_addr_to_ipaddr(ip_2_ip4(ipaddr), &((sin)->sin_addr)); \
00092     (port) = ntohs((sin)->sin_port); }while(0)
00093 #endif /* LWIP_IPV4 */
00094 
00095 #if LWIP_IPV6
00096 #define IP6ADDR_PORT_TO_SOCKADDR(sin6, ipaddr, port) do { \
00097       (sin6)->sin6_len = sizeof(struct sockaddr_in6); \
00098       (sin6)->sin6_family = AF_INET6; \
00099       (sin6)->sin6_port = htons((port)); \
00100       (sin6)->sin6_flowinfo = 0; \
00101       inet6_addr_from_ip6addr(&(sin6)->sin6_addr, ipaddr); \
00102       (sin6)->sin6_scope_id = 0; }while(0)
00103 #define SOCKADDR6_TO_IP6ADDR_PORT(sin6, ipaddr, port) do { \
00104     inet6_addr_to_ip6addr(ip_2_ip6(ipaddr), &((sin6)->sin6_addr)); \
00105     (port) = ntohs((sin6)->sin6_port); }while(0)
00106 #endif /* LWIP_IPV6 */
00107 
00108 #if LWIP_IPV4 && LWIP_IPV6
00109 static void sockaddr_to_ipaddr_port(const struct sockaddr* sockaddr, ip_addr_t* ipaddr, u16_t* port);
00110 
00111 #define IS_SOCK_ADDR_LEN_VALID(namelen)  (((namelen) == sizeof(struct sockaddr_in)) || \
00112                                          ((namelen) == sizeof(struct sockaddr_in6)))
00113 #define IS_SOCK_ADDR_TYPE_VALID(name)    (((name)->sa_family == AF_INET) || \
00114                                          ((name)->sa_family == AF_INET6))
00115 #define SOCK_ADDR_TYPE_MATCH(name, sock) \
00116        ((((name)->sa_family == AF_INET) && !(NETCONNTYPE_ISIPV6((sock)->conn->type))) || \
00117        (((name)->sa_family == AF_INET6) && (NETCONNTYPE_ISIPV6((sock)->conn->type))))
00118 #define IPADDR_PORT_TO_SOCKADDR(sockaddr, ipaddr, port) do { \
00119     if (IP_IS_V6(ipaddr)) { \
00120       IP6ADDR_PORT_TO_SOCKADDR((struct sockaddr_in6*)(void*)(sockaddr), ip_2_ip6(ipaddr), port); \
00121     } else { \
00122       IP4ADDR_PORT_TO_SOCKADDR((struct sockaddr_in*)(void*)(sockaddr), ip_2_ip4(ipaddr), port); \
00123     } } while(0)
00124 #define SOCKADDR_TO_IPADDR_PORT(sockaddr, ipaddr, port) sockaddr_to_ipaddr_port(sockaddr, ipaddr, &(port))
00125 #define DOMAIN_TO_NETCONN_TYPE(domain, type) (((domain) == AF_INET) ? \
00126   (type) : (enum netconn_type)((type) | NETCONN_TYPE_IPV6))
00127 #elif LWIP_IPV6 /* LWIP_IPV4 && LWIP_IPV6 */
00128 #define IS_SOCK_ADDR_LEN_VALID(namelen)  ((namelen) == sizeof(struct sockaddr_in6))
00129 #define IS_SOCK_ADDR_TYPE_VALID(name)    ((name)->sa_family == AF_INET6)
00130 #define SOCK_ADDR_TYPE_MATCH(name, sock) 1
00131 #define IPADDR_PORT_TO_SOCKADDR(sockaddr, ipaddr, port) \
00132         IP6ADDR_PORT_TO_SOCKADDR((struct sockaddr_in6*)(void*)(sockaddr), ip_2_ip6(ipaddr), port)
00133 #define SOCKADDR_TO_IPADDR_PORT(sockaddr, ipaddr, port) \
00134         SOCKADDR6_TO_IP6ADDR_PORT((const struct sockaddr_in6*)(const void*)(sockaddr), ipaddr, port)
00135 #define DOMAIN_TO_NETCONN_TYPE(domain, netconn_type) (netconn_type)
00136 #else /*-> LWIP_IPV4: LWIP_IPV4 && LWIP_IPV6 */
00137 #define IS_SOCK_ADDR_LEN_VALID(namelen)  ((namelen) == sizeof(struct sockaddr_in))
00138 #define IS_SOCK_ADDR_TYPE_VALID(name)    ((name)->sa_family == AF_INET)
00139 #define SOCK_ADDR_TYPE_MATCH(name, sock) 1
00140 #define IPADDR_PORT_TO_SOCKADDR(sockaddr, ipaddr, port) \
00141         IP4ADDR_PORT_TO_SOCKADDR((struct sockaddr_in*)(void*)(sockaddr), ip_2_ip4(ipaddr), port)
00142 #define SOCKADDR_TO_IPADDR_PORT(sockaddr, ipaddr, port) \
00143         SOCKADDR4_TO_IP4ADDR_PORT((const struct sockaddr_in*)(const void*)(sockaddr), ipaddr, port)
00144 #define DOMAIN_TO_NETCONN_TYPE(domain, netconn_type) (netconn_type)
00145 #endif /* LWIP_IPV6 */
00146 
00147 #define IS_SOCK_ADDR_TYPE_VALID_OR_UNSPEC(name)    (((name)->sa_family == AF_UNSPEC) || \
00148                                                     IS_SOCK_ADDR_TYPE_VALID(name))
00149 #define SOCK_ADDR_TYPE_MATCH_OR_UNSPEC(name, sock) (((name)->sa_family == AF_UNSPEC) || \
00150                                                     SOCK_ADDR_TYPE_MATCH(name, sock))
00151 #define IS_SOCK_ADDR_ALIGNED(name)      ((((mem_ptr_t)(name)) % 4) == 0)
00152 
00153 
00154 #define LWIP_SOCKOPT_CHECK_OPTLEN(optlen, opttype) do { if ((optlen) < sizeof(opttype)) { return EINVAL; }}while(0)
00155 #define LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, optlen, opttype) do { \
00156   LWIP_SOCKOPT_CHECK_OPTLEN(optlen, opttype); \
00157   if ((sock)->conn == NULL) { return EINVAL; } }while(0)
00158 #define LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, optlen, opttype) do { \
00159   LWIP_SOCKOPT_CHECK_OPTLEN(optlen, opttype); \
00160   if (((sock)->conn == NULL) || ((sock)->conn->pcb.tcp == NULL)) { return EINVAL; } }while(0)
00161 #define LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, opttype, netconntype) do { \
00162   LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, optlen, opttype); \
00163   if (NETCONNTYPE_GROUP(netconn_type((sock)->conn)) != netconntype) { return ENOPROTOOPT; } }while(0)
00164 
00165 
00166 #define LWIP_SETGETSOCKOPT_DATA_VAR_REF(name)     API_VAR_REF(name)
00167 #define LWIP_SETGETSOCKOPT_DATA_VAR_DECLARE(name) API_VAR_DECLARE(struct lwip_setgetsockopt_data, name)
00168 #define LWIP_SETGETSOCKOPT_DATA_VAR_FREE(name)    API_VAR_FREE(MEMP_SOCKET_SETGETSOCKOPT_DATA, name)
00169 #if LWIP_MPU_COMPATIBLE
00170 #define LWIP_SETGETSOCKOPT_DATA_VAR_ALLOC(name, sock) do { \
00171   name = (struct lwip_setgetsockopt_data *)memp_malloc(MEMP_SOCKET_SETGETSOCKOPT_DATA); \
00172   if (name == NULL) { \
00173     sock_set_errno(sock, ENOMEM); \
00174     return -1; \
00175   } }while(0)
00176 #else /* LWIP_MPU_COMPATIBLE */
00177 #define LWIP_SETGETSOCKOPT_DATA_VAR_ALLOC(name, sock)
00178 #endif /* LWIP_MPU_COMPATIBLE */
00179 
00180 #if LWIP_SO_SNDRCVTIMEO_NONSTANDARD
00181 #define LWIP_SO_SNDRCVTIMEO_OPTTYPE int
00182 #define LWIP_SO_SNDRCVTIMEO_SET(optval, val) (*(int *)(optval) = (val))
00183 #define LWIP_SO_SNDRCVTIMEO_GET_MS(optval)   ((s32_t)*(const int*)(optval))
00184 #else
00185 #define LWIP_SO_SNDRCVTIMEO_OPTTYPE struct timeval
00186 #define LWIP_SO_SNDRCVTIMEO_SET(optval, val)  do { \
00187   s32_t loc = (val); \
00188   ((struct timeval *)(optval))->tv_sec = (loc) / 1000U; \
00189   ((struct timeval *)(optval))->tv_usec = ((loc) % 1000U) * 1000U; }while(0)
00190 #define LWIP_SO_SNDRCVTIMEO_GET_MS(optval) ((((const struct timeval *)(optval))->tv_sec * 1000U) + (((const struct timeval *)(optval))->tv_usec / 1000U))
00191 #endif
00192 
00193 #define NUM_SOCKETS MEMP_NUM_NETCONN
00194 
00195 /** This is overridable for the rare case where more than 255 threads
00196  * select on the same socket...
00197  */
00198 #ifndef SELWAIT_T
00199 #define SELWAIT_T u8_t
00200 #endif
00201 
00202 /** Contains all internal pointers and states used for a socket */
00203 struct lwip_sock {
00204   /** sockets currently are built on netconns, each socket has one netconn */
00205   struct netconn *conn;
00206   /** data that was left from the previous read */
00207   void *lastdata;
00208   /** offset in the data that was left from the previous read */
00209   u16_t lastoffset;
00210   /** number of times data was received, set by event_callback(),
00211       tested by the receive and select functions */
00212   s16_t rcvevent;
00213   /** number of times data was ACKed (free send buffer), set by event_callback(),
00214       tested by select */
00215   u16_t sendevent;
00216   /** error happened for this socket, set by event_callback(), tested by select */
00217   u16_t errevent;
00218   /** last error that occurred on this socket (in fact, all our errnos fit into an u8_t) */
00219   u8_t err;
00220   /** counter of how many threads are waiting for this socket using select */
00221   SELWAIT_T select_waiting;
00222 };
00223 
00224 #if LWIP_NETCONN_SEM_PER_THREAD
00225 #define SELECT_SEM_T        sys_sem_t*
00226 #define SELECT_SEM_PTR(sem) (sem)
00227 #else /* LWIP_NETCONN_SEM_PER_THREAD */
00228 #define SELECT_SEM_T        sys_sem_t
00229 #define SELECT_SEM_PTR(sem) (&(sem))
00230 #endif /* LWIP_NETCONN_SEM_PER_THREAD */
00231 
00232 /** Description for a task waiting in select */
00233 struct lwip_select_cb {
00234   /** Pointer to the next waiting task */
00235   struct lwip_select_cb *next;
00236   /** Pointer to the previous waiting task */
00237   struct lwip_select_cb *prev;
00238   /** readset passed to select */
00239   fd_set *readset;
00240   /** writeset passed to select */
00241   fd_set *writeset;
00242   /** unimplemented: exceptset passed to select */
00243   fd_set *exceptset;
00244   /** don't signal the same semaphore twice: set to 1 when signalled */
00245   int sem_signalled;
00246   /** semaphore to wake up a task waiting for select */
00247   SELECT_SEM_T sem;
00248 };
00249 
00250 /** A struct sockaddr replacement that has the same alignment as sockaddr_in/
00251  *  sockaddr_in6 if instantiated.
00252  */
00253 union sockaddr_aligned {
00254    struct sockaddr sa;
00255 #if LWIP_IPV6
00256    struct sockaddr_in6 sin6;
00257 #endif /* LWIP_IPV6 */
00258 #if LWIP_IPV4
00259    struct sockaddr_in sin;
00260 #endif /* LWIP_IPV4 */
00261 };
00262 
00263 #if LWIP_IGMP
00264 /* Define the number of IPv4 multicast memberships, default is one per socket */
00265 #ifndef LWIP_SOCKET_MAX_MEMBERSHIPS
00266 #define LWIP_SOCKET_MAX_MEMBERSHIPS NUM_SOCKETS
00267 #endif
00268 
00269 /* This is to keep track of IP_ADD_MEMBERSHIP calls to drop the membership when
00270    a socket is closed */
00271 struct lwip_socket_multicast_pair {
00272   /** the socket (+1 to not require initialization) */
00273   int sa;
00274   /** the interface address */
00275   ip4_addr_t if_addr;
00276   /** the group address */
00277   ip4_addr_t multi_addr;
00278 };
00279 
00280 struct lwip_socket_multicast_pair socket_ipv4_multicast_memberships[LWIP_SOCKET_MAX_MEMBERSHIPS];
00281 
00282 static int  lwip_socket_register_membership(int s, const ip4_addr_t *if_addr, const ip4_addr_t *multi_addr);
00283 static void lwip_socket_unregister_membership(int s, const ip4_addr_t *if_addr, const ip4_addr_t *multi_addr);
00284 static void lwip_socket_drop_registered_memberships(int s);
00285 #endif /* LWIP_IGMP */
00286 
00287 /** The global array of available sockets */
00288 static struct lwip_sock sockets[NUM_SOCKETS];
00289 /** The global list of tasks waiting for select */
00290 static struct lwip_select_cb *select_cb_list;
00291 /** This counter is increased from lwip_select when the list is changed
00292     and checked in event_callback to see if it has changed. */
00293 static volatile int select_cb_ctr;
00294 
00295 /** Table to quickly map an lwIP error (err_t) to a socket error
00296   * by using -err as an index */
00297 static const int err_to_errno_table[] = {
00298   0,             /* ERR_OK          0      No error, everything OK. */
00299   ENOMEM,        /* ERR_MEM        -1      Out of memory error.     */
00300   ENOBUFS,       /* ERR_BUF        -2      Buffer error.            */
00301   EWOULDBLOCK,   /* ERR_TIMEOUT    -3      Timeout                  */
00302   EHOSTUNREACH,  /* ERR_RTE        -4      Routing problem.         */
00303   EINPROGRESS,   /* ERR_INPROGRESS -5      Operation in progress    */
00304   EINVAL,        /* ERR_VAL        -6      Illegal value.           */
00305   EWOULDBLOCK,   /* ERR_WOULDBLOCK -7      Operation would block.   */
00306   EADDRINUSE,    /* ERR_USE        -8      Address in use.          */
00307   EALREADY,      /* ERR_ALREADY    -9      Already connecting.      */
00308   EISCONN,       /* ERR_ISCONN     -10     Conn already established.*/
00309   ENOTCONN,      /* ERR_CONN       -11     Not connected.           */
00310   -1,            /* ERR_IF         -12     Low-level netif error    */
00311   ECONNABORTED,  /* ERR_ABRT       -13     Connection aborted.      */
00312   ECONNRESET,    /* ERR_RST        -14     Connection reset.        */
00313   ENOTCONN,      /* ERR_CLSD       -15     Connection closed.       */
00314   EIO            /* ERR_ARG        -16     Illegal argument.        */
00315 };
00316 
00317 #define ERR_TO_ERRNO_TABLE_SIZE LWIP_ARRAYSIZE(err_to_errno_table)
00318 
00319 #define err_to_errno(err) \
00320   ((unsigned)(-(signed)(err)) < ERR_TO_ERRNO_TABLE_SIZE ? \
00321     err_to_errno_table[-(signed)(err)] : EIO)
00322 
00323 #if LWIP_SOCKET_SET_ERRNO
00324 #ifndef set_errno
00325 #define set_errno(err) do { if (err) { errno = (err); } } while(0)
00326 #endif
00327 #else /* LWIP_SOCKET_SET_ERRNO */
00328 #define set_errno(err)
00329 #endif /* LWIP_SOCKET_SET_ERRNO */
00330 
00331 #define sock_set_errno(sk, e) do { \
00332   const int sockerr = (e); \
00333   sk->err = (u8_t)sockerr; \
00334   set_errno(sockerr); \
00335 } while (0)
00336 
00337 /* Forward declaration of some functions */
00338 static void event_callback(struct netconn *conn, enum netconn_evt evt, u16_t len);
00339 #if !LWIP_TCPIP_CORE_LOCKING
00340 static void lwip_getsockopt_callback(void *arg);
00341 static void lwip_setsockopt_callback(void *arg);
00342 #endif
00343 static u8_t lwip_getsockopt_impl(int s, int level, int optname, void *optval, socklen_t *optlen);
00344 static u8_t lwip_setsockopt_impl(int s, int level, int optname, const void *optval, socklen_t optlen);
00345 
00346 #if LWIP_IPV4 && LWIP_IPV6
00347 static void
00348 sockaddr_to_ipaddr_port(const struct sockaddr* sockaddr, ip_addr_t* ipaddr, u16_t* port)
00349 {
00350   if ((sockaddr->sa_family) == AF_INET6) {
00351     SOCKADDR6_TO_IP6ADDR_PORT((const struct sockaddr_in6*)(const void*)(sockaddr), ipaddr, *port);
00352     ipaddr->type = IPADDR_TYPE_V6;
00353   } else {
00354     SOCKADDR4_TO_IP4ADDR_PORT((const struct sockaddr_in*)(const void*)(sockaddr), ipaddr, *port);
00355     ipaddr->type = IPADDR_TYPE_V4;
00356   }
00357 }
00358 #endif /* LWIP_IPV4 && LWIP_IPV6 */
00359 
00360 /** LWIP_NETCONN_SEM_PER_THREAD==1: initialize thread-local semaphore */
00361 void
00362 lwip_socket_thread_init(void)
00363 {
00364    netconn_thread_init();
00365 }
00366 
00367 /** LWIP_NETCONN_SEM_PER_THREAD==1: destroy thread-local semaphore */
00368 void
00369 lwip_socket_thread_cleanup(void)
00370 {
00371    netconn_thread_cleanup();
00372 }
00373 
00374 /**
00375  * Map a externally used socket index to the internal socket representation.
00376  *
00377  * @param s externally used socket index
00378  * @return struct lwip_sock for the socket or NULL if not found
00379  */
00380 static struct lwip_sock *
00381 get_socket(int s)
00382 {
00383   struct lwip_sock *sock;
00384 
00385   s -= LWIP_SOCKET_OFFSET;
00386 
00387   if ((s < 0) || (s >= NUM_SOCKETS)) {
00388     LWIP_DEBUGF(SOCKETS_DEBUG, ("get_socket(%d): invalid\n", s + LWIP_SOCKET_OFFSET));
00389     set_errno(EBADF);
00390     return NULL;
00391   }
00392 
00393   sock = &sockets[s];
00394 
00395   if (!sock->conn) {
00396     LWIP_DEBUGF(SOCKETS_DEBUG, ("get_socket(%d): not active\n", s + LWIP_SOCKET_OFFSET));
00397     set_errno(EBADF);
00398     return NULL;
00399   }
00400 
00401   return sock;
00402 }
00403 
00404 /**
00405  * Same as get_socket but doesn't set errno
00406  *
00407  * @param s externally used socket index
00408  * @return struct lwip_sock for the socket or NULL if not found
00409  */
00410 static struct lwip_sock *
00411 tryget_socket(int s)
00412 {
00413   s -= LWIP_SOCKET_OFFSET;
00414   if ((s < 0) || (s >= NUM_SOCKETS)) {
00415     return NULL;
00416   }
00417   if (!sockets[s].conn) {
00418     return NULL;
00419   }
00420   return &sockets[s];
00421 }
00422 
00423 /**
00424  * Allocate a new socket for a given netconn.
00425  *
00426  * @param newconn the netconn for which to allocate a socket
00427  * @param accepted 1 if socket has been created by accept(),
00428  *                 0 if socket has been created by socket()
00429  * @return the index of the new socket; -1 on error
00430  */
00431 static int
00432 alloc_socket(struct netconn *newconn, int accepted)
00433 {
00434   int i;
00435   SYS_ARCH_DECL_PROTECT(lev);
00436 
00437   /* allocate a new socket identifier */
00438   for (i = 0; i < NUM_SOCKETS; ++i) {
00439     /* Protect socket array */
00440     SYS_ARCH_PROTECT(lev);
00441     if (!sockets[i].conn) {
00442       sockets[i].conn       = newconn;
00443       /* The socket is not yet known to anyone, so no need to protect
00444          after having marked it as used. */
00445       SYS_ARCH_UNPROTECT(lev);
00446       sockets[i].lastdata   = NULL;
00447       sockets[i].lastoffset = 0;
00448       sockets[i].rcvevent   = 0;
00449       /* TCP sendbuf is empty, but the socket is not yet writable until connected
00450        * (unless it has been created by accept()). */
00451       sockets[i].sendevent  = (NETCONNTYPE_GROUP(newconn->type) == NETCONN_TCP ? (accepted != 0) : 1);
00452       sockets[i].errevent   = 0;
00453       sockets[i].err        = 0;
00454       sockets[i].select_waiting = 0;
00455       return i + LWIP_SOCKET_OFFSET;
00456     }
00457     SYS_ARCH_UNPROTECT(lev);
00458   }
00459   return -1;
00460 }
00461 
00462 /** Free a socket. The socket's netconn must have been
00463  * delete before!
00464  *
00465  * @param sock the socket to free
00466  * @param is_tcp != 0 for TCP sockets, used to free lastdata
00467  */
00468 static void
00469 free_socket(struct lwip_sock *sock, int is_tcp)
00470 {
00471   void *lastdata;
00472 
00473   lastdata         = sock->lastdata;
00474   sock->lastdata   = NULL;
00475   sock->lastoffset = 0;
00476   sock->err        = 0;
00477 
00478   /* Protect socket array */
00479   SYS_ARCH_SET(sock->conn, NULL);
00480   /* don't use 'sock' after this line, as another task might have allocated it */
00481 
00482   if (lastdata != NULL) {
00483     if (is_tcp) {
00484       pbuf_free((struct pbuf *)lastdata);
00485     } else {
00486       netbuf_delete((struct netbuf *)lastdata);
00487     }
00488   }
00489 }
00490 
00491 /* Below this, the well-known socket functions are implemented.
00492  * Use google.com or opengroup.org to get a good description :-)
00493  *
00494  * Exceptions are documented!
00495  */
00496 
00497 int
00498 lwip_accept(int s, struct sockaddr *addr, socklen_t *addrlen)
00499 {
00500   struct lwip_sock *sock, *nsock;
00501   struct netconn *newconn;
00502   ip_addr_t naddr;
00503   u16_t port = 0;
00504   int newsock;
00505   err_t err;
00506   SYS_ARCH_DECL_PROTECT(lev);
00507 
00508   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d)...\n", s));
00509   sock = get_socket(s);
00510   if (!sock) {
00511     return -1;
00512   }
00513 
00514   if (netconn_is_nonblocking(sock->conn) && (sock->rcvevent <= 0)) {
00515     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d): returning EWOULDBLOCK\n", s));
00516     sock_set_errno(sock, EWOULDBLOCK);
00517     return -1;
00518   }
00519 
00520   /* wait for a new connection */
00521   err = netconn_accept(sock->conn, &newconn);
00522   if (err != ERR_OK) {
00523     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d): netconn_acept failed, err=%d\n", s, err));
00524     if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_TCP) {
00525       sock_set_errno(sock, EOPNOTSUPP);
00526     } else if (err == ERR_CLSD) {
00527       sock_set_errno(sock, EINVAL);
00528     } else {
00529       sock_set_errno(sock, err_to_errno(err));
00530     }
00531     return -1;
00532   }
00533   LWIP_ASSERT("newconn != NULL", newconn != NULL);
00534 
00535   newsock = alloc_socket(newconn, 1);
00536   if (newsock == -1) {
00537     netconn_delete(newconn);
00538     sock_set_errno(sock, ENFILE);
00539     return -1;
00540   }
00541   LWIP_ASSERT("invalid socket index", (newsock >= LWIP_SOCKET_OFFSET) && (newsock < NUM_SOCKETS + LWIP_SOCKET_OFFSET));
00542   LWIP_ASSERT("newconn->callback == event_callback", newconn->callback == event_callback);
00543   nsock = &sockets[newsock - LWIP_SOCKET_OFFSET];
00544 
00545   /* See event_callback: If data comes in right away after an accept, even
00546    * though the server task might not have created a new socket yet.
00547    * In that case, newconn->socket is counted down (newconn->socket--),
00548    * so nsock->rcvevent is >= 1 here!
00549    */
00550   SYS_ARCH_PROTECT(lev);
00551   nsock->rcvevent += (s16_t)(-1 - newconn->socket);
00552   newconn->socket = newsock;
00553   SYS_ARCH_UNPROTECT(lev);
00554 
00555   /* Note that POSIX only requires us to check addr is non-NULL. addrlen must
00556    * not be NULL if addr is valid.
00557    */
00558   if (addr != NULL) {
00559     union sockaddr_aligned tempaddr;
00560     /* get the IP address and port of the remote host */
00561     err = netconn_peer(newconn, &naddr, &port);
00562     if (err != ERR_OK) {
00563       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d): netconn_peer failed, err=%d\n", s, err));
00564       netconn_delete(newconn);
00565       free_socket(nsock, 1);
00566       sock_set_errno(sock, err_to_errno(err));
00567       return -1;
00568     }
00569     LWIP_ASSERT("addr valid but addrlen NULL", addrlen != NULL);
00570 
00571     IPADDR_PORT_TO_SOCKADDR(&tempaddr, &naddr, port);
00572     if (*addrlen > tempaddr.sa.sa_len) {
00573       *addrlen = tempaddr.sa.sa_len;
00574     }
00575     MEMCPY(addr, &tempaddr, *addrlen);
00576 
00577     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d) returning new sock=%d addr=", s, newsock));
00578     ip_addr_debug_print_val(SOCKETS_DEBUG, naddr);
00579     LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F"\n", port));
00580   } else {
00581     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d) returning new sock=%d", s, newsock));
00582   }
00583 
00584   sock_set_errno(sock, 0);
00585   return newsock;
00586 }
00587 
00588 int
00589 lwip_bind(int s, const struct sockaddr *name, socklen_t namelen)
00590 {
00591   struct lwip_sock *sock;
00592   ip_addr_t local_addr;
00593   u16_t local_port;
00594   err_t err;
00595 
00596   sock = get_socket(s);
00597   if (!sock) {
00598     return -1;
00599   }
00600 
00601   if (!SOCK_ADDR_TYPE_MATCH(name, sock)) {
00602     /* sockaddr does not match socket type (IPv4/IPv6) */
00603     sock_set_errno(sock, err_to_errno(ERR_VAL));
00604     return -1;
00605   }
00606 
00607   /* check size, family and alignment of 'name' */
00608   LWIP_ERROR("lwip_bind: invalid address", (IS_SOCK_ADDR_LEN_VALID(namelen) &&
00609              IS_SOCK_ADDR_TYPE_VALID(name) && IS_SOCK_ADDR_ALIGNED(name)),
00610              sock_set_errno(sock, err_to_errno(ERR_ARG)); return -1;);
00611   LWIP_UNUSED_ARG(namelen);
00612 
00613   SOCKADDR_TO_IPADDR_PORT(name, &local_addr, local_port);
00614   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d, addr=", s));
00615   ip_addr_debug_print_val(SOCKETS_DEBUG, local_addr);
00616   LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F")\n", local_port));
00617 
00618   err = netconn_bind(sock->conn, &local_addr, local_port);
00619 
00620   if (err != ERR_OK) {
00621     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d) failed, err=%d\n", s, err));
00622     sock_set_errno(sock, err_to_errno(err));
00623     return -1;
00624   }
00625 
00626   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d) succeeded\n", s));
00627   sock_set_errno(sock, 0);
00628   return 0;
00629 }
00630 
00631 int
00632 lwip_close(int s)
00633 {
00634   struct lwip_sock *sock;
00635   int is_tcp = 0;
00636   err_t err;
00637 
00638   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_close(%d)\n", s));
00639 
00640   sock = get_socket(s);
00641   if (!sock) {
00642     return -1;
00643   }
00644 
00645   if (sock->conn != NULL) {
00646     is_tcp = NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP;
00647   } else {
00648     LWIP_ASSERT("sock->lastdata == NULL", sock->lastdata == NULL);
00649   }
00650 
00651 #if LWIP_IGMP
00652   /* drop all possibly joined IGMP memberships */
00653   lwip_socket_drop_registered_memberships(s);
00654 #endif /* LWIP_IGMP */
00655 
00656   err = netconn_delete(sock->conn);
00657   if (err != ERR_OK) {
00658     sock_set_errno(sock, err_to_errno(err));
00659     return -1;
00660   }
00661 
00662   free_socket(sock, is_tcp);
00663   set_errno(0);
00664   return 0;
00665 }
00666 
00667 int
00668 lwip_connect(int s, const struct sockaddr *name, socklen_t namelen)
00669 {
00670   struct lwip_sock *sock;
00671   err_t err;
00672 
00673   sock = get_socket(s);
00674   if (!sock) {
00675     return -1;
00676   }
00677 
00678   if (!SOCK_ADDR_TYPE_MATCH_OR_UNSPEC(name, sock)) {
00679     /* sockaddr does not match socket type (IPv4/IPv6) */
00680     sock_set_errno(sock, err_to_errno(ERR_VAL));
00681     return -1;
00682   }
00683 
00684   LWIP_UNUSED_ARG(namelen);
00685   if (name->sa_family == AF_UNSPEC) {
00686     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d, AF_UNSPEC)\n", s));
00687     err = netconn_disconnect(sock->conn);
00688   } else {
00689     ip_addr_t remote_addr;
00690     u16_t remote_port;
00691 
00692     /* check size, family and alignment of 'name' */
00693     LWIP_ERROR("lwip_connect: invalid address", IS_SOCK_ADDR_LEN_VALID(namelen) &&
00694                IS_SOCK_ADDR_TYPE_VALID_OR_UNSPEC(name) && IS_SOCK_ADDR_ALIGNED(name),
00695                sock_set_errno(sock, err_to_errno(ERR_ARG)); return -1;);
00696 
00697     SOCKADDR_TO_IPADDR_PORT(name, &remote_addr, remote_port);
00698     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d, addr=", s));
00699     ip_addr_debug_print_val(SOCKETS_DEBUG, remote_addr);
00700     LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F")\n", remote_port));
00701 
00702     err = netconn_connect(sock->conn, &remote_addr, remote_port);
00703   }
00704 
00705   if (err != ERR_OK) {
00706     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d) failed, err=%d\n", s, err));
00707     sock_set_errno(sock, err_to_errno(err));
00708     return -1;
00709   }
00710 
00711   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d) succeeded\n", s));
00712   sock_set_errno(sock, 0);
00713   return 0;
00714 }
00715 
00716 /**
00717  * Set a socket into listen mode.
00718  * The socket may not have been used for another connection previously.
00719  *
00720  * @param s the socket to set to listening mode
00721  * @param backlog (ATTENTION: needs TCP_LISTEN_BACKLOG=1)
00722  * @return 0 on success, non-zero on failure
00723  */
00724 int
00725 lwip_listen(int s, int backlog)
00726 {
00727   struct lwip_sock *sock;
00728   err_t err;
00729 
00730   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_listen(%d, backlog=%d)\n", s, backlog));
00731 
00732   sock = get_socket(s);
00733   if (!sock) {
00734     return -1;
00735   }
00736 
00737   /* limit the "backlog" parameter to fit in an u8_t */
00738   backlog = LWIP_MIN(LWIP_MAX(backlog, 0), 0xff);
00739 
00740   err = netconn_listen_with_backlog(sock->conn, (u8_t)backlog);
00741 
00742   if (err != ERR_OK) {
00743     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_listen(%d) failed, err=%d\n", s, err));
00744     if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_TCP) {
00745       sock_set_errno(sock, EOPNOTSUPP);
00746       return -1;
00747     }
00748     sock_set_errno(sock, err_to_errno(err));
00749     return -1;
00750   }
00751 
00752   sock_set_errno(sock, 0);
00753   return 0;
00754 }
00755 
00756 int
00757 lwip_recvfrom(int s, void *mem, size_t len, int flags,
00758               struct sockaddr *from, socklen_t *fromlen)
00759 {
00760   struct lwip_sock *sock;
00761   void             *buf = NULL;
00762   struct pbuf      *p;
00763   u16_t            buflen, copylen;
00764   int              off = 0;
00765   u8_t             done = 0;
00766   err_t            err;
00767 
00768   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d, %p, %"SZT_F", 0x%x, ..)\n", s, mem, len, flags));
00769   sock = get_socket(s);
00770   if (!sock) {
00771     return -1;
00772   }
00773 
00774   do {
00775     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: top while sock->lastdata=%p\n", sock->lastdata));
00776     /* Check if there is data left from the last recv operation. */
00777     if (sock->lastdata) {
00778       buf = sock->lastdata;
00779     } else {
00780       /* If this is non-blocking call, then check first */
00781       if (((flags & MSG_DONTWAIT) || netconn_is_nonblocking(sock->conn)) &&
00782           (sock->rcvevent <= 0)) {
00783         if (off > 0) {
00784           /* already received data, return that */
00785           sock_set_errno(sock, 0);
00786           return off;
00787         }
00788         LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): returning EWOULDBLOCK\n", s));
00789         sock_set_errno(sock, EWOULDBLOCK);
00790         return -1;
00791       }
00792 
00793       /* No data was left from the previous operation, so we try to get
00794          some from the network. */
00795       if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) {
00796         err = netconn_recv_tcp_pbuf(sock->conn, (struct pbuf **)&buf);
00797       } else {
00798         err = netconn_recv(sock->conn, (struct netbuf **)&buf);
00799       }
00800       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: netconn_recv err=%d, netbuf=%p\n",
00801         err, buf));
00802 
00803       if (err != ERR_OK) {
00804         if (off > 0) {
00805           if (err == ERR_CLSD) {
00806             /* closed but already received data, ensure select gets the FIN, too */
00807             event_callback(sock->conn, NETCONN_EVT_RCVPLUS, 0);
00808           }
00809           /* already received data, return that */
00810           sock_set_errno(sock, 0);
00811           return off;
00812         }
00813         /* We should really do some error checking here. */
00814         LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): buf == NULL, error is \"%s\"!\n",
00815           s, lwip_strerr(err)));
00816         sock_set_errno(sock, err_to_errno(err));
00817         if (err == ERR_CLSD) {
00818           return 0;
00819         } else {
00820           return -1;
00821         }
00822       }
00823       LWIP_ASSERT("buf != NULL", buf != NULL);
00824       sock->lastdata = buf;
00825     }
00826 
00827     if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) {
00828       p = (struct pbuf *)buf;
00829     } else {
00830       p = ((struct netbuf *)buf)->p;
00831     }
00832     buflen = p->tot_len;
00833     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: buflen=%"U16_F" len=%"SZT_F" off=%d sock->lastoffset=%"U16_F"\n",
00834       buflen, len, off, sock->lastoffset));
00835 
00836     buflen -= sock->lastoffset;
00837 
00838     if (len > buflen) {
00839       copylen = buflen;
00840     } else {
00841       copylen = (u16_t)len;
00842     }
00843 
00844     /* copy the contents of the received buffer into
00845     the supplied memory pointer mem */
00846     pbuf_copy_partial(p, (u8_t*)mem + off, copylen, sock->lastoffset);
00847 
00848     off += copylen;
00849 
00850     if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) {
00851       LWIP_ASSERT("invalid copylen, len would underflow", len >= copylen);
00852       len -= copylen;
00853       if ((len <= 0) ||
00854           (p->flags & PBUF_FLAG_PUSH) ||
00855           (sock->rcvevent <= 0) ||
00856           ((flags & MSG_PEEK) != 0)) {
00857         done = 1;
00858       }
00859     } else {
00860       done = 1;
00861     }
00862 
00863     /* Check to see from where the data was.*/
00864     if (done) {
00865 #if !SOCKETS_DEBUG
00866       if (from && fromlen)
00867 #endif /* !SOCKETS_DEBUG */
00868       {
00869         u16_t port;
00870         ip_addr_t tmpaddr;
00871         ip_addr_t *fromaddr;
00872         union sockaddr_aligned saddr;
00873         LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): addr=", s));
00874         if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) {
00875           fromaddr = &tmpaddr;
00876           netconn_getaddr(sock->conn, fromaddr, &port, 0);
00877         } else {
00878           port = netbuf_fromport((struct netbuf *)buf);
00879           fromaddr = netbuf_fromaddr((struct netbuf *)buf);
00880         }
00881         IPADDR_PORT_TO_SOCKADDR(&saddr, fromaddr, port);
00882         ip_addr_debug_print(SOCKETS_DEBUG, fromaddr);
00883         LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F" len=%d\n", port, off));
00884 #if SOCKETS_DEBUG
00885         if (from && fromlen)
00886 #endif /* SOCKETS_DEBUG */
00887         {
00888           if (*fromlen > saddr.sa.sa_len) {
00889             *fromlen = saddr.sa.sa_len;
00890           }
00891           MEMCPY(from, &saddr, *fromlen);
00892         }
00893       }
00894     }
00895 
00896     /* If we don't peek the incoming message... */
00897     if ((flags & MSG_PEEK) == 0) {
00898       /* If this is a TCP socket, check if there is data left in the
00899          buffer. If so, it should be saved in the sock structure for next
00900          time around. */
00901       if ((NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) && (buflen - copylen > 0)) {
00902         sock->lastdata = buf;
00903         sock->lastoffset += copylen;
00904         LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: lastdata now netbuf=%p\n", buf));
00905       } else {
00906         sock->lastdata = NULL;
00907         sock->lastoffset = 0;
00908         LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: deleting netbuf=%p\n", buf));
00909         if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) {
00910           pbuf_free((struct pbuf *)buf);
00911         } else {
00912           netbuf_delete((struct netbuf *)buf);
00913         }
00914         buf = NULL;
00915       }
00916     }
00917   } while (!done);
00918 
00919   sock_set_errno(sock, 0);
00920   return off;
00921 }
00922 
00923 int
00924 lwip_read(int s, void *mem, size_t len)
00925 {
00926   return lwip_recvfrom(s, mem, len, 0, NULL, NULL);
00927 }
00928 
00929 int
00930 lwip_recv(int s, void *mem, size_t len, int flags)
00931 {
00932   return lwip_recvfrom(s, mem, len, flags, NULL, NULL);
00933 }
00934 
00935 int
00936 lwip_send(int s, const void *data, size_t size, int flags)
00937 {
00938   struct lwip_sock *sock;
00939   err_t err;
00940   u8_t write_flags;
00941   size_t written;
00942 
00943   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_send(%d, data=%p, size=%"SZT_F", flags=0x%x)\n",
00944                               s, data, size, flags));
00945 
00946   sock = get_socket(s);
00947   if (!sock) {
00948     return -1;
00949   }
00950 
00951   if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_TCP) {
00952 #if (LWIP_UDP || LWIP_RAW)
00953     return lwip_sendto(s, data, size, flags, NULL, 0);
00954 #else /* (LWIP_UDP || LWIP_RAW) */
00955     sock_set_errno(sock, err_to_errno(ERR_ARG));
00956     return -1;
00957 #endif /* (LWIP_UDP || LWIP_RAW) */
00958   }
00959 
00960   write_flags = NETCONN_COPY |
00961     ((flags & MSG_MORE)     ? NETCONN_MORE      : 0) |
00962     ((flags & MSG_DONTWAIT) ? NETCONN_DONTBLOCK : 0);
00963   written = 0;
00964   err = netconn_write_partly(sock->conn, data, size, write_flags, &written);
00965 
00966   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_send(%d) err=%d written=%"SZT_F"\n", s, err, written));
00967   sock_set_errno(sock, err_to_errno(err));
00968   return (err == ERR_OK ? (int)written : -1);
00969 }
00970 
00971 int
00972 lwip_sendmsg(int s, const struct msghdr *msg, int flags)
00973 {
00974   struct lwip_sock *sock;
00975   struct netbuf *chain_buf;
00976   u16_t remote_port;
00977   int i;
00978 #if LWIP_TCP
00979   u8_t write_flags;
00980   size_t written;
00981 #endif
00982   int size = 0;
00983   err_t err = ERR_OK;
00984 
00985   sock = get_socket(s);
00986   if (!sock) {
00987     return -1;
00988   }
00989 
00990   LWIP_ERROR("lwip_sendmsg: invalid msghdr", msg != NULL,
00991              sock_set_errno(sock, err_to_errno(ERR_ARG)); return -1;);
00992 
00993   LWIP_UNUSED_ARG(msg->msg_control);
00994   LWIP_UNUSED_ARG(msg->msg_controllen);
00995   LWIP_UNUSED_ARG(msg->msg_flags);
00996   LWIP_ERROR("lwip_sendmsg: invalid msghdr iov", (msg->msg_iov != NULL && msg->msg_iovlen != 0),
00997              sock_set_errno(sock, err_to_errno(ERR_ARG)); return -1;);
00998 
00999   if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) {
01000 #if LWIP_TCP
01001     write_flags = NETCONN_COPY |
01002     ((flags & MSG_MORE)     ? NETCONN_MORE      : 0) |
01003     ((flags & MSG_DONTWAIT) ? NETCONN_DONTBLOCK : 0);
01004 
01005     for (i = 0; i < msg->msg_iovlen; i++) {
01006       written = 0;
01007       err = netconn_write_partly(sock->conn, msg->msg_iov[i].iov_base, msg->msg_iov[i].iov_len, write_flags, &written);
01008       if (err == ERR_OK) {
01009         size += written;
01010         /* check that the entire IO vector was accepected, if not return a partial write */
01011         if (written != msg->msg_iov[i].iov_len)
01012           break;
01013       }
01014       /* none of this IO vector was accepted, but previous was, return partial write and conceal ERR_WOULDBLOCK */
01015       else if (err == ERR_WOULDBLOCK && size > 0) {
01016         err = ERR_OK;
01017         /* let ERR_WOULDBLOCK persist on the netconn since we are returning ERR_OK */
01018         break;
01019       } else {
01020         size = -1;
01021         break;
01022       }
01023     }
01024     sock_set_errno(sock, err_to_errno(err));
01025     return size;
01026 #else /* LWIP_TCP */
01027     sock_set_errno(sock, err_to_errno(ERR_ARG));
01028     return -1;
01029 #endif /* LWIP_TCP */
01030   }
01031   /* else, UDP and RAW NETCONNs */
01032 #if LWIP_UDP || LWIP_RAW
01033 
01034   LWIP_UNUSED_ARG(flags);
01035   LWIP_ERROR("lwip_sendmsg: invalid msghdr name", (((msg->msg_name == NULL) && (msg->msg_namelen == 0)) ||
01036              IS_SOCK_ADDR_LEN_VALID(msg->msg_namelen)) ,
01037              sock_set_errno(sock, err_to_errno(ERR_ARG)); return -1;);
01038 
01039   /* initialize chain buffer with destination */
01040   chain_buf = netbuf_new();
01041   if (!chain_buf) {
01042     sock_set_errno(sock, err_to_errno(ERR_MEM));
01043     return -1;
01044   }
01045   if (msg->msg_name) {
01046     SOCKADDR_TO_IPADDR_PORT((const struct sockaddr *)msg->msg_name, &chain_buf->addr, remote_port);
01047     netbuf_fromport(chain_buf) = remote_port;
01048   }
01049 #if LWIP_NETIF_TX_SINGLE_PBUF
01050   for (i = 0; i < msg->msg_iovlen; i++) {
01051     size += msg->msg_iov[i].iov_len;
01052   }
01053   /* Allocate a new netbuf and copy the data into it. */
01054   if (netbuf_alloc(chain_buf, (u16_t)size) == NULL) {
01055     err = ERR_MEM;
01056   }
01057   else {
01058     /* flatten the IO vectors */
01059     size_t offset = 0;
01060     for (i = 0; i < msg->msg_iovlen; i++) {
01061       MEMCPY(&((u8_t*)chain_buf->p->payload)[offset], msg->msg_iov[i].iov_base, msg->msg_iov[i].iov_len);
01062       offset += msg->msg_iov[i].iov_len;
01063     }
01064 #if LWIP_CHECKSUM_ON_COPY
01065     {
01066       /* This can be improved by using LWIP_CHKSUM_COPY() and aggregating the checksum for each IO vector */
01067       u16_t chksum = ~inet_chksum_pbuf(chain_buf->p);
01068       netbuf_set_chksum(chain_buf, chksum);
01069     }
01070 #endif /* LWIP_CHECKSUM_ON_COPY */
01071     err = ERR_OK;
01072   }
01073 #else /* LWIP_NETIF_TX_SINGLE_PBUF */
01074   /* create a chained netbuf from the IO vectors. NOTE: we assemble a pbuf chain
01075      manually to avoid having to allocate, chain, and delete a netbuf for each iov */
01076   for (i = 0; i < msg->msg_iovlen; i++) {
01077     struct pbuf *p = pbuf_alloc(PBUF_TRANSPORT, 0, PBUF_REF);
01078     if (p == NULL) {
01079       err = ERR_MEM; /* let netbuf_delete() cleanup chain_buf */
01080       break;
01081     }
01082     p->payload = msg->msg_iov[i].iov_base;
01083     LWIP_ASSERT("iov_len < u16_t", msg->msg_iov[i].iov_len <= 0xFFFF);
01084     p->len = p->tot_len = (u16_t)msg->msg_iov[i].iov_len;
01085     /* netbuf empty, add new pbuf */
01086     if (chain_buf->p == NULL) {
01087       chain_buf->p = chain_buf->ptr = p;
01088     /* add pbuf to existing pbuf chain */
01089     } else {
01090       pbuf_cat(chain_buf->p, p);
01091     }
01092   }    
01093   /* save size of total chain */
01094   if (err == ERR_OK) {
01095     size = netbuf_len(chain_buf);
01096   }
01097 #endif /* LWIP_NETIF_TX_SINGLE_PBUF */
01098 
01099   if (err == ERR_OK) {
01100     /* send the data */
01101     err = netconn_send(sock->conn, chain_buf);
01102   }
01103 
01104   /* deallocated the buffer */
01105   netbuf_delete(chain_buf);
01106 
01107   sock_set_errno(sock, err_to_errno(err));
01108   return (err == ERR_OK ? size : -1);
01109 #else /* LWIP_UDP || LWIP_RAW */
01110   sock_set_errno(sock, err_to_errno(ERR_ARG));
01111   return -1;
01112 #endif /* LWIP_UDP || LWIP_RAW */
01113 }
01114 
01115 int
01116 lwip_sendto(int s, const void *data, size_t size, int flags,
01117        const struct sockaddr *to, socklen_t tolen)
01118 {
01119   struct lwip_sock *sock;
01120   err_t err;
01121   u16_t short_size;
01122   u16_t remote_port;
01123   struct netbuf buf;
01124 
01125   sock = get_socket(s);
01126   if (!sock) {
01127     return -1;
01128   }
01129 
01130   if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) {
01131 #if LWIP_TCP
01132     return lwip_send(s, data, size, flags);
01133 #else /* LWIP_TCP */
01134     LWIP_UNUSED_ARG(flags);
01135     sock_set_errno(sock, err_to_errno(ERR_ARG));
01136     return -1;
01137 #endif /* LWIP_TCP */
01138   }
01139 
01140   if ((to != NULL) && !SOCK_ADDR_TYPE_MATCH(to, sock)) {
01141     /* sockaddr does not match socket type (IPv4/IPv6) */
01142     sock_set_errno(sock, err_to_errno(ERR_VAL));
01143     return -1;
01144   }
01145 
01146   /* @todo: split into multiple sendto's? */
01147   LWIP_ASSERT("lwip_sendto: size must fit in u16_t", size <= 0xffff);
01148   short_size = (u16_t)size;
01149   LWIP_ERROR("lwip_sendto: invalid address", (((to == NULL) && (tolen == 0)) ||
01150              (IS_SOCK_ADDR_LEN_VALID(tolen) &&
01151              IS_SOCK_ADDR_TYPE_VALID(to) && IS_SOCK_ADDR_ALIGNED(to))),
01152              sock_set_errno(sock, err_to_errno(ERR_ARG)); return -1;);
01153   LWIP_UNUSED_ARG(tolen);
01154 
01155   /* initialize a buffer */
01156   buf.p = buf.ptr = NULL;
01157 #if LWIP_CHECKSUM_ON_COPY
01158   buf.flags = 0;
01159 #endif /* LWIP_CHECKSUM_ON_COPY */
01160   if (to) {
01161     SOCKADDR_TO_IPADDR_PORT(to, &buf.addr, remote_port);
01162   } else {
01163     remote_port = 0;
01164     ip_addr_set_any(NETCONNTYPE_ISIPV6(netconn_type(sock->conn)), &buf.addr);
01165   }
01166   netbuf_fromport(&buf) = remote_port;
01167 
01168 
01169   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_sendto(%d, data=%p, short_size=%"U16_F", flags=0x%x to=",
01170               s, data, short_size, flags));
01171   ip_addr_debug_print(SOCKETS_DEBUG, &buf.addr);
01172   LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F"\n", remote_port));
01173 
01174   /* make the buffer point to the data that should be sent */
01175 #if LWIP_NETIF_TX_SINGLE_PBUF
01176   /* Allocate a new netbuf and copy the data into it. */
01177   if (netbuf_alloc(&buf, short_size) == NULL) {
01178     err = ERR_MEM;
01179   } else {
01180 #if LWIP_CHECKSUM_ON_COPY
01181     if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_RAW) {
01182       u16_t chksum = LWIP_CHKSUM_COPY(buf.p->payload, data, short_size);
01183       netbuf_set_chksum(&buf, chksum);
01184     } else
01185 #endif /* LWIP_CHECKSUM_ON_COPY */
01186     {
01187       MEMCPY(buf.p->payload, data, short_size);
01188     }
01189     err = ERR_OK;
01190   }
01191 #else /* LWIP_NETIF_TX_SINGLE_PBUF */
01192   err = netbuf_ref(&buf, data, short_size);
01193 #endif /* LWIP_NETIF_TX_SINGLE_PBUF */
01194   if (err == ERR_OK) {
01195     /* send the data */
01196     err = netconn_send(sock->conn, &buf);
01197   }
01198 
01199   /* deallocated the buffer */
01200   netbuf_free(&buf);
01201 
01202   sock_set_errno(sock, err_to_errno(err));
01203   return (err == ERR_OK ? short_size : -1);
01204 }
01205 
01206 int
01207 lwip_socket(int domain, int type, int protocol)
01208 {
01209   struct netconn *conn;
01210   int i;
01211 
01212 #if !LWIP_IPV6
01213   LWIP_UNUSED_ARG(domain); /* @todo: check this */
01214 #endif /* LWIP_IPV6 */
01215 
01216   /* create a netconn */
01217   switch (type) {
01218   case SOCK_RAW:
01219     conn = netconn_new_with_proto_and_callback(DOMAIN_TO_NETCONN_TYPE(domain, NETCONN_RAW),
01220                                                (u8_t)protocol, event_callback);
01221     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_RAW, %d) = ",
01222                                  domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol));
01223     break;
01224   case SOCK_DGRAM:
01225     conn = netconn_new_with_callback(DOMAIN_TO_NETCONN_TYPE(domain,
01226                  ((protocol == IPPROTO_UDPLITE) ? NETCONN_UDPLITE : NETCONN_UDP)) ,
01227                  event_callback);
01228     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_DGRAM, %d) = ",
01229                                  domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol));
01230     break;
01231   case SOCK_STREAM:
01232     conn = netconn_new_with_callback(DOMAIN_TO_NETCONN_TYPE(domain, NETCONN_TCP), event_callback);
01233     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_STREAM, %d) = ",
01234                                  domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol));
01235     break;
01236   default:
01237     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%d, %d/UNKNOWN, %d) = -1\n",
01238                                  domain, type, protocol));
01239     set_errno(EINVAL);
01240     return -1;
01241   }
01242 
01243   if (!conn) {
01244     LWIP_DEBUGF(SOCKETS_DEBUG, ("-1 / ENOBUFS (could not create netconn)\n"));
01245     set_errno(ENOBUFS);
01246     return -1;
01247   }
01248 
01249   i = alloc_socket(conn, 0);
01250 
01251   if (i == -1) {
01252     netconn_delete(conn);
01253     set_errno(ENFILE);
01254     return -1;
01255   }
01256   conn->socket = i;
01257   LWIP_DEBUGF(SOCKETS_DEBUG, ("%d\n", i));
01258   set_errno(0);
01259   return i;
01260 }
01261 
01262 int
01263 lwip_write(int s, const void *data, size_t size)
01264 {
01265   return lwip_send(s, data, size, 0);
01266 }
01267 
01268 int
01269 lwip_writev(int s, const struct iovec *iov, int iovcnt)
01270 {
01271   struct msghdr msg;
01272 
01273   msg.msg_name = NULL;
01274   msg.msg_namelen = 0;
01275   /* Hack: we have to cast via number to cast from 'const' pointer to non-const.
01276      Blame the opengroup standard for this inconsistency. */
01277   msg.msg_iov = (struct iovec *)(size_t)iov;
01278   msg.msg_iovlen = iovcnt;
01279   msg.msg_control = NULL;
01280   msg.msg_controllen = 0;
01281   msg.msg_flags = 0;
01282   return lwip_sendmsg(s, &msg, 0);
01283 }
01284 
01285 /**
01286  * Go through the readset and writeset lists and see which socket of the sockets
01287  * set in the sets has events. On return, readset, writeset and exceptset have
01288  * the sockets enabled that had events.
01289  *
01290  * @param maxfdp1 the highest socket index in the sets
01291  * @param readset_in:    set of sockets to check for read events
01292  * @param writeset_in:   set of sockets to check for write events
01293  * @param exceptset_in:  set of sockets to check for error events
01294  * @param readset_out:   set of sockets that had read events
01295  * @param writeset_out:  set of sockets that had write events
01296  * @param exceptset_out: set os sockets that had error events
01297  * @return number of sockets that had events (read/write/exception) (>= 0)
01298  */
01299 static int
01300 lwip_selscan(int maxfdp1, fd_set *readset_in, fd_set *writeset_in, fd_set *exceptset_in,
01301              fd_set *readset_out, fd_set *writeset_out, fd_set *exceptset_out)
01302 {
01303   int i, nready = 0;
01304   fd_set lreadset, lwriteset, lexceptset;
01305   struct lwip_sock *sock;
01306   SYS_ARCH_DECL_PROTECT(lev);
01307 
01308   FD_ZERO(&lreadset);
01309   FD_ZERO(&lwriteset);
01310   FD_ZERO(&lexceptset);
01311 
01312   /* Go through each socket in each list to count number of sockets which
01313      currently match */
01314   for (i = LWIP_SOCKET_OFFSET; i < maxfdp1; i++) {
01315     /* if this FD is not in the set, continue */
01316     if (!(readset_in && FD_ISSET(i, readset_in)) &&
01317         !(writeset_in && FD_ISSET(i, writeset_in)) &&
01318         !(exceptset_in && FD_ISSET(i, exceptset_in))) {
01319       continue;
01320     }
01321     /* First get the socket's status (protected)... */
01322     SYS_ARCH_PROTECT(lev);
01323     sock = tryget_socket(i);
01324     if (sock != NULL) {
01325       void* lastdata = sock->lastdata;
01326       s16_t rcvevent = sock->rcvevent;
01327       u16_t sendevent = sock->sendevent;
01328       u16_t errevent = sock->errevent;
01329       SYS_ARCH_UNPROTECT(lev);
01330 
01331       /* ... then examine it: */
01332       /* See if netconn of this socket is ready for read */
01333       if (readset_in && FD_ISSET(i, readset_in) && ((lastdata != NULL) || (rcvevent > 0))) {
01334         FD_SET(i, &lreadset);
01335         LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_selscan: fd=%d ready for reading\n", i));
01336         nready++;
01337       }
01338       /* See if netconn of this socket is ready for write */
01339       if (writeset_in && FD_ISSET(i, writeset_in) && (sendevent != 0)) {
01340         FD_SET(i, &lwriteset);
01341         LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_selscan: fd=%d ready for writing\n", i));
01342         nready++;
01343       }
01344       /* See if netconn of this socket had an error */
01345       if (exceptset_in && FD_ISSET(i, exceptset_in) && (errevent != 0)) {
01346         FD_SET(i, &lexceptset);
01347         LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_selscan: fd=%d ready for exception\n", i));
01348         nready++;
01349       }
01350     } else {
01351       SYS_ARCH_UNPROTECT(lev);
01352       /* continue on to next FD in list */
01353     }
01354   }
01355   /* copy local sets to the ones provided as arguments */
01356   *readset_out = lreadset;
01357   *writeset_out = lwriteset;
01358   *exceptset_out = lexceptset;
01359 
01360   LWIP_ASSERT("nready >= 0", nready >= 0);
01361   return nready;
01362 }
01363 
01364 int
01365 lwip_select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset,
01366             struct timeval *timeout)
01367 {
01368   u32_t waitres = 0;
01369   int nready;
01370   fd_set lreadset, lwriteset, lexceptset;
01371   u32_t msectimeout;
01372   struct lwip_select_cb select_cb;
01373   int i;
01374   int maxfdp2;
01375 #if LWIP_NETCONN_SEM_PER_THREAD
01376   int waited = 0;
01377 #endif
01378   SYS_ARCH_DECL_PROTECT(lev);
01379 
01380   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select(%d, %p, %p, %p, tvsec=%"S32_F" tvusec=%"S32_F")\n",
01381                   maxfdp1, (void *)readset, (void *) writeset, (void *) exceptset,
01382                   timeout ? (s32_t)timeout->tv_sec : (s32_t)-1,
01383                   timeout ? (s32_t)timeout->tv_usec : (s32_t)-1));
01384 
01385   /* Go through each socket in each list to count number of sockets which
01386      currently match */
01387   nready = lwip_selscan(maxfdp1, readset, writeset, exceptset, &lreadset, &lwriteset, &lexceptset);
01388 
01389   /* If we don't have any current events, then suspend if we are supposed to */
01390   if (!nready) {
01391     if (timeout && timeout->tv_sec == 0 && timeout->tv_usec == 0) {
01392       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select: no timeout, returning 0\n"));
01393       /* This is OK as the local fdsets are empty and nready is zero,
01394          or we would have returned earlier. */
01395       goto return_copy_fdsets;
01396     }
01397 
01398     /* None ready: add our semaphore to list:
01399        We don't actually need any dynamic memory. Our entry on the
01400        list is only valid while we are in this function, so it's ok
01401        to use local variables. */
01402 
01403     select_cb.next = NULL;
01404     select_cb.prev = NULL;
01405     select_cb.readset = readset;
01406     select_cb.writeset = writeset;
01407     select_cb.exceptset = exceptset;
01408     select_cb.sem_signalled = 0;
01409 #if LWIP_NETCONN_SEM_PER_THREAD
01410     select_cb.sem = LWIP_NETCONN_THREAD_SEM_GET();
01411 #else /* LWIP_NETCONN_SEM_PER_THREAD */
01412     if (sys_sem_new(&select_cb.sem, 0) != ERR_OK) {
01413       /* failed to create semaphore */
01414       set_errno(ENOMEM);
01415       return -1;
01416     }
01417 #endif /* LWIP_NETCONN_SEM_PER_THREAD */
01418 
01419     /* Protect the select_cb_list */
01420     SYS_ARCH_PROTECT(lev);
01421 
01422     /* Put this select_cb on top of list */
01423     select_cb.next = select_cb_list;
01424     if (select_cb_list != NULL) {
01425       select_cb_list->prev = &select_cb;
01426     }
01427     select_cb_list = &select_cb;
01428     /* Increasing this counter tells event_callback that the list has changed. */
01429     select_cb_ctr++;
01430 
01431     /* Now we can safely unprotect */
01432     SYS_ARCH_UNPROTECT(lev);
01433 
01434     /* Increase select_waiting for each socket we are interested in */
01435     maxfdp2 = maxfdp1;
01436     for (i = LWIP_SOCKET_OFFSET; i < maxfdp1; i++) {
01437       if ((readset && FD_ISSET(i, readset)) ||
01438           (writeset && FD_ISSET(i, writeset)) ||
01439           (exceptset && FD_ISSET(i, exceptset))) {
01440         struct lwip_sock *sock;
01441         SYS_ARCH_PROTECT(lev);
01442         sock = tryget_socket(i);
01443         if (sock != NULL) {
01444           sock->select_waiting++;
01445           LWIP_ASSERT("sock->select_waiting > 0", sock->select_waiting > 0);
01446         } else {
01447           /* Not a valid socket */
01448           nready = -1;
01449           maxfdp2 = i;
01450           SYS_ARCH_UNPROTECT(lev);
01451           break;
01452         }
01453         SYS_ARCH_UNPROTECT(lev);
01454       }
01455     }
01456 
01457     if (nready >= 0) {
01458       /* Call lwip_selscan again: there could have been events between
01459          the last scan (without us on the list) and putting us on the list! */
01460       nready = lwip_selscan(maxfdp1, readset, writeset, exceptset, &lreadset, &lwriteset, &lexceptset);
01461       if (!nready) {
01462         /* Still none ready, just wait to be woken */
01463         if (timeout == 0) {
01464           /* Wait forever */
01465           msectimeout = 0;
01466         } else {
01467           msectimeout =  ((timeout->tv_sec * 1000) + ((timeout->tv_usec + 500)/1000));
01468           if (msectimeout == 0) {
01469             /* Wait 1ms at least (0 means wait forever) */
01470             msectimeout = 1;
01471           }
01472         }
01473 
01474         waitres = sys_arch_sem_wait(SELECT_SEM_PTR(select_cb.sem), msectimeout);
01475 #if LWIP_NETCONN_SEM_PER_THREAD
01476         waited = 1;
01477 #endif
01478       }
01479     }
01480 
01481     /* Decrease select_waiting for each socket we are interested in */
01482     for (i = LWIP_SOCKET_OFFSET; i < maxfdp2; i++) {
01483       if ((readset && FD_ISSET(i, readset)) ||
01484           (writeset && FD_ISSET(i, writeset)) ||
01485           (exceptset && FD_ISSET(i, exceptset))) {
01486         struct lwip_sock *sock;
01487         SYS_ARCH_PROTECT(lev);
01488         sock = tryget_socket(i);
01489         if (sock != NULL) {
01490           /* @todo: what if this is a new socket (reallocated?) in this case,
01491              select_waiting-- would be wrong (a global 'sockalloc' counter,
01492              stored per socket could help) */
01493           LWIP_ASSERT("sock->select_waiting > 0", sock->select_waiting > 0);
01494           if (sock->select_waiting > 0) {
01495             sock->select_waiting--;
01496           }
01497         } else {
01498           /* Not a valid socket */
01499           nready = -1;
01500         }
01501         SYS_ARCH_UNPROTECT(lev);
01502       }
01503     }
01504     /* Take us off the list */
01505     SYS_ARCH_PROTECT(lev);
01506     if (select_cb.next != NULL) {
01507       select_cb.next->prev = select_cb.prev;
01508     }
01509     if (select_cb_list == &select_cb) {
01510       LWIP_ASSERT("select_cb.prev == NULL", select_cb.prev == NULL);
01511       select_cb_list = select_cb.next;
01512     } else {
01513       LWIP_ASSERT("select_cb.prev != NULL", select_cb.prev != NULL);
01514       select_cb.prev->next = select_cb.next;
01515     }
01516     /* Increasing this counter tells event_callback that the list has changed. */
01517     select_cb_ctr++;
01518     SYS_ARCH_UNPROTECT(lev);
01519 
01520 #if LWIP_NETCONN_SEM_PER_THREAD
01521     if (select_cb.sem_signalled && (!waited || (waitres == SYS_ARCH_TIMEOUT))) {
01522       /* don't leave the thread-local semaphore signalled */
01523       sys_arch_sem_wait(select_cb.sem, 1);
01524     }
01525 #else /* LWIP_NETCONN_SEM_PER_THREAD */
01526     sys_sem_free(&select_cb.sem);
01527 #endif /* LWIP_NETCONN_SEM_PER_THREAD */
01528 
01529     if (nready < 0) {
01530       /* This happens when a socket got closed while waiting */
01531       set_errno(EBADF);
01532       return -1;
01533     }
01534 
01535     if (waitres == SYS_ARCH_TIMEOUT) {
01536       /* Timeout */
01537       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select: timeout expired\n"));
01538       /* This is OK as the local fdsets are empty and nready is zero,
01539          or we would have returned earlier. */
01540       goto return_copy_fdsets;
01541     }
01542 
01543     /* See what's set */
01544     nready = lwip_selscan(maxfdp1, readset, writeset, exceptset, &lreadset, &lwriteset, &lexceptset);
01545   }
01546 
01547   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select: nready=%d\n", nready));
01548 return_copy_fdsets:
01549   set_errno(0);
01550   if (readset) {
01551     *readset = lreadset;
01552   }
01553   if (writeset) {
01554     *writeset = lwriteset;
01555   }
01556   if (exceptset) {
01557     *exceptset = lexceptset;
01558   }
01559   return nready;
01560 }
01561 
01562 /**
01563  * Callback registered in the netconn layer for each socket-netconn.
01564  * Processes recvevent (data available) and wakes up tasks waiting for select.
01565  */
01566 static void
01567 event_callback(struct netconn *conn, enum netconn_evt evt, u16_t len)
01568 {
01569   int s;
01570   struct lwip_sock *sock;
01571   struct lwip_select_cb *scb;
01572   int last_select_cb_ctr;
01573   SYS_ARCH_DECL_PROTECT(lev);
01574 
01575   LWIP_UNUSED_ARG(len);
01576 
01577   /* Get socket */
01578   if (conn) {
01579     s = conn->socket;
01580     if (s < 0) {
01581       /* Data comes in right away after an accept, even though
01582        * the server task might not have created a new socket yet.
01583        * Just count down (or up) if that's the case and we
01584        * will use the data later. Note that only receive events
01585        * can happen before the new socket is set up. */
01586       SYS_ARCH_PROTECT(lev);
01587       if (conn->socket < 0) {
01588         if (evt == NETCONN_EVT_RCVPLUS) {
01589           conn->socket--;
01590         }
01591         SYS_ARCH_UNPROTECT(lev);
01592         return;
01593       }
01594       s = conn->socket;
01595       SYS_ARCH_UNPROTECT(lev);
01596     }
01597 
01598     sock = get_socket(s);
01599     if (!sock) {
01600       return;
01601     }
01602   } else {
01603     return;
01604   }
01605 
01606   SYS_ARCH_PROTECT(lev);
01607   /* Set event as required */
01608   switch (evt) {
01609     case NETCONN_EVT_RCVPLUS:
01610       sock->rcvevent++;
01611       break;
01612     case NETCONN_EVT_RCVMINUS:
01613       sock->rcvevent--;
01614       break;
01615     case NETCONN_EVT_SENDPLUS:
01616       sock->sendevent = 1;
01617       break;
01618     case NETCONN_EVT_SENDMINUS:
01619       sock->sendevent = 0;
01620       break;
01621     case NETCONN_EVT_ERROR:
01622       sock->errevent = 1;
01623       break;
01624     default:
01625       LWIP_ASSERT("unknown event", 0);
01626       break;
01627   }
01628 
01629   if (sock->select_waiting == 0) {
01630     /* noone is waiting for this socket, no need to check select_cb_list */
01631     SYS_ARCH_UNPROTECT(lev);
01632     return;
01633   }
01634 
01635   /* Now decide if anyone is waiting for this socket */
01636   /* NOTE: This code goes through the select_cb_list list multiple times
01637      ONLY IF a select was actually waiting. We go through the list the number
01638      of waiting select calls + 1. This list is expected to be small. */
01639 
01640   /* At this point, SYS_ARCH is still protected! */
01641 again:
01642   for (scb = select_cb_list; scb != NULL; scb = scb->next) {
01643     /* remember the state of select_cb_list to detect changes */
01644     last_select_cb_ctr = select_cb_ctr;
01645     if (scb->sem_signalled == 0) {
01646       /* semaphore not signalled yet */
01647       int do_signal = 0;
01648       /* Test this select call for our socket */
01649       if (sock->rcvevent > 0) {
01650         if (scb->readset && FD_ISSET(s, scb->readset)) {
01651           do_signal = 1;
01652         }
01653       }
01654       if (sock->sendevent != 0) {
01655         if (!do_signal && scb->writeset && FD_ISSET(s, scb->writeset)) {
01656           do_signal = 1;
01657         }
01658       }
01659       if (sock->errevent != 0) {
01660         if (!do_signal && scb->exceptset && FD_ISSET(s, scb->exceptset)) {
01661           do_signal = 1;
01662         }
01663       }
01664       if (do_signal) {
01665         scb->sem_signalled = 1;
01666         /* Don't call SYS_ARCH_UNPROTECT() before signaling the semaphore, as this might
01667            lead to the select thread taking itself off the list, invalidating the semaphore. */
01668         sys_sem_signal(SELECT_SEM_PTR(scb->sem));
01669       }
01670     }
01671     /* unlock interrupts with each step */
01672     SYS_ARCH_UNPROTECT(lev);
01673     /* this makes sure interrupt protection time is short */
01674     SYS_ARCH_PROTECT(lev);
01675     if (last_select_cb_ctr != select_cb_ctr) {
01676       /* someone has changed select_cb_list, restart at the beginning */
01677       goto again;
01678     }
01679   }
01680   SYS_ARCH_UNPROTECT(lev);
01681 }
01682 
01683 /**
01684  * Unimplemented: Close one end of a full-duplex connection.
01685  * Currently, the full connection is closed.
01686  */
01687 int
01688 lwip_shutdown(int s, int how)
01689 {
01690   struct lwip_sock *sock;
01691   err_t err;
01692   u8_t shut_rx = 0, shut_tx = 0;
01693 
01694   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_shutdown(%d, how=%d)\n", s, how));
01695 
01696   sock = get_socket(s);
01697   if (!sock) {
01698     return -1;
01699   }
01700 
01701   if (sock->conn != NULL) {
01702     if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_TCP) {
01703       sock_set_errno(sock, EOPNOTSUPP);
01704       return -1;
01705     }
01706   } else {
01707     sock_set_errno(sock, ENOTCONN);
01708     return -1;
01709   }
01710 
01711   if (how == SHUT_RD) {
01712     shut_rx = 1;
01713   } else if (how == SHUT_WR) {
01714     shut_tx = 1;
01715   } else if (how == SHUT_RDWR) {
01716     shut_rx = 1;
01717     shut_tx = 1;
01718   } else {
01719     sock_set_errno(sock, EINVAL);
01720     return -1;
01721   }
01722   err = netconn_shutdown(sock->conn, shut_rx, shut_tx);
01723 
01724   sock_set_errno(sock, err_to_errno(err));
01725   return (err == ERR_OK ? 0 : -1);
01726 }
01727 
01728 static int
01729 lwip_getaddrname(int s, struct sockaddr *name, socklen_t *namelen, u8_t local)
01730 {
01731   struct lwip_sock *sock;
01732   union sockaddr_aligned saddr;
01733   ip_addr_t naddr;
01734   u16_t port;
01735   err_t err;
01736 
01737   sock = get_socket(s);
01738   if (!sock) {
01739     return -1;
01740   }
01741 
01742   /* get the IP address and port */
01743   /* @todo: this does not work for IPv6, yet */
01744   err = netconn_getaddr(sock->conn, &naddr, &port, local);
01745   if (err != ERR_OK) {
01746     sock_set_errno(sock, err_to_errno(err));
01747     return -1;
01748   }
01749   IPADDR_PORT_TO_SOCKADDR(&saddr, &naddr, port);
01750 
01751   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getaddrname(%d, addr=", s));
01752   ip_addr_debug_print_val(SOCKETS_DEBUG, naddr);
01753   LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F")\n", port));
01754 
01755   if (*namelen > saddr.sa.sa_len) {
01756     *namelen = saddr.sa.sa_len;
01757   }
01758   MEMCPY(name, &saddr, *namelen);
01759 
01760   sock_set_errno(sock, 0);
01761   return 0;
01762 }
01763 
01764 int
01765 lwip_getpeername(int s, struct sockaddr *name, socklen_t *namelen)
01766 {
01767   return lwip_getaddrname(s, name, namelen, 0);
01768 }
01769 
01770 int
01771 lwip_getsockname(int s, struct sockaddr *name, socklen_t *namelen)
01772 {
01773   return lwip_getaddrname(s, name, namelen, 1);
01774 }
01775 
01776 int
01777 lwip_getsockopt(int s, int level, int optname, void *optval, socklen_t *optlen)
01778 {
01779   u8_t err;
01780   struct lwip_sock *sock = get_socket(s);
01781 #if !LWIP_TCPIP_CORE_LOCKING
01782   LWIP_SETGETSOCKOPT_DATA_VAR_DECLARE(data);
01783 #endif /* !LWIP_TCPIP_CORE_LOCKING */
01784 
01785   if (!sock) {
01786     return -1;
01787   }
01788 
01789   if ((NULL == optval) || (NULL == optlen)) {
01790     sock_set_errno(sock, EFAULT);
01791     return -1;
01792   }
01793 
01794 #if LWIP_TCPIP_CORE_LOCKING
01795   /* core-locking can just call the -impl function */
01796   LOCK_TCPIP_CORE();
01797   err = lwip_getsockopt_impl(s, level, optname, optval, optlen);
01798   UNLOCK_TCPIP_CORE();
01799 
01800 #else /* LWIP_TCPIP_CORE_LOCKING */
01801 
01802 #if LWIP_MPU_COMPATIBLE
01803   /* MPU_COMPATIBLE copies the optval data, so check for max size here */
01804   if (*optlen > LWIP_SETGETSOCKOPT_MAXOPTLEN) {
01805     sock_set_errno(sock, ENOBUFS);
01806     return -1;
01807   }
01808 #endif /* LWIP_MPU_COMPATIBLE */
01809 
01810   LWIP_SETGETSOCKOPT_DATA_VAR_ALLOC(data, sock);
01811   LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).s = s;
01812   LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).level = level;
01813   LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optname = optname;
01814   LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optlen = *optlen;
01815 #if !LWIP_MPU_COMPATIBLE
01816   LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optval.p = optval;
01817 #endif /* !LWIP_MPU_COMPATIBLE */
01818   LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).err = 0;
01819 #if LWIP_NETCONN_SEM_PER_THREAD
01820   LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).completed_sem = LWIP_NETCONN_THREAD_SEM_GET();
01821 #else
01822   LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).completed_sem = &sock->conn->op_completed;
01823 #endif
01824   err = tcpip_callback(lwip_getsockopt_callback, &LWIP_SETGETSOCKOPT_DATA_VAR_REF(data));
01825   if (err != ERR_OK) {
01826     LWIP_SETGETSOCKOPT_DATA_VAR_FREE(data);
01827     sock_set_errno(sock, err_to_errno(err));
01828     return -1;
01829   }
01830   sys_arch_sem_wait((sys_sem_t*)(LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).completed_sem), 0);
01831 
01832   /* write back optlen and optval */
01833   *optlen = LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optlen;
01834 #if LWIP_MPU_COMPATIBLE
01835   memcpy(optval, LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optval,
01836     LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optlen);
01837 #endif /* LWIP_MPU_COMPATIBLE */
01838 
01839   /* maybe lwip_getsockopt_internal has changed err */
01840   err = LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).err;
01841   LWIP_SETGETSOCKOPT_DATA_VAR_FREE(data);
01842 #endif /* LWIP_TCPIP_CORE_LOCKING */
01843 
01844   sock_set_errno(sock, err);
01845   return err ? -1 : 0;
01846 }
01847 
01848 #if !LWIP_TCPIP_CORE_LOCKING
01849 /** lwip_getsockopt_callback: only used without CORE_LOCKING
01850  * to get into the tcpip_thread
01851  */
01852 static void
01853 lwip_getsockopt_callback(void *arg)
01854 {
01855   struct lwip_setgetsockopt_data *data;
01856   LWIP_ASSERT("arg != NULL", arg != NULL);
01857   data = (struct lwip_setgetsockopt_data*)arg;
01858 
01859   data->err = lwip_getsockopt_impl(data->s, data->level, data->optname,
01860 #if LWIP_MPU_COMPATIBLE
01861     data->optval,
01862 #else /* LWIP_MPU_COMPATIBLE */
01863     data->optval.p,
01864 #endif /* LWIP_MPU_COMPATIBLE */
01865     &data->optlen);
01866 
01867   sys_sem_signal((sys_sem_t*)(data->completed_sem));
01868 }
01869 #endif  /* LWIP_TCPIP_CORE_LOCKING */
01870 
01871 /** lwip_getsockopt_impl: the actual implementation of getsockopt:
01872  * same argument as lwip_getsockopt, either called directly or through callback
01873  */
01874 static u8_t
01875 lwip_getsockopt_impl(int s, int level, int optname, void *optval, socklen_t *optlen)
01876 {
01877   u8_t err = 0;
01878   struct lwip_sock *sock = tryget_socket(s);
01879   if (!sock) {
01880     return EBADF;
01881   }
01882 
01883   switch (level) {
01884 
01885 /* Level: SOL_SOCKET */
01886   case SOL_SOCKET:
01887     switch (optname) {
01888 
01889 #if LWIP_TCP
01890     case SO_ACCEPTCONN:
01891       LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, *optlen, int);
01892       if (NETCONNTYPE_GROUP(sock->conn->type) != NETCONN_TCP) {
01893         return ENOPROTOOPT;
01894       }
01895       if ((sock->conn->pcb.tcp != NULL) && (sock->conn->pcb.tcp->state == LISTEN)) {
01896         *(int*)optval = 1;
01897       } else {
01898         *(int*)optval = 0;
01899       }
01900       break;
01901 #endif /* LWIP_TCP */
01902 
01903     /* The option flags */
01904     case SO_BROADCAST:
01905     case SO_KEEPALIVE:
01906 #if SO_REUSE
01907     case SO_REUSEADDR:
01908 #endif /* SO_REUSE */
01909       LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, *optlen, int);
01910       *(int*)optval = ip_get_option(sock->conn->pcb.ip, optname);
01911       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, optname=0x%x, ..) = %s\n",
01912                                   s, optname, (*(int*)optval?"on":"off")));
01913       break;
01914 
01915     case SO_TYPE:
01916       LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, *optlen, int);
01917       switch (NETCONNTYPE_GROUP(netconn_type(sock->conn))) {
01918       case NETCONN_RAW:
01919         *(int*)optval = SOCK_RAW;
01920         break;
01921       case NETCONN_TCP:
01922         *(int*)optval = SOCK_STREAM;
01923         break;
01924       case NETCONN_UDP:
01925         *(int*)optval = SOCK_DGRAM;
01926         break;
01927       default: /* unrecognized socket type */
01928         *(int*)optval = netconn_type(sock->conn);
01929         LWIP_DEBUGF(SOCKETS_DEBUG,
01930                     ("lwip_getsockopt(%d, SOL_SOCKET, SO_TYPE): unrecognized socket type %d\n",
01931                     s, *(int *)optval));
01932       }  /* switch (netconn_type(sock->conn)) */
01933       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, SO_TYPE) = %d\n",
01934                   s, *(int *)optval));
01935       break;
01936 
01937     case SO_ERROR:
01938       LWIP_SOCKOPT_CHECK_OPTLEN(*optlen, int);
01939       /* only overwrite ERR_OK or temporary errors */
01940       if (((sock->err == 0) || (sock->err == EINPROGRESS)) && (sock->conn != NULL)) {
01941         sock_set_errno(sock, err_to_errno(sock->conn->last_err));
01942       }
01943       *(int *)optval = (sock->err == 0xFF ? (int)-1 : (int)sock->err);
01944       sock->err = 0;
01945       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, SO_ERROR) = %d\n",
01946                   s, *(int *)optval));
01947       break;
01948 
01949 #if LWIP_SO_SNDTIMEO
01950     case SO_SNDTIMEO:
01951       LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, *optlen, LWIP_SO_SNDRCVTIMEO_OPTTYPE);
01952       LWIP_SO_SNDRCVTIMEO_SET(optval, netconn_get_sendtimeout(sock->conn));
01953       break;
01954 #endif /* LWIP_SO_SNDTIMEO */
01955 #if LWIP_SO_RCVTIMEO
01956     case SO_RCVTIMEO:
01957       LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, *optlen, LWIP_SO_SNDRCVTIMEO_OPTTYPE);
01958       LWIP_SO_SNDRCVTIMEO_SET(optval, netconn_get_recvtimeout(sock->conn));
01959       break;
01960 #endif /* LWIP_SO_RCVTIMEO */
01961 #if LWIP_SO_RCVBUF
01962     case SO_RCVBUF:
01963       LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, *optlen, int);
01964       *(int *)optval = netconn_get_recvbufsize(sock->conn);
01965       break;
01966 #endif /* LWIP_SO_RCVBUF */
01967 #if LWIP_SO_LINGER
01968     case SO_LINGER:
01969       {
01970         s16_t conn_linger;
01971         struct linger* linger = (struct linger*)optval;
01972         LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, *optlen, struct linger);
01973         conn_linger = sock->conn->linger;
01974         if (conn_linger >= 0) {
01975           linger->l_onoff = 1;
01976           linger->l_linger = (int)conn_linger;
01977         } else {
01978           linger->l_onoff = 0;
01979           linger->l_linger = 0;
01980         }
01981       }
01982       break;
01983 #endif /* LWIP_SO_LINGER */
01984 #if LWIP_UDP
01985     case SO_NO_CHECK:
01986       LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, *optlen, int, NETCONN_UDP);
01987 #if LWIP_UDPLITE
01988       if ((udp_flags(sock->conn->pcb.udp) & UDP_FLAGS_UDPLITE) != 0) {
01989         /* this flag is only available for UDP, not for UDP lite */
01990         return EAFNOSUPPORT;
01991       }
01992 #endif /* LWIP_UDPLITE */
01993       *(int*)optval = (udp_flags(sock->conn->pcb.udp) & UDP_FLAGS_NOCHKSUM) ? 1 : 0;
01994       break;
01995 #endif /* LWIP_UDP*/
01996     default:
01997       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, UNIMPL: optname=0x%x, ..)\n",
01998                   s, optname));
01999       err = ENOPROTOOPT;
02000       break;
02001     }  /* switch (optname) */
02002     break;
02003 
02004 /* Level: IPPROTO_IP */
02005   case IPPROTO_IP:
02006     switch (optname) {
02007     case IP_TTL:
02008       LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, *optlen, int);
02009       *(int*)optval = sock->conn->pcb.ip->ttl;
02010       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_TTL) = %d\n",
02011                   s, *(int *)optval));
02012       break;
02013     case IP_TOS:
02014       LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, *optlen, int);
02015       *(int*)optval = sock->conn->pcb.ip->tos;
02016       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_TOS) = %d\n",
02017                   s, *(int *)optval));
02018       break;
02019 #if LWIP_MULTICAST_TX_OPTIONS
02020     case IP_MULTICAST_TTL:
02021       LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, *optlen, u8_t);
02022       if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_UDP) {
02023         return ENOPROTOOPT;
02024       }
02025       *(u8_t*)optval = sock->conn->pcb.udp->mcast_ttl;
02026       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_MULTICAST_TTL) = %d\n",
02027                   s, *(int *)optval));
02028       break;
02029     case IP_MULTICAST_IF:
02030       LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, *optlen, struct in_addr);
02031       if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_UDP) {
02032         return ENOPROTOOPT;
02033       }
02034       inet_addr_from_ipaddr((struct in_addr*)optval, udp_get_multicast_netif_addr(sock->conn->pcb.udp));
02035       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_MULTICAST_IF) = 0x%"X32_F"\n",
02036                   s, *(u32_t *)optval));
02037       break;
02038     case IP_MULTICAST_LOOP:
02039       LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, *optlen, u8_t);
02040       if ((sock->conn->pcb.udp->flags & UDP_FLAGS_MULTICAST_LOOP) != 0) {
02041         *(u8_t*)optval = 1;
02042       } else {
02043         *(u8_t*)optval = 0;
02044       }
02045       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_MULTICAST_LOOP) = %d\n",
02046                   s, *(int *)optval));
02047       break;
02048 #endif /* LWIP_MULTICAST_TX_OPTIONS */
02049     default:
02050       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, UNIMPL: optname=0x%x, ..)\n",
02051                   s, optname));
02052       err = ENOPROTOOPT;
02053       break;
02054     }  /* switch (optname) */
02055     break;
02056 
02057 #if LWIP_TCP
02058 /* Level: IPPROTO_TCP */
02059   case IPPROTO_TCP:
02060     /* Special case: all IPPROTO_TCP option take an int */
02061     LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, *optlen, int, NETCONN_TCP);
02062     switch (optname) {
02063     case TCP_NODELAY:
02064       *(int*)optval = tcp_nagle_disabled(sock->conn->pcb.tcp);
02065       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_TCP, TCP_NODELAY) = %s\n",
02066                   s, (*(int*)optval)?"on":"off") );
02067       break;
02068     case TCP_KEEPALIVE:
02069       *(int*)optval = (int)sock->conn->pcb.tcp->keep_idle;
02070       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_TCP, TCP_KEEPALIVE) = %d\n",
02071                   s, *(int *)optval));
02072       break;
02073 
02074 #if LWIP_TCP_KEEPALIVE
02075     case TCP_KEEPIDLE:
02076       *(int*)optval = (int)(sock->conn->pcb.tcp->keep_idle/1000);
02077       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_TCP, TCP_KEEPIDLE) = %d\n",
02078                   s, *(int *)optval));
02079       break;
02080     case TCP_KEEPINTVL:
02081       *(int*)optval = (int)(sock->conn->pcb.tcp->keep_intvl/1000);
02082       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_TCP, TCP_KEEPINTVL) = %d\n",
02083                   s, *(int *)optval));
02084       break;
02085     case TCP_KEEPCNT:
02086       *(int*)optval = (int)sock->conn->pcb.tcp->keep_cnt;
02087       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_TCP, TCP_KEEPCNT) = %d\n",
02088                   s, *(int *)optval));
02089       break;
02090 #endif /* LWIP_TCP_KEEPALIVE */
02091     default:
02092       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_TCP, UNIMPL: optname=0x%x, ..)\n",
02093                   s, optname));
02094       err = ENOPROTOOPT;
02095       break;
02096     }  /* switch (optname) */
02097     break;
02098 #endif /* LWIP_TCP */
02099 
02100 #if LWIP_IPV6
02101 /* Level: IPPROTO_IPV6 */
02102   case IPPROTO_IPV6:
02103     switch (optname) {
02104     case IPV6_V6ONLY:
02105       LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, *optlen, int);
02106       /* @todo: this does not work for datagram sockets, yet */
02107       if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_TCP) {
02108         return ENOPROTOOPT;
02109       }
02110       *(int*)optval = (netconn_get_ipv6only(sock->conn) ? 1 : 0);
02111       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IPV6, IPV6_V6ONLY) = %d\n",
02112                   s, *(int *)optval));
02113       break;
02114     default:
02115       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IPV6, UNIMPL: optname=0x%x, ..)\n",
02116                   s, optname));
02117       err = ENOPROTOOPT;
02118       break;
02119     }  /* switch (optname) */
02120     break;
02121 #endif /* LWIP_IPV6 */
02122 
02123 #if LWIP_UDP && LWIP_UDPLITE
02124   /* Level: IPPROTO_UDPLITE */
02125   case IPPROTO_UDPLITE:
02126     /* Special case: all IPPROTO_UDPLITE option take an int */
02127     LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, *optlen, int);
02128     /* If this is no UDP lite socket, ignore any options. */
02129     if (!NETCONNTYPE_ISUDPLITE(netconn_type(sock->conn))) {
02130       return ENOPROTOOPT;
02131     }
02132     switch (optname) {
02133     case UDPLITE_SEND_CSCOV:
02134       *(int*)optval = sock->conn->pcb.udp->chksum_len_tx;
02135       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_UDPLITE, UDPLITE_SEND_CSCOV) = %d\n",
02136                   s, (*(int*)optval)) );
02137       break;
02138     case UDPLITE_RECV_CSCOV:
02139       *(int*)optval = sock->conn->pcb.udp->chksum_len_rx;
02140       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_UDPLITE, UDPLITE_RECV_CSCOV) = %d\n",
02141                   s, (*(int*)optval)) );
02142       break;
02143     default:
02144       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_UDPLITE, UNIMPL: optname=0x%x, ..)\n",
02145                   s, optname));
02146       err = ENOPROTOOPT;
02147       break;
02148     }  /* switch (optname) */
02149     break;
02150 #endif /* LWIP_UDP */
02151   /* Level: IPPROTO_RAW */
02152   case IPPROTO_RAW:
02153     switch (optname) {
02154 #if LWIP_IPV6 && LWIP_RAW
02155     case IPV6_CHECKSUM:
02156       LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, *optlen, int, NETCONN_RAW);
02157       if (sock->conn->pcb.raw->chksum_reqd == 0) {
02158         *(int *)optval = -1;
02159       } else {
02160         *(int *)optval = sock->conn->pcb.raw->chksum_offset;
02161       }
02162       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_RAW, IPV6_CHECKSUM) = %d\n",
02163                   s, (*(int*)optval)) );
02164       break;
02165 #endif /* LWIP_IPV6 && LWIP_RAW */
02166     default:
02167       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_RAW, UNIMPL: optname=0x%x, ..)\n",
02168                   s, optname));
02169       err = ENOPROTOOPT;
02170       break;
02171     }  /* switch (optname) */
02172     break;
02173   default:
02174     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, level=0x%x, UNIMPL: optname=0x%x, ..)\n",
02175                                 s, level, optname));
02176     err = ENOPROTOOPT;
02177     break;
02178   } /* switch (level) */
02179 
02180   return err;
02181 }
02182 
02183 int
02184 lwip_setsockopt(int s, int level, int optname, const void *optval, socklen_t optlen)
02185 {
02186   u8_t err = 0;
02187   struct lwip_sock *sock = get_socket(s);
02188 #if !LWIP_TCPIP_CORE_LOCKING
02189   LWIP_SETGETSOCKOPT_DATA_VAR_DECLARE(data);
02190 #endif /* !LWIP_TCPIP_CORE_LOCKING */
02191 
02192   if (!sock) {
02193     return -1;
02194   }
02195 
02196   if (NULL == optval) {
02197     sock_set_errno(sock, EFAULT);
02198     return -1;
02199   }
02200 
02201 #if LWIP_TCPIP_CORE_LOCKING
02202   /* core-locking can just call the -impl function */
02203   LOCK_TCPIP_CORE();
02204   err = lwip_setsockopt_impl(s, level, optname, optval, optlen);
02205   UNLOCK_TCPIP_CORE();
02206 
02207 #else /* LWIP_TCPIP_CORE_LOCKING */
02208 
02209 #if LWIP_MPU_COMPATIBLE
02210   /* MPU_COMPATIBLE copies the optval data, so check for max size here */
02211   if (optlen > LWIP_SETGETSOCKOPT_MAXOPTLEN) {
02212     sock_set_errno(sock, ENOBUFS);
02213     return -1;
02214   }
02215 #endif /* LWIP_MPU_COMPATIBLE */
02216 
02217   LWIP_SETGETSOCKOPT_DATA_VAR_ALLOC(data, sock);
02218   LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).s = s;
02219   LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).level = level;
02220   LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optname = optname;
02221   LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optlen = optlen;
02222 #if LWIP_MPU_COMPATIBLE
02223   memcpy(LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optval, optval, optlen);
02224 #else /* LWIP_MPU_COMPATIBLE */
02225   LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optval.pc = (const void*)optval;
02226 #endif /* LWIP_MPU_COMPATIBLE */
02227   LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).err = 0;
02228 #if LWIP_NETCONN_SEM_PER_THREAD
02229   LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).completed_sem = LWIP_NETCONN_THREAD_SEM_GET();
02230 #else
02231   LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).completed_sem = &sock->conn->op_completed;
02232 #endif
02233   err = tcpip_callback(lwip_setsockopt_callback, &LWIP_SETGETSOCKOPT_DATA_VAR_REF(data));
02234   if (err != ERR_OK) {
02235     LWIP_SETGETSOCKOPT_DATA_VAR_FREE(data);
02236     sock_set_errno(sock, err_to_errno(err));
02237     return -1;
02238   }
02239   sys_arch_sem_wait((sys_sem_t*)(LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).completed_sem), 0);
02240 
02241   /* maybe lwip_getsockopt_internal has changed err */
02242   err = LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).err;
02243   LWIP_SETGETSOCKOPT_DATA_VAR_FREE(data);
02244 #endif  /* LWIP_TCPIP_CORE_LOCKING */
02245 
02246   sock_set_errno(sock, err);
02247   return err ? -1 : 0;
02248 }
02249 
02250 #if !LWIP_TCPIP_CORE_LOCKING
02251 /** lwip_setsockopt_callback: only used without CORE_LOCKING
02252  * to get into the tcpip_thread
02253  */
02254 static void
02255 lwip_setsockopt_callback(void *arg)
02256 {
02257   struct lwip_setgetsockopt_data *data;
02258   LWIP_ASSERT("arg != NULL", arg != NULL);
02259   data = (struct lwip_setgetsockopt_data*)arg;
02260 
02261   data->err = lwip_setsockopt_impl(data->s, data->level, data->optname,
02262 #if LWIP_MPU_COMPATIBLE
02263     data->optval,
02264 #else /* LWIP_MPU_COMPATIBLE */
02265     data->optval.pc,
02266 #endif /* LWIP_MPU_COMPATIBLE */
02267     data->optlen);
02268 
02269   sys_sem_signal((sys_sem_t*)(data->completed_sem));
02270 }
02271 #endif  /* LWIP_TCPIP_CORE_LOCKING */
02272 
02273 /** lwip_setsockopt_impl: the actual implementation of setsockopt:
02274  * same argument as lwip_setsockopt, either called directly or through callback
02275  */
02276 static u8_t
02277 lwip_setsockopt_impl(int s, int level, int optname, const void *optval, socklen_t optlen)
02278 {
02279   u8_t err = 0;
02280   struct lwip_sock *sock = tryget_socket(s);
02281   if (!sock) {
02282     return EBADF;
02283   }
02284 
02285   switch (level) {
02286 
02287 /* Level: SOL_SOCKET */
02288   case SOL_SOCKET:
02289     switch (optname) {
02290 
02291     /* SO_ACCEPTCONN is get-only */
02292 
02293     /* The option flags */
02294     case SO_BROADCAST:
02295     case SO_KEEPALIVE:
02296 #if SO_REUSE
02297     case SO_REUSEADDR:
02298 #endif /* SO_REUSE */
02299       LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, optlen, int);
02300       if (*(const int*)optval) {
02301         ip_set_option(sock->conn->pcb.ip, optname);
02302       } else {
02303         ip_reset_option(sock->conn->pcb.ip, optname);
02304       }
02305       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, SOL_SOCKET, optname=0x%x, ..) -> %s\n",
02306                   s, optname, (*(const int*)optval?"on":"off")));
02307       break;
02308 
02309     /* SO_TYPE is get-only */
02310     /* SO_ERROR is get-only */
02311 
02312 #if LWIP_SO_SNDTIMEO
02313     case SO_SNDTIMEO:
02314       LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, optlen, LWIP_SO_SNDRCVTIMEO_OPTTYPE);
02315       netconn_set_sendtimeout(sock->conn, LWIP_SO_SNDRCVTIMEO_GET_MS(optval));
02316       break;
02317 #endif /* LWIP_SO_SNDTIMEO */
02318 #if LWIP_SO_RCVTIMEO
02319     case SO_RCVTIMEO:
02320       LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, optlen, LWIP_SO_SNDRCVTIMEO_OPTTYPE);
02321       netconn_set_recvtimeout(sock->conn, (int)LWIP_SO_SNDRCVTIMEO_GET_MS(optval));
02322       break;
02323 #endif /* LWIP_SO_RCVTIMEO */
02324 #if LWIP_SO_RCVBUF
02325     case SO_RCVBUF:
02326       LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, optlen, int);
02327       netconn_set_recvbufsize(sock->conn, *(const int*)optval);
02328       break;
02329 #endif /* LWIP_SO_RCVBUF */
02330 #if LWIP_SO_LINGER
02331     case SO_LINGER:
02332       {
02333         const struct linger* linger = (const struct linger*)optval;
02334         LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, optlen, struct linger);
02335         if (linger->l_onoff) {
02336           int lingersec = linger->l_linger;
02337           if (lingersec < 0) {
02338             return EINVAL;
02339           }
02340           if (lingersec > 0xFFFF) {
02341             lingersec = 0xFFFF;
02342           }
02343           sock->conn->linger = (s16_t)lingersec;
02344         } else {
02345           sock->conn->linger = -1;
02346         }
02347       }
02348       break;
02349 #endif /* LWIP_SO_LINGER */
02350 #if LWIP_UDP
02351     case SO_NO_CHECK:
02352       LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, int, NETCONN_UDP);
02353 #if LWIP_UDPLITE
02354       if ((udp_flags(sock->conn->pcb.udp) & UDP_FLAGS_UDPLITE) != 0) {
02355         /* this flag is only available for UDP, not for UDP lite */
02356         return EAFNOSUPPORT;
02357       }
02358 #endif /* LWIP_UDPLITE */
02359       if (*(const int*)optval) {
02360         udp_setflags(sock->conn->pcb.udp, udp_flags(sock->conn->pcb.udp) | UDP_FLAGS_NOCHKSUM);
02361       } else {
02362         udp_setflags(sock->conn->pcb.udp, udp_flags(sock->conn->pcb.udp) & ~UDP_FLAGS_NOCHKSUM);
02363       }
02364       break;
02365 #endif /* LWIP_UDP */
02366     default:
02367       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, SOL_SOCKET, UNIMPL: optname=0x%x, ..)\n",
02368                   s, optname));
02369       err = ENOPROTOOPT;
02370       break;
02371     }  /* switch (optname) */
02372     break;
02373 
02374 /* Level: IPPROTO_IP */
02375   case IPPROTO_IP:
02376     switch (optname) {
02377     case IP_TTL:
02378       LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, optlen, int);
02379       sock->conn->pcb.ip->ttl = (u8_t)(*(const int*)optval);
02380       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IP, IP_TTL, ..) -> %d\n",
02381                   s, sock->conn->pcb.ip->ttl));
02382       break;
02383     case IP_TOS:
02384       LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, optlen, int);
02385       sock->conn->pcb.ip->tos = (u8_t)(*(const int*)optval);
02386       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IP, IP_TOS, ..)-> %d\n",
02387                   s, sock->conn->pcb.ip->tos));
02388       break;
02389 #if LWIP_MULTICAST_TX_OPTIONS
02390     case IP_MULTICAST_TTL:
02391       LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, u8_t, NETCONN_UDP);
02392       sock->conn->pcb.udp->mcast_ttl = (u8_t)(*(const u8_t*)optval);
02393       break;
02394     case IP_MULTICAST_IF:
02395       {
02396         ip4_addr_t if_addr;
02397         LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, struct in_addr, NETCONN_UDP);
02398         inet_addr_to_ipaddr(&if_addr, (const struct in_addr*)optval);
02399         udp_set_multicast_netif_addr(sock->conn->pcb.udp, &if_addr);
02400       }
02401       break;
02402     case IP_MULTICAST_LOOP:
02403       LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, u8_t, NETCONN_UDP);
02404       if (*(const u8_t*)optval) {
02405         udp_setflags(sock->conn->pcb.udp, udp_flags(sock->conn->pcb.udp) | UDP_FLAGS_MULTICAST_LOOP);
02406       } else {
02407         udp_setflags(sock->conn->pcb.udp, udp_flags(sock->conn->pcb.udp) & ~UDP_FLAGS_MULTICAST_LOOP);
02408       }
02409       break;
02410 #endif /* LWIP_MULTICAST_TX_OPTIONS */
02411 #if LWIP_IGMP
02412     case IP_ADD_MEMBERSHIP:
02413     case IP_DROP_MEMBERSHIP:
02414       {
02415         /* If this is a TCP or a RAW socket, ignore these options. */
02416         /* @todo: assign membership to this socket so that it is dropped when closing the socket */
02417         err_t igmp_err;
02418         const struct ip_mreq *imr = (const struct ip_mreq *)optval;
02419         ip4_addr_t if_addr;
02420         ip4_addr_t multi_addr;
02421         LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, struct ip_mreq, NETCONN_UDP);
02422         inet_addr_to_ipaddr(&if_addr, &imr->imr_interface);
02423         inet_addr_to_ipaddr(&multi_addr, &imr->imr_multiaddr);
02424         if (optname == IP_ADD_MEMBERSHIP) {
02425           if (!lwip_socket_register_membership(s, &if_addr, &multi_addr)) {
02426             /* cannot track membership (out of memory) */
02427             err = ENOMEM;
02428             igmp_err = ERR_OK;
02429           } else {
02430             igmp_err = igmp_joingroup(&if_addr, &multi_addr);
02431           }
02432         } else {
02433           igmp_err = igmp_leavegroup(&if_addr, &multi_addr);
02434           lwip_socket_unregister_membership(s, &if_addr, &multi_addr);
02435         }
02436         if (igmp_err != ERR_OK) {
02437           err = EADDRNOTAVAIL;
02438         }
02439       }
02440       break;
02441 #endif /* LWIP_IGMP */
02442     default:
02443       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IP, UNIMPL: optname=0x%x, ..)\n",
02444                   s, optname));
02445       err = ENOPROTOOPT;
02446       break;
02447     }  /* switch (optname) */
02448     break;
02449 
02450 #if LWIP_TCP
02451 /* Level: IPPROTO_TCP */
02452   case IPPROTO_TCP:
02453     /* Special case: all IPPROTO_TCP option take an int */
02454     LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, int, NETCONN_TCP);
02455     switch (optname) {
02456     case TCP_NODELAY:
02457       if (*(const int*)optval) {
02458         tcp_nagle_disable(sock->conn->pcb.tcp);
02459       } else {
02460         tcp_nagle_enable(sock->conn->pcb.tcp);
02461       }
02462       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_NODELAY) -> %s\n",
02463                   s, (*(const int *)optval)?"on":"off") );
02464       break;
02465     case TCP_KEEPALIVE:
02466       sock->conn->pcb.tcp->keep_idle = (u32_t)(*(const int*)optval);
02467       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPALIVE) -> %"U32_F"\n",
02468                   s, sock->conn->pcb.tcp->keep_idle));
02469       break;
02470 
02471 #if LWIP_TCP_KEEPALIVE
02472     case TCP_KEEPIDLE:
02473       sock->conn->pcb.tcp->keep_idle = 1000*(u32_t)(*(const int*)optval);
02474       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPIDLE) -> %"U32_F"\n",
02475                   s, sock->conn->pcb.tcp->keep_idle));
02476       break;
02477     case TCP_KEEPINTVL:
02478       sock->conn->pcb.tcp->keep_intvl = 1000*(u32_t)(*(const int*)optval);
02479       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPINTVL) -> %"U32_F"\n",
02480                   s, sock->conn->pcb.tcp->keep_intvl));
02481       break;
02482     case TCP_KEEPCNT:
02483       sock->conn->pcb.tcp->keep_cnt = (u32_t)(*(const int*)optval);
02484       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPCNT) -> %"U32_F"\n",
02485                   s, sock->conn->pcb.tcp->keep_cnt));
02486       break;
02487 #endif /* LWIP_TCP_KEEPALIVE */
02488     default:
02489       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, UNIMPL: optname=0x%x, ..)\n",
02490                   s, optname));
02491       err = ENOPROTOOPT;
02492       break;
02493     }  /* switch (optname) */
02494     break;
02495 #endif /* LWIP_TCP*/
02496 
02497 #if LWIP_IPV6
02498 /* Level: IPPROTO_IPV6 */
02499   case IPPROTO_IPV6:
02500     switch (optname) {
02501     case IPV6_V6ONLY:
02502       /* @todo: this does not work for datagram sockets, yet */
02503       LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, int, NETCONN_TCP);
02504       if (*(const int*)optval) {
02505         netconn_set_ipv6only(sock->conn, 1);
02506       } else {
02507         netconn_set_ipv6only(sock->conn, 0);
02508       }
02509       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IPV6, IPV6_V6ONLY, ..) -> %d\n",
02510                   s, (netconn_get_ipv6only(sock->conn) ? 1 : 0)));
02511       break;
02512     default:
02513       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IPV6, UNIMPL: optname=0x%x, ..)\n",
02514                   s, optname));
02515       err = ENOPROTOOPT;
02516       break;
02517     }  /* switch (optname) */
02518     break;
02519 #endif /* LWIP_IPV6 */
02520 
02521 #if LWIP_UDP && LWIP_UDPLITE
02522   /* Level: IPPROTO_UDPLITE */
02523   case IPPROTO_UDPLITE:
02524     /* Special case: all IPPROTO_UDPLITE option take an int */
02525     LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, optlen, int);
02526     /* If this is no UDP lite socket, ignore any options. */
02527     if (!NETCONNTYPE_ISUDPLITE(netconn_type(sock->conn))) {
02528       return ENOPROTOOPT;
02529     }
02530     switch (optname) {
02531     case UDPLITE_SEND_CSCOV:
02532       if ((*(const int*)optval != 0) && ((*(const int*)optval < 8) || (*(const int*)optval > 0xffff))) {
02533         /* don't allow illegal values! */
02534         sock->conn->pcb.udp->chksum_len_tx = 8;
02535       } else {
02536         sock->conn->pcb.udp->chksum_len_tx = (u16_t)*(const int*)optval;
02537       }
02538       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_UDPLITE, UDPLITE_SEND_CSCOV) -> %d\n",
02539                   s, (*(const int*)optval)) );
02540       break;
02541     case UDPLITE_RECV_CSCOV:
02542       if ((*(const int*)optval != 0) && ((*(const int*)optval < 8) || (*(const int*)optval > 0xffff))) {
02543         /* don't allow illegal values! */
02544         sock->conn->pcb.udp->chksum_len_rx = 8;
02545       } else {
02546         sock->conn->pcb.udp->chksum_len_rx = (u16_t)*(const int*)optval;
02547       }
02548       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_UDPLITE, UDPLITE_RECV_CSCOV) -> %d\n",
02549                   s, (*(const int*)optval)) );
02550       break;
02551     default:
02552       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_UDPLITE, UNIMPL: optname=0x%x, ..)\n",
02553                   s, optname));
02554       err = ENOPROTOOPT;
02555       break;
02556     }  /* switch (optname) */
02557     break;
02558 #endif /* LWIP_UDP */
02559   /* Level: IPPROTO_RAW */
02560   case IPPROTO_RAW:
02561     switch (optname) {
02562 #if LWIP_IPV6 && LWIP_RAW
02563     case IPV6_CHECKSUM:
02564       LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, int, NETCONN_RAW);
02565       if (*(const int *)optval < 0) {
02566         sock->conn->pcb.raw->chksum_reqd = 0;
02567       } else if (*(const int *)optval & 1) {
02568         /* Per RFC3542, odd offsets are not allowed */
02569         return EINVAL;
02570       } else {
02571         sock->conn->pcb.raw->chksum_reqd = 1;
02572         sock->conn->pcb.raw->chksum_offset = (u16_t)*(const int *)optval;
02573       }
02574       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_RAW, IPV6_CHECKSUM, ..) -> %d\n",
02575                   s, sock->conn->pcb.raw->chksum_reqd));
02576       break;
02577 #endif /* LWIP_IPV6 && LWIP_RAW */
02578     default:
02579       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_RAW, UNIMPL: optname=0x%x, ..)\n",
02580                                   s, optname));
02581       err = ENOPROTOOPT;
02582       break;
02583     }  /* switch (optname) */
02584     break;
02585   default:
02586     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, level=0x%x, UNIMPL: optname=0x%x, ..)\n",
02587                 s, level, optname));
02588     err = ENOPROTOOPT;
02589     break;
02590   }  /* switch (level) */
02591 
02592   return err;
02593 }
02594 
02595 int
02596 lwip_ioctl(int s, long cmd, void *argp)
02597 {
02598   struct lwip_sock *sock = get_socket(s);
02599   u8_t val;
02600 #if LWIP_SO_RCVBUF
02601   u16_t buflen = 0;
02602   int recv_avail;
02603 #endif /* LWIP_SO_RCVBUF */
02604 
02605   if (!sock) {
02606     return -1;
02607   }
02608 
02609   switch (cmd) {
02610 #if LWIP_SO_RCVBUF || LWIP_FIONREAD_LINUXMODE
02611   case FIONREAD:
02612     if (!argp) {
02613       sock_set_errno(sock, EINVAL);
02614       return -1;
02615     }
02616 #if LWIP_FIONREAD_LINUXMODE
02617     if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_TCP) {
02618       struct pbuf *p;
02619       if (sock->lastdata) {
02620         p = ((struct netbuf *)sock->lastdata)->p;
02621         *((int*)argp) = p->tot_len - sock->lastoffset;
02622       } else {
02623         struct netbuf *rxbuf;
02624         err_t err;
02625         if (sock->rcvevent <= 0) {
02626           *((int*)argp) = 0;
02627         } else {
02628           err = netconn_recv(sock->conn, &rxbuf);
02629           if (err != ERR_OK) {
02630             *((int*)argp) = 0;
02631           } else {
02632             sock->lastdata = rxbuf;
02633             sock->lastoffset = 0;
02634             *((int*)argp) = rxbuf->p->tot_len;
02635           }
02636         }
02637       }
02638       return 0;
02639     }
02640 #endif /* LWIP_FIONREAD_LINUXMODE */
02641 
02642 #if LWIP_SO_RCVBUF
02643     /* we come here if either LWIP_FIONREAD_LINUXMODE==0 or this is a TCP socket */
02644     SYS_ARCH_GET(sock->conn->recv_avail, recv_avail);
02645     if (recv_avail < 0) {
02646       recv_avail = 0;
02647     }
02648     *((int*)argp) = recv_avail;
02649 
02650     /* Check if there is data left from the last recv operation. /maq 041215 */
02651     if (sock->lastdata) {
02652       struct pbuf *p = (struct pbuf *)sock->lastdata;
02653       if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_TCP) {
02654         p = ((struct netbuf *)p)->p;
02655       }
02656       buflen = p->tot_len;
02657       buflen -= sock->lastoffset;
02658 
02659       *((int*)argp) += buflen;
02660     }
02661 
02662     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(%d, FIONREAD, %p) = %"U16_F"\n", s, argp, *((u16_t*)argp)));
02663     sock_set_errno(sock, 0);
02664     return 0;
02665 #else /* LWIP_SO_RCVBUF */
02666     break;
02667 #endif /* LWIP_SO_RCVBUF */
02668 #endif /* LWIP_SO_RCVBUF || LWIP_FIONREAD_LINUXMODE */
02669 
02670   case (long)FIONBIO:
02671     val = 0;
02672     if (argp && *(u32_t*)argp) {
02673       val = 1;
02674     }
02675     netconn_set_nonblocking(sock->conn, val);
02676     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(%d, FIONBIO, %d)\n", s, val));
02677     sock_set_errno(sock, 0);
02678     return 0;
02679 
02680   default:
02681     break;
02682   } /* switch (cmd) */
02683   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(%d, UNIMPL: 0x%lx, %p)\n", s, cmd, argp));
02684   sock_set_errno(sock, ENOSYS); /* not yet implemented */
02685   return -1;
02686 }
02687 
02688 /** A minimal implementation of fcntl.
02689  * Currently only the commands F_GETFL and F_SETFL are implemented.
02690  * Only the flag O_NONBLOCK is implemented.
02691  */
02692 int
02693 lwip_fcntl(int s, int cmd, int val)
02694 {
02695   struct lwip_sock *sock = get_socket(s);
02696   int ret = -1;
02697 
02698   if (!sock) {
02699     return -1;
02700   }
02701 
02702   switch (cmd) {
02703   case F_GETFL:
02704     ret = netconn_is_nonblocking(sock->conn) ? O_NONBLOCK : 0;
02705     sock_set_errno(sock, 0);
02706     break;
02707   case F_SETFL:
02708     if ((val & ~O_NONBLOCK) == 0) {
02709       /* only O_NONBLOCK, all other bits are zero */
02710       netconn_set_nonblocking(sock->conn, val & O_NONBLOCK);
02711       ret = 0;
02712       sock_set_errno(sock, 0);
02713     } else {
02714       sock_set_errno(sock, ENOSYS); /* not yet implemented */
02715     }
02716     break;
02717   default:
02718     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_fcntl(%d, UNIMPL: %d, %d)\n", s, cmd, val));
02719     sock_set_errno(sock, ENOSYS); /* not yet implemented */
02720     break;
02721   }
02722   return ret;
02723 }
02724 
02725 #if LWIP_IGMP
02726 /** Register a new IGMP membership. On socket close, the membership is dropped automatically.
02727  *
02728  * ATTENTION: this function is called from tcpip_thread (or under CORE_LOCK).
02729  *
02730  * @return 1 on success, 0 on failure
02731  */
02732 static int
02733 lwip_socket_register_membership(int s, const ip4_addr_t *if_addr, const ip4_addr_t *multi_addr)
02734 {
02735   /* s+1 is stored in the array to prevent having to initialize the array
02736      (default initialization is to 0) */
02737   int sa = s + 1;
02738   int i;
02739 
02740   for (i = 0; i < LWIP_SOCKET_MAX_MEMBERSHIPS; i++) {
02741     if (socket_ipv4_multicast_memberships[i].sa == 0) {
02742       socket_ipv4_multicast_memberships[i].sa = sa;
02743       ip4_addr_copy(socket_ipv4_multicast_memberships[i].if_addr, *if_addr);
02744       ip4_addr_copy(socket_ipv4_multicast_memberships[i].multi_addr, *multi_addr);
02745       return 1;
02746     }
02747   }
02748   return 0;
02749 }
02750 
02751 /** Unregister a previously registered membership. This prevents dropping the membership
02752  * on socket close.
02753  *
02754  * ATTENTION: this function is called from tcpip_thread (or under CORE_LOCK).
02755  */
02756 static void
02757 lwip_socket_unregister_membership(int s, const ip4_addr_t *if_addr, const ip4_addr_t *multi_addr)
02758 {
02759   /* s+1 is stored in the array to prevent having to initialize the array
02760      (default initialization is to 0) */
02761   int sa = s + 1;
02762   int i;
02763 
02764   for (i = 0; i < LWIP_SOCKET_MAX_MEMBERSHIPS; i++) {
02765     if ((socket_ipv4_multicast_memberships[i].sa == sa) &&
02766         ip4_addr_cmp(&socket_ipv4_multicast_memberships[i].if_addr, if_addr) &&
02767         ip4_addr_cmp(&socket_ipv4_multicast_memberships[i].multi_addr, multi_addr)) {
02768       socket_ipv4_multicast_memberships[i].sa = 0;
02769       ip4_addr_set_zero(&socket_ipv4_multicast_memberships[i].if_addr);
02770       ip4_addr_set_zero(&socket_ipv4_multicast_memberships[i].multi_addr);
02771       return;
02772     }
02773   }
02774 }
02775 
02776 /** Drop all memberships of a socket that were not dropped explicitly via setsockopt.
02777  *
02778  * ATTENTION: this function is NOT called from tcpip_thread (or under CORE_LOCK).
02779  */
02780 static void lwip_socket_drop_registered_memberships(int s)
02781 {
02782   /* s+1 is stored in the array to prevent having to initialize the array
02783      (default initialization is to 0) */
02784   int sa = s + 1;
02785   int i;
02786 
02787   LWIP_ASSERT("socket has no netconn", sockets[s].conn != NULL);
02788 
02789   for (i = 0; i < LWIP_SOCKET_MAX_MEMBERSHIPS; i++) {
02790     if (socket_ipv4_multicast_memberships[i].sa == sa) {
02791       ip_addr_t multi_addr, if_addr;
02792       ip_addr_copy_from_ip4(multi_addr, socket_ipv4_multicast_memberships[i].multi_addr);
02793       ip_addr_copy_from_ip4(if_addr, socket_ipv4_multicast_memberships[i].if_addr);
02794       socket_ipv4_multicast_memberships[i].sa = 0;
02795       ip4_addr_set_zero(&socket_ipv4_multicast_memberships[i].if_addr);
02796       ip4_addr_set_zero(&socket_ipv4_multicast_memberships[i].multi_addr);
02797 
02798       netconn_join_leave_group(sockets[s].conn, &multi_addr, &if_addr, NETCONN_LEAVE);
02799     }
02800   }
02801 }
02802 #endif /* LWIP_IGMP */
02803 #endif /* LWIP_SOCKET */