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
7   Authors: Daniele Lacamera
8 *********************************************************************/
9
10#include "pico_config.h"
11#include "pico_tree.h"
12#include "pico_icmp6.h"
13#include "pico_ipv6.h"
14#include "pico_stack.h"
15#include "pico_device.h"
16#include "pico_eth.h"
17#include "pico_addressing.h"
18#include "pico_ipv6_nd.h"
19#include "pico_ethernet.h"
20#include "pico_6lowpan.h"
21#include "pico_6lowpan_ll.h"
22
23#ifdef PICO_SUPPORT_IPV6
24
25#ifdef DEBUG_IPV6_ND
26#define nd_dbg dbg
27#else
28#define nd_dbg(...) do {} while(0)
29#endif
30
31#define ONE_MINUTE                          ((pico_time)(1000 * 60))
32
33#ifdef PICO_SUPPORT_6LOWPAN
34    #define MAX_RTR_SOLICITATIONS           (3)
35    #define RTR_SOLICITATION_INTERVAL       (10000)
36    #define MAX_RTR_SOLICITATION_INTERVAL   (60000)
37#endif
38
39static struct pico_frame *frames_queued_v6[PICO_ND_MAX_FRAMES_QUEUED] = {
40    0
41};
42
43enum pico_ipv6_neighbor_state {
44    PICO_ND_STATE_INCOMPLETE = 0,
45    PICO_ND_STATE_REACHABLE,
46    PICO_ND_STATE_STALE,
47    PICO_ND_STATE_DELAY,
48    PICO_ND_STATE_PROBE
49};
50
51struct pico_ipv6_neighbor {
52    enum pico_ipv6_neighbor_state state;
53    struct pico_ip6 address;
54    union pico_hw_addr hwaddr;
55    struct pico_device *dev;
56    uint16_t is_router;
57    uint16_t failure_count;
58    pico_time expire;
59};
60
61/******************************************************************************
62 *  Function prototypes
63 ******************************************************************************/
64
65#ifdef PICO_SUPPORT_6LOWPAN
66static void pico_6lp_nd_deregister(struct pico_ipv6_link *);
67static void pico_6lp_nd_unreachable_gateway(struct pico_ip6 *a);
68static int pico_6lp_nd_neigh_adv_process(struct pico_frame *f);
69static int neigh_sol_detect_dad_6lp(struct pico_frame *f);
70#endif
71
72static int pico_ipv6_neighbor_compare(void *ka, void *kb)
73{
74    struct pico_ipv6_neighbor *a = ka, *b = kb;
75    return pico_ipv6_compare(&a->address, &b->address);
76}
77PICO_TREE_DECLARE(NCache, pico_ipv6_neighbor_compare);
78
79static struct pico_ipv6_neighbor *pico_nd_find_neighbor(struct pico_ip6 *dst)
80{
81    struct pico_ipv6_neighbor test = {
82        0
83    };
84
85    test.address = *dst;
86    return pico_tree_findKey(&NCache, &test);
87}
88
89static void pico_ipv6_nd_queued_trigger(void)
90{
91    int i;
92    struct pico_frame *f;
93    for (i = 0; i < PICO_ND_MAX_FRAMES_QUEUED; i++)
94    {
95        f = frames_queued_v6[i];
96        if (f) {
97            if (pico_datalink_send(f) <= 0)
98                pico_frame_discard(f);
99            frames_queued_v6[i] = NULL;
100        }
101    }
102}
103
104static void ipv6_duplicate_detected(struct pico_ipv6_link *l)
105{
106    struct pico_device *dev;
107    int is_ll = pico_ipv6_is_linklocal(l->address.addr);
108    dev = l->dev;
109    dbg("IPV6: Duplicate address detected. Removing link.\n");
110    pico_ipv6_link_del(l->dev, l->address);
111#ifdef PICO_SUPPORT_6LOWPAN
112    if (PICO_DEV_IS_6LOWPAN(l->dev)) {
113        pico_6lp_nd_deregister(l);
114    }
115#endif
116    if (is_ll)
117        pico_device_ipv6_random_ll(dev);
118}
119
120static struct pico_ipv6_neighbor *pico_nd_add(struct pico_ip6 *addr, struct pico_device *dev)
121{
122    struct pico_ipv6_neighbor *n;
123    char address[120];
124    /* Create a new NCE */
125    n = PICO_ZALLOC(sizeof(struct pico_ipv6_neighbor));
126    if (!n)
127        return NULL;
128    pico_ipv6_to_string(address, addr->addr);
129    memcpy(&n->address, addr, sizeof(struct pico_ip6));
130    n->dev = dev;
131
132    if (pico_tree_insert(&NCache, n)) {
133        nd_dbg("IPv6 ND: Failed to insert neigbor in tree\n");
134		PICO_FREE(n);
135		return NULL;
136	}
137
138    return n;
139}
140
141static void pico_ipv6_nd_unreachable(struct pico_ip6 *a)
142{
143    int i;
144    struct pico_frame *f;
145    struct pico_ipv6_hdr *hdr;
146    struct pico_ip6 dst;
147#ifdef PICO_SUPPORT_6LOWPAN
148    /* 6LP: Find any 6LoWPAN-hosts for which this address might have been a default gateway.
149     * If such a host found, send a router solicitation again */
150    pico_6lp_nd_unreachable_gateway(a);
151#endif /* PICO_SUPPORT_6LOWPAN */
152    for (i = 0; i < PICO_ND_MAX_FRAMES_QUEUED; i++)
153    {
154        f = frames_queued_v6[i];
155        if (f) {
156            hdr = (struct pico_ipv6_hdr *) f->net_hdr;
157            dst = pico_ipv6_route_get_gateway(&hdr->dst);
158            if (pico_ipv6_is_unspecified(dst.addr))
159                dst = hdr->dst;
160
161            if (memcmp(dst.addr, a->addr, PICO_SIZE_IP6) == 0) {
162                if (!pico_source_is_local(f)) {
163                    pico_notify_dest_unreachable(f);
164                }
165
166                pico_frame_discard(f);
167                frames_queued_v6[i] = NULL;
168            }
169        }
170    }
171}
172
173static void pico_nd_new_expire_time(struct pico_ipv6_neighbor *n)
174{
175    if (n->state == PICO_ND_STATE_REACHABLE)
176        n->expire = PICO_TIME_MS() + PICO_ND_REACHABLE_TIME;
177    else if ((n->state == PICO_ND_STATE_DELAY) || (n->state == PICO_ND_STATE_STALE))
178        n->expire = PICO_TIME_MS() + PICO_ND_DELAY_FIRST_PROBE_TIME;
179    else {
180        n->expire = n->dev->hostvars.retranstime + PICO_TIME_MS();
181    }
182}
183
184static void pico_nd_discover(struct pico_ipv6_neighbor *n)
185{
186    char IPADDR[64];
187
188    if (!n) {
189        return;
190    } else {
191        if (n->expire != (pico_time)0) {
192            return;
193        } else {
194            pico_ipv6_to_string(IPADDR, n->address.addr);
195            /* dbg("Sending NS for %s\n", IPADDR); */
196            if (++n->failure_count > PICO_ND_MAX_SOLICIT)
197                return;
198
199            if (n->state == PICO_ND_STATE_INCOMPLETE) {
200                pico_icmp6_neighbor_solicitation(n->dev, &n->address, PICO_ICMP6_ND_SOLICITED, &n->address);
201            } else {
202                pico_icmp6_neighbor_solicitation(n->dev, &n->address, PICO_ICMP6_ND_UNICAST, &n->address);
203            }
204
205            pico_nd_new_expire_time(n);
206        }
207    }
208}
209
210static struct pico_eth *pico_nd_get_neighbor(struct pico_ip6 *addr, struct pico_ipv6_neighbor *n, struct pico_device *dev)
211{
212    /* dbg("Finding neighbor %02x:...:%02x, state = %d\n", addr->addr[0], addr->addr[15], n?n->state:-1); */
213
214    if (!n) {
215        n = pico_nd_add(addr, dev);
216        pico_nd_discover(n);
217        return NULL;
218    } else {
219        if (n->state == PICO_ND_STATE_INCOMPLETE) {
220            return NULL;
221        } else if (n->state == PICO_ND_STATE_STALE) {
222            n->state = PICO_ND_STATE_DELAY;
223            pico_nd_new_expire_time(n);
224        }
225
226        if (n->state != PICO_ND_STATE_REACHABLE) {
227            pico_nd_discover(n);
228        }
229    }
230    return &n->hwaddr.mac;
231}
232
233static struct pico_eth *pico_nd_get(struct pico_ip6 *address, struct pico_device *dev)
234{
235    struct pico_ip6 gateway = {{0}}, addr = {{0}};
236
237    /* should we use gateway, or is dst local (gateway == 0)? */
238    gateway = pico_ipv6_route_get_gateway(address);
239    if (memcmp(gateway.addr, PICO_IP6_ANY, PICO_SIZE_IP6) == 0)
240        addr = *address;
241    else
242        addr = gateway;
243
244    return pico_nd_get_neighbor(&addr, pico_nd_find_neighbor(&addr), dev);
245}
246
247static int nd_options(uint8_t *options, struct pico_icmp6_opt_lladdr *opt, uint8_t expected_opt, int optlen, int len)
248{
249    uint8_t type = 0;
250    int found = 0;
251
252    while (optlen > 0) {
253        type = ((struct pico_icmp6_opt_lladdr *)options)->type;
254        len = ((struct pico_icmp6_opt_lladdr *)options)->len;
255        optlen -= len << 3; /* len in units of 8 octets */
256        if (len <= 0)
257            return -1; /* malformed option. */
258
259        if (type == expected_opt) {
260            if (found > 0)
261                return -1; /* malformed option: option is there twice. */
262
263            memcpy(opt, (struct pico_icmp6_opt_lladdr *)options, sizeof(struct pico_icmp6_opt_lladdr));
264            found++;
265        }
266
267        if (optlen > 0) {
268            options += len << 3;
269        } else { /* parsing options: terminated. */
270            return found;
271        }
272    }
273    return found;
274}
275
276static int neigh_options(struct pico_frame *f, struct pico_icmp6_opt_lladdr *opt, uint8_t expected_opt)
277{
278    /* RFC 4861 $7.1.2 + $7.2.5.
279     *  * The contents of any defined options that are not specified to be used
280     *  * with Neighbor Advertisement messages MUST be ignored and the packet
281     *  * processed as normal. The only defined option that may appear is the
282     *  * Target Link-Layer Address option.
283     *  */
284    struct pico_icmp6_hdr *icmp6_hdr = (struct pico_icmp6_hdr *)f->transport_hdr;
285    uint8_t *option = NULL;
286    int optlen = 0;
287    int len = 0;
288
289    optlen = f->transport_len - PICO_ICMP6HDR_NEIGH_ADV_SIZE;
290    if (optlen)
291        option = ((uint8_t *)&icmp6_hdr->msg.info.neigh_adv) + sizeof(struct neigh_adv_s);
292
293    return nd_options(option, opt, expected_opt, optlen, len);
294}
295
296static size_t pico_hw_addr_len(struct pico_device *dev, struct pico_icmp6_opt_lladdr *opt)
297{
298    size_t len = PICO_SIZE_ETH;
299#ifndef PICO_SUPPORT_6LOWPAN
300    IGNORE_PARAMETER(dev);
301    IGNORE_PARAMETER(opt);
302#else
303    if (PICO_DEV_IS_6LOWPAN(dev)) {
304        if (1 == opt->len) {
305            len = (size_t)SIZE_6LOWPAN_SHORT;
306        } else {
307            len = (size_t)SIZE_6LOWPAN_EXT;
308        }
309    }
310#endif
311    return len;
312}
313
314static void pico_ipv6_neighbor_update(struct pico_ipv6_neighbor *n, struct pico_icmp6_opt_lladdr *opt, struct pico_device *dev)
315{
316    memcpy(n->hwaddr.data, opt->addr.data, pico_hw_addr_len(dev, opt));
317}
318
319static int pico_ipv6_neighbor_compare_stored(struct pico_ipv6_neighbor *n, struct pico_icmp6_opt_lladdr *opt, struct pico_device *dev)
320{
321    return memcmp(n->hwaddr.data, opt->addr.data, pico_hw_addr_len(dev, opt));
322}
323
324static void neigh_adv_reconfirm_router_option(struct pico_ipv6_neighbor *n, unsigned int isRouter)
325{
326    if (!isRouter && n->is_router) {
327        pico_ipv6_router_down(&n->address);
328    }
329
330    if (isRouter)
331        n->is_router = 1;
332    else
333        n->is_router = 0;
334}
335
336
337static int neigh_adv_reconfirm_no_tlla(struct pico_ipv6_neighbor *n, struct pico_icmp6_hdr *hdr)
338{
339    if (IS_SOLICITED(hdr)) {
340        n->state = PICO_ND_STATE_REACHABLE;
341        n->failure_count = 0;
342        pico_ipv6_nd_queued_trigger();
343        pico_nd_new_expire_time(n);
344        return 0;
345    }
346
347    return -1;
348}
349
350
351static int neigh_adv_reconfirm(struct pico_ipv6_neighbor *n, struct pico_icmp6_opt_lladdr *opt, struct pico_icmp6_hdr *hdr, struct pico_device *dev)
352{
353
354    if (IS_SOLICITED(hdr) && !IS_OVERRIDE(hdr) && (pico_ipv6_neighbor_compare_stored(n, opt, dev) == 0)) {
355        n->state = PICO_ND_STATE_REACHABLE;
356        n->failure_count = 0;
357        pico_ipv6_nd_queued_trigger();
358        pico_nd_new_expire_time(n);
359        return 0;
360    }
361
362    if ((n->state == PICO_ND_STATE_REACHABLE) && IS_SOLICITED(hdr) && !IS_OVERRIDE(hdr)) {
363        n->state = PICO_ND_STATE_STALE;
364        return 0;
365    }
366
367    if (IS_SOLICITED(hdr) && IS_OVERRIDE(hdr)) {
368        pico_ipv6_neighbor_update(n, opt, dev);
369        n->state = PICO_ND_STATE_REACHABLE;
370        n->failure_count = 0;
371        pico_ipv6_nd_queued_trigger();
372        pico_nd_new_expire_time(n);
373        return 0;
374    }
375
376    if (!IS_SOLICITED(hdr) && IS_OVERRIDE(hdr) && (pico_ipv6_neighbor_compare_stored(n, opt, dev) != 0)) {
377        pico_ipv6_neighbor_update(n, opt, dev);
378        n->state = PICO_ND_STATE_STALE;
379        pico_ipv6_nd_queued_trigger();
380        pico_nd_new_expire_time(n);
381        return 0;
382    }
383
384    if ((n->state == PICO_ND_STATE_REACHABLE) && (!IS_SOLICITED(hdr)) && (!IS_OVERRIDE(hdr)) &&
385        (pico_ipv6_neighbor_compare_stored(n, opt, dev) != 0)) {
386
387        /* I.  If the Override flag is clear and the supplied link-layer address
388         *     differs from that in the cache, then one of two actions takes
389         *     place:
390         *     a. If the state of the entry is REACHABLE, set it to STALE, but
391         *        do not update the entry in any other way.
392         *     b. Otherwise, the received advertisement should be ignored and
393         *        MUST NOT update the cache.
394         */
395        n->state = PICO_ND_STATE_STALE;
396        pico_nd_new_expire_time(n);
397        return 0;
398    }
399
400    return -1;
401}
402
403static void neigh_adv_process_incomplete(struct pico_ipv6_neighbor *n, struct pico_frame *f, struct pico_icmp6_opt_lladdr *opt)
404{
405    struct pico_icmp6_hdr *icmp6_hdr = NULL;
406    if (!n || !f) {
407        return;
408    } else {
409        if (!(icmp6_hdr = (struct pico_icmp6_hdr *)f->transport_hdr))
410            return;
411        else {
412            if (IS_SOLICITED(icmp6_hdr)) {
413                n->state = PICO_ND_STATE_REACHABLE;
414                n->failure_count = 0;
415                pico_nd_new_expire_time(n);
416            } else {
417                n->state = PICO_ND_STATE_STALE;
418            }
419
420            if (opt)
421                pico_ipv6_neighbor_update(n, opt, f->dev);
422
423            pico_ipv6_nd_queued_trigger();
424        }
425    }
426}
427
428
429static int neigh_adv_process(struct pico_frame *f)
430{
431    struct pico_icmp6_hdr *icmp6_hdr = NULL;
432    struct pico_ipv6_neighbor *n = NULL;
433    struct pico_icmp6_opt_lladdr opt = {
434        0
435    };
436    int optres = neigh_options(f, &opt, PICO_ND_OPT_LLADDR_TGT);
437    icmp6_hdr = (struct pico_icmp6_hdr *)f->transport_hdr;
438
439    if (optres < 0) { /* Malformed packet: option field cannot be processed. */
440        return -1;
441    }
442
443#ifdef PICO_SUPPORT_6LOWPAN
444    if (PICO_DEV_IS_6LOWPAN(f->dev)) {
445        /* 6LoWPAN: parse Address Registration Comfirmation(nothing on success, remove link on failure) */
446        pico_6lp_nd_neigh_adv_process(f);
447    }
448#endif
449
450    /* Check if there's a NCE in the cache */
451    n = pico_nd_find_neighbor(&icmp6_hdr->msg.info.neigh_adv.target);
452    if (!n) {
453        return 0;
454    }
455
456    if ((optres == 0) || IS_OVERRIDE(icmp6_hdr) || (pico_ipv6_neighbor_compare_stored(n, &opt, f->dev) == 0)) {
457        neigh_adv_reconfirm_router_option(n, IS_ROUTER(icmp6_hdr));
458    }
459
460    if ((optres > 0) && (n->state == PICO_ND_STATE_INCOMPLETE)) {
461        neigh_adv_process_incomplete(n, f, &opt);
462        return 0;
463    }
464
465    if (optres > 0)
466        return neigh_adv_reconfirm(n, &opt, icmp6_hdr, f->dev);
467    else
468        return neigh_adv_reconfirm_no_tlla(n, icmp6_hdr);
469
470}
471
472static struct pico_ipv6_neighbor *pico_ipv6_neighbor_from_sol_new(struct pico_ip6 *ip, struct pico_icmp6_opt_lladdr *opt, struct pico_device *dev)
473{
474    size_t len = pico_hw_addr_len(dev, opt);
475    struct pico_ipv6_neighbor *n = NULL;
476    n = pico_nd_add(ip, dev);
477    if (!n)
478        return NULL;
479
480    memcpy(n->hwaddr.data, opt->addr.data, len);
481    memset(n->hwaddr.data + len, 0, sizeof(union pico_hw_addr) - len);
482    n->state = PICO_ND_STATE_STALE;
483    pico_ipv6_nd_queued_trigger();
484    return n;
485}
486
487static void pico_ipv6_neighbor_from_unsolicited(struct pico_frame *f)
488{
489    struct pico_ipv6_neighbor *n = NULL;
490    struct pico_icmp6_opt_lladdr opt = {
491        0
492    };
493    struct pico_ipv6_hdr *ip = (struct pico_ipv6_hdr *)f->net_hdr;
494    int valid_lladdr = neigh_options(f, &opt, PICO_ND_OPT_LLADDR_SRC);
495
496    if (!pico_ipv6_is_unspecified(ip->src.addr) && (valid_lladdr > 0)) {
497        n = pico_nd_find_neighbor(&ip->src);
498        if (!n) {
499            n = pico_ipv6_neighbor_from_sol_new(&ip->src, &opt, f->dev);
500        } else if (memcmp(opt.addr.data, n->hwaddr.data, pico_hw_addr_len(f->dev, &opt))) {
501            pico_ipv6_neighbor_update(n, &opt, f->dev);
502            n->state = PICO_ND_STATE_STALE;
503            pico_ipv6_nd_queued_trigger();
504            pico_nd_new_expire_time(n);
505        }
506
507        if (!n)
508            return;
509    }
510}
511
512static int neigh_sol_detect_dad(struct pico_frame *f)
513{
514    struct pico_icmp6_hdr *icmp6_hdr = NULL;
515    struct pico_ipv6_hdr *ipv6_hdr = NULL;
516    struct pico_ipv6_link *link = NULL;
517    ipv6_hdr = (struct pico_ipv6_hdr *)f->net_hdr;
518    icmp6_hdr = (struct pico_icmp6_hdr *)f->transport_hdr;
519
520    if (!f->dev->mode) {
521        link = pico_ipv6_link_istentative(&icmp6_hdr->msg.info.neigh_adv.target);
522        if (link) {
523            if (pico_ipv6_is_unicast(&ipv6_hdr->src))
524            {
525                /* RFC4862 5.4.3 : sender is performing address resolution,
526                 * our address is not yet valid, discard silently.
527                 */
528                dbg("DAD:Sender performing AR\n");
529            }
530
531            else if (pico_ipv6_is_unspecified(ipv6_hdr->src.addr) &&
532                     !pico_ipv6_is_allhosts_multicast(ipv6_hdr->dst.addr))
533            {
534                /* RFC4862 5.4.3 : sender is performing DaD */
535                dbg("DAD:Sender performing DaD\n");
536                ipv6_duplicate_detected(link);
537            }
538
539            return 0;
540        }
541    }
542
543    return -1; /* Current link is not tentative */
544}
545
546static int neigh_sol_process(struct pico_frame *f)
547{
548    struct pico_icmp6_hdr *icmp6_hdr = NULL;
549    struct pico_ipv6_link *link = NULL;
550    int valid_lladdr;
551    struct pico_icmp6_opt_lladdr opt = {
552        0
553    };
554    icmp6_hdr = (struct pico_icmp6_hdr *)f->transport_hdr;
555
556    valid_lladdr = neigh_options(f, &opt, PICO_ND_OPT_LLADDR_SRC);
557    pico_ipv6_neighbor_from_unsolicited(f);
558
559    if (!f->dev->mode && !valid_lladdr && (0 == neigh_sol_detect_dad(f)))
560        return 0;
561#ifdef PICO_SUPPORT_6LOWPAN
562    else if (PICO_DEV_IS_6LOWPAN(f->dev)) {
563        nd_dbg("[6LP-ND] Received Address Registration Option\n");
564        neigh_sol_detect_dad_6lp(f);
565    }
566#endif
567
568    if (valid_lladdr < 0)
569        return -1; /* Malformed packet. */
570
571    link = pico_ipv6_link_get(&icmp6_hdr->msg.info.neigh_adv.target);
572    if (!link) { /* Not for us. */
573        return -1;
574    }
575
576    pico_icmp6_neighbor_advertisement(f,  &icmp6_hdr->msg.info.neigh_adv.target);
577    return 0;
578}
579
580static int icmp6_initial_checks(struct pico_frame *f)
581{
582    /* Common "step 0" validation */
583    struct pico_ipv6_hdr *ipv6_hdr = NULL;
584    struct pico_icmp6_hdr *icmp6_hdr = NULL;
585
586    ipv6_hdr = (struct pico_ipv6_hdr *)f->net_hdr;
587    icmp6_hdr = (struct pico_icmp6_hdr *)f->transport_hdr;
588
589    /* RFC4861 - 7.1.2 :
590     *       - The IP Hop Limit field has a value of 255, i.e., the packet
591     *               could not possibly have been forwarded by a router.
592     *       - ICMP Checksum is valid.
593     *       - ICMP Code is 0.
594     */
595    if (ipv6_hdr->hop != 255 || pico_icmp6_checksum(f) != 0 || icmp6_hdr->code != 0)
596        return -1;
597
598    return 0;
599}
600
601static int neigh_adv_option_len_validity_check(struct pico_frame *f)
602{
603    /* Step 4 validation */
604    struct pico_icmp6_hdr *icmp6_hdr = NULL;
605    uint8_t *opt;
606    int optlen = f->transport_len - PICO_ICMP6HDR_NEIGH_ADV_SIZE;
607    /* RFC4861 - 7.1.2 :
608     *       - All included options have a length that is greater than zero.
609     */
610    icmp6_hdr = (struct pico_icmp6_hdr *)f->transport_hdr;
611    opt = ((uint8_t *)&icmp6_hdr->msg.info.neigh_adv) + sizeof(struct neigh_adv_s);
612
613    while(optlen > 0) {
614        int opt_size = (opt[1] << 3);
615        if (opt_size == 0)
616            return -1;
617
618        opt = opt + opt_size;
619        optlen -= opt_size;
620    }
621    return 0;
622}
623
624static int neigh_adv_mcast_validity_check(struct pico_frame *f)
625{
626    /* Step 3 validation */
627    struct pico_ipv6_hdr *ipv6_hdr = NULL;
628    struct pico_icmp6_hdr *icmp6_hdr = NULL;
629    /* RFC4861 - 7.1.2 :
630     *       - If the IP Destination Address is a multicast address the
631     *         Solicited flag is zero.
632     */
633    ipv6_hdr = (struct pico_ipv6_hdr *)f->net_hdr;
634    icmp6_hdr = (struct pico_icmp6_hdr *)f->transport_hdr;
635    if (pico_ipv6_is_multicast(ipv6_hdr->dst.addr) && IS_SOLICITED(icmp6_hdr))
636        return -1;
637
638    return neigh_adv_option_len_validity_check(f);
639}
640
641static int neigh_adv_validity_checks(struct pico_frame *f)
642{
643    /* Step 2 validation */
644    /* RFC4861 - 7.1.2:
645     * - ICMP length (derived from the IP length) is 24 or more octets.
646     */
647    if (f->transport_len < PICO_ICMP6HDR_NEIGH_ADV_SIZE)
648        return -1;
649
650    return neigh_adv_mcast_validity_check(f);
651}
652
653
654static int neigh_sol_mcast_validity_check(struct pico_frame *f)
655{
656    struct pico_icmp6_hdr *icmp6_hdr = NULL;
657    icmp6_hdr = (struct pico_icmp6_hdr *)f->transport_hdr;
658    if (pico_ipv6_is_solnode_multicast(icmp6_hdr->msg.info.neigh_sol.target.addr, f->dev) == 0)
659        return -1;
660
661    return 0;
662}
663
664static int neigh_sol_unicast_validity_check(struct pico_frame *f)
665{
666    struct pico_ipv6_link *link;
667    struct pico_icmp6_hdr *icmp6_hdr = NULL;
668
669#ifdef PICO_SUPPORT_6LOWPAN
670    /* Don't validate target address, the sol is always targeted at 6LBR so
671     * no possible interface on the 6LBR can have the same address as specified in
672     * the target */
673    if (PICO_DEV_IS_6LOWPAN(f->dev))
674        return 0;
675#endif
676
677    link = pico_ipv6_link_by_dev(f->dev);
678    icmp6_hdr = (struct pico_icmp6_hdr *)f->transport_hdr;
679    while(link) {
680        /* RFC4861, 7.2.3:
681         *
682         *  - The Target Address is a "valid" unicast or anycast address
683         *    assigned to the receiving interface [ADDRCONF],
684         *  - The Target Address is a unicast or anycast address for which the
685         *    node is offering proxy service, or
686         *  - The Target Address is a "tentative" address on which Duplicate
687         *    Address Detection is being performed
688         */
689        if (pico_ipv6_compare(&link->address, &icmp6_hdr->msg.info.neigh_sol.target) == 0)
690            return 0;
691
692        link = pico_ipv6_link_by_dev_next(f->dev, link);
693    }
694    return -1;
695
696}
697
698static int neigh_sol_validate_unspec(struct pico_frame *f)
699{
700    /* RFC4861, 7.1.1:
701     *
702     * - If the IP source address is the unspecified address, the IP
703     *   destination address is a solicited-node multicast address.
704     *
705     * - If the IP source address is the unspecified address, there is no
706     *   source link-layer address option in the message.
707     *
708     */
709
710    struct pico_ipv6_hdr *hdr = (struct pico_ipv6_hdr *)(f->net_hdr);
711    struct pico_icmp6_opt_lladdr opt = {
712        0
713    };
714    int valid_lladdr = neigh_options(f, &opt, PICO_ND_OPT_LLADDR_SRC);
715    if (!f->dev->mode && pico_ipv6_is_solnode_multicast(hdr->dst.addr, f->dev) == 0) {
716        return -1;
717    }
718
719    if (valid_lladdr) {
720        return -1;
721    }
722
723    return 0;
724}
725
726static int neigh_sol_validity_checks(struct pico_frame *f)
727{
728    /* Step 2 validation */
729    struct pico_icmp6_hdr *icmp6_hdr = NULL;
730    struct pico_ipv6_hdr *hdr = (struct pico_ipv6_hdr *)(f->net_hdr);
731    if (f->transport_len < PICO_ICMP6HDR_NEIGH_ADV_SIZE)
732        return -1;
733
734    if ((pico_ipv6_is_unspecified(hdr->src.addr)) && (neigh_sol_validate_unspec(f) < 0))
735    {
736        return -1;
737    }
738
739    icmp6_hdr = (struct pico_icmp6_hdr *)f->transport_hdr;
740    if (pico_ipv6_is_multicast(icmp6_hdr->msg.info.neigh_adv.target.addr)) {
741        return neigh_sol_mcast_validity_check(f);
742    }
743
744    return neigh_sol_unicast_validity_check(f);
745}
746
747static int router_adv_validity_checks(struct pico_frame *f)
748{
749    /* Step 2 validation */
750    if (f->transport_len < PICO_ICMP6HDR_ROUTER_ADV_SIZE)
751        return -1;
752
753    return 0;
754}
755
756static int neigh_adv_checks(struct pico_frame *f)
757{
758    /* Step 1 validation */
759    if (icmp6_initial_checks(f) < 0)
760        return -1;
761
762    return neigh_adv_validity_checks(f);
763}
764
765/*MARK*/
766#ifdef PICO_SUPPORT_6LOWPAN
767static void pico_6lp_nd_unreachable_gateway(struct pico_ip6 *a)
768{
769    struct pico_ipv6_route *route = NULL;
770    struct pico_ipv6_link *local = NULL;
771    struct pico_tree_node *node = NULL;
772    struct pico_device *dev = NULL;
773
774    /* RFC6775, 5.3:
775     *  ... HOSTS need to intelligently retransmit RSs when one of its
776     *  default routers becomes unreachable ...
777     */
778    pico_tree_foreach(node, &Device_tree) {
779        if (PICO_DEV_IS_6LOWPAN(dev) && (!dev->hostvars.routing)) {
780            /* Check if there's a gateway configured */
781            route = pico_ipv6_gateway_by_dev(dev);
782            while (route) {
783                if (0 == pico_ipv6_compare(&route->gateway, a)) {
784                    local = pico_ipv6_linklocal_get(dev);
785                    pico_6lp_nd_start_soliciting(local, route);
786                    break;
787                }
788                route = pico_ipv6_gateway_by_dev_next(dev, route);
789            }
790        }
791    }
792}
793
794static int pico_6lp_nd_validate_sol_aro(struct pico_icmp6_opt_aro *aro)
795{
796    if (aro->len != 2 || aro->status != 0)
797        return -1;
798    return 0;
799}
800
801static int pico_6lp_nd_validate_adv_aro(struct pico_device *dev, struct pico_icmp6_opt_aro *aro, uint8_t *status)
802{
803    union pico_ll_addr addr, eui;
804
805    /* RFC6775 - 5.5.2 :
806     *      - If the length field is not two, the option is silently ignored.
807     *      - If the EUI-64 field does not match the EUI-64 of the interface,
808     *        the option is silently ignored.
809     */
810    if (aro->len != 2)
811        return -1;
812
813    /* TODO: Update to abstract address, e.g. remove dependency of '.pan' */
814    eui.pan.addr._ext = aro->eui64;
815    eui.pan.mode = AM_6LOWPAN_EXT;
816    addr.pan.addr._ext = ((struct pico_6lowpan_info *)dev->eth)->addr_ext;
817    addr.pan.mode = AM_6LOWPAN_EXT;
818
819    if (dev && pico_6lowpan_lls[dev->mode].addr_cmp) {
820        if (pico_6lowpan_lls[dev->mode].addr_cmp(&addr, &eui))
821            return -1;
822    } else {
823        return -1;
824    }
825
826    *status = aro->status;
827    return 0;
828}
829
830/* Deregisters a link from all default gateways */
831static void pico_6lp_nd_deregister(struct pico_ipv6_link *l)
832{
833    struct pico_ipv6_route *gw = pico_ipv6_gateway_by_dev(l->dev);
834    while (gw) {
835        pico_icmp6_neighbor_solicitation(l->dev, &l->address, PICO_ICMP6_ND_DEREGISTER, &gw->gateway);
836        gw = pico_ipv6_gateway_by_dev_next(l->dev, gw);
837    }
838}
839
840/* Retransmits neighbors solicitations with address registration if ARO is not acknowledged */
841static void pico_6lp_nd_register_try(pico_time now, void *arg)
842{
843    struct pico_ipv6_link *l = arg;
844    struct pico_ipv6_route *gw = pico_ipv6_gateway_by_dev(l->dev);
845    IGNORE_PARAMETER(now);
846    while (gw) {
847        l->istentative = 1;
848        pico_icmp6_neighbor_solicitation(l->dev, &l->address, PICO_ICMP6_ND_DAD, &gw->gateway);
849        gw = pico_ipv6_gateway_by_dev_next(l->dev, gw);
850    }
851    pico_timer_add(l->dev->hostvars.retranstime, pico_6lp_nd_register_try, l);
852}
853
854/* Tries to register a link with one or more of its default routers */
855void pico_6lp_nd_register(struct pico_ipv6_link *link)
856{
857    /* RFC6775: When a host has configured a non-link-local IPv6 address, it registers that
858     *      address with one or more of its default routers using the Address Registration
859     *      Option (ARO) in an NS message. */
860    pico_6lp_nd_register_try(PICO_TIME_MS(), link);
861}
862
863/* Check if there are default routers configured. If not, sent a router solicitation */
864static void pico_6lp_nd_do_solicit(pico_time now, void *arg)
865{
866    struct pico_ipv6_route *gw = arg;
867    struct pico_ip6 *dst = NULL;
868    IGNORE_PARAMETER(now);
869
870    if (!pico_ipv6_gateway_by_dev(gw->link->dev) && !gw->link->dev->hostvars.routing) {
871        /* If the solicitation is to be sent unicast */
872        if (!pico_ipv6_is_unspecified(gw->gateway.addr) && gw->retrans < MAX_RTR_SOLICITATIONS)
873            dst = &gw->gateway;
874
875        /* Exponential backoff */
876        if (++gw->retrans == MAX_RTR_SOLICITATIONS) {
877            gw->backoff <<= 1;
878            if (gw->backoff >= MAX_RTR_SOLICITATION_INTERVAL)
879                gw->backoff = (pico_time)MAX_RTR_SOLICITATION_INTERVAL;
880        }
881
882        /* If router list is empty, send router solicitation */
883        pico_icmp6_router_solicitation(gw->link->dev, &gw->link->address, dst);
884
885        /* Apply exponential retransmission timer, see RFC6775 5.3 */
886        pico_timer_add(gw->backoff, pico_6lp_nd_do_solicit, gw);
887        nd_dbg("[6LP-ND]$ No default routers configured, soliciting\n");
888    } else {
889        PICO_FREE(gw);
890    }
891}
892
893/* Start transmitting repetitive router solicitations */
894int pico_6lp_nd_start_soliciting(struct pico_ipv6_link *l, struct pico_ipv6_route *gw)
895{
896    struct pico_ipv6_route *dummy = PICO_ZALLOC(sizeof(struct pico_ipv6_route));
897    struct pico_ip6 *dst = NULL;
898
899    if (dummy) {
900        if (gw) { // If the router solicitation has to be sent unicast ...
901            dst = &gw->gateway; // ... the gateway is the destination
902            memcpy(dummy->gateway.addr, gw->gateway.addr, PICO_SIZE_IP6); // and should be retrievable in the timer event
903        }
904        dummy->link = l; // the link that has to be reconfirmed as well.
905
906        /* If router list is empty, send router solicitation */
907        pico_icmp6_router_solicitation(l->dev, &l->address, dst);
908
909        if (!l->dev->hostvars.routing) {
910            dummy->retrans = 0;
911            dummy->backoff = RTR_SOLICITATION_INTERVAL;
912            if (!pico_timer_add(dummy->backoff, pico_6lp_nd_do_solicit, dummy)) {
913                PICO_FREE(dummy);
914                return -1;
915            }
916        } else {
917            PICO_FREE(dummy);
918        }
919        return 0;
920    }
921    return -1;
922}
923
924/* Validate Neighbor advertisement mesaage */
925static int pico_6lp_nd_neigh_adv_validate(struct pico_frame *f, uint8_t *status)
926{
927    struct pico_icmp6_hdr *icmp = (struct pico_icmp6_hdr *)f->transport_hdr;
928    struct pico_icmp6_opt_aro *aro = (struct pico_icmp6_opt_aro *)((uint8_t *)&icmp->msg.info.neigh_adv + sizeof(struct neigh_sol_s));
929    struct pico_ipv6_hdr *ip = (struct pico_ipv6_hdr *)f->net_hdr;
930
931    /* 6LP: Target address cannot be MCAST and the Source IP-address cannot be UNSPECIFIED or MCAST */
932    if (pico_ipv6_is_multicast(icmp->msg.info.neigh_adv.target.addr) || pico_ipv6_is_unspecified(ip->src.addr) ||
933        pico_ipv6_is_multicast(ip->src.addr))
934        return -1;
935
936    return pico_6lp_nd_validate_adv_aro(f->dev, aro, status);
937}
938
939/* Process neighbor advertisement */
940static int pico_6lp_nd_neigh_adv_process(struct pico_frame *f)
941{
942    struct pico_icmp6_hdr *icmp = (struct pico_icmp6_hdr *)f->transport_hdr;
943    struct pico_ipv6_hdr *hdr = (struct pico_ipv6_hdr *)f->net_hdr;
944    struct pico_ipv6_link *l = NULL;
945    struct pico_ip6 zero = {
946        .addr = {0}
947    };
948    uint8_t status = 0;
949
950    if (pico_6lp_nd_neigh_adv_validate(f, &status)) {
951        return -1;
952    } else {
953        l = pico_ipv6_link_get(&icmp->msg.info.neigh_adv.target);
954        if (l)
955            l->istentative = 0;
956        else
957            return -1;
958
959        /* Globally routable address has been registered @ 6LoWPAN Border Router */
960        if (1 == status) { // Duplicate address detected
961            nd_dbg("[6LP-ND]: Registering routable address failed, removing link...\n");
962            ipv6_duplicate_detected(l);
963            return -1;
964        } else if (2 == status) { // Router's NCE is full, remove router from default router list
965            pico_ipv6_route_del(zero, zero, hdr->src, 10, l);
966            pico_6lp_nd_start_soliciting(pico_ipv6_linklocal_get(l->dev), NULL);
967        } else { // Registration success
968            nd_dbg("[6LP-ND]: Registering routable address succeeded!\n");
969        }
970    }
971    return 0;
972}
973
974/* Add a new 6LoWPAN neighbor with lifetime from ARO */
975static struct pico_ipv6_neighbor *pico_nd_add_6lp(struct pico_ip6 naddr, struct pico_icmp6_opt_aro *aro, struct pico_device *dev)
976{
977    struct pico_ipv6_neighbor *new = NULL;
978
979    if ((new = pico_nd_add(&naddr, dev))) {
980        new->expire = PICO_TIME_MS() + (pico_time)(ONE_MINUTE * aro->lifetime);
981        dbg("ARO Lifetime: %d minutes\n", aro->lifetime);
982    } else {
983        return NULL;
984    }
985
986    return new;
987}
988
989/* RFC6775 ��6.5.2.  Returning Address Registration Errors */
990static int neigh_sol_dad_reply(struct pico_frame *sol, struct pico_icmp6_opt_lladdr *sllao, struct pico_icmp6_opt_aro *aro, uint8_t status)
991{
992    uint8_t sllao_len = (uint8_t)(sllao->len * 8);
993    struct pico_icmp6_hdr *icmp = NULL;
994    struct pico_frame *adv = pico_frame_copy(sol);
995    struct pico_ip6 ll = {{0xfe,0x80,0,0,0,0,0,0, 0,0,0,0,0,0,0,0}};
996    size_t len = pico_hw_addr_len(sol->dev, sllao);
997    union pico_ll_addr lladdr;
998
999    if (!adv) {
1000        return -1;
1001    } else {
1002        icmp = (struct pico_icmp6_hdr *)adv->transport_hdr;
1003
1004        /* Set the status of the Address Registration */
1005        aro->status = status;
1006        if (PICO_DEV_IS_6LOWPAN(sol->dev)) {
1007            memcpy(lladdr.pan.addr.data, aro->eui64.addr, len);
1008            lladdr.pan.mode = (len == SIZE_6LOWPAN_EXT) ? AM_6LOWPAN_EXT : AM_6LOWPAN_SHORT;
1009            if (pico_6lowpan_lls[sol->dev->mode].addr_iid)
1010                pico_6lowpan_lls[sol->dev->mode].addr_iid(ll.addr + 8, &lladdr);
1011        }
1012
1013        /* Remove the SLLAO from the frame */
1014        memmove(((uint8_t *)&icmp->msg.info.neigh_sol) + sizeof(struct neigh_sol_s), ((uint8_t *)&icmp->msg.info.neigh_sol) + sizeof(struct neigh_sol_s) + sllao_len, (size_t)(aro->len * 8));
1015        adv->transport_len = (uint16_t)(adv->transport_len - sllao_len);
1016        adv->len = (uint16_t)(adv->len - sllao_len);
1017
1018        /* I'm a router, and it's always solicited */
1019        icmp->msg.info.neigh_adv.rsor = 0xE0;
1020
1021        /* Set the ICMPv6 message type to Neighbor Advertisements */
1022        icmp->type = PICO_ICMP6_NEIGH_ADV;
1023        icmp->code = 0;
1024        icmp->crc = pico_icmp6_checksum(adv);
1025
1026        pico_ipv6_frame_push(adv, NULL, &ll, PICO_PROTO_ICMP6, 0);
1027        return 0;
1028    }
1029}
1030
1031/* RFC6775 ��6.5.1.  Checking for Duplicates */
1032static int neigh_sol_detect_dad_6lp(struct pico_frame *f)
1033{
1034    struct pico_ipv6_neighbor *n = NULL;
1035    struct pico_icmp6_opt_lladdr *sllao = NULL;
1036    struct pico_icmp6_hdr *icmp = NULL;
1037    struct pico_icmp6_opt_aro *aro = NULL;
1038    size_t len = 0;
1039
1040    icmp = (struct pico_icmp6_hdr *)f->transport_hdr;
1041    sllao = (struct pico_icmp6_opt_lladdr *)((uint8_t *)&icmp->msg.info.neigh_sol + sizeof(struct neigh_sol_s));
1042    aro = (struct pico_icmp6_opt_aro *)(((uint8_t *)&icmp->msg.info.neigh_sol) + sizeof(struct neigh_sol_s) + (sllao->len * 8));
1043
1044    /* Validate Address Registration Option */
1045    if (pico_6lp_nd_validate_sol_aro(aro))
1046        return -1;
1047
1048    /* See RFC6775 $6.5.1: Checking for duplicates */
1049    if (!(n = pico_nd_find_neighbor(&icmp->msg.info.neigh_sol.target))) {
1050        /* No dup, add neighbor to cache */
1051        if (pico_nd_add_6lp(icmp->msg.info.neigh_sol.target, aro, f->dev))
1052            neigh_sol_dad_reply(f, sllao, aro, ICMP6_ARO_SUCCES);
1053        else /* No dup, but neighbor cache is full */
1054            neigh_sol_dad_reply(f, sllao, aro, ICMP6_ARO_FULL);
1055        return 0;
1056    } else {
1057        if (!aro->lifetime) {
1058            pico_tree_delete(&NCache, n);
1059            PICO_FREE(n);
1060            neigh_sol_dad_reply(f, sllao, aro, ICMP6_ARO_SUCCES);
1061            return 0;
1062        }
1063        /* Check if hwaddr differs */
1064        len = pico_hw_addr_len(f->dev, sllao);
1065        if (memcmp(sllao->addr.data, n->hwaddr.data, len) == 0) {
1066            n->expire = PICO_TIME_MS() + (pico_time)(ONE_MINUTE * aro->lifetime);
1067            neigh_sol_dad_reply(f, sllao, aro, ICMP6_ARO_DUP);
1068        }
1069        return 0;
1070    }
1071}
1072
1073static int router_options(struct pico_frame *f, struct pico_icmp6_opt_lladdr *opt, uint8_t expected_opt)
1074{
1075    /* RFC 4861 $6.1
1076     *  The contents of any defined options that are not specified to be used
1077     *  with Router Solicitation messages MUST be ignored and the packet
1078     *  processed as normal.  The only defined option that may appear is the
1079     *  Source Link-Layer Address option.
1080     */
1081    struct pico_icmp6_hdr *icmp6_hdr = NULL;
1082    uint8_t *options = NULL;
1083    int optlen = 0;
1084    int len = 0;
1085
1086    icmp6_hdr = (struct pico_icmp6_hdr *)f->transport_hdr;
1087    optlen = f->transport_len - PICO_ICMP6HDR_ROUTER_SOL_SIZE;
1088    if (optlen)
1089        options = ((uint8_t *)&icmp6_hdr->msg.info.router_sol) + sizeof(struct router_sol_s);
1090
1091    return nd_options(options, opt, expected_opt, optlen, len);
1092}
1093
1094static int router_sol_validity_checks(struct pico_frame *f)
1095{
1096    struct pico_ipv6_hdr *hdr = (struct pico_ipv6_hdr *)(f->net_hdr);
1097    struct pico_icmp6_opt_lladdr opt = { 0 };
1098    int sllao_present = 0;
1099
1100    /* Step 2 validation */
1101    if (f->transport_len < PICO_ICMP6HDR_ROUTER_SOL_SIZE_6LP)
1102        return -1;
1103
1104    /* RFC4861, 6.1.1:
1105     * - If the IP source address is the unspecified address, there is no
1106     *   source link-layer address option in the message.
1107     */
1108    /* Check for SLLAO if the IP source address is UNSPECIFIED */
1109    sllao_present = router_options(f, &opt, PICO_ND_OPT_LLADDR_SRC);
1110    if (pico_ipv6_is_unspecified(hdr->src.addr)) {
1111        /* Frame is not valid when SLLAO is present if IP6-SRC is UNSPEC. */
1112        if (sllao_present) {
1113            return -1;
1114        }
1115    } else {
1116        /* Frame is not valid when no SLLAO if present if there's a IP6-SRC */
1117        if (sllao_present <= 0) {
1118            return -1;
1119        }
1120    }
1121
1122    return 0;
1123}
1124
1125static int router_sol_checks(struct pico_frame *f)
1126{
1127    /* Step 1 validation */
1128    if (icmp6_initial_checks(f) < 0)
1129        return -1;
1130
1131    return router_sol_validity_checks(f);
1132}
1133
1134static int router_sol_process(struct pico_frame *f)
1135{
1136    struct pico_ipv6_hdr *hdr = NULL;
1137
1138    /* Determine if i'm a 6LBR, if i'm not, can't do anything with a router solicitation */
1139    if (!f->dev->hostvars.routing)
1140        return -1;
1141
1142    nd_dbg("[6LBR]: Processing router solicitation...\n");
1143
1144    /* Router solicitation message validation */
1145    if (router_sol_checks(f) < 0)
1146        return -1;
1147
1148    /* Maybe create a tentative NCE? No, will do it later */
1149
1150    /* Send a router advertisement via unicast to requesting host */
1151    hdr = (struct pico_ipv6_hdr *)f->net_hdr;
1152    return pico_icmp6_router_advertisement(f->dev, &hdr->src);
1153}
1154
1155#endif /* PICO_SUPPORT_6LOWPAN */
1156
1157static int pico_nd_router_sol_recv(struct pico_frame *f)
1158{
1159#ifdef PICO_SUPPORT_6LOWPAN
1160    /* 6LoWPAN: reply on explicit router solicitations via unicast */
1161    if (PICO_DEV_IS_6LOWPAN(f->dev))
1162        return router_sol_process(f);
1163#endif
1164
1165    pico_ipv6_neighbor_from_unsolicited(f);
1166    /* Host only: router solicitation is discarded. */
1167    return 0;
1168}
1169static int radv_process(struct pico_frame *f)
1170{
1171    struct pico_icmp6_hdr *icmp6_hdr = NULL;
1172    uint8_t *nxtopt, *opt_start;
1173    struct pico_ipv6_link *link;
1174    uint32_t pref_lifetime = 0;
1175    struct pico_ipv6_hdr *hdr;
1176    struct pico_ip6 zero = {
1177        .addr = {0}
1178    };
1179    int optlen;
1180#ifdef PICO_SUPPORT_6LOWPAN
1181    int sllao = 0;
1182#endif
1183
1184    hdr = (struct pico_ipv6_hdr *)f->net_hdr;
1185    icmp6_hdr = (struct pico_icmp6_hdr *)f->transport_hdr;
1186    optlen = f->transport_len - PICO_ICMP6HDR_ROUTER_ADV_SIZE;
1187    opt_start = ((uint8_t *)&icmp6_hdr->msg.info.router_adv) + sizeof(struct router_adv_s);
1188    nxtopt = opt_start;
1189
1190    while (optlen > 0) {
1191        uint8_t *type = (uint8_t *)nxtopt;
1192        switch (*type) {
1193        case PICO_ND_OPT_PREFIX:
1194        {
1195            pico_time now = PICO_TIME_MS();
1196            struct pico_icmp6_opt_prefix *prefix =
1197                (struct pico_icmp6_opt_prefix *) nxtopt;
1198            /* RFC4862 5.5.3 */
1199            /* a) If the Autonomous flag is not set, silently ignore the Prefix
1200             *       Information option.
1201             */
1202            if (prefix->aac == 0)
1203                goto ignore_opt_prefix;
1204
1205            /* b) If the prefix is the link-local prefix, silently ignore the
1206             *       Prefix Information option
1207             */
1208            if (pico_ipv6_is_linklocal(prefix->prefix.addr))
1209                goto ignore_opt_prefix;
1210
1211            /* c) If the preferred lifetime is greater than the valid lifetime,
1212             *       silently ignore the Prefix Information option
1213             */
1214            pref_lifetime = long_be(prefix->pref_lifetime);
1215            if (pref_lifetime > long_be(prefix->val_lifetime))
1216                goto ignore_opt_prefix;
1217
1218#ifdef PICO_SUPPORT_6LOWPAN
1219            /* RFC6775 (6LoWPAN): Should the host erroneously receive a PIO with the L (on-link)
1220             *      flag set, then that PIO MUST be ignored.
1221             */
1222            if (PICO_DEV_IS_6LOWPAN(f->dev) && prefix->onlink)
1223                goto ignore_opt_prefix;
1224#endif
1225
1226            if (prefix->val_lifetime == 0)
1227                goto ignore_opt_prefix;
1228
1229            if (prefix->prefix_len != 64) {
1230                return -1;
1231            }
1232
1233            /* Refresh lifetime of a prefix */
1234            link = pico_ipv6_prefix_configured(&prefix->prefix);
1235            if (link) {
1236                pico_ipv6_lifetime_set(link, now + (1000 * (pico_time)(long_be(prefix->val_lifetime))));
1237                goto ignore_opt_prefix;
1238            }
1239
1240            /* Configure a an non linklocal IPv6 address */
1241            link = pico_ipv6_link_add_local(f->dev, &prefix->prefix);
1242            if (link) {
1243                pico_ipv6_lifetime_set(link, now + (1000 * (pico_time)(long_be(prefix->val_lifetime))));
1244                /* Add a default gateway to the default routers list with source of RADV */
1245                pico_ipv6_route_add(zero, zero, hdr->src, 10, link);
1246#ifdef PICO_SUPPORT_6LOWPAN
1247                if (PICO_DEV_IS_6LOWPAN(f->dev)) {
1248                    pico_6lp_nd_register(link);
1249                }
1250#endif
1251            }
1252
1253ignore_opt_prefix:
1254            optlen -= (prefix->len << 3);
1255            nxtopt += (prefix->len << 3);
1256        }
1257        break;
1258        case PICO_ND_OPT_LLADDR_SRC:
1259        {
1260            struct pico_icmp6_opt_lladdr *lladdr_src =
1261                (struct pico_icmp6_opt_lladdr *) nxtopt;
1262#ifdef PICO_SUPPORT_6LOWPAN
1263            sllao = 1; // RFC6775 (6LoWPAN): An SLLAO MUST be included in the RA.
1264#endif
1265            optlen -= (lladdr_src->len << 3);
1266            nxtopt += (lladdr_src->len << 3);
1267        }
1268        break;
1269        case PICO_ND_OPT_MTU:
1270        {
1271            struct pico_icmp6_opt_mtu *mtu =
1272                (struct pico_icmp6_opt_mtu *) nxtopt;
1273            /* Skip this */
1274            optlen -= (mtu->len << 3);
1275            nxtopt += (mtu->len << 3);
1276        }
1277        break;
1278        case PICO_ND_OPT_REDIRECT:
1279        {
1280            struct pico_icmp6_opt_redirect *redirect =
1281                (struct pico_icmp6_opt_redirect *) nxtopt;
1282            /* Skip this */
1283            optlen -= (redirect->len << 3);
1284            nxtopt += (redirect->len << 3);
1285
1286        }
1287        break;
1288        case PICO_ND_OPT_RDNSS:
1289        {
1290            struct pico_icmp6_opt_rdnss *rdnss =
1291                (struct pico_icmp6_opt_rdnss *) nxtopt;
1292            /* Skip this */
1293            optlen -= (rdnss->len << 3);
1294            nxtopt += (rdnss->len << 3);
1295        }
1296        break;
1297#ifdef PICO_SUPPORT_6LOWPAN
1298        case PICO_ND_OPT_6CO:
1299        {
1300            struct pico_icmp6_opt_6co *co = (struct pico_icmp6_opt_6co *)nxtopt;
1301#ifdef PICO_6LOWPAN_IPHC_ENABLED
1302            if (PICO_DEV_IS_6LOWPAN(f->dev)) {
1303                struct pico_ip6 prefix;
1304                memcpy(prefix.addr, (uint8_t *)&co->prefix, (size_t)(co->len - 1) << 3);
1305                ctx_update(prefix, co->id, co->clen, co->lifetime, co->c, f->dev);
1306            }
1307#endif
1308            optlen -= (co->len << 3);
1309            nxtopt += (co->len << 3);
1310        }
1311        break;
1312        case PICO_ND_OPT_ABRO:
1313        {
1314            struct pico_icmp6_opt_abro *abro = (struct pico_icmp6_opt_abro *)nxtopt;
1315            /* TODO: Process */
1316            optlen -= (abro->len << 3);
1317            nxtopt += (abro->len << 3);
1318        }
1319        break;
1320#endif
1321        default:
1322            pico_icmp6_parameter_problem(f, PICO_ICMP6_PARAMPROB_IPV6OPT,
1323                                         (uint32_t)sizeof(struct pico_ipv6_hdr) + (uint32_t)PICO_ICMP6HDR_ROUTER_ADV_SIZE + (uint32_t)(nxtopt - opt_start));
1324            return -1;
1325        }
1326    }
1327#ifdef PICO_SUPPORT_6LOWPAN
1328    if (PICO_DEV_IS_6LOWPAN(f->dev) && !sllao) {
1329        return -1;
1330    }
1331#endif
1332    if (icmp6_hdr->msg.info.router_adv.retrans_time != 0u) {
1333        f->dev->hostvars.retranstime = long_be(icmp6_hdr->msg.info.router_adv.retrans_time);
1334    }
1335
1336    return 0;
1337}
1338
1339
1340static int pico_nd_router_adv_recv(struct pico_frame *f)
1341{
1342    if (icmp6_initial_checks(f) < 0)
1343        return -1;
1344
1345    if (router_adv_validity_checks(f) < 0)
1346        return -1;
1347
1348    pico_ipv6_neighbor_from_unsolicited(f);
1349    return radv_process(f);
1350}
1351
1352static int pico_nd_neigh_sol_recv(struct pico_frame *f)
1353{
1354    if (icmp6_initial_checks(f) < 0)
1355        return -1;
1356
1357    if (neigh_sol_validity_checks(f) < 0)
1358        return -1;
1359
1360    return neigh_sol_process(f);
1361}
1362
1363static int pico_nd_neigh_adv_recv(struct pico_frame *f)
1364{
1365    struct pico_icmp6_hdr *icmp6_hdr = NULL;
1366    struct pico_ipv6_link *link = NULL;
1367
1368    icmp6_hdr = (struct pico_icmp6_hdr *)f->transport_hdr;
1369    if (neigh_adv_checks(f) < 0) {
1370        return -1;
1371    }
1372
1373    /* ETH: Target address belongs to a tentative link on this device, DaD detected a dup */
1374    link = pico_ipv6_link_istentative(&icmp6_hdr->msg.info.neigh_adv.target);
1375    if (link && !link->dev->mode)
1376        ipv6_duplicate_detected(link);
1377
1378    return neigh_adv_process(f);
1379}
1380
1381static int pico_nd_redirect_recv(struct pico_frame *f)
1382{
1383    pico_ipv6_neighbor_from_unsolicited(f);
1384    /* TODO */
1385    return 0;
1386}
1387
1388static void pico_ipv6_nd_timer_elapsed(pico_time now, struct pico_ipv6_neighbor *n)
1389{
1390    (void)now;
1391    switch(n->state) {
1392    case PICO_ND_STATE_INCOMPLETE:
1393    /* intentional fall through */
1394    case PICO_ND_STATE_PROBE:
1395        if (n->failure_count > PICO_ND_MAX_SOLICIT) {
1396            pico_ipv6_nd_unreachable(&n->address);
1397            pico_tree_delete(&NCache, n);
1398            PICO_FREE(n);
1399            return;
1400        }
1401
1402        n->expire = 0ull;
1403        pico_nd_discover(n);
1404        break;
1405
1406    case PICO_ND_STATE_REACHABLE:
1407        n->state = PICO_ND_STATE_STALE;
1408        /* dbg("IPv6_ND: neighbor expired!\n"); */
1409        return;
1410
1411    case PICO_ND_STATE_STALE:
1412        break;
1413
1414    case PICO_ND_STATE_DELAY:
1415        n->expire = 0ull;
1416        n->state = PICO_ND_STATE_PROBE;
1417        break;
1418    default:
1419        dbg("IPv6_ND: neighbor in wrong state!\n");
1420    }
1421    pico_nd_new_expire_time(n);
1422}
1423
1424static void pico_ipv6_nd_timer_callback(pico_time now, void *arg)
1425{
1426    struct pico_tree_node *index = NULL, *_tmp = NULL;
1427    struct pico_ipv6_neighbor *n;
1428
1429    (void)arg;
1430    pico_tree_foreach_safe(index, &NCache, _tmp)
1431    {
1432        n = index->keyValue;
1433        if ( now > n->expire ) {
1434            pico_ipv6_nd_timer_elapsed(now, n);
1435        }
1436    }
1437    if (!pico_timer_add(200, pico_ipv6_nd_timer_callback, NULL)) {
1438        dbg("IPV6 ND: Failed to start callback timer\n");
1439        /* TODO no idea what consequences this has */
1440    }
1441}
1442
1443#define PICO_IPV6_ND_MIN_RADV_INTERVAL  (5000)
1444#define PICO_IPV6_ND_MAX_RADV_INTERVAL (15000)
1445
1446static void pico_ipv6_nd_ra_timer_callback(pico_time now, void *arg)
1447{
1448    struct pico_tree_node *devindex = NULL;
1449    struct pico_tree_node *rindex = NULL;
1450    struct pico_device *dev;
1451    struct pico_ipv6_route *rt;
1452    struct pico_ip6 nm64 = { {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0 } };
1453    pico_time next_timer_expire = 0u;
1454
1455    (void)arg;
1456    (void)now;
1457    pico_tree_foreach(rindex, &IPV6Routes)
1458    {
1459        rt = rindex->keyValue;
1460        if (pico_ipv6_compare(&nm64, &rt->netmask) == 0) {
1461            pico_tree_foreach(devindex, &Device_tree) {
1462                dev = devindex->keyValue;
1463                /* Do not send periodic router advertisements when there aren't 2 interfaces from and to the device can route */
1464                if ((!pico_ipv6_is_linklocal(rt->dest.addr)) && dev->hostvars.routing && (rt->link)
1465                    && (dev != rt->link->dev) && !PICO_DEV_IS_6LOWPAN(dev)) {
1466                    pico_icmp6_router_advertisement(dev, &rt->dest);
1467                }
1468            }
1469        }
1470    }
1471
1472    next_timer_expire = PICO_IPV6_ND_MIN_RADV_INTERVAL + (pico_rand() % (PICO_IPV6_ND_MAX_RADV_INTERVAL - PICO_IPV6_ND_MIN_RADV_INTERVAL));
1473    if (!pico_timer_add(next_timer_expire, pico_ipv6_nd_ra_timer_callback, NULL)) {
1474        dbg("IPv6 ND: Failed to start callback timer\n");
1475        /* TODO no idea what consequences this has */
1476    }
1477}
1478
1479/* Public API */
1480
1481struct pico_eth *pico_ipv6_get_neighbor(struct pico_frame *f)
1482{
1483    struct pico_ipv6_hdr *hdr = NULL;
1484    struct pico_ipv6_link *l = NULL;
1485    if (!f)
1486        return NULL;
1487
1488    hdr = (struct pico_ipv6_hdr *)f->net_hdr;
1489    /* If we are still probing for Duplicate Address, abort now. */
1490    if (pico_ipv6_link_istentative(&hdr->src))
1491        return NULL;
1492
1493    /* address belongs to ourselves? */
1494    l = pico_ipv6_link_get(&hdr->dst);
1495    if (l && !l->dev->mode)
1496        return &l->dev->eth->mac;
1497    else if (l && PICO_DEV_IS_6LOWPAN(l->dev))
1498        return (struct pico_eth *)l->dev->eth;
1499
1500    return pico_nd_get(&hdr->dst, f->dev);
1501}
1502
1503void pico_ipv6_nd_postpone(struct pico_frame *f)
1504{
1505    int i;
1506    static int last_enq = -1;
1507    for (i = 0; i < PICO_ND_MAX_FRAMES_QUEUED; i++)
1508    {
1509        if (!frames_queued_v6[i]) {
1510            frames_queued_v6[i] = f;
1511            last_enq = i;
1512            return;
1513        }
1514    }
1515    /* Overwrite the oldest frame in the buffer */
1516    if (++last_enq >= PICO_ND_MAX_FRAMES_QUEUED) {
1517        last_enq = 0;
1518    }
1519
1520    if (frames_queued_v6[last_enq])
1521        pico_frame_discard(frames_queued_v6[last_enq]);
1522
1523    frames_queued_v6[last_enq] = f;
1524}
1525
1526
1527int pico_ipv6_nd_recv(struct pico_frame *f)
1528{
1529
1530    struct pico_icmp6_hdr *hdr = (struct pico_icmp6_hdr *)f->transport_hdr;
1531    int ret = -1;
1532    switch(hdr->type) {
1533    case PICO_ICMP6_ROUTER_SOL:
1534        nd_dbg("ICMP6: received ROUTER SOL\n");
1535        ret = pico_nd_router_sol_recv(f);
1536        break;
1537
1538    case PICO_ICMP6_ROUTER_ADV:
1539        nd_dbg("ICMP6: received ROUTER ADV\n");
1540        ret = pico_nd_router_adv_recv(f);
1541        break;
1542
1543    case PICO_ICMP6_NEIGH_SOL:
1544        nd_dbg("ICMP6: received NEIGH SOL\n");
1545        ret = pico_nd_neigh_sol_recv(f);
1546        break;
1547
1548    case PICO_ICMP6_NEIGH_ADV:
1549        nd_dbg("ICMP6: received NEIGH ADV\n");
1550        ret = pico_nd_neigh_adv_recv(f);
1551        break;
1552
1553    case PICO_ICMP6_REDIRECT:
1554        ret = pico_nd_redirect_recv(f);
1555        break;
1556    }
1557    pico_frame_discard(f);
1558    return ret;
1559}
1560
1561void pico_ipv6_nd_init(void)
1562{
1563    uint32_t timer_cb = 0, ra_timer_cb = 0;
1564
1565    timer_cb = pico_timer_add(200, pico_ipv6_nd_timer_callback, NULL);
1566    if (!timer_cb) {
1567        nd_dbg("IPv6 ND: Failed to start callback timer\n");
1568        return;
1569    }
1570
1571    ra_timer_cb = pico_timer_add(200, pico_ipv6_nd_ra_timer_callback, NULL);
1572    if (!ra_timer_cb) {
1573        nd_dbg("IPv6 ND: Failed to start RA callback timer\n");
1574        pico_timer_cancel(timer_cb);
1575        return;
1576    }
1577
1578    if (!pico_timer_add(1000, pico_ipv6_check_lifetime_expired, NULL)) {
1579        nd_dbg("IPv6 ND: Failed to start check_lifetime timer\n");
1580        pico_timer_cancel(timer_cb);
1581        pico_timer_cancel(ra_timer_cb);
1582        return;
1583    }
1584}
1585
1586#endif
1587