Adapt to kernel 2.6.36+ netfilter API changes
[ipt_ACCOUNT] / linux-2.6.36 / net / ipv4 / netfilter / ipt_ACCOUNT.c
CommitLineData
3b4b23d1
TJ
1/***************************************************************************
2 * This is a module which is used for counting packets. *
3 * See http://www.intra2net.com/opensource/ipt_account *
4 * for further information *
5 * *
d641f433 6 * Copyright (C) 2004-2011 by Intra2net AG *
3b4b23d1
TJ
7 * opensource@intra2net.com *
8 * *
9 * This program is free software; you can redistribute it and/or modify *
10 * it under the terms of the GNU General Public License *
11 * version 2 as published by the Free Software Foundation; *
12 * *
13 ***************************************************************************/
14
15#include <linux/module.h>
16#include <linux/version.h>
17#include <linux/skbuff.h>
18#include <linux/ip.h>
19#include <net/icmp.h>
20#include <net/udp.h>
21#include <net/tcp.h>
22#include <linux/netfilter_ipv4/ip_tables.h>
23
24#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
25 #include <linux/semaphore.h>
26#else
27 #include <asm/semaphore.h>
28#endif
29
30#include <linux/kernel.h>
31#include <linux/mm.h>
32#include <linux/string.h>
33#include <linux/spinlock.h>
34#include <asm/uaccess.h>
35
36#include <net/route.h>
37#include <linux/netfilter_ipv4/ipt_ACCOUNT.h>
38
39#if 0
40#define DEBUGP printk
41#else
42#define DEBUGP(format, args...)
43#endif
44
45#if (PAGE_SIZE < 4096)
46#error "ipt_ACCOUNT needs at least a PAGE_SIZE of 4096"
47#endif
48
49static struct ipt_acc_table *ipt_acc_tables = NULL;
50static struct ipt_acc_handle *ipt_acc_handles = NULL;
51static void *ipt_acc_tmpbuf = NULL;
52
53/* Spinlock used for manipulating the current accounting tables/data */
54static DEFINE_SPINLOCK(ipt_acc_lock);
55/* Mutex (semaphore) used for manipulating userspace handles/snapshot data */
56static struct semaphore ipt_acc_userspace_mutex;
57
58/* Allocates a page and clears it */
59static void *ipt_acc_zalloc_page(void)
60{
61 // Don't use get_zeroed_page until it's fixed in the kernel.
62 // get_zeroed_page(GFP_ATOMIC)
63 void *mem = (void *)__get_free_page(GFP_ATOMIC);
64 if (mem) {
65 memset (mem, 0, PAGE_SIZE);
66 }
67
68 return mem;
69}
70
71/* Recursive free of all data structures */
72static void ipt_acc_data_free(void *data, unsigned char depth)
73{
74 /* Empty data set */
75 if (!data)
76 return;
77
78 /* Free for 8 bit network */
79 if (depth == 0) {
80 free_page((unsigned long)data);
81 return;
82 }
83
84 /* Free for 16 bit network */
85 if (depth == 1) {
86 struct ipt_acc_mask_16 *mask_16 = (struct ipt_acc_mask_16 *)data;
87 unsigned int b;
88 for (b=0; b <= 255; b++) {
89 if (mask_16->mask_24[b]) {
90 free_page((unsigned long)mask_16->mask_24[b]);
91 }
92 }
93 free_page((unsigned long)data);
94 return;
95 }
96
97 /* Free for 24 bit network */
98 if (depth == 2) {
99 unsigned int a, b;
100 for (a=0; a <= 255; a++) {
101 if (((struct ipt_acc_mask_8 *)data)->mask_16[a]) {
102 struct ipt_acc_mask_16 *mask_16 = (struct ipt_acc_mask_16*)
103 ((struct ipt_acc_mask_8 *)data)->mask_16[a];
104
105 for (b=0; b <= 255; b++) {
106 if (mask_16->mask_24[b]) {
107 free_page((unsigned long)mask_16->mask_24[b]);
108 }
109 }
110 free_page((unsigned long)mask_16);
111 }
112 }
113 free_page((unsigned long)data);
114 return;
115 }
116
117 printk("ACCOUNT: ipt_acc_data_free called with unknown depth: %d\n",
118 depth);
119 return;
120}
121
122/* Look for existing table / insert new one.
123 Return internal ID or -1 on error */
124static int ipt_acc_table_insert(char *name, u_int32_t ip, u_int32_t netmask)
125{
126 unsigned int i;
127
a0ed824e
TJ
128 DEBUGP("ACCOUNT: ipt_acc_table_insert: %s, %pI4/%pI4\n",
129 name, &ip, &netmask);
3b4b23d1
TJ
130
131 /* Look for existing table */
132 for (i = 0; i < ACCOUNT_MAX_TABLES; i++) {
133 if (strncmp(ipt_acc_tables[i].name, name,
134 ACCOUNT_TABLE_NAME_LEN) == 0) {
135 DEBUGP("ACCOUNT: Found existing slot: %d - "
a0ed824e
TJ
136 "%pI4/%pI4\n", i,
137 &ipt_acc_tables[i].ip,
138 &ipt_acc_tables[i].netmask);
3b4b23d1
TJ
139
140 if (ipt_acc_tables[i].ip != ip
141 || ipt_acc_tables[i].netmask != netmask) {
142 printk("ACCOUNT: Table %s found, but IP/netmask mismatch. "
a0ed824e
TJ
143 "IP/netmask found: %pI4/%pI4\n",
144 name, &ipt_acc_tables[i].ip,
145 &ipt_acc_tables[i].netmask);
3b4b23d1
TJ
146 return -1;
147 }
148
149 ipt_acc_tables[i].refcount++;
150 DEBUGP("ACCOUNT: Refcount: %d\n", ipt_acc_tables[i].refcount);
151 return i;
152 }
153 }
154
155 /* Insert new table */
156 for (i = 0; i < ACCOUNT_MAX_TABLES; i++) {
157 /* Found free slot */
158 if (ipt_acc_tables[i].name[0] == 0) {
159 unsigned int netsize=0;
160 u_int32_t calc_mask;
161 int j; /* needs to be signed, otherwise we risk endless loop */
162
163 DEBUGP("ACCOUNT: Found free slot: %d\n", i);
164 strncpy (ipt_acc_tables[i].name, name, ACCOUNT_TABLE_NAME_LEN-1);
165
166 ipt_acc_tables[i].ip = ip;
167 ipt_acc_tables[i].netmask = netmask;
168
169 /* Calculate netsize */
170 calc_mask = htonl(netmask);
171 for (j = 31; j >= 0; j--) {
172 if (calc_mask&(1<<j))
173 netsize++;
174 else
175 break;
176 }
177
178 /* Calculate depth from netsize */
179 if (netsize >= 24)
180 ipt_acc_tables[i].depth = 0;
181 else if (netsize >= 16)
182 ipt_acc_tables[i].depth = 1;
183 else if(netsize >= 8)
184 ipt_acc_tables[i].depth = 2;
185
186 DEBUGP("ACCOUNT: calculated netsize: %u -> "
187 "ipt_acc_table depth %u\n", netsize,
188 ipt_acc_tables[i].depth);
189
190 ipt_acc_tables[i].refcount++;
191 if ((ipt_acc_tables[i].data
192 = ipt_acc_zalloc_page()) == NULL) {
193 printk("ACCOUNT: out of memory for data of table: %s\n", name);
194 memset(&ipt_acc_tables[i], 0,
195 sizeof(struct ipt_acc_table));
196 return -1;
197 }
198
199 return i;
200 }
201 }
202
203 /* No free slot found */
204 printk("ACCOUNT: No free table slot found (max: %d). "
205 "Please increase ACCOUNT_MAX_TABLES.\n", ACCOUNT_MAX_TABLES);
206 return -1;
207}
208
35fc8e31
TJ
209#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,36)
210static int ipt_acc_checkentry(const struct xt_tgchk_param *par)
211#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,28)
3b4b23d1
TJ
212static bool ipt_acc_checkentry(const struct xt_tgchk_param *par)
213#else
214#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,23)
215static bool ipt_acc_checkentry(const char *tablename,
216#else
217static int ipt_acc_checkentry(const char *tablename,
218#endif
219#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,16)
220 const void *e,
221#else
222 const struct ipt_entry *e,
223#endif
224#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,17)
225 const struct xt_target *target,
226#endif
227 void *targinfo,
228#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
229 unsigned int targinfosize,
230#endif
231 unsigned int hook_mask)
232#endif /* >= 2.6.28 */
233{
234#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,28)
235 struct ipt_acc_info *info = par->targinfo;
236#else
237 struct ipt_acc_info *info = targinfo;
238#endif
239 int table_nr;
240
241#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,17)
242 if (targinfosize != IPT_ALIGN(sizeof(struct ipt_acc_info))) {
243 DEBUGP("ACCOUNT: targinfosize %u != %u\n",
244 targinfosize, IPT_ALIGN(sizeof(struct ipt_acc_info)));
245 return 0;
246 }
247#endif
248
249 spin_lock_bh(&ipt_acc_lock);
250 table_nr = ipt_acc_table_insert(info->table_name, info->net_ip,
251 info->net_mask);
252 spin_unlock_bh(&ipt_acc_lock);
253
254 if (table_nr == -1) {
255 printk("ACCOUNT: Table insert problem. Aborting\n");
35fc8e31
TJ
256#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,36)
257 return -EINVAL;
258#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,23)
3b4b23d1
TJ
259 return false;
260#else
261 return 0;
262#endif
263 }
264 /* Table nr caching so we don't have to do an extra string compare
265 for every packet */
266 info->table_nr = table_nr;
267
35fc8e31
TJ
268 /* All fine */
269#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,36)
270 return 0;
271#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,23)
3b4b23d1
TJ
272 return true;
273#else
274 return 1;
275#endif
276}
277
278#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,28)
279static void ipt_acc_destroy(const struct xt_tgdtor_param *par)
280#else
281static void ipt_acc_destroy(
282#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,17)
283 const struct xt_target *target,
284#endif
285#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,19)
286 void *targinfo)
287#else
288 void *targinfo,
289 unsigned int targinfosize)
290#endif
291#endif /* >= 2.6.28 */
292{
293 unsigned int i;
294#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,28)
295 struct ipt_acc_info *info = par->targinfo;
296#else
297 struct ipt_acc_info *info = targinfo;
298#endif
299
300#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,17)
301 if (targinfosize != IPT_ALIGN(sizeof(struct ipt_acc_info))) {
302 DEBUGP("ACCOUNT: targinfosize %u != %u\n",
303 targinfosize, IPT_ALIGN(sizeof(struct ipt_acc_info)));
304 }
305#endif
306
307 spin_lock_bh(&ipt_acc_lock);
308
309 DEBUGP("ACCOUNT: ipt_acc_deleteentry called for table: %s (#%d)\n",
310 info->table_name, info->table_nr);
311
312 info->table_nr = -1; /* Set back to original state */
313
314 /* Look for table */
315 for (i = 0; i < ACCOUNT_MAX_TABLES; i++) {
316 if (strncmp(ipt_acc_tables[i].name, info->table_name,
317 ACCOUNT_TABLE_NAME_LEN) == 0) {
318 DEBUGP("ACCOUNT: Found table at slot: %d\n", i);
319
320 ipt_acc_tables[i].refcount--;
321 DEBUGP("ACCOUNT: Refcount left: %d\n",
322 ipt_acc_tables[i].refcount);
323
324 /* Table not needed anymore? */
325 if (ipt_acc_tables[i].refcount == 0) {
326 DEBUGP("ACCOUNT: Destroying table at slot: %d\n", i);
327 ipt_acc_data_free(ipt_acc_tables[i].data,
328 ipt_acc_tables[i].depth);
329 memset(&ipt_acc_tables[i], 0,
330 sizeof(struct ipt_acc_table));
331 }
332
333 spin_unlock_bh(&ipt_acc_lock);
334 return;
335 }
336 }
337
338 /* Table not found */
339 printk("ACCOUNT: Table %s not found for destroy\n", info->table_name);
340 spin_unlock_bh(&ipt_acc_lock);
341}
342
343static void ipt_acc_depth0_insert(struct ipt_acc_mask_24 *mask_24,
344 u_int32_t net_ip, u_int32_t netmask,
345 u_int32_t src_ip, u_int32_t dst_ip,
346 u_int32_t size, u_int32_t *itemcount)
347{
348 unsigned char is_src = 0, is_dst = 0, src_slot, dst_slot;
349 char is_src_new_ip = 0, is_dst_new_ip = 0; /* Check if this entry is new */
350
a0ed824e
TJ
351 DEBUGP("ACCOUNT: ipt_acc_depth0_insert: %pI4/%pI4 "
352 "for net %pI4/%pI4, size: %u\n", &src_ip,
353 &dst_ip, &net_ip, &netmask, size);
3b4b23d1
TJ
354
355 /* Check if src/dst is inside our network. */
356 /* Special: net_ip = 0.0.0.0/0 gets stored as src in slot 0 */
357 if (!netmask)
358 src_ip = 0;
359 if ((net_ip&netmask) == (src_ip&netmask))
360 is_src = 1;
361 if ((net_ip&netmask) == (dst_ip&netmask) && netmask)
362 is_dst = 1;
363
364 if (!is_src && !is_dst) {
a0ed824e
TJ
365 DEBUGP("ACCOUNT: Skipping packet %pI4/%pI4 "
366 "for net %pI4/%pI4\n", &src_ip,
367 &dst_ip, &net_ip, &netmask);
3b4b23d1
TJ
368 return;
369 }
370
371 /* Calculate array positions */
372 src_slot = (unsigned char)((src_ip&0xFF000000) >> 24);
373 dst_slot = (unsigned char)((dst_ip&0xFF000000) >> 24);
374
375 /* Increase size counters */
376 if (is_src) {
377 /* Calculate network slot */
378 DEBUGP("ACCOUNT: Calculated SRC 8 bit network slot: %d\n", src_slot);
379 if (!mask_24->ip[src_slot].src_packets
380 && !mask_24->ip[src_slot].dst_packets)
381 is_src_new_ip = 1;
382
383 mask_24->ip[src_slot].src_packets++;
384 mask_24->ip[src_slot].src_bytes+=size;
385 }
386 if (is_dst) {
387 DEBUGP("ACCOUNT: Calculated DST 8 bit network slot: %d\n", dst_slot);
388 if (!mask_24->ip[dst_slot].src_packets
389 && !mask_24->ip[dst_slot].dst_packets)
390 is_dst_new_ip = 1;
391
392 mask_24->ip[dst_slot].dst_packets++;
393 mask_24->ip[dst_slot].dst_bytes+=size;
394 }
395
396 /* Increase itemcounter */
397 DEBUGP("ACCOUNT: Itemcounter before: %d\n", *itemcount);
398 if (src_slot == dst_slot) {
399 if (is_src_new_ip || is_dst_new_ip) {
400 DEBUGP("ACCOUNT: src_slot == dst_slot: %d, %d\n",
401 is_src_new_ip, is_dst_new_ip);
402 (*itemcount)++;
403 }
404 } else {
405 if (is_src_new_ip) {
a0ed824e 406 DEBUGP("ACCOUNT: New src_ip: %pI4\n", &src_ip);
3b4b23d1
TJ
407 (*itemcount)++;
408 }
409 if (is_dst_new_ip) {
a0ed824e 410 DEBUGP("ACCOUNT: New dst_ip: %pI4\n", &dst_ip);
3b4b23d1
TJ
411 (*itemcount)++;
412 }
413 }
414 DEBUGP("ACCOUNT: Itemcounter after: %d\n", *itemcount);
415}
416
417static void ipt_acc_depth1_insert(struct ipt_acc_mask_16 *mask_16,
418 u_int32_t net_ip, u_int32_t netmask,
419 u_int32_t src_ip, u_int32_t dst_ip,
420 u_int32_t size, u_int32_t *itemcount)
421{
422 /* Do we need to process src IP? */
423 if ((net_ip&netmask) == (src_ip&netmask)) {
424 unsigned char slot = (unsigned char)((src_ip&0x00FF0000) >> 16);
425 DEBUGP("ACCOUNT: Calculated SRC 16 bit network slot: %d\n", slot);
426
427 /* Do we need to create a new mask_24 bucket? */
428 if (!mask_16->mask_24[slot] && (mask_16->mask_24[slot] =
429 ipt_acc_zalloc_page()) == NULL) {
430 printk("ACCOUNT: Can't process packet because out of memory!\n");
431 return;
432 }
433
434 ipt_acc_depth0_insert((struct ipt_acc_mask_24 *)mask_16->mask_24[slot],
435 net_ip, netmask, src_ip, 0, size, itemcount);
436 }
437
438 /* Do we need to process dst IP? */
439 if ((net_ip&netmask) == (dst_ip&netmask)) {
440 unsigned char slot = (unsigned char)((dst_ip&0x00FF0000) >> 16);
441 DEBUGP("ACCOUNT: Calculated DST 16 bit network slot: %d\n", slot);
442
443 /* Do we need to create a new mask_24 bucket? */
444 if (!mask_16->mask_24[slot] && (mask_16->mask_24[slot]
445 = ipt_acc_zalloc_page()) == NULL) {
446 printk("ACCOUT: Can't process packet because out of memory!\n");
447 return;
448 }
449
450 ipt_acc_depth0_insert((struct ipt_acc_mask_24 *)mask_16->mask_24[slot],
451 net_ip, netmask, 0, dst_ip, size, itemcount);
452 }
453}
454
455static void ipt_acc_depth2_insert(struct ipt_acc_mask_8 *mask_8,
456 u_int32_t net_ip, u_int32_t netmask,
457 u_int32_t src_ip, u_int32_t dst_ip,
458 u_int32_t size, u_int32_t *itemcount)
459{
460 /* Do we need to process src IP? */
461 if ((net_ip&netmask) == (src_ip&netmask)) {
462 unsigned char slot = (unsigned char)((src_ip&0x0000FF00) >> 8);
463 DEBUGP("ACCOUNT: Calculated SRC 24 bit network slot: %d\n", slot);
464
465 /* Do we need to create a new mask_24 bucket? */
466 if (!mask_8->mask_16[slot] && (mask_8->mask_16[slot]
467 = ipt_acc_zalloc_page()) == NULL) {
468 printk("ACCOUNT: Can't process packet because out of memory!\n");
469 return;
470 }
471
472 ipt_acc_depth1_insert((struct ipt_acc_mask_16 *)mask_8->mask_16[slot],
473 net_ip, netmask, src_ip, 0, size, itemcount);
474 }
475
476 /* Do we need to process dst IP? */
477 if ((net_ip&netmask) == (dst_ip&netmask)) {
478 unsigned char slot = (unsigned char)((dst_ip&0x0000FF00) >> 8);
479 DEBUGP("ACCOUNT: Calculated DST 24 bit network slot: %d\n", slot);
480
481 /* Do we need to create a new mask_24 bucket? */
482 if (!mask_8->mask_16[slot] && (mask_8->mask_16[slot]
483 = ipt_acc_zalloc_page()) == NULL) {
484 printk("ACCOUNT: Can't process packet because out of memory!\n");
485 return;
486 }
487
488 ipt_acc_depth1_insert((struct ipt_acc_mask_16 *)mask_8->mask_16[slot],
489 net_ip, netmask, 0, dst_ip, size, itemcount);
490 }
491}
492
35fc8e31
TJ
493#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,36)
494static unsigned int ipt_acc_target(struct sk_buff *skb, const struct xt_action_param *par)
495#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,28)
3b4b23d1
TJ
496static unsigned int ipt_acc_target(struct sk_buff *skb, const struct xt_target_param *par)
497#else
498#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
499static unsigned int ipt_acc_target(struct sk_buff *skb,
500#else
501static unsigned int ipt_acc_target(struct sk_buff **pskb,
502#endif
503 const struct net_device *in,
504 const struct net_device *out,
505 unsigned int hooknum,
506#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,17)
507 const struct xt_target *target,
508#endif
509#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,19)
510 const void *targinfo)
511#else
512 const void *targinfo,
513 void *userinfo)
514#endif
515#endif /* 2.6.28 */
516{
517 const struct ipt_acc_info *info =
518#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,28)
519 par->targinfo;
520#else
521 (const struct ipt_acc_info *)targinfo;
522#endif
523
524#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
525 u_int32_t src_ip = ip_hdr(skb)->saddr;
526 u_int32_t dst_ip = ip_hdr(skb)->daddr;
527 u_int32_t size = ntohs(ip_hdr(skb)->tot_len);
528#else
529#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
530 u_int32_t src_ip = ip_hdr(*pskb)->saddr;
531 u_int32_t dst_ip = ip_hdr(*pskb)->daddr;
532 u_int32_t size = ntohs(ip_hdr(*pskb)->tot_len);
533#else
534 u_int32_t src_ip = (*pskb)->nh.iph->saddr;
535 u_int32_t dst_ip = (*pskb)->nh.iph->daddr;
536 u_int32_t size = ntohs((*pskb)->nh.iph->tot_len);
537#endif
538#endif
539
540 spin_lock_bh(&ipt_acc_lock);
541
542 if (ipt_acc_tables[info->table_nr].name[0] == 0) {
543 printk("ACCOUNT: ipt_acc_target: Invalid table id %u. "
a0ed824e
TJ
544 "IPs %pI4/%pI4\n", info->table_nr,
545 &src_ip, &dst_ip);
3b4b23d1 546 spin_unlock_bh(&ipt_acc_lock);
35fc8e31 547 return XT_CONTINUE;
3b4b23d1
TJ
548 }
549
550 /* 8 bit network or "any" network */
551 if (ipt_acc_tables[info->table_nr].depth == 0) {
552 /* Count packet and check if the IP is new */
553 ipt_acc_depth0_insert(
554 (struct ipt_acc_mask_24 *)ipt_acc_tables[info->table_nr].data,
555 ipt_acc_tables[info->table_nr].ip,
556 ipt_acc_tables[info->table_nr].netmask,
557 src_ip, dst_ip, size, &ipt_acc_tables[info->table_nr].itemcount);
558 spin_unlock_bh(&ipt_acc_lock);
35fc8e31 559 return XT_CONTINUE;
3b4b23d1
TJ
560 }
561
562 /* 16 bit network */
563 if (ipt_acc_tables[info->table_nr].depth == 1) {
564 ipt_acc_depth1_insert(
565 (struct ipt_acc_mask_16 *)ipt_acc_tables[info->table_nr].data,
566 ipt_acc_tables[info->table_nr].ip,
567 ipt_acc_tables[info->table_nr].netmask,
568 src_ip, dst_ip, size, &ipt_acc_tables[info->table_nr].itemcount);
569 spin_unlock_bh(&ipt_acc_lock);
35fc8e31 570 return XT_CONTINUE;
3b4b23d1
TJ
571 }
572
573 /* 24 bit network */
574 if (ipt_acc_tables[info->table_nr].depth == 2) {
575 ipt_acc_depth2_insert(
576 (struct ipt_acc_mask_8 *)ipt_acc_tables[info->table_nr].data,
577 ipt_acc_tables[info->table_nr].ip,
578 ipt_acc_tables[info->table_nr].netmask,
579 src_ip, dst_ip, size, &ipt_acc_tables[info->table_nr].itemcount);
580 spin_unlock_bh(&ipt_acc_lock);
35fc8e31 581 return XT_CONTINUE;
3b4b23d1
TJ
582 }
583
584 printk("ACCOUNT: ipt_acc_target: Unable to process packet. "
a0ed824e
TJ
585 "Table id %u. IPs %pI4/%pI4\n",
586 info->table_nr, &src_ip, &dst_ip);
3b4b23d1
TJ
587
588 spin_unlock_bh(&ipt_acc_lock);
35fc8e31 589 return XT_CONTINUE;
3b4b23d1
TJ
590}
591
592/*
593 Functions dealing with "handles":
594 Handles are snapshots of a accounting state.
595
596 read snapshots are only for debugging the code
597 and are very expensive concerning speed/memory
598 compared to read_and_flush.
599
600 The functions aren't protected by spinlocks themselves
601 as this is done in the ioctl part of the code.
602*/
603
604/*
605 Find a free handle slot. Normally only one should be used,
606 but there could be two or more applications accessing the data
607 at the same time.
608*/
609static int ipt_acc_handle_find_slot(void)
610{
611 unsigned int i;
612 /* Insert new table */
613 for (i = 0; i < ACCOUNT_MAX_HANDLES; i++) {
614 /* Found free slot */
615 if (ipt_acc_handles[i].data == NULL) {
616 /* Don't "mark" data as used as we are protected by a spinlock
617 by the calling function. handle_find_slot() is only a function
618 to prevent code duplication. */
619 return i;
620 }
621 }
622
623 /* No free slot found */
624 printk("ACCOUNT: No free handle slot found (max: %u). "
625 "Please increase ACCOUNT_MAX_HANDLES.\n", ACCOUNT_MAX_HANDLES);
626 return -1;
627}
628
629static int ipt_acc_handle_free(unsigned int handle)
630{
631 if (handle >= ACCOUNT_MAX_HANDLES) {
632 printk("ACCOUNT: Invalid handle for ipt_acc_handle_free() specified:"
633 " %u\n", handle);
634 return -EINVAL;
635 }
636
637 ipt_acc_data_free(ipt_acc_handles[handle].data,
638 ipt_acc_handles[handle].depth);
639 memset (&ipt_acc_handles[handle], 0, sizeof (struct ipt_acc_handle));
640 return 0;
641}
642
643/* Prepare data for read without flush. Use only for debugging!
644 Real applications should use read&flush as it's way more efficent */
645static int ipt_acc_handle_prepare_read(char *tablename,
646 struct ipt_acc_handle *dest, u_int32_t *count)
647{
648 int table_nr=-1;
649 unsigned char depth;
650
651 for (table_nr = 0; table_nr < ACCOUNT_MAX_TABLES; table_nr++)
652 if (strncmp(ipt_acc_tables[table_nr].name, tablename,
653 ACCOUNT_TABLE_NAME_LEN) == 0)
654 break;
655
656 if (table_nr == ACCOUNT_MAX_TABLES) {
657 printk("ACCOUNT: ipt_acc_handle_prepare_read(): "
658 "Table %s not found\n", tablename);
659 return -1;
660 }
661
662 /* Fill up handle structure */
663 dest->ip = ipt_acc_tables[table_nr].ip;
664 dest->depth = ipt_acc_tables[table_nr].depth;
665 dest->itemcount = ipt_acc_tables[table_nr].itemcount;
666
667 /* allocate "root" table */
668 if ((dest->data = ipt_acc_zalloc_page()) == NULL) {
669 printk("ACCOUNT: out of memory for root table "
670 "in ipt_acc_handle_prepare_read()\n");
671 return -1;
672 }
673
674 /* Recursive copy of complete data structure */
675 depth = dest->depth;
676 if (depth == 0) {
677 memcpy(dest->data,
678 ipt_acc_tables[table_nr].data,
679 sizeof(struct ipt_acc_mask_24));
680 } else if (depth == 1) {
681 struct ipt_acc_mask_16 *src_16 =
682 (struct ipt_acc_mask_16 *)ipt_acc_tables[table_nr].data;
683 struct ipt_acc_mask_16 *network_16 =
684 (struct ipt_acc_mask_16 *)dest->data;
685 unsigned int b;
686
687 for (b = 0; b <= 255; b++) {
688 if (src_16->mask_24[b]) {
689 if ((network_16->mask_24[b] =
690 ipt_acc_zalloc_page()) == NULL) {
691 printk("ACCOUNT: out of memory during copy of 16 bit "
692 "network in ipt_acc_handle_prepare_read()\n");
693 ipt_acc_data_free(dest->data, depth);
694 return -1;
695 }
696
697 memcpy(network_16->mask_24[b], src_16->mask_24[b],
698 sizeof(struct ipt_acc_mask_24));
699 }
700 }
701 } else if(depth == 2) {
702 struct ipt_acc_mask_8 *src_8 =
703 (struct ipt_acc_mask_8 *)ipt_acc_tables[table_nr].data;
704 struct ipt_acc_mask_8 *network_8 =
705 (struct ipt_acc_mask_8 *)dest->data;
706 struct ipt_acc_mask_16 *src_16, *network_16;
707 unsigned int a, b;
708
709 for (a = 0; a <= 255; a++) {
710 if (src_8->mask_16[a]) {
711 if ((network_8->mask_16[a] =
712 ipt_acc_zalloc_page()) == NULL) {
713 printk("ACCOUNT: out of memory during copy of 24 bit network"
714 " in ipt_acc_handle_prepare_read()\n");
715 ipt_acc_data_free(dest->data, depth);
716 return -1;
717 }
718
719 memcpy(network_8->mask_16[a], src_8->mask_16[a],
720 sizeof(struct ipt_acc_mask_16));
721
722 src_16 = src_8->mask_16[a];
723 network_16 = network_8->mask_16[a];
724
725 for (b = 0; b <= 255; b++) {
726 if (src_16->mask_24[b]) {
727 if ((network_16->mask_24[b] =
728 ipt_acc_zalloc_page()) == NULL) {
729 printk("ACCOUNT: out of memory during copy of 16 bit"
730 " network in ipt_acc_handle_prepare_read()\n");
731 ipt_acc_data_free(dest->data, depth);
732 return -1;
733 }
734
735 memcpy(network_16->mask_24[b], src_16->mask_24[b],
736 sizeof(struct ipt_acc_mask_24));
737 }
738 }
739 }
740 }
741 }
742
743 *count = ipt_acc_tables[table_nr].itemcount;
744
745 return 0;
746}
747
748/* Prepare data for read and flush it */
749static int ipt_acc_handle_prepare_read_flush(char *tablename,
750 struct ipt_acc_handle *dest, u_int32_t *count)
751{
752 int table_nr;
753 void *new_data_page;
754
755 for (table_nr = 0; table_nr < ACCOUNT_MAX_TABLES; table_nr++)
756 if (strncmp(ipt_acc_tables[table_nr].name, tablename,
757 ACCOUNT_TABLE_NAME_LEN) == 0)
758 break;
759
760 if (table_nr == ACCOUNT_MAX_TABLES) {
761 printk("ACCOUNT: ipt_acc_handle_prepare_read_flush(): "
762 "Table %s not found\n", tablename);
763 return -1;
764 }
765
766 /* Try to allocate memory */
767 if (!(new_data_page = ipt_acc_zalloc_page())) {
768 printk("ACCOUNT: ipt_acc_handle_prepare_read_flush(): "
769 "Out of memory!\n");
770 return -1;
771 }
772
773 /* Fill up handle structure */
774 dest->ip = ipt_acc_tables[table_nr].ip;
775 dest->depth = ipt_acc_tables[table_nr].depth;
776 dest->itemcount = ipt_acc_tables[table_nr].itemcount;
777 dest->data = ipt_acc_tables[table_nr].data;
778 *count = ipt_acc_tables[table_nr].itemcount;
779
780 /* "Flush" table data */
781 ipt_acc_tables[table_nr].data = new_data_page;
782 ipt_acc_tables[table_nr].itemcount = 0;
783
784 return 0;
785}
786
787/* Copy 8 bit network data into a prepared buffer.
788 We only copy entries != 0 to increase performance.
789*/
790static int ipt_acc_handle_copy_data(void *to_user, unsigned long *to_user_pos,
791 unsigned long *tmpbuf_pos,
792 struct ipt_acc_mask_24 *data,
793 u_int32_t net_ip, u_int32_t net_OR_mask)
794{
795 struct ipt_acc_handle_ip handle_ip;
796 size_t handle_ip_size = sizeof (struct ipt_acc_handle_ip);
797 unsigned int i;
798
799 for (i = 0; i <= 255; i++) {
800 if (data->ip[i].src_packets || data->ip[i].dst_packets) {
801 handle_ip.ip = net_ip | net_OR_mask | (i<<24);
802
803 handle_ip.src_packets = data->ip[i].src_packets;
804 handle_ip.src_bytes = data->ip[i].src_bytes;
805 handle_ip.dst_packets = data->ip[i].dst_packets;
806 handle_ip.dst_bytes = data->ip[i].dst_bytes;
807
808 /* Temporary buffer full? Flush to userspace */
809 if (*tmpbuf_pos+handle_ip_size >= PAGE_SIZE) {
810 if (copy_to_user(to_user + *to_user_pos, ipt_acc_tmpbuf,
811 *tmpbuf_pos))
812 return -EFAULT;
813 *to_user_pos = *to_user_pos + *tmpbuf_pos;
814 *tmpbuf_pos = 0;
815 }
816 memcpy(ipt_acc_tmpbuf+*tmpbuf_pos, &handle_ip, handle_ip_size);
817 *tmpbuf_pos += handle_ip_size;
818 }
819 }
820
821 return 0;
822}
823
824/* Copy the data from our internal structure
825 We only copy entries != 0 to increase performance.
826 Overwrites ipt_acc_tmpbuf.
827*/
828static int ipt_acc_handle_get_data(u_int32_t handle, void *to_user)
829{
830 unsigned long to_user_pos=0, tmpbuf_pos=0;
831 u_int32_t net_ip;
832 unsigned char depth;
833
834 if (handle >= ACCOUNT_MAX_HANDLES) {
835 printk("ACCOUNT: invalid handle for ipt_acc_handle_get_data() "
836 "specified: %u\n", handle);
837 return -1;
838 }
839
840 if (ipt_acc_handles[handle].data == NULL) {
841 printk("ACCOUNT: handle %u is BROKEN: Contains no data\n", handle);
842 return -1;
843 }
844
845 net_ip = ipt_acc_handles[handle].ip;
846 depth = ipt_acc_handles[handle].depth;
847
848 /* 8 bit network */
849 if (depth == 0) {
850 struct ipt_acc_mask_24 *network =
851 (struct ipt_acc_mask_24*)ipt_acc_handles[handle].data;
852 if (ipt_acc_handle_copy_data(to_user, &to_user_pos, &tmpbuf_pos,
853 network, net_ip, 0))
854 return -1;
855
856 /* Flush remaining data to userspace */
857 if (tmpbuf_pos)
858 if (copy_to_user(to_user+to_user_pos, ipt_acc_tmpbuf, tmpbuf_pos))
859 return -1;
860
861 return 0;
862 }
863
864 /* 16 bit network */
865 if (depth == 1) {
866 struct ipt_acc_mask_16 *network_16 =
867 (struct ipt_acc_mask_16*)ipt_acc_handles[handle].data;
868 unsigned int b;
869 for (b = 0; b <= 255; b++) {
870 if (network_16->mask_24[b]) {
871 struct ipt_acc_mask_24 *network =
872 (struct ipt_acc_mask_24*)network_16->mask_24[b];
873 if (ipt_acc_handle_copy_data(to_user, &to_user_pos,
874 &tmpbuf_pos, network, net_ip, (b << 16)))
875 return -1;
876 }
877 }
878
879 /* Flush remaining data to userspace */
880 if (tmpbuf_pos)
881 if (copy_to_user(to_user+to_user_pos, ipt_acc_tmpbuf, tmpbuf_pos))
882 return -1;
883
884 return 0;
885 }
886
887 /* 24 bit network */
888 if (depth == 2) {
889 struct ipt_acc_mask_8 *network_8 =
890 (struct ipt_acc_mask_8*)ipt_acc_handles[handle].data;
891 unsigned int a, b;
892 for (a = 0; a <= 255; a++) {
893 if (network_8->mask_16[a]) {
894 struct ipt_acc_mask_16 *network_16 =
895 (struct ipt_acc_mask_16*)network_8->mask_16[a];
896 for (b = 0; b <= 255; b++) {
897 if (network_16->mask_24[b]) {
898 struct ipt_acc_mask_24 *network =
899 (struct ipt_acc_mask_24*)network_16->mask_24[b];
900 if (ipt_acc_handle_copy_data(to_user,
901 &to_user_pos, &tmpbuf_pos,
902 network, net_ip, (a << 8) | (b << 16)))
903 return -1;
904 }
905 }
906 }
907 }
908
909 /* Flush remaining data to userspace */
910 if (tmpbuf_pos)
911 if (copy_to_user(to_user+to_user_pos, ipt_acc_tmpbuf, tmpbuf_pos))
912 return -1;
913
914 return 0;
915 }
916
917 return -1;
918}
919
920static int ipt_acc_set_ctl(struct sock *sk, int cmd,
921 void *user, unsigned int len)
922{
923 struct ipt_acc_handle_sockopt handle;
924 int ret = -EINVAL;
925
926 if (!capable(CAP_NET_ADMIN))
927 return -EPERM;
928
929 switch (cmd) {
930 case IPT_SO_SET_ACCOUNT_HANDLE_FREE:
931 if (len != sizeof(struct ipt_acc_handle_sockopt)) {
932 printk("ACCOUNT: ipt_acc_set_ctl: wrong data size (%u != %zu) "
933 "for IPT_SO_SET_HANDLE_FREE\n",
934 len, sizeof(struct ipt_acc_handle_sockopt));
935 break;
936 }
937
938 if (copy_from_user (&handle, user, len)) {
939 printk("ACCOUNT: ipt_acc_set_ctl: copy_from_user failed for "
940 "IPT_SO_SET_HANDLE_FREE\n");
941 break;
942 }
943
944 down(&ipt_acc_userspace_mutex);
945 ret = ipt_acc_handle_free(handle.handle_nr);
946 up(&ipt_acc_userspace_mutex);
947 break;
948 case IPT_SO_SET_ACCOUNT_HANDLE_FREE_ALL: {
949 unsigned int i;
950 down(&ipt_acc_userspace_mutex);
951 for (i = 0; i < ACCOUNT_MAX_HANDLES; i++)
952 ipt_acc_handle_free(i);
953 up(&ipt_acc_userspace_mutex);
954 ret = 0;
955 break;
956 }
957 default:
958 printk("ACCOUNT: ipt_acc_set_ctl: unknown request %i\n", cmd);
959 }
960
961 return ret;
962}
963
964static int ipt_acc_get_ctl(struct sock *sk, int cmd, void *user, int *len)
965{
966 struct ipt_acc_handle_sockopt handle;
967 int ret = -EINVAL;
968
969 if (!capable(CAP_NET_ADMIN))
970 return -EPERM;
971
972 switch (cmd) {
973 case IPT_SO_GET_ACCOUNT_PREPARE_READ_FLUSH:
974 case IPT_SO_GET_ACCOUNT_PREPARE_READ: {
975 struct ipt_acc_handle dest;
976
977 if (*len < sizeof(struct ipt_acc_handle_sockopt)) {
978 printk("ACCOUNT: ipt_acc_get_ctl: wrong data size (%u != %zu) "
979 "for IPT_SO_GET_ACCOUNT_PREPARE_READ/READ_FLUSH\n",
980 *len, sizeof(struct ipt_acc_handle_sockopt));
981 break;
982 }
983
984 if (copy_from_user (&handle, user,
985 sizeof(struct ipt_acc_handle_sockopt))) {
986 return -EFAULT;
987 break;
988 }
989
990 spin_lock_bh(&ipt_acc_lock);
991 if (cmd == IPT_SO_GET_ACCOUNT_PREPARE_READ_FLUSH)
992 ret = ipt_acc_handle_prepare_read_flush(
993 handle.name, &dest, &handle.itemcount);
994 else
995 ret = ipt_acc_handle_prepare_read(
996 handle.name, &dest, &handle.itemcount);
997 spin_unlock_bh(&ipt_acc_lock);
998 // Error occured during prepare_read?
999 if (ret == -1)
1000 return -EINVAL;
1001
1002 /* Allocate a userspace handle */
1003 down(&ipt_acc_userspace_mutex);
1004 if ((handle.handle_nr = ipt_acc_handle_find_slot()) == -1) {
1005 ipt_acc_data_free(dest.data, dest.depth);
1006 up(&ipt_acc_userspace_mutex);
1007 return -EINVAL;
1008 }
1009 memcpy(&ipt_acc_handles[handle.handle_nr], &dest,
1010 sizeof(struct ipt_acc_handle));
1011 up(&ipt_acc_userspace_mutex);
1012
1013 if (copy_to_user(user, &handle,
1014 sizeof(struct ipt_acc_handle_sockopt))) {
1015 return -EFAULT;
1016 break;
1017 }
1018 ret = 0;
1019 break;
1020 }
1021 case IPT_SO_GET_ACCOUNT_GET_DATA:
1022 if (*len < sizeof(struct ipt_acc_handle_sockopt)) {
1023 printk("ACCOUNT: ipt_acc_get_ctl: wrong data size (%u != %zu)"
1024 " for IPT_SO_GET_ACCOUNT_PREPARE_READ/READ_FLUSH\n",
1025 *len, sizeof(struct ipt_acc_handle_sockopt));
1026 break;
1027 }
1028
1029 if (copy_from_user (&handle, user,
1030 sizeof(struct ipt_acc_handle_sockopt))) {
1031 return -EFAULT;
1032 break;
1033 }
1034
1035 if (handle.handle_nr >= ACCOUNT_MAX_HANDLES) {
1036 return -EINVAL;
1037 break;
1038 }
1039
1040 if (*len < ipt_acc_handles[handle.handle_nr].itemcount
1041 * sizeof(struct ipt_acc_handle_ip)) {
1042 printk("ACCOUNT: ipt_acc_get_ctl: not enough space (%u < %zu)"
1043 " to store data from IPT_SO_GET_ACCOUNT_GET_DATA\n",
1044 *len, ipt_acc_handles[handle.handle_nr].itemcount
1045 * sizeof(struct ipt_acc_handle_ip));
1046 ret = -ENOMEM;
1047 break;
1048 }
1049
1050 down(&ipt_acc_userspace_mutex);
1051 ret = ipt_acc_handle_get_data(handle.handle_nr, user);
1052 up(&ipt_acc_userspace_mutex);
1053 if (ret) {
1054 printk("ACCOUNT: ipt_acc_get_ctl: ipt_acc_handle_get_data"
1055 " failed for handle %u\n", handle.handle_nr);
1056 break;
1057 }
1058
1059 ret = 0;
1060 break;
1061 case IPT_SO_GET_ACCOUNT_GET_HANDLE_USAGE: {
1062 unsigned int i;
1063 if (*len < sizeof(struct ipt_acc_handle_sockopt)) {
1064 printk("ACCOUNT: ipt_acc_get_ctl: wrong data size (%u != %zu)"
1065 " for IPT_SO_GET_ACCOUNT_GET_HANDLE_USAGE\n",
1066 *len, sizeof(struct ipt_acc_handle_sockopt));
1067 break;
1068 }
1069
1070 /* Find out how many handles are in use */
1071 handle.itemcount = 0;
1072 down(&ipt_acc_userspace_mutex);
1073 for (i = 0; i < ACCOUNT_MAX_HANDLES; i++)
1074 if (ipt_acc_handles[i].data)
1075 handle.itemcount++;
1076 up(&ipt_acc_userspace_mutex);
1077
1078 if (copy_to_user(user, &handle,
1079 sizeof(struct ipt_acc_handle_sockopt))) {
1080 return -EFAULT;
1081 break;
1082 }
1083 ret = 0;
1084 break;
1085 }
1086 case IPT_SO_GET_ACCOUNT_GET_TABLE_NAMES: {
1087 u_int32_t size = 0, i, name_len;
1088 char *tnames;
1089
1090 spin_lock_bh(&ipt_acc_lock);
1091
1092 /* Determine size of table names */
1093 for (i = 0; i < ACCOUNT_MAX_TABLES; i++) {
1094 if (ipt_acc_tables[i].name[0] != 0)
1095 size += strlen (ipt_acc_tables[i].name) + 1;
1096 }
1097 size += 1; /* Terminating NULL character */
1098
1099 if (*len < size || size > PAGE_SIZE) {
1100 spin_unlock_bh(&ipt_acc_lock);
1101 printk("ACCOUNT: ipt_acc_get_ctl: not enough space (%u < %u < %lu)"
1102 " to store table names\n", *len, size, PAGE_SIZE);
1103 ret = -ENOMEM;
1104 break;
1105 }
1106 /* Copy table names to userspace */
1107 tnames = ipt_acc_tmpbuf;
1108 for (i = 0; i < ACCOUNT_MAX_TABLES; i++) {
1109 if (ipt_acc_tables[i].name[0] != 0) {
1110 name_len = strlen (ipt_acc_tables[i].name) + 1;
1111 memcpy(tnames, ipt_acc_tables[i].name, name_len);
1112 tnames += name_len;
1113 }
1114 }
1115 spin_unlock_bh(&ipt_acc_lock);
1116
1117 /* Terminating NULL character */
1118 *tnames = 0;
1119
1120 /* Transfer to userspace */
1121 if (copy_to_user(user, ipt_acc_tmpbuf, size))
1122 return -EFAULT;
1123
1124 ret = 0;
1125 break;
1126 }
1127 default:
1128 printk("ACCOUNT: ipt_acc_get_ctl: unknown request %i\n", cmd);
1129 }
1130
1131 return ret;
1132}
1133
1134#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21)
1135static struct xt_target xt_acc_reg = {
1136#else
1137static struct ipt_target ipt_acc_reg = {
1138#endif
1139 .name = "ACCOUNT",
1140#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21)
1141 .family = AF_INET,
1142#endif
1143 .target = ipt_acc_target,
1144#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,17)
1145 .targetsize = sizeof(struct ipt_acc_info),
1146#endif
1147 .checkentry = ipt_acc_checkentry,
1148 .destroy = ipt_acc_destroy,
1149 .me = THIS_MODULE
1150};
1151
1152static struct nf_sockopt_ops ipt_acc_sockopts = {
1153 .pf = PF_INET,
1154 .set_optmin = IPT_SO_SET_ACCOUNT_HANDLE_FREE,
1155 .set_optmax = IPT_SO_SET_ACCOUNT_MAX+1,
1156 .set = ipt_acc_set_ctl,
1157 .get_optmin = IPT_SO_GET_ACCOUNT_PREPARE_READ,
1158 .get_optmax = IPT_SO_GET_ACCOUNT_MAX+1,
1159 .get = ipt_acc_get_ctl
1160};
1161
1162static int __init init(void)
1163{
7c213d6f 1164 sema_init(&ipt_acc_userspace_mutex, 1);
3b4b23d1
TJ
1165
1166 if ((ipt_acc_tables =
1167 kmalloc(ACCOUNT_MAX_TABLES *
1168 sizeof(struct ipt_acc_table), GFP_KERNEL)) == NULL) {
1169 printk("ACCOUNT: Out of memory allocating account_tables structure");
1170 goto error_cleanup;
1171 }
1172 memset(ipt_acc_tables, 0,
1173 ACCOUNT_MAX_TABLES * sizeof(struct ipt_acc_table));
1174
1175 if ((ipt_acc_handles =
1176 kmalloc(ACCOUNT_MAX_HANDLES *
1177 sizeof(struct ipt_acc_handle), GFP_KERNEL)) == NULL) {
1178 printk("ACCOUNT: Out of memory allocating account_handles structure");
1179 goto error_cleanup;
1180 }
1181 memset(ipt_acc_handles, 0,
1182 ACCOUNT_MAX_HANDLES * sizeof(struct ipt_acc_handle));
1183
1184 /* Allocate one page as temporary storage */
1185 if ((ipt_acc_tmpbuf = (void*)__get_free_page(GFP_KERNEL)) == NULL) {
1186 printk("ACCOUNT: Out of memory for temporary buffer page\n");
1187 goto error_cleanup;
1188 }
1189
1190 /* Register setsockopt */
1191 if (nf_register_sockopt(&ipt_acc_sockopts) < 0) {
1192 printk("ACCOUNT: Can't register sockopts. Aborting\n");
1193 goto error_cleanup;
1194 }
1195
1196#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21)
1197 if (xt_register_target(&xt_acc_reg))
1198#else
1199 if (ipt_register_target(&ipt_acc_reg))
1200#endif
1201 goto error_cleanup;
1202
1203 return 0;
1204
1205error_cleanup:
1206 if(ipt_acc_tables)
1207 kfree(ipt_acc_tables);
1208 if(ipt_acc_handles)
1209 kfree(ipt_acc_handles);
1210 if (ipt_acc_tmpbuf)
1211 free_page((unsigned long)ipt_acc_tmpbuf);
1212
1213 return -EINVAL;
1214}
1215
1216static void __exit fini(void)
1217{
1218#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21)
1219 xt_unregister_target(&xt_acc_reg);
1220#else
1221 ipt_unregister_target(&ipt_acc_reg);
1222#endif
1223
1224 nf_unregister_sockopt(&ipt_acc_sockopts);
1225
1226 kfree(ipt_acc_tables);
1227 kfree(ipt_acc_handles);
1228 free_page((unsigned long)ipt_acc_tmpbuf);
1229}
1230
1231module_init(init);
1232module_exit(fini);
1233MODULE_LICENSE("GPL");