diff options
-rw-r--r-- | include/net/xfrm.h | 10 | ||||
-rw-r--r-- | net/ipv4/xfrm4_policy.c | 42 | ||||
-rw-r--r-- | net/ipv6/xfrm6_policy.c | 43 | ||||
-rw-r--r-- | net/xfrm/xfrm_policy.c | 25 |
4 files changed, 97 insertions, 23 deletions
diff --git a/include/net/xfrm.h b/include/net/xfrm.h index 73e9a8ca3d3b..e142a256d5dc 100644 --- a/include/net/xfrm.h +++ b/include/net/xfrm.h | |||
@@ -1,6 +1,7 @@ | |||
1 | #ifndef _NET_XFRM_H | 1 | #ifndef _NET_XFRM_H |
2 | #define _NET_XFRM_H | 2 | #define _NET_XFRM_H |
3 | 3 | ||
4 | #include <linux/compiler.h> | ||
4 | #include <linux/xfrm.h> | 5 | #include <linux/xfrm.h> |
5 | #include <linux/spinlock.h> | 6 | #include <linux/spinlock.h> |
6 | #include <linux/list.h> | 7 | #include <linux/list.h> |
@@ -516,6 +517,15 @@ struct xfrm_dst | |||
516 | u32 child_mtu_cached; | 517 | u32 child_mtu_cached; |
517 | }; | 518 | }; |
518 | 519 | ||
520 | static inline void xfrm_dst_destroy(struct xfrm_dst *xdst) | ||
521 | { | ||
522 | dst_release(xdst->route); | ||
523 | if (likely(xdst->u.dst.xfrm)) | ||
524 | xfrm_state_put(xdst->u.dst.xfrm); | ||
525 | } | ||
526 | |||
527 | extern void xfrm_dst_ifdown(struct dst_entry *dst, struct net_device *dev); | ||
528 | |||
519 | /* Decapsulation state, used by the input to store data during | 529 | /* Decapsulation state, used by the input to store data during |
520 | * decapsulation procedure, to be used later (during the policy | 530 | * decapsulation procedure, to be used later (during the policy |
521 | * check | 531 | * check |
diff --git a/net/ipv4/xfrm4_policy.c b/net/ipv4/xfrm4_policy.c index 7fe2afd2e669..b2b60f3e9cdd 100644 --- a/net/ipv4/xfrm4_policy.c +++ b/net/ipv4/xfrm4_policy.c | |||
@@ -8,7 +8,10 @@ | |||
8 | * | 8 | * |
9 | */ | 9 | */ |
10 | 10 | ||
11 | #include <asm/bug.h> | ||
12 | #include <linux/compiler.h> | ||
11 | #include <linux/config.h> | 13 | #include <linux/config.h> |
14 | #include <linux/inetdevice.h> | ||
12 | #include <net/xfrm.h> | 15 | #include <net/xfrm.h> |
13 | #include <net/ip.h> | 16 | #include <net/ip.h> |
14 | 17 | ||
@@ -152,6 +155,8 @@ __xfrm4_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int | |||
152 | x->u.rt.rt_dst = rt0->rt_dst; | 155 | x->u.rt.rt_dst = rt0->rt_dst; |
153 | x->u.rt.rt_gateway = rt->rt_gateway; | 156 | x->u.rt.rt_gateway = rt->rt_gateway; |
154 | x->u.rt.rt_spec_dst = rt0->rt_spec_dst; | 157 | x->u.rt.rt_spec_dst = rt0->rt_spec_dst; |
158 | x->u.rt.idev = rt0->idev; | ||
159 | in_dev_hold(rt0->idev); | ||
155 | header_len -= x->u.dst.xfrm->props.header_len; | 160 | header_len -= x->u.dst.xfrm->props.header_len; |
156 | trailer_len -= x->u.dst.xfrm->props.trailer_len; | 161 | trailer_len -= x->u.dst.xfrm->props.trailer_len; |
157 | } | 162 | } |
@@ -243,11 +248,48 @@ static void xfrm4_update_pmtu(struct dst_entry *dst, u32 mtu) | |||
243 | path->ops->update_pmtu(path, mtu); | 248 | path->ops->update_pmtu(path, mtu); |
244 | } | 249 | } |
245 | 250 | ||
251 | static void xfrm4_dst_destroy(struct dst_entry *dst) | ||
252 | { | ||
253 | struct xfrm_dst *xdst = (struct xfrm_dst *)dst; | ||
254 | |||
255 | if (likely(xdst->u.rt.idev)) | ||
256 | in_dev_put(xdst->u.rt.idev); | ||
257 | xfrm_dst_destroy(xdst); | ||
258 | } | ||
259 | |||
260 | static void xfrm4_dst_ifdown(struct dst_entry *dst, struct net_device *dev, | ||
261 | int unregister) | ||
262 | { | ||
263 | struct xfrm_dst *xdst; | ||
264 | |||
265 | if (!unregister) | ||
266 | return; | ||
267 | |||
268 | xdst = (struct xfrm_dst *)dst; | ||
269 | if (xdst->u.rt.idev->dev == dev) { | ||
270 | struct in_device *loopback_idev = in_dev_get(&loopback_dev); | ||
271 | BUG_ON(!loopback_idev); | ||
272 | |||
273 | do { | ||
274 | in_dev_put(xdst->u.rt.idev); | ||
275 | xdst->u.rt.idev = loopback_idev; | ||
276 | in_dev_hold(loopback_idev); | ||
277 | xdst = (struct xfrm_dst *)xdst->u.dst.child; | ||
278 | } while (xdst->u.dst.xfrm); | ||
279 | |||
280 | __in_dev_put(loopback_idev); | ||
281 | } | ||
282 | |||
283 | xfrm_dst_ifdown(dst, dev); | ||
284 | } | ||
285 | |||
246 | static struct dst_ops xfrm4_dst_ops = { | 286 | static struct dst_ops xfrm4_dst_ops = { |
247 | .family = AF_INET, | 287 | .family = AF_INET, |
248 | .protocol = __constant_htons(ETH_P_IP), | 288 | .protocol = __constant_htons(ETH_P_IP), |
249 | .gc = xfrm4_garbage_collect, | 289 | .gc = xfrm4_garbage_collect, |
250 | .update_pmtu = xfrm4_update_pmtu, | 290 | .update_pmtu = xfrm4_update_pmtu, |
291 | .destroy = xfrm4_dst_destroy, | ||
292 | .ifdown = xfrm4_dst_ifdown, | ||
251 | .gc_thresh = 1024, | 293 | .gc_thresh = 1024, |
252 | .entry_size = sizeof(struct xfrm_dst), | 294 | .entry_size = sizeof(struct xfrm_dst), |
253 | }; | 295 | }; |
diff --git a/net/ipv6/xfrm6_policy.c b/net/ipv6/xfrm6_policy.c index 8a4f37de4d2d..4429b1a1fe5f 100644 --- a/net/ipv6/xfrm6_policy.c +++ b/net/ipv6/xfrm6_policy.c | |||
@@ -11,7 +11,11 @@ | |||
11 | * | 11 | * |
12 | */ | 12 | */ |
13 | 13 | ||
14 | #include <asm/bug.h> | ||
15 | #include <linux/compiler.h> | ||
14 | #include <linux/config.h> | 16 | #include <linux/config.h> |
17 | #include <linux/netdevice.h> | ||
18 | #include <net/addrconf.h> | ||
15 | #include <net/xfrm.h> | 19 | #include <net/xfrm.h> |
16 | #include <net/ip.h> | 20 | #include <net/ip.h> |
17 | #include <net/ipv6.h> | 21 | #include <net/ipv6.h> |
@@ -166,6 +170,8 @@ __xfrm6_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int | |||
166 | memcpy(&x->u.rt6.rt6i_gateway, &rt0->rt6i_gateway, sizeof(x->u.rt6.rt6i_gateway)); | 170 | memcpy(&x->u.rt6.rt6i_gateway, &rt0->rt6i_gateway, sizeof(x->u.rt6.rt6i_gateway)); |
167 | x->u.rt6.rt6i_dst = rt0->rt6i_dst; | 171 | x->u.rt6.rt6i_dst = rt0->rt6i_dst; |
168 | x->u.rt6.rt6i_src = rt0->rt6i_src; | 172 | x->u.rt6.rt6i_src = rt0->rt6i_src; |
173 | x->u.rt6.rt6i_idev = rt0->rt6i_idev; | ||
174 | in6_dev_hold(rt0->rt6i_idev); | ||
169 | header_len -= x->u.dst.xfrm->props.header_len; | 175 | header_len -= x->u.dst.xfrm->props.header_len; |
170 | trailer_len -= x->u.dst.xfrm->props.trailer_len; | 176 | trailer_len -= x->u.dst.xfrm->props.trailer_len; |
171 | } | 177 | } |
@@ -251,11 +257,48 @@ static void xfrm6_update_pmtu(struct dst_entry *dst, u32 mtu) | |||
251 | path->ops->update_pmtu(path, mtu); | 257 | path->ops->update_pmtu(path, mtu); |
252 | } | 258 | } |
253 | 259 | ||
260 | static void xfrm6_dst_destroy(struct dst_entry *dst) | ||
261 | { | ||
262 | struct xfrm_dst *xdst = (struct xfrm_dst *)dst; | ||
263 | |||
264 | if (likely(xdst->u.rt6.rt6i_idev)) | ||
265 | in6_dev_put(xdst->u.rt6.rt6i_idev); | ||
266 | xfrm_dst_destroy(xdst); | ||
267 | } | ||
268 | |||
269 | static void xfrm6_dst_ifdown(struct dst_entry *dst, struct net_device *dev, | ||
270 | int unregister) | ||
271 | { | ||
272 | struct xfrm_dst *xdst; | ||
273 | |||
274 | if (!unregister) | ||
275 | return; | ||
276 | |||
277 | xdst = (struct xfrm_dst *)dst; | ||
278 | if (xdst->u.rt6.rt6i_idev->dev == dev) { | ||
279 | struct inet6_dev *loopback_idev = in6_dev_get(&loopback_dev); | ||
280 | BUG_ON(!loopback_idev); | ||
281 | |||
282 | do { | ||
283 | in6_dev_put(xdst->u.rt6.rt6i_idev); | ||
284 | xdst->u.rt6.rt6i_idev = loopback_idev; | ||
285 | in6_dev_hold(loopback_idev); | ||
286 | xdst = (struct xfrm_dst *)xdst->u.dst.child; | ||
287 | } while (xdst->u.dst.xfrm); | ||
288 | |||
289 | __in6_dev_put(loopback_idev); | ||
290 | } | ||
291 | |||
292 | xfrm_dst_ifdown(dst, dev); | ||
293 | } | ||
294 | |||
254 | static struct dst_ops xfrm6_dst_ops = { | 295 | static struct dst_ops xfrm6_dst_ops = { |
255 | .family = AF_INET6, | 296 | .family = AF_INET6, |
256 | .protocol = __constant_htons(ETH_P_IPV6), | 297 | .protocol = __constant_htons(ETH_P_IPV6), |
257 | .gc = xfrm6_garbage_collect, | 298 | .gc = xfrm6_garbage_collect, |
258 | .update_pmtu = xfrm6_update_pmtu, | 299 | .update_pmtu = xfrm6_update_pmtu, |
300 | .destroy = xfrm6_dst_destroy, | ||
301 | .ifdown = xfrm6_dst_ifdown, | ||
259 | .gc_thresh = 1024, | 302 | .gc_thresh = 1024, |
260 | .entry_size = sizeof(struct xfrm_dst), | 303 | .entry_size = sizeof(struct xfrm_dst), |
261 | }; | 304 | }; |
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c index 80828078733d..55ed979db144 100644 --- a/net/xfrm/xfrm_policy.c +++ b/net/xfrm/xfrm_policy.c | |||
@@ -1028,30 +1028,15 @@ static int stale_bundle(struct dst_entry *dst) | |||
1028 | return !xfrm_bundle_ok((struct xfrm_dst *)dst, NULL, AF_UNSPEC); | 1028 | return !xfrm_bundle_ok((struct xfrm_dst *)dst, NULL, AF_UNSPEC); |
1029 | } | 1029 | } |
1030 | 1030 | ||
1031 | static void xfrm_dst_destroy(struct dst_entry *dst) | 1031 | void xfrm_dst_ifdown(struct dst_entry *dst, struct net_device *dev) |
1032 | { | 1032 | { |
1033 | struct xfrm_dst *xdst = (struct xfrm_dst *)dst; | ||
1034 | |||
1035 | dst_release(xdst->route); | ||
1036 | |||
1037 | if (!dst->xfrm) | ||
1038 | return; | ||
1039 | xfrm_state_put(dst->xfrm); | ||
1040 | dst->xfrm = NULL; | ||
1041 | } | ||
1042 | |||
1043 | static void xfrm_dst_ifdown(struct dst_entry *dst, struct net_device *dev, | ||
1044 | int unregister) | ||
1045 | { | ||
1046 | if (!unregister) | ||
1047 | return; | ||
1048 | |||
1049 | while ((dst = dst->child) && dst->xfrm && dst->dev == dev) { | 1033 | while ((dst = dst->child) && dst->xfrm && dst->dev == dev) { |
1050 | dst->dev = &loopback_dev; | 1034 | dst->dev = &loopback_dev; |
1051 | dev_hold(&loopback_dev); | 1035 | dev_hold(&loopback_dev); |
1052 | dev_put(dev); | 1036 | dev_put(dev); |
1053 | } | 1037 | } |
1054 | } | 1038 | } |
1039 | EXPORT_SYMBOL(xfrm_dst_ifdown); | ||
1055 | 1040 | ||
1056 | static void xfrm_link_failure(struct sk_buff *skb) | 1041 | static void xfrm_link_failure(struct sk_buff *skb) |
1057 | { | 1042 | { |
@@ -1262,10 +1247,6 @@ int xfrm_policy_register_afinfo(struct xfrm_policy_afinfo *afinfo) | |||
1262 | dst_ops->kmem_cachep = xfrm_dst_cache; | 1247 | dst_ops->kmem_cachep = xfrm_dst_cache; |
1263 | if (likely(dst_ops->check == NULL)) | 1248 | if (likely(dst_ops->check == NULL)) |
1264 | dst_ops->check = xfrm_dst_check; | 1249 | dst_ops->check = xfrm_dst_check; |
1265 | if (likely(dst_ops->destroy == NULL)) | ||
1266 | dst_ops->destroy = xfrm_dst_destroy; | ||
1267 | if (likely(dst_ops->ifdown == NULL)) | ||
1268 | dst_ops->ifdown = xfrm_dst_ifdown; | ||
1269 | if (likely(dst_ops->negative_advice == NULL)) | 1250 | if (likely(dst_ops->negative_advice == NULL)) |
1270 | dst_ops->negative_advice = xfrm_negative_advice; | 1251 | dst_ops->negative_advice = xfrm_negative_advice; |
1271 | if (likely(dst_ops->link_failure == NULL)) | 1252 | if (likely(dst_ops->link_failure == NULL)) |
@@ -1297,8 +1278,6 @@ int xfrm_policy_unregister_afinfo(struct xfrm_policy_afinfo *afinfo) | |||
1297 | xfrm_policy_afinfo[afinfo->family] = NULL; | 1278 | xfrm_policy_afinfo[afinfo->family] = NULL; |
1298 | dst_ops->kmem_cachep = NULL; | 1279 | dst_ops->kmem_cachep = NULL; |
1299 | dst_ops->check = NULL; | 1280 | dst_ops->check = NULL; |
1300 | dst_ops->destroy = NULL; | ||
1301 | dst_ops->ifdown = NULL; | ||
1302 | dst_ops->negative_advice = NULL; | 1281 | dst_ops->negative_advice = NULL; |
1303 | dst_ops->link_failure = NULL; | 1282 | dst_ops->link_failure = NULL; |
1304 | dst_ops->get_mss = NULL; | 1283 | dst_ops->get_mss = NULL; |