aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorMasahide NAKAMURA <nakam@linux-ipv6.org>2007-04-30 03:33:35 -0400
committerDavid S. Miller <davem@sunset.davemloft.net>2007-04-30 03:58:09 -0400
commit157bfc25020f7eb731f94140e099307ade47299e (patch)
tree422821e5233daf0d8347ac361f09be9f49b43de4 /net
parent34588b4c046c34773e5a1a962da7b78b05c4d1bd (diff)
[XFRM]: Restrict upper layer information by bundle.
On MIPv6 usage, XFRM sub policy is enabled. When main (IPsec) and sub (MIPv6) policy selectors have the same address set but different upper layer information (i.e. protocol number and its ports or type/code), multiple bundle should be created. However, currently we have issue to use the same bundle created for the first time with all flows covered by the case. It is useful for the bundle to have the upper layer information to be restructured correctly if it does not match with the flow. 1. Bundle was created by two policies Selector from another policy is added to xfrm_dst. If the flow does not match the selector, it goes to slow path to restructure new bundle by single policy. 2. Bundle was created by one policy Flow cache is added to xfrm_dst as originated one. If the flow does not match the cache, it goes to slow path to try searching another policy. Signed-off-by: Masahide NAKAMURA <nakam@linux-ipv6.org> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r--net/xfrm/xfrm_policy.c55
1 files changed, 55 insertions, 0 deletions
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
index dbf9d96a2f0b..263e34e45265 100644
--- a/net/xfrm/xfrm_policy.c
+++ b/net/xfrm/xfrm_policy.c
@@ -1344,6 +1344,40 @@ xfrm_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int nx,
1344 return err; 1344 return err;
1345} 1345}
1346 1346
1347static int inline
1348xfrm_dst_alloc_copy(void **target, void *src, int size)
1349{
1350 if (!*target) {
1351 *target = kmalloc(size, GFP_ATOMIC);
1352 if (!*target)
1353 return -ENOMEM;
1354 }
1355 memcpy(*target, src, size);
1356 return 0;
1357}
1358
1359static int inline
1360xfrm_dst_update_parent(struct dst_entry *dst, struct xfrm_selector *sel)
1361{
1362#ifdef CONFIG_XFRM_SUB_POLICY
1363 struct xfrm_dst *xdst = (struct xfrm_dst *)dst;
1364 return xfrm_dst_alloc_copy((void **)&(xdst->partner),
1365 sel, sizeof(*sel));
1366#else
1367 return 0;
1368#endif
1369}
1370
1371static int inline
1372xfrm_dst_update_origin(struct dst_entry *dst, struct flowi *fl)
1373{
1374#ifdef CONFIG_XFRM_SUB_POLICY
1375 struct xfrm_dst *xdst = (struct xfrm_dst *)dst;
1376 return xfrm_dst_alloc_copy((void **)&(xdst->origin), fl, sizeof(*fl));
1377#else
1378 return 0;
1379#endif
1380}
1347 1381
1348static int stale_bundle(struct dst_entry *dst); 1382static int stale_bundle(struct dst_entry *dst);
1349 1383
@@ -1532,6 +1566,18 @@ restart:
1532 err = -EHOSTUNREACH; 1566 err = -EHOSTUNREACH;
1533 goto error; 1567 goto error;
1534 } 1568 }
1569
1570 if (npols > 1)
1571 err = xfrm_dst_update_parent(dst, &pols[1]->selector);
1572 else
1573 err = xfrm_dst_update_origin(dst, fl);
1574 if (unlikely(err)) {
1575 write_unlock_bh(&policy->lock);
1576 if (dst)
1577 dst_free(dst);
1578 goto error;
1579 }
1580
1535 dst->next = policy->bundles; 1581 dst->next = policy->bundles;
1536 policy->bundles = dst; 1582 policy->bundles = dst;
1537 dst_hold(dst); 1583 dst_hold(dst);
@@ -1947,6 +1993,15 @@ int xfrm_bundle_ok(struct xfrm_policy *pol, struct xfrm_dst *first,
1947 if (!dst_check(dst->path, ((struct xfrm_dst *)dst)->path_cookie) || 1993 if (!dst_check(dst->path, ((struct xfrm_dst *)dst)->path_cookie) ||
1948 (dst->dev && !netif_running(dst->dev))) 1994 (dst->dev && !netif_running(dst->dev)))
1949 return 0; 1995 return 0;
1996#ifdef CONFIG_XFRM_SUB_POLICY
1997 if (fl) {
1998 if (first->origin && !flow_cache_uli_match(first->origin, fl))
1999 return 0;
2000 if (first->partner &&
2001 !xfrm_selector_match(first->partner, fl, family))
2002 return 0;
2003 }
2004#endif
1950 2005
1951 last = NULL; 2006 last = NULL;
1952 2007