diff options
Diffstat (limited to 'net')
-rw-r--r-- | net/netfilter/nf_conntrack_helper.c | 70 |
1 files changed, 57 insertions, 13 deletions
diff --git a/net/netfilter/nf_conntrack_helper.c b/net/netfilter/nf_conntrack_helper.c index 66c209d7e09d..b1179dd3d8c3 100644 --- a/net/netfilter/nf_conntrack_helper.c +++ b/net/netfilter/nf_conntrack_helper.c | |||
@@ -28,23 +28,41 @@ | |||
28 | #include <net/netfilter/nf_conntrack_core.h> | 28 | #include <net/netfilter/nf_conntrack_core.h> |
29 | #include <net/netfilter/nf_conntrack_extend.h> | 29 | #include <net/netfilter/nf_conntrack_extend.h> |
30 | 30 | ||
31 | static __read_mostly LIST_HEAD(helpers); | 31 | static struct hlist_head *nf_ct_helper_hash __read_mostly; |
32 | static unsigned int nf_ct_helper_hsize __read_mostly; | ||
33 | static unsigned int nf_ct_helper_count __read_mostly; | ||
34 | static int nf_ct_helper_vmalloc; | ||
35 | |||
36 | |||
37 | /* Stupid hash, but collision free for the default registrations of the | ||
38 | * helpers currently in the kernel. */ | ||
39 | static unsigned int helper_hash(const struct nf_conntrack_tuple *tuple) | ||
40 | { | ||
41 | return (((tuple->src.l3num << 8) | tuple->dst.protonum) ^ | ||
42 | tuple->src.u.all) % nf_ct_helper_hsize; | ||
43 | } | ||
32 | 44 | ||
33 | struct nf_conntrack_helper * | 45 | struct nf_conntrack_helper * |
34 | __nf_ct_helper_find(const struct nf_conntrack_tuple *tuple) | 46 | __nf_ct_helper_find(const struct nf_conntrack_tuple *tuple) |
35 | { | 47 | { |
36 | struct nf_conntrack_helper *h; | 48 | struct nf_conntrack_helper *helper; |
37 | struct nf_conntrack_tuple_mask mask = { .src.u.all = htons(0xFFFF) }; | 49 | struct nf_conntrack_tuple_mask mask = { .src.u.all = htons(0xFFFF) }; |
50 | struct hlist_node *n; | ||
51 | unsigned int h; | ||
38 | 52 | ||
39 | list_for_each_entry(h, &helpers, list) { | 53 | if (!nf_ct_helper_count) |
40 | if (nf_ct_tuple_src_mask_cmp(tuple, &h->tuple, &mask)) | 54 | return NULL; |
41 | return h; | 55 | |
56 | h = helper_hash(tuple); | ||
57 | hlist_for_each_entry(helper, n, &nf_ct_helper_hash[h], hnode) { | ||
58 | if (nf_ct_tuple_src_mask_cmp(tuple, &helper->tuple, &mask)) | ||
59 | return helper; | ||
42 | } | 60 | } |
43 | return NULL; | 61 | return NULL; |
44 | } | 62 | } |
45 | 63 | ||
46 | struct nf_conntrack_helper * | 64 | struct nf_conntrack_helper * |
47 | nf_ct_helper_find_get( const struct nf_conntrack_tuple *tuple) | 65 | nf_ct_helper_find_get(const struct nf_conntrack_tuple *tuple) |
48 | { | 66 | { |
49 | struct nf_conntrack_helper *helper; | 67 | struct nf_conntrack_helper *helper; |
50 | 68 | ||
@@ -77,12 +95,15 @@ struct nf_conntrack_helper * | |||
77 | __nf_conntrack_helper_find_byname(const char *name) | 95 | __nf_conntrack_helper_find_byname(const char *name) |
78 | { | 96 | { |
79 | struct nf_conntrack_helper *h; | 97 | struct nf_conntrack_helper *h; |
98 | struct hlist_node *n; | ||
99 | unsigned int i; | ||
80 | 100 | ||
81 | list_for_each_entry(h, &helpers, list) { | 101 | for (i = 0; i < nf_ct_helper_hsize; i++) { |
82 | if (!strcmp(h->name, name)) | 102 | hlist_for_each_entry(h, n, &nf_ct_helper_hash[i], hnode) { |
83 | return h; | 103 | if (!strcmp(h->name, name)) |
104 | return h; | ||
105 | } | ||
84 | } | 106 | } |
85 | |||
86 | return NULL; | 107 | return NULL; |
87 | } | 108 | } |
88 | EXPORT_SYMBOL_GPL(__nf_conntrack_helper_find_byname); | 109 | EXPORT_SYMBOL_GPL(__nf_conntrack_helper_find_byname); |
@@ -115,10 +136,13 @@ static inline int unhelp(struct nf_conntrack_tuple_hash *i, | |||
115 | 136 | ||
116 | int nf_conntrack_helper_register(struct nf_conntrack_helper *me) | 137 | int nf_conntrack_helper_register(struct nf_conntrack_helper *me) |
117 | { | 138 | { |
139 | unsigned int h = helper_hash(&me->tuple); | ||
140 | |||
118 | BUG_ON(me->timeout == 0); | 141 | BUG_ON(me->timeout == 0); |
119 | 142 | ||
120 | write_lock_bh(&nf_conntrack_lock); | 143 | write_lock_bh(&nf_conntrack_lock); |
121 | list_add(&me->list, &helpers); | 144 | hlist_add_head(&me->hnode, &nf_ct_helper_hash[h]); |
145 | nf_ct_helper_count++; | ||
122 | write_unlock_bh(&nf_conntrack_lock); | 146 | write_unlock_bh(&nf_conntrack_lock); |
123 | 147 | ||
124 | return 0; | 148 | return 0; |
@@ -134,7 +158,8 @@ void nf_conntrack_helper_unregister(struct nf_conntrack_helper *me) | |||
134 | 158 | ||
135 | /* Need write lock here, to delete helper. */ | 159 | /* Need write lock here, to delete helper. */ |
136 | write_lock_bh(&nf_conntrack_lock); | 160 | write_lock_bh(&nf_conntrack_lock); |
137 | list_del(&me->list); | 161 | hlist_del(&me->hnode); |
162 | nf_ct_helper_count--; | ||
138 | 163 | ||
139 | /* Get rid of expectations */ | 164 | /* Get rid of expectations */ |
140 | for (i = 0; i < nf_ct_expect_hsize; i++) { | 165 | for (i = 0; i < nf_ct_expect_hsize; i++) { |
@@ -171,10 +196,29 @@ static struct nf_ct_ext_type helper_extend __read_mostly = { | |||
171 | 196 | ||
172 | int nf_conntrack_helper_init() | 197 | int nf_conntrack_helper_init() |
173 | { | 198 | { |
174 | return nf_ct_extend_register(&helper_extend); | 199 | int err; |
200 | |||
201 | nf_ct_helper_hsize = 1; /* gets rounded up to use one page */ | ||
202 | nf_ct_helper_hash = nf_ct_alloc_hashtable(&nf_ct_helper_hsize, | ||
203 | &nf_ct_helper_vmalloc); | ||
204 | if (!nf_ct_helper_hash) | ||
205 | return -ENOMEM; | ||
206 | |||
207 | err = nf_ct_extend_register(&helper_extend); | ||
208 | if (err < 0) | ||
209 | goto err1; | ||
210 | |||
211 | return 0; | ||
212 | |||
213 | err1: | ||
214 | nf_ct_free_hashtable(nf_ct_helper_hash, nf_ct_helper_vmalloc, | ||
215 | nf_ct_helper_hsize); | ||
216 | return err; | ||
175 | } | 217 | } |
176 | 218 | ||
177 | void nf_conntrack_helper_fini() | 219 | void nf_conntrack_helper_fini() |
178 | { | 220 | { |
179 | nf_ct_extend_unregister(&helper_extend); | 221 | nf_ct_extend_unregister(&helper_extend); |
222 | nf_ct_free_hashtable(nf_ct_helper_hash, nf_ct_helper_vmalloc, | ||
223 | nf_ct_helper_hsize); | ||
180 | } | 224 | } |