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