CDC/ECM driver for mbed, based on USBDevice by mbed-official. Uses PicoTCP to access Ethernet USB device. License: GPLv2

Dependents:   USBEthernet_TEST

Fork of USB_Ethernet by Daniele Lacamera

Committer:
daniele
Date:
Sat Aug 03 13:16:14 2013 +0000
Revision:
2:540f6e142d59
Moved to single package

Who changed what in which revision?

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