diff options
Diffstat (limited to 'net/xfrm/xfrm_policy.c')
-rw-r--r-- | net/xfrm/xfrm_policy.c | 79 |
1 files changed, 46 insertions, 33 deletions
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c index 9fc4c315f6cd..bae94a8031a2 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 | ||
@@ -208,6 +209,7 @@ struct xfrm_policy *xfrm_policy_alloc(gfp_t gfp) | |||
208 | policy = kzalloc(sizeof(struct xfrm_policy), gfp); | 209 | policy = kzalloc(sizeof(struct xfrm_policy), gfp); |
209 | 210 | ||
210 | if (policy) { | 211 | if (policy) { |
212 | INIT_LIST_HEAD(&policy->bytype); | ||
211 | INIT_HLIST_NODE(&policy->bydst); | 213 | INIT_HLIST_NODE(&policy->bydst); |
212 | INIT_HLIST_NODE(&policy->byidx); | 214 | INIT_HLIST_NODE(&policy->byidx); |
213 | rwlock_init(&policy->lock); | 215 | rwlock_init(&policy->lock); |
@@ -230,6 +232,10 @@ void xfrm_policy_destroy(struct xfrm_policy *policy) | |||
230 | if (del_timer(&policy->timer)) | 232 | if (del_timer(&policy->timer)) |
231 | BUG(); | 233 | BUG(); |
232 | 234 | ||
235 | write_lock_bh(&xfrm_policy_lock); | ||
236 | list_del(&policy->bytype); | ||
237 | write_unlock_bh(&xfrm_policy_lock); | ||
238 | |||
233 | security_xfrm_policy_free(policy); | 239 | security_xfrm_policy_free(policy); |
234 | kfree(policy); | 240 | kfree(policy); |
235 | } | 241 | } |
@@ -584,6 +590,7 @@ int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl) | |||
584 | policy->curlft.use_time = 0; | 590 | policy->curlft.use_time = 0; |
585 | if (!mod_timer(&policy->timer, jiffies + HZ)) | 591 | if (!mod_timer(&policy->timer, jiffies + HZ)) |
586 | xfrm_pol_hold(policy); | 592 | xfrm_pol_hold(policy); |
593 | list_add_tail(&policy->bytype, &xfrm_policy_bytype[policy->type]); | ||
587 | write_unlock_bh(&xfrm_policy_lock); | 594 | write_unlock_bh(&xfrm_policy_lock); |
588 | 595 | ||
589 | if (delpol) | 596 | if (delpol) |
@@ -822,57 +829,60 @@ out: | |||
822 | } | 829 | } |
823 | EXPORT_SYMBOL(xfrm_policy_flush); | 830 | EXPORT_SYMBOL(xfrm_policy_flush); |
824 | 831 | ||
825 | int xfrm_policy_walk(u8 type, int (*func)(struct xfrm_policy *, int, int, void*), | 832 | int xfrm_policy_walk(struct xfrm_policy_walk *walk, |
833 | int (*func)(struct xfrm_policy *, int, int, void*), | ||
826 | void *data) | 834 | void *data) |
827 | { | 835 | { |
828 | struct xfrm_policy *pol, *last = NULL; | 836 | struct xfrm_policy *old, *pol, *last = NULL; |
829 | struct hlist_node *entry; | 837 | int error = 0; |
830 | int dir, last_dir = 0, count, error; | 838 | |
839 | if (walk->type >= XFRM_POLICY_TYPE_MAX && | ||
840 | walk->type != XFRM_POLICY_TYPE_ANY) | ||
841 | return -EINVAL; | ||
831 | 842 | ||
843 | if (walk->policy == NULL && walk->count != 0) | ||
844 | return 0; | ||
845 | |||
846 | old = pol = walk->policy; | ||
847 | walk->policy = NULL; | ||
832 | read_lock_bh(&xfrm_policy_lock); | 848 | read_lock_bh(&xfrm_policy_lock); |
833 | count = 0; | ||
834 | 849 | ||
835 | for (dir = 0; dir < 2*XFRM_POLICY_MAX; dir++) { | 850 | for (; walk->cur_type < XFRM_POLICY_TYPE_MAX; walk->cur_type++) { |
836 | struct hlist_head *table = xfrm_policy_bydst[dir].table; | 851 | if (walk->type != walk->cur_type && |
837 | int i; | 852 | walk->type != XFRM_POLICY_TYPE_ANY) |
853 | continue; | ||
838 | 854 | ||
839 | hlist_for_each_entry(pol, entry, | 855 | if (pol == NULL) { |
840 | &xfrm_policy_inexact[dir], bydst) { | 856 | pol = list_first_entry(&xfrm_policy_bytype[walk->cur_type], |
841 | if (pol->type != type) | 857 | struct xfrm_policy, bytype); |
858 | } | ||
859 | list_for_each_entry_from(pol, &xfrm_policy_bytype[walk->cur_type], bytype) { | ||
860 | if (pol->dead) | ||
842 | continue; | 861 | continue; |
843 | if (last) { | 862 | if (last) { |
844 | error = func(last, last_dir % XFRM_POLICY_MAX, | 863 | error = func(last, xfrm_policy_id2dir(last->index), |
845 | count, data); | 864 | walk->count, data); |
846 | if (error) | 865 | if (error) { |
866 | xfrm_pol_hold(last); | ||
867 | walk->policy = last; | ||
847 | goto out; | 868 | 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 | } | 869 | } |
863 | last = pol; | ||
864 | last_dir = dir; | ||
865 | count++; | ||
866 | } | 870 | } |
871 | last = pol; | ||
872 | walk->count++; | ||
867 | } | 873 | } |
874 | pol = NULL; | ||
868 | } | 875 | } |
869 | if (count == 0) { | 876 | if (walk->count == 0) { |
870 | error = -ENOENT; | 877 | error = -ENOENT; |
871 | goto out; | 878 | goto out; |
872 | } | 879 | } |
873 | error = func(last, last_dir % XFRM_POLICY_MAX, 0, data); | 880 | if (last) |
881 | error = func(last, xfrm_policy_id2dir(last->index), 0, data); | ||
874 | out: | 882 | out: |
875 | read_unlock_bh(&xfrm_policy_lock); | 883 | read_unlock_bh(&xfrm_policy_lock); |
884 | if (old != NULL) | ||
885 | xfrm_pol_put(old); | ||
876 | return error; | 886 | return error; |
877 | } | 887 | } |
878 | EXPORT_SYMBOL(xfrm_policy_walk); | 888 | EXPORT_SYMBOL(xfrm_policy_walk); |
@@ -2365,6 +2375,9 @@ static void __init xfrm_policy_init(void) | |||
2365 | panic("XFRM: failed to allocate bydst hash\n"); | 2375 | panic("XFRM: failed to allocate bydst hash\n"); |
2366 | } | 2376 | } |
2367 | 2377 | ||
2378 | for (dir = 0; dir < XFRM_POLICY_TYPE_MAX; dir++) | ||
2379 | INIT_LIST_HEAD(&xfrm_policy_bytype[dir]); | ||
2380 | |||
2368 | INIT_WORK(&xfrm_policy_gc_work, xfrm_policy_gc_task); | 2381 | INIT_WORK(&xfrm_policy_gc_work, xfrm_policy_gc_task); |
2369 | register_netdevice_notifier(&xfrm_dev_notifier); | 2382 | register_netdevice_notifier(&xfrm_dev_notifier); |
2370 | } | 2383 | } |