xref: /nrf52832-nimble/rt-thread/components/net/lwip-2.0.2/src/api/sockets.c (revision 104654410c56c573564690304ae786df310c91fc)
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