aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2011-03-02 16:27:41 -0500
committerDavid S. Miller <davem@davemloft.net>2011-03-02 16:27:41 -0500
commit452edd598f60522c11f7f88fdbab27eb36509d1a (patch)
treedf1510e9848e591a412c8bfa724253470c48c4c2
parent3872b284087081ee5cb0e4630954c2f7a2153cf5 (diff)
xfrm: Return dst directly from xfrm_lookup()
Instead of on the stack. Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--include/net/dst.h14
-rw-r--r--net/decnet/dn_route.c12
-rw-r--r--net/ipv4/icmp.c36
-rw-r--r--net/ipv4/netfilter.c6
-rw-r--r--net/ipv4/route.c7
-rw-r--r--net/ipv6/icmp.c37
-rw-r--r--net/ipv6/ip6_output.c10
-rw-r--r--net/ipv6/ip6_tunnel.c8
-rw-r--r--net/ipv6/mcast.c13
-rw-r--r--net/ipv6/ndisc.c8
-rw-r--r--net/ipv6/netfilter.c3
-rw-r--r--net/ipv6/netfilter/ip6t_REJECT.c3
-rw-r--r--net/netfilter/ipvs/ip_vs_xmit.c9
-rw-r--r--net/xfrm/xfrm_policy.c34
14 files changed, 111 insertions, 89 deletions
diff --git a/include/net/dst.h b/include/net/dst.h
index 8948452132ad..2a46cbaef92d 100644
--- a/include/net/dst.h
+++ b/include/net/dst.h
@@ -426,15 +426,17 @@ enum {
426 426
427struct flowi; 427struct flowi;
428#ifndef CONFIG_XFRM 428#ifndef CONFIG_XFRM
429static inline int xfrm_lookup(struct net *net, struct dst_entry **dst_p, 429static inline struct dst_entry *xfrm_lookup(struct net *net,
430 const struct flowi *fl, struct sock *sk, 430 struct dst_entry *dst_orig,
431 int flags) 431 const struct flowi *fl, struct sock *sk,
432 int flags)
432{ 433{
433 return 0; 434 return dst_orig;
434} 435}
435#else 436#else
436extern int xfrm_lookup(struct net *net, struct dst_entry **dst_p, 437extern struct dst_entry *xfrm_lookup(struct net *net, struct dst_entry *dst_orig,
437 const struct flowi *fl, struct sock *sk, int flags); 438 const struct flowi *fl, struct sock *sk,
439 int flags);
438#endif 440#endif
439#endif 441#endif
440 442
diff --git a/net/decnet/dn_route.c b/net/decnet/dn_route.c
index 0877147d2167..484fdbf92bd8 100644
--- a/net/decnet/dn_route.c
+++ b/net/decnet/dn_route.c
@@ -1222,7 +1222,11 @@ static int dn_route_output_key(struct dst_entry **pprt, struct flowi *flp, int f
1222 1222
1223 err = __dn_route_output_key(pprt, flp, flags); 1223 err = __dn_route_output_key(pprt, flp, flags);
1224 if (err == 0 && flp->proto) { 1224 if (err == 0 && flp->proto) {
1225 err = xfrm_lookup(&init_net, pprt, flp, NULL, 0); 1225 *pprt = xfrm_lookup(&init_net, *pprt, flp, NULL, 0);
1226 if (IS_ERR(*pprt)) {
1227 err = PTR_ERR(*pprt);
1228 *pprt = NULL;
1229 }
1226 } 1230 }
1227 return err; 1231 return err;
1228} 1232}
@@ -1235,7 +1239,11 @@ int dn_route_output_sock(struct dst_entry **pprt, struct flowi *fl, struct sock
1235 if (err == 0 && fl->proto) { 1239 if (err == 0 && fl->proto) {
1236 if (!(flags & MSG_DONTWAIT)) 1240 if (!(flags & MSG_DONTWAIT))
1237 fl->flags |= FLOWI_FLAG_CAN_SLEEP; 1241 fl->flags |= FLOWI_FLAG_CAN_SLEEP;
1238 err = xfrm_lookup(&init_net, pprt, fl, sk, 0); 1242 *pprt = xfrm_lookup(&init_net, *pprt, fl, sk, 0);
1243 if (IS_ERR(*pprt)) {
1244 err = PTR_ERR(*pprt);
1245 *pprt = NULL;
1246 }
1239 } 1247 }
1240 return err; 1248 return err;
1241} 1249}
diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c
index 2a86c8951dcd..c23bd8cdeee0 100644
--- a/net/ipv4/icmp.c
+++ b/net/ipv4/icmp.c
@@ -398,18 +398,14 @@ static struct rtable *icmp_route_lookup(struct net *net, struct sk_buff *skb_in,
398 if (!fl.fl4_src) 398 if (!fl.fl4_src)
399 fl.fl4_src = rt->rt_src; 399 fl.fl4_src = rt->rt_src;
400 400
401 err = xfrm_lookup(net, (struct dst_entry **)&rt, &fl, NULL, 0); 401 rt = (struct rtable *) xfrm_lookup(net, &rt->dst, &fl, NULL, 0);
402 switch (err) { 402 if (!IS_ERR(rt)) {
403 case 0:
404 if (rt != rt2) 403 if (rt != rt2)
405 return rt; 404 return rt;
406 break; 405 } else if (PTR_ERR(rt) == -EPERM) {
407 case -EPERM:
408 rt = NULL; 406 rt = NULL;
409 break; 407 } else
410 default: 408 return rt;
411 return ERR_PTR(err);
412 }
413 409
414 err = xfrm_decode_session_reverse(skb_in, &fl, AF_INET); 410 err = xfrm_decode_session_reverse(skb_in, &fl, AF_INET);
415 if (err) 411 if (err)
@@ -438,22 +434,18 @@ static struct rtable *icmp_route_lookup(struct net *net, struct sk_buff *skb_in,
438 if (err) 434 if (err)
439 goto relookup_failed; 435 goto relookup_failed;
440 436
441 err = xfrm_lookup(net, (struct dst_entry **)&rt2, &fl, NULL, 437 rt2 = (struct rtable *) xfrm_lookup(net, &rt2->dst, &fl, NULL, XFRM_LOOKUP_ICMP);
442 XFRM_LOOKUP_ICMP); 438 if (!IS_ERR(rt2)) {
443 switch (err) {
444 case 0:
445 dst_release(&rt->dst); 439 dst_release(&rt->dst);
446 rt = rt2; 440 rt = rt2;
447 break; 441 } else if (PTR_ERR(rt2) == -EPERM) {
448 case -EPERM: 442 if (rt)
449 return ERR_PTR(err); 443 dst_release(&rt->dst);
450 default: 444 return rt2;
451 if (!rt) 445 } else {
452 return ERR_PTR(err); 446 err = PTR_ERR(rt2);
453 break; 447 goto relookup_failed;
454 } 448 }
455
456
457 return rt; 449 return rt;
458 450
459relookup_failed: 451relookup_failed:
diff --git a/net/ipv4/netfilter.c b/net/ipv4/netfilter.c
index 994a1f29ebbc..9770bb427952 100644
--- a/net/ipv4/netfilter.c
+++ b/net/ipv4/netfilter.c
@@ -69,7 +69,8 @@ int ip_route_me_harder(struct sk_buff *skb, unsigned addr_type)
69 xfrm_decode_session(skb, &fl, AF_INET) == 0) { 69 xfrm_decode_session(skb, &fl, AF_INET) == 0) {
70 struct dst_entry *dst = skb_dst(skb); 70 struct dst_entry *dst = skb_dst(skb);
71 skb_dst_set(skb, NULL); 71 skb_dst_set(skb, NULL);
72 if (xfrm_lookup(net, &dst, &fl, skb->sk, 0)) 72 dst = xfrm_lookup(net, dst, &fl, skb->sk, 0);
73 if (IS_ERR(dst))
73 return -1; 74 return -1;
74 skb_dst_set(skb, dst); 75 skb_dst_set(skb, dst);
75 } 76 }
@@ -102,7 +103,8 @@ int ip_xfrm_me_harder(struct sk_buff *skb)
102 dst = ((struct xfrm_dst *)dst)->route; 103 dst = ((struct xfrm_dst *)dst)->route;
103 dst_hold(dst); 104 dst_hold(dst);
104 105
105 if (xfrm_lookup(dev_net(dst->dev), &dst, &fl, skb->sk, 0) < 0) 106 dst = xfrm_lookup(dev_net(dst->dev), dst, &fl, skb->sk, 0);
107 if (IS_ERR(dst))
106 return -1; 108 return -1;
107 109
108 skb_dst_drop(skb); 110 skb_dst_drop(skb);
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index e24e4cf2a112..63d37004ee66 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -2730,7 +2730,12 @@ int ip_route_output_flow(struct net *net, struct rtable **rp, struct flowi *flp,
2730 flp->fl4_src = (*rp)->rt_src; 2730 flp->fl4_src = (*rp)->rt_src;
2731 if (!flp->fl4_dst) 2731 if (!flp->fl4_dst)
2732 flp->fl4_dst = (*rp)->rt_dst; 2732 flp->fl4_dst = (*rp)->rt_dst;
2733 return xfrm_lookup(net, (struct dst_entry **)rp, flp, sk, 0); 2733 *rp = (struct rtable *) xfrm_lookup(net, &(*rp)->dst, flp, sk, 0);
2734 if (IS_ERR(*rp)) {
2735 err = PTR_ERR(*rp);
2736 *rp = NULL;
2737 return err;
2738 }
2734 } 2739 }
2735 2740
2736 return 0; 2741 return 0;
diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c
index e332bae104ee..55665956b3a8 100644
--- a/net/ipv6/icmp.c
+++ b/net/ipv6/icmp.c
@@ -324,17 +324,15 @@ static struct dst_entry *icmpv6_route_lookup(struct net *net, struct sk_buff *sk
324 /* No need to clone since we're just using its address. */ 324 /* No need to clone since we're just using its address. */
325 dst2 = dst; 325 dst2 = dst;
326 326
327 err = xfrm_lookup(net, &dst, fl, sk, 0); 327 dst = xfrm_lookup(net, dst, fl, sk, 0);
328 switch (err) { 328 if (!IS_ERR(dst)) {
329 case 0:
330 if (dst != dst2) 329 if (dst != dst2)
331 return dst; 330 return dst;
332 break; 331 } else {
333 case -EPERM: 332 if (PTR_ERR(dst) == -EPERM)
334 dst = NULL; 333 dst = NULL;
335 break; 334 else
336 default: 335 return dst;
337 return ERR_PTR(err);
338 } 336 }
339 337
340 err = xfrm_decode_session_reverse(skb, &fl2, AF_INET6); 338 err = xfrm_decode_session_reverse(skb, &fl2, AF_INET6);
@@ -345,17 +343,17 @@ static struct dst_entry *icmpv6_route_lookup(struct net *net, struct sk_buff *sk
345 if (err) 343 if (err)
346 goto relookup_failed; 344 goto relookup_failed;
347 345
348 err = xfrm_lookup(net, &dst2, &fl2, sk, XFRM_LOOKUP_ICMP); 346 dst2 = xfrm_lookup(net, dst2, &fl2, sk, XFRM_LOOKUP_ICMP);
349 switch (err) { 347 if (!IS_ERR(dst2)) {
350 case 0:
351 dst_release(dst); 348 dst_release(dst);
352 dst = dst2; 349 dst = dst2;
353 break; 350 } else {
354 case -EPERM: 351 err = PTR_ERR(dst2);
355 dst_release(dst); 352 if (err == -EPERM) {
356 return ERR_PTR(err); 353 dst_release(dst);
357 default: 354 return dst2;
358 goto relookup_failed; 355 } else
356 goto relookup_failed;
359 } 357 }
360 358
361relookup_failed: 359relookup_failed:
@@ -560,7 +558,8 @@ static void icmpv6_echo_reply(struct sk_buff *skb)
560 err = ip6_dst_lookup(sk, &dst, &fl); 558 err = ip6_dst_lookup(sk, &dst, &fl);
561 if (err) 559 if (err)
562 goto out; 560 goto out;
563 if ((err = xfrm_lookup(net, &dst, &fl, sk, 0)) < 0) 561 dst = xfrm_lookup(net, dst, &fl, sk, 0);
562 if (IS_ERR(dst))
564 goto out; 563 goto out;
565 564
566 if (ipv6_addr_is_multicast(&fl.fl6_dst)) 565 if (ipv6_addr_is_multicast(&fl.fl6_dst))
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
index 35a4ad90a0f5..adaffaf84555 100644
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -1028,10 +1028,7 @@ struct dst_entry *ip6_dst_lookup_flow(struct sock *sk, struct flowi *fl,
1028 if (can_sleep) 1028 if (can_sleep)
1029 fl->flags |= FLOWI_FLAG_CAN_SLEEP; 1029 fl->flags |= FLOWI_FLAG_CAN_SLEEP;
1030 1030
1031 err = xfrm_lookup(sock_net(sk), &dst, fl, sk, 0); 1031 return xfrm_lookup(sock_net(sk), dst, fl, sk, 0);
1032 if (err)
1033 return ERR_PTR(err);
1034 return dst;
1035} 1032}
1036EXPORT_SYMBOL_GPL(ip6_dst_lookup_flow); 1033EXPORT_SYMBOL_GPL(ip6_dst_lookup_flow);
1037 1034
@@ -1067,10 +1064,7 @@ struct dst_entry *ip6_sk_dst_lookup_flow(struct sock *sk, struct flowi *fl,
1067 if (can_sleep) 1064 if (can_sleep)
1068 fl->flags |= FLOWI_FLAG_CAN_SLEEP; 1065 fl->flags |= FLOWI_FLAG_CAN_SLEEP;
1069 1066
1070 err = xfrm_lookup(sock_net(sk), &dst, fl, sk, 0); 1067 return xfrm_lookup(sock_net(sk), dst, fl, sk, 0);
1071 if (err)
1072 return ERR_PTR(err);
1073 return dst;
1074} 1068}
1075EXPORT_SYMBOL_GPL(ip6_sk_dst_lookup_flow); 1069EXPORT_SYMBOL_GPL(ip6_sk_dst_lookup_flow);
1076 1070
diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c
index 4f4483e697bd..da43038ae18e 100644
--- a/net/ipv6/ip6_tunnel.c
+++ b/net/ipv6/ip6_tunnel.c
@@ -903,8 +903,14 @@ static int ip6_tnl_xmit2(struct sk_buff *skb,
903 else { 903 else {
904 dst = ip6_route_output(net, NULL, fl); 904 dst = ip6_route_output(net, NULL, fl);
905 905
906 if (dst->error || xfrm_lookup(net, &dst, fl, NULL, 0) < 0) 906 if (dst->error)
907 goto tx_err_link_failure; 907 goto tx_err_link_failure;
908 dst = xfrm_lookup(net, dst, fl, NULL, 0);
909 if (IS_ERR(dst)) {
910 err = PTR_ERR(dst);
911 dst = NULL;
912 goto tx_err_link_failure;
913 }
908 } 914 }
909 915
910 tdev = dst->dev; 916 tdev = dst->dev;
diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c
index 49f986d626a0..7b27d08ee281 100644
--- a/net/ipv6/mcast.c
+++ b/net/ipv6/mcast.c
@@ -1429,7 +1429,12 @@ static void mld_sendpack(struct sk_buff *skb)
1429 &ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->daddr, 1429 &ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->daddr,
1430 skb->dev->ifindex); 1430 skb->dev->ifindex);
1431 1431
1432 err = xfrm_lookup(net, &dst, &fl, NULL, 0); 1432 dst = xfrm_lookup(net, dst, &fl, NULL, 0);
1433 err = 0;
1434 if (IS_ERR(dst)) {
1435 err = PTR_ERR(dst);
1436 dst = NULL;
1437 }
1433 skb_dst_set(skb, dst); 1438 skb_dst_set(skb, dst);
1434 if (err) 1439 if (err)
1435 goto err_out; 1440 goto err_out;
@@ -1796,9 +1801,11 @@ static void igmp6_send(struct in6_addr *addr, struct net_device *dev, int type)
1796 &ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->daddr, 1801 &ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->daddr,
1797 skb->dev->ifindex); 1802 skb->dev->ifindex);
1798 1803
1799 err = xfrm_lookup(net, &dst, &fl, NULL, 0); 1804 dst = xfrm_lookup(net, dst, &fl, NULL, 0);
1800 if (err) 1805 if (IS_ERR(dst)) {
1806 err = PTR_ERR(dst);
1801 goto err_out; 1807 goto err_out;
1808 }
1802 1809
1803 skb_dst_set(skb, dst); 1810 skb_dst_set(skb, dst);
1804 err = NF_HOOK(NFPROTO_IPV6, NF_INET_LOCAL_OUT, skb, NULL, skb->dev, 1811 err = NF_HOOK(NFPROTO_IPV6, NF_INET_LOCAL_OUT, skb, NULL, skb->dev,
diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c
index 7254ce364006..9360d3be94f0 100644
--- a/net/ipv6/ndisc.c
+++ b/net/ipv6/ndisc.c
@@ -529,8 +529,8 @@ void ndisc_send_skb(struct sk_buff *skb,
529 return; 529 return;
530 } 530 }
531 531
532 err = xfrm_lookup(net, &dst, &fl, NULL, 0); 532 dst = xfrm_lookup(net, dst, &fl, NULL, 0);
533 if (err < 0) { 533 if (IS_ERR(dst)) {
534 kfree_skb(skb); 534 kfree_skb(skb);
535 return; 535 return;
536 } 536 }
@@ -1542,8 +1542,8 @@ void ndisc_send_redirect(struct sk_buff *skb, struct neighbour *neigh,
1542 if (dst == NULL) 1542 if (dst == NULL)
1543 return; 1543 return;
1544 1544
1545 err = xfrm_lookup(net, &dst, &fl, NULL, 0); 1545 dst = xfrm_lookup(net, dst, &fl, NULL, 0);
1546 if (err) 1546 if (IS_ERR(dst))
1547 return; 1547 return;
1548 1548
1549 rt = (struct rt6_info *) dst; 1549 rt = (struct rt6_info *) dst;
diff --git a/net/ipv6/netfilter.c b/net/ipv6/netfilter.c
index 35915e8617f0..8d74116ae27d 100644
--- a/net/ipv6/netfilter.c
+++ b/net/ipv6/netfilter.c
@@ -39,7 +39,8 @@ int ip6_route_me_harder(struct sk_buff *skb)
39 if (!(IP6CB(skb)->flags & IP6SKB_XFRM_TRANSFORMED) && 39 if (!(IP6CB(skb)->flags & IP6SKB_XFRM_TRANSFORMED) &&
40 xfrm_decode_session(skb, &fl, AF_INET6) == 0) { 40 xfrm_decode_session(skb, &fl, AF_INET6) == 0) {
41 skb_dst_set(skb, NULL); 41 skb_dst_set(skb, NULL);
42 if (xfrm_lookup(net, &dst, &fl, skb->sk, 0)) 42 dst = xfrm_lookup(net, dst, &fl, skb->sk, 0);
43 if (IS_ERR(dst))
43 return -1; 44 return -1;
44 skb_dst_set(skb, dst); 45 skb_dst_set(skb, dst);
45 } 46 }
diff --git a/net/ipv6/netfilter/ip6t_REJECT.c b/net/ipv6/netfilter/ip6t_REJECT.c
index bf998feac14e..91f6a61cefab 100644
--- a/net/ipv6/netfilter/ip6t_REJECT.c
+++ b/net/ipv6/netfilter/ip6t_REJECT.c
@@ -101,7 +101,8 @@ static void send_reset(struct net *net, struct sk_buff *oldskb)
101 dst_release(dst); 101 dst_release(dst);
102 return; 102 return;
103 } 103 }
104 if (xfrm_lookup(net, &dst, &fl, NULL, 0)) 104 dst = xfrm_lookup(net, dst, &fl, NULL, 0);
105 if (IS_ERR(dst))
105 return; 106 return;
106 107
107 hh_len = (dst->dev->hard_header_len + 15)&~15; 108 hh_len = (dst->dev->hard_header_len + 15)&~15;
diff --git a/net/netfilter/ipvs/ip_vs_xmit.c b/net/netfilter/ipvs/ip_vs_xmit.c
index a48239aba33b..6264219f0a42 100644
--- a/net/netfilter/ipvs/ip_vs_xmit.c
+++ b/net/netfilter/ipvs/ip_vs_xmit.c
@@ -218,8 +218,13 @@ __ip_vs_route_output_v6(struct net *net, struct in6_addr *daddr,
218 ipv6_dev_get_saddr(net, ip6_dst_idev(dst)->dev, 218 ipv6_dev_get_saddr(net, ip6_dst_idev(dst)->dev,
219 &fl.fl6_dst, 0, &fl.fl6_src) < 0) 219 &fl.fl6_dst, 0, &fl.fl6_src) < 0)
220 goto out_err; 220 goto out_err;
221 if (do_xfrm && xfrm_lookup(net, &dst, &fl, NULL, 0) < 0) 221 if (do_xfrm) {
222 goto out_err; 222 dst = xfrm_lookup(net, dst, &fl, NULL, 0);
223 if (IS_ERR(dst)) {
224 dst = NULL;
225 goto out_err;
226 }
227 }
223 ipv6_addr_copy(ret_saddr, &fl.fl6_src); 228 ipv6_addr_copy(ret_saddr, &fl.fl6_src);
224 return dst; 229 return dst;
225 230
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
index 0248afa11cda..b1932a629ef8 100644
--- a/net/xfrm/xfrm_policy.c
+++ b/net/xfrm/xfrm_policy.c
@@ -1757,14 +1757,14 @@ static struct dst_entry *make_blackhole(struct net *net, u16 family,
1757 * At the moment we eat a raw IP route. Mostly to speed up lookups 1757 * At the moment we eat a raw IP route. Mostly to speed up lookups
1758 * on interfaces with disabled IPsec. 1758 * on interfaces with disabled IPsec.
1759 */ 1759 */
1760int xfrm_lookup(struct net *net, struct dst_entry **dst_p, 1760struct dst_entry *xfrm_lookup(struct net *net, struct dst_entry *dst_orig,
1761 const struct flowi *fl, 1761 const struct flowi *fl,
1762 struct sock *sk, int flags) 1762 struct sock *sk, int flags)
1763{ 1763{
1764 struct xfrm_policy *pols[XFRM_POLICY_TYPE_MAX]; 1764 struct xfrm_policy *pols[XFRM_POLICY_TYPE_MAX];
1765 struct flow_cache_object *flo; 1765 struct flow_cache_object *flo;
1766 struct xfrm_dst *xdst; 1766 struct xfrm_dst *xdst;
1767 struct dst_entry *dst, *dst_orig = *dst_p, *route; 1767 struct dst_entry *dst, *route;
1768 u16 family = dst_orig->ops->family; 1768 u16 family = dst_orig->ops->family;
1769 u8 dir = policy_to_flow_dir(XFRM_POLICY_OUT); 1769 u8 dir = policy_to_flow_dir(XFRM_POLICY_OUT);
1770 int i, err, num_pols, num_xfrms = 0, drop_pols = 0; 1770 int i, err, num_pols, num_xfrms = 0, drop_pols = 0;
@@ -1847,11 +1847,7 @@ restart:
1847 xfrm_pols_put(pols, drop_pols); 1847 xfrm_pols_put(pols, drop_pols);
1848 XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTNOSTATES); 1848 XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTNOSTATES);
1849 1849
1850 dst = make_blackhole(net, family, dst_orig); 1850 return make_blackhole(net, family, dst_orig);
1851 if (IS_ERR(dst))
1852 return PTR_ERR(dst);
1853 *dst_p = dst;
1854 return 0;
1855 } 1851 }
1856 if (fl->flags & FLOWI_FLAG_CAN_SLEEP) { 1852 if (fl->flags & FLOWI_FLAG_CAN_SLEEP) {
1857 DECLARE_WAITQUEUE(wait, current); 1853 DECLARE_WAITQUEUE(wait, current);
@@ -1895,27 +1891,28 @@ no_transform:
1895 goto error; 1891 goto error;
1896 } else if (num_xfrms > 0) { 1892 } else if (num_xfrms > 0) {
1897 /* Flow transformed */ 1893 /* Flow transformed */
1898 *dst_p = dst;
1899 dst_release(dst_orig); 1894 dst_release(dst_orig);
1900 } else { 1895 } else {
1901 /* Flow passes untransformed */ 1896 /* Flow passes untransformed */
1902 dst_release(dst); 1897 dst_release(dst);
1898 dst = dst_orig;
1903 } 1899 }
1904ok: 1900ok:
1905 xfrm_pols_put(pols, drop_pols); 1901 xfrm_pols_put(pols, drop_pols);
1906 return 0; 1902 return dst;
1907 1903
1908nopol: 1904nopol:
1909 if (!(flags & XFRM_LOOKUP_ICMP)) 1905 if (!(flags & XFRM_LOOKUP_ICMP)) {
1906 dst = dst_orig;
1910 goto ok; 1907 goto ok;
1908 }
1911 err = -ENOENT; 1909 err = -ENOENT;
1912error: 1910error:
1913 dst_release(dst); 1911 dst_release(dst);
1914dropdst: 1912dropdst:
1915 dst_release(dst_orig); 1913 dst_release(dst_orig);
1916 *dst_p = NULL;
1917 xfrm_pols_put(pols, drop_pols); 1914 xfrm_pols_put(pols, drop_pols);
1918 return err; 1915 return ERR_PTR(err);
1919} 1916}
1920EXPORT_SYMBOL(xfrm_lookup); 1917EXPORT_SYMBOL(xfrm_lookup);
1921 1918
@@ -2175,7 +2172,7 @@ int __xfrm_route_forward(struct sk_buff *skb, unsigned short family)
2175 struct net *net = dev_net(skb->dev); 2172 struct net *net = dev_net(skb->dev);
2176 struct flowi fl; 2173 struct flowi fl;
2177 struct dst_entry *dst; 2174 struct dst_entry *dst;
2178 int res; 2175 int res = 0;
2179 2176
2180 if (xfrm_decode_session(skb, &fl, family) < 0) { 2177 if (xfrm_decode_session(skb, &fl, family) < 0) {
2181 XFRM_INC_STATS(net, LINUX_MIB_XFRMFWDHDRERROR); 2178 XFRM_INC_STATS(net, LINUX_MIB_XFRMFWDHDRERROR);
@@ -2183,9 +2180,12 @@ int __xfrm_route_forward(struct sk_buff *skb, unsigned short family)
2183 } 2180 }
2184 2181
2185 skb_dst_force(skb); 2182 skb_dst_force(skb);
2186 dst = skb_dst(skb);
2187 2183
2188 res = xfrm_lookup(net, &dst, &fl, NULL, 0) == 0; 2184 dst = xfrm_lookup(net, skb_dst(skb), &fl, NULL, 0);
2185 if (IS_ERR(dst)) {
2186 res = 1;
2187 dst = NULL;
2188 }
2189 skb_dst_set(skb, dst); 2189 skb_dst_set(skb, dst);
2190 return res; 2190 return res;
2191} 2191}