This commit was manufactured by cvs2svn to create branch 'vserver'.
[linux-2.6.git] / net / ipv4 / netfilter / ip_set_macipmap.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-2004 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 macipmap type */
12
13 #include <linux/module.h>
14 #include <linux/ip.h>
15 #include <linux/skbuff.h>
16 #include <linux/netfilter_ipv4/ip_tables.h>
17 #include <linux/netfilter_ipv4/ip_set.h>
18 #include <linux/errno.h>
19 #include <asm/uaccess.h>
20 #include <asm/bitops.h>
21 #include <linux/spinlock.h>
22 #include <linux/if_ether.h>
23 #include <linux/vmalloc.h>
24
25 #include <linux/netfilter_ipv4/ip_set_malloc.h>
26 #include <linux/netfilter_ipv4/ip_set_macipmap.h>
27
28 static int
29 testip(struct ip_set *set, const void *data, size_t size, ip_set_ip_t *hash_ip)
30 {
31         struct ip_set_macipmap *map = (struct ip_set_macipmap *) set->data;
32         struct ip_set_macip *table = (struct ip_set_macip *) map->members;      
33         struct ip_set_req_macipmap *req = (struct ip_set_req_macipmap *) data;
34
35         if (size != sizeof(struct ip_set_req_macipmap)) {
36                 ip_set_printk("data length wrong (want %zu, have %zu)",
37                               sizeof(struct ip_set_req_macipmap),
38                               size);
39                 return -EINVAL;
40         }
41
42         if (req->ip < map->first_ip || req->ip > map->last_ip)
43                 return -ERANGE;
44
45         *hash_ip = req->ip;
46         DP("set: %s, ip:%u.%u.%u.%u, %u.%u.%u.%u",
47            set->name, HIPQUAD(req->ip), HIPQUAD(*hash_ip));             
48         if (test_bit(IPSET_MACIP_ISSET,
49                      (void *) &table[req->ip - map->first_ip].flags)) {
50                 return (memcmp(req->ethernet,
51                                &table[req->ip - map->first_ip].ethernet,
52                                ETH_ALEN) == 0);
53         } else {
54                 return (map->flags & IPSET_MACIP_MATCHUNSET ? 1 : 0);
55         }
56 }
57
58 static int
59 testip_kernel(struct ip_set *set, 
60               const struct sk_buff *skb,
61               ip_set_ip_t *hash_ip,
62               const u_int32_t *flags,
63               unsigned char index)
64 {
65         struct ip_set_macipmap *map =
66             (struct ip_set_macipmap *) set->data;
67         struct ip_set_macip *table =
68             (struct ip_set_macip *) map->members;
69         ip_set_ip_t ip;
70         
71         ip = ntohl(flags[index] & IPSET_SRC
72                         ? skb->nh.iph->saddr
73                         : skb->nh.iph->daddr);
74         DP("flag: %s src: %u.%u.%u.%u dst: %u.%u.%u.%u",
75            flags[index] & IPSET_SRC ? "SRC" : "DST",
76            NIPQUAD(skb->nh.iph->saddr),
77            NIPQUAD(skb->nh.iph->daddr));
78
79         if (ip < map->first_ip || ip > map->last_ip)
80                 return 0;
81
82         *hash_ip = ip;  
83         DP("set: %s, ip:%u.%u.%u.%u, %u.%u.%u.%u",
84            set->name, HIPQUAD(ip), HIPQUAD(*hash_ip));          
85         if (test_bit(IPSET_MACIP_ISSET,
86             (void *) &table[ip - map->first_ip].flags)) {
87                 /* Is mac pointer valid?
88                  * If so, compare... */
89                 return (skb->mac.raw >= skb->head
90                         && (skb->mac.raw + ETH_HLEN) <= skb->data
91                         && (memcmp(eth_hdr(skb)->h_source,
92                                    &table[ip - map->first_ip].ethernet,
93                                    ETH_ALEN) == 0));
94         } else {
95                 return (map->flags & IPSET_MACIP_MATCHUNSET ? 1 : 0);
96         }
97 }
98
99 /* returns 0 on success */
100 static inline int
101 __addip(struct ip_set *set, 
102         ip_set_ip_t ip, unsigned char *ethernet, ip_set_ip_t *hash_ip)
103 {
104         struct ip_set_macipmap *map =
105             (struct ip_set_macipmap *) set->data;
106         struct ip_set_macip *table =
107             (struct ip_set_macip *) map->members;
108
109         if (ip < map->first_ip || ip > map->last_ip)
110                 return -ERANGE;
111         if (test_and_set_bit(IPSET_MACIP_ISSET, 
112                              (void *) &table[ip - map->first_ip].flags))
113                 return -EEXIST;
114
115         *hash_ip = ip;
116         DP("%u.%u.%u.%u, %u.%u.%u.%u", HIPQUAD(ip), HIPQUAD(*hash_ip));
117         memcpy(&table[ip - map->first_ip].ethernet, ethernet, ETH_ALEN);
118         return 0;
119 }
120
121 static int
122 addip(struct ip_set *set, const void *data, size_t size,
123       ip_set_ip_t *hash_ip)
124 {
125         struct ip_set_req_macipmap *req =
126             (struct ip_set_req_macipmap *) data;
127
128         if (size != sizeof(struct ip_set_req_macipmap)) {
129                 ip_set_printk("data length wrong (want %zu, have %zu)",
130                               sizeof(struct ip_set_req_macipmap),
131                               size);
132                 return -EINVAL;
133         }
134         return __addip(set, req->ip, req->ethernet, hash_ip);
135 }
136
137 static int
138 addip_kernel(struct ip_set *set, 
139              const struct sk_buff *skb,
140              ip_set_ip_t *hash_ip,
141              const u_int32_t *flags,
142              unsigned char index)
143 {
144         ip_set_ip_t ip;
145         
146         ip = ntohl(flags[index] & IPSET_SRC
147                         ? skb->nh.iph->saddr
148                         : skb->nh.iph->daddr);
149
150         if (!(skb->mac.raw >= skb->head
151               && (skb->mac.raw + ETH_HLEN) <= skb->data))
152                 return -EINVAL;
153
154         return __addip(set, ip, eth_hdr(skb)->h_source, hash_ip);
155 }
156
157 static inline int
158 __delip(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t *hash_ip)
159 {
160         struct ip_set_macipmap *map =
161             (struct ip_set_macipmap *) set->data;
162         struct ip_set_macip *table =
163             (struct ip_set_macip *) map->members;
164
165         if (ip < map->first_ip || ip > map->last_ip)
166                 return -ERANGE;
167         if (!test_and_clear_bit(IPSET_MACIP_ISSET, 
168                                 (void *)&table[ip - map->first_ip].flags))
169                 return -EEXIST;
170
171         *hash_ip = ip;
172         DP("%u.%u.%u.%u, %u.%u.%u.%u", HIPQUAD(ip), HIPQUAD(*hash_ip));
173         return 0;
174 }
175
176 static int
177 delip(struct ip_set *set, const void *data, size_t size,
178      ip_set_ip_t *hash_ip)
179 {
180         struct ip_set_req_macipmap *req =
181             (struct ip_set_req_macipmap *) data;
182
183         if (size != sizeof(struct ip_set_req_macipmap)) {
184                 ip_set_printk("data length wrong (want %zu, have %zu)",
185                               sizeof(struct ip_set_req_macipmap),
186                               size);
187                 return -EINVAL;
188         }
189         return __delip(set, req->ip, hash_ip);
190 }
191
192 static int
193 delip_kernel(struct ip_set *set,
194              const struct sk_buff *skb,
195              ip_set_ip_t *hash_ip,
196              const u_int32_t *flags,
197              unsigned char index)
198 {
199         return __delip(set,
200                        ntohl(flags[index] & IPSET_SRC 
201                                 ? skb->nh.iph->saddr 
202                                 : skb->nh.iph->daddr),
203                        hash_ip);
204 }
205
206 static inline size_t members_size(ip_set_id_t from, ip_set_id_t to)
207 {
208         return (size_t)((to - from + 1) * sizeof(struct ip_set_macip));
209 }
210
211 static int create(struct ip_set *set, const void *data, size_t size)
212 {
213         int newbytes;
214         struct ip_set_req_macipmap_create *req =
215             (struct ip_set_req_macipmap_create *) data;
216         struct ip_set_macipmap *map;
217
218         if (size != sizeof(struct ip_set_req_macipmap_create)) {
219                 ip_set_printk("data length wrong (want %zu, have %zu)",
220                               sizeof(struct ip_set_req_macipmap_create),
221                               size);
222                 return -EINVAL;
223         }
224
225         DP("from %u.%u.%u.%u to %u.%u.%u.%u",
226            HIPQUAD(req->from), HIPQUAD(req->to));
227
228         if (req->from > req->to) {
229                 DP("bad ip range");
230                 return -ENOEXEC;
231         }
232
233         if (req->to - req->from > MAX_RANGE) {
234                 ip_set_printk("range too big (max %d addresses)",
235                                MAX_RANGE+1);
236                 return -ENOEXEC;
237         }
238
239         map = kmalloc(sizeof(struct ip_set_macipmap), GFP_KERNEL);
240         if (!map) {
241                 DP("out of memory for %d bytes",
242                    sizeof(struct ip_set_macipmap));
243                 return -ENOMEM;
244         }
245         map->flags = req->flags;
246         map->first_ip = req->from;
247         map->last_ip = req->to;
248         newbytes = members_size(map->first_ip, map->last_ip);
249         map->members = ip_set_malloc(newbytes);
250         DP("members: %u %p", newbytes, map->members);
251         if (!map->members) {
252                 DP("out of memory for %d bytes", newbytes);
253                 kfree(map);
254                 return -ENOMEM;
255         }
256         memset(map->members, 0, newbytes);
257         
258         set->data = map;
259         return 0;
260 }
261
262 static void destroy(struct ip_set *set)
263 {
264         struct ip_set_macipmap *map =
265             (struct ip_set_macipmap *) set->data;
266
267         ip_set_free(map->members, members_size(map->first_ip, map->last_ip));
268         kfree(map);
269
270         set->data = NULL;
271 }
272
273 static void flush(struct ip_set *set)
274 {
275         struct ip_set_macipmap *map =
276             (struct ip_set_macipmap *) set->data;
277         memset(map->members, 0, members_size(map->first_ip, map->last_ip));
278 }
279
280 static void list_header(const struct ip_set *set, void *data)
281 {
282         struct ip_set_macipmap *map =
283             (struct ip_set_macipmap *) set->data;
284         struct ip_set_req_macipmap_create *header =
285             (struct ip_set_req_macipmap_create *) data;
286
287         DP("list_header %x %x %u", map->first_ip, map->last_ip,
288            map->flags);
289
290         header->from = map->first_ip;
291         header->to = map->last_ip;
292         header->flags = map->flags;
293 }
294
295 static int list_members_size(const struct ip_set *set)
296 {
297         struct ip_set_macipmap *map =
298             (struct ip_set_macipmap *) set->data;
299
300         DP("%u", members_size(map->first_ip, map->last_ip));
301         return members_size(map->first_ip, map->last_ip);
302 }
303
304 static void list_members(const struct ip_set *set, void *data)
305 {
306         struct ip_set_macipmap *map =
307             (struct ip_set_macipmap *) set->data;
308
309         int bytes = members_size(map->first_ip, map->last_ip);
310
311         DP("members: %u %p", bytes, map->members);
312         memcpy(data, map->members, bytes);
313 }
314
315 static struct ip_set_type ip_set_macipmap = {
316         .typename               = SETTYPE_NAME,
317         .features               = IPSET_TYPE_IP | IPSET_DATA_SINGLE,
318         .protocol_version       = IP_SET_PROTOCOL_VERSION,
319         .create                 = &create,
320         .destroy                = &destroy,
321         .flush                  = &flush,
322         .reqsize                = sizeof(struct ip_set_req_macipmap),
323         .addip                  = &addip,
324         .addip_kernel           = &addip_kernel,
325         .delip                  = &delip,
326         .delip_kernel           = &delip_kernel,
327         .testip                 = &testip,
328         .testip_kernel          = &testip_kernel,
329         .header_size            = sizeof(struct ip_set_req_macipmap_create),
330         .list_header            = &list_header,
331         .list_members_size      = &list_members_size,
332         .list_members           = &list_members,
333         .me                     = THIS_MODULE,
334 };
335
336 MODULE_LICENSE("GPL");
337 MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
338 MODULE_DESCRIPTION("macipmap type of IP sets");
339
340 static int __init init(void)
341 {
342         init_max_malloc_size();
343         return ip_set_register_set_type(&ip_set_macipmap);
344 }
345
346 static void __exit fini(void)
347 {
348         /* FIXME: possible race with ip_set_create() */
349         ip_set_unregister_set_type(&ip_set_macipmap);
350 }
351
352 module_init(init);
353 module_exit(fini);