Forked from STM32F7 internet for nucleo F746ZG

Dependents:   Nucleo_F746ZG_Ethernet_MQTT_Ultrasound

Fork of F7_Ethernet by Dieter Graef

Committer:
DieterGraef
Date:
Sun Jun 19 16:23:40 2016 +0000
Revision:
0:d26c1b55cfca
Ethernet Library for Nucleo stm32f746ZG and Disco stm32f746NG  works under arm and gcc environment

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)
DieterGraef 0:d26c1b55cfca 163 static int errno;
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 */