aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4
diff options
context:
space:
mode:
authorHerbert Xu <herbert@gondor.apana.org.au>2005-05-03 19:27:10 -0400
committerDavid S. Miller <davem@davemloft.net>2005-05-03 19:27:10 -0400
commitaabc9761b69f1bfa30a78f7005be95cc9cc06175 (patch)
tree50dc9f510011ac03656aeba0595b2b0b5c5f5e22 /net/ipv4
parentd5d75cd6b10ddad2f375b61092754474ad78aec7 (diff)
[IPSEC]: Store idev entries
I found a bug that stopped IPsec/IPv6 from working. About a month ago IPv6 started using rt6i_idev->dev on the cached socket dst entries. If the cached socket dst entry is IPsec, then rt6i_idev will be NULL. Since we want to look at the rt6i_idev of the original route in this case, the easiest fix is to store rt6i_idev in the IPsec dst entry just as we do for a number of other IPv6 route attributes. Unfortunately this means that we need some new code to handle the references to rt6i_idev. That's why this patch is bigger than it would otherwise be. I've also done the same thing for IPv4 since it is conceivable that once these idev attributes start getting used for accounting, we probably need to dereference them for IPv4 IPsec entries too. Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv4')
-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};