]> git.karo-electronics.de Git - karo-tx-linux.git/blob - net/netfilter/ipset/ip_set_bitmap_ipmac.c
Merge remote-tracking branch 'slave-dma/next'
[karo-tx-linux.git] / net / netfilter / ipset / ip_set_bitmap_ipmac.c
1 /* Copyright (C) 2000-2002 Joakim Axelsson <gozem@linux.nu>
2  *                         Patrick Schaaf <bof@bof.de>
3  *                         Martin Josefsson <gandalf@wlug.westbo.se>
4  * Copyright (C) 2003-2013 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 /* 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>
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>
26 #include <linux/netfilter/ipset/ip_set_bitmap.h>
27
28 #define REVISION_MIN    0
29 #define REVISION_MAX    1       /* Counter support added */
30
31 MODULE_LICENSE("GPL");
32 MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
33 IP_SET_MODULE_DESC("bitmap:ip,mac", REVISION_MIN, REVISION_MAX);
34 MODULE_ALIAS("ip_set_bitmap:ip,mac");
35
36 #define MTYPE           bitmap_ipmac
37 #define IP_SET_BITMAP_STORED_TIMEOUT
38
39 enum {
40         MAC_UNSET,              /* element is set, without MAC */
41         MAC_FILLED,             /* element is set with MAC */
42 };
43
44 /* Type structure */
45 struct bitmap_ipmac {
46         void *members;          /* the set members */
47         void *extensions;       /* MAC + data extensions */
48         u32 first_ip;           /* host byte order, included in range */
49         u32 last_ip;            /* host byte order, included in range */
50         u32 elements;           /* number of max elements in the set */
51         u32 timeout;            /* timeout value */
52         struct timer_list gc;   /* garbage collector */
53         size_t memsize;         /* members size */
54         size_t dsize;           /* size of element */
55         size_t offset[IPSET_OFFSET_MAX]; /* Offsets to extensions */
56 };
57
58 /* ADT structure for generic function args */
59 struct bitmap_ipmac_adt_elem {
60         u16 id;
61         unsigned char *ether;
62 };
63
64 struct bitmap_ipmac_elem {
65         unsigned char ether[ETH_ALEN];
66         unsigned char filled;
67 } __attribute__ ((aligned));
68
69 static inline u32
70 ip_to_id(const struct bitmap_ipmac *m, u32 ip)
71 {
72         return ip - m->first_ip;
73 }
74
75 static inline struct bitmap_ipmac_elem *
76 get_elem(void *extensions, u16 id, size_t dsize)
77 {
78         return (struct bitmap_ipmac_elem *)(extensions + id * dsize);
79 }
80
81 /* Common functions */
82
83 static inline int
84 bitmap_ipmac_do_test(const struct bitmap_ipmac_adt_elem *e,
85                      const struct bitmap_ipmac *map)
86 {
87         const struct bitmap_ipmac_elem *elem;
88
89         if (!test_bit(e->id, map->members))
90                 return 0;
91         elem = get_elem(map->extensions, e->id, map->dsize);
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;
97 }
98
99 static inline int
100 bitmap_ipmac_gc_test(u16 id, const struct bitmap_ipmac *map)
101 {
102         const struct bitmap_ipmac_elem *elem;
103
104         if (!test_bit(id, map->members))
105                 return 0;
106         elem = get_elem(map->extensions, id, map->dsize);
107         /* Timer not started for the incomplete elements */
108         return elem->filled == MAC_FILLED;
109 }
110
111 static inline int
112 bitmap_ipmac_is_filled(const struct bitmap_ipmac_elem *elem)
113 {
114         return elem->filled == MAC_FILLED;
115 }
116
117 static inline int
118 bitmap_ipmac_add_timeout(unsigned long *timeout,
119                          const struct bitmap_ipmac_adt_elem *e,
120                          const struct ip_set_ext *ext,
121                          struct bitmap_ipmac *map, int mode)
122 {
123         u32 t = ext->timeout;
124
125         if (mode == IPSET_ADD_START_STORED_TIMEOUT) {
126                 if (t == map->timeout)
127                         /* Timeout was not specified, get stored one */
128                         t = *timeout;
129                 ip_set_timeout_set(timeout, t);
130         } else {
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 */
135                 if (e->ether)
136                         ip_set_timeout_set(timeout, t);
137                 else
138                         *timeout = t;
139         }
140         return 0;
141 }
142
143 static inline int
144 bitmap_ipmac_do_add(const struct bitmap_ipmac_adt_elem *e,
145                     struct bitmap_ipmac *map, u32 flags)
146 {
147         struct bitmap_ipmac_elem *elem;
148
149         elem = get_elem(map->extensions, e->id, map->dsize);
150         if (test_and_set_bit(e->id, map->members)) {
151                 if (elem->filled == MAC_FILLED) {
152                         if (e->ether && (flags & IPSET_FLAG_EXIST))
153                                 memcpy(elem->ether, e->ether, ETH_ALEN);
154                         return IPSET_ADD_FAILED;
155                 } else if (!e->ether)
156                         /* Already added without ethernet address */
157                         return IPSET_ADD_FAILED;
158                 /* Fill the MAC address and trigger the timer activation */
159                 memcpy(elem->ether, e->ether, ETH_ALEN);
160                 elem->filled = MAC_FILLED;
161                 return IPSET_ADD_START_STORED_TIMEOUT;
162         } else if (e->ether) {
163                 /* We can store MAC too */
164                 memcpy(elem->ether, e->ether, ETH_ALEN);
165                 elem->filled = MAC_FILLED;
166                 return 0;
167         } else {
168                 elem->filled = MAC_UNSET;
169                 /* MAC is not stored yet, don't start timer */
170                 return IPSET_ADD_STORE_PLAIN_TIMEOUT;
171         }
172 }
173
174 static inline int
175 bitmap_ipmac_do_del(const struct bitmap_ipmac_adt_elem *e,
176                     struct bitmap_ipmac *map)
177 {
178         return !test_and_clear_bit(e->id, map->members);
179 }
180
181 static inline unsigned long
182 ip_set_timeout_stored(struct bitmap_ipmac *map, u32 id, unsigned long *timeout)
183 {
184         const struct bitmap_ipmac_elem *elem =
185                 get_elem(map->extensions, id, map->dsize);
186
187         return elem->filled == MAC_FILLED ? ip_set_timeout_get(timeout) :
188                                             *timeout;
189 }
190
191 static inline int
192 bitmap_ipmac_do_list(struct sk_buff *skb, const struct bitmap_ipmac *map,
193                      u32 id)
194 {
195         const struct bitmap_ipmac_elem *elem =
196                 get_elem(map->extensions, id, map->dsize);
197
198         return nla_put_ipaddr4(skb, IPSET_ATTR_IP,
199                                htonl(map->first_ip + id)) ||
200                (elem->filled == MAC_FILLED &&
201                 nla_put(skb, IPSET_ATTR_ETHER, ETH_ALEN, elem->ether));
202 }
203
204 static inline int
205 bitmap_ipmac_do_head(struct sk_buff *skb, const struct bitmap_ipmac *map)
206 {
207         return nla_put_ipaddr4(skb, IPSET_ATTR_IP, htonl(map->first_ip)) ||
208                nla_put_ipaddr4(skb, IPSET_ATTR_IP_TO, htonl(map->last_ip));
209 }
210
211 static int
212 bitmap_ipmac_kadt(struct ip_set *set, const struct sk_buff *skb,
213                   const struct xt_action_param *par,
214                   enum ipset_adt adt, struct ip_set_adt_opt *opt)
215 {
216         struct bitmap_ipmac *map = set->data;
217         ipset_adtfn adtfn = set->variant->adt[adt];
218         struct bitmap_ipmac_adt_elem e = {};
219         struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, map);
220         u32 ip;
221
222         /* MAC can be src only */
223         if (!(opt->flags & IPSET_DIM_TWO_SRC))
224                 return 0;
225
226         ip = ntohl(ip4addr(skb, opt->flags & IPSET_DIM_ONE_SRC));
227         if (ip < map->first_ip || ip > map->last_ip)
228                 return -IPSET_ERR_BITMAP_RANGE;
229
230         /* Backward compatibility: we don't check the second flag */
231         if (skb_mac_header(skb) < skb->head ||
232             (skb_mac_header(skb) + ETH_HLEN) > skb->data)
233                 return -EINVAL;
234
235         e.id = ip_to_id(map, ip);
236         e.ether = eth_hdr(skb)->h_source;
237
238         return adtfn(set, &e, &ext, &opt->ext, opt->cmdflags);
239 }
240
241 static int
242 bitmap_ipmac_uadt(struct ip_set *set, struct nlattr *tb[],
243                   enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
244 {
245         const struct bitmap_ipmac *map = set->data;
246         ipset_adtfn adtfn = set->variant->adt[adt];
247         struct bitmap_ipmac_adt_elem e = {};
248         struct ip_set_ext ext = IP_SET_INIT_UEXT(map);
249         u32 ip;
250         int ret = 0;
251
252         if (unlikely(!tb[IPSET_ATTR_IP] ||
253                      !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) ||
254                      !ip_set_optattr_netorder(tb, IPSET_ATTR_PACKETS) ||
255                      !ip_set_optattr_netorder(tb, IPSET_ATTR_BYTES)))
256                 return -IPSET_ERR_PROTOCOL;
257
258         if (tb[IPSET_ATTR_LINENO])
259                 *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
260
261         ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP], &ip) ||
262               ip_set_get_extensions(set, tb, &ext);
263         if (ret)
264                 return ret;
265
266         if (ip < map->first_ip || ip > map->last_ip)
267                 return -IPSET_ERR_BITMAP_RANGE;
268
269         e.id = ip_to_id(map, ip);
270         if (tb[IPSET_ATTR_ETHER])
271                 e.ether = nla_data(tb[IPSET_ATTR_ETHER]);
272         else
273                 e.ether = NULL;
274
275         ret = adtfn(set, &e, &ext, &ext, flags);
276
277         return ip_set_eexist(ret, flags) ? 0 : ret;
278 }
279
280 static bool
281 bitmap_ipmac_same_set(const struct ip_set *a, const struct ip_set *b)
282 {
283         const struct bitmap_ipmac *x = a->data;
284         const struct bitmap_ipmac *y = b->data;
285
286         return x->first_ip == y->first_ip &&
287                x->last_ip == y->last_ip &&
288                x->timeout == y->timeout &&
289                a->extensions == b->extensions;
290 }
291
292 /* Plain variant */
293
294 /* Timeout variant */
295
296 struct bitmap_ipmact_elem {
297         struct {
298                 unsigned char ether[ETH_ALEN];
299                 unsigned char filled;
300         } __attribute__ ((aligned));
301         unsigned long timeout;
302 };
303
304 /* Plain variant with counter */
305
306 struct bitmap_ipmacc_elem {
307         struct {
308                 unsigned char ether[ETH_ALEN];
309                 unsigned char filled;
310         } __attribute__ ((aligned));
311         struct ip_set_counter counter;
312 };
313
314 /* Timeout variant with counter */
315
316 struct bitmap_ipmacct_elem {
317         struct {
318                 unsigned char ether[ETH_ALEN];
319                 unsigned char filled;
320         } __attribute__ ((aligned));
321         unsigned long timeout;
322         struct ip_set_counter counter;
323 };
324
325 #include "ip_set_bitmap_gen.h"
326
327 /* Create bitmap:ip,mac type of sets */
328
329 static bool
330 init_map_ipmac(struct ip_set *set, struct bitmap_ipmac *map,
331                u32 first_ip, u32 last_ip, u32 elements)
332 {
333         map->members = ip_set_alloc((last_ip - first_ip + 1) * map->dsize);
334         if (!map->members)
335                 return false;
336         if (map->dsize) {
337                 map->extensions = ip_set_alloc(map->dsize * elements);
338                 if (!map->extensions) {
339                         kfree(map->members);
340                         return false;
341                 }
342         }
343         map->first_ip = first_ip;
344         map->last_ip = last_ip;
345         map->elements = elements;
346         map->timeout = IPSET_NO_TIMEOUT;
347
348         set->data = map;
349         set->family = NFPROTO_IPV4;
350
351         return true;
352 }
353
354 static int
355 bitmap_ipmac_create(struct ip_set *set, struct nlattr *tb[],
356                     u32 flags)
357 {
358         u32 first_ip, last_ip, cadt_flags = 0;
359         u64 elements;
360         struct bitmap_ipmac *map;
361         int ret;
362
363         if (unlikely(!tb[IPSET_ATTR_IP] ||
364                      !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) ||
365                      !ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS)))
366                 return -IPSET_ERR_PROTOCOL;
367
368         ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP], &first_ip);
369         if (ret)
370                 return ret;
371
372         if (tb[IPSET_ATTR_IP_TO]) {
373                 ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP_TO], &last_ip);
374                 if (ret)
375                         return ret;
376                 if (first_ip > last_ip) {
377                         u32 tmp = first_ip;
378
379                         first_ip = last_ip;
380                         last_ip = tmp;
381                 }
382         } else if (tb[IPSET_ATTR_CIDR]) {
383                 u8 cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]);
384
385                 if (cidr >= 32)
386                         return -IPSET_ERR_INVALID_CIDR;
387                 ip_set_mask_from_to(first_ip, last_ip, cidr);
388         } else
389                 return -IPSET_ERR_PROTOCOL;
390
391         elements = (u64)last_ip - first_ip + 1;
392
393         if (elements > IPSET_BITMAP_MAX_RANGE + 1)
394                 return -IPSET_ERR_BITMAP_RANGE_SIZE;
395
396         map = kzalloc(sizeof(*map), GFP_KERNEL);
397         if (!map)
398                 return -ENOMEM;
399
400         map->memsize = bitmap_bytes(0, elements - 1);
401         set->variant = &bitmap_ipmac;
402         if (tb[IPSET_ATTR_CADT_FLAGS])
403                 cadt_flags = ip_set_get_h32(tb[IPSET_ATTR_CADT_FLAGS]);
404         if (cadt_flags & IPSET_FLAG_WITH_COUNTERS) {
405                 set->extensions |= IPSET_EXT_COUNTER;
406                 if (tb[IPSET_ATTR_TIMEOUT]) {
407                         map->dsize = sizeof(struct bitmap_ipmacct_elem);
408                         map->offset[IPSET_OFFSET_TIMEOUT] =
409                                 offsetof(struct bitmap_ipmacct_elem, timeout);
410                         map->offset[IPSET_OFFSET_COUNTER] =
411                                 offsetof(struct bitmap_ipmacct_elem, counter);
412
413                         if (!init_map_ipmac(set, map, first_ip, last_ip,
414                                             elements)) {
415                                 kfree(map);
416                                 return -ENOMEM;
417                         }
418                         map->timeout = ip_set_timeout_uget(
419                                 tb[IPSET_ATTR_TIMEOUT]);
420                         set->extensions |= IPSET_EXT_TIMEOUT;
421                         bitmap_ipmac_gc_init(set, bitmap_ipmac_gc);
422                 } else {
423                         map->dsize = sizeof(struct bitmap_ipmacc_elem);
424                         map->offset[IPSET_OFFSET_COUNTER] =
425                                 offsetof(struct bitmap_ipmacc_elem, counter);
426
427                         if (!init_map_ipmac(set, map, first_ip, last_ip,
428                                             elements)) {
429                                 kfree(map);
430                                 return -ENOMEM;
431                         }
432                 }
433         } else if (tb[IPSET_ATTR_TIMEOUT]) {
434                 map->dsize = sizeof(struct bitmap_ipmact_elem);
435                 map->offset[IPSET_OFFSET_TIMEOUT] =
436                         offsetof(struct bitmap_ipmact_elem, timeout);
437
438                 if (!init_map_ipmac(set, map, first_ip, last_ip, elements)) {
439                         kfree(map);
440                         return -ENOMEM;
441                 }
442                 map->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
443                 set->extensions |= IPSET_EXT_TIMEOUT;
444                 bitmap_ipmac_gc_init(set, bitmap_ipmac_gc);
445         } else {
446                 map->dsize = sizeof(struct bitmap_ipmac_elem);
447
448                 if (!init_map_ipmac(set, map, first_ip, last_ip, elements)) {
449                         kfree(map);
450                         return -ENOMEM;
451                 }
452                 set->variant = &bitmap_ipmac;
453         }
454         return 0;
455 }
456
457 static struct ip_set_type bitmap_ipmac_type = {
458         .name           = "bitmap:ip,mac",
459         .protocol       = IPSET_PROTOCOL,
460         .features       = IPSET_TYPE_IP | IPSET_TYPE_MAC,
461         .dimension      = IPSET_DIM_TWO,
462         .family         = NFPROTO_IPV4,
463         .revision_min   = REVISION_MIN,
464         .revision_max   = REVISION_MAX,
465         .create         = bitmap_ipmac_create,
466         .create_policy  = {
467                 [IPSET_ATTR_IP]         = { .type = NLA_NESTED },
468                 [IPSET_ATTR_IP_TO]      = { .type = NLA_NESTED },
469                 [IPSET_ATTR_CIDR]       = { .type = NLA_U8 },
470                 [IPSET_ATTR_TIMEOUT]    = { .type = NLA_U32 },
471                 [IPSET_ATTR_CADT_FLAGS] = { .type = NLA_U32 },
472         },
473         .adt_policy     = {
474                 [IPSET_ATTR_IP]         = { .type = NLA_NESTED },
475                 [IPSET_ATTR_ETHER]      = { .type = NLA_BINARY,
476                                             .len  = ETH_ALEN },
477                 [IPSET_ATTR_TIMEOUT]    = { .type = NLA_U32 },
478                 [IPSET_ATTR_LINENO]     = { .type = NLA_U32 },
479                 [IPSET_ATTR_BYTES]      = { .type = NLA_U64 },
480                 [IPSET_ATTR_PACKETS]    = { .type = NLA_U64 },
481         },
482         .me             = THIS_MODULE,
483 };
484
485 static int __init
486 bitmap_ipmac_init(void)
487 {
488         return ip_set_type_register(&bitmap_ipmac_type);
489 }
490
491 static void __exit
492 bitmap_ipmac_fini(void)
493 {
494         ip_set_type_unregister(&bitmap_ipmac_type);
495 }
496
497 module_init(bitmap_ipmac_init);
498 module_exit(bitmap_ipmac_fini);