Daniele Lacamera / PicoTCP-Experimental_CDC_ECM_Branch

Fork of PicoTCP by Daniele Lacamera

Committer:
daniele
Date:
Thu Apr 25 13:22:51 2013 +0000
Revision:
0:d7f2341ab245
Initial import of PicoTCP Free TCP/IP stack

Who changed what in which revision?

UserRevisionLine numberNew contents of line
daniele 0:d7f2341ab245 1 /*********************************************************************
daniele 0:d7f2341ab245 2 PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved.
daniele 0:d7f2341ab245 3 See LICENSE and COPYING for usage.
daniele 0:d7f2341ab245 4
daniele 0:d7f2341ab245 5
daniele 0:d7f2341ab245 6 Authors: Daniele Lacamera
daniele 0:d7f2341ab245 7 *********************************************************************/
daniele 0:d7f2341ab245 8
daniele 0:d7f2341ab245 9
daniele 0:d7f2341ab245 10 #include "pico_config.h"
daniele 0:d7f2341ab245 11 #include "pico_queue.h"
daniele 0:d7f2341ab245 12 #include "pico_socket.h"
daniele 0:d7f2341ab245 13 #include "pico_ipv4.h"
daniele 0:d7f2341ab245 14 #include "pico_ipv6.h"
daniele 0:d7f2341ab245 15 #include "pico_udp.h"
daniele 0:d7f2341ab245 16 #include "pico_tcp.h"
daniele 0:d7f2341ab245 17 #include "pico_stack.h"
daniele 0:d7f2341ab245 18 #include "pico_icmp4.h"
daniele 0:d7f2341ab245 19 #include "pico_nat.h"
daniele 0:d7f2341ab245 20 #include "pico_tree.h"
daniele 0:d7f2341ab245 21 #include "pico_device.h"
daniele 0:d7f2341ab245 22
daniele 0:d7f2341ab245 23 #if defined (PICO_SUPPORT_IPV4) || defined (PICO_SUPPORT_IPV6)
daniele 0:d7f2341ab245 24 #if defined (PICO_SUPPORT_TCP) || defined (PICO_SUPPORT_UDP)
daniele 0:d7f2341ab245 25
daniele 0:d7f2341ab245 26
daniele 0:d7f2341ab245 27 #define PROTO(s) ((s)->proto->proto_number)
daniele 0:d7f2341ab245 28
daniele 0:d7f2341ab245 29 #ifdef PICO_SUPPORT_TCP
daniele 0:d7f2341ab245 30 # define IS_NAGLE_ENABLED(s) (s->opt_flags & (1 << PICO_SOCKET_OPT_TCPNODELAY))
daniele 0:d7f2341ab245 31 #endif
daniele 0:d7f2341ab245 32
daniele 0:d7f2341ab245 33 #define PICO_SOCKET_MTU 1480 /* Ethernet MTU(1500) - IP header size(20) */
daniele 0:d7f2341ab245 34
daniele 0:d7f2341ab245 35 #ifdef PICO_SUPPORT_IPV4
daniele 0:d7f2341ab245 36 # define IS_SOCK_IPV4(s) ((s->net == &pico_proto_ipv4))
daniele 0:d7f2341ab245 37 #else
daniele 0:d7f2341ab245 38 # define IS_SOCK_IPV4(s) (0)
daniele 0:d7f2341ab245 39 #endif
daniele 0:d7f2341ab245 40
daniele 0:d7f2341ab245 41 #ifdef PICO_SUPPORT_IPV6
daniele 0:d7f2341ab245 42 # define IS_SOCK_IPV6(s) ((s->net == &pico_proto_ipv6))
daniele 0:d7f2341ab245 43 #else
daniele 0:d7f2341ab245 44 # define IS_SOCK_IPV6(s) (0)
daniele 0:d7f2341ab245 45 #endif
daniele 0:d7f2341ab245 46
daniele 0:d7f2341ab245 47 #ifdef PICO_SUPPORT_IPFRAG
daniele 0:d7f2341ab245 48 # define frag_dbg(...) do{}while(0)
daniele 0:d7f2341ab245 49 #endif
daniele 0:d7f2341ab245 50
daniele 0:d7f2341ab245 51 static struct pico_sockport *sp_udp = NULL ,*sp_tcp = NULL;
daniele 0:d7f2341ab245 52
daniele 0:d7f2341ab245 53 struct pico_frame *pico_socket_frame_alloc(struct pico_socket *s, int len);
daniele 0:d7f2341ab245 54
daniele 0:d7f2341ab245 55 static int socket_cmp(void * ka, void * kb)
daniele 0:d7f2341ab245 56 {
daniele 0:d7f2341ab245 57 struct pico_socket *a = ka, *b = kb;
daniele 0:d7f2341ab245 58 int a_is_ip6 = is_sock_ipv6(a);
daniele 0:d7f2341ab245 59 int b_is_ip6 = is_sock_ipv6(b);
daniele 0:d7f2341ab245 60
daniele 0:d7f2341ab245 61 int diff;
daniele 0:d7f2341ab245 62
daniele 0:d7f2341ab245 63 /* First, order by network ver */
daniele 0:d7f2341ab245 64 if (a_is_ip6 < b_is_ip6)
daniele 0:d7f2341ab245 65 return -1;
daniele 0:d7f2341ab245 66 if (a_is_ip6 > b_is_ip6)
daniele 0:d7f2341ab245 67 return 1;
daniele 0:d7f2341ab245 68
daniele 0:d7f2341ab245 69 /* If either socket is PICO_IPV4_INADDR_ANY mode, skip local address comparison */
daniele 0:d7f2341ab245 70
daniele 0:d7f2341ab245 71 /* At this point, sort by local host */
daniele 0:d7f2341ab245 72
daniele 0:d7f2341ab245 73 if (0) {
daniele 0:d7f2341ab245 74 #ifdef PICO_SUPPORT_IPV6
daniele 0:d7f2341ab245 75 } else if (a_is_ip6) {
daniele 0:d7f2341ab245 76 if ((memcmp(a->local_addr.ip6.addr, PICO_IP6_ANY, PICO_SIZE_IP6)==0) || memcmp((b->local_addr.ip6.addr, PICO_IP6_ANY, PICO_SIZE_IP6) == 0))
daniele 0:d7f2341ab245 77 diff = 0;
daniele 0:d7f2341ab245 78 else
daniele 0:d7f2341ab245 79 diff = memcmp(a->local_addr.ip6.addr, b->local_addr.ip6.addr, PICO_SIZE_IP6);
daniele 0:d7f2341ab245 80 #endif
daniele 0:d7f2341ab245 81 } else {
daniele 0:d7f2341ab245 82 if ((a->local_addr.ip4.addr == PICO_IP4_ANY) || (b->local_addr.ip4.addr == PICO_IP4_ANY))
daniele 0:d7f2341ab245 83 diff = 0;
daniele 0:d7f2341ab245 84 else
daniele 0:d7f2341ab245 85 diff = a->local_addr.ip4.addr - b->local_addr.ip4.addr;
daniele 0:d7f2341ab245 86 }
daniele 0:d7f2341ab245 87
daniele 0:d7f2341ab245 88 if (diff)
daniele 0:d7f2341ab245 89 return diff;
daniele 0:d7f2341ab245 90
daniele 0:d7f2341ab245 91
daniele 0:d7f2341ab245 92 /* Sort by remote host */
daniele 0:d7f2341ab245 93 if (a_is_ip6)
daniele 0:d7f2341ab245 94 diff = memcmp(a->remote_addr.ip6.addr, b->remote_addr.ip6.addr, PICO_SIZE_IP6);
daniele 0:d7f2341ab245 95 else
daniele 0:d7f2341ab245 96 diff = a->remote_addr.ip4.addr - b->remote_addr.ip4.addr;
daniele 0:d7f2341ab245 97
daniele 0:d7f2341ab245 98 if (diff)
daniele 0:d7f2341ab245 99 return diff;
daniele 0:d7f2341ab245 100
daniele 0:d7f2341ab245 101 /* And finally by remote port. The two sockets are coincident if the quad is the same. */
daniele 0:d7f2341ab245 102 return b->remote_port - a->remote_port;
daniele 0:d7f2341ab245 103 }
daniele 0:d7f2341ab245 104
daniele 0:d7f2341ab245 105 struct pico_sockport
daniele 0:d7f2341ab245 106 {
daniele 0:d7f2341ab245 107 struct pico_tree socks; // how you make the connection ?
daniele 0:d7f2341ab245 108 uint16_t number;
daniele 0:d7f2341ab245 109 uint16_t proto;
daniele 0:d7f2341ab245 110 };
daniele 0:d7f2341ab245 111
daniele 0:d7f2341ab245 112 #define INIT_SOCKPORT { {&LEAF , socket_cmp}, 0, 0 }
daniele 0:d7f2341ab245 113
daniele 0:d7f2341ab245 114 int sockport_cmp(void * ka, void * kb)
daniele 0:d7f2341ab245 115 {
daniele 0:d7f2341ab245 116 struct pico_sockport *a = ka, *b = kb;
daniele 0:d7f2341ab245 117 if (a->number < b->number)
daniele 0:d7f2341ab245 118 return -1;
daniele 0:d7f2341ab245 119 if (a->number > b->number)
daniele 0:d7f2341ab245 120 return 1;
daniele 0:d7f2341ab245 121 return 0;
daniele 0:d7f2341ab245 122 }
daniele 0:d7f2341ab245 123
daniele 0:d7f2341ab245 124 PICO_TREE_DECLARE(UDPTable,sockport_cmp);
daniele 0:d7f2341ab245 125 PICO_TREE_DECLARE(TCPTable,sockport_cmp);
daniele 0:d7f2341ab245 126
daniele 0:d7f2341ab245 127 static struct pico_sockport *pico_get_sockport(uint16_t proto, uint16_t port)
daniele 0:d7f2341ab245 128 {
daniele 0:d7f2341ab245 129 struct pico_sockport test = INIT_SOCKPORT;
daniele 0:d7f2341ab245 130 test.number = port;
daniele 0:d7f2341ab245 131
daniele 0:d7f2341ab245 132 if (proto == PICO_PROTO_UDP)
daniele 0:d7f2341ab245 133 return pico_tree_findKey(&UDPTable,&test);
daniele 0:d7f2341ab245 134
daniele 0:d7f2341ab245 135 else if (proto == PICO_PROTO_TCP)
daniele 0:d7f2341ab245 136 return pico_tree_findKey(&TCPTable,&test);
daniele 0:d7f2341ab245 137
daniele 0:d7f2341ab245 138 else return NULL;
daniele 0:d7f2341ab245 139 }
daniele 0:d7f2341ab245 140
daniele 0:d7f2341ab245 141 int pico_is_port_free(uint16_t proto, uint16_t port, void *addr, void *net)
daniele 0:d7f2341ab245 142 {
daniele 0:d7f2341ab245 143 struct pico_sockport *sp;
daniele 0:d7f2341ab245 144 struct pico_ip4 ip;
daniele 0:d7f2341ab245 145 sp = pico_get_sockport(proto, port);
daniele 0:d7f2341ab245 146
daniele 0:d7f2341ab245 147 if (!net)
daniele 0:d7f2341ab245 148 net = &pico_proto_ipv4;
daniele 0:d7f2341ab245 149
daniele 0:d7f2341ab245 150 /** IPv6 (wip) ***/
daniele 0:d7f2341ab245 151 if (net != &pico_proto_ipv4) {
daniele 0:d7f2341ab245 152 dbg("IPV6!!!!!\n");
daniele 0:d7f2341ab245 153 return (!sp);
daniele 0:d7f2341ab245 154 }
daniele 0:d7f2341ab245 155
daniele 0:d7f2341ab245 156 /* IPv4 */
daniele 0:d7f2341ab245 157 #ifdef PICO_SUPPORT_NAT
daniele 0:d7f2341ab245 158 if (pico_ipv4_nat_find(port,NULL, 0,proto) == 0) {
daniele 0:d7f2341ab245 159 dbg("In use by nat....\n");
daniele 0:d7f2341ab245 160 return 0;
daniele 0:d7f2341ab245 161 }
daniele 0:d7f2341ab245 162 #endif
daniele 0:d7f2341ab245 163 if (addr)
daniele 0:d7f2341ab245 164 ip.addr = ((struct pico_ip4 *)addr)->addr;
daniele 0:d7f2341ab245 165 else
daniele 0:d7f2341ab245 166 ip.addr = PICO_IPV4_INADDR_ANY;
daniele 0:d7f2341ab245 167
daniele 0:d7f2341ab245 168 if (ip.addr == PICO_IPV4_INADDR_ANY) {
daniele 0:d7f2341ab245 169 if (!sp) return 1;
daniele 0:d7f2341ab245 170 else {
daniele 0:d7f2341ab245 171 dbg("In use, and asked for ANY\n");
daniele 0:d7f2341ab245 172 return 0;
daniele 0:d7f2341ab245 173 }
daniele 0:d7f2341ab245 174 }
daniele 0:d7f2341ab245 175 if (sp) {
daniele 0:d7f2341ab245 176 struct pico_ip4 *s_local;
daniele 0:d7f2341ab245 177 struct pico_tree_node *idx;
daniele 0:d7f2341ab245 178 struct pico_socket *s;
daniele 0:d7f2341ab245 179 pico_tree_foreach(idx, &sp->socks) {
daniele 0:d7f2341ab245 180 s = idx->keyValue;
daniele 0:d7f2341ab245 181 if (s->net == &pico_proto_ipv4) {
daniele 0:d7f2341ab245 182 s_local = (struct pico_ip4*) &s->local_addr;
daniele 0:d7f2341ab245 183 if ((s_local->addr == PICO_IPV4_INADDR_ANY) || (s_local->addr == ip.addr))
daniele 0:d7f2341ab245 184 return 0;
daniele 0:d7f2341ab245 185 }
daniele 0:d7f2341ab245 186 }
daniele 0:d7f2341ab245 187 }
daniele 0:d7f2341ab245 188 return 1;
daniele 0:d7f2341ab245 189 }
daniele 0:d7f2341ab245 190
daniele 0:d7f2341ab245 191 static int pico_check_socket(struct pico_socket *s)
daniele 0:d7f2341ab245 192 {
daniele 0:d7f2341ab245 193 struct pico_sockport *test;
daniele 0:d7f2341ab245 194 struct pico_socket *found;
daniele 0:d7f2341ab245 195 struct pico_tree_node * index;
daniele 0:d7f2341ab245 196
daniele 0:d7f2341ab245 197 test = pico_get_sockport(PROTO(s), s->local_port);
daniele 0:d7f2341ab245 198
daniele 0:d7f2341ab245 199 if (!test) {
daniele 0:d7f2341ab245 200 return -1;
daniele 0:d7f2341ab245 201 }
daniele 0:d7f2341ab245 202
daniele 0:d7f2341ab245 203 pico_tree_foreach(index,&test->socks){
daniele 0:d7f2341ab245 204 found = index->keyValue;
daniele 0:d7f2341ab245 205 if (s == found) {
daniele 0:d7f2341ab245 206 return 0;
daniele 0:d7f2341ab245 207 }
daniele 0:d7f2341ab245 208 }
daniele 0:d7f2341ab245 209
daniele 0:d7f2341ab245 210 return -1;
daniele 0:d7f2341ab245 211 }
daniele 0:d7f2341ab245 212
daniele 0:d7f2341ab245 213
daniele 0:d7f2341ab245 214 int pico_socket_add(struct pico_socket *s)
daniele 0:d7f2341ab245 215 {
daniele 0:d7f2341ab245 216 struct pico_sockport *sp = pico_get_sockport(PROTO(s), s->local_port);
daniele 0:d7f2341ab245 217 if (!sp) {
daniele 0:d7f2341ab245 218 //dbg("Creating sockport..%04x\n", s->local_port); /* In comment due to spam during test */
daniele 0:d7f2341ab245 219 sp = pico_zalloc(sizeof(struct pico_sockport));
daniele 0:d7f2341ab245 220
daniele 0:d7f2341ab245 221 if (!sp) {
daniele 0:d7f2341ab245 222 pico_err = PICO_ERR_ENOMEM;
daniele 0:d7f2341ab245 223 return -1;
daniele 0:d7f2341ab245 224 }
daniele 0:d7f2341ab245 225 sp->proto = PROTO(s);
daniele 0:d7f2341ab245 226 sp->number = s->local_port;
daniele 0:d7f2341ab245 227 sp->socks.root = &LEAF;
daniele 0:d7f2341ab245 228 sp->socks.compare = socket_cmp;
daniele 0:d7f2341ab245 229
daniele 0:d7f2341ab245 230 if (PROTO(s) == PICO_PROTO_UDP)
daniele 0:d7f2341ab245 231 {
daniele 0:d7f2341ab245 232 pico_tree_insert(&UDPTable,sp);
daniele 0:d7f2341ab245 233 }
daniele 0:d7f2341ab245 234 else if (PROTO(s) == PICO_PROTO_TCP)
daniele 0:d7f2341ab245 235 {
daniele 0:d7f2341ab245 236 pico_tree_insert(&TCPTable,sp);
daniele 0:d7f2341ab245 237 }
daniele 0:d7f2341ab245 238 }
daniele 0:d7f2341ab245 239
daniele 0:d7f2341ab245 240 pico_tree_insert(&sp->socks,s);
daniele 0:d7f2341ab245 241 s->state |= PICO_SOCKET_STATE_BOUND;
daniele 0:d7f2341ab245 242
daniele 0:d7f2341ab245 243 #if DEBUG_SOCKET_TREE
daniele 0:d7f2341ab245 244 {
daniele 0:d7f2341ab245 245 struct pico_tree_node * index;
daniele 0:d7f2341ab245 246 //RB_FOREACH(s, socket_tree, &sp->socks) {
daniele 0:d7f2341ab245 247 pico_tree_foreach(index,&sp->socks){
daniele 0:d7f2341ab245 248 s = index->keyValue;
daniele 0:d7f2341ab245 249 dbg(">>>> List Socket lc=%hu rm=%hu\n", short_be(s->local_port), short_be(s->remote_port));
daniele 0:d7f2341ab245 250 }
daniele 0:d7f2341ab245 251
daniele 0:d7f2341ab245 252 }
daniele 0:d7f2341ab245 253 #endif
daniele 0:d7f2341ab245 254 return 0;
daniele 0:d7f2341ab245 255 }
daniele 0:d7f2341ab245 256
daniele 0:d7f2341ab245 257 static void socket_garbage_collect(unsigned long now, void *arg)
daniele 0:d7f2341ab245 258 {
daniele 0:d7f2341ab245 259 struct pico_socket *s = (struct pico_socket *) arg;
daniele 0:d7f2341ab245 260 pico_free(s);
daniele 0:d7f2341ab245 261 }
daniele 0:d7f2341ab245 262
daniele 0:d7f2341ab245 263 int pico_socket_del(struct pico_socket *s)
daniele 0:d7f2341ab245 264 {
daniele 0:d7f2341ab245 265 struct pico_sockport *sp = pico_get_sockport(PROTO(s), s->local_port);
daniele 0:d7f2341ab245 266
daniele 0:d7f2341ab245 267 if (!sp) {
daniele 0:d7f2341ab245 268 pico_err = PICO_ERR_ENXIO;
daniele 0:d7f2341ab245 269 return -1;
daniele 0:d7f2341ab245 270 }
daniele 0:d7f2341ab245 271 pico_tree_delete(&sp->socks,s);
daniele 0:d7f2341ab245 272
daniele 0:d7f2341ab245 273 if(pico_tree_empty(&sp->socks)){
daniele 0:d7f2341ab245 274 if (PROTO(s) == PICO_PROTO_UDP)
daniele 0:d7f2341ab245 275 {
daniele 0:d7f2341ab245 276 pico_tree_delete(&UDPTable,sp);
daniele 0:d7f2341ab245 277 }
daniele 0:d7f2341ab245 278 else if (PROTO(s) == PICO_PROTO_TCP)
daniele 0:d7f2341ab245 279 {
daniele 0:d7f2341ab245 280 pico_tree_delete(&TCPTable,sp);
daniele 0:d7f2341ab245 281 }
daniele 0:d7f2341ab245 282
daniele 0:d7f2341ab245 283 if(sp_tcp == sp) sp_tcp = NULL;
daniele 0:d7f2341ab245 284
daniele 0:d7f2341ab245 285 if(sp_udp == sp) sp_udp = NULL;
daniele 0:d7f2341ab245 286
daniele 0:d7f2341ab245 287 pico_free(sp);
daniele 0:d7f2341ab245 288
daniele 0:d7f2341ab245 289 }
daniele 0:d7f2341ab245 290
daniele 0:d7f2341ab245 291 s->state = PICO_SOCKET_STATE_CLOSED;
daniele 0:d7f2341ab245 292 pico_timer_add(3000, socket_garbage_collect, s);
daniele 0:d7f2341ab245 293
daniele 0:d7f2341ab245 294
daniele 0:d7f2341ab245 295 return 0;
daniele 0:d7f2341ab245 296 }
daniele 0:d7f2341ab245 297
daniele 0:d7f2341ab245 298 static int pico_socket_alter_state(struct pico_socket *s, uint16_t more_states, uint16_t less_states, uint16_t tcp_state)
daniele 0:d7f2341ab245 299 {
daniele 0:d7f2341ab245 300 struct pico_sockport *sp;
daniele 0:d7f2341ab245 301 if (more_states & PICO_SOCKET_STATE_BOUND)
daniele 0:d7f2341ab245 302 return pico_socket_add(s);
daniele 0:d7f2341ab245 303
daniele 0:d7f2341ab245 304 if (less_states & PICO_SOCKET_STATE_BOUND)
daniele 0:d7f2341ab245 305 return pico_socket_del(s);
daniele 0:d7f2341ab245 306
daniele 0:d7f2341ab245 307 sp = pico_get_sockport(PROTO(s), s->local_port);
daniele 0:d7f2341ab245 308 if (!sp) {
daniele 0:d7f2341ab245 309 pico_err = PICO_ERR_ENXIO;
daniele 0:d7f2341ab245 310 return -1;
daniele 0:d7f2341ab245 311 }
daniele 0:d7f2341ab245 312
daniele 0:d7f2341ab245 313 s->state |= more_states;
daniele 0:d7f2341ab245 314 s->state &= (~less_states);
daniele 0:d7f2341ab245 315 if (tcp_state) {
daniele 0:d7f2341ab245 316 s->state &= 0x00FF;
daniele 0:d7f2341ab245 317 s->state |= tcp_state;
daniele 0:d7f2341ab245 318 }
daniele 0:d7f2341ab245 319
daniele 0:d7f2341ab245 320 return 0;
daniele 0:d7f2341ab245 321 }
daniele 0:d7f2341ab245 322
daniele 0:d7f2341ab245 323 static int pico_socket_deliver(struct pico_protocol *p, struct pico_frame *f, uint16_t localport)
daniele 0:d7f2341ab245 324 {
daniele 0:d7f2341ab245 325 struct pico_frame *cpy = NULL;
daniele 0:d7f2341ab245 326 struct pico_sockport *sp = NULL;
daniele 0:d7f2341ab245 327 struct pico_socket *s = NULL, *found = NULL;
daniele 0:d7f2341ab245 328 struct pico_tree_node *index = NULL;
daniele 0:d7f2341ab245 329 struct pico_trans *tr = (struct pico_trans *) f->transport_hdr;
daniele 0:d7f2341ab245 330 #ifdef PICO_SUPPORT_IPV4
daniele 0:d7f2341ab245 331 struct pico_ipv4_hdr *ip4hdr;
daniele 0:d7f2341ab245 332 #endif
daniele 0:d7f2341ab245 333 #ifdef PICO_SUPPORT_IPV6
daniele 0:d7f2341ab245 334 struct pico_ipv6_hdr *ip6hdr;
daniele 0:d7f2341ab245 335 #endif
daniele 0:d7f2341ab245 336
daniele 0:d7f2341ab245 337 if (!tr)
daniele 0:d7f2341ab245 338 return -1;
daniele 0:d7f2341ab245 339
daniele 0:d7f2341ab245 340 sp = pico_get_sockport(p->proto_number, localport);
daniele 0:d7f2341ab245 341
daniele 0:d7f2341ab245 342 if (!sp) {
daniele 0:d7f2341ab245 343 dbg("No such port %d\n",short_be(localport));
daniele 0:d7f2341ab245 344 return -1;
daniele 0:d7f2341ab245 345 }
daniele 0:d7f2341ab245 346
daniele 0:d7f2341ab245 347 #ifdef PICO_SUPPORT_TCP
daniele 0:d7f2341ab245 348 if (p->proto_number == PICO_PROTO_TCP) {
daniele 0:d7f2341ab245 349 pico_tree_foreach(index,&sp->socks){
daniele 0:d7f2341ab245 350 s = index->keyValue;
daniele 0:d7f2341ab245 351 /* 4-tuple identification of socket (port-IP) */
daniele 0:d7f2341ab245 352 #ifdef PICO_SUPPORT_IPV4
daniele 0:d7f2341ab245 353 if (IS_IPV4(f)) {
daniele 0:d7f2341ab245 354 struct pico_ip4 s_local, s_remote, p_src, p_dst;
daniele 0:d7f2341ab245 355 ip4hdr = (struct pico_ipv4_hdr*)(f->net_hdr);
daniele 0:d7f2341ab245 356 s_local.addr = s->local_addr.ip4.addr;
daniele 0:d7f2341ab245 357 s_remote.addr = s->remote_addr.ip4.addr;
daniele 0:d7f2341ab245 358 p_src.addr = ip4hdr->src.addr;
daniele 0:d7f2341ab245 359 p_dst.addr = ip4hdr->dst.addr;
daniele 0:d7f2341ab245 360 if ( (s->remote_port == tr->sport) && /* remote port check */
daniele 0:d7f2341ab245 361 (s_remote.addr == p_src.addr) && /* remote addr check */
daniele 0:d7f2341ab245 362 ((s_local.addr == PICO_IPV4_INADDR_ANY) || (s_local.addr == p_dst.addr))) { /* Either local socket is ANY, or matches dst */
daniele 0:d7f2341ab245 363 found = s;
daniele 0:d7f2341ab245 364 break;
daniele 0:d7f2341ab245 365 } else if ( (s->remote_port == 0) && /* not connected... listening */
daniele 0:d7f2341ab245 366 ((s_local.addr == PICO_IPV4_INADDR_ANY) || (s_local.addr == p_dst.addr))) { /* Either local socket is ANY, or matches dst */
daniele 0:d7f2341ab245 367 /* listen socket */
daniele 0:d7f2341ab245 368 found = s;
daniele 0:d7f2341ab245 369 }
daniele 0:d7f2341ab245 370 }
daniele 0:d7f2341ab245 371 #endif
daniele 0:d7f2341ab245 372 #ifdef PICO_SUPPORT_IPV6 /* XXX TODO make compare for ipv6 addresses */
daniele 0:d7f2341ab245 373 if (IS_IPV6(f)) {
daniele 0:d7f2341ab245 374 ip6hdr = (struct pico_ipv6_hdr*)(f->net_hdr);
daniele 0:d7f2341ab245 375 if ( (s->remote_port == localport) ) { // && (((struct pico_ip6) s->remote_addr.ip6).addr == ((struct pico_ip6)(ip6hdr->src)).addr) ) {
daniele 0:d7f2341ab245 376 found = s;
daniele 0:d7f2341ab245 377 break;
daniele 0:d7f2341ab245 378 } else if (s->remote_port == 0) {
daniele 0:d7f2341ab245 379 /* listen socket */
daniele 0:d7f2341ab245 380 found = s;
daniele 0:d7f2341ab245 381 }
daniele 0:d7f2341ab245 382 }
daniele 0:d7f2341ab245 383 #endif
daniele 0:d7f2341ab245 384 } /* FOREACH */
daniele 0:d7f2341ab245 385 if (found != NULL) {
daniele 0:d7f2341ab245 386 pico_tcp_input(found,f);
daniele 0:d7f2341ab245 387 if ((found->ev_pending) && found->wakeup) {
daniele 0:d7f2341ab245 388 found->wakeup(found->ev_pending, found);
daniele 0:d7f2341ab245 389 }
daniele 0:d7f2341ab245 390 return 0;
daniele 0:d7f2341ab245 391 } else {
daniele 0:d7f2341ab245 392 dbg("SOCKET> mmm something wrong (prob sockport)\n");
daniele 0:d7f2341ab245 393 return -1;
daniele 0:d7f2341ab245 394 }
daniele 0:d7f2341ab245 395 } /* TCP CASE */
daniele 0:d7f2341ab245 396 #endif
daniele 0:d7f2341ab245 397
daniele 0:d7f2341ab245 398 #ifdef PICO_SUPPORT_UDP
daniele 0:d7f2341ab245 399 if (p->proto_number == PICO_PROTO_UDP) {
daniele 0:d7f2341ab245 400 pico_tree_foreach(index, &sp->socks) {
daniele 0:d7f2341ab245 401 s = index->keyValue;
daniele 0:d7f2341ab245 402 if (IS_IPV4(f)) { /* IPV4 */
daniele 0:d7f2341ab245 403 struct pico_ip4 s_local, p_dst;
daniele 0:d7f2341ab245 404 ip4hdr = (struct pico_ipv4_hdr*)(f->net_hdr);
daniele 0:d7f2341ab245 405 s_local.addr = s->local_addr.ip4.addr;
daniele 0:d7f2341ab245 406 p_dst.addr = ip4hdr->dst.addr;
daniele 0:d7f2341ab245 407 if ((pico_ipv4_is_broadcast(p_dst.addr)) || !pico_ipv4_is_unicast(p_dst.addr)) {
daniele 0:d7f2341ab245 408 struct pico_device *dev = pico_ipv4_link_find(&s->local_addr.ip4);
daniele 0:d7f2341ab245 409 if ((s_local.addr == PICO_IPV4_INADDR_ANY) || /* If our local ip is ANY, or.. */
daniele 0:d7f2341ab245 410 (dev == f->dev) ) { /* the source of the bcast packet is a neighbor... */
daniele 0:d7f2341ab245 411 cpy = pico_frame_copy(f);
daniele 0:d7f2341ab245 412 if (!cpy)
daniele 0:d7f2341ab245 413 return -1;
daniele 0:d7f2341ab245 414 if (pico_enqueue(&s->q_in, cpy) > 0) {
daniele 0:d7f2341ab245 415 if (s->wakeup)
daniele 0:d7f2341ab245 416 s->wakeup(PICO_SOCK_EV_RD, s);
daniele 0:d7f2341ab245 417 }
daniele 0:d7f2341ab245 418 }
daniele 0:d7f2341ab245 419 } else if ((s_local.addr == PICO_IPV4_INADDR_ANY) || (s_local.addr == p_dst.addr))
daniele 0:d7f2341ab245 420 { /* Either local socket is ANY, or matches dst */
daniele 0:d7f2341ab245 421 cpy = pico_frame_copy(f);
daniele 0:d7f2341ab245 422 if (!cpy)
daniele 0:d7f2341ab245 423 return -1;
daniele 0:d7f2341ab245 424 if (pico_enqueue(&s->q_in, cpy) > 0) {
daniele 0:d7f2341ab245 425 if (s->wakeup)
daniele 0:d7f2341ab245 426 s->wakeup(PICO_SOCK_EV_RD, s);
daniele 0:d7f2341ab245 427 }
daniele 0:d7f2341ab245 428 }
daniele 0:d7f2341ab245 429 } else {
daniele 0:d7f2341ab245 430 /*... IPv6 */
daniele 0:d7f2341ab245 431 }
daniele 0:d7f2341ab245 432 } /* FOREACH */
daniele 0:d7f2341ab245 433 pico_frame_discard(f);
daniele 0:d7f2341ab245 434 if (s)
daniele 0:d7f2341ab245 435 return 0;
daniele 0:d7f2341ab245 436 else
daniele 0:d7f2341ab245 437 return -1;
daniele 0:d7f2341ab245 438 }
daniele 0:d7f2341ab245 439 #endif
daniele 0:d7f2341ab245 440 return -1;
daniele 0:d7f2341ab245 441 }
daniele 0:d7f2341ab245 442
daniele 0:d7f2341ab245 443 struct pico_socket *pico_socket_open(uint16_t net, uint16_t proto, void (*wakeup)(uint16_t ev, struct pico_socket *))
daniele 0:d7f2341ab245 444 {
daniele 0:d7f2341ab245 445
daniele 0:d7f2341ab245 446 struct pico_socket *s = NULL;
daniele 0:d7f2341ab245 447
daniele 0:d7f2341ab245 448 #ifdef PICO_SUPPORT_UDP
daniele 0:d7f2341ab245 449 if (proto == PICO_PROTO_UDP) {
daniele 0:d7f2341ab245 450 s = pico_udp_open();
daniele 0:d7f2341ab245 451 s->proto = &pico_proto_udp;
daniele 0:d7f2341ab245 452 }
daniele 0:d7f2341ab245 453 #endif
daniele 0:d7f2341ab245 454
daniele 0:d7f2341ab245 455 #ifdef PICO_SUPPORT_TCP
daniele 0:d7f2341ab245 456 if (proto == PICO_PROTO_TCP) {
daniele 0:d7f2341ab245 457 s = pico_tcp_open();
daniele 0:d7f2341ab245 458 s->proto = &pico_proto_tcp;
daniele 0:d7f2341ab245 459 /*check if Nagle enabled */
daniele 0:d7f2341ab245 460 if (!IS_NAGLE_ENABLED(s))
daniele 0:d7f2341ab245 461 dbg("ERROR Nagle should be enabled here\n\n");
daniele 0:d7f2341ab245 462 }
daniele 0:d7f2341ab245 463 #endif
daniele 0:d7f2341ab245 464
daniele 0:d7f2341ab245 465 if (!s) {
daniele 0:d7f2341ab245 466 pico_err = PICO_ERR_EPROTONOSUPPORT;
daniele 0:d7f2341ab245 467 return NULL;
daniele 0:d7f2341ab245 468 }
daniele 0:d7f2341ab245 469
daniele 0:d7f2341ab245 470 #ifdef PICO_SUPPORT_IPV4
daniele 0:d7f2341ab245 471 if (net == PICO_PROTO_IPV4)
daniele 0:d7f2341ab245 472 s->net = &pico_proto_ipv4;
daniele 0:d7f2341ab245 473 #endif
daniele 0:d7f2341ab245 474
daniele 0:d7f2341ab245 475 #ifdef PICO_SUPPORT_IPV6
daniele 0:d7f2341ab245 476 if (net == PICO_PROTO_IPV6)
daniele 0:d7f2341ab245 477 s->net = &pico_proto_ipv6;
daniele 0:d7f2341ab245 478 #endif
daniele 0:d7f2341ab245 479
daniele 0:d7f2341ab245 480 s->q_in.max_size = PICO_DEFAULT_SOCKETQ;
daniele 0:d7f2341ab245 481 s->q_out.max_size = PICO_DEFAULT_SOCKETQ;
daniele 0:d7f2341ab245 482 s->wakeup = wakeup;
daniele 0:d7f2341ab245 483
daniele 0:d7f2341ab245 484 if (!s->net) {
daniele 0:d7f2341ab245 485 pico_free(s);
daniele 0:d7f2341ab245 486 pico_err = PICO_ERR_ENETUNREACH;
daniele 0:d7f2341ab245 487 return NULL;
daniele 0:d7f2341ab245 488 }
daniele 0:d7f2341ab245 489 return s;
daniele 0:d7f2341ab245 490 }
daniele 0:d7f2341ab245 491
daniele 0:d7f2341ab245 492
daniele 0:d7f2341ab245 493 struct pico_socket *pico_socket_clone(struct pico_socket *facsimile)
daniele 0:d7f2341ab245 494 {
daniele 0:d7f2341ab245 495 struct pico_socket *s = NULL;
daniele 0:d7f2341ab245 496
daniele 0:d7f2341ab245 497 #ifdef PICO_SUPPORT_UDP
daniele 0:d7f2341ab245 498 if (facsimile->proto->proto_number == PICO_PROTO_UDP) {
daniele 0:d7f2341ab245 499 s = pico_udp_open();
daniele 0:d7f2341ab245 500 s->proto = &pico_proto_udp;
daniele 0:d7f2341ab245 501 }
daniele 0:d7f2341ab245 502 #endif
daniele 0:d7f2341ab245 503
daniele 0:d7f2341ab245 504 #ifdef PICO_SUPPORT_TCP
daniele 0:d7f2341ab245 505 if (facsimile->proto->proto_number == PICO_PROTO_TCP) {
daniele 0:d7f2341ab245 506 s = pico_tcp_open();
daniele 0:d7f2341ab245 507 s->proto = &pico_proto_tcp;
daniele 0:d7f2341ab245 508 }
daniele 0:d7f2341ab245 509 #endif
daniele 0:d7f2341ab245 510
daniele 0:d7f2341ab245 511 if (!s) {
daniele 0:d7f2341ab245 512 pico_err = PICO_ERR_EPROTONOSUPPORT;
daniele 0:d7f2341ab245 513 return NULL;
daniele 0:d7f2341ab245 514 }
daniele 0:d7f2341ab245 515 s->local_port = facsimile->local_port;
daniele 0:d7f2341ab245 516 s->remote_port = facsimile->remote_port;
daniele 0:d7f2341ab245 517 s->state = facsimile->state;
daniele 0:d7f2341ab245 518
daniele 0:d7f2341ab245 519 #ifdef PICO_SUPPORT_IPV4
daniele 0:d7f2341ab245 520 if (facsimile->net == &pico_proto_ipv4) {
daniele 0:d7f2341ab245 521 s->net = &pico_proto_ipv4;
daniele 0:d7f2341ab245 522 memcpy(&s->local_addr, &facsimile->local_addr, sizeof(struct pico_ip4));
daniele 0:d7f2341ab245 523 memcpy(&s->remote_addr, &facsimile->remote_addr, sizeof(struct pico_ip4));
daniele 0:d7f2341ab245 524 }
daniele 0:d7f2341ab245 525 #endif
daniele 0:d7f2341ab245 526
daniele 0:d7f2341ab245 527 #ifdef PICO_SUPPORT_IPV6
daniele 0:d7f2341ab245 528 if (net == &pico_proto_ipv6) {
daniele 0:d7f2341ab245 529 s->net = &pico_proto_ipv6;
daniele 0:d7f2341ab245 530 memcpy(&s->local_addr, &facsimile->local_addr, sizeof(struct pico_ip6));
daniele 0:d7f2341ab245 531 memcpy(&s->remote_addr, &facsimile->remote_addr, sizeof(struct pico_ip6));
daniele 0:d7f2341ab245 532 }
daniele 0:d7f2341ab245 533 #endif
daniele 0:d7f2341ab245 534 s->q_in.max_size = PICO_DEFAULT_SOCKETQ;
daniele 0:d7f2341ab245 535 s->q_out.max_size = PICO_DEFAULT_SOCKETQ;
daniele 0:d7f2341ab245 536 s->wakeup = NULL;
daniele 0:d7f2341ab245 537 if (!s->net) {
daniele 0:d7f2341ab245 538 pico_free(s);
daniele 0:d7f2341ab245 539 pico_err = PICO_ERR_ENETUNREACH;
daniele 0:d7f2341ab245 540 return NULL;
daniele 0:d7f2341ab245 541 }
daniele 0:d7f2341ab245 542 return s;
daniele 0:d7f2341ab245 543 }
daniele 0:d7f2341ab245 544
daniele 0:d7f2341ab245 545 int pico_socket_read(struct pico_socket *s, void *buf, int len)
daniele 0:d7f2341ab245 546 {
daniele 0:d7f2341ab245 547 if (!s || buf == NULL) {
daniele 0:d7f2341ab245 548 pico_err = PICO_ERR_EINVAL;
daniele 0:d7f2341ab245 549 return -1;
daniele 0:d7f2341ab245 550 } else {
daniele 0:d7f2341ab245 551 /* check if exists in tree */
daniele 0:d7f2341ab245 552 /* See task #178 */
daniele 0:d7f2341ab245 553 if (pico_check_socket(s) != 0) {
daniele 0:d7f2341ab245 554 pico_err = PICO_ERR_EINVAL;
daniele 0:d7f2341ab245 555 return -1;
daniele 0:d7f2341ab245 556 }
daniele 0:d7f2341ab245 557 }
daniele 0:d7f2341ab245 558
daniele 0:d7f2341ab245 559 if ((s->state & PICO_SOCKET_STATE_BOUND) == 0) {
daniele 0:d7f2341ab245 560 pico_err = PICO_ERR_EIO;
daniele 0:d7f2341ab245 561 return -1;
daniele 0:d7f2341ab245 562 }
daniele 0:d7f2341ab245 563 #ifdef PICO_SUPPORT_UDP
daniele 0:d7f2341ab245 564 if (PROTO(s) == PICO_PROTO_UDP)
daniele 0:d7f2341ab245 565 return pico_udp_recv(s, buf, len, NULL, NULL);
daniele 0:d7f2341ab245 566 #endif
daniele 0:d7f2341ab245 567
daniele 0:d7f2341ab245 568 #ifdef PICO_SUPPORT_TCP
daniele 0:d7f2341ab245 569 if (PROTO(s) == PICO_PROTO_TCP){
daniele 0:d7f2341ab245 570 /* check if in shutdown state and if no more data in tcpq_in */
daniele 0:d7f2341ab245 571 if ((s->state & PICO_SOCKET_STATE_SHUT_REMOTE) && pico_tcp_queue_in_is_empty(s) ) {
daniele 0:d7f2341ab245 572 pico_err = PICO_ERR_ESHUTDOWN;
daniele 0:d7f2341ab245 573 return -1;
daniele 0:d7f2341ab245 574 } else {
daniele 0:d7f2341ab245 575 return pico_tcp_read(s, buf, len);
daniele 0:d7f2341ab245 576 }
daniele 0:d7f2341ab245 577 }
daniele 0:d7f2341ab245 578 #endif
daniele 0:d7f2341ab245 579 return 0;
daniele 0:d7f2341ab245 580 }
daniele 0:d7f2341ab245 581
daniele 0:d7f2341ab245 582 int pico_socket_write(struct pico_socket *s, void *buf, int len)
daniele 0:d7f2341ab245 583 {
daniele 0:d7f2341ab245 584 if (!s || buf == NULL) {
daniele 0:d7f2341ab245 585 pico_err = PICO_ERR_EINVAL;
daniele 0:d7f2341ab245 586 return -1;
daniele 0:d7f2341ab245 587 } else {
daniele 0:d7f2341ab245 588 /* check if exists in tree */
daniele 0:d7f2341ab245 589 /* See task #178 */
daniele 0:d7f2341ab245 590 if (pico_check_socket(s) != 0) {
daniele 0:d7f2341ab245 591 pico_err = PICO_ERR_EINVAL;
daniele 0:d7f2341ab245 592 return -1;
daniele 0:d7f2341ab245 593 }
daniele 0:d7f2341ab245 594 }
daniele 0:d7f2341ab245 595
daniele 0:d7f2341ab245 596 if ((s->state & PICO_SOCKET_STATE_BOUND) == 0) {
daniele 0:d7f2341ab245 597 pico_err = PICO_ERR_EIO;
daniele 0:d7f2341ab245 598 return -1;
daniele 0:d7f2341ab245 599 }
daniele 0:d7f2341ab245 600 if ((s->state & PICO_SOCKET_STATE_CONNECTED) == 0) {
daniele 0:d7f2341ab245 601 pico_err = PICO_ERR_ENOTCONN;
daniele 0:d7f2341ab245 602 return -1;
daniele 0:d7f2341ab245 603 } else if (s->state & PICO_SOCKET_STATE_SHUT_LOCAL) { /* check if in shutdown state */
daniele 0:d7f2341ab245 604 pico_err = PICO_ERR_ESHUTDOWN;
daniele 0:d7f2341ab245 605 return -1;
daniele 0:d7f2341ab245 606 } else {
daniele 0:d7f2341ab245 607 return pico_socket_sendto(s, buf, len, &s->remote_addr, s->remote_port);
daniele 0:d7f2341ab245 608 }
daniele 0:d7f2341ab245 609 }
daniele 0:d7f2341ab245 610
daniele 0:d7f2341ab245 611 uint16_t pico_socket_high_port(uint16_t proto)
daniele 0:d7f2341ab245 612 {
daniele 0:d7f2341ab245 613 uint16_t port;
daniele 0:d7f2341ab245 614 if (0 ||
daniele 0:d7f2341ab245 615 #ifdef PICO_SUPPORT_TCP
daniele 0:d7f2341ab245 616 (proto == PICO_PROTO_TCP) ||
daniele 0:d7f2341ab245 617 #endif
daniele 0:d7f2341ab245 618 #ifdef PICO_SUPPORT_TCP
daniele 0:d7f2341ab245 619 (proto == PICO_PROTO_UDP) ||
daniele 0:d7f2341ab245 620 #endif
daniele 0:d7f2341ab245 621 0) {
daniele 0:d7f2341ab245 622 do {
daniele 0:d7f2341ab245 623 uint32_t rand = pico_rand();
daniele 0:d7f2341ab245 624 port = (uint16_t) (rand & 0xFFFFU);
daniele 0:d7f2341ab245 625 port = (uint16_t)(port % (65535 - 1024)) + 1024U;
daniele 0:d7f2341ab245 626 if (pico_is_port_free(proto, port, NULL, NULL)) {
daniele 0:d7f2341ab245 627 return short_be(port);
daniele 0:d7f2341ab245 628 }
daniele 0:d7f2341ab245 629 } while(1);
daniele 0:d7f2341ab245 630 }
daniele 0:d7f2341ab245 631 else return 0U;
daniele 0:d7f2341ab245 632 }
daniele 0:d7f2341ab245 633
daniele 0:d7f2341ab245 634
daniele 0:d7f2341ab245 635 int pico_socket_sendto(struct pico_socket *s, void *buf, int len, void *dst, uint16_t remote_port)
daniele 0:d7f2341ab245 636 {
daniele 0:d7f2341ab245 637 struct pico_frame *f;
daniele 0:d7f2341ab245 638 struct pico_remote_duple *remote_duple = NULL;
daniele 0:d7f2341ab245 639 int header_offset = 0;
daniele 0:d7f2341ab245 640 int total_payload_written = 0;
daniele 0:d7f2341ab245 641 #ifdef PICO_SUPPORT_IPV4
daniele 0:d7f2341ab245 642 struct pico_ip4 *src4;
daniele 0:d7f2341ab245 643 #endif
daniele 0:d7f2341ab245 644
daniele 0:d7f2341ab245 645 #ifdef PICO_SUPPORT_IPV6
daniele 0:d7f2341ab245 646 struct pico_ip6 *src6;
daniele 0:d7f2341ab245 647 #endif
daniele 0:d7f2341ab245 648 if (len == 0) {
daniele 0:d7f2341ab245 649 return 0;
daniele 0:d7f2341ab245 650 } else if (len < 0) {
daniele 0:d7f2341ab245 651 pico_err = PICO_ERR_EINVAL;
daniele 0:d7f2341ab245 652 return -1;
daniele 0:d7f2341ab245 653 }
daniele 0:d7f2341ab245 654
daniele 0:d7f2341ab245 655 if (buf == NULL || s == NULL) {
daniele 0:d7f2341ab245 656 pico_err = PICO_ERR_EINVAL;
daniele 0:d7f2341ab245 657 return -1;
daniele 0:d7f2341ab245 658 }
daniele 0:d7f2341ab245 659
daniele 0:d7f2341ab245 660 if (!dst || !remote_port) {
daniele 0:d7f2341ab245 661 pico_err = PICO_ERR_EADDRNOTAVAIL;
daniele 0:d7f2341ab245 662 return -1;
daniele 0:d7f2341ab245 663 }
daniele 0:d7f2341ab245 664
daniele 0:d7f2341ab245 665 if ((s->state & PICO_SOCKET_STATE_CONNECTED) != 0) {
daniele 0:d7f2341ab245 666 if (remote_port != s->remote_port) {
daniele 0:d7f2341ab245 667 pico_err = PICO_ERR_EINVAL;
daniele 0:d7f2341ab245 668 return -1;
daniele 0:d7f2341ab245 669 }
daniele 0:d7f2341ab245 670 }
daniele 0:d7f2341ab245 671
daniele 0:d7f2341ab245 672 #ifdef PICO_SUPPORT_IPV4
daniele 0:d7f2341ab245 673 if (IS_SOCK_IPV4(s)) {
daniele 0:d7f2341ab245 674 if ((s->state & PICO_SOCKET_STATE_CONNECTED)) {
daniele 0:d7f2341ab245 675 if (s->remote_addr.ip4.addr != ((struct pico_ip4 *)dst)->addr ) {
daniele 0:d7f2341ab245 676 pico_err = PICO_ERR_EADDRNOTAVAIL;
daniele 0:d7f2341ab245 677 return -1;
daniele 0:d7f2341ab245 678 }
daniele 0:d7f2341ab245 679 } else {
daniele 0:d7f2341ab245 680 src4 = pico_ipv4_source_find(dst);
daniele 0:d7f2341ab245 681 if (!src4) {
daniele 0:d7f2341ab245 682 pico_err = PICO_ERR_EHOSTUNREACH;
daniele 0:d7f2341ab245 683 return -1;
daniele 0:d7f2341ab245 684 }
daniele 0:d7f2341ab245 685 if (src4->addr != PICO_IPV4_INADDR_ANY)
daniele 0:d7f2341ab245 686 s->local_addr.ip4.addr = src4->addr;
daniele 0:d7f2341ab245 687 # ifdef PICO_SUPPORT_UDP
daniele 0:d7f2341ab245 688 /* socket remote info could change in a consecutive call, make persistent */
daniele 0:d7f2341ab245 689 if (PROTO(s) == PICO_PROTO_UDP) {
daniele 0:d7f2341ab245 690 remote_duple = pico_zalloc(sizeof(struct pico_remote_duple));
daniele 0:d7f2341ab245 691 remote_duple->remote_addr.ip4.addr = ((struct pico_ip4 *)dst)->addr;
daniele 0:d7f2341ab245 692 remote_duple->remote_port = remote_port;
daniele 0:d7f2341ab245 693 }
daniele 0:d7f2341ab245 694 # endif
daniele 0:d7f2341ab245 695 }
daniele 0:d7f2341ab245 696 }
daniele 0:d7f2341ab245 697 #endif
daniele 0:d7f2341ab245 698
daniele 0:d7f2341ab245 699 #ifdef PICO_SUPPORT_IPV6
daniele 0:d7f2341ab245 700 if (IS_SOCK_IPV6(s)) {
daniele 0:d7f2341ab245 701 if (s->state & PICO_SOCKET_STATE_CONNECTED) {
daniele 0:d7f2341ab245 702 if (memcmp(&s->remote_addr, dst, PICO_SIZE_IP6))
daniele 0:d7f2341ab245 703 return -1;
daniele 0:d7f2341ab245 704 } else {
daniele 0:d7f2341ab245 705 src6 = pico_ipv6_source_find(dst);
daniele 0:d7f2341ab245 706 if (!src6) {
daniele 0:d7f2341ab245 707 pico_err = PICO_ERR_EHOSTUNREACH;
daniele 0:d7f2341ab245 708 return -1;
daniele 0:d7f2341ab245 709 }
daniele 0:d7f2341ab245 710 memcpy(&s->local_addr, src6, PICO_SIZE_IP6);
daniele 0:d7f2341ab245 711 memcpy(&s->remote_addr, dst, PICO_SIZE_IP6);
daniele 0:d7f2341ab245 712 # ifdef PICO_SUPPORT_UDP
daniele 0:d7f2341ab245 713 if (PROTO(s) == PICO_PROTO_UDP) {
daniele 0:d7f2341ab245 714 remote_duple = pico_zalloc(sizeof(struct pico_remote_duple));
daniele 0:d7f2341ab245 715 remote_duple->remote_addr.ip6.addr = ((struct pico_ip6 *)dst)->addr;
daniele 0:d7f2341ab245 716 remote_duple->remote_port = remote_port;
daniele 0:d7f2341ab245 717 }
daniele 0:d7f2341ab245 718 # endif
daniele 0:d7f2341ab245 719 }
daniele 0:d7f2341ab245 720 }
daniele 0:d7f2341ab245 721 #endif
daniele 0:d7f2341ab245 722
daniele 0:d7f2341ab245 723 if ((s->state & PICO_SOCKET_STATE_BOUND) == 0) {
daniele 0:d7f2341ab245 724 s->local_port = pico_socket_high_port(s->proto->proto_number);
daniele 0:d7f2341ab245 725 if (s->local_port == 0) {
daniele 0:d7f2341ab245 726 pico_err = PICO_ERR_EINVAL;
daniele 0:d7f2341ab245 727 return -1;
daniele 0:d7f2341ab245 728 }
daniele 0:d7f2341ab245 729 }
daniele 0:d7f2341ab245 730 if ((s->state & PICO_SOCKET_STATE_CONNECTED) == 0) {
daniele 0:d7f2341ab245 731 s->remote_port = remote_port;
daniele 0:d7f2341ab245 732 }
daniele 0:d7f2341ab245 733
daniele 0:d7f2341ab245 734 #ifdef PICO_SUPPORT_TCP
daniele 0:d7f2341ab245 735 if (PROTO(s) == PICO_PROTO_TCP)
daniele 0:d7f2341ab245 736 header_offset = pico_tcp_overhead(s);
daniele 0:d7f2341ab245 737 #endif
daniele 0:d7f2341ab245 738
daniele 0:d7f2341ab245 739 #ifdef PICO_SUPPORT_UDP
daniele 0:d7f2341ab245 740 if (PROTO(s) == PICO_PROTO_UDP)
daniele 0:d7f2341ab245 741 header_offset = sizeof(struct pico_udp_hdr);
daniele 0:d7f2341ab245 742 #endif
daniele 0:d7f2341ab245 743
daniele 0:d7f2341ab245 744 while (total_payload_written < len) {
daniele 0:d7f2341ab245 745 int transport_len = (len - total_payload_written) + header_offset;
daniele 0:d7f2341ab245 746 if (transport_len > PICO_SOCKET_MTU)
daniele 0:d7f2341ab245 747 transport_len = PICO_SOCKET_MTU;
daniele 0:d7f2341ab245 748 #ifdef PICO_SUPPORT_IPFRAG
daniele 0:d7f2341ab245 749 else {
daniele 0:d7f2341ab245 750 if (total_payload_written)
daniele 0:d7f2341ab245 751 transport_len -= header_offset; /* last fragment, do not allocate memory for transport header */
daniele 0:d7f2341ab245 752 }
daniele 0:d7f2341ab245 753 #endif /* PICO_SUPPORT_IPFRAG */
daniele 0:d7f2341ab245 754
daniele 0:d7f2341ab245 755 f = pico_socket_frame_alloc(s, transport_len);
daniele 0:d7f2341ab245 756 if (!f) {
daniele 0:d7f2341ab245 757 pico_err = PICO_ERR_ENOMEM;
daniele 0:d7f2341ab245 758 return -1;
daniele 0:d7f2341ab245 759 }
daniele 0:d7f2341ab245 760 f->payload += header_offset;
daniele 0:d7f2341ab245 761 f->payload_len -= header_offset;
daniele 0:d7f2341ab245 762 f->sock = s;
daniele 0:d7f2341ab245 763 if (remote_duple) {
daniele 0:d7f2341ab245 764 f->info = pico_zalloc(sizeof(struct pico_remote_duple));
daniele 0:d7f2341ab245 765 memcpy(f->info, remote_duple, sizeof(struct pico_remote_duple));
daniele 0:d7f2341ab245 766 }
daniele 0:d7f2341ab245 767
daniele 0:d7f2341ab245 768 #ifdef PICO_SUPPORT_IPFRAG
daniele 0:d7f2341ab245 769 # ifdef PICO_SUPPORT_UDP
daniele 0:d7f2341ab245 770 if (PROTO(s) == PICO_PROTO_UDP && ((len + header_offset) > PICO_SOCKET_MTU)) {
daniele 0:d7f2341ab245 771 /* hacking way to identify fragmentation frames: payload != transport_hdr -> first frame */
daniele 0:d7f2341ab245 772 if (!total_payload_written) {
daniele 0:d7f2341ab245 773 frag_dbg("FRAG: first fragmented frame %p | len = %u offset = 0\n", f, f->payload_len);
daniele 0:d7f2341ab245 774 /* transport header length field contains total length + header length */
daniele 0:d7f2341ab245 775 f->transport_len = len + header_offset;
daniele 0:d7f2341ab245 776 f->frag = short_be(PICO_IPV4_MOREFRAG);
daniele 0:d7f2341ab245 777 } else {
daniele 0:d7f2341ab245 778 /* no transport header in fragmented IP */
daniele 0:d7f2341ab245 779 f->payload = f->transport_hdr;
daniele 0:d7f2341ab245 780 f->payload_len += header_offset;
daniele 0:d7f2341ab245 781 /* set offset in octets */
daniele 0:d7f2341ab245 782 f->frag = short_be((total_payload_written + header_offset) / 8);
daniele 0:d7f2341ab245 783 if (total_payload_written + f->payload_len < len) {
daniele 0:d7f2341ab245 784 frag_dbg("FRAG: intermediate fragmented frame %p | len = %u offset = %u\n", f, f->payload_len, short_be(f->frag));
daniele 0:d7f2341ab245 785 f->frag |= short_be(PICO_IPV4_MOREFRAG);
daniele 0:d7f2341ab245 786 } else {
daniele 0:d7f2341ab245 787 frag_dbg("FRAG: last fragmented frame %p | len = %u offset = %u\n", f, f->payload_len, short_be(f->frag));
daniele 0:d7f2341ab245 788 f->frag &= short_be(PICO_IPV4_FRAG_MASK);
daniele 0:d7f2341ab245 789 }
daniele 0:d7f2341ab245 790 }
daniele 0:d7f2341ab245 791 } else {
daniele 0:d7f2341ab245 792 f->frag = short_be(PICO_IPV4_DONTFRAG);
daniele 0:d7f2341ab245 793 }
daniele 0:d7f2341ab245 794 # endif /* PICO_SUPPORT_UDP */
daniele 0:d7f2341ab245 795 #endif /* PICO_SUPPORT_IPFRAG */
daniele 0:d7f2341ab245 796
daniele 0:d7f2341ab245 797 if (f->payload_len <= 0) {
daniele 0:d7f2341ab245 798 pico_frame_discard(f);
daniele 0:d7f2341ab245 799 pico_free(remote_duple);
daniele 0:d7f2341ab245 800 return total_payload_written;
daniele 0:d7f2341ab245 801 }
daniele 0:d7f2341ab245 802
daniele 0:d7f2341ab245 803 memcpy(f->payload, buf + total_payload_written, f->payload_len);
daniele 0:d7f2341ab245 804 //dbg("Pushing segment, hdr len: %d, payload_len: %d\n", header_offset, f->payload_len);
daniele 0:d7f2341ab245 805
daniele 0:d7f2341ab245 806 if (s->proto->push(s->proto, f) > 0) {
daniele 0:d7f2341ab245 807 total_payload_written += f->payload_len;
daniele 0:d7f2341ab245 808 } else {
daniele 0:d7f2341ab245 809 pico_frame_discard(f);
daniele 0:d7f2341ab245 810 pico_err = PICO_ERR_EAGAIN;
daniele 0:d7f2341ab245 811 break;
daniele 0:d7f2341ab245 812 }
daniele 0:d7f2341ab245 813 }
daniele 0:d7f2341ab245 814 pico_free(remote_duple);
daniele 0:d7f2341ab245 815 return total_payload_written;
daniele 0:d7f2341ab245 816 }
daniele 0:d7f2341ab245 817
daniele 0:d7f2341ab245 818 int pico_socket_send(struct pico_socket *s, void *buf, int len)
daniele 0:d7f2341ab245 819 {
daniele 0:d7f2341ab245 820 if (!s || buf == NULL) {
daniele 0:d7f2341ab245 821 pico_err = PICO_ERR_EINVAL;
daniele 0:d7f2341ab245 822 return -1;
daniele 0:d7f2341ab245 823 } else {
daniele 0:d7f2341ab245 824 /* check if exists in tree */
daniele 0:d7f2341ab245 825 /* See task #178 */
daniele 0:d7f2341ab245 826 if (pico_check_socket(s) != 0) {
daniele 0:d7f2341ab245 827 pico_err = PICO_ERR_EINVAL;
daniele 0:d7f2341ab245 828 return -1;
daniele 0:d7f2341ab245 829 }
daniele 0:d7f2341ab245 830 }
daniele 0:d7f2341ab245 831
daniele 0:d7f2341ab245 832 if ((s->state & PICO_SOCKET_STATE_CONNECTED) == 0) {
daniele 0:d7f2341ab245 833 pico_err = PICO_ERR_ENOTCONN;
daniele 0:d7f2341ab245 834 return -1;
daniele 0:d7f2341ab245 835 }
daniele 0:d7f2341ab245 836 return pico_socket_sendto(s, buf, len, &s->remote_addr, s->remote_port);
daniele 0:d7f2341ab245 837 }
daniele 0:d7f2341ab245 838
daniele 0:d7f2341ab245 839 int pico_socket_recvfrom(struct pico_socket *s, void *buf, int len, void *orig, uint16_t *remote_port)
daniele 0:d7f2341ab245 840 {
daniele 0:d7f2341ab245 841 if (!s || buf == NULL) { /// || orig == NULL || remote_port == NULL) {
daniele 0:d7f2341ab245 842 pico_err = PICO_ERR_EINVAL;
daniele 0:d7f2341ab245 843 return -1;
daniele 0:d7f2341ab245 844 } else {
daniele 0:d7f2341ab245 845 /* check if exists in tree */
daniele 0:d7f2341ab245 846 if (pico_check_socket(s) != 0) {
daniele 0:d7f2341ab245 847 pico_err = PICO_ERR_EINVAL;
daniele 0:d7f2341ab245 848 /* See task #178 */
daniele 0:d7f2341ab245 849 return -1;
daniele 0:d7f2341ab245 850 }
daniele 0:d7f2341ab245 851 }
daniele 0:d7f2341ab245 852
daniele 0:d7f2341ab245 853 if ((s->state & PICO_SOCKET_STATE_BOUND) == 0) {
daniele 0:d7f2341ab245 854 pico_err = PICO_ERR_EADDRNOTAVAIL;
daniele 0:d7f2341ab245 855 return -1;
daniele 0:d7f2341ab245 856 }
daniele 0:d7f2341ab245 857 #ifdef PICO_SUPPORT_UDP
daniele 0:d7f2341ab245 858 if (PROTO(s) == PICO_PROTO_UDP) {
daniele 0:d7f2341ab245 859 return pico_udp_recv(s, buf, len, orig, remote_port);
daniele 0:d7f2341ab245 860 }
daniele 0:d7f2341ab245 861 #endif
daniele 0:d7f2341ab245 862 #ifdef PICO_SUPPORT_TCP
daniele 0:d7f2341ab245 863 if (PROTO(s) == PICO_PROTO_TCP) {
daniele 0:d7f2341ab245 864 /* check if in shutdown state and if tcpq_in empty */
daniele 0:d7f2341ab245 865 if ((s->state & PICO_SOCKET_STATE_SHUT_REMOTE) && pico_tcp_queue_in_is_empty(s)) {
daniele 0:d7f2341ab245 866 pico_err = PICO_ERR_ESHUTDOWN;
daniele 0:d7f2341ab245 867 return -1;
daniele 0:d7f2341ab245 868 } else {
daniele 0:d7f2341ab245 869 //dbg("socket tcp recv\n");
daniele 0:d7f2341ab245 870 return pico_tcp_read(s, buf, len);
daniele 0:d7f2341ab245 871 }
daniele 0:d7f2341ab245 872 }
daniele 0:d7f2341ab245 873 #endif
daniele 0:d7f2341ab245 874 //dbg("socket return 0\n");
daniele 0:d7f2341ab245 875 return 0;
daniele 0:d7f2341ab245 876 }
daniele 0:d7f2341ab245 877
daniele 0:d7f2341ab245 878 int pico_socket_recv(struct pico_socket *s, void *buf, int len)
daniele 0:d7f2341ab245 879 {
daniele 0:d7f2341ab245 880 return pico_socket_recvfrom(s, buf, len, NULL, NULL);
daniele 0:d7f2341ab245 881 }
daniele 0:d7f2341ab245 882
daniele 0:d7f2341ab245 883
daniele 0:d7f2341ab245 884 int pico_socket_bind(struct pico_socket *s, void *local_addr, uint16_t *port)
daniele 0:d7f2341ab245 885 {
daniele 0:d7f2341ab245 886 if (!s || !local_addr || !port) {
daniele 0:d7f2341ab245 887 pico_err = PICO_ERR_EINVAL;
daniele 0:d7f2341ab245 888 return -1;
daniele 0:d7f2341ab245 889 }
daniele 0:d7f2341ab245 890
daniele 0:d7f2341ab245 891 if (!is_sock_ipv6(s)) {
daniele 0:d7f2341ab245 892 struct pico_ip4 *ip = (struct pico_ip4 *)local_addr;
daniele 0:d7f2341ab245 893 if (ip->addr != PICO_IPV4_INADDR_ANY) {
daniele 0:d7f2341ab245 894 if (!pico_ipv4_link_find(local_addr)) {
daniele 0:d7f2341ab245 895 pico_err = PICO_ERR_EINVAL;
daniele 0:d7f2341ab245 896 return -1;
daniele 0:d7f2341ab245 897 }
daniele 0:d7f2341ab245 898 }
daniele 0:d7f2341ab245 899 } else {
daniele 0:d7f2341ab245 900 /*... IPv6 */
daniele 0:d7f2341ab245 901 }
daniele 0:d7f2341ab245 902
daniele 0:d7f2341ab245 903
daniele 0:d7f2341ab245 904 /* When given port = 0, get a random high port to bind to. */
daniele 0:d7f2341ab245 905 if (*port == 0) {
daniele 0:d7f2341ab245 906 *port = pico_socket_high_port(PROTO(s));
daniele 0:d7f2341ab245 907 if (*port == 0) {
daniele 0:d7f2341ab245 908 pico_err = PICO_ERR_EINVAL;
daniele 0:d7f2341ab245 909 return -1;
daniele 0:d7f2341ab245 910 }
daniele 0:d7f2341ab245 911 }
daniele 0:d7f2341ab245 912
daniele 0:d7f2341ab245 913 if (pico_is_port_free(PROTO(s), *port, local_addr, s->net) == 0) {
daniele 0:d7f2341ab245 914 pico_err = PICO_ERR_EADDRINUSE;
daniele 0:d7f2341ab245 915 return -1;
daniele 0:d7f2341ab245 916 }
daniele 0:d7f2341ab245 917 s->local_port = *port;
daniele 0:d7f2341ab245 918
daniele 0:d7f2341ab245 919 if (is_sock_ipv6(s)) {
daniele 0:d7f2341ab245 920 struct pico_ip6 *ip = (struct pico_ip6 *) local_addr;
daniele 0:d7f2341ab245 921 memcpy(s->local_addr.ip6.addr, ip, PICO_SIZE_IP6);
daniele 0:d7f2341ab245 922 /* XXX: port ipv4 functionality to ipv6 */
daniele 0:d7f2341ab245 923 /* Check for port already in use */
daniele 0:d7f2341ab245 924 if (pico_is_port_free(PROTO(s), *port, &local_addr, s->net)) {
daniele 0:d7f2341ab245 925 pico_err = PICO_ERR_EADDRINUSE;
daniele 0:d7f2341ab245 926 return -1;
daniele 0:d7f2341ab245 927 }
daniele 0:d7f2341ab245 928 } else if (is_sock_ipv4(s)) {
daniele 0:d7f2341ab245 929 struct pico_ip4 *ip = (struct pico_ip4 *) local_addr;
daniele 0:d7f2341ab245 930 s->local_addr.ip4.addr = ip->addr;
daniele 0:d7f2341ab245 931 }
daniele 0:d7f2341ab245 932 return pico_socket_alter_state(s, PICO_SOCKET_STATE_BOUND, 0, 0);
daniele 0:d7f2341ab245 933 }
daniele 0:d7f2341ab245 934
daniele 0:d7f2341ab245 935 int pico_socket_connect(struct pico_socket *s, void *remote_addr, uint16_t remote_port)
daniele 0:d7f2341ab245 936 {
daniele 0:d7f2341ab245 937 int ret = -1;
daniele 0:d7f2341ab245 938 pico_err = PICO_ERR_EPROTONOSUPPORT;
daniele 0:d7f2341ab245 939 if (!s || remote_addr == NULL || remote_port == 0) {
daniele 0:d7f2341ab245 940 pico_err = PICO_ERR_EINVAL;
daniele 0:d7f2341ab245 941 return -1;
daniele 0:d7f2341ab245 942 }
daniele 0:d7f2341ab245 943
daniele 0:d7f2341ab245 944 s->remote_port = remote_port;
daniele 0:d7f2341ab245 945
daniele 0:d7f2341ab245 946 if (s->local_port == 0) {
daniele 0:d7f2341ab245 947 s->local_port = pico_socket_high_port(PROTO(s));
daniele 0:d7f2341ab245 948 if (!s->local_port) {
daniele 0:d7f2341ab245 949 pico_err = PICO_ERR_EINVAL;
daniele 0:d7f2341ab245 950 return -1;
daniele 0:d7f2341ab245 951 }
daniele 0:d7f2341ab245 952 }
daniele 0:d7f2341ab245 953
daniele 0:d7f2341ab245 954 if (is_sock_ipv6(s)) {
daniele 0:d7f2341ab245 955 struct pico_ip6 *ip = (struct pico_ip6 *) remote_addr;
daniele 0:d7f2341ab245 956 memcpy(s->remote_addr.ip6.addr, ip, PICO_SIZE_IP6);
daniele 0:d7f2341ab245 957 } else if (is_sock_ipv4(s)) {
daniele 0:d7f2341ab245 958 struct pico_ip4 *local, *ip = (struct pico_ip4 *) remote_addr;
daniele 0:d7f2341ab245 959 s->remote_addr.ip4.addr = ip->addr;
daniele 0:d7f2341ab245 960 local = pico_ipv4_source_find(ip);
daniele 0:d7f2341ab245 961 if (local) {
daniele 0:d7f2341ab245 962 s->local_addr.ip4.addr = local->addr;
daniele 0:d7f2341ab245 963 } else {
daniele 0:d7f2341ab245 964 pico_err = PICO_ERR_EHOSTUNREACH;
daniele 0:d7f2341ab245 965 return -1;
daniele 0:d7f2341ab245 966 }
daniele 0:d7f2341ab245 967 }
daniele 0:d7f2341ab245 968
daniele 0:d7f2341ab245 969 pico_socket_alter_state(s, PICO_SOCKET_STATE_BOUND, 0, 0);
daniele 0:d7f2341ab245 970
daniele 0:d7f2341ab245 971 #ifdef PICO_SUPPORT_UDP
daniele 0:d7f2341ab245 972 if (PROTO(s) == PICO_PROTO_UDP) {
daniele 0:d7f2341ab245 973 pico_socket_alter_state(s, PICO_SOCKET_STATE_CONNECTED, 0, 0);
daniele 0:d7f2341ab245 974 pico_err = PICO_ERR_NOERR;
daniele 0:d7f2341ab245 975 ret = 0;
daniele 0:d7f2341ab245 976 }
daniele 0:d7f2341ab245 977 #endif
daniele 0:d7f2341ab245 978
daniele 0:d7f2341ab245 979 #ifdef PICO_SUPPORT_TCP
daniele 0:d7f2341ab245 980 if (PROTO(s) == PICO_PROTO_TCP) {
daniele 0:d7f2341ab245 981 if (pico_tcp_initconn(s) == 0) {
daniele 0:d7f2341ab245 982 pico_socket_alter_state(s, PICO_SOCKET_STATE_CONNECTED | PICO_SOCKET_STATE_TCP_SYN_SENT, 0, 0);
daniele 0:d7f2341ab245 983 pico_err = PICO_ERR_NOERR;
daniele 0:d7f2341ab245 984 ret = 0;
daniele 0:d7f2341ab245 985 } else {
daniele 0:d7f2341ab245 986 pico_err = PICO_ERR_EHOSTUNREACH;
daniele 0:d7f2341ab245 987 }
daniele 0:d7f2341ab245 988 }
daniele 0:d7f2341ab245 989 #endif
daniele 0:d7f2341ab245 990
daniele 0:d7f2341ab245 991 return ret;
daniele 0:d7f2341ab245 992 }
daniele 0:d7f2341ab245 993
daniele 0:d7f2341ab245 994 #ifdef PICO_SUPPORT_TCP
daniele 0:d7f2341ab245 995
daniele 0:d7f2341ab245 996 int pico_socket_listen(struct pico_socket *s, int backlog)
daniele 0:d7f2341ab245 997 {
daniele 0:d7f2341ab245 998 if (!s || backlog < 1) {
daniele 0:d7f2341ab245 999 pico_err = PICO_ERR_EINVAL;
daniele 0:d7f2341ab245 1000 return -1;
daniele 0:d7f2341ab245 1001 } else {
daniele 0:d7f2341ab245 1002 /* check if exists in tree */
daniele 0:d7f2341ab245 1003 /* See task #178 */
daniele 0:d7f2341ab245 1004 if (pico_check_socket(s) != 0) {
daniele 0:d7f2341ab245 1005 pico_err = PICO_ERR_EINVAL;
daniele 0:d7f2341ab245 1006 return -1;
daniele 0:d7f2341ab245 1007 }
daniele 0:d7f2341ab245 1008 }
daniele 0:d7f2341ab245 1009
daniele 0:d7f2341ab245 1010 if (PROTO(s) == PICO_PROTO_UDP) {
daniele 0:d7f2341ab245 1011 pico_err = PICO_ERR_EINVAL;
daniele 0:d7f2341ab245 1012 return -1;
daniele 0:d7f2341ab245 1013 }
daniele 0:d7f2341ab245 1014
daniele 0:d7f2341ab245 1015 if ((s->state & PICO_SOCKET_STATE_BOUND) == 0) {
daniele 0:d7f2341ab245 1016 pico_err = PICO_ERR_EISCONN;
daniele 0:d7f2341ab245 1017 return -1;
daniele 0:d7f2341ab245 1018 }
daniele 0:d7f2341ab245 1019
daniele 0:d7f2341ab245 1020 if (backlog < 1) {
daniele 0:d7f2341ab245 1021 pico_err = PICO_ERR_EINVAL;
daniele 0:d7f2341ab245 1022 return -1;
daniele 0:d7f2341ab245 1023 }
daniele 0:d7f2341ab245 1024
daniele 0:d7f2341ab245 1025 if (PROTO(s) == PICO_PROTO_TCP)
daniele 0:d7f2341ab245 1026 pico_socket_alter_state(s, PICO_SOCKET_STATE_TCP_SYN_SENT, 0, PICO_SOCKET_STATE_TCP_LISTEN);
daniele 0:d7f2341ab245 1027 s->max_backlog = backlog;
daniele 0:d7f2341ab245 1028
daniele 0:d7f2341ab245 1029 return 0;
daniele 0:d7f2341ab245 1030 }
daniele 0:d7f2341ab245 1031
daniele 0:d7f2341ab245 1032 struct pico_socket *pico_socket_accept(struct pico_socket *s, void *orig, uint16_t *port)
daniele 0:d7f2341ab245 1033 {
daniele 0:d7f2341ab245 1034 if (!s || !orig || !port) {
daniele 0:d7f2341ab245 1035 pico_err = PICO_ERR_EINVAL;
daniele 0:d7f2341ab245 1036 return NULL;
daniele 0:d7f2341ab245 1037 }
daniele 0:d7f2341ab245 1038
daniele 0:d7f2341ab245 1039 pico_err = PICO_ERR_EINVAL;
daniele 0:d7f2341ab245 1040
daniele 0:d7f2341ab245 1041 if ((s->state & PICO_SOCKET_STATE_BOUND) == 0) {
daniele 0:d7f2341ab245 1042 return NULL;
daniele 0:d7f2341ab245 1043 }
daniele 0:d7f2341ab245 1044
daniele 0:d7f2341ab245 1045 if (PROTO(s) == PICO_PROTO_UDP) {
daniele 0:d7f2341ab245 1046 return NULL;
daniele 0:d7f2341ab245 1047 }
daniele 0:d7f2341ab245 1048
daniele 0:d7f2341ab245 1049 if (TCPSTATE(s) == PICO_SOCKET_STATE_TCP_LISTEN) {
daniele 0:d7f2341ab245 1050 struct pico_sockport *sp = pico_get_sockport(PICO_PROTO_TCP, s->local_port);
daniele 0:d7f2341ab245 1051 struct pico_socket *found;
daniele 0:d7f2341ab245 1052 /* If at this point no incoming connection socket is found,
daniele 0:d7f2341ab245 1053 * the accept call is valid, but no connection is established yet.
daniele 0:d7f2341ab245 1054 */
daniele 0:d7f2341ab245 1055 pico_err = PICO_ERR_EAGAIN;
daniele 0:d7f2341ab245 1056 if (sp) {
daniele 0:d7f2341ab245 1057 struct pico_tree_node * index;
daniele 0:d7f2341ab245 1058 //RB_FOREACH(found, socket_tree, &sp->socks) {
daniele 0:d7f2341ab245 1059 pico_tree_foreach(index,&sp->socks){
daniele 0:d7f2341ab245 1060 found = index->keyValue;
daniele 0:d7f2341ab245 1061 if (s == found->parent) {
daniele 0:d7f2341ab245 1062 found->parent = NULL;
daniele 0:d7f2341ab245 1063 pico_err = PICO_ERR_NOERR;
daniele 0:d7f2341ab245 1064 memcpy(orig, &found->remote_addr, sizeof(struct pico_ip4));
daniele 0:d7f2341ab245 1065 *port = found->remote_port;
daniele 0:d7f2341ab245 1066 return found;
daniele 0:d7f2341ab245 1067 }
daniele 0:d7f2341ab245 1068 }
daniele 0:d7f2341ab245 1069 }
daniele 0:d7f2341ab245 1070 }
daniele 0:d7f2341ab245 1071 return NULL;
daniele 0:d7f2341ab245 1072 }
daniele 0:d7f2341ab245 1073
daniele 0:d7f2341ab245 1074 #else
daniele 0:d7f2341ab245 1075
daniele 0:d7f2341ab245 1076 int pico_socket_listen(struct pico_socket *s, int backlog)
daniele 0:d7f2341ab245 1077 {
daniele 0:d7f2341ab245 1078 pico_err = PICO_ERR_EINVAL;
daniele 0:d7f2341ab245 1079 return -1;
daniele 0:d7f2341ab245 1080 }
daniele 0:d7f2341ab245 1081
daniele 0:d7f2341ab245 1082 struct pico_socket *pico_socket_accept(struct pico_socket *s, void *orig, uint16_t *local_port)
daniele 0:d7f2341ab245 1083 {
daniele 0:d7f2341ab245 1084 pico_err = PICO_ERR_EINVAL;
daniele 0:d7f2341ab245 1085 return NULL;
daniele 0:d7f2341ab245 1086 }
daniele 0:d7f2341ab245 1087
daniele 0:d7f2341ab245 1088 #endif
daniele 0:d7f2341ab245 1089
daniele 0:d7f2341ab245 1090 #define PICO_SOCKET_SETOPT_EN(socket,index) (socket->opt_flags |= (1 << index))
daniele 0:d7f2341ab245 1091 #define PICO_SOCKET_SETOPT_DIS(socket,index) (socket->opt_flags &= ~(1 << index))
daniele 0:d7f2341ab245 1092
daniele 0:d7f2341ab245 1093 int pico_socket_setoption(struct pico_socket *s, int option, void *value) // XXX no check against proto (vs setsockopt) or implicit by socket?
daniele 0:d7f2341ab245 1094 {
daniele 0:d7f2341ab245 1095 if (s == NULL) {
daniele 0:d7f2341ab245 1096 pico_err = PICO_ERR_EINVAL;
daniele 0:d7f2341ab245 1097 return -1;
daniele 0:d7f2341ab245 1098 }
daniele 0:d7f2341ab245 1099
daniele 0:d7f2341ab245 1100 pico_err = PICO_ERR_NOERR;
daniele 0:d7f2341ab245 1101
daniele 0:d7f2341ab245 1102 switch (option)
daniele 0:d7f2341ab245 1103 {
daniele 0:d7f2341ab245 1104 #ifdef PICO_SUPPORT_TCP
daniele 0:d7f2341ab245 1105 case PICO_TCP_NODELAY:
daniele 0:d7f2341ab245 1106 if (s->proto->proto_number == PICO_PROTO_TCP) {
daniele 0:d7f2341ab245 1107 /* disable Nagle's algorithm */
daniele 0:d7f2341ab245 1108 PICO_SOCKET_SETOPT_DIS(s,PICO_SOCKET_OPT_TCPNODELAY);
daniele 0:d7f2341ab245 1109 } else {
daniele 0:d7f2341ab245 1110 pico_err = PICO_ERR_EINVAL;
daniele 0:d7f2341ab245 1111 }
daniele 0:d7f2341ab245 1112 break;
daniele 0:d7f2341ab245 1113 #endif
daniele 0:d7f2341ab245 1114
daniele 0:d7f2341ab245 1115
daniele 0:d7f2341ab245 1116 #ifdef PICO_SUPPORT_MCAST
daniele 0:d7f2341ab245 1117 case PICO_IP_MULTICAST_IF:
daniele 0:d7f2341ab245 1118 pico_err = PICO_ERR_EOPNOTSUPP;
daniele 0:d7f2341ab245 1119 return -1;
daniele 0:d7f2341ab245 1120 break;
daniele 0:d7f2341ab245 1121
daniele 0:d7f2341ab245 1122 case PICO_IP_MULTICAST_TTL:
daniele 0:d7f2341ab245 1123 if (s->proto->proto_number == PICO_PROTO_UDP) {
daniele 0:d7f2341ab245 1124 return pico_udp_set_mc_ttl(s, *((uint8_t *) value));
daniele 0:d7f2341ab245 1125 }
daniele 0:d7f2341ab245 1126 break;
daniele 0:d7f2341ab245 1127
daniele 0:d7f2341ab245 1128 case PICO_IP_MULTICAST_LOOP:
daniele 0:d7f2341ab245 1129 if (s->proto->proto_number == PICO_PROTO_UDP) {
daniele 0:d7f2341ab245 1130 switch (*(uint8_t *) value)
daniele 0:d7f2341ab245 1131 {
daniele 0:d7f2341ab245 1132 case 0:
daniele 0:d7f2341ab245 1133 /* do not loop back multicast datagram */
daniele 0:d7f2341ab245 1134 PICO_SOCKET_SETOPT_DIS(s,PICO_SOCKET_OPT_MULTICAST_LOOP);
daniele 0:d7f2341ab245 1135 break;
daniele 0:d7f2341ab245 1136
daniele 0:d7f2341ab245 1137 case 1:
daniele 0:d7f2341ab245 1138 /* do loop back multicast datagram */
daniele 0:d7f2341ab245 1139 PICO_SOCKET_SETOPT_EN(s,PICO_SOCKET_OPT_MULTICAST_LOOP);
daniele 0:d7f2341ab245 1140 break;
daniele 0:d7f2341ab245 1141
daniele 0:d7f2341ab245 1142 default:
daniele 0:d7f2341ab245 1143 pico_err = PICO_ERR_EINVAL;
daniele 0:d7f2341ab245 1144 return -1;
daniele 0:d7f2341ab245 1145 }
daniele 0:d7f2341ab245 1146 }
daniele 0:d7f2341ab245 1147 break;
daniele 0:d7f2341ab245 1148
daniele 0:d7f2341ab245 1149 case PICO_IP_ADD_MEMBERSHIP:
daniele 0:d7f2341ab245 1150 if (s->proto->proto_number == PICO_PROTO_UDP) {
daniele 0:d7f2341ab245 1151 struct pico_ip_mreq *mreq = (struct pico_ip_mreq *) value;
daniele 0:d7f2341ab245 1152 struct pico_ipv4_link *mcast_link;
daniele 0:d7f2341ab245 1153 if (!mreq->mcast_link_addr.addr) {
daniele 0:d7f2341ab245 1154 mcast_link = NULL; /* use default multicast link */
daniele 0:d7f2341ab245 1155 } else {
daniele 0:d7f2341ab245 1156 mcast_link = pico_ipv4_link_get(&mreq->mcast_link_addr);
daniele 0:d7f2341ab245 1157 if (!mcast_link) {
daniele 0:d7f2341ab245 1158 pico_err = PICO_ERR_EINVAL;
daniele 0:d7f2341ab245 1159 return -1;
daniele 0:d7f2341ab245 1160 }
daniele 0:d7f2341ab245 1161 }
daniele 0:d7f2341ab245 1162 return pico_ipv4_mcast_join_group(&mreq->mcast_group_addr, mcast_link);
daniele 0:d7f2341ab245 1163 }
daniele 0:d7f2341ab245 1164 break;
daniele 0:d7f2341ab245 1165
daniele 0:d7f2341ab245 1166 case PICO_IP_DROP_MEMBERSHIP:
daniele 0:d7f2341ab245 1167 if (s->proto->proto_number == PICO_PROTO_UDP) {
daniele 0:d7f2341ab245 1168 struct pico_ip_mreq *mreq = (struct pico_ip_mreq *) value;
daniele 0:d7f2341ab245 1169 struct pico_ipv4_link *mcast_link;
daniele 0:d7f2341ab245 1170 if (!mreq->mcast_link_addr.addr) {
daniele 0:d7f2341ab245 1171 mcast_link = NULL; /* use default multicast link */
daniele 0:d7f2341ab245 1172 } else {
daniele 0:d7f2341ab245 1173 mcast_link = pico_ipv4_link_get(&mreq->mcast_link_addr);
daniele 0:d7f2341ab245 1174 if (!mcast_link) {
daniele 0:d7f2341ab245 1175 pico_err = PICO_ERR_EINVAL;
daniele 0:d7f2341ab245 1176 return -1;
daniele 0:d7f2341ab245 1177 }
daniele 0:d7f2341ab245 1178 }
daniele 0:d7f2341ab245 1179 return pico_ipv4_mcast_leave_group(&mreq->mcast_group_addr, mcast_link);
daniele 0:d7f2341ab245 1180 }
daniele 0:d7f2341ab245 1181 break;
daniele 0:d7f2341ab245 1182 #endif /* PICO_SUPPORT_MCAST */
daniele 0:d7f2341ab245 1183
daniele 0:d7f2341ab245 1184 default:
daniele 0:d7f2341ab245 1185 pico_err = PICO_ERR_EINVAL;
daniele 0:d7f2341ab245 1186 return -1;
daniele 0:d7f2341ab245 1187 }
daniele 0:d7f2341ab245 1188
daniele 0:d7f2341ab245 1189 if (pico_err != PICO_ERR_NOERR)
daniele 0:d7f2341ab245 1190 return -1;
daniele 0:d7f2341ab245 1191 else
daniele 0:d7f2341ab245 1192 return 0;
daniele 0:d7f2341ab245 1193 }
daniele 0:d7f2341ab245 1194
daniele 0:d7f2341ab245 1195 #define PICO_SOCKET_GETOPT(socket,index) ((socket->opt_flags & (1 << index)) != 0)
daniele 0:d7f2341ab245 1196
daniele 0:d7f2341ab245 1197 int pico_socket_getoption(struct pico_socket *s, int option, void *value)
daniele 0:d7f2341ab245 1198 {
daniele 0:d7f2341ab245 1199 if (!s || !value) {
daniele 0:d7f2341ab245 1200 pico_err = PICO_ERR_EINVAL;
daniele 0:d7f2341ab245 1201 return -1;
daniele 0:d7f2341ab245 1202 }
daniele 0:d7f2341ab245 1203
daniele 0:d7f2341ab245 1204 switch (option)
daniele 0:d7f2341ab245 1205 {
daniele 0:d7f2341ab245 1206 #ifdef PICO_SUPPORT_TCP
daniele 0:d7f2341ab245 1207 case PICO_TCP_NODELAY:
daniele 0:d7f2341ab245 1208 if (s->proto->proto_number == PICO_PROTO_TCP)
daniele 0:d7f2341ab245 1209 /* state Nagle's algorithm */
daniele 0:d7f2341ab245 1210 *(int *)value = PICO_SOCKET_GETOPT(s,PICO_SOCKET_OPT_TCPNODELAY);
daniele 0:d7f2341ab245 1211 else
daniele 0:d7f2341ab245 1212 *(int *)value = 0;
daniele 0:d7f2341ab245 1213 break;
daniele 0:d7f2341ab245 1214 #endif
daniele 0:d7f2341ab245 1215
daniele 0:d7f2341ab245 1216 #ifdef PICO_SUPPORT_MCAST
daniele 0:d7f2341ab245 1217 case PICO_IP_MULTICAST_IF:
daniele 0:d7f2341ab245 1218 pico_err = PICO_ERR_EOPNOTSUPP;
daniele 0:d7f2341ab245 1219 return -1;
daniele 0:d7f2341ab245 1220 break;
daniele 0:d7f2341ab245 1221
daniele 0:d7f2341ab245 1222 case PICO_IP_MULTICAST_TTL:
daniele 0:d7f2341ab245 1223 if (s->proto->proto_number == PICO_PROTO_UDP) {
daniele 0:d7f2341ab245 1224 pico_udp_get_mc_ttl(s, (uint8_t *) value);
daniele 0:d7f2341ab245 1225 } else {
daniele 0:d7f2341ab245 1226 *(uint8_t *)value = 0;
daniele 0:d7f2341ab245 1227 pico_err = PICO_ERR_EINVAL;
daniele 0:d7f2341ab245 1228 return -1;
daniele 0:d7f2341ab245 1229 }
daniele 0:d7f2341ab245 1230 break;
daniele 0:d7f2341ab245 1231
daniele 0:d7f2341ab245 1232 case PICO_IP_MULTICAST_LOOP:
daniele 0:d7f2341ab245 1233 if (s->proto->proto_number == PICO_PROTO_UDP) {
daniele 0:d7f2341ab245 1234 *(uint8_t *)value = PICO_SOCKET_GETOPT(s,PICO_SOCKET_OPT_MULTICAST_LOOP);
daniele 0:d7f2341ab245 1235 } else {
daniele 0:d7f2341ab245 1236 *(uint8_t *)value = 0;
daniele 0:d7f2341ab245 1237 pico_err = PICO_ERR_EINVAL;
daniele 0:d7f2341ab245 1238 return -1;
daniele 0:d7f2341ab245 1239 }
daniele 0:d7f2341ab245 1240 break;
daniele 0:d7f2341ab245 1241 #endif /* PICO_SUPPORT_MCAST */
daniele 0:d7f2341ab245 1242
daniele 0:d7f2341ab245 1243 default:
daniele 0:d7f2341ab245 1244 pico_err = PICO_ERR_EINVAL;
daniele 0:d7f2341ab245 1245 return -1;
daniele 0:d7f2341ab245 1246 }
daniele 0:d7f2341ab245 1247
daniele 0:d7f2341ab245 1248 return 0;
daniele 0:d7f2341ab245 1249 }
daniele 0:d7f2341ab245 1250
daniele 0:d7f2341ab245 1251
daniele 0:d7f2341ab245 1252 int pico_socket_shutdown(struct pico_socket *s, int mode)
daniele 0:d7f2341ab245 1253 {
daniele 0:d7f2341ab245 1254 if (!s) {
daniele 0:d7f2341ab245 1255 pico_err = PICO_ERR_EINVAL;
daniele 0:d7f2341ab245 1256 return -1;
daniele 0:d7f2341ab245 1257 } else {
daniele 0:d7f2341ab245 1258 /* check if exists in tree */
daniele 0:d7f2341ab245 1259 /* See task #178 */
daniele 0:d7f2341ab245 1260 if (pico_check_socket(s) != 0) {
daniele 0:d7f2341ab245 1261 pico_free(s); /* close socket after bind or connect failed */
daniele 0:d7f2341ab245 1262 return 0;
daniele 0:d7f2341ab245 1263 }
daniele 0:d7f2341ab245 1264 }
daniele 0:d7f2341ab245 1265
daniele 0:d7f2341ab245 1266 #ifdef PICO_SUPPORT_UDP
daniele 0:d7f2341ab245 1267 if (PROTO(s) == PICO_PROTO_UDP) {
daniele 0:d7f2341ab245 1268 if (mode & PICO_SHUT_RDWR)
daniele 0:d7f2341ab245 1269 pico_socket_alter_state(s, PICO_SOCKET_STATE_CLOSED, PICO_SOCKET_STATE_CLOSING |PICO_SOCKET_STATE_BOUND | PICO_SOCKET_STATE_CONNECTED, 0);
daniele 0:d7f2341ab245 1270 else if (mode & PICO_SHUT_RD)
daniele 0:d7f2341ab245 1271 pico_socket_alter_state(s, PICO_SOCKET_STATE_BOUND, 0, 0);
daniele 0:d7f2341ab245 1272 }
daniele 0:d7f2341ab245 1273 #endif
daniele 0:d7f2341ab245 1274 #ifdef PICO_SUPPORT_TCP
daniele 0:d7f2341ab245 1275 if (PROTO(s) == PICO_PROTO_TCP) {
daniele 0:d7f2341ab245 1276 if (mode & PICO_SHUT_WR)
daniele 0:d7f2341ab245 1277 pico_socket_alter_state(s, PICO_SOCKET_STATE_SHUT_LOCAL, 0, 0);
daniele 0:d7f2341ab245 1278 else if (mode & PICO_SHUT_RD)
daniele 0:d7f2341ab245 1279 pico_socket_alter_state(s, PICO_SOCKET_STATE_SHUT_REMOTE, 0, 0);
daniele 0:d7f2341ab245 1280 else if (mode & PICO_SHUT_RDWR)
daniele 0:d7f2341ab245 1281 pico_socket_alter_state(s, PICO_SOCKET_STATE_SHUT_LOCAL | PICO_SOCKET_STATE_SHUT_REMOTE, 0, 0);
daniele 0:d7f2341ab245 1282 }
daniele 0:d7f2341ab245 1283 #endif
daniele 0:d7f2341ab245 1284 return 0;
daniele 0:d7f2341ab245 1285 }
daniele 0:d7f2341ab245 1286
daniele 0:d7f2341ab245 1287 int pico_socket_close(struct pico_socket *s)
daniele 0:d7f2341ab245 1288 {
daniele 0:d7f2341ab245 1289 return pico_socket_shutdown(s, PICO_SHUT_RDWR);
daniele 0:d7f2341ab245 1290 }
daniele 0:d7f2341ab245 1291
daniele 0:d7f2341ab245 1292 #ifdef PICO_SUPPORT_CRC
daniele 0:d7f2341ab245 1293 static inline int pico_transport_crc_check(struct pico_frame *f)
daniele 0:d7f2341ab245 1294 {
daniele 0:d7f2341ab245 1295 struct pico_ipv4_hdr *net_hdr = (struct pico_ipv4_hdr *) f->net_hdr;
daniele 0:d7f2341ab245 1296 struct pico_udp_hdr *udp_hdr = NULL;
daniele 0:d7f2341ab245 1297 uint16_t checksum_invalid = 1;
daniele 0:d7f2341ab245 1298
daniele 0:d7f2341ab245 1299 switch (net_hdr->proto)
daniele 0:d7f2341ab245 1300 {
daniele 0:d7f2341ab245 1301 case PICO_PROTO_TCP:
daniele 0:d7f2341ab245 1302 checksum_invalid = short_be(pico_tcp_checksum_ipv4(f));
daniele 0:d7f2341ab245 1303 //dbg("TCP CRC validation == %u\n", checksum_invalid);
daniele 0:d7f2341ab245 1304 if (checksum_invalid) {
daniele 0:d7f2341ab245 1305 //dbg("TCP CRC: validation failed!\n");
daniele 0:d7f2341ab245 1306 pico_frame_discard(f);
daniele 0:d7f2341ab245 1307 return 0;
daniele 0:d7f2341ab245 1308 }
daniele 0:d7f2341ab245 1309 break;
daniele 0:d7f2341ab245 1310
daniele 0:d7f2341ab245 1311 case PICO_PROTO_UDP:
daniele 0:d7f2341ab245 1312 udp_hdr = (struct pico_udp_hdr *) f->transport_hdr;
daniele 0:d7f2341ab245 1313 if (short_be(udp_hdr->crc)) {
daniele 0:d7f2341ab245 1314 checksum_invalid = short_be(pico_udp_checksum_ipv4(f));
daniele 0:d7f2341ab245 1315 //dbg("UDP CRC validation == %u\n", checksum_invalid);
daniele 0:d7f2341ab245 1316 if (checksum_invalid) {
daniele 0:d7f2341ab245 1317 //dbg("UDP CRC: validation failed!\n");
daniele 0:d7f2341ab245 1318 pico_frame_discard(f);
daniele 0:d7f2341ab245 1319 return 0;
daniele 0:d7f2341ab245 1320 }
daniele 0:d7f2341ab245 1321 }
daniele 0:d7f2341ab245 1322 break;
daniele 0:d7f2341ab245 1323
daniele 0:d7f2341ab245 1324 default:
daniele 0:d7f2341ab245 1325 // Do nothing
daniele 0:d7f2341ab245 1326 break;
daniele 0:d7f2341ab245 1327 }
daniele 0:d7f2341ab245 1328 return 1;
daniele 0:d7f2341ab245 1329 }
daniele 0:d7f2341ab245 1330 #else
daniele 0:d7f2341ab245 1331 static inline int pico_transport_crc_check(struct pico_frame *f)
daniele 0:d7f2341ab245 1332 {
daniele 0:d7f2341ab245 1333 return 1;
daniele 0:d7f2341ab245 1334 }
daniele 0:d7f2341ab245 1335 #endif /* PICO_SUPPORT_CRC */
daniele 0:d7f2341ab245 1336
daniele 0:d7f2341ab245 1337 int pico_transport_process_in(struct pico_protocol *self, struct pico_frame *f)
daniele 0:d7f2341ab245 1338 {
daniele 0:d7f2341ab245 1339 struct pico_trans *hdr = (struct pico_trans *) f->transport_hdr;
daniele 0:d7f2341ab245 1340 int ret = 0;
daniele 0:d7f2341ab245 1341
daniele 0:d7f2341ab245 1342 if (!hdr) {
daniele 0:d7f2341ab245 1343 pico_err = PICO_ERR_EFAULT;
daniele 0:d7f2341ab245 1344 return -1;
daniele 0:d7f2341ab245 1345 }
daniele 0:d7f2341ab245 1346
daniele 0:d7f2341ab245 1347 ret = pico_transport_crc_check(f);
daniele 0:d7f2341ab245 1348 if (ret < 1)
daniele 0:d7f2341ab245 1349 return ret;
daniele 0:d7f2341ab245 1350 else
daniele 0:d7f2341ab245 1351 ret = 0;
daniele 0:d7f2341ab245 1352
daniele 0:d7f2341ab245 1353 if ((hdr) && (pico_socket_deliver(self, f, hdr->dport) == 0))
daniele 0:d7f2341ab245 1354 return ret;
daniele 0:d7f2341ab245 1355
daniele 0:d7f2341ab245 1356 if (!IS_BCAST(f)) {
daniele 0:d7f2341ab245 1357 dbg("Socket not found... \n");
daniele 0:d7f2341ab245 1358 pico_notify_socket_unreachable(f);
daniele 0:d7f2341ab245 1359 #ifdef PICO_SUPPORT_TCP
daniele 0:d7f2341ab245 1360 /* if tcp protocol send RST segment */
daniele 0:d7f2341ab245 1361 //if (self->proto_number == PICO_PROTO_TCP)
daniele 0:d7f2341ab245 1362 // pico_tcp_reply_rst(f);
daniele 0:d7f2341ab245 1363 #endif
daniele 0:d7f2341ab245 1364 ret = -1;
daniele 0:d7f2341ab245 1365 pico_err = PICO_ERR_ENOENT;
daniele 0:d7f2341ab245 1366 }
daniele 0:d7f2341ab245 1367 pico_frame_discard(f);
daniele 0:d7f2341ab245 1368 return ret;
daniele 0:d7f2341ab245 1369 }
daniele 0:d7f2341ab245 1370
daniele 0:d7f2341ab245 1371 #define SL_LOOP_MIN 1
daniele 0:d7f2341ab245 1372
daniele 0:d7f2341ab245 1373
daniele 0:d7f2341ab245 1374 int pico_sockets_loop(int loop_score)
daniele 0:d7f2341ab245 1375 {
daniele 0:d7f2341ab245 1376 static struct pico_tree_node *index_udp, * index_tcp;
daniele 0:d7f2341ab245 1377
daniele 0:d7f2341ab245 1378 struct pico_sockport *start;
daniele 0:d7f2341ab245 1379 struct pico_socket *s;
daniele 0:d7f2341ab245 1380
daniele 0:d7f2341ab245 1381 #ifdef PICO_SUPPORT_UDP
daniele 0:d7f2341ab245 1382 struct pico_frame *f;
daniele 0:d7f2341ab245 1383
daniele 0:d7f2341ab245 1384 if (sp_udp == NULL)
daniele 0:d7f2341ab245 1385 {
daniele 0:d7f2341ab245 1386 index_udp = pico_tree_firstNode(UDPTable.root);
daniele 0:d7f2341ab245 1387 sp_udp = index_udp->keyValue;
daniele 0:d7f2341ab245 1388 }
daniele 0:d7f2341ab245 1389
daniele 0:d7f2341ab245 1390 /* init start node */
daniele 0:d7f2341ab245 1391 start = sp_udp;
daniele 0:d7f2341ab245 1392
daniele 0:d7f2341ab245 1393 /* round-robin all transport protocols, break if traversed all protocols */
daniele 0:d7f2341ab245 1394 while (loop_score > SL_LOOP_MIN && sp_udp != NULL) {
daniele 0:d7f2341ab245 1395 struct pico_tree_node * index;
daniele 0:d7f2341ab245 1396
daniele 0:d7f2341ab245 1397 pico_tree_foreach(index,&sp_udp->socks){
daniele 0:d7f2341ab245 1398 s = index->keyValue;
daniele 0:d7f2341ab245 1399 f = pico_dequeue(&s->q_out);
daniele 0:d7f2341ab245 1400 while (f && (loop_score > 0)) {
daniele 0:d7f2341ab245 1401 pico_proto_udp.push(&pico_proto_udp, f);
daniele 0:d7f2341ab245 1402 loop_score -= 1;
daniele 0:d7f2341ab245 1403 f = pico_dequeue(&s->q_out);
daniele 0:d7f2341ab245 1404 }
daniele 0:d7f2341ab245 1405 }
daniele 0:d7f2341ab245 1406
daniele 0:d7f2341ab245 1407 index_udp = pico_tree_next(index_udp);
daniele 0:d7f2341ab245 1408 sp_udp = index_udp->keyValue;
daniele 0:d7f2341ab245 1409
daniele 0:d7f2341ab245 1410 if (sp_udp == NULL)
daniele 0:d7f2341ab245 1411 {
daniele 0:d7f2341ab245 1412 index_udp = pico_tree_firstNode(UDPTable.root);
daniele 0:d7f2341ab245 1413 sp_udp = index_udp->keyValue;
daniele 0:d7f2341ab245 1414 }
daniele 0:d7f2341ab245 1415 if (sp_udp == start)
daniele 0:d7f2341ab245 1416 break;
daniele 0:d7f2341ab245 1417 }
daniele 0:d7f2341ab245 1418 #endif
daniele 0:d7f2341ab245 1419
daniele 0:d7f2341ab245 1420 #ifdef PICO_SUPPORT_TCP
daniele 0:d7f2341ab245 1421 if (sp_tcp == NULL)
daniele 0:d7f2341ab245 1422 {
daniele 0:d7f2341ab245 1423 index_tcp = pico_tree_firstNode(TCPTable.root);
daniele 0:d7f2341ab245 1424 sp_tcp = index_tcp->keyValue;
daniele 0:d7f2341ab245 1425 }
daniele 0:d7f2341ab245 1426
daniele 0:d7f2341ab245 1427 /* init start node */
daniele 0:d7f2341ab245 1428 start = sp_tcp;
daniele 0:d7f2341ab245 1429
daniele 0:d7f2341ab245 1430 while (loop_score > SL_LOOP_MIN && sp_tcp != NULL) {
daniele 0:d7f2341ab245 1431 struct pico_tree_node * index;
daniele 0:d7f2341ab245 1432 pico_tree_foreach(index, &sp_tcp->socks){
daniele 0:d7f2341ab245 1433 s = index->keyValue;
daniele 0:d7f2341ab245 1434 loop_score = pico_tcp_output(s, loop_score);
daniele 0:d7f2341ab245 1435 if ((s->ev_pending) && s->wakeup) {
daniele 0:d7f2341ab245 1436 s->wakeup(s->ev_pending, s);
daniele 0:d7f2341ab245 1437 }
daniele 0:d7f2341ab245 1438 if (loop_score <= 0) {
daniele 0:d7f2341ab245 1439 loop_score = 0;
daniele 0:d7f2341ab245 1440 break;
daniele 0:d7f2341ab245 1441 }
daniele 0:d7f2341ab245 1442 }
daniele 0:d7f2341ab245 1443
daniele 0:d7f2341ab245 1444 /* check if RB_FOREACH ended, if not, break to keep the cur sp_tcp */
daniele 0:d7f2341ab245 1445 if (s != NULL)
daniele 0:d7f2341ab245 1446 break;
daniele 0:d7f2341ab245 1447
daniele 0:d7f2341ab245 1448 index_tcp = pico_tree_next(index_tcp);
daniele 0:d7f2341ab245 1449 sp_tcp = index_tcp->keyValue;
daniele 0:d7f2341ab245 1450
daniele 0:d7f2341ab245 1451 if (sp_tcp == NULL)
daniele 0:d7f2341ab245 1452 {
daniele 0:d7f2341ab245 1453 index_tcp = pico_tree_firstNode(TCPTable.root);
daniele 0:d7f2341ab245 1454 sp_tcp = index_tcp->keyValue;
daniele 0:d7f2341ab245 1455 }
daniele 0:d7f2341ab245 1456 if (sp_tcp == start)
daniele 0:d7f2341ab245 1457 break;
daniele 0:d7f2341ab245 1458 }
daniele 0:d7f2341ab245 1459 #endif
daniele 0:d7f2341ab245 1460
daniele 0:d7f2341ab245 1461 return loop_score;
daniele 0:d7f2341ab245 1462 }
daniele 0:d7f2341ab245 1463
daniele 0:d7f2341ab245 1464
daniele 0:d7f2341ab245 1465 struct pico_frame *pico_socket_frame_alloc(struct pico_socket *s, int len)
daniele 0:d7f2341ab245 1466 {
daniele 0:d7f2341ab245 1467 struct pico_frame *f = NULL;
daniele 0:d7f2341ab245 1468
daniele 0:d7f2341ab245 1469 #ifdef PICO_SUPPORT_IPV6
daniele 0:d7f2341ab245 1470 if (IS_SOCK_IPV6(s))
daniele 0:d7f2341ab245 1471 f = pico_proto_ipv6.alloc(&pico_proto_ipv6, len);
daniele 0:d7f2341ab245 1472 #endif
daniele 0:d7f2341ab245 1473
daniele 0:d7f2341ab245 1474 #ifdef PICO_SUPPORT_IPV4
daniele 0:d7f2341ab245 1475 if (IS_SOCK_IPV4(s))
daniele 0:d7f2341ab245 1476 f = pico_proto_ipv4.alloc(&pico_proto_ipv4, len);
daniele 0:d7f2341ab245 1477 #endif
daniele 0:d7f2341ab245 1478 if (!f) {
daniele 0:d7f2341ab245 1479 pico_err = PICO_ERR_ENOMEM;
daniele 0:d7f2341ab245 1480 return f;
daniele 0:d7f2341ab245 1481 }
daniele 0:d7f2341ab245 1482 f->payload = f->transport_hdr;
daniele 0:d7f2341ab245 1483 f->payload_len = len;
daniele 0:d7f2341ab245 1484 f->sock = s;
daniele 0:d7f2341ab245 1485 return f;
daniele 0:d7f2341ab245 1486 }
daniele 0:d7f2341ab245 1487
daniele 0:d7f2341ab245 1488 int pico_transport_error(struct pico_frame *f, uint8_t proto, int code)
daniele 0:d7f2341ab245 1489 {
daniele 0:d7f2341ab245 1490 int ret = -1;
daniele 0:d7f2341ab245 1491 struct pico_trans *trans = (struct pico_trans*) f->transport_hdr;
daniele 0:d7f2341ab245 1492 struct pico_sockport *port = NULL;
daniele 0:d7f2341ab245 1493 struct pico_socket *s = NULL;
daniele 0:d7f2341ab245 1494 switch (proto) {
daniele 0:d7f2341ab245 1495
daniele 0:d7f2341ab245 1496
daniele 0:d7f2341ab245 1497 #ifdef PICO_SUPPORT_UDP
daniele 0:d7f2341ab245 1498 case PICO_PROTO_UDP:
daniele 0:d7f2341ab245 1499 port = pico_get_sockport(proto, trans->sport);
daniele 0:d7f2341ab245 1500 break;
daniele 0:d7f2341ab245 1501 #endif
daniele 0:d7f2341ab245 1502
daniele 0:d7f2341ab245 1503 #ifdef PICO_SUPPORT_TCP
daniele 0:d7f2341ab245 1504 case PICO_PROTO_TCP:
daniele 0:d7f2341ab245 1505 port = pico_get_sockport(proto, trans->sport);
daniele 0:d7f2341ab245 1506 break;
daniele 0:d7f2341ab245 1507 #endif
daniele 0:d7f2341ab245 1508
daniele 0:d7f2341ab245 1509 default:
daniele 0:d7f2341ab245 1510 /* Protocol not available */
daniele 0:d7f2341ab245 1511 ret = -1;
daniele 0:d7f2341ab245 1512 }
daniele 0:d7f2341ab245 1513 if (port) {
daniele 0:d7f2341ab245 1514 struct pico_tree_node * index;
daniele 0:d7f2341ab245 1515 ret = 0;
daniele 0:d7f2341ab245 1516
daniele 0:d7f2341ab245 1517 pico_tree_foreach(index,&port->socks) {
daniele 0:d7f2341ab245 1518 s = index->keyValue;
daniele 0:d7f2341ab245 1519 if (trans->dport == s->remote_port) {
daniele 0:d7f2341ab245 1520 if (s->wakeup) {
daniele 0:d7f2341ab245 1521 //dbg("SOCKET ERROR FROM ICMP NOTIFICATION. (icmp code= %d)\n\n", code);
daniele 0:d7f2341ab245 1522 switch(code) {
daniele 0:d7f2341ab245 1523 case PICO_ICMP_UNREACH_PROTOCOL:
daniele 0:d7f2341ab245 1524 pico_err = PICO_ERR_EPROTO;
daniele 0:d7f2341ab245 1525 break;
daniele 0:d7f2341ab245 1526
daniele 0:d7f2341ab245 1527 case PICO_ICMP_UNREACH_PORT:
daniele 0:d7f2341ab245 1528 pico_err = PICO_ERR_ECONNREFUSED;
daniele 0:d7f2341ab245 1529 break;
daniele 0:d7f2341ab245 1530
daniele 0:d7f2341ab245 1531 case PICO_ICMP_UNREACH_NET:
daniele 0:d7f2341ab245 1532 case PICO_ICMP_UNREACH_NET_PROHIB:
daniele 0:d7f2341ab245 1533 case PICO_ICMP_UNREACH_NET_UNKNOWN:
daniele 0:d7f2341ab245 1534 pico_err = PICO_ERR_ENETUNREACH;
daniele 0:d7f2341ab245 1535 break;
daniele 0:d7f2341ab245 1536
daniele 0:d7f2341ab245 1537 default:
daniele 0:d7f2341ab245 1538 pico_err = PICO_ERR_EHOSTUNREACH;
daniele 0:d7f2341ab245 1539 }
daniele 0:d7f2341ab245 1540 s->wakeup(PICO_SOCK_EV_ERR, s);
daniele 0:d7f2341ab245 1541 }
daniele 0:d7f2341ab245 1542 break;
daniele 0:d7f2341ab245 1543 }
daniele 0:d7f2341ab245 1544 }
daniele 0:d7f2341ab245 1545 }
daniele 0:d7f2341ab245 1546 pico_frame_discard(f);
daniele 0:d7f2341ab245 1547 return ret;
daniele 0:d7f2341ab245 1548 }
daniele 0:d7f2341ab245 1549 #endif
daniele 0:d7f2341ab245 1550 #endif