diff options
Diffstat (limited to 'net/ipv6')
| -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 | }; | 
