Commit | Line | Data |
---|---|---|
72205fc6 JK |
1 | /* Copyright (C) 2000-2002 Joakim Axelsson <gozem@linux.nu> |
2 | * Patrick Schaaf <bof@bof.de> | |
3 | * Copyright (C) 2003-2011 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu> | |
4 | * | |
5 | * This program is free software; you can redistribute it and/or modify | |
6 | * it under the terms of the GNU General Public License version 2 as | |
7 | * published by the Free Software Foundation. | |
8 | */ | |
9 | ||
10 | /* Kernel module implementing an IP set type: the bitmap:ip type */ | |
11 | ||
12 | #include <linux/module.h> | |
13 | #include <linux/ip.h> | |
14 | #include <linux/skbuff.h> | |
15 | #include <linux/errno.h> | |
72205fc6 JK |
16 | #include <linux/bitops.h> |
17 | #include <linux/spinlock.h> | |
18 | #include <linux/netlink.h> | |
19 | #include <linux/jiffies.h> | |
20 | #include <linux/timer.h> | |
21 | #include <net/netlink.h> | |
22 | #include <net/tcp.h> | |
23 | ||
24 | #include <linux/netfilter/ipset/pfxlen.h> | |
25 | #include <linux/netfilter/ipset/ip_set.h> | |
26 | #include <linux/netfilter/ipset/ip_set_bitmap.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:ip type of IP sets"); | |
33 | MODULE_ALIAS("ip_set_bitmap:ip"); | |
34 | ||
35 | /* Type structure */ | |
36 | struct bitmap_ip { | |
37 | void *members; /* the set members */ | |
38 | u32 first_ip; /* host byte order, included in range */ | |
39 | u32 last_ip; /* host byte order, included in range */ | |
40 | u32 elements; /* number of max elements in the set */ | |
41 | u32 hosts; /* number of hosts in a subnet */ | |
42 | size_t memsize; /* members size */ | |
43 | u8 netmask; /* subnet netmask */ | |
44 | u32 timeout; /* timeout parameter */ | |
45 | struct timer_list gc; /* garbage collection */ | |
46 | }; | |
47 | ||
48 | /* Base variant */ | |
49 | ||
50 | static inline u32 | |
51 | ip_to_id(const struct bitmap_ip *m, u32 ip) | |
52 | { | |
53 | return ((ip & ip_set_hostmask(m->netmask)) - m->first_ip)/m->hosts; | |
54 | } | |
55 | ||
56 | static int | |
57 | bitmap_ip_test(struct ip_set *set, void *value, u32 timeout) | |
58 | { | |
59 | const struct bitmap_ip *map = set->data; | |
60 | u16 id = *(u16 *)value; | |
61 | ||
62 | return !!test_bit(id, map->members); | |
63 | } | |
64 | ||
65 | static int | |
66 | bitmap_ip_add(struct ip_set *set, void *value, u32 timeout) | |
67 | { | |
68 | struct bitmap_ip *map = set->data; | |
69 | u16 id = *(u16 *)value; | |
70 | ||
71 | if (test_and_set_bit(id, map->members)) | |
72 | return -IPSET_ERR_EXIST; | |
73 | ||
74 | return 0; | |
75 | } | |
76 | ||
77 | static int | |
78 | bitmap_ip_del(struct ip_set *set, void *value, u32 timeout) | |
79 | { | |
80 | struct bitmap_ip *map = set->data; | |
81 | u16 id = *(u16 *)value; | |
82 | ||
83 | if (!test_and_clear_bit(id, map->members)) | |
84 | return -IPSET_ERR_EXIST; | |
85 | ||
86 | return 0; | |
87 | } | |
88 | ||
89 | static int | |
90 | bitmap_ip_list(const struct ip_set *set, | |
91 | struct sk_buff *skb, struct netlink_callback *cb) | |
92 | { | |
93 | const struct bitmap_ip *map = set->data; | |
94 | struct nlattr *atd, *nested; | |
95 | u32 id, first = cb->args[2]; | |
96 | ||
97 | atd = ipset_nest_start(skb, IPSET_ATTR_ADT); | |
98 | if (!atd) | |
99 | return -EMSGSIZE; | |
100 | for (; cb->args[2] < map->elements; cb->args[2]++) { | |
101 | id = cb->args[2]; | |
102 | if (!test_bit(id, map->members)) | |
103 | continue; | |
104 | nested = ipset_nest_start(skb, IPSET_ATTR_DATA); | |
105 | if (!nested) { | |
106 | if (id == first) { | |
107 | nla_nest_cancel(skb, atd); | |
108 | return -EMSGSIZE; | |
109 | } else | |
110 | goto nla_put_failure; | |
111 | } | |
112 | NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP, | |
113 | htonl(map->first_ip + id * map->hosts)); | |
114 | ipset_nest_end(skb, nested); | |
115 | } | |
116 | ipset_nest_end(skb, atd); | |
117 | /* Set listing finished */ | |
118 | cb->args[2] = 0; | |
119 | return 0; | |
120 | ||
121 | nla_put_failure: | |
122 | nla_nest_cancel(skb, nested); | |
123 | ipset_nest_end(skb, atd); | |
124 | if (unlikely(id == first)) { | |
125 | cb->args[2] = 0; | |
126 | return -EMSGSIZE; | |
127 | } | |
128 | return 0; | |
129 | } | |
130 | ||
131 | /* Timeout variant */ | |
132 | ||
133 | static int | |
134 | bitmap_ip_ttest(struct ip_set *set, void *value, u32 timeout) | |
135 | { | |
136 | const struct bitmap_ip *map = set->data; | |
137 | const unsigned long *members = map->members; | |
138 | u16 id = *(u16 *)value; | |
139 | ||
140 | return ip_set_timeout_test(members[id]); | |
141 | } | |
142 | ||
143 | static int | |
144 | bitmap_ip_tadd(struct ip_set *set, void *value, u32 timeout) | |
145 | { | |
146 | struct bitmap_ip *map = set->data; | |
147 | unsigned long *members = map->members; | |
148 | u16 id = *(u16 *)value; | |
149 | ||
150 | if (ip_set_timeout_test(members[id])) | |
151 | return -IPSET_ERR_EXIST; | |
152 | ||
153 | members[id] = ip_set_timeout_set(timeout); | |
154 | ||
155 | return 0; | |
156 | } | |
157 | ||
158 | static int | |
159 | bitmap_ip_tdel(struct ip_set *set, void *value, u32 timeout) | |
160 | { | |
161 | struct bitmap_ip *map = set->data; | |
162 | unsigned long *members = map->members; | |
163 | u16 id = *(u16 *)value; | |
164 | int ret = -IPSET_ERR_EXIST; | |
165 | ||
166 | if (ip_set_timeout_test(members[id])) | |
167 | ret = 0; | |
168 | ||
169 | members[id] = IPSET_ELEM_UNSET; | |
170 | return ret; | |
171 | } | |
172 | ||
173 | static int | |
174 | bitmap_ip_tlist(const struct ip_set *set, | |
175 | struct sk_buff *skb, struct netlink_callback *cb) | |
176 | { | |
177 | const struct bitmap_ip *map = set->data; | |
178 | struct nlattr *adt, *nested; | |
179 | u32 id, first = cb->args[2]; | |
180 | const unsigned long *members = map->members; | |
181 | ||
182 | adt = ipset_nest_start(skb, IPSET_ATTR_ADT); | |
183 | if (!adt) | |
184 | return -EMSGSIZE; | |
185 | for (; cb->args[2] < map->elements; cb->args[2]++) { | |
186 | id = cb->args[2]; | |
187 | if (!ip_set_timeout_test(members[id])) | |
188 | continue; | |
189 | nested = ipset_nest_start(skb, IPSET_ATTR_DATA); | |
190 | if (!nested) { | |
191 | if (id == first) { | |
192 | nla_nest_cancel(skb, adt); | |
193 | return -EMSGSIZE; | |
194 | } else | |
195 | goto nla_put_failure; | |
196 | } | |
197 | NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP, | |
198 | htonl(map->first_ip + id * map->hosts)); | |
199 | NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT, | |
200 | htonl(ip_set_timeout_get(members[id]))); | |
201 | ipset_nest_end(skb, nested); | |
202 | } | |
203 | ipset_nest_end(skb, adt); | |
204 | ||
205 | /* Set listing finished */ | |
206 | cb->args[2] = 0; | |
207 | ||
208 | return 0; | |
209 | ||
210 | nla_put_failure: | |
211 | nla_nest_cancel(skb, nested); | |
212 | ipset_nest_end(skb, adt); | |
213 | if (unlikely(id == first)) { | |
214 | cb->args[2] = 0; | |
215 | return -EMSGSIZE; | |
216 | } | |
217 | return 0; | |
218 | } | |
219 | ||
220 | static int | |
221 | bitmap_ip_kadt(struct ip_set *set, const struct sk_buff *skb, | |
222 | enum ipset_adt adt, u8 pf, u8 dim, u8 flags) | |
223 | { | |
224 | struct bitmap_ip *map = set->data; | |
225 | ipset_adtfn adtfn = set->variant->adt[adt]; | |
226 | u32 ip; | |
227 | ||
228 | ip = ntohl(ip4addr(skb, flags & IPSET_DIM_ONE_SRC)); | |
229 | if (ip < map->first_ip || ip > map->last_ip) | |
230 | return -IPSET_ERR_BITMAP_RANGE; | |
231 | ||
232 | ip = ip_to_id(map, ip); | |
233 | ||
234 | return adtfn(set, &ip, map->timeout); | |
235 | } | |
236 | ||
237 | static int | |
238 | bitmap_ip_uadt(struct ip_set *set, struct nlattr *tb[], | |
239 | enum ipset_adt adt, u32 *lineno, u32 flags) | |
240 | { | |
241 | struct bitmap_ip *map = set->data; | |
242 | ipset_adtfn adtfn = set->variant->adt[adt]; | |
243 | u32 timeout = map->timeout; | |
244 | u32 ip, ip_to, id; | |
245 | int ret = 0; | |
246 | ||
247 | if (unlikely(!tb[IPSET_ATTR_IP] || | |
248 | !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT))) | |
249 | return -IPSET_ERR_PROTOCOL; | |
250 | ||
251 | if (tb[IPSET_ATTR_LINENO]) | |
252 | *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]); | |
253 | ||
254 | ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP], &ip); | |
255 | if (ret) | |
256 | return ret; | |
257 | ||
258 | if (ip < map->first_ip || ip > map->last_ip) | |
259 | return -IPSET_ERR_BITMAP_RANGE; | |
260 | ||
261 | if (tb[IPSET_ATTR_TIMEOUT]) { | |
262 | if (!with_timeout(map->timeout)) | |
263 | return -IPSET_ERR_TIMEOUT; | |
264 | timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]); | |
265 | } | |
266 | ||
267 | if (adt == IPSET_TEST) { | |
268 | id = ip_to_id(map, ip); | |
269 | return adtfn(set, &id, timeout); | |
270 | } | |
271 | ||
272 | if (tb[IPSET_ATTR_IP_TO]) { | |
273 | ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP_TO], &ip_to); | |
274 | if (ret) | |
275 | return ret; | |
276 | if (ip > ip_to) { | |
277 | swap(ip, ip_to); | |
278 | if (ip < map->first_ip) | |
279 | return -IPSET_ERR_BITMAP_RANGE; | |
280 | } | |
281 | } else if (tb[IPSET_ATTR_CIDR]) { | |
282 | u8 cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]); | |
283 | ||
284 | if (cidr > 32) | |
285 | return -IPSET_ERR_INVALID_CIDR; | |
286 | ip &= ip_set_hostmask(cidr); | |
287 | ip_to = ip | ~ip_set_hostmask(cidr); | |
288 | } else | |
289 | ip_to = ip; | |
290 | ||
291 | if (ip_to > map->last_ip) | |
292 | return -IPSET_ERR_BITMAP_RANGE; | |
293 | ||
294 | for (; !before(ip_to, ip); ip += map->hosts) { | |
295 | id = ip_to_id(map, ip); | |
6eab04a8 | 296 | ret = adtfn(set, &id, timeout); |
72205fc6 JK |
297 | |
298 | if (ret && !ip_set_eexist(ret, flags)) | |
299 | return ret; | |
300 | else | |
301 | ret = 0; | |
302 | } | |
303 | return ret; | |
304 | } | |
305 | ||
306 | static void | |
307 | bitmap_ip_destroy(struct ip_set *set) | |
308 | { | |
309 | struct bitmap_ip *map = set->data; | |
310 | ||
311 | if (with_timeout(map->timeout)) | |
312 | del_timer_sync(&map->gc); | |
313 | ||
314 | ip_set_free(map->members); | |
315 | kfree(map); | |
316 | ||
317 | set->data = NULL; | |
318 | } | |
319 | ||
320 | static void | |
321 | bitmap_ip_flush(struct ip_set *set) | |
322 | { | |
323 | struct bitmap_ip *map = set->data; | |
324 | ||
325 | memset(map->members, 0, map->memsize); | |
326 | } | |
327 | ||
328 | static int | |
329 | bitmap_ip_head(struct ip_set *set, struct sk_buff *skb) | |
330 | { | |
331 | const struct bitmap_ip *map = set->data; | |
332 | struct nlattr *nested; | |
333 | ||
334 | nested = ipset_nest_start(skb, IPSET_ATTR_DATA); | |
335 | if (!nested) | |
336 | goto nla_put_failure; | |
337 | NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP, htonl(map->first_ip)); | |
338 | NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP_TO, htonl(map->last_ip)); | |
339 | if (map->netmask != 32) | |
340 | NLA_PUT_U8(skb, IPSET_ATTR_NETMASK, map->netmask); | |
341 | NLA_PUT_NET32(skb, IPSET_ATTR_REFERENCES, | |
342 | htonl(atomic_read(&set->ref) - 1)); | |
343 | NLA_PUT_NET32(skb, IPSET_ATTR_MEMSIZE, | |
344 | htonl(sizeof(*map) + map->memsize)); | |
345 | if (with_timeout(map->timeout)) | |
346 | NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT, htonl(map->timeout)); | |
347 | ipset_nest_end(skb, nested); | |
348 | ||
349 | return 0; | |
350 | nla_put_failure: | |
351 | return -EMSGSIZE; | |
352 | } | |
353 | ||
354 | static bool | |
355 | bitmap_ip_same_set(const struct ip_set *a, const struct ip_set *b) | |
356 | { | |
357 | const struct bitmap_ip *x = a->data; | |
358 | const struct bitmap_ip *y = b->data; | |
359 | ||
360 | return x->first_ip == y->first_ip && | |
361 | x->last_ip == y->last_ip && | |
362 | x->netmask == y->netmask && | |
363 | x->timeout == y->timeout; | |
364 | } | |
365 | ||
366 | static const struct ip_set_type_variant bitmap_ip = { | |
367 | .kadt = bitmap_ip_kadt, | |
368 | .uadt = bitmap_ip_uadt, | |
369 | .adt = { | |
370 | [IPSET_ADD] = bitmap_ip_add, | |
371 | [IPSET_DEL] = bitmap_ip_del, | |
372 | [IPSET_TEST] = bitmap_ip_test, | |
373 | }, | |
374 | .destroy = bitmap_ip_destroy, | |
375 | .flush = bitmap_ip_flush, | |
376 | .head = bitmap_ip_head, | |
377 | .list = bitmap_ip_list, | |
378 | .same_set = bitmap_ip_same_set, | |
379 | }; | |
380 | ||
381 | static const struct ip_set_type_variant bitmap_tip = { | |
382 | .kadt = bitmap_ip_kadt, | |
383 | .uadt = bitmap_ip_uadt, | |
384 | .adt = { | |
385 | [IPSET_ADD] = bitmap_ip_tadd, | |
386 | [IPSET_DEL] = bitmap_ip_tdel, | |
387 | [IPSET_TEST] = bitmap_ip_ttest, | |
388 | }, | |
389 | .destroy = bitmap_ip_destroy, | |
390 | .flush = bitmap_ip_flush, | |
391 | .head = bitmap_ip_head, | |
392 | .list = bitmap_ip_tlist, | |
393 | .same_set = bitmap_ip_same_set, | |
394 | }; | |
395 | ||
396 | static void | |
397 | bitmap_ip_gc(unsigned long ul_set) | |
398 | { | |
399 | struct ip_set *set = (struct ip_set *) ul_set; | |
400 | struct bitmap_ip *map = set->data; | |
401 | unsigned long *table = map->members; | |
402 | u32 id; | |
403 | ||
404 | /* We run parallel with other readers (test element) | |
405 | * but adding/deleting new entries is locked out */ | |
406 | read_lock_bh(&set->lock); | |
407 | for (id = 0; id < map->elements; id++) | |
408 | if (ip_set_timeout_expired(table[id])) | |
409 | table[id] = IPSET_ELEM_UNSET; | |
410 | read_unlock_bh(&set->lock); | |
411 | ||
412 | map->gc.expires = jiffies + IPSET_GC_PERIOD(map->timeout) * HZ; | |
413 | add_timer(&map->gc); | |
414 | } | |
415 | ||
416 | static void | |
417 | bitmap_ip_gc_init(struct ip_set *set) | |
418 | { | |
419 | struct bitmap_ip *map = set->data; | |
420 | ||
421 | init_timer(&map->gc); | |
422 | map->gc.data = (unsigned long) set; | |
423 | map->gc.function = bitmap_ip_gc; | |
424 | map->gc.expires = jiffies + IPSET_GC_PERIOD(map->timeout) * HZ; | |
425 | add_timer(&map->gc); | |
426 | } | |
427 | ||
428 | /* Create bitmap:ip type of sets */ | |
429 | ||
430 | static bool | |
431 | init_map_ip(struct ip_set *set, struct bitmap_ip *map, | |
432 | u32 first_ip, u32 last_ip, | |
433 | u32 elements, u32 hosts, u8 netmask) | |
434 | { | |
435 | map->members = ip_set_alloc(map->memsize); | |
436 | if (!map->members) | |
437 | return false; | |
438 | map->first_ip = first_ip; | |
439 | map->last_ip = last_ip; | |
440 | map->elements = elements; | |
441 | map->hosts = hosts; | |
442 | map->netmask = netmask; | |
443 | map->timeout = IPSET_NO_TIMEOUT; | |
444 | ||
445 | set->data = map; | |
446 | set->family = AF_INET; | |
447 | ||
448 | return true; | |
449 | } | |
450 | ||
451 | static int | |
452 | bitmap_ip_create(struct ip_set *set, struct nlattr *tb[], u32 flags) | |
453 | { | |
454 | struct bitmap_ip *map; | |
455 | u32 first_ip, last_ip, hosts, elements; | |
456 | u8 netmask = 32; | |
457 | int ret; | |
458 | ||
459 | if (unlikely(!tb[IPSET_ATTR_IP] || | |
460 | !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT))) | |
461 | return -IPSET_ERR_PROTOCOL; | |
462 | ||
463 | ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP], &first_ip); | |
464 | if (ret) | |
465 | return ret; | |
466 | ||
467 | if (tb[IPSET_ATTR_IP_TO]) { | |
468 | ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP_TO], &last_ip); | |
469 | if (ret) | |
470 | return ret; | |
471 | if (first_ip > last_ip) { | |
472 | u32 tmp = first_ip; | |
473 | ||
474 | first_ip = last_ip; | |
475 | last_ip = tmp; | |
476 | } | |
477 | } else if (tb[IPSET_ATTR_CIDR]) { | |
478 | u8 cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]); | |
479 | ||
480 | if (cidr >= 32) | |
481 | return -IPSET_ERR_INVALID_CIDR; | |
482 | last_ip = first_ip | ~ip_set_hostmask(cidr); | |
483 | } else | |
484 | return -IPSET_ERR_PROTOCOL; | |
485 | ||
486 | if (tb[IPSET_ATTR_NETMASK]) { | |
487 | netmask = nla_get_u8(tb[IPSET_ATTR_NETMASK]); | |
488 | ||
489 | if (netmask > 32) | |
490 | return -IPSET_ERR_INVALID_NETMASK; | |
491 | ||
492 | first_ip &= ip_set_hostmask(netmask); | |
493 | last_ip |= ~ip_set_hostmask(netmask); | |
494 | } | |
495 | ||
496 | if (netmask == 32) { | |
497 | hosts = 1; | |
498 | elements = last_ip - first_ip + 1; | |
499 | } else { | |
500 | u8 mask_bits; | |
501 | u32 mask; | |
502 | ||
503 | mask = range_to_mask(first_ip, last_ip, &mask_bits); | |
504 | ||
505 | if ((!mask && (first_ip || last_ip != 0xFFFFFFFF)) || | |
506 | netmask <= mask_bits) | |
507 | return -IPSET_ERR_BITMAP_RANGE; | |
508 | ||
509 | pr_debug("mask_bits %u, netmask %u\n", mask_bits, netmask); | |
510 | hosts = 2 << (32 - netmask - 1); | |
511 | elements = 2 << (netmask - mask_bits - 1); | |
512 | } | |
513 | if (elements > IPSET_BITMAP_MAX_RANGE + 1) | |
514 | return -IPSET_ERR_BITMAP_RANGE_SIZE; | |
515 | ||
516 | pr_debug("hosts %u, elements %u\n", hosts, elements); | |
517 | ||
518 | map = kzalloc(sizeof(*map), GFP_KERNEL); | |
519 | if (!map) | |
520 | return -ENOMEM; | |
521 | ||
522 | if (tb[IPSET_ATTR_TIMEOUT]) { | |
523 | map->memsize = elements * sizeof(unsigned long); | |
524 | ||
525 | if (!init_map_ip(set, map, first_ip, last_ip, | |
526 | elements, hosts, netmask)) { | |
527 | kfree(map); | |
528 | return -ENOMEM; | |
529 | } | |
530 | ||
531 | map->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]); | |
532 | set->variant = &bitmap_tip; | |
533 | ||
534 | bitmap_ip_gc_init(set); | |
535 | } else { | |
536 | map->memsize = bitmap_bytes(0, elements - 1); | |
537 | ||
538 | if (!init_map_ip(set, map, first_ip, last_ip, | |
539 | elements, hosts, netmask)) { | |
540 | kfree(map); | |
541 | return -ENOMEM; | |
542 | } | |
543 | ||
544 | set->variant = &bitmap_ip; | |
545 | } | |
546 | return 0; | |
547 | } | |
548 | ||
549 | static struct ip_set_type bitmap_ip_type __read_mostly = { | |
550 | .name = "bitmap:ip", | |
551 | .protocol = IPSET_PROTOCOL, | |
552 | .features = IPSET_TYPE_IP, | |
553 | .dimension = IPSET_DIM_ONE, | |
554 | .family = AF_INET, | |
555 | .revision = 0, | |
556 | .create = bitmap_ip_create, | |
557 | .create_policy = { | |
558 | [IPSET_ATTR_IP] = { .type = NLA_NESTED }, | |
559 | [IPSET_ATTR_IP_TO] = { .type = NLA_NESTED }, | |
560 | [IPSET_ATTR_CIDR] = { .type = NLA_U8 }, | |
561 | [IPSET_ATTR_NETMASK] = { .type = NLA_U8 }, | |
562 | [IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 }, | |
563 | }, | |
564 | .adt_policy = { | |
565 | [IPSET_ATTR_IP] = { .type = NLA_NESTED }, | |
566 | [IPSET_ATTR_IP_TO] = { .type = NLA_NESTED }, | |
567 | [IPSET_ATTR_CIDR] = { .type = NLA_U8 }, | |
568 | [IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 }, | |
569 | [IPSET_ATTR_LINENO] = { .type = NLA_U32 }, | |
570 | }, | |
571 | .me = THIS_MODULE, | |
572 | }; | |
573 | ||
574 | static int __init | |
575 | bitmap_ip_init(void) | |
576 | { | |
577 | return ip_set_type_register(&bitmap_ip_type); | |
578 | } | |
579 | ||
580 | static void __exit | |
581 | bitmap_ip_fini(void) | |
582 | { | |
583 | ip_set_type_unregister(&bitmap_ip_type); | |
584 | } | |
585 | ||
586 | module_init(bitmap_ip_init); | |
587 | module_exit(bitmap_ip_fini); |