diff options
Diffstat (limited to 'net/xfrm/xfrm_policy.c')
-rw-r--r-- | net/xfrm/xfrm_policy.c | 71 |
1 files changed, 70 insertions, 1 deletions
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c index 762926009c04..263e34e45265 100644 --- a/net/xfrm/xfrm_policy.c +++ b/net/xfrm/xfrm_policy.c | |||
@@ -579,8 +579,22 @@ static inline int xfrm_byidx_should_resize(int total) | |||
579 | return 0; | 579 | return 0; |
580 | } | 580 | } |
581 | 581 | ||
582 | static DEFINE_MUTEX(hash_resize_mutex); | 582 | void xfrm_spd_getinfo(struct xfrm_spdinfo *si) |
583 | { | ||
584 | read_lock_bh(&xfrm_policy_lock); | ||
585 | si->incnt = xfrm_policy_count[XFRM_POLICY_IN]; | ||
586 | si->outcnt = xfrm_policy_count[XFRM_POLICY_OUT]; | ||
587 | si->fwdcnt = xfrm_policy_count[XFRM_POLICY_FWD]; | ||
588 | si->inscnt = xfrm_policy_count[XFRM_POLICY_IN+XFRM_POLICY_MAX]; | ||
589 | si->outscnt = xfrm_policy_count[XFRM_POLICY_OUT+XFRM_POLICY_MAX]; | ||
590 | si->fwdscnt = xfrm_policy_count[XFRM_POLICY_FWD+XFRM_POLICY_MAX]; | ||
591 | si->spdhcnt = xfrm_idx_hmask; | ||
592 | si->spdhmcnt = xfrm_policy_hashmax; | ||
593 | read_unlock_bh(&xfrm_policy_lock); | ||
594 | } | ||
595 | EXPORT_SYMBOL(xfrm_spd_getinfo); | ||
583 | 596 | ||
597 | static DEFINE_MUTEX(hash_resize_mutex); | ||
584 | static void xfrm_hash_resize(struct work_struct *__unused) | 598 | static void xfrm_hash_resize(struct work_struct *__unused) |
585 | { | 599 | { |
586 | int dir, total; | 600 | int dir, total; |
@@ -1330,6 +1344,40 @@ xfrm_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int nx, | |||
1330 | return err; | 1344 | return err; |
1331 | } | 1345 | } |
1332 | 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 | } | ||
1333 | 1381 | ||
1334 | static int stale_bundle(struct dst_entry *dst); | 1382 | static int stale_bundle(struct dst_entry *dst); |
1335 | 1383 | ||
@@ -1518,6 +1566,18 @@ restart: | |||
1518 | err = -EHOSTUNREACH; | 1566 | err = -EHOSTUNREACH; |
1519 | goto error; | 1567 | goto error; |
1520 | } | 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 | |||
1521 | dst->next = policy->bundles; | 1581 | dst->next = policy->bundles; |
1522 | policy->bundles = dst; | 1582 | policy->bundles = dst; |
1523 | dst_hold(dst); | 1583 | dst_hold(dst); |
@@ -1933,6 +1993,15 @@ int xfrm_bundle_ok(struct xfrm_policy *pol, struct xfrm_dst *first, | |||
1933 | if (!dst_check(dst->path, ((struct xfrm_dst *)dst)->path_cookie) || | 1993 | if (!dst_check(dst->path, ((struct xfrm_dst *)dst)->path_cookie) || |
1934 | (dst->dev && !netif_running(dst->dev))) | 1994 | (dst->dev && !netif_running(dst->dev))) |
1935 | 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 | ||
1936 | 2005 | ||
1937 | last = NULL; | 2006 | last = NULL; |
1938 | 2007 | ||