diff options
-rw-r--r-- | include/linux/if_addr.h | 1 | ||||
-rw-r--r-- | include/linux/ipv6.h | 4 | ||||
-rw-r--r-- | include/net/addrconf.h | 4 | ||||
-rw-r--r-- | net/ipv6/Kconfig | 10 | ||||
-rw-r--r-- | net/ipv6/addrconf.c | 106 | ||||
-rw-r--r-- | net/ipv6/ip6_output.c | 35 | ||||
-rw-r--r-- | net/ipv6/mcast.c | 4 | ||||
-rw-r--r-- | net/ipv6/ndisc.c | 84 |
8 files changed, 207 insertions, 41 deletions
diff --git a/include/linux/if_addr.h b/include/linux/if_addr.h index d557e4ce9b6b..43f3bedaafd3 100644 --- a/include/linux/if_addr.h +++ b/include/linux/if_addr.h | |||
@@ -39,6 +39,7 @@ enum | |||
39 | #define IFA_F_TEMPORARY IFA_F_SECONDARY | 39 | #define IFA_F_TEMPORARY IFA_F_SECONDARY |
40 | 40 | ||
41 | #define IFA_F_NODAD 0x02 | 41 | #define IFA_F_NODAD 0x02 |
42 | #define IFA_F_OPTIMISTIC 0x04 | ||
42 | #define IFA_F_HOMEADDRESS 0x10 | 43 | #define IFA_F_HOMEADDRESS 0x10 |
43 | #define IFA_F_DEPRECATED 0x20 | 44 | #define IFA_F_DEPRECATED 0x20 |
44 | #define IFA_F_TENTATIVE 0x40 | 45 | #define IFA_F_TENTATIVE 0x40 |
diff --git a/include/linux/ipv6.h b/include/linux/ipv6.h index 713eb5eaa81f..e046b22a2222 100644 --- a/include/linux/ipv6.h +++ b/include/linux/ipv6.h | |||
@@ -178,6 +178,9 @@ struct ipv6_devconf { | |||
178 | #endif | 178 | #endif |
179 | __s32 proxy_ndp; | 179 | __s32 proxy_ndp; |
180 | __s32 accept_source_route; | 180 | __s32 accept_source_route; |
181 | #ifdef CONFIG_IPV6_OPTIMISTIC_DAD | ||
182 | __s32 optimistic_dad; | ||
183 | #endif | ||
181 | void *sysctl; | 184 | void *sysctl; |
182 | }; | 185 | }; |
183 | 186 | ||
@@ -208,6 +211,7 @@ enum { | |||
208 | DEVCONF_PROXY_NDP, | 211 | DEVCONF_PROXY_NDP, |
209 | __DEVCONF_OPTIMISTIC_DAD, | 212 | __DEVCONF_OPTIMISTIC_DAD, |
210 | DEVCONF_ACCEPT_SOURCE_ROUTE, | 213 | DEVCONF_ACCEPT_SOURCE_ROUTE, |
214 | DEVCONF_OPTIMISTIC_DAD, | ||
211 | DEVCONF_MAX | 215 | DEVCONF_MAX |
212 | }; | 216 | }; |
213 | 217 | ||
diff --git a/include/net/addrconf.h b/include/net/addrconf.h index 88df8fc814e4..f3531d0bcd05 100644 --- a/include/net/addrconf.h +++ b/include/net/addrconf.h | |||
@@ -73,7 +73,9 @@ extern int ipv6_get_saddr(struct dst_entry *dst, | |||
73 | extern int ipv6_dev_get_saddr(struct net_device *dev, | 73 | extern int ipv6_dev_get_saddr(struct net_device *dev, |
74 | struct in6_addr *daddr, | 74 | struct in6_addr *daddr, |
75 | struct in6_addr *saddr); | 75 | struct in6_addr *saddr); |
76 | extern int ipv6_get_lladdr(struct net_device *dev, struct in6_addr *); | 76 | extern int ipv6_get_lladdr(struct net_device *dev, |
77 | struct in6_addr *addr, | ||
78 | unsigned char banned_flags); | ||
77 | extern int ipv6_rcv_saddr_equal(const struct sock *sk, | 79 | extern int ipv6_rcv_saddr_equal(const struct sock *sk, |
78 | const struct sock *sk2); | 80 | const struct sock *sk2); |
79 | extern void addrconf_join_solict(struct net_device *dev, | 81 | extern void addrconf_join_solict(struct net_device *dev, |
diff --git a/net/ipv6/Kconfig b/net/ipv6/Kconfig index 79682efb14be..8e5d54f23b49 100644 --- a/net/ipv6/Kconfig +++ b/net/ipv6/Kconfig | |||
@@ -57,6 +57,16 @@ config IPV6_ROUTE_INFO | |||
57 | 57 | ||
58 | If unsure, say N. | 58 | If unsure, say N. |
59 | 59 | ||
60 | config IPV6_OPTIMISTIC_DAD | ||
61 | bool "IPv6: Enable RFC 4429 Optimistic DAD (EXPERIMENTAL)" | ||
62 | depends on IPV6 && EXPERIMENTAL | ||
63 | ---help--- | ||
64 | This is experimental support for optimistic Duplicate | ||
65 | Address Detection. It allows for autoconfigured addresses | ||
66 | to be used more quickly. | ||
67 | |||
68 | If unsure, say N. | ||
69 | |||
60 | config INET6_AH | 70 | config INET6_AH |
61 | tristate "IPv6: AH transformation" | 71 | tristate "IPv6: AH transformation" |
62 | depends on IPV6 | 72 | depends on IPV6 |
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index e035896657bc..38274c20eaa2 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c | |||
@@ -530,6 +530,16 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, int pfxlen, | |||
530 | 530 | ||
531 | ifa->rt = rt; | 531 | ifa->rt = rt; |
532 | 532 | ||
533 | /* | ||
534 | * part one of RFC 4429, section 3.3 | ||
535 | * We should not configure an address as | ||
536 | * optimistic if we do not yet know the link | ||
537 | * layer address of our nexhop router | ||
538 | */ | ||
539 | |||
540 | if (rt->rt6i_nexthop == NULL) | ||
541 | ifa->flags &= ~IFA_F_OPTIMISTIC; | ||
542 | |||
533 | ifa->idev = idev; | 543 | ifa->idev = idev; |
534 | in6_dev_hold(idev); | 544 | in6_dev_hold(idev); |
535 | /* For caller */ | 545 | /* For caller */ |
@@ -706,6 +716,7 @@ static int ipv6_create_tempaddr(struct inet6_ifaddr *ifp, struct inet6_ifaddr *i | |||
706 | int tmp_plen; | 716 | int tmp_plen; |
707 | int ret = 0; | 717 | int ret = 0; |
708 | int max_addresses; | 718 | int max_addresses; |
719 | u32 addr_flags; | ||
709 | 720 | ||
710 | write_lock(&idev->lock); | 721 | write_lock(&idev->lock); |
711 | if (ift) { | 722 | if (ift) { |
@@ -763,10 +774,17 @@ retry: | |||
763 | spin_unlock_bh(&ifp->lock); | 774 | spin_unlock_bh(&ifp->lock); |
764 | 775 | ||
765 | write_unlock(&idev->lock); | 776 | write_unlock(&idev->lock); |
777 | |||
778 | addr_flags = IFA_F_TEMPORARY; | ||
779 | /* set in addrconf_prefix_rcv() */ | ||
780 | if (ifp->flags & IFA_F_OPTIMISTIC) | ||
781 | addr_flags |= IFA_F_OPTIMISTIC; | ||
782 | |||
766 | ift = !max_addresses || | 783 | ift = !max_addresses || |
767 | ipv6_count_addresses(idev) < max_addresses ? | 784 | ipv6_count_addresses(idev) < max_addresses ? |
768 | ipv6_add_addr(idev, &addr, tmp_plen, | 785 | ipv6_add_addr(idev, &addr, tmp_plen, |
769 | ipv6_addr_type(&addr)&IPV6_ADDR_SCOPE_MASK, IFA_F_TEMPORARY) : NULL; | 786 | ipv6_addr_type(&addr)&IPV6_ADDR_SCOPE_MASK, |
787 | addr_flags) : NULL; | ||
770 | if (!ift || IS_ERR(ift)) { | 788 | if (!ift || IS_ERR(ift)) { |
771 | in6_ifa_put(ifp); | 789 | in6_ifa_put(ifp); |
772 | in6_dev_put(idev); | 790 | in6_dev_put(idev); |
@@ -898,13 +916,14 @@ int ipv6_dev_get_saddr(struct net_device *daddr_dev, | |||
898 | * - Tentative Address (RFC2462 section 5.4) | 916 | * - Tentative Address (RFC2462 section 5.4) |
899 | * - A tentative address is not considered | 917 | * - A tentative address is not considered |
900 | * "assigned to an interface" in the traditional | 918 | * "assigned to an interface" in the traditional |
901 | * sense. | 919 | * sense, unless it is also flagged as optimistic. |
902 | * - Candidate Source Address (section 4) | 920 | * - Candidate Source Address (section 4) |
903 | * - In any case, anycast addresses, multicast | 921 | * - In any case, anycast addresses, multicast |
904 | * addresses, and the unspecified address MUST | 922 | * addresses, and the unspecified address MUST |
905 | * NOT be included in a candidate set. | 923 | * NOT be included in a candidate set. |
906 | */ | 924 | */ |
907 | if (ifa->flags & IFA_F_TENTATIVE) | 925 | if ((ifa->flags & IFA_F_TENTATIVE) && |
926 | (!(ifa->flags & IFA_F_OPTIMISTIC))) | ||
908 | continue; | 927 | continue; |
909 | if (unlikely(score.addr_type == IPV6_ADDR_ANY || | 928 | if (unlikely(score.addr_type == IPV6_ADDR_ANY || |
910 | score.addr_type & IPV6_ADDR_MULTICAST)) { | 929 | score.addr_type & IPV6_ADDR_MULTICAST)) { |
@@ -963,15 +982,17 @@ int ipv6_dev_get_saddr(struct net_device *daddr_dev, | |||
963 | } | 982 | } |
964 | } | 983 | } |
965 | 984 | ||
966 | /* Rule 3: Avoid deprecated address */ | 985 | /* Rule 3: Avoid deprecated and optimistic addresses */ |
967 | if (hiscore.rule < 3) { | 986 | if (hiscore.rule < 3) { |
968 | if (ipv6_saddr_preferred(hiscore.addr_type) || | 987 | if (ipv6_saddr_preferred(hiscore.addr_type) || |
969 | !(ifa_result->flags & IFA_F_DEPRECATED)) | 988 | (((ifa_result->flags & |
989 | (IFA_F_DEPRECATED|IFA_F_OPTIMISTIC)) == 0))) | ||
970 | hiscore.attrs |= IPV6_SADDR_SCORE_PREFERRED; | 990 | hiscore.attrs |= IPV6_SADDR_SCORE_PREFERRED; |
971 | hiscore.rule++; | 991 | hiscore.rule++; |
972 | } | 992 | } |
973 | if (ipv6_saddr_preferred(score.addr_type) || | 993 | if (ipv6_saddr_preferred(score.addr_type) || |
974 | !(ifa->flags & IFA_F_DEPRECATED)) { | 994 | (((ifa_result->flags & |
995 | (IFA_F_DEPRECATED|IFA_F_OPTIMISTIC)) == 0))) { | ||
975 | score.attrs |= IPV6_SADDR_SCORE_PREFERRED; | 996 | score.attrs |= IPV6_SADDR_SCORE_PREFERRED; |
976 | if (!(hiscore.attrs & IPV6_SADDR_SCORE_PREFERRED)) { | 997 | if (!(hiscore.attrs & IPV6_SADDR_SCORE_PREFERRED)) { |
977 | score.rule = 3; | 998 | score.rule = 3; |
@@ -1111,7 +1132,8 @@ int ipv6_get_saddr(struct dst_entry *dst, | |||
1111 | 1132 | ||
1112 | EXPORT_SYMBOL(ipv6_get_saddr); | 1133 | EXPORT_SYMBOL(ipv6_get_saddr); |
1113 | 1134 | ||
1114 | int ipv6_get_lladdr(struct net_device *dev, struct in6_addr *addr) | 1135 | int ipv6_get_lladdr(struct net_device *dev, struct in6_addr *addr, |
1136 | unsigned char banned_flags) | ||
1115 | { | 1137 | { |
1116 | struct inet6_dev *idev; | 1138 | struct inet6_dev *idev; |
1117 | int err = -EADDRNOTAVAIL; | 1139 | int err = -EADDRNOTAVAIL; |
@@ -1122,7 +1144,7 @@ int ipv6_get_lladdr(struct net_device *dev, struct in6_addr *addr) | |||
1122 | 1144 | ||
1123 | read_lock_bh(&idev->lock); | 1145 | read_lock_bh(&idev->lock); |
1124 | for (ifp=idev->addr_list; ifp; ifp=ifp->if_next) { | 1146 | for (ifp=idev->addr_list; ifp; ifp=ifp->if_next) { |
1125 | if (ifp->scope == IFA_LINK && !(ifp->flags&IFA_F_TENTATIVE)) { | 1147 | if (ifp->scope == IFA_LINK && !(ifp->flags & banned_flags)) { |
1126 | ipv6_addr_copy(addr, &ifp->addr); | 1148 | ipv6_addr_copy(addr, &ifp->addr); |
1127 | err = 0; | 1149 | err = 0; |
1128 | break; | 1150 | break; |
@@ -1674,6 +1696,13 @@ ok: | |||
1674 | 1696 | ||
1675 | if (ifp == NULL && valid_lft) { | 1697 | if (ifp == NULL && valid_lft) { |
1676 | int max_addresses = in6_dev->cnf.max_addresses; | 1698 | int max_addresses = in6_dev->cnf.max_addresses; |
1699 | u32 addr_flags = 0; | ||
1700 | |||
1701 | #ifdef CONFIG_IPV6_OPTIMISTIC_DAD | ||
1702 | if (in6_dev->cnf.optimistic_dad && | ||
1703 | !ipv6_devconf.forwarding) | ||
1704 | addr_flags = IFA_F_OPTIMISTIC; | ||
1705 | #endif | ||
1677 | 1706 | ||
1678 | /* Do not allow to create too much of autoconfigured | 1707 | /* Do not allow to create too much of autoconfigured |
1679 | * addresses; this would be too easy way to crash kernel. | 1708 | * addresses; this would be too easy way to crash kernel. |
@@ -1681,7 +1710,8 @@ ok: | |||
1681 | if (!max_addresses || | 1710 | if (!max_addresses || |
1682 | ipv6_count_addresses(in6_dev) < max_addresses) | 1711 | ipv6_count_addresses(in6_dev) < max_addresses) |
1683 | ifp = ipv6_add_addr(in6_dev, &addr, pinfo->prefix_len, | 1712 | ifp = ipv6_add_addr(in6_dev, &addr, pinfo->prefix_len, |
1684 | addr_type&IPV6_ADDR_SCOPE_MASK, 0); | 1713 | addr_type&IPV6_ADDR_SCOPE_MASK, |
1714 | addr_flags); | ||
1685 | 1715 | ||
1686 | if (!ifp || IS_ERR(ifp)) { | 1716 | if (!ifp || IS_ERR(ifp)) { |
1687 | in6_dev_put(in6_dev); | 1717 | in6_dev_put(in6_dev); |
@@ -1889,6 +1919,11 @@ static int inet6_addr_add(int ifindex, struct in6_addr *pfx, int plen, | |||
1889 | 1919 | ||
1890 | addrconf_prefix_route(&ifp->addr, ifp->prefix_len, dev, | 1920 | addrconf_prefix_route(&ifp->addr, ifp->prefix_len, dev, |
1891 | jiffies_to_clock_t(valid_lft * HZ), flags); | 1921 | jiffies_to_clock_t(valid_lft * HZ), flags); |
1922 | /* | ||
1923 | * Note that section 3.1 of RFC 4429 indicates | ||
1924 | * that the Optimistic flag should not be set for | ||
1925 | * manually configured addresses | ||
1926 | */ | ||
1892 | addrconf_dad_start(ifp, 0); | 1927 | addrconf_dad_start(ifp, 0); |
1893 | in6_ifa_put(ifp); | 1928 | in6_ifa_put(ifp); |
1894 | addrconf_verify(0); | 1929 | addrconf_verify(0); |
@@ -2065,8 +2100,16 @@ static void init_loopback(struct net_device *dev) | |||
2065 | static void addrconf_add_linklocal(struct inet6_dev *idev, struct in6_addr *addr) | 2100 | static void addrconf_add_linklocal(struct inet6_dev *idev, struct in6_addr *addr) |
2066 | { | 2101 | { |
2067 | struct inet6_ifaddr * ifp; | 2102 | struct inet6_ifaddr * ifp; |
2103 | u32 addr_flags = IFA_F_PERMANENT; | ||
2104 | |||
2105 | #ifdef CONFIG_IPV6_OPTIMISTIC_DAD | ||
2106 | if (idev->cnf.optimistic_dad && | ||
2107 | !ipv6_devconf.forwarding) | ||
2108 | addr_flags |= IFA_F_OPTIMISTIC; | ||
2109 | #endif | ||
2068 | 2110 | ||
2069 | ifp = ipv6_add_addr(idev, addr, 64, IFA_LINK, IFA_F_PERMANENT); | 2111 | |
2112 | ifp = ipv6_add_addr(idev, addr, 64, IFA_LINK, addr_flags); | ||
2070 | if (!IS_ERR(ifp)) { | 2113 | if (!IS_ERR(ifp)) { |
2071 | addrconf_prefix_route(&ifp->addr, ifp->prefix_len, idev->dev, 0, 0); | 2114 | addrconf_prefix_route(&ifp->addr, ifp->prefix_len, idev->dev, 0, 0); |
2072 | addrconf_dad_start(ifp, 0); | 2115 | addrconf_dad_start(ifp, 0); |
@@ -2134,7 +2177,7 @@ ipv6_inherit_linklocal(struct inet6_dev *idev, struct net_device *link_dev) | |||
2134 | { | 2177 | { |
2135 | struct in6_addr lladdr; | 2178 | struct in6_addr lladdr; |
2136 | 2179 | ||
2137 | if (!ipv6_get_lladdr(link_dev, &lladdr)) { | 2180 | if (!ipv6_get_lladdr(link_dev, &lladdr, IFA_F_TENTATIVE)) { |
2138 | addrconf_add_linklocal(idev, &lladdr); | 2181 | addrconf_add_linklocal(idev, &lladdr); |
2139 | return 0; | 2182 | return 0; |
2140 | } | 2183 | } |
@@ -2479,7 +2522,11 @@ static void addrconf_dad_kick(struct inet6_ifaddr *ifp) | |||
2479 | unsigned long rand_num; | 2522 | unsigned long rand_num; |
2480 | struct inet6_dev *idev = ifp->idev; | 2523 | struct inet6_dev *idev = ifp->idev; |
2481 | 2524 | ||
2482 | rand_num = net_random() % (idev->cnf.rtr_solicit_delay ? : 1); | 2525 | if (ifp->flags & IFA_F_OPTIMISTIC) |
2526 | rand_num = 0; | ||
2527 | else | ||
2528 | rand_num = net_random() % (idev->cnf.rtr_solicit_delay ? : 1); | ||
2529 | |||
2483 | ifp->probes = idev->cnf.dad_transmits; | 2530 | ifp->probes = idev->cnf.dad_transmits; |
2484 | addrconf_mod_timer(ifp, AC_DAD, rand_num); | 2531 | addrconf_mod_timer(ifp, AC_DAD, rand_num); |
2485 | } | 2532 | } |
@@ -2501,7 +2548,7 @@ static void addrconf_dad_start(struct inet6_ifaddr *ifp, u32 flags) | |||
2501 | if (dev->flags&(IFF_NOARP|IFF_LOOPBACK) || | 2548 | if (dev->flags&(IFF_NOARP|IFF_LOOPBACK) || |
2502 | !(ifp->flags&IFA_F_TENTATIVE) || | 2549 | !(ifp->flags&IFA_F_TENTATIVE) || |
2503 | ifp->flags & IFA_F_NODAD) { | 2550 | ifp->flags & IFA_F_NODAD) { |
2504 | ifp->flags &= ~IFA_F_TENTATIVE; | 2551 | ifp->flags &= ~(IFA_F_TENTATIVE|IFA_F_OPTIMISTIC); |
2505 | spin_unlock_bh(&ifp->lock); | 2552 | spin_unlock_bh(&ifp->lock); |
2506 | read_unlock_bh(&idev->lock); | 2553 | read_unlock_bh(&idev->lock); |
2507 | 2554 | ||
@@ -2521,6 +2568,14 @@ static void addrconf_dad_start(struct inet6_ifaddr *ifp, u32 flags) | |||
2521 | addrconf_dad_stop(ifp); | 2568 | addrconf_dad_stop(ifp); |
2522 | return; | 2569 | return; |
2523 | } | 2570 | } |
2571 | |||
2572 | /* | ||
2573 | * Optimistic nodes can start receiving | ||
2574 | * Frames right away | ||
2575 | */ | ||
2576 | if(ifp->flags & IFA_F_OPTIMISTIC) | ||
2577 | ip6_ins_rt(ifp->rt); | ||
2578 | |||
2524 | addrconf_dad_kick(ifp); | 2579 | addrconf_dad_kick(ifp); |
2525 | spin_unlock_bh(&ifp->lock); | 2580 | spin_unlock_bh(&ifp->lock); |
2526 | out: | 2581 | out: |
@@ -2545,7 +2600,7 @@ static void addrconf_dad_timer(unsigned long data) | |||
2545 | * DAD was successful | 2600 | * DAD was successful |
2546 | */ | 2601 | */ |
2547 | 2602 | ||
2548 | ifp->flags &= ~IFA_F_TENTATIVE; | 2603 | ifp->flags &= ~(IFA_F_TENTATIVE|IFA_F_OPTIMISTIC); |
2549 | spin_unlock_bh(&ifp->lock); | 2604 | spin_unlock_bh(&ifp->lock); |
2550 | read_unlock_bh(&idev->lock); | 2605 | read_unlock_bh(&idev->lock); |
2551 | 2606 | ||
@@ -3364,6 +3419,9 @@ static inline void ipv6_store_devconf(struct ipv6_devconf *cnf, | |||
3364 | #endif | 3419 | #endif |
3365 | array[DEVCONF_PROXY_NDP] = cnf->proxy_ndp; | 3420 | array[DEVCONF_PROXY_NDP] = cnf->proxy_ndp; |
3366 | array[DEVCONF_ACCEPT_SOURCE_ROUTE] = cnf->accept_source_route; | 3421 | array[DEVCONF_ACCEPT_SOURCE_ROUTE] = cnf->accept_source_route; |
3422 | #ifdef CONFIG_IPV6_OPTIMISTIC_DAD | ||
3423 | array[DEVCONF_OPTIMISTIC_DAD] = cnf->optimistic_dad; | ||
3424 | #endif | ||
3367 | } | 3425 | } |
3368 | 3426 | ||
3369 | static inline size_t inet6_if_nlmsg_size(void) | 3427 | static inline size_t inet6_if_nlmsg_size(void) |
@@ -3578,7 +3636,14 @@ static void __ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp) | |||
3578 | 3636 | ||
3579 | switch (event) { | 3637 | switch (event) { |
3580 | case RTM_NEWADDR: | 3638 | case RTM_NEWADDR: |
3581 | ip6_ins_rt(ifp->rt); | 3639 | /* |
3640 | * If the address was optimistic | ||
3641 | * we inserted the route at the start of | ||
3642 | * our DAD process, so we don't need | ||
3643 | * to do it again | ||
3644 | */ | ||
3645 | if (!(ifp->rt->rt6i_node)) | ||
3646 | ip6_ins_rt(ifp->rt); | ||
3582 | if (ifp->idev->cnf.forwarding) | 3647 | if (ifp->idev->cnf.forwarding) |
3583 | addrconf_join_anycast(ifp); | 3648 | addrconf_join_anycast(ifp); |
3584 | break; | 3649 | break; |
@@ -3899,6 +3964,17 @@ static struct addrconf_sysctl_table | |||
3899 | .mode = 0644, | 3964 | .mode = 0644, |
3900 | .proc_handler = &proc_dointvec, | 3965 | .proc_handler = &proc_dointvec, |
3901 | }, | 3966 | }, |
3967 | #ifdef CONFIG_IPV6_OPTIMISTIC_DAD | ||
3968 | { | ||
3969 | .ctl_name = CTL_UNNUMBERED, | ||
3970 | .procname = "optimistic_dad", | ||
3971 | .data = &ipv6_devconf.optimistic_dad, | ||
3972 | .maxlen = sizeof(int), | ||
3973 | .mode = 0644, | ||
3974 | .proc_handler = &proc_dointvec, | ||
3975 | |||
3976 | }, | ||
3977 | #endif | ||
3902 | { | 3978 | { |
3903 | .ctl_name = 0, /* sentinel */ | 3979 | .ctl_name = 0, /* sentinel */ |
3904 | } | 3980 | } |
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index 0d60fbc59d8f..7e25043d826c 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c | |||
@@ -863,6 +863,41 @@ static int ip6_dst_lookup_tail(struct sock *sk, | |||
863 | goto out_err_release; | 863 | goto out_err_release; |
864 | } | 864 | } |
865 | 865 | ||
866 | #ifdef CONFIG_IPV6_OPTIMISTIC_DAD | ||
867 | /* | ||
868 | * Here if the dst entry we've looked up | ||
869 | * has a neighbour entry that is in the INCOMPLETE | ||
870 | * state and the src address from the flow is | ||
871 | * marked as OPTIMISTIC, we release the found | ||
872 | * dst entry and replace it instead with the | ||
873 | * dst entry of the nexthop router | ||
874 | */ | ||
875 | if (!((*dst)->neighbour->nud_state & NUD_VALID)) { | ||
876 | struct inet6_ifaddr *ifp; | ||
877 | struct flowi fl_gw; | ||
878 | int redirect; | ||
879 | |||
880 | ifp = ipv6_get_ifaddr(&fl->fl6_src, (*dst)->dev, 1); | ||
881 | |||
882 | redirect = (ifp && ifp->flags & IFA_F_OPTIMISTIC); | ||
883 | if (ifp) | ||
884 | in6_ifa_put(ifp); | ||
885 | |||
886 | if (redirect) { | ||
887 | /* | ||
888 | * We need to get the dst entry for the | ||
889 | * default router instead | ||
890 | */ | ||
891 | dst_release(*dst); | ||
892 | memcpy(&fl_gw, fl, sizeof(struct flowi)); | ||
893 | memset(&fl_gw.fl6_dst, 0, sizeof(struct in6_addr)); | ||
894 | *dst = ip6_route_output(sk, &fl_gw); | ||
895 | if ((err = (*dst)->error)) | ||
896 | goto out_err_release; | ||
897 | } | ||
898 | } | ||
899 | #endif | ||
900 | |||
866 | return 0; | 901 | return 0; |
867 | 902 | ||
868 | out_err_release: | 903 | out_err_release: |
diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c index a8d6625ec782..924e24907c3e 100644 --- a/net/ipv6/mcast.c +++ b/net/ipv6/mcast.c | |||
@@ -1411,7 +1411,7 @@ static struct sk_buff *mld_newpack(struct net_device *dev, int size) | |||
1411 | 1411 | ||
1412 | skb_reserve(skb, LL_RESERVED_SPACE(dev)); | 1412 | skb_reserve(skb, LL_RESERVED_SPACE(dev)); |
1413 | 1413 | ||
1414 | if (ipv6_get_lladdr(dev, &addr_buf)) { | 1414 | if (ipv6_get_lladdr(dev, &addr_buf, IFA_F_TENTATIVE)) { |
1415 | /* <draft-ietf-magma-mld-source-05.txt>: | 1415 | /* <draft-ietf-magma-mld-source-05.txt>: |
1416 | * use unspecified address as the source address | 1416 | * use unspecified address as the source address |
1417 | * when a valid link-local address is not available. | 1417 | * when a valid link-local address is not available. |
@@ -1791,7 +1791,7 @@ static void igmp6_send(struct in6_addr *addr, struct net_device *dev, int type) | |||
1791 | 1791 | ||
1792 | skb_reserve(skb, LL_RESERVED_SPACE(dev)); | 1792 | skb_reserve(skb, LL_RESERVED_SPACE(dev)); |
1793 | 1793 | ||
1794 | if (ipv6_get_lladdr(dev, &addr_buf)) { | 1794 | if (ipv6_get_lladdr(dev, &addr_buf, IFA_F_TENTATIVE)) { |
1795 | /* <draft-ietf-magma-mld-source-05.txt>: | 1795 | /* <draft-ietf-magma-mld-source-05.txt>: |
1796 | * use unspecified address as the source address | 1796 | * use unspecified address as the source address |
1797 | * when a valid link-local address is not available. | 1797 | * when a valid link-local address is not available. |
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); |