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