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