diff options
Diffstat (limited to 'net/ipv6/xfrm6_policy.c')
-rw-r--r-- | net/ipv6/xfrm6_policy.c | 43 |
1 files changed, 43 insertions, 0 deletions
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 | }; |