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:
daniele
Date:
Fri May 24 15:25:25 2013 +0000
Revision:
3:b4047e8a0123
Updated from main repo + fixed Mutexes;

Who changed what in which revision?

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