1 /* Copyright (c) 2004-2006 Piotr 'QuakeR' Gasidlo <quaker@barbara.eu.org>
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 as
5 * published by the Free Software Foundation.
8 #include <linux/moduleparam.h>
9 // #include <linux/module.h>
10 #include <linux/skbuff.h>
11 #include <linux/vmalloc.h>
12 #include <linux/proc_fs.h>
13 #include <linux/seq_file.h>
14 #include <linux/time.h>
15 #include <asm/uaccess.h>
16 #include <linux/spinlock.h>
17 #include <linux/interrupt.h>
19 #define IPT_ACCOUNT_VERSION "0.1.20"
21 // #define DEBUG_IPT_ACCOUNT
23 MODULE_AUTHOR("Piotr Gasidlo <quaker@barbara.eu.org>");
24 MODULE_DESCRIPTION("Traffic accounting module");
25 MODULE_LICENSE("GPL");
27 #include <linux/netfilter_ipv4/ip_tables.h>
28 #include <linux/netfilter_ipv4/ipt_account.h>
30 /* defaults, can be overriden */
31 static unsigned int netmask
= 16; /* Safe netmask, if you try to create table
32 for larger netblock you will get error.
33 Increase by command line only when you
34 known what are you doing. */
36 #ifdef DEBUG_IPT_ACCOUNT
40 MODULE_PARM(netmask
, "i");
41 MODULE_PARM_DESC(netmask
,"maximum *save* netmask");
42 #ifdef DEBUG_IPT_ACCOUNT
43 MODULE_PARM(debug
, "i");
44 MODULE_PARM_DESC(debug
,"enable debugging output");
47 /* structure with statistics counter, used when table is created without --ashort switch */
48 struct t_ipt_account_stat_long
{
49 u_int64_t b_all
, b_tcp
, b_udp
, b_icmp
, b_other
;
50 u_int64_t p_all
, p_tcp
, p_udp
, p_icmp
, p_other
;
53 /* same as above, for tables created with --ashort switch */
54 struct t_ipt_account_stat_short
{
59 /* structure holding to/from statistics for single ip when table is created without --ashort switch */
60 struct t_ipt_account_stats_long
{
61 struct t_ipt_account_stat_long src
, dst
;
62 struct timespec time
; /* time, when statistics was last modified */
65 /* same as above, for tables created with --ashort switch */
66 struct t_ipt_account_stats_short
{
67 struct t_ipt_account_stat_short src
, dst
;
71 /* structure describing single table */
72 struct t_ipt_account_table
{
73 struct list_head list
;
74 atomic_t use
; /* use counter, the number of rules which points to this table */
76 char name
[IPT_ACCOUNT_NAME_LEN
+ 1]; /* table name ( = filename in /proc/net/ipt_account/) */
77 u_int32_t network
, netmask
, count
; /* network/netmask/hosts count coverted by table */
79 int shortlisting
:1; /* gather only total statistics (set for tables created with --ashort switch) */
80 int timesrc
:1; /* update time when accounting outgoing traffic */
81 int timedst
:1; /* update time when accounting incomming traffic */
83 union { /* statistics for each ip in network/netmask */
84 struct t_ipt_account_stats_long
*l
;
85 struct t_ipt_account_stats_short
*s
;
87 rwlock_t stats_lock
; /* lock, to assure that above union can be safely modified */
89 struct proc_dir_entry
*pde
; /* handle to proc entry */
92 static LIST_HEAD(ipt_account_tables
);
93 static rwlock_t ipt_account_lock
= RW_LOCK_UNLOCKED
; /* lock, to assure that table list can be safely modified */
94 static DECLARE_MUTEX(ipt_account_mutex
); /* additional checkentry protection */
96 static struct file_operations ipt_account_proc_fops
;
97 static struct proc_dir_entry
*ipt_account_procdir
;
100 * Function creates new table and inserts it into linked list.
102 static struct t_ipt_account_table
*
103 ipt_account_table_init(struct t_ipt_account_info
*info
)
105 struct t_ipt_account_table
*table
;
107 #ifdef IPT_ACCOUNT_DEBUG
108 if (debug
) printk(KERN_DEBUG
"ipt_account [ipt_account_table_init]: name = %s\n", info
->name
);
112 * Allocate memory for table.
114 table
= vmalloc(sizeof(struct t_ipt_account_table
));
116 printk(KERN_ERR
"ipt_account [ipt_account_table_init]: table = vmalloc(sizeof(struct t_ipt_account_table)) failed.\n");
119 memset(table
, 0, sizeof(struct t_ipt_account_table
));
124 strncpy(table
->name
, info
->name
, IPT_ACCOUNT_NAME_LEN
);
125 table
->name
[IPT_ACCOUNT_NAME_LEN
] = '\0';
127 table
->network
= info
->network
;
128 table
->netmask
= info
->netmask
;
129 table
->count
= (0xffffffff ^ table
->netmask
) + 1;
134 table
->shortlisting
= info
->shortlisting
;
139 * Initialize use counter.
141 atomic_set(&table
->use
, 1);
144 * Allocate memory for statistic counters.
146 if (table
->shortlisting
) {
147 table
->stats
.s
= vmalloc(sizeof(struct t_ipt_account_stats_short
) * table
->count
);
148 if (!table
->stats
.s
) {
149 printk(KERN_ERR
"ipt_account [ipt_account_table_init]: table->stats.s = vmalloc(sizeof(struct t_ipt_account_stats_short) * table->count) failed.\n");
152 memset(table
->stats
.s
, 0, sizeof(struct t_ipt_account_stats_short
) * table
->count
);
154 table
->stats
.l
= vmalloc(sizeof(struct t_ipt_account_stats_long
) * table
->count
);
155 if (!table
->stats
.l
) {
156 printk(KERN_ERR
"ipt_account [ipt_account_table_init]: table->stats.l = vmalloc(sizeof(struct t_ipt_account_stats_long) * table->count) failed.\n");
159 memset(table
->stats
.l
, 0, sizeof(struct t_ipt_account_stats_long
) * table
->count
);
165 table
->stats_lock
= RW_LOCK_UNLOCKED
;
168 * Create /proc/ipt_account/name entry.
170 table
->pde
= create_proc_entry(table
->name
, S_IWUSR
| S_IRUSR
, ipt_account_procdir
);
174 table
->pde
->proc_fops
= &ipt_account_proc_fops
;
175 table
->pde
->data
= table
;
178 * Insert table into list.
180 write_lock_bh(&ipt_account_lock
);
181 list_add(&table
->list
, &ipt_account_tables
);
182 write_unlock_bh(&ipt_account_lock
);
187 * If something goes wrong we end here.
190 if (table
->shortlisting
)
191 vfree(table
->stats
.s
);
193 vfree(table
->stats
.l
);
203 * Function destroys table. Table *must* be already unlinked.
206 ipt_account_table_destroy(struct t_ipt_account_table
*table
)
208 #ifdef IPT_ACCOUNT_DEBUG
209 if (debug
) printk(KERN_DEBUG
"ipt_account [ipt_account_table_destory]: name = %s\n", table
->name
);
211 remove_proc_entry(table
->pde
->name
, table
->pde
->parent
);
212 if (table
->shortlisting
)
213 vfree(table
->stats
.s
);
215 vfree(table
->stats
.l
);
220 * Function increments use counter for table.
223 ipt_account_table_get(struct t_ipt_account_table
*table
)
225 #ifdef IPT_ACCOUNT_DEBUG
226 if (debug
) printk(KERN_DEBUG
"ipt_account [ipt_account_table_get]: name = %s\n", table
->name
);
228 atomic_inc(&table
->use
);
232 * Function decrements use counter for table. If use counter drops to zero,
233 * table is removed from linked list and destroyed.
236 ipt_account_table_put(struct t_ipt_account_table
*table
)
238 #ifdef IPT_ACCOUNT_DEBUG
239 if (debug
) printk(KERN_DEBUG
"ipt_account [ipt_account_table_put]: name = %s\n", table
->name
);
241 if (atomic_dec_and_test(&table
->use
)) {
242 write_lock_bh(&ipt_account_lock
);
243 list_del(&table
->list
);
244 write_unlock_bh(&ipt_account_lock
);
245 ipt_account_table_destroy(table
);
250 * Helper function, which returns a structure pointer to a table with
253 static struct t_ipt_account_table
*
254 __ipt_account_table_find(char *name
)
256 struct list_head
*pos
;
257 list_for_each(pos
, &ipt_account_tables
) {
258 struct t_ipt_account_table
*table
= list_entry(pos
,
259 struct t_ipt_account_table
, list
);
260 if (!strncmp(table
->name
, name
, IPT_ACCOUNT_NAME_LEN
))
267 * Function, which returns a structure pointer to a table with
268 * specified name. When such table is found its use coutner
271 static inline struct t_ipt_account_table
*
272 ipt_account_table_find_get(char *name
)
274 struct t_ipt_account_table
*table
;
276 #ifdef IPT_ACCOUNT_DEBUG
277 if (debug
) printk(KERN_DEBUG
"ipt_account [ipt_account_table_find_get]: name = %s\n", name
);
279 read_lock_bh(&ipt_account_lock
);
280 table
= __ipt_account_table_find(name
);
282 read_unlock_bh(&ipt_account_lock
);
285 atomic_inc(&table
->use
);
286 read_unlock_bh(&ipt_account_lock
);
291 * Helper function, with updates statistics for specified IP. It's only
292 * used for tables created without --ashort switch.
295 __account_long(struct t_ipt_account_stat_long
*stat
, const struct sk_buff
*skb
)
297 stat
->b_all
+= skb
->len
;
300 switch (skb
->nh
.iph
->protocol
) {
302 stat
->b_tcp
+= skb
->len
;
306 stat
->b_udp
+= skb
->len
;
310 stat
->b_icmp
+= skb
->len
;
314 stat
->b_other
+= skb
->len
;
320 * Same as above, but used for tables created with --ashort switch.
323 __account_short(struct t_ipt_account_stat_short
*stat
, const struct sk_buff
*skb
)
325 stat
->b_all
+= skb
->len
;
330 * Match function. Here we do accounting stuff.
333 match(const struct sk_buff
*skb
,
334 const struct net_device
*in
,
335 const struct net_device
*out
,
336 const void *matchinfo
,
342 struct t_ipt_account_info
*info
= (struct t_ipt_account_info
*)matchinfo
;
343 struct t_ipt_account_table
*table
= info
->table
;
345 /* Get current time. */
347 jiffies_to_timespec(jiffies
, &now
);
348 /* Default we assume no match. */
351 #ifdef IPT_ACCOUNT_DEBUG
352 if (debug
) printk(KERN_DEBUG
"ipt_account [match]: name = %s\n", table
->name
);
354 /* Check whether traffic from source ip address ... */
355 address
= ntohl(skb
->nh
.iph
->saddr
);
356 /* ... is being accounted by this table. */
357 if (address
&& ((u_int32_t
)(address
& table
->netmask
) == (u_int32_t
)table
->network
)) {
358 write_lock_bh(&table
->stats_lock
);
359 /* Yes, account this packet. */
360 #ifdef IPT_ACCOUNT_DEBUG
361 if (debug
) printk(KERN_DEBUG
"ipt_account: [match]: accounting packet src = %u.%u.%u.%u, proto = %u.\n", HIPQUAD(address
), skb
->nh
.iph
->protocol
);
363 /* Update counters this host. */
364 if (!table
->shortlisting
) {
365 __account_long(&table
->stats
.l
[address
- table
->network
].src
, skb
);
367 table
->stats
.l
[address
- table
->network
].time
= now
;
368 /* Update also counters for all hosts in this table (network address) */
369 if (table
->count
> 1) {
370 __account_long(&table
->stats
.l
[0].src
, skb
);
371 table
->stats
.l
[0].time
= now
;
374 __account_short(&table
->stats
.s
[address
- table
->network
].src
, skb
);
376 table
->stats
.s
[address
- table
->network
].time
= now
;
377 if (table
->count
> 1) {
378 __account_short(&table
->stats
.s
[0].src
, skb
);
379 table
->stats
.s
[0].time
= now
;
382 write_unlock_bh(&table
->stats_lock
);
383 /* Yes, it's a match. */
387 /* Do the same thing with destination ip address. */
388 address
= ntohl(skb
->nh
.iph
->daddr
);
389 if (address
&& ((u_int32_t
)(address
& table
->netmask
) == (u_int32_t
)table
->network
)) {
390 write_lock_bh(&table
->stats_lock
);
391 #ifdef IPT_ACCOUNT_DEBUG
392 if (debug
) printk(KERN_DEBUG
"ipt_account: [match]: accounting packet dst = %u.%u.%u.%u, proto = %u.\n", HIPQUAD(address
), skb
->nh
.iph
->protocol
);
394 if (!table
->shortlisting
) {
395 __account_long(&table
->stats
.l
[address
- table
->network
].dst
, skb
);
396 table
->stats
.l
[address
- table
->network
].time
= now
;
397 if (table
->count
> 1) {
398 __account_long(&table
->stats
.l
[0].dst
, skb
);
399 table
->stats
.l
[0].time
= now
;
402 __account_short(&table
->stats
.s
[address
- table
->network
].dst
, skb
);
403 table
->stats
.s
[address
- table
->network
].time
= now
;
404 if (table
->count
> 1) {
405 __account_short(&table
->stats
.s
[0].dst
, skb
);
406 table
->stats
.s
[0].time
= now
;
409 write_unlock_bh(&table
->stats_lock
);
417 * Checkentry function.
420 checkentry(const char *tablename
,
421 const struct ipt_ip
*ipt_ip
,
423 unsigned int matchsize
,
424 unsigned int hook_mask
)
426 struct t_ipt_account_info
*info
= matchinfo
;
427 struct t_ipt_account_table
*table
;
429 #ifdef IPT_ACCOUNT_DEBUG
430 if (debug
) printk(KERN_DEBUG
"ipt_account [checkentry]: name = %s\n", info
->name
);
432 if (matchsize
!= IPT_ALIGN(sizeof(struct t_ipt_account_info
)))
438 if (info
->netmask
< ((~0L << (32 - netmask
)) & 0xffffffff)) {
439 printk(KERN_ERR
"ipt_account[checkentry]: too big netmask (increase module 'netmask' parameter).\n");
442 if ((info
->network
& info
->netmask
) != info
->network
) {
443 printk(KERN_ERR
"ipt_account[checkentry]: wrong network/netmask.\n");
446 if (info
->name
[0] == '\0') {
447 printk(KERN_ERR
"ipt_account[checkentry]: wrong table name.\n");
452 * We got new rule. Try to find table with the same name as given in info structure.
453 * Mutex magic based on ipt_hashlimit.c.
455 down(&ipt_account_mutex
);
456 table
= ipt_account_table_find_get(info
->name
);
458 if (info
->table
!= NULL
) {
459 if (info
->table
!= table
) {
463 printk(KERN_ERR
"ipt_account[checkentry]: reloaded rule has invalid table pointer.\n");
464 up(&ipt_account_mutex
);
467 up(&ipt_account_mutex
);
470 #ifdef IPT_ACCOUNT_DEBUG
471 if (debug
) printk(KERN_DEBUG
"ipt_account [checkentry]: table found, checking.\n");
474 * Table exists, but whether rule network/netmask/shortlisting matches
475 * table network/netmask/shortlisting. Failure on missmatch.
477 if (table
->network
!= info
->network
|| table
->netmask
!= info
->netmask
|| table
->shortlisting
!= info
->shortlisting
) {
478 printk(KERN_ERR
"ipt_account [checkentry]: table found, rule network/netmask/shortlisting not match table network/netmask/shortlisting.\n");
480 * Remember to release table usage counter.
482 ipt_account_table_put(table
);
483 up(&ipt_account_mutex
);
486 #ifdef IPT_ACCOUNT_DEBUG
487 if (debug
) printk(KERN_DEBUG
"ipt_account [checkentry]: table found, reusing.\n");
490 * Link rule with table.
495 #ifdef IPT_ACCOUNT_DEBUG
496 if (debug
) printk(KERN_DEBUG
"ipt_account [checkentry]: table not found, creating new one.\n");
499 * Table not exist, create new one.
501 info
->table
= table
= ipt_account_table_init(info
);
503 up(&ipt_account_mutex
);
507 up(&ipt_account_mutex
);
515 destroy(void *matchinfo
, unsigned int matchsize
)
517 struct t_ipt_account_info
*info
= matchinfo
;
519 #ifdef IPT_ACCOUNT_DEBUG
520 if (debug
) printk(KERN_DEBUG
"ipt_account [destroy]: name = %s\n", info
->name
);
523 * Release table, by decreasing its usage counter. When
524 * counter hits zero, memory used by table structure is
525 * released and table is removed from list.
527 ipt_account_table_put(info
->table
);
531 static struct ipt_match account_match
= {
534 .checkentry
= &checkentry
,
540 * Below functions (ipt_account_seq_start, ipt_account_seq_next,
541 * ipt_account_seq_stop, ipt_account_seq_show, ipt_account_proc_write)
542 * are used to implement proc stuff.
544 static void *ipt_account_seq_start(struct seq_file
*sf
, loff_t
*pos
)
546 struct proc_dir_entry
*pde
= sf
->private;
547 struct t_ipt_account_table
*table
= pde
->data
;
550 read_lock_bh(&table
->stats_lock
);
551 if (*pos
>= table
->count
)
553 i
= kmalloc(sizeof(unsigned int), GFP_ATOMIC
);
555 return ERR_PTR(-ENOMEM
);
560 static void *ipt_account_seq_next(struct seq_file
*sf
, void *v
, loff_t
*pos
)
562 struct proc_dir_entry
*pde
= sf
->private;
563 struct t_ipt_account_table
*table
= pde
->data
;
564 unsigned int *i
= (unsigned int *)v
;
567 if (*i
>= table
->count
) {
574 static void ipt_account_seq_stop(struct seq_file
*sf
, void *v
)
576 struct proc_dir_entry
*pde
= sf
->private;
577 struct t_ipt_account_table
*table
= pde
->data
;
579 read_unlock_bh(&table
->stats_lock
);
582 static int ipt_account_seq_show(struct seq_file
*sf
, void *v
)
584 struct proc_dir_entry
*pde
= sf
->private;
585 struct t_ipt_account_table
*table
= pde
->data
;
586 unsigned int *i
= (unsigned int *)v
;
589 jiffies_to_timespec(jiffies
, &now
);
591 u_int32_t address
= table
->network
+ *i
;
593 if (!table
->shortlisting
) {
594 struct t_ipt_account_stats_long
*l
= &table
->stats
.l
[*i
];
596 "ip = %u.%u.%u.%u bytes_src = %Lu %Lu %Lu %Lu %Lu packets_src = %Lu %Lu %Lu %Lu %Lu bytes_dst = %Lu %Lu %Lu %Lu %Lu packets_dst = %Lu %Lu %Lu %Lu %Lu time = %lu\n",
618 now
.tv_sec
- l
->time
.tv_sec
621 struct t_ipt_account_stats_short
*s
= &table
->stats
.s
[*i
];
623 "ip = %u.%u.%u.%u bytes_src = %Lu packets_src = %Lu bytes_dst = %Lu packets_dst = %Lu time = %lu\n",
629 now
.tv_sec
- s
->time
.tv_sec
636 static struct seq_operations ipt_account_seq_ops
= {
637 .start
= ipt_account_seq_start
,
638 .next
= ipt_account_seq_next
,
639 .stop
= ipt_account_seq_stop
,
640 .show
= ipt_account_seq_show
643 static ssize_t
ipt_account_proc_write(struct file
*file
, const char __user
*input
, size_t size
, loff_t
*ofs
)
646 struct proc_dir_entry
*pde
= PDE(file
->f_dentry
->d_inode
);
647 struct t_ipt_account_table
*table
= pde
->data
;
650 struct t_ipt_account_stats_long l
;
651 struct t_ipt_account_stats_short s
;
653 #ifdef IPT_ACCOUNT_DEBUG
654 if (debug
) printk(KERN_DEBUG
"ipt_account [ipt_account_proc_write]: name = %s.\n", table
->name
);
656 if (copy_from_user(buffer
, input
, 1024))
660 if (!strncmp(buffer
, "reset\n", 6)) {
662 * User requested to clear all table. Ignorant, does
663 * he known how match time it took us to fill it? ;-)
665 write_lock_bh(&table
->stats_lock
);
666 if (table
->shortlisting
)
667 memset(table
->stats
.s
, 0, sizeof(struct t_ipt_account_stats_short
) * table
->count
);
669 memset(table
->stats
.l
, 0, sizeof(struct t_ipt_account_stats_long
) * table
->count
);
670 write_unlock_bh(&table
->stats_lock
);
671 } else if (!strncmp(buffer
, "time=any\n", 9)) {
672 table
->timesrc
= table
->timedst
= 1;
673 } else if (!strncmp(buffer
, "time=src\n", 9)) {
676 } else if (!strncmp(buffer
, "time=dst\n", 9)) {
679 } else if (!table
->shortlisting
&& sscanf(buffer
, "ip = %u.%u.%u.%u bytes_src = %Lu %Lu %Lu %Lu %Lu packets_src = %Lu %Lu %Lu %Lu %Lu bytes_dst = %Lu %Lu %Lu %Lu %Lu packets_dst = %Lu %Lu %Lu %Lu %Lu time = %lu",
680 &o
[0], &o
[1], &o
[2], &o
[3],
681 &l
.src
.b_all
, &l
.src
.b_tcp
, &l
.src
.b_udp
, &l
.src
.b_icmp
, &l
.src
.b_other
,
682 &l
.src
.p_all
, &l
.src
.p_tcp
, &l
.src
.p_udp
, &l
.src
.p_icmp
, &l
.src
.p_other
,
683 &l
.dst
.b_all
, &l
.dst
.b_tcp
, &l
.dst
.b_udp
, &l
.dst
.b_icmp
, &l
.dst
.b_other
,
684 &l
.dst
.p_all
, &l
.dst
.p_tcp
, &l
.dst
.p_udp
, &l
.dst
.p_icmp
, &l
.dst
.p_other
,
685 &l
.time
.tv_sec
) == 25) {
687 * We got line formated like long listing row. We have to
688 * check, if IP is accounted by table. If so, we
689 * simply replace row with user's one.
691 ip
= o
[0] << 24 | o
[1] << 16 | o
[2] << 8 | o
[3];
692 if ((u_int32_t
)(ip
& table
->netmask
) == (u_int32_t
)table
->network
) {
694 * Ignore user input time. Set current time.
696 jiffies_to_timespec(jiffies
, &l
.time
);
697 write_lock_bh(&table
->stats_lock
);
698 table
->stats
.l
[ip
- table
->network
] = l
;
699 write_unlock_bh(&table
->stats_lock
);
701 } else if (table
->shortlisting
&& sscanf(buffer
, "ip = %u.%u.%u.%u bytes_src = %Lu packets_src = %Lu bytes_dst = %Lu packets_dst = %Lu time = %lu\n",
702 &o
[0], &o
[1], &o
[2], &o
[3],
707 &s
.time
.tv_sec
) == 9) {
709 * We got line formated like short listing row. Do the
710 * same action like above.
712 ip
= o
[0] << 24 | o
[1] << 16 | o
[2] << 8 | o
[3];
713 if ((u_int32_t
)(ip
& table
->netmask
) == (u_int32_t
)table
->network
) {
714 jiffies_to_timespec(jiffies
, &s
.time
);
715 write_lock_bh(&table
->stats_lock
);
716 table
->stats
.s
[ip
- table
->network
] = s
;
717 write_unlock_bh(&table
->stats_lock
);
721 * We don't understand what user have just wrote.
729 static int ipt_account_proc_open(struct inode
*inode
, struct file
*file
)
731 int ret
= seq_open(file
, &ipt_account_seq_ops
);
733 struct seq_file
*sf
= file
->private_data
;
734 struct proc_dir_entry
*pde
= PDE(inode
);
735 struct t_ipt_account_table
*table
= pde
->data
;
739 ipt_account_table_get(table
);
744 static int ipt_account_proc_release(struct inode
*inode
, struct file
*file
)
746 struct proc_dir_entry
*pde
= PDE(inode
);
747 struct t_ipt_account_table
*table
= pde
->data
;
750 ret
= seq_release(inode
, file
);
753 ipt_account_table_put(table
);
758 static struct file_operations ipt_account_proc_fops
= {
759 .owner
= THIS_MODULE
,
760 .open
= ipt_account_proc_open
,
762 .write
= ipt_account_proc_write
,
764 .release
= ipt_account_proc_release
768 * Module init function.
770 static int __init
init(void)
774 printk(KERN_INFO
"ipt_account %s : Piotr Gasidlo <quaker@barbara.eu.org>, http://www.barbara.eu.org/~quaker/ipt_account/\n", IPT_ACCOUNT_VERSION
);
776 /* Check module parameters. */
777 if (netmask
> 32 || netmask
< 0) {
778 printk(KERN_ERR
"ipt_account[__init]: Wrong netmask given as parameter (%i). Valid is 32 to 0.\n", netmask
);
783 /* Register match. */
784 if (ipt_register_match(&account_match
)) {
789 /* Create /proc/net/ipt_account/ entry. */
790 ipt_account_procdir
= proc_mkdir("ipt_account", proc_net
);
791 if (!ipt_account_procdir
) {
792 printk(KERN_ERR
"ipt_account [__init]: ipt_account_procdir = proc_mkdir(\"ipt_account\", proc_net) failed.\n");
799 /* If something goes wrong we end here. */
801 ipt_unregister_match(&account_match
);
807 * Module exit function.
809 static void __exit
fini(void)
811 /* Remove /proc/net/ipt_account/ */
812 remove_proc_entry(ipt_account_procdir
->name
, ipt_account_procdir
->parent
);
813 ipt_unregister_match(&account_match
);