* Neighbor advertisement input handling. * * Based on RFC 2461 * Based on RFC 2462 (duplicate address detection) * * the following items are not implemented yet: * - proxy advertisement delay rule (RFC2461 7.2.8, last paragraph, SHOULD) * - anycast advertisement delay rule (RFC2461 7.2.7, SHOULD) */
| 612 | * - anycast advertisement delay rule (RFC2461 7.2.7, SHOULD) |
| 613 | */ |
| 614 | void |
| 615 | nd6_na_input(struct mbuf *m, int off, int icmp6len) |
| 616 | { |
| 617 | struct ifnet *ifp; |
| 618 | struct ip6_hdr *ip6; |
| 619 | struct ifaddr *ifa; |
| 620 | struct llentry *ln; |
| 621 | struct mbuf *chain; |
| 622 | struct nd_neighbor_advert *nd_na; |
| 623 | struct in6_addr daddr6, taddr6; |
| 624 | struct sockaddr_in6 sin6; |
| 625 | union nd_opts ndopts; |
| 626 | u_char linkhdr[LLE_MAX_LINKHDR]; |
| 627 | char ip6bufs[INET6_ADDRSTRLEN], ip6bufd[INET6_ADDRSTRLEN]; |
| 628 | char *lladdr; |
| 629 | size_t linkhdrsize; |
| 630 | int flags, is_override, is_router, is_solicited; |
| 631 | int lladdr_off, lladdrlen, checklink; |
| 632 | |
| 633 | NET_EPOCH_ASSERT(); |
| 634 | |
| 635 | chain = NULL; |
| 636 | ln = NULL; |
| 637 | checklink = 0; |
| 638 | |
| 639 | /* RFC 6980: Nodes MUST silently ignore fragments */ |
| 640 | if(m->m_flags & M_FRAGMENTED) |
| 641 | goto freeit; |
| 642 | |
| 643 | ifp = m->m_pkthdr.rcvif; |
| 644 | ip6 = mtod(m, struct ip6_hdr *); |
| 645 | if (__predict_false(ip6->ip6_hlim != 255)) { |
| 646 | ICMP6STAT_INC(icp6s_invlhlim); |
| 647 | nd6log((LOG_ERR, |
| 648 | "nd6_na_input: invalid hlim (%d) from %s to %s on %s\n", |
| 649 | ip6->ip6_hlim, ip6_sprintf(ip6bufs, &ip6->ip6_src), |
| 650 | ip6_sprintf(ip6bufd, &ip6->ip6_dst), if_name(ifp))); |
| 651 | goto bad; |
| 652 | } |
| 653 | |
| 654 | if (m->m_len < off + icmp6len) { |
| 655 | m = m_pullup(m, off + icmp6len); |
| 656 | if (m == NULL) { |
| 657 | IP6STAT_INC(ip6s_exthdrtoolong); |
| 658 | return; |
| 659 | } |
| 660 | } |
| 661 | ip6 = mtod(m, struct ip6_hdr *); |
| 662 | nd_na = (struct nd_neighbor_advert *)((caddr_t)ip6 + off); |
| 663 | |
| 664 | flags = nd_na->nd_na_flags_reserved; |
| 665 | is_router = ((flags & ND_NA_FLAG_ROUTER) != 0); |
| 666 | is_solicited = ((flags & ND_NA_FLAG_SOLICITED) != 0); |
| 667 | is_override = ((flags & ND_NA_FLAG_OVERRIDE) != 0); |
| 668 | |
| 669 | taddr6 = nd_na->nd_na_target; |
| 670 | if (in6_setscope(&taddr6, ifp, NULL)) |
| 671 | goto bad; /* XXX: impossible */ |
no test coverage detected