The Pedigree Project 0.1
sockets.c
Go to the documentation of this file.
1/*
2 * Copyright (c) 2008-2014, Pedigree Developers
3 *
4 * Please see the CONTRIB file in the root of the source tree for a full
5 * list of contributors.
6 *
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
10 *
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 */
19
32/*
33 * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
34 * All rights reserved.
35 *
36 * Redistribution and use in source and binary forms, with or without modification,
37 * are permitted provided that the following conditions are met:
38 *
39 * 1. Redistributions of source code must retain the above copyright notice,
40 * this list of conditions and the following disclaimer.
41 * 2. Redistributions in binary form must reproduce the above copyright notice,
42 * this list of conditions and the following disclaimer in the documentation
43 * and/or other materials provided with the distribution.
44 * 3. The name of the author may not be used to endorse or promote products
45 * derived from this software without specific prior written permission.
46 *
47 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
48 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
49 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
50 * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
51 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
52 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
53 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
54 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
55 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
56 * OF SUCH DAMAGE.
57 *
58 * This file is part of the lwIP TCP/IP stack.
59 *
60 * Author: Adam Dunkels <adam@sics.se>
61 *
62 * Improved by Marc Boucher <marc@mbsi.ca> and David Haas <dhaas@alum.rpi.edu>
63 *
64 */
65
66#include "lwip/opt.h"
67
68#if LWIP_SOCKET /* don't build if not configured for use in lwipopts.h */
69
70#include "lwip/sockets.h"
71#include "lwip/api.h"
72#include "lwip/sys.h"
73#include "lwip/igmp.h"
74#include "lwip/inet.h"
75#include "lwip/tcp.h"
76#include "lwip/raw.h"
77#include "lwip/udp.h"
78#include "lwip/memp.h"
79#include "lwip/pbuf.h"
81#if LWIP_CHECKSUM_ON_COPY
82#include "lwip/inet_chksum.h"
83#endif
84
85#include <string.h>
86
87/* If the netconn API is not required publicly, then we include the necessary
88 files here to get the implementation */
89#if !LWIP_NETCONN
90#undef LWIP_NETCONN
91#define LWIP_NETCONN 1
92#include "api_msg.c"
93#include "api_lib.c"
94#include "netbuf.c"
95#undef LWIP_NETCONN
96#define LWIP_NETCONN 0
97#endif
98
99#if LWIP_IPV4
100#define IP4ADDR_PORT_TO_SOCKADDR(sin, ipaddr, port) do { \
101 (sin)->sin_len = sizeof(struct sockaddr_in); \
102 (sin)->sin_family = AF_INET; \
103 (sin)->sin_port = lwip_htons((port)); \
104 inet_addr_from_ip4addr(&(sin)->sin_addr, ipaddr); \
105 memset((sin)->sin_zero, 0, SIN_ZERO_LEN); }while(0)
106#define SOCKADDR4_TO_IP4ADDR_PORT(sin, ipaddr, port) do { \
107 inet_addr_to_ip4addr(ip_2_ip4(ipaddr), &((sin)->sin_addr)); \
108 (port) = lwip_ntohs((sin)->sin_port); }while(0)
109#endif /* LWIP_IPV4 */
110
111#if LWIP_IPV6
112#define IP6ADDR_PORT_TO_SOCKADDR(sin6, ipaddr, port) do { \
113 (sin6)->sin6_len = sizeof(struct sockaddr_in6); \
114 (sin6)->sin6_family = AF_INET6; \
115 (sin6)->sin6_port = lwip_htons((port)); \
116 (sin6)->sin6_flowinfo = 0; \
117 inet6_addr_from_ip6addr(&(sin6)->sin6_addr, ipaddr); \
118 (sin6)->sin6_scope_id = 0; }while(0)
119#define SOCKADDR6_TO_IP6ADDR_PORT(sin6, ipaddr, port) do { \
120 inet6_addr_to_ip6addr(ip_2_ip6(ipaddr), &((sin6)->sin6_addr)); \
121 (port) = lwip_ntohs((sin6)->sin6_port); }while(0)
122#endif /* LWIP_IPV6 */
123
124#if LWIP_IPV4 && LWIP_IPV6
125static void sockaddr_to_ipaddr_port(const struct sockaddr* sockaddr, ip_addr_t* ipaddr, u16_t* port);
126
127#define IS_SOCK_ADDR_LEN_VALID(namelen) (((namelen) == sizeof(struct sockaddr_in)) || \
128 ((namelen) == sizeof(struct sockaddr_in6)))
129#define IS_SOCK_ADDR_TYPE_VALID(name) (((name)->sa_family == AF_INET) || \
130 ((name)->sa_family == AF_INET6))
131#define SOCK_ADDR_TYPE_MATCH(name, sock) \
132 ((((name)->sa_family == AF_INET) && !(NETCONNTYPE_ISIPV6((sock)->conn->type))) || \
133 (((name)->sa_family == AF_INET6) && (NETCONNTYPE_ISIPV6((sock)->conn->type))))
134#define IPADDR_PORT_TO_SOCKADDR(sockaddr, ipaddr, port) do { \
135 if (IP_IS_V6(ipaddr)) { \
136 IP6ADDR_PORT_TO_SOCKADDR((struct sockaddr_in6*)(void*)(sockaddr), ip_2_ip6(ipaddr), port); \
137 } else { \
138 IP4ADDR_PORT_TO_SOCKADDR((struct sockaddr_in*)(void*)(sockaddr), ip_2_ip4(ipaddr), port); \
139 } } while(0)
140#define SOCKADDR_TO_IPADDR_PORT(sockaddr, ipaddr, port) sockaddr_to_ipaddr_port(sockaddr, ipaddr, &(port))
141#define DOMAIN_TO_NETCONN_TYPE(domain, type) (((domain) == AF_INET) ? \
142 (type) : (enum netconn_type)((type) | NETCONN_TYPE_IPV6))
143#elif LWIP_IPV6 /* LWIP_IPV4 && LWIP_IPV6 */
144#define IS_SOCK_ADDR_LEN_VALID(namelen) ((namelen) == sizeof(struct sockaddr_in6))
145#define IS_SOCK_ADDR_TYPE_VALID(name) ((name)->sa_family == AF_INET6)
146#define SOCK_ADDR_TYPE_MATCH(name, sock) 1
147#define IPADDR_PORT_TO_SOCKADDR(sockaddr, ipaddr, port) \
148 IP6ADDR_PORT_TO_SOCKADDR((struct sockaddr_in6*)(void*)(sockaddr), ip_2_ip6(ipaddr), port)
149#define SOCKADDR_TO_IPADDR_PORT(sockaddr, ipaddr, port) \
150 SOCKADDR6_TO_IP6ADDR_PORT((const struct sockaddr_in6*)(const void*)(sockaddr), ipaddr, port)
151#define DOMAIN_TO_NETCONN_TYPE(domain, netconn_type) (netconn_type)
152#else /*-> LWIP_IPV4: LWIP_IPV4 && LWIP_IPV6 */
153#define IS_SOCK_ADDR_LEN_VALID(namelen) ((namelen) == sizeof(struct sockaddr_in))
154#define IS_SOCK_ADDR_TYPE_VALID(name) ((name)->sa_family == AF_INET)
155#define SOCK_ADDR_TYPE_MATCH(name, sock) 1
156#define IPADDR_PORT_TO_SOCKADDR(sockaddr, ipaddr, port) \
157 IP4ADDR_PORT_TO_SOCKADDR((struct sockaddr_in*)(void*)(sockaddr), ip_2_ip4(ipaddr), port)
158#define SOCKADDR_TO_IPADDR_PORT(sockaddr, ipaddr, port) \
159 SOCKADDR4_TO_IP4ADDR_PORT((const struct sockaddr_in*)(const void*)(sockaddr), ipaddr, port)
160#define DOMAIN_TO_NETCONN_TYPE(domain, netconn_type) (netconn_type)
161#endif /* LWIP_IPV6 */
162
163#define IS_SOCK_ADDR_TYPE_VALID_OR_UNSPEC(name) (((name)->sa_family == AF_UNSPEC) || \
164 IS_SOCK_ADDR_TYPE_VALID(name))
165#define SOCK_ADDR_TYPE_MATCH_OR_UNSPEC(name, sock) (((name)->sa_family == AF_UNSPEC) || \
166 SOCK_ADDR_TYPE_MATCH(name, sock))
167#define IS_SOCK_ADDR_ALIGNED(name) ((((mem_ptr_t)(name)) % 4) == 0)
168
169
170#define LWIP_SOCKOPT_CHECK_OPTLEN(optlen, opttype) do { if ((optlen) < sizeof(opttype)) { return EINVAL; }}while(0)
171#define LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, optlen, opttype) do { \
172 LWIP_SOCKOPT_CHECK_OPTLEN(optlen, opttype); \
173 if ((sock)->conn == NULL) { return EINVAL; } }while(0)
174#define LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, optlen, opttype) do { \
175 LWIP_SOCKOPT_CHECK_OPTLEN(optlen, opttype); \
176 if (((sock)->conn == NULL) || ((sock)->conn->pcb.tcp == NULL)) { return EINVAL; } }while(0)
177#define LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, opttype, netconntype) do { \
178 LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, optlen, opttype); \
179 if (NETCONNTYPE_GROUP(netconn_type((sock)->conn)) != netconntype) { return ENOPROTOOPT; } }while(0)
180
181
182#define LWIP_SETGETSOCKOPT_DATA_VAR_REF(name) API_VAR_REF(name)
183#define LWIP_SETGETSOCKOPT_DATA_VAR_DECLARE(name) API_VAR_DECLARE(struct lwip_setgetsockopt_data, name)
184#define LWIP_SETGETSOCKOPT_DATA_VAR_FREE(name) API_VAR_FREE(MEMP_SOCKET_SETGETSOCKOPT_DATA, name)
185#if LWIP_MPU_COMPATIBLE
186#define LWIP_SETGETSOCKOPT_DATA_VAR_ALLOC(name, sock) do { \
187 name = (struct lwip_setgetsockopt_data *)memp_malloc(MEMP_SOCKET_SETGETSOCKOPT_DATA); \
188 if (name == NULL) { \
189 sock_set_errno(sock, ENOMEM); \
190 return -1; \
191 } }while(0)
192#else /* LWIP_MPU_COMPATIBLE */
193#define LWIP_SETGETSOCKOPT_DATA_VAR_ALLOC(name, sock)
194#endif /* LWIP_MPU_COMPATIBLE */
195
196#if LWIP_SO_SNDRCVTIMEO_NONSTANDARD
197#define LWIP_SO_SNDRCVTIMEO_OPTTYPE int
198#define LWIP_SO_SNDRCVTIMEO_SET(optval, val) (*(int *)(optval) = (val))
199#define LWIP_SO_SNDRCVTIMEO_GET_MS(optval) ((s32_t)*(const int*)(optval))
200#else
201#define LWIP_SO_SNDRCVTIMEO_OPTTYPE struct timeval
202#define LWIP_SO_SNDRCVTIMEO_SET(optval, val) do { \
203 s32_t loc = (val); \
204 ((struct timeval *)(optval))->tv_sec = (loc) / 1000U; \
205 ((struct timeval *)(optval))->tv_usec = ((loc) % 1000U) * 1000U; }while(0)
206#define LWIP_SO_SNDRCVTIMEO_GET_MS(optval) ((((const struct timeval *)(optval))->tv_sec * 1000U) + (((const struct timeval *)(optval))->tv_usec / 1000U))
207#endif
208
209#define NUM_SOCKETS MEMP_NUM_NETCONN
210
214#ifndef SELWAIT_T
215#define SELWAIT_T u8_t
216#endif
217
219struct lwip_sock {
221 struct netconn *conn;
223 void *lastdata;
225 u16_t lastoffset;
228 s16_t rcvevent;
231 u16_t sendevent;
233 u16_t errevent;
235 u8_t err;
237 SELWAIT_T select_waiting;
238};
239
240#if LWIP_NETCONN_SEM_PER_THREAD
241#define SELECT_SEM_T sys_sem_t*
242#define SELECT_SEM_PTR(sem) (sem)
243#else /* LWIP_NETCONN_SEM_PER_THREAD */
244#define SELECT_SEM_T sys_sem_t
245#define SELECT_SEM_PTR(sem) (&(sem))
246#endif /* LWIP_NETCONN_SEM_PER_THREAD */
247
249struct lwip_select_cb {
251 struct lwip_select_cb *next;
253 struct lwip_select_cb *prev;
255 fd_set *readset;
257 fd_set *writeset;
259 fd_set *exceptset;
261 int sem_signalled;
263 SELECT_SEM_T sem;
264};
265
269union sockaddr_aligned {
270 struct sockaddr sa;
271#if LWIP_IPV6
272 struct sockaddr_in6 sin6;
273#endif /* LWIP_IPV6 */
274#if LWIP_IPV4
275 struct sockaddr_in sin;
276#endif /* LWIP_IPV4 */
277};
278
279#if LWIP_IGMP
280/* Define the number of IPv4 multicast memberships, default is one per socket */
281#ifndef LWIP_SOCKET_MAX_MEMBERSHIPS
282#define LWIP_SOCKET_MAX_MEMBERSHIPS NUM_SOCKETS
283#endif
284
285/* This is to keep track of IP_ADD_MEMBERSHIP calls to drop the membership when
286 a socket is closed */
287struct lwip_socket_multicast_pair {
289 struct lwip_sock* sock;
291 ip4_addr_t if_addr;
293 ip4_addr_t multi_addr;
294};
295
296struct lwip_socket_multicast_pair socket_ipv4_multicast_memberships[LWIP_SOCKET_MAX_MEMBERSHIPS];
297
298static int lwip_socket_register_membership(int s, const ip4_addr_t *if_addr, const ip4_addr_t *multi_addr);
299static void lwip_socket_unregister_membership(int s, const ip4_addr_t *if_addr, const ip4_addr_t *multi_addr);
300static void lwip_socket_drop_registered_memberships(int s);
301#endif /* LWIP_IGMP */
302
304static struct lwip_sock sockets[NUM_SOCKETS];
306static struct lwip_select_cb *select_cb_list;
309static volatile int select_cb_ctr;
310
311#if LWIP_SOCKET_SET_ERRNO
312#ifndef set_errno
313#define set_errno(err) do { if (err) { errno = (err); } } while(0)
314#endif
315#else /* LWIP_SOCKET_SET_ERRNO */
316#define set_errno(err)
317#endif /* LWIP_SOCKET_SET_ERRNO */
318
319#define sock_set_errno(sk, e) do { \
320 const int sockerr = (e); \
321 sk->err = (u8_t)sockerr; \
322 set_errno(sockerr); \
323} while (0)
324
325/* Forward declaration of some functions */
326static void event_callback(struct netconn *conn, enum netconn_evt evt, u16_t len);
327#if !LWIP_TCPIP_CORE_LOCKING
328static void lwip_getsockopt_callback(void *arg);
329static void lwip_setsockopt_callback(void *arg);
330#endif
331static u8_t lwip_getsockopt_impl(int s, int level, int optname, void *optval, socklen_t *optlen);
332static u8_t lwip_setsockopt_impl(int s, int level, int optname, const void *optval, socklen_t optlen);
333
334#if LWIP_IPV4 && LWIP_IPV6
335static void
336sockaddr_to_ipaddr_port(const struct sockaddr* sockaddr, ip_addr_t* ipaddr, u16_t* port)
337{
338 if ((sockaddr->sa_family) == AF_INET6) {
339 SOCKADDR6_TO_IP6ADDR_PORT((const struct sockaddr_in6*)(const void*)(sockaddr), ipaddr, *port);
340 ipaddr->type = IPADDR_TYPE_V6;
341 } else {
342 SOCKADDR4_TO_IP4ADDR_PORT((const struct sockaddr_in*)(const void*)(sockaddr), ipaddr, *port);
343 ipaddr->type = IPADDR_TYPE_V4;
344 }
345}
346#endif /* LWIP_IPV4 && LWIP_IPV6 */
347
349void
350lwip_socket_thread_init(void)
351{
352 netconn_thread_init();
353}
354
356void
357lwip_socket_thread_cleanup(void)
358{
359 netconn_thread_cleanup();
360}
361
368static struct lwip_sock *
369get_socket(int s)
370{
371 struct lwip_sock *sock;
372
374
375 if ((s < 0) || (s >= NUM_SOCKETS)) {
376 LWIP_DEBUGF(SOCKETS_DEBUG, ("get_socket(%d): invalid\n", s + LWIP_SOCKET_OFFSET));
377 set_errno(EBADF);
378 return NULL;
379 }
380
381 sock = &sockets[s];
382
383 if (!sock->conn) {
384 LWIP_DEBUGF(SOCKETS_DEBUG, ("get_socket(%d): not active\n", s + LWIP_SOCKET_OFFSET));
385 set_errno(EBADF);
386 return NULL;
387 }
388
389 return sock;
390}
391
398static struct lwip_sock *
399tryget_socket(int s)
400{
402 if ((s < 0) || (s >= NUM_SOCKETS)) {
403 return NULL;
404 }
405 if (!sockets[s].conn) {
406 return NULL;
407 }
408 return &sockets[s];
409}
410
419static int
420alloc_socket(struct netconn *newconn, int accepted)
421{
422 int i;
424
425 /* allocate a new socket identifier */
426 for (i = 0; i < NUM_SOCKETS; ++i) {
427 /* Protect socket array */
428 SYS_ARCH_PROTECT(lev);
429 if (!sockets[i].conn && (sockets[i].select_waiting == 0)) {
430 sockets[i].conn = newconn;
431 /* The socket is not yet known to anyone, so no need to protect
432 after having marked it as used. */
433 SYS_ARCH_UNPROTECT(lev);
434 sockets[i].lastdata = NULL;
435 sockets[i].lastoffset = 0;
436 sockets[i].rcvevent = 0;
437 /* TCP sendbuf is empty, but the socket is not yet writable until connected
438 * (unless it has been created by accept()). */
439 sockets[i].sendevent = (NETCONNTYPE_GROUP(newconn->type) == NETCONN_TCP ? (accepted != 0) : 1);
440 sockets[i].errevent = 0;
441 sockets[i].err = 0;
442 return i + LWIP_SOCKET_OFFSET;
443 }
444 SYS_ARCH_UNPROTECT(lev);
445 }
446 return -1;
447}
448
455static void
456free_socket(struct lwip_sock *sock, int is_tcp)
457{
458 void *lastdata;
459
460 lastdata = sock->lastdata;
461 sock->lastdata = NULL;
462 sock->lastoffset = 0;
463 sock->err = 0;
464
465 /* Protect socket array */
466 SYS_ARCH_SET(sock->conn, NULL);
467 /* don't use 'sock' after this line, as another task might have allocated it */
468
469 if (lastdata != NULL) {
470 if (is_tcp) {
471 pbuf_free((struct pbuf *)lastdata);
472 } else {
473 netbuf_delete((struct netbuf *)lastdata);
474 }
475 }
476}
477
478/* Below this, the well-known socket functions are implemented.
479 * Use google.com or opengroup.org to get a good description :-)
480 *
481 * Exceptions are documented!
482 */
483
484int
485lwip_accept(int s, struct sockaddr *addr, socklen_t *addrlen)
486{
487 struct lwip_sock *sock, *nsock;
488 struct netconn *newconn;
489 ip_addr_t naddr;
490 u16_t port = 0;
491 int newsock;
492 err_t err;
494
495 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d)...\n", s));
496 sock = get_socket(s);
497 if (!sock) {
498 return -1;
499 }
500
501 if (netconn_is_nonblocking(sock->conn) && (sock->rcvevent <= 0)) {
502 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d): returning EWOULDBLOCK\n", s));
503 set_errno(EWOULDBLOCK);
504 return -1;
505 }
506
507 /* wait for a new connection */
508 err = netconn_accept(sock->conn, &newconn);
509 if (err != ERR_OK) {
510 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d): netconn_acept failed, err=%d\n", s, err));
511 if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_TCP) {
512 sock_set_errno(sock, EOPNOTSUPP);
513 } else if (err == ERR_CLSD) {
514 sock_set_errno(sock, EINVAL);
515 } else {
516 sock_set_errno(sock, err_to_errno(err));
517 }
518 return -1;
519 }
520 LWIP_ASSERT("newconn != NULL", newconn != NULL);
521
522 newsock = alloc_socket(newconn, 1);
523 if (newsock == -1) {
524 netconn_delete(newconn);
525 sock_set_errno(sock, ENFILE);
526 return -1;
527 }
528 LWIP_ASSERT("invalid socket index", (newsock >= LWIP_SOCKET_OFFSET) && (newsock < NUM_SOCKETS + LWIP_SOCKET_OFFSET));
529 LWIP_ASSERT("newconn->callback == event_callback", newconn->callback == event_callback);
530 nsock = &sockets[newsock - LWIP_SOCKET_OFFSET];
531
532 /* See event_callback: If data comes in right away after an accept, even
533 * though the server task might not have created a new socket yet.
534 * In that case, newconn->socket is counted down (newconn->socket--),
535 * so nsock->rcvevent is >= 1 here!
536 */
537 SYS_ARCH_PROTECT(lev);
538 nsock->rcvevent += (s16_t)(-1 - newconn->socket);
539 newconn->socket = newsock;
540 SYS_ARCH_UNPROTECT(lev);
541
542 /* Note that POSIX only requires us to check addr is non-NULL. addrlen must
543 * not be NULL if addr is valid.
544 */
545 if (addr != NULL) {
546 union sockaddr_aligned tempaddr;
547 /* get the IP address and port of the remote host */
548 err = netconn_peer(newconn, &naddr, &port);
549 if (err != ERR_OK) {
550 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d): netconn_peer failed, err=%d\n", s, err));
551 netconn_delete(newconn);
552 free_socket(nsock, 1);
553 sock_set_errno(sock, err_to_errno(err));
554 return -1;
555 }
556 LWIP_ASSERT("addr valid but addrlen NULL", addrlen != NULL);
557
558 IPADDR_PORT_TO_SOCKADDR(&tempaddr, &naddr, port);
559 if (*addrlen > tempaddr.sa.sa_len) {
560 *addrlen = tempaddr.sa.sa_len;
561 }
562 MEMCPY(addr, &tempaddr, *addrlen);
563
564 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d) returning new sock=%d addr=", s, newsock));
565 ip_addr_debug_print_val(SOCKETS_DEBUG, naddr);
566 LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F"\n", port));
567 } else {
568 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d) returning new sock=%d", s, newsock));
569 }
570
571 sock_set_errno(sock, 0);
572 return newsock;
573}
574
575int
576lwip_bind(int s, const struct sockaddr *name, socklen_t namelen)
577{
578 struct lwip_sock *sock;
579 ip_addr_t local_addr;
580 u16_t local_port;
581 err_t err;
582
583 sock = get_socket(s);
584 if (!sock) {
585 return -1;
586 }
587
588 if (!SOCK_ADDR_TYPE_MATCH(name, sock)) {
589 /* sockaddr does not match socket type (IPv4/IPv6) */
590 sock_set_errno(sock, err_to_errno(ERR_VAL));
591 return -1;
592 }
593
594 /* check size, family and alignment of 'name' */
595 LWIP_ERROR("lwip_bind: invalid address", (IS_SOCK_ADDR_LEN_VALID(namelen) &&
596 IS_SOCK_ADDR_TYPE_VALID(name) && IS_SOCK_ADDR_ALIGNED(name)),
597 sock_set_errno(sock, err_to_errno(ERR_ARG)); return -1;);
598 LWIP_UNUSED_ARG(namelen);
599
600 SOCKADDR_TO_IPADDR_PORT(name, &local_addr, local_port);
601 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d, addr=", s));
602 ip_addr_debug_print_val(SOCKETS_DEBUG, local_addr);
603 LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F")\n", local_port));
604
605#if LWIP_IPV4 && LWIP_IPV6
606 /* Dual-stack: Unmap IPv4 mapped IPv6 addresses */
607 if (IP_IS_V6_VAL(local_addr) && ip6_addr_isipv4mappedipv6(ip_2_ip6(&local_addr))) {
608 unmap_ipv4_mapped_ipv6(ip_2_ip4(&local_addr), ip_2_ip6(&local_addr));
609 IP_SET_TYPE_VAL(local_addr, IPADDR_TYPE_V4);
610 }
611#endif /* LWIP_IPV4 && LWIP_IPV6 */
612
613 err = netconn_bind(sock->conn, &local_addr, local_port);
614
615 if (err != ERR_OK) {
616 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d) failed, err=%d\n", s, err));
617 sock_set_errno(sock, err_to_errno(err));
618 return -1;
619 }
620
621 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d) succeeded\n", s));
622 sock_set_errno(sock, 0);
623 return 0;
624}
625
626int
627lwip_close(int s)
628{
629 struct lwip_sock *sock;
630 int is_tcp = 0;
631 err_t err;
632
633 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_close(%d)\n", s));
634
635 sock = get_socket(s);
636 if (!sock) {
637 return -1;
638 }
639
640 if (sock->conn != NULL) {
641 is_tcp = NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP;
642 } else {
643 LWIP_ASSERT("sock->lastdata == NULL", sock->lastdata == NULL);
644 }
645
646#if LWIP_IGMP
647 /* drop all possibly joined IGMP memberships */
648 lwip_socket_drop_registered_memberships(s);
649#endif /* LWIP_IGMP */
650
651 err = netconn_delete(sock->conn);
652 if (err != ERR_OK) {
653 sock_set_errno(sock, err_to_errno(err));
654 return -1;
655 }
656
657 free_socket(sock, is_tcp);
658 set_errno(0);
659 return 0;
660}
661
662int
663lwip_connect(int s, const struct sockaddr *name, socklen_t namelen)
664{
665 struct lwip_sock *sock;
666 err_t err;
667
668 sock = get_socket(s);
669 if (!sock) {
670 return -1;
671 }
672
673 if (!SOCK_ADDR_TYPE_MATCH_OR_UNSPEC(name, sock)) {
674 /* sockaddr does not match socket type (IPv4/IPv6) */
675 sock_set_errno(sock, err_to_errno(ERR_VAL));
676 return -1;
677 }
678
679 LWIP_UNUSED_ARG(namelen);
680 if (name->sa_family == AF_UNSPEC) {
681 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d, AF_UNSPEC)\n", s));
682 err = netconn_disconnect(sock->conn);
683 } else {
684 ip_addr_t remote_addr;
685 u16_t remote_port;
686
687 /* check size, family and alignment of 'name' */
688 LWIP_ERROR("lwip_connect: invalid address", IS_SOCK_ADDR_LEN_VALID(namelen) &&
689 IS_SOCK_ADDR_TYPE_VALID_OR_UNSPEC(name) && IS_SOCK_ADDR_ALIGNED(name),
690 sock_set_errno(sock, err_to_errno(ERR_ARG)); return -1;);
691
692 SOCKADDR_TO_IPADDR_PORT(name, &remote_addr, remote_port);
693 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d, addr=", s));
694 ip_addr_debug_print_val(SOCKETS_DEBUG, remote_addr);
695 LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F")\n", remote_port));
696
697#if LWIP_IPV4 && LWIP_IPV6
698 /* Dual-stack: Unmap IPv4 mapped IPv6 addresses */
699 if (IP_IS_V6_VAL(remote_addr) && ip6_addr_isipv4mappedipv6(ip_2_ip6(&remote_addr))) {
700 unmap_ipv4_mapped_ipv6(ip_2_ip4(&remote_addr), ip_2_ip6(&remote_addr));
701 IP_SET_TYPE_VAL(remote_addr, IPADDR_TYPE_V4);
702 }
703#endif /* LWIP_IPV4 && LWIP_IPV6 */
704
705 err = netconn_connect(sock->conn, &remote_addr, remote_port);
706 }
707
708 if (err != ERR_OK) {
709 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d) failed, err=%d\n", s, err));
710 sock_set_errno(sock, err_to_errno(err));
711 return -1;
712 }
713
714 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d) succeeded\n", s));
715 sock_set_errno(sock, 0);
716 return 0;
717}
718
727int
728lwip_listen(int s, int backlog)
729{
730 struct lwip_sock *sock;
731 err_t err;
732
733 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_listen(%d, backlog=%d)\n", s, backlog));
734
735 sock = get_socket(s);
736 if (!sock) {
737 return -1;
738 }
739
740 /* limit the "backlog" parameter to fit in an u8_t */
741 backlog = LWIP_MIN(LWIP_MAX(backlog, 0), 0xff);
742
743 err = netconn_listen_with_backlog(sock->conn, (u8_t)backlog);
744
745 if (err != ERR_OK) {
746 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_listen(%d) failed, err=%d\n", s, err));
747 if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_TCP) {
748 sock_set_errno(sock, EOPNOTSUPP);
749 return -1;
750 }
751 sock_set_errno(sock, err_to_errno(err));
752 return -1;
753 }
754
755 sock_set_errno(sock, 0);
756 return 0;
757}
758
759int
760lwip_recvfrom(int s, void *mem, size_t len, int flags,
761 struct sockaddr *from, socklen_t *fromlen)
762{
763 struct lwip_sock *sock;
764 void *buf = NULL;
765 struct pbuf *p;
766 u16_t buflen, copylen;
767 int off = 0;
768 u8_t done = 0;
769 err_t err;
770
771 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d, %p, %"SZT_F", 0x%x, ..)\n", s, mem, len, flags));
772 sock = get_socket(s);
773 if (!sock) {
774 return -1;
775 }
776
777 do {
778 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: top while sock->lastdata=%p\n", sock->lastdata));
779 /* Check if there is data left from the last recv operation. */
780 if (sock->lastdata) {
781 buf = sock->lastdata;
782 } else {
783 /* If this is non-blocking call, then check first */
784 if (((flags & MSG_DONTWAIT) || netconn_is_nonblocking(sock->conn)) &&
785 (sock->rcvevent <= 0)) {
786 if (off > 0) {
787 /* already received data, return that */
788 sock_set_errno(sock, 0);
789 return off;
790 }
791 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): returning EWOULDBLOCK\n", s));
792 set_errno(EWOULDBLOCK);
793 return -1;
794 }
795
796 /* No data was left from the previous operation, so we try to get
797 some from the network. */
798 if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) {
799 err = netconn_recv_tcp_pbuf(sock->conn, (struct pbuf **)&buf);
800 } else {
801 err = netconn_recv(sock->conn, (struct netbuf **)&buf);
802 }
803 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: netconn_recv err=%d, netbuf=%p\n",
804 err, buf));
805
806 if (err != ERR_OK) {
807 if (off > 0) {
808 if (err == ERR_CLSD) {
809 /* closed but already received data, ensure select gets the FIN, too */
810 event_callback(sock->conn, NETCONN_EVT_RCVPLUS, 0);
811 }
812 /* already received data, return that */
813 sock_set_errno(sock, 0);
814 return off;
815 }
816 /* We should really do some error checking here. */
817 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): buf == NULL, error is \"%s\"!\n",
818 s, lwip_strerr(err)));
819 sock_set_errno(sock, err_to_errno(err));
820 if (err == ERR_CLSD) {
821 return 0;
822 } else {
823 return -1;
824 }
825 }
826 LWIP_ASSERT("buf != NULL", buf != NULL);
827 sock->lastdata = buf;
828 }
829
830 if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) {
831 p = (struct pbuf *)buf;
832 } else {
833 p = ((struct netbuf *)buf)->p;
834 }
835 buflen = p->tot_len;
836 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: buflen=%"U16_F" len=%"SZT_F" off=%d sock->lastoffset=%"U16_F"\n",
837 buflen, len, off, sock->lastoffset));
838
839 buflen -= sock->lastoffset;
840
841 if (len > buflen) {
842 copylen = buflen;
843 } else {
844 copylen = (u16_t)len;
845 }
846
847 /* copy the contents of the received buffer into
848 the supplied memory pointer mem */
849 pbuf_copy_partial(p, (u8_t*)mem + off, copylen, sock->lastoffset);
850
851 off += copylen;
852
853 if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) {
854 LWIP_ASSERT("invalid copylen, len would underflow", len >= copylen);
855 len -= copylen;
856 if ((len <= 0) ||
857 (p->flags & PBUF_FLAG_PUSH) ||
858 (sock->rcvevent <= 0) ||
859 ((flags & MSG_PEEK) != 0)) {
860 done = 1;
861 }
862 } else {
863 done = 1;
864 }
865
866 /* Check to see from where the data was.*/
867 if (done) {
868#if !SOCKETS_DEBUG
869 if (from && fromlen)
870#endif /* !SOCKETS_DEBUG */
871 {
872 u16_t port;
873 ip_addr_t tmpaddr;
874 ip_addr_t *fromaddr;
875 union sockaddr_aligned saddr;
876 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): addr=", s));
877 if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) {
878 fromaddr = &tmpaddr;
879 netconn_getaddr(sock->conn, fromaddr, &port, 0);
880 } else {
881 port = netbuf_fromport((struct netbuf *)buf);
882 fromaddr = netbuf_fromaddr((struct netbuf *)buf);
883 }
884
885#if LWIP_IPV4 && LWIP_IPV6
886 /* Dual-stack: Map IPv4 addresses to IPv4 mapped IPv6 */
887 if (NETCONNTYPE_ISIPV6(netconn_type(sock->conn)) && IP_IS_V4(fromaddr)) {
888 ip4_2_ipv4_mapped_ipv6(ip_2_ip6(fromaddr), ip_2_ip4(fromaddr));
889 IP_SET_TYPE(fromaddr, IPADDR_TYPE_V6);
890 }
891#endif /* LWIP_IPV4 && LWIP_IPV6 */
892
893 IPADDR_PORT_TO_SOCKADDR(&saddr, fromaddr, port);
894 ip_addr_debug_print(SOCKETS_DEBUG, fromaddr);
895 LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F" len=%d\n", port, off));
896#if SOCKETS_DEBUG
897 if (from && fromlen)
898#endif /* SOCKETS_DEBUG */
899 {
900 if (*fromlen > saddr.sa.sa_len) {
901 *fromlen = saddr.sa.sa_len;
902 }
903 MEMCPY(from, &saddr, *fromlen);
904 }
905 }
906 }
907
908 /* If we don't peek the incoming message... */
909 if ((flags & MSG_PEEK) == 0) {
910 /* If this is a TCP socket, check if there is data left in the
911 buffer. If so, it should be saved in the sock structure for next
912 time around. */
913 if ((NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) && (buflen - copylen > 0)) {
914 sock->lastdata = buf;
915 sock->lastoffset += copylen;
916 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: lastdata now netbuf=%p\n", buf));
917 } else {
918 sock->lastdata = NULL;
919 sock->lastoffset = 0;
920 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: deleting netbuf=%p\n", buf));
921 if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) {
922 pbuf_free((struct pbuf *)buf);
923 } else {
924 netbuf_delete((struct netbuf *)buf);
925 }
926 buf = NULL;
927 }
928 }
929 } while (!done);
930
931 sock_set_errno(sock, 0);
932 return off;
933}
934
935int
936lwip_read(int s, void *mem, size_t len)
937{
938 return lwip_recvfrom(s, mem, len, 0, NULL, NULL);
939}
940
941int
942lwip_recv(int s, void *mem, size_t len, int flags)
943{
944 return lwip_recvfrom(s, mem, len, flags, NULL, NULL);
945}
946
947int
948lwip_send(int s, const void *data, size_t size, int flags)
949{
950 struct lwip_sock *sock;
951 err_t err;
952 u8_t write_flags;
953 size_t written;
954
955 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_send(%d, data=%p, size=%"SZT_F", flags=0x%x)\n",
956 s, data, size, flags));
957
958 sock = get_socket(s);
959 if (!sock) {
960 return -1;
961 }
962
963 if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_TCP) {
964#if (LWIP_UDP || LWIP_RAW)
965 return lwip_sendto(s, data, size, flags, NULL, 0);
966#else /* (LWIP_UDP || LWIP_RAW) */
967 sock_set_errno(sock, err_to_errno(ERR_ARG));
968 return -1;
969#endif /* (LWIP_UDP || LWIP_RAW) */
970 }
971
972 write_flags = NETCONN_COPY |
973 ((flags & MSG_MORE) ? NETCONN_MORE : 0) |
974 ((flags & MSG_DONTWAIT) ? NETCONN_DONTBLOCK : 0);
975 written = 0;
976 err = netconn_write_partly(sock->conn, data, size, write_flags, &written);
977
978 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_send(%d) err=%d written=%"SZT_F"\n", s, err, written));
979 sock_set_errno(sock, err_to_errno(err));
980 return (err == ERR_OK ? (int)written : -1);
981}
982
983int
984lwip_sendmsg(int s, const struct msghdr *msg, int flags)
985{
986 struct lwip_sock *sock;
987 int i;
988#if LWIP_TCP
989 u8_t write_flags;
990 size_t written;
991#endif
992 int size = 0;
993 err_t err = ERR_OK;
994
995 sock = get_socket(s);
996 if (!sock) {
997 return -1;
998 }
999
1000 LWIP_ERROR("lwip_sendmsg: invalid msghdr", msg != NULL,
1001 sock_set_errno(sock, err_to_errno(ERR_ARG)); return -1;);
1002
1003 LWIP_UNUSED_ARG(msg->msg_control);
1004 LWIP_UNUSED_ARG(msg->msg_controllen);
1005 LWIP_UNUSED_ARG(msg->msg_flags);
1006 LWIP_ERROR("lwip_sendmsg: invalid msghdr iov", (msg->msg_iov != NULL && msg->msg_iovlen != 0),
1007 sock_set_errno(sock, err_to_errno(ERR_ARG)); return -1;);
1008
1009 if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) {
1010#if LWIP_TCP
1011 write_flags = NETCONN_COPY |
1012 ((flags & MSG_MORE) ? NETCONN_MORE : 0) |
1013 ((flags & MSG_DONTWAIT) ? NETCONN_DONTBLOCK : 0);
1014
1015 for (i = 0; i < msg->msg_iovlen; i++) {
1016 u8_t apiflags = write_flags;
1017 if (i + 1 < msg->msg_iovlen) {
1018 apiflags |= NETCONN_MORE;
1019 }
1020 written = 0;
1021 err = netconn_write_partly(sock->conn, msg->msg_iov[i].iov_base, msg->msg_iov[i].iov_len, write_flags, &written);
1022 if (err == ERR_OK) {
1023 size += written;
1024 /* check that the entire IO vector was accepected, if not return a partial write */
1025 if (written != msg->msg_iov[i].iov_len)
1026 break;
1027 }
1028 /* none of this IO vector was accepted, but previous was, return partial write and conceal ERR_WOULDBLOCK */
1029 else if (err == ERR_WOULDBLOCK && size > 0) {
1030 err = ERR_OK;
1031 /* let ERR_WOULDBLOCK persist on the netconn since we are returning ERR_OK */
1032 break;
1033 } else {
1034 size = -1;
1035 break;
1036 }
1037 }
1038 sock_set_errno(sock, err_to_errno(err));
1039 return size;
1040#else /* LWIP_TCP */
1041 sock_set_errno(sock, err_to_errno(ERR_ARG));
1042 return -1;
1043#endif /* LWIP_TCP */
1044 }
1045 /* else, UDP and RAW NETCONNs */
1046#if LWIP_UDP || LWIP_RAW
1047 {
1048 struct netbuf *chain_buf;
1049
1050 LWIP_UNUSED_ARG(flags);
1051 LWIP_ERROR("lwip_sendmsg: invalid msghdr name", (((msg->msg_name == NULL) && (msg->msg_namelen == 0)) ||
1052 IS_SOCK_ADDR_LEN_VALID(msg->msg_namelen)) ,
1053 sock_set_errno(sock, err_to_errno(ERR_ARG)); return -1;);
1054
1055 /* initialize chain buffer with destination */
1056 chain_buf = netbuf_new();
1057 if (!chain_buf) {
1058 sock_set_errno(sock, err_to_errno(ERR_MEM));
1059 return -1;
1060 }
1061 if (msg->msg_name) {
1062 u16_t remote_port;
1063 SOCKADDR_TO_IPADDR_PORT((const struct sockaddr *)msg->msg_name, &chain_buf->addr, remote_port);
1064 netbuf_fromport(chain_buf) = remote_port;
1065 }
1066#if LWIP_NETIF_TX_SINGLE_PBUF
1067 for (i = 0; i < msg->msg_iovlen; i++) {
1068 size += msg->msg_iov[i].iov_len;
1069 }
1070 /* Allocate a new netbuf and copy the data into it. */
1071 if (netbuf_alloc(chain_buf, (u16_t)size) == NULL) {
1072 err = ERR_MEM;
1073 } else {
1074 /* flatten the IO vectors */
1075 size_t offset = 0;
1076 for (i = 0; i < msg->msg_iovlen; i++) {
1077 MEMCPY(&((u8_t*)chain_buf->p->payload)[offset], msg->msg_iov[i].iov_base, msg->msg_iov[i].iov_len);
1078 offset += msg->msg_iov[i].iov_len;
1079 }
1080#if LWIP_CHECKSUM_ON_COPY
1081 {
1082 /* This can be improved by using LWIP_CHKSUM_COPY() and aggregating the checksum for each IO vector */
1083 u16_t chksum = ~inet_chksum_pbuf(chain_buf->p);
1084 netbuf_set_chksum(chain_buf, chksum);
1085 }
1086#endif /* LWIP_CHECKSUM_ON_COPY */
1087 err = ERR_OK;
1088 }
1089#else /* LWIP_NETIF_TX_SINGLE_PBUF */
1090 /* create a chained netbuf from the IO vectors. NOTE: we assemble a pbuf chain
1091 manually to avoid having to allocate, chain, and delete a netbuf for each iov */
1092 for (i = 0; i < msg->msg_iovlen; i++) {
1093 struct pbuf *p = pbuf_alloc(PBUF_TRANSPORT, 0, PBUF_REF);
1094 if (p == NULL) {
1095 err = ERR_MEM; /* let netbuf_delete() cleanup chain_buf */
1096 break;
1097 }
1098 p->payload = msg->msg_iov[i].iov_base;
1099 LWIP_ASSERT("iov_len < u16_t", msg->msg_iov[i].iov_len <= 0xFFFF);
1100 p->len = p->tot_len = (u16_t)msg->msg_iov[i].iov_len;
1101 /* netbuf empty, add new pbuf */
1102 if (chain_buf->p == NULL) {
1103 chain_buf->p = chain_buf->ptr = p;
1104 /* add pbuf to existing pbuf chain */
1105 } else {
1106 pbuf_cat(chain_buf->p, p);
1107 }
1108 }
1109 /* save size of total chain */
1110 if (err == ERR_OK) {
1111 size = netbuf_len(chain_buf);
1112 }
1113#endif /* LWIP_NETIF_TX_SINGLE_PBUF */
1114
1115 if (err == ERR_OK) {
1116#if LWIP_IPV4 && LWIP_IPV6
1117 /* Dual-stack: Unmap IPv4 mapped IPv6 addresses */
1118 if (IP_IS_V6_VAL(chain_buf->addr) && ip6_addr_isipv4mappedipv6(ip_2_ip6(&chain_buf->addr))) {
1119 unmap_ipv4_mapped_ipv6(ip_2_ip4(&chain_buf->addr), ip_2_ip6(&chain_buf->addr));
1120 IP_SET_TYPE_VAL(chain_buf->addr, IPADDR_TYPE_V4);
1121 }
1122#endif /* LWIP_IPV4 && LWIP_IPV6 */
1123
1124 /* send the data */
1125 err = netconn_send(sock->conn, chain_buf);
1126 }
1127
1128 /* deallocated the buffer */
1129 netbuf_delete(chain_buf);
1130
1131 sock_set_errno(sock, err_to_errno(err));
1132 return (err == ERR_OK ? size : -1);
1133 }
1134#else /* LWIP_UDP || LWIP_RAW */
1135 sock_set_errno(sock, err_to_errno(ERR_ARG));
1136 return -1;
1137#endif /* LWIP_UDP || LWIP_RAW */
1138}
1139
1140int
1141lwip_sendto(int s, const void *data, size_t size, int flags,
1142 const struct sockaddr *to, socklen_t tolen)
1143{
1144 struct lwip_sock *sock;
1145 err_t err;
1146 u16_t short_size;
1147 u16_t remote_port;
1148 struct netbuf buf;
1149
1150 sock = get_socket(s);
1151 if (!sock) {
1152 return -1;
1153 }
1154
1155 if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) == NETCONN_TCP) {
1156#if LWIP_TCP
1157 return lwip_send(s, data, size, flags);
1158#else /* LWIP_TCP */
1159 LWIP_UNUSED_ARG(flags);
1160 sock_set_errno(sock, err_to_errno(ERR_ARG));
1161 return -1;
1162#endif /* LWIP_TCP */
1163 }
1164
1165 /* @todo: split into multiple sendto's? */
1166 LWIP_ASSERT("lwip_sendto: size must fit in u16_t", size <= 0xffff);
1167 short_size = (u16_t)size;
1168 LWIP_ERROR("lwip_sendto: invalid address", (((to == NULL) && (tolen == 0)) ||
1169 (IS_SOCK_ADDR_LEN_VALID(tolen) &&
1170 IS_SOCK_ADDR_TYPE_VALID(to) && IS_SOCK_ADDR_ALIGNED(to))),
1171 sock_set_errno(sock, err_to_errno(ERR_ARG)); return -1;);
1172 LWIP_UNUSED_ARG(tolen);
1173
1174 /* initialize a buffer */
1175 buf.p = buf.ptr = NULL;
1176#if LWIP_CHECKSUM_ON_COPY
1177 buf.flags = 0;
1178#endif /* LWIP_CHECKSUM_ON_COPY */
1179 if (to) {
1180 SOCKADDR_TO_IPADDR_PORT(to, &buf.addr, remote_port);
1181 } else {
1182 remote_port = 0;
1183 ip_addr_set_any(NETCONNTYPE_ISIPV6(netconn_type(sock->conn)), &buf.addr);
1184 }
1185 netbuf_fromport(&buf) = remote_port;
1186
1187
1188 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_sendto(%d, data=%p, short_size=%"U16_F", flags=0x%x to=",
1189 s, data, short_size, flags));
1190 ip_addr_debug_print(SOCKETS_DEBUG, &buf.addr);
1191 LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F"\n", remote_port));
1192
1193 /* make the buffer point to the data that should be sent */
1194#if LWIP_NETIF_TX_SINGLE_PBUF
1195 /* Allocate a new netbuf and copy the data into it. */
1196 if (netbuf_alloc(&buf, short_size) == NULL) {
1197 err = ERR_MEM;
1198 } else {
1199#if LWIP_CHECKSUM_ON_COPY
1200 if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_RAW) {
1201 u16_t chksum = LWIP_CHKSUM_COPY(buf.p->payload, data, short_size);
1202 netbuf_set_chksum(&buf, chksum);
1203 } else
1204#endif /* LWIP_CHECKSUM_ON_COPY */
1205 {
1206 MEMCPY(buf.p->payload, data, short_size);
1207 }
1208 err = ERR_OK;
1209 }
1210#else /* LWIP_NETIF_TX_SINGLE_PBUF */
1211 err = netbuf_ref(&buf, data, short_size);
1212#endif /* LWIP_NETIF_TX_SINGLE_PBUF */
1213 if (err == ERR_OK) {
1214#if LWIP_IPV4 && LWIP_IPV6
1215 /* Dual-stack: Unmap IPv4 mapped IPv6 addresses */
1216 if (IP_IS_V6_VAL(buf.addr) && ip6_addr_isipv4mappedipv6(ip_2_ip6(&buf.addr))) {
1217 unmap_ipv4_mapped_ipv6(ip_2_ip4(&buf.addr), ip_2_ip6(&buf.addr));
1218 IP_SET_TYPE_VAL(buf.addr, IPADDR_TYPE_V4);
1219 }
1220#endif /* LWIP_IPV4 && LWIP_IPV6 */
1221
1222 /* send the data */
1223 err = netconn_send(sock->conn, &buf);
1224 }
1225
1226 /* deallocated the buffer */
1227 netbuf_free(&buf);
1228
1229 sock_set_errno(sock, err_to_errno(err));
1230 return (err == ERR_OK ? short_size : -1);
1231}
1232
1233int
1234lwip_socket(int domain, int type, int protocol)
1235{
1236 struct netconn *conn;
1237 int i;
1238
1239 LWIP_UNUSED_ARG(domain); /* @todo: check this */
1240
1241 /* create a netconn */
1242 switch (type) {
1243 case SOCK_RAW:
1244 conn = netconn_new_with_proto_and_callback(DOMAIN_TO_NETCONN_TYPE(domain, NETCONN_RAW),
1245 (u8_t)protocol, event_callback);
1246 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_RAW, %d) = ",
1247 domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol));
1248 break;
1249 case SOCK_DGRAM:
1250 conn = netconn_new_with_callback(DOMAIN_TO_NETCONN_TYPE(domain,
1251 ((protocol == IPPROTO_UDPLITE) ? NETCONN_UDPLITE : NETCONN_UDP)) ,
1252 event_callback);
1253 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_DGRAM, %d) = ",
1254 domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol));
1255 break;
1256 case SOCK_STREAM:
1257 conn = netconn_new_with_callback(DOMAIN_TO_NETCONN_TYPE(domain, NETCONN_TCP), event_callback);
1258 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_STREAM, %d) = ",
1259 domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol));
1260 break;
1261 default:
1262 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%d, %d/UNKNOWN, %d) = -1\n",
1263 domain, type, protocol));
1264 set_errno(EINVAL);
1265 return -1;
1266 }
1267
1268 if (!conn) {
1269 LWIP_DEBUGF(SOCKETS_DEBUG, ("-1 / ENOBUFS (could not create netconn)\n"));
1270 set_errno(ENOBUFS);
1271 return -1;
1272 }
1273
1274 i = alloc_socket(conn, 0);
1275
1276 if (i == -1) {
1277 netconn_delete(conn);
1278 set_errno(ENFILE);
1279 return -1;
1280 }
1281 conn->socket = i;
1282 LWIP_DEBUGF(SOCKETS_DEBUG, ("%d\n", i));
1283 set_errno(0);
1284 return i;
1285}
1286
1287int
1288lwip_write(int s, const void *data, size_t size)
1289{
1290 return lwip_send(s, data, size, 0);
1291}
1292
1293int
1294lwip_writev(int s, const struct iovec *iov, int iovcnt)
1295{
1296 struct msghdr msg;
1297
1298 msg.msg_name = NULL;
1299 msg.msg_namelen = 0;
1300 /* Hack: we have to cast via number to cast from 'const' pointer to non-const.
1301 Blame the opengroup standard for this inconsistency. */
1302 msg.msg_iov = LWIP_CONST_CAST(struct iovec *, iov);
1303 msg.msg_iovlen = iovcnt;
1304 msg.msg_control = NULL;
1305 msg.msg_controllen = 0;
1306 msg.msg_flags = 0;
1307 return lwip_sendmsg(s, &msg, 0);
1308}
1309
1324static int
1325lwip_selscan(int maxfdp1, fd_set *readset_in, fd_set *writeset_in, fd_set *exceptset_in,
1326 fd_set *readset_out, fd_set *writeset_out, fd_set *exceptset_out)
1327{
1328 int i, nready = 0;
1329 fd_set lreadset, lwriteset, lexceptset;
1330 struct lwip_sock *sock;
1332
1333 FD_ZERO(&lreadset);
1334 FD_ZERO(&lwriteset);
1335 FD_ZERO(&lexceptset);
1336
1337 /* Go through each socket in each list to count number of sockets which
1338 currently match */
1339 for (i = LWIP_SOCKET_OFFSET; i < maxfdp1; i++) {
1340 /* if this FD is not in the set, continue */
1341 if (!(readset_in && FD_ISSET(i, readset_in)) &&
1342 !(writeset_in && FD_ISSET(i, writeset_in)) &&
1343 !(exceptset_in && FD_ISSET(i, exceptset_in))) {
1344 continue;
1345 }
1346 /* First get the socket's status (protected)... */
1347 SYS_ARCH_PROTECT(lev);
1348 sock = tryget_socket(i);
1349 if (sock != NULL) {
1350 void* lastdata = sock->lastdata;
1351 s16_t rcvevent = sock->rcvevent;
1352 u16_t sendevent = sock->sendevent;
1353 u16_t errevent = sock->errevent;
1354 SYS_ARCH_UNPROTECT(lev);
1355
1356 /* ... then examine it: */
1357 /* See if netconn of this socket is ready for read */
1358 if (readset_in && FD_ISSET(i, readset_in) && ((lastdata != NULL) || (rcvevent > 0))) {
1359 FD_SET(i, &lreadset);
1360 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_selscan: fd=%d ready for reading\n", i));
1361 nready++;
1362 }
1363 /* See if netconn of this socket is ready for write */
1364 if (writeset_in && FD_ISSET(i, writeset_in) && (sendevent != 0)) {
1365 FD_SET(i, &lwriteset);
1366 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_selscan: fd=%d ready for writing\n", i));
1367 nready++;
1368 }
1369 /* See if netconn of this socket had an error */
1370 if (exceptset_in && FD_ISSET(i, exceptset_in) && (errevent != 0)) {
1371 FD_SET(i, &lexceptset);
1372 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_selscan: fd=%d ready for exception\n", i));
1373 nready++;
1374 }
1375 } else {
1376 SYS_ARCH_UNPROTECT(lev);
1377 /* continue on to next FD in list */
1378 }
1379 }
1380 /* copy local sets to the ones provided as arguments */
1381 *readset_out = lreadset;
1382 *writeset_out = lwriteset;
1383 *exceptset_out = lexceptset;
1384
1385 LWIP_ASSERT("nready >= 0", nready >= 0);
1386 return nready;
1387}
1388
1389int
1390lwip_select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset,
1391 struct timeval *timeout)
1392{
1393 u32_t waitres = 0;
1394 int nready;
1395 fd_set lreadset, lwriteset, lexceptset;
1396 u32_t msectimeout;
1397 struct lwip_select_cb select_cb;
1398 int i;
1399 int maxfdp2;
1400#if LWIP_NETCONN_SEM_PER_THREAD
1401 int waited = 0;
1402#endif
1404
1405 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select(%d, %p, %p, %p, tvsec=%"S32_F" tvusec=%"S32_F")\n",
1406 maxfdp1, (void *)readset, (void *) writeset, (void *) exceptset,
1407 timeout ? (s32_t)timeout->tv_sec : (s32_t)-1,
1408 timeout ? (s32_t)timeout->tv_usec : (s32_t)-1));
1409
1410 /* Go through each socket in each list to count number of sockets which
1411 currently match */
1412 nready = lwip_selscan(maxfdp1, readset, writeset, exceptset, &lreadset, &lwriteset, &lexceptset);
1413
1414 /* If we don't have any current events, then suspend if we are supposed to */
1415 if (!nready) {
1416 if (timeout && timeout->tv_sec == 0 && timeout->tv_usec == 0) {
1417 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select: no timeout, returning 0\n"));
1418 /* This is OK as the local fdsets are empty and nready is zero,
1419 or we would have returned earlier. */
1420 goto return_copy_fdsets;
1421 }
1422
1423 /* None ready: add our semaphore to list:
1424 We don't actually need any dynamic memory. Our entry on the
1425 list is only valid while we are in this function, so it's ok
1426 to use local variables. */
1427
1428 select_cb.next = NULL;
1429 select_cb.prev = NULL;
1430 select_cb.readset = readset;
1431 select_cb.writeset = writeset;
1432 select_cb.exceptset = exceptset;
1433 select_cb.sem_signalled = 0;
1434#if LWIP_NETCONN_SEM_PER_THREAD
1435 select_cb.sem = LWIP_NETCONN_THREAD_SEM_GET();
1436#else /* LWIP_NETCONN_SEM_PER_THREAD */
1437 if (sys_sem_new(&select_cb.sem, 0) != ERR_OK) {
1438 /* failed to create semaphore */
1439 set_errno(ENOMEM);
1440 return -1;
1441 }
1442#endif /* LWIP_NETCONN_SEM_PER_THREAD */
1443
1444 /* Protect the select_cb_list */
1445 SYS_ARCH_PROTECT(lev);
1446
1447 /* Put this select_cb on top of list */
1448 select_cb.next = select_cb_list;
1449 if (select_cb_list != NULL) {
1450 select_cb_list->prev = &select_cb;
1451 }
1452 select_cb_list = &select_cb;
1453 /* Increasing this counter tells event_callback that the list has changed. */
1454 select_cb_ctr++;
1455
1456 /* Now we can safely unprotect */
1457 SYS_ARCH_UNPROTECT(lev);
1458
1459 /* Increase select_waiting for each socket we are interested in */
1460 maxfdp2 = maxfdp1;
1461 for (i = LWIP_SOCKET_OFFSET; i < maxfdp1; i++) {
1462 if ((readset && FD_ISSET(i, readset)) ||
1463 (writeset && FD_ISSET(i, writeset)) ||
1464 (exceptset && FD_ISSET(i, exceptset))) {
1465 struct lwip_sock *sock;
1466 SYS_ARCH_PROTECT(lev);
1467 sock = tryget_socket(i);
1468 if (sock != NULL) {
1469 sock->select_waiting++;
1470 LWIP_ASSERT("sock->select_waiting > 0", sock->select_waiting > 0);
1471 } else {
1472 /* Not a valid socket */
1473 nready = -1;
1474 maxfdp2 = i;
1475 SYS_ARCH_UNPROTECT(lev);
1476 break;
1477 }
1478 SYS_ARCH_UNPROTECT(lev);
1479 }
1480 }
1481
1482 if (nready >= 0) {
1483 /* Call lwip_selscan again: there could have been events between
1484 the last scan (without us on the list) and putting us on the list! */
1485 nready = lwip_selscan(maxfdp1, readset, writeset, exceptset, &lreadset, &lwriteset, &lexceptset);
1486 if (!nready) {
1487 /* Still none ready, just wait to be woken */
1488 if (timeout == 0) {
1489 /* Wait forever */
1490 msectimeout = 0;
1491 } else {
1492 msectimeout = ((timeout->tv_sec * 1000) + ((timeout->tv_usec + 500)/1000));
1493 if (msectimeout == 0) {
1494 /* Wait 1ms at least (0 means wait forever) */
1495 msectimeout = 1;
1496 }
1497 }
1498
1499 waitres = sys_arch_sem_wait(SELECT_SEM_PTR(select_cb.sem), msectimeout);
1500#if LWIP_NETCONN_SEM_PER_THREAD
1501 waited = 1;
1502#endif
1503 }
1504 }
1505
1506 /* Decrease select_waiting for each socket we are interested in */
1507 for (i = LWIP_SOCKET_OFFSET; i < maxfdp2; i++) {
1508 if ((readset && FD_ISSET(i, readset)) ||
1509 (writeset && FD_ISSET(i, writeset)) ||
1510 (exceptset && FD_ISSET(i, exceptset))) {
1511 struct lwip_sock *sock;
1512 SYS_ARCH_PROTECT(lev);
1513 sock = tryget_socket(i);
1514 if (sock != NULL) {
1515 /* for now, handle select_waiting==0... */
1516 LWIP_ASSERT("sock->select_waiting > 0", sock->select_waiting > 0);
1517 if (sock->select_waiting > 0) {
1518 sock->select_waiting--;
1519 }
1520 } else {
1521 /* Not a valid socket */
1522 nready = -1;
1523 }
1524 SYS_ARCH_UNPROTECT(lev);
1525 }
1526 }
1527 /* Take us off the list */
1528 SYS_ARCH_PROTECT(lev);
1529 if (select_cb.next != NULL) {
1530 select_cb.next->prev = select_cb.prev;
1531 }
1532 if (select_cb_list == &select_cb) {
1533 LWIP_ASSERT("select_cb.prev == NULL", select_cb.prev == NULL);
1534 select_cb_list = select_cb.next;
1535 } else {
1536 LWIP_ASSERT("select_cb.prev != NULL", select_cb.prev != NULL);
1537 select_cb.prev->next = select_cb.next;
1538 }
1539 /* Increasing this counter tells event_callback that the list has changed. */
1540 select_cb_ctr++;
1541 SYS_ARCH_UNPROTECT(lev);
1542
1543#if LWIP_NETCONN_SEM_PER_THREAD
1544 if (select_cb.sem_signalled && (!waited || (waitres == SYS_ARCH_TIMEOUT))) {
1545 /* don't leave the thread-local semaphore signalled */
1546 sys_arch_sem_wait(select_cb.sem, 1);
1547 }
1548#else /* LWIP_NETCONN_SEM_PER_THREAD */
1549 sys_sem_free(&select_cb.sem);
1550#endif /* LWIP_NETCONN_SEM_PER_THREAD */
1551
1552 if (nready < 0) {
1553 /* This happens when a socket got closed while waiting */
1554 set_errno(EBADF);
1555 return -1;
1556 }
1557
1558 if (waitres == SYS_ARCH_TIMEOUT) {
1559 /* Timeout */
1560 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select: timeout expired\n"));
1561 /* This is OK as the local fdsets are empty and nready is zero,
1562 or we would have returned earlier. */
1563 goto return_copy_fdsets;
1564 }
1565
1566 /* See what's set */
1567 nready = lwip_selscan(maxfdp1, readset, writeset, exceptset, &lreadset, &lwriteset, &lexceptset);
1568 }
1569
1570 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select: nready=%d\n", nready));
1571return_copy_fdsets:
1572 set_errno(0);
1573 if (readset) {
1574 *readset = lreadset;
1575 }
1576 if (writeset) {
1577 *writeset = lwriteset;
1578 }
1579 if (exceptset) {
1580 *exceptset = lexceptset;
1581 }
1582 return nready;
1583}
1584
1589static void
1590event_callback(struct netconn *conn, enum netconn_evt evt, u16_t len)
1591{
1592 int s;
1593 struct lwip_sock *sock;
1594 struct lwip_select_cb *scb;
1595 int last_select_cb_ctr;
1597
1598 LWIP_UNUSED_ARG(len);
1599
1600 /* Get socket */
1601 if (conn) {
1602 s = conn->socket;
1603 if (s < 0) {
1604 /* Data comes in right away after an accept, even though
1605 * the server task might not have created a new socket yet.
1606 * Just count down (or up) if that's the case and we
1607 * will use the data later. Note that only receive events
1608 * can happen before the new socket is set up. */
1609 SYS_ARCH_PROTECT(lev);
1610 if (conn->socket < 0) {
1611 if (evt == NETCONN_EVT_RCVPLUS) {
1612 conn->socket--;
1613 }
1614 SYS_ARCH_UNPROTECT(lev);
1615 return;
1616 }
1617 s = conn->socket;
1618 SYS_ARCH_UNPROTECT(lev);
1619 }
1620
1621 sock = get_socket(s);
1622 if (!sock) {
1623 return;
1624 }
1625 } else {
1626 return;
1627 }
1628
1629 SYS_ARCH_PROTECT(lev);
1630 /* Set event as required */
1631 switch (evt) {
1632 case NETCONN_EVT_RCVPLUS:
1633 sock->rcvevent++;
1634 break;
1635 case NETCONN_EVT_RCVMINUS:
1636 sock->rcvevent--;
1637 break;
1638 case NETCONN_EVT_SENDPLUS:
1639 sock->sendevent = 1;
1640 break;
1641 case NETCONN_EVT_SENDMINUS:
1642 sock->sendevent = 0;
1643 break;
1644 case NETCONN_EVT_ERROR:
1645 sock->errevent = 1;
1646 break;
1647 default:
1648 LWIP_ASSERT("unknown event", 0);
1649 break;
1650 }
1651
1652 if (sock->select_waiting == 0) {
1653 /* noone is waiting for this socket, no need to check select_cb_list */
1654 SYS_ARCH_UNPROTECT(lev);
1655 return;
1656 }
1657
1658 /* Now decide if anyone is waiting for this socket */
1659 /* NOTE: This code goes through the select_cb_list list multiple times
1660 ONLY IF a select was actually waiting. We go through the list the number
1661 of waiting select calls + 1. This list is expected to be small. */
1662
1663 /* At this point, SYS_ARCH is still protected! */
1664again:
1665 for (scb = select_cb_list; scb != NULL; scb = scb->next) {
1666 /* remember the state of select_cb_list to detect changes */
1667 last_select_cb_ctr = select_cb_ctr;
1668 if (scb->sem_signalled == 0) {
1669 /* semaphore not signalled yet */
1670 int do_signal = 0;
1671 /* Test this select call for our socket */
1672 if (sock->rcvevent > 0) {
1673 if (scb->readset && FD_ISSET(s, scb->readset)) {
1674 do_signal = 1;
1675 }
1676 }
1677 if (sock->sendevent != 0) {
1678 if (!do_signal && scb->writeset && FD_ISSET(s, scb->writeset)) {
1679 do_signal = 1;
1680 }
1681 }
1682 if (sock->errevent != 0) {
1683 if (!do_signal && scb->exceptset && FD_ISSET(s, scb->exceptset)) {
1684 do_signal = 1;
1685 }
1686 }
1687 if (do_signal) {
1688 scb->sem_signalled = 1;
1689 /* Don't call SYS_ARCH_UNPROTECT() before signaling the semaphore, as this might
1690 lead to the select thread taking itself off the list, invalidating the semaphore. */
1691 sys_sem_signal(SELECT_SEM_PTR(scb->sem));
1692 }
1693 }
1694 /* unlock interrupts with each step */
1695 SYS_ARCH_UNPROTECT(lev);
1696 /* this makes sure interrupt protection time is short */
1697 SYS_ARCH_PROTECT(lev);
1698 if (last_select_cb_ctr != select_cb_ctr) {
1699 /* someone has changed select_cb_list, restart at the beginning */
1700 goto again;
1701 }
1702 }
1703 SYS_ARCH_UNPROTECT(lev);
1704}
1705
1709int
1710lwip_shutdown(int s, int how)
1711{
1712 struct lwip_sock *sock;
1713 err_t err;
1714 u8_t shut_rx = 0, shut_tx = 0;
1715
1716 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_shutdown(%d, how=%d)\n", s, how));
1717
1718 sock = get_socket(s);
1719 if (!sock) {
1720 return -1;
1721 }
1722
1723 if (sock->conn != NULL) {
1724 if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_TCP) {
1725 sock_set_errno(sock, EOPNOTSUPP);
1726 return -1;
1727 }
1728 } else {
1729 sock_set_errno(sock, ENOTCONN);
1730 return -1;
1731 }
1732
1733 if (how == SHUT_RD) {
1734 shut_rx = 1;
1735 } else if (how == SHUT_WR) {
1736 shut_tx = 1;
1737 } else if (how == SHUT_RDWR) {
1738 shut_rx = 1;
1739 shut_tx = 1;
1740 } else {
1741 sock_set_errno(sock, EINVAL);
1742 return -1;
1743 }
1744 err = netconn_shutdown(sock->conn, shut_rx, shut_tx);
1745
1746 sock_set_errno(sock, err_to_errno(err));
1747 return (err == ERR_OK ? 0 : -1);
1748}
1749
1750static int
1751lwip_getaddrname(int s, struct sockaddr *name, socklen_t *namelen, u8_t local)
1752{
1753 struct lwip_sock *sock;
1754 union sockaddr_aligned saddr;
1755 ip_addr_t naddr;
1756 u16_t port;
1757 err_t err;
1758
1759 sock = get_socket(s);
1760 if (!sock) {
1761 return -1;
1762 }
1763
1764 /* get the IP address and port */
1765 err = netconn_getaddr(sock->conn, &naddr, &port, local);
1766 if (err != ERR_OK) {
1767 sock_set_errno(sock, err_to_errno(err));
1768 return -1;
1769 }
1770
1771#if LWIP_IPV4 && LWIP_IPV6
1772 /* Dual-stack: Map IPv4 addresses to IPv4 mapped IPv6 */
1773 if (NETCONNTYPE_ISIPV6(netconn_type(sock->conn)) &&
1774 IP_IS_V4_VAL(naddr)) {
1775 ip4_2_ipv4_mapped_ipv6(ip_2_ip6(&naddr), ip_2_ip4(&naddr));
1776 IP_SET_TYPE_VAL(naddr, IPADDR_TYPE_V6);
1777 }
1778#endif /* LWIP_IPV4 && LWIP_IPV6 */
1779
1780 IPADDR_PORT_TO_SOCKADDR(&saddr, &naddr, port);
1781
1782 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getaddrname(%d, addr=", s));
1783 ip_addr_debug_print_val(SOCKETS_DEBUG, naddr);
1784 LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F")\n", port));
1785
1786 if (*namelen > saddr.sa.sa_len) {
1787 *namelen = saddr.sa.sa_len;
1788 }
1789 MEMCPY(name, &saddr, *namelen);
1790
1791 sock_set_errno(sock, 0);
1792 return 0;
1793}
1794
1795int
1796lwip_getpeername(int s, struct sockaddr *name, socklen_t *namelen)
1797{
1798 return lwip_getaddrname(s, name, namelen, 0);
1799}
1800
1801int
1802lwip_getsockname(int s, struct sockaddr *name, socklen_t *namelen)
1803{
1804 return lwip_getaddrname(s, name, namelen, 1);
1805}
1806
1807int
1808lwip_getsockopt(int s, int level, int optname, void *optval, socklen_t *optlen)
1809{
1810 u8_t err;
1811 struct lwip_sock *sock = get_socket(s);
1812#if !LWIP_TCPIP_CORE_LOCKING
1813 LWIP_SETGETSOCKOPT_DATA_VAR_DECLARE(data);
1814#endif /* !LWIP_TCPIP_CORE_LOCKING */
1815
1816 if (!sock) {
1817 return -1;
1818 }
1819
1820 if ((NULL == optval) || (NULL == optlen)) {
1821 sock_set_errno(sock, EFAULT);
1822 return -1;
1823 }
1824
1825#if LWIP_TCPIP_CORE_LOCKING
1826 /* core-locking can just call the -impl function */
1827 LOCK_TCPIP_CORE();
1828 err = lwip_getsockopt_impl(s, level, optname, optval, optlen);
1829 UNLOCK_TCPIP_CORE();
1830
1831#else /* LWIP_TCPIP_CORE_LOCKING */
1832
1833#if LWIP_MPU_COMPATIBLE
1834 /* MPU_COMPATIBLE copies the optval data, so check for max size here */
1835 if (*optlen > LWIP_SETGETSOCKOPT_MAXOPTLEN) {
1836 sock_set_errno(sock, ENOBUFS);
1837 return -1;
1838 }
1839#endif /* LWIP_MPU_COMPATIBLE */
1840
1841 LWIP_SETGETSOCKOPT_DATA_VAR_ALLOC(data, sock);
1842 LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).s = s;
1843 LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).level = level;
1844 LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optname = optname;
1845 LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optlen = *optlen;
1846#if !LWIP_MPU_COMPATIBLE
1847 LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optval.p = optval;
1848#endif /* !LWIP_MPU_COMPATIBLE */
1849 LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).err = 0;
1850#if LWIP_NETCONN_SEM_PER_THREAD
1851 LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).completed_sem = LWIP_NETCONN_THREAD_SEM_GET();
1852#else
1853 LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).completed_sem = &sock->conn->op_completed;
1854#endif
1855 err = tcpip_callback(lwip_getsockopt_callback, &LWIP_SETGETSOCKOPT_DATA_VAR_REF(data));
1856 if (err != ERR_OK) {
1857 LWIP_SETGETSOCKOPT_DATA_VAR_FREE(data);
1858 sock_set_errno(sock, err_to_errno(err));
1859 return -1;
1860 }
1861 sys_arch_sem_wait((sys_sem_t*)(LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).completed_sem), 0);
1862
1863 /* write back optlen and optval */
1864 *optlen = LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optlen;
1865#if LWIP_MPU_COMPATIBLE
1866 MEMCPY(optval, LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optval,
1867 LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optlen);
1868#endif /* LWIP_MPU_COMPATIBLE */
1869
1870 /* maybe lwip_getsockopt_internal has changed err */
1871 err = LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).err;
1872 LWIP_SETGETSOCKOPT_DATA_VAR_FREE(data);
1873#endif /* LWIP_TCPIP_CORE_LOCKING */
1874
1875 sock_set_errno(sock, err);
1876 return err ? -1 : 0;
1877}
1878
1879#if !LWIP_TCPIP_CORE_LOCKING
1883static void
1884lwip_getsockopt_callback(void *arg)
1885{
1886 struct lwip_setgetsockopt_data *data;
1887 LWIP_ASSERT("arg != NULL", arg != NULL);
1888 data = (struct lwip_setgetsockopt_data*)arg;
1889
1890 data->err = lwip_getsockopt_impl(data->s, data->level, data->optname,
1892 data->optval,
1893#else /* LWIP_MPU_COMPATIBLE */
1894 data->optval.p,
1895#endif /* LWIP_MPU_COMPATIBLE */
1896 &data->optlen);
1897
1898 sys_sem_signal((sys_sem_t*)(data->completed_sem));
1899}
1900#endif /* LWIP_TCPIP_CORE_LOCKING */
1901
1905static u8_t
1906lwip_getsockopt_impl(int s, int level, int optname, void *optval, socklen_t *optlen)
1907{
1908 u8_t err = 0;
1909 struct lwip_sock *sock = tryget_socket(s);
1910 if (!sock) {
1911 return EBADF;
1912 }
1913
1914 switch (level) {
1915
1916/* Level: SOL_SOCKET */
1917 case SOL_SOCKET:
1918 switch (optname) {
1919
1920#if LWIP_TCP
1921 case SO_ACCEPTCONN:
1922 LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, *optlen, int);
1923 if (NETCONNTYPE_GROUP(sock->conn->type) != NETCONN_TCP) {
1924 return ENOPROTOOPT;
1925 }
1926 if ((sock->conn->pcb.tcp != NULL) && (sock->conn->pcb.tcp->state == LISTEN)) {
1927 *(int*)optval = 1;
1928 } else {
1929 *(int*)optval = 0;
1930 }
1931 break;
1932#endif /* LWIP_TCP */
1933
1934 /* The option flags */
1935 case SO_BROADCAST:
1936 case SO_KEEPALIVE:
1937#if SO_REUSE
1938 case SO_REUSEADDR:
1939#endif /* SO_REUSE */
1940 LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, *optlen, int);
1941 *(int*)optval = ip_get_option(sock->conn->pcb.ip, optname);
1942 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, optname=0x%x, ..) = %s\n",
1943 s, optname, (*(int*)optval?"on":"off")));
1944 break;
1945
1946 case SO_TYPE:
1947 LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, *optlen, int);
1948 switch (NETCONNTYPE_GROUP(netconn_type(sock->conn))) {
1949 case NETCONN_RAW:
1950 *(int*)optval = SOCK_RAW;
1951 break;
1952 case NETCONN_TCP:
1953 *(int*)optval = SOCK_STREAM;
1954 break;
1955 case NETCONN_UDP:
1956 *(int*)optval = SOCK_DGRAM;
1957 break;
1958 default: /* unrecognized socket type */
1959 *(int*)optval = netconn_type(sock->conn);
1961 ("lwip_getsockopt(%d, SOL_SOCKET, SO_TYPE): unrecognized socket type %d\n",
1962 s, *(int *)optval));
1963 } /* switch (netconn_type(sock->conn)) */
1964 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, SO_TYPE) = %d\n",
1965 s, *(int *)optval));
1966 break;
1967
1968 case SO_ERROR:
1969 LWIP_SOCKOPT_CHECK_OPTLEN(*optlen, int);
1970 /* only overwrite ERR_OK or temporary errors */
1971 if (((sock->err == 0) || (sock->err == EINPROGRESS)) && (sock->conn != NULL)) {
1972 sock_set_errno(sock, err_to_errno(sock->conn->last_err));
1973 }
1974 *(int *)optval = (sock->err == 0xFF ? (int)-1 : (int)sock->err);
1975 sock->err = 0;
1976 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, SO_ERROR) = %d\n",
1977 s, *(int *)optval));
1978 break;
1979
1980#if LWIP_SO_SNDTIMEO
1981 case SO_SNDTIMEO:
1982 LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, *optlen, LWIP_SO_SNDRCVTIMEO_OPTTYPE);
1983 LWIP_SO_SNDRCVTIMEO_SET(optval, netconn_get_sendtimeout(sock->conn));
1984 break;
1985#endif /* LWIP_SO_SNDTIMEO */
1986#if LWIP_SO_RCVTIMEO
1987 case SO_RCVTIMEO:
1988 LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, *optlen, LWIP_SO_SNDRCVTIMEO_OPTTYPE);
1989 LWIP_SO_SNDRCVTIMEO_SET(optval, netconn_get_recvtimeout(sock->conn));
1990 break;
1991#endif /* LWIP_SO_RCVTIMEO */
1992#if LWIP_SO_RCVBUF
1993 case SO_RCVBUF:
1994 LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, *optlen, int);
1995 *(int *)optval = netconn_get_recvbufsize(sock->conn);
1996 break;
1997#endif /* LWIP_SO_RCVBUF */
1998#if LWIP_SO_LINGER
1999 case SO_LINGER:
2000 {
2001 s16_t conn_linger;
2002 struct linger* linger = (struct linger*)optval;
2003 LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, *optlen, struct linger);
2004 conn_linger = sock->conn->linger;
2005 if (conn_linger >= 0) {
2006 linger->l_onoff = 1;
2007 linger->l_linger = (int)conn_linger;
2008 } else {
2009 linger->l_onoff = 0;
2010 linger->l_linger = 0;
2011 }
2012 }
2013 break;
2014#endif /* LWIP_SO_LINGER */
2015#if LWIP_UDP
2016 case SO_NO_CHECK:
2017 LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, *optlen, int, NETCONN_UDP);
2018#if LWIP_UDPLITE
2019 if ((udp_flags(sock->conn->pcb.udp) & UDP_FLAGS_UDPLITE) != 0) {
2020 /* this flag is only available for UDP, not for UDP lite */
2021 return EAFNOSUPPORT;
2022 }
2023#endif /* LWIP_UDPLITE */
2024 *(int*)optval = (udp_flags(sock->conn->pcb.udp) & UDP_FLAGS_NOCHKSUM) ? 1 : 0;
2025 break;
2026#endif /* LWIP_UDP*/
2027 default:
2028 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, UNIMPL: optname=0x%x, ..)\n",
2029 s, optname));
2030 err = ENOPROTOOPT;
2031 break;
2032 } /* switch (optname) */
2033 break;
2034
2035/* Level: IPPROTO_IP */
2036 case IPPROTO_IP:
2037 switch (optname) {
2038 case IP_TTL:
2039 LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, *optlen, int);
2040 *(int*)optval = sock->conn->pcb.ip->ttl;
2041 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_TTL) = %d\n",
2042 s, *(int *)optval));
2043 break;
2044 case IP_TOS:
2045 LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, *optlen, int);
2046 *(int*)optval = sock->conn->pcb.ip->tos;
2047 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_TOS) = %d\n",
2048 s, *(int *)optval));
2049 break;
2050#if LWIP_MULTICAST_TX_OPTIONS
2051 case IP_MULTICAST_TTL:
2052 LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, *optlen, u8_t);
2053 if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_UDP) {
2054 return ENOPROTOOPT;
2055 }
2056 *(u8_t*)optval = udp_get_multicast_ttl(sock->conn->pcb.udp);
2057 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_MULTICAST_TTL) = %d\n",
2058 s, *(int *)optval));
2059 break;
2060 case IP_MULTICAST_IF:
2061 LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, *optlen, struct in_addr);
2062 if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_UDP) {
2063 return ENOPROTOOPT;
2064 }
2065 inet_addr_from_ip4addr((struct in_addr*)optval, udp_get_multicast_netif_addr(sock->conn->pcb.udp));
2066 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_MULTICAST_IF) = 0x%"X32_F"\n",
2067 s, *(u32_t *)optval));
2068 break;
2069 case IP_MULTICAST_LOOP:
2070 LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, *optlen, u8_t);
2071 if ((sock->conn->pcb.udp->flags & UDP_FLAGS_MULTICAST_LOOP) != 0) {
2072 *(u8_t*)optval = 1;
2073 } else {
2074 *(u8_t*)optval = 0;
2075 }
2076 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_MULTICAST_LOOP) = %d\n",
2077 s, *(int *)optval));
2078 break;
2079#endif /* LWIP_MULTICAST_TX_OPTIONS */
2080 default:
2081 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, UNIMPL: optname=0x%x, ..)\n",
2082 s, optname));
2083 err = ENOPROTOOPT;
2084 break;
2085 } /* switch (optname) */
2086 break;
2087
2088#if LWIP_TCP
2089/* Level: IPPROTO_TCP */
2090 case IPPROTO_TCP:
2091 /* Special case: all IPPROTO_TCP option take an int */
2092 LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, *optlen, int, NETCONN_TCP);
2093 if (sock->conn->pcb.tcp->state == LISTEN) {
2094 return EINVAL;
2095 }
2096 switch (optname) {
2097 case TCP_NODELAY:
2098 *(int*)optval = tcp_nagle_disabled(sock->conn->pcb.tcp);
2099 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_TCP, TCP_NODELAY) = %s\n",
2100 s, (*(int*)optval)?"on":"off") );
2101 break;
2102 case TCP_KEEPALIVE:
2103 *(int*)optval = (int)sock->conn->pcb.tcp->keep_idle;
2104 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_TCP, TCP_KEEPALIVE) = %d\n",
2105 s, *(int *)optval));
2106 break;
2107
2108#if LWIP_TCP_KEEPALIVE
2109 case TCP_KEEPIDLE:
2110 *(int*)optval = (int)(sock->conn->pcb.tcp->keep_idle/1000);
2111 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_TCP, TCP_KEEPIDLE) = %d\n",
2112 s, *(int *)optval));
2113 break;
2114 case TCP_KEEPINTVL:
2115 *(int*)optval = (int)(sock->conn->pcb.tcp->keep_intvl/1000);
2116 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_TCP, TCP_KEEPINTVL) = %d\n",
2117 s, *(int *)optval));
2118 break;
2119 case TCP_KEEPCNT:
2120 *(int*)optval = (int)sock->conn->pcb.tcp->keep_cnt;
2121 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_TCP, TCP_KEEPCNT) = %d\n",
2122 s, *(int *)optval));
2123 break;
2124#endif /* LWIP_TCP_KEEPALIVE */
2125 default:
2126 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_TCP, UNIMPL: optname=0x%x, ..)\n",
2127 s, optname));
2128 err = ENOPROTOOPT;
2129 break;
2130 } /* switch (optname) */
2131 break;
2132#endif /* LWIP_TCP */
2133
2134#if LWIP_IPV6
2135/* Level: IPPROTO_IPV6 */
2136 case IPPROTO_IPV6:
2137 switch (optname) {
2138 case IPV6_V6ONLY:
2139 LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, *optlen, int);
2140 *(int*)optval = (netconn_get_ipv6only(sock->conn) ? 1 : 0);
2141 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IPV6, IPV6_V6ONLY) = %d\n",
2142 s, *(int *)optval));
2143 break;
2144 default:
2145 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IPV6, UNIMPL: optname=0x%x, ..)\n",
2146 s, optname));
2147 err = ENOPROTOOPT;
2148 break;
2149 } /* switch (optname) */
2150 break;
2151#endif /* LWIP_IPV6 */
2152
2153#if LWIP_UDP && LWIP_UDPLITE
2154 /* Level: IPPROTO_UDPLITE */
2155 case IPPROTO_UDPLITE:
2156 /* Special case: all IPPROTO_UDPLITE option take an int */
2157 LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, *optlen, int);
2158 /* If this is no UDP lite socket, ignore any options. */
2159 if (!NETCONNTYPE_ISUDPLITE(netconn_type(sock->conn))) {
2160 return ENOPROTOOPT;
2161 }
2162 switch (optname) {
2163 case UDPLITE_SEND_CSCOV:
2164 *(int*)optval = sock->conn->pcb.udp->chksum_len_tx;
2165 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_UDPLITE, UDPLITE_SEND_CSCOV) = %d\n",
2166 s, (*(int*)optval)) );
2167 break;
2168 case UDPLITE_RECV_CSCOV:
2169 *(int*)optval = sock->conn->pcb.udp->chksum_len_rx;
2170 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_UDPLITE, UDPLITE_RECV_CSCOV) = %d\n",
2171 s, (*(int*)optval)) );
2172 break;
2173 default:
2174 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_UDPLITE, UNIMPL: optname=0x%x, ..)\n",
2175 s, optname));
2176 err = ENOPROTOOPT;
2177 break;
2178 } /* switch (optname) */
2179 break;
2180#endif /* LWIP_UDP */
2181 /* Level: IPPROTO_RAW */
2182 case IPPROTO_RAW:
2183 switch (optname) {
2184#if LWIP_IPV6 && LWIP_RAW
2185 case IPV6_CHECKSUM:
2186 LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, *optlen, int, NETCONN_RAW);
2187 if (sock->conn->pcb.raw->chksum_reqd == 0) {
2188 *(int *)optval = -1;
2189 } else {
2190 *(int *)optval = sock->conn->pcb.raw->chksum_offset;
2191 }
2192 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_RAW, IPV6_CHECKSUM) = %d\n",
2193 s, (*(int*)optval)) );
2194 break;
2195#endif /* LWIP_IPV6 && LWIP_RAW */
2196 default:
2197 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_RAW, UNIMPL: optname=0x%x, ..)\n",
2198 s, optname));
2199 err = ENOPROTOOPT;
2200 break;
2201 } /* switch (optname) */
2202 break;
2203 default:
2204 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, level=0x%x, UNIMPL: optname=0x%x, ..)\n",
2205 s, level, optname));
2206 err = ENOPROTOOPT;
2207 break;
2208 } /* switch (level) */
2209
2210 return err;
2211}
2212
2213int
2214lwip_setsockopt(int s, int level, int optname, const void *optval, socklen_t optlen)
2215{
2216 u8_t err = 0;
2217 struct lwip_sock *sock = get_socket(s);
2218#if !LWIP_TCPIP_CORE_LOCKING
2219 LWIP_SETGETSOCKOPT_DATA_VAR_DECLARE(data);
2220#endif /* !LWIP_TCPIP_CORE_LOCKING */
2221
2222 if (!sock) {
2223 return -1;
2224 }
2225
2226 if (NULL == optval) {
2227 sock_set_errno(sock, EFAULT);
2228 return -1;
2229 }
2230
2231#if LWIP_TCPIP_CORE_LOCKING
2232 /* core-locking can just call the -impl function */
2233 LOCK_TCPIP_CORE();
2234 err = lwip_setsockopt_impl(s, level, optname, optval, optlen);
2235 UNLOCK_TCPIP_CORE();
2236
2237#else /* LWIP_TCPIP_CORE_LOCKING */
2238
2239#if LWIP_MPU_COMPATIBLE
2240 /* MPU_COMPATIBLE copies the optval data, so check for max size here */
2241 if (optlen > LWIP_SETGETSOCKOPT_MAXOPTLEN) {
2242 sock_set_errno(sock, ENOBUFS);
2243 return -1;
2244 }
2245#endif /* LWIP_MPU_COMPATIBLE */
2246
2247 LWIP_SETGETSOCKOPT_DATA_VAR_ALLOC(data, sock);
2248 LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).s = s;
2249 LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).level = level;
2250 LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optname = optname;
2251 LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optlen = optlen;
2252#if LWIP_MPU_COMPATIBLE
2253 MEMCPY(LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optval, optval, optlen);
2254#else /* LWIP_MPU_COMPATIBLE */
2255 LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).optval.pc = (const void*)optval;
2256#endif /* LWIP_MPU_COMPATIBLE */
2257 LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).err = 0;
2258#if LWIP_NETCONN_SEM_PER_THREAD
2259 LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).completed_sem = LWIP_NETCONN_THREAD_SEM_GET();
2260#else
2261 LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).completed_sem = &sock->conn->op_completed;
2262#endif
2263 err = tcpip_callback(lwip_setsockopt_callback, &LWIP_SETGETSOCKOPT_DATA_VAR_REF(data));
2264 if (err != ERR_OK) {
2265 LWIP_SETGETSOCKOPT_DATA_VAR_FREE(data);
2266 sock_set_errno(sock, err_to_errno(err));
2267 return -1;
2268 }
2269 sys_arch_sem_wait((sys_sem_t*)(LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).completed_sem), 0);
2270
2271 /* maybe lwip_getsockopt_internal has changed err */
2272 err = LWIP_SETGETSOCKOPT_DATA_VAR_REF(data).err;
2273 LWIP_SETGETSOCKOPT_DATA_VAR_FREE(data);
2274#endif /* LWIP_TCPIP_CORE_LOCKING */
2275
2276 sock_set_errno(sock, err);
2277 return err ? -1 : 0;
2278}
2279
2280#if !LWIP_TCPIP_CORE_LOCKING
2284static void
2285lwip_setsockopt_callback(void *arg)
2286{
2287 struct lwip_setgetsockopt_data *data;
2288 LWIP_ASSERT("arg != NULL", arg != NULL);
2289 data = (struct lwip_setgetsockopt_data*)arg;
2290
2291 data->err = lwip_setsockopt_impl(data->s, data->level, data->optname,
2293 data->optval,
2294#else /* LWIP_MPU_COMPATIBLE */
2295 data->optval.pc,
2296#endif /* LWIP_MPU_COMPATIBLE */
2297 data->optlen);
2298
2299 sys_sem_signal((sys_sem_t*)(data->completed_sem));
2300}
2301#endif /* LWIP_TCPIP_CORE_LOCKING */
2302
2306static u8_t
2307lwip_setsockopt_impl(int s, int level, int optname, const void *optval, socklen_t optlen)
2308{
2309 u8_t err = 0;
2310 struct lwip_sock *sock = tryget_socket(s);
2311 if (!sock) {
2312 return EBADF;
2313 }
2314
2315 switch (level) {
2316
2317/* Level: SOL_SOCKET */
2318 case SOL_SOCKET:
2319 switch (optname) {
2320
2321 /* SO_ACCEPTCONN is get-only */
2322
2323 /* The option flags */
2324 case SO_BROADCAST:
2325 case SO_KEEPALIVE:
2326#if SO_REUSE
2327 case SO_REUSEADDR:
2328#endif /* SO_REUSE */
2329 LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, optlen, int);
2330 if (*(const int*)optval) {
2331 ip_set_option(sock->conn->pcb.ip, optname);
2332 } else {
2333 ip_reset_option(sock->conn->pcb.ip, optname);
2334 }
2335 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, SOL_SOCKET, optname=0x%x, ..) -> %s\n",
2336 s, optname, (*(const int*)optval?"on":"off")));
2337 break;
2338
2339 /* SO_TYPE is get-only */
2340 /* SO_ERROR is get-only */
2341
2342#if LWIP_SO_SNDTIMEO
2343 case SO_SNDTIMEO:
2344 LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, optlen, LWIP_SO_SNDRCVTIMEO_OPTTYPE);
2345 netconn_set_sendtimeout(sock->conn, LWIP_SO_SNDRCVTIMEO_GET_MS(optval));
2346 break;
2347#endif /* LWIP_SO_SNDTIMEO */
2348#if LWIP_SO_RCVTIMEO
2349 case SO_RCVTIMEO:
2350 LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, optlen, LWIP_SO_SNDRCVTIMEO_OPTTYPE);
2351 netconn_set_recvtimeout(sock->conn, (int)LWIP_SO_SNDRCVTIMEO_GET_MS(optval));
2352 break;
2353#endif /* LWIP_SO_RCVTIMEO */
2354#if LWIP_SO_RCVBUF
2355 case SO_RCVBUF:
2356 LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, optlen, int);
2357 netconn_set_recvbufsize(sock->conn, *(const int*)optval);
2358 break;
2359#endif /* LWIP_SO_RCVBUF */
2360#if LWIP_SO_LINGER
2361 case SO_LINGER:
2362 {
2363 const struct linger* linger = (const struct linger*)optval;
2364 LWIP_SOCKOPT_CHECK_OPTLEN_CONN(sock, optlen, struct linger);
2365 if (linger->l_onoff) {
2366 int lingersec = linger->l_linger;
2367 if (lingersec < 0) {
2368 return EINVAL;
2369 }
2370 if (lingersec > 0xFFFF) {
2371 lingersec = 0xFFFF;
2372 }
2373 sock->conn->linger = (s16_t)lingersec;
2374 } else {
2375 sock->conn->linger = -1;
2376 }
2377 }
2378 break;
2379#endif /* LWIP_SO_LINGER */
2380#if LWIP_UDP
2381 case SO_NO_CHECK:
2382 LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, int, NETCONN_UDP);
2383#if LWIP_UDPLITE
2384 if ((udp_flags(sock->conn->pcb.udp) & UDP_FLAGS_UDPLITE) != 0) {
2385 /* this flag is only available for UDP, not for UDP lite */
2386 return EAFNOSUPPORT;
2387 }
2388#endif /* LWIP_UDPLITE */
2389 if (*(const int*)optval) {
2390 udp_setflags(sock->conn->pcb.udp, udp_flags(sock->conn->pcb.udp) | UDP_FLAGS_NOCHKSUM);
2391 } else {
2392 udp_setflags(sock->conn->pcb.udp, udp_flags(sock->conn->pcb.udp) & ~UDP_FLAGS_NOCHKSUM);
2393 }
2394 break;
2395#endif /* LWIP_UDP */
2396 default:
2397 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, SOL_SOCKET, UNIMPL: optname=0x%x, ..)\n",
2398 s, optname));
2399 err = ENOPROTOOPT;
2400 break;
2401 } /* switch (optname) */
2402 break;
2403
2404/* Level: IPPROTO_IP */
2405 case IPPROTO_IP:
2406 switch (optname) {
2407 case IP_TTL:
2408 LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, optlen, int);
2409 sock->conn->pcb.ip->ttl = (u8_t)(*(const int*)optval);
2410 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IP, IP_TTL, ..) -> %d\n",
2411 s, sock->conn->pcb.ip->ttl));
2412 break;
2413 case IP_TOS:
2414 LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, optlen, int);
2415 sock->conn->pcb.ip->tos = (u8_t)(*(const int*)optval);
2416 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IP, IP_TOS, ..)-> %d\n",
2417 s, sock->conn->pcb.ip->tos));
2418 break;
2419#if LWIP_MULTICAST_TX_OPTIONS
2420 case IP_MULTICAST_TTL:
2421 LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, u8_t, NETCONN_UDP);
2422 udp_set_multicast_ttl(sock->conn->pcb.udp, (u8_t)(*(const u8_t*)optval));
2423 break;
2424 case IP_MULTICAST_IF:
2425 {
2426 ip4_addr_t if_addr;
2427 LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, struct in_addr, NETCONN_UDP);
2428 inet_addr_to_ip4addr(&if_addr, (const struct in_addr*)optval);
2429 udp_set_multicast_netif_addr(sock->conn->pcb.udp, &if_addr);
2430 }
2431 break;
2432 case IP_MULTICAST_LOOP:
2433 LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, u8_t, NETCONN_UDP);
2434 if (*(const u8_t*)optval) {
2435 udp_setflags(sock->conn->pcb.udp, udp_flags(sock->conn->pcb.udp) | UDP_FLAGS_MULTICAST_LOOP);
2436 } else {
2437 udp_setflags(sock->conn->pcb.udp, udp_flags(sock->conn->pcb.udp) & ~UDP_FLAGS_MULTICAST_LOOP);
2438 }
2439 break;
2440#endif /* LWIP_MULTICAST_TX_OPTIONS */
2441#if LWIP_IGMP
2442 case IP_ADD_MEMBERSHIP:
2443 case IP_DROP_MEMBERSHIP:
2444 {
2445 /* If this is a TCP or a RAW socket, ignore these options. */
2446 /* @todo: assign membership to this socket so that it is dropped when closing the socket */
2447 err_t igmp_err;
2448 const struct ip_mreq *imr = (const struct ip_mreq *)optval;
2449 ip4_addr_t if_addr;
2450 ip4_addr_t multi_addr;
2451 LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, struct ip_mreq, NETCONN_UDP);
2452 inet_addr_to_ip4addr(&if_addr, &imr->imr_interface);
2453 inet_addr_to_ip4addr(&multi_addr, &imr->imr_multiaddr);
2454 if (optname == IP_ADD_MEMBERSHIP) {
2455 if (!lwip_socket_register_membership(s, &if_addr, &multi_addr)) {
2456 /* cannot track membership (out of memory) */
2457 err = ENOMEM;
2458 igmp_err = ERR_OK;
2459 } else {
2460 igmp_err = igmp_joingroup(&if_addr, &multi_addr);
2461 }
2462 } else {
2463 igmp_err = igmp_leavegroup(&if_addr, &multi_addr);
2464 lwip_socket_unregister_membership(s, &if_addr, &multi_addr);
2465 }
2466 if (igmp_err != ERR_OK) {
2467 err = EADDRNOTAVAIL;
2468 }
2469 }
2470 break;
2471#endif /* LWIP_IGMP */
2472 default:
2473 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IP, UNIMPL: optname=0x%x, ..)\n",
2474 s, optname));
2475 err = ENOPROTOOPT;
2476 break;
2477 } /* switch (optname) */
2478 break;
2479
2480#if LWIP_TCP
2481/* Level: IPPROTO_TCP */
2482 case IPPROTO_TCP:
2483 /* Special case: all IPPROTO_TCP option take an int */
2484 LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, int, NETCONN_TCP);
2485 if (sock->conn->pcb.tcp->state == LISTEN) {
2486 return EINVAL;
2487 }
2488 switch (optname) {
2489 case TCP_NODELAY:
2490 if (*(const int*)optval) {
2491 tcp_nagle_disable(sock->conn->pcb.tcp);
2492 } else {
2493 tcp_nagle_enable(sock->conn->pcb.tcp);
2494 }
2495 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_NODELAY) -> %s\n",
2496 s, (*(const int *)optval)?"on":"off") );
2497 break;
2498 case TCP_KEEPALIVE:
2499 sock->conn->pcb.tcp->keep_idle = (u32_t)(*(const int*)optval);
2500 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPALIVE) -> %"U32_F"\n",
2501 s, sock->conn->pcb.tcp->keep_idle));
2502 break;
2503
2504#if LWIP_TCP_KEEPALIVE
2505 case TCP_KEEPIDLE:
2506 sock->conn->pcb.tcp->keep_idle = 1000*(u32_t)(*(const int*)optval);
2507 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPIDLE) -> %"U32_F"\n",
2508 s, sock->conn->pcb.tcp->keep_idle));
2509 break;
2510 case TCP_KEEPINTVL:
2511 sock->conn->pcb.tcp->keep_intvl = 1000*(u32_t)(*(const int*)optval);
2512 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPINTVL) -> %"U32_F"\n",
2513 s, sock->conn->pcb.tcp->keep_intvl));
2514 break;
2515 case TCP_KEEPCNT:
2516 sock->conn->pcb.tcp->keep_cnt = (u32_t)(*(const int*)optval);
2517 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPCNT) -> %"U32_F"\n",
2518 s, sock->conn->pcb.tcp->keep_cnt));
2519 break;
2520#endif /* LWIP_TCP_KEEPALIVE */
2521 default:
2522 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, UNIMPL: optname=0x%x, ..)\n",
2523 s, optname));
2524 err = ENOPROTOOPT;
2525 break;
2526 } /* switch (optname) */
2527 break;
2528#endif /* LWIP_TCP*/
2529
2530#if LWIP_IPV6
2531/* Level: IPPROTO_IPV6 */
2532 case IPPROTO_IPV6:
2533 switch (optname) {
2534 case IPV6_V6ONLY:
2535 LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, int, NETCONN_TCP);
2536 if (*(const int*)optval) {
2537 netconn_set_ipv6only(sock->conn, 1);
2538 } else {
2539 netconn_set_ipv6only(sock->conn, 0);
2540 }
2541 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IPV6, IPV6_V6ONLY, ..) -> %d\n",
2542 s, (netconn_get_ipv6only(sock->conn) ? 1 : 0)));
2543 break;
2544 default:
2545 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IPV6, UNIMPL: optname=0x%x, ..)\n",
2546 s, optname));
2547 err = ENOPROTOOPT;
2548 break;
2549 } /* switch (optname) */
2550 break;
2551#endif /* LWIP_IPV6 */
2552
2553#if LWIP_UDP && LWIP_UDPLITE
2554 /* Level: IPPROTO_UDPLITE */
2555 case IPPROTO_UDPLITE:
2556 /* Special case: all IPPROTO_UDPLITE option take an int */
2557 LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB(sock, optlen, int);
2558 /* If this is no UDP lite socket, ignore any options. */
2559 if (!NETCONNTYPE_ISUDPLITE(netconn_type(sock->conn))) {
2560 return ENOPROTOOPT;
2561 }
2562 switch (optname) {
2563 case UDPLITE_SEND_CSCOV:
2564 if ((*(const int*)optval != 0) && ((*(const int*)optval < 8) || (*(const int*)optval > 0xffff))) {
2565 /* don't allow illegal values! */
2566 sock->conn->pcb.udp->chksum_len_tx = 8;
2567 } else {
2568 sock->conn->pcb.udp->chksum_len_tx = (u16_t)*(const int*)optval;
2569 }
2570 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_UDPLITE, UDPLITE_SEND_CSCOV) -> %d\n",
2571 s, (*(const int*)optval)) );
2572 break;
2573 case UDPLITE_RECV_CSCOV:
2574 if ((*(const int*)optval != 0) && ((*(const int*)optval < 8) || (*(const int*)optval > 0xffff))) {
2575 /* don't allow illegal values! */
2576 sock->conn->pcb.udp->chksum_len_rx = 8;
2577 } else {
2578 sock->conn->pcb.udp->chksum_len_rx = (u16_t)*(const int*)optval;
2579 }
2580 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_UDPLITE, UDPLITE_RECV_CSCOV) -> %d\n",
2581 s, (*(const int*)optval)) );
2582 break;
2583 default:
2584 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_UDPLITE, UNIMPL: optname=0x%x, ..)\n",
2585 s, optname));
2586 err = ENOPROTOOPT;
2587 break;
2588 } /* switch (optname) */
2589 break;
2590#endif /* LWIP_UDP */
2591 /* Level: IPPROTO_RAW */
2592 case IPPROTO_RAW:
2593 switch (optname) {
2594#if LWIP_IPV6 && LWIP_RAW
2595 case IPV6_CHECKSUM:
2596 /* It should not be possible to disable the checksum generation with ICMPv6
2597 * as per RFC 3542 chapter 3.1 */
2598 if(sock->conn->pcb.raw->protocol == IPPROTO_ICMPV6) {
2599 return EINVAL;
2600 }
2601
2602 LWIP_SOCKOPT_CHECK_OPTLEN_CONN_PCB_TYPE(sock, optlen, int, NETCONN_RAW);
2603 if (*(const int *)optval < 0) {
2604 sock->conn->pcb.raw->chksum_reqd = 0;
2605 } else if (*(const int *)optval & 1) {
2606 /* Per RFC3542, odd offsets are not allowed */
2607 return EINVAL;
2608 } else {
2609 sock->conn->pcb.raw->chksum_reqd = 1;
2610 sock->conn->pcb.raw->chksum_offset = (u16_t)*(const int *)optval;
2611 }
2612 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_RAW, IPV6_CHECKSUM, ..) -> %d\n",
2613 s, sock->conn->pcb.raw->chksum_reqd));
2614 break;
2615#endif /* LWIP_IPV6 && LWIP_RAW */
2616 default:
2617 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_RAW, UNIMPL: optname=0x%x, ..)\n",
2618 s, optname));
2619 err = ENOPROTOOPT;
2620 break;
2621 } /* switch (optname) */
2622 break;
2623 default:
2624 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, level=0x%x, UNIMPL: optname=0x%x, ..)\n",
2625 s, level, optname));
2626 err = ENOPROTOOPT;
2627 break;
2628 } /* switch (level) */
2629
2630 return err;
2631}
2632
2633int
2634lwip_ioctl(int s, long cmd, void *argp)
2635{
2636 struct lwip_sock *sock = get_socket(s);
2637 u8_t val;
2638#if LWIP_SO_RCVBUF
2639 u16_t buflen = 0;
2640 int recv_avail;
2641#endif /* LWIP_SO_RCVBUF */
2642
2643 if (!sock) {
2644 return -1;
2645 }
2646
2647 switch (cmd) {
2648#if LWIP_SO_RCVBUF || LWIP_FIONREAD_LINUXMODE
2649 case FIONREAD:
2650 if (!argp) {
2651 sock_set_errno(sock, EINVAL);
2652 return -1;
2653 }
2654#if LWIP_FIONREAD_LINUXMODE
2655 if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_TCP) {
2656 struct pbuf *p;
2657 if (sock->lastdata) {
2658 p = ((struct netbuf *)sock->lastdata)->p;
2659 *((int*)argp) = p->tot_len - sock->lastoffset;
2660 } else {
2661 struct netbuf *rxbuf;
2662 err_t err;
2663 if (sock->rcvevent <= 0) {
2664 *((int*)argp) = 0;
2665 } else {
2666 err = netconn_recv(sock->conn, &rxbuf);
2667 if (err != ERR_OK) {
2668 *((int*)argp) = 0;
2669 } else {
2670 sock->lastdata = rxbuf;
2671 sock->lastoffset = 0;
2672 *((int*)argp) = rxbuf->p->tot_len;
2673 }
2674 }
2675 }
2676 return 0;
2677 }
2678#endif /* LWIP_FIONREAD_LINUXMODE */
2679
2680#if LWIP_SO_RCVBUF
2681 /* we come here if either LWIP_FIONREAD_LINUXMODE==0 or this is a TCP socket */
2682 SYS_ARCH_GET(sock->conn->recv_avail, recv_avail);
2683 if (recv_avail < 0) {
2684 recv_avail = 0;
2685 }
2686 *((int*)argp) = recv_avail;
2687
2688 /* Check if there is data left from the last recv operation. /maq 041215 */
2689 if (sock->lastdata) {
2690 struct pbuf *p = (struct pbuf *)sock->lastdata;
2691 if (NETCONNTYPE_GROUP(netconn_type(sock->conn)) != NETCONN_TCP) {
2692 p = ((struct netbuf *)p)->p;
2693 }
2694 buflen = p->tot_len;
2695 buflen -= sock->lastoffset;
2696
2697 *((int*)argp) += buflen;
2698 }
2699
2700 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(%d, FIONREAD, %p) = %"U16_F"\n", s, argp, *((u16_t*)argp)));
2701 sock_set_errno(sock, 0);
2702 return 0;
2703#else /* LWIP_SO_RCVBUF */
2704 break;
2705#endif /* LWIP_SO_RCVBUF */
2706#endif /* LWIP_SO_RCVBUF || LWIP_FIONREAD_LINUXMODE */
2707
2708 case (long)FIONBIO:
2709 val = 0;
2710 if (argp && *(u32_t*)argp) {
2711 val = 1;
2712 }
2713 netconn_set_nonblocking(sock->conn, val);
2714 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(%d, FIONBIO, %d)\n", s, val));
2715 sock_set_errno(sock, 0);
2716 return 0;
2717
2718 default:
2719 break;
2720 } /* switch (cmd) */
2721 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(%d, UNIMPL: 0x%lx, %p)\n", s, cmd, argp));
2722 sock_set_errno(sock, ENOSYS); /* not yet implemented */
2723 return -1;
2724}
2725
2730int
2731lwip_fcntl(int s, int cmd, int val)
2732{
2733 struct lwip_sock *sock = get_socket(s);
2734 int ret = -1;
2735
2736 if (!sock) {
2737 return -1;
2738 }
2739
2740 switch (cmd) {
2741 case F_GETFL:
2742 ret = netconn_is_nonblocking(sock->conn) ? O_NONBLOCK : 0;
2743 sock_set_errno(sock, 0);
2744 break;
2745 case F_SETFL:
2746 if ((val & ~O_NONBLOCK) == 0) {
2747 /* only O_NONBLOCK, all other bits are zero */
2748 netconn_set_nonblocking(sock->conn, val & O_NONBLOCK);
2749 ret = 0;
2750 sock_set_errno(sock, 0);
2751 } else {
2752 sock_set_errno(sock, ENOSYS); /* not yet implemented */
2753 }
2754 break;
2755 default:
2756 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_fcntl(%d, UNIMPL: %d, %d)\n", s, cmd, val));
2757 sock_set_errno(sock, ENOSYS); /* not yet implemented */
2758 break;
2759 }
2760 return ret;
2761}
2762
2763#if LWIP_IGMP
2770static int
2771lwip_socket_register_membership(int s, const ip4_addr_t *if_addr, const ip4_addr_t *multi_addr)
2772{
2773 struct lwip_sock *sock = get_socket(s);
2774 int i;
2775
2776 if (!sock) {
2777 return 0;
2778 }
2779
2780 for (i = 0; i < LWIP_SOCKET_MAX_MEMBERSHIPS; i++) {
2781 if (socket_ipv4_multicast_memberships[i].sock == NULL) {
2782 socket_ipv4_multicast_memberships[i].sock = sock;
2783 ip4_addr_copy(socket_ipv4_multicast_memberships[i].if_addr, *if_addr);
2784 ip4_addr_copy(socket_ipv4_multicast_memberships[i].multi_addr, *multi_addr);
2785 return 1;
2786 }
2787 }
2788 return 0;
2789}
2790
2796static void
2797lwip_socket_unregister_membership(int s, const ip4_addr_t *if_addr, const ip4_addr_t *multi_addr)
2798{
2799 struct lwip_sock *sock = get_socket(s);
2800 int i;
2801
2802 if (!sock) {
2803 return;
2804 }
2805
2806 for (i = 0; i < LWIP_SOCKET_MAX_MEMBERSHIPS; i++) {
2807 if ((socket_ipv4_multicast_memberships[i].sock == sock) &&
2808 ip4_addr_cmp(&socket_ipv4_multicast_memberships[i].if_addr, if_addr) &&
2809 ip4_addr_cmp(&socket_ipv4_multicast_memberships[i].multi_addr, multi_addr)) {
2810 socket_ipv4_multicast_memberships[i].sock = NULL;
2811 ip4_addr_set_zero(&socket_ipv4_multicast_memberships[i].if_addr);
2812 ip4_addr_set_zero(&socket_ipv4_multicast_memberships[i].multi_addr);
2813 return;
2814 }
2815 }
2816}
2817
2822static void
2823lwip_socket_drop_registered_memberships(int s)
2824{
2825 struct lwip_sock *sock = get_socket(s);
2826 int i;
2827
2828 if (!sock) {
2829 return;
2830 }
2831
2832 for (i = 0; i < LWIP_SOCKET_MAX_MEMBERSHIPS; i++) {
2833 if (socket_ipv4_multicast_memberships[i].sock == sock) {
2834 ip_addr_t multi_addr, if_addr;
2835 ip_addr_copy_from_ip4(multi_addr, socket_ipv4_multicast_memberships[i].multi_addr);
2836 ip_addr_copy_from_ip4(if_addr, socket_ipv4_multicast_memberships[i].if_addr);
2837 socket_ipv4_multicast_memberships[i].sock = NULL;
2838 ip4_addr_set_zero(&socket_ipv4_multicast_memberships[i].if_addr);
2839 ip4_addr_set_zero(&socket_ipv4_multicast_memberships[i].multi_addr);
2840
2841 netconn_join_leave_group(sock->conn, &multi_addr, &if_addr, NETCONN_LEAVE);
2842 }
2843 }
2844}
2845#endif /* LWIP_IGMP */
2846#endif /* LWIP_SOCKET */
#define LWIP_DEBUGF(debug, message)
Definition debug.h:183
#define LWIP_UNUSED_ARG(x)
Definition arch.h:327
#define LWIP_CONST_CAST(target_type, val)
Definition arch.h:199
s8_t err_t
Definition err.h:76
@ ERR_OK
Definition err.h:82
@ ERR_CLSD
Definition err.h:113
@ ERR_VAL
Definition err.h:94
@ ERR_MEM
Definition err.h:84
@ ERR_ARG
Definition err.h:115
@ ERR_WOULDBLOCK
Definition err.h:96
@ IPADDR_TYPE_V6
Definition ip_addr.h:77
@ IPADDR_TYPE_V4
Definition ip_addr.h:75
#define SOCKETS_DEBUG
Definition opt.h:2685
#define LWIP_MPU_COMPATIBLE
Definition opt.h:188
#define LWIP_SOCKET_OFFSET
Definition opt.h:1789
void pbuf_cat(struct pbuf *h, struct pbuf *t)
Definition pbuf.c:859
struct pbuf * pbuf_alloc(pbuf_layer layer, u16_t length, pbuf_type type)
Definition pbuf.c:267
u8_t pbuf_free(struct pbuf *p)
Definition pbuf.c:734
u16_t pbuf_copy_partial(const struct pbuf *buf, void *dataptr, u16_t len, u16_t offset)
Definition pbuf.c:1034
@ PBUF_REF
Definition pbuf.h:135
@ PBUF_TRANSPORT
Definition pbuf.h:95
void sys_sem_free(sys_sem_t *sem)
Definition sys_arch.cc:152
u32_t sys_arch_sem_wait(sys_sem_t *sem, u32_t timeout)
Definition sys_arch.cc:189
void sys_sem_signal(sys_sem_t *sem)
Definition sys_arch.cc:180
err_t sys_sem_new(sys_sem_t *sem, u8_t count)
Definition sys_arch.cc:138
#define ip_set_option(pcb, opt)
Definition ip.h:236
#define ip_get_option(pcb, opt)
Definition ip.h:234
#define ip_reset_option(pcb, opt)
Definition ip.h:238
#define PBUF_FLAG_PUSH
Definition pbuf.h:147
Definition cmd.h:30
Definition inet.h:77
Definition mem.c:283
Definition pbuf.h:161
u16_t tot_len
Definition pbuf.h:175
u16_t len
Definition pbuf.h:178
void * payload
Definition pbuf.h:166
u8_t flags
Definition pbuf.h:184
#define SYS_ARCH_DECL_PROTECT(lev)
Definition sys.h:426
#define SYS_ARCH_TIMEOUT
Definition sys.h:106
#define tcpip_callback(f, ctx)
Definition tcpip.h:113