Daiki Kato / mbed-os-lychee

Dependents:   mbed-os-example-blinky-gr-lychee GR-Boads_Camera_sample GR-Boards_Audio_Recoder GR-Boads_Camera_DisplayApp ... more

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