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); |
