aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/net/xfrm.h10
-rw-r--r--net/ipv4/xfrm4_policy.c42
-rw-r--r--net/ipv6/xfrm6_policy.c43
-rw-r--r--net/xfrm/xfrm_policy.c25
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
520static 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
527extern 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
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};
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
260static 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
269static 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
254static struct dst_ops xfrm6_dst_ops = { 295static 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
1031static void xfrm_dst_destroy(struct dst_entry *dst) 1031void 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
1043static 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}
1039EXPORT_SYMBOL(xfrm_dst_ifdown);
1055 1040
1056static void xfrm_link_failure(struct sk_buff *skb) 1041static 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;