aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorYOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>2005-12-21 08:57:24 -0500
committerYOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>2005-12-21 08:57:24 -0500
commit3c21edbd113788b110116141c8078623a0900b6a (patch)
treeb6d7cc0655f0965725e6b3a025724ea018c53c4a
parent8de3351e6e0a1081fbf6864ae37839e327699a08 (diff)
[IPV6]: Defer IPv6 device initialization until the link becomes ready.
NETDEV_UP might be sent even if the link attached to the interface was not ready. DAD does not make sense in such case, so we won't do so. After interface Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
-rw-r--r--include/net/if_inet6.h1
-rw-r--r--net/ipv6/addrconf.c74
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
1218void addrconf_dad_failure(struct inet6_ifaddr *ifp) 1221void 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
1248void 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 */
2417static 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
2380static void addrconf_dad_start(struct inet6_ifaddr *ifp, u32 flags) 2427static 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);
2414out: 2468out: