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 13:06:00 2013 +0000
Revision:
66:71a2ef45a035
Parent:
63:97f481e33cb2
Parent:
64:0225b609335e
Merged branches.

Who changed what in which revision?

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