diff options
author | David S. Miller <davem@davemloft.net> | 2011-03-02 16:27:41 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2011-03-02 16:27:41 -0500 |
commit | 452edd598f60522c11f7f88fdbab27eb36509d1a (patch) | |
tree | df1510e9848e591a412c8bfa724253470c48c4c2 | |
parent | 3872b284087081ee5cb0e4630954c2f7a2153cf5 (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.h | 14 | ||||
-rw-r--r-- | net/decnet/dn_route.c | 12 | ||||
-rw-r--r-- | net/ipv4/icmp.c | 36 | ||||
-rw-r--r-- | net/ipv4/netfilter.c | 6 | ||||
-rw-r--r-- | net/ipv4/route.c | 7 | ||||
-rw-r--r-- | net/ipv6/icmp.c | 37 | ||||
-rw-r--r-- | net/ipv6/ip6_output.c | 10 | ||||
-rw-r--r-- | net/ipv6/ip6_tunnel.c | 8 | ||||
-rw-r--r-- | net/ipv6/mcast.c | 13 | ||||
-rw-r--r-- | net/ipv6/ndisc.c | 8 | ||||
-rw-r--r-- | net/ipv6/netfilter.c | 3 | ||||
-rw-r--r-- | net/ipv6/netfilter/ip6t_REJECT.c | 3 | ||||
-rw-r--r-- | net/netfilter/ipvs/ip_vs_xmit.c | 9 | ||||
-rw-r--r-- | net/xfrm/xfrm_policy.c | 34 |
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 | ||
427 | struct flowi; | 427 | struct flowi; |
428 | #ifndef CONFIG_XFRM | 428 | #ifndef CONFIG_XFRM |
429 | static inline int xfrm_lookup(struct net *net, struct dst_entry **dst_p, | 429 | static 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 |
436 | extern int xfrm_lookup(struct net *net, struct dst_entry **dst_p, | 437 | extern 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 | ||
459 | relookup_failed: | 451 | relookup_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 | ||
361 | relookup_failed: | 359 | relookup_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 | } |
1036 | EXPORT_SYMBOL_GPL(ip6_dst_lookup_flow); | 1033 | EXPORT_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 | } |
1075 | EXPORT_SYMBOL_GPL(ip6_sk_dst_lookup_flow); | 1069 | EXPORT_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 | */ |
1760 | int xfrm_lookup(struct net *net, struct dst_entry **dst_p, | 1760 | struct 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 | } |
1904 | ok: | 1900 | ok: |
1905 | xfrm_pols_put(pols, drop_pols); | 1901 | xfrm_pols_put(pols, drop_pols); |
1906 | return 0; | 1902 | return dst; |
1907 | 1903 | ||
1908 | nopol: | 1904 | nopol: |
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; |
1912 | error: | 1910 | error: |
1913 | dst_release(dst); | 1911 | dst_release(dst); |
1914 | dropdst: | 1912 | dropdst: |
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 | } |
1920 | EXPORT_SYMBOL(xfrm_lookup); | 1917 | EXPORT_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 | } |