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

Fork of PicoTCP by Daniele Lacamera

Committer:
tass
Date:
Fri Aug 02 07:28:05 2013 +0000
Revision:
49:40fc4462265c
Parent:
29:1a47b7151851
Fixes for issues #8,#9,#10 from github.

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