diff options
author | David S. Miller <davem@sunset.davemloft.net> | 2005-12-22 10:41:27 -0500 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2005-12-22 10:41:27 -0500 |
commit | e6469297d4eecfd9f46929fe1f56a01141cb0791 (patch) | |
tree | 9cdd368a9c5e02c177e54edcfd8bcc06155526a9 | |
parent | 9b78a82c1cf19aa813bdaa184fa840a3ba811750 (diff) | |
parent | 6b3ae80a63e47f6e97d68a1ddd520e3509e62821 (diff) |
Merge git://git.skbuff.net/gitroot/yoshfuji/linux-2.6.14+git+ipv6-fix-20051221a
-rw-r--r-- | include/linux/ipv6_route.h | 1 | ||||
-rw-r--r-- | include/net/if_inet6.h | 1 | ||||
-rw-r--r-- | net/ipv6/addrconf.c | 106 | ||||
-rw-r--r-- | net/ipv6/icmp.c | 16 | ||||
-rw-r--r-- | net/ipv6/route.c | 13 |
5 files changed, 120 insertions, 17 deletions
diff --git a/include/linux/ipv6_route.h b/include/linux/ipv6_route.h index e2f935038013..d7c41d1d706a 100644 --- a/include/linux/ipv6_route.h +++ b/include/linux/ipv6_route.h | |||
@@ -18,6 +18,7 @@ | |||
18 | fallback, no routers on link */ | 18 | fallback, no routers on link */ |
19 | #define RTF_ADDRCONF 0x00040000 /* addrconf route - RA */ | 19 | #define RTF_ADDRCONF 0x00040000 /* addrconf route - RA */ |
20 | #define RTF_PREFIX_RT 0x00080000 /* A prefix only route - RA */ | 20 | #define RTF_PREFIX_RT 0x00080000 /* A prefix only route - RA */ |
21 | #define RTF_ANYCAST 0x00100000 /* Anycast */ | ||
21 | 22 | ||
22 | #define RTF_NONEXTHOP 0x00200000 /* route with no nexthop */ | 23 | #define RTF_NONEXTHOP 0x00200000 /* route with no nexthop */ |
23 | #define RTF_EXPIRES 0x00400000 | 24 | #define RTF_EXPIRES 0x00400000 |
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 e717a034c953..510220f2ae8b 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c | |||
@@ -137,6 +137,7 @@ static int addrconf_ifdown(struct net_device *dev, int how); | |||
137 | static void addrconf_dad_start(struct inet6_ifaddr *ifp, u32 flags); | 137 | static void addrconf_dad_start(struct inet6_ifaddr *ifp, u32 flags); |
138 | static void addrconf_dad_timer(unsigned long data); | 138 | static void addrconf_dad_timer(unsigned long data); |
139 | static void addrconf_dad_completed(struct inet6_ifaddr *ifp); | 139 | static void addrconf_dad_completed(struct inet6_ifaddr *ifp); |
140 | static void addrconf_dad_run(struct inet6_dev *idev); | ||
140 | static void addrconf_rs_timer(unsigned long data); | 141 | static void addrconf_rs_timer(unsigned long data); |
141 | static void __ipv6_ifa_notify(int event, struct inet6_ifaddr *ifa); | 142 | static void __ipv6_ifa_notify(int event, struct inet6_ifaddr *ifa); |
142 | static void ipv6_ifa_notify(int event, struct inet6_ifaddr *ifa); | 143 | static void ipv6_ifa_notify(int event, struct inet6_ifaddr *ifa); |
@@ -388,6 +389,9 @@ static struct inet6_dev * ipv6_add_dev(struct net_device *dev) | |||
388 | } | 389 | } |
389 | #endif | 390 | #endif |
390 | 391 | ||
392 | if (netif_carrier_ok(dev)) | ||
393 | ndev->if_flags |= IF_READY; | ||
394 | |||
391 | write_lock_bh(&addrconf_lock); | 395 | write_lock_bh(&addrconf_lock); |
392 | dev->ip6_ptr = ndev; | 396 | dev->ip6_ptr = ndev; |
393 | write_unlock_bh(&addrconf_lock); | 397 | write_unlock_bh(&addrconf_lock); |
@@ -415,6 +419,7 @@ static struct inet6_dev * ipv6_find_idev(struct net_device *dev) | |||
415 | if ((idev = ipv6_add_dev(dev)) == NULL) | 419 | if ((idev = ipv6_add_dev(dev)) == NULL) |
416 | return NULL; | 420 | return NULL; |
417 | } | 421 | } |
422 | |||
418 | if (dev->flags&IFF_UP) | 423 | if (dev->flags&IFF_UP) |
419 | ipv6_mc_up(idev); | 424 | ipv6_mc_up(idev); |
420 | return idev; | 425 | return idev; |
@@ -904,11 +909,18 @@ int ipv6_dev_get_saddr(struct net_device *daddr_dev, | |||
904 | 909 | ||
905 | score.addr_type = __ipv6_addr_type(&ifa->addr); | 910 | score.addr_type = __ipv6_addr_type(&ifa->addr); |
906 | 911 | ||
907 | /* Rule 0: Candidate Source Address (section 4) | 912 | /* Rule 0: |
913 | * - Tentative Address (RFC2462 section 5.4) | ||
914 | * - A tentative address is not considered | ||
915 | * "assigned to an interface" in the traditional | ||
916 | * sense. | ||
917 | * - Candidate Source Address (section 4) | ||
908 | * - In any case, anycast addresses, multicast | 918 | * - In any case, anycast addresses, multicast |
909 | * addresses, and the unspecified address MUST | 919 | * addresses, and the unspecified address MUST |
910 | * NOT be included in a candidate set. | 920 | * NOT be included in a candidate set. |
911 | */ | 921 | */ |
922 | if (ifa->flags & IFA_F_TENTATIVE) | ||
923 | continue; | ||
912 | if (unlikely(score.addr_type == IPV6_ADDR_ANY || | 924 | if (unlikely(score.addr_type == IPV6_ADDR_ANY || |
913 | score.addr_type & IPV6_ADDR_MULTICAST)) { | 925 | score.addr_type & IPV6_ADDR_MULTICAST)) { |
914 | LIMIT_NETDEBUG(KERN_DEBUG | 926 | LIMIT_NETDEBUG(KERN_DEBUG |
@@ -1216,10 +1228,8 @@ int ipv6_rcv_saddr_equal(const struct sock *sk, const struct sock *sk2) | |||
1216 | 1228 | ||
1217 | /* Gets referenced address, destroys ifaddr */ | 1229 | /* Gets referenced address, destroys ifaddr */ |
1218 | 1230 | ||
1219 | void addrconf_dad_failure(struct inet6_ifaddr *ifp) | 1231 | void addrconf_dad_stop(struct inet6_ifaddr *ifp) |
1220 | { | 1232 | { |
1221 | if (net_ratelimit()) | ||
1222 | printk(KERN_INFO "%s: duplicate address detected!\n", ifp->idev->dev->name); | ||
1223 | if (ifp->flags&IFA_F_PERMANENT) { | 1233 | if (ifp->flags&IFA_F_PERMANENT) { |
1224 | spin_lock_bh(&ifp->lock); | 1234 | spin_lock_bh(&ifp->lock); |
1225 | addrconf_del_timer(ifp); | 1235 | addrconf_del_timer(ifp); |
@@ -1245,6 +1255,12 @@ void addrconf_dad_failure(struct inet6_ifaddr *ifp) | |||
1245 | ipv6_del_addr(ifp); | 1255 | ipv6_del_addr(ifp); |
1246 | } | 1256 | } |
1247 | 1257 | ||
1258 | void addrconf_dad_failure(struct inet6_ifaddr *ifp) | ||
1259 | { | ||
1260 | if (net_ratelimit()) | ||
1261 | printk(KERN_INFO "%s: duplicate address detected!\n", ifp->idev->dev->name); | ||
1262 | addrconf_dad_stop(ifp); | ||
1263 | } | ||
1248 | 1264 | ||
1249 | /* Join to solicited addr multicast group. */ | 1265 | /* Join to solicited addr multicast group. */ |
1250 | 1266 | ||
@@ -2134,9 +2150,42 @@ static int addrconf_notify(struct notifier_block *this, unsigned long event, | |||
2134 | { | 2150 | { |
2135 | struct net_device *dev = (struct net_device *) data; | 2151 | struct net_device *dev = (struct net_device *) data; |
2136 | struct inet6_dev *idev = __in6_dev_get(dev); | 2152 | struct inet6_dev *idev = __in6_dev_get(dev); |
2153 | int run_pending = 0; | ||
2137 | 2154 | ||
2138 | switch(event) { | 2155 | switch(event) { |
2139 | case NETDEV_UP: | 2156 | case NETDEV_UP: |
2157 | case NETDEV_CHANGE: | ||
2158 | if (event == NETDEV_UP) { | ||
2159 | if (!netif_carrier_ok(dev)) { | ||
2160 | /* device is not ready yet. */ | ||
2161 | printk(KERN_INFO | ||
2162 | "ADDRCONF(NETDEV_UP): %s: " | ||
2163 | "link is not ready\n", | ||
2164 | dev->name); | ||
2165 | break; | ||
2166 | } | ||
2167 | } else { | ||
2168 | if (!netif_carrier_ok(dev)) { | ||
2169 | /* device is still not ready. */ | ||
2170 | break; | ||
2171 | } | ||
2172 | |||
2173 | if (idev) { | ||
2174 | if (idev->if_flags & IF_READY) { | ||
2175 | /* device is already configured. */ | ||
2176 | break; | ||
2177 | } | ||
2178 | idev->if_flags |= IF_READY; | ||
2179 | } | ||
2180 | |||
2181 | printk(KERN_INFO | ||
2182 | "ADDRCONF(NETDEV_CHANGE): %s: " | ||
2183 | "link becomes ready\n", | ||
2184 | dev->name); | ||
2185 | |||
2186 | run_pending = 1; | ||
2187 | } | ||
2188 | |||
2140 | switch(dev->type) { | 2189 | switch(dev->type) { |
2141 | case ARPHRD_SIT: | 2190 | case ARPHRD_SIT: |
2142 | addrconf_sit_config(dev); | 2191 | addrconf_sit_config(dev); |
@@ -2153,6 +2202,9 @@ static int addrconf_notify(struct notifier_block *this, unsigned long event, | |||
2153 | break; | 2202 | break; |
2154 | }; | 2203 | }; |
2155 | if (idev) { | 2204 | if (idev) { |
2205 | if (run_pending) | ||
2206 | addrconf_dad_run(idev); | ||
2207 | |||
2156 | /* If the MTU changed during the interface down, when the | 2208 | /* If the MTU changed during the interface down, when the |
2157 | interface up, the changed MTU must be reflected in the | 2209 | interface up, the changed MTU must be reflected in the |
2158 | idev as well as routers. | 2210 | idev as well as routers. |
@@ -2187,8 +2239,7 @@ static int addrconf_notify(struct notifier_block *this, unsigned long event, | |||
2187 | */ | 2239 | */ |
2188 | addrconf_ifdown(dev, event != NETDEV_DOWN); | 2240 | addrconf_ifdown(dev, event != NETDEV_DOWN); |
2189 | break; | 2241 | break; |
2190 | case NETDEV_CHANGE: | 2242 | |
2191 | break; | ||
2192 | case NETDEV_CHANGENAME: | 2243 | case NETDEV_CHANGENAME: |
2193 | #ifdef CONFIG_SYSCTL | 2244 | #ifdef CONFIG_SYSCTL |
2194 | if (idev) { | 2245 | if (idev) { |
@@ -2269,7 +2320,7 @@ static int addrconf_ifdown(struct net_device *dev, int how) | |||
2269 | 2320 | ||
2270 | /* Step 3: clear flags for stateless addrconf */ | 2321 | /* Step 3: clear flags for stateless addrconf */ |
2271 | if (how != 1) | 2322 | if (how != 1) |
2272 | idev->if_flags &= ~(IF_RS_SENT|IF_RA_RCVD); | 2323 | idev->if_flags &= ~(IF_RS_SENT|IF_RA_RCVD|IF_READY); |
2273 | 2324 | ||
2274 | /* Step 4: clear address list */ | 2325 | /* Step 4: clear address list */ |
2275 | #ifdef CONFIG_IPV6_PRIVACY | 2326 | #ifdef CONFIG_IPV6_PRIVACY |
@@ -2378,11 +2429,20 @@ out: | |||
2378 | /* | 2429 | /* |
2379 | * Duplicate Address Detection | 2430 | * Duplicate Address Detection |
2380 | */ | 2431 | */ |
2432 | static void addrconf_dad_kick(struct inet6_ifaddr *ifp) | ||
2433 | { | ||
2434 | unsigned long rand_num; | ||
2435 | struct inet6_dev *idev = ifp->idev; | ||
2436 | |||
2437 | rand_num = net_random() % (idev->cnf.rtr_solicit_delay ? : 1); | ||
2438 | ifp->probes = idev->cnf.dad_transmits; | ||
2439 | addrconf_mod_timer(ifp, AC_DAD, rand_num); | ||
2440 | } | ||
2441 | |||
2381 | static void addrconf_dad_start(struct inet6_ifaddr *ifp, u32 flags) | 2442 | static void addrconf_dad_start(struct inet6_ifaddr *ifp, u32 flags) |
2382 | { | 2443 | { |
2383 | struct inet6_dev *idev = ifp->idev; | 2444 | struct inet6_dev *idev = ifp->idev; |
2384 | struct net_device *dev = idev->dev; | 2445 | struct net_device *dev = idev->dev; |
2385 | unsigned long rand_num; | ||
2386 | 2446 | ||
2387 | addrconf_join_solict(dev, &ifp->addr); | 2447 | addrconf_join_solict(dev, &ifp->addr); |
2388 | 2448 | ||
@@ -2391,7 +2451,6 @@ static void addrconf_dad_start(struct inet6_ifaddr *ifp, u32 flags) | |||
2391 | flags); | 2451 | flags); |
2392 | 2452 | ||
2393 | net_srandom(ifp->addr.s6_addr32[3]); | 2453 | net_srandom(ifp->addr.s6_addr32[3]); |
2394 | rand_num = net_random() % (idev->cnf.rtr_solicit_delay ? : 1); | ||
2395 | 2454 | ||
2396 | read_lock_bh(&idev->lock); | 2455 | read_lock_bh(&idev->lock); |
2397 | if (ifp->dead) | 2456 | if (ifp->dead) |
@@ -2408,8 +2467,17 @@ static void addrconf_dad_start(struct inet6_ifaddr *ifp, u32 flags) | |||
2408 | return; | 2467 | return; |
2409 | } | 2468 | } |
2410 | 2469 | ||
2411 | ifp->probes = idev->cnf.dad_transmits; | 2470 | if (idev->if_flags & IF_READY) |
2412 | addrconf_mod_timer(ifp, AC_DAD, rand_num); | 2471 | addrconf_dad_kick(ifp); |
2472 | else { | ||
2473 | /* | ||
2474 | * If the defice is not ready: | ||
2475 | * - keep it tentative if it is a permanent address. | ||
2476 | * - otherwise, kill it. | ||
2477 | */ | ||
2478 | in6_ifa_hold(ifp); | ||
2479 | addrconf_dad_stop(ifp); | ||
2480 | } | ||
2413 | 2481 | ||
2414 | spin_unlock_bh(&ifp->lock); | 2482 | spin_unlock_bh(&ifp->lock); |
2415 | out: | 2483 | out: |
@@ -2493,6 +2561,22 @@ static void addrconf_dad_completed(struct inet6_ifaddr *ifp) | |||
2493 | } | 2561 | } |
2494 | } | 2562 | } |
2495 | 2563 | ||
2564 | static void addrconf_dad_run(struct inet6_dev *idev) { | ||
2565 | struct inet6_ifaddr *ifp; | ||
2566 | |||
2567 | read_lock_bh(&idev->lock); | ||
2568 | for (ifp = idev->addr_list; ifp; ifp = ifp->if_next) { | ||
2569 | spin_lock_bh(&ifp->lock); | ||
2570 | if (!(ifp->flags & IFA_F_TENTATIVE)) { | ||
2571 | spin_unlock_bh(&ifp->lock); | ||
2572 | continue; | ||
2573 | } | ||
2574 | spin_unlock_bh(&ifp->lock); | ||
2575 | addrconf_dad_kick(ifp); | ||
2576 | } | ||
2577 | read_unlock_bh(&idev->lock); | ||
2578 | } | ||
2579 | |||
2496 | #ifdef CONFIG_PROC_FS | 2580 | #ifdef CONFIG_PROC_FS |
2497 | struct if6_iter_state { | 2581 | struct if6_iter_state { |
2498 | int bucket; | 2582 | int bucket; |
diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c index 34a332225c17..6ec6a2b549bb 100644 --- a/net/ipv6/icmp.c +++ b/net/ipv6/icmp.c | |||
@@ -328,8 +328,10 @@ void icmpv6_send(struct sk_buff *skb, int type, int code, __u32 info, | |||
328 | iif = skb->dev->ifindex; | 328 | iif = skb->dev->ifindex; |
329 | 329 | ||
330 | /* | 330 | /* |
331 | * Must not send if we know that source is Anycast also. | 331 | * Must not send error if the source does not uniquely |
332 | * for now we don't know that. | 332 | * identify a single node (RFC2463 Section 2.4). |
333 | * We check unspecified / multicast addresses here, | ||
334 | * and anycast addresses will be checked later. | ||
333 | */ | 335 | */ |
334 | if ((addr_type == IPV6_ADDR_ANY) || (addr_type & IPV6_ADDR_MULTICAST)) { | 336 | if ((addr_type == IPV6_ADDR_ANY) || (addr_type & IPV6_ADDR_MULTICAST)) { |
335 | LIMIT_NETDEBUG(KERN_DEBUG "icmpv6_send: addr_any/mcast source\n"); | 337 | LIMIT_NETDEBUG(KERN_DEBUG "icmpv6_send: addr_any/mcast source\n"); |
@@ -373,6 +375,16 @@ void icmpv6_send(struct sk_buff *skb, int type, int code, __u32 info, | |||
373 | err = ip6_dst_lookup(sk, &dst, &fl); | 375 | err = ip6_dst_lookup(sk, &dst, &fl); |
374 | if (err) | 376 | if (err) |
375 | goto out; | 377 | goto out; |
378 | |||
379 | /* | ||
380 | * We won't send icmp if the destination is known | ||
381 | * anycast. | ||
382 | */ | ||
383 | if (((struct rt6_info *)dst)->rt6i_flags & RTF_ANYCAST) { | ||
384 | LIMIT_NETDEBUG(KERN_DEBUG "icmpv6_send: acast source\n"); | ||
385 | goto out_dst_release; | ||
386 | } | ||
387 | |||
376 | if ((err = xfrm_lookup(&dst, &fl, sk, 0)) < 0) | 388 | if ((err = xfrm_lookup(&dst, &fl, sk, 0)) < 0) |
377 | goto out; | 389 | goto out; |
378 | 390 | ||
diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 7c68bfbee361..66140f13d119 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c | |||
@@ -413,11 +413,14 @@ static struct rt6_info *rt6_cow(struct rt6_info *ort, struct in6_addr *daddr, | |||
413 | rt = ip6_rt_copy(ort); | 413 | rt = ip6_rt_copy(ort); |
414 | 414 | ||
415 | if (rt) { | 415 | if (rt) { |
416 | ipv6_addr_copy(&rt->rt6i_dst.addr, daddr); | 416 | if (!(rt->rt6i_flags&RTF_GATEWAY)) { |
417 | 417 | if (rt->rt6i_dst.plen != 128 && | |
418 | if (!(rt->rt6i_flags&RTF_GATEWAY)) | 418 | ipv6_addr_equal(&rt->rt6i_dst.addr, daddr)) |
419 | rt->rt6i_flags |= RTF_ANYCAST; | ||
419 | ipv6_addr_copy(&rt->rt6i_gateway, daddr); | 420 | ipv6_addr_copy(&rt->rt6i_gateway, daddr); |
421 | } | ||
420 | 422 | ||
423 | ipv6_addr_copy(&rt->rt6i_dst.addr, daddr); | ||
421 | rt->rt6i_dst.plen = 128; | 424 | rt->rt6i_dst.plen = 128; |
422 | rt->rt6i_flags |= RTF_CACHE; | 425 | rt->rt6i_flags |= RTF_CACHE; |
423 | rt->u.dst.flags |= DST_HOST; | 426 | rt->u.dst.flags |= DST_HOST; |
@@ -1413,7 +1416,9 @@ struct rt6_info *addrconf_dst_alloc(struct inet6_dev *idev, | |||
1413 | rt->u.dst.obsolete = -1; | 1416 | rt->u.dst.obsolete = -1; |
1414 | 1417 | ||
1415 | rt->rt6i_flags = RTF_UP | RTF_NONEXTHOP; | 1418 | rt->rt6i_flags = RTF_UP | RTF_NONEXTHOP; |
1416 | if (!anycast) | 1419 | if (anycast) |
1420 | rt->rt6i_flags |= RTF_ANYCAST; | ||
1421 | else | ||
1417 | rt->rt6i_flags |= RTF_LOCAL; | 1422 | rt->rt6i_flags |= RTF_LOCAL; |
1418 | rt->rt6i_nexthop = ndisc_get_neigh(rt->rt6i_dev, &rt->rt6i_gateway); | 1423 | rt->rt6i_nexthop = ndisc_get_neigh(rt->rt6i_dev, &rt->rt6i_gateway); |
1419 | if (rt->rt6i_nexthop == NULL) { | 1424 | if (rt->rt6i_nexthop == NULL) { |