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:
Fri Oct 18 09:08:45 2013 +0000
Revision:
100:2a37cbd6814d
Parent:
95:f4ca916a26fe
Child:
110:0ece1bbbd36e
Fix Issue #39

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