diff options
Diffstat (limited to 'net/xfrm/xfrm_policy.c')
-rw-r--r-- | net/xfrm/xfrm_policy.c | 48 |
1 files changed, 40 insertions, 8 deletions
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c index beeed602aeb3..fdde51f4271a 100644 --- a/net/xfrm/xfrm_policy.c +++ b/net/xfrm/xfrm_policy.c | |||
@@ -39,6 +39,11 @@ | |||
39 | #define XFRM_QUEUE_TMO_MAX ((unsigned)(60*HZ)) | 39 | #define XFRM_QUEUE_TMO_MAX ((unsigned)(60*HZ)) |
40 | #define XFRM_MAX_QUEUE_LEN 100 | 40 | #define XFRM_MAX_QUEUE_LEN 100 |
41 | 41 | ||
42 | struct xfrm_flo { | ||
43 | struct dst_entry *dst_orig; | ||
44 | u8 flags; | ||
45 | }; | ||
46 | |||
42 | static DEFINE_SPINLOCK(xfrm_policy_afinfo_lock); | 47 | static DEFINE_SPINLOCK(xfrm_policy_afinfo_lock); |
43 | static struct xfrm_policy_afinfo __rcu *xfrm_policy_afinfo[NPROTO] | 48 | static struct xfrm_policy_afinfo __rcu *xfrm_policy_afinfo[NPROTO] |
44 | __read_mostly; | 49 | __read_mostly; |
@@ -1877,13 +1882,14 @@ static int xdst_queue_output(struct sock *sk, struct sk_buff *skb) | |||
1877 | } | 1882 | } |
1878 | 1883 | ||
1879 | static struct xfrm_dst *xfrm_create_dummy_bundle(struct net *net, | 1884 | static struct xfrm_dst *xfrm_create_dummy_bundle(struct net *net, |
1880 | struct dst_entry *dst, | 1885 | struct xfrm_flo *xflo, |
1881 | const struct flowi *fl, | 1886 | const struct flowi *fl, |
1882 | int num_xfrms, | 1887 | int num_xfrms, |
1883 | u16 family) | 1888 | u16 family) |
1884 | { | 1889 | { |
1885 | int err; | 1890 | int err; |
1886 | struct net_device *dev; | 1891 | struct net_device *dev; |
1892 | struct dst_entry *dst; | ||
1887 | struct dst_entry *dst1; | 1893 | struct dst_entry *dst1; |
1888 | struct xfrm_dst *xdst; | 1894 | struct xfrm_dst *xdst; |
1889 | 1895 | ||
@@ -1891,9 +1897,12 @@ static struct xfrm_dst *xfrm_create_dummy_bundle(struct net *net, | |||
1891 | if (IS_ERR(xdst)) | 1897 | if (IS_ERR(xdst)) |
1892 | return xdst; | 1898 | return xdst; |
1893 | 1899 | ||
1894 | if (net->xfrm.sysctl_larval_drop || num_xfrms <= 0) | 1900 | if (!(xflo->flags & XFRM_LOOKUP_QUEUE) || |
1901 | net->xfrm.sysctl_larval_drop || | ||
1902 | num_xfrms <= 0) | ||
1895 | return xdst; | 1903 | return xdst; |
1896 | 1904 | ||
1905 | dst = xflo->dst_orig; | ||
1897 | dst1 = &xdst->u.dst; | 1906 | dst1 = &xdst->u.dst; |
1898 | dst_hold(dst); | 1907 | dst_hold(dst); |
1899 | xdst->route = dst; | 1908 | xdst->route = dst; |
@@ -1935,7 +1944,7 @@ static struct flow_cache_object * | |||
1935 | xfrm_bundle_lookup(struct net *net, const struct flowi *fl, u16 family, u8 dir, | 1944 | xfrm_bundle_lookup(struct net *net, const struct flowi *fl, u16 family, u8 dir, |
1936 | struct flow_cache_object *oldflo, void *ctx) | 1945 | struct flow_cache_object *oldflo, void *ctx) |
1937 | { | 1946 | { |
1938 | struct dst_entry *dst_orig = (struct dst_entry *)ctx; | 1947 | struct xfrm_flo *xflo = (struct xfrm_flo *)ctx; |
1939 | struct xfrm_policy *pols[XFRM_POLICY_TYPE_MAX]; | 1948 | struct xfrm_policy *pols[XFRM_POLICY_TYPE_MAX]; |
1940 | struct xfrm_dst *xdst, *new_xdst; | 1949 | struct xfrm_dst *xdst, *new_xdst; |
1941 | int num_pols = 0, num_xfrms = 0, i, err, pol_dead; | 1950 | int num_pols = 0, num_xfrms = 0, i, err, pol_dead; |
@@ -1976,7 +1985,8 @@ xfrm_bundle_lookup(struct net *net, const struct flowi *fl, u16 family, u8 dir, | |||
1976 | goto make_dummy_bundle; | 1985 | goto make_dummy_bundle; |
1977 | } | 1986 | } |
1978 | 1987 | ||
1979 | new_xdst = xfrm_resolve_and_create_bundle(pols, num_pols, fl, family, dst_orig); | 1988 | new_xdst = xfrm_resolve_and_create_bundle(pols, num_pols, fl, family, |
1989 | xflo->dst_orig); | ||
1980 | if (IS_ERR(new_xdst)) { | 1990 | if (IS_ERR(new_xdst)) { |
1981 | err = PTR_ERR(new_xdst); | 1991 | err = PTR_ERR(new_xdst); |
1982 | if (err != -EAGAIN) | 1992 | if (err != -EAGAIN) |
@@ -2010,7 +2020,7 @@ make_dummy_bundle: | |||
2010 | /* We found policies, but there's no bundles to instantiate: | 2020 | /* We found policies, but there's no bundles to instantiate: |
2011 | * either because the policy blocks, has no transformations or | 2021 | * either because the policy blocks, has no transformations or |
2012 | * we could not build template (no xfrm_states).*/ | 2022 | * we could not build template (no xfrm_states).*/ |
2013 | xdst = xfrm_create_dummy_bundle(net, dst_orig, fl, num_xfrms, family); | 2023 | xdst = xfrm_create_dummy_bundle(net, xflo, fl, num_xfrms, family); |
2014 | if (IS_ERR(xdst)) { | 2024 | if (IS_ERR(xdst)) { |
2015 | xfrm_pols_put(pols, num_pols); | 2025 | xfrm_pols_put(pols, num_pols); |
2016 | return ERR_CAST(xdst); | 2026 | return ERR_CAST(xdst); |
@@ -2104,13 +2114,18 @@ struct dst_entry *xfrm_lookup(struct net *net, struct dst_entry *dst_orig, | |||
2104 | } | 2114 | } |
2105 | 2115 | ||
2106 | if (xdst == NULL) { | 2116 | if (xdst == NULL) { |
2117 | struct xfrm_flo xflo; | ||
2118 | |||
2119 | xflo.dst_orig = dst_orig; | ||
2120 | xflo.flags = flags; | ||
2121 | |||
2107 | /* To accelerate a bit... */ | 2122 | /* To accelerate a bit... */ |
2108 | if ((dst_orig->flags & DST_NOXFRM) || | 2123 | if ((dst_orig->flags & DST_NOXFRM) || |
2109 | !net->xfrm.policy_count[XFRM_POLICY_OUT]) | 2124 | !net->xfrm.policy_count[XFRM_POLICY_OUT]) |
2110 | goto nopol; | 2125 | goto nopol; |
2111 | 2126 | ||
2112 | flo = flow_cache_lookup(net, fl, family, dir, | 2127 | flo = flow_cache_lookup(net, fl, family, dir, |
2113 | xfrm_bundle_lookup, dst_orig); | 2128 | xfrm_bundle_lookup, &xflo); |
2114 | if (flo == NULL) | 2129 | if (flo == NULL) |
2115 | goto nopol; | 2130 | goto nopol; |
2116 | if (IS_ERR(flo)) { | 2131 | if (IS_ERR(flo)) { |
@@ -2138,7 +2153,7 @@ struct dst_entry *xfrm_lookup(struct net *net, struct dst_entry *dst_orig, | |||
2138 | xfrm_pols_put(pols, drop_pols); | 2153 | xfrm_pols_put(pols, drop_pols); |
2139 | XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTNOSTATES); | 2154 | XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTNOSTATES); |
2140 | 2155 | ||
2141 | return make_blackhole(net, family, dst_orig); | 2156 | return ERR_PTR(-EREMOTE); |
2142 | } | 2157 | } |
2143 | 2158 | ||
2144 | err = -EAGAIN; | 2159 | err = -EAGAIN; |
@@ -2195,6 +2210,23 @@ dropdst: | |||
2195 | } | 2210 | } |
2196 | EXPORT_SYMBOL(xfrm_lookup); | 2211 | EXPORT_SYMBOL(xfrm_lookup); |
2197 | 2212 | ||
2213 | /* Callers of xfrm_lookup_route() must ensure a call to dst_output(). | ||
2214 | * Otherwise we may send out blackholed packets. | ||
2215 | */ | ||
2216 | struct dst_entry *xfrm_lookup_route(struct net *net, struct dst_entry *dst_orig, | ||
2217 | const struct flowi *fl, | ||
2218 | struct sock *sk, int flags) | ||
2219 | { | ||
2220 | struct dst_entry *dst = xfrm_lookup(net, dst_orig, fl, sk, | ||
2221 | flags | XFRM_LOOKUP_QUEUE); | ||
2222 | |||
2223 | if (IS_ERR(dst) && PTR_ERR(dst) == -EREMOTE) | ||
2224 | return make_blackhole(net, dst_orig->ops->family, dst_orig); | ||
2225 | |||
2226 | return dst; | ||
2227 | } | ||
2228 | EXPORT_SYMBOL(xfrm_lookup_route); | ||
2229 | |||
2198 | static inline int | 2230 | static inline int |
2199 | xfrm_secpath_reject(int idx, struct sk_buff *skb, const struct flowi *fl) | 2231 | xfrm_secpath_reject(int idx, struct sk_buff *skb, const struct flowi *fl) |
2200 | { | 2232 | { |
@@ -2460,7 +2492,7 @@ int __xfrm_route_forward(struct sk_buff *skb, unsigned short family) | |||
2460 | 2492 | ||
2461 | skb_dst_force(skb); | 2493 | skb_dst_force(skb); |
2462 | 2494 | ||
2463 | dst = xfrm_lookup(net, skb_dst(skb), &fl, NULL, 0); | 2495 | dst = xfrm_lookup(net, skb_dst(skb), &fl, NULL, XFRM_LOOKUP_QUEUE); |
2464 | if (IS_ERR(dst)) { | 2496 | if (IS_ERR(dst)) { |
2465 | res = 0; | 2497 | res = 0; |
2466 | dst = NULL; | 2498 | dst = NULL; |