ProjetoBB

Dependencies:   F7_Ethernet WebSocketClient mbed mcp3008

Fork of Nucleo_F746ZG_Ethernet by Dieter Graef

Committer:
DieterGraef
Date:
Sat Jun 18 10:49:12 2016 +0000
Revision:
0:f9b6112278fe
Ethernet for the NUCLEO STM32F746 Board Testprogram uses DHCP and NTP to set the clock

Who changed what in which revision?

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