diff options
Diffstat (limited to 'net/xfrm/xfrm_state.c')
-rw-r--r-- | net/xfrm/xfrm_state.c | 53 |
1 files changed, 36 insertions, 17 deletions
diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c index 7ba65e82941c..9880b792e6a5 100644 --- a/net/xfrm/xfrm_state.c +++ b/net/xfrm/xfrm_state.c | |||
@@ -50,6 +50,7 @@ static DEFINE_SPINLOCK(xfrm_state_lock); | |||
50 | * Main use is finding SA after policy selected tunnel or transport mode. | 50 | * Main use is finding SA after policy selected tunnel or transport mode. |
51 | * Also, it can be used by ah/esp icmp error handler to find offending SA. | 51 | * Also, it can be used by ah/esp icmp error handler to find offending SA. |
52 | */ | 52 | */ |
53 | static LIST_HEAD(xfrm_state_all); | ||
53 | static struct hlist_head *xfrm_state_bydst __read_mostly; | 54 | static struct hlist_head *xfrm_state_bydst __read_mostly; |
54 | static struct hlist_head *xfrm_state_bysrc __read_mostly; | 55 | static struct hlist_head *xfrm_state_bysrc __read_mostly; |
55 | static struct hlist_head *xfrm_state_byspi __read_mostly; | 56 | static struct hlist_head *xfrm_state_byspi __read_mostly; |
@@ -510,6 +511,7 @@ struct xfrm_state *xfrm_state_alloc(void) | |||
510 | if (x) { | 511 | if (x) { |
511 | atomic_set(&x->refcnt, 1); | 512 | atomic_set(&x->refcnt, 1); |
512 | atomic_set(&x->tunnel_users, 0); | 513 | atomic_set(&x->tunnel_users, 0); |
514 | INIT_LIST_HEAD(&x->all); | ||
513 | INIT_HLIST_NODE(&x->bydst); | 515 | INIT_HLIST_NODE(&x->bydst); |
514 | INIT_HLIST_NODE(&x->bysrc); | 516 | INIT_HLIST_NODE(&x->bysrc); |
515 | INIT_HLIST_NODE(&x->byspi); | 517 | INIT_HLIST_NODE(&x->byspi); |
@@ -533,6 +535,10 @@ void __xfrm_state_destroy(struct xfrm_state *x) | |||
533 | { | 535 | { |
534 | BUG_TRAP(x->km.state == XFRM_STATE_DEAD); | 536 | BUG_TRAP(x->km.state == XFRM_STATE_DEAD); |
535 | 537 | ||
538 | spin_lock_bh(&xfrm_state_lock); | ||
539 | list_del(&x->all); | ||
540 | spin_unlock_bh(&xfrm_state_lock); | ||
541 | |||
536 | spin_lock_bh(&xfrm_state_gc_lock); | 542 | spin_lock_bh(&xfrm_state_gc_lock); |
537 | hlist_add_head(&x->bydst, &xfrm_state_gc_list); | 543 | hlist_add_head(&x->bydst, &xfrm_state_gc_list); |
538 | spin_unlock_bh(&xfrm_state_gc_lock); | 544 | spin_unlock_bh(&xfrm_state_gc_lock); |
@@ -909,6 +915,8 @@ static void __xfrm_state_insert(struct xfrm_state *x) | |||
909 | 915 | ||
910 | x->genid = ++xfrm_state_genid; | 916 | x->genid = ++xfrm_state_genid; |
911 | 917 | ||
918 | list_add_tail(&x->all, &xfrm_state_all); | ||
919 | |||
912 | h = xfrm_dst_hash(&x->id.daddr, &x->props.saddr, | 920 | h = xfrm_dst_hash(&x->id.daddr, &x->props.saddr, |
913 | x->props.reqid, x->props.family); | 921 | x->props.reqid, x->props.family); |
914 | hlist_add_head(&x->bydst, xfrm_state_bydst+h); | 922 | hlist_add_head(&x->bydst, xfrm_state_bydst+h); |
@@ -1518,36 +1526,47 @@ unlock: | |||
1518 | } | 1526 | } |
1519 | EXPORT_SYMBOL(xfrm_alloc_spi); | 1527 | EXPORT_SYMBOL(xfrm_alloc_spi); |
1520 | 1528 | ||
1521 | int xfrm_state_walk(u8 proto, int (*func)(struct xfrm_state *, int, void*), | 1529 | int xfrm_state_walk(struct xfrm_state_walk *walk, |
1530 | int (*func)(struct xfrm_state *, int, void*), | ||
1522 | void *data) | 1531 | void *data) |
1523 | { | 1532 | { |
1524 | int i; | 1533 | struct xfrm_state *old, *x, *last = NULL; |
1525 | struct xfrm_state *x, *last = NULL; | ||
1526 | struct hlist_node *entry; | ||
1527 | int count = 0; | ||
1528 | int err = 0; | 1534 | int err = 0; |
1529 | 1535 | ||
1536 | if (walk->state == NULL && walk->count != 0) | ||
1537 | return 0; | ||
1538 | |||
1539 | old = x = walk->state; | ||
1540 | walk->state = NULL; | ||
1530 | spin_lock_bh(&xfrm_state_lock); | 1541 | spin_lock_bh(&xfrm_state_lock); |
1531 | for (i = 0; i <= xfrm_state_hmask; i++) { | 1542 | if (x == NULL) |
1532 | hlist_for_each_entry(x, entry, xfrm_state_bydst+i, bydst) { | 1543 | x = list_first_entry(&xfrm_state_all, struct xfrm_state, all); |
1533 | if (!xfrm_id_proto_match(x->id.proto, proto)) | 1544 | list_for_each_entry_from(x, &xfrm_state_all, all) { |
1534 | continue; | 1545 | if (x->km.state == XFRM_STATE_DEAD) |
1535 | if (last) { | 1546 | continue; |
1536 | err = func(last, count, data); | 1547 | if (!xfrm_id_proto_match(x->id.proto, walk->proto)) |
1537 | if (err) | 1548 | continue; |
1538 | goto out; | 1549 | if (last) { |
1550 | err = func(last, walk->count, data); | ||
1551 | if (err) { | ||
1552 | xfrm_state_hold(last); | ||
1553 | walk->state = last; | ||
1554 | goto out; | ||
1539 | } | 1555 | } |
1540 | last = x; | ||
1541 | count++; | ||
1542 | } | 1556 | } |
1557 | last = x; | ||
1558 | walk->count++; | ||
1543 | } | 1559 | } |
1544 | if (count == 0) { | 1560 | if (walk->count == 0) { |
1545 | err = -ENOENT; | 1561 | err = -ENOENT; |
1546 | goto out; | 1562 | goto out; |
1547 | } | 1563 | } |
1548 | err = func(last, 0, data); | 1564 | if (last) |
1565 | err = func(last, 0, data); | ||
1549 | out: | 1566 | out: |
1550 | spin_unlock_bh(&xfrm_state_lock); | 1567 | spin_unlock_bh(&xfrm_state_lock); |
1568 | if (old != NULL) | ||
1569 | xfrm_state_put(old); | ||
1551 | return err; | 1570 | return err; |
1552 | } | 1571 | } |
1553 | EXPORT_SYMBOL(xfrm_state_walk); | 1572 | EXPORT_SYMBOL(xfrm_state_walk); |