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.c114
1 files changed, 71 insertions, 43 deletions
diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c
index 4c6914ef7d92..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)
@@ -780,11 +776,13 @@ xfrm_state_find(xfrm_address_t *daddr, xfrm_address_t *saddr,
780{ 776{
781 unsigned int h; 777 unsigned int h;
782 struct hlist_node *entry; 778 struct hlist_node *entry;
783 struct xfrm_state *x, *x0; 779 struct xfrm_state *x, *x0, *to_put;
784 int acquire_in_progress = 0; 780 int acquire_in_progress = 0;
785 int error = 0; 781 int error = 0;
786 struct xfrm_state *best = NULL; 782 struct xfrm_state *best = NULL;
787 783
784 to_put = NULL;
785
788 spin_lock_bh(&xfrm_state_lock); 786 spin_lock_bh(&xfrm_state_lock);
789 h = xfrm_dst_hash(daddr, saddr, tmpl->reqid, family); 787 h = xfrm_dst_hash(daddr, saddr, tmpl->reqid, family);
790 hlist_for_each_entry(x, entry, xfrm_state_bydst+h, bydst) { 788 hlist_for_each_entry(x, entry, xfrm_state_bydst+h, bydst) {
@@ -833,7 +831,7 @@ xfrm_state_find(xfrm_address_t *daddr, xfrm_address_t *saddr,
833 if (tmpl->id.spi && 831 if (tmpl->id.spi &&
834 (x0 = __xfrm_state_lookup(daddr, tmpl->id.spi, 832 (x0 = __xfrm_state_lookup(daddr, tmpl->id.spi,
835 tmpl->id.proto, family)) != NULL) { 833 tmpl->id.proto, family)) != NULL) {
836 xfrm_state_put(x0); 834 to_put = x0;
837 error = -EEXIST; 835 error = -EEXIST;
838 goto out; 836 goto out;
839 } 837 }
@@ -849,13 +847,14 @@ xfrm_state_find(xfrm_address_t *daddr, xfrm_address_t *saddr,
849 error = security_xfrm_state_alloc_acquire(x, pol->security, fl->secid); 847 error = security_xfrm_state_alloc_acquire(x, pol->security, fl->secid);
850 if (error) { 848 if (error) {
851 x->km.state = XFRM_STATE_DEAD; 849 x->km.state = XFRM_STATE_DEAD;
852 xfrm_state_put(x); 850 to_put = x;
853 x = NULL; 851 x = NULL;
854 goto out; 852 goto out;
855 } 853 }
856 854
857 if (km_query(x, tmpl, pol) == 0) { 855 if (km_query(x, tmpl, pol) == 0) {
858 x->km.state = XFRM_STATE_ACQ; 856 x->km.state = XFRM_STATE_ACQ;
857 list_add(&x->km.all, &xfrm_state_all);
859 hlist_add_head(&x->bydst, xfrm_state_bydst+h); 858 hlist_add_head(&x->bydst, xfrm_state_bydst+h);
860 h = xfrm_src_hash(daddr, saddr, family); 859 h = xfrm_src_hash(daddr, saddr, family);
861 hlist_add_head(&x->bysrc, xfrm_state_bysrc+h); 860 hlist_add_head(&x->bysrc, xfrm_state_bysrc+h);
@@ -870,7 +869,7 @@ xfrm_state_find(xfrm_address_t *daddr, xfrm_address_t *saddr,
870 xfrm_hash_grow_check(x->bydst.next != NULL); 869 xfrm_hash_grow_check(x->bydst.next != NULL);
871 } else { 870 } else {
872 x->km.state = XFRM_STATE_DEAD; 871 x->km.state = XFRM_STATE_DEAD;
873 xfrm_state_put(x); 872 to_put = x;
874 x = NULL; 873 x = NULL;
875 error = -ESRCH; 874 error = -ESRCH;
876 } 875 }
@@ -881,6 +880,8 @@ out:
881 else 880 else
882 *err = acquire_in_progress ? -EAGAIN : error; 881 *err = acquire_in_progress ? -EAGAIN : error;
883 spin_unlock_bh(&xfrm_state_lock); 882 spin_unlock_bh(&xfrm_state_lock);
883 if (to_put)
884 xfrm_state_put(to_put);
884 return x; 885 return x;
885} 886}
886 887
@@ -922,7 +923,7 @@ static void __xfrm_state_insert(struct xfrm_state *x)
922 923
923 x->genid = ++xfrm_state_genid; 924 x->genid = ++xfrm_state_genid;
924 925
925 list_add_tail(&x->all, &xfrm_state_all); 926 list_add(&x->km.all, &xfrm_state_all);
926 927
927 h = xfrm_dst_hash(&x->id.daddr, &x->props.saddr, 928 h = xfrm_dst_hash(&x->id.daddr, &x->props.saddr,
928 x->props.reqid, x->props.family); 929 x->props.reqid, x->props.family);
@@ -1051,6 +1052,7 @@ static struct xfrm_state *__find_acq_core(unsigned short family, u8 mode, u32 re
1051 xfrm_state_hold(x); 1052 xfrm_state_hold(x);
1052 x->timer.expires = jiffies + sysctl_xfrm_acq_expires*HZ; 1053 x->timer.expires = jiffies + sysctl_xfrm_acq_expires*HZ;
1053 add_timer(&x->timer); 1054 add_timer(&x->timer);
1055 list_add(&x->km.all, &xfrm_state_all);
1054 hlist_add_head(&x->bydst, xfrm_state_bydst+h); 1056 hlist_add_head(&x->bydst, xfrm_state_bydst+h);
1055 h = xfrm_src_hash(daddr, saddr, family); 1057 h = xfrm_src_hash(daddr, saddr, family);
1056 hlist_add_head(&x->bysrc, xfrm_state_bysrc+h); 1058 hlist_add_head(&x->bysrc, xfrm_state_bysrc+h);
@@ -1067,18 +1069,20 @@ static struct xfrm_state *__xfrm_find_acq_byseq(u32 seq);
1067 1069
1068int xfrm_state_add(struct xfrm_state *x) 1070int xfrm_state_add(struct xfrm_state *x)
1069{ 1071{
1070 struct xfrm_state *x1; 1072 struct xfrm_state *x1, *to_put;
1071 int family; 1073 int family;
1072 int err; 1074 int err;
1073 int use_spi = xfrm_id_proto_match(x->id.proto, IPSEC_PROTO_ANY); 1075 int use_spi = xfrm_id_proto_match(x->id.proto, IPSEC_PROTO_ANY);
1074 1076
1075 family = x->props.family; 1077 family = x->props.family;
1076 1078
1079 to_put = NULL;
1080
1077 spin_lock_bh(&xfrm_state_lock); 1081 spin_lock_bh(&xfrm_state_lock);
1078 1082
1079 x1 = __xfrm_state_locate(x, use_spi, family); 1083 x1 = __xfrm_state_locate(x, use_spi, family);
1080 if (x1) { 1084 if (x1) {
1081 xfrm_state_put(x1); 1085 to_put = x1;
1082 x1 = NULL; 1086 x1 = NULL;
1083 err = -EEXIST; 1087 err = -EEXIST;
1084 goto out; 1088 goto out;
@@ -1088,7 +1092,7 @@ int xfrm_state_add(struct xfrm_state *x)
1088 x1 = __xfrm_find_acq_byseq(x->km.seq); 1092 x1 = __xfrm_find_acq_byseq(x->km.seq);
1089 if (x1 && ((x1->id.proto != x->id.proto) || 1093 if (x1 && ((x1->id.proto != x->id.proto) ||
1090 xfrm_addr_cmp(&x1->id.daddr, &x->id.daddr, family))) { 1094 xfrm_addr_cmp(&x1->id.daddr, &x->id.daddr, family))) {
1091 xfrm_state_put(x1); 1095 to_put = x1;
1092 x1 = NULL; 1096 x1 = NULL;
1093 } 1097 }
1094 } 1098 }
@@ -1110,6 +1114,9 @@ out:
1110 xfrm_state_put(x1); 1114 xfrm_state_put(x1);
1111 } 1115 }
1112 1116
1117 if (to_put)
1118 xfrm_state_put(to_put);
1119
1113 return err; 1120 return err;
1114} 1121}
1115EXPORT_SYMBOL(xfrm_state_add); 1122EXPORT_SYMBOL(xfrm_state_add);
@@ -1269,10 +1276,12 @@ EXPORT_SYMBOL(xfrm_state_migrate);
1269 1276
1270int xfrm_state_update(struct xfrm_state *x) 1277int xfrm_state_update(struct xfrm_state *x)
1271{ 1278{
1272 struct xfrm_state *x1; 1279 struct xfrm_state *x1, *to_put;
1273 int err; 1280 int err;
1274 int use_spi = xfrm_id_proto_match(x->id.proto, IPSEC_PROTO_ANY); 1281 int use_spi = xfrm_id_proto_match(x->id.proto, IPSEC_PROTO_ANY);
1275 1282
1283 to_put = NULL;
1284
1276 spin_lock_bh(&xfrm_state_lock); 1285 spin_lock_bh(&xfrm_state_lock);
1277 x1 = __xfrm_state_locate(x, use_spi, x->props.family); 1286 x1 = __xfrm_state_locate(x, use_spi, x->props.family);
1278 1287
@@ -1281,7 +1290,7 @@ int xfrm_state_update(struct xfrm_state *x)
1281 goto out; 1290 goto out;
1282 1291
1283 if (xfrm_state_kern(x1)) { 1292 if (xfrm_state_kern(x1)) {
1284 xfrm_state_put(x1); 1293 to_put = x1;
1285 err = -EEXIST; 1294 err = -EEXIST;
1286 goto out; 1295 goto out;
1287 } 1296 }
@@ -1295,6 +1304,9 @@ int xfrm_state_update(struct xfrm_state *x)
1295out: 1304out:
1296 spin_unlock_bh(&xfrm_state_lock); 1305 spin_unlock_bh(&xfrm_state_lock);
1297 1306
1307 if (to_put)
1308 xfrm_state_put(to_put);
1309
1298 if (err) 1310 if (err)
1299 return err; 1311 return err;
1300 1312
@@ -1537,47 +1549,62 @@ int xfrm_state_walk(struct xfrm_state_walk *walk,
1537 int (*func)(struct xfrm_state *, int, void*), 1549 int (*func)(struct xfrm_state *, int, void*),
1538 void *data) 1550 void *data)
1539{ 1551{
1540 struct xfrm_state *old, *x, *last = NULL; 1552 struct xfrm_state *state;
1553 struct xfrm_state_walk *x;
1541 int err = 0; 1554 int err = 0;
1542 1555
1543 if (walk->state == NULL && walk->count != 0) 1556 if (walk->seq != 0 && list_empty(&walk->all))
1544 return 0; 1557 return 0;
1545 1558
1546 old = x = walk->state;
1547 walk->state = NULL;
1548 spin_lock_bh(&xfrm_state_lock); 1559 spin_lock_bh(&xfrm_state_lock);
1549 if (x == NULL) 1560 if (list_empty(&walk->all))
1550 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);
1551 list_for_each_entry_from(x, &xfrm_state_all, all) { 1564 list_for_each_entry_from(x, &xfrm_state_all, all) {
1552 if (x->km.state == XFRM_STATE_DEAD) 1565 if (x->state == XFRM_STATE_DEAD)
1553 continue; 1566 continue;
1554 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))
1555 continue; 1569 continue;
1556 if (last) { 1570 err = func(state, walk->seq, data);
1557 err = func(last, walk->count, data); 1571 if (err) {
1558 if (err) { 1572 list_move_tail(&walk->all, &x->all);
1559 xfrm_state_hold(last); 1573 goto out;
1560 walk->state = last;
1561 goto out;
1562 }
1563 } 1574 }
1564 last = x; 1575 walk->seq++;
1565 walk->count++;
1566 } 1576 }
1567 if (walk->count == 0) { 1577 if (walk->seq == 0) {
1568 err = -ENOENT; 1578 err = -ENOENT;
1569 goto out; 1579 goto out;
1570 } 1580 }
1571 if (last) 1581 list_del_init(&walk->all);
1572 err = func(last, 0, data);
1573out: 1582out:
1574 spin_unlock_bh(&xfrm_state_lock); 1583 spin_unlock_bh(&xfrm_state_lock);
1575 if (old != NULL)
1576 xfrm_state_put(old);
1577 return err; 1584 return err;
1578} 1585}
1579EXPORT_SYMBOL(xfrm_state_walk); 1586EXPORT_SYMBOL(xfrm_state_walk);
1580 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
1581 1608
1582void xfrm_replay_notify(struct xfrm_state *x, int event) 1609void xfrm_replay_notify(struct xfrm_state *x, int event)
1583{ 1610{
@@ -1787,7 +1814,8 @@ EXPORT_SYMBOL(km_policy_expired);
1787 1814
1788#ifdef CONFIG_XFRM_MIGRATE 1815#ifdef CONFIG_XFRM_MIGRATE
1789int km_migrate(struct xfrm_selector *sel, u8 dir, u8 type, 1816int km_migrate(struct xfrm_selector *sel, u8 dir, u8 type,
1790 struct xfrm_migrate *m, int num_migrate) 1817 struct xfrm_migrate *m, int num_migrate,
1818 struct xfrm_kmaddress *k)
1791{ 1819{
1792 int err = -EINVAL; 1820 int err = -EINVAL;
1793 int ret; 1821 int ret;
@@ -1796,7 +1824,7 @@ int km_migrate(struct xfrm_selector *sel, u8 dir, u8 type,
1796 read_lock(&xfrm_km_lock); 1824 read_lock(&xfrm_km_lock);
1797 list_for_each_entry(km, &xfrm_km_list, list) { 1825 list_for_each_entry(km, &xfrm_km_list, list) {
1798 if (km->migrate) { 1826 if (km->migrate) {
1799 ret = km->migrate(sel, dir, type, m, num_migrate); 1827 ret = km->migrate(sel, dir, type, m, num_migrate, k);
1800 if (!ret) 1828 if (!ret)
1801 err = ret; 1829 err = ret;
1802 } 1830 }