diff options
Diffstat (limited to 'net/xfrm/xfrm_state.c')
-rw-r--r-- | net/xfrm/xfrm_state.c | 114 |
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 | ||
1068 | int xfrm_state_add(struct xfrm_state *x) | 1070 | int 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 | } |
1115 | EXPORT_SYMBOL(xfrm_state_add); | 1122 | EXPORT_SYMBOL(xfrm_state_add); |
@@ -1269,10 +1276,12 @@ EXPORT_SYMBOL(xfrm_state_migrate); | |||
1269 | 1276 | ||
1270 | int xfrm_state_update(struct xfrm_state *x) | 1277 | int 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) | |||
1295 | out: | 1304 | out: |
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); | ||
1573 | out: | 1582 | out: |
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 | } |
1579 | EXPORT_SYMBOL(xfrm_state_walk); | 1586 | EXPORT_SYMBOL(xfrm_state_walk); |
1580 | 1587 | ||
1588 | void 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 | } | ||
1595 | EXPORT_SYMBOL(xfrm_state_walk_init); | ||
1596 | |||
1597 | void 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 | } | ||
1606 | EXPORT_SYMBOL(xfrm_state_walk_done); | ||
1607 | |||
1581 | 1608 | ||
1582 | void xfrm_replay_notify(struct xfrm_state *x, int event) | 1609 | void 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 |
1789 | int km_migrate(struct xfrm_selector *sel, u8 dir, u8 type, | 1816 | int 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 | } |