Kenji Arai / mbed-os_TYBLE16

Dependents:   TYBLE16_simple_data_logger TYBLE16_MP3_Air

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers lwip_sockets.c Source File

lwip_sockets.c

Go to the documentation of this file.
00001 /**
00002  * @file
00003  * Sockets BSD-Like API module
00004  */
00005 
00006 /*
00007  * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
00008  * All rights reserved.
00009  *
00010  * Redistribution and use in source and binary forms, with or without modification,
00011  * are permitted provided that the following conditions are met:
00012  *
00013  * 1. Redistributions of source code must retain the above copyright notice,
00014  *    this list of conditions and the following disclaimer.
00015  * 2. Redistributions in binary form must reproduce the above copyright notice,
00016  *    this list of conditions and the following disclaimer in the documentation
00017  *    and/or other materials provided with the distribution.
00018  * 3. The name of the author may not be used to endorse or promote products
00019  *    derived from this software without specific prior written permission.
00020  *
00021  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
00022  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
00023  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
00024  * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
00025  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
00026  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00027  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
00028  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
00029  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
00030  * OF SUCH DAMAGE.
00031  *
00032  * This file is part of the lwIP TCP/IP stack.
00033  *
00034  * Author: Adam Dunkels <adam@sics.se>
00035  *
00036  * Improved by Marc Boucher <marc@mbsi.ca> and David Haas <dhaas@alum.rpi.edu>
00037  *
00038  */
00039 
00040 #include "lwip/opt.h"
00041 
00042 #if LWIP_SOCKET /* don't build if not configured for use in lwipopts.h */
00043 
00044 #include "lwip/sockets.h"
00045 #include "lwip/priv/sockets_priv.h"
00046 #include "lwip/api.h"
00047 #include "lwip/igmp.h"
00048 #include "lwip/inet.h"
00049 #include "lwip/tcp.h"
00050 #include "lwip/raw.h"
00051 #include "lwip/udp.h"
00052 #include "lwip/memp.h"
00053 #include "lwip/pbuf.h"
00054 #include "lwip/netif.h"
00055 #include "lwip/priv/tcpip_priv.h"
00056 #include "lwip/mld6.h"
00057 #if LWIP_CHECKSUM_ON_COPY
00058 #include "lwip/inet_chksum.h"
00059 #endif
00060 
00061 #if LWIP_COMPAT_SOCKETS == 2 && LWIP_POSIX_SOCKETS_IO_NAMES
00062 #include <stdarg.h>
00063 #endif
00064 
00065 #include <string.h>
00066 
00067 #ifdef LWIP_HOOK_FILENAME
00068 #include LWIP_HOOK_FILENAME
00069 #endif
00070 
00071 /* If the netconn API is not required publicly, then we include the necessary
00072    files here to get the implementation */
00073 #if !LWIP_NETCONN
00074 #undef LWIP_NETCONN
00075 #define LWIP_NETCONN 1
00076 #include "api_msg.c"
00077 #include "api_lib.c"
00078 #include "netbuf.c"
00079 #undef LWIP_NETCONN
00080 #define LWIP_NETCONN 0
00081 #endif
00082 
00083 #define API_SELECT_CB_VAR_REF(name)               API_VAR_REF(name)
00084 #define API_SELECT_CB_VAR_DECLARE(name)           API_VAR_DECLARE(struct lwip_select_cb, name)
00085 #define API_SELECT_CB_VAR_ALLOC(name, retblock)   API_VAR_ALLOC_EXT(struct lwip_select_cb, MEMP_SELECT_CB, name, retblock)
00086 #define API_SELECT_CB_VAR_FREE(name)              API_VAR_FREE(MEMP_SELECT_CB, name)
00087 
00088 #if LWIP_IPV4
00089 #define IP4ADDR_PORT_TO_SOCKADDR(sin, ipaddr, port) do { \
00090       (sin)->sin_len = sizeof(struct sockaddr_in); \
00091       (sin)->sin_family = AF_INET; \
00092       (sin)->sin_port = lwip_htons((port)); \
00093       inet_addr_from_ip4addr(&(sin)->sin_addr, ipaddr); \
00094       memset((sin)->sin_zero, 0, SIN_ZERO_LEN); }while(0)
00095 #define SOCKADDR4_TO_IP4ADDR_PORT(sin, ipaddr, port) do { \
00096     inet_addr_to_ip4addr(ip_2_ip4(ipaddr), &((sin)->sin_addr)); \
00097     (port) = lwip_ntohs((sin)->sin_port); }while(0)
00098 #endif /* LWIP_IPV4 */
00099 
00100 #if LWIP_IPV6
00101 #define IP6ADDR_PORT_TO_SOCKADDR(sin6, ipaddr, port) do { \
00102       (sin6)->sin6_len = sizeof(struct sockaddr_in6); \
00103       (sin6)->sin6_family = AF_INET6; \
00104       (sin6)->sin6_port = lwip_htons((port)); \
00105       (sin6)->sin6_flowinfo = 0; \
00106       inet6_addr_from_ip6addr(&(sin6)->sin6_addr, ipaddr); \
00107       (sin6)->sin6_scope_id = ip6_addr_zone(ipaddr); }while(0)
00108 #define SOCKADDR6_TO_IP6ADDR_PORT(sin6, ipaddr, port) do { \
00109     inet6_addr_to_ip6addr(ip_2_ip6(ipaddr), &((sin6)->sin6_addr)); \
00110     if (ip6_addr_has_scope(ip_2_ip6(ipaddr), IP6_UNKNOWN)) { \
00111       ip6_addr_set_zone(ip_2_ip6(ipaddr), (u8_t)((sin6)->sin6_scope_id)); \
00112     } \
00113     (port) = lwip_ntohs((sin6)->sin6_port); }while(0)
00114 #endif /* LWIP_IPV6 */
00115 
00116 #if LWIP_IPV4 && LWIP_IPV6
00117 static void sockaddr_to_ipaddr_port(const struct sockaddr *sockaddr, ip_addr_t *ipaddr, u16_t *port);
00118 
00119 #define IS_SOCK_ADDR_LEN_VALID(namelen)  (((namelen) == sizeof(struct sockaddr_in)) || \
00120                                          ((namelen) == sizeof(struct sockaddr_in6)))
00121 #define IS_SOCK_ADDR_TYPE_VALID(name)    (((name)->sa_family == AF_INET) || \
00122                                          ((name)->sa_family == AF_INET6))
00123 #define SOCK_ADDR_TYPE_MATCH(name, sock) \
00124        ((((name)->sa_family == AF_INET) && !(NETCONNTYPE_ISIPV6((sock)->conn->type))) || \
00125        (((name)->sa_family == AF_INET6) && (NETCONNTYPE_ISIPV6((sock)->conn->type))))
00126 #define IPADDR_PORT_TO_SOCKADDR(sockaddr, ipaddr, port) do { \
00127     if (IP_IS_ANY_TYPE_VAL(*ipaddr) || IP_IS_V6_VAL(*ipaddr)) { \
00128       IP6ADDR_PORT_TO_SOCKADDR((struct sockaddr_in6*)(void*)(sockaddr), ip_2_ip6(ipaddr), port); \
00129     } else { \
00130       IP4ADDR_PORT_TO_SOCKADDR((struct sockaddr_in*)(void*)(sockaddr), ip_2_ip4(ipaddr), port); \
00131     } } while(0)
00132 #define SOCKADDR_TO_IPADDR_PORT(sockaddr, ipaddr, port) sockaddr_to_ipaddr_port(sockaddr, ipaddr, &(port))
00133 #define DOMAIN_TO_NETCONN_TYPE(domain, type) (((domain) == AF_INET) ? \
00134   (type) : (enum netconn_type)((type) | NETCONN_TYPE_IPV6))
00135 #elif LWIP_IPV6 /* LWIP_IPV4 && LWIP_IPV6 */
00136 #define IS_SOCK_ADDR_LEN_VALID(namelen)  ((namelen) == sizeof(struct sockaddr_in6))
00137 #define IS_SOCK_ADDR_TYPE_VALID(name)    ((name)->sa_family == AF_INET6)
00138 #define SOCK_ADDR_TYPE_MATCH(name, sock) 1
00139 #define IPADDR_PORT_TO_SOCKADDR(sockaddr, ipaddr, port) \
00140         IP6ADDR_PORT_TO_SOCKADDR((struct sockaddr_in6*)(void*)(sockaddr), ip_2_ip6(ipaddr), port)
00141 #define SOCKADDR_TO_IPADDR_PORT(sockaddr, ipaddr, port) \
00142         SOCKADDR6_TO_IP6ADDR_PORT((const struct sockaddr_in6*)(const void*)(sockaddr), ipaddr, port)
00143 #define DOMAIN_TO_NETCONN_TYPE(domain, netconn_type) (netconn_type)
00144 #else /*-> LWIP_IPV4: LWIP_IPV4 && LWIP_IPV6 */
00145 #define IS_SOCK_ADDR_LEN_VALID(namelen)  ((namelen) == sizeof(struct sockaddr_in))
00146 #define IS_SOCK_ADDR_TYPE_VALID(name)    ((name)->sa_family == AF_INET)
00147 #define SOCK_ADDR_TYPE_MATCH(name, sock) 1
00148 #define IPADDR_PORT_TO_SOCKADDR(sockaddr, ipaddr, port) \
00149         IP4ADDR_PORT_TO_SOCKADDR((struct sockaddr_in*)(void*)(sockaddr), ip_2_ip4(ipaddr), port)
00150 #define SOCKADDR_TO_IPADDR_PORT(sockaddr, ipaddr, port) \
00151         SOCKADDR4_TO_IP4ADDR_PORT((const struct sockaddr_in*)(const void*)(sockaddr), ipaddr, port)
00152 #define DOMAIN_TO_NETCONN_TYPE(domain, netconn_type) (netconn_type)
00153 #endif /* LWIP_IPV6 */
00154 
00155 #define IS_SOCK_ADDR_TYPE_VALID_OR_UNSPEC(name)    (((name)->sa_family == AF_UNSPEC) || \
00156                                                     IS_SOCK_ADDR_TYPE_VALID(name))
00157 #define SOCK_ADDR_TYPE_MATCH_OR_UNSPEC(name, sock) (((name)->sa_family == AF_UNSPEC) || \
00158                                                     SOCK_ADDR_TYPE_MATCH(name, sock))
00159 #define IS_SOCK_ADDR_ALIGNED(name)      ((((mem_ptr_t)(name)) % 4) == 0)
00160 
00161 
00162 #define LWIP_SOCKOPT_CHECK_OPTLEN(sock, optlen, opttype) do { if ((optlen) < sizeof(opttype)) { done_socket(sock); return EINVAL; }}while(0)
00163 #define LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, optlen, opttype) do { \
00164   LWIP_SOCKOPT_CHECK_OPTLEN(sock, optlen, opttype); \
00165   if ((sock)->conn == NULL) { done_socket(sock); return EINVAL; } }while(0)
00166 #define LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, optlen, opttype) do { \
00167   LWIP_SOCKOPT_CHECK_OPTLEN(sock, optlen, opttype); \
00168   if (((sock)->conn == NULL) || ((sock)->conn->pcb.tcp == NULL)) { done_socket(sock); return EINVAL; } }while(0)
00169 #define LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, opttype, netconntype) do { \
00170   LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, optlen, opttype); \
00171   if (NETCONNTYPE_GROUP(netconn_type((sock)->conn)) != netconntype) { done_socket(sock); return ENOPROTOOPT; } }while(0)
00172 
00173 
00174 #define LWIP_SETGETSOCKOPT_DATA_VAR_REF(name)     API_VAR_REF(name)
00175 #define LWIP_SETGETSOCKOPT_DATA_VAR_DECLARE(name) API_VAR_DECLARE(struct lwip_setgetsockopt_data, name)
00176 #define LWIP_SETGETSOCKOPT_DATA_VAR_FREE(name)    API_VAR_FREE(MEMP_SOCKET_SETGETSOCKOPT_DATA, name)
00177 #if LWIP_MPU_COMPATIBLE
00178 #define LWIP_SETGETSOCKOPT_DATA_VAR_ALLOC(name, sock) do { \
00179   name = (struct lwip_setgetsockopt_data *)memp_malloc(MEMP_SOCKET_SETGETSOCKOPT_DATA); \
00180   if (name == NULL) { \
00181     sock_set_errno(sock, ENOMEM); \
00182     done_socket(sock); \
00183     return -1; \
00184   } }while(0)
00185 #else /* LWIP_MPU_COMPATIBLE */
00186 #define LWIP_SETGETSOCKOPT_DATA_VAR_ALLOC(name, sock)
00187 #endif /* LWIP_MPU_COMPATIBLE */
00188 
00189 #if LWIP_SO_SNDRCVTIMEO_NONSTANDARD
00190 #define LWIP_SO_SNDRCVTIMEO_OPTTYPE int
00191 #define LWIP_SO_SNDRCVTIMEO_SET(optval, val) (*(int *)(optval) = (val))
00192 #define LWIP_SO_SNDRCVTIMEO_GET_MS(optval)   ((long)*(const int*)(optval))
00193 #else
00194 #define LWIP_SO_SNDRCVTIMEO_OPTTYPE struct timeval
00195 #define LWIP_SO_SNDRCVTIMEO_SET(optval, val)  do { \
00196   u32_t loc = (val); \
00197   ((struct timeval *)(optval))->tv_sec = (long)((loc) / 1000U); \
00198   ((struct timeval *)(optval))->tv_usec = (long)(((loc) % 1000U) * 1000U); }while(0)
00199 #define LWIP_SO_SNDRCVTIMEO_GET_MS(optval) ((((const struct timeval *)(optval))->tv_sec * 1000) + (((const struct timeval *)(optval))->tv_usec / 1000))
00200 #endif
00201 
00202 
00203 /** A struct sockaddr replacement that has the same alignment as sockaddr_in/
00204  *  sockaddr_in6 if instantiated.
00205  */
00206 union sockaddr_aligned {
00207   struct sockaddr sa;
00208 #if LWIP_IPV6
00209   struct sockaddr_in6 sin6;
00210 #endif /* LWIP_IPV6 */
00211 #if LWIP_IPV4
00212   struct sockaddr_in sin;
00213 #endif /* LWIP_IPV4 */
00214 };
00215 
00216 /* Define the number of IPv4 multicast memberships, default is one per socket */
00217 #ifndef LWIP_SOCKET_MAX_MEMBERSHIPS
00218 #define LWIP_SOCKET_MAX_MEMBERSHIPS NUM_SOCKETS
00219 #endif
00220 
00221 #if LWIP_IGMP
00222 /* This is to keep track of IP_ADD_MEMBERSHIP calls to drop the membership when
00223    a socket is closed */
00224 struct lwip_socket_multicast_pair {
00225   /** the socket */
00226   struct lwip_sock *sock;
00227   /** the interface address */
00228   ip4_addr_t if_addr;
00229   /** the group address */
00230   ip4_addr_t multi_addr;
00231 };
00232 
00233 static struct lwip_socket_multicast_pair socket_ipv4_multicast_memberships[LWIP_SOCKET_MAX_MEMBERSHIPS];
00234 
00235 static int  lwip_socket_register_membership(int s, const ip4_addr_t *if_addr, const ip4_addr_t *multi_addr);
00236 static void lwip_socket_unregister_membership(int s, const ip4_addr_t *if_addr, const ip4_addr_t *multi_addr);
00237 static void lwip_socket_drop_registered_memberships(int s);
00238 #endif /* LWIP_IGMP */
00239 
00240 #if LWIP_IPV6_MLD
00241 /* This is to keep track of IP_JOIN_GROUP calls to drop the membership when
00242    a socket is closed */
00243 struct lwip_socket_multicast_mld6_pair {
00244   /** the socket */
00245   struct lwip_sock *sock;
00246   /** the interface index */
00247   u8_t if_idx;
00248   /** the group address */
00249   ip6_addr_t multi_addr;
00250 };
00251 
00252 static struct lwip_socket_multicast_mld6_pair socket_ipv6_multicast_memberships[LWIP_SOCKET_MAX_MEMBERSHIPS];
00253 
00254 static int  lwip_socket_register_mld6_membership(int s, unsigned int if_idx, const ip6_addr_t *multi_addr);
00255 static void lwip_socket_unregister_mld6_membership(int s, unsigned int if_idx, const ip6_addr_t *multi_addr);
00256 static void lwip_socket_drop_registered_mld6_memberships(int s);
00257 #endif /* LWIP_IPV6_MLD */
00258 
00259 /** The global array of available sockets */
00260 static struct lwip_sock sockets[NUM_SOCKETS];
00261 
00262 #if LWIP_SOCKET_SELECT || LWIP_SOCKET_POLL
00263 #if LWIP_TCPIP_CORE_LOCKING
00264 /* protect the select_cb_list using core lock */
00265 #define LWIP_SOCKET_SELECT_DECL_PROTECT(lev)
00266 #define LWIP_SOCKET_SELECT_PROTECT(lev)   LOCK_TCPIP_CORE()
00267 #define LWIP_SOCKET_SELECT_UNPROTECT(lev) UNLOCK_TCPIP_CORE()
00268 #else /* LWIP_TCPIP_CORE_LOCKING */
00269 /* protect the select_cb_list using SYS_LIGHTWEIGHT_PROT */
00270 #define LWIP_SOCKET_SELECT_DECL_PROTECT(lev)  SYS_ARCH_DECL_PROTECT(lev)
00271 #define LWIP_SOCKET_SELECT_PROTECT(lev)       SYS_ARCH_PROTECT(lev)
00272 #define LWIP_SOCKET_SELECT_UNPROTECT(lev)     SYS_ARCH_UNPROTECT(lev)
00273 /** This counter is increased from lwip_select when the list is changed
00274     and checked in select_check_waiters to see if it has changed. */
00275 static volatile int select_cb_ctr;
00276 #endif /* LWIP_TCPIP_CORE_LOCKING */
00277 /** The global list of tasks waiting for select */
00278 static struct lwip_select_cb *select_cb_list;
00279 #endif /* LWIP_SOCKET_SELECT || LWIP_SOCKET_POLL */
00280 
00281 #define sock_set_errno(sk, e) do { \
00282   const int sockerr = (e); \
00283   set_errno(sockerr); \
00284 } while (0)
00285 
00286 /* Forward declaration of some functions */
00287 #if LWIP_SOCKET_SELECT || LWIP_SOCKET_POLL
00288 static void event_callback(struct netconn *conn, enum netconn_evt evt, u16_t len);
00289 #define DEFAULT_SOCKET_EVENTCB event_callback
00290 static void select_check_waiters(int s, int has_recvevent, int has_sendevent, int has_errevent);
00291 #else
00292 #define DEFAULT_SOCKET_EVENTCB NULL
00293 #endif
00294 #if !LWIP_TCPIP_CORE_LOCKING
00295 static void lwip_getsockopt_callback(void *arg);
00296 static void lwip_setsockopt_callback(void *arg);
00297 #endif
00298 static int lwip_getsockopt_impl(int s, int level, int optname, void *optval, socklen_t *optlen);
00299 static int lwip_setsockopt_impl(int s, int level, int optname, const void *optval, socklen_t optlen);
00300 static int free_socket_locked(struct lwip_sock *sock, int is_tcp, struct netconn **conn,
00301                               union lwip_sock_lastdata *lastdata);
00302 static void free_socket_free_elements(int is_tcp, struct netconn *conn, union lwip_sock_lastdata *lastdata);
00303 
00304 #if LWIP_IPV4 && LWIP_IPV6
00305 static void
00306 sockaddr_to_ipaddr_port(const struct sockaddr *sockaddr, ip_addr_t *ipaddr, u16_t *port)
00307 {
00308   if ((sockaddr->sa_family) == AF_INET6) {
00309     SOCKADDR6_TO_IP6ADDR_PORT((const struct sockaddr_in6 *)(const void *)(sockaddr), ipaddr, *port);
00310     ipaddr->type = IPADDR_TYPE_V6;
00311   } else {
00312     SOCKADDR4_TO_IP4ADDR_PORT((const struct sockaddr_in *)(const void *)(sockaddr), ipaddr, *port);
00313     ipaddr->type = IPADDR_TYPE_V4;
00314   }
00315 }
00316 #endif /* LWIP_IPV4 && LWIP_IPV6 */
00317 
00318 /** LWIP_NETCONN_SEM_PER_THREAD==1: initialize thread-local semaphore */
00319 void
00320 lwip_socket_thread_init(void)
00321 {
00322   netconn_thread_init();
00323 }
00324 
00325 /** LWIP_NETCONN_SEM_PER_THREAD==1: destroy thread-local semaphore */
00326 void
00327 lwip_socket_thread_cleanup(void)
00328 {
00329   netconn_thread_cleanup();
00330 }
00331 
00332 #if LWIP_NETCONN_FULLDUPLEX
00333 /* Thread-safe increment of sock->fd_used, with overflow check */
00334 static int
00335 sock_inc_used(struct lwip_sock *sock)
00336 {
00337   int ret;
00338   SYS_ARCH_DECL_PROTECT(lev);
00339 
00340   LWIP_ASSERT("sock != NULL", sock != NULL);
00341 
00342   SYS_ARCH_PROTECT(lev);
00343   if (sock->fd_free_pending) {
00344     /* prevent new usage of this socket if free is pending */
00345     ret = 0;
00346   } else {
00347     ++sock->fd_used;
00348     ret = 1;
00349     LWIP_ASSERT("sock->fd_used != 0", sock->fd_used != 0);
00350   }
00351   SYS_ARCH_UNPROTECT(lev);
00352   return ret;
00353 }
00354 
00355 /* Like sock_inc_used(), but called under SYS_ARCH_PROTECT lock. */
00356 static int
00357 sock_inc_used_locked(struct lwip_sock *sock)
00358 {
00359   LWIP_ASSERT("sock != NULL", sock != NULL);
00360 
00361   if (sock->fd_free_pending) {
00362     LWIP_ASSERT("sock->fd_used != 0", sock->fd_used != 0);
00363     return 0;
00364   }
00365 
00366   ++sock->fd_used;
00367   LWIP_ASSERT("sock->fd_used != 0", sock->fd_used != 0);
00368   return 1;
00369 }
00370 
00371 /* In full-duplex mode,sock->fd_used != 0 prevents a socket descriptor from being
00372  * released (and possibly reused) when used from more than one thread
00373  * (e.g. read-while-write or close-while-write, etc)
00374  * This function is called at the end of functions using (try)get_socket*().
00375  */
00376 static void
00377 done_socket(struct lwip_sock *sock)
00378 {
00379   int freed = 0;
00380   int is_tcp = 0;
00381   struct netconn *conn = NULL;
00382   union lwip_sock_lastdata lastdata;
00383   SYS_ARCH_DECL_PROTECT(lev);
00384   LWIP_ASSERT("sock != NULL", sock != NULL);
00385 
00386   SYS_ARCH_PROTECT(lev);
00387   LWIP_ASSERT("sock->fd_used > 0", sock->fd_used > 0);
00388   if (--sock->fd_used == 0) {
00389     if (sock->fd_free_pending) {
00390       /* free the socket */
00391       sock->fd_used = 1;
00392       is_tcp = sock->fd_free_pending & LWIP_SOCK_FD_FREE_TCP;
00393       freed = free_socket_locked(sock, is_tcp, &conn, &lastdata);
00394     }
00395   }
00396   SYS_ARCH_UNPROTECT(lev);
00397 
00398   if (freed) {
00399     free_socket_free_elements(is_tcp, conn, &lastdata);
00400   }
00401 }
00402 
00403 #else /* LWIP_NETCONN_FULLDUPLEX */
00404 #define sock_inc_used(sock)         1
00405 #define sock_inc_used_locked(sock)  1
00406 #define done_socket(sock)
00407 #endif /* LWIP_NETCONN_FULLDUPLEX */
00408 
00409 /* Translate a socket 'int' into a pointer (only fails if the index is invalid) */
00410 static struct lwip_sock *
00411 tryget_socket_unconn_nouse(int fd)
00412 {
00413   int s = fd - LWIP_SOCKET_OFFSET;
00414   if ((s < 0) || (s >= NUM_SOCKETS)) {
00415     LWIP_DEBUGF(SOCKETS_DEBUG, ("tryget_socket_unconn(%d): invalid\n", fd));
00416     return NULL;
00417   }
00418   return &sockets[s];
00419 }
00420 
00421 struct lwip_sock *
00422 lwip_socket_dbg_get_socket(int fd)
00423 {
00424   return tryget_socket_unconn_nouse(fd);
00425 }
00426 
00427 /* Translate a socket 'int' into a pointer (only fails if the index is invalid) */
00428 static struct lwip_sock *
00429 tryget_socket_unconn(int fd)
00430 {
00431   struct lwip_sock *ret = tryget_socket_unconn_nouse(fd);
00432   if (ret != NULL) {
00433     if (!sock_inc_used(ret)) {
00434       return NULL;
00435     }
00436   }
00437   return ret;
00438 }
00439 
00440 /* Like tryget_socket_unconn(), but called under SYS_ARCH_PROTECT lock. */
00441 static struct lwip_sock *
00442 tryget_socket_unconn_locked(int fd)
00443 {
00444   struct lwip_sock *ret = tryget_socket_unconn_nouse(fd);
00445   if (ret != NULL) {
00446     if (!sock_inc_used_locked(ret)) {
00447       return NULL;
00448     }
00449   }
00450   return ret;
00451 }
00452 
00453 /**
00454  * Same as get_socket but doesn't set errno
00455  *
00456  * @param fd externally used socket index
00457  * @return struct lwip_sock for the socket or NULL if not found
00458  */
00459 static struct lwip_sock *
00460 tryget_socket(int fd)
00461 {
00462   struct lwip_sock *sock = tryget_socket_unconn(fd);
00463   if (sock != NULL) {
00464     if (sock->conn) {
00465       return sock;
00466     }
00467     done_socket(sock);
00468   }
00469   return NULL;
00470 }
00471 
00472 /**
00473  * Map a externally used socket index to the internal socket representation.
00474  *
00475  * @param fd externally used socket index
00476  * @return struct lwip_sock for the socket or NULL if not found
00477  */
00478 static struct lwip_sock *
00479 get_socket(int fd)
00480 {
00481   struct lwip_sock *sock = tryget_socket(fd);
00482   if (!sock) {
00483     if ((fd < LWIP_SOCKET_OFFSET) || (fd >= (LWIP_SOCKET_OFFSET + NUM_SOCKETS))) {
00484       LWIP_DEBUGF(SOCKETS_DEBUG, ("get_socket(%d): invalid\n", fd));
00485     }
00486     set_errno(EBADF);
00487     return NULL;
00488   }
00489   return sock;
00490 }
00491 
00492 /**
00493  * Allocate a new socket for a given netconn.
00494  *
00495  * @param newconn the netconn for which to allocate a socket
00496  * @param accepted 1 if socket has been created by accept(),
00497  *                 0 if socket has been created by socket()
00498  * @return the index of the new socket; -1 on error
00499  */
00500 static int
00501 alloc_socket(struct netconn *newconn, int accepted)
00502 {
00503   int i;
00504   SYS_ARCH_DECL_PROTECT(lev);
00505   LWIP_UNUSED_ARG(accepted);
00506 
00507   /* allocate a new socket identifier */
00508   for (i = 0; i < NUM_SOCKETS; ++i) {
00509     /* Protect socket array */
00510     SYS_ARCH_PROTECT(lev);
00511     if (!sockets[i].conn) {
00512 #if LWIP_NETCONN_FULLDUPLEX
00513       if (sockets[i].fd_used) {
00514         SYS_ARCH_UNPROTECT(lev);
00515         continue;
00516       }
00517       sockets[i].fd_used    = 1;
00518       sockets[i].fd_free_pending = 0;
00519 #endif
00520       sockets[i].conn       = newconn;
00521       /* The socket is not yet known to anyone, so no need to protect
00522          after having marked it as used. */
00523       SYS_ARCH_UNPROTECT(lev);
00524       sockets[i].lastdata.pbuf = NULL;
00525 #if LWIP_SOCKET_SELECT || LWIP_SOCKET_POLL
00526       LWIP_ASSERT("sockets[i].select_waiting == 0", sockets[i].select_waiting == 0);
00527       sockets[i].rcvevent   = 0;
00528       /* TCP sendbuf is empty, but the socket is not yet writable until connected
00529        * (unless it has been created by accept()). */
00530       sockets[i].sendevent  = (NETCONNTYPE_GROUP(newconn->type) == NETCONN_TCP ? (accepted != 0) : 1);
00531       sockets[i].errevent   = 0;
00532 #endif /* LWIP_SOCKET_SELECT || LWIP_SOCKET_POLL */
00533       return i + LWIP_SOCKET_OFFSET;
00534     }
00535     SYS_ARCH_UNPROTECT(lev);
00536   }
00537   return -1;
00538 }
00539 
00540 /** Free a socket (under lock)
00541  *
00542  * @param sock the socket to free
00543  * @param is_tcp != 0 for TCP sockets, used to free lastdata
00544  * @param conn the socekt's netconn is stored here, must be freed externally
00545  * @param lastdata lastdata is stored here, must be freed externally
00546  */
00547 static int
00548 free_socket_locked(struct lwip_sock *sock, int is_tcp, struct netconn **conn,
00549                    union lwip_sock_lastdata *lastdata)
00550 {
00551 #if LWIP_NETCONN_FULLDUPLEX
00552   LWIP_ASSERT("sock->fd_used > 0", sock->fd_used > 0);
00553   sock->fd_used--;
00554   if (sock->fd_used > 0) {
00555     sock->fd_free_pending = LWIP_SOCK_FD_FREE_FREE | (is_tcp ? LWIP_SOCK_FD_FREE_TCP : 0);
00556     return 0;
00557   }
00558 #else /* LWIP_NETCONN_FULLDUPLEX */
00559   LWIP_UNUSED_ARG(is_tcp);
00560 #endif /* LWIP_NETCONN_FULLDUPLEX */
00561 
00562   *lastdata = sock->lastdata;
00563   sock->lastdata.pbuf = NULL;
00564   *conn = sock->conn;
00565   sock->conn = NULL;
00566   return 1;
00567 }
00568 
00569 /** Free a socket's leftover members.
00570  */
00571 static void
00572 free_socket_free_elements(int is_tcp, struct netconn *conn, union lwip_sock_lastdata *lastdata)
00573 {
00574   if (lastdata->pbuf != NULL) {
00575     if (is_tcp) {
00576       pbuf_free(lastdata->pbuf);
00577     } else {
00578       netbuf_delete(lastdata->netbuf);
00579     }
00580   }
00581   if (conn != NULL) {
00582     /* netconn_prepare_delete() has already been called, here we only free the conn */
00583     netconn_delete(conn);
00584   }
00585 }
00586 
00587 /** Free a socket. The socket's netconn must have been
00588  * delete before!
00589  *
00590  * @param sock the socket to free
00591  * @param is_tcp != 0 for TCP sockets, used to free lastdata
00592  */
00593 static void
00594 free_socket(struct lwip_sock *sock, int is_tcp)
00595 {
00596   int freed;
00597   struct netconn *conn;
00598   union lwip_sock_lastdata lastdata;
00599   SYS_ARCH_DECL_PROTECT(lev);
00600 
00601   /* Protect socket array */
00602   SYS_ARCH_PROTECT(lev);
00603 
00604   freed = free_socket_locked(sock, is_tcp, &conn, &lastdata);
00605   SYS_ARCH_UNPROTECT(lev);
00606   /* don't use 'sock' after this line, as another task might have allocated it */
00607 
00608   if (freed) {
00609     free_socket_free_elements(is_tcp, conn, &lastdata);
00610   }
00611 }
00612 
00613 /* Below this, the well-known socket functions are implemented.
00614  * Use google.com or opengroup.org to get a good description :-)
00615  *
00616  * Exceptions are documented!
00617  */
00618 
00619 int
00620 lwip_accept(int s, struct sockaddr *addr, socklen_t *addrlen)
00621 {
00622   struct lwip_sock *sock, *nsock;
00623   struct netconn *newconn;
00624   ip_addr_t naddr;
00625   u16_t port = 0;
00626   int newsock;
00627   err_t err;
00628   int recvevent;
00629   SYS_ARCH_DECL_PROTECT(lev);
00630 
00631   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d)...\n", s));
00632   sock = get_socket(s);
00633   if (!sock) {
00634     return -1;
00635   }
00636 
00637   /* wait for a new connection */
00638   err = netconn_accept(sock->conn, &newconn);
00639   if (err != ERR_OK) {
00640     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d): netconn_acept failed, err=%d\n", s, err));
00641     if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_TCP) {
00642       sock_set_errno(sock, EOPNOTSUPP);
00643     } else if (err == ERR_CLSD) {
00644       sock_set_errno(sock, EINVAL);
00645     } else {
00646       sock_set_errno(sock, err_to_errno(err));
00647     }
00648     done_socket(sock);
00649     return -1;
00650   }
00651   LWIP_ASSERT("newconn != NULL", newconn != NULL);
00652 
00653   newsock = alloc_socket(newconn, 1);
00654   if (newsock == -1) {
00655     netconn_delete(newconn);
00656     sock_set_errno(sock, ENFILE);
00657     done_socket(sock);
00658     return -1;
00659   }
00660   LWIP_ASSERT("invalid socket index", (newsock >= LWIP_SOCKET_OFFSET) && (newsock < NUM_SOCKETS + LWIP_SOCKET_OFFSET));
00661   nsock = &sockets[newsock - LWIP_SOCKET_OFFSET];
00662 
00663   /* See event_callback: If data comes in right away after an accept, even
00664    * though the server task might not have created a new socket yet.
00665    * In that case, newconn->socket is counted down (newconn->socket--),
00666    * so nsock->rcvevent is >= 1 here!
00667    */
00668   SYS_ARCH_PROTECT(lev);
00669   recvevent = (s16_t)(-1 - newconn->socket);
00670   newconn->socket = newsock;
00671   SYS_ARCH_UNPROTECT(lev);
00672 
00673   if (newconn->callback) {
00674     LOCK_TCPIP_CORE();
00675     while (recvevent > 0) {
00676       recvevent--;
00677       newconn->callback(newconn, NETCONN_EVT_RCVPLUS, 0);
00678     }
00679     UNLOCK_TCPIP_CORE();
00680   }
00681 
00682   /* Note that POSIX only requires us to check addr is non-NULL. addrlen must
00683    * not be NULL if addr is valid.
00684    */
00685   if ((addr != NULL) && (addrlen != NULL)) {
00686     union sockaddr_aligned tempaddr;
00687     /* get the IP address and port of the remote host */
00688     err = netconn_peer(newconn, &naddr, &port);
00689     if (err != ERR_OK) {
00690       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d): netconn_peer failed, err=%d\n", s, err));
00691       netconn_delete(newconn);
00692       free_socket(nsock, 1);
00693       sock_set_errno(sock, err_to_errno(err));
00694       done_socket(sock);
00695       return -1;
00696     }
00697 
00698     IPADDR_PORT_TO_SOCKADDR(&tempaddr, &naddr, port);
00699     if (*addrlen > tempaddr.sa.sa_len) {
00700       *addrlen = tempaddr.sa.sa_len;
00701     }
00702     MEMCPY(addr, &tempaddr, *addrlen);
00703 
00704     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d) returning new sock=%d addr=", s, newsock));
00705     ip_addr_debug_print_val(SOCKETS_DEBUG, naddr);
00706     LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F"\n", port));
00707   } else {
00708     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d) returning new sock=%d", s, newsock));
00709   }
00710 
00711   sock_set_errno(sock, 0);
00712   done_socket(sock);
00713   done_socket(nsock);
00714   return newsock;
00715 }
00716 
00717 int
00718 lwip_bind(int s, const struct sockaddr *name, socklen_t namelen)
00719 {
00720   struct lwip_sock *sock;
00721   ip_addr_t local_addr;
00722   u16_t local_port;
00723   err_t err;
00724 
00725   sock = get_socket(s);
00726   if (!sock) {
00727     return -1;
00728   }
00729 
00730   if (!SOCK_ADDR_TYPE_MATCH(name, sock)) {
00731     /* sockaddr does not match socket type (IPv4/IPv6) */
00732     sock_set_errno(sock, err_to_errno(ERR_VAL));
00733     done_socket(sock);
00734     return -1;
00735   }
00736 
00737   /* check size, family and alignment of 'name' */
00738   LWIP_ERROR("lwip_bind: invalid address", (IS_SOCK_ADDR_LEN_VALID(namelen) &&
00739              IS_SOCK_ADDR_TYPE_VALID(name) && IS_SOCK_ADDR_ALIGNED(name)),
00740              sock_set_errno(sock, err_to_errno(ERR_ARG)); done_socket(sock); return -1;);
00741   LWIP_UNUSED_ARG(namelen);
00742 
00743   SOCKADDR_TO_IPADDR_PORT(name, &local_addr, local_port);
00744   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d, addr=", s));
00745   ip_addr_debug_print_val(SOCKETS_DEBUG, local_addr);
00746   LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F")\n", local_port));
00747 
00748 #if LWIP_IPV4 && LWIP_IPV6
00749   /* Dual-stack: Unmap IPv4 mapped IPv6 addresses */
00750   if (IP_IS_V6_VAL(local_addr) && ip6_addr_isipv4mappedipv6(ip_2_ip6(&local_addr))) {
00751     unmap_ipv4_mapped_ipv6(ip_2_ip4(&local_addr), ip_2_ip6(&local_addr));
00752     IP_SET_TYPE_VAL(local_addr, IPADDR_TYPE_V4);
00753   }
00754 #endif /* LWIP_IPV4 && LWIP_IPV6 */
00755 
00756   err = netconn_bind(sock->conn, &local_addr, local_port);
00757 
00758   if (err != ERR_OK) {
00759     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d) failed, err=%d\n", s, err));
00760     sock_set_errno(sock, err_to_errno(err));
00761     done_socket(sock);
00762     return -1;
00763   }
00764 
00765   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d) succeeded\n", s));
00766   sock_set_errno(sock, 0);
00767   done_socket(sock);
00768   return 0;
00769 }
00770 
00771 int
00772 lwip_close(int s)
00773 {
00774   struct lwip_sock *sock;
00775   int is_tcp = 0;
00776   err_t err;
00777 
00778   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_close(%d)\n", s));
00779 
00780   sock = get_socket(s);
00781   if (!sock) {
00782     return -1;
00783   }
00784 
00785   if (sock->conn != NULL) {
00786     is_tcp = NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP;
00787   } else {
00788     LWIP_ASSERT("sock->lastdata == NULL", sock->lastdata.pbuf == NULL);
00789   }
00790 
00791 #if LWIP_IGMP
00792   /* drop all possibly joined IGMP memberships */
00793   lwip_socket_drop_registered_memberships(s);
00794 #endif /* LWIP_IGMP */
00795 #if LWIP_IPV6_MLD
00796   /* drop all possibly joined MLD6 memberships */
00797   lwip_socket_drop_registered_mld6_memberships(s);
00798 #endif /* LWIP_IPV6_MLD */
00799 
00800   err = netconn_prepare_delete(sock->conn);
00801   if (err != ERR_OK) {
00802     sock_set_errno(sock, err_to_errno(err));
00803     done_socket(sock);
00804     return -1;
00805   }
00806 
00807   free_socket(sock, is_tcp);
00808   set_errno(0);
00809   return 0;
00810 }
00811 
00812 int
00813 lwip_connect(int s, const struct sockaddr *name, socklen_t namelen)
00814 {
00815   struct lwip_sock *sock;
00816   err_t err;
00817 
00818   sock = get_socket(s);
00819   if (!sock) {
00820     return -1;
00821   }
00822 
00823   if (!SOCK_ADDR_TYPE_MATCH_OR_UNSPEC(name, sock)) {
00824     /* sockaddr does not match socket type (IPv4/IPv6) */
00825     sock_set_errno(sock, err_to_errno(ERR_VAL));
00826     done_socket(sock);
00827     return -1;
00828   }
00829 
00830   LWIP_UNUSED_ARG(namelen);
00831   if (name->sa_family == AF_UNSPEC) {
00832     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d, AF_UNSPEC)\n", s));
00833     err = netconn_disconnect(sock->conn);
00834   } else {
00835     ip_addr_t remote_addr;
00836     u16_t remote_port;
00837 
00838     /* check size, family and alignment of 'name' */
00839     LWIP_ERROR("lwip_connect: invalid address", IS_SOCK_ADDR_LEN_VALID(namelen) &&
00840                IS_SOCK_ADDR_TYPE_VALID_OR_UNSPEC(name) && IS_SOCK_ADDR_ALIGNED(name),
00841                sock_set_errno(sock, err_to_errno(ERR_ARG)); done_socket(sock); return -1;);
00842 
00843     SOCKADDR_TO_IPADDR_PORT(name, &remote_addr, remote_port);
00844     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d, addr=", s));
00845     ip_addr_debug_print_val(SOCKETS_DEBUG, remote_addr);
00846     LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F")\n", remote_port));
00847 
00848 #if LWIP_IPV4 && LWIP_IPV6
00849     /* Dual-stack: Unmap IPv4 mapped IPv6 addresses */
00850     if (IP_IS_V6_VAL(remote_addr) && ip6_addr_isipv4mappedipv6(ip_2_ip6(&remote_addr))) {
00851       unmap_ipv4_mapped_ipv6(ip_2_ip4(&remote_addr), ip_2_ip6(&remote_addr));
00852       IP_SET_TYPE_VAL(remote_addr, IPADDR_TYPE_V4);
00853     }
00854 #endif /* LWIP_IPV4 && LWIP_IPV6 */
00855 
00856     err = netconn_connect(sock->conn, &remote_addr, remote_port);
00857   }
00858 
00859   if (err != ERR_OK) {
00860     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d) failed, err=%d\n", s, err));
00861     sock_set_errno(sock, err_to_errno(err));
00862     done_socket(sock);
00863     return -1;
00864   }
00865 
00866   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d) succeeded\n", s));
00867   sock_set_errno(sock, 0);
00868   done_socket(sock);
00869   return 0;
00870 }
00871 
00872 /**
00873  * Set a socket into listen mode.
00874  * The socket may not have been used for another connection previously.
00875  *
00876  * @param s the socket to set to listening mode
00877  * @param backlog (ATTENTION: needs TCP_LISTEN_BACKLOG=1)
00878  * @return 0 on success, non-zero on failure
00879  */
00880 int
00881 lwip_listen(int s, int backlog)
00882 {
00883   struct lwip_sock *sock;
00884   err_t err;
00885 
00886   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_listen(%d, backlog=%d)\n", s, backlog));
00887 
00888   sock = get_socket(s);
00889   if (!sock) {
00890     return -1;
00891   }
00892 
00893   /* limit the "backlog" parameter to fit in an u8_t */
00894   backlog = LWIP_MIN(LWIP_MAX(backlog, 0), 0xff);
00895 
00896   err = netconn_listen_with_backlog(sock->conn, (u8_t)backlog);
00897 
00898   if (err != ERR_OK) {
00899     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_listen(%d) failed, err=%d\n", s, err));
00900     if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_TCP) {
00901       sock_set_errno(sock, EOPNOTSUPP);
00902     } else {
00903       sock_set_errno(sock, err_to_errno(err));
00904     }
00905     done_socket(sock);
00906     return -1;
00907   }
00908 
00909   sock_set_errno(sock, 0);
00910   done_socket(sock);
00911   return 0;
00912 }
00913 
00914 #if LWIP_TCP
00915 /* Helper function to loop over receiving pbufs from netconn
00916  * until "len" bytes are received or we're otherwise done.
00917  * Keeps sock->lastdata for peeking or partly copying.
00918  */
00919 static ssize_t
00920 lwip_recv_tcp(struct lwip_sock *sock, void *mem, size_t len, int flags)
00921 {
00922   u8_t apiflags = NETCONN_NOAUTORCVD;
00923   ssize_t recvd = 0;
00924   ssize_t recv_left = (len <= SSIZE_MAX) ? (ssize_t)len : SSIZE_MAX;
00925 
00926   LWIP_ASSERT("no socket given", sock != NULL);
00927   LWIP_ASSERT("this should be checked internally", NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP);
00928 
00929   if (flags & MSG_DONTWAIT) {
00930     apiflags |= NETCONN_DONTBLOCK;
00931   }
00932 
00933   do {
00934     struct pbuf *p;
00935     err_t err;
00936     u16_t copylen;
00937 
00938     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recv_tcp: top while sock->lastdata=%p\n", (void *)sock->lastdata.pbuf));
00939     /* Check if there is data left from the last recv operation. */
00940     if (sock->lastdata.pbuf) {
00941       p = sock->lastdata.pbuf;
00942     } else {
00943       /* No data was left from the previous operation, so we try to get
00944          some from the network. */
00945       err = netconn_recv_tcp_pbuf_flags(sock->conn, &p, apiflags);
00946       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recv_tcp: netconn_recv err=%d, pbuf=%p\n",
00947                                   err, (void *)p));
00948 
00949       if (err != ERR_OK) {
00950         if (recvd > 0) {
00951           /* already received data, return that (this trusts in getting the same error from
00952              netconn layer again next time netconn_recv is called) */
00953           goto lwip_recv_tcp_done;
00954         }
00955         /* We should really do some error checking here. */
00956         LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recv_tcp: p == NULL, error is \"%s\"!\n",
00957                                     lwip_strerr(err)));
00958         sock_set_errno(sock, err_to_errno(err));
00959         if (err == ERR_CLSD) {
00960           return 0;
00961         } else {
00962           return -1;
00963         }
00964       }
00965       LWIP_ASSERT("p != NULL", p != NULL);
00966       sock->lastdata.pbuf = p;
00967     }
00968 
00969     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recv_tcp: buflen=%"U16_F" recv_left=%d off=%d\n",
00970                                 p->tot_len, (int)recv_left, (int)recvd));
00971 
00972     if (recv_left > p->tot_len) {
00973       copylen = p->tot_len;
00974     } else {
00975       copylen = (u16_t)recv_left;
00976     }
00977     if (recvd + copylen < recvd) {
00978       /* overflow */
00979       copylen = (u16_t)(SSIZE_MAX - recvd);
00980     }
00981 
00982     /* copy the contents of the received buffer into
00983     the supplied memory pointer mem */
00984     pbuf_copy_partial(p, (u8_t *)mem + recvd, copylen, 0);
00985 
00986     recvd += copylen;
00987 
00988     /* TCP combines multiple pbufs for one recv */
00989     LWIP_ASSERT("invalid copylen, len would underflow", recv_left >= copylen);
00990     recv_left -= copylen;
00991 
00992     /* Unless we peek the incoming message... */
00993     if ((flags & MSG_PEEK) == 0) {
00994       /* ... check if there is data left in the pbuf */
00995       LWIP_ASSERT("invalid copylen", p->tot_len >= copylen);
00996       if (p->tot_len - copylen > 0) {
00997         /* If so, it should be saved in the sock structure for the next recv call.
00998            We store the pbuf but hide/free the consumed data: */
00999         sock->lastdata.pbuf = pbuf_free_header(p, copylen);
01000         LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recv_tcp: lastdata now pbuf=%p\n", (void *)sock->lastdata.pbuf));
01001       } else {
01002         sock->lastdata.pbuf = NULL;
01003         LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recv_tcp: deleting pbuf=%p\n", (void *)p));
01004         pbuf_free(p);
01005       }
01006     }
01007     /* once we have some data to return, only add more if we don't need to wait */
01008     apiflags |= NETCONN_DONTBLOCK | NETCONN_NOFIN;
01009     /* @todo: do we need to support peeking more than one pbuf? */
01010   } while ((recv_left > 0) && !(flags & MSG_PEEK));
01011 lwip_recv_tcp_done:
01012   if ((recvd > 0) && !(flags & MSG_PEEK)) {
01013     /* ensure window update after copying all data */
01014     netconn_tcp_recvd(sock->conn, (size_t)recvd);
01015   }
01016   sock_set_errno(sock, 0);
01017   return recvd;
01018 }
01019 #endif
01020 
01021 /* Convert a netbuf's address data to struct sockaddr */
01022 static int
01023 lwip_sock_make_addr(struct netconn *conn, ip_addr_t *fromaddr, u16_t port,
01024                     struct sockaddr *from, socklen_t *fromlen)
01025 {
01026   int truncated = 0;
01027   union sockaddr_aligned saddr;
01028 
01029   LWIP_UNUSED_ARG(conn);
01030 
01031   LWIP_ASSERT("fromaddr != NULL", fromaddr != NULL);
01032   LWIP_ASSERT("from != NULL", from != NULL);
01033   LWIP_ASSERT("fromlen != NULL", fromlen != NULL);
01034 
01035 #if LWIP_IPV4 && LWIP_IPV6
01036   /* Dual-stack: Map IPv4 addresses to IPv4 mapped IPv6 */
01037   if (NETCONNTYPE_ISIPV6(netconn_type(conn)) && IP_IS_V4(fromaddr)) {
01038     ip4_2_ipv4_mapped_ipv6(ip_2_ip6(fromaddr), ip_2_ip4(fromaddr));
01039     IP_SET_TYPE(fromaddr, IPADDR_TYPE_V6);
01040   }
01041 #endif /* LWIP_IPV4 && LWIP_IPV6 */
01042 
01043   IPADDR_PORT_TO_SOCKADDR(&saddr, fromaddr, port);
01044   if (*fromlen < saddr.sa.sa_len) {
01045     truncated = 1;
01046   } else if (*fromlen > saddr.sa.sa_len) {
01047     *fromlen = saddr.sa.sa_len;
01048   }
01049   MEMCPY(from, &saddr, *fromlen);
01050   return truncated;
01051 }
01052 
01053 #if LWIP_TCP
01054 /* Helper function to get a tcp socket's remote address info */
01055 static int
01056 lwip_recv_tcp_from(struct lwip_sock *sock, struct sockaddr *from, socklen_t *fromlen, const char *dbg_fn, int dbg_s, ssize_t dbg_ret)
01057 {
01058   if (sock == NULL) {
01059     return 0;
01060   }
01061   LWIP_UNUSED_ARG(dbg_fn);
01062   LWIP_UNUSED_ARG(dbg_s);
01063   LWIP_UNUSED_ARG(dbg_ret);
01064 
01065 #if !SOCKETS_DEBUG
01066   if (from && fromlen)
01067 #endif /* !SOCKETS_DEBUG */
01068   {
01069     /* get remote addr/port from tcp_pcb */
01070     u16_t port;
01071     ip_addr_t tmpaddr;
01072     netconn_getaddr(sock->conn, &tmpaddr, &port, 0);
01073     LWIP_DEBUGF(SOCKETS_DEBUG, ("%s(%d):  addr=", dbg_fn, dbg_s));
01074     ip_addr_debug_print_val(SOCKETS_DEBUG, tmpaddr);
01075     LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F" len=%d\n", port, (int)dbg_ret));
01076     if (from && fromlen) {
01077       return lwip_sock_make_addr(sock->conn, &tmpaddr, port, from, fromlen);
01078     }
01079   }
01080   return 0;
01081 }
01082 #endif
01083 
01084 /* Helper function to receive a netbuf from a udp or raw netconn.
01085  * Keeps sock->lastdata for peeking.
01086  */
01087 static err_t
01088 lwip_recvfrom_udp_raw(struct lwip_sock *sock, int flags, struct msghdr *msg, u16_t *datagram_len, int dbg_s)
01089 {
01090   struct netbuf *buf;
01091   u8_t apiflags;
01092   err_t err;
01093   u16_t buflen, copylen, copied;
01094   int i;
01095 
01096   LWIP_UNUSED_ARG(dbg_s);
01097   LWIP_ERROR("lwip_recvfrom_udp_raw: invalid arguments", (msg->msg_iov != NULL) || (msg->msg_iovlen <= 0), return ERR_ARG;);
01098 
01099   if (flags & MSG_DONTWAIT) {
01100     apiflags = NETCONN_DONTBLOCK;
01101   } else {
01102     apiflags = 0;
01103   }
01104 
01105   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom_udp_raw[UDP/RAW]: top sock->lastdata=%p\n", (void *)sock->lastdata.netbuf));
01106   /* Check if there is data left from the last recv operation. */
01107   buf = sock->lastdata.netbuf;
01108   if (buf == NULL) {
01109     /* No data was left from the previous operation, so we try to get
01110         some from the network. */
01111     err = netconn_recv_udp_raw_netbuf_flags(sock->conn, &buf, apiflags);
01112     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom_udp_raw[UDP/RAW]: netconn_recv err=%d, netbuf=%p\n",
01113                                 err, (void *)buf));
01114 
01115     if (err != ERR_OK) {
01116       return err;
01117     }
01118     LWIP_ASSERT("buf != NULL", buf != NULL);
01119     sock->lastdata.netbuf = buf;
01120   }
01121   buflen = buf->p->tot_len;
01122   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom_udp_raw: buflen=%"U16_F"\n", buflen));
01123 
01124   copied = 0;
01125   /* copy the pbuf payload into the iovs */
01126   for (i = 0; (i < msg->msg_iovlen) && (copied < buflen); i++) {
01127     u16_t len_left = (u16_t)(buflen - copied);
01128     if (msg->msg_iov[i].iov_len > len_left) {
01129       copylen = len_left;
01130     } else {
01131       copylen = (u16_t)msg->msg_iov[i].iov_len;
01132     }
01133 
01134     /* copy the contents of the received buffer into
01135         the supplied memory buffer */
01136     pbuf_copy_partial(buf->p, (u8_t *)msg->msg_iov[i].iov_base, copylen, copied);
01137     copied = (u16_t)(copied + copylen);
01138   }
01139 
01140   /* Check to see from where the data was.*/
01141 #if !SOCKETS_DEBUG
01142   if (msg->msg_name && msg->msg_namelen)
01143 #endif /* !SOCKETS_DEBUG */
01144   {
01145     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom_udp_raw(%d):  addr=", dbg_s));
01146     ip_addr_debug_print_val(SOCKETS_DEBUG, *netbuf_fromaddr(buf));
01147     LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F" len=%d\n", netbuf_fromport(buf), copied));
01148     if (msg->msg_name && msg->msg_namelen) {
01149       lwip_sock_make_addr(sock->conn, netbuf_fromaddr(buf), netbuf_fromport(buf),
01150                           (struct sockaddr *)msg->msg_name, &msg->msg_namelen);
01151     }
01152   }
01153 
01154   /* Initialize flag output */
01155   msg->msg_flags = 0;
01156 
01157   if (msg->msg_control) {
01158     u8_t wrote_msg = 0;
01159 #if LWIP_NETBUF_RECVINFO
01160     /* Check if packet info was recorded */
01161     if (buf->flags & NETBUF_FLAG_DESTADDR) {
01162       if (IP_IS_V4(&buf->toaddr)) {
01163 #if LWIP_IPV4
01164         if (msg->msg_controllen >= CMSG_SPACE(sizeof(struct in_pktinfo))) {
01165           struct cmsghdr *chdr = CMSG_FIRSTHDR(msg); /* This will always return a header!! */
01166           struct in_pktinfo *pkti = (struct in_pktinfo *)CMSG_DATA(chdr);
01167           chdr->cmsg_level = IPPROTO_IP;
01168           chdr->cmsg_type = IP_PKTINFO;
01169           chdr->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
01170           pkti->ipi_ifindex = buf->p->if_idx;
01171           inet_addr_from_ip4addr(&pkti->ipi_addr, ip_2_ip4(netbuf_destaddr(buf)));
01172           msg->msg_controllen = CMSG_SPACE(sizeof(struct in_pktinfo));
01173           wrote_msg = 1;
01174         } else {
01175           msg->msg_flags |= MSG_CTRUNC;
01176         }
01177 #endif /* LWIP_IPV4 */
01178       }
01179     }
01180 #endif /* LWIP_NETBUF_RECVINFO */
01181 
01182     if (!wrote_msg) {
01183       msg->msg_controllen = 0;
01184     }
01185   }
01186 
01187   /* If we don't peek the incoming message: zero lastdata pointer and free the netbuf */
01188   if ((flags & MSG_PEEK) == 0) {
01189     sock->lastdata.netbuf = NULL;
01190     netbuf_delete(buf);
01191   }
01192   if (datagram_len) {
01193     *datagram_len = buflen;
01194   }
01195   return ERR_OK;
01196 }
01197 
01198 ssize_t
01199 lwip_recvfrom(int s, void *mem, size_t len, int flags,
01200               struct sockaddr *from, socklen_t *fromlen)
01201 {
01202   struct lwip_sock *sock;
01203   ssize_t ret;
01204 
01205   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d, %p, %"SZT_F", 0x%x, ..)\n", s, mem, len, flags));
01206   sock = get_socket(s);
01207   if (!sock) {
01208     return -1;
01209   }
01210 #if LWIP_TCP
01211   if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) {
01212     ret = lwip_recv_tcp(sock, mem, len, flags);
01213     lwip_recv_tcp_from(sock, from, fromlen, "lwip_recvfrom", s, ret);
01214     done_socket(sock);
01215     return ret;
01216   } else
01217 #endif
01218   {
01219     u16_t datagram_len = 0;
01220     struct iovec vec;
01221     struct msghdr msg;
01222     err_t err;
01223     vec.iov_base = mem;
01224     vec.iov_len = len;
01225     msg.msg_control = NULL;
01226     msg.msg_controllen = 0;
01227     msg.msg_flags = 0;
01228     msg.msg_iov = &vec;
01229     msg.msg_iovlen = 1;
01230     msg.msg_name = from;
01231     msg.msg_namelen = (fromlen ? *fromlen : 0);
01232     err = lwip_recvfrom_udp_raw(sock, flags, &msg, &datagram_len, s);
01233     if (err != ERR_OK) {
01234       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom[UDP/RAW](%d): buf == NULL, error is \"%s\"!\n",
01235                                   s, lwip_strerr(err)));
01236       sock_set_errno(sock, err_to_errno(err));
01237       done_socket(sock);
01238       return -1;
01239     }
01240     ret = (ssize_t)LWIP_MIN(LWIP_MIN(len, datagram_len), SSIZE_MAX);
01241     if (fromlen) {
01242       *fromlen = msg.msg_namelen;
01243     }
01244   }
01245 
01246   sock_set_errno(sock, 0);
01247   done_socket(sock);
01248   return ret;
01249 }
01250 
01251 ssize_t
01252 lwip_read(int s, void *mem, size_t len)
01253 {
01254   return lwip_recvfrom(s, mem, len, 0, NULL, NULL);
01255 }
01256 
01257 ssize_t
01258 lwip_readv(int s, const struct iovec *iov, int iovcnt)
01259 {
01260   struct msghdr msg;
01261 
01262   msg.msg_name = NULL;
01263   msg.msg_namelen = 0;
01264   /* Hack: we have to cast via number to cast from 'const' pointer to non-const.
01265      Blame the opengroup standard for this inconsistency. */
01266   msg.msg_iov = LWIP_CONST_CAST(struct iovec *, iov);
01267   msg.msg_iovlen = iovcnt;
01268   msg.msg_control = NULL;
01269   msg.msg_controllen = 0;
01270   msg.msg_flags = 0;
01271   return lwip_recvmsg(s, &msg, 0);
01272 }
01273 
01274 ssize_t
01275 lwip_recv(int s, void *mem, size_t len, int flags)
01276 {
01277   return lwip_recvfrom(s, mem, len, flags, NULL, NULL);
01278 }
01279 
01280 ssize_t
01281 lwip_recvmsg(int s, struct msghdr *message, int flags)
01282 {
01283   struct lwip_sock *sock;
01284   int i;
01285   ssize_t buflen;
01286 
01287   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvmsg(%d, message=%p, flags=0x%x)\n", s, (void *)message, flags));
01288   LWIP_ERROR("lwip_recvmsg: invalid message pointer", message != NULL, return ERR_ARG;);
01289   LWIP_ERROR("lwip_recvmsg: unsupported flags", (flags & ~(MSG_PEEK|MSG_DONTWAIT)) == 0,
01290              set_errno(EOPNOTSUPP); return -1;);
01291 
01292   if ((message->msg_iovlen <= 0) || (message->msg_iovlen > IOV_MAX)) {
01293     set_errno(EMSGSIZE);
01294     return -1;
01295   }
01296 
01297   sock = get_socket(s);
01298   if (!sock) {
01299     return -1;
01300   }
01301 
01302   /* check for valid vectors */
01303   buflen = 0;
01304   for (i = 0; i < message->msg_iovlen; i++) {
01305     if ((message->msg_iov[i].iov_base == NULL) || ((ssize_t)message->msg_iov[i].iov_len <= 0) ||
01306         ((size_t)(ssize_t)message->msg_iov[i].iov_len != message->msg_iov[i].iov_len) ||
01307         ((ssize_t)(buflen + (ssize_t)message->msg_iov[i].iov_len) <= 0)) {
01308       sock_set_errno(sock, err_to_errno(ERR_VAL));
01309       done_socket(sock);
01310       return -1;
01311     }
01312     buflen = (ssize_t)(buflen + (ssize_t)message->msg_iov[i].iov_len);
01313   }
01314 
01315   if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) {
01316 #if LWIP_TCP
01317     int recv_flags = flags;
01318     message->msg_flags = 0;
01319     /* recv the data */
01320     buflen = 0;
01321     for (i = 0; i < message->msg_iovlen; i++) {
01322       /* try to receive into this vector's buffer */
01323       ssize_t recvd_local = lwip_recv_tcp(sock, message->msg_iov[i].iov_base, message->msg_iov[i].iov_len, recv_flags);
01324       if (recvd_local > 0) {
01325         /* sum up received bytes */
01326         buflen += recvd_local;
01327       }
01328       if ((recvd_local < 0) || (recvd_local < (int)message->msg_iov[i].iov_len) ||
01329           (flags & MSG_PEEK)) {
01330         /* returned prematurely (or peeking, which might actually be limitated to the first iov) */
01331         if (buflen <= 0) {
01332           /* nothing received at all, propagate the error */
01333           buflen = recvd_local;
01334         }
01335         break;
01336       }
01337       /* pass MSG_DONTWAIT to lwip_recv_tcp() to prevent waiting for more data */
01338       recv_flags |= MSG_DONTWAIT;
01339     }
01340     if (buflen > 0) {
01341       /* reset socket error since we have received something */
01342       sock_set_errno(sock, 0);
01343     }
01344     /* " If the socket is connected, the msg_name and msg_namelen members shall be ignored." */
01345     done_socket(sock);
01346     return buflen;
01347 #else /* LWIP_TCP */
01348     sock_set_errno(sock, err_to_errno(ERR_ARG));
01349     done_socket(sock);
01350     return -1;
01351 #endif /* LWIP_TCP */
01352   }
01353   /* else, UDP and RAW NETCONNs */
01354 #if LWIP_UDP || LWIP_RAW
01355   {
01356     u16_t datagram_len = 0;
01357     err_t err;
01358     err = lwip_recvfrom_udp_raw(sock, flags, message, &datagram_len, s);
01359     if (err != ERR_OK) {
01360       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvmsg[UDP/RAW](%d): buf == NULL, error is \"%s\"!\n",
01361                                   s, lwip_strerr(err)));
01362       sock_set_errno(sock, err_to_errno(err));
01363       done_socket(sock);
01364       return -1;
01365     }
01366     if (datagram_len > buflen) {
01367       message->msg_flags |= MSG_TRUNC;
01368     }
01369 
01370     sock_set_errno(sock, 0);
01371     done_socket(sock);
01372     return (int)datagram_len;
01373   }
01374 #else /* LWIP_UDP || LWIP_RAW */
01375   sock_set_errno(sock, err_to_errno(ERR_ARG));
01376   done_socket(sock);
01377   return -1;
01378 #endif /* LWIP_UDP || LWIP_RAW */
01379 }
01380 
01381 ssize_t
01382 lwip_send(int s, const void *data, size_t size, int flags)
01383 {
01384   struct lwip_sock *sock;
01385   err_t err;
01386   u8_t write_flags;
01387   size_t written;
01388 
01389   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_send(%d, data=%p, size=%"SZT_F", flags=0x%x)\n",
01390                               s, data, size, flags));
01391 
01392   sock = get_socket(s);
01393   if (!sock) {
01394     return -1;
01395   }
01396 
01397   if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_TCP) {
01398 #if (LWIP_UDP || LWIP_RAW)
01399     done_socket(sock);
01400     return lwip_sendto(s, data, size, flags, NULL, 0);
01401 #else /* (LWIP_UDP || LWIP_RAW) */
01402     sock_set_errno(sock, err_to_errno(ERR_ARG));
01403     done_socket(sock);
01404     return -1;
01405 #endif /* (LWIP_UDP || LWIP_RAW) */
01406   }
01407 
01408   write_flags = (u8_t)(NETCONN_COPY |
01409                        ((flags & MSG_MORE)     ? NETCONN_MORE      : 0) |
01410                        ((flags & MSG_DONTWAIT) ? NETCONN_DONTBLOCK : 0));
01411   written = 0;
01412   err = netconn_write_partly(sock->conn, data, size, write_flags, &written);
01413 
01414   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_send(%d) err=%d written=%"SZT_F"\n", s, err, written));
01415   sock_set_errno(sock, err_to_errno(err));
01416   done_socket(sock);
01417   /* casting 'written' to ssize_t is OK here since the netconn API limits it to SSIZE_MAX */
01418   return (err == ERR_OK ? (ssize_t)written : -1);
01419 }
01420 
01421 ssize_t
01422 lwip_sendmsg(int s, const struct msghdr *msg, int flags)
01423 {
01424   struct lwip_sock *sock;
01425 #if LWIP_TCP
01426   u8_t write_flags;
01427   size_t written;
01428 #endif
01429   err_t err = ERR_OK;
01430 
01431   sock = get_socket(s);
01432   if (!sock) {
01433     return -1;
01434   }
01435 
01436   LWIP_ERROR("lwip_sendmsg: invalid msghdr", msg != NULL,
01437              sock_set_errno(sock, err_to_errno(ERR_ARG)); done_socket(sock); return -1;);
01438   LWIP_ERROR("lwip_sendmsg: invalid msghdr iov", msg->msg_iov != NULL,
01439              sock_set_errno(sock, err_to_errno(ERR_ARG)); done_socket(sock); return -1;);
01440   LWIP_ERROR("lwip_sendmsg: maximum iovs exceeded", (msg->msg_iovlen > 0) && (msg->msg_iovlen <= IOV_MAX),
01441              sock_set_errno(sock, EMSGSIZE); done_socket(sock); return -1;);
01442   LWIP_ERROR("lwip_sendmsg: unsupported flags", (flags & ~(MSG_DONTWAIT | MSG_MORE)) == 0,
01443              sock_set_errno(sock, EOPNOTSUPP); done_socket(sock); return -1;);
01444 
01445   LWIP_UNUSED_ARG(msg->msg_control);
01446   LWIP_UNUSED_ARG(msg->msg_controllen);
01447   LWIP_UNUSED_ARG(msg->msg_flags);
01448 
01449   if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) {
01450 #if LWIP_TCP
01451     write_flags = (u8_t)(NETCONN_COPY |
01452                          ((flags & MSG_MORE)     ? NETCONN_MORE      : 0) |
01453                          ((flags & MSG_DONTWAIT) ? NETCONN_DONTBLOCK : 0));
01454 
01455     written = 0;
01456     err = netconn_write_vectors_partly(sock->conn, (struct netvector *)msg->msg_iov, (u16_t)msg->msg_iovlen, write_flags, &written);
01457     sock_set_errno(sock, err_to_errno(err));
01458     done_socket(sock);
01459     /* casting 'written' to ssize_t is OK here since the netconn API limits it to SSIZE_MAX */
01460     return (err == ERR_OK ? (ssize_t)written : -1);
01461 #else /* LWIP_TCP */
01462     sock_set_errno(sock, err_to_errno(ERR_ARG));
01463     done_socket(sock);
01464     return -1;
01465 #endif /* LWIP_TCP */
01466   }
01467   /* else, UDP and RAW NETCONNs */
01468 #if LWIP_UDP || LWIP_RAW
01469   {
01470     struct netbuf chain_buf;
01471     int i;
01472     ssize_t size = 0;
01473 
01474     LWIP_UNUSED_ARG(flags);
01475     LWIP_ERROR("lwip_sendmsg: invalid msghdr name", (((msg->msg_name == NULL) && (msg->msg_namelen == 0)) ||
01476                IS_SOCK_ADDR_LEN_VALID(msg->msg_namelen)),
01477                sock_set_errno(sock, err_to_errno(ERR_ARG)); done_socket(sock); return -1;);
01478 
01479     /* initialize chain buffer with destination */
01480     memset(&chain_buf, 0, sizeof(struct netbuf));
01481     if (msg->msg_name) {
01482       u16_t remote_port;
01483       SOCKADDR_TO_IPADDR_PORT((const struct sockaddr *)msg->msg_name, &chain_buf.addr, remote_port);
01484       netbuf_fromport(&chain_buf) = remote_port;
01485     }
01486 #if LWIP_NETIF_TX_SINGLE_PBUF
01487     for (i = 0; i < msg->msg_iovlen; i++) {
01488       size += msg->msg_iov[i].iov_len;
01489       if ((msg->msg_iov[i].iov_len > INT_MAX) || (size < (int)msg->msg_iov[i].iov_len)) {
01490         /* overflow */
01491         goto sendmsg_emsgsize;
01492       }
01493     }
01494     if (size > 0xFFFF) {
01495       /* overflow */
01496       goto sendmsg_emsgsize;
01497     }
01498     /* Allocate a new netbuf and copy the data into it. */
01499     if (netbuf_alloc(&chain_buf, (u16_t)size) == NULL) {
01500       err = ERR_MEM;
01501     } else {
01502       /* flatten the IO vectors */
01503       size_t offset = 0;
01504       for (i = 0; i < msg->msg_iovlen; i++) {
01505         MEMCPY(&((u8_t *)chain_buf.p->payload)[offset], msg->msg_iov[i].iov_base, msg->msg_iov[i].iov_len);
01506         offset += msg->msg_iov[i].iov_len;
01507       }
01508 #if LWIP_CHECKSUM_ON_COPY
01509       {
01510         /* This can be improved by using LWIP_CHKSUM_COPY() and aggregating the checksum for each IO vector */
01511         u16_t chksum = ~inet_chksum_pbuf(chain_buf.p);
01512         netbuf_set_chksum(&chain_buf, chksum);
01513       }
01514 #endif /* LWIP_CHECKSUM_ON_COPY */
01515       err = ERR_OK;
01516     }
01517 #else /* LWIP_NETIF_TX_SINGLE_PBUF */
01518     /* create a chained netbuf from the IO vectors. NOTE: we assemble a pbuf chain
01519        manually to avoid having to allocate, chain, and delete a netbuf for each iov */
01520     for (i = 0; i < msg->msg_iovlen; i++) {
01521       struct pbuf *p;
01522       if (msg->msg_iov[i].iov_len > 0xFFFF) {
01523         /* overflow */
01524         goto sendmsg_emsgsize;
01525       }
01526       p = pbuf_alloc(PBUF_TRANSPORT, 0, PBUF_REF);
01527       if (p == NULL) {
01528         err = ERR_MEM; /* let netbuf_delete() cleanup chain_buf */
01529         break;
01530       }
01531       p->payload = msg->msg_iov[i].iov_base;
01532       p->len = p->tot_len = (u16_t)msg->msg_iov[i].iov_len;
01533       /* netbuf empty, add new pbuf */
01534       if (chain_buf.p == NULL) {
01535         chain_buf.p = chain_buf.ptr = p;
01536         /* add pbuf to existing pbuf chain */
01537       } else {
01538         if (chain_buf.p->tot_len + p->len > 0xffff) {
01539           /* overflow */
01540           pbuf_free(p);
01541           goto sendmsg_emsgsize;
01542         }
01543         pbuf_cat(chain_buf.p, p);
01544       }
01545     }
01546     /* save size of total chain */
01547     if (err == ERR_OK) {
01548       size = netbuf_len(&chain_buf);
01549     }
01550 #endif /* LWIP_NETIF_TX_SINGLE_PBUF */
01551 
01552     if (err == ERR_OK) {
01553 #if LWIP_IPV4 && LWIP_IPV6
01554       /* Dual-stack: Unmap IPv4 mapped IPv6 addresses */
01555       if (IP_IS_V6_VAL(chain_buf.addr) && ip6_addr_isipv4mappedipv6(ip_2_ip6(&chain_buf.addr))) {
01556         unmap_ipv4_mapped_ipv6(ip_2_ip4(&chain_buf.addr), ip_2_ip6(&chain_buf.addr));
01557         IP_SET_TYPE_VAL(chain_buf.addr, IPADDR_TYPE_V4);
01558       }
01559 #endif /* LWIP_IPV4 && LWIP_IPV6 */
01560 
01561       /* send the data */
01562       err = netconn_send(sock->conn, &chain_buf);
01563     }
01564 
01565     /* deallocated the buffer */
01566     netbuf_free(&chain_buf);
01567 
01568     sock_set_errno(sock, err_to_errno(err));
01569     done_socket(sock);
01570     return (err == ERR_OK ? size : -1);
01571 sendmsg_emsgsize:
01572     sock_set_errno(sock, EMSGSIZE);
01573     netbuf_free(&chain_buf);
01574     done_socket(sock);
01575     return -1;
01576   }
01577 #else /* LWIP_UDP || LWIP_RAW */
01578   sock_set_errno(sock, err_to_errno(ERR_ARG));
01579   done_socket(sock);
01580   return -1;
01581 #endif /* LWIP_UDP || LWIP_RAW */
01582 }
01583 
01584 ssize_t
01585 lwip_sendto(int s, const void *data, size_t size, int flags,
01586             const struct sockaddr *to, socklen_t tolen)
01587 {
01588   struct lwip_sock *sock;
01589   err_t err;
01590   u16_t short_size;
01591   u16_t remote_port;
01592   struct netbuf buf;
01593 
01594   sock = get_socket(s);
01595   if (!sock) {
01596     return -1;
01597   }
01598 
01599   if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) {
01600 #if LWIP_TCP
01601     done_socket(sock);
01602     return lwip_send(s, data, size, flags);
01603 #else /* LWIP_TCP */
01604     LWIP_UNUSED_ARG(flags);
01605     sock_set_errno(sock, err_to_errno(ERR_ARG));
01606     done_socket(sock);
01607     return -1;
01608 #endif /* LWIP_TCP */
01609   }
01610 
01611   if (size > LWIP_MIN(0xFFFF, SSIZE_MAX)) {
01612     /* cannot fit into one datagram (at least for us) */
01613     sock_set_errno(sock, EMSGSIZE);
01614     done_socket(sock);
01615     return -1;
01616   }
01617   short_size = (u16_t)size;
01618   LWIP_ERROR("lwip_sendto: invalid address", (((to == NULL) && (tolen == 0)) ||
01619              (IS_SOCK_ADDR_LEN_VALID(tolen) &&
01620               ((to != NULL) && (IS_SOCK_ADDR_TYPE_VALID(to) && IS_SOCK_ADDR_ALIGNED(to))))),
01621              sock_set_errno(sock, err_to_errno(ERR_ARG)); done_socket(sock); return -1;);
01622   LWIP_UNUSED_ARG(tolen);
01623 
01624   /* initialize a buffer */
01625   buf.p = buf.ptr = NULL;
01626 #if LWIP_CHECKSUM_ON_COPY
01627   buf.flags = 0;
01628 #endif /* LWIP_CHECKSUM_ON_COPY */
01629   if (to) {
01630     SOCKADDR_TO_IPADDR_PORT(to, &buf.addr, remote_port);
01631   } else {
01632     remote_port = 0;
01633     ip_addr_set_any(NETCONNTYPE_ISIPV6(netconn_type(sock->conn)), &buf.addr);
01634   }
01635   netbuf_fromport(&buf) = remote_port;
01636 
01637 
01638   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_sendto(%d, data=%p, short_size=%"U16_F", flags=0x%x to=",
01639                               s, data, short_size, flags));
01640   ip_addr_debug_print_val(SOCKETS_DEBUG, buf.addr);
01641   LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F"\n", remote_port));
01642 
01643   /* make the buffer point to the data that should be sent */
01644 #if LWIP_NETIF_TX_SINGLE_PBUF
01645   /* Allocate a new netbuf and copy the data into it. */
01646   if (netbuf_alloc(&buf, short_size) == NULL) {
01647     err = ERR_MEM;
01648   } else {
01649 #if LWIP_CHECKSUM_ON_COPY
01650     if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_RAW) {
01651       u16_t chksum = LWIP_CHKSUM_COPY(buf.p->payload, data, short_size);
01652       netbuf_set_chksum(&buf, chksum);
01653     } else
01654 #endif /* LWIP_CHECKSUM_ON_COPY */
01655     {
01656       MEMCPY(buf.p->payload, data, short_size);
01657     }
01658     err = ERR_OK;
01659   }
01660 #else /* LWIP_NETIF_TX_SINGLE_PBUF */
01661   err = netbuf_ref(&buf, data, short_size);
01662 #endif /* LWIP_NETIF_TX_SINGLE_PBUF */
01663   if (err == ERR_OK) {
01664 #if LWIP_IPV4 && LWIP_IPV6
01665     /* Dual-stack: Unmap IPv4 mapped IPv6 addresses */
01666     if (IP_IS_V6_VAL(buf.addr) && ip6_addr_isipv4mappedipv6(ip_2_ip6(&buf.addr))) {
01667       unmap_ipv4_mapped_ipv6(ip_2_ip4(&buf.addr), ip_2_ip6(&buf.addr));
01668       IP_SET_TYPE_VAL(buf.addr, IPADDR_TYPE_V4);
01669     }
01670 #endif /* LWIP_IPV4 && LWIP_IPV6 */
01671 
01672     /* send the data */
01673     err = netconn_send(sock->conn, &buf);
01674   }
01675 
01676   /* deallocated the buffer */
01677   netbuf_free(&buf);
01678 
01679   sock_set_errno(sock, err_to_errno(err));
01680   done_socket(sock);
01681   return (err == ERR_OK ? short_size : -1);
01682 }
01683 
01684 int
01685 lwip_socket(int domain, int type, int protocol)
01686 {
01687   struct netconn *conn;
01688   int i;
01689 
01690   LWIP_UNUSED_ARG(domain); /* @todo: check this */
01691 
01692   /* create a netconn */
01693   switch (type) {
01694     case SOCK_RAW:
01695       conn = netconn_new_with_proto_and_callback(DOMAIN_TO_NETCONN_TYPE(domain, NETCONN_RAW),
01696              (u8_t)protocol, DEFAULT_SOCKET_EVENTCB);
01697       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_RAW, %d) = ",
01698                                   domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol));
01699       break;
01700     case SOCK_DGRAM:
01701       conn = netconn_new_with_callback(DOMAIN_TO_NETCONN_TYPE(domain,
01702                                        ((protocol == IPPROTO_UDPLITE) ? NETCONN_UDPLITE : NETCONN_UDP)),
01703                                        DEFAULT_SOCKET_EVENTCB);
01704       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_DGRAM, %d) = ",
01705                                   domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol));
01706 #if LWIP_NETBUF_RECVINFO
01707       if (conn) {
01708         /* netconn layer enables pktinfo by default, sockets default to off */
01709         conn->flags &= ~NETCONN_FLAG_PKTINFO;
01710       }
01711 #endif /* LWIP_NETBUF_RECVINFO */
01712       break;
01713     case SOCK_STREAM:
01714       conn = netconn_new_with_callback(DOMAIN_TO_NETCONN_TYPE(domain, NETCONN_TCP), DEFAULT_SOCKET_EVENTCB);
01715       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_STREAM, %d) = ",
01716                                   domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol));
01717       break;
01718     default:
01719       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%d, %d/UNKNOWN, %d) = -1\n",
01720                                   domain, type, protocol));
01721       set_errno(EINVAL);
01722       return -1;
01723   }
01724 
01725   if (!conn) {
01726     LWIP_DEBUGF(SOCKETS_DEBUG, ("-1 / ENOBUFS (could not create netconn)\n"));
01727     set_errno(ENOBUFS);
01728     return -1;
01729   }
01730 
01731   i = alloc_socket(conn, 0);
01732 
01733   if (i == -1) {
01734     netconn_delete(conn);
01735     set_errno(ENFILE);
01736     return -1;
01737   }
01738   conn->socket = i;
01739   done_socket(&sockets[i - LWIP_SOCKET_OFFSET]);
01740   LWIP_DEBUGF(SOCKETS_DEBUG, ("%d\n", i));
01741   set_errno(0);
01742   return i;
01743 }
01744 
01745 ssize_t
01746 lwip_write(int s, const void *data, size_t size)
01747 {
01748   return lwip_send(s, data, size, 0);
01749 }
01750 
01751 ssize_t
01752 lwip_writev(int s, const struct iovec *iov, int iovcnt)
01753 {
01754   struct msghdr msg;
01755 
01756   msg.msg_name = NULL;
01757   msg.msg_namelen = 0;
01758   /* Hack: we have to cast via number to cast from 'const' pointer to non-const.
01759      Blame the opengroup standard for this inconsistency. */
01760   msg.msg_iov = LWIP_CONST_CAST(struct iovec *, iov);
01761   msg.msg_iovlen = iovcnt;
01762   msg.msg_control = NULL;
01763   msg.msg_controllen = 0;
01764   msg.msg_flags = 0;
01765   return lwip_sendmsg(s, &msg, 0);
01766 }
01767 
01768 #if LWIP_SOCKET_SELECT || LWIP_SOCKET_POLL
01769 /* Add select_cb to select_cb_list. */
01770 static void
01771 lwip_link_select_cb(struct lwip_select_cb *select_cb)
01772 {
01773   LWIP_SOCKET_SELECT_DECL_PROTECT(lev);
01774 
01775   /* Protect the select_cb_list */
01776   LWIP_SOCKET_SELECT_PROTECT(lev);
01777 
01778   /* Put this select_cb on top of list */
01779   select_cb->next = select_cb_list;
01780   if (select_cb_list != NULL) {
01781     select_cb_list->prev = select_cb;
01782   }
01783   select_cb_list = select_cb;
01784 #if !LWIP_TCPIP_CORE_LOCKING
01785   /* Increasing this counter tells select_check_waiters that the list has changed. */
01786   select_cb_ctr++;
01787 #endif
01788 
01789   /* Now we can safely unprotect */
01790   LWIP_SOCKET_SELECT_UNPROTECT(lev);
01791 }
01792 
01793 /* Remove select_cb from select_cb_list. */
01794 static void
01795 lwip_unlink_select_cb(struct lwip_select_cb *select_cb)
01796 {
01797   LWIP_SOCKET_SELECT_DECL_PROTECT(lev);
01798 
01799   /* Take us off the list */
01800   LWIP_SOCKET_SELECT_PROTECT(lev);
01801   if (select_cb->next != NULL) {
01802     select_cb->next->prev = select_cb->prev;
01803   }
01804   if (select_cb_list == select_cb) {
01805     LWIP_ASSERT("select_cb->prev == NULL", select_cb->prev == NULL);
01806     select_cb_list = select_cb->next;
01807   } else {
01808     LWIP_ASSERT("select_cb->prev != NULL", select_cb->prev != NULL);
01809     select_cb->prev->next = select_cb->next;
01810   }
01811 #if !LWIP_TCPIP_CORE_LOCKING
01812   /* Increasing this counter tells select_check_waiters that the list has changed. */
01813   select_cb_ctr++;
01814 #endif
01815   LWIP_SOCKET_SELECT_UNPROTECT(lev);
01816 }
01817 #endif /* LWIP_SOCKET_SELECT || LWIP_SOCKET_POLL */
01818 
01819 #if LWIP_SOCKET_SELECT
01820 /**
01821  * Go through the readset and writeset lists and see which socket of the sockets
01822  * set in the sets has events. On return, readset, writeset and exceptset have
01823  * the sockets enabled that had events.
01824  *
01825  * @param maxfdp1 the highest socket index in the sets
01826  * @param readset_in    set of sockets to check for read events
01827  * @param writeset_in   set of sockets to check for write events
01828  * @param exceptset_in  set of sockets to check for error events
01829  * @param readset_out   set of sockets that had read events
01830  * @param writeset_out  set of sockets that had write events
01831  * @param exceptset_out set os sockets that had error events
01832  * @return number of sockets that had events (read/write/exception) (>= 0)
01833  */
01834 static int
01835 lwip_selscan(int maxfdp1, fd_set *readset_in, fd_set *writeset_in, fd_set *exceptset_in,
01836              fd_set *readset_out, fd_set *writeset_out, fd_set *exceptset_out)
01837 {
01838   int i, nready = 0;
01839   fd_set lreadset, lwriteset, lexceptset;
01840   struct lwip_sock *sock;
01841   SYS_ARCH_DECL_PROTECT(lev);
01842 
01843   FD_ZERO(&lreadset);
01844   FD_ZERO(&lwriteset);
01845   FD_ZERO(&lexceptset);
01846 
01847   /* Go through each socket in each list to count number of sockets which
01848      currently match */
01849   for (i = LWIP_SOCKET_OFFSET; i < maxfdp1; i++) {
01850     /* if this FD is not in the set, continue */
01851     if (!(readset_in && FD_ISSET(i, readset_in)) &&
01852         !(writeset_in && FD_ISSET(i, writeset_in)) &&
01853         !(exceptset_in && FD_ISSET(i, exceptset_in))) {
01854       continue;
01855     }
01856     /* First get the socket's status (protected)... */
01857     SYS_ARCH_PROTECT(lev);
01858     sock = tryget_socket_unconn_locked(i);
01859     if (sock != NULL) {
01860       void *lastdata = sock->lastdata.pbuf;
01861       s16_t rcvevent = sock->rcvevent;
01862       u16_t sendevent = sock->sendevent;
01863       u16_t errevent = sock->errevent;
01864       SYS_ARCH_UNPROTECT(lev);
01865 
01866       /* ... then examine it: */
01867       /* See if netconn of this socket is ready for read */
01868       if (readset_in && FD_ISSET(i, readset_in) && ((lastdata != NULL) || (rcvevent > 0))) {
01869         FD_SET(i, &lreadset);
01870         LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_selscan: fd=%d ready for reading\n", i));
01871         nready++;
01872       }
01873       /* See if netconn of this socket is ready for write */
01874       if (writeset_in && FD_ISSET(i, writeset_in) && (sendevent != 0)) {
01875         FD_SET(i, &lwriteset);
01876         LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_selscan: fd=%d ready for writing\n", i));
01877         nready++;
01878       }
01879       /* See if netconn of this socket had an error */
01880       if (exceptset_in && FD_ISSET(i, exceptset_in) && (errevent != 0)) {
01881         FD_SET(i, &lexceptset);
01882         LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_selscan: fd=%d ready for exception\n", i));
01883         nready++;
01884       }
01885       done_socket(sock);
01886     } else {
01887       SYS_ARCH_UNPROTECT(lev);
01888       /* no a valid open socket */
01889       return -1;
01890     }
01891   }
01892   /* copy local sets to the ones provided as arguments */
01893   *readset_out = lreadset;
01894   *writeset_out = lwriteset;
01895   *exceptset_out = lexceptset;
01896 
01897   LWIP_ASSERT("nready >= 0", nready >= 0);
01898   return nready;
01899 }
01900 
01901 #if LWIP_NETCONN_FULLDUPLEX
01902 /* Mark all of the set sockets in one of the three fdsets passed to select as used.
01903  * All sockets are marked (and later unmarked), whether they are open or not.
01904  * This is OK as lwip_selscan aborts select when non-open sockets are found.
01905  */
01906 static void
01907 lwip_select_inc_sockets_used_set(int maxfdp, fd_set *fdset, fd_set *used_sockets)
01908 {
01909   SYS_ARCH_DECL_PROTECT(lev);
01910   if (fdset) {
01911     int i;
01912     for (i = LWIP_SOCKET_OFFSET; i < maxfdp; i++) {
01913       /* if this FD is in the set, lock it (unless already done) */
01914       if (FD_ISSET(i, fdset) && !FD_ISSET(i, used_sockets)) {
01915         struct lwip_sock *sock;
01916         SYS_ARCH_PROTECT(lev);
01917         sock = tryget_socket_unconn_locked(i);
01918         if (sock != NULL) {
01919           /* leave the socket used until released by lwip_select_dec_sockets_used */
01920           FD_SET(i, used_sockets);
01921         }
01922         SYS_ARCH_UNPROTECT(lev);
01923       }
01924     }
01925   }
01926 }
01927 
01928 /* Mark all sockets passed to select as used to prevent them from being freed
01929  * from other threads while select is running.
01930  * Marked sockets are added to 'used_sockets' to mark them only once an be able
01931  * to unmark them correctly.
01932  */
01933 static void
01934 lwip_select_inc_sockets_used(int maxfdp, fd_set *fdset1, fd_set *fdset2, fd_set *fdset3, fd_set *used_sockets)
01935 {
01936   FD_ZERO(used_sockets);
01937   lwip_select_inc_sockets_used_set(maxfdp, fdset1, used_sockets);
01938   lwip_select_inc_sockets_used_set(maxfdp, fdset2, used_sockets);
01939   lwip_select_inc_sockets_used_set(maxfdp, fdset3, used_sockets);
01940 }
01941 
01942 /* Let go all sockets that were marked as used when starting select */
01943 static void
01944 lwip_select_dec_sockets_used(int maxfdp, fd_set *used_sockets)
01945 {
01946   int i;
01947   for (i = LWIP_SOCKET_OFFSET; i < maxfdp; i++) {
01948     /* if this FD is not in the set, continue */
01949     if (FD_ISSET(i, used_sockets)) {
01950       struct lwip_sock *sock = tryget_socket_unconn_nouse(i);
01951       LWIP_ASSERT("socket gone at the end of select", sock != NULL);
01952       if (sock != NULL) {
01953         done_socket(sock);
01954       }
01955     }
01956   }
01957 }
01958 #else /* LWIP_NETCONN_FULLDUPLEX */
01959 #define lwip_select_inc_sockets_used(maxfdp1, readset, writeset, exceptset, used_sockets)
01960 #define lwip_select_dec_sockets_used(maxfdp1, used_sockets)
01961 #endif /* LWIP_NETCONN_FULLDUPLEX */
01962 
01963 int
01964 lwip_select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset,
01965             struct timeval *timeout)
01966 {
01967   u32_t waitres = 0;
01968   int nready;
01969   fd_set lreadset, lwriteset, lexceptset;
01970   u32_t msectimeout;
01971   int i;
01972   int maxfdp2;
01973 #if LWIP_NETCONN_SEM_PER_THREAD
01974   int waited = 0;
01975 #endif
01976 #if LWIP_NETCONN_FULLDUPLEX
01977   fd_set used_sockets;
01978 #endif
01979   SYS_ARCH_DECL_PROTECT(lev);
01980 
01981   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select(%d, %p, %p, %p, tvsec=%"S32_F" tvusec=%"S32_F")\n",
01982                               maxfdp1, (void *)readset, (void *) writeset, (void *) exceptset,
01983                               timeout ? (s32_t)timeout->tv_sec : (s32_t) - 1,
01984                               timeout ? (s32_t)timeout->tv_usec : (s32_t) - 1));
01985 
01986   if ((maxfdp1 < 0) || (maxfdp1 > LWIP_SELECT_MAXNFDS)) {
01987     set_errno(EINVAL);
01988     return -1;
01989   }
01990 
01991   lwip_select_inc_sockets_used(maxfdp1, readset, writeset, exceptset, &used_sockets);
01992 
01993   /* Go through each socket in each list to count number of sockets which
01994      currently match */
01995   nready = lwip_selscan(maxfdp1, readset, writeset, exceptset, &lreadset, &lwriteset, &lexceptset);
01996 
01997   if (nready < 0) {
01998     /* one of the sockets in one of the fd_sets was invalid */
01999     set_errno(EBADF);
02000     lwip_select_dec_sockets_used(maxfdp1, &used_sockets);
02001     return -1;
02002   } else if (nready > 0) {
02003     /* one or more sockets are set, no need to wait */
02004     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select: nready=%d\n", nready));
02005   } else {
02006     /* If we don't have any current events, then suspend if we are supposed to */
02007     if (timeout && timeout->tv_sec == 0 && timeout->tv_usec == 0) {
02008       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select: no timeout, returning 0\n"));
02009       /* This is OK as the local fdsets are empty and nready is zero,
02010          or we would have returned earlier. */
02011     } else {
02012       /* None ready: add our semaphore to list:
02013          We don't actually need any dynamic memory. Our entry on the
02014          list is only valid while we are in this function, so it's ok
02015          to use local variables (unless we're running in MPU compatible
02016          mode). */
02017       API_SELECT_CB_VAR_DECLARE(select_cb);
02018       API_SELECT_CB_VAR_ALLOC(select_cb, set_errno(ENOMEM); lwip_select_dec_sockets_used(maxfdp1, &used_sockets); return -1);
02019       memset(&API_SELECT_CB_VAR_REF(select_cb), 0, sizeof(struct lwip_select_cb));
02020 
02021       API_SELECT_CB_VAR_REF(select_cb).readset = readset;
02022       API_SELECT_CB_VAR_REF(select_cb).writeset = writeset;
02023       API_SELECT_CB_VAR_REF(select_cb).exceptset = exceptset;
02024 #if LWIP_NETCONN_SEM_PER_THREAD
02025       API_SELECT_CB_VAR_REF(select_cb).sem = LWIP_NETCONN_THREAD_SEM_GET();
02026 #else /* LWIP_NETCONN_SEM_PER_THREAD */
02027       if (sys_sem_new(&API_SELECT_CB_VAR_REF(select_cb).sem, 0) != ERR_OK) {
02028         /* failed to create semaphore */
02029         set_errno(ENOMEM);
02030         lwip_select_dec_sockets_used(maxfdp1, &used_sockets);
02031         API_SELECT_CB_VAR_FREE(select_cb);
02032         return -1;
02033       }
02034 #endif /* LWIP_NETCONN_SEM_PER_THREAD */
02035 
02036       lwip_link_select_cb(&API_SELECT_CB_VAR_REF(select_cb));
02037 
02038       /* Increase select_waiting for each socket we are interested in */
02039       maxfdp2 = maxfdp1;
02040       for (i = LWIP_SOCKET_OFFSET; i < maxfdp1; i++) {
02041         if ((readset && FD_ISSET(i, readset)) ||
02042             (writeset && FD_ISSET(i, writeset)) ||
02043             (exceptset && FD_ISSET(i, exceptset))) {
02044           struct lwip_sock *sock;
02045           SYS_ARCH_PROTECT(lev);
02046           sock = tryget_socket_unconn_locked(i);
02047           if (sock != NULL) {
02048             sock->select_waiting++;
02049             if (sock->select_waiting == 0) {
02050               /* overflow - too many threads waiting */
02051               sock->select_waiting--;
02052               nready = -1;
02053               maxfdp2 = i;
02054               SYS_ARCH_UNPROTECT(lev);
02055               done_socket(sock);
02056               set_errno(EBUSY);
02057               break;
02058             }
02059             SYS_ARCH_UNPROTECT(lev);
02060             done_socket(sock);
02061           } else {
02062             /* Not a valid socket */
02063             nready = -1;
02064             maxfdp2 = i;
02065             SYS_ARCH_UNPROTECT(lev);
02066             set_errno(EBADF);
02067             break;
02068           }
02069         }
02070       }
02071 
02072       if (nready >= 0) {
02073         /* Call lwip_selscan again: there could have been events between
02074            the last scan (without us on the list) and putting us on the list! */
02075         nready = lwip_selscan(maxfdp1, readset, writeset, exceptset, &lreadset, &lwriteset, &lexceptset);
02076         if (!nready) {
02077           /* Still none ready, just wait to be woken */
02078           if (timeout == 0) {
02079             /* Wait forever */
02080             msectimeout = 0;
02081           } else {
02082             long msecs_long = ((timeout->tv_sec * 1000) + ((timeout->tv_usec + 500) / 1000));
02083             if (msecs_long <= 0) {
02084               /* Wait 1ms at least (0 means wait forever) */
02085               msectimeout = 1;
02086             } else {
02087               msectimeout = (u32_t)msecs_long;
02088             }
02089           }
02090 
02091           waitres = sys_arch_sem_wait(SELECT_SEM_PTR(API_SELECT_CB_VAR_REF(select_cb).sem), msectimeout);
02092 #if LWIP_NETCONN_SEM_PER_THREAD
02093           waited = 1;
02094 #endif
02095         }
02096       }
02097 
02098       /* Decrease select_waiting for each socket we are interested in */
02099       for (i = LWIP_SOCKET_OFFSET; i < maxfdp2; i++) {
02100         if ((readset && FD_ISSET(i, readset)) ||
02101             (writeset && FD_ISSET(i, writeset)) ||
02102             (exceptset && FD_ISSET(i, exceptset))) {
02103           struct lwip_sock *sock;
02104           SYS_ARCH_PROTECT(lev);
02105           sock = tryget_socket_unconn_locked(i);
02106           if (sock != NULL) {
02107             /* for now, handle select_waiting==0... */
02108             LWIP_ASSERT("sock->select_waiting > 0", sock->select_waiting > 0);
02109             if (sock->select_waiting > 0) {
02110               sock->select_waiting--;
02111             }
02112             SYS_ARCH_UNPROTECT(lev);
02113             done_socket(sock);
02114           } else {
02115             SYS_ARCH_UNPROTECT(lev);
02116             /* Not a valid socket */
02117             nready = -1;
02118             set_errno(EBADF);
02119           }
02120         }
02121       }
02122 
02123       lwip_unlink_select_cb(&API_SELECT_CB_VAR_REF(select_cb));
02124 
02125 #if LWIP_NETCONN_SEM_PER_THREAD
02126       if (API_SELECT_CB_VAR_REF(select_cb).sem_signalled && (!waited || (waitres == SYS_ARCH_TIMEOUT))) {
02127         /* don't leave the thread-local semaphore signalled */
02128         sys_arch_sem_wait(API_SELECT_CB_VAR_REF(select_cb).sem, 1);
02129       }
02130 #else /* LWIP_NETCONN_SEM_PER_THREAD */
02131       sys_sem_free(&API_SELECT_CB_VAR_REF(select_cb).sem);
02132 #endif /* LWIP_NETCONN_SEM_PER_THREAD */
02133       API_SELECT_CB_VAR_FREE(select_cb);
02134 
02135       if (nready < 0) {
02136         /* This happens when a socket got closed while waiting */
02137         lwip_select_dec_sockets_used(maxfdp1, &used_sockets);
02138         return -1;
02139       }
02140 
02141       if (waitres == SYS_ARCH_TIMEOUT) {
02142         /* Timeout */
02143         LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select: timeout expired\n"));
02144         /* This is OK as the local fdsets are empty and nready is zero,
02145            or we would have returned earlier. */
02146       } else {
02147         /* See what's set now after waiting */
02148         nready = lwip_selscan(maxfdp1, readset, writeset, exceptset, &lreadset, &lwriteset, &lexceptset);
02149         LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select: nready=%d\n", nready));
02150       }
02151     }
02152   }
02153 
02154   lwip_select_dec_sockets_used(maxfdp1, &used_sockets);
02155   set_errno(0);
02156   if (readset) {
02157     *readset = lreadset;
02158   }
02159   if (writeset) {
02160     *writeset = lwriteset;
02161   }
02162   if (exceptset) {
02163     *exceptset = lexceptset;
02164   }
02165   return nready;
02166 }
02167 #endif /* LWIP_SOCKET_SELECT */
02168 
02169 #if LWIP_SOCKET_POLL
02170 /** Options for the lwip_pollscan function. */
02171 enum lwip_pollscan_opts
02172 {
02173   /** Clear revents in each struct pollfd. */
02174   LWIP_POLLSCAN_CLEAR = 1,
02175 
02176   /** Increment select_waiting in each struct lwip_sock. */
02177   LWIP_POLLSCAN_INC_WAIT = 2,
02178 
02179   /** Decrement select_waiting in each struct lwip_sock. */
02180   LWIP_POLLSCAN_DEC_WAIT = 4
02181 };
02182 
02183 /**
02184  * Update revents in each struct pollfd.
02185  * Optionally update select_waiting in struct lwip_sock.
02186  *
02187  * @param fds          array of structures to update
02188  * @param nfds         number of structures in fds
02189  * @param opts         what to update and how
02190  * @return number of structures that have revents != 0
02191  */
02192 static int
02193 lwip_pollscan(struct pollfd *fds, nfds_t nfds, enum lwip_pollscan_opts opts)
02194 {
02195   int nready = 0;
02196   nfds_t fdi;
02197   struct lwip_sock *sock;
02198   SYS_ARCH_DECL_PROTECT(lev);
02199 
02200   /* Go through each struct pollfd in the array. */
02201   for (fdi = 0; fdi < nfds; fdi++) {
02202     if ((opts & LWIP_POLLSCAN_CLEAR) != 0) {
02203       fds[fdi].revents = 0;
02204     }
02205 
02206     /* Negative fd means the caller wants us to ignore this struct.
02207        POLLNVAL means we already detected that the fd is invalid;
02208        if another thread has since opened a new socket with that fd,
02209        we must not use that socket. */
02210     if (fds[fdi].fd >= 0 && (fds[fdi].revents & POLLNVAL) == 0) {
02211       /* First get the socket's status (protected)... */
02212       SYS_ARCH_PROTECT(lev);
02213       sock = tryget_socket_unconn_locked(fds[fdi].fd);
02214       if (sock != NULL) {
02215         void* lastdata = sock->lastdata.pbuf;
02216         s16_t rcvevent = sock->rcvevent;
02217         u16_t sendevent = sock->sendevent;
02218         u16_t errevent = sock->errevent;
02219 
02220         if ((opts & LWIP_POLLSCAN_INC_WAIT) != 0) {
02221           sock->select_waiting++;
02222           if (sock->select_waiting == 0) {
02223             /* overflow - too many threads waiting */
02224             sock->select_waiting--;
02225             nready = -1;
02226             SYS_ARCH_UNPROTECT(lev);
02227             done_socket(sock);
02228             break;
02229           }
02230         } else if ((opts & LWIP_POLLSCAN_DEC_WAIT) != 0) {
02231           /* for now, handle select_waiting==0... */
02232           LWIP_ASSERT("sock->select_waiting > 0", sock->select_waiting > 0);
02233           if (sock->select_waiting > 0) {
02234             sock->select_waiting--;
02235           }
02236         }
02237         SYS_ARCH_UNPROTECT(lev);
02238         done_socket(sock);
02239 
02240         /* ... then examine it: */
02241         /* See if netconn of this socket is ready for read */
02242         if ((fds[fdi].events & POLLIN) != 0 && ((lastdata != NULL) || (rcvevent > 0))) {
02243           fds[fdi].revents |= POLLIN;
02244           LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_pollscan: fd=%d ready for reading\n", fds[fdi].fd));
02245         }
02246         /* See if netconn of this socket is ready for write */
02247         if ((fds[fdi].events & POLLOUT) != 0 && (sendevent != 0)) {
02248           fds[fdi].revents |= POLLOUT;
02249           LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_pollscan: fd=%d ready for writing\n", fds[fdi].fd));
02250         }
02251         /* See if netconn of this socket had an error */
02252         if (errevent != 0) {
02253           /* POLLERR is output only. */
02254           fds[fdi].revents |= POLLERR;
02255           LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_pollscan: fd=%d ready for exception\n", fds[fdi].fd));
02256         }
02257       } else {
02258         /* Not a valid socket */
02259         SYS_ARCH_UNPROTECT(lev);
02260         /* POLLNVAL is output only. */
02261         fds[fdi].revents |= POLLNVAL;
02262         return -1;
02263       }
02264     }
02265 
02266     /* Will return the number of structures that have events,
02267        not the number of events. */
02268     if (fds[fdi].revents != 0) {
02269       nready++;
02270     }
02271   }
02272 
02273   LWIP_ASSERT("nready >= 0", nready >= 0);
02274   return nready;
02275 }
02276 
02277 #if LWIP_NETCONN_FULLDUPLEX
02278 /* Mark all sockets as used.
02279  *
02280  * All sockets are marked (and later unmarked), whether they are open or not.
02281  * This is OK as lwip_pollscan aborts select when non-open sockets are found.
02282  */
02283 static void
02284 lwip_poll_inc_sockets_used(struct pollfd *fds, nfds_t nfds)
02285 {
02286   nfds_t fdi;
02287 
02288   if(fds) {
02289     /* Go through each struct pollfd in the array. */
02290     for (fdi = 0; fdi < nfds; fdi++) {
02291       /* Increase the reference counter */
02292       tryget_socket_unconn(fds[fdi].fd);
02293     }
02294   }
02295 }
02296 
02297 /* Let go all sockets that were marked as used when starting poll */
02298 static void
02299 lwip_poll_dec_sockets_used(struct pollfd *fds, nfds_t nfds)
02300 {
02301   nfds_t fdi;
02302 
02303   if(fds) {
02304     /* Go through each struct pollfd in the array. */
02305     for (fdi = 0; fdi < nfds; fdi++) {
02306       struct lwip_sock *sock = tryget_socket_unconn_nouse(fds[fdi].fd);
02307       if (sock != NULL) {
02308         done_socket(sock);
02309       }
02310     }
02311   }
02312 }
02313 #else /* LWIP_NETCONN_FULLDUPLEX */
02314 #define lwip_poll_inc_sockets_used(fds, nfds)
02315 #define lwip_poll_dec_sockets_used(fds, nfds)
02316 #endif /* LWIP_NETCONN_FULLDUPLEX */
02317 
02318 int
02319 lwip_poll(struct pollfd *fds, nfds_t nfds, int timeout)
02320 {
02321   u32_t waitres = 0;
02322   int nready;
02323   u32_t msectimeout;
02324 #if LWIP_NETCONN_SEM_PER_THREAD
02325   int waited = 0;
02326 #endif
02327 
02328   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_poll(%p, %d, %d)\n",
02329                   (void*)fds, (int)nfds, timeout));
02330   LWIP_ERROR("lwip_poll: invalid fds", ((fds != NULL && nfds > 0) || (fds == NULL && nfds == 0)),
02331              set_errno(EINVAL); return -1;);
02332 
02333   lwip_poll_inc_sockets_used(fds, nfds);
02334 
02335   /* Go through each struct pollfd to count number of structures
02336      which currently match */
02337   nready = lwip_pollscan(fds, nfds, LWIP_POLLSCAN_CLEAR);
02338 
02339   if (nready < 0) {
02340     lwip_poll_dec_sockets_used(fds, nfds);
02341     return -1;
02342   }
02343 
02344   /* If we don't have any current events, then suspend if we are supposed to */
02345   if (!nready) {
02346     API_SELECT_CB_VAR_DECLARE(select_cb);
02347 
02348     if (timeout == 0) {
02349       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_poll: no timeout, returning 0\n"));
02350       goto return_success;
02351     }
02352     API_SELECT_CB_VAR_ALLOC(select_cb, set_errno(EAGAIN); lwip_poll_dec_sockets_used(fds, nfds); return -1);
02353     memset(&API_SELECT_CB_VAR_REF(select_cb), 0, sizeof(struct lwip_select_cb));
02354 
02355     /* None ready: add our semaphore to list:
02356        We don't actually need any dynamic memory. Our entry on the
02357        list is only valid while we are in this function, so it's ok
02358        to use local variables. */
02359 
02360     API_SELECT_CB_VAR_REF(select_cb).poll_fds = fds;
02361     API_SELECT_CB_VAR_REF(select_cb).poll_nfds = nfds;
02362 #if LWIP_NETCONN_SEM_PER_THREAD
02363     API_SELECT_CB_VAR_REF(select_cb).sem = LWIP_NETCONN_THREAD_SEM_GET();
02364 #else /* LWIP_NETCONN_SEM_PER_THREAD */
02365     if (sys_sem_new(&API_SELECT_CB_VAR_REF(select_cb).sem, 0) != ERR_OK) {
02366       /* failed to create semaphore */
02367       set_errno(EAGAIN);
02368       lwip_poll_dec_sockets_used(fds, nfds);
02369       API_SELECT_CB_VAR_FREE(select_cb);
02370       return -1;
02371     }
02372 #endif /* LWIP_NETCONN_SEM_PER_THREAD */
02373 
02374     lwip_link_select_cb(&API_SELECT_CB_VAR_REF(select_cb));
02375 
02376     /* Increase select_waiting for each socket we are interested in.
02377        Also, check for events again: there could have been events between
02378        the last scan (without us on the list) and putting us on the list! */
02379     nready = lwip_pollscan(fds, nfds, LWIP_POLLSCAN_INC_WAIT);
02380 
02381     if (!nready) {
02382       /* Still none ready, just wait to be woken */
02383       if (timeout < 0) {
02384         /* Wait forever */
02385         msectimeout = 0;
02386       } else {
02387         /* timeout == 0 would have been handled earlier. */
02388         LWIP_ASSERT("timeout > 0", timeout > 0);
02389         msectimeout = timeout;
02390       }
02391       waitres = sys_arch_sem_wait(SELECT_SEM_PTR(API_SELECT_CB_VAR_REF(select_cb).sem), msectimeout);
02392 #if LWIP_NETCONN_SEM_PER_THREAD
02393       waited = 1;
02394 #endif
02395     }
02396 
02397     /* Decrease select_waiting for each socket we are interested in,
02398        and check which events occurred while we waited. */
02399     nready = lwip_pollscan(fds, nfds, LWIP_POLLSCAN_DEC_WAIT);
02400 
02401     lwip_unlink_select_cb(&API_SELECT_CB_VAR_REF(select_cb));
02402 
02403 #if LWIP_NETCONN_SEM_PER_THREAD
02404     if (select_cb.sem_signalled && (!waited || (waitres == SYS_ARCH_TIMEOUT))) {
02405       /* don't leave the thread-local semaphore signalled */
02406       sys_arch_sem_wait(API_SELECT_CB_VAR_REF(select_cb).sem, 1);
02407     }
02408 #else /* LWIP_NETCONN_SEM_PER_THREAD */
02409     sys_sem_free(&API_SELECT_CB_VAR_REF(select_cb).sem);
02410 #endif /* LWIP_NETCONN_SEM_PER_THREAD */
02411     API_SELECT_CB_VAR_FREE(select_cb);
02412 
02413     if (nready < 0) {
02414       /* This happens when a socket got closed while waiting */
02415       lwip_poll_dec_sockets_used(fds, nfds);
02416       return -1;
02417     }
02418 
02419     if (waitres == SYS_ARCH_TIMEOUT) {
02420       /* Timeout */
02421       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_poll: timeout expired\n"));
02422       goto return_success;
02423     }
02424   }
02425 
02426   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_poll: nready=%d\n", nready));
02427 return_success:
02428   lwip_poll_dec_sockets_used(fds, nfds);
02429   set_errno(0);
02430   return nready;
02431 }
02432 
02433 /**
02434  * Check whether event_callback should wake up a thread waiting in
02435  * lwip_poll.
02436  */
02437 static int
02438 lwip_poll_should_wake(const struct lwip_select_cb *scb, int fd, int has_recvevent, int has_sendevent, int has_errevent)
02439 {
02440   nfds_t fdi;
02441   for (fdi = 0; fdi < scb->poll_nfds; fdi++) {
02442     const struct pollfd *pollfd = &scb->poll_fds[fdi];
02443     if (pollfd->fd == fd) {
02444       /* Do not update pollfd->revents right here;
02445          that would be a data race because lwip_pollscan
02446          accesses revents without protecting. */
02447       if (has_recvevent && (pollfd->events & POLLIN) != 0) {
02448         return 1;
02449       }
02450       if (has_sendevent && (pollfd->events & POLLOUT) != 0) {
02451         return 1;
02452       }
02453       if (has_errevent) {
02454         /* POLLERR is output only. */
02455         return 1;
02456       }
02457     }
02458   }
02459   return 0;
02460 }
02461 #endif /* LWIP_SOCKET_POLL */
02462 
02463 #if LWIP_SOCKET_SELECT || LWIP_SOCKET_POLL
02464 /**
02465  * Callback registered in the netconn layer for each socket-netconn.
02466  * Processes recvevent (data available) and wakes up tasks waiting for select.
02467  *
02468  * @note for LWIP_TCPIP_CORE_LOCKING any caller of this function
02469  * must have the core lock held when signaling the following events
02470  * as they might cause select_list_cb to be checked:
02471  *   NETCONN_EVT_RCVPLUS
02472  *   NETCONN_EVT_SENDPLUS
02473  *   NETCONN_EVT_ERROR
02474  * This requirement will be asserted in select_check_waiters()
02475  */
02476 static void
02477 event_callback(struct netconn *conn, enum netconn_evt evt, u16_t len)
02478 {
02479   int s, check_waiters;
02480   struct lwip_sock *sock;
02481   SYS_ARCH_DECL_PROTECT(lev);
02482 
02483   LWIP_UNUSED_ARG(len);
02484 
02485   /* Get socket */
02486   if (conn) {
02487     s = conn->socket;
02488     if (s < 0) {
02489       /* Data comes in right away after an accept, even though
02490        * the server task might not have created a new socket yet.
02491        * Just count down (or up) if that's the case and we
02492        * will use the data later. Note that only receive events
02493        * can happen before the new socket is set up. */
02494       SYS_ARCH_PROTECT(lev);
02495       if (conn->socket < 0) {
02496         if (evt == NETCONN_EVT_RCVPLUS) {
02497           /* conn->socket is -1 on initialization
02498              lwip_accept adjusts sock->recvevent if conn->socket < -1 */
02499           conn->socket--;
02500         }
02501         SYS_ARCH_UNPROTECT(lev);
02502         return;
02503       }
02504       s = conn->socket;
02505       SYS_ARCH_UNPROTECT(lev);
02506     }
02507 
02508     sock = get_socket(s);
02509     if (!sock) {
02510       return;
02511     }
02512   } else {
02513     return;
02514   }
02515 
02516   check_waiters = 1;
02517   SYS_ARCH_PROTECT(lev);
02518   /* Set event as required */
02519   switch (evt) {
02520     case NETCONN_EVT_RCVPLUS:
02521       sock->rcvevent++;
02522       if (sock->rcvevent > 1) {
02523         check_waiters = 0;
02524       }
02525       break;
02526     case NETCONN_EVT_RCVMINUS:
02527       sock->rcvevent--;
02528       check_waiters = 0;
02529       break;
02530     case NETCONN_EVT_SENDPLUS:
02531       if (sock->sendevent) {
02532         check_waiters = 0;
02533       }
02534       sock->sendevent = 1;
02535       break;
02536     case NETCONN_EVT_SENDMINUS:
02537       sock->sendevent = 0;
02538       check_waiters = 0;
02539       break;
02540     case NETCONN_EVT_ERROR:
02541       sock->errevent = 1;
02542       break;
02543     default:
02544       LWIP_ASSERT("unknown event", 0);
02545       break;
02546   }
02547 
02548   if (sock->select_waiting && check_waiters) {
02549     /* Save which events are active */
02550     int has_recvevent, has_sendevent, has_errevent;
02551     has_recvevent = sock->rcvevent > 0;
02552     has_sendevent = sock->sendevent != 0;
02553     has_errevent = sock->errevent != 0;
02554     SYS_ARCH_UNPROTECT(lev);
02555     /* Check any select calls waiting on this socket */
02556     select_check_waiters(s, has_recvevent, has_sendevent, has_errevent);
02557   } else {
02558     SYS_ARCH_UNPROTECT(lev);
02559   }
02560   done_socket(sock);
02561 }
02562 
02563 /**
02564  * Check if any select waiters are waiting on this socket and its events
02565  *
02566  * @note on synchronization of select_cb_list:
02567  * LWIP_TCPIP_CORE_LOCKING: the select_cb_list must only be accessed while holding
02568  * the core lock. We do a single pass through the list and signal any waiters.
02569  * Core lock should already be held when calling here!!!!
02570 
02571  * !LWIP_TCPIP_CORE_LOCKING: we use SYS_ARCH_PROTECT but unlock on each iteration
02572  * of the loop, thus creating a possibility where a thread could modify the
02573  * select_cb_list during our UNPROTECT/PROTECT. We use a generational counter to
02574  * detect this change and restart the list walk. The list is expected to be small
02575  */
02576 static void select_check_waiters(int s, int has_recvevent, int has_sendevent, int has_errevent)
02577 {
02578   struct lwip_select_cb *scb;
02579 #if !LWIP_TCPIP_CORE_LOCKING
02580   int last_select_cb_ctr;
02581   SYS_ARCH_DECL_PROTECT(lev);
02582 #endif /* !LWIP_TCPIP_CORE_LOCKING */
02583 
02584   LWIP_ASSERT_CORE_LOCKED();
02585 
02586 #if !LWIP_TCPIP_CORE_LOCKING
02587   SYS_ARCH_PROTECT(lev);
02588 again:
02589   /* remember the state of select_cb_list to detect changes */
02590   last_select_cb_ctr = select_cb_ctr;
02591 #endif /* !LWIP_TCPIP_CORE_LOCKING */
02592   for (scb = select_cb_list; scb != NULL; scb = scb->next) {
02593     if (scb->sem_signalled == 0) {
02594       /* semaphore not signalled yet */
02595       int do_signal = 0;
02596 #if LWIP_SOCKET_POLL
02597       if (scb->poll_fds != NULL) {
02598         do_signal = lwip_poll_should_wake(scb, s, has_recvevent, has_sendevent, has_errevent);
02599       }
02600 #endif /* LWIP_SOCKET_POLL */
02601 #if LWIP_SOCKET_SELECT && LWIP_SOCKET_POLL
02602       else
02603 #endif /* LWIP_SOCKET_SELECT && LWIP_SOCKET_POLL */
02604 #if LWIP_SOCKET_SELECT
02605       {
02606         /* Test this select call for our socket */
02607         if (has_recvevent) {
02608           if (scb->readset && FD_ISSET(s, scb->readset)) {
02609             do_signal = 1;
02610           }
02611         }
02612         if (has_sendevent) {
02613           if (!do_signal && scb->writeset && FD_ISSET(s, scb->writeset)) {
02614             do_signal = 1;
02615           }
02616         }
02617         if (has_errevent) {
02618           if (!do_signal && scb->exceptset && FD_ISSET(s, scb->exceptset)) {
02619             do_signal = 1;
02620           }
02621         }
02622       }
02623 #endif /* LWIP_SOCKET_SELECT */
02624       if (do_signal) {
02625         scb->sem_signalled = 1;
02626         /* For !LWIP_TCPIP_CORE_LOCKING, we don't call SYS_ARCH_UNPROTECT() before signaling
02627            the semaphore, as this might lead to the select thread taking itself off the list,
02628            invalidating the semaphore. */
02629         sys_sem_signal(SELECT_SEM_PTR(scb->sem));
02630       }
02631     }
02632 #if LWIP_TCPIP_CORE_LOCKING
02633   }
02634 #else
02635     /* unlock interrupts with each step */
02636     SYS_ARCH_UNPROTECT(lev);
02637     /* this makes sure interrupt protection time is short */
02638     SYS_ARCH_PROTECT(lev);
02639     if (last_select_cb_ctr != select_cb_ctr) {
02640       /* someone has changed select_cb_list, restart at the beginning */
02641       goto again;
02642     }
02643     /* remember the state of select_cb_list to detect changes */
02644     last_select_cb_ctr = select_cb_ctr;
02645   }
02646   SYS_ARCH_UNPROTECT(lev);
02647 #endif
02648 }
02649 #endif /* LWIP_SOCKET_SELECT || LWIP_SOCKET_POLL */
02650 
02651 /**
02652  * Close one end of a full-duplex connection.
02653  */
02654 int
02655 lwip_shutdown(int s, int how)
02656 {
02657   struct lwip_sock *sock;
02658   err_t err;
02659   u8_t shut_rx = 0, shut_tx = 0;
02660 
02661   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_shutdown(%d, how=%d)\n", s, how));
02662 
02663   sock = get_socket(s);
02664   if (!sock) {
02665     return -1;
02666   }
02667 
02668   if (sock->conn != NULL) {
02669     if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_TCP) {
02670       sock_set_errno(sock, EOPNOTSUPP);
02671       done_socket(sock);
02672       return -1;
02673     }
02674   } else {
02675     sock_set_errno(sock, ENOTCONN);
02676     done_socket(sock);
02677     return -1;
02678   }
02679 
02680   if (how == SHUT_RD) {
02681     shut_rx = 1;
02682   } else if (how == SHUT_WR) {
02683     shut_tx = 1;
02684   } else if (how == SHUT_RDWR) {
02685     shut_rx = 1;
02686     shut_tx = 1;
02687   } else {
02688     sock_set_errno(sock, EINVAL);
02689     done_socket(sock);
02690     return -1;
02691   }
02692   err = netconn_shutdown(sock->conn, shut_rx, shut_tx);
02693 
02694   sock_set_errno(sock, err_to_errno(err));
02695   done_socket(sock);
02696   return (err == ERR_OK ? 0 : -1);
02697 }
02698 
02699 static int
02700 lwip_getaddrname(int s, struct sockaddr *name, socklen_t *namelen, u8_t local)
02701 {
02702   struct lwip_sock *sock;
02703   union sockaddr_aligned saddr;
02704   ip_addr_t naddr;
02705   u16_t port;
02706   err_t err;
02707 
02708   sock = get_socket(s);
02709   if (!sock) {
02710     return -1;
02711   }
02712 
02713   /* get the IP address and port */
02714   err = netconn_getaddr(sock->conn, &naddr, &port, local);
02715   if (err != ERR_OK) {
02716     sock_set_errno(sock, err_to_errno(err));
02717     done_socket(sock);
02718     return -1;
02719   }
02720 
02721 #if LWIP_IPV4 && LWIP_IPV6
02722   /* Dual-stack: Map IPv4 addresses to IPv4 mapped IPv6 */
02723   if (NETCONNTYPE_ISIPV6(netconn_type(sock->conn)) &&
02724       IP_IS_V4_VAL(naddr)) {
02725     ip4_2_ipv4_mapped_ipv6(ip_2_ip6(&naddr), ip_2_ip4(&naddr));
02726     IP_SET_TYPE_VAL(naddr, IPADDR_TYPE_V6);
02727   }
02728 #endif /* LWIP_IPV4 && LWIP_IPV6 */
02729 
02730   IPADDR_PORT_TO_SOCKADDR(&saddr, &naddr, port);
02731 
02732   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getaddrname(%d, addr=", s));
02733   ip_addr_debug_print_val(SOCKETS_DEBUG, naddr);
02734   LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F")\n", port));
02735 
02736   if (*namelen > saddr.sa.sa_len) {
02737     *namelen = saddr.sa.sa_len;
02738   }
02739   MEMCPY(name, &saddr, *namelen);
02740 
02741   sock_set_errno(sock, 0);
02742   done_socket(sock);
02743   return 0;
02744 }
02745 
02746 int
02747 lwip_getpeername(int s, struct sockaddr *name, socklen_t *namelen)
02748 {
02749   return lwip_getaddrname(s, name, namelen, 0);
02750 }
02751 
02752 int
02753 lwip_getsockname(int s, struct sockaddr *name, socklen_t *namelen)
02754 {
02755   return lwip_getaddrname(s, name, namelen, 1);
02756 }
02757 
02758 int
02759 lwip_getsockopt(int s, int level, int optname, void *optval, socklen_t *optlen)
02760 {
02761   int err;
02762   struct lwip_sock *sock = get_socket(s);
02763 #if !LWIP_TCPIP_CORE_LOCKING
02764   err_t cberr;
02765   LWIP_SETGETSOCKOPT_DATA_VAR_DECLARE(data);
02766 #endif /* !LWIP_TCPIP_CORE_LOCKING */
02767 
02768   if (!sock) {
02769     return -1;
02770   }
02771 
02772   if ((NULL == optval) || (NULL == optlen)) {
02773     sock_set_errno(sock, EFAULT);
02774     done_socket(sock);
02775     return -1;
02776   }
02777 
02778 #if LWIP_TCPIP_CORE_LOCKING
02779   /* core-locking can just call the -impl function */
02780   LOCK_TCPIP_CORE();
02781   err = lwip_getsockopt_impl(s, level, optname, optval, optlen);
02782   UNLOCK_TCPIP_CORE();
02783 
02784 #else /* LWIP_TCPIP_CORE_LOCKING */
02785 
02786 #if LWIP_MPU_COMPATIBLE
02787   /* MPU_COMPATIBLE copies the optval data, so check for max size here */
02788   if (*optlen > LWIP_SETGETSOCKOPT_MAXOPTLEN) {
02789     sock_set_errno(sock, ENOBUFS);
02790     done_socket(sock);
02791     return -1;
02792   }
02793 #endif /* LWIP_MPU_COMPATIBLE */
02794 
02795   LWIP_SETGETSOCKOPT_DATA_VAR_ALLOC(data, sock);
02796   LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).s = s;
02797   LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).level = level;
02798   LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optname = optname;
02799   LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optlen = *optlen;
02800 #if !LWIP_MPU_COMPATIBLE
02801   LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optval.p = optval;
02802 #endif /* !LWIP_MPU_COMPATIBLE */
02803   LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).err = 0;
02804 #if LWIP_NETCONN_SEM_PER_THREAD
02805   LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).completed_sem = LWIP_NETCONN_THREAD_SEM_GET();
02806 #else
02807   LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).completed_sem = &sock->conn->op_completed;
02808 #endif
02809   cberr = tcpip_callback(lwip_getsockopt_callback, &LWIP_SETGETSOCKOPT_DATA_VAR_REF(data));
02810   if (cberr != ERR_OK) {
02811     LWIP_SETGETSOCKOPT_DATA_VAR_FREE(data);
02812     sock_set_errno(sock, err_to_errno(cberr));
02813     done_socket(sock);
02814     return -1;
02815   }
02816   sys_arch_sem_wait((sys_sem_t *)(LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).completed_sem), 0);
02817 
02818   /* write back optlen and optval */
02819   *optlen = LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optlen;
02820 #if LWIP_MPU_COMPATIBLE
02821   MEMCPY(optval, LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optval,
02822          LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optlen);
02823 #endif /* LWIP_MPU_COMPATIBLE */
02824 
02825   /* maybe lwip_getsockopt_internal has changed err */
02826   err = LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).err;
02827   LWIP_SETGETSOCKOPT_DATA_VAR_FREE(data);
02828 #endif /* LWIP_TCPIP_CORE_LOCKING */
02829 
02830   sock_set_errno(sock, err);
02831   done_socket(sock);
02832   return err ? -1 : 0;
02833 }
02834 
02835 #if !LWIP_TCPIP_CORE_LOCKING
02836 /** lwip_getsockopt_callback: only used without CORE_LOCKING
02837  * to get into the tcpip_thread
02838  */
02839 static void
02840 lwip_getsockopt_callback(void *arg)
02841 {
02842   struct lwip_setgetsockopt_data *data;
02843   LWIP_ASSERT("arg != NULL", arg != NULL);
02844   data = (struct lwip_setgetsockopt_data *)arg;
02845 
02846   data->err = lwip_getsockopt_impl(data->s, data->level, data->optname,
02847 #if LWIP_MPU_COMPATIBLE
02848                                    data->optval,
02849 #else /* LWIP_MPU_COMPATIBLE */
02850                                    data->optval.p,
02851 #endif /* LWIP_MPU_COMPATIBLE */
02852                                    &data->optlen);
02853 
02854   sys_sem_signal((sys_sem_t *)(data->completed_sem));
02855 }
02856 #endif  /* LWIP_TCPIP_CORE_LOCKING */
02857 
02858 static int
02859 lwip_sockopt_to_ipopt(int optname)
02860 {
02861   /* Map SO_* values to our internal SOF_* values
02862    * We should not rely on #defines in socket.h
02863    * being in sync with ip.h.
02864    */
02865   switch (optname) {
02866   case SO_BROADCAST:
02867     return SOF_BROADCAST;
02868   case SO_KEEPALIVE:
02869     return SOF_KEEPALIVE;
02870   case SO_REUSEADDR:
02871     return SOF_REUSEADDR;
02872   default:
02873     LWIP_ASSERT("Unknown socket option", 0);
02874     return 0;
02875   }
02876 }
02877 
02878 /** lwip_getsockopt_impl: the actual implementation of getsockopt:
02879  * same argument as lwip_getsockopt, either called directly or through callback
02880  */
02881 static int
02882 lwip_getsockopt_impl(int s, int level, int optname, void *optval, socklen_t *optlen)
02883 {
02884   int err = 0;
02885   struct lwip_sock *sock = tryget_socket(s);
02886   if (!sock) {
02887     return EBADF;
02888   }
02889 
02890 #ifdef LWIP_HOOK_SOCKETS_GETSOCKOPT
02891   if (LWIP_HOOK_SOCKETS_GETSOCKOPT(s, sock, level, optname, optval, optlen, &err)) {
02892     return err;
02893   }
02894 #endif
02895 
02896   switch (level) {
02897 
02898     /* Level: SOL_SOCKET */
02899     case SOL_SOCKET:
02900       switch (optname) {
02901 
02902 #if LWIP_TCP
02903         case SO_ACCEPTCONN:
02904           LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, *optlen, int);
02905           if (NETCONNTYPE_GROUP(sock->conn->type) != NETCONN_TCP) {
02906             done_socket(sock);
02907             return ENOPROTOOPT;
02908           }
02909           if ((sock->conn->pcb.tcp != NULL) && (sock->conn->pcb.tcp->state == LISTEN)) {
02910             *(int *)optval = 1;
02911           } else {
02912             *(int *)optval = 0;
02913           }
02914           break;
02915 #endif /* LWIP_TCP */
02916 
02917         /* The option flags */
02918         case SO_BROADCAST:
02919         case SO_KEEPALIVE:
02920 #if SO_REUSE
02921         case SO_REUSEADDR:
02922 #endif /* SO_REUSE */
02923           if ((optname == SO_BROADCAST) &&
02924               (NETCONNTYPE_GROUP(sock->conn->type) != NETCONN_UDP)) {
02925             done_socket(sock);
02926             return ENOPROTOOPT;
02927           }
02928 
02929           optname = lwip_sockopt_to_ipopt(optname);
02930 
02931           LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, *optlen, int);
02932           *(int *)optval = ip_get_option(sock->conn->pcb.ip, optname);
02933           LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, optname=0x%x, ..) = %s\n",
02934                                       s, optname, (*(int *)optval ? "on" : "off")));
02935           break;
02936 
02937         case SO_TYPE:
02938           LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, *optlen, int);
02939           switch (NETCONNTYPE_GROUP(netconn_type(sock->conn))) {
02940             case NETCONN_RAW:
02941               *(int *)optval = SOCK_RAW;
02942               break;
02943             case NETCONN_TCP:
02944               *(int *)optval = SOCK_STREAM;
02945               break;
02946             case NETCONN_UDP:
02947               *(int *)optval = SOCK_DGRAM;
02948               break;
02949             default: /* unrecognized socket type */
02950               *(int *)optval = netconn_type(sock->conn);
02951               LWIP_DEBUGF(SOCKETS_DEBUG,
02952                           ("lwip_getsockopt(%d, SOL_SOCKET, SO_TYPE): unrecognized socket type %d\n",
02953                            s, *(int *)optval));
02954           }  /* switch (netconn_type(sock->conn)) */
02955           LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, SO_TYPE) = %d\n",
02956                                       s, *(int *)optval));
02957           break;
02958 
02959         case SO_ERROR:
02960           LWIP_SOCKOPT_CHECK_OPTLEN(sock, *optlen, int);
02961           *(int *)optval = err_to_errno(netconn_err(sock->conn));
02962           LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, SO_ERROR) = %d\n",
02963                                       s, *(int *)optval));
02964           break;
02965 
02966 #if LWIP_SO_SNDTIMEO
02967         case SO_SNDTIMEO:
02968           LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, *optlen, LWIP_SO_SNDRCVTIMEO_OPTTYPE);
02969           LWIP_SO_SNDRCVTIMEO_SET(optval, netconn_get_sendtimeout(sock->conn));
02970           break;
02971 #endif /* LWIP_SO_SNDTIMEO */
02972 #if LWIP_SO_RCVTIMEO
02973         case SO_RCVTIMEO:
02974           LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, *optlen, LWIP_SO_SNDRCVTIMEO_OPTTYPE);
02975           LWIP_SO_SNDRCVTIMEO_SET(optval, netconn_get_recvtimeout(sock->conn));
02976           break;
02977 #endif /* LWIP_SO_RCVTIMEO */
02978 #if LWIP_SO_RCVBUF
02979         case SO_RCVBUF:
02980           LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, *optlen, int);
02981           *(int *)optval = netconn_get_recvbufsize(sock->conn);
02982           break;
02983 #endif /* LWIP_SO_RCVBUF */
02984 #if LWIP_SO_LINGER
02985         case SO_LINGER: {
02986           s16_t conn_linger;
02987           struct linger *linger = (struct linger *)optval;
02988           LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, *optlen, struct linger);
02989           conn_linger = sock->conn->linger;
02990           if (conn_linger >= 0) {
02991             linger->l_onoff = 1;
02992             linger->l_linger = (int)conn_linger;
02993           } else {
02994             linger->l_onoff = 0;
02995             linger->l_linger = 0;
02996           }
02997         }
02998         break;
02999 #endif /* LWIP_SO_LINGER */
03000 #if LWIP_UDP
03001         case SO_NO_CHECK:
03002           LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, *optlen, int, NETCONN_UDP);
03003 #if LWIP_UDPLITE
03004           if (udp_is_flag_set(sock->conn->pcb.udp, UDP_FLAGS_UDPLITE)) {
03005             /* this flag is only available for UDP, not for UDP lite */
03006             done_socket(sock);
03007             return EAFNOSUPPORT;
03008           }
03009 #endif /* LWIP_UDPLITE */
03010           *(int *)optval = udp_is_flag_set(sock->conn->pcb.udp, UDP_FLAGS_NOCHKSUM) ? 1 : 0;
03011           break;
03012 #endif /* LWIP_UDP*/
03013         default:
03014           LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, UNIMPL: optname=0x%x, ..)\n",
03015                                       s, optname));
03016           err = ENOPROTOOPT;
03017           break;
03018       }  /* switch (optname) */
03019       break;
03020 
03021     /* Level: IPPROTO_IP */
03022     case IPPROTO_IP:
03023       switch (optname) {
03024         case IP_TTL:
03025           LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, *optlen, int);
03026           *(int *)optval = sock->conn->pcb.ip->ttl;
03027           LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_TTL) = %d\n",
03028                                       s, *(int *)optval));
03029           break;
03030         case IP_TOS:
03031           LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, *optlen, int);
03032           *(int *)optval = sock->conn->pcb.ip->tos;
03033           LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_TOS) = %d\n",
03034                                       s, *(int *)optval));
03035           break;
03036 #if LWIP_IPV4 && LWIP_MULTICAST_TX_OPTIONS && LWIP_UDP
03037         case IP_MULTICAST_TTL:
03038           LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, *optlen, u8_t);
03039           if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_UDP) {
03040             done_socket(sock);
03041             return ENOPROTOOPT;
03042           }
03043           *(u8_t *)optval = udp_get_multicast_ttl(sock->conn->pcb.udp);
03044           LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_MULTICAST_TTL) = %d\n",
03045                                       s, *(int *)optval));
03046           break;
03047         case IP_MULTICAST_IF:
03048           LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, *optlen, struct in_addr);
03049           if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_UDP) {
03050             done_socket(sock);
03051             return ENOPROTOOPT;
03052           }
03053           inet_addr_from_ip4addr((struct in_addr *)optval, udp_get_multicast_netif_addr(sock->conn->pcb.udp));
03054           LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_MULTICAST_IF) = 0x%"X32_F"\n",
03055                                       s, *(u32_t *)optval));
03056           break;
03057         case IP_MULTICAST_LOOP:
03058           LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, *optlen, u8_t);
03059           if ((sock->conn->pcb.udp->flags & UDP_FLAGS_MULTICAST_LOOP) != 0) {
03060             *(u8_t *)optval = 1;
03061           } else {
03062             *(u8_t *)optval = 0;
03063           }
03064           LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_MULTICAST_LOOP) = %d\n",
03065                                       s, *(int *)optval));
03066           break;
03067 #endif /* LWIP_IPV4 && LWIP_MULTICAST_TX_OPTIONS && LWIP_UDP */
03068         default:
03069           LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, UNIMPL: optname=0x%x, ..)\n",
03070                                       s, optname));
03071           err = ENOPROTOOPT;
03072           break;
03073       }  /* switch (optname) */
03074       break;
03075 
03076 #if LWIP_TCP
03077     /* Level: IPPROTO_TCP */
03078     case IPPROTO_TCP:
03079       /* Special case: all IPPROTO_TCP option take an int */
03080       LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, *optlen, int, NETCONN_TCP);
03081       if (sock->conn->pcb.tcp->state == LISTEN) {
03082         done_socket(sock);
03083         return EINVAL;
03084       }
03085       switch (optname) {
03086         case TCP_NODELAY:
03087           *(int *)optval = tcp_nagle_disabled(sock->conn->pcb.tcp);
03088           LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_TCP, TCP_NODELAY) = %s\n",
03089                                       s, (*(int *)optval) ? "on" : "off") );
03090           break;
03091         case TCP_KEEPALIVE:
03092           *(int *)optval = (int)sock->conn->pcb.tcp->keep_idle;
03093           LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_TCP, TCP_KEEPALIVE) = %d\n",
03094                                       s, *(int *)optval));
03095           break;
03096 
03097 #if LWIP_TCP_KEEPALIVE
03098         case TCP_KEEPIDLE:
03099           *(int *)optval = (int)(sock->conn->pcb.tcp->keep_idle / 1000);
03100           LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_TCP, TCP_KEEPIDLE) = %d\n",
03101                                       s, *(int *)optval));
03102           break;
03103         case TCP_KEEPINTVL:
03104           *(int *)optval = (int)(sock->conn->pcb.tcp->keep_intvl / 1000);
03105           LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_TCP, TCP_KEEPINTVL) = %d\n",
03106                                       s, *(int *)optval));
03107           break;
03108         case TCP_KEEPCNT:
03109           *(int *)optval = (int)sock->conn->pcb.tcp->keep_cnt;
03110           LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_TCP, TCP_KEEPCNT) = %d\n",
03111                                       s, *(int *)optval));
03112           break;
03113 #endif /* LWIP_TCP_KEEPALIVE */
03114         default:
03115           LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_TCP, UNIMPL: optname=0x%x, ..)\n",
03116                                       s, optname));
03117           err = ENOPROTOOPT;
03118           break;
03119       }  /* switch (optname) */
03120       break;
03121 #endif /* LWIP_TCP */
03122 
03123 #if LWIP_IPV6
03124     /* Level: IPPROTO_IPV6 */
03125     case IPPROTO_IPV6:
03126       switch (optname) {
03127         case IPV6_V6ONLY:
03128           LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, *optlen, int);
03129           *(int *)optval = (netconn_get_ipv6only(sock->conn) ? 1 : 0);
03130           LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IPV6, IPV6_V6ONLY) = %d\n",
03131                                       s, *(int *)optval));
03132           break;
03133         default:
03134           LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IPV6, UNIMPL: optname=0x%x, ..)\n",
03135                                       s, optname));
03136           err = ENOPROTOOPT;
03137           break;
03138       }  /* switch (optname) */
03139       break;
03140 #endif /* LWIP_IPV6 */
03141 
03142 #if LWIP_UDP && LWIP_UDPLITE
03143     /* Level: IPPROTO_UDPLITE */
03144     case IPPROTO_UDPLITE:
03145       /* Special case: all IPPROTO_UDPLITE option take an int */
03146       LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, *optlen, int);
03147       /* If this is no UDP lite socket, ignore any options. */
03148       if (!NETCONNTYPE_ISUDPLITE(netconn_type(sock->conn))) {
03149         done_socket(sock);
03150         return ENOPROTOOPT;
03151       }
03152       switch (optname) {
03153         case UDPLITE_SEND_CSCOV:
03154           *(int *)optval = sock->conn->pcb.udp->chksum_len_tx;
03155           LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_UDPLITE, UDPLITE_SEND_CSCOV) = %d\n",
03156                                       s, (*(int *)optval)) );
03157           break;
03158         case UDPLITE_RECV_CSCOV:
03159           *(int *)optval = sock->conn->pcb.udp->chksum_len_rx;
03160           LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_UDPLITE, UDPLITE_RECV_CSCOV) = %d\n",
03161                                       s, (*(int *)optval)) );
03162           break;
03163         default:
03164           LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_UDPLITE, UNIMPL: optname=0x%x, ..)\n",
03165                                       s, optname));
03166           err = ENOPROTOOPT;
03167           break;
03168       }  /* switch (optname) */
03169       break;
03170 #endif /* LWIP_UDP */
03171     /* Level: IPPROTO_RAW */
03172     case IPPROTO_RAW:
03173       switch (optname) {
03174 #if LWIP_IPV6 && LWIP_RAW
03175         case IPV6_CHECKSUM:
03176           LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, *optlen, int, NETCONN_RAW);
03177           if (sock->conn->pcb.raw->chksum_reqd == 0) {
03178             *(int *)optval = -1;
03179           } else {
03180             *(int *)optval = sock->conn->pcb.raw->chksum_offset;
03181           }
03182           LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_RAW, IPV6_CHECKSUM) = %d\n",
03183                                       s, (*(int *)optval)) );
03184           break;
03185 #endif /* LWIP_IPV6 && LWIP_RAW */
03186         default:
03187           LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_RAW, UNIMPL: optname=0x%x, ..)\n",
03188                                       s, optname));
03189           err = ENOPROTOOPT;
03190           break;
03191       }  /* switch (optname) */
03192       break;
03193     default:
03194       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, level=0x%x, UNIMPL: optname=0x%x, ..)\n",
03195                                   s, level, optname));
03196       err = ENOPROTOOPT;
03197       break;
03198   } /* switch (level) */
03199 
03200   done_socket(sock);
03201   return err;
03202 }
03203 
03204 int
03205 lwip_setsockopt(int s, int level, int optname, const void *optval, socklen_t optlen)
03206 {
03207   int err = 0;
03208   struct lwip_sock *sock = get_socket(s);
03209 #if !LWIP_TCPIP_CORE_LOCKING
03210   err_t cberr;
03211   LWIP_SETGETSOCKOPT_DATA_VAR_DECLARE(data);
03212 #endif /* !LWIP_TCPIP_CORE_LOCKING */
03213 
03214   if (!sock) {
03215     return -1;
03216   }
03217 
03218   if (NULL == optval) {
03219     sock_set_errno(sock, EFAULT);
03220     done_socket(sock);
03221     return -1;
03222   }
03223 
03224 #if LWIP_TCPIP_CORE_LOCKING
03225   /* core-locking can just call the -impl function */
03226   LOCK_TCPIP_CORE();
03227   err = lwip_setsockopt_impl(s, level, optname, optval, optlen);
03228   UNLOCK_TCPIP_CORE();
03229 
03230 #else /* LWIP_TCPIP_CORE_LOCKING */
03231 
03232 #if LWIP_MPU_COMPATIBLE
03233   /* MPU_COMPATIBLE copies the optval data, so check for max size here */
03234   if (optlen > LWIP_SETGETSOCKOPT_MAXOPTLEN) {
03235     sock_set_errno(sock, ENOBUFS);
03236     done_socket(sock);
03237     return -1;
03238   }
03239 #endif /* LWIP_MPU_COMPATIBLE */
03240 
03241   LWIP_SETGETSOCKOPT_DATA_VAR_ALLOC(data, sock);
03242   LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).s = s;
03243   LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).level = level;
03244   LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optname = optname;
03245   LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optlen = optlen;
03246 #if LWIP_MPU_COMPATIBLE
03247   MEMCPY(LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optval, optval, optlen);
03248 #else /* LWIP_MPU_COMPATIBLE */
03249   LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optval.pc = (const void *)optval;
03250 #endif /* LWIP_MPU_COMPATIBLE */
03251   LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).err = 0;
03252 #if LWIP_NETCONN_SEM_PER_THREAD
03253   LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).completed_sem = LWIP_NETCONN_THREAD_SEM_GET();
03254 #else
03255   LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).completed_sem = &sock->conn->op_completed;
03256 #endif
03257   cberr = tcpip_callback(lwip_setsockopt_callback, &LWIP_SETGETSOCKOPT_DATA_VAR_REF(data));
03258   if (cberr != ERR_OK) {
03259     LWIP_SETGETSOCKOPT_DATA_VAR_FREE(data);
03260     sock_set_errno(sock, err_to_errno(cberr));
03261     done_socket(sock);
03262     return -1;
03263   }
03264   sys_arch_sem_wait((sys_sem_t *)(LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).completed_sem), 0);
03265 
03266   /* maybe lwip_getsockopt_internal has changed err */
03267   err = LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).err;
03268   LWIP_SETGETSOCKOPT_DATA_VAR_FREE(data);
03269 #endif  /* LWIP_TCPIP_CORE_LOCKING */
03270 
03271   sock_set_errno(sock, err);
03272   done_socket(sock);
03273   return err ? -1 : 0;
03274 }
03275 
03276 #if !LWIP_TCPIP_CORE_LOCKING
03277 /** lwip_setsockopt_callback: only used without CORE_LOCKING
03278  * to get into the tcpip_thread
03279  */
03280 static void
03281 lwip_setsockopt_callback(void *arg)
03282 {
03283   struct lwip_setgetsockopt_data *data;
03284   LWIP_ASSERT("arg != NULL", arg != NULL);
03285   data = (struct lwip_setgetsockopt_data *)arg;
03286 
03287   data->err = lwip_setsockopt_impl(data->s, data->level, data->optname,
03288 #if LWIP_MPU_COMPATIBLE
03289                                    data->optval,
03290 #else /* LWIP_MPU_COMPATIBLE */
03291                                    data->optval.pc,
03292 #endif /* LWIP_MPU_COMPATIBLE */
03293                                    data->optlen);
03294 
03295   sys_sem_signal((sys_sem_t *)(data->completed_sem));
03296 }
03297 #endif  /* LWIP_TCPIP_CORE_LOCKING */
03298 
03299 /** lwip_setsockopt_impl: the actual implementation of setsockopt:
03300  * same argument as lwip_setsockopt, either called directly or through callback
03301  */
03302 static int
03303 lwip_setsockopt_impl(int s, int level, int optname, const void *optval, socklen_t optlen)
03304 {
03305   int err = 0;
03306   struct lwip_sock *sock = tryget_socket(s);
03307   if (!sock) {
03308     return EBADF;
03309   }
03310 
03311 #ifdef LWIP_HOOK_SOCKETS_SETSOCKOPT
03312   if (LWIP_HOOK_SOCKETS_SETSOCKOPT(s, sock, level, optname, optval, optlen, &err)) {
03313     return err;
03314   }
03315 #endif
03316 
03317   switch (level) {
03318 
03319     /* Level: SOL_SOCKET */
03320     case SOL_SOCKET:
03321       switch (optname) {
03322 
03323         /* SO_ACCEPTCONN is get-only */
03324 
03325         /* The option flags */
03326         case SO_BROADCAST:
03327         case SO_KEEPALIVE:
03328 #if SO_REUSE
03329         case SO_REUSEADDR:
03330 #endif /* SO_REUSE */
03331           if ((optname == SO_BROADCAST) &&
03332               (NETCONNTYPE_GROUP(sock->conn->type) != NETCONN_UDP)) {
03333             done_socket(sock);
03334             return ENOPROTOOPT;
03335           }
03336 
03337           optname = lwip_sockopt_to_ipopt(optname);
03338 
03339           LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, optlen, int);
03340           if (*(const int *)optval) {
03341             ip_set_option(sock->conn->pcb.ip, optname);
03342           } else {
03343             ip_reset_option(sock->conn->pcb.ip, optname);
03344           }
03345           LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, SOL_SOCKET, optname=0x%x, ..) -> %s\n",
03346                                       s, optname, (*(const int *)optval ? "on" : "off")));
03347           break;
03348 
03349           /* SO_TYPE is get-only */
03350           /* SO_ERROR is get-only */
03351 
03352 #if LWIP_SO_SNDTIMEO
03353         case SO_SNDTIMEO: {
03354           long ms_long;
03355           LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, optlen, LWIP_SO_SNDRCVTIMEO_OPTTYPE);
03356           ms_long = LWIP_SO_SNDRCVTIMEO_GET_MS(optval);
03357           if (ms_long < 0) {
03358             done_socket(sock);
03359             return EINVAL;
03360           }
03361           netconn_set_sendtimeout(sock->conn, ms_long);
03362           break;
03363         }
03364 #endif /* LWIP_SO_SNDTIMEO */
03365 #if LWIP_SO_RCVTIMEO
03366         case SO_RCVTIMEO: {
03367           long ms_long;
03368           LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, optlen, LWIP_SO_SNDRCVTIMEO_OPTTYPE);
03369           ms_long = LWIP_SO_SNDRCVTIMEO_GET_MS(optval);
03370           if (ms_long < 0) {
03371             done_socket(sock);
03372             return EINVAL;
03373           }
03374           netconn_set_recvtimeout(sock->conn, (u32_t)ms_long);
03375           break;
03376         }
03377 #endif /* LWIP_SO_RCVTIMEO */
03378 #if LWIP_SO_RCVBUF
03379         case SO_RCVBUF:
03380           LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, optlen, int);
03381           netconn_set_recvbufsize(sock->conn, *(const int *)optval);
03382           break;
03383 #endif /* LWIP_SO_RCVBUF */
03384 #if LWIP_SO_LINGER
03385         case SO_LINGER: {
03386           const struct linger *linger = (const struct linger *)optval;
03387           LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, optlen, struct linger);
03388           if (linger->l_onoff) {
03389             int lingersec = linger->l_linger;
03390             if (lingersec < 0) {
03391               done_socket(sock);
03392               return EINVAL;
03393             }
03394             if (lingersec > 0xFFFF) {
03395               lingersec = 0xFFFF;
03396             }
03397             sock->conn->linger = (s16_t)lingersec;
03398           } else {
03399             sock->conn->linger = -1;
03400           }
03401         }
03402         break;
03403 #endif /* LWIP_SO_LINGER */
03404 #if LWIP_UDP
03405         case SO_NO_CHECK:
03406           LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, int, NETCONN_UDP);
03407 #if LWIP_UDPLITE
03408           if (udp_is_flag_set(sock->conn->pcb.udp, UDP_FLAGS_UDPLITE)) {
03409             /* this flag is only available for UDP, not for UDP lite */
03410             done_socket(sock);
03411             return EAFNOSUPPORT;
03412           }
03413 #endif /* LWIP_UDPLITE */
03414           if (*(const int *)optval) {
03415             udp_set_flags(sock->conn->pcb.udp, UDP_FLAGS_NOCHKSUM);
03416           } else {
03417             udp_clear_flags(sock->conn->pcb.udp, UDP_FLAGS_NOCHKSUM);
03418           }
03419           break;
03420 #endif /* LWIP_UDP */
03421         case SO_BINDTODEVICE: {
03422           const struct ifreq *iface;
03423           struct netif *n = NULL;
03424 
03425           LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, optlen, struct ifreq);
03426 
03427           iface = (const struct ifreq *)optval;
03428           if (iface->ifr_name[0] != 0) {
03429             n = netif_find(iface->ifr_name);
03430             if (n == NULL) {
03431               done_socket(sock);
03432               return ENODEV;
03433             }
03434           }
03435 
03436           switch (NETCONNTYPE_GROUP(netconn_type(sock->conn))) {
03437 #if LWIP_TCP
03438             case NETCONN_TCP:
03439               tcp_bind_netif(sock->conn->pcb.tcp, n);
03440               break;
03441 #endif
03442 #if LWIP_UDP
03443             case NETCONN_UDP:
03444               udp_bind_netif(sock->conn->pcb.udp, n);
03445               break;
03446 #endif
03447 #if LWIP_RAW
03448             case NETCONN_RAW:
03449               raw_bind_netif(sock->conn->pcb.raw, n);
03450               break;
03451 #endif
03452             default:
03453               LWIP_ASSERT("Unhandled netconn type in SO_BINDTODEVICE", 0);
03454               break;
03455           }
03456         }
03457         break;
03458         default:
03459           LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, SOL_SOCKET, UNIMPL: optname=0x%x, ..)\n",
03460                                       s, optname));
03461           err = ENOPROTOOPT;
03462           break;
03463       }  /* switch (optname) */
03464       break;
03465 
03466     /* Level: IPPROTO_IP */
03467     case IPPROTO_IP:
03468       switch (optname) {
03469         case IP_TTL:
03470           LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, optlen, int);
03471           sock->conn->pcb.ip->ttl = (u8_t)(*(const int *)optval);
03472           LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IP, IP_TTL, ..) -> %d\n",
03473                                       s, sock->conn->pcb.ip->ttl));
03474           break;
03475         case IP_TOS:
03476           LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, optlen, int);
03477           sock->conn->pcb.ip->tos = (u8_t)(*(const int *)optval);
03478           LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IP, IP_TOS, ..)-> %d\n",
03479                                       s, sock->conn->pcb.ip->tos));
03480           break;
03481 #if LWIP_NETBUF_RECVINFO
03482         case IP_PKTINFO:
03483           LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, int, NETCONN_UDP);
03484           if (*(const int *)optval) {
03485             sock->conn->flags |= NETCONN_FLAG_PKTINFO;
03486           } else {
03487             sock->conn->flags &= ~NETCONN_FLAG_PKTINFO;
03488           }
03489           break;
03490 #endif /* LWIP_NETBUF_RECVINFO */
03491 #if LWIP_IPV4 && LWIP_MULTICAST_TX_OPTIONS && LWIP_UDP
03492         case IP_MULTICAST_TTL:
03493           LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, u8_t, NETCONN_UDP);
03494           udp_set_multicast_ttl(sock->conn->pcb.udp, (u8_t)(*(const u8_t *)optval));
03495           break;
03496         case IP_MULTICAST_IF: {
03497           ip4_addr_t if_addr;
03498           LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, struct in_addr, NETCONN_UDP);
03499           inet_addr_to_ip4addr(&if_addr, (const struct in_addr *)optval);
03500           udp_set_multicast_netif_addr(sock->conn->pcb.udp, &if_addr);
03501         }
03502         break;
03503         case IP_MULTICAST_LOOP:
03504           LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, u8_t, NETCONN_UDP);
03505           if (*(const u8_t *)optval) {
03506             udp_set_flags(sock->conn->pcb.udp, UDP_FLAGS_MULTICAST_LOOP);
03507           } else {
03508             udp_clear_flags(sock->conn->pcb.udp, UDP_FLAGS_MULTICAST_LOOP);
03509           }
03510           break;
03511 #endif /* LWIP_IPV4 && LWIP_MULTICAST_TX_OPTIONS && LWIP_UDP */
03512 #if LWIP_IGMP
03513         case IP_ADD_MEMBERSHIP:
03514         case IP_DROP_MEMBERSHIP: {
03515           /* If this is a TCP or a RAW socket, ignore these options. */
03516           err_t igmp_err;
03517           const struct ip_mreq *imr = (const struct ip_mreq *)optval;
03518           ip4_addr_t if_addr;
03519           ip4_addr_t multi_addr;
03520           LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, struct ip_mreq, NETCONN_UDP);
03521           inet_addr_to_ip4addr(&if_addr, &imr->imr_interface);
03522           inet_addr_to_ip4addr(&multi_addr, &imr->imr_multiaddr);
03523           if (optname == IP_ADD_MEMBERSHIP) {
03524             if (!lwip_socket_register_membership(s, &if_addr, &multi_addr)) {
03525               /* cannot track membership (out of memory) */
03526               err = ENOMEM;
03527               igmp_err = ERR_OK;
03528             } else {
03529               igmp_err = igmp_joingroup(&if_addr, &multi_addr);
03530             }
03531           } else {
03532             igmp_err = igmp_leavegroup(&if_addr, &multi_addr);
03533             lwip_socket_unregister_membership(s, &if_addr, &multi_addr);
03534           }
03535           if (igmp_err != ERR_OK) {
03536             err = EADDRNOTAVAIL;
03537           }
03538         }
03539         break;
03540 #endif /* LWIP_IGMP */
03541         default:
03542           LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IP, UNIMPL: optname=0x%x, ..)\n",
03543                                       s, optname));
03544           err = ENOPROTOOPT;
03545           break;
03546       }  /* switch (optname) */
03547       break;
03548 
03549 #if LWIP_TCP
03550     /* Level: IPPROTO_TCP */
03551     case IPPROTO_TCP:
03552       /* Special case: all IPPROTO_TCP option take an int */
03553       LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, int, NETCONN_TCP);
03554       if (sock->conn->pcb.tcp->state == LISTEN) {
03555         done_socket(sock);
03556         return EINVAL;
03557       }
03558       switch (optname) {
03559         case TCP_NODELAY:
03560           if (*(const int *)optval) {
03561             tcp_nagle_disable(sock->conn->pcb.tcp);
03562           } else {
03563             tcp_nagle_enable(sock->conn->pcb.tcp);
03564           }
03565           LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_NODELAY) -> %s\n",
03566                                       s, (*(const int *)optval) ? "on" : "off") );
03567           break;
03568         case TCP_KEEPALIVE:
03569           sock->conn->pcb.tcp->keep_idle = (u32_t)(*(const int *)optval);
03570           LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPALIVE) -> %"U32_F"\n",
03571                                       s, sock->conn->pcb.tcp->keep_idle));
03572           break;
03573 
03574 #if LWIP_TCP_KEEPALIVE
03575         case TCP_KEEPIDLE:
03576           sock->conn->pcb.tcp->keep_idle = 1000 * (u32_t)(*(const int *)optval);
03577           LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPIDLE) -> %"U32_F"\n",
03578                                       s, sock->conn->pcb.tcp->keep_idle));
03579           break;
03580         case TCP_KEEPINTVL:
03581           sock->conn->pcb.tcp->keep_intvl = 1000 * (u32_t)(*(const int *)optval);
03582           LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPINTVL) -> %"U32_F"\n",
03583                                       s, sock->conn->pcb.tcp->keep_intvl));
03584           break;
03585         case TCP_KEEPCNT:
03586           sock->conn->pcb.tcp->keep_cnt = (u32_t)(*(const int *)optval);
03587           LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPCNT) -> %"U32_F"\n",
03588                                       s, sock->conn->pcb.tcp->keep_cnt));
03589           break;
03590 #endif /* LWIP_TCP_KEEPALIVE */
03591         default:
03592           LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, UNIMPL: optname=0x%x, ..)\n",
03593                                       s, optname));
03594           err = ENOPROTOOPT;
03595           break;
03596       }  /* switch (optname) */
03597       break;
03598 #endif /* LWIP_TCP*/
03599 
03600 #if LWIP_IPV6
03601     /* Level: IPPROTO_IPV6 */
03602     case IPPROTO_IPV6:
03603       switch (optname) {
03604         case IPV6_V6ONLY:
03605           LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, optlen, int);
03606           if (*(const int *)optval) {
03607             netconn_set_ipv6only(sock->conn, 1);
03608           } else {
03609             netconn_set_ipv6only(sock->conn, 0);
03610           }
03611           LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IPV6, IPV6_V6ONLY, ..) -> %d\n",
03612                                       s, (netconn_get_ipv6only(sock->conn) ? 1 : 0)));
03613           break;
03614 #if LWIP_IPV6_MLD
03615         case IPV6_JOIN_GROUP:
03616         case IPV6_LEAVE_GROUP: {
03617           /* If this is a TCP or a RAW socket, ignore these options. */
03618           err_t mld6_err;
03619           struct netif *netif;
03620           ip6_addr_t multi_addr;
03621           const struct ipv6_mreq *imr = (const struct ipv6_mreq *)optval;
03622           LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, struct ipv6_mreq, NETCONN_UDP);
03623           inet6_addr_to_ip6addr(&multi_addr, &imr->ipv6mr_multiaddr);
03624           LWIP_ASSERT("Invalid netif index", imr->ipv6mr_interface <= 0xFFu);
03625           netif = netif_get_by_index((u8_t)imr->ipv6mr_interface);
03626           if (netif == NULL) {
03627             err = EADDRNOTAVAIL;
03628             break;
03629           }
03630 
03631           if (optname == IPV6_JOIN_GROUP) {
03632             if (!lwip_socket_register_mld6_membership(s, imr->ipv6mr_interface, &multi_addr)) {
03633               /* cannot track membership (out of memory) */
03634               err = ENOMEM;
03635               mld6_err = ERR_OK;
03636             } else {
03637               mld6_err = mld6_joingroup_netif(netif, &multi_addr);
03638             }
03639           } else {
03640             mld6_err = mld6_leavegroup_netif(netif, &multi_addr);
03641             lwip_socket_unregister_mld6_membership(s, imr->ipv6mr_interface, &multi_addr);
03642           }
03643           if (mld6_err != ERR_OK) {
03644             err = EADDRNOTAVAIL;
03645           }
03646         }
03647         break;
03648 #endif /* LWIP_IPV6_MLD */
03649         default:
03650           LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IPV6, UNIMPL: optname=0x%x, ..)\n",
03651                                       s, optname));
03652           err = ENOPROTOOPT;
03653           break;
03654       }  /* switch (optname) */
03655       break;
03656 #endif /* LWIP_IPV6 */
03657 
03658 #if LWIP_UDP && LWIP_UDPLITE
03659     /* Level: IPPROTO_UDPLITE */
03660     case IPPROTO_UDPLITE:
03661       /* Special case: all IPPROTO_UDPLITE option take an int */
03662       LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, optlen, int);
03663       /* If this is no UDP lite socket, ignore any options. */
03664       if (!NETCONNTYPE_ISUDPLITE(netconn_type(sock->conn))) {
03665         done_socket(sock);
03666         return ENOPROTOOPT;
03667       }
03668       switch (optname) {
03669         case UDPLITE_SEND_CSCOV:
03670           if ((*(const int *)optval != 0) && ((*(const int *)optval < 8) || (*(const int *)optval > 0xffff))) {
03671             /* don't allow illegal values! */
03672             sock->conn->pcb.udp->chksum_len_tx = 8;
03673           } else {
03674             sock->conn->pcb.udp->chksum_len_tx = (u16_t) * (const int *)optval;
03675           }
03676           LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_UDPLITE, UDPLITE_SEND_CSCOV) -> %d\n",
03677                                       s, (*(const int *)optval)) );
03678           break;
03679         case UDPLITE_RECV_CSCOV:
03680           if ((*(const int *)optval != 0) && ((*(const int *)optval < 8) || (*(const int *)optval > 0xffff))) {
03681             /* don't allow illegal values! */
03682             sock->conn->pcb.udp->chksum_len_rx = 8;
03683           } else {
03684             sock->conn->pcb.udp->chksum_len_rx = (u16_t) * (const int *)optval;
03685           }
03686           LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_UDPLITE, UDPLITE_RECV_CSCOV) -> %d\n",
03687                                       s, (*(const int *)optval)) );
03688           break;
03689         default:
03690           LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_UDPLITE, UNIMPL: optname=0x%x, ..)\n",
03691                                       s, optname));
03692           err = ENOPROTOOPT;
03693           break;
03694       }  /* switch (optname) */
03695       break;
03696 #endif /* LWIP_UDP */
03697     /* Level: IPPROTO_RAW */
03698     case IPPROTO_RAW:
03699       switch (optname) {
03700 #if LWIP_IPV6 && LWIP_RAW
03701         case IPV6_CHECKSUM:
03702           /* It should not be possible to disable the checksum generation with ICMPv6
03703            * as per RFC 3542 chapter 3.1 */
03704           if (sock->conn->pcb.raw->protocol == IPPROTO_ICMPV6) {
03705             done_socket(sock);
03706             return EINVAL;
03707           }
03708 
03709           LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, int, NETCONN_RAW);
03710           if (*(const int *)optval < 0) {
03711             sock->conn->pcb.raw->chksum_reqd = 0;
03712           } else if (*(const int *)optval & 1) {
03713             /* Per RFC3542, odd offsets are not allowed */
03714             done_socket(sock);
03715             return EINVAL;
03716           } else {
03717             sock->conn->pcb.raw->chksum_reqd = 1;
03718             sock->conn->pcb.raw->chksum_offset = (u16_t) * (const int *)optval;
03719           }
03720           LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_RAW, IPV6_CHECKSUM, ..) -> %d\n",
03721                                       s, sock->conn->pcb.raw->chksum_reqd));
03722           break;
03723 #endif /* LWIP_IPV6 && LWIP_RAW */
03724         default:
03725           LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_RAW, UNIMPL: optname=0x%x, ..)\n",
03726                                       s, optname));
03727           err = ENOPROTOOPT;
03728           break;
03729       }  /* switch (optname) */
03730       break;
03731     default:
03732       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, level=0x%x, UNIMPL: optname=0x%x, ..)\n",
03733                                   s, level, optname));
03734       err = ENOPROTOOPT;
03735       break;
03736   }  /* switch (level) */
03737 
03738   done_socket(sock);
03739   return err;
03740 }
03741 
03742 int
03743 lwip_ioctl(int s, long cmd, void *argp)
03744 {
03745   struct lwip_sock *sock = get_socket(s);
03746   u8_t val;
03747 #if LWIP_SO_RCVBUF
03748   int recv_avail;
03749 #endif /* LWIP_SO_RCVBUF */
03750 
03751   if (!sock) {
03752     return -1;
03753   }
03754 
03755   switch (cmd) {
03756 #if LWIP_SO_RCVBUF || LWIP_FIONREAD_LINUXMODE
03757     case FIONREAD:
03758       if (!argp) {
03759         sock_set_errno(sock, EINVAL);
03760         done_socket(sock);
03761         return -1;
03762       }
03763 #if LWIP_FIONREAD_LINUXMODE
03764       if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_TCP) {
03765         struct netbuf *nb;
03766         if (sock->lastdata.netbuf) {
03767           nb = sock->lastdata.netbuf;
03768           *((int *)argp) = nb->p->tot_len;
03769         } else {
03770           struct netbuf *rxbuf;
03771           err_t err = netconn_recv_udp_raw_netbuf_flags(sock->conn, &rxbuf, NETCONN_DONTBLOCK);
03772           if (err != ERR_OK) {
03773             *((int *)argp) = 0;
03774           } else {
03775             sock->lastdata.netbuf = rxbuf;
03776             *((int *)argp) = rxbuf->p->tot_len;
03777           }
03778         }
03779         done_socket(sock);
03780         return 0;
03781       }
03782 #endif /* LWIP_FIONREAD_LINUXMODE */
03783 
03784 #if LWIP_SO_RCVBUF
03785       /* we come here if either LWIP_FIONREAD_LINUXMODE==0 or this is a TCP socket */
03786       SYS_ARCH_GET(sock->conn->recv_avail, recv_avail);
03787       if (recv_avail < 0) {
03788         recv_avail = 0;
03789       }
03790 
03791       /* Check if there is data left from the last recv operation. /maq 041215 */
03792       if (sock->lastdata.netbuf) {
03793         if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) {
03794           recv_avail += sock->lastdata.pbuf->tot_len;
03795         } else {
03796           recv_avail += sock->lastdata.netbuf->p->tot_len;
03797         }
03798       }
03799       *((int *)argp) = recv_avail;
03800 
03801       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(%d, FIONREAD, %p) = %"U16_F"\n", s, argp, *((u16_t *)argp)));
03802       sock_set_errno(sock, 0);
03803       done_socket(sock);
03804       return 0;
03805 #else /* LWIP_SO_RCVBUF */
03806       break;
03807 #endif /* LWIP_SO_RCVBUF */
03808 #endif /* LWIP_SO_RCVBUF || LWIP_FIONREAD_LINUXMODE */
03809 
03810     case (long)FIONBIO:
03811       val = 0;
03812       if (argp && *(int *)argp) {
03813         val = 1;
03814       }
03815       netconn_set_nonblocking(sock->conn, val);
03816       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(%d, FIONBIO, %d)\n", s, val));
03817       sock_set_errno(sock, 0);
03818       done_socket(sock);
03819       return 0;
03820 
03821     default:
03822       break;
03823   } /* switch (cmd) */
03824   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(%d, UNIMPL: 0x%lx, %p)\n", s, cmd, argp));
03825   sock_set_errno(sock, ENOSYS); /* not yet implemented */
03826   done_socket(sock);
03827   return -1;
03828 }
03829 
03830 /** A minimal implementation of fcntl.
03831  * Currently only the commands F_GETFL and F_SETFL are implemented.
03832  * The flag O_NONBLOCK and access modes are supported for F_GETFL, only
03833  * the flag O_NONBLOCK is implemented for F_SETFL.
03834  */
03835 int
03836 lwip_fcntl(int s, int cmd, int val)
03837 {
03838   struct lwip_sock *sock = get_socket(s);
03839   int ret = -1;
03840   int op_mode = 0;
03841 
03842   if (!sock) {
03843     return -1;
03844   }
03845 
03846   switch (cmd) {
03847     case F_GETFL:
03848       ret = netconn_is_nonblocking(sock->conn) ? O_NONBLOCK : 0;
03849       sock_set_errno(sock, 0);
03850 
03851       if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) {
03852 #if LWIP_TCPIP_CORE_LOCKING
03853         LOCK_TCPIP_CORE();
03854 #else
03855         SYS_ARCH_DECL_PROTECT(lev);
03856         /* the proper thing to do here would be to get into the tcpip_thread,
03857            but locking should be OK as well since we only *read* some flags */
03858         SYS_ARCH_PROTECT(lev);
03859 #endif
03860 #if LWIP_TCP
03861         if (sock->conn->pcb.tcp) {
03862           if (!(sock->conn->pcb.tcp->flags & TF_RXCLOSED)) {
03863             op_mode |= O_RDONLY;
03864           }
03865           if (!(sock->conn->pcb.tcp->flags & TF_FIN)) {
03866             op_mode |= O_WRONLY;
03867           }
03868         }
03869 #endif
03870 #if LWIP_TCPIP_CORE_LOCKING
03871         UNLOCK_TCPIP_CORE();
03872 #else
03873         SYS_ARCH_UNPROTECT(lev);
03874 #endif
03875       } else {
03876         op_mode |= O_RDWR;
03877       }
03878 
03879       /* ensure O_RDWR for (O_RDONLY|O_WRONLY) != O_RDWR cases */
03880       ret |= (op_mode == (O_RDONLY | O_WRONLY)) ? O_RDWR : op_mode;
03881 
03882       break;
03883     case F_SETFL:
03884       /* Bits corresponding to the file access mode and the file creation flags [..] that are set in arg shall be ignored */
03885       val &= ~(O_RDONLY | O_WRONLY | O_RDWR);
03886       if ((val & ~O_NONBLOCK) == 0) {
03887         /* only O_NONBLOCK, all other bits are zero */
03888         netconn_set_nonblocking(sock->conn, val & O_NONBLOCK);
03889         ret = 0;
03890         sock_set_errno(sock, 0);
03891       } else {
03892         sock_set_errno(sock, ENOSYS); /* not yet implemented */
03893       }
03894       break;
03895     default:
03896       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_fcntl(%d, UNIMPL: %d, %d)\n", s, cmd, val));
03897       sock_set_errno(sock, ENOSYS); /* not yet implemented */
03898       break;
03899   }
03900   done_socket(sock);
03901   return ret;
03902 }
03903 
03904 #if LWIP_COMPAT_SOCKETS == 2 && LWIP_POSIX_SOCKETS_IO_NAMES
03905 int
03906 fcntl(int s, int cmd, ...)
03907 {
03908   va_list ap;
03909   int val;
03910 
03911   va_start(ap, cmd);
03912   val = va_arg(ap, int);
03913   va_end(ap);
03914   return lwip_fcntl(s, cmd, val);
03915 }
03916 #endif
03917 
03918 const char *
03919 lwip_inet_ntop(int af, const void *src, char *dst, socklen_t size)
03920 {
03921   const char *ret = NULL;
03922   int size_int = (int)size;
03923   if (size_int < 0) {
03924     set_errno(ENOSPC);
03925     return NULL;
03926   }
03927   switch (af) {
03928 #if LWIP_IPV4
03929     case AF_INET:
03930       ret = ip4addr_ntoa_r((const ip4_addr_t *)src, dst, size_int);
03931       if (ret == NULL) {
03932         set_errno(ENOSPC);
03933       }
03934       break;
03935 #endif
03936 #if LWIP_IPV6
03937     case AF_INET6:
03938       ret = ip6addr_ntoa_r((const ip6_addr_t *)src, dst, size_int);
03939       if (ret == NULL) {
03940         set_errno(ENOSPC);
03941       }
03942       break;
03943 #endif
03944     default:
03945       set_errno(EAFNOSUPPORT);
03946       break;
03947   }
03948   return ret;
03949 }
03950 
03951 int
03952 lwip_inet_pton(int af, const char *src, void *dst)
03953 {
03954   int err;
03955   switch (af) {
03956 #if LWIP_IPV4
03957     case AF_INET:
03958       err = ip4addr_aton(src, (ip4_addr_t *)dst);
03959       break;
03960 #endif
03961 #if LWIP_IPV6
03962     case AF_INET6: {
03963       /* convert into temporary variable since ip6_addr_t might be larger
03964          than in6_addr when scopes are enabled */
03965       ip6_addr_t addr;
03966       err = ip6addr_aton(src, &addr);
03967       if (err) {
03968         memcpy(dst, &addr.addr, sizeof(addr.addr));
03969       }
03970       break;
03971     }
03972 #endif
03973     default:
03974       err = -1;
03975       set_errno(EAFNOSUPPORT);
03976       break;
03977   }
03978   return err;
03979 }
03980 
03981 #if LWIP_IGMP
03982 /** Register a new IGMP membership. On socket close, the membership is dropped automatically.
03983  *
03984  * ATTENTION: this function is called from tcpip_thread (or under CORE_LOCK).
03985  *
03986  * @return 1 on success, 0 on failure
03987  */
03988 static int
03989 lwip_socket_register_membership(int s, const ip4_addr_t *if_addr, const ip4_addr_t *multi_addr)
03990 {
03991   struct lwip_sock *sock = get_socket(s);
03992   int i;
03993 
03994   if (!sock) {
03995     return 0;
03996   }
03997 
03998   for (i = 0; i < LWIP_SOCKET_MAX_MEMBERSHIPS; i++) {
03999     if (socket_ipv4_multicast_memberships[i].sock == NULL) {
04000       socket_ipv4_multicast_memberships[i].sock = sock;
04001       ip4_addr_copy(socket_ipv4_multicast_memberships[i].if_addr, *if_addr);
04002       ip4_addr_copy(socket_ipv4_multicast_memberships[i].multi_addr, *multi_addr);
04003       done_socket(sock);
04004       return 1;
04005     }
04006   }
04007   done_socket(sock);
04008   return 0;
04009 }
04010 
04011 /** Unregister a previously registered membership. This prevents dropping the membership
04012  * on socket close.
04013  *
04014  * ATTENTION: this function is called from tcpip_thread (or under CORE_LOCK).
04015  */
04016 static void
04017 lwip_socket_unregister_membership(int s, const ip4_addr_t *if_addr, const ip4_addr_t *multi_addr)
04018 {
04019   struct lwip_sock *sock = get_socket(s);
04020   int i;
04021 
04022   if (!sock) {
04023     return;
04024   }
04025 
04026   for (i = 0; i < LWIP_SOCKET_MAX_MEMBERSHIPS; i++) {
04027     if ((socket_ipv4_multicast_memberships[i].sock == sock) &&
04028         ip4_addr_cmp(&socket_ipv4_multicast_memberships[i].if_addr, if_addr) &&
04029         ip4_addr_cmp(&socket_ipv4_multicast_memberships[i].multi_addr, multi_addr)) {
04030       socket_ipv4_multicast_memberships[i].sock = NULL;
04031       ip4_addr_set_zero(&socket_ipv4_multicast_memberships[i].if_addr);
04032       ip4_addr_set_zero(&socket_ipv4_multicast_memberships[i].multi_addr);
04033       break;
04034     }
04035   }
04036   done_socket(sock);
04037 }
04038 
04039 /** Drop all memberships of a socket that were not dropped explicitly via setsockopt.
04040  *
04041  * ATTENTION: this function is NOT called from tcpip_thread (or under CORE_LOCK).
04042  */
04043 static void
04044 lwip_socket_drop_registered_memberships(int s)
04045 {
04046   struct lwip_sock *sock = get_socket(s);
04047   int i;
04048 
04049   if (!sock) {
04050     return;
04051   }
04052 
04053   for (i = 0; i < LWIP_SOCKET_MAX_MEMBERSHIPS; i++) {
04054     if (socket_ipv4_multicast_memberships[i].sock == sock) {
04055       ip_addr_t multi_addr, if_addr;
04056       ip_addr_copy_from_ip4(multi_addr, socket_ipv4_multicast_memberships[i].multi_addr);
04057       ip_addr_copy_from_ip4(if_addr, socket_ipv4_multicast_memberships[i].if_addr);
04058       socket_ipv4_multicast_memberships[i].sock = NULL;
04059       ip4_addr_set_zero(&socket_ipv4_multicast_memberships[i].if_addr);
04060       ip4_addr_set_zero(&socket_ipv4_multicast_memberships[i].multi_addr);
04061 
04062       netconn_join_leave_group(sock->conn, &multi_addr, &if_addr, NETCONN_LEAVE);
04063     }
04064   }
04065   done_socket(sock);
04066 }
04067 #endif /* LWIP_IGMP */
04068 
04069 #if LWIP_IPV6_MLD
04070 /** Register a new MLD6 membership. On socket close, the membership is dropped automatically.
04071  *
04072  * ATTENTION: this function is called from tcpip_thread (or under CORE_LOCK).
04073  *
04074  * @return 1 on success, 0 on failure
04075  */
04076 static int
04077 lwip_socket_register_mld6_membership(int s, unsigned int if_idx, const ip6_addr_t *multi_addr)
04078 {
04079   struct lwip_sock *sock = get_socket(s);
04080   int i;
04081 
04082   if (!sock) {
04083     return 0;
04084   }
04085 
04086   for (i = 0; i < LWIP_SOCKET_MAX_MEMBERSHIPS; i++) {
04087     if (socket_ipv6_multicast_memberships[i].sock == NULL) {
04088       socket_ipv6_multicast_memberships[i].sock   = sock;
04089       socket_ipv6_multicast_memberships[i].if_idx = (u8_t)if_idx;
04090       ip6_addr_copy(socket_ipv6_multicast_memberships[i].multi_addr, *multi_addr);
04091       done_socket(sock);
04092       return 1;
04093     }
04094   }
04095   done_socket(sock);
04096   return 0;
04097 }
04098 
04099 /** Unregister a previously registered MLD6 membership. This prevents dropping the membership
04100  * on socket close.
04101  *
04102  * ATTENTION: this function is called from tcpip_thread (or under CORE_LOCK).
04103  */
04104 static void
04105 lwip_socket_unregister_mld6_membership(int s, unsigned int if_idx, const ip6_addr_t *multi_addr)
04106 {
04107   struct lwip_sock *sock = get_socket(s);
04108   int i;
04109 
04110   if (!sock) {
04111     return;
04112   }
04113 
04114   for (i = 0; i < LWIP_SOCKET_MAX_MEMBERSHIPS; i++) {
04115     if ((socket_ipv6_multicast_memberships[i].sock   == sock) &&
04116         (socket_ipv6_multicast_memberships[i].if_idx == if_idx) &&
04117         ip6_addr_cmp(&socket_ipv6_multicast_memberships[i].multi_addr, multi_addr)) {
04118       socket_ipv6_multicast_memberships[i].sock   = NULL;
04119       socket_ipv6_multicast_memberships[i].if_idx = NETIF_NO_INDEX;
04120       ip6_addr_set_zero(&socket_ipv6_multicast_memberships[i].multi_addr);
04121       break;
04122     }
04123   }
04124   done_socket(sock);
04125 }
04126 
04127 /** Drop all MLD6 memberships of a socket that were not dropped explicitly via setsockopt.
04128  *
04129  * ATTENTION: this function is NOT called from tcpip_thread (or under CORE_LOCK).
04130  */
04131 static void
04132 lwip_socket_drop_registered_mld6_memberships(int s)
04133 {
04134   struct lwip_sock *sock = get_socket(s);
04135   int i;
04136 
04137   if (!sock) {
04138     return;
04139   }
04140 
04141   for (i = 0; i < LWIP_SOCKET_MAX_MEMBERSHIPS; i++) {
04142     if (socket_ipv6_multicast_memberships[i].sock == sock) {
04143       ip_addr_t multi_addr;
04144       u8_t if_idx;
04145 
04146       ip_addr_copy_from_ip6(multi_addr, socket_ipv6_multicast_memberships[i].multi_addr);
04147       if_idx = socket_ipv6_multicast_memberships[i].if_idx;
04148 
04149       socket_ipv6_multicast_memberships[i].sock   = NULL;
04150       socket_ipv6_multicast_memberships[i].if_idx = NETIF_NO_INDEX;
04151       ip6_addr_set_zero(&socket_ipv6_multicast_memberships[i].multi_addr);
04152 
04153       netconn_join_leave_group_netif(sock->conn, &multi_addr, if_idx, NETCONN_LEAVE);
04154     }
04155   }
04156   done_socket(sock);
04157 }
04158 #endif /* LWIP_IPV6_MLD */
04159 
04160 #endif /* LWIP_SOCKET */