aboutsummaryrefslogtreecommitdiffstats
path: root/net/xfrm
diff options
context:
space:
mode:
Diffstat (limited to 'net/xfrm')
-rw-r--r--net/xfrm/xfrm_policy.c132
-rw-r--r--net/xfrm/xfrm_state.c53
-rw-r--r--net/xfrm/xfrm_user.c71
3 files changed, 167 insertions, 89 deletions
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
index 9fc4c315f6cd..15d73e47cc2c 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,6 +259,10 @@ 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
262 write_lock_bh(&xfrm_policy_lock);
263 list_del(&policy->bytype);
264 write_unlock_bh(&xfrm_policy_lock);
265
233 security_xfrm_policy_free(policy); 266 security_xfrm_policy_free(policy);
234 kfree(policy); 267 kfree(policy);
235} 268}
@@ -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)
@@ -822,57 +856,60 @@ out:
822} 856}
823EXPORT_SYMBOL(xfrm_policy_flush); 857EXPORT_SYMBOL(xfrm_policy_flush);
824 858
825int xfrm_policy_walk(u8 type, int (*func)(struct xfrm_policy *, int, int, void*), 859int xfrm_policy_walk(struct xfrm_policy_walk *walk,
860 int (*func)(struct xfrm_policy *, int, int, void*),
826 void *data) 861 void *data)
827{ 862{
828 struct xfrm_policy *pol, *last = NULL; 863 struct xfrm_policy *old, *pol, *last = NULL;
829 struct hlist_node *entry; 864 int error = 0;
830 int dir, last_dir = 0, count, error;
831 865
866 if (walk->type >= XFRM_POLICY_TYPE_MAX &&
867 walk->type != XFRM_POLICY_TYPE_ANY)
868 return -EINVAL;
869
870 if (walk->policy == NULL && walk->count != 0)
871 return 0;
872
873 old = pol = walk->policy;
874 walk->policy = NULL;
832 read_lock_bh(&xfrm_policy_lock); 875 read_lock_bh(&xfrm_policy_lock);
833 count = 0;
834 876
835 for (dir = 0; dir < 2*XFRM_POLICY_MAX; dir++) { 877 for (; walk->cur_type < XFRM_POLICY_TYPE_MAX; walk->cur_type++) {
836 struct hlist_head *table = xfrm_policy_bydst[dir].table; 878 if (walk->type != walk->cur_type &&
837 int i; 879 walk->type != XFRM_POLICY_TYPE_ANY)
880 continue;
838 881
839 hlist_for_each_entry(pol, entry, 882 if (pol == NULL) {
840 &xfrm_policy_inexact[dir], bydst) { 883 pol = list_first_entry(&xfrm_policy_bytype[walk->cur_type],
841 if (pol->type != type) 884 struct xfrm_policy, bytype);
885 }
886 list_for_each_entry_from(pol, &xfrm_policy_bytype[walk->cur_type], bytype) {
887 if (pol->dead)
842 continue; 888 continue;
843 if (last) { 889 if (last) {
844 error = func(last, last_dir % XFRM_POLICY_MAX, 890 error = func(last, xfrm_policy_id2dir(last->index),
845 count, data); 891 walk->count, data);
846 if (error) 892 if (error) {
893 xfrm_pol_hold(last);
894 walk->policy = last;
847 goto out; 895 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 } 896 }
863 last = pol;
864 last_dir = dir;
865 count++;
866 } 897 }
898 last = pol;
899 walk->count++;
867 } 900 }
901 pol = NULL;
868 } 902 }
869 if (count == 0) { 903 if (walk->count == 0) {
870 error = -ENOENT; 904 error = -ENOENT;
871 goto out; 905 goto out;
872 } 906 }
873 error = func(last, last_dir % XFRM_POLICY_MAX, 0, data); 907 if (last)
908 error = func(last, xfrm_policy_id2dir(last->index), 0, data);
874out: 909out:
875 read_unlock_bh(&xfrm_policy_lock); 910 read_unlock_bh(&xfrm_policy_lock);
911 if (old != NULL)
912 xfrm_pol_put(old);
876 return error; 913 return error;
877} 914}
878EXPORT_SYMBOL(xfrm_policy_walk); 915EXPORT_SYMBOL(xfrm_policy_walk);
@@ -1344,6 +1381,9 @@ static struct dst_entry *xfrm_bundle_create(struct xfrm_policy *policy,
1344 int trailer_len = 0; 1381 int trailer_len = 0;
1345 int tos; 1382 int tos;
1346 int family = policy->selector.family; 1383 int family = policy->selector.family;
1384 xfrm_address_t saddr, daddr;
1385
1386 xfrm_flowi_addr_get(fl, &saddr, &daddr, family);
1347 1387
1348 tos = xfrm_get_tos(fl, family); 1388 tos = xfrm_get_tos(fl, family);
1349 err = tos; 1389 err = tos;
@@ -1374,7 +1414,8 @@ static struct dst_entry *xfrm_bundle_create(struct xfrm_policy *policy,
1374 1414
1375 if (xfrm[i]->props.mode != XFRM_MODE_TRANSPORT) { 1415 if (xfrm[i]->props.mode != XFRM_MODE_TRANSPORT) {
1376 family = xfrm[i]->props.family; 1416 family = xfrm[i]->props.family;
1377 dst = xfrm_dst_lookup(xfrm[i], tos, family); 1417 dst = xfrm_dst_lookup(xfrm[i], tos, &saddr, &daddr,
1418 family);
1378 err = PTR_ERR(dst); 1419 err = PTR_ERR(dst);
1379 if (IS_ERR(dst)) 1420 if (IS_ERR(dst))
1380 goto put_states; 1421 goto put_states;
@@ -2038,7 +2079,7 @@ static int stale_bundle(struct dst_entry *dst)
2038void xfrm_dst_ifdown(struct dst_entry *dst, struct net_device *dev) 2079void xfrm_dst_ifdown(struct dst_entry *dst, struct net_device *dev)
2039{ 2080{
2040 while ((dst = dst->child) && dst->xfrm && dst->dev == dev) { 2081 while ((dst = dst->child) && dst->xfrm && dst->dev == dev) {
2041 dst->dev = dev->nd_net->loopback_dev; 2082 dst->dev = dev_net(dev)->loopback_dev;
2042 dev_hold(dst->dev); 2083 dev_hold(dst->dev);
2043 dev_put(dev); 2084 dev_put(dev);
2044 } 2085 }
@@ -2309,7 +2350,7 @@ static int xfrm_dev_event(struct notifier_block *this, unsigned long event, void
2309{ 2350{
2310 struct net_device *dev = ptr; 2351 struct net_device *dev = ptr;
2311 2352
2312 if (dev->nd_net != &init_net) 2353 if (dev_net(dev) != &init_net)
2313 return NOTIFY_DONE; 2354 return NOTIFY_DONE;
2314 2355
2315 switch (event) { 2356 switch (event) {
@@ -2365,6 +2406,9 @@ static void __init xfrm_policy_init(void)
2365 panic("XFRM: failed to allocate bydst hash\n"); 2406 panic("XFRM: failed to allocate bydst hash\n");
2366 } 2407 }
2367 2408
2409 for (dir = 0; dir < XFRM_POLICY_TYPE_MAX; dir++)
2410 INIT_LIST_HEAD(&xfrm_policy_bytype[dir]);
2411
2368 INIT_WORK(&xfrm_policy_gc_work, xfrm_policy_gc_task); 2412 INIT_WORK(&xfrm_policy_gc_work, xfrm_policy_gc_task);
2369 register_netdevice_notifier(&xfrm_dev_notifier); 2413 register_netdevice_notifier(&xfrm_dev_notifier);
2370} 2414}
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 5d96f2728dc6..5578c909fcf6 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);
@@ -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);
@@ -1888,15 +1900,18 @@ static const struct nla_policy xfrma_policy[XFRMA_MAX+1] = {
1888static struct xfrm_link { 1900static struct xfrm_link {
1889 int (*doit)(struct sk_buff *, struct nlmsghdr *, struct nlattr **); 1901 int (*doit)(struct sk_buff *, struct nlmsghdr *, struct nlattr **);
1890 int (*dump)(struct sk_buff *, struct netlink_callback *); 1902 int (*dump)(struct sk_buff *, struct netlink_callback *);
1903 int (*done)(struct netlink_callback *);
1891} xfrm_dispatch[XFRM_NR_MSGTYPES] = { 1904} xfrm_dispatch[XFRM_NR_MSGTYPES] = {
1892 [XFRM_MSG_NEWSA - XFRM_MSG_BASE] = { .doit = xfrm_add_sa }, 1905 [XFRM_MSG_NEWSA - XFRM_MSG_BASE] = { .doit = xfrm_add_sa },
1893 [XFRM_MSG_DELSA - XFRM_MSG_BASE] = { .doit = xfrm_del_sa }, 1906 [XFRM_MSG_DELSA - XFRM_MSG_BASE] = { .doit = xfrm_del_sa },
1894 [XFRM_MSG_GETSA - XFRM_MSG_BASE] = { .doit = xfrm_get_sa, 1907 [XFRM_MSG_GETSA - XFRM_MSG_BASE] = { .doit = xfrm_get_sa,
1895 .dump = xfrm_dump_sa }, 1908 .dump = xfrm_dump_sa,
1909 .done = xfrm_dump_sa_done },
1896 [XFRM_MSG_NEWPOLICY - XFRM_MSG_BASE] = { .doit = xfrm_add_policy }, 1910 [XFRM_MSG_NEWPOLICY - XFRM_MSG_BASE] = { .doit = xfrm_add_policy },
1897 [XFRM_MSG_DELPOLICY - XFRM_MSG_BASE] = { .doit = xfrm_get_policy }, 1911 [XFRM_MSG_DELPOLICY - XFRM_MSG_BASE] = { .doit = xfrm_get_policy },
1898 [XFRM_MSG_GETPOLICY - XFRM_MSG_BASE] = { .doit = xfrm_get_policy, 1912 [XFRM_MSG_GETPOLICY - XFRM_MSG_BASE] = { .doit = xfrm_get_policy,
1899 .dump = xfrm_dump_policy }, 1913 .dump = xfrm_dump_policy,
1914 .done = xfrm_dump_policy_done },
1900 [XFRM_MSG_ALLOCSPI - XFRM_MSG_BASE] = { .doit = xfrm_alloc_userspi }, 1915 [XFRM_MSG_ALLOCSPI - XFRM_MSG_BASE] = { .doit = xfrm_alloc_userspi },
1901 [XFRM_MSG_ACQUIRE - XFRM_MSG_BASE] = { .doit = xfrm_add_acquire }, 1916 [XFRM_MSG_ACQUIRE - XFRM_MSG_BASE] = { .doit = xfrm_add_acquire },
1902 [XFRM_MSG_EXPIRE - XFRM_MSG_BASE] = { .doit = xfrm_add_sa_expire }, 1917 [XFRM_MSG_EXPIRE - XFRM_MSG_BASE] = { .doit = xfrm_add_sa_expire },
@@ -1935,7 +1950,7 @@ static int xfrm_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
1935 if (link->dump == NULL) 1950 if (link->dump == NULL)
1936 return -EINVAL; 1951 return -EINVAL;
1937 1952
1938 return netlink_dump_start(xfrm_nl, skb, nlh, link->dump, NULL); 1953 return netlink_dump_start(xfrm_nl, skb, nlh, link->dump, link->done);
1939 } 1954 }
1940 1955
1941 err = nlmsg_parse(nlh, xfrm_msg_min[type], attrs, XFRMA_MAX, 1956 err = nlmsg_parse(nlh, xfrm_msg_min[type], attrs, XFRMA_MAX,