aboutsummaryrefslogtreecommitdiffstats
path: root/net/xfrm/xfrm_state.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/xfrm/xfrm_state.c')
-rw-r--r--net/xfrm/xfrm_state.c53
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 */
53static LIST_HEAD(xfrm_state_all);
53static struct hlist_head *xfrm_state_bydst __read_mostly; 54static struct hlist_head *xfrm_state_bydst __read_mostly;
54static struct hlist_head *xfrm_state_bysrc __read_mostly; 55static struct hlist_head *xfrm_state_bysrc __read_mostly;
55static struct hlist_head *xfrm_state_byspi __read_mostly; 56static 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}
1519EXPORT_SYMBOL(xfrm_alloc_spi); 1527EXPORT_SYMBOL(xfrm_alloc_spi);
1520 1528
1521int xfrm_state_walk(u8 proto, int (*func)(struct xfrm_state *, int, void*), 1529int 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);
1549out: 1566out:
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}
1553EXPORT_SYMBOL(xfrm_state_walk); 1572EXPORT_SYMBOL(xfrm_state_walk);