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