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