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