• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * @file
3  * Sockets BSD-Like API module
4  */
5 
6 /*
7  * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
8  * All rights reserved.
9  *
10  * Redistribution and use in source and binary forms, with or without modification,
11  * are permitted provided that the following conditions are met:
12  *
13  * 1. Redistributions of source code must retain the above copyright notice,
14  *    this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright notice,
16  *    this list of conditions and the following disclaimer in the documentation
17  *    and/or other materials provided with the distribution.
18  * 3. The name of the author may not be used to endorse or promote products
19  *    derived from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
22  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
23  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
24  * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
26  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
29  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
30  * OF SUCH DAMAGE.
31  *
32  * This file is part of the lwIP TCP/IP stack.
33  *
34  * Author: Adam Dunkels <adam@sics.se>
35  *
36  * Improved by Marc Boucher <marc@mbsi.ca> and David Haas <dhaas@alum.rpi.edu>
37  *
38  */
39 
40 #include "lwip/opt.h"
41 
42 #if LWIP_SOCKET /* don't build if not configured for use in lwipopts.h */
43 
44 #include "lwip/sockets.h"
45 #include "lwip/priv/sockets_priv.h"
46 #include "netif/ifaddrs.h"
47 #include "lwip/api.h"
48 #include "lwip/igmp.h"
49 #include "lwip/inet.h"
50 #include "lwip/tcp.h"
51 #include "lwip/raw.h"
52 #include "lwip/udp.h"
53 #include "lwip/memp.h"
54 #include "lwip/pbuf.h"
55 #include "lwip/netif.h"
56 #include "netif/etharp.h"
57 #include "lwip/priv/tcpip_priv.h"
58 #include "lwip/priv/api_msg.h"
59 #include "lwip/mld6.h"
60 
61 #if LWIP_IPV6_DHCP6
62 #include "lwip/dhcp6.h"
63 #include "lwip/prot/dhcp6.h"
64 #endif /* LWIP_IPV6_DHCP6 */
65 
66 #if LWIP_DHCP
67 #include "lwip/dhcp.h"
68 #endif
69 
70 #if LWIP_CHECKSUM_ON_COPY
71 #include "lwip/inet_chksum.h"
72 #endif
73 #include "lwip/tcp_info.h"
74 
75 #if LWIP_NETIF_ETHTOOL
76 #include "lwip/ethtool.h"
77 #endif
78 
79 #if LWIP_COMPAT_SOCKETS == 2 && LWIP_POSIX_SOCKETS_IO_NAMES
80 #include <stdarg.h>
81 #endif
82 #include <string.h>
83 
84 #ifdef LWIP_HOOK_FILENAME
85 #include LWIP_HOOK_FILENAME
86 #endif
87 
88 #if LWIP_LOWPOWER
89 #include "lwip/lowpower.h"
90 #endif
91 
92 /* If the netconn API is not required publicly, then we include the necessary
93    files here to get the implementation */
94 #if !LWIP_NETCONN
95 #undef LWIP_NETCONN
96 #define LWIP_NETCONN 1
97 #include "api_msg.c"
98 #include "api_lib.c"
99 #include "netbuf.c"
100 #undef LWIP_NETCONN
101 #define LWIP_NETCONN 0
102 #endif
103 
104 #if LWIP_ENABLE_NET_CAPABILITY
105 #include "capability_type.h"
106 #include "capability_api.h"
107 #define BIND_SERVICE_CAP_MIN_PORT 1024
108 #endif
109 
110 #define API_SELECT_CB_VAR_REF(name)               API_VAR_REF(name)
111 #define API_SELECT_CB_VAR_DECLARE(name)           API_VAR_DECLARE(struct lwip_select_cb, name)
112 #define API_SELECT_CB_VAR_ALLOC(name, retblock)   API_VAR_ALLOC_EXT(struct lwip_select_cb, MEMP_SELECT_CB, name, retblock)
113 #define API_SELECT_CB_VAR_FREE(name)              API_VAR_FREE(MEMP_SELECT_CB, name)
114 
115 #if LWIP_IPV4
116 #define IP4ADDR_PORT_TO_SOCKADDR(sin, ipaddr, port) do { \
117       (sin)->sin_family = AF_INET; \
118       (sin)->sin_port = lwip_htons((port)); \
119       inet_addr_from_ip4addr(&(sin)->sin_addr, ipaddr); \
120       memset((sin)->sin_zero, 0, SIN_ZERO_LEN); }while(0)
121 #define SOCKADDR4_TO_IP4ADDR_PORT(sin, ipaddr, port) do { \
122     inet_addr_to_ip4addr(ip_2_ip4(ipaddr), &((sin)->sin_addr)); \
123     (port) = lwip_ntohs((sin)->sin_port); }while(0)
124 #endif /* LWIP_IPV4 */
125 
126 #if LWIP_IPV6
127 /* SIN6_LEN macro is to differntiate whether stack is using 4.3BSD or 4.4BSD variants of sockaddr_in6
128 structure */
129 #if defined(SIN6_LEN)
130 #define IP6ADDR_PORT_TO_SOCKADDR(sin6, ipaddr, port) do { \
131       (sin6)->sin6_len = sizeof(struct sockaddr_in6); \
132       (sin6)->sin6_family = AF_INET6; \
133       (sin6)->sin6_port = lwip_htons((port)); \
134       (sin6)->sin6_flowinfo = 0; \
135       inet6_addr_from_ip6addr(&(sin6)->sin6_addr, ipaddr); \
136       (sin6)->sin6_scope_id = ip6_addr_zone(ipaddr); }while(0)
137 #else
138 #define IP6ADDR_PORT_TO_SOCKADDR(sin6, ipaddr, port) do { \
139       (sin6)->sin6_family = AF_INET6; \
140       (sin6)->sin6_port = lwip_htons((port)); \
141       (sin6)->sin6_flowinfo = 0; \
142       inet6_addr_from_ip6addr(&(sin6)->sin6_addr, ipaddr); \
143       (sin6)->sin6_scope_id = ip6_addr_zone(ipaddr); } while (0)
144 #endif
145 #define SOCKADDR6_TO_IP6ADDR_PORT(sin6, ipaddr, port) do { \
146     inet6_addr_to_ip6addr(ip_2_ip6(ipaddr), &((sin6)->sin6_addr)); \
147     if (ip6_addr_has_scope(ip_2_ip6(ipaddr), IP6_UNKNOWN)) { \
148       ip6_addr_set_zone(ip_2_ip6(ipaddr), (u8_t)((sin6)->sin6_scope_id)); \
149     } \
150     (port) = lwip_ntohs((sin6)->sin6_port); }while(0)
151 #endif /* LWIP_IPV6 */
152 
153 #if LWIP_IPV4 && LWIP_IPV6
154 static void sockaddr_to_ipaddr_port(const struct sockaddr *sockaddr, ip_addr_t *ipaddr, u16_t *port);
155 static int lwip_sockopt_check_optlen_conn_pcb(const struct lwip_sock *sock, socklen_t optlen, socklen_t len);
156 static int lwip_sockopt_check_optlen_conn_pcb_type(const struct lwip_sock *sock, socklen_t optlen, socklen_t len,
157                                                    enum netconn_type type, int is_v6);
158 
159 #define IS_SOCK_ADDR_LEN_VALID(namelen)  (((namelen) == sizeof(struct sockaddr_in)) || \
160                                          ((namelen) == sizeof(struct sockaddr_in6)))
161 #define IS_SOCK_ADDR_TYPE_VALID(name)    (((name)->sa_family == AF_INET) || \
162                                          ((name)->sa_family == AF_INET6))
163 #define IS_SOCK_ADDR_TYPE_LEN_COMPAT(name, namelen) ((((name)->sa_family == AF_INET) && \
164                                                        ((namelen) == sizeof(struct sockaddr_in))) || \
165                                                      (((name)->sa_family == AF_INET6) && \
166                                                       ((namelen) == sizeof(struct sockaddr_in6))))
167 #define SOCK_ADDR_TYPE_MATCH(name, sock) \
168        ((((name)->sa_family == AF_INET) && !(NETCONNTYPE_ISIPV6((sock)->conn->type))) || \
169        (((name)->sa_family == AF_INET6) && (NETCONNTYPE_ISIPV6((sock)->conn->type))))
170 #define IPADDR_PORT_TO_SOCKADDR(sockaddr, ipaddr, port) do { \
171     if (IP_IS_ANY_TYPE_VAL(*ipaddr) || IP_IS_V6_VAL(*ipaddr)) { \
172       IP6ADDR_PORT_TO_SOCKADDR((struct sockaddr_in6*)(void*)(sockaddr), ip_2_ip6(ipaddr), port); \
173     } else { \
174       IP4ADDR_PORT_TO_SOCKADDR((struct sockaddr_in*)(void*)(sockaddr), ip_2_ip4(ipaddr), port); \
175     } } while(0)
176 #define SOCKADDR_TO_IPADDR_PORT(sockaddr, ipaddr, port) sockaddr_to_ipaddr_port(sockaddr, ipaddr, &(port))
177 #define DOMAIN_TO_NETCONN_TYPE(domain, type) (((domain) == AF_INET6) ? \
178   (enum netconn_type)(((uint32_t)(type)) | NETCONN_TYPE_IPV6) : (type))
179 #elif LWIP_IPV6 /* LWIP_IPV4 && LWIP_IPV6 */
180 #define IS_SOCK_ADDR_LEN_VALID(namelen)  ((namelen) == sizeof(struct sockaddr_in6))
181 #define IS_SOCK_ADDR_TYPE_VALID(name)    ((name)->sa_family == AF_INET6)
182 #define SOCK_ADDR_TYPE_MATCH(name, sock) 1
183 #define IPADDR_PORT_TO_SOCKADDR(sockaddr, ipaddr, port) \
184         IP6ADDR_PORT_TO_SOCKADDR((struct sockaddr_in6*)(void*)(sockaddr), ip_2_ip6(ipaddr), port)
185 #define SOCKADDR_TO_IPADDR_PORT(sockaddr, ipaddr, port) \
186         SOCKADDR6_TO_IP6ADDR_PORT((const struct sockaddr_in6*)(const void*)(sockaddr), ipaddr, port)
187 #define DOMAIN_TO_NETCONN_TYPE(domain, netconn_type) (netconn_type)
188 #else /*-> LWIP_IPV4: LWIP_IPV4 && LWIP_IPV6 */
189 #define IS_SOCK_ADDR_LEN_VALID(namelen)  ((namelen) == sizeof(struct sockaddr_in))
190 #define IS_SOCK_ADDR_TYPE_VALID(name)    ((name)->sa_family == AF_INET)
191 #define SOCK_ADDR_TYPE_MATCH(name, sock) 1
192 #define IPADDR_PORT_TO_SOCKADDR(sockaddr, ipaddr, port) \
193         IP4ADDR_PORT_TO_SOCKADDR((struct sockaddr_in*)(void*)(sockaddr), ip_2_ip4(ipaddr), port)
194 #define SOCKADDR_TO_IPADDR_PORT(sockaddr, ipaddr, port) \
195         SOCKADDR4_TO_IP4ADDR_PORT((const struct sockaddr_in*)(const void*)(sockaddr), ipaddr, port)
196 #define DOMAIN_TO_NETCONN_TYPE(domain, netconn_type) (netconn_type)
197 #endif /* LWIP_IPV6 */
198 
199 #define IS_SOCK_ADDR_TYPE_VALID_OR_UNSPEC(name)    (((name)->sa_family == AF_UNSPEC) || \
200                                                     IS_SOCK_ADDR_TYPE_VALID(name))
201 #define SOCK_ADDR_TYPE_MATCH_OR_UNSPEC(name, sock) (((name)->sa_family == AF_UNSPEC) || \
202                                                     SOCK_ADDR_TYPE_MATCH(name, sock))
203 #define IS_SOCK_ADDR_ALIGNED(name)      ((((mem_ptr_t)(name)) % LWIP_MIN(4, MEM_ALIGNMENT)) == 0)
204 
205 
206 #define LWIP_SOCKOPT_CHECK_OPTLEN(sock, optlen, opttype) do { if ((optlen) < sizeof(opttype)) { done_socket(sock); return EINVAL; }}while(0)
207 #define LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, optlen, opttype) do { \
208   LWIP_SOCKOPT_CHECK_OPTLEN(sock, optlen, opttype); \
209   if ((sock)->conn == NULL) { done_socket(sock); return EINVAL; } }while(0)
210 #define LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, optlen, opttype) do { \
211   int ret = lwip_sockopt_check_optlen_conn_pcb(sock, optlen, (socklen_t)sizeof(opttype)); \
212   if (ret != 0) { \
213     done_socket(sock); \
214     return ret; \
215   } \
216 } while (0)
217 
218 #define LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, opttype, netconntype) do { \
219   int ret = lwip_sockopt_check_optlen_conn_pcb_type(sock, optlen, (socklen_t)sizeof(opttype), netconntype, 0); \
220   if (ret != 0) { \
221     done_socket(sock); \
222     return ret; \
223   } \
224 } while (0)
225 
226 #if LWIP_IPV6
227 #define LWIP_SOCKOPT_CHECK_IPTYPE_V6(sock, contype) do { \
228   if (!(NETCONNTYPE_ISIPV6(contype))) { \
229     done_socket(sock); \
230     return ENOPROTOOPT; \
231   } \
232 } while (0)
233 
234 #define LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE_IPV6(sock, optlen, opttype, netconntype) do { \
235   int ret = lwip_sockopt_check_optlen_conn_pcb_type(sock, optlen, sizeof(opttype), netconntype, 1); \
236   if (ret != 0) { \
237     done_socket(sock); \
238     return ret; \
239   } \
240 } while (0)
241 #endif /* LWIP_IPV6 */
242 
243 #define LWIP_SETGETSOCKOPT_DATA_VAR_REF(name)     API_VAR_REF(name)
244 #define LWIP_SETGETSOCKOPT_DATA_VAR_DECLARE(name) API_VAR_DECLARE(struct lwip_setgetsockopt_data, name)
245 #define LWIP_SETGETSOCKOPT_DATA_VAR_FREE(name)    API_VAR_FREE(MEMP_SOCKET_SETGETSOCKOPT_DATA, name)
246 #if LWIP_MPU_COMPATIBLE
247 #define LWIP_SETGETSOCKOPT_DATA_VAR_ALLOC(name, sock) do { \
248   name = (struct lwip_setgetsockopt_data *)memp_malloc(MEMP_SOCKET_SETGETSOCKOPT_DATA); \
249   if (name == NULL) { \
250     sock_set_errno(sock, ENOMEM); \
251     done_socket(sock); \
252     return -1; \
253   } }while(0)
254 #else /* LWIP_MPU_COMPATIBLE */
255 #define LWIP_SETGETSOCKOPT_DATA_VAR_ALLOC(name, sock)
256 #endif /* LWIP_MPU_COMPATIBLE */
257 
258 #if LWIP_SO_SNDRCVTIMEO_NONSTANDARD
259 #define LWIP_SO_SNDRCVTIMEO_OPTTYPE int
260 #define LWIP_SO_SNDRCVTIMEO_SET(optval, val) (*(int *)(optval) = (val))
261 #define LWIP_SO_SNDRCVTIMEO_GET_MS(optval)   ((long)*(const int*)(optval))
262 #define LWIP_SO_SNDRECVTIMO_VALIDATE(_sock, optval)
263 
264 #else
265 #define LWIP_SO_SNDRCVTIMEO_OPTTYPE struct timeval
266 #define LWIP_SO_SNDRCVTIMEO_SET(optval, val)  do { \
267   u32_t loc = (val); \
268   ((struct timeval *)(optval))->tv_sec = (long)((loc) / 1000U); \
269   ((struct timeval *)(optval))->tv_usec = (long)(((loc) % 1000U) * 1000U); }while (0)
270 #define LWIP_SO_SNDRCVTIMEO_GET_MS(optval) ((((const struct timeval *)(optval))->tv_sec * 1000) + (((const struct timeval *)(optval))->tv_usec / 1000))
271 #define LWIP_MAX_TV_SEC_VAL       ((0x7FFFFFFF / 1000)-1000)
272 #define LWIP_SO_SNDRECVTIMO_VALIDATE(_sock, optval) do { \
273       struct timeval * tv = (struct timeval *)optval; \
274         if (tv->tv_usec < 0 || tv->tv_sec < 0 || tv->tv_usec >= 1000000 \
275           || tv->tv_sec >= LWIP_MAX_TV_SEC_VAL) { \
276         done_socket(_sock); \
277           return  EDOM; \
278       } else if (tv->tv_sec == 0 && tv->tv_usec < 1000 && tv->tv_usec > 0) { \
279         done_socket(_sock); \
280         return EINVAL; \
281       } \
282     }while (0)
283 
284 #endif
285 
286 /** A struct sockaddr replacement that has the same alignment as sockaddr_in/
287  *  sockaddr_in6 if instantiated.
288  */
289 union sockaddr_aligned {
290   struct sockaddr sa;
291 #if LWIP_IPV6
292   struct sockaddr_in6 sin6;
293 #endif /* LWIP_IPV6 */
294 #if LWIP_IPV4
295   struct sockaddr_in sin;
296 #endif /* LWIP_IPV4 */
297 };
298 
299 /* Define the number of IPv4 multicast memberships, default is one per socket */
300 #ifndef LWIP_SOCKET_MAX_MEMBERSHIPS
301 #define LWIP_SOCKET_MAX_MEMBERSHIPS LWIP_CONFIG_NUM_SOCKETS
302 #endif
303 
304 #if LWIP_IGMP
305 /* This is to keep track of IP_ADD_MEMBERSHIP calls to drop the membership when
306    a socket is closed */
307 struct lwip_socket_multicast_pair {
308   /** the socket */
309   struct lwip_sock *sock;
310   /** the interface address */
311   ip4_addr_t if_addr;
312   /** the group address */
313   ip4_addr_t multi_addr;
314 };
315 
316 #if LWIP_ALLOW_SOCKET_CONFIG
317 struct lwip_socket_multicast_pair *socket_ipv4_multicast_memberships = NULL;
318 #else
319 static struct lwip_socket_multicast_pair socket_ipv4_multicast_memberships[LWIP_SOCKET_MAX_MEMBERSHIPS];
320 #endif
321 
322 static int  lwip_socket_register_membership(int s, const ip4_addr_t *if_addr, const ip4_addr_t *multi_addr);
323 static void lwip_socket_unregister_membership(int s, const ip4_addr_t *if_addr, const ip4_addr_t *multi_addr);
324 static void lwip_socket_drop_registered_memberships(int s);
325 #endif /* LWIP_IGMP */
326 
327 #if LWIP_IPV6 && LWIP_IPV6_MLD
328 /* This is to keep track of IP_JOIN_GROUP calls to drop the membership when
329    a socket is closed */
330 struct lwip_socket_multicast_mld6_pair {
331   /** the socket */
332   struct lwip_sock *sock;
333   /** the interface index */
334   u8_t if_idx;
335   /** the group address */
336   ip6_addr_t multi_addr;
337 };
338 
339 #if LWIP_ALLOW_SOCKET_CONFIG
340 static struct lwip_socket_multicast_mld6_pair *socket_ipv6_multicast_memberships = NULL;
341 #else
342 static struct lwip_socket_multicast_mld6_pair socket_ipv6_multicast_memberships[LWIP_SOCKET_MAX_MEMBERSHIPS];
343 #endif
344 
345 static int  lwip_socket_register_mld6_membership(int s, unsigned int if_idx, const ip6_addr_t *multi_addr);
346 static void lwip_socket_unregister_mld6_membership(int s, unsigned int if_idx, const ip6_addr_t *multi_addr);
347 static void lwip_socket_drop_registered_mld6_memberships(int s);
348 #endif /* LWIP_IPV6 && LWIP_IPV6_MLD */
349 
350 /** The global array of available sockets */
351 #if LWIP_ALLOW_SOCKET_CONFIG
352 static struct lwip_sock *sockets = NULL;
353 #else
354 static struct lwip_sock sockets[LWIP_CONFIG_NUM_SOCKETS];
355 #endif
356 
357 #if LWIP_SOCKET_SELECT || LWIP_SOCKET_POLL
358 #if LWIP_TCPIP_CORE_LOCKING
359 /* protect the select_cb_list using core lock */
360 #define LWIP_SOCKET_SELECT_DECL_PROTECT(lev)
361 #define LWIP_SOCKET_SELECT_PROTECT(lev)   LOCK_TCPIP_CORE()
362 #define LWIP_SOCKET_SELECT_UNPROTECT(lev) UNLOCK_TCPIP_CORE()
363 #else /* LWIP_TCPIP_CORE_LOCKING */
364 /* protect the select_cb_list using SYS_LIGHTWEIGHT_PROT */
365 #define LWIP_SOCKET_SELECT_DECL_PROTECT(lev)  SYS_ARCH_DECL_PROTECT(lev)
366 #define LWIP_SOCKET_SELECT_PROTECT(lev)       SYS_ARCH_PROTECT(lev)
367 #define LWIP_SOCKET_SELECT_UNPROTECT(lev)     SYS_ARCH_UNPROTECT(lev)
368 /** This counter is increased from lwip_select when the list is changed
369     and checked in select_check_waiters to see if it has changed. */
370 static volatile int select_cb_ctr;
371 #endif /* LWIP_TCPIP_CORE_LOCKING */
372 /** The global list of tasks waiting for select */
373 static struct lwip_select_cb *select_cb_list;
374 #endif /* LWIP_SOCKET_SELECT || LWIP_SOCKET_POLL */
375 
376 #define sock_set_errno(sk, e) do { \
377   const int sockerr = (e); \
378   (void)atomic_set(&sk->err, sockerr); \
379   set_errno(sockerr); \
380 } while (0)
381 
382 #define VALIDATE_SET_RAW_OPTNAME_RET(_sock,_optname) do { \
383       if (((_sock)->conn != NULL && NETCONNTYPE_GROUP((_sock)->conn->type) == NETCONN_RAW) && \
384         (((_optname) != SO_BROADCAST) && ((_optname) != SO_RCVTIMEO) && \
385         ((_optname)  != SO_RCVBUF) && ((_optname) != SO_DONTROUTE) && ((_optname) != SO_BINDTODEVICE) && \
386         ((_optname)  != SO_PRIORITY))) { \
387         done_socket(_sock); \
388         return ENOPROTOOPT; \
389       } \
390     } while (0)
391 
392 #define VALIDATE_GET_RAW_OPTNAME_RET(_sock,_optname) do { \
393       if ((_sock)->conn != NULL && (NETCONNTYPE_GROUP((_sock)->conn->type) == NETCONN_RAW) && \
394         (((_optname) != SO_BROADCAST) && ((_optname) != SO_RCVTIMEO) && \
395         ((_optname) != SO_RCVBUF) && ((_optname) != SO_TYPE) && \
396         ((_optname) != SO_DONTROUTE) && ((_optname) != SO_BINDTODEVICE) && \
397         ((_optname) != SO_PRIORITY))) { \
398         done_socket(_sock); \
399         return ENOPROTOOPT;   \
400       } \
401     } while (0)
402 
403 #if PF_PKT_SUPPORT
404 #define VALIDATE_SET_PF_PKT_OPTNAME_RET(_s,_sock,_level,_optname) do { \
405       if ((_level) == SOL_PACKET && ((_optname) != SO_RCVTIMEO && (_optname) != SO_RCVBUF) &&  \
406           (_optname) != SO_ATTACH_FILTER && (_optname) != SO_DETACH_FILTER) { \
407         LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, SOL_PACKET, UNIMPL: optname=0x%x, ..)\n",  \
408                     (_s), (_optname)));  \
409         done_socket(_sock); \
410         return ENOPROTOOPT;  \
411       } \
412     } while (0)
413 
414 #define VALIDATE_GET_PF_PKT_OPTNAME_RET(_s,_sock,_level,_optname) do { \
415       if ((_sock)->conn != NULL && (NETCONNTYPE_GROUP((_sock)->conn->type) == NETCONN_PKT_RAW) && \
416           (_level) == SOL_PACKET && ((_optname) != SO_RCVTIMEO && (_optname) != SO_RCVBUF && (_optname) != SO_TYPE)) { \
417         LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%p, SOL_PACKET, UNIMPL: optname=0x%x, ..)\n",  \
418                     (_s), (_optname)));  \
419         done_socket(_sock); \
420         return  ENOPROTOOPT;  \
421       } \
422     } while (0)
423 
424 #define VALIDATE_LEVEL_PF_PACKET(_sock,_level) \
425     if ((_sock)->conn != NULL && ((NETCONNTYPE_GROUP(NETCONN_TYPE(_sock->conn)) == NETCONN_PKT_RAW \
426       && SOL_SOCKET != (_level) && SOL_PACKET != (_level)) ||  \
427       (NETCONNTYPE_GROUP((_sock)->conn->type) != NETCONN_PKT_RAW && SOL_PACKET == (_level))))
428 #endif
429 
430 /* Forward declaration of some functions */
431 #if LWIP_SOCKET_SELECT || LWIP_SOCKET_POLL
432 static void event_callback(struct netconn *conn, enum netconn_evt evt, u16_t len);
433 #define DEFAULT_SOCKET_EVENTCB event_callback
434 static void select_check_waiters(int s, int has_recvevent, int has_sendevent, int has_errevent);
435 #else
436 #define DEFAULT_SOCKET_EVENTCB NULL
437 #endif
438 #if !LWIP_TCPIP_CORE_LOCKING
439 static void lwip_getsockopt_callback(void *arg);
440 static void lwip_setsockopt_callback(void *arg);
441 #endif
442 static int lwip_getsockopt_impl(int s, int level, int optname, void *optval, socklen_t *optlen);
443 static int lwip_setsockopt_impl(int s, int level, int optname, const void *optval, socklen_t optlen);
444 
445 #if LWIP_IOCTL_ROUTE
446 static u8_t lwip_ioctl_internal_SIOCADDRT(const struct rtentry *rmten);
447 #endif /* LWIP_IOCTL_ROUTE */
448 
449 #if LWIP_IOCTL_IF
450 static u8_t lwip_ioctl_internal_SIOCGIFCONF(struct ifreq *ifr);
451 static u8_t lwip_ioctl_internal_SIOCGIFADDR(struct ifreq *ifr);
452 static u8_t lwip_ioctl_internal_SIOCSIFADDR(const struct ifreq *ifr);
453 static u8_t lwip_ioctl_internal_SIOCDIFADDR(const struct ifreq *ifr);
454 #if LWIP_IPV6
455 static u8_t lwip_ioctl_internal_SIOCSIFADDR_6(struct ifreq *ifr);
456 static u8_t lwip_ioctl_internal_SIOCDIFADDR_6(struct ifreq *ifr);
457 #endif
458 static u8_t lwip_ioctl_internal_SIOCGIFBRDADDR(struct ifreq *ifr);
459 static u8_t lwip_ioctl_internal_SIOCGIFNETMASK(struct ifreq *ifr);
460 static u8_t lwip_ioctl_internal_SIOCSIFNETMASK(const struct ifreq *ifr);
461 static u8_t lwip_ioctl_internal_SIOCGIFHWADDR(struct ifreq *ifr);
462 static u8_t lwip_ioctl_internal_SIOCSIFHWADDR(const struct ifreq *ifr);
463 static u8_t lwip_ioctl_internal_SIOCGIFFLAGS(struct ifreq *ifr);
464 static u8_t lwip_ioctl_internal_SIOCSIFFLAGS(const struct ifreq *ifr);
465 static u8_t lwip_ioctl_internal_SIOCGIFNAME(struct ifreq *ifr);
466 static u8_t lwip_ioctl_internal_SIOCSIFNAME(struct ifreq *ifr);
467 static u8_t lwip_validate_ifname(const char *name, u8_t *let_pos);
468 static u8_t lwip_ioctl_internal_SIOCGIFINDEX(struct ifreq *ifr);
469 static u8_t lwip_ioctl_internal_SIOCSIFMTU(const struct ifreq *ifr);
470 static u8_t lwip_ioctl_internal_SIOCGIFMTU(struct ifreq *ifr);
471 #endif /* LWIP_IOCTL_IF */
472 
473 #if LWIP_NETIF_ETHTOOL
474 static s32_t lwip_ioctl_internal_SIOCETHTOOL(struct ifreq *ifr);
475 #endif
476 
477 #if LWIP_IPV6
478 #if LWIP_IPV6_DUP_DETECT_ATTEMPTS
479 static u8_t lwip_ioctl_internal_SIOCSIPV6DAD(const struct ifreq *ifr);
480 static u8_t lwip_ioctl_internal_SIOCGIPV6DAD(struct ifreq *ifr);
481 #endif
482 #if LWIP_IOCTL_IPV6DPCTD
483 static u8_t lwip_ioctl_internal_SIOCSIPV6DPCTD(const struct ifreq *ifr);
484 static u8_t lwip_ioctl_internal_SIOCGIPV6DPCTD(struct ifreq *ifr);
485 #endif
486 #endif
487 
488 static int free_socket_locked(struct lwip_sock *sock, int is_tcp, struct netconn **conn,
489                               union lwip_sock_lastdata *lastdata);
490 static void free_socket_free_elements(int is_tcp, struct netconn *conn, union lwip_sock_lastdata *lastdata);
491 
492 #if LWIP_ENABLE_NET_CAPABILITY && LWIP_ENABLE_CAP_NET_BROADCAST
ip_addr_isbroadcast_by_sock(const ip_addr_t * ipaddr,const struct lwip_sock * sock)493 static u8_t ip_addr_isbroadcast_by_sock(const ip_addr_t *ipaddr, const struct lwip_sock *sock)
494 {
495   struct netif *netif = NULL;
496   u8_t res;
497 
498 #if LWIP_TCPIP_CORE_LOCKING
499   LOCK_TCPIP_CORE();
500 #else
501   SYS_ARCH_DECL_PROTECT(lev);
502   SYS_ARCH_PROTECT(lev);
503 #endif
504 
505   LWIP_ASSERT("socket invalid!", sock != NULL && sock->conn != NULL);
506 
507   if (sock->conn->pcb.ip != NULL) {
508     netif = netif_get_by_index(sock->conn->pcb.ip->netif_idx);
509     if (netif != NULL) {
510       res = ip_addr_isbroadcast(ipaddr, netif);
511       goto done;
512     }
513   }
514   res = netif_ipaddr_isbrdcast(ipaddr);
515 
516 done:
517 #if LWIP_TCPIP_CORE_LOCKING
518   UNLOCK_TCPIP_CORE();
519 #else
520   SYS_ARCH_UNPROTECT(lev);
521 #endif
522   return res;
523 }
524 #endif
525 
526 static int
lwip_sockopt_check_optlen_conn_pcb(const struct lwip_sock * sock,socklen_t optlen,socklen_t len)527 lwip_sockopt_check_optlen_conn_pcb(const struct lwip_sock *sock, socklen_t optlen, socklen_t len)
528 {
529   if ((optlen) < len) {
530     return EINVAL;
531   }
532 
533   if (((sock)->conn == NULL) || ((sock)->conn->pcb.tcp == NULL)) {
534     return EINVAL;
535   }
536 
537   return 0;
538 }
539 
540 static int
lwip_sockopt_check_optlen_conn_pcb_type(const struct lwip_sock * sock,socklen_t optlen,socklen_t len,enum netconn_type type,int is_v6)541 lwip_sockopt_check_optlen_conn_pcb_type(const struct lwip_sock *sock, socklen_t optlen, socklen_t len,
542                                         enum netconn_type type, int is_v6)
543 {
544   int ret = lwip_sockopt_check_optlen_conn_pcb(sock, optlen, len);
545   if (ret != 0) {
546     return ret;
547   }
548 #if LWIP_IPV6
549   if (is_v6 && !(NETCONNTYPE_ISIPV6(sock->conn->type))) {
550     return ENOPROTOOPT;
551   }
552 #endif
553 
554   if (type != NETCONNTYPE_GROUP(NETCONN_TYPE((sock)->conn))) {
555     return ENOPROTOOPT;
556   }
557   return 0;
558 }
559 
560 #if LWIP_IPV4 && LWIP_IPV6
561 static void
sockaddr_to_ipaddr_port(const struct sockaddr * sockaddr,ip_addr_t * ipaddr,u16_t * port)562 sockaddr_to_ipaddr_port(const struct sockaddr *sockaddr, ip_addr_t *ipaddr, u16_t *port)
563 {
564   if ((sockaddr->sa_family) == AF_INET6) {
565     SOCKADDR6_TO_IP6ADDR_PORT((const struct sockaddr_in6 *)(const void *)(sockaddr), ipaddr, *port);
566     ipaddr->type = IPADDR_TYPE_V6;
567   } else {
568     SOCKADDR4_TO_IP4ADDR_PORT((const struct sockaddr_in *)(const void *)(sockaddr), ipaddr, *port);
569     ipaddr->type = IPADDR_TYPE_V4;
570   }
571 }
572 #endif /* LWIP_IPV4 && LWIP_IPV6 */
573 
574 /** LWIP_NETCONN_SEM_PER_THREAD==1: initialize thread-local semaphore */
575 void
lwip_socket_thread_init(void)576 lwip_socket_thread_init(void)
577 {
578   netconn_thread_init();
579 }
580 
581 /** LWIP_NETCONN_SEM_PER_THREAD==1: destroy thread-local semaphore */
582 void
lwip_socket_thread_cleanup(void)583 lwip_socket_thread_cleanup(void)
584 {
585   netconn_thread_cleanup();
586 }
587 
sock_init(void)588 int sock_init(void)
589 {
590   int i;
591 
592 #if LWIP_ALLOW_SOCKET_CONFIG
593   /* this space will not be free, use it as a static pool. for memory pool configuration purpose */
594   if (LWIP_CONFIG_NUM_SOCKETS > LWIP_NUM_SOCKETS_MAX) {
595     return ERR_MEM;
596   }
597 
598   sockets = (struct lwip_sock *)mem_malloc(LWIP_CONFIG_NUM_SOCKETS * sizeof(struct lwip_sock));
599   if (sockets == NULL) {
600     return ERR_MEM;
601   }
602   (void)memset(sockets, 0, LWIP_CONFIG_NUM_SOCKETS * sizeof(struct lwip_sock));
603 #endif /* LWIP_ALLOW_SOCKET_CONFIG */
604 
605   /* allocate a new socket identifier */
606   for (i = 0; i < (int)LWIP_CONFIG_NUM_SOCKETS; ++i) {
607     if (sys_mutex_new(&sockets[i].mutex) != ERR_OK) {
608       goto FAILURE;
609     }
610   }
611 
612   return ERR_OK;
613 
614 FAILURE:
615   /* Free all resources if failure happens */
616   for (--i; i >= 0; i--) {
617     sys_mutex_free(&sockets[i].mutex);
618   }
619 
620 #if LWIP_ALLOW_SOCKET_CONFIG
621   mem_free(sockets);
622   sockets = NULL;
623 #endif
624   return ERR_MEM;
625 }
626 
627 /*
628  * lock lwip_sock parameters from race condition from different thread in parallel
629  *
630  * @param *sock socket whos paramerters need to be protected.
631  * @return void
632  */
633 static inline void
lwip_sock_lock(struct lwip_sock * sock)634 lwip_sock_lock(struct lwip_sock *sock)
635 {
636 #if LWIP_COMPAT_MUTEX
637   u32_t ret;
638   ret = sys_mutex_lock(&sock->mutex);
639   LWIP_ASSERT("sys_mutex_lock failed", (ret == 0));
640   LWIP_UNUSED_ARG(ret);
641 #else
642   sys_mutex_lock(&sock->mutex);
643 #endif
644 }
645 
646 /*
647  * unlock lwip_sock parameters for using through different thread in parallel
648  *
649  * @param *sock socket.
650  * @return void
651  */
652 static inline void
lwip_sock_unlock(struct lwip_sock * sock)653 lwip_sock_unlock(struct lwip_sock *sock)
654 {
655   sys_mutex_unlock(&sock->mutex);
656 }
657 
658 #if LWIP_NETCONN_FULLDUPLEX
659 /* Thread-safe increment of sock->fd_used, with overflow check */
660 static int
sock_inc_used(struct lwip_sock * sock)661 sock_inc_used(struct lwip_sock *sock)
662 {
663   int ret;
664   SYS_ARCH_DECL_PROTECT(lev);
665 
666   LWIP_ASSERT("sock != NULL", sock != NULL);
667 
668   SYS_ARCH_PROTECT(lev);
669   if (sock->fd_free_pending || sock->closing || sock->conn == NULL) {
670     /* prevent new usage of this socket if free is pending or finished */
671     ret = 0;
672   } else {
673     ++sock->fd_used;
674     ret = 1;
675     LWIP_ASSERT("sock->fd_used != 0", sock->fd_used != 0);
676   }
677   SYS_ARCH_UNPROTECT(lev);
678   return ret;
679 }
680 
681 /* Like sock_inc_used(), but called under SYS_ARCH_PROTECT lock. */
682 static int
sock_inc_used_locked(struct lwip_sock * sock)683 sock_inc_used_locked(struct lwip_sock *sock)
684 {
685   LWIP_ASSERT("sock != NULL", sock != NULL);
686 
687   if (sock->fd_free_pending || sock->closing || sock->conn == NULL) {
688     LWIP_ASSERT("sock->fd_used != 0", sock->fd_used != 0);
689     return 0;
690   }
691 
692   ++sock->fd_used;
693   LWIP_ASSERT("sock->fd_used != 0", sock->fd_used != 0);
694   return 1;
695 }
696 
697 /* In full-duplex mode,sock->fd_used != 0 prevents a socket descriptor from being
698  * released (and possibly reused) when used from more than one thread
699  * (e.g. read-while-write or close-while-write, etc)
700  * This function is called at the end of functions using (try)get_socket*().
701  */
702 static void
done_socket(struct lwip_sock * sock)703 done_socket(struct lwip_sock *sock)
704 {
705   int freed = 0;
706   int is_tcp = 0;
707   struct netconn *conn = NULL;
708   union lwip_sock_lastdata lastdata;
709   SYS_ARCH_DECL_PROTECT(lev);
710   LWIP_ASSERT("sock != NULL", sock != NULL);
711 
712   SYS_ARCH_PROTECT(lev);
713   LWIP_ASSERT("sock->fd_used > 0", sock->fd_used > 0);
714   if (--sock->fd_used == 0) {
715     if (sock->fd_free_pending) {
716       /* free the socket */
717       sock->fd_used = 1;
718       is_tcp = sock->fd_free_pending & LWIP_SOCK_FD_FREE_TCP;
719       freed = free_socket_locked(sock, is_tcp, &conn, &lastdata);
720     }
721   }
722   SYS_ARCH_UNPROTECT(lev);
723 
724   if (freed) {
725     free_socket_free_elements(is_tcp, conn, &lastdata);
726   }
727 }
728 
729 #else /* LWIP_NETCONN_FULLDUPLEX */
730 #define sock_inc_used(sock)         1
731 #define sock_inc_used_locked(sock)  1
732 #define done_socket(sock)
733 #endif /* LWIP_NETCONN_FULLDUPLEX */
734 
735 /* Translate a socket 'int' into a pointer (only fails if the index is invalid) */
736 static struct lwip_sock *
tryget_socket_unconn_nouse(int fd)737 tryget_socket_unconn_nouse(int fd)
738 {
739   int s = fd - LWIP_SOCKET_OFFSET;
740   if ((s < 0) || (s >= (int)LWIP_CONFIG_NUM_SOCKETS)) {
741     LWIP_DEBUGF(SOCKETS_DEBUG, ("tryget_socket_unconn(%d): invalid\n", fd));
742     return NULL;
743   }
744   return &sockets[s];
745 }
746 
747 struct lwip_sock *
lwip_socket_dbg_get_socket(int fd)748 lwip_socket_dbg_get_socket(int fd)
749 {
750   return tryget_socket_unconn_nouse(fd);
751 }
752 
753 /** Free a socket. The socket's netconn must have been
754  * delete before!
755  *
756  * @param sock the socket to free
757  * @param is_tcp != 0 for TCP sockets, used to free lastdata
758  */
759 static void
free_socket(struct lwip_sock * sock,int is_tcp)760 free_socket(struct lwip_sock *sock, int is_tcp)
761 {
762   int freed;
763   struct netconn *conn;
764   union lwip_sock_lastdata lastdata;
765   SYS_ARCH_DECL_PROTECT(lev);
766 
767   /* Protect socket array */
768   SYS_ARCH_PROTECT(lev);
769 
770   freed = free_socket_locked(sock, is_tcp, &conn, &lastdata);
771   SYS_ARCH_UNPROTECT(lev);
772   /* don't use 'sock' after this line, as another task might have allocated it */
773 
774   if (freed) {
775     free_socket_free_elements(is_tcp, conn, &lastdata);
776   }
777 }
778 
779 /* Translate a socket 'int' into a pointer (only fails if the index is invalid) */
780 static struct lwip_sock *
tryget_socket_unconn(int fd)781 tryget_socket_unconn(int fd)
782 {
783   struct lwip_sock *ret = tryget_socket_unconn_nouse(fd);
784   if (ret != NULL) {
785     if (!sock_inc_used(ret)) {
786       return NULL;
787     }
788   }
789   return ret;
790 }
791 
792 /* Like tryget_socket_unconn(), but called under SYS_ARCH_PROTECT lock. */
793 static struct lwip_sock *
tryget_socket_unconn_locked(int fd)794 tryget_socket_unconn_locked(int fd)
795 {
796   struct lwip_sock *ret = tryget_socket_unconn_nouse(fd);
797   if (ret != NULL) {
798     if (!sock_inc_used_locked(ret)) {
799       return NULL;
800     }
801   }
802   return ret;
803 }
804 
805 /**
806  * Same as get_socket but doesn't set errno
807  *
808  * @param fd externally used socket index
809  * @return struct lwip_sock for the socket or NULL if not found
810  */
811 static struct lwip_sock *
tryget_socket(int fd)812 tryget_socket(int fd)
813 {
814   struct lwip_sock *sock = tryget_socket_unconn(fd);
815   if (sock != NULL) {
816     if (sock->conn) {
817       return sock;
818     }
819     done_socket(sock);
820   }
821   return NULL;
822 }
823 
824 /**
825  * Map a externally used socket index to the internal socket representation.
826  *
827  * @param fd externally used socket index
828  * @return struct lwip_sock for the socket or NULL if not found
829  */
830 static struct lwip_sock *
get_socket(int fd)831 get_socket(int fd)
832 {
833   struct lwip_sock *sock = tryget_socket(fd);
834   if (!sock) {
835     if ((fd < LWIP_SOCKET_OFFSET) || (fd >= (int)(LWIP_SOCKET_OFFSET + LWIP_CONFIG_NUM_SOCKETS))) {
836       LWIP_DEBUGF(SOCKETS_DEBUG, ("get_socket(%d): invalid\n", fd));
837     }
838     set_errno(EBADF);
839     return NULL;
840   }
841   return sock;
842 }
843 
844 /* get numbers of unused sockets */
get_unused_socket_num(void)845 int get_unused_socket_num(void)
846 {
847   int unused = 0, i;
848   SYS_ARCH_DECL_PROTECT(lev);
849 
850   SYS_ARCH_PROTECT(lev);
851 
852   for (i = 0; i < (int)LWIP_CONFIG_NUM_SOCKETS; i++) {
853     if (!sockets[i].conn
854 #if LWIP_NETCONN_FULLDUPLEX
855       && !sockets[i].fd_used
856 #endif
857     ) {
858       unused++;
859     }
860   }
861 
862   SYS_ARCH_UNPROTECT(lev);
863 
864   return unused;
865 }
866 
867 /**
868  * Allocate a new socket for a given netconn.
869  *
870  * @param newconn the netconn for which to allocate a socket
871  * @param accepted 1 if socket has been created by accept(),
872  *                 0 if socket has been created by socket()
873  * @return the index of the new socket; -1 on error
874  */
875 static int
alloc_socket(struct netconn * newconn,int accepted)876 alloc_socket(struct netconn *newconn, int accepted)
877 {
878   int i;
879   SYS_ARCH_DECL_PROTECT(lev);
880   LWIP_UNUSED_ARG(accepted);
881 
882   /* allocate a new socket identifier */
883   for (i = 0; i < (int)LWIP_CONFIG_NUM_SOCKETS; ++i) {
884     /* Protect socket array */
885     SYS_ARCH_PROTECT(lev);
886     if (!sockets[i].conn) {
887 #if LWIP_NETCONN_FULLDUPLEX
888       if (sockets[i].fd_used) {
889         SYS_ARCH_UNPROTECT(lev);
890         continue;
891       }
892       sockets[i].fd_used    = 1;
893       sockets[i].fd_free_pending = 0;
894       sockets[i].closing = 0;
895 #endif
896       sockets[i].conn       = newconn;
897       /* The socket is not yet known to anyone, so no need to protect
898          after having marked it as used. */
899       SYS_ARCH_UNPROTECT(lev);
900       sockets[i].lastdata.pbuf = NULL;
901       (void)atomic_set(&sockets[i].err, 0);
902 #if LWIP_SOCKET_SELECT || LWIP_SOCKET_POLL
903       LWIP_ASSERT("sockets[i].select_waiting == 0", sockets[i].select_waiting == 0);
904       sockets[i].rcvevent   = 0;
905       /* TCP sendbuf is empty, but the socket is not yet writable until connected
906        * (unless it has been created by accept()). */
907       sockets[i].sendevent  = (NETCONNTYPE_GROUP(newconn->type) == NETCONN_TCP ? (accepted != 0) : 1);
908       sockets[i].errevent   = 0;
909 #if LWIP_EXT_POLL_SUPPORT
910 #if LWIP_LITEOS_COMPAT
911       __init_waitqueue_head(&sockets[i].wq);
912 #endif /* LWIP_LITEOS_COMPAT */
913 #endif
914 #endif /* LWIP_SOCKET_SELECT || LWIP_SOCKET_POLL */
915       return i + LWIP_SOCKET_OFFSET;
916     }
917     SYS_ARCH_UNPROTECT(lev);
918   }
919   return -1;
920 }
921 
922 /** Free a socket (under lock)
923  *
924  * @param sock the socket to free
925  * @param is_tcp != 0 for TCP sockets, used to free lastdata
926  * @param conn the socekt's netconn is stored here, must be freed externally
927  * @param lastdata lastdata is stored here, must be freed externally
928  */
929 static int
free_socket_locked(struct lwip_sock * sock,int is_tcp,struct netconn ** conn,union lwip_sock_lastdata * lastdata)930 free_socket_locked(struct lwip_sock *sock, int is_tcp, struct netconn **conn,
931                    union lwip_sock_lastdata *lastdata)
932 {
933 #if LWIP_NETCONN_FULLDUPLEX
934   LWIP_ASSERT("sock->fd_used > 0", sock->fd_used > 0);
935   sock->fd_used--;
936   if (sock->fd_used > 0) {
937     sock->fd_free_pending = LWIP_SOCK_FD_FREE_FREE | (is_tcp ? LWIP_SOCK_FD_FREE_TCP : 0);
938     return 0;
939   }
940 #else /* LWIP_NETCONN_FULLDUPLEX */
941   LWIP_UNUSED_ARG(is_tcp);
942 #endif /* LWIP_NETCONN_FULLDUPLEX */
943 
944   *lastdata = sock->lastdata;
945   sock->lastdata.pbuf = NULL;
946   (void)atomic_set(&sock->err, 0);
947   *conn = sock->conn;
948   sock->conn = NULL;
949   return 1;
950 }
951 
952 /** Free a socket's leftover members.
953  */
954 static void
free_socket_free_elements(int is_tcp,struct netconn * conn,union lwip_sock_lastdata * lastdata)955 free_socket_free_elements(int is_tcp, struct netconn *conn, union lwip_sock_lastdata *lastdata)
956 {
957   if (lastdata->pbuf != NULL) {
958     if (is_tcp) {
959       pbuf_free(lastdata->pbuf);
960     } else {
961       netbuf_delete(lastdata->netbuf);
962     }
963   }
964   if (conn != NULL) {
965     /* netconn_prepare_delete() has already been called, here we only free the conn */
966     netconn_delete(conn);
967   }
968 }
969 
970 /* Below this, the well-known socket functions are implemented.
971  * Use google.com or opengroup.org to get a good description :-)
972  *
973  * Exceptions are documented!
974  */
975 
976 int
lwip_accept(int s,struct sockaddr * addr,socklen_t * addrlen)977 lwip_accept(int s, struct sockaddr *addr, socklen_t *addrlen)
978 {
979   struct lwip_sock *sock, *nsock;
980   struct netconn *newconn;
981   ip_addr_t naddr;
982   u16_t port = 0;
983   int newsock;
984   err_t err;
985   int recvevent;
986   SYS_ARCH_DECL_PROTECT(lev);
987 
988   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d)...\n", s));
989   /* Correcting the errno to EINVAL to be consistent with Linux
990    If addr is valid and addrlen is null , stack should return EINVAL
991    If addr is NULL pointer and addrlen is null or valid - ignore the addrlen and function normally as
992    POSIX doesnot mandate addr to be non null pointer */
993   LWIP_ERROR("Invalid address space\n",
994              (((addr) && (addrlen != NULL)) || (addr == NULL)),
995              set_errno(EINVAL); return -1);
996 
997   LWIP_ERROR("Invalid address length\n", ((addrlen == NULL) || ((int)(*addrlen) >= 0)),
998              set_errno(EINVAL); return -1);
999 
1000   sock = get_socket(s);
1001   if (!sock) {
1002     return -1;
1003   }
1004 
1005   /* wait for a new connection */
1006   err = netconn_accept(sock->conn, &newconn);
1007   if (err != ERR_OK) {
1008     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d): netconn_acept failed, err=%d\n", s, err));
1009     if (NETCONNTYPE_GROUP(NETCONN_TYPE(sock->conn)) != NETCONN_TCP) {
1010       sock_set_errno(sock, EOPNOTSUPP);
1011     } else if (err == ERR_CLSD) {
1012       sock_set_errno(sock, EINVAL);
1013     } else {
1014       sock_set_errno(sock, err_to_errno(err));
1015     }
1016     done_socket(sock);
1017     return -1;
1018   }
1019   LWIP_ASSERT("newconn != NULL", newconn != NULL);
1020 
1021   newsock = alloc_socket(newconn, 1);
1022   if (newsock == -1) {
1023     netconn_delete(newconn);
1024     sock_set_errno(sock, ENFILE);
1025     done_socket(sock);
1026     return -1;
1027   }
1028   LWIP_ASSERT("invalid socket index", (newsock >= (int)(LWIP_SOCKET_OFFSET)) &&
1029   	          (newsock < (int)(LWIP_CONFIG_NUM_SOCKETS + LWIP_SOCKET_OFFSET)));
1030   nsock = &sockets[newsock - LWIP_SOCKET_OFFSET];
1031 
1032   /* See event_callback: If data comes in right away after an accept, even
1033    * though the server task might not have created a new socket yet.
1034    * In that case, newconn->socket is counted down (newconn->socket--),
1035    * so nsock->rcvevent is >= 1 here!
1036    */
1037   SYS_ARCH_PROTECT(lev);
1038   recvevent = (s16_t)(-1 - newconn->socket);
1039   newconn->socket = newsock;
1040   SYS_ARCH_UNPROTECT(lev);
1041 
1042   if (newconn->callback) {
1043     LOCK_TCPIP_CORE();
1044     while (recvevent > 0) {
1045       recvevent--;
1046       newconn->callback(newconn, NETCONN_EVT_RCVPLUS, 0);
1047     }
1048     UNLOCK_TCPIP_CORE();
1049   }
1050 
1051   /* Note that POSIX only requires us to check addr is non-NULL. addrlen must
1052    * not be NULL if addr is valid.
1053    */
1054   if ((addr != NULL) && (addrlen != NULL)) {
1055     union sockaddr_aligned tempaddr;
1056     /* get the IP address and port of the remote host */
1057     err = netconn_peer(newconn, &naddr, &port);
1058     if (err != ERR_OK) {
1059       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d): netconn_peer failed, err=%d\n", s, err));
1060       err = ERR_ABRT;
1061       free_socket(nsock, 1);
1062       sock_set_errno(sock, err_to_errno(err));
1063       done_socket(sock);
1064       return -1;
1065     }
1066 
1067     IPADDR_PORT_TO_SOCKADDR(&tempaddr, &naddr, port);
1068     if (IP_IS_V4_VAL(naddr) && (*addrlen > (int)sizeof(struct sockaddr_in))) {
1069       *addrlen = sizeof(struct sockaddr_in);
1070     } else if (IP_IS_V6_VAL(naddr) && (*addrlen > (int)sizeof(struct sockaddr_in6))) {
1071       *addrlen = sizeof(struct sockaddr_in6);
1072     }
1073     MEMCPY(addr, &tempaddr, *addrlen);
1074 
1075     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d) returning new sock=%d addr=", s, newsock));
1076     ip_addr_debug_print_val(SOCKETS_DEBUG, naddr);
1077     LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F"\n", port));
1078   } else {
1079     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d) returning new sock=%d", s, newsock));
1080   }
1081 
1082   sock_set_errno(sock, 0);
1083   done_socket(sock);
1084   done_socket(nsock);
1085   return newsock;
1086 }
1087 
1088 int
lwip_bind(int s,const struct sockaddr * name,socklen_t namelen)1089 lwip_bind(int s, const struct sockaddr *name, socklen_t namelen)
1090 {
1091   struct lwip_sock *sock;
1092   ip_addr_t local_addr;
1093   u16_t local_port;
1094   err_t err;
1095 
1096 #if PF_PKT_SUPPORT
1097   const struct sockaddr_ll *name_ll = NULL;
1098   u8_t local_ifindex = 0;
1099 #endif
1100   sock = get_socket(s);
1101   if (!sock) {
1102     return -1;
1103   }
1104 
1105   /* check size, family and alignment of 'name' */
1106 #if PF_PKT_SUPPORT
1107   if (NETCONNTYPE_GROUP(NETCONN_TYPE(sock->conn)) & NETCONN_PKT_RAW) {
1108     name_ll = (const struct sockaddr_ll *)(void*)name;
1109     LWIP_ERROR("lwip_bind: invalid address", ((name_ll != NULL)&&(namelen == sizeof(struct sockaddr_ll)) &&
1110                ((name_ll->sll_family) == PF_PACKET) && IS_SOCK_ADDR_ALIGNED(name) &&
1111                (name_ll->sll_ifindex <= LWIP_NETIF_IFINDEX_MAX)), sock_set_errno(sock, err_to_errno(ERR_VAL));
1112                done_socket(sock); return -1);
1113 
1114     ip_addr_set_any_val(IPADDR_TYPE_V4, local_addr);
1115     local_port = name_ll->sll_protocol;
1116     local_ifindex = (u8_t)name_ll->sll_ifindex;
1117 
1118     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d, ", s));
1119     LWIP_DEBUGF(SOCKETS_DEBUG, (" ifindex=%u proto=%"U16_F")\n", local_ifindex, local_port));
1120   } else
1121 #endif
1122   {
1123     LWIP_ERROR("lwip_bind: name or namelen invalid\n", ((name != NULL) && IS_SOCK_ADDR_LEN_VALID(namelen) &&
1124                IS_SOCK_ADDR_ALIGNED(name)), sock_set_errno(sock, err_to_errno(ERR_VAL));
1125                done_socket(sock); return -1);
1126     LWIP_ERROR("lwip_bind: sockaddr type is invalid\n",
1127                (IS_SOCK_ADDR_TYPE_VALID(name)), sock_set_errno(sock, err_to_errno(ERR_AFNOSUPPORT));
1128                done_socket(sock); return -1);
1129 #if LWIP_IPV4 && LWIP_IPV6
1130     LWIP_ERROR("lwip_bind: sockaddr type not compat with length\n", (IS_SOCK_ADDR_TYPE_LEN_COMPAT(name, namelen)),
1131                sock_set_errno(sock, err_to_errno(ERR_VAL));
1132                done_socket(sock); return -1);
1133 #endif
1134 
1135     if (!SOCK_ADDR_TYPE_MATCH(name, sock)) {
1136       /* sockaddr does not match socket type (IPv4/IPv6) */
1137       sock_set_errno(sock, err_to_errno(ERR_VAL));
1138       done_socket(sock);
1139       return -1;
1140     }
1141 
1142     LWIP_UNUSED_ARG(namelen);
1143 
1144     SOCKADDR_TO_IPADDR_PORT(name, &local_addr, local_port);
1145     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d, addr=", s));
1146     ip_addr_debug_print_val(SOCKETS_DEBUG, local_addr);
1147     LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F")\n", local_port));
1148   }
1149 
1150 #if LWIP_ENABLE_NET_CAPABILITY
1151   if (local_port != 0 && local_port < BIND_SERVICE_CAP_MIN_PORT) {
1152     LWIP_ERROR("permission deny: NET_BIND_SERVICE\n", IsCapPermit(CAP_NET_BIND_SERVICE),
1153                sock_set_errno(sock, EPERM); done_socket(sock); return -1);
1154   }
1155 #if LWIP_ENABLE_CAP_NET_BROADCAST
1156   if (ip_addr_ismulticast(&local_addr) || ip_addr_isbroadcast_by_sock(&local_addr, sock)) {
1157     LWIP_ERROR("lwip_bind permission deny: NET_BROADCAST\n", IsCapPermit(CAP_NET_BROADCAST),
1158                sock_set_errno(sock, EPERM); done_socket(sock); return -1);
1159   }
1160 #endif /* LWIP_ENABLE_CAP_NET_BROADCAST */
1161 #endif /* LWIP_ENABLE_NET_CAPABILITY */
1162 
1163 #if LWIP_IPV4 && LWIP_IPV6
1164   /* Dual-stack: Unmap IPv4 mapped IPv6 addresses */
1165   if (IP_IS_V6_VAL(local_addr) && ip6_addr_isipv4mappedipv6(ip_2_ip6(&local_addr))) {
1166     unmap_ipv4_mapped_ipv6(ip_2_ip4(&local_addr), ip_2_ip6(&local_addr));
1167     IP_SET_TYPE_VAL(local_addr, IPADDR_TYPE_V4);
1168   }
1169 #endif /* LWIP_IPV4 && LWIP_IPV6 */
1170 
1171 #if PF_PKT_SUPPORT
1172   err = netconn_bind(sock->conn, &local_addr, local_port, local_ifindex);
1173 #else
1174   err = netconn_bind(sock->conn, &local_addr, local_port);
1175 #endif
1176 
1177   if (err != ERR_OK) {
1178     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d) failed, err=%d\n", s, err));
1179     sock_set_errno(sock, err_to_errno(err));
1180     done_socket(sock);
1181     return -1;
1182   }
1183 
1184   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d) succeeded\n", s));
1185   sock_set_errno(sock, 0);
1186   done_socket(sock);
1187   return 0;
1188 }
1189 
1190 int
lwip_close(int s)1191 lwip_close(int s)
1192 {
1193   struct lwip_sock *sock;
1194   int is_tcp = 0;
1195   err_t err;
1196   SYS_ARCH_DECL_PROTECT(lev);
1197 
1198   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_close(%d)\n", s));
1199 
1200   sock = get_socket(s);
1201   if (!sock) {
1202     return -1;
1203   }
1204 
1205   /* Close operation already in progress, can not process multiple close in parallel */
1206   SYS_ARCH_PROTECT(lev);
1207 #if LWIP_NETCONN_FULLDUPLEX
1208   if (sock->closing == 1) {
1209     SYS_ARCH_UNPROTECT(lev);
1210     done_socket(sock);
1211     set_errno(EBADF);
1212     return -1;
1213   }
1214 #endif
1215   SYS_ARCH_UNPROTECT(lev);
1216 
1217   if (sock->conn != NULL) {
1218     is_tcp = NETCONNTYPE_GROUP(NETCONN_TYPE(sock->conn)) == NETCONN_TCP;
1219   } else {
1220     LWIP_ASSERT("sock->lastdata == NULL", sock->lastdata.pbuf == NULL);
1221   }
1222 
1223 #if LWIP_IGMP
1224   /* drop all possibly joined IGMP memberships */
1225   lwip_socket_drop_registered_memberships(s);
1226 #endif /* LWIP_IGMP */
1227 #if LWIP_IPV6 && LWIP_IPV6_MLD
1228   /* drop all possibly joined MLD6 memberships */
1229   lwip_socket_drop_registered_mld6_memberships(s);
1230 #endif /* LWIP_IPV6 && LWIP_IPV6_MLD */
1231 
1232 #if LWIP_NETCONN_FULLDUPLEX
1233   sock->closing = 1;
1234 #endif
1235   err = netconn_prepare_delete(sock->conn);
1236   if (err != ERR_OK) {
1237     sock_set_errno(sock, err_to_errno(err));
1238     done_socket(sock);
1239     return -1;
1240   }
1241 
1242   free_socket(sock, is_tcp);
1243   set_errno(0);
1244   return 0;
1245 }
1246 
1247 int
lwip_connect(int s,const struct sockaddr * name,socklen_t namelen)1248 lwip_connect(int s, const struct sockaddr *name, socklen_t namelen)
1249 {
1250   struct lwip_sock *sock;
1251   err_t err;
1252 
1253   LWIP_ERROR("lwip_connect: invalid address", (name != NULL),
1254              set_errno(EINVAL);  return -1);
1255 
1256   sock = get_socket(s);
1257   if (!sock) {
1258     return -1;
1259   }
1260 
1261 #if PF_PKT_SUPPORT
1262   if (NETCONN_PKT_RAW & NETCONNTYPE_GROUP(NETCONN_TYPE(sock->conn))) {
1263     sock_set_errno(sock, EOPNOTSUPP);
1264     done_socket(sock);
1265     return -1;
1266   }
1267 #endif
1268 
1269   if (namelen < sizeof(struct sockaddr) || !SOCK_ADDR_TYPE_MATCH_OR_UNSPEC(name, sock)) {
1270     /* sockaddr does not match socket type (IPv4/IPv6) */
1271     sock_set_errno(sock, err_to_errno(ERR_VAL));
1272     done_socket(sock);
1273     return -1;
1274   }
1275 
1276   LWIP_UNUSED_ARG(namelen);
1277   if (name->sa_family == AF_UNSPEC) {
1278     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d, AF_UNSPEC)\n", s));
1279     err = netconn_disconnect(sock->conn);
1280   } else {
1281     ip_addr_t remote_addr;
1282     u16_t remote_port;
1283 
1284     /* check size, family and alignment of 'name' */
1285     LWIP_ERROR("lwip_connect: invalid address", IS_SOCK_ADDR_LEN_VALID(namelen) &&
1286                IS_SOCK_ADDR_TYPE_VALID_OR_UNSPEC(name) && IS_SOCK_ADDR_ALIGNED(name),
1287                sock_set_errno(sock, err_to_errno(ERR_VAL));
1288                done_socket(sock); return -1);
1289 
1290     LWIP_ERROR("lwip_connect: invalid address family", IS_SOCK_ADDR_TYPE_VALID_OR_UNSPEC(name),
1291                sock_set_errno(sock, err_to_errno(EAFNOSUPPORT));
1292                done_socket(sock); return -1);
1293 
1294     SOCKADDR_TO_IPADDR_PORT(name, &remote_addr, remote_port);
1295     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d, addr=", s));
1296     ip_addr_debug_print_val(SOCKETS_DEBUG, remote_addr);
1297     LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F")\n", remote_port));
1298 
1299 #if LWIP_IPV4 && LWIP_IPV6
1300     /* Dual-stack: Unmap IPv4 mapped IPv6 addresses */
1301     if (IP_IS_V6_VAL(remote_addr) && ip6_addr_isipv4mappedipv6(ip_2_ip6(&remote_addr))) {
1302       unmap_ipv4_mapped_ipv6(ip_2_ip4(&remote_addr), ip_2_ip6(&remote_addr));
1303       IP_SET_TYPE_VAL(remote_addr, IPADDR_TYPE_V4);
1304     }
1305 #endif /* LWIP_IPV4 && LWIP_IPV6 */
1306 
1307     err = netconn_connect(sock->conn, &remote_addr, remote_port);
1308   }
1309 
1310   if (err != ERR_OK) {
1311     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d) failed, err=%d\n", s, err));
1312     if (err == ERR_RST) {
1313       sock_set_errno(sock, ECONNREFUSED);
1314     } else {
1315       err = (err_t)((err == ERR_CLSD) ? ERR_ABRT : err);
1316       sock_set_errno(sock, err_to_errno(err));
1317     }
1318     done_socket(sock);
1319     return -1;
1320   }
1321 
1322   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d) succeeded\n", s));
1323   sock_set_errno(sock, 0);
1324   done_socket(sock);
1325   return 0;
1326 }
1327 
1328 /**
1329  * Set a socket into listen mode.
1330  * The socket may not have been used for another connection previously.
1331  *
1332  * @param s the socket to set to listening mode
1333  * @param backlog (ATTENTION: needs TCP_LISTEN_BACKLOG=1)
1334  * @return 0 on success, non-zero on failure
1335  */
1336 int
lwip_listen(int s,int backlog)1337 lwip_listen(int s, int backlog)
1338 {
1339   struct lwip_sock *sock;
1340   err_t err;
1341 
1342   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_listen(%d, backlog=%d)\n", s, backlog));
1343 
1344   sock = get_socket(s);
1345   if (!sock) {
1346     return -1;
1347   }
1348 
1349   /* limit the "backlog" parameter to fit in an u8_t */
1350   backlog = LWIP_MIN(LWIP_MAX(backlog, 0), TCP_DEFAULT_LISTEN_BACKLOG);
1351 
1352   err = netconn_listen_with_backlog(sock->conn, (u8_t)backlog);
1353 
1354   if (err != ERR_OK) {
1355     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_listen(%d) failed, err=%d\n", s, err));
1356     if (NETCONNTYPE_GROUP(NETCONN_TYPE(sock->conn)) != NETCONN_TCP) {
1357       sock_set_errno(sock, EOPNOTSUPP);
1358     } else {
1359       sock_set_errno(sock, err_to_errno(err));
1360     }
1361     done_socket(sock);
1362     return -1;
1363   }
1364 
1365   sock_set_errno(sock, 0);
1366   done_socket(sock);
1367   return 0;
1368 }
1369 
1370 #if LWIP_TCP
1371 /* Helper function to loop over receiving pbufs from netconn
1372  * until "len" bytes are received or we're otherwise done.
1373  * Keeps sock->lastdata for peeking or partly copying.
1374  */
1375 static ssize_t
lwip_recv_tcp(struct lwip_sock * sock,void * mem,size_t len,int flags)1376 lwip_recv_tcp(struct lwip_sock *sock, void *mem, size_t len, int flags)
1377 {
1378   u8_t apiflags = NETCONN_NOAUTORCVD;
1379   ssize_t recvd = 0;
1380   ssize_t recv_left = (len <= SSIZE_MAX) ? (ssize_t)len : SSIZE_MAX;
1381 
1382   LWIP_ASSERT("no socket given", sock != NULL);
1383   LWIP_ASSERT("this should be checked internally", NETCONNTYPE_GROUP(NETCONN_TYPE(sock->conn)) == NETCONN_TCP);
1384 
1385   if (flags & MSG_DONTWAIT) {
1386     apiflags |= NETCONN_DONTBLOCK;
1387   }
1388 
1389   /* If this is non-blocking call, then check first */
1390   if (atomic_read(&sock->conn->tcp_connected) != 1) {
1391     sock_set_errno(sock, ENOTCONN);
1392     return -1;
1393   }
1394 
1395   do {
1396     struct pbuf *p;
1397     err_t err;
1398     u16_t copylen;
1399 
1400     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recv_tcp: top while sock->lastdata=%p\n", (void *)sock->lastdata.pbuf));
1401     /* Check if there is data left from the last recv operation. */
1402     if (sock->lastdata.pbuf) {
1403       p = sock->lastdata.pbuf;
1404     } else {
1405       /* No data was left from the previous operation, so we try to get
1406          some from the network. */
1407       err = netconn_recv_tcp_pbuf_flags(sock->conn, &p, apiflags);
1408       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recv_tcp: netconn_recv err=%d, pbuf=%p\n",
1409                                   err, (void *)p));
1410 
1411       if (err != ERR_OK) {
1412         if (recvd > 0) {
1413           /* already received data, return that (this trusts in getting the same error from
1414              netconn layer again next time netconn_recv is called) */
1415           goto lwip_recv_tcp_done;
1416         }
1417         /* We should really do some error checking here. */
1418         LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recv_tcp: p == NULL, error is \"%s\"!\n",
1419                                     lwip_strerr(err)));
1420         sock_set_errno(sock, err_to_errno(err));
1421         if (err == ERR_CLSD) {
1422           return 0;
1423         } else {
1424           return -1;
1425         }
1426       }
1427       LWIP_ASSERT("p != NULL", p != NULL);
1428       sock->lastdata.pbuf = p;
1429     }
1430 
1431     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recv_tcp: buflen=%"U16_F" recv_left=%d off=%d\n",
1432                                 p->tot_len, (int)recv_left, (int)recvd));
1433 
1434     if (recv_left > p->tot_len) {
1435       copylen = p->tot_len;
1436     } else {
1437       copylen = (u16_t)recv_left;
1438     }
1439     if (recvd + copylen < recvd) {
1440       /* overflow */
1441       copylen = (u16_t)(SSIZE_MAX - recvd);
1442     }
1443 
1444     /* copy the contents of the received buffer into
1445     the supplied memory pointer mem */
1446     pbuf_copy_partial(p, (u8_t *)mem + recvd, copylen, 0);
1447 
1448     recvd += copylen;
1449 
1450     /* TCP combines multiple pbufs for one recv */
1451     LWIP_ASSERT("invalid copylen, len would underflow", recv_left >= copylen);
1452     recv_left -= copylen;
1453 
1454     /* Unless we peek the incoming message... */
1455     if ((flags & MSG_PEEK) == 0) {
1456       /* ... check if there is data left in the pbuf */
1457       LWIP_ASSERT("invalid copylen", p->tot_len >= copylen);
1458       if (p->tot_len - copylen > 0) {
1459         /* If so, it should be saved in the sock structure for the next recv call.
1460            We store the pbuf but hide/free the consumed data: */
1461         sock->lastdata.pbuf = pbuf_free_header(p, copylen);
1462         LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recv_tcp: lastdata now pbuf=%p\n", (void *)sock->lastdata.pbuf));
1463       } else {
1464         sock->lastdata.pbuf = NULL;
1465         LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recv_tcp: deleting pbuf=%p\n", (void *)p));
1466         pbuf_free(p);
1467       }
1468     }
1469     /* once we have some data to return, only add more if we don't need to wait */
1470     apiflags |= NETCONN_DONTBLOCK | NETCONN_NOFIN;
1471     /* @todo: do we need to support peeking more than one pbuf? */
1472   } while ((recv_left > 0) && !(flags & MSG_PEEK));
1473 lwip_recv_tcp_done:
1474   if ((recvd > 0) && !(flags & MSG_PEEK)) {
1475     /* ensure window update after copying all data */
1476     netconn_tcp_recvd(sock->conn, (size_t)recvd);
1477   }
1478   /* store data left count on this rcv operation */
1479   if (sock->lastdata.pbuf) {
1480     sock->conn->lrcv_left = (u32_t)(sock->lastdata.pbuf->tot_len);
1481   } else {
1482     sock->conn->lrcv_left = 0;
1483   }
1484   sock_set_errno(sock, 0);
1485   return recvd;
1486 }
1487 #endif
1488 
1489 /* Convert a netbuf's address data to struct sockaddr */
1490 static int
lwip_sock_make_addr(struct netconn * conn,ip_addr_t * fromaddr,u16_t port,struct sockaddr * from,socklen_t * fromlen)1491 lwip_sock_make_addr(struct netconn *conn, ip_addr_t *fromaddr, u16_t port,
1492                     struct sockaddr *from, socklen_t *fromlen)
1493 {
1494   int truncated = 0;
1495   union sockaddr_aligned saddr;
1496   socklen_t sa_len;
1497 
1498   LWIP_UNUSED_ARG(conn);
1499 
1500   LWIP_ASSERT("fromaddr != NULL", fromaddr != NULL);
1501   LWIP_ASSERT("from != NULL", from != NULL);
1502   LWIP_ASSERT("fromlen != NULL", fromlen != NULL);
1503 
1504 #if LWIP_IPV4 && LWIP_IPV6
1505   /* Dual-stack: Map IPv4 addresses to IPv4 mapped IPv6 */
1506   if (NETCONNTYPE_ISIPV6(NETCONN_TYPE(conn)) && IP_IS_V4(fromaddr)) {
1507     ip4_2_ipv4_mapped_ipv6(ip_2_ip6(fromaddr), ip_2_ip4(fromaddr));
1508     IP_SET_TYPE(fromaddr, IPADDR_TYPE_V6);
1509   }
1510 #endif /* LWIP_IPV4 && LWIP_IPV6 */
1511 
1512   IPADDR_PORT_TO_SOCKADDR(&saddr, fromaddr, port);
1513   if (IP_IS_V4_VAL(*fromaddr)) {
1514     sa_len = sizeof(struct sockaddr_in);
1515   } else {
1516     sa_len = sizeof(struct sockaddr_in6);
1517   }
1518   if (*fromlen < sa_len) {
1519     truncated = 1;
1520   } else if (*fromlen > sa_len) {
1521     *fromlen = sa_len;
1522   }
1523   MEMCPY(from, &saddr, *fromlen);
1524   return truncated;
1525 }
1526 
1527 #if LWIP_TCP
1528 /* Helper function to get a tcp socket's remote address info */
1529 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)1530 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)
1531 {
1532   if (sock == NULL) {
1533     return 0;
1534   }
1535   LWIP_UNUSED_ARG(dbg_fn);
1536   LWIP_UNUSED_ARG(dbg_s);
1537   LWIP_UNUSED_ARG(dbg_ret);
1538 
1539 #if !SOCKETS_DEBUG
1540   if (from && fromlen)
1541 #endif /* !SOCKETS_DEBUG */
1542   {
1543     LWIP_DEBUGF(SOCKETS_DEBUG, ("%s(%d):  addr=", dbg_fn, dbg_s));
1544     LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F" len=%d\n", sock->conn->remote_port, (int)dbg_ret));
1545     ip_addr_debug_print_val(SOCKETS_DEBUG, sock->conn->remote_ip);
1546     if (from && fromlen) {
1547       return lwip_sock_make_addr(sock->conn, &sock->conn->remote_ip, sock->conn->remote_port, from, fromlen);
1548     }
1549   }
1550   return 0;
1551 }
1552 #endif
1553 
1554 /* Helper function to receive a netbuf from a udp or raw netconn.
1555  * Keeps sock->lastdata for peeking.
1556  */
1557 static err_t
lwip_recvfrom_udp_raw(struct lwip_sock * sock,int flags,struct msghdr * msg,u16_t * datagram_len,int dbg_s)1558 lwip_recvfrom_udp_raw(struct lwip_sock *sock, int flags, struct msghdr *msg, u16_t *datagram_len, int dbg_s)
1559 {
1560   struct netbuf *buf;
1561   u8_t apiflags;
1562   err_t err;
1563   u16_t buflen, copylen, copied;
1564   int i;
1565 
1566   LWIP_UNUSED_ARG(dbg_s);
1567   LWIP_ERROR("lwip_recvfrom_udp_raw: invalid arguments", (msg->msg_iov != NULL) || (msg->msg_iovlen <= 0), return ERR_ARG;);
1568 
1569   if (flags & MSG_DONTWAIT) {
1570     apiflags = NETCONN_DONTBLOCK;
1571   } else {
1572     apiflags = 0;
1573   }
1574 
1575   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom_udp_raw[UDP/RAW]: top sock->lastdata=%p\n", (void *)sock->lastdata.netbuf));
1576   /* Check if there is data left from the last recv operation. */
1577   buf = sock->lastdata.netbuf;
1578   if (buf == NULL) {
1579     /* No data was left from the previous operation, so we try to get
1580         some from the network. */
1581     err = netconn_recv_udp_raw_netbuf_flags(sock->conn, &buf, apiflags);
1582     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom_udp_raw[UDP/RAW]: netconn_recv err=%d, netbuf=%p\n",
1583                                 err, (void *)buf));
1584 
1585     if (err != ERR_OK) {
1586       return err;
1587     }
1588     LWIP_ASSERT("buf != NULL", buf != NULL);
1589     sock->lastdata.netbuf = buf;
1590   }
1591   buflen = buf->p->tot_len;
1592   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom_udp_raw: buflen=%"U16_F"\n", buflen));
1593 
1594   copied = 0;
1595   /* copy the pbuf payload into the iovs */
1596   for (i = 0; (i < msg->msg_iovlen) && (copied < buflen); i++) {
1597     u16_t len_left = (u16_t)(buflen - copied);
1598     if (msg->msg_iov[i].iov_len > len_left) {
1599       copylen = len_left;
1600     } else {
1601       copylen = (u16_t)msg->msg_iov[i].iov_len;
1602     }
1603 
1604     /* copy the contents of the received buffer into
1605         the supplied memory buffer */
1606     pbuf_copy_partial(buf->p, (u8_t *)msg->msg_iov[i].iov_base, copylen, copied);
1607     copied = (u16_t)(copied + copylen);
1608   }
1609 
1610   /* Check to see from where the data was.*/
1611 #if !SOCKETS_DEBUG
1612   if (msg->msg_name && msg->msg_namelen)
1613 #endif /* !SOCKETS_DEBUG */
1614   {
1615     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom_udp_raw(%d):  addr=", dbg_s));
1616     ip_addr_debug_print_val(SOCKETS_DEBUG, *netbuf_fromaddr(buf));
1617     LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F" len=%d\n", netbuf_fromport(buf), copied));
1618     if (msg->msg_name && msg->msg_namelen) {
1619 #if PF_PKT_SUPPORT
1620       struct sockaddr_ll sll;
1621 
1622       if (NETCONNTYPE_GROUP(NETCONN_TYPE(sock->conn)) & NETCONN_PKT_RAW) {
1623         if (msg->msg_namelen > sizeof(sll)) {
1624           msg->msg_namelen = sizeof(sll);
1625         }
1626 
1627         if (msg->msg_namelen) {
1628           (void)memset_s(&sll, sizeof(sll), 0, sizeof(sll));
1629           sll.sll_family = PF_PACKET;
1630           sll.sll_protocol = netbuf_fromport(buf);
1631           sll.sll_hatype = netbuf_fromhatype(buf);
1632           sll.sll_ifindex = netbuf_fromifindex(buf);
1633 
1634           if (buf->p->flags & PBUF_FLAG_LLBCAST) {
1635             sll.sll_pkttype = PACKET_BROADCAST;
1636           } else if (buf->p->flags & PBUF_FLAG_LLMCAST) {
1637             sll.sll_pkttype = PACKET_MULTICAST;
1638           } else if (buf->p->flags & PBUF_FLAG_HOST) {
1639             sll.sll_pkttype = PACKET_HOST;
1640           } else if (buf->p->flags & PBUF_FLAG_OUTGOING) {
1641             sll.sll_pkttype = PACKET_OUTGOING;
1642           } else {
1643             sll.sll_pkttype = PACKET_OTHERHOST;
1644           }
1645 
1646           (void)memcpy_s(msg->msg_name, msg->msg_namelen, (void *)&sll, msg->msg_namelen);
1647 
1648           LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom_udp_raw(%d): hatype=%u", dbg_s, ntohs(sll.sll_hatype)));
1649           LWIP_DEBUGF(SOCKETS_DEBUG, (" packet type = %u\n", sll.sll_pkttype));
1650         }
1651       } else
1652 #endif
1653       {
1654         lwip_sock_make_addr(sock->conn, netbuf_fromaddr(buf), netbuf_fromport(buf),
1655                             (struct sockaddr *)msg->msg_name, &msg->msg_namelen);
1656       }
1657     }
1658   }
1659 
1660   /* Initialize flag output */
1661   msg->msg_flags = 0;
1662 
1663   if (msg->msg_control) {
1664     u8_t wrote_msg = 0;
1665 #if LWIP_NETBUF_RECVINFO
1666     /* Check if packet info was recorded */
1667     if (buf->flags & NETBUF_FLAG_DESTADDR) {
1668       if (IP_IS_V4(&buf->toaddr)) {
1669 #if LWIP_IPV4
1670         if (msg->msg_controllen >= CMSG_SPACE(sizeof(struct in_pktinfo))) {
1671           struct cmsghdr *chdr = CMSG_FIRSTHDR(msg); /* This will always return a header!! */
1672           struct in_pktinfo *pkti = (struct in_pktinfo *)CMSG_DATA(chdr);
1673           chdr->cmsg_level = IPPROTO_IP;
1674           chdr->cmsg_type = IP_PKTINFO;
1675           chdr->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
1676           pkti->ipi_ifindex = buf->p->if_idx;
1677           inet_addr_from_ip4addr(&pkti->ipi_addr, ip_2_ip4(netbuf_destaddr(buf)));
1678           msg->msg_controllen = CMSG_SPACE(sizeof(struct in_pktinfo));
1679           wrote_msg = 1;
1680         } else {
1681           msg->msg_flags |= MSG_CTRUNC;
1682         }
1683 #endif /* LWIP_IPV4 */
1684       }
1685     }
1686 #endif /* LWIP_NETBUF_RECVINFO */
1687 
1688     if (!wrote_msg) {
1689       msg->msg_controllen = 0;
1690     }
1691   }
1692 
1693   /* If we don't peek the incoming message: zero lastdata pointer and free the netbuf */
1694   if ((flags & MSG_PEEK) == 0) {
1695     sock->lastdata.netbuf = NULL;
1696     netbuf_delete(buf);
1697     sock->conn->lrcv_left = 0;
1698   } else {
1699     /* store data left count on this rcv operation */
1700     sock->conn->lrcv_left = (u32_t)(buf->p->tot_len);
1701   }
1702   if (datagram_len) {
1703     *datagram_len = buflen;
1704   }
1705   return ERR_OK;
1706 }
1707 
1708 ssize_t
lwip_recvfrom(int s,void * mem,size_t len,int flags,struct sockaddr * from,socklen_t * fromlen)1709 lwip_recvfrom(int s, void *mem, size_t len, int flags,
1710               struct sockaddr *from, socklen_t *fromlen)
1711 {
1712   struct lwip_sock *sock;
1713   ssize_t ret;
1714 
1715   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d, %p, %"SZT_F", 0x%x, ..)\n", s, mem, len, flags));
1716   LWIP_ERROR("lwip_recvfrom: invalid arguments", ((mem != NULL)), set_errno(EFAULT);  return -1);
1717   LWIP_ERROR("lwip_recvfrom: invalid arguments",
1718              ((len != 0) && (flags >= 0) && ((fromlen == NULL) || (*((int*)fromlen) > 0))),
1719              set_errno(EINVAL); return -1);
1720 
1721   sock = get_socket(s);
1722   if (!sock) {
1723     return -1;
1724   }
1725 
1726   unsigned int unacceptable_flags = ~(u32_t)(MSG_PEEK | MSG_DONTWAIT | MSG_NOSIGNAL);
1727   if (unacceptable_flags & (u32_t)flags) {
1728     sock_set_errno(sock, EOPNOTSUPP);
1729     done_socket(sock);
1730     return -1;
1731   }
1732 
1733   lwip_sock_lock(sock);
1734 #if LWIP_TCP
1735   if (NETCONNTYPE_GROUP(NETCONN_TYPE(sock->conn)) == NETCONN_TCP) {
1736     ret = lwip_recv_tcp(sock, mem, len, flags);
1737     lwip_recv_tcp_from(sock, from, fromlen, "lwip_recvfrom", s, ret);
1738     lwip_sock_unlock(sock);
1739     done_socket(sock);
1740     return ret;
1741   } else
1742 #endif
1743   {
1744     u16_t datagram_len = 0;
1745     struct iovec vec;
1746     struct msghdr msg;
1747     err_t err;
1748     vec.iov_base = mem;
1749     vec.iov_len = len;
1750     msg.msg_control = NULL;
1751     msg.msg_controllen = 0;
1752     msg.msg_flags = 0;
1753     msg.msg_iov = &vec;
1754     msg.msg_iovlen = 1;
1755     msg.msg_name = from;
1756     msg.msg_namelen = (fromlen ? *fromlen : 0);
1757     err = lwip_recvfrom_udp_raw(sock, flags, &msg, &datagram_len, s);
1758     if (err != ERR_OK) {
1759       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom[UDP/RAW](%d): buf == NULL, error is \"%s\"!\n",
1760                                   s, lwip_strerr(err)));
1761       sock_set_errno(sock, err_to_errno(err));
1762       lwip_sock_unlock(sock);
1763       done_socket(sock);
1764       return (err == ERR_CLSD) ? 0 : -1;
1765     }
1766     ret = (ssize_t)LWIP_MIN(LWIP_MIN(len, datagram_len), SSIZE_MAX);
1767     if (fromlen) {
1768       *fromlen = msg.msg_namelen;
1769     }
1770   }
1771 
1772   sock_set_errno(sock, 0);
1773   lwip_sock_unlock(sock);
1774   done_socket(sock);
1775   return ret;
1776 }
1777 
1778 ssize_t
lwip_read(int s,void * mem,size_t len)1779 lwip_read(int s, void *mem, size_t len)
1780 {
1781   return lwip_recvfrom(s, mem, len, 0, NULL, NULL);
1782 }
1783 
1784 ssize_t
lwip_readv(int s,const struct iovec * iov,int iovcnt)1785 lwip_readv(int s, const struct iovec *iov, int iovcnt)
1786 {
1787   struct msghdr msg;
1788 
1789   msg.msg_name = NULL;
1790   msg.msg_namelen = 0;
1791   /* Hack: we have to cast via number to cast from 'const' pointer to non-const.
1792      Blame the opengroup standard for this inconsistency. */
1793   msg.msg_iov = LWIP_CONST_CAST(struct iovec *, iov);
1794   msg.msg_iovlen = iovcnt;
1795   msg.msg_control = NULL;
1796   msg.msg_controllen = 0;
1797   msg.msg_flags = 0;
1798   return lwip_recvmsg(s, &msg, 0);
1799 }
1800 
1801 ssize_t
lwip_recv(int s,void * mem,size_t len,int flags)1802 lwip_recv(int s, void *mem, size_t len, int flags)
1803 {
1804   return lwip_recvfrom(s, mem, len, flags, NULL, NULL);
1805 }
1806 
1807 ssize_t
lwip_recvmsg(int s,struct msghdr * message,int flags)1808 lwip_recvmsg(int s, struct msghdr *message, int flags)
1809 {
1810   struct lwip_sock *sock;
1811   int i;
1812   ssize_t buflen;
1813 
1814   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvmsg(%d, message=%p, flags=0x%x)\n", s, (void *)message, flags));
1815   LWIP_ERROR("lwip_recvmsg: invalid message pointer", message != NULL, return ERR_ARG;);
1816   LWIP_ERROR("lwip_recvmsg: unsupported flags", (flags & ~(MSG_PEEK|MSG_DONTWAIT)) == 0,
1817              set_errno(EOPNOTSUPP); return -1;);
1818 
1819   if ((message->msg_iovlen <= 0) || (message->msg_iovlen > IOV_MAX)) {
1820     set_errno(EMSGSIZE);
1821     return -1;
1822   }
1823 
1824   sock = get_socket(s);
1825   if (!sock) {
1826     return -1;
1827   }
1828 
1829   lwip_sock_lock(sock);
1830   /* check for valid vectors */
1831   buflen = 0;
1832   for (i = 0; i < message->msg_iovlen; i++) {
1833     if ((message->msg_iov[i].iov_base == NULL) || ((ssize_t)message->msg_iov[i].iov_len <= 0) ||
1834         ((size_t)(ssize_t)message->msg_iov[i].iov_len != message->msg_iov[i].iov_len) ||
1835         ((ssize_t)(buflen + (ssize_t)message->msg_iov[i].iov_len) <= 0)) {
1836       sock_set_errno(sock, err_to_errno(ERR_VAL));
1837       lwip_sock_unlock(sock);
1838       done_socket(sock);
1839       return -1;
1840     }
1841     buflen = (ssize_t)(buflen + (ssize_t)message->msg_iov[i].iov_len);
1842   }
1843 
1844   if (NETCONNTYPE_GROUP(NETCONN_TYPE(sock->conn)) == NETCONN_TCP) {
1845 #if LWIP_TCP
1846     int recv_flags = flags;
1847     message->msg_flags = 0;
1848     /* recv the data */
1849     buflen = 0;
1850     for (i = 0; i < message->msg_iovlen; i++) {
1851       /* try to receive into this vector's buffer */
1852       ssize_t recvd_local = lwip_recv_tcp(sock, message->msg_iov[i].iov_base, message->msg_iov[i].iov_len, recv_flags);
1853       if (recvd_local > 0) {
1854         /* sum up received bytes */
1855         buflen += recvd_local;
1856       }
1857       if ((recvd_local <= 0) || (recvd_local < (int)message->msg_iov[i].iov_len) ||
1858           (flags & MSG_PEEK)) {
1859         /* returned prematurely (or peeking, which might actually be limitated to the first iov) */
1860         if (buflen <= 0) {
1861           /* nothing received at all, propagate the error */
1862           buflen = recvd_local;
1863         }
1864         break;
1865       }
1866       /* pass MSG_DONTWAIT to lwip_recv_tcp() to prevent waiting for more data */
1867       recv_flags |= MSG_DONTWAIT;
1868     }
1869     if (buflen > 0) {
1870       /* reset socket error since we have received something */
1871       sock_set_errno(sock, 0);
1872     }
1873     /* " If the socket is connected, the msg_name and msg_namelen members shall be ignored." */
1874     lwip_sock_unlock(sock);
1875     done_socket(sock);
1876     return buflen;
1877 #else /* LWIP_TCP */
1878     sock_set_errno(sock, err_to_errno(ERR_ARG));
1879     lwip_sock_unlock(sock);
1880     done_socket(sock);
1881     return -1;
1882 #endif /* LWIP_TCP */
1883   }
1884   /* else, UDP and RAW NETCONNs */
1885 #if LWIP_UDP || LWIP_RAW
1886   {
1887     u16_t datagram_len = 0;
1888     err_t err;
1889     err = lwip_recvfrom_udp_raw(sock, flags, message, &datagram_len, s);
1890     if (err != ERR_OK) {
1891       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvmsg[UDP/RAW](%d): buf == NULL, error is \"%s\"!\n",
1892                                   s, lwip_strerr(err)));
1893       sock_set_errno(sock, err_to_errno(err));
1894       lwip_sock_unlock(sock);
1895       done_socket(sock);
1896       return (err == ERR_CLSD) ? 0 : -1;
1897     }
1898     if (datagram_len > buflen) {
1899       message->msg_flags |= MSG_TRUNC;
1900     }
1901 
1902     sock_set_errno(sock, 0);
1903     lwip_sock_unlock(sock);
1904     done_socket(sock);
1905     return (int)datagram_len;
1906   }
1907 #else /* LWIP_UDP || LWIP_RAW */
1908   sock_set_errno(sock, err_to_errno(ERR_ARG));
1909   lwip_sock_unlock(sock);
1910   done_socket(sock);
1911   return -1;
1912 #endif /* LWIP_UDP || LWIP_RAW */
1913 }
1914 
1915 ssize_t
lwip_send(int s,const void * data,size_t size,int flags)1916 lwip_send(int s, const void *data, size_t size, int flags)
1917 {
1918   struct lwip_sock *sock;
1919   err_t err;
1920   u8_t write_flags;
1921   size_t written;
1922   unsigned int acceptable_flags;
1923 
1924   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_send(%d, data=%p, size=%"SZT_F", flags=0x%x)\n",
1925                               s, data, size, flags));
1926 
1927   sock = get_socket(s);
1928   if (!sock) {
1929     return -1;
1930   }
1931 
1932   if (NETCONNTYPE_GROUP(NETCONN_TYPE(sock->conn)) != NETCONN_TCP) {
1933 #if (LWIP_UDP || LWIP_RAW)
1934     done_socket(sock);
1935     return lwip_sendto(s, data, size, flags, NULL, 0);
1936 #else /* (LWIP_UDP || LWIP_RAW) */
1937     sock_set_errno(sock, err_to_errno(ERR_ARG));
1938     done_socket(sock);
1939     return -1;
1940 #endif /* (LWIP_UDP || LWIP_RAW) */
1941   }
1942 
1943   LWIP_ERROR("lwip_send: invalid arguments", ((data != NULL) && (size != 0) && (flags >= 0)),
1944               sock_set_errno(sock, err_to_errno(ERR_VAL)); done_socket(sock); return -1;);
1945 
1946   acceptable_flags = MSG_DONTWAIT | MSG_MORE | MSG_NOSIGNAL;
1947   LWIP_ERROR("lwip_send: unsupported flags", !((~acceptable_flags) & flags),
1948               sock_set_errno(sock, EOPNOTSUPP); done_socket(sock); return -1;);
1949 
1950   write_flags = (u8_t)(NETCONN_COPY |
1951                        ((flags & MSG_MORE)     ? NETCONN_MORE      : 0) |
1952                        ((flags & MSG_DONTWAIT) ? NETCONN_DONTBLOCK : 0));
1953   written = 0;
1954   err = netconn_write_partly(sock->conn, data, size, write_flags, &written);
1955 
1956   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_send(%d) err=%d written=%"SZT_F"\n", s, err, written));
1957   if (err != ERR_OK) {
1958     sock_set_errno(sock, err_to_errno(err));
1959   }
1960   done_socket(sock);
1961   /* casting 'written' to ssize_t is OK here since the netconn API limits it to SSIZE_MAX */
1962   return (err == ERR_OK ? (ssize_t)written : -1);
1963 }
1964 
1965 ssize_t
lwip_sendmsg(int s,const struct msghdr * msg,int flags)1966 lwip_sendmsg(int s, const struct msghdr *msg, int flags)
1967 {
1968   struct lwip_sock *sock;
1969 #if LWIP_TCP
1970   u8_t write_flags;
1971   size_t written;
1972   unsigned int acceptable_flags = 0;
1973 #endif
1974   err_t err = ERR_OK;
1975 
1976   sock = get_socket(s);
1977   if (!sock) {
1978     return -1;
1979   }
1980 
1981   LWIP_ERROR("lwip_sendmsg: invalid msghdr", msg != NULL,
1982              sock_set_errno(sock, err_to_errno(ERR_ARG)); done_socket(sock); return -1;);
1983   LWIP_ERROR("lwip_sendmsg: invalid msghdr iov", msg->msg_iov != NULL,
1984              sock_set_errno(sock, err_to_errno(ERR_ARG)); done_socket(sock); return -1;);
1985   LWIP_ERROR("lwip_sendmsg: maximum iovs exceeded", (msg->msg_iovlen > 0) && (msg->msg_iovlen <= IOV_MAX),
1986              sock_set_errno(sock, EMSGSIZE); done_socket(sock); return -1;);
1987   LWIP_ERROR("lwip_sendmsg: unsupported flags", (flags & ~(MSG_DONTWAIT | MSG_MORE)) == 0,
1988              sock_set_errno(sock, EOPNOTSUPP); done_socket(sock); return -1;);
1989 
1990   LWIP_UNUSED_ARG(msg->msg_control);
1991   LWIP_UNUSED_ARG(msg->msg_controllen);
1992   LWIP_UNUSED_ARG(msg->msg_flags);
1993 
1994   if (NETCONNTYPE_GROUP(NETCONN_TYPE(sock->conn)) == NETCONN_TCP) {
1995 #if LWIP_TCP
1996 
1997     acceptable_flags = MSG_DONTWAIT | MSG_MORE | MSG_NOSIGNAL;
1998     LWIP_ERROR("lwip_send: unsupported flags", !((~acceptable_flags) & flags),
1999                 sock_set_errno(sock, EOPNOTSUPP); done_socket(sock); return -1;);
2000 
2001     write_flags = (u8_t)(NETCONN_COPY |
2002                          ((flags & MSG_MORE)     ? NETCONN_MORE      : 0) |
2003                          ((flags & MSG_DONTWAIT) ? NETCONN_DONTBLOCK : 0));
2004 
2005     written = 0;
2006     err = netconn_write_vectors_partly(sock->conn, (struct netvector *)msg->msg_iov, (u16_t)msg->msg_iovlen, write_flags, &written);
2007     if (err != ERR_OK) {
2008       sock_set_errno(sock, err_to_errno(err));
2009     }
2010     done_socket(sock);
2011     /* casting 'written' to ssize_t is OK here since the netconn API limits it to SSIZE_MAX */
2012     return (err == ERR_OK ? (ssize_t)written : -1);
2013 #else /* LWIP_TCP */
2014     sock_set_errno(sock, err_to_errno(ERR_ARG));
2015     done_socket(sock);
2016     return -1;
2017 #endif /* LWIP_TCP */
2018   }
2019   /* else, UDP and RAW NETCONNs */
2020 #if LWIP_UDP || LWIP_RAW
2021   {
2022     struct netbuf chain_buf;
2023     int i;
2024     ssize_t size = 0;
2025 
2026     LWIP_UNUSED_ARG(flags);
2027     LWIP_ERROR("lwip_sendmsg: invalid msghdr name", (((msg->msg_name == NULL) && (msg->msg_namelen == 0)) ||
2028                IS_SOCK_ADDR_LEN_VALID(msg->msg_namelen)),
2029                sock_set_errno(sock, err_to_errno(ERR_ARG)); done_socket(sock); return -1;);
2030 
2031     /* initialize chain buffer with destination */
2032     memset(&chain_buf, 0, sizeof(struct netbuf));
2033     if (msg->msg_name) {
2034       u16_t remote_port;
2035       SOCKADDR_TO_IPADDR_PORT((const struct sockaddr *)msg->msg_name, &chain_buf.addr, remote_port);
2036       netbuf_fromport(&chain_buf) = remote_port;
2037     }
2038 #if LWIP_NETIF_TX_SINGLE_PBUF
2039     for (i = 0; i < msg->msg_iovlen; i++) {
2040       size += msg->msg_iov[i].iov_len;
2041       if ((msg->msg_iov[i].iov_len > INT_MAX) || (size < (int)msg->msg_iov[i].iov_len)) {
2042         /* overflow */
2043         goto sendmsg_emsgsize;
2044       }
2045     }
2046     if (size > 0xFFFF) {
2047       /* overflow */
2048       goto sendmsg_emsgsize;
2049     }
2050     /* Allocate a new netbuf and copy the data into it. */
2051     if (netbuf_alloc(&chain_buf, (u16_t)size, NETCONNTYPE_GROUP(NETCONN_TYPE(sock->conn))) == NULL) {
2052       err = ERR_MEM;
2053     } else {
2054       /* flatten the IO vectors */
2055       size_t offset = 0;
2056       for (i = 0; i < msg->msg_iovlen; i++) {
2057         MEMCPY(&((u8_t *)chain_buf.p->payload)[offset], msg->msg_iov[i].iov_base, msg->msg_iov[i].iov_len);
2058         offset += msg->msg_iov[i].iov_len;
2059       }
2060 #if LWIP_CHECKSUM_ON_COPY
2061       {
2062         /* This can be improved by using LWIP_CHKSUM_COPY() and aggregating the checksum for each IO vector */
2063         u16_t chksum = (u16_t)(~inet_chksum_pbuf(chain_buf.p));
2064         netbuf_set_chksum(&chain_buf, chksum);
2065       }
2066 #endif /* LWIP_CHECKSUM_ON_COPY */
2067       err = ERR_OK;
2068     }
2069 #else /* LWIP_NETIF_TX_SINGLE_PBUF */
2070     /* create a chained netbuf from the IO vectors. NOTE: we assemble a pbuf chain
2071        manually to avoid having to allocate, chain, and delete a netbuf for each iov */
2072     for (i = 0; i < msg->msg_iovlen; i++) {
2073       struct pbuf *p;
2074       if (msg->msg_iov[i].iov_len > 0xFFFF) {
2075         /* overflow */
2076         goto sendmsg_emsgsize;
2077       }
2078       p = pbuf_alloc(PBUF_TRANSPORT, 0, PBUF_REF);
2079       if (p == NULL) {
2080         err = ERR_MEM; /* let netbuf_delete() cleanup chain_buf */
2081         break;
2082       }
2083       p->payload = msg->msg_iov[i].iov_base;
2084       p->len = p->tot_len = (u16_t)msg->msg_iov[i].iov_len;
2085       /* netbuf empty, add new pbuf */
2086       if (chain_buf.p == NULL) {
2087         chain_buf.p = chain_buf.ptr = p;
2088         /* add pbuf to existing pbuf chain */
2089       } else {
2090         if (chain_buf.p->tot_len + p->len > 0xffff) {
2091           /* overflow */
2092           pbuf_free(p);
2093           goto sendmsg_emsgsize;
2094         }
2095         pbuf_cat(chain_buf.p, p);
2096       }
2097     }
2098     /* save size of total chain */
2099     if (err == ERR_OK) {
2100       size = netbuf_len(&chain_buf);
2101     }
2102 #endif /* LWIP_NETIF_TX_SINGLE_PBUF */
2103 
2104     if (err == ERR_OK) {
2105 #if LWIP_IPV4 && LWIP_IPV6
2106       /* Dual-stack: Unmap IPv4 mapped IPv6 addresses */
2107       if (IP_IS_V6_VAL(chain_buf.addr) && ip6_addr_isipv4mappedipv6(ip_2_ip6(&chain_buf.addr))) {
2108         unmap_ipv4_mapped_ipv6(ip_2_ip4(&chain_buf.addr), ip_2_ip6(&chain_buf.addr));
2109         IP_SET_TYPE_VAL(chain_buf.addr, IPADDR_TYPE_V4);
2110       }
2111 #endif /* LWIP_IPV4 && LWIP_IPV6 */
2112 
2113       /* send the data */
2114       err = netconn_send(sock->conn, &chain_buf);
2115     }
2116 
2117     /* deallocated the buffer */
2118     netbuf_free(&chain_buf);
2119 
2120     if (err != ERR_OK) {
2121       sock_set_errno(sock, err_to_errno(err));
2122     }
2123     done_socket(sock);
2124     return (err == ERR_OK ? size : -1);
2125 sendmsg_emsgsize:
2126     sock_set_errno(sock, EMSGSIZE);
2127     netbuf_free(&chain_buf);
2128     done_socket(sock);
2129     return -1;
2130   }
2131 #else /* LWIP_UDP || LWIP_RAW */
2132   sock_set_errno(sock, err_to_errno(ERR_ARG));
2133   done_socket(sock);
2134   return -1;
2135 #endif /* LWIP_UDP || LWIP_RAW */
2136 }
2137 
2138 ssize_t
lwip_sendto(int s,const void * data,size_t size,int flags,const struct sockaddr * to,socklen_t tolen)2139 lwip_sendto(int s, const void *data, size_t size, int flags,
2140             const struct sockaddr *to, socklen_t tolen)
2141 {
2142   struct lwip_sock *sock;
2143   err_t err;
2144   u16_t short_size;
2145   u16_t remote_port = 0;
2146   struct netbuf buf;
2147 #if PF_PKT_SUPPORT
2148   const struct sockaddr_ll *to_ll = NULL;
2149 #endif
2150   const struct sockaddr_in *to_in = NULL;
2151 
2152 #if LWIP_UDP || LWIP_RAW
2153   SYS_ARCH_DECL_PROTECT(lev);
2154 #endif
2155 
2156   unsigned int acceptable_flags = 0;
2157 
2158   sock = get_socket(s);
2159   if (!sock) {
2160     return -1;
2161   }
2162 
2163   if (NETCONNTYPE_GROUP(NETCONN_TYPE(sock->conn)) == NETCONN_TCP) {
2164 #if LWIP_TCP
2165     done_socket(sock);
2166     return lwip_send(s, data, size, flags);
2167 #else /* LWIP_TCP */
2168     LWIP_UNUSED_ARG(flags);
2169     sock_set_errno(sock, err_to_errno(ERR_ARG));
2170     done_socket(sock);
2171     return -1;
2172 #endif /* LWIP_TCP */
2173   }
2174 
2175 #if PF_PKT_SUPPORT
2176   if (NETCONNTYPE_GROUP(NETCONN_TYPE(sock->conn))  & NETCONN_PKT_RAW) {
2177     to_ll = (const struct sockaddr_ll *)(void *)to;
2178 
2179     LWIP_ERROR("lwip_sendto: invalid address", (((data != NULL) && (size!=0)) &&
2180                (((to_ll != NULL) && (tolen == sizeof(struct sockaddr_ll)))  &&
2181                ((to_ll->sll_family) == PF_PACKET) && ((((mem_ptr_t)to_ll) % 4) == 0)) &&
2182                (to_ll->sll_ifindex <= LWIP_NETIF_IFINDEX_MAX)),
2183                sock_set_errno(sock, err_to_errno(ERR_VAL));
2184                done_socket(sock); return -1);
2185 
2186     LWIP_ERROR("lwip_sendto: invalid address family", ((to_ll->sll_family) == PF_PACKET),
2187                sock_set_errno(sock, err_to_errno(ERR_AFNOSUPP));
2188                done_socket(sock); return -1);
2189 
2190     LWIP_ERROR("lwip_sendto: invalid flags. Should be 0", (flags == 0),
2191                sock_set_errno(sock, err_to_errno(ERR_OPNOTSUPP));
2192                done_socket(sock); return -1);
2193 
2194     if (size > LWIP_MAX_PF_RAW_SEND_SIZE) {
2195       sock_set_errno(sock, EMSGSIZE);
2196       done_socket(sock);
2197       return -1;
2198     }
2199   } else
2200 #endif
2201   {
2202     to_in = (const struct sockaddr_in *)(void*)to;
2203     acceptable_flags = acceptable_flags | MSG_MORE | MSG_DONTWAIT | MSG_NOSIGNAL;
2204     if ((~acceptable_flags) & (unsigned int)flags) {
2205       sock_set_errno(sock, err_to_errno(ERR_OPNOTSUPP));
2206       done_socket(sock);
2207       return -1;
2208     }
2209 
2210     LWIP_ERROR("lwip_sendto: invalid address", ((data != NULL) && (size!=0) && (flags>=0)),
2211                sock_set_errno(sock, err_to_errno(ERR_VAL));
2212                done_socket(sock); return -1);
2213 
2214     LWIP_ERROR("lwip_sendto: invalid address", (((to_in == NULL) && (tolen == 0)) ||
2215                (((to_in == NULL) && (tolen != 0)) || IS_SOCK_ADDR_LEN_VALID(tolen))),
2216                sock_set_errno(sock, err_to_errno(ERR_VAL));
2217                done_socket(sock);
2218                return -1);
2219 
2220 #if LWIP_CHECK_ADDR_ALIGN
2221     LWIP_ERROR("lwip_sendto: invalid address", (IS_SOCK_ADDR_ALIGNED(to_in)),
2222                sock_set_errno(sock, err_to_errno(ERR_VAL));
2223                done_socket(sock);
2224                return -1);
2225 #endif
2226 
2227     LWIP_ERROR("lwip_sendto: invalid address", (to == NULL || IS_SOCK_ADDR_TYPE_VALID(to)),
2228                sock_set_errno(sock, err_to_errno(ERR_AFNOSUPPORT));
2229                done_socket(sock);
2230                return -1);
2231 
2232     if (size > LWIP_MAX_UDP_RAW_SEND_SIZE) {
2233       sock_set_errno(sock, EMSGSIZE);
2234       done_socket(sock);
2235       return -1;
2236     }
2237   }
2238 
2239   /* size must fit in u16_t */
2240   short_size = (u16_t)size;
2241   LWIP_UNUSED_ARG(tolen);
2242 
2243   /* initialize a buffer */
2244   buf.p = buf.ptr = NULL;
2245 #if LWIP_CHECKSUM_ON_COPY || PF_PKT_SUPPORT
2246   buf.flags = 0;
2247 #endif /* LWIP_CHECKSUM_ON_COPY || PF_PKT_SUPPORT */
2248 #if PF_PKT_SUPPORT
2249   buf.netifindex = 0;
2250 #endif
2251   if (to_in) {
2252     SOCKADDR_TO_IPADDR_PORT(to, &buf.addr, remote_port);
2253     netbuf_fromport(&buf) = remote_port;
2254 #if LWIP_ENABLE_NET_CAPABILITY && LWIP_ENABLE_CAP_NET_BROADCAST
2255     if (ip_addr_ismulticast(&buf.addr) || ip_addr_isbroadcast_by_sock(&buf.addr, sock)) {
2256       LWIP_ERROR("lwip_sendto permission deny: NET_BROADCAST\n", IsCapPermit(CAP_NET_BROADCAST),
2257                  sock_set_errno(sock, EPERM); done_socket(sock); return -1);
2258     }
2259 #endif
2260   } else {
2261 #if PF_PKT_SUPPORT
2262     if (to_ll != NULL) {
2263       buf.flags |= NETBUF_FLAG_IFINDEX;
2264       buf.netifindex = (u8_t)to_ll->sll_ifindex;
2265     } else
2266 #endif
2267     {
2268 #if LWIP_UDP
2269       if (NETCONNTYPE_GROUP(NETCONN_TYPE(sock->conn)) == NETCONN_UDP) {
2270         SYS_ARCH_PROTECT(lev);
2271         if (sock->conn->pcb.udp != NULL && (sock->conn->pcb.udp->flags & UDP_FLAGS_CONNECTED)) {
2272           buf.addr = sock->conn->pcb.udp->remote_ip;
2273           remote_port           = sock->conn->pcb.udp->remote_port;
2274           SYS_ARCH_UNPROTECT(lev);
2275           netbuf_fromport(&buf) = remote_port;
2276         } else {
2277           SYS_ARCH_UNPROTECT(lev);
2278           LWIP_DEBUGF(SOCKETS_DEBUG, ("No address provide for UDP unconnect socket\n"));
2279           sock_set_errno(sock, err_to_errno(ERR_NODEST));
2280           done_socket(sock);
2281           return -1;
2282         }
2283       }
2284 #endif
2285 #if LWIP_RAW
2286       if (NETCONNTYPE_GROUP(NETCONN_TYPE(sock->conn)) & NETCONN_RAW) {
2287         SYS_ARCH_PROTECT(lev);
2288         if (sock->conn->pcb.raw != NULL && (sock->conn->pcb.raw->flags & RAW_FLAGS_CONNECTED)) {
2289           buf.addr = sock->conn->pcb.raw->remote_ip;
2290           SYS_ARCH_UNPROTECT(lev);
2291         } else {
2292           SYS_ARCH_UNPROTECT(lev);
2293           LWIP_DEBUGF(SOCKETS_DEBUG, ("No address provide for unconnect RAW socket\n"));
2294           sock_set_errno(sock, err_to_errno(ERR_NODEST));
2295           done_socket(sock);
2296           return -1;
2297         }
2298       }
2299 #endif
2300     }
2301   }
2302 
2303   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_sendto(%d, data=%p, short_size=%"U16_F", flags=0x%x to=",
2304                               s, data, short_size, flags));
2305 #if PF_PKT_SUPPORT
2306   if (buf.flags & NETBUF_FLAG_IFINDEX) {
2307     LWIP_DEBUGF(SOCKETS_DEBUG, (" netifindex = %d\n", buf.netifindex));
2308   } else
2309 #endif
2310   {
2311     ip_addr_debug_print_val(SOCKETS_DEBUG, buf.addr);
2312     LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F"\n", remote_port));
2313   }
2314   /* make the buffer point to the data that should be sent */
2315 #if LWIP_NETIF_TX_SINGLE_PBUF
2316   /* Allocate a new netbuf and copy the data into it. */
2317   if (netbuf_alloc(&buf, short_size, NETCONNTYPE_GROUP(NETCONN_TYPE(sock->conn))) == NULL) {
2318     err = ERR_MEM;
2319   } else {
2320 #if LWIP_CHECKSUM_ON_COPY
2321 #if PF_PKT_SUPPORT
2322     if ((NETCONNTYPE_GROUP(NETCONN_TYPE(sock->conn)) != NETCONN_PKT_RAW) &&
2323         (NETCONNTYPE_GROUP(NETCONN_TYPE(sock->conn)) != NETCONN_RAW))
2324 #else
2325     if (NETCONNTYPE_GROUP(NETCONN_TYPE(sock->conn)) != NETCONN_RAW)
2326 #endif
2327     {
2328       u16_t chksum = LWIP_CHKSUM_COPY(buf.p->payload, data, short_size);
2329       netbuf_set_chksum(&buf, chksum);
2330     } else
2331 #endif /* LWIP_CHECKSUM_ON_COPY */
2332     {
2333       MEMCPY(buf.p->payload, data, short_size);
2334     }
2335     err = ERR_OK;
2336   }
2337 #else /* LWIP_NETIF_TX_SINGLE_PBUF */
2338   err = netbuf_ref(&buf, data, short_size);
2339 #endif /* LWIP_NETIF_TX_SINGLE_PBUF */
2340   if (err == ERR_OK) {
2341 #if LWIP_IPV4 && LWIP_IPV6
2342     /* Dual-stack: Unmap IPv4 mapped IPv6 addresses */
2343     if (IP_IS_V6_VAL(buf.addr) && ip6_addr_isipv4mappedipv6(ip_2_ip6(&buf.addr))) {
2344       unmap_ipv4_mapped_ipv6(ip_2_ip4(&buf.addr), ip_2_ip6(&buf.addr));
2345       IP_SET_TYPE_VAL(buf.addr, IPADDR_TYPE_V4);
2346     }
2347 #endif /* LWIP_IPV4 && LWIP_IPV6 */
2348 
2349     /* send the data */
2350     err = netconn_send(sock->conn, &buf);
2351   }
2352 
2353   /* deallocated the buffer */
2354   netbuf_free(&buf);
2355 
2356   sock_set_errno(sock, err_to_errno(err));
2357   done_socket(sock);
2358   return (err == ERR_OK ? short_size : -1);
2359 }
2360 
2361 int
lwip_socket(int domain,int type,int protocol)2362 lwip_socket(int domain, int type, int protocol)
2363 {
2364   struct netconn *conn;
2365   int i;
2366 
2367   LWIP_UNUSED_ARG(domain); /* @todo: check this */
2368   LWIP_ERROR("domain invalid\n",  (LWIP_IS_VALID_DOMAIN(domain)),
2369              set_errno(EAFNOSUPPORT); return -1);
2370 
2371   LWIP_ERROR("flag invalid\n", !(type & ~SOCK_TYPE_MASK),
2372              set_errno(EINVAL); return -1);
2373 
2374 #if PF_PKT_SUPPORT
2375   LWIP_ERROR("Invalid socket type for PF_PACKET domain\n", ((domain != PF_PACKET) || (type == SOCK_RAW)),
2376              set_errno(ESOCKTNOSUPPORT); return -1);
2377 #endif
2378 
2379   /* create a netconn */
2380   switch (type) {
2381     case SOCK_RAW:
2382 #if LWIP_ENABLE_NET_CAPABILITY
2383       LWIP_ERROR("permission deny: NET_RAW\n", IsCapPermit(CAP_NET_RAW),
2384                  set_errno(EPERM); return -1);
2385 #endif
2386 #if PF_PKT_SUPPORT
2387       if (domain == PF_PACKET) {
2388         conn = netconn_new_with_proto_and_callback(DOMAIN_TO_NETCONN_TYPE(domain, NETCONN_PKT_RAW),
2389                                                    (u16_t)protocol, event_callback);
2390         LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_RAW, %d) = ", "PF_PACKET", protocol));
2391       } else
2392 #endif
2393       {
2394         conn = netconn_new_with_proto_and_callback(DOMAIN_TO_NETCONN_TYPE(domain, NETCONN_RAW),
2395                (u16_t)protocol, DEFAULT_SOCKET_EVENTCB);
2396         LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_RAW, %d) = ",
2397                                     domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol));
2398       }
2399       break;
2400     case SOCK_DGRAM:
2401       LWIP_ERROR("protocol invalid\n",
2402                  (protocol == IPPROTO_UDPLITE || protocol == IPPROTO_UDP || LWIP_IS_IPPROTOCOL(protocol)),
2403                  set_errno(EPROTONOSUPPORT); return -1;);
2404       conn = netconn_new_with_callback(DOMAIN_TO_NETCONN_TYPE(domain,
2405                                        ((protocol == IPPROTO_UDPLITE) ? NETCONN_UDPLITE : NETCONN_UDP)),
2406                                        DEFAULT_SOCKET_EVENTCB);
2407       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_DGRAM, %d) = ",
2408                                   domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol));
2409 #if LWIP_NETBUF_RECVINFO
2410       if (conn) {
2411         /* netconn layer enables pktinfo by default, sockets default to off */
2412         conn->flags &= ~NETCONN_FLAG_PKTINFO;
2413       }
2414 #endif /* LWIP_NETBUF_RECVINFO */
2415       break;
2416     case SOCK_STREAM:
2417       LWIP_ERROR("protocol invalid\n", (protocol == IPPROTO_TCP || LWIP_IS_IPPROTOCOL(protocol)),
2418                                      set_errno(EPROTONOSUPPORT); return -1;);
2419       conn = netconn_new_with_callback(DOMAIN_TO_NETCONN_TYPE(domain, NETCONN_TCP), DEFAULT_SOCKET_EVENTCB);
2420       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_STREAM, %d) = ",
2421                                   domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol));
2422       break;
2423     default:
2424       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%d, %d/UNKNOWN, %d) = -1\n",
2425                                   domain, type, protocol));
2426       set_errno(ESOCKTNOSUPPORT);
2427       return -1;
2428   }
2429 
2430   if (!conn) {
2431     LWIP_DEBUGF(SOCKETS_DEBUG, ("-1 / ENOBUFS (could not create netconn)\n"));
2432     set_errno(ENOBUFS);
2433     return -1;
2434   }
2435 
2436   i = alloc_socket(conn, 0);
2437 
2438   if (i == -1) {
2439     netconn_delete(conn);
2440     set_errno(ENFILE);
2441     return -1;
2442   }
2443   conn->socket = i;
2444   done_socket(&sockets[i - LWIP_SOCKET_OFFSET]);
2445   LWIP_DEBUGF(SOCKETS_DEBUG, ("%d\n", i));
2446   set_errno(0);
2447   return i;
2448 }
2449 
2450 ssize_t
lwip_write(int s,const void * data,size_t size)2451 lwip_write(int s, const void *data, size_t size)
2452 {
2453   return lwip_send(s, data, size, 0);
2454 }
2455 
2456 ssize_t
lwip_writev(int s,const struct iovec * iov,int iovcnt)2457 lwip_writev(int s, const struct iovec *iov, int iovcnt)
2458 {
2459   struct msghdr msg;
2460 
2461   LWIP_ERROR("iovcnt invalid\n", (iovcnt >= 0),
2462              set_errno(EINVAL); return -1);
2463   msg.msg_name = NULL;
2464   msg.msg_namelen = 0;
2465   /* Hack: we have to cast via number to cast from 'const' pointer to non-const.
2466      Blame the opengroup standard for this inconsistency. */
2467   msg.msg_iov = LWIP_CONST_CAST(struct iovec *, iov);
2468   msg.msg_iovlen = iovcnt;
2469   msg.msg_control = NULL;
2470   msg.msg_controllen = 0;
2471   msg.msg_flags = 0;
2472   return lwip_sendmsg(s, &msg, 0);
2473 }
2474 
2475 #if LWIP_SOCKET_SELECT || LWIP_SOCKET_POLL
2476 /* Add select_cb to select_cb_list. */
2477 static void
lwip_link_select_cb(struct lwip_select_cb * select_cb)2478 lwip_link_select_cb(struct lwip_select_cb *select_cb)
2479 {
2480   LWIP_SOCKET_SELECT_DECL_PROTECT(lev);
2481 
2482   /* Protect the select_cb_list */
2483   LWIP_SOCKET_SELECT_PROTECT(lev);
2484 
2485   /* Put this select_cb on top of list */
2486   select_cb->next = select_cb_list;
2487   if (select_cb_list != NULL) {
2488     select_cb_list->prev = select_cb;
2489   }
2490   select_cb_list = select_cb;
2491 #if !LWIP_TCPIP_CORE_LOCKING
2492   /* Increasing this counter tells select_check_waiters that the list has changed. */
2493   select_cb_ctr++;
2494 #endif
2495 
2496   /* Now we can safely unprotect */
2497   LWIP_SOCKET_SELECT_UNPROTECT(lev);
2498 }
2499 
2500 /* Remove select_cb from select_cb_list. */
2501 static void
lwip_unlink_select_cb(struct lwip_select_cb * select_cb)2502 lwip_unlink_select_cb(struct lwip_select_cb *select_cb)
2503 {
2504   LWIP_SOCKET_SELECT_DECL_PROTECT(lev);
2505 
2506   /* Take us off the list */
2507   LWIP_SOCKET_SELECT_PROTECT(lev);
2508   if (select_cb->next != NULL) {
2509     select_cb->next->prev = select_cb->prev;
2510   }
2511   if (select_cb_list == select_cb) {
2512     LWIP_ASSERT("select_cb->prev == NULL", select_cb->prev == NULL);
2513     select_cb_list = select_cb->next;
2514   } else {
2515     LWIP_ASSERT("select_cb->prev != NULL", select_cb->prev != NULL);
2516     select_cb->prev->next = select_cb->next;
2517   }
2518 #if !LWIP_TCPIP_CORE_LOCKING
2519   /* Increasing this counter tells select_check_waiters that the list has changed. */
2520   select_cb_ctr++;
2521 #endif
2522   LWIP_SOCKET_SELECT_UNPROTECT(lev);
2523 }
2524 #endif /* LWIP_SOCKET_SELECT || LWIP_SOCKET_POLL */
2525 
2526 #define LWIP_MAX_SELECT_TIMEOUT_VAL_MSEC 0xFFFFFFFEU // in milliseconds
2527 
2528 #if LWIP_SOCKET_SELECT
2529 /**
2530  * Go through the readset and writeset lists and see which socket of the sockets
2531  * set in the sets has events. On return, readset, writeset and exceptset have
2532  * the sockets enabled that had events.
2533  *
2534  * @param maxfdp1 the highest socket index in the sets
2535  * @param readset_in    set of sockets to check for read events
2536  * @param writeset_in   set of sockets to check for write events
2537  * @param exceptset_in  set of sockets to check for error events
2538  * @param readset_out   set of sockets that had read events
2539  * @param writeset_out  set of sockets that had write events
2540  * @param exceptset_out set os sockets that had error events
2541  * @return number of sockets that had events (read/write/exception) (>= 0)
2542  */
2543 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)2544 lwip_selscan(int maxfdp1, fd_set *readset_in, fd_set *writeset_in, fd_set *exceptset_in,
2545              fd_set *readset_out, fd_set *writeset_out, fd_set *exceptset_out)
2546 {
2547   int i, nready = 0;
2548   fd_set lreadset, lwriteset, lexceptset;
2549   struct lwip_sock *sock;
2550   SYS_ARCH_DECL_PROTECT(lev);
2551 
2552   FD_ZERO(&lreadset);
2553   FD_ZERO(&lwriteset);
2554   FD_ZERO(&lexceptset);
2555 
2556   /* Go through each socket in each list to count number of sockets which
2557      currently match */
2558   for (i = LWIP_SOCKET_OFFSET; i < maxfdp1; i++) {
2559     /* if this FD is not in the set, continue */
2560     if (!(readset_in && FD_ISSET(i, readset_in)) &&
2561         !(writeset_in && FD_ISSET(i, writeset_in)) &&
2562         !(exceptset_in && FD_ISSET(i, exceptset_in))) {
2563       continue;
2564     }
2565     /* First get the socket's status (protected)... */
2566     SYS_ARCH_PROTECT(lev);
2567     sock = tryget_socket_unconn_locked(i);
2568     if (sock != NULL) {
2569       void *lastdata = sock->lastdata.pbuf;
2570       s16_t rcvevent = sock->rcvevent;
2571       u16_t sendevent = sock->sendevent;
2572       u16_t errevent = sock->errevent;
2573       SYS_ARCH_UNPROTECT(lev);
2574 
2575       /* ... then examine it: */
2576       /* See if netconn of this socket is ready for read */
2577       if (readset_in && FD_ISSET(i, readset_in) && ((lastdata != NULL) || (rcvevent > 0))) {
2578         FD_SET(i, &lreadset);
2579         LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_selscan: fd=%d ready for reading\n", i));
2580         nready++;
2581       }
2582       /* See if netconn of this socket is ready for write */
2583       if (writeset_in && FD_ISSET(i, writeset_in) && (sendevent != 0)) {
2584         FD_SET(i, &lwriteset);
2585         LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_selscan: fd=%d ready for writing\n", i));
2586         nready++;
2587       }
2588       /* See if netconn of this socket had an error */
2589       if (exceptset_in && FD_ISSET(i, exceptset_in) && (errevent != 0)) {
2590         FD_SET(i, &lexceptset);
2591         LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_selscan: fd=%d ready for exception\n", i));
2592         nready++;
2593       }
2594       done_socket(sock);
2595     } else {
2596       SYS_ARCH_UNPROTECT(lev);
2597       /* no a valid open socket */
2598       return -1;
2599     }
2600   }
2601   /* copy local sets to the ones provided as arguments */
2602   *readset_out = lreadset;
2603   *writeset_out = lwriteset;
2604   *exceptset_out = lexceptset;
2605 
2606   LWIP_ASSERT("nready >= 0", nready >= 0);
2607   return nready;
2608 }
2609 
2610 #if LWIP_NETCONN_FULLDUPLEX
2611 static void
2612 lwip_select_dec_sockets_used(int maxfdp, fd_set *used_sockets);
2613 /* Mark all of the set sockets in one of the three fdsets passed to select as used.
2614  * All sockets are marked (and later unmarked), whether they are open or not.
2615  * This is OK as lwip_selscan aborts select when non-open sockets are found.
2616  */
2617 static err_t
lwip_select_inc_sockets_used_set(int maxfdp,fd_set * fdset,fd_set * used_sockets)2618 lwip_select_inc_sockets_used_set(int maxfdp, fd_set *fdset, fd_set *used_sockets)
2619 {
2620   SYS_ARCH_DECL_PROTECT(lev);
2621   if (fdset) {
2622     int i;
2623     for (i = LWIP_SOCKET_OFFSET; i < maxfdp; i++) {
2624       /* if this FD is in the set, lock it (unless already done) */
2625       if (FD_ISSET(i, fdset) && !FD_ISSET(i, used_sockets)) {
2626         struct lwip_sock *sock;
2627         SYS_ARCH_PROTECT(lev);
2628         sock = tryget_socket_unconn_locked(i);
2629         if (sock != NULL) {
2630           /* leave the socket used until released by lwip_select_dec_sockets_used */
2631           FD_SET(i, used_sockets);
2632         } else {
2633           SYS_ARCH_UNPROTECT(lev);
2634           lwip_select_dec_sockets_used(maxfdp, used_sockets);
2635           return ERR_VAL;
2636         }
2637         SYS_ARCH_UNPROTECT(lev);
2638       }
2639     }
2640   }
2641 
2642   return ERR_OK;
2643 }
2644 
2645 /* Mark all sockets passed to select as used to prevent them from being freed
2646  * from other threads while select is running.
2647  * Marked sockets are added to 'used_sockets' to mark them only once an be able
2648  * to unmark them correctly.
2649  */
2650 static err_t
lwip_select_inc_sockets_used(int maxfdp,fd_set * fdset1,fd_set * fdset2,fd_set * fdset3,fd_set * used_sockets)2651 lwip_select_inc_sockets_used(int maxfdp, fd_set *fdset1, fd_set *fdset2, fd_set *fdset3, fd_set *used_sockets)
2652 {
2653   err_t retval;
2654   int i;
2655   u32_t used = 0;
2656   FD_ZERO(used_sockets);
2657   retval = lwip_select_inc_sockets_used_set(maxfdp, fdset1, used_sockets);
2658   if (retval != ERR_OK) {
2659     return retval;
2660   }
2661 
2662   retval = lwip_select_inc_sockets_used_set(maxfdp, fdset2, used_sockets);
2663   if (retval != ERR_OK) {
2664     return retval;
2665   }
2666 
2667   retval = lwip_select_inc_sockets_used_set(maxfdp, fdset3, used_sockets);
2668   if (retval != ERR_OK) {
2669     return retval;
2670   }
2671 
2672   for (i = LWIP_SOCKET_OFFSET; i < maxfdp; i++) {
2673     /* if this FD is not in the set, continue */
2674     if (FD_ISSET(i, used_sockets)) {
2675       used++;
2676     }
2677   }
2678 
2679   if (used == 0) {
2680     return ERR_VAL;
2681   }
2682   return ERR_OK;
2683 }
2684 
2685 /* Let go all sockets that were marked as used when starting select */
2686 static void
lwip_select_dec_sockets_used(int maxfdp,fd_set * used_sockets)2687 lwip_select_dec_sockets_used(int maxfdp, fd_set *used_sockets)
2688 {
2689   int i;
2690   for (i = LWIP_SOCKET_OFFSET; i < maxfdp; i++) {
2691     /* if this FD is not in the set, continue */
2692     if (FD_ISSET(i, used_sockets)) {
2693       struct lwip_sock *sock = tryget_socket_unconn_nouse(i);
2694       LWIP_ASSERT("socket gone at the end of select", sock != NULL);
2695       if (sock != NULL) {
2696         done_socket(sock);
2697       }
2698     }
2699   }
2700 }
2701 #else /* LWIP_NETCONN_FULLDUPLEX */
2702 #define lwip_select_inc_sockets_used(maxfdp1, readset, writeset, exceptset, used_sockets)
2703 #define lwip_select_dec_sockets_used(maxfdp1, used_sockets)
2704 #endif /* LWIP_NETCONN_FULLDUPLEX */
2705 
2706 int
lwip_select(int maxfdp1,fd_set * readset,fd_set * writeset,fd_set * exceptset,struct timeval * timeout)2707 lwip_select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset,
2708             struct timeval *timeout)
2709 {
2710   u32_t waitres = 0;
2711   int nready;
2712   fd_set lreadset, lwriteset, lexceptset;
2713   u32_t msectimeout;
2714   u64_t msectimeout_temp = 0;
2715   int i;
2716   int maxfdp2;
2717 #if LWIP_NETCONN_SEM_PER_THREAD
2718   int waited = 0;
2719 #endif
2720 #if LWIP_NETCONN_FULLDUPLEX
2721   fd_set used_sockets;
2722 #endif
2723   SYS_ARCH_DECL_PROTECT(lev);
2724 
2725   LWIP_ERROR("lwip_select: invalid maxfdp1",
2726              (maxfdp1 > (int)LWIP_SOCKET_OFFSET) && (maxfdp1 <= (int)(LWIP_SOCKET_OFFSET + LWIP_CONFIG_NUM_SOCKETS)),
2727              set_errno(EINVAL); return -1);
2728 
2729   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select(%d, %p, %p, %p, tvsec=%"S32_F" tvusec=%"S32_F")\n",
2730                               maxfdp1, (void *)readset, (void *) writeset, (void *) exceptset,
2731                               timeout ? (s32_t)timeout->tv_sec : (s32_t) - 1,
2732                               timeout ? (s32_t)timeout->tv_usec : (s32_t) - 1));
2733   if (timeout != NULL) {
2734     /* avoid overflow of timeout duration with very large value of sec or usec */
2735     if ((timeout->tv_sec < 0) || (timeout->tv_usec < 0)) {
2736         LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select: Invalid value of timeout"));
2737         set_errno(EINVAL);
2738         return -1;
2739     }
2740 
2741     msectimeout_temp = ((u64_t)(unsigned long)timeout->tv_sec) * MS_PER_SECOND;
2742     if (msectimeout_temp > LWIP_MAX_SELECT_TIMEOUT_VAL_MSEC) {
2743       set_errno(EINVAL);
2744       return -1;
2745     }
2746 
2747     /* add 500us to round off to ms */
2748     if (((((u64_t)(unsigned long)timeout->tv_usec + (US_PER_MSECOND >> 1)) / US_PER_MSECOND) + msectimeout_temp) >
2749         LWIP_MAX_SELECT_TIMEOUT_VAL_MSEC) {
2750       set_errno(EINVAL);
2751       return -1;
2752     }
2753 
2754     msectimeout = (u32_t)(msectimeout_temp + (((unsigned long)timeout->tv_usec + 500) / US_PER_MSECOND));
2755     if (msectimeout == 0) {
2756       /* wait for atleast 1 ms */
2757       msectimeout = 1;
2758     }
2759   }
2760 
2761 #if LWIP_NETCONN_FULLDUPLEX
2762   nready = lwip_select_inc_sockets_used(maxfdp1, readset, writeset, exceptset, &used_sockets);
2763   if (nready != ERR_OK) {
2764     set_errno(EBADF);
2765     return -1;
2766   }
2767 #endif
2768 
2769   /* Go through each socket in each list to count number of sockets which
2770      currently match */
2771   nready = lwip_selscan(maxfdp1, readset, writeset, exceptset, &lreadset, &lwriteset, &lexceptset);
2772 
2773   if (nready < 0) {
2774     /* one of the sockets in one of the fd_sets was invalid */
2775     set_errno(EBADF);
2776     lwip_select_dec_sockets_used(maxfdp1, &used_sockets);
2777     return -1;
2778   } else if (nready > 0) {
2779     /* one or more sockets are set, no need to wait */
2780     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select: nready=%d\n", nready));
2781   } else {
2782     /* If we don't have any current events, then suspend if we are supposed to */
2783     if (timeout && timeout->tv_sec == 0 && timeout->tv_usec == 0) {
2784       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select: no timeout, returning 0\n"));
2785       /* This is OK as the local fdsets are empty and nready is zero,
2786          or we would have returned earlier. */
2787     } else {
2788       /* None ready: add our semaphore to list:
2789          We don't actually need any dynamic memory. Our entry on the
2790          list is only valid while we are in this function, so it's ok
2791          to use local variables (unless we're running in MPU compatible
2792          mode). */
2793       API_SELECT_CB_VAR_DECLARE(select_cb);
2794       API_SELECT_CB_VAR_ALLOC(select_cb, set_errno(ENOMEM); lwip_select_dec_sockets_used(maxfdp1, &used_sockets); return -1);
2795       memset(&API_SELECT_CB_VAR_REF(select_cb), 0, sizeof(struct lwip_select_cb));
2796 
2797       API_SELECT_CB_VAR_REF(select_cb).readset = readset;
2798       API_SELECT_CB_VAR_REF(select_cb).writeset = writeset;
2799       API_SELECT_CB_VAR_REF(select_cb).exceptset = exceptset;
2800 #if LWIP_NETCONN_SEM_PER_THREAD
2801       API_SELECT_CB_VAR_REF(select_cb).sem = LWIP_NETCONN_THREAD_SEM_GET();
2802 #else /* LWIP_NETCONN_SEM_PER_THREAD */
2803       if (sys_sem_new(&API_SELECT_CB_VAR_REF(select_cb).sem, 0) != ERR_OK) {
2804         /* failed to create semaphore */
2805         set_errno(ENOMEM);
2806         lwip_select_dec_sockets_used(maxfdp1, &used_sockets);
2807         API_SELECT_CB_VAR_FREE(select_cb);
2808         return -1;
2809       }
2810 #endif /* LWIP_NETCONN_SEM_PER_THREAD */
2811 
2812       lwip_link_select_cb(&API_SELECT_CB_VAR_REF(select_cb));
2813 
2814       /* Increase select_waiting for each socket we are interested in */
2815       maxfdp2 = maxfdp1;
2816       for (i = LWIP_SOCKET_OFFSET; i < maxfdp1; i++) {
2817         if ((readset && FD_ISSET(i, readset)) ||
2818             (writeset && FD_ISSET(i, writeset)) ||
2819             (exceptset && FD_ISSET(i, exceptset))) {
2820           struct lwip_sock *sock;
2821           SYS_ARCH_PROTECT(lev);
2822           sock = tryget_socket_unconn_locked(i);
2823           if (sock != NULL) {
2824             sock->select_waiting++;
2825             if (sock->select_waiting == 0) {
2826               /* overflow - too many threads waiting */
2827               sock->select_waiting--;
2828               nready = -1;
2829               maxfdp2 = i;
2830               SYS_ARCH_UNPROTECT(lev);
2831               done_socket(sock);
2832               set_errno(EBUSY);
2833               break;
2834             }
2835             SYS_ARCH_UNPROTECT(lev);
2836             done_socket(sock);
2837           } else {
2838             /* Not a valid socket */
2839             nready = -1;
2840             maxfdp2 = i;
2841             SYS_ARCH_UNPROTECT(lev);
2842             set_errno(EBADF);
2843             break;
2844           }
2845         }
2846       }
2847 
2848       if (nready >= 0) {
2849         /* Call lwip_selscan again: there could have been events between
2850            the last scan (without us on the list) and putting us on the list! */
2851         nready = lwip_selscan(maxfdp1, readset, writeset, exceptset, &lreadset, &lwriteset, &lexceptset);
2852         if (nready < 0) {
2853           set_errno(EBADF);
2854         } else if (!nready) {
2855           /* Still none ready, just wait to be woken */
2856           if (timeout == 0) {
2857             /* Wait forever */
2858             msectimeout = 0;
2859           } else {
2860             long msecs_long = ((timeout->tv_sec * 1000) + ((timeout->tv_usec + 500) / 1000));
2861             if (msecs_long <= 0) {
2862               /* Wait 1ms at least (0 means wait forever) */
2863               msectimeout = 1;
2864             } else {
2865               msectimeout = (u32_t)msecs_long;
2866             }
2867           }
2868 
2869           waitres = sys_arch_sem_wait(SELECT_SEM_PTR(API_SELECT_CB_VAR_REF(select_cb).sem), msectimeout);
2870 #if LWIP_NETCONN_SEM_PER_THREAD
2871           waited = 1;
2872 #endif
2873         }
2874       }
2875 
2876       /* Decrease select_waiting for each socket we are interested in */
2877       for (i = LWIP_SOCKET_OFFSET; i < maxfdp2; i++) {
2878         if ((readset && FD_ISSET(i, readset)) ||
2879             (writeset && FD_ISSET(i, writeset)) ||
2880             (exceptset && FD_ISSET(i, exceptset))) {
2881           struct lwip_sock *sock;
2882           SYS_ARCH_PROTECT(lev);
2883           sock = tryget_socket_unconn_nouse(i);
2884           LWIP_ASSERT("socket gone at the end of select", sock != NULL);
2885           if (sock != NULL) {
2886             /* for now, handle select_waiting==0... */
2887             LWIP_ASSERT("sock->select_waiting > 0", sock->select_waiting > 0);
2888             if (sock->select_waiting > 0) {
2889               sock->select_waiting--;
2890             }
2891             SYS_ARCH_UNPROTECT(lev);
2892           } else {
2893             SYS_ARCH_UNPROTECT(lev);
2894             /* Not a valid socket */
2895             nready = -1;
2896             set_errno(EBADF);
2897           }
2898         }
2899       }
2900 
2901       lwip_unlink_select_cb(&API_SELECT_CB_VAR_REF(select_cb));
2902 
2903 #if LWIP_NETCONN_SEM_PER_THREAD
2904       if (API_SELECT_CB_VAR_REF(select_cb).sem_signalled && (!waited || (waitres == SYS_ARCH_TIMEOUT))) {
2905         /* don't leave the thread-local semaphore signalled */
2906         sys_arch_sem_wait(API_SELECT_CB_VAR_REF(select_cb).sem, 1);
2907       }
2908 #else /* LWIP_NETCONN_SEM_PER_THREAD */
2909       sys_sem_free(&API_SELECT_CB_VAR_REF(select_cb).sem);
2910 #endif /* LWIP_NETCONN_SEM_PER_THREAD */
2911       API_SELECT_CB_VAR_FREE(select_cb);
2912 
2913       if (nready < 0) {
2914         /* This happens when a socket got closed while waiting */
2915         lwip_select_dec_sockets_used(maxfdp1, &used_sockets);
2916         return -1;
2917       }
2918 
2919       if (waitres == SYS_ARCH_TIMEOUT) {
2920         /* Timeout */
2921         LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select: timeout expired\n"));
2922         /* This is OK as the local fdsets are empty and nready is zero,
2923            or we would have returned earlier. */
2924       } else {
2925         /* See what's set now after waiting */
2926         nready = lwip_selscan(maxfdp1, readset, writeset, exceptset, &lreadset, &lwriteset, &lexceptset);
2927         LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select: nready=%d\n", nready));
2928         if (nready < 0) {
2929           set_errno(EBADF);
2930           lwip_select_dec_sockets_used(maxfdp1, &used_sockets);
2931           return -1;
2932         }
2933       }
2934     }
2935   }
2936 
2937   lwip_select_dec_sockets_used(maxfdp1, &used_sockets);
2938   set_errno(0);
2939   if (readset) {
2940     *readset = lreadset;
2941   }
2942   if (writeset) {
2943     *writeset = lwriteset;
2944   }
2945   if (exceptset) {
2946     *exceptset = lexceptset;
2947   }
2948   return nready;
2949 }
2950 #endif /* LWIP_SOCKET_SELECT */
2951 
2952 #if LWIP_SOCKET_POLL
2953 #if LWIP_EXT_POLL_SUPPORT
lwip_poll(int sockfd,poll_table * wait)2954 int lwip_poll(int sockfd, poll_table *wait)
2955 {
2956   struct lwip_sock *sock = NULL;
2957   struct netconn *conn = NULL;
2958   pollevent_t mask = 0;
2959   pollevent_t ret;
2960 
2961   SYS_ARCH_DECL_PROTECT(lev);
2962   LWIP_ASSERT("wait!= NULL", wait != NULL);
2963 
2964   sock = get_socket(sockfd);
2965   if (sock == NULL) {
2966     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_poll: Invalid socket"));
2967     set_errno(EBADF);
2968     return -EBADF; /* compatible with file poll */
2969   }
2970 
2971   LOCK_TCPIP_CORE();
2972   SYS_ARCH_PROTECT(lev);
2973 
2974   conn = sock->conn;
2975 
2976   /* listen socket need special poll impl */
2977   if ((conn->type == SOCK_STREAM) && (conn->state == NETCONN_LISTEN)) {
2978     /* POLLIN if new connection establised by tcp stack */
2979     if (sock->rcvevent > 0) {
2980       mask |= POLLIN | POLLRDNORM;
2981       goto done;
2982     }
2983   }
2984 
2985   /* SHUTDOWN_MASK means both direction was closed due to some errors, eg. RST recved */
2986   if (conn->shutdown == SHUTDOWN_MASK) {
2987     mask |= POLLHUP | POLLIN | POLLRDNORM | POLLRDHUP | POLLOUT | POLLWRNORM;
2988   }
2989 
2990   /* FIN segment recved */
2991   if (conn->shutdown == RCV_SHUTDOWN) {
2992     mask |= POLLIN | POLLRDNORM | POLLRDHUP;
2993   }
2994 
2995   /* normal data readable, socket option SO_RCVLOWAT not support now */
2996   if ((sock->lastdata.pbuf != NULL) || (sock->rcvevent > 0)) {
2997     mask |= POLLIN | POLLRDNORM;
2998   }
2999 
3000   /* make socket writeable if any space usable */
3001   if ((conn->shutdown == SND_SHUTDOWN) || (sock->sendevent != 0)) {
3002     mask |= POLLOUT | POLLWRNORM;
3003   }
3004 
3005   if (sock->errevent != 0) {
3006     mask |= POLLERR;
3007   }
3008 
3009 done:
3010   ret = mask & wait->key;
3011   if (!ret) {
3012     /* add socket to wait queue if no event got */
3013     poll_wait(NULL, &sock->wq, wait);
3014   }
3015   SYS_ARCH_UNPROTECT(lev);
3016   UNLOCK_TCPIP_CORE();
3017 
3018   done_socket(sock);
3019   return ret;
3020 }
3021 #else /* LWIP_EXT_POLL_SUPPORT */
3022 /** Options for the lwip_pollscan function. */
3023 enum lwip_pollscan_opts
3024 {
3025   /** Clear revents in each struct pollfd. */
3026   LWIP_POLLSCAN_CLEAR = 1,
3027 
3028   /** Increment select_waiting in each struct lwip_sock. */
3029   LWIP_POLLSCAN_INC_WAIT = 2,
3030 
3031   /** Decrement select_waiting in each struct lwip_sock. */
3032   LWIP_POLLSCAN_DEC_WAIT = 4
3033 };
3034 
3035 /**
3036  * Update revents in each struct pollfd.
3037  * Optionally update select_waiting in struct lwip_sock.
3038  *
3039  * @param fds          array of structures to update
3040  * @param nfds         number of structures in fds
3041  * @param opts         what to update and how
3042  * @return number of structures that have revents != 0
3043  */
3044 static int
lwip_pollscan(struct pollfd * fds,nfds_t nfds,enum lwip_pollscan_opts opts)3045 lwip_pollscan(struct pollfd *fds, nfds_t nfds, enum lwip_pollscan_opts opts)
3046 {
3047   int nready = 0;
3048   nfds_t fdi;
3049   struct lwip_sock *sock;
3050   SYS_ARCH_DECL_PROTECT(lev);
3051 
3052   /* Go through each struct pollfd in the array. */
3053   for (fdi = 0; fdi < nfds; fdi++) {
3054     if ((opts & LWIP_POLLSCAN_CLEAR) != 0) {
3055       fds[fdi].revents = 0;
3056     }
3057 
3058     /* Negative fd means the caller wants us to ignore this struct.
3059        POLLNVAL means we already detected that the fd is invalid;
3060        if another thread has since opened a new socket with that fd,
3061        we must not use that socket. */
3062     if (fds[fdi].fd >= 0 && (fds[fdi].revents & POLLNVAL) == 0) {
3063       /* First get the socket's status (protected)... */
3064       SYS_ARCH_PROTECT(lev);
3065       sock = tryget_socket_unconn_locked(fds[fdi].fd);
3066       if (sock != NULL) {
3067         void* lastdata = sock->lastdata.pbuf;
3068         s16_t rcvevent = sock->rcvevent;
3069         u16_t sendevent = sock->sendevent;
3070         u16_t errevent = sock->errevent;
3071 
3072         if ((opts & LWIP_POLLSCAN_INC_WAIT) != 0) {
3073           sock->select_waiting++;
3074           if (sock->select_waiting == 0) {
3075             /* overflow - too many threads waiting */
3076             sock->select_waiting--;
3077             nready = -1;
3078             SYS_ARCH_UNPROTECT(lev);
3079             done_socket(sock);
3080             break;
3081           }
3082         } else if ((opts & LWIP_POLLSCAN_DEC_WAIT) != 0) {
3083           /* for now, handle select_waiting==0... */
3084           LWIP_ASSERT("sock->select_waiting > 0", sock->select_waiting > 0);
3085           if (sock->select_waiting > 0) {
3086             sock->select_waiting--;
3087           }
3088         }
3089         SYS_ARCH_UNPROTECT(lev);
3090         done_socket(sock);
3091 
3092         /* ... then examine it: */
3093         /* See if netconn of this socket is ready for read */
3094         if ((fds[fdi].events & POLLIN) != 0 && ((lastdata != NULL) || (rcvevent > 0))) {
3095           fds[fdi].revents |= POLLIN;
3096           LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_pollscan: fd=%d ready for reading\n", fds[fdi].fd));
3097         }
3098         /* See if netconn of this socket is ready for write */
3099         if ((fds[fdi].events & POLLOUT) != 0 && (sendevent != 0)) {
3100           fds[fdi].revents |= POLLOUT;
3101           LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_pollscan: fd=%d ready for writing\n", fds[fdi].fd));
3102         }
3103         /* See if netconn of this socket had an error */
3104         if (errevent != 0) {
3105           /* POLLERR is output only. */
3106           fds[fdi].revents |= POLLERR;
3107           LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_pollscan: fd=%d ready for exception\n", fds[fdi].fd));
3108         }
3109       } else {
3110         /* Not a valid socket */
3111         SYS_ARCH_UNPROTECT(lev);
3112         /* POLLNVAL is output only. */
3113         fds[fdi].revents |= POLLNVAL;
3114         return -1;
3115       }
3116     }
3117 
3118     /* Will return the number of structures that have events,
3119        not the number of events. */
3120     if (fds[fdi].revents != 0) {
3121       nready++;
3122     }
3123   }
3124 
3125   LWIP_ASSERT("nready >= 0", nready >= 0);
3126   return nready;
3127 }
3128 
3129 #if LWIP_NETCONN_FULLDUPLEX
3130 /* Mark all sockets as used.
3131  *
3132  * All sockets are marked (and later unmarked), whether they are open or not.
3133  * This is OK as lwip_pollscan aborts select when non-open sockets are found.
3134  */
3135 static void
lwip_poll_inc_sockets_used(struct pollfd * fds,nfds_t nfds)3136 lwip_poll_inc_sockets_used(struct pollfd *fds, nfds_t nfds)
3137 {
3138   nfds_t fdi;
3139 
3140   if(fds) {
3141     /* Go through each struct pollfd in the array. */
3142     for (fdi = 0; fdi < nfds; fdi++) {
3143       /* Increase the reference counter */
3144       tryget_socket_unconn(fds[fdi].fd);
3145     }
3146   }
3147 }
3148 
3149 /* Let go all sockets that were marked as used when starting poll */
3150 static void
lwip_poll_dec_sockets_used(struct pollfd * fds,nfds_t nfds)3151 lwip_poll_dec_sockets_used(struct pollfd *fds, nfds_t nfds)
3152 {
3153   nfds_t fdi;
3154 
3155   if(fds) {
3156     /* Go through each struct pollfd in the array. */
3157     for (fdi = 0; fdi < nfds; fdi++) {
3158       struct lwip_sock *sock = tryget_socket_unconn_nouse(fds[fdi].fd);
3159       if (sock != NULL) {
3160         done_socket(sock);
3161       }
3162     }
3163   }
3164 }
3165 #else /* LWIP_NETCONN_FULLDUPLEX */
3166 #define lwip_poll_inc_sockets_used(fds, nfds)
3167 #define lwip_poll_dec_sockets_used(fds, nfds)
3168 #endif /* LWIP_NETCONN_FULLDUPLEX */
3169 
3170 int
lwip_poll(struct pollfd * fds,nfds_t nfds,int timeout)3171 lwip_poll(struct pollfd *fds, nfds_t nfds, int timeout)
3172 {
3173   u32_t waitres = 0;
3174   int nready;
3175   u32_t msectimeout;
3176 #if LWIP_NETCONN_SEM_PER_THREAD
3177   int waited = 0;
3178 #endif
3179 
3180   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_poll(%p, %d, %d)\n",
3181                   (void*)fds, (int)nfds, timeout));
3182   LWIP_ERROR("lwip_poll: invalid fds", ((fds != NULL && nfds > 0) || (fds == NULL && nfds == 0)),
3183              set_errno(EINVAL); return -1;);
3184 
3185   lwip_poll_inc_sockets_used(fds, nfds);
3186 
3187   /* Go through each struct pollfd to count number of structures
3188      which currently match */
3189   nready = lwip_pollscan(fds, nfds, LWIP_POLLSCAN_CLEAR);
3190 
3191   if (nready < 0) {
3192     lwip_poll_dec_sockets_used(fds, nfds);
3193     return -1;
3194   }
3195 
3196   /* If we don't have any current events, then suspend if we are supposed to */
3197   if (!nready) {
3198     API_SELECT_CB_VAR_DECLARE(select_cb);
3199 
3200     if (timeout == 0) {
3201       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_poll: no timeout, returning 0\n"));
3202       goto return_success;
3203     }
3204     API_SELECT_CB_VAR_ALLOC(select_cb, set_errno(EAGAIN); lwip_poll_dec_sockets_used(fds, nfds); return -1);
3205     memset(&API_SELECT_CB_VAR_REF(select_cb), 0, sizeof(struct lwip_select_cb));
3206 
3207     /* None ready: add our semaphore to list:
3208        We don't actually need any dynamic memory. Our entry on the
3209        list is only valid while we are in this function, so it's ok
3210        to use local variables. */
3211 
3212     API_SELECT_CB_VAR_REF(select_cb).poll_fds = fds;
3213     API_SELECT_CB_VAR_REF(select_cb).poll_nfds = nfds;
3214 #if LWIP_NETCONN_SEM_PER_THREAD
3215     API_SELECT_CB_VAR_REF(select_cb).sem = LWIP_NETCONN_THREAD_SEM_GET();
3216 #else /* LWIP_NETCONN_SEM_PER_THREAD */
3217     if (sys_sem_new(&API_SELECT_CB_VAR_REF(select_cb).sem, 0) != ERR_OK) {
3218       /* failed to create semaphore */
3219       set_errno(EAGAIN);
3220       lwip_poll_dec_sockets_used(fds, nfds);
3221       API_SELECT_CB_VAR_FREE(select_cb);
3222       return -1;
3223     }
3224 #endif /* LWIP_NETCONN_SEM_PER_THREAD */
3225 
3226     lwip_link_select_cb(&API_SELECT_CB_VAR_REF(select_cb));
3227 
3228     /* Increase select_waiting for each socket we are interested in.
3229        Also, check for events again: there could have been events between
3230        the last scan (without us on the list) and putting us on the list! */
3231     nready = lwip_pollscan(fds, nfds, LWIP_POLLSCAN_INC_WAIT);
3232 
3233     if (!nready) {
3234       /* Still none ready, just wait to be woken */
3235       if (timeout < 0) {
3236         /* Wait forever */
3237         msectimeout = 0;
3238       } else {
3239         /* timeout == 0 would have been handled earlier. */
3240         LWIP_ASSERT("timeout > 0", timeout > 0);
3241         msectimeout = timeout;
3242       }
3243       waitres = sys_arch_sem_wait(SELECT_SEM_PTR(API_SELECT_CB_VAR_REF(select_cb).sem), msectimeout);
3244 #if LWIP_NETCONN_SEM_PER_THREAD
3245       waited = 1;
3246 #endif
3247     }
3248 
3249     /* Decrease select_waiting for each socket we are interested in,
3250        and check which events occurred while we waited. */
3251     nready = lwip_pollscan(fds, nfds, LWIP_POLLSCAN_DEC_WAIT);
3252 
3253     lwip_unlink_select_cb(&API_SELECT_CB_VAR_REF(select_cb));
3254 
3255 #if LWIP_NETCONN_SEM_PER_THREAD
3256     if (select_cb.sem_signalled && (!waited || (waitres == SYS_ARCH_TIMEOUT))) {
3257       /* don't leave the thread-local semaphore signalled */
3258       sys_arch_sem_wait(API_SELECT_CB_VAR_REF(select_cb).sem, 1);
3259     }
3260 #else /* LWIP_NETCONN_SEM_PER_THREAD */
3261     sys_sem_free(&API_SELECT_CB_VAR_REF(select_cb).sem);
3262 #endif /* LWIP_NETCONN_SEM_PER_THREAD */
3263     API_SELECT_CB_VAR_FREE(select_cb);
3264 
3265     if (nready < 0) {
3266       /* This happens when a socket got closed while waiting */
3267       lwip_poll_dec_sockets_used(fds, nfds);
3268       return -1;
3269     }
3270 
3271     if (waitres == SYS_ARCH_TIMEOUT) {
3272       /* Timeout */
3273       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_poll: timeout expired\n"));
3274       goto return_success;
3275     }
3276   }
3277 
3278   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_poll: nready=%d\n", nready));
3279 return_success:
3280   lwip_poll_dec_sockets_used(fds, nfds);
3281   set_errno(0);
3282   return nready;
3283 }
3284 
3285 /**
3286  * Check whether event_callback should wake up a thread waiting in
3287  * lwip_poll.
3288  */
3289 static int
lwip_poll_should_wake(const struct lwip_select_cb * scb,int fd,int has_recvevent,int has_sendevent,int has_errevent)3290 lwip_poll_should_wake(const struct lwip_select_cb *scb, int fd, int has_recvevent, int has_sendevent, int has_errevent)
3291 {
3292   nfds_t fdi;
3293   for (fdi = 0; fdi < scb->poll_nfds; fdi++) {
3294     const struct pollfd *pollfd = &scb->poll_fds[fdi];
3295     if (pollfd->fd == fd) {
3296       /* Do not update pollfd->revents right here;
3297          that would be a data race because lwip_pollscan
3298          accesses revents without protecting. */
3299       if (has_recvevent && (pollfd->events & POLLIN) != 0) {
3300         return 1;
3301       }
3302       if (has_sendevent && (pollfd->events & POLLOUT) != 0) {
3303         return 1;
3304       }
3305       if (has_errevent) {
3306         /* POLLERR is output only. */
3307         return 1;
3308       }
3309     }
3310   }
3311   return 0;
3312 }
3313 #endif /* LWIP_EXT_POLL_SUPPORT */
3314 #endif /* LWIP_SOCKET_POLL */
3315 
3316 #if LWIP_SOCKET_SELECT || LWIP_SOCKET_POLL
3317 /**
3318  * Callback registered in the netconn layer for each socket-netconn.
3319  * Processes recvevent (data available) and wakes up tasks waiting for select.
3320  *
3321  * @note for LWIP_TCPIP_CORE_LOCKING any caller of this function
3322  * must have the core lock held when signaling the following events
3323  * as they might cause select_list_cb to be checked:
3324  *   NETCONN_EVT_RCVPLUS
3325  *   NETCONN_EVT_SENDPLUS
3326  *   NETCONN_EVT_ERROR
3327  * This requirement will be asserted in select_check_waiters()
3328  */
3329 static void
event_callback(struct netconn * conn,enum netconn_evt evt,u16_t len)3330 event_callback(struct netconn *conn, enum netconn_evt evt, u16_t len)
3331 {
3332   int s, check_waiters;
3333   struct lwip_sock *sock;
3334   SYS_ARCH_DECL_PROTECT(lev);
3335 #if LWIP_EXT_POLL_SUPPORT
3336   unsigned int mask = 0;
3337 #endif
3338   LWIP_UNUSED_ARG(len);
3339 
3340   /* Get socket */
3341   if (conn) {
3342     s = conn->socket;
3343     if (s < 0) {
3344       /* Data comes in right away after an accept, even though
3345        * the server task might not have created a new socket yet.
3346        * Just count down (or up) if that's the case and we
3347        * will use the data later. Note that only receive events
3348        * can happen before the new socket is set up. */
3349       SYS_ARCH_PROTECT(lev);
3350       if (conn->socket < 0) {
3351         if (evt == NETCONN_EVT_RCVPLUS) {
3352           /* conn->socket is -1 on initialization
3353              lwip_accept adjusts sock->recvevent if conn->socket < -1 */
3354           conn->socket--;
3355         }
3356         SYS_ARCH_UNPROTECT(lev);
3357         return;
3358       }
3359       s = conn->socket;
3360       SYS_ARCH_UNPROTECT(lev);
3361     }
3362 
3363     sock = tryget_socket_unconn_nouse(s);
3364     if (!sock) {
3365       return;
3366     }
3367   } else {
3368     return;
3369   }
3370 
3371   check_waiters = 1;
3372   SYS_ARCH_PROTECT(lev);
3373   /* Set event as required */
3374   switch (evt) {
3375     case NETCONN_EVT_RCVPLUS:
3376       sock->rcvevent++;
3377       if (sock->rcvevent > 1) {
3378         check_waiters = 0;
3379       }
3380       break;
3381     case NETCONN_EVT_RCVMINUS:
3382       sock->rcvevent--;
3383       check_waiters = 0;
3384       break;
3385     case NETCONN_EVT_SENDPLUS:
3386       if (sock->sendevent) {
3387         check_waiters = 0;
3388       }
3389       sock->sendevent = 1;
3390       break;
3391     case NETCONN_EVT_SENDMINUS:
3392       sock->sendevent = 0;
3393       check_waiters = 0;
3394       break;
3395     case NETCONN_EVT_ERROR:
3396       sock->errevent = 1;
3397       break;
3398     default:
3399       LWIP_ASSERT("unknown event", 0);
3400       break;
3401   }
3402 
3403 #if LWIP_EXT_POLL_SUPPORT
3404   /* check shutdown mask firstly */
3405   switch (conn->shutdown) {
3406     case SHUTDOWN_MASK:
3407       mask |= POLLHUP | POLLIN | POLLRDNORM | POLLRDHUP | POLLOUT | POLLWRNORM;
3408       break;
3409     case RCV_SHUTDOWN:
3410       mask |= POLLIN | POLLRDNORM | POLLRDHUP;
3411       break;
3412     case SND_SHUTDOWN:
3413       mask |= POLLOUT | POLLWRNORM;
3414       break;
3415     default:
3416       mask = 0;
3417   }
3418 
3419   /* wakeup poll task if any data readable, for both listen socket and connected socket */
3420   if (sock->rcvevent > 0) {
3421     mask |= (POLLIN | POLLPRI | POLLRDNORM | POLLRDBAND);
3422   }
3423 
3424   if (sock->sendevent != 0) {
3425     mask |= (POLLOUT | POLLWRNORM | POLLWRBAND);
3426   }
3427 
3428   if (sock->errevent != 0) {
3429     mask |= POLLERR;
3430   }
3431 
3432 #if LWIP_LITEOS_COMPAT
3433   /* try to wakeup the pending task if any */
3434   if (mask && !LOS_ListEmpty(&(sock->wq.poll_queue))) {
3435     wake_up_interruptible_poll(&sock->wq, mask);
3436   }
3437 #endif /* LWIP_LITEOS_COMPAT */
3438 #endif
3439 
3440   if (sock->select_waiting && check_waiters) {
3441     /* Save which events are active */
3442     int has_recvevent, has_sendevent, has_errevent;
3443     has_recvevent = sock->rcvevent > 0;
3444     has_sendevent = sock->sendevent != 0;
3445     has_errevent = sock->errevent != 0;
3446     SYS_ARCH_UNPROTECT(lev);
3447     /* Check any select calls waiting on this socket */
3448     select_check_waiters(s, has_recvevent, has_sendevent, has_errevent);
3449   } else {
3450     SYS_ARCH_UNPROTECT(lev);
3451   }
3452 }
3453 
3454 /**
3455  * Check if any select waiters are waiting on this socket and its events
3456  *
3457  * @note on synchronization of select_cb_list:
3458  * LWIP_TCPIP_CORE_LOCKING: the select_cb_list must only be accessed while holding
3459  * the core lock. We do a single pass through the list and signal any waiters.
3460  * Core lock should already be held when calling here!!!!
3461 
3462  * !LWIP_TCPIP_CORE_LOCKING: we use SYS_ARCH_PROTECT but unlock on each iteration
3463  * of the loop, thus creating a possibility where a thread could modify the
3464  * select_cb_list during our UNPROTECT/PROTECT. We use a generational counter to
3465  * detect this change and restart the list walk. The list is expected to be small
3466  */
select_check_waiters(int s,int has_recvevent,int has_sendevent,int has_errevent)3467 static void select_check_waiters(int s, int has_recvevent, int has_sendevent, int has_errevent)
3468 {
3469   struct lwip_select_cb *scb;
3470 #if !LWIP_TCPIP_CORE_LOCKING
3471   int last_select_cb_ctr;
3472   SYS_ARCH_DECL_PROTECT(lev);
3473 #endif /* !LWIP_TCPIP_CORE_LOCKING */
3474 
3475   LWIP_ASSERT_CORE_LOCKED();
3476 
3477 #if !LWIP_TCPIP_CORE_LOCKING
3478   SYS_ARCH_PROTECT(lev);
3479 again:
3480   /* remember the state of select_cb_list to detect changes */
3481   last_select_cb_ctr = select_cb_ctr;
3482 #endif /* !LWIP_TCPIP_CORE_LOCKING */
3483   for (scb = select_cb_list; scb != NULL; scb = scb->next) {
3484     if (scb->sem_signalled == 0) {
3485       /* semaphore not signalled yet */
3486       int do_signal = 0;
3487 #if LWIP_SOCKET_POLL && !LWIP_EXT_POLL_SUPPORT
3488       if (scb->poll_fds != NULL) {
3489         do_signal = lwip_poll_should_wake(scb, s, has_recvevent, has_sendevent, has_errevent);
3490       }
3491 #endif /* LWIP_SOCKET_POLL */
3492 #if LWIP_SOCKET_SELECT && LWIP_SOCKET_POLL && !LWIP_EXT_POLL_SUPPORT
3493       else
3494 #endif /* LWIP_SOCKET_SELECT && LWIP_SOCKET_POLL */
3495 #if LWIP_SOCKET_SELECT
3496       {
3497         /* Test this select call for our socket */
3498         if (has_recvevent) {
3499           if (scb->readset && FD_ISSET(s, scb->readset)) {
3500             do_signal = 1;
3501           }
3502         }
3503         if (has_sendevent) {
3504           if (!do_signal && scb->writeset && FD_ISSET(s, scb->writeset)) {
3505             do_signal = 1;
3506           }
3507         }
3508         if (has_errevent) {
3509           if (!do_signal && scb->exceptset && FD_ISSET(s, scb->exceptset)) {
3510             do_signal = 1;
3511           }
3512         }
3513       }
3514 #endif /* LWIP_SOCKET_SELECT */
3515       if (do_signal) {
3516         scb->sem_signalled = 1;
3517         /* For !LWIP_TCPIP_CORE_LOCKING, we don't call SYS_ARCH_UNPROTECT() before signaling
3518            the semaphore, as this might lead to the select thread taking itself off the list,
3519            invalidating the semaphore. */
3520         sys_sem_signal(SELECT_SEM_PTR(scb->sem));
3521       }
3522     }
3523 #if LWIP_TCPIP_CORE_LOCKING
3524   }
3525 #else
3526     /* unlock interrupts with each step */
3527     SYS_ARCH_UNPROTECT(lev);
3528     /* this makes sure interrupt protection time is short */
3529     SYS_ARCH_PROTECT(lev);
3530     if (last_select_cb_ctr != select_cb_ctr) {
3531       /* someone has changed select_cb_list, restart at the beginning */
3532       goto again;
3533     }
3534     /* remember the state of select_cb_list to detect changes */
3535     last_select_cb_ctr = select_cb_ctr;
3536   }
3537   SYS_ARCH_UNPROTECT(lev);
3538 #endif
3539 }
3540 #endif /* LWIP_SOCKET_SELECT || LWIP_SOCKET_POLL */
3541 
3542 /**
3543  * Close one end of a full-duplex connection.
3544  */
3545 int
lwip_shutdown(int s,int how)3546 lwip_shutdown(int s, int how)
3547 {
3548   struct lwip_sock *sock;
3549   err_t err;
3550   u8_t shut_rx = 0, shut_tx = 0;
3551 
3552   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_shutdown(%d, how=%d)\n", s, how));
3553 
3554   sock = get_socket(s);
3555   if (!sock) {
3556     return -1;
3557   }
3558 
3559   if (sock->conn != NULL) {
3560     if (NETCONNTYPE_GROUP(NETCONN_TYPE(sock->conn)) != NETCONN_TCP) {
3561       sock_set_errno(sock, ENOTCONN);
3562       done_socket(sock);
3563       return -1;
3564     }
3565   } else {
3566     sock_set_errno(sock, ENOTCONN);
3567     done_socket(sock);
3568     return -1;
3569   }
3570 
3571   if (how == SHUT_RD) {
3572     shut_rx = 1;
3573   } else if (how == SHUT_WR) {
3574     shut_tx = 1;
3575   } else if (how == SHUT_RDWR) {
3576     shut_rx = 1;
3577     shut_tx = 1;
3578   } else {
3579     sock_set_errno(sock, EINVAL);
3580     done_socket(sock);
3581     return -1;
3582   }
3583   err = netconn_shutdown(sock->conn, shut_rx, shut_tx);
3584   if (err != ERR_OK) {
3585     sock_set_errno(sock, err_to_errno(err));
3586   }
3587   done_socket(sock);
3588   return (err == ERR_OK ? 0 : -1);
3589 }
3590 
3591 static int
lwip_getaddrname(int s,struct sockaddr * name,socklen_t * namelen,u8_t local)3592 lwip_getaddrname(int s, struct sockaddr *name, socklen_t *namelen, u8_t local)
3593 {
3594   struct lwip_sock *sock;
3595   union sockaddr_aligned saddr;
3596   ip_addr_t naddr;
3597   u16_t port;
3598   err_t err;
3599   socklen_t sa_len;
3600 
3601 #if PF_PKT_SUPPORT
3602   struct sockaddr_ll addr_sin;
3603   struct pf_pkt_ll ll;
3604   socklen_t outlen;
3605 #endif
3606 
3607   LWIP_ERROR("lwip_getaddrname: invalid arguments", ((name != NULL) && (namelen != NULL)),
3608              set_errno(EINVAL); return -1);
3609 
3610   sock = get_socket(s);
3611   if (!sock) {
3612     return -1;
3613   }
3614 
3615 #if PF_PKT_SUPPORT
3616   if (NETCONNTYPE_GROUP(NETCONN_TYPE(sock->conn)) == NETCONN_PKT_RAW) {
3617     err = netconn_getaddr_pfpkt(sock->conn, &ll, local);
3618     if (err != ERR_OK) {
3619       sock_set_errno(sock, err_to_errno(err));
3620       done_socket(sock);
3621       return -1;
3622     }
3623 
3624     (void)memset_s(&addr_sin, sizeof(struct sockaddr_ll), 0, sizeof(struct sockaddr_ll));
3625     addr_sin.sll_family = PF_PACKET;
3626     addr_sin.sll_protocol = ll.sll_protocol;
3627     addr_sin.sll_pkttype = 0;
3628     addr_sin.sll_ifindex = ll.if_idx;
3629     addr_sin.sll_hatype = ll.sll_hatype;
3630     addr_sin.sll_halen = ll.sll_halen;
3631 
3632     if ((ll.sll_halen > 0) && (memcpy_s(addr_sin.sll_addr, addr_sin.sll_halen, ll.sll_addr, ll.sll_halen) != EOK)) {
3633       sock_set_errno(sock, err_to_errno(ERR_MEM));
3634       done_socket(sock);
3635       return -1;
3636     }
3637 
3638     outlen = sizeof(struct sockaddr_ll);
3639     if (outlen > *namelen) {
3640       outlen = *namelen;
3641     }
3642     if (memcpy_s(name, *namelen, &addr_sin, outlen) != EOK) {
3643       sock_set_errno(sock, err_to_errno(ERR_MEM));
3644       done_socket(sock);
3645       return -1;
3646     }
3647     *namelen = outlen;
3648     done_socket(sock);
3649     return 0;
3650   }
3651 #endif /* PF_PKT_SUPPORT */
3652 
3653   /* get the IP address and port */
3654   err = netconn_getaddr(sock->conn, &naddr, &port, local);
3655   if (err != ERR_OK) {
3656     sock_set_errno(sock, err_to_errno(err));
3657     done_socket(sock);
3658     return -1;
3659   }
3660 
3661 #if LWIP_IPV4 && LWIP_IPV6
3662   /* Dual-stack: Map IPv4 addresses to IPv4 mapped IPv6 */
3663   if (NETCONNTYPE_ISIPV6(NETCONN_TYPE(sock->conn)) &&
3664       IP_IS_V4_VAL(naddr)) {
3665     ip4_2_ipv4_mapped_ipv6(ip_2_ip6(&naddr), ip_2_ip4(&naddr));
3666     IP_SET_TYPE_VAL(naddr, IPADDR_TYPE_V6);
3667   }
3668 #endif /* LWIP_IPV4 && LWIP_IPV6 */
3669 
3670   IPADDR_PORT_TO_SOCKADDR(&saddr, &naddr, port);
3671 
3672   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getaddrname(%d, addr=", s));
3673   ip_addr_debug_print_val(SOCKETS_DEBUG, naddr);
3674   LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F")\n", port));
3675   if (IP_IS_V4_VAL(naddr)) {
3676     sa_len = sizeof(struct sockaddr_in);
3677   } else {
3678     sa_len = sizeof(struct sockaddr_in6);
3679   }
3680 
3681   if (*namelen > sa_len) {
3682     *namelen = sa_len;
3683   }
3684   MEMCPY(name, &saddr, *namelen);
3685 
3686   sock_set_errno(sock, 0);
3687   done_socket(sock);
3688   return 0;
3689 }
3690 
3691 int
lwip_getpeername(int s,struct sockaddr * name,socklen_t * namelen)3692 lwip_getpeername(int s, struct sockaddr *name, socklen_t *namelen)
3693 {
3694   return lwip_getaddrname(s, name, namelen, 0);
3695 }
3696 
3697 int
lwip_getsockname(int s,struct sockaddr * name,socklen_t * namelen)3698 lwip_getsockname(int s, struct sockaddr *name, socklen_t *namelen)
3699 {
3700   return lwip_getaddrname(s, name, namelen, 1);
3701 }
3702 
3703 int
lwip_getsockopt(int s,int level,int optname,void * optval,socklen_t * optlen)3704 lwip_getsockopt(int s, int level, int optname, void *optval, socklen_t *optlen)
3705 {
3706   int err;
3707   struct lwip_sock *sock = get_socket(s);
3708 #if !LWIP_TCPIP_CORE_LOCKING
3709   err_t cberr;
3710   LWIP_SETGETSOCKOPT_DATA_VAR_DECLARE(data);
3711 #endif /* !LWIP_TCPIP_CORE_LOCKING */
3712 
3713   if (!sock) {
3714     return -1;
3715   }
3716 
3717   if ((NULL == optval) || (NULL == optlen)) {
3718     sock_set_errno(sock, EFAULT);
3719     done_socket(sock);
3720     return -1;
3721   }
3722 
3723 #if PF_PKT_SUPPORT
3724   VALIDATE_LEVEL_PF_PACKET(sock, level) {
3725     sock_set_errno(sock, EINVAL);
3726     done_socket(sock);
3727     return -1;
3728   }
3729 #endif /* PF_PKT_SUPPORT  */
3730 
3731 #if LWIP_TCPIP_CORE_LOCKING
3732   /* core-locking can just call the -impl function */
3733   LOCK_TCPIP_CORE();
3734   err = lwip_getsockopt_impl(s, level, optname, optval, optlen);
3735   UNLOCK_TCPIP_CORE();
3736 
3737 #else /* LWIP_TCPIP_CORE_LOCKING */
3738 
3739 #if LWIP_MPU_COMPATIBLE
3740   /* MPU_COMPATIBLE copies the optval data, so check for max size here */
3741   if (*optlen > LWIP_SETGETSOCKOPT_MAXOPTLEN) {
3742     sock_set_errno(sock, ENOBUFS);
3743     done_socket(sock);
3744     return -1;
3745   }
3746 #endif /* LWIP_MPU_COMPATIBLE */
3747 
3748   LWIP_SETGETSOCKOPT_DATA_VAR_ALLOC(data, sock);
3749   LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).s = s;
3750   LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).level = level;
3751   LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optname = optname;
3752   LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optlen = *optlen;
3753 #if !LWIP_MPU_COMPATIBLE
3754   LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optval.p = optval;
3755 #endif /* !LWIP_MPU_COMPATIBLE */
3756   LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).err = 0;
3757 #if LWIP_NETCONN_SEM_PER_THREAD
3758   LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).completed_sem = LWIP_NETCONN_THREAD_SEM_GET();
3759 #else
3760   LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).completed_sem = &sock->conn->op_completed;
3761 #endif
3762   cberr = tcpip_callback(lwip_getsockopt_callback, &LWIP_SETGETSOCKOPT_DATA_VAR_REF(data));
3763   if (cberr != ERR_OK) {
3764     LWIP_SETGETSOCKOPT_DATA_VAR_FREE(data);
3765     sock_set_errno(sock, err_to_errno(cberr));
3766     done_socket(sock);
3767     return -1;
3768   }
3769   sys_arch_sem_wait((sys_sem_t *)(LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).completed_sem), 0);
3770 
3771   /* write back optlen and optval */
3772   *optlen = LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optlen;
3773 #if LWIP_MPU_COMPATIBLE
3774   MEMCPY(optval, LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optval,
3775          LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optlen);
3776 #endif /* LWIP_MPU_COMPATIBLE */
3777 
3778   /* maybe lwip_getsockopt_internal has changed err */
3779   err = LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).err;
3780   LWIP_SETGETSOCKOPT_DATA_VAR_FREE(data);
3781 #endif /* LWIP_TCPIP_CORE_LOCKING */
3782   if (err != ERR_OK) {
3783     sock_set_errno(sock, err);
3784   }
3785   done_socket(sock);
3786   return err ? -1 : 0;
3787 }
3788 
3789 #if !LWIP_TCPIP_CORE_LOCKING
3790 /** lwip_getsockopt_callback: only used without CORE_LOCKING
3791  * to get into the tcpip_thread
3792  */
3793 static void
lwip_getsockopt_callback(void * arg)3794 lwip_getsockopt_callback(void *arg)
3795 {
3796   struct lwip_setgetsockopt_data *data;
3797   LWIP_ASSERT("arg != NULL", arg != NULL);
3798   data = (struct lwip_setgetsockopt_data *)arg;
3799 
3800   data->err = lwip_getsockopt_impl(data->s, data->level, data->optname,
3801 #if LWIP_MPU_COMPATIBLE
3802                                    data->optval,
3803 #else /* LWIP_MPU_COMPATIBLE */
3804                                    data->optval.p,
3805 #endif /* LWIP_MPU_COMPATIBLE */
3806                                    &data->optlen);
3807 
3808   sys_sem_signal((sys_sem_t *)(data->completed_sem));
3809 }
3810 #endif  /* LWIP_TCPIP_CORE_LOCKING */
3811 
3812 static int
lwip_sockopt_to_ipopt(int optname)3813 lwip_sockopt_to_ipopt(int optname)
3814 {
3815   /* Map SO_* values to our internal SOF_* values
3816    * We should not rely on #defines in socket.h
3817    * being in sync with ip.h.
3818    */
3819   switch (optname) {
3820   case SO_BROADCAST:
3821     return SOF_BROADCAST;
3822   case SO_KEEPALIVE:
3823     return SOF_KEEPALIVE;
3824   case SO_REUSEADDR:
3825     return SOF_REUSEADDR;
3826   case SO_DONTROUTE:
3827     return SOF_DONTROUTE;
3828   default:
3829     LWIP_ASSERT("Unknown socket option", 0);
3830     return 0;
3831   }
3832 }
3833 
3834 /** lwip_sockopt_getval: update optval and optlen.follow linux getsockopt behavior!
3835  * warning: this function is only suit for getting u8_t type socket options.
3836  */
3837 static inline void
lwip_sockopt_getval(void * outval,socklen_t * outlen,const u8_t * inval)3838 lwip_sockopt_getval(void *outval, socklen_t *outlen, const u8_t *inval)
3839 {
3840   u32_t len = (*outlen < sizeof(u32_t)) ? sizeof(u8_t) : sizeof(u32_t);
3841   u32_t val = *(const u8_t *)inval;
3842   (void)memcpy_s(outval, len, &val, len);
3843   *outlen = len;
3844 }
3845 
3846 /** lwip_getsockopt_impl: the actual implementation of getsockopt:
3847  * same argument as lwip_getsockopt, either called directly or through callback
3848  */
3849 static int
lwip_getsockopt_impl(int s,int level,int optname,void * optval,socklen_t * optlen)3850 lwip_getsockopt_impl(int s, int level, int optname, void *optval, socklen_t *optlen)
3851 {
3852   int err = 0;
3853   struct lwip_sock *sock = tryget_socket(s);
3854   if (!sock) {
3855     return EBADF;
3856   }
3857 
3858 #ifdef LWIP_HOOK_SOCKETS_GETSOCKOPT
3859   if (LWIP_HOOK_SOCKETS_GETSOCKOPT(s, sock, level, optname, optval, optlen, &err)) {
3860     return err;
3861   }
3862 #endif
3863 
3864   switch (level) {
3865     /* Level: SOL_SOCKET */
3866     case SOL_SOCKET:
3867 #if PF_PKT_SUPPORT
3868     case SOL_PACKET:
3869       VALIDATE_GET_PF_PKT_OPTNAME_RET(s, sock, level, optname);
3870 #endif /* PF_PKT_SUPPORT  */
3871 
3872       VALIDATE_GET_RAW_OPTNAME_RET(sock, optname);
3873       switch (optname) {
3874     case SO_BINDTODEVICE:
3875       if ((*optlen < NETIF_NAMESIZE) || (sock->conn == NULL) || (sock->conn->pcb.ip == NULL)) {
3876         done_socket(sock);
3877         return EINVAL;
3878       }
3879       if (sock->conn->pcb.ip->netif_idx != NETIF_NO_INDEX) {
3880         struct netif *netif = netif_find_by_ifindex(sock->conn->pcb.ip->netif_idx);
3881         if (netif == NULL) {
3882           *(optlen) = 0;
3883           done_socket(sock);
3884           return ENODEV;
3885         } else {
3886           int len = snprintf_s((char *)optval, NETIF_NAMESIZE, NETIF_NAMESIZE - 1, "%s%hhu", netif->name, netif->num);
3887           if (len <= 0) {
3888             *(optlen) = 0;
3889             done_socket(sock);
3890             return ENOMEM;
3891           }
3892           *(optlen) = 1 + (socklen_t)len;
3893         }
3894       } else {
3895         *(optlen) = 0;
3896         done_socket(sock);
3897         return EINVAL;
3898       }
3899       break;
3900 #if LWIP_TCP
3901         case SO_ACCEPTCONN:
3902           LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, *optlen, int);
3903           if ((sock->conn != NULL) && NETCONNTYPE_GROUP(sock->conn->type) != NETCONN_TCP) {
3904             done_socket(sock);
3905             return ENOPROTOOPT;
3906           }
3907           if ((sock->conn->pcb.tcp != NULL) && (sock->conn->pcb.tcp->state == LISTEN)) {
3908             *(int *)optval = 1;
3909           } else {
3910             *(int *)optval = 0;
3911           }
3912           break;
3913 #endif /* LWIP_TCP */
3914 
3915         /* The option flags */
3916         case SO_BROADCAST:
3917 #if LWIP_SO_DONTROUTE
3918         case SO_DONTROUTE:
3919 #endif /* LWIP_SO_DONTROUTE */
3920         case SO_KEEPALIVE:
3921 #if SO_REUSE
3922         case SO_REUSEADDR:
3923 #endif /* SO_REUSE */
3924           if (sock->conn == NULL) {
3925             done_socket(sock);
3926             return EINVAL;
3927           }
3928           if ((optname == SO_BROADCAST) &&
3929               (NETCONNTYPE_GROUP(sock->conn->type) == NETCONN_TCP)) {
3930             done_socket(sock);
3931             return ENOPROTOOPT;
3932           }
3933 
3934           optname = lwip_sockopt_to_ipopt(optname);
3935 
3936           LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, *optlen, int);
3937           if (ip_get_option(sock->conn->pcb.ip, optname)) {
3938             *(int *)optval = 1;
3939           } else {
3940             *(int *)optval = 0;
3941           }
3942           LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, optname=0x%x, ..) = %s\n",
3943                                       s, optname, (*(int *)optval ? "on" : "off")));
3944           break;
3945 
3946         case SO_TYPE:
3947           LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, *optlen, int);
3948           switch (NETCONNTYPE_GROUP(NETCONN_TYPE(sock->conn))) {
3949 #if PF_PKT_SUPPORT
3950             case NETCONN_PKT_RAW:
3951 #endif
3952             case NETCONN_RAW:
3953               *(int *)optval = SOCK_RAW;
3954               break;
3955             case NETCONN_TCP:
3956               *(int *)optval = SOCK_STREAM;
3957               break;
3958             case NETCONN_UDP:
3959               *(int *)optval = SOCK_DGRAM;
3960               break;
3961             default: /* unrecognized socket type */
3962               *(int *)optval = NETCONN_TYPE(sock->conn);
3963 #if PF_PKT_SUPPORT
3964               LWIP_DEBUGF(SOCKETS_DEBUG,
3965                           ("lwip_getsockopt(%d, %s, SO_TYPE): unrecognized socket type %d\n",
3966                           s, (NETCONN_PKT_RAW != NETCONNTYPE_GROUP(sock->conn->type)) ? "SOL_SOCKET" : "SOL_PACKET",
3967                           *(int *)optval));
3968 #else
3969               LWIP_DEBUGF(SOCKETS_DEBUG,
3970                           ("lwip_getsockopt(%d, SOL_SOCKET, SO_TYPE): unrecognized socket type %d\n",
3971                            s, *(int *)optval));
3972 #endif
3973           }  /* switch (NETCONN_TYPE(sock->conn)) */
3974           LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, SO_TYPE) = %d\n",
3975                                       s, *(int *)optval));
3976           break;
3977 
3978         case SO_ERROR:
3979           LWIP_SOCKOPT_CHECK_OPTLEN(sock, *optlen, int);
3980           /* only overwrite ERR_OK or temporary errors */
3981           if (((atomic_read(&sock->err) == 0) || (atomic_read(&sock->err) == EINPROGRESS)) && (sock->conn != NULL)) {
3982             sock_set_errno(sock, err_to_errno(sock->conn->last_err));
3983           }
3984           *(int *)optval = (atomic_read(&sock->err) == 0xFF ? (int)-1 : (int)atomic_read(&sock->err));
3985           (void)atomic_set(&sock->err, 0);
3986           LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, SO_ERROR) = %d\n",
3987                                       s, *(int *)optval));
3988           break;
3989 #if LWIP_TCP && LWIP_SO_SNDBUF
3990         case SO_SNDBUF:
3991           LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, *optlen, int, NETCONN_TCP);
3992           *(u32_t *)optval = tcp_get_sendbufsize(sock->conn->pcb.tcp);
3993           break;
3994 #endif /* LWIP_SO_SNDBUF */
3995 #if LWIP_SO_SNDTIMEO
3996         case SO_SNDTIMEO:
3997           LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, *optlen, LWIP_SO_SNDRCVTIMEO_OPTTYPE);
3998           LWIP_SO_SNDRCVTIMEO_SET(optval, netconn_get_sendtimeout(sock->conn));
3999           break;
4000 #endif /* LWIP_SO_SNDTIMEO */
4001 #if LWIP_SO_RCVTIMEO
4002         case SO_RCVTIMEO:
4003           LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, *optlen, LWIP_SO_SNDRCVTIMEO_OPTTYPE);
4004           LWIP_SO_SNDRCVTIMEO_SET(optval, netconn_get_recvtimeout(sock->conn));
4005           break;
4006 #endif /* LWIP_SO_RCVTIMEO */
4007 #if LWIP_SO_RCVBUF
4008         case SO_RCVBUF:
4009           LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, *optlen, int);
4010           *(int *)optval = netconn_get_recvbufsize(sock->conn);
4011           break;
4012 #endif /* LWIP_SO_RCVBUF */
4013 #if LWIP_SO_LINGER
4014         case SO_LINGER: {
4015           s16_t conn_linger;
4016           struct linger *linger = (struct linger *)optval;
4017           LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, *optlen, struct linger);
4018           conn_linger = sock->conn->linger;
4019           if (conn_linger >= 0) {
4020             linger->l_onoff = 1;
4021             linger->l_linger = (int)conn_linger;
4022           } else {
4023             linger->l_onoff = 0;
4024             linger->l_linger = 0;
4025           }
4026         }
4027         break;
4028 #endif /* LWIP_SO_LINGER */
4029 #if LWIP_UDP
4030         case SO_NO_CHECK:
4031           LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, *optlen, int, NETCONN_UDP);
4032 #if LWIP_UDPLITE
4033           if (udp_is_flag_set(sock->conn->pcb.udp, UDP_FLAGS_UDPLITE)) {
4034             /* this flag is only available for UDP, not for UDP lite */
4035             done_socket(sock);
4036             return ENOPROTOOPT;
4037           }
4038 #endif /* LWIP_UDPLITE */
4039           *(int *)optval = udp_is_flag_set(sock->conn->pcb.udp, UDP_FLAGS_NOCHKSUM) ? 1 : 0;
4040           break;
4041 #endif /* LWIP_UDP */
4042 #if LWIP_SO_PRIORITY
4043         case SO_PRIORITY: {
4044           LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, *optlen, prio_t);
4045 
4046 #if LWIP_UDP
4047           if (NETCONNTYPE_GROUP(sock->conn->type) == NETCONN_UDP) {
4048             *(prio_t *)optval = sock->conn->pcb.udp->priority;
4049           } else
4050 #endif
4051 #if LWIP_TCP
4052           if (NETCONNTYPE_GROUP(sock->conn->type) == NETCONN_TCP) {
4053             *(prio_t *)optval = sock->conn->pcb.tcp->priority;
4054           } else
4055 #endif
4056 #if LWIP_RAW
4057           if (NETCONNTYPE_GROUP(sock->conn->type) == NETCONN_RAW) {
4058             *(prio_t *)optval = sock->conn->pcb.raw->priority;
4059           } else
4060 #endif
4061           {
4062             LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt Invalid socket type \n"));
4063             return ENOPROTOOPT;
4064           }
4065           break;
4066         }
4067 
4068 #endif /* LWIP_SO_PRIORITY */
4069 
4070         default:
4071           LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, UNIMPL: optname=0x%x, ..)\n",
4072                                       s, optname));
4073           err = ENOPROTOOPT;
4074           break;
4075       }  /* switch (optname) */
4076       break;
4077 
4078     /* Level: IPPROTO_IP */
4079     case IPPROTO_IP:
4080       switch (optname) {
4081         case IP_TTL:
4082           LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, *optlen, u8_t);
4083           lwip_sockopt_getval(optval, optlen, &sock->conn->pcb.ip->ttl);
4084           LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_TTL) = %u\n",
4085                                       s, *(u8_t *)optval));
4086           break;
4087         case IP_TOS:
4088           LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, *optlen, u8_t);
4089           lwip_sockopt_getval(optval, optlen, &sock->conn->pcb.ip->tos);
4090           LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_TOS) = %u\n",
4091                                       s, *(u8_t *)optval));
4092           break;
4093 #if LWIP_RAW
4094         case IP_HDRINCL: {
4095             u8_t raw_flag;
4096             LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, *optlen, u8_t, NETCONN_RAW);
4097             if (NETCONNTYPE_ISIPV6(sock->conn->type)) {
4098               done_socket(sock);
4099               return ENOPROTOOPT;
4100             }
4101 
4102             raw_flag = raw_is_flag_set(sock->conn->pcb.raw, RAW_FLAGS_HDRINCL);
4103             lwip_sockopt_getval(optval, optlen, &raw_flag);
4104             LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IP_HDRINCL) = %u\n",
4105                         s, *(u8_t *)optval));
4106           }
4107           break;
4108 #endif
4109 #if LWIP_IPV4 && LWIP_MULTICAST_TX_OPTIONS && LWIP_UDP
4110         case IP_MULTICAST_TTL: {
4111             u8_t ttl;
4112             LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, *optlen, u8_t);
4113             if (NETCONNTYPE_GROUP(NETCONN_TYPE(sock->conn)) != NETCONN_UDP) {
4114               done_socket(sock);
4115               return ENOPROTOOPT;
4116             }
4117             ttl = udp_get_multicast_ttl(sock->conn->pcb.udp);
4118             lwip_sockopt_getval(optval, optlen, &ttl);
4119             LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_MULTICAST_TTL) = %u\n",
4120                                         s, *(u8_t *)optval));
4121           }
4122           break;
4123         case IP_MULTICAST_IF:
4124           LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, *optlen, struct in_addr);
4125           if (NETCONNTYPE_GROUP(NETCONN_TYPE(sock->conn)) != NETCONN_UDP) {
4126             done_socket(sock);
4127             return ENOPROTOOPT;
4128           }
4129           inet_addr_from_ip4addr((struct in_addr *)optval, udp_get_multicast_netif_addr(sock->conn->pcb.udp));
4130           LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_MULTICAST_IF) = 0x%"X32_F"\n",
4131                                       s, *(u32_t *)optval));
4132           break;
4133         case IP_MULTICAST_LOOP:
4134           LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, *optlen, u8_t, NETCONN_UDP);
4135           if ((sock->conn->pcb.udp->flags & UDP_FLAGS_MULTICAST_LOOP) != 0) {
4136             *(u8_t *)optval = 1;
4137           } else {
4138             *(u8_t *)optval = 0;
4139           }
4140           LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_MULTICAST_LOOP) = %d\n",
4141                                       s, *(int *)optval));
4142           break;
4143 #endif /* LWIP_IPV4 && LWIP_MULTICAST_TX_OPTIONS && LWIP_UDP */
4144         default:
4145           LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, UNIMPL: optname=0x%x, ..)\n",
4146                                       s, optname));
4147           err = ENOPROTOOPT;
4148           break;
4149       }  /* switch (optname) */
4150       break;
4151 
4152 #if LWIP_TCP
4153     /* Level: IPPROTO_TCP */
4154     case IPPROTO_TCP:
4155 #if LWIP_TCP_INFO
4156       if (optname == TCP_INFO) {
4157         LWIP_SOCKOPT_CHECK_OPTLEN(sock, *optlen, struct tcp_info);
4158         if (sock->conn == NULL) {
4159           return EINVAL;
4160         }
4161 
4162         if (NETCONNTYPE_GROUP(NETCONN_TYPE((sock)->conn)) != NETCONN_TCP) {
4163           return ENOPROTOOPT;
4164         }
4165         if ((sock->conn == NULL) || (sock->conn->pcb.tcp == NULL)) {
4166           ((struct tcp_info *)optval)->tcpi_state = TCP_CLOSE;
4167           break;
4168         }
4169 
4170         tcp_get_info(sock->conn->pcb.tcp, (struct tcp_info *)optval);
4171         break;
4172       }
4173 #endif
4174       /* Special case: all IPPROTO_TCP option take an int */
4175       LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, *optlen, int, NETCONN_TCP);
4176       if ((sock->conn->pcb.tcp->state == LISTEN)
4177 #if LWIP_TCP_MAXSEG
4178           && (optname != TCP_MAXSEG)
4179 #endif /* LWIP_TCP_MAXSEG */
4180          ) {
4181         done_socket(sock);
4182         return EINVAL;
4183       }
4184       switch (optname) {
4185         case TCP_NODELAY:
4186           *(int *)optval = tcp_nagle_disabled(sock->conn->pcb.tcp);
4187           LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_TCP, TCP_NODELAY) = %s\n",
4188                                       s, (*(int *)optval) ? "on" : "off") );
4189           break;
4190 #if LWIP_TCP_KEEPALIVE
4191         case TCP_KEEPIDLE:
4192           *(int*)optval = (int)(sock->conn->pcb.tcp->keep_idle / MS_PER_SECOND);
4193           LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_TCP, TCP_KEEPIDLE) = %d\n",
4194                       s, *(int *)optval));
4195           break;
4196         case TCP_KEEPINTVL:
4197           *(int*)optval = (int)(sock->conn->pcb.tcp->keep_intvl / MS_PER_SECOND);
4198           LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_TCP, TCP_KEEPINTVL) = %d\n",
4199                       s, *(int *)optval));
4200           break;
4201         case TCP_KEEPCNT:
4202           *(int*)optval = (int)sock->conn->pcb.tcp->keep_cnt;
4203           LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_TCP, TCP_KEEPCNT) = %d\n",
4204                       s, *(int *)optval));
4205           break;
4206 #endif /* LWIP_TCP_KEEPALIVE */
4207 #if LWIP_SOCK_OPT_TCP_QUEUE_SEQ
4208         case TCP_QUEUE_SEQ:
4209           if (*(unsigned int*)optval == TCP_RECV_QUEUE) {
4210               *(unsigned int*)optval = sock->conn->pcb.tcp->rcv_nxt;
4211           } else if (*(int*)optval == TCP_SEND_QUEUE) {
4212               *(unsigned int*)optval = sock->conn->pcb.tcp->snd_nxt;
4213           } else {
4214             done_socket(sock);
4215             return EINVAL;
4216           }
4217           LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_TCP, TCP_QUEUE_SEQ) = %d\n",
4218                       s, *(int *)optval));
4219           break;
4220 #endif /* LWIP_SOCK_OPT_TCP_QUEUE_SEQ */
4221 #if LWIP_TCP_MAXSEG
4222         case TCP_MAXSEG:
4223           *(int*)optval = (int)sock->conn->pcb.tcp->usr_mss;
4224           LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_TCP, TCP_MAXSEG) = %d\n",
4225                       s, *(int *)optval));
4226           break;
4227 #endif /* LWIP_TCP_MAXSEG */
4228 
4229         default:
4230           LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_TCP, UNIMPL: optname=0x%x, ..)\n",
4231                                       s, optname));
4232           err = ENOPROTOOPT;
4233           break;
4234       }  /* switch (optname) */
4235       break;
4236 #endif /* LWIP_TCP */
4237 
4238 #if LWIP_IPV6
4239     /* Level: IPPROTO_IPV6 */
4240     case IPPROTO_IPV6:
4241       switch (optname) {
4242         case IPV6_V6ONLY:
4243           LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, *optlen, int);
4244           LWIP_SOCKOPT_CHECK_IPTYPE_V6(sock, sock->conn->type);
4245 
4246           *(int*)optval = (netconn_get_ipv6only(sock->conn) ? 1 : 0);
4247           LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IPV6, IPV6_V6ONLY) = %d\n",
4248                                       s, *(int *)optval));
4249           break;
4250 #if LWIP_IPV6 && LWIP_RAW
4251         case IPV6_CHECKSUM:
4252           LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE_IPV6(sock, *optlen, int, NETCONN_RAW);
4253           if (sock->conn->pcb.raw->chksum_reqd == 0) {
4254             *(int *)optval = -1;
4255           } else {
4256             *(int *)optval = sock->conn->pcb.raw->chksum_offset;
4257           }
4258           LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IPV6, IPV6_CHECKSUM) = %d\n",
4259                       s, (*(int*)optval)));
4260           break;
4261 #endif
4262 #if LWIP_SOCK_OPT_IPV6_UNICAST_HOPS
4263         case IPV6_UNICAST_HOPS:
4264           LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, *optlen, int);
4265           LWIP_SOCKOPT_CHECK_IPTYPE_V6(sock, sock->conn->type);
4266 
4267           *(int *)optval = (int)sock->conn->pcb.ip->ttl;
4268           LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IPV6, IPV6_UNICAST_HOPS) = %d\n",
4269                       s, *(int *)optval));
4270           break;
4271 #endif
4272 #if LWIP_MULTICAST_TX_OPTIONS
4273         case IPV6_MULTICAST_HOPS:
4274           LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE_IPV6(sock, *optlen, int, NETCONN_UDP);
4275 
4276           *(int *)optval = (int)udp_get_multicast_ttl(sock->conn->pcb.udp);
4277           LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IPV6, IPV6_MULTICAST_HOPS) = %d\n",
4278                       s, *(int *)optval));
4279           break;
4280         case IPV6_MULTICAST_IF:
4281           LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE_IPV6(sock, *optlen, u8_t, NETCONN_UDP);
4282           *(u8_t*)optval = udp_get_multicast_netif_index(sock->conn->pcb.udp);
4283           LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IPV6, IPV6_MULTICAST_IF) = %d\n",
4284                       s, *(u8_t *)optval));
4285           break;
4286         case IPV6_MULTICAST_LOOP:
4287           LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE_IPV6(sock, *optlen, u8_t, NETCONN_UDP);
4288           if ((sock->conn->pcb.udp->flags & UDP_FLAGS_MULTICAST_LOOP) != 0) {
4289             *(u8_t*)optval = 1;
4290           } else {
4291             *(u8_t*)optval = 0;
4292           }
4293           break;
4294 #endif /* LWIP_MULTICAST_TX_OPTIONS */
4295         default:
4296           LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IPV6, UNIMPL: optname=0x%x, ..)\n",
4297                                       s, optname));
4298           err = ENOPROTOOPT;
4299           break;
4300       }  /* switch (optname) */
4301       break;
4302 #endif /* LWIP_IPV6 */
4303 
4304 #if LWIP_UDP && LWIP_UDPLITE
4305     /* Level: IPPROTO_UDPLITE */
4306     case IPPROTO_UDPLITE:
4307       /* Special case: all IPPROTO_UDPLITE option take an int */
4308       LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, *optlen, int);
4309       /* If this is no UDP lite socket, ignore any options. */
4310       if (!NETCONNTYPE_ISUDPLITE(NETCONN_TYPE(sock->conn))) {
4311         done_socket(sock);
4312         return ENOPROTOOPT;
4313       }
4314       switch (optname) {
4315         case UDPLITE_SEND_CSCOV:
4316           *(int *)optval = sock->conn->pcb.udp->chksum_len_tx;
4317           LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_UDPLITE, UDPLITE_SEND_CSCOV) = %d\n",
4318                                       s, (*(int *)optval)) );
4319           break;
4320         case UDPLITE_RECV_CSCOV:
4321           *(int *)optval = sock->conn->pcb.udp->chksum_len_rx;
4322           LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_UDPLITE, UDPLITE_RECV_CSCOV) = %d\n",
4323                                       s, (*(int *)optval)) );
4324           break;
4325         default:
4326           LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_UDPLITE, UNIMPL: optname=0x%x, ..)\n",
4327                                       s, optname));
4328           err = ENOPROTOOPT;
4329           break;
4330       }  /* switch (optname) */
4331       break;
4332 #endif /* LWIP_UDP */
4333     /* Level: IPPROTO_RAW */
4334     case IPPROTO_RAW:
4335       switch (optname) {
4336 #if LWIP_IPV6 && LWIP_RAW
4337         case IPV6_CHECKSUM:
4338           LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE_IPV6(sock, *optlen, int, NETCONN_RAW);
4339           if (sock->conn->pcb.raw->chksum_reqd == 0) {
4340             *(int *)optval = -1;
4341           } else {
4342             *(int *)optval = sock->conn->pcb.raw->chksum_offset;
4343           }
4344           LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_RAW, IPV6_CHECKSUM) = %d\n",
4345                                       s, (*(int *)optval)) );
4346           break;
4347 #endif /* LWIP_IPV6 && LWIP_RAW */
4348         default:
4349           LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_RAW, UNIMPL: optname=0x%x, ..)\n",
4350                                       s, optname));
4351           err = ENOPROTOOPT;
4352           break;
4353       }  /* switch (optname) */
4354       break;
4355 
4356       /* [rfc2292 section3.2][12-06-2018][Start] */
4357       /* Below feature is enabled  only if ipv6 raw socket is enabled */
4358 #if LWIP_IPV6 && LWIP_RAW && LWIP_SOCK_OPT_ICMP6_FILTER
4359     case IPPROTO_ICMPV6:
4360       switch (optname) {
4361         case ICMP6_FILTER:
4362           LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE_IPV6(sock, *optlen, struct icmp6_filter, NETCONN_RAW);
4363           if (memcpy_s(optval, *optlen, &sock->conn->pcb.raw->icmp6_filter, sizeof(struct icmp6_filter)) != EOK) {
4364             err = ENOMEM;
4365           }
4366           break;
4367         default:
4368           LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_ICMPV6, UNIMPL: optname=0x%x, ..)\n",
4369                       s, optname));
4370           err = ENOPROTOOPT;
4371           break;
4372       }
4373       break;
4374 #endif /* LWIP_IPV6 && LWIP_RAW */
4375     default:
4376       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, level=0x%x, UNIMPL: optname=0x%x, ..)\n",
4377                                   s, level, optname));
4378       err = ENOPROTOOPT;
4379       break;
4380   } /* switch (level) */
4381 
4382   done_socket(sock);
4383   return err;
4384 }
4385 
4386 /**
4387     @page RFC-2553_RFC-3493 RFC-2553/3493
4388 
4389     @par Compliant Section
4390     Section 5.1 Unicast Hop Limit
4391     @par Behavior Description
4392     This option controls the hop limit used in outgoing unicast IPv6 packets.\n
4393     Stack allows the IPV6_UNICAST_HOPS value to be retrieved using the lwip_getsockopt() function.\n
4394     Currently, the stack does not allow the Set option for the same. The stack sets the error as ENOPROTOOPT.
4395     */
4396 /**
4397     @page RFC-2553_RFC-3493 RFC-2553/3493
4398 
4399     @par Compliant Section
4400     Section 5.2 Sending and Receiving Multicast Packets
4401 
4402     @par Behavior Description
4403     IPV6_MULTICAST_HOPS - Set the hop limit to use for outgoing multicast packets.\n
4404     IPV6_JOIN_GROUP - Join a multicast group on a specified local interface. If the interface index is specified as 0,
4405     no interface will be selected
4406     and EADDRNOTAVAIL will be set. The maximum value of index supported is 254 as of now. \n
4407     IPV6_LEAVE_GROUP - Leave a multicast group on a specified interface.\n
4408 
4409     */
4410 /**
4411     @page RFC-2553_RFC-3493 RFC-2553/3493
4412     @par Non-Compliant Section
4413     Section 6.1 Nodename-to-Address Translation
4414 
4415     @par Behavior Description
4416     getipnodebyname:\n
4417     The commonly used function gethostbyname() is inadequate for many applications due to the following reasons:\n
4418     - It provides no way for the caller to specify anything about the types of\n
4419     addresses desired (IPv4 only,   IPv6 only, IPv4-mapped IPv6 are OK)\n
4420     - Many   implementations of this function are not thread safe.\n
4421     The stack does not implement the function. RFC-2553 introduces the\n
4422     functions ,but RFC-3493 deprecates the same in favor of getaddrinfo() and getnameinfo().
4423     */
4424 /**
4425     @page RFC-2553_RFC-3493 RFC-2553/3493
4426     @par Non-Compliant Section
4427     Section 6.2 Address-To-Nodename Translation
4428     @par Behavior Description
4429     getipnodebyaddr:\n
4430     As with getipnodebyname(), getipnodebyaddr() must be thread safe and is an alternative to
4431     gethostbyaddr() \n
4432     The stack does not implement the function. RFC-2553 introduces the
4433     functions, but RFC-3493 deprecates the same in favor of getaddrinfo() and getnameinfo().
4434     */
4435 /**
4436    @page RFC-2553_RFC-3493 RFC-2553/3493
4437 
4438     @par Non-Compliant Section
4439     Section 6.3 Freeing memory for getipnodebyname and getipnodebyaddr
4440     @par Behavior Description
4441     freehostent:\n
4442     The function frees the memory dynamically allocated by getipnodebyname and getipnodebyaddr\n
4443     The stack does not implement the function. RFC-2553 introduces the\n
4444     functions, but RFC-3493 deprecates the same in favor of getaddrinfo() and getnameinfo().
4445     */
4446 
4447 /**
4448     @page RFC-3493 RFC-3493
4449     @par RFC-3493 Compliance Information
4450     @par Compliant Section
4451     Section 5.3  IPV6_V6ONLY option for AF_INET6 Sockets
4452     @par Behavior Description
4453     This socket option restricts AF_INET6 sockets to IPv6 communications only.\n
4454     Stack allows this option for all sock types and is not restricted to TCP type.
4455     */
4456 
4457 int
lwip_setsockopt(int s,int level,int optname,const void * optval,socklen_t optlen)4458 lwip_setsockopt(int s, int level, int optname, const void *optval, socklen_t optlen)
4459 {
4460   int err = 0;
4461 #if LWIP_SOCK_FILTER
4462   int detachfilteroverride = 0;
4463 #endif
4464   struct lwip_sock *sock = get_socket(s);
4465 #if !LWIP_TCPIP_CORE_LOCKING
4466   err_t cberr;
4467   LWIP_SETGETSOCKOPT_DATA_VAR_DECLARE(data);
4468 #endif /* !LWIP_TCPIP_CORE_LOCKING */
4469 
4470   if (!sock) {
4471     return -1;
4472   }
4473 
4474 #if LWIP_SOCK_FILTER
4475   if (optname == SO_DETACH_FILTER) {
4476     optval  = (void*)&detachfilteroverride;
4477   }
4478 #endif
4479 
4480   if (NULL == optval) {
4481     sock_set_errno(sock, EFAULT);
4482     done_socket(sock);
4483     return -1;
4484   }
4485 
4486 #if PF_PKT_SUPPORT
4487   VALIDATE_LEVEL_PF_PACKET(sock, level)
4488   {
4489     sock_set_errno(sock, EINVAL);
4490     done_socket(sock);
4491     return -1;
4492   }
4493 #endif /* PF_PKT_SUPPORT  */
4494 
4495 #if LWIP_TCPIP_CORE_LOCKING
4496   /* core-locking can just call the -impl function */
4497   LOCK_TCPIP_CORE();
4498   err = lwip_setsockopt_impl(s, level, optname, optval, optlen);
4499   UNLOCK_TCPIP_CORE();
4500 #if LWIP_LOWPOWER
4501   tcpip_send_msg_na(LOW_NON_BLOCK);
4502 #endif
4503 
4504 #else /* LWIP_TCPIP_CORE_LOCKING */
4505 
4506 #if LWIP_MPU_COMPATIBLE
4507   /* MPU_COMPATIBLE copies the optval data, so check for max size here */
4508   if (optlen > LWIP_SETGETSOCKOPT_MAXOPTLEN) {
4509     sock_set_errno(sock, ENOBUFS);
4510     done_socket(sock);
4511     return -1;
4512   }
4513 #endif /* LWIP_MPU_COMPATIBLE */
4514 
4515   LWIP_SETGETSOCKOPT_DATA_VAR_ALLOC(data, sock);
4516   LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).s = s;
4517   LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).level = level;
4518   LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optname = optname;
4519   LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optlen = optlen;
4520 #if LWIP_MPU_COMPATIBLE
4521   MEMCPY(LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optval, optval, optlen);
4522 #else /* LWIP_MPU_COMPATIBLE */
4523   LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optval.pc = (const void *)optval;
4524 #endif /* LWIP_MPU_COMPATIBLE */
4525   LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).err = 0;
4526 #if LWIP_NETCONN_SEM_PER_THREAD
4527   LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).completed_sem = LWIP_NETCONN_THREAD_SEM_GET();
4528 #else
4529   LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).completed_sem = &sock->conn->op_completed;
4530 #endif
4531   cberr = tcpip_callback(lwip_setsockopt_callback, &LWIP_SETGETSOCKOPT_DATA_VAR_REF(data));
4532   if (cberr != ERR_OK) {
4533     LWIP_SETGETSOCKOPT_DATA_VAR_FREE(data);
4534     sock_set_errno(sock, err_to_errno(cberr));
4535     done_socket(sock);
4536     return -1;
4537   }
4538   sys_arch_sem_wait((sys_sem_t *)(LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).completed_sem), 0);
4539 
4540   /* maybe lwip_getsockopt_internal has changed err */
4541   err = LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).err;
4542   LWIP_SETGETSOCKOPT_DATA_VAR_FREE(data);
4543 #endif  /* LWIP_TCPIP_CORE_LOCKING */
4544 
4545   if (err != ERR_OK) {
4546     sock_set_errno(sock, err);
4547   }
4548   done_socket(sock);
4549   return err ? -1 : 0;
4550 }
4551 
4552 #if !LWIP_TCPIP_CORE_LOCKING
4553 /** lwip_setsockopt_callback: only used without CORE_LOCKING
4554  * to get into the tcpip_thread
4555  */
4556 static void
lwip_setsockopt_callback(void * arg)4557 lwip_setsockopt_callback(void *arg)
4558 {
4559   struct lwip_setgetsockopt_data *data;
4560   LWIP_ASSERT("arg != NULL", arg != NULL);
4561   data = (struct lwip_setgetsockopt_data *)arg;
4562 
4563   data->err = lwip_setsockopt_impl(data->s, data->level, data->optname,
4564 #if LWIP_MPU_COMPATIBLE
4565                                    data->optval,
4566 #else /* LWIP_MPU_COMPATIBLE */
4567                                    data->optval.pc,
4568 #endif /* LWIP_MPU_COMPATIBLE */
4569                                    data->optlen);
4570 
4571   sys_sem_signal((sys_sem_t *)(data->completed_sem));
4572 }
4573 #endif  /* LWIP_TCPIP_CORE_LOCKING */
4574 
4575 /** lwip_getoptval: get input parameter optval.
4576  * warning: this function is only suit for setting u8_t type socket options.
4577  */
4578 static inline s32_t
lwip_getoptval(const void * optval,socklen_t optlen)4579 lwip_getoptval(const void *optval, socklen_t optlen)
4580 {
4581   int val = 0;
4582   int len = (optlen < sizeof(int)) ? sizeof(u8_t) : sizeof(int);
4583   (void)memcpy_s(&val, sizeof(int), optval, len);
4584   return val;
4585 }
4586 
4587 /** lwip_setsockopt_impl: the actual implementation of setsockopt:
4588  * same argument as lwip_setsockopt, either called directly or through callback
4589  */
4590 static int
lwip_setsockopt_impl(int s,int level,int optname,const void * optval,socklen_t optlen)4591 lwip_setsockopt_impl(int s, int level, int optname, const void *optval, socklen_t optlen)
4592 {
4593   int err = 0;
4594   struct lwip_sock *sock = tryget_socket(s);
4595   if (!sock) {
4596     return EBADF;
4597   }
4598 
4599 #ifdef LWIP_HOOK_SOCKETS_SETSOCKOPT
4600   if (LWIP_HOOK_SOCKETS_SETSOCKOPT(s, sock, level, optname, optval, optlen, &err)) {
4601     return err;
4602   }
4603 #endif
4604 
4605   switch (level) {
4606 
4607     /* Level: SOL_SOCKET */
4608     case SOL_SOCKET:
4609 #if PF_PKT_SUPPORT
4610     case SOL_PACKET:
4611       VALIDATE_SET_PF_PKT_OPTNAME_RET(s, sock, level, optname);
4612 #endif /* PF_PKT_SUPPORT */
4613 
4614       VALIDATE_SET_RAW_OPTNAME_RET(sock, optname);
4615       switch (optname) {
4616 
4617         /* SO_ACCEPTCONN is get-only */
4618 #if LWIP_SOCK_FILTER
4619       case SO_ATTACH_FILTER:
4620         {
4621           struct sock_fprog *filter = NULL;
4622           /* only AF_PACKET RAW socket support sock filter now */
4623           LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, struct sock_fprog, NETCONN_PKT_RAW);
4624           filter = (struct sock_fprog *)optval;
4625           err = (u8_t)sock_attach_filter(filter, sock->conn);
4626           LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, SOL_SOCKET, optname=0x%x, ..) = %u\n",
4627                       s, SO_ATTACH_FILTER, err));
4628           break;
4629         }
4630       case SO_DETACH_FILTER:
4631         /* only AF_PACKET RAW socket support sock filter now */
4632         if (sock->conn == NULL) {
4633           done_socket(sock);
4634           return EINVAL;
4635         }
4636         if (NETCONNTYPE_GROUP(NETCONN_TYPE(sock->conn)) != NETCONN_PKT_RAW) {
4637           done_socket(sock);
4638           return ENOPROTOOPT;
4639         }
4640         err = (u8_t)sock_detach_filter(sock->conn);
4641         LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, SOL_SOCKET, optname=0x%x, ..) = %u\n",
4642                     s, SO_DETACH_FILTER, err));
4643         break;
4644 #endif /* LWIP_SOCK_FILTER && PF_PKT_SUPPORT */
4645         /* The option flags */
4646         case SO_BROADCAST:
4647 #if LWIP_SO_DONTROUTE
4648         case SO_DONTROUTE:
4649 #endif /* LWIP_SO_DONTROUTE */
4650         case SO_KEEPALIVE:
4651 #if SO_REUSE
4652         case SO_REUSEADDR:
4653 #endif /* SO_REUSE */
4654           if (optname == SO_BROADCAST) {
4655 #if LWIP_ENABLE_NET_CAPABILITY && LWIP_ENABLE_CAP_NET_BROADCAST
4656             LWIP_ERROR("lwip_setsockopt_impl permission deny: NET_BROADCAST\n",
4657                        IsCapPermit(CAP_NET_BROADCAST), err = EPERM; break);
4658 #endif
4659             if (NETCONNTYPE_GROUP(sock->conn->type) == NETCONN_TCP) {
4660               done_socket(sock);
4661               return ENOPROTOOPT;
4662             }
4663           }
4664 
4665           optname = lwip_sockopt_to_ipopt(optname);
4666 
4667           LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, optlen, int);
4668           if (*(const int *)optval) {
4669             ip_set_option(sock->conn->pcb.ip, optname);
4670           } else {
4671             ip_reset_option(sock->conn->pcb.ip, optname);
4672           }
4673           LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, SOL_SOCKET, optname=0x%x, ..) -> %s\n",
4674                                       s, optname, (*(const int *)optval ? "on" : "off")));
4675           break;
4676 
4677           /* SO_TYPE is get-only */
4678           /* SO_ERROR is get-only */
4679 
4680 #if LWIP_SO_SNDTIMEO
4681         case SO_SNDTIMEO: {
4682           long ms_long;
4683           LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, optlen, LWIP_SO_SNDRCVTIMEO_OPTTYPE);
4684           LWIP_SO_SNDRECVTIMO_VALIDATE(sock, optval);
4685           ms_long = LWIP_SO_SNDRCVTIMEO_GET_MS(optval);
4686           if (ms_long < 0) {
4687             done_socket(sock);
4688             return EINVAL;
4689           }
4690           netconn_set_sendtimeout(sock->conn, ms_long);
4691           break;
4692         }
4693 #endif /* LWIP_SO_SNDTIMEO */
4694 #if LWIP_SO_RCVTIMEO
4695         case SO_RCVTIMEO: {
4696           long ms_long;
4697           LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, optlen, LWIP_SO_SNDRCVTIMEO_OPTTYPE);
4698           LWIP_SO_SNDRECVTIMO_VALIDATE(sock, optval);
4699           ms_long = LWIP_SO_SNDRCVTIMEO_GET_MS(optval);
4700           if (ms_long < 0) {
4701             done_socket(sock);
4702             return EINVAL;
4703           }
4704           netconn_set_recvtimeout(sock->conn, (u32_t)ms_long);
4705           break;
4706         }
4707 #endif /* LWIP_SO_RCVTIMEO */
4708 #if LWIP_SO_RCVBUF
4709         case SO_RCVBUF:
4710           LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, optlen, int);
4711           if ((*(int*)optval) < RECV_BUFSIZE_MIN) {
4712             LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, SOL_SOCKET, optname=0x%x) Invalid value \n",
4713                         s, SO_RCVBUF));
4714             done_socket(sock);
4715             return EINVAL;
4716           }
4717           netconn_set_recvbufsize(sock->conn, *(const int *)optval);
4718           break;
4719 #endif /* LWIP_SO_RCVBUF */
4720 #if LWIP_TCP && LWIP_SO_SNDBUF
4721       case SO_SNDBUF:
4722         LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, int, NETCONN_TCP);
4723         if (((sock->conn->pcb.tcp->state != CLOSED) && (sock->conn->pcb.tcp->state != LISTEN))) {
4724           LWIP_DEBUGF(SOCKETS_DEBUG,
4725                       ("lwip_setsockopt(%d, SOL_SOCKET, optname=0x%x) Unsupported state \n", s, SO_SNDBUF));
4726           done_socket(sock);
4727           return EOPNOTSUPP;
4728         }
4729 
4730         if (((*(int*)optval) < SEND_BUFSIZE_MIN) || ((*(int*)optval) > SEND_BUFSIZE_MAX)) {
4731           LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, SOL_SOCKET, optname=0x%x) Invalid value \n", s, SO_SNDBUF));
4732           done_socket(sock);
4733           return EINVAL;
4734         } else {
4735           tcp_set_sendbufsize(sock->conn->pcb.tcp, *(u32_t*)optval);
4736 
4737           if (sock->conn->pcb.tcp->state == CLOSED) {
4738             sock->conn->pcb.tcp->snd_buf = *(u32_t*)optval;
4739           }
4740         }
4741         break;
4742 #endif /* LWIP_TCP && LWIP_SO_SNDBUF */
4743 #if LWIP_SO_LINGER
4744         case SO_LINGER: {
4745           const struct linger *linger = (const struct linger *)optval;
4746           LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, optlen, struct linger);
4747           if (linger->l_onoff) {
4748             int lingersec = linger->l_linger;
4749             if (lingersec < 0) {
4750               done_socket(sock);
4751               return EINVAL;
4752             }
4753             if (lingersec > 0xFFFF) {
4754               lingersec = 0xFFFF;
4755             }
4756             sock->conn->linger = (s16_t)lingersec;
4757           } else {
4758             sock->conn->linger = -1;
4759           }
4760         }
4761         break;
4762 #endif /* LWIP_SO_LINGER */
4763 #if LWIP_UDP
4764         case SO_NO_CHECK:
4765           LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, int, NETCONN_UDP);
4766 #if LWIP_UDPLITE
4767           if (udp_is_flag_set(sock->conn->pcb.udp, UDP_FLAGS_UDPLITE)) {
4768             /* this flag is only available for UDP, not for UDP lite */
4769             done_socket(sock);
4770             return EAFNOSUPPORT;
4771           }
4772 #endif /* LWIP_UDPLITE */
4773           if (*(const int *)optval) {
4774             udp_set_flags(sock->conn->pcb.udp, UDP_FLAGS_NOCHKSUM);
4775           } else {
4776             udp_clear_flags(sock->conn->pcb.udp, UDP_FLAGS_NOCHKSUM);
4777           }
4778           break;
4779 #endif /* LWIP_UDP */
4780         case SO_BINDTODEVICE: {
4781           const struct ifreq *iface;
4782           struct netif *n = NULL;
4783 
4784           LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, optlen, struct ifreq);
4785 
4786           iface = (const struct ifreq *)optval;
4787           if (iface->ifr_name[0] != 0) {
4788             n = netif_find(iface->ifr_name);
4789             if (n == NULL) {
4790               done_socket(sock);
4791               return ENODEV;
4792             }
4793           }
4794 
4795           switch (NETCONNTYPE_GROUP(NETCONN_TYPE(sock->conn))) {
4796 #if LWIP_TCP
4797             case NETCONN_TCP:
4798               tcp_bind_netif(sock->conn->pcb.tcp, n);
4799               break;
4800 #endif
4801 #if LWIP_UDP
4802             case NETCONN_UDP:
4803               udp_bind_netif(sock->conn->pcb.udp, n);
4804               break;
4805 #endif
4806 #if LWIP_RAW
4807             case NETCONN_RAW:
4808               raw_bind_netif(sock->conn->pcb.raw, n);
4809               break;
4810 #endif
4811             default:
4812               LWIP_ASSERT("Unhandled netconn type in SO_BINDTODEVICE", 0);
4813               break;
4814           }
4815         }
4816         break;
4817 #if LWIP_SO_PRIORITY
4818         case SO_PRIORITY: {
4819 #if LWIP_ENABLE_NET_CAPABILITY
4820           LWIP_ERROR("permission deny: NET_ADMIN\n", IsCapPermit(CAP_NET_ADMIN), err = EPERM; break);
4821 #endif
4822           LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, optlen, prio_t);
4823           if ((*(prio_t *)optval) > LWIP_PKT_PRIORITY_MAX) {
4824             LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, SO_PRIORITY, optname=0x%x) Invalid value \n", s,
4825                                         SO_PRIORITY));
4826             return EINVAL;
4827           }
4828 #if LWIP_UDP
4829           if (NETCONNTYPE_GROUP(sock->conn->type) == NETCONN_UDP) {
4830             sock->conn->pcb.udp->priority = *(const prio_t *)optval;
4831           } else
4832 #endif
4833 #if LWIP_TCP
4834           if (NETCONNTYPE_GROUP(sock->conn->type) == NETCONN_TCP) {
4835             sock->conn->pcb.tcp->priority = *(const prio_t *)optval;
4836           } else
4837 #endif
4838 #if LWIP_RAW
4839           if (NETCONNTYPE_GROUP(sock->conn->type) == NETCONN_RAW) {
4840             sock->conn->pcb.raw->priority = *(const prio_t *)optval;
4841           } else
4842 #endif
4843           {
4844             LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt Invalid socket type \n"));
4845             return ENOPROTOOPT;
4846           }
4847           break;
4848         }
4849 #endif /* LWIP_SO_PRIORITY */
4850 
4851         default:
4852           LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, SOL_SOCKET, UNIMPL: optname=0x%x, ..)\n",
4853                                       s, optname));
4854           err = ENOPROTOOPT;
4855           break;
4856       }  /* switch (optname) */
4857       break;
4858 
4859     /* Level: IPPROTO_IP */
4860     case IPPROTO_IP:
4861       switch (optname) {
4862         case IP_TTL:
4863           {
4864             s32_t ip_ttl;
4865             LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, optlen, u8_t);
4866             ip_ttl = lwip_getoptval(optval, optlen);
4867             if ((IP_USE_DEFAULT_TTL <= ip_ttl) && (ip_ttl <= IP_MAX_TTL)) {
4868               sock->conn->pcb.ip->ttl = (ip_ttl == IP_USE_DEFAULT_TTL ? IP_DEFAULT_TTL : (u8_t)ip_ttl);
4869               LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IP, IP_TTL, ..) -> %"U8_F"\n",
4870                           s, sock->conn->pcb.ip->ttl));
4871             } else {
4872               err = EINVAL;
4873             }
4874           }
4875           break;
4876         case IP_TOS:
4877           LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, optlen, u8_t);
4878           sock->conn->pcb.ip->tos = (u8_t)lwip_getoptval(optval, optlen);
4879           LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IP, IP_TOS, ..)-> %u\n",
4880                                       s, sock->conn->pcb.ip->tos));
4881           break;
4882 #if LWIP_RAW
4883       case IP_HDRINCL:
4884           LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, u8_t, NETCONN_RAW);
4885           if (NETCONNTYPE_ISIPV6(sock->conn->type)) {
4886             done_socket(sock);
4887             return ENOPROTOOPT;
4888           }
4889 
4890           if (lwip_getoptval(optval, optlen)) {
4891             raw_set_flags(sock->conn->pcb.raw, RAW_FLAGS_HDRINCL);
4892           } else {
4893             raw_clear_flags(sock->conn->pcb.raw, RAW_FLAGS_HDRINCL);
4894           }
4895           LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IP_HDRINCL)-> %u\n",
4896                       s, *(u8_t *)optval));
4897           break;
4898 #endif
4899 #if LWIP_NETBUF_RECVINFO
4900         case IP_PKTINFO:
4901           LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, u8_t, NETCONN_UDP);
4902           if (lwip_getoptval(optval, optlen)) {
4903             sock->conn->flags |= NETCONN_FLAG_PKTINFO;
4904           } else {
4905             sock->conn->flags &= ~NETCONN_FLAG_PKTINFO;
4906           }
4907           break;
4908 #endif /* LWIP_NETBUF_RECVINFO */
4909 #if LWIP_IPV4 && LWIP_MULTICAST_TX_OPTIONS && LWIP_UDP
4910         case IP_MULTICAST_TTL:
4911           {
4912             s32_t mc_ttl;
4913             LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, u8_t, NETCONN_UDP);
4914             mc_ttl = lwip_getoptval(optval, optlen);
4915             if ((IP_USE_DEFAULT_TTL <= mc_ttl) && (mc_ttl <= IP_MAX_TTL)) {
4916               udp_set_multicast_ttl(sock->conn->pcb.udp, mc_ttl == IP_USE_DEFAULT_TTL ? MC_TTL : (u8_t)mc_ttl);
4917               LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IP, IP_MULTICAST_TTL, ..) -> %"U8_F"\n",
4918                           s, sock->conn->pcb.udp->mcast_ttl));
4919             } else {
4920               err = EINVAL;
4921             }
4922           }
4923           break;
4924         case IP_MULTICAST_IF:
4925           {
4926             struct netif *netif = NULL;
4927             ip_addr_t if_addr;
4928             (void)memset_s(&if_addr, sizeof(ip_addr_t), 0, sizeof(ip_addr_t));
4929             IP_SET_TYPE_VAL(if_addr, IPADDR_TYPE_V4);
4930             LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, struct in_addr, NETCONN_UDP);
4931             inet_addr_to_ip4addr(ip_2_ip4(&if_addr), (const struct in_addr*)optval);
4932             netif = netif_find_by_ipaddr(&if_addr);
4933             if ((netif == NULL) ||
4934                 (sock->conn->pcb.ip->netif_idx && (sock->conn->pcb.ip->netif_idx != netif->ifindex))) {
4935               err = EADDRNOTAVAIL;
4936             } else {
4937               udp_set_multicast_netif_addr(sock->conn->pcb.udp, ip_2_ip4(&if_addr));
4938             }
4939           }
4940           break;
4941         case IP_MULTICAST_LOOP:
4942           LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, u8_t, NETCONN_UDP);
4943           if (*(const u8_t *)optval) {
4944             udp_set_flags(sock->conn->pcb.udp, UDP_FLAGS_MULTICAST_LOOP);
4945           } else {
4946             udp_clear_flags(sock->conn->pcb.udp, UDP_FLAGS_MULTICAST_LOOP);
4947           }
4948           break;
4949 #endif /* LWIP_IPV4 && LWIP_MULTICAST_TX_OPTIONS && LWIP_UDP */
4950 #if LWIP_IGMP
4951         case IP_ADD_MEMBERSHIP:
4952         case IP_DROP_MEMBERSHIP: {
4953           /* If this is a TCP or a RAW socket, ignore these options. */
4954           err_t igmp_err;
4955           const struct ip_mreq *imr = (const struct ip_mreq *)optval;
4956           ip4_addr_t if_addr;
4957           ip4_addr_t multi_addr;
4958           LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, struct ip_mreq, NETCONN_UDP);
4959           inet_addr_to_ip4addr(&if_addr, &imr->imr_interface);
4960           inet_addr_to_ip4addr(&multi_addr, &imr->imr_multiaddr);
4961           if (optname == IP_ADD_MEMBERSHIP) {
4962             if (!lwip_socket_register_membership(s, &if_addr, &multi_addr)) {
4963               /* cannot track membership (out of memory) */
4964               err = ENOMEM;
4965               igmp_err = ERR_OK;
4966             } else {
4967               igmp_err = igmp_joingroup(&if_addr, &multi_addr);
4968             }
4969           } else {
4970             igmp_err = igmp_leavegroup(&if_addr, &multi_addr);
4971             lwip_socket_unregister_membership(s, &if_addr, &multi_addr);
4972           }
4973           if (igmp_err != ERR_OK) {
4974             err = EADDRNOTAVAIL;
4975           }
4976         }
4977         break;
4978 #endif /* LWIP_IGMP */
4979         default:
4980           LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IP, UNIMPL: optname=0x%x, ..)\n",
4981                                       s, optname));
4982           err = ENOPROTOOPT;
4983           break;
4984       }  /* switch (optname) */
4985       break;
4986 
4987 #if LWIP_TCP
4988     /* Level: IPPROTO_TCP */
4989     case IPPROTO_TCP:
4990       /* Special case: all IPPROTO_TCP option take an int */
4991       LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, int, NETCONN_TCP);
4992       if ((sock->conn->pcb.tcp->state == LISTEN)
4993 #if LWIP_TCP_MAXSEG
4994           && (optname != TCP_MAXSEG)
4995 #endif
4996          ) {
4997         done_socket(sock);
4998         return EINVAL;
4999       }
5000       switch (optname) {
5001         case TCP_NODELAY:
5002           if (*(const int *)optval) {
5003             tcp_nagle_disable(sock->conn->pcb.tcp);
5004           } else {
5005             tcp_nagle_enable(sock->conn->pcb.tcp);
5006           }
5007           LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_NODELAY) -> %s\n",
5008                                       s, (*(const int *)optval) ? "on" : "off") );
5009           break;
5010 #if LWIP_TCP_KEEPALIVE
5011         case TCP_KEEPIDLE:
5012           sock->conn->pcb.tcp->keep_idle = MS_PER_SECOND * (u32_t)(*(const int*)optval);
5013           LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPIDLE) -> %"U32_F"\n",
5014                                       s, sock->conn->pcb.tcp->keep_idle));
5015           break;
5016         case TCP_KEEPINTVL:
5017           sock->conn->pcb.tcp->keep_intvl = MS_PER_SECOND * (u32_t)(*(const int*)optval);
5018           LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPINTVL) -> %"U32_F"\n",
5019                                       s, sock->conn->pcb.tcp->keep_intvl));
5020           break;
5021         case TCP_KEEPCNT:
5022           sock->conn->pcb.tcp->keep_cnt = (u32_t)(*(const int *)optval);
5023           LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPCNT) -> %"U32_F"\n",
5024                                       s, sock->conn->pcb.tcp->keep_cnt));
5025           break;
5026 #endif /* LWIP_TCP_KEEPALIVE */
5027 
5028 #if LWIP_TCP_MAXSEG
5029         case TCP_MAXSEG:
5030         {
5031           s32_t usr_mss = *(const int*)optval;
5032           if ((usr_mss < TCP_MIN_MSS) || (usr_mss > TCP_MAX_MSS)) {
5033             done_socket(sock);
5034             return EINVAL;
5035           }
5036           sock->conn->pcb.tcp->usr_mss = (u16_t)(*(const int*)optval);
5037           LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_MAXSEG) -> %"U32_F"\n",
5038                       s, sock->conn->pcb.tcp->usr_mss));
5039           break;
5040         }
5041 #endif /* LWIP_TCP_MAXSEG */
5042         default:
5043           LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, UNIMPL: optname=0x%x, ..)\n",
5044                                       s, optname));
5045           err = ENOPROTOOPT;
5046           break;
5047       }  /* switch (optname) */
5048       break;
5049 #endif /* LWIP_TCP*/
5050 
5051 #if LWIP_IPV6
5052     /* Level: IPPROTO_IPV6 */
5053     case IPPROTO_IPV6:
5054       switch (optname) {
5055         case IPV6_V6ONLY:
5056           LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, optlen, int);
5057           /* The below check is to ensure that the option is used for AF_INET6 only */
5058           LWIP_SOCKOPT_CHECK_IPTYPE_V6(sock, sock->conn->type);
5059           if (*(const int *)optval) {
5060             netconn_set_ipv6only(sock->conn, 1);
5061           } else {
5062             netconn_set_ipv6only(sock->conn, 0);
5063           }
5064           LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IPV6, IPV6_V6ONLY, ..) -> %d\n",
5065                                       s, (netconn_get_ipv6only(sock->conn) ? 1 : 0)));
5066           break;
5067 #if LWIP_RAW
5068         case IPV6_CHECKSUM:
5069           LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE_IPV6(sock, optlen, int, NETCONN_RAW);
5070           if (sock->conn->pcb.raw->raw_proto == IPPROTO_ICMPV6) {
5071             done_socket(sock);
5072             LWIP_DEBUGF(SOCKETS_DEBUG,
5073                         ("lwip_setsockopt(%d, socket type IPPROTO_ICMPV6, \
5074                         opttype - IPV6_CHECKSUM, ..) -> %d Not allowed \n",
5075                         s, sock->conn->pcb.raw->chksum_reqd));
5076             return EINVAL;
5077           }
5078 
5079           if (*(const int *)optval < 0) {
5080             sock->conn->pcb.raw->chksum_reqd = 0;
5081             /* reseting the offset of icmp value to 2 */
5082             sock->conn->pcb.raw->chksum_offset = RAW_CHKSUM_OFFSET;
5083           } else if ((unsigned int)(*(const int *)optval) & 1) {
5084             done_socket(sock);
5085               /* Per RFC3542, odd offsets are not allowed */
5086             return EINVAL;
5087           } else if (*(const int *)optval > 0xFFFF) {
5088             done_socket(sock);
5089             /* Check added to avoid overflow or avoid big invalid value. */
5090               return EINVAL;
5091           } else {
5092               sock->conn->pcb.raw->chksum_reqd = 1;
5093               sock->conn->pcb.raw->chksum_offset = (u16_t)(*(const int *)optval);
5094           }
5095           LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IPV6, IPV6_CHECKSUM, ..) -> %d\n",
5096                       s, sock->conn->pcb.raw->chksum_reqd));
5097           break;
5098 #endif
5099 #if LWIP_IPV6_MLD
5100         case IPV6_JOIN_GROUP:
5101         case IPV6_LEAVE_GROUP: {
5102           /* If this is a TCP or a RAW socket, ignore these options. */
5103           err_t mld6_err;
5104           struct netif *netif;
5105           ip6_addr_t multi_addr;
5106           const struct ipv6_mreq *imr = (const struct ipv6_mreq *)optval;
5107           LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, struct ipv6_mreq, NETCONN_UDP);
5108           inet6_addr_to_ip6addr(&multi_addr, &imr->ipv6mr_multiaddr);
5109 
5110           /* Check if the address is multicast or not */
5111           if (!ip6_addr_ismulticast(&multi_addr)) {
5112             err = EADDRNOTAVAIL;
5113             break;
5114           }
5115 
5116           /* Stack as of now doesnot handle the 0 interface index scenario */
5117           if (imr->ipv6mr_interface > LWIP_NETIF_IFINDEX_MAX_EX) {
5118               LWIP_DEBUGF(SOCKETS_DEBUG,
5119                           ("lwip_setsockopt(%d, Invalid Interface index IPPROTO_IPV6, \
5120                           IPV6_JOIN_GROUP/IPV6_LEAVE_GROUP) -> %d\n",
5121                           s, (imr->ipv6mr_interface)));
5122               err = ENXIO;
5123               break;
5124           }
5125 
5126           LWIP_ASSERT("Invalid netif index", imr->ipv6mr_interface <= 0xFFu);
5127           netif = netif_get_by_index((u8_t)imr->ipv6mr_interface);
5128           if (netif == NULL) {
5129             err = EADDRNOTAVAIL;
5130             break;
5131           }
5132 
5133           if (optname == IPV6_JOIN_GROUP) {
5134             if (!lwip_socket_register_mld6_membership(s, imr->ipv6mr_interface, &multi_addr)) {
5135               /* cannot track membership (out of memory) */
5136               err = ENOMEM;
5137               mld6_err = ERR_OK;
5138             } else {
5139               mld6_err = mld6_joingroup_netif(netif, &multi_addr);
5140             }
5141           } else {
5142             mld6_err = mld6_leavegroup_netif(netif, &multi_addr);
5143             lwip_socket_unregister_mld6_membership(s, imr->ipv6mr_interface, &multi_addr);
5144           }
5145           if (mld6_err != ERR_OK) {
5146             err = EADDRNOTAVAIL;
5147           }
5148         }
5149         break;
5150 #endif /* LWIP_IPV6_MLD */
5151 #if LWIP_MULTICAST_TX_OPTIONS
5152       case IPV6_MULTICAST_HOPS:
5153         {
5154           s32_t mc_hops;
5155           LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE_IPV6(sock, optlen, int, NETCONN_UDP);
5156           mc_hops = (s32_t)(*(const s32_t *)optval);
5157           if ((IP_USE_DEFAULT_TTL <= mc_hops) && (mc_hops <= IP_MAX_TTL)) {
5158             udp_set_multicast_ttl(sock->conn->pcb.udp, mc_hops == IP_USE_DEFAULT_TTL ? MC_TTL : (u8_t)mc_hops);
5159           } else {
5160             err = EINVAL;
5161           }
5162         }
5163         break;
5164       case IPV6_MULTICAST_IF:
5165         LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE_IPV6(sock, optlen, u8_t, NETCONN_UDP);
5166         udp_set_multicast_netif_index(sock->conn->pcb.udp, (u8_t)(*(const u8_t *)optval));
5167         break;
5168       case IPV6_MULTICAST_LOOP:
5169         LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE_IPV6(sock, optlen, u8_t, NETCONN_UDP);
5170         if (*(const u8_t*)optval) {
5171           udp_setflags(sock->conn->pcb.udp, udp_flags(sock->conn->pcb.udp) | UDP_FLAGS_MULTICAST_LOOP);
5172         } else {
5173           udp_setflags(sock->conn->pcb.udp, udp_flags(sock->conn->pcb.udp) & ~UDP_FLAGS_MULTICAST_LOOP);
5174         }
5175         break;
5176 #endif /* LWIP_MULTICAST_TX_OPTIONS */
5177 
5178 #if LWIP_NETBUF_RECVINFO
5179       case IPV6_RECVPKTINFO:
5180         LWIP_SOCKOPT_CHECK_IPTYPE_V6(sock, sock->conn->type);
5181         LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, int, NETCONN_UDP);
5182         if (*(const int *)optval) {
5183           sock->conn->flags |= NETCONN_FLAG_PKTINFO;
5184         } else {
5185           sock->conn->flags &= ~NETCONN_FLAG_PKTINFO;
5186         }
5187         break;
5188 #endif /* LWIP_NETBUF_RECVINFO */
5189         default:
5190           LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IPV6, UNIMPL: optname=0x%x, ..)\n",
5191                                       s, optname));
5192           err = ENOPROTOOPT;
5193           break;
5194       }  /* switch (optname) */
5195       break;
5196 #endif /* LWIP_IPV6 */
5197 
5198 #if LWIP_UDP && LWIP_UDPLITE
5199     /* Level: IPPROTO_UDPLITE */
5200     case IPPROTO_UDPLITE:
5201       /* Special case: all IPPROTO_UDPLITE option take an int */
5202       LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, optlen, int);
5203       /* If this is no UDP lite socket, ignore any options. */
5204       if (!NETCONNTYPE_ISUDPLITE(NETCONN_TYPE(sock->conn))) {
5205         done_socket(sock);
5206         return ENOPROTOOPT;
5207       }
5208       switch (optname) {
5209         case UDPLITE_SEND_CSCOV:
5210           if ((*(const int *)optval != 0) && ((*(const int *)optval < 8) || (*(const int *)optval > 0xffff))) {
5211             /* don't allow illegal values! */
5212             sock->conn->pcb.udp->chksum_len_tx = 8;
5213           } else {
5214             sock->conn->pcb.udp->chksum_len_tx = (u16_t) * (const int *)optval;
5215           }
5216           LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_UDPLITE, UDPLITE_SEND_CSCOV) -> %d\n",
5217                                       s, (*(const int *)optval)) );
5218           break;
5219         case UDPLITE_RECV_CSCOV:
5220           if ((*(const int *)optval != 0) && ((*(const int *)optval < 8) || (*(const int *)optval > 0xffff))) {
5221             /* don't allow illegal values! */
5222             sock->conn->pcb.udp->chksum_len_rx = 8;
5223           } else {
5224             sock->conn->pcb.udp->chksum_len_rx = (u16_t) * (const int *)optval;
5225           }
5226           LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_UDPLITE, UDPLITE_RECV_CSCOV) -> %d\n",
5227                                       s, (*(const int *)optval)) );
5228           break;
5229         default:
5230           LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_UDPLITE, UNIMPL: optname=0x%x, ..)\n",
5231                                       s, optname));
5232           err = ENOPROTOOPT;
5233           break;
5234       }  /* switch (optname) */
5235       break;
5236 #endif /* LWIP_UDP */
5237     /* Level: IPPROTO_RAW */
5238     case IPPROTO_RAW:
5239       switch (optname) {
5240 #if LWIP_IPV6 && LWIP_RAW
5241         case IPV6_CHECKSUM:
5242           LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE_IPV6(sock, optlen, int, NETCONN_RAW);
5243           /* It should not be possible to disable the checksum generation with ICMPv6
5244            * as per RFC 3542 chapter 3.1 */
5245           if (sock->conn->pcb.raw->raw_proto == IPPROTO_ICMPV6) {
5246             done_socket(sock);
5247             return EINVAL;
5248           }
5249 
5250           if (*(const int *)optval < 0) {
5251             sock->conn->pcb.raw->chksum_reqd = 0;
5252             sock->conn->pcb.raw->chksum_offset = RAW_CHKSUM_OFFSET;
5253           } else if (*(const int *)optval & 1) {
5254             /* Per RFC3542, odd offsets are not allowed */
5255             done_socket(sock);
5256             return EINVAL;
5257           } else if (*(const int *)optval > 0xFFFF) {
5258             sock->conn->pcb.raw->chksum_reqd = 1;
5259             /* Check added to avoid overflow or avoid  big invalid value. */
5260             done_socket(sock);
5261             return EINVAL;
5262           } else {
5263             sock->conn->pcb.raw->chksum_reqd = 1;
5264             sock->conn->pcb.raw->chksum_offset = (u16_t) * (const int *)optval;
5265           }
5266           LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_RAW, IPV6_CHECKSUM, ..) -> %d\n",
5267                                       s, sock->conn->pcb.raw->chksum_reqd));
5268           break;
5269 #endif /* LWIP_IPV6 && LWIP_RAW */
5270         default:
5271           LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_RAW, UNIMPL: optname=0x%x, ..)\n",
5272                                       s, optname));
5273           err = ENOPROTOOPT;
5274           break;
5275       }  /* switch (optname) */
5276       break;
5277 
5278   /* Below feature is enabled  only if ipv6 raw socket is enabled */
5279 #if LWIP_IPV6 && LWIP_RAW && LWIP_SOCK_OPT_ICMP6_FILTER
5280     /* Level: IPPROTO_ICMPV6 */
5281     case IPPROTO_ICMPV6:
5282       switch (optname) {
5283         case ICMP6_FILTER:
5284           LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE_IPV6(sock, optlen, struct icmp6_filter, NETCONN_RAW);
5285           if (optlen > sizeof(struct icmp6_filter)) {
5286             optlen = sizeof(struct icmp6_filter);
5287           }
5288 
5289           if (memcpy_s(&sock->conn->pcb.raw->icmp6_filter, sizeof(struct icmp6_filter),
5290                        optval, optlen) != 0) {
5291             LWIP_DEBUGF(SOCKETS_DEBUG,
5292                         ("lwip_setsockopt(%d, IPPROTO_ICMPV6, ICMP6_FILTER:  ..) mem error\n", s));
5293             err = EINVAL;
5294             break;
5295           }
5296           LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_ICMPV6, ICMP6_FILTER:  ..)\n", s));
5297           break;
5298         default:
5299           LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_ICMPV6, UNIMPL: optname=0x%x, ..)\n",
5300                             s, optname));
5301           err = ENOPROTOOPT;
5302           break;
5303       }
5304       break;
5305 #endif /* LWIP_IPV6 && LWIP_RAW */
5306     default:
5307       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, level=0x%x, UNIMPL: optname=0x%x, ..)\n",
5308                                   s, level, optname));
5309       err = ENOPROTOOPT;
5310       break;
5311   }  /* switch (level) */
5312 
5313   done_socket(sock);
5314   return err;
5315 }
5316 
5317 #if LWIP_IOCTL_ROUTE
lwip_ioctl_internal_SIOCADDRT(const struct rtentry * rmten)5318 static u8_t lwip_ioctl_internal_SIOCADDRT(const struct rtentry *rmten)
5319 {
5320   struct netif *netif = NULL;
5321   ip_addr_t rtgw_addr;
5322   u16_t rtgw_port;
5323 
5324 #if LWIP_ENABLE_NET_CAPABILITY
5325   LWIP_ERROR("lwip_ioctl_internal_SIOCADDRT: Have no permission CAP_NET_ADMIN",
5326              IsCapPermit(CAP_NET_ADMIN), return EPERM);
5327 #endif
5328 
5329   SOCKADDR_TO_IPADDR_PORT(&rmten->rt_gateway, &rtgw_addr, rtgw_port);
5330   LWIP_UNUSED_ARG(rtgw_port);
5331 
5332   if (!IP_IS_V4_VAL(rtgw_addr)) {
5333     return EINVAL;
5334   }
5335 
5336   /* check if multicast/0/loopback */
5337   if (ip_addr_ismulticast_val(rtgw_addr) || ip_addr_isany_val(rtgw_addr) ||
5338       ip_addr_isloopback_val(rtgw_addr)) {
5339     return EINVAL;
5340   }
5341 
5342   /* check if reachable */
5343   for (netif = netif_list; netif != NULL; netif = netif->next) {
5344     if (ip_addr_netcmp_val(rtgw_addr, netif->ip_addr, ip_2_ip4(&netif->netmask))) {
5345       break;
5346     }
5347   }
5348 
5349   if (netif == NULL) {
5350     return EHOSTUNREACH;
5351   }
5352 
5353   /* check if broadcast */
5354   if (ip_addr_isbroadcast_val(rtgw_addr, netif)) {
5355     return EINVAL;
5356   }
5357 
5358   /* Check flags */
5359   if (!(rmten->rt_flags & RTF_GATEWAY)) {
5360     return EINVAL;
5361   }
5362 
5363   /* Add validation */
5364   if (netif_default != netif) {
5365     if (netif_default != NULL) {
5366       ip_addr_set_zero(&netif_default->gw);
5367     }
5368     (void)netif_set_default(netif);
5369   }
5370   netif_set_gw(netif, ip_2_ip4(&rtgw_addr));
5371 
5372   return 0;
5373 }
5374 #endif /* LWIP_IOCTL_ROUTE */
5375 
5376 #if LWIP_IOCTL_IF
lwip_ioctl_internal_SIOCGIFCONF(struct ifreq * ifr)5377 static u8_t lwip_ioctl_internal_SIOCGIFCONF(struct ifreq *ifr)
5378 {
5379   struct ifconf *ifc = NULL;
5380   struct netif *netif = NULL;
5381   struct ifreq ifreq;
5382   struct sockaddr_in *sock_in = NULL;
5383   int pos;
5384   int len;
5385   int ret;
5386 
5387   /* Format the caller's buffer. */
5388   ifc = (struct ifconf*)ifr;
5389   len = ifc->ifc_len;
5390 
5391   /* Loop over the interfaces, and write an info block for each. */
5392   pos = 0;
5393   for (netif = netif_list; netif != NULL; netif = netif->next) {
5394     if (ifc->ifc_buf == NULL) {
5395       pos =  (pos + (int)sizeof(struct ifreq));
5396       continue;
5397     }
5398 
5399     if (len < (int)sizeof(ifreq)) {
5400       break;
5401     }
5402 
5403     (void)memset_s(&ifreq, sizeof(struct ifreq), 0, sizeof(struct ifreq));
5404     if (netif->link_layer_type == LOOPBACK_IF) {
5405       ret = snprintf_s(ifreq.ifr_name, NETIF_NAMESIZE, (NETIF_NAMESIZE - 1), "%s", netif->name);
5406       if ((ret <= 0) || (ret >= IFNAMSIZ)) {
5407         LWIP_DEBUGF(NETIF_DEBUG, ("lwip_ioctl: snprintf_s ifr_name failed."));
5408         return ENOBUFS;
5409       }
5410     } else {
5411       ret = snprintf_s(ifreq.ifr_name, NETIF_NAMESIZE, NETIF_NAMESIZE - 1, "%s%"U8_F, netif->name, netif->num);
5412       if ((ret <= 0) || (ret >= NETIF_NAMESIZE)) {
5413         LWIP_DEBUGF(NETIF_DEBUG, ("lwip_ioctl: snprintf_s ifr_name failed."));
5414         return ENOBUFS;
5415       }
5416     }
5417 
5418     sock_in = (struct sockaddr_in *)&ifreq.ifr_addr;
5419     sock_in->sin_family = AF_INET;
5420     sock_in->sin_addr.s_addr = ip_2_ip4(&netif->ip_addr)->addr;
5421     if (memcpy_s(ifc->ifc_buf + pos, sizeof(struct ifreq), &ifreq, sizeof(struct ifreq)) != EOK) {
5422       return ENOBUFS;
5423     }
5424     pos = pos + (int)sizeof(struct ifreq);
5425     len = len - (int)sizeof(struct ifreq);
5426   }
5427 
5428   ifc->ifc_len = pos;
5429 
5430   return 0;
5431 }
5432 
lwip_ioctl_internal_SIOCGIFADDR(struct ifreq * ifr)5433 static u8_t lwip_ioctl_internal_SIOCGIFADDR(struct ifreq *ifr)
5434 {
5435   struct netif *netif = NULL;
5436   struct sockaddr_in *sock_in = NULL;
5437 
5438   /* get netif ipaddr */
5439   netif = netif_find(ifr->ifr_name);
5440   if (netif == NULL) {
5441     return ENODEV;
5442   } else {
5443     sock_in = (struct sockaddr_in *)&ifr->ifr_addr;
5444     sock_in->sin_family = AF_INET;
5445     sock_in->sin_addr.s_addr = ip_2_ip4(&netif->ip_addr)->addr;
5446     return 0;
5447   }
5448 }
5449 
5450 #if LWIP_IPV6
lwip_ioctl_internal_SIOCSIFADDR_6(struct ifreq * ifr)5451 static u8_t lwip_ioctl_internal_SIOCSIFADDR_6(struct ifreq *ifr)
5452 {
5453   struct netif *netif = NULL;
5454   err_t err;
5455   struct in6_ifreq *ifr6 = NULL;
5456   ip_addr_t target_addr;
5457   s8_t idx;
5458 
5459 #if LWIP_ENABLE_NET_CAPABILITY
5460   LWIP_ERROR("lwip_ioctl_internal_SIOCSIFADDR_6: Have no permission CAP_NET_ADMIN",
5461              IsCapPermit(CAP_NET_ADMIN), return EPERM);
5462 #endif
5463 
5464   ifr6 = (struct in6_ifreq *)ifr;
5465 
5466   /* Supports only fixed length LWIP_IPV6_PREFIX_LEN of prefix */
5467   if ((ifr6->ifr6_prefixlen != LWIP_IPV6_PREFIX_LEN) ||
5468       (ifr6->ifr6_ifindex > LWIP_NETIF_IFINDEX_MAX)) {
5469     return EINVAL;
5470   }
5471 
5472   netif = netif_get_by_index((u8_t)ifr6->ifr6_ifindex);
5473   if (netif == NULL) {
5474     return ENODEV;
5475   }
5476 #if LWIP_HAVE_LOOPIF
5477   /* Most likely unhittable code.. since loopif is global address.. remove code after confirmation */
5478   else if (netif->link_layer_type == LOOPBACK_IF) {
5479     return EPERM;
5480   }
5481 #endif
5482 
5483   ip_addr_set_zero_ip6_val(target_addr);
5484   inet6_addr_to_ip6addr(ip_2_ip6(&target_addr), &ifr6->ifr6_addr);
5485 
5486   /* Do no allow multicast or any ip address or loopback address to be set as interface address */
5487   if (ip_addr_ismulticast_val(target_addr) ||
5488       ip_addr_isany_val(target_addr) ||
5489       ip_addr_isloopback_val(target_addr)) {
5490     return EINVAL;
5491   }
5492 
5493   idx = netif_get_ip6_addr_match(netif, ip_2_ip6(&target_addr));
5494   if (idx >= 0) {
5495     return EEXIST;
5496   }
5497 
5498 #if LWIP_IPV6_DHCP6
5499   if (netif_dhcp6_data(netif) && netif_dhcp6_data(netif)->state != DHCP6_STATE_OFF) {
5500     dhcp6_disable(netif);
5501   }
5502 #endif
5503 
5504   err = netif_add_ip6_address(netif, ip_2_ip6(&target_addr), &idx);
5505   if ((err != ERR_OK) || (idx == -1)) {
5506     return ENOBUFS;
5507   }
5508 
5509   netif_ip6_addr_set_state(netif, idx, IP6_ADDR_PREFERRED);
5510 
5511   return ERR_OK;
5512 }
5513 #endif
5514 
lwip_ioctl_internal_SIOCSIFADDR(const struct ifreq * ifr)5515 static u8_t lwip_ioctl_internal_SIOCSIFADDR(const struct ifreq *ifr)
5516 {
5517   struct netif *netif = NULL;
5518 
5519   struct netif *loc_netif = NULL;
5520   ip_addr_t taget_addr;
5521   u16_t taget_port;
5522   SOCKADDR_TO_IPADDR_PORT(&ifr->ifr_addr, &taget_addr, taget_port);
5523   LWIP_UNUSED_ARG(taget_port);
5524 
5525 #if LWIP_ENABLE_NET_CAPABILITY
5526   LWIP_ERROR("lwip_ioctl_internal_SIOCSIFADDR: Have no permission CAP_NET_ADMIN",
5527              IsCapPermit(CAP_NET_ADMIN), return EPERM);
5528 #endif
5529 
5530   /* set netif ipaddr */
5531   netif = netif_find(ifr->ifr_name);
5532   if (netif == NULL) {
5533     return ENODEV;
5534   }
5535 #if LWIP_HAVE_LOOPIF
5536   else if (netif->link_layer_type == LOOPBACK_IF) {
5537     return EPERM;
5538   }
5539 #endif
5540   else {
5541      /* check the address is not multicast/broadcast/0/loopback */
5542     if (!IP_IS_V4_VAL(taget_addr) || ip_addr_ismulticast_val(taget_addr) ||
5543         ip_addr_isbroadcast_val(taget_addr, netif) ||
5544         ip_addr_isany_val(taget_addr) ||
5545         ip_addr_isloopback_val(taget_addr)) {
5546       return EINVAL;
5547     }
5548 
5549     /* reset gateway if new and previous ipaddr not in same net */
5550     if (!ip_addr_netcmp_val(taget_addr, netif->ip_addr, ip_2_ip4(&netif->netmask))) {
5551       ip_addr_set_zero_val(netif->gw);
5552       if (netif == netif_default) {
5553         (void)netif_set_default(NULL);
5554       }
5555     }
5556 
5557     /* lwip disallow two netif sit in same net at the same time */
5558     loc_netif = netif_list;
5559     while (loc_netif != NULL) {
5560       if (loc_netif == netif) {
5561         loc_netif = loc_netif->next;
5562         continue;
5563       }
5564       if (ip_addr_cmp(&netif->netmask, &loc_netif->netmask) &&
5565           ip_addr_netcmp_val(loc_netif->ip_addr, taget_addr, ip_2_ip4(&netif->netmask))) {
5566         return EINVAL;
5567       }
5568       loc_netif = loc_netif->next;
5569     }
5570 
5571 #if LWIP_DHCP
5572     if (netif_dhcp_data(netif) &&
5573         (netif_dhcp_data(netif)->client.states[LWIP_DHCP_NATIVE_IDX].state != DHCP_STATE_OFF)) {
5574       (void)netif_dhcp_off(netif);
5575     }
5576 #endif
5577 
5578 #if LWIP_ARP
5579     /* clear ARP cache when IP address changed */
5580     if (netif->flags & NETIF_FLAG_ETHARP) {
5581       etharp_cleanup_netif(netif);
5582     }
5583 #endif /* LWIP_ARP */
5584 
5585     netif_set_ipaddr(netif, ip_2_ip4(&taget_addr));
5586 
5587     return 0;
5588   }
5589 }
5590 
5591 #if LWIP_IPV6
lwip_ioctl_internal_SIOCDIFADDR_6(struct ifreq * ifr)5592 static u8_t lwip_ioctl_internal_SIOCDIFADDR_6(struct ifreq *ifr)
5593 {
5594   struct netif *netif = NULL;
5595   err_t err;
5596   struct in6_ifreq *ifr6 = NULL;
5597   ip_addr_t target_addr;
5598   s8_t idx;
5599 
5600 #if LWIP_ENABLE_NET_CAPABILITY
5601   LWIP_ERROR("lwip_ioctl_internal_SIOCDIFADDR_6: Have no permission CAP_NET_ADMIN",
5602              IsCapPermit(CAP_NET_ADMIN), return EPERM);
5603 #endif
5604 
5605   ifr6 = (struct in6_ifreq *)ifr;
5606 
5607   /* Supports only fixed length LWIP_IPV6_PREFIX_LEN of prefix */
5608   if ((ifr6->ifr6_prefixlen != LWIP_IPV6_PREFIX_LEN) ||
5609       (ifr6->ifr6_ifindex > LWIP_NETIF_IFINDEX_MAX)) {
5610     return EINVAL;
5611   }
5612 
5613   netif = netif_get_by_index((u8_t)ifr6->ifr6_ifindex);
5614   if (netif == NULL) {
5615     return ENODEV;
5616   }
5617 #if LWIP_HAVE_LOOPIF
5618   /* Most likely unhittable code.. since loopif is global address.. remove code after confirmation */
5619   else if (netif->link_layer_type == LOOPBACK_IF) {
5620     return EPERM;
5621   }
5622 #endif
5623 
5624   ip_addr_set_zero_ip6_val(target_addr);
5625   inet6_addr_to_ip6addr(ip_2_ip6(&target_addr), &ifr6->ifr6_addr);
5626 
5627   /* It should not be loopback address */
5628   if (ip_addr_isloopback_val(target_addr)) {
5629     return EINVAL;
5630   }
5631 
5632   /* Allow deletion of existing IPv6 address.... only limitation is, it does not allow removal of link local address */
5633   idx = netif_get_ip6_addr_match(netif, ip_2_ip6(&target_addr));
5634   if (idx < 0) {
5635     return EADDRNOTAVAIL;
5636   }
5637 
5638   /* Removal of link local address not permitted */
5639   if (idx == 0) {
5640     return EPERM;
5641   }
5642 
5643 #if LWIP_IPV6_DHCP6
5644   if (netif_dhcp6_data(netif) && netif_dhcp6_data(netif)->state != DHCP6_STATE_OFF) {
5645     dhcp6_disable(netif);
5646   }
5647 #endif
5648 
5649   err = netif_do_rmv_ipv6_addr(netif, ip_2_ip6(&target_addr));
5650   if ((err != ERR_OK) || (idx == -1)) {
5651     return ENOBUFS;
5652   }
5653 
5654   return ERR_OK;
5655 }
5656 #endif
5657 
lwip_ioctl_internal_SIOCDIFADDR(const struct ifreq * ifr)5658 static u8_t lwip_ioctl_internal_SIOCDIFADDR(const struct ifreq *ifr)
5659 {
5660   struct netif *netif = NULL;
5661 
5662   ip_addr_t target_addr;
5663   u16_t target_port;
5664 
5665   SOCKADDR_TO_IPADDR_PORT(&ifr->ifr_addr, &target_addr, target_port);
5666   LWIP_UNUSED_ARG(target_port);
5667 
5668 #if LWIP_ENABLE_NET_CAPABILITY
5669   LWIP_ERROR("lwip_ioctl_internal_SIOCDIFADDR: Have no permission CAP_NET_ADMIN",
5670              IsCapPermit(CAP_NET_ADMIN), return EPERM);
5671 #endif
5672 
5673   /* set netif ipaddr */
5674   netif = netif_find(ifr->ifr_name);
5675   if (netif == NULL) {
5676     return ENODEV;
5677   }
5678 #if LWIP_HAVE_LOOPIF
5679   else if (netif->link_layer_type == LOOPBACK_IF) {
5680     return EPERM;
5681   }
5682 #endif
5683 
5684    /* check the address is not loopback */
5685   if (!IP_IS_V4_VAL(target_addr) || ip_addr_isloopback_val(target_addr)) {
5686     return EINVAL;
5687   }
5688 
5689 #if LWIP_DHCP
5690   if (netif_dhcp_data(netif) &&
5691       (netif_dhcp_data(netif)->client.states[LWIP_DHCP_NATIVE_IDX].state != DHCP_STATE_OFF)) {
5692     (void)netif_dhcp_off(netif);
5693   }
5694 #endif
5695 
5696   ip_addr_set_zero_val(netif->gw);
5697   ip_addr_set_zero_val(netif->ip_addr);
5698   ip_addr_set_zero_val(netif->netmask);
5699   if (netif == netif_default) {
5700     (void)netif_set_default(NULL);
5701   }
5702 
5703 #if LWIP_IPV4 && LWIP_ARP
5704   if (netif->flags & NETIF_FLAG_ETHARP) {
5705     etharp_cleanup_netif(netif);
5706   }
5707 #endif /* LWIP_IPV4 && LWIP_ARP */
5708 
5709   return ERR_OK;
5710 }
5711 
lwip_ioctl_internal_SIOCGIFBRDADDR(struct ifreq * ifr)5712 static u8_t lwip_ioctl_internal_SIOCGIFBRDADDR(struct ifreq *ifr)
5713 {
5714   struct netif *netif = NULL;
5715   struct sockaddr_in *sock_in = NULL;
5716 
5717   /* get netif subnet broadcast addr */
5718   netif = netif_find(ifr->ifr_name);
5719   if (netif == NULL) {
5720     return ENODEV;
5721   }
5722   if (ip4_addr_isany_val(*(ip_2_ip4(&netif->netmask)))) {
5723     return ENXIO;
5724   }
5725   sock_in = (struct sockaddr_in *)&ifr->ifr_addr;
5726   sock_in->sin_family = AF_INET;
5727   sock_in->sin_addr.s_addr = (ip_2_ip4(&((netif)->ip_addr))->addr | ~(ip_2_ip4(&netif->netmask)->addr));
5728   return 0;
5729 }
5730 
lwip_ioctl_internal_SIOCGIFNETMASK(struct ifreq * ifr)5731 static u8_t lwip_ioctl_internal_SIOCGIFNETMASK(struct ifreq *ifr)
5732 {
5733   struct netif *netif = NULL;
5734   struct sockaddr_in *sock_in = NULL;
5735 
5736   /* get netif netmask */
5737   netif = netif_find(ifr->ifr_name);
5738   if (netif == NULL) {
5739     return ENODEV;
5740   } else {
5741     sock_in = (struct sockaddr_in *)&ifr->ifr_netmask;
5742     sock_in->sin_family = AF_INET;
5743     sock_in->sin_addr.s_addr = ip_2_ip4(&netif->netmask)->addr;
5744     return 0;
5745   }
5746 }
5747 
lwip_ioctl_internal_SIOCSIFNETMASK(const struct ifreq * ifr)5748 static u8_t lwip_ioctl_internal_SIOCSIFNETMASK(const struct ifreq *ifr)
5749 {
5750   struct netif *netif = NULL;
5751 
5752   struct netif *loc_netif = NULL;
5753   ip_addr_t taget_addr;
5754   u16_t taget_port;
5755 
5756 #if LWIP_ENABLE_NET_CAPABILITY
5757   LWIP_ERROR("lwip_ioctl_internal_SIOCSIFNETMASK: Have no permission CAP_NET_ADMIN",
5758              IsCapPermit(CAP_NET_ADMIN), return EPERM);
5759 #endif
5760 
5761   SOCKADDR_TO_IPADDR_PORT(&ifr->ifr_addr, &taget_addr, taget_port);
5762   LWIP_UNUSED_ARG(taget_port);
5763 
5764   if (!IP_IS_V4_VAL(taget_addr)) {
5765     return EINVAL;
5766   }
5767 
5768   /* set netif netmask */
5769   netif = netif_find(ifr->ifr_name);
5770   if (netif == NULL) {
5771     return ENODEV;
5772   }
5773 #if LWIP_HAVE_LOOPIF
5774   else if (netif->link_layer_type == LOOPBACK_IF) {
5775     return EPERM;
5776   }
5777 #endif
5778   else {
5779     if (ip_addr_cmp(&netif->netmask, &taget_addr)) {
5780       return 0;
5781     }
5782     /* check data valid */
5783     if (!ip_addr_netmask_valid(ip_2_ip4(&taget_addr))) {
5784       return EINVAL;
5785     }
5786 
5787     /* lwip disallow two netif sit in same net at the same time */
5788     loc_netif = netif_list;
5789     while (loc_netif != NULL) {
5790       if (loc_netif == netif) {
5791         loc_netif = loc_netif->next;
5792         continue;
5793       }
5794       if (ip_addr_cmp(&loc_netif->netmask, &taget_addr) &&
5795           ip_addr_netcmp_val(loc_netif->ip_addr, netif->ip_addr, ip_2_ip4(&loc_netif->netmask))) {
5796         return EINVAL;
5797       }
5798       loc_netif = loc_netif->next;
5799     }
5800 
5801 #if LWIP_DHCP // LWIP_DHCP
5802     if (netif_dhcp_data(netif) &&
5803         (netif_dhcp_data(netif)->client.states[LWIP_DHCP_NATIVE_IDX].state != DHCP_STATE_OFF)) {
5804       (void)netif_dhcp_off(netif);
5805     }
5806 #endif
5807 
5808     netif_set_netmask(netif, ip_2_ip4(&taget_addr));
5809 
5810     /* check if gateway still reachable */
5811     if (!ip_addr_netcmp_val(netif->gw, netif->ip_addr, ip_2_ip4(&taget_addr))) {
5812       ip_addr_set_zero_val(netif->gw);
5813       if (netif == netif_default) {
5814         (void)netif_set_default(NULL);
5815       }
5816     }
5817     return 0;
5818   }
5819 }
5820 
lwip_ioctl_internal_SIOCSIFHWADDR(const struct ifreq * ifr)5821 static u8_t lwip_ioctl_internal_SIOCSIFHWADDR(const struct ifreq *ifr)
5822 {
5823   struct netif *netif;
5824   err_t ret;
5825 
5826 #if LWIP_ENABLE_NET_CAPABILITY
5827   LWIP_ERROR("lwip_ioctl_internal_SIOCSIFHWADDR: Have no permission CAP_NET_ADMIN",
5828              IsCapPermit(CAP_NET_ADMIN), return EPERM);
5829 #endif
5830 
5831   /* set netif hw addr */
5832   netif = netif_find(ifr->ifr_name);
5833   if (netif == NULL) {
5834     return ENODEV;
5835   }
5836 #if LWIP_HAVE_LOOPIF
5837   else if (netif->link_layer_type == LOOPBACK_IF) {
5838     return EPERM;
5839   }
5840 #endif
5841   else {
5842 
5843     /* bring netif down to clear all Neighbor Cache Entry */
5844     (void)netif_set_down(netif);
5845 
5846     ret = netif_set_hwaddr(netif, (const unsigned char *)ifr->ifr_hwaddr.sa_data, netif->hwaddr_len);
5847 
5848     if (ret != ERR_OK) {
5849       (void)netif_set_up(netif);
5850       return (u8_t)err_to_errno(ret);
5851     }
5852 
5853     /* bring netif up to try to send GARP/IGMP/NA/MLD/RS. GARP and NA would
5854       make the neighboring nodes update their Neighbor Cache immediately. */
5855     (void)netif_set_up(netif);
5856     return 0;
5857   }
5858 }
5859 
lwip_ioctl_internal_SIOCGIFHWADDR(struct ifreq * ifr)5860 static u8_t lwip_ioctl_internal_SIOCGIFHWADDR(struct ifreq *ifr)
5861 {
5862   struct netif *netif = NULL;
5863 
5864   /* get netif hw addr */
5865   netif = netif_find(ifr->ifr_name);
5866   if (netif == NULL) {
5867     return ENODEV;
5868   }
5869 #if LWIP_HAVE_LOOPIF
5870   else if (netif->link_layer_type == LOOPBACK_IF) {
5871     return EPERM;
5872   }
5873 #endif /* LWIP_HAVE_LOOPIF */
5874   else {
5875     if (memcpy_s((void *)ifr->ifr_hwaddr.sa_data, sizeof(ifr->ifr_hwaddr.sa_data),
5876                  (void *)netif->hwaddr, netif->hwaddr_len) != EOK) {
5877       return EINVAL;
5878     }
5879     return 0;
5880   }
5881 }
5882 
lwip_ioctl_internal_SIOCSIFFLAGS(const struct ifreq * ifr)5883 static u8_t lwip_ioctl_internal_SIOCSIFFLAGS(const struct ifreq *ifr)
5884 {
5885   struct netif *netif = NULL;
5886 
5887 #if LWIP_ENABLE_NET_CAPABILITY
5888   LWIP_ERROR("lwip_ioctl_internal_SIOCSIFFLAGS: Have no permission CAP_NET_ADMIN",
5889              IsCapPermit(CAP_NET_ADMIN), return EPERM);
5890 #endif
5891 
5892   /* set netif hw addr */
5893   netif = netif_find(ifr->ifr_name);
5894   if (netif == NULL) {
5895     return ENODEV;
5896   }
5897 #if LWIP_HAVE_LOOPIF
5898   else if (netif->link_layer_type == LOOPBACK_IF) {
5899     return EPERM;
5900   }
5901 #endif /* LWIP_HAVE_LOOPIF */
5902   else {
5903     if ((ifr->ifr_flags & IFF_UP) && !(netif->flags & NETIF_FLAG_UP)) {
5904       (void)netif_set_up(netif);
5905     } else if (!(ifr->ifr_flags & IFF_UP) && (netif->flags & NETIF_FLAG_UP)) {
5906       (void)netif_set_down(netif);
5907     }
5908     if ((ifr->ifr_flags & IFF_RUNNING) && !(netif->flags & NETIF_FLAG_LINK_UP)) {
5909       (void)netif_set_link_up(netif);
5910     } else if (!(ifr->ifr_flags & IFF_RUNNING) && (netif->flags & NETIF_FLAG_LINK_UP)) {
5911       (void)netif_set_link_down(netif);
5912     }
5913 
5914     if (ifr->ifr_flags & IFF_BROADCAST) {
5915       netif->flags |= NETIF_FLAG_BROADCAST;
5916     } else {
5917       netif->flags = netif->flags & (~NETIF_FLAG_BROADCAST);
5918     }
5919     if (ifr->ifr_flags & IFF_NOARP) {
5920       netif->flags = (netif->flags & (~NETIF_FLAG_ETHARP));
5921     } else {
5922       netif->flags |= NETIF_FLAG_ETHARP;
5923     }
5924 
5925     if (ifr->ifr_flags & IFF_MULTICAST) {
5926 #if LWIP_IGMP
5927       netif->flags |= NETIF_FLAG_IGMP;
5928 #endif /* LWIP_IGMP */
5929 #if LWIP_IPV6 && LWIP_IPV6_MLD
5930       netif->flags |= NETIF_FLAG_MLD6;
5931 #endif /* LWIP_IPV6_MLD */
5932     }
5933     else {
5934 #if LWIP_IGMP
5935       netif->flags = (netif->flags &  ~NETIF_FLAG_IGMP);
5936 #endif /* LWIP_IGMP */
5937 #if LWIP_IPV6 && LWIP_IPV6_MLD
5938       netif->flags = (netif->flags &  ~NETIF_FLAG_MLD6);
5939 #endif /* LWIP_IPV6_MLD */
5940     }
5941 
5942 #if LWIP_DHCP
5943     if (ifr->ifr_flags & IFF_DYNAMIC) {
5944       (void)dhcp_start(netif);
5945     } else {
5946       dhcp_stop(netif);
5947 #if !LWIP_DHCP_SUBSTITUTE
5948       dhcp_cleanup(netif);
5949 #endif
5950     }
5951 #endif
5952 
5953 #if LWIP_NETIF_PROMISC
5954     if ((ifr->ifr_flags & IFF_PROMISC)) {
5955       netif_update_promiscuous_mode_status(netif, 1);
5956     } else {
5957       netif_update_promiscuous_mode_status(netif, 0);
5958     }
5959 #endif /* LWIP_NETIF_PROMISC */
5960     return 0;
5961   }
5962 }
5963 
lwip_ioctl_internal_SIOCGIFFLAGS(struct ifreq * ifr)5964 static u8_t lwip_ioctl_internal_SIOCGIFFLAGS(struct ifreq *ifr)
5965 {
5966   struct netif *netif = NULL;
5967 
5968   /* set netif hw addr */
5969   netif = netif_find(ifr->ifr_name);
5970   if (netif == NULL) {
5971     return ENODEV;
5972   } else {
5973     if (netif->flags & NETIF_FLAG_UP) {
5974       ifr->ifr_flags |= IFF_UP;
5975     } else {
5976       ifr->ifr_flags &= ~IFF_UP;
5977     }
5978     if (netif->flags & NETIF_FLAG_LINK_UP) {
5979       ifr->ifr_flags |= IFF_RUNNING;
5980     } else {
5981       ifr->ifr_flags &= ~IFF_RUNNING;
5982     }
5983     if (netif->flags & NETIF_FLAG_BROADCAST) {
5984       ifr->ifr_flags |= IFF_BROADCAST;
5985     } else {
5986       ifr->ifr_flags &= ~IFF_BROADCAST;
5987     }
5988     if (netif->flags & NETIF_FLAG_ETHARP) {
5989       ifr->ifr_flags &= ~IFF_NOARP;
5990     } else {
5991       ifr->ifr_flags |= IFF_NOARP;
5992     }
5993 
5994 #if LWIP_IGMP || LWIP_IPV6_MLD
5995     if (
5996 #if LWIP_IGMP
5997       (netif->flags & NETIF_FLAG_IGMP)
5998 #endif /* LWIP_IGMP */
5999 #if LWIP_IGMP && LWIP_IPV6_MLD
6000       ||
6001 #endif /* LWIP_IGMP && LWIP_IPV6_MLD */
6002 #if LWIP_IPV6_MLD
6003       (netif->flags & NETIF_FLAG_MLD6)
6004 #endif /* LWIP_IPV6_MLD */
6005         ) {
6006       ifr->ifr_flags = (short)((unsigned short)ifr->ifr_flags | IFF_MULTICAST);
6007     } else {
6008       ifr->ifr_flags = (short)((unsigned short)ifr->ifr_flags & (~IFF_MULTICAST));
6009     }
6010 #endif /* LWIP_IGMP || LWIP_IPV6_MLD */
6011 
6012 #if LWIP_DHCP
6013     if (netif->flags & NETIF_FLAG_DHCP) {
6014       ifr->ifr_flags = (short)((unsigned short)ifr->ifr_flags | IFF_DYNAMIC);
6015     } else {
6016       ifr->ifr_flags = (short)((unsigned short)ifr->ifr_flags & (~IFF_DYNAMIC));
6017     }
6018 #endif
6019 
6020 #if LWIP_HAVE_LOOPIF
6021     if (netif->link_layer_type == LOOPBACK_IF) {
6022       ifr->ifr_flags |= IFF_LOOPBACK;
6023     }
6024 #endif
6025 
6026 #if LWIP_NETIF_PROMISC
6027     if (atomic_read(&(netif->flags_ext)) == NETIF_FLAG_PROMISC) {
6028       ifr->ifr_flags |= IFF_PROMISC;
6029     } else {
6030       ifr->ifr_flags &= ~IFF_PROMISC;
6031     }
6032 #endif /* LWIP_NETIF_PROMISC */
6033 
6034     return 0;
6035   }
6036 }
6037 
lwip_ioctl_internal_SIOCGIFNAME(struct ifreq * ifr)6038 static u8_t lwip_ioctl_internal_SIOCGIFNAME(struct ifreq *ifr)
6039 {
6040   struct netif *netif = NULL;
6041   int ret;
6042 
6043   for (netif = netif_list; netif != NULL; netif = netif->next) {
6044     if (ifr->ifr_ifindex == netif->ifindex) {
6045       break;
6046     }
6047   }
6048 
6049   if (netif == NULL) {
6050     return ENODEV;
6051   } else {
6052     if (netif->link_layer_type == LOOPBACK_IF) {
6053       ret = snprintf_s(ifr->ifr_name, NETIF_NAMESIZE, (NETIF_NAMESIZE - 1), "%s", netif->name);
6054       if ((ret <= 0) || (ret >= NETIF_NAMESIZE)) {
6055         return ENOBUFS;
6056       }
6057     } else {
6058       ret = snprintf_s(ifr->ifr_name, NETIF_NAMESIZE, (NETIF_NAMESIZE - 1), "%s%"U8_F, netif->name, netif->num);
6059       if ((ret <= 0) || (ret >= NETIF_NAMESIZE)) {
6060         return ENOBUFS;
6061       }
6062     }
6063     return 0;
6064   }
6065 }
6066 
lwip_validate_ifname(const char * name,u8_t * let_pos)6067 static u8_t lwip_validate_ifname(const char *name, u8_t *let_pos)
6068 {
6069   unsigned short num_pos = 0;
6070   unsigned short letter_pos = 0;
6071   unsigned short pos = 0;
6072   u8_t have_num = 0;
6073 
6074   /* if the first position of variable name is not letter, such as '6eth2' */
6075   if (!((*name >= 'a' && *name <= 'z') || (*name >= 'A' && *name <= 'Z'))) {
6076     return 0;
6077   }
6078 
6079   /* check if the position of letter is bigger than the the position of digital */
6080   while (*name != '\0') {
6081     if (*name >= '0' && *name <= '9') {
6082       num_pos = pos;
6083       have_num = 1;
6084     } else if ((*name >= 'a' && *name <= 'z') || (*name >= 'A' && *name <= 'Z')) {
6085       letter_pos = pos;
6086       if (have_num) {
6087         return 0;
6088       }
6089     } else {
6090       return 0;
6091     }
6092     pos++;
6093     name++;
6094   }
6095 
6096   /* for the speacil case as all position of variable name is letter, such as 'ethabc' */
6097   if (num_pos == 0) {
6098       return 0;
6099   }
6100 
6101   /* cheak if the digital in the variable name is bigger than 255, such as 'eth266' */
6102   if (atoi(name - (pos - letter_pos - 1)) > 255) {
6103     return 0;
6104   }
6105 
6106   *let_pos = (u8_t)letter_pos;
6107 
6108   return 1;
6109 }
6110 
lwip_ioctl_internal_SIOCSIFNAME(struct ifreq * ifr)6111 static u8_t lwip_ioctl_internal_SIOCSIFNAME(struct ifreq *ifr)
6112 {
6113   struct netif *netif = NULL;
6114   char name[NETIF_NAMESIZE];
6115   s32_t num = 0;
6116   u8_t letter_pos = 0;
6117 
6118 #if LWIP_ENABLE_NET_CAPABILITY
6119   LWIP_ERROR("lwip_ioctl_internal_SIOCSIFNAME: Have no permission CAP_NET_ADMIN",
6120              IsCapPermit(CAP_NET_ADMIN), return EPERM);
6121 #endif
6122 
6123   netif = netif_find(ifr->ifr_name);
6124 
6125   if (netif == NULL) {
6126     return  ENODEV;
6127   } else if (netif->link_layer_type == LOOPBACK_IF) {
6128     return EPERM;
6129   } else if (netif->flags & IFF_UP) {
6130     return EBUSY;
6131   } else {
6132     ifr->ifr_newname[NETIF_NAMESIZE - 1] = '\0';
6133     if (!lwip_validate_ifname(ifr->ifr_newname, &letter_pos) || strlen(ifr->ifr_newname) > (NETIF_NAMESIZE - 1)) {
6134       return EINVAL;
6135     }
6136 
6137     (void)memset_s(name, NETIF_NAMESIZE, 0, NETIF_NAMESIZE);
6138     (void)strncpy_s(name, NETIF_NAMESIZE, ifr->ifr_newname, strlen(ifr->ifr_newname));
6139 
6140     num = atoi(name + letter_pos + 1);
6141     if (num > 0xFF || num < 0) {
6142       return EINVAL;
6143     }
6144 
6145     name[letter_pos + 1] = '\0';
6146     if (netif_check_num_isusing(name, (u8_t)num) == 1) {
6147       return EINVAL;
6148     }
6149 
6150     if (strncpy_s(netif->name, sizeof(netif->name), name, strlen(name)) != EOK) {
6151       return EINVAL;
6152     }
6153     netif->name[strlen(name)] = '\0';
6154     netif->num = (u8_t)num;
6155   }
6156 
6157   return 0;
6158 }
6159 
lwip_ioctl_internal_SIOCGIFINDEX(struct ifreq * ifr)6160 static u8_t lwip_ioctl_internal_SIOCGIFINDEX(struct ifreq *ifr)
6161 {
6162   struct netif *netif = NULL;
6163 
6164   netif = netif_find(ifr->ifr_name);
6165   if (netif == NULL) {
6166     return ENODEV;
6167   } else {
6168     ifr->ifr_ifindex = netif->ifindex;
6169     return 0;
6170   }
6171 }
6172 
lwip_ioctl_internal_SIOCSIFMTU(const struct ifreq * ifr)6173 static u8_t lwip_ioctl_internal_SIOCSIFMTU(const struct ifreq *ifr)
6174 {
6175   struct netif *netif = NULL;
6176 
6177 #if LWIP_ENABLE_NET_CAPABILITY
6178   LWIP_ERROR("lwip_ioctl_internal_SIOCSIFMTU: Have no permission CAP_NET_ADMIN",
6179              IsCapPermit(CAP_NET_ADMIN), return EPERM);
6180 #endif
6181 
6182   /* set netif hw addr */
6183   netif = netif_find(ifr->ifr_name);
6184   if (netif == NULL) {
6185     return ENODEV;
6186   }
6187 #if LWIP_HAVE_LOOPIF
6188   /* the mtu of loopif is not used. */
6189   else if (netif->link_layer_type == LOOPBACK_IF) {
6190     return EPERM;
6191   }
6192 #endif
6193   else {
6194     if (ERR_OK != netif_set_mtu(netif, (u16_t)ifr->ifr_mtu)) {
6195       return EINVAL;
6196     }
6197 
6198     return 0;
6199   }
6200 }
6201 
lwip_ioctl_internal_SIOCGIFMTU(struct ifreq * ifr)6202 static u8_t lwip_ioctl_internal_SIOCGIFMTU(struct ifreq *ifr)
6203 {
6204   struct netif *netif = NULL;
6205 
6206   /* get netif hw addr */
6207   netif = netif_find(ifr->ifr_name);
6208 
6209   if (netif == NULL) {
6210     return ENODEV;
6211   } else {
6212     ifr->ifr_mtu = netif->mtu;
6213     return 0;
6214   }
6215 }
6216 #endif /* LWIP_IOCTL_IF */
6217 
6218 #if LWIP_NETIF_ETHTOOL
lwip_ioctl_internal_SIOCETHTOOL(struct ifreq * ifr)6219 static s32_t lwip_ioctl_internal_SIOCETHTOOL(struct ifreq *ifr)
6220 {
6221   struct netif *netif = NULL;
6222 
6223 #if LWIP_ENABLE_NET_CAPABILITY
6224   LWIP_ERROR("lwip_ioctl_internal_SIOCETHTOOL: Have no permission CAP_NET_ADMIN",
6225              IsCapPermit(CAP_NET_ADMIN), return EPERM);
6226 #endif
6227 
6228   netif = netif_find(ifr->ifr_name);
6229   if (netif == NULL) {
6230     return ENODEV;
6231   } else {
6232     return dev_ethtool(netif, ifr);
6233   }
6234 }
6235 #endif
6236 
6237 #if LWIP_SO_RCVBUF || LWIP_FIONREAD_LINUXMODE
lwip_ioctl_internal_FIONREAD(struct lwip_sock * sock,void * argp)6238 static u8_t lwip_ioctl_internal_FIONREAD(struct lwip_sock *sock, void *argp)
6239 {
6240 #if LWIP_SO_RCVBUF
6241   int recv_avail;
6242 #endif
6243 #if LWIP_FIONREAD_LINUXMODE
6244   SYS_ARCH_DECL_PROTECT(lev);
6245 #endif
6246 
6247   if (!argp) {
6248     return EINVAL;
6249   }
6250 
6251   lwip_sock_lock(sock);
6252 #if LWIP_FIONREAD_LINUXMODE
6253   if (NETCONNTYPE_GROUP(NETCONN_TYPE(sock->conn)) != NETCONN_TCP) {
6254     struct netbuf *nb;
6255     if (sock->lastdata.netbuf) {
6256       nb = sock->lastdata.netbuf;
6257       *((int *)argp) = nb->p->tot_len;
6258     } else {
6259       struct netbuf *rxbuf;
6260       err_t err;
6261 
6262       SYS_ARCH_PROTECT(lev);
6263       if (sock->rcvevent <= 0) {
6264         *((int*)argp) = 0;
6265         SYS_ARCH_UNPROTECT(lev);
6266       } else {
6267         SYS_ARCH_UNPROTECT(lev);
6268         err = netconn_recv_udp_raw_netbuf_flags(sock->conn, &rxbuf, NETCONN_DONTBLOCK);
6269         if (err != ERR_OK) {
6270           *((int *)argp) = 0;
6271         } else {
6272           sock->lastdata.netbuf = rxbuf;
6273           *((int *)argp) = rxbuf->p->tot_len;
6274         }
6275       }
6276     }
6277 
6278     lwip_sock_unlock(sock);
6279     return 0;
6280   }
6281 #endif /* LWIP_FIONREAD_LINUXMODE */
6282 
6283 #if LWIP_SO_RCVBUF
6284   /* we come here if either LWIP_FIONREAD_LINUXMODE==0 or this is a TCP socket */
6285   SYS_ARCH_GET(sock->conn->recv_avail, recv_avail);
6286   if (recv_avail < 0) {
6287     recv_avail = 0;
6288   }
6289 
6290   /* Check if there is data left from the last recv operation. /maq 041215 */
6291   if (sock->lastdata.netbuf) {
6292     if (NETCONNTYPE_GROUP(NETCONN_TYPE(sock->conn)) == NETCONN_TCP) {
6293       recv_avail += sock->lastdata.pbuf->tot_len;
6294     } else {
6295       recv_avail += sock->lastdata.netbuf->p->tot_len;
6296     }
6297   }
6298   *((int *)argp) = recv_avail;
6299 
6300   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(FIONREAD, %p) = %"U16_F"\n", argp, *((u16_t *)argp)));
6301   lwip_sock_unlock(sock);
6302   return 0;
6303 #else /* LWIP_SO_RCVBUF */
6304   lwip_sock_unlock(sock);
6305   return ENOSYS;
6306 #endif /* LWIP_SO_RCVBUF */
6307 }
6308 #endif /* LWIP_SO_RCVBUF || LWIP_FIONREAD_LINUXMODE */
6309 
lwip_ioctl_internal_FIONBIO(struct lwip_sock * sock,const void * argp)6310 static u8_t lwip_ioctl_internal_FIONBIO(struct lwip_sock *sock, const void *argp)
6311 {
6312   u8_t val = 0;
6313   SYS_ARCH_DECL_PROTECT(lev);
6314   if (argp == NULL) {
6315     return EINVAL;
6316   }
6317   if (*(int *)argp) {
6318     val = 1;
6319   }
6320   SYS_ARCH_PROTECT(lev);
6321   netconn_set_nonblocking(sock->conn, val);
6322   SYS_ARCH_UNPROTECT(lev);
6323   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(FIONBIO, %d)\n", val));
6324   return 0;
6325 }
6326 
6327 #if LWIP_IPV6
6328 #if LWIP_IPV6_DUP_DETECT_ATTEMPTS
lwip_ioctl_internal_SIOCSIPV6DAD(const struct ifreq * ifr)6329 static u8_t lwip_ioctl_internal_SIOCSIPV6DAD(const struct ifreq *ifr)
6330 {
6331 #if LWIP_ENABLE_NET_CAPABILITY
6332   LWIP_ERROR("lwip_ioctl_internal_SIOCSIPV6DAD: Have no permission CAP_NET_ADMIN",
6333              IsCapPermit(CAP_NET_ADMIN), return EPERM);
6334 #endif
6335   struct netif *tmpnetif = netif_find(ifr->ifr_name);
6336   if (tmpnetif == NULL) {
6337     LWIP_DEBUGF(SOCKETS_DEBUG, ("Interface not found.\n"));
6338     return ENODEV;
6339   }
6340 
6341   if ((ifr->ifr_ifru.ifru_ivalue != 0) && (ifr->ifr_ifru.ifru_ivalue != 1)) {
6342     LWIP_DEBUGF(SOCKETS_DEBUG, ("Invalid ioctl argument(ifru_ivalue 0/1).\n"));
6343     return EBADRQC;
6344   }
6345 
6346   if (ifr->ifr_ifru.ifru_ivalue == 1) {
6347     tmpnetif->ipv6_flags = (tmpnetif->ipv6_flags | LWIP_IPV6_ND6_FLAG_DAD);
6348 
6349     LWIP_DEBUGF(SOCKETS_DEBUG, ("DAD turned on through ioctl for  %s iface index %u \n",
6350       tmpnetif->name, tmpnetif->num));
6351   } else {
6352     tmpnetif->ipv6_flags = (tmpnetif->ipv6_flags & ((~LWIP_IPV6_ND6_FLAG_DAD) & 0xffU));
6353 
6354     LWIP_DEBUGF(SOCKETS_DEBUG, ("DAD turned off through ioctl for  %s iface index %u \n",
6355       tmpnetif->name, tmpnetif->num));
6356   }
6357   return 0;
6358 }
6359 
lwip_ioctl_internal_SIOCGIPV6DAD(struct ifreq * ifr)6360 static u8_t lwip_ioctl_internal_SIOCGIPV6DAD(struct ifreq *ifr)
6361 {
6362   struct netif *tmpnetif = netif_find(ifr->ifr_name);
6363   if (tmpnetif == NULL) {
6364     LWIP_DEBUGF(SOCKETS_DEBUG, ("Interface not found.\n"));
6365     return ENODEV;
6366   }
6367   ifr->ifr_ifru.ifru_ivalue = (tmpnetif->ipv6_flags & LWIP_IPV6_ND6_FLAG_DAD) ? 1 : 0;
6368   return 0;
6369 }
6370 #endif
6371 
6372 #if LWIP_IOCTL_IPV6DPCTD
lwip_ioctl_internal_SIOCSIPV6DPCTD(const struct ifreq * ifr)6373 static u8_t lwip_ioctl_internal_SIOCSIPV6DPCTD(const struct ifreq *ifr)
6374 {
6375 #if LWIP_ENABLE_NET_CAPABILITY
6376   LWIP_ERROR("lwip_ioctl_internal_SIOCSIPV6DPCTD: Have no permission CAP_NET_ADMIN",
6377              IsCapPermit(CAP_NET_ADMIN), return EPERM);
6378 #endif
6379   struct netif *tmpnetif = netif_find(ifr->ifr_name);
6380   if (tmpnetif == NULL) {
6381     LWIP_DEBUGF(SOCKETS_DEBUG, ("Interface not found.\n"));
6382     return ENODEV;
6383   }
6384   if ((ifr->ifr_ifru.ifru_ivalue != 0) && (ifr->ifr_ifru.ifru_ivalue != 1)) {
6385     LWIP_DEBUGF(SOCKETS_DEBUG, ("Invalid ioctl argument(ifru_ivalue 0/1).\n"));
6386     return EBADRQC;
6387   }
6388   if (ifr->ifr_ifru.ifru_ivalue == 1) {
6389     tmpnetif->ipv6_flags = (tmpnetif->ipv6_flags | LWIP_IPV6_ND6_FLAG_DEPRECATED);
6390     LWIP_DEBUGF(SOCKETS_DEBUG, ("Deprecation turned on through ioctl for  %s iface index %u \n",
6391       tmpnetif->name, tmpnetif->num));
6392   } else {
6393     tmpnetif->ipv6_flags = (tmpnetif->ipv6_flags & ((~LWIP_IPV6_ND6_FLAG_DEPRECATED) & 0xffU));
6394     LWIP_DEBUGF(SOCKETS_DEBUG, ("Deprecation turned off through ioctl for  %s iface index %u \n",
6395       tmpnetif->name, tmpnetif->num));
6396   }
6397   return 0;
6398 }
6399 
lwip_ioctl_internal_SIOCGIPV6DPCTD(struct ifreq * ifr)6400 static u8_t lwip_ioctl_internal_SIOCGIPV6DPCTD(struct ifreq *ifr)
6401 {
6402   struct netif *tmpnetif = netif_find(ifr->ifr_name);
6403   if (tmpnetif == NULL) {
6404     LWIP_DEBUGF(SOCKETS_DEBUG, ("Interface not found.\n"));
6405     return ENODEV;
6406   }
6407 
6408   ifr->ifr_ifru.ifru_ivalue = (tmpnetif->ipv6_flags & LWIP_IPV6_ND6_FLAG_DEPRECATED) ? 1 : 0;
6409   return 0;
6410 }
6411 #endif /* LWIP_IOCTL_IPV6DPCTD */
6412 #endif
lwip_ioctl_impl(struct lwip_sock * sock,long cmd,void * argp)6413 static u8_t lwip_ioctl_impl(struct lwip_sock *sock, long cmd, void *argp)
6414 {
6415   u8_t err = 0;
6416 #if LWIP_NETIF_ETHTOOL
6417   s32_t ret;
6418 #endif
6419 #if LWIP_IPV6_DUP_DETECT_ATTEMPTS || LWIP_IOCTL_IPV6DPCTD || LWIP_IOCTL_IF || LWIP_NETIF_ETHTOOL
6420   struct ifreq *ifr = (struct ifreq *)argp;
6421 #endif
6422 #if LWIP_IOCTL_ROUTE
6423   struct rtentry *rmten = (struct rtentry *)argp;
6424 #endif
6425 #if LWIP_IPV6_DUP_DETECT_ATTEMPTS || LWIP_IOCTL_IPV6DPCTD || LWIP_IOCTL_ROUTE || LWIP_IOCTL_IF
6426   u8_t is_ipv6 = NETCONNTYPE_ISIPV6(sock->conn->type);
6427 #endif
6428 
6429   LWIP_ASSERT("no socket given", sock != NULL);
6430 
6431   switch (cmd) {
6432 #if LWIP_IPV6
6433 #if LWIP_IPV6_DUP_DETECT_ATTEMPTS
6434     case SIOCSIPV6DAD:
6435       /* allow it only on IPv6 sockets... */
6436       if (!is_ipv6) {
6437         err = EINVAL;
6438       } else {
6439         err = lwip_ioctl_internal_SIOCSIPV6DAD(ifr);
6440       }
6441       break;
6442     case SIOCGIPV6DAD:
6443       /* allow it only on IPv6 sockets... */
6444       if (!is_ipv6) {
6445         err = EINVAL;
6446       } else {
6447         err = lwip_ioctl_internal_SIOCGIPV6DAD(ifr);
6448       }
6449       break;
6450 #endif /* LWIP_IPV6_DUP_DETECT_ATTEMPTS */
6451 #if LWIP_IOCTL_IPV6DPCTD
6452     case SIOCSIPV6DPCTD:
6453       /* allow it only on IPv6 sockets... */
6454       if (!is_ipv6) {
6455         err = EINVAL;
6456       } else {
6457         err = lwip_ioctl_internal_SIOCSIPV6DPCTD(ifr);
6458       }
6459       break;
6460     case SIOCGIPV6DPCTD:
6461       /* allow it only on IPv6 sockets... */
6462       if (!is_ipv6) {
6463         err = EINVAL;
6464       } else {
6465         err = lwip_ioctl_internal_SIOCGIPV6DPCTD(ifr);
6466       }
6467       break;
6468 #endif /* LWIP_IOCTL_IPV6DPCTD */
6469 #endif /* LWIP_IPV6 */
6470 #if LWIP_IOCTL_ROUTE
6471     case SIOCADDRT:
6472       /* Do not allow if socket is AF_INET6 */
6473       if (is_ipv6) {
6474         err = EINVAL;
6475       } else {
6476         err = lwip_ioctl_internal_SIOCADDRT(rmten);
6477       }
6478       break;
6479 #endif
6480 #if LWIP_IOCTL_IF
6481     case SIOCGIFCONF:
6482       /* Do not allow if socket is AF_INET6 */
6483       if (is_ipv6) {
6484         err = EINVAL;
6485       } else {
6486         err = lwip_ioctl_internal_SIOCGIFCONF(ifr);
6487       }
6488       break;
6489     case SIOCGIFADDR:
6490       if (is_ipv6) {
6491         err = EINVAL;
6492       } else {
6493         err = lwip_ioctl_internal_SIOCGIFADDR(ifr);
6494       }
6495       break;
6496     case SIOCSIFADDR:
6497 #if LWIP_IPV6
6498       if (is_ipv6) {
6499         err = lwip_ioctl_internal_SIOCSIFADDR_6(ifr);
6500       }
6501       else
6502 #endif
6503       {
6504         err = lwip_ioctl_internal_SIOCSIFADDR(ifr);
6505       }
6506       break;
6507     case SIOCDIFADDR:
6508       /* Delete interface address */
6509 #if LWIP_IPV6
6510       if (is_ipv6) {
6511         err = lwip_ioctl_internal_SIOCDIFADDR_6(ifr);
6512       }
6513       else
6514 #endif
6515       {
6516         err = lwip_ioctl_internal_SIOCDIFADDR(ifr);
6517       }
6518       break;
6519     case SIOCGIFBRDADDR:
6520       if (is_ipv6) {
6521         err = EINVAL;
6522       } else {
6523         err = lwip_ioctl_internal_SIOCGIFBRDADDR(ifr);
6524       }
6525       break;
6526     case SIOCGIFNETMASK:
6527       if (is_ipv6) {
6528         err = EINVAL;
6529       } else {
6530         err = lwip_ioctl_internal_SIOCGIFNETMASK(ifr);
6531       }
6532       break;
6533     case SIOCSIFNETMASK:
6534       if (is_ipv6) {
6535         err = EINVAL;
6536       } else {
6537         err = lwip_ioctl_internal_SIOCSIFNETMASK(ifr);
6538       }
6539       break;
6540     case SIOCSIFHWADDR:
6541       err = lwip_ioctl_internal_SIOCSIFHWADDR(ifr);
6542       break;
6543     case SIOCGIFHWADDR:
6544       err = lwip_ioctl_internal_SIOCGIFHWADDR(ifr);
6545       break;
6546     case SIOCSIFFLAGS:
6547       err = lwip_ioctl_internal_SIOCSIFFLAGS(ifr);
6548       break;
6549     case SIOCGIFFLAGS:
6550       err = lwip_ioctl_internal_SIOCGIFFLAGS(ifr);
6551       break;
6552     case SIOCGIFNAME:
6553       err = lwip_ioctl_internal_SIOCGIFNAME(ifr);
6554       break;
6555     case SIOCSIFNAME:
6556       err = lwip_ioctl_internal_SIOCSIFNAME(ifr);
6557       break;
6558     /* Need to support the get index through ioctl
6559      * As of now the options is restricted to PF_PACKET scenario , so removed the compiler flag Begin
6560      */
6561     case SIOCGIFINDEX:
6562       err = lwip_ioctl_internal_SIOCGIFINDEX(ifr);
6563       break;
6564     case SIOCGIFMTU:
6565       err = lwip_ioctl_internal_SIOCGIFMTU(ifr);
6566       break;
6567     case SIOCSIFMTU:
6568       err = lwip_ioctl_internal_SIOCSIFMTU(ifr);
6569       break;
6570 #endif /* LWIP_IOCTL_IF */
6571 
6572 #if LWIP_NETIF_ETHTOOL
6573     case SIOCETHTOOL:
6574       ret = lwip_ioctl_internal_SIOCETHTOOL(ifr);
6575       if (ret != 0) {
6576         /* an IO error happened */
6577         err = EIO;
6578       }
6579       break;
6580 #endif
6581 
6582 #if LWIP_SO_RCVBUF || LWIP_FIONREAD_LINUXMODE
6583     case FIONREAD:
6584       err = lwip_ioctl_internal_FIONREAD(sock, argp);
6585       break;
6586 #endif /* LWIP_SO_RCVBUF || LWIP_FIONREAD_LINUXMODE */
6587 
6588     case FIONBIO:
6589       err = lwip_ioctl_internal_FIONBIO(sock, argp);
6590       break;
6591     /* -1 should return EINVAL */
6592     case -1:
6593       err = EINVAL;
6594       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl_impl(INVALID: 0x%lx)\n", cmd));
6595       break;
6596     default:
6597       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(UNIMPL: 0x%lx, %p)\n", cmd, argp));
6598       err = ENOSYS; /* not yet implemented */
6599       break;
6600   } /* switch (cmd) */
6601 
6602   return err;
6603 }
6604 
6605 int
lwip_ioctl(int s,long cmd,void * argp)6606 lwip_ioctl(int s, long cmd, void *argp)
6607 {
6608   u8_t err;
6609   struct lwip_sock *sock = get_socket(s);
6610   if (!sock) {
6611     /* get_socket has updated errno */
6612     return -1;
6613   }
6614   if (argp == NULL) {
6615     sock_set_errno(sock, EFAULT);
6616     done_socket(sock);
6617     return -1;
6618   }
6619 
6620   LOCK_TCPIP_CORE();
6621   err = lwip_ioctl_impl(sock, cmd, argp);
6622   UNLOCK_TCPIP_CORE();
6623   if (err != ERR_OK) {
6624     LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(%d, cmd: 0x%lx, %p)\n", s, cmd, argp));
6625     sock_set_errno(sock, err);
6626   }
6627   done_socket(sock);
6628   return (err == 0) ? 0 : -1;
6629 }
6630 
6631 /** A minimal implementation of fcntl.
6632  * Currently only the commands F_GETFL and F_SETFL are implemented.
6633  * The flag O_NONBLOCK and access modes are supported for F_GETFL, only
6634  * the flag O_NONBLOCK is implemented for F_SETFL.
6635  */
6636 int
lwip_fcntl(int s,int cmd,int val)6637 lwip_fcntl(int s, int cmd, int val)
6638 {
6639   struct lwip_sock *sock = get_socket(s);
6640   int ret = -1;
6641   int op_mode = 0;
6642 
6643   if (!sock) {
6644     return -1;
6645   }
6646 
6647   switch (cmd) {
6648     case F_GETFL:
6649       ret = netconn_is_nonblocking(sock->conn) ? O_NONBLOCK : 0;
6650       sock_set_errno(sock, 0);
6651 
6652       if (NETCONNTYPE_GROUP(NETCONN_TYPE(sock->conn)) == NETCONN_TCP) {
6653 #if LWIP_TCPIP_CORE_LOCKING
6654         LOCK_TCPIP_CORE();
6655 #else
6656         SYS_ARCH_DECL_PROTECT(lev);
6657         /* the proper thing to do here would be to get into the tcpip_thread,
6658            but locking should be OK as well since we only *read* some flags */
6659         SYS_ARCH_PROTECT(lev);
6660 #endif
6661 #if LWIP_TCP
6662         if (sock->conn->pcb.tcp) {
6663           if (!(sock->conn->pcb.tcp->flags & TF_RXCLOSED)) {
6664             op_mode |= O_RDONLY;
6665           }
6666           if (!(sock->conn->pcb.tcp->flags & TF_FIN)) {
6667             op_mode |= O_WRONLY;
6668           }
6669         }
6670 #endif
6671 #if LWIP_TCPIP_CORE_LOCKING
6672         UNLOCK_TCPIP_CORE();
6673 #else
6674         SYS_ARCH_UNPROTECT(lev);
6675 #endif
6676       } else {
6677         op_mode |= O_RDWR;
6678       }
6679 
6680       /* ensure O_RDWR for (O_RDONLY|O_WRONLY) != O_RDWR cases */
6681       ret |= (op_mode == (O_RDONLY | O_WRONLY)) ? O_RDWR : op_mode;
6682 
6683       break;
6684     case F_SETFL:
6685       if (val < 0) {
6686         set_errno(EINVAL);
6687         done_socket(sock);
6688         return -1;
6689       }
6690       /* Bits corresponding to the file access mode and the file creation flags [..] that are set in arg shall be ignored */
6691       val &= ~(O_RDONLY | O_WRONLY | O_RDWR);
6692       if ((val & ~O_NONBLOCK) == 0) {
6693         /* only O_NONBLOCK, all other bits are zero */
6694         netconn_set_nonblocking(sock->conn, val & O_NONBLOCK);
6695         ret = 0;
6696         sock_set_errno(sock, 0);
6697       } else {
6698         sock_set_errno(sock, ENOSYS); /* not yet implemented */
6699       }
6700       break;
6701     default:
6702       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_fcntl(%d, UNIMPL: %d, %d)\n", s, cmd, val));
6703       sock_set_errno(sock, ENOSYS); /* not yet implemented */
6704       break;
6705   }
6706   done_socket(sock);
6707   return ret;
6708 }
6709 
6710 #if LWIP_COMPAT_SOCKETS == 2 && LWIP_POSIX_SOCKETS_IO_NAMES
6711 int
fcntl(int s,int cmd,...)6712 fcntl(int s, int cmd, ...)
6713 {
6714   va_list ap;
6715   int val;
6716 
6717   va_start(ap, cmd);
6718   val = va_arg(ap, int);
6719   va_end(ap);
6720   return lwip_fcntl(s, cmd, val);
6721 }
6722 #endif
6723 
6724 const char *
lwip_inet_ntop(int af,const void * src,char * dst,socklen_t size)6725 lwip_inet_ntop(int af, const void *src, char *dst, socklen_t size)
6726 {
6727   const char *ret = NULL;
6728   int size_int = (int)size;
6729   if ((src == NULL) || (dst == NULL)) {
6730     set_errno(EINVAL);
6731     return NULL;
6732   }
6733   if (size_int < 0) {
6734     set_errno(ENOSPC);
6735     return NULL;
6736   }
6737   switch (af) {
6738 #if LWIP_IPV4
6739     case AF_INET:
6740       ret = ip4addr_ntoa_r((const ip4_addr_t *)src, dst, size_int);
6741       if (ret == NULL) {
6742         set_errno(ENOSPC);
6743       }
6744       break;
6745 #endif
6746 #if LWIP_IPV6
6747     case AF_INET6:
6748       ret = ip6addr_ntoa_r((const ip6_addr_t *)src, dst, size_int);
6749       if (ret == NULL) {
6750         set_errno(ENOSPC);
6751       }
6752       break;
6753 #endif
6754     default:
6755       set_errno(EAFNOSUPPORT);
6756       break;
6757   }
6758   return ret;
6759 }
6760 
6761 int
lwip_inet_pton(int af,const char * src,void * dst)6762 lwip_inet_pton(int af, const char *src, void *dst)
6763 {
6764   int err;
6765   if ((src == NULL) || (dst == NULL)) {
6766     set_errno(EINVAL);
6767     return 0;
6768   }
6769   switch (af) {
6770 #if LWIP_IPV4
6771     case AF_INET:
6772       err = ip4addr_aton(src, (ip4_addr_t *)dst);
6773       break;
6774 #endif
6775 #if LWIP_IPV6
6776     case AF_INET6: {
6777       /* convert into temporary variable since ip6_addr_t might be larger
6778          than in6_addr when scopes are enabled */
6779       ip6_addr_t addr;
6780       err = ip6addr_aton(src, &addr);
6781       if (err) {
6782         memcpy(dst, &addr.addr, sizeof(addr.addr));
6783       }
6784       break;
6785     }
6786 #endif
6787     default:
6788       err = -1;
6789       set_errno(EAFNOSUPPORT);
6790       break;
6791   }
6792   return err;
6793 }
6794 
6795 #if LWIP_IGMP
6796 /** Register a new IGMP membership. On socket close, the membership is dropped automatically.
6797  *
6798  * ATTENTION: this function is called from tcpip_thread (or under CORE_LOCK).
6799  *
6800  * @return 1 on success, 0 on failure
6801  */
6802 static int
lwip_socket_register_membership(int s,const ip4_addr_t * if_addr,const ip4_addr_t * multi_addr)6803 lwip_socket_register_membership(int s, const ip4_addr_t *if_addr, const ip4_addr_t *multi_addr)
6804 {
6805   struct lwip_sock *sock = get_socket(s);
6806   u32_t i;
6807   SYS_ARCH_DECL_PROTECT(lev);
6808 
6809   if (!sock) {
6810     return 0;
6811   }
6812 
6813   SYS_ARCH_PROTECT(lev);
6814 #if LWIP_ALLOW_SOCKET_CONFIG
6815   if (socket_ipv4_multicast_memberships == NULL) {
6816     socket_ipv4_multicast_memberships =
6817         mem_malloc(sizeof(struct lwip_socket_multicast_pair) * LWIP_SOCKET_MAX_MEMBERSHIPS);
6818     if (socket_ipv4_multicast_memberships == NULL) {
6819       SYS_ARCH_UNPROTECT(lev);
6820       done_socket(sock);
6821       return 0;
6822     }
6823     (void)memset(socket_ipv4_multicast_memberships,
6824                  0,
6825                  sizeof(struct lwip_socket_multicast_pair) * LWIP_SOCKET_MAX_MEMBERSHIPS);
6826   }
6827 #endif
6828 
6829   for (i = 0; i < LWIP_SOCKET_MAX_MEMBERSHIPS; i++) {
6830     if (socket_ipv4_multicast_memberships[i].sock == NULL) {
6831       socket_ipv4_multicast_memberships[i].sock = sock;
6832       ip4_addr_copy(socket_ipv4_multicast_memberships[i].if_addr, *if_addr);
6833       ip4_addr_copy(socket_ipv4_multicast_memberships[i].multi_addr, *multi_addr);
6834       SYS_ARCH_UNPROTECT(lev);
6835       done_socket(sock);
6836       return 1;
6837     }
6838   }
6839   SYS_ARCH_UNPROTECT(lev);
6840   done_socket(sock);
6841   return 0;
6842 }
6843 
6844 /** Unregister a previously registered membership. This prevents dropping the membership
6845  * on socket close.
6846  *
6847  * ATTENTION: this function is called from tcpip_thread (or under CORE_LOCK).
6848  */
6849 static void
lwip_socket_unregister_membership(int s,const ip4_addr_t * if_addr,const ip4_addr_t * multi_addr)6850 lwip_socket_unregister_membership(int s, const ip4_addr_t *if_addr, const ip4_addr_t *multi_addr)
6851 {
6852   struct lwip_sock *sock = get_socket(s);
6853   u32_t i;
6854   SYS_ARCH_DECL_PROTECT(lev);
6855 
6856   if (!sock) {
6857     return;
6858   }
6859 
6860   SYS_ARCH_PROTECT(lev);
6861 #if LWIP_ALLOW_SOCKET_CONFIG
6862   if (socket_ipv4_multicast_memberships == NULL) {
6863     SYS_ARCH_UNPROTECT(lev);
6864     done_socket(sock);
6865     return;
6866   }
6867 #endif
6868 
6869   for (i = 0; i < LWIP_SOCKET_MAX_MEMBERSHIPS; i++) {
6870     if ((socket_ipv4_multicast_memberships[i].sock == sock) &&
6871         ip4_addr_cmp(&socket_ipv4_multicast_memberships[i].if_addr, if_addr) &&
6872         ip4_addr_cmp(&socket_ipv4_multicast_memberships[i].multi_addr, multi_addr)) {
6873       socket_ipv4_multicast_memberships[i].sock = NULL;
6874       ip4_addr_set_zero(&socket_ipv4_multicast_memberships[i].if_addr);
6875       ip4_addr_set_zero(&socket_ipv4_multicast_memberships[i].multi_addr);
6876       break;
6877     }
6878   }
6879   SYS_ARCH_UNPROTECT(lev);
6880   done_socket(sock);
6881 }
6882 
6883 /** Drop all memberships of a socket that were not dropped explicitly via setsockopt.
6884  *
6885  * ATTENTION: this function is NOT called from tcpip_thread (or under CORE_LOCK).
6886  */
6887 static void
lwip_socket_drop_registered_memberships(int s)6888 lwip_socket_drop_registered_memberships(int s)
6889 {
6890   struct lwip_sock *sock = get_socket(s);
6891   u32_t i;
6892   SYS_ARCH_DECL_PROTECT(lev);
6893 
6894   if (!sock) {
6895     return;
6896   }
6897 
6898   SYS_ARCH_PROTECT(lev);
6899 #if LWIP_ALLOW_SOCKET_CONFIG
6900   if (socket_ipv4_multicast_memberships == NULL) {
6901     SYS_ARCH_UNPROTECT(lev);
6902     done_socket(sock);
6903     return;
6904   }
6905 #endif
6906   SYS_ARCH_UNPROTECT(lev);
6907   for (i = 0; i < LWIP_SOCKET_MAX_MEMBERSHIPS; i++) {
6908     SYS_ARCH_PROTECT(lev);
6909     if (socket_ipv4_multicast_memberships[i].sock == sock) {
6910       ip_addr_t multi_addr, if_addr;
6911       ip_addr_copy_from_ip4(multi_addr, socket_ipv4_multicast_memberships[i].multi_addr);
6912       ip_addr_copy_from_ip4(if_addr, socket_ipv4_multicast_memberships[i].if_addr);
6913       socket_ipv4_multicast_memberships[i].sock = NULL;
6914       ip4_addr_set_zero(&socket_ipv4_multicast_memberships[i].if_addr);
6915       ip4_addr_set_zero(&socket_ipv4_multicast_memberships[i].multi_addr);
6916 
6917       SYS_ARCH_UNPROTECT(lev);
6918       (void)netconn_leave_group(sock->conn, &multi_addr, &if_addr, NETCONN_LEAVE);
6919     } else {
6920       SYS_ARCH_UNPROTECT(lev);
6921     }
6922   }
6923   done_socket(sock);
6924 }
6925 #endif /* LWIP_IGMP */
6926 
6927 #ifdef LWIP_DEBUG_INFO
debug_socket_info(int idx,int filter,int expend)6928 void debug_socket_info(int idx, int filter, int expend)
6929 {
6930   struct lwip_sock *sock = NULL;
6931   if ((idx >= (int)LWIP_CONFIG_NUM_SOCKETS) || (idx < 0)) {
6932     LWIP_PLATFORM_PRINT("problem:idx >= LWIP_CONFIG_NUM_SOCKETS || idx < 0\n");
6933     return;
6934   }
6935   sock = get_socket(idx + LWIP_SOCKET_OFFSET);
6936   if (sock == NULL) {
6937     return;
6938   }
6939   if (filter) {
6940     LWIP_PLATFORM_PRINT("\n---------------SOCKET\n");
6941     LWIP_PLATFORM_PRINT("idx      :%d\n", idx);
6942     LWIP_PLATFORM_PRINT("conn     :%p\n", sockets[idx].conn);
6943     LWIP_PLATFORM_PRINT("r_event  :%d\n", sockets[idx].rcvevent);
6944     LWIP_PLATFORM_PRINT("s_event  :%d\n", sockets[idx].sendevent);
6945     LWIP_PLATFORM_PRINT("e_event  :%d\n", sockets[idx].errevent);
6946     LWIP_PLATFORM_PRINT("err      :%d\n", atomic_read(&sockets[idx].err));
6947 #if LWIP_NETCONN_FULLDUPLEX
6948     LWIP_PLATFORM_PRINT("fd_used  :%d\n", sockets[idx].fd_used);
6949     LWIP_PLATFORM_PRINT("fd_used  :%d\n", sockets[idx].closing);
6950 #endif
6951     LWIP_PLATFORM_PRINT("select_w :%d\n", sockets[idx].select_waiting);
6952     LWIP_PLATFORM_PRINT("last_offset :%d\n", sockets[idx].lastoffset);
6953 #if LWIP_EXT_POLL_SUPPORT
6954 #if defined(LWIP_ALIOS_COMPAT) && LWIP_ALIOS_COMPAT
6955     LWIP_PLATFORM_PRINT("poll_prev:%p\n",   sockets[idx].wq.poll_queue.prev);
6956     LWIP_PLATFORM_PRINT("poll_next:%p\n",   sockets[idx].wq.poll_queue.next);
6957 #else /* LWIP_ALIOS_COMPAT */
6958     LWIP_PLATFORM_PRINT("poll_prev:%p\n",   sockets[idx].wq.poll_queue.pstPrev);
6959     LWIP_PLATFORM_PRINT("poll_next:%p\n",   sockets[idx].wq.poll_queue.pstNext);
6960 #endif /* LWIP_ALIOS_COMPAT */
6961 #endif /* LWIP_EXT_POLL_SUPPORT */
6962     if (expend) {
6963       debug_netconn_info((void*)sockets[idx].conn, expend);
6964     }
6965   }
6966   done_socket(sock);
6967 }
6968 #endif /* LWIP_DEBUG_INFO */
6969 
6970 #if LWIP_IPV6 && LWIP_IPV6_MLD
6971 /** Register a new MLD6 membership. On socket close, the membership is dropped automatically.
6972  *
6973  * ATTENTION: this function is called from tcpip_thread (or under CORE_LOCK).
6974  *
6975  * @return 1 on success, 0 on failure
6976  */
6977 static int
lwip_socket_register_mld6_membership(int s,unsigned int if_idx,const ip6_addr_t * multi_addr)6978 lwip_socket_register_mld6_membership(int s, unsigned int if_idx, const ip6_addr_t *multi_addr)
6979 {
6980   struct lwip_sock *sock = get_socket(s);
6981   u32_t i;
6982   SYS_ARCH_DECL_PROTECT(lev);
6983 
6984   if (!sock) {
6985     return 0;
6986   }
6987 
6988   SYS_ARCH_PROTECT(lev);
6989 #if LWIP_ALLOW_SOCKET_CONFIG
6990   if (socket_ipv6_multicast_memberships == NULL) {
6991     socket_ipv6_multicast_memberships =
6992         mem_malloc(sizeof(struct lwip_socket_multicast_mld6_pair) * LWIP_SOCKET_MAX_MEMBERSHIPS);
6993     if (socket_ipv6_multicast_memberships == NULL) {
6994       SYS_ARCH_UNPROTECT(lev);
6995       done_socket(sock);
6996       return 0;
6997     }
6998     (void)memset(socket_ipv6_multicast_memberships, 0,
6999                  sizeof(struct lwip_socket_multicast_mld6_pair) * LWIP_SOCKET_MAX_MEMBERSHIPS);
7000   }
7001 #endif
7002 
7003   for (i = 0; i < LWIP_SOCKET_MAX_MEMBERSHIPS; i++) {
7004     if (socket_ipv6_multicast_memberships[i].sock == NULL) {
7005       socket_ipv6_multicast_memberships[i].sock   = sock;
7006       socket_ipv6_multicast_memberships[i].if_idx = (u8_t)if_idx;
7007       ip6_addr_copy(socket_ipv6_multicast_memberships[i].multi_addr, *multi_addr);
7008       SYS_ARCH_UNPROTECT(lev);
7009       done_socket(sock);
7010       return 1;
7011     }
7012   }
7013   SYS_ARCH_UNPROTECT(lev);
7014   done_socket(sock);
7015   return 0;
7016 }
7017 
7018 /** Unregister a previously registered MLD6 membership. This prevents dropping the membership
7019  * on socket close.
7020  *
7021  * ATTENTION: this function is called from tcpip_thread (or under CORE_LOCK).
7022  */
7023 static void
lwip_socket_unregister_mld6_membership(int s,unsigned int if_idx,const ip6_addr_t * multi_addr)7024 lwip_socket_unregister_mld6_membership(int s, unsigned int if_idx, const ip6_addr_t *multi_addr)
7025 {
7026   struct lwip_sock *sock = get_socket(s);
7027   u32_t i;
7028   SYS_ARCH_DECL_PROTECT(lev);
7029 
7030   if (!sock) {
7031     return;
7032   }
7033 
7034   SYS_ARCH_PROTECT(lev);
7035 #if LWIP_ALLOW_SOCKET_CONFIG
7036   if (socket_ipv6_multicast_memberships == NULL) {
7037     SYS_ARCH_UNPROTECT(lev);
7038     done_socket(sock);
7039     return;
7040   }
7041 #endif
7042 
7043   for (i = 0; i < LWIP_SOCKET_MAX_MEMBERSHIPS; i++) {
7044     if ((socket_ipv6_multicast_memberships[i].sock   == sock) &&
7045         (socket_ipv6_multicast_memberships[i].if_idx == if_idx) &&
7046         ip6_addr_cmp(&socket_ipv6_multicast_memberships[i].multi_addr, multi_addr)) {
7047       socket_ipv6_multicast_memberships[i].sock   = NULL;
7048       socket_ipv6_multicast_memberships[i].if_idx = NETIF_NO_INDEX;
7049       ip6_addr_set_zero(&socket_ipv6_multicast_memberships[i].multi_addr);
7050       break;
7051     }
7052   }
7053   SYS_ARCH_UNPROTECT(lev);
7054   done_socket(sock);
7055 }
7056 
7057 /** Drop all MLD6 memberships of a socket that were not dropped explicitly via setsockopt.
7058  *
7059  * ATTENTION: this function is NOT called from tcpip_thread (or under CORE_LOCK).
7060  */
7061 static void
lwip_socket_drop_registered_mld6_memberships(int s)7062 lwip_socket_drop_registered_mld6_memberships(int s)
7063 {
7064   struct lwip_sock *sock = get_socket(s);
7065   u32_t i;
7066   SYS_ARCH_DECL_PROTECT(lev);
7067 
7068   if (!sock) {
7069     return;
7070   }
7071 
7072   SYS_ARCH_PROTECT(lev);
7073 #if LWIP_ALLOW_SOCKET_CONFIG
7074   if (socket_ipv6_multicast_memberships == NULL) {
7075     SYS_ARCH_UNPROTECT(lev);
7076     done_socket(sock);
7077     return;
7078   }
7079 #endif
7080   SYS_ARCH_UNPROTECT(lev);
7081 
7082   for (i = 0; i < LWIP_SOCKET_MAX_MEMBERSHIPS; i++) {
7083     SYS_ARCH_PROTECT(lev);
7084     if (socket_ipv6_multicast_memberships[i].sock == sock) {
7085       ip_addr_t multi_addr;
7086       u8_t if_idx;
7087 
7088       ip_addr_copy_from_ip6(multi_addr, socket_ipv6_multicast_memberships[i].multi_addr);
7089       if_idx = socket_ipv6_multicast_memberships[i].if_idx;
7090 
7091       socket_ipv6_multicast_memberships[i].sock   = NULL;
7092       socket_ipv6_multicast_memberships[i].if_idx = NETIF_NO_INDEX;
7093       ip6_addr_set_zero(&socket_ipv6_multicast_memberships[i].multi_addr);
7094       SYS_ARCH_UNPROTECT(lev);
7095 
7096       (void)netconn_leave_group_netif(sock->conn, &multi_addr, if_idx, NETCONN_LEAVE);
7097     } else {
7098       SYS_ARCH_UNPROTECT(lev);
7099     }
7100   }
7101   done_socket(sock);
7102 }
7103 #endif /* LWIP_IPV6 && LWIP_IPV6_MLD */
7104 
7105 /* Get dst_mac TCP / IP connections, src_ip, dst_ip, ipid, srcport, dstport,
7106  * Seq, ack, tcpwin, tsval, tsecr information
7107  *
7108  * @param s socket descriptor for which the details are required
7109  * @param conn parameter in which the acquired TCP / IP connection information is to be saved
7110  *
7111  * @note If the UDP connection, seq, ack, tcpwin, tsval, tsecr is set to 0
7112  * @return 0 if successful; failure to return -1
7113  */
7114 
lwip_get_conn_info(int s,void * conninfo)7115 int lwip_get_conn_info(int s, void *conninfo)
7116 {
7117   struct lwip_sock *isock;
7118   err_t err;
7119   int retval = 0;
7120 
7121   isock = get_socket(s);
7122   if (isock == NULL) {
7123     set_errno(EBADF);
7124     return -1;
7125   }
7126 
7127   err = netconn_getconninfo(isock->conn, conninfo);
7128   if (err != ERR_OK) {
7129     retval = -1;
7130     goto RETURN;
7131   }
7132 
7133 RETURN:
7134   if (err == ERR_VAL) {
7135       set_errno(EOPNOTSUPP);
7136   } else {
7137     set_errno(err_to_errno(err));
7138   }
7139   done_socket(isock);
7140   return retval;
7141 }
7142 
7143 #ifdef LWIP_LITEOS_A_COMPAT
7144 #include "los_vm_map.h"
7145 #include "user_copy.h"
7146 #include "los_strnlen_user.h"
7147 #include "lwip/netifapi.h"
7148 
7149 #define DHCP_START 0xFFFFFFFDUL
7150 #define DHCP_STOP  0xFFFFFFFEUL
7151 
7152 static int
do_ioctl_SIOCGIFCONF(int sockfd,long cmd,void * argp)7153 do_ioctl_SIOCGIFCONF(int sockfd, long cmd, void *argp)
7154 {
7155   int nbytes;
7156   struct ifconf ifc;
7157   char *buf_bak = NULL;
7158   int ret;
7159 
7160   if (LOS_ArchCopyFromUser(&ifc, argp, sizeof(struct ifconf)) != 0) {
7161     set_errno(EFAULT);
7162     return -1;
7163   }
7164   if (ifc.ifc_len < 0) {
7165     set_errno(EINVAL);
7166     return -1;
7167   }
7168   if (ifc.ifc_len > LWIP_NETIF_NUM_MAX * sizeof(struct ifreq)) {
7169     LWIP_DEBUGF(SOCKETS_DEBUG, ("do_ioctl_SIOCGIFCONF: ifconf.ifc_len is out of limit!"));
7170     ifc.ifc_len = LWIP_NETIF_NUM_MAX * sizeof(struct ifreq);
7171   }
7172   nbytes = ifc.ifc_len;
7173   buf_bak = ifc.ifc_buf;
7174   ifc.ifc_buf = malloc(nbytes);
7175   if (ifc.ifc_buf == NULL) {
7176     set_errno(ENOMEM);
7177     return -1;
7178   }
7179   (void)memset_s(ifc.ifc_buf, nbytes, 0, nbytes);
7180 
7181   ret = lwip_ioctl(sockfd, cmd, &ifc);
7182   if (ret == 0) {
7183     if (LOS_IsUserAddress((VADDR_T)(uintptr_t)buf_bak)) {
7184       if (LOS_ArchCopyToUser(buf_bak, ifc.ifc_buf, nbytes) != 0) {
7185         set_errno(EFAULT);
7186         ret = -1;
7187       }
7188     } else {
7189       set_errno(EFAULT);
7190       ret = -1;
7191     }
7192   }
7193 
7194   free(ifc.ifc_buf);
7195   ifc.ifc_buf = buf_bak;
7196   if (LOS_ArchCopyToUser(argp, &ifc, sizeof(struct ifconf)) != 0) {
7197     set_errno(EFAULT);
7198     ret = -1;
7199   }
7200   return ret;
7201 }
7202 
7203 static size_t
get_argp_size(int sockfd,long cmd)7204 get_argp_size(int sockfd, long cmd)
7205 {
7206   switch (cmd) {
7207     case FIONREAD:
7208     case FIONBIO:
7209       return sizeof(int);
7210     case SIOCADDRT:
7211       return sizeof(struct rtentry);
7212     case SIOCSIFADDR:
7213     case SIOCDIFADDR:
7214       size_t nbytes;
7215 #if LWIP_IPV6
7216       struct lwip_sock *sock = get_socket(sockfd);
7217       if (!sock) {
7218         return 0;
7219       }
7220       u8_t is_ipv6 = NETCONNTYPE_ISIPV6(sock->conn->type);
7221       done_socket(sock);
7222       if (is_ipv6) {
7223         nbytes = sizeof(struct in6_ifreq);
7224       } else
7225 #endif
7226       {
7227         nbytes = sizeof(struct ifreq);
7228       }
7229       return nbytes;
7230 #if LWIP_IPV6
7231     case SIOCSIPV6DAD:
7232     case SIOCGIPV6DAD:
7233     case SIOCSIPV6DPCTD:
7234     case SIOCGIPV6DPCTD:
7235 #endif
7236     case SIOCGIFADDR:
7237     case SIOCGIFBRDADDR:
7238     case SIOCGIFNETMASK:
7239     case SIOCSIFNETMASK:
7240     case SIOCSIFHWADDR:
7241     case SIOCGIFHWADDR:
7242     case SIOCSIFFLAGS:
7243     case SIOCGIFFLAGS:
7244     case SIOCGIFNAME:
7245     case SIOCSIFNAME:
7246     case SIOCGIFINDEX:
7247     case SIOCGIFMTU:
7248     case SIOCSIFMTU:
7249     case SIOCETHTOOL:
7250       return sizeof(struct ifreq);
7251     default:
7252       return 0;
7253   }
7254 }
7255 
7256 static int
do_ioctl_netifapi_dhcp(struct lwip_sock * sock,unsigned long cmd,struct netif * netif)7257 do_ioctl_netifapi_dhcp(struct lwip_sock *sock, unsigned long cmd, struct netif *netif)
7258 {
7259   int ret = -1;
7260   err_t err;
7261   switch (cmd) {
7262     case DHCP_START:
7263       err = netifapi_dhcp_start(netif);
7264       if (err != ERR_OK) {
7265         sock_set_errno(sock, err_to_errno(err));
7266         break;
7267       }
7268       ret = 0;
7269       break;
7270     case DHCP_STOP:
7271       err = netifapi_dhcp_stop(netif);
7272       if (err != ERR_OK) {
7273         sock_set_errno(sock, err_to_errno(err));
7274         break;
7275       }
7276       ret = 0;
7277       break;
7278     default:
7279       sock_set_errno(sock, EINVAL);
7280       break;
7281   }
7282   return ret;
7283 }
7284 
7285 static int
do_ioctl_dhcp(int sockfd,long cmd,void * argp)7286 do_ioctl_dhcp(int sockfd, long cmd, void *argp)
7287 {
7288   struct netif *netif = NULL;
7289   char netif_name[NETIF_NAMESIZE];
7290   u16_t name_len;
7291   int ret = -1;
7292   (void)memset_s(netif_name, NETIF_NAMESIZE, 0, NETIF_NAMESIZE);
7293   struct lwip_sock *sock = get_socket(sockfd);
7294   if (sock == NULL) {
7295     set_errno(EFAULT);
7296     return -1;
7297   }
7298   name_len = LOS_StrnlenUser(argp, NETIF_NAMESIZE - 1);
7299   /* LOS_StrnlenUser didn't follow strnlen's behavior, LOS_StrnlenUser's
7300    * return value is not reliable.
7301    */
7302   if (name_len == 0 || name_len > NETIF_NAMESIZE - 1) {
7303     sock_set_errno(sock, EINVAL);
7304     goto FINISH;
7305   }
7306 
7307   if (LOS_ArchCopyFromUser(netif_name, argp, name_len) != 0) {
7308     sock_set_errno(sock, EFAULT);
7309     goto FINISH;
7310   }
7311   netif = netifapi_netif_find(netif_name);
7312   if (netif == NULL) {
7313     sock_set_errno(sock, EINVAL);
7314     goto FINISH;
7315   }
7316   ret = do_ioctl_netifapi_dhcp(sock, (unsigned long)cmd, netif);
7317 
7318 FINISH:
7319   done_socket(sock);
7320   return ret;
7321 }
7322 
7323 int
socks_ioctl(int sockfd,long cmd,void * argp)7324 socks_ioctl(int sockfd, long cmd, void *argp)
7325 {
7326   void *argpbak = argp;
7327   int ret;
7328   size_t nbytes;
7329   if (argp == NULL) {
7330     set_errno(EINVAL);
7331     return -1;
7332   }
7333   if (LOS_IsUserAddress((VADDR_T)(uintptr_t)argp)) {
7334     if (cmd == SIOCGIFCONF) {
7335       return do_ioctl_SIOCGIFCONF(sockfd, cmd, argp);
7336     }
7337     /* ioctl dhcp only used in user space */
7338     if ((unsigned long)cmd == DHCP_START || (unsigned long)cmd == DHCP_STOP) {
7339       return do_ioctl_dhcp(sockfd, cmd, argp);
7340     }
7341     nbytes = get_argp_size(sockfd, cmd);
7342     if (nbytes == 0) {
7343       set_errno(EINVAL);
7344       return -1;
7345     }
7346     argp = malloc(nbytes);
7347     if (argp == NULL) {
7348       set_errno(ENOMEM);
7349       return -1;
7350     }
7351     if (LOS_ArchCopyFromUser(argp, argpbak, nbytes) != 0) {
7352       free(argp);
7353       set_errno(EFAULT);
7354       return -1;
7355     }
7356   }
7357   ret = lwip_ioctl(sockfd, cmd, argp);
7358   if (ret != 0) {
7359     if (argp != argpbak) {
7360       free(argp);
7361     }
7362     return -1;
7363   }
7364   if (argp != argpbak) {
7365     if (LOS_ArchCopyToUser(argpbak, argp, nbytes) != 0) {
7366       set_errno(EFAULT);
7367       ret = -1;
7368     }
7369     free(argp);
7370   }
7371   return ret;
7372 }
7373 
7374 void
socks_refer(int sockfd)7375 socks_refer(int sockfd)
7376 {
7377   struct lwip_sock *sock = NULL;
7378   SYS_ARCH_DECL_PROTECT(lev);
7379 
7380   sock = get_socket(sockfd);
7381   if (!sock) {
7382     return;
7383   }
7384 
7385   SYS_ARCH_PROTECT(lev);
7386 
7387   sock->s_refcount++;
7388 
7389   SYS_ARCH_UNPROTECT(lev);
7390 
7391   done_socket(sock);
7392 }
7393 
7394 int
socks_close(int sockfd)7395 socks_close(int sockfd)
7396 {
7397   struct lwip_sock *sock = NULL;
7398   SYS_ARCH_DECL_PROTECT(lev);
7399 
7400   sock = get_socket(sockfd);
7401   if (!sock) {
7402     return -1;
7403   }
7404 
7405   SYS_ARCH_PROTECT(lev);
7406 
7407   if (sock->s_refcount == 0) {
7408     SYS_ARCH_UNPROTECT(lev);
7409     done_socket(sock);
7410     return lwip_close(sockfd);
7411   }
7412 
7413   sock->s_refcount--;
7414 
7415   SYS_ARCH_UNPROTECT(lev);
7416   done_socket(sock);
7417   return 0;
7418 }
7419 
7420 #if LWIP_SOCKET_POLL && LWIP_EXT_POLL_SUPPORT
7421 int
socks_poll(int sockfd,poll_table * wait)7422 socks_poll(int sockfd, poll_table *wait)
7423 {
7424   if (wait == NULL) {
7425     return -EFAULT;
7426   }
7427   return lwip_poll(sockfd, wait);
7428 }
7429 #endif /* LWIP_SOCKET_POLL && LWIP_EXT_POLL_SUPPORT */
7430 #endif /* LWIP_LITEOS_A_COMPAT */
7431 #endif /* LWIP_SOCKET */
7432