blob: 740eabededd9754b7db95a9d46d48f8a1f283bf7 [file] [log] [blame]
Jozsef Kadlecsikde760212011-02-01 15:35:12 +01001/* Copyright (C) 2000-2002 Joakim Axelsson <gozem@linux.nu>
2 * Patrick Schaaf <bof@bof.de>
3 * Martin Josefsson <gandalf@wlug.westbo.se>
Jozsef Kadlecsikb0da3902013-04-27 14:37:01 +02004 * Copyright (C) 2003-2013 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
Jozsef Kadlecsikde760212011-02-01 15:35:12 +01005 *
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>
Jozsef Kadlecsikde760212011-02-01 15:35:12 +010018#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>
Jozsef Kadlecsikde760212011-02-01 15:35:12 +010026#include <linux/netfilter/ipset/ip_set_bitmap.h>
27
Jozsef Kadlecsik35b8dcf2013-04-30 23:02:43 +020028#define IPSET_TYPE_REV_MIN 0
Oliver Smithb90cb8b2013-09-22 20:56:32 +020029/* 1 Counter support added */
30#define IPSET_TYPE_REV_MAX 2 /* Comment support added */
Jozsef Kadlecsik10111a62012-09-21 21:59:32 +020031
Jozsef Kadlecsikde760212011-02-01 15:35:12 +010032MODULE_LICENSE("GPL");
33MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
Jozsef Kadlecsik35b8dcf2013-04-30 23:02:43 +020034IP_SET_MODULE_DESC("bitmap:ip,mac", IPSET_TYPE_REV_MIN, IPSET_TYPE_REV_MAX);
Jozsef Kadlecsikde760212011-02-01 15:35:12 +010035MODULE_ALIAS("ip_set_bitmap:ip,mac");
36
Jozsef Kadlecsikb0da3902013-04-27 14:37:01 +020037#define MTYPE bitmap_ipmac
38#define IP_SET_BITMAP_STORED_TIMEOUT
39
Jozsef Kadlecsikde760212011-02-01 15:35:12 +010040enum {
Jozsef Kadlecsikde760212011-02-01 15:35:12 +010041 MAC_UNSET, /* element is set, without MAC */
Jozsef Kadlecsikb0da3902013-04-27 14:37:01 +020042 MAC_FILLED, /* element is set with MAC */
Jozsef Kadlecsikde760212011-02-01 15:35:12 +010043};
44
45/* Type structure */
46struct bitmap_ipmac {
47 void *members; /* the set members */
Jozsef Kadlecsikb0da3902013-04-27 14:37:01 +020048 void *extensions; /* MAC + data extensions */
Jozsef Kadlecsikde760212011-02-01 15:35:12 +010049 u32 first_ip; /* host byte order, included in range */
50 u32 last_ip; /* host byte order, included in range */
Jozsef Kadlecsikb0da3902013-04-27 14:37:01 +020051 u32 elements; /* number of max elements in the set */
Jozsef Kadlecsikb0da3902013-04-27 14:37:01 +020052 size_t memsize; /* members size */
Jozsef Kadlecsikca134ce2013-09-07 00:10:07 +020053 struct timer_list gc; /* garbage collector */
Jozsef Kadlecsikde760212011-02-01 15:35:12 +010054};
55
56/* ADT structure for generic function args */
Jozsef Kadlecsikb0da3902013-04-27 14:37:01 +020057struct bitmap_ipmac_adt_elem {
58 u16 id;
59 unsigned char *ether;
Jozsef Kadlecsikde760212011-02-01 15:35:12 +010060};
61
Jozsef Kadlecsikb0da3902013-04-27 14:37:01 +020062struct bitmap_ipmac_elem {
Jozsef Kadlecsikde760212011-02-01 15:35:12 +010063 unsigned char ether[ETH_ALEN];
Jozsef Kadlecsikb0da3902013-04-27 14:37:01 +020064 unsigned char filled;
Jozsef Kadlecsikde760212011-02-01 15:35:12 +010065} __attribute__ ((aligned));
66
Jozsef Kadlecsikb0da3902013-04-27 14:37:01 +020067static inline u32
68ip_to_id(const struct bitmap_ipmac *m, u32 ip)
Jozsef Kadlecsikde760212011-02-01 15:35:12 +010069{
Jozsef Kadlecsikb0da3902013-04-27 14:37:01 +020070 return ip - m->first_ip;
Jozsef Kadlecsikde760212011-02-01 15:35:12 +010071}
72
Jozsef Kadlecsikb0da3902013-04-27 14:37:01 +020073static inline struct bitmap_ipmac_elem *
74get_elem(void *extensions, u16 id, size_t dsize)
Jozsef Kadlecsikde760212011-02-01 15:35:12 +010075{
Jozsef Kadlecsikb0da3902013-04-27 14:37:01 +020076 return (struct bitmap_ipmac_elem *)(extensions + id * dsize);
Jozsef Kadlecsikde760212011-02-01 15:35:12 +010077}
78
Jozsef Kadlecsikb0da3902013-04-27 14:37:01 +020079/* Common functions */
Jozsef Kadlecsikde760212011-02-01 15:35:12 +010080
Jozsef Kadlecsikb0da3902013-04-27 14:37:01 +020081static inline int
82bitmap_ipmac_do_test(const struct bitmap_ipmac_adt_elem *e,
Jozsef Kadlecsikca134ce2013-09-07 00:10:07 +020083 const struct bitmap_ipmac *map, size_t dsize)
Jozsef Kadlecsikb0da3902013-04-27 14:37:01 +020084{
85 const struct bitmap_ipmac_elem *elem;
86
87 if (!test_bit(e->id, map->members))
88 return 0;
Jozsef Kadlecsikca134ce2013-09-07 00:10:07 +020089 elem = get_elem(map->extensions, e->id, dsize);
Jozsef Kadlecsikb0da3902013-04-27 14:37:01 +020090 if (elem->filled == MAC_FILLED)
91 return e->ether == NULL ||
92 ether_addr_equal(e->ether, elem->ether);
93 /* Trigger kernel to fill out the ethernet address */
94 return -EAGAIN;
Jozsef Kadlecsikde760212011-02-01 15:35:12 +010095}
96
97static inline int
Jozsef Kadlecsikca134ce2013-09-07 00:10:07 +020098bitmap_ipmac_gc_test(u16 id, const struct bitmap_ipmac *map, size_t dsize)
Jozsef Kadlecsikde760212011-02-01 15:35:12 +010099{
Jozsef Kadlecsikb0da3902013-04-27 14:37:01 +0200100 const struct bitmap_ipmac_elem *elem;
101
102 if (!test_bit(id, map->members))
103 return 0;
Jozsef Kadlecsikca134ce2013-09-07 00:10:07 +0200104 elem = get_elem(map->extensions, id, dsize);
Jozsef Kadlecsikb0da3902013-04-27 14:37:01 +0200105 /* Timer not started for the incomplete elements */
106 return elem->filled == MAC_FILLED;
Jozsef Kadlecsikde760212011-02-01 15:35:12 +0100107}
108
Jozsef Kadlecsikb0da3902013-04-27 14:37:01 +0200109static inline int
110bitmap_ipmac_is_filled(const struct bitmap_ipmac_elem *elem)
Jozsef Kadlecsikde760212011-02-01 15:35:12 +0100111{
Jozsef Kadlecsikb0da3902013-04-27 14:37:01 +0200112 return elem->filled == MAC_FILLED;
Jozsef Kadlecsikde760212011-02-01 15:35:12 +0100113}
114
Jozsef Kadlecsikb0da3902013-04-27 14:37:01 +0200115static inline int
116bitmap_ipmac_add_timeout(unsigned long *timeout,
117 const struct bitmap_ipmac_adt_elem *e,
Jozsef Kadlecsikca134ce2013-09-07 00:10:07 +0200118 const struct ip_set_ext *ext, struct ip_set *set,
Jozsef Kadlecsikb0da3902013-04-27 14:37:01 +0200119 struct bitmap_ipmac *map, int mode)
Jozsef Kadlecsikde760212011-02-01 15:35:12 +0100120{
Jozsef Kadlecsikb0da3902013-04-27 14:37:01 +0200121 u32 t = ext->timeout;
Jozsef Kadlecsikde760212011-02-01 15:35:12 +0100122
Jozsef Kadlecsikb0da3902013-04-27 14:37:01 +0200123 if (mode == IPSET_ADD_START_STORED_TIMEOUT) {
Jozsef Kadlecsikca134ce2013-09-07 00:10:07 +0200124 if (t == set->timeout)
Jozsef Kadlecsikde760212011-02-01 15:35:12 +0100125 /* Timeout was not specified, get stored one */
Jozsef Kadlecsikb0da3902013-04-27 14:37:01 +0200126 t = *timeout;
127 ip_set_timeout_set(timeout, t);
128 } else {
Jozsef Kadlecsikde760212011-02-01 15:35:12 +0100129 /* If MAC is unset yet, we store plain timeout value
130 * because the timer is not activated yet
131 * and we can reuse it later when MAC is filled out,
132 * possibly by the kernel */
Jozsef Kadlecsikb0da3902013-04-27 14:37:01 +0200133 if (e->ether)
134 ip_set_timeout_set(timeout, t);
135 else
136 *timeout = t;
Jozsef Kadlecsikde760212011-02-01 15:35:12 +0100137 }
Jozsef Kadlecsikde760212011-02-01 15:35:12 +0100138 return 0;
139}
140
Jozsef Kadlecsikb0da3902013-04-27 14:37:01 +0200141static inline int
142bitmap_ipmac_do_add(const struct bitmap_ipmac_adt_elem *e,
Jozsef Kadlecsikca134ce2013-09-07 00:10:07 +0200143 struct bitmap_ipmac *map, u32 flags, size_t dsize)
Jozsef Kadlecsikde760212011-02-01 15:35:12 +0100144{
Jozsef Kadlecsikb0da3902013-04-27 14:37:01 +0200145 struct bitmap_ipmac_elem *elem;
Jozsef Kadlecsikde760212011-02-01 15:35:12 +0100146
Jozsef Kadlecsikca134ce2013-09-07 00:10:07 +0200147 elem = get_elem(map->extensions, e->id, dsize);
Jozsef Kadlecsikb0da3902013-04-27 14:37:01 +0200148 if (test_and_set_bit(e->id, map->members)) {
149 if (elem->filled == MAC_FILLED) {
150 if (e->ether && (flags & IPSET_FLAG_EXIST))
151 memcpy(elem->ether, e->ether, ETH_ALEN);
152 return IPSET_ADD_FAILED;
153 } else if (!e->ether)
154 /* Already added without ethernet address */
155 return IPSET_ADD_FAILED;
156 /* Fill the MAC address and trigger the timer activation */
157 memcpy(elem->ether, e->ether, ETH_ALEN);
158 elem->filled = MAC_FILLED;
159 return IPSET_ADD_START_STORED_TIMEOUT;
160 } else if (e->ether) {
161 /* We can store MAC too */
162 memcpy(elem->ether, e->ether, ETH_ALEN);
163 elem->filled = MAC_FILLED;
164 return 0;
165 } else {
166 elem->filled = MAC_UNSET;
167 /* MAC is not stored yet, don't start timer */
168 return IPSET_ADD_STORE_PLAIN_TIMEOUT;
169 }
Jozsef Kadlecsikde760212011-02-01 15:35:12 +0100170}
171
Jozsef Kadlecsikb0da3902013-04-27 14:37:01 +0200172static inline int
173bitmap_ipmac_do_del(const struct bitmap_ipmac_adt_elem *e,
174 struct bitmap_ipmac *map)
Jozsef Kadlecsikde760212011-02-01 15:35:12 +0100175{
Jozsef Kadlecsikb0da3902013-04-27 14:37:01 +0200176 return !test_and_clear_bit(e->id, map->members);
177}
Jozsef Kadlecsikde760212011-02-01 15:35:12 +0100178
Jozsef Kadlecsikb0da3902013-04-27 14:37:01 +0200179static inline int
180bitmap_ipmac_do_list(struct sk_buff *skb, const struct bitmap_ipmac *map,
Jozsef Kadlecsikca134ce2013-09-07 00:10:07 +0200181 u32 id, size_t dsize)
Jozsef Kadlecsikb0da3902013-04-27 14:37:01 +0200182{
183 const struct bitmap_ipmac_elem *elem =
Jozsef Kadlecsikca134ce2013-09-07 00:10:07 +0200184 get_elem(map->extensions, id, dsize);
Jozsef Kadlecsikb0da3902013-04-27 14:37:01 +0200185
186 return nla_put_ipaddr4(skb, IPSET_ATTR_IP,
187 htonl(map->first_ip + id)) ||
188 (elem->filled == MAC_FILLED &&
189 nla_put(skb, IPSET_ATTR_ETHER, ETH_ALEN, elem->ether));
190}
191
192static inline int
193bitmap_ipmac_do_head(struct sk_buff *skb, const struct bitmap_ipmac *map)
194{
195 return nla_put_ipaddr4(skb, IPSET_ATTR_IP, htonl(map->first_ip)) ||
196 nla_put_ipaddr4(skb, IPSET_ATTR_IP_TO, htonl(map->last_ip));
Jozsef Kadlecsikde760212011-02-01 15:35:12 +0100197}
198
199static int
200bitmap_ipmac_kadt(struct ip_set *set, const struct sk_buff *skb,
Jozsef Kadlecsikb66554c2011-06-16 18:56:47 +0200201 const struct xt_action_param *par,
Jozsef Kadlecsikb0da3902013-04-27 14:37:01 +0200202 enum ipset_adt adt, struct ip_set_adt_opt *opt)
Jozsef Kadlecsikde760212011-02-01 15:35:12 +0100203{
204 struct bitmap_ipmac *map = set->data;
205 ipset_adtfn adtfn = set->variant->adt[adt];
Jozsef Kadlecsikb0da3902013-04-27 14:37:01 +0200206 struct bitmap_ipmac_adt_elem e = {};
Jozsef Kadlecsikca134ce2013-09-07 00:10:07 +0200207 struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set);
Jozsef Kadlecsikb0da3902013-04-27 14:37:01 +0200208 u32 ip;
Jozsef Kadlecsikde760212011-02-01 15:35:12 +0100209
Jozsef Kadlecsik0e8a8352011-04-13 13:43:23 +0200210 /* MAC can be src only */
Jozsef Kadlecsikac8cc922011-06-16 18:42:40 +0200211 if (!(opt->flags & IPSET_DIM_TWO_SRC))
Jozsef Kadlecsik0e8a8352011-04-13 13:43:23 +0200212 return 0;
213
Jozsef Kadlecsikb0da3902013-04-27 14:37:01 +0200214 ip = ntohl(ip4addr(skb, opt->flags & IPSET_DIM_ONE_SRC));
215 if (ip < map->first_ip || ip > map->last_ip)
Jozsef Kadlecsikde760212011-02-01 15:35:12 +0100216 return -IPSET_ERR_BITMAP_RANGE;
217
218 /* Backward compatibility: we don't check the second flag */
219 if (skb_mac_header(skb) < skb->head ||
220 (skb_mac_header(skb) + ETH_HLEN) > skb->data)
221 return -EINVAL;
222
Jozsef Kadlecsikb0da3902013-04-27 14:37:01 +0200223 e.id = ip_to_id(map, ip);
224 e.ether = eth_hdr(skb)->h_source;
Jozsef Kadlecsikde760212011-02-01 15:35:12 +0100225
Jozsef Kadlecsikb0da3902013-04-27 14:37:01 +0200226 return adtfn(set, &e, &ext, &opt->ext, opt->cmdflags);
Jozsef Kadlecsikde760212011-02-01 15:35:12 +0100227}
228
229static int
230bitmap_ipmac_uadt(struct ip_set *set, struct nlattr *tb[],
Jozsef Kadlecsik3d14b172011-06-16 18:49:17 +0200231 enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
Jozsef Kadlecsikde760212011-02-01 15:35:12 +0100232{
233 const struct bitmap_ipmac *map = set->data;
234 ipset_adtfn adtfn = set->variant->adt[adt];
Jozsef Kadlecsikb0da3902013-04-27 14:37:01 +0200235 struct bitmap_ipmac_adt_elem e = {};
Jozsef Kadlecsikca134ce2013-09-07 00:10:07 +0200236 struct ip_set_ext ext = IP_SET_INIT_UEXT(set);
Jozsef Kadlecsik20b2fab2013-05-01 18:47:32 +0200237 u32 ip = 0;
Jozsef Kadlecsikde760212011-02-01 15:35:12 +0100238 int ret = 0;
239
240 if (unlikely(!tb[IPSET_ATTR_IP] ||
Jozsef Kadlecsikf48d19d2013-04-08 23:10:22 +0200241 !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) ||
242 !ip_set_optattr_netorder(tb, IPSET_ATTR_PACKETS) ||
243 !ip_set_optattr_netorder(tb, IPSET_ATTR_BYTES)))
Jozsef Kadlecsikde760212011-02-01 15:35:12 +0100244 return -IPSET_ERR_PROTOCOL;
245
246 if (tb[IPSET_ATTR_LINENO])
247 *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
248
Jozsef Kadlecsikb0da3902013-04-27 14:37:01 +0200249 ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP], &ip) ||
250 ip_set_get_extensions(set, tb, &ext);
Jozsef Kadlecsikde760212011-02-01 15:35:12 +0100251 if (ret)
252 return ret;
253
Jozsef Kadlecsikb0da3902013-04-27 14:37:01 +0200254 if (ip < map->first_ip || ip > map->last_ip)
Jozsef Kadlecsikde760212011-02-01 15:35:12 +0100255 return -IPSET_ERR_BITMAP_RANGE;
256
Jozsef Kadlecsikb0da3902013-04-27 14:37:01 +0200257 e.id = ip_to_id(map, ip);
Jozsef Kadlecsikde760212011-02-01 15:35:12 +0100258 if (tb[IPSET_ATTR_ETHER])
Jozsef Kadlecsikb0da3902013-04-27 14:37:01 +0200259 e.ether = nla_data(tb[IPSET_ATTR_ETHER]);
Jozsef Kadlecsikde760212011-02-01 15:35:12 +0100260 else
Jozsef Kadlecsikb0da3902013-04-27 14:37:01 +0200261 e.ether = NULL;
Jozsef Kadlecsikde760212011-02-01 15:35:12 +0100262
Jozsef Kadlecsikb0da3902013-04-27 14:37:01 +0200263 ret = adtfn(set, &e, &ext, &ext, flags);
Jozsef Kadlecsikde760212011-02-01 15:35:12 +0100264
265 return ip_set_eexist(ret, flags) ? 0 : ret;
266}
267
Jozsef Kadlecsikde760212011-02-01 15:35:12 +0100268static bool
269bitmap_ipmac_same_set(const struct ip_set *a, const struct ip_set *b)
270{
271 const struct bitmap_ipmac *x = a->data;
272 const struct bitmap_ipmac *y = b->data;
273
274 return x->first_ip == y->first_ip &&
275 x->last_ip == y->last_ip &&
Jozsef Kadlecsikca134ce2013-09-07 00:10:07 +0200276 a->timeout == b->timeout &&
Jozsef Kadlecsikb0da3902013-04-27 14:37:01 +0200277 a->extensions == b->extensions;
Jozsef Kadlecsikde760212011-02-01 15:35:12 +0100278}
279
Jozsef Kadlecsikb0da3902013-04-27 14:37:01 +0200280/* Plain variant */
281
Jozsef Kadlecsikb0da3902013-04-27 14:37:01 +0200282#include "ip_set_bitmap_gen.h"
Jozsef Kadlecsikde760212011-02-01 15:35:12 +0100283
284/* Create bitmap:ip,mac type of sets */
285
286static bool
287init_map_ipmac(struct ip_set *set, struct bitmap_ipmac *map,
Jozsef Kadlecsikb0da3902013-04-27 14:37:01 +0200288 u32 first_ip, u32 last_ip, u32 elements)
Jozsef Kadlecsikde760212011-02-01 15:35:12 +0100289{
Jozsef Kadlecsik03c8b232013-09-07 00:43:52 +0200290 map->members = ip_set_alloc(map->memsize);
Jozsef Kadlecsikde760212011-02-01 15:35:12 +0100291 if (!map->members)
292 return false;
Jozsef Kadlecsikca134ce2013-09-07 00:10:07 +0200293 if (set->dsize) {
294 map->extensions = ip_set_alloc(set->dsize * elements);
Jozsef Kadlecsikb0da3902013-04-27 14:37:01 +0200295 if (!map->extensions) {
296 kfree(map->members);
297 return false;
298 }
299 }
Jozsef Kadlecsikde760212011-02-01 15:35:12 +0100300 map->first_ip = first_ip;
301 map->last_ip = last_ip;
Jozsef Kadlecsikb0da3902013-04-27 14:37:01 +0200302 map->elements = elements;
Jozsef Kadlecsikca134ce2013-09-07 00:10:07 +0200303 set->timeout = IPSET_NO_TIMEOUT;
Jozsef Kadlecsikde760212011-02-01 15:35:12 +0100304
305 set->data = map;
Jan Engelhardtc15f1c82012-02-14 00:24:10 +0100306 set->family = NFPROTO_IPV4;
Jozsef Kadlecsikde760212011-02-01 15:35:12 +0100307
308 return true;
309}
310
311static int
Vitaly Lavrov1785e8f2013-09-30 17:07:02 +0200312bitmap_ipmac_create(struct net *net, struct ip_set *set, struct nlattr *tb[],
Jozsef Kadlecsikde760212011-02-01 15:35:12 +0100313 u32 flags)
314{
Jozsef Kadlecsik03c8b232013-09-07 00:43:52 +0200315 u32 first_ip = 0, last_ip = 0;
Jozsef Kadlecsikb9fed742012-09-04 17:45:59 +0200316 u64 elements;
Jozsef Kadlecsikde760212011-02-01 15:35:12 +0100317 struct bitmap_ipmac *map;
318 int ret;
319
320 if (unlikely(!tb[IPSET_ATTR_IP] ||
Jozsef Kadlecsikf48d19d2013-04-08 23:10:22 +0200321 !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) ||
322 !ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS)))
Jozsef Kadlecsikde760212011-02-01 15:35:12 +0100323 return -IPSET_ERR_PROTOCOL;
324
325 ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP], &first_ip);
326 if (ret)
327 return ret;
328
329 if (tb[IPSET_ATTR_IP_TO]) {
330 ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP_TO], &last_ip);
331 if (ret)
332 return ret;
333 if (first_ip > last_ip) {
334 u32 tmp = first_ip;
335
336 first_ip = last_ip;
337 last_ip = tmp;
338 }
339 } else if (tb[IPSET_ATTR_CIDR]) {
340 u8 cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]);
341
342 if (cidr >= 32)
343 return -IPSET_ERR_INVALID_CIDR;
Jozsef Kadlecsike6146e82011-06-16 18:55:58 +0200344 ip_set_mask_from_to(first_ip, last_ip, cidr);
Jozsef Kadlecsikde760212011-02-01 15:35:12 +0100345 } else
346 return -IPSET_ERR_PROTOCOL;
347
Jozsef Kadlecsikb9fed742012-09-04 17:45:59 +0200348 elements = (u64)last_ip - first_ip + 1;
Jozsef Kadlecsikde760212011-02-01 15:35:12 +0100349
350 if (elements > IPSET_BITMAP_MAX_RANGE + 1)
351 return -IPSET_ERR_BITMAP_RANGE_SIZE;
352
353 map = kzalloc(sizeof(*map), GFP_KERNEL);
354 if (!map)
355 return -ENOMEM;
356
Jozsef Kadlecsikb0da3902013-04-27 14:37:01 +0200357 map->memsize = bitmap_bytes(0, elements - 1);
358 set->variant = &bitmap_ipmac;
Jozsef Kadlecsik03c8b232013-09-07 00:43:52 +0200359 set->dsize = ip_set_elem_len(set, tb,
360 sizeof(struct bitmap_ipmac_elem));
361 if (!init_map_ipmac(set, map, first_ip, last_ip, elements)) {
362 kfree(map);
363 return -ENOMEM;
364 }
365 if (tb[IPSET_ATTR_TIMEOUT]) {
Jozsef Kadlecsikca134ce2013-09-07 00:10:07 +0200366 set->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
Jozsef Kadlecsikb0da3902013-04-27 14:37:01 +0200367 bitmap_ipmac_gc_init(set, bitmap_ipmac_gc);
Jozsef Kadlecsikde760212011-02-01 15:35:12 +0100368 }
369 return 0;
370}
371
372static struct ip_set_type bitmap_ipmac_type = {
373 .name = "bitmap:ip,mac",
374 .protocol = IPSET_PROTOCOL,
375 .features = IPSET_TYPE_IP | IPSET_TYPE_MAC,
376 .dimension = IPSET_DIM_TWO,
Jan Engelhardtc15f1c82012-02-14 00:24:10 +0100377 .family = NFPROTO_IPV4,
Jozsef Kadlecsik35b8dcf2013-04-30 23:02:43 +0200378 .revision_min = IPSET_TYPE_REV_MIN,
379 .revision_max = IPSET_TYPE_REV_MAX,
Jozsef Kadlecsikde760212011-02-01 15:35:12 +0100380 .create = bitmap_ipmac_create,
381 .create_policy = {
382 [IPSET_ATTR_IP] = { .type = NLA_NESTED },
383 [IPSET_ATTR_IP_TO] = { .type = NLA_NESTED },
384 [IPSET_ATTR_CIDR] = { .type = NLA_U8 },
385 [IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 },
Jozsef Kadlecsikf48d19d2013-04-08 23:10:22 +0200386 [IPSET_ATTR_CADT_FLAGS] = { .type = NLA_U32 },
Jozsef Kadlecsikde760212011-02-01 15:35:12 +0100387 },
388 .adt_policy = {
389 [IPSET_ATTR_IP] = { .type = NLA_NESTED },
Jozsef Kadlecsik15b4d932011-06-16 19:01:26 +0200390 [IPSET_ATTR_ETHER] = { .type = NLA_BINARY,
391 .len = ETH_ALEN },
Jozsef Kadlecsikde760212011-02-01 15:35:12 +0100392 [IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 },
393 [IPSET_ATTR_LINENO] = { .type = NLA_U32 },
Jozsef Kadlecsikf48d19d2013-04-08 23:10:22 +0200394 [IPSET_ATTR_BYTES] = { .type = NLA_U64 },
395 [IPSET_ATTR_PACKETS] = { .type = NLA_U64 },
Oliver Smithb90cb8b2013-09-22 20:56:32 +0200396 [IPSET_ATTR_COMMENT] = { .type = NLA_NUL_STRING },
Jozsef Kadlecsikde760212011-02-01 15:35:12 +0100397 },
398 .me = THIS_MODULE,
399};
400
401static int __init
402bitmap_ipmac_init(void)
403{
404 return ip_set_type_register(&bitmap_ipmac_type);
405}
406
407static void __exit
408bitmap_ipmac_fini(void)
409{
410 ip_set_type_unregister(&bitmap_ipmac_type);
411}
412
413module_init(bitmap_ipmac_init);
414module_exit(bitmap_ipmac_fini);