1195972f6Sopenharmony_ci/** 2195972f6Sopenharmony_ci * @file 3195972f6Sopenharmony_ci * Sockets BSD-Like API module 4195972f6Sopenharmony_ci */ 5195972f6Sopenharmony_ci 6195972f6Sopenharmony_ci/* 7195972f6Sopenharmony_ci * Copyright (c) 2001-2004 Swedish Institute of Computer Science. 8195972f6Sopenharmony_ci * All rights reserved. 9195972f6Sopenharmony_ci * 10195972f6Sopenharmony_ci * Redistribution and use in source and binary forms, with or without modification, 11195972f6Sopenharmony_ci * are permitted provided that the following conditions are met: 12195972f6Sopenharmony_ci * 13195972f6Sopenharmony_ci * 1. Redistributions of source code must retain the above copyright notice, 14195972f6Sopenharmony_ci * this list of conditions and the following disclaimer. 15195972f6Sopenharmony_ci * 2. Redistributions in binary form must reproduce the above copyright notice, 16195972f6Sopenharmony_ci * this list of conditions and the following disclaimer in the documentation 17195972f6Sopenharmony_ci * and/or other materials provided with the distribution. 18195972f6Sopenharmony_ci * 3. The name of the author may not be used to endorse or promote products 19195972f6Sopenharmony_ci * derived from this software without specific prior written permission. 20195972f6Sopenharmony_ci * 21195972f6Sopenharmony_ci * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 22195972f6Sopenharmony_ci * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 23195972f6Sopenharmony_ci * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 24195972f6Sopenharmony_ci * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 25195972f6Sopenharmony_ci * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 26195972f6Sopenharmony_ci * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27195972f6Sopenharmony_ci * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28195972f6Sopenharmony_ci * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 29195972f6Sopenharmony_ci * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 30195972f6Sopenharmony_ci * OF SUCH DAMAGE. 31195972f6Sopenharmony_ci * 32195972f6Sopenharmony_ci * This file is part of the lwIP TCP/IP stack. 33195972f6Sopenharmony_ci * 34195972f6Sopenharmony_ci * Author: Adam Dunkels <adam@sics.se> 35195972f6Sopenharmony_ci * 36195972f6Sopenharmony_ci * Improved by Marc Boucher <marc@mbsi.ca> and David Haas <dhaas@alum.rpi.edu> 37195972f6Sopenharmony_ci * 38195972f6Sopenharmony_ci */ 39195972f6Sopenharmony_ci 40195972f6Sopenharmony_ci#include "lwip/opt.h" 41195972f6Sopenharmony_ci 42195972f6Sopenharmony_ci#if LWIP_SOCKET /* don't build if not configured for use in lwipopts.h */ 43195972f6Sopenharmony_ci 44195972f6Sopenharmony_ci#include "lwip/sockets.h" 45195972f6Sopenharmony_ci#include "lwip/priv/sockets_priv.h" 46195972f6Sopenharmony_ci#include "lwip/api.h" 47195972f6Sopenharmony_ci#include "lwip/igmp.h" 48195972f6Sopenharmony_ci#include "lwip/inet.h" 49195972f6Sopenharmony_ci#include "lwip/tcp.h" 50195972f6Sopenharmony_ci#include "lwip/raw.h" 51195972f6Sopenharmony_ci#include "lwip/udp.h" 52195972f6Sopenharmony_ci#include "lwip/memp.h" 53195972f6Sopenharmony_ci#include "lwip/pbuf.h" 54195972f6Sopenharmony_ci#include "lwip/netif.h" 55195972f6Sopenharmony_ci#include "lwip/priv/tcpip_priv.h" 56195972f6Sopenharmony_ci#include "lwip/mld6.h" 57195972f6Sopenharmony_ci#if LWIP_ENABLE_DISTRIBUTED_NET 58195972f6Sopenharmony_ci#include "lwip/distributed_net/distributed_net.h" 59195972f6Sopenharmony_ci#include "lwip/distributed_net/distributed_net_core.h" 60195972f6Sopenharmony_ci#endif /* LWIP_ENABLE_DISTRIBUTED_NET */ 61195972f6Sopenharmony_ci#if LWIP_CHECKSUM_ON_COPY 62195972f6Sopenharmony_ci#include "lwip/inet_chksum.h" 63195972f6Sopenharmony_ci#endif 64195972f6Sopenharmony_ci 65195972f6Sopenharmony_ci#if LWIP_COMPAT_SOCKETS == 2 && LWIP_POSIX_SOCKETS_IO_NAMES 66195972f6Sopenharmony_ci#include <stdarg.h> 67195972f6Sopenharmony_ci#endif 68195972f6Sopenharmony_ci 69195972f6Sopenharmony_ci#include <string.h> 70195972f6Sopenharmony_ci 71195972f6Sopenharmony_ci#ifdef LWIP_HOOK_FILENAME 72195972f6Sopenharmony_ci#include LWIP_HOOK_FILENAME 73195972f6Sopenharmony_ci#endif 74195972f6Sopenharmony_ci 75195972f6Sopenharmony_ci#if LWIP_LOWPOWER 76195972f6Sopenharmony_ci#include "lwip/lowpower.h" 77195972f6Sopenharmony_ci#endif 78195972f6Sopenharmony_ci 79195972f6Sopenharmony_ci/* If the netconn API is not required publicly, then we include the necessary 80195972f6Sopenharmony_ci files here to get the implementation */ 81195972f6Sopenharmony_ci#if !LWIP_NETCONN 82195972f6Sopenharmony_ci#undef LWIP_NETCONN 83195972f6Sopenharmony_ci#define LWIP_NETCONN 1 84195972f6Sopenharmony_ci#include "api_msg.c" 85195972f6Sopenharmony_ci#include "api_lib.c" 86195972f6Sopenharmony_ci#include "netbuf.c" 87195972f6Sopenharmony_ci#undef LWIP_NETCONN 88195972f6Sopenharmony_ci#define LWIP_NETCONN 0 89195972f6Sopenharmony_ci#endif 90195972f6Sopenharmony_ci 91195972f6Sopenharmony_ci#define API_SELECT_CB_VAR_REF(name) API_VAR_REF(name) 92195972f6Sopenharmony_ci#define API_SELECT_CB_VAR_DECLARE(name) API_VAR_DECLARE(struct lwip_select_cb, name) 93195972f6Sopenharmony_ci#define API_SELECT_CB_VAR_ALLOC(name, retblock) API_VAR_ALLOC_EXT(struct lwip_select_cb, MEMP_SELECT_CB, name, retblock) 94195972f6Sopenharmony_ci#define API_SELECT_CB_VAR_FREE(name) API_VAR_FREE(MEMP_SELECT_CB, name) 95195972f6Sopenharmony_ci 96195972f6Sopenharmony_ci#if LWIP_IPV4 97195972f6Sopenharmony_ci#define IP4ADDR_PORT_TO_SOCKADDR(sin, ipaddr, port) do { \ 98195972f6Sopenharmony_ci (sin)->sin_len = sizeof(struct sockaddr_in); \ 99195972f6Sopenharmony_ci (sin)->sin_family = AF_INET; \ 100195972f6Sopenharmony_ci (sin)->sin_port = lwip_htons((port)); \ 101195972f6Sopenharmony_ci inet_addr_from_ip4addr(&(sin)->sin_addr, ipaddr); \ 102195972f6Sopenharmony_ci memset((sin)->sin_zero, 0, SIN_ZERO_LEN); }while(0) 103195972f6Sopenharmony_ci#define SOCKADDR4_TO_IP4ADDR_PORT(sin, ipaddr, port) do { \ 104195972f6Sopenharmony_ci inet_addr_to_ip4addr(ip_2_ip4(ipaddr), &((sin)->sin_addr)); \ 105195972f6Sopenharmony_ci (port) = lwip_ntohs((sin)->sin_port); }while(0) 106195972f6Sopenharmony_ci#endif /* LWIP_IPV4 */ 107195972f6Sopenharmony_ci 108195972f6Sopenharmony_ci#if LWIP_IPV6 109195972f6Sopenharmony_ci#define IP6ADDR_PORT_TO_SOCKADDR(sin6, ipaddr, port) do { \ 110195972f6Sopenharmony_ci (sin6)->sin6_len = sizeof(struct sockaddr_in6); \ 111195972f6Sopenharmony_ci (sin6)->sin6_family = AF_INET6; \ 112195972f6Sopenharmony_ci (sin6)->sin6_port = lwip_htons((port)); \ 113195972f6Sopenharmony_ci (sin6)->sin6_flowinfo = 0; \ 114195972f6Sopenharmony_ci inet6_addr_from_ip6addr(&(sin6)->sin6_addr, ipaddr); \ 115195972f6Sopenharmony_ci (sin6)->sin6_scope_id = ip6_addr_zone(ipaddr); }while(0) 116195972f6Sopenharmony_ci#define SOCKADDR6_TO_IP6ADDR_PORT(sin6, ipaddr, port) do { \ 117195972f6Sopenharmony_ci inet6_addr_to_ip6addr(ip_2_ip6(ipaddr), &((sin6)->sin6_addr)); \ 118195972f6Sopenharmony_ci if (ip6_addr_has_scope(ip_2_ip6(ipaddr), IP6_UNKNOWN)) { \ 119195972f6Sopenharmony_ci ip6_addr_set_zone(ip_2_ip6(ipaddr), (u8_t)((sin6)->sin6_scope_id)); \ 120195972f6Sopenharmony_ci } \ 121195972f6Sopenharmony_ci (port) = lwip_ntohs((sin6)->sin6_port); }while(0) 122195972f6Sopenharmony_ci#endif /* LWIP_IPV6 */ 123195972f6Sopenharmony_ci 124195972f6Sopenharmony_ci#if LWIP_IPV4 && LWIP_IPV6 125195972f6Sopenharmony_cistatic void sockaddr_to_ipaddr_port(const struct sockaddr *sockaddr, ip_addr_t *ipaddr, u16_t *port); 126195972f6Sopenharmony_ci 127195972f6Sopenharmony_ci#define IS_SOCK_ADDR_LEN_VALID(namelen) (((namelen) == sizeof(struct sockaddr_in)) || \ 128195972f6Sopenharmony_ci ((namelen) == sizeof(struct sockaddr_in6))) 129195972f6Sopenharmony_ci#define IS_SOCK_ADDR_TYPE_VALID(name) (((name)->sa_family == AF_INET) || \ 130195972f6Sopenharmony_ci ((name)->sa_family == AF_INET6)) 131195972f6Sopenharmony_ci#define SOCK_ADDR_TYPE_MATCH(name, sock) \ 132195972f6Sopenharmony_ci ((((name)->sa_family == AF_INET) && !(NETCONNTYPE_ISIPV6((sock)->conn->type))) || \ 133195972f6Sopenharmony_ci (((name)->sa_family == AF_INET6) && (NETCONNTYPE_ISIPV6((sock)->conn->type)))) 134195972f6Sopenharmony_ci#define IPADDR_PORT_TO_SOCKADDR(sockaddr, ipaddr, port) do { \ 135195972f6Sopenharmony_ci if (IP_IS_ANY_TYPE_VAL(*ipaddr) || IP_IS_V6_VAL(*ipaddr)) { \ 136195972f6Sopenharmony_ci IP6ADDR_PORT_TO_SOCKADDR((struct sockaddr_in6*)(void*)(sockaddr), ip_2_ip6(ipaddr), port); \ 137195972f6Sopenharmony_ci } else { \ 138195972f6Sopenharmony_ci IP4ADDR_PORT_TO_SOCKADDR((struct sockaddr_in*)(void*)(sockaddr), ip_2_ip4(ipaddr), port); \ 139195972f6Sopenharmony_ci } } while(0) 140195972f6Sopenharmony_ci#define SOCKADDR_TO_IPADDR_PORT(sockaddr, ipaddr, port) sockaddr_to_ipaddr_port(sockaddr, ipaddr, &(port)) 141195972f6Sopenharmony_ci#define DOMAIN_TO_NETCONN_TYPE(domain, type) (((domain) == AF_INET) ? \ 142195972f6Sopenharmony_ci (type) : (enum netconn_type)((type) | NETCONN_TYPE_IPV6)) 143195972f6Sopenharmony_ci#elif LWIP_IPV6 /* LWIP_IPV4 && LWIP_IPV6 */ 144195972f6Sopenharmony_ci#define IS_SOCK_ADDR_LEN_VALID(namelen) ((namelen) == sizeof(struct sockaddr_in6)) 145195972f6Sopenharmony_ci#define IS_SOCK_ADDR_TYPE_VALID(name) ((name)->sa_family == AF_INET6) 146195972f6Sopenharmony_ci#define SOCK_ADDR_TYPE_MATCH(name, sock) 1 147195972f6Sopenharmony_ci#define IPADDR_PORT_TO_SOCKADDR(sockaddr, ipaddr, port) \ 148195972f6Sopenharmony_ci IP6ADDR_PORT_TO_SOCKADDR((struct sockaddr_in6*)(void*)(sockaddr), ip_2_ip6(ipaddr), port) 149195972f6Sopenharmony_ci#define SOCKADDR_TO_IPADDR_PORT(sockaddr, ipaddr, port) \ 150195972f6Sopenharmony_ci SOCKADDR6_TO_IP6ADDR_PORT((const struct sockaddr_in6*)(const void*)(sockaddr), ipaddr, port) 151195972f6Sopenharmony_ci#define DOMAIN_TO_NETCONN_TYPE(domain, netconn_type) (netconn_type) 152195972f6Sopenharmony_ci#else /*-> LWIP_IPV4: LWIP_IPV4 && LWIP_IPV6 */ 153195972f6Sopenharmony_ci#define IS_SOCK_ADDR_LEN_VALID(namelen) ((namelen) == sizeof(struct sockaddr_in)) 154195972f6Sopenharmony_ci#define IS_SOCK_ADDR_TYPE_VALID(name) ((name)->sa_family == AF_INET) 155195972f6Sopenharmony_ci#define SOCK_ADDR_TYPE_MATCH(name, sock) 1 156195972f6Sopenharmony_ci#define IPADDR_PORT_TO_SOCKADDR(sockaddr, ipaddr, port) \ 157195972f6Sopenharmony_ci IP4ADDR_PORT_TO_SOCKADDR((struct sockaddr_in*)(void*)(sockaddr), ip_2_ip4(ipaddr), port) 158195972f6Sopenharmony_ci#define SOCKADDR_TO_IPADDR_PORT(sockaddr, ipaddr, port) \ 159195972f6Sopenharmony_ci SOCKADDR4_TO_IP4ADDR_PORT((const struct sockaddr_in*)(const void*)(sockaddr), ipaddr, port) 160195972f6Sopenharmony_ci#define DOMAIN_TO_NETCONN_TYPE(domain, netconn_type) (netconn_type) 161195972f6Sopenharmony_ci#endif /* LWIP_IPV6 */ 162195972f6Sopenharmony_ci 163195972f6Sopenharmony_ci#define IS_SOCK_ADDR_TYPE_VALID_OR_UNSPEC(name) (((name)->sa_family == AF_UNSPEC) || \ 164195972f6Sopenharmony_ci IS_SOCK_ADDR_TYPE_VALID(name)) 165195972f6Sopenharmony_ci#define SOCK_ADDR_TYPE_MATCH_OR_UNSPEC(name, sock) (((name)->sa_family == AF_UNSPEC) || \ 166195972f6Sopenharmony_ci SOCK_ADDR_TYPE_MATCH(name, sock)) 167195972f6Sopenharmony_ci#define IS_SOCK_ADDR_ALIGNED(name) ((((mem_ptr_t)(name)) % 4) == 0) 168195972f6Sopenharmony_ci 169195972f6Sopenharmony_ci 170195972f6Sopenharmony_ci#define LWIP_SOCKOPT_CHECK_OPTLEN(sock, optlen, opttype) do { if ((optlen) < sizeof(opttype)) { done_socket(sock); return EINVAL; }}while(0) 171195972f6Sopenharmony_ci#define LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, optlen, opttype) do { \ 172195972f6Sopenharmony_ci LWIP_SOCKOPT_CHECK_OPTLEN(sock, optlen, opttype); \ 173195972f6Sopenharmony_ci if ((sock)->conn == NULL) { done_socket(sock); return EINVAL; } }while(0) 174195972f6Sopenharmony_ci#define LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, optlen, opttype) do { \ 175195972f6Sopenharmony_ci LWIP_SOCKOPT_CHECK_OPTLEN(sock, optlen, opttype); \ 176195972f6Sopenharmony_ci if (((sock)->conn == NULL) || ((sock)->conn->pcb.tcp == NULL)) { done_socket(sock); return EINVAL; } }while(0) 177195972f6Sopenharmony_ci#define LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, opttype, netconntype) do { \ 178195972f6Sopenharmony_ci LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, optlen, opttype); \ 179195972f6Sopenharmony_ci if (NETCONNTYPE_GROUP(netconn_type((sock)->conn)) != netconntype) { done_socket(sock); return ENOPROTOOPT; } }while(0) 180195972f6Sopenharmony_ci 181195972f6Sopenharmony_ci 182195972f6Sopenharmony_ci#define LWIP_SETGETSOCKOPT_DATA_VAR_REF(name) API_VAR_REF(name) 183195972f6Sopenharmony_ci#define LWIP_SETGETSOCKOPT_DATA_VAR_DECLARE(name) API_VAR_DECLARE(struct lwip_setgetsockopt_data, name) 184195972f6Sopenharmony_ci#define LWIP_SETGETSOCKOPT_DATA_VAR_FREE(name) API_VAR_FREE(MEMP_SOCKET_SETGETSOCKOPT_DATA, name) 185195972f6Sopenharmony_ci#if LWIP_MPU_COMPATIBLE 186195972f6Sopenharmony_ci#define LWIP_SETGETSOCKOPT_DATA_VAR_ALLOC(name, sock) do { \ 187195972f6Sopenharmony_ci name = (struct lwip_setgetsockopt_data *)memp_malloc(MEMP_SOCKET_SETGETSOCKOPT_DATA); \ 188195972f6Sopenharmony_ci if (name == NULL) { \ 189195972f6Sopenharmony_ci sock_set_errno(sock, ENOMEM); \ 190195972f6Sopenharmony_ci done_socket(sock); \ 191195972f6Sopenharmony_ci return -1; \ 192195972f6Sopenharmony_ci } }while(0) 193195972f6Sopenharmony_ci#else /* LWIP_MPU_COMPATIBLE */ 194195972f6Sopenharmony_ci#define LWIP_SETGETSOCKOPT_DATA_VAR_ALLOC(name, sock) 195195972f6Sopenharmony_ci#endif /* LWIP_MPU_COMPATIBLE */ 196195972f6Sopenharmony_ci 197195972f6Sopenharmony_ci#if LWIP_SO_SNDRCVTIMEO_NONSTANDARD 198195972f6Sopenharmony_ci#define LWIP_SO_SNDRCVTIMEO_OPTTYPE int 199195972f6Sopenharmony_ci#define LWIP_SO_SNDRCVTIMEO_SET(optval, val) (*(int *)(optval) = (val)) 200195972f6Sopenharmony_ci#define LWIP_SO_SNDRCVTIMEO_GET_MS(optval) ((long)*(const int*)(optval)) 201195972f6Sopenharmony_ci#else 202195972f6Sopenharmony_ci#define LWIP_SO_SNDRCVTIMEO_OPTTYPE struct timeval 203195972f6Sopenharmony_ci#define LWIP_SO_SNDRCVTIMEO_SET(optval, val) do { \ 204195972f6Sopenharmony_ci u32_t loc = (val); \ 205195972f6Sopenharmony_ci ((struct timeval *)(optval))->tv_sec = (long)((loc) / 1000U); \ 206195972f6Sopenharmony_ci ((struct timeval *)(optval))->tv_usec = (long)(((loc) % 1000U) * 1000U); }while(0) 207195972f6Sopenharmony_ci#define LWIP_SO_SNDRCVTIMEO_GET_MS(optval) ((((const struct timeval *)(optval))->tv_sec * 1000) + (((const struct timeval *)(optval))->tv_usec / 1000)) 208195972f6Sopenharmony_ci#endif 209195972f6Sopenharmony_ci 210195972f6Sopenharmony_ci 211195972f6Sopenharmony_ci/** A struct sockaddr replacement that has the same alignment as sockaddr_in/ 212195972f6Sopenharmony_ci * sockaddr_in6 if instantiated. 213195972f6Sopenharmony_ci */ 214195972f6Sopenharmony_ciunion sockaddr_aligned { 215195972f6Sopenharmony_ci struct sockaddr sa; 216195972f6Sopenharmony_ci#if LWIP_IPV6 217195972f6Sopenharmony_ci struct sockaddr_in6 sin6; 218195972f6Sopenharmony_ci#endif /* LWIP_IPV6 */ 219195972f6Sopenharmony_ci#if LWIP_IPV4 220195972f6Sopenharmony_ci struct sockaddr_in sin; 221195972f6Sopenharmony_ci#endif /* LWIP_IPV4 */ 222195972f6Sopenharmony_ci}; 223195972f6Sopenharmony_ci 224195972f6Sopenharmony_ci/* Define the number of IPv4 multicast memberships, default is one per socket */ 225195972f6Sopenharmony_ci#ifndef LWIP_SOCKET_MAX_MEMBERSHIPS 226195972f6Sopenharmony_ci#define LWIP_SOCKET_MAX_MEMBERSHIPS NUM_SOCKETS 227195972f6Sopenharmony_ci#endif 228195972f6Sopenharmony_ci 229195972f6Sopenharmony_ci#if LWIP_IGMP 230195972f6Sopenharmony_ci/* This is to keep track of IP_ADD_MEMBERSHIP calls to drop the membership when 231195972f6Sopenharmony_ci a socket is closed */ 232195972f6Sopenharmony_cistruct lwip_socket_multicast_pair { 233195972f6Sopenharmony_ci /** the socket */ 234195972f6Sopenharmony_ci struct lwip_sock *sock; 235195972f6Sopenharmony_ci /** the interface address */ 236195972f6Sopenharmony_ci ip4_addr_t if_addr; 237195972f6Sopenharmony_ci /** the group address */ 238195972f6Sopenharmony_ci ip4_addr_t multi_addr; 239195972f6Sopenharmony_ci}; 240195972f6Sopenharmony_ci 241195972f6Sopenharmony_cistatic struct lwip_socket_multicast_pair socket_ipv4_multicast_memberships[LWIP_SOCKET_MAX_MEMBERSHIPS]; 242195972f6Sopenharmony_ci 243195972f6Sopenharmony_cistatic int lwip_socket_register_membership(int s, const ip4_addr_t *if_addr, const ip4_addr_t *multi_addr); 244195972f6Sopenharmony_cistatic void lwip_socket_unregister_membership(int s, const ip4_addr_t *if_addr, const ip4_addr_t *multi_addr); 245195972f6Sopenharmony_cistatic void lwip_socket_drop_registered_memberships(int s); 246195972f6Sopenharmony_ci#endif /* LWIP_IGMP */ 247195972f6Sopenharmony_ci 248195972f6Sopenharmony_ci#if LWIP_IPV6_MLD 249195972f6Sopenharmony_ci/* This is to keep track of IP_JOIN_GROUP calls to drop the membership when 250195972f6Sopenharmony_ci a socket is closed */ 251195972f6Sopenharmony_cistruct lwip_socket_multicast_mld6_pair { 252195972f6Sopenharmony_ci /** the socket */ 253195972f6Sopenharmony_ci struct lwip_sock *sock; 254195972f6Sopenharmony_ci /** the interface index */ 255195972f6Sopenharmony_ci u8_t if_idx; 256195972f6Sopenharmony_ci /** the group address */ 257195972f6Sopenharmony_ci ip6_addr_t multi_addr; 258195972f6Sopenharmony_ci}; 259195972f6Sopenharmony_ci 260195972f6Sopenharmony_cistatic struct lwip_socket_multicast_mld6_pair socket_ipv6_multicast_memberships[LWIP_SOCKET_MAX_MEMBERSHIPS]; 261195972f6Sopenharmony_ci 262195972f6Sopenharmony_cistatic int lwip_socket_register_mld6_membership(int s, unsigned int if_idx, const ip6_addr_t *multi_addr); 263195972f6Sopenharmony_cistatic void lwip_socket_unregister_mld6_membership(int s, unsigned int if_idx, const ip6_addr_t *multi_addr); 264195972f6Sopenharmony_cistatic void lwip_socket_drop_registered_mld6_memberships(int s); 265195972f6Sopenharmony_ci#endif /* LWIP_IPV6_MLD */ 266195972f6Sopenharmony_ci 267195972f6Sopenharmony_ci/** The global array of available sockets */ 268195972f6Sopenharmony_cistatic struct lwip_sock sockets[NUM_SOCKETS]; 269195972f6Sopenharmony_ci 270195972f6Sopenharmony_ci#if LWIP_SOCKET_SELECT || LWIP_SOCKET_POLL 271195972f6Sopenharmony_ci#if LWIP_TCPIP_CORE_LOCKING 272195972f6Sopenharmony_ci/* protect the select_cb_list using core lock */ 273195972f6Sopenharmony_ci#define LWIP_SOCKET_SELECT_DECL_PROTECT(lev) 274195972f6Sopenharmony_ci#define LWIP_SOCKET_SELECT_PROTECT(lev) LOCK_TCPIP_CORE() 275195972f6Sopenharmony_ci#define LWIP_SOCKET_SELECT_UNPROTECT(lev) UNLOCK_TCPIP_CORE() 276195972f6Sopenharmony_ci#else /* LWIP_TCPIP_CORE_LOCKING */ 277195972f6Sopenharmony_ci/* protect the select_cb_list using SYS_LIGHTWEIGHT_PROT */ 278195972f6Sopenharmony_ci#define LWIP_SOCKET_SELECT_DECL_PROTECT(lev) SYS_ARCH_DECL_PROTECT(lev) 279195972f6Sopenharmony_ci#define LWIP_SOCKET_SELECT_PROTECT(lev) SYS_ARCH_PROTECT(lev) 280195972f6Sopenharmony_ci#define LWIP_SOCKET_SELECT_UNPROTECT(lev) SYS_ARCH_UNPROTECT(lev) 281195972f6Sopenharmony_ci/** This counter is increased from lwip_select when the list is changed 282195972f6Sopenharmony_ci and checked in select_check_waiters to see if it has changed. */ 283195972f6Sopenharmony_cistatic volatile int select_cb_ctr; 284195972f6Sopenharmony_ci#endif /* LWIP_TCPIP_CORE_LOCKING */ 285195972f6Sopenharmony_ci/** The global list of tasks waiting for select */ 286195972f6Sopenharmony_cistatic struct lwip_select_cb *select_cb_list; 287195972f6Sopenharmony_ci#endif /* LWIP_SOCKET_SELECT || LWIP_SOCKET_POLL */ 288195972f6Sopenharmony_ci 289195972f6Sopenharmony_ci#define sock_set_errno(sk, e) do { \ 290195972f6Sopenharmony_ci const int sockerr = (e); \ 291195972f6Sopenharmony_ci set_errno(sockerr); \ 292195972f6Sopenharmony_ci} while (0) 293195972f6Sopenharmony_ci 294195972f6Sopenharmony_ci/* Forward declaration of some functions */ 295195972f6Sopenharmony_ci#if LWIP_SOCKET_SELECT || LWIP_SOCKET_POLL 296195972f6Sopenharmony_cistatic void event_callback(struct netconn *conn, enum netconn_evt evt, u16_t len); 297195972f6Sopenharmony_ci#define DEFAULT_SOCKET_EVENTCB event_callback 298195972f6Sopenharmony_cistatic void select_check_waiters(int s, int has_recvevent, int has_sendevent, int has_errevent); 299195972f6Sopenharmony_ci#else 300195972f6Sopenharmony_ci#define DEFAULT_SOCKET_EVENTCB NULL 301195972f6Sopenharmony_ci#endif 302195972f6Sopenharmony_ci#if !LWIP_TCPIP_CORE_LOCKING 303195972f6Sopenharmony_cistatic void lwip_getsockopt_callback(void *arg); 304195972f6Sopenharmony_cistatic void lwip_setsockopt_callback(void *arg); 305195972f6Sopenharmony_ci#endif 306195972f6Sopenharmony_cistatic int lwip_getsockopt_impl(int s, int level, int optname, void *optval, socklen_t *optlen); 307195972f6Sopenharmony_cistatic int lwip_setsockopt_impl(int s, int level, int optname, const void *optval, socklen_t optlen); 308195972f6Sopenharmony_cistatic int free_socket_locked(struct lwip_sock *sock, int is_tcp, struct netconn **conn, 309195972f6Sopenharmony_ci union lwip_sock_lastdata *lastdata); 310195972f6Sopenharmony_cistatic void free_socket_free_elements(int is_tcp, struct netconn *conn, union lwip_sock_lastdata *lastdata); 311195972f6Sopenharmony_ci 312195972f6Sopenharmony_ci#if LWIP_IPV4 && LWIP_IPV6 313195972f6Sopenharmony_cistatic void 314195972f6Sopenharmony_cisockaddr_to_ipaddr_port(const struct sockaddr *sockaddr, ip_addr_t *ipaddr, u16_t *port) 315195972f6Sopenharmony_ci{ 316195972f6Sopenharmony_ci if ((sockaddr->sa_family) == AF_INET6) { 317195972f6Sopenharmony_ci SOCKADDR6_TO_IP6ADDR_PORT((const struct sockaddr_in6 *)(const void *)(sockaddr), ipaddr, *port); 318195972f6Sopenharmony_ci ipaddr->type = IPADDR_TYPE_V6; 319195972f6Sopenharmony_ci } else { 320195972f6Sopenharmony_ci SOCKADDR4_TO_IP4ADDR_PORT((const struct sockaddr_in *)(const void *)(sockaddr), ipaddr, *port); 321195972f6Sopenharmony_ci ipaddr->type = IPADDR_TYPE_V4; 322195972f6Sopenharmony_ci } 323195972f6Sopenharmony_ci} 324195972f6Sopenharmony_ci#endif /* LWIP_IPV4 && LWIP_IPV6 */ 325195972f6Sopenharmony_ci 326195972f6Sopenharmony_ci/** LWIP_NETCONN_SEM_PER_THREAD==1: initialize thread-local semaphore */ 327195972f6Sopenharmony_civoid 328195972f6Sopenharmony_cilwip_socket_thread_init(void) 329195972f6Sopenharmony_ci{ 330195972f6Sopenharmony_ci netconn_thread_init(); 331195972f6Sopenharmony_ci} 332195972f6Sopenharmony_ci 333195972f6Sopenharmony_ci/** LWIP_NETCONN_SEM_PER_THREAD==1: destroy thread-local semaphore */ 334195972f6Sopenharmony_civoid 335195972f6Sopenharmony_cilwip_socket_thread_cleanup(void) 336195972f6Sopenharmony_ci{ 337195972f6Sopenharmony_ci netconn_thread_cleanup(); 338195972f6Sopenharmony_ci} 339195972f6Sopenharmony_ci 340195972f6Sopenharmony_ci#if LWIP_NETCONN_FULLDUPLEX 341195972f6Sopenharmony_ci/* Thread-safe increment of sock->fd_used, with overflow check */ 342195972f6Sopenharmony_cistatic int 343195972f6Sopenharmony_cisock_inc_used(struct lwip_sock *sock) 344195972f6Sopenharmony_ci{ 345195972f6Sopenharmony_ci int ret; 346195972f6Sopenharmony_ci SYS_ARCH_DECL_PROTECT(lev); 347195972f6Sopenharmony_ci 348195972f6Sopenharmony_ci LWIP_ASSERT("sock != NULL", sock != NULL); 349195972f6Sopenharmony_ci 350195972f6Sopenharmony_ci SYS_ARCH_PROTECT(lev); 351195972f6Sopenharmony_ci if (sock->fd_free_pending) { 352195972f6Sopenharmony_ci /* prevent new usage of this socket if free is pending */ 353195972f6Sopenharmony_ci ret = 0; 354195972f6Sopenharmony_ci } else { 355195972f6Sopenharmony_ci ++sock->fd_used; 356195972f6Sopenharmony_ci ret = 1; 357195972f6Sopenharmony_ci LWIP_ASSERT("sock->fd_used != 0", sock->fd_used != 0); 358195972f6Sopenharmony_ci } 359195972f6Sopenharmony_ci SYS_ARCH_UNPROTECT(lev); 360195972f6Sopenharmony_ci return ret; 361195972f6Sopenharmony_ci} 362195972f6Sopenharmony_ci 363195972f6Sopenharmony_ci/* Like sock_inc_used(), but called under SYS_ARCH_PROTECT lock. */ 364195972f6Sopenharmony_cistatic int 365195972f6Sopenharmony_cisock_inc_used_locked(struct lwip_sock *sock) 366195972f6Sopenharmony_ci{ 367195972f6Sopenharmony_ci LWIP_ASSERT("sock != NULL", sock != NULL); 368195972f6Sopenharmony_ci 369195972f6Sopenharmony_ci if (sock->fd_free_pending) { 370195972f6Sopenharmony_ci LWIP_ASSERT("sock->fd_used != 0", sock->fd_used != 0); 371195972f6Sopenharmony_ci return 0; 372195972f6Sopenharmony_ci } 373195972f6Sopenharmony_ci 374195972f6Sopenharmony_ci ++sock->fd_used; 375195972f6Sopenharmony_ci LWIP_ASSERT("sock->fd_used != 0", sock->fd_used != 0); 376195972f6Sopenharmony_ci return 1; 377195972f6Sopenharmony_ci} 378195972f6Sopenharmony_ci 379195972f6Sopenharmony_ci/* In full-duplex mode,sock->fd_used != 0 prevents a socket descriptor from being 380195972f6Sopenharmony_ci * released (and possibly reused) when used from more than one thread 381195972f6Sopenharmony_ci * (e.g. read-while-write or close-while-write, etc) 382195972f6Sopenharmony_ci * This function is called at the end of functions using (try)get_socket*(). 383195972f6Sopenharmony_ci */ 384195972f6Sopenharmony_cistatic void 385195972f6Sopenharmony_cidone_socket(struct lwip_sock *sock) 386195972f6Sopenharmony_ci{ 387195972f6Sopenharmony_ci int freed = 0; 388195972f6Sopenharmony_ci int is_tcp = 0; 389195972f6Sopenharmony_ci struct netconn *conn = NULL; 390195972f6Sopenharmony_ci union lwip_sock_lastdata lastdata; 391195972f6Sopenharmony_ci SYS_ARCH_DECL_PROTECT(lev); 392195972f6Sopenharmony_ci LWIP_ASSERT("sock != NULL", sock != NULL); 393195972f6Sopenharmony_ci 394195972f6Sopenharmony_ci SYS_ARCH_PROTECT(lev); 395195972f6Sopenharmony_ci LWIP_ASSERT("sock->fd_used > 0", sock->fd_used > 0); 396195972f6Sopenharmony_ci if (--sock->fd_used == 0) { 397195972f6Sopenharmony_ci if (sock->fd_free_pending) { 398195972f6Sopenharmony_ci /* free the socket */ 399195972f6Sopenharmony_ci sock->fd_used = 1; 400195972f6Sopenharmony_ci is_tcp = sock->fd_free_pending & LWIP_SOCK_FD_FREE_TCP; 401195972f6Sopenharmony_ci freed = free_socket_locked(sock, is_tcp, &conn, &lastdata); 402195972f6Sopenharmony_ci } 403195972f6Sopenharmony_ci } 404195972f6Sopenharmony_ci SYS_ARCH_UNPROTECT(lev); 405195972f6Sopenharmony_ci 406195972f6Sopenharmony_ci if (freed) { 407195972f6Sopenharmony_ci free_socket_free_elements(is_tcp, conn, &lastdata); 408195972f6Sopenharmony_ci } 409195972f6Sopenharmony_ci} 410195972f6Sopenharmony_ci 411195972f6Sopenharmony_ci#else /* LWIP_NETCONN_FULLDUPLEX */ 412195972f6Sopenharmony_ci#define sock_inc_used(sock) 1 413195972f6Sopenharmony_ci#define sock_inc_used_locked(sock) 1 414195972f6Sopenharmony_ci#define done_socket(sock) 415195972f6Sopenharmony_ci#endif /* LWIP_NETCONN_FULLDUPLEX */ 416195972f6Sopenharmony_ci 417195972f6Sopenharmony_ci/* Translate a socket 'int' into a pointer (only fails if the index is invalid) */ 418195972f6Sopenharmony_cistatic struct lwip_sock * 419195972f6Sopenharmony_citryget_socket_unconn_nouse(int fd) 420195972f6Sopenharmony_ci{ 421195972f6Sopenharmony_ci int s = fd - LWIP_SOCKET_OFFSET; 422195972f6Sopenharmony_ci if ((s < 0) || (s >= NUM_SOCKETS)) { 423195972f6Sopenharmony_ci LWIP_DEBUGF(SOCKETS_DEBUG, ("tryget_socket_unconn(%d): invalid\n", fd)); 424195972f6Sopenharmony_ci return NULL; 425195972f6Sopenharmony_ci } 426195972f6Sopenharmony_ci return &sockets[s]; 427195972f6Sopenharmony_ci} 428195972f6Sopenharmony_ci 429195972f6Sopenharmony_cistruct lwip_sock * 430195972f6Sopenharmony_cilwip_socket_dbg_get_socket(int fd) 431195972f6Sopenharmony_ci{ 432195972f6Sopenharmony_ci return tryget_socket_unconn_nouse(fd); 433195972f6Sopenharmony_ci} 434195972f6Sopenharmony_ci 435195972f6Sopenharmony_ci/* Translate a socket 'int' into a pointer (only fails if the index is invalid) */ 436195972f6Sopenharmony_cistatic struct lwip_sock * 437195972f6Sopenharmony_citryget_socket_unconn(int fd) 438195972f6Sopenharmony_ci{ 439195972f6Sopenharmony_ci struct lwip_sock *ret = tryget_socket_unconn_nouse(fd); 440195972f6Sopenharmony_ci if (ret != NULL) { 441195972f6Sopenharmony_ci if (!sock_inc_used(ret)) { 442195972f6Sopenharmony_ci return NULL; 443195972f6Sopenharmony_ci } 444195972f6Sopenharmony_ci } 445195972f6Sopenharmony_ci return ret; 446195972f6Sopenharmony_ci} 447195972f6Sopenharmony_ci 448195972f6Sopenharmony_ci/* Like tryget_socket_unconn(), but called under SYS_ARCH_PROTECT lock. */ 449195972f6Sopenharmony_cistatic struct lwip_sock * 450195972f6Sopenharmony_citryget_socket_unconn_locked(int fd) 451195972f6Sopenharmony_ci{ 452195972f6Sopenharmony_ci struct lwip_sock *ret = tryget_socket_unconn_nouse(fd); 453195972f6Sopenharmony_ci if (ret != NULL) { 454195972f6Sopenharmony_ci if (!sock_inc_used_locked(ret)) { 455195972f6Sopenharmony_ci return NULL; 456195972f6Sopenharmony_ci } 457195972f6Sopenharmony_ci } 458195972f6Sopenharmony_ci return ret; 459195972f6Sopenharmony_ci} 460195972f6Sopenharmony_ci 461195972f6Sopenharmony_ci/** 462195972f6Sopenharmony_ci * Same as get_socket but doesn't set errno 463195972f6Sopenharmony_ci * 464195972f6Sopenharmony_ci * @param fd externally used socket index 465195972f6Sopenharmony_ci * @return struct lwip_sock for the socket or NULL if not found 466195972f6Sopenharmony_ci */ 467195972f6Sopenharmony_cistatic struct lwip_sock * 468195972f6Sopenharmony_citryget_socket(int fd) 469195972f6Sopenharmony_ci{ 470195972f6Sopenharmony_ci struct lwip_sock *sock = tryget_socket_unconn(fd); 471195972f6Sopenharmony_ci if (sock != NULL) { 472195972f6Sopenharmony_ci if (sock->conn) { 473195972f6Sopenharmony_ci return sock; 474195972f6Sopenharmony_ci } 475195972f6Sopenharmony_ci done_socket(sock); 476195972f6Sopenharmony_ci } 477195972f6Sopenharmony_ci return NULL; 478195972f6Sopenharmony_ci} 479195972f6Sopenharmony_ci 480195972f6Sopenharmony_ci/** 481195972f6Sopenharmony_ci * Map a externally used socket index to the internal socket representation. 482195972f6Sopenharmony_ci * 483195972f6Sopenharmony_ci * @param fd externally used socket index 484195972f6Sopenharmony_ci * @return struct lwip_sock for the socket or NULL if not found 485195972f6Sopenharmony_ci */ 486195972f6Sopenharmony_cistatic struct lwip_sock * 487195972f6Sopenharmony_ciget_socket(int fd) 488195972f6Sopenharmony_ci{ 489195972f6Sopenharmony_ci struct lwip_sock *sock = tryget_socket(fd); 490195972f6Sopenharmony_ci if (!sock) { 491195972f6Sopenharmony_ci if ((fd < LWIP_SOCKET_OFFSET) || (fd >= (LWIP_SOCKET_OFFSET + NUM_SOCKETS))) { 492195972f6Sopenharmony_ci LWIP_DEBUGF(SOCKETS_DEBUG, ("get_socket(%d): invalid\n", fd)); 493195972f6Sopenharmony_ci } 494195972f6Sopenharmony_ci set_errno(EBADF); 495195972f6Sopenharmony_ci return NULL; 496195972f6Sopenharmony_ci } 497195972f6Sopenharmony_ci return sock; 498195972f6Sopenharmony_ci} 499195972f6Sopenharmony_ci 500195972f6Sopenharmony_ci/** 501195972f6Sopenharmony_ci * Allocate a new socket for a given netconn. 502195972f6Sopenharmony_ci * 503195972f6Sopenharmony_ci * @param newconn the netconn for which to allocate a socket 504195972f6Sopenharmony_ci * @param accepted 1 if socket has been created by accept(), 505195972f6Sopenharmony_ci * 0 if socket has been created by socket() 506195972f6Sopenharmony_ci * @return the index of the new socket; -1 on error 507195972f6Sopenharmony_ci */ 508195972f6Sopenharmony_cistatic int 509195972f6Sopenharmony_cialloc_socket(struct netconn *newconn, int accepted) 510195972f6Sopenharmony_ci{ 511195972f6Sopenharmony_ci int i; 512195972f6Sopenharmony_ci SYS_ARCH_DECL_PROTECT(lev); 513195972f6Sopenharmony_ci LWIP_UNUSED_ARG(accepted); 514195972f6Sopenharmony_ci 515195972f6Sopenharmony_ci /* allocate a new socket identifier */ 516195972f6Sopenharmony_ci for (i = 0; i < NUM_SOCKETS; ++i) { 517195972f6Sopenharmony_ci /* Protect socket array */ 518195972f6Sopenharmony_ci SYS_ARCH_PROTECT(lev); 519195972f6Sopenharmony_ci if (!sockets[i].conn) { 520195972f6Sopenharmony_ci#if LWIP_NETCONN_FULLDUPLEX 521195972f6Sopenharmony_ci if (sockets[i].fd_used) { 522195972f6Sopenharmony_ci SYS_ARCH_UNPROTECT(lev); 523195972f6Sopenharmony_ci continue; 524195972f6Sopenharmony_ci } 525195972f6Sopenharmony_ci sockets[i].fd_used = 1; 526195972f6Sopenharmony_ci sockets[i].fd_free_pending = 0; 527195972f6Sopenharmony_ci#endif 528195972f6Sopenharmony_ci sockets[i].conn = newconn; 529195972f6Sopenharmony_ci /* The socket is not yet known to anyone, so no need to protect 530195972f6Sopenharmony_ci after having marked it as used. */ 531195972f6Sopenharmony_ci SYS_ARCH_UNPROTECT(lev); 532195972f6Sopenharmony_ci sockets[i].lastdata.pbuf = NULL; 533195972f6Sopenharmony_ci#if LWIP_SOCKET_SELECT || LWIP_SOCKET_POLL 534195972f6Sopenharmony_ci LWIP_ASSERT("sockets[i].select_waiting == 0", sockets[i].select_waiting == 0); 535195972f6Sopenharmony_ci sockets[i].rcvevent = 0; 536195972f6Sopenharmony_ci /* TCP sendbuf is empty, but the socket is not yet writable until connected 537195972f6Sopenharmony_ci * (unless it has been created by accept()). */ 538195972f6Sopenharmony_ci sockets[i].sendevent = (NETCONNTYPE_GROUP(newconn->type) == NETCONN_TCP ? (accepted != 0) : 1); 539195972f6Sopenharmony_ci sockets[i].errevent = 0; 540195972f6Sopenharmony_ci init_waitqueue_head(&sockets[i].wq); 541195972f6Sopenharmony_ci#endif /* LWIP_SOCKET_SELECT || LWIP_SOCKET_POLL */ 542195972f6Sopenharmony_ci return i + LWIP_SOCKET_OFFSET; 543195972f6Sopenharmony_ci } 544195972f6Sopenharmony_ci SYS_ARCH_UNPROTECT(lev); 545195972f6Sopenharmony_ci } 546195972f6Sopenharmony_ci return -1; 547195972f6Sopenharmony_ci} 548195972f6Sopenharmony_ci 549195972f6Sopenharmony_ci/** Free a socket (under lock) 550195972f6Sopenharmony_ci * 551195972f6Sopenharmony_ci * @param sock the socket to free 552195972f6Sopenharmony_ci * @param is_tcp != 0 for TCP sockets, used to free lastdata 553195972f6Sopenharmony_ci * @param conn the socekt's netconn is stored here, must be freed externally 554195972f6Sopenharmony_ci * @param lastdata lastdata is stored here, must be freed externally 555195972f6Sopenharmony_ci */ 556195972f6Sopenharmony_cistatic int 557195972f6Sopenharmony_cifree_socket_locked(struct lwip_sock *sock, int is_tcp, struct netconn **conn, 558195972f6Sopenharmony_ci union lwip_sock_lastdata *lastdata) 559195972f6Sopenharmony_ci{ 560195972f6Sopenharmony_ci#if LWIP_NETCONN_FULLDUPLEX 561195972f6Sopenharmony_ci LWIP_ASSERT("sock->fd_used > 0", sock->fd_used > 0); 562195972f6Sopenharmony_ci sock->fd_used--; 563195972f6Sopenharmony_ci if (sock->fd_used > 0) { 564195972f6Sopenharmony_ci sock->fd_free_pending = LWIP_SOCK_FD_FREE_FREE | (is_tcp ? LWIP_SOCK_FD_FREE_TCP : 0); 565195972f6Sopenharmony_ci return 0; 566195972f6Sopenharmony_ci } 567195972f6Sopenharmony_ci#else /* LWIP_NETCONN_FULLDUPLEX */ 568195972f6Sopenharmony_ci LWIP_UNUSED_ARG(is_tcp); 569195972f6Sopenharmony_ci#endif /* LWIP_NETCONN_FULLDUPLEX */ 570195972f6Sopenharmony_ci 571195972f6Sopenharmony_ci *lastdata = sock->lastdata; 572195972f6Sopenharmony_ci sock->lastdata.pbuf = NULL; 573195972f6Sopenharmony_ci *conn = sock->conn; 574195972f6Sopenharmony_ci sock->conn = NULL; 575195972f6Sopenharmony_ci return 1; 576195972f6Sopenharmony_ci} 577195972f6Sopenharmony_ci 578195972f6Sopenharmony_ci/** Free a socket's leftover members. 579195972f6Sopenharmony_ci */ 580195972f6Sopenharmony_cistatic void 581195972f6Sopenharmony_cifree_socket_free_elements(int is_tcp, struct netconn *conn, union lwip_sock_lastdata *lastdata) 582195972f6Sopenharmony_ci{ 583195972f6Sopenharmony_ci if (lastdata->pbuf != NULL) { 584195972f6Sopenharmony_ci if (is_tcp) { 585195972f6Sopenharmony_ci pbuf_free(lastdata->pbuf); 586195972f6Sopenharmony_ci } else { 587195972f6Sopenharmony_ci netbuf_delete(lastdata->netbuf); 588195972f6Sopenharmony_ci } 589195972f6Sopenharmony_ci } 590195972f6Sopenharmony_ci if (conn != NULL) { 591195972f6Sopenharmony_ci /* netconn_prepare_delete() has already been called, here we only free the conn */ 592195972f6Sopenharmony_ci netconn_delete(conn); 593195972f6Sopenharmony_ci } 594195972f6Sopenharmony_ci} 595195972f6Sopenharmony_ci 596195972f6Sopenharmony_ci/** Free a socket. The socket's netconn must have been 597195972f6Sopenharmony_ci * delete before! 598195972f6Sopenharmony_ci * 599195972f6Sopenharmony_ci * @param sock the socket to free 600195972f6Sopenharmony_ci * @param is_tcp != 0 for TCP sockets, used to free lastdata 601195972f6Sopenharmony_ci */ 602195972f6Sopenharmony_cistatic void 603195972f6Sopenharmony_cifree_socket(struct lwip_sock *sock, int is_tcp) 604195972f6Sopenharmony_ci{ 605195972f6Sopenharmony_ci int freed; 606195972f6Sopenharmony_ci struct netconn *conn; 607195972f6Sopenharmony_ci union lwip_sock_lastdata lastdata; 608195972f6Sopenharmony_ci SYS_ARCH_DECL_PROTECT(lev); 609195972f6Sopenharmony_ci 610195972f6Sopenharmony_ci /* Protect socket array */ 611195972f6Sopenharmony_ci SYS_ARCH_PROTECT(lev); 612195972f6Sopenharmony_ci 613195972f6Sopenharmony_ci freed = free_socket_locked(sock, is_tcp, &conn, &lastdata); 614195972f6Sopenharmony_ci SYS_ARCH_UNPROTECT(lev); 615195972f6Sopenharmony_ci /* don't use 'sock' after this line, as another task might have allocated it */ 616195972f6Sopenharmony_ci 617195972f6Sopenharmony_ci if (freed) { 618195972f6Sopenharmony_ci free_socket_free_elements(is_tcp, conn, &lastdata); 619195972f6Sopenharmony_ci } 620195972f6Sopenharmony_ci} 621195972f6Sopenharmony_ci 622195972f6Sopenharmony_ci/* Below this, the well-known socket functions are implemented. 623195972f6Sopenharmony_ci * Use google.com or opengroup.org to get a good description :-) 624195972f6Sopenharmony_ci * 625195972f6Sopenharmony_ci * Exceptions are documented! 626195972f6Sopenharmony_ci */ 627195972f6Sopenharmony_ci 628195972f6Sopenharmony_ciint 629195972f6Sopenharmony_cilwip_accept(int s, struct sockaddr *addr, socklen_t *addrlen) 630195972f6Sopenharmony_ci{ 631195972f6Sopenharmony_ci struct lwip_sock *sock, *nsock; 632195972f6Sopenharmony_ci struct netconn *newconn; 633195972f6Sopenharmony_ci ip_addr_t naddr; 634195972f6Sopenharmony_ci u16_t port = 0; 635195972f6Sopenharmony_ci int newsock; 636195972f6Sopenharmony_ci err_t err; 637195972f6Sopenharmony_ci int recvevent; 638195972f6Sopenharmony_ci SYS_ARCH_DECL_PROTECT(lev); 639195972f6Sopenharmony_ci 640195972f6Sopenharmony_ci LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d)...\n", s)); 641195972f6Sopenharmony_ci sock = get_socket(s); 642195972f6Sopenharmony_ci if (!sock) { 643195972f6Sopenharmony_ci return -1; 644195972f6Sopenharmony_ci } 645195972f6Sopenharmony_ci 646195972f6Sopenharmony_ci /* wait for a new connection */ 647195972f6Sopenharmony_ci err = netconn_accept(sock->conn, &newconn); 648195972f6Sopenharmony_ci if (err != ERR_OK) { 649195972f6Sopenharmony_ci LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d): netconn_acept failed, err=%d\n", s, err)); 650195972f6Sopenharmony_ci if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_TCP) { 651195972f6Sopenharmony_ci sock_set_errno(sock, EOPNOTSUPP); 652195972f6Sopenharmony_ci } else if (err == ERR_CLSD) { 653195972f6Sopenharmony_ci sock_set_errno(sock, EINVAL); 654195972f6Sopenharmony_ci } else { 655195972f6Sopenharmony_ci sock_set_errno(sock, err_to_errno(err)); 656195972f6Sopenharmony_ci } 657195972f6Sopenharmony_ci done_socket(sock); 658195972f6Sopenharmony_ci return -1; 659195972f6Sopenharmony_ci } 660195972f6Sopenharmony_ci LWIP_ASSERT("newconn != NULL", newconn != NULL); 661195972f6Sopenharmony_ci 662195972f6Sopenharmony_ci newsock = alloc_socket(newconn, 1); 663195972f6Sopenharmony_ci if (newsock == -1) { 664195972f6Sopenharmony_ci netconn_delete(newconn); 665195972f6Sopenharmony_ci sock_set_errno(sock, ENFILE); 666195972f6Sopenharmony_ci done_socket(sock); 667195972f6Sopenharmony_ci return -1; 668195972f6Sopenharmony_ci } 669195972f6Sopenharmony_ci LWIP_ASSERT("invalid socket index", (newsock >= LWIP_SOCKET_OFFSET) && (newsock < NUM_SOCKETS + LWIP_SOCKET_OFFSET)); 670195972f6Sopenharmony_ci nsock = &sockets[newsock - LWIP_SOCKET_OFFSET]; 671195972f6Sopenharmony_ci 672195972f6Sopenharmony_ci /* See event_callback: If data comes in right away after an accept, even 673195972f6Sopenharmony_ci * though the server task might not have created a new socket yet. 674195972f6Sopenharmony_ci * In that case, newconn->socket is counted down (newconn->socket--), 675195972f6Sopenharmony_ci * so nsock->rcvevent is >= 1 here! 676195972f6Sopenharmony_ci */ 677195972f6Sopenharmony_ci SYS_ARCH_PROTECT(lev); 678195972f6Sopenharmony_ci recvevent = (s16_t)(-1 - newconn->socket); 679195972f6Sopenharmony_ci newconn->socket = newsock; 680195972f6Sopenharmony_ci SYS_ARCH_UNPROTECT(lev); 681195972f6Sopenharmony_ci 682195972f6Sopenharmony_ci if (newconn->callback) { 683195972f6Sopenharmony_ci LOCK_TCPIP_CORE(); 684195972f6Sopenharmony_ci while (recvevent > 0) { 685195972f6Sopenharmony_ci recvevent--; 686195972f6Sopenharmony_ci newconn->callback(newconn, NETCONN_EVT_RCVPLUS, 0); 687195972f6Sopenharmony_ci } 688195972f6Sopenharmony_ci UNLOCK_TCPIP_CORE(); 689195972f6Sopenharmony_ci } 690195972f6Sopenharmony_ci 691195972f6Sopenharmony_ci /* Note that POSIX only requires us to check addr is non-NULL. addrlen must 692195972f6Sopenharmony_ci * not be NULL if addr is valid. 693195972f6Sopenharmony_ci */ 694195972f6Sopenharmony_ci if ((addr != NULL) && (addrlen != NULL)) { 695195972f6Sopenharmony_ci union sockaddr_aligned tempaddr; 696195972f6Sopenharmony_ci /* get the IP address and port of the remote host */ 697195972f6Sopenharmony_ci err = netconn_peer(newconn, &naddr, &port); 698195972f6Sopenharmony_ci if (err != ERR_OK) { 699195972f6Sopenharmony_ci LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d): netconn_peer failed, err=%d\n", s, err)); 700195972f6Sopenharmony_ci free_socket(nsock, 1); 701195972f6Sopenharmony_ci sock_set_errno(sock, err_to_errno(err)); 702195972f6Sopenharmony_ci done_socket(sock); 703195972f6Sopenharmony_ci return -1; 704195972f6Sopenharmony_ci } 705195972f6Sopenharmony_ci 706195972f6Sopenharmony_ci IPADDR_PORT_TO_SOCKADDR(&tempaddr, &naddr, port); 707195972f6Sopenharmony_ci if (*addrlen > tempaddr.sa.sa_len) { 708195972f6Sopenharmony_ci *addrlen = tempaddr.sa.sa_len; 709195972f6Sopenharmony_ci } 710195972f6Sopenharmony_ci MEMCPY(addr, &tempaddr, *addrlen); 711195972f6Sopenharmony_ci 712195972f6Sopenharmony_ci LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d) returning new sock=%d addr=", s, newsock)); 713195972f6Sopenharmony_ci ip_addr_debug_print_val(SOCKETS_DEBUG, naddr); 714195972f6Sopenharmony_ci LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F"\n", port)); 715195972f6Sopenharmony_ci } else { 716195972f6Sopenharmony_ci LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d) returning new sock=%d", s, newsock)); 717195972f6Sopenharmony_ci } 718195972f6Sopenharmony_ci 719195972f6Sopenharmony_ci sock_set_errno(sock, 0); 720195972f6Sopenharmony_ci done_socket(sock); 721195972f6Sopenharmony_ci done_socket(nsock); 722195972f6Sopenharmony_ci return newsock; 723195972f6Sopenharmony_ci} 724195972f6Sopenharmony_ci 725195972f6Sopenharmony_ciint 726195972f6Sopenharmony_cilwip_bind(int s, const struct sockaddr *name, socklen_t namelen) 727195972f6Sopenharmony_ci{ 728195972f6Sopenharmony_ci struct lwip_sock *sock; 729195972f6Sopenharmony_ci ip_addr_t local_addr; 730195972f6Sopenharmony_ci u16_t local_port; 731195972f6Sopenharmony_ci err_t err; 732195972f6Sopenharmony_ci 733195972f6Sopenharmony_ci sock = get_socket(s); 734195972f6Sopenharmony_ci if (!sock) { 735195972f6Sopenharmony_ci return -1; 736195972f6Sopenharmony_ci } 737195972f6Sopenharmony_ci 738195972f6Sopenharmony_ci if (!SOCK_ADDR_TYPE_MATCH(name, sock)) { 739195972f6Sopenharmony_ci /* sockaddr does not match socket type (IPv4/IPv6) */ 740195972f6Sopenharmony_ci sock_set_errno(sock, err_to_errno(ERR_VAL)); 741195972f6Sopenharmony_ci done_socket(sock); 742195972f6Sopenharmony_ci return -1; 743195972f6Sopenharmony_ci } 744195972f6Sopenharmony_ci 745195972f6Sopenharmony_ci /* check size, family and alignment of 'name' */ 746195972f6Sopenharmony_ci LWIP_ERROR("lwip_bind: invalid address", (IS_SOCK_ADDR_LEN_VALID(namelen) && 747195972f6Sopenharmony_ci IS_SOCK_ADDR_TYPE_VALID(name) && IS_SOCK_ADDR_ALIGNED(name)), 748195972f6Sopenharmony_ci sock_set_errno(sock, err_to_errno(ERR_ARG)); done_socket(sock); return -1;); 749195972f6Sopenharmony_ci LWIP_UNUSED_ARG(namelen); 750195972f6Sopenharmony_ci 751195972f6Sopenharmony_ci SOCKADDR_TO_IPADDR_PORT(name, &local_addr, local_port); 752195972f6Sopenharmony_ci LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d, addr=", s)); 753195972f6Sopenharmony_ci ip_addr_debug_print_val(SOCKETS_DEBUG, local_addr); 754195972f6Sopenharmony_ci LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F")\n", local_port)); 755195972f6Sopenharmony_ci 756195972f6Sopenharmony_ci#if LWIP_IPV4 && LWIP_IPV6 757195972f6Sopenharmony_ci /* Dual-stack: Unmap IPv4 mapped IPv6 addresses */ 758195972f6Sopenharmony_ci if (IP_IS_V6_VAL(local_addr) && ip6_addr_isipv4mappedipv6(ip_2_ip6(&local_addr))) { 759195972f6Sopenharmony_ci unmap_ipv4_mapped_ipv6(ip_2_ip4(&local_addr), ip_2_ip6(&local_addr)); 760195972f6Sopenharmony_ci IP_SET_TYPE_VAL(local_addr, IPADDR_TYPE_V4); 761195972f6Sopenharmony_ci } 762195972f6Sopenharmony_ci#endif /* LWIP_IPV4 && LWIP_IPV6 */ 763195972f6Sopenharmony_ci 764195972f6Sopenharmony_ci err = netconn_bind(sock->conn, &local_addr, local_port); 765195972f6Sopenharmony_ci 766195972f6Sopenharmony_ci if (err != ERR_OK) { 767195972f6Sopenharmony_ci LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d) failed, err=%d\n", s, err)); 768195972f6Sopenharmony_ci sock_set_errno(sock, err_to_errno(err)); 769195972f6Sopenharmony_ci done_socket(sock); 770195972f6Sopenharmony_ci return -1; 771195972f6Sopenharmony_ci } 772195972f6Sopenharmony_ci 773195972f6Sopenharmony_ci LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d) succeeded\n", s)); 774195972f6Sopenharmony_ci sock_set_errno(sock, 0); 775195972f6Sopenharmony_ci done_socket(sock); 776195972f6Sopenharmony_ci return 0; 777195972f6Sopenharmony_ci} 778195972f6Sopenharmony_ci 779195972f6Sopenharmony_ciint 780195972f6Sopenharmony_cilwip_close(int s) 781195972f6Sopenharmony_ci{ 782195972f6Sopenharmony_ci#if LWIP_ENABLE_DISTRIBUTED_NET 783195972f6Sopenharmony_ci if (!is_distributed_net_enabled()) { 784195972f6Sopenharmony_ci return lwip_close_internal(s); 785195972f6Sopenharmony_ci } 786195972f6Sopenharmony_ci return distributed_net_close(s); 787195972f6Sopenharmony_ci} 788195972f6Sopenharmony_ci 789195972f6Sopenharmony_ciint 790195972f6Sopenharmony_cilwip_close_internal(int s) 791195972f6Sopenharmony_ci{ 792195972f6Sopenharmony_ci#endif 793195972f6Sopenharmony_ci struct lwip_sock *sock; 794195972f6Sopenharmony_ci int is_tcp = 0; 795195972f6Sopenharmony_ci err_t err; 796195972f6Sopenharmony_ci 797195972f6Sopenharmony_ci LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_close(%d)\n", s)); 798195972f6Sopenharmony_ci 799195972f6Sopenharmony_ci sock = get_socket(s); 800195972f6Sopenharmony_ci if (!sock) { 801195972f6Sopenharmony_ci return -1; 802195972f6Sopenharmony_ci } 803195972f6Sopenharmony_ci 804195972f6Sopenharmony_ci if (sock->conn != NULL) { 805195972f6Sopenharmony_ci is_tcp = NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP; 806195972f6Sopenharmony_ci } else { 807195972f6Sopenharmony_ci LWIP_ASSERT("sock->lastdata == NULL", sock->lastdata.pbuf == NULL); 808195972f6Sopenharmony_ci } 809195972f6Sopenharmony_ci 810195972f6Sopenharmony_ci#if LWIP_IGMP 811195972f6Sopenharmony_ci /* drop all possibly joined IGMP memberships */ 812195972f6Sopenharmony_ci lwip_socket_drop_registered_memberships(s); 813195972f6Sopenharmony_ci#endif /* LWIP_IGMP */ 814195972f6Sopenharmony_ci#if LWIP_IPV6_MLD 815195972f6Sopenharmony_ci /* drop all possibly joined MLD6 memberships */ 816195972f6Sopenharmony_ci lwip_socket_drop_registered_mld6_memberships(s); 817195972f6Sopenharmony_ci#endif /* LWIP_IPV6_MLD */ 818195972f6Sopenharmony_ci 819195972f6Sopenharmony_ci err = netconn_prepare_delete(sock->conn); 820195972f6Sopenharmony_ci if (err != ERR_OK) { 821195972f6Sopenharmony_ci sock_set_errno(sock, err_to_errno(err)); 822195972f6Sopenharmony_ci done_socket(sock); 823195972f6Sopenharmony_ci return -1; 824195972f6Sopenharmony_ci } 825195972f6Sopenharmony_ci 826195972f6Sopenharmony_ci free_socket(sock, is_tcp); 827195972f6Sopenharmony_ci set_errno(0); 828195972f6Sopenharmony_ci return 0; 829195972f6Sopenharmony_ci} 830195972f6Sopenharmony_ci 831195972f6Sopenharmony_ciint 832195972f6Sopenharmony_cilwip_connect(int s, const struct sockaddr *name, socklen_t namelen) 833195972f6Sopenharmony_ci{ 834195972f6Sopenharmony_ci#if LWIP_ENABLE_DISTRIBUTED_NET 835195972f6Sopenharmony_ci if (!is_distributed_net_enabled()) { 836195972f6Sopenharmony_ci return lwip_connect_internal(s, name, namelen); 837195972f6Sopenharmony_ci } 838195972f6Sopenharmony_ci return distributed_net_connect(s, name, namelen); 839195972f6Sopenharmony_ci} 840195972f6Sopenharmony_ci 841195972f6Sopenharmony_ciint 842195972f6Sopenharmony_cilwip_connect_internal(int s, const struct sockaddr *name, socklen_t namelen) 843195972f6Sopenharmony_ci{ 844195972f6Sopenharmony_ci#endif 845195972f6Sopenharmony_ci struct lwip_sock *sock; 846195972f6Sopenharmony_ci err_t err; 847195972f6Sopenharmony_ci 848195972f6Sopenharmony_ci sock = get_socket(s); 849195972f6Sopenharmony_ci if (!sock) { 850195972f6Sopenharmony_ci return -1; 851195972f6Sopenharmony_ci } 852195972f6Sopenharmony_ci 853195972f6Sopenharmony_ci if (!SOCK_ADDR_TYPE_MATCH_OR_UNSPEC(name, sock)) { 854195972f6Sopenharmony_ci /* sockaddr does not match socket type (IPv4/IPv6) */ 855195972f6Sopenharmony_ci sock_set_errno(sock, err_to_errno(ERR_VAL)); 856195972f6Sopenharmony_ci done_socket(sock); 857195972f6Sopenharmony_ci return -1; 858195972f6Sopenharmony_ci } 859195972f6Sopenharmony_ci 860195972f6Sopenharmony_ci LWIP_UNUSED_ARG(namelen); 861195972f6Sopenharmony_ci if (name->sa_family == AF_UNSPEC) { 862195972f6Sopenharmony_ci LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d, AF_UNSPEC)\n", s)); 863195972f6Sopenharmony_ci err = netconn_disconnect(sock->conn); 864195972f6Sopenharmony_ci } else { 865195972f6Sopenharmony_ci ip_addr_t remote_addr; 866195972f6Sopenharmony_ci u16_t remote_port; 867195972f6Sopenharmony_ci 868195972f6Sopenharmony_ci /* check size, family and alignment of 'name' */ 869195972f6Sopenharmony_ci LWIP_ERROR("lwip_connect: invalid address", IS_SOCK_ADDR_LEN_VALID(namelen) && 870195972f6Sopenharmony_ci IS_SOCK_ADDR_TYPE_VALID_OR_UNSPEC(name) && IS_SOCK_ADDR_ALIGNED(name), 871195972f6Sopenharmony_ci sock_set_errno(sock, err_to_errno(ERR_ARG)); done_socket(sock); return -1;); 872195972f6Sopenharmony_ci 873195972f6Sopenharmony_ci SOCKADDR_TO_IPADDR_PORT(name, &remote_addr, remote_port); 874195972f6Sopenharmony_ci LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d, addr=", s)); 875195972f6Sopenharmony_ci ip_addr_debug_print_val(SOCKETS_DEBUG, remote_addr); 876195972f6Sopenharmony_ci LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F")\n", remote_port)); 877195972f6Sopenharmony_ci 878195972f6Sopenharmony_ci#if LWIP_IPV4 && LWIP_IPV6 879195972f6Sopenharmony_ci /* Dual-stack: Unmap IPv4 mapped IPv6 addresses */ 880195972f6Sopenharmony_ci if (IP_IS_V6_VAL(remote_addr) && ip6_addr_isipv4mappedipv6(ip_2_ip6(&remote_addr))) { 881195972f6Sopenharmony_ci unmap_ipv4_mapped_ipv6(ip_2_ip4(&remote_addr), ip_2_ip6(&remote_addr)); 882195972f6Sopenharmony_ci IP_SET_TYPE_VAL(remote_addr, IPADDR_TYPE_V4); 883195972f6Sopenharmony_ci } 884195972f6Sopenharmony_ci#endif /* LWIP_IPV4 && LWIP_IPV6 */ 885195972f6Sopenharmony_ci 886195972f6Sopenharmony_ci err = netconn_connect(sock->conn, &remote_addr, remote_port); 887195972f6Sopenharmony_ci } 888195972f6Sopenharmony_ci 889195972f6Sopenharmony_ci if (err != ERR_OK) { 890195972f6Sopenharmony_ci LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d) failed, err=%d\n", s, err)); 891195972f6Sopenharmony_ci sock_set_errno(sock, err_to_errno(err)); 892195972f6Sopenharmony_ci done_socket(sock); 893195972f6Sopenharmony_ci return -1; 894195972f6Sopenharmony_ci } 895195972f6Sopenharmony_ci 896195972f6Sopenharmony_ci LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d) succeeded\n", s)); 897195972f6Sopenharmony_ci sock_set_errno(sock, 0); 898195972f6Sopenharmony_ci done_socket(sock); 899195972f6Sopenharmony_ci return 0; 900195972f6Sopenharmony_ci} 901195972f6Sopenharmony_ci 902195972f6Sopenharmony_ci/** 903195972f6Sopenharmony_ci * Set a socket into listen mode. 904195972f6Sopenharmony_ci * The socket may not have been used for another connection previously. 905195972f6Sopenharmony_ci * 906195972f6Sopenharmony_ci * @param s the socket to set to listening mode 907195972f6Sopenharmony_ci * @param backlog (ATTENTION: needs TCP_LISTEN_BACKLOG=1) 908195972f6Sopenharmony_ci * @return 0 on success, non-zero on failure 909195972f6Sopenharmony_ci */ 910195972f6Sopenharmony_ciint 911195972f6Sopenharmony_cilwip_listen(int s, int backlog) 912195972f6Sopenharmony_ci{ 913195972f6Sopenharmony_ci struct lwip_sock *sock; 914195972f6Sopenharmony_ci err_t err; 915195972f6Sopenharmony_ci 916195972f6Sopenharmony_ci LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_listen(%d, backlog=%d)\n", s, backlog)); 917195972f6Sopenharmony_ci 918195972f6Sopenharmony_ci sock = get_socket(s); 919195972f6Sopenharmony_ci if (!sock) { 920195972f6Sopenharmony_ci return -1; 921195972f6Sopenharmony_ci } 922195972f6Sopenharmony_ci 923195972f6Sopenharmony_ci /* limit the "backlog" parameter to fit in an u8_t */ 924195972f6Sopenharmony_ci backlog = LWIP_MIN(LWIP_MAX(backlog, 0), 0xff); 925195972f6Sopenharmony_ci 926195972f6Sopenharmony_ci err = netconn_listen_with_backlog(sock->conn, (u8_t)backlog); 927195972f6Sopenharmony_ci 928195972f6Sopenharmony_ci if (err != ERR_OK) { 929195972f6Sopenharmony_ci LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_listen(%d) failed, err=%d\n", s, err)); 930195972f6Sopenharmony_ci if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_TCP) { 931195972f6Sopenharmony_ci sock_set_errno(sock, EOPNOTSUPP); 932195972f6Sopenharmony_ci } else { 933195972f6Sopenharmony_ci sock_set_errno(sock, err_to_errno(err)); 934195972f6Sopenharmony_ci } 935195972f6Sopenharmony_ci done_socket(sock); 936195972f6Sopenharmony_ci return -1; 937195972f6Sopenharmony_ci } 938195972f6Sopenharmony_ci 939195972f6Sopenharmony_ci sock_set_errno(sock, 0); 940195972f6Sopenharmony_ci done_socket(sock); 941195972f6Sopenharmony_ci return 0; 942195972f6Sopenharmony_ci} 943195972f6Sopenharmony_ci 944195972f6Sopenharmony_ci#if LWIP_TCP 945195972f6Sopenharmony_ci/* Helper function to loop over receiving pbufs from netconn 946195972f6Sopenharmony_ci * until "len" bytes are received or we're otherwise done. 947195972f6Sopenharmony_ci * Keeps sock->lastdata for peeking or partly copying. 948195972f6Sopenharmony_ci */ 949195972f6Sopenharmony_cistatic ssize_t 950195972f6Sopenharmony_cilwip_recv_tcp(struct lwip_sock *sock, void *mem, size_t len, int flags) 951195972f6Sopenharmony_ci{ 952195972f6Sopenharmony_ci u8_t apiflags = NETCONN_NOAUTORCVD; 953195972f6Sopenharmony_ci ssize_t recvd = 0; 954195972f6Sopenharmony_ci ssize_t recv_left = (len <= SSIZE_MAX) ? (ssize_t)len : SSIZE_MAX; 955195972f6Sopenharmony_ci 956195972f6Sopenharmony_ci LWIP_ASSERT("no socket given", sock != NULL); 957195972f6Sopenharmony_ci LWIP_ASSERT("this should be checked internally", NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP); 958195972f6Sopenharmony_ci 959195972f6Sopenharmony_ci if (flags & MSG_DONTWAIT) { 960195972f6Sopenharmony_ci apiflags |= NETCONN_DONTBLOCK; 961195972f6Sopenharmony_ci } 962195972f6Sopenharmony_ci 963195972f6Sopenharmony_ci do { 964195972f6Sopenharmony_ci struct pbuf *p; 965195972f6Sopenharmony_ci err_t err; 966195972f6Sopenharmony_ci u16_t copylen; 967195972f6Sopenharmony_ci 968195972f6Sopenharmony_ci LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recv_tcp: top while sock->lastdata=%p\n", (void *)sock->lastdata.pbuf)); 969195972f6Sopenharmony_ci /* Check if there is data left from the last recv operation. */ 970195972f6Sopenharmony_ci if (sock->lastdata.pbuf) { 971195972f6Sopenharmony_ci p = sock->lastdata.pbuf; 972195972f6Sopenharmony_ci } else { 973195972f6Sopenharmony_ci /* No data was left from the previous operation, so we try to get 974195972f6Sopenharmony_ci some from the network. */ 975195972f6Sopenharmony_ci err = netconn_recv_tcp_pbuf_flags(sock->conn, &p, apiflags); 976195972f6Sopenharmony_ci LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recv_tcp: netconn_recv err=%d, pbuf=%p\n", 977195972f6Sopenharmony_ci err, (void *)p)); 978195972f6Sopenharmony_ci 979195972f6Sopenharmony_ci if (err != ERR_OK) { 980195972f6Sopenharmony_ci if (recvd > 0) { 981195972f6Sopenharmony_ci /* already received data, return that (this trusts in getting the same error from 982195972f6Sopenharmony_ci netconn layer again next time netconn_recv is called) */ 983195972f6Sopenharmony_ci goto lwip_recv_tcp_done; 984195972f6Sopenharmony_ci } 985195972f6Sopenharmony_ci /* We should really do some error checking here. */ 986195972f6Sopenharmony_ci LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recv_tcp: p == NULL, error is \"%s\"!\n", 987195972f6Sopenharmony_ci lwip_strerr(err))); 988195972f6Sopenharmony_ci sock_set_errno(sock, err_to_errno(err)); 989195972f6Sopenharmony_ci if (err == ERR_CLSD) { 990195972f6Sopenharmony_ci return 0; 991195972f6Sopenharmony_ci } else { 992195972f6Sopenharmony_ci return -1; 993195972f6Sopenharmony_ci } 994195972f6Sopenharmony_ci } 995195972f6Sopenharmony_ci LWIP_ASSERT("p != NULL", p != NULL); 996195972f6Sopenharmony_ci sock->lastdata.pbuf = p; 997195972f6Sopenharmony_ci } 998195972f6Sopenharmony_ci 999195972f6Sopenharmony_ci LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recv_tcp: buflen=%"U16_F" recv_left=%d off=%d\n", 1000195972f6Sopenharmony_ci p->tot_len, (int)recv_left, (int)recvd)); 1001195972f6Sopenharmony_ci 1002195972f6Sopenharmony_ci if (recv_left > p->tot_len) { 1003195972f6Sopenharmony_ci copylen = p->tot_len; 1004195972f6Sopenharmony_ci } else { 1005195972f6Sopenharmony_ci copylen = (u16_t)recv_left; 1006195972f6Sopenharmony_ci } 1007195972f6Sopenharmony_ci if (recvd + copylen < recvd) { 1008195972f6Sopenharmony_ci /* overflow */ 1009195972f6Sopenharmony_ci copylen = (u16_t)(SSIZE_MAX - recvd); 1010195972f6Sopenharmony_ci } 1011195972f6Sopenharmony_ci 1012195972f6Sopenharmony_ci /* copy the contents of the received buffer into 1013195972f6Sopenharmony_ci the supplied memory pointer mem */ 1014195972f6Sopenharmony_ci pbuf_copy_partial(p, (u8_t *)mem + recvd, copylen, 0); 1015195972f6Sopenharmony_ci 1016195972f6Sopenharmony_ci recvd += copylen; 1017195972f6Sopenharmony_ci 1018195972f6Sopenharmony_ci /* TCP combines multiple pbufs for one recv */ 1019195972f6Sopenharmony_ci LWIP_ASSERT("invalid copylen, len would underflow", recv_left >= copylen); 1020195972f6Sopenharmony_ci recv_left -= copylen; 1021195972f6Sopenharmony_ci 1022195972f6Sopenharmony_ci /* Unless we peek the incoming message... */ 1023195972f6Sopenharmony_ci if ((flags & MSG_PEEK) == 0) { 1024195972f6Sopenharmony_ci /* ... check if there is data left in the pbuf */ 1025195972f6Sopenharmony_ci LWIP_ASSERT("invalid copylen", p->tot_len >= copylen); 1026195972f6Sopenharmony_ci if (p->tot_len - copylen > 0) { 1027195972f6Sopenharmony_ci /* If so, it should be saved in the sock structure for the next recv call. 1028195972f6Sopenharmony_ci We store the pbuf but hide/free the consumed data: */ 1029195972f6Sopenharmony_ci sock->lastdata.pbuf = pbuf_free_header(p, copylen); 1030195972f6Sopenharmony_ci LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recv_tcp: lastdata now pbuf=%p\n", (void *)sock->lastdata.pbuf)); 1031195972f6Sopenharmony_ci } else { 1032195972f6Sopenharmony_ci sock->lastdata.pbuf = NULL; 1033195972f6Sopenharmony_ci LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recv_tcp: deleting pbuf=%p\n", (void *)p)); 1034195972f6Sopenharmony_ci pbuf_free(p); 1035195972f6Sopenharmony_ci } 1036195972f6Sopenharmony_ci } 1037195972f6Sopenharmony_ci /* once we have some data to return, only add more if we don't need to wait */ 1038195972f6Sopenharmony_ci apiflags |= NETCONN_DONTBLOCK | NETCONN_NOFIN; 1039195972f6Sopenharmony_ci /* @todo: do we need to support peeking more than one pbuf? */ 1040195972f6Sopenharmony_ci } while ((recv_left > 0) && !(flags & MSG_PEEK)); 1041195972f6Sopenharmony_cilwip_recv_tcp_done: 1042195972f6Sopenharmony_ci if ((recvd > 0) && !(flags & MSG_PEEK)) { 1043195972f6Sopenharmony_ci /* ensure window update after copying all data */ 1044195972f6Sopenharmony_ci netconn_tcp_recvd(sock->conn, (size_t)recvd); 1045195972f6Sopenharmony_ci } 1046195972f6Sopenharmony_ci sock_set_errno(sock, 0); 1047195972f6Sopenharmony_ci return recvd; 1048195972f6Sopenharmony_ci} 1049195972f6Sopenharmony_ci#endif 1050195972f6Sopenharmony_ci 1051195972f6Sopenharmony_ci/* Convert a netbuf's address data to struct sockaddr */ 1052195972f6Sopenharmony_cistatic int 1053195972f6Sopenharmony_cilwip_sock_make_addr(struct netconn *conn, ip_addr_t *fromaddr, u16_t port, 1054195972f6Sopenharmony_ci struct sockaddr *from, socklen_t *fromlen) 1055195972f6Sopenharmony_ci{ 1056195972f6Sopenharmony_ci int truncated = 0; 1057195972f6Sopenharmony_ci union sockaddr_aligned saddr; 1058195972f6Sopenharmony_ci 1059195972f6Sopenharmony_ci LWIP_UNUSED_ARG(conn); 1060195972f6Sopenharmony_ci 1061195972f6Sopenharmony_ci LWIP_ASSERT("fromaddr != NULL", fromaddr != NULL); 1062195972f6Sopenharmony_ci LWIP_ASSERT("from != NULL", from != NULL); 1063195972f6Sopenharmony_ci LWIP_ASSERT("fromlen != NULL", fromlen != NULL); 1064195972f6Sopenharmony_ci 1065195972f6Sopenharmony_ci#if LWIP_IPV4 && LWIP_IPV6 1066195972f6Sopenharmony_ci /* Dual-stack: Map IPv4 addresses to IPv4 mapped IPv6 */ 1067195972f6Sopenharmony_ci if (NETCONNTYPE_ISIPV6(netconn_type(conn)) && IP_IS_V4(fromaddr)) { 1068195972f6Sopenharmony_ci ip4_2_ipv4_mapped_ipv6(ip_2_ip6(fromaddr), ip_2_ip4(fromaddr)); 1069195972f6Sopenharmony_ci IP_SET_TYPE(fromaddr, IPADDR_TYPE_V6); 1070195972f6Sopenharmony_ci } 1071195972f6Sopenharmony_ci#endif /* LWIP_IPV4 && LWIP_IPV6 */ 1072195972f6Sopenharmony_ci 1073195972f6Sopenharmony_ci IPADDR_PORT_TO_SOCKADDR(&saddr, fromaddr, port); 1074195972f6Sopenharmony_ci DF_NADDR(*fromaddr); 1075195972f6Sopenharmony_ci if (*fromlen < saddr.sa.sa_len) { 1076195972f6Sopenharmony_ci truncated = 1; 1077195972f6Sopenharmony_ci } else if (*fromlen > saddr.sa.sa_len) { 1078195972f6Sopenharmony_ci *fromlen = saddr.sa.sa_len; 1079195972f6Sopenharmony_ci } 1080195972f6Sopenharmony_ci MEMCPY(from, &saddr, *fromlen); 1081195972f6Sopenharmony_ci return truncated; 1082195972f6Sopenharmony_ci} 1083195972f6Sopenharmony_ci 1084195972f6Sopenharmony_ci#if LWIP_TCP 1085195972f6Sopenharmony_ci/* Helper function to get a tcp socket's remote address info */ 1086195972f6Sopenharmony_cistatic int 1087195972f6Sopenharmony_cilwip_recv_tcp_from(struct lwip_sock *sock, struct sockaddr *from, socklen_t *fromlen, const char *dbg_fn, int dbg_s, ssize_t dbg_ret) 1088195972f6Sopenharmony_ci{ 1089195972f6Sopenharmony_ci if (sock == NULL) { 1090195972f6Sopenharmony_ci return 0; 1091195972f6Sopenharmony_ci } 1092195972f6Sopenharmony_ci LWIP_UNUSED_ARG(dbg_fn); 1093195972f6Sopenharmony_ci LWIP_UNUSED_ARG(dbg_s); 1094195972f6Sopenharmony_ci LWIP_UNUSED_ARG(dbg_ret); 1095195972f6Sopenharmony_ci 1096195972f6Sopenharmony_ci#if !SOCKETS_DEBUG 1097195972f6Sopenharmony_ci if (from && fromlen) 1098195972f6Sopenharmony_ci#endif /* !SOCKETS_DEBUG */ 1099195972f6Sopenharmony_ci { 1100195972f6Sopenharmony_ci /* get remote addr/port from tcp_pcb */ 1101195972f6Sopenharmony_ci u16_t port; 1102195972f6Sopenharmony_ci ip_addr_t tmpaddr; 1103195972f6Sopenharmony_ci err_t err = netconn_getaddr(sock->conn, &tmpaddr, &port, 0); 1104195972f6Sopenharmony_ci LWIP_DEBUGF(SOCKETS_DEBUG, ("%s(%d): addr=", dbg_fn, dbg_s)); 1105195972f6Sopenharmony_ci ip_addr_debug_print_val(SOCKETS_DEBUG, tmpaddr); 1106195972f6Sopenharmony_ci LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F" len=%d\n", port, (int)dbg_ret)); 1107195972f6Sopenharmony_ci if (!err && from && fromlen) { 1108195972f6Sopenharmony_ci return lwip_sock_make_addr(sock->conn, &tmpaddr, port, from, fromlen); 1109195972f6Sopenharmony_ci } 1110195972f6Sopenharmony_ci } 1111195972f6Sopenharmony_ci return 0; 1112195972f6Sopenharmony_ci} 1113195972f6Sopenharmony_ci#endif 1114195972f6Sopenharmony_ci 1115195972f6Sopenharmony_ci/* Helper function to receive a netbuf from a udp or raw netconn. 1116195972f6Sopenharmony_ci * Keeps sock->lastdata for peeking. 1117195972f6Sopenharmony_ci */ 1118195972f6Sopenharmony_cistatic err_t 1119195972f6Sopenharmony_cilwip_recvfrom_udp_raw(struct lwip_sock *sock, int flags, struct msghdr *msg, u16_t *datagram_len, int dbg_s) 1120195972f6Sopenharmony_ci{ 1121195972f6Sopenharmony_ci struct netbuf *buf; 1122195972f6Sopenharmony_ci u8_t apiflags; 1123195972f6Sopenharmony_ci err_t err; 1124195972f6Sopenharmony_ci u16_t buflen, copylen, copied; 1125195972f6Sopenharmony_ci int i; 1126195972f6Sopenharmony_ci 1127195972f6Sopenharmony_ci LWIP_UNUSED_ARG(dbg_s); 1128195972f6Sopenharmony_ci LWIP_ERROR("lwip_recvfrom_udp_raw: invalid arguments", (msg->msg_iov != NULL) || (msg->msg_iovlen <= 0), return ERR_ARG;); 1129195972f6Sopenharmony_ci 1130195972f6Sopenharmony_ci if (flags & MSG_DONTWAIT) { 1131195972f6Sopenharmony_ci apiflags = NETCONN_DONTBLOCK; 1132195972f6Sopenharmony_ci } else { 1133195972f6Sopenharmony_ci apiflags = 0; 1134195972f6Sopenharmony_ci } 1135195972f6Sopenharmony_ci 1136195972f6Sopenharmony_ci LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom_udp_raw[UDP/RAW]: top sock->lastdata=%p\n", (void *)sock->lastdata.netbuf)); 1137195972f6Sopenharmony_ci /* Check if there is data left from the last recv operation. */ 1138195972f6Sopenharmony_ci buf = sock->lastdata.netbuf; 1139195972f6Sopenharmony_ci if (buf == NULL) { 1140195972f6Sopenharmony_ci /* No data was left from the previous operation, so we try to get 1141195972f6Sopenharmony_ci some from the network. */ 1142195972f6Sopenharmony_ci err = netconn_recv_udp_raw_netbuf_flags(sock->conn, &buf, apiflags); 1143195972f6Sopenharmony_ci LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom_udp_raw[UDP/RAW]: netconn_recv err=%d, netbuf=%p\n", 1144195972f6Sopenharmony_ci err, (void *)buf)); 1145195972f6Sopenharmony_ci 1146195972f6Sopenharmony_ci if (err != ERR_OK) { 1147195972f6Sopenharmony_ci return err; 1148195972f6Sopenharmony_ci } 1149195972f6Sopenharmony_ci LWIP_ASSERT("buf != NULL", buf != NULL); 1150195972f6Sopenharmony_ci sock->lastdata.netbuf = buf; 1151195972f6Sopenharmony_ci } 1152195972f6Sopenharmony_ci buflen = buf->p->tot_len; 1153195972f6Sopenharmony_ci LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom_udp_raw: buflen=%"U16_F"\n", buflen)); 1154195972f6Sopenharmony_ci 1155195972f6Sopenharmony_ci copied = 0; 1156195972f6Sopenharmony_ci /* copy the pbuf payload into the iovs */ 1157195972f6Sopenharmony_ci for (i = 0; (i < msg->msg_iovlen) && (copied < buflen); i++) { 1158195972f6Sopenharmony_ci u16_t len_left = (u16_t)(buflen - copied); 1159195972f6Sopenharmony_ci if (msg->msg_iov[i].iov_len > len_left) { 1160195972f6Sopenharmony_ci copylen = len_left; 1161195972f6Sopenharmony_ci } else { 1162195972f6Sopenharmony_ci copylen = (u16_t)msg->msg_iov[i].iov_len; 1163195972f6Sopenharmony_ci } 1164195972f6Sopenharmony_ci 1165195972f6Sopenharmony_ci /* copy the contents of the received buffer into 1166195972f6Sopenharmony_ci the supplied memory buffer */ 1167195972f6Sopenharmony_ci pbuf_copy_partial(buf->p, (u8_t *)msg->msg_iov[i].iov_base, copylen, copied); 1168195972f6Sopenharmony_ci copied = (u16_t)(copied + copylen); 1169195972f6Sopenharmony_ci } 1170195972f6Sopenharmony_ci 1171195972f6Sopenharmony_ci /* Check to see from where the data was.*/ 1172195972f6Sopenharmony_ci#if !SOCKETS_DEBUG 1173195972f6Sopenharmony_ci if (msg->msg_name && msg->msg_namelen) 1174195972f6Sopenharmony_ci#endif /* !SOCKETS_DEBUG */ 1175195972f6Sopenharmony_ci { 1176195972f6Sopenharmony_ci LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom_udp_raw(%d): addr=", dbg_s)); 1177195972f6Sopenharmony_ci ip_addr_debug_print_val(SOCKETS_DEBUG, *netbuf_fromaddr(buf)); 1178195972f6Sopenharmony_ci LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F" len=%d\n", netbuf_fromport(buf), copied)); 1179195972f6Sopenharmony_ci if (msg->msg_name && msg->msg_namelen) { 1180195972f6Sopenharmony_ci lwip_sock_make_addr(sock->conn, netbuf_fromaddr(buf), netbuf_fromport(buf), 1181195972f6Sopenharmony_ci (struct sockaddr *)msg->msg_name, &msg->msg_namelen); 1182195972f6Sopenharmony_ci } 1183195972f6Sopenharmony_ci } 1184195972f6Sopenharmony_ci 1185195972f6Sopenharmony_ci /* Initialize flag output */ 1186195972f6Sopenharmony_ci msg->msg_flags = 0; 1187195972f6Sopenharmony_ci 1188195972f6Sopenharmony_ci if (msg->msg_control) { 1189195972f6Sopenharmony_ci u8_t wrote_msg = 0; 1190195972f6Sopenharmony_ci#if LWIP_NETBUF_RECVINFO 1191195972f6Sopenharmony_ci /* Check if packet info was recorded */ 1192195972f6Sopenharmony_ci if (buf->flags & NETBUF_FLAG_DESTADDR) { 1193195972f6Sopenharmony_ci if (IP_IS_V4(&buf->toaddr)) { 1194195972f6Sopenharmony_ci#if LWIP_IPV4 1195195972f6Sopenharmony_ci if (msg->msg_controllen >= CMSG_SPACE(sizeof(struct in_pktinfo))) { 1196195972f6Sopenharmony_ci struct cmsghdr *chdr = CMSG_FIRSTHDR(msg); /* This will always return a header!! */ 1197195972f6Sopenharmony_ci struct in_pktinfo *pkti = (struct in_pktinfo *)CMSG_DATA(chdr); 1198195972f6Sopenharmony_ci chdr->cmsg_level = IPPROTO_IP; 1199195972f6Sopenharmony_ci chdr->cmsg_type = IP_PKTINFO; 1200195972f6Sopenharmony_ci chdr->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo)); 1201195972f6Sopenharmony_ci pkti->ipi_ifindex = buf->p->if_idx; 1202195972f6Sopenharmony_ci inet_addr_from_ip4addr(&pkti->ipi_addr, ip_2_ip4(netbuf_destaddr(buf))); 1203195972f6Sopenharmony_ci msg->msg_controllen = CMSG_SPACE(sizeof(struct in_pktinfo)); 1204195972f6Sopenharmony_ci wrote_msg = 1; 1205195972f6Sopenharmony_ci } else { 1206195972f6Sopenharmony_ci msg->msg_flags |= MSG_CTRUNC; 1207195972f6Sopenharmony_ci } 1208195972f6Sopenharmony_ci#endif /* LWIP_IPV4 */ 1209195972f6Sopenharmony_ci } 1210195972f6Sopenharmony_ci } 1211195972f6Sopenharmony_ci#endif /* LWIP_NETBUF_RECVINFO */ 1212195972f6Sopenharmony_ci 1213195972f6Sopenharmony_ci if (!wrote_msg) { 1214195972f6Sopenharmony_ci msg->msg_controllen = 0; 1215195972f6Sopenharmony_ci } 1216195972f6Sopenharmony_ci } 1217195972f6Sopenharmony_ci 1218195972f6Sopenharmony_ci /* If we don't peek the incoming message: zero lastdata pointer and free the netbuf */ 1219195972f6Sopenharmony_ci if ((flags & MSG_PEEK) == 0) { 1220195972f6Sopenharmony_ci sock->lastdata.netbuf = NULL; 1221195972f6Sopenharmony_ci netbuf_delete(buf); 1222195972f6Sopenharmony_ci } 1223195972f6Sopenharmony_ci if (datagram_len) { 1224195972f6Sopenharmony_ci *datagram_len = buflen; 1225195972f6Sopenharmony_ci } 1226195972f6Sopenharmony_ci return ERR_OK; 1227195972f6Sopenharmony_ci} 1228195972f6Sopenharmony_ci 1229195972f6Sopenharmony_cissize_t 1230195972f6Sopenharmony_cilwip_recvfrom(int s, void *mem, size_t len, int flags, 1231195972f6Sopenharmony_ci struct sockaddr *from, socklen_t *fromlen) 1232195972f6Sopenharmony_ci{ 1233195972f6Sopenharmony_ci#if LWIP_ENABLE_DISTRIBUTED_NET && LWIP_USE_GET_HOST_BY_NAME_EXTERNAL 1234195972f6Sopenharmony_ci if (!is_distributed_net_enabled()) { 1235195972f6Sopenharmony_ci return lwip_recvfrom_internal(s, mem, len, flags, from, fromlen); 1236195972f6Sopenharmony_ci } 1237195972f6Sopenharmony_ci return distributed_net_recvfrom(s, mem, len, flags, from, fromlen); 1238195972f6Sopenharmony_ci} 1239195972f6Sopenharmony_ci 1240195972f6Sopenharmony_cissize_t 1241195972f6Sopenharmony_cilwip_recvfrom_internal(int s, void *mem, size_t len, int flags, 1242195972f6Sopenharmony_ci struct sockaddr *from, socklen_t *fromlen) 1243195972f6Sopenharmony_ci{ 1244195972f6Sopenharmony_ci#endif 1245195972f6Sopenharmony_ci struct lwip_sock *sock; 1246195972f6Sopenharmony_ci ssize_t ret; 1247195972f6Sopenharmony_ci 1248195972f6Sopenharmony_ci LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d, %p, %"SZT_F", 0x%x, ..)\n", s, mem, len, flags)); 1249195972f6Sopenharmony_ci sock = get_socket(s); 1250195972f6Sopenharmony_ci if (!sock) { 1251195972f6Sopenharmony_ci return -1; 1252195972f6Sopenharmony_ci } 1253195972f6Sopenharmony_ci#if LWIP_TCP 1254195972f6Sopenharmony_ci if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) { 1255195972f6Sopenharmony_ci ret = lwip_recv_tcp(sock, mem, len, flags); 1256195972f6Sopenharmony_ci lwip_recv_tcp_from(sock, from, fromlen, "lwip_recvfrom", s, ret); 1257195972f6Sopenharmony_ci done_socket(sock); 1258195972f6Sopenharmony_ci return ret; 1259195972f6Sopenharmony_ci } else 1260195972f6Sopenharmony_ci#endif 1261195972f6Sopenharmony_ci { 1262195972f6Sopenharmony_ci u16_t datagram_len = 0; 1263195972f6Sopenharmony_ci struct iovec vec; 1264195972f6Sopenharmony_ci struct msghdr msg; 1265195972f6Sopenharmony_ci err_t err; 1266195972f6Sopenharmony_ci vec.iov_base = mem; 1267195972f6Sopenharmony_ci vec.iov_len = len; 1268195972f6Sopenharmony_ci msg.msg_control = NULL; 1269195972f6Sopenharmony_ci msg.msg_controllen = 0; 1270195972f6Sopenharmony_ci msg.msg_flags = 0; 1271195972f6Sopenharmony_ci msg.msg_iov = &vec; 1272195972f6Sopenharmony_ci msg.msg_iovlen = 1; 1273195972f6Sopenharmony_ci msg.msg_name = from; 1274195972f6Sopenharmony_ci msg.msg_namelen = (fromlen ? *fromlen : 0); 1275195972f6Sopenharmony_ci err = lwip_recvfrom_udp_raw(sock, flags, &msg, &datagram_len, s); 1276195972f6Sopenharmony_ci if (err != ERR_OK) { 1277195972f6Sopenharmony_ci LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom[UDP/RAW](%d): buf == NULL, error is \"%s\"!\n", 1278195972f6Sopenharmony_ci s, lwip_strerr(err))); 1279195972f6Sopenharmony_ci sock_set_errno(sock, err_to_errno(err)); 1280195972f6Sopenharmony_ci done_socket(sock); 1281195972f6Sopenharmony_ci return -1; 1282195972f6Sopenharmony_ci } 1283195972f6Sopenharmony_ci ret = (ssize_t)LWIP_MIN(LWIP_MIN(len, datagram_len), SSIZE_MAX); 1284195972f6Sopenharmony_ci if (fromlen) { 1285195972f6Sopenharmony_ci *fromlen = msg.msg_namelen; 1286195972f6Sopenharmony_ci } 1287195972f6Sopenharmony_ci } 1288195972f6Sopenharmony_ci 1289195972f6Sopenharmony_ci sock_set_errno(sock, 0); 1290195972f6Sopenharmony_ci done_socket(sock); 1291195972f6Sopenharmony_ci return ret; 1292195972f6Sopenharmony_ci} 1293195972f6Sopenharmony_ci 1294195972f6Sopenharmony_cissize_t 1295195972f6Sopenharmony_cilwip_read(int s, void *mem, size_t len) 1296195972f6Sopenharmony_ci{ 1297195972f6Sopenharmony_ci return lwip_recvfrom(s, mem, len, 0, NULL, NULL); 1298195972f6Sopenharmony_ci} 1299195972f6Sopenharmony_ci 1300195972f6Sopenharmony_cissize_t 1301195972f6Sopenharmony_cilwip_readv(int s, const struct iovec *iov, int iovcnt) 1302195972f6Sopenharmony_ci{ 1303195972f6Sopenharmony_ci struct msghdr msg; 1304195972f6Sopenharmony_ci 1305195972f6Sopenharmony_ci msg.msg_name = NULL; 1306195972f6Sopenharmony_ci msg.msg_namelen = 0; 1307195972f6Sopenharmony_ci /* Hack: we have to cast via number to cast from 'const' pointer to non-const. 1308195972f6Sopenharmony_ci Blame the opengroup standard for this inconsistency. */ 1309195972f6Sopenharmony_ci msg.msg_iov = LWIP_CONST_CAST(struct iovec *, iov); 1310195972f6Sopenharmony_ci msg.msg_iovlen = iovcnt; 1311195972f6Sopenharmony_ci msg.msg_control = NULL; 1312195972f6Sopenharmony_ci msg.msg_controllen = 0; 1313195972f6Sopenharmony_ci msg.msg_flags = 0; 1314195972f6Sopenharmony_ci return lwip_recvmsg(s, &msg, 0); 1315195972f6Sopenharmony_ci} 1316195972f6Sopenharmony_ci 1317195972f6Sopenharmony_cissize_t 1318195972f6Sopenharmony_cilwip_recv(int s, void *mem, size_t len, int flags) 1319195972f6Sopenharmony_ci{ 1320195972f6Sopenharmony_ci return lwip_recvfrom(s, mem, len, flags, NULL, NULL); 1321195972f6Sopenharmony_ci} 1322195972f6Sopenharmony_ci 1323195972f6Sopenharmony_cissize_t 1324195972f6Sopenharmony_cilwip_recvmsg(int s, struct msghdr *message, int flags) 1325195972f6Sopenharmony_ci{ 1326195972f6Sopenharmony_ci struct lwip_sock *sock; 1327195972f6Sopenharmony_ci int i; 1328195972f6Sopenharmony_ci ssize_t buflen; 1329195972f6Sopenharmony_ci 1330195972f6Sopenharmony_ci LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvmsg(%d, message=%p, flags=0x%x)\n", s, (void *)message, flags)); 1331195972f6Sopenharmony_ci LWIP_ERROR("lwip_recvmsg: invalid message pointer", message != NULL, return ERR_ARG;); 1332195972f6Sopenharmony_ci LWIP_ERROR("lwip_recvmsg: unsupported flags", (flags & ~(MSG_PEEK|MSG_DONTWAIT)) == 0, 1333195972f6Sopenharmony_ci set_errno(EOPNOTSUPP); return -1;); 1334195972f6Sopenharmony_ci 1335195972f6Sopenharmony_ci if ((message->msg_iovlen <= 0) || (message->msg_iovlen > IOV_MAX)) { 1336195972f6Sopenharmony_ci set_errno(EMSGSIZE); 1337195972f6Sopenharmony_ci return -1; 1338195972f6Sopenharmony_ci } 1339195972f6Sopenharmony_ci 1340195972f6Sopenharmony_ci sock = get_socket(s); 1341195972f6Sopenharmony_ci if (!sock) { 1342195972f6Sopenharmony_ci return -1; 1343195972f6Sopenharmony_ci } 1344195972f6Sopenharmony_ci 1345195972f6Sopenharmony_ci /* check for valid vectors */ 1346195972f6Sopenharmony_ci buflen = 0; 1347195972f6Sopenharmony_ci for (i = 0; i < message->msg_iovlen; i++) { 1348195972f6Sopenharmony_ci if ((message->msg_iov[i].iov_base == NULL) || ((ssize_t)message->msg_iov[i].iov_len <= 0) || 1349195972f6Sopenharmony_ci ((size_t)(ssize_t)message->msg_iov[i].iov_len != message->msg_iov[i].iov_len) || 1350195972f6Sopenharmony_ci ((ssize_t)(buflen + (ssize_t)message->msg_iov[i].iov_len) <= 0)) { 1351195972f6Sopenharmony_ci sock_set_errno(sock, err_to_errno(ERR_VAL)); 1352195972f6Sopenharmony_ci done_socket(sock); 1353195972f6Sopenharmony_ci return -1; 1354195972f6Sopenharmony_ci } 1355195972f6Sopenharmony_ci buflen = (ssize_t)(buflen + (ssize_t)message->msg_iov[i].iov_len); 1356195972f6Sopenharmony_ci } 1357195972f6Sopenharmony_ci 1358195972f6Sopenharmony_ci if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) { 1359195972f6Sopenharmony_ci#if LWIP_TCP 1360195972f6Sopenharmony_ci int recv_flags = flags; 1361195972f6Sopenharmony_ci message->msg_flags = 0; 1362195972f6Sopenharmony_ci /* recv the data */ 1363195972f6Sopenharmony_ci buflen = 0; 1364195972f6Sopenharmony_ci for (i = 0; i < message->msg_iovlen; i++) { 1365195972f6Sopenharmony_ci /* try to receive into this vector's buffer */ 1366195972f6Sopenharmony_ci ssize_t recvd_local = lwip_recv_tcp(sock, message->msg_iov[i].iov_base, message->msg_iov[i].iov_len, recv_flags); 1367195972f6Sopenharmony_ci if (recvd_local > 0) { 1368195972f6Sopenharmony_ci /* sum up received bytes */ 1369195972f6Sopenharmony_ci buflen += recvd_local; 1370195972f6Sopenharmony_ci } 1371195972f6Sopenharmony_ci if ((recvd_local < 0) || (recvd_local < (int)message->msg_iov[i].iov_len) || 1372195972f6Sopenharmony_ci (flags & MSG_PEEK)) { 1373195972f6Sopenharmony_ci /* returned prematurely (or peeking, which might actually be limitated to the first iov) */ 1374195972f6Sopenharmony_ci if (buflen <= 0) { 1375195972f6Sopenharmony_ci /* nothing received at all, propagate the error */ 1376195972f6Sopenharmony_ci buflen = recvd_local; 1377195972f6Sopenharmony_ci } 1378195972f6Sopenharmony_ci break; 1379195972f6Sopenharmony_ci } 1380195972f6Sopenharmony_ci /* pass MSG_DONTWAIT to lwip_recv_tcp() to prevent waiting for more data */ 1381195972f6Sopenharmony_ci recv_flags |= MSG_DONTWAIT; 1382195972f6Sopenharmony_ci } 1383195972f6Sopenharmony_ci if (buflen > 0) { 1384195972f6Sopenharmony_ci /* reset socket error since we have received something */ 1385195972f6Sopenharmony_ci sock_set_errno(sock, 0); 1386195972f6Sopenharmony_ci } 1387195972f6Sopenharmony_ci /* " If the socket is connected, the msg_name and msg_namelen members shall be ignored." */ 1388195972f6Sopenharmony_ci done_socket(sock); 1389195972f6Sopenharmony_ci return buflen; 1390195972f6Sopenharmony_ci#else /* LWIP_TCP */ 1391195972f6Sopenharmony_ci sock_set_errno(sock, err_to_errno(ERR_ARG)); 1392195972f6Sopenharmony_ci done_socket(sock); 1393195972f6Sopenharmony_ci return -1; 1394195972f6Sopenharmony_ci#endif /* LWIP_TCP */ 1395195972f6Sopenharmony_ci } 1396195972f6Sopenharmony_ci /* else, UDP and RAW NETCONNs */ 1397195972f6Sopenharmony_ci#if LWIP_UDP || LWIP_RAW 1398195972f6Sopenharmony_ci { 1399195972f6Sopenharmony_ci u16_t datagram_len = 0; 1400195972f6Sopenharmony_ci err_t err; 1401195972f6Sopenharmony_ci err = lwip_recvfrom_udp_raw(sock, flags, message, &datagram_len, s); 1402195972f6Sopenharmony_ci if (err != ERR_OK) { 1403195972f6Sopenharmony_ci LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvmsg[UDP/RAW](%d): buf == NULL, error is \"%s\"!\n", 1404195972f6Sopenharmony_ci s, lwip_strerr(err))); 1405195972f6Sopenharmony_ci sock_set_errno(sock, err_to_errno(err)); 1406195972f6Sopenharmony_ci done_socket(sock); 1407195972f6Sopenharmony_ci return -1; 1408195972f6Sopenharmony_ci } 1409195972f6Sopenharmony_ci if (datagram_len > buflen) { 1410195972f6Sopenharmony_ci message->msg_flags |= MSG_TRUNC; 1411195972f6Sopenharmony_ci } 1412195972f6Sopenharmony_ci 1413195972f6Sopenharmony_ci sock_set_errno(sock, 0); 1414195972f6Sopenharmony_ci done_socket(sock); 1415195972f6Sopenharmony_ci return (int)datagram_len; 1416195972f6Sopenharmony_ci } 1417195972f6Sopenharmony_ci#else /* LWIP_UDP || LWIP_RAW */ 1418195972f6Sopenharmony_ci sock_set_errno(sock, err_to_errno(ERR_ARG)); 1419195972f6Sopenharmony_ci done_socket(sock); 1420195972f6Sopenharmony_ci return -1; 1421195972f6Sopenharmony_ci#endif /* LWIP_UDP || LWIP_RAW */ 1422195972f6Sopenharmony_ci} 1423195972f6Sopenharmony_ci 1424195972f6Sopenharmony_cissize_t 1425195972f6Sopenharmony_cilwip_send(int s, const void *data, size_t size, int flags) 1426195972f6Sopenharmony_ci{ 1427195972f6Sopenharmony_ci struct lwip_sock *sock; 1428195972f6Sopenharmony_ci err_t err; 1429195972f6Sopenharmony_ci u8_t write_flags; 1430195972f6Sopenharmony_ci size_t written; 1431195972f6Sopenharmony_ci 1432195972f6Sopenharmony_ci LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_send(%d, data=%p, size=%"SZT_F", flags=0x%x)\n", 1433195972f6Sopenharmony_ci s, data, size, flags)); 1434195972f6Sopenharmony_ci 1435195972f6Sopenharmony_ci sock = get_socket(s); 1436195972f6Sopenharmony_ci if (!sock) { 1437195972f6Sopenharmony_ci return -1; 1438195972f6Sopenharmony_ci } 1439195972f6Sopenharmony_ci 1440195972f6Sopenharmony_ci if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_TCP) { 1441195972f6Sopenharmony_ci#if (LWIP_UDP || LWIP_RAW) 1442195972f6Sopenharmony_ci done_socket(sock); 1443195972f6Sopenharmony_ci#if LWIP_ENABLE_DISTRIBUTED_NET && LWIP_USE_GET_HOST_BY_NAME_EXTERNAL 1444195972f6Sopenharmony_ci return lwip_sendto_internal(s, data, size, flags, NULL, 0); 1445195972f6Sopenharmony_ci#else 1446195972f6Sopenharmony_ci return lwip_sendto(s, data, size, flags, NULL, 0); 1447195972f6Sopenharmony_ci#endif 1448195972f6Sopenharmony_ci#else /* (LWIP_UDP || LWIP_RAW) */ 1449195972f6Sopenharmony_ci sock_set_errno(sock, err_to_errno(ERR_ARG)); 1450195972f6Sopenharmony_ci done_socket(sock); 1451195972f6Sopenharmony_ci return -1; 1452195972f6Sopenharmony_ci#endif /* (LWIP_UDP || LWIP_RAW) */ 1453195972f6Sopenharmony_ci } 1454195972f6Sopenharmony_ci 1455195972f6Sopenharmony_ci write_flags = (u8_t)(NETCONN_COPY | 1456195972f6Sopenharmony_ci ((flags & MSG_MORE) ? NETCONN_MORE : 0) | 1457195972f6Sopenharmony_ci ((flags & MSG_DONTWAIT) ? NETCONN_DONTBLOCK : 0)); 1458195972f6Sopenharmony_ci written = 0; 1459195972f6Sopenharmony_ci err = netconn_write_partly(sock->conn, data, size, write_flags, &written); 1460195972f6Sopenharmony_ci 1461195972f6Sopenharmony_ci LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_send(%d) err=%d written=%"SZT_F"\n", s, err, written)); 1462195972f6Sopenharmony_ci sock_set_errno(sock, err_to_errno(err)); 1463195972f6Sopenharmony_ci done_socket(sock); 1464195972f6Sopenharmony_ci /* casting 'written' to ssize_t is OK here since the netconn API limits it to SSIZE_MAX */ 1465195972f6Sopenharmony_ci return (err == ERR_OK ? (ssize_t)written : -1); 1466195972f6Sopenharmony_ci} 1467195972f6Sopenharmony_ci 1468195972f6Sopenharmony_cissize_t 1469195972f6Sopenharmony_cilwip_sendmsg(int s, const struct msghdr *msg, int flags) 1470195972f6Sopenharmony_ci{ 1471195972f6Sopenharmony_ci#if LWIP_ENABLE_DISTRIBUTED_NET && LWIP_USE_GET_HOST_BY_NAME_EXTERNAL && LWIP_DISTRIBUTED_NET_ENABLE_SENDMSG 1472195972f6Sopenharmony_ci if (!is_distributed_net_enabled()) { 1473195972f6Sopenharmony_ci return lwip_sendmsg_internal(s, msg, flags); 1474195972f6Sopenharmony_ci } 1475195972f6Sopenharmony_ci return distributed_net_sendmsg(s, msg, flags); 1476195972f6Sopenharmony_ci} 1477195972f6Sopenharmony_ci 1478195972f6Sopenharmony_cissize_t 1479195972f6Sopenharmony_cilwip_sendmsg_internal(int s, const struct msghdr *msg, int flags) 1480195972f6Sopenharmony_ci{ 1481195972f6Sopenharmony_ci#endif 1482195972f6Sopenharmony_ci struct lwip_sock *sock; 1483195972f6Sopenharmony_ci#if LWIP_TCP 1484195972f6Sopenharmony_ci u8_t write_flags; 1485195972f6Sopenharmony_ci size_t written; 1486195972f6Sopenharmony_ci#endif 1487195972f6Sopenharmony_ci err_t err = ERR_OK; 1488195972f6Sopenharmony_ci 1489195972f6Sopenharmony_ci sock = get_socket(s); 1490195972f6Sopenharmony_ci if (!sock) { 1491195972f6Sopenharmony_ci return -1; 1492195972f6Sopenharmony_ci } 1493195972f6Sopenharmony_ci 1494195972f6Sopenharmony_ci LWIP_ERROR("lwip_sendmsg: invalid msghdr", msg != NULL, 1495195972f6Sopenharmony_ci sock_set_errno(sock, err_to_errno(ERR_ARG)); done_socket(sock); return -1;); 1496195972f6Sopenharmony_ci LWIP_ERROR("lwip_sendmsg: invalid msghdr iov", msg->msg_iov != NULL, 1497195972f6Sopenharmony_ci sock_set_errno(sock, err_to_errno(ERR_ARG)); done_socket(sock); return -1;); 1498195972f6Sopenharmony_ci LWIP_ERROR("lwip_sendmsg: maximum iovs exceeded", (msg->msg_iovlen > 0) && (msg->msg_iovlen <= IOV_MAX), 1499195972f6Sopenharmony_ci sock_set_errno(sock, EMSGSIZE); done_socket(sock); return -1;); 1500195972f6Sopenharmony_ci LWIP_ERROR("lwip_sendmsg: unsupported flags", (flags & ~(MSG_DONTWAIT | MSG_MORE)) == 0, 1501195972f6Sopenharmony_ci sock_set_errno(sock, EOPNOTSUPP); done_socket(sock); return -1;); 1502195972f6Sopenharmony_ci 1503195972f6Sopenharmony_ci LWIP_UNUSED_ARG(msg->msg_control); 1504195972f6Sopenharmony_ci LWIP_UNUSED_ARG(msg->msg_controllen); 1505195972f6Sopenharmony_ci LWIP_UNUSED_ARG(msg->msg_flags); 1506195972f6Sopenharmony_ci 1507195972f6Sopenharmony_ci if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) { 1508195972f6Sopenharmony_ci#if LWIP_TCP 1509195972f6Sopenharmony_ci write_flags = (u8_t)(NETCONN_COPY | 1510195972f6Sopenharmony_ci ((flags & MSG_MORE) ? NETCONN_MORE : 0) | 1511195972f6Sopenharmony_ci ((flags & MSG_DONTWAIT) ? NETCONN_DONTBLOCK : 0)); 1512195972f6Sopenharmony_ci 1513195972f6Sopenharmony_ci written = 0; 1514195972f6Sopenharmony_ci err = netconn_write_vectors_partly(sock->conn, (struct netvector *)msg->msg_iov, (u16_t)msg->msg_iovlen, write_flags, &written); 1515195972f6Sopenharmony_ci sock_set_errno(sock, err_to_errno(err)); 1516195972f6Sopenharmony_ci done_socket(sock); 1517195972f6Sopenharmony_ci /* casting 'written' to ssize_t is OK here since the netconn API limits it to SSIZE_MAX */ 1518195972f6Sopenharmony_ci return (err == ERR_OK ? (ssize_t)written : -1); 1519195972f6Sopenharmony_ci#else /* LWIP_TCP */ 1520195972f6Sopenharmony_ci sock_set_errno(sock, err_to_errno(ERR_ARG)); 1521195972f6Sopenharmony_ci done_socket(sock); 1522195972f6Sopenharmony_ci return -1; 1523195972f6Sopenharmony_ci#endif /* LWIP_TCP */ 1524195972f6Sopenharmony_ci } 1525195972f6Sopenharmony_ci /* else, UDP and RAW NETCONNs */ 1526195972f6Sopenharmony_ci#if LWIP_UDP || LWIP_RAW 1527195972f6Sopenharmony_ci { 1528195972f6Sopenharmony_ci struct netbuf chain_buf; 1529195972f6Sopenharmony_ci int i; 1530195972f6Sopenharmony_ci ssize_t size = 0; 1531195972f6Sopenharmony_ci 1532195972f6Sopenharmony_ci LWIP_UNUSED_ARG(flags); 1533195972f6Sopenharmony_ci LWIP_ERROR("lwip_sendmsg: invalid msghdr name", (((msg->msg_name == NULL) && (msg->msg_namelen == 0)) || 1534195972f6Sopenharmony_ci IS_SOCK_ADDR_LEN_VALID(msg->msg_namelen)), 1535195972f6Sopenharmony_ci sock_set_errno(sock, err_to_errno(ERR_ARG)); done_socket(sock); return -1;); 1536195972f6Sopenharmony_ci 1537195972f6Sopenharmony_ci /* initialize chain buffer with destination */ 1538195972f6Sopenharmony_ci memset(&chain_buf, 0, sizeof(struct netbuf)); 1539195972f6Sopenharmony_ci if (msg->msg_name) { 1540195972f6Sopenharmony_ci u16_t remote_port; 1541195972f6Sopenharmony_ci SOCKADDR_TO_IPADDR_PORT((const struct sockaddr *)msg->msg_name, &chain_buf.addr, remote_port); 1542195972f6Sopenharmony_ci netbuf_fromport(&chain_buf) = remote_port; 1543195972f6Sopenharmony_ci } 1544195972f6Sopenharmony_ci#if LWIP_NETIF_TX_SINGLE_PBUF 1545195972f6Sopenharmony_ci for (i = 0; i < msg->msg_iovlen; i++) { 1546195972f6Sopenharmony_ci size += msg->msg_iov[i].iov_len; 1547195972f6Sopenharmony_ci if ((msg->msg_iov[i].iov_len > INT_MAX) || (size < (int)msg->msg_iov[i].iov_len)) { 1548195972f6Sopenharmony_ci /* overflow */ 1549195972f6Sopenharmony_ci goto sendmsg_emsgsize; 1550195972f6Sopenharmony_ci } 1551195972f6Sopenharmony_ci } 1552195972f6Sopenharmony_ci if (size > 0xFFFF) { 1553195972f6Sopenharmony_ci /* overflow */ 1554195972f6Sopenharmony_ci goto sendmsg_emsgsize; 1555195972f6Sopenharmony_ci } 1556195972f6Sopenharmony_ci /* Allocate a new netbuf and copy the data into it. */ 1557195972f6Sopenharmony_ci if (netbuf_alloc(&chain_buf, (u16_t)size) == NULL) { 1558195972f6Sopenharmony_ci err = ERR_MEM; 1559195972f6Sopenharmony_ci } else { 1560195972f6Sopenharmony_ci /* flatten the IO vectors */ 1561195972f6Sopenharmony_ci size_t offset = 0; 1562195972f6Sopenharmony_ci for (i = 0; i < msg->msg_iovlen; i++) { 1563195972f6Sopenharmony_ci MEMCPY(&((u8_t *)chain_buf.p->payload)[offset], msg->msg_iov[i].iov_base, msg->msg_iov[i].iov_len); 1564195972f6Sopenharmony_ci offset += msg->msg_iov[i].iov_len; 1565195972f6Sopenharmony_ci } 1566195972f6Sopenharmony_ci#if LWIP_CHECKSUM_ON_COPY 1567195972f6Sopenharmony_ci { 1568195972f6Sopenharmony_ci /* This can be improved by using LWIP_CHKSUM_COPY() and aggregating the checksum for each IO vector */ 1569195972f6Sopenharmony_ci u16_t chksum = ~inet_chksum_pbuf(chain_buf.p); 1570195972f6Sopenharmony_ci netbuf_set_chksum(&chain_buf, chksum); 1571195972f6Sopenharmony_ci } 1572195972f6Sopenharmony_ci#endif /* LWIP_CHECKSUM_ON_COPY */ 1573195972f6Sopenharmony_ci err = ERR_OK; 1574195972f6Sopenharmony_ci } 1575195972f6Sopenharmony_ci#else /* LWIP_NETIF_TX_SINGLE_PBUF */ 1576195972f6Sopenharmony_ci /* create a chained netbuf from the IO vectors. NOTE: we assemble a pbuf chain 1577195972f6Sopenharmony_ci manually to avoid having to allocate, chain, and delete a netbuf for each iov */ 1578195972f6Sopenharmony_ci for (i = 0; i < msg->msg_iovlen; i++) { 1579195972f6Sopenharmony_ci struct pbuf *p; 1580195972f6Sopenharmony_ci if (msg->msg_iov[i].iov_len > 0xFFFF) { 1581195972f6Sopenharmony_ci /* overflow */ 1582195972f6Sopenharmony_ci goto sendmsg_emsgsize; 1583195972f6Sopenharmony_ci } 1584195972f6Sopenharmony_ci p = pbuf_alloc(PBUF_TRANSPORT, 0, PBUF_REF); 1585195972f6Sopenharmony_ci if (p == NULL) { 1586195972f6Sopenharmony_ci err = ERR_MEM; /* let netbuf_delete() cleanup chain_buf */ 1587195972f6Sopenharmony_ci break; 1588195972f6Sopenharmony_ci } 1589195972f6Sopenharmony_ci p->payload = msg->msg_iov[i].iov_base; 1590195972f6Sopenharmony_ci p->len = p->tot_len = (u16_t)msg->msg_iov[i].iov_len; 1591195972f6Sopenharmony_ci /* netbuf empty, add new pbuf */ 1592195972f6Sopenharmony_ci if (chain_buf.p == NULL) { 1593195972f6Sopenharmony_ci chain_buf.p = chain_buf.ptr = p; 1594195972f6Sopenharmony_ci /* add pbuf to existing pbuf chain */ 1595195972f6Sopenharmony_ci } else { 1596195972f6Sopenharmony_ci if (chain_buf.p->tot_len + p->len > 0xffff) { 1597195972f6Sopenharmony_ci /* overflow */ 1598195972f6Sopenharmony_ci pbuf_free(p); 1599195972f6Sopenharmony_ci goto sendmsg_emsgsize; 1600195972f6Sopenharmony_ci } 1601195972f6Sopenharmony_ci pbuf_cat(chain_buf.p, p); 1602195972f6Sopenharmony_ci } 1603195972f6Sopenharmony_ci } 1604195972f6Sopenharmony_ci /* save size of total chain */ 1605195972f6Sopenharmony_ci if (err == ERR_OK) { 1606195972f6Sopenharmony_ci size = netbuf_len(&chain_buf); 1607195972f6Sopenharmony_ci } 1608195972f6Sopenharmony_ci#endif /* LWIP_NETIF_TX_SINGLE_PBUF */ 1609195972f6Sopenharmony_ci 1610195972f6Sopenharmony_ci if (err == ERR_OK) { 1611195972f6Sopenharmony_ci#if LWIP_IPV4 && LWIP_IPV6 1612195972f6Sopenharmony_ci /* Dual-stack: Unmap IPv4 mapped IPv6 addresses */ 1613195972f6Sopenharmony_ci if (IP_IS_V6_VAL(chain_buf.addr) && ip6_addr_isipv4mappedipv6(ip_2_ip6(&chain_buf.addr))) { 1614195972f6Sopenharmony_ci unmap_ipv4_mapped_ipv6(ip_2_ip4(&chain_buf.addr), ip_2_ip6(&chain_buf.addr)); 1615195972f6Sopenharmony_ci IP_SET_TYPE_VAL(chain_buf.addr, IPADDR_TYPE_V4); 1616195972f6Sopenharmony_ci } 1617195972f6Sopenharmony_ci#endif /* LWIP_IPV4 && LWIP_IPV6 */ 1618195972f6Sopenharmony_ci 1619195972f6Sopenharmony_ci /* send the data */ 1620195972f6Sopenharmony_ci err = netconn_send(sock->conn, &chain_buf); 1621195972f6Sopenharmony_ci } 1622195972f6Sopenharmony_ci 1623195972f6Sopenharmony_ci /* deallocated the buffer */ 1624195972f6Sopenharmony_ci netbuf_free(&chain_buf); 1625195972f6Sopenharmony_ci 1626195972f6Sopenharmony_ci sock_set_errno(sock, err_to_errno(err)); 1627195972f6Sopenharmony_ci done_socket(sock); 1628195972f6Sopenharmony_ci return (err == ERR_OK ? size : -1); 1629195972f6Sopenharmony_cisendmsg_emsgsize: 1630195972f6Sopenharmony_ci sock_set_errno(sock, EMSGSIZE); 1631195972f6Sopenharmony_ci netbuf_free(&chain_buf); 1632195972f6Sopenharmony_ci done_socket(sock); 1633195972f6Sopenharmony_ci return -1; 1634195972f6Sopenharmony_ci } 1635195972f6Sopenharmony_ci#else /* LWIP_UDP || LWIP_RAW */ 1636195972f6Sopenharmony_ci sock_set_errno(sock, err_to_errno(ERR_ARG)); 1637195972f6Sopenharmony_ci done_socket(sock); 1638195972f6Sopenharmony_ci return -1; 1639195972f6Sopenharmony_ci#endif /* LWIP_UDP || LWIP_RAW */ 1640195972f6Sopenharmony_ci} 1641195972f6Sopenharmony_ci 1642195972f6Sopenharmony_cissize_t 1643195972f6Sopenharmony_cilwip_sendto(int s, const void *data, size_t size, int flags, 1644195972f6Sopenharmony_ci const struct sockaddr *to, socklen_t tolen) 1645195972f6Sopenharmony_ci{ 1646195972f6Sopenharmony_ci#if LWIP_ENABLE_DISTRIBUTED_NET && LWIP_USE_GET_HOST_BY_NAME_EXTERNAL 1647195972f6Sopenharmony_ci if (!is_distributed_net_enabled()) { 1648195972f6Sopenharmony_ci return lwip_sendto_internal(s, data, size, flags, to, tolen); 1649195972f6Sopenharmony_ci } 1650195972f6Sopenharmony_ci return distributed_net_sendto(s, data, size, flags, to, tolen); 1651195972f6Sopenharmony_ci} 1652195972f6Sopenharmony_ci 1653195972f6Sopenharmony_cissize_t 1654195972f6Sopenharmony_cilwip_sendto_internal(int s, const void *data, size_t size, int flags, 1655195972f6Sopenharmony_ci const struct sockaddr *to, socklen_t tolen) 1656195972f6Sopenharmony_ci{ 1657195972f6Sopenharmony_ci#endif 1658195972f6Sopenharmony_ci struct lwip_sock *sock; 1659195972f6Sopenharmony_ci err_t err; 1660195972f6Sopenharmony_ci u16_t short_size; 1661195972f6Sopenharmony_ci u16_t remote_port; 1662195972f6Sopenharmony_ci struct netbuf buf; 1663195972f6Sopenharmony_ci 1664195972f6Sopenharmony_ci sock = get_socket(s); 1665195972f6Sopenharmony_ci if (!sock) { 1666195972f6Sopenharmony_ci return -1; 1667195972f6Sopenharmony_ci } 1668195972f6Sopenharmony_ci 1669195972f6Sopenharmony_ci if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) { 1670195972f6Sopenharmony_ci#if LWIP_TCP 1671195972f6Sopenharmony_ci done_socket(sock); 1672195972f6Sopenharmony_ci return lwip_send(s, data, size, flags); 1673195972f6Sopenharmony_ci#else /* LWIP_TCP */ 1674195972f6Sopenharmony_ci LWIP_UNUSED_ARG(flags); 1675195972f6Sopenharmony_ci sock_set_errno(sock, err_to_errno(ERR_ARG)); 1676195972f6Sopenharmony_ci done_socket(sock); 1677195972f6Sopenharmony_ci return -1; 1678195972f6Sopenharmony_ci#endif /* LWIP_TCP */ 1679195972f6Sopenharmony_ci } 1680195972f6Sopenharmony_ci 1681195972f6Sopenharmony_ci if (size > LWIP_MIN(0xFFFF, SSIZE_MAX)) { 1682195972f6Sopenharmony_ci /* cannot fit into one datagram (at least for us) */ 1683195972f6Sopenharmony_ci sock_set_errno(sock, EMSGSIZE); 1684195972f6Sopenharmony_ci done_socket(sock); 1685195972f6Sopenharmony_ci return -1; 1686195972f6Sopenharmony_ci } 1687195972f6Sopenharmony_ci short_size = (u16_t)size; 1688195972f6Sopenharmony_ci LWIP_ERROR("lwip_sendto: invalid address", (((to == NULL) && (tolen == 0)) || 1689195972f6Sopenharmony_ci (IS_SOCK_ADDR_LEN_VALID(tolen) && 1690195972f6Sopenharmony_ci ((to != NULL) && (IS_SOCK_ADDR_TYPE_VALID(to) && IS_SOCK_ADDR_ALIGNED(to))))), 1691195972f6Sopenharmony_ci sock_set_errno(sock, err_to_errno(ERR_ARG)); done_socket(sock); return -1;); 1692195972f6Sopenharmony_ci LWIP_UNUSED_ARG(tolen); 1693195972f6Sopenharmony_ci 1694195972f6Sopenharmony_ci /* initialize a buffer */ 1695195972f6Sopenharmony_ci buf.p = buf.ptr = NULL; 1696195972f6Sopenharmony_ci#if LWIP_CHECKSUM_ON_COPY 1697195972f6Sopenharmony_ci buf.flags = 0; 1698195972f6Sopenharmony_ci#endif /* LWIP_CHECKSUM_ON_COPY */ 1699195972f6Sopenharmony_ci if (to) { 1700195972f6Sopenharmony_ci SOCKADDR_TO_IPADDR_PORT(to, &buf.addr, remote_port); 1701195972f6Sopenharmony_ci } else { 1702195972f6Sopenharmony_ci remote_port = 0; 1703195972f6Sopenharmony_ci ip_addr_set_any(NETCONNTYPE_ISIPV6(netconn_type(sock->conn)), &buf.addr); 1704195972f6Sopenharmony_ci } 1705195972f6Sopenharmony_ci netbuf_fromport(&buf) = remote_port; 1706195972f6Sopenharmony_ci 1707195972f6Sopenharmony_ci 1708195972f6Sopenharmony_ci LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_sendto(%d, data=%p, short_size=%"U16_F", flags=0x%x to=", 1709195972f6Sopenharmony_ci s, data, short_size, flags)); 1710195972f6Sopenharmony_ci ip_addr_debug_print_val(SOCKETS_DEBUG, buf.addr); 1711195972f6Sopenharmony_ci LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F"\n", remote_port)); 1712195972f6Sopenharmony_ci 1713195972f6Sopenharmony_ci /* make the buffer point to the data that should be sent */ 1714195972f6Sopenharmony_ci#if LWIP_NETIF_TX_SINGLE_PBUF 1715195972f6Sopenharmony_ci /* Allocate a new netbuf and copy the data into it. */ 1716195972f6Sopenharmony_ci if (netbuf_alloc(&buf, short_size) == NULL) { 1717195972f6Sopenharmony_ci err = ERR_MEM; 1718195972f6Sopenharmony_ci } else { 1719195972f6Sopenharmony_ci#if LWIP_CHECKSUM_ON_COPY 1720195972f6Sopenharmony_ci if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_RAW) { 1721195972f6Sopenharmony_ci u16_t chksum = LWIP_CHKSUM_COPY(buf.p->payload, data, short_size); 1722195972f6Sopenharmony_ci netbuf_set_chksum(&buf, chksum); 1723195972f6Sopenharmony_ci } else 1724195972f6Sopenharmony_ci#endif /* LWIP_CHECKSUM_ON_COPY */ 1725195972f6Sopenharmony_ci { 1726195972f6Sopenharmony_ci MEMCPY(buf.p->payload, data, short_size); 1727195972f6Sopenharmony_ci } 1728195972f6Sopenharmony_ci err = ERR_OK; 1729195972f6Sopenharmony_ci } 1730195972f6Sopenharmony_ci#else /* LWIP_NETIF_TX_SINGLE_PBUF */ 1731195972f6Sopenharmony_ci err = netbuf_ref(&buf, data, short_size); 1732195972f6Sopenharmony_ci#endif /* LWIP_NETIF_TX_SINGLE_PBUF */ 1733195972f6Sopenharmony_ci if (err == ERR_OK) { 1734195972f6Sopenharmony_ci#if LWIP_IPV4 && LWIP_IPV6 1735195972f6Sopenharmony_ci /* Dual-stack: Unmap IPv4 mapped IPv6 addresses */ 1736195972f6Sopenharmony_ci if (IP_IS_V6_VAL(buf.addr) && ip6_addr_isipv4mappedipv6(ip_2_ip6(&buf.addr))) { 1737195972f6Sopenharmony_ci unmap_ipv4_mapped_ipv6(ip_2_ip4(&buf.addr), ip_2_ip6(&buf.addr)); 1738195972f6Sopenharmony_ci IP_SET_TYPE_VAL(buf.addr, IPADDR_TYPE_V4); 1739195972f6Sopenharmony_ci } 1740195972f6Sopenharmony_ci#endif /* LWIP_IPV4 && LWIP_IPV6 */ 1741195972f6Sopenharmony_ci 1742195972f6Sopenharmony_ci /* send the data */ 1743195972f6Sopenharmony_ci err = netconn_send(sock->conn, &buf); 1744195972f6Sopenharmony_ci } 1745195972f6Sopenharmony_ci 1746195972f6Sopenharmony_ci /* deallocated the buffer */ 1747195972f6Sopenharmony_ci netbuf_free(&buf); 1748195972f6Sopenharmony_ci 1749195972f6Sopenharmony_ci sock_set_errno(sock, err_to_errno(err)); 1750195972f6Sopenharmony_ci done_socket(sock); 1751195972f6Sopenharmony_ci return (err == ERR_OK ? short_size : -1); 1752195972f6Sopenharmony_ci} 1753195972f6Sopenharmony_ci 1754195972f6Sopenharmony_ciint 1755195972f6Sopenharmony_cilwip_socket(int domain, int type, int protocol) 1756195972f6Sopenharmony_ci{ 1757195972f6Sopenharmony_ci struct netconn *conn; 1758195972f6Sopenharmony_ci int i; 1759195972f6Sopenharmony_ci 1760195972f6Sopenharmony_ci LWIP_UNUSED_ARG(domain); /* @todo: check this */ 1761195972f6Sopenharmony_ci 1762195972f6Sopenharmony_ci /* create a netconn */ 1763195972f6Sopenharmony_ci switch (type) { 1764195972f6Sopenharmony_ci case SOCK_RAW: 1765195972f6Sopenharmony_ci conn = netconn_new_with_proto_and_callback(DOMAIN_TO_NETCONN_TYPE(domain, NETCONN_RAW), 1766195972f6Sopenharmony_ci (u8_t)protocol, DEFAULT_SOCKET_EVENTCB); 1767195972f6Sopenharmony_ci LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_RAW, %d) = ", 1768195972f6Sopenharmony_ci domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol)); 1769195972f6Sopenharmony_ci break; 1770195972f6Sopenharmony_ci case SOCK_DGRAM: 1771195972f6Sopenharmony_ci conn = netconn_new_with_callback(DOMAIN_TO_NETCONN_TYPE(domain, 1772195972f6Sopenharmony_ci ((protocol == IPPROTO_UDPLITE) ? NETCONN_UDPLITE : NETCONN_UDP)), 1773195972f6Sopenharmony_ci DEFAULT_SOCKET_EVENTCB); 1774195972f6Sopenharmony_ci LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_DGRAM, %d) = ", 1775195972f6Sopenharmony_ci domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol)); 1776195972f6Sopenharmony_ci#if LWIP_NETBUF_RECVINFO 1777195972f6Sopenharmony_ci if (conn) { 1778195972f6Sopenharmony_ci /* netconn layer enables pktinfo by default, sockets default to off */ 1779195972f6Sopenharmony_ci conn->flags &= ~NETCONN_FLAG_PKTINFO; 1780195972f6Sopenharmony_ci } 1781195972f6Sopenharmony_ci#endif /* LWIP_NETBUF_RECVINFO */ 1782195972f6Sopenharmony_ci break; 1783195972f6Sopenharmony_ci case SOCK_STREAM: 1784195972f6Sopenharmony_ci conn = netconn_new_with_callback(DOMAIN_TO_NETCONN_TYPE(domain, NETCONN_TCP), DEFAULT_SOCKET_EVENTCB); 1785195972f6Sopenharmony_ci LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_STREAM, %d) = ", 1786195972f6Sopenharmony_ci domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol)); 1787195972f6Sopenharmony_ci break; 1788195972f6Sopenharmony_ci default: 1789195972f6Sopenharmony_ci LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%d, %d/UNKNOWN, %d) = -1\n", 1790195972f6Sopenharmony_ci domain, type, protocol)); 1791195972f6Sopenharmony_ci set_errno(EINVAL); 1792195972f6Sopenharmony_ci return -1; 1793195972f6Sopenharmony_ci } 1794195972f6Sopenharmony_ci 1795195972f6Sopenharmony_ci if (!conn) { 1796195972f6Sopenharmony_ci LWIP_DEBUGF(SOCKETS_DEBUG, ("-1 / ENOBUFS (could not create netconn)\n")); 1797195972f6Sopenharmony_ci set_errno(ENOBUFS); 1798195972f6Sopenharmony_ci return -1; 1799195972f6Sopenharmony_ci } 1800195972f6Sopenharmony_ci 1801195972f6Sopenharmony_ci i = alloc_socket(conn, 0); 1802195972f6Sopenharmony_ci 1803195972f6Sopenharmony_ci if (i == -1) { 1804195972f6Sopenharmony_ci netconn_delete(conn); 1805195972f6Sopenharmony_ci set_errno(ENFILE); 1806195972f6Sopenharmony_ci return -1; 1807195972f6Sopenharmony_ci } 1808195972f6Sopenharmony_ci conn->socket = i; 1809195972f6Sopenharmony_ci done_socket(&sockets[i - LWIP_SOCKET_OFFSET]); 1810195972f6Sopenharmony_ci LWIP_DEBUGF(SOCKETS_DEBUG, ("%d\n", i)); 1811195972f6Sopenharmony_ci set_errno(0); 1812195972f6Sopenharmony_ci return i; 1813195972f6Sopenharmony_ci} 1814195972f6Sopenharmony_ci 1815195972f6Sopenharmony_cissize_t 1816195972f6Sopenharmony_cilwip_write(int s, const void *data, size_t size) 1817195972f6Sopenharmony_ci{ 1818195972f6Sopenharmony_ci return lwip_send(s, data, size, 0); 1819195972f6Sopenharmony_ci} 1820195972f6Sopenharmony_ci 1821195972f6Sopenharmony_cissize_t 1822195972f6Sopenharmony_cilwip_writev(int s, const struct iovec *iov, int iovcnt) 1823195972f6Sopenharmony_ci{ 1824195972f6Sopenharmony_ci struct msghdr msg; 1825195972f6Sopenharmony_ci 1826195972f6Sopenharmony_ci msg.msg_name = NULL; 1827195972f6Sopenharmony_ci msg.msg_namelen = 0; 1828195972f6Sopenharmony_ci /* Hack: we have to cast via number to cast from 'const' pointer to non-const. 1829195972f6Sopenharmony_ci Blame the opengroup standard for this inconsistency. */ 1830195972f6Sopenharmony_ci msg.msg_iov = LWIP_CONST_CAST(struct iovec *, iov); 1831195972f6Sopenharmony_ci msg.msg_iovlen = iovcnt; 1832195972f6Sopenharmony_ci msg.msg_control = NULL; 1833195972f6Sopenharmony_ci msg.msg_controllen = 0; 1834195972f6Sopenharmony_ci msg.msg_flags = 0; 1835195972f6Sopenharmony_ci return lwip_sendmsg(s, &msg, 0); 1836195972f6Sopenharmony_ci} 1837195972f6Sopenharmony_ci 1838195972f6Sopenharmony_ci#if LWIP_SOCKET_SELECT || LWIP_SOCKET_POLL 1839195972f6Sopenharmony_ci/* Add select_cb to select_cb_list. */ 1840195972f6Sopenharmony_cistatic void 1841195972f6Sopenharmony_cilwip_link_select_cb(struct lwip_select_cb *select_cb) 1842195972f6Sopenharmony_ci{ 1843195972f6Sopenharmony_ci LWIP_SOCKET_SELECT_DECL_PROTECT(lev); 1844195972f6Sopenharmony_ci 1845195972f6Sopenharmony_ci /* Protect the select_cb_list */ 1846195972f6Sopenharmony_ci LWIP_SOCKET_SELECT_PROTECT(lev); 1847195972f6Sopenharmony_ci 1848195972f6Sopenharmony_ci /* Put this select_cb on top of list */ 1849195972f6Sopenharmony_ci select_cb->next = select_cb_list; 1850195972f6Sopenharmony_ci if (select_cb_list != NULL) { 1851195972f6Sopenharmony_ci select_cb_list->prev = select_cb; 1852195972f6Sopenharmony_ci } 1853195972f6Sopenharmony_ci select_cb_list = select_cb; 1854195972f6Sopenharmony_ci#if !LWIP_TCPIP_CORE_LOCKING 1855195972f6Sopenharmony_ci /* Increasing this counter tells select_check_waiters that the list has changed. */ 1856195972f6Sopenharmony_ci select_cb_ctr++; 1857195972f6Sopenharmony_ci#endif 1858195972f6Sopenharmony_ci 1859195972f6Sopenharmony_ci /* Now we can safely unprotect */ 1860195972f6Sopenharmony_ci LWIP_SOCKET_SELECT_UNPROTECT(lev); 1861195972f6Sopenharmony_ci} 1862195972f6Sopenharmony_ci 1863195972f6Sopenharmony_ci/* Remove select_cb from select_cb_list. */ 1864195972f6Sopenharmony_cistatic void 1865195972f6Sopenharmony_cilwip_unlink_select_cb(struct lwip_select_cb *select_cb) 1866195972f6Sopenharmony_ci{ 1867195972f6Sopenharmony_ci LWIP_SOCKET_SELECT_DECL_PROTECT(lev); 1868195972f6Sopenharmony_ci 1869195972f6Sopenharmony_ci /* Take us off the list */ 1870195972f6Sopenharmony_ci LWIP_SOCKET_SELECT_PROTECT(lev); 1871195972f6Sopenharmony_ci if (select_cb->next != NULL) { 1872195972f6Sopenharmony_ci select_cb->next->prev = select_cb->prev; 1873195972f6Sopenharmony_ci } 1874195972f6Sopenharmony_ci if (select_cb_list == select_cb) { 1875195972f6Sopenharmony_ci LWIP_ASSERT("select_cb->prev == NULL", select_cb->prev == NULL); 1876195972f6Sopenharmony_ci select_cb_list = select_cb->next; 1877195972f6Sopenharmony_ci } else { 1878195972f6Sopenharmony_ci LWIP_ASSERT("select_cb->prev != NULL", select_cb->prev != NULL); 1879195972f6Sopenharmony_ci select_cb->prev->next = select_cb->next; 1880195972f6Sopenharmony_ci } 1881195972f6Sopenharmony_ci#if !LWIP_TCPIP_CORE_LOCKING 1882195972f6Sopenharmony_ci /* Increasing this counter tells select_check_waiters that the list has changed. */ 1883195972f6Sopenharmony_ci select_cb_ctr++; 1884195972f6Sopenharmony_ci#endif 1885195972f6Sopenharmony_ci LWIP_SOCKET_SELECT_UNPROTECT(lev); 1886195972f6Sopenharmony_ci} 1887195972f6Sopenharmony_ci#endif /* LWIP_SOCKET_SELECT || LWIP_SOCKET_POLL */ 1888195972f6Sopenharmony_ci 1889195972f6Sopenharmony_ci#if LWIP_SOCKET_SELECT 1890195972f6Sopenharmony_ci/** 1891195972f6Sopenharmony_ci * Go through the readset and writeset lists and see which socket of the sockets 1892195972f6Sopenharmony_ci * set in the sets has events. On return, readset, writeset and exceptset have 1893195972f6Sopenharmony_ci * the sockets enabled that had events. 1894195972f6Sopenharmony_ci * 1895195972f6Sopenharmony_ci * @param maxfdp1 the highest socket index in the sets 1896195972f6Sopenharmony_ci * @param readset_in set of sockets to check for read events 1897195972f6Sopenharmony_ci * @param writeset_in set of sockets to check for write events 1898195972f6Sopenharmony_ci * @param exceptset_in set of sockets to check for error events 1899195972f6Sopenharmony_ci * @param readset_out set of sockets that had read events 1900195972f6Sopenharmony_ci * @param writeset_out set of sockets that had write events 1901195972f6Sopenharmony_ci * @param exceptset_out set os sockets that had error events 1902195972f6Sopenharmony_ci * @return number of sockets that had events (read/write/exception) (>= 0) 1903195972f6Sopenharmony_ci */ 1904195972f6Sopenharmony_cistatic int 1905195972f6Sopenharmony_cilwip_selscan(int maxfdp1, fd_set *readset_in, fd_set *writeset_in, fd_set *exceptset_in, 1906195972f6Sopenharmony_ci fd_set *readset_out, fd_set *writeset_out, fd_set *exceptset_out) 1907195972f6Sopenharmony_ci{ 1908195972f6Sopenharmony_ci int i, nready = 0; 1909195972f6Sopenharmony_ci fd_set lreadset, lwriteset, lexceptset; 1910195972f6Sopenharmony_ci struct lwip_sock *sock; 1911195972f6Sopenharmony_ci SYS_ARCH_DECL_PROTECT(lev); 1912195972f6Sopenharmony_ci 1913195972f6Sopenharmony_ci FD_ZERO(&lreadset); 1914195972f6Sopenharmony_ci FD_ZERO(&lwriteset); 1915195972f6Sopenharmony_ci FD_ZERO(&lexceptset); 1916195972f6Sopenharmony_ci 1917195972f6Sopenharmony_ci /* Go through each socket in each list to count number of sockets which 1918195972f6Sopenharmony_ci currently match */ 1919195972f6Sopenharmony_ci for (i = LWIP_SOCKET_OFFSET; i < maxfdp1; i++) { 1920195972f6Sopenharmony_ci /* if this FD is not in the set, continue */ 1921195972f6Sopenharmony_ci if (!(readset_in && FD_ISSET(i, readset_in)) && 1922195972f6Sopenharmony_ci !(writeset_in && FD_ISSET(i, writeset_in)) && 1923195972f6Sopenharmony_ci !(exceptset_in && FD_ISSET(i, exceptset_in))) { 1924195972f6Sopenharmony_ci continue; 1925195972f6Sopenharmony_ci } 1926195972f6Sopenharmony_ci /* First get the socket's status (protected)... */ 1927195972f6Sopenharmony_ci SYS_ARCH_PROTECT(lev); 1928195972f6Sopenharmony_ci sock = tryget_socket_unconn_locked(i); 1929195972f6Sopenharmony_ci if (sock != NULL) { 1930195972f6Sopenharmony_ci void *lastdata = sock->lastdata.pbuf; 1931195972f6Sopenharmony_ci s16_t rcvevent = sock->rcvevent; 1932195972f6Sopenharmony_ci u16_t sendevent = sock->sendevent; 1933195972f6Sopenharmony_ci u16_t errevent = sock->errevent; 1934195972f6Sopenharmony_ci SYS_ARCH_UNPROTECT(lev); 1935195972f6Sopenharmony_ci 1936195972f6Sopenharmony_ci /* ... then examine it: */ 1937195972f6Sopenharmony_ci /* See if netconn of this socket is ready for read */ 1938195972f6Sopenharmony_ci if (readset_in && FD_ISSET(i, readset_in) && ((lastdata != NULL) || (rcvevent > 0))) { 1939195972f6Sopenharmony_ci FD_SET(i, &lreadset); 1940195972f6Sopenharmony_ci LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_selscan: fd=%d ready for reading\n", i)); 1941195972f6Sopenharmony_ci nready++; 1942195972f6Sopenharmony_ci } 1943195972f6Sopenharmony_ci /* See if netconn of this socket is ready for write */ 1944195972f6Sopenharmony_ci if (writeset_in && FD_ISSET(i, writeset_in) && (sendevent != 0)) { 1945195972f6Sopenharmony_ci FD_SET(i, &lwriteset); 1946195972f6Sopenharmony_ci LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_selscan: fd=%d ready for writing\n", i)); 1947195972f6Sopenharmony_ci nready++; 1948195972f6Sopenharmony_ci } 1949195972f6Sopenharmony_ci /* See if netconn of this socket had an error */ 1950195972f6Sopenharmony_ci if (exceptset_in && FD_ISSET(i, exceptset_in) && (errevent != 0)) { 1951195972f6Sopenharmony_ci FD_SET(i, &lexceptset); 1952195972f6Sopenharmony_ci LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_selscan: fd=%d ready for exception\n", i)); 1953195972f6Sopenharmony_ci nready++; 1954195972f6Sopenharmony_ci } 1955195972f6Sopenharmony_ci done_socket(sock); 1956195972f6Sopenharmony_ci } else { 1957195972f6Sopenharmony_ci SYS_ARCH_UNPROTECT(lev); 1958195972f6Sopenharmony_ci /* no a valid open socket */ 1959195972f6Sopenharmony_ci return -1; 1960195972f6Sopenharmony_ci } 1961195972f6Sopenharmony_ci } 1962195972f6Sopenharmony_ci /* copy local sets to the ones provided as arguments */ 1963195972f6Sopenharmony_ci *readset_out = lreadset; 1964195972f6Sopenharmony_ci *writeset_out = lwriteset; 1965195972f6Sopenharmony_ci *exceptset_out = lexceptset; 1966195972f6Sopenharmony_ci 1967195972f6Sopenharmony_ci LWIP_ASSERT("nready >= 0", nready >= 0); 1968195972f6Sopenharmony_ci return nready; 1969195972f6Sopenharmony_ci} 1970195972f6Sopenharmony_ci 1971195972f6Sopenharmony_ci#if LWIP_NETCONN_FULLDUPLEX 1972195972f6Sopenharmony_ci/* Mark all of the set sockets in one of the three fdsets passed to select as used. 1973195972f6Sopenharmony_ci * All sockets are marked (and later unmarked), whether they are open or not. 1974195972f6Sopenharmony_ci * This is OK as lwip_selscan aborts select when non-open sockets are found. 1975195972f6Sopenharmony_ci */ 1976195972f6Sopenharmony_cistatic void 1977195972f6Sopenharmony_cilwip_select_inc_sockets_used_set(int maxfdp, fd_set *fdset, fd_set *used_sockets) 1978195972f6Sopenharmony_ci{ 1979195972f6Sopenharmony_ci SYS_ARCH_DECL_PROTECT(lev); 1980195972f6Sopenharmony_ci if (fdset) { 1981195972f6Sopenharmony_ci int i; 1982195972f6Sopenharmony_ci for (i = LWIP_SOCKET_OFFSET; i < maxfdp; i++) { 1983195972f6Sopenharmony_ci /* if this FD is in the set, lock it (unless already done) */ 1984195972f6Sopenharmony_ci if (FD_ISSET(i, fdset) && !FD_ISSET(i, used_sockets)) { 1985195972f6Sopenharmony_ci struct lwip_sock *sock; 1986195972f6Sopenharmony_ci SYS_ARCH_PROTECT(lev); 1987195972f6Sopenharmony_ci sock = tryget_socket_unconn_locked(i); 1988195972f6Sopenharmony_ci if (sock != NULL) { 1989195972f6Sopenharmony_ci /* leave the socket used until released by lwip_select_dec_sockets_used */ 1990195972f6Sopenharmony_ci FD_SET(i, used_sockets); 1991195972f6Sopenharmony_ci } 1992195972f6Sopenharmony_ci SYS_ARCH_UNPROTECT(lev); 1993195972f6Sopenharmony_ci } 1994195972f6Sopenharmony_ci } 1995195972f6Sopenharmony_ci } 1996195972f6Sopenharmony_ci} 1997195972f6Sopenharmony_ci 1998195972f6Sopenharmony_ci/* Mark all sockets passed to select as used to prevent them from being freed 1999195972f6Sopenharmony_ci * from other threads while select is running. 2000195972f6Sopenharmony_ci * Marked sockets are added to 'used_sockets' to mark them only once an be able 2001195972f6Sopenharmony_ci * to unmark them correctly. 2002195972f6Sopenharmony_ci */ 2003195972f6Sopenharmony_cistatic void 2004195972f6Sopenharmony_cilwip_select_inc_sockets_used(int maxfdp, fd_set *fdset1, fd_set *fdset2, fd_set *fdset3, fd_set *used_sockets) 2005195972f6Sopenharmony_ci{ 2006195972f6Sopenharmony_ci FD_ZERO(used_sockets); 2007195972f6Sopenharmony_ci lwip_select_inc_sockets_used_set(maxfdp, fdset1, used_sockets); 2008195972f6Sopenharmony_ci lwip_select_inc_sockets_used_set(maxfdp, fdset2, used_sockets); 2009195972f6Sopenharmony_ci lwip_select_inc_sockets_used_set(maxfdp, fdset3, used_sockets); 2010195972f6Sopenharmony_ci} 2011195972f6Sopenharmony_ci 2012195972f6Sopenharmony_ci/* Let go all sockets that were marked as used when starting select */ 2013195972f6Sopenharmony_cistatic void 2014195972f6Sopenharmony_cilwip_select_dec_sockets_used(int maxfdp, fd_set *used_sockets) 2015195972f6Sopenharmony_ci{ 2016195972f6Sopenharmony_ci int i; 2017195972f6Sopenharmony_ci for (i = LWIP_SOCKET_OFFSET; i < maxfdp; i++) { 2018195972f6Sopenharmony_ci /* if this FD is not in the set, continue */ 2019195972f6Sopenharmony_ci if (FD_ISSET(i, used_sockets)) { 2020195972f6Sopenharmony_ci struct lwip_sock *sock = tryget_socket_unconn_nouse(i); 2021195972f6Sopenharmony_ci LWIP_ASSERT("socket gone at the end of select", sock != NULL); 2022195972f6Sopenharmony_ci if (sock != NULL) { 2023195972f6Sopenharmony_ci done_socket(sock); 2024195972f6Sopenharmony_ci } 2025195972f6Sopenharmony_ci } 2026195972f6Sopenharmony_ci } 2027195972f6Sopenharmony_ci} 2028195972f6Sopenharmony_ci#else /* LWIP_NETCONN_FULLDUPLEX */ 2029195972f6Sopenharmony_ci#define lwip_select_inc_sockets_used(maxfdp1, readset, writeset, exceptset, used_sockets) 2030195972f6Sopenharmony_ci#define lwip_select_dec_sockets_used(maxfdp1, used_sockets) 2031195972f6Sopenharmony_ci#endif /* LWIP_NETCONN_FULLDUPLEX */ 2032195972f6Sopenharmony_ci 2033195972f6Sopenharmony_ciint 2034195972f6Sopenharmony_cilwip_select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset, 2035195972f6Sopenharmony_ci struct timeval *timeout) 2036195972f6Sopenharmony_ci{ 2037195972f6Sopenharmony_ci u32_t waitres = 0; 2038195972f6Sopenharmony_ci int nready; 2039195972f6Sopenharmony_ci fd_set lreadset, lwriteset, lexceptset; 2040195972f6Sopenharmony_ci u32_t msectimeout; 2041195972f6Sopenharmony_ci int i; 2042195972f6Sopenharmony_ci int maxfdp2; 2043195972f6Sopenharmony_ci#if LWIP_NETCONN_SEM_PER_THREAD 2044195972f6Sopenharmony_ci int waited = 0; 2045195972f6Sopenharmony_ci#endif 2046195972f6Sopenharmony_ci#if LWIP_NETCONN_FULLDUPLEX 2047195972f6Sopenharmony_ci fd_set used_sockets; 2048195972f6Sopenharmony_ci#endif 2049195972f6Sopenharmony_ci SYS_ARCH_DECL_PROTECT(lev); 2050195972f6Sopenharmony_ci 2051195972f6Sopenharmony_ci LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select(%d, %p, %p, %p, tvsec=%"S32_F" tvusec=%"S32_F")\n", 2052195972f6Sopenharmony_ci maxfdp1, (void *)readset, (void *) writeset, (void *) exceptset, 2053195972f6Sopenharmony_ci timeout ? (s32_t)timeout->tv_sec : (s32_t) - 1, 2054195972f6Sopenharmony_ci timeout ? (s32_t)timeout->tv_usec : (s32_t) - 1)); 2055195972f6Sopenharmony_ci 2056195972f6Sopenharmony_ci if ((maxfdp1 < 0) || (maxfdp1 > LWIP_SELECT_MAXNFDS)) { 2057195972f6Sopenharmony_ci set_errno(EINVAL); 2058195972f6Sopenharmony_ci return -1; 2059195972f6Sopenharmony_ci } 2060195972f6Sopenharmony_ci 2061195972f6Sopenharmony_ci lwip_select_inc_sockets_used(maxfdp1, readset, writeset, exceptset, &used_sockets); 2062195972f6Sopenharmony_ci 2063195972f6Sopenharmony_ci /* Go through each socket in each list to count number of sockets which 2064195972f6Sopenharmony_ci currently match */ 2065195972f6Sopenharmony_ci nready = lwip_selscan(maxfdp1, readset, writeset, exceptset, &lreadset, &lwriteset, &lexceptset); 2066195972f6Sopenharmony_ci 2067195972f6Sopenharmony_ci if (nready < 0) { 2068195972f6Sopenharmony_ci /* one of the sockets in one of the fd_sets was invalid */ 2069195972f6Sopenharmony_ci set_errno(EBADF); 2070195972f6Sopenharmony_ci lwip_select_dec_sockets_used(maxfdp1, &used_sockets); 2071195972f6Sopenharmony_ci return -1; 2072195972f6Sopenharmony_ci } else if (nready > 0) { 2073195972f6Sopenharmony_ci /* one or more sockets are set, no need to wait */ 2074195972f6Sopenharmony_ci LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select: nready=%d\n", nready)); 2075195972f6Sopenharmony_ci } else { 2076195972f6Sopenharmony_ci /* If we don't have any current events, then suspend if we are supposed to */ 2077195972f6Sopenharmony_ci if (timeout && timeout->tv_sec == 0 && timeout->tv_usec == 0) { 2078195972f6Sopenharmony_ci LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select: no timeout, returning 0\n")); 2079195972f6Sopenharmony_ci /* This is OK as the local fdsets are empty and nready is zero, 2080195972f6Sopenharmony_ci or we would have returned earlier. */ 2081195972f6Sopenharmony_ci } else { 2082195972f6Sopenharmony_ci /* None ready: add our semaphore to list: 2083195972f6Sopenharmony_ci We don't actually need any dynamic memory. Our entry on the 2084195972f6Sopenharmony_ci list is only valid while we are in this function, so it's ok 2085195972f6Sopenharmony_ci to use local variables (unless we're running in MPU compatible 2086195972f6Sopenharmony_ci mode). */ 2087195972f6Sopenharmony_ci API_SELECT_CB_VAR_DECLARE(select_cb); 2088195972f6Sopenharmony_ci API_SELECT_CB_VAR_ALLOC(select_cb, set_errno(ENOMEM); lwip_select_dec_sockets_used(maxfdp1, &used_sockets); return -1); 2089195972f6Sopenharmony_ci memset(&API_SELECT_CB_VAR_REF(select_cb), 0, sizeof(struct lwip_select_cb)); 2090195972f6Sopenharmony_ci 2091195972f6Sopenharmony_ci API_SELECT_CB_VAR_REF(select_cb).readset = readset; 2092195972f6Sopenharmony_ci API_SELECT_CB_VAR_REF(select_cb).writeset = writeset; 2093195972f6Sopenharmony_ci API_SELECT_CB_VAR_REF(select_cb).exceptset = exceptset; 2094195972f6Sopenharmony_ci#if LWIP_NETCONN_SEM_PER_THREAD 2095195972f6Sopenharmony_ci API_SELECT_CB_VAR_REF(select_cb).sem = LWIP_NETCONN_THREAD_SEM_GET(); 2096195972f6Sopenharmony_ci#else /* LWIP_NETCONN_SEM_PER_THREAD */ 2097195972f6Sopenharmony_ci if (sys_sem_new(&API_SELECT_CB_VAR_REF(select_cb).sem, 0) != ERR_OK) { 2098195972f6Sopenharmony_ci /* failed to create semaphore */ 2099195972f6Sopenharmony_ci set_errno(ENOMEM); 2100195972f6Sopenharmony_ci lwip_select_dec_sockets_used(maxfdp1, &used_sockets); 2101195972f6Sopenharmony_ci API_SELECT_CB_VAR_FREE(select_cb); 2102195972f6Sopenharmony_ci return -1; 2103195972f6Sopenharmony_ci } 2104195972f6Sopenharmony_ci#endif /* LWIP_NETCONN_SEM_PER_THREAD */ 2105195972f6Sopenharmony_ci 2106195972f6Sopenharmony_ci lwip_link_select_cb(&API_SELECT_CB_VAR_REF(select_cb)); 2107195972f6Sopenharmony_ci 2108195972f6Sopenharmony_ci /* Increase select_waiting for each socket we are interested in */ 2109195972f6Sopenharmony_ci maxfdp2 = maxfdp1; 2110195972f6Sopenharmony_ci for (i = LWIP_SOCKET_OFFSET; i < maxfdp1; i++) { 2111195972f6Sopenharmony_ci if ((readset && FD_ISSET(i, readset)) || 2112195972f6Sopenharmony_ci (writeset && FD_ISSET(i, writeset)) || 2113195972f6Sopenharmony_ci (exceptset && FD_ISSET(i, exceptset))) { 2114195972f6Sopenharmony_ci struct lwip_sock *sock; 2115195972f6Sopenharmony_ci SYS_ARCH_PROTECT(lev); 2116195972f6Sopenharmony_ci sock = tryget_socket_unconn_locked(i); 2117195972f6Sopenharmony_ci if (sock != NULL) { 2118195972f6Sopenharmony_ci sock->select_waiting++; 2119195972f6Sopenharmony_ci if (sock->select_waiting == 0) { 2120195972f6Sopenharmony_ci /* overflow - too many threads waiting */ 2121195972f6Sopenharmony_ci sock->select_waiting--; 2122195972f6Sopenharmony_ci nready = -1; 2123195972f6Sopenharmony_ci maxfdp2 = i; 2124195972f6Sopenharmony_ci SYS_ARCH_UNPROTECT(lev); 2125195972f6Sopenharmony_ci done_socket(sock); 2126195972f6Sopenharmony_ci set_errno(EBUSY); 2127195972f6Sopenharmony_ci break; 2128195972f6Sopenharmony_ci } 2129195972f6Sopenharmony_ci SYS_ARCH_UNPROTECT(lev); 2130195972f6Sopenharmony_ci done_socket(sock); 2131195972f6Sopenharmony_ci } else { 2132195972f6Sopenharmony_ci /* Not a valid socket */ 2133195972f6Sopenharmony_ci nready = -1; 2134195972f6Sopenharmony_ci maxfdp2 = i; 2135195972f6Sopenharmony_ci SYS_ARCH_UNPROTECT(lev); 2136195972f6Sopenharmony_ci set_errno(EBADF); 2137195972f6Sopenharmony_ci break; 2138195972f6Sopenharmony_ci } 2139195972f6Sopenharmony_ci } 2140195972f6Sopenharmony_ci } 2141195972f6Sopenharmony_ci 2142195972f6Sopenharmony_ci if (nready >= 0) { 2143195972f6Sopenharmony_ci /* Call lwip_selscan again: there could have been events between 2144195972f6Sopenharmony_ci the last scan (without us on the list) and putting us on the list! */ 2145195972f6Sopenharmony_ci nready = lwip_selscan(maxfdp1, readset, writeset, exceptset, &lreadset, &lwriteset, &lexceptset); 2146195972f6Sopenharmony_ci if (nready < 0) { 2147195972f6Sopenharmony_ci set_errno(EBADF); 2148195972f6Sopenharmony_ci } else if (!nready) { 2149195972f6Sopenharmony_ci /* Still none ready, just wait to be woken */ 2150195972f6Sopenharmony_ci if (timeout == 0) { 2151195972f6Sopenharmony_ci /* Wait forever */ 2152195972f6Sopenharmony_ci msectimeout = 0; 2153195972f6Sopenharmony_ci } else { 2154195972f6Sopenharmony_ci long msecs_long = ((timeout->tv_sec * 1000) + ((timeout->tv_usec + 500) / 1000)); 2155195972f6Sopenharmony_ci if (msecs_long <= 0) { 2156195972f6Sopenharmony_ci /* Wait 1ms at least (0 means wait forever) */ 2157195972f6Sopenharmony_ci msectimeout = 1; 2158195972f6Sopenharmony_ci } else { 2159195972f6Sopenharmony_ci msectimeout = (u32_t)msecs_long; 2160195972f6Sopenharmony_ci } 2161195972f6Sopenharmony_ci } 2162195972f6Sopenharmony_ci 2163195972f6Sopenharmony_ci waitres = sys_arch_sem_wait(SELECT_SEM_PTR(API_SELECT_CB_VAR_REF(select_cb).sem), msectimeout); 2164195972f6Sopenharmony_ci#if LWIP_NETCONN_SEM_PER_THREAD 2165195972f6Sopenharmony_ci waited = 1; 2166195972f6Sopenharmony_ci#endif 2167195972f6Sopenharmony_ci } 2168195972f6Sopenharmony_ci } 2169195972f6Sopenharmony_ci 2170195972f6Sopenharmony_ci /* Decrease select_waiting for each socket we are interested in */ 2171195972f6Sopenharmony_ci for (i = LWIP_SOCKET_OFFSET; i < maxfdp2; i++) { 2172195972f6Sopenharmony_ci if ((readset && FD_ISSET(i, readset)) || 2173195972f6Sopenharmony_ci (writeset && FD_ISSET(i, writeset)) || 2174195972f6Sopenharmony_ci (exceptset && FD_ISSET(i, exceptset))) { 2175195972f6Sopenharmony_ci struct lwip_sock *sock; 2176195972f6Sopenharmony_ci SYS_ARCH_PROTECT(lev); 2177195972f6Sopenharmony_ci sock = tryget_socket_unconn_nouse(i); 2178195972f6Sopenharmony_ci LWIP_ASSERT("socket gone at the end of select", sock != NULL); 2179195972f6Sopenharmony_ci if (sock != NULL) { 2180195972f6Sopenharmony_ci /* for now, handle select_waiting==0... */ 2181195972f6Sopenharmony_ci LWIP_ASSERT("sock->select_waiting > 0", sock->select_waiting > 0); 2182195972f6Sopenharmony_ci if (sock->select_waiting > 0) { 2183195972f6Sopenharmony_ci sock->select_waiting--; 2184195972f6Sopenharmony_ci } 2185195972f6Sopenharmony_ci SYS_ARCH_UNPROTECT(lev); 2186195972f6Sopenharmony_ci } else { 2187195972f6Sopenharmony_ci SYS_ARCH_UNPROTECT(lev); 2188195972f6Sopenharmony_ci /* Not a valid socket */ 2189195972f6Sopenharmony_ci nready = -1; 2190195972f6Sopenharmony_ci set_errno(EBADF); 2191195972f6Sopenharmony_ci } 2192195972f6Sopenharmony_ci } 2193195972f6Sopenharmony_ci } 2194195972f6Sopenharmony_ci 2195195972f6Sopenharmony_ci lwip_unlink_select_cb(&API_SELECT_CB_VAR_REF(select_cb)); 2196195972f6Sopenharmony_ci 2197195972f6Sopenharmony_ci#if LWIP_NETCONN_SEM_PER_THREAD 2198195972f6Sopenharmony_ci if (API_SELECT_CB_VAR_REF(select_cb).sem_signalled && (!waited || (waitres == SYS_ARCH_TIMEOUT))) { 2199195972f6Sopenharmony_ci /* don't leave the thread-local semaphore signalled */ 2200195972f6Sopenharmony_ci sys_arch_sem_wait(API_SELECT_CB_VAR_REF(select_cb).sem, 1); 2201195972f6Sopenharmony_ci } 2202195972f6Sopenharmony_ci#else /* LWIP_NETCONN_SEM_PER_THREAD */ 2203195972f6Sopenharmony_ci sys_sem_free(&API_SELECT_CB_VAR_REF(select_cb).sem); 2204195972f6Sopenharmony_ci#endif /* LWIP_NETCONN_SEM_PER_THREAD */ 2205195972f6Sopenharmony_ci API_SELECT_CB_VAR_FREE(select_cb); 2206195972f6Sopenharmony_ci 2207195972f6Sopenharmony_ci if (nready < 0) { 2208195972f6Sopenharmony_ci /* This happens when a socket got closed while waiting */ 2209195972f6Sopenharmony_ci lwip_select_dec_sockets_used(maxfdp1, &used_sockets); 2210195972f6Sopenharmony_ci return -1; 2211195972f6Sopenharmony_ci } 2212195972f6Sopenharmony_ci 2213195972f6Sopenharmony_ci if (waitres == SYS_ARCH_TIMEOUT) { 2214195972f6Sopenharmony_ci /* Timeout */ 2215195972f6Sopenharmony_ci LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select: timeout expired\n")); 2216195972f6Sopenharmony_ci /* This is OK as the local fdsets are empty and nready is zero, 2217195972f6Sopenharmony_ci or we would have returned earlier. */ 2218195972f6Sopenharmony_ci } else { 2219195972f6Sopenharmony_ci /* See what's set now after waiting */ 2220195972f6Sopenharmony_ci nready = lwip_selscan(maxfdp1, readset, writeset, exceptset, &lreadset, &lwriteset, &lexceptset); 2221195972f6Sopenharmony_ci LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select: nready=%d\n", nready)); 2222195972f6Sopenharmony_ci if (nready < 0) { 2223195972f6Sopenharmony_ci set_errno(EBADF); 2224195972f6Sopenharmony_ci lwip_select_dec_sockets_used(maxfdp1, &used_sockets); 2225195972f6Sopenharmony_ci return -1; 2226195972f6Sopenharmony_ci } 2227195972f6Sopenharmony_ci } 2228195972f6Sopenharmony_ci } 2229195972f6Sopenharmony_ci } 2230195972f6Sopenharmony_ci 2231195972f6Sopenharmony_ci lwip_select_dec_sockets_used(maxfdp1, &used_sockets); 2232195972f6Sopenharmony_ci set_errno(0); 2233195972f6Sopenharmony_ci if (readset) { 2234195972f6Sopenharmony_ci *readset = lreadset; 2235195972f6Sopenharmony_ci } 2236195972f6Sopenharmony_ci if (writeset) { 2237195972f6Sopenharmony_ci *writeset = lwriteset; 2238195972f6Sopenharmony_ci } 2239195972f6Sopenharmony_ci if (exceptset) { 2240195972f6Sopenharmony_ci *exceptset = lexceptset; 2241195972f6Sopenharmony_ci } 2242195972f6Sopenharmony_ci return nready; 2243195972f6Sopenharmony_ci} 2244195972f6Sopenharmony_ci#endif /* LWIP_SOCKET_SELECT */ 2245195972f6Sopenharmony_ci 2246195972f6Sopenharmony_ci#if LWIP_SOCKET_POLL 2247195972f6Sopenharmony_ci/** Options for the lwip_pollscan function. */ 2248195972f6Sopenharmony_cienum lwip_pollscan_opts 2249195972f6Sopenharmony_ci{ 2250195972f6Sopenharmony_ci /** Clear revents in each struct pollfd. */ 2251195972f6Sopenharmony_ci LWIP_POLLSCAN_CLEAR = 1, 2252195972f6Sopenharmony_ci 2253195972f6Sopenharmony_ci /** Increment select_waiting in each struct lwip_sock. */ 2254195972f6Sopenharmony_ci LWIP_POLLSCAN_INC_WAIT = 2, 2255195972f6Sopenharmony_ci 2256195972f6Sopenharmony_ci /** Decrement select_waiting in each struct lwip_sock. */ 2257195972f6Sopenharmony_ci LWIP_POLLSCAN_DEC_WAIT = 4 2258195972f6Sopenharmony_ci}; 2259195972f6Sopenharmony_ci 2260195972f6Sopenharmony_ci/** 2261195972f6Sopenharmony_ci * Update revents in each struct pollfd. 2262195972f6Sopenharmony_ci * Optionally update select_waiting in struct lwip_sock. 2263195972f6Sopenharmony_ci * 2264195972f6Sopenharmony_ci * @param fds array of structures to update 2265195972f6Sopenharmony_ci * @param nfds number of structures in fds 2266195972f6Sopenharmony_ci * @param opts what to update and how 2267195972f6Sopenharmony_ci * @return number of structures that have revents != 0 2268195972f6Sopenharmony_ci */ 2269195972f6Sopenharmony_cistatic int 2270195972f6Sopenharmony_cilwip_pollscan(struct pollfd *fds, nfds_t nfds, enum lwip_pollscan_opts opts) 2271195972f6Sopenharmony_ci{ 2272195972f6Sopenharmony_ci int nready = 0; 2273195972f6Sopenharmony_ci nfds_t fdi; 2274195972f6Sopenharmony_ci struct lwip_sock *sock; 2275195972f6Sopenharmony_ci SYS_ARCH_DECL_PROTECT(lev); 2276195972f6Sopenharmony_ci 2277195972f6Sopenharmony_ci /* Go through each struct pollfd in the array. */ 2278195972f6Sopenharmony_ci for (fdi = 0; fdi < nfds; fdi++) { 2279195972f6Sopenharmony_ci if ((opts & LWIP_POLLSCAN_CLEAR) != 0) { 2280195972f6Sopenharmony_ci fds[fdi].revents = 0; 2281195972f6Sopenharmony_ci } 2282195972f6Sopenharmony_ci 2283195972f6Sopenharmony_ci /* Negative fd means the caller wants us to ignore this struct. 2284195972f6Sopenharmony_ci POLLNVAL means we already detected that the fd is invalid; 2285195972f6Sopenharmony_ci if another thread has since opened a new socket with that fd, 2286195972f6Sopenharmony_ci we must not use that socket. */ 2287195972f6Sopenharmony_ci if (fds[fdi].fd >= 0 && (fds[fdi].revents & POLLNVAL) == 0) { 2288195972f6Sopenharmony_ci /* First get the socket's status (protected)... */ 2289195972f6Sopenharmony_ci SYS_ARCH_PROTECT(lev); 2290195972f6Sopenharmony_ci sock = tryget_socket_unconn_locked(fds[fdi].fd); 2291195972f6Sopenharmony_ci if (sock != NULL) { 2292195972f6Sopenharmony_ci void* lastdata = sock->lastdata.pbuf; 2293195972f6Sopenharmony_ci s16_t rcvevent = sock->rcvevent; 2294195972f6Sopenharmony_ci u16_t sendevent = sock->sendevent; 2295195972f6Sopenharmony_ci u16_t errevent = sock->errevent; 2296195972f6Sopenharmony_ci 2297195972f6Sopenharmony_ci if ((opts & LWIP_POLLSCAN_INC_WAIT) != 0) { 2298195972f6Sopenharmony_ci sock->select_waiting++; 2299195972f6Sopenharmony_ci if (sock->select_waiting == 0) { 2300195972f6Sopenharmony_ci /* overflow - too many threads waiting */ 2301195972f6Sopenharmony_ci sock->select_waiting--; 2302195972f6Sopenharmony_ci nready = -1; 2303195972f6Sopenharmony_ci SYS_ARCH_UNPROTECT(lev); 2304195972f6Sopenharmony_ci done_socket(sock); 2305195972f6Sopenharmony_ci break; 2306195972f6Sopenharmony_ci } 2307195972f6Sopenharmony_ci } else if ((opts & LWIP_POLLSCAN_DEC_WAIT) != 0) { 2308195972f6Sopenharmony_ci /* for now, handle select_waiting==0... */ 2309195972f6Sopenharmony_ci LWIP_ASSERT("sock->select_waiting > 0", sock->select_waiting > 0); 2310195972f6Sopenharmony_ci if (sock->select_waiting > 0) { 2311195972f6Sopenharmony_ci sock->select_waiting--; 2312195972f6Sopenharmony_ci } 2313195972f6Sopenharmony_ci } 2314195972f6Sopenharmony_ci SYS_ARCH_UNPROTECT(lev); 2315195972f6Sopenharmony_ci done_socket(sock); 2316195972f6Sopenharmony_ci 2317195972f6Sopenharmony_ci /* ... then examine it: */ 2318195972f6Sopenharmony_ci /* See if netconn of this socket is ready for read */ 2319195972f6Sopenharmony_ci if ((fds[fdi].events & POLLIN) != 0 && ((lastdata != NULL) || (rcvevent > 0))) { 2320195972f6Sopenharmony_ci fds[fdi].revents |= POLLIN; 2321195972f6Sopenharmony_ci LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_pollscan: fd=%d ready for reading\n", fds[fdi].fd)); 2322195972f6Sopenharmony_ci } 2323195972f6Sopenharmony_ci /* See if netconn of this socket is ready for write */ 2324195972f6Sopenharmony_ci if ((fds[fdi].events & POLLOUT) != 0 && (sendevent != 0)) { 2325195972f6Sopenharmony_ci fds[fdi].revents |= POLLOUT; 2326195972f6Sopenharmony_ci LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_pollscan: fd=%d ready for writing\n", fds[fdi].fd)); 2327195972f6Sopenharmony_ci } 2328195972f6Sopenharmony_ci /* See if netconn of this socket had an error */ 2329195972f6Sopenharmony_ci if (errevent != 0) { 2330195972f6Sopenharmony_ci /* POLLERR is output only. */ 2331195972f6Sopenharmony_ci fds[fdi].revents |= POLLERR; 2332195972f6Sopenharmony_ci LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_pollscan: fd=%d ready for exception\n", fds[fdi].fd)); 2333195972f6Sopenharmony_ci } 2334195972f6Sopenharmony_ci } else { 2335195972f6Sopenharmony_ci /* Not a valid socket */ 2336195972f6Sopenharmony_ci SYS_ARCH_UNPROTECT(lev); 2337195972f6Sopenharmony_ci /* POLLNVAL is output only. */ 2338195972f6Sopenharmony_ci fds[fdi].revents |= POLLNVAL; 2339195972f6Sopenharmony_ci return -1; 2340195972f6Sopenharmony_ci } 2341195972f6Sopenharmony_ci } 2342195972f6Sopenharmony_ci 2343195972f6Sopenharmony_ci /* Will return the number of structures that have events, 2344195972f6Sopenharmony_ci not the number of events. */ 2345195972f6Sopenharmony_ci if (fds[fdi].revents != 0) { 2346195972f6Sopenharmony_ci nready++; 2347195972f6Sopenharmony_ci } 2348195972f6Sopenharmony_ci } 2349195972f6Sopenharmony_ci 2350195972f6Sopenharmony_ci LWIP_ASSERT("nready >= 0", nready >= 0); 2351195972f6Sopenharmony_ci return nready; 2352195972f6Sopenharmony_ci} 2353195972f6Sopenharmony_ci 2354195972f6Sopenharmony_ci#if LWIP_NETCONN_FULLDUPLEX 2355195972f6Sopenharmony_ci/* Mark all sockets as used. 2356195972f6Sopenharmony_ci * 2357195972f6Sopenharmony_ci * All sockets are marked (and later unmarked), whether they are open or not. 2358195972f6Sopenharmony_ci * This is OK as lwip_pollscan aborts select when non-open sockets are found. 2359195972f6Sopenharmony_ci */ 2360195972f6Sopenharmony_cistatic void 2361195972f6Sopenharmony_cilwip_poll_inc_sockets_used(struct pollfd *fds, nfds_t nfds) 2362195972f6Sopenharmony_ci{ 2363195972f6Sopenharmony_ci nfds_t fdi; 2364195972f6Sopenharmony_ci 2365195972f6Sopenharmony_ci if(fds) { 2366195972f6Sopenharmony_ci /* Go through each struct pollfd in the array. */ 2367195972f6Sopenharmony_ci for (fdi = 0; fdi < nfds; fdi++) { 2368195972f6Sopenharmony_ci /* Increase the reference counter */ 2369195972f6Sopenharmony_ci tryget_socket_unconn(fds[fdi].fd); 2370195972f6Sopenharmony_ci } 2371195972f6Sopenharmony_ci } 2372195972f6Sopenharmony_ci} 2373195972f6Sopenharmony_ci 2374195972f6Sopenharmony_ci/* Let go all sockets that were marked as used when starting poll */ 2375195972f6Sopenharmony_cistatic void 2376195972f6Sopenharmony_cilwip_poll_dec_sockets_used(struct pollfd *fds, nfds_t nfds) 2377195972f6Sopenharmony_ci{ 2378195972f6Sopenharmony_ci nfds_t fdi; 2379195972f6Sopenharmony_ci 2380195972f6Sopenharmony_ci if(fds) { 2381195972f6Sopenharmony_ci /* Go through each struct pollfd in the array. */ 2382195972f6Sopenharmony_ci for (fdi = 0; fdi < nfds; fdi++) { 2383195972f6Sopenharmony_ci struct lwip_sock *sock = tryget_socket_unconn_nouse(fds[fdi].fd); 2384195972f6Sopenharmony_ci if (sock != NULL) { 2385195972f6Sopenharmony_ci done_socket(sock); 2386195972f6Sopenharmony_ci } 2387195972f6Sopenharmony_ci } 2388195972f6Sopenharmony_ci } 2389195972f6Sopenharmony_ci} 2390195972f6Sopenharmony_ci#else /* LWIP_NETCONN_FULLDUPLEX */ 2391195972f6Sopenharmony_ci#define lwip_poll_inc_sockets_used(fds, nfds) 2392195972f6Sopenharmony_ci#define lwip_poll_dec_sockets_used(fds, nfds) 2393195972f6Sopenharmony_ci#endif /* LWIP_NETCONN_FULLDUPLEX */ 2394195972f6Sopenharmony_ci 2395195972f6Sopenharmony_ciint 2396195972f6Sopenharmony_cilwip_poll(struct pollfd *fds, nfds_t nfds, int timeout) 2397195972f6Sopenharmony_ci{ 2398195972f6Sopenharmony_ci u32_t waitres = 0; 2399195972f6Sopenharmony_ci int nready; 2400195972f6Sopenharmony_ci u32_t msectimeout; 2401195972f6Sopenharmony_ci#if LWIP_NETCONN_SEM_PER_THREAD 2402195972f6Sopenharmony_ci int waited = 0; 2403195972f6Sopenharmony_ci#endif 2404195972f6Sopenharmony_ci 2405195972f6Sopenharmony_ci LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_poll(%p, %d, %d)\n", 2406195972f6Sopenharmony_ci (void*)fds, (int)nfds, timeout)); 2407195972f6Sopenharmony_ci LWIP_ERROR("lwip_poll: invalid fds", ((fds != NULL && nfds > 0) || (fds == NULL && nfds == 0)), 2408195972f6Sopenharmony_ci set_errno(EINVAL); return -1;); 2409195972f6Sopenharmony_ci 2410195972f6Sopenharmony_ci lwip_poll_inc_sockets_used(fds, nfds); 2411195972f6Sopenharmony_ci 2412195972f6Sopenharmony_ci /* Go through each struct pollfd to count number of structures 2413195972f6Sopenharmony_ci which currently match */ 2414195972f6Sopenharmony_ci nready = lwip_pollscan(fds, nfds, LWIP_POLLSCAN_CLEAR); 2415195972f6Sopenharmony_ci 2416195972f6Sopenharmony_ci if (nready < 0) { 2417195972f6Sopenharmony_ci lwip_poll_dec_sockets_used(fds, nfds); 2418195972f6Sopenharmony_ci return -1; 2419195972f6Sopenharmony_ci } 2420195972f6Sopenharmony_ci 2421195972f6Sopenharmony_ci /* If we don't have any current events, then suspend if we are supposed to */ 2422195972f6Sopenharmony_ci if (!nready) { 2423195972f6Sopenharmony_ci API_SELECT_CB_VAR_DECLARE(select_cb); 2424195972f6Sopenharmony_ci 2425195972f6Sopenharmony_ci if (timeout == 0) { 2426195972f6Sopenharmony_ci LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_poll: no timeout, returning 0\n")); 2427195972f6Sopenharmony_ci goto return_success; 2428195972f6Sopenharmony_ci } 2429195972f6Sopenharmony_ci API_SELECT_CB_VAR_ALLOC(select_cb, set_errno(EAGAIN); lwip_poll_dec_sockets_used(fds, nfds); return -1); 2430195972f6Sopenharmony_ci memset(&API_SELECT_CB_VAR_REF(select_cb), 0, sizeof(struct lwip_select_cb)); 2431195972f6Sopenharmony_ci 2432195972f6Sopenharmony_ci /* None ready: add our semaphore to list: 2433195972f6Sopenharmony_ci We don't actually need any dynamic memory. Our entry on the 2434195972f6Sopenharmony_ci list is only valid while we are in this function, so it's ok 2435195972f6Sopenharmony_ci to use local variables. */ 2436195972f6Sopenharmony_ci 2437195972f6Sopenharmony_ci API_SELECT_CB_VAR_REF(select_cb).poll_fds = fds; 2438195972f6Sopenharmony_ci API_SELECT_CB_VAR_REF(select_cb).poll_nfds = nfds; 2439195972f6Sopenharmony_ci#if LWIP_NETCONN_SEM_PER_THREAD 2440195972f6Sopenharmony_ci API_SELECT_CB_VAR_REF(select_cb).sem = LWIP_NETCONN_THREAD_SEM_GET(); 2441195972f6Sopenharmony_ci#else /* LWIP_NETCONN_SEM_PER_THREAD */ 2442195972f6Sopenharmony_ci if (sys_sem_new(&API_SELECT_CB_VAR_REF(select_cb).sem, 0) != ERR_OK) { 2443195972f6Sopenharmony_ci /* failed to create semaphore */ 2444195972f6Sopenharmony_ci set_errno(EAGAIN); 2445195972f6Sopenharmony_ci lwip_poll_dec_sockets_used(fds, nfds); 2446195972f6Sopenharmony_ci API_SELECT_CB_VAR_FREE(select_cb); 2447195972f6Sopenharmony_ci return -1; 2448195972f6Sopenharmony_ci } 2449195972f6Sopenharmony_ci#endif /* LWIP_NETCONN_SEM_PER_THREAD */ 2450195972f6Sopenharmony_ci 2451195972f6Sopenharmony_ci lwip_link_select_cb(&API_SELECT_CB_VAR_REF(select_cb)); 2452195972f6Sopenharmony_ci 2453195972f6Sopenharmony_ci /* Increase select_waiting for each socket we are interested in. 2454195972f6Sopenharmony_ci Also, check for events again: there could have been events between 2455195972f6Sopenharmony_ci the last scan (without us on the list) and putting us on the list! */ 2456195972f6Sopenharmony_ci nready = lwip_pollscan(fds, nfds, LWIP_POLLSCAN_INC_WAIT); 2457195972f6Sopenharmony_ci 2458195972f6Sopenharmony_ci if (!nready) { 2459195972f6Sopenharmony_ci /* Still none ready, just wait to be woken */ 2460195972f6Sopenharmony_ci if (timeout < 0) { 2461195972f6Sopenharmony_ci /* Wait forever */ 2462195972f6Sopenharmony_ci msectimeout = 0; 2463195972f6Sopenharmony_ci } else { 2464195972f6Sopenharmony_ci /* timeout == 0 would have been handled earlier. */ 2465195972f6Sopenharmony_ci LWIP_ASSERT("timeout > 0", timeout > 0); 2466195972f6Sopenharmony_ci msectimeout = timeout; 2467195972f6Sopenharmony_ci } 2468195972f6Sopenharmony_ci waitres = sys_arch_sem_wait(SELECT_SEM_PTR(API_SELECT_CB_VAR_REF(select_cb).sem), msectimeout); 2469195972f6Sopenharmony_ci#if LWIP_NETCONN_SEM_PER_THREAD 2470195972f6Sopenharmony_ci waited = 1; 2471195972f6Sopenharmony_ci#endif 2472195972f6Sopenharmony_ci } 2473195972f6Sopenharmony_ci 2474195972f6Sopenharmony_ci /* Decrease select_waiting for each socket we are interested in, 2475195972f6Sopenharmony_ci and check which events occurred while we waited. */ 2476195972f6Sopenharmony_ci nready = lwip_pollscan(fds, nfds, LWIP_POLLSCAN_DEC_WAIT); 2477195972f6Sopenharmony_ci 2478195972f6Sopenharmony_ci lwip_unlink_select_cb(&API_SELECT_CB_VAR_REF(select_cb)); 2479195972f6Sopenharmony_ci 2480195972f6Sopenharmony_ci#if LWIP_NETCONN_SEM_PER_THREAD 2481195972f6Sopenharmony_ci if (select_cb.sem_signalled && (!waited || (waitres == SYS_ARCH_TIMEOUT))) { 2482195972f6Sopenharmony_ci /* don't leave the thread-local semaphore signalled */ 2483195972f6Sopenharmony_ci sys_arch_sem_wait(API_SELECT_CB_VAR_REF(select_cb).sem, 1); 2484195972f6Sopenharmony_ci } 2485195972f6Sopenharmony_ci#else /* LWIP_NETCONN_SEM_PER_THREAD */ 2486195972f6Sopenharmony_ci sys_sem_free(&API_SELECT_CB_VAR_REF(select_cb).sem); 2487195972f6Sopenharmony_ci#endif /* LWIP_NETCONN_SEM_PER_THREAD */ 2488195972f6Sopenharmony_ci API_SELECT_CB_VAR_FREE(select_cb); 2489195972f6Sopenharmony_ci 2490195972f6Sopenharmony_ci if (nready < 0) { 2491195972f6Sopenharmony_ci /* This happens when a socket got closed while waiting */ 2492195972f6Sopenharmony_ci lwip_poll_dec_sockets_used(fds, nfds); 2493195972f6Sopenharmony_ci return -1; 2494195972f6Sopenharmony_ci } 2495195972f6Sopenharmony_ci 2496195972f6Sopenharmony_ci if (waitres == SYS_ARCH_TIMEOUT) { 2497195972f6Sopenharmony_ci /* Timeout */ 2498195972f6Sopenharmony_ci LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_poll: timeout expired\n")); 2499195972f6Sopenharmony_ci goto return_success; 2500195972f6Sopenharmony_ci } 2501195972f6Sopenharmony_ci } 2502195972f6Sopenharmony_ci 2503195972f6Sopenharmony_ci LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_poll: nready=%d\n", nready)); 2504195972f6Sopenharmony_cireturn_success: 2505195972f6Sopenharmony_ci lwip_poll_dec_sockets_used(fds, nfds); 2506195972f6Sopenharmony_ci set_errno(0); 2507195972f6Sopenharmony_ci return nready; 2508195972f6Sopenharmony_ci} 2509195972f6Sopenharmony_ci 2510195972f6Sopenharmony_ci/** 2511195972f6Sopenharmony_ci * Check whether event_callback should wake up a thread waiting in 2512195972f6Sopenharmony_ci * lwip_poll. 2513195972f6Sopenharmony_ci */ 2514195972f6Sopenharmony_cistatic int 2515195972f6Sopenharmony_cilwip_poll_should_wake(const struct lwip_select_cb *scb, int fd, int has_recvevent, int has_sendevent, int has_errevent) 2516195972f6Sopenharmony_ci{ 2517195972f6Sopenharmony_ci nfds_t fdi; 2518195972f6Sopenharmony_ci for (fdi = 0; fdi < scb->poll_nfds; fdi++) { 2519195972f6Sopenharmony_ci const struct pollfd *pollfd = &scb->poll_fds[fdi]; 2520195972f6Sopenharmony_ci if (pollfd->fd == fd) { 2521195972f6Sopenharmony_ci /* Do not update pollfd->revents right here; 2522195972f6Sopenharmony_ci that would be a data race because lwip_pollscan 2523195972f6Sopenharmony_ci accesses revents without protecting. */ 2524195972f6Sopenharmony_ci if (has_recvevent && (pollfd->events & POLLIN) != 0) { 2525195972f6Sopenharmony_ci return 1; 2526195972f6Sopenharmony_ci } 2527195972f6Sopenharmony_ci if (has_sendevent && (pollfd->events & POLLOUT) != 0) { 2528195972f6Sopenharmony_ci return 1; 2529195972f6Sopenharmony_ci } 2530195972f6Sopenharmony_ci if (has_errevent) { 2531195972f6Sopenharmony_ci /* POLLERR is output only. */ 2532195972f6Sopenharmony_ci return 1; 2533195972f6Sopenharmony_ci } 2534195972f6Sopenharmony_ci } 2535195972f6Sopenharmony_ci } 2536195972f6Sopenharmony_ci return 0; 2537195972f6Sopenharmony_ci} 2538195972f6Sopenharmony_ci#endif /* LWIP_SOCKET_POLL */ 2539195972f6Sopenharmony_ci 2540195972f6Sopenharmony_ci#if LWIP_SOCKET_SELECT || LWIP_SOCKET_POLL 2541195972f6Sopenharmony_ci/** 2542195972f6Sopenharmony_ci * Callback registered in the netconn layer for each socket-netconn. 2543195972f6Sopenharmony_ci * Processes recvevent (data available) and wakes up tasks waiting for select. 2544195972f6Sopenharmony_ci * 2545195972f6Sopenharmony_ci * @note for LWIP_TCPIP_CORE_LOCKING any caller of this function 2546195972f6Sopenharmony_ci * must have the core lock held when signaling the following events 2547195972f6Sopenharmony_ci * as they might cause select_list_cb to be checked: 2548195972f6Sopenharmony_ci * NETCONN_EVT_RCVPLUS 2549195972f6Sopenharmony_ci * NETCONN_EVT_SENDPLUS 2550195972f6Sopenharmony_ci * NETCONN_EVT_ERROR 2551195972f6Sopenharmony_ci * This requirement will be asserted in select_check_waiters() 2552195972f6Sopenharmony_ci */ 2553195972f6Sopenharmony_cistatic void 2554195972f6Sopenharmony_cievent_callback(struct netconn *conn, enum netconn_evt evt, u16_t len) 2555195972f6Sopenharmony_ci{ 2556195972f6Sopenharmony_ci int s, check_waiters; 2557195972f6Sopenharmony_ci struct lwip_sock *sock; 2558195972f6Sopenharmony_ci SYS_ARCH_DECL_PROTECT(lev); 2559195972f6Sopenharmony_ci 2560195972f6Sopenharmony_ci LWIP_UNUSED_ARG(len); 2561195972f6Sopenharmony_ci 2562195972f6Sopenharmony_ci /* Get socket */ 2563195972f6Sopenharmony_ci if (conn) { 2564195972f6Sopenharmony_ci s = conn->socket; 2565195972f6Sopenharmony_ci if (s < 0) { 2566195972f6Sopenharmony_ci /* Data comes in right away after an accept, even though 2567195972f6Sopenharmony_ci * the server task might not have created a new socket yet. 2568195972f6Sopenharmony_ci * Just count down (or up) if that's the case and we 2569195972f6Sopenharmony_ci * will use the data later. Note that only receive events 2570195972f6Sopenharmony_ci * can happen before the new socket is set up. */ 2571195972f6Sopenharmony_ci SYS_ARCH_PROTECT(lev); 2572195972f6Sopenharmony_ci if (conn->socket < 0) { 2573195972f6Sopenharmony_ci if (evt == NETCONN_EVT_RCVPLUS) { 2574195972f6Sopenharmony_ci /* conn->socket is -1 on initialization 2575195972f6Sopenharmony_ci lwip_accept adjusts sock->recvevent if conn->socket < -1 */ 2576195972f6Sopenharmony_ci conn->socket--; 2577195972f6Sopenharmony_ci } 2578195972f6Sopenharmony_ci SYS_ARCH_UNPROTECT(lev); 2579195972f6Sopenharmony_ci return; 2580195972f6Sopenharmony_ci } 2581195972f6Sopenharmony_ci s = conn->socket; 2582195972f6Sopenharmony_ci SYS_ARCH_UNPROTECT(lev); 2583195972f6Sopenharmony_ci } 2584195972f6Sopenharmony_ci 2585195972f6Sopenharmony_ci sock = get_socket(s); 2586195972f6Sopenharmony_ci if (!sock) { 2587195972f6Sopenharmony_ci return; 2588195972f6Sopenharmony_ci } 2589195972f6Sopenharmony_ci } else { 2590195972f6Sopenharmony_ci return; 2591195972f6Sopenharmony_ci } 2592195972f6Sopenharmony_ci 2593195972f6Sopenharmony_ci check_waiters = 1; 2594195972f6Sopenharmony_ci SYS_ARCH_PROTECT(lev); 2595195972f6Sopenharmony_ci /* Set event as required */ 2596195972f6Sopenharmony_ci switch (evt) { 2597195972f6Sopenharmony_ci case NETCONN_EVT_RCVPLUS: 2598195972f6Sopenharmony_ci sock->rcvevent++; 2599195972f6Sopenharmony_ci if (sock->rcvevent > 1) { 2600195972f6Sopenharmony_ci check_waiters = 0; 2601195972f6Sopenharmony_ci } 2602195972f6Sopenharmony_ci break; 2603195972f6Sopenharmony_ci case NETCONN_EVT_RCVMINUS: 2604195972f6Sopenharmony_ci sock->rcvevent--; 2605195972f6Sopenharmony_ci check_waiters = 0; 2606195972f6Sopenharmony_ci break; 2607195972f6Sopenharmony_ci case NETCONN_EVT_SENDPLUS: 2608195972f6Sopenharmony_ci if (sock->sendevent) { 2609195972f6Sopenharmony_ci check_waiters = 0; 2610195972f6Sopenharmony_ci } 2611195972f6Sopenharmony_ci sock->sendevent = 1; 2612195972f6Sopenharmony_ci break; 2613195972f6Sopenharmony_ci case NETCONN_EVT_SENDMINUS: 2614195972f6Sopenharmony_ci sock->sendevent = 0; 2615195972f6Sopenharmony_ci check_waiters = 0; 2616195972f6Sopenharmony_ci break; 2617195972f6Sopenharmony_ci case NETCONN_EVT_ERROR: 2618195972f6Sopenharmony_ci sock->errevent = 1; 2619195972f6Sopenharmony_ci break; 2620195972f6Sopenharmony_ci default: 2621195972f6Sopenharmony_ci LWIP_ASSERT("unknown event", 0); 2622195972f6Sopenharmony_ci break; 2623195972f6Sopenharmony_ci } 2624195972f6Sopenharmony_ci 2625195972f6Sopenharmony_ci if (sock->select_waiting && check_waiters) { 2626195972f6Sopenharmony_ci /* Save which events are active */ 2627195972f6Sopenharmony_ci int has_recvevent, has_sendevent, has_errevent; 2628195972f6Sopenharmony_ci has_recvevent = sock->rcvevent > 0; 2629195972f6Sopenharmony_ci has_sendevent = sock->sendevent != 0; 2630195972f6Sopenharmony_ci has_errevent = sock->errevent != 0; 2631195972f6Sopenharmony_ci SYS_ARCH_UNPROTECT(lev); 2632195972f6Sopenharmony_ci /* Check any select calls waiting on this socket */ 2633195972f6Sopenharmony_ci select_check_waiters(s, has_recvevent, has_sendevent, has_errevent); 2634195972f6Sopenharmony_ci } else { 2635195972f6Sopenharmony_ci SYS_ARCH_UNPROTECT(lev); 2636195972f6Sopenharmony_ci } 2637195972f6Sopenharmony_ci poll_check_waiters(s, check_waiters); 2638195972f6Sopenharmony_ci done_socket(sock); 2639195972f6Sopenharmony_ci} 2640195972f6Sopenharmony_ci 2641195972f6Sopenharmony_ci/** 2642195972f6Sopenharmony_ci * Check if any select waiters are waiting on this socket and its events 2643195972f6Sopenharmony_ci * 2644195972f6Sopenharmony_ci * @note on synchronization of select_cb_list: 2645195972f6Sopenharmony_ci * LWIP_TCPIP_CORE_LOCKING: the select_cb_list must only be accessed while holding 2646195972f6Sopenharmony_ci * the core lock. We do a single pass through the list and signal any waiters. 2647195972f6Sopenharmony_ci * Core lock should already be held when calling here!!!! 2648195972f6Sopenharmony_ci 2649195972f6Sopenharmony_ci * !LWIP_TCPIP_CORE_LOCKING: we use SYS_ARCH_PROTECT but unlock on each iteration 2650195972f6Sopenharmony_ci * of the loop, thus creating a possibility where a thread could modify the 2651195972f6Sopenharmony_ci * select_cb_list during our UNPROTECT/PROTECT. We use a generational counter to 2652195972f6Sopenharmony_ci * detect this change and restart the list walk. The list is expected to be small 2653195972f6Sopenharmony_ci */ 2654195972f6Sopenharmony_cistatic void select_check_waiters(int s, int has_recvevent, int has_sendevent, int has_errevent) 2655195972f6Sopenharmony_ci{ 2656195972f6Sopenharmony_ci struct lwip_select_cb *scb; 2657195972f6Sopenharmony_ci#if !LWIP_TCPIP_CORE_LOCKING 2658195972f6Sopenharmony_ci int last_select_cb_ctr; 2659195972f6Sopenharmony_ci SYS_ARCH_DECL_PROTECT(lev); 2660195972f6Sopenharmony_ci#endif /* !LWIP_TCPIP_CORE_LOCKING */ 2661195972f6Sopenharmony_ci 2662195972f6Sopenharmony_ci LWIP_ASSERT_CORE_LOCKED(); 2663195972f6Sopenharmony_ci 2664195972f6Sopenharmony_ci#if !LWIP_TCPIP_CORE_LOCKING 2665195972f6Sopenharmony_ci SYS_ARCH_PROTECT(lev); 2666195972f6Sopenharmony_ciagain: 2667195972f6Sopenharmony_ci /* remember the state of select_cb_list to detect changes */ 2668195972f6Sopenharmony_ci last_select_cb_ctr = select_cb_ctr; 2669195972f6Sopenharmony_ci#endif /* !LWIP_TCPIP_CORE_LOCKING */ 2670195972f6Sopenharmony_ci for (scb = select_cb_list; scb != NULL; scb = scb->next) { 2671195972f6Sopenharmony_ci if (scb->sem_signalled == 0) { 2672195972f6Sopenharmony_ci /* semaphore not signalled yet */ 2673195972f6Sopenharmony_ci int do_signal = 0; 2674195972f6Sopenharmony_ci#if LWIP_SOCKET_POLL 2675195972f6Sopenharmony_ci if (scb->poll_fds != NULL) { 2676195972f6Sopenharmony_ci do_signal = lwip_poll_should_wake(scb, s, has_recvevent, has_sendevent, has_errevent); 2677195972f6Sopenharmony_ci } 2678195972f6Sopenharmony_ci#endif /* LWIP_SOCKET_POLL */ 2679195972f6Sopenharmony_ci#if LWIP_SOCKET_SELECT && LWIP_SOCKET_POLL 2680195972f6Sopenharmony_ci else 2681195972f6Sopenharmony_ci#endif /* LWIP_SOCKET_SELECT && LWIP_SOCKET_POLL */ 2682195972f6Sopenharmony_ci#if LWIP_SOCKET_SELECT 2683195972f6Sopenharmony_ci { 2684195972f6Sopenharmony_ci /* Test this select call for our socket */ 2685195972f6Sopenharmony_ci if (has_recvevent) { 2686195972f6Sopenharmony_ci if (scb->readset && FD_ISSET(s, scb->readset)) { 2687195972f6Sopenharmony_ci do_signal = 1; 2688195972f6Sopenharmony_ci } 2689195972f6Sopenharmony_ci } 2690195972f6Sopenharmony_ci if (has_sendevent) { 2691195972f6Sopenharmony_ci if (!do_signal && scb->writeset && FD_ISSET(s, scb->writeset)) { 2692195972f6Sopenharmony_ci do_signal = 1; 2693195972f6Sopenharmony_ci } 2694195972f6Sopenharmony_ci } 2695195972f6Sopenharmony_ci if (has_errevent) { 2696195972f6Sopenharmony_ci if (!do_signal && scb->exceptset && FD_ISSET(s, scb->exceptset)) { 2697195972f6Sopenharmony_ci do_signal = 1; 2698195972f6Sopenharmony_ci } 2699195972f6Sopenharmony_ci } 2700195972f6Sopenharmony_ci } 2701195972f6Sopenharmony_ci#endif /* LWIP_SOCKET_SELECT */ 2702195972f6Sopenharmony_ci if (do_signal) { 2703195972f6Sopenharmony_ci scb->sem_signalled = 1; 2704195972f6Sopenharmony_ci /* For !LWIP_TCPIP_CORE_LOCKING, we don't call SYS_ARCH_UNPROTECT() before signaling 2705195972f6Sopenharmony_ci the semaphore, as this might lead to the select thread taking itself off the list, 2706195972f6Sopenharmony_ci invalidating the semaphore. */ 2707195972f6Sopenharmony_ci sys_sem_signal(SELECT_SEM_PTR(scb->sem)); 2708195972f6Sopenharmony_ci } 2709195972f6Sopenharmony_ci } 2710195972f6Sopenharmony_ci#if LWIP_TCPIP_CORE_LOCKING 2711195972f6Sopenharmony_ci } 2712195972f6Sopenharmony_ci#else 2713195972f6Sopenharmony_ci /* unlock interrupts with each step */ 2714195972f6Sopenharmony_ci SYS_ARCH_UNPROTECT(lev); 2715195972f6Sopenharmony_ci /* this makes sure interrupt protection time is short */ 2716195972f6Sopenharmony_ci SYS_ARCH_PROTECT(lev); 2717195972f6Sopenharmony_ci if (last_select_cb_ctr != select_cb_ctr) { 2718195972f6Sopenharmony_ci /* someone has changed select_cb_list, restart at the beginning */ 2719195972f6Sopenharmony_ci goto again; 2720195972f6Sopenharmony_ci } 2721195972f6Sopenharmony_ci /* remember the state of select_cb_list to detect changes */ 2722195972f6Sopenharmony_ci last_select_cb_ctr = select_cb_ctr; 2723195972f6Sopenharmony_ci } 2724195972f6Sopenharmony_ci SYS_ARCH_UNPROTECT(lev); 2725195972f6Sopenharmony_ci#endif 2726195972f6Sopenharmony_ci} 2727195972f6Sopenharmony_ci#endif /* LWIP_SOCKET_SELECT || LWIP_SOCKET_POLL */ 2728195972f6Sopenharmony_ci 2729195972f6Sopenharmony_ci/** 2730195972f6Sopenharmony_ci * Close one end of a full-duplex connection. 2731195972f6Sopenharmony_ci */ 2732195972f6Sopenharmony_ciint 2733195972f6Sopenharmony_cilwip_shutdown(int s, int how) 2734195972f6Sopenharmony_ci{ 2735195972f6Sopenharmony_ci struct lwip_sock *sock; 2736195972f6Sopenharmony_ci err_t err; 2737195972f6Sopenharmony_ci u8_t shut_rx = 0, shut_tx = 0; 2738195972f6Sopenharmony_ci 2739195972f6Sopenharmony_ci LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_shutdown(%d, how=%d)\n", s, how)); 2740195972f6Sopenharmony_ci 2741195972f6Sopenharmony_ci sock = get_socket(s); 2742195972f6Sopenharmony_ci if (!sock) { 2743195972f6Sopenharmony_ci return -1; 2744195972f6Sopenharmony_ci } 2745195972f6Sopenharmony_ci 2746195972f6Sopenharmony_ci if (sock->conn != NULL) { 2747195972f6Sopenharmony_ci if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_TCP) { 2748195972f6Sopenharmony_ci sock_set_errno(sock, EOPNOTSUPP); 2749195972f6Sopenharmony_ci done_socket(sock); 2750195972f6Sopenharmony_ci return -1; 2751195972f6Sopenharmony_ci } 2752195972f6Sopenharmony_ci } else { 2753195972f6Sopenharmony_ci sock_set_errno(sock, ENOTCONN); 2754195972f6Sopenharmony_ci done_socket(sock); 2755195972f6Sopenharmony_ci return -1; 2756195972f6Sopenharmony_ci } 2757195972f6Sopenharmony_ci 2758195972f6Sopenharmony_ci if (how == SHUT_RD) { 2759195972f6Sopenharmony_ci shut_rx = 1; 2760195972f6Sopenharmony_ci } else if (how == SHUT_WR) { 2761195972f6Sopenharmony_ci shut_tx = 1; 2762195972f6Sopenharmony_ci } else if (how == SHUT_RDWR) { 2763195972f6Sopenharmony_ci shut_rx = 1; 2764195972f6Sopenharmony_ci shut_tx = 1; 2765195972f6Sopenharmony_ci } else { 2766195972f6Sopenharmony_ci sock_set_errno(sock, EINVAL); 2767195972f6Sopenharmony_ci done_socket(sock); 2768195972f6Sopenharmony_ci return -1; 2769195972f6Sopenharmony_ci } 2770195972f6Sopenharmony_ci err = netconn_shutdown(sock->conn, shut_rx, shut_tx); 2771195972f6Sopenharmony_ci 2772195972f6Sopenharmony_ci sock_set_errno(sock, err_to_errno(err)); 2773195972f6Sopenharmony_ci done_socket(sock); 2774195972f6Sopenharmony_ci return (err == ERR_OK ? 0 : -1); 2775195972f6Sopenharmony_ci} 2776195972f6Sopenharmony_ci 2777195972f6Sopenharmony_cistatic int 2778195972f6Sopenharmony_cilwip_getaddrname(int s, struct sockaddr *name, socklen_t *namelen, u8_t local) 2779195972f6Sopenharmony_ci{ 2780195972f6Sopenharmony_ci struct lwip_sock *sock; 2781195972f6Sopenharmony_ci union sockaddr_aligned saddr; 2782195972f6Sopenharmony_ci ip_addr_t naddr; 2783195972f6Sopenharmony_ci u16_t port; 2784195972f6Sopenharmony_ci err_t err; 2785195972f6Sopenharmony_ci 2786195972f6Sopenharmony_ci sock = get_socket(s); 2787195972f6Sopenharmony_ci if (!sock) { 2788195972f6Sopenharmony_ci return -1; 2789195972f6Sopenharmony_ci } 2790195972f6Sopenharmony_ci 2791195972f6Sopenharmony_ci /* get the IP address and port */ 2792195972f6Sopenharmony_ci err = netconn_getaddr(sock->conn, &naddr, &port, local); 2793195972f6Sopenharmony_ci if (err != ERR_OK) { 2794195972f6Sopenharmony_ci sock_set_errno(sock, err_to_errno(err)); 2795195972f6Sopenharmony_ci done_socket(sock); 2796195972f6Sopenharmony_ci return -1; 2797195972f6Sopenharmony_ci } 2798195972f6Sopenharmony_ci 2799195972f6Sopenharmony_ci#if LWIP_IPV4 && LWIP_IPV6 2800195972f6Sopenharmony_ci /* Dual-stack: Map IPv4 addresses to IPv4 mapped IPv6 */ 2801195972f6Sopenharmony_ci if (NETCONNTYPE_ISIPV6(netconn_type(sock->conn)) && 2802195972f6Sopenharmony_ci IP_IS_V4_VAL(naddr)) { 2803195972f6Sopenharmony_ci ip4_2_ipv4_mapped_ipv6(ip_2_ip6(&naddr), ip_2_ip4(&naddr)); 2804195972f6Sopenharmony_ci IP_SET_TYPE_VAL(naddr, IPADDR_TYPE_V6); 2805195972f6Sopenharmony_ci } 2806195972f6Sopenharmony_ci#endif /* LWIP_IPV4 && LWIP_IPV6 */ 2807195972f6Sopenharmony_ci 2808195972f6Sopenharmony_ci IPADDR_PORT_TO_SOCKADDR(&saddr, &naddr, port); 2809195972f6Sopenharmony_ci 2810195972f6Sopenharmony_ci LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getaddrname(%d, addr=", s)); 2811195972f6Sopenharmony_ci ip_addr_debug_print_val(SOCKETS_DEBUG, naddr); 2812195972f6Sopenharmony_ci LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F")\n", port)); 2813195972f6Sopenharmony_ci 2814195972f6Sopenharmony_ci if (*namelen > saddr.sa.sa_len) { 2815195972f6Sopenharmony_ci *namelen = saddr.sa.sa_len; 2816195972f6Sopenharmony_ci } 2817195972f6Sopenharmony_ci MEMCPY(name, &saddr, *namelen); 2818195972f6Sopenharmony_ci 2819195972f6Sopenharmony_ci sock_set_errno(sock, 0); 2820195972f6Sopenharmony_ci done_socket(sock); 2821195972f6Sopenharmony_ci return 0; 2822195972f6Sopenharmony_ci} 2823195972f6Sopenharmony_ci 2824195972f6Sopenharmony_ciint 2825195972f6Sopenharmony_cilwip_getpeername(int s, struct sockaddr *name, socklen_t *namelen) 2826195972f6Sopenharmony_ci{ 2827195972f6Sopenharmony_ci return lwip_getaddrname(s, name, namelen, 0); 2828195972f6Sopenharmony_ci} 2829195972f6Sopenharmony_ci 2830195972f6Sopenharmony_ciint 2831195972f6Sopenharmony_cilwip_getsockname(int s, struct sockaddr *name, socklen_t *namelen) 2832195972f6Sopenharmony_ci{ 2833195972f6Sopenharmony_ci return lwip_getaddrname(s, name, namelen, 1); 2834195972f6Sopenharmony_ci} 2835195972f6Sopenharmony_ci 2836195972f6Sopenharmony_ciint 2837195972f6Sopenharmony_cilwip_getsockopt(int s, int level, int optname, void *optval, socklen_t *optlen) 2838195972f6Sopenharmony_ci{ 2839195972f6Sopenharmony_ci int err; 2840195972f6Sopenharmony_ci struct lwip_sock *sock = get_socket(s); 2841195972f6Sopenharmony_ci#if !LWIP_TCPIP_CORE_LOCKING 2842195972f6Sopenharmony_ci err_t cberr; 2843195972f6Sopenharmony_ci LWIP_SETGETSOCKOPT_DATA_VAR_DECLARE(data); 2844195972f6Sopenharmony_ci#endif /* !LWIP_TCPIP_CORE_LOCKING */ 2845195972f6Sopenharmony_ci 2846195972f6Sopenharmony_ci if (!sock) { 2847195972f6Sopenharmony_ci return -1; 2848195972f6Sopenharmony_ci } 2849195972f6Sopenharmony_ci 2850195972f6Sopenharmony_ci if ((NULL == optval) || (NULL == optlen)) { 2851195972f6Sopenharmony_ci sock_set_errno(sock, EFAULT); 2852195972f6Sopenharmony_ci done_socket(sock); 2853195972f6Sopenharmony_ci return -1; 2854195972f6Sopenharmony_ci } 2855195972f6Sopenharmony_ci 2856195972f6Sopenharmony_ci#if LWIP_TCPIP_CORE_LOCKING 2857195972f6Sopenharmony_ci /* core-locking can just call the -impl function */ 2858195972f6Sopenharmony_ci LOCK_TCPIP_CORE(); 2859195972f6Sopenharmony_ci err = lwip_getsockopt_impl(s, level, optname, optval, optlen); 2860195972f6Sopenharmony_ci UNLOCK_TCPIP_CORE(); 2861195972f6Sopenharmony_ci 2862195972f6Sopenharmony_ci#else /* LWIP_TCPIP_CORE_LOCKING */ 2863195972f6Sopenharmony_ci 2864195972f6Sopenharmony_ci#if LWIP_MPU_COMPATIBLE 2865195972f6Sopenharmony_ci /* MPU_COMPATIBLE copies the optval data, so check for max size here */ 2866195972f6Sopenharmony_ci if (*optlen > LWIP_SETGETSOCKOPT_MAXOPTLEN) { 2867195972f6Sopenharmony_ci sock_set_errno(sock, ENOBUFS); 2868195972f6Sopenharmony_ci done_socket(sock); 2869195972f6Sopenharmony_ci return -1; 2870195972f6Sopenharmony_ci } 2871195972f6Sopenharmony_ci#endif /* LWIP_MPU_COMPATIBLE */ 2872195972f6Sopenharmony_ci 2873195972f6Sopenharmony_ci LWIP_SETGETSOCKOPT_DATA_VAR_ALLOC(data, sock); 2874195972f6Sopenharmony_ci LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).s = s; 2875195972f6Sopenharmony_ci LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).level = level; 2876195972f6Sopenharmony_ci LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optname = optname; 2877195972f6Sopenharmony_ci LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optlen = *optlen; 2878195972f6Sopenharmony_ci#if !LWIP_MPU_COMPATIBLE 2879195972f6Sopenharmony_ci LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optval.p = optval; 2880195972f6Sopenharmony_ci#endif /* !LWIP_MPU_COMPATIBLE */ 2881195972f6Sopenharmony_ci LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).err = 0; 2882195972f6Sopenharmony_ci#if LWIP_NETCONN_SEM_PER_THREAD 2883195972f6Sopenharmony_ci LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).completed_sem = LWIP_NETCONN_THREAD_SEM_GET(); 2884195972f6Sopenharmony_ci#else 2885195972f6Sopenharmony_ci LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).completed_sem = &sock->conn->op_completed; 2886195972f6Sopenharmony_ci#endif 2887195972f6Sopenharmony_ci cberr = tcpip_callback(lwip_getsockopt_callback, &LWIP_SETGETSOCKOPT_DATA_VAR_REF(data)); 2888195972f6Sopenharmony_ci if (cberr != ERR_OK) { 2889195972f6Sopenharmony_ci LWIP_SETGETSOCKOPT_DATA_VAR_FREE(data); 2890195972f6Sopenharmony_ci sock_set_errno(sock, err_to_errno(cberr)); 2891195972f6Sopenharmony_ci done_socket(sock); 2892195972f6Sopenharmony_ci return -1; 2893195972f6Sopenharmony_ci } 2894195972f6Sopenharmony_ci sys_arch_sem_wait((sys_sem_t *)(LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).completed_sem), 0); 2895195972f6Sopenharmony_ci 2896195972f6Sopenharmony_ci /* write back optlen and optval */ 2897195972f6Sopenharmony_ci *optlen = LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optlen; 2898195972f6Sopenharmony_ci#if LWIP_MPU_COMPATIBLE 2899195972f6Sopenharmony_ci MEMCPY(optval, LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optval, 2900195972f6Sopenharmony_ci LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optlen); 2901195972f6Sopenharmony_ci#endif /* LWIP_MPU_COMPATIBLE */ 2902195972f6Sopenharmony_ci 2903195972f6Sopenharmony_ci /* maybe lwip_getsockopt_internal has changed err */ 2904195972f6Sopenharmony_ci err = LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).err; 2905195972f6Sopenharmony_ci LWIP_SETGETSOCKOPT_DATA_VAR_FREE(data); 2906195972f6Sopenharmony_ci#endif /* LWIP_TCPIP_CORE_LOCKING */ 2907195972f6Sopenharmony_ci 2908195972f6Sopenharmony_ci sock_set_errno(sock, err); 2909195972f6Sopenharmony_ci done_socket(sock); 2910195972f6Sopenharmony_ci return err ? -1 : 0; 2911195972f6Sopenharmony_ci} 2912195972f6Sopenharmony_ci 2913195972f6Sopenharmony_ci#if !LWIP_TCPIP_CORE_LOCKING 2914195972f6Sopenharmony_ci/** lwip_getsockopt_callback: only used without CORE_LOCKING 2915195972f6Sopenharmony_ci * to get into the tcpip_thread 2916195972f6Sopenharmony_ci */ 2917195972f6Sopenharmony_cistatic void 2918195972f6Sopenharmony_cilwip_getsockopt_callback(void *arg) 2919195972f6Sopenharmony_ci{ 2920195972f6Sopenharmony_ci struct lwip_setgetsockopt_data *data; 2921195972f6Sopenharmony_ci LWIP_ASSERT("arg != NULL", arg != NULL); 2922195972f6Sopenharmony_ci data = (struct lwip_setgetsockopt_data *)arg; 2923195972f6Sopenharmony_ci 2924195972f6Sopenharmony_ci data->err = lwip_getsockopt_impl(data->s, data->level, data->optname, 2925195972f6Sopenharmony_ci#if LWIP_MPU_COMPATIBLE 2926195972f6Sopenharmony_ci data->optval, 2927195972f6Sopenharmony_ci#else /* LWIP_MPU_COMPATIBLE */ 2928195972f6Sopenharmony_ci data->optval.p, 2929195972f6Sopenharmony_ci#endif /* LWIP_MPU_COMPATIBLE */ 2930195972f6Sopenharmony_ci &data->optlen); 2931195972f6Sopenharmony_ci 2932195972f6Sopenharmony_ci sys_sem_signal((sys_sem_t *)(data->completed_sem)); 2933195972f6Sopenharmony_ci} 2934195972f6Sopenharmony_ci#endif /* LWIP_TCPIP_CORE_LOCKING */ 2935195972f6Sopenharmony_ci 2936195972f6Sopenharmony_cistatic int 2937195972f6Sopenharmony_cilwip_sockopt_to_ipopt(int optname) 2938195972f6Sopenharmony_ci{ 2939195972f6Sopenharmony_ci /* Map SO_* values to our internal SOF_* values 2940195972f6Sopenharmony_ci * We should not rely on #defines in socket.h 2941195972f6Sopenharmony_ci * being in sync with ip.h. 2942195972f6Sopenharmony_ci */ 2943195972f6Sopenharmony_ci switch (optname) { 2944195972f6Sopenharmony_ci case SO_BROADCAST: 2945195972f6Sopenharmony_ci return SOF_BROADCAST; 2946195972f6Sopenharmony_ci case SO_KEEPALIVE: 2947195972f6Sopenharmony_ci return SOF_KEEPALIVE; 2948195972f6Sopenharmony_ci case SO_REUSEADDR: 2949195972f6Sopenharmony_ci return SOF_REUSEADDR; 2950195972f6Sopenharmony_ci default: 2951195972f6Sopenharmony_ci LWIP_ASSERT("Unknown socket option", 0); 2952195972f6Sopenharmony_ci return 0; 2953195972f6Sopenharmony_ci } 2954195972f6Sopenharmony_ci} 2955195972f6Sopenharmony_ci 2956195972f6Sopenharmony_ci/** lwip_getsockopt_impl: the actual implementation of getsockopt: 2957195972f6Sopenharmony_ci * same argument as lwip_getsockopt, either called directly or through callback 2958195972f6Sopenharmony_ci */ 2959195972f6Sopenharmony_cistatic int 2960195972f6Sopenharmony_cilwip_getsockopt_impl(int s, int level, int optname, void *optval, socklen_t *optlen) 2961195972f6Sopenharmony_ci{ 2962195972f6Sopenharmony_ci int err = 0; 2963195972f6Sopenharmony_ci struct lwip_sock *sock = tryget_socket(s); 2964195972f6Sopenharmony_ci if (!sock) { 2965195972f6Sopenharmony_ci return EBADF; 2966195972f6Sopenharmony_ci } 2967195972f6Sopenharmony_ci 2968195972f6Sopenharmony_ci#ifdef LWIP_HOOK_SOCKETS_GETSOCKOPT 2969195972f6Sopenharmony_ci if (LWIP_HOOK_SOCKETS_GETSOCKOPT(s, sock, level, optname, optval, optlen, &err)) { 2970195972f6Sopenharmony_ci return err; 2971195972f6Sopenharmony_ci } 2972195972f6Sopenharmony_ci#endif 2973195972f6Sopenharmony_ci 2974195972f6Sopenharmony_ci switch (level) { 2975195972f6Sopenharmony_ci 2976195972f6Sopenharmony_ci /* Level: SOL_SOCKET */ 2977195972f6Sopenharmony_ci case SOL_SOCKET: 2978195972f6Sopenharmony_ci switch (optname) { 2979195972f6Sopenharmony_ci 2980195972f6Sopenharmony_ci#if LWIP_TCP 2981195972f6Sopenharmony_ci case SO_ACCEPTCONN: 2982195972f6Sopenharmony_ci LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, *optlen, int); 2983195972f6Sopenharmony_ci if (NETCONNTYPE_GROUP(sock->conn->type) != NETCONN_TCP) { 2984195972f6Sopenharmony_ci done_socket(sock); 2985195972f6Sopenharmony_ci return ENOPROTOOPT; 2986195972f6Sopenharmony_ci } 2987195972f6Sopenharmony_ci if ((sock->conn->pcb.tcp != NULL) && (sock->conn->pcb.tcp->state == LISTEN)) { 2988195972f6Sopenharmony_ci *(int *)optval = 1; 2989195972f6Sopenharmony_ci } else { 2990195972f6Sopenharmony_ci *(int *)optval = 0; 2991195972f6Sopenharmony_ci } 2992195972f6Sopenharmony_ci break; 2993195972f6Sopenharmony_ci#endif /* LWIP_TCP */ 2994195972f6Sopenharmony_ci 2995195972f6Sopenharmony_ci /* The option flags */ 2996195972f6Sopenharmony_ci case SO_BROADCAST: 2997195972f6Sopenharmony_ci case SO_KEEPALIVE: 2998195972f6Sopenharmony_ci#if SO_REUSE 2999195972f6Sopenharmony_ci case SO_REUSEADDR: 3000195972f6Sopenharmony_ci#endif /* SO_REUSE */ 3001195972f6Sopenharmony_ci if ((optname == SO_BROADCAST) && 3002195972f6Sopenharmony_ci (NETCONNTYPE_GROUP(sock->conn->type) != NETCONN_UDP)) { 3003195972f6Sopenharmony_ci done_socket(sock); 3004195972f6Sopenharmony_ci return ENOPROTOOPT; 3005195972f6Sopenharmony_ci } 3006195972f6Sopenharmony_ci 3007195972f6Sopenharmony_ci optname = lwip_sockopt_to_ipopt(optname); 3008195972f6Sopenharmony_ci 3009195972f6Sopenharmony_ci LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, *optlen, int); 3010195972f6Sopenharmony_ci *(int *)optval = ip_get_option(sock->conn->pcb.ip, optname); 3011195972f6Sopenharmony_ci LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, optname=0x%x, ..) = %s\n", 3012195972f6Sopenharmony_ci s, optname, (*(int *)optval ? "on" : "off"))); 3013195972f6Sopenharmony_ci break; 3014195972f6Sopenharmony_ci 3015195972f6Sopenharmony_ci case SO_TYPE: 3016195972f6Sopenharmony_ci LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, *optlen, int); 3017195972f6Sopenharmony_ci switch (NETCONNTYPE_GROUP(netconn_type(sock->conn))) { 3018195972f6Sopenharmony_ci case NETCONN_RAW: 3019195972f6Sopenharmony_ci *(int *)optval = SOCK_RAW; 3020195972f6Sopenharmony_ci break; 3021195972f6Sopenharmony_ci case NETCONN_TCP: 3022195972f6Sopenharmony_ci *(int *)optval = SOCK_STREAM; 3023195972f6Sopenharmony_ci break; 3024195972f6Sopenharmony_ci case NETCONN_UDP: 3025195972f6Sopenharmony_ci *(int *)optval = SOCK_DGRAM; 3026195972f6Sopenharmony_ci break; 3027195972f6Sopenharmony_ci default: /* unrecognized socket type */ 3028195972f6Sopenharmony_ci *(int *)optval = netconn_type(sock->conn); 3029195972f6Sopenharmony_ci LWIP_DEBUGF(SOCKETS_DEBUG, 3030195972f6Sopenharmony_ci ("lwip_getsockopt(%d, SOL_SOCKET, SO_TYPE): unrecognized socket type %d\n", 3031195972f6Sopenharmony_ci s, *(int *)optval)); 3032195972f6Sopenharmony_ci } /* switch (netconn_type(sock->conn)) */ 3033195972f6Sopenharmony_ci LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, SO_TYPE) = %d\n", 3034195972f6Sopenharmony_ci s, *(int *)optval)); 3035195972f6Sopenharmony_ci break; 3036195972f6Sopenharmony_ci 3037195972f6Sopenharmony_ci case SO_ERROR: 3038195972f6Sopenharmony_ci LWIP_SOCKOPT_CHECK_OPTLEN(sock, *optlen, int); 3039195972f6Sopenharmony_ci *(int *)optval = err_to_errno(netconn_err(sock->conn)); 3040195972f6Sopenharmony_ci LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, SO_ERROR) = %d\n", 3041195972f6Sopenharmony_ci s, *(int *)optval)); 3042195972f6Sopenharmony_ci break; 3043195972f6Sopenharmony_ci 3044195972f6Sopenharmony_ci#if LWIP_SO_SNDTIMEO 3045195972f6Sopenharmony_ci case SO_SNDTIMEO: 3046195972f6Sopenharmony_ci LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, *optlen, LWIP_SO_SNDRCVTIMEO_OPTTYPE); 3047195972f6Sopenharmony_ci LWIP_SO_SNDRCVTIMEO_SET(optval, netconn_get_sendtimeout(sock->conn)); 3048195972f6Sopenharmony_ci break; 3049195972f6Sopenharmony_ci#endif /* LWIP_SO_SNDTIMEO */ 3050195972f6Sopenharmony_ci#if LWIP_SO_RCVTIMEO 3051195972f6Sopenharmony_ci case SO_RCVTIMEO: 3052195972f6Sopenharmony_ci LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, *optlen, LWIP_SO_SNDRCVTIMEO_OPTTYPE); 3053195972f6Sopenharmony_ci LWIP_SO_SNDRCVTIMEO_SET(optval, netconn_get_recvtimeout(sock->conn)); 3054195972f6Sopenharmony_ci break; 3055195972f6Sopenharmony_ci#endif /* LWIP_SO_RCVTIMEO */ 3056195972f6Sopenharmony_ci#if LWIP_SO_RCVBUF 3057195972f6Sopenharmony_ci case SO_RCVBUF: 3058195972f6Sopenharmony_ci LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, *optlen, int); 3059195972f6Sopenharmony_ci *(int *)optval = netconn_get_recvbufsize(sock->conn); 3060195972f6Sopenharmony_ci break; 3061195972f6Sopenharmony_ci#endif /* LWIP_SO_RCVBUF */ 3062195972f6Sopenharmony_ci#if LWIP_SO_LINGER 3063195972f6Sopenharmony_ci case SO_LINGER: { 3064195972f6Sopenharmony_ci s16_t conn_linger; 3065195972f6Sopenharmony_ci struct linger *linger = (struct linger *)optval; 3066195972f6Sopenharmony_ci LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, *optlen, struct linger); 3067195972f6Sopenharmony_ci conn_linger = sock->conn->linger; 3068195972f6Sopenharmony_ci if (conn_linger >= 0) { 3069195972f6Sopenharmony_ci linger->l_onoff = 1; 3070195972f6Sopenharmony_ci linger->l_linger = (int)conn_linger; 3071195972f6Sopenharmony_ci } else { 3072195972f6Sopenharmony_ci linger->l_onoff = 0; 3073195972f6Sopenharmony_ci linger->l_linger = 0; 3074195972f6Sopenharmony_ci } 3075195972f6Sopenharmony_ci } 3076195972f6Sopenharmony_ci break; 3077195972f6Sopenharmony_ci#endif /* LWIP_SO_LINGER */ 3078195972f6Sopenharmony_ci#if LWIP_UDP 3079195972f6Sopenharmony_ci case SO_NO_CHECK: 3080195972f6Sopenharmony_ci LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, *optlen, int, NETCONN_UDP); 3081195972f6Sopenharmony_ci#if LWIP_UDPLITE 3082195972f6Sopenharmony_ci if (udp_is_flag_set(sock->conn->pcb.udp, UDP_FLAGS_UDPLITE)) { 3083195972f6Sopenharmony_ci /* this flag is only available for UDP, not for UDP lite */ 3084195972f6Sopenharmony_ci done_socket(sock); 3085195972f6Sopenharmony_ci return EAFNOSUPPORT; 3086195972f6Sopenharmony_ci } 3087195972f6Sopenharmony_ci#endif /* LWIP_UDPLITE */ 3088195972f6Sopenharmony_ci *(int *)optval = udp_is_flag_set(sock->conn->pcb.udp, UDP_FLAGS_NOCHKSUM) ? 1 : 0; 3089195972f6Sopenharmony_ci break; 3090195972f6Sopenharmony_ci#endif /* LWIP_UDP*/ 3091195972f6Sopenharmony_ci default: 3092195972f6Sopenharmony_ci LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, UNIMPL: optname=0x%x, ..)\n", 3093195972f6Sopenharmony_ci s, optname)); 3094195972f6Sopenharmony_ci err = ENOPROTOOPT; 3095195972f6Sopenharmony_ci break; 3096195972f6Sopenharmony_ci } /* switch (optname) */ 3097195972f6Sopenharmony_ci break; 3098195972f6Sopenharmony_ci 3099195972f6Sopenharmony_ci /* Level: IPPROTO_IP */ 3100195972f6Sopenharmony_ci case IPPROTO_IP: 3101195972f6Sopenharmony_ci switch (optname) { 3102195972f6Sopenharmony_ci case IP_TTL: 3103195972f6Sopenharmony_ci LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, *optlen, int); 3104195972f6Sopenharmony_ci *(int *)optval = sock->conn->pcb.ip->ttl; 3105195972f6Sopenharmony_ci LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_TTL) = %d\n", 3106195972f6Sopenharmony_ci s, *(int *)optval)); 3107195972f6Sopenharmony_ci break; 3108195972f6Sopenharmony_ci case IP_TOS: 3109195972f6Sopenharmony_ci LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, *optlen, int); 3110195972f6Sopenharmony_ci *(int *)optval = sock->conn->pcb.ip->tos; 3111195972f6Sopenharmony_ci LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_TOS) = %d\n", 3112195972f6Sopenharmony_ci s, *(int *)optval)); 3113195972f6Sopenharmony_ci break; 3114195972f6Sopenharmony_ci#if LWIP_IPV4 && LWIP_MULTICAST_TX_OPTIONS && LWIP_UDP 3115195972f6Sopenharmony_ci case IP_MULTICAST_TTL: 3116195972f6Sopenharmony_ci LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, *optlen, u8_t); 3117195972f6Sopenharmony_ci if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_UDP) { 3118195972f6Sopenharmony_ci done_socket(sock); 3119195972f6Sopenharmony_ci return ENOPROTOOPT; 3120195972f6Sopenharmony_ci } 3121195972f6Sopenharmony_ci *(u8_t *)optval = udp_get_multicast_ttl(sock->conn->pcb.udp); 3122195972f6Sopenharmony_ci LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_MULTICAST_TTL) = %d\n", 3123195972f6Sopenharmony_ci s, *(int *)optval)); 3124195972f6Sopenharmony_ci break; 3125195972f6Sopenharmony_ci case IP_MULTICAST_IF: 3126195972f6Sopenharmony_ci LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, *optlen, struct in_addr); 3127195972f6Sopenharmony_ci if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_UDP) { 3128195972f6Sopenharmony_ci done_socket(sock); 3129195972f6Sopenharmony_ci return ENOPROTOOPT; 3130195972f6Sopenharmony_ci } 3131195972f6Sopenharmony_ci inet_addr_from_ip4addr((struct in_addr *)optval, udp_get_multicast_netif_addr(sock->conn->pcb.udp)); 3132195972f6Sopenharmony_ci LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_MULTICAST_IF) = 0x%"X32_F"\n", 3133195972f6Sopenharmony_ci s, *(u32_t *)optval)); 3134195972f6Sopenharmony_ci break; 3135195972f6Sopenharmony_ci case IP_MULTICAST_LOOP: 3136195972f6Sopenharmony_ci LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, *optlen, u8_t); 3137195972f6Sopenharmony_ci if ((sock->conn->pcb.udp->flags & UDP_FLAGS_MULTICAST_LOOP) != 0) { 3138195972f6Sopenharmony_ci *(u8_t *)optval = 1; 3139195972f6Sopenharmony_ci } else { 3140195972f6Sopenharmony_ci *(u8_t *)optval = 0; 3141195972f6Sopenharmony_ci } 3142195972f6Sopenharmony_ci LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_MULTICAST_LOOP) = %d\n", 3143195972f6Sopenharmony_ci s, *(int *)optval)); 3144195972f6Sopenharmony_ci break; 3145195972f6Sopenharmony_ci#endif /* LWIP_IPV4 && LWIP_MULTICAST_TX_OPTIONS && LWIP_UDP */ 3146195972f6Sopenharmony_ci default: 3147195972f6Sopenharmony_ci LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, UNIMPL: optname=0x%x, ..)\n", 3148195972f6Sopenharmony_ci s, optname)); 3149195972f6Sopenharmony_ci err = ENOPROTOOPT; 3150195972f6Sopenharmony_ci break; 3151195972f6Sopenharmony_ci } /* switch (optname) */ 3152195972f6Sopenharmony_ci break; 3153195972f6Sopenharmony_ci 3154195972f6Sopenharmony_ci#if LWIP_TCP 3155195972f6Sopenharmony_ci /* Level: IPPROTO_TCP */ 3156195972f6Sopenharmony_ci case IPPROTO_TCP: 3157195972f6Sopenharmony_ci /* Special case: all IPPROTO_TCP option take an int */ 3158195972f6Sopenharmony_ci LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, *optlen, int, NETCONN_TCP); 3159195972f6Sopenharmony_ci if (sock->conn->pcb.tcp->state == LISTEN) { 3160195972f6Sopenharmony_ci done_socket(sock); 3161195972f6Sopenharmony_ci return EINVAL; 3162195972f6Sopenharmony_ci } 3163195972f6Sopenharmony_ci switch (optname) { 3164195972f6Sopenharmony_ci case TCP_NODELAY: 3165195972f6Sopenharmony_ci *(int *)optval = tcp_nagle_disabled(sock->conn->pcb.tcp); 3166195972f6Sopenharmony_ci LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_TCP, TCP_NODELAY) = %s\n", 3167195972f6Sopenharmony_ci s, (*(int *)optval) ? "on" : "off") ); 3168195972f6Sopenharmony_ci break; 3169195972f6Sopenharmony_ci case TCP_KEEPALIVE: 3170195972f6Sopenharmony_ci *(int *)optval = (int)sock->conn->pcb.tcp->keep_idle; 3171195972f6Sopenharmony_ci LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_TCP, TCP_KEEPALIVE) = %d\n", 3172195972f6Sopenharmony_ci s, *(int *)optval)); 3173195972f6Sopenharmony_ci break; 3174195972f6Sopenharmony_ci 3175195972f6Sopenharmony_ci#if LWIP_TCP_KEEPALIVE 3176195972f6Sopenharmony_ci case TCP_KEEPIDLE: 3177195972f6Sopenharmony_ci *(int *)optval = (int)(sock->conn->pcb.tcp->keep_idle / 1000); 3178195972f6Sopenharmony_ci LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_TCP, TCP_KEEPIDLE) = %d\n", 3179195972f6Sopenharmony_ci s, *(int *)optval)); 3180195972f6Sopenharmony_ci break; 3181195972f6Sopenharmony_ci case TCP_KEEPINTVL: 3182195972f6Sopenharmony_ci *(int *)optval = (int)(sock->conn->pcb.tcp->keep_intvl / 1000); 3183195972f6Sopenharmony_ci LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_TCP, TCP_KEEPINTVL) = %d\n", 3184195972f6Sopenharmony_ci s, *(int *)optval)); 3185195972f6Sopenharmony_ci break; 3186195972f6Sopenharmony_ci case TCP_KEEPCNT: 3187195972f6Sopenharmony_ci *(int *)optval = (int)sock->conn->pcb.tcp->keep_cnt; 3188195972f6Sopenharmony_ci LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_TCP, TCP_KEEPCNT) = %d\n", 3189195972f6Sopenharmony_ci s, *(int *)optval)); 3190195972f6Sopenharmony_ci break; 3191195972f6Sopenharmony_ci#endif /* LWIP_TCP_KEEPALIVE */ 3192195972f6Sopenharmony_ci default: 3193195972f6Sopenharmony_ci LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_TCP, UNIMPL: optname=0x%x, ..)\n", 3194195972f6Sopenharmony_ci s, optname)); 3195195972f6Sopenharmony_ci err = ENOPROTOOPT; 3196195972f6Sopenharmony_ci break; 3197195972f6Sopenharmony_ci } /* switch (optname) */ 3198195972f6Sopenharmony_ci break; 3199195972f6Sopenharmony_ci#endif /* LWIP_TCP */ 3200195972f6Sopenharmony_ci 3201195972f6Sopenharmony_ci#if LWIP_IPV6 3202195972f6Sopenharmony_ci /* Level: IPPROTO_IPV6 */ 3203195972f6Sopenharmony_ci case IPPROTO_IPV6: 3204195972f6Sopenharmony_ci switch (optname) { 3205195972f6Sopenharmony_ci case IPV6_V6ONLY: 3206195972f6Sopenharmony_ci LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, *optlen, int); 3207195972f6Sopenharmony_ci *(int *)optval = (netconn_get_ipv6only(sock->conn) ? 1 : 0); 3208195972f6Sopenharmony_ci LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IPV6, IPV6_V6ONLY) = %d\n", 3209195972f6Sopenharmony_ci s, *(int *)optval)); 3210195972f6Sopenharmony_ci break; 3211195972f6Sopenharmony_ci default: 3212195972f6Sopenharmony_ci LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IPV6, UNIMPL: optname=0x%x, ..)\n", 3213195972f6Sopenharmony_ci s, optname)); 3214195972f6Sopenharmony_ci err = ENOPROTOOPT; 3215195972f6Sopenharmony_ci break; 3216195972f6Sopenharmony_ci } /* switch (optname) */ 3217195972f6Sopenharmony_ci break; 3218195972f6Sopenharmony_ci#endif /* LWIP_IPV6 */ 3219195972f6Sopenharmony_ci 3220195972f6Sopenharmony_ci#if LWIP_UDP && LWIP_UDPLITE 3221195972f6Sopenharmony_ci /* Level: IPPROTO_UDPLITE */ 3222195972f6Sopenharmony_ci case IPPROTO_UDPLITE: 3223195972f6Sopenharmony_ci /* Special case: all IPPROTO_UDPLITE option take an int */ 3224195972f6Sopenharmony_ci LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, *optlen, int); 3225195972f6Sopenharmony_ci /* If this is no UDP lite socket, ignore any options. */ 3226195972f6Sopenharmony_ci if (!NETCONNTYPE_ISUDPLITE(netconn_type(sock->conn))) { 3227195972f6Sopenharmony_ci done_socket(sock); 3228195972f6Sopenharmony_ci return ENOPROTOOPT; 3229195972f6Sopenharmony_ci } 3230195972f6Sopenharmony_ci switch (optname) { 3231195972f6Sopenharmony_ci case UDPLITE_SEND_CSCOV: 3232195972f6Sopenharmony_ci *(int *)optval = sock->conn->pcb.udp->chksum_len_tx; 3233195972f6Sopenharmony_ci LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_UDPLITE, UDPLITE_SEND_CSCOV) = %d\n", 3234195972f6Sopenharmony_ci s, (*(int *)optval)) ); 3235195972f6Sopenharmony_ci break; 3236195972f6Sopenharmony_ci case UDPLITE_RECV_CSCOV: 3237195972f6Sopenharmony_ci *(int *)optval = sock->conn->pcb.udp->chksum_len_rx; 3238195972f6Sopenharmony_ci LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_UDPLITE, UDPLITE_RECV_CSCOV) = %d\n", 3239195972f6Sopenharmony_ci s, (*(int *)optval)) ); 3240195972f6Sopenharmony_ci break; 3241195972f6Sopenharmony_ci default: 3242195972f6Sopenharmony_ci LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_UDPLITE, UNIMPL: optname=0x%x, ..)\n", 3243195972f6Sopenharmony_ci s, optname)); 3244195972f6Sopenharmony_ci err = ENOPROTOOPT; 3245195972f6Sopenharmony_ci break; 3246195972f6Sopenharmony_ci } /* switch (optname) */ 3247195972f6Sopenharmony_ci break; 3248195972f6Sopenharmony_ci#endif /* LWIP_UDP */ 3249195972f6Sopenharmony_ci /* Level: IPPROTO_RAW */ 3250195972f6Sopenharmony_ci case IPPROTO_RAW: 3251195972f6Sopenharmony_ci switch (optname) { 3252195972f6Sopenharmony_ci#if LWIP_IPV6 && LWIP_RAW 3253195972f6Sopenharmony_ci case IPV6_CHECKSUM: 3254195972f6Sopenharmony_ci LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, *optlen, int, NETCONN_RAW); 3255195972f6Sopenharmony_ci if (sock->conn->pcb.raw->chksum_reqd == 0) { 3256195972f6Sopenharmony_ci *(int *)optval = -1; 3257195972f6Sopenharmony_ci } else { 3258195972f6Sopenharmony_ci *(int *)optval = sock->conn->pcb.raw->chksum_offset; 3259195972f6Sopenharmony_ci } 3260195972f6Sopenharmony_ci LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_RAW, IPV6_CHECKSUM) = %d\n", 3261195972f6Sopenharmony_ci s, (*(int *)optval)) ); 3262195972f6Sopenharmony_ci break; 3263195972f6Sopenharmony_ci#endif /* LWIP_IPV6 && LWIP_RAW */ 3264195972f6Sopenharmony_ci default: 3265195972f6Sopenharmony_ci LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_RAW, UNIMPL: optname=0x%x, ..)\n", 3266195972f6Sopenharmony_ci s, optname)); 3267195972f6Sopenharmony_ci err = ENOPROTOOPT; 3268195972f6Sopenharmony_ci break; 3269195972f6Sopenharmony_ci } /* switch (optname) */ 3270195972f6Sopenharmony_ci break; 3271195972f6Sopenharmony_ci default: 3272195972f6Sopenharmony_ci LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, level=0x%x, UNIMPL: optname=0x%x, ..)\n", 3273195972f6Sopenharmony_ci s, level, optname)); 3274195972f6Sopenharmony_ci err = ENOPROTOOPT; 3275195972f6Sopenharmony_ci break; 3276195972f6Sopenharmony_ci } /* switch (level) */ 3277195972f6Sopenharmony_ci 3278195972f6Sopenharmony_ci done_socket(sock); 3279195972f6Sopenharmony_ci return err; 3280195972f6Sopenharmony_ci} 3281195972f6Sopenharmony_ci 3282195972f6Sopenharmony_ciint 3283195972f6Sopenharmony_cilwip_setsockopt(int s, int level, int optname, const void *optval, socklen_t optlen) 3284195972f6Sopenharmony_ci{ 3285195972f6Sopenharmony_ci int err = 0; 3286195972f6Sopenharmony_ci struct lwip_sock *sock = get_socket(s); 3287195972f6Sopenharmony_ci#if !LWIP_TCPIP_CORE_LOCKING 3288195972f6Sopenharmony_ci err_t cberr; 3289195972f6Sopenharmony_ci LWIP_SETGETSOCKOPT_DATA_VAR_DECLARE(data); 3290195972f6Sopenharmony_ci#endif /* !LWIP_TCPIP_CORE_LOCKING */ 3291195972f6Sopenharmony_ci 3292195972f6Sopenharmony_ci if (!sock) { 3293195972f6Sopenharmony_ci return -1; 3294195972f6Sopenharmony_ci } 3295195972f6Sopenharmony_ci 3296195972f6Sopenharmony_ci if (NULL == optval) { 3297195972f6Sopenharmony_ci sock_set_errno(sock, EFAULT); 3298195972f6Sopenharmony_ci done_socket(sock); 3299195972f6Sopenharmony_ci return -1; 3300195972f6Sopenharmony_ci } 3301195972f6Sopenharmony_ci 3302195972f6Sopenharmony_ci#if LWIP_TCPIP_CORE_LOCKING 3303195972f6Sopenharmony_ci /* core-locking can just call the -impl function */ 3304195972f6Sopenharmony_ci LOCK_TCPIP_CORE(); 3305195972f6Sopenharmony_ci err = lwip_setsockopt_impl(s, level, optname, optval, optlen); 3306195972f6Sopenharmony_ci UNLOCK_TCPIP_CORE(); 3307195972f6Sopenharmony_ci#if LWIP_LOWPOWER 3308195972f6Sopenharmony_ci tcpip_send_msg_na(LOW_NON_BLOCK); 3309195972f6Sopenharmony_ci#endif 3310195972f6Sopenharmony_ci 3311195972f6Sopenharmony_ci#else /* LWIP_TCPIP_CORE_LOCKING */ 3312195972f6Sopenharmony_ci 3313195972f6Sopenharmony_ci#if LWIP_MPU_COMPATIBLE 3314195972f6Sopenharmony_ci /* MPU_COMPATIBLE copies the optval data, so check for max size here */ 3315195972f6Sopenharmony_ci if (optlen > LWIP_SETGETSOCKOPT_MAXOPTLEN) { 3316195972f6Sopenharmony_ci sock_set_errno(sock, ENOBUFS); 3317195972f6Sopenharmony_ci done_socket(sock); 3318195972f6Sopenharmony_ci return -1; 3319195972f6Sopenharmony_ci } 3320195972f6Sopenharmony_ci#endif /* LWIP_MPU_COMPATIBLE */ 3321195972f6Sopenharmony_ci 3322195972f6Sopenharmony_ci LWIP_SETGETSOCKOPT_DATA_VAR_ALLOC(data, sock); 3323195972f6Sopenharmony_ci LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).s = s; 3324195972f6Sopenharmony_ci LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).level = level; 3325195972f6Sopenharmony_ci LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optname = optname; 3326195972f6Sopenharmony_ci LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optlen = optlen; 3327195972f6Sopenharmony_ci#if LWIP_MPU_COMPATIBLE 3328195972f6Sopenharmony_ci MEMCPY(LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optval, optval, optlen); 3329195972f6Sopenharmony_ci#else /* LWIP_MPU_COMPATIBLE */ 3330195972f6Sopenharmony_ci LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optval.pc = (const void *)optval; 3331195972f6Sopenharmony_ci#endif /* LWIP_MPU_COMPATIBLE */ 3332195972f6Sopenharmony_ci LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).err = 0; 3333195972f6Sopenharmony_ci#if LWIP_NETCONN_SEM_PER_THREAD 3334195972f6Sopenharmony_ci LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).completed_sem = LWIP_NETCONN_THREAD_SEM_GET(); 3335195972f6Sopenharmony_ci#else 3336195972f6Sopenharmony_ci LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).completed_sem = &sock->conn->op_completed; 3337195972f6Sopenharmony_ci#endif 3338195972f6Sopenharmony_ci cberr = tcpip_callback(lwip_setsockopt_callback, &LWIP_SETGETSOCKOPT_DATA_VAR_REF(data)); 3339195972f6Sopenharmony_ci if (cberr != ERR_OK) { 3340195972f6Sopenharmony_ci LWIP_SETGETSOCKOPT_DATA_VAR_FREE(data); 3341195972f6Sopenharmony_ci sock_set_errno(sock, err_to_errno(cberr)); 3342195972f6Sopenharmony_ci done_socket(sock); 3343195972f6Sopenharmony_ci return -1; 3344195972f6Sopenharmony_ci } 3345195972f6Sopenharmony_ci sys_arch_sem_wait((sys_sem_t *)(LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).completed_sem), 0); 3346195972f6Sopenharmony_ci 3347195972f6Sopenharmony_ci /* maybe lwip_getsockopt_internal has changed err */ 3348195972f6Sopenharmony_ci err = LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).err; 3349195972f6Sopenharmony_ci LWIP_SETGETSOCKOPT_DATA_VAR_FREE(data); 3350195972f6Sopenharmony_ci#endif /* LWIP_TCPIP_CORE_LOCKING */ 3351195972f6Sopenharmony_ci 3352195972f6Sopenharmony_ci sock_set_errno(sock, err); 3353195972f6Sopenharmony_ci done_socket(sock); 3354195972f6Sopenharmony_ci return err ? -1 : 0; 3355195972f6Sopenharmony_ci} 3356195972f6Sopenharmony_ci 3357195972f6Sopenharmony_ci#if !LWIP_TCPIP_CORE_LOCKING 3358195972f6Sopenharmony_ci/** lwip_setsockopt_callback: only used without CORE_LOCKING 3359195972f6Sopenharmony_ci * to get into the tcpip_thread 3360195972f6Sopenharmony_ci */ 3361195972f6Sopenharmony_cistatic void 3362195972f6Sopenharmony_cilwip_setsockopt_callback(void *arg) 3363195972f6Sopenharmony_ci{ 3364195972f6Sopenharmony_ci struct lwip_setgetsockopt_data *data; 3365195972f6Sopenharmony_ci LWIP_ASSERT("arg != NULL", arg != NULL); 3366195972f6Sopenharmony_ci data = (struct lwip_setgetsockopt_data *)arg; 3367195972f6Sopenharmony_ci 3368195972f6Sopenharmony_ci data->err = lwip_setsockopt_impl(data->s, data->level, data->optname, 3369195972f6Sopenharmony_ci#if LWIP_MPU_COMPATIBLE 3370195972f6Sopenharmony_ci data->optval, 3371195972f6Sopenharmony_ci#else /* LWIP_MPU_COMPATIBLE */ 3372195972f6Sopenharmony_ci data->optval.pc, 3373195972f6Sopenharmony_ci#endif /* LWIP_MPU_COMPATIBLE */ 3374195972f6Sopenharmony_ci data->optlen); 3375195972f6Sopenharmony_ci 3376195972f6Sopenharmony_ci sys_sem_signal((sys_sem_t *)(data->completed_sem)); 3377195972f6Sopenharmony_ci} 3378195972f6Sopenharmony_ci#endif /* LWIP_TCPIP_CORE_LOCKING */ 3379195972f6Sopenharmony_ci 3380195972f6Sopenharmony_ci/** lwip_setsockopt_impl: the actual implementation of setsockopt: 3381195972f6Sopenharmony_ci * same argument as lwip_setsockopt, either called directly or through callback 3382195972f6Sopenharmony_ci */ 3383195972f6Sopenharmony_cistatic int 3384195972f6Sopenharmony_cilwip_setsockopt_impl(int s, int level, int optname, const void *optval, socklen_t optlen) 3385195972f6Sopenharmony_ci{ 3386195972f6Sopenharmony_ci int err = 0; 3387195972f6Sopenharmony_ci struct lwip_sock *sock = tryget_socket(s); 3388195972f6Sopenharmony_ci if (!sock) { 3389195972f6Sopenharmony_ci return EBADF; 3390195972f6Sopenharmony_ci } 3391195972f6Sopenharmony_ci 3392195972f6Sopenharmony_ci#ifdef LWIP_HOOK_SOCKETS_SETSOCKOPT 3393195972f6Sopenharmony_ci if (LWIP_HOOK_SOCKETS_SETSOCKOPT(s, sock, level, optname, optval, optlen, &err)) { 3394195972f6Sopenharmony_ci return err; 3395195972f6Sopenharmony_ci } 3396195972f6Sopenharmony_ci#endif 3397195972f6Sopenharmony_ci 3398195972f6Sopenharmony_ci switch (level) { 3399195972f6Sopenharmony_ci 3400195972f6Sopenharmony_ci /* Level: SOL_SOCKET */ 3401195972f6Sopenharmony_ci case SOL_SOCKET: 3402195972f6Sopenharmony_ci switch (optname) { 3403195972f6Sopenharmony_ci 3404195972f6Sopenharmony_ci /* SO_ACCEPTCONN is get-only */ 3405195972f6Sopenharmony_ci 3406195972f6Sopenharmony_ci /* The option flags */ 3407195972f6Sopenharmony_ci case SO_BROADCAST: 3408195972f6Sopenharmony_ci case SO_KEEPALIVE: 3409195972f6Sopenharmony_ci#if SO_REUSE 3410195972f6Sopenharmony_ci case SO_REUSEADDR: 3411195972f6Sopenharmony_ci#endif /* SO_REUSE */ 3412195972f6Sopenharmony_ci if ((optname == SO_BROADCAST) && 3413195972f6Sopenharmony_ci (NETCONNTYPE_GROUP(sock->conn->type) != NETCONN_UDP)) { 3414195972f6Sopenharmony_ci done_socket(sock); 3415195972f6Sopenharmony_ci return ENOPROTOOPT; 3416195972f6Sopenharmony_ci } 3417195972f6Sopenharmony_ci 3418195972f6Sopenharmony_ci optname = lwip_sockopt_to_ipopt(optname); 3419195972f6Sopenharmony_ci 3420195972f6Sopenharmony_ci LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, optlen, int); 3421195972f6Sopenharmony_ci if (*(const int *)optval) { 3422195972f6Sopenharmony_ci ip_set_option(sock->conn->pcb.ip, optname); 3423195972f6Sopenharmony_ci } else { 3424195972f6Sopenharmony_ci ip_reset_option(sock->conn->pcb.ip, optname); 3425195972f6Sopenharmony_ci } 3426195972f6Sopenharmony_ci LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, SOL_SOCKET, optname=0x%x, ..) -> %s\n", 3427195972f6Sopenharmony_ci s, optname, (*(const int *)optval ? "on" : "off"))); 3428195972f6Sopenharmony_ci break; 3429195972f6Sopenharmony_ci 3430195972f6Sopenharmony_ci /* SO_TYPE is get-only */ 3431195972f6Sopenharmony_ci /* SO_ERROR is get-only */ 3432195972f6Sopenharmony_ci 3433195972f6Sopenharmony_ci#if LWIP_SO_SNDTIMEO 3434195972f6Sopenharmony_ci case SO_SNDTIMEO: { 3435195972f6Sopenharmony_ci long ms_long; 3436195972f6Sopenharmony_ci LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, optlen, LWIP_SO_SNDRCVTIMEO_OPTTYPE); 3437195972f6Sopenharmony_ci ms_long = LWIP_SO_SNDRCVTIMEO_GET_MS(optval); 3438195972f6Sopenharmony_ci if (ms_long < 0) { 3439195972f6Sopenharmony_ci done_socket(sock); 3440195972f6Sopenharmony_ci return EINVAL; 3441195972f6Sopenharmony_ci } 3442195972f6Sopenharmony_ci netconn_set_sendtimeout(sock->conn, ms_long); 3443195972f6Sopenharmony_ci break; 3444195972f6Sopenharmony_ci } 3445195972f6Sopenharmony_ci#endif /* LWIP_SO_SNDTIMEO */ 3446195972f6Sopenharmony_ci#if LWIP_SO_RCVTIMEO 3447195972f6Sopenharmony_ci case SO_RCVTIMEO: { 3448195972f6Sopenharmony_ci long ms_long; 3449195972f6Sopenharmony_ci LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, optlen, LWIP_SO_SNDRCVTIMEO_OPTTYPE); 3450195972f6Sopenharmony_ci ms_long = LWIP_SO_SNDRCVTIMEO_GET_MS(optval); 3451195972f6Sopenharmony_ci if (ms_long < 0) { 3452195972f6Sopenharmony_ci done_socket(sock); 3453195972f6Sopenharmony_ci return EINVAL; 3454195972f6Sopenharmony_ci } 3455195972f6Sopenharmony_ci netconn_set_recvtimeout(sock->conn, (u32_t)ms_long); 3456195972f6Sopenharmony_ci break; 3457195972f6Sopenharmony_ci } 3458195972f6Sopenharmony_ci#endif /* LWIP_SO_RCVTIMEO */ 3459195972f6Sopenharmony_ci#if LWIP_SO_RCVBUF 3460195972f6Sopenharmony_ci case SO_RCVBUF: 3461195972f6Sopenharmony_ci LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, optlen, int); 3462195972f6Sopenharmony_ci netconn_set_recvbufsize(sock->conn, *(const int *)optval); 3463195972f6Sopenharmony_ci break; 3464195972f6Sopenharmony_ci#endif /* LWIP_SO_RCVBUF */ 3465195972f6Sopenharmony_ci#if LWIP_SO_LINGER 3466195972f6Sopenharmony_ci case SO_LINGER: { 3467195972f6Sopenharmony_ci const struct linger *linger = (const struct linger *)optval; 3468195972f6Sopenharmony_ci LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, optlen, struct linger); 3469195972f6Sopenharmony_ci if (linger->l_onoff) { 3470195972f6Sopenharmony_ci int lingersec = linger->l_linger; 3471195972f6Sopenharmony_ci if (lingersec < 0) { 3472195972f6Sopenharmony_ci done_socket(sock); 3473195972f6Sopenharmony_ci return EINVAL; 3474195972f6Sopenharmony_ci } 3475195972f6Sopenharmony_ci if (lingersec > 0xFFFF) { 3476195972f6Sopenharmony_ci lingersec = 0xFFFF; 3477195972f6Sopenharmony_ci } 3478195972f6Sopenharmony_ci sock->conn->linger = (s16_t)lingersec; 3479195972f6Sopenharmony_ci } else { 3480195972f6Sopenharmony_ci sock->conn->linger = -1; 3481195972f6Sopenharmony_ci } 3482195972f6Sopenharmony_ci } 3483195972f6Sopenharmony_ci break; 3484195972f6Sopenharmony_ci#endif /* LWIP_SO_LINGER */ 3485195972f6Sopenharmony_ci#if LWIP_UDP 3486195972f6Sopenharmony_ci case SO_NO_CHECK: 3487195972f6Sopenharmony_ci LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, int, NETCONN_UDP); 3488195972f6Sopenharmony_ci#if LWIP_UDPLITE 3489195972f6Sopenharmony_ci if (udp_is_flag_set(sock->conn->pcb.udp, UDP_FLAGS_UDPLITE)) { 3490195972f6Sopenharmony_ci /* this flag is only available for UDP, not for UDP lite */ 3491195972f6Sopenharmony_ci done_socket(sock); 3492195972f6Sopenharmony_ci return EAFNOSUPPORT; 3493195972f6Sopenharmony_ci } 3494195972f6Sopenharmony_ci#endif /* LWIP_UDPLITE */ 3495195972f6Sopenharmony_ci if (*(const int *)optval) { 3496195972f6Sopenharmony_ci udp_set_flags(sock->conn->pcb.udp, UDP_FLAGS_NOCHKSUM); 3497195972f6Sopenharmony_ci } else { 3498195972f6Sopenharmony_ci udp_clear_flags(sock->conn->pcb.udp, UDP_FLAGS_NOCHKSUM); 3499195972f6Sopenharmony_ci } 3500195972f6Sopenharmony_ci break; 3501195972f6Sopenharmony_ci#endif /* LWIP_UDP */ 3502195972f6Sopenharmony_ci case SO_BINDTODEVICE: { 3503195972f6Sopenharmony_ci const struct ifreq *iface; 3504195972f6Sopenharmony_ci struct netif *n = NULL; 3505195972f6Sopenharmony_ci 3506195972f6Sopenharmony_ci LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, optlen, struct ifreq); 3507195972f6Sopenharmony_ci 3508195972f6Sopenharmony_ci iface = (const struct ifreq *)optval; 3509195972f6Sopenharmony_ci if (iface->ifr_name[0] != 0) { 3510195972f6Sopenharmony_ci n = netif_find(iface->ifr_name); 3511195972f6Sopenharmony_ci if (n == NULL) { 3512195972f6Sopenharmony_ci done_socket(sock); 3513195972f6Sopenharmony_ci return ENODEV; 3514195972f6Sopenharmony_ci } 3515195972f6Sopenharmony_ci } 3516195972f6Sopenharmony_ci 3517195972f6Sopenharmony_ci switch (NETCONNTYPE_GROUP(netconn_type(sock->conn))) { 3518195972f6Sopenharmony_ci#if LWIP_TCP 3519195972f6Sopenharmony_ci case NETCONN_TCP: 3520195972f6Sopenharmony_ci tcp_bind_netif(sock->conn->pcb.tcp, n); 3521195972f6Sopenharmony_ci break; 3522195972f6Sopenharmony_ci#endif 3523195972f6Sopenharmony_ci#if LWIP_UDP 3524195972f6Sopenharmony_ci case NETCONN_UDP: 3525195972f6Sopenharmony_ci udp_bind_netif(sock->conn->pcb.udp, n); 3526195972f6Sopenharmony_ci break; 3527195972f6Sopenharmony_ci#endif 3528195972f6Sopenharmony_ci#if LWIP_RAW 3529195972f6Sopenharmony_ci case NETCONN_RAW: 3530195972f6Sopenharmony_ci raw_bind_netif(sock->conn->pcb.raw, n); 3531195972f6Sopenharmony_ci break; 3532195972f6Sopenharmony_ci#endif 3533195972f6Sopenharmony_ci default: 3534195972f6Sopenharmony_ci LWIP_ASSERT("Unhandled netconn type in SO_BINDTODEVICE", 0); 3535195972f6Sopenharmony_ci break; 3536195972f6Sopenharmony_ci } 3537195972f6Sopenharmony_ci } 3538195972f6Sopenharmony_ci break; 3539195972f6Sopenharmony_ci default: 3540195972f6Sopenharmony_ci LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, SOL_SOCKET, UNIMPL: optname=0x%x, ..)\n", 3541195972f6Sopenharmony_ci s, optname)); 3542195972f6Sopenharmony_ci err = ENOPROTOOPT; 3543195972f6Sopenharmony_ci break; 3544195972f6Sopenharmony_ci } /* switch (optname) */ 3545195972f6Sopenharmony_ci break; 3546195972f6Sopenharmony_ci 3547195972f6Sopenharmony_ci /* Level: IPPROTO_IP */ 3548195972f6Sopenharmony_ci case IPPROTO_IP: 3549195972f6Sopenharmony_ci switch (optname) { 3550195972f6Sopenharmony_ci case IP_TTL: 3551195972f6Sopenharmony_ci LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, optlen, int); 3552195972f6Sopenharmony_ci sock->conn->pcb.ip->ttl = (u8_t)(*(const int *)optval); 3553195972f6Sopenharmony_ci LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IP, IP_TTL, ..) -> %d\n", 3554195972f6Sopenharmony_ci s, sock->conn->pcb.ip->ttl)); 3555195972f6Sopenharmony_ci break; 3556195972f6Sopenharmony_ci case IP_TOS: 3557195972f6Sopenharmony_ci LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, optlen, int); 3558195972f6Sopenharmony_ci sock->conn->pcb.ip->tos = (u8_t)(*(const int *)optval); 3559195972f6Sopenharmony_ci LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IP, IP_TOS, ..)-> %d\n", 3560195972f6Sopenharmony_ci s, sock->conn->pcb.ip->tos)); 3561195972f6Sopenharmony_ci break; 3562195972f6Sopenharmony_ci#if LWIP_NETBUF_RECVINFO 3563195972f6Sopenharmony_ci case IP_PKTINFO: 3564195972f6Sopenharmony_ci LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, int, NETCONN_UDP); 3565195972f6Sopenharmony_ci if (*(const int *)optval) { 3566195972f6Sopenharmony_ci sock->conn->flags |= NETCONN_FLAG_PKTINFO; 3567195972f6Sopenharmony_ci } else { 3568195972f6Sopenharmony_ci sock->conn->flags &= ~NETCONN_FLAG_PKTINFO; 3569195972f6Sopenharmony_ci } 3570195972f6Sopenharmony_ci break; 3571195972f6Sopenharmony_ci#endif /* LWIP_NETBUF_RECVINFO */ 3572195972f6Sopenharmony_ci#if LWIP_IPV4 && LWIP_MULTICAST_TX_OPTIONS && LWIP_UDP 3573195972f6Sopenharmony_ci case IP_MULTICAST_TTL: 3574195972f6Sopenharmony_ci LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, u8_t, NETCONN_UDP); 3575195972f6Sopenharmony_ci udp_set_multicast_ttl(sock->conn->pcb.udp, (u8_t)(*(const u8_t *)optval)); 3576195972f6Sopenharmony_ci break; 3577195972f6Sopenharmony_ci case IP_MULTICAST_IF: { 3578195972f6Sopenharmony_ci ip4_addr_t if_addr; 3579195972f6Sopenharmony_ci LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, struct in_addr, NETCONN_UDP); 3580195972f6Sopenharmony_ci inet_addr_to_ip4addr(&if_addr, (const struct in_addr *)optval); 3581195972f6Sopenharmony_ci udp_set_multicast_netif_addr(sock->conn->pcb.udp, &if_addr); 3582195972f6Sopenharmony_ci } 3583195972f6Sopenharmony_ci break; 3584195972f6Sopenharmony_ci case IP_MULTICAST_LOOP: 3585195972f6Sopenharmony_ci LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, u8_t, NETCONN_UDP); 3586195972f6Sopenharmony_ci if (*(const u8_t *)optval) { 3587195972f6Sopenharmony_ci udp_set_flags(sock->conn->pcb.udp, UDP_FLAGS_MULTICAST_LOOP); 3588195972f6Sopenharmony_ci } else { 3589195972f6Sopenharmony_ci udp_clear_flags(sock->conn->pcb.udp, UDP_FLAGS_MULTICAST_LOOP); 3590195972f6Sopenharmony_ci } 3591195972f6Sopenharmony_ci break; 3592195972f6Sopenharmony_ci#endif /* LWIP_IPV4 && LWIP_MULTICAST_TX_OPTIONS && LWIP_UDP */ 3593195972f6Sopenharmony_ci#if LWIP_IGMP 3594195972f6Sopenharmony_ci case IP_ADD_MEMBERSHIP: 3595195972f6Sopenharmony_ci case IP_DROP_MEMBERSHIP: { 3596195972f6Sopenharmony_ci /* If this is a TCP or a RAW socket, ignore these options. */ 3597195972f6Sopenharmony_ci err_t igmp_err; 3598195972f6Sopenharmony_ci const struct ip_mreq *imr = (const struct ip_mreq *)optval; 3599195972f6Sopenharmony_ci ip4_addr_t if_addr; 3600195972f6Sopenharmony_ci ip4_addr_t multi_addr; 3601195972f6Sopenharmony_ci LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, struct ip_mreq, NETCONN_UDP); 3602195972f6Sopenharmony_ci inet_addr_to_ip4addr(&if_addr, &imr->imr_interface); 3603195972f6Sopenharmony_ci inet_addr_to_ip4addr(&multi_addr, &imr->imr_multiaddr); 3604195972f6Sopenharmony_ci if (optname == IP_ADD_MEMBERSHIP) { 3605195972f6Sopenharmony_ci if (!lwip_socket_register_membership(s, &if_addr, &multi_addr)) { 3606195972f6Sopenharmony_ci /* cannot track membership (out of memory) */ 3607195972f6Sopenharmony_ci err = ENOMEM; 3608195972f6Sopenharmony_ci igmp_err = ERR_OK; 3609195972f6Sopenharmony_ci } else { 3610195972f6Sopenharmony_ci igmp_err = igmp_joingroup(&if_addr, &multi_addr); 3611195972f6Sopenharmony_ci } 3612195972f6Sopenharmony_ci } else { 3613195972f6Sopenharmony_ci igmp_err = igmp_leavegroup(&if_addr, &multi_addr); 3614195972f6Sopenharmony_ci lwip_socket_unregister_membership(s, &if_addr, &multi_addr); 3615195972f6Sopenharmony_ci } 3616195972f6Sopenharmony_ci if (igmp_err != ERR_OK) { 3617195972f6Sopenharmony_ci err = EADDRNOTAVAIL; 3618195972f6Sopenharmony_ci } 3619195972f6Sopenharmony_ci } 3620195972f6Sopenharmony_ci break; 3621195972f6Sopenharmony_ci#endif /* LWIP_IGMP */ 3622195972f6Sopenharmony_ci default: 3623195972f6Sopenharmony_ci LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IP, UNIMPL: optname=0x%x, ..)\n", 3624195972f6Sopenharmony_ci s, optname)); 3625195972f6Sopenharmony_ci err = ENOPROTOOPT; 3626195972f6Sopenharmony_ci break; 3627195972f6Sopenharmony_ci } /* switch (optname) */ 3628195972f6Sopenharmony_ci break; 3629195972f6Sopenharmony_ci 3630195972f6Sopenharmony_ci#if LWIP_TCP 3631195972f6Sopenharmony_ci /* Level: IPPROTO_TCP */ 3632195972f6Sopenharmony_ci case IPPROTO_TCP: 3633195972f6Sopenharmony_ci /* Special case: all IPPROTO_TCP option take an int */ 3634195972f6Sopenharmony_ci LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, int, NETCONN_TCP); 3635195972f6Sopenharmony_ci if (sock->conn->pcb.tcp->state == LISTEN) { 3636195972f6Sopenharmony_ci done_socket(sock); 3637195972f6Sopenharmony_ci return EINVAL; 3638195972f6Sopenharmony_ci } 3639195972f6Sopenharmony_ci switch (optname) { 3640195972f6Sopenharmony_ci case TCP_NODELAY: 3641195972f6Sopenharmony_ci if (*(const int *)optval) { 3642195972f6Sopenharmony_ci tcp_nagle_disable(sock->conn->pcb.tcp); 3643195972f6Sopenharmony_ci } else { 3644195972f6Sopenharmony_ci tcp_nagle_enable(sock->conn->pcb.tcp); 3645195972f6Sopenharmony_ci } 3646195972f6Sopenharmony_ci LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_NODELAY) -> %s\n", 3647195972f6Sopenharmony_ci s, (*(const int *)optval) ? "on" : "off") ); 3648195972f6Sopenharmony_ci break; 3649195972f6Sopenharmony_ci case TCP_KEEPALIVE: 3650195972f6Sopenharmony_ci sock->conn->pcb.tcp->keep_idle = (u32_t)(*(const int *)optval); 3651195972f6Sopenharmony_ci LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPALIVE) -> %"U32_F"\n", 3652195972f6Sopenharmony_ci s, sock->conn->pcb.tcp->keep_idle)); 3653195972f6Sopenharmony_ci break; 3654195972f6Sopenharmony_ci 3655195972f6Sopenharmony_ci#if LWIP_TCP_KEEPALIVE 3656195972f6Sopenharmony_ci case TCP_KEEPIDLE: 3657195972f6Sopenharmony_ci sock->conn->pcb.tcp->keep_idle = 1000 * (u32_t)(*(const int *)optval); 3658195972f6Sopenharmony_ci LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPIDLE) -> %"U32_F"\n", 3659195972f6Sopenharmony_ci s, sock->conn->pcb.tcp->keep_idle)); 3660195972f6Sopenharmony_ci break; 3661195972f6Sopenharmony_ci case TCP_KEEPINTVL: 3662195972f6Sopenharmony_ci sock->conn->pcb.tcp->keep_intvl = 1000 * (u32_t)(*(const int *)optval); 3663195972f6Sopenharmony_ci LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPINTVL) -> %"U32_F"\n", 3664195972f6Sopenharmony_ci s, sock->conn->pcb.tcp->keep_intvl)); 3665195972f6Sopenharmony_ci break; 3666195972f6Sopenharmony_ci case TCP_KEEPCNT: 3667195972f6Sopenharmony_ci sock->conn->pcb.tcp->keep_cnt = (u32_t)(*(const int *)optval); 3668195972f6Sopenharmony_ci LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPCNT) -> %"U32_F"\n", 3669195972f6Sopenharmony_ci s, sock->conn->pcb.tcp->keep_cnt)); 3670195972f6Sopenharmony_ci break; 3671195972f6Sopenharmony_ci#endif /* LWIP_TCP_KEEPALIVE */ 3672195972f6Sopenharmony_ci default: 3673195972f6Sopenharmony_ci LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, UNIMPL: optname=0x%x, ..)\n", 3674195972f6Sopenharmony_ci s, optname)); 3675195972f6Sopenharmony_ci err = ENOPROTOOPT; 3676195972f6Sopenharmony_ci break; 3677195972f6Sopenharmony_ci } /* switch (optname) */ 3678195972f6Sopenharmony_ci break; 3679195972f6Sopenharmony_ci#endif /* LWIP_TCP*/ 3680195972f6Sopenharmony_ci 3681195972f6Sopenharmony_ci#if LWIP_IPV6 3682195972f6Sopenharmony_ci /* Level: IPPROTO_IPV6 */ 3683195972f6Sopenharmony_ci case IPPROTO_IPV6: 3684195972f6Sopenharmony_ci switch (optname) { 3685195972f6Sopenharmony_ci case IPV6_V6ONLY: 3686195972f6Sopenharmony_ci LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, optlen, int); 3687195972f6Sopenharmony_ci if (*(const int *)optval) { 3688195972f6Sopenharmony_ci netconn_set_ipv6only(sock->conn, 1); 3689195972f6Sopenharmony_ci } else { 3690195972f6Sopenharmony_ci netconn_set_ipv6only(sock->conn, 0); 3691195972f6Sopenharmony_ci } 3692195972f6Sopenharmony_ci LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IPV6, IPV6_V6ONLY, ..) -> %d\n", 3693195972f6Sopenharmony_ci s, (netconn_get_ipv6only(sock->conn) ? 1 : 0))); 3694195972f6Sopenharmony_ci break; 3695195972f6Sopenharmony_ci#if LWIP_IPV6_MLD 3696195972f6Sopenharmony_ci case IPV6_JOIN_GROUP: 3697195972f6Sopenharmony_ci case IPV6_LEAVE_GROUP: { 3698195972f6Sopenharmony_ci /* If this is a TCP or a RAW socket, ignore these options. */ 3699195972f6Sopenharmony_ci err_t mld6_err; 3700195972f6Sopenharmony_ci struct netif *netif; 3701195972f6Sopenharmony_ci ip6_addr_t multi_addr; 3702195972f6Sopenharmony_ci const struct ipv6_mreq *imr = (const struct ipv6_mreq *)optval; 3703195972f6Sopenharmony_ci LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, struct ipv6_mreq, NETCONN_UDP); 3704195972f6Sopenharmony_ci inet6_addr_to_ip6addr(&multi_addr, &imr->ipv6mr_multiaddr); 3705195972f6Sopenharmony_ci LWIP_ASSERT("Invalid netif index", imr->ipv6mr_interface <= 0xFFu); 3706195972f6Sopenharmony_ci#ifdef LOSCFG_NET_CONTAINER 3707195972f6Sopenharmony_ci netif = netif_get_by_index((u8_t)imr->ipv6mr_interface, get_net_group_from_ippcb(sock->conn->pcb.ip)); 3708195972f6Sopenharmony_ci#else 3709195972f6Sopenharmony_ci netif = netif_get_by_index((u8_t)imr->ipv6mr_interface); 3710195972f6Sopenharmony_ci#endif 3711195972f6Sopenharmony_ci if (netif == NULL) { 3712195972f6Sopenharmony_ci err = EADDRNOTAVAIL; 3713195972f6Sopenharmony_ci break; 3714195972f6Sopenharmony_ci } 3715195972f6Sopenharmony_ci 3716195972f6Sopenharmony_ci if (optname == IPV6_JOIN_GROUP) { 3717195972f6Sopenharmony_ci if (!lwip_socket_register_mld6_membership(s, imr->ipv6mr_interface, &multi_addr)) { 3718195972f6Sopenharmony_ci /* cannot track membership (out of memory) */ 3719195972f6Sopenharmony_ci err = ENOMEM; 3720195972f6Sopenharmony_ci mld6_err = ERR_OK; 3721195972f6Sopenharmony_ci } else { 3722195972f6Sopenharmony_ci mld6_err = mld6_joingroup_netif(netif, &multi_addr); 3723195972f6Sopenharmony_ci } 3724195972f6Sopenharmony_ci } else { 3725195972f6Sopenharmony_ci mld6_err = mld6_leavegroup_netif(netif, &multi_addr); 3726195972f6Sopenharmony_ci lwip_socket_unregister_mld6_membership(s, imr->ipv6mr_interface, &multi_addr); 3727195972f6Sopenharmony_ci } 3728195972f6Sopenharmony_ci if (mld6_err != ERR_OK) { 3729195972f6Sopenharmony_ci err = EADDRNOTAVAIL; 3730195972f6Sopenharmony_ci } 3731195972f6Sopenharmony_ci } 3732195972f6Sopenharmony_ci break; 3733195972f6Sopenharmony_ci#endif /* LWIP_IPV6_MLD */ 3734195972f6Sopenharmony_ci default: 3735195972f6Sopenharmony_ci LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IPV6, UNIMPL: optname=0x%x, ..)\n", 3736195972f6Sopenharmony_ci s, optname)); 3737195972f6Sopenharmony_ci err = ENOPROTOOPT; 3738195972f6Sopenharmony_ci break; 3739195972f6Sopenharmony_ci } /* switch (optname) */ 3740195972f6Sopenharmony_ci break; 3741195972f6Sopenharmony_ci#endif /* LWIP_IPV6 */ 3742195972f6Sopenharmony_ci 3743195972f6Sopenharmony_ci#if LWIP_UDP && LWIP_UDPLITE 3744195972f6Sopenharmony_ci /* Level: IPPROTO_UDPLITE */ 3745195972f6Sopenharmony_ci case IPPROTO_UDPLITE: 3746195972f6Sopenharmony_ci /* Special case: all IPPROTO_UDPLITE option take an int */ 3747195972f6Sopenharmony_ci LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, optlen, int); 3748195972f6Sopenharmony_ci /* If this is no UDP lite socket, ignore any options. */ 3749195972f6Sopenharmony_ci if (!NETCONNTYPE_ISUDPLITE(netconn_type(sock->conn))) { 3750195972f6Sopenharmony_ci done_socket(sock); 3751195972f6Sopenharmony_ci return ENOPROTOOPT; 3752195972f6Sopenharmony_ci } 3753195972f6Sopenharmony_ci switch (optname) { 3754195972f6Sopenharmony_ci case UDPLITE_SEND_CSCOV: 3755195972f6Sopenharmony_ci if ((*(const int *)optval != 0) && ((*(const int *)optval < 8) || (*(const int *)optval > 0xffff))) { 3756195972f6Sopenharmony_ci /* don't allow illegal values! */ 3757195972f6Sopenharmony_ci sock->conn->pcb.udp->chksum_len_tx = 8; 3758195972f6Sopenharmony_ci } else { 3759195972f6Sopenharmony_ci sock->conn->pcb.udp->chksum_len_tx = (u16_t) * (const int *)optval; 3760195972f6Sopenharmony_ci } 3761195972f6Sopenharmony_ci LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_UDPLITE, UDPLITE_SEND_CSCOV) -> %d\n", 3762195972f6Sopenharmony_ci s, (*(const int *)optval)) ); 3763195972f6Sopenharmony_ci break; 3764195972f6Sopenharmony_ci case UDPLITE_RECV_CSCOV: 3765195972f6Sopenharmony_ci if ((*(const int *)optval != 0) && ((*(const int *)optval < 8) || (*(const int *)optval > 0xffff))) { 3766195972f6Sopenharmony_ci /* don't allow illegal values! */ 3767195972f6Sopenharmony_ci sock->conn->pcb.udp->chksum_len_rx = 8; 3768195972f6Sopenharmony_ci } else { 3769195972f6Sopenharmony_ci sock->conn->pcb.udp->chksum_len_rx = (u16_t) * (const int *)optval; 3770195972f6Sopenharmony_ci } 3771195972f6Sopenharmony_ci LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_UDPLITE, UDPLITE_RECV_CSCOV) -> %d\n", 3772195972f6Sopenharmony_ci s, (*(const int *)optval)) ); 3773195972f6Sopenharmony_ci break; 3774195972f6Sopenharmony_ci default: 3775195972f6Sopenharmony_ci LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_UDPLITE, UNIMPL: optname=0x%x, ..)\n", 3776195972f6Sopenharmony_ci s, optname)); 3777195972f6Sopenharmony_ci err = ENOPROTOOPT; 3778195972f6Sopenharmony_ci break; 3779195972f6Sopenharmony_ci } /* switch (optname) */ 3780195972f6Sopenharmony_ci break; 3781195972f6Sopenharmony_ci#endif /* LWIP_UDP */ 3782195972f6Sopenharmony_ci /* Level: IPPROTO_RAW */ 3783195972f6Sopenharmony_ci case IPPROTO_RAW: 3784195972f6Sopenharmony_ci switch (optname) { 3785195972f6Sopenharmony_ci#if LWIP_IPV6 && LWIP_RAW 3786195972f6Sopenharmony_ci case IPV6_CHECKSUM: 3787195972f6Sopenharmony_ci /* It should not be possible to disable the checksum generation with ICMPv6 3788195972f6Sopenharmony_ci * as per RFC 3542 chapter 3.1 */ 3789195972f6Sopenharmony_ci if (sock->conn->pcb.raw->protocol == IPPROTO_ICMPV6) { 3790195972f6Sopenharmony_ci done_socket(sock); 3791195972f6Sopenharmony_ci return EINVAL; 3792195972f6Sopenharmony_ci } 3793195972f6Sopenharmony_ci 3794195972f6Sopenharmony_ci LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, int, NETCONN_RAW); 3795195972f6Sopenharmony_ci if (*(const int *)optval < 0) { 3796195972f6Sopenharmony_ci sock->conn->pcb.raw->chksum_reqd = 0; 3797195972f6Sopenharmony_ci } else if (*(const int *)optval & 1) { 3798195972f6Sopenharmony_ci /* Per RFC3542, odd offsets are not allowed */ 3799195972f6Sopenharmony_ci done_socket(sock); 3800195972f6Sopenharmony_ci return EINVAL; 3801195972f6Sopenharmony_ci } else { 3802195972f6Sopenharmony_ci sock->conn->pcb.raw->chksum_reqd = 1; 3803195972f6Sopenharmony_ci sock->conn->pcb.raw->chksum_offset = (u16_t) * (const int *)optval; 3804195972f6Sopenharmony_ci } 3805195972f6Sopenharmony_ci LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_RAW, IPV6_CHECKSUM, ..) -> %d\n", 3806195972f6Sopenharmony_ci s, sock->conn->pcb.raw->chksum_reqd)); 3807195972f6Sopenharmony_ci break; 3808195972f6Sopenharmony_ci#endif /* LWIP_IPV6 && LWIP_RAW */ 3809195972f6Sopenharmony_ci default: 3810195972f6Sopenharmony_ci LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_RAW, UNIMPL: optname=0x%x, ..)\n", 3811195972f6Sopenharmony_ci s, optname)); 3812195972f6Sopenharmony_ci err = ENOPROTOOPT; 3813195972f6Sopenharmony_ci break; 3814195972f6Sopenharmony_ci } /* switch (optname) */ 3815195972f6Sopenharmony_ci break; 3816195972f6Sopenharmony_ci default: 3817195972f6Sopenharmony_ci LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, level=0x%x, UNIMPL: optname=0x%x, ..)\n", 3818195972f6Sopenharmony_ci s, level, optname)); 3819195972f6Sopenharmony_ci err = ENOPROTOOPT; 3820195972f6Sopenharmony_ci break; 3821195972f6Sopenharmony_ci } /* switch (level) */ 3822195972f6Sopenharmony_ci 3823195972f6Sopenharmony_ci done_socket(sock); 3824195972f6Sopenharmony_ci return err; 3825195972f6Sopenharmony_ci} 3826195972f6Sopenharmony_ci 3827195972f6Sopenharmony_ciint 3828195972f6Sopenharmony_cilwip_ioctl(int s, long cmd, void *argp) 3829195972f6Sopenharmony_ci{ 3830195972f6Sopenharmony_ci struct lwip_sock *sock = get_socket(s); 3831195972f6Sopenharmony_ci u8_t val; 3832195972f6Sopenharmony_ci#if LWIP_SO_RCVBUF 3833195972f6Sopenharmony_ci int recv_avail; 3834195972f6Sopenharmony_ci#endif /* LWIP_SO_RCVBUF */ 3835195972f6Sopenharmony_ci 3836195972f6Sopenharmony_ci if (!sock) { 3837195972f6Sopenharmony_ci return -1; 3838195972f6Sopenharmony_ci } 3839195972f6Sopenharmony_ci 3840195972f6Sopenharmony_ci switch (cmd) { 3841195972f6Sopenharmony_ci#if LWIP_SO_RCVBUF || LWIP_FIONREAD_LINUXMODE 3842195972f6Sopenharmony_ci case FIONREAD: 3843195972f6Sopenharmony_ci if (!argp) { 3844195972f6Sopenharmony_ci sock_set_errno(sock, EINVAL); 3845195972f6Sopenharmony_ci done_socket(sock); 3846195972f6Sopenharmony_ci return -1; 3847195972f6Sopenharmony_ci } 3848195972f6Sopenharmony_ci#if LWIP_FIONREAD_LINUXMODE 3849195972f6Sopenharmony_ci if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_TCP) { 3850195972f6Sopenharmony_ci struct netbuf *nb; 3851195972f6Sopenharmony_ci if (sock->lastdata.netbuf) { 3852195972f6Sopenharmony_ci nb = sock->lastdata.netbuf; 3853195972f6Sopenharmony_ci *((int *)argp) = nb->p->tot_len; 3854195972f6Sopenharmony_ci } else { 3855195972f6Sopenharmony_ci struct netbuf *rxbuf; 3856195972f6Sopenharmony_ci err_t err = netconn_recv_udp_raw_netbuf_flags(sock->conn, &rxbuf, NETCONN_DONTBLOCK); 3857195972f6Sopenharmony_ci if (err != ERR_OK) { 3858195972f6Sopenharmony_ci *((int *)argp) = 0; 3859195972f6Sopenharmony_ci } else { 3860195972f6Sopenharmony_ci sock->lastdata.netbuf = rxbuf; 3861195972f6Sopenharmony_ci *((int *)argp) = rxbuf->p->tot_len; 3862195972f6Sopenharmony_ci } 3863195972f6Sopenharmony_ci } 3864195972f6Sopenharmony_ci done_socket(sock); 3865195972f6Sopenharmony_ci return 0; 3866195972f6Sopenharmony_ci } 3867195972f6Sopenharmony_ci#endif /* LWIP_FIONREAD_LINUXMODE */ 3868195972f6Sopenharmony_ci 3869195972f6Sopenharmony_ci#if LWIP_SO_RCVBUF 3870195972f6Sopenharmony_ci /* we come here if either LWIP_FIONREAD_LINUXMODE==0 or this is a TCP socket */ 3871195972f6Sopenharmony_ci SYS_ARCH_GET(sock->conn->recv_avail, recv_avail); 3872195972f6Sopenharmony_ci if (recv_avail < 0) { 3873195972f6Sopenharmony_ci recv_avail = 0; 3874195972f6Sopenharmony_ci } 3875195972f6Sopenharmony_ci 3876195972f6Sopenharmony_ci /* Check if there is data left from the last recv operation. /maq 041215 */ 3877195972f6Sopenharmony_ci if (sock->lastdata.netbuf) { 3878195972f6Sopenharmony_ci if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) { 3879195972f6Sopenharmony_ci recv_avail += sock->lastdata.pbuf->tot_len; 3880195972f6Sopenharmony_ci } else { 3881195972f6Sopenharmony_ci recv_avail += sock->lastdata.netbuf->p->tot_len; 3882195972f6Sopenharmony_ci } 3883195972f6Sopenharmony_ci } 3884195972f6Sopenharmony_ci *((int *)argp) = recv_avail; 3885195972f6Sopenharmony_ci 3886195972f6Sopenharmony_ci LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(%d, FIONREAD, %p) = %"U16_F"\n", s, argp, *((u16_t *)argp))); 3887195972f6Sopenharmony_ci sock_set_errno(sock, 0); 3888195972f6Sopenharmony_ci done_socket(sock); 3889195972f6Sopenharmony_ci return 0; 3890195972f6Sopenharmony_ci#else /* LWIP_SO_RCVBUF */ 3891195972f6Sopenharmony_ci break; 3892195972f6Sopenharmony_ci#endif /* LWIP_SO_RCVBUF */ 3893195972f6Sopenharmony_ci#endif /* LWIP_SO_RCVBUF || LWIP_FIONREAD_LINUXMODE */ 3894195972f6Sopenharmony_ci 3895195972f6Sopenharmony_ci case (long)FIONBIO: 3896195972f6Sopenharmony_ci val = 0; 3897195972f6Sopenharmony_ci if (argp && *(int *)argp) { 3898195972f6Sopenharmony_ci val = 1; 3899195972f6Sopenharmony_ci } 3900195972f6Sopenharmony_ci netconn_set_nonblocking(sock->conn, val); 3901195972f6Sopenharmony_ci LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(%d, FIONBIO, %d)\n", s, val)); 3902195972f6Sopenharmony_ci sock_set_errno(sock, 0); 3903195972f6Sopenharmony_ci done_socket(sock); 3904195972f6Sopenharmony_ci return 0; 3905195972f6Sopenharmony_ci 3906195972f6Sopenharmony_ci default: 3907195972f6Sopenharmony_ci IOCTL_CMD_CASE_HANDLER(); 3908195972f6Sopenharmony_ci break; 3909195972f6Sopenharmony_ci } /* switch (cmd) */ 3910195972f6Sopenharmony_ci LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(%d, UNIMPL: 0x%lx, %p)\n", s, cmd, argp)); 3911195972f6Sopenharmony_ci sock_set_errno(sock, ENOSYS); /* not yet implemented */ 3912195972f6Sopenharmony_ci done_socket(sock); 3913195972f6Sopenharmony_ci return -1; 3914195972f6Sopenharmony_ci} 3915195972f6Sopenharmony_ci 3916195972f6Sopenharmony_ci/** A minimal implementation of fcntl. 3917195972f6Sopenharmony_ci * Currently only the commands F_GETFL and F_SETFL are implemented. 3918195972f6Sopenharmony_ci * The flag O_NONBLOCK and access modes are supported for F_GETFL, only 3919195972f6Sopenharmony_ci * the flag O_NONBLOCK is implemented for F_SETFL. 3920195972f6Sopenharmony_ci */ 3921195972f6Sopenharmony_ciint 3922195972f6Sopenharmony_cilwip_fcntl(int s, int cmd, int val) 3923195972f6Sopenharmony_ci{ 3924195972f6Sopenharmony_ci struct lwip_sock *sock = get_socket(s); 3925195972f6Sopenharmony_ci int ret = -1; 3926195972f6Sopenharmony_ci int op_mode = 0; 3927195972f6Sopenharmony_ci 3928195972f6Sopenharmony_ci if (!sock) { 3929195972f6Sopenharmony_ci return -1; 3930195972f6Sopenharmony_ci } 3931195972f6Sopenharmony_ci 3932195972f6Sopenharmony_ci switch (cmd) { 3933195972f6Sopenharmony_ci case F_GETFL: 3934195972f6Sopenharmony_ci ret = netconn_is_nonblocking(sock->conn) ? O_NONBLOCK : 0; 3935195972f6Sopenharmony_ci sock_set_errno(sock, 0); 3936195972f6Sopenharmony_ci 3937195972f6Sopenharmony_ci if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) { 3938195972f6Sopenharmony_ci#if LWIP_TCPIP_CORE_LOCKING 3939195972f6Sopenharmony_ci LOCK_TCPIP_CORE(); 3940195972f6Sopenharmony_ci#else 3941195972f6Sopenharmony_ci SYS_ARCH_DECL_PROTECT(lev); 3942195972f6Sopenharmony_ci /* the proper thing to do here would be to get into the tcpip_thread, 3943195972f6Sopenharmony_ci but locking should be OK as well since we only *read* some flags */ 3944195972f6Sopenharmony_ci SYS_ARCH_PROTECT(lev); 3945195972f6Sopenharmony_ci#endif 3946195972f6Sopenharmony_ci#if LWIP_TCP 3947195972f6Sopenharmony_ci if (sock->conn->pcb.tcp) { 3948195972f6Sopenharmony_ci if (!(sock->conn->pcb.tcp->flags & TF_RXCLOSED)) { 3949195972f6Sopenharmony_ci op_mode |= O_RDONLY; 3950195972f6Sopenharmony_ci } 3951195972f6Sopenharmony_ci if (!(sock->conn->pcb.tcp->flags & TF_FIN)) { 3952195972f6Sopenharmony_ci op_mode |= O_WRONLY; 3953195972f6Sopenharmony_ci } 3954195972f6Sopenharmony_ci } 3955195972f6Sopenharmony_ci#endif 3956195972f6Sopenharmony_ci#if LWIP_TCPIP_CORE_LOCKING 3957195972f6Sopenharmony_ci UNLOCK_TCPIP_CORE(); 3958195972f6Sopenharmony_ci#else 3959195972f6Sopenharmony_ci SYS_ARCH_UNPROTECT(lev); 3960195972f6Sopenharmony_ci#endif 3961195972f6Sopenharmony_ci } else { 3962195972f6Sopenharmony_ci op_mode |= O_RDWR; 3963195972f6Sopenharmony_ci } 3964195972f6Sopenharmony_ci 3965195972f6Sopenharmony_ci /* ensure O_RDWR for (O_RDONLY|O_WRONLY) != O_RDWR cases */ 3966195972f6Sopenharmony_ci ret |= (op_mode == (O_RDONLY | O_WRONLY)) ? O_RDWR : op_mode; 3967195972f6Sopenharmony_ci 3968195972f6Sopenharmony_ci break; 3969195972f6Sopenharmony_ci case F_SETFL: 3970195972f6Sopenharmony_ci /* Bits corresponding to the file access mode and the file creation flags [..] that are set in arg shall be ignored */ 3971195972f6Sopenharmony_ci val &= ~(O_RDONLY | O_WRONLY | O_RDWR); 3972195972f6Sopenharmony_ci if ((val & ~O_NONBLOCK) == 0) { 3973195972f6Sopenharmony_ci /* only O_NONBLOCK, all other bits are zero */ 3974195972f6Sopenharmony_ci netconn_set_nonblocking(sock->conn, val & O_NONBLOCK); 3975195972f6Sopenharmony_ci ret = 0; 3976195972f6Sopenharmony_ci sock_set_errno(sock, 0); 3977195972f6Sopenharmony_ci } else { 3978195972f6Sopenharmony_ci sock_set_errno(sock, ENOSYS); /* not yet implemented */ 3979195972f6Sopenharmony_ci } 3980195972f6Sopenharmony_ci break; 3981195972f6Sopenharmony_ci default: 3982195972f6Sopenharmony_ci LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_fcntl(%d, UNIMPL: %d, %d)\n", s, cmd, val)); 3983195972f6Sopenharmony_ci sock_set_errno(sock, ENOSYS); /* not yet implemented */ 3984195972f6Sopenharmony_ci break; 3985195972f6Sopenharmony_ci } 3986195972f6Sopenharmony_ci done_socket(sock); 3987195972f6Sopenharmony_ci return ret; 3988195972f6Sopenharmony_ci} 3989195972f6Sopenharmony_ci 3990195972f6Sopenharmony_ci#if LWIP_COMPAT_SOCKETS == 2 && LWIP_POSIX_SOCKETS_IO_NAMES 3991195972f6Sopenharmony_ciint 3992195972f6Sopenharmony_cifcntl(int s, int cmd, ...) 3993195972f6Sopenharmony_ci{ 3994195972f6Sopenharmony_ci va_list ap; 3995195972f6Sopenharmony_ci int val; 3996195972f6Sopenharmony_ci 3997195972f6Sopenharmony_ci va_start(ap, cmd); 3998195972f6Sopenharmony_ci val = va_arg(ap, int); 3999195972f6Sopenharmony_ci va_end(ap); 4000195972f6Sopenharmony_ci return lwip_fcntl(s, cmd, val); 4001195972f6Sopenharmony_ci} 4002195972f6Sopenharmony_ci#endif 4003195972f6Sopenharmony_ci 4004195972f6Sopenharmony_ciconst char * 4005195972f6Sopenharmony_cilwip_inet_ntop(int af, const void *src, char *dst, socklen_t size) 4006195972f6Sopenharmony_ci{ 4007195972f6Sopenharmony_ci const char *ret = NULL; 4008195972f6Sopenharmony_ci int size_int = (int)size; 4009195972f6Sopenharmony_ci if (size_int < 0) { 4010195972f6Sopenharmony_ci set_errno(ENOSPC); 4011195972f6Sopenharmony_ci return NULL; 4012195972f6Sopenharmony_ci } 4013195972f6Sopenharmony_ci switch (af) { 4014195972f6Sopenharmony_ci#if LWIP_IPV4 4015195972f6Sopenharmony_ci case AF_INET: 4016195972f6Sopenharmony_ci ret = ip4addr_ntoa_r((const ip4_addr_t *)src, dst, size_int); 4017195972f6Sopenharmony_ci if (ret == NULL) { 4018195972f6Sopenharmony_ci set_errno(ENOSPC); 4019195972f6Sopenharmony_ci } 4020195972f6Sopenharmony_ci break; 4021195972f6Sopenharmony_ci#endif 4022195972f6Sopenharmony_ci#if LWIP_IPV6 4023195972f6Sopenharmony_ci case AF_INET6: 4024195972f6Sopenharmony_ci ret = ip6addr_ntoa_r((const ip6_addr_t *)src, dst, size_int); 4025195972f6Sopenharmony_ci if (ret == NULL) { 4026195972f6Sopenharmony_ci set_errno(ENOSPC); 4027195972f6Sopenharmony_ci } 4028195972f6Sopenharmony_ci break; 4029195972f6Sopenharmony_ci#endif 4030195972f6Sopenharmony_ci default: 4031195972f6Sopenharmony_ci set_errno(EAFNOSUPPORT); 4032195972f6Sopenharmony_ci break; 4033195972f6Sopenharmony_ci } 4034195972f6Sopenharmony_ci return ret; 4035195972f6Sopenharmony_ci} 4036195972f6Sopenharmony_ci 4037195972f6Sopenharmony_ciint 4038195972f6Sopenharmony_cilwip_inet_pton(int af, const char *src, void *dst) 4039195972f6Sopenharmony_ci{ 4040195972f6Sopenharmony_ci int err; 4041195972f6Sopenharmony_ci switch (af) { 4042195972f6Sopenharmony_ci#if LWIP_IPV4 4043195972f6Sopenharmony_ci case AF_INET: 4044195972f6Sopenharmony_ci err = ip4addr_aton(src, (ip4_addr_t *)dst); 4045195972f6Sopenharmony_ci break; 4046195972f6Sopenharmony_ci#endif 4047195972f6Sopenharmony_ci#if LWIP_IPV6 4048195972f6Sopenharmony_ci case AF_INET6: { 4049195972f6Sopenharmony_ci /* convert into temporary variable since ip6_addr_t might be larger 4050195972f6Sopenharmony_ci than in6_addr when scopes are enabled */ 4051195972f6Sopenharmony_ci ip6_addr_t addr; 4052195972f6Sopenharmony_ci err = ip6addr_aton(src, &addr); 4053195972f6Sopenharmony_ci if (err) { 4054195972f6Sopenharmony_ci memcpy(dst, &addr.addr, sizeof(addr.addr)); 4055195972f6Sopenharmony_ci } 4056195972f6Sopenharmony_ci break; 4057195972f6Sopenharmony_ci } 4058195972f6Sopenharmony_ci#endif 4059195972f6Sopenharmony_ci default: 4060195972f6Sopenharmony_ci err = -1; 4061195972f6Sopenharmony_ci set_errno(EAFNOSUPPORT); 4062195972f6Sopenharmony_ci break; 4063195972f6Sopenharmony_ci } 4064195972f6Sopenharmony_ci return err; 4065195972f6Sopenharmony_ci} 4066195972f6Sopenharmony_ci 4067195972f6Sopenharmony_ci#if LWIP_IGMP 4068195972f6Sopenharmony_ci/** Register a new IGMP membership. On socket close, the membership is dropped automatically. 4069195972f6Sopenharmony_ci * 4070195972f6Sopenharmony_ci * ATTENTION: this function is called from tcpip_thread (or under CORE_LOCK). 4071195972f6Sopenharmony_ci * 4072195972f6Sopenharmony_ci * @return 1 on success, 0 on failure 4073195972f6Sopenharmony_ci */ 4074195972f6Sopenharmony_cistatic int 4075195972f6Sopenharmony_cilwip_socket_register_membership(int s, const ip4_addr_t *if_addr, const ip4_addr_t *multi_addr) 4076195972f6Sopenharmony_ci{ 4077195972f6Sopenharmony_ci struct lwip_sock *sock = get_socket(s); 4078195972f6Sopenharmony_ci int i; 4079195972f6Sopenharmony_ci 4080195972f6Sopenharmony_ci if (!sock) { 4081195972f6Sopenharmony_ci return 0; 4082195972f6Sopenharmony_ci } 4083195972f6Sopenharmony_ci 4084195972f6Sopenharmony_ci for (i = 0; i < LWIP_SOCKET_MAX_MEMBERSHIPS; i++) { 4085195972f6Sopenharmony_ci if (socket_ipv4_multicast_memberships[i].sock == NULL) { 4086195972f6Sopenharmony_ci socket_ipv4_multicast_memberships[i].sock = sock; 4087195972f6Sopenharmony_ci ip4_addr_copy(socket_ipv4_multicast_memberships[i].if_addr, *if_addr); 4088195972f6Sopenharmony_ci ip4_addr_copy(socket_ipv4_multicast_memberships[i].multi_addr, *multi_addr); 4089195972f6Sopenharmony_ci done_socket(sock); 4090195972f6Sopenharmony_ci return 1; 4091195972f6Sopenharmony_ci } 4092195972f6Sopenharmony_ci } 4093195972f6Sopenharmony_ci done_socket(sock); 4094195972f6Sopenharmony_ci return 0; 4095195972f6Sopenharmony_ci} 4096195972f6Sopenharmony_ci 4097195972f6Sopenharmony_ci/** Unregister a previously registered membership. This prevents dropping the membership 4098195972f6Sopenharmony_ci * on socket close. 4099195972f6Sopenharmony_ci * 4100195972f6Sopenharmony_ci * ATTENTION: this function is called from tcpip_thread (or under CORE_LOCK). 4101195972f6Sopenharmony_ci */ 4102195972f6Sopenharmony_cistatic void 4103195972f6Sopenharmony_cilwip_socket_unregister_membership(int s, const ip4_addr_t *if_addr, const ip4_addr_t *multi_addr) 4104195972f6Sopenharmony_ci{ 4105195972f6Sopenharmony_ci struct lwip_sock *sock = get_socket(s); 4106195972f6Sopenharmony_ci int i; 4107195972f6Sopenharmony_ci 4108195972f6Sopenharmony_ci if (!sock) { 4109195972f6Sopenharmony_ci return; 4110195972f6Sopenharmony_ci } 4111195972f6Sopenharmony_ci 4112195972f6Sopenharmony_ci for (i = 0; i < LWIP_SOCKET_MAX_MEMBERSHIPS; i++) { 4113195972f6Sopenharmony_ci if ((socket_ipv4_multicast_memberships[i].sock == sock) && 4114195972f6Sopenharmony_ci ip4_addr_cmp(&socket_ipv4_multicast_memberships[i].if_addr, if_addr) && 4115195972f6Sopenharmony_ci ip4_addr_cmp(&socket_ipv4_multicast_memberships[i].multi_addr, multi_addr)) { 4116195972f6Sopenharmony_ci socket_ipv4_multicast_memberships[i].sock = NULL; 4117195972f6Sopenharmony_ci ip4_addr_set_zero(&socket_ipv4_multicast_memberships[i].if_addr); 4118195972f6Sopenharmony_ci ip4_addr_set_zero(&socket_ipv4_multicast_memberships[i].multi_addr); 4119195972f6Sopenharmony_ci break; 4120195972f6Sopenharmony_ci } 4121195972f6Sopenharmony_ci } 4122195972f6Sopenharmony_ci done_socket(sock); 4123195972f6Sopenharmony_ci} 4124195972f6Sopenharmony_ci 4125195972f6Sopenharmony_ci/** Drop all memberships of a socket that were not dropped explicitly via setsockopt. 4126195972f6Sopenharmony_ci * 4127195972f6Sopenharmony_ci * ATTENTION: this function is NOT called from tcpip_thread (or under CORE_LOCK). 4128195972f6Sopenharmony_ci */ 4129195972f6Sopenharmony_cistatic void 4130195972f6Sopenharmony_cilwip_socket_drop_registered_memberships(int s) 4131195972f6Sopenharmony_ci{ 4132195972f6Sopenharmony_ci struct lwip_sock *sock = get_socket(s); 4133195972f6Sopenharmony_ci int i; 4134195972f6Sopenharmony_ci 4135195972f6Sopenharmony_ci if (!sock) { 4136195972f6Sopenharmony_ci return; 4137195972f6Sopenharmony_ci } 4138195972f6Sopenharmony_ci 4139195972f6Sopenharmony_ci for (i = 0; i < LWIP_SOCKET_MAX_MEMBERSHIPS; i++) { 4140195972f6Sopenharmony_ci if (socket_ipv4_multicast_memberships[i].sock == sock) { 4141195972f6Sopenharmony_ci ip_addr_t multi_addr, if_addr; 4142195972f6Sopenharmony_ci ip_addr_copy_from_ip4(multi_addr, socket_ipv4_multicast_memberships[i].multi_addr); 4143195972f6Sopenharmony_ci ip_addr_copy_from_ip4(if_addr, socket_ipv4_multicast_memberships[i].if_addr); 4144195972f6Sopenharmony_ci socket_ipv4_multicast_memberships[i].sock = NULL; 4145195972f6Sopenharmony_ci ip4_addr_set_zero(&socket_ipv4_multicast_memberships[i].if_addr); 4146195972f6Sopenharmony_ci ip4_addr_set_zero(&socket_ipv4_multicast_memberships[i].multi_addr); 4147195972f6Sopenharmony_ci 4148195972f6Sopenharmony_ci netconn_join_leave_group(sock->conn, &multi_addr, &if_addr, NETCONN_LEAVE); 4149195972f6Sopenharmony_ci } 4150195972f6Sopenharmony_ci } 4151195972f6Sopenharmony_ci done_socket(sock); 4152195972f6Sopenharmony_ci} 4153195972f6Sopenharmony_ci#endif /* LWIP_IGMP */ 4154195972f6Sopenharmony_ci 4155195972f6Sopenharmony_ci#if LWIP_IPV6_MLD 4156195972f6Sopenharmony_ci/** Register a new MLD6 membership. On socket close, the membership is dropped automatically. 4157195972f6Sopenharmony_ci * 4158195972f6Sopenharmony_ci * ATTENTION: this function is called from tcpip_thread (or under CORE_LOCK). 4159195972f6Sopenharmony_ci * 4160195972f6Sopenharmony_ci * @return 1 on success, 0 on failure 4161195972f6Sopenharmony_ci */ 4162195972f6Sopenharmony_cistatic int 4163195972f6Sopenharmony_cilwip_socket_register_mld6_membership(int s, unsigned int if_idx, const ip6_addr_t *multi_addr) 4164195972f6Sopenharmony_ci{ 4165195972f6Sopenharmony_ci struct lwip_sock *sock = get_socket(s); 4166195972f6Sopenharmony_ci int i; 4167195972f6Sopenharmony_ci 4168195972f6Sopenharmony_ci if (!sock) { 4169195972f6Sopenharmony_ci return 0; 4170195972f6Sopenharmony_ci } 4171195972f6Sopenharmony_ci 4172195972f6Sopenharmony_ci for (i = 0; i < LWIP_SOCKET_MAX_MEMBERSHIPS; i++) { 4173195972f6Sopenharmony_ci if (socket_ipv6_multicast_memberships[i].sock == NULL) { 4174195972f6Sopenharmony_ci socket_ipv6_multicast_memberships[i].sock = sock; 4175195972f6Sopenharmony_ci socket_ipv6_multicast_memberships[i].if_idx = (u8_t)if_idx; 4176195972f6Sopenharmony_ci ip6_addr_copy(socket_ipv6_multicast_memberships[i].multi_addr, *multi_addr); 4177195972f6Sopenharmony_ci done_socket(sock); 4178195972f6Sopenharmony_ci return 1; 4179195972f6Sopenharmony_ci } 4180195972f6Sopenharmony_ci } 4181195972f6Sopenharmony_ci done_socket(sock); 4182195972f6Sopenharmony_ci return 0; 4183195972f6Sopenharmony_ci} 4184195972f6Sopenharmony_ci 4185195972f6Sopenharmony_ci/** Unregister a previously registered MLD6 membership. This prevents dropping the membership 4186195972f6Sopenharmony_ci * on socket close. 4187195972f6Sopenharmony_ci * 4188195972f6Sopenharmony_ci * ATTENTION: this function is called from tcpip_thread (or under CORE_LOCK). 4189195972f6Sopenharmony_ci */ 4190195972f6Sopenharmony_cistatic void 4191195972f6Sopenharmony_cilwip_socket_unregister_mld6_membership(int s, unsigned int if_idx, const ip6_addr_t *multi_addr) 4192195972f6Sopenharmony_ci{ 4193195972f6Sopenharmony_ci struct lwip_sock *sock = get_socket(s); 4194195972f6Sopenharmony_ci int i; 4195195972f6Sopenharmony_ci 4196195972f6Sopenharmony_ci if (!sock) { 4197195972f6Sopenharmony_ci return; 4198195972f6Sopenharmony_ci } 4199195972f6Sopenharmony_ci 4200195972f6Sopenharmony_ci for (i = 0; i < LWIP_SOCKET_MAX_MEMBERSHIPS; i++) { 4201195972f6Sopenharmony_ci if ((socket_ipv6_multicast_memberships[i].sock == sock) && 4202195972f6Sopenharmony_ci (socket_ipv6_multicast_memberships[i].if_idx == if_idx) && 4203195972f6Sopenharmony_ci ip6_addr_cmp(&socket_ipv6_multicast_memberships[i].multi_addr, multi_addr)) { 4204195972f6Sopenharmony_ci socket_ipv6_multicast_memberships[i].sock = NULL; 4205195972f6Sopenharmony_ci socket_ipv6_multicast_memberships[i].if_idx = NETIF_NO_INDEX; 4206195972f6Sopenharmony_ci ip6_addr_set_zero(&socket_ipv6_multicast_memberships[i].multi_addr); 4207195972f6Sopenharmony_ci break; 4208195972f6Sopenharmony_ci } 4209195972f6Sopenharmony_ci } 4210195972f6Sopenharmony_ci done_socket(sock); 4211195972f6Sopenharmony_ci} 4212195972f6Sopenharmony_ci 4213195972f6Sopenharmony_ci/** Drop all MLD6 memberships of a socket that were not dropped explicitly via setsockopt. 4214195972f6Sopenharmony_ci * 4215195972f6Sopenharmony_ci * ATTENTION: this function is NOT called from tcpip_thread (or under CORE_LOCK). 4216195972f6Sopenharmony_ci */ 4217195972f6Sopenharmony_cistatic void 4218195972f6Sopenharmony_cilwip_socket_drop_registered_mld6_memberships(int s) 4219195972f6Sopenharmony_ci{ 4220195972f6Sopenharmony_ci struct lwip_sock *sock = get_socket(s); 4221195972f6Sopenharmony_ci int i; 4222195972f6Sopenharmony_ci 4223195972f6Sopenharmony_ci if (!sock) { 4224195972f6Sopenharmony_ci return; 4225195972f6Sopenharmony_ci } 4226195972f6Sopenharmony_ci 4227195972f6Sopenharmony_ci for (i = 0; i < LWIP_SOCKET_MAX_MEMBERSHIPS; i++) { 4228195972f6Sopenharmony_ci if (socket_ipv6_multicast_memberships[i].sock == sock) { 4229195972f6Sopenharmony_ci ip_addr_t multi_addr; 4230195972f6Sopenharmony_ci u8_t if_idx; 4231195972f6Sopenharmony_ci 4232195972f6Sopenharmony_ci ip_addr_copy_from_ip6(multi_addr, socket_ipv6_multicast_memberships[i].multi_addr); 4233195972f6Sopenharmony_ci if_idx = socket_ipv6_multicast_memberships[i].if_idx; 4234195972f6Sopenharmony_ci 4235195972f6Sopenharmony_ci socket_ipv6_multicast_memberships[i].sock = NULL; 4236195972f6Sopenharmony_ci socket_ipv6_multicast_memberships[i].if_idx = NETIF_NO_INDEX; 4237195972f6Sopenharmony_ci ip6_addr_set_zero(&socket_ipv6_multicast_memberships[i].multi_addr); 4238195972f6Sopenharmony_ci 4239195972f6Sopenharmony_ci netconn_join_leave_group_netif(sock->conn, &multi_addr, if_idx, NETCONN_LEAVE); 4240195972f6Sopenharmony_ci } 4241195972f6Sopenharmony_ci } 4242195972f6Sopenharmony_ci done_socket(sock); 4243195972f6Sopenharmony_ci} 4244195972f6Sopenharmony_ci#endif /* LWIP_IPV6_MLD */ 4245195972f6Sopenharmony_ci 4246195972f6Sopenharmony_ci#endif /* LWIP_SOCKET */ 4247