Rtos API example

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers lwip_sockets.c Source File

lwip_sockets.c

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