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

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

PicoTCP. Copyright (c) 2013 TASS Belgium NV.

Released under the GNU General Public License, version 2.

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

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

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

Development steps:

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

Demo application (measuring TCP sender performance):

Import programlpc1768-picotcp-demo

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

Committer:
tass
Date:
Thu Sep 26 07:05:22 2013 +0000
Revision:
70:cd218dd180e5
Parent:
68:0847e35d08a6
Child:
73:dfb737147f6e
Update from masterbranch

Who changed what in which revision?

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