diff options
Diffstat (limited to 'net/xfrm')
-rw-r--r-- | net/xfrm/xfrm_policy.c | 55 |
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 | ||
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 | ||