diff options
Diffstat (limited to 'net/ipv4/route.c')
-rw-r--r-- | net/ipv4/route.c | 41 |
1 files changed, 24 insertions, 17 deletions
diff --git a/net/ipv4/route.c b/net/ipv4/route.c index 6ee5354c9aa1..942be04e7955 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c | |||
@@ -282,6 +282,8 @@ static struct rtable *rt_cache_get_first(struct seq_file *seq) | |||
282 | struct rtable *r = NULL; | 282 | struct rtable *r = NULL; |
283 | 283 | ||
284 | for (st->bucket = rt_hash_mask; st->bucket >= 0; --st->bucket) { | 284 | for (st->bucket = rt_hash_mask; st->bucket >= 0; --st->bucket) { |
285 | if (!rt_hash_table[st->bucket].chain) | ||
286 | continue; | ||
285 | rcu_read_lock_bh(); | 287 | rcu_read_lock_bh(); |
286 | r = rcu_dereference(rt_hash_table[st->bucket].chain); | 288 | r = rcu_dereference(rt_hash_table[st->bucket].chain); |
287 | while (r) { | 289 | while (r) { |
@@ -299,11 +301,14 @@ static struct rtable *__rt_cache_get_next(struct seq_file *seq, | |||
299 | struct rtable *r) | 301 | struct rtable *r) |
300 | { | 302 | { |
301 | struct rt_cache_iter_state *st = seq->private; | 303 | struct rt_cache_iter_state *st = seq->private; |
304 | |||
302 | r = r->u.dst.rt_next; | 305 | r = r->u.dst.rt_next; |
303 | while (!r) { | 306 | while (!r) { |
304 | rcu_read_unlock_bh(); | 307 | rcu_read_unlock_bh(); |
305 | if (--st->bucket < 0) | 308 | do { |
306 | break; | 309 | if (--st->bucket < 0) |
310 | return NULL; | ||
311 | } while (!rt_hash_table[st->bucket].chain); | ||
307 | rcu_read_lock_bh(); | 312 | rcu_read_lock_bh(); |
308 | r = rt_hash_table[st->bucket].chain; | 313 | r = rt_hash_table[st->bucket].chain; |
309 | } | 314 | } |
@@ -2356,11 +2361,6 @@ static int ip_route_output_slow(struct net *net, struct rtable **rp, | |||
2356 | ipv4_is_zeronet(oldflp->fl4_src)) | 2361 | ipv4_is_zeronet(oldflp->fl4_src)) |
2357 | goto out; | 2362 | goto out; |
2358 | 2363 | ||
2359 | /* It is equivalent to inet_addr_type(saddr) == RTN_LOCAL */ | ||
2360 | dev_out = ip_dev_find(net, oldflp->fl4_src); | ||
2361 | if (dev_out == NULL) | ||
2362 | goto out; | ||
2363 | |||
2364 | /* I removed check for oif == dev_out->oif here. | 2364 | /* I removed check for oif == dev_out->oif here. |
2365 | It was wrong for two reasons: | 2365 | It was wrong for two reasons: |
2366 | 1. ip_dev_find(net, saddr) can return wrong iface, if saddr | 2366 | 1. ip_dev_find(net, saddr) can return wrong iface, if saddr |
@@ -2372,6 +2372,11 @@ static int ip_route_output_slow(struct net *net, struct rtable **rp, | |||
2372 | if (oldflp->oif == 0 | 2372 | if (oldflp->oif == 0 |
2373 | && (ipv4_is_multicast(oldflp->fl4_dst) || | 2373 | && (ipv4_is_multicast(oldflp->fl4_dst) || |
2374 | oldflp->fl4_dst == htonl(0xFFFFFFFF))) { | 2374 | oldflp->fl4_dst == htonl(0xFFFFFFFF))) { |
2375 | /* It is equivalent to inet_addr_type(saddr) == RTN_LOCAL */ | ||
2376 | dev_out = ip_dev_find(net, oldflp->fl4_src); | ||
2377 | if (dev_out == NULL) | ||
2378 | goto out; | ||
2379 | |||
2375 | /* Special hack: user can direct multicasts | 2380 | /* Special hack: user can direct multicasts |
2376 | and limited broadcast via necessary interface | 2381 | and limited broadcast via necessary interface |
2377 | without fiddling with IP_MULTICAST_IF or IP_PKTINFO. | 2382 | without fiddling with IP_MULTICAST_IF or IP_PKTINFO. |
@@ -2390,9 +2395,15 @@ static int ip_route_output_slow(struct net *net, struct rtable **rp, | |||
2390 | fl.oif = dev_out->ifindex; | 2395 | fl.oif = dev_out->ifindex; |
2391 | goto make_route; | 2396 | goto make_route; |
2392 | } | 2397 | } |
2393 | if (dev_out) | 2398 | |
2399 | if (!(oldflp->flags & FLOWI_FLAG_ANYSRC)) { | ||
2400 | /* It is equivalent to inet_addr_type(saddr) == RTN_LOCAL */ | ||
2401 | dev_out = ip_dev_find(net, oldflp->fl4_src); | ||
2402 | if (dev_out == NULL) | ||
2403 | goto out; | ||
2394 | dev_put(dev_out); | 2404 | dev_put(dev_out); |
2395 | dev_out = NULL; | 2405 | dev_out = NULL; |
2406 | } | ||
2396 | } | 2407 | } |
2397 | 2408 | ||
2398 | 2409 | ||
@@ -2840,7 +2851,9 @@ int ip_rt_dump(struct sk_buff *skb, struct netlink_callback *cb) | |||
2840 | if (s_h < 0) | 2851 | if (s_h < 0) |
2841 | s_h = 0; | 2852 | s_h = 0; |
2842 | s_idx = idx = cb->args[1]; | 2853 | s_idx = idx = cb->args[1]; |
2843 | for (h = s_h; h <= rt_hash_mask; h++) { | 2854 | for (h = s_h; h <= rt_hash_mask; h++, s_idx = 0) { |
2855 | if (!rt_hash_table[h].chain) | ||
2856 | continue; | ||
2844 | rcu_read_lock_bh(); | 2857 | rcu_read_lock_bh(); |
2845 | for (rt = rcu_dereference(rt_hash_table[h].chain), idx = 0; rt; | 2858 | for (rt = rcu_dereference(rt_hash_table[h].chain), idx = 0; rt; |
2846 | rt = rcu_dereference(rt->u.dst.rt_next), idx++) { | 2859 | rt = rcu_dereference(rt->u.dst.rt_next), idx++) { |
@@ -2859,7 +2872,6 @@ int ip_rt_dump(struct sk_buff *skb, struct netlink_callback *cb) | |||
2859 | dst_release(xchg(&skb->dst, NULL)); | 2872 | dst_release(xchg(&skb->dst, NULL)); |
2860 | } | 2873 | } |
2861 | rcu_read_unlock_bh(); | 2874 | rcu_read_unlock_bh(); |
2862 | s_idx = 0; | ||
2863 | } | 2875 | } |
2864 | 2876 | ||
2865 | done: | 2877 | done: |
@@ -2896,8 +2908,6 @@ static int ipv4_sysctl_rtcache_flush(ctl_table *__ctl, int write, | |||
2896 | } | 2908 | } |
2897 | 2909 | ||
2898 | static int ipv4_sysctl_rtcache_flush_strategy(ctl_table *table, | 2910 | static int ipv4_sysctl_rtcache_flush_strategy(ctl_table *table, |
2899 | int __user *name, | ||
2900 | int nlen, | ||
2901 | void __user *oldval, | 2911 | void __user *oldval, |
2902 | size_t __user *oldlenp, | 2912 | size_t __user *oldlenp, |
2903 | void __user *newval, | 2913 | void __user *newval, |
@@ -2960,16 +2970,13 @@ static int ipv4_sysctl_rt_secret_interval(ctl_table *ctl, int write, | |||
2960 | } | 2970 | } |
2961 | 2971 | ||
2962 | static int ipv4_sysctl_rt_secret_interval_strategy(ctl_table *table, | 2972 | static int ipv4_sysctl_rt_secret_interval_strategy(ctl_table *table, |
2963 | int __user *name, | ||
2964 | int nlen, | ||
2965 | void __user *oldval, | 2973 | void __user *oldval, |
2966 | size_t __user *oldlenp, | 2974 | size_t __user *oldlenp, |
2967 | void __user *newval, | 2975 | void __user *newval, |
2968 | size_t newlen) | 2976 | size_t newlen) |
2969 | { | 2977 | { |
2970 | int old = ip_rt_secret_interval; | 2978 | int old = ip_rt_secret_interval; |
2971 | int ret = sysctl_jiffies(table, name, nlen, oldval, oldlenp, newval, | 2979 | int ret = sysctl_jiffies(table, oldval, oldlenp, newval, newlen); |
2972 | newlen); | ||
2973 | 2980 | ||
2974 | rt_secret_reschedule(old); | 2981 | rt_secret_reschedule(old); |
2975 | 2982 | ||