aboutsummaryrefslogtreecommitdiffstats
path: root/net/xfrm/xfrm_policy.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/xfrm/xfrm_policy.c')
-rw-r--r--net/xfrm/xfrm_policy.c111
1 files changed, 59 insertions, 52 deletions
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
index ef9ccbc38752..b7ec08025ffb 100644
--- a/net/xfrm/xfrm_policy.c
+++ b/net/xfrm/xfrm_policy.c
@@ -46,7 +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]; 49static struct list_head xfrm_policy_all;
50unsigned int xfrm_policy_count[XFRM_POLICY_MAX*2]; 50unsigned int xfrm_policy_count[XFRM_POLICY_MAX*2];
51EXPORT_SYMBOL(xfrm_policy_count); 51EXPORT_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
253void xfrm_policy_destroy(struct xfrm_policy *policy) 253void 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)) {
@@ -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;
@@ -840,6 +839,7 @@ int xfrm_policy_flush(u8 type, struct xfrm_audit *audit_info)
840 continue; 839 continue;
841 hlist_del(&pol->bydst); 840 hlist_del(&pol->bydst);
842 hlist_del(&pol->byidx); 841 hlist_del(&pol->byidx);
842 list_del(&pol->walk.all);
843 write_unlock_bh(&xfrm_policy_lock); 843 write_unlock_bh(&xfrm_policy_lock);
844 844
845 xfrm_audit_policy_delete(pol, 1, 845 xfrm_audit_policy_delete(pol, 1,
@@ -867,60 +867,68 @@ int xfrm_policy_walk(struct xfrm_policy_walk *walk,
867 int (*func)(struct xfrm_policy *, int, int, void*), 867 int (*func)(struct xfrm_policy *, int, int, void*),
868 void *data) 868 void *data)
869{ 869{
870 struct xfrm_policy *old, *pol, *last = NULL; 870 struct xfrm_policy *pol;
871 struct xfrm_policy_walk_entry *x;
871 int error = 0; 872 int error = 0;
872 873
873 if (walk->type >= XFRM_POLICY_TYPE_MAX && 874 if (walk->type >= XFRM_POLICY_TYPE_MAX &&
874 walk->type != XFRM_POLICY_TYPE_ANY) 875 walk->type != XFRM_POLICY_TYPE_ANY)
875 return -EINVAL; 876 return -EINVAL;
876 877
877 if (walk->policy == NULL && walk->count != 0) 878 if (list_empty(&walk->walk.all) && walk->seq != 0)
878 return 0; 879 return 0;
879 880
880 old = pol = walk->policy; 881 write_lock_bh(&xfrm_policy_lock);
881 walk->policy = NULL; 882 if (list_empty(&walk->walk.all))
882 read_lock_bh(&xfrm_policy_lock); 883 x = list_first_entry(&xfrm_policy_all, struct xfrm_policy_walk_entry, all);
883 884 else
884 for (; walk->cur_type < XFRM_POLICY_TYPE_MAX; walk->cur_type++) { 885 x = list_entry(&walk->walk.all, struct xfrm_policy_walk_entry, all);
885 if (walk->type != walk->cur_type && 886 list_for_each_entry_from(x, &xfrm_policy_all, all) {
886 walk->type != XFRM_POLICY_TYPE_ANY) 887 if (x->dead)
887 continue; 888 continue;
888 889 pol = container_of(x, struct xfrm_policy, walk);
889 if (pol == NULL) { 890 if (walk->type != XFRM_POLICY_TYPE_ANY &&
890 pol = list_first_entry(&xfrm_policy_bytype[walk->cur_type], 891 walk->type != pol->type)
891 struct xfrm_policy, bytype); 892 continue;
892 } 893 error = func(pol, xfrm_policy_id2dir(pol->index),
893 list_for_each_entry_from(pol, &xfrm_policy_bytype[walk->cur_type], bytype) { 894 walk->seq, data);
894 if (pol->dead) 895 if (error) {
895 continue; 896 list_move_tail(&walk->walk.all, &x->all);
896 if (last) { 897 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 } 898 }
908 pol = NULL; 899 walk->seq++;
909 } 900 }
910 if (walk->count == 0) { 901 if (walk->seq == 0) {
911 error = -ENOENT; 902 error = -ENOENT;
912 goto out; 903 goto out;
913 } 904 }
914 if (last) 905 list_del_init(&walk->walk.all);
915 error = func(last, xfrm_policy_id2dir(last->index), 0, data);
916out: 906out:
917 read_unlock_bh(&xfrm_policy_lock); 907 write_unlock_bh(&xfrm_policy_lock);
918 if (old != NULL)
919 xfrm_pol_put(old);
920 return error; 908 return error;
921} 909}
922EXPORT_SYMBOL(xfrm_policy_walk); 910EXPORT_SYMBOL(xfrm_policy_walk);
923 911
912void xfrm_policy_walk_init(struct xfrm_policy_walk *walk, u8 type)
913{
914 INIT_LIST_HEAD(&walk->walk.all);
915 walk->walk.dead = 1;
916 walk->type = type;
917 walk->seq = 0;
918}
919EXPORT_SYMBOL(xfrm_policy_walk_init);
920
921void xfrm_policy_walk_done(struct xfrm_policy_walk *walk)
922{
923 if (list_empty(&walk->walk.all))
924 return;
925
926 write_lock_bh(&xfrm_policy_lock);
927 list_del(&walk->walk.all);
928 write_unlock_bh(&xfrm_policy_lock);
929}
930EXPORT_SYMBOL(xfrm_policy_walk_done);
931
924/* 932/*
925 * Find policy to apply to this flow. 933 * Find policy to apply to this flow.
926 * 934 *
@@ -1077,7 +1085,7 @@ static void __xfrm_policy_link(struct xfrm_policy *pol, int dir)
1077 struct hlist_head *chain = policy_hash_bysel(&pol->selector, 1085 struct hlist_head *chain = policy_hash_bysel(&pol->selector,
1078 pol->family, dir); 1086 pol->family, dir);
1079 1087
1080 list_add_tail(&pol->bytype, &xfrm_policy_bytype[pol->type]); 1088 list_add(&pol->walk.all, &xfrm_policy_all);
1081 hlist_add_head(&pol->bydst, chain); 1089 hlist_add_head(&pol->bydst, chain);
1082 hlist_add_head(&pol->byidx, xfrm_policy_byidx+idx_hash(pol->index)); 1090 hlist_add_head(&pol->byidx, xfrm_policy_byidx+idx_hash(pol->index));
1083 xfrm_policy_count[dir]++; 1091 xfrm_policy_count[dir]++;
@@ -1095,6 +1103,7 @@ static struct xfrm_policy *__xfrm_policy_unlink(struct xfrm_policy *pol,
1095 1103
1096 hlist_del(&pol->bydst); 1104 hlist_del(&pol->bydst);
1097 hlist_del(&pol->byidx); 1105 hlist_del(&pol->byidx);
1106 list_del(&pol->walk.all);
1098 xfrm_policy_count[dir]--; 1107 xfrm_policy_count[dir]--;
1099 1108
1100 return pol; 1109 return pol;
@@ -1720,7 +1729,7 @@ restart:
1720 1729
1721 for (pi = 0; pi < npols; pi++) { 1730 for (pi = 0; pi < npols; pi++) {
1722 read_lock_bh(&pols[pi]->lock); 1731 read_lock_bh(&pols[pi]->lock);
1723 pol_dead |= pols[pi]->dead; 1732 pol_dead |= pols[pi]->walk.dead;
1724 read_unlock_bh(&pols[pi]->lock); 1733 read_unlock_bh(&pols[pi]->lock);
1725 } 1734 }
1726 1735
@@ -2415,9 +2424,7 @@ static void __init xfrm_policy_init(void)
2415 panic("XFRM: failed to allocate bydst hash\n"); 2424 panic("XFRM: failed to allocate bydst hash\n");
2416 } 2425 }
2417 2426
2418 for (dir = 0; dir < XFRM_POLICY_TYPE_MAX; dir++) 2427 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); 2428 INIT_WORK(&xfrm_policy_gc_work, xfrm_policy_gc_task);
2422 register_netdevice_notifier(&xfrm_dev_notifier); 2429 register_netdevice_notifier(&xfrm_dev_notifier);
2423} 2430}
@@ -2601,7 +2608,7 @@ static int xfrm_policy_migrate(struct xfrm_policy *pol,
2601 int i, j, n = 0; 2608 int i, j, n = 0;
2602 2609
2603 write_lock_bh(&pol->lock); 2610 write_lock_bh(&pol->lock);
2604 if (unlikely(pol->dead)) { 2611 if (unlikely(pol->walk.dead)) {
2605 /* target policy has been deleted */ 2612 /* target policy has been deleted */
2606 write_unlock_bh(&pol->lock); 2613 write_unlock_bh(&pol->lock);
2607 return -ENOENT; 2614 return -ENOENT;