diff options
-rw-r--r-- | include/net/flow.h | 6 | ||||
-rw-r--r-- | include/net/xfrm.h | 10 | ||||
-rw-r--r-- | net/xfrm/xfrm_policy.c | 55 |
3 files changed, 71 insertions, 0 deletions
diff --git a/include/net/flow.h b/include/net/flow.h index ce4b10d8b412..f3cc1f812619 100644 --- a/include/net/flow.h +++ b/include/net/flow.h | |||
@@ -97,4 +97,10 @@ extern void *flow_cache_lookup(struct flowi *key, u16 family, u8 dir, | |||
97 | extern void flow_cache_flush(void); | 97 | extern void flow_cache_flush(void); |
98 | extern atomic_t flow_cache_genid; | 98 | extern atomic_t flow_cache_genid; |
99 | 99 | ||
100 | static inline int flow_cache_uli_match(struct flowi *fl1, struct flowi *fl2) | ||
101 | { | ||
102 | return (fl1->proto == fl2->proto && | ||
103 | !memcmp(&fl1->uli_u, &fl2->uli_u, sizeof(fl1->uli_u))); | ||
104 | } | ||
105 | |||
100 | #endif | 106 | #endif |
diff --git a/include/net/xfrm.h b/include/net/xfrm.h index 9561bf817b02..66c2d3eec03c 100644 --- a/include/net/xfrm.h +++ b/include/net/xfrm.h | |||
@@ -603,6 +603,10 @@ struct xfrm_dst | |||
603 | struct rt6_info rt6; | 603 | struct rt6_info rt6; |
604 | } u; | 604 | } u; |
605 | struct dst_entry *route; | 605 | struct dst_entry *route; |
606 | #ifdef CONFIG_XFRM_SUB_POLICY | ||
607 | struct flowi *origin; | ||
608 | struct xfrm_selector *partner; | ||
609 | #endif | ||
606 | u32 genid; | 610 | u32 genid; |
607 | u32 route_mtu_cached; | 611 | u32 route_mtu_cached; |
608 | u32 child_mtu_cached; | 612 | u32 child_mtu_cached; |
@@ -615,6 +619,12 @@ static inline void xfrm_dst_destroy(struct xfrm_dst *xdst) | |||
615 | dst_release(xdst->route); | 619 | dst_release(xdst->route); |
616 | if (likely(xdst->u.dst.xfrm)) | 620 | if (likely(xdst->u.dst.xfrm)) |
617 | xfrm_state_put(xdst->u.dst.xfrm); | 621 | xfrm_state_put(xdst->u.dst.xfrm); |
622 | #ifdef CONFIG_XFRM_SUB_POLICY | ||
623 | kfree(xdst->origin); | ||
624 | xdst->origin = NULL; | ||
625 | kfree(xdst->partner); | ||
626 | xdst->partner = NULL; | ||
627 | #endif | ||
618 | } | 628 | } |
619 | 629 | ||
620 | extern void xfrm_dst_ifdown(struct dst_entry *dst, struct net_device *dev); | 630 | extern void xfrm_dst_ifdown(struct dst_entry *dst, struct net_device *dev); |
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 | ||
1347 | static int inline | ||
1348 | xfrm_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 | |||
1359 | static int inline | ||
1360 | xfrm_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 | |||
1371 | static int inline | ||
1372 | xfrm_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 | ||
1348 | static int stale_bundle(struct dst_entry *dst); | 1382 | static 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 | ||