Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Fork of lwip by
sockets.c
00001 /** 00002 * @file 00003 * Sockets BSD-Like API module 00004 * 00005 */ 00006 00007 /* 00008 * Copyright (c) 2001-2004 Swedish Institute of Computer Science. 00009 * All rights reserved. 00010 * 00011 * Redistribution and use in source and binary forms, with or without modification, 00012 * are permitted provided that the following conditions are met: 00013 * 00014 * 1. Redistributions of source code must retain the above copyright notice, 00015 * this list of conditions and the following disclaimer. 00016 * 2. Redistributions in binary form must reproduce the above copyright notice, 00017 * this list of conditions and the following disclaimer in the documentation 00018 * and/or other materials provided with the distribution. 00019 * 3. The name of the author may not be used to endorse or promote products 00020 * derived from this software without specific prior written permission. 00021 * 00022 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 00023 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 00024 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 00025 * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 00026 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 00027 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 00028 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 00029 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 00030 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 00031 * OF SUCH DAMAGE. 00032 * 00033 * This file is part of the lwIP TCP/IP stack. 00034 * 00035 * Author: Adam Dunkels <adam@sics.se> 00036 * 00037 * Improved by Marc Boucher <marc@mbsi.ca> and David Haas <dhaas@alum.rpi.edu> 00038 * 00039 */ 00040 00041 #include "lwip/opt.h" 00042 00043 #if LWIP_SOCKET /* don't build if not configured for use in lwipopts.h */ 00044 00045 #include "lwip/sockets.h" 00046 #include "lwip/api.h" 00047 #include "lwip/sys.h" 00048 #include "lwip/igmp.h" 00049 #include "lwip/inet.h" 00050 #include "lwip/tcp.h" 00051 #include "lwip/raw.h" 00052 #include "lwip/udp.h" 00053 #include "lwip/tcpip.h" 00054 00055 #include <string.h> 00056 00057 #define NUM_SOCKETS MEMP_NUM_NETCONN 00058 00059 /** Contains all internal pointers and states used for a socket */ 00060 struct lwip_socket { 00061 /** sockets currently are built on netconns, each socket has one netconn */ 00062 struct netconn *conn; 00063 /** data that was left from the previous read */ 00064 struct netbuf *lastdata; 00065 /** offset in the data that was left from the previous read */ 00066 u16_t lastoffset; 00067 /** number of times data was received, set by event_callback(), 00068 tested by the receive and select functions */ 00069 u16_t rcvevent; 00070 /** number of times data was received, set by event_callback(), 00071 tested by select */ 00072 u16_t sendevent; 00073 /** socket flags (currently, only used for O_NONBLOCK) */ 00074 u16_t flags; 00075 /** last error that occurred on this socket */ 00076 int err; 00077 }; 00078 00079 /** Description for a task waiting in select */ 00080 struct lwip_select_cb { 00081 /** Pointer to the next waiting task */ 00082 struct lwip_select_cb *next; 00083 /** readset passed to select */ 00084 fd_set *readset; 00085 /** writeset passed to select */ 00086 fd_set *writeset; 00087 /** unimplemented: exceptset passed to select */ 00088 fd_set *exceptset; 00089 /** don't signal the same semaphore twice: set to 1 when signalled */ 00090 int sem_signalled; 00091 /** semaphore to wake up a task waiting for select */ 00092 sys_sem_t sem; 00093 }; 00094 00095 /** This struct is used to pass data to the set/getsockopt_internal 00096 * functions running in tcpip_thread context (only a void* is allowed) */ 00097 struct lwip_setgetsockopt_data { 00098 /** socket struct for which to change options */ 00099 struct lwip_socket *sock; 00100 /** socket index for which to change options */ 00101 int s; 00102 /** level of the option to process */ 00103 int level; 00104 /** name of the option to process */ 00105 int optname; 00106 /** set: value to set the option to 00107 * get: value of the option is stored here */ 00108 void *optval; 00109 /** size of *optval */ 00110 socklen_t *optlen; 00111 /** if an error occures, it is temporarily stored here */ 00112 err_t err; 00113 }; 00114 00115 /** The global array of available sockets */ 00116 static struct lwip_socket sockets[NUM_SOCKETS]; 00117 /** The global list of tasks waiting for select */ 00118 static struct lwip_select_cb *select_cb_list; 00119 00120 /** Semaphore protecting the sockets array */ 00121 static sys_sem_t socksem; 00122 /** Semaphore protecting select_cb_list */ 00123 static sys_sem_t selectsem; 00124 00125 /** Table to quickly map an lwIP error (err_t) to a socket error 00126 * by using -err as an index */ 00127 static const int err_to_errno_table[] = { 00128 0, /* ERR_OK 0 No error, everything OK. */ 00129 ENOMEM, /* ERR_MEM -1 Out of memory error. */ 00130 ENOBUFS, /* ERR_BUF -2 Buffer error. */ 00131 EHOSTUNREACH, /* ERR_RTE -3 Routing problem. */ 00132 ECONNABORTED, /* ERR_ABRT -4 Connection aborted. */ 00133 ECONNRESET, /* ERR_RST -5 Connection reset. */ 00134 ESHUTDOWN, /* ERR_CLSD -6 Connection closed. */ 00135 ENOTCONN, /* ERR_CONN -7 Not connected. */ 00136 EINVAL, /* ERR_VAL -8 Illegal value. */ 00137 EIO, /* ERR_ARG -9 Illegal argument. */ 00138 EADDRINUSE, /* ERR_USE -10 Address in use. */ 00139 -1, /* ERR_IF -11 Low-level netif error */ 00140 -1, /* ERR_ISCONN -12 Already connected. */ 00141 ETIMEDOUT, /* ERR_TIMEOUT -13 Timeout */ 00142 EINPROGRESS /* ERR_INPROGRESS -14 Operation in progress */ 00143 }; 00144 00145 #define ERR_TO_ERRNO_TABLE_SIZE \ 00146 (sizeof(err_to_errno_table)/sizeof(err_to_errno_table[0])) 00147 00148 #define err_to_errno(err) \ 00149 ((unsigned)(-(err)) < ERR_TO_ERRNO_TABLE_SIZE ? \ 00150 err_to_errno_table[-(err)] : EIO) 00151 00152 #ifdef ERRNO 00153 #define set_errno(err) errno = (err) 00154 #else 00155 #define set_errno(err) 00156 #endif 00157 00158 #define sock_set_errno(sk, e) do { \ 00159 sk->err = (e); \ 00160 set_errno(sk->err); \ 00161 } while (0) 00162 00163 /* Forward delcaration of some functions */ 00164 static void event_callback(struct netconn *conn, enum netconn_evt evt, u16_t len); 00165 static void lwip_getsockopt_internal(void *arg); 00166 static void lwip_setsockopt_internal(void *arg); 00167 00168 /** 00169 * Initialize this module. This function has to be called before any other 00170 * functions in this module! 00171 */ 00172 void 00173 lwip_socket_init(void) 00174 { 00175 socksem = sys_sem_new(1); 00176 selectsem = sys_sem_new(1); 00177 } 00178 00179 /** 00180 * Map a externally used socket index to the internal socket representation. 00181 * 00182 * @param s externally used socket index 00183 * @return struct lwip_socket for the socket or NULL if not found 00184 */ 00185 static struct lwip_socket * 00186 get_socket(int s) 00187 { 00188 struct lwip_socket *sock; 00189 00190 if ((s < 0) || (s >= NUM_SOCKETS)) { 00191 LWIP_DEBUGF(SOCKETS_DEBUG, ("get_socket(%d): invalid\n", s)); 00192 set_errno(EBADF); 00193 return NULL; 00194 } 00195 00196 sock = &sockets[s]; 00197 00198 if (!sock->conn) { 00199 LWIP_DEBUGF(SOCKETS_DEBUG, ("get_socket(%d): not active\n", s)); 00200 set_errno(EBADF); 00201 return NULL; 00202 } 00203 00204 return sock; 00205 } 00206 00207 /** 00208 * Allocate a new socket for a given netconn. 00209 * 00210 * @param newconn the netconn for which to allocate a socket 00211 * @return the index of the new socket; -1 on error 00212 */ 00213 static int 00214 alloc_socket(struct netconn *newconn) 00215 { 00216 int i; 00217 00218 /* Protect socket array */ 00219 sys_sem_wait(socksem); 00220 00221 /* allocate a new socket identifier */ 00222 for (i = 0; i < NUM_SOCKETS; ++i) { 00223 if (!sockets[i].conn) { 00224 sockets[i].conn = newconn; 00225 sockets[i].lastdata = NULL; 00226 sockets[i].lastoffset = 0; 00227 sockets[i].rcvevent = 0; 00228 sockets[i].sendevent = 1; /* TCP send buf is empty */ 00229 sockets[i].flags = 0; 00230 sockets[i].err = 0; 00231 sys_sem_signal(socksem); 00232 return i; 00233 } 00234 } 00235 sys_sem_signal(socksem); 00236 return -1; 00237 } 00238 00239 /* Below this, the well-known socket functions are implemented. 00240 * Use google.com or opengroup.org to get a good description :-) 00241 * 00242 * Exceptions are documented! 00243 */ 00244 00245 int 00246 lwip_accept(int s, struct sockaddr *addr, socklen_t *addrlen) 00247 { 00248 struct lwip_socket *sock, *nsock; 00249 struct netconn *newconn; 00250 struct ip_addr naddr; 00251 u16_t port; 00252 int newsock; 00253 struct sockaddr_in sin; 00254 err_t err; 00255 00256 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d)...\n", s)); 00257 sock = get_socket(s); 00258 if (!sock) 00259 return -1; 00260 00261 newconn = netconn_accept(sock->conn); 00262 if (!newconn) { 00263 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d) failed, err=%d\n", s, sock->conn->err)); 00264 sock_set_errno(sock, err_to_errno(sock->conn->err)); 00265 return -1; 00266 } 00267 00268 /* get the IP address and port of the remote host */ 00269 err = netconn_peer(newconn, &naddr, &port); 00270 if (err != ERR_OK) { 00271 netconn_delete(newconn); 00272 sock_set_errno(sock, err_to_errno(err)); 00273 return -1; 00274 } 00275 00276 memset(&sin, 0, sizeof(sin)); 00277 sin.sin_len = sizeof(sin); 00278 sin.sin_family = AF_INET; 00279 sin.sin_port = htons(port); 00280 sin.sin_addr.s_addr = naddr.addr; 00281 00282 if (*addrlen > sizeof(sin)) 00283 *addrlen = sizeof(sin); 00284 00285 SMEMCPY(addr, &sin, *addrlen); 00286 00287 newsock = alloc_socket(newconn); 00288 if (newsock == -1) { 00289 netconn_delete(newconn); 00290 sock_set_errno(sock, ENFILE); 00291 return -1; 00292 } 00293 LWIP_ASSERT("invalid socket index", (newsock >= 0) && (newsock < NUM_SOCKETS)); 00294 newconn->callback = event_callback; 00295 nsock = &sockets[newsock]; 00296 LWIP_ASSERT("invalid socket pointer", nsock != NULL); 00297 00298 sys_sem_wait(socksem); 00299 /* See event_callback: If data comes in right away after an accept, even 00300 * though the server task might not have created a new socket yet. 00301 * In that case, newconn->socket is counted down (newconn->socket--), 00302 * so nsock->rcvevent is >= 1 here! 00303 */ 00304 nsock->rcvevent += -1 - newconn->socket; 00305 newconn->socket = newsock; 00306 sys_sem_signal(socksem); 00307 00308 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d) returning new sock=%d addr=", s, newsock)); 00309 ip_addr_debug_print(SOCKETS_DEBUG, &naddr); 00310 LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%u\n", port)); 00311 00312 sock_set_errno(sock, 0); 00313 return newsock; 00314 } 00315 00316 int 00317 lwip_bind(int s, struct sockaddr *name, socklen_t namelen) 00318 { 00319 struct lwip_socket *sock; 00320 struct ip_addr local_addr; 00321 u16_t local_port; 00322 err_t err; 00323 00324 sock = get_socket(s); 00325 if (!sock) 00326 return -1; 00327 00328 LWIP_ERROR("lwip_bind: invalid address", ((namelen == sizeof(struct sockaddr_in)) && 00329 ((((struct sockaddr_in *)name)->sin_family) == AF_INET)), 00330 sock_set_errno(sock, err_to_errno(ERR_ARG)); return -1;); 00331 00332 local_addr.addr = ((struct sockaddr_in *)name)->sin_addr.s_addr; 00333 local_port = ((struct sockaddr_in *)name)->sin_port; 00334 00335 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d, addr=", s)); 00336 ip_addr_debug_print(SOCKETS_DEBUG, &local_addr); 00337 LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%u)\n", ntohs(local_port))); 00338 00339 err = netconn_bind(sock->conn, &local_addr, ntohs(local_port)); 00340 00341 if (err != ERR_OK) { 00342 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d) failed, err=%d\n", s, err)); 00343 sock_set_errno(sock, err_to_errno(err)); 00344 return -1; 00345 } 00346 00347 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d) succeeded\n", s)); 00348 sock_set_errno(sock, 0); 00349 return 0; 00350 } 00351 00352 int 00353 lwip_close(int s) 00354 { 00355 struct lwip_socket *sock; 00356 00357 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_close(%d)\n", s)); 00358 00359 sock = get_socket(s); 00360 if (!sock) { 00361 return -1; 00362 } 00363 00364 netconn_delete(sock->conn); 00365 00366 sys_sem_wait(socksem); 00367 if (sock->lastdata) { 00368 netbuf_delete(sock->lastdata); 00369 } 00370 sock->lastdata = NULL; 00371 sock->lastoffset = 0; 00372 sock->conn = NULL; 00373 sock_set_errno(sock, 0); 00374 sys_sem_signal(socksem); 00375 return 0; 00376 } 00377 00378 int 00379 lwip_connect(int s, const struct sockaddr *name, socklen_t namelen) 00380 { 00381 struct lwip_socket *sock; 00382 err_t err; 00383 00384 sock = get_socket(s); 00385 if (!sock) 00386 return -1; 00387 00388 LWIP_ERROR("lwip_connect: invalid address", ((namelen == sizeof(struct sockaddr_in)) && 00389 ((((struct sockaddr_in *)name)->sin_family) == AF_INET)), 00390 sock_set_errno(sock, err_to_errno(ERR_ARG)); return -1;); 00391 00392 if (((struct sockaddr_in *)name)->sin_family == AF_UNSPEC) { 00393 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d, AF_UNSPEC)\n", s)); 00394 err = netconn_disconnect(sock->conn); 00395 } else { 00396 struct ip_addr remote_addr; 00397 u16_t remote_port; 00398 00399 remote_addr.addr = ((struct sockaddr_in *)name)->sin_addr.s_addr; 00400 remote_port = ((struct sockaddr_in *)name)->sin_port; 00401 00402 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d, addr=", s)); 00403 ip_addr_debug_print(SOCKETS_DEBUG, &remote_addr); 00404 LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%u)\n", ntohs(remote_port))); 00405 00406 err = netconn_connect(sock->conn, &remote_addr, ntohs(remote_port)); 00407 } 00408 00409 if (err != ERR_OK) { 00410 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d) failed, err=%d\n", s, err)); 00411 sock_set_errno(sock, err_to_errno(err)); 00412 return -1; 00413 } 00414 00415 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d) succeeded\n", s)); 00416 sock_set_errno(sock, 0); 00417 return 0; 00418 } 00419 00420 /** 00421 * Set a socket into listen mode. 00422 * The socket may not have been used for another connection previously. 00423 * 00424 * @param s the socket to set to listening mode 00425 * @param backlog (ATTENTION: need TCP_LISTEN_BACKLOG=1) 00426 * @return 0 on success, non-zero on failure 00427 */ 00428 int 00429 lwip_listen(int s, int backlog) 00430 { 00431 struct lwip_socket *sock; 00432 err_t err; 00433 00434 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_listen(%d, backlog=%d)\n", s, backlog)); 00435 00436 sock = get_socket(s); 00437 if (!sock) 00438 return -1; 00439 00440 /* limit the "backlog" parameter to fit in an u8_t */ 00441 if (backlog < 0) { 00442 backlog = 0; 00443 } 00444 if (backlog > 0xff) { 00445 backlog = 0xff; 00446 } 00447 00448 err = netconn_listen_with_backlog(sock->conn, backlog); 00449 00450 if (err != ERR_OK) { 00451 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_listen(%d) failed, err=%d\n", s, err)); 00452 sock_set_errno(sock, err_to_errno(err)); 00453 return -1; 00454 } 00455 00456 sock_set_errno(sock, 0); 00457 return 0; 00458 } 00459 00460 int 00461 lwip_recvfrom(int s, void *mem, int len, unsigned int flags, 00462 struct sockaddr *from, socklen_t *fromlen) 00463 { 00464 struct lwip_socket *sock; 00465 struct netbuf *buf; 00466 u16_t buflen, copylen, off = 0; 00467 struct ip_addr *addr; 00468 u16_t port; 00469 u8_t done = 0; 00470 00471 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d, %p, %d, 0x%x, ..)\n", s, mem, len, flags)); 00472 sock = get_socket(s); 00473 if (!sock) 00474 return -1; 00475 00476 do { 00477 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: top while sock->lastdata=%p\n", (void*)sock->lastdata)); 00478 /* Check if there is data left from the last recv operation. */ 00479 if (sock->lastdata) { 00480 buf = sock->lastdata; 00481 } else { 00482 /* If this is non-blocking call, then check first */ 00483 if (((flags & MSG_DONTWAIT) || (sock->flags & O_NONBLOCK)) && !sock->rcvevent) { 00484 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): returning EWOULDBLOCK\n", s)); 00485 sock_set_errno(sock, EWOULDBLOCK); 00486 return -1; 00487 } 00488 00489 /* No data was left from the previous operation, so we try to get 00490 some from the network. */ 00491 sock->lastdata = buf = netconn_recv(sock->conn); 00492 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: netconn_recv netbuf=%p\n", (void*)buf)); 00493 00494 if (!buf) { 00495 /* We should really do some error checking here. */ 00496 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): buf == NULL!\n", s)); 00497 sock_set_errno(sock, (((sock->conn->pcb.ip!=NULL) && (sock->conn->err==ERR_OK))?ETIMEDOUT:err_to_errno(sock->conn->err))); 00498 return 0; 00499 } 00500 } 00501 00502 buflen = netbuf_len(buf); 00503 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: buflen=%d len=%d off=%d sock->lastoffset=%d\n", buflen, len, off, sock->lastoffset)); 00504 00505 buflen -= sock->lastoffset; 00506 00507 if (len > buflen) { 00508 copylen = buflen; 00509 } else { 00510 copylen = len; 00511 } 00512 00513 /* copy the contents of the received buffer into 00514 the supplied memory pointer mem */ 00515 netbuf_copy_partial(buf, (u8_t*)mem + off, copylen, sock->lastoffset); 00516 00517 off += copylen; 00518 00519 if (netconn_type(sock->conn) == NETCONN_TCP) { 00520 len -= copylen; 00521 if ( (len <= 0) || (buf->p->flags & PBUF_FLAG_PUSH) || !sock->rcvevent) { 00522 done = 1; 00523 } 00524 } else { 00525 done = 1; 00526 } 00527 00528 /* If we don't peek the incoming message... */ 00529 if ((flags & MSG_PEEK)==0) { 00530 /* If this is a TCP socket, check if there is data left in the 00531 buffer. If so, it should be saved in the sock structure for next 00532 time around. */ 00533 if ((sock->conn->type == NETCONN_TCP) && (buflen - copylen > 0)) { 00534 sock->lastdata = buf; 00535 sock->lastoffset += copylen; 00536 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: lastdata now netbuf=%p\n", (void*)buf)); 00537 } else { 00538 sock->lastdata = NULL; 00539 sock->lastoffset = 0; 00540 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: deleting netbuf=%p\n", (void*)buf)); 00541 netbuf_delete(buf); 00542 } 00543 } else { 00544 done = 1; 00545 } 00546 } while (!done); 00547 00548 /* Check to see from where the data was.*/ 00549 if (from && fromlen) { 00550 struct sockaddr_in sin; 00551 00552 if (netconn_type(sock->conn) == NETCONN_TCP) { 00553 addr = (struct ip_addr*)&(sin.sin_addr.s_addr); 00554 netconn_getaddr(sock->conn, addr, &port, 0); 00555 } else { 00556 addr = netbuf_fromaddr(buf); 00557 port = netbuf_fromport(buf); 00558 } 00559 00560 memset(&sin, 0, sizeof(sin)); 00561 sin.sin_len = sizeof(sin); 00562 sin.sin_family = AF_INET; 00563 sin.sin_port = htons(port); 00564 sin.sin_addr.s_addr = addr->addr; 00565 00566 if (*fromlen > sizeof(sin)) 00567 *fromlen = sizeof(sin); 00568 00569 SMEMCPY(from, &sin, *fromlen); 00570 00571 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): addr=", s)); 00572 ip_addr_debug_print(SOCKETS_DEBUG, addr); 00573 LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%u len=%u\n", port, off)); 00574 } else { 00575 #if SOCKETS_DEBUG 00576 struct sockaddr_in sin; 00577 00578 if (netconn_type(sock->conn) == NETCONN_TCP) { 00579 addr = (struct ip_addr*)&(sin.sin_addr.s_addr); 00580 netconn_getaddr(sock->conn, addr, &port, 0); 00581 } else { 00582 addr = netbuf_fromaddr(buf); 00583 port = netbuf_fromport(buf); 00584 } 00585 00586 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): addr=", s)); 00587 ip_addr_debug_print(SOCKETS_DEBUG, addr); 00588 LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%u len=%u\n", port, off)); 00589 #endif /* SOCKETS_DEBUG */ 00590 } 00591 00592 sock_set_errno(sock, 0); 00593 return off; 00594 } 00595 00596 int 00597 lwip_read(int s, void *mem, int len) 00598 { 00599 return lwip_recvfrom(s, mem, len, 0, NULL, NULL); 00600 } 00601 00602 int 00603 lwip_recv(int s, void *mem, int len, unsigned int flags) 00604 { 00605 return lwip_recvfrom(s, mem, len, flags, NULL, NULL); 00606 } 00607 00608 int 00609 lwip_send(int s, const void *data, int size, unsigned int flags) 00610 { 00611 struct lwip_socket *sock; 00612 err_t err; 00613 00614 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_send(%d, data=%p, size=%d, flags=0x%x)\n", 00615 s, data, size, flags)); 00616 00617 sock = get_socket(s); 00618 if (!sock) 00619 return -1; 00620 00621 if (sock->conn->type!=NETCONN_TCP) { 00622 #if (LWIP_UDP || LWIP_RAW) 00623 return lwip_sendto(s, data, size, flags, NULL, 0); 00624 #else 00625 sock_set_errno(sock, err_to_errno(ERR_ARG)); 00626 return -1; 00627 #endif /* (LWIP_UDP || LWIP_RAW) */ 00628 } 00629 00630 err = netconn_write(sock->conn, data, size, NETCONN_COPY | ((flags & MSG_MORE)?NETCONN_MORE:0)); 00631 00632 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_send(%d) err=%d size=%d\n", s, err, size)); 00633 sock_set_errno(sock, err_to_errno(err)); 00634 return (err==ERR_OK?size:-1); 00635 } 00636 00637 int 00638 lwip_sendto(int s, const void *data, int size, unsigned int flags, 00639 struct sockaddr *to, socklen_t tolen) 00640 { 00641 struct lwip_socket *sock; 00642 struct ip_addr remote_addr; 00643 int err; 00644 #if !LWIP_TCPIP_CORE_LOCKING 00645 struct netbuf buf; 00646 u16_t remote_port; 00647 #endif 00648 00649 sock = get_socket(s); 00650 if (!sock) 00651 return -1; 00652 00653 if (sock->conn->type==NETCONN_TCP) { 00654 #if LWIP_TCP 00655 return lwip_send(s, data, size, flags); 00656 #else 00657 sock_set_errno(sock, err_to_errno(ERR_ARG)); 00658 return -1; 00659 #endif /* LWIP_TCP */ 00660 } 00661 00662 LWIP_ASSERT("lwip_sendto: size must fit in u16_t", 00663 ((size >= 0) && (size <= 0xffff))); 00664 LWIP_ERROR("lwip_sendto: invalid address", (((to == NULL) && (tolen == 0)) || 00665 ((tolen == sizeof(struct sockaddr_in)) && 00666 ((((struct sockaddr_in *)to)->sin_family) == AF_INET))), 00667 sock_set_errno(sock, err_to_errno(ERR_ARG)); return -1;); 00668 00669 #if LWIP_TCPIP_CORE_LOCKING 00670 /* Should only be consider like a sample or a simple way to experiment this option (no check of "to" field...) */ 00671 { struct pbuf* p; 00672 00673 p = pbuf_alloc(PBUF_TRANSPORT, 0, PBUF_REF); 00674 if (p == NULL) { 00675 err = ERR_MEM; 00676 } else { 00677 p->payload = (void*)data; 00678 p->len = p->tot_len = size; 00679 00680 remote_addr.addr = ((struct sockaddr_in *)to)->sin_addr.s_addr; 00681 00682 LOCK_TCPIP_CORE(); 00683 if (sock->conn->type==NETCONN_RAW) { 00684 err = sock->conn->err = raw_sendto(sock->conn->pcb.raw, p, &remote_addr); 00685 } else { 00686 err = sock->conn->err = udp_sendto(sock->conn->pcb.udp, p, &remote_addr, ntohs(((struct sockaddr_in *)to)->sin_port)); 00687 } 00688 UNLOCK_TCPIP_CORE(); 00689 00690 pbuf_free(p); 00691 } 00692 } 00693 #else 00694 /* initialize a buffer */ 00695 buf.p = buf.ptr = NULL; 00696 if (to) { 00697 remote_addr.addr = ((struct sockaddr_in *)to)->sin_addr.s_addr; 00698 remote_port = ntohs(((struct sockaddr_in *)to)->sin_port); 00699 buf.addr = &remote_addr; 00700 buf.port = remote_port; 00701 } else { 00702 remote_addr.addr = 0; 00703 remote_port = 0; 00704 buf.addr = NULL; 00705 buf.port = 0; 00706 } 00707 00708 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_sendto(%d, data=%p, size=%d, flags=0x%x to=", 00709 s, data, size, flags)); 00710 ip_addr_debug_print(SOCKETS_DEBUG, &remote_addr); 00711 LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%u\n", remote_port)); 00712 00713 /* make the buffer point to the data that should be sent */ 00714 if ((err = netbuf_ref(&buf, data, size)) == ERR_OK) { 00715 /* send the data */ 00716 err = netconn_send(sock->conn, &buf); 00717 } 00718 00719 /* deallocated the buffer */ 00720 if (buf.p != NULL) { 00721 pbuf_free(buf.p); 00722 } 00723 #endif /* LWIP_TCPIP_CORE_LOCKING */ 00724 sock_set_errno(sock, err_to_errno(err)); 00725 return (err==ERR_OK?size:-1); 00726 } 00727 00728 int 00729 lwip_socket(int domain, int type, int protocol) 00730 { 00731 struct netconn *conn; 00732 int i; 00733 00734 LWIP_UNUSED_ARG(domain); 00735 00736 /* create a netconn */ 00737 switch (type) { 00738 case SOCK_RAW: 00739 conn = netconn_new_with_proto_and_callback(NETCONN_RAW, (u8_t)protocol, event_callback); 00740 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_RAW, %d) = ", 00741 domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol)); 00742 break; 00743 case SOCK_DGRAM: 00744 conn = netconn_new_with_callback( (protocol == IPPROTO_UDPLITE) ? 00745 NETCONN_UDPLITE : NETCONN_UDP, event_callback); 00746 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_DGRAM, %d) = ", 00747 domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol)); 00748 break; 00749 case SOCK_STREAM: 00750 conn = netconn_new_with_callback(NETCONN_TCP, event_callback); 00751 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_STREAM, %d) = ", 00752 domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol)); 00753 break; 00754 default: 00755 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%d, %d/UNKNOWN, %d) = -1\n", 00756 domain, type, protocol)); 00757 set_errno(EINVAL); 00758 return -1; 00759 } 00760 00761 if (!conn) { 00762 LWIP_DEBUGF(SOCKETS_DEBUG, ("-1 / ENOBUFS (could not create netconn)\n")); 00763 set_errno(ENOBUFS); 00764 return -1; 00765 } 00766 00767 i = alloc_socket(conn); 00768 00769 if (i == -1) { 00770 netconn_delete(conn); 00771 set_errno(ENFILE); 00772 return -1; 00773 } 00774 conn->socket = i; 00775 LWIP_DEBUGF(SOCKETS_DEBUG, ("%d\n", i)); 00776 set_errno(0); 00777 return i; 00778 } 00779 00780 int 00781 lwip_write(int s, const void *data, int size) 00782 { 00783 return lwip_send(s, data, size, 0); 00784 } 00785 00786 /** 00787 * Go through the readset and writeset lists and see which socket of the sockets 00788 * set in the sets has events. On return, readset, writeset and exceptset have 00789 * the sockets enabled that had events. 00790 * 00791 * exceptset is not used for now!!! 00792 * 00793 * @param maxfdp1 the highest socket index in the sets 00794 * @param readset in: set of sockets to check for read events; 00795 * out: set of sockets that had read events 00796 * @param writeset in: set of sockets to check for write events; 00797 * out: set of sockets that had write events 00798 * @param exceptset not yet implemented 00799 * @return number of sockets that had events (read+write) 00800 */ 00801 static int 00802 lwip_selscan(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset) 00803 { 00804 int i, nready = 0; 00805 fd_set lreadset, lwriteset, lexceptset; 00806 struct lwip_socket *p_sock; 00807 00808 FD_ZERO(&lreadset); 00809 FD_ZERO(&lwriteset); 00810 FD_ZERO(&lexceptset); 00811 00812 /* Go through each socket in each list to count number of sockets which 00813 currently match */ 00814 for(i = 0; i < maxfdp1; i++) { 00815 if (FD_ISSET(i, readset)) { 00816 /* See if netconn of this socket is ready for read */ 00817 p_sock = get_socket(i); 00818 if (p_sock && (p_sock->lastdata || p_sock->rcvevent)) { 00819 FD_SET(i, &lreadset); 00820 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_selscan: fd=%d ready for reading\n", i)); 00821 nready++; 00822 } 00823 } 00824 if (FD_ISSET(i, writeset)) { 00825 /* See if netconn of this socket is ready for write */ 00826 p_sock = get_socket(i); 00827 if (p_sock && p_sock->sendevent) { 00828 FD_SET(i, &lwriteset); 00829 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_selscan: fd=%d ready for writing\n", i)); 00830 nready++; 00831 } 00832 } 00833 } 00834 *readset = lreadset; 00835 *writeset = lwriteset; 00836 FD_ZERO(exceptset); 00837 00838 return nready; 00839 } 00840 00841 00842 /** 00843 * Processing exceptset is not yet implemented. 00844 */ 00845 int 00846 lwip_select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset, 00847 struct timeval *timeout) 00848 { 00849 int i; 00850 int nready; 00851 fd_set lreadset, lwriteset, lexceptset; 00852 u32_t msectimeout; 00853 struct lwip_select_cb select_cb; 00854 struct lwip_select_cb *p_selcb; 00855 00856 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select(%d, %p, %p, %p, tvsec=%ld tvusec=%ld)\n", 00857 maxfdp1, (void *)readset, (void *) writeset, (void *) exceptset, 00858 timeout ? timeout->tv_sec : -1L, timeout ? timeout->tv_usec : -1L)); 00859 00860 select_cb.next = 0; 00861 select_cb.readset = readset; 00862 select_cb.writeset = writeset; 00863 select_cb.exceptset = exceptset; 00864 select_cb.sem_signalled = 0; 00865 00866 /* Protect ourselves searching through the list */ 00867 sys_sem_wait(selectsem); 00868 00869 if (readset) 00870 lreadset = *readset; 00871 else 00872 FD_ZERO(&lreadset); 00873 if (writeset) 00874 lwriteset = *writeset; 00875 else 00876 FD_ZERO(&lwriteset); 00877 if (exceptset) 00878 lexceptset = *exceptset; 00879 else 00880 FD_ZERO(&lexceptset); 00881 00882 /* Go through each socket in each list to count number of sockets which 00883 currently match */ 00884 nready = lwip_selscan(maxfdp1, &lreadset, &lwriteset, &lexceptset); 00885 00886 /* If we don't have any current events, then suspend if we are supposed to */ 00887 if (!nready) { 00888 if (timeout && timeout->tv_sec == 0 && timeout->tv_usec == 0) { 00889 sys_sem_signal(selectsem); 00890 if (readset) 00891 FD_ZERO(readset); 00892 if (writeset) 00893 FD_ZERO(writeset); 00894 if (exceptset) 00895 FD_ZERO(exceptset); 00896 00897 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select: no timeout, returning 0\n")); 00898 set_errno(0); 00899 00900 return 0; 00901 } 00902 00903 /* add our semaphore to list */ 00904 /* We don't actually need any dynamic memory. Our entry on the 00905 * list is only valid while we are in this function, so it's ok 00906 * to use local variables */ 00907 00908 select_cb.sem = sys_sem_new(0); 00909 /* Note that we are still protected */ 00910 /* Put this select_cb on top of list */ 00911 select_cb.next = select_cb_list; 00912 select_cb_list = &select_cb; 00913 00914 /* Now we can safely unprotect */ 00915 sys_sem_signal(selectsem); 00916 00917 /* Now just wait to be woken */ 00918 if (timeout == 0) 00919 /* Wait forever */ 00920 msectimeout = 0; 00921 else { 00922 msectimeout = ((timeout->tv_sec * 1000) + ((timeout->tv_usec + 500)/1000)); 00923 if(msectimeout == 0) 00924 msectimeout = 1; 00925 } 00926 00927 i = sys_sem_wait_timeout(select_cb.sem, msectimeout); 00928 00929 /* Take us off the list */ 00930 sys_sem_wait(selectsem); 00931 if (select_cb_list == &select_cb) 00932 select_cb_list = select_cb.next; 00933 else 00934 for (p_selcb = select_cb_list; p_selcb; p_selcb = p_selcb->next) { 00935 if (p_selcb->next == &select_cb) { 00936 p_selcb->next = select_cb.next; 00937 break; 00938 } 00939 } 00940 00941 sys_sem_signal(selectsem); 00942 00943 sys_sem_free(select_cb.sem); 00944 if (i == 0) { 00945 /* Timeout */ 00946 if (readset) 00947 FD_ZERO(readset); 00948 if (writeset) 00949 FD_ZERO(writeset); 00950 if (exceptset) 00951 FD_ZERO(exceptset); 00952 00953 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select: timeout expired\n")); 00954 set_errno(0); 00955 00956 return 0; 00957 } 00958 00959 if (readset) 00960 lreadset = *readset; 00961 else 00962 FD_ZERO(&lreadset); 00963 if (writeset) 00964 lwriteset = *writeset; 00965 else 00966 FD_ZERO(&lwriteset); 00967 if (exceptset) 00968 lexceptset = *exceptset; 00969 else 00970 FD_ZERO(&lexceptset); 00971 00972 /* See what's set */ 00973 nready = lwip_selscan(maxfdp1, &lreadset, &lwriteset, &lexceptset); 00974 } else 00975 sys_sem_signal(selectsem); 00976 00977 if (readset) 00978 *readset = lreadset; 00979 if (writeset) 00980 *writeset = lwriteset; 00981 if (exceptset) 00982 *exceptset = lexceptset; 00983 00984 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select: nready=%d\n", nready)); 00985 set_errno(0); 00986 00987 return nready; 00988 } 00989 00990 /** 00991 * Callback registered in the netconn layer for each socket-netconn. 00992 * Processes recvevent (data available) and wakes up tasks waiting for select. 00993 */ 00994 static void 00995 event_callback(struct netconn *conn, enum netconn_evt evt, u16_t len) 00996 { 00997 int s; 00998 struct lwip_socket *sock; 00999 struct lwip_select_cb *scb; 01000 01001 LWIP_UNUSED_ARG(len); 01002 01003 /* Get socket */ 01004 if (conn) { 01005 s = conn->socket; 01006 if (s < 0) { 01007 /* Data comes in right away after an accept, even though 01008 * the server task might not have created a new socket yet. 01009 * Just count down (or up) if that's the case and we 01010 * will use the data later. Note that only receive events 01011 * can happen before the new socket is set up. */ 01012 sys_sem_wait(socksem); 01013 if (conn->socket < 0) { 01014 if (evt == NETCONN_EVT_RCVPLUS) { 01015 conn->socket--; 01016 } 01017 sys_sem_signal(socksem); 01018 return; 01019 } 01020 sys_sem_signal(socksem); 01021 } 01022 01023 sock = get_socket(s); 01024 if (!sock) { 01025 return; 01026 } 01027 } else { 01028 return; 01029 } 01030 01031 sys_sem_wait(selectsem); 01032 /* Set event as required */ 01033 switch (evt) { 01034 case NETCONN_EVT_RCVPLUS: 01035 sock->rcvevent++; 01036 break; 01037 case NETCONN_EVT_RCVMINUS: 01038 sock->rcvevent--; 01039 break; 01040 case NETCONN_EVT_SENDPLUS: 01041 sock->sendevent = 1; 01042 break; 01043 case NETCONN_EVT_SENDMINUS: 01044 sock->sendevent = 0; 01045 break; 01046 default: 01047 LWIP_ASSERT("unknown event", 0); 01048 break; 01049 } 01050 sys_sem_signal(selectsem); 01051 01052 /* Now decide if anyone is waiting for this socket */ 01053 /* NOTE: This code is written this way to protect the select link list 01054 but to avoid a deadlock situation by releasing socksem before 01055 signalling for the select. This means we need to go through the list 01056 multiple times ONLY IF a select was actually waiting. We go through 01057 the list the number of waiting select calls + 1. This list is 01058 expected to be small. */ 01059 while (1) { 01060 sys_sem_wait(selectsem); 01061 for (scb = select_cb_list; scb; scb = scb->next) { 01062 if (scb->sem_signalled == 0) { 01063 /* Test this select call for our socket */ 01064 if (scb->readset && FD_ISSET(s, scb->readset)) 01065 if (sock->rcvevent) 01066 break; 01067 if (scb->writeset && FD_ISSET(s, scb->writeset)) 01068 if (sock->sendevent) 01069 break; 01070 } 01071 } 01072 if (scb) { 01073 scb->sem_signalled = 1; 01074 sys_sem_signal(selectsem); 01075 sys_sem_signal(scb->sem); 01076 } else { 01077 sys_sem_signal(selectsem); 01078 break; 01079 } 01080 } 01081 } 01082 01083 /** 01084 * Unimplemented: Close one end of a full-duplex connection. 01085 * Currently, the full connection is closed. 01086 */ 01087 int 01088 lwip_shutdown(int s, int how) 01089 { 01090 LWIP_UNUSED_ARG(how); 01091 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_shutdown(%d, how=%d)\n", s, how)); 01092 return lwip_close(s); /* XXX temporary hack until proper implementation */ 01093 } 01094 01095 static int 01096 lwip_getaddrname(int s, struct sockaddr *name, socklen_t *namelen, u8_t local) 01097 { 01098 struct lwip_socket *sock; 01099 struct sockaddr_in sin; 01100 struct ip_addr naddr; 01101 01102 sock = get_socket(s); 01103 if (!sock) 01104 return -1; 01105 01106 memset(&sin, 0, sizeof(sin)); 01107 sin.sin_len = sizeof(sin); 01108 sin.sin_family = AF_INET; 01109 01110 /* get the IP address and port */ 01111 netconn_getaddr(sock->conn, &naddr, &sin.sin_port, local); 01112 01113 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getaddrname(%d, addr=", s)); 01114 ip_addr_debug_print(SOCKETS_DEBUG, &naddr); 01115 LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%d)\n", sin.sin_port)); 01116 01117 sin.sin_port = htons(sin.sin_port); 01118 sin.sin_addr.s_addr = naddr.addr; 01119 01120 if (*namelen > sizeof(sin)) 01121 *namelen = sizeof(sin); 01122 01123 SMEMCPY(name, &sin, *namelen); 01124 sock_set_errno(sock, 0); 01125 return 0; 01126 } 01127 01128 int 01129 lwip_getpeername(int s, struct sockaddr *name, socklen_t *namelen) 01130 { 01131 return lwip_getaddrname(s, name, namelen, 0); 01132 } 01133 01134 int 01135 lwip_getsockname(int s, struct sockaddr *name, socklen_t *namelen) 01136 { 01137 return lwip_getaddrname(s, name, namelen, 1); 01138 } 01139 01140 int 01141 lwip_getsockopt(int s, int level, int optname, void *optval, socklen_t *optlen) 01142 { 01143 err_t err = ERR_OK; 01144 struct lwip_socket *sock = get_socket(s); 01145 struct lwip_setgetsockopt_data data; 01146 01147 if (!sock) 01148 return -1; 01149 01150 if ((NULL == optval) || (NULL == optlen)) { 01151 sock_set_errno(sock, EFAULT); 01152 return -1; 01153 } 01154 01155 /* Do length and type checks for the various options first, to keep it readable. */ 01156 switch (level) { 01157 01158 /* Level: SOL_SOCKET */ 01159 case SOL_SOCKET: 01160 switch (optname) { 01161 01162 case SO_ACCEPTCONN: 01163 case SO_BROADCAST: 01164 /* UNIMPL case SO_DEBUG: */ 01165 /* UNIMPL case SO_DONTROUTE: */ 01166 case SO_ERROR: 01167 case SO_KEEPALIVE: 01168 /* UNIMPL case SO_CONTIMEO: */ 01169 /* UNIMPL case SO_SNDTIMEO: */ 01170 #if LWIP_SO_RCVTIMEO 01171 case SO_RCVTIMEO: 01172 #endif /* LWIP_SO_RCVTIMEO */ 01173 #if LWIP_SO_RCVBUF 01174 case SO_RCVBUF: 01175 #endif /* LWIP_SO_RCVBUF */ 01176 /* UNIMPL case SO_OOBINLINE: */ 01177 /* UNIMPL case SO_SNDBUF: */ 01178 /* UNIMPL case SO_RCVLOWAT: */ 01179 /* UNIMPL case SO_SNDLOWAT: */ 01180 #if SO_REUSE 01181 case SO_REUSEADDR: 01182 case SO_REUSEPORT: 01183 #endif /* SO_REUSE */ 01184 case SO_TYPE: 01185 /* UNIMPL case SO_USELOOPBACK: */ 01186 if (*optlen < sizeof(int)) { 01187 err = EINVAL; 01188 } 01189 break; 01190 01191 case SO_NO_CHECK: 01192 if (*optlen < sizeof(int)) { 01193 err = EINVAL; 01194 } 01195 #if LWIP_UDP 01196 if ((sock->conn->type != NETCONN_UDP) || 01197 ((udp_flags(sock->conn->pcb.udp) & UDP_FLAGS_UDPLITE) != 0)) { 01198 /* this flag is only available for UDP, not for UDP lite */ 01199 err = EAFNOSUPPORT; 01200 } 01201 #endif /* LWIP_UDP */ 01202 break; 01203 01204 default: 01205 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, UNIMPL: optname=0x%x, ..)\n", 01206 s, optname)); 01207 err = ENOPROTOOPT; 01208 } /* switch (optname) */ 01209 break; 01210 01211 /* Level: IPPROTO_IP */ 01212 case IPPROTO_IP: 01213 switch (optname) { 01214 /* UNIMPL case IP_HDRINCL: */ 01215 /* UNIMPL case IP_RCVDSTADDR: */ 01216 /* UNIMPL case IP_RCVIF: */ 01217 case IP_TTL: 01218 case IP_TOS: 01219 if (*optlen < sizeof(int)) { 01220 err = EINVAL; 01221 } 01222 break; 01223 #if LWIP_IGMP 01224 case IP_MULTICAST_TTL: 01225 if (*optlen < sizeof(u8_t)) { 01226 err = EINVAL; 01227 } 01228 break; 01229 case IP_MULTICAST_IF: 01230 if (*optlen < sizeof(struct in_addr)) { 01231 err = EINVAL; 01232 } 01233 break; 01234 #endif /* LWIP_IGMP */ 01235 01236 default: 01237 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, UNIMPL: optname=0x%x, ..)\n", 01238 s, optname)); 01239 err = ENOPROTOOPT; 01240 } /* switch (optname) */ 01241 break; 01242 01243 #if LWIP_TCP 01244 /* Level: IPPROTO_TCP */ 01245 case IPPROTO_TCP: 01246 if (*optlen < sizeof(int)) { 01247 err = EINVAL; 01248 break; 01249 } 01250 01251 /* If this is no TCP socket, ignore any options. */ 01252 if (sock->conn->type != NETCONN_TCP) 01253 return 0; 01254 01255 switch (optname) { 01256 case TCP_NODELAY: 01257 case TCP_KEEPALIVE: 01258 #if LWIP_TCP_KEEPALIVE 01259 case TCP_KEEPIDLE: 01260 case TCP_KEEPINTVL: 01261 case TCP_KEEPCNT: 01262 #endif /* LWIP_TCP_KEEPALIVE */ 01263 break; 01264 01265 default: 01266 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_TCP, UNIMPL: optname=0x%x, ..)\n", 01267 s, optname)); 01268 err = ENOPROTOOPT; 01269 } /* switch (optname) */ 01270 break; 01271 #endif /* LWIP_TCP */ 01272 #if LWIP_UDP && LWIP_UDPLITE 01273 /* Level: IPPROTO_UDPLITE */ 01274 case IPPROTO_UDPLITE: 01275 if (*optlen < sizeof(int)) { 01276 err = EINVAL; 01277 break; 01278 } 01279 01280 /* If this is no UDP lite socket, ignore any options. */ 01281 if (sock->conn->type != NETCONN_UDPLITE) 01282 return 0; 01283 01284 switch (optname) { 01285 case UDPLITE_SEND_CSCOV: 01286 case UDPLITE_RECV_CSCOV: 01287 break; 01288 01289 default: 01290 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_UDPLITE, UNIMPL: optname=0x%x, ..)\n", 01291 s, optname)); 01292 err = ENOPROTOOPT; 01293 } /* switch (optname) */ 01294 break; 01295 #endif /* LWIP_UDP && LWIP_UDPLITE*/ 01296 /* UNDEFINED LEVEL */ 01297 default: 01298 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, level=0x%x, UNIMPL: optname=0x%x, ..)\n", 01299 s, level, optname)); 01300 err = ENOPROTOOPT; 01301 } /* switch */ 01302 01303 01304 if (err != ERR_OK) { 01305 sock_set_errno(sock, err); 01306 return -1; 01307 } 01308 01309 /* Now do the actual option processing */ 01310 data.sock = sock; 01311 data.level = level; 01312 data.optname = optname; 01313 data.optval = optval; 01314 data.optlen = optlen; 01315 data.err = err; 01316 tcpip_callback(lwip_getsockopt_internal, &data); 01317 sys_arch_sem_wait(sock->conn->op_completed, 0); 01318 /* maybe lwip_getsockopt_internal has changed err */ 01319 err = data.err; 01320 01321 sock_set_errno(sock, err); 01322 return err ? -1 : 0; 01323 } 01324 01325 static void 01326 lwip_getsockopt_internal(void *arg) 01327 { 01328 struct lwip_socket *sock; 01329 #ifdef LWIP_DEBUG 01330 int s; 01331 #endif /* LWIP_DEBUG */ 01332 int level, optname; 01333 void *optval; 01334 struct lwip_setgetsockopt_data *data; 01335 01336 LWIP_ASSERT("arg != NULL", arg != NULL); 01337 01338 data = (struct lwip_setgetsockopt_data*)arg; 01339 sock = data->sock; 01340 #ifdef LWIP_DEBUG 01341 s = data->s; 01342 #endif /* LWIP_DEBUG */ 01343 level = data->level; 01344 optname = data->optname; 01345 optval = data->optval; 01346 01347 switch (level) { 01348 01349 /* Level: SOL_SOCKET */ 01350 case SOL_SOCKET: 01351 switch (optname) { 01352 01353 /* The option flags */ 01354 case SO_ACCEPTCONN: 01355 case SO_BROADCAST: 01356 /* UNIMPL case SO_DEBUG: */ 01357 /* UNIMPL case SO_DONTROUTE: */ 01358 case SO_KEEPALIVE: 01359 /* UNIMPL case SO_OOBINCLUDE: */ 01360 #if SO_REUSE 01361 case SO_REUSEADDR: 01362 case SO_REUSEPORT: 01363 #endif /* SO_REUSE */ 01364 /*case SO_USELOOPBACK: UNIMPL */ 01365 *(int*)optval = sock->conn->pcb.ip->so_options & optname; 01366 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, optname=0x%x, ..) = %s\n", 01367 s, optname, (*(int*)optval?"on":"off"))); 01368 break; 01369 01370 case SO_TYPE: 01371 switch (NETCONNTYPE_GROUP(sock->conn->type)) { 01372 case NETCONN_RAW: 01373 *(int*)optval = SOCK_RAW; 01374 break; 01375 case NETCONN_TCP: 01376 *(int*)optval = SOCK_STREAM; 01377 break; 01378 case NETCONN_UDP: 01379 *(int*)optval = SOCK_DGRAM; 01380 break; 01381 default: /* unrecognized socket type */ 01382 *(int*)optval = sock->conn->type; 01383 LWIP_DEBUGF(SOCKETS_DEBUG, 01384 ("lwip_getsockopt(%d, SOL_SOCKET, SO_TYPE): unrecognized socket type %d\n", 01385 s, *(int *)optval)); 01386 } /* switch (sock->conn->type) */ 01387 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, SO_TYPE) = %d\n", 01388 s, *(int *)optval)); 01389 break; 01390 01391 case SO_ERROR: 01392 if (sock->err == 0) { 01393 sock_set_errno(sock, err_to_errno(sock->conn->err)); 01394 } 01395 *(int *)optval = sock->err; 01396 sock->err = 0; 01397 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, SO_ERROR) = %d\n", 01398 s, *(int *)optval)); 01399 break; 01400 01401 #if LWIP_SO_RCVTIMEO 01402 case SO_RCVTIMEO: 01403 *(int *)optval = sock->conn->recv_timeout; 01404 break; 01405 #endif /* LWIP_SO_RCVTIMEO */ 01406 #if LWIP_SO_RCVBUF 01407 case SO_RCVBUF: 01408 *(int *)optval = sock->conn->recv_bufsize; 01409 break; 01410 #endif /* LWIP_SO_RCVBUF */ 01411 #if LWIP_UDP 01412 case SO_NO_CHECK: 01413 *(int*)optval = (udp_flags(sock->conn->pcb.udp) & UDP_FLAGS_NOCHKSUM) ? 1 : 0; 01414 break; 01415 #endif /* LWIP_UDP*/ 01416 } /* switch (optname) */ 01417 break; 01418 01419 /* Level: IPPROTO_IP */ 01420 case IPPROTO_IP: 01421 switch (optname) { 01422 case IP_TTL: 01423 *(int*)optval = sock->conn->pcb.ip->ttl; 01424 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_TTL) = %d\n", 01425 s, *(int *)optval)); 01426 break; 01427 case IP_TOS: 01428 *(int*)optval = sock->conn->pcb.ip->tos; 01429 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_TOS) = %d\n", 01430 s, *(int *)optval)); 01431 break; 01432 #if LWIP_IGMP 01433 case IP_MULTICAST_TTL: 01434 *(u8_t*)optval = sock->conn->pcb.ip->ttl; 01435 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_MULTICAST_TTL) = %d\n", 01436 s, *(int *)optval)); 01437 break; 01438 case IP_MULTICAST_IF: 01439 ((struct in_addr*) optval)->s_addr = sock->conn->pcb.udp->multicast_ip.addr; 01440 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_MULTICAST_IF) = 0x%x\n", 01441 s, *(u32_t *)optval)); 01442 break; 01443 #endif /* LWIP_IGMP */ 01444 } /* switch (optname) */ 01445 break; 01446 01447 #if LWIP_TCP 01448 /* Level: IPPROTO_TCP */ 01449 case IPPROTO_TCP: 01450 switch (optname) { 01451 case TCP_NODELAY: 01452 *(int*)optval = (sock->conn->pcb.tcp->flags & TF_NODELAY); 01453 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_TCP, TCP_NODELAY) = %s\n", 01454 s, (*(int*)optval)?"on":"off") ); 01455 break; 01456 case TCP_KEEPALIVE: 01457 *(int*)optval = (int)sock->conn->pcb.tcp->keep_idle; 01458 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, TCP_KEEPALIVE) = %d\n", 01459 s, *(int *)optval)); 01460 break; 01461 01462 #if LWIP_TCP_KEEPALIVE 01463 case TCP_KEEPIDLE: 01464 *(int*)optval = (int)(sock->conn->pcb.tcp->keep_idle/1000); 01465 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, TCP_KEEPIDLE) = %d\n", 01466 s, *(int *)optval)); 01467 break; 01468 case TCP_KEEPINTVL: 01469 *(int*)optval = (int)(sock->conn->pcb.tcp->keep_intvl/1000); 01470 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, TCP_KEEPINTVL) = %d\n", 01471 s, *(int *)optval)); 01472 break; 01473 case TCP_KEEPCNT: 01474 *(int*)optval = (int)sock->conn->pcb.tcp->keep_cnt; 01475 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, TCP_KEEPCNT) = %d\n", 01476 s, *(int *)optval)); 01477 break; 01478 #endif /* LWIP_TCP_KEEPALIVE */ 01479 01480 } /* switch (optname) */ 01481 break; 01482 #endif /* LWIP_TCP */ 01483 #if LWIP_UDP && LWIP_UDPLITE 01484 /* Level: IPPROTO_UDPLITE */ 01485 case IPPROTO_UDPLITE: 01486 switch (optname) { 01487 case UDPLITE_SEND_CSCOV: 01488 *(int*)optval = sock->conn->pcb.udp->chksum_len_tx; 01489 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_UDPLITE, UDPLITE_SEND_CSCOV) = %d\n", 01490 s, (*(int*)optval)) ); 01491 break; 01492 case UDPLITE_RECV_CSCOV: 01493 *(int*)optval = sock->conn->pcb.udp->chksum_len_rx; 01494 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_UDPLITE, UDPLITE_RECV_CSCOV) = %d\n", 01495 s, (*(int*)optval)) ); 01496 break; 01497 } /* switch (optname) */ 01498 break; 01499 #endif /* LWIP_UDP */ 01500 } /* switch (level) */ 01501 sys_sem_signal(sock->conn->op_completed); 01502 } 01503 01504 int 01505 lwip_setsockopt(int s, int level, int optname, const void *optval, socklen_t optlen) 01506 { 01507 struct lwip_socket *sock = get_socket(s); 01508 int err = ERR_OK; 01509 struct lwip_setgetsockopt_data data; 01510 01511 if (!sock) 01512 return -1; 01513 01514 if (NULL == optval) { 01515 sock_set_errno(sock, EFAULT); 01516 return -1; 01517 } 01518 01519 /* Do length and type checks for the various options first, to keep it readable. */ 01520 switch (level) { 01521 01522 /* Level: SOL_SOCKET */ 01523 case SOL_SOCKET: 01524 switch (optname) { 01525 01526 case SO_BROADCAST: 01527 /* UNIMPL case SO_DEBUG: */ 01528 /* UNIMPL case SO_DONTROUTE: */ 01529 case SO_KEEPALIVE: 01530 /* UNIMPL case case SO_CONTIMEO: */ 01531 /* UNIMPL case case SO_SNDTIMEO: */ 01532 #if LWIP_SO_RCVTIMEO 01533 case SO_RCVTIMEO: 01534 #endif /* LWIP_SO_RCVTIMEO */ 01535 #if LWIP_SO_RCVBUF 01536 case SO_RCVBUF: 01537 #endif /* LWIP_SO_RCVBUF */ 01538 /* UNIMPL case SO_OOBINLINE: */ 01539 /* UNIMPL case SO_SNDBUF: */ 01540 /* UNIMPL case SO_RCVLOWAT: */ 01541 /* UNIMPL case SO_SNDLOWAT: */ 01542 #if SO_REUSE 01543 case SO_REUSEADDR: 01544 case SO_REUSEPORT: 01545 #endif /* SO_REUSE */ 01546 /* UNIMPL case SO_USELOOPBACK: */ 01547 if (optlen < sizeof(int)) { 01548 err = EINVAL; 01549 } 01550 break; 01551 case SO_NO_CHECK: 01552 if (optlen < sizeof(int)) { 01553 err = EINVAL; 01554 } 01555 #if LWIP_UDP 01556 if ((sock->conn->type != NETCONN_UDP) || 01557 ((udp_flags(sock->conn->pcb.udp) & UDP_FLAGS_UDPLITE) != 0)) { 01558 /* this flag is only available for UDP, not for UDP lite */ 01559 err = EAFNOSUPPORT; 01560 } 01561 #endif /* LWIP_UDP */ 01562 break; 01563 default: 01564 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, SOL_SOCKET, UNIMPL: optname=0x%x, ..)\n", 01565 s, optname)); 01566 err = ENOPROTOOPT; 01567 } /* switch (optname) */ 01568 break; 01569 01570 /* Level: IPPROTO_IP */ 01571 case IPPROTO_IP: 01572 switch (optname) { 01573 /* UNIMPL case IP_HDRINCL: */ 01574 /* UNIMPL case IP_RCVDSTADDR: */ 01575 /* UNIMPL case IP_RCVIF: */ 01576 case IP_TTL: 01577 case IP_TOS: 01578 if (optlen < sizeof(int)) { 01579 err = EINVAL; 01580 } 01581 break; 01582 #if LWIP_IGMP 01583 case IP_MULTICAST_TTL: 01584 if (optlen < sizeof(u8_t)) { 01585 err = EINVAL; 01586 } 01587 if (NETCONNTYPE_GROUP(sock->conn->type) != NETCONN_UDP) { 01588 err = EAFNOSUPPORT; 01589 } 01590 break; 01591 case IP_MULTICAST_IF: 01592 if (optlen < sizeof(struct in_addr)) { 01593 err = EINVAL; 01594 } 01595 if (NETCONNTYPE_GROUP(sock->conn->type) != NETCONN_UDP) { 01596 err = EAFNOSUPPORT; 01597 } 01598 break; 01599 case IP_ADD_MEMBERSHIP: 01600 case IP_DROP_MEMBERSHIP: 01601 if (optlen < sizeof(struct ip_mreq)) { 01602 err = EINVAL; 01603 } 01604 if (NETCONNTYPE_GROUP(sock->conn->type) != NETCONN_UDP) { 01605 err = EAFNOSUPPORT; 01606 } 01607 break; 01608 #endif /* LWIP_IGMP */ 01609 default: 01610 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IP, UNIMPL: optname=0x%x, ..)\n", 01611 s, optname)); 01612 err = ENOPROTOOPT; 01613 } /* switch (optname) */ 01614 break; 01615 01616 #if LWIP_TCP 01617 /* Level: IPPROTO_TCP */ 01618 case IPPROTO_TCP: 01619 if (optlen < sizeof(int)) { 01620 err = EINVAL; 01621 break; 01622 } 01623 01624 /* If this is no TCP socket, ignore any options. */ 01625 if (sock->conn->type != NETCONN_TCP) 01626 return 0; 01627 01628 switch (optname) { 01629 case TCP_NODELAY: 01630 case TCP_KEEPALIVE: 01631 #if LWIP_TCP_KEEPALIVE 01632 case TCP_KEEPIDLE: 01633 case TCP_KEEPINTVL: 01634 case TCP_KEEPCNT: 01635 #endif /* LWIP_TCP_KEEPALIVE */ 01636 break; 01637 01638 default: 01639 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, UNIMPL: optname=0x%x, ..)\n", 01640 s, optname)); 01641 err = ENOPROTOOPT; 01642 } /* switch (optname) */ 01643 break; 01644 #endif /* LWIP_TCP */ 01645 #if LWIP_UDP && LWIP_UDPLITE 01646 /* Level: IPPROTO_UDPLITE */ 01647 case IPPROTO_UDPLITE: 01648 if (optlen < sizeof(int)) { 01649 err = EINVAL; 01650 break; 01651 } 01652 01653 /* If this is no UDP lite socket, ignore any options. */ 01654 if (sock->conn->type != NETCONN_UDPLITE) 01655 return 0; 01656 01657 switch (optname) { 01658 case UDPLITE_SEND_CSCOV: 01659 case UDPLITE_RECV_CSCOV: 01660 break; 01661 01662 default: 01663 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_UDPLITE, UNIMPL: optname=0x%x, ..)\n", 01664 s, optname)); 01665 err = ENOPROTOOPT; 01666 } /* switch (optname) */ 01667 break; 01668 #endif /* LWIP_UDP && LWIP_UDPLITE */ 01669 /* UNDEFINED LEVEL */ 01670 default: 01671 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, level=0x%x, UNIMPL: optname=0x%x, ..)\n", 01672 s, level, optname)); 01673 err = ENOPROTOOPT; 01674 } /* switch (level) */ 01675 01676 01677 if (err != ERR_OK) { 01678 sock_set_errno(sock, err); 01679 return -1; 01680 } 01681 01682 01683 /* Now do the actual option processing */ 01684 data.sock = sock; 01685 data.level = level; 01686 data.optname = optname; 01687 data.optval = (void*)optval; 01688 data.optlen = &optlen; 01689 data.err = err; 01690 tcpip_callback(lwip_setsockopt_internal, &data); 01691 sys_arch_sem_wait(sock->conn->op_completed, 0); 01692 /* maybe lwip_setsockopt_internal has changed err */ 01693 err = data.err; 01694 01695 sock_set_errno(sock, err); 01696 return err ? -1 : 0; 01697 } 01698 01699 static void 01700 lwip_setsockopt_internal(void *arg) 01701 { 01702 struct lwip_socket *sock; 01703 #ifdef LWIP_DEBUG 01704 int s; 01705 #endif /* LWIP_DEBUG */ 01706 int level, optname; 01707 const void *optval; 01708 struct lwip_setgetsockopt_data *data; 01709 01710 LWIP_ASSERT("arg != NULL", arg != NULL); 01711 01712 data = (struct lwip_setgetsockopt_data*)arg; 01713 sock = data->sock; 01714 #ifdef LWIP_DEBUG 01715 s = data->s; 01716 #endif /* LWIP_DEBUG */ 01717 level = data->level; 01718 optname = data->optname; 01719 optval = data->optval; 01720 01721 switch (level) { 01722 01723 /* Level: SOL_SOCKET */ 01724 case SOL_SOCKET: 01725 switch (optname) { 01726 01727 /* The option flags */ 01728 case SO_BROADCAST: 01729 /* UNIMPL case SO_DEBUG: */ 01730 /* UNIMPL case SO_DONTROUTE: */ 01731 case SO_KEEPALIVE: 01732 /* UNIMPL case SO_OOBINCLUDE: */ 01733 #if SO_REUSE 01734 case SO_REUSEADDR: 01735 case SO_REUSEPORT: 01736 #endif /* SO_REUSE */ 01737 /* UNIMPL case SO_USELOOPBACK: */ 01738 if (*(int*)optval) { 01739 sock->conn->pcb.ip->so_options |= optname; 01740 } else { 01741 sock->conn->pcb.ip->so_options &= ~optname; 01742 } 01743 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, SOL_SOCKET, optname=0x%x, ..) -> %s\n", 01744 s, optname, (*(int*)optval?"on":"off"))); 01745 break; 01746 #if LWIP_SO_RCVTIMEO 01747 case SO_RCVTIMEO: 01748 sock->conn->recv_timeout = ( *(int*)optval ); 01749 break; 01750 #endif /* LWIP_SO_RCVTIMEO */ 01751 #if LWIP_SO_RCVBUF 01752 case SO_RCVBUF: 01753 sock->conn->recv_bufsize = ( *(int*)optval ); 01754 break; 01755 #endif /* LWIP_SO_RCVBUF */ 01756 #if LWIP_UDP 01757 case SO_NO_CHECK: 01758 if (*(int*)optval) { 01759 udp_setflags(sock->conn->pcb.udp, udp_flags(sock->conn->pcb.udp) | UDP_FLAGS_NOCHKSUM); 01760 } else { 01761 udp_setflags(sock->conn->pcb.udp, udp_flags(sock->conn->pcb.udp) & ~UDP_FLAGS_NOCHKSUM); 01762 } 01763 break; 01764 #endif /* LWIP_UDP */ 01765 } /* switch (optname) */ 01766 break; 01767 01768 /* Level: IPPROTO_IP */ 01769 case IPPROTO_IP: 01770 switch (optname) { 01771 case IP_TTL: 01772 sock->conn->pcb.ip->ttl = (u8_t)(*(int*)optval); 01773 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IP, IP_TTL, ..) -> %u\n", 01774 s, sock->conn->pcb.ip->ttl)); 01775 break; 01776 case IP_TOS: 01777 sock->conn->pcb.ip->tos = (u8_t)(*(int*)optval); 01778 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IP, IP_TOS, ..)-> %u\n", 01779 s, sock->conn->pcb.ip->tos)); 01780 break; 01781 #if LWIP_IGMP 01782 case IP_MULTICAST_TTL: 01783 sock->conn->pcb.udp->ttl = (u8_t)(*(u8_t*)optval); 01784 break; 01785 case IP_MULTICAST_IF: 01786 sock->conn->pcb.udp->multicast_ip.addr = ((struct in_addr*) optval)->s_addr; 01787 break; 01788 case IP_ADD_MEMBERSHIP: 01789 case IP_DROP_MEMBERSHIP: 01790 { 01791 /* If this is a TCP or a RAW socket, ignore these options. */ 01792 struct ip_mreq *imr = (struct ip_mreq *)optval; 01793 if(optname == IP_ADD_MEMBERSHIP){ 01794 data->err = igmp_joingroup((struct ip_addr*)&(imr->imr_interface.s_addr), (struct ip_addr*)&(imr->imr_multiaddr.s_addr)); 01795 } else { 01796 data->err = igmp_leavegroup((struct ip_addr*)&(imr->imr_interface.s_addr), (struct ip_addr*)&(imr->imr_multiaddr.s_addr)); 01797 } 01798 if(data->err != ERR_OK) { 01799 data->err = EADDRNOTAVAIL; 01800 } 01801 } 01802 break; 01803 #endif /* LWIP_IGMP */ 01804 } /* switch (optname) */ 01805 break; 01806 01807 #if LWIP_TCP 01808 /* Level: IPPROTO_TCP */ 01809 case IPPROTO_TCP: 01810 switch (optname) { 01811 case TCP_NODELAY: 01812 if (*(int*)optval) { 01813 sock->conn->pcb.tcp->flags |= TF_NODELAY; 01814 } else { 01815 sock->conn->pcb.tcp->flags &= ~TF_NODELAY; 01816 } 01817 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_NODELAY) -> %s\n", 01818 s, (*(int *)optval)?"on":"off") ); 01819 break; 01820 case TCP_KEEPALIVE: 01821 sock->conn->pcb.tcp->keep_idle = (u32_t)(*(int*)optval); 01822 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPALIVE) -> %lu\n", 01823 s, sock->conn->pcb.tcp->keep_idle)); 01824 break; 01825 01826 #if LWIP_TCP_KEEPALIVE 01827 case TCP_KEEPIDLE: 01828 sock->conn->pcb.tcp->keep_idle = 1000*(u32_t)(*(int*)optval); 01829 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPIDLE) -> %lu\n", 01830 s, sock->conn->pcb.tcp->keep_idle)); 01831 break; 01832 case TCP_KEEPINTVL: 01833 sock->conn->pcb.tcp->keep_intvl = 1000*(u32_t)(*(int*)optval); 01834 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPINTVL) -> %lu\n", 01835 s, sock->conn->pcb.tcp->keep_intvl)); 01836 break; 01837 case TCP_KEEPCNT: 01838 sock->conn->pcb.tcp->keep_cnt = (u32_t)(*(int*)optval); 01839 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPCNT) -> %lu\n", 01840 s, sock->conn->pcb.tcp->keep_cnt)); 01841 break; 01842 #endif /* LWIP_TCP_KEEPALIVE */ 01843 01844 } /* switch (optname) */ 01845 break; 01846 #endif /* LWIP_TCP*/ 01847 #if LWIP_UDP && LWIP_UDPLITE 01848 /* Level: IPPROTO_UDPLITE */ 01849 case IPPROTO_UDPLITE: 01850 switch (optname) { 01851 case UDPLITE_SEND_CSCOV: 01852 if ((*(int*)optval != 0) && (*(int*)optval < 8)) { 01853 /* don't allow illegal values! */ 01854 sock->conn->pcb.udp->chksum_len_tx = 8; 01855 } else { 01856 sock->conn->pcb.udp->chksum_len_tx = *(int*)optval; 01857 } 01858 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_UDPLITE, UDPLITE_SEND_CSCOV) -> %d\n", 01859 s, (*(int*)optval)) ); 01860 break; 01861 case UDPLITE_RECV_CSCOV: 01862 if ((*(int*)optval != 0) && (*(int*)optval < 8)) { 01863 /* don't allow illegal values! */ 01864 sock->conn->pcb.udp->chksum_len_rx = 8; 01865 } else { 01866 sock->conn->pcb.udp->chksum_len_rx = *(int*)optval; 01867 } 01868 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_UDPLITE, UDPLITE_RECV_CSCOV) -> %d\n", 01869 s, (*(int*)optval)) ); 01870 break; 01871 } /* switch (optname) */ 01872 break; 01873 #endif /* LWIP_UDP */ 01874 } /* switch (level) */ 01875 sys_sem_signal(sock->conn->op_completed); 01876 } 01877 01878 int 01879 lwip_ioctl(int s, long cmd, void *argp) 01880 { 01881 struct lwip_socket *sock = get_socket(s); 01882 u16_t buflen = 0; 01883 01884 if (!sock) 01885 return -1; 01886 01887 switch (cmd) { 01888 case FIONREAD: 01889 if (!argp) { 01890 sock_set_errno(sock, EINVAL); 01891 return -1; 01892 } 01893 01894 SYS_ARCH_GET(sock->conn->recv_avail, *((u16_t*)argp)); 01895 01896 /* Check if there is data left from the last recv operation. /maq 041215 */ 01897 if (sock->lastdata) { 01898 buflen = netbuf_len(sock->lastdata); 01899 buflen -= sock->lastoffset; 01900 01901 *((u16_t*)argp) += buflen; 01902 } 01903 01904 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(%d, FIONREAD, %p) = %u\n", s, argp, *((u16_t*)argp))); 01905 sock_set_errno(sock, 0); 01906 return 0; 01907 01908 case FIONBIO: 01909 if (argp && *(u32_t*)argp) 01910 sock->flags |= O_NONBLOCK; 01911 else 01912 sock->flags &= ~O_NONBLOCK; 01913 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(%d, FIONBIO, %d)\n", s, !!(sock->flags & O_NONBLOCK))); 01914 sock_set_errno(sock, 0); 01915 return 0; 01916 01917 default: 01918 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(%d, UNIMPL: 0x%lx, %p)\n", s, cmd, argp)); 01919 sock_set_errno(sock, ENOSYS); /* not yet implemented */ 01920 return -1; 01921 } /* switch (cmd) */ 01922 } 01923 01924 #endif /* LWIP_SOCKET */
Generated on Tue Jul 12 2022 16:07:16 by
1.7.2
