aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6/ndisc.c
diff options
context:
space:
mode:
authorNeil Horman <nhorman@tuxdriver.com>2007-04-25 20:08:10 -0400
committerDavid S. Miller <davem@sunset.davemloft.net>2007-04-26 01:23:43 -0400
commit95c385b4d5a71b8ad552aecaa968ea46d7da2f6a (patch)
tree49d8e60418cb4eeb0c9ed79fd095af50f6ec6623 /net/ipv6/ndisc.c
parent502b093569e48db264831be7966e1c447de2f52f (diff)
[IPV6] ADDRCONF: Optimistic Duplicate Address Detection (RFC 4429) Support.
Nominally an autoconfigured IPv6 address is added to an interface in the Tentative state (as per RFC 2462). Addresses in this state remain in this state while the Duplicate Address Detection process operates on them to determine their uniqueness on the network. During this period, these tentative addresses may not be used for communication, increasing the time before a node may be able to communicate on a network. Using Optimistic Duplicate Address Detection, autoconfigured addresses may be used immediately for communication on the network, as long as certain rules are followed to avoid conflicts with other nodes during the Duplicate Address Detection process. Signed-off-by: Neil Horman <nhorman@tuxdriver.com> Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv6/ndisc.c')
-rw-r--r--net/ipv6/ndisc.c84
1 files changed, 61 insertions, 23 deletions
diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c
index 886c5be14906..b79b00042310 100644
--- a/net/ipv6/ndisc.c
+++ b/net/ipv6/ndisc.c
@@ -449,6 +449,8 @@ static void ndisc_send_na(struct net_device *dev, struct neighbour *neigh,
449 ifp = ipv6_get_ifaddr(solicited_addr, dev, 1); 449 ifp = ipv6_get_ifaddr(solicited_addr, dev, 1);
450 if (ifp) { 450 if (ifp) {
451 src_addr = solicited_addr; 451 src_addr = solicited_addr;
452 if (ifp->flags & IFA_F_OPTIMISTIC)
453 override = 0;
452 in6_ifa_put(ifp); 454 in6_ifa_put(ifp);
453 } else { 455 } else {
454 if (ipv6_dev_get_saddr(dev, daddr, &tmpaddr)) 456 if (ipv6_dev_get_saddr(dev, daddr, &tmpaddr))
@@ -544,7 +546,8 @@ void ndisc_send_ns(struct net_device *dev, struct neighbour *neigh,
544 int send_llinfo; 546 int send_llinfo;
545 547
546 if (saddr == NULL) { 548 if (saddr == NULL) {
547 if (ipv6_get_lladdr(dev, &addr_buf)) 549 if (ipv6_get_lladdr(dev, &addr_buf,
550 (IFA_F_TENTATIVE|IFA_F_OPTIMISTIC)))
548 return; 551 return;
549 saddr = &addr_buf; 552 saddr = &addr_buf;
550 } 553 }
@@ -624,9 +627,33 @@ void ndisc_send_rs(struct net_device *dev, struct in6_addr *saddr,
624 struct sk_buff *skb; 627 struct sk_buff *skb;
625 struct icmp6hdr *hdr; 628 struct icmp6hdr *hdr;
626 __u8 * opt; 629 __u8 * opt;
630 struct inet6_ifaddr *ifp;
631 int send_sllao = dev->addr_len;
627 int len; 632 int len;
628 int err; 633 int err;
629 634
635
636#ifdef CONFIG_IPV6_OPTIMISTIC_DAD
637 /*
638 * According to section 2.2 of RFC 4429, we must not
639 * send router solicitations with a sllao from
640 * optimistic addresses, but we may send the solicitation
641 * if we don't include the sllao. So here we check
642 * if our address is optimistic, and if so, we
643 * supress the inclusion of the sllao.
644 */
645 if (send_sllao) {
646 ifp = ipv6_get_ifaddr(saddr, dev, 1);
647 if (ifp) {
648 if (ifp->flags & IFA_F_OPTIMISTIC) {
649 send_sllao=0;
650 in6_ifa_put(ifp);
651 }
652 } else {
653 send_sllao = 0;
654 }
655 }
656#endif
630 ndisc_flow_init(&fl, NDISC_ROUTER_SOLICITATION, saddr, daddr, 657 ndisc_flow_init(&fl, NDISC_ROUTER_SOLICITATION, saddr, daddr,
631 dev->ifindex); 658 dev->ifindex);
632 659
@@ -639,7 +666,7 @@ void ndisc_send_rs(struct net_device *dev, struct in6_addr *saddr,
639 return; 666 return;
640 667
641 len = sizeof(struct icmp6hdr); 668 len = sizeof(struct icmp6hdr);
642 if (dev->addr_len) 669 if (send_sllao)
643 len += ndisc_opt_addr_space(dev); 670 len += ndisc_opt_addr_space(dev);
644 671
645 skb = sock_alloc_send_skb(sk, 672 skb = sock_alloc_send_skb(sk,
@@ -666,7 +693,7 @@ void ndisc_send_rs(struct net_device *dev, struct in6_addr *saddr,
666 693
667 opt = (u8*) (hdr + 1); 694 opt = (u8*) (hdr + 1);
668 695
669 if (dev->addr_len) 696 if (send_sllao)
670 ndisc_fill_addr_option(opt, ND_OPT_SOURCE_LL_ADDR, dev->dev_addr, 697 ndisc_fill_addr_option(opt, ND_OPT_SOURCE_LL_ADDR, dev->dev_addr,
671 dev->addr_len, dev->type); 698 dev->addr_len, dev->type);
672 699
@@ -798,28 +825,39 @@ static void ndisc_recv_ns(struct sk_buff *skb)
798 inc = ipv6_addr_is_multicast(daddr); 825 inc = ipv6_addr_is_multicast(daddr);
799 826
800 if ((ifp = ipv6_get_ifaddr(&msg->target, dev, 1)) != NULL) { 827 if ((ifp = ipv6_get_ifaddr(&msg->target, dev, 1)) != NULL) {
801 if (ifp->flags & IFA_F_TENTATIVE) { 828
802 /* Address is tentative. If the source 829 if (ifp->flags & (IFA_F_TENTATIVE|IFA_F_OPTIMISTIC)) {
803 is unspecified address, it is someone 830 if (dad) {
804 does DAD, otherwise we ignore solicitations 831 if (dev->type == ARPHRD_IEEE802_TR) {
805 until DAD timer expires. 832 unsigned char *sadr = skb->mac.raw;
806 */ 833 if (((sadr[8] ^ dev->dev_addr[0]) & 0x7f) == 0 &&
807 if (!dad) 834 sadr[9] == dev->dev_addr[1] &&
835 sadr[10] == dev->dev_addr[2] &&
836 sadr[11] == dev->dev_addr[3] &&
837 sadr[12] == dev->dev_addr[4] &&
838 sadr[13] == dev->dev_addr[5]) {
839 /* looped-back to us */
840 goto out;
841 }
842 }
843
844 /*
845 * We are colliding with another node
846 * who is doing DAD
847 * so fail our DAD process
848 */
849 addrconf_dad_failure(ifp);
808 goto out; 850 goto out;
809 if (dev->type == ARPHRD_IEEE802_TR) { 851 } else {
810 unsigned char *sadr = skb->mac.raw; 852 /*
811 if (((sadr[8] ^ dev->dev_addr[0]) & 0x7f) == 0 && 853 * This is not a dad solicitation.
812 sadr[9] == dev->dev_addr[1] && 854 * If we are an optimistic node,
813 sadr[10] == dev->dev_addr[2] && 855 * we should respond.
814 sadr[11] == dev->dev_addr[3] && 856 * Otherwise, we should ignore it.
815 sadr[12] == dev->dev_addr[4] && 857 */
816 sadr[13] == dev->dev_addr[5]) { 858 if (!(ifp->flags & IFA_F_OPTIMISTIC))
817 /* looped-back to us */
818 goto out; 859 goto out;
819 }
820 } 860 }
821 addrconf_dad_failure(ifp);
822 return;
823 } 861 }
824 862
825 idev = ifp->idev; 863 idev = ifp->idev;
@@ -1408,7 +1446,7 @@ void ndisc_send_redirect(struct sk_buff *skb, struct neighbour *neigh,
1408 1446
1409 dev = skb->dev; 1447 dev = skb->dev;
1410 1448
1411 if (ipv6_get_lladdr(dev, &saddr_buf)) { 1449 if (ipv6_get_lladdr(dev, &saddr_buf, IFA_F_TENTATIVE)) {
1412 ND_PRINTK2(KERN_WARNING 1450 ND_PRINTK2(KERN_WARNING
1413 "ICMPv6 Redirect: no link-local address on %s\n", 1451 "ICMPv6 Redirect: no link-local address on %s\n",
1414 dev->name); 1452 dev->name);