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