diff options
-rw-r--r-- | include/net/if_inet6.h | 1 | ||||
-rw-r--r-- | net/ipv6/addrconf.c | 74 |
2 files changed, 65 insertions, 10 deletions
diff --git a/include/net/if_inet6.h b/include/net/if_inet6.h index e97a9accb71d..d8234f9bd4c4 100644 --- a/include/net/if_inet6.h +++ b/include/net/if_inet6.h | |||
@@ -24,6 +24,7 @@ | |||
24 | #define IF_RA_MANAGED 0x40 | 24 | #define IF_RA_MANAGED 0x40 |
25 | #define IF_RA_RCVD 0x20 | 25 | #define IF_RA_RCVD 0x20 |
26 | #define IF_RS_SENT 0x10 | 26 | #define IF_RS_SENT 0x10 |
27 | #define IF_READY 0x80000000 | ||
27 | 28 | ||
28 | /* prefix flags */ | 29 | /* prefix flags */ |
29 | #define IF_PREFIX_ONLINK 0x01 | 30 | #define IF_PREFIX_ONLINK 0x01 |
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 4ea8cf7c0cc4..d012f6ac7040 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c | |||
@@ -388,6 +388,9 @@ static struct inet6_dev * ipv6_add_dev(struct net_device *dev) | |||
388 | } | 388 | } |
389 | #endif | 389 | #endif |
390 | 390 | ||
391 | if (netif_carrier_ok(dev)) | ||
392 | ndev->if_flags |= IF_READY; | ||
393 | |||
391 | write_lock_bh(&addrconf_lock); | 394 | write_lock_bh(&addrconf_lock); |
392 | dev->ip6_ptr = ndev; | 395 | dev->ip6_ptr = ndev; |
393 | write_unlock_bh(&addrconf_lock); | 396 | write_unlock_bh(&addrconf_lock); |
@@ -1215,10 +1218,8 @@ int ipv6_rcv_saddr_equal(const struct sock *sk, const struct sock *sk2) | |||
1215 | 1218 | ||
1216 | /* Gets referenced address, destroys ifaddr */ | 1219 | /* Gets referenced address, destroys ifaddr */ |
1217 | 1220 | ||
1218 | void addrconf_dad_failure(struct inet6_ifaddr *ifp) | 1221 | void addrconf_dad_stop(struct inet6_ifaddr *ifp) |
1219 | { | 1222 | { |
1220 | if (net_ratelimit()) | ||
1221 | printk(KERN_INFO "%s: duplicate address detected!\n", ifp->idev->dev->name); | ||
1222 | if (ifp->flags&IFA_F_PERMANENT) { | 1223 | if (ifp->flags&IFA_F_PERMANENT) { |
1223 | spin_lock_bh(&ifp->lock); | 1224 | spin_lock_bh(&ifp->lock); |
1224 | addrconf_del_timer(ifp); | 1225 | addrconf_del_timer(ifp); |
@@ -1244,6 +1245,12 @@ void addrconf_dad_failure(struct inet6_ifaddr *ifp) | |||
1244 | ipv6_del_addr(ifp); | 1245 | ipv6_del_addr(ifp); |
1245 | } | 1246 | } |
1246 | 1247 | ||
1248 | void addrconf_dad_failure(struct inet6_ifaddr *ifp) | ||
1249 | { | ||
1250 | if (net_ratelimit()) | ||
1251 | printk(KERN_INFO "%s: duplicate address detected!\n", ifp->idev->dev->name); | ||
1252 | addrconf_dad_stop(ifp); | ||
1253 | } | ||
1247 | 1254 | ||
1248 | /* Join to solicited addr multicast group. */ | 1255 | /* Join to solicited addr multicast group. */ |
1249 | 1256 | ||
@@ -2136,6 +2143,37 @@ static int addrconf_notify(struct notifier_block *this, unsigned long event, | |||
2136 | 2143 | ||
2137 | switch(event) { | 2144 | switch(event) { |
2138 | case NETDEV_UP: | 2145 | case NETDEV_UP: |
2146 | case NETDEV_CHANGE: | ||
2147 | if (event == NETDEV_UP) { | ||
2148 | if (!netif_carrier_ok(dev)) { | ||
2149 | /* device is not ready yet. */ | ||
2150 | printk(KERN_INFO | ||
2151 | "ADDRCONF(NETDEV_UP): %s: " | ||
2152 | "link is not ready\n", | ||
2153 | dev->name); | ||
2154 | break; | ||
2155 | } | ||
2156 | } else { | ||
2157 | if (!netif_carrier_ok(dev)) { | ||
2158 | /* device is still not ready. */ | ||
2159 | break; | ||
2160 | } | ||
2161 | |||
2162 | if (idev) { | ||
2163 | if (idev->if_flags & IF_READY) { | ||
2164 | /* device is already configured. */ | ||
2165 | break; | ||
2166 | } | ||
2167 | idev->if_flags |= IF_READY; | ||
2168 | } | ||
2169 | |||
2170 | printk(KERN_INFO | ||
2171 | "ADDRCONF(NETDEV_CHANGE): %s: " | ||
2172 | "link becomes ready\n", | ||
2173 | dev->name); | ||
2174 | |||
2175 | } | ||
2176 | |||
2139 | switch(dev->type) { | 2177 | switch(dev->type) { |
2140 | case ARPHRD_SIT: | 2178 | case ARPHRD_SIT: |
2141 | addrconf_sit_config(dev); | 2179 | addrconf_sit_config(dev); |
@@ -2186,8 +2224,7 @@ static int addrconf_notify(struct notifier_block *this, unsigned long event, | |||
2186 | */ | 2224 | */ |
2187 | addrconf_ifdown(dev, event != NETDEV_DOWN); | 2225 | addrconf_ifdown(dev, event != NETDEV_DOWN); |
2188 | break; | 2226 | break; |
2189 | case NETDEV_CHANGE: | 2227 | |
2190 | break; | ||
2191 | case NETDEV_CHANGENAME: | 2228 | case NETDEV_CHANGENAME: |
2192 | #ifdef CONFIG_SYSCTL | 2229 | #ifdef CONFIG_SYSCTL |
2193 | if (idev) { | 2230 | if (idev) { |
@@ -2268,7 +2305,7 @@ static int addrconf_ifdown(struct net_device *dev, int how) | |||
2268 | 2305 | ||
2269 | /* Step 3: clear flags for stateless addrconf */ | 2306 | /* Step 3: clear flags for stateless addrconf */ |
2270 | if (how != 1) | 2307 | if (how != 1) |
2271 | idev->if_flags &= ~(IF_RS_SENT|IF_RA_RCVD); | 2308 | idev->if_flags &= ~(IF_RS_SENT|IF_RA_RCVD|IF_READY); |
2272 | 2309 | ||
2273 | /* Step 4: clear address list */ | 2310 | /* Step 4: clear address list */ |
2274 | #ifdef CONFIG_IPV6_PRIVACY | 2311 | #ifdef CONFIG_IPV6_PRIVACY |
@@ -2377,11 +2414,20 @@ out: | |||
2377 | /* | 2414 | /* |
2378 | * Duplicate Address Detection | 2415 | * Duplicate Address Detection |
2379 | */ | 2416 | */ |
2417 | static void addrconf_dad_kick(struct inet6_ifaddr *ifp) | ||
2418 | { | ||
2419 | unsigned long rand_num; | ||
2420 | struct inet6_dev *idev = ifp->idev; | ||
2421 | |||
2422 | rand_num = net_random() % (idev->cnf.rtr_solicit_delay ? : 1); | ||
2423 | ifp->probes = idev->cnf.dad_transmits; | ||
2424 | addrconf_mod_timer(ifp, AC_DAD, rand_num); | ||
2425 | } | ||
2426 | |||
2380 | static void addrconf_dad_start(struct inet6_ifaddr *ifp, u32 flags) | 2427 | static void addrconf_dad_start(struct inet6_ifaddr *ifp, u32 flags) |
2381 | { | 2428 | { |
2382 | struct inet6_dev *idev = ifp->idev; | 2429 | struct inet6_dev *idev = ifp->idev; |
2383 | struct net_device *dev = idev->dev; | 2430 | struct net_device *dev = idev->dev; |
2384 | unsigned long rand_num; | ||
2385 | 2431 | ||
2386 | addrconf_join_solict(dev, &ifp->addr); | 2432 | addrconf_join_solict(dev, &ifp->addr); |
2387 | 2433 | ||
@@ -2390,7 +2436,6 @@ static void addrconf_dad_start(struct inet6_ifaddr *ifp, u32 flags) | |||
2390 | flags); | 2436 | flags); |
2391 | 2437 | ||
2392 | net_srandom(ifp->addr.s6_addr32[3]); | 2438 | net_srandom(ifp->addr.s6_addr32[3]); |
2393 | rand_num = net_random() % (idev->cnf.rtr_solicit_delay ? : 1); | ||
2394 | 2439 | ||
2395 | read_lock_bh(&idev->lock); | 2440 | read_lock_bh(&idev->lock); |
2396 | if (ifp->dead) | 2441 | if (ifp->dead) |
@@ -2407,8 +2452,17 @@ static void addrconf_dad_start(struct inet6_ifaddr *ifp, u32 flags) | |||
2407 | return; | 2452 | return; |
2408 | } | 2453 | } |
2409 | 2454 | ||
2410 | ifp->probes = idev->cnf.dad_transmits; | 2455 | if (idev->if_flags & IF_READY) |
2411 | addrconf_mod_timer(ifp, AC_DAD, rand_num); | 2456 | addrconf_dad_kick(ifp); |
2457 | else { | ||
2458 | /* | ||
2459 | * If the defice is not ready: | ||
2460 | * - keep it tentative if it is a permanent address. | ||
2461 | * - otherwise, kill it. | ||
2462 | */ | ||
2463 | in6_ifa_hold(ifp); | ||
2464 | addrconf_dad_stop(ifp); | ||
2465 | } | ||
2412 | 2466 | ||
2413 | spin_unlock_bh(&ifp->lock); | 2467 | spin_unlock_bh(&ifp->lock); |
2414 | out: | 2468 | out: |