netfilter: ipset: Introduce RCU locking in list type
[linux-2.6-block.git] / net / netfilter / ipset / ip_set_bitmap_ipmac.c
CommitLineData
de76021a
JK
1/* Copyright (C) 2000-2002 Joakim Axelsson <gozem@linux.nu>
2 * Patrick Schaaf <bof@bof.de>
3 * Martin Josefsson <gandalf@wlug.westbo.se>
b0da3905 4 * Copyright (C) 2003-2013 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
de76021a
JK
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/* Kernel module implementing an IP set type: the bitmap:ip,mac type */
12
13#include <linux/module.h>
14#include <linux/ip.h>
15#include <linux/etherdevice.h>
16#include <linux/skbuff.h>
17#include <linux/errno.h>
de76021a
JK
18#include <linux/if_ether.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/pfxlen.h>
25#include <linux/netfilter/ipset/ip_set.h>
de76021a
JK
26#include <linux/netfilter/ipset/ip_set_bitmap.h>
27
35b8dcf8 28#define IPSET_TYPE_REV_MIN 0
b90cb8ba 29/* 1 Counter support added */
39d1ecf1
AD
30/* 2 Comment support added */
31#define IPSET_TYPE_REV_MAX 3 /* skbinfo support added */
10111a6e 32
de76021a
JK
33MODULE_LICENSE("GPL");
34MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
35b8dcf8 35IP_SET_MODULE_DESC("bitmap:ip,mac", IPSET_TYPE_REV_MIN, IPSET_TYPE_REV_MAX);
de76021a
JK
36MODULE_ALIAS("ip_set_bitmap:ip,mac");
37
b0da3905 38#define MTYPE bitmap_ipmac
cabfd139 39#define HOST_MASK 32
b0da3905
JK
40#define IP_SET_BITMAP_STORED_TIMEOUT
41
de76021a 42enum {
de76021a 43 MAC_UNSET, /* element is set, without MAC */
b0da3905 44 MAC_FILLED, /* element is set with MAC */
de76021a
JK
45};
46
47/* Type structure */
48struct bitmap_ipmac {
49 void *members; /* the set members */
b0da3905 50 void *extensions; /* MAC + data extensions */
de76021a
JK
51 u32 first_ip; /* host byte order, included in range */
52 u32 last_ip; /* host byte order, included in range */
b0da3905 53 u32 elements; /* number of max elements in the set */
b0da3905 54 size_t memsize; /* members size */
ca134ce8 55 struct timer_list gc; /* garbage collector */
de76021a
JK
56};
57
58/* ADT structure for generic function args */
b0da3905
JK
59struct bitmap_ipmac_adt_elem {
60 u16 id;
61 unsigned char *ether;
de76021a
JK
62};
63
b0da3905 64struct bitmap_ipmac_elem {
de76021a 65 unsigned char ether[ETH_ALEN];
b0da3905 66 unsigned char filled;
de76021a
JK
67} __attribute__ ((aligned));
68
b0da3905
JK
69static inline u32
70ip_to_id(const struct bitmap_ipmac *m, u32 ip)
de76021a 71{
b0da3905 72 return ip - m->first_ip;
de76021a
JK
73}
74
b0da3905
JK
75static inline struct bitmap_ipmac_elem *
76get_elem(void *extensions, u16 id, size_t dsize)
de76021a 77{
b0da3905 78 return (struct bitmap_ipmac_elem *)(extensions + id * dsize);
de76021a
JK
79}
80
b0da3905 81/* Common functions */
de76021a
JK
82
83static inline int
b0da3905 84bitmap_ipmac_do_test(const struct bitmap_ipmac_adt_elem *e,
ca134ce8 85 const struct bitmap_ipmac *map, size_t dsize)
de76021a 86{
b0da3905 87 const struct bitmap_ipmac_elem *elem;
de76021a 88
b0da3905
JK
89 if (!test_bit(e->id, map->members))
90 return 0;
ca134ce8 91 elem = get_elem(map->extensions, e->id, dsize);
b0da3905
JK
92 if (elem->filled == MAC_FILLED)
93 return e->ether == NULL ||
94 ether_addr_equal(e->ether, elem->ether);
95 /* Trigger kernel to fill out the ethernet address */
96 return -EAGAIN;
de76021a
JK
97}
98
b0da3905 99static inline int
ca134ce8 100bitmap_ipmac_gc_test(u16 id, const struct bitmap_ipmac *map, size_t dsize)
de76021a 101{
b0da3905 102 const struct bitmap_ipmac_elem *elem;
de76021a 103
b0da3905
JK
104 if (!test_bit(id, map->members))
105 return 0;
ca134ce8 106 elem = get_elem(map->extensions, id, dsize);
b0da3905
JK
107 /* Timer not started for the incomplete elements */
108 return elem->filled == MAC_FILLED;
de76021a
JK
109}
110
b0da3905
JK
111static inline int
112bitmap_ipmac_is_filled(const struct bitmap_ipmac_elem *elem)
de76021a 113{
b0da3905 114 return elem->filled == MAC_FILLED;
de76021a
JK
115}
116
b0da3905
JK
117static inline int
118bitmap_ipmac_add_timeout(unsigned long *timeout,
119 const struct bitmap_ipmac_adt_elem *e,
ca134ce8 120 const struct ip_set_ext *ext, struct ip_set *set,
b0da3905 121 struct bitmap_ipmac *map, int mode)
de76021a 122{
b0da3905 123 u32 t = ext->timeout;
de76021a 124
b0da3905 125 if (mode == IPSET_ADD_START_STORED_TIMEOUT) {
ca134ce8 126 if (t == set->timeout)
de76021a 127 /* Timeout was not specified, get stored one */
b0da3905
JK
128 t = *timeout;
129 ip_set_timeout_set(timeout, t);
130 } else {
de76021a
JK
131 /* If MAC is unset yet, we store plain timeout value
132 * because the timer is not activated yet
133 * and we can reuse it later when MAC is filled out,
134 * possibly by the kernel */
b0da3905
JK
135 if (e->ether)
136 ip_set_timeout_set(timeout, t);
137 else
138 *timeout = t;
de76021a 139 }
de76021a
JK
140 return 0;
141}
142
b0da3905
JK
143static inline int
144bitmap_ipmac_do_add(const struct bitmap_ipmac_adt_elem *e,
ca134ce8 145 struct bitmap_ipmac *map, u32 flags, size_t dsize)
de76021a 146{
b0da3905
JK
147 struct bitmap_ipmac_elem *elem;
148
ca134ce8 149 elem = get_elem(map->extensions, e->id, dsize);
96f51428 150 if (test_bit(e->id, map->members)) {
b0da3905 151 if (elem->filled == MAC_FILLED) {
96f51428
JK
152 if (e->ether &&
153 (flags & IPSET_FLAG_EXIST) &&
154 !ether_addr_equal(e->ether, elem->ether)) {
155 /* memcpy isn't atomic */
156 clear_bit(e->id, map->members);
157 smp_mb__after_atomic();
b0da3905 158 memcpy(elem->ether, e->ether, ETH_ALEN);
96f51428 159 }
b0da3905
JK
160 return IPSET_ADD_FAILED;
161 } else if (!e->ether)
162 /* Already added without ethernet address */
163 return IPSET_ADD_FAILED;
164 /* Fill the MAC address and trigger the timer activation */
96f51428
JK
165 clear_bit(e->id, map->members);
166 smp_mb__after_atomic();
b0da3905
JK
167 memcpy(elem->ether, e->ether, ETH_ALEN);
168 elem->filled = MAC_FILLED;
169 return IPSET_ADD_START_STORED_TIMEOUT;
170 } else if (e->ether) {
171 /* We can store MAC too */
172 memcpy(elem->ether, e->ether, ETH_ALEN);
173 elem->filled = MAC_FILLED;
174 return 0;
175 } else {
176 elem->filled = MAC_UNSET;
177 /* MAC is not stored yet, don't start timer */
178 return IPSET_ADD_STORE_PLAIN_TIMEOUT;
179 }
180}
de76021a 181
b0da3905
JK
182static inline int
183bitmap_ipmac_do_del(const struct bitmap_ipmac_adt_elem *e,
184 struct bitmap_ipmac *map)
185{
186 return !test_and_clear_bit(e->id, map->members);
187}
de76021a 188
b0da3905
JK
189static inline int
190bitmap_ipmac_do_list(struct sk_buff *skb, const struct bitmap_ipmac *map,
ca134ce8 191 u32 id, size_t dsize)
de76021a 192{
b0da3905 193 const struct bitmap_ipmac_elem *elem =
ca134ce8 194 get_elem(map->extensions, id, dsize);
de76021a 195
b0da3905
JK
196 return nla_put_ipaddr4(skb, IPSET_ATTR_IP,
197 htonl(map->first_ip + id)) ||
198 (elem->filled == MAC_FILLED &&
199 nla_put(skb, IPSET_ATTR_ETHER, ETH_ALEN, elem->ether));
200}
de76021a 201
b0da3905
JK
202static inline int
203bitmap_ipmac_do_head(struct sk_buff *skb, const struct bitmap_ipmac *map)
204{
205 return nla_put_ipaddr4(skb, IPSET_ATTR_IP, htonl(map->first_ip)) ||
206 nla_put_ipaddr4(skb, IPSET_ATTR_IP_TO, htonl(map->last_ip));
de76021a
JK
207}
208
209static int
210bitmap_ipmac_kadt(struct ip_set *set, const struct sk_buff *skb,
b66554cf 211 const struct xt_action_param *par,
b0da3905 212 enum ipset_adt adt, struct ip_set_adt_opt *opt)
de76021a
JK
213{
214 struct bitmap_ipmac *map = set->data;
215 ipset_adtfn adtfn = set->variant->adt[adt];
94729f8a 216 struct bitmap_ipmac_adt_elem e = { .id = 0 };
ca134ce8 217 struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set);
b0da3905 218 u32 ip;
de76021a 219
0e8a835a 220 /* MAC can be src only */
ac8cc925 221 if (!(opt->flags & IPSET_DIM_TWO_SRC))
0e8a835a
JK
222 return 0;
223
b0da3905
JK
224 ip = ntohl(ip4addr(skb, opt->flags & IPSET_DIM_ONE_SRC));
225 if (ip < map->first_ip || ip > map->last_ip)
de76021a
JK
226 return -IPSET_ERR_BITMAP_RANGE;
227
228 /* Backward compatibility: we don't check the second flag */
229 if (skb_mac_header(skb) < skb->head ||
230 (skb_mac_header(skb) + ETH_HLEN) > skb->data)
231 return -EINVAL;
232
b0da3905
JK
233 e.id = ip_to_id(map, ip);
234 e.ether = eth_hdr(skb)->h_source;
de76021a 235
b0da3905 236 return adtfn(set, &e, &ext, &opt->ext, opt->cmdflags);
de76021a
JK
237}
238
239static int
240bitmap_ipmac_uadt(struct ip_set *set, struct nlattr *tb[],
3d14b171 241 enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
de76021a
JK
242{
243 const struct bitmap_ipmac *map = set->data;
244 ipset_adtfn adtfn = set->variant->adt[adt];
94729f8a 245 struct bitmap_ipmac_adt_elem e = { .id = 0 };
ca134ce8 246 struct ip_set_ext ext = IP_SET_INIT_UEXT(set);
20b2fab4 247 u32 ip = 0;
de76021a
JK
248 int ret = 0;
249
de76021a
JK
250 if (tb[IPSET_ATTR_LINENO])
251 *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
252
a212e08e
SP
253 if (unlikely(!tb[IPSET_ATTR_IP]))
254 return -IPSET_ERR_PROTOCOL;
255
8e55d2e5
SP
256 ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP], &ip);
257 if (ret)
258 return ret;
259
260 ret = ip_set_get_extensions(set, tb, &ext);
de76021a
JK
261 if (ret)
262 return ret;
263
b0da3905 264 if (ip < map->first_ip || ip > map->last_ip)
de76021a
JK
265 return -IPSET_ERR_BITMAP_RANGE;
266
b0da3905 267 e.id = ip_to_id(map, ip);
de76021a 268 if (tb[IPSET_ATTR_ETHER])
b0da3905 269 e.ether = nla_data(tb[IPSET_ATTR_ETHER]);
de76021a 270 else
b0da3905 271 e.ether = NULL;
de76021a 272
b0da3905 273 ret = adtfn(set, &e, &ext, &ext, flags);
de76021a
JK
274
275 return ip_set_eexist(ret, flags) ? 0 : ret;
276}
277
de76021a
JK
278static bool
279bitmap_ipmac_same_set(const struct ip_set *a, const struct ip_set *b)
280{
281 const struct bitmap_ipmac *x = a->data;
282 const struct bitmap_ipmac *y = b->data;
283
284 return x->first_ip == y->first_ip &&
285 x->last_ip == y->last_ip &&
ca134ce8 286 a->timeout == b->timeout &&
b0da3905 287 a->extensions == b->extensions;
de76021a
JK
288}
289
b0da3905 290/* Plain variant */
de76021a 291
b0da3905 292#include "ip_set_bitmap_gen.h"
de76021a
JK
293
294/* Create bitmap:ip,mac type of sets */
295
296static bool
297init_map_ipmac(struct ip_set *set, struct bitmap_ipmac *map,
b0da3905 298 u32 first_ip, u32 last_ip, u32 elements)
de76021a 299{
03c8b234 300 map->members = ip_set_alloc(map->memsize);
de76021a
JK
301 if (!map->members)
302 return false;
ca134ce8
JK
303 if (set->dsize) {
304 map->extensions = ip_set_alloc(set->dsize * elements);
b0da3905
JK
305 if (!map->extensions) {
306 kfree(map->members);
307 return false;
308 }
309 }
de76021a
JK
310 map->first_ip = first_ip;
311 map->last_ip = last_ip;
b0da3905 312 map->elements = elements;
ca134ce8 313 set->timeout = IPSET_NO_TIMEOUT;
de76021a
JK
314
315 set->data = map;
c15f1c83 316 set->family = NFPROTO_IPV4;
de76021a
JK
317
318 return true;
319}
320
321static int
1785e8f4 322bitmap_ipmac_create(struct net *net, struct ip_set *set, struct nlattr *tb[],
de76021a
JK
323 u32 flags)
324{
03c8b234 325 u32 first_ip = 0, last_ip = 0;
b9fed748 326 u64 elements;
de76021a
JK
327 struct bitmap_ipmac *map;
328 int ret;
329
330 if (unlikely(!tb[IPSET_ATTR_IP] ||
f48d19db
JK
331 !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) ||
332 !ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS)))
de76021a
JK
333 return -IPSET_ERR_PROTOCOL;
334
335 ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP], &first_ip);
336 if (ret)
337 return ret;
338
339 if (tb[IPSET_ATTR_IP_TO]) {
340 ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP_TO], &last_ip);
341 if (ret)
342 return ret;
343 if (first_ip > last_ip) {
344 u32 tmp = first_ip;
345
346 first_ip = last_ip;
347 last_ip = tmp;
348 }
349 } else if (tb[IPSET_ATTR_CIDR]) {
350 u8 cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]);
351
cabfd139 352 if (cidr >= HOST_MASK)
de76021a 353 return -IPSET_ERR_INVALID_CIDR;
e6146e86 354 ip_set_mask_from_to(first_ip, last_ip, cidr);
de76021a
JK
355 } else
356 return -IPSET_ERR_PROTOCOL;
357
b9fed748 358 elements = (u64)last_ip - first_ip + 1;
de76021a
JK
359
360 if (elements > IPSET_BITMAP_MAX_RANGE + 1)
361 return -IPSET_ERR_BITMAP_RANGE_SIZE;
362
363 map = kzalloc(sizeof(*map), GFP_KERNEL);
364 if (!map)
365 return -ENOMEM;
366
b0da3905
JK
367 map->memsize = bitmap_bytes(0, elements - 1);
368 set->variant = &bitmap_ipmac;
03c8b234
JK
369 set->dsize = ip_set_elem_len(set, tb,
370 sizeof(struct bitmap_ipmac_elem));
371 if (!init_map_ipmac(set, map, first_ip, last_ip, elements)) {
372 kfree(map);
373 return -ENOMEM;
374 }
375 if (tb[IPSET_ATTR_TIMEOUT]) {
ca134ce8 376 set->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
b0da3905 377 bitmap_ipmac_gc_init(set, bitmap_ipmac_gc);
de76021a
JK
378 }
379 return 0;
380}
381
382static struct ip_set_type bitmap_ipmac_type = {
383 .name = "bitmap:ip,mac",
384 .protocol = IPSET_PROTOCOL,
385 .features = IPSET_TYPE_IP | IPSET_TYPE_MAC,
386 .dimension = IPSET_DIM_TWO,
c15f1c83 387 .family = NFPROTO_IPV4,
35b8dcf8
JK
388 .revision_min = IPSET_TYPE_REV_MIN,
389 .revision_max = IPSET_TYPE_REV_MAX,
de76021a
JK
390 .create = bitmap_ipmac_create,
391 .create_policy = {
392 [IPSET_ATTR_IP] = { .type = NLA_NESTED },
393 [IPSET_ATTR_IP_TO] = { .type = NLA_NESTED },
394 [IPSET_ATTR_CIDR] = { .type = NLA_U8 },
395 [IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 },
f48d19db 396 [IPSET_ATTR_CADT_FLAGS] = { .type = NLA_U32 },
de76021a
JK
397 },
398 .adt_policy = {
399 [IPSET_ATTR_IP] = { .type = NLA_NESTED },
15b4d93f
JK
400 [IPSET_ATTR_ETHER] = { .type = NLA_BINARY,
401 .len = ETH_ALEN },
de76021a
JK
402 [IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 },
403 [IPSET_ATTR_LINENO] = { .type = NLA_U32 },
f48d19db
JK
404 [IPSET_ATTR_BYTES] = { .type = NLA_U64 },
405 [IPSET_ATTR_PACKETS] = { .type = NLA_U64 },
03726186
SP
406 [IPSET_ATTR_COMMENT] = { .type = NLA_NUL_STRING,
407 .len = IPSET_MAX_COMMENT_SIZE },
39d1ecf1
AD
408 [IPSET_ATTR_SKBMARK] = { .type = NLA_U64 },
409 [IPSET_ATTR_SKBPRIO] = { .type = NLA_U32 },
410 [IPSET_ATTR_SKBQUEUE] = { .type = NLA_U16 },
de76021a
JK
411 },
412 .me = THIS_MODULE,
413};
414
415static int __init
416bitmap_ipmac_init(void)
417{
418 return ip_set_type_register(&bitmap_ipmac_type);
419}
420
421static void __exit
422bitmap_ipmac_fini(void)
423{
96f51428 424 rcu_barrier();
de76021a
JK
425 ip_set_type_unregister(&bitmap_ipmac_type);
426}
427
428module_init(bitmap_ipmac_init);
429module_exit(bitmap_ipmac_fini);