|
@@ -530,6 +530,16 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, int pfxlen,
|
|
|
|
|
|
ifa->rt = rt;
|
|
|
|
|
|
+ /*
|
|
|
+ * part one of RFC 4429, section 3.3
|
|
|
+ * We should not configure an address as
|
|
|
+ * optimistic if we do not yet know the link
|
|
|
+ * layer address of our nexhop router
|
|
|
+ */
|
|
|
+
|
|
|
+ if (rt->rt6i_nexthop == NULL)
|
|
|
+ ifa->flags &= ~IFA_F_OPTIMISTIC;
|
|
|
+
|
|
|
ifa->idev = idev;
|
|
|
in6_dev_hold(idev);
|
|
|
/* For caller */
|
|
@@ -706,6 +716,7 @@ static int ipv6_create_tempaddr(struct inet6_ifaddr *ifp, struct inet6_ifaddr *i
|
|
|
int tmp_plen;
|
|
|
int ret = 0;
|
|
|
int max_addresses;
|
|
|
+ u32 addr_flags;
|
|
|
|
|
|
write_lock(&idev->lock);
|
|
|
if (ift) {
|
|
@@ -763,10 +774,17 @@ retry:
|
|
|
spin_unlock_bh(&ifp->lock);
|
|
|
|
|
|
write_unlock(&idev->lock);
|
|
|
+
|
|
|
+ addr_flags = IFA_F_TEMPORARY;
|
|
|
+ /* set in addrconf_prefix_rcv() */
|
|
|
+ if (ifp->flags & IFA_F_OPTIMISTIC)
|
|
|
+ addr_flags |= IFA_F_OPTIMISTIC;
|
|
|
+
|
|
|
ift = !max_addresses ||
|
|
|
ipv6_count_addresses(idev) < max_addresses ?
|
|
|
ipv6_add_addr(idev, &addr, tmp_plen,
|
|
|
- ipv6_addr_type(&addr)&IPV6_ADDR_SCOPE_MASK, IFA_F_TEMPORARY) : NULL;
|
|
|
+ ipv6_addr_type(&addr)&IPV6_ADDR_SCOPE_MASK,
|
|
|
+ addr_flags) : NULL;
|
|
|
if (!ift || IS_ERR(ift)) {
|
|
|
in6_ifa_put(ifp);
|
|
|
in6_dev_put(idev);
|
|
@@ -898,13 +916,14 @@ int ipv6_dev_get_saddr(struct net_device *daddr_dev,
|
|
|
* - Tentative Address (RFC2462 section 5.4)
|
|
|
* - A tentative address is not considered
|
|
|
* "assigned to an interface" in the traditional
|
|
|
- * sense.
|
|
|
+ * sense, unless it is also flagged as optimistic.
|
|
|
* - Candidate Source Address (section 4)
|
|
|
* - In any case, anycast addresses, multicast
|
|
|
* addresses, and the unspecified address MUST
|
|
|
* NOT be included in a candidate set.
|
|
|
*/
|
|
|
- if (ifa->flags & IFA_F_TENTATIVE)
|
|
|
+ if ((ifa->flags & IFA_F_TENTATIVE) &&
|
|
|
+ (!(ifa->flags & IFA_F_OPTIMISTIC)))
|
|
|
continue;
|
|
|
if (unlikely(score.addr_type == IPV6_ADDR_ANY ||
|
|
|
score.addr_type & IPV6_ADDR_MULTICAST)) {
|
|
@@ -963,15 +982,17 @@ int ipv6_dev_get_saddr(struct net_device *daddr_dev,
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- /* Rule 3: Avoid deprecated address */
|
|
|
+ /* Rule 3: Avoid deprecated and optimistic addresses */
|
|
|
if (hiscore.rule < 3) {
|
|
|
if (ipv6_saddr_preferred(hiscore.addr_type) ||
|
|
|
- !(ifa_result->flags & IFA_F_DEPRECATED))
|
|
|
+ (((ifa_result->flags &
|
|
|
+ (IFA_F_DEPRECATED|IFA_F_OPTIMISTIC)) == 0)))
|
|
|
hiscore.attrs |= IPV6_SADDR_SCORE_PREFERRED;
|
|
|
hiscore.rule++;
|
|
|
}
|
|
|
if (ipv6_saddr_preferred(score.addr_type) ||
|
|
|
- !(ifa->flags & IFA_F_DEPRECATED)) {
|
|
|
+ (((ifa_result->flags &
|
|
|
+ (IFA_F_DEPRECATED|IFA_F_OPTIMISTIC)) == 0))) {
|
|
|
score.attrs |= IPV6_SADDR_SCORE_PREFERRED;
|
|
|
if (!(hiscore.attrs & IPV6_SADDR_SCORE_PREFERRED)) {
|
|
|
score.rule = 3;
|
|
@@ -1111,7 +1132,8 @@ int ipv6_get_saddr(struct dst_entry *dst,
|
|
|
|
|
|
EXPORT_SYMBOL(ipv6_get_saddr);
|
|
|
|
|
|
-int ipv6_get_lladdr(struct net_device *dev, struct in6_addr *addr)
|
|
|
+int ipv6_get_lladdr(struct net_device *dev, struct in6_addr *addr,
|
|
|
+ unsigned char banned_flags)
|
|
|
{
|
|
|
struct inet6_dev *idev;
|
|
|
int err = -EADDRNOTAVAIL;
|
|
@@ -1122,7 +1144,7 @@ int ipv6_get_lladdr(struct net_device *dev, struct in6_addr *addr)
|
|
|
|
|
|
read_lock_bh(&idev->lock);
|
|
|
for (ifp=idev->addr_list; ifp; ifp=ifp->if_next) {
|
|
|
- if (ifp->scope == IFA_LINK && !(ifp->flags&IFA_F_TENTATIVE)) {
|
|
|
+ if (ifp->scope == IFA_LINK && !(ifp->flags & banned_flags)) {
|
|
|
ipv6_addr_copy(addr, &ifp->addr);
|
|
|
err = 0;
|
|
|
break;
|
|
@@ -1674,6 +1696,13 @@ ok:
|
|
|
|
|
|
if (ifp == NULL && valid_lft) {
|
|
|
int max_addresses = in6_dev->cnf.max_addresses;
|
|
|
+ u32 addr_flags = 0;
|
|
|
+
|
|
|
+#ifdef CONFIG_IPV6_OPTIMISTIC_DAD
|
|
|
+ if (in6_dev->cnf.optimistic_dad &&
|
|
|
+ !ipv6_devconf.forwarding)
|
|
|
+ addr_flags = IFA_F_OPTIMISTIC;
|
|
|
+#endif
|
|
|
|
|
|
/* Do not allow to create too much of autoconfigured
|
|
|
* addresses; this would be too easy way to crash kernel.
|
|
@@ -1681,7 +1710,8 @@ ok:
|
|
|
if (!max_addresses ||
|
|
|
ipv6_count_addresses(in6_dev) < max_addresses)
|
|
|
ifp = ipv6_add_addr(in6_dev, &addr, pinfo->prefix_len,
|
|
|
- addr_type&IPV6_ADDR_SCOPE_MASK, 0);
|
|
|
+ addr_type&IPV6_ADDR_SCOPE_MASK,
|
|
|
+ addr_flags);
|
|
|
|
|
|
if (!ifp || IS_ERR(ifp)) {
|
|
|
in6_dev_put(in6_dev);
|
|
@@ -1889,6 +1919,11 @@ static int inet6_addr_add(int ifindex, struct in6_addr *pfx, int plen,
|
|
|
|
|
|
addrconf_prefix_route(&ifp->addr, ifp->prefix_len, dev,
|
|
|
jiffies_to_clock_t(valid_lft * HZ), flags);
|
|
|
+ /*
|
|
|
+ * Note that section 3.1 of RFC 4429 indicates
|
|
|
+ * that the Optimistic flag should not be set for
|
|
|
+ * manually configured addresses
|
|
|
+ */
|
|
|
addrconf_dad_start(ifp, 0);
|
|
|
in6_ifa_put(ifp);
|
|
|
addrconf_verify(0);
|
|
@@ -2065,8 +2100,16 @@ static void init_loopback(struct net_device *dev)
|
|
|
static void addrconf_add_linklocal(struct inet6_dev *idev, struct in6_addr *addr)
|
|
|
{
|
|
|
struct inet6_ifaddr * ifp;
|
|
|
+ u32 addr_flags = IFA_F_PERMANENT;
|
|
|
+
|
|
|
+#ifdef CONFIG_IPV6_OPTIMISTIC_DAD
|
|
|
+ if (idev->cnf.optimistic_dad &&
|
|
|
+ !ipv6_devconf.forwarding)
|
|
|
+ addr_flags |= IFA_F_OPTIMISTIC;
|
|
|
+#endif
|
|
|
|
|
|
- ifp = ipv6_add_addr(idev, addr, 64, IFA_LINK, IFA_F_PERMANENT);
|
|
|
+
|
|
|
+ ifp = ipv6_add_addr(idev, addr, 64, IFA_LINK, addr_flags);
|
|
|
if (!IS_ERR(ifp)) {
|
|
|
addrconf_prefix_route(&ifp->addr, ifp->prefix_len, idev->dev, 0, 0);
|
|
|
addrconf_dad_start(ifp, 0);
|
|
@@ -2134,7 +2177,7 @@ ipv6_inherit_linklocal(struct inet6_dev *idev, struct net_device *link_dev)
|
|
|
{
|
|
|
struct in6_addr lladdr;
|
|
|
|
|
|
- if (!ipv6_get_lladdr(link_dev, &lladdr)) {
|
|
|
+ if (!ipv6_get_lladdr(link_dev, &lladdr, IFA_F_TENTATIVE)) {
|
|
|
addrconf_add_linklocal(idev, &lladdr);
|
|
|
return 0;
|
|
|
}
|
|
@@ -2479,7 +2522,11 @@ static void addrconf_dad_kick(struct inet6_ifaddr *ifp)
|
|
|
unsigned long rand_num;
|
|
|
struct inet6_dev *idev = ifp->idev;
|
|
|
|
|
|
- rand_num = net_random() % (idev->cnf.rtr_solicit_delay ? : 1);
|
|
|
+ if (ifp->flags & IFA_F_OPTIMISTIC)
|
|
|
+ rand_num = 0;
|
|
|
+ else
|
|
|
+ rand_num = net_random() % (idev->cnf.rtr_solicit_delay ? : 1);
|
|
|
+
|
|
|
ifp->probes = idev->cnf.dad_transmits;
|
|
|
addrconf_mod_timer(ifp, AC_DAD, rand_num);
|
|
|
}
|
|
@@ -2501,7 +2548,7 @@ static void addrconf_dad_start(struct inet6_ifaddr *ifp, u32 flags)
|
|
|
if (dev->flags&(IFF_NOARP|IFF_LOOPBACK) ||
|
|
|
!(ifp->flags&IFA_F_TENTATIVE) ||
|
|
|
ifp->flags & IFA_F_NODAD) {
|
|
|
- ifp->flags &= ~IFA_F_TENTATIVE;
|
|
|
+ ifp->flags &= ~(IFA_F_TENTATIVE|IFA_F_OPTIMISTIC);
|
|
|
spin_unlock_bh(&ifp->lock);
|
|
|
read_unlock_bh(&idev->lock);
|
|
|
|
|
@@ -2521,6 +2568,14 @@ static void addrconf_dad_start(struct inet6_ifaddr *ifp, u32 flags)
|
|
|
addrconf_dad_stop(ifp);
|
|
|
return;
|
|
|
}
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Optimistic nodes can start receiving
|
|
|
+ * Frames right away
|
|
|
+ */
|
|
|
+ if(ifp->flags & IFA_F_OPTIMISTIC)
|
|
|
+ ip6_ins_rt(ifp->rt);
|
|
|
+
|
|
|
addrconf_dad_kick(ifp);
|
|
|
spin_unlock_bh(&ifp->lock);
|
|
|
out:
|
|
@@ -2545,7 +2600,7 @@ static void addrconf_dad_timer(unsigned long data)
|
|
|
* DAD was successful
|
|
|
*/
|
|
|
|
|
|
- ifp->flags &= ~IFA_F_TENTATIVE;
|
|
|
+ ifp->flags &= ~(IFA_F_TENTATIVE|IFA_F_OPTIMISTIC);
|
|
|
spin_unlock_bh(&ifp->lock);
|
|
|
read_unlock_bh(&idev->lock);
|
|
|
|
|
@@ -3364,6 +3419,9 @@ static inline void ipv6_store_devconf(struct ipv6_devconf *cnf,
|
|
|
#endif
|
|
|
array[DEVCONF_PROXY_NDP] = cnf->proxy_ndp;
|
|
|
array[DEVCONF_ACCEPT_SOURCE_ROUTE] = cnf->accept_source_route;
|
|
|
+#ifdef CONFIG_IPV6_OPTIMISTIC_DAD
|
|
|
+ array[DEVCONF_OPTIMISTIC_DAD] = cnf->optimistic_dad;
|
|
|
+#endif
|
|
|
}
|
|
|
|
|
|
static inline size_t inet6_if_nlmsg_size(void)
|
|
@@ -3578,7 +3636,14 @@ static void __ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp)
|
|
|
|
|
|
switch (event) {
|
|
|
case RTM_NEWADDR:
|
|
|
- ip6_ins_rt(ifp->rt);
|
|
|
+ /*
|
|
|
+ * If the address was optimistic
|
|
|
+ * we inserted the route at the start of
|
|
|
+ * our DAD process, so we don't need
|
|
|
+ * to do it again
|
|
|
+ */
|
|
|
+ if (!(ifp->rt->rt6i_node))
|
|
|
+ ip6_ins_rt(ifp->rt);
|
|
|
if (ifp->idev->cnf.forwarding)
|
|
|
addrconf_join_anycast(ifp);
|
|
|
break;
|
|
@@ -3899,6 +3964,17 @@ static struct addrconf_sysctl_table
|
|
|
.mode = 0644,
|
|
|
.proc_handler = &proc_dointvec,
|
|
|
},
|
|
|
+#ifdef CONFIG_IPV6_OPTIMISTIC_DAD
|
|
|
+ {
|
|
|
+ .ctl_name = CTL_UNNUMBERED,
|
|
|
+ .procname = "optimistic_dad",
|
|
|
+ .data = &ipv6_devconf.optimistic_dad,
|
|
|
+ .maxlen = sizeof(int),
|
|
|
+ .mode = 0644,
|
|
|
+ .proc_handler = &proc_dointvec,
|
|
|
+
|
|
|
+ },
|
|
|
+#endif
|
|
|
{
|
|
|
.ctl_name = 0, /* sentinel */
|
|
|
}
|