aboutsummaryrefslogtreecommitdiffstats
path: root/net/xfrm
diff options
context:
space:
mode:
Diffstat (limited to 'net/xfrm')
-rw-r--r--net/xfrm/xfrm_policy.c156
-rw-r--r--net/xfrm/xfrm_state.c53
-rw-r--r--net/xfrm/xfrm_user.c104
3 files changed, 199 insertions, 114 deletions
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
index 9fc4c315f6cd..ab4d0e598a2c 100644
--- a/net/xfrm/xfrm_policy.c
+++ b/net/xfrm/xfrm_policy.c
@@ -46,6 +46,7 @@ EXPORT_SYMBOL(xfrm_cfg_mutex);
46 46
47static DEFINE_RWLOCK(xfrm_policy_lock); 47static DEFINE_RWLOCK(xfrm_policy_lock);
48 48
49static struct list_head xfrm_policy_bytype[XFRM_POLICY_TYPE_MAX];
49unsigned int xfrm_policy_count[XFRM_POLICY_MAX*2]; 50unsigned int xfrm_policy_count[XFRM_POLICY_MAX*2];
50EXPORT_SYMBOL(xfrm_policy_count); 51EXPORT_SYMBOL(xfrm_policy_count);
51 52
@@ -96,25 +97,52 @@ int xfrm_selector_match(struct xfrm_selector *sel, struct flowi *fl,
96 return 0; 97 return 0;
97} 98}
98 99
100static inline struct dst_entry *__xfrm_dst_lookup(int tos,
101 xfrm_address_t *saddr,
102 xfrm_address_t *daddr,
103 int family)
104{
105 struct xfrm_policy_afinfo *afinfo;
106 struct dst_entry *dst;
107
108 afinfo = xfrm_policy_get_afinfo(family);
109 if (unlikely(afinfo == NULL))
110 return ERR_PTR(-EAFNOSUPPORT);
111
112 dst = afinfo->dst_lookup(tos, saddr, daddr);
113
114 xfrm_policy_put_afinfo(afinfo);
115
116 return dst;
117}
118
99static inline struct dst_entry *xfrm_dst_lookup(struct xfrm_state *x, int tos, 119static inline struct dst_entry *xfrm_dst_lookup(struct xfrm_state *x, int tos,
120 xfrm_address_t *prev_saddr,
121 xfrm_address_t *prev_daddr,
100 int family) 122 int family)
101{ 123{
102 xfrm_address_t *saddr = &x->props.saddr; 124 xfrm_address_t *saddr = &x->props.saddr;
103 xfrm_address_t *daddr = &x->id.daddr; 125 xfrm_address_t *daddr = &x->id.daddr;
104 struct xfrm_policy_afinfo *afinfo;
105 struct dst_entry *dst; 126 struct dst_entry *dst;
106 127
107 if (x->type->flags & XFRM_TYPE_LOCAL_COADDR) 128 if (x->type->flags & XFRM_TYPE_LOCAL_COADDR) {
108 saddr = x->coaddr; 129 saddr = x->coaddr;
109 if (x->type->flags & XFRM_TYPE_REMOTE_COADDR) 130 daddr = prev_daddr;
131 }
132 if (x->type->flags & XFRM_TYPE_REMOTE_COADDR) {
133 saddr = prev_saddr;
110 daddr = x->coaddr; 134 daddr = x->coaddr;
135 }
111 136
112 afinfo = xfrm_policy_get_afinfo(family); 137 dst = __xfrm_dst_lookup(tos, saddr, daddr, family);
113 if (unlikely(afinfo == NULL)) 138
114 return ERR_PTR(-EAFNOSUPPORT); 139 if (!IS_ERR(dst)) {
140 if (prev_saddr != saddr)
141 memcpy(prev_saddr, saddr, sizeof(*prev_saddr));
142 if (prev_daddr != daddr)
143 memcpy(prev_daddr, daddr, sizeof(*prev_daddr));
144 }
115 145
116 dst = afinfo->dst_lookup(tos, saddr, daddr);
117 xfrm_policy_put_afinfo(afinfo);
118 return dst; 146 return dst;
119} 147}
120 148
@@ -208,6 +236,7 @@ struct xfrm_policy *xfrm_policy_alloc(gfp_t gfp)
208 policy = kzalloc(sizeof(struct xfrm_policy), gfp); 236 policy = kzalloc(sizeof(struct xfrm_policy), gfp);
209 237
210 if (policy) { 238 if (policy) {
239 INIT_LIST_HEAD(&policy->bytype);
211 INIT_HLIST_NODE(&policy->bydst); 240 INIT_HLIST_NODE(&policy->bydst);
212 INIT_HLIST_NODE(&policy->byidx); 241 INIT_HLIST_NODE(&policy->byidx);
213 rwlock_init(&policy->lock); 242 rwlock_init(&policy->lock);
@@ -230,7 +259,11 @@ void xfrm_policy_destroy(struct xfrm_policy *policy)
230 if (del_timer(&policy->timer)) 259 if (del_timer(&policy->timer))
231 BUG(); 260 BUG();
232 261
233 security_xfrm_policy_free(policy); 262 write_lock_bh(&xfrm_policy_lock);
263 list_del(&policy->bytype);
264 write_unlock_bh(&xfrm_policy_lock);
265
266 security_xfrm_policy_free(policy->security);
234 kfree(policy); 267 kfree(policy);
235} 268}
236EXPORT_SYMBOL(xfrm_policy_destroy); 269EXPORT_SYMBOL(xfrm_policy_destroy);
@@ -584,6 +617,7 @@ int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl)
584 policy->curlft.use_time = 0; 617 policy->curlft.use_time = 0;
585 if (!mod_timer(&policy->timer, jiffies + HZ)) 618 if (!mod_timer(&policy->timer, jiffies + HZ))
586 xfrm_pol_hold(policy); 619 xfrm_pol_hold(policy);
620 list_add_tail(&policy->bytype, &xfrm_policy_bytype[policy->type]);
587 write_unlock_bh(&xfrm_policy_lock); 621 write_unlock_bh(&xfrm_policy_lock);
588 622
589 if (delpol) 623 if (delpol)
@@ -642,7 +676,8 @@ struct xfrm_policy *xfrm_policy_bysel_ctx(u8 type, int dir,
642 xfrm_sec_ctx_match(ctx, pol->security)) { 676 xfrm_sec_ctx_match(ctx, pol->security)) {
643 xfrm_pol_hold(pol); 677 xfrm_pol_hold(pol);
644 if (delete) { 678 if (delete) {
645 *err = security_xfrm_policy_delete(pol); 679 *err = security_xfrm_policy_delete(
680 pol->security);
646 if (*err) { 681 if (*err) {
647 write_unlock_bh(&xfrm_policy_lock); 682 write_unlock_bh(&xfrm_policy_lock);
648 return pol; 683 return pol;
@@ -684,7 +719,8 @@ struct xfrm_policy *xfrm_policy_byid(u8 type, int dir, u32 id, int delete,
684 if (pol->type == type && pol->index == id) { 719 if (pol->type == type && pol->index == id) {
685 xfrm_pol_hold(pol); 720 xfrm_pol_hold(pol);
686 if (delete) { 721 if (delete) {
687 *err = security_xfrm_policy_delete(pol); 722 *err = security_xfrm_policy_delete(
723 pol->security);
688 if (*err) { 724 if (*err) {
689 write_unlock_bh(&xfrm_policy_lock); 725 write_unlock_bh(&xfrm_policy_lock);
690 return pol; 726 return pol;
@@ -722,7 +758,7 @@ xfrm_policy_flush_secctx_check(u8 type, struct xfrm_audit *audit_info)
722 &xfrm_policy_inexact[dir], bydst) { 758 &xfrm_policy_inexact[dir], bydst) {
723 if (pol->type != type) 759 if (pol->type != type)
724 continue; 760 continue;
725 err = security_xfrm_policy_delete(pol); 761 err = security_xfrm_policy_delete(pol->security);
726 if (err) { 762 if (err) {
727 xfrm_audit_policy_delete(pol, 0, 763 xfrm_audit_policy_delete(pol, 0,
728 audit_info->loginuid, 764 audit_info->loginuid,
@@ -736,7 +772,8 @@ xfrm_policy_flush_secctx_check(u8 type, struct xfrm_audit *audit_info)
736 bydst) { 772 bydst) {
737 if (pol->type != type) 773 if (pol->type != type)
738 continue; 774 continue;
739 err = security_xfrm_policy_delete(pol); 775 err = security_xfrm_policy_delete(
776 pol->security);
740 if (err) { 777 if (err) {
741 xfrm_audit_policy_delete(pol, 0, 778 xfrm_audit_policy_delete(pol, 0,
742 audit_info->loginuid, 779 audit_info->loginuid,
@@ -822,57 +859,60 @@ out:
822} 859}
823EXPORT_SYMBOL(xfrm_policy_flush); 860EXPORT_SYMBOL(xfrm_policy_flush);
824 861
825int xfrm_policy_walk(u8 type, int (*func)(struct xfrm_policy *, int, int, void*), 862int xfrm_policy_walk(struct xfrm_policy_walk *walk,
863 int (*func)(struct xfrm_policy *, int, int, void*),
826 void *data) 864 void *data)
827{ 865{
828 struct xfrm_policy *pol, *last = NULL; 866 struct xfrm_policy *old, *pol, *last = NULL;
829 struct hlist_node *entry; 867 int error = 0;
830 int dir, last_dir = 0, count, error;
831 868
869 if (walk->type >= XFRM_POLICY_TYPE_MAX &&
870 walk->type != XFRM_POLICY_TYPE_ANY)
871 return -EINVAL;
872
873 if (walk->policy == NULL && walk->count != 0)
874 return 0;
875
876 old = pol = walk->policy;
877 walk->policy = NULL;
832 read_lock_bh(&xfrm_policy_lock); 878 read_lock_bh(&xfrm_policy_lock);
833 count = 0;
834 879
835 for (dir = 0; dir < 2*XFRM_POLICY_MAX; dir++) { 880 for (; walk->cur_type < XFRM_POLICY_TYPE_MAX; walk->cur_type++) {
836 struct hlist_head *table = xfrm_policy_bydst[dir].table; 881 if (walk->type != walk->cur_type &&
837 int i; 882 walk->type != XFRM_POLICY_TYPE_ANY)
883 continue;
838 884
839 hlist_for_each_entry(pol, entry, 885 if (pol == NULL) {
840 &xfrm_policy_inexact[dir], bydst) { 886 pol = list_first_entry(&xfrm_policy_bytype[walk->cur_type],
841 if (pol->type != type) 887 struct xfrm_policy, bytype);
888 }
889 list_for_each_entry_from(pol, &xfrm_policy_bytype[walk->cur_type], bytype) {
890 if (pol->dead)
842 continue; 891 continue;
843 if (last) { 892 if (last) {
844 error = func(last, last_dir % XFRM_POLICY_MAX, 893 error = func(last, xfrm_policy_id2dir(last->index),
845 count, data); 894 walk->count, data);
846 if (error) 895 if (error) {
896 xfrm_pol_hold(last);
897 walk->policy = last;
847 goto out; 898 goto out;
848 }
849 last = pol;
850 last_dir = dir;
851 count++;
852 }
853 for (i = xfrm_policy_bydst[dir].hmask; i >= 0; i--) {
854 hlist_for_each_entry(pol, entry, table + i, bydst) {
855 if (pol->type != type)
856 continue;
857 if (last) {
858 error = func(last, last_dir % XFRM_POLICY_MAX,
859 count, data);
860 if (error)
861 goto out;
862 } 899 }
863 last = pol;
864 last_dir = dir;
865 count++;
866 } 900 }
901 last = pol;
902 walk->count++;
867 } 903 }
904 pol = NULL;
868 } 905 }
869 if (count == 0) { 906 if (walk->count == 0) {
870 error = -ENOENT; 907 error = -ENOENT;
871 goto out; 908 goto out;
872 } 909 }
873 error = func(last, last_dir % XFRM_POLICY_MAX, 0, data); 910 if (last)
911 error = func(last, xfrm_policy_id2dir(last->index), 0, data);
874out: 912out:
875 read_unlock_bh(&xfrm_policy_lock); 913 read_unlock_bh(&xfrm_policy_lock);
914 if (old != NULL)
915 xfrm_pol_put(old);
876 return error; 916 return error;
877} 917}
878EXPORT_SYMBOL(xfrm_policy_walk); 918EXPORT_SYMBOL(xfrm_policy_walk);
@@ -894,7 +934,8 @@ static int xfrm_policy_match(struct xfrm_policy *pol, struct flowi *fl,
894 934
895 match = xfrm_selector_match(sel, fl, family); 935 match = xfrm_selector_match(sel, fl, family);
896 if (match) 936 if (match)
897 ret = security_xfrm_policy_lookup(pol, fl->secid, dir); 937 ret = security_xfrm_policy_lookup(pol->security, fl->secid,
938 dir);
898 939
899 return ret; 940 return ret;
900} 941}
@@ -1011,8 +1052,9 @@ static struct xfrm_policy *xfrm_sk_policy_lookup(struct sock *sk, int dir, struc
1011 int err = 0; 1052 int err = 0;
1012 1053
1013 if (match) { 1054 if (match) {
1014 err = security_xfrm_policy_lookup(pol, fl->secid, 1055 err = security_xfrm_policy_lookup(pol->security,
1015 policy_to_flow_dir(dir)); 1056 fl->secid,
1057 policy_to_flow_dir(dir));
1016 if (!err) 1058 if (!err)
1017 xfrm_pol_hold(pol); 1059 xfrm_pol_hold(pol);
1018 else if (err == -ESRCH) 1060 else if (err == -ESRCH)
@@ -1101,7 +1143,8 @@ static struct xfrm_policy *clone_policy(struct xfrm_policy *old, int dir)
1101 1143
1102 if (newp) { 1144 if (newp) {
1103 newp->selector = old->selector; 1145 newp->selector = old->selector;
1104 if (security_xfrm_policy_clone(old, newp)) { 1146 if (security_xfrm_policy_clone(old->security,
1147 &newp->security)) {
1105 kfree(newp); 1148 kfree(newp);
1106 return NULL; /* ENOMEM */ 1149 return NULL; /* ENOMEM */
1107 } 1150 }
@@ -1344,6 +1387,9 @@ static struct dst_entry *xfrm_bundle_create(struct xfrm_policy *policy,
1344 int trailer_len = 0; 1387 int trailer_len = 0;
1345 int tos; 1388 int tos;
1346 int family = policy->selector.family; 1389 int family = policy->selector.family;
1390 xfrm_address_t saddr, daddr;
1391
1392 xfrm_flowi_addr_get(fl, &saddr, &daddr, family);
1347 1393
1348 tos = xfrm_get_tos(fl, family); 1394 tos = xfrm_get_tos(fl, family);
1349 err = tos; 1395 err = tos;
@@ -1374,7 +1420,8 @@ static struct dst_entry *xfrm_bundle_create(struct xfrm_policy *policy,
1374 1420
1375 if (xfrm[i]->props.mode != XFRM_MODE_TRANSPORT) { 1421 if (xfrm[i]->props.mode != XFRM_MODE_TRANSPORT) {
1376 family = xfrm[i]->props.family; 1422 family = xfrm[i]->props.family;
1377 dst = xfrm_dst_lookup(xfrm[i], tos, family); 1423 dst = xfrm_dst_lookup(xfrm[i], tos, &saddr, &daddr,
1424 family);
1378 err = PTR_ERR(dst); 1425 err = PTR_ERR(dst);
1379 if (IS_ERR(dst)) 1426 if (IS_ERR(dst))
1380 goto put_states; 1427 goto put_states;
@@ -2038,7 +2085,7 @@ static int stale_bundle(struct dst_entry *dst)
2038void xfrm_dst_ifdown(struct dst_entry *dst, struct net_device *dev) 2085void xfrm_dst_ifdown(struct dst_entry *dst, struct net_device *dev)
2039{ 2086{
2040 while ((dst = dst->child) && dst->xfrm && dst->dev == dev) { 2087 while ((dst = dst->child) && dst->xfrm && dst->dev == dev) {
2041 dst->dev = dev->nd_net->loopback_dev; 2088 dst->dev = dev_net(dev)->loopback_dev;
2042 dev_hold(dst->dev); 2089 dev_hold(dst->dev);
2043 dev_put(dev); 2090 dev_put(dev);
2044 } 2091 }
@@ -2309,7 +2356,7 @@ static int xfrm_dev_event(struct notifier_block *this, unsigned long event, void
2309{ 2356{
2310 struct net_device *dev = ptr; 2357 struct net_device *dev = ptr;
2311 2358
2312 if (dev->nd_net != &init_net) 2359 if (dev_net(dev) != &init_net)
2313 return NOTIFY_DONE; 2360 return NOTIFY_DONE;
2314 2361
2315 switch (event) { 2362 switch (event) {
@@ -2365,6 +2412,9 @@ static void __init xfrm_policy_init(void)
2365 panic("XFRM: failed to allocate bydst hash\n"); 2412 panic("XFRM: failed to allocate bydst hash\n");
2366 } 2413 }
2367 2414
2415 for (dir = 0; dir < XFRM_POLICY_TYPE_MAX; dir++)
2416 INIT_LIST_HEAD(&xfrm_policy_bytype[dir]);
2417
2368 INIT_WORK(&xfrm_policy_gc_work, xfrm_policy_gc_task); 2418 INIT_WORK(&xfrm_policy_gc_work, xfrm_policy_gc_task);
2369 register_netdevice_notifier(&xfrm_dev_notifier); 2419 register_netdevice_notifier(&xfrm_dev_notifier);
2370} 2420}
diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c
index 58f1f9347b54..5dcc10b93c86 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;
@@ -512,6 +513,7 @@ struct xfrm_state *xfrm_state_alloc(void)
512 if (x) { 513 if (x) {
513 atomic_set(&x->refcnt, 1); 514 atomic_set(&x->refcnt, 1);
514 atomic_set(&x->tunnel_users, 0); 515 atomic_set(&x->tunnel_users, 0);
516 INIT_LIST_HEAD(&x->all);
515 INIT_HLIST_NODE(&x->bydst); 517 INIT_HLIST_NODE(&x->bydst);
516 INIT_HLIST_NODE(&x->bysrc); 518 INIT_HLIST_NODE(&x->bysrc);
517 INIT_HLIST_NODE(&x->byspi); 519 INIT_HLIST_NODE(&x->byspi);
@@ -537,6 +539,10 @@ void __xfrm_state_destroy(struct xfrm_state *x)
537{ 539{
538 BUG_TRAP(x->km.state == XFRM_STATE_DEAD); 540 BUG_TRAP(x->km.state == XFRM_STATE_DEAD);
539 541
542 spin_lock_bh(&xfrm_state_lock);
543 list_del(&x->all);
544 spin_unlock_bh(&xfrm_state_lock);
545
540 spin_lock_bh(&xfrm_state_gc_lock); 546 spin_lock_bh(&xfrm_state_gc_lock);
541 hlist_add_head(&x->bydst, &xfrm_state_gc_list); 547 hlist_add_head(&x->bydst, &xfrm_state_gc_list);
542 spin_unlock_bh(&xfrm_state_gc_lock); 548 spin_unlock_bh(&xfrm_state_gc_lock);
@@ -913,6 +919,8 @@ static void __xfrm_state_insert(struct xfrm_state *x)
913 919
914 x->genid = ++xfrm_state_genid; 920 x->genid = ++xfrm_state_genid;
915 921
922 list_add_tail(&x->all, &xfrm_state_all);
923
916 h = xfrm_dst_hash(&x->id.daddr, &x->props.saddr, 924 h = xfrm_dst_hash(&x->id.daddr, &x->props.saddr,
917 x->props.reqid, x->props.family); 925 x->props.reqid, x->props.family);
918 hlist_add_head(&x->bydst, xfrm_state_bydst+h); 926 hlist_add_head(&x->bydst, xfrm_state_bydst+h);
@@ -1522,36 +1530,47 @@ unlock:
1522} 1530}
1523EXPORT_SYMBOL(xfrm_alloc_spi); 1531EXPORT_SYMBOL(xfrm_alloc_spi);
1524 1532
1525int xfrm_state_walk(u8 proto, int (*func)(struct xfrm_state *, int, void*), 1533int xfrm_state_walk(struct xfrm_state_walk *walk,
1534 int (*func)(struct xfrm_state *, int, void*),
1526 void *data) 1535 void *data)
1527{ 1536{
1528 int i; 1537 struct xfrm_state *old, *x, *last = NULL;
1529 struct xfrm_state *x, *last = NULL;
1530 struct hlist_node *entry;
1531 int count = 0;
1532 int err = 0; 1538 int err = 0;
1533 1539
1540 if (walk->state == NULL && walk->count != 0)
1541 return 0;
1542
1543 old = x = walk->state;
1544 walk->state = NULL;
1534 spin_lock_bh(&xfrm_state_lock); 1545 spin_lock_bh(&xfrm_state_lock);
1535 for (i = 0; i <= xfrm_state_hmask; i++) { 1546 if (x == NULL)
1536 hlist_for_each_entry(x, entry, xfrm_state_bydst+i, bydst) { 1547 x = list_first_entry(&xfrm_state_all, struct xfrm_state, all);
1537 if (!xfrm_id_proto_match(x->id.proto, proto)) 1548 list_for_each_entry_from(x, &xfrm_state_all, all) {
1538 continue; 1549 if (x->km.state == XFRM_STATE_DEAD)
1539 if (last) { 1550 continue;
1540 err = func(last, count, data); 1551 if (!xfrm_id_proto_match(x->id.proto, walk->proto))
1541 if (err) 1552 continue;
1542 goto out; 1553 if (last) {
1554 err = func(last, walk->count, data);
1555 if (err) {
1556 xfrm_state_hold(last);
1557 walk->state = last;
1558 goto out;
1543 } 1559 }
1544 last = x;
1545 count++;
1546 } 1560 }
1561 last = x;
1562 walk->count++;
1547 } 1563 }
1548 if (count == 0) { 1564 if (walk->count == 0) {
1549 err = -ENOENT; 1565 err = -ENOENT;
1550 goto out; 1566 goto out;
1551 } 1567 }
1552 err = func(last, 0, data); 1568 if (last)
1569 err = func(last, 0, data);
1553out: 1570out:
1554 spin_unlock_bh(&xfrm_state_lock); 1571 spin_unlock_bh(&xfrm_state_lock);
1572 if (old != NULL)
1573 xfrm_state_put(old);
1555 return err; 1574 return err;
1556} 1575}
1557EXPORT_SYMBOL(xfrm_state_walk); 1576EXPORT_SYMBOL(xfrm_state_walk);
diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c
index 019d21de19b3..b822b56e5b8e 100644
--- a/net/xfrm/xfrm_user.c
+++ b/net/xfrm/xfrm_user.c
@@ -529,8 +529,6 @@ struct xfrm_dump_info {
529 struct sk_buff *out_skb; 529 struct sk_buff *out_skb;
530 u32 nlmsg_seq; 530 u32 nlmsg_seq;
531 u16 nlmsg_flags; 531 u16 nlmsg_flags;
532 int start_idx;
533 int this_idx;
534}; 532};
535 533
536static int copy_sec_ctx(struct xfrm_sec_ctx *s, struct sk_buff *skb) 534static int copy_sec_ctx(struct xfrm_sec_ctx *s, struct sk_buff *skb)
@@ -597,9 +595,6 @@ static int dump_one_state(struct xfrm_state *x, int count, void *ptr)
597 struct nlmsghdr *nlh; 595 struct nlmsghdr *nlh;
598 int err; 596 int err;
599 597
600 if (sp->this_idx < sp->start_idx)
601 goto out;
602
603 nlh = nlmsg_put(skb, NETLINK_CB(in_skb).pid, sp->nlmsg_seq, 598 nlh = nlmsg_put(skb, NETLINK_CB(in_skb).pid, sp->nlmsg_seq,
604 XFRM_MSG_NEWSA, sizeof(*p), sp->nlmsg_flags); 599 XFRM_MSG_NEWSA, sizeof(*p), sp->nlmsg_flags);
605 if (nlh == NULL) 600 if (nlh == NULL)
@@ -612,8 +607,6 @@ static int dump_one_state(struct xfrm_state *x, int count, void *ptr)
612 goto nla_put_failure; 607 goto nla_put_failure;
613 608
614 nlmsg_end(skb, nlh); 609 nlmsg_end(skb, nlh);
615out:
616 sp->this_idx++;
617 return 0; 610 return 0;
618 611
619nla_put_failure: 612nla_put_failure:
@@ -621,18 +614,32 @@ nla_put_failure:
621 return err; 614 return err;
622} 615}
623 616
617static int xfrm_dump_sa_done(struct netlink_callback *cb)
618{
619 struct xfrm_state_walk *walk = (struct xfrm_state_walk *) &cb->args[1];
620 xfrm_state_walk_done(walk);
621 return 0;
622}
623
624static int xfrm_dump_sa(struct sk_buff *skb, struct netlink_callback *cb) 624static int xfrm_dump_sa(struct sk_buff *skb, struct netlink_callback *cb)
625{ 625{
626 struct xfrm_state_walk *walk = (struct xfrm_state_walk *) &cb->args[1];
626 struct xfrm_dump_info info; 627 struct xfrm_dump_info info;
627 628
629 BUILD_BUG_ON(sizeof(struct xfrm_state_walk) >
630 sizeof(cb->args) - sizeof(cb->args[0]));
631
628 info.in_skb = cb->skb; 632 info.in_skb = cb->skb;
629 info.out_skb = skb; 633 info.out_skb = skb;
630 info.nlmsg_seq = cb->nlh->nlmsg_seq; 634 info.nlmsg_seq = cb->nlh->nlmsg_seq;
631 info.nlmsg_flags = NLM_F_MULTI; 635 info.nlmsg_flags = NLM_F_MULTI;
632 info.this_idx = 0; 636
633 info.start_idx = cb->args[0]; 637 if (!cb->args[0]) {
634 (void) xfrm_state_walk(0, dump_one_state, &info); 638 cb->args[0] = 1;
635 cb->args[0] = info.this_idx; 639 xfrm_state_walk_init(walk, 0);
640 }
641
642 (void) xfrm_state_walk(walk, dump_one_state, &info);
636 643
637 return skb->len; 644 return skb->len;
638} 645}
@@ -651,7 +658,6 @@ static struct sk_buff *xfrm_state_netlink(struct sk_buff *in_skb,
651 info.out_skb = skb; 658 info.out_skb = skb;
652 info.nlmsg_seq = seq; 659 info.nlmsg_seq = seq;
653 info.nlmsg_flags = 0; 660 info.nlmsg_flags = 0;
654 info.this_idx = info.start_idx = 0;
655 661
656 if (dump_one_state(x, 0, &info)) { 662 if (dump_one_state(x, 0, &info)) {
657 kfree_skb(skb); 663 kfree_skb(skb);
@@ -953,7 +959,7 @@ static int copy_from_user_sec_ctx(struct xfrm_policy *pol, struct nlattr **attrs
953 return 0; 959 return 0;
954 960
955 uctx = nla_data(rt); 961 uctx = nla_data(rt);
956 return security_xfrm_policy_alloc(pol, uctx); 962 return security_xfrm_policy_alloc(&pol->security, uctx);
957} 963}
958 964
959static void copy_templates(struct xfrm_policy *xp, struct xfrm_user_tmpl *ut, 965static void copy_templates(struct xfrm_policy *xp, struct xfrm_user_tmpl *ut,
@@ -1137,7 +1143,7 @@ static int xfrm_add_policy(struct sk_buff *skb, struct nlmsghdr *nlh,
1137 NETLINK_CB(skb).sid); 1143 NETLINK_CB(skb).sid);
1138 1144
1139 if (err) { 1145 if (err) {
1140 security_xfrm_policy_free(xp); 1146 security_xfrm_policy_free(xp->security);
1141 kfree(xp); 1147 kfree(xp);
1142 return err; 1148 return err;
1143 } 1149 }
@@ -1229,9 +1235,6 @@ static int dump_one_policy(struct xfrm_policy *xp, int dir, int count, void *ptr
1229 struct sk_buff *skb = sp->out_skb; 1235 struct sk_buff *skb = sp->out_skb;
1230 struct nlmsghdr *nlh; 1236 struct nlmsghdr *nlh;
1231 1237
1232 if (sp->this_idx < sp->start_idx)
1233 goto out;
1234
1235 nlh = nlmsg_put(skb, NETLINK_CB(in_skb).pid, sp->nlmsg_seq, 1238 nlh = nlmsg_put(skb, NETLINK_CB(in_skb).pid, sp->nlmsg_seq,
1236 XFRM_MSG_NEWPOLICY, sizeof(*p), sp->nlmsg_flags); 1239 XFRM_MSG_NEWPOLICY, sizeof(*p), sp->nlmsg_flags);
1237 if (nlh == NULL) 1240 if (nlh == NULL)
@@ -1247,8 +1250,6 @@ static int dump_one_policy(struct xfrm_policy *xp, int dir, int count, void *ptr
1247 goto nlmsg_failure; 1250 goto nlmsg_failure;
1248 1251
1249 nlmsg_end(skb, nlh); 1252 nlmsg_end(skb, nlh);
1250out:
1251 sp->this_idx++;
1252 return 0; 1253 return 0;
1253 1254
1254nlmsg_failure: 1255nlmsg_failure:
@@ -1256,21 +1257,33 @@ nlmsg_failure:
1256 return -EMSGSIZE; 1257 return -EMSGSIZE;
1257} 1258}
1258 1259
1260static int xfrm_dump_policy_done(struct netlink_callback *cb)
1261{
1262 struct xfrm_policy_walk *walk = (struct xfrm_policy_walk *) &cb->args[1];
1263
1264 xfrm_policy_walk_done(walk);
1265 return 0;
1266}
1267
1259static int xfrm_dump_policy(struct sk_buff *skb, struct netlink_callback *cb) 1268static int xfrm_dump_policy(struct sk_buff *skb, struct netlink_callback *cb)
1260{ 1269{
1270 struct xfrm_policy_walk *walk = (struct xfrm_policy_walk *) &cb->args[1];
1261 struct xfrm_dump_info info; 1271 struct xfrm_dump_info info;
1262 1272
1273 BUILD_BUG_ON(sizeof(struct xfrm_policy_walk) >
1274 sizeof(cb->args) - sizeof(cb->args[0]));
1275
1263 info.in_skb = cb->skb; 1276 info.in_skb = cb->skb;
1264 info.out_skb = skb; 1277 info.out_skb = skb;
1265 info.nlmsg_seq = cb->nlh->nlmsg_seq; 1278 info.nlmsg_seq = cb->nlh->nlmsg_seq;
1266 info.nlmsg_flags = NLM_F_MULTI; 1279 info.nlmsg_flags = NLM_F_MULTI;
1267 info.this_idx = 0; 1280
1268 info.start_idx = cb->args[0]; 1281 if (!cb->args[0]) {
1269 (void) xfrm_policy_walk(XFRM_POLICY_TYPE_MAIN, dump_one_policy, &info); 1282 cb->args[0] = 1;
1270#ifdef CONFIG_XFRM_SUB_POLICY 1283 xfrm_policy_walk_init(walk, XFRM_POLICY_TYPE_ANY);
1271 (void) xfrm_policy_walk(XFRM_POLICY_TYPE_SUB, dump_one_policy, &info); 1284 }
1272#endif 1285
1273 cb->args[0] = info.this_idx; 1286 (void) xfrm_policy_walk(walk, dump_one_policy, &info);
1274 1287
1275 return skb->len; 1288 return skb->len;
1276} 1289}
@@ -1290,7 +1303,6 @@ static struct sk_buff *xfrm_policy_netlink(struct sk_buff *in_skb,
1290 info.out_skb = skb; 1303 info.out_skb = skb;
1291 info.nlmsg_seq = seq; 1304 info.nlmsg_seq = seq;
1292 info.nlmsg_flags = 0; 1305 info.nlmsg_flags = 0;
1293 info.this_idx = info.start_idx = 0;
1294 1306
1295 if (dump_one_policy(xp, dir, 0, &info) < 0) { 1307 if (dump_one_policy(xp, dir, 0, &info) < 0) {
1296 kfree_skb(skb); 1308 kfree_skb(skb);
@@ -1325,22 +1337,23 @@ static int xfrm_get_policy(struct sk_buff *skb, struct nlmsghdr *nlh,
1325 xp = xfrm_policy_byid(type, p->dir, p->index, delete, &err); 1337 xp = xfrm_policy_byid(type, p->dir, p->index, delete, &err);
1326 else { 1338 else {
1327 struct nlattr *rt = attrs[XFRMA_SEC_CTX]; 1339 struct nlattr *rt = attrs[XFRMA_SEC_CTX];
1328 struct xfrm_policy tmp; 1340 struct xfrm_sec_ctx *ctx;
1329 1341
1330 err = verify_sec_ctx_len(attrs); 1342 err = verify_sec_ctx_len(attrs);
1331 if (err) 1343 if (err)
1332 return err; 1344 return err;
1333 1345
1334 memset(&tmp, 0, sizeof(struct xfrm_policy));
1335 if (rt) { 1346 if (rt) {
1336 struct xfrm_user_sec_ctx *uctx = nla_data(rt); 1347 struct xfrm_user_sec_ctx *uctx = nla_data(rt);
1337 1348
1338 if ((err = security_xfrm_policy_alloc(&tmp, uctx))) 1349 err = security_xfrm_policy_alloc(&ctx, uctx);
1350 if (err)
1339 return err; 1351 return err;
1340 } 1352 } else
1341 xp = xfrm_policy_bysel_ctx(type, p->dir, &p->sel, tmp.security, 1353 ctx = NULL;
1354 xp = xfrm_policy_bysel_ctx(type, p->dir, &p->sel, ctx,
1342 delete, &err); 1355 delete, &err);
1343 security_xfrm_policy_free(&tmp); 1356 security_xfrm_policy_free(ctx);
1344 } 1357 }
1345 if (xp == NULL) 1358 if (xp == NULL)
1346 return -ENOENT; 1359 return -ENOENT;
@@ -1560,26 +1573,26 @@ static int xfrm_add_pol_expire(struct sk_buff *skb, struct nlmsghdr *nlh,
1560 xp = xfrm_policy_byid(type, p->dir, p->index, 0, &err); 1573 xp = xfrm_policy_byid(type, p->dir, p->index, 0, &err);
1561 else { 1574 else {
1562 struct nlattr *rt = attrs[XFRMA_SEC_CTX]; 1575 struct nlattr *rt = attrs[XFRMA_SEC_CTX];
1563 struct xfrm_policy tmp; 1576 struct xfrm_sec_ctx *ctx;
1564 1577
1565 err = verify_sec_ctx_len(attrs); 1578 err = verify_sec_ctx_len(attrs);
1566 if (err) 1579 if (err)
1567 return err; 1580 return err;
1568 1581
1569 memset(&tmp, 0, sizeof(struct xfrm_policy));
1570 if (rt) { 1582 if (rt) {
1571 struct xfrm_user_sec_ctx *uctx = nla_data(rt); 1583 struct xfrm_user_sec_ctx *uctx = nla_data(rt);
1572 1584
1573 if ((err = security_xfrm_policy_alloc(&tmp, uctx))) 1585 err = security_xfrm_policy_alloc(&ctx, uctx);
1586 if (err)
1574 return err; 1587 return err;
1575 } 1588 } else
1576 xp = xfrm_policy_bysel_ctx(type, p->dir, &p->sel, tmp.security, 1589 ctx = NULL;
1577 0, &err); 1590 xp = xfrm_policy_bysel_ctx(type, p->dir, &p->sel, ctx, 0, &err);
1578 security_xfrm_policy_free(&tmp); 1591 security_xfrm_policy_free(ctx);
1579 } 1592 }
1580
1581 if (xp == NULL) 1593 if (xp == NULL)
1582 return -ENOENT; 1594 return -ENOENT;
1595
1583 read_lock(&xp->lock); 1596 read_lock(&xp->lock);
1584 if (xp->dead) { 1597 if (xp->dead) {
1585 read_unlock(&xp->lock); 1598 read_unlock(&xp->lock);
@@ -1888,15 +1901,18 @@ static const struct nla_policy xfrma_policy[XFRMA_MAX+1] = {
1888static struct xfrm_link { 1901static struct xfrm_link {
1889 int (*doit)(struct sk_buff *, struct nlmsghdr *, struct nlattr **); 1902 int (*doit)(struct sk_buff *, struct nlmsghdr *, struct nlattr **);
1890 int (*dump)(struct sk_buff *, struct netlink_callback *); 1903 int (*dump)(struct sk_buff *, struct netlink_callback *);
1904 int (*done)(struct netlink_callback *);
1891} xfrm_dispatch[XFRM_NR_MSGTYPES] = { 1905} xfrm_dispatch[XFRM_NR_MSGTYPES] = {
1892 [XFRM_MSG_NEWSA - XFRM_MSG_BASE] = { .doit = xfrm_add_sa }, 1906 [XFRM_MSG_NEWSA - XFRM_MSG_BASE] = { .doit = xfrm_add_sa },
1893 [XFRM_MSG_DELSA - XFRM_MSG_BASE] = { .doit = xfrm_del_sa }, 1907 [XFRM_MSG_DELSA - XFRM_MSG_BASE] = { .doit = xfrm_del_sa },
1894 [XFRM_MSG_GETSA - XFRM_MSG_BASE] = { .doit = xfrm_get_sa, 1908 [XFRM_MSG_GETSA - XFRM_MSG_BASE] = { .doit = xfrm_get_sa,
1895 .dump = xfrm_dump_sa }, 1909 .dump = xfrm_dump_sa,
1910 .done = xfrm_dump_sa_done },
1896 [XFRM_MSG_NEWPOLICY - XFRM_MSG_BASE] = { .doit = xfrm_add_policy }, 1911 [XFRM_MSG_NEWPOLICY - XFRM_MSG_BASE] = { .doit = xfrm_add_policy },
1897 [XFRM_MSG_DELPOLICY - XFRM_MSG_BASE] = { .doit = xfrm_get_policy }, 1912 [XFRM_MSG_DELPOLICY - XFRM_MSG_BASE] = { .doit = xfrm_get_policy },
1898 [XFRM_MSG_GETPOLICY - XFRM_MSG_BASE] = { .doit = xfrm_get_policy, 1913 [XFRM_MSG_GETPOLICY - XFRM_MSG_BASE] = { .doit = xfrm_get_policy,
1899 .dump = xfrm_dump_policy }, 1914 .dump = xfrm_dump_policy,
1915 .done = xfrm_dump_policy_done },
1900 [XFRM_MSG_ALLOCSPI - XFRM_MSG_BASE] = { .doit = xfrm_alloc_userspi }, 1916 [XFRM_MSG_ALLOCSPI - XFRM_MSG_BASE] = { .doit = xfrm_alloc_userspi },
1901 [XFRM_MSG_ACQUIRE - XFRM_MSG_BASE] = { .doit = xfrm_add_acquire }, 1917 [XFRM_MSG_ACQUIRE - XFRM_MSG_BASE] = { .doit = xfrm_add_acquire },
1902 [XFRM_MSG_EXPIRE - XFRM_MSG_BASE] = { .doit = xfrm_add_sa_expire }, 1918 [XFRM_MSG_EXPIRE - XFRM_MSG_BASE] = { .doit = xfrm_add_sa_expire },
@@ -1935,7 +1951,7 @@ static int xfrm_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
1935 if (link->dump == NULL) 1951 if (link->dump == NULL)
1936 return -EINVAL; 1952 return -EINVAL;
1937 1953
1938 return netlink_dump_start(xfrm_nl, skb, nlh, link->dump, NULL); 1954 return netlink_dump_start(xfrm_nl, skb, nlh, link->dump, link->done);
1939 } 1955 }
1940 1956
1941 err = nlmsg_parse(nlh, xfrm_msg_min[type], attrs, XFRMA_MAX, 1957 err = nlmsg_parse(nlh, xfrm_msg_min[type], attrs, XFRMA_MAX,