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

Dependents:   lpc1768-picotcp-demo ZeroMQ_PicoTCP_Publisher_demo TCPSocket_HelloWorld_PicoTCP Pico_TCP_UDP_Test ... more

PicoTCP. Copyright (c) 2013 TASS Belgium NV.

Released under the GNU General Public License, version 2.

Different licensing models may exist, at the sole discretion of the Copyright holders.

Official homepage: http://www.picotcp.com

Bug tracker: https://github.com/tass-belgium/picotcp/issues

Development steps:

  • initial integration with mbed RTOS
  • generic mbed Ethernet driver
  • high performance NXP LPC1768 specific Ethernet driver
  • Multi-threading support for mbed RTOS
  • Berkeley sockets and integration with the New Socket API
  • Fork of the apps running on top of the New Socket API
  • Scheduling optimizations
  • Debugging/benchmarking/testing

Demo application (measuring TCP sender performance):

Import programlpc1768-picotcp-demo

A PicoTCP demo app testing the ethernet throughput on the lpc1768 mbed board.

Committer:
tass
Date:
Thu Sep 19 12:38:53 2013 +0000
Revision:
63:97f481e33cb2
Parent:
51:ab4529a384a6
Child:
66:71a2ef45a035
Update from the master branch

Who changed what in which revision?

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