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:
Wed Jun 12 13:35:01 2013 +0000
Revision:
31:d3b2dfcc358f
Parent:
10:dd7111d4279f
updated pico_tcp and pico_socket after the mainline.

Who changed what in which revision?

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