SAMV71 Xplained Ultra Software Package 1.3

sockets.c

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