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