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