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