diff options
Diffstat (limited to 'net/ipv4')
-rw-r--r-- | net/ipv4/route.c | 33 |
1 files changed, 15 insertions, 18 deletions
diff --git a/net/ipv4/route.c b/net/ipv4/route.c index 98beda47bc99..ea895004caf3 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c | |||
@@ -2358,9 +2358,8 @@ static int __mkroute_output(struct rtable **result, | |||
2358 | struct rtable *rth; | 2358 | struct rtable *rth; |
2359 | struct in_device *in_dev; | 2359 | struct in_device *in_dev; |
2360 | u32 tos = RT_FL_TOS(oldflp); | 2360 | u32 tos = RT_FL_TOS(oldflp); |
2361 | int err = 0; | ||
2362 | 2361 | ||
2363 | if (ipv4_is_loopback(fl->fl4_src) && !(dev_out->flags&IFF_LOOPBACK)) | 2362 | if (ipv4_is_loopback(fl->fl4_src) && !(dev_out->flags & IFF_LOOPBACK)) |
2364 | return -EINVAL; | 2363 | return -EINVAL; |
2365 | 2364 | ||
2366 | if (fl->fl4_dst == htonl(0xFFFFFFFF)) | 2365 | if (fl->fl4_dst == htonl(0xFFFFFFFF)) |
@@ -2373,11 +2372,12 @@ static int __mkroute_output(struct rtable **result, | |||
2373 | if (dev_out->flags & IFF_LOOPBACK) | 2372 | if (dev_out->flags & IFF_LOOPBACK) |
2374 | flags |= RTCF_LOCAL; | 2373 | flags |= RTCF_LOCAL; |
2375 | 2374 | ||
2376 | /* get work reference to inet device */ | 2375 | rcu_read_lock(); |
2377 | in_dev = in_dev_get(dev_out); | 2376 | in_dev = __in_dev_get_rcu(dev_out); |
2378 | if (!in_dev) | 2377 | if (!in_dev) { |
2378 | rcu_read_unlock(); | ||
2379 | return -EINVAL; | 2379 | return -EINVAL; |
2380 | 2380 | } | |
2381 | if (res->type == RTN_BROADCAST) { | 2381 | if (res->type == RTN_BROADCAST) { |
2382 | flags |= RTCF_BROADCAST | RTCF_LOCAL; | 2382 | flags |= RTCF_BROADCAST | RTCF_LOCAL; |
2383 | if (res->fi) { | 2383 | if (res->fi) { |
@@ -2385,13 +2385,13 @@ static int __mkroute_output(struct rtable **result, | |||
2385 | res->fi = NULL; | 2385 | res->fi = NULL; |
2386 | } | 2386 | } |
2387 | } else if (res->type == RTN_MULTICAST) { | 2387 | } else if (res->type == RTN_MULTICAST) { |
2388 | flags |= RTCF_MULTICAST|RTCF_LOCAL; | 2388 | flags |= RTCF_MULTICAST | RTCF_LOCAL; |
2389 | if (!ip_check_mc(in_dev, oldflp->fl4_dst, oldflp->fl4_src, | 2389 | if (!ip_check_mc(in_dev, oldflp->fl4_dst, oldflp->fl4_src, |
2390 | oldflp->proto)) | 2390 | oldflp->proto)) |
2391 | flags &= ~RTCF_LOCAL; | 2391 | flags &= ~RTCF_LOCAL; |
2392 | /* If multicast route do not exist use | 2392 | /* If multicast route do not exist use |
2393 | default one, but do not gateway in this case. | 2393 | * default one, but do not gateway in this case. |
2394 | Yes, it is hack. | 2394 | * Yes, it is hack. |
2395 | */ | 2395 | */ |
2396 | if (res->fi && res->prefixlen < 4) { | 2396 | if (res->fi && res->prefixlen < 4) { |
2397 | fib_info_put(res->fi); | 2397 | fib_info_put(res->fi); |
@@ -2402,9 +2402,12 @@ static int __mkroute_output(struct rtable **result, | |||
2402 | 2402 | ||
2403 | rth = dst_alloc(&ipv4_dst_ops); | 2403 | rth = dst_alloc(&ipv4_dst_ops); |
2404 | if (!rth) { | 2404 | if (!rth) { |
2405 | err = -ENOBUFS; | 2405 | rcu_read_unlock(); |
2406 | goto cleanup; | 2406 | return -ENOBUFS; |
2407 | } | 2407 | } |
2408 | in_dev_hold(in_dev); | ||
2409 | rcu_read_unlock(); | ||
2410 | rth->idev = in_dev; | ||
2408 | 2411 | ||
2409 | atomic_set(&rth->dst.__refcnt, 1); | 2412 | atomic_set(&rth->dst.__refcnt, 1); |
2410 | rth->dst.flags= DST_HOST; | 2413 | rth->dst.flags= DST_HOST; |
@@ -2425,7 +2428,6 @@ static int __mkroute_output(struct rtable **result, | |||
2425 | cache entry */ | 2428 | cache entry */ |
2426 | rth->dst.dev = dev_out; | 2429 | rth->dst.dev = dev_out; |
2427 | dev_hold(dev_out); | 2430 | dev_hold(dev_out); |
2428 | rth->idev = in_dev_get(dev_out); | ||
2429 | rth->rt_gateway = fl->fl4_dst; | 2431 | rth->rt_gateway = fl->fl4_dst; |
2430 | rth->rt_spec_dst= fl->fl4_src; | 2432 | rth->rt_spec_dst= fl->fl4_src; |
2431 | 2433 | ||
@@ -2460,13 +2462,8 @@ static int __mkroute_output(struct rtable **result, | |||
2460 | rt_set_nexthop(rth, res, 0); | 2462 | rt_set_nexthop(rth, res, 0); |
2461 | 2463 | ||
2462 | rth->rt_flags = flags; | 2464 | rth->rt_flags = flags; |
2463 | |||
2464 | *result = rth; | 2465 | *result = rth; |
2465 | cleanup: | 2466 | return 0; |
2466 | /* release work reference to inet device */ | ||
2467 | in_dev_put(in_dev); | ||
2468 | |||
2469 | return err; | ||
2470 | } | 2467 | } |
2471 | 2468 | ||
2472 | static int ip_mkroute_output(struct rtable **rp, | 2469 | static int ip_mkroute_output(struct rtable **rp, |