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