Free (GPLv2) TCP/IP stack developed by TASS Belgium

Dependents:   lpc1768-picotcp-demo ZeroMQ_PicoTCP_Publisher_demo TCPSocket_HelloWorld_PicoTCP Pico_TCP_UDP_Test ... more

PicoTCP. Copyright (c) 2013 TASS Belgium NV.

Released under the GNU General Public License, version 2.

Different licensing models may exist, at the sole discretion of the Copyright holders.

Official homepage: http://www.picotcp.com

Bug tracker: https://github.com/tass-belgium/picotcp/issues

Development steps:

  • initial integration with mbed RTOS
  • generic mbed Ethernet driver
  • high performance NXP LPC1768 specific Ethernet driver
  • Multi-threading support for mbed RTOS
  • Berkeley sockets and integration with the New Socket API
  • Fork of the apps running on top of the New Socket API
  • Scheduling optimizations
  • Debugging/benchmarking/testing

Demo application (measuring TCP sender performance):

Import programlpc1768-picotcp-demo

A PicoTCP demo app testing the ethernet throughput on the lpc1768 mbed board.

Committer:
tass
Date:
Thu Dec 05 08:31:32 2013 +0000
Revision:
128:ae39e6e81531
Parent:
125:96003ae6f1d8
Child:
131:4758606c9316
updated repo to work with uint64 tick.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
tass 68:0847e35d08a6 1 /*********************************************************************
tass 68:0847e35d08a6 2 PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved.
tass 68:0847e35d08a6 3 See LICENSE and COPYING for usage.
tass 68:0847e35d08a6 4
tass 68:0847e35d08a6 5
tass 68:0847e35d08a6 6 Authors: Daniele Lacamera
tass 68:0847e35d08a6 7 *********************************************************************/
tass 68:0847e35d08a6 8
tass 68:0847e35d08a6 9
tass 68:0847e35d08a6 10 #include "pico_config.h"
tass 68:0847e35d08a6 11 #include "pico_queue.h"
tass 68:0847e35d08a6 12 #include "pico_socket.h"
tass 68:0847e35d08a6 13 #include "pico_ipv4.h"
tass 68:0847e35d08a6 14 #include "pico_ipv6.h"
tass 68:0847e35d08a6 15 #include "pico_udp.h"
tass 68:0847e35d08a6 16 #include "pico_tcp.h"
tass 68:0847e35d08a6 17 #include "pico_stack.h"
tass 68:0847e35d08a6 18 #include "pico_icmp4.h"
tass 68:0847e35d08a6 19 #include "pico_nat.h"
tass 68:0847e35d08a6 20 #include "pico_tree.h"
tass 68:0847e35d08a6 21 #include "pico_device.h"
tass 68:0847e35d08a6 22
tass 68:0847e35d08a6 23 #if defined (PICO_SUPPORT_IPV4) || defined (PICO_SUPPORT_IPV6)
tass 68:0847e35d08a6 24 #if defined (PICO_SUPPORT_TCP) || defined (PICO_SUPPORT_UDP)
tass 68:0847e35d08a6 25
tass 110:0ece1bbbd36e 26 #define UDP_FRAME_OVERHEAD (sizeof(struct pico_frame))
tass 68:0847e35d08a6 27
tass 68:0847e35d08a6 28 #define PROTO(s) ((s)->proto->proto_number)
tass 68:0847e35d08a6 29 #define PICO_SOCKET4_MTU 1480 /* Ethernet MTU(1500) - IP header size(20) */
tass 68:0847e35d08a6 30 #define PICO_SOCKET6_MTU 1460 /* Ethernet MTU(1500) - IP header size(40) */
tass 68:0847e35d08a6 31 #define TCP_STATE(s) (s->state & PICO_SOCKET_STATE_TCP)
tass 68:0847e35d08a6 32
tass 68:0847e35d08a6 33 #ifdef PICO_SUPPORT_MUTEX
tass 68:0847e35d08a6 34 static void * Mutex = NULL;
tass 68:0847e35d08a6 35 #define LOCK(x) {\
tass 68:0847e35d08a6 36 if (x == NULL) \
tass 68:0847e35d08a6 37 x = pico_mutex_init(); \
tass 68:0847e35d08a6 38 pico_mutex_lock(x); \
tass 68:0847e35d08a6 39 }
tass 68:0847e35d08a6 40 #define UNLOCK(x) pico_mutex_unlock(x);
tass 68:0847e35d08a6 41
tass 68:0847e35d08a6 42 #else
tass 68:0847e35d08a6 43 #define LOCK(x) do{}while(0)
tass 68:0847e35d08a6 44 #define UNLOCK(x) do{}while(0)
tass 68:0847e35d08a6 45 #endif
tass 68:0847e35d08a6 46
tass 68:0847e35d08a6 47
tass 68:0847e35d08a6 48 #define PROTO(s) ((s)->proto->proto_number)
tass 68:0847e35d08a6 49
tass 68:0847e35d08a6 50 #ifdef PICO_SUPPORT_TCP
tass 68:0847e35d08a6 51 # define IS_NAGLE_ENABLED(s) (!(!(!(s->opt_flags & (1 << PICO_SOCKET_OPT_TCPNODELAY)))))
tass 68:0847e35d08a6 52 #endif
tass 68:0847e35d08a6 53
tass 68:0847e35d08a6 54 #define PICO_SOCKET_MTU 1480 /* Ethernet MTU(1500) - IP header size(20) */
tass 68:0847e35d08a6 55
tass 68:0847e35d08a6 56 #ifdef PICO_SUPPORT_IPV4
tass 68:0847e35d08a6 57 # define IS_SOCK_IPV4(s) ((s->net == &pico_proto_ipv4))
tass 68:0847e35d08a6 58 #else
tass 68:0847e35d08a6 59 # define IS_SOCK_IPV4(s) (0)
tass 68:0847e35d08a6 60 #endif
tass 68:0847e35d08a6 61
tass 68:0847e35d08a6 62 #ifdef PICO_SUPPORT_IPV6
tass 68:0847e35d08a6 63 # define IS_SOCK_IPV6(s) ((s->net == &pico_proto_ipv6))
tass 68:0847e35d08a6 64 #else
tass 68:0847e35d08a6 65 # define IS_SOCK_IPV6(s) (0)
tass 68:0847e35d08a6 66 #endif
tass 68:0847e35d08a6 67
tass 68:0847e35d08a6 68 #ifdef PICO_SUPPORT_IPFRAG
tass 68:0847e35d08a6 69 # define frag_dbg(...) do{}while(0)
tass 68:0847e35d08a6 70 #endif
tass 68:0847e35d08a6 71
tass 68:0847e35d08a6 72 #ifdef PICO_SUPPORT_MCAST
tass 68:0847e35d08a6 73 # define so_mcast_dbg(...) do{}while(0) /* ip_mcast_dbg in pico_ipv4.c */
tass 68:0847e35d08a6 74 #endif
tass 68:0847e35d08a6 75
tass 68:0847e35d08a6 76 static struct pico_sockport *sp_udp = NULL ,*sp_tcp = NULL;
tass 68:0847e35d08a6 77
tass 70:cd218dd180e5 78 struct pico_frame *pico_socket_frame_alloc(struct pico_socket *s, uint16_t len);
tass 68:0847e35d08a6 79
tass 70:cd218dd180e5 80 static int32_t socket_cmp(void * ka, void * kb)
tass 68:0847e35d08a6 81 {
tass 68:0847e35d08a6 82 struct pico_socket *a = ka, *b = kb;
tass 70:cd218dd180e5 83 uint32_t a_is_ip6 = is_sock_ipv6(a);
tass 70:cd218dd180e5 84 uint32_t b_is_ip6 = is_sock_ipv6(b);
tass 68:0847e35d08a6 85
tass 70:cd218dd180e5 86 int32_t diff;
tass 68:0847e35d08a6 87
tass 68:0847e35d08a6 88 /* First, order by network ver */
tass 68:0847e35d08a6 89 if (a_is_ip6 < b_is_ip6)
tass 68:0847e35d08a6 90 return -1;
tass 68:0847e35d08a6 91 if (a_is_ip6 > b_is_ip6)
tass 68:0847e35d08a6 92 return 1;
tass 68:0847e35d08a6 93
tass 68:0847e35d08a6 94 /* If either socket is PICO_IPV4_INADDR_ANY mode, skip local address comparison */
tass 68:0847e35d08a6 95
tass 68:0847e35d08a6 96 /* At this point, sort by local host */
tass 68:0847e35d08a6 97
tass 68:0847e35d08a6 98 if (0) {
tass 68:0847e35d08a6 99 #ifdef PICO_SUPPORT_IPV6
tass 68:0847e35d08a6 100 } else if (a_is_ip6) {
tass 68:0847e35d08a6 101 if ((memcmp(a->local_addr.ip6.addr, PICO_IP6_ANY, PICO_SIZE_IP6)==0) || memcmp((b->local_addr.ip6.addr, PICO_IP6_ANY, PICO_SIZE_IP6) == 0))
tass 68:0847e35d08a6 102 diff = 0;
tass 68:0847e35d08a6 103 else
tass 68:0847e35d08a6 104 diff = memcmp(a->local_addr.ip6.addr, b->local_addr.ip6.addr, PICO_SIZE_IP6);
tass 68:0847e35d08a6 105 #endif
tass 68:0847e35d08a6 106 } else {
tass 68:0847e35d08a6 107 if ((a->local_addr.ip4.addr == PICO_IP4_ANY) || (b->local_addr.ip4.addr == PICO_IP4_ANY))
tass 68:0847e35d08a6 108 diff = 0;
tass 68:0847e35d08a6 109 else
tass 70:cd218dd180e5 110 diff = (int32_t)(a->local_addr.ip4.addr - b->local_addr.ip4.addr);
tass 68:0847e35d08a6 111 }
tass 68:0847e35d08a6 112
tass 68:0847e35d08a6 113 if (diff)
tass 68:0847e35d08a6 114 return diff;
tass 68:0847e35d08a6 115
tass 68:0847e35d08a6 116
tass 68:0847e35d08a6 117 /* Sort by remote host */
tass 68:0847e35d08a6 118 if (a_is_ip6)
tass 68:0847e35d08a6 119 diff = memcmp(a->remote_addr.ip6.addr, b->remote_addr.ip6.addr, PICO_SIZE_IP6);
tass 68:0847e35d08a6 120 else
tass 70:cd218dd180e5 121 diff = (int32_t)(a->remote_addr.ip4.addr - b->remote_addr.ip4.addr);
tass 68:0847e35d08a6 122
tass 68:0847e35d08a6 123 if (diff)
tass 68:0847e35d08a6 124 return diff;
tass 68:0847e35d08a6 125
tass 68:0847e35d08a6 126 /* And finally by remote port. The two sockets are coincident if the quad is the same. */
tass 68:0847e35d08a6 127 return b->remote_port - a->remote_port;
tass 68:0847e35d08a6 128 }
tass 68:0847e35d08a6 129
tass 68:0847e35d08a6 130 struct pico_sockport
tass 68:0847e35d08a6 131 {
tass 68:0847e35d08a6 132 struct pico_tree socks; // how you make the connection ?
tass 68:0847e35d08a6 133 uint16_t number;
tass 68:0847e35d08a6 134 uint16_t proto;
tass 68:0847e35d08a6 135 };
tass 68:0847e35d08a6 136
tass 68:0847e35d08a6 137 #define INIT_SOCKPORT { {&LEAF , socket_cmp}, 0, 0 }
tass 68:0847e35d08a6 138
tass 68:0847e35d08a6 139 int sockport_cmp(void * ka, void * kb)
tass 68:0847e35d08a6 140 {
tass 68:0847e35d08a6 141 struct pico_sockport *a = ka, *b = kb;
tass 68:0847e35d08a6 142 if (a->number < b->number)
tass 68:0847e35d08a6 143 return -1;
tass 68:0847e35d08a6 144 if (a->number > b->number)
tass 68:0847e35d08a6 145 return 1;
tass 68:0847e35d08a6 146 return 0;
tass 68:0847e35d08a6 147 }
tass 68:0847e35d08a6 148
tass 68:0847e35d08a6 149 PICO_TREE_DECLARE(UDPTable,sockport_cmp);
tass 68:0847e35d08a6 150 PICO_TREE_DECLARE(TCPTable,sockport_cmp);
tass 68:0847e35d08a6 151
tass 68:0847e35d08a6 152 #ifdef PICO_SUPPORT_MCAST
tass 68:0847e35d08a6 153 /* socket
tass 68:0847e35d08a6 154 * |
tass 68:0847e35d08a6 155 * MCASTListen
tass 68:0847e35d08a6 156 * | | |
tass 68:0847e35d08a6 157 * ------------ | ------------
tass 68:0847e35d08a6 158 * | | |
tass 68:0847e35d08a6 159 * MCASTSources MCASTSources MCASTSources
tass 68:0847e35d08a6 160 * | | | | | | | | | | | |
tass 68:0847e35d08a6 161 * S S S S S S S S S S S S
tass 68:0847e35d08a6 162 *
tass 68:0847e35d08a6 163 * MCASTListen: RBTree(mcast_link, mcast_group)
tass 68:0847e35d08a6 164 * MCASTSources: RBTree(source)
tass 68:0847e35d08a6 165 */
tass 68:0847e35d08a6 166 struct pico_mcast_listen
tass 68:0847e35d08a6 167 {
tass 68:0847e35d08a6 168 uint8_t filter_mode;
tass 68:0847e35d08a6 169 struct pico_ip4 mcast_link;
tass 68:0847e35d08a6 170 struct pico_ip4 mcast_group;
tass 68:0847e35d08a6 171 struct pico_tree MCASTSources;
tass 68:0847e35d08a6 172 };
tass 68:0847e35d08a6 173
tass 68:0847e35d08a6 174 static int mcast_listen_cmp(void *ka, void *kb)
tass 68:0847e35d08a6 175 {
tass 68:0847e35d08a6 176 struct pico_mcast_listen *a = ka, *b = kb;
tass 68:0847e35d08a6 177 if (a->mcast_group.addr < b->mcast_group.addr)
tass 68:0847e35d08a6 178 return -1;
tass 68:0847e35d08a6 179 if (a->mcast_group.addr > b->mcast_group.addr)
tass 68:0847e35d08a6 180 return 1;
tass 68:0847e35d08a6 181
tass 68:0847e35d08a6 182 if (a->mcast_link.addr < b->mcast_link.addr)
tass 68:0847e35d08a6 183 return -1;
tass 68:0847e35d08a6 184 if (a->mcast_link.addr > b->mcast_link.addr)
tass 68:0847e35d08a6 185 return 1;
tass 68:0847e35d08a6 186
tass 68:0847e35d08a6 187 return 0;
tass 68:0847e35d08a6 188 }
tass 68:0847e35d08a6 189
tass 68:0847e35d08a6 190 static int mcast_sources_cmp(void *ka, void *kb)
tass 68:0847e35d08a6 191 {
tass 68:0847e35d08a6 192 struct pico_ip4 *a = ka, *b = kb;
tass 68:0847e35d08a6 193 if (a->addr < b->addr)
tass 68:0847e35d08a6 194 return -1;
tass 68:0847e35d08a6 195 if (a->addr > b->addr)
tass 68:0847e35d08a6 196 return 1;
tass 68:0847e35d08a6 197 return 0;
tass 68:0847e35d08a6 198 }
tass 68:0847e35d08a6 199
tass 68:0847e35d08a6 200 static int mcast_socket_cmp(void *ka, void *kb)
tass 68:0847e35d08a6 201 {
tass 68:0847e35d08a6 202 struct pico_socket *a = ka, *b = kb;
tass 68:0847e35d08a6 203 if (a < b)
tass 68:0847e35d08a6 204 return -1;
tass 68:0847e35d08a6 205 if (a > b)
tass 68:0847e35d08a6 206 return 1;
tass 68:0847e35d08a6 207 return 0;
tass 68:0847e35d08a6 208 }
tass 68:0847e35d08a6 209 /* gather all multicast sockets to hasten filter aggregation */
tass 68:0847e35d08a6 210 PICO_TREE_DECLARE(MCASTSockets, mcast_socket_cmp);
tass 68:0847e35d08a6 211
tass 68:0847e35d08a6 212 static int mcast_filter_cmp(void *ka, void *kb)
tass 68:0847e35d08a6 213 {
tass 68:0847e35d08a6 214 struct pico_ip4 *a = ka, *b = kb;
tass 68:0847e35d08a6 215 if (a->addr < b->addr)
tass 68:0847e35d08a6 216 return -1;
tass 68:0847e35d08a6 217 if (a->addr > b->addr)
tass 68:0847e35d08a6 218 return 1;
tass 68:0847e35d08a6 219 return 0;
tass 68:0847e35d08a6 220 }
tass 68:0847e35d08a6 221 /* gather sources to be filtered */
tass 68:0847e35d08a6 222 PICO_TREE_DECLARE(MCASTFilter, mcast_filter_cmp);
tass 68:0847e35d08a6 223
tass 74:c146c4e346c4 224 static struct pico_mcast_listen *listen_find(struct pico_socket *s, struct pico_ip4 *lnk, struct pico_ip4 *grp)
tass 74:c146c4e346c4 225 {
tass 74:c146c4e346c4 226 struct pico_mcast_listen ltest = {0};
tass 74:c146c4e346c4 227 ltest.mcast_link.addr = lnk->addr;
tass 74:c146c4e346c4 228 ltest.mcast_group.addr = grp->addr;
tass 74:c146c4e346c4 229 return pico_tree_findKey(s->MCASTListen, &ltest);
tass 74:c146c4e346c4 230 }
tass 74:c146c4e346c4 231
tass 68:0847e35d08a6 232 /* MCASTFilter will be empty if no socket is listening on mcast_group on mcast_link anymore */
tass 68:0847e35d08a6 233 static int pico_socket_aggregate_mcastfilters(struct pico_ip4 *mcast_link, struct pico_ip4 *mcast_group)
tass 68:0847e35d08a6 234 {
tass 68:0847e35d08a6 235 uint8_t filter_mode = PICO_IP_MULTICAST_INCLUDE;
tass 74:c146c4e346c4 236 struct pico_mcast_listen *listen = NULL;
tass 68:0847e35d08a6 237 struct pico_ip4 *source = NULL;
tass 68:0847e35d08a6 238 struct pico_socket *mcast_sock = NULL;
tass 68:0847e35d08a6 239 struct pico_tree_node *index = NULL, *_tmp = NULL, *index2 = NULL, *_tmp2 = NULL;
tass 68:0847e35d08a6 240
tass 68:0847e35d08a6 241
tass 68:0847e35d08a6 242 /* cleanup old filter */
tass 68:0847e35d08a6 243 pico_tree_foreach_safe(index, &MCASTFilter, _tmp)
tass 68:0847e35d08a6 244 {
tass 68:0847e35d08a6 245 pico_tree_delete(&MCASTFilter, index->keyValue);
tass 68:0847e35d08a6 246 }
tass 68:0847e35d08a6 247
tass 68:0847e35d08a6 248 /* construct new filter */
tass 68:0847e35d08a6 249 pico_tree_foreach(index, &MCASTSockets)
tass 68:0847e35d08a6 250 {
tass 68:0847e35d08a6 251 mcast_sock = index->keyValue;
tass 74:c146c4e346c4 252 listen = listen_find(mcast_sock, mcast_link, mcast_group);
tass 68:0847e35d08a6 253 if (listen) {
tass 68:0847e35d08a6 254 /* aggregate filter */
tass 68:0847e35d08a6 255 switch(filter_mode)
tass 68:0847e35d08a6 256 {
tass 68:0847e35d08a6 257 case PICO_IP_MULTICAST_INCLUDE:
tass 68:0847e35d08a6 258 switch (listen->filter_mode)
tass 68:0847e35d08a6 259 {
tass 68:0847e35d08a6 260 case PICO_IP_MULTICAST_INCLUDE:
tass 68:0847e35d08a6 261 /* filter = summation of INCLUDEs */
tass 68:0847e35d08a6 262 /* mode stays INCLUDE, add all sources to filter */
tass 68:0847e35d08a6 263 pico_tree_foreach(index2, &listen->MCASTSources)
tass 68:0847e35d08a6 264 {
tass 68:0847e35d08a6 265 source = index2->keyValue;
tass 68:0847e35d08a6 266 pico_tree_insert(&MCASTFilter, source);
tass 68:0847e35d08a6 267 }
tass 68:0847e35d08a6 268 break;
tass 68:0847e35d08a6 269
tass 68:0847e35d08a6 270 case PICO_IP_MULTICAST_EXCLUDE:
tass 68:0847e35d08a6 271 /* filter = EXCLUDE - INCLUDE */
tass 68:0847e35d08a6 272 /* delete from the interface INCLUDE filter any source NOT in the socket EXCLUDE filter */
tass 68:0847e35d08a6 273 pico_tree_foreach_safe(index2, &MCASTFilter, _tmp2)
tass 68:0847e35d08a6 274 {
tass 68:0847e35d08a6 275 source = pico_tree_findKey(&listen->MCASTSources, index2->keyValue);
tass 68:0847e35d08a6 276 if (!source)
tass 68:0847e35d08a6 277 pico_tree_delete(&MCASTFilter, index2->keyValue);
tass 68:0847e35d08a6 278 }
tass 68:0847e35d08a6 279 /* any record with filter mode EXCLUDE, causes the interface mode to be EXCLUDE */
tass 68:0847e35d08a6 280 filter_mode = PICO_IP_MULTICAST_EXCLUDE;
tass 68:0847e35d08a6 281 /* add to the interface EXCLUDE filter any socket source NOT in the former interface INCLUDE filter */
tass 68:0847e35d08a6 282 pico_tree_foreach(index2, &listen->MCASTSources)
tass 68:0847e35d08a6 283 {
tass 68:0847e35d08a6 284 source = pico_tree_insert(&MCASTFilter, index2->keyValue);
tass 68:0847e35d08a6 285 if (source)
tass 68:0847e35d08a6 286 pico_tree_delete(&MCASTFilter, source);
tass 68:0847e35d08a6 287 }
tass 68:0847e35d08a6 288 break;
tass 68:0847e35d08a6 289
tass 68:0847e35d08a6 290 default:
tass 68:0847e35d08a6 291 return -1;
tass 68:0847e35d08a6 292 }
tass 68:0847e35d08a6 293 break;
tass 68:0847e35d08a6 294
tass 68:0847e35d08a6 295 case PICO_IP_MULTICAST_EXCLUDE:
tass 68:0847e35d08a6 296 switch (listen->filter_mode)
tass 68:0847e35d08a6 297 {
tass 68:0847e35d08a6 298 case PICO_IP_MULTICAST_INCLUDE:
tass 68:0847e35d08a6 299 /* filter = EXCLUDE - INCLUDE */
tass 68:0847e35d08a6 300 /* any record with filter mode EXCLUDE, causes the interface mode to be EXCLUDE */
tass 68:0847e35d08a6 301 /* remove from the interface EXCLUDE filter any source in the socket INCLUDE filter */
tass 68:0847e35d08a6 302 pico_tree_foreach(index2, &listen->MCASTSources)
tass 68:0847e35d08a6 303 {
tass 68:0847e35d08a6 304 source = pico_tree_findKey(&MCASTFilter, index2->keyValue);
tass 68:0847e35d08a6 305 if (source)
tass 68:0847e35d08a6 306 pico_tree_delete(&MCASTFilter, source);
tass 68:0847e35d08a6 307 }
tass 68:0847e35d08a6 308 break;
tass 68:0847e35d08a6 309
tass 68:0847e35d08a6 310 case PICO_IP_MULTICAST_EXCLUDE:
tass 68:0847e35d08a6 311 /* filter = intersection of EXCLUDEs */
tass 68:0847e35d08a6 312 /* any record with filter mode EXCLUDE, causes the interface mode to be EXCLUDE */
tass 68:0847e35d08a6 313 /* remove from the interface EXCLUDE filter any source not in the socket EXCLUDE filter */
tass 68:0847e35d08a6 314 pico_tree_foreach_safe(index2, &MCASTFilter, _tmp2)
tass 68:0847e35d08a6 315 {
tass 68:0847e35d08a6 316 source = pico_tree_findKey(&listen->MCASTSources, index2->keyValue);
tass 68:0847e35d08a6 317 if (!source)
tass 68:0847e35d08a6 318 pico_tree_delete(&MCASTFilter, index2->keyValue);
tass 68:0847e35d08a6 319 }
tass 68:0847e35d08a6 320 break;
tass 68:0847e35d08a6 321
tass 68:0847e35d08a6 322 default:
tass 68:0847e35d08a6 323 return -1;
tass 68:0847e35d08a6 324 }
tass 68:0847e35d08a6 325 break;
tass 68:0847e35d08a6 326
tass 68:0847e35d08a6 327 default:
tass 68:0847e35d08a6 328 return -1;
tass 68:0847e35d08a6 329 }
tass 68:0847e35d08a6 330 }
tass 68:0847e35d08a6 331 }
tass 68:0847e35d08a6 332 return filter_mode;
tass 68:0847e35d08a6 333 }
tass 68:0847e35d08a6 334
tass 68:0847e35d08a6 335 static int pico_socket_mcast_filter(struct pico_socket *s, struct pico_ip4 *mcast_group, struct pico_ip4 *src)
tass 68:0847e35d08a6 336 {
tass 68:0847e35d08a6 337 struct pico_ipv4_link *mcast_link = NULL;
tass 74:c146c4e346c4 338 struct pico_mcast_listen *listen = NULL;
tass 68:0847e35d08a6 339 struct pico_tree_node *index = NULL;
tass 68:0847e35d08a6 340
tass 68:0847e35d08a6 341 /* no multicast enabled on socket */
tass 68:0847e35d08a6 342 if (!s->MCASTListen)
tass 68:0847e35d08a6 343 return 0;
tass 68:0847e35d08a6 344
tass 68:0847e35d08a6 345 mcast_link = pico_ipv4_link_get(&s->local_addr.ip4);
tass 68:0847e35d08a6 346 if (!mcast_link)
tass 68:0847e35d08a6 347 return -1;
tass 74:c146c4e346c4 348 listen = listen_find(s, &mcast_link->address, mcast_group);
tass 68:0847e35d08a6 349 if (!listen)
tass 68:0847e35d08a6 350 return -1;
tass 68:0847e35d08a6 351
tass 68:0847e35d08a6 352 /* perform source filtering */
tass 68:0847e35d08a6 353 switch (listen->filter_mode)
tass 68:0847e35d08a6 354 {
tass 68:0847e35d08a6 355 case PICO_IP_MULTICAST_INCLUDE:
tass 68:0847e35d08a6 356 pico_tree_foreach(index, &listen->MCASTSources)
tass 68:0847e35d08a6 357 {
tass 68:0847e35d08a6 358 if (src->addr == ((struct pico_ip4 *)index->keyValue)->addr) {
tass 68:0847e35d08a6 359 so_mcast_dbg("MCAST: IP %08X in included socket source list\n", src->addr);
tass 68:0847e35d08a6 360 return 0;
tass 68:0847e35d08a6 361 }
tass 68:0847e35d08a6 362 }
tass 68:0847e35d08a6 363 so_mcast_dbg("MCAST: IP %08X NOT in included socket source list\n", src->addr);
tass 68:0847e35d08a6 364 return -1;
tass 68:0847e35d08a6 365 break;
tass 68:0847e35d08a6 366
tass 68:0847e35d08a6 367 case PICO_IP_MULTICAST_EXCLUDE:
tass 68:0847e35d08a6 368 pico_tree_foreach(index, &listen->MCASTSources)
tass 68:0847e35d08a6 369 {
tass 68:0847e35d08a6 370 if (src->addr == ((struct pico_ip4 *)index->keyValue)->addr) {
tass 68:0847e35d08a6 371 so_mcast_dbg("MCAST: IP %08X in excluded socket source list\n", src->addr);
tass 68:0847e35d08a6 372 return -1;
tass 68:0847e35d08a6 373 }
tass 68:0847e35d08a6 374 }
tass 68:0847e35d08a6 375 so_mcast_dbg("MCAST: IP %08X NOT in excluded socket source list\n", src->addr);
tass 68:0847e35d08a6 376 return 0;
tass 68:0847e35d08a6 377 break;
tass 68:0847e35d08a6 378
tass 68:0847e35d08a6 379 default:
tass 68:0847e35d08a6 380 return -1;
tass 68:0847e35d08a6 381 break;
tass 68:0847e35d08a6 382 }
tass 68:0847e35d08a6 383 return -1;
tass 68:0847e35d08a6 384 }
tass 68:0847e35d08a6 385
tass 68:0847e35d08a6 386 static inline struct pico_ipv4_link *pico_socket_setoption_mcastargs_validation(struct pico_ip_mreq *mreq, struct pico_ip_mreq_source *mreq_source)
tass 68:0847e35d08a6 387 {
tass 68:0847e35d08a6 388 struct pico_ipv4_link *mcast_link = NULL;
tass 68:0847e35d08a6 389
tass 68:0847e35d08a6 390 if (!mreq && !mreq_source)
tass 68:0847e35d08a6 391 return NULL;
tass 68:0847e35d08a6 392
tass 68:0847e35d08a6 393 if (mreq) {
tass 68:0847e35d08a6 394 if (!mreq->mcast_group_addr.addr)
tass 68:0847e35d08a6 395 return NULL;
tass 68:0847e35d08a6 396 if (pico_ipv4_is_unicast(mreq->mcast_group_addr.addr))
tass 68:0847e35d08a6 397 return NULL;
tass 68:0847e35d08a6 398
tass 68:0847e35d08a6 399 if (!mreq->mcast_link_addr.addr) {
tass 68:0847e35d08a6 400 mcast_link = pico_ipv4_get_default_mcastlink();
tass 68:0847e35d08a6 401 if (!mcast_link)
tass 68:0847e35d08a6 402 return NULL;
tass 68:0847e35d08a6 403 } else {
tass 68:0847e35d08a6 404 mcast_link = pico_ipv4_link_get(&mreq->mcast_link_addr);
tass 68:0847e35d08a6 405 if (!mcast_link)
tass 68:0847e35d08a6 406 return NULL;
tass 68:0847e35d08a6 407 }
tass 68:0847e35d08a6 408 }
tass 68:0847e35d08a6 409 if (mreq_source) {
tass 68:0847e35d08a6 410 if (!mreq_source->mcast_group_addr.addr)
tass 68:0847e35d08a6 411 return NULL;
tass 68:0847e35d08a6 412 if (pico_ipv4_is_unicast(mreq_source->mcast_group_addr.addr))
tass 68:0847e35d08a6 413 return NULL;
tass 68:0847e35d08a6 414
tass 68:0847e35d08a6 415 if (!mreq_source->mcast_source_addr.addr)
tass 68:0847e35d08a6 416 return NULL;
tass 68:0847e35d08a6 417 if (!pico_ipv4_is_unicast(mreq_source->mcast_source_addr.addr))
tass 68:0847e35d08a6 418 return NULL;
tass 68:0847e35d08a6 419
tass 68:0847e35d08a6 420 if (!mreq_source->mcast_link_addr.addr) {
tass 68:0847e35d08a6 421 mcast_link = pico_ipv4_get_default_mcastlink();
tass 68:0847e35d08a6 422 if (!mcast_link)
tass 68:0847e35d08a6 423 return NULL;
tass 68:0847e35d08a6 424 } else {
tass 68:0847e35d08a6 425 mcast_link = pico_ipv4_link_get(&mreq_source->mcast_link_addr);
tass 68:0847e35d08a6 426 if (!mcast_link)
tass 68:0847e35d08a6 427 return NULL;
tass 68:0847e35d08a6 428 }
tass 68:0847e35d08a6 429 }
tass 68:0847e35d08a6 430 return mcast_link;
tass 68:0847e35d08a6 431 }
tass 68:0847e35d08a6 432 #else
tass 68:0847e35d08a6 433 static int pico_socket_mcast_filter(struct pico_socket *s, struct pico_ip4 *mcast_group, struct pico_ip4 *src) {
tass 68:0847e35d08a6 434 return 0;
tass 68:0847e35d08a6 435 }
tass 68:0847e35d08a6 436 #endif /* PICO_SUPPORT_MCAST */
tass 68:0847e35d08a6 437
tass 68:0847e35d08a6 438 static struct pico_sockport *pico_get_sockport(uint16_t proto, uint16_t port)
tass 68:0847e35d08a6 439 {
tass 68:0847e35d08a6 440 struct pico_sockport test = INIT_SOCKPORT;
tass 68:0847e35d08a6 441 test.number = port;
tass 68:0847e35d08a6 442
tass 68:0847e35d08a6 443 if (proto == PICO_PROTO_UDP)
tass 68:0847e35d08a6 444 return pico_tree_findKey(&UDPTable,&test);
tass 68:0847e35d08a6 445
tass 68:0847e35d08a6 446 else if (proto == PICO_PROTO_TCP)
tass 68:0847e35d08a6 447 return pico_tree_findKey(&TCPTable,&test);
tass 68:0847e35d08a6 448
tass 68:0847e35d08a6 449 else return NULL;
tass 68:0847e35d08a6 450 }
tass 68:0847e35d08a6 451
tass 68:0847e35d08a6 452 int pico_is_port_free(uint16_t proto, uint16_t port, void *addr, void *net)
tass 68:0847e35d08a6 453 {
tass 68:0847e35d08a6 454 struct pico_sockport *sp;
tass 68:0847e35d08a6 455 struct pico_ip4 ip;
tass 68:0847e35d08a6 456 sp = pico_get_sockport(proto, port);
tass 68:0847e35d08a6 457
tass 68:0847e35d08a6 458 if (!net)
tass 68:0847e35d08a6 459 net = &pico_proto_ipv4;
tass 68:0847e35d08a6 460
tass 68:0847e35d08a6 461 /** IPv6 (wip) ***/
tass 68:0847e35d08a6 462 if (net != &pico_proto_ipv4) {
tass 68:0847e35d08a6 463 dbg("IPV6!!!!!\n");
tass 68:0847e35d08a6 464 return (!sp);
tass 68:0847e35d08a6 465 }
tass 68:0847e35d08a6 466
tass 68:0847e35d08a6 467 /* IPv4 */
tass 68:0847e35d08a6 468 #ifdef PICO_SUPPORT_NAT
tass 70:cd218dd180e5 469 if (pico_ipv4_nat_find(port, NULL, 0, (uint8_t)proto)) {
tass 68:0847e35d08a6 470 dbg("In use by nat....\n");
tass 68:0847e35d08a6 471 return 0;
tass 68:0847e35d08a6 472 }
tass 68:0847e35d08a6 473 #endif
tass 68:0847e35d08a6 474 if (addr)
tass 68:0847e35d08a6 475 ip.addr = ((struct pico_ip4 *)addr)->addr;
tass 68:0847e35d08a6 476 else
tass 68:0847e35d08a6 477 ip.addr = PICO_IPV4_INADDR_ANY;
tass 68:0847e35d08a6 478
tass 68:0847e35d08a6 479 if (ip.addr == PICO_IPV4_INADDR_ANY) {
tass 68:0847e35d08a6 480 if (!sp) return 1;
tass 68:0847e35d08a6 481 else {
tass 68:0847e35d08a6 482 dbg("In use, and asked for ANY\n");
tass 68:0847e35d08a6 483 return 0;
tass 68:0847e35d08a6 484 }
tass 68:0847e35d08a6 485 }
tass 68:0847e35d08a6 486 if (sp) {
tass 68:0847e35d08a6 487 struct pico_ip4 *s_local;
tass 68:0847e35d08a6 488 struct pico_tree_node *idx;
tass 68:0847e35d08a6 489 struct pico_socket *s;
tass 68:0847e35d08a6 490 pico_tree_foreach(idx, &sp->socks) {
tass 68:0847e35d08a6 491 s = idx->keyValue;
tass 68:0847e35d08a6 492 if (s->net == &pico_proto_ipv4) {
tass 68:0847e35d08a6 493 s_local = (struct pico_ip4*) &s->local_addr;
tass 68:0847e35d08a6 494 if ((s_local->addr == PICO_IPV4_INADDR_ANY) || (s_local->addr == ip.addr))
tass 68:0847e35d08a6 495 return 0;
tass 68:0847e35d08a6 496 }
tass 68:0847e35d08a6 497 }
tass 68:0847e35d08a6 498 }
tass 68:0847e35d08a6 499 return 1;
tass 68:0847e35d08a6 500 }
tass 68:0847e35d08a6 501
tass 68:0847e35d08a6 502 static int pico_check_socket(struct pico_socket *s)
tass 68:0847e35d08a6 503 {
tass 68:0847e35d08a6 504 struct pico_sockport *test;
tass 68:0847e35d08a6 505 struct pico_socket *found;
tass 68:0847e35d08a6 506 struct pico_tree_node * index;
tass 68:0847e35d08a6 507
tass 68:0847e35d08a6 508 test = pico_get_sockport(PROTO(s), s->local_port);
tass 68:0847e35d08a6 509
tass 68:0847e35d08a6 510 if (!test) {
tass 68:0847e35d08a6 511 return -1;
tass 68:0847e35d08a6 512 }
tass 68:0847e35d08a6 513
tass 68:0847e35d08a6 514 pico_tree_foreach(index,&test->socks){
tass 68:0847e35d08a6 515 found = index->keyValue;
tass 68:0847e35d08a6 516 if (s == found) {
tass 68:0847e35d08a6 517 return 0;
tass 68:0847e35d08a6 518 }
tass 68:0847e35d08a6 519 }
tass 68:0847e35d08a6 520
tass 68:0847e35d08a6 521 return -1;
tass 68:0847e35d08a6 522 }
tass 68:0847e35d08a6 523
tass 68:0847e35d08a6 524 struct pico_socket* pico_sockets_find(uint16_t local,uint16_t remote)
tass 68:0847e35d08a6 525 {
tass 68:0847e35d08a6 526 struct pico_socket * sock = NULL;
tass 68:0847e35d08a6 527 struct pico_tree_node *index = NULL;
tass 68:0847e35d08a6 528 struct pico_sockport *sp = NULL;
tass 68:0847e35d08a6 529
tass 68:0847e35d08a6 530 sp = pico_get_sockport(PICO_PROTO_TCP,local);
tass 68:0847e35d08a6 531 if(sp)
tass 68:0847e35d08a6 532 {
tass 68:0847e35d08a6 533 pico_tree_foreach(index,&sp->socks)
tass 68:0847e35d08a6 534 {
tass 68:0847e35d08a6 535 if( ((struct pico_socket *)index->keyValue)->remote_port == remote)
tass 68:0847e35d08a6 536 {
tass 68:0847e35d08a6 537 sock = (struct pico_socket *)index->keyValue;
tass 68:0847e35d08a6 538 break;
tass 68:0847e35d08a6 539 }
tass 68:0847e35d08a6 540 }
tass 68:0847e35d08a6 541 }
tass 68:0847e35d08a6 542
tass 68:0847e35d08a6 543 return sock;
tass 68:0847e35d08a6 544 }
tass 68:0847e35d08a6 545
tass 68:0847e35d08a6 546
tass 70:cd218dd180e5 547 int8_t pico_socket_add(struct pico_socket *s)
tass 68:0847e35d08a6 548 {
tass 68:0847e35d08a6 549 struct pico_sockport *sp = pico_get_sockport(PROTO(s), s->local_port);
tass 68:0847e35d08a6 550 LOCK(Mutex);
tass 68:0847e35d08a6 551 if (!sp) {
tass 68:0847e35d08a6 552 //dbg("Creating sockport..%04x\n", s->local_port); /* In comment due to spam during test */
tass 68:0847e35d08a6 553 sp = pico_zalloc(sizeof(struct pico_sockport));
tass 68:0847e35d08a6 554
tass 68:0847e35d08a6 555 if (!sp) {
tass 68:0847e35d08a6 556 pico_err = PICO_ERR_ENOMEM;
tass 68:0847e35d08a6 557 UNLOCK(Mutex);
tass 68:0847e35d08a6 558 return -1;
tass 68:0847e35d08a6 559 }
tass 68:0847e35d08a6 560 sp->proto = PROTO(s);
tass 68:0847e35d08a6 561 sp->number = s->local_port;
tass 68:0847e35d08a6 562 sp->socks.root = &LEAF;
tass 68:0847e35d08a6 563 sp->socks.compare = socket_cmp;
tass 68:0847e35d08a6 564
tass 68:0847e35d08a6 565 if (PROTO(s) == PICO_PROTO_UDP)
tass 68:0847e35d08a6 566 {
tass 68:0847e35d08a6 567 pico_tree_insert(&UDPTable,sp);
tass 68:0847e35d08a6 568 }
tass 68:0847e35d08a6 569 else if (PROTO(s) == PICO_PROTO_TCP)
tass 68:0847e35d08a6 570 {
tass 68:0847e35d08a6 571 pico_tree_insert(&TCPTable,sp);
tass 68:0847e35d08a6 572 }
tass 68:0847e35d08a6 573 }
tass 68:0847e35d08a6 574
tass 68:0847e35d08a6 575 pico_tree_insert(&sp->socks,s);
tass 68:0847e35d08a6 576 s->state |= PICO_SOCKET_STATE_BOUND;
tass 68:0847e35d08a6 577 UNLOCK(Mutex);
tass 68:0847e35d08a6 578 #if DEBUG_SOCKET_TREE
tass 68:0847e35d08a6 579 {
tass 68:0847e35d08a6 580 struct pico_tree_node * index;
tass 68:0847e35d08a6 581 //RB_FOREACH(s, socket_tree, &sp->socks) {
tass 68:0847e35d08a6 582 pico_tree_foreach(index,&sp->socks){
tass 68:0847e35d08a6 583 s = index->keyValue;
tass 68:0847e35d08a6 584 dbg(">>>> List Socket lc=%hu rm=%hu\n", short_be(s->local_port), short_be(s->remote_port));
tass 68:0847e35d08a6 585 }
tass 68:0847e35d08a6 586
tass 68:0847e35d08a6 587 }
tass 68:0847e35d08a6 588 #endif
tass 68:0847e35d08a6 589 return 0;
tass 68:0847e35d08a6 590 }
tass 68:0847e35d08a6 591
tass 68:0847e35d08a6 592 static void socket_clean_queues(struct pico_socket *sock)
tass 68:0847e35d08a6 593 {
tass 68:0847e35d08a6 594 struct pico_frame * f_in = pico_dequeue(&sock->q_in);
tass 68:0847e35d08a6 595 struct pico_frame * f_out = pico_dequeue(&sock->q_out);
tass 68:0847e35d08a6 596 while(f_in || f_out)
tass 68:0847e35d08a6 597 {
tass 68:0847e35d08a6 598 if(f_in)
tass 68:0847e35d08a6 599 {
tass 68:0847e35d08a6 600 pico_frame_discard(f_in);
tass 68:0847e35d08a6 601 f_in = pico_dequeue(&sock->q_in);
tass 68:0847e35d08a6 602 }
tass 68:0847e35d08a6 603
tass 68:0847e35d08a6 604 if(f_out)
tass 68:0847e35d08a6 605 {
tass 68:0847e35d08a6 606 pico_frame_discard(f_out);
tass 68:0847e35d08a6 607 f_out = pico_dequeue(&sock->q_out);
tass 68:0847e35d08a6 608 }
tass 68:0847e35d08a6 609 }
tass 68:0847e35d08a6 610 // for tcp sockets go further and clean the sockets inside queue
tass 68:0847e35d08a6 611 if(sock->proto == &pico_proto_tcp)
tass 68:0847e35d08a6 612 pico_tcp_cleanup_queues(sock);
tass 68:0847e35d08a6 613 }
tass 68:0847e35d08a6 614
tass 128:ae39e6e81531 615 static void socket_garbage_collect(pico_time now, void *arg)
tass 68:0847e35d08a6 616 {
tass 68:0847e35d08a6 617 struct pico_socket *s = (struct pico_socket *) arg;
tass 68:0847e35d08a6 618 IGNORE_PARAMETER(now);
tass 128:ae39e6e81531 619
tass 128:ae39e6e81531 620 if(s->parent)
tass 128:ae39e6e81531 621 s->parent->number_of_pending_conn--;
tass 128:ae39e6e81531 622
tass 68:0847e35d08a6 623 socket_clean_queues(s);
tass 68:0847e35d08a6 624 pico_free(s);
tass 68:0847e35d08a6 625 }
tass 68:0847e35d08a6 626
tass 70:cd218dd180e5 627 int8_t pico_socket_del(struct pico_socket *s)
tass 68:0847e35d08a6 628 {
tass 68:0847e35d08a6 629 struct pico_sockport *sp = pico_get_sockport(PROTO(s), s->local_port);
tass 68:0847e35d08a6 630
tass 68:0847e35d08a6 631 if (!sp) {
tass 68:0847e35d08a6 632 pico_err = PICO_ERR_ENXIO;
tass 68:0847e35d08a6 633 return -1;
tass 68:0847e35d08a6 634 }
tass 68:0847e35d08a6 635
tass 68:0847e35d08a6 636 LOCK(Mutex);
tass 68:0847e35d08a6 637 pico_tree_delete(&sp->socks,s);
tass 68:0847e35d08a6 638 s->net = NULL;
tass 68:0847e35d08a6 639 if(pico_tree_empty(&sp->socks)){
tass 68:0847e35d08a6 640 if (PROTO(s) == PICO_PROTO_UDP)
tass 68:0847e35d08a6 641 {
tass 68:0847e35d08a6 642 pico_tree_delete(&UDPTable,sp);
tass 68:0847e35d08a6 643 }
tass 68:0847e35d08a6 644 else if (PROTO(s) == PICO_PROTO_TCP)
tass 68:0847e35d08a6 645 {
tass 68:0847e35d08a6 646 pico_tree_delete(&TCPTable,sp);
tass 68:0847e35d08a6 647 }
tass 68:0847e35d08a6 648
tass 68:0847e35d08a6 649 if(sp_tcp == sp) sp_tcp = NULL;
tass 68:0847e35d08a6 650
tass 68:0847e35d08a6 651 if(sp_udp == sp) sp_udp = NULL;
tass 68:0847e35d08a6 652
tass 68:0847e35d08a6 653 pico_free(sp);
tass 68:0847e35d08a6 654
tass 68:0847e35d08a6 655 }
tass 68:0847e35d08a6 656
tass 68:0847e35d08a6 657 #ifdef PICO_SUPPORT_MCAST
tass 68:0847e35d08a6 658 do {
tass 68:0847e35d08a6 659 int filter_mode;
tass 68:0847e35d08a6 660 struct pico_tree_node *index = NULL, *_tmp = NULL, *index2 = NULL, *_tmp2 = NULL;
tass 68:0847e35d08a6 661 struct pico_mcast_listen *listen = NULL;
tass 68:0847e35d08a6 662 struct pico_ip4 *source = NULL;
tass 68:0847e35d08a6 663 if (s->MCASTListen) {
tass 68:0847e35d08a6 664 pico_tree_delete(&MCASTSockets, s);
tass 68:0847e35d08a6 665 pico_tree_foreach_safe(index, s->MCASTListen, _tmp)
tass 68:0847e35d08a6 666 {
tass 68:0847e35d08a6 667 listen = index->keyValue;
tass 68:0847e35d08a6 668 pico_tree_foreach_safe(index2, &listen->MCASTSources, _tmp2)
tass 68:0847e35d08a6 669 {
tass 68:0847e35d08a6 670 source = index->keyValue;
tass 68:0847e35d08a6 671 pico_tree_delete(&listen->MCASTSources, source);
tass 68:0847e35d08a6 672 pico_free(source);
tass 68:0847e35d08a6 673 }
tass 68:0847e35d08a6 674 filter_mode = pico_socket_aggregate_mcastfilters(&listen->mcast_link, &listen->mcast_group);
tass 68:0847e35d08a6 675 if (filter_mode >= 0)
tass 70:cd218dd180e5 676 pico_ipv4_mcast_leave(&listen->mcast_link, &listen->mcast_group, 1, (uint8_t)filter_mode, &MCASTFilter);
tass 68:0847e35d08a6 677 pico_tree_delete(s->MCASTListen, listen);
tass 68:0847e35d08a6 678 pico_free(listen);
tass 68:0847e35d08a6 679 }
tass 68:0847e35d08a6 680 pico_free(s->MCASTListen);
tass 68:0847e35d08a6 681 }
tass 68:0847e35d08a6 682 } while (0);
tass 68:0847e35d08a6 683 #endif
tass 68:0847e35d08a6 684
tass 68:0847e35d08a6 685 s->state = PICO_SOCKET_STATE_CLOSED;
tass 68:0847e35d08a6 686 pico_timer_add(3000, socket_garbage_collect, s);
tass 68:0847e35d08a6 687 UNLOCK(Mutex);
tass 68:0847e35d08a6 688 return 0;
tass 68:0847e35d08a6 689 }
tass 68:0847e35d08a6 690
tass 70:cd218dd180e5 691 static int8_t pico_socket_alter_state(struct pico_socket *s, uint16_t more_states, uint16_t less_states, uint16_t tcp_state)
tass 68:0847e35d08a6 692 {
tass 68:0847e35d08a6 693 struct pico_sockport *sp;
tass 68:0847e35d08a6 694 if (more_states & PICO_SOCKET_STATE_BOUND)
tass 68:0847e35d08a6 695 return pico_socket_add(s);
tass 68:0847e35d08a6 696
tass 68:0847e35d08a6 697 if (less_states & PICO_SOCKET_STATE_BOUND)
tass 68:0847e35d08a6 698 return pico_socket_del(s);
tass 68:0847e35d08a6 699
tass 68:0847e35d08a6 700 sp = pico_get_sockport(PROTO(s), s->local_port);
tass 68:0847e35d08a6 701 if (!sp) {
tass 68:0847e35d08a6 702 pico_err = PICO_ERR_ENXIO;
tass 68:0847e35d08a6 703 return -1;
tass 68:0847e35d08a6 704 }
tass 68:0847e35d08a6 705
tass 68:0847e35d08a6 706 s->state |= more_states;
tass 73:dfb737147f6e 707 s->state = (uint16_t)(s->state & (~less_states));
tass 68:0847e35d08a6 708 if (tcp_state) {
tass 68:0847e35d08a6 709 s->state &= 0x00FF;
tass 68:0847e35d08a6 710 s->state |= tcp_state;
tass 68:0847e35d08a6 711 }
tass 68:0847e35d08a6 712
tass 68:0847e35d08a6 713 return 0;
tass 68:0847e35d08a6 714 }
tass 68:0847e35d08a6 715
tass 68:0847e35d08a6 716 static int pico_socket_deliver(struct pico_protocol *p, struct pico_frame *f, uint16_t localport)
tass 68:0847e35d08a6 717 {
tass 68:0847e35d08a6 718 struct pico_frame *cpy = NULL;
tass 68:0847e35d08a6 719 struct pico_sockport *sp = NULL;
tass 125:96003ae6f1d8 720 struct pico_socket *s = NULL;
tass 68:0847e35d08a6 721 struct pico_tree_node *index = NULL;
tass 68:0847e35d08a6 722 struct pico_tree_node *_tmp;
tass 68:0847e35d08a6 723 struct pico_trans *tr = (struct pico_trans *) f->transport_hdr;
tass 68:0847e35d08a6 724 #ifdef PICO_SUPPORT_IPV4
tass 68:0847e35d08a6 725 struct pico_ipv4_hdr *ip4hdr;
tass 68:0847e35d08a6 726 #endif
tass 68:0847e35d08a6 727 #ifdef PICO_SUPPORT_IPV6
tass 68:0847e35d08a6 728 struct pico_ipv6_hdr *ip6hdr;
tass 68:0847e35d08a6 729 #endif
tass 68:0847e35d08a6 730
tass 125:96003ae6f1d8 731 #ifdef PICO_SUPPORT_TCP
tass 125:96003ae6f1d8 732 struct pico_socket *found = NULL;
tass 125:96003ae6f1d8 733 #endif
tass 125:96003ae6f1d8 734
tass 68:0847e35d08a6 735 if (!tr)
tass 68:0847e35d08a6 736 return -1;
tass 68:0847e35d08a6 737
tass 68:0847e35d08a6 738 sp = pico_get_sockport(p->proto_number, localport);
tass 68:0847e35d08a6 739
tass 68:0847e35d08a6 740 if (!sp) {
tass 68:0847e35d08a6 741 dbg("No such port %d\n",short_be(localport));
tass 68:0847e35d08a6 742 return -1;
tass 68:0847e35d08a6 743 }
tass 68:0847e35d08a6 744
tass 68:0847e35d08a6 745 #ifdef PICO_SUPPORT_TCP
tass 68:0847e35d08a6 746 if (p->proto_number == PICO_PROTO_TCP) {
tass 68:0847e35d08a6 747 pico_tree_foreach_safe(index,&sp->socks, _tmp){
tass 68:0847e35d08a6 748 s = index->keyValue;
tass 68:0847e35d08a6 749 /* 4-tuple identification of socket (port-IP) */
tass 68:0847e35d08a6 750 #ifdef PICO_SUPPORT_IPV4
tass 68:0847e35d08a6 751 if (IS_IPV4(f)) {
tass 68:0847e35d08a6 752 struct pico_ip4 s_local, s_remote, p_src, p_dst;
tass 68:0847e35d08a6 753 ip4hdr = (struct pico_ipv4_hdr*)(f->net_hdr);
tass 68:0847e35d08a6 754 s_local.addr = s->local_addr.ip4.addr;
tass 68:0847e35d08a6 755 s_remote.addr = s->remote_addr.ip4.addr;
tass 68:0847e35d08a6 756 p_src.addr = ip4hdr->src.addr;
tass 68:0847e35d08a6 757 p_dst.addr = ip4hdr->dst.addr;
tass 68:0847e35d08a6 758 if ( (s->remote_port == tr->sport) && /* remote port check */
tass 68:0847e35d08a6 759 (s_remote.addr == p_src.addr) && /* remote addr check */
tass 68:0847e35d08a6 760 ((s_local.addr == PICO_IPV4_INADDR_ANY) || (s_local.addr == p_dst.addr))) { /* Either local socket is ANY, or matches dst */
tass 68:0847e35d08a6 761 found = s;
tass 68:0847e35d08a6 762 break;
tass 68:0847e35d08a6 763 } else if ( (s->remote_port == 0) && /* not connected... listening */
tass 68:0847e35d08a6 764 ((s_local.addr == PICO_IPV4_INADDR_ANY) || (s_local.addr == p_dst.addr))) { /* Either local socket is ANY, or matches dst */
tass 68:0847e35d08a6 765 /* listen socket */
tass 68:0847e35d08a6 766 found = s;
tass 68:0847e35d08a6 767 }
tass 68:0847e35d08a6 768 }
tass 68:0847e35d08a6 769 #endif
tass 68:0847e35d08a6 770 #ifdef PICO_SUPPORT_IPV6 /* XXX TODO make compare for ipv6 addresses */
tass 68:0847e35d08a6 771 if (IS_IPV6(f)) {
tass 68:0847e35d08a6 772 ip6hdr = (struct pico_ipv6_hdr*)(f->net_hdr);
tass 68:0847e35d08a6 773 if ( (s->remote_port == localport) ) { // && (((struct pico_ip6) s->remote_addr.ip6).addr == ((struct pico_ip6)(ip6hdr->src)).addr) ) {
tass 68:0847e35d08a6 774 found = s;
tass 68:0847e35d08a6 775 break;
tass 68:0847e35d08a6 776 } else if (s->remote_port == 0) {
tass 68:0847e35d08a6 777 /* listen socket */
tass 68:0847e35d08a6 778 found = s;
tass 68:0847e35d08a6 779 }
tass 68:0847e35d08a6 780 }
tass 68:0847e35d08a6 781 #endif
tass 68:0847e35d08a6 782 } /* FOREACH */
tass 68:0847e35d08a6 783 if (found != NULL) {
tass 68:0847e35d08a6 784 pico_tcp_input(found,f);
tass 68:0847e35d08a6 785 if ((found->ev_pending) && found->wakeup) {
tass 68:0847e35d08a6 786 found->wakeup(found->ev_pending, found);
tass 122:5b1e9de8bf7f 787 if(!found->parent)
tass 122:5b1e9de8bf7f 788 found->ev_pending = 0;
tass 68:0847e35d08a6 789 }
tass 68:0847e35d08a6 790 return 0;
tass 68:0847e35d08a6 791 } else {
tass 68:0847e35d08a6 792 dbg("SOCKET> mmm something wrong (prob sockport)\n");
tass 68:0847e35d08a6 793 return -1;
tass 68:0847e35d08a6 794 }
tass 68:0847e35d08a6 795 } /* TCP CASE */
tass 68:0847e35d08a6 796 #endif
tass 68:0847e35d08a6 797
tass 68:0847e35d08a6 798 #ifdef PICO_SUPPORT_UDP
tass 68:0847e35d08a6 799 if (p->proto_number == PICO_PROTO_UDP) {
tass 68:0847e35d08a6 800 pico_tree_foreach_safe(index,&sp->socks, _tmp){
tass 68:0847e35d08a6 801 s = index->keyValue;
tass 68:0847e35d08a6 802 if (IS_IPV4(f)) { /* IPV4 */
tass 68:0847e35d08a6 803 struct pico_ip4 s_local, p_dst;
tass 68:0847e35d08a6 804 ip4hdr = (struct pico_ipv4_hdr*)(f->net_hdr);
tass 68:0847e35d08a6 805 s_local.addr = s->local_addr.ip4.addr;
tass 68:0847e35d08a6 806 p_dst.addr = ip4hdr->dst.addr;
tass 68:0847e35d08a6 807 if ((pico_ipv4_is_broadcast(p_dst.addr)) || pico_ipv4_is_multicast(p_dst.addr)) {
tass 68:0847e35d08a6 808 struct pico_device *dev = pico_ipv4_link_find(&s->local_addr.ip4);
tass 68:0847e35d08a6 809 if (pico_ipv4_is_multicast(p_dst.addr) && (pico_socket_mcast_filter(s, &ip4hdr->dst, &ip4hdr->src) < 0))
tass 68:0847e35d08a6 810 return -1;
tass 68:0847e35d08a6 811 if ((s_local.addr == PICO_IPV4_INADDR_ANY) || /* If our local ip is ANY, or.. */
tass 68:0847e35d08a6 812 (dev == f->dev) ) { /* the source of the bcast packet is a neighbor... */
tass 68:0847e35d08a6 813 cpy = pico_frame_copy(f);
tass 68:0847e35d08a6 814 if (!cpy)
tass 68:0847e35d08a6 815 return -1;
tass 68:0847e35d08a6 816 if (pico_enqueue(&s->q_in, cpy) > 0) {
tass 68:0847e35d08a6 817 if (s->wakeup)
tass 68:0847e35d08a6 818 s->wakeup(PICO_SOCK_EV_RD, s);
tass 68:0847e35d08a6 819 }
tass 110:0ece1bbbd36e 820 else
tass 110:0ece1bbbd36e 821 pico_frame_discard(cpy);
tass 110:0ece1bbbd36e 822
tass 68:0847e35d08a6 823 }
tass 68:0847e35d08a6 824 } else if ((s_local.addr == PICO_IPV4_INADDR_ANY) || (s_local.addr == p_dst.addr))
tass 68:0847e35d08a6 825 { /* Either local socket is ANY, or matches dst */
tass 68:0847e35d08a6 826 cpy = pico_frame_copy(f);
tass 68:0847e35d08a6 827 if (!cpy)
tass 68:0847e35d08a6 828 return -1;
tass 68:0847e35d08a6 829 if (pico_enqueue(&s->q_in, cpy) > 0) {
tass 68:0847e35d08a6 830 if (s->wakeup)
tass 68:0847e35d08a6 831 s->wakeup(PICO_SOCK_EV_RD, s);
tass 68:0847e35d08a6 832 }
tass 110:0ece1bbbd36e 833 else
tass 110:0ece1bbbd36e 834 pico_frame_discard(cpy);
tass 68:0847e35d08a6 835 }
tass 68:0847e35d08a6 836 } else {
tass 68:0847e35d08a6 837 /*... IPv6 */
tass 68:0847e35d08a6 838 }
tass 68:0847e35d08a6 839 } /* FOREACH */
tass 68:0847e35d08a6 840 pico_frame_discard(f);
tass 68:0847e35d08a6 841 if (s)
tass 68:0847e35d08a6 842 return 0;
tass 68:0847e35d08a6 843 else
tass 68:0847e35d08a6 844 return -1;
tass 68:0847e35d08a6 845 }
tass 68:0847e35d08a6 846 #endif
tass 68:0847e35d08a6 847 return -1;
tass 68:0847e35d08a6 848 }
tass 68:0847e35d08a6 849
tass 68:0847e35d08a6 850 struct pico_socket *pico_socket_open(uint16_t net, uint16_t proto, void (*wakeup)(uint16_t ev, struct pico_socket *))
tass 68:0847e35d08a6 851 {
tass 68:0847e35d08a6 852
tass 68:0847e35d08a6 853 struct pico_socket *s = NULL;
tass 68:0847e35d08a6 854
tass 68:0847e35d08a6 855 #ifdef PICO_SUPPORT_UDP
tass 68:0847e35d08a6 856 if (proto == PICO_PROTO_UDP) {
tass 68:0847e35d08a6 857 s = pico_udp_open();
tass 68:0847e35d08a6 858 s->proto = &pico_proto_udp;
tass 110:0ece1bbbd36e 859 s->q_in.overhead = s->q_out.overhead = UDP_FRAME_OVERHEAD;
tass 68:0847e35d08a6 860 }
tass 68:0847e35d08a6 861 #endif
tass 68:0847e35d08a6 862
tass 68:0847e35d08a6 863 #ifdef PICO_SUPPORT_TCP
tass 68:0847e35d08a6 864 if (proto == PICO_PROTO_TCP) {
tass 68:0847e35d08a6 865 s = pico_tcp_open();
tass 68:0847e35d08a6 866 s->proto = &pico_proto_tcp;
tass 68:0847e35d08a6 867 /*check if Nagle enabled */
tass 68:0847e35d08a6 868 if (!IS_NAGLE_ENABLED(s))
tass 68:0847e35d08a6 869 dbg("ERROR Nagle should be enabled here\n\n");
tass 68:0847e35d08a6 870 }
tass 68:0847e35d08a6 871 #endif
tass 68:0847e35d08a6 872
tass 68:0847e35d08a6 873 if (!s) {
tass 68:0847e35d08a6 874 pico_err = PICO_ERR_EPROTONOSUPPORT;
tass 68:0847e35d08a6 875 return NULL;
tass 68:0847e35d08a6 876 }
tass 68:0847e35d08a6 877
tass 68:0847e35d08a6 878 #ifdef PICO_SUPPORT_IPV4
tass 68:0847e35d08a6 879 if (net == PICO_PROTO_IPV4)
tass 68:0847e35d08a6 880 s->net = &pico_proto_ipv4;
tass 68:0847e35d08a6 881 #endif
tass 68:0847e35d08a6 882
tass 68:0847e35d08a6 883 #ifdef PICO_SUPPORT_IPV6
tass 68:0847e35d08a6 884 if (net == PICO_PROTO_IPV6)
tass 68:0847e35d08a6 885 s->net = &pico_proto_ipv6;
tass 68:0847e35d08a6 886 #endif
tass 68:0847e35d08a6 887
tass 68:0847e35d08a6 888 s->q_in.max_size = PICO_DEFAULT_SOCKETQ;
tass 68:0847e35d08a6 889 s->q_out.max_size = PICO_DEFAULT_SOCKETQ;
tass 110:0ece1bbbd36e 890
tass 68:0847e35d08a6 891 s->wakeup = wakeup;
tass 68:0847e35d08a6 892
tass 68:0847e35d08a6 893 if (!s->net) {
tass 68:0847e35d08a6 894 pico_free(s);
tass 68:0847e35d08a6 895 pico_err = PICO_ERR_ENETUNREACH;
tass 68:0847e35d08a6 896 return NULL;
tass 68:0847e35d08a6 897 }
tass 68:0847e35d08a6 898 return s;
tass 68:0847e35d08a6 899 }
tass 68:0847e35d08a6 900
tass 68:0847e35d08a6 901
tass 68:0847e35d08a6 902 struct pico_socket *pico_socket_clone(struct pico_socket *facsimile)
tass 68:0847e35d08a6 903 {
tass 68:0847e35d08a6 904 struct pico_socket *s = NULL;
tass 68:0847e35d08a6 905
tass 68:0847e35d08a6 906 #ifdef PICO_SUPPORT_UDP
tass 68:0847e35d08a6 907 if (facsimile->proto->proto_number == PICO_PROTO_UDP) {
tass 68:0847e35d08a6 908 s = pico_udp_open();
tass 68:0847e35d08a6 909 s->proto = &pico_proto_udp;
tass 110:0ece1bbbd36e 910 s->q_in.overhead = s->q_out.overhead = UDP_FRAME_OVERHEAD;
tass 68:0847e35d08a6 911 }
tass 68:0847e35d08a6 912 #endif
tass 68:0847e35d08a6 913
tass 68:0847e35d08a6 914 #ifdef PICO_SUPPORT_TCP
tass 68:0847e35d08a6 915 if (facsimile->proto->proto_number == PICO_PROTO_TCP) {
tass 68:0847e35d08a6 916 s = pico_tcp_open();
tass 68:0847e35d08a6 917 s->proto = &pico_proto_tcp;
tass 68:0847e35d08a6 918 }
tass 68:0847e35d08a6 919 #endif
tass 68:0847e35d08a6 920
tass 68:0847e35d08a6 921 if (!s) {
tass 68:0847e35d08a6 922 pico_err = PICO_ERR_EPROTONOSUPPORT;
tass 68:0847e35d08a6 923 return NULL;
tass 68:0847e35d08a6 924 }
tass 68:0847e35d08a6 925 s->local_port = facsimile->local_port;
tass 68:0847e35d08a6 926 s->remote_port = facsimile->remote_port;
tass 68:0847e35d08a6 927 s->state = facsimile->state;
tass 68:0847e35d08a6 928
tass 68:0847e35d08a6 929 #ifdef PICO_SUPPORT_IPV4
tass 68:0847e35d08a6 930 if (facsimile->net == &pico_proto_ipv4) {
tass 68:0847e35d08a6 931 s->net = &pico_proto_ipv4;
tass 68:0847e35d08a6 932 memcpy(&s->local_addr, &facsimile->local_addr, sizeof(struct pico_ip4));
tass 68:0847e35d08a6 933 memcpy(&s->remote_addr, &facsimile->remote_addr, sizeof(struct pico_ip4));
tass 68:0847e35d08a6 934 }
tass 68:0847e35d08a6 935 #endif
tass 68:0847e35d08a6 936
tass 68:0847e35d08a6 937 #ifdef PICO_SUPPORT_IPV6
tass 68:0847e35d08a6 938 if (net == &pico_proto_ipv6) {
tass 68:0847e35d08a6 939 s->net = &pico_proto_ipv6;
tass 68:0847e35d08a6 940 memcpy(&s->local_addr, &facsimile->local_addr, sizeof(struct pico_ip6));
tass 68:0847e35d08a6 941 memcpy(&s->remote_addr, &facsimile->remote_addr, sizeof(struct pico_ip6));
tass 68:0847e35d08a6 942 }
tass 68:0847e35d08a6 943 #endif
tass 68:0847e35d08a6 944 s->q_in.max_size = PICO_DEFAULT_SOCKETQ;
tass 68:0847e35d08a6 945 s->q_out.max_size = PICO_DEFAULT_SOCKETQ;
tass 68:0847e35d08a6 946 s->wakeup = NULL;
tass 68:0847e35d08a6 947 if (!s->net) {
tass 68:0847e35d08a6 948 pico_free(s);
tass 68:0847e35d08a6 949 pico_err = PICO_ERR_ENETUNREACH;
tass 68:0847e35d08a6 950 return NULL;
tass 68:0847e35d08a6 951 }
tass 68:0847e35d08a6 952 return s;
tass 68:0847e35d08a6 953 }
tass 68:0847e35d08a6 954
tass 68:0847e35d08a6 955 int pico_socket_read(struct pico_socket *s, void *buf, int len)
tass 68:0847e35d08a6 956 {
tass 68:0847e35d08a6 957 if (!s || buf == NULL) {
tass 68:0847e35d08a6 958 pico_err = PICO_ERR_EINVAL;
tass 68:0847e35d08a6 959 return -1;
tass 68:0847e35d08a6 960 } else {
tass 68:0847e35d08a6 961 /* check if exists in tree */
tass 68:0847e35d08a6 962 /* See task #178 */
tass 68:0847e35d08a6 963 if (pico_check_socket(s) != 0) {
tass 68:0847e35d08a6 964 pico_err = PICO_ERR_EINVAL;
tass 68:0847e35d08a6 965 return -1;
tass 68:0847e35d08a6 966 }
tass 68:0847e35d08a6 967 }
tass 68:0847e35d08a6 968
tass 68:0847e35d08a6 969 if ((s->state & PICO_SOCKET_STATE_BOUND) == 0) {
tass 68:0847e35d08a6 970 pico_err = PICO_ERR_EIO;
tass 68:0847e35d08a6 971 return -1;
tass 68:0847e35d08a6 972 }
tass 68:0847e35d08a6 973 #ifdef PICO_SUPPORT_UDP
tass 68:0847e35d08a6 974 if (PROTO(s) == PICO_PROTO_UDP)
tass 70:cd218dd180e5 975 return pico_udp_recv(s, buf, (uint16_t)len, NULL, NULL);
tass 68:0847e35d08a6 976 #endif
tass 68:0847e35d08a6 977
tass 68:0847e35d08a6 978 #ifdef PICO_SUPPORT_TCP
tass 68:0847e35d08a6 979 if (PROTO(s) == PICO_PROTO_TCP){
tass 68:0847e35d08a6 980 /* check if in shutdown state and if no more data in tcpq_in */
tass 68:0847e35d08a6 981 if ((s->state & PICO_SOCKET_STATE_SHUT_REMOTE) && pico_tcp_queue_in_is_empty(s) ) {
tass 68:0847e35d08a6 982 pico_err = PICO_ERR_ESHUTDOWN;
tass 68:0847e35d08a6 983 return -1;
tass 68:0847e35d08a6 984 } else {
tass 70:cd218dd180e5 985 return (int)pico_tcp_read(s, buf, (uint32_t)len);
tass 68:0847e35d08a6 986 }
tass 68:0847e35d08a6 987 }
tass 68:0847e35d08a6 988 #endif
tass 68:0847e35d08a6 989 return 0;
tass 68:0847e35d08a6 990 }
tass 68:0847e35d08a6 991
tass 68:0847e35d08a6 992 int pico_socket_write(struct pico_socket *s, const void *buf, int len)
tass 68:0847e35d08a6 993 {
tass 68:0847e35d08a6 994 if (!s || buf == NULL) {
tass 68:0847e35d08a6 995 pico_err = PICO_ERR_EINVAL;
tass 68:0847e35d08a6 996 return -1;
tass 68:0847e35d08a6 997 } else {
tass 68:0847e35d08a6 998 /* check if exists in tree */
tass 68:0847e35d08a6 999 /* See task #178 */
tass 68:0847e35d08a6 1000 if (pico_check_socket(s) != 0) {
tass 68:0847e35d08a6 1001 pico_err = PICO_ERR_EINVAL;
tass 68:0847e35d08a6 1002 return -1;
tass 68:0847e35d08a6 1003 }
tass 68:0847e35d08a6 1004 }
tass 68:0847e35d08a6 1005
tass 68:0847e35d08a6 1006 if ((s->state & PICO_SOCKET_STATE_BOUND) == 0) {
tass 68:0847e35d08a6 1007 pico_err = PICO_ERR_EIO;
tass 68:0847e35d08a6 1008 return -1;
tass 68:0847e35d08a6 1009 }
tass 68:0847e35d08a6 1010 if ((s->state & PICO_SOCKET_STATE_CONNECTED) == 0) {
tass 68:0847e35d08a6 1011 pico_err = PICO_ERR_ENOTCONN;
tass 68:0847e35d08a6 1012 return -1;
tass 68:0847e35d08a6 1013 } else if (s->state & PICO_SOCKET_STATE_SHUT_LOCAL) { /* check if in shutdown state */
tass 68:0847e35d08a6 1014 pico_err = PICO_ERR_ESHUTDOWN;
tass 68:0847e35d08a6 1015 return -1;
tass 68:0847e35d08a6 1016 } else {
tass 68:0847e35d08a6 1017 return pico_socket_sendto(s, buf, len, &s->remote_addr, s->remote_port);
tass 68:0847e35d08a6 1018 }
tass 68:0847e35d08a6 1019 }
tass 68:0847e35d08a6 1020
tass 68:0847e35d08a6 1021 uint16_t pico_socket_high_port(uint16_t proto)
tass 68:0847e35d08a6 1022 {
tass 68:0847e35d08a6 1023 uint16_t port;
tass 68:0847e35d08a6 1024 if (0 ||
tass 68:0847e35d08a6 1025 #ifdef PICO_SUPPORT_TCP
tass 68:0847e35d08a6 1026 (proto == PICO_PROTO_TCP) ||
tass 68:0847e35d08a6 1027 #endif
tass 68:0847e35d08a6 1028 #ifdef PICO_SUPPORT_TCP
tass 68:0847e35d08a6 1029 (proto == PICO_PROTO_UDP) ||
tass 68:0847e35d08a6 1030 #endif
tass 68:0847e35d08a6 1031 0) {
tass 68:0847e35d08a6 1032 do {
tass 68:0847e35d08a6 1033 uint32_t rand = pico_rand();
tass 68:0847e35d08a6 1034 port = (uint16_t) (rand & 0xFFFFU);
tass 70:cd218dd180e5 1035 port = (uint16_t)((port % (65535 - 1024)) + 1024U);
tass 68:0847e35d08a6 1036 if (pico_is_port_free(proto, port, NULL, NULL)) {
tass 68:0847e35d08a6 1037 return short_be(port);
tass 68:0847e35d08a6 1038 }
tass 68:0847e35d08a6 1039 } while(1);
tass 68:0847e35d08a6 1040 }
tass 68:0847e35d08a6 1041 else return 0U;
tass 68:0847e35d08a6 1042 }
tass 68:0847e35d08a6 1043
tass 68:0847e35d08a6 1044
tass 68:0847e35d08a6 1045 int pico_socket_sendto(struct pico_socket *s, const void *buf, const int len, void *dst, uint16_t remote_port)
tass 68:0847e35d08a6 1046 {
tass 68:0847e35d08a6 1047 struct pico_frame *f;
tass 68:0847e35d08a6 1048 struct pico_remote_duple *remote_duple = NULL;
tass 68:0847e35d08a6 1049 int socket_mtu = PICO_SOCKET4_MTU;
tass 68:0847e35d08a6 1050 int header_offset = 0;
tass 68:0847e35d08a6 1051 int total_payload_written = 0;
tass 68:0847e35d08a6 1052 #ifdef PICO_SUPPORT_IPV4
tass 68:0847e35d08a6 1053 struct pico_ip4 *src4;
tass 68:0847e35d08a6 1054 #endif
tass 68:0847e35d08a6 1055
tass 68:0847e35d08a6 1056 #ifdef PICO_SUPPORT_IPV6
tass 68:0847e35d08a6 1057 struct pico_ip6 *src6;
tass 68:0847e35d08a6 1058 #endif
tass 68:0847e35d08a6 1059 if (len == 0) {
tass 68:0847e35d08a6 1060 return 0;
tass 68:0847e35d08a6 1061 } else if (len < 0) {
tass 68:0847e35d08a6 1062 pico_err = PICO_ERR_EINVAL;
tass 68:0847e35d08a6 1063 return -1;
tass 68:0847e35d08a6 1064 }
tass 68:0847e35d08a6 1065
tass 68:0847e35d08a6 1066 if (buf == NULL || s == NULL) {
tass 68:0847e35d08a6 1067 pico_err = PICO_ERR_EINVAL;
tass 68:0847e35d08a6 1068 return -1;
tass 68:0847e35d08a6 1069 }
tass 68:0847e35d08a6 1070
tass 68:0847e35d08a6 1071 if (!dst || !remote_port) {
tass 68:0847e35d08a6 1072 pico_err = PICO_ERR_EADDRNOTAVAIL;
tass 68:0847e35d08a6 1073 return -1;
tass 68:0847e35d08a6 1074 }
tass 68:0847e35d08a6 1075
tass 68:0847e35d08a6 1076 if ((s->state & PICO_SOCKET_STATE_CONNECTED) != 0) {
tass 68:0847e35d08a6 1077 if (remote_port != s->remote_port) {
tass 68:0847e35d08a6 1078 pico_err = PICO_ERR_EINVAL;
tass 68:0847e35d08a6 1079 return -1;
tass 68:0847e35d08a6 1080 }
tass 68:0847e35d08a6 1081 }
tass 68:0847e35d08a6 1082
tass 68:0847e35d08a6 1083 #ifdef PICO_SUPPORT_IPV4
tass 68:0847e35d08a6 1084 if (IS_SOCK_IPV4(s)) {
tass 68:0847e35d08a6 1085 socket_mtu = PICO_SOCKET4_MTU;
tass 68:0847e35d08a6 1086 if ((s->state & PICO_SOCKET_STATE_CONNECTED)) {
tass 68:0847e35d08a6 1087 if (s->remote_addr.ip4.addr != ((struct pico_ip4 *)dst)->addr ) {
tass 68:0847e35d08a6 1088 pico_err = PICO_ERR_EADDRNOTAVAIL;
tass 68:0847e35d08a6 1089 return -1;
tass 68:0847e35d08a6 1090 }
tass 68:0847e35d08a6 1091 } else {
tass 68:0847e35d08a6 1092 src4 = pico_ipv4_source_find(dst);
tass 68:0847e35d08a6 1093 if (!src4) {
tass 68:0847e35d08a6 1094 pico_err = PICO_ERR_EHOSTUNREACH;
tass 68:0847e35d08a6 1095 return -1;
tass 68:0847e35d08a6 1096 }
tass 68:0847e35d08a6 1097 if (src4->addr != PICO_IPV4_INADDR_ANY)
tass 68:0847e35d08a6 1098 s->local_addr.ip4.addr = src4->addr;
tass 68:0847e35d08a6 1099 # ifdef PICO_SUPPORT_UDP
tass 68:0847e35d08a6 1100 /* socket remote info could change in a consecutive call, make persistent */
tass 68:0847e35d08a6 1101 if (PROTO(s) == PICO_PROTO_UDP) {
tass 68:0847e35d08a6 1102 remote_duple = pico_zalloc(sizeof(struct pico_remote_duple));
tass 68:0847e35d08a6 1103 remote_duple->remote_addr.ip4.addr = ((struct pico_ip4 *)dst)->addr;
tass 68:0847e35d08a6 1104 remote_duple->remote_port = remote_port;
tass 68:0847e35d08a6 1105 }
tass 68:0847e35d08a6 1106 # endif
tass 68:0847e35d08a6 1107 }
tass 68:0847e35d08a6 1108 #endif
tass 68:0847e35d08a6 1109 } else if (IS_SOCK_IPV6(s)) {
tass 68:0847e35d08a6 1110 socket_mtu = PICO_SOCKET6_MTU;
tass 68:0847e35d08a6 1111 #ifdef PICO_SUPPORT_IPV6
tass 68:0847e35d08a6 1112 if (s->state & PICO_SOCKET_STATE_CONNECTED) {
tass 68:0847e35d08a6 1113 if (memcmp(&s->remote_addr, dst, PICO_SIZE_IP6))
tass 68:0847e35d08a6 1114 return -1;
tass 68:0847e35d08a6 1115 } else {
tass 68:0847e35d08a6 1116 src6 = pico_ipv6_source_find(dst);
tass 68:0847e35d08a6 1117 if (!src6) {
tass 68:0847e35d08a6 1118 pico_err = PICO_ERR_EHOSTUNREACH;
tass 68:0847e35d08a6 1119 return -1;
tass 68:0847e35d08a6 1120 }
tass 68:0847e35d08a6 1121 memcpy(&s->local_addr, src6, PICO_SIZE_IP6);
tass 68:0847e35d08a6 1122 memcpy(&s->remote_addr, dst, PICO_SIZE_IP6);
tass 68:0847e35d08a6 1123 # ifdef PICO_SUPPORT_UDP
tass 68:0847e35d08a6 1124 if (PROTO(s) == PICO_PROTO_UDP) {
tass 68:0847e35d08a6 1125 remote_duple = pico_zalloc(sizeof(struct pico_remote_duple));
tass 68:0847e35d08a6 1126 remote_duple->remote_addr.ip6.addr = ((struct pico_ip6 *)dst)->addr;
tass 68:0847e35d08a6 1127 remote_duple->remote_port = remote_port;
tass 68:0847e35d08a6 1128 }
tass 68:0847e35d08a6 1129 # endif
tass 68:0847e35d08a6 1130 }
tass 68:0847e35d08a6 1131 #endif
tass 68:0847e35d08a6 1132 }
tass 68:0847e35d08a6 1133
tass 68:0847e35d08a6 1134 if ((s->state & PICO_SOCKET_STATE_BOUND) == 0) {
tass 68:0847e35d08a6 1135 s->local_port = pico_socket_high_port(s->proto->proto_number);
tass 68:0847e35d08a6 1136 if (s->local_port == 0) {
tass 68:0847e35d08a6 1137 pico_err = PICO_ERR_EINVAL;
tass 68:0847e35d08a6 1138 return -1;
tass 68:0847e35d08a6 1139 }
tass 68:0847e35d08a6 1140 }
tass 68:0847e35d08a6 1141 if ((s->state & PICO_SOCKET_STATE_CONNECTED) == 0) {
tass 68:0847e35d08a6 1142 s->remote_port = remote_port;
tass 68:0847e35d08a6 1143 }
tass 68:0847e35d08a6 1144
tass 68:0847e35d08a6 1145 #ifdef PICO_SUPPORT_TCP
tass 68:0847e35d08a6 1146 if (PROTO(s) == PICO_PROTO_TCP)
tass 68:0847e35d08a6 1147 header_offset = pico_tcp_overhead(s);
tass 68:0847e35d08a6 1148 #endif
tass 68:0847e35d08a6 1149
tass 68:0847e35d08a6 1150 #ifdef PICO_SUPPORT_UDP
tass 68:0847e35d08a6 1151 if (PROTO(s) == PICO_PROTO_UDP)
tass 68:0847e35d08a6 1152 header_offset = sizeof(struct pico_udp_hdr);
tass 68:0847e35d08a6 1153 #endif
tass 68:0847e35d08a6 1154
tass 68:0847e35d08a6 1155 while (total_payload_written < len) {
tass 68:0847e35d08a6 1156 int transport_len = (len - total_payload_written) + header_offset;
tass 68:0847e35d08a6 1157 if (transport_len > socket_mtu)
tass 68:0847e35d08a6 1158 transport_len = socket_mtu;
tass 68:0847e35d08a6 1159 #ifdef PICO_SUPPORT_IPFRAG
tass 68:0847e35d08a6 1160 else {
tass 68:0847e35d08a6 1161 if (total_payload_written)
tass 68:0847e35d08a6 1162 transport_len -= header_offset; /* last fragment, do not allocate memory for transport header */
tass 68:0847e35d08a6 1163 }
tass 68:0847e35d08a6 1164 #endif /* PICO_SUPPORT_IPFRAG */
tass 68:0847e35d08a6 1165
tass 70:cd218dd180e5 1166 f = pico_socket_frame_alloc(s, (uint16_t)transport_len);
tass 68:0847e35d08a6 1167 if (!f) {
tass 68:0847e35d08a6 1168 pico_err = PICO_ERR_ENOMEM;
tass 68:0847e35d08a6 1169 return -1;
tass 68:0847e35d08a6 1170 }
tass 68:0847e35d08a6 1171 f->payload += header_offset;
tass 73:dfb737147f6e 1172 f->payload_len = (uint16_t)(f->payload_len - header_offset);
tass 68:0847e35d08a6 1173 f->sock = s;
tass 68:0847e35d08a6 1174 if (remote_duple) {
tass 68:0847e35d08a6 1175 f->info = pico_zalloc(sizeof(struct pico_remote_duple));
tass 68:0847e35d08a6 1176 memcpy(f->info, remote_duple, sizeof(struct pico_remote_duple));
tass 68:0847e35d08a6 1177 }
tass 68:0847e35d08a6 1178
tass 68:0847e35d08a6 1179 #ifdef PICO_SUPPORT_IPFRAG
tass 68:0847e35d08a6 1180 #ifdef PICO_SUPPORT_UDP
tass 68:0847e35d08a6 1181 if (PROTO(s) == PICO_PROTO_UDP && ((len + header_offset) > socket_mtu)) {
tass 68:0847e35d08a6 1182 /* hacking way to identify fragmentation frames: payload != transport_hdr -> first frame */
tass 68:0847e35d08a6 1183 if (!total_payload_written) {
tass 68:0847e35d08a6 1184 frag_dbg("FRAG: first fragmented frame %p | len = %u offset = 0\n", f, f->payload_len);
tass 68:0847e35d08a6 1185 /* transport header length field contains total length + header length */
tass 70:cd218dd180e5 1186 f->transport_len = (uint16_t)(len + header_offset);
tass 68:0847e35d08a6 1187 f->frag = short_be(PICO_IPV4_MOREFRAG);
tass 68:0847e35d08a6 1188 } else {
tass 68:0847e35d08a6 1189 /* no transport header in fragmented IP */
tass 68:0847e35d08a6 1190 f->payload = f->transport_hdr;
tass 73:dfb737147f6e 1191 f->payload_len = (uint16_t)(f->payload_len + header_offset);
tass 68:0847e35d08a6 1192 /* set offset in octets */
tass 70:cd218dd180e5 1193 f->frag = short_be((uint16_t)((total_payload_written + header_offset) / 8));
tass 68:0847e35d08a6 1194 if (total_payload_written + f->payload_len < len) {
tass 68:0847e35d08a6 1195 frag_dbg("FRAG: intermediate fragmented frame %p | len = %u offset = %u\n", f, f->payload_len, short_be(f->frag));
tass 68:0847e35d08a6 1196 f->frag |= short_be(PICO_IPV4_MOREFRAG);
tass 68:0847e35d08a6 1197 } else {
tass 68:0847e35d08a6 1198 frag_dbg("FRAG: last fragmented frame %p | len = %u offset = %u\n", f, f->payload_len, short_be(f->frag));
tass 68:0847e35d08a6 1199 f->frag &= short_be(PICO_IPV4_FRAG_MASK);
tass 68:0847e35d08a6 1200 }
tass 68:0847e35d08a6 1201 }
tass 68:0847e35d08a6 1202 } else {
tass 68:0847e35d08a6 1203 f->frag = short_be(PICO_IPV4_DONTFRAG);
tass 68:0847e35d08a6 1204 }
tass 68:0847e35d08a6 1205 # endif /* PICO_SUPPORT_UDP */
tass 68:0847e35d08a6 1206 #endif /* PICO_SUPPORT_IPFRAG */
tass 68:0847e35d08a6 1207
tass 68:0847e35d08a6 1208 if (f->payload_len <= 0) {
tass 68:0847e35d08a6 1209 pico_frame_discard(f);
tass 68:0847e35d08a6 1210 if (remote_duple)
tass 68:0847e35d08a6 1211 pico_free(remote_duple);
tass 68:0847e35d08a6 1212 return total_payload_written;
tass 68:0847e35d08a6 1213 }
tass 68:0847e35d08a6 1214
tass 68:0847e35d08a6 1215 memcpy(f->payload, buf + total_payload_written, f->payload_len);
tass 68:0847e35d08a6 1216 //dbg("Pushing segment, hdr len: %d, payload_len: %d\n", header_offset, f->payload_len);
tass 68:0847e35d08a6 1217
tass 68:0847e35d08a6 1218 if (s->proto->push(s->proto, f) > 0) {
tass 70:cd218dd180e5 1219 total_payload_written += (int)f->payload_len;
tass 68:0847e35d08a6 1220 } else {
tass 68:0847e35d08a6 1221 pico_frame_discard(f);
tass 68:0847e35d08a6 1222 pico_err = PICO_ERR_EAGAIN;
tass 68:0847e35d08a6 1223 break;
tass 68:0847e35d08a6 1224 }
tass 68:0847e35d08a6 1225 }
tass 68:0847e35d08a6 1226 if (remote_duple)
tass 68:0847e35d08a6 1227 pico_free(remote_duple);
tass 68:0847e35d08a6 1228 return total_payload_written;
tass 68:0847e35d08a6 1229 }
tass 68:0847e35d08a6 1230
tass 68:0847e35d08a6 1231 int pico_socket_send(struct pico_socket *s, const void *buf, int len)
tass 68:0847e35d08a6 1232 {
tass 68:0847e35d08a6 1233 if (!s || buf == NULL) {
tass 68:0847e35d08a6 1234 pico_err = PICO_ERR_EINVAL;
tass 68:0847e35d08a6 1235 return -1;
tass 68:0847e35d08a6 1236 } else {
tass 68:0847e35d08a6 1237 /* check if exists in tree */
tass 68:0847e35d08a6 1238 /* See task #178 */
tass 68:0847e35d08a6 1239 if (pico_check_socket(s) != 0) {
tass 68:0847e35d08a6 1240 pico_err = PICO_ERR_EINVAL;
tass 68:0847e35d08a6 1241 return -1;
tass 68:0847e35d08a6 1242 }
tass 68:0847e35d08a6 1243 }
tass 68:0847e35d08a6 1244
tass 68:0847e35d08a6 1245 if ((s->state & PICO_SOCKET_STATE_CONNECTED) == 0) {
tass 68:0847e35d08a6 1246 pico_err = PICO_ERR_ENOTCONN;
tass 68:0847e35d08a6 1247 return -1;
tass 68:0847e35d08a6 1248 }
tass 68:0847e35d08a6 1249 return pico_socket_sendto(s, buf, len, &s->remote_addr, s->remote_port);
tass 68:0847e35d08a6 1250 }
tass 68:0847e35d08a6 1251
tass 68:0847e35d08a6 1252 int pico_socket_recvfrom(struct pico_socket *s, void *buf, int len, void *orig, uint16_t *remote_port)
tass 68:0847e35d08a6 1253 {
tass 68:0847e35d08a6 1254 if (!s || buf == NULL) { /// || orig == NULL || remote_port == NULL) {
tass 68:0847e35d08a6 1255 pico_err = PICO_ERR_EINVAL;
tass 68:0847e35d08a6 1256 return -1;
tass 68:0847e35d08a6 1257 } else {
tass 68:0847e35d08a6 1258 /* check if exists in tree */
tass 68:0847e35d08a6 1259 if (pico_check_socket(s) != 0) {
tass 68:0847e35d08a6 1260 pico_err = PICO_ERR_EINVAL;
tass 68:0847e35d08a6 1261 /* See task #178 */
tass 68:0847e35d08a6 1262 return -1;
tass 68:0847e35d08a6 1263 }
tass 68:0847e35d08a6 1264 }
tass 68:0847e35d08a6 1265
tass 68:0847e35d08a6 1266 if ((s->state & PICO_SOCKET_STATE_BOUND) == 0) {
tass 68:0847e35d08a6 1267 pico_err = PICO_ERR_EADDRNOTAVAIL;
tass 68:0847e35d08a6 1268 return -1;
tass 68:0847e35d08a6 1269 }
tass 68:0847e35d08a6 1270 #ifdef PICO_SUPPORT_UDP
tass 68:0847e35d08a6 1271 if (PROTO(s) == PICO_PROTO_UDP) {
tass 70:cd218dd180e5 1272 return pico_udp_recv(s, buf, (uint16_t)len, orig, remote_port);
tass 68:0847e35d08a6 1273 }
tass 68:0847e35d08a6 1274 #endif
tass 68:0847e35d08a6 1275 #ifdef PICO_SUPPORT_TCP
tass 68:0847e35d08a6 1276 if (PROTO(s) == PICO_PROTO_TCP) {
tass 68:0847e35d08a6 1277 /* check if in shutdown state and if tcpq_in empty */
tass 68:0847e35d08a6 1278 if ((s->state & PICO_SOCKET_STATE_SHUT_REMOTE) && pico_tcp_queue_in_is_empty(s)) {
tass 68:0847e35d08a6 1279 pico_err = PICO_ERR_ESHUTDOWN;
tass 68:0847e35d08a6 1280 return -1;
tass 68:0847e35d08a6 1281 } else {
tass 68:0847e35d08a6 1282 //dbg("socket tcp recv\n");
tass 70:cd218dd180e5 1283 return (int)pico_tcp_read(s, buf, (uint32_t)len);
tass 68:0847e35d08a6 1284 }
tass 68:0847e35d08a6 1285 }
tass 68:0847e35d08a6 1286 #endif
tass 68:0847e35d08a6 1287 //dbg("socket return 0\n");
tass 68:0847e35d08a6 1288 return 0;
tass 68:0847e35d08a6 1289 }
tass 68:0847e35d08a6 1290
tass 68:0847e35d08a6 1291 int pico_socket_recv(struct pico_socket *s, void *buf, int len)
tass 68:0847e35d08a6 1292 {
tass 68:0847e35d08a6 1293 return pico_socket_recvfrom(s, buf, len, NULL, NULL);
tass 68:0847e35d08a6 1294 }
tass 68:0847e35d08a6 1295
tass 68:0847e35d08a6 1296
tass 68:0847e35d08a6 1297 int pico_socket_bind(struct pico_socket *s, void *local_addr, uint16_t *port)
tass 68:0847e35d08a6 1298 {
tass 68:0847e35d08a6 1299 if (!s || !local_addr || !port) {
tass 68:0847e35d08a6 1300 pico_err = PICO_ERR_EINVAL;
tass 68:0847e35d08a6 1301 return -1;
tass 68:0847e35d08a6 1302 }
tass 68:0847e35d08a6 1303
tass 68:0847e35d08a6 1304 if (!is_sock_ipv6(s)) {
tass 68:0847e35d08a6 1305 struct pico_ip4 *ip = (struct pico_ip4 *)local_addr;
tass 68:0847e35d08a6 1306 if (ip->addr != PICO_IPV4_INADDR_ANY) {
tass 68:0847e35d08a6 1307 if (!pico_ipv4_link_find(local_addr)) {
tass 68:0847e35d08a6 1308 pico_err = PICO_ERR_EINVAL;
tass 68:0847e35d08a6 1309 return -1;
tass 68:0847e35d08a6 1310 }
tass 68:0847e35d08a6 1311 }
tass 68:0847e35d08a6 1312 } else {
tass 68:0847e35d08a6 1313 /*... IPv6 */
tass 68:0847e35d08a6 1314 }
tass 68:0847e35d08a6 1315
tass 68:0847e35d08a6 1316
tass 68:0847e35d08a6 1317 /* When given port = 0, get a random high port to bind to. */
tass 68:0847e35d08a6 1318 if (*port == 0) {
tass 68:0847e35d08a6 1319 *port = pico_socket_high_port(PROTO(s));
tass 68:0847e35d08a6 1320 if (*port == 0) {
tass 68:0847e35d08a6 1321 pico_err = PICO_ERR_EINVAL;
tass 68:0847e35d08a6 1322 return -1;
tass 68:0847e35d08a6 1323 }
tass 68:0847e35d08a6 1324 }
tass 68:0847e35d08a6 1325
tass 68:0847e35d08a6 1326 if (pico_is_port_free(PROTO(s), *port, local_addr, s->net) == 0) {
tass 68:0847e35d08a6 1327 pico_err = PICO_ERR_EADDRINUSE;
tass 68:0847e35d08a6 1328 return -1;
tass 68:0847e35d08a6 1329 }
tass 68:0847e35d08a6 1330 s->local_port = *port;
tass 68:0847e35d08a6 1331
tass 68:0847e35d08a6 1332 if (is_sock_ipv6(s)) {
tass 68:0847e35d08a6 1333 struct pico_ip6 *ip = (struct pico_ip6 *) local_addr;
tass 68:0847e35d08a6 1334 memcpy(s->local_addr.ip6.addr, ip, PICO_SIZE_IP6);
tass 68:0847e35d08a6 1335 /* XXX: port ipv4 functionality to ipv6 */
tass 68:0847e35d08a6 1336 /* Check for port already in use */
tass 68:0847e35d08a6 1337 if (pico_is_port_free(PROTO(s), *port, &local_addr, s->net)) {
tass 68:0847e35d08a6 1338 pico_err = PICO_ERR_EADDRINUSE;
tass 68:0847e35d08a6 1339 return -1;
tass 68:0847e35d08a6 1340 }
tass 68:0847e35d08a6 1341 } else if (is_sock_ipv4(s)) {
tass 68:0847e35d08a6 1342 struct pico_ip4 *ip = (struct pico_ip4 *) local_addr;
tass 68:0847e35d08a6 1343 s->local_addr.ip4.addr = ip->addr;
tass 68:0847e35d08a6 1344 }
tass 68:0847e35d08a6 1345 return pico_socket_alter_state(s, PICO_SOCKET_STATE_BOUND, 0, 0);
tass 68:0847e35d08a6 1346 }
tass 68:0847e35d08a6 1347
tass 68:0847e35d08a6 1348 int pico_socket_connect(struct pico_socket *s, const void *remote_addr, uint16_t remote_port)
tass 68:0847e35d08a6 1349 {
tass 68:0847e35d08a6 1350 int ret = -1;
tass 68:0847e35d08a6 1351 pico_err = PICO_ERR_EPROTONOSUPPORT;
tass 68:0847e35d08a6 1352 if (!s || remote_addr == NULL || remote_port == 0) {
tass 68:0847e35d08a6 1353 pico_err = PICO_ERR_EINVAL;
tass 68:0847e35d08a6 1354 return -1;
tass 68:0847e35d08a6 1355 }
tass 68:0847e35d08a6 1356
tass 68:0847e35d08a6 1357 s->remote_port = remote_port;
tass 68:0847e35d08a6 1358
tass 68:0847e35d08a6 1359 if (s->local_port == 0) {
tass 68:0847e35d08a6 1360 s->local_port = pico_socket_high_port(PROTO(s));
tass 68:0847e35d08a6 1361 if (!s->local_port) {
tass 68:0847e35d08a6 1362 pico_err = PICO_ERR_EINVAL;
tass 68:0847e35d08a6 1363 return -1;
tass 68:0847e35d08a6 1364 }
tass 68:0847e35d08a6 1365 }
tass 68:0847e35d08a6 1366
tass 68:0847e35d08a6 1367 if (is_sock_ipv6(s)) {
tass 68:0847e35d08a6 1368 const struct pico_ip6 *ip = (const struct pico_ip6 *) remote_addr;
tass 68:0847e35d08a6 1369 memcpy(s->remote_addr.ip6.addr, ip, PICO_SIZE_IP6);
tass 68:0847e35d08a6 1370 } else if (is_sock_ipv4(s)) {
tass 68:0847e35d08a6 1371 const struct pico_ip4 *local, *ip = (const struct pico_ip4 *) remote_addr;
tass 68:0847e35d08a6 1372 s->remote_addr.ip4.addr = ip->addr;
tass 68:0847e35d08a6 1373 local = pico_ipv4_source_find(ip);
tass 68:0847e35d08a6 1374 if (local) {
tass 68:0847e35d08a6 1375 s->local_addr.ip4.addr = local->addr;
tass 68:0847e35d08a6 1376 } else {
tass 68:0847e35d08a6 1377 pico_err = PICO_ERR_EHOSTUNREACH;
tass 68:0847e35d08a6 1378 return -1;
tass 68:0847e35d08a6 1379 }
tass 68:0847e35d08a6 1380 }
tass 68:0847e35d08a6 1381
tass 68:0847e35d08a6 1382 pico_socket_alter_state(s, PICO_SOCKET_STATE_BOUND, 0, 0);
tass 68:0847e35d08a6 1383
tass 68:0847e35d08a6 1384 #ifdef PICO_SUPPORT_UDP
tass 68:0847e35d08a6 1385 if (PROTO(s) == PICO_PROTO_UDP) {
tass 68:0847e35d08a6 1386 pico_socket_alter_state(s, PICO_SOCKET_STATE_CONNECTED, 0, 0);
tass 68:0847e35d08a6 1387 pico_err = PICO_ERR_NOERR;
tass 68:0847e35d08a6 1388 ret = 0;
tass 68:0847e35d08a6 1389 }
tass 68:0847e35d08a6 1390 #endif
tass 68:0847e35d08a6 1391
tass 68:0847e35d08a6 1392 #ifdef PICO_SUPPORT_TCP
tass 68:0847e35d08a6 1393 if (PROTO(s) == PICO_PROTO_TCP) {
tass 68:0847e35d08a6 1394 if (pico_tcp_initconn(s) == 0) {
tass 68:0847e35d08a6 1395 pico_socket_alter_state(s, PICO_SOCKET_STATE_CONNECTED | PICO_SOCKET_STATE_TCP_SYN_SENT, 0, 0);
tass 68:0847e35d08a6 1396 pico_err = PICO_ERR_NOERR;
tass 68:0847e35d08a6 1397 ret = 0;
tass 68:0847e35d08a6 1398 } else {
tass 68:0847e35d08a6 1399 pico_err = PICO_ERR_EHOSTUNREACH;
tass 68:0847e35d08a6 1400 }
tass 68:0847e35d08a6 1401 }
tass 68:0847e35d08a6 1402 #endif
tass 68:0847e35d08a6 1403
tass 68:0847e35d08a6 1404 return ret;
tass 68:0847e35d08a6 1405 }
tass 68:0847e35d08a6 1406
tass 68:0847e35d08a6 1407 #ifdef PICO_SUPPORT_TCP
tass 68:0847e35d08a6 1408
tass 68:0847e35d08a6 1409 int pico_socket_listen(struct pico_socket *s, int backlog)
tass 68:0847e35d08a6 1410 {
tass 68:0847e35d08a6 1411 if (!s || backlog < 1) {
tass 68:0847e35d08a6 1412 pico_err = PICO_ERR_EINVAL;
tass 68:0847e35d08a6 1413 return -1;
tass 68:0847e35d08a6 1414 } else {
tass 68:0847e35d08a6 1415 /* check if exists in tree */
tass 68:0847e35d08a6 1416 /* See task #178 */
tass 68:0847e35d08a6 1417 if (pico_check_socket(s) != 0) {
tass 68:0847e35d08a6 1418 pico_err = PICO_ERR_EINVAL;
tass 68:0847e35d08a6 1419 return -1;
tass 68:0847e35d08a6 1420 }
tass 68:0847e35d08a6 1421 }
tass 68:0847e35d08a6 1422
tass 68:0847e35d08a6 1423 if (PROTO(s) == PICO_PROTO_UDP) {
tass 68:0847e35d08a6 1424 pico_err = PICO_ERR_EINVAL;
tass 68:0847e35d08a6 1425 return -1;
tass 68:0847e35d08a6 1426 }
tass 68:0847e35d08a6 1427
tass 68:0847e35d08a6 1428 if ((s->state & PICO_SOCKET_STATE_BOUND) == 0) {
tass 68:0847e35d08a6 1429 pico_err = PICO_ERR_EISCONN;
tass 68:0847e35d08a6 1430 return -1;
tass 68:0847e35d08a6 1431 }
tass 68:0847e35d08a6 1432
tass 68:0847e35d08a6 1433 if (backlog < 1) {
tass 68:0847e35d08a6 1434 pico_err = PICO_ERR_EINVAL;
tass 68:0847e35d08a6 1435 return -1;
tass 68:0847e35d08a6 1436 }
tass 68:0847e35d08a6 1437
tass 68:0847e35d08a6 1438 if (PROTO(s) == PICO_PROTO_TCP)
tass 68:0847e35d08a6 1439 pico_socket_alter_state(s, PICO_SOCKET_STATE_TCP_SYN_SENT, 0, PICO_SOCKET_STATE_TCP_LISTEN);
tass 68:0847e35d08a6 1440 s->max_backlog = backlog;
tass 68:0847e35d08a6 1441
tass 68:0847e35d08a6 1442 return 0;
tass 68:0847e35d08a6 1443 }
tass 68:0847e35d08a6 1444
tass 68:0847e35d08a6 1445 struct pico_socket *pico_socket_accept(struct pico_socket *s, void *orig, uint16_t *port)
tass 68:0847e35d08a6 1446 {
tass 68:0847e35d08a6 1447 if (!s || !orig || !port) {
tass 68:0847e35d08a6 1448 pico_err = PICO_ERR_EINVAL;
tass 68:0847e35d08a6 1449 return NULL;
tass 68:0847e35d08a6 1450 }
tass 68:0847e35d08a6 1451
tass 68:0847e35d08a6 1452 pico_err = PICO_ERR_EINVAL;
tass 68:0847e35d08a6 1453
tass 68:0847e35d08a6 1454 if ((s->state & PICO_SOCKET_STATE_BOUND) == 0) {
tass 68:0847e35d08a6 1455 return NULL;
tass 68:0847e35d08a6 1456 }
tass 68:0847e35d08a6 1457
tass 68:0847e35d08a6 1458 if (PROTO(s) == PICO_PROTO_UDP) {
tass 68:0847e35d08a6 1459 return NULL;
tass 68:0847e35d08a6 1460 }
tass 68:0847e35d08a6 1461
tass 68:0847e35d08a6 1462 if (TCPSTATE(s) == PICO_SOCKET_STATE_TCP_LISTEN) {
tass 68:0847e35d08a6 1463 struct pico_sockport *sp = pico_get_sockport(PICO_PROTO_TCP, s->local_port);
tass 68:0847e35d08a6 1464 struct pico_socket *found;
tass 68:0847e35d08a6 1465 /* If at this point no incoming connection socket is found,
tass 68:0847e35d08a6 1466 * the accept call is valid, but no connection is established yet.
tass 68:0847e35d08a6 1467 */
tass 68:0847e35d08a6 1468 pico_err = PICO_ERR_EAGAIN;
tass 68:0847e35d08a6 1469 if (sp) {
tass 68:0847e35d08a6 1470 struct pico_tree_node * index;
tass 68:0847e35d08a6 1471 //RB_FOREACH(found, socket_tree, &sp->socks) {
tass 68:0847e35d08a6 1472 pico_tree_foreach(index,&sp->socks){
tass 68:0847e35d08a6 1473 found = index->keyValue;
tass 92:f9b6cc6c54c2 1474 if ((s == found->parent) && ((found->state & PICO_SOCKET_STATE_TCP) == PICO_SOCKET_STATE_TCP_ESTABLISHED)) {
tass 68:0847e35d08a6 1475 found->parent = NULL;
tass 68:0847e35d08a6 1476 pico_err = PICO_ERR_NOERR;
tass 68:0847e35d08a6 1477 memcpy(orig, &found->remote_addr, sizeof(struct pico_ip4));
tass 68:0847e35d08a6 1478 *port = found->remote_port;
tass 95:f4ca916a26fe 1479 s->number_of_pending_conn--;
tass 68:0847e35d08a6 1480 return found;
tass 68:0847e35d08a6 1481 }
tass 68:0847e35d08a6 1482 }
tass 68:0847e35d08a6 1483 }
tass 68:0847e35d08a6 1484 }
tass 68:0847e35d08a6 1485 return NULL;
tass 68:0847e35d08a6 1486 }
tass 68:0847e35d08a6 1487
tass 68:0847e35d08a6 1488 #else
tass 68:0847e35d08a6 1489
tass 68:0847e35d08a6 1490 int pico_socket_listen(struct pico_socket *s, int backlog)
tass 68:0847e35d08a6 1491 {
tass 125:96003ae6f1d8 1492 IGNORE_PARAMETER(s);
tass 125:96003ae6f1d8 1493 IGNORE_PARAMETER(backlog);
tass 68:0847e35d08a6 1494 pico_err = PICO_ERR_EINVAL;
tass 68:0847e35d08a6 1495 return -1;
tass 68:0847e35d08a6 1496 }
tass 68:0847e35d08a6 1497
tass 68:0847e35d08a6 1498 struct pico_socket *pico_socket_accept(struct pico_socket *s, void *orig, uint16_t *local_port)
tass 68:0847e35d08a6 1499 {
tass 125:96003ae6f1d8 1500 IGNORE_PARAMETER(s);
tass 125:96003ae6f1d8 1501 IGNORE_PARAMETER(orig);
tass 125:96003ae6f1d8 1502 IGNORE_PARAMETER(local_port);
tass 68:0847e35d08a6 1503 pico_err = PICO_ERR_EINVAL;
tass 68:0847e35d08a6 1504 return NULL;
tass 68:0847e35d08a6 1505 }
tass 68:0847e35d08a6 1506
tass 68:0847e35d08a6 1507 #endif
tass 68:0847e35d08a6 1508
tass 68:0847e35d08a6 1509 #define PICO_SOCKET_SETOPT_EN(socket,index) (socket->opt_flags |= (1 << index))
tass 73:dfb737147f6e 1510 #define PICO_SOCKET_SETOPT_DIS(socket,index) (socket->opt_flags &= (uint16_t)~(1 << index))
tass 68:0847e35d08a6 1511
tass 74:c146c4e346c4 1512 #ifdef PICO_SUPPORT_MCAST
tass 74:c146c4e346c4 1513 static struct pico_ipv4_link *setopt_multicast_check(struct pico_socket *s, void *value, int alloc, int bysource)
tass 74:c146c4e346c4 1514 {
tass 74:c146c4e346c4 1515 struct pico_ip_mreq *mreq = NULL;
tass 74:c146c4e346c4 1516 struct pico_ipv4_link *mcast_link = NULL;
tass 74:c146c4e346c4 1517 struct pico_ip_mreq_source *mreq_src = NULL;
tass 74:c146c4e346c4 1518
tass 74:c146c4e346c4 1519 if (!value) {
tass 74:c146c4e346c4 1520 pico_err = PICO_ERR_EINVAL;
tass 74:c146c4e346c4 1521 return NULL;
tass 74:c146c4e346c4 1522 }
tass 74:c146c4e346c4 1523 if (!bysource) {
tass 74:c146c4e346c4 1524 mreq = (struct pico_ip_mreq *) value;
tass 74:c146c4e346c4 1525 mcast_link = pico_socket_setoption_mcastargs_validation(mreq, NULL);
tass 74:c146c4e346c4 1526 if (!mreq->mcast_link_addr.addr)
tass 74:c146c4e346c4 1527 mreq->mcast_link_addr.addr = mcast_link->address.addr;
tass 74:c146c4e346c4 1528 } else {
tass 74:c146c4e346c4 1529 mreq_src = (struct pico_ip_mreq_source *) value;
tass 74:c146c4e346c4 1530 mcast_link = pico_socket_setoption_mcastargs_validation(NULL, mreq_src);
tass 74:c146c4e346c4 1531 if (!mreq_src->mcast_link_addr.addr)
tass 74:c146c4e346c4 1532 mreq_src->mcast_link_addr.addr = mcast_link->address.addr;
tass 74:c146c4e346c4 1533 }
tass 74:c146c4e346c4 1534 if (!mcast_link) {
tass 74:c146c4e346c4 1535 pico_err = PICO_ERR_EINVAL;
tass 74:c146c4e346c4 1536 return NULL;
tass 74:c146c4e346c4 1537 }
tass 74:c146c4e346c4 1538
tass 74:c146c4e346c4 1539 if (!s->MCASTListen) { /* No RBTree allocated yet */
tass 74:c146c4e346c4 1540 if (alloc) {
tass 74:c146c4e346c4 1541 s->MCASTListen = pico_zalloc(sizeof(struct pico_tree));
tass 74:c146c4e346c4 1542 if (!s->MCASTListen) {
tass 74:c146c4e346c4 1543 pico_err = PICO_ERR_ENOMEM;
tass 74:c146c4e346c4 1544 return NULL;
tass 74:c146c4e346c4 1545 }
tass 74:c146c4e346c4 1546 s->MCASTListen->root = &LEAF;
tass 74:c146c4e346c4 1547 s->MCASTListen->compare = mcast_listen_cmp;
tass 74:c146c4e346c4 1548 } else return NULL;
tass 74:c146c4e346c4 1549 }
tass 74:c146c4e346c4 1550 return mcast_link;
tass 74:c146c4e346c4 1551 }
tass 74:c146c4e346c4 1552 #endif
tass 74:c146c4e346c4 1553
tass 68:0847e35d08a6 1554 int pico_socket_setoption(struct pico_socket *s, int option, void *value) // XXX no check against proto (vs setsockopt) or implicit by socket?
tass 68:0847e35d08a6 1555 {
tass 68:0847e35d08a6 1556 if (s == NULL) {
tass 68:0847e35d08a6 1557 pico_err = PICO_ERR_EINVAL;
tass 68:0847e35d08a6 1558 return -1;
tass 68:0847e35d08a6 1559 }
tass 68:0847e35d08a6 1560
tass 68:0847e35d08a6 1561 pico_err = PICO_ERR_NOERR;
tass 68:0847e35d08a6 1562
tass 68:0847e35d08a6 1563 switch (option)
tass 68:0847e35d08a6 1564 {
tass 68:0847e35d08a6 1565 #ifdef PICO_SUPPORT_TCP
tass 68:0847e35d08a6 1566 case PICO_TCP_NODELAY:
tass 68:0847e35d08a6 1567 if (!value) {
tass 68:0847e35d08a6 1568 pico_err = PICO_ERR_EINVAL;
tass 68:0847e35d08a6 1569 return -1;
tass 68:0847e35d08a6 1570 }
tass 68:0847e35d08a6 1571 if (s->proto->proto_number == PICO_PROTO_TCP) {
tass 68:0847e35d08a6 1572 int *val = (int*)value;
tass 68:0847e35d08a6 1573 if (*val > 0) {
tass 68:0847e35d08a6 1574 dbg("setsockopt: Nagle algorithm disabled.\n");
tass 68:0847e35d08a6 1575 PICO_SOCKET_SETOPT_EN(s,PICO_SOCKET_OPT_TCPNODELAY);
tass 68:0847e35d08a6 1576 } else {
tass 68:0847e35d08a6 1577 dbg("setsockopt: Nagle algorithm enabled.\n");
tass 68:0847e35d08a6 1578 PICO_SOCKET_SETOPT_DIS(s,PICO_SOCKET_OPT_TCPNODELAY);
tass 68:0847e35d08a6 1579 }
tass 68:0847e35d08a6 1580 } else {
tass 68:0847e35d08a6 1581 pico_err = PICO_ERR_EINVAL;
tass 68:0847e35d08a6 1582 }
tass 68:0847e35d08a6 1583 break;
tass 68:0847e35d08a6 1584 #endif
tass 68:0847e35d08a6 1585
tass 68:0847e35d08a6 1586
tass 68:0847e35d08a6 1587 #ifdef PICO_SUPPORT_MCAST
tass 68:0847e35d08a6 1588 case PICO_IP_MULTICAST_IF:
tass 68:0847e35d08a6 1589 pico_err = PICO_ERR_EOPNOTSUPP;
tass 68:0847e35d08a6 1590 return -1;
tass 68:0847e35d08a6 1591 break;
tass 68:0847e35d08a6 1592
tass 68:0847e35d08a6 1593 case PICO_IP_MULTICAST_TTL:
tass 68:0847e35d08a6 1594 if (s->proto->proto_number == PICO_PROTO_UDP) {
tass 68:0847e35d08a6 1595 return pico_udp_set_mc_ttl(s, *((uint8_t *) value));
tass 68:0847e35d08a6 1596 }
tass 68:0847e35d08a6 1597 break;
tass 68:0847e35d08a6 1598
tass 68:0847e35d08a6 1599 case PICO_IP_MULTICAST_LOOP:
tass 68:0847e35d08a6 1600 if (s->proto->proto_number == PICO_PROTO_UDP) {
tass 68:0847e35d08a6 1601 switch (*(uint8_t *) value)
tass 68:0847e35d08a6 1602 {
tass 68:0847e35d08a6 1603 case 0:
tass 68:0847e35d08a6 1604 /* do not loop back multicast datagram */
tass 68:0847e35d08a6 1605 PICO_SOCKET_SETOPT_DIS(s,PICO_SOCKET_OPT_MULTICAST_LOOP);
tass 68:0847e35d08a6 1606 break;
tass 68:0847e35d08a6 1607
tass 68:0847e35d08a6 1608 case 1:
tass 68:0847e35d08a6 1609 /* do loop back multicast datagram */
tass 68:0847e35d08a6 1610 PICO_SOCKET_SETOPT_EN(s,PICO_SOCKET_OPT_MULTICAST_LOOP);
tass 68:0847e35d08a6 1611 break;
tass 68:0847e35d08a6 1612
tass 68:0847e35d08a6 1613 default:
tass 68:0847e35d08a6 1614 pico_err = PICO_ERR_EINVAL;
tass 68:0847e35d08a6 1615 return -1;
tass 68:0847e35d08a6 1616 }
tass 68:0847e35d08a6 1617 }
tass 68:0847e35d08a6 1618 break;
tass 68:0847e35d08a6 1619
tass 68:0847e35d08a6 1620 case PICO_IP_ADD_MEMBERSHIP:
tass 68:0847e35d08a6 1621 /* EXCLUDE mode */
tass 68:0847e35d08a6 1622 if (s->proto->proto_number == PICO_PROTO_UDP) {
tass 68:0847e35d08a6 1623 int filter_mode;
tass 74:c146c4e346c4 1624 struct pico_mcast_listen *listen;
tass 74:c146c4e346c4 1625 struct pico_ip_mreq *mreq = (struct pico_ip_mreq *)value;
tass 74:c146c4e346c4 1626 struct pico_ipv4_link *mcast_link = setopt_multicast_check(s, value, 1, 0);
tass 74:c146c4e346c4 1627 if (!mcast_link)
tass 68:0847e35d08a6 1628 return -1;
tass 74:c146c4e346c4 1629 listen = listen_find(s, &mreq->mcast_link_addr, &mreq->mcast_group_addr);
tass 68:0847e35d08a6 1630 if (listen) {
tass 68:0847e35d08a6 1631 if (listen->filter_mode != PICO_IP_MULTICAST_EXCLUDE) {
tass 68:0847e35d08a6 1632 so_mcast_dbg("pico_socket_setoption: ERROR any-source multicast (exclude) on source-specific multicast (include)\n");
tass 68:0847e35d08a6 1633 pico_err = PICO_ERR_EINVAL;
tass 68:0847e35d08a6 1634 return -1;
tass 68:0847e35d08a6 1635 } else {
tass 68:0847e35d08a6 1636 so_mcast_dbg("pico_socket_setoption: ERROR duplicate PICO_IP_ADD_MEMBERSHIP\n");
tass 68:0847e35d08a6 1637 pico_err = PICO_ERR_EINVAL;
tass 68:0847e35d08a6 1638 return -1;
tass 68:0847e35d08a6 1639 }
tass 68:0847e35d08a6 1640 } else {
tass 68:0847e35d08a6 1641 listen = pico_zalloc(sizeof(struct pico_mcast_listen));
tass 68:0847e35d08a6 1642 if (!listen) {
tass 68:0847e35d08a6 1643 pico_err = PICO_ERR_ENOMEM;
tass 68:0847e35d08a6 1644 return -1;
tass 68:0847e35d08a6 1645 }
tass 68:0847e35d08a6 1646 listen->filter_mode = PICO_IP_MULTICAST_EXCLUDE;
tass 68:0847e35d08a6 1647 listen->mcast_link = mreq->mcast_link_addr;
tass 68:0847e35d08a6 1648 listen->mcast_group = mreq->mcast_group_addr;
tass 68:0847e35d08a6 1649 listen->MCASTSources.root = &LEAF;
tass 68:0847e35d08a6 1650 listen->MCASTSources.compare = mcast_sources_cmp;
tass 68:0847e35d08a6 1651 pico_tree_insert(s->MCASTListen, listen);
tass 68:0847e35d08a6 1652 }
tass 68:0847e35d08a6 1653
tass 68:0847e35d08a6 1654 pico_tree_insert(&MCASTSockets, s);
tass 68:0847e35d08a6 1655 filter_mode = pico_socket_aggregate_mcastfilters(&mcast_link->address, &mreq->mcast_group_addr);
tass 68:0847e35d08a6 1656 if (filter_mode < 0)
tass 68:0847e35d08a6 1657 return -1;
tass 68:0847e35d08a6 1658
tass 70:cd218dd180e5 1659 return pico_ipv4_mcast_join(&mreq->mcast_link_addr, &mreq->mcast_group_addr, 1, (uint8_t)filter_mode, &MCASTFilter);
tass 68:0847e35d08a6 1660 }
tass 68:0847e35d08a6 1661 break;
tass 68:0847e35d08a6 1662
tass 68:0847e35d08a6 1663 case PICO_IP_DROP_MEMBERSHIP:
tass 68:0847e35d08a6 1664 /* EXCLUDE mode */
tass 68:0847e35d08a6 1665 if (s->proto->proto_number == PICO_PROTO_UDP) {
tass 68:0847e35d08a6 1666 int filter_mode = 0;
tass 74:c146c4e346c4 1667 struct pico_mcast_listen *listen;
tass 74:c146c4e346c4 1668 struct pico_ip_mreq *mreq = (struct pico_ip_mreq *)value;
tass 68:0847e35d08a6 1669 struct pico_ip4 *source = NULL;
tass 68:0847e35d08a6 1670 struct pico_tree_node *index, *_tmp;
tass 74:c146c4e346c4 1671 struct pico_ipv4_link *mcast_link = setopt_multicast_check(s, value, 0, 0);
tass 74:c146c4e346c4 1672 if (!mcast_link)
tass 68:0847e35d08a6 1673 return -1;
tass 68:0847e35d08a6 1674
tass 74:c146c4e346c4 1675 listen = listen_find(s, &mreq->mcast_link_addr, &mreq->mcast_group_addr);
tass 68:0847e35d08a6 1676 if (!listen) {
tass 68:0847e35d08a6 1677 so_mcast_dbg("pico_socket_setoption: ERROR PICO_IP_DROP_MEMBERSHIP before PICO_IP_ADD_MEMBERSHIP/SOURCE_MEMBERSHIP\n");
tass 68:0847e35d08a6 1678 pico_err = PICO_ERR_EADDRNOTAVAIL;
tass 68:0847e35d08a6 1679 return -1;
tass 68:0847e35d08a6 1680 } else {
tass 68:0847e35d08a6 1681 pico_tree_foreach_safe(index, &listen->MCASTSources, _tmp)
tass 68:0847e35d08a6 1682 {
tass 68:0847e35d08a6 1683 source = index->keyValue;
tass 68:0847e35d08a6 1684 pico_tree_delete(&listen->MCASTSources, source);
tass 68:0847e35d08a6 1685 pico_free(source);
tass 68:0847e35d08a6 1686 }
tass 68:0847e35d08a6 1687 pico_tree_delete(s->MCASTListen, listen);
tass 68:0847e35d08a6 1688 pico_free(listen);
tass 68:0847e35d08a6 1689 if (pico_tree_empty(s->MCASTListen)) {
tass 68:0847e35d08a6 1690 pico_free(s->MCASTListen);
tass 68:0847e35d08a6 1691 s->MCASTListen = NULL;
tass 68:0847e35d08a6 1692 pico_tree_delete(&MCASTSockets, s);
tass 68:0847e35d08a6 1693 }
tass 68:0847e35d08a6 1694 }
tass 68:0847e35d08a6 1695
tass 68:0847e35d08a6 1696 filter_mode = pico_socket_aggregate_mcastfilters(&mcast_link->address, &mreq->mcast_group_addr);
tass 68:0847e35d08a6 1697 if (filter_mode < 0)
tass 68:0847e35d08a6 1698 return -1;
tass 68:0847e35d08a6 1699
tass 70:cd218dd180e5 1700 return pico_ipv4_mcast_leave(&mreq->mcast_link_addr, &mreq->mcast_group_addr, 1, (uint8_t)filter_mode, &MCASTFilter);
tass 68:0847e35d08a6 1701 }
tass 68:0847e35d08a6 1702 break;
tass 68:0847e35d08a6 1703
tass 68:0847e35d08a6 1704 case PICO_IP_UNBLOCK_SOURCE:
tass 68:0847e35d08a6 1705 /* EXCLUDE mode */
tass 68:0847e35d08a6 1706 if (s->proto->proto_number == PICO_PROTO_UDP) {
tass 68:0847e35d08a6 1707 int filter_mode = 0;
tass 74:c146c4e346c4 1708 struct pico_ip_mreq_source *mreq = (struct pico_ip_mreq_source *)value;
tass 74:c146c4e346c4 1709 struct pico_mcast_listen *listen = NULL;
tass 68:0847e35d08a6 1710 struct pico_ip4 *source = NULL, stest = {0};
tass 74:c146c4e346c4 1711 struct pico_ipv4_link *mcast_link = setopt_multicast_check(s, value, 0, 1);
tass 74:c146c4e346c4 1712 if (!mcast_link)
tass 68:0847e35d08a6 1713 return -1;
tass 74:c146c4e346c4 1714 listen = listen_find(s, &mreq->mcast_link_addr, &mreq->mcast_group_addr);
tass 68:0847e35d08a6 1715 if (!listen) {
tass 68:0847e35d08a6 1716 so_mcast_dbg("pico_socket_setoption: ERROR PICO_IP_UNBLOCK_SOURCE before PICO_IP_ADD_MEMBERSHIP\n");
tass 68:0847e35d08a6 1717 pico_err = PICO_ERR_EINVAL;
tass 68:0847e35d08a6 1718 return -1;
tass 68:0847e35d08a6 1719 } else {
tass 68:0847e35d08a6 1720 if (listen->filter_mode != PICO_IP_MULTICAST_EXCLUDE) {
tass 68:0847e35d08a6 1721 so_mcast_dbg("pico_socket_setoption: ERROR any-source multicast (exclude) on source-specific multicast (include)\n");
tass 68:0847e35d08a6 1722 pico_err = PICO_ERR_EINVAL;
tass 68:0847e35d08a6 1723 return -1;
tass 68:0847e35d08a6 1724 }
tass 68:0847e35d08a6 1725 stest.addr = mreq->mcast_source_addr.addr;
tass 68:0847e35d08a6 1726 source = pico_tree_findKey(&listen->MCASTSources, &stest);
tass 68:0847e35d08a6 1727 if (!source) {
tass 68:0847e35d08a6 1728 so_mcast_dbg("pico_socket_setoption: ERROR address to unblock not in source list\n");
tass 68:0847e35d08a6 1729 pico_err = PICO_ERR_EADDRNOTAVAIL;
tass 68:0847e35d08a6 1730 return -1;
tass 68:0847e35d08a6 1731 } else {
tass 68:0847e35d08a6 1732 pico_tree_delete(&listen->MCASTSources, source);
tass 68:0847e35d08a6 1733 pico_free(source);
tass 68:0847e35d08a6 1734 }
tass 68:0847e35d08a6 1735 }
tass 68:0847e35d08a6 1736
tass 68:0847e35d08a6 1737 filter_mode = pico_socket_aggregate_mcastfilters(&mcast_link->address, &mreq->mcast_group_addr);
tass 68:0847e35d08a6 1738 if (filter_mode < 0)
tass 68:0847e35d08a6 1739 return -1;
tass 68:0847e35d08a6 1740
tass 70:cd218dd180e5 1741 return pico_ipv4_mcast_leave(&mreq->mcast_link_addr, &mreq->mcast_group_addr, 0, (uint8_t)filter_mode, &MCASTFilter);
tass 68:0847e35d08a6 1742 }
tass 68:0847e35d08a6 1743 break;
tass 68:0847e35d08a6 1744
tass 68:0847e35d08a6 1745 case PICO_IP_BLOCK_SOURCE:
tass 68:0847e35d08a6 1746 /* EXCLUDE mode */
tass 68:0847e35d08a6 1747 if (s->proto->proto_number == PICO_PROTO_UDP) {
tass 68:0847e35d08a6 1748 int filter_mode = 0;
tass 74:c146c4e346c4 1749 struct pico_ip_mreq_source *mreq = (struct pico_ip_mreq_source *)value;
tass 74:c146c4e346c4 1750 struct pico_mcast_listen *listen = NULL;
tass 68:0847e35d08a6 1751 struct pico_ip4 *source = NULL, stest = {0};
tass 74:c146c4e346c4 1752 struct pico_ipv4_link *mcast_link = setopt_multicast_check(s, value, 0, 1);
tass 74:c146c4e346c4 1753 if (!mcast_link)
tass 68:0847e35d08a6 1754 return -1;
tass 74:c146c4e346c4 1755 listen = listen_find(s, &mreq->mcast_link_addr, &mreq->mcast_group_addr);
tass 68:0847e35d08a6 1756 if (!listen) {
tass 74:c146c4e346c4 1757 dbg("pico_socket_setoption: ERROR PICO_IP_BLOCK_SOURCE before PICO_IP_ADD_MEMBERSHIP\n");
tass 68:0847e35d08a6 1758 pico_err = PICO_ERR_EINVAL;
tass 68:0847e35d08a6 1759 return -1;
tass 68:0847e35d08a6 1760 } else {
tass 68:0847e35d08a6 1761 if (listen->filter_mode != PICO_IP_MULTICAST_EXCLUDE) {
tass 68:0847e35d08a6 1762 so_mcast_dbg("pico_socket_setoption: ERROR any-source multicast (exclude) on source-specific multicast (include)\n");
tass 68:0847e35d08a6 1763 pico_err = PICO_ERR_EINVAL;
tass 68:0847e35d08a6 1764 return -1;
tass 68:0847e35d08a6 1765 }
tass 68:0847e35d08a6 1766 stest.addr = mreq->mcast_source_addr.addr;
tass 68:0847e35d08a6 1767 source = pico_tree_findKey(&listen->MCASTSources, &stest);
tass 68:0847e35d08a6 1768 if (source) {
tass 68:0847e35d08a6 1769 so_mcast_dbg("pico_socket_setoption: ERROR address to block already in source list\n");
tass 68:0847e35d08a6 1770 pico_err = PICO_ERR_EADDRNOTAVAIL;
tass 68:0847e35d08a6 1771 return -1;
tass 68:0847e35d08a6 1772 } else {
tass 68:0847e35d08a6 1773 source = pico_zalloc(sizeof(struct pico_ip4));
tass 68:0847e35d08a6 1774 if (!source) {
tass 68:0847e35d08a6 1775 pico_err = PICO_ERR_ENOMEM;
tass 68:0847e35d08a6 1776 return -1;
tass 68:0847e35d08a6 1777 }
tass 68:0847e35d08a6 1778 source->addr = mreq->mcast_source_addr.addr;
tass 68:0847e35d08a6 1779 pico_tree_insert(&listen->MCASTSources, source);
tass 68:0847e35d08a6 1780 }
tass 68:0847e35d08a6 1781 }
tass 68:0847e35d08a6 1782
tass 68:0847e35d08a6 1783 filter_mode = pico_socket_aggregate_mcastfilters(&mcast_link->address, &mreq->mcast_group_addr);
tass 68:0847e35d08a6 1784 if (filter_mode < 0)
tass 68:0847e35d08a6 1785 return -1;
tass 68:0847e35d08a6 1786
tass 70:cd218dd180e5 1787 return pico_ipv4_mcast_join(&mreq->mcast_link_addr, &mreq->mcast_group_addr, 0, (uint8_t)filter_mode, &MCASTFilter);
tass 68:0847e35d08a6 1788 }
tass 68:0847e35d08a6 1789 break;
tass 68:0847e35d08a6 1790
tass 68:0847e35d08a6 1791 case PICO_IP_ADD_SOURCE_MEMBERSHIP:
tass 68:0847e35d08a6 1792 /* INCLUDE mode */
tass 68:0847e35d08a6 1793 if (s->proto->proto_number == PICO_PROTO_UDP) {
tass 68:0847e35d08a6 1794 int filter_mode = 0, reference_count = 0;
tass 74:c146c4e346c4 1795 struct pico_ip_mreq_source *mreq = (struct pico_ip_mreq_source *)value;
tass 74:c146c4e346c4 1796 struct pico_mcast_listen *listen = NULL;
tass 68:0847e35d08a6 1797 struct pico_ip4 *source = NULL, stest = {0};
tass 74:c146c4e346c4 1798 struct pico_ipv4_link *mcast_link = setopt_multicast_check(s, value, 1, 1);
tass 74:c146c4e346c4 1799 if (!mcast_link)
tass 68:0847e35d08a6 1800 return -1;
tass 74:c146c4e346c4 1801 listen = listen_find(s, &mreq->mcast_link_addr, &mreq->mcast_group_addr);
tass 68:0847e35d08a6 1802 if (listen) {
tass 68:0847e35d08a6 1803 if (listen->filter_mode != PICO_IP_MULTICAST_INCLUDE) {
tass 68:0847e35d08a6 1804 so_mcast_dbg("pico_socket_setoption: ERROR source-specific multicast (include) on any-source multicast (exclude)\n");
tass 68:0847e35d08a6 1805 pico_err = PICO_ERR_EINVAL;
tass 68:0847e35d08a6 1806 return -1;
tass 68:0847e35d08a6 1807 }
tass 68:0847e35d08a6 1808 stest.addr = mreq->mcast_source_addr.addr;
tass 68:0847e35d08a6 1809 source = pico_tree_findKey(&listen->MCASTSources, &stest);
tass 68:0847e35d08a6 1810 if (source) {
tass 68:0847e35d08a6 1811 so_mcast_dbg("pico_socket_setoption: ERROR source address to allow already in source list\n");
tass 68:0847e35d08a6 1812 pico_err = PICO_ERR_EADDRNOTAVAIL;
tass 68:0847e35d08a6 1813 return -1;
tass 68:0847e35d08a6 1814 } else {
tass 68:0847e35d08a6 1815 source = pico_zalloc(sizeof(struct pico_ip4));
tass 68:0847e35d08a6 1816 if (!source) {
tass 68:0847e35d08a6 1817 pico_err = PICO_ERR_ENOMEM;
tass 68:0847e35d08a6 1818 return -1;
tass 68:0847e35d08a6 1819 }
tass 68:0847e35d08a6 1820 source->addr = mreq->mcast_source_addr.addr;
tass 68:0847e35d08a6 1821 pico_tree_insert(&listen->MCASTSources, source);
tass 68:0847e35d08a6 1822 }
tass 68:0847e35d08a6 1823 } else {
tass 68:0847e35d08a6 1824 listen = pico_zalloc(sizeof(struct pico_mcast_listen));
tass 68:0847e35d08a6 1825 if (!listen) {
tass 68:0847e35d08a6 1826 pico_err = PICO_ERR_ENOMEM;
tass 68:0847e35d08a6 1827 return -1;
tass 68:0847e35d08a6 1828 }
tass 68:0847e35d08a6 1829 listen->filter_mode = PICO_IP_MULTICAST_INCLUDE;
tass 68:0847e35d08a6 1830 listen->mcast_link = mreq->mcast_link_addr;
tass 68:0847e35d08a6 1831 listen->mcast_group = mreq->mcast_group_addr;
tass 68:0847e35d08a6 1832 listen->MCASTSources.root = &LEAF;
tass 68:0847e35d08a6 1833 listen->MCASTSources.compare = mcast_sources_cmp;
tass 68:0847e35d08a6 1834 source = pico_zalloc(sizeof(struct pico_ip4));
tass 68:0847e35d08a6 1835 if (!source) {
tass 68:0847e35d08a6 1836 pico_free(listen);
tass 68:0847e35d08a6 1837 pico_err = PICO_ERR_ENOMEM;
tass 68:0847e35d08a6 1838 return -1;
tass 68:0847e35d08a6 1839 }
tass 68:0847e35d08a6 1840 source->addr = mreq->mcast_source_addr.addr;
tass 68:0847e35d08a6 1841 pico_tree_insert(&listen->MCASTSources, source);
tass 68:0847e35d08a6 1842 pico_tree_insert(s->MCASTListen, listen);
tass 68:0847e35d08a6 1843 reference_count = 1;
tass 68:0847e35d08a6 1844 }
tass 68:0847e35d08a6 1845
tass 68:0847e35d08a6 1846 pico_tree_insert(&MCASTSockets, s);
tass 68:0847e35d08a6 1847 filter_mode = pico_socket_aggregate_mcastfilters(&mcast_link->address, &mreq->mcast_group_addr);
tass 68:0847e35d08a6 1848 if (filter_mode < 0)
tass 68:0847e35d08a6 1849 return -1;
tass 68:0847e35d08a6 1850
tass 70:cd218dd180e5 1851 return pico_ipv4_mcast_join(&mreq->mcast_link_addr, &mreq->mcast_group_addr, (uint8_t)reference_count, (uint8_t)filter_mode, &MCASTFilter);
tass 68:0847e35d08a6 1852 }
tass 68:0847e35d08a6 1853 break;
tass 68:0847e35d08a6 1854
tass 68:0847e35d08a6 1855 case PICO_IP_DROP_SOURCE_MEMBERSHIP:
tass 68:0847e35d08a6 1856 /* INCLUDE mode */
tass 68:0847e35d08a6 1857 if (s->proto->proto_number == PICO_PROTO_UDP) {
tass 68:0847e35d08a6 1858 int filter_mode = 0, reference_count = 0;
tass 74:c146c4e346c4 1859 struct pico_ip_mreq_source *mreq = (struct pico_ip_mreq_source *)value;
tass 74:c146c4e346c4 1860 struct pico_mcast_listen *listen = NULL;
tass 68:0847e35d08a6 1861 struct pico_ip4 *source = NULL, stest = {0};
tass 74:c146c4e346c4 1862 struct pico_ipv4_link *mcast_link = setopt_multicast_check(s, value, 0, 1);
tass 74:c146c4e346c4 1863 if (!mcast_link)
tass 68:0847e35d08a6 1864 return -1;
tass 74:c146c4e346c4 1865 listen = listen_find(s, &mreq->mcast_link_addr, &mreq->mcast_group_addr);
tass 68:0847e35d08a6 1866 if (!listen) {
tass 68:0847e35d08a6 1867 so_mcast_dbg("pico_socket_setoption: ERROR PICO_IP_DROP_SOURCE_MEMBERSHIP before PICO_IP_ADD_SOURCE_MEMBERSHIP\n");
tass 68:0847e35d08a6 1868 pico_err = PICO_ERR_EADDRNOTAVAIL;
tass 68:0847e35d08a6 1869 return -1;
tass 68:0847e35d08a6 1870 } else {
tass 68:0847e35d08a6 1871 if (listen->filter_mode != PICO_IP_MULTICAST_INCLUDE) {
tass 68:0847e35d08a6 1872 so_mcast_dbg("pico_socket_setoption: ERROR source-specific multicast (include) on any-source multicast (exclude)\n");
tass 68:0847e35d08a6 1873 pico_err = PICO_ERR_EINVAL;
tass 68:0847e35d08a6 1874 return -1;
tass 68:0847e35d08a6 1875 }
tass 68:0847e35d08a6 1876 stest.addr = mreq->mcast_source_addr.addr;
tass 68:0847e35d08a6 1877 source = pico_tree_findKey(&listen->MCASTSources, &stest);
tass 68:0847e35d08a6 1878 if (!source) {
tass 68:0847e35d08a6 1879 so_mcast_dbg("pico_socket_setoption: ERROR address to drop not in source list\n");
tass 68:0847e35d08a6 1880 pico_err = PICO_ERR_EADDRNOTAVAIL;
tass 68:0847e35d08a6 1881 return -1;
tass 68:0847e35d08a6 1882 } else {
tass 68:0847e35d08a6 1883 pico_tree_delete(&listen->MCASTSources, source);
tass 68:0847e35d08a6 1884 pico_free(source);
tass 68:0847e35d08a6 1885 if (pico_tree_empty(&listen->MCASTSources)) { /* 1 if empty, 0 otherwise */
tass 68:0847e35d08a6 1886 reference_count = 1;
tass 68:0847e35d08a6 1887 pico_tree_delete(s->MCASTListen, listen);
tass 68:0847e35d08a6 1888 pico_free(listen);
tass 68:0847e35d08a6 1889 if (pico_tree_empty(s->MCASTListen)) {
tass 68:0847e35d08a6 1890 pico_free(s->MCASTListen);
tass 68:0847e35d08a6 1891 s->MCASTListen = NULL;
tass 68:0847e35d08a6 1892 pico_tree_delete(&MCASTSockets, s);
tass 68:0847e35d08a6 1893 }
tass 68:0847e35d08a6 1894 }
tass 68:0847e35d08a6 1895 }
tass 68:0847e35d08a6 1896 }
tass 68:0847e35d08a6 1897
tass 68:0847e35d08a6 1898 filter_mode = pico_socket_aggregate_mcastfilters(&mcast_link->address, &mreq->mcast_group_addr);
tass 68:0847e35d08a6 1899 if (filter_mode < 0)
tass 68:0847e35d08a6 1900 return -1;
tass 68:0847e35d08a6 1901
tass 70:cd218dd180e5 1902 return pico_ipv4_mcast_leave(&mreq->mcast_link_addr, &mreq->mcast_group_addr, (uint8_t)reference_count, (uint8_t)filter_mode, &MCASTFilter);
tass 68:0847e35d08a6 1903 }
tass 68:0847e35d08a6 1904 break;
tass 68:0847e35d08a6 1905 #endif /* PICO_SUPPORT_MCAST */
tass 68:0847e35d08a6 1906
tass 68:0847e35d08a6 1907 default:
tass 68:0847e35d08a6 1908 pico_err = PICO_ERR_EINVAL;
tass 68:0847e35d08a6 1909 return -1;
tass 68:0847e35d08a6 1910 }
tass 68:0847e35d08a6 1911
tass 68:0847e35d08a6 1912 if (pico_err != PICO_ERR_NOERR)
tass 68:0847e35d08a6 1913 return -1;
tass 68:0847e35d08a6 1914 else
tass 68:0847e35d08a6 1915 return 0;
tass 68:0847e35d08a6 1916 }
tass 68:0847e35d08a6 1917
tass 68:0847e35d08a6 1918 #define PICO_SOCKET_GETOPT(socket,index) ((socket->opt_flags & (1 << index)) != 0)
tass 68:0847e35d08a6 1919
tass 68:0847e35d08a6 1920 int pico_socket_getoption(struct pico_socket *s, int option, void *value)
tass 68:0847e35d08a6 1921 {
tass 68:0847e35d08a6 1922 if (!s || !value) {
tass 68:0847e35d08a6 1923 pico_err = PICO_ERR_EINVAL;
tass 68:0847e35d08a6 1924 return -1;
tass 68:0847e35d08a6 1925 }
tass 68:0847e35d08a6 1926
tass 68:0847e35d08a6 1927 switch (option)
tass 68:0847e35d08a6 1928 {
tass 68:0847e35d08a6 1929 #ifdef PICO_SUPPORT_TCP
tass 68:0847e35d08a6 1930 case PICO_TCP_NODELAY:
tass 68:0847e35d08a6 1931 if (s->proto->proto_number == PICO_PROTO_TCP)
tass 68:0847e35d08a6 1932 /* state of the NODELAY option */
tass 68:0847e35d08a6 1933 *(int *)value = PICO_SOCKET_GETOPT(s,PICO_SOCKET_OPT_TCPNODELAY);
tass 68:0847e35d08a6 1934 else
tass 68:0847e35d08a6 1935 *(int *)value = 0;
tass 68:0847e35d08a6 1936 break;
tass 68:0847e35d08a6 1937 #endif
tass 68:0847e35d08a6 1938
tass 68:0847e35d08a6 1939 #ifdef PICO_SUPPORT_MCAST
tass 68:0847e35d08a6 1940 case PICO_IP_MULTICAST_IF:
tass 68:0847e35d08a6 1941 pico_err = PICO_ERR_EOPNOTSUPP;
tass 68:0847e35d08a6 1942 return -1;
tass 68:0847e35d08a6 1943 break;
tass 68:0847e35d08a6 1944
tass 68:0847e35d08a6 1945 case PICO_IP_MULTICAST_TTL:
tass 68:0847e35d08a6 1946 if (s->proto->proto_number == PICO_PROTO_UDP) {
tass 68:0847e35d08a6 1947 pico_udp_get_mc_ttl(s, (uint8_t *) value);
tass 68:0847e35d08a6 1948 } else {
tass 68:0847e35d08a6 1949 *(uint8_t *)value = 0;
tass 68:0847e35d08a6 1950 pico_err = PICO_ERR_EINVAL;
tass 68:0847e35d08a6 1951 return -1;
tass 68:0847e35d08a6 1952 }
tass 68:0847e35d08a6 1953 break;
tass 68:0847e35d08a6 1954
tass 68:0847e35d08a6 1955 case PICO_IP_MULTICAST_LOOP:
tass 68:0847e35d08a6 1956 if (s->proto->proto_number == PICO_PROTO_UDP) {
tass 68:0847e35d08a6 1957 *(uint8_t *)value = PICO_SOCKET_GETOPT(s,PICO_SOCKET_OPT_MULTICAST_LOOP);
tass 68:0847e35d08a6 1958 } else {
tass 68:0847e35d08a6 1959 *(uint8_t *)value = 0;
tass 68:0847e35d08a6 1960 pico_err = PICO_ERR_EINVAL;
tass 68:0847e35d08a6 1961 return -1;
tass 68:0847e35d08a6 1962 }
tass 68:0847e35d08a6 1963 break;
tass 68:0847e35d08a6 1964 #endif /* PICO_SUPPORT_MCAST */
tass 68:0847e35d08a6 1965
tass 68:0847e35d08a6 1966 default:
tass 68:0847e35d08a6 1967 pico_err = PICO_ERR_EINVAL;
tass 68:0847e35d08a6 1968 return -1;
tass 68:0847e35d08a6 1969 }
tass 68:0847e35d08a6 1970
tass 68:0847e35d08a6 1971 return 0;
tass 68:0847e35d08a6 1972 }
tass 68:0847e35d08a6 1973
tass 68:0847e35d08a6 1974
tass 68:0847e35d08a6 1975 int pico_socket_shutdown(struct pico_socket *s, int mode)
tass 68:0847e35d08a6 1976 {
tass 68:0847e35d08a6 1977 if (!s) {
tass 68:0847e35d08a6 1978 pico_err = PICO_ERR_EINVAL;
tass 68:0847e35d08a6 1979 return -1;
tass 68:0847e35d08a6 1980 } else {
tass 68:0847e35d08a6 1981 /* check if exists in tree */
tass 68:0847e35d08a6 1982 /* See task #178 */
tass 68:0847e35d08a6 1983 if (pico_check_socket(s) != 0) {
tass 68:0847e35d08a6 1984 pico_free(s); /* close socket after bind or connect failed */
tass 68:0847e35d08a6 1985 return 0;
tass 68:0847e35d08a6 1986 }
tass 68:0847e35d08a6 1987 }
tass 68:0847e35d08a6 1988
tass 68:0847e35d08a6 1989 #ifdef PICO_SUPPORT_UDP
tass 68:0847e35d08a6 1990 if (PROTO(s) == PICO_PROTO_UDP) {
tass 68:0847e35d08a6 1991 if (mode & PICO_SHUT_RDWR)
tass 68:0847e35d08a6 1992 pico_socket_alter_state(s, PICO_SOCKET_STATE_CLOSED, PICO_SOCKET_STATE_CLOSING |PICO_SOCKET_STATE_BOUND | PICO_SOCKET_STATE_CONNECTED, 0);
tass 68:0847e35d08a6 1993 else if (mode & PICO_SHUT_RD)
tass 68:0847e35d08a6 1994 pico_socket_alter_state(s, 0, PICO_SOCKET_STATE_BOUND, 0);
tass 68:0847e35d08a6 1995 }
tass 68:0847e35d08a6 1996 #endif
tass 68:0847e35d08a6 1997 #ifdef PICO_SUPPORT_TCP
tass 68:0847e35d08a6 1998 if (PROTO(s) == PICO_PROTO_TCP) {
tass 68:0847e35d08a6 1999 if(mode & PICO_SHUT_RDWR)
tass 76:938a140caf12 2000 {
tass 68:0847e35d08a6 2001 pico_socket_alter_state(s, PICO_SOCKET_STATE_SHUT_LOCAL | PICO_SOCKET_STATE_SHUT_REMOTE, 0, 0);
tass 76:938a140caf12 2002 pico_tcp_notify_closing(s);
tass 76:938a140caf12 2003 }
tass 68:0847e35d08a6 2004 else if (mode & PICO_SHUT_WR)
tass 68:0847e35d08a6 2005 pico_socket_alter_state(s, PICO_SOCKET_STATE_SHUT_LOCAL, 0, 0);
tass 68:0847e35d08a6 2006 else if (mode & PICO_SHUT_RD)
tass 68:0847e35d08a6 2007 pico_socket_alter_state(s, PICO_SOCKET_STATE_SHUT_REMOTE, 0, 0);
tass 68:0847e35d08a6 2008
tass 68:0847e35d08a6 2009 }
tass 68:0847e35d08a6 2010 #endif
tass 68:0847e35d08a6 2011 return 0;
tass 68:0847e35d08a6 2012 }
tass 68:0847e35d08a6 2013
tass 68:0847e35d08a6 2014 int pico_socket_close(struct pico_socket *s)
tass 68:0847e35d08a6 2015 {
tass 68:0847e35d08a6 2016 return pico_socket_shutdown(s, PICO_SHUT_RDWR);
tass 68:0847e35d08a6 2017 }
tass 68:0847e35d08a6 2018
tass 68:0847e35d08a6 2019 #ifdef PICO_SUPPORT_CRC
tass 68:0847e35d08a6 2020 static inline int pico_transport_crc_check(struct pico_frame *f)
tass 68:0847e35d08a6 2021 {
tass 68:0847e35d08a6 2022 struct pico_ipv4_hdr *net_hdr = (struct pico_ipv4_hdr *) f->net_hdr;
tass 68:0847e35d08a6 2023 struct pico_udp_hdr *udp_hdr = NULL;
tass 68:0847e35d08a6 2024 uint16_t checksum_invalid = 1;
tass 68:0847e35d08a6 2025
tass 68:0847e35d08a6 2026 switch (net_hdr->proto)
tass 68:0847e35d08a6 2027 {
tass 68:0847e35d08a6 2028 case PICO_PROTO_TCP:
tass 68:0847e35d08a6 2029 checksum_invalid = short_be(pico_tcp_checksum_ipv4(f));
tass 68:0847e35d08a6 2030 //dbg("TCP CRC validation == %u\n", checksum_invalid);
tass 68:0847e35d08a6 2031 if (checksum_invalid) {
tass 68:0847e35d08a6 2032 //dbg("TCP CRC: validation failed!\n");
tass 68:0847e35d08a6 2033 pico_frame_discard(f);
tass 68:0847e35d08a6 2034 return 0;
tass 68:0847e35d08a6 2035 }
tass 68:0847e35d08a6 2036 break;
tass 68:0847e35d08a6 2037
tass 68:0847e35d08a6 2038 case PICO_PROTO_UDP:
tass 68:0847e35d08a6 2039 udp_hdr = (struct pico_udp_hdr *) f->transport_hdr;
tass 68:0847e35d08a6 2040 if (short_be(udp_hdr->crc)) {
tass 68:0847e35d08a6 2041 checksum_invalid = short_be(pico_udp_checksum_ipv4(f));
tass 68:0847e35d08a6 2042 //dbg("UDP CRC validation == %u\n", checksum_invalid);
tass 68:0847e35d08a6 2043 if (checksum_invalid) {
tass 68:0847e35d08a6 2044 //dbg("UDP CRC: validation failed!\n");
tass 68:0847e35d08a6 2045 pico_frame_discard(f);
tass 68:0847e35d08a6 2046 return 0;
tass 68:0847e35d08a6 2047 }
tass 68:0847e35d08a6 2048 }
tass 68:0847e35d08a6 2049 break;
tass 68:0847e35d08a6 2050
tass 68:0847e35d08a6 2051 default:
tass 68:0847e35d08a6 2052 // Do nothing
tass 68:0847e35d08a6 2053 break;
tass 68:0847e35d08a6 2054 }
tass 68:0847e35d08a6 2055 return 1;
tass 68:0847e35d08a6 2056 }
tass 68:0847e35d08a6 2057 #else
tass 68:0847e35d08a6 2058 static inline int pico_transport_crc_check(struct pico_frame *f)
tass 68:0847e35d08a6 2059 {
tass 68:0847e35d08a6 2060 IGNORE_PARAMETER(f);
tass 68:0847e35d08a6 2061 return 1;
tass 68:0847e35d08a6 2062 }
tass 68:0847e35d08a6 2063 #endif /* PICO_SUPPORT_CRC */
tass 68:0847e35d08a6 2064
tass 68:0847e35d08a6 2065 int pico_transport_process_in(struct pico_protocol *self, struct pico_frame *f)
tass 68:0847e35d08a6 2066 {
tass 68:0847e35d08a6 2067 struct pico_trans *hdr = (struct pico_trans *) f->transport_hdr;
tass 68:0847e35d08a6 2068 int ret = 0;
tass 68:0847e35d08a6 2069
tass 68:0847e35d08a6 2070 if (!hdr) {
tass 68:0847e35d08a6 2071 pico_err = PICO_ERR_EFAULT;
tass 68:0847e35d08a6 2072 return -1;
tass 68:0847e35d08a6 2073 }
tass 68:0847e35d08a6 2074
tass 68:0847e35d08a6 2075 ret = pico_transport_crc_check(f);
tass 68:0847e35d08a6 2076 if (ret < 1)
tass 68:0847e35d08a6 2077 return ret;
tass 68:0847e35d08a6 2078 else
tass 68:0847e35d08a6 2079 ret = 0;
tass 68:0847e35d08a6 2080
tass 68:0847e35d08a6 2081 if ((hdr) && (pico_socket_deliver(self, f, hdr->dport) == 0))
tass 68:0847e35d08a6 2082 return ret;
tass 68:0847e35d08a6 2083
tass 68:0847e35d08a6 2084 if (!IS_BCAST(f)) {
tass 68:0847e35d08a6 2085 dbg("Socket not found... \n");
tass 68:0847e35d08a6 2086 pico_notify_socket_unreachable(f);
tass 68:0847e35d08a6 2087 #ifdef PICO_SUPPORT_TCP
tass 68:0847e35d08a6 2088 /* if tcp protocol send RST segment */
tass 68:0847e35d08a6 2089 //if (self->proto_number == PICO_PROTO_TCP)
tass 68:0847e35d08a6 2090 // pico_tcp_reply_rst(f);
tass 68:0847e35d08a6 2091 #endif
tass 68:0847e35d08a6 2092 ret = -1;
tass 68:0847e35d08a6 2093 pico_err = PICO_ERR_ENOENT;
tass 68:0847e35d08a6 2094 }
tass 68:0847e35d08a6 2095 pico_frame_discard(f);
tass 68:0847e35d08a6 2096 return ret;
tass 68:0847e35d08a6 2097 }
tass 68:0847e35d08a6 2098
tass 68:0847e35d08a6 2099 #define SL_LOOP_MIN 1
tass 68:0847e35d08a6 2100
tass 125:96003ae6f1d8 2101 #ifdef PICO_SUPPORT_TCP
tass 95:f4ca916a26fe 2102 static int checkSocketSanity(struct pico_socket *s)
tass 95:f4ca916a26fe 2103 {
tass 95:f4ca916a26fe 2104
tass 95:f4ca916a26fe 2105 // checking for pending connections
tass 95:f4ca916a26fe 2106 if(TCP_STATE(s) == PICO_SOCKET_STATE_TCP_SYN_RECV)
tass 128:ae39e6e81531 2107 if((pico_time)(PICO_TIME_MS() - s->timestamp) >= PICO_SOCKET_BOUND_TIMEOUT){
tass 95:f4ca916a26fe 2108 s->parent->number_of_pending_conn--;
tass 95:f4ca916a26fe 2109 return -1;
tass 95:f4ca916a26fe 2110 }
tass 128:ae39e6e81531 2111 if((pico_time)(PICO_TIME_MS() - s->timestamp) >= PICO_SOCKET_TIMEOUT) {
tass 95:f4ca916a26fe 2112 // checking for hanging sockets
tass 95:f4ca916a26fe 2113 if( (TCP_STATE(s) != PICO_SOCKET_STATE_TCP_LISTEN) && (TCP_STATE(s) != PICO_SOCKET_STATE_TCP_ESTABLISHED ) )
tass 95:f4ca916a26fe 2114 return -1;
tass 95:f4ca916a26fe 2115 // if no activity, force the socket into closing state
tass 95:f4ca916a26fe 2116 if( TCP_STATE(s) == PICO_SOCKET_STATE_TCP_ESTABLISHED )
tass 95:f4ca916a26fe 2117 {
tass 123:dd26752a4538 2118 s->wakeup(PICO_SOCK_EV_CLOSE,s);
tass 95:f4ca916a26fe 2119 pico_socket_close(s);
tass 95:f4ca916a26fe 2120 s->timestamp = PICO_TIME_MS();
tass 95:f4ca916a26fe 2121 }
tass 95:f4ca916a26fe 2122 }
tass 95:f4ca916a26fe 2123 return 0;
tass 95:f4ca916a26fe 2124 }
tass 125:96003ae6f1d8 2125 #endif
tass 95:f4ca916a26fe 2126
tass 68:0847e35d08a6 2127 int pico_sockets_loop(int loop_score)
tass 68:0847e35d08a6 2128 {
tass 125:96003ae6f1d8 2129 #ifdef PICO_SUPPORT_UDP
tass 125:96003ae6f1d8 2130 static struct pico_tree_node *index_udp;
tass 125:96003ae6f1d8 2131 #endif
tass 125:96003ae6f1d8 2132
tass 125:96003ae6f1d8 2133 #ifdef PICO_SUPPORT_TCP
tass 125:96003ae6f1d8 2134 static struct pico_tree_node* index_tcp;
tass 125:96003ae6f1d8 2135 #endif
tass 68:0847e35d08a6 2136
tass 68:0847e35d08a6 2137 struct pico_sockport *start;
tass 68:0847e35d08a6 2138 struct pico_socket *s;
tass 68:0847e35d08a6 2139
tass 68:0847e35d08a6 2140 #ifdef PICO_SUPPORT_UDP
tass 68:0847e35d08a6 2141 struct pico_frame *f;
tass 68:0847e35d08a6 2142
tass 68:0847e35d08a6 2143 if (sp_udp == NULL)
tass 68:0847e35d08a6 2144 {
tass 68:0847e35d08a6 2145 index_udp = pico_tree_firstNode(UDPTable.root);
tass 68:0847e35d08a6 2146 sp_udp = index_udp->keyValue;
tass 68:0847e35d08a6 2147 }
tass 68:0847e35d08a6 2148
tass 68:0847e35d08a6 2149 /* init start node */
tass 68:0847e35d08a6 2150 start = sp_udp;
tass 68:0847e35d08a6 2151
tass 68:0847e35d08a6 2152 /* round-robin all transport protocols, break if traversed all protocols */
tass 68:0847e35d08a6 2153 while (loop_score > SL_LOOP_MIN && sp_udp != NULL) {
tass 68:0847e35d08a6 2154 struct pico_tree_node * index;
tass 68:0847e35d08a6 2155
tass 68:0847e35d08a6 2156 pico_tree_foreach(index,&sp_udp->socks){
tass 68:0847e35d08a6 2157 s = index->keyValue;
tass 68:0847e35d08a6 2158 f = pico_dequeue(&s->q_out);
tass 68:0847e35d08a6 2159 while (f && (loop_score > 0)) {
tass 68:0847e35d08a6 2160 pico_proto_udp.push(&pico_proto_udp, f);
tass 68:0847e35d08a6 2161 loop_score -= 1;
tass 68:0847e35d08a6 2162 f = pico_dequeue(&s->q_out);
tass 68:0847e35d08a6 2163 }
tass 68:0847e35d08a6 2164 }
tass 68:0847e35d08a6 2165
tass 68:0847e35d08a6 2166 index_udp = pico_tree_next(index_udp);
tass 68:0847e35d08a6 2167 sp_udp = index_udp->keyValue;
tass 68:0847e35d08a6 2168
tass 68:0847e35d08a6 2169 if (sp_udp == NULL)
tass 68:0847e35d08a6 2170 {
tass 68:0847e35d08a6 2171 index_udp = pico_tree_firstNode(UDPTable.root);
tass 68:0847e35d08a6 2172 sp_udp = index_udp->keyValue;
tass 68:0847e35d08a6 2173 }
tass 68:0847e35d08a6 2174 if (sp_udp == start)
tass 68:0847e35d08a6 2175 break;
tass 68:0847e35d08a6 2176 }
tass 68:0847e35d08a6 2177 #endif
tass 68:0847e35d08a6 2178
tass 68:0847e35d08a6 2179 #ifdef PICO_SUPPORT_TCP
tass 68:0847e35d08a6 2180 if (sp_tcp == NULL)
tass 68:0847e35d08a6 2181 {
tass 68:0847e35d08a6 2182 index_tcp = pico_tree_firstNode(TCPTable.root);
tass 68:0847e35d08a6 2183 sp_tcp = index_tcp->keyValue;
tass 68:0847e35d08a6 2184 }
tass 68:0847e35d08a6 2185
tass 68:0847e35d08a6 2186 /* init start node */
tass 68:0847e35d08a6 2187 start = sp_tcp;
tass 68:0847e35d08a6 2188
tass 68:0847e35d08a6 2189 while (loop_score > SL_LOOP_MIN && sp_tcp != NULL) {
tass 68:0847e35d08a6 2190 struct pico_tree_node * index = NULL, * safe_index = NULL;
tass 68:0847e35d08a6 2191 pico_tree_foreach_safe(index, &sp_tcp->socks,safe_index){
tass 68:0847e35d08a6 2192 s = index->keyValue;
tass 68:0847e35d08a6 2193 loop_score = pico_tcp_output(s, loop_score);
tass 68:0847e35d08a6 2194 if ((s->ev_pending) && s->wakeup) {
tass 68:0847e35d08a6 2195 s->wakeup(s->ev_pending, s);
tass 122:5b1e9de8bf7f 2196 if(!s->parent)
tass 122:5b1e9de8bf7f 2197 s->ev_pending = 0;
tass 68:0847e35d08a6 2198 }
tass 68:0847e35d08a6 2199 if (loop_score <= 0) {
tass 68:0847e35d08a6 2200 loop_score = 0;
tass 68:0847e35d08a6 2201 break;
tass 68:0847e35d08a6 2202 }
tass 95:f4ca916a26fe 2203 if(checkSocketSanity(s) < 0)
tass 95:f4ca916a26fe 2204 {
tass 95:f4ca916a26fe 2205 pico_socket_del(s);
tass 95:f4ca916a26fe 2206 index_tcp = NULL; // forcing the restart of loop
tass 95:f4ca916a26fe 2207 sp_tcp = NULL;
tass 95:f4ca916a26fe 2208 break;
tass 68:0847e35d08a6 2209 }
tass 95:f4ca916a26fe 2210 }
tass 68:0847e35d08a6 2211
tass 68:0847e35d08a6 2212 /* check if RB_FOREACH ended, if not, break to keep the cur sp_tcp */
tass 95:f4ca916a26fe 2213 if (!index_tcp || (index && index->keyValue) )
tass 68:0847e35d08a6 2214 break;
tass 68:0847e35d08a6 2215
tass 68:0847e35d08a6 2216 index_tcp = pico_tree_next(index_tcp);
tass 68:0847e35d08a6 2217 sp_tcp = index_tcp->keyValue;
tass 68:0847e35d08a6 2218
tass 68:0847e35d08a6 2219 if (sp_tcp == NULL)
tass 68:0847e35d08a6 2220 {
tass 68:0847e35d08a6 2221 index_tcp = pico_tree_firstNode(TCPTable.root);
tass 68:0847e35d08a6 2222 sp_tcp = index_tcp->keyValue;
tass 68:0847e35d08a6 2223 }
tass 68:0847e35d08a6 2224 if (sp_tcp == start)
tass 68:0847e35d08a6 2225 break;
tass 68:0847e35d08a6 2226 }
tass 68:0847e35d08a6 2227 #endif
tass 68:0847e35d08a6 2228
tass 68:0847e35d08a6 2229 return loop_score;
tass 68:0847e35d08a6 2230 }
tass 68:0847e35d08a6 2231
tass 68:0847e35d08a6 2232
tass 70:cd218dd180e5 2233 struct pico_frame *pico_socket_frame_alloc(struct pico_socket *s, uint16_t len)
tass 68:0847e35d08a6 2234 {
tass 68:0847e35d08a6 2235 struct pico_frame *f = NULL;
tass 68:0847e35d08a6 2236
tass 68:0847e35d08a6 2237 #ifdef PICO_SUPPORT_IPV6
tass 68:0847e35d08a6 2238 if (IS_SOCK_IPV6(s))
tass 68:0847e35d08a6 2239 f = pico_proto_ipv6.alloc(&pico_proto_ipv6, len);
tass 68:0847e35d08a6 2240 #endif
tass 68:0847e35d08a6 2241
tass 68:0847e35d08a6 2242 #ifdef PICO_SUPPORT_IPV4
tass 68:0847e35d08a6 2243 if (IS_SOCK_IPV4(s))
tass 70:cd218dd180e5 2244 f = pico_proto_ipv4.alloc(&pico_proto_ipv4, (uint16_t)len);
tass 68:0847e35d08a6 2245 #endif
tass 68:0847e35d08a6 2246 if (!f) {
tass 68:0847e35d08a6 2247 pico_err = PICO_ERR_ENOMEM;
tass 68:0847e35d08a6 2248 return f;
tass 68:0847e35d08a6 2249 }
tass 68:0847e35d08a6 2250 f->payload = f->transport_hdr;
tass 68:0847e35d08a6 2251 f->payload_len = len;
tass 68:0847e35d08a6 2252 f->sock = s;
tass 68:0847e35d08a6 2253 return f;
tass 68:0847e35d08a6 2254 }
tass 68:0847e35d08a6 2255
tass 68:0847e35d08a6 2256 int pico_transport_error(struct pico_frame *f, uint8_t proto, int code)
tass 68:0847e35d08a6 2257 {
tass 68:0847e35d08a6 2258 int ret = -1;
tass 68:0847e35d08a6 2259 struct pico_trans *trans = (struct pico_trans*) f->transport_hdr;
tass 68:0847e35d08a6 2260 struct pico_sockport *port = NULL;
tass 68:0847e35d08a6 2261 struct pico_socket *s = NULL;
tass 68:0847e35d08a6 2262 switch (proto) {
tass 68:0847e35d08a6 2263
tass 68:0847e35d08a6 2264
tass 68:0847e35d08a6 2265 #ifdef PICO_SUPPORT_UDP
tass 68:0847e35d08a6 2266 case PICO_PROTO_UDP:
tass 68:0847e35d08a6 2267 port = pico_get_sockport(proto, trans->sport);
tass 68:0847e35d08a6 2268 break;
tass 68:0847e35d08a6 2269 #endif
tass 68:0847e35d08a6 2270
tass 68:0847e35d08a6 2271 #ifdef PICO_SUPPORT_TCP
tass 68:0847e35d08a6 2272 case PICO_PROTO_TCP:
tass 68:0847e35d08a6 2273 port = pico_get_sockport(proto, trans->sport);
tass 68:0847e35d08a6 2274 break;
tass 68:0847e35d08a6 2275 #endif
tass 68:0847e35d08a6 2276
tass 68:0847e35d08a6 2277 default:
tass 68:0847e35d08a6 2278 /* Protocol not available */
tass 68:0847e35d08a6 2279 ret = -1;
tass 68:0847e35d08a6 2280 }
tass 68:0847e35d08a6 2281 if (port) {
tass 68:0847e35d08a6 2282 struct pico_tree_node * index;
tass 68:0847e35d08a6 2283 ret = 0;
tass 68:0847e35d08a6 2284
tass 68:0847e35d08a6 2285 pico_tree_foreach(index,&port->socks) {
tass 68:0847e35d08a6 2286 s = index->keyValue;
tass 68:0847e35d08a6 2287 if (trans->dport == s->remote_port) {
tass 68:0847e35d08a6 2288 if (s->wakeup) {
tass 68:0847e35d08a6 2289 //dbg("SOCKET ERROR FROM ICMP NOTIFICATION. (icmp code= %d)\n\n", code);
tass 68:0847e35d08a6 2290 switch(code) {
tass 68:0847e35d08a6 2291 case PICO_ICMP_UNREACH_PROTOCOL:
tass 68:0847e35d08a6 2292 pico_err = PICO_ERR_EPROTO;
tass 68:0847e35d08a6 2293 break;
tass 68:0847e35d08a6 2294
tass 68:0847e35d08a6 2295 case PICO_ICMP_UNREACH_PORT:
tass 68:0847e35d08a6 2296 pico_err = PICO_ERR_ECONNREFUSED;
tass 68:0847e35d08a6 2297 break;
tass 68:0847e35d08a6 2298
tass 68:0847e35d08a6 2299 case PICO_ICMP_UNREACH_NET:
tass 68:0847e35d08a6 2300 case PICO_ICMP_UNREACH_NET_PROHIB:
tass 68:0847e35d08a6 2301 case PICO_ICMP_UNREACH_NET_UNKNOWN:
tass 68:0847e35d08a6 2302 pico_err = PICO_ERR_ENETUNREACH;
tass 68:0847e35d08a6 2303 break;
tass 68:0847e35d08a6 2304
tass 68:0847e35d08a6 2305 default:
tass 68:0847e35d08a6 2306 pico_err = PICO_ERR_EHOSTUNREACH;
tass 68:0847e35d08a6 2307 }
tass 122:5b1e9de8bf7f 2308 s->state |= PICO_SOCKET_STATE_SHUT_REMOTE;
tass 68:0847e35d08a6 2309 s->wakeup(PICO_SOCK_EV_ERR, s);
tass 122:5b1e9de8bf7f 2310
tass 68:0847e35d08a6 2311 }
tass 68:0847e35d08a6 2312 break;
tass 68:0847e35d08a6 2313 }
tass 68:0847e35d08a6 2314 }
tass 68:0847e35d08a6 2315 }
tass 68:0847e35d08a6 2316 pico_frame_discard(f);
tass 68:0847e35d08a6 2317 return ret;
tass 68:0847e35d08a6 2318 }
tass 68:0847e35d08a6 2319 #endif
tass 68:0847e35d08a6 2320 #endif