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