aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4/xfrm4_policy.c
diff options
context:
space:
mode:
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 @@
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
251static 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
260static 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
246static struct dst_ops xfrm4_dst_ops = { 286static 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};