Changes for kernel and Busybox
[tomato.git] / release / src / linux / linux / net / ipv4 / netfilter / ipt_account.c
blob8b862588a32c7789cbdb11b1d36d2cdd88503037
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.
6 */
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
37 static int debug = 0;
38 #endif
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");
45 #endif
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 {
55 u_int64_t b_all;
56 u_int64_t p_all;
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;
68 struct timespec time;
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;
86 } stats;
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);
109 #endif
112 * Allocate memory for table.
114 table = vmalloc(sizeof(struct t_ipt_account_table));
115 if (!table) {
116 printk(KERN_ERR "ipt_account [ipt_account_table_init]: table = vmalloc(sizeof(struct t_ipt_account_table)) failed.\n");
117 goto cleanup_none;
119 memset(table, 0, sizeof(struct t_ipt_account_table));
122 * Table attributes.
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;
132 * Table properties.
134 table->shortlisting = info->shortlisting;
135 table->timesrc = 1;
136 table->timedst = 1;
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");
150 goto cleanup_table;
152 memset(table->stats.s, 0, sizeof(struct t_ipt_account_stats_short) * table->count);
153 } else {
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");
157 goto cleanup_table;
159 memset(table->stats.l, 0, sizeof(struct t_ipt_account_stats_long) * table->count);
163 * Reset locks.
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);
171 if (!table->pde) {
172 goto cleanup_stats;
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);
184 return table;
187 * If something goes wrong we end here.
189 cleanup_stats:
190 if (table->shortlisting)
191 vfree(table->stats.s);
192 else
193 vfree(table->stats.l);
195 cleanup_table:
196 vfree(table);
197 cleanup_none:
198 return NULL;
203 * Function destroys table. Table *must* be already unlinked.
205 static void
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);
210 #endif
211 remove_proc_entry(table->pde->name, table->pde->parent);
212 if (table->shortlisting)
213 vfree(table->stats.s);
214 else
215 vfree(table->stats.l);
216 vfree(table);
220 * Function increments use counter for table.
222 static inline void
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);
227 #endif
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.
235 static inline void
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);
240 #endif
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
251 * specified name.
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))
261 return table;
263 return NULL;
267 * Function, which returns a structure pointer to a table with
268 * specified name. When such table is found its use coutner
269 * is incremented.
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);
278 #endif
279 read_lock_bh(&ipt_account_lock);
280 table = __ipt_account_table_find(name);
281 if (!table) {
282 read_unlock_bh(&ipt_account_lock);
283 return NULL;
285 atomic_inc(&table->use);
286 read_unlock_bh(&ipt_account_lock);
287 return table;
291 * Helper function, with updates statistics for specified IP. It's only
292 * used for tables created without --ashort switch.
294 static inline void
295 __account_long(struct t_ipt_account_stat_long *stat, const struct sk_buff *skb)
297 stat->b_all += skb->len;
298 stat->p_all++;
300 switch (skb->nh.iph->protocol) {
301 case IPPROTO_TCP:
302 stat->b_tcp += skb->len;
303 stat->p_tcp++;
304 break;
305 case IPPROTO_UDP:
306 stat->b_udp += skb->len;
307 stat->p_udp++;
308 break;
309 case IPPROTO_ICMP:
310 stat->b_icmp += skb->len;
311 stat->p_icmp++;
312 break;
313 default:
314 stat->b_other += skb->len;
315 stat->p_other++;
320 * Same as above, but used for tables created with --ashort switch.
322 static inline void
323 __account_short(struct t_ipt_account_stat_short *stat, const struct sk_buff *skb)
325 stat->b_all += skb->len;
326 stat->p_all++;
330 * Match function. Here we do accounting stuff.
332 static int
333 match(const struct sk_buff *skb,
334 const struct net_device *in,
335 const struct net_device *out,
336 const void *matchinfo,
337 int offset,
338 const void *hdr,
339 u_int16_t datalen,
340 int *hotdrop)
342 struct t_ipt_account_info *info = (struct t_ipt_account_info *)matchinfo;
343 struct t_ipt_account_table *table = info->table;
344 u_int32_t address;
345 /* Get current time. */
346 struct timespec now;
347 jiffies_to_timespec(jiffies, &now);
348 /* Default we assume no match. */
349 int ret = 0;
351 #ifdef IPT_ACCOUNT_DEBUG
352 if (debug) printk(KERN_DEBUG "ipt_account [match]: name = %s\n", table->name);
353 #endif
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);
362 #endif
363 /* Update counters this host. */
364 if (!table->shortlisting) {
365 __account_long(&table->stats.l[address - table->network].src, skb);
366 if (table->timesrc)
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;
373 } else {
374 __account_short(&table->stats.s[address - table->network].src, skb);
375 if (table->timedst)
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. */
384 ret = 1;
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);
393 #endif
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;
401 } else {
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);
410 ret = 1;
413 return ret;
417 * Checkentry function.
419 static int
420 checkentry(const char *tablename,
421 const struct ipt_ip *ipt_ip,
422 void *matchinfo,
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);
431 #endif
432 if (matchsize != IPT_ALIGN(sizeof(struct t_ipt_account_info)))
433 return 0;
436 * Sanity checks.
438 if (info->netmask < ((~0L << (32 - netmask)) & 0xffffffff)) {
439 printk(KERN_ERR "ipt_account[checkentry]: too big netmask (increase module 'netmask' parameter).\n");
440 return 0;
442 if ((info->network & info->netmask) != info->network) {
443 printk(KERN_ERR "ipt_account[checkentry]: wrong network/netmask.\n");
444 return 0;
446 if (info->name[0] == '\0') {
447 printk(KERN_ERR "ipt_account[checkentry]: wrong table name.\n");
448 return 0;
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);
457 if (table) {
458 if (info->table != NULL) {
459 if (info->table != table) {
461 * Shouldn't happen.
463 printk(KERN_ERR "ipt_account[checkentry]: reloaded rule has invalid table pointer.\n");
464 up(&ipt_account_mutex);
465 return 0;
467 up(&ipt_account_mutex);
468 return 1;
469 } else {
470 #ifdef IPT_ACCOUNT_DEBUG
471 if (debug) printk(KERN_DEBUG "ipt_account [checkentry]: table found, checking.\n");
472 #endif
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);
484 return 0;
486 #ifdef IPT_ACCOUNT_DEBUG
487 if (debug) printk(KERN_DEBUG "ipt_account [checkentry]: table found, reusing.\n");
488 #endif
490 * Link rule with table.
492 info->table = table;
494 } else {
495 #ifdef IPT_ACCOUNT_DEBUG
496 if (debug) printk(KERN_DEBUG "ipt_account [checkentry]: table not found, creating new one.\n");
497 #endif
499 * Table not exist, create new one.
501 info->table = table = ipt_account_table_init(info);
502 if (!table) {
503 up(&ipt_account_mutex);
504 return 0;
507 up(&ipt_account_mutex);
508 return 1;
512 * Destroy function.
514 static void
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);
521 #endif
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);
528 return;
531 static struct ipt_match account_match = {
532 .name = "account",
533 .match = &match,
534 .checkentry = &checkentry,
535 .destroy = &destroy,
536 .me = THIS_MODULE
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;
548 unsigned int *i;
550 read_lock_bh(&table->stats_lock);
551 if (*pos >= table->count)
552 return NULL;
553 i = kmalloc(sizeof(unsigned int), GFP_ATOMIC);
554 if (!i)
555 return ERR_PTR(-ENOMEM);
556 *i = *pos;
557 return i;
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;
566 *pos = ++(*i);
567 if (*i >= table->count) {
568 kfree(v);
569 return NULL;
571 return i;
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;
578 kfree(v);
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;
588 struct timespec now;
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];
595 seq_printf(sf,
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",
597 HIPQUAD(address),
598 l->src.b_all,
599 l->src.b_tcp,
600 l->src.b_udp,
601 l->src.b_icmp,
602 l->src.b_other,
603 l->src.p_all,
604 l->src.p_tcp,
605 l->src.p_udp,
606 l->src.p_icmp,
607 l->src.p_other,
608 l->dst.b_all,
609 l->dst.b_tcp,
610 l->dst.b_udp,
611 l->dst.b_icmp,
612 l->dst.b_other,
613 l->dst.p_all,
614 l->dst.p_tcp,
615 l->dst.p_udp,
616 l->dst.p_icmp,
617 l->dst.p_other,
618 now.tv_sec - l->time.tv_sec
620 } else {
621 struct t_ipt_account_stats_short *s = &table->stats.s[*i];
622 seq_printf(sf,
623 "ip = %u.%u.%u.%u bytes_src = %Lu packets_src = %Lu bytes_dst = %Lu packets_dst = %Lu time = %lu\n",
624 HIPQUAD(address),
625 s->src.b_all,
626 s->src.p_all,
627 s->dst.b_all,
628 s->dst.p_all,
629 now.tv_sec - s->time.tv_sec
633 return 0;
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)
645 char buffer[1024];
646 struct proc_dir_entry *pde = PDE(file->f_dentry->d_inode);
647 struct t_ipt_account_table *table = pde->data;
649 u_int32_t o[4], ip;
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);
655 #endif
656 if (copy_from_user(buffer, input, 1024))
657 return -EFAULT;
658 buffer[1023] = '\0';
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);
668 else
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)) {
674 table->timesrc = 1;
675 table->timedst = 0;
676 } else if (!strncmp(buffer, "time=dst\n", 9)) {
677 table->timesrc = 0;
678 table->timedst = 1;
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],
703 &s.src.b_all,
704 &s.src.p_all,
705 &s.dst.b_all,
706 &s.dst.p_all,
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);
719 } else {
721 * We don't understand what user have just wrote.
723 return -EIO;
726 return size;
729 static int ipt_account_proc_open(struct inode *inode, struct file *file)
731 int ret = seq_open(file, &ipt_account_seq_ops);
732 if (!ret) {
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;
737 sf->private = pde;
739 ipt_account_table_get(table);
741 return ret;
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;
748 int ret;
750 ret = seq_release(inode, file);
752 if (!ret)
753 ipt_account_table_put(table);
755 return ret;
758 static struct file_operations ipt_account_proc_fops = {
759 .owner = THIS_MODULE,
760 .open = ipt_account_proc_open,
761 .read = seq_read,
762 .write = ipt_account_proc_write,
763 .llseek = seq_lseek,
764 .release = ipt_account_proc_release
768 * Module init function.
770 static int __init init(void)
772 int ret = 0;
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);
779 ret = -EINVAL;
780 goto cleanup_none;
783 /* Register match. */
784 if (ipt_register_match(&account_match)) {
785 ret = -EINVAL;
786 goto cleanup_none;
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");
793 ret = -ENOMEM;
794 goto cleanup_match;
797 return ret;
799 /* If something goes wrong we end here. */
800 cleanup_match:
801 ipt_unregister_match(&account_match);
802 cleanup_none:
803 return ret;
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);
816 module_init(init);
817 module_exit(fini);