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.c82
1 files changed, 48 insertions, 34 deletions
diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c
index 7bd62f61593f..508337f97249 100644
--- a/net/xfrm/xfrm_state.c
+++ b/net/xfrm/xfrm_state.c
@@ -408,11 +408,10 @@ static void xfrm_state_gc_task(struct work_struct *data)
408 struct hlist_head gc_list; 408 struct hlist_head gc_list;
409 409
410 spin_lock_bh(&xfrm_state_gc_lock); 410 spin_lock_bh(&xfrm_state_gc_lock);
411 gc_list.first = xfrm_state_gc_list.first; 411 hlist_move_list(&xfrm_state_gc_list, &gc_list);
412 INIT_HLIST_HEAD(&xfrm_state_gc_list);
413 spin_unlock_bh(&xfrm_state_gc_lock); 412 spin_unlock_bh(&xfrm_state_gc_lock);
414 413
415 hlist_for_each_entry_safe(x, entry, tmp, &gc_list, bydst) 414 hlist_for_each_entry_safe(x, entry, tmp, &gc_list, gclist)
416 xfrm_state_gc_destroy(x); 415 xfrm_state_gc_destroy(x);
417 416
418 wake_up(&km_waitq); 417 wake_up(&km_waitq);
@@ -514,7 +513,7 @@ struct xfrm_state *xfrm_state_alloc(void)
514 if (x) { 513 if (x) {
515 atomic_set(&x->refcnt, 1); 514 atomic_set(&x->refcnt, 1);
516 atomic_set(&x->tunnel_users, 0); 515 atomic_set(&x->tunnel_users, 0);
517 INIT_LIST_HEAD(&x->all); 516 INIT_LIST_HEAD(&x->km.all);
518 INIT_HLIST_NODE(&x->bydst); 517 INIT_HLIST_NODE(&x->bydst);
519 INIT_HLIST_NODE(&x->bysrc); 518 INIT_HLIST_NODE(&x->bysrc);
520 INIT_HLIST_NODE(&x->byspi); 519 INIT_HLIST_NODE(&x->byspi);
@@ -540,12 +539,8 @@ void __xfrm_state_destroy(struct xfrm_state *x)
540{ 539{
541 WARN_ON(x->km.state != XFRM_STATE_DEAD); 540 WARN_ON(x->km.state != XFRM_STATE_DEAD);
542 541
543 spin_lock_bh(&xfrm_state_lock);
544 list_del(&x->all);
545 spin_unlock_bh(&xfrm_state_lock);
546
547 spin_lock_bh(&xfrm_state_gc_lock); 542 spin_lock_bh(&xfrm_state_gc_lock);
548 hlist_add_head(&x->bydst, &xfrm_state_gc_list); 543 hlist_add_head(&x->gclist, &xfrm_state_gc_list);
549 spin_unlock_bh(&xfrm_state_gc_lock); 544 spin_unlock_bh(&xfrm_state_gc_lock);
550 schedule_work(&xfrm_state_gc_work); 545 schedule_work(&xfrm_state_gc_work);
551} 546}
@@ -558,6 +553,7 @@ int __xfrm_state_delete(struct xfrm_state *x)
558 if (x->km.state != XFRM_STATE_DEAD) { 553 if (x->km.state != XFRM_STATE_DEAD) {
559 x->km.state = XFRM_STATE_DEAD; 554 x->km.state = XFRM_STATE_DEAD;
560 spin_lock(&xfrm_state_lock); 555 spin_lock(&xfrm_state_lock);
556 list_del(&x->km.all);
561 hlist_del(&x->bydst); 557 hlist_del(&x->bydst);
562 hlist_del(&x->bysrc); 558 hlist_del(&x->bysrc);
563 if (x->id.spi) 559 if (x->id.spi)
@@ -858,6 +854,7 @@ xfrm_state_find(xfrm_address_t *daddr, xfrm_address_t *saddr,
858 854
859 if (km_query(x, tmpl, pol) == 0) { 855 if (km_query(x, tmpl, pol) == 0) {
860 x->km.state = XFRM_STATE_ACQ; 856 x->km.state = XFRM_STATE_ACQ;
857 list_add(&x->km.all, &xfrm_state_all);
861 hlist_add_head(&x->bydst, xfrm_state_bydst+h); 858 hlist_add_head(&x->bydst, xfrm_state_bydst+h);
862 h = xfrm_src_hash(daddr, saddr, family); 859 h = xfrm_src_hash(daddr, saddr, family);
863 hlist_add_head(&x->bysrc, xfrm_state_bysrc+h); 860 hlist_add_head(&x->bysrc, xfrm_state_bysrc+h);
@@ -926,7 +923,7 @@ static void __xfrm_state_insert(struct xfrm_state *x)
926 923
927 x->genid = ++xfrm_state_genid; 924 x->genid = ++xfrm_state_genid;
928 925
929 list_add_tail(&x->all, &xfrm_state_all); 926 list_add(&x->km.all, &xfrm_state_all);
930 927
931 h = xfrm_dst_hash(&x->id.daddr, &x->props.saddr, 928 h = xfrm_dst_hash(&x->id.daddr, &x->props.saddr,
932 x->props.reqid, x->props.family); 929 x->props.reqid, x->props.family);
@@ -1055,6 +1052,7 @@ static struct xfrm_state *__find_acq_core(unsigned short family, u8 mode, u32 re
1055 xfrm_state_hold(x); 1052 xfrm_state_hold(x);
1056 x->timer.expires = jiffies + sysctl_xfrm_acq_expires*HZ; 1053 x->timer.expires = jiffies + sysctl_xfrm_acq_expires*HZ;
1057 add_timer(&x->timer); 1054 add_timer(&x->timer);
1055 list_add(&x->km.all, &xfrm_state_all);
1058 hlist_add_head(&x->bydst, xfrm_state_bydst+h); 1056 hlist_add_head(&x->bydst, xfrm_state_bydst+h);
1059 h = xfrm_src_hash(daddr, saddr, family); 1057 h = xfrm_src_hash(daddr, saddr, family);
1060 hlist_add_head(&x->bysrc, xfrm_state_bysrc+h); 1058 hlist_add_head(&x->bysrc, xfrm_state_bysrc+h);
@@ -1551,47 +1549,62 @@ int xfrm_state_walk(struct xfrm_state_walk *walk,
1551 int (*func)(struct xfrm_state *, int, void*), 1549 int (*func)(struct xfrm_state *, int, void*),
1552 void *data) 1550 void *data)
1553{ 1551{
1554 struct xfrm_state *old, *x, *last = NULL; 1552 struct xfrm_state *state;
1553 struct xfrm_state_walk *x;
1555 int err = 0; 1554 int err = 0;
1556 1555
1557 if (walk->state == NULL && walk->count != 0) 1556 if (walk->seq != 0 && list_empty(&walk->all))
1558 return 0; 1557 return 0;
1559 1558
1560 old = x = walk->state;
1561 walk->state = NULL;
1562 spin_lock_bh(&xfrm_state_lock); 1559 spin_lock_bh(&xfrm_state_lock);
1563 if (x == NULL) 1560 if (list_empty(&walk->all))
1564 x = list_first_entry(&xfrm_state_all, struct xfrm_state, all); 1561 x = list_first_entry(&xfrm_state_all, struct xfrm_state_walk, all);
1562 else
1563 x = list_entry(&walk->all, struct xfrm_state_walk, all);
1565 list_for_each_entry_from(x, &xfrm_state_all, all) { 1564 list_for_each_entry_from(x, &xfrm_state_all, all) {
1566 if (x->km.state == XFRM_STATE_DEAD) 1565 if (x->state == XFRM_STATE_DEAD)
1567 continue; 1566 continue;
1568 if (!xfrm_id_proto_match(x->id.proto, walk->proto)) 1567 state = container_of(x, struct xfrm_state, km);
1568 if (!xfrm_id_proto_match(state->id.proto, walk->proto))
1569 continue; 1569 continue;
1570 if (last) { 1570 err = func(state, walk->seq, data);
1571 err = func(last, walk->count, data); 1571 if (err) {
1572 if (err) { 1572 list_move_tail(&walk->all, &x->all);
1573 xfrm_state_hold(last); 1573 goto out;
1574 walk->state = last;
1575 goto out;
1576 }
1577 } 1574 }
1578 last = x; 1575 walk->seq++;
1579 walk->count++;
1580 } 1576 }
1581 if (walk->count == 0) { 1577 if (walk->seq == 0) {
1582 err = -ENOENT; 1578 err = -ENOENT;
1583 goto out; 1579 goto out;
1584 } 1580 }
1585 if (last) 1581 list_del_init(&walk->all);
1586 err = func(last, 0, data);
1587out: 1582out:
1588 spin_unlock_bh(&xfrm_state_lock); 1583 spin_unlock_bh(&xfrm_state_lock);
1589 if (old != NULL)
1590 xfrm_state_put(old);
1591 return err; 1584 return err;
1592} 1585}
1593EXPORT_SYMBOL(xfrm_state_walk); 1586EXPORT_SYMBOL(xfrm_state_walk);
1594 1587
1588void xfrm_state_walk_init(struct xfrm_state_walk *walk, u8 proto)
1589{
1590 INIT_LIST_HEAD(&walk->all);
1591 walk->proto = proto;
1592 walk->state = XFRM_STATE_DEAD;
1593 walk->seq = 0;
1594}
1595EXPORT_SYMBOL(xfrm_state_walk_init);
1596
1597void xfrm_state_walk_done(struct xfrm_state_walk *walk)
1598{
1599 if (list_empty(&walk->all))
1600 return;
1601
1602 spin_lock_bh(&xfrm_state_lock);
1603 list_del(&walk->all);
1604 spin_lock_bh(&xfrm_state_lock);
1605}
1606EXPORT_SYMBOL(xfrm_state_walk_done);
1607
1595 1608
1596void xfrm_replay_notify(struct xfrm_state *x, int event) 1609void xfrm_replay_notify(struct xfrm_state *x, int event)
1597{ 1610{
@@ -1801,7 +1814,8 @@ EXPORT_SYMBOL(km_policy_expired);
1801 1814
1802#ifdef CONFIG_XFRM_MIGRATE 1815#ifdef CONFIG_XFRM_MIGRATE
1803int km_migrate(struct xfrm_selector *sel, u8 dir, u8 type, 1816int km_migrate(struct xfrm_selector *sel, u8 dir, u8 type,
1804 struct xfrm_migrate *m, int num_migrate) 1817 struct xfrm_migrate *m, int num_migrate,
1818 struct xfrm_kmaddress *k)
1805{ 1819{
1806 int err = -EINVAL; 1820 int err = -EINVAL;
1807 int ret; 1821 int ret;
@@ -1810,7 +1824,7 @@ int km_migrate(struct xfrm_selector *sel, u8 dir, u8 type,
1810 read_lock(&xfrm_km_lock); 1824 read_lock(&xfrm_km_lock);
1811 list_for_each_entry(km, &xfrm_km_list, list) { 1825 list_for_each_entry(km, &xfrm_km_list, list) {
1812 if (km->migrate) { 1826 if (km->migrate) {
1813 ret = km->migrate(sel, dir, type, m, num_migrate); 1827 ret = km->migrate(sel, dir, type, m, num_migrate, k);
1814 if (!ret) 1828 if (!ret)
1815 err = ret; 1829 err = ret;
1816 } 1830 }