summaryrefslogtreecommitdiffstats
path: root/net/ipv4/xfrm4_policy.c
diff options
context:
space:
mode:
authorDavid Woodhouse <dwmw2@shinybook.infradead.org>2005-05-05 13:59:37 +0100
committerDavid Woodhouse <dwmw2@shinybook.infradead.org>2005-05-05 13:59:37 +0100
commitbfd4bda097f8758d28e632ff2035e25577f6b060 (patch)
tree022276b3625a432c7132e39776e7e448445087ac /net/ipv4/xfrm4_policy.c
parent488f2eaca1b0831a5a5e6a66e33bad2cdeff7238 (diff)
parentb2d84f078a8be40f5ae3b4d2ac001e2a7f45fe4f (diff)
downloadlinux-bfd4bda097f8758d28e632ff2035e25577f6b060.tar.gz
linux-bfd4bda097f8758d28e632ff2035e25577f6b060.tar.bz2
linux-bfd4bda097f8758d28e632ff2035e25577f6b060.zip
Merge with master.kernel.org:/pub/scm/linux/kernel/git/torvalds/linux-2.6.git
Diffstat (limited to 'net/ipv4/xfrm4_policy.c')
-rw-r--r--net/ipv4/xfrm4_policy.c42
1 files changed, 42 insertions, 0 deletions
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 @@
*
*/
+#include <asm/bug.h>
+#include <linux/compiler.h>
#include <linux/config.h>
+#include <linux/inetdevice.h>
#include <net/xfrm.h>
#include <net/ip.h>
@@ -152,6 +155,8 @@ __xfrm4_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int
x->u.rt.rt_dst = rt0->rt_dst;
x->u.rt.rt_gateway = rt->rt_gateway;
x->u.rt.rt_spec_dst = rt0->rt_spec_dst;
+ x->u.rt.idev = rt0->idev;
+ in_dev_hold(rt0->idev);
header_len -= x->u.dst.xfrm->props.header_len;
trailer_len -= x->u.dst.xfrm->props.trailer_len;
}
@@ -243,11 +248,48 @@ static void xfrm4_update_pmtu(struct dst_entry *dst, u32 mtu)
path->ops->update_pmtu(path, mtu);
}
+static void xfrm4_dst_destroy(struct dst_entry *dst)
+{
+ struct xfrm_dst *xdst = (struct xfrm_dst *)dst;
+
+ if (likely(xdst->u.rt.idev))
+ in_dev_put(xdst->u.rt.idev);
+ xfrm_dst_destroy(xdst);
+}
+
+static void xfrm4_dst_ifdown(struct dst_entry *dst, struct net_device *dev,
+ int unregister)
+{
+ struct xfrm_dst *xdst;
+
+ if (!unregister)
+ return;
+
+ xdst = (struct xfrm_dst *)dst;
+ if (xdst->u.rt.idev->dev == dev) {
+ struct in_device *loopback_idev = in_dev_get(&loopback_dev);
+ BUG_ON(!loopback_idev);
+
+ do {
+ in_dev_put(xdst->u.rt.idev);
+ xdst->u.rt.idev = loopback_idev;
+ in_dev_hold(loopback_idev);
+ xdst = (struct xfrm_dst *)xdst->u.dst.child;
+ } while (xdst->u.dst.xfrm);
+
+ __in_dev_put(loopback_idev);
+ }
+
+ xfrm_dst_ifdown(dst, dev);
+}
+
static struct dst_ops xfrm4_dst_ops = {
.family = AF_INET,
.protocol = __constant_htons(ETH_P_IP),
.gc = xfrm4_garbage_collect,
.update_pmtu = xfrm4_update_pmtu,
+ .destroy = xfrm4_dst_destroy,
+ .ifdown = xfrm4_dst_ifdown,
.gc_thresh = 1024,
.entry_size = sizeof(struct xfrm_dst),
};