A version of LWIP, provided for backwards compatibility.
Dependents: AA_DemoBoard DemoBoard HelloServerDemo DemoBoard_RangeIndicator ... more
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:06:24 by 1.7.2