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