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