diff options
-rw-r--r-- | include/net/dst.h | 7 | ||||
-rw-r--r-- | include/net/ipv6.h | 3 | ||||
-rw-r--r-- | net/core/sysctl_net_core.c | 9 | ||||
-rw-r--r-- | net/dccp/ipv6.c | 10 | ||||
-rw-r--r-- | net/ipv4/route.c | 71 | ||||
-rw-r--r-- | net/ipv6/datagram.c | 8 | ||||
-rw-r--r-- | net/ipv6/raw.c | 8 | ||||
-rw-r--r-- | net/ipv6/route.c | 63 | ||||
-rw-r--r-- | net/ipv6/tcp_ipv6.c | 8 | ||||
-rw-r--r-- | net/ipv6/udp.c | 8 | ||||
-rw-r--r-- | net/xfrm/xfrm_policy.c | 28 |
11 files changed, 209 insertions, 14 deletions
diff --git a/include/net/dst.h b/include/net/dst.h index e12a8ce0b9b3..82270f9332db 100644 --- a/include/net/dst.h +++ b/include/net/dst.h | |||
@@ -265,9 +265,16 @@ static inline int xfrm_lookup(struct dst_entry **dst_p, struct flowi *fl, | |||
265 | { | 265 | { |
266 | return 0; | 266 | return 0; |
267 | } | 267 | } |
268 | static inline int __xfrm_lookup(struct dst_entry **dst_p, struct flowi *fl, | ||
269 | struct sock *sk, int flags) | ||
270 | { | ||
271 | return 0; | ||
272 | } | ||
268 | #else | 273 | #else |
269 | extern int xfrm_lookup(struct dst_entry **dst_p, struct flowi *fl, | 274 | extern int xfrm_lookup(struct dst_entry **dst_p, struct flowi *fl, |
270 | struct sock *sk, int flags); | 275 | struct sock *sk, int flags); |
276 | extern int __xfrm_lookup(struct dst_entry **dst_p, struct flowi *fl, | ||
277 | struct sock *sk, int flags); | ||
271 | #endif | 278 | #endif |
272 | #endif | 279 | #endif |
273 | 280 | ||
diff --git a/include/net/ipv6.h b/include/net/ipv6.h index 4fa5dfe886c4..78a0d06d98d5 100644 --- a/include/net/ipv6.h +++ b/include/net/ipv6.h | |||
@@ -469,6 +469,9 @@ extern void ip6_flush_pending_frames(struct sock *sk); | |||
469 | extern int ip6_dst_lookup(struct sock *sk, | 469 | extern int ip6_dst_lookup(struct sock *sk, |
470 | struct dst_entry **dst, | 470 | struct dst_entry **dst, |
471 | struct flowi *fl); | 471 | struct flowi *fl); |
472 | extern int ip6_dst_blackhole(struct sock *sk, | ||
473 | struct dst_entry **dst, | ||
474 | struct flowi *fl); | ||
472 | extern int ip6_sk_dst_lookup(struct sock *sk, | 475 | extern int ip6_sk_dst_lookup(struct sock *sk, |
473 | struct dst_entry **dst, | 476 | struct dst_entry **dst, |
474 | struct flowi *fl); | 477 | struct flowi *fl); |
diff --git a/net/core/sysctl_net_core.c b/net/core/sysctl_net_core.c index b29712033dd4..f34aca041a25 100644 --- a/net/core/sysctl_net_core.c +++ b/net/core/sysctl_net_core.c | |||
@@ -24,6 +24,7 @@ extern int sysctl_core_destroy_delay; | |||
24 | #ifdef CONFIG_XFRM | 24 | #ifdef CONFIG_XFRM |
25 | extern u32 sysctl_xfrm_aevent_etime; | 25 | extern u32 sysctl_xfrm_aevent_etime; |
26 | extern u32 sysctl_xfrm_aevent_rseqth; | 26 | extern u32 sysctl_xfrm_aevent_rseqth; |
27 | extern int sysctl_xfrm_larval_drop; | ||
27 | #endif | 28 | #endif |
28 | 29 | ||
29 | ctl_table core_table[] = { | 30 | ctl_table core_table[] = { |
@@ -118,6 +119,14 @@ ctl_table core_table[] = { | |||
118 | .mode = 0644, | 119 | .mode = 0644, |
119 | .proc_handler = &proc_dointvec | 120 | .proc_handler = &proc_dointvec |
120 | }, | 121 | }, |
122 | { | ||
123 | .ctl_name = CTL_UNNUMBERED, | ||
124 | .procname = "xfrm_larval_drop", | ||
125 | .data = &sysctl_xfrm_larval_drop, | ||
126 | .maxlen = sizeof(int), | ||
127 | .mode = 0644, | ||
128 | .proc_handler = &proc_dointvec | ||
129 | }, | ||
121 | #endif /* CONFIG_XFRM */ | 130 | #endif /* CONFIG_XFRM */ |
122 | #endif /* CONFIG_NET */ | 131 | #endif /* CONFIG_NET */ |
123 | { | 132 | { |
diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c index 64eac2515aa2..31737cdf156a 100644 --- a/net/dccp/ipv6.c +++ b/net/dccp/ipv6.c | |||
@@ -1043,9 +1043,13 @@ static int dccp_v6_connect(struct sock *sk, struct sockaddr *uaddr, | |||
1043 | if (final_p) | 1043 | if (final_p) |
1044 | ipv6_addr_copy(&fl.fl6_dst, final_p); | 1044 | ipv6_addr_copy(&fl.fl6_dst, final_p); |
1045 | 1045 | ||
1046 | err = xfrm_lookup(&dst, &fl, sk, 1); | 1046 | err = __xfrm_lookup(&dst, &fl, sk, 1); |
1047 | if (err < 0) | 1047 | if (err < 0) { |
1048 | goto failure; | 1048 | if (err == -EREMOTE) |
1049 | err = ip6_dst_blackhole(sk, &dst, &fl); | ||
1050 | if (err < 0) | ||
1051 | goto failure; | ||
1052 | } | ||
1049 | 1053 | ||
1050 | if (saddr == NULL) { | 1054 | if (saddr == NULL) { |
1051 | saddr = &fl.fl6_src; | 1055 | saddr = &fl.fl6_src; |
diff --git a/net/ipv4/route.c b/net/ipv4/route.c index df9fe4f2e8cc..8603cfb271f2 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c | |||
@@ -2598,6 +2598,69 @@ int __ip_route_output_key(struct rtable **rp, const struct flowi *flp) | |||
2598 | 2598 | ||
2599 | EXPORT_SYMBOL_GPL(__ip_route_output_key); | 2599 | EXPORT_SYMBOL_GPL(__ip_route_output_key); |
2600 | 2600 | ||
2601 | static void ipv4_rt_blackhole_update_pmtu(struct dst_entry *dst, u32 mtu) | ||
2602 | { | ||
2603 | } | ||
2604 | |||
2605 | static struct dst_ops ipv4_dst_blackhole_ops = { | ||
2606 | .family = AF_INET, | ||
2607 | .protocol = __constant_htons(ETH_P_IP), | ||
2608 | .destroy = ipv4_dst_destroy, | ||
2609 | .check = ipv4_dst_check, | ||
2610 | .update_pmtu = ipv4_rt_blackhole_update_pmtu, | ||
2611 | .entry_size = sizeof(struct rtable), | ||
2612 | }; | ||
2613 | |||
2614 | |||
2615 | static int ipv4_blackhole_output(struct sk_buff *skb) | ||
2616 | { | ||
2617 | kfree_skb(skb); | ||
2618 | return 0; | ||
2619 | } | ||
2620 | |||
2621 | static int ipv4_dst_blackhole(struct rtable **rp, struct flowi *flp, struct sock *sk) | ||
2622 | { | ||
2623 | struct rtable *ort = *rp; | ||
2624 | struct rtable *rt = (struct rtable *) | ||
2625 | dst_alloc(&ipv4_dst_blackhole_ops); | ||
2626 | |||
2627 | if (rt) { | ||
2628 | struct dst_entry *new = &rt->u.dst; | ||
2629 | |||
2630 | atomic_set(&new->__refcnt, 1); | ||
2631 | new->__use = 1; | ||
2632 | new->input = ipv4_blackhole_output; | ||
2633 | new->output = ipv4_blackhole_output; | ||
2634 | memcpy(new->metrics, ort->u.dst.metrics, RTAX_MAX*sizeof(u32)); | ||
2635 | |||
2636 | new->dev = ort->u.dst.dev; | ||
2637 | if (new->dev) | ||
2638 | dev_hold(new->dev); | ||
2639 | |||
2640 | rt->fl = ort->fl; | ||
2641 | |||
2642 | rt->idev = ort->idev; | ||
2643 | if (rt->idev) | ||
2644 | in_dev_hold(rt->idev); | ||
2645 | rt->rt_flags = ort->rt_flags; | ||
2646 | rt->rt_type = ort->rt_type; | ||
2647 | rt->rt_dst = ort->rt_dst; | ||
2648 | rt->rt_src = ort->rt_src; | ||
2649 | rt->rt_iif = ort->rt_iif; | ||
2650 | rt->rt_gateway = ort->rt_gateway; | ||
2651 | rt->rt_spec_dst = ort->rt_spec_dst; | ||
2652 | rt->peer = ort->peer; | ||
2653 | if (rt->peer) | ||
2654 | atomic_inc(&rt->peer->refcnt); | ||
2655 | |||
2656 | dst_free(new); | ||
2657 | } | ||
2658 | |||
2659 | dst_release(&(*rp)->u.dst); | ||
2660 | *rp = rt; | ||
2661 | return (rt ? 0 : -ENOMEM); | ||
2662 | } | ||
2663 | |||
2601 | int ip_route_output_flow(struct rtable **rp, struct flowi *flp, struct sock *sk, int flags) | 2664 | int ip_route_output_flow(struct rtable **rp, struct flowi *flp, struct sock *sk, int flags) |
2602 | { | 2665 | { |
2603 | int err; | 2666 | int err; |
@@ -2610,7 +2673,11 @@ int ip_route_output_flow(struct rtable **rp, struct flowi *flp, struct sock *sk, | |||
2610 | flp->fl4_src = (*rp)->rt_src; | 2673 | flp->fl4_src = (*rp)->rt_src; |
2611 | if (!flp->fl4_dst) | 2674 | if (!flp->fl4_dst) |
2612 | flp->fl4_dst = (*rp)->rt_dst; | 2675 | flp->fl4_dst = (*rp)->rt_dst; |
2613 | return xfrm_lookup((struct dst_entry **)rp, flp, sk, flags); | 2676 | err = __xfrm_lookup((struct dst_entry **)rp, flp, sk, flags); |
2677 | if (err == -EREMOTE) | ||
2678 | err = ipv4_dst_blackhole(rp, flp, sk); | ||
2679 | |||
2680 | return err; | ||
2614 | } | 2681 | } |
2615 | 2682 | ||
2616 | return 0; | 2683 | return 0; |
@@ -3139,6 +3206,8 @@ int __init ip_rt_init(void) | |||
3139 | kmem_cache_create("ip_dst_cache", sizeof(struct rtable), 0, | 3206 | kmem_cache_create("ip_dst_cache", sizeof(struct rtable), 0, |
3140 | SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL, NULL); | 3207 | SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL, NULL); |
3141 | 3208 | ||
3209 | ipv4_dst_blackhole_ops.kmem_cachep = ipv4_dst_ops.kmem_cachep; | ||
3210 | |||
3142 | rt_hash_table = (struct rt_hash_bucket *) | 3211 | rt_hash_table = (struct rt_hash_bucket *) |
3143 | alloc_large_system_hash("IP route cache", | 3212 | alloc_large_system_hash("IP route cache", |
3144 | sizeof(struct rt_hash_bucket), | 3213 | sizeof(struct rt_hash_bucket), |
diff --git a/net/ipv6/datagram.c b/net/ipv6/datagram.c index 403eee66b9c5..b1fe7ac5dc90 100644 --- a/net/ipv6/datagram.c +++ b/net/ipv6/datagram.c | |||
@@ -177,8 +177,12 @@ ipv4_connected: | |||
177 | if (final_p) | 177 | if (final_p) |
178 | ipv6_addr_copy(&fl.fl6_dst, final_p); | 178 | ipv6_addr_copy(&fl.fl6_dst, final_p); |
179 | 179 | ||
180 | if ((err = xfrm_lookup(&dst, &fl, sk, 1)) < 0) | 180 | if ((err = __xfrm_lookup(&dst, &fl, sk, 1)) < 0) { |
181 | goto out; | 181 | if (err == -EREMOTE) |
182 | err = ip6_dst_blackhole(sk, &dst, &fl); | ||
183 | if (err < 0) | ||
184 | goto out; | ||
185 | } | ||
182 | 186 | ||
183 | /* source address lookup done in ip6_dst_lookup */ | 187 | /* source address lookup done in ip6_dst_lookup */ |
184 | 188 | ||
diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c index 009a1047fc3f..a58459a76684 100644 --- a/net/ipv6/raw.c +++ b/net/ipv6/raw.c | |||
@@ -818,8 +818,12 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk, | |||
818 | if (final_p) | 818 | if (final_p) |
819 | ipv6_addr_copy(&fl.fl6_dst, final_p); | 819 | ipv6_addr_copy(&fl.fl6_dst, final_p); |
820 | 820 | ||
821 | if ((err = xfrm_lookup(&dst, &fl, sk, 1)) < 0) | 821 | if ((err = __xfrm_lookup(&dst, &fl, sk, 1)) < 0) { |
822 | goto out; | 822 | if (err == -EREMOTE) |
823 | err = ip6_dst_blackhole(sk, &dst, &fl); | ||
824 | if (err < 0) | ||
825 | goto out; | ||
826 | } | ||
823 | 827 | ||
824 | if (hlimit < 0) { | 828 | if (hlimit < 0) { |
825 | if (ipv6_addr_is_multicast(&fl.fl6_dst)) | 829 | if (ipv6_addr_is_multicast(&fl.fl6_dst)) |
diff --git a/net/ipv6/route.c b/net/ipv6/route.c index b46ad53044ba..1324b06796c0 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c | |||
@@ -119,6 +119,19 @@ static struct dst_ops ip6_dst_ops = { | |||
119 | .entry_size = sizeof(struct rt6_info), | 119 | .entry_size = sizeof(struct rt6_info), |
120 | }; | 120 | }; |
121 | 121 | ||
122 | static void ip6_rt_blackhole_update_pmtu(struct dst_entry *dst, u32 mtu) | ||
123 | { | ||
124 | } | ||
125 | |||
126 | static struct dst_ops ip6_dst_blackhole_ops = { | ||
127 | .family = AF_INET6, | ||
128 | .protocol = __constant_htons(ETH_P_IPV6), | ||
129 | .destroy = ip6_dst_destroy, | ||
130 | .check = ip6_dst_check, | ||
131 | .update_pmtu = ip6_rt_blackhole_update_pmtu, | ||
132 | .entry_size = sizeof(struct rt6_info), | ||
133 | }; | ||
134 | |||
122 | struct rt6_info ip6_null_entry = { | 135 | struct rt6_info ip6_null_entry = { |
123 | .u = { | 136 | .u = { |
124 | .dst = { | 137 | .dst = { |
@@ -833,6 +846,54 @@ struct dst_entry * ip6_route_output(struct sock *sk, struct flowi *fl) | |||
833 | 846 | ||
834 | EXPORT_SYMBOL(ip6_route_output); | 847 | EXPORT_SYMBOL(ip6_route_output); |
835 | 848 | ||
849 | static int ip6_blackhole_output(struct sk_buff *skb) | ||
850 | { | ||
851 | kfree_skb(skb); | ||
852 | return 0; | ||
853 | } | ||
854 | |||
855 | int ip6_dst_blackhole(struct sock *sk, struct dst_entry **dstp, struct flowi *fl) | ||
856 | { | ||
857 | struct rt6_info *ort = (struct rt6_info *) *dstp; | ||
858 | struct rt6_info *rt = (struct rt6_info *) | ||
859 | dst_alloc(&ip6_dst_blackhole_ops); | ||
860 | struct dst_entry *new = NULL; | ||
861 | |||
862 | if (rt) { | ||
863 | new = &rt->u.dst; | ||
864 | |||
865 | atomic_set(&new->__refcnt, 1); | ||
866 | new->__use = 1; | ||
867 | new->input = ip6_blackhole_output; | ||
868 | new->output = ip6_blackhole_output; | ||
869 | |||
870 | memcpy(new->metrics, ort->u.dst.metrics, RTAX_MAX*sizeof(u32)); | ||
871 | new->dev = ort->u.dst.dev; | ||
872 | if (new->dev) | ||
873 | dev_hold(new->dev); | ||
874 | rt->rt6i_idev = ort->rt6i_idev; | ||
875 | if (rt->rt6i_idev) | ||
876 | in6_dev_hold(rt->rt6i_idev); | ||
877 | rt->rt6i_expires = 0; | ||
878 | |||
879 | ipv6_addr_copy(&rt->rt6i_gateway, &ort->rt6i_gateway); | ||
880 | rt->rt6i_flags = ort->rt6i_flags & ~RTF_EXPIRES; | ||
881 | rt->rt6i_metric = 0; | ||
882 | |||
883 | memcpy(&rt->rt6i_dst, &ort->rt6i_dst, sizeof(struct rt6key)); | ||
884 | #ifdef CONFIG_IPV6_SUBTREES | ||
885 | memcpy(&rt->rt6i_src, &ort->rt6i_src, sizeof(struct rt6key)); | ||
886 | #endif | ||
887 | |||
888 | dst_free(new); | ||
889 | } | ||
890 | |||
891 | dst_release(*dstp); | ||
892 | *dstp = new; | ||
893 | return (new ? 0 : -ENOMEM); | ||
894 | } | ||
895 | EXPORT_SYMBOL_GPL(ip6_dst_blackhole); | ||
896 | |||
836 | /* | 897 | /* |
837 | * Destination cache support functions | 898 | * Destination cache support functions |
838 | */ | 899 | */ |
@@ -2495,6 +2556,8 @@ void __init ip6_route_init(void) | |||
2495 | ip6_dst_ops.kmem_cachep = | 2556 | ip6_dst_ops.kmem_cachep = |
2496 | kmem_cache_create("ip6_dst_cache", sizeof(struct rt6_info), 0, | 2557 | kmem_cache_create("ip6_dst_cache", sizeof(struct rt6_info), 0, |
2497 | SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL, NULL); | 2558 | SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL, NULL); |
2559 | ip6_dst_blackhole_ops.kmem_cachep = ip6_dst_ops.kmem_cachep; | ||
2560 | |||
2498 | fib6_init(); | 2561 | fib6_init(); |
2499 | #ifdef CONFIG_PROC_FS | 2562 | #ifdef CONFIG_PROC_FS |
2500 | p = proc_net_create("ipv6_route", 0, rt6_proc_info); | 2563 | p = proc_net_create("ipv6_route", 0, rt6_proc_info); |
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index e2f25ea43b68..4f06a51ad4fd 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c | |||
@@ -265,8 +265,12 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr, | |||
265 | if (final_p) | 265 | if (final_p) |
266 | ipv6_addr_copy(&fl.fl6_dst, final_p); | 266 | ipv6_addr_copy(&fl.fl6_dst, final_p); |
267 | 267 | ||
268 | if ((err = xfrm_lookup(&dst, &fl, sk, 1)) < 0) | 268 | if ((err = __xfrm_lookup(&dst, &fl, sk, 1)) < 0) { |
269 | goto failure; | 269 | if (err == -EREMOTE) |
270 | err = ip6_dst_blackhole(sk, &dst, &fl); | ||
271 | if (err < 0) | ||
272 | goto failure; | ||
273 | } | ||
270 | 274 | ||
271 | if (saddr == NULL) { | 275 | if (saddr == NULL) { |
272 | saddr = &fl.fl6_src; | 276 | saddr = &fl.fl6_src; |
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index a7ae59c954d5..d1fbddd172e7 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c | |||
@@ -767,8 +767,12 @@ do_udp_sendmsg: | |||
767 | if (final_p) | 767 | if (final_p) |
768 | ipv6_addr_copy(&fl.fl6_dst, final_p); | 768 | ipv6_addr_copy(&fl.fl6_dst, final_p); |
769 | 769 | ||
770 | if ((err = xfrm_lookup(&dst, &fl, sk, 1)) < 0) | 770 | if ((err = __xfrm_lookup(&dst, &fl, sk, 1)) < 0) { |
771 | goto out; | 771 | if (err == -EREMOTE) |
772 | err = ip6_dst_blackhole(sk, &dst, &fl); | ||
773 | if (err < 0) | ||
774 | goto out; | ||
775 | } | ||
772 | 776 | ||
773 | if (hlimit < 0) { | 777 | if (hlimit < 0) { |
774 | if (ipv6_addr_is_multicast(&fl.fl6_dst)) | 778 | if (ipv6_addr_is_multicast(&fl.fl6_dst)) |
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c index d0882e53b6fc..b8bab89616a0 100644 --- a/net/xfrm/xfrm_policy.c +++ b/net/xfrm/xfrm_policy.c | |||
@@ -29,6 +29,8 @@ | |||
29 | 29 | ||
30 | #include "xfrm_hash.h" | 30 | #include "xfrm_hash.h" |
31 | 31 | ||
32 | int sysctl_xfrm_larval_drop; | ||
33 | |||
32 | DEFINE_MUTEX(xfrm_cfg_mutex); | 34 | DEFINE_MUTEX(xfrm_cfg_mutex); |
33 | EXPORT_SYMBOL(xfrm_cfg_mutex); | 35 | EXPORT_SYMBOL(xfrm_cfg_mutex); |
34 | 36 | ||
@@ -1390,8 +1392,8 @@ static int stale_bundle(struct dst_entry *dst); | |||
1390 | * At the moment we eat a raw IP route. Mostly to speed up lookups | 1392 | * At the moment we eat a raw IP route. Mostly to speed up lookups |
1391 | * on interfaces with disabled IPsec. | 1393 | * on interfaces with disabled IPsec. |
1392 | */ | 1394 | */ |
1393 | int xfrm_lookup(struct dst_entry **dst_p, struct flowi *fl, | 1395 | int __xfrm_lookup(struct dst_entry **dst_p, struct flowi *fl, |
1394 | struct sock *sk, int flags) | 1396 | struct sock *sk, int flags) |
1395 | { | 1397 | { |
1396 | struct xfrm_policy *policy; | 1398 | struct xfrm_policy *policy; |
1397 | struct xfrm_policy *pols[XFRM_POLICY_TYPE_MAX]; | 1399 | struct xfrm_policy *pols[XFRM_POLICY_TYPE_MAX]; |
@@ -1509,6 +1511,13 @@ restart: | |||
1509 | 1511 | ||
1510 | if (unlikely(nx<0)) { | 1512 | if (unlikely(nx<0)) { |
1511 | err = nx; | 1513 | err = nx; |
1514 | if (err == -EAGAIN && sysctl_xfrm_larval_drop) { | ||
1515 | /* EREMOTE tells the caller to generate | ||
1516 | * a one-shot blackhole route. | ||
1517 | */ | ||
1518 | xfrm_pol_put(policy); | ||
1519 | return -EREMOTE; | ||
1520 | } | ||
1512 | if (err == -EAGAIN && flags) { | 1521 | if (err == -EAGAIN && flags) { |
1513 | DECLARE_WAITQUEUE(wait, current); | 1522 | DECLARE_WAITQUEUE(wait, current); |
1514 | 1523 | ||
@@ -1598,6 +1607,21 @@ error: | |||
1598 | *dst_p = NULL; | 1607 | *dst_p = NULL; |
1599 | return err; | 1608 | return err; |
1600 | } | 1609 | } |
1610 | EXPORT_SYMBOL(__xfrm_lookup); | ||
1611 | |||
1612 | int xfrm_lookup(struct dst_entry **dst_p, struct flowi *fl, | ||
1613 | struct sock *sk, int flags) | ||
1614 | { | ||
1615 | int err = __xfrm_lookup(dst_p, fl, sk, flags); | ||
1616 | |||
1617 | if (err == -EREMOTE) { | ||
1618 | dst_release(*dst_p); | ||
1619 | *dst_p = NULL; | ||
1620 | err = -EAGAIN; | ||
1621 | } | ||
1622 | |||
1623 | return err; | ||
1624 | } | ||
1601 | EXPORT_SYMBOL(xfrm_lookup); | 1625 | EXPORT_SYMBOL(xfrm_lookup); |
1602 | 1626 | ||
1603 | static inline int | 1627 | static inline int |