diff options
author | Takashi Iwai <tiwai@suse.de> | 2008-12-19 02:22:57 -0500 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2008-12-19 02:22:57 -0500 |
commit | 0ff555192a8d20385d49d1c420e2e8d409b3c0da (patch) | |
tree | b6e4b6cae1028a310a3488ebf745954c51694bfc /net/xfrm | |
parent | 3218c178b41b420cb7e0d120c7a137a3969242e5 (diff) | |
parent | 9e43f0de690211cf7153b5f3ec251bc315647ada (diff) |
Merge branch 'fix/hda' into topic/hda
Diffstat (limited to 'net/xfrm')
-rw-r--r-- | net/xfrm/xfrm_policy.c | 125 | ||||
-rw-r--r-- | net/xfrm/xfrm_state.c | 84 | ||||
-rw-r--r-- | net/xfrm/xfrm_user.c | 61 |
3 files changed, 163 insertions, 107 deletions
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c index b7754b1b73a4..fb216c9adf86 100644 --- a/net/xfrm/xfrm_policy.c +++ b/net/xfrm/xfrm_policy.c | |||
@@ -34,7 +34,7 @@ | |||
34 | 34 | ||
35 | #include "xfrm_hash.h" | 35 | #include "xfrm_hash.h" |
36 | 36 | ||
37 | int sysctl_xfrm_larval_drop __read_mostly; | 37 | int sysctl_xfrm_larval_drop __read_mostly = 1; |
38 | 38 | ||
39 | #ifdef CONFIG_XFRM_STATISTICS | 39 | #ifdef CONFIG_XFRM_STATISTICS |
40 | DEFINE_SNMP_STAT(struct linux_xfrm_mib, xfrm_statistics) __read_mostly; | 40 | DEFINE_SNMP_STAT(struct linux_xfrm_mib, xfrm_statistics) __read_mostly; |
@@ -46,7 +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 | static struct list_head xfrm_policy_all; |
50 | unsigned int xfrm_policy_count[XFRM_POLICY_MAX*2]; | 50 | unsigned int xfrm_policy_count[XFRM_POLICY_MAX*2]; |
51 | EXPORT_SYMBOL(xfrm_policy_count); | 51 | EXPORT_SYMBOL(xfrm_policy_count); |
52 | 52 | ||
@@ -164,7 +164,7 @@ static void xfrm_policy_timer(unsigned long data) | |||
164 | 164 | ||
165 | read_lock(&xp->lock); | 165 | read_lock(&xp->lock); |
166 | 166 | ||
167 | if (xp->dead) | 167 | if (xp->walk.dead) |
168 | goto out; | 168 | goto out; |
169 | 169 | ||
170 | dir = xfrm_policy_id2dir(xp->index); | 170 | dir = xfrm_policy_id2dir(xp->index); |
@@ -236,7 +236,7 @@ struct xfrm_policy *xfrm_policy_alloc(gfp_t gfp) | |||
236 | policy = kzalloc(sizeof(struct xfrm_policy), gfp); | 236 | policy = kzalloc(sizeof(struct xfrm_policy), gfp); |
237 | 237 | ||
238 | if (policy) { | 238 | if (policy) { |
239 | INIT_LIST_HEAD(&policy->bytype); | 239 | INIT_LIST_HEAD(&policy->walk.all); |
240 | INIT_HLIST_NODE(&policy->bydst); | 240 | INIT_HLIST_NODE(&policy->bydst); |
241 | INIT_HLIST_NODE(&policy->byidx); | 241 | INIT_HLIST_NODE(&policy->byidx); |
242 | rwlock_init(&policy->lock); | 242 | rwlock_init(&policy->lock); |
@@ -252,17 +252,13 @@ EXPORT_SYMBOL(xfrm_policy_alloc); | |||
252 | 252 | ||
253 | void xfrm_policy_destroy(struct xfrm_policy *policy) | 253 | void xfrm_policy_destroy(struct xfrm_policy *policy) |
254 | { | 254 | { |
255 | BUG_ON(!policy->dead); | 255 | BUG_ON(!policy->walk.dead); |
256 | 256 | ||
257 | BUG_ON(policy->bundles); | 257 | BUG_ON(policy->bundles); |
258 | 258 | ||
259 | if (del_timer(&policy->timer)) | 259 | if (del_timer(&policy->timer)) |
260 | BUG(); | 260 | BUG(); |
261 | 261 | ||
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); | 262 | security_xfrm_policy_free(policy->security); |
267 | kfree(policy); | 263 | kfree(policy); |
268 | } | 264 | } |
@@ -310,8 +306,8 @@ static void xfrm_policy_kill(struct xfrm_policy *policy) | |||
310 | int dead; | 306 | int dead; |
311 | 307 | ||
312 | write_lock_bh(&policy->lock); | 308 | write_lock_bh(&policy->lock); |
313 | dead = policy->dead; | 309 | dead = policy->walk.dead; |
314 | policy->dead = 1; | 310 | policy->walk.dead = 1; |
315 | write_unlock_bh(&policy->lock); | 311 | write_unlock_bh(&policy->lock); |
316 | 312 | ||
317 | if (unlikely(dead)) { | 313 | if (unlikely(dead)) { |
@@ -319,9 +315,9 @@ static void xfrm_policy_kill(struct xfrm_policy *policy) | |||
319 | return; | 315 | return; |
320 | } | 316 | } |
321 | 317 | ||
322 | spin_lock(&xfrm_policy_gc_lock); | 318 | spin_lock_bh(&xfrm_policy_gc_lock); |
323 | hlist_add_head(&policy->bydst, &xfrm_policy_gc_list); | 319 | hlist_add_head(&policy->bydst, &xfrm_policy_gc_list); |
324 | spin_unlock(&xfrm_policy_gc_lock); | 320 | spin_unlock_bh(&xfrm_policy_gc_lock); |
325 | 321 | ||
326 | schedule_work(&xfrm_policy_gc_work); | 322 | schedule_work(&xfrm_policy_gc_work); |
327 | } | 323 | } |
@@ -609,6 +605,7 @@ int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl) | |||
609 | if (delpol) { | 605 | if (delpol) { |
610 | hlist_del(&delpol->bydst); | 606 | hlist_del(&delpol->bydst); |
611 | hlist_del(&delpol->byidx); | 607 | hlist_del(&delpol->byidx); |
608 | list_del(&delpol->walk.all); | ||
612 | xfrm_policy_count[dir]--; | 609 | xfrm_policy_count[dir]--; |
613 | } | 610 | } |
614 | policy->index = delpol ? delpol->index : xfrm_gen_index(policy->type, dir); | 611 | policy->index = delpol ? delpol->index : xfrm_gen_index(policy->type, dir); |
@@ -617,7 +614,7 @@ int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl) | |||
617 | policy->curlft.use_time = 0; | 614 | policy->curlft.use_time = 0; |
618 | if (!mod_timer(&policy->timer, jiffies + HZ)) | 615 | if (!mod_timer(&policy->timer, jiffies + HZ)) |
619 | xfrm_pol_hold(policy); | 616 | xfrm_pol_hold(policy); |
620 | list_add_tail(&policy->bytype, &xfrm_policy_bytype[policy->type]); | 617 | list_add(&policy->walk.all, &xfrm_policy_all); |
621 | write_unlock_bh(&xfrm_policy_lock); | 618 | write_unlock_bh(&xfrm_policy_lock); |
622 | 619 | ||
623 | if (delpol) | 620 | if (delpol) |
@@ -684,6 +681,7 @@ struct xfrm_policy *xfrm_policy_bysel_ctx(u8 type, int dir, | |||
684 | } | 681 | } |
685 | hlist_del(&pol->bydst); | 682 | hlist_del(&pol->bydst); |
686 | hlist_del(&pol->byidx); | 683 | hlist_del(&pol->byidx); |
684 | list_del(&pol->walk.all); | ||
687 | xfrm_policy_count[dir]--; | 685 | xfrm_policy_count[dir]--; |
688 | } | 686 | } |
689 | ret = pol; | 687 | ret = pol; |
@@ -727,6 +725,7 @@ struct xfrm_policy *xfrm_policy_byid(u8 type, int dir, u32 id, int delete, | |||
727 | } | 725 | } |
728 | hlist_del(&pol->bydst); | 726 | hlist_del(&pol->bydst); |
729 | hlist_del(&pol->byidx); | 727 | hlist_del(&pol->byidx); |
728 | list_del(&pol->walk.all); | ||
730 | xfrm_policy_count[dir]--; | 729 | xfrm_policy_count[dir]--; |
731 | } | 730 | } |
732 | ret = pol; | 731 | ret = pol; |
@@ -818,6 +817,7 @@ int xfrm_policy_flush(u8 type, struct xfrm_audit *audit_info) | |||
818 | continue; | 817 | continue; |
819 | hlist_del(&pol->bydst); | 818 | hlist_del(&pol->bydst); |
820 | hlist_del(&pol->byidx); | 819 | hlist_del(&pol->byidx); |
820 | list_del(&pol->walk.all); | ||
821 | write_unlock_bh(&xfrm_policy_lock); | 821 | write_unlock_bh(&xfrm_policy_lock); |
822 | 822 | ||
823 | xfrm_audit_policy_delete(pol, 1, audit_info->loginuid, | 823 | xfrm_audit_policy_delete(pol, 1, audit_info->loginuid, |
@@ -840,6 +840,7 @@ int xfrm_policy_flush(u8 type, struct xfrm_audit *audit_info) | |||
840 | continue; | 840 | continue; |
841 | hlist_del(&pol->bydst); | 841 | hlist_del(&pol->bydst); |
842 | hlist_del(&pol->byidx); | 842 | hlist_del(&pol->byidx); |
843 | list_del(&pol->walk.all); | ||
843 | write_unlock_bh(&xfrm_policy_lock); | 844 | write_unlock_bh(&xfrm_policy_lock); |
844 | 845 | ||
845 | xfrm_audit_policy_delete(pol, 1, | 846 | xfrm_audit_policy_delete(pol, 1, |
@@ -867,60 +868,68 @@ int xfrm_policy_walk(struct xfrm_policy_walk *walk, | |||
867 | int (*func)(struct xfrm_policy *, int, int, void*), | 868 | int (*func)(struct xfrm_policy *, int, int, void*), |
868 | void *data) | 869 | void *data) |
869 | { | 870 | { |
870 | struct xfrm_policy *old, *pol, *last = NULL; | 871 | struct xfrm_policy *pol; |
872 | struct xfrm_policy_walk_entry *x; | ||
871 | int error = 0; | 873 | int error = 0; |
872 | 874 | ||
873 | if (walk->type >= XFRM_POLICY_TYPE_MAX && | 875 | if (walk->type >= XFRM_POLICY_TYPE_MAX && |
874 | walk->type != XFRM_POLICY_TYPE_ANY) | 876 | walk->type != XFRM_POLICY_TYPE_ANY) |
875 | return -EINVAL; | 877 | return -EINVAL; |
876 | 878 | ||
877 | if (walk->policy == NULL && walk->count != 0) | 879 | if (list_empty(&walk->walk.all) && walk->seq != 0) |
878 | return 0; | 880 | return 0; |
879 | 881 | ||
880 | old = pol = walk->policy; | 882 | write_lock_bh(&xfrm_policy_lock); |
881 | walk->policy = NULL; | 883 | if (list_empty(&walk->walk.all)) |
882 | read_lock_bh(&xfrm_policy_lock); | 884 | x = list_first_entry(&xfrm_policy_all, struct xfrm_policy_walk_entry, all); |
883 | 885 | else | |
884 | for (; walk->cur_type < XFRM_POLICY_TYPE_MAX; walk->cur_type++) { | 886 | x = list_entry(&walk->walk.all, struct xfrm_policy_walk_entry, all); |
885 | if (walk->type != walk->cur_type && | 887 | list_for_each_entry_from(x, &xfrm_policy_all, all) { |
886 | walk->type != XFRM_POLICY_TYPE_ANY) | 888 | if (x->dead) |
887 | continue; | 889 | continue; |
888 | 890 | pol = container_of(x, struct xfrm_policy, walk); | |
889 | if (pol == NULL) { | 891 | if (walk->type != XFRM_POLICY_TYPE_ANY && |
890 | pol = list_first_entry(&xfrm_policy_bytype[walk->cur_type], | 892 | walk->type != pol->type) |
891 | struct xfrm_policy, bytype); | 893 | continue; |
892 | } | 894 | error = func(pol, xfrm_policy_id2dir(pol->index), |
893 | list_for_each_entry_from(pol, &xfrm_policy_bytype[walk->cur_type], bytype) { | 895 | walk->seq, data); |
894 | if (pol->dead) | 896 | if (error) { |
895 | continue; | 897 | list_move_tail(&walk->walk.all, &x->all); |
896 | if (last) { | 898 | goto out; |
897 | error = func(last, xfrm_policy_id2dir(last->index), | ||
898 | walk->count, data); | ||
899 | if (error) { | ||
900 | xfrm_pol_hold(last); | ||
901 | walk->policy = last; | ||
902 | goto out; | ||
903 | } | ||
904 | } | ||
905 | last = pol; | ||
906 | walk->count++; | ||
907 | } | 899 | } |
908 | pol = NULL; | 900 | walk->seq++; |
909 | } | 901 | } |
910 | if (walk->count == 0) { | 902 | if (walk->seq == 0) { |
911 | error = -ENOENT; | 903 | error = -ENOENT; |
912 | goto out; | 904 | goto out; |
913 | } | 905 | } |
914 | if (last) | 906 | list_del_init(&walk->walk.all); |
915 | error = func(last, xfrm_policy_id2dir(last->index), 0, data); | ||
916 | out: | 907 | out: |
917 | read_unlock_bh(&xfrm_policy_lock); | 908 | write_unlock_bh(&xfrm_policy_lock); |
918 | if (old != NULL) | ||
919 | xfrm_pol_put(old); | ||
920 | return error; | 909 | return error; |
921 | } | 910 | } |
922 | EXPORT_SYMBOL(xfrm_policy_walk); | 911 | EXPORT_SYMBOL(xfrm_policy_walk); |
923 | 912 | ||
913 | void xfrm_policy_walk_init(struct xfrm_policy_walk *walk, u8 type) | ||
914 | { | ||
915 | INIT_LIST_HEAD(&walk->walk.all); | ||
916 | walk->walk.dead = 1; | ||
917 | walk->type = type; | ||
918 | walk->seq = 0; | ||
919 | } | ||
920 | EXPORT_SYMBOL(xfrm_policy_walk_init); | ||
921 | |||
922 | void xfrm_policy_walk_done(struct xfrm_policy_walk *walk) | ||
923 | { | ||
924 | if (list_empty(&walk->walk.all)) | ||
925 | return; | ||
926 | |||
927 | write_lock_bh(&xfrm_policy_lock); | ||
928 | list_del(&walk->walk.all); | ||
929 | write_unlock_bh(&xfrm_policy_lock); | ||
930 | } | ||
931 | EXPORT_SYMBOL(xfrm_policy_walk_done); | ||
932 | |||
924 | /* | 933 | /* |
925 | * Find policy to apply to this flow. | 934 | * Find policy to apply to this flow. |
926 | * | 935 | * |
@@ -1077,7 +1086,7 @@ static void __xfrm_policy_link(struct xfrm_policy *pol, int dir) | |||
1077 | struct hlist_head *chain = policy_hash_bysel(&pol->selector, | 1086 | struct hlist_head *chain = policy_hash_bysel(&pol->selector, |
1078 | pol->family, dir); | 1087 | pol->family, dir); |
1079 | 1088 | ||
1080 | list_add_tail(&pol->bytype, &xfrm_policy_bytype[pol->type]); | 1089 | list_add(&pol->walk.all, &xfrm_policy_all); |
1081 | hlist_add_head(&pol->bydst, chain); | 1090 | hlist_add_head(&pol->bydst, chain); |
1082 | hlist_add_head(&pol->byidx, xfrm_policy_byidx+idx_hash(pol->index)); | 1091 | hlist_add_head(&pol->byidx, xfrm_policy_byidx+idx_hash(pol->index)); |
1083 | xfrm_policy_count[dir]++; | 1092 | xfrm_policy_count[dir]++; |
@@ -1095,6 +1104,7 @@ static struct xfrm_policy *__xfrm_policy_unlink(struct xfrm_policy *pol, | |||
1095 | 1104 | ||
1096 | hlist_del(&pol->bydst); | 1105 | hlist_del(&pol->bydst); |
1097 | hlist_del(&pol->byidx); | 1106 | hlist_del(&pol->byidx); |
1107 | list_del(&pol->walk.all); | ||
1098 | xfrm_policy_count[dir]--; | 1108 | xfrm_policy_count[dir]--; |
1099 | 1109 | ||
1100 | return pol; | 1110 | return pol; |
@@ -1242,6 +1252,8 @@ xfrm_tmpl_resolve_one(struct xfrm_policy *policy, struct flowi *fl, | |||
1242 | -EINVAL : -EAGAIN); | 1252 | -EINVAL : -EAGAIN); |
1243 | xfrm_state_put(x); | 1253 | xfrm_state_put(x); |
1244 | } | 1254 | } |
1255 | else if (error == -ESRCH) | ||
1256 | error = -EAGAIN; | ||
1245 | 1257 | ||
1246 | if (!tmpl->optional) | 1258 | if (!tmpl->optional) |
1247 | goto fail; | 1259 | goto fail; |
@@ -1720,7 +1732,7 @@ restart: | |||
1720 | 1732 | ||
1721 | for (pi = 0; pi < npols; pi++) { | 1733 | for (pi = 0; pi < npols; pi++) { |
1722 | read_lock_bh(&pols[pi]->lock); | 1734 | read_lock_bh(&pols[pi]->lock); |
1723 | pol_dead |= pols[pi]->dead; | 1735 | pol_dead |= pols[pi]->walk.dead; |
1724 | read_unlock_bh(&pols[pi]->lock); | 1736 | read_unlock_bh(&pols[pi]->lock); |
1725 | } | 1737 | } |
1726 | 1738 | ||
@@ -2415,9 +2427,7 @@ static void __init xfrm_policy_init(void) | |||
2415 | panic("XFRM: failed to allocate bydst hash\n"); | 2427 | panic("XFRM: failed to allocate bydst hash\n"); |
2416 | } | 2428 | } |
2417 | 2429 | ||
2418 | for (dir = 0; dir < XFRM_POLICY_TYPE_MAX; dir++) | 2430 | INIT_LIST_HEAD(&xfrm_policy_all); |
2419 | INIT_LIST_HEAD(&xfrm_policy_bytype[dir]); | ||
2420 | |||
2421 | INIT_WORK(&xfrm_policy_gc_work, xfrm_policy_gc_task); | 2431 | INIT_WORK(&xfrm_policy_gc_work, xfrm_policy_gc_task); |
2422 | register_netdevice_notifier(&xfrm_dev_notifier); | 2432 | register_netdevice_notifier(&xfrm_dev_notifier); |
2423 | } | 2433 | } |
@@ -2601,7 +2611,7 @@ static int xfrm_policy_migrate(struct xfrm_policy *pol, | |||
2601 | int i, j, n = 0; | 2611 | int i, j, n = 0; |
2602 | 2612 | ||
2603 | write_lock_bh(&pol->lock); | 2613 | write_lock_bh(&pol->lock); |
2604 | if (unlikely(pol->dead)) { | 2614 | if (unlikely(pol->walk.dead)) { |
2605 | /* target policy has been deleted */ | 2615 | /* target policy has been deleted */ |
2606 | write_unlock_bh(&pol->lock); | 2616 | write_unlock_bh(&pol->lock); |
2607 | return -ENOENT; | 2617 | return -ENOENT; |
@@ -2672,7 +2682,8 @@ static int xfrm_migrate_check(struct xfrm_migrate *m, int num_migrate) | |||
2672 | } | 2682 | } |
2673 | 2683 | ||
2674 | int xfrm_migrate(struct xfrm_selector *sel, u8 dir, u8 type, | 2684 | int xfrm_migrate(struct xfrm_selector *sel, u8 dir, u8 type, |
2675 | struct xfrm_migrate *m, int num_migrate) | 2685 | struct xfrm_migrate *m, int num_migrate, |
2686 | struct xfrm_kmaddress *k) | ||
2676 | { | 2687 | { |
2677 | int i, err, nx_cur = 0, nx_new = 0; | 2688 | int i, err, nx_cur = 0, nx_new = 0; |
2678 | struct xfrm_policy *pol = NULL; | 2689 | struct xfrm_policy *pol = NULL; |
@@ -2716,7 +2727,7 @@ int xfrm_migrate(struct xfrm_selector *sel, u8 dir, u8 type, | |||
2716 | } | 2727 | } |
2717 | 2728 | ||
2718 | /* Stage 5 - announce */ | 2729 | /* Stage 5 - announce */ |
2719 | km_migrate(sel, dir, type, m, num_migrate); | 2730 | km_migrate(sel, dir, type, m, num_migrate, k); |
2720 | 2731 | ||
2721 | xfrm_pol_put(pol); | 2732 | xfrm_pol_put(pol); |
2722 | 2733 | ||
diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c index 0a8f09c3144c..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) |
@@ -858,7 +854,7 @@ xfrm_state_find(xfrm_address_t *daddr, xfrm_address_t *saddr, | |||
858 | 854 | ||
859 | if (km_query(x, tmpl, pol) == 0) { | 855 | if (km_query(x, tmpl, pol) == 0) { |
860 | x->km.state = XFRM_STATE_ACQ; | 856 | x->km.state = XFRM_STATE_ACQ; |
861 | list_add_tail(&x->all, &xfrm_state_all); | 857 | list_add(&x->km.all, &xfrm_state_all); |
862 | hlist_add_head(&x->bydst, xfrm_state_bydst+h); | 858 | hlist_add_head(&x->bydst, xfrm_state_bydst+h); |
863 | h = xfrm_src_hash(daddr, saddr, family); | 859 | h = xfrm_src_hash(daddr, saddr, family); |
864 | hlist_add_head(&x->bysrc, xfrm_state_bysrc+h); | 860 | hlist_add_head(&x->bysrc, xfrm_state_bysrc+h); |
@@ -927,7 +923,7 @@ static void __xfrm_state_insert(struct xfrm_state *x) | |||
927 | 923 | ||
928 | x->genid = ++xfrm_state_genid; | 924 | x->genid = ++xfrm_state_genid; |
929 | 925 | ||
930 | list_add_tail(&x->all, &xfrm_state_all); | 926 | list_add(&x->km.all, &xfrm_state_all); |
931 | 927 | ||
932 | h = xfrm_dst_hash(&x->id.daddr, &x->props.saddr, | 928 | h = xfrm_dst_hash(&x->id.daddr, &x->props.saddr, |
933 | x->props.reqid, x->props.family); | 929 | x->props.reqid, x->props.family); |
@@ -1056,7 +1052,7 @@ static struct xfrm_state *__find_acq_core(unsigned short family, u8 mode, u32 re | |||
1056 | xfrm_state_hold(x); | 1052 | xfrm_state_hold(x); |
1057 | x->timer.expires = jiffies + sysctl_xfrm_acq_expires*HZ; | 1053 | x->timer.expires = jiffies + sysctl_xfrm_acq_expires*HZ; |
1058 | add_timer(&x->timer); | 1054 | add_timer(&x->timer); |
1059 | list_add_tail(&x->all, &xfrm_state_all); | 1055 | list_add(&x->km.all, &xfrm_state_all); |
1060 | hlist_add_head(&x->bydst, xfrm_state_bydst+h); | 1056 | hlist_add_head(&x->bydst, xfrm_state_bydst+h); |
1061 | h = xfrm_src_hash(daddr, saddr, family); | 1057 | h = xfrm_src_hash(daddr, saddr, family); |
1062 | hlist_add_head(&x->bysrc, xfrm_state_bysrc+h); | 1058 | hlist_add_head(&x->bysrc, xfrm_state_bysrc+h); |
@@ -1553,47 +1549,62 @@ int xfrm_state_walk(struct xfrm_state_walk *walk, | |||
1553 | int (*func)(struct xfrm_state *, int, void*), | 1549 | int (*func)(struct xfrm_state *, int, void*), |
1554 | void *data) | 1550 | void *data) |
1555 | { | 1551 | { |
1556 | struct xfrm_state *old, *x, *last = NULL; | 1552 | struct xfrm_state *state; |
1553 | struct xfrm_state_walk *x; | ||
1557 | int err = 0; | 1554 | int err = 0; |
1558 | 1555 | ||
1559 | if (walk->state == NULL && walk->count != 0) | 1556 | if (walk->seq != 0 && list_empty(&walk->all)) |
1560 | return 0; | 1557 | return 0; |
1561 | 1558 | ||
1562 | old = x = walk->state; | ||
1563 | walk->state = NULL; | ||
1564 | spin_lock_bh(&xfrm_state_lock); | 1559 | spin_lock_bh(&xfrm_state_lock); |
1565 | if (x == NULL) | 1560 | if (list_empty(&walk->all)) |
1566 | 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); | ||
1567 | list_for_each_entry_from(x, &xfrm_state_all, all) { | 1564 | list_for_each_entry_from(x, &xfrm_state_all, all) { |
1568 | if (x->km.state == XFRM_STATE_DEAD) | 1565 | if (x->state == XFRM_STATE_DEAD) |
1569 | continue; | 1566 | continue; |
1570 | 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)) | ||
1571 | continue; | 1569 | continue; |
1572 | if (last) { | 1570 | err = func(state, walk->seq, data); |
1573 | err = func(last, walk->count, data); | 1571 | if (err) { |
1574 | if (err) { | 1572 | list_move_tail(&walk->all, &x->all); |
1575 | xfrm_state_hold(last); | 1573 | goto out; |
1576 | walk->state = last; | ||
1577 | goto out; | ||
1578 | } | ||
1579 | } | 1574 | } |
1580 | last = x; | 1575 | walk->seq++; |
1581 | walk->count++; | ||
1582 | } | 1576 | } |
1583 | if (walk->count == 0) { | 1577 | if (walk->seq == 0) { |
1584 | err = -ENOENT; | 1578 | err = -ENOENT; |
1585 | goto out; | 1579 | goto out; |
1586 | } | 1580 | } |
1587 | if (last) | 1581 | list_del_init(&walk->all); |
1588 | err = func(last, 0, data); | ||
1589 | out: | 1582 | out: |
1590 | spin_unlock_bh(&xfrm_state_lock); | 1583 | spin_unlock_bh(&xfrm_state_lock); |
1591 | if (old != NULL) | ||
1592 | xfrm_state_put(old); | ||
1593 | return err; | 1584 | return err; |
1594 | } | 1585 | } |
1595 | EXPORT_SYMBOL(xfrm_state_walk); | 1586 | EXPORT_SYMBOL(xfrm_state_walk); |
1596 | 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 | |||
1597 | 1608 | ||
1598 | void xfrm_replay_notify(struct xfrm_state *x, int event) | 1609 | void xfrm_replay_notify(struct xfrm_state *x, int event) |
1599 | { | 1610 | { |
@@ -1803,7 +1814,8 @@ EXPORT_SYMBOL(km_policy_expired); | |||
1803 | 1814 | ||
1804 | #ifdef CONFIG_XFRM_MIGRATE | 1815 | #ifdef CONFIG_XFRM_MIGRATE |
1805 | int km_migrate(struct xfrm_selector *sel, u8 dir, u8 type, | 1816 | int km_migrate(struct xfrm_selector *sel, u8 dir, u8 type, |
1806 | struct xfrm_migrate *m, int num_migrate) | 1817 | struct xfrm_migrate *m, int num_migrate, |
1818 | struct xfrm_kmaddress *k) | ||
1807 | { | 1819 | { |
1808 | int err = -EINVAL; | 1820 | int err = -EINVAL; |
1809 | int ret; | 1821 | int ret; |
@@ -1812,7 +1824,7 @@ int km_migrate(struct xfrm_selector *sel, u8 dir, u8 type, | |||
1812 | read_lock(&xfrm_km_lock); | 1824 | read_lock(&xfrm_km_lock); |
1813 | list_for_each_entry(km, &xfrm_km_list, list) { | 1825 | list_for_each_entry(km, &xfrm_km_list, list) { |
1814 | if (km->migrate) { | 1826 | if (km->migrate) { |
1815 | ret = km->migrate(sel, dir, type, m, num_migrate); | 1827 | ret = km->migrate(sel, dir, type, m, num_migrate, k); |
1816 | if (!ret) | 1828 | if (!ret) |
1817 | err = ret; | 1829 | err = ret; |
1818 | } | 1830 | } |
diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c index 04c41504f84c..a278a6f3b991 100644 --- a/net/xfrm/xfrm_user.c +++ b/net/xfrm/xfrm_user.c | |||
@@ -1102,7 +1102,7 @@ static struct xfrm_policy *xfrm_policy_construct(struct xfrm_userpolicy_info *p, | |||
1102 | return xp; | 1102 | return xp; |
1103 | error: | 1103 | error: |
1104 | *errp = err; | 1104 | *errp = err; |
1105 | xp->dead = 1; | 1105 | xp->walk.dead = 1; |
1106 | xfrm_policy_destroy(xp); | 1106 | xfrm_policy_destroy(xp); |
1107 | return NULL; | 1107 | return NULL; |
1108 | } | 1108 | } |
@@ -1595,7 +1595,7 @@ static int xfrm_add_pol_expire(struct sk_buff *skb, struct nlmsghdr *nlh, | |||
1595 | return -ENOENT; | 1595 | return -ENOENT; |
1596 | 1596 | ||
1597 | read_lock(&xp->lock); | 1597 | read_lock(&xp->lock); |
1598 | if (xp->dead) { | 1598 | if (xp->walk.dead) { |
1599 | read_unlock(&xp->lock); | 1599 | read_unlock(&xp->lock); |
1600 | goto out; | 1600 | goto out; |
1601 | } | 1601 | } |
@@ -1710,12 +1710,23 @@ static int xfrm_add_acquire(struct sk_buff *skb, struct nlmsghdr *nlh, | |||
1710 | 1710 | ||
1711 | #ifdef CONFIG_XFRM_MIGRATE | 1711 | #ifdef CONFIG_XFRM_MIGRATE |
1712 | static int copy_from_user_migrate(struct xfrm_migrate *ma, | 1712 | static int copy_from_user_migrate(struct xfrm_migrate *ma, |
1713 | struct xfrm_kmaddress *k, | ||
1713 | struct nlattr **attrs, int *num) | 1714 | struct nlattr **attrs, int *num) |
1714 | { | 1715 | { |
1715 | struct nlattr *rt = attrs[XFRMA_MIGRATE]; | 1716 | struct nlattr *rt = attrs[XFRMA_MIGRATE]; |
1716 | struct xfrm_user_migrate *um; | 1717 | struct xfrm_user_migrate *um; |
1717 | int i, num_migrate; | 1718 | int i, num_migrate; |
1718 | 1719 | ||
1720 | if (k != NULL) { | ||
1721 | struct xfrm_user_kmaddress *uk; | ||
1722 | |||
1723 | uk = nla_data(attrs[XFRMA_KMADDRESS]); | ||
1724 | memcpy(&k->local, &uk->local, sizeof(k->local)); | ||
1725 | memcpy(&k->remote, &uk->remote, sizeof(k->remote)); | ||
1726 | k->family = uk->family; | ||
1727 | k->reserved = uk->reserved; | ||
1728 | } | ||
1729 | |||
1719 | um = nla_data(rt); | 1730 | um = nla_data(rt); |
1720 | num_migrate = nla_len(rt) / sizeof(*um); | 1731 | num_migrate = nla_len(rt) / sizeof(*um); |
1721 | 1732 | ||
@@ -1745,6 +1756,7 @@ static int xfrm_do_migrate(struct sk_buff *skb, struct nlmsghdr *nlh, | |||
1745 | { | 1756 | { |
1746 | struct xfrm_userpolicy_id *pi = nlmsg_data(nlh); | 1757 | struct xfrm_userpolicy_id *pi = nlmsg_data(nlh); |
1747 | struct xfrm_migrate m[XFRM_MAX_DEPTH]; | 1758 | struct xfrm_migrate m[XFRM_MAX_DEPTH]; |
1759 | struct xfrm_kmaddress km, *kmp; | ||
1748 | u8 type; | 1760 | u8 type; |
1749 | int err; | 1761 | int err; |
1750 | int n = 0; | 1762 | int n = 0; |
@@ -1752,19 +1764,20 @@ static int xfrm_do_migrate(struct sk_buff *skb, struct nlmsghdr *nlh, | |||
1752 | if (attrs[XFRMA_MIGRATE] == NULL) | 1764 | if (attrs[XFRMA_MIGRATE] == NULL) |
1753 | return -EINVAL; | 1765 | return -EINVAL; |
1754 | 1766 | ||
1767 | kmp = attrs[XFRMA_KMADDRESS] ? &km : NULL; | ||
1768 | |||
1755 | err = copy_from_user_policy_type(&type, attrs); | 1769 | err = copy_from_user_policy_type(&type, attrs); |
1756 | if (err) | 1770 | if (err) |
1757 | return err; | 1771 | return err; |
1758 | 1772 | ||
1759 | err = copy_from_user_migrate((struct xfrm_migrate *)m, | 1773 | err = copy_from_user_migrate((struct xfrm_migrate *)m, kmp, attrs, &n); |
1760 | attrs, &n); | ||
1761 | if (err) | 1774 | if (err) |
1762 | return err; | 1775 | return err; |
1763 | 1776 | ||
1764 | if (!n) | 1777 | if (!n) |
1765 | return 0; | 1778 | return 0; |
1766 | 1779 | ||
1767 | xfrm_migrate(&pi->sel, pi->dir, type, m, n); | 1780 | xfrm_migrate(&pi->sel, pi->dir, type, m, n, kmp); |
1768 | 1781 | ||
1769 | return 0; | 1782 | return 0; |
1770 | } | 1783 | } |
@@ -1795,16 +1808,30 @@ static int copy_to_user_migrate(struct xfrm_migrate *m, struct sk_buff *skb) | |||
1795 | return nla_put(skb, XFRMA_MIGRATE, sizeof(um), &um); | 1808 | return nla_put(skb, XFRMA_MIGRATE, sizeof(um), &um); |
1796 | } | 1809 | } |
1797 | 1810 | ||
1798 | static inline size_t xfrm_migrate_msgsize(int num_migrate) | 1811 | static int copy_to_user_kmaddress(struct xfrm_kmaddress *k, struct sk_buff *skb) |
1812 | { | ||
1813 | struct xfrm_user_kmaddress uk; | ||
1814 | |||
1815 | memset(&uk, 0, sizeof(uk)); | ||
1816 | uk.family = k->family; | ||
1817 | uk.reserved = k->reserved; | ||
1818 | memcpy(&uk.local, &k->local, sizeof(uk.local)); | ||
1819 | memcpy(&uk.remote, &k->remote, sizeof(uk.remote)); | ||
1820 | |||
1821 | return nla_put(skb, XFRMA_KMADDRESS, sizeof(uk), &uk); | ||
1822 | } | ||
1823 | |||
1824 | static inline size_t xfrm_migrate_msgsize(int num_migrate, int with_kma) | ||
1799 | { | 1825 | { |
1800 | return NLMSG_ALIGN(sizeof(struct xfrm_userpolicy_id)) | 1826 | return NLMSG_ALIGN(sizeof(struct xfrm_userpolicy_id)) |
1801 | + nla_total_size(sizeof(struct xfrm_user_migrate) * num_migrate) | 1827 | + (with_kma ? nla_total_size(sizeof(struct xfrm_kmaddress)) : 0) |
1802 | + userpolicy_type_attrsize(); | 1828 | + nla_total_size(sizeof(struct xfrm_user_migrate) * num_migrate) |
1829 | + userpolicy_type_attrsize(); | ||
1803 | } | 1830 | } |
1804 | 1831 | ||
1805 | static int build_migrate(struct sk_buff *skb, struct xfrm_migrate *m, | 1832 | static int build_migrate(struct sk_buff *skb, struct xfrm_migrate *m, |
1806 | int num_migrate, struct xfrm_selector *sel, | 1833 | int num_migrate, struct xfrm_kmaddress *k, |
1807 | u8 dir, u8 type) | 1834 | struct xfrm_selector *sel, u8 dir, u8 type) |
1808 | { | 1835 | { |
1809 | struct xfrm_migrate *mp; | 1836 | struct xfrm_migrate *mp; |
1810 | struct xfrm_userpolicy_id *pol_id; | 1837 | struct xfrm_userpolicy_id *pol_id; |
@@ -1821,6 +1848,9 @@ static int build_migrate(struct sk_buff *skb, struct xfrm_migrate *m, | |||
1821 | memcpy(&pol_id->sel, sel, sizeof(pol_id->sel)); | 1848 | memcpy(&pol_id->sel, sel, sizeof(pol_id->sel)); |
1822 | pol_id->dir = dir; | 1849 | pol_id->dir = dir; |
1823 | 1850 | ||
1851 | if (k != NULL && (copy_to_user_kmaddress(k, skb) < 0)) | ||
1852 | goto nlmsg_failure; | ||
1853 | |||
1824 | if (copy_to_user_policy_type(type, skb) < 0) | 1854 | if (copy_to_user_policy_type(type, skb) < 0) |
1825 | goto nlmsg_failure; | 1855 | goto nlmsg_failure; |
1826 | 1856 | ||
@@ -1836,23 +1866,25 @@ nlmsg_failure: | |||
1836 | } | 1866 | } |
1837 | 1867 | ||
1838 | static int xfrm_send_migrate(struct xfrm_selector *sel, u8 dir, u8 type, | 1868 | static int xfrm_send_migrate(struct xfrm_selector *sel, u8 dir, u8 type, |
1839 | struct xfrm_migrate *m, int num_migrate) | 1869 | struct xfrm_migrate *m, int num_migrate, |
1870 | struct xfrm_kmaddress *k) | ||
1840 | { | 1871 | { |
1841 | struct sk_buff *skb; | 1872 | struct sk_buff *skb; |
1842 | 1873 | ||
1843 | skb = nlmsg_new(xfrm_migrate_msgsize(num_migrate), GFP_ATOMIC); | 1874 | skb = nlmsg_new(xfrm_migrate_msgsize(num_migrate, !!k), GFP_ATOMIC); |
1844 | if (skb == NULL) | 1875 | if (skb == NULL) |
1845 | return -ENOMEM; | 1876 | return -ENOMEM; |
1846 | 1877 | ||
1847 | /* build migrate */ | 1878 | /* build migrate */ |
1848 | if (build_migrate(skb, m, num_migrate, sel, dir, type) < 0) | 1879 | if (build_migrate(skb, m, num_migrate, k, sel, dir, type) < 0) |
1849 | BUG(); | 1880 | BUG(); |
1850 | 1881 | ||
1851 | return nlmsg_multicast(xfrm_nl, skb, 0, XFRMNLGRP_MIGRATE, GFP_ATOMIC); | 1882 | return nlmsg_multicast(xfrm_nl, skb, 0, XFRMNLGRP_MIGRATE, GFP_ATOMIC); |
1852 | } | 1883 | } |
1853 | #else | 1884 | #else |
1854 | static int xfrm_send_migrate(struct xfrm_selector *sel, u8 dir, u8 type, | 1885 | static int xfrm_send_migrate(struct xfrm_selector *sel, u8 dir, u8 type, |
1855 | struct xfrm_migrate *m, int num_migrate) | 1886 | struct xfrm_migrate *m, int num_migrate, |
1887 | struct xfrm_kmaddress *k) | ||
1856 | { | 1888 | { |
1857 | return -ENOPROTOOPT; | 1889 | return -ENOPROTOOPT; |
1858 | } | 1890 | } |
@@ -1901,6 +1933,7 @@ static const struct nla_policy xfrma_policy[XFRMA_MAX+1] = { | |||
1901 | [XFRMA_COADDR] = { .len = sizeof(xfrm_address_t) }, | 1933 | [XFRMA_COADDR] = { .len = sizeof(xfrm_address_t) }, |
1902 | [XFRMA_POLICY_TYPE] = { .len = sizeof(struct xfrm_userpolicy_type)}, | 1934 | [XFRMA_POLICY_TYPE] = { .len = sizeof(struct xfrm_userpolicy_type)}, |
1903 | [XFRMA_MIGRATE] = { .len = sizeof(struct xfrm_user_migrate) }, | 1935 | [XFRMA_MIGRATE] = { .len = sizeof(struct xfrm_user_migrate) }, |
1936 | [XFRMA_KMADDRESS] = { .len = sizeof(struct xfrm_user_kmaddress) }, | ||
1904 | }; | 1937 | }; |
1905 | 1938 | ||
1906 | static struct xfrm_link { | 1939 | static struct xfrm_link { |