diff options
author | Jozsef Kadlecsik <kadlec@blackhole.kfki.hu> | 2011-02-01 09:37:04 -0500 |
---|---|---|
committer | Patrick McHardy <kaber@trash.net> | 2011-02-01 09:37:04 -0500 |
commit | 543261907dc3c4e90845acfcd602ebdbfdfcb4f0 (patch) | |
tree | a8f233fa9532347b4d795d5d8021c36df7c60471 /net | |
parent | de76021a1bb35e3560afccf741d1119a872aea49 (diff) |
netfilter: ipset; bitmap:port set type support
The module implements the bitmap:port type in two flavours, without
and with timeout support to store TCP/UDP ports from a range.
Signed-off-by: Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
Signed-off-by: Patrick McHardy <kaber@trash.net>
Diffstat (limited to 'net')
-rw-r--r-- | net/netfilter/ipset/Kconfig | 9 | ||||
-rw-r--r-- | net/netfilter/ipset/Makefile | 1 | ||||
-rw-r--r-- | net/netfilter/ipset/ip_set_bitmap_port.c | 520 |
3 files changed, 530 insertions, 0 deletions
diff --git a/net/netfilter/ipset/Kconfig b/net/netfilter/ipset/Kconfig index f18654c73af2..f401e9112703 100644 --- a/net/netfilter/ipset/Kconfig +++ b/net/netfilter/ipset/Kconfig | |||
@@ -41,4 +41,13 @@ config IP_SET_BITMAP_IPMAC | |||
41 | 41 | ||
42 | To compile it as a module, choose M here. If unsure, say N. | 42 | To compile it as a module, choose M here. If unsure, say N. |
43 | 43 | ||
44 | config IP_SET_BITMAP_PORT | ||
45 | tristate "bitmap:port set support" | ||
46 | depends on IP_SET | ||
47 | help | ||
48 | This option adds the bitmap:port set type support, by which one | ||
49 | can store TCP/UDP port numbers from a range. | ||
50 | |||
51 | To compile it as a module, choose M here. If unsure, say N. | ||
52 | |||
44 | endif # IP_SET | 53 | endif # IP_SET |
diff --git a/net/netfilter/ipset/Makefile b/net/netfilter/ipset/Makefile index f7a099f40d0b..40866e267752 100644 --- a/net/netfilter/ipset/Makefile +++ b/net/netfilter/ipset/Makefile | |||
@@ -10,3 +10,4 @@ obj-$(CONFIG_IP_SET) += ip_set.o | |||
10 | # bitmap types | 10 | # bitmap types |
11 | obj-$(CONFIG_IP_SET_BITMAP_IP) += ip_set_bitmap_ip.o | 11 | obj-$(CONFIG_IP_SET_BITMAP_IP) += ip_set_bitmap_ip.o |
12 | obj-$(CONFIG_IP_SET_BITMAP_IPMAC) += ip_set_bitmap_ipmac.o | 12 | obj-$(CONFIG_IP_SET_BITMAP_IPMAC) += ip_set_bitmap_ipmac.o |
13 | obj-$(CONFIG_IP_SET_BITMAP_PORT) += ip_set_bitmap_port.o | ||
diff --git a/net/netfilter/ipset/ip_set_bitmap_port.c b/net/netfilter/ipset/ip_set_bitmap_port.c new file mode 100644 index 000000000000..92074bb64134 --- /dev/null +++ b/net/netfilter/ipset/ip_set_bitmap_port.c | |||
@@ -0,0 +1,520 @@ | |||
1 | /* Copyright (C) 2003-2011 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu> | ||
2 | * | ||
3 | * This program is free software; you can redistribute it and/or modify | ||
4 | * it under the terms of the GNU General Public License version 2 as | ||
5 | * published by the Free Software Foundation. | ||
6 | */ | ||
7 | |||
8 | /* Kernel module implementing an IP set type: the bitmap:port type */ | ||
9 | |||
10 | #include <linux/module.h> | ||
11 | #include <linux/ip.h> | ||
12 | #include <linux/tcp.h> | ||
13 | #include <linux/udp.h> | ||
14 | #include <linux/skbuff.h> | ||
15 | #include <linux/errno.h> | ||
16 | #include <linux/uaccess.h> | ||
17 | #include <linux/bitops.h> | ||
18 | #include <linux/spinlock.h> | ||
19 | #include <linux/netlink.h> | ||
20 | #include <linux/jiffies.h> | ||
21 | #include <linux/timer.h> | ||
22 | #include <net/netlink.h> | ||
23 | |||
24 | #include <linux/netfilter/ipset/ip_set.h> | ||
25 | #include <linux/netfilter/ipset/ip_set_bitmap.h> | ||
26 | #include <linux/netfilter/ipset/ip_set_getport.h> | ||
27 | #define IP_SET_BITMAP_TIMEOUT | ||
28 | #include <linux/netfilter/ipset/ip_set_timeout.h> | ||
29 | |||
30 | MODULE_LICENSE("GPL"); | ||
31 | MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>"); | ||
32 | MODULE_DESCRIPTION("bitmap:port type of IP sets"); | ||
33 | MODULE_ALIAS("ip_set_bitmap:port"); | ||
34 | |||
35 | /* Type structure */ | ||
36 | struct bitmap_port { | ||
37 | void *members; /* the set members */ | ||
38 | u16 first_port; /* host byte order, included in range */ | ||
39 | u16 last_port; /* host byte order, included in range */ | ||
40 | size_t memsize; /* members size */ | ||
41 | u32 timeout; /* timeout parameter */ | ||
42 | struct timer_list gc; /* garbage collection */ | ||
43 | }; | ||
44 | |||
45 | /* Base variant */ | ||
46 | |||
47 | static int | ||
48 | bitmap_port_test(struct ip_set *set, void *value, u32 timeout) | ||
49 | { | ||
50 | const struct bitmap_port *map = set->data; | ||
51 | u16 id = *(u16 *)value; | ||
52 | |||
53 | return !!test_bit(id, map->members); | ||
54 | } | ||
55 | |||
56 | static int | ||
57 | bitmap_port_add(struct ip_set *set, void *value, u32 timeout) | ||
58 | { | ||
59 | struct bitmap_port *map = set->data; | ||
60 | u16 id = *(u16 *)value; | ||
61 | |||
62 | if (test_and_set_bit(id, map->members)) | ||
63 | return -IPSET_ERR_EXIST; | ||
64 | |||
65 | return 0; | ||
66 | } | ||
67 | |||
68 | static int | ||
69 | bitmap_port_del(struct ip_set *set, void *value, u32 timeout) | ||
70 | { | ||
71 | struct bitmap_port *map = set->data; | ||
72 | u16 id = *(u16 *)value; | ||
73 | |||
74 | if (!test_and_clear_bit(id, map->members)) | ||
75 | return -IPSET_ERR_EXIST; | ||
76 | |||
77 | return 0; | ||
78 | } | ||
79 | |||
80 | static int | ||
81 | bitmap_port_list(const struct ip_set *set, | ||
82 | struct sk_buff *skb, struct netlink_callback *cb) | ||
83 | { | ||
84 | const struct bitmap_port *map = set->data; | ||
85 | struct nlattr *atd, *nested; | ||
86 | u16 id, first = cb->args[2]; | ||
87 | u16 last = map->last_port - map->first_port; | ||
88 | |||
89 | atd = ipset_nest_start(skb, IPSET_ATTR_ADT); | ||
90 | if (!atd) | ||
91 | return -EMSGSIZE; | ||
92 | for (; cb->args[2] <= last; cb->args[2]++) { | ||
93 | id = cb->args[2]; | ||
94 | if (!test_bit(id, map->members)) | ||
95 | continue; | ||
96 | nested = ipset_nest_start(skb, IPSET_ATTR_DATA); | ||
97 | if (!nested) { | ||
98 | if (id == first) { | ||
99 | nla_nest_cancel(skb, atd); | ||
100 | return -EMSGSIZE; | ||
101 | } else | ||
102 | goto nla_put_failure; | ||
103 | } | ||
104 | NLA_PUT_NET16(skb, IPSET_ATTR_PORT, | ||
105 | htons(map->first_port + id)); | ||
106 | ipset_nest_end(skb, nested); | ||
107 | } | ||
108 | ipset_nest_end(skb, atd); | ||
109 | /* Set listing finished */ | ||
110 | cb->args[2] = 0; | ||
111 | |||
112 | return 0; | ||
113 | |||
114 | nla_put_failure: | ||
115 | nla_nest_cancel(skb, nested); | ||
116 | ipset_nest_end(skb, atd); | ||
117 | if (unlikely(id == first)) { | ||
118 | cb->args[2] = 0; | ||
119 | return -EMSGSIZE; | ||
120 | } | ||
121 | return 0; | ||
122 | } | ||
123 | |||
124 | /* Timeout variant */ | ||
125 | |||
126 | static int | ||
127 | bitmap_port_ttest(struct ip_set *set, void *value, u32 timeout) | ||
128 | { | ||
129 | const struct bitmap_port *map = set->data; | ||
130 | const unsigned long *members = map->members; | ||
131 | u16 id = *(u16 *)value; | ||
132 | |||
133 | return ip_set_timeout_test(members[id]); | ||
134 | } | ||
135 | |||
136 | static int | ||
137 | bitmap_port_tadd(struct ip_set *set, void *value, u32 timeout) | ||
138 | { | ||
139 | struct bitmap_port *map = set->data; | ||
140 | unsigned long *members = map->members; | ||
141 | u16 id = *(u16 *)value; | ||
142 | |||
143 | if (ip_set_timeout_test(members[id])) | ||
144 | return -IPSET_ERR_EXIST; | ||
145 | |||
146 | members[id] = ip_set_timeout_set(timeout); | ||
147 | |||
148 | return 0; | ||
149 | } | ||
150 | |||
151 | static int | ||
152 | bitmap_port_tdel(struct ip_set *set, void *value, u32 timeout) | ||
153 | { | ||
154 | struct bitmap_port *map = set->data; | ||
155 | unsigned long *members = map->members; | ||
156 | u16 id = *(u16 *)value; | ||
157 | int ret = -IPSET_ERR_EXIST; | ||
158 | |||
159 | if (ip_set_timeout_test(members[id])) | ||
160 | ret = 0; | ||
161 | |||
162 | members[id] = IPSET_ELEM_UNSET; | ||
163 | return ret; | ||
164 | } | ||
165 | |||
166 | static int | ||
167 | bitmap_port_tlist(const struct ip_set *set, | ||
168 | struct sk_buff *skb, struct netlink_callback *cb) | ||
169 | { | ||
170 | const struct bitmap_port *map = set->data; | ||
171 | struct nlattr *adt, *nested; | ||
172 | u16 id, first = cb->args[2]; | ||
173 | u16 last = map->last_port - map->first_port; | ||
174 | const unsigned long *members = map->members; | ||
175 | |||
176 | adt = ipset_nest_start(skb, IPSET_ATTR_ADT); | ||
177 | if (!adt) | ||
178 | return -EMSGSIZE; | ||
179 | for (; cb->args[2] <= last; cb->args[2]++) { | ||
180 | id = cb->args[2]; | ||
181 | if (!ip_set_timeout_test(members[id])) | ||
182 | continue; | ||
183 | nested = ipset_nest_start(skb, IPSET_ATTR_DATA); | ||
184 | if (!nested) { | ||
185 | if (id == first) { | ||
186 | nla_nest_cancel(skb, adt); | ||
187 | return -EMSGSIZE; | ||
188 | } else | ||
189 | goto nla_put_failure; | ||
190 | } | ||
191 | NLA_PUT_NET16(skb, IPSET_ATTR_PORT, | ||
192 | htons(map->first_port + id)); | ||
193 | NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT, | ||
194 | htonl(ip_set_timeout_get(members[id]))); | ||
195 | ipset_nest_end(skb, nested); | ||
196 | } | ||
197 | ipset_nest_end(skb, adt); | ||
198 | |||
199 | /* Set listing finished */ | ||
200 | cb->args[2] = 0; | ||
201 | |||
202 | return 0; | ||
203 | |||
204 | nla_put_failure: | ||
205 | nla_nest_cancel(skb, nested); | ||
206 | ipset_nest_end(skb, adt); | ||
207 | if (unlikely(id == first)) { | ||
208 | cb->args[2] = 0; | ||
209 | return -EMSGSIZE; | ||
210 | } | ||
211 | return 0; | ||
212 | } | ||
213 | |||
214 | static int | ||
215 | bitmap_port_kadt(struct ip_set *set, const struct sk_buff *skb, | ||
216 | enum ipset_adt adt, u8 pf, u8 dim, u8 flags) | ||
217 | { | ||
218 | struct bitmap_port *map = set->data; | ||
219 | ipset_adtfn adtfn = set->variant->adt[adt]; | ||
220 | __be16 __port; | ||
221 | u16 port = 0; | ||
222 | |||
223 | if (!ip_set_get_ip_port(skb, pf, flags & IPSET_DIM_ONE_SRC, &__port)) | ||
224 | return -EINVAL; | ||
225 | |||
226 | port = ntohs(__port); | ||
227 | |||
228 | if (port < map->first_port || port > map->last_port) | ||
229 | return -IPSET_ERR_BITMAP_RANGE; | ||
230 | |||
231 | port -= map->first_port; | ||
232 | |||
233 | return adtfn(set, &port, map->timeout); | ||
234 | } | ||
235 | |||
236 | static int | ||
237 | bitmap_port_uadt(struct ip_set *set, struct nlattr *tb[], | ||
238 | enum ipset_adt adt, u32 *lineno, u32 flags) | ||
239 | { | ||
240 | struct bitmap_port *map = set->data; | ||
241 | ipset_adtfn adtfn = set->variant->adt[adt]; | ||
242 | u32 timeout = map->timeout; | ||
243 | u32 port; /* wraparound */ | ||
244 | u16 id, port_to; | ||
245 | int ret = 0; | ||
246 | |||
247 | if (unlikely(!ip_set_attr_netorder(tb, IPSET_ATTR_PORT) || | ||
248 | !ip_set_optattr_netorder(tb, IPSET_ATTR_PORT_TO) || | ||
249 | !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT))) | ||
250 | return -IPSET_ERR_PROTOCOL; | ||
251 | |||
252 | if (tb[IPSET_ATTR_LINENO]) | ||
253 | *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]); | ||
254 | |||
255 | port = ip_set_get_h16(tb[IPSET_ATTR_PORT]); | ||
256 | if (port < map->first_port || port > map->last_port) | ||
257 | return -IPSET_ERR_BITMAP_RANGE; | ||
258 | |||
259 | if (tb[IPSET_ATTR_TIMEOUT]) { | ||
260 | if (!with_timeout(map->timeout)) | ||
261 | return -IPSET_ERR_TIMEOUT; | ||
262 | timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]); | ||
263 | } | ||
264 | |||
265 | if (adt == IPSET_TEST) { | ||
266 | id = port - map->first_port; | ||
267 | return adtfn(set, &id, timeout); | ||
268 | } | ||
269 | |||
270 | if (tb[IPSET_ATTR_PORT_TO]) { | ||
271 | port_to = ip_set_get_h16(tb[IPSET_ATTR_PORT_TO]); | ||
272 | if (port > port_to) { | ||
273 | swap(port, port_to); | ||
274 | if (port < map->first_port) | ||
275 | return -IPSET_ERR_BITMAP_RANGE; | ||
276 | } | ||
277 | } else | ||
278 | port_to = port; | ||
279 | |||
280 | if (port_to > map->last_port) | ||
281 | return -IPSET_ERR_BITMAP_RANGE; | ||
282 | |||
283 | for (; port <= port_to; port++) { | ||
284 | id = port - map->first_port; | ||
285 | ret = adtfn(set, &id, timeout); | ||
286 | |||
287 | if (ret && !ip_set_eexist(ret, flags)) | ||
288 | return ret; | ||
289 | else | ||
290 | ret = 0; | ||
291 | } | ||
292 | return ret; | ||
293 | } | ||
294 | |||
295 | static void | ||
296 | bitmap_port_destroy(struct ip_set *set) | ||
297 | { | ||
298 | struct bitmap_port *map = set->data; | ||
299 | |||
300 | if (with_timeout(map->timeout)) | ||
301 | del_timer_sync(&map->gc); | ||
302 | |||
303 | ip_set_free(map->members); | ||
304 | kfree(map); | ||
305 | |||
306 | set->data = NULL; | ||
307 | } | ||
308 | |||
309 | static void | ||
310 | bitmap_port_flush(struct ip_set *set) | ||
311 | { | ||
312 | struct bitmap_port *map = set->data; | ||
313 | |||
314 | memset(map->members, 0, map->memsize); | ||
315 | } | ||
316 | |||
317 | static int | ||
318 | bitmap_port_head(struct ip_set *set, struct sk_buff *skb) | ||
319 | { | ||
320 | const struct bitmap_port *map = set->data; | ||
321 | struct nlattr *nested; | ||
322 | |||
323 | nested = ipset_nest_start(skb, IPSET_ATTR_DATA); | ||
324 | if (!nested) | ||
325 | goto nla_put_failure; | ||
326 | NLA_PUT_NET16(skb, IPSET_ATTR_PORT, htons(map->first_port)); | ||
327 | NLA_PUT_NET16(skb, IPSET_ATTR_PORT_TO, htons(map->last_port)); | ||
328 | NLA_PUT_NET32(skb, IPSET_ATTR_REFERENCES, | ||
329 | htonl(atomic_read(&set->ref) - 1)); | ||
330 | NLA_PUT_NET32(skb, IPSET_ATTR_MEMSIZE, | ||
331 | htonl(sizeof(*map) + map->memsize)); | ||
332 | if (with_timeout(map->timeout)) | ||
333 | NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT, htonl(map->timeout)); | ||
334 | ipset_nest_end(skb, nested); | ||
335 | |||
336 | return 0; | ||
337 | nla_put_failure: | ||
338 | return -EMSGSIZE; | ||
339 | } | ||
340 | |||
341 | static bool | ||
342 | bitmap_port_same_set(const struct ip_set *a, const struct ip_set *b) | ||
343 | { | ||
344 | const struct bitmap_port *x = a->data; | ||
345 | const struct bitmap_port *y = b->data; | ||
346 | |||
347 | return x->first_port == y->first_port && | ||
348 | x->last_port == y->last_port && | ||
349 | x->timeout == y->timeout; | ||
350 | } | ||
351 | |||
352 | static const struct ip_set_type_variant bitmap_port = { | ||
353 | .kadt = bitmap_port_kadt, | ||
354 | .uadt = bitmap_port_uadt, | ||
355 | .adt = { | ||
356 | [IPSET_ADD] = bitmap_port_add, | ||
357 | [IPSET_DEL] = bitmap_port_del, | ||
358 | [IPSET_TEST] = bitmap_port_test, | ||
359 | }, | ||
360 | .destroy = bitmap_port_destroy, | ||
361 | .flush = bitmap_port_flush, | ||
362 | .head = bitmap_port_head, | ||
363 | .list = bitmap_port_list, | ||
364 | .same_set = bitmap_port_same_set, | ||
365 | }; | ||
366 | |||
367 | static const struct ip_set_type_variant bitmap_tport = { | ||
368 | .kadt = bitmap_port_kadt, | ||
369 | .uadt = bitmap_port_uadt, | ||
370 | .adt = { | ||
371 | [IPSET_ADD] = bitmap_port_tadd, | ||
372 | [IPSET_DEL] = bitmap_port_tdel, | ||
373 | [IPSET_TEST] = bitmap_port_ttest, | ||
374 | }, | ||
375 | .destroy = bitmap_port_destroy, | ||
376 | .flush = bitmap_port_flush, | ||
377 | .head = bitmap_port_head, | ||
378 | .list = bitmap_port_tlist, | ||
379 | .same_set = bitmap_port_same_set, | ||
380 | }; | ||
381 | |||
382 | static void | ||
383 | bitmap_port_gc(unsigned long ul_set) | ||
384 | { | ||
385 | struct ip_set *set = (struct ip_set *) ul_set; | ||
386 | struct bitmap_port *map = set->data; | ||
387 | unsigned long *table = map->members; | ||
388 | u32 id; /* wraparound */ | ||
389 | u16 last = map->last_port - map->first_port; | ||
390 | |||
391 | /* We run parallel with other readers (test element) | ||
392 | * but adding/deleting new entries is locked out */ | ||
393 | read_lock_bh(&set->lock); | ||
394 | for (id = 0; id <= last; id++) | ||
395 | if (ip_set_timeout_expired(table[id])) | ||
396 | table[id] = IPSET_ELEM_UNSET; | ||
397 | read_unlock_bh(&set->lock); | ||
398 | |||
399 | map->gc.expires = jiffies + IPSET_GC_PERIOD(map->timeout) * HZ; | ||
400 | add_timer(&map->gc); | ||
401 | } | ||
402 | |||
403 | static void | ||
404 | bitmap_port_gc_init(struct ip_set *set) | ||
405 | { | ||
406 | struct bitmap_port *map = set->data; | ||
407 | |||
408 | init_timer(&map->gc); | ||
409 | map->gc.data = (unsigned long) set; | ||
410 | map->gc.function = bitmap_port_gc; | ||
411 | map->gc.expires = jiffies + IPSET_GC_PERIOD(map->timeout) * HZ; | ||
412 | add_timer(&map->gc); | ||
413 | } | ||
414 | |||
415 | /* Create bitmap:ip type of sets */ | ||
416 | |||
417 | static bool | ||
418 | init_map_port(struct ip_set *set, struct bitmap_port *map, | ||
419 | u16 first_port, u16 last_port) | ||
420 | { | ||
421 | map->members = ip_set_alloc(map->memsize); | ||
422 | if (!map->members) | ||
423 | return false; | ||
424 | map->first_port = first_port; | ||
425 | map->last_port = last_port; | ||
426 | map->timeout = IPSET_NO_TIMEOUT; | ||
427 | |||
428 | set->data = map; | ||
429 | set->family = AF_UNSPEC; | ||
430 | |||
431 | return true; | ||
432 | } | ||
433 | |||
434 | static int | ||
435 | bitmap_port_create(struct ip_set *set, struct nlattr *tb[], | ||
436 | u32 flags) | ||
437 | { | ||
438 | struct bitmap_port *map; | ||
439 | u16 first_port, last_port; | ||
440 | |||
441 | if (unlikely(!ip_set_attr_netorder(tb, IPSET_ATTR_PORT) || | ||
442 | !ip_set_attr_netorder(tb, IPSET_ATTR_PORT_TO) || | ||
443 | !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT))) | ||
444 | return -IPSET_ERR_PROTOCOL; | ||
445 | |||
446 | first_port = ip_set_get_h16(tb[IPSET_ATTR_PORT]); | ||
447 | last_port = ip_set_get_h16(tb[IPSET_ATTR_PORT_TO]); | ||
448 | if (first_port > last_port) { | ||
449 | u16 tmp = first_port; | ||
450 | |||
451 | first_port = last_port; | ||
452 | last_port = tmp; | ||
453 | } | ||
454 | |||
455 | map = kzalloc(sizeof(*map), GFP_KERNEL); | ||
456 | if (!map) | ||
457 | return -ENOMEM; | ||
458 | |||
459 | if (tb[IPSET_ATTR_TIMEOUT]) { | ||
460 | map->memsize = (last_port - first_port + 1) | ||
461 | * sizeof(unsigned long); | ||
462 | |||
463 | if (!init_map_port(set, map, first_port, last_port)) { | ||
464 | kfree(map); | ||
465 | return -ENOMEM; | ||
466 | } | ||
467 | |||
468 | map->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]); | ||
469 | set->variant = &bitmap_tport; | ||
470 | |||
471 | bitmap_port_gc_init(set); | ||
472 | } else { | ||
473 | map->memsize = bitmap_bytes(0, last_port - first_port); | ||
474 | pr_debug("memsize: %zu\n", map->memsize); | ||
475 | if (!init_map_port(set, map, first_port, last_port)) { | ||
476 | kfree(map); | ||
477 | return -ENOMEM; | ||
478 | } | ||
479 | |||
480 | set->variant = &bitmap_port; | ||
481 | } | ||
482 | return 0; | ||
483 | } | ||
484 | |||
485 | static struct ip_set_type bitmap_port_type = { | ||
486 | .name = "bitmap:port", | ||
487 | .protocol = IPSET_PROTOCOL, | ||
488 | .features = IPSET_TYPE_PORT, | ||
489 | .dimension = IPSET_DIM_ONE, | ||
490 | .family = AF_UNSPEC, | ||
491 | .revision = 0, | ||
492 | .create = bitmap_port_create, | ||
493 | .create_policy = { | ||
494 | [IPSET_ATTR_PORT] = { .type = NLA_U16 }, | ||
495 | [IPSET_ATTR_PORT_TO] = { .type = NLA_U16 }, | ||
496 | [IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 }, | ||
497 | }, | ||
498 | .adt_policy = { | ||
499 | [IPSET_ATTR_PORT] = { .type = NLA_U16 }, | ||
500 | [IPSET_ATTR_PORT_TO] = { .type = NLA_U16 }, | ||
501 | [IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 }, | ||
502 | [IPSET_ATTR_LINENO] = { .type = NLA_U32 }, | ||
503 | }, | ||
504 | .me = THIS_MODULE, | ||
505 | }; | ||
506 | |||
507 | static int __init | ||
508 | bitmap_port_init(void) | ||
509 | { | ||
510 | return ip_set_type_register(&bitmap_port_type); | ||
511 | } | ||
512 | |||
513 | static void __exit | ||
514 | bitmap_port_fini(void) | ||
515 | { | ||
516 | ip_set_type_unregister(&bitmap_port_type); | ||
517 | } | ||
518 | |||
519 | module_init(bitmap_port_init); | ||
520 | module_exit(bitmap_port_fini); | ||