diff options
Diffstat (limited to 'net/ipv6/ndisc.c')
-rw-r--r-- | net/ipv6/ndisc.c | 435 |
1 files changed, 183 insertions, 252 deletions
diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index 121f31c283f8..d8b36451bada 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c | |||
@@ -319,6 +319,8 @@ int ndisc_mc_map(struct in6_addr *addr, char *buf, struct net_device *dev, int d | |||
319 | return -EINVAL; | 319 | return -EINVAL; |
320 | } | 320 | } |
321 | 321 | ||
322 | EXPORT_SYMBOL(ndisc_mc_map); | ||
323 | |||
322 | static u32 ndisc_hash(const void *pkey, const struct net_device *dev) | 324 | static u32 ndisc_hash(const void *pkey, const struct net_device *dev) |
323 | { | 325 | { |
324 | const u32 *p32 = pkey; | 326 | const u32 *p32 = pkey; |
@@ -425,36 +427,23 @@ static inline void ndisc_flow_init(struct flowi *fl, u8 type, | |||
425 | security_sk_classify_flow(ndisc_socket->sk, fl); | 427 | security_sk_classify_flow(ndisc_socket->sk, fl); |
426 | } | 428 | } |
427 | 429 | ||
428 | static void ndisc_send_na(struct net_device *dev, struct neighbour *neigh, | 430 | static void __ndisc_send(struct net_device *dev, |
429 | struct in6_addr *daddr, struct in6_addr *solicited_addr, | 431 | struct neighbour *neigh, |
430 | int router, int solicited, int override, int inc_opt) | 432 | struct in6_addr *daddr, struct in6_addr *saddr, |
433 | struct icmp6hdr *icmp6h, struct in6_addr *target, | ||
434 | int llinfo, int icmp6_mib_outnd) | ||
431 | { | 435 | { |
432 | struct in6_addr tmpaddr; | ||
433 | struct inet6_ifaddr *ifp; | ||
434 | struct inet6_dev *idev; | ||
435 | struct flowi fl; | 436 | struct flowi fl; |
436 | struct dst_entry* dst; | 437 | struct dst_entry *dst; |
437 | struct sock *sk = ndisc_socket->sk; | 438 | struct sock *sk = ndisc_socket->sk; |
438 | struct in6_addr *src_addr; | ||
439 | struct nd_msg *msg; | ||
440 | int len; | ||
441 | struct sk_buff *skb; | 439 | struct sk_buff *skb; |
440 | struct icmp6hdr *hdr; | ||
441 | struct inet6_dev *idev; | ||
442 | int len; | ||
442 | int err; | 443 | int err; |
444 | u8 *opt; | ||
443 | 445 | ||
444 | len = sizeof(struct icmp6hdr) + sizeof(struct in6_addr); | 446 | ndisc_flow_init(&fl, icmp6h->icmp6_type, saddr, daddr, |
445 | |||
446 | /* for anycast or proxy, solicited_addr != src_addr */ | ||
447 | ifp = ipv6_get_ifaddr(solicited_addr, dev, 1); | ||
448 | if (ifp) { | ||
449 | src_addr = solicited_addr; | ||
450 | in6_ifa_put(ifp); | ||
451 | } else { | ||
452 | if (ipv6_dev_get_saddr(dev, daddr, &tmpaddr)) | ||
453 | return; | ||
454 | src_addr = &tmpaddr; | ||
455 | } | ||
456 | |||
457 | ndisc_flow_init(&fl, NDISC_NEIGHBOUR_ADVERTISEMENT, src_addr, daddr, | ||
458 | dev->ifindex); | 447 | dev->ifindex); |
459 | 448 | ||
460 | dst = ndisc_dst_alloc(dev, neigh, daddr, ip6_output); | 449 | dst = ndisc_dst_alloc(dev, neigh, daddr, ip6_output); |
@@ -465,60 +454,57 @@ static void ndisc_send_na(struct net_device *dev, struct neighbour *neigh, | |||
465 | if (err < 0) | 454 | if (err < 0) |
466 | return; | 455 | return; |
467 | 456 | ||
468 | if (inc_opt) { | 457 | if (!dev->addr_len) |
469 | if (dev->addr_len) | 458 | llinfo = 0; |
470 | len += ndisc_opt_addr_space(dev); | 459 | |
471 | else | 460 | len = sizeof(struct icmp6hdr) + (target ? sizeof(*target) : 0); |
472 | inc_opt = 0; | 461 | if (llinfo) |
473 | } | 462 | len += ndisc_opt_addr_space(dev); |
474 | 463 | ||
475 | skb = sock_alloc_send_skb(sk, | 464 | skb = sock_alloc_send_skb(sk, |
476 | (MAX_HEADER + sizeof(struct ipv6hdr) + | 465 | (MAX_HEADER + sizeof(struct ipv6hdr) + |
477 | len + LL_RESERVED_SPACE(dev)), | 466 | len + LL_RESERVED_SPACE(dev)), |
478 | 1, &err); | 467 | 1, &err); |
479 | 468 | if (!skb) { | |
480 | if (skb == NULL) { | ||
481 | ND_PRINTK0(KERN_ERR | 469 | ND_PRINTK0(KERN_ERR |
482 | "ICMPv6 NA: %s() failed to allocate an skb.\n", | 470 | "ICMPv6 ND: %s() failed to allocate an skb.\n", |
483 | __FUNCTION__); | 471 | __FUNCTION__); |
484 | dst_release(dst); | 472 | dst_release(dst); |
485 | return; | 473 | return; |
486 | } | 474 | } |
487 | 475 | ||
488 | skb_reserve(skb, LL_RESERVED_SPACE(dev)); | 476 | skb_reserve(skb, LL_RESERVED_SPACE(dev)); |
489 | ip6_nd_hdr(sk, skb, dev, src_addr, daddr, IPPROTO_ICMPV6, len); | 477 | ip6_nd_hdr(sk, skb, dev, saddr, daddr, IPPROTO_ICMPV6, len); |
490 | |||
491 | msg = (struct nd_msg *)skb_put(skb, len); | ||
492 | skb->h.raw = (unsigned char*)msg; | ||
493 | 478 | ||
494 | msg->icmph.icmp6_type = NDISC_NEIGHBOUR_ADVERTISEMENT; | 479 | skb->transport_header = skb->tail; |
495 | msg->icmph.icmp6_code = 0; | 480 | skb_put(skb, len); |
496 | msg->icmph.icmp6_cksum = 0; | ||
497 | 481 | ||
498 | msg->icmph.icmp6_unused = 0; | 482 | hdr = (struct icmp6hdr *)skb_transport_header(skb); |
499 | msg->icmph.icmp6_router = router; | 483 | memcpy(hdr, icmp6h, sizeof(*hdr)); |
500 | msg->icmph.icmp6_solicited = solicited; | ||
501 | msg->icmph.icmp6_override = override; | ||
502 | 484 | ||
503 | /* Set the target address. */ | 485 | opt = skb_transport_header(skb) + sizeof(struct icmp6hdr); |
504 | ipv6_addr_copy(&msg->target, solicited_addr); | 486 | if (target) { |
487 | ipv6_addr_copy((struct in6_addr *)opt, target); | ||
488 | opt += sizeof(*target); | ||
489 | } | ||
505 | 490 | ||
506 | if (inc_opt) | 491 | if (llinfo) |
507 | ndisc_fill_addr_option(msg->opt, ND_OPT_TARGET_LL_ADDR, dev->dev_addr, | 492 | ndisc_fill_addr_option(opt, llinfo, dev->dev_addr, |
508 | dev->addr_len, dev->type); | 493 | dev->addr_len, dev->type); |
509 | 494 | ||
510 | /* checksum */ | 495 | hdr->icmp6_cksum = csum_ipv6_magic(saddr, daddr, len, |
511 | msg->icmph.icmp6_cksum = csum_ipv6_magic(src_addr, daddr, len, | 496 | IPPROTO_ICMPV6, |
512 | IPPROTO_ICMPV6, | 497 | csum_partial((__u8 *) hdr, |
513 | csum_partial((__u8 *) msg, | 498 | len, 0)); |
514 | len, 0)); | ||
515 | 499 | ||
516 | skb->dst = dst; | 500 | skb->dst = dst; |
501 | |||
517 | idev = in6_dev_get(dst->dev); | 502 | idev = in6_dev_get(dst->dev); |
518 | IP6_INC_STATS(idev, IPSTATS_MIB_OUTREQUESTS); | 503 | IP6_INC_STATS(idev, IPSTATS_MIB_OUTREQUESTS); |
504 | |||
519 | err = NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, skb, NULL, dst->dev, dst_output); | 505 | err = NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, skb, NULL, dst->dev, dst_output); |
520 | if (!err) { | 506 | if (!err) { |
521 | ICMP6_INC_STATS(idev, ICMP6_MIB_OUTNEIGHBORADVERTISEMENTS); | 507 | ICMP6_INC_STATS(idev, icmp6_mib_outnd); |
522 | ICMP6_INC_STATS(idev, ICMP6_MIB_OUTMSGS); | 508 | ICMP6_INC_STATS(idev, ICMP6_MIB_OUTMSGS); |
523 | } | 509 | } |
524 | 510 | ||
@@ -526,165 +512,95 @@ static void ndisc_send_na(struct net_device *dev, struct neighbour *neigh, | |||
526 | in6_dev_put(idev); | 512 | in6_dev_put(idev); |
527 | } | 513 | } |
528 | 514 | ||
515 | static void ndisc_send_na(struct net_device *dev, struct neighbour *neigh, | ||
516 | struct in6_addr *daddr, struct in6_addr *solicited_addr, | ||
517 | int router, int solicited, int override, int inc_opt) | ||
518 | { | ||
519 | struct in6_addr tmpaddr; | ||
520 | struct inet6_ifaddr *ifp; | ||
521 | struct in6_addr *src_addr; | ||
522 | struct icmp6hdr icmp6h = { | ||
523 | .icmp6_type = NDISC_NEIGHBOUR_ADVERTISEMENT, | ||
524 | }; | ||
525 | |||
526 | /* for anycast or proxy, solicited_addr != src_addr */ | ||
527 | ifp = ipv6_get_ifaddr(solicited_addr, dev, 1); | ||
528 | if (ifp) { | ||
529 | src_addr = solicited_addr; | ||
530 | if (ifp->flags & IFA_F_OPTIMISTIC) | ||
531 | override = 0; | ||
532 | in6_ifa_put(ifp); | ||
533 | } else { | ||
534 | if (ipv6_dev_get_saddr(dev, daddr, &tmpaddr)) | ||
535 | return; | ||
536 | src_addr = &tmpaddr; | ||
537 | } | ||
538 | |||
539 | icmp6h.icmp6_router = router; | ||
540 | icmp6h.icmp6_solicited = solicited; | ||
541 | icmp6h.icmp6_override = override; | ||
542 | |||
543 | __ndisc_send(dev, neigh, daddr, src_addr, | ||
544 | &icmp6h, solicited_addr, | ||
545 | inc_opt ? ND_OPT_TARGET_LL_ADDR : 0, | ||
546 | ICMP6_MIB_OUTNEIGHBORADVERTISEMENTS); | ||
547 | } | ||
548 | |||
529 | void ndisc_send_ns(struct net_device *dev, struct neighbour *neigh, | 549 | void ndisc_send_ns(struct net_device *dev, struct neighbour *neigh, |
530 | struct in6_addr *solicit, | 550 | struct in6_addr *solicit, |
531 | struct in6_addr *daddr, struct in6_addr *saddr) | 551 | struct in6_addr *daddr, struct in6_addr *saddr) |
532 | { | 552 | { |
533 | struct flowi fl; | ||
534 | struct dst_entry* dst; | ||
535 | struct inet6_dev *idev; | ||
536 | struct sock *sk = ndisc_socket->sk; | ||
537 | struct sk_buff *skb; | ||
538 | struct nd_msg *msg; | ||
539 | struct in6_addr addr_buf; | 553 | struct in6_addr addr_buf; |
540 | int len; | 554 | struct icmp6hdr icmp6h = { |
541 | int err; | 555 | .icmp6_type = NDISC_NEIGHBOUR_SOLICITATION, |
542 | int send_llinfo; | 556 | }; |
543 | 557 | ||
544 | if (saddr == NULL) { | 558 | if (saddr == NULL) { |
545 | if (ipv6_get_lladdr(dev, &addr_buf)) | 559 | if (ipv6_get_lladdr(dev, &addr_buf, |
560 | (IFA_F_TENTATIVE|IFA_F_OPTIMISTIC))) | ||
546 | return; | 561 | return; |
547 | saddr = &addr_buf; | 562 | saddr = &addr_buf; |
548 | } | 563 | } |
549 | 564 | ||
550 | ndisc_flow_init(&fl, NDISC_NEIGHBOUR_SOLICITATION, saddr, daddr, | 565 | __ndisc_send(dev, neigh, daddr, saddr, |
551 | dev->ifindex); | 566 | &icmp6h, solicit, |
552 | 567 | !ipv6_addr_any(saddr) ? ND_OPT_SOURCE_LL_ADDR : 0, | |
553 | dst = ndisc_dst_alloc(dev, neigh, daddr, ip6_output); | 568 | ICMP6_MIB_OUTNEIGHBORSOLICITS); |
554 | if (!dst) | ||
555 | return; | ||
556 | |||
557 | err = xfrm_lookup(&dst, &fl, NULL, 0); | ||
558 | if (err < 0) | ||
559 | return; | ||
560 | |||
561 | len = sizeof(struct icmp6hdr) + sizeof(struct in6_addr); | ||
562 | send_llinfo = dev->addr_len && !ipv6_addr_any(saddr); | ||
563 | if (send_llinfo) | ||
564 | len += ndisc_opt_addr_space(dev); | ||
565 | |||
566 | skb = sock_alloc_send_skb(sk, | ||
567 | (MAX_HEADER + sizeof(struct ipv6hdr) + | ||
568 | len + LL_RESERVED_SPACE(dev)), | ||
569 | 1, &err); | ||
570 | if (skb == NULL) { | ||
571 | ND_PRINTK0(KERN_ERR | ||
572 | "ICMPv6 NA: %s() failed to allocate an skb.\n", | ||
573 | __FUNCTION__); | ||
574 | dst_release(dst); | ||
575 | return; | ||
576 | } | ||
577 | |||
578 | skb_reserve(skb, LL_RESERVED_SPACE(dev)); | ||
579 | ip6_nd_hdr(sk, skb, dev, saddr, daddr, IPPROTO_ICMPV6, len); | ||
580 | |||
581 | msg = (struct nd_msg *)skb_put(skb, len); | ||
582 | skb->h.raw = (unsigned char*)msg; | ||
583 | msg->icmph.icmp6_type = NDISC_NEIGHBOUR_SOLICITATION; | ||
584 | msg->icmph.icmp6_code = 0; | ||
585 | msg->icmph.icmp6_cksum = 0; | ||
586 | msg->icmph.icmp6_unused = 0; | ||
587 | |||
588 | /* Set the target address. */ | ||
589 | ipv6_addr_copy(&msg->target, solicit); | ||
590 | |||
591 | if (send_llinfo) | ||
592 | ndisc_fill_addr_option(msg->opt, ND_OPT_SOURCE_LL_ADDR, dev->dev_addr, | ||
593 | dev->addr_len, dev->type); | ||
594 | |||
595 | /* checksum */ | ||
596 | msg->icmph.icmp6_cksum = csum_ipv6_magic(&skb->nh.ipv6h->saddr, | ||
597 | daddr, len, | ||
598 | IPPROTO_ICMPV6, | ||
599 | csum_partial((__u8 *) msg, | ||
600 | len, 0)); | ||
601 | /* send it! */ | ||
602 | skb->dst = dst; | ||
603 | idev = in6_dev_get(dst->dev); | ||
604 | IP6_INC_STATS(idev, IPSTATS_MIB_OUTREQUESTS); | ||
605 | err = NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, skb, NULL, dst->dev, dst_output); | ||
606 | if (!err) { | ||
607 | ICMP6_INC_STATS(idev, ICMP6_MIB_OUTNEIGHBORSOLICITS); | ||
608 | ICMP6_INC_STATS(idev, ICMP6_MIB_OUTMSGS); | ||
609 | } | ||
610 | |||
611 | if (likely(idev != NULL)) | ||
612 | in6_dev_put(idev); | ||
613 | } | 569 | } |
614 | 570 | ||
615 | void ndisc_send_rs(struct net_device *dev, struct in6_addr *saddr, | 571 | void ndisc_send_rs(struct net_device *dev, struct in6_addr *saddr, |
616 | struct in6_addr *daddr) | 572 | struct in6_addr *daddr) |
617 | { | 573 | { |
618 | struct flowi fl; | 574 | struct icmp6hdr icmp6h = { |
619 | struct dst_entry* dst; | 575 | .icmp6_type = NDISC_ROUTER_SOLICITATION, |
620 | struct inet6_dev *idev; | 576 | }; |
621 | struct sock *sk = ndisc_socket->sk; | 577 | int send_sllao = dev->addr_len; |
622 | struct sk_buff *skb; | ||
623 | struct icmp6hdr *hdr; | ||
624 | __u8 * opt; | ||
625 | int len; | ||
626 | int err; | ||
627 | |||
628 | ndisc_flow_init(&fl, NDISC_ROUTER_SOLICITATION, saddr, daddr, | ||
629 | dev->ifindex); | ||
630 | |||
631 | dst = ndisc_dst_alloc(dev, NULL, daddr, ip6_output); | ||
632 | if (!dst) | ||
633 | return; | ||
634 | |||
635 | err = xfrm_lookup(&dst, &fl, NULL, 0); | ||
636 | if (err < 0) | ||
637 | return; | ||
638 | |||
639 | len = sizeof(struct icmp6hdr); | ||
640 | if (dev->addr_len) | ||
641 | len += ndisc_opt_addr_space(dev); | ||
642 | |||
643 | skb = sock_alloc_send_skb(sk, | ||
644 | (MAX_HEADER + sizeof(struct ipv6hdr) + | ||
645 | len + LL_RESERVED_SPACE(dev)), | ||
646 | 1, &err); | ||
647 | if (skb == NULL) { | ||
648 | ND_PRINTK0(KERN_ERR | ||
649 | "ICMPv6 RS: %s() failed to allocate an skb.\n", | ||
650 | __FUNCTION__); | ||
651 | dst_release(dst); | ||
652 | return; | ||
653 | } | ||
654 | |||
655 | skb_reserve(skb, LL_RESERVED_SPACE(dev)); | ||
656 | ip6_nd_hdr(sk, skb, dev, saddr, daddr, IPPROTO_ICMPV6, len); | ||
657 | |||
658 | hdr = (struct icmp6hdr *)skb_put(skb, len); | ||
659 | skb->h.raw = (unsigned char*)hdr; | ||
660 | hdr->icmp6_type = NDISC_ROUTER_SOLICITATION; | ||
661 | hdr->icmp6_code = 0; | ||
662 | hdr->icmp6_cksum = 0; | ||
663 | hdr->icmp6_unused = 0; | ||
664 | |||
665 | opt = (u8*) (hdr + 1); | ||
666 | |||
667 | if (dev->addr_len) | ||
668 | ndisc_fill_addr_option(opt, ND_OPT_SOURCE_LL_ADDR, dev->dev_addr, | ||
669 | dev->addr_len, dev->type); | ||
670 | |||
671 | /* checksum */ | ||
672 | hdr->icmp6_cksum = csum_ipv6_magic(&skb->nh.ipv6h->saddr, daddr, len, | ||
673 | IPPROTO_ICMPV6, | ||
674 | csum_partial((__u8 *) hdr, len, 0)); | ||
675 | 578 | ||
676 | /* send it! */ | 579 | #ifdef CONFIG_IPV6_OPTIMISTIC_DAD |
677 | skb->dst = dst; | 580 | /* |
678 | idev = in6_dev_get(dst->dev); | 581 | * According to section 2.2 of RFC 4429, we must not |
679 | IP6_INC_STATS(idev, IPSTATS_MIB_OUTREQUESTS); | 582 | * send router solicitations with a sllao from |
680 | err = NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, skb, NULL, dst->dev, dst_output); | 583 | * optimistic addresses, but we may send the solicitation |
681 | if (!err) { | 584 | * if we don't include the sllao. So here we check |
682 | ICMP6_INC_STATS(idev, ICMP6_MIB_OUTROUTERSOLICITS); | 585 | * if our address is optimistic, and if so, we |
683 | ICMP6_INC_STATS(idev, ICMP6_MIB_OUTMSGS); | 586 | * supress the inclusion of the sllao. |
587 | */ | ||
588 | if (send_sllao) { | ||
589 | struct inet6_ifaddr *ifp = ipv6_get_ifaddr(saddr, dev, 1); | ||
590 | if (ifp) { | ||
591 | if (ifp->flags & IFA_F_OPTIMISTIC) { | ||
592 | send_sllao = 0; | ||
593 | } | ||
594 | in6_ifa_put(ifp); | ||
595 | } else { | ||
596 | send_sllao = 0; | ||
597 | } | ||
684 | } | 598 | } |
685 | 599 | #endif | |
686 | if (likely(idev != NULL)) | 600 | __ndisc_send(dev, NULL, daddr, saddr, |
687 | in6_dev_put(idev); | 601 | &icmp6h, NULL, |
602 | send_sllao ? ND_OPT_SOURCE_LL_ADDR : 0, | ||
603 | ICMP6_MIB_OUTROUTERSOLICITS); | ||
688 | } | 604 | } |
689 | 605 | ||
690 | 606 | ||
@@ -708,8 +624,8 @@ static void ndisc_solicit(struct neighbour *neigh, struct sk_buff *skb) | |||
708 | struct in6_addr *target = (struct in6_addr *)&neigh->primary_key; | 624 | struct in6_addr *target = (struct in6_addr *)&neigh->primary_key; |
709 | int probes = atomic_read(&neigh->probes); | 625 | int probes = atomic_read(&neigh->probes); |
710 | 626 | ||
711 | if (skb && ipv6_chk_addr(&skb->nh.ipv6h->saddr, dev, 1)) | 627 | if (skb && ipv6_chk_addr(&ipv6_hdr(skb)->saddr, dev, 1)) |
712 | saddr = &skb->nh.ipv6h->saddr; | 628 | saddr = &ipv6_hdr(skb)->saddr; |
713 | 629 | ||
714 | if ((probes -= neigh->parms->ucast_probes) < 0) { | 630 | if ((probes -= neigh->parms->ucast_probes) < 0) { |
715 | if (!(neigh->nud_state & NUD_VALID)) { | 631 | if (!(neigh->nud_state & NUD_VALID)) { |
@@ -732,11 +648,12 @@ static void ndisc_solicit(struct neighbour *neigh, struct sk_buff *skb) | |||
732 | 648 | ||
733 | static void ndisc_recv_ns(struct sk_buff *skb) | 649 | static void ndisc_recv_ns(struct sk_buff *skb) |
734 | { | 650 | { |
735 | struct nd_msg *msg = (struct nd_msg *)skb->h.raw; | 651 | struct nd_msg *msg = (struct nd_msg *)skb_transport_header(skb); |
736 | struct in6_addr *saddr = &skb->nh.ipv6h->saddr; | 652 | struct in6_addr *saddr = &ipv6_hdr(skb)->saddr; |
737 | struct in6_addr *daddr = &skb->nh.ipv6h->daddr; | 653 | struct in6_addr *daddr = &ipv6_hdr(skb)->daddr; |
738 | u8 *lladdr = NULL; | 654 | u8 *lladdr = NULL; |
739 | u32 ndoptlen = skb->tail - msg->opt; | 655 | u32 ndoptlen = skb->tail - (skb->transport_header + |
656 | offsetof(struct nd_msg, opt)); | ||
740 | struct ndisc_options ndopts; | 657 | struct ndisc_options ndopts; |
741 | struct net_device *dev = skb->dev; | 658 | struct net_device *dev = skb->dev; |
742 | struct inet6_ifaddr *ifp; | 659 | struct inet6_ifaddr *ifp; |
@@ -796,28 +713,40 @@ static void ndisc_recv_ns(struct sk_buff *skb) | |||
796 | inc = ipv6_addr_is_multicast(daddr); | 713 | inc = ipv6_addr_is_multicast(daddr); |
797 | 714 | ||
798 | if ((ifp = ipv6_get_ifaddr(&msg->target, dev, 1)) != NULL) { | 715 | if ((ifp = ipv6_get_ifaddr(&msg->target, dev, 1)) != NULL) { |
799 | if (ifp->flags & IFA_F_TENTATIVE) { | 716 | |
800 | /* Address is tentative. If the source | 717 | if (ifp->flags & (IFA_F_TENTATIVE|IFA_F_OPTIMISTIC)) { |
801 | is unspecified address, it is someone | 718 | if (dad) { |
802 | does DAD, otherwise we ignore solicitations | 719 | if (dev->type == ARPHRD_IEEE802_TR) { |
803 | until DAD timer expires. | 720 | const unsigned char *sadr; |
804 | */ | 721 | sadr = skb_mac_header(skb); |
805 | if (!dad) | 722 | if (((sadr[8] ^ dev->dev_addr[0]) & 0x7f) == 0 && |
723 | sadr[9] == dev->dev_addr[1] && | ||
724 | sadr[10] == dev->dev_addr[2] && | ||
725 | sadr[11] == dev->dev_addr[3] && | ||
726 | sadr[12] == dev->dev_addr[4] && | ||
727 | sadr[13] == dev->dev_addr[5]) { | ||
728 | /* looped-back to us */ | ||
729 | goto out; | ||
730 | } | ||
731 | } | ||
732 | |||
733 | /* | ||
734 | * We are colliding with another node | ||
735 | * who is doing DAD | ||
736 | * so fail our DAD process | ||
737 | */ | ||
738 | addrconf_dad_failure(ifp); | ||
806 | goto out; | 739 | goto out; |
807 | if (dev->type == ARPHRD_IEEE802_TR) { | 740 | } else { |
808 | unsigned char *sadr = skb->mac.raw; | 741 | /* |
809 | if (((sadr[8] ^ dev->dev_addr[0]) & 0x7f) == 0 && | 742 | * This is not a dad solicitation. |
810 | sadr[9] == dev->dev_addr[1] && | 743 | * If we are an optimistic node, |
811 | sadr[10] == dev->dev_addr[2] && | 744 | * we should respond. |
812 | sadr[11] == dev->dev_addr[3] && | 745 | * Otherwise, we should ignore it. |
813 | sadr[12] == dev->dev_addr[4] && | 746 | */ |
814 | sadr[13] == dev->dev_addr[5]) { | 747 | if (!(ifp->flags & IFA_F_OPTIMISTIC)) |
815 | /* looped-back to us */ | ||
816 | goto out; | 748 | goto out; |
817 | } | ||
818 | } | 749 | } |
819 | addrconf_dad_failure(ifp); | ||
820 | return; | ||
821 | } | 750 | } |
822 | 751 | ||
823 | idev = ifp->idev; | 752 | idev = ifp->idev; |
@@ -898,11 +827,12 @@ out: | |||
898 | 827 | ||
899 | static void ndisc_recv_na(struct sk_buff *skb) | 828 | static void ndisc_recv_na(struct sk_buff *skb) |
900 | { | 829 | { |
901 | struct nd_msg *msg = (struct nd_msg *)skb->h.raw; | 830 | struct nd_msg *msg = (struct nd_msg *)skb_transport_header(skb); |
902 | struct in6_addr *saddr = &skb->nh.ipv6h->saddr; | 831 | struct in6_addr *saddr = &ipv6_hdr(skb)->saddr; |
903 | struct in6_addr *daddr = &skb->nh.ipv6h->daddr; | 832 | struct in6_addr *daddr = &ipv6_hdr(skb)->daddr; |
904 | u8 *lladdr = NULL; | 833 | u8 *lladdr = NULL; |
905 | u32 ndoptlen = skb->tail - msg->opt; | 834 | u32 ndoptlen = skb->tail - (skb->transport_header + |
835 | offsetof(struct nd_msg, opt)); | ||
906 | struct ndisc_options ndopts; | 836 | struct ndisc_options ndopts; |
907 | struct net_device *dev = skb->dev; | 837 | struct net_device *dev = skb->dev; |
908 | struct inet6_ifaddr *ifp; | 838 | struct inet6_ifaddr *ifp; |
@@ -1000,11 +930,11 @@ out: | |||
1000 | 930 | ||
1001 | static void ndisc_recv_rs(struct sk_buff *skb) | 931 | static void ndisc_recv_rs(struct sk_buff *skb) |
1002 | { | 932 | { |
1003 | struct rs_msg *rs_msg = (struct rs_msg *) skb->h.raw; | 933 | struct rs_msg *rs_msg = (struct rs_msg *)skb_transport_header(skb); |
1004 | unsigned long ndoptlen = skb->len - sizeof(*rs_msg); | 934 | unsigned long ndoptlen = skb->len - sizeof(*rs_msg); |
1005 | struct neighbour *neigh; | 935 | struct neighbour *neigh; |
1006 | struct inet6_dev *idev; | 936 | struct inet6_dev *idev; |
1007 | struct in6_addr *saddr = &skb->nh.ipv6h->saddr; | 937 | struct in6_addr *saddr = &ipv6_hdr(skb)->saddr; |
1008 | struct ndisc_options ndopts; | 938 | struct ndisc_options ndopts; |
1009 | u8 *lladdr = NULL; | 939 | u8 *lladdr = NULL; |
1010 | 940 | ||
@@ -1057,7 +987,7 @@ out: | |||
1057 | 987 | ||
1058 | static void ndisc_router_discovery(struct sk_buff *skb) | 988 | static void ndisc_router_discovery(struct sk_buff *skb) |
1059 | { | 989 | { |
1060 | struct ra_msg *ra_msg = (struct ra_msg *) skb->h.raw; | 990 | struct ra_msg *ra_msg = (struct ra_msg *)skb_transport_header(skb); |
1061 | struct neighbour *neigh = NULL; | 991 | struct neighbour *neigh = NULL; |
1062 | struct inet6_dev *in6_dev; | 992 | struct inet6_dev *in6_dev; |
1063 | struct rt6_info *rt = NULL; | 993 | struct rt6_info *rt = NULL; |
@@ -1068,9 +998,9 @@ static void ndisc_router_discovery(struct sk_buff *skb) | |||
1068 | 998 | ||
1069 | __u8 * opt = (__u8 *)(ra_msg + 1); | 999 | __u8 * opt = (__u8 *)(ra_msg + 1); |
1070 | 1000 | ||
1071 | optlen = (skb->tail - skb->h.raw) - sizeof(struct ra_msg); | 1001 | optlen = (skb->tail - skb->transport_header) - sizeof(struct ra_msg); |
1072 | 1002 | ||
1073 | if (!(ipv6_addr_type(&skb->nh.ipv6h->saddr) & IPV6_ADDR_LINKLOCAL)) { | 1003 | if (!(ipv6_addr_type(&ipv6_hdr(skb)->saddr) & IPV6_ADDR_LINKLOCAL)) { |
1074 | ND_PRINTK2(KERN_WARNING | 1004 | ND_PRINTK2(KERN_WARNING |
1075 | "ICMPv6 RA: source address is not link-local.\n"); | 1005 | "ICMPv6 RA: source address is not link-local.\n"); |
1076 | return; | 1006 | return; |
@@ -1136,7 +1066,7 @@ static void ndisc_router_discovery(struct sk_buff *skb) | |||
1136 | pref = ICMPV6_ROUTER_PREF_MEDIUM; | 1066 | pref = ICMPV6_ROUTER_PREF_MEDIUM; |
1137 | #endif | 1067 | #endif |
1138 | 1068 | ||
1139 | rt = rt6_get_dflt_router(&skb->nh.ipv6h->saddr, skb->dev); | 1069 | rt = rt6_get_dflt_router(&ipv6_hdr(skb)->saddr, skb->dev); |
1140 | 1070 | ||
1141 | if (rt) | 1071 | if (rt) |
1142 | neigh = rt->rt6i_nexthop; | 1072 | neigh = rt->rt6i_nexthop; |
@@ -1151,7 +1081,7 @@ static void ndisc_router_discovery(struct sk_buff *skb) | |||
1151 | ND_PRINTK3(KERN_DEBUG | 1081 | ND_PRINTK3(KERN_DEBUG |
1152 | "ICMPv6 RA: adding default router.\n"); | 1082 | "ICMPv6 RA: adding default router.\n"); |
1153 | 1083 | ||
1154 | rt = rt6_add_dflt_router(&skb->nh.ipv6h->saddr, skb->dev, pref); | 1084 | rt = rt6_add_dflt_router(&ipv6_hdr(skb)->saddr, skb->dev, pref); |
1155 | if (rt == NULL) { | 1085 | if (rt == NULL) { |
1156 | ND_PRINTK0(KERN_ERR | 1086 | ND_PRINTK0(KERN_ERR |
1157 | "ICMPv6 RA: %s() failed to add default route.\n", | 1087 | "ICMPv6 RA: %s() failed to add default route.\n", |
@@ -1223,7 +1153,7 @@ skip_defrtr: | |||
1223 | */ | 1153 | */ |
1224 | 1154 | ||
1225 | if (!neigh) | 1155 | if (!neigh) |
1226 | neigh = __neigh_lookup(&nd_tbl, &skb->nh.ipv6h->saddr, | 1156 | neigh = __neigh_lookup(&nd_tbl, &ipv6_hdr(skb)->saddr, |
1227 | skb->dev, 1); | 1157 | skb->dev, 1); |
1228 | if (neigh) { | 1158 | if (neigh) { |
1229 | u8 *lladdr = NULL; | 1159 | u8 *lladdr = NULL; |
@@ -1252,7 +1182,7 @@ skip_defrtr: | |||
1252 | if (((struct route_info *)p)->prefix_len > in6_dev->cnf.accept_ra_rt_info_max_plen) | 1182 | if (((struct route_info *)p)->prefix_len > in6_dev->cnf.accept_ra_rt_info_max_plen) |
1253 | continue; | 1183 | continue; |
1254 | rt6_route_rcv(skb->dev, (u8*)p, (p->nd_opt_len) << 3, | 1184 | rt6_route_rcv(skb->dev, (u8*)p, (p->nd_opt_len) << 3, |
1255 | &skb->nh.ipv6h->saddr); | 1185 | &ipv6_hdr(skb)->saddr); |
1256 | } | 1186 | } |
1257 | } | 1187 | } |
1258 | #endif | 1188 | #endif |
@@ -1311,13 +1241,13 @@ static void ndisc_redirect_rcv(struct sk_buff *skb) | |||
1311 | int optlen; | 1241 | int optlen; |
1312 | u8 *lladdr = NULL; | 1242 | u8 *lladdr = NULL; |
1313 | 1243 | ||
1314 | if (!(ipv6_addr_type(&skb->nh.ipv6h->saddr) & IPV6_ADDR_LINKLOCAL)) { | 1244 | if (!(ipv6_addr_type(&ipv6_hdr(skb)->saddr) & IPV6_ADDR_LINKLOCAL)) { |
1315 | ND_PRINTK2(KERN_WARNING | 1245 | ND_PRINTK2(KERN_WARNING |
1316 | "ICMPv6 Redirect: source address is not link-local.\n"); | 1246 | "ICMPv6 Redirect: source address is not link-local.\n"); |
1317 | return; | 1247 | return; |
1318 | } | 1248 | } |
1319 | 1249 | ||
1320 | optlen = skb->tail - skb->h.raw; | 1250 | optlen = skb->tail - skb->transport_header; |
1321 | optlen -= sizeof(struct icmp6hdr) + 2 * sizeof(struct in6_addr); | 1251 | optlen -= sizeof(struct icmp6hdr) + 2 * sizeof(struct in6_addr); |
1322 | 1252 | ||
1323 | if (optlen < 0) { | 1253 | if (optlen < 0) { |
@@ -1326,7 +1256,7 @@ static void ndisc_redirect_rcv(struct sk_buff *skb) | |||
1326 | return; | 1256 | return; |
1327 | } | 1257 | } |
1328 | 1258 | ||
1329 | icmph = (struct icmp6hdr *) skb->h.raw; | 1259 | icmph = icmp6_hdr(skb); |
1330 | target = (struct in6_addr *) (icmph + 1); | 1260 | target = (struct in6_addr *) (icmph + 1); |
1331 | dest = target + 1; | 1261 | dest = target + 1; |
1332 | 1262 | ||
@@ -1376,8 +1306,8 @@ static void ndisc_redirect_rcv(struct sk_buff *skb) | |||
1376 | 1306 | ||
1377 | neigh = __neigh_lookup(&nd_tbl, target, skb->dev, 1); | 1307 | neigh = __neigh_lookup(&nd_tbl, target, skb->dev, 1); |
1378 | if (neigh) { | 1308 | if (neigh) { |
1379 | rt6_redirect(dest, &skb->nh.ipv6h->daddr, | 1309 | rt6_redirect(dest, &ipv6_hdr(skb)->daddr, |
1380 | &skb->nh.ipv6h->saddr, neigh, lladdr, | 1310 | &ipv6_hdr(skb)->saddr, neigh, lladdr, |
1381 | on_link); | 1311 | on_link); |
1382 | neigh_release(neigh); | 1312 | neigh_release(neigh); |
1383 | } | 1313 | } |
@@ -1406,21 +1336,21 @@ void ndisc_send_redirect(struct sk_buff *skb, struct neighbour *neigh, | |||
1406 | 1336 | ||
1407 | dev = skb->dev; | 1337 | dev = skb->dev; |
1408 | 1338 | ||
1409 | if (ipv6_get_lladdr(dev, &saddr_buf)) { | 1339 | if (ipv6_get_lladdr(dev, &saddr_buf, IFA_F_TENTATIVE)) { |
1410 | ND_PRINTK2(KERN_WARNING | 1340 | ND_PRINTK2(KERN_WARNING |
1411 | "ICMPv6 Redirect: no link-local address on %s\n", | 1341 | "ICMPv6 Redirect: no link-local address on %s\n", |
1412 | dev->name); | 1342 | dev->name); |
1413 | return; | 1343 | return; |
1414 | } | 1344 | } |
1415 | 1345 | ||
1416 | if (!ipv6_addr_equal(&skb->nh.ipv6h->daddr, target) && | 1346 | if (!ipv6_addr_equal(&ipv6_hdr(skb)->daddr, target) && |
1417 | !(ipv6_addr_type(target) & IPV6_ADDR_LINKLOCAL)) { | 1347 | !(ipv6_addr_type(target) & IPV6_ADDR_LINKLOCAL)) { |
1418 | ND_PRINTK2(KERN_WARNING | 1348 | ND_PRINTK2(KERN_WARNING |
1419 | "ICMPv6 Redirect: target address is not link-local.\n"); | 1349 | "ICMPv6 Redirect: target address is not link-local.\n"); |
1420 | return; | 1350 | return; |
1421 | } | 1351 | } |
1422 | 1352 | ||
1423 | ndisc_flow_init(&fl, NDISC_REDIRECT, &saddr_buf, &skb->nh.ipv6h->saddr, | 1353 | ndisc_flow_init(&fl, NDISC_REDIRECT, &saddr_buf, &ipv6_hdr(skb)->saddr, |
1424 | dev->ifindex); | 1354 | dev->ifindex); |
1425 | 1355 | ||
1426 | dst = ip6_route_output(NULL, &fl); | 1356 | dst = ip6_route_output(NULL, &fl); |
@@ -1475,11 +1405,12 @@ void ndisc_send_redirect(struct sk_buff *skb, struct neighbour *neigh, | |||
1475 | hlen = 0; | 1405 | hlen = 0; |
1476 | 1406 | ||
1477 | skb_reserve(buff, LL_RESERVED_SPACE(dev)); | 1407 | skb_reserve(buff, LL_RESERVED_SPACE(dev)); |
1478 | ip6_nd_hdr(sk, buff, dev, &saddr_buf, &skb->nh.ipv6h->saddr, | 1408 | ip6_nd_hdr(sk, buff, dev, &saddr_buf, &ipv6_hdr(skb)->saddr, |
1479 | IPPROTO_ICMPV6, len); | 1409 | IPPROTO_ICMPV6, len); |
1480 | 1410 | ||
1481 | icmph = (struct icmp6hdr *)skb_put(buff, len); | 1411 | skb_set_transport_header(buff, skb_tail_pointer(buff) - buff->data); |
1482 | buff->h.raw = (unsigned char*)icmph; | 1412 | skb_put(buff, len); |
1413 | icmph = icmp6_hdr(buff); | ||
1483 | 1414 | ||
1484 | memset(icmph, 0, sizeof(struct icmp6hdr)); | 1415 | memset(icmph, 0, sizeof(struct icmp6hdr)); |
1485 | icmph->icmp6_type = NDISC_REDIRECT; | 1416 | icmph->icmp6_type = NDISC_REDIRECT; |
@@ -1491,7 +1422,7 @@ void ndisc_send_redirect(struct sk_buff *skb, struct neighbour *neigh, | |||
1491 | addrp = (struct in6_addr *)(icmph + 1); | 1422 | addrp = (struct in6_addr *)(icmph + 1); |
1492 | ipv6_addr_copy(addrp, target); | 1423 | ipv6_addr_copy(addrp, target); |
1493 | addrp++; | 1424 | addrp++; |
1494 | ipv6_addr_copy(addrp, &skb->nh.ipv6h->daddr); | 1425 | ipv6_addr_copy(addrp, &ipv6_hdr(skb)->daddr); |
1495 | 1426 | ||
1496 | opt = (u8*) (addrp + 1); | 1427 | opt = (u8*) (addrp + 1); |
1497 | 1428 | ||
@@ -1512,9 +1443,9 @@ void ndisc_send_redirect(struct sk_buff *skb, struct neighbour *neigh, | |||
1512 | *(opt++) = (rd_len >> 3); | 1443 | *(opt++) = (rd_len >> 3); |
1513 | opt += 6; | 1444 | opt += 6; |
1514 | 1445 | ||
1515 | memcpy(opt, skb->nh.ipv6h, rd_len - 8); | 1446 | memcpy(opt, ipv6_hdr(skb), rd_len - 8); |
1516 | 1447 | ||
1517 | icmph->icmp6_cksum = csum_ipv6_magic(&saddr_buf, &skb->nh.ipv6h->saddr, | 1448 | icmph->icmp6_cksum = csum_ipv6_magic(&saddr_buf, &ipv6_hdr(skb)->saddr, |
1518 | len, IPPROTO_ICMPV6, | 1449 | len, IPPROTO_ICMPV6, |
1519 | csum_partial((u8 *) icmph, len, 0)); | 1450 | csum_partial((u8 *) icmph, len, 0)); |
1520 | 1451 | ||
@@ -1544,14 +1475,14 @@ int ndisc_rcv(struct sk_buff *skb) | |||
1544 | if (!pskb_may_pull(skb, skb->len)) | 1475 | if (!pskb_may_pull(skb, skb->len)) |
1545 | return 0; | 1476 | return 0; |
1546 | 1477 | ||
1547 | msg = (struct nd_msg *) skb->h.raw; | 1478 | msg = (struct nd_msg *)skb_transport_header(skb); |
1548 | 1479 | ||
1549 | __skb_push(skb, skb->data-skb->h.raw); | 1480 | __skb_push(skb, skb->data - skb_transport_header(skb)); |
1550 | 1481 | ||
1551 | if (skb->nh.ipv6h->hop_limit != 255) { | 1482 | if (ipv6_hdr(skb)->hop_limit != 255) { |
1552 | ND_PRINTK2(KERN_WARNING | 1483 | ND_PRINTK2(KERN_WARNING |
1553 | "ICMPv6 NDISC: invalid hop-limit: %d\n", | 1484 | "ICMPv6 NDISC: invalid hop-limit: %d\n", |
1554 | skb->nh.ipv6h->hop_limit); | 1485 | ipv6_hdr(skb)->hop_limit); |
1555 | return 0; | 1486 | return 0; |
1556 | } | 1487 | } |
1557 | 1488 | ||
@@ -1584,7 +1515,7 @@ int ndisc_rcv(struct sk_buff *skb) | |||
1584 | case NDISC_REDIRECT: | 1515 | case NDISC_REDIRECT: |
1585 | ndisc_redirect_rcv(skb); | 1516 | ndisc_redirect_rcv(skb); |
1586 | break; | 1517 | break; |
1587 | }; | 1518 | } |
1588 | 1519 | ||
1589 | return 0; | 1520 | return 0; |
1590 | } | 1521 | } |