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; |
