LwIP with PPP & Ethernet integration

Dependents:   NetworkingCoreLib

This is the mbed port of the LwIP stack: http://savannah.nongnu.org/projects/lwip/

It includes contributed content from NXP's port for LPCxxxx devices: http://www.lpcware.com/content/project/lightweight-ip-lwip-networking-stack

Licence

LwIP is licenced under the BSD licence:

Copyright (c) 2001-2004 Swedish Institute of Computer Science. 
All rights reserved. 
Redistribution and use in source and binary forms, with or without modification, 
are permitted provided that the following conditions are met: 
1. Redistributions of source code must retain the above copyright notice, 
this list of conditions and the following disclaimer. 
2. Redistributions in binary form must reproduce the above copyright notice, 
this list of conditions and the following disclaimer in the documentation 
and/or other materials provided with the distribution. 
3. The name of the author may not be used to endorse or promote products 
derived from this software without specific prior written permission. 
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 
SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 
OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 
OF SUCH DAMAGE.
Committer:
donatien
Date:
Thu May 24 15:53:48 2012 +0000
Revision:
0:8e01dca41002
Merge with Emilio's LwIp

Who changed what in which revision?

UserRevisionLine numberNew contents of line
donatien 0:8e01dca41002 1 /**
donatien 0:8e01dca41002 2 * @file
donatien 0:8e01dca41002 3 * Sockets BSD-Like API module
donatien 0:8e01dca41002 4 *
donatien 0:8e01dca41002 5 */
donatien 0:8e01dca41002 6
donatien 0:8e01dca41002 7 /*
donatien 0:8e01dca41002 8 * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
donatien 0:8e01dca41002 9 * All rights reserved.
donatien 0:8e01dca41002 10 *
donatien 0:8e01dca41002 11 * Redistribution and use in source and binary forms, with or without modification,
donatien 0:8e01dca41002 12 * are permitted provided that the following conditions are met:
donatien 0:8e01dca41002 13 *
donatien 0:8e01dca41002 14 * 1. Redistributions of source code must retain the above copyright notice,
donatien 0:8e01dca41002 15 * this list of conditions and the following disclaimer.
donatien 0:8e01dca41002 16 * 2. Redistributions in binary form must reproduce the above copyright notice,
donatien 0:8e01dca41002 17 * this list of conditions and the following disclaimer in the documentation
donatien 0:8e01dca41002 18 * and/or other materials provided with the distribution.
donatien 0:8e01dca41002 19 * 3. The name of the author may not be used to endorse or promote products
donatien 0:8e01dca41002 20 * derived from this software without specific prior written permission.
donatien 0:8e01dca41002 21 *
donatien 0:8e01dca41002 22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
donatien 0:8e01dca41002 23 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
donatien 0:8e01dca41002 24 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
donatien 0:8e01dca41002 25 * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
donatien 0:8e01dca41002 26 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
donatien 0:8e01dca41002 27 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
donatien 0:8e01dca41002 28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
donatien 0:8e01dca41002 29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
donatien 0:8e01dca41002 30 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
donatien 0:8e01dca41002 31 * OF SUCH DAMAGE.
donatien 0:8e01dca41002 32 *
donatien 0:8e01dca41002 33 * This file is part of the lwIP TCP/IP stack.
donatien 0:8e01dca41002 34 *
donatien 0:8e01dca41002 35 * Author: Adam Dunkels <adam@sics.se>
donatien 0:8e01dca41002 36 *
donatien 0:8e01dca41002 37 * Improved by Marc Boucher <marc@mbsi.ca> and David Haas <dhaas@alum.rpi.edu>
donatien 0:8e01dca41002 38 *
donatien 0:8e01dca41002 39 */
donatien 0:8e01dca41002 40
donatien 0:8e01dca41002 41 #include "lwip/opt.h"
donatien 0:8e01dca41002 42
donatien 0:8e01dca41002 43 #if LWIP_SOCKET /* don't build if not configured for use in lwipopts.h */
donatien 0:8e01dca41002 44
donatien 0:8e01dca41002 45 #include "lwip/sockets.h"
donatien 0:8e01dca41002 46 #include "lwip/api.h"
donatien 0:8e01dca41002 47 #include "lwip/sys.h"
donatien 0:8e01dca41002 48 #include "lwip/igmp.h"
donatien 0:8e01dca41002 49 #include "lwip/inet.h"
donatien 0:8e01dca41002 50 #include "lwip/tcp.h"
donatien 0:8e01dca41002 51 #include "lwip/raw.h"
donatien 0:8e01dca41002 52 #include "lwip/udp.h"
donatien 0:8e01dca41002 53 #include "lwip/tcpip.h"
donatien 0:8e01dca41002 54 #include "lwip/pbuf.h"
donatien 0:8e01dca41002 55 #if LWIP_CHECKSUM_ON_COPY
donatien 0:8e01dca41002 56 #include "lwip/inet_chksum.h"
donatien 0:8e01dca41002 57 #endif
donatien 0:8e01dca41002 58
donatien 0:8e01dca41002 59 #include <string.h>
donatien 0:8e01dca41002 60
donatien 0:8e01dca41002 61 #define NUM_SOCKETS MEMP_NUM_NETCONN
donatien 0:8e01dca41002 62
donatien 0:8e01dca41002 63 /** Contains all internal pointers and states used for a socket */
donatien 0:8e01dca41002 64 struct lwip_sock {
donatien 0:8e01dca41002 65 /** sockets currently are built on netconns, each socket has one netconn */
donatien 0:8e01dca41002 66 struct netconn *conn;
donatien 0:8e01dca41002 67 /** data that was left from the previous read */
donatien 0:8e01dca41002 68 void *lastdata;
donatien 0:8e01dca41002 69 /** offset in the data that was left from the previous read */
donatien 0:8e01dca41002 70 u16_t lastoffset;
donatien 0:8e01dca41002 71 /** number of times data was received, set by event_callback(),
donatien 0:8e01dca41002 72 tested by the receive and select functions */
donatien 0:8e01dca41002 73 s16_t rcvevent;
donatien 0:8e01dca41002 74 /** number of times data was ACKed (free send buffer), set by event_callback(),
donatien 0:8e01dca41002 75 tested by select */
donatien 0:8e01dca41002 76 u16_t sendevent;
donatien 0:8e01dca41002 77 /** error happened for this socket, set by event_callback(), tested by select */
donatien 0:8e01dca41002 78 u16_t errevent;
donatien 0:8e01dca41002 79 /** last error that occurred on this socket */
donatien 0:8e01dca41002 80 int err;
donatien 0:8e01dca41002 81 /** counter of how many threads are waiting for this socket using select */
donatien 0:8e01dca41002 82 int select_waiting;
donatien 0:8e01dca41002 83 };
donatien 0:8e01dca41002 84
donatien 0:8e01dca41002 85 /** Description for a task waiting in select */
donatien 0:8e01dca41002 86 struct lwip_select_cb {
donatien 0:8e01dca41002 87 /** Pointer to the next waiting task */
donatien 0:8e01dca41002 88 struct lwip_select_cb *next;
donatien 0:8e01dca41002 89 /** Pointer to the previous waiting task */
donatien 0:8e01dca41002 90 struct lwip_select_cb *prev;
donatien 0:8e01dca41002 91 /** readset passed to select */
donatien 0:8e01dca41002 92 fd_set *readset;
donatien 0:8e01dca41002 93 /** writeset passed to select */
donatien 0:8e01dca41002 94 fd_set *writeset;
donatien 0:8e01dca41002 95 /** unimplemented: exceptset passed to select */
donatien 0:8e01dca41002 96 fd_set *exceptset;
donatien 0:8e01dca41002 97 /** don't signal the same semaphore twice: set to 1 when signalled */
donatien 0:8e01dca41002 98 int sem_signalled;
donatien 0:8e01dca41002 99 /** semaphore to wake up a task waiting for select */
donatien 0:8e01dca41002 100 sys_sem_t sem;
donatien 0:8e01dca41002 101 };
donatien 0:8e01dca41002 102
donatien 0:8e01dca41002 103 /** This struct is used to pass data to the set/getsockopt_internal
donatien 0:8e01dca41002 104 * functions running in tcpip_thread context (only a void* is allowed) */
donatien 0:8e01dca41002 105 struct lwip_setgetsockopt_data {
donatien 0:8e01dca41002 106 /** socket struct for which to change options */
donatien 0:8e01dca41002 107 struct lwip_sock *sock;
donatien 0:8e01dca41002 108 #ifdef LWIP_DEBUG
donatien 0:8e01dca41002 109 /** socket index for which to change options */
donatien 0:8e01dca41002 110 int s;
donatien 0:8e01dca41002 111 #endif /* LWIP_DEBUG */
donatien 0:8e01dca41002 112 /** level of the option to process */
donatien 0:8e01dca41002 113 int level;
donatien 0:8e01dca41002 114 /** name of the option to process */
donatien 0:8e01dca41002 115 int optname;
donatien 0:8e01dca41002 116 /** set: value to set the option to
donatien 0:8e01dca41002 117 * get: value of the option is stored here */
donatien 0:8e01dca41002 118 void *optval;
donatien 0:8e01dca41002 119 /** size of *optval */
donatien 0:8e01dca41002 120 socklen_t *optlen;
donatien 0:8e01dca41002 121 /** if an error occures, it is temporarily stored here */
donatien 0:8e01dca41002 122 err_t err;
donatien 0:8e01dca41002 123 };
donatien 0:8e01dca41002 124
donatien 0:8e01dca41002 125 /** The global array of available sockets */
donatien 0:8e01dca41002 126 static struct lwip_sock sockets[NUM_SOCKETS];
donatien 0:8e01dca41002 127 /** The global list of tasks waiting for select */
donatien 0:8e01dca41002 128 static struct lwip_select_cb *select_cb_list;
donatien 0:8e01dca41002 129 /** This counter is increased from lwip_select when the list is chagned
donatien 0:8e01dca41002 130 and checked in event_callback to see if it has changed. */
donatien 0:8e01dca41002 131 static volatile int select_cb_ctr;
donatien 0:8e01dca41002 132
donatien 0:8e01dca41002 133 /** Table to quickly map an lwIP error (err_t) to a socket error
donatien 0:8e01dca41002 134 * by using -err as an index */
donatien 0:8e01dca41002 135 static const int err_to_errno_table[] = {
donatien 0:8e01dca41002 136 0, /* ERR_OK 0 No error, everything OK. */
donatien 0:8e01dca41002 137 ENOMEM, /* ERR_MEM -1 Out of memory error. */
donatien 0:8e01dca41002 138 ENOBUFS, /* ERR_BUF -2 Buffer error. */
donatien 0:8e01dca41002 139 EWOULDBLOCK, /* ERR_TIMEOUT -3 Timeout */
donatien 0:8e01dca41002 140 EHOSTUNREACH, /* ERR_RTE -4 Routing problem. */
donatien 0:8e01dca41002 141 EINPROGRESS, /* ERR_INPROGRESS -5 Operation in progress */
donatien 0:8e01dca41002 142 EINVAL, /* ERR_VAL -6 Illegal value. */
donatien 0:8e01dca41002 143 EWOULDBLOCK, /* ERR_WOULDBLOCK -7 Operation would block. */
donatien 0:8e01dca41002 144 EADDRINUSE, /* ERR_USE -8 Address in use. */
donatien 0:8e01dca41002 145 EALREADY, /* ERR_ISCONN -9 Already connected. */
donatien 0:8e01dca41002 146 ECONNABORTED, /* ERR_ABRT -10 Connection aborted. */
donatien 0:8e01dca41002 147 ECONNRESET, /* ERR_RST -11 Connection reset. */
donatien 0:8e01dca41002 148 ENOTCONN, /* ERR_CLSD -12 Connection closed. */
donatien 0:8e01dca41002 149 ENOTCONN, /* ERR_CONN -13 Not connected. */
donatien 0:8e01dca41002 150 EIO, /* ERR_ARG -14 Illegal argument. */
donatien 0:8e01dca41002 151 -1, /* ERR_IF -15 Low-level netif error */
donatien 0:8e01dca41002 152 };
donatien 0:8e01dca41002 153
donatien 0:8e01dca41002 154 #define ERR_TO_ERRNO_TABLE_SIZE \
donatien 0:8e01dca41002 155 (sizeof(err_to_errno_table)/sizeof(err_to_errno_table[0]))
donatien 0:8e01dca41002 156
donatien 0:8e01dca41002 157 #define err_to_errno(err) \
donatien 0:8e01dca41002 158 ((unsigned)(-(err)) < ERR_TO_ERRNO_TABLE_SIZE ? \
donatien 0:8e01dca41002 159 err_to_errno_table[-(err)] : EIO)
donatien 0:8e01dca41002 160
donatien 0:8e01dca41002 161 #ifdef ERRNO
donatien 0:8e01dca41002 162 #ifndef set_errno
donatien 0:8e01dca41002 163 #define set_errno(err) errno = (err)
donatien 0:8e01dca41002 164 #endif
donatien 0:8e01dca41002 165 #else /* ERRNO */
donatien 0:8e01dca41002 166 #define set_errno(err)
donatien 0:8e01dca41002 167 #endif /* ERRNO */
donatien 0:8e01dca41002 168
donatien 0:8e01dca41002 169 #define sock_set_errno(sk, e) do { \
donatien 0:8e01dca41002 170 sk->err = (e); \
donatien 0:8e01dca41002 171 set_errno(sk->err); \
donatien 0:8e01dca41002 172 } while (0)
donatien 0:8e01dca41002 173
donatien 0:8e01dca41002 174 /* Forward delcaration of some functions */
donatien 0:8e01dca41002 175 static void event_callback(struct netconn *conn, enum netconn_evt evt, u16_t len);
donatien 0:8e01dca41002 176 static void lwip_getsockopt_internal(void *arg);
donatien 0:8e01dca41002 177 static void lwip_setsockopt_internal(void *arg);
donatien 0:8e01dca41002 178
donatien 0:8e01dca41002 179 /**
donatien 0:8e01dca41002 180 * Initialize this module. This function has to be called before any other
donatien 0:8e01dca41002 181 * functions in this module!
donatien 0:8e01dca41002 182 */
donatien 0:8e01dca41002 183 void
donatien 0:8e01dca41002 184 lwip_socket_init(void)
donatien 0:8e01dca41002 185 {
donatien 0:8e01dca41002 186 }
donatien 0:8e01dca41002 187
donatien 0:8e01dca41002 188 /**
donatien 0:8e01dca41002 189 * Map a externally used socket index to the internal socket representation.
donatien 0:8e01dca41002 190 *
donatien 0:8e01dca41002 191 * @param s externally used socket index
donatien 0:8e01dca41002 192 * @return struct lwip_sock for the socket or NULL if not found
donatien 0:8e01dca41002 193 */
donatien 0:8e01dca41002 194 static struct lwip_sock *
donatien 0:8e01dca41002 195 get_socket(int s)
donatien 0:8e01dca41002 196 {
donatien 0:8e01dca41002 197 struct lwip_sock *sock;
donatien 0:8e01dca41002 198
donatien 0:8e01dca41002 199 if ((s < 0) || (s >= NUM_SOCKETS)) {
donatien 0:8e01dca41002 200 LWIP_DEBUGF(SOCKETS_DEBUG, ("get_socket(%d): invalid\n", s));
donatien 0:8e01dca41002 201 set_errno(EBADF);
donatien 0:8e01dca41002 202 return NULL;
donatien 0:8e01dca41002 203 }
donatien 0:8e01dca41002 204
donatien 0:8e01dca41002 205 sock = &sockets[s];
donatien 0:8e01dca41002 206
donatien 0:8e01dca41002 207 if (!sock->conn) {
donatien 0:8e01dca41002 208 LWIP_DEBUGF(SOCKETS_DEBUG, ("get_socket(%d): not active\n", s));
donatien 0:8e01dca41002 209 set_errno(EBADF);
donatien 0:8e01dca41002 210 return NULL;
donatien 0:8e01dca41002 211 }
donatien 0:8e01dca41002 212
donatien 0:8e01dca41002 213 return sock;
donatien 0:8e01dca41002 214 }
donatien 0:8e01dca41002 215
donatien 0:8e01dca41002 216 /**
donatien 0:8e01dca41002 217 * Same as get_socket but doesn't set errno
donatien 0:8e01dca41002 218 *
donatien 0:8e01dca41002 219 * @param s externally used socket index
donatien 0:8e01dca41002 220 * @return struct lwip_sock for the socket or NULL if not found
donatien 0:8e01dca41002 221 */
donatien 0:8e01dca41002 222 static struct lwip_sock *
donatien 0:8e01dca41002 223 tryget_socket(int s)
donatien 0:8e01dca41002 224 {
donatien 0:8e01dca41002 225 if ((s < 0) || (s >= NUM_SOCKETS)) {
donatien 0:8e01dca41002 226 return NULL;
donatien 0:8e01dca41002 227 }
donatien 0:8e01dca41002 228 if (!sockets[s].conn) {
donatien 0:8e01dca41002 229 return NULL;
donatien 0:8e01dca41002 230 }
donatien 0:8e01dca41002 231 return &sockets[s];
donatien 0:8e01dca41002 232 }
donatien 0:8e01dca41002 233
donatien 0:8e01dca41002 234 /**
donatien 0:8e01dca41002 235 * Allocate a new socket for a given netconn.
donatien 0:8e01dca41002 236 *
donatien 0:8e01dca41002 237 * @param newconn the netconn for which to allocate a socket
donatien 0:8e01dca41002 238 * @param accepted 1 if socket has been created by accept(),
donatien 0:8e01dca41002 239 * 0 if socket has been created by socket()
donatien 0:8e01dca41002 240 * @return the index of the new socket; -1 on error
donatien 0:8e01dca41002 241 */
donatien 0:8e01dca41002 242 static int
donatien 0:8e01dca41002 243 alloc_socket(struct netconn *newconn, int accepted)
donatien 0:8e01dca41002 244 {
donatien 0:8e01dca41002 245 int i;
donatien 0:8e01dca41002 246 SYS_ARCH_DECL_PROTECT(lev);
donatien 0:8e01dca41002 247
donatien 0:8e01dca41002 248 /* allocate a new socket identifier */
donatien 0:8e01dca41002 249 for (i = 0; i < NUM_SOCKETS; ++i) {
donatien 0:8e01dca41002 250 /* Protect socket array */
donatien 0:8e01dca41002 251 SYS_ARCH_PROTECT(lev);
donatien 0:8e01dca41002 252 if (!sockets[i].conn) {
donatien 0:8e01dca41002 253 sockets[i].conn = newconn;
donatien 0:8e01dca41002 254 /* The socket is not yet known to anyone, so no need to protect
donatien 0:8e01dca41002 255 after having marked it as used. */
donatien 0:8e01dca41002 256 SYS_ARCH_UNPROTECT(lev);
donatien 0:8e01dca41002 257 sockets[i].lastdata = NULL;
donatien 0:8e01dca41002 258 sockets[i].lastoffset = 0;
donatien 0:8e01dca41002 259 sockets[i].rcvevent = 0;
donatien 0:8e01dca41002 260 /* TCP sendbuf is empty, but the socket is not yet writable until connected
donatien 0:8e01dca41002 261 * (unless it has been created by accept()). */
donatien 0:8e01dca41002 262 sockets[i].sendevent = (newconn->type == NETCONN_TCP ? (accepted != 0) : 1);
donatien 0:8e01dca41002 263 sockets[i].errevent = 0;
donatien 0:8e01dca41002 264 sockets[i].err = 0;
donatien 0:8e01dca41002 265 sockets[i].select_waiting = 0;
donatien 0:8e01dca41002 266 return i;
donatien 0:8e01dca41002 267 }
donatien 0:8e01dca41002 268 SYS_ARCH_UNPROTECT(lev);
donatien 0:8e01dca41002 269 }
donatien 0:8e01dca41002 270 return -1;
donatien 0:8e01dca41002 271 }
donatien 0:8e01dca41002 272
donatien 0:8e01dca41002 273 /** Free a socket. The socket's netconn must have been
donatien 0:8e01dca41002 274 * delete before!
donatien 0:8e01dca41002 275 *
donatien 0:8e01dca41002 276 * @param sock the socket to free
donatien 0:8e01dca41002 277 * @param is_tcp != 0 for TCP sockets, used to free lastdata
donatien 0:8e01dca41002 278 */
donatien 0:8e01dca41002 279 static void
donatien 0:8e01dca41002 280 free_socket(struct lwip_sock *sock, int is_tcp)
donatien 0:8e01dca41002 281 {
donatien 0:8e01dca41002 282 void *lastdata;
donatien 0:8e01dca41002 283 SYS_ARCH_DECL_PROTECT(lev);
donatien 0:8e01dca41002 284
donatien 0:8e01dca41002 285 lastdata = sock->lastdata;
donatien 0:8e01dca41002 286 sock->lastdata = NULL;
donatien 0:8e01dca41002 287 sock->lastoffset = 0;
donatien 0:8e01dca41002 288 sock->err = 0;
donatien 0:8e01dca41002 289
donatien 0:8e01dca41002 290 /* Protect socket array */
donatien 0:8e01dca41002 291 SYS_ARCH_PROTECT(lev);
donatien 0:8e01dca41002 292 sock->conn = NULL;
donatien 0:8e01dca41002 293 SYS_ARCH_UNPROTECT(lev);
donatien 0:8e01dca41002 294 /* don't use 'sock' after this line, as another task might have allocated it */
donatien 0:8e01dca41002 295
donatien 0:8e01dca41002 296 if (lastdata != NULL) {
donatien 0:8e01dca41002 297 if (is_tcp) {
donatien 0:8e01dca41002 298 pbuf_free((struct pbuf *)lastdata);
donatien 0:8e01dca41002 299 } else {
donatien 0:8e01dca41002 300 netbuf_delete((struct netbuf *)lastdata);
donatien 0:8e01dca41002 301 }
donatien 0:8e01dca41002 302 }
donatien 0:8e01dca41002 303 }
donatien 0:8e01dca41002 304
donatien 0:8e01dca41002 305 /* Below this, the well-known socket functions are implemented.
donatien 0:8e01dca41002 306 * Use google.com or opengroup.org to get a good description :-)
donatien 0:8e01dca41002 307 *
donatien 0:8e01dca41002 308 * Exceptions are documented!
donatien 0:8e01dca41002 309 */
donatien 0:8e01dca41002 310
donatien 0:8e01dca41002 311 int
donatien 0:8e01dca41002 312 lwip_accept(int s, struct sockaddr *addr, socklen_t *addrlen)
donatien 0:8e01dca41002 313 {
donatien 0:8e01dca41002 314 struct lwip_sock *sock, *nsock;
donatien 0:8e01dca41002 315 struct netconn *newconn;
donatien 0:8e01dca41002 316 ip_addr_t naddr;
donatien 0:8e01dca41002 317 u16_t port;
donatien 0:8e01dca41002 318 int newsock;
donatien 0:8e01dca41002 319 struct sockaddr_in sin;
donatien 0:8e01dca41002 320 err_t err;
donatien 0:8e01dca41002 321 SYS_ARCH_DECL_PROTECT(lev);
donatien 0:8e01dca41002 322
donatien 0:8e01dca41002 323 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d)...\n", s));
donatien 0:8e01dca41002 324 sock = get_socket(s);
donatien 0:8e01dca41002 325 if (!sock) {
donatien 0:8e01dca41002 326 return -1;
donatien 0:8e01dca41002 327 }
donatien 0:8e01dca41002 328
donatien 0:8e01dca41002 329 if (netconn_is_nonblocking(sock->conn) && (sock->rcvevent <= 0)) {
donatien 0:8e01dca41002 330 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d): returning EWOULDBLOCK\n", s));
donatien 0:8e01dca41002 331 sock_set_errno(sock, EWOULDBLOCK);
donatien 0:8e01dca41002 332 return -1;
donatien 0:8e01dca41002 333 }
donatien 0:8e01dca41002 334
donatien 0:8e01dca41002 335 /* wait for a new connection */
donatien 0:8e01dca41002 336 err = netconn_accept(sock->conn, &newconn);
donatien 0:8e01dca41002 337 if (err != ERR_OK) {
donatien 0:8e01dca41002 338 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d): netconn_acept failed, err=%d\n", s, err));
donatien 0:8e01dca41002 339 sock_set_errno(sock, err_to_errno(err));
donatien 0:8e01dca41002 340 return -1;
donatien 0:8e01dca41002 341 }
donatien 0:8e01dca41002 342 LWIP_ASSERT("newconn != NULL", newconn != NULL);
donatien 0:8e01dca41002 343 /* Prevent automatic window updates, we do this on our own! */
donatien 0:8e01dca41002 344 netconn_set_noautorecved(newconn, 1);
donatien 0:8e01dca41002 345
donatien 0:8e01dca41002 346 /* get the IP address and port of the remote host */
donatien 0:8e01dca41002 347 err = netconn_peer(newconn, &naddr, &port);
donatien 0:8e01dca41002 348 if (err != ERR_OK) {
donatien 0:8e01dca41002 349 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d): netconn_peer failed, err=%d\n", s, err));
donatien 0:8e01dca41002 350 netconn_delete(newconn);
donatien 0:8e01dca41002 351 sock_set_errno(sock, err_to_errno(err));
donatien 0:8e01dca41002 352 return -1;
donatien 0:8e01dca41002 353 }
donatien 0:8e01dca41002 354
donatien 0:8e01dca41002 355 /* Note that POSIX only requires us to check addr is non-NULL. addrlen must
donatien 0:8e01dca41002 356 * not be NULL if addr is valid.
donatien 0:8e01dca41002 357 */
donatien 0:8e01dca41002 358 if (NULL != addr) {
donatien 0:8e01dca41002 359 LWIP_ASSERT("addr valid but addrlen NULL", addrlen != NULL);
donatien 0:8e01dca41002 360 memset(&sin, 0, sizeof(sin));
donatien 0:8e01dca41002 361 sin.sin_len = sizeof(sin);
donatien 0:8e01dca41002 362 sin.sin_family = AF_INET;
donatien 0:8e01dca41002 363 sin.sin_port = htons(port);
donatien 0:8e01dca41002 364 inet_addr_from_ipaddr(&sin.sin_addr, &naddr);
donatien 0:8e01dca41002 365
donatien 0:8e01dca41002 366 if (*addrlen > sizeof(sin))
donatien 0:8e01dca41002 367 *addrlen = sizeof(sin);
donatien 0:8e01dca41002 368
donatien 0:8e01dca41002 369 MEMCPY(addr, &sin, *addrlen);
donatien 0:8e01dca41002 370 }
donatien 0:8e01dca41002 371
donatien 0:8e01dca41002 372 newsock = alloc_socket(newconn, 1);
donatien 0:8e01dca41002 373 if (newsock == -1) {
donatien 0:8e01dca41002 374 netconn_delete(newconn);
donatien 0:8e01dca41002 375 sock_set_errno(sock, ENFILE);
donatien 0:8e01dca41002 376 return -1;
donatien 0:8e01dca41002 377 }
donatien 0:8e01dca41002 378 LWIP_ASSERT("invalid socket index", (newsock >= 0) && (newsock < NUM_SOCKETS));
donatien 0:8e01dca41002 379 LWIP_ASSERT("newconn->callback == event_callback", newconn->callback == event_callback);
donatien 0:8e01dca41002 380 nsock = &sockets[newsock];
donatien 0:8e01dca41002 381
donatien 0:8e01dca41002 382 /* See event_callback: If data comes in right away after an accept, even
donatien 0:8e01dca41002 383 * though the server task might not have created a new socket yet.
donatien 0:8e01dca41002 384 * In that case, newconn->socket is counted down (newconn->socket--),
donatien 0:8e01dca41002 385 * so nsock->rcvevent is >= 1 here!
donatien 0:8e01dca41002 386 */
donatien 0:8e01dca41002 387 SYS_ARCH_PROTECT(lev);
donatien 0:8e01dca41002 388 nsock->rcvevent += (s16_t)(-1 - newconn->socket);
donatien 0:8e01dca41002 389 newconn->socket = newsock;
donatien 0:8e01dca41002 390 SYS_ARCH_UNPROTECT(lev);
donatien 0:8e01dca41002 391
donatien 0:8e01dca41002 392 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d) returning new sock=%d addr=", s, newsock));
donatien 0:8e01dca41002 393 ip_addr_debug_print(SOCKETS_DEBUG, &naddr);
donatien 0:8e01dca41002 394 LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F"\n", port));
donatien 0:8e01dca41002 395
donatien 0:8e01dca41002 396 sock_set_errno(sock, 0);
donatien 0:8e01dca41002 397 return newsock;
donatien 0:8e01dca41002 398 }
donatien 0:8e01dca41002 399
donatien 0:8e01dca41002 400 int
donatien 0:8e01dca41002 401 lwip_bind(int s, const struct sockaddr *name, socklen_t namelen)
donatien 0:8e01dca41002 402 {
donatien 0:8e01dca41002 403 struct lwip_sock *sock;
donatien 0:8e01dca41002 404 ip_addr_t local_addr;
donatien 0:8e01dca41002 405 u16_t local_port;
donatien 0:8e01dca41002 406 err_t err;
donatien 0:8e01dca41002 407 const struct sockaddr_in *name_in;
donatien 0:8e01dca41002 408
donatien 0:8e01dca41002 409 sock = get_socket(s);
donatien 0:8e01dca41002 410 if (!sock) {
donatien 0:8e01dca41002 411 return -1;
donatien 0:8e01dca41002 412 }
donatien 0:8e01dca41002 413
donatien 0:8e01dca41002 414 /* check size, familiy and alignment of 'name' */
donatien 0:8e01dca41002 415 LWIP_ERROR("lwip_bind: invalid address", ((namelen == sizeof(struct sockaddr_in)) &&
donatien 0:8e01dca41002 416 ((name->sa_family) == AF_INET) && ((((mem_ptr_t)name) % 4) == 0)),
donatien 0:8e01dca41002 417 sock_set_errno(sock, err_to_errno(ERR_ARG)); return -1;);
donatien 0:8e01dca41002 418 name_in = (const struct sockaddr_in *)(void*)name;
donatien 0:8e01dca41002 419
donatien 0:8e01dca41002 420 inet_addr_to_ipaddr(&local_addr, &name_in->sin_addr);
donatien 0:8e01dca41002 421 local_port = name_in->sin_port;
donatien 0:8e01dca41002 422
donatien 0:8e01dca41002 423 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d, addr=", s));
donatien 0:8e01dca41002 424 ip_addr_debug_print(SOCKETS_DEBUG, &local_addr);
donatien 0:8e01dca41002 425 LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F")\n", ntohs(local_port)));
donatien 0:8e01dca41002 426
donatien 0:8e01dca41002 427 err = netconn_bind(sock->conn, &local_addr, ntohs(local_port));
donatien 0:8e01dca41002 428
donatien 0:8e01dca41002 429 if (err != ERR_OK) {
donatien 0:8e01dca41002 430 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d) failed, err=%d\n", s, err));
donatien 0:8e01dca41002 431 sock_set_errno(sock, err_to_errno(err));
donatien 0:8e01dca41002 432 return -1;
donatien 0:8e01dca41002 433 }
donatien 0:8e01dca41002 434
donatien 0:8e01dca41002 435 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d) succeeded\n", s));
donatien 0:8e01dca41002 436 sock_set_errno(sock, 0);
donatien 0:8e01dca41002 437 return 0;
donatien 0:8e01dca41002 438 }
donatien 0:8e01dca41002 439
donatien 0:8e01dca41002 440 int
donatien 0:8e01dca41002 441 lwip_close(int s)
donatien 0:8e01dca41002 442 {
donatien 0:8e01dca41002 443 struct lwip_sock *sock;
donatien 0:8e01dca41002 444 int is_tcp = 0;
donatien 0:8e01dca41002 445
donatien 0:8e01dca41002 446 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_close(%d)\n", s));
donatien 0:8e01dca41002 447
donatien 0:8e01dca41002 448 sock = get_socket(s);
donatien 0:8e01dca41002 449 if (!sock) {
donatien 0:8e01dca41002 450 return -1;
donatien 0:8e01dca41002 451 }
donatien 0:8e01dca41002 452
donatien 0:8e01dca41002 453 if(sock->conn != NULL) {
donatien 0:8e01dca41002 454 is_tcp = netconn_type(sock->conn) == NETCONN_TCP;
donatien 0:8e01dca41002 455 } else {
donatien 0:8e01dca41002 456 LWIP_ASSERT("sock->lastdata == NULL", sock->lastdata == NULL);
donatien 0:8e01dca41002 457 }
donatien 0:8e01dca41002 458
donatien 0:8e01dca41002 459 netconn_delete(sock->conn);
donatien 0:8e01dca41002 460
donatien 0:8e01dca41002 461 free_socket(sock, is_tcp);
donatien 0:8e01dca41002 462 set_errno(0);
donatien 0:8e01dca41002 463 return 0;
donatien 0:8e01dca41002 464 }
donatien 0:8e01dca41002 465
donatien 0:8e01dca41002 466 int
donatien 0:8e01dca41002 467 lwip_connect(int s, const struct sockaddr *name, socklen_t namelen)
donatien 0:8e01dca41002 468 {
donatien 0:8e01dca41002 469 struct lwip_sock *sock;
donatien 0:8e01dca41002 470 err_t err;
donatien 0:8e01dca41002 471 const struct sockaddr_in *name_in;
donatien 0:8e01dca41002 472
donatien 0:8e01dca41002 473 sock = get_socket(s);
donatien 0:8e01dca41002 474 if (!sock) {
donatien 0:8e01dca41002 475 return -1;
donatien 0:8e01dca41002 476 }
donatien 0:8e01dca41002 477
donatien 0:8e01dca41002 478 /* check size, familiy and alignment of 'name' */
donatien 0:8e01dca41002 479 LWIP_ERROR("lwip_connect: invalid address", ((namelen == sizeof(struct sockaddr_in)) &&
donatien 0:8e01dca41002 480 ((name->sa_family) == AF_INET) && ((((mem_ptr_t)name) % 4) == 0)),
donatien 0:8e01dca41002 481 sock_set_errno(sock, err_to_errno(ERR_ARG)); return -1;);
donatien 0:8e01dca41002 482 name_in = (const struct sockaddr_in *)(void*)name;
donatien 0:8e01dca41002 483
donatien 0:8e01dca41002 484 if (name_in->sin_family == AF_UNSPEC) {
donatien 0:8e01dca41002 485 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d, AF_UNSPEC)\n", s));
donatien 0:8e01dca41002 486 err = netconn_disconnect(sock->conn);
donatien 0:8e01dca41002 487 } else {
donatien 0:8e01dca41002 488 ip_addr_t remote_addr;
donatien 0:8e01dca41002 489 u16_t remote_port;
donatien 0:8e01dca41002 490
donatien 0:8e01dca41002 491 inet_addr_to_ipaddr(&remote_addr, &name_in->sin_addr);
donatien 0:8e01dca41002 492 remote_port = name_in->sin_port;
donatien 0:8e01dca41002 493
donatien 0:8e01dca41002 494 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d, addr=", s));
donatien 0:8e01dca41002 495 ip_addr_debug_print(SOCKETS_DEBUG, &remote_addr);
donatien 0:8e01dca41002 496 LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F")\n", ntohs(remote_port)));
donatien 0:8e01dca41002 497
donatien 0:8e01dca41002 498 err = netconn_connect(sock->conn, &remote_addr, ntohs(remote_port));
donatien 0:8e01dca41002 499 }
donatien 0:8e01dca41002 500
donatien 0:8e01dca41002 501 if (err != ERR_OK) {
donatien 0:8e01dca41002 502 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d) failed, err=%d\n", s, err));
donatien 0:8e01dca41002 503 sock_set_errno(sock, err_to_errno(err));
donatien 0:8e01dca41002 504 return -1;
donatien 0:8e01dca41002 505 }
donatien 0:8e01dca41002 506
donatien 0:8e01dca41002 507 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d) succeeded\n", s));
donatien 0:8e01dca41002 508 sock_set_errno(sock, 0);
donatien 0:8e01dca41002 509 return 0;
donatien 0:8e01dca41002 510 }
donatien 0:8e01dca41002 511
donatien 0:8e01dca41002 512 /**
donatien 0:8e01dca41002 513 * Set a socket into listen mode.
donatien 0:8e01dca41002 514 * The socket may not have been used for another connection previously.
donatien 0:8e01dca41002 515 *
donatien 0:8e01dca41002 516 * @param s the socket to set to listening mode
donatien 0:8e01dca41002 517 * @param backlog (ATTENTION: needs TCP_LISTEN_BACKLOG=1)
donatien 0:8e01dca41002 518 * @return 0 on success, non-zero on failure
donatien 0:8e01dca41002 519 */
donatien 0:8e01dca41002 520 int
donatien 0:8e01dca41002 521 lwip_listen(int s, int backlog)
donatien 0:8e01dca41002 522 {
donatien 0:8e01dca41002 523 struct lwip_sock *sock;
donatien 0:8e01dca41002 524 err_t err;
donatien 0:8e01dca41002 525
donatien 0:8e01dca41002 526 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_listen(%d, backlog=%d)\n", s, backlog));
donatien 0:8e01dca41002 527
donatien 0:8e01dca41002 528 sock = get_socket(s);
donatien 0:8e01dca41002 529 if (!sock) {
donatien 0:8e01dca41002 530 return -1;
donatien 0:8e01dca41002 531 }
donatien 0:8e01dca41002 532
donatien 0:8e01dca41002 533 /* limit the "backlog" parameter to fit in an u8_t */
donatien 0:8e01dca41002 534 backlog = LWIP_MIN(LWIP_MAX(backlog, 0), 0xff);
donatien 0:8e01dca41002 535
donatien 0:8e01dca41002 536 err = netconn_listen_with_backlog(sock->conn, (u8_t)backlog);
donatien 0:8e01dca41002 537
donatien 0:8e01dca41002 538 if (err != ERR_OK) {
donatien 0:8e01dca41002 539 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_listen(%d) failed, err=%d\n", s, err));
donatien 0:8e01dca41002 540 sock_set_errno(sock, err_to_errno(err));
donatien 0:8e01dca41002 541 return -1;
donatien 0:8e01dca41002 542 }
donatien 0:8e01dca41002 543
donatien 0:8e01dca41002 544 sock_set_errno(sock, 0);
donatien 0:8e01dca41002 545 return 0;
donatien 0:8e01dca41002 546 }
donatien 0:8e01dca41002 547
donatien 0:8e01dca41002 548 int
donatien 0:8e01dca41002 549 lwip_recvfrom(int s, void *mem, size_t len, int flags,
donatien 0:8e01dca41002 550 struct sockaddr *from, socklen_t *fromlen)
donatien 0:8e01dca41002 551 {
donatien 0:8e01dca41002 552 struct lwip_sock *sock;
donatien 0:8e01dca41002 553 void *buf = NULL;
donatien 0:8e01dca41002 554 struct pbuf *p;
donatien 0:8e01dca41002 555 u16_t buflen, copylen;
donatien 0:8e01dca41002 556 int off = 0;
donatien 0:8e01dca41002 557 ip_addr_t *addr;
donatien 0:8e01dca41002 558 u16_t port;
donatien 0:8e01dca41002 559 u8_t done = 0;
donatien 0:8e01dca41002 560 err_t err;
donatien 0:8e01dca41002 561
donatien 0:8e01dca41002 562 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d, %p, %"SZT_F", 0x%x, ..)\n", s, mem, len, flags));
donatien 0:8e01dca41002 563 sock = get_socket(s);
donatien 0:8e01dca41002 564 if (!sock) {
donatien 0:8e01dca41002 565 return -1;
donatien 0:8e01dca41002 566 }
donatien 0:8e01dca41002 567
donatien 0:8e01dca41002 568 do {
donatien 0:8e01dca41002 569 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: top while sock->lastdata=%p\n", sock->lastdata));
donatien 0:8e01dca41002 570 /* Check if there is data left from the last recv operation. */
donatien 0:8e01dca41002 571 if (sock->lastdata) {
donatien 0:8e01dca41002 572 buf = sock->lastdata;
donatien 0:8e01dca41002 573 } else {
donatien 0:8e01dca41002 574 /* If this is non-blocking call, then check first */
donatien 0:8e01dca41002 575 if (((flags & MSG_DONTWAIT) || netconn_is_nonblocking(sock->conn)) &&
donatien 0:8e01dca41002 576 (sock->rcvevent <= 0)) {
donatien 0:8e01dca41002 577 if (off > 0) {
donatien 0:8e01dca41002 578 /* update receive window */
donatien 0:8e01dca41002 579 netconn_recved(sock->conn, (u32_t)off);
donatien 0:8e01dca41002 580 /* already received data, return that */
donatien 0:8e01dca41002 581 sock_set_errno(sock, 0);
donatien 0:8e01dca41002 582 return off;
donatien 0:8e01dca41002 583 }
donatien 0:8e01dca41002 584 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): returning EWOULDBLOCK\n", s));
donatien 0:8e01dca41002 585 sock_set_errno(sock, EWOULDBLOCK);
donatien 0:8e01dca41002 586 return -1;
donatien 0:8e01dca41002 587 }
donatien 0:8e01dca41002 588
donatien 0:8e01dca41002 589 /* No data was left from the previous operation, so we try to get
donatien 0:8e01dca41002 590 some from the network. */
donatien 0:8e01dca41002 591 if (netconn_type(sock->conn) == NETCONN_TCP) {
donatien 0:8e01dca41002 592 err = netconn_recv_tcp_pbuf(sock->conn, (struct pbuf **)&buf);
donatien 0:8e01dca41002 593 } else {
donatien 0:8e01dca41002 594 err = netconn_recv(sock->conn, (struct netbuf **)&buf);
donatien 0:8e01dca41002 595 }
donatien 0:8e01dca41002 596 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: netconn_recv err=%d, netbuf=%p\n",
donatien 0:8e01dca41002 597 err, buf));
donatien 0:8e01dca41002 598
donatien 0:8e01dca41002 599 if (err != ERR_OK) {
donatien 0:8e01dca41002 600 if (off > 0) {
donatien 0:8e01dca41002 601 /* update receive window */
donatien 0:8e01dca41002 602 netconn_recved(sock->conn, (u32_t)off);
donatien 0:8e01dca41002 603 /* already received data, return that */
donatien 0:8e01dca41002 604 sock_set_errno(sock, 0);
donatien 0:8e01dca41002 605 return off;
donatien 0:8e01dca41002 606 }
donatien 0:8e01dca41002 607 /* We should really do some error checking here. */
donatien 0:8e01dca41002 608 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): buf == NULL, error is \"%s\"!\n",
donatien 0:8e01dca41002 609 s, lwip_strerr(err)));
donatien 0:8e01dca41002 610 sock_set_errno(sock, err_to_errno(err));
donatien 0:8e01dca41002 611 if (err == ERR_CLSD) {
donatien 0:8e01dca41002 612 return 0;
donatien 0:8e01dca41002 613 } else {
donatien 0:8e01dca41002 614 return -1;
donatien 0:8e01dca41002 615 }
donatien 0:8e01dca41002 616 }
donatien 0:8e01dca41002 617 LWIP_ASSERT("buf != NULL", buf != NULL);
donatien 0:8e01dca41002 618 sock->lastdata = buf;
donatien 0:8e01dca41002 619 }
donatien 0:8e01dca41002 620
donatien 0:8e01dca41002 621 if (netconn_type(sock->conn) == NETCONN_TCP) {
donatien 0:8e01dca41002 622 p = (struct pbuf *)buf;
donatien 0:8e01dca41002 623 } else {
donatien 0:8e01dca41002 624 p = ((struct netbuf *)buf)->p;
donatien 0:8e01dca41002 625 }
donatien 0:8e01dca41002 626 buflen = p->tot_len;
donatien 0:8e01dca41002 627 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: buflen=%"U16_F" len=%"SZT_F" off=%d sock->lastoffset=%"U16_F"\n",
donatien 0:8e01dca41002 628 buflen, len, off, sock->lastoffset));
donatien 0:8e01dca41002 629
donatien 0:8e01dca41002 630 buflen -= sock->lastoffset;
donatien 0:8e01dca41002 631
donatien 0:8e01dca41002 632 if (len > buflen) {
donatien 0:8e01dca41002 633 copylen = buflen;
donatien 0:8e01dca41002 634 } else {
donatien 0:8e01dca41002 635 copylen = (u16_t)len;
donatien 0:8e01dca41002 636 }
donatien 0:8e01dca41002 637
donatien 0:8e01dca41002 638 /* copy the contents of the received buffer into
donatien 0:8e01dca41002 639 the supplied memory pointer mem */
donatien 0:8e01dca41002 640 pbuf_copy_partial(p, (u8_t*)mem + off, copylen, sock->lastoffset);
donatien 0:8e01dca41002 641
donatien 0:8e01dca41002 642 off += copylen;
donatien 0:8e01dca41002 643
donatien 0:8e01dca41002 644 if (netconn_type(sock->conn) == NETCONN_TCP) {
donatien 0:8e01dca41002 645 LWIP_ASSERT("invalid copylen, len would underflow", len >= copylen);
donatien 0:8e01dca41002 646 len -= copylen;
donatien 0:8e01dca41002 647 if ( (len <= 0) ||
donatien 0:8e01dca41002 648 (p->flags & PBUF_FLAG_PUSH) ||
donatien 0:8e01dca41002 649 (sock->rcvevent <= 0) ||
donatien 0:8e01dca41002 650 ((flags & MSG_PEEK)!=0)) {
donatien 0:8e01dca41002 651 done = 1;
donatien 0:8e01dca41002 652 }
donatien 0:8e01dca41002 653 } else {
donatien 0:8e01dca41002 654 done = 1;
donatien 0:8e01dca41002 655 }
donatien 0:8e01dca41002 656
donatien 0:8e01dca41002 657 /* Check to see from where the data was.*/
donatien 0:8e01dca41002 658 if (done) {
donatien 0:8e01dca41002 659 ip_addr_t fromaddr;
donatien 0:8e01dca41002 660 if (from && fromlen) {
donatien 0:8e01dca41002 661 struct sockaddr_in sin;
donatien 0:8e01dca41002 662
donatien 0:8e01dca41002 663 if (netconn_type(sock->conn) == NETCONN_TCP) {
donatien 0:8e01dca41002 664 addr = &fromaddr;
donatien 0:8e01dca41002 665 netconn_getaddr(sock->conn, addr, &port, 0);
donatien 0:8e01dca41002 666 } else {
donatien 0:8e01dca41002 667 addr = netbuf_fromaddr((struct netbuf *)buf);
donatien 0:8e01dca41002 668 port = netbuf_fromport((struct netbuf *)buf);
donatien 0:8e01dca41002 669 }
donatien 0:8e01dca41002 670
donatien 0:8e01dca41002 671 memset(&sin, 0, sizeof(sin));
donatien 0:8e01dca41002 672 sin.sin_len = sizeof(sin);
donatien 0:8e01dca41002 673 sin.sin_family = AF_INET;
donatien 0:8e01dca41002 674 sin.sin_port = htons(port);
donatien 0:8e01dca41002 675 inet_addr_from_ipaddr(&sin.sin_addr, addr);
donatien 0:8e01dca41002 676
donatien 0:8e01dca41002 677 if (*fromlen > sizeof(sin)) {
donatien 0:8e01dca41002 678 *fromlen = sizeof(sin);
donatien 0:8e01dca41002 679 }
donatien 0:8e01dca41002 680
donatien 0:8e01dca41002 681 MEMCPY(from, &sin, *fromlen);
donatien 0:8e01dca41002 682
donatien 0:8e01dca41002 683 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): addr=", s));
donatien 0:8e01dca41002 684 ip_addr_debug_print(SOCKETS_DEBUG, addr);
donatien 0:8e01dca41002 685 LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F" len=%d\n", port, off));
donatien 0:8e01dca41002 686 } else {
donatien 0:8e01dca41002 687 #if SOCKETS_DEBUG
donatien 0:8e01dca41002 688 if (netconn_type(sock->conn) == NETCONN_TCP) {
donatien 0:8e01dca41002 689 addr = &fromaddr;
donatien 0:8e01dca41002 690 netconn_getaddr(sock->conn, addr, &port, 0);
donatien 0:8e01dca41002 691 } else {
donatien 0:8e01dca41002 692 addr = netbuf_fromaddr((struct netbuf *)buf);
donatien 0:8e01dca41002 693 port = netbuf_fromport((struct netbuf *)buf);
donatien 0:8e01dca41002 694 }
donatien 0:8e01dca41002 695
donatien 0:8e01dca41002 696 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): addr=", s));
donatien 0:8e01dca41002 697 ip_addr_debug_print(SOCKETS_DEBUG, addr);
donatien 0:8e01dca41002 698 LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F" len=%d\n", port, off));
donatien 0:8e01dca41002 699 #endif /* SOCKETS_DEBUG */
donatien 0:8e01dca41002 700 }
donatien 0:8e01dca41002 701 }
donatien 0:8e01dca41002 702
donatien 0:8e01dca41002 703 /* If we don't peek the incoming message... */
donatien 0:8e01dca41002 704 if ((flags & MSG_PEEK) == 0) {
donatien 0:8e01dca41002 705 /* If this is a TCP socket, check if there is data left in the
donatien 0:8e01dca41002 706 buffer. If so, it should be saved in the sock structure for next
donatien 0:8e01dca41002 707 time around. */
donatien 0:8e01dca41002 708 if ((netconn_type(sock->conn) == NETCONN_TCP) && (buflen - copylen > 0)) {
donatien 0:8e01dca41002 709 sock->lastdata = buf;
donatien 0:8e01dca41002 710 sock->lastoffset += copylen;
donatien 0:8e01dca41002 711 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: lastdata now netbuf=%p\n", buf));
donatien 0:8e01dca41002 712 } else {
donatien 0:8e01dca41002 713 sock->lastdata = NULL;
donatien 0:8e01dca41002 714 sock->lastoffset = 0;
donatien 0:8e01dca41002 715 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: deleting netbuf=%p\n", buf));
donatien 0:8e01dca41002 716 if (netconn_type(sock->conn) == NETCONN_TCP) {
donatien 0:8e01dca41002 717 pbuf_free((struct pbuf *)buf);
donatien 0:8e01dca41002 718 } else {
donatien 0:8e01dca41002 719 netbuf_delete((struct netbuf *)buf);
donatien 0:8e01dca41002 720 }
donatien 0:8e01dca41002 721 }
donatien 0:8e01dca41002 722 }
donatien 0:8e01dca41002 723 } while (!done);
donatien 0:8e01dca41002 724
donatien 0:8e01dca41002 725 if (off > 0) {
donatien 0:8e01dca41002 726 /* update receive window */
donatien 0:8e01dca41002 727 netconn_recved(sock->conn, (u32_t)off);
donatien 0:8e01dca41002 728 }
donatien 0:8e01dca41002 729 sock_set_errno(sock, 0);
donatien 0:8e01dca41002 730 return off;
donatien 0:8e01dca41002 731 }
donatien 0:8e01dca41002 732
donatien 0:8e01dca41002 733 int
donatien 0:8e01dca41002 734 lwip_read(int s, void *mem, size_t len)
donatien 0:8e01dca41002 735 {
donatien 0:8e01dca41002 736 return lwip_recvfrom(s, mem, len, 0, NULL, NULL);
donatien 0:8e01dca41002 737 }
donatien 0:8e01dca41002 738
donatien 0:8e01dca41002 739 int
donatien 0:8e01dca41002 740 lwip_recv(int s, void *mem, size_t len, int flags)
donatien 0:8e01dca41002 741 {
donatien 0:8e01dca41002 742 return lwip_recvfrom(s, mem, len, flags, NULL, NULL);
donatien 0:8e01dca41002 743 }
donatien 0:8e01dca41002 744
donatien 0:8e01dca41002 745 int
donatien 0:8e01dca41002 746 lwip_send(int s, const void *data, size_t size, int flags)
donatien 0:8e01dca41002 747 {
donatien 0:8e01dca41002 748 struct lwip_sock *sock;
donatien 0:8e01dca41002 749 err_t err;
donatien 0:8e01dca41002 750 u8_t write_flags;
donatien 0:8e01dca41002 751
donatien 0:8e01dca41002 752 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_send(%d, data=%p, size=%"SZT_F", flags=0x%x)\n",
donatien 0:8e01dca41002 753 s, data, size, flags));
donatien 0:8e01dca41002 754
donatien 0:8e01dca41002 755 sock = get_socket(s);
donatien 0:8e01dca41002 756 if (!sock) {
donatien 0:8e01dca41002 757 return -1;
donatien 0:8e01dca41002 758 }
donatien 0:8e01dca41002 759
donatien 0:8e01dca41002 760 if (sock->conn->type != NETCONN_TCP) {
donatien 0:8e01dca41002 761 #if (LWIP_UDP || LWIP_RAW)
donatien 0:8e01dca41002 762 return lwip_sendto(s, data, size, flags, NULL, 0);
donatien 0:8e01dca41002 763 #else /* (LWIP_UDP || LWIP_RAW) */
donatien 0:8e01dca41002 764 sock_set_errno(sock, err_to_errno(ERR_ARG));
donatien 0:8e01dca41002 765 return -1;
donatien 0:8e01dca41002 766 #endif /* (LWIP_UDP || LWIP_RAW) */
donatien 0:8e01dca41002 767 }
donatien 0:8e01dca41002 768
donatien 0:8e01dca41002 769 if ((flags & MSG_DONTWAIT) || netconn_is_nonblocking(sock->conn)) {
donatien 0:8e01dca41002 770 if ((size > TCP_SND_BUF) || ((size / TCP_MSS) > TCP_SND_QUEUELEN)) {
donatien 0:8e01dca41002 771 /* too much data to ever send nonblocking! */
donatien 0:8e01dca41002 772 sock_set_errno(sock, EMSGSIZE);
donatien 0:8e01dca41002 773 return -1;
donatien 0:8e01dca41002 774 }
donatien 0:8e01dca41002 775 }
donatien 0:8e01dca41002 776
donatien 0:8e01dca41002 777 write_flags = NETCONN_COPY |
donatien 0:8e01dca41002 778 ((flags & MSG_MORE) ? NETCONN_MORE : 0) |
donatien 0:8e01dca41002 779 ((flags & MSG_DONTWAIT) ? NETCONN_DONTBLOCK : 0);
donatien 0:8e01dca41002 780 err = netconn_write(sock->conn, data, size, write_flags);
donatien 0:8e01dca41002 781
donatien 0:8e01dca41002 782 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_send(%d) err=%d size=%"SZT_F"\n", s, err, size));
donatien 0:8e01dca41002 783 sock_set_errno(sock, err_to_errno(err));
donatien 0:8e01dca41002 784 return (err == ERR_OK ? (int)size : -1);
donatien 0:8e01dca41002 785 }
donatien 0:8e01dca41002 786
donatien 0:8e01dca41002 787 int
donatien 0:8e01dca41002 788 lwip_sendto(int s, const void *data, size_t size, int flags,
donatien 0:8e01dca41002 789 const struct sockaddr *to, socklen_t tolen)
donatien 0:8e01dca41002 790 {
donatien 0:8e01dca41002 791 struct lwip_sock *sock;
donatien 0:8e01dca41002 792 err_t err;
donatien 0:8e01dca41002 793 u16_t short_size;
donatien 0:8e01dca41002 794 const struct sockaddr_in *to_in;
donatien 0:8e01dca41002 795 u16_t remote_port;
donatien 0:8e01dca41002 796 #if !LWIP_TCPIP_CORE_LOCKING
donatien 0:8e01dca41002 797 struct netbuf buf;
donatien 0:8e01dca41002 798 #endif
donatien 0:8e01dca41002 799
donatien 0:8e01dca41002 800 sock = get_socket(s);
donatien 0:8e01dca41002 801 if (!sock) {
donatien 0:8e01dca41002 802 return -1;
donatien 0:8e01dca41002 803 }
donatien 0:8e01dca41002 804
donatien 0:8e01dca41002 805 if (sock->conn->type == NETCONN_TCP) {
donatien 0:8e01dca41002 806 #if LWIP_TCP
donatien 0:8e01dca41002 807 return lwip_send(s, data, size, flags);
donatien 0:8e01dca41002 808 #else /* LWIP_TCP */
donatien 0:8e01dca41002 809 LWIP_UNUSED_ARG(flags);
donatien 0:8e01dca41002 810 sock_set_errno(sock, err_to_errno(ERR_ARG));
donatien 0:8e01dca41002 811 return -1;
donatien 0:8e01dca41002 812 #endif /* LWIP_TCP */
donatien 0:8e01dca41002 813 }
donatien 0:8e01dca41002 814
donatien 0:8e01dca41002 815 /* @todo: split into multiple sendto's? */
donatien 0:8e01dca41002 816 LWIP_ASSERT("lwip_sendto: size must fit in u16_t", size <= 0xffff);
donatien 0:8e01dca41002 817 short_size = (u16_t)size;
donatien 0:8e01dca41002 818 LWIP_ERROR("lwip_sendto: invalid address", (((to == NULL) && (tolen == 0)) ||
donatien 0:8e01dca41002 819 ((tolen == sizeof(struct sockaddr_in)) &&
donatien 0:8e01dca41002 820 ((to->sa_family) == AF_INET) && ((((mem_ptr_t)to) % 4) == 0))),
donatien 0:8e01dca41002 821 sock_set_errno(sock, err_to_errno(ERR_ARG)); return -1;);
donatien 0:8e01dca41002 822 to_in = (const struct sockaddr_in *)(void*)to;
donatien 0:8e01dca41002 823
donatien 0:8e01dca41002 824 #if LWIP_TCPIP_CORE_LOCKING
donatien 0:8e01dca41002 825 /* Should only be consider like a sample or a simple way to experiment this option (no check of "to" field...) */
donatien 0:8e01dca41002 826 {
donatien 0:8e01dca41002 827 struct pbuf* p;
donatien 0:8e01dca41002 828 ip_addr_t *remote_addr;
donatien 0:8e01dca41002 829
donatien 0:8e01dca41002 830 #if LWIP_NETIF_TX_SINGLE_PBUF
donatien 0:8e01dca41002 831 p = pbuf_alloc(PBUF_TRANSPORT, short_size, PBUF_RAM);
donatien 0:8e01dca41002 832 if (p != NULL) {
donatien 0:8e01dca41002 833 #if LWIP_CHECKSUM_ON_COPY
donatien 0:8e01dca41002 834 u16_t chksum = 0;
donatien 0:8e01dca41002 835 if (sock->conn->type != NETCONN_RAW) {
donatien 0:8e01dca41002 836 chksum = LWIP_CHKSUM_COPY(p->payload, data, short_size);
donatien 0:8e01dca41002 837 } else
donatien 0:8e01dca41002 838 #endif /* LWIP_CHECKSUM_ON_COPY */
donatien 0:8e01dca41002 839 MEMCPY(p->payload, data, size);
donatien 0:8e01dca41002 840 #else /* LWIP_NETIF_TX_SINGLE_PBUF */
donatien 0:8e01dca41002 841 p = pbuf_alloc(PBUF_TRANSPORT, short_size, PBUF_REF);
donatien 0:8e01dca41002 842 if (p != NULL) {
donatien 0:8e01dca41002 843 p->payload = (void*)data;
donatien 0:8e01dca41002 844 #endif /* LWIP_NETIF_TX_SINGLE_PBUF */
donatien 0:8e01dca41002 845
donatien 0:8e01dca41002 846 if (to_in != NULL) {
donatien 0:8e01dca41002 847 inet_addr_to_ipaddr_p(remote_addr, &to_in->sin_addr);
donatien 0:8e01dca41002 848 remote_port = ntohs(to_in->sin_port);
donatien 0:8e01dca41002 849 } else {
donatien 0:8e01dca41002 850 remote_addr = &sock->conn->pcb.raw->remote_ip;
donatien 0:8e01dca41002 851 if (sock->conn->type == NETCONN_RAW) {
donatien 0:8e01dca41002 852 remote_port = 0;
donatien 0:8e01dca41002 853 } else {
donatien 0:8e01dca41002 854 remote_port = sock->conn->pcb.udp->remote_port;
donatien 0:8e01dca41002 855 }
donatien 0:8e01dca41002 856 }
donatien 0:8e01dca41002 857
donatien 0:8e01dca41002 858 LOCK_TCPIP_CORE();
donatien 0:8e01dca41002 859 if (sock->conn->type == NETCONN_RAW) {
donatien 0:8e01dca41002 860 err = sock->conn->last_err = raw_sendto(sock->conn->pcb.raw, p, remote_addr);
donatien 0:8e01dca41002 861 } else {
donatien 0:8e01dca41002 862 #if LWIP_UDP
donatien 0:8e01dca41002 863 #if LWIP_CHECKSUM_ON_COPY && LWIP_NETIF_TX_SINGLE_PBUF
donatien 0:8e01dca41002 864 err = sock->conn->last_err = udp_sendto_chksum(sock->conn->pcb.udp, p,
donatien 0:8e01dca41002 865 remote_addr, remote_port, 1, chksum);
donatien 0:8e01dca41002 866 #else /* LWIP_CHECKSUM_ON_COPY && LWIP_NETIF_TX_SINGLE_PBUF */
donatien 0:8e01dca41002 867 err = sock->conn->last_err = udp_sendto(sock->conn->pcb.udp, p,
donatien 0:8e01dca41002 868 remote_addr, remote_port);
donatien 0:8e01dca41002 869 #endif /* LWIP_CHECKSUM_ON_COPY && LWIP_NETIF_TX_SINGLE_PBUF */
donatien 0:8e01dca41002 870 #else /* LWIP_UDP */
donatien 0:8e01dca41002 871 err = ERR_ARG;
donatien 0:8e01dca41002 872 #endif /* LWIP_UDP */
donatien 0:8e01dca41002 873 }
donatien 0:8e01dca41002 874 UNLOCK_TCPIP_CORE();
donatien 0:8e01dca41002 875
donatien 0:8e01dca41002 876 pbuf_free(p);
donatien 0:8e01dca41002 877 } else {
donatien 0:8e01dca41002 878 err = ERR_MEM;
donatien 0:8e01dca41002 879 }
donatien 0:8e01dca41002 880 }
donatien 0:8e01dca41002 881 #else /* LWIP_TCPIP_CORE_LOCKING */
donatien 0:8e01dca41002 882 /* initialize a buffer */
donatien 0:8e01dca41002 883 buf.p = buf.ptr = NULL;
donatien 0:8e01dca41002 884 #if LWIP_CHECKSUM_ON_COPY
donatien 0:8e01dca41002 885 buf.flags = 0;
donatien 0:8e01dca41002 886 #endif /* LWIP_CHECKSUM_ON_COPY */
donatien 0:8e01dca41002 887 if (to) {
donatien 0:8e01dca41002 888 inet_addr_to_ipaddr(&buf.addr, &to_in->sin_addr);
donatien 0:8e01dca41002 889 remote_port = ntohs(to_in->sin_port);
donatien 0:8e01dca41002 890 netbuf_fromport(&buf) = remote_port;
donatien 0:8e01dca41002 891 } else {
donatien 0:8e01dca41002 892 remote_port = 0;
donatien 0:8e01dca41002 893 ip_addr_set_any(&buf.addr);
donatien 0:8e01dca41002 894 netbuf_fromport(&buf) = 0;
donatien 0:8e01dca41002 895 }
donatien 0:8e01dca41002 896
donatien 0:8e01dca41002 897 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_sendto(%d, data=%p, short_size=%"U16_F", flags=0x%x to=",
donatien 0:8e01dca41002 898 s, data, short_size, flags));
donatien 0:8e01dca41002 899 ip_addr_debug_print(SOCKETS_DEBUG, &buf.addr);
donatien 0:8e01dca41002 900 LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F"\n", remote_port));
donatien 0:8e01dca41002 901
donatien 0:8e01dca41002 902 /* make the buffer point to the data that should be sent */
donatien 0:8e01dca41002 903 #if LWIP_NETIF_TX_SINGLE_PBUF
donatien 0:8e01dca41002 904 /* Allocate a new netbuf and copy the data into it. */
donatien 0:8e01dca41002 905 if (netbuf_alloc(&buf, short_size) == NULL) {
donatien 0:8e01dca41002 906 err = ERR_MEM;
donatien 0:8e01dca41002 907 } else {
donatien 0:8e01dca41002 908 #if LWIP_CHECKSUM_ON_COPY
donatien 0:8e01dca41002 909 if (sock->conn->type != NETCONN_RAW) {
donatien 0:8e01dca41002 910 u16_t chksum = LWIP_CHKSUM_COPY(buf.p->payload, data, short_size);
donatien 0:8e01dca41002 911 netbuf_set_chksum(&buf, chksum);
donatien 0:8e01dca41002 912 err = ERR_OK;
donatien 0:8e01dca41002 913 } else
donatien 0:8e01dca41002 914 #endif /* LWIP_CHECKSUM_ON_COPY */
donatien 0:8e01dca41002 915 {
donatien 0:8e01dca41002 916 err = netbuf_take(&buf, data, short_size);
donatien 0:8e01dca41002 917 }
donatien 0:8e01dca41002 918 }
donatien 0:8e01dca41002 919 #else /* LWIP_NETIF_TX_SINGLE_PBUF */
donatien 0:8e01dca41002 920 err = netbuf_ref(&buf, data, short_size);
donatien 0:8e01dca41002 921 #endif /* LWIP_NETIF_TX_SINGLE_PBUF */
donatien 0:8e01dca41002 922 if (err == ERR_OK) {
donatien 0:8e01dca41002 923 /* send the data */
donatien 0:8e01dca41002 924 err = netconn_send(sock->conn, &buf);
donatien 0:8e01dca41002 925 }
donatien 0:8e01dca41002 926
donatien 0:8e01dca41002 927 /* deallocated the buffer */
donatien 0:8e01dca41002 928 netbuf_free(&buf);
donatien 0:8e01dca41002 929 #endif /* LWIP_TCPIP_CORE_LOCKING */
donatien 0:8e01dca41002 930 sock_set_errno(sock, err_to_errno(err));
donatien 0:8e01dca41002 931 return (err == ERR_OK ? short_size : -1);
donatien 0:8e01dca41002 932 }
donatien 0:8e01dca41002 933
donatien 0:8e01dca41002 934 int
donatien 0:8e01dca41002 935 lwip_socket(int domain, int type, int protocol)
donatien 0:8e01dca41002 936 {
donatien 0:8e01dca41002 937 struct netconn *conn;
donatien 0:8e01dca41002 938 int i;
donatien 0:8e01dca41002 939
donatien 0:8e01dca41002 940 LWIP_UNUSED_ARG(domain);
donatien 0:8e01dca41002 941
donatien 0:8e01dca41002 942 /* create a netconn */
donatien 0:8e01dca41002 943 switch (type) {
donatien 0:8e01dca41002 944 case SOCK_RAW:
donatien 0:8e01dca41002 945 conn = netconn_new_with_proto_and_callback(NETCONN_RAW, (u8_t)protocol, event_callback);
donatien 0:8e01dca41002 946 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_RAW, %d) = ",
donatien 0:8e01dca41002 947 domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol));
donatien 0:8e01dca41002 948 break;
donatien 0:8e01dca41002 949 case SOCK_DGRAM:
donatien 0:8e01dca41002 950 conn = netconn_new_with_callback( (protocol == IPPROTO_UDPLITE) ?
donatien 0:8e01dca41002 951 NETCONN_UDPLITE : NETCONN_UDP, event_callback);
donatien 0:8e01dca41002 952 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_DGRAM, %d) = ",
donatien 0:8e01dca41002 953 domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol));
donatien 0:8e01dca41002 954 break;
donatien 0:8e01dca41002 955 case SOCK_STREAM:
donatien 0:8e01dca41002 956 conn = netconn_new_with_callback(NETCONN_TCP, event_callback);
donatien 0:8e01dca41002 957 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_STREAM, %d) = ",
donatien 0:8e01dca41002 958 domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol));
donatien 0:8e01dca41002 959 if (conn != NULL) {
donatien 0:8e01dca41002 960 /* Prevent automatic window updates, we do this on our own! */
donatien 0:8e01dca41002 961 netconn_set_noautorecved(conn, 1);
donatien 0:8e01dca41002 962 }
donatien 0:8e01dca41002 963 break;
donatien 0:8e01dca41002 964 default:
donatien 0:8e01dca41002 965 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%d, %d/UNKNOWN, %d) = -1\n",
donatien 0:8e01dca41002 966 domain, type, protocol));
donatien 0:8e01dca41002 967 set_errno(EINVAL);
donatien 0:8e01dca41002 968 return -1;
donatien 0:8e01dca41002 969 }
donatien 0:8e01dca41002 970
donatien 0:8e01dca41002 971 if (!conn) {
donatien 0:8e01dca41002 972 LWIP_DEBUGF(SOCKETS_DEBUG, ("-1 / ENOBUFS (could not create netconn)\n"));
donatien 0:8e01dca41002 973 set_errno(ENOBUFS);
donatien 0:8e01dca41002 974 return -1;
donatien 0:8e01dca41002 975 }
donatien 0:8e01dca41002 976
donatien 0:8e01dca41002 977 i = alloc_socket(conn, 0);
donatien 0:8e01dca41002 978
donatien 0:8e01dca41002 979 if (i == -1) {
donatien 0:8e01dca41002 980 netconn_delete(conn);
donatien 0:8e01dca41002 981 set_errno(ENFILE);
donatien 0:8e01dca41002 982 return -1;
donatien 0:8e01dca41002 983 }
donatien 0:8e01dca41002 984 conn->socket = i;
donatien 0:8e01dca41002 985 LWIP_DEBUGF(SOCKETS_DEBUG, ("%d\n", i));
donatien 0:8e01dca41002 986 set_errno(0);
donatien 0:8e01dca41002 987 return i;
donatien 0:8e01dca41002 988 }
donatien 0:8e01dca41002 989
donatien 0:8e01dca41002 990 int
donatien 0:8e01dca41002 991 lwip_write(int s, const void *data, size_t size)
donatien 0:8e01dca41002 992 {
donatien 0:8e01dca41002 993 return lwip_send(s, data, size, 0);
donatien 0:8e01dca41002 994 }
donatien 0:8e01dca41002 995
donatien 0:8e01dca41002 996 /**
donatien 0:8e01dca41002 997 * Go through the readset and writeset lists and see which socket of the sockets
donatien 0:8e01dca41002 998 * set in the sets has events. On return, readset, writeset and exceptset have
donatien 0:8e01dca41002 999 * the sockets enabled that had events.
donatien 0:8e01dca41002 1000 *
donatien 0:8e01dca41002 1001 * exceptset is not used for now!!!
donatien 0:8e01dca41002 1002 *
donatien 0:8e01dca41002 1003 * @param maxfdp1 the highest socket index in the sets
donatien 0:8e01dca41002 1004 * @param readset_in: set of sockets to check for read events
donatien 0:8e01dca41002 1005 * @param writeset_in: set of sockets to check for write events
donatien 0:8e01dca41002 1006 * @param exceptset_in: set of sockets to check for error events
donatien 0:8e01dca41002 1007 * @param readset_out: set of sockets that had read events
donatien 0:8e01dca41002 1008 * @param writeset_out: set of sockets that had write events
donatien 0:8e01dca41002 1009 * @param exceptset_out: set os sockets that had error events
donatien 0:8e01dca41002 1010 * @return number of sockets that had events (read/write/exception) (>= 0)
donatien 0:8e01dca41002 1011 */
donatien 0:8e01dca41002 1012 static int
donatien 0:8e01dca41002 1013 lwip_selscan(int maxfdp1, fd_set *readset_in, fd_set *writeset_in, fd_set *exceptset_in,
donatien 0:8e01dca41002 1014 fd_set *readset_out, fd_set *writeset_out, fd_set *exceptset_out)
donatien 0:8e01dca41002 1015 {
donatien 0:8e01dca41002 1016 int i, nready = 0;
donatien 0:8e01dca41002 1017 fd_set lreadset, lwriteset, lexceptset;
donatien 0:8e01dca41002 1018 struct lwip_sock *sock;
donatien 0:8e01dca41002 1019 SYS_ARCH_DECL_PROTECT(lev);
donatien 0:8e01dca41002 1020
donatien 0:8e01dca41002 1021 FD_ZERO(&lreadset);
donatien 0:8e01dca41002 1022 FD_ZERO(&lwriteset);
donatien 0:8e01dca41002 1023 FD_ZERO(&lexceptset);
donatien 0:8e01dca41002 1024
donatien 0:8e01dca41002 1025 /* Go through each socket in each list to count number of sockets which
donatien 0:8e01dca41002 1026 currently match */
donatien 0:8e01dca41002 1027 for(i = 0; i < maxfdp1; i++) {
donatien 0:8e01dca41002 1028 void* lastdata = NULL;
donatien 0:8e01dca41002 1029 s16_t rcvevent = 0;
donatien 0:8e01dca41002 1030 u16_t sendevent = 0;
donatien 0:8e01dca41002 1031 u16_t errevent = 0;
donatien 0:8e01dca41002 1032 /* First get the socket's status (protected)... */
donatien 0:8e01dca41002 1033 SYS_ARCH_PROTECT(lev);
donatien 0:8e01dca41002 1034 sock = tryget_socket(i);
donatien 0:8e01dca41002 1035 if (sock != NULL) {
donatien 0:8e01dca41002 1036 lastdata = sock->lastdata;
donatien 0:8e01dca41002 1037 rcvevent = sock->rcvevent;
donatien 0:8e01dca41002 1038 sendevent = sock->sendevent;
donatien 0:8e01dca41002 1039 errevent = sock->errevent;
donatien 0:8e01dca41002 1040 }
donatien 0:8e01dca41002 1041 SYS_ARCH_UNPROTECT(lev);
donatien 0:8e01dca41002 1042 /* ... then examine it: */
donatien 0:8e01dca41002 1043 /* See if netconn of this socket is ready for read */
donatien 0:8e01dca41002 1044 if (readset_in && FD_ISSET(i, readset_in) && ((lastdata != NULL) || (rcvevent > 0))) {
donatien 0:8e01dca41002 1045 FD_SET(i, &lreadset);
donatien 0:8e01dca41002 1046 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_selscan: fd=%d ready for reading\n", i));
donatien 0:8e01dca41002 1047 nready++;
donatien 0:8e01dca41002 1048 }
donatien 0:8e01dca41002 1049 /* See if netconn of this socket is ready for write */
donatien 0:8e01dca41002 1050 if (writeset_in && FD_ISSET(i, writeset_in) && (sendevent != 0)) {
donatien 0:8e01dca41002 1051 FD_SET(i, &lwriteset);
donatien 0:8e01dca41002 1052 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_selscan: fd=%d ready for writing\n", i));
donatien 0:8e01dca41002 1053 nready++;
donatien 0:8e01dca41002 1054 }
donatien 0:8e01dca41002 1055 /* See if netconn of this socket had an error */
donatien 0:8e01dca41002 1056 if (exceptset_in && FD_ISSET(i, exceptset_in) && (errevent != 0)) {
donatien 0:8e01dca41002 1057 FD_SET(i, &lexceptset);
donatien 0:8e01dca41002 1058 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_selscan: fd=%d ready for exception\n", i));
donatien 0:8e01dca41002 1059 nready++;
donatien 0:8e01dca41002 1060 }
donatien 0:8e01dca41002 1061 }
donatien 0:8e01dca41002 1062 /* copy local sets to the ones provided as arguments */
donatien 0:8e01dca41002 1063 *readset_out = lreadset;
donatien 0:8e01dca41002 1064 *writeset_out = lwriteset;
donatien 0:8e01dca41002 1065 *exceptset_out = lexceptset;
donatien 0:8e01dca41002 1066
donatien 0:8e01dca41002 1067 LWIP_ASSERT("nready >= 0", nready >= 0);
donatien 0:8e01dca41002 1068 return nready;
donatien 0:8e01dca41002 1069 }
donatien 0:8e01dca41002 1070
donatien 0:8e01dca41002 1071 /**
donatien 0:8e01dca41002 1072 * Processing exceptset is not yet implemented.
donatien 0:8e01dca41002 1073 */
donatien 0:8e01dca41002 1074 int
donatien 0:8e01dca41002 1075 lwip_select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset,
donatien 0:8e01dca41002 1076 struct timeval *timeout)
donatien 0:8e01dca41002 1077 {
donatien 0:8e01dca41002 1078 u32_t waitres = 0;
donatien 0:8e01dca41002 1079 int nready;
donatien 0:8e01dca41002 1080 fd_set lreadset, lwriteset, lexceptset;
donatien 0:8e01dca41002 1081 u32_t msectimeout;
donatien 0:8e01dca41002 1082 struct lwip_select_cb select_cb;
donatien 0:8e01dca41002 1083 err_t err;
donatien 0:8e01dca41002 1084 int i;
donatien 0:8e01dca41002 1085 SYS_ARCH_DECL_PROTECT(lev);
donatien 0:8e01dca41002 1086
donatien 0:8e01dca41002 1087 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select(%d, %p, %p, %p, tvsec=%"S32_F" tvusec=%"S32_F")\n",
donatien 0:8e01dca41002 1088 maxfdp1, (void *)readset, (void *) writeset, (void *) exceptset,
donatien 0:8e01dca41002 1089 timeout ? (s32_t)timeout->tv_sec : (s32_t)-1,
donatien 0:8e01dca41002 1090 timeout ? (s32_t)timeout->tv_usec : (s32_t)-1));
donatien 0:8e01dca41002 1091
donatien 0:8e01dca41002 1092 /* Go through each socket in each list to count number of sockets which
donatien 0:8e01dca41002 1093 currently match */
donatien 0:8e01dca41002 1094 nready = lwip_selscan(maxfdp1, readset, writeset, exceptset, &lreadset, &lwriteset, &lexceptset);
donatien 0:8e01dca41002 1095
donatien 0:8e01dca41002 1096 /* If we don't have any current events, then suspend if we are supposed to */
donatien 0:8e01dca41002 1097 if (!nready) {
donatien 0:8e01dca41002 1098 if (timeout && timeout->tv_sec == 0 && timeout->tv_usec == 0) {
donatien 0:8e01dca41002 1099 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select: no timeout, returning 0\n"));
donatien 0:8e01dca41002 1100 /* This is OK as the local fdsets are empty and nready is zero,
donatien 0:8e01dca41002 1101 or we would have returned earlier. */
donatien 0:8e01dca41002 1102 goto return_copy_fdsets;
donatien 0:8e01dca41002 1103 }
donatien 0:8e01dca41002 1104
donatien 0:8e01dca41002 1105 /* None ready: add our semaphore to list:
donatien 0:8e01dca41002 1106 We don't actually need any dynamic memory. Our entry on the
donatien 0:8e01dca41002 1107 list is only valid while we are in this function, so it's ok
donatien 0:8e01dca41002 1108 to use local variables. */
donatien 0:8e01dca41002 1109
donatien 0:8e01dca41002 1110 select_cb.next = NULL;
donatien 0:8e01dca41002 1111 select_cb.prev = NULL;
donatien 0:8e01dca41002 1112 select_cb.readset = readset;
donatien 0:8e01dca41002 1113 select_cb.writeset = writeset;
donatien 0:8e01dca41002 1114 select_cb.exceptset = exceptset;
donatien 0:8e01dca41002 1115 select_cb.sem_signalled = 0;
donatien 0:8e01dca41002 1116 err = sys_sem_new(&select_cb.sem, 0);
donatien 0:8e01dca41002 1117 if (err != ERR_OK) {
donatien 0:8e01dca41002 1118 /* failed to create semaphore */
donatien 0:8e01dca41002 1119 set_errno(ENOMEM);
donatien 0:8e01dca41002 1120 return -1;
donatien 0:8e01dca41002 1121 }
donatien 0:8e01dca41002 1122
donatien 0:8e01dca41002 1123 /* Protect the select_cb_list */
donatien 0:8e01dca41002 1124 SYS_ARCH_PROTECT(lev);
donatien 0:8e01dca41002 1125
donatien 0:8e01dca41002 1126 /* Put this select_cb on top of list */
donatien 0:8e01dca41002 1127 select_cb.next = select_cb_list;
donatien 0:8e01dca41002 1128 if (select_cb_list != NULL) {
donatien 0:8e01dca41002 1129 select_cb_list->prev = &select_cb;
donatien 0:8e01dca41002 1130 }
donatien 0:8e01dca41002 1131 select_cb_list = &select_cb;
donatien 0:8e01dca41002 1132 /* Increasing this counter tells even_callback that the list has changed. */
donatien 0:8e01dca41002 1133 select_cb_ctr++;
donatien 0:8e01dca41002 1134
donatien 0:8e01dca41002 1135 /* Now we can safely unprotect */
donatien 0:8e01dca41002 1136 SYS_ARCH_UNPROTECT(lev);
donatien 0:8e01dca41002 1137
donatien 0:8e01dca41002 1138 /* Increase select_waiting for each socket we are interested in */
donatien 0:8e01dca41002 1139 for(i = 0; i < maxfdp1; i++) {
donatien 0:8e01dca41002 1140 if ((readset && FD_ISSET(i, readset)) ||
donatien 0:8e01dca41002 1141 (writeset && FD_ISSET(i, writeset)) ||
donatien 0:8e01dca41002 1142 (exceptset && FD_ISSET(i, exceptset))) {
donatien 0:8e01dca41002 1143 struct lwip_sock *sock = tryget_socket(i);
donatien 0:8e01dca41002 1144 LWIP_ASSERT("sock != NULL", sock != NULL);
donatien 0:8e01dca41002 1145 SYS_ARCH_PROTECT(lev);
donatien 0:8e01dca41002 1146 sock->select_waiting++;
donatien 0:8e01dca41002 1147 LWIP_ASSERT("sock->select_waiting > 0", sock->select_waiting > 0);
donatien 0:8e01dca41002 1148 SYS_ARCH_UNPROTECT(lev);
donatien 0:8e01dca41002 1149 }
donatien 0:8e01dca41002 1150 }
donatien 0:8e01dca41002 1151
donatien 0:8e01dca41002 1152 /* Call lwip_selscan again: there could have been events between
donatien 0:8e01dca41002 1153 the last scan (whithout us on the list) and putting us on the list! */
donatien 0:8e01dca41002 1154 nready = lwip_selscan(maxfdp1, readset, writeset, exceptset, &lreadset, &lwriteset, &lexceptset);
donatien 0:8e01dca41002 1155 if (!nready) {
donatien 0:8e01dca41002 1156 /* Still none ready, just wait to be woken */
donatien 0:8e01dca41002 1157 if (timeout == 0) {
donatien 0:8e01dca41002 1158 /* Wait forever */
donatien 0:8e01dca41002 1159 msectimeout = 0;
donatien 0:8e01dca41002 1160 } else {
donatien 0:8e01dca41002 1161 msectimeout = ((timeout->tv_sec * 1000) + ((timeout->tv_usec + 500)/1000));
donatien 0:8e01dca41002 1162 if (msectimeout == 0) {
donatien 0:8e01dca41002 1163 /* Wait 1ms at least (0 means wait forever) */
donatien 0:8e01dca41002 1164 msectimeout = 1;
donatien 0:8e01dca41002 1165 }
donatien 0:8e01dca41002 1166 }
donatien 0:8e01dca41002 1167
donatien 0:8e01dca41002 1168 waitres = sys_arch_sem_wait(&select_cb.sem, msectimeout);
donatien 0:8e01dca41002 1169 }
donatien 0:8e01dca41002 1170 /* Increase select_waiting for each socket we are interested in */
donatien 0:8e01dca41002 1171 for(i = 0; i < maxfdp1; i++) {
donatien 0:8e01dca41002 1172 if ((readset && FD_ISSET(i, readset)) ||
donatien 0:8e01dca41002 1173 (writeset && FD_ISSET(i, writeset)) ||
donatien 0:8e01dca41002 1174 (exceptset && FD_ISSET(i, exceptset))) {
donatien 0:8e01dca41002 1175 struct lwip_sock *sock = tryget_socket(i);
donatien 0:8e01dca41002 1176 LWIP_ASSERT("sock != NULL", sock != NULL);
donatien 0:8e01dca41002 1177 SYS_ARCH_PROTECT(lev);
donatien 0:8e01dca41002 1178 sock->select_waiting--;
donatien 0:8e01dca41002 1179 LWIP_ASSERT("sock->select_waiting >= 0", sock->select_waiting >= 0);
donatien 0:8e01dca41002 1180 SYS_ARCH_UNPROTECT(lev);
donatien 0:8e01dca41002 1181 }
donatien 0:8e01dca41002 1182 }
donatien 0:8e01dca41002 1183 /* Take us off the list */
donatien 0:8e01dca41002 1184 SYS_ARCH_PROTECT(lev);
donatien 0:8e01dca41002 1185 if (select_cb.next != NULL) {
donatien 0:8e01dca41002 1186 select_cb.next->prev = select_cb.prev;
donatien 0:8e01dca41002 1187 }
donatien 0:8e01dca41002 1188 if (select_cb_list == &select_cb) {
donatien 0:8e01dca41002 1189 LWIP_ASSERT("select_cb.prev == NULL", select_cb.prev == NULL);
donatien 0:8e01dca41002 1190 select_cb_list = select_cb.next;
donatien 0:8e01dca41002 1191 } else {
donatien 0:8e01dca41002 1192 LWIP_ASSERT("select_cb.prev != NULL", select_cb.prev != NULL);
donatien 0:8e01dca41002 1193 select_cb.prev->next = select_cb.next;
donatien 0:8e01dca41002 1194 }
donatien 0:8e01dca41002 1195 /* Increasing this counter tells even_callback that the list has changed. */
donatien 0:8e01dca41002 1196 select_cb_ctr++;
donatien 0:8e01dca41002 1197 SYS_ARCH_UNPROTECT(lev);
donatien 0:8e01dca41002 1198
donatien 0:8e01dca41002 1199 sys_sem_free(&select_cb.sem);
donatien 0:8e01dca41002 1200 if (waitres == SYS_ARCH_TIMEOUT) {
donatien 0:8e01dca41002 1201 /* Timeout */
donatien 0:8e01dca41002 1202 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select: timeout expired\n"));
donatien 0:8e01dca41002 1203 /* This is OK as the local fdsets are empty and nready is zero,
donatien 0:8e01dca41002 1204 or we would have returned earlier. */
donatien 0:8e01dca41002 1205 goto return_copy_fdsets;
donatien 0:8e01dca41002 1206 }
donatien 0:8e01dca41002 1207
donatien 0:8e01dca41002 1208 /* See what's set */
donatien 0:8e01dca41002 1209 nready = lwip_selscan(maxfdp1, readset, writeset, exceptset, &lreadset, &lwriteset, &lexceptset);
donatien 0:8e01dca41002 1210 }
donatien 0:8e01dca41002 1211
donatien 0:8e01dca41002 1212 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select: nready=%d\n", nready));
donatien 0:8e01dca41002 1213 return_copy_fdsets:
donatien 0:8e01dca41002 1214 set_errno(0);
donatien 0:8e01dca41002 1215 if (readset) {
donatien 0:8e01dca41002 1216 *readset = lreadset;
donatien 0:8e01dca41002 1217 }
donatien 0:8e01dca41002 1218 if (writeset) {
donatien 0:8e01dca41002 1219 *writeset = lwriteset;
donatien 0:8e01dca41002 1220 }
donatien 0:8e01dca41002 1221 if (exceptset) {
donatien 0:8e01dca41002 1222 *exceptset = lexceptset;
donatien 0:8e01dca41002 1223 }
donatien 0:8e01dca41002 1224
donatien 0:8e01dca41002 1225
donatien 0:8e01dca41002 1226 return nready;
donatien 0:8e01dca41002 1227 }
donatien 0:8e01dca41002 1228
donatien 0:8e01dca41002 1229 /**
donatien 0:8e01dca41002 1230 * Callback registered in the netconn layer for each socket-netconn.
donatien 0:8e01dca41002 1231 * Processes recvevent (data available) and wakes up tasks waiting for select.
donatien 0:8e01dca41002 1232 */
donatien 0:8e01dca41002 1233 static void
donatien 0:8e01dca41002 1234 event_callback(struct netconn *conn, enum netconn_evt evt, u16_t len)
donatien 0:8e01dca41002 1235 {
donatien 0:8e01dca41002 1236 int s;
donatien 0:8e01dca41002 1237 struct lwip_sock *sock;
donatien 0:8e01dca41002 1238 struct lwip_select_cb *scb;
donatien 0:8e01dca41002 1239 int last_select_cb_ctr;
donatien 0:8e01dca41002 1240 SYS_ARCH_DECL_PROTECT(lev);
donatien 0:8e01dca41002 1241
donatien 0:8e01dca41002 1242 LWIP_UNUSED_ARG(len);
donatien 0:8e01dca41002 1243
donatien 0:8e01dca41002 1244 /* Get socket */
donatien 0:8e01dca41002 1245 if (conn) {
donatien 0:8e01dca41002 1246 s = conn->socket;
donatien 0:8e01dca41002 1247 if (s < 0) {
donatien 0:8e01dca41002 1248 /* Data comes in right away after an accept, even though
donatien 0:8e01dca41002 1249 * the server task might not have created a new socket yet.
donatien 0:8e01dca41002 1250 * Just count down (or up) if that's the case and we
donatien 0:8e01dca41002 1251 * will use the data later. Note that only receive events
donatien 0:8e01dca41002 1252 * can happen before the new socket is set up. */
donatien 0:8e01dca41002 1253 SYS_ARCH_PROTECT(lev);
donatien 0:8e01dca41002 1254 if (conn->socket < 0) {
donatien 0:8e01dca41002 1255 if (evt == NETCONN_EVT_RCVPLUS) {
donatien 0:8e01dca41002 1256 conn->socket--;
donatien 0:8e01dca41002 1257 }
donatien 0:8e01dca41002 1258 SYS_ARCH_UNPROTECT(lev);
donatien 0:8e01dca41002 1259 return;
donatien 0:8e01dca41002 1260 }
donatien 0:8e01dca41002 1261 s = conn->socket;
donatien 0:8e01dca41002 1262 SYS_ARCH_UNPROTECT(lev);
donatien 0:8e01dca41002 1263 }
donatien 0:8e01dca41002 1264
donatien 0:8e01dca41002 1265 sock = get_socket(s);
donatien 0:8e01dca41002 1266 if (!sock) {
donatien 0:8e01dca41002 1267 return;
donatien 0:8e01dca41002 1268 }
donatien 0:8e01dca41002 1269 } else {
donatien 0:8e01dca41002 1270 return;
donatien 0:8e01dca41002 1271 }
donatien 0:8e01dca41002 1272
donatien 0:8e01dca41002 1273 SYS_ARCH_PROTECT(lev);
donatien 0:8e01dca41002 1274 /* Set event as required */
donatien 0:8e01dca41002 1275 switch (evt) {
donatien 0:8e01dca41002 1276 case NETCONN_EVT_RCVPLUS:
donatien 0:8e01dca41002 1277 sock->rcvevent++;
donatien 0:8e01dca41002 1278 break;
donatien 0:8e01dca41002 1279 case NETCONN_EVT_RCVMINUS:
donatien 0:8e01dca41002 1280 sock->rcvevent--;
donatien 0:8e01dca41002 1281 break;
donatien 0:8e01dca41002 1282 case NETCONN_EVT_SENDPLUS:
donatien 0:8e01dca41002 1283 sock->sendevent = 1;
donatien 0:8e01dca41002 1284 break;
donatien 0:8e01dca41002 1285 case NETCONN_EVT_SENDMINUS:
donatien 0:8e01dca41002 1286 sock->sendevent = 0;
donatien 0:8e01dca41002 1287 break;
donatien 0:8e01dca41002 1288 case NETCONN_EVT_ERROR:
donatien 0:8e01dca41002 1289 sock->errevent = 1;
donatien 0:8e01dca41002 1290 break;
donatien 0:8e01dca41002 1291 default:
donatien 0:8e01dca41002 1292 LWIP_ASSERT("unknown event", 0);
donatien 0:8e01dca41002 1293 break;
donatien 0:8e01dca41002 1294 }
donatien 0:8e01dca41002 1295
donatien 0:8e01dca41002 1296 if (sock->select_waiting == 0) {
donatien 0:8e01dca41002 1297 /* noone is waiting for this socket, no need to check select_cb_list */
donatien 0:8e01dca41002 1298 SYS_ARCH_UNPROTECT(lev);
donatien 0:8e01dca41002 1299 return;
donatien 0:8e01dca41002 1300 }
donatien 0:8e01dca41002 1301
donatien 0:8e01dca41002 1302 /* Now decide if anyone is waiting for this socket */
donatien 0:8e01dca41002 1303 /* NOTE: This code goes through the select_cb_list list multiple times
donatien 0:8e01dca41002 1304 ONLY IF a select was actually waiting. We go through the list the number
donatien 0:8e01dca41002 1305 of waiting select calls + 1. This list is expected to be small. */
donatien 0:8e01dca41002 1306
donatien 0:8e01dca41002 1307 /* At this point, SYS_ARCH is still protected! */
donatien 0:8e01dca41002 1308 again:
donatien 0:8e01dca41002 1309 for (scb = select_cb_list; scb != NULL; scb = scb->next) {
donatien 0:8e01dca41002 1310 if (scb->sem_signalled == 0) {
donatien 0:8e01dca41002 1311 /* semaphore not signalled yet */
donatien 0:8e01dca41002 1312 int do_signal = 0;
donatien 0:8e01dca41002 1313 /* Test this select call for our socket */
donatien 0:8e01dca41002 1314 if (sock->rcvevent > 0) {
donatien 0:8e01dca41002 1315 if (scb->readset && FD_ISSET(s, scb->readset)) {
donatien 0:8e01dca41002 1316 do_signal = 1;
donatien 0:8e01dca41002 1317 }
donatien 0:8e01dca41002 1318 }
donatien 0:8e01dca41002 1319 if (sock->sendevent != 0) {
donatien 0:8e01dca41002 1320 if (!do_signal && scb->writeset && FD_ISSET(s, scb->writeset)) {
donatien 0:8e01dca41002 1321 do_signal = 1;
donatien 0:8e01dca41002 1322 }
donatien 0:8e01dca41002 1323 }
donatien 0:8e01dca41002 1324 if (sock->errevent != 0) {
donatien 0:8e01dca41002 1325 if (!do_signal && scb->exceptset && FD_ISSET(s, scb->exceptset)) {
donatien 0:8e01dca41002 1326 do_signal = 1;
donatien 0:8e01dca41002 1327 }
donatien 0:8e01dca41002 1328 }
donatien 0:8e01dca41002 1329 if (do_signal) {
donatien 0:8e01dca41002 1330 scb->sem_signalled = 1;
donatien 0:8e01dca41002 1331 /* Don't call SYS_ARCH_UNPROTECT() before signaling the semaphore, as this might
donatien 0:8e01dca41002 1332 lead to the select thread taking itself off the list, invalidagin the semaphore. */
donatien 0:8e01dca41002 1333 sys_sem_signal(&scb->sem);
donatien 0:8e01dca41002 1334 }
donatien 0:8e01dca41002 1335 }
donatien 0:8e01dca41002 1336 /* unlock interrupts with each step */
donatien 0:8e01dca41002 1337 last_select_cb_ctr = select_cb_ctr;
donatien 0:8e01dca41002 1338 SYS_ARCH_UNPROTECT(lev);
donatien 0:8e01dca41002 1339 /* this makes sure interrupt protection time is short */
donatien 0:8e01dca41002 1340 SYS_ARCH_PROTECT(lev);
donatien 0:8e01dca41002 1341 if (last_select_cb_ctr != select_cb_ctr) {
donatien 0:8e01dca41002 1342 /* someone has changed select_cb_list, restart at the beginning */
donatien 0:8e01dca41002 1343 goto again;
donatien 0:8e01dca41002 1344 }
donatien 0:8e01dca41002 1345 }
donatien 0:8e01dca41002 1346 SYS_ARCH_UNPROTECT(lev);
donatien 0:8e01dca41002 1347 }
donatien 0:8e01dca41002 1348
donatien 0:8e01dca41002 1349 /**
donatien 0:8e01dca41002 1350 * Unimplemented: Close one end of a full-duplex connection.
donatien 0:8e01dca41002 1351 * Currently, the full connection is closed.
donatien 0:8e01dca41002 1352 */
donatien 0:8e01dca41002 1353 int
donatien 0:8e01dca41002 1354 lwip_shutdown(int s, int how)
donatien 0:8e01dca41002 1355 {
donatien 0:8e01dca41002 1356 struct lwip_sock *sock;
donatien 0:8e01dca41002 1357 err_t err;
donatien 0:8e01dca41002 1358 u8_t shut_rx = 0, shut_tx = 0;
donatien 0:8e01dca41002 1359
donatien 0:8e01dca41002 1360 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_shutdown(%d, how=%d)\n", s, how));
donatien 0:8e01dca41002 1361
donatien 0:8e01dca41002 1362 sock = get_socket(s);
donatien 0:8e01dca41002 1363 if (!sock) {
donatien 0:8e01dca41002 1364 return -1;
donatien 0:8e01dca41002 1365 }
donatien 0:8e01dca41002 1366
donatien 0:8e01dca41002 1367 if (sock->conn != NULL) {
donatien 0:8e01dca41002 1368 if (netconn_type(sock->conn) != NETCONN_TCP) {
donatien 0:8e01dca41002 1369 sock_set_errno(sock, EOPNOTSUPP);
donatien 0:8e01dca41002 1370 return EOPNOTSUPP;
donatien 0:8e01dca41002 1371 }
donatien 0:8e01dca41002 1372 } else {
donatien 0:8e01dca41002 1373 sock_set_errno(sock, ENOTCONN);
donatien 0:8e01dca41002 1374 return ENOTCONN;
donatien 0:8e01dca41002 1375 }
donatien 0:8e01dca41002 1376
donatien 0:8e01dca41002 1377 if (how == SHUT_RD) {
donatien 0:8e01dca41002 1378 shut_rx = 1;
donatien 0:8e01dca41002 1379 } else if (how == SHUT_WR) {
donatien 0:8e01dca41002 1380 shut_tx = 1;
donatien 0:8e01dca41002 1381 } else if(how == SHUT_RDWR) {
donatien 0:8e01dca41002 1382 shut_rx = 1;
donatien 0:8e01dca41002 1383 shut_tx = 1;
donatien 0:8e01dca41002 1384 } else {
donatien 0:8e01dca41002 1385 sock_set_errno(sock, EINVAL);
donatien 0:8e01dca41002 1386 return EINVAL;
donatien 0:8e01dca41002 1387 }
donatien 0:8e01dca41002 1388 err = netconn_shutdown(sock->conn, shut_rx, shut_tx);
donatien 0:8e01dca41002 1389
donatien 0:8e01dca41002 1390 sock_set_errno(sock, err_to_errno(err));
donatien 0:8e01dca41002 1391 return (err == ERR_OK ? 0 : -1);
donatien 0:8e01dca41002 1392 }
donatien 0:8e01dca41002 1393
donatien 0:8e01dca41002 1394 static int
donatien 0:8e01dca41002 1395 lwip_getaddrname(int s, struct sockaddr *name, socklen_t *namelen, u8_t local)
donatien 0:8e01dca41002 1396 {
donatien 0:8e01dca41002 1397 struct lwip_sock *sock;
donatien 0:8e01dca41002 1398 struct sockaddr_in sin;
donatien 0:8e01dca41002 1399 ip_addr_t naddr;
donatien 0:8e01dca41002 1400
donatien 0:8e01dca41002 1401 sock = get_socket(s);
donatien 0:8e01dca41002 1402 if (!sock) {
donatien 0:8e01dca41002 1403 return -1;
donatien 0:8e01dca41002 1404 }
donatien 0:8e01dca41002 1405
donatien 0:8e01dca41002 1406 memset(&sin, 0, sizeof(sin));
donatien 0:8e01dca41002 1407 sin.sin_len = sizeof(sin);
donatien 0:8e01dca41002 1408 sin.sin_family = AF_INET;
donatien 0:8e01dca41002 1409
donatien 0:8e01dca41002 1410 /* get the IP address and port */
donatien 0:8e01dca41002 1411 netconn_getaddr(sock->conn, &naddr, &sin.sin_port, local);
donatien 0:8e01dca41002 1412
donatien 0:8e01dca41002 1413 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getaddrname(%d, addr=", s));
donatien 0:8e01dca41002 1414 ip_addr_debug_print(SOCKETS_DEBUG, &naddr);
donatien 0:8e01dca41002 1415 LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F")\n", sin.sin_port));
donatien 0:8e01dca41002 1416
donatien 0:8e01dca41002 1417 sin.sin_port = htons(sin.sin_port);
donatien 0:8e01dca41002 1418 inet_addr_from_ipaddr(&sin.sin_addr, &naddr);
donatien 0:8e01dca41002 1419
donatien 0:8e01dca41002 1420 if (*namelen > sizeof(sin)) {
donatien 0:8e01dca41002 1421 *namelen = sizeof(sin);
donatien 0:8e01dca41002 1422 }
donatien 0:8e01dca41002 1423
donatien 0:8e01dca41002 1424 MEMCPY(name, &sin, *namelen);
donatien 0:8e01dca41002 1425 sock_set_errno(sock, 0);
donatien 0:8e01dca41002 1426 return 0;
donatien 0:8e01dca41002 1427 }
donatien 0:8e01dca41002 1428
donatien 0:8e01dca41002 1429 int
donatien 0:8e01dca41002 1430 lwip_getpeername(int s, struct sockaddr *name, socklen_t *namelen)
donatien 0:8e01dca41002 1431 {
donatien 0:8e01dca41002 1432 return lwip_getaddrname(s, name, namelen, 0);
donatien 0:8e01dca41002 1433 }
donatien 0:8e01dca41002 1434
donatien 0:8e01dca41002 1435 int
donatien 0:8e01dca41002 1436 lwip_getsockname(int s, struct sockaddr *name, socklen_t *namelen)
donatien 0:8e01dca41002 1437 {
donatien 0:8e01dca41002 1438 return lwip_getaddrname(s, name, namelen, 1);
donatien 0:8e01dca41002 1439 }
donatien 0:8e01dca41002 1440
donatien 0:8e01dca41002 1441 int
donatien 0:8e01dca41002 1442 lwip_getsockopt(int s, int level, int optname, void *optval, socklen_t *optlen)
donatien 0:8e01dca41002 1443 {
donatien 0:8e01dca41002 1444 err_t err = ERR_OK;
donatien 0:8e01dca41002 1445 struct lwip_sock *sock = get_socket(s);
donatien 0:8e01dca41002 1446 struct lwip_setgetsockopt_data data;
donatien 0:8e01dca41002 1447
donatien 0:8e01dca41002 1448 if (!sock) {
donatien 0:8e01dca41002 1449 return -1;
donatien 0:8e01dca41002 1450 }
donatien 0:8e01dca41002 1451
donatien 0:8e01dca41002 1452 if ((NULL == optval) || (NULL == optlen)) {
donatien 0:8e01dca41002 1453 sock_set_errno(sock, EFAULT);
donatien 0:8e01dca41002 1454 return -1;
donatien 0:8e01dca41002 1455 }
donatien 0:8e01dca41002 1456
donatien 0:8e01dca41002 1457 /* Do length and type checks for the various options first, to keep it readable. */
donatien 0:8e01dca41002 1458 switch (level) {
donatien 0:8e01dca41002 1459
donatien 0:8e01dca41002 1460 /* Level: SOL_SOCKET */
donatien 0:8e01dca41002 1461 case SOL_SOCKET:
donatien 0:8e01dca41002 1462 switch (optname) {
donatien 0:8e01dca41002 1463
donatien 0:8e01dca41002 1464 case SO_ACCEPTCONN:
donatien 0:8e01dca41002 1465 case SO_BROADCAST:
donatien 0:8e01dca41002 1466 /* UNIMPL case SO_DEBUG: */
donatien 0:8e01dca41002 1467 /* UNIMPL case SO_DONTROUTE: */
donatien 0:8e01dca41002 1468 case SO_ERROR:
donatien 0:8e01dca41002 1469 case SO_KEEPALIVE:
donatien 0:8e01dca41002 1470 /* UNIMPL case SO_CONTIMEO: */
donatien 0:8e01dca41002 1471 /* UNIMPL case SO_SNDTIMEO: */
donatien 0:8e01dca41002 1472 #if LWIP_SO_RCVTIMEO
donatien 0:8e01dca41002 1473 case SO_RCVTIMEO:
donatien 0:8e01dca41002 1474 #endif /* LWIP_SO_RCVTIMEO */
donatien 0:8e01dca41002 1475 #if LWIP_SO_RCVBUF
donatien 0:8e01dca41002 1476 case SO_RCVBUF:
donatien 0:8e01dca41002 1477 #endif /* LWIP_SO_RCVBUF */
donatien 0:8e01dca41002 1478 /* UNIMPL case SO_OOBINLINE: */
donatien 0:8e01dca41002 1479 /* UNIMPL case SO_SNDBUF: */
donatien 0:8e01dca41002 1480 /* UNIMPL case SO_RCVLOWAT: */
donatien 0:8e01dca41002 1481 /* UNIMPL case SO_SNDLOWAT: */
donatien 0:8e01dca41002 1482 #if SO_REUSE
donatien 0:8e01dca41002 1483 case SO_REUSEADDR:
donatien 0:8e01dca41002 1484 case SO_REUSEPORT:
donatien 0:8e01dca41002 1485 #endif /* SO_REUSE */
donatien 0:8e01dca41002 1486 case SO_TYPE:
donatien 0:8e01dca41002 1487 /* UNIMPL case SO_USELOOPBACK: */
donatien 0:8e01dca41002 1488 if (*optlen < sizeof(int)) {
donatien 0:8e01dca41002 1489 err = EINVAL;
donatien 0:8e01dca41002 1490 }
donatien 0:8e01dca41002 1491 break;
donatien 0:8e01dca41002 1492
donatien 0:8e01dca41002 1493 case SO_NO_CHECK:
donatien 0:8e01dca41002 1494 if (*optlen < sizeof(int)) {
donatien 0:8e01dca41002 1495 err = EINVAL;
donatien 0:8e01dca41002 1496 }
donatien 0:8e01dca41002 1497 #if LWIP_UDP
donatien 0:8e01dca41002 1498 if ((sock->conn->type != NETCONN_UDP) ||
donatien 0:8e01dca41002 1499 ((udp_flags(sock->conn->pcb.udp) & UDP_FLAGS_UDPLITE) != 0)) {
donatien 0:8e01dca41002 1500 /* this flag is only available for UDP, not for UDP lite */
donatien 0:8e01dca41002 1501 err = EAFNOSUPPORT;
donatien 0:8e01dca41002 1502 }
donatien 0:8e01dca41002 1503 #endif /* LWIP_UDP */
donatien 0:8e01dca41002 1504 break;
donatien 0:8e01dca41002 1505
donatien 0:8e01dca41002 1506 default:
donatien 0:8e01dca41002 1507 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, UNIMPL: optname=0x%x, ..)\n",
donatien 0:8e01dca41002 1508 s, optname));
donatien 0:8e01dca41002 1509 err = ENOPROTOOPT;
donatien 0:8e01dca41002 1510 } /* switch (optname) */
donatien 0:8e01dca41002 1511 break;
donatien 0:8e01dca41002 1512
donatien 0:8e01dca41002 1513 /* Level: IPPROTO_IP */
donatien 0:8e01dca41002 1514 case IPPROTO_IP:
donatien 0:8e01dca41002 1515 switch (optname) {
donatien 0:8e01dca41002 1516 /* UNIMPL case IP_HDRINCL: */
donatien 0:8e01dca41002 1517 /* UNIMPL case IP_RCVDSTADDR: */
donatien 0:8e01dca41002 1518 /* UNIMPL case IP_RCVIF: */
donatien 0:8e01dca41002 1519 case IP_TTL:
donatien 0:8e01dca41002 1520 case IP_TOS:
donatien 0:8e01dca41002 1521 if (*optlen < sizeof(int)) {
donatien 0:8e01dca41002 1522 err = EINVAL;
donatien 0:8e01dca41002 1523 }
donatien 0:8e01dca41002 1524 break;
donatien 0:8e01dca41002 1525 #if LWIP_IGMP
donatien 0:8e01dca41002 1526 case IP_MULTICAST_TTL:
donatien 0:8e01dca41002 1527 if (*optlen < sizeof(u8_t)) {
donatien 0:8e01dca41002 1528 err = EINVAL;
donatien 0:8e01dca41002 1529 }
donatien 0:8e01dca41002 1530 break;
donatien 0:8e01dca41002 1531 case IP_MULTICAST_IF:
donatien 0:8e01dca41002 1532 if (*optlen < sizeof(struct in_addr)) {
donatien 0:8e01dca41002 1533 err = EINVAL;
donatien 0:8e01dca41002 1534 }
donatien 0:8e01dca41002 1535 break;
donatien 0:8e01dca41002 1536 case IP_MULTICAST_LOOP:
donatien 0:8e01dca41002 1537 if (*optlen < sizeof(u8_t)) {
donatien 0:8e01dca41002 1538 err = EINVAL;
donatien 0:8e01dca41002 1539 }
donatien 0:8e01dca41002 1540 if (NETCONNTYPE_GROUP(sock->conn->type) != NETCONN_UDP) {
donatien 0:8e01dca41002 1541 err = EAFNOSUPPORT;
donatien 0:8e01dca41002 1542 }
donatien 0:8e01dca41002 1543 break;
donatien 0:8e01dca41002 1544 #endif /* LWIP_IGMP */
donatien 0:8e01dca41002 1545
donatien 0:8e01dca41002 1546 default:
donatien 0:8e01dca41002 1547 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, UNIMPL: optname=0x%x, ..)\n",
donatien 0:8e01dca41002 1548 s, optname));
donatien 0:8e01dca41002 1549 err = ENOPROTOOPT;
donatien 0:8e01dca41002 1550 } /* switch (optname) */
donatien 0:8e01dca41002 1551 break;
donatien 0:8e01dca41002 1552
donatien 0:8e01dca41002 1553 #if LWIP_TCP
donatien 0:8e01dca41002 1554 /* Level: IPPROTO_TCP */
donatien 0:8e01dca41002 1555 case IPPROTO_TCP:
donatien 0:8e01dca41002 1556 if (*optlen < sizeof(int)) {
donatien 0:8e01dca41002 1557 err = EINVAL;
donatien 0:8e01dca41002 1558 break;
donatien 0:8e01dca41002 1559 }
donatien 0:8e01dca41002 1560
donatien 0:8e01dca41002 1561 /* If this is no TCP socket, ignore any options. */
donatien 0:8e01dca41002 1562 if (sock->conn->type != NETCONN_TCP)
donatien 0:8e01dca41002 1563 return 0;
donatien 0:8e01dca41002 1564
donatien 0:8e01dca41002 1565 switch (optname) {
donatien 0:8e01dca41002 1566 case TCP_NODELAY:
donatien 0:8e01dca41002 1567 case TCP_KEEPALIVE:
donatien 0:8e01dca41002 1568 #if LWIP_TCP_KEEPALIVE
donatien 0:8e01dca41002 1569 case TCP_KEEPIDLE:
donatien 0:8e01dca41002 1570 case TCP_KEEPINTVL:
donatien 0:8e01dca41002 1571 case TCP_KEEPCNT:
donatien 0:8e01dca41002 1572 #endif /* LWIP_TCP_KEEPALIVE */
donatien 0:8e01dca41002 1573 break;
donatien 0:8e01dca41002 1574
donatien 0:8e01dca41002 1575 default:
donatien 0:8e01dca41002 1576 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_TCP, UNIMPL: optname=0x%x, ..)\n",
donatien 0:8e01dca41002 1577 s, optname));
donatien 0:8e01dca41002 1578 err = ENOPROTOOPT;
donatien 0:8e01dca41002 1579 } /* switch (optname) */
donatien 0:8e01dca41002 1580 break;
donatien 0:8e01dca41002 1581 #endif /* LWIP_TCP */
donatien 0:8e01dca41002 1582 #if LWIP_UDP && LWIP_UDPLITE
donatien 0:8e01dca41002 1583 /* Level: IPPROTO_UDPLITE */
donatien 0:8e01dca41002 1584 case IPPROTO_UDPLITE:
donatien 0:8e01dca41002 1585 if (*optlen < sizeof(int)) {
donatien 0:8e01dca41002 1586 err = EINVAL;
donatien 0:8e01dca41002 1587 break;
donatien 0:8e01dca41002 1588 }
donatien 0:8e01dca41002 1589
donatien 0:8e01dca41002 1590 /* If this is no UDP lite socket, ignore any options. */
donatien 0:8e01dca41002 1591 if (sock->conn->type != NETCONN_UDPLITE) {
donatien 0:8e01dca41002 1592 return 0;
donatien 0:8e01dca41002 1593 }
donatien 0:8e01dca41002 1594
donatien 0:8e01dca41002 1595 switch (optname) {
donatien 0:8e01dca41002 1596 case UDPLITE_SEND_CSCOV:
donatien 0:8e01dca41002 1597 case UDPLITE_RECV_CSCOV:
donatien 0:8e01dca41002 1598 break;
donatien 0:8e01dca41002 1599
donatien 0:8e01dca41002 1600 default:
donatien 0:8e01dca41002 1601 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_UDPLITE, UNIMPL: optname=0x%x, ..)\n",
donatien 0:8e01dca41002 1602 s, optname));
donatien 0:8e01dca41002 1603 err = ENOPROTOOPT;
donatien 0:8e01dca41002 1604 } /* switch (optname) */
donatien 0:8e01dca41002 1605 break;
donatien 0:8e01dca41002 1606 #endif /* LWIP_UDP && LWIP_UDPLITE*/
donatien 0:8e01dca41002 1607 /* UNDEFINED LEVEL */
donatien 0:8e01dca41002 1608 default:
donatien 0:8e01dca41002 1609 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, level=0x%x, UNIMPL: optname=0x%x, ..)\n",
donatien 0:8e01dca41002 1610 s, level, optname));
donatien 0:8e01dca41002 1611 err = ENOPROTOOPT;
donatien 0:8e01dca41002 1612 } /* switch */
donatien 0:8e01dca41002 1613
donatien 0:8e01dca41002 1614
donatien 0:8e01dca41002 1615 if (err != ERR_OK) {
donatien 0:8e01dca41002 1616 sock_set_errno(sock, err);
donatien 0:8e01dca41002 1617 return -1;
donatien 0:8e01dca41002 1618 }
donatien 0:8e01dca41002 1619
donatien 0:8e01dca41002 1620 /* Now do the actual option processing */
donatien 0:8e01dca41002 1621 data.sock = sock;
donatien 0:8e01dca41002 1622 #ifdef LWIP_DEBUG
donatien 0:8e01dca41002 1623 data.s = s;
donatien 0:8e01dca41002 1624 #endif /* LWIP_DEBUG */
donatien 0:8e01dca41002 1625 data.level = level;
donatien 0:8e01dca41002 1626 data.optname = optname;
donatien 0:8e01dca41002 1627 data.optval = optval;
donatien 0:8e01dca41002 1628 data.optlen = optlen;
donatien 0:8e01dca41002 1629 data.err = err;
donatien 0:8e01dca41002 1630 tcpip_callback(lwip_getsockopt_internal, &data);
donatien 0:8e01dca41002 1631 sys_arch_sem_wait(&sock->conn->op_completed, 0);
donatien 0:8e01dca41002 1632 /* maybe lwip_getsockopt_internal has changed err */
donatien 0:8e01dca41002 1633 err = data.err;
donatien 0:8e01dca41002 1634
donatien 0:8e01dca41002 1635 sock_set_errno(sock, err);
donatien 0:8e01dca41002 1636 return err ? -1 : 0;
donatien 0:8e01dca41002 1637 }
donatien 0:8e01dca41002 1638
donatien 0:8e01dca41002 1639 static void
donatien 0:8e01dca41002 1640 lwip_getsockopt_internal(void *arg)
donatien 0:8e01dca41002 1641 {
donatien 0:8e01dca41002 1642 struct lwip_sock *sock;
donatien 0:8e01dca41002 1643 #ifdef LWIP_DEBUG
donatien 0:8e01dca41002 1644 int s;
donatien 0:8e01dca41002 1645 #endif /* LWIP_DEBUG */
donatien 0:8e01dca41002 1646 int level, optname;
donatien 0:8e01dca41002 1647 void *optval;
donatien 0:8e01dca41002 1648 struct lwip_setgetsockopt_data *data;
donatien 0:8e01dca41002 1649
donatien 0:8e01dca41002 1650 LWIP_ASSERT("arg != NULL", arg != NULL);
donatien 0:8e01dca41002 1651
donatien 0:8e01dca41002 1652 data = (struct lwip_setgetsockopt_data*)arg;
donatien 0:8e01dca41002 1653 sock = data->sock;
donatien 0:8e01dca41002 1654 #ifdef LWIP_DEBUG
donatien 0:8e01dca41002 1655 s = data->s;
donatien 0:8e01dca41002 1656 #endif /* LWIP_DEBUG */
donatien 0:8e01dca41002 1657 level = data->level;
donatien 0:8e01dca41002 1658 optname = data->optname;
donatien 0:8e01dca41002 1659 optval = data->optval;
donatien 0:8e01dca41002 1660
donatien 0:8e01dca41002 1661 switch (level) {
donatien 0:8e01dca41002 1662
donatien 0:8e01dca41002 1663 /* Level: SOL_SOCKET */
donatien 0:8e01dca41002 1664 case SOL_SOCKET:
donatien 0:8e01dca41002 1665 switch (optname) {
donatien 0:8e01dca41002 1666
donatien 0:8e01dca41002 1667 /* The option flags */
donatien 0:8e01dca41002 1668 case SO_ACCEPTCONN:
donatien 0:8e01dca41002 1669 case SO_BROADCAST:
donatien 0:8e01dca41002 1670 /* UNIMPL case SO_DEBUG: */
donatien 0:8e01dca41002 1671 /* UNIMPL case SO_DONTROUTE: */
donatien 0:8e01dca41002 1672 case SO_KEEPALIVE:
donatien 0:8e01dca41002 1673 /* UNIMPL case SO_OOBINCLUDE: */
donatien 0:8e01dca41002 1674 #if SO_REUSE
donatien 0:8e01dca41002 1675 case SO_REUSEADDR:
donatien 0:8e01dca41002 1676 case SO_REUSEPORT:
donatien 0:8e01dca41002 1677 #endif /* SO_REUSE */
donatien 0:8e01dca41002 1678 /*case SO_USELOOPBACK: UNIMPL */
donatien 0:8e01dca41002 1679 *(int*)optval = sock->conn->pcb.ip->so_options & optname;
donatien 0:8e01dca41002 1680 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, optname=0x%x, ..) = %s\n",
donatien 0:8e01dca41002 1681 s, optname, (*(int*)optval?"on":"off")));
donatien 0:8e01dca41002 1682 break;
donatien 0:8e01dca41002 1683
donatien 0:8e01dca41002 1684 case SO_TYPE:
donatien 0:8e01dca41002 1685 switch (NETCONNTYPE_GROUP(sock->conn->type)) {
donatien 0:8e01dca41002 1686 case NETCONN_RAW:
donatien 0:8e01dca41002 1687 *(int*)optval = SOCK_RAW;
donatien 0:8e01dca41002 1688 break;
donatien 0:8e01dca41002 1689 case NETCONN_TCP:
donatien 0:8e01dca41002 1690 *(int*)optval = SOCK_STREAM;
donatien 0:8e01dca41002 1691 break;
donatien 0:8e01dca41002 1692 case NETCONN_UDP:
donatien 0:8e01dca41002 1693 *(int*)optval = SOCK_DGRAM;
donatien 0:8e01dca41002 1694 break;
donatien 0:8e01dca41002 1695 default: /* unrecognized socket type */
donatien 0:8e01dca41002 1696 *(int*)optval = sock->conn->type;
donatien 0:8e01dca41002 1697 LWIP_DEBUGF(SOCKETS_DEBUG,
donatien 0:8e01dca41002 1698 ("lwip_getsockopt(%d, SOL_SOCKET, SO_TYPE): unrecognized socket type %d\n",
donatien 0:8e01dca41002 1699 s, *(int *)optval));
donatien 0:8e01dca41002 1700 } /* switch (sock->conn->type) */
donatien 0:8e01dca41002 1701 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, SO_TYPE) = %d\n",
donatien 0:8e01dca41002 1702 s, *(int *)optval));
donatien 0:8e01dca41002 1703 break;
donatien 0:8e01dca41002 1704
donatien 0:8e01dca41002 1705 case SO_ERROR:
donatien 0:8e01dca41002 1706 /* only overwrite ERR_OK or tempoary errors */
donatien 0:8e01dca41002 1707 if ((sock->err == 0) || (sock->err == EINPROGRESS)) {
donatien 0:8e01dca41002 1708 sock_set_errno(sock, err_to_errno(sock->conn->last_err));
donatien 0:8e01dca41002 1709 }
donatien 0:8e01dca41002 1710 *(int *)optval = sock->err;
donatien 0:8e01dca41002 1711 sock->err = 0;
donatien 0:8e01dca41002 1712 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, SO_ERROR) = %d\n",
donatien 0:8e01dca41002 1713 s, *(int *)optval));
donatien 0:8e01dca41002 1714 break;
donatien 0:8e01dca41002 1715
donatien 0:8e01dca41002 1716 #if LWIP_SO_RCVTIMEO
donatien 0:8e01dca41002 1717 case SO_RCVTIMEO:
donatien 0:8e01dca41002 1718 *(int *)optval = netconn_get_recvtimeout(sock->conn);
donatien 0:8e01dca41002 1719 break;
donatien 0:8e01dca41002 1720 #endif /* LWIP_SO_RCVTIMEO */
donatien 0:8e01dca41002 1721 #if LWIP_SO_RCVBUF
donatien 0:8e01dca41002 1722 case SO_RCVBUF:
donatien 0:8e01dca41002 1723 *(int *)optval = netconn_get_recvbufsize(sock->conn);
donatien 0:8e01dca41002 1724 break;
donatien 0:8e01dca41002 1725 #endif /* LWIP_SO_RCVBUF */
donatien 0:8e01dca41002 1726 #if LWIP_UDP
donatien 0:8e01dca41002 1727 case SO_NO_CHECK:
donatien 0:8e01dca41002 1728 *(int*)optval = (udp_flags(sock->conn->pcb.udp) & UDP_FLAGS_NOCHKSUM) ? 1 : 0;
donatien 0:8e01dca41002 1729 break;
donatien 0:8e01dca41002 1730 #endif /* LWIP_UDP*/
donatien 0:8e01dca41002 1731 default:
donatien 0:8e01dca41002 1732 LWIP_ASSERT("unhandled optname", 0);
donatien 0:8e01dca41002 1733 break;
donatien 0:8e01dca41002 1734 } /* switch (optname) */
donatien 0:8e01dca41002 1735 break;
donatien 0:8e01dca41002 1736
donatien 0:8e01dca41002 1737 /* Level: IPPROTO_IP */
donatien 0:8e01dca41002 1738 case IPPROTO_IP:
donatien 0:8e01dca41002 1739 switch (optname) {
donatien 0:8e01dca41002 1740 case IP_TTL:
donatien 0:8e01dca41002 1741 *(int*)optval = sock->conn->pcb.ip->ttl;
donatien 0:8e01dca41002 1742 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_TTL) = %d\n",
donatien 0:8e01dca41002 1743 s, *(int *)optval));
donatien 0:8e01dca41002 1744 break;
donatien 0:8e01dca41002 1745 case IP_TOS:
donatien 0:8e01dca41002 1746 *(int*)optval = sock->conn->pcb.ip->tos;
donatien 0:8e01dca41002 1747 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_TOS) = %d\n",
donatien 0:8e01dca41002 1748 s, *(int *)optval));
donatien 0:8e01dca41002 1749 break;
donatien 0:8e01dca41002 1750 #if LWIP_IGMP
donatien 0:8e01dca41002 1751 case IP_MULTICAST_TTL:
donatien 0:8e01dca41002 1752 *(u8_t*)optval = sock->conn->pcb.ip->ttl;
donatien 0:8e01dca41002 1753 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_MULTICAST_TTL) = %d\n",
donatien 0:8e01dca41002 1754 s, *(int *)optval));
donatien 0:8e01dca41002 1755 break;
donatien 0:8e01dca41002 1756 case IP_MULTICAST_IF:
donatien 0:8e01dca41002 1757 inet_addr_from_ipaddr((struct in_addr*)optval, &sock->conn->pcb.udp->multicast_ip);
donatien 0:8e01dca41002 1758 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_MULTICAST_IF) = 0x%"X32_F"\n",
donatien 0:8e01dca41002 1759 s, *(u32_t *)optval));
donatien 0:8e01dca41002 1760 break;
donatien 0:8e01dca41002 1761 case IP_MULTICAST_LOOP:
donatien 0:8e01dca41002 1762 if ((sock->conn->pcb.udp->flags & UDP_FLAGS_MULTICAST_LOOP) != 0) {
donatien 0:8e01dca41002 1763 *(u8_t*)optval = 1;
donatien 0:8e01dca41002 1764 } else {
donatien 0:8e01dca41002 1765 *(u8_t*)optval = 0;
donatien 0:8e01dca41002 1766 }
donatien 0:8e01dca41002 1767 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_MULTICAST_LOOP) = %d\n",
donatien 0:8e01dca41002 1768 s, *(int *)optval));
donatien 0:8e01dca41002 1769 break;
donatien 0:8e01dca41002 1770 #endif /* LWIP_IGMP */
donatien 0:8e01dca41002 1771 default:
donatien 0:8e01dca41002 1772 LWIP_ASSERT("unhandled optname", 0);
donatien 0:8e01dca41002 1773 break;
donatien 0:8e01dca41002 1774 } /* switch (optname) */
donatien 0:8e01dca41002 1775 break;
donatien 0:8e01dca41002 1776
donatien 0:8e01dca41002 1777 #if LWIP_TCP
donatien 0:8e01dca41002 1778 /* Level: IPPROTO_TCP */
donatien 0:8e01dca41002 1779 case IPPROTO_TCP:
donatien 0:8e01dca41002 1780 switch (optname) {
donatien 0:8e01dca41002 1781 case TCP_NODELAY:
donatien 0:8e01dca41002 1782 *(int*)optval = tcp_nagle_disabled(sock->conn->pcb.tcp);
donatien 0:8e01dca41002 1783 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_TCP, TCP_NODELAY) = %s\n",
donatien 0:8e01dca41002 1784 s, (*(int*)optval)?"on":"off") );
donatien 0:8e01dca41002 1785 break;
donatien 0:8e01dca41002 1786 case TCP_KEEPALIVE:
donatien 0:8e01dca41002 1787 *(int*)optval = (int)sock->conn->pcb.tcp->keep_idle;
donatien 0:8e01dca41002 1788 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, TCP_KEEPALIVE) = %d\n",
donatien 0:8e01dca41002 1789 s, *(int *)optval));
donatien 0:8e01dca41002 1790 break;
donatien 0:8e01dca41002 1791
donatien 0:8e01dca41002 1792 #if LWIP_TCP_KEEPALIVE
donatien 0:8e01dca41002 1793 case TCP_KEEPIDLE:
donatien 0:8e01dca41002 1794 *(int*)optval = (int)(sock->conn->pcb.tcp->keep_idle/1000);
donatien 0:8e01dca41002 1795 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, TCP_KEEPIDLE) = %d\n",
donatien 0:8e01dca41002 1796 s, *(int *)optval));
donatien 0:8e01dca41002 1797 break;
donatien 0:8e01dca41002 1798 case TCP_KEEPINTVL:
donatien 0:8e01dca41002 1799 *(int*)optval = (int)(sock->conn->pcb.tcp->keep_intvl/1000);
donatien 0:8e01dca41002 1800 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, TCP_KEEPINTVL) = %d\n",
donatien 0:8e01dca41002 1801 s, *(int *)optval));
donatien 0:8e01dca41002 1802 break;
donatien 0:8e01dca41002 1803 case TCP_KEEPCNT:
donatien 0:8e01dca41002 1804 *(int*)optval = (int)sock->conn->pcb.tcp->keep_cnt;
donatien 0:8e01dca41002 1805 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, TCP_KEEPCNT) = %d\n",
donatien 0:8e01dca41002 1806 s, *(int *)optval));
donatien 0:8e01dca41002 1807 break;
donatien 0:8e01dca41002 1808 #endif /* LWIP_TCP_KEEPALIVE */
donatien 0:8e01dca41002 1809 default:
donatien 0:8e01dca41002 1810 LWIP_ASSERT("unhandled optname", 0);
donatien 0:8e01dca41002 1811 break;
donatien 0:8e01dca41002 1812 } /* switch (optname) */
donatien 0:8e01dca41002 1813 break;
donatien 0:8e01dca41002 1814 #endif /* LWIP_TCP */
donatien 0:8e01dca41002 1815 #if LWIP_UDP && LWIP_UDPLITE
donatien 0:8e01dca41002 1816 /* Level: IPPROTO_UDPLITE */
donatien 0:8e01dca41002 1817 case IPPROTO_UDPLITE:
donatien 0:8e01dca41002 1818 switch (optname) {
donatien 0:8e01dca41002 1819 case UDPLITE_SEND_CSCOV:
donatien 0:8e01dca41002 1820 *(int*)optval = sock->conn->pcb.udp->chksum_len_tx;
donatien 0:8e01dca41002 1821 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_UDPLITE, UDPLITE_SEND_CSCOV) = %d\n",
donatien 0:8e01dca41002 1822 s, (*(int*)optval)) );
donatien 0:8e01dca41002 1823 break;
donatien 0:8e01dca41002 1824 case UDPLITE_RECV_CSCOV:
donatien 0:8e01dca41002 1825 *(int*)optval = sock->conn->pcb.udp->chksum_len_rx;
donatien 0:8e01dca41002 1826 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_UDPLITE, UDPLITE_RECV_CSCOV) = %d\n",
donatien 0:8e01dca41002 1827 s, (*(int*)optval)) );
donatien 0:8e01dca41002 1828 break;
donatien 0:8e01dca41002 1829 default:
donatien 0:8e01dca41002 1830 LWIP_ASSERT("unhandled optname", 0);
donatien 0:8e01dca41002 1831 break;
donatien 0:8e01dca41002 1832 } /* switch (optname) */
donatien 0:8e01dca41002 1833 break;
donatien 0:8e01dca41002 1834 #endif /* LWIP_UDP */
donatien 0:8e01dca41002 1835 default:
donatien 0:8e01dca41002 1836 LWIP_ASSERT("unhandled level", 0);
donatien 0:8e01dca41002 1837 break;
donatien 0:8e01dca41002 1838 } /* switch (level) */
donatien 0:8e01dca41002 1839 sys_sem_signal(&sock->conn->op_completed);
donatien 0:8e01dca41002 1840 }
donatien 0:8e01dca41002 1841
donatien 0:8e01dca41002 1842 int
donatien 0:8e01dca41002 1843 lwip_setsockopt(int s, int level, int optname, const void *optval, socklen_t optlen)
donatien 0:8e01dca41002 1844 {
donatien 0:8e01dca41002 1845 struct lwip_sock *sock = get_socket(s);
donatien 0:8e01dca41002 1846 err_t err = ERR_OK;
donatien 0:8e01dca41002 1847 struct lwip_setgetsockopt_data data;
donatien 0:8e01dca41002 1848
donatien 0:8e01dca41002 1849 if (!sock) {
donatien 0:8e01dca41002 1850 return -1;
donatien 0:8e01dca41002 1851 }
donatien 0:8e01dca41002 1852
donatien 0:8e01dca41002 1853 if (NULL == optval) {
donatien 0:8e01dca41002 1854 sock_set_errno(sock, EFAULT);
donatien 0:8e01dca41002 1855 return -1;
donatien 0:8e01dca41002 1856 }
donatien 0:8e01dca41002 1857
donatien 0:8e01dca41002 1858 /* Do length and type checks for the various options first, to keep it readable. */
donatien 0:8e01dca41002 1859 switch (level) {
donatien 0:8e01dca41002 1860
donatien 0:8e01dca41002 1861 /* Level: SOL_SOCKET */
donatien 0:8e01dca41002 1862 case SOL_SOCKET:
donatien 0:8e01dca41002 1863 switch (optname) {
donatien 0:8e01dca41002 1864
donatien 0:8e01dca41002 1865 case SO_BROADCAST:
donatien 0:8e01dca41002 1866 /* UNIMPL case SO_DEBUG: */
donatien 0:8e01dca41002 1867 /* UNIMPL case SO_DONTROUTE: */
donatien 0:8e01dca41002 1868 case SO_KEEPALIVE:
donatien 0:8e01dca41002 1869 /* UNIMPL case case SO_CONTIMEO: */
donatien 0:8e01dca41002 1870 /* UNIMPL case case SO_SNDTIMEO: */
donatien 0:8e01dca41002 1871 #if LWIP_SO_RCVTIMEO
donatien 0:8e01dca41002 1872 case SO_RCVTIMEO:
donatien 0:8e01dca41002 1873 #endif /* LWIP_SO_RCVTIMEO */
donatien 0:8e01dca41002 1874 #if LWIP_SO_RCVBUF
donatien 0:8e01dca41002 1875 case SO_RCVBUF:
donatien 0:8e01dca41002 1876 #endif /* LWIP_SO_RCVBUF */
donatien 0:8e01dca41002 1877 /* UNIMPL case SO_OOBINLINE: */
donatien 0:8e01dca41002 1878 /* UNIMPL case SO_SNDBUF: */
donatien 0:8e01dca41002 1879 /* UNIMPL case SO_RCVLOWAT: */
donatien 0:8e01dca41002 1880 /* UNIMPL case SO_SNDLOWAT: */
donatien 0:8e01dca41002 1881 #if SO_REUSE
donatien 0:8e01dca41002 1882 case SO_REUSEADDR:
donatien 0:8e01dca41002 1883 case SO_REUSEPORT:
donatien 0:8e01dca41002 1884 #endif /* SO_REUSE */
donatien 0:8e01dca41002 1885 /* UNIMPL case SO_USELOOPBACK: */
donatien 0:8e01dca41002 1886 if (optlen < sizeof(int)) {
donatien 0:8e01dca41002 1887 err = EINVAL;
donatien 0:8e01dca41002 1888 }
donatien 0:8e01dca41002 1889 break;
donatien 0:8e01dca41002 1890 case SO_NO_CHECK:
donatien 0:8e01dca41002 1891 if (optlen < sizeof(int)) {
donatien 0:8e01dca41002 1892 err = EINVAL;
donatien 0:8e01dca41002 1893 }
donatien 0:8e01dca41002 1894 #if LWIP_UDP
donatien 0:8e01dca41002 1895 if ((sock->conn->type != NETCONN_UDP) ||
donatien 0:8e01dca41002 1896 ((udp_flags(sock->conn->pcb.udp) & UDP_FLAGS_UDPLITE) != 0)) {
donatien 0:8e01dca41002 1897 /* this flag is only available for UDP, not for UDP lite */
donatien 0:8e01dca41002 1898 err = EAFNOSUPPORT;
donatien 0:8e01dca41002 1899 }
donatien 0:8e01dca41002 1900 #endif /* LWIP_UDP */
donatien 0:8e01dca41002 1901 break;
donatien 0:8e01dca41002 1902 default:
donatien 0:8e01dca41002 1903 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, SOL_SOCKET, UNIMPL: optname=0x%x, ..)\n",
donatien 0:8e01dca41002 1904 s, optname));
donatien 0:8e01dca41002 1905 err = ENOPROTOOPT;
donatien 0:8e01dca41002 1906 } /* switch (optname) */
donatien 0:8e01dca41002 1907 break;
donatien 0:8e01dca41002 1908
donatien 0:8e01dca41002 1909 /* Level: IPPROTO_IP */
donatien 0:8e01dca41002 1910 case IPPROTO_IP:
donatien 0:8e01dca41002 1911 switch (optname) {
donatien 0:8e01dca41002 1912 /* UNIMPL case IP_HDRINCL: */
donatien 0:8e01dca41002 1913 /* UNIMPL case IP_RCVDSTADDR: */
donatien 0:8e01dca41002 1914 /* UNIMPL case IP_RCVIF: */
donatien 0:8e01dca41002 1915 case IP_TTL:
donatien 0:8e01dca41002 1916 case IP_TOS:
donatien 0:8e01dca41002 1917 if (optlen < sizeof(int)) {
donatien 0:8e01dca41002 1918 err = EINVAL;
donatien 0:8e01dca41002 1919 }
donatien 0:8e01dca41002 1920 break;
donatien 0:8e01dca41002 1921 #if LWIP_IGMP
donatien 0:8e01dca41002 1922 case IP_MULTICAST_TTL:
donatien 0:8e01dca41002 1923 if (optlen < sizeof(u8_t)) {
donatien 0:8e01dca41002 1924 err = EINVAL;
donatien 0:8e01dca41002 1925 }
donatien 0:8e01dca41002 1926 if (NETCONNTYPE_GROUP(sock->conn->type) != NETCONN_UDP) {
donatien 0:8e01dca41002 1927 err = EAFNOSUPPORT;
donatien 0:8e01dca41002 1928 }
donatien 0:8e01dca41002 1929 break;
donatien 0:8e01dca41002 1930 case IP_MULTICAST_IF:
donatien 0:8e01dca41002 1931 if (optlen < sizeof(struct in_addr)) {
donatien 0:8e01dca41002 1932 err = EINVAL;
donatien 0:8e01dca41002 1933 }
donatien 0:8e01dca41002 1934 if (NETCONNTYPE_GROUP(sock->conn->type) != NETCONN_UDP) {
donatien 0:8e01dca41002 1935 err = EAFNOSUPPORT;
donatien 0:8e01dca41002 1936 }
donatien 0:8e01dca41002 1937 break;
donatien 0:8e01dca41002 1938 case IP_MULTICAST_LOOP:
donatien 0:8e01dca41002 1939 if (optlen < sizeof(u8_t)) {
donatien 0:8e01dca41002 1940 err = EINVAL;
donatien 0:8e01dca41002 1941 }
donatien 0:8e01dca41002 1942 if (NETCONNTYPE_GROUP(sock->conn->type) != NETCONN_UDP) {
donatien 0:8e01dca41002 1943 err = EAFNOSUPPORT;
donatien 0:8e01dca41002 1944 }
donatien 0:8e01dca41002 1945 break;
donatien 0:8e01dca41002 1946 case IP_ADD_MEMBERSHIP:
donatien 0:8e01dca41002 1947 case IP_DROP_MEMBERSHIP:
donatien 0:8e01dca41002 1948 if (optlen < sizeof(struct ip_mreq)) {
donatien 0:8e01dca41002 1949 err = EINVAL;
donatien 0:8e01dca41002 1950 }
donatien 0:8e01dca41002 1951 if (NETCONNTYPE_GROUP(sock->conn->type) != NETCONN_UDP) {
donatien 0:8e01dca41002 1952 err = EAFNOSUPPORT;
donatien 0:8e01dca41002 1953 }
donatien 0:8e01dca41002 1954 break;
donatien 0:8e01dca41002 1955 #endif /* LWIP_IGMP */
donatien 0:8e01dca41002 1956 default:
donatien 0:8e01dca41002 1957 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IP, UNIMPL: optname=0x%x, ..)\n",
donatien 0:8e01dca41002 1958 s, optname));
donatien 0:8e01dca41002 1959 err = ENOPROTOOPT;
donatien 0:8e01dca41002 1960 } /* switch (optname) */
donatien 0:8e01dca41002 1961 break;
donatien 0:8e01dca41002 1962
donatien 0:8e01dca41002 1963 #if LWIP_TCP
donatien 0:8e01dca41002 1964 /* Level: IPPROTO_TCP */
donatien 0:8e01dca41002 1965 case IPPROTO_TCP:
donatien 0:8e01dca41002 1966 if (optlen < sizeof(int)) {
donatien 0:8e01dca41002 1967 err = EINVAL;
donatien 0:8e01dca41002 1968 break;
donatien 0:8e01dca41002 1969 }
donatien 0:8e01dca41002 1970
donatien 0:8e01dca41002 1971 /* If this is no TCP socket, ignore any options. */
donatien 0:8e01dca41002 1972 if (sock->conn->type != NETCONN_TCP)
donatien 0:8e01dca41002 1973 return 0;
donatien 0:8e01dca41002 1974
donatien 0:8e01dca41002 1975 switch (optname) {
donatien 0:8e01dca41002 1976 case TCP_NODELAY:
donatien 0:8e01dca41002 1977 case TCP_KEEPALIVE:
donatien 0:8e01dca41002 1978 #if LWIP_TCP_KEEPALIVE
donatien 0:8e01dca41002 1979 case TCP_KEEPIDLE:
donatien 0:8e01dca41002 1980 case TCP_KEEPINTVL:
donatien 0:8e01dca41002 1981 case TCP_KEEPCNT:
donatien 0:8e01dca41002 1982 #endif /* LWIP_TCP_KEEPALIVE */
donatien 0:8e01dca41002 1983 break;
donatien 0:8e01dca41002 1984
donatien 0:8e01dca41002 1985 default:
donatien 0:8e01dca41002 1986 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, UNIMPL: optname=0x%x, ..)\n",
donatien 0:8e01dca41002 1987 s, optname));
donatien 0:8e01dca41002 1988 err = ENOPROTOOPT;
donatien 0:8e01dca41002 1989 } /* switch (optname) */
donatien 0:8e01dca41002 1990 break;
donatien 0:8e01dca41002 1991 #endif /* LWIP_TCP */
donatien 0:8e01dca41002 1992 #if LWIP_UDP && LWIP_UDPLITE
donatien 0:8e01dca41002 1993 /* Level: IPPROTO_UDPLITE */
donatien 0:8e01dca41002 1994 case IPPROTO_UDPLITE:
donatien 0:8e01dca41002 1995 if (optlen < sizeof(int)) {
donatien 0:8e01dca41002 1996 err = EINVAL;
donatien 0:8e01dca41002 1997 break;
donatien 0:8e01dca41002 1998 }
donatien 0:8e01dca41002 1999
donatien 0:8e01dca41002 2000 /* If this is no UDP lite socket, ignore any options. */
donatien 0:8e01dca41002 2001 if (sock->conn->type != NETCONN_UDPLITE)
donatien 0:8e01dca41002 2002 return 0;
donatien 0:8e01dca41002 2003
donatien 0:8e01dca41002 2004 switch (optname) {
donatien 0:8e01dca41002 2005 case UDPLITE_SEND_CSCOV:
donatien 0:8e01dca41002 2006 case UDPLITE_RECV_CSCOV:
donatien 0:8e01dca41002 2007 break;
donatien 0:8e01dca41002 2008
donatien 0:8e01dca41002 2009 default:
donatien 0:8e01dca41002 2010 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_UDPLITE, UNIMPL: optname=0x%x, ..)\n",
donatien 0:8e01dca41002 2011 s, optname));
donatien 0:8e01dca41002 2012 err = ENOPROTOOPT;
donatien 0:8e01dca41002 2013 } /* switch (optname) */
donatien 0:8e01dca41002 2014 break;
donatien 0:8e01dca41002 2015 #endif /* LWIP_UDP && LWIP_UDPLITE */
donatien 0:8e01dca41002 2016 /* UNDEFINED LEVEL */
donatien 0:8e01dca41002 2017 default:
donatien 0:8e01dca41002 2018 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, level=0x%x, UNIMPL: optname=0x%x, ..)\n",
donatien 0:8e01dca41002 2019 s, level, optname));
donatien 0:8e01dca41002 2020 err = ENOPROTOOPT;
donatien 0:8e01dca41002 2021 } /* switch (level) */
donatien 0:8e01dca41002 2022
donatien 0:8e01dca41002 2023
donatien 0:8e01dca41002 2024 if (err != ERR_OK) {
donatien 0:8e01dca41002 2025 sock_set_errno(sock, err);
donatien 0:8e01dca41002 2026 return -1;
donatien 0:8e01dca41002 2027 }
donatien 0:8e01dca41002 2028
donatien 0:8e01dca41002 2029
donatien 0:8e01dca41002 2030 /* Now do the actual option processing */
donatien 0:8e01dca41002 2031 data.sock = sock;
donatien 0:8e01dca41002 2032 #ifdef LWIP_DEBUG
donatien 0:8e01dca41002 2033 data.s = s;
donatien 0:8e01dca41002 2034 #endif /* LWIP_DEBUG */
donatien 0:8e01dca41002 2035 data.level = level;
donatien 0:8e01dca41002 2036 data.optname = optname;
donatien 0:8e01dca41002 2037 data.optval = (void*)optval;
donatien 0:8e01dca41002 2038 data.optlen = &optlen;
donatien 0:8e01dca41002 2039 data.err = err;
donatien 0:8e01dca41002 2040 tcpip_callback(lwip_setsockopt_internal, &data);
donatien 0:8e01dca41002 2041 sys_arch_sem_wait(&sock->conn->op_completed, 0);
donatien 0:8e01dca41002 2042 /* maybe lwip_setsockopt_internal has changed err */
donatien 0:8e01dca41002 2043 err = data.err;
donatien 0:8e01dca41002 2044
donatien 0:8e01dca41002 2045 sock_set_errno(sock, err);
donatien 0:8e01dca41002 2046 return err ? -1 : 0;
donatien 0:8e01dca41002 2047 }
donatien 0:8e01dca41002 2048
donatien 0:8e01dca41002 2049 static void
donatien 0:8e01dca41002 2050 lwip_setsockopt_internal(void *arg)
donatien 0:8e01dca41002 2051 {
donatien 0:8e01dca41002 2052 struct lwip_sock *sock;
donatien 0:8e01dca41002 2053 #ifdef LWIP_DEBUG
donatien 0:8e01dca41002 2054 int s;
donatien 0:8e01dca41002 2055 #endif /* LWIP_DEBUG */
donatien 0:8e01dca41002 2056 int level, optname;
donatien 0:8e01dca41002 2057 const void *optval;
donatien 0:8e01dca41002 2058 struct lwip_setgetsockopt_data *data;
donatien 0:8e01dca41002 2059
donatien 0:8e01dca41002 2060 LWIP_ASSERT("arg != NULL", arg != NULL);
donatien 0:8e01dca41002 2061
donatien 0:8e01dca41002 2062 data = (struct lwip_setgetsockopt_data*)arg;
donatien 0:8e01dca41002 2063 sock = data->sock;
donatien 0:8e01dca41002 2064 #ifdef LWIP_DEBUG
donatien 0:8e01dca41002 2065 s = data->s;
donatien 0:8e01dca41002 2066 #endif /* LWIP_DEBUG */
donatien 0:8e01dca41002 2067 level = data->level;
donatien 0:8e01dca41002 2068 optname = data->optname;
donatien 0:8e01dca41002 2069 optval = data->optval;
donatien 0:8e01dca41002 2070
donatien 0:8e01dca41002 2071 switch (level) {
donatien 0:8e01dca41002 2072
donatien 0:8e01dca41002 2073 /* Level: SOL_SOCKET */
donatien 0:8e01dca41002 2074 case SOL_SOCKET:
donatien 0:8e01dca41002 2075 switch (optname) {
donatien 0:8e01dca41002 2076
donatien 0:8e01dca41002 2077 /* The option flags */
donatien 0:8e01dca41002 2078 case SO_BROADCAST:
donatien 0:8e01dca41002 2079 /* UNIMPL case SO_DEBUG: */
donatien 0:8e01dca41002 2080 /* UNIMPL case SO_DONTROUTE: */
donatien 0:8e01dca41002 2081 case SO_KEEPALIVE:
donatien 0:8e01dca41002 2082 /* UNIMPL case SO_OOBINCLUDE: */
donatien 0:8e01dca41002 2083 #if SO_REUSE
donatien 0:8e01dca41002 2084 case SO_REUSEADDR:
donatien 0:8e01dca41002 2085 case SO_REUSEPORT:
donatien 0:8e01dca41002 2086 #endif /* SO_REUSE */
donatien 0:8e01dca41002 2087 /* UNIMPL case SO_USELOOPBACK: */
donatien 0:8e01dca41002 2088 if (*(int*)optval) {
donatien 0:8e01dca41002 2089 sock->conn->pcb.ip->so_options |= optname;
donatien 0:8e01dca41002 2090 } else {
donatien 0:8e01dca41002 2091 sock->conn->pcb.ip->so_options &= ~optname;
donatien 0:8e01dca41002 2092 }
donatien 0:8e01dca41002 2093 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, SOL_SOCKET, optname=0x%x, ..) -> %s\n",
donatien 0:8e01dca41002 2094 s, optname, (*(int*)optval?"on":"off")));
donatien 0:8e01dca41002 2095 break;
donatien 0:8e01dca41002 2096 #if LWIP_SO_RCVTIMEO
donatien 0:8e01dca41002 2097 case SO_RCVTIMEO:
donatien 0:8e01dca41002 2098 netconn_set_recvtimeout(sock->conn, *(int*)optval);
donatien 0:8e01dca41002 2099 break;
donatien 0:8e01dca41002 2100 #endif /* LWIP_SO_RCVTIMEO */
donatien 0:8e01dca41002 2101 #if LWIP_SO_RCVBUF
donatien 0:8e01dca41002 2102 case SO_RCVBUF:
donatien 0:8e01dca41002 2103 netconn_set_recvbufsize(sock->conn, *(int*)optval);
donatien 0:8e01dca41002 2104 break;
donatien 0:8e01dca41002 2105 #endif /* LWIP_SO_RCVBUF */
donatien 0:8e01dca41002 2106 #if LWIP_UDP
donatien 0:8e01dca41002 2107 case SO_NO_CHECK:
donatien 0:8e01dca41002 2108 if (*(int*)optval) {
donatien 0:8e01dca41002 2109 udp_setflags(sock->conn->pcb.udp, udp_flags(sock->conn->pcb.udp) | UDP_FLAGS_NOCHKSUM);
donatien 0:8e01dca41002 2110 } else {
donatien 0:8e01dca41002 2111 udp_setflags(sock->conn->pcb.udp, udp_flags(sock->conn->pcb.udp) & ~UDP_FLAGS_NOCHKSUM);
donatien 0:8e01dca41002 2112 }
donatien 0:8e01dca41002 2113 break;
donatien 0:8e01dca41002 2114 #endif /* LWIP_UDP */
donatien 0:8e01dca41002 2115 default:
donatien 0:8e01dca41002 2116 LWIP_ASSERT("unhandled optname", 0);
donatien 0:8e01dca41002 2117 break;
donatien 0:8e01dca41002 2118 } /* switch (optname) */
donatien 0:8e01dca41002 2119 break;
donatien 0:8e01dca41002 2120
donatien 0:8e01dca41002 2121 /* Level: IPPROTO_IP */
donatien 0:8e01dca41002 2122 case IPPROTO_IP:
donatien 0:8e01dca41002 2123 switch (optname) {
donatien 0:8e01dca41002 2124 case IP_TTL:
donatien 0:8e01dca41002 2125 sock->conn->pcb.ip->ttl = (u8_t)(*(int*)optval);
donatien 0:8e01dca41002 2126 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IP, IP_TTL, ..) -> %d\n",
donatien 0:8e01dca41002 2127 s, sock->conn->pcb.ip->ttl));
donatien 0:8e01dca41002 2128 break;
donatien 0:8e01dca41002 2129 case IP_TOS:
donatien 0:8e01dca41002 2130 sock->conn->pcb.ip->tos = (u8_t)(*(int*)optval);
donatien 0:8e01dca41002 2131 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IP, IP_TOS, ..)-> %d\n",
donatien 0:8e01dca41002 2132 s, sock->conn->pcb.ip->tos));
donatien 0:8e01dca41002 2133 break;
donatien 0:8e01dca41002 2134 #if LWIP_IGMP
donatien 0:8e01dca41002 2135 case IP_MULTICAST_TTL:
donatien 0:8e01dca41002 2136 sock->conn->pcb.udp->ttl = (u8_t)(*(u8_t*)optval);
donatien 0:8e01dca41002 2137 break;
donatien 0:8e01dca41002 2138 case IP_MULTICAST_IF:
donatien 0:8e01dca41002 2139 inet_addr_to_ipaddr(&sock->conn->pcb.udp->multicast_ip, (struct in_addr*)optval);
donatien 0:8e01dca41002 2140 break;
donatien 0:8e01dca41002 2141 case IP_MULTICAST_LOOP:
donatien 0:8e01dca41002 2142 if (*(u8_t*)optval) {
donatien 0:8e01dca41002 2143 udp_setflags(sock->conn->pcb.udp, udp_flags(sock->conn->pcb.udp) | UDP_FLAGS_MULTICAST_LOOP);
donatien 0:8e01dca41002 2144 } else {
donatien 0:8e01dca41002 2145 udp_setflags(sock->conn->pcb.udp, udp_flags(sock->conn->pcb.udp) & ~UDP_FLAGS_MULTICAST_LOOP);
donatien 0:8e01dca41002 2146 }
donatien 0:8e01dca41002 2147 break;
donatien 0:8e01dca41002 2148 case IP_ADD_MEMBERSHIP:
donatien 0:8e01dca41002 2149 case IP_DROP_MEMBERSHIP:
donatien 0:8e01dca41002 2150 {
donatien 0:8e01dca41002 2151 /* If this is a TCP or a RAW socket, ignore these options. */
donatien 0:8e01dca41002 2152 struct ip_mreq *imr = (struct ip_mreq *)optval;
donatien 0:8e01dca41002 2153 ip_addr_t if_addr;
donatien 0:8e01dca41002 2154 ip_addr_t multi_addr;
donatien 0:8e01dca41002 2155 inet_addr_to_ipaddr(&if_addr, &imr->imr_interface);
donatien 0:8e01dca41002 2156 inet_addr_to_ipaddr(&multi_addr, &imr->imr_multiaddr);
donatien 0:8e01dca41002 2157 if(optname == IP_ADD_MEMBERSHIP){
donatien 0:8e01dca41002 2158 data->err = igmp_joingroup(&if_addr, &multi_addr);
donatien 0:8e01dca41002 2159 } else {
donatien 0:8e01dca41002 2160 data->err = igmp_leavegroup(&if_addr, &multi_addr);
donatien 0:8e01dca41002 2161 }
donatien 0:8e01dca41002 2162 if(data->err != ERR_OK) {
donatien 0:8e01dca41002 2163 data->err = EADDRNOTAVAIL;
donatien 0:8e01dca41002 2164 }
donatien 0:8e01dca41002 2165 }
donatien 0:8e01dca41002 2166 break;
donatien 0:8e01dca41002 2167 #endif /* LWIP_IGMP */
donatien 0:8e01dca41002 2168 default:
donatien 0:8e01dca41002 2169 LWIP_ASSERT("unhandled optname", 0);
donatien 0:8e01dca41002 2170 break;
donatien 0:8e01dca41002 2171 } /* switch (optname) */
donatien 0:8e01dca41002 2172 break;
donatien 0:8e01dca41002 2173
donatien 0:8e01dca41002 2174 #if LWIP_TCP
donatien 0:8e01dca41002 2175 /* Level: IPPROTO_TCP */
donatien 0:8e01dca41002 2176 case IPPROTO_TCP:
donatien 0:8e01dca41002 2177 switch (optname) {
donatien 0:8e01dca41002 2178 case TCP_NODELAY:
donatien 0:8e01dca41002 2179 if (*(int*)optval) {
donatien 0:8e01dca41002 2180 tcp_nagle_disable(sock->conn->pcb.tcp);
donatien 0:8e01dca41002 2181 } else {
donatien 0:8e01dca41002 2182 tcp_nagle_enable(sock->conn->pcb.tcp);
donatien 0:8e01dca41002 2183 }
donatien 0:8e01dca41002 2184 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_NODELAY) -> %s\n",
donatien 0:8e01dca41002 2185 s, (*(int *)optval)?"on":"off") );
donatien 0:8e01dca41002 2186 break;
donatien 0:8e01dca41002 2187 case TCP_KEEPALIVE:
donatien 0:8e01dca41002 2188 sock->conn->pcb.tcp->keep_idle = (u32_t)(*(int*)optval);
donatien 0:8e01dca41002 2189 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPALIVE) -> %"U32_F"\n",
donatien 0:8e01dca41002 2190 s, sock->conn->pcb.tcp->keep_idle));
donatien 0:8e01dca41002 2191 break;
donatien 0:8e01dca41002 2192
donatien 0:8e01dca41002 2193 #if LWIP_TCP_KEEPALIVE
donatien 0:8e01dca41002 2194 case TCP_KEEPIDLE:
donatien 0:8e01dca41002 2195 sock->conn->pcb.tcp->keep_idle = 1000*(u32_t)(*(int*)optval);
donatien 0:8e01dca41002 2196 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPIDLE) -> %"U32_F"\n",
donatien 0:8e01dca41002 2197 s, sock->conn->pcb.tcp->keep_idle));
donatien 0:8e01dca41002 2198 break;
donatien 0:8e01dca41002 2199 case TCP_KEEPINTVL:
donatien 0:8e01dca41002 2200 sock->conn->pcb.tcp->keep_intvl = 1000*(u32_t)(*(int*)optval);
donatien 0:8e01dca41002 2201 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPINTVL) -> %"U32_F"\n",
donatien 0:8e01dca41002 2202 s, sock->conn->pcb.tcp->keep_intvl));
donatien 0:8e01dca41002 2203 break;
donatien 0:8e01dca41002 2204 case TCP_KEEPCNT:
donatien 0:8e01dca41002 2205 sock->conn->pcb.tcp->keep_cnt = (u32_t)(*(int*)optval);
donatien 0:8e01dca41002 2206 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPCNT) -> %"U32_F"\n",
donatien 0:8e01dca41002 2207 s, sock->conn->pcb.tcp->keep_cnt));
donatien 0:8e01dca41002 2208 break;
donatien 0:8e01dca41002 2209 #endif /* LWIP_TCP_KEEPALIVE */
donatien 0:8e01dca41002 2210 default:
donatien 0:8e01dca41002 2211 LWIP_ASSERT("unhandled optname", 0);
donatien 0:8e01dca41002 2212 break;
donatien 0:8e01dca41002 2213 } /* switch (optname) */
donatien 0:8e01dca41002 2214 break;
donatien 0:8e01dca41002 2215 #endif /* LWIP_TCP*/
donatien 0:8e01dca41002 2216 #if LWIP_UDP && LWIP_UDPLITE
donatien 0:8e01dca41002 2217 /* Level: IPPROTO_UDPLITE */
donatien 0:8e01dca41002 2218 case IPPROTO_UDPLITE:
donatien 0:8e01dca41002 2219 switch (optname) {
donatien 0:8e01dca41002 2220 case UDPLITE_SEND_CSCOV:
donatien 0:8e01dca41002 2221 if ((*(int*)optval != 0) && ((*(int*)optval < 8)) || (*(int*)optval > 0xffff)) {
donatien 0:8e01dca41002 2222 /* don't allow illegal values! */
donatien 0:8e01dca41002 2223 sock->conn->pcb.udp->chksum_len_tx = 8;
donatien 0:8e01dca41002 2224 } else {
donatien 0:8e01dca41002 2225 sock->conn->pcb.udp->chksum_len_tx = (u16_t)*(int*)optval;
donatien 0:8e01dca41002 2226 }
donatien 0:8e01dca41002 2227 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_UDPLITE, UDPLITE_SEND_CSCOV) -> %d\n",
donatien 0:8e01dca41002 2228 s, (*(int*)optval)) );
donatien 0:8e01dca41002 2229 break;
donatien 0:8e01dca41002 2230 case UDPLITE_RECV_CSCOV:
donatien 0:8e01dca41002 2231 if ((*(int*)optval != 0) && ((*(int*)optval < 8)) || (*(int*)optval > 0xffff)) {
donatien 0:8e01dca41002 2232 /* don't allow illegal values! */
donatien 0:8e01dca41002 2233 sock->conn->pcb.udp->chksum_len_rx = 8;
donatien 0:8e01dca41002 2234 } else {
donatien 0:8e01dca41002 2235 sock->conn->pcb.udp->chksum_len_rx = (u16_t)*(int*)optval;
donatien 0:8e01dca41002 2236 }
donatien 0:8e01dca41002 2237 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_UDPLITE, UDPLITE_RECV_CSCOV) -> %d\n",
donatien 0:8e01dca41002 2238 s, (*(int*)optval)) );
donatien 0:8e01dca41002 2239 break;
donatien 0:8e01dca41002 2240 default:
donatien 0:8e01dca41002 2241 LWIP_ASSERT("unhandled optname", 0);
donatien 0:8e01dca41002 2242 break;
donatien 0:8e01dca41002 2243 } /* switch (optname) */
donatien 0:8e01dca41002 2244 break;
donatien 0:8e01dca41002 2245 #endif /* LWIP_UDP */
donatien 0:8e01dca41002 2246 default:
donatien 0:8e01dca41002 2247 LWIP_ASSERT("unhandled level", 0);
donatien 0:8e01dca41002 2248 break;
donatien 0:8e01dca41002 2249 } /* switch (level) */
donatien 0:8e01dca41002 2250 sys_sem_signal(&sock->conn->op_completed);
donatien 0:8e01dca41002 2251 }
donatien 0:8e01dca41002 2252
donatien 0:8e01dca41002 2253 int
donatien 0:8e01dca41002 2254 lwip_ioctl(int s, long cmd, void *argp)
donatien 0:8e01dca41002 2255 {
donatien 0:8e01dca41002 2256 struct lwip_sock *sock = get_socket(s);
donatien 0:8e01dca41002 2257 u8_t val;
donatien 0:8e01dca41002 2258 #if LWIP_SO_RCVBUF
donatien 0:8e01dca41002 2259 u16_t buflen = 0;
donatien 0:8e01dca41002 2260 s16_t recv_avail;
donatien 0:8e01dca41002 2261 #endif /* LWIP_SO_RCVBUF */
donatien 0:8e01dca41002 2262
donatien 0:8e01dca41002 2263 if (!sock) {
donatien 0:8e01dca41002 2264 return -1;
donatien 0:8e01dca41002 2265 }
donatien 0:8e01dca41002 2266
donatien 0:8e01dca41002 2267 switch (cmd) {
donatien 0:8e01dca41002 2268 #if LWIP_SO_RCVBUF
donatien 0:8e01dca41002 2269 case FIONREAD:
donatien 0:8e01dca41002 2270 if (!argp) {
donatien 0:8e01dca41002 2271 sock_set_errno(sock, EINVAL);
donatien 0:8e01dca41002 2272 return -1;
donatien 0:8e01dca41002 2273 }
donatien 0:8e01dca41002 2274
donatien 0:8e01dca41002 2275 SYS_ARCH_GET(sock->conn->recv_avail, recv_avail);
donatien 0:8e01dca41002 2276 if (recv_avail < 0) {
donatien 0:8e01dca41002 2277 recv_avail = 0;
donatien 0:8e01dca41002 2278 }
donatien 0:8e01dca41002 2279 *((u16_t*)argp) = (u16_t)recv_avail;
donatien 0:8e01dca41002 2280
donatien 0:8e01dca41002 2281 /* Check if there is data left from the last recv operation. /maq 041215 */
donatien 0:8e01dca41002 2282 if (sock->lastdata) {
donatien 0:8e01dca41002 2283 struct pbuf *p = (struct pbuf *)sock->lastdata;
donatien 0:8e01dca41002 2284 if (netconn_type(sock->conn) != NETCONN_TCP) {
donatien 0:8e01dca41002 2285 p = ((struct netbuf *)p)->p;
donatien 0:8e01dca41002 2286 }
donatien 0:8e01dca41002 2287 buflen = p->tot_len;
donatien 0:8e01dca41002 2288 buflen -= sock->lastoffset;
donatien 0:8e01dca41002 2289
donatien 0:8e01dca41002 2290 *((u16_t*)argp) += buflen;
donatien 0:8e01dca41002 2291 }
donatien 0:8e01dca41002 2292
donatien 0:8e01dca41002 2293 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(%d, FIONREAD, %p) = %"U16_F"\n", s, argp, *((u16_t*)argp)));
donatien 0:8e01dca41002 2294 sock_set_errno(sock, 0);
donatien 0:8e01dca41002 2295 return 0;
donatien 0:8e01dca41002 2296 #endif /* LWIP_SO_RCVBUF */
donatien 0:8e01dca41002 2297
donatien 0:8e01dca41002 2298 case FIONBIO:
donatien 0:8e01dca41002 2299 val = 0;
donatien 0:8e01dca41002 2300 if (argp && *(u32_t*)argp) {
donatien 0:8e01dca41002 2301 val = 1;
donatien 0:8e01dca41002 2302 }
donatien 0:8e01dca41002 2303 netconn_set_nonblocking(sock->conn, val);
donatien 0:8e01dca41002 2304 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(%d, FIONBIO, %d)\n", s, val));
donatien 0:8e01dca41002 2305 sock_set_errno(sock, 0);
donatien 0:8e01dca41002 2306 return 0;
donatien 0:8e01dca41002 2307
donatien 0:8e01dca41002 2308 default:
donatien 0:8e01dca41002 2309 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(%d, UNIMPL: 0x%lx, %p)\n", s, cmd, argp));
donatien 0:8e01dca41002 2310 sock_set_errno(sock, ENOSYS); /* not yet implemented */
donatien 0:8e01dca41002 2311 return -1;
donatien 0:8e01dca41002 2312 } /* switch (cmd) */
donatien 0:8e01dca41002 2313 }
donatien 0:8e01dca41002 2314
donatien 0:8e01dca41002 2315 /** A minimal implementation of fcntl.
donatien 0:8e01dca41002 2316 * Currently only the commands F_GETFL and F_SETFL are implemented.
donatien 0:8e01dca41002 2317 * Only the flag O_NONBLOCK is implemented.
donatien 0:8e01dca41002 2318 */
donatien 0:8e01dca41002 2319 int
donatien 0:8e01dca41002 2320 lwip_fcntl(int s, int cmd, int val)
donatien 0:8e01dca41002 2321 {
donatien 0:8e01dca41002 2322 struct lwip_sock *sock = get_socket(s);
donatien 0:8e01dca41002 2323 int ret = -1;
donatien 0:8e01dca41002 2324
donatien 0:8e01dca41002 2325 if (!sock || !sock->conn) {
donatien 0:8e01dca41002 2326 return -1;
donatien 0:8e01dca41002 2327 }
donatien 0:8e01dca41002 2328
donatien 0:8e01dca41002 2329 switch (cmd) {
donatien 0:8e01dca41002 2330 case F_GETFL:
donatien 0:8e01dca41002 2331 ret = netconn_is_nonblocking(sock->conn) ? O_NONBLOCK : 0;
donatien 0:8e01dca41002 2332 break;
donatien 0:8e01dca41002 2333 case F_SETFL:
donatien 0:8e01dca41002 2334 if ((val & ~O_NONBLOCK) == 0) {
donatien 0:8e01dca41002 2335 /* only O_NONBLOCK, all other bits are zero */
donatien 0:8e01dca41002 2336 netconn_set_nonblocking(sock->conn, val & O_NONBLOCK);
donatien 0:8e01dca41002 2337 ret = 0;
donatien 0:8e01dca41002 2338 }
donatien 0:8e01dca41002 2339 break;
donatien 0:8e01dca41002 2340 default:
donatien 0:8e01dca41002 2341 LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_fcntl(%d, UNIMPL: %d, %d)\n", s, cmd, val));
donatien 0:8e01dca41002 2342 break;
donatien 0:8e01dca41002 2343 }
donatien 0:8e01dca41002 2344 return ret;
donatien 0:8e01dca41002 2345 }
donatien 0:8e01dca41002 2346
donatien 0:8e01dca41002 2347 #endif /* LWIP_SOCKET */