ndisc.c (712cba5d87a6c0e980ee5fad45734e189c4d7151) | ndisc.c (adc176c5472214971d77c1a61c83db9b01e9cdc7) |
---|---|
1/* 2 * Neighbour Discovery for IPv6 3 * Linux INET6 implementation 4 * 5 * Authors: 6 * Pedro Roque <roque@di.fc.ul.pt> 7 * Mike Shaver <shaver@ingenia.com> 8 * --- 219 unchanged lines hidden (view full) --- 228 if (opt_len < l || l == 0) 229 return NULL; 230 if (ndisc_ops_parse_options(dev, nd_opt, ndopts)) 231 goto next_opt; 232 switch (nd_opt->nd_opt_type) { 233 case ND_OPT_SOURCE_LL_ADDR: 234 case ND_OPT_TARGET_LL_ADDR: 235 case ND_OPT_MTU: | 1/* 2 * Neighbour Discovery for IPv6 3 * Linux INET6 implementation 4 * 5 * Authors: 6 * Pedro Roque <roque@di.fc.ul.pt> 7 * Mike Shaver <shaver@ingenia.com> 8 * --- 219 unchanged lines hidden (view full) --- 228 if (opt_len < l || l == 0) 229 return NULL; 230 if (ndisc_ops_parse_options(dev, nd_opt, ndopts)) 231 goto next_opt; 232 switch (nd_opt->nd_opt_type) { 233 case ND_OPT_SOURCE_LL_ADDR: 234 case ND_OPT_TARGET_LL_ADDR: 235 case ND_OPT_MTU: |
236 case ND_OPT_NONCE: |
|
236 case ND_OPT_REDIRECT_HDR: 237 if (ndopts->nd_opt_array[nd_opt->nd_opt_type]) { 238 ND_PRINTK(2, warn, 239 "%s: duplicated ND6 option found: type=%d\n", 240 __func__, nd_opt->nd_opt_type); 241 } else { 242 ndopts->nd_opt_array[nd_opt->nd_opt_type] = nd_opt; 243 } --- 319 unchanged lines hidden (view full) --- 563 /*inc_opt=*/ true); 564 } 565 read_unlock_bh(&idev->lock); 566 567 in6_dev_put(idev); 568} 569 570void ndisc_send_ns(struct net_device *dev, const struct in6_addr *solicit, | 237 case ND_OPT_REDIRECT_HDR: 238 if (ndopts->nd_opt_array[nd_opt->nd_opt_type]) { 239 ND_PRINTK(2, warn, 240 "%s: duplicated ND6 option found: type=%d\n", 241 __func__, nd_opt->nd_opt_type); 242 } else { 243 ndopts->nd_opt_array[nd_opt->nd_opt_type] = nd_opt; 244 } --- 319 unchanged lines hidden (view full) --- 564 /*inc_opt=*/ true); 565 } 566 read_unlock_bh(&idev->lock); 567 568 in6_dev_put(idev); 569} 570 571void ndisc_send_ns(struct net_device *dev, const struct in6_addr *solicit, |
571 const struct in6_addr *daddr, const struct in6_addr *saddr) | 572 const struct in6_addr *daddr, const struct in6_addr *saddr, 573 u64 nonce) |
572{ 573 struct sk_buff *skb; 574 struct in6_addr addr_buf; 575 int inc_opt = dev->addr_len; 576 int optlen = 0; 577 struct nd_msg *msg; 578 579 if (!saddr) { 580 if (ipv6_get_lladdr(dev, &addr_buf, 581 (IFA_F_TENTATIVE|IFA_F_OPTIMISTIC))) 582 return; 583 saddr = &addr_buf; 584 } 585 586 if (ipv6_addr_any(saddr)) 587 inc_opt = false; 588 if (inc_opt) 589 optlen += ndisc_opt_addr_space(dev, 590 NDISC_NEIGHBOUR_SOLICITATION); | 574{ 575 struct sk_buff *skb; 576 struct in6_addr addr_buf; 577 int inc_opt = dev->addr_len; 578 int optlen = 0; 579 struct nd_msg *msg; 580 581 if (!saddr) { 582 if (ipv6_get_lladdr(dev, &addr_buf, 583 (IFA_F_TENTATIVE|IFA_F_OPTIMISTIC))) 584 return; 585 saddr = &addr_buf; 586 } 587 588 if (ipv6_addr_any(saddr)) 589 inc_opt = false; 590 if (inc_opt) 591 optlen += ndisc_opt_addr_space(dev, 592 NDISC_NEIGHBOUR_SOLICITATION); |
593 if (nonce != 0) 594 optlen += 8; |
|
591 592 skb = ndisc_alloc_skb(dev, sizeof(*msg) + optlen); 593 if (!skb) 594 return; 595 596 msg = (struct nd_msg *)skb_put(skb, sizeof(*msg)); 597 *msg = (struct nd_msg) { 598 .icmph = { 599 .icmp6_type = NDISC_NEIGHBOUR_SOLICITATION, 600 }, 601 .target = *solicit, 602 }; 603 604 if (inc_opt) 605 ndisc_fill_addr_option(skb, ND_OPT_SOURCE_LL_ADDR, 606 dev->dev_addr, 607 NDISC_NEIGHBOUR_SOLICITATION); | 595 596 skb = ndisc_alloc_skb(dev, sizeof(*msg) + optlen); 597 if (!skb) 598 return; 599 600 msg = (struct nd_msg *)skb_put(skb, sizeof(*msg)); 601 *msg = (struct nd_msg) { 602 .icmph = { 603 .icmp6_type = NDISC_NEIGHBOUR_SOLICITATION, 604 }, 605 .target = *solicit, 606 }; 607 608 if (inc_opt) 609 ndisc_fill_addr_option(skb, ND_OPT_SOURCE_LL_ADDR, 610 dev->dev_addr, 611 NDISC_NEIGHBOUR_SOLICITATION); |
612 if (nonce != 0) { 613 u8 *opt = skb_put(skb, 8); |
|
608 | 614 |
615 opt[0] = ND_OPT_NONCE; 616 opt[1] = 8 >> 3; 617 memcpy(opt + 2, &nonce, 6); 618 } 619 |
|
609 ndisc_send_skb(skb, daddr, saddr); 610} 611 612void ndisc_send_rs(struct net_device *dev, const struct in6_addr *saddr, 613 const struct in6_addr *daddr) 614{ 615 struct sk_buff *skb; 616 struct rs_msg *msg; --- 71 unchanged lines hidden (view full) --- 688 saddr = &ipv6_hdr(skb)->saddr; 689 probes -= NEIGH_VAR(neigh->parms, UCAST_PROBES); 690 if (probes < 0) { 691 if (!(neigh->nud_state & NUD_VALID)) { 692 ND_PRINTK(1, dbg, 693 "%s: trying to ucast probe in NUD_INVALID: %pI6\n", 694 __func__, target); 695 } | 620 ndisc_send_skb(skb, daddr, saddr); 621} 622 623void ndisc_send_rs(struct net_device *dev, const struct in6_addr *saddr, 624 const struct in6_addr *daddr) 625{ 626 struct sk_buff *skb; 627 struct rs_msg *msg; --- 71 unchanged lines hidden (view full) --- 699 saddr = &ipv6_hdr(skb)->saddr; 700 probes -= NEIGH_VAR(neigh->parms, UCAST_PROBES); 701 if (probes < 0) { 702 if (!(neigh->nud_state & NUD_VALID)) { 703 ND_PRINTK(1, dbg, 704 "%s: trying to ucast probe in NUD_INVALID: %pI6\n", 705 __func__, target); 706 } |
696 ndisc_send_ns(dev, target, target, saddr); | 707 ndisc_send_ns(dev, target, target, saddr, 0); |
697 } else if ((probes -= NEIGH_VAR(neigh->parms, APP_PROBES)) < 0) { 698 neigh_app_ns(neigh); 699 } else { 700 addrconf_addr_solict_mult(target, &mcaddr); | 708 } else if ((probes -= NEIGH_VAR(neigh->parms, APP_PROBES)) < 0) { 709 neigh_app_ns(neigh); 710 } else { 711 addrconf_addr_solict_mult(target, &mcaddr); |
701 ndisc_send_ns(dev, target, &mcaddr, saddr); | 712 ndisc_send_ns(dev, target, &mcaddr, saddr, 0); |
702 } 703} 704 705static int pndisc_is_router(const void *pkey, 706 struct net_device *dev) 707{ 708 struct pneigh_entry *n; 709 int ret = -1; --- 27 unchanged lines hidden (view full) --- 737 struct ndisc_options ndopts; 738 struct net_device *dev = skb->dev; 739 struct inet6_ifaddr *ifp; 740 struct inet6_dev *idev = NULL; 741 struct neighbour *neigh; 742 int dad = ipv6_addr_any(saddr); 743 bool inc; 744 int is_router = -1; | 713 } 714} 715 716static int pndisc_is_router(const void *pkey, 717 struct net_device *dev) 718{ 719 struct pneigh_entry *n; 720 int ret = -1; --- 27 unchanged lines hidden (view full) --- 748 struct ndisc_options ndopts; 749 struct net_device *dev = skb->dev; 750 struct inet6_ifaddr *ifp; 751 struct inet6_dev *idev = NULL; 752 struct neighbour *neigh; 753 int dad = ipv6_addr_any(saddr); 754 bool inc; 755 int is_router = -1; |
756 u64 nonce = 0; |
|
745 746 if (skb->len < sizeof(struct nd_msg)) { 747 ND_PRINTK(2, warn, "NS: packet too short\n"); 748 return; 749 } 750 751 if (ipv6_addr_is_multicast(&msg->target)) { 752 ND_PRINTK(2, warn, "NS: multicast target address\n"); --- 28 unchanged lines hidden (view full) --- 781 * in the message. 782 */ 783 if (dad) { 784 ND_PRINTK(2, warn, 785 "NS: bad DAD packet (link-layer address option)\n"); 786 return; 787 } 788 } | 757 758 if (skb->len < sizeof(struct nd_msg)) { 759 ND_PRINTK(2, warn, "NS: packet too short\n"); 760 return; 761 } 762 763 if (ipv6_addr_is_multicast(&msg->target)) { 764 ND_PRINTK(2, warn, "NS: multicast target address\n"); --- 28 unchanged lines hidden (view full) --- 793 * in the message. 794 */ 795 if (dad) { 796 ND_PRINTK(2, warn, 797 "NS: bad DAD packet (link-layer address option)\n"); 798 return; 799 } 800 } |
801 if (ndopts.nd_opts_nonce) 802 memcpy(&nonce, (u8 *)(ndopts.nd_opts_nonce + 1), 6); |
|
789 790 inc = ipv6_addr_is_multicast(daddr); 791 792 ifp = ipv6_get_ifaddr(dev_net(dev), &msg->target, dev, 1); 793 if (ifp) { 794have_ifp: 795 if (ifp->flags & (IFA_F_TENTATIVE|IFA_F_OPTIMISTIC)) { 796 if (dad) { | 803 804 inc = ipv6_addr_is_multicast(daddr); 805 806 ifp = ipv6_get_ifaddr(dev_net(dev), &msg->target, dev, 1); 807 if (ifp) { 808have_ifp: 809 if (ifp->flags & (IFA_F_TENTATIVE|IFA_F_OPTIMISTIC)) { 810 if (dad) { |
811 if (nonce != 0 && ifp->dad_nonce == nonce) { 812 u8 *np = (u8 *)&nonce; 813 /* Matching nonce if looped back */ 814 ND_PRINTK(2, notice, 815 "%s: IPv6 DAD loopback for address %pI6c nonce %pM ignored\n", 816 ifp->idev->dev->name, 817 &ifp->addr, np); 818 goto out; 819 } |
|
797 /* 798 * We are colliding with another node 799 * who is doing DAD 800 * so fail our DAD process 801 */ 802 addrconf_dad_failure(ifp); 803 return; 804 } else { --- 1086 unchanged lines hidden --- | 820 /* 821 * We are colliding with another node 822 * who is doing DAD 823 * so fail our DAD process 824 */ 825 addrconf_dad_failure(ifp); 826 return; 827 } else { --- 1086 unchanged lines hidden --- |