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