Ethernet for Nucleo and Disco board STM32F746 works with gcc and arm. IAC is untested

Fork of F7_Ethernet by Dieter Graef

Committer:
TudaPellini
Date:
Sun Aug 20 17:01:43 2017 +0000
Revision:
2:11660e6c9d7a
Parent:
0:d26c1b55cfca
Added support to F767 and LWIP entries to receive raw ethernet data in promiscuous mode for IEC 61850 GOOSE messages

Who changed what in which revision?

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