aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4/route.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv4/route.c')
-rw-r--r--net/ipv4/route.c59
1 files changed, 24 insertions, 35 deletions
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index 04e0df82b88c..7864d0c48968 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -1773,12 +1773,15 @@ void ip_rt_get_source(u8 *addr, struct rtable *rt)
1773 1773
1774 if (rt->fl.iif == 0) 1774 if (rt->fl.iif == 0)
1775 src = rt->rt_src; 1775 src = rt->rt_src;
1776 else if (fib_lookup(dev_net(rt->dst.dev), &rt->fl, &res) == 0) { 1776 else {
1777 src = FIB_RES_PREFSRC(res); 1777 rcu_read_lock();
1778 fib_res_put(&res); 1778 if (fib_lookup(dev_net(rt->dst.dev), &rt->fl, &res) == 0)
1779 } else 1779 src = FIB_RES_PREFSRC(res);
1780 src = inet_select_addr(rt->dst.dev, rt->rt_gateway, 1780 else
1781 src = inet_select_addr(rt->dst.dev, rt->rt_gateway,
1781 RT_SCOPE_UNIVERSE); 1782 RT_SCOPE_UNIVERSE);
1783 rcu_read_unlock();
1784 }
1782 memcpy(addr, &src, 4); 1785 memcpy(addr, &src, 4);
1783} 1786}
1784 1787
@@ -2081,6 +2084,7 @@ static int ip_mkroute_input(struct sk_buff *skb,
2081 * Such approach solves two big problems: 2084 * Such approach solves two big problems:
2082 * 1. Not simplex devices are handled properly. 2085 * 1. Not simplex devices are handled properly.
2083 * 2. IP spoofing attempts are filtered with 100% of guarantee. 2086 * 2. IP spoofing attempts are filtered with 100% of guarantee.
2087 * called with rcu_read_lock()
2084 */ 2088 */
2085 2089
2086static int ip_route_input_slow(struct sk_buff *skb, __be32 daddr, __be32 saddr, 2090static int ip_route_input_slow(struct sk_buff *skb, __be32 daddr, __be32 saddr,
@@ -2102,7 +2106,6 @@ static int ip_route_input_slow(struct sk_buff *skb, __be32 daddr, __be32 saddr,
2102 unsigned hash; 2106 unsigned hash;
2103 __be32 spec_dst; 2107 __be32 spec_dst;
2104 int err = -EINVAL; 2108 int err = -EINVAL;
2105 int free_res = 0;
2106 struct net * net = dev_net(dev); 2109 struct net * net = dev_net(dev);
2107 2110
2108 /* IP on this device is disabled. */ 2111 /* IP on this device is disabled. */
@@ -2134,12 +2137,12 @@ static int ip_route_input_slow(struct sk_buff *skb, __be32 daddr, __be32 saddr,
2134 /* 2137 /*
2135 * Now we are ready to route packet. 2138 * Now we are ready to route packet.
2136 */ 2139 */
2137 if ((err = fib_lookup(net, &fl, &res)) != 0) { 2140 err = fib_lookup(net, &fl, &res);
2141 if (err != 0) {
2138 if (!IN_DEV_FORWARD(in_dev)) 2142 if (!IN_DEV_FORWARD(in_dev))
2139 goto e_hostunreach; 2143 goto e_hostunreach;
2140 goto no_route; 2144 goto no_route;
2141 } 2145 }
2142 free_res = 1;
2143 2146
2144 RT_CACHE_STAT_INC(in_slow_tot); 2147 RT_CACHE_STAT_INC(in_slow_tot);
2145 2148
@@ -2148,8 +2151,8 @@ static int ip_route_input_slow(struct sk_buff *skb, __be32 daddr, __be32 saddr,
2148 2151
2149 if (res.type == RTN_LOCAL) { 2152 if (res.type == RTN_LOCAL) {
2150 err = fib_validate_source(saddr, daddr, tos, 2153 err = fib_validate_source(saddr, daddr, tos,
2151 net->loopback_dev->ifindex, 2154 net->loopback_dev->ifindex,
2152 dev, &spec_dst, &itag, skb->mark); 2155 dev, &spec_dst, &itag, skb->mark);
2153 if (err < 0) 2156 if (err < 0)
2154 goto martian_source_keep_err; 2157 goto martian_source_keep_err;
2155 if (err) 2158 if (err)
@@ -2164,9 +2167,6 @@ static int ip_route_input_slow(struct sk_buff *skb, __be32 daddr, __be32 saddr,
2164 goto martian_destination; 2167 goto martian_destination;
2165 2168
2166 err = ip_mkroute_input(skb, &res, &fl, in_dev, daddr, saddr, tos); 2169 err = ip_mkroute_input(skb, &res, &fl, in_dev, daddr, saddr, tos);
2167done:
2168 if (free_res)
2169 fib_res_put(&res);
2170out: return err; 2170out: return err;
2171 2171
2172brd_input: 2172brd_input:
@@ -2226,7 +2226,7 @@ local_input:
2226 rth->rt_type = res.type; 2226 rth->rt_type = res.type;
2227 hash = rt_hash(daddr, saddr, fl.iif, rt_genid(net)); 2227 hash = rt_hash(daddr, saddr, fl.iif, rt_genid(net));
2228 err = rt_intern_hash(hash, rth, NULL, skb, fl.iif); 2228 err = rt_intern_hash(hash, rth, NULL, skb, fl.iif);
2229 goto done; 2229 goto out;
2230 2230
2231no_route: 2231no_route:
2232 RT_CACHE_STAT_INC(in_no_route); 2232 RT_CACHE_STAT_INC(in_no_route);
@@ -2249,21 +2249,21 @@ martian_destination:
2249 2249
2250e_hostunreach: 2250e_hostunreach:
2251 err = -EHOSTUNREACH; 2251 err = -EHOSTUNREACH;
2252 goto done; 2252 goto out;
2253 2253
2254e_inval: 2254e_inval:
2255 err = -EINVAL; 2255 err = -EINVAL;
2256 goto done; 2256 goto out;
2257 2257
2258e_nobufs: 2258e_nobufs:
2259 err = -ENOBUFS; 2259 err = -ENOBUFS;
2260 goto done; 2260 goto out;
2261 2261
2262martian_source: 2262martian_source:
2263 err = -EINVAL; 2263 err = -EINVAL;
2264martian_source_keep_err: 2264martian_source_keep_err:
2265 ip_handle_martian_source(dev, in_dev, skb, daddr, saddr); 2265 ip_handle_martian_source(dev, in_dev, skb, daddr, saddr);
2266 goto done; 2266 goto out;
2267} 2267}
2268 2268
2269int ip_route_input_common(struct sk_buff *skb, __be32 daddr, __be32 saddr, 2269int ip_route_input_common(struct sk_buff *skb, __be32 daddr, __be32 saddr,
@@ -2349,6 +2349,7 @@ skip_cache:
2349} 2349}
2350EXPORT_SYMBOL(ip_route_input_common); 2350EXPORT_SYMBOL(ip_route_input_common);
2351 2351
2352/* called with rcu_read_lock() */
2352static int __mkroute_output(struct rtable **result, 2353static int __mkroute_output(struct rtable **result,
2353 struct fib_result *res, 2354 struct fib_result *res,
2354 const struct flowi *fl, 2355 const struct flowi *fl,
@@ -2373,18 +2374,13 @@ static int __mkroute_output(struct rtable **result,
2373 if (dev_out->flags & IFF_LOOPBACK) 2374 if (dev_out->flags & IFF_LOOPBACK)
2374 flags |= RTCF_LOCAL; 2375 flags |= RTCF_LOCAL;
2375 2376
2376 rcu_read_lock();
2377 in_dev = __in_dev_get_rcu(dev_out); 2377 in_dev = __in_dev_get_rcu(dev_out);
2378 if (!in_dev) { 2378 if (!in_dev)
2379 rcu_read_unlock();
2380 return -EINVAL; 2379 return -EINVAL;
2381 } 2380
2382 if (res->type == RTN_BROADCAST) { 2381 if (res->type == RTN_BROADCAST) {
2383 flags |= RTCF_BROADCAST | RTCF_LOCAL; 2382 flags |= RTCF_BROADCAST | RTCF_LOCAL;
2384 if (res->fi) { 2383 res->fi = NULL;
2385 fib_info_put(res->fi);
2386 res->fi = NULL;
2387 }
2388 } else if (res->type == RTN_MULTICAST) { 2384 } else if (res->type == RTN_MULTICAST) {
2389 flags |= RTCF_MULTICAST | RTCF_LOCAL; 2385 flags |= RTCF_MULTICAST | RTCF_LOCAL;
2390 if (!ip_check_mc(in_dev, oldflp->fl4_dst, oldflp->fl4_src, 2386 if (!ip_check_mc(in_dev, oldflp->fl4_dst, oldflp->fl4_src,
@@ -2394,10 +2390,8 @@ static int __mkroute_output(struct rtable **result,
2394 * default one, but do not gateway in this case. 2390 * default one, but do not gateway in this case.
2395 * Yes, it is hack. 2391 * Yes, it is hack.
2396 */ 2392 */
2397 if (res->fi && res->prefixlen < 4) { 2393 if (res->fi && res->prefixlen < 4)
2398 fib_info_put(res->fi);
2399 res->fi = NULL; 2394 res->fi = NULL;
2400 }
2401 } 2395 }
2402 2396
2403 2397
@@ -2467,6 +2461,7 @@ static int __mkroute_output(struct rtable **result,
2467 return 0; 2461 return 0;
2468} 2462}
2469 2463
2464/* called with rcu_read_lock() */
2470static int ip_mkroute_output(struct rtable **rp, 2465static int ip_mkroute_output(struct rtable **rp,
2471 struct fib_result *res, 2466 struct fib_result *res,
2472 const struct flowi *fl, 2467 const struct flowi *fl,
@@ -2509,7 +2504,6 @@ static int ip_route_output_slow(struct net *net, struct rtable **rp,
2509 struct fib_result res; 2504 struct fib_result res;
2510 unsigned int flags = 0; 2505 unsigned int flags = 0;
2511 struct net_device *dev_out = NULL; 2506 struct net_device *dev_out = NULL;
2512 int free_res = 0;
2513 int err; 2507 int err;
2514 2508
2515 2509
@@ -2636,15 +2630,12 @@ static int ip_route_output_slow(struct net *net, struct rtable **rp,
2636 err = -ENETUNREACH; 2630 err = -ENETUNREACH;
2637 goto out; 2631 goto out;
2638 } 2632 }
2639 free_res = 1;
2640 2633
2641 if (res.type == RTN_LOCAL) { 2634 if (res.type == RTN_LOCAL) {
2642 if (!fl.fl4_src) 2635 if (!fl.fl4_src)
2643 fl.fl4_src = fl.fl4_dst; 2636 fl.fl4_src = fl.fl4_dst;
2644 dev_out = net->loopback_dev; 2637 dev_out = net->loopback_dev;
2645 fl.oif = dev_out->ifindex; 2638 fl.oif = dev_out->ifindex;
2646 if (res.fi)
2647 fib_info_put(res.fi);
2648 res.fi = NULL; 2639 res.fi = NULL;
2649 flags |= RTCF_LOCAL; 2640 flags |= RTCF_LOCAL;
2650 goto make_route; 2641 goto make_route;
@@ -2668,8 +2659,6 @@ static int ip_route_output_slow(struct net *net, struct rtable **rp,
2668make_route: 2659make_route:
2669 err = ip_mkroute_output(rp, &res, &fl, oldflp, dev_out, flags); 2660 err = ip_mkroute_output(rp, &res, &fl, oldflp, dev_out, flags);
2670 2661
2671 if (free_res)
2672 fib_res_put(&res);
2673out: return err; 2662out: return err;
2674} 2663}
2675 2664