1/** 2 * @file 3 * Sockets BSD-Like API module 4 */ 5 6/* 7 * Copyright (c) 2001-2004 Swedish Institute of Computer Science. 8 * All rights reserved. 9 * 10 * Redistribution and use in source and binary forms, with or without modification, 11 * are permitted provided that the following conditions are met: 12 * 13 * 1. Redistributions of source code must retain the above copyright notice, 14 * this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright notice, 16 * this list of conditions and the following disclaimer in the documentation 17 * and/or other materials provided with the distribution. 18 * 3. The name of the author may not be used to endorse or promote products 19 * derived from this software without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 22 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 23 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 24 * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 25 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 26 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 29 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 30 * OF SUCH DAMAGE. 31 * 32 * This file is part of the lwIP TCP/IP stack. 33 * 34 * Author: Adam Dunkels <adam@sics.se> 35 * 36 * Improved by Marc Boucher <marc@mbsi.ca> and David Haas <dhaas@alum.rpi.edu> 37 * 38 */ 39 40#include "lwip/opt.h" 41 42#if LWIP_SOCKET /* don't build if not configured for use in lwipopts.h */ 43 44#include "lwip/sockets.h" 45#include "lwip/priv/sockets_priv.h" 46#include "lwip/api.h" 47#include "lwip/igmp.h" 48#include "lwip/inet.h" 49#include "lwip/tcp.h" 50#include "lwip/raw.h" 51#include "lwip/udp.h" 52#include "lwip/memp.h" 53#include "lwip/pbuf.h" 54#include "lwip/netif.h" 55#include "lwip/priv/tcpip_priv.h" 56#include "lwip/mld6.h" 57#if LWIP_ENABLE_DISTRIBUTED_NET 58#include "lwip/distributed_net/distributed_net.h" 59#include "lwip/distributed_net/distributed_net_core.h" 60#endif /* LWIP_ENABLE_DISTRIBUTED_NET */ 61#if LWIP_CHECKSUM_ON_COPY 62#include "lwip/inet_chksum.h" 63#endif 64 65#if LWIP_COMPAT_SOCKETS == 2 && LWIP_POSIX_SOCKETS_IO_NAMES 66#include <stdarg.h> 67#endif 68 69#include <string.h> 70 71#ifdef LWIP_HOOK_FILENAME 72#include LWIP_HOOK_FILENAME 73#endif 74 75#if LWIP_LOWPOWER 76#include "lwip/lowpower.h" 77#endif 78 79/* If the netconn API is not required publicly, then we include the necessary 80 files here to get the implementation */ 81#if !LWIP_NETCONN 82#undef LWIP_NETCONN 83#define LWIP_NETCONN 1 84#include "api_msg.c" 85#include "api_lib.c" 86#include "netbuf.c" 87#undef LWIP_NETCONN 88#define LWIP_NETCONN 0 89#endif 90 91#define API_SELECT_CB_VAR_REF(name) API_VAR_REF(name) 92#define API_SELECT_CB_VAR_DECLARE(name) API_VAR_DECLARE(struct lwip_select_cb, name) 93#define API_SELECT_CB_VAR_ALLOC(name, retblock) API_VAR_ALLOC_EXT(struct lwip_select_cb, MEMP_SELECT_CB, name, retblock) 94#define API_SELECT_CB_VAR_FREE(name) API_VAR_FREE(MEMP_SELECT_CB, name) 95 96#if LWIP_IPV4 97#define IP4ADDR_PORT_TO_SOCKADDR(sin, ipaddr, port) do { \ 98 (sin)->sin_len = sizeof(struct sockaddr_in); \ 99 (sin)->sin_family = AF_INET; \ 100 (sin)->sin_port = lwip_htons((port)); \ 101 inet_addr_from_ip4addr(&(sin)->sin_addr, ipaddr); \ 102 memset((sin)->sin_zero, 0, SIN_ZERO_LEN); }while(0) 103#define SOCKADDR4_TO_IP4ADDR_PORT(sin, ipaddr, port) do { \ 104 inet_addr_to_ip4addr(ip_2_ip4(ipaddr), &((sin)->sin_addr)); \ 105 (port) = lwip_ntohs((sin)->sin_port); }while(0) 106#endif /* LWIP_IPV4 */ 107 108#if LWIP_IPV6 109#define IP6ADDR_PORT_TO_SOCKADDR(sin6, ipaddr, port) do { \ 110 (sin6)->sin6_len = sizeof(struct sockaddr_in6); \ 111 (sin6)->sin6_family = AF_INET6; \ 112 (sin6)->sin6_port = lwip_htons((port)); \ 113 (sin6)->sin6_flowinfo = 0; \ 114 inet6_addr_from_ip6addr(&(sin6)->sin6_addr, ipaddr); \ 115 (sin6)->sin6_scope_id = ip6_addr_zone(ipaddr); }while(0) 116#define SOCKADDR6_TO_IP6ADDR_PORT(sin6, ipaddr, port) do { \ 117 inet6_addr_to_ip6addr(ip_2_ip6(ipaddr), &((sin6)->sin6_addr)); \ 118 if (ip6_addr_has_scope(ip_2_ip6(ipaddr), IP6_UNKNOWN)) { \ 119 ip6_addr_set_zone(ip_2_ip6(ipaddr), (u8_t)((sin6)->sin6_scope_id)); \ 120 } \ 121 (port) = lwip_ntohs((sin6)->sin6_port); }while(0) 122#endif /* LWIP_IPV6 */ 123 124#if LWIP_IPV4 && LWIP_IPV6 125static void sockaddr_to_ipaddr_port(const struct sockaddr *sockaddr, ip_addr_t *ipaddr, u16_t *port); 126 127#define IS_SOCK_ADDR_LEN_VALID(namelen) (((namelen) == sizeof(struct sockaddr_in)) || \ 128 ((namelen) == sizeof(struct sockaddr_in6))) 129#define IS_SOCK_ADDR_TYPE_VALID(name) (((name)->sa_family == AF_INET) || \ 130 ((name)->sa_family == AF_INET6)) 131#define SOCK_ADDR_TYPE_MATCH(name, sock) \ 132 ((((name)->sa_family == AF_INET) && !(NETCONNTYPE_ISIPV6((sock)->conn->type))) || \ 133 (((name)->sa_family == AF_INET6) && (NETCONNTYPE_ISIPV6((sock)->conn->type)))) 134#define IPADDR_PORT_TO_SOCKADDR(sockaddr, ipaddr, port) do { \ 135 if (IP_IS_ANY_TYPE_VAL(*ipaddr) || IP_IS_V6_VAL(*ipaddr)) { \ 136 IP6ADDR_PORT_TO_SOCKADDR((struct sockaddr_in6*)(void*)(sockaddr), ip_2_ip6(ipaddr), port); \ 137 } else { \ 138 IP4ADDR_PORT_TO_SOCKADDR((struct sockaddr_in*)(void*)(sockaddr), ip_2_ip4(ipaddr), port); \ 139 } } while(0) 140#define SOCKADDR_TO_IPADDR_PORT(sockaddr, ipaddr, port) sockaddr_to_ipaddr_port(sockaddr, ipaddr, &(port)) 141#define DOMAIN_TO_NETCONN_TYPE(domain, type) (((domain) == AF_INET) ? \ 142 (type) : (enum netconn_type)((type) | NETCONN_TYPE_IPV6)) 143#elif LWIP_IPV6 /* LWIP_IPV4 && LWIP_IPV6 */ 144#define IS_SOCK_ADDR_LEN_VALID(namelen) ((namelen) == sizeof(struct sockaddr_in6)) 145#define IS_SOCK_ADDR_TYPE_VALID(name) ((name)->sa_family == AF_INET6) 146#define SOCK_ADDR_TYPE_MATCH(name, sock) 1 147#define IPADDR_PORT_TO_SOCKADDR(sockaddr, ipaddr, port) \ 148 IP6ADDR_PORT_TO_SOCKADDR((struct sockaddr_in6*)(void*)(sockaddr), ip_2_ip6(ipaddr), port) 149#define SOCKADDR_TO_IPADDR_PORT(sockaddr, ipaddr, port) \ 150 SOCKADDR6_TO_IP6ADDR_PORT((const struct sockaddr_in6*)(const void*)(sockaddr), ipaddr, port) 151#define DOMAIN_TO_NETCONN_TYPE(domain, netconn_type) (netconn_type) 152#else /*-> LWIP_IPV4: LWIP_IPV4 && LWIP_IPV6 */ 153#define IS_SOCK_ADDR_LEN_VALID(namelen) ((namelen) == sizeof(struct sockaddr_in)) 154#define IS_SOCK_ADDR_TYPE_VALID(name) ((name)->sa_family == AF_INET) 155#define SOCK_ADDR_TYPE_MATCH(name, sock) 1 156#define IPADDR_PORT_TO_SOCKADDR(sockaddr, ipaddr, port) \ 157 IP4ADDR_PORT_TO_SOCKADDR((struct sockaddr_in*)(void*)(sockaddr), ip_2_ip4(ipaddr), port) 158#define SOCKADDR_TO_IPADDR_PORT(sockaddr, ipaddr, port) \ 159 SOCKADDR4_TO_IP4ADDR_PORT((const struct sockaddr_in*)(const void*)(sockaddr), ipaddr, port) 160#define DOMAIN_TO_NETCONN_TYPE(domain, netconn_type) (netconn_type) 161#endif /* LWIP_IPV6 */ 162 163#define IS_SOCK_ADDR_TYPE_VALID_OR_UNSPEC(name) (((name)->sa_family == AF_UNSPEC) || \ 164 IS_SOCK_ADDR_TYPE_VALID(name)) 165#define SOCK_ADDR_TYPE_MATCH_OR_UNSPEC(name, sock) (((name)->sa_family == AF_UNSPEC) || \ 166 SOCK_ADDR_TYPE_MATCH(name, sock)) 167#define IS_SOCK_ADDR_ALIGNED(name) ((((mem_ptr_t)(name)) % 4) == 0) 168 169 170#define LWIP_SOCKOPT_CHECK_OPTLEN(sock, optlen, opttype) do { if ((optlen) < sizeof(opttype)) { done_socket(sock); return EINVAL; }}while(0) 171#define LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, optlen, opttype) do { \ 172 LWIP_SOCKOPT_CHECK_OPTLEN(sock, optlen, opttype); \ 173 if ((sock)->conn == NULL) { done_socket(sock); return EINVAL; } }while(0) 174#define LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, optlen, opttype) do { \ 175 LWIP_SOCKOPT_CHECK_OPTLEN(sock, optlen, opttype); \ 176 if (((sock)->conn == NULL) || ((sock)->conn->pcb.tcp == NULL)) { done_socket(sock); return EINVAL; } }while(0) 177#define LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, opttype, netconntype) do { \ 178 LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, optlen, opttype); \ 179 if (NETCONNTYPE_GROUP(netconn_type((sock)->conn)) != netconntype) { done_socket(sock); return ENOPROTOOPT; } }while(0) 180 181 182#define LWIP_SETGETSOCKOPT_DATA_VAR_REF(name) API_VAR_REF(name) 183#define LWIP_SETGETSOCKOPT_DATA_VAR_DECLARE(name) API_VAR_DECLARE(struct lwip_setgetsockopt_data, name) 184#define LWIP_SETGETSOCKOPT_DATA_VAR_FREE(name) API_VAR_FREE(MEMP_SOCKET_SETGETSOCKOPT_DATA, name) 185#if LWIP_MPU_COMPATIBLE 186#define LWIP_SETGETSOCKOPT_DATA_VAR_ALLOC(name, sock) do { \ 187 name = (struct lwip_setgetsockopt_data *)memp_malloc(MEMP_SOCKET_SETGETSOCKOPT_DATA); \ 188 if (name == NULL) { \ 189 sock_set_errno(sock, ENOMEM); \ 190 done_socket(sock); \ 191 return -1; \ 192 } }while(0) 193#else /* LWIP_MPU_COMPATIBLE */ 194#define LWIP_SETGETSOCKOPT_DATA_VAR_ALLOC(name, sock) 195#endif /* LWIP_MPU_COMPATIBLE */ 196 197#if LWIP_SO_SNDRCVTIMEO_NONSTANDARD 198#define LWIP_SO_SNDRCVTIMEO_OPTTYPE int 199#define LWIP_SO_SNDRCVTIMEO_SET(optval, val) (*(int *)(optval) = (val)) 200#define LWIP_SO_SNDRCVTIMEO_GET_MS(optval) ((long)*(const int*)(optval)) 201#else 202#define LWIP_SO_SNDRCVTIMEO_OPTTYPE struct timeval 203#define LWIP_SO_SNDRCVTIMEO_SET(optval, val) do { \ 204 u32_t loc = (val); \ 205 ((struct timeval *)(optval))->tv_sec = (long)((loc) / 1000U); \ 206 ((struct timeval *)(optval))->tv_usec = (long)(((loc) % 1000U) * 1000U); }while(0) 207#define LWIP_SO_SNDRCVTIMEO_GET_MS(optval) ((((const struct timeval *)(optval))->tv_sec * 1000) + (((const struct timeval *)(optval))->tv_usec / 1000)) 208#endif 209 210 211/** A struct sockaddr replacement that has the same alignment as sockaddr_in/ 212 * sockaddr_in6 if instantiated. 213 */ 214union sockaddr_aligned { 215 struct sockaddr sa; 216#if LWIP_IPV6 217 struct sockaddr_in6 sin6; 218#endif /* LWIP_IPV6 */ 219#if LWIP_IPV4 220 struct sockaddr_in sin; 221#endif /* LWIP_IPV4 */ 222}; 223 224/* Define the number of IPv4 multicast memberships, default is one per socket */ 225#ifndef LWIP_SOCKET_MAX_MEMBERSHIPS 226#define LWIP_SOCKET_MAX_MEMBERSHIPS NUM_SOCKETS 227#endif 228 229#if LWIP_IGMP 230/* This is to keep track of IP_ADD_MEMBERSHIP calls to drop the membership when 231 a socket is closed */ 232struct lwip_socket_multicast_pair { 233 /** the socket */ 234 struct lwip_sock *sock; 235 /** the interface address */ 236 ip4_addr_t if_addr; 237 /** the group address */ 238 ip4_addr_t multi_addr; 239}; 240 241static struct lwip_socket_multicast_pair socket_ipv4_multicast_memberships[LWIP_SOCKET_MAX_MEMBERSHIPS]; 242 243static int lwip_socket_register_membership(int s, const ip4_addr_t *if_addr, const ip4_addr_t *multi_addr); 244static void lwip_socket_unregister_membership(int s, const ip4_addr_t *if_addr, const ip4_addr_t *multi_addr); 245static void lwip_socket_drop_registered_memberships(int s); 246#endif /* LWIP_IGMP */ 247 248#if LWIP_IPV6_MLD 249/* This is to keep track of IP_JOIN_GROUP calls to drop the membership when 250 a socket is closed */ 251struct lwip_socket_multicast_mld6_pair { 252 /** the socket */ 253 struct lwip_sock *sock; 254 /** the interface index */ 255 u8_t if_idx; 256 /** the group address */ 257 ip6_addr_t multi_addr; 258}; 259 260static struct lwip_socket_multicast_mld6_pair socket_ipv6_multicast_memberships[LWIP_SOCKET_MAX_MEMBERSHIPS]; 261 262static int lwip_socket_register_mld6_membership(int s, unsigned int if_idx, const ip6_addr_t *multi_addr); 263static void lwip_socket_unregister_mld6_membership(int s, unsigned int if_idx, const ip6_addr_t *multi_addr); 264static void lwip_socket_drop_registered_mld6_memberships(int s); 265#endif /* LWIP_IPV6_MLD */ 266 267/** The global array of available sockets */ 268static struct lwip_sock sockets[NUM_SOCKETS]; 269 270#if LWIP_SOCKET_SELECT || LWIP_SOCKET_POLL 271#if LWIP_TCPIP_CORE_LOCKING 272/* protect the select_cb_list using core lock */ 273#define LWIP_SOCKET_SELECT_DECL_PROTECT(lev) 274#define LWIP_SOCKET_SELECT_PROTECT(lev) LOCK_TCPIP_CORE() 275#define LWIP_SOCKET_SELECT_UNPROTECT(lev) UNLOCK_TCPIP_CORE() 276#else /* LWIP_TCPIP_CORE_LOCKING */ 277/* protect the select_cb_list using SYS_LIGHTWEIGHT_PROT */ 278#define LWIP_SOCKET_SELECT_DECL_PROTECT(lev) SYS_ARCH_DECL_PROTECT(lev) 279#define LWIP_SOCKET_SELECT_PROTECT(lev) SYS_ARCH_PROTECT(lev) 280#define LWIP_SOCKET_SELECT_UNPROTECT(lev) SYS_ARCH_UNPROTECT(lev) 281/** This counter is increased from lwip_select when the list is changed 282 and checked in select_check_waiters to see if it has changed. */ 283static volatile int select_cb_ctr; 284#endif /* LWIP_TCPIP_CORE_LOCKING */ 285/** The global list of tasks waiting for select */ 286static struct lwip_select_cb *select_cb_list; 287#endif /* LWIP_SOCKET_SELECT || LWIP_SOCKET_POLL */ 288 289#define sock_set_errno(sk, e) do { \ 290 const int sockerr = (e); \ 291 set_errno(sockerr); \ 292} while (0) 293 294/* Forward declaration of some functions */ 295#if LWIP_SOCKET_SELECT || LWIP_SOCKET_POLL 296static void event_callback(struct netconn *conn, enum netconn_evt evt, u16_t len); 297#define DEFAULT_SOCKET_EVENTCB event_callback 298static void select_check_waiters(int s, int has_recvevent, int has_sendevent, int has_errevent); 299#else 300#define DEFAULT_SOCKET_EVENTCB NULL 301#endif 302#if !LWIP_TCPIP_CORE_LOCKING 303static void lwip_getsockopt_callback(void *arg); 304static void lwip_setsockopt_callback(void *arg); 305#endif 306static int lwip_getsockopt_impl(int s, int level, int optname, void *optval, socklen_t *optlen); 307static int lwip_setsockopt_impl(int s, int level, int optname, const void *optval, socklen_t optlen); 308static int free_socket_locked(struct lwip_sock *sock, int is_tcp, struct netconn **conn, 309 union lwip_sock_lastdata *lastdata); 310static void free_socket_free_elements(int is_tcp, struct netconn *conn, union lwip_sock_lastdata *lastdata); 311 312#if LWIP_IPV4 && LWIP_IPV6 313static void 314sockaddr_to_ipaddr_port(const struct sockaddr *sockaddr, ip_addr_t *ipaddr, u16_t *port) 315{ 316 if ((sockaddr->sa_family) == AF_INET6) { 317 SOCKADDR6_TO_IP6ADDR_PORT((const struct sockaddr_in6 *)(const void *)(sockaddr), ipaddr, *port); 318 ipaddr->type = IPADDR_TYPE_V6; 319 } else { 320 SOCKADDR4_TO_IP4ADDR_PORT((const struct sockaddr_in *)(const void *)(sockaddr), ipaddr, *port); 321 ipaddr->type = IPADDR_TYPE_V4; 322 } 323} 324#endif /* LWIP_IPV4 && LWIP_IPV6 */ 325 326/** LWIP_NETCONN_SEM_PER_THREAD==1: initialize thread-local semaphore */ 327void 328lwip_socket_thread_init(void) 329{ 330 netconn_thread_init(); 331} 332 333/** LWIP_NETCONN_SEM_PER_THREAD==1: destroy thread-local semaphore */ 334void 335lwip_socket_thread_cleanup(void) 336{ 337 netconn_thread_cleanup(); 338} 339 340#if LWIP_NETCONN_FULLDUPLEX 341/* Thread-safe increment of sock->fd_used, with overflow check */ 342static int 343sock_inc_used(struct lwip_sock *sock) 344{ 345 int ret; 346 SYS_ARCH_DECL_PROTECT(lev); 347 348 LWIP_ASSERT("sock != NULL", sock != NULL); 349 350 SYS_ARCH_PROTECT(lev); 351 if (sock->fd_free_pending) { 352 /* prevent new usage of this socket if free is pending */ 353 ret = 0; 354 } else { 355 ++sock->fd_used; 356 ret = 1; 357 LWIP_ASSERT("sock->fd_used != 0", sock->fd_used != 0); 358 } 359 SYS_ARCH_UNPROTECT(lev); 360 return ret; 361} 362 363/* Like sock_inc_used(), but called under SYS_ARCH_PROTECT lock. */ 364static int 365sock_inc_used_locked(struct lwip_sock *sock) 366{ 367 LWIP_ASSERT("sock != NULL", sock != NULL); 368 369 if (sock->fd_free_pending) { 370 LWIP_ASSERT("sock->fd_used != 0", sock->fd_used != 0); 371 return 0; 372 } 373 374 ++sock->fd_used; 375 LWIP_ASSERT("sock->fd_used != 0", sock->fd_used != 0); 376 return 1; 377} 378 379/* In full-duplex mode,sock->fd_used != 0 prevents a socket descriptor from being 380 * released (and possibly reused) when used from more than one thread 381 * (e.g. read-while-write or close-while-write, etc) 382 * This function is called at the end of functions using (try)get_socket*(). 383 */ 384static void 385done_socket(struct lwip_sock *sock) 386{ 387 int freed = 0; 388 int is_tcp = 0; 389 struct netconn *conn = NULL; 390 union lwip_sock_lastdata lastdata; 391 SYS_ARCH_DECL_PROTECT(lev); 392 LWIP_ASSERT("sock != NULL", sock != NULL); 393 394 SYS_ARCH_PROTECT(lev); 395 LWIP_ASSERT("sock->fd_used > 0", sock->fd_used > 0); 396 if (--sock->fd_used == 0) { 397 if (sock->fd_free_pending) { 398 /* free the socket */ 399 sock->fd_used = 1; 400 is_tcp = sock->fd_free_pending & LWIP_SOCK_FD_FREE_TCP; 401 freed = free_socket_locked(sock, is_tcp, &conn, &lastdata); 402 } 403 } 404 SYS_ARCH_UNPROTECT(lev); 405 406 if (freed) { 407 free_socket_free_elements(is_tcp, conn, &lastdata); 408 } 409} 410 411#else /* LWIP_NETCONN_FULLDUPLEX */ 412#define sock_inc_used(sock) 1 413#define sock_inc_used_locked(sock) 1 414#define done_socket(sock) 415#endif /* LWIP_NETCONN_FULLDUPLEX */ 416 417/* Translate a socket 'int' into a pointer (only fails if the index is invalid) */ 418static struct lwip_sock * 419tryget_socket_unconn_nouse(int fd) 420{ 421 int s = fd - LWIP_SOCKET_OFFSET; 422 if ((s < 0) || (s >= NUM_SOCKETS)) { 423 LWIP_DEBUGF(SOCKETS_DEBUG, ("tryget_socket_unconn(%d): invalid\n", fd)); 424 return NULL; 425 } 426 return &sockets[s]; 427} 428 429struct lwip_sock * 430lwip_socket_dbg_get_socket(int fd) 431{ 432 return tryget_socket_unconn_nouse(fd); 433} 434 435/* Translate a socket 'int' into a pointer (only fails if the index is invalid) */ 436static struct lwip_sock * 437tryget_socket_unconn(int fd) 438{ 439 struct lwip_sock *ret = tryget_socket_unconn_nouse(fd); 440 if (ret != NULL) { 441 if (!sock_inc_used(ret)) { 442 return NULL; 443 } 444 } 445 return ret; 446} 447 448/* Like tryget_socket_unconn(), but called under SYS_ARCH_PROTECT lock. */ 449static struct lwip_sock * 450tryget_socket_unconn_locked(int fd) 451{ 452 struct lwip_sock *ret = tryget_socket_unconn_nouse(fd); 453 if (ret != NULL) { 454 if (!sock_inc_used_locked(ret)) { 455 return NULL; 456 } 457 } 458 return ret; 459} 460 461/** 462 * Same as get_socket but doesn't set errno 463 * 464 * @param fd externally used socket index 465 * @return struct lwip_sock for the socket or NULL if not found 466 */ 467static struct lwip_sock * 468tryget_socket(int fd) 469{ 470 struct lwip_sock *sock = tryget_socket_unconn(fd); 471 if (sock != NULL) { 472 if (sock->conn) { 473 return sock; 474 } 475 done_socket(sock); 476 } 477 return NULL; 478} 479 480/** 481 * Map a externally used socket index to the internal socket representation. 482 * 483 * @param fd externally used socket index 484 * @return struct lwip_sock for the socket or NULL if not found 485 */ 486static struct lwip_sock * 487get_socket(int fd) 488{ 489 struct lwip_sock *sock = tryget_socket(fd); 490 if (!sock) { 491 if ((fd < LWIP_SOCKET_OFFSET) || (fd >= (LWIP_SOCKET_OFFSET + NUM_SOCKETS))) { 492 LWIP_DEBUGF(SOCKETS_DEBUG, ("get_socket(%d): invalid\n", fd)); 493 } 494 set_errno(EBADF); 495 return NULL; 496 } 497 return sock; 498} 499 500/** 501 * Allocate a new socket for a given netconn. 502 * 503 * @param newconn the netconn for which to allocate a socket 504 * @param accepted 1 if socket has been created by accept(), 505 * 0 if socket has been created by socket() 506 * @return the index of the new socket; -1 on error 507 */ 508static int 509alloc_socket(struct netconn *newconn, int accepted) 510{ 511 int i; 512 SYS_ARCH_DECL_PROTECT(lev); 513 LWIP_UNUSED_ARG(accepted); 514 515 /* allocate a new socket identifier */ 516 for (i = 0; i < NUM_SOCKETS; ++i) { 517 /* Protect socket array */ 518 SYS_ARCH_PROTECT(lev); 519 if (!sockets[i].conn) { 520#if LWIP_NETCONN_FULLDUPLEX 521 if (sockets[i].fd_used) { 522 SYS_ARCH_UNPROTECT(lev); 523 continue; 524 } 525 sockets[i].fd_used = 1; 526 sockets[i].fd_free_pending = 0; 527#endif 528 sockets[i].conn = newconn; 529 /* The socket is not yet known to anyone, so no need to protect 530 after having marked it as used. */ 531 SYS_ARCH_UNPROTECT(lev); 532 sockets[i].lastdata.pbuf = NULL; 533#if LWIP_SOCKET_SELECT || LWIP_SOCKET_POLL 534 LWIP_ASSERT("sockets[i].select_waiting == 0", sockets[i].select_waiting == 0); 535 sockets[i].rcvevent = 0; 536 /* TCP sendbuf is empty, but the socket is not yet writable until connected 537 * (unless it has been created by accept()). */ 538 sockets[i].sendevent = (NETCONNTYPE_GROUP(newconn->type) == NETCONN_TCP ? (accepted != 0) : 1); 539 sockets[i].errevent = 0; 540 init_waitqueue_head(&sockets[i].wq); 541#endif /* LWIP_SOCKET_SELECT || LWIP_SOCKET_POLL */ 542 return i + LWIP_SOCKET_OFFSET; 543 } 544 SYS_ARCH_UNPROTECT(lev); 545 } 546 return -1; 547} 548 549/** Free a socket (under lock) 550 * 551 * @param sock the socket to free 552 * @param is_tcp != 0 for TCP sockets, used to free lastdata 553 * @param conn the socekt's netconn is stored here, must be freed externally 554 * @param lastdata lastdata is stored here, must be freed externally 555 */ 556static int 557free_socket_locked(struct lwip_sock *sock, int is_tcp, struct netconn **conn, 558 union lwip_sock_lastdata *lastdata) 559{ 560#if LWIP_NETCONN_FULLDUPLEX 561 LWIP_ASSERT("sock->fd_used > 0", sock->fd_used > 0); 562 sock->fd_used--; 563 if (sock->fd_used > 0) { 564 sock->fd_free_pending = LWIP_SOCK_FD_FREE_FREE | (is_tcp ? LWIP_SOCK_FD_FREE_TCP : 0); 565 return 0; 566 } 567#else /* LWIP_NETCONN_FULLDUPLEX */ 568 LWIP_UNUSED_ARG(is_tcp); 569#endif /* LWIP_NETCONN_FULLDUPLEX */ 570 571 *lastdata = sock->lastdata; 572 sock->lastdata.pbuf = NULL; 573 *conn = sock->conn; 574 sock->conn = NULL; 575 return 1; 576} 577 578/** Free a socket's leftover members. 579 */ 580static void 581free_socket_free_elements(int is_tcp, struct netconn *conn, union lwip_sock_lastdata *lastdata) 582{ 583 if (lastdata->pbuf != NULL) { 584 if (is_tcp) { 585 pbuf_free(lastdata->pbuf); 586 } else { 587 netbuf_delete(lastdata->netbuf); 588 } 589 } 590 if (conn != NULL) { 591 /* netconn_prepare_delete() has already been called, here we only free the conn */ 592 netconn_delete(conn); 593 } 594} 595 596/** Free a socket. The socket's netconn must have been 597 * delete before! 598 * 599 * @param sock the socket to free 600 * @param is_tcp != 0 for TCP sockets, used to free lastdata 601 */ 602static void 603free_socket(struct lwip_sock *sock, int is_tcp) 604{ 605 int freed; 606 struct netconn *conn; 607 union lwip_sock_lastdata lastdata; 608 SYS_ARCH_DECL_PROTECT(lev); 609 610 /* Protect socket array */ 611 SYS_ARCH_PROTECT(lev); 612 613 freed = free_socket_locked(sock, is_tcp, &conn, &lastdata); 614 SYS_ARCH_UNPROTECT(lev); 615 /* don't use 'sock' after this line, as another task might have allocated it */ 616 617 if (freed) { 618 free_socket_free_elements(is_tcp, conn, &lastdata); 619 } 620} 621 622/* Below this, the well-known socket functions are implemented. 623 * Use google.com or opengroup.org to get a good description :-) 624 * 625 * Exceptions are documented! 626 */ 627 628int 629lwip_accept(int s, struct sockaddr *addr, socklen_t *addrlen) 630{ 631 struct lwip_sock *sock, *nsock; 632 struct netconn *newconn; 633 ip_addr_t naddr; 634 u16_t port = 0; 635 int newsock; 636 err_t err; 637 int recvevent; 638 SYS_ARCH_DECL_PROTECT(lev); 639 640 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d)...\n", s)); 641 sock = get_socket(s); 642 if (!sock) { 643 return -1; 644 } 645 646 /* wait for a new connection */ 647 err = netconn_accept(sock->conn, &newconn); 648 if (err != ERR_OK) { 649 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d): netconn_acept failed, err=%d\n", s, err)); 650 if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_TCP) { 651 sock_set_errno(sock, EOPNOTSUPP); 652 } else if (err == ERR_CLSD) { 653 sock_set_errno(sock, EINVAL); 654 } else { 655 sock_set_errno(sock, err_to_errno(err)); 656 } 657 done_socket(sock); 658 return -1; 659 } 660 LWIP_ASSERT("newconn != NULL", newconn != NULL); 661 662 newsock = alloc_socket(newconn, 1); 663 if (newsock == -1) { 664 netconn_delete(newconn); 665 sock_set_errno(sock, ENFILE); 666 done_socket(sock); 667 return -1; 668 } 669 LWIP_ASSERT("invalid socket index", (newsock >= LWIP_SOCKET_OFFSET) && (newsock < NUM_SOCKETS + LWIP_SOCKET_OFFSET)); 670 nsock = &sockets[newsock - LWIP_SOCKET_OFFSET]; 671 672 /* See event_callback: If data comes in right away after an accept, even 673 * though the server task might not have created a new socket yet. 674 * In that case, newconn->socket is counted down (newconn->socket--), 675 * so nsock->rcvevent is >= 1 here! 676 */ 677 SYS_ARCH_PROTECT(lev); 678 recvevent = (s16_t)(-1 - newconn->socket); 679 newconn->socket = newsock; 680 SYS_ARCH_UNPROTECT(lev); 681 682 if (newconn->callback) { 683 LOCK_TCPIP_CORE(); 684 while (recvevent > 0) { 685 recvevent--; 686 newconn->callback(newconn, NETCONN_EVT_RCVPLUS, 0); 687 } 688 UNLOCK_TCPIP_CORE(); 689 } 690 691 /* Note that POSIX only requires us to check addr is non-NULL. addrlen must 692 * not be NULL if addr is valid. 693 */ 694 if ((addr != NULL) && (addrlen != NULL)) { 695 union sockaddr_aligned tempaddr; 696 /* get the IP address and port of the remote host */ 697 err = netconn_peer(newconn, &naddr, &port); 698 if (err != ERR_OK) { 699 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d): netconn_peer failed, err=%d\n", s, err)); 700 free_socket(nsock, 1); 701 sock_set_errno(sock, err_to_errno(err)); 702 done_socket(sock); 703 return -1; 704 } 705 706 IPADDR_PORT_TO_SOCKADDR(&tempaddr, &naddr, port); 707 if (*addrlen > tempaddr.sa.sa_len) { 708 *addrlen = tempaddr.sa.sa_len; 709 } 710 MEMCPY(addr, &tempaddr, *addrlen); 711 712 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d) returning new sock=%d addr=", s, newsock)); 713 ip_addr_debug_print_val(SOCKETS_DEBUG, naddr); 714 LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F"\n", port)); 715 } else { 716 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d) returning new sock=%d", s, newsock)); 717 } 718 719 sock_set_errno(sock, 0); 720 done_socket(sock); 721 done_socket(nsock); 722 return newsock; 723} 724 725int 726lwip_bind(int s, const struct sockaddr *name, socklen_t namelen) 727{ 728 struct lwip_sock *sock; 729 ip_addr_t local_addr; 730 u16_t local_port; 731 err_t err; 732 733 sock = get_socket(s); 734 if (!sock) { 735 return -1; 736 } 737 738 if (!SOCK_ADDR_TYPE_MATCH(name, sock)) { 739 /* sockaddr does not match socket type (IPv4/IPv6) */ 740 sock_set_errno(sock, err_to_errno(ERR_VAL)); 741 done_socket(sock); 742 return -1; 743 } 744 745 /* check size, family and alignment of 'name' */ 746 LWIP_ERROR("lwip_bind: invalid address", (IS_SOCK_ADDR_LEN_VALID(namelen) && 747 IS_SOCK_ADDR_TYPE_VALID(name) && IS_SOCK_ADDR_ALIGNED(name)), 748 sock_set_errno(sock, err_to_errno(ERR_ARG)); done_socket(sock); return -1;); 749 LWIP_UNUSED_ARG(namelen); 750 751 SOCKADDR_TO_IPADDR_PORT(name, &local_addr, local_port); 752 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d, addr=", s)); 753 ip_addr_debug_print_val(SOCKETS_DEBUG, local_addr); 754 LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F")\n", local_port)); 755 756#if LWIP_IPV4 && LWIP_IPV6 757 /* Dual-stack: Unmap IPv4 mapped IPv6 addresses */ 758 if (IP_IS_V6_VAL(local_addr) && ip6_addr_isipv4mappedipv6(ip_2_ip6(&local_addr))) { 759 unmap_ipv4_mapped_ipv6(ip_2_ip4(&local_addr), ip_2_ip6(&local_addr)); 760 IP_SET_TYPE_VAL(local_addr, IPADDR_TYPE_V4); 761 } 762#endif /* LWIP_IPV4 && LWIP_IPV6 */ 763 764 err = netconn_bind(sock->conn, &local_addr, local_port); 765 766 if (err != ERR_OK) { 767 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d) failed, err=%d\n", s, err)); 768 sock_set_errno(sock, err_to_errno(err)); 769 done_socket(sock); 770 return -1; 771 } 772 773 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d) succeeded\n", s)); 774 sock_set_errno(sock, 0); 775 done_socket(sock); 776 return 0; 777} 778 779int 780lwip_close(int s) 781{ 782#if LWIP_ENABLE_DISTRIBUTED_NET 783 if (!is_distributed_net_enabled()) { 784 return lwip_close_internal(s); 785 } 786 return distributed_net_close(s); 787} 788 789int 790lwip_close_internal(int s) 791{ 792#endif 793 struct lwip_sock *sock; 794 int is_tcp = 0; 795 err_t err; 796 797 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_close(%d)\n", s)); 798 799 sock = get_socket(s); 800 if (!sock) { 801 return -1; 802 } 803 804 if (sock->conn != NULL) { 805 is_tcp = NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP; 806 } else { 807 LWIP_ASSERT("sock->lastdata == NULL", sock->lastdata.pbuf == NULL); 808 } 809 810#if LWIP_IGMP 811 /* drop all possibly joined IGMP memberships */ 812 lwip_socket_drop_registered_memberships(s); 813#endif /* LWIP_IGMP */ 814#if LWIP_IPV6_MLD 815 /* drop all possibly joined MLD6 memberships */ 816 lwip_socket_drop_registered_mld6_memberships(s); 817#endif /* LWIP_IPV6_MLD */ 818 819 err = netconn_prepare_delete(sock->conn); 820 if (err != ERR_OK) { 821 sock_set_errno(sock, err_to_errno(err)); 822 done_socket(sock); 823 return -1; 824 } 825 826 free_socket(sock, is_tcp); 827 set_errno(0); 828 return 0; 829} 830 831int 832lwip_connect(int s, const struct sockaddr *name, socklen_t namelen) 833{ 834#if LWIP_ENABLE_DISTRIBUTED_NET 835 if (!is_distributed_net_enabled()) { 836 return lwip_connect_internal(s, name, namelen); 837 } 838 return distributed_net_connect(s, name, namelen); 839} 840 841int 842lwip_connect_internal(int s, const struct sockaddr *name, socklen_t namelen) 843{ 844#endif 845 struct lwip_sock *sock; 846 err_t err; 847 848 sock = get_socket(s); 849 if (!sock) { 850 return -1; 851 } 852 853 if (!SOCK_ADDR_TYPE_MATCH_OR_UNSPEC(name, sock)) { 854 /* sockaddr does not match socket type (IPv4/IPv6) */ 855 sock_set_errno(sock, err_to_errno(ERR_VAL)); 856 done_socket(sock); 857 return -1; 858 } 859 860 LWIP_UNUSED_ARG(namelen); 861 if (name->sa_family == AF_UNSPEC) { 862 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d, AF_UNSPEC)\n", s)); 863 err = netconn_disconnect(sock->conn); 864 } else { 865 ip_addr_t remote_addr; 866 u16_t remote_port; 867 868 /* check size, family and alignment of 'name' */ 869 LWIP_ERROR("lwip_connect: invalid address", IS_SOCK_ADDR_LEN_VALID(namelen) && 870 IS_SOCK_ADDR_TYPE_VALID_OR_UNSPEC(name) && IS_SOCK_ADDR_ALIGNED(name), 871 sock_set_errno(sock, err_to_errno(ERR_ARG)); done_socket(sock); return -1;); 872 873 SOCKADDR_TO_IPADDR_PORT(name, &remote_addr, remote_port); 874 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d, addr=", s)); 875 ip_addr_debug_print_val(SOCKETS_DEBUG, remote_addr); 876 LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F")\n", remote_port)); 877 878#if LWIP_IPV4 && LWIP_IPV6 879 /* Dual-stack: Unmap IPv4 mapped IPv6 addresses */ 880 if (IP_IS_V6_VAL(remote_addr) && ip6_addr_isipv4mappedipv6(ip_2_ip6(&remote_addr))) { 881 unmap_ipv4_mapped_ipv6(ip_2_ip4(&remote_addr), ip_2_ip6(&remote_addr)); 882 IP_SET_TYPE_VAL(remote_addr, IPADDR_TYPE_V4); 883 } 884#endif /* LWIP_IPV4 && LWIP_IPV6 */ 885 886 err = netconn_connect(sock->conn, &remote_addr, remote_port); 887 } 888 889 if (err != ERR_OK) { 890 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d) failed, err=%d\n", s, err)); 891 sock_set_errno(sock, err_to_errno(err)); 892 done_socket(sock); 893 return -1; 894 } 895 896 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d) succeeded\n", s)); 897 sock_set_errno(sock, 0); 898 done_socket(sock); 899 return 0; 900} 901 902/** 903 * Set a socket into listen mode. 904 * The socket may not have been used for another connection previously. 905 * 906 * @param s the socket to set to listening mode 907 * @param backlog (ATTENTION: needs TCP_LISTEN_BACKLOG=1) 908 * @return 0 on success, non-zero on failure 909 */ 910int 911lwip_listen(int s, int backlog) 912{ 913 struct lwip_sock *sock; 914 err_t err; 915 916 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_listen(%d, backlog=%d)\n", s, backlog)); 917 918 sock = get_socket(s); 919 if (!sock) { 920 return -1; 921 } 922 923 /* limit the "backlog" parameter to fit in an u8_t */ 924 backlog = LWIP_MIN(LWIP_MAX(backlog, 0), 0xff); 925 926 err = netconn_listen_with_backlog(sock->conn, (u8_t)backlog); 927 928 if (err != ERR_OK) { 929 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_listen(%d) failed, err=%d\n", s, err)); 930 if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_TCP) { 931 sock_set_errno(sock, EOPNOTSUPP); 932 } else { 933 sock_set_errno(sock, err_to_errno(err)); 934 } 935 done_socket(sock); 936 return -1; 937 } 938 939 sock_set_errno(sock, 0); 940 done_socket(sock); 941 return 0; 942} 943 944#if LWIP_TCP 945/* Helper function to loop over receiving pbufs from netconn 946 * until "len" bytes are received or we're otherwise done. 947 * Keeps sock->lastdata for peeking or partly copying. 948 */ 949static ssize_t 950lwip_recv_tcp(struct lwip_sock *sock, void *mem, size_t len, int flags) 951{ 952 u8_t apiflags = NETCONN_NOAUTORCVD; 953 ssize_t recvd = 0; 954 ssize_t recv_left = (len <= SSIZE_MAX) ? (ssize_t)len : SSIZE_MAX; 955 956 LWIP_ASSERT("no socket given", sock != NULL); 957 LWIP_ASSERT("this should be checked internally", NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP); 958 959 if (flags & MSG_DONTWAIT) { 960 apiflags |= NETCONN_DONTBLOCK; 961 } 962 963 do { 964 struct pbuf *p; 965 err_t err; 966 u16_t copylen; 967 968 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recv_tcp: top while sock->lastdata=%p\n", (void *)sock->lastdata.pbuf)); 969 /* Check if there is data left from the last recv operation. */ 970 if (sock->lastdata.pbuf) { 971 p = sock->lastdata.pbuf; 972 } else { 973 /* No data was left from the previous operation, so we try to get 974 some from the network. */ 975 err = netconn_recv_tcp_pbuf_flags(sock->conn, &p, apiflags); 976 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recv_tcp: netconn_recv err=%d, pbuf=%p\n", 977 err, (void *)p)); 978 979 if (err != ERR_OK) { 980 if (recvd > 0) { 981 /* already received data, return that (this trusts in getting the same error from 982 netconn layer again next time netconn_recv is called) */ 983 goto lwip_recv_tcp_done; 984 } 985 /* We should really do some error checking here. */ 986 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recv_tcp: p == NULL, error is \"%s\"!\n", 987 lwip_strerr(err))); 988 sock_set_errno(sock, err_to_errno(err)); 989 if (err == ERR_CLSD) { 990 return 0; 991 } else { 992 return -1; 993 } 994 } 995 LWIP_ASSERT("p != NULL", p != NULL); 996 sock->lastdata.pbuf = p; 997 } 998 999 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recv_tcp: buflen=%"U16_F" recv_left=%d off=%d\n", 1000 p->tot_len, (int)recv_left, (int)recvd)); 1001 1002 if (recv_left > p->tot_len) { 1003 copylen = p->tot_len; 1004 } else { 1005 copylen = (u16_t)recv_left; 1006 } 1007 if (recvd + copylen < recvd) { 1008 /* overflow */ 1009 copylen = (u16_t)(SSIZE_MAX - recvd); 1010 } 1011 1012 /* copy the contents of the received buffer into 1013 the supplied memory pointer mem */ 1014 pbuf_copy_partial(p, (u8_t *)mem + recvd, copylen, 0); 1015 1016 recvd += copylen; 1017 1018 /* TCP combines multiple pbufs for one recv */ 1019 LWIP_ASSERT("invalid copylen, len would underflow", recv_left >= copylen); 1020 recv_left -= copylen; 1021 1022 /* Unless we peek the incoming message... */ 1023 if ((flags & MSG_PEEK) == 0) { 1024 /* ... check if there is data left in the pbuf */ 1025 LWIP_ASSERT("invalid copylen", p->tot_len >= copylen); 1026 if (p->tot_len - copylen > 0) { 1027 /* If so, it should be saved in the sock structure for the next recv call. 1028 We store the pbuf but hide/free the consumed data: */ 1029 sock->lastdata.pbuf = pbuf_free_header(p, copylen); 1030 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recv_tcp: lastdata now pbuf=%p\n", (void *)sock->lastdata.pbuf)); 1031 } else { 1032 sock->lastdata.pbuf = NULL; 1033 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recv_tcp: deleting pbuf=%p\n", (void *)p)); 1034 pbuf_free(p); 1035 } 1036 } 1037 /* once we have some data to return, only add more if we don't need to wait */ 1038 apiflags |= NETCONN_DONTBLOCK | NETCONN_NOFIN; 1039 /* @todo: do we need to support peeking more than one pbuf? */ 1040 } while ((recv_left > 0) && !(flags & MSG_PEEK)); 1041lwip_recv_tcp_done: 1042 if ((recvd > 0) && !(flags & MSG_PEEK)) { 1043 /* ensure window update after copying all data */ 1044 netconn_tcp_recvd(sock->conn, (size_t)recvd); 1045 } 1046 sock_set_errno(sock, 0); 1047 return recvd; 1048} 1049#endif 1050 1051/* Convert a netbuf's address data to struct sockaddr */ 1052static int 1053lwip_sock_make_addr(struct netconn *conn, ip_addr_t *fromaddr, u16_t port, 1054 struct sockaddr *from, socklen_t *fromlen) 1055{ 1056 int truncated = 0; 1057 union sockaddr_aligned saddr; 1058 1059 LWIP_UNUSED_ARG(conn); 1060 1061 LWIP_ASSERT("fromaddr != NULL", fromaddr != NULL); 1062 LWIP_ASSERT("from != NULL", from != NULL); 1063 LWIP_ASSERT("fromlen != NULL", fromlen != NULL); 1064 1065#if LWIP_IPV4 && LWIP_IPV6 1066 /* Dual-stack: Map IPv4 addresses to IPv4 mapped IPv6 */ 1067 if (NETCONNTYPE_ISIPV6(netconn_type(conn)) && IP_IS_V4(fromaddr)) { 1068 ip4_2_ipv4_mapped_ipv6(ip_2_ip6(fromaddr), ip_2_ip4(fromaddr)); 1069 IP_SET_TYPE(fromaddr, IPADDR_TYPE_V6); 1070 } 1071#endif /* LWIP_IPV4 && LWIP_IPV6 */ 1072 1073 IPADDR_PORT_TO_SOCKADDR(&saddr, fromaddr, port); 1074 DF_NADDR(*fromaddr); 1075 if (*fromlen < saddr.sa.sa_len) { 1076 truncated = 1; 1077 } else if (*fromlen > saddr.sa.sa_len) { 1078 *fromlen = saddr.sa.sa_len; 1079 } 1080 MEMCPY(from, &saddr, *fromlen); 1081 return truncated; 1082} 1083 1084#if LWIP_TCP 1085/* Helper function to get a tcp socket's remote address info */ 1086static int 1087lwip_recv_tcp_from(struct lwip_sock *sock, struct sockaddr *from, socklen_t *fromlen, const char *dbg_fn, int dbg_s, ssize_t dbg_ret) 1088{ 1089 if (sock == NULL) { 1090 return 0; 1091 } 1092 LWIP_UNUSED_ARG(dbg_fn); 1093 LWIP_UNUSED_ARG(dbg_s); 1094 LWIP_UNUSED_ARG(dbg_ret); 1095 1096#if !SOCKETS_DEBUG 1097 if (from && fromlen) 1098#endif /* !SOCKETS_DEBUG */ 1099 { 1100 /* get remote addr/port from tcp_pcb */ 1101 u16_t port; 1102 ip_addr_t tmpaddr; 1103 err_t err = netconn_getaddr(sock->conn, &tmpaddr, &port, 0); 1104 LWIP_DEBUGF(SOCKETS_DEBUG, ("%s(%d): addr=", dbg_fn, dbg_s)); 1105 ip_addr_debug_print_val(SOCKETS_DEBUG, tmpaddr); 1106 LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F" len=%d\n", port, (int)dbg_ret)); 1107 if (!err && from && fromlen) { 1108 return lwip_sock_make_addr(sock->conn, &tmpaddr, port, from, fromlen); 1109 } 1110 } 1111 return 0; 1112} 1113#endif 1114 1115/* Helper function to receive a netbuf from a udp or raw netconn. 1116 * Keeps sock->lastdata for peeking. 1117 */ 1118static err_t 1119lwip_recvfrom_udp_raw(struct lwip_sock *sock, int flags, struct msghdr *msg, u16_t *datagram_len, int dbg_s) 1120{ 1121 struct netbuf *buf; 1122 u8_t apiflags; 1123 err_t err; 1124 u16_t buflen, copylen, copied; 1125 int i; 1126 1127 LWIP_UNUSED_ARG(dbg_s); 1128 LWIP_ERROR("lwip_recvfrom_udp_raw: invalid arguments", (msg->msg_iov != NULL) || (msg->msg_iovlen <= 0), return ERR_ARG;); 1129 1130 if (flags & MSG_DONTWAIT) { 1131 apiflags = NETCONN_DONTBLOCK; 1132 } else { 1133 apiflags = 0; 1134 } 1135 1136 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom_udp_raw[UDP/RAW]: top sock->lastdata=%p\n", (void *)sock->lastdata.netbuf)); 1137 /* Check if there is data left from the last recv operation. */ 1138 buf = sock->lastdata.netbuf; 1139 if (buf == NULL) { 1140 /* No data was left from the previous operation, so we try to get 1141 some from the network. */ 1142 err = netconn_recv_udp_raw_netbuf_flags(sock->conn, &buf, apiflags); 1143 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom_udp_raw[UDP/RAW]: netconn_recv err=%d, netbuf=%p\n", 1144 err, (void *)buf)); 1145 1146 if (err != ERR_OK) { 1147 return err; 1148 } 1149 LWIP_ASSERT("buf != NULL", buf != NULL); 1150 sock->lastdata.netbuf = buf; 1151 } 1152 buflen = buf->p->tot_len; 1153 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom_udp_raw: buflen=%"U16_F"\n", buflen)); 1154 1155 copied = 0; 1156 /* copy the pbuf payload into the iovs */ 1157 for (i = 0; (i < msg->msg_iovlen) && (copied < buflen); i++) { 1158 u16_t len_left = (u16_t)(buflen - copied); 1159 if (msg->msg_iov[i].iov_len > len_left) { 1160 copylen = len_left; 1161 } else { 1162 copylen = (u16_t)msg->msg_iov[i].iov_len; 1163 } 1164 1165 /* copy the contents of the received buffer into 1166 the supplied memory buffer */ 1167 pbuf_copy_partial(buf->p, (u8_t *)msg->msg_iov[i].iov_base, copylen, copied); 1168 copied = (u16_t)(copied + copylen); 1169 } 1170 1171 /* Check to see from where the data was.*/ 1172#if !SOCKETS_DEBUG 1173 if (msg->msg_name && msg->msg_namelen) 1174#endif /* !SOCKETS_DEBUG */ 1175 { 1176 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom_udp_raw(%d): addr=", dbg_s)); 1177 ip_addr_debug_print_val(SOCKETS_DEBUG, *netbuf_fromaddr(buf)); 1178 LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F" len=%d\n", netbuf_fromport(buf), copied)); 1179 if (msg->msg_name && msg->msg_namelen) { 1180 lwip_sock_make_addr(sock->conn, netbuf_fromaddr(buf), netbuf_fromport(buf), 1181 (struct sockaddr *)msg->msg_name, &msg->msg_namelen); 1182 } 1183 } 1184 1185 /* Initialize flag output */ 1186 msg->msg_flags = 0; 1187 1188 if (msg->msg_control) { 1189 u8_t wrote_msg = 0; 1190#if LWIP_NETBUF_RECVINFO 1191 /* Check if packet info was recorded */ 1192 if (buf->flags & NETBUF_FLAG_DESTADDR) { 1193 if (IP_IS_V4(&buf->toaddr)) { 1194#if LWIP_IPV4 1195 if (msg->msg_controllen >= CMSG_SPACE(sizeof(struct in_pktinfo))) { 1196 struct cmsghdr *chdr = CMSG_FIRSTHDR(msg); /* This will always return a header!! */ 1197 struct in_pktinfo *pkti = (struct in_pktinfo *)CMSG_DATA(chdr); 1198 chdr->cmsg_level = IPPROTO_IP; 1199 chdr->cmsg_type = IP_PKTINFO; 1200 chdr->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo)); 1201 pkti->ipi_ifindex = buf->p->if_idx; 1202 inet_addr_from_ip4addr(&pkti->ipi_addr, ip_2_ip4(netbuf_destaddr(buf))); 1203 msg->msg_controllen = CMSG_SPACE(sizeof(struct in_pktinfo)); 1204 wrote_msg = 1; 1205 } else { 1206 msg->msg_flags |= MSG_CTRUNC; 1207 } 1208#endif /* LWIP_IPV4 */ 1209 } 1210 } 1211#endif /* LWIP_NETBUF_RECVINFO */ 1212 1213 if (!wrote_msg) { 1214 msg->msg_controllen = 0; 1215 } 1216 } 1217 1218 /* If we don't peek the incoming message: zero lastdata pointer and free the netbuf */ 1219 if ((flags & MSG_PEEK) == 0) { 1220 sock->lastdata.netbuf = NULL; 1221 netbuf_delete(buf); 1222 } 1223 if (datagram_len) { 1224 *datagram_len = buflen; 1225 } 1226 return ERR_OK; 1227} 1228 1229ssize_t 1230lwip_recvfrom(int s, void *mem, size_t len, int flags, 1231 struct sockaddr *from, socklen_t *fromlen) 1232{ 1233#if LWIP_ENABLE_DISTRIBUTED_NET && LWIP_USE_GET_HOST_BY_NAME_EXTERNAL 1234 if (!is_distributed_net_enabled()) { 1235 return lwip_recvfrom_internal(s, mem, len, flags, from, fromlen); 1236 } 1237 return distributed_net_recvfrom(s, mem, len, flags, from, fromlen); 1238} 1239 1240ssize_t 1241lwip_recvfrom_internal(int s, void *mem, size_t len, int flags, 1242 struct sockaddr *from, socklen_t *fromlen) 1243{ 1244#endif 1245 struct lwip_sock *sock; 1246 ssize_t ret; 1247 1248 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d, %p, %"SZT_F", 0x%x, ..)\n", s, mem, len, flags)); 1249 sock = get_socket(s); 1250 if (!sock) { 1251 return -1; 1252 } 1253#if LWIP_TCP 1254 if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) { 1255 ret = lwip_recv_tcp(sock, mem, len, flags); 1256 lwip_recv_tcp_from(sock, from, fromlen, "lwip_recvfrom", s, ret); 1257 done_socket(sock); 1258 return ret; 1259 } else 1260#endif 1261 { 1262 u16_t datagram_len = 0; 1263 struct iovec vec; 1264 struct msghdr msg; 1265 err_t err; 1266 vec.iov_base = mem; 1267 vec.iov_len = len; 1268 msg.msg_control = NULL; 1269 msg.msg_controllen = 0; 1270 msg.msg_flags = 0; 1271 msg.msg_iov = &vec; 1272 msg.msg_iovlen = 1; 1273 msg.msg_name = from; 1274 msg.msg_namelen = (fromlen ? *fromlen : 0); 1275 err = lwip_recvfrom_udp_raw(sock, flags, &msg, &datagram_len, s); 1276 if (err != ERR_OK) { 1277 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom[UDP/RAW](%d): buf == NULL, error is \"%s\"!\n", 1278 s, lwip_strerr(err))); 1279 sock_set_errno(sock, err_to_errno(err)); 1280 done_socket(sock); 1281 return -1; 1282 } 1283 ret = (ssize_t)LWIP_MIN(LWIP_MIN(len, datagram_len), SSIZE_MAX); 1284 if (fromlen) { 1285 *fromlen = msg.msg_namelen; 1286 } 1287 } 1288 1289 sock_set_errno(sock, 0); 1290 done_socket(sock); 1291 return ret; 1292} 1293 1294ssize_t 1295lwip_read(int s, void *mem, size_t len) 1296{ 1297 return lwip_recvfrom(s, mem, len, 0, NULL, NULL); 1298} 1299 1300ssize_t 1301lwip_readv(int s, const struct iovec *iov, int iovcnt) 1302{ 1303 struct msghdr msg; 1304 1305 msg.msg_name = NULL; 1306 msg.msg_namelen = 0; 1307 /* Hack: we have to cast via number to cast from 'const' pointer to non-const. 1308 Blame the opengroup standard for this inconsistency. */ 1309 msg.msg_iov = LWIP_CONST_CAST(struct iovec *, iov); 1310 msg.msg_iovlen = iovcnt; 1311 msg.msg_control = NULL; 1312 msg.msg_controllen = 0; 1313 msg.msg_flags = 0; 1314 return lwip_recvmsg(s, &msg, 0); 1315} 1316 1317ssize_t 1318lwip_recv(int s, void *mem, size_t len, int flags) 1319{ 1320 return lwip_recvfrom(s, mem, len, flags, NULL, NULL); 1321} 1322 1323ssize_t 1324lwip_recvmsg(int s, struct msghdr *message, int flags) 1325{ 1326 struct lwip_sock *sock; 1327 int i; 1328 ssize_t buflen; 1329 1330 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvmsg(%d, message=%p, flags=0x%x)\n", s, (void *)message, flags)); 1331 LWIP_ERROR("lwip_recvmsg: invalid message pointer", message != NULL, return ERR_ARG;); 1332 LWIP_ERROR("lwip_recvmsg: unsupported flags", (flags & ~(MSG_PEEK|MSG_DONTWAIT)) == 0, 1333 set_errno(EOPNOTSUPP); return -1;); 1334 1335 if ((message->msg_iovlen <= 0) || (message->msg_iovlen > IOV_MAX)) { 1336 set_errno(EMSGSIZE); 1337 return -1; 1338 } 1339 1340 sock = get_socket(s); 1341 if (!sock) { 1342 return -1; 1343 } 1344 1345 /* check for valid vectors */ 1346 buflen = 0; 1347 for (i = 0; i < message->msg_iovlen; i++) { 1348 if ((message->msg_iov[i].iov_base == NULL) || ((ssize_t)message->msg_iov[i].iov_len <= 0) || 1349 ((size_t)(ssize_t)message->msg_iov[i].iov_len != message->msg_iov[i].iov_len) || 1350 ((ssize_t)(buflen + (ssize_t)message->msg_iov[i].iov_len) <= 0)) { 1351 sock_set_errno(sock, err_to_errno(ERR_VAL)); 1352 done_socket(sock); 1353 return -1; 1354 } 1355 buflen = (ssize_t)(buflen + (ssize_t)message->msg_iov[i].iov_len); 1356 } 1357 1358 if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) { 1359#if LWIP_TCP 1360 int recv_flags = flags; 1361 message->msg_flags = 0; 1362 /* recv the data */ 1363 buflen = 0; 1364 for (i = 0; i < message->msg_iovlen; i++) { 1365 /* try to receive into this vector's buffer */ 1366 ssize_t recvd_local = lwip_recv_tcp(sock, message->msg_iov[i].iov_base, message->msg_iov[i].iov_len, recv_flags); 1367 if (recvd_local > 0) { 1368 /* sum up received bytes */ 1369 buflen += recvd_local; 1370 } 1371 if ((recvd_local < 0) || (recvd_local < (int)message->msg_iov[i].iov_len) || 1372 (flags & MSG_PEEK)) { 1373 /* returned prematurely (or peeking, which might actually be limitated to the first iov) */ 1374 if (buflen <= 0) { 1375 /* nothing received at all, propagate the error */ 1376 buflen = recvd_local; 1377 } 1378 break; 1379 } 1380 /* pass MSG_DONTWAIT to lwip_recv_tcp() to prevent waiting for more data */ 1381 recv_flags |= MSG_DONTWAIT; 1382 } 1383 if (buflen > 0) { 1384 /* reset socket error since we have received something */ 1385 sock_set_errno(sock, 0); 1386 } 1387 /* " If the socket is connected, the msg_name and msg_namelen members shall be ignored." */ 1388 done_socket(sock); 1389 return buflen; 1390#else /* LWIP_TCP */ 1391 sock_set_errno(sock, err_to_errno(ERR_ARG)); 1392 done_socket(sock); 1393 return -1; 1394#endif /* LWIP_TCP */ 1395 } 1396 /* else, UDP and RAW NETCONNs */ 1397#if LWIP_UDP || LWIP_RAW 1398 { 1399 u16_t datagram_len = 0; 1400 err_t err; 1401 err = lwip_recvfrom_udp_raw(sock, flags, message, &datagram_len, s); 1402 if (err != ERR_OK) { 1403 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvmsg[UDP/RAW](%d): buf == NULL, error is \"%s\"!\n", 1404 s, lwip_strerr(err))); 1405 sock_set_errno(sock, err_to_errno(err)); 1406 done_socket(sock); 1407 return -1; 1408 } 1409 if (datagram_len > buflen) { 1410 message->msg_flags |= MSG_TRUNC; 1411 } 1412 1413 sock_set_errno(sock, 0); 1414 done_socket(sock); 1415 return (int)datagram_len; 1416 } 1417#else /* LWIP_UDP || LWIP_RAW */ 1418 sock_set_errno(sock, err_to_errno(ERR_ARG)); 1419 done_socket(sock); 1420 return -1; 1421#endif /* LWIP_UDP || LWIP_RAW */ 1422} 1423 1424ssize_t 1425lwip_send(int s, const void *data, size_t size, int flags) 1426{ 1427 struct lwip_sock *sock; 1428 err_t err; 1429 u8_t write_flags; 1430 size_t written; 1431 1432 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_send(%d, data=%p, size=%"SZT_F", flags=0x%x)\n", 1433 s, data, size, flags)); 1434 1435 sock = get_socket(s); 1436 if (!sock) { 1437 return -1; 1438 } 1439 1440 if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_TCP) { 1441#if (LWIP_UDP || LWIP_RAW) 1442 done_socket(sock); 1443#if LWIP_ENABLE_DISTRIBUTED_NET && LWIP_USE_GET_HOST_BY_NAME_EXTERNAL 1444 return lwip_sendto_internal(s, data, size, flags, NULL, 0); 1445#else 1446 return lwip_sendto(s, data, size, flags, NULL, 0); 1447#endif 1448#else /* (LWIP_UDP || LWIP_RAW) */ 1449 sock_set_errno(sock, err_to_errno(ERR_ARG)); 1450 done_socket(sock); 1451 return -1; 1452#endif /* (LWIP_UDP || LWIP_RAW) */ 1453 } 1454 1455 write_flags = (u8_t)(NETCONN_COPY | 1456 ((flags & MSG_MORE) ? NETCONN_MORE : 0) | 1457 ((flags & MSG_DONTWAIT) ? NETCONN_DONTBLOCK : 0)); 1458 written = 0; 1459 err = netconn_write_partly(sock->conn, data, size, write_flags, &written); 1460 1461 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_send(%d) err=%d written=%"SZT_F"\n", s, err, written)); 1462 sock_set_errno(sock, err_to_errno(err)); 1463 done_socket(sock); 1464 /* casting 'written' to ssize_t is OK here since the netconn API limits it to SSIZE_MAX */ 1465 return (err == ERR_OK ? (ssize_t)written : -1); 1466} 1467 1468ssize_t 1469lwip_sendmsg(int s, const struct msghdr *msg, int flags) 1470{ 1471#if LWIP_ENABLE_DISTRIBUTED_NET && LWIP_USE_GET_HOST_BY_NAME_EXTERNAL && LWIP_DISTRIBUTED_NET_ENABLE_SENDMSG 1472 if (!is_distributed_net_enabled()) { 1473 return lwip_sendmsg_internal(s, msg, flags); 1474 } 1475 return distributed_net_sendmsg(s, msg, flags); 1476} 1477 1478ssize_t 1479lwip_sendmsg_internal(int s, const struct msghdr *msg, int flags) 1480{ 1481#endif 1482 struct lwip_sock *sock; 1483#if LWIP_TCP 1484 u8_t write_flags; 1485 size_t written; 1486#endif 1487 err_t err = ERR_OK; 1488 1489 sock = get_socket(s); 1490 if (!sock) { 1491 return -1; 1492 } 1493 1494 LWIP_ERROR("lwip_sendmsg: invalid msghdr", msg != NULL, 1495 sock_set_errno(sock, err_to_errno(ERR_ARG)); done_socket(sock); return -1;); 1496 LWIP_ERROR("lwip_sendmsg: invalid msghdr iov", msg->msg_iov != NULL, 1497 sock_set_errno(sock, err_to_errno(ERR_ARG)); done_socket(sock); return -1;); 1498 LWIP_ERROR("lwip_sendmsg: maximum iovs exceeded", (msg->msg_iovlen > 0) && (msg->msg_iovlen <= IOV_MAX), 1499 sock_set_errno(sock, EMSGSIZE); done_socket(sock); return -1;); 1500 LWIP_ERROR("lwip_sendmsg: unsupported flags", (flags & ~(MSG_DONTWAIT | MSG_MORE)) == 0, 1501 sock_set_errno(sock, EOPNOTSUPP); done_socket(sock); return -1;); 1502 1503 LWIP_UNUSED_ARG(msg->msg_control); 1504 LWIP_UNUSED_ARG(msg->msg_controllen); 1505 LWIP_UNUSED_ARG(msg->msg_flags); 1506 1507 if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) { 1508#if LWIP_TCP 1509 write_flags = (u8_t)(NETCONN_COPY | 1510 ((flags & MSG_MORE) ? NETCONN_MORE : 0) | 1511 ((flags & MSG_DONTWAIT) ? NETCONN_DONTBLOCK : 0)); 1512 1513 written = 0; 1514 err = netconn_write_vectors_partly(sock->conn, (struct netvector *)msg->msg_iov, (u16_t)msg->msg_iovlen, write_flags, &written); 1515 sock_set_errno(sock, err_to_errno(err)); 1516 done_socket(sock); 1517 /* casting 'written' to ssize_t is OK here since the netconn API limits it to SSIZE_MAX */ 1518 return (err == ERR_OK ? (ssize_t)written : -1); 1519#else /* LWIP_TCP */ 1520 sock_set_errno(sock, err_to_errno(ERR_ARG)); 1521 done_socket(sock); 1522 return -1; 1523#endif /* LWIP_TCP */ 1524 } 1525 /* else, UDP and RAW NETCONNs */ 1526#if LWIP_UDP || LWIP_RAW 1527 { 1528 struct netbuf chain_buf; 1529 int i; 1530 ssize_t size = 0; 1531 1532 LWIP_UNUSED_ARG(flags); 1533 LWIP_ERROR("lwip_sendmsg: invalid msghdr name", (((msg->msg_name == NULL) && (msg->msg_namelen == 0)) || 1534 IS_SOCK_ADDR_LEN_VALID(msg->msg_namelen)), 1535 sock_set_errno(sock, err_to_errno(ERR_ARG)); done_socket(sock); return -1;); 1536 1537 /* initialize chain buffer with destination */ 1538 memset(&chain_buf, 0, sizeof(struct netbuf)); 1539 if (msg->msg_name) { 1540 u16_t remote_port; 1541 SOCKADDR_TO_IPADDR_PORT((const struct sockaddr *)msg->msg_name, &chain_buf.addr, remote_port); 1542 netbuf_fromport(&chain_buf) = remote_port; 1543 } 1544#if LWIP_NETIF_TX_SINGLE_PBUF 1545 for (i = 0; i < msg->msg_iovlen; i++) { 1546 size += msg->msg_iov[i].iov_len; 1547 if ((msg->msg_iov[i].iov_len > INT_MAX) || (size < (int)msg->msg_iov[i].iov_len)) { 1548 /* overflow */ 1549 goto sendmsg_emsgsize; 1550 } 1551 } 1552 if (size > 0xFFFF) { 1553 /* overflow */ 1554 goto sendmsg_emsgsize; 1555 } 1556 /* Allocate a new netbuf and copy the data into it. */ 1557 if (netbuf_alloc(&chain_buf, (u16_t)size) == NULL) { 1558 err = ERR_MEM; 1559 } else { 1560 /* flatten the IO vectors */ 1561 size_t offset = 0; 1562 for (i = 0; i < msg->msg_iovlen; i++) { 1563 MEMCPY(&((u8_t *)chain_buf.p->payload)[offset], msg->msg_iov[i].iov_base, msg->msg_iov[i].iov_len); 1564 offset += msg->msg_iov[i].iov_len; 1565 } 1566#if LWIP_CHECKSUM_ON_COPY 1567 { 1568 /* This can be improved by using LWIP_CHKSUM_COPY() and aggregating the checksum for each IO vector */ 1569 u16_t chksum = ~inet_chksum_pbuf(chain_buf.p); 1570 netbuf_set_chksum(&chain_buf, chksum); 1571 } 1572#endif /* LWIP_CHECKSUM_ON_COPY */ 1573 err = ERR_OK; 1574 } 1575#else /* LWIP_NETIF_TX_SINGLE_PBUF */ 1576 /* create a chained netbuf from the IO vectors. NOTE: we assemble a pbuf chain 1577 manually to avoid having to allocate, chain, and delete a netbuf for each iov */ 1578 for (i = 0; i < msg->msg_iovlen; i++) { 1579 struct pbuf *p; 1580 if (msg->msg_iov[i].iov_len > 0xFFFF) { 1581 /* overflow */ 1582 goto sendmsg_emsgsize; 1583 } 1584 p = pbuf_alloc(PBUF_TRANSPORT, 0, PBUF_REF); 1585 if (p == NULL) { 1586 err = ERR_MEM; /* let netbuf_delete() cleanup chain_buf */ 1587 break; 1588 } 1589 p->payload = msg->msg_iov[i].iov_base; 1590 p->len = p->tot_len = (u16_t)msg->msg_iov[i].iov_len; 1591 /* netbuf empty, add new pbuf */ 1592 if (chain_buf.p == NULL) { 1593 chain_buf.p = chain_buf.ptr = p; 1594 /* add pbuf to existing pbuf chain */ 1595 } else { 1596 if (chain_buf.p->tot_len + p->len > 0xffff) { 1597 /* overflow */ 1598 pbuf_free(p); 1599 goto sendmsg_emsgsize; 1600 } 1601 pbuf_cat(chain_buf.p, p); 1602 } 1603 } 1604 /* save size of total chain */ 1605 if (err == ERR_OK) { 1606 size = netbuf_len(&chain_buf); 1607 } 1608#endif /* LWIP_NETIF_TX_SINGLE_PBUF */ 1609 1610 if (err == ERR_OK) { 1611#if LWIP_IPV4 && LWIP_IPV6 1612 /* Dual-stack: Unmap IPv4 mapped IPv6 addresses */ 1613 if (IP_IS_V6_VAL(chain_buf.addr) && ip6_addr_isipv4mappedipv6(ip_2_ip6(&chain_buf.addr))) { 1614 unmap_ipv4_mapped_ipv6(ip_2_ip4(&chain_buf.addr), ip_2_ip6(&chain_buf.addr)); 1615 IP_SET_TYPE_VAL(chain_buf.addr, IPADDR_TYPE_V4); 1616 } 1617#endif /* LWIP_IPV4 && LWIP_IPV6 */ 1618 1619 /* send the data */ 1620 err = netconn_send(sock->conn, &chain_buf); 1621 } 1622 1623 /* deallocated the buffer */ 1624 netbuf_free(&chain_buf); 1625 1626 sock_set_errno(sock, err_to_errno(err)); 1627 done_socket(sock); 1628 return (err == ERR_OK ? size : -1); 1629sendmsg_emsgsize: 1630 sock_set_errno(sock, EMSGSIZE); 1631 netbuf_free(&chain_buf); 1632 done_socket(sock); 1633 return -1; 1634 } 1635#else /* LWIP_UDP || LWIP_RAW */ 1636 sock_set_errno(sock, err_to_errno(ERR_ARG)); 1637 done_socket(sock); 1638 return -1; 1639#endif /* LWIP_UDP || LWIP_RAW */ 1640} 1641 1642ssize_t 1643lwip_sendto(int s, const void *data, size_t size, int flags, 1644 const struct sockaddr *to, socklen_t tolen) 1645{ 1646#if LWIP_ENABLE_DISTRIBUTED_NET && LWIP_USE_GET_HOST_BY_NAME_EXTERNAL 1647 if (!is_distributed_net_enabled()) { 1648 return lwip_sendto_internal(s, data, size, flags, to, tolen); 1649 } 1650 return distributed_net_sendto(s, data, size, flags, to, tolen); 1651} 1652 1653ssize_t 1654lwip_sendto_internal(int s, const void *data, size_t size, int flags, 1655 const struct sockaddr *to, socklen_t tolen) 1656{ 1657#endif 1658 struct lwip_sock *sock; 1659 err_t err; 1660 u16_t short_size; 1661 u16_t remote_port; 1662 struct netbuf buf; 1663 1664 sock = get_socket(s); 1665 if (!sock) { 1666 return -1; 1667 } 1668 1669 if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) { 1670#if LWIP_TCP 1671 done_socket(sock); 1672 return lwip_send(s, data, size, flags); 1673#else /* LWIP_TCP */ 1674 LWIP_UNUSED_ARG(flags); 1675 sock_set_errno(sock, err_to_errno(ERR_ARG)); 1676 done_socket(sock); 1677 return -1; 1678#endif /* LWIP_TCP */ 1679 } 1680 1681 if (size > LWIP_MIN(0xFFFF, SSIZE_MAX)) { 1682 /* cannot fit into one datagram (at least for us) */ 1683 sock_set_errno(sock, EMSGSIZE); 1684 done_socket(sock); 1685 return -1; 1686 } 1687 short_size = (u16_t)size; 1688 LWIP_ERROR("lwip_sendto: invalid address", (((to == NULL) && (tolen == 0)) || 1689 (IS_SOCK_ADDR_LEN_VALID(tolen) && 1690 ((to != NULL) && (IS_SOCK_ADDR_TYPE_VALID(to) && IS_SOCK_ADDR_ALIGNED(to))))), 1691 sock_set_errno(sock, err_to_errno(ERR_ARG)); done_socket(sock); return -1;); 1692 LWIP_UNUSED_ARG(tolen); 1693 1694 /* initialize a buffer */ 1695 buf.p = buf.ptr = NULL; 1696#if LWIP_CHECKSUM_ON_COPY 1697 buf.flags = 0; 1698#endif /* LWIP_CHECKSUM_ON_COPY */ 1699 if (to) { 1700 SOCKADDR_TO_IPADDR_PORT(to, &buf.addr, remote_port); 1701 } else { 1702 remote_port = 0; 1703 ip_addr_set_any(NETCONNTYPE_ISIPV6(netconn_type(sock->conn)), &buf.addr); 1704 } 1705 netbuf_fromport(&buf) = remote_port; 1706 1707 1708 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_sendto(%d, data=%p, short_size=%"U16_F", flags=0x%x to=", 1709 s, data, short_size, flags)); 1710 ip_addr_debug_print_val(SOCKETS_DEBUG, buf.addr); 1711 LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F"\n", remote_port)); 1712 1713 /* make the buffer point to the data that should be sent */ 1714#if LWIP_NETIF_TX_SINGLE_PBUF 1715 /* Allocate a new netbuf and copy the data into it. */ 1716 if (netbuf_alloc(&buf, short_size) == NULL) { 1717 err = ERR_MEM; 1718 } else { 1719#if LWIP_CHECKSUM_ON_COPY 1720 if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_RAW) { 1721 u16_t chksum = LWIP_CHKSUM_COPY(buf.p->payload, data, short_size); 1722 netbuf_set_chksum(&buf, chksum); 1723 } else 1724#endif /* LWIP_CHECKSUM_ON_COPY */ 1725 { 1726 MEMCPY(buf.p->payload, data, short_size); 1727 } 1728 err = ERR_OK; 1729 } 1730#else /* LWIP_NETIF_TX_SINGLE_PBUF */ 1731 err = netbuf_ref(&buf, data, short_size); 1732#endif /* LWIP_NETIF_TX_SINGLE_PBUF */ 1733 if (err == ERR_OK) { 1734#if LWIP_IPV4 && LWIP_IPV6 1735 /* Dual-stack: Unmap IPv4 mapped IPv6 addresses */ 1736 if (IP_IS_V6_VAL(buf.addr) && ip6_addr_isipv4mappedipv6(ip_2_ip6(&buf.addr))) { 1737 unmap_ipv4_mapped_ipv6(ip_2_ip4(&buf.addr), ip_2_ip6(&buf.addr)); 1738 IP_SET_TYPE_VAL(buf.addr, IPADDR_TYPE_V4); 1739 } 1740#endif /* LWIP_IPV4 && LWIP_IPV6 */ 1741 1742 /* send the data */ 1743 err = netconn_send(sock->conn, &buf); 1744 } 1745 1746 /* deallocated the buffer */ 1747 netbuf_free(&buf); 1748 1749 sock_set_errno(sock, err_to_errno(err)); 1750 done_socket(sock); 1751 return (err == ERR_OK ? short_size : -1); 1752} 1753 1754int 1755lwip_socket(int domain, int type, int protocol) 1756{ 1757 struct netconn *conn; 1758 int i; 1759 1760 LWIP_UNUSED_ARG(domain); /* @todo: check this */ 1761 1762 /* create a netconn */ 1763 switch (type) { 1764 case SOCK_RAW: 1765 conn = netconn_new_with_proto_and_callback(DOMAIN_TO_NETCONN_TYPE(domain, NETCONN_RAW), 1766 (u8_t)protocol, DEFAULT_SOCKET_EVENTCB); 1767 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_RAW, %d) = ", 1768 domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol)); 1769 break; 1770 case SOCK_DGRAM: 1771 conn = netconn_new_with_callback(DOMAIN_TO_NETCONN_TYPE(domain, 1772 ((protocol == IPPROTO_UDPLITE) ? NETCONN_UDPLITE : NETCONN_UDP)), 1773 DEFAULT_SOCKET_EVENTCB); 1774 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_DGRAM, %d) = ", 1775 domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol)); 1776#if LWIP_NETBUF_RECVINFO 1777 if (conn) { 1778 /* netconn layer enables pktinfo by default, sockets default to off */ 1779 conn->flags &= ~NETCONN_FLAG_PKTINFO; 1780 } 1781#endif /* LWIP_NETBUF_RECVINFO */ 1782 break; 1783 case SOCK_STREAM: 1784 conn = netconn_new_with_callback(DOMAIN_TO_NETCONN_TYPE(domain, NETCONN_TCP), DEFAULT_SOCKET_EVENTCB); 1785 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_STREAM, %d) = ", 1786 domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol)); 1787 break; 1788 default: 1789 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%d, %d/UNKNOWN, %d) = -1\n", 1790 domain, type, protocol)); 1791 set_errno(EINVAL); 1792 return -1; 1793 } 1794 1795 if (!conn) { 1796 LWIP_DEBUGF(SOCKETS_DEBUG, ("-1 / ENOBUFS (could not create netconn)\n")); 1797 set_errno(ENOBUFS); 1798 return -1; 1799 } 1800 1801 i = alloc_socket(conn, 0); 1802 1803 if (i == -1) { 1804 netconn_delete(conn); 1805 set_errno(ENFILE); 1806 return -1; 1807 } 1808 conn->socket = i; 1809 done_socket(&sockets[i - LWIP_SOCKET_OFFSET]); 1810 LWIP_DEBUGF(SOCKETS_DEBUG, ("%d\n", i)); 1811 set_errno(0); 1812 return i; 1813} 1814 1815ssize_t 1816lwip_write(int s, const void *data, size_t size) 1817{ 1818 return lwip_send(s, data, size, 0); 1819} 1820 1821ssize_t 1822lwip_writev(int s, const struct iovec *iov, int iovcnt) 1823{ 1824 struct msghdr msg; 1825 1826 msg.msg_name = NULL; 1827 msg.msg_namelen = 0; 1828 /* Hack: we have to cast via number to cast from 'const' pointer to non-const. 1829 Blame the opengroup standard for this inconsistency. */ 1830 msg.msg_iov = LWIP_CONST_CAST(struct iovec *, iov); 1831 msg.msg_iovlen = iovcnt; 1832 msg.msg_control = NULL; 1833 msg.msg_controllen = 0; 1834 msg.msg_flags = 0; 1835 return lwip_sendmsg(s, &msg, 0); 1836} 1837 1838#if LWIP_SOCKET_SELECT || LWIP_SOCKET_POLL 1839/* Add select_cb to select_cb_list. */ 1840static void 1841lwip_link_select_cb(struct lwip_select_cb *select_cb) 1842{ 1843 LWIP_SOCKET_SELECT_DECL_PROTECT(lev); 1844 1845 /* Protect the select_cb_list */ 1846 LWIP_SOCKET_SELECT_PROTECT(lev); 1847 1848 /* Put this select_cb on top of list */ 1849 select_cb->next = select_cb_list; 1850 if (select_cb_list != NULL) { 1851 select_cb_list->prev = select_cb; 1852 } 1853 select_cb_list = select_cb; 1854#if !LWIP_TCPIP_CORE_LOCKING 1855 /* Increasing this counter tells select_check_waiters that the list has changed. */ 1856 select_cb_ctr++; 1857#endif 1858 1859 /* Now we can safely unprotect */ 1860 LWIP_SOCKET_SELECT_UNPROTECT(lev); 1861} 1862 1863/* Remove select_cb from select_cb_list. */ 1864static void 1865lwip_unlink_select_cb(struct lwip_select_cb *select_cb) 1866{ 1867 LWIP_SOCKET_SELECT_DECL_PROTECT(lev); 1868 1869 /* Take us off the list */ 1870 LWIP_SOCKET_SELECT_PROTECT(lev); 1871 if (select_cb->next != NULL) { 1872 select_cb->next->prev = select_cb->prev; 1873 } 1874 if (select_cb_list == select_cb) { 1875 LWIP_ASSERT("select_cb->prev == NULL", select_cb->prev == NULL); 1876 select_cb_list = select_cb->next; 1877 } else { 1878 LWIP_ASSERT("select_cb->prev != NULL", select_cb->prev != NULL); 1879 select_cb->prev->next = select_cb->next; 1880 } 1881#if !LWIP_TCPIP_CORE_LOCKING 1882 /* Increasing this counter tells select_check_waiters that the list has changed. */ 1883 select_cb_ctr++; 1884#endif 1885 LWIP_SOCKET_SELECT_UNPROTECT(lev); 1886} 1887#endif /* LWIP_SOCKET_SELECT || LWIP_SOCKET_POLL */ 1888 1889#if LWIP_SOCKET_SELECT 1890/** 1891 * Go through the readset and writeset lists and see which socket of the sockets 1892 * set in the sets has events. On return, readset, writeset and exceptset have 1893 * the sockets enabled that had events. 1894 * 1895 * @param maxfdp1 the highest socket index in the sets 1896 * @param readset_in set of sockets to check for read events 1897 * @param writeset_in set of sockets to check for write events 1898 * @param exceptset_in set of sockets to check for error events 1899 * @param readset_out set of sockets that had read events 1900 * @param writeset_out set of sockets that had write events 1901 * @param exceptset_out set os sockets that had error events 1902 * @return number of sockets that had events (read/write/exception) (>= 0) 1903 */ 1904static int 1905lwip_selscan(int maxfdp1, fd_set *readset_in, fd_set *writeset_in, fd_set *exceptset_in, 1906 fd_set *readset_out, fd_set *writeset_out, fd_set *exceptset_out) 1907{ 1908 int i, nready = 0; 1909 fd_set lreadset, lwriteset, lexceptset; 1910 struct lwip_sock *sock; 1911 SYS_ARCH_DECL_PROTECT(lev); 1912 1913 FD_ZERO(&lreadset); 1914 FD_ZERO(&lwriteset); 1915 FD_ZERO(&lexceptset); 1916 1917 /* Go through each socket in each list to count number of sockets which 1918 currently match */ 1919 for (i = LWIP_SOCKET_OFFSET; i < maxfdp1; i++) { 1920 /* if this FD is not in the set, continue */ 1921 if (!(readset_in && FD_ISSET(i, readset_in)) && 1922 !(writeset_in && FD_ISSET(i, writeset_in)) && 1923 !(exceptset_in && FD_ISSET(i, exceptset_in))) { 1924 continue; 1925 } 1926 /* First get the socket's status (protected)... */ 1927 SYS_ARCH_PROTECT(lev); 1928 sock = tryget_socket_unconn_locked(i); 1929 if (sock != NULL) { 1930 void *lastdata = sock->lastdata.pbuf; 1931 s16_t rcvevent = sock->rcvevent; 1932 u16_t sendevent = sock->sendevent; 1933 u16_t errevent = sock->errevent; 1934 SYS_ARCH_UNPROTECT(lev); 1935 1936 /* ... then examine it: */ 1937 /* See if netconn of this socket is ready for read */ 1938 if (readset_in && FD_ISSET(i, readset_in) && ((lastdata != NULL) || (rcvevent > 0))) { 1939 FD_SET(i, &lreadset); 1940 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_selscan: fd=%d ready for reading\n", i)); 1941 nready++; 1942 } 1943 /* See if netconn of this socket is ready for write */ 1944 if (writeset_in && FD_ISSET(i, writeset_in) && (sendevent != 0)) { 1945 FD_SET(i, &lwriteset); 1946 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_selscan: fd=%d ready for writing\n", i)); 1947 nready++; 1948 } 1949 /* See if netconn of this socket had an error */ 1950 if (exceptset_in && FD_ISSET(i, exceptset_in) && (errevent != 0)) { 1951 FD_SET(i, &lexceptset); 1952 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_selscan: fd=%d ready for exception\n", i)); 1953 nready++; 1954 } 1955 done_socket(sock); 1956 } else { 1957 SYS_ARCH_UNPROTECT(lev); 1958 /* no a valid open socket */ 1959 return -1; 1960 } 1961 } 1962 /* copy local sets to the ones provided as arguments */ 1963 *readset_out = lreadset; 1964 *writeset_out = lwriteset; 1965 *exceptset_out = lexceptset; 1966 1967 LWIP_ASSERT("nready >= 0", nready >= 0); 1968 return nready; 1969} 1970 1971#if LWIP_NETCONN_FULLDUPLEX 1972/* Mark all of the set sockets in one of the three fdsets passed to select as used. 1973 * All sockets are marked (and later unmarked), whether they are open or not. 1974 * This is OK as lwip_selscan aborts select when non-open sockets are found. 1975 */ 1976static void 1977lwip_select_inc_sockets_used_set(int maxfdp, fd_set *fdset, fd_set *used_sockets) 1978{ 1979 SYS_ARCH_DECL_PROTECT(lev); 1980 if (fdset) { 1981 int i; 1982 for (i = LWIP_SOCKET_OFFSET; i < maxfdp; i++) { 1983 /* if this FD is in the set, lock it (unless already done) */ 1984 if (FD_ISSET(i, fdset) && !FD_ISSET(i, used_sockets)) { 1985 struct lwip_sock *sock; 1986 SYS_ARCH_PROTECT(lev); 1987 sock = tryget_socket_unconn_locked(i); 1988 if (sock != NULL) { 1989 /* leave the socket used until released by lwip_select_dec_sockets_used */ 1990 FD_SET(i, used_sockets); 1991 } 1992 SYS_ARCH_UNPROTECT(lev); 1993 } 1994 } 1995 } 1996} 1997 1998/* Mark all sockets passed to select as used to prevent them from being freed 1999 * from other threads while select is running. 2000 * Marked sockets are added to 'used_sockets' to mark them only once an be able 2001 * to unmark them correctly. 2002 */ 2003static void 2004lwip_select_inc_sockets_used(int maxfdp, fd_set *fdset1, fd_set *fdset2, fd_set *fdset3, fd_set *used_sockets) 2005{ 2006 FD_ZERO(used_sockets); 2007 lwip_select_inc_sockets_used_set(maxfdp, fdset1, used_sockets); 2008 lwip_select_inc_sockets_used_set(maxfdp, fdset2, used_sockets); 2009 lwip_select_inc_sockets_used_set(maxfdp, fdset3, used_sockets); 2010} 2011 2012/* Let go all sockets that were marked as used when starting select */ 2013static void 2014lwip_select_dec_sockets_used(int maxfdp, fd_set *used_sockets) 2015{ 2016 int i; 2017 for (i = LWIP_SOCKET_OFFSET; i < maxfdp; i++) { 2018 /* if this FD is not in the set, continue */ 2019 if (FD_ISSET(i, used_sockets)) { 2020 struct lwip_sock *sock = tryget_socket_unconn_nouse(i); 2021 LWIP_ASSERT("socket gone at the end of select", sock != NULL); 2022 if (sock != NULL) { 2023 done_socket(sock); 2024 } 2025 } 2026 } 2027} 2028#else /* LWIP_NETCONN_FULLDUPLEX */ 2029#define lwip_select_inc_sockets_used(maxfdp1, readset, writeset, exceptset, used_sockets) 2030#define lwip_select_dec_sockets_used(maxfdp1, used_sockets) 2031#endif /* LWIP_NETCONN_FULLDUPLEX */ 2032 2033int 2034lwip_select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset, 2035 struct timeval *timeout) 2036{ 2037 u32_t waitres = 0; 2038 int nready; 2039 fd_set lreadset, lwriteset, lexceptset; 2040 u32_t msectimeout; 2041 int i; 2042 int maxfdp2; 2043#if LWIP_NETCONN_SEM_PER_THREAD 2044 int waited = 0; 2045#endif 2046#if LWIP_NETCONN_FULLDUPLEX 2047 fd_set used_sockets; 2048#endif 2049 SYS_ARCH_DECL_PROTECT(lev); 2050 2051 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select(%d, %p, %p, %p, tvsec=%"S32_F" tvusec=%"S32_F")\n", 2052 maxfdp1, (void *)readset, (void *) writeset, (void *) exceptset, 2053 timeout ? (s32_t)timeout->tv_sec : (s32_t) - 1, 2054 timeout ? (s32_t)timeout->tv_usec : (s32_t) - 1)); 2055 2056 if ((maxfdp1 < 0) || (maxfdp1 > LWIP_SELECT_MAXNFDS)) { 2057 set_errno(EINVAL); 2058 return -1; 2059 } 2060 2061 lwip_select_inc_sockets_used(maxfdp1, readset, writeset, exceptset, &used_sockets); 2062 2063 /* Go through each socket in each list to count number of sockets which 2064 currently match */ 2065 nready = lwip_selscan(maxfdp1, readset, writeset, exceptset, &lreadset, &lwriteset, &lexceptset); 2066 2067 if (nready < 0) { 2068 /* one of the sockets in one of the fd_sets was invalid */ 2069 set_errno(EBADF); 2070 lwip_select_dec_sockets_used(maxfdp1, &used_sockets); 2071 return -1; 2072 } else if (nready > 0) { 2073 /* one or more sockets are set, no need to wait */ 2074 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select: nready=%d\n", nready)); 2075 } else { 2076 /* If we don't have any current events, then suspend if we are supposed to */ 2077 if (timeout && timeout->tv_sec == 0 && timeout->tv_usec == 0) { 2078 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select: no timeout, returning 0\n")); 2079 /* This is OK as the local fdsets are empty and nready is zero, 2080 or we would have returned earlier. */ 2081 } else { 2082 /* None ready: add our semaphore to list: 2083 We don't actually need any dynamic memory. Our entry on the 2084 list is only valid while we are in this function, so it's ok 2085 to use local variables (unless we're running in MPU compatible 2086 mode). */ 2087 API_SELECT_CB_VAR_DECLARE(select_cb); 2088 API_SELECT_CB_VAR_ALLOC(select_cb, set_errno(ENOMEM); lwip_select_dec_sockets_used(maxfdp1, &used_sockets); return -1); 2089 memset(&API_SELECT_CB_VAR_REF(select_cb), 0, sizeof(struct lwip_select_cb)); 2090 2091 API_SELECT_CB_VAR_REF(select_cb).readset = readset; 2092 API_SELECT_CB_VAR_REF(select_cb).writeset = writeset; 2093 API_SELECT_CB_VAR_REF(select_cb).exceptset = exceptset; 2094#if LWIP_NETCONN_SEM_PER_THREAD 2095 API_SELECT_CB_VAR_REF(select_cb).sem = LWIP_NETCONN_THREAD_SEM_GET(); 2096#else /* LWIP_NETCONN_SEM_PER_THREAD */ 2097 if (sys_sem_new(&API_SELECT_CB_VAR_REF(select_cb).sem, 0) != ERR_OK) { 2098 /* failed to create semaphore */ 2099 set_errno(ENOMEM); 2100 lwip_select_dec_sockets_used(maxfdp1, &used_sockets); 2101 API_SELECT_CB_VAR_FREE(select_cb); 2102 return -1; 2103 } 2104#endif /* LWIP_NETCONN_SEM_PER_THREAD */ 2105 2106 lwip_link_select_cb(&API_SELECT_CB_VAR_REF(select_cb)); 2107 2108 /* Increase select_waiting for each socket we are interested in */ 2109 maxfdp2 = maxfdp1; 2110 for (i = LWIP_SOCKET_OFFSET; i < maxfdp1; i++) { 2111 if ((readset && FD_ISSET(i, readset)) || 2112 (writeset && FD_ISSET(i, writeset)) || 2113 (exceptset && FD_ISSET(i, exceptset))) { 2114 struct lwip_sock *sock; 2115 SYS_ARCH_PROTECT(lev); 2116 sock = tryget_socket_unconn_locked(i); 2117 if (sock != NULL) { 2118 sock->select_waiting++; 2119 if (sock->select_waiting == 0) { 2120 /* overflow - too many threads waiting */ 2121 sock->select_waiting--; 2122 nready = -1; 2123 maxfdp2 = i; 2124 SYS_ARCH_UNPROTECT(lev); 2125 done_socket(sock); 2126 set_errno(EBUSY); 2127 break; 2128 } 2129 SYS_ARCH_UNPROTECT(lev); 2130 done_socket(sock); 2131 } else { 2132 /* Not a valid socket */ 2133 nready = -1; 2134 maxfdp2 = i; 2135 SYS_ARCH_UNPROTECT(lev); 2136 set_errno(EBADF); 2137 break; 2138 } 2139 } 2140 } 2141 2142 if (nready >= 0) { 2143 /* Call lwip_selscan again: there could have been events between 2144 the last scan (without us on the list) and putting us on the list! */ 2145 nready = lwip_selscan(maxfdp1, readset, writeset, exceptset, &lreadset, &lwriteset, &lexceptset); 2146 if (nready < 0) { 2147 set_errno(EBADF); 2148 } else if (!nready) { 2149 /* Still none ready, just wait to be woken */ 2150 if (timeout == 0) { 2151 /* Wait forever */ 2152 msectimeout = 0; 2153 } else { 2154 long msecs_long = ((timeout->tv_sec * 1000) + ((timeout->tv_usec + 500) / 1000)); 2155 if (msecs_long <= 0) { 2156 /* Wait 1ms at least (0 means wait forever) */ 2157 msectimeout = 1; 2158 } else { 2159 msectimeout = (u32_t)msecs_long; 2160 } 2161 } 2162 2163 waitres = sys_arch_sem_wait(SELECT_SEM_PTR(API_SELECT_CB_VAR_REF(select_cb).sem), msectimeout); 2164#if LWIP_NETCONN_SEM_PER_THREAD 2165 waited = 1; 2166#endif 2167 } 2168 } 2169 2170 /* Decrease select_waiting for each socket we are interested in */ 2171 for (i = LWIP_SOCKET_OFFSET; i < maxfdp2; i++) { 2172 if ((readset && FD_ISSET(i, readset)) || 2173 (writeset && FD_ISSET(i, writeset)) || 2174 (exceptset && FD_ISSET(i, exceptset))) { 2175 struct lwip_sock *sock; 2176 SYS_ARCH_PROTECT(lev); 2177 sock = tryget_socket_unconn_nouse(i); 2178 LWIP_ASSERT("socket gone at the end of select", sock != NULL); 2179 if (sock != NULL) { 2180 /* for now, handle select_waiting==0... */ 2181 LWIP_ASSERT("sock->select_waiting > 0", sock->select_waiting > 0); 2182 if (sock->select_waiting > 0) { 2183 sock->select_waiting--; 2184 } 2185 SYS_ARCH_UNPROTECT(lev); 2186 } else { 2187 SYS_ARCH_UNPROTECT(lev); 2188 /* Not a valid socket */ 2189 nready = -1; 2190 set_errno(EBADF); 2191 } 2192 } 2193 } 2194 2195 lwip_unlink_select_cb(&API_SELECT_CB_VAR_REF(select_cb)); 2196 2197#if LWIP_NETCONN_SEM_PER_THREAD 2198 if (API_SELECT_CB_VAR_REF(select_cb).sem_signalled && (!waited || (waitres == SYS_ARCH_TIMEOUT))) { 2199 /* don't leave the thread-local semaphore signalled */ 2200 sys_arch_sem_wait(API_SELECT_CB_VAR_REF(select_cb).sem, 1); 2201 } 2202#else /* LWIP_NETCONN_SEM_PER_THREAD */ 2203 sys_sem_free(&API_SELECT_CB_VAR_REF(select_cb).sem); 2204#endif /* LWIP_NETCONN_SEM_PER_THREAD */ 2205 API_SELECT_CB_VAR_FREE(select_cb); 2206 2207 if (nready < 0) { 2208 /* This happens when a socket got closed while waiting */ 2209 lwip_select_dec_sockets_used(maxfdp1, &used_sockets); 2210 return -1; 2211 } 2212 2213 if (waitres == SYS_ARCH_TIMEOUT) { 2214 /* Timeout */ 2215 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select: timeout expired\n")); 2216 /* This is OK as the local fdsets are empty and nready is zero, 2217 or we would have returned earlier. */ 2218 } else { 2219 /* See what's set now after waiting */ 2220 nready = lwip_selscan(maxfdp1, readset, writeset, exceptset, &lreadset, &lwriteset, &lexceptset); 2221 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select: nready=%d\n", nready)); 2222 if (nready < 0) { 2223 set_errno(EBADF); 2224 lwip_select_dec_sockets_used(maxfdp1, &used_sockets); 2225 return -1; 2226 } 2227 } 2228 } 2229 } 2230 2231 lwip_select_dec_sockets_used(maxfdp1, &used_sockets); 2232 set_errno(0); 2233 if (readset) { 2234 *readset = lreadset; 2235 } 2236 if (writeset) { 2237 *writeset = lwriteset; 2238 } 2239 if (exceptset) { 2240 *exceptset = lexceptset; 2241 } 2242 return nready; 2243} 2244#endif /* LWIP_SOCKET_SELECT */ 2245 2246#if LWIP_SOCKET_POLL 2247/** Options for the lwip_pollscan function. */ 2248enum lwip_pollscan_opts 2249{ 2250 /** Clear revents in each struct pollfd. */ 2251 LWIP_POLLSCAN_CLEAR = 1, 2252 2253 /** Increment select_waiting in each struct lwip_sock. */ 2254 LWIP_POLLSCAN_INC_WAIT = 2, 2255 2256 /** Decrement select_waiting in each struct lwip_sock. */ 2257 LWIP_POLLSCAN_DEC_WAIT = 4 2258}; 2259 2260/** 2261 * Update revents in each struct pollfd. 2262 * Optionally update select_waiting in struct lwip_sock. 2263 * 2264 * @param fds array of structures to update 2265 * @param nfds number of structures in fds 2266 * @param opts what to update and how 2267 * @return number of structures that have revents != 0 2268 */ 2269static int 2270lwip_pollscan(struct pollfd *fds, nfds_t nfds, enum lwip_pollscan_opts opts) 2271{ 2272 int nready = 0; 2273 nfds_t fdi; 2274 struct lwip_sock *sock; 2275 SYS_ARCH_DECL_PROTECT(lev); 2276 2277 /* Go through each struct pollfd in the array. */ 2278 for (fdi = 0; fdi < nfds; fdi++) { 2279 if ((opts & LWIP_POLLSCAN_CLEAR) != 0) { 2280 fds[fdi].revents = 0; 2281 } 2282 2283 /* Negative fd means the caller wants us to ignore this struct. 2284 POLLNVAL means we already detected that the fd is invalid; 2285 if another thread has since opened a new socket with that fd, 2286 we must not use that socket. */ 2287 if (fds[fdi].fd >= 0 && (fds[fdi].revents & POLLNVAL) == 0) { 2288 /* First get the socket's status (protected)... */ 2289 SYS_ARCH_PROTECT(lev); 2290 sock = tryget_socket_unconn_locked(fds[fdi].fd); 2291 if (sock != NULL) { 2292 void* lastdata = sock->lastdata.pbuf; 2293 s16_t rcvevent = sock->rcvevent; 2294 u16_t sendevent = sock->sendevent; 2295 u16_t errevent = sock->errevent; 2296 2297 if ((opts & LWIP_POLLSCAN_INC_WAIT) != 0) { 2298 sock->select_waiting++; 2299 if (sock->select_waiting == 0) { 2300 /* overflow - too many threads waiting */ 2301 sock->select_waiting--; 2302 nready = -1; 2303 SYS_ARCH_UNPROTECT(lev); 2304 done_socket(sock); 2305 break; 2306 } 2307 } else if ((opts & LWIP_POLLSCAN_DEC_WAIT) != 0) { 2308 /* for now, handle select_waiting==0... */ 2309 LWIP_ASSERT("sock->select_waiting > 0", sock->select_waiting > 0); 2310 if (sock->select_waiting > 0) { 2311 sock->select_waiting--; 2312 } 2313 } 2314 SYS_ARCH_UNPROTECT(lev); 2315 done_socket(sock); 2316 2317 /* ... then examine it: */ 2318 /* See if netconn of this socket is ready for read */ 2319 if ((fds[fdi].events & POLLIN) != 0 && ((lastdata != NULL) || (rcvevent > 0))) { 2320 fds[fdi].revents |= POLLIN; 2321 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_pollscan: fd=%d ready for reading\n", fds[fdi].fd)); 2322 } 2323 /* See if netconn of this socket is ready for write */ 2324 if ((fds[fdi].events & POLLOUT) != 0 && (sendevent != 0)) { 2325 fds[fdi].revents |= POLLOUT; 2326 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_pollscan: fd=%d ready for writing\n", fds[fdi].fd)); 2327 } 2328 /* See if netconn of this socket had an error */ 2329 if (errevent != 0) { 2330 /* POLLERR is output only. */ 2331 fds[fdi].revents |= POLLERR; 2332 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_pollscan: fd=%d ready for exception\n", fds[fdi].fd)); 2333 } 2334 } else { 2335 /* Not a valid socket */ 2336 SYS_ARCH_UNPROTECT(lev); 2337 /* POLLNVAL is output only. */ 2338 fds[fdi].revents |= POLLNVAL; 2339 return -1; 2340 } 2341 } 2342 2343 /* Will return the number of structures that have events, 2344 not the number of events. */ 2345 if (fds[fdi].revents != 0) { 2346 nready++; 2347 } 2348 } 2349 2350 LWIP_ASSERT("nready >= 0", nready >= 0); 2351 return nready; 2352} 2353 2354#if LWIP_NETCONN_FULLDUPLEX 2355/* Mark all sockets as used. 2356 * 2357 * All sockets are marked (and later unmarked), whether they are open or not. 2358 * This is OK as lwip_pollscan aborts select when non-open sockets are found. 2359 */ 2360static void 2361lwip_poll_inc_sockets_used(struct pollfd *fds, nfds_t nfds) 2362{ 2363 nfds_t fdi; 2364 2365 if(fds) { 2366 /* Go through each struct pollfd in the array. */ 2367 for (fdi = 0; fdi < nfds; fdi++) { 2368 /* Increase the reference counter */ 2369 tryget_socket_unconn(fds[fdi].fd); 2370 } 2371 } 2372} 2373 2374/* Let go all sockets that were marked as used when starting poll */ 2375static void 2376lwip_poll_dec_sockets_used(struct pollfd *fds, nfds_t nfds) 2377{ 2378 nfds_t fdi; 2379 2380 if(fds) { 2381 /* Go through each struct pollfd in the array. */ 2382 for (fdi = 0; fdi < nfds; fdi++) { 2383 struct lwip_sock *sock = tryget_socket_unconn_nouse(fds[fdi].fd); 2384 if (sock != NULL) { 2385 done_socket(sock); 2386 } 2387 } 2388 } 2389} 2390#else /* LWIP_NETCONN_FULLDUPLEX */ 2391#define lwip_poll_inc_sockets_used(fds, nfds) 2392#define lwip_poll_dec_sockets_used(fds, nfds) 2393#endif /* LWIP_NETCONN_FULLDUPLEX */ 2394 2395int 2396lwip_poll(struct pollfd *fds, nfds_t nfds, int timeout) 2397{ 2398 u32_t waitres = 0; 2399 int nready; 2400 u32_t msectimeout; 2401#if LWIP_NETCONN_SEM_PER_THREAD 2402 int waited = 0; 2403#endif 2404 2405 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_poll(%p, %d, %d)\n", 2406 (void*)fds, (int)nfds, timeout)); 2407 LWIP_ERROR("lwip_poll: invalid fds", ((fds != NULL && nfds > 0) || (fds == NULL && nfds == 0)), 2408 set_errno(EINVAL); return -1;); 2409 2410 lwip_poll_inc_sockets_used(fds, nfds); 2411 2412 /* Go through each struct pollfd to count number of structures 2413 which currently match */ 2414 nready = lwip_pollscan(fds, nfds, LWIP_POLLSCAN_CLEAR); 2415 2416 if (nready < 0) { 2417 lwip_poll_dec_sockets_used(fds, nfds); 2418 return -1; 2419 } 2420 2421 /* If we don't have any current events, then suspend if we are supposed to */ 2422 if (!nready) { 2423 API_SELECT_CB_VAR_DECLARE(select_cb); 2424 2425 if (timeout == 0) { 2426 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_poll: no timeout, returning 0\n")); 2427 goto return_success; 2428 } 2429 API_SELECT_CB_VAR_ALLOC(select_cb, set_errno(EAGAIN); lwip_poll_dec_sockets_used(fds, nfds); return -1); 2430 memset(&API_SELECT_CB_VAR_REF(select_cb), 0, sizeof(struct lwip_select_cb)); 2431 2432 /* None ready: add our semaphore to list: 2433 We don't actually need any dynamic memory. Our entry on the 2434 list is only valid while we are in this function, so it's ok 2435 to use local variables. */ 2436 2437 API_SELECT_CB_VAR_REF(select_cb).poll_fds = fds; 2438 API_SELECT_CB_VAR_REF(select_cb).poll_nfds = nfds; 2439#if LWIP_NETCONN_SEM_PER_THREAD 2440 API_SELECT_CB_VAR_REF(select_cb).sem = LWIP_NETCONN_THREAD_SEM_GET(); 2441#else /* LWIP_NETCONN_SEM_PER_THREAD */ 2442 if (sys_sem_new(&API_SELECT_CB_VAR_REF(select_cb).sem, 0) != ERR_OK) { 2443 /* failed to create semaphore */ 2444 set_errno(EAGAIN); 2445 lwip_poll_dec_sockets_used(fds, nfds); 2446 API_SELECT_CB_VAR_FREE(select_cb); 2447 return -1; 2448 } 2449#endif /* LWIP_NETCONN_SEM_PER_THREAD */ 2450 2451 lwip_link_select_cb(&API_SELECT_CB_VAR_REF(select_cb)); 2452 2453 /* Increase select_waiting for each socket we are interested in. 2454 Also, check for events again: there could have been events between 2455 the last scan (without us on the list) and putting us on the list! */ 2456 nready = lwip_pollscan(fds, nfds, LWIP_POLLSCAN_INC_WAIT); 2457 2458 if (!nready) { 2459 /* Still none ready, just wait to be woken */ 2460 if (timeout < 0) { 2461 /* Wait forever */ 2462 msectimeout = 0; 2463 } else { 2464 /* timeout == 0 would have been handled earlier. */ 2465 LWIP_ASSERT("timeout > 0", timeout > 0); 2466 msectimeout = timeout; 2467 } 2468 waitres = sys_arch_sem_wait(SELECT_SEM_PTR(API_SELECT_CB_VAR_REF(select_cb).sem), msectimeout); 2469#if LWIP_NETCONN_SEM_PER_THREAD 2470 waited = 1; 2471#endif 2472 } 2473 2474 /* Decrease select_waiting for each socket we are interested in, 2475 and check which events occurred while we waited. */ 2476 nready = lwip_pollscan(fds, nfds, LWIP_POLLSCAN_DEC_WAIT); 2477 2478 lwip_unlink_select_cb(&API_SELECT_CB_VAR_REF(select_cb)); 2479 2480#if LWIP_NETCONN_SEM_PER_THREAD 2481 if (select_cb.sem_signalled && (!waited || (waitres == SYS_ARCH_TIMEOUT))) { 2482 /* don't leave the thread-local semaphore signalled */ 2483 sys_arch_sem_wait(API_SELECT_CB_VAR_REF(select_cb).sem, 1); 2484 } 2485#else /* LWIP_NETCONN_SEM_PER_THREAD */ 2486 sys_sem_free(&API_SELECT_CB_VAR_REF(select_cb).sem); 2487#endif /* LWIP_NETCONN_SEM_PER_THREAD */ 2488 API_SELECT_CB_VAR_FREE(select_cb); 2489 2490 if (nready < 0) { 2491 /* This happens when a socket got closed while waiting */ 2492 lwip_poll_dec_sockets_used(fds, nfds); 2493 return -1; 2494 } 2495 2496 if (waitres == SYS_ARCH_TIMEOUT) { 2497 /* Timeout */ 2498 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_poll: timeout expired\n")); 2499 goto return_success; 2500 } 2501 } 2502 2503 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_poll: nready=%d\n", nready)); 2504return_success: 2505 lwip_poll_dec_sockets_used(fds, nfds); 2506 set_errno(0); 2507 return nready; 2508} 2509 2510/** 2511 * Check whether event_callback should wake up a thread waiting in 2512 * lwip_poll. 2513 */ 2514static int 2515lwip_poll_should_wake(const struct lwip_select_cb *scb, int fd, int has_recvevent, int has_sendevent, int has_errevent) 2516{ 2517 nfds_t fdi; 2518 for (fdi = 0; fdi < scb->poll_nfds; fdi++) { 2519 const struct pollfd *pollfd = &scb->poll_fds[fdi]; 2520 if (pollfd->fd == fd) { 2521 /* Do not update pollfd->revents right here; 2522 that would be a data race because lwip_pollscan 2523 accesses revents without protecting. */ 2524 if (has_recvevent && (pollfd->events & POLLIN) != 0) { 2525 return 1; 2526 } 2527 if (has_sendevent && (pollfd->events & POLLOUT) != 0) { 2528 return 1; 2529 } 2530 if (has_errevent) { 2531 /* POLLERR is output only. */ 2532 return 1; 2533 } 2534 } 2535 } 2536 return 0; 2537} 2538#endif /* LWIP_SOCKET_POLL */ 2539 2540#if LWIP_SOCKET_SELECT || LWIP_SOCKET_POLL 2541/** 2542 * Callback registered in the netconn layer for each socket-netconn. 2543 * Processes recvevent (data available) and wakes up tasks waiting for select. 2544 * 2545 * @note for LWIP_TCPIP_CORE_LOCKING any caller of this function 2546 * must have the core lock held when signaling the following events 2547 * as they might cause select_list_cb to be checked: 2548 * NETCONN_EVT_RCVPLUS 2549 * NETCONN_EVT_SENDPLUS 2550 * NETCONN_EVT_ERROR 2551 * This requirement will be asserted in select_check_waiters() 2552 */ 2553static void 2554event_callback(struct netconn *conn, enum netconn_evt evt, u16_t len) 2555{ 2556 int s, check_waiters; 2557 struct lwip_sock *sock; 2558 SYS_ARCH_DECL_PROTECT(lev); 2559 2560 LWIP_UNUSED_ARG(len); 2561 2562 /* Get socket */ 2563 if (conn) { 2564 s = conn->socket; 2565 if (s < 0) { 2566 /* Data comes in right away after an accept, even though 2567 * the server task might not have created a new socket yet. 2568 * Just count down (or up) if that's the case and we 2569 * will use the data later. Note that only receive events 2570 * can happen before the new socket is set up. */ 2571 SYS_ARCH_PROTECT(lev); 2572 if (conn->socket < 0) { 2573 if (evt == NETCONN_EVT_RCVPLUS) { 2574 /* conn->socket is -1 on initialization 2575 lwip_accept adjusts sock->recvevent if conn->socket < -1 */ 2576 conn->socket--; 2577 } 2578 SYS_ARCH_UNPROTECT(lev); 2579 return; 2580 } 2581 s = conn->socket; 2582 SYS_ARCH_UNPROTECT(lev); 2583 } 2584 2585 sock = get_socket(s); 2586 if (!sock) { 2587 return; 2588 } 2589 } else { 2590 return; 2591 } 2592 2593 check_waiters = 1; 2594 SYS_ARCH_PROTECT(lev); 2595 /* Set event as required */ 2596 switch (evt) { 2597 case NETCONN_EVT_RCVPLUS: 2598 sock->rcvevent++; 2599 if (sock->rcvevent > 1) { 2600 check_waiters = 0; 2601 } 2602 break; 2603 case NETCONN_EVT_RCVMINUS: 2604 sock->rcvevent--; 2605 check_waiters = 0; 2606 break; 2607 case NETCONN_EVT_SENDPLUS: 2608 if (sock->sendevent) { 2609 check_waiters = 0; 2610 } 2611 sock->sendevent = 1; 2612 break; 2613 case NETCONN_EVT_SENDMINUS: 2614 sock->sendevent = 0; 2615 check_waiters = 0; 2616 break; 2617 case NETCONN_EVT_ERROR: 2618 sock->errevent = 1; 2619 break; 2620 default: 2621 LWIP_ASSERT("unknown event", 0); 2622 break; 2623 } 2624 2625 if (sock->select_waiting && check_waiters) { 2626 /* Save which events are active */ 2627 int has_recvevent, has_sendevent, has_errevent; 2628 has_recvevent = sock->rcvevent > 0; 2629 has_sendevent = sock->sendevent != 0; 2630 has_errevent = sock->errevent != 0; 2631 SYS_ARCH_UNPROTECT(lev); 2632 /* Check any select calls waiting on this socket */ 2633 select_check_waiters(s, has_recvevent, has_sendevent, has_errevent); 2634 } else { 2635 SYS_ARCH_UNPROTECT(lev); 2636 } 2637 poll_check_waiters(s, check_waiters); 2638 done_socket(sock); 2639} 2640 2641/** 2642 * Check if any select waiters are waiting on this socket and its events 2643 * 2644 * @note on synchronization of select_cb_list: 2645 * LWIP_TCPIP_CORE_LOCKING: the select_cb_list must only be accessed while holding 2646 * the core lock. We do a single pass through the list and signal any waiters. 2647 * Core lock should already be held when calling here!!!! 2648 2649 * !LWIP_TCPIP_CORE_LOCKING: we use SYS_ARCH_PROTECT but unlock on each iteration 2650 * of the loop, thus creating a possibility where a thread could modify the 2651 * select_cb_list during our UNPROTECT/PROTECT. We use a generational counter to 2652 * detect this change and restart the list walk. The list is expected to be small 2653 */ 2654static void select_check_waiters(int s, int has_recvevent, int has_sendevent, int has_errevent) 2655{ 2656 struct lwip_select_cb *scb; 2657#if !LWIP_TCPIP_CORE_LOCKING 2658 int last_select_cb_ctr; 2659 SYS_ARCH_DECL_PROTECT(lev); 2660#endif /* !LWIP_TCPIP_CORE_LOCKING */ 2661 2662 LWIP_ASSERT_CORE_LOCKED(); 2663 2664#if !LWIP_TCPIP_CORE_LOCKING 2665 SYS_ARCH_PROTECT(lev); 2666again: 2667 /* remember the state of select_cb_list to detect changes */ 2668 last_select_cb_ctr = select_cb_ctr; 2669#endif /* !LWIP_TCPIP_CORE_LOCKING */ 2670 for (scb = select_cb_list; scb != NULL; scb = scb->next) { 2671 if (scb->sem_signalled == 0) { 2672 /* semaphore not signalled yet */ 2673 int do_signal = 0; 2674#if LWIP_SOCKET_POLL 2675 if (scb->poll_fds != NULL) { 2676 do_signal = lwip_poll_should_wake(scb, s, has_recvevent, has_sendevent, has_errevent); 2677 } 2678#endif /* LWIP_SOCKET_POLL */ 2679#if LWIP_SOCKET_SELECT && LWIP_SOCKET_POLL 2680 else 2681#endif /* LWIP_SOCKET_SELECT && LWIP_SOCKET_POLL */ 2682#if LWIP_SOCKET_SELECT 2683 { 2684 /* Test this select call for our socket */ 2685 if (has_recvevent) { 2686 if (scb->readset && FD_ISSET(s, scb->readset)) { 2687 do_signal = 1; 2688 } 2689 } 2690 if (has_sendevent) { 2691 if (!do_signal && scb->writeset && FD_ISSET(s, scb->writeset)) { 2692 do_signal = 1; 2693 } 2694 } 2695 if (has_errevent) { 2696 if (!do_signal && scb->exceptset && FD_ISSET(s, scb->exceptset)) { 2697 do_signal = 1; 2698 } 2699 } 2700 } 2701#endif /* LWIP_SOCKET_SELECT */ 2702 if (do_signal) { 2703 scb->sem_signalled = 1; 2704 /* For !LWIP_TCPIP_CORE_LOCKING, we don't call SYS_ARCH_UNPROTECT() before signaling 2705 the semaphore, as this might lead to the select thread taking itself off the list, 2706 invalidating the semaphore. */ 2707 sys_sem_signal(SELECT_SEM_PTR(scb->sem)); 2708 } 2709 } 2710#if LWIP_TCPIP_CORE_LOCKING 2711 } 2712#else 2713 /* unlock interrupts with each step */ 2714 SYS_ARCH_UNPROTECT(lev); 2715 /* this makes sure interrupt protection time is short */ 2716 SYS_ARCH_PROTECT(lev); 2717 if (last_select_cb_ctr != select_cb_ctr) { 2718 /* someone has changed select_cb_list, restart at the beginning */ 2719 goto again; 2720 } 2721 /* remember the state of select_cb_list to detect changes */ 2722 last_select_cb_ctr = select_cb_ctr; 2723 } 2724 SYS_ARCH_UNPROTECT(lev); 2725#endif 2726} 2727#endif /* LWIP_SOCKET_SELECT || LWIP_SOCKET_POLL */ 2728 2729/** 2730 * Close one end of a full-duplex connection. 2731 */ 2732int 2733lwip_shutdown(int s, int how) 2734{ 2735 struct lwip_sock *sock; 2736 err_t err; 2737 u8_t shut_rx = 0, shut_tx = 0; 2738 2739 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_shutdown(%d, how=%d)\n", s, how)); 2740 2741 sock = get_socket(s); 2742 if (!sock) { 2743 return -1; 2744 } 2745 2746 if (sock->conn != NULL) { 2747 if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_TCP) { 2748 sock_set_errno(sock, EOPNOTSUPP); 2749 done_socket(sock); 2750 return -1; 2751 } 2752 } else { 2753 sock_set_errno(sock, ENOTCONN); 2754 done_socket(sock); 2755 return -1; 2756 } 2757 2758 if (how == SHUT_RD) { 2759 shut_rx = 1; 2760 } else if (how == SHUT_WR) { 2761 shut_tx = 1; 2762 } else if (how == SHUT_RDWR) { 2763 shut_rx = 1; 2764 shut_tx = 1; 2765 } else { 2766 sock_set_errno(sock, EINVAL); 2767 done_socket(sock); 2768 return -1; 2769 } 2770 err = netconn_shutdown(sock->conn, shut_rx, shut_tx); 2771 2772 sock_set_errno(sock, err_to_errno(err)); 2773 done_socket(sock); 2774 return (err == ERR_OK ? 0 : -1); 2775} 2776 2777static int 2778lwip_getaddrname(int s, struct sockaddr *name, socklen_t *namelen, u8_t local) 2779{ 2780 struct lwip_sock *sock; 2781 union sockaddr_aligned saddr; 2782 ip_addr_t naddr; 2783 u16_t port; 2784 err_t err; 2785 2786 sock = get_socket(s); 2787 if (!sock) { 2788 return -1; 2789 } 2790 2791 /* get the IP address and port */ 2792 err = netconn_getaddr(sock->conn, &naddr, &port, local); 2793 if (err != ERR_OK) { 2794 sock_set_errno(sock, err_to_errno(err)); 2795 done_socket(sock); 2796 return -1; 2797 } 2798 2799#if LWIP_IPV4 && LWIP_IPV6 2800 /* Dual-stack: Map IPv4 addresses to IPv4 mapped IPv6 */ 2801 if (NETCONNTYPE_ISIPV6(netconn_type(sock->conn)) && 2802 IP_IS_V4_VAL(naddr)) { 2803 ip4_2_ipv4_mapped_ipv6(ip_2_ip6(&naddr), ip_2_ip4(&naddr)); 2804 IP_SET_TYPE_VAL(naddr, IPADDR_TYPE_V6); 2805 } 2806#endif /* LWIP_IPV4 && LWIP_IPV6 */ 2807 2808 IPADDR_PORT_TO_SOCKADDR(&saddr, &naddr, port); 2809 2810 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getaddrname(%d, addr=", s)); 2811 ip_addr_debug_print_val(SOCKETS_DEBUG, naddr); 2812 LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F")\n", port)); 2813 2814 if (*namelen > saddr.sa.sa_len) { 2815 *namelen = saddr.sa.sa_len; 2816 } 2817 MEMCPY(name, &saddr, *namelen); 2818 2819 sock_set_errno(sock, 0); 2820 done_socket(sock); 2821 return 0; 2822} 2823 2824int 2825lwip_getpeername(int s, struct sockaddr *name, socklen_t *namelen) 2826{ 2827 return lwip_getaddrname(s, name, namelen, 0); 2828} 2829 2830int 2831lwip_getsockname(int s, struct sockaddr *name, socklen_t *namelen) 2832{ 2833 return lwip_getaddrname(s, name, namelen, 1); 2834} 2835 2836int 2837lwip_getsockopt(int s, int level, int optname, void *optval, socklen_t *optlen) 2838{ 2839 int err; 2840 struct lwip_sock *sock = get_socket(s); 2841#if !LWIP_TCPIP_CORE_LOCKING 2842 err_t cberr; 2843 LWIP_SETGETSOCKOPT_DATA_VAR_DECLARE(data); 2844#endif /* !LWIP_TCPIP_CORE_LOCKING */ 2845 2846 if (!sock) { 2847 return -1; 2848 } 2849 2850 if ((NULL == optval) || (NULL == optlen)) { 2851 sock_set_errno(sock, EFAULT); 2852 done_socket(sock); 2853 return -1; 2854 } 2855 2856#if LWIP_TCPIP_CORE_LOCKING 2857 /* core-locking can just call the -impl function */ 2858 LOCK_TCPIP_CORE(); 2859 err = lwip_getsockopt_impl(s, level, optname, optval, optlen); 2860 UNLOCK_TCPIP_CORE(); 2861 2862#else /* LWIP_TCPIP_CORE_LOCKING */ 2863 2864#if LWIP_MPU_COMPATIBLE 2865 /* MPU_COMPATIBLE copies the optval data, so check for max size here */ 2866 if (*optlen > LWIP_SETGETSOCKOPT_MAXOPTLEN) { 2867 sock_set_errno(sock, ENOBUFS); 2868 done_socket(sock); 2869 return -1; 2870 } 2871#endif /* LWIP_MPU_COMPATIBLE */ 2872 2873 LWIP_SETGETSOCKOPT_DATA_VAR_ALLOC(data, sock); 2874 LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).s = s; 2875 LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).level = level; 2876 LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optname = optname; 2877 LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optlen = *optlen; 2878#if !LWIP_MPU_COMPATIBLE 2879 LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optval.p = optval; 2880#endif /* !LWIP_MPU_COMPATIBLE */ 2881 LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).err = 0; 2882#if LWIP_NETCONN_SEM_PER_THREAD 2883 LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).completed_sem = LWIP_NETCONN_THREAD_SEM_GET(); 2884#else 2885 LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).completed_sem = &sock->conn->op_completed; 2886#endif 2887 cberr = tcpip_callback(lwip_getsockopt_callback, &LWIP_SETGETSOCKOPT_DATA_VAR_REF(data)); 2888 if (cberr != ERR_OK) { 2889 LWIP_SETGETSOCKOPT_DATA_VAR_FREE(data); 2890 sock_set_errno(sock, err_to_errno(cberr)); 2891 done_socket(sock); 2892 return -1; 2893 } 2894 sys_arch_sem_wait((sys_sem_t *)(LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).completed_sem), 0); 2895 2896 /* write back optlen and optval */ 2897 *optlen = LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optlen; 2898#if LWIP_MPU_COMPATIBLE 2899 MEMCPY(optval, LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optval, 2900 LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optlen); 2901#endif /* LWIP_MPU_COMPATIBLE */ 2902 2903 /* maybe lwip_getsockopt_internal has changed err */ 2904 err = LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).err; 2905 LWIP_SETGETSOCKOPT_DATA_VAR_FREE(data); 2906#endif /* LWIP_TCPIP_CORE_LOCKING */ 2907 2908 sock_set_errno(sock, err); 2909 done_socket(sock); 2910 return err ? -1 : 0; 2911} 2912 2913#if !LWIP_TCPIP_CORE_LOCKING 2914/** lwip_getsockopt_callback: only used without CORE_LOCKING 2915 * to get into the tcpip_thread 2916 */ 2917static void 2918lwip_getsockopt_callback(void *arg) 2919{ 2920 struct lwip_setgetsockopt_data *data; 2921 LWIP_ASSERT("arg != NULL", arg != NULL); 2922 data = (struct lwip_setgetsockopt_data *)arg; 2923 2924 data->err = lwip_getsockopt_impl(data->s, data->level, data->optname, 2925#if LWIP_MPU_COMPATIBLE 2926 data->optval, 2927#else /* LWIP_MPU_COMPATIBLE */ 2928 data->optval.p, 2929#endif /* LWIP_MPU_COMPATIBLE */ 2930 &data->optlen); 2931 2932 sys_sem_signal((sys_sem_t *)(data->completed_sem)); 2933} 2934#endif /* LWIP_TCPIP_CORE_LOCKING */ 2935 2936static int 2937lwip_sockopt_to_ipopt(int optname) 2938{ 2939 /* Map SO_* values to our internal SOF_* values 2940 * We should not rely on #defines in socket.h 2941 * being in sync with ip.h. 2942 */ 2943 switch (optname) { 2944 case SO_BROADCAST: 2945 return SOF_BROADCAST; 2946 case SO_KEEPALIVE: 2947 return SOF_KEEPALIVE; 2948 case SO_REUSEADDR: 2949 return SOF_REUSEADDR; 2950 default: 2951 LWIP_ASSERT("Unknown socket option", 0); 2952 return 0; 2953 } 2954} 2955 2956/** lwip_getsockopt_impl: the actual implementation of getsockopt: 2957 * same argument as lwip_getsockopt, either called directly or through callback 2958 */ 2959static int 2960lwip_getsockopt_impl(int s, int level, int optname, void *optval, socklen_t *optlen) 2961{ 2962 int err = 0; 2963 struct lwip_sock *sock = tryget_socket(s); 2964 if (!sock) { 2965 return EBADF; 2966 } 2967 2968#ifdef LWIP_HOOK_SOCKETS_GETSOCKOPT 2969 if (LWIP_HOOK_SOCKETS_GETSOCKOPT(s, sock, level, optname, optval, optlen, &err)) { 2970 return err; 2971 } 2972#endif 2973 2974 switch (level) { 2975 2976 /* Level: SOL_SOCKET */ 2977 case SOL_SOCKET: 2978 switch (optname) { 2979 2980#if LWIP_TCP 2981 case SO_ACCEPTCONN: 2982 LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, *optlen, int); 2983 if (NETCONNTYPE_GROUP(sock->conn->type) != NETCONN_TCP) { 2984 done_socket(sock); 2985 return ENOPROTOOPT; 2986 } 2987 if ((sock->conn->pcb.tcp != NULL) && (sock->conn->pcb.tcp->state == LISTEN)) { 2988 *(int *)optval = 1; 2989 } else { 2990 *(int *)optval = 0; 2991 } 2992 break; 2993#endif /* LWIP_TCP */ 2994 2995 /* The option flags */ 2996 case SO_BROADCAST: 2997 case SO_KEEPALIVE: 2998#if SO_REUSE 2999 case SO_REUSEADDR: 3000#endif /* SO_REUSE */ 3001 if ((optname == SO_BROADCAST) && 3002 (NETCONNTYPE_GROUP(sock->conn->type) != NETCONN_UDP)) { 3003 done_socket(sock); 3004 return ENOPROTOOPT; 3005 } 3006 3007 optname = lwip_sockopt_to_ipopt(optname); 3008 3009 LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, *optlen, int); 3010 *(int *)optval = ip_get_option(sock->conn->pcb.ip, optname); 3011 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, optname=0x%x, ..) = %s\n", 3012 s, optname, (*(int *)optval ? "on" : "off"))); 3013 break; 3014 3015 case SO_TYPE: 3016 LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, *optlen, int); 3017 switch (NETCONNTYPE_GROUP(netconn_type(sock->conn))) { 3018 case NETCONN_RAW: 3019 *(int *)optval = SOCK_RAW; 3020 break; 3021 case NETCONN_TCP: 3022 *(int *)optval = SOCK_STREAM; 3023 break; 3024 case NETCONN_UDP: 3025 *(int *)optval = SOCK_DGRAM; 3026 break; 3027 default: /* unrecognized socket type */ 3028 *(int *)optval = netconn_type(sock->conn); 3029 LWIP_DEBUGF(SOCKETS_DEBUG, 3030 ("lwip_getsockopt(%d, SOL_SOCKET, SO_TYPE): unrecognized socket type %d\n", 3031 s, *(int *)optval)); 3032 } /* switch (netconn_type(sock->conn)) */ 3033 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, SO_TYPE) = %d\n", 3034 s, *(int *)optval)); 3035 break; 3036 3037 case SO_ERROR: 3038 LWIP_SOCKOPT_CHECK_OPTLEN(sock, *optlen, int); 3039 *(int *)optval = err_to_errno(netconn_err(sock->conn)); 3040 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, SO_ERROR) = %d\n", 3041 s, *(int *)optval)); 3042 break; 3043 3044#if LWIP_SO_SNDTIMEO 3045 case SO_SNDTIMEO: 3046 LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, *optlen, LWIP_SO_SNDRCVTIMEO_OPTTYPE); 3047 LWIP_SO_SNDRCVTIMEO_SET(optval, netconn_get_sendtimeout(sock->conn)); 3048 break; 3049#endif /* LWIP_SO_SNDTIMEO */ 3050#if LWIP_SO_RCVTIMEO 3051 case SO_RCVTIMEO: 3052 LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, *optlen, LWIP_SO_SNDRCVTIMEO_OPTTYPE); 3053 LWIP_SO_SNDRCVTIMEO_SET(optval, netconn_get_recvtimeout(sock->conn)); 3054 break; 3055#endif /* LWIP_SO_RCVTIMEO */ 3056#if LWIP_SO_RCVBUF 3057 case SO_RCVBUF: 3058 LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, *optlen, int); 3059 *(int *)optval = netconn_get_recvbufsize(sock->conn); 3060 break; 3061#endif /* LWIP_SO_RCVBUF */ 3062#if LWIP_SO_LINGER 3063 case SO_LINGER: { 3064 s16_t conn_linger; 3065 struct linger *linger = (struct linger *)optval; 3066 LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, *optlen, struct linger); 3067 conn_linger = sock->conn->linger; 3068 if (conn_linger >= 0) { 3069 linger->l_onoff = 1; 3070 linger->l_linger = (int)conn_linger; 3071 } else { 3072 linger->l_onoff = 0; 3073 linger->l_linger = 0; 3074 } 3075 } 3076 break; 3077#endif /* LWIP_SO_LINGER */ 3078#if LWIP_UDP 3079 case SO_NO_CHECK: 3080 LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, *optlen, int, NETCONN_UDP); 3081#if LWIP_UDPLITE 3082 if (udp_is_flag_set(sock->conn->pcb.udp, UDP_FLAGS_UDPLITE)) { 3083 /* this flag is only available for UDP, not for UDP lite */ 3084 done_socket(sock); 3085 return EAFNOSUPPORT; 3086 } 3087#endif /* LWIP_UDPLITE */ 3088 *(int *)optval = udp_is_flag_set(sock->conn->pcb.udp, UDP_FLAGS_NOCHKSUM) ? 1 : 0; 3089 break; 3090#endif /* LWIP_UDP*/ 3091 default: 3092 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, UNIMPL: optname=0x%x, ..)\n", 3093 s, optname)); 3094 err = ENOPROTOOPT; 3095 break; 3096 } /* switch (optname) */ 3097 break; 3098 3099 /* Level: IPPROTO_IP */ 3100 case IPPROTO_IP: 3101 switch (optname) { 3102 case IP_TTL: 3103 LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, *optlen, int); 3104 *(int *)optval = sock->conn->pcb.ip->ttl; 3105 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_TTL) = %d\n", 3106 s, *(int *)optval)); 3107 break; 3108 case IP_TOS: 3109 LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, *optlen, int); 3110 *(int *)optval = sock->conn->pcb.ip->tos; 3111 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_TOS) = %d\n", 3112 s, *(int *)optval)); 3113 break; 3114#if LWIP_IPV4 && LWIP_MULTICAST_TX_OPTIONS && LWIP_UDP 3115 case IP_MULTICAST_TTL: 3116 LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, *optlen, u8_t); 3117 if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_UDP) { 3118 done_socket(sock); 3119 return ENOPROTOOPT; 3120 } 3121 *(u8_t *)optval = udp_get_multicast_ttl(sock->conn->pcb.udp); 3122 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_MULTICAST_TTL) = %d\n", 3123 s, *(int *)optval)); 3124 break; 3125 case IP_MULTICAST_IF: 3126 LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, *optlen, struct in_addr); 3127 if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_UDP) { 3128 done_socket(sock); 3129 return ENOPROTOOPT; 3130 } 3131 inet_addr_from_ip4addr((struct in_addr *)optval, udp_get_multicast_netif_addr(sock->conn->pcb.udp)); 3132 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_MULTICAST_IF) = 0x%"X32_F"\n", 3133 s, *(u32_t *)optval)); 3134 break; 3135 case IP_MULTICAST_LOOP: 3136 LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, *optlen, u8_t); 3137 if ((sock->conn->pcb.udp->flags & UDP_FLAGS_MULTICAST_LOOP) != 0) { 3138 *(u8_t *)optval = 1; 3139 } else { 3140 *(u8_t *)optval = 0; 3141 } 3142 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_MULTICAST_LOOP) = %d\n", 3143 s, *(int *)optval)); 3144 break; 3145#endif /* LWIP_IPV4 && LWIP_MULTICAST_TX_OPTIONS && LWIP_UDP */ 3146 default: 3147 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, UNIMPL: optname=0x%x, ..)\n", 3148 s, optname)); 3149 err = ENOPROTOOPT; 3150 break; 3151 } /* switch (optname) */ 3152 break; 3153 3154#if LWIP_TCP 3155 /* Level: IPPROTO_TCP */ 3156 case IPPROTO_TCP: 3157 /* Special case: all IPPROTO_TCP option take an int */ 3158 LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, *optlen, int, NETCONN_TCP); 3159 if (sock->conn->pcb.tcp->state == LISTEN) { 3160 done_socket(sock); 3161 return EINVAL; 3162 } 3163 switch (optname) { 3164 case TCP_NODELAY: 3165 *(int *)optval = tcp_nagle_disabled(sock->conn->pcb.tcp); 3166 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_TCP, TCP_NODELAY) = %s\n", 3167 s, (*(int *)optval) ? "on" : "off") ); 3168 break; 3169 case TCP_KEEPALIVE: 3170 *(int *)optval = (int)sock->conn->pcb.tcp->keep_idle; 3171 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_TCP, TCP_KEEPALIVE) = %d\n", 3172 s, *(int *)optval)); 3173 break; 3174 3175#if LWIP_TCP_KEEPALIVE 3176 case TCP_KEEPIDLE: 3177 *(int *)optval = (int)(sock->conn->pcb.tcp->keep_idle / 1000); 3178 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_TCP, TCP_KEEPIDLE) = %d\n", 3179 s, *(int *)optval)); 3180 break; 3181 case TCP_KEEPINTVL: 3182 *(int *)optval = (int)(sock->conn->pcb.tcp->keep_intvl / 1000); 3183 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_TCP, TCP_KEEPINTVL) = %d\n", 3184 s, *(int *)optval)); 3185 break; 3186 case TCP_KEEPCNT: 3187 *(int *)optval = (int)sock->conn->pcb.tcp->keep_cnt; 3188 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_TCP, TCP_KEEPCNT) = %d\n", 3189 s, *(int *)optval)); 3190 break; 3191#endif /* LWIP_TCP_KEEPALIVE */ 3192 default: 3193 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_TCP, UNIMPL: optname=0x%x, ..)\n", 3194 s, optname)); 3195 err = ENOPROTOOPT; 3196 break; 3197 } /* switch (optname) */ 3198 break; 3199#endif /* LWIP_TCP */ 3200 3201#if LWIP_IPV6 3202 /* Level: IPPROTO_IPV6 */ 3203 case IPPROTO_IPV6: 3204 switch (optname) { 3205 case IPV6_V6ONLY: 3206 LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, *optlen, int); 3207 *(int *)optval = (netconn_get_ipv6only(sock->conn) ? 1 : 0); 3208 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IPV6, IPV6_V6ONLY) = %d\n", 3209 s, *(int *)optval)); 3210 break; 3211 default: 3212 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IPV6, UNIMPL: optname=0x%x, ..)\n", 3213 s, optname)); 3214 err = ENOPROTOOPT; 3215 break; 3216 } /* switch (optname) */ 3217 break; 3218#endif /* LWIP_IPV6 */ 3219 3220#if LWIP_UDP && LWIP_UDPLITE 3221 /* Level: IPPROTO_UDPLITE */ 3222 case IPPROTO_UDPLITE: 3223 /* Special case: all IPPROTO_UDPLITE option take an int */ 3224 LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, *optlen, int); 3225 /* If this is no UDP lite socket, ignore any options. */ 3226 if (!NETCONNTYPE_ISUDPLITE(netconn_type(sock->conn))) { 3227 done_socket(sock); 3228 return ENOPROTOOPT; 3229 } 3230 switch (optname) { 3231 case UDPLITE_SEND_CSCOV: 3232 *(int *)optval = sock->conn->pcb.udp->chksum_len_tx; 3233 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_UDPLITE, UDPLITE_SEND_CSCOV) = %d\n", 3234 s, (*(int *)optval)) ); 3235 break; 3236 case UDPLITE_RECV_CSCOV: 3237 *(int *)optval = sock->conn->pcb.udp->chksum_len_rx; 3238 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_UDPLITE, UDPLITE_RECV_CSCOV) = %d\n", 3239 s, (*(int *)optval)) ); 3240 break; 3241 default: 3242 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_UDPLITE, UNIMPL: optname=0x%x, ..)\n", 3243 s, optname)); 3244 err = ENOPROTOOPT; 3245 break; 3246 } /* switch (optname) */ 3247 break; 3248#endif /* LWIP_UDP */ 3249 /* Level: IPPROTO_RAW */ 3250 case IPPROTO_RAW: 3251 switch (optname) { 3252#if LWIP_IPV6 && LWIP_RAW 3253 case IPV6_CHECKSUM: 3254 LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, *optlen, int, NETCONN_RAW); 3255 if (sock->conn->pcb.raw->chksum_reqd == 0) { 3256 *(int *)optval = -1; 3257 } else { 3258 *(int *)optval = sock->conn->pcb.raw->chksum_offset; 3259 } 3260 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_RAW, IPV6_CHECKSUM) = %d\n", 3261 s, (*(int *)optval)) ); 3262 break; 3263#endif /* LWIP_IPV6 && LWIP_RAW */ 3264 default: 3265 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_RAW, UNIMPL: optname=0x%x, ..)\n", 3266 s, optname)); 3267 err = ENOPROTOOPT; 3268 break; 3269 } /* switch (optname) */ 3270 break; 3271 default: 3272 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, level=0x%x, UNIMPL: optname=0x%x, ..)\n", 3273 s, level, optname)); 3274 err = ENOPROTOOPT; 3275 break; 3276 } /* switch (level) */ 3277 3278 done_socket(sock); 3279 return err; 3280} 3281 3282int 3283lwip_setsockopt(int s, int level, int optname, const void *optval, socklen_t optlen) 3284{ 3285 int err = 0; 3286 struct lwip_sock *sock = get_socket(s); 3287#if !LWIP_TCPIP_CORE_LOCKING 3288 err_t cberr; 3289 LWIP_SETGETSOCKOPT_DATA_VAR_DECLARE(data); 3290#endif /* !LWIP_TCPIP_CORE_LOCKING */ 3291 3292 if (!sock) { 3293 return -1; 3294 } 3295 3296 if (NULL == optval) { 3297 sock_set_errno(sock, EFAULT); 3298 done_socket(sock); 3299 return -1; 3300 } 3301 3302#if LWIP_TCPIP_CORE_LOCKING 3303 /* core-locking can just call the -impl function */ 3304 LOCK_TCPIP_CORE(); 3305 err = lwip_setsockopt_impl(s, level, optname, optval, optlen); 3306 UNLOCK_TCPIP_CORE(); 3307#if LWIP_LOWPOWER 3308 tcpip_send_msg_na(LOW_NON_BLOCK); 3309#endif 3310 3311#else /* LWIP_TCPIP_CORE_LOCKING */ 3312 3313#if LWIP_MPU_COMPATIBLE 3314 /* MPU_COMPATIBLE copies the optval data, so check for max size here */ 3315 if (optlen > LWIP_SETGETSOCKOPT_MAXOPTLEN) { 3316 sock_set_errno(sock, ENOBUFS); 3317 done_socket(sock); 3318 return -1; 3319 } 3320#endif /* LWIP_MPU_COMPATIBLE */ 3321 3322 LWIP_SETGETSOCKOPT_DATA_VAR_ALLOC(data, sock); 3323 LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).s = s; 3324 LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).level = level; 3325 LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optname = optname; 3326 LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optlen = optlen; 3327#if LWIP_MPU_COMPATIBLE 3328 MEMCPY(LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optval, optval, optlen); 3329#else /* LWIP_MPU_COMPATIBLE */ 3330 LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optval.pc = (const void *)optval; 3331#endif /* LWIP_MPU_COMPATIBLE */ 3332 LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).err = 0; 3333#if LWIP_NETCONN_SEM_PER_THREAD 3334 LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).completed_sem = LWIP_NETCONN_THREAD_SEM_GET(); 3335#else 3336 LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).completed_sem = &sock->conn->op_completed; 3337#endif 3338 cberr = tcpip_callback(lwip_setsockopt_callback, &LWIP_SETGETSOCKOPT_DATA_VAR_REF(data)); 3339 if (cberr != ERR_OK) { 3340 LWIP_SETGETSOCKOPT_DATA_VAR_FREE(data); 3341 sock_set_errno(sock, err_to_errno(cberr)); 3342 done_socket(sock); 3343 return -1; 3344 } 3345 sys_arch_sem_wait((sys_sem_t *)(LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).completed_sem), 0); 3346 3347 /* maybe lwip_getsockopt_internal has changed err */ 3348 err = LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).err; 3349 LWIP_SETGETSOCKOPT_DATA_VAR_FREE(data); 3350#endif /* LWIP_TCPIP_CORE_LOCKING */ 3351 3352 sock_set_errno(sock, err); 3353 done_socket(sock); 3354 return err ? -1 : 0; 3355} 3356 3357#if !LWIP_TCPIP_CORE_LOCKING 3358/** lwip_setsockopt_callback: only used without CORE_LOCKING 3359 * to get into the tcpip_thread 3360 */ 3361static void 3362lwip_setsockopt_callback(void *arg) 3363{ 3364 struct lwip_setgetsockopt_data *data; 3365 LWIP_ASSERT("arg != NULL", arg != NULL); 3366 data = (struct lwip_setgetsockopt_data *)arg; 3367 3368 data->err = lwip_setsockopt_impl(data->s, data->level, data->optname, 3369#if LWIP_MPU_COMPATIBLE 3370 data->optval, 3371#else /* LWIP_MPU_COMPATIBLE */ 3372 data->optval.pc, 3373#endif /* LWIP_MPU_COMPATIBLE */ 3374 data->optlen); 3375 3376 sys_sem_signal((sys_sem_t *)(data->completed_sem)); 3377} 3378#endif /* LWIP_TCPIP_CORE_LOCKING */ 3379 3380/** lwip_setsockopt_impl: the actual implementation of setsockopt: 3381 * same argument as lwip_setsockopt, either called directly or through callback 3382 */ 3383static int 3384lwip_setsockopt_impl(int s, int level, int optname, const void *optval, socklen_t optlen) 3385{ 3386 int err = 0; 3387 struct lwip_sock *sock = tryget_socket(s); 3388 if (!sock) { 3389 return EBADF; 3390 } 3391 3392#ifdef LWIP_HOOK_SOCKETS_SETSOCKOPT 3393 if (LWIP_HOOK_SOCKETS_SETSOCKOPT(s, sock, level, optname, optval, optlen, &err)) { 3394 return err; 3395 } 3396#endif 3397 3398 switch (level) { 3399 3400 /* Level: SOL_SOCKET */ 3401 case SOL_SOCKET: 3402 switch (optname) { 3403 3404 /* SO_ACCEPTCONN is get-only */ 3405 3406 /* The option flags */ 3407 case SO_BROADCAST: 3408 case SO_KEEPALIVE: 3409#if SO_REUSE 3410 case SO_REUSEADDR: 3411#endif /* SO_REUSE */ 3412 if ((optname == SO_BROADCAST) && 3413 (NETCONNTYPE_GROUP(sock->conn->type) != NETCONN_UDP)) { 3414 done_socket(sock); 3415 return ENOPROTOOPT; 3416 } 3417 3418 optname = lwip_sockopt_to_ipopt(optname); 3419 3420 LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, optlen, int); 3421 if (*(const int *)optval) { 3422 ip_set_option(sock->conn->pcb.ip, optname); 3423 } else { 3424 ip_reset_option(sock->conn->pcb.ip, optname); 3425 } 3426 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, SOL_SOCKET, optname=0x%x, ..) -> %s\n", 3427 s, optname, (*(const int *)optval ? "on" : "off"))); 3428 break; 3429 3430 /* SO_TYPE is get-only */ 3431 /* SO_ERROR is get-only */ 3432 3433#if LWIP_SO_SNDTIMEO 3434 case SO_SNDTIMEO: { 3435 long ms_long; 3436 LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, optlen, LWIP_SO_SNDRCVTIMEO_OPTTYPE); 3437 ms_long = LWIP_SO_SNDRCVTIMEO_GET_MS(optval); 3438 if (ms_long < 0) { 3439 done_socket(sock); 3440 return EINVAL; 3441 } 3442 netconn_set_sendtimeout(sock->conn, ms_long); 3443 break; 3444 } 3445#endif /* LWIP_SO_SNDTIMEO */ 3446#if LWIP_SO_RCVTIMEO 3447 case SO_RCVTIMEO: { 3448 long ms_long; 3449 LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, optlen, LWIP_SO_SNDRCVTIMEO_OPTTYPE); 3450 ms_long = LWIP_SO_SNDRCVTIMEO_GET_MS(optval); 3451 if (ms_long < 0) { 3452 done_socket(sock); 3453 return EINVAL; 3454 } 3455 netconn_set_recvtimeout(sock->conn, (u32_t)ms_long); 3456 break; 3457 } 3458#endif /* LWIP_SO_RCVTIMEO */ 3459#if LWIP_SO_RCVBUF 3460 case SO_RCVBUF: 3461 LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, optlen, int); 3462 netconn_set_recvbufsize(sock->conn, *(const int *)optval); 3463 break; 3464#endif /* LWIP_SO_RCVBUF */ 3465#if LWIP_SO_LINGER 3466 case SO_LINGER: { 3467 const struct linger *linger = (const struct linger *)optval; 3468 LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, optlen, struct linger); 3469 if (linger->l_onoff) { 3470 int lingersec = linger->l_linger; 3471 if (lingersec < 0) { 3472 done_socket(sock); 3473 return EINVAL; 3474 } 3475 if (lingersec > 0xFFFF) { 3476 lingersec = 0xFFFF; 3477 } 3478 sock->conn->linger = (s16_t)lingersec; 3479 } else { 3480 sock->conn->linger = -1; 3481 } 3482 } 3483 break; 3484#endif /* LWIP_SO_LINGER */ 3485#if LWIP_UDP 3486 case SO_NO_CHECK: 3487 LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, int, NETCONN_UDP); 3488#if LWIP_UDPLITE 3489 if (udp_is_flag_set(sock->conn->pcb.udp, UDP_FLAGS_UDPLITE)) { 3490 /* this flag is only available for UDP, not for UDP lite */ 3491 done_socket(sock); 3492 return EAFNOSUPPORT; 3493 } 3494#endif /* LWIP_UDPLITE */ 3495 if (*(const int *)optval) { 3496 udp_set_flags(sock->conn->pcb.udp, UDP_FLAGS_NOCHKSUM); 3497 } else { 3498 udp_clear_flags(sock->conn->pcb.udp, UDP_FLAGS_NOCHKSUM); 3499 } 3500 break; 3501#endif /* LWIP_UDP */ 3502 case SO_BINDTODEVICE: { 3503 const struct ifreq *iface; 3504 struct netif *n = NULL; 3505 3506 LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, optlen, struct ifreq); 3507 3508 iface = (const struct ifreq *)optval; 3509 if (iface->ifr_name[0] != 0) { 3510 n = netif_find(iface->ifr_name); 3511 if (n == NULL) { 3512 done_socket(sock); 3513 return ENODEV; 3514 } 3515 } 3516 3517 switch (NETCONNTYPE_GROUP(netconn_type(sock->conn))) { 3518#if LWIP_TCP 3519 case NETCONN_TCP: 3520 tcp_bind_netif(sock->conn->pcb.tcp, n); 3521 break; 3522#endif 3523#if LWIP_UDP 3524 case NETCONN_UDP: 3525 udp_bind_netif(sock->conn->pcb.udp, n); 3526 break; 3527#endif 3528#if LWIP_RAW 3529 case NETCONN_RAW: 3530 raw_bind_netif(sock->conn->pcb.raw, n); 3531 break; 3532#endif 3533 default: 3534 LWIP_ASSERT("Unhandled netconn type in SO_BINDTODEVICE", 0); 3535 break; 3536 } 3537 } 3538 break; 3539 default: 3540 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, SOL_SOCKET, UNIMPL: optname=0x%x, ..)\n", 3541 s, optname)); 3542 err = ENOPROTOOPT; 3543 break; 3544 } /* switch (optname) */ 3545 break; 3546 3547 /* Level: IPPROTO_IP */ 3548 case IPPROTO_IP: 3549 switch (optname) { 3550 case IP_TTL: 3551 LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, optlen, int); 3552 sock->conn->pcb.ip->ttl = (u8_t)(*(const int *)optval); 3553 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IP, IP_TTL, ..) -> %d\n", 3554 s, sock->conn->pcb.ip->ttl)); 3555 break; 3556 case IP_TOS: 3557 LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, optlen, int); 3558 sock->conn->pcb.ip->tos = (u8_t)(*(const int *)optval); 3559 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IP, IP_TOS, ..)-> %d\n", 3560 s, sock->conn->pcb.ip->tos)); 3561 break; 3562#if LWIP_NETBUF_RECVINFO 3563 case IP_PKTINFO: 3564 LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, int, NETCONN_UDP); 3565 if (*(const int *)optval) { 3566 sock->conn->flags |= NETCONN_FLAG_PKTINFO; 3567 } else { 3568 sock->conn->flags &= ~NETCONN_FLAG_PKTINFO; 3569 } 3570 break; 3571#endif /* LWIP_NETBUF_RECVINFO */ 3572#if LWIP_IPV4 && LWIP_MULTICAST_TX_OPTIONS && LWIP_UDP 3573 case IP_MULTICAST_TTL: 3574 LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, u8_t, NETCONN_UDP); 3575 udp_set_multicast_ttl(sock->conn->pcb.udp, (u8_t)(*(const u8_t *)optval)); 3576 break; 3577 case IP_MULTICAST_IF: { 3578 ip4_addr_t if_addr; 3579 LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, struct in_addr, NETCONN_UDP); 3580 inet_addr_to_ip4addr(&if_addr, (const struct in_addr *)optval); 3581 udp_set_multicast_netif_addr(sock->conn->pcb.udp, &if_addr); 3582 } 3583 break; 3584 case IP_MULTICAST_LOOP: 3585 LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, u8_t, NETCONN_UDP); 3586 if (*(const u8_t *)optval) { 3587 udp_set_flags(sock->conn->pcb.udp, UDP_FLAGS_MULTICAST_LOOP); 3588 } else { 3589 udp_clear_flags(sock->conn->pcb.udp, UDP_FLAGS_MULTICAST_LOOP); 3590 } 3591 break; 3592#endif /* LWIP_IPV4 && LWIP_MULTICAST_TX_OPTIONS && LWIP_UDP */ 3593#if LWIP_IGMP 3594 case IP_ADD_MEMBERSHIP: 3595 case IP_DROP_MEMBERSHIP: { 3596 /* If this is a TCP or a RAW socket, ignore these options. */ 3597 err_t igmp_err; 3598 const struct ip_mreq *imr = (const struct ip_mreq *)optval; 3599 ip4_addr_t if_addr; 3600 ip4_addr_t multi_addr; 3601 LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, struct ip_mreq, NETCONN_UDP); 3602 inet_addr_to_ip4addr(&if_addr, &imr->imr_interface); 3603 inet_addr_to_ip4addr(&multi_addr, &imr->imr_multiaddr); 3604 if (optname == IP_ADD_MEMBERSHIP) { 3605 if (!lwip_socket_register_membership(s, &if_addr, &multi_addr)) { 3606 /* cannot track membership (out of memory) */ 3607 err = ENOMEM; 3608 igmp_err = ERR_OK; 3609 } else { 3610 igmp_err = igmp_joingroup(&if_addr, &multi_addr); 3611 } 3612 } else { 3613 igmp_err = igmp_leavegroup(&if_addr, &multi_addr); 3614 lwip_socket_unregister_membership(s, &if_addr, &multi_addr); 3615 } 3616 if (igmp_err != ERR_OK) { 3617 err = EADDRNOTAVAIL; 3618 } 3619 } 3620 break; 3621#endif /* LWIP_IGMP */ 3622 default: 3623 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IP, UNIMPL: optname=0x%x, ..)\n", 3624 s, optname)); 3625 err = ENOPROTOOPT; 3626 break; 3627 } /* switch (optname) */ 3628 break; 3629 3630#if LWIP_TCP 3631 /* Level: IPPROTO_TCP */ 3632 case IPPROTO_TCP: 3633 /* Special case: all IPPROTO_TCP option take an int */ 3634 LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, int, NETCONN_TCP); 3635 if (sock->conn->pcb.tcp->state == LISTEN) { 3636 done_socket(sock); 3637 return EINVAL; 3638 } 3639 switch (optname) { 3640 case TCP_NODELAY: 3641 if (*(const int *)optval) { 3642 tcp_nagle_disable(sock->conn->pcb.tcp); 3643 } else { 3644 tcp_nagle_enable(sock->conn->pcb.tcp); 3645 } 3646 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_NODELAY) -> %s\n", 3647 s, (*(const int *)optval) ? "on" : "off") ); 3648 break; 3649 case TCP_KEEPALIVE: 3650 sock->conn->pcb.tcp->keep_idle = (u32_t)(*(const int *)optval); 3651 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPALIVE) -> %"U32_F"\n", 3652 s, sock->conn->pcb.tcp->keep_idle)); 3653 break; 3654 3655#if LWIP_TCP_KEEPALIVE 3656 case TCP_KEEPIDLE: 3657 sock->conn->pcb.tcp->keep_idle = 1000 * (u32_t)(*(const int *)optval); 3658 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPIDLE) -> %"U32_F"\n", 3659 s, sock->conn->pcb.tcp->keep_idle)); 3660 break; 3661 case TCP_KEEPINTVL: 3662 sock->conn->pcb.tcp->keep_intvl = 1000 * (u32_t)(*(const int *)optval); 3663 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPINTVL) -> %"U32_F"\n", 3664 s, sock->conn->pcb.tcp->keep_intvl)); 3665 break; 3666 case TCP_KEEPCNT: 3667 sock->conn->pcb.tcp->keep_cnt = (u32_t)(*(const int *)optval); 3668 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPCNT) -> %"U32_F"\n", 3669 s, sock->conn->pcb.tcp->keep_cnt)); 3670 break; 3671#endif /* LWIP_TCP_KEEPALIVE */ 3672 default: 3673 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, UNIMPL: optname=0x%x, ..)\n", 3674 s, optname)); 3675 err = ENOPROTOOPT; 3676 break; 3677 } /* switch (optname) */ 3678 break; 3679#endif /* LWIP_TCP*/ 3680 3681#if LWIP_IPV6 3682 /* Level: IPPROTO_IPV6 */ 3683 case IPPROTO_IPV6: 3684 switch (optname) { 3685 case IPV6_V6ONLY: 3686 LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, optlen, int); 3687 if (*(const int *)optval) { 3688 netconn_set_ipv6only(sock->conn, 1); 3689 } else { 3690 netconn_set_ipv6only(sock->conn, 0); 3691 } 3692 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IPV6, IPV6_V6ONLY, ..) -> %d\n", 3693 s, (netconn_get_ipv6only(sock->conn) ? 1 : 0))); 3694 break; 3695#if LWIP_IPV6_MLD 3696 case IPV6_JOIN_GROUP: 3697 case IPV6_LEAVE_GROUP: { 3698 /* If this is a TCP or a RAW socket, ignore these options. */ 3699 err_t mld6_err; 3700 struct netif *netif; 3701 ip6_addr_t multi_addr; 3702 const struct ipv6_mreq *imr = (const struct ipv6_mreq *)optval; 3703 LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, struct ipv6_mreq, NETCONN_UDP); 3704 inet6_addr_to_ip6addr(&multi_addr, &imr->ipv6mr_multiaddr); 3705 LWIP_ASSERT("Invalid netif index", imr->ipv6mr_interface <= 0xFFu); 3706#ifdef LOSCFG_NET_CONTAINER 3707 netif = netif_get_by_index((u8_t)imr->ipv6mr_interface, get_net_group_from_ippcb(sock->conn->pcb.ip)); 3708#else 3709 netif = netif_get_by_index((u8_t)imr->ipv6mr_interface); 3710#endif 3711 if (netif == NULL) { 3712 err = EADDRNOTAVAIL; 3713 break; 3714 } 3715 3716 if (optname == IPV6_JOIN_GROUP) { 3717 if (!lwip_socket_register_mld6_membership(s, imr->ipv6mr_interface, &multi_addr)) { 3718 /* cannot track membership (out of memory) */ 3719 err = ENOMEM; 3720 mld6_err = ERR_OK; 3721 } else { 3722 mld6_err = mld6_joingroup_netif(netif, &multi_addr); 3723 } 3724 } else { 3725 mld6_err = mld6_leavegroup_netif(netif, &multi_addr); 3726 lwip_socket_unregister_mld6_membership(s, imr->ipv6mr_interface, &multi_addr); 3727 } 3728 if (mld6_err != ERR_OK) { 3729 err = EADDRNOTAVAIL; 3730 } 3731 } 3732 break; 3733#endif /* LWIP_IPV6_MLD */ 3734 default: 3735 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IPV6, UNIMPL: optname=0x%x, ..)\n", 3736 s, optname)); 3737 err = ENOPROTOOPT; 3738 break; 3739 } /* switch (optname) */ 3740 break; 3741#endif /* LWIP_IPV6 */ 3742 3743#if LWIP_UDP && LWIP_UDPLITE 3744 /* Level: IPPROTO_UDPLITE */ 3745 case IPPROTO_UDPLITE: 3746 /* Special case: all IPPROTO_UDPLITE option take an int */ 3747 LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, optlen, int); 3748 /* If this is no UDP lite socket, ignore any options. */ 3749 if (!NETCONNTYPE_ISUDPLITE(netconn_type(sock->conn))) { 3750 done_socket(sock); 3751 return ENOPROTOOPT; 3752 } 3753 switch (optname) { 3754 case UDPLITE_SEND_CSCOV: 3755 if ((*(const int *)optval != 0) && ((*(const int *)optval < 8) || (*(const int *)optval > 0xffff))) { 3756 /* don't allow illegal values! */ 3757 sock->conn->pcb.udp->chksum_len_tx = 8; 3758 } else { 3759 sock->conn->pcb.udp->chksum_len_tx = (u16_t) * (const int *)optval; 3760 } 3761 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_UDPLITE, UDPLITE_SEND_CSCOV) -> %d\n", 3762 s, (*(const int *)optval)) ); 3763 break; 3764 case UDPLITE_RECV_CSCOV: 3765 if ((*(const int *)optval != 0) && ((*(const int *)optval < 8) || (*(const int *)optval > 0xffff))) { 3766 /* don't allow illegal values! */ 3767 sock->conn->pcb.udp->chksum_len_rx = 8; 3768 } else { 3769 sock->conn->pcb.udp->chksum_len_rx = (u16_t) * (const int *)optval; 3770 } 3771 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_UDPLITE, UDPLITE_RECV_CSCOV) -> %d\n", 3772 s, (*(const int *)optval)) ); 3773 break; 3774 default: 3775 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_UDPLITE, UNIMPL: optname=0x%x, ..)\n", 3776 s, optname)); 3777 err = ENOPROTOOPT; 3778 break; 3779 } /* switch (optname) */ 3780 break; 3781#endif /* LWIP_UDP */ 3782 /* Level: IPPROTO_RAW */ 3783 case IPPROTO_RAW: 3784 switch (optname) { 3785#if LWIP_IPV6 && LWIP_RAW 3786 case IPV6_CHECKSUM: 3787 /* It should not be possible to disable the checksum generation with ICMPv6 3788 * as per RFC 3542 chapter 3.1 */ 3789 if (sock->conn->pcb.raw->protocol == IPPROTO_ICMPV6) { 3790 done_socket(sock); 3791 return EINVAL; 3792 } 3793 3794 LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, int, NETCONN_RAW); 3795 if (*(const int *)optval < 0) { 3796 sock->conn->pcb.raw->chksum_reqd = 0; 3797 } else if (*(const int *)optval & 1) { 3798 /* Per RFC3542, odd offsets are not allowed */ 3799 done_socket(sock); 3800 return EINVAL; 3801 } else { 3802 sock->conn->pcb.raw->chksum_reqd = 1; 3803 sock->conn->pcb.raw->chksum_offset = (u16_t) * (const int *)optval; 3804 } 3805 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_RAW, IPV6_CHECKSUM, ..) -> %d\n", 3806 s, sock->conn->pcb.raw->chksum_reqd)); 3807 break; 3808#endif /* LWIP_IPV6 && LWIP_RAW */ 3809 default: 3810 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_RAW, UNIMPL: optname=0x%x, ..)\n", 3811 s, optname)); 3812 err = ENOPROTOOPT; 3813 break; 3814 } /* switch (optname) */ 3815 break; 3816 default: 3817 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, level=0x%x, UNIMPL: optname=0x%x, ..)\n", 3818 s, level, optname)); 3819 err = ENOPROTOOPT; 3820 break; 3821 } /* switch (level) */ 3822 3823 done_socket(sock); 3824 return err; 3825} 3826 3827int 3828lwip_ioctl(int s, long cmd, void *argp) 3829{ 3830 struct lwip_sock *sock = get_socket(s); 3831 u8_t val; 3832#if LWIP_SO_RCVBUF 3833 int recv_avail; 3834#endif /* LWIP_SO_RCVBUF */ 3835 3836 if (!sock) { 3837 return -1; 3838 } 3839 3840 switch (cmd) { 3841#if LWIP_SO_RCVBUF || LWIP_FIONREAD_LINUXMODE 3842 case FIONREAD: 3843 if (!argp) { 3844 sock_set_errno(sock, EINVAL); 3845 done_socket(sock); 3846 return -1; 3847 } 3848#if LWIP_FIONREAD_LINUXMODE 3849 if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_TCP) { 3850 struct netbuf *nb; 3851 if (sock->lastdata.netbuf) { 3852 nb = sock->lastdata.netbuf; 3853 *((int *)argp) = nb->p->tot_len; 3854 } else { 3855 struct netbuf *rxbuf; 3856 err_t err = netconn_recv_udp_raw_netbuf_flags(sock->conn, &rxbuf, NETCONN_DONTBLOCK); 3857 if (err != ERR_OK) { 3858 *((int *)argp) = 0; 3859 } else { 3860 sock->lastdata.netbuf = rxbuf; 3861 *((int *)argp) = rxbuf->p->tot_len; 3862 } 3863 } 3864 done_socket(sock); 3865 return 0; 3866 } 3867#endif /* LWIP_FIONREAD_LINUXMODE */ 3868 3869#if LWIP_SO_RCVBUF 3870 /* we come here if either LWIP_FIONREAD_LINUXMODE==0 or this is a TCP socket */ 3871 SYS_ARCH_GET(sock->conn->recv_avail, recv_avail); 3872 if (recv_avail < 0) { 3873 recv_avail = 0; 3874 } 3875 3876 /* Check if there is data left from the last recv operation. /maq 041215 */ 3877 if (sock->lastdata.netbuf) { 3878 if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) { 3879 recv_avail += sock->lastdata.pbuf->tot_len; 3880 } else { 3881 recv_avail += sock->lastdata.netbuf->p->tot_len; 3882 } 3883 } 3884 *((int *)argp) = recv_avail; 3885 3886 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(%d, FIONREAD, %p) = %"U16_F"\n", s, argp, *((u16_t *)argp))); 3887 sock_set_errno(sock, 0); 3888 done_socket(sock); 3889 return 0; 3890#else /* LWIP_SO_RCVBUF */ 3891 break; 3892#endif /* LWIP_SO_RCVBUF */ 3893#endif /* LWIP_SO_RCVBUF || LWIP_FIONREAD_LINUXMODE */ 3894 3895 case (long)FIONBIO: 3896 val = 0; 3897 if (argp && *(int *)argp) { 3898 val = 1; 3899 } 3900 netconn_set_nonblocking(sock->conn, val); 3901 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(%d, FIONBIO, %d)\n", s, val)); 3902 sock_set_errno(sock, 0); 3903 done_socket(sock); 3904 return 0; 3905 3906 default: 3907 IOCTL_CMD_CASE_HANDLER(); 3908 break; 3909 } /* switch (cmd) */ 3910 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(%d, UNIMPL: 0x%lx, %p)\n", s, cmd, argp)); 3911 sock_set_errno(sock, ENOSYS); /* not yet implemented */ 3912 done_socket(sock); 3913 return -1; 3914} 3915 3916/** A minimal implementation of fcntl. 3917 * Currently only the commands F_GETFL and F_SETFL are implemented. 3918 * The flag O_NONBLOCK and access modes are supported for F_GETFL, only 3919 * the flag O_NONBLOCK is implemented for F_SETFL. 3920 */ 3921int 3922lwip_fcntl(int s, int cmd, int val) 3923{ 3924 struct lwip_sock *sock = get_socket(s); 3925 int ret = -1; 3926 int op_mode = 0; 3927 3928 if (!sock) { 3929 return -1; 3930 } 3931 3932 switch (cmd) { 3933 case F_GETFL: 3934 ret = netconn_is_nonblocking(sock->conn) ? O_NONBLOCK : 0; 3935 sock_set_errno(sock, 0); 3936 3937 if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) { 3938#if LWIP_TCPIP_CORE_LOCKING 3939 LOCK_TCPIP_CORE(); 3940#else 3941 SYS_ARCH_DECL_PROTECT(lev); 3942 /* the proper thing to do here would be to get into the tcpip_thread, 3943 but locking should be OK as well since we only *read* some flags */ 3944 SYS_ARCH_PROTECT(lev); 3945#endif 3946#if LWIP_TCP 3947 if (sock->conn->pcb.tcp) { 3948 if (!(sock->conn->pcb.tcp->flags & TF_RXCLOSED)) { 3949 op_mode |= O_RDONLY; 3950 } 3951 if (!(sock->conn->pcb.tcp->flags & TF_FIN)) { 3952 op_mode |= O_WRONLY; 3953 } 3954 } 3955#endif 3956#if LWIP_TCPIP_CORE_LOCKING 3957 UNLOCK_TCPIP_CORE(); 3958#else 3959 SYS_ARCH_UNPROTECT(lev); 3960#endif 3961 } else { 3962 op_mode |= O_RDWR; 3963 } 3964 3965 /* ensure O_RDWR for (O_RDONLY|O_WRONLY) != O_RDWR cases */ 3966 ret |= (op_mode == (O_RDONLY | O_WRONLY)) ? O_RDWR : op_mode; 3967 3968 break; 3969 case F_SETFL: 3970 /* Bits corresponding to the file access mode and the file creation flags [..] that are set in arg shall be ignored */ 3971 val &= ~(O_RDONLY | O_WRONLY | O_RDWR); 3972 if ((val & ~O_NONBLOCK) == 0) { 3973 /* only O_NONBLOCK, all other bits are zero */ 3974 netconn_set_nonblocking(sock->conn, val & O_NONBLOCK); 3975 ret = 0; 3976 sock_set_errno(sock, 0); 3977 } else { 3978 sock_set_errno(sock, ENOSYS); /* not yet implemented */ 3979 } 3980 break; 3981 default: 3982 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_fcntl(%d, UNIMPL: %d, %d)\n", s, cmd, val)); 3983 sock_set_errno(sock, ENOSYS); /* not yet implemented */ 3984 break; 3985 } 3986 done_socket(sock); 3987 return ret; 3988} 3989 3990#if LWIP_COMPAT_SOCKETS == 2 && LWIP_POSIX_SOCKETS_IO_NAMES 3991int 3992fcntl(int s, int cmd, ...) 3993{ 3994 va_list ap; 3995 int val; 3996 3997 va_start(ap, cmd); 3998 val = va_arg(ap, int); 3999 va_end(ap); 4000 return lwip_fcntl(s, cmd, val); 4001} 4002#endif 4003 4004const char * 4005lwip_inet_ntop(int af, const void *src, char *dst, socklen_t size) 4006{ 4007 const char *ret = NULL; 4008 int size_int = (int)size; 4009 if (size_int < 0) { 4010 set_errno(ENOSPC); 4011 return NULL; 4012 } 4013 switch (af) { 4014#if LWIP_IPV4 4015 case AF_INET: 4016 ret = ip4addr_ntoa_r((const ip4_addr_t *)src, dst, size_int); 4017 if (ret == NULL) { 4018 set_errno(ENOSPC); 4019 } 4020 break; 4021#endif 4022#if LWIP_IPV6 4023 case AF_INET6: 4024 ret = ip6addr_ntoa_r((const ip6_addr_t *)src, dst, size_int); 4025 if (ret == NULL) { 4026 set_errno(ENOSPC); 4027 } 4028 break; 4029#endif 4030 default: 4031 set_errno(EAFNOSUPPORT); 4032 break; 4033 } 4034 return ret; 4035} 4036 4037int 4038lwip_inet_pton(int af, const char *src, void *dst) 4039{ 4040 int err; 4041 switch (af) { 4042#if LWIP_IPV4 4043 case AF_INET: 4044 err = ip4addr_aton(src, (ip4_addr_t *)dst); 4045 break; 4046#endif 4047#if LWIP_IPV6 4048 case AF_INET6: { 4049 /* convert into temporary variable since ip6_addr_t might be larger 4050 than in6_addr when scopes are enabled */ 4051 ip6_addr_t addr; 4052 err = ip6addr_aton(src, &addr); 4053 if (err) { 4054 memcpy(dst, &addr.addr, sizeof(addr.addr)); 4055 } 4056 break; 4057 } 4058#endif 4059 default: 4060 err = -1; 4061 set_errno(EAFNOSUPPORT); 4062 break; 4063 } 4064 return err; 4065} 4066 4067#if LWIP_IGMP 4068/** Register a new IGMP membership. On socket close, the membership is dropped automatically. 4069 * 4070 * ATTENTION: this function is called from tcpip_thread (or under CORE_LOCK). 4071 * 4072 * @return 1 on success, 0 on failure 4073 */ 4074static int 4075lwip_socket_register_membership(int s, const ip4_addr_t *if_addr, const ip4_addr_t *multi_addr) 4076{ 4077 struct lwip_sock *sock = get_socket(s); 4078 int i; 4079 4080 if (!sock) { 4081 return 0; 4082 } 4083 4084 for (i = 0; i < LWIP_SOCKET_MAX_MEMBERSHIPS; i++) { 4085 if (socket_ipv4_multicast_memberships[i].sock == NULL) { 4086 socket_ipv4_multicast_memberships[i].sock = sock; 4087 ip4_addr_copy(socket_ipv4_multicast_memberships[i].if_addr, *if_addr); 4088 ip4_addr_copy(socket_ipv4_multicast_memberships[i].multi_addr, *multi_addr); 4089 done_socket(sock); 4090 return 1; 4091 } 4092 } 4093 done_socket(sock); 4094 return 0; 4095} 4096 4097/** Unregister a previously registered membership. This prevents dropping the membership 4098 * on socket close. 4099 * 4100 * ATTENTION: this function is called from tcpip_thread (or under CORE_LOCK). 4101 */ 4102static void 4103lwip_socket_unregister_membership(int s, const ip4_addr_t *if_addr, const ip4_addr_t *multi_addr) 4104{ 4105 struct lwip_sock *sock = get_socket(s); 4106 int i; 4107 4108 if (!sock) { 4109 return; 4110 } 4111 4112 for (i = 0; i < LWIP_SOCKET_MAX_MEMBERSHIPS; i++) { 4113 if ((socket_ipv4_multicast_memberships[i].sock == sock) && 4114 ip4_addr_cmp(&socket_ipv4_multicast_memberships[i].if_addr, if_addr) && 4115 ip4_addr_cmp(&socket_ipv4_multicast_memberships[i].multi_addr, multi_addr)) { 4116 socket_ipv4_multicast_memberships[i].sock = NULL; 4117 ip4_addr_set_zero(&socket_ipv4_multicast_memberships[i].if_addr); 4118 ip4_addr_set_zero(&socket_ipv4_multicast_memberships[i].multi_addr); 4119 break; 4120 } 4121 } 4122 done_socket(sock); 4123} 4124 4125/** Drop all memberships of a socket that were not dropped explicitly via setsockopt. 4126 * 4127 * ATTENTION: this function is NOT called from tcpip_thread (or under CORE_LOCK). 4128 */ 4129static void 4130lwip_socket_drop_registered_memberships(int s) 4131{ 4132 struct lwip_sock *sock = get_socket(s); 4133 int i; 4134 4135 if (!sock) { 4136 return; 4137 } 4138 4139 for (i = 0; i < LWIP_SOCKET_MAX_MEMBERSHIPS; i++) { 4140 if (socket_ipv4_multicast_memberships[i].sock == sock) { 4141 ip_addr_t multi_addr, if_addr; 4142 ip_addr_copy_from_ip4(multi_addr, socket_ipv4_multicast_memberships[i].multi_addr); 4143 ip_addr_copy_from_ip4(if_addr, socket_ipv4_multicast_memberships[i].if_addr); 4144 socket_ipv4_multicast_memberships[i].sock = NULL; 4145 ip4_addr_set_zero(&socket_ipv4_multicast_memberships[i].if_addr); 4146 ip4_addr_set_zero(&socket_ipv4_multicast_memberships[i].multi_addr); 4147 4148 netconn_join_leave_group(sock->conn, &multi_addr, &if_addr, NETCONN_LEAVE); 4149 } 4150 } 4151 done_socket(sock); 4152} 4153#endif /* LWIP_IGMP */ 4154 4155#if LWIP_IPV6_MLD 4156/** Register a new MLD6 membership. On socket close, the membership is dropped automatically. 4157 * 4158 * ATTENTION: this function is called from tcpip_thread (or under CORE_LOCK). 4159 * 4160 * @return 1 on success, 0 on failure 4161 */ 4162static int 4163lwip_socket_register_mld6_membership(int s, unsigned int if_idx, const ip6_addr_t *multi_addr) 4164{ 4165 struct lwip_sock *sock = get_socket(s); 4166 int i; 4167 4168 if (!sock) { 4169 return 0; 4170 } 4171 4172 for (i = 0; i < LWIP_SOCKET_MAX_MEMBERSHIPS; i++) { 4173 if (socket_ipv6_multicast_memberships[i].sock == NULL) { 4174 socket_ipv6_multicast_memberships[i].sock = sock; 4175 socket_ipv6_multicast_memberships[i].if_idx = (u8_t)if_idx; 4176 ip6_addr_copy(socket_ipv6_multicast_memberships[i].multi_addr, *multi_addr); 4177 done_socket(sock); 4178 return 1; 4179 } 4180 } 4181 done_socket(sock); 4182 return 0; 4183} 4184 4185/** Unregister a previously registered MLD6 membership. This prevents dropping the membership 4186 * on socket close. 4187 * 4188 * ATTENTION: this function is called from tcpip_thread (or under CORE_LOCK). 4189 */ 4190static void 4191lwip_socket_unregister_mld6_membership(int s, unsigned int if_idx, const ip6_addr_t *multi_addr) 4192{ 4193 struct lwip_sock *sock = get_socket(s); 4194 int i; 4195 4196 if (!sock) { 4197 return; 4198 } 4199 4200 for (i = 0; i < LWIP_SOCKET_MAX_MEMBERSHIPS; i++) { 4201 if ((socket_ipv6_multicast_memberships[i].sock == sock) && 4202 (socket_ipv6_multicast_memberships[i].if_idx == if_idx) && 4203 ip6_addr_cmp(&socket_ipv6_multicast_memberships[i].multi_addr, multi_addr)) { 4204 socket_ipv6_multicast_memberships[i].sock = NULL; 4205 socket_ipv6_multicast_memberships[i].if_idx = NETIF_NO_INDEX; 4206 ip6_addr_set_zero(&socket_ipv6_multicast_memberships[i].multi_addr); 4207 break; 4208 } 4209 } 4210 done_socket(sock); 4211} 4212 4213/** Drop all MLD6 memberships of a socket that were not dropped explicitly via setsockopt. 4214 * 4215 * ATTENTION: this function is NOT called from tcpip_thread (or under CORE_LOCK). 4216 */ 4217static void 4218lwip_socket_drop_registered_mld6_memberships(int s) 4219{ 4220 struct lwip_sock *sock = get_socket(s); 4221 int i; 4222 4223 if (!sock) { 4224 return; 4225 } 4226 4227 for (i = 0; i < LWIP_SOCKET_MAX_MEMBERSHIPS; i++) { 4228 if (socket_ipv6_multicast_memberships[i].sock == sock) { 4229 ip_addr_t multi_addr; 4230 u8_t if_idx; 4231 4232 ip_addr_copy_from_ip6(multi_addr, socket_ipv6_multicast_memberships[i].multi_addr); 4233 if_idx = socket_ipv6_multicast_memberships[i].if_idx; 4234 4235 socket_ipv6_multicast_memberships[i].sock = NULL; 4236 socket_ipv6_multicast_memberships[i].if_idx = NETIF_NO_INDEX; 4237 ip6_addr_set_zero(&socket_ipv6_multicast_memberships[i].multi_addr); 4238 4239 netconn_join_leave_group_netif(sock->conn, &multi_addr, if_idx, NETCONN_LEAVE); 4240 } 4241 } 4242 done_socket(sock); 4243} 4244#endif /* LWIP_IPV6_MLD */ 4245 4246#endif /* LWIP_SOCKET */ 4247