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

Fork of PicoTCP by Daniele Lacamera

Committer:
daniele
Date:
Sat Aug 03 08:50:27 2013 +0000
Revision:
51:18637a3d071f
Parent:
29:1a47b7151851
Child:
49:40fc4462265c
Branch for CDC-ECM: Work in progress

Who changed what in which revision?

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