diff options
Diffstat (limited to 'net/xfrm')
-rw-r--r-- | net/xfrm/xfrm_policy.c | 132 | ||||
-rw-r--r-- | net/xfrm/xfrm_state.c | 53 | ||||
-rw-r--r-- | net/xfrm/xfrm_user.c | 71 |
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 | ||
47 | static DEFINE_RWLOCK(xfrm_policy_lock); | 47 | static DEFINE_RWLOCK(xfrm_policy_lock); |
48 | 48 | ||
49 | static struct list_head xfrm_policy_bytype[XFRM_POLICY_TYPE_MAX]; | ||
49 | unsigned int xfrm_policy_count[XFRM_POLICY_MAX*2]; | 50 | unsigned int xfrm_policy_count[XFRM_POLICY_MAX*2]; |
50 | EXPORT_SYMBOL(xfrm_policy_count); | 51 | EXPORT_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 | ||
100 | static 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 | |||
99 | static inline struct dst_entry *xfrm_dst_lookup(struct xfrm_state *x, int tos, | 119 | static 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 | } |
823 | EXPORT_SYMBOL(xfrm_policy_flush); | 857 | EXPORT_SYMBOL(xfrm_policy_flush); |
824 | 858 | ||
825 | int xfrm_policy_walk(u8 type, int (*func)(struct xfrm_policy *, int, int, void*), | 859 | int 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); | ||
874 | out: | 909 | out: |
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 | } |
878 | EXPORT_SYMBOL(xfrm_policy_walk); | 915 | EXPORT_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) | |||
2038 | void xfrm_dst_ifdown(struct dst_entry *dst, struct net_device *dev) | 2079 | void 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 | */ |
53 | static LIST_HEAD(xfrm_state_all); | ||
53 | static struct hlist_head *xfrm_state_bydst __read_mostly; | 54 | static struct hlist_head *xfrm_state_bydst __read_mostly; |
54 | static struct hlist_head *xfrm_state_bysrc __read_mostly; | 55 | static struct hlist_head *xfrm_state_bysrc __read_mostly; |
55 | static struct hlist_head *xfrm_state_byspi __read_mostly; | 56 | static 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 | } |
1523 | EXPORT_SYMBOL(xfrm_alloc_spi); | 1531 | EXPORT_SYMBOL(xfrm_alloc_spi); |
1524 | 1532 | ||
1525 | int xfrm_state_walk(u8 proto, int (*func)(struct xfrm_state *, int, void*), | 1533 | int 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); | ||
1553 | out: | 1570 | out: |
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 | } |
1557 | EXPORT_SYMBOL(xfrm_state_walk); | 1576 | EXPORT_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 | ||
536 | static int copy_sec_ctx(struct xfrm_sec_ctx *s, struct sk_buff *skb) | 534 | static 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); |
615 | out: | ||
616 | sp->this_idx++; | ||
617 | return 0; | 610 | return 0; |
618 | 611 | ||
619 | nla_put_failure: | 612 | nla_put_failure: |
@@ -621,18 +614,32 @@ nla_put_failure: | |||
621 | return err; | 614 | return err; |
622 | } | 615 | } |
623 | 616 | ||
617 | static 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 | |||
624 | static int xfrm_dump_sa(struct sk_buff *skb, struct netlink_callback *cb) | 624 | static 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); |
1250 | out: | ||
1251 | sp->this_idx++; | ||
1252 | return 0; | 1253 | return 0; |
1253 | 1254 | ||
1254 | nlmsg_failure: | 1255 | nlmsg_failure: |
@@ -1256,21 +1257,33 @@ nlmsg_failure: | |||
1256 | return -EMSGSIZE; | 1257 | return -EMSGSIZE; |
1257 | } | 1258 | } |
1258 | 1259 | ||
1260 | static 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 | |||
1259 | static int xfrm_dump_policy(struct sk_buff *skb, struct netlink_callback *cb) | 1268 | static 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] = { | |||
1888 | static struct xfrm_link { | 1900 | static 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, |