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