aboutsummaryrefslogtreecommitdiffstats
path: root/net/xfrm/xfrm_policy.c
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2008-12-19 02:22:57 -0500
committerTakashi Iwai <tiwai@suse.de>2008-12-19 02:22:57 -0500
commit0ff555192a8d20385d49d1c420e2e8d409b3c0da (patch)
treeb6e4b6cae1028a310a3488ebf745954c51694bfc /net/xfrm/xfrm_policy.c
parent3218c178b41b420cb7e0d120c7a137a3969242e5 (diff)
parent9e43f0de690211cf7153b5f3ec251bc315647ada (diff)
Merge branch 'fix/hda' into topic/hda
Diffstat (limited to 'net/xfrm/xfrm_policy.c')
-rw-r--r--net/xfrm/xfrm_policy.c125
1 files changed, 68 insertions, 57 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
37int sysctl_xfrm_larval_drop __read_mostly; 37int sysctl_xfrm_larval_drop __read_mostly = 1;
38 38
39#ifdef CONFIG_XFRM_STATISTICS 39#ifdef CONFIG_XFRM_STATISTICS
40DEFINE_SNMP_STAT(struct linux_xfrm_mib, xfrm_statistics) __read_mostly; 40DEFINE_SNMP_STAT(struct linux_xfrm_mib, xfrm_statistics) __read_mostly;
@@ -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)) {
@@ -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);
916out: 907out:
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}
922EXPORT_SYMBOL(xfrm_policy_walk); 911EXPORT_SYMBOL(xfrm_policy_walk);
923 912
913void 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}
920EXPORT_SYMBOL(xfrm_policy_walk_init);
921
922void 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}
931EXPORT_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
2674int xfrm_migrate(struct xfrm_selector *sel, u8 dir, u8 type, 2684int 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