aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6/ndisc.c
diff options
context:
space:
mode:
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);