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

Fork of PicoTCP by Daniele Lacamera

Committer:
tass
Date:
Wed Jun 12 13:35:01 2013 +0000
Revision:
31:d3b2dfcc358f
Parent:
10:dd7111d4279f
updated pico_tcp and pico_socket after the mainline.

Who changed what in which revision?

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