All of lore.kernel.org
 help / color / mirror / Atom feed
From: "Piotr Gasidło" <quaker@pandora.barbara.ds.polsl.gliwice.pl>
To: netfilter-devel@lists.netfilter.org
Subject: [PATCH] account match seq_file update [RESEND of RESEND]
Date: Sun, 26 Sep 2004 12:02:02 +0200	[thread overview]
Message-ID: <20040926100202.GA8843@barbara.eu.org> (raw)


[-- Attachment #1.1: Type: text/plain, Size: 486 bytes --]

Hello,

This is fourth try to send this patch. Last three mails were not
noticed on group :/

Changes (0.1.16 to 0.1.17):
- use of seq_file API in /proc/net/ipt_account/*
- code cleanup

Patch includes updates for both 2.4 and 2.6.

Please apply.

-- 
Piotr 'QuakeR' Gasidło, BOFH @ pandora.barbara.eu.org
############## sending lusers to /dev/null since 1998
##### Waiting for tomorrow, for a little ray of light
### Waiting for tomorrow just to see your smile again

[-- Attachment #1.2: ipt_account-0.1.17.diff --]
[-- Type: text/plain, Size: 63990 bytes --]

diff -uNr patch-o-matic-ng.orig/account/linux/Documentation/Configure.help.ladd patch-o-matic-ng/account/linux/Documentation/Configure.help.ladd
--- patch-o-matic-ng.orig/account/linux/Documentation/Configure.help.ladd	1970-01-01 01:00:00.000000000 +0100
+++ patch-o-matic-ng/account/linux/Documentation/Configure.help.ladd	2004-08-27 16:59:25.000000000 +0200
@@ -0,0 +1,44 @@
+CONFIG_IP_NF_MATCH_TOS
+account match support
+CONFIG_IP_NF_MATCH_ACCOUNT
+  This match is used for accounting traffic for all hosts in
+  defined network/netmask. 
+  
+  Features:
+  - long (one counter per protocol TCP/UDP/IMCP/Other) and short statistics
+  - one iptables rule for all hosts in network/netmask
+  - loading/saving counters (by reading/writting to procfs entries)
+  
+  Example usage:
+  
+  account traffic for/to 192.168.0.0/24 network into table mynetwork:
+  
+  # iptables -A FORWARD -m account --aname mynetwork --aaddr 192.168.0.0/24
+  
+  account traffic for/to WWW serwer for 192.168.0.0/24 network into table 
+  mywwwserver:
+  
+  # iptables -A INPUT -p tcp --dport 80 
+    -m account --aname mywwwserver --aaddr 192.168.0.0/24 --ashort
+  # iptables -A OUTPUT -p tcp --sport 80
+    -m account --aname mywwwserver --aaddr 192.168.0.0/24 --ashort    
+  
+  read counters:
+  
+  # cat /proc/net/ipt_account/mynetwork
+  # cat /proc/net/ipt_account/mywwwserver
+  
+  set counters:
+  
+  # echo "ip = 192.168.0.1 packets_src = 0" > /proc/net/ipt_account/mywwserver
+  
+  Webpage: 
+    http://www.barbara.eu.org/~quaker/ipt_account/    
+ 
+  If you want to compile it as a module, say M here and read
+  Documentation/modules.txt.  If unsure, say `N'.
+
+account debugging output
+CONFIG_IP_NF_MATCH_ACCOUNT_DEBUG
+  Say Y to get lots of debugging output.
+
diff -uNr patch-o-matic-ng.orig/account/linux/include/linux/netfilter_ipv4/ipt_account.h patch-o-matic-ng/account/linux/include/linux/netfilter_ipv4/ipt_account.h
--- patch-o-matic-ng.orig/account/linux/include/linux/netfilter_ipv4/ipt_account.h	2004-09-15 14:01:27.000000000 +0200
+++ patch-o-matic-ng/account/linux/include/linux/netfilter_ipv4/ipt_account.h	2004-09-07 12:12:08.000000000 +0200
@@ -2,7 +2,7 @@
  * accounting match (ipt_account.c)
  * (C) 2003,2004 by Piotr Gasidlo (quaker@barbara.eu.org)
  *
- * Version: 0.1.6
+ * Version: 0.1.7
  *
  * This software is distributed under the terms of GNU GPL
  */
@@ -13,7 +13,7 @@
 #define IPT_ACCOUNT_NAME_LEN 64
 
 #define IPT_ACCOUNT_NAME "ipt_account"
-#define IPT_ACCOUNT_VERSION  "0.1.6"
+#define IPT_ACCOUNT_VERSION  "0.1.7"
 
 struct t_ipt_account_info {
 	char name[IPT_ACCOUNT_NAME_LEN];
diff -uNr patch-o-matic-ng.orig/account/linux/net/ipv4/netfilter/ipt_account.c patch-o-matic-ng/account/linux/net/ipv4/netfilter/ipt_account.c
--- patch-o-matic-ng.orig/account/linux/net/ipv4/netfilter/ipt_account.c	2004-09-15 14:01:27.000000000 +0200
+++ patch-o-matic-ng/account/linux/net/ipv4/netfilter/ipt_account.c	2004-09-07 12:11:48.000000000 +0200
@@ -2,7 +2,7 @@
  * accounting match (ipt_account.c)
  * (C) 2003,2004 by Piotr Gasidlo (quaker@barbara.eu.org)
  *
- * Version: 0.1.6
+ * Version: 0.1.7
  *
  * This software is distributed under the terms of GNU GPL
  */
@@ -15,6 +15,8 @@
 #include <linux/interrupt.h>
 #include <linux/ctype.h>
 
+#include <linux/seq_file.h>
+
 #include <asm/uaccess.h>
 
 #include <linux/ip.h>
@@ -161,124 +163,53 @@
 	return (bufferptr - buffer);
 }
 
-static int account_proc_read(char *buffer, char **start, off_t offset,
-		int length, int *eof, void *data) {
-	
-	int len = 0, last_len = 0;
-	off_t pos = 0, begin = 0;
-	u_int32_t address, index;	
-	struct timespec last;
-	unsigned long now = jiffies;
+static void *account_seq_start(struct seq_file *s, loff_t *pos)
+{
+	struct proc_dir_entry *pde = s->private;
+	struct t_ipt_account_table *table = pde->data;
 
-	struct t_ipt_account_table *table = (struct t_ipt_account_table*)data;
+	unsigned int *bucket;
 	
-	dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_proc_read() entered.\n");
-
 	spin_lock_bh(&table->ip_list_lock);
-	for (address = table->network, index = 0; index < table->count; address++, index++) {
-		last_len = len;		
-		jiffies_to_timespec(now - table->ip_list.l[index].time, &last);
-		len += sprintf(buffer + len,
-				"ip = %u.%u.%u.%u bytes_src = %llu %llu %llu %llu %llu packets_src = %llu %llu %llu %llu %llu bytes_dest = %llu %llu %llu %llu %llu packets_dest = %llu %llu %llu %llu %llu time = %lu\n",
-				HIPQUAD(address),
-				table->ip_list.l[index].src.b_all,
-				table->ip_list.l[index].src.b_tcp,
-				table->ip_list.l[index].src.b_udp,
-				table->ip_list.l[index].src.b_icmp,
-				table->ip_list.l[index].src.b_other,
-				
-				table->ip_list.l[index].src.p_all,
-				table->ip_list.l[index].src.p_tcp,
-				table->ip_list.l[index].src.p_udp,
-				table->ip_list.l[index].src.p_icmp,
-				table->ip_list.l[index].src.p_other,
-				
-				table->ip_list.l[index].dest.b_all,
-				table->ip_list.l[index].dest.b_tcp,
-				table->ip_list.l[index].dest.b_udp,
-				table->ip_list.l[index].dest.b_icmp,
-				table->ip_list.l[index].dest.b_other,				
-				
-				table->ip_list.l[index].dest.p_all,
-				table->ip_list.l[index].dest.p_tcp,
-				table->ip_list.l[index].dest.p_udp,
-				table->ip_list.l[index].dest.p_icmp,
-				table->ip_list.l[index].dest.p_other,
-
-				last.tv_sec
-				);
-		pos = begin + len;
-		if (pos < offset) {
-			len = 0;
-			begin = pos;
-		}
-		if (pos > offset + length) {
-			len = last_len;
-			break;
-		}
-	}
-	spin_unlock_bh(&table->ip_list_lock);
-	*start = buffer + (offset - begin);
-	len -= (offset - begin);
-	if (len > length)
-		len = length;
+	if (*pos >= table->count)
+		return NULL;
 
-	dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_proc_read() left.\n");
-	
-	return len;
+	bucket = kmalloc(sizeof(unsigned int), GFP_KERNEL);
+	if (!bucket)
+		return ERR_PTR(-ENOMEM);
+	*bucket = *pos;
+	return bucket;
 }
 
-static int account_proc_read_short(char *buffer, char **start, off_t offset,
-		int length, int *eof, void *data) {
+static void *account_seq_next(struct seq_file *s, void *v, loff_t *pos)
+{
+	struct proc_dir_entry *pde = s->private;
+	struct t_ipt_account_table *table = pde->data;
 	
-	int len = 0, last_len = 0;
-	off_t pos = 0, begin = 0;
-	u_int32_t address, index;	
-	struct timespec last;
-	unsigned long now = jiffies;
-
-	struct t_ipt_account_table *table = (struct t_ipt_account_table*)data;
+	unsigned int *bucket = (unsigned int *)v;
 	
-	dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_proc_read_short() entered.\n");
-
-	spin_lock_bh(&table->ip_list_lock);
-	for (address = table->network, index = 0; index < table->count; address++, index++) {
-		last_len = len;		
-		jiffies_to_timespec(now - table->ip_list.s[index].time, &last);
-		len += sprintf(buffer + len,
-				"ip = %u.%u.%u.%u bytes_src = %llu packets_src = %llu bytes_dest = %llu packets_dest = %llu time = %lu\n",
-				HIPQUAD(address),
-				table->ip_list.s[index].src.b_all,
-				table->ip_list.s[index].src.p_all,
-				table->ip_list.s[index].dest.b_all,
-				table->ip_list.s[index].dest.p_all,
-				last.tv_sec
-				);
-		pos = begin + len;
-		if (pos < offset) {
-			len = 0;
-			begin = pos;
-		}
-		if (pos > offset + length) {
-			len = last_len;
-			break;
-		}
+	*pos = ++(*bucket);
+	if (*pos >= table->count) {
+		kfree(v);
+		return NULL;
 	}
-	spin_unlock_bh(&table->ip_list_lock);
-	*start = buffer + (offset - begin);
-	len -= (offset - begin);
-	if (len > length)
-		len = length;
-
-	dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_proc_read_short() left.\n");
-	
-	return len;
+	return bucket;
 }
 
-static int account_proc_write(struct file *file, const char *ubuffer, 
-		unsigned long ulength, void *data) {
+static void account_seq_stop(struct seq_file *s, void *v)
+{
+	struct proc_dir_entry *pde = s->private;
+	struct t_ipt_account_table *table = pde->data;
+	unsigned int *bucket = (unsigned int *)v;
+	kfree(bucket);
+	spin_unlock_bh(&table->ip_list_lock);
+}
 
-	struct t_ipt_account_table *table = (struct t_ipt_account_table*)data;
+static int account_seq_write(struct file *file, const char *ubuffer, 
+		size_t ulength, loff_t *pos)
+{
+	struct proc_dir_entry *pde = ((struct seq_file *)file->private_data)->private;
+	struct t_ipt_account_table *table = pde->data;
 	char buffer[1024], *bufferptr;
 	int length;
 
@@ -289,8 +220,8 @@
 	u_int64_t *p, dummy;
 	
 	
-	dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_proc_write() entered.\n");
-	dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_proc_write() ulength = %li.\n", ulength);
+	dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() entered.\n");
+	dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() ulength = %i.\n", ulength);
 	
 	length = ulength;
 	if (ulength > 1024)
@@ -300,11 +231,11 @@
 	buffer[length - 1] = 0;
 	bufferptr = buffer;
 
-	dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_proc_write() buffer = \'%s\' length = %li.\n", buffer, length);
+	dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() buffer = \'%s\' length = %i.\n", buffer, length);
 	
 	/* reset table counters */
 	if (!memcmp(buffer, "reset", 5)) {
-		dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_proc_write() got \"reset\".\n");
+		dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() got \"reset\".\n");
 		if (!table->shortlisting) {
 			spin_lock_bh(&table->ip_list_lock);
 			memset(table->ip_list.l, 0, sizeof(struct t_ipt_account_ip_list) * table->count);
@@ -318,110 +249,110 @@
 	}
 
 	if (!memcmp(buffer, "ip", 2)) {
-		dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_proc_write() got \"ip\".\n");
+		dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() got \"ip\".\n");
 		bufferptr += 2;
 		if (!isspace(*bufferptr)) {
-			dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_proc_write() expected space (%i).\n", bufferptr - buffer);
+			dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() expected space (%i).\n", bufferptr - buffer);
 			return length; /* expected space */
 		}
 		bufferptr += 1;
 		if (*bufferptr != '=') {
-			dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_proc_write() expected equal (%i).\n", bufferptr - buffer);
+			dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() expected equal (%i).\n", bufferptr - buffer);
 			return length; /* expected equal */
 		}
 		bufferptr += 1;
 		if (!isspace(*bufferptr)) {
-			dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_proc_write() expected space (%i).\n", bufferptr - buffer);
+			dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() expected space (%i).\n", bufferptr - buffer);
 			return length; /* expected space */
 		}
 		bufferptr += 1;
 		if (!(len = atoip(bufferptr, &ip))) {
-			dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_proc_write() expected ip (%i).\n", bufferptr - buffer);
+			dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() expected ip (%i).\n", bufferptr - buffer);
 			return length; /* expected ip */
 		}
 		bufferptr += len;
 		if ((ip & table->netmask) != table->network) {
-			dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_proc_write() expected ip [%u.%u.%u.%u] from table's network/netmask [%u.%u.%u.%u/%u.%u.%u.%u].\n", HIPQUAD(ip), HIPQUAD(table->network), HIPQUAD(table->netmask));
+			dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() expected ip [%u.%u.%u.%u] from table's network/netmask [%u.%u.%u.%u/%u.%u.%u.%u].\n", HIPQUAD(ip), HIPQUAD(table->network), HIPQUAD(table->netmask));
 			return length; /* expected ip from table's network/netmask */
 		}
 		if (!table->shortlisting) {
 			memset(&l, 0, sizeof(struct t_ipt_account_ip_list));
 			while(*bufferptr) {
 				if (!isspace(*bufferptr)) {
-					dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_proc_write() expected space (%i).\n", bufferptr - buffer);
+					dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() expected space (%i).\n", bufferptr - buffer);
 					return length; /* expected space */
 				}
 				bufferptr += 1;
 				if (!memcmp(bufferptr, "bytes_src", 9)) {
-					dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_proc_write() got bytes_src (%i).\n", bufferptr - buffer);
+					dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() got bytes_src (%i).\n", bufferptr - buffer);
 					p = &l.src.b_all;
 					bufferptr += 9;
 				} else if (!memcmp(bufferptr, "bytes_dest", 10)) {					
-					dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_proc_write() got bytes_dest (%i).\n", bufferptr - buffer);
+					dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() got bytes_dest (%i).\n", bufferptr - buffer);
 					p = &l.dest.b_all;
 					bufferptr += 10;
 				} else if (!memcmp(bufferptr, "packets_src", 11)) {
-					dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_proc_write() got packets_src (%i).\n", bufferptr - buffer);
+					dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() got packets_src (%i).\n", bufferptr - buffer);
 					p = &l.src.p_all;
 					bufferptr += 11;
 				} else if (!memcmp(bufferptr, "packets_dest", 12)) {
-					dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_proc_write() got packets_dest (%i).\n", bufferptr - buffer);
+					dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() got packets_dest (%i).\n", bufferptr - buffer);
 					p = &l.dest.p_all;
 					bufferptr += 12;
 				} else if (!memcmp(bufferptr, "time", 4)) {
 					/* time hack, ignore time tokens */
-					dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_proc_write() got time (%i).\n", bufferptr - buffer);
+					dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() got time (%i).\n", bufferptr - buffer);
 					bufferptr += 4;
 					if (!isspace(*bufferptr)) {
-						dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_proc_write() expected space (%i).\n", bufferptr - buffer);
+						dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() expected space (%i).\n", bufferptr - buffer);
 						return length; /* expected space */
 					}
 					bufferptr += 1;
 					if (*bufferptr != '=') {
-						dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_proc_write() expected equal (%i).\n", bufferptr - buffer);
+						dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() expected equal (%i).\n", bufferptr - buffer);
 						return length; /* expected equal */
 					}
 					bufferptr += 1;
 					if (!isspace(*bufferptr)) {
-						dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_proc_write() expected space (%i).\n", bufferptr - buffer);
+						dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() expected space (%i).\n", bufferptr - buffer);
 						return length; /* expected space */
 					}
 					bufferptr += 1;
 					if (!(len = atoi64(bufferptr, &dummy))) {
-						dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_proc_write() expected int64 (%i).\n", bufferptr - buffer);
+						dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() expected int64 (%i).\n", bufferptr - buffer);
 						return length; /* expected int64 */
 					}
-					dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_proc_write() got %llu (%i).\n", dummy, bufferptr - buffer);
+					dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() got %llu (%i).\n", dummy, bufferptr - buffer);
 					bufferptr += len;
 					continue; /* skip time token */
 				} else
 					return length;	/* expected token */
 				if (!isspace(*bufferptr)) {
-					dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_proc_write() expected space (%i).\n", bufferptr - buffer);
+					dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() expected space (%i).\n", bufferptr - buffer);
 					return length; /* expected space */
 				}
 				bufferptr += 1;
 				if (*bufferptr != '=') {
-					dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_proc_write() expected equal (%i).\n", bufferptr - buffer);
+					dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() expected equal (%i).\n", bufferptr - buffer);
 					return length; /* expected equal */
 				}
 				bufferptr += 1;
 				for (i = 0; i < 5; i++) {
 					if (!isspace(*bufferptr)) {
-						dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_proc_write() expected space (%i).\n", bufferptr - buffer);
+						dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() expected space (%i).\n", bufferptr - buffer);
 						return length; /* expected space */
 					}
 					bufferptr += 1;
 					if (!(len = atoi64(bufferptr, p))) {
-						dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_proc_write() expected int64 (%i).\n", bufferptr - buffer);
+						dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() expected int64 (%i).\n", bufferptr - buffer);
 						return length; /* expected int64 */
 					}
-					dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_proc_write() got %llu (%i).\n", *p, bufferptr - buffer);
+					dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() got %llu (%i).\n", *p, bufferptr - buffer);
 					bufferptr += len;
 					p++;
 				}
 			}
-			dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_proc_write() updating row.\n");
+			dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() updating row.\n");
 			spin_lock_bh(&table->ip_list_lock);
 			/* update counters, do not overwrite time field */
 			memcpy(&table->ip_list.l[ip - table->network], &l, sizeof(struct t_ipt_account_ip_list) - sizeof(unsigned long));
@@ -430,79 +361,79 @@
 			memset(&s, 0, sizeof(struct t_ipt_account_ip_list_short));
 			while(*bufferptr) {
 				if (!isspace(*bufferptr)) {
-					dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_proc_write() expected space (%i).\n", bufferptr - buffer);
+					dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() expected space (%i).\n", bufferptr - buffer);
 					return length; /* expected space */
 				}
 				bufferptr += 1;
 				if (!memcmp(bufferptr, "bytes_src", 9)) {
-					dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_proc_write() got bytes_src (%i).\n", bufferptr - buffer);
+					dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() got bytes_src (%i).\n", bufferptr - buffer);
 					p = &s.src.b_all;
 					bufferptr += 9;
 				} else if (!memcmp(bufferptr, "bytes_dest", 10)) {					
-					dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_proc_write() got bytes_dest (%i).\n", bufferptr - buffer);
+					dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() got bytes_dest (%i).\n", bufferptr - buffer);
 					p = &s.dest.b_all;
 					bufferptr += 10;
 				} else if (!memcmp(bufferptr, "packets_src", 11)) {
-					dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_proc_write() got packets_src (%i).\n", bufferptr - buffer);
+					dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() got packets_src (%i).\n", bufferptr - buffer);
 					p = &s.src.p_all;
 					bufferptr += 11;
 				} else if (!memcmp(bufferptr, "packets_dest", 12)) {
-					dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_proc_write() got packets_dest (%i).\n", bufferptr - buffer);
+					dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() got packets_dest (%i).\n", bufferptr - buffer);
 					p = &s.dest.p_all;
 					bufferptr += 12;
 				} else if (!memcmp(bufferptr, "time", 4)) {
 					/* time hack, ignore time tokens */
-					dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_proc_write() got time (%i).\n", bufferptr - buffer);
+					dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() got time (%i).\n", bufferptr - buffer);
 					bufferptr += 4;
 					if (!isspace(*bufferptr)) {
-						dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_proc_write() expected space (%i).\n", bufferptr - buffer);
+						dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() expected space (%i).\n", bufferptr - buffer);
 						return length; /* expected space */
 					}
 					bufferptr += 1;
 					if (*bufferptr != '=') {
-						dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_proc_write() expected equal (%i).\n", bufferptr - buffer);
+						dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() expected equal (%i).\n", bufferptr - buffer);
 						return length; /* expected equal */
 					}
 					bufferptr += 1;
 					if (!isspace(*bufferptr)) {
-						dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_proc_write() expected space (%i).\n", bufferptr - buffer);
+						dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() expected space (%i).\n", bufferptr - buffer);
 						return length; /* expected space */
 					}
 					bufferptr += 1;
 					if (!(len = atoi64(bufferptr, &dummy))) {
-						dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_proc_write() expected int64 (%i).\n", bufferptr - buffer);
+						dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() expected int64 (%i).\n", bufferptr - buffer);
 						return length; /* expected int64 */
 					}
-					dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_proc_write() got %llu (%i).\n", dummy, bufferptr - buffer);
+					dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() got %llu (%i).\n", dummy, bufferptr - buffer);
 					bufferptr += len;
 					continue; /* skip time token */
 				} else {
-					dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_proc_write() expected token (%i).\n", bufferptr - buffer);
+					dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() expected token (%i).\n", bufferptr - buffer);
 					return length;	/* expected token */
 				}
 				if (!isspace(*bufferptr)) {
-					dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_proc_write() expected space (%i).\n", bufferptr - buffer);
+					dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() expected space (%i).\n", bufferptr - buffer);
 					return length; /* expected space */
 				}
 				bufferptr += 1;
 				if (*bufferptr != '=') {
-					dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_proc_write() expected equal (%i).\n", bufferptr - buffer);
+					dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() expected equal (%i).\n", bufferptr - buffer);
 					return length; /* expected equal */
 				}
 				bufferptr += 1;
 				if (!isspace(*bufferptr)) {
-					dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_proc_write() expected space (%i).\n", bufferptr - buffer);
+					dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() expected space (%i).\n", bufferptr - buffer);
 					return length; /* expected space */
 				}
 				bufferptr += 1;
 				if (!(len = atoi64(bufferptr, p))) {
-					dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_proc_write() expected int64 (%i).\n", bufferptr - buffer);
+					dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() expected int64 (%i).\n", bufferptr - buffer);
 					return length; /* expected int64 */
 				}
-				dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_proc_write() got %llu (%i).\n", *p, bufferptr - buffer);
+				dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() got %llu (%i).\n", *p, bufferptr - buffer);
 				bufferptr += len;
 			}
-			dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_proc_write() updating row.\n");
+			dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() updating row.\n");
 			spin_lock_bh(&table->ip_list_lock);
 			/* update counters, do not overwrite time field */
 			memcpy(&table->ip_list.s[ip - table->network], &s, sizeof(struct t_ipt_account_ip_list_short) - sizeof(unsigned long));
@@ -510,10 +441,84 @@
 		}
 	}
 	
-	dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_proc_write() left.\n");
+	dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() left.\n");
 	return length;
 }
 
+
+static int account_seq_show(struct seq_file *s, void *v)
+{
+	struct proc_dir_entry *pde = s->private;
+	struct t_ipt_account_table *table = pde->data;
+	unsigned int *bucket = (unsigned int *)v;
+
+	u_int32_t address = table->network + *bucket;
+
+	if (!table->shortlisting) {
+		seq_printf(s,
+				"ip = %u.%u.%u.%u bytes_src = %llu %llu %llu %llu %llu packets_src = %llu %llu %llu %llu %llu bytes_dest = %llu %llu %llu %llu %llu packets_dest = %llu %llu %llu %llu %llu\n",
+				HIPQUAD(address),
+				table->ip_list.l[*bucket].src.b_all,
+				table->ip_list.l[*bucket].src.b_tcp,
+				table->ip_list.l[*bucket].src.b_udp,
+				table->ip_list.l[*bucket].src.b_icmp,
+				table->ip_list.l[*bucket].src.b_other,
+				table->ip_list.l[*bucket].src.p_all,
+				table->ip_list.l[*bucket].src.p_tcp,
+				table->ip_list.l[*bucket].src.p_udp,
+				table->ip_list.l[*bucket].src.p_icmp,
+				table->ip_list.l[*bucket].src.p_other,
+				table->ip_list.l[*bucket].dest.b_all,
+				table->ip_list.l[*bucket].dest.b_tcp,
+				table->ip_list.l[*bucket].dest.b_udp,
+				table->ip_list.l[*bucket].dest.b_icmp,
+				table->ip_list.l[*bucket].dest.b_other,				
+				table->ip_list.l[*bucket].dest.p_all,
+				table->ip_list.l[*bucket].dest.p_tcp,
+				table->ip_list.l[*bucket].dest.p_udp,
+				table->ip_list.l[*bucket].dest.p_icmp,
+				table->ip_list.l[*bucket].dest.p_other
+			);
+	} else {
+		seq_printf(s,
+				"ip = %u.%u.%u.%u bytes_src = %llu packets_src = %llu bytes_dest = %llu packets_dest = %llu\n",
+				HIPQUAD(address),
+				table->ip_list.s[*bucket].src.b_all,
+				table->ip_list.s[*bucket].src.p_all,
+				table->ip_list.s[*bucket].dest.b_all,
+				table->ip_list.s[*bucket].dest.p_all
+			  );
+	}
+	return 0;
+}
+
+static struct seq_operations account_seq_ops = {
+	.start = account_seq_start,
+	.next  = account_seq_next,
+	.stop  = account_seq_stop,
+	.show  = account_seq_show
+};
+
+static int account_seq_open(struct inode *inode, struct file *file)
+{
+	int ret = seq_open(file, &account_seq_ops);
+	
+	if (!ret) {
+		struct seq_file *sf = file->private_data;
+		sf->private = PDE(inode);
+	}
+	return ret;
+}
+
+static struct file_operations account_file_ops = {
+	.owner = THIS_MODULE,
+	.open = account_seq_open,
+	.read = seq_read,
+	.write = account_seq_write,
+	.llseek = seq_lseek,
+	.release = seq_release
+};
+
 /* do raw accounting */
 static inline void do_account(struct t_ipt_account_stat *stat, const struct sk_buff *skb) {
 	
@@ -764,13 +769,12 @@
 		goto failure_unlink;
 	}
 	table->status_file->owner = THIS_MODULE;
-	table->status_file->data = table;
+	table->status_file->data = table;	
 	wmb();
-	if (!table->shortlisting)
-		table->status_file->read_proc = account_proc_read;
-	else
-		table->status_file->read_proc = account_proc_read_short;
-	table->status_file->write_proc = account_proc_write;
+//	if (!table->shortlisting)
+		table->status_file->proc_fops = &account_file_ops;
+//	else
+//		table->status_file->proc_fops = &account_file_ops_short;
 
 	dprintk(KERN_INFO IPT_ACCOUNT_NAME ": checkentry() left.\n");	
 	/* everything went just okey */
diff -uNr patch-o-matic-ng.orig/account/linux-2.6/include/linux/netfilter_ipv4/ipt_account.h patch-o-matic-ng/account/linux-2.6/include/linux/netfilter_ipv4/ipt_account.h
--- patch-o-matic-ng.orig/account/linux-2.6/include/linux/netfilter_ipv4/ipt_account.h	1970-01-01 01:00:00.000000000 +0100
+++ patch-o-matic-ng/account/linux-2.6/include/linux/netfilter_ipv4/ipt_account.h	2004-09-07 12:12:08.000000000 +0200
@@ -0,0 +1,26 @@
+/* 
+ * accounting match (ipt_account.c)
+ * (C) 2003,2004 by Piotr Gasidlo (quaker@barbara.eu.org)
+ *
+ * Version: 0.1.7
+ *
+ * This software is distributed under the terms of GNU GPL
+ */
+
+#ifndef _IPT_ACCOUNT_H_
+#define _IPT_ACCOUNT_H_
+
+#define IPT_ACCOUNT_NAME_LEN 64
+
+#define IPT_ACCOUNT_NAME "ipt_account"
+#define IPT_ACCOUNT_VERSION  "0.1.7"
+
+struct t_ipt_account_info {
+	char name[IPT_ACCOUNT_NAME_LEN];
+	u_int32_t network;
+	u_int32_t netmask;
+	int shortlisting:1;
+};
+
+#endif
+
diff -uNr patch-o-matic-ng.orig/account/linux-2.6/net/ipv4/netfilter/Kconfig.ladd patch-o-matic-ng/account/linux-2.6/net/ipv4/netfilter/Kconfig.ladd
--- patch-o-matic-ng.orig/account/linux-2.6/net/ipv4/netfilter/Kconfig.ladd	1970-01-01 01:00:00.000000000 +0100
+++ patch-o-matic-ng/account/linux-2.6/net/ipv4/netfilter/Kconfig.ladd	2004-08-27 16:40:42.000000000 +0200
@@ -0,0 +1,45 @@
+config IP_NF_MATCH_ACCOUNT
+	tristate "account match support"
+	depends on IP_NF_IPTABLES && PROC_FS
+	help
+	  This match is used for accounting traffic for all hosts in
+	  defined network/netmask. 
+	  
+	  Features:
+	  - long (one counter per protocol TCP/UDP/IMCP/Other) and short statistics
+	  - one iptables rule for all hosts in network/netmask
+	  - loading/saving counters (by reading/writting to procfs entries)
+	  
+	  Example usage:
+	  
+	  account traffic for/to 192.168.0.0/24 network into table mynetwork:
+	  
+	  # iptables -A FORWARD -m account --aname mynetwork --aaddr 192.168.0.0/24
+	  
+	  account traffic for/to WWW serwer for 192.168.0.0/24 network into table 
+	  mywwwserver:
+	  
+	  # iptables -A INPUT -p tcp --dport 80 
+	    -m account --aname mywwwserver --aaddr 192.168.0.0/24 --ashort
+	  # iptables -A OUTPUT -p tcp --sport 80
+	    -m account --aname mywwwserver --aaddr 192.168.0.0/24 --ashort    
+	  
+	  read counters:
+	  
+	  # cat /proc/net/ipt_account/mynetwork
+	  # cat /proc/net/ipt_account/mywwwserver
+	  
+	  set counters:
+	  
+	  # echo "ip = 192.168.0.1 packets_src = 0" > /proc/net/ipt_account/mywwserver
+	  
+	  Webpage: 
+	    http://www.barbara.eu.org/~quaker/ipt_account/
+
+config IP_NF_MATCH_ACCOUNT_DEBUG
+	bool "account debugging output"
+	depends on IP_NF_MATCH_ACCOUNT
+	help
+	  Say Y to get lots of debugging output.
+	  
+
diff -uNr patch-o-matic-ng.orig/account/linux-2.6/net/ipv4/netfilter/Makefile.ladd patch-o-matic-ng/account/linux-2.6/net/ipv4/netfilter/Makefile.ladd
--- patch-o-matic-ng.orig/account/linux-2.6/net/ipv4/netfilter/Makefile.ladd	1970-01-01 01:00:00.000000000 +0100
+++ patch-o-matic-ng/account/linux-2.6/net/ipv4/netfilter/Makefile.ladd	2004-03-17 15:50:12.000000000 +0100
@@ -0,0 +1,2 @@
+obj-$(CONFIG_IP_NF_MATCH_TOS) += ipt_tos.o
+obj-$(CONFIG_IP_NF_MATCH_ACCOUNT) += ipt_account.o
diff -uNr patch-o-matic-ng.orig/account/linux-2.6/net/ipv4/netfilter/ipt_account.c patch-o-matic-ng/account/linux-2.6/net/ipv4/netfilter/ipt_account.c
--- patch-o-matic-ng.orig/account/linux-2.6/net/ipv4/netfilter/ipt_account.c	1970-01-01 01:00:00.000000000 +0100
+++ patch-o-matic-ng/account/linux-2.6/net/ipv4/netfilter/ipt_account.c	2004-09-15 14:10:40.000000000 +0200
@@ -0,0 +1,923 @@
+/* 
+ * accounting match (ipt_account.c)
+ * (C) 2003,2004 by Piotr Gasidlo (quaker@barbara.eu.org)
+ *
+ * Version: 0.1.7
+ *
+ * This software is distributed under the terms of GNU GPL
+ */
+
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/proc_fs.h>
+#include <linux/spinlock.h>
+#include <linux/vmalloc.h>
+#include <linux/interrupt.h>
+#include <linux/ctype.h>
+
+#include <linux/seq_file.h>
+
+#include <asm/uaccess.h>
+
+#include <linux/ip.h>
+#include <linux/tcp.h>
+#include <linux/udp.h>
+
+#include <linux/netfilter_ipv4/ip_tables.h>
+#include <linux/netfilter_ipv4/ipt_account.h>
+
+#if defined(CONFIG_IP_NF_MATCH_ACCOUNT_DEBUG)
+	#define dprintk(format,args...) printk(format,##args)
+#else
+        #define dprintk(format,args...)
+#endif
+
+static char version[] =
+KERN_INFO IPT_ACCOUNT_NAME " " IPT_ACCOUNT_VERSION " : Piotr Gasidło <quaker@barbara.eu.org>, http://www.barbara.eu.org/~quaker/ipt_account/\n";
+
+/* rights for files created in /proc/net/ipt_account/ */
+static int permissions = 0644;
+/* maximal netmask for single table */
+static int netmask = 16;
+
+/* module information */
+MODULE_AUTHOR("Piotr Gasidlo <quaker@barbara.eu.org>");
+MODULE_DESCRIPTION("Traffic accounting modules");
+MODULE_LICENSE("GPL");
+MODULE_PARM(permissions,"i");
+MODULE_PARM_DESC(permissions,"permissions on /proc/net/ipt_account/* files");
+MODULE_PARM(netmask, "i");
+MODULE_PARM_DESC(netmask, "maximum *save* size of one list (netmask)");
+
+/* structure with statistics counters */
+struct t_ipt_account_stat {
+	u_int64_t b_all, b_tcp, b_udp, b_icmp, b_other;		/* byte counters for all/tcp/udp/icmp/other traffic  */
+	u_int64_t p_all, p_tcp, p_udp, p_icmp, p_other;		/* packet counters for all/tcp/udp/icmp/other traffic */
+};
+
+/* stucture with statistics counters, used when table is created with --ashort switch */
+struct t_ipt_account_stat_short {
+	u_int64_t b_all;					/* byte counters for all traffic */
+	u_int64_t p_all;					/* packet counters for all traffic */
+};
+ 
+/* structure holding to/from statistics for single ip */
+struct t_ipt_account_ip_list {
+	struct t_ipt_account_stat src;
+	struct t_ipt_account_stat dest;
+	unsigned long time;					/* time when this record was last updated */	
+	
+};
+
+/* same as above, for tables with --ashort switch */
+struct t_ipt_account_ip_list_short {
+	struct t_ipt_account_stat_short src;
+	struct t_ipt_account_stat_short dest;
+	unsigned long time;
+};
+
+/* structure describing single table */
+struct t_ipt_account_table {
+	char name[IPT_ACCOUNT_NAME_LEN];	/* table name ( = filename in /proc/net/ipt_account/) */
+	union {					/* table with statistics for each ip in network/netmask */
+		struct t_ipt_account_ip_list *l;
+		struct t_ipt_account_ip_list_short *s;
+	} ip_list;
+	u_int32_t network;			/* network/netmask covered by table*/
+	u_int32_t netmask;					
+	u_int32_t count;
+	int shortlisting:1;			/* show only total columns of counters */	
+	int use_count;				/* rules counter - counting number of rules using this table */
+	struct t_ipt_account_table *next;
+	spinlock_t ip_list_lock;
+	struct proc_dir_entry *status_file;
+};
+
+/* we must use spinlocks to avoid parallel modifications of table list */
+static spinlock_t account_lock = SPIN_LOCK_UNLOCKED;
+
+static struct proc_dir_entry *proc_net_ipt_account = NULL;
+
+/* root pointer holding list of the tables */
+static struct t_ipt_account_table *account_tables = NULL;
+
+/* convert ascii to ip */
+int atoip(char *buffer, u_int32_t *ip) {
+
+	char *bufferptr = buffer;
+	int part, shift;
+	
+	/* zero ip */
+	*ip = 0;
+
+	/* first must be a digit */
+	if (!isdigit(*bufferptr))
+		return 0;
+
+	/* parse first 3 octets (III.III.III.iii) */
+	for (part = 0, shift = 24; *bufferptr && shift; bufferptr++) {
+		if (isdigit(*bufferptr)) {
+			part = part * 10 + (*bufferptr - '0');
+			continue;
+		}
+		if (*bufferptr == '.') {
+			if (part > 255)
+				return 0;
+			*ip |= part << shift;
+			shift -= 8;
+			part = 0;
+			continue;
+		}
+		return 0;
+	}
+	
+	/* we expect more digts */
+	if (!*bufferptr)
+		return 0;
+	/* parse last octet (iii.iii.iii.III) */
+	for (; *bufferptr; bufferptr++) {
+		if (isdigit(*bufferptr)) {
+			part = part * 10 + (*bufferptr - '0');			
+			continue;
+		} else {
+			if (part > 255)
+				return 0;
+			*ip |= part;
+			break;
+		}
+	}
+	return (bufferptr - buffer);
+}
+
+/* convert ascii to 64bit integer */
+int atoi64(char *buffer, u_int64_t *i) {	
+	char *bufferptr = buffer;
+
+	/* zero integer */
+	*i = 0;
+	
+	while (isdigit(*bufferptr)) {
+		*i = *i * 10 + (*bufferptr - '0');
+		bufferptr++;
+	}
+	return (bufferptr - buffer);
+}
+
+static void *account_seq_start(struct seq_file *s, loff_t *pos)
+{
+	struct proc_dir_entry *pde = s->private;
+	struct t_ipt_account_table *table = pde->data;
+
+	unsigned int *bucket;
+	
+	spin_lock_bh(&table->ip_list_lock);
+	if (*pos >= table->count)
+		return NULL;
+
+	bucket = kmalloc(sizeof(unsigned int), GFP_KERNEL);
+	if (!bucket)
+		return ERR_PTR(-ENOMEM);
+	*bucket = *pos;
+	return bucket;
+}
+
+static void *account_seq_next(struct seq_file *s, void *v, loff_t *pos)
+{
+	struct proc_dir_entry *pde = s->private;
+	struct t_ipt_account_table *table = pde->data;
+	
+	unsigned int *bucket = (unsigned int *)v;
+	
+	*pos = ++(*bucket);
+	if (*pos >= table->count) {
+		kfree(v);
+		return NULL;
+	}
+	return bucket;
+}
+
+static void account_seq_stop(struct seq_file *s, void *v)
+{
+	struct proc_dir_entry *pde = s->private;
+	struct t_ipt_account_table *table = pde->data;
+	unsigned int *bucket = (unsigned int *)v;
+	kfree(bucket);
+	spin_unlock_bh(&table->ip_list_lock);
+}
+
+static int account_seq_write(struct file *file, const char *ubuffer, 
+		size_t ulength, loff_t *pos)
+{
+	struct proc_dir_entry *pde = ((struct seq_file *)file->private_data)->private;
+	struct t_ipt_account_table *table = pde->data;
+	char buffer[1024], *bufferptr;
+	int length;
+
+	u_int32_t ip;
+	int len, i;
+	struct t_ipt_account_ip_list l;
+	struct t_ipt_account_ip_list_short s;
+	u_int64_t *p, dummy;
+	
+	
+	dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() entered.\n");
+	dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() ulength = %i.\n", ulength);
+	
+	length = ulength;
+	if (ulength > 1024)
+		length = 1024;
+	if (copy_from_user(buffer, ubuffer, length))
+		return -EFAULT;
+	buffer[length - 1] = 0;
+	bufferptr = buffer;
+
+	dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() buffer = \'%s\' length = %i.\n", buffer, length);
+	
+	/* reset table counters */
+	if (!memcmp(buffer, "reset", 5)) {
+		dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() got \"reset\".\n");
+		if (!table->shortlisting) {
+			spin_lock_bh(&table->ip_list_lock);
+			memset(table->ip_list.l, 0, sizeof(struct t_ipt_account_ip_list) * table->count);
+			spin_unlock_bh(&table->ip_list_lock);
+		} else {
+			spin_lock_bh(&table->ip_list_lock);
+			memset(table->ip_list.s, 0, sizeof(struct t_ipt_account_ip_list_short) * table->count);
+			spin_unlock_bh(&table->ip_list_lock);
+		}
+		return length;
+	}
+
+	if (!memcmp(buffer, "ip", 2)) {
+		dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() got \"ip\".\n");
+		bufferptr += 2;
+		if (!isspace(*bufferptr)) {
+			dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() expected space (%i).\n", bufferptr - buffer);
+			return length; /* expected space */
+		}
+		bufferptr += 1;
+		if (*bufferptr != '=') {
+			dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() expected equal (%i).\n", bufferptr - buffer);
+			return length; /* expected equal */
+		}
+		bufferptr += 1;
+		if (!isspace(*bufferptr)) {
+			dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() expected space (%i).\n", bufferptr - buffer);
+			return length; /* expected space */
+		}
+		bufferptr += 1;
+		if (!(len = atoip(bufferptr, &ip))) {
+			dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() expected ip (%i).\n", bufferptr - buffer);
+			return length; /* expected ip */
+		}
+		bufferptr += len;
+		if ((ip & table->netmask) != table->network) {
+			dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() expected ip [%u.%u.%u.%u] from table's network/netmask [%u.%u.%u.%u/%u.%u.%u.%u].\n", HIPQUAD(ip), HIPQUAD(table->network), HIPQUAD(table->netmask));
+			return length; /* expected ip from table's network/netmask */
+		}
+		if (!table->shortlisting) {
+			memset(&l, 0, sizeof(struct t_ipt_account_ip_list));
+			while(*bufferptr) {
+				if (!isspace(*bufferptr)) {
+					dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() expected space (%i).\n", bufferptr - buffer);
+					return length; /* expected space */
+				}
+				bufferptr += 1;
+				if (!memcmp(bufferptr, "bytes_src", 9)) {
+					dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() got bytes_src (%i).\n", bufferptr - buffer);
+					p = &l.src.b_all;
+					bufferptr += 9;
+				} else if (!memcmp(bufferptr, "bytes_dest", 10)) {					
+					dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() got bytes_dest (%i).\n", bufferptr - buffer);
+					p = &l.dest.b_all;
+					bufferptr += 10;
+				} else if (!memcmp(bufferptr, "packets_src", 11)) {
+					dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() got packets_src (%i).\n", bufferptr - buffer);
+					p = &l.src.p_all;
+					bufferptr += 11;
+				} else if (!memcmp(bufferptr, "packets_dest", 12)) {
+					dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() got packets_dest (%i).\n", bufferptr - buffer);
+					p = &l.dest.p_all;
+					bufferptr += 12;
+				} else if (!memcmp(bufferptr, "time", 4)) {
+					/* time hack, ignore time tokens */
+					dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() got time (%i).\n", bufferptr - buffer);
+					bufferptr += 4;
+					if (!isspace(*bufferptr)) {
+						dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() expected space (%i).\n", bufferptr - buffer);
+						return length; /* expected space */
+					}
+					bufferptr += 1;
+					if (*bufferptr != '=') {
+						dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() expected equal (%i).\n", bufferptr - buffer);
+						return length; /* expected equal */
+					}
+					bufferptr += 1;
+					if (!isspace(*bufferptr)) {
+						dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() expected space (%i).\n", bufferptr - buffer);
+						return length; /* expected space */
+					}
+					bufferptr += 1;
+					if (!(len = atoi64(bufferptr, &dummy))) {
+						dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() expected int64 (%i).\n", bufferptr - buffer);
+						return length; /* expected int64 */
+					}
+					dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() got %llu (%i).\n", dummy, bufferptr - buffer);
+					bufferptr += len;
+					continue; /* skip time token */
+				} else
+					return length;	/* expected token */
+				if (!isspace(*bufferptr)) {
+					dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() expected space (%i).\n", bufferptr - buffer);
+					return length; /* expected space */
+				}
+				bufferptr += 1;
+				if (*bufferptr != '=') {
+					dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() expected equal (%i).\n", bufferptr - buffer);
+					return length; /* expected equal */
+				}
+				bufferptr += 1;
+				for (i = 0; i < 5; i++) {
+					if (!isspace(*bufferptr)) {
+						dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() expected space (%i).\n", bufferptr - buffer);
+						return length; /* expected space */
+					}
+					bufferptr += 1;
+					if (!(len = atoi64(bufferptr, p))) {
+						dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() expected int64 (%i).\n", bufferptr - buffer);
+						return length; /* expected int64 */
+					}
+					dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() got %llu (%i).\n", *p, bufferptr - buffer);
+					bufferptr += len;
+					p++;
+				}
+			}
+			dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() updating row.\n");
+			spin_lock_bh(&table->ip_list_lock);
+			/* update counters, do not overwrite time field */
+			memcpy(&table->ip_list.l[ip - table->network], &l, sizeof(struct t_ipt_account_ip_list) - sizeof(unsigned long));
+			spin_unlock_bh(&table->ip_list_lock);
+		} else {
+			memset(&s, 0, sizeof(struct t_ipt_account_ip_list_short));
+			while(*bufferptr) {
+				if (!isspace(*bufferptr)) {
+					dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() expected space (%i).\n", bufferptr - buffer);
+					return length; /* expected space */
+				}
+				bufferptr += 1;
+				if (!memcmp(bufferptr, "bytes_src", 9)) {
+					dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() got bytes_src (%i).\n", bufferptr - buffer);
+					p = &s.src.b_all;
+					bufferptr += 9;
+				} else if (!memcmp(bufferptr, "bytes_dest", 10)) {					
+					dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() got bytes_dest (%i).\n", bufferptr - buffer);
+					p = &s.dest.b_all;
+					bufferptr += 10;
+				} else if (!memcmp(bufferptr, "packets_src", 11)) {
+					dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() got packets_src (%i).\n", bufferptr - buffer);
+					p = &s.src.p_all;
+					bufferptr += 11;
+				} else if (!memcmp(bufferptr, "packets_dest", 12)) {
+					dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() got packets_dest (%i).\n", bufferptr - buffer);
+					p = &s.dest.p_all;
+					bufferptr += 12;
+				} else if (!memcmp(bufferptr, "time", 4)) {
+					/* time hack, ignore time tokens */
+					dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() got time (%i).\n", bufferptr - buffer);
+					bufferptr += 4;
+					if (!isspace(*bufferptr)) {
+						dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() expected space (%i).\n", bufferptr - buffer);
+						return length; /* expected space */
+					}
+					bufferptr += 1;
+					if (*bufferptr != '=') {
+						dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() expected equal (%i).\n", bufferptr - buffer);
+						return length; /* expected equal */
+					}
+					bufferptr += 1;
+					if (!isspace(*bufferptr)) {
+						dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() expected space (%i).\n", bufferptr - buffer);
+						return length; /* expected space */
+					}
+					bufferptr += 1;
+					if (!(len = atoi64(bufferptr, &dummy))) {
+						dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() expected int64 (%i).\n", bufferptr - buffer);
+						return length; /* expected int64 */
+					}
+					dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() got %llu (%i).\n", dummy, bufferptr - buffer);
+					bufferptr += len;
+					continue; /* skip time token */
+				} else {
+					dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() expected token (%i).\n", bufferptr - buffer);
+					return length;	/* expected token */
+				}
+				if (!isspace(*bufferptr)) {
+					dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() expected space (%i).\n", bufferptr - buffer);
+					return length; /* expected space */
+				}
+				bufferptr += 1;
+				if (*bufferptr != '=') {
+					dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() expected equal (%i).\n", bufferptr - buffer);
+					return length; /* expected equal */
+				}
+				bufferptr += 1;
+				if (!isspace(*bufferptr)) {
+					dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() expected space (%i).\n", bufferptr - buffer);
+					return length; /* expected space */
+				}
+				bufferptr += 1;
+				if (!(len = atoi64(bufferptr, p))) {
+					dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() expected int64 (%i).\n", bufferptr - buffer);
+					return length; /* expected int64 */
+				}
+				dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() got %llu (%i).\n", *p, bufferptr - buffer);
+				bufferptr += len;
+			}
+			dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() updating row.\n");
+			spin_lock_bh(&table->ip_list_lock);
+			/* update counters, do not overwrite time field */
+			memcpy(&table->ip_list.s[ip - table->network], &s, sizeof(struct t_ipt_account_ip_list_short) - sizeof(unsigned long));
+			spin_unlock_bh(&table->ip_list_lock);
+		}
+	}
+	
+	dprintk(KERN_INFO IPT_ACCOUNT_NAME ": account_seq_write() left.\n");
+	return length;
+}
+
+
+static int account_seq_show(struct seq_file *s, void *v)
+{
+	struct proc_dir_entry *pde = s->private;
+	struct t_ipt_account_table *table = pde->data;
+	unsigned int *bucket = (unsigned int *)v;
+
+	u_int32_t address = table->network + *bucket;
+
+	if (!table->shortlisting) {
+		seq_printf(s,
+				"ip = %u.%u.%u.%u bytes_src = %llu %llu %llu %llu %llu packets_src = %llu %llu %llu %llu %llu bytes_dest = %llu %llu %llu %llu %llu packets_dest = %llu %llu %llu %llu %llu\n",
+				HIPQUAD(address),
+				table->ip_list.l[*bucket].src.b_all,
+				table->ip_list.l[*bucket].src.b_tcp,
+				table->ip_list.l[*bucket].src.b_udp,
+				table->ip_list.l[*bucket].src.b_icmp,
+				table->ip_list.l[*bucket].src.b_other,
+				table->ip_list.l[*bucket].src.p_all,
+				table->ip_list.l[*bucket].src.p_tcp,
+				table->ip_list.l[*bucket].src.p_udp,
+				table->ip_list.l[*bucket].src.p_icmp,
+				table->ip_list.l[*bucket].src.p_other,
+				table->ip_list.l[*bucket].dest.b_all,
+				table->ip_list.l[*bucket].dest.b_tcp,
+				table->ip_list.l[*bucket].dest.b_udp,
+				table->ip_list.l[*bucket].dest.b_icmp,
+				table->ip_list.l[*bucket].dest.b_other,				
+				table->ip_list.l[*bucket].dest.p_all,
+				table->ip_list.l[*bucket].dest.p_tcp,
+				table->ip_list.l[*bucket].dest.p_udp,
+				table->ip_list.l[*bucket].dest.p_icmp,
+				table->ip_list.l[*bucket].dest.p_other
+			);
+	} else {
+		seq_printf(s,
+				"ip = %u.%u.%u.%u bytes_src = %llu packets_src = %llu bytes_dest = %llu packets_dest = %llu\n",
+				HIPQUAD(address),
+				table->ip_list.s[*bucket].src.b_all,
+				table->ip_list.s[*bucket].src.p_all,
+				table->ip_list.s[*bucket].dest.b_all,
+				table->ip_list.s[*bucket].dest.p_all
+			  );
+	}
+	return 0;
+}
+
+static struct seq_operations account_seq_ops = {
+	.start = account_seq_start,
+	.next  = account_seq_next,
+	.stop  = account_seq_stop,
+	.show  = account_seq_show
+};
+
+static int account_seq_open(struct inode *inode, struct file *file)
+{
+	int ret = seq_open(file, &account_seq_ops);
+	
+	if (!ret) {
+		struct seq_file *sf = file->private_data;
+		sf->private = PDE(inode);
+	}
+	return ret;
+}
+
+static struct file_operations account_file_ops = {
+	.owner = THIS_MODULE,
+	.open = account_seq_open,
+	.read = seq_read,
+	.write = account_seq_write,
+	.llseek = seq_lseek,
+	.release = seq_release
+};
+
+/* do raw accounting */
+static inline void do_account(struct t_ipt_account_stat *stat, const struct sk_buff *skb) {
+	
+	/* update packet & bytes counters in *stat structure */
+	stat->b_all += skb->len;
+	stat->p_all++;
+	
+	switch (skb->nh.iph->protocol) {
+		case IPPROTO_TCP:
+			stat->b_tcp += skb->len;
+			stat->p_tcp++;
+			break;
+		case IPPROTO_UDP:
+			stat->b_udp += skb->len;
+			stat->p_udp++;
+			break;
+		case IPPROTO_ICMP:
+			stat->b_icmp += skb->len;
+			stat->p_icmp++;
+			break;
+		default:
+			stat->b_other += skb->len;
+			stat->p_other++;
+	}
+}
+
+static inline void do_account_short(struct t_ipt_account_stat_short *stat, const struct sk_buff *skb) {
+
+	/* update packet & bytes counters in *stat structure */
+	stat->b_all += skb->len;
+	stat->p_all++;
+}
+
+static int match(const struct sk_buff *skb,
+	  const struct net_device *in,
+	  const struct net_device *out,
+	  const void *matchinfo,
+	  int offset,
+	  int *hotdrop)
+{
+	
+	const struct t_ipt_account_info *info = (struct t_ipt_account_info*)matchinfo;
+	struct t_ipt_account_table *table;
+	int ret;
+	unsigned long now;
+
+	u_int32_t address;
+	
+	dprintk(KERN_INFO IPT_ACCOUNT_NAME ": match() entered.\n");
+	dprintk(KERN_INFO IPT_ACCOUNT_NAME ": match() match name = %s.\n", info->name);
+	
+	spin_lock_bh(&account_lock);
+	/* find the right table */
+	table = account_tables;
+	while (table && strncmp(table->name, info->name, IPT_ACCOUNT_NAME_LEN) && (table = table->next));
+	spin_unlock_bh(&account_lock);
+
+	if (table == NULL) {
+		/* ups, no table with that name */
+		dprintk(KERN_INFO IPT_ACCOUNT_NAME ": match() table %s not found. Leaving.\n", info->name);
+		return 0;
+	}
+
+	dprintk(KERN_INFO IPT_ACCOUNT_NAME ": match() table found %s\n", table->name);
+
+	/*  lock table while updating statistics */
+	spin_lock_bh(&table->ip_list_lock);
+
+	/* default: no match */
+	ret = 0;
+
+	/* get current time */
+	now = jiffies;
+
+	dprintk(KERN_INFO IPT_ACCOUNT_NAME ": match() got packet src = %u.%u.%u.%u, dst = %u.%u.%u.%u, proto = %u.\n", NIPQUAD(skb->nh.iph->saddr), NIPQUAD(skb->nh.iph->daddr), skb->nh.iph->protocol);
+			
+	/* check whether traffic from source ip address ... */
+	address = ntohl(skb->nh.iph->saddr);
+	/* ... is being accounted by this table */	
+	if (address && ((u_int32_t)(address & table->netmask) == (u_int32_t)table->network)) {		
+		/* yes, account this packet */
+		dprintk(KERN_INFO "ipt_account: match() accounting packet src = %u.%u.%u.%u, proto = %u.\n", HIPQUAD(address), skb->nh.iph->protocol);
+		/* update counters this host */
+		if (!table->shortlisting) {
+			do_account(&table->ip_list.l[address - table->network].src, skb);
+			table->ip_list.l[address - table->network].time = now;
+			/* update also counters for all hosts in this table (network address) */
+			if (table->netmask != INADDR_BROADCAST) {
+				do_account(&table->ip_list.l[0].src, skb);
+				table->ip_list.l[0].time = now;
+			}
+		} else {
+			do_account_short(&table->ip_list.s[address - table->network].src, skb);
+			table->ip_list.s[address - table->network].time = now;
+			/* update also counters for all hosts in this table (network address) */
+			if (table->netmask != INADDR_BROADCAST) {
+				do_account_short(&table->ip_list.s[0].src, skb);
+				table->ip_list.s[0].time = now;
+			}
+		}
+		/* yes, it's a match */
+		ret = 1;
+	}
+
+	/* do the same thing with destination ip address */
+	address = ntohl(skb->nh.iph->daddr);
+	if (address && ((u_int32_t)(address & table->netmask) == (u_int32_t)table->network)) {
+		dprintk(KERN_INFO IPT_ACCOUNT_NAME ": match() accounting packet dst = %u.%u.%u.%u, proto = %u.\n", HIPQUAD(address), skb->nh.iph->protocol);
+		if (!table->shortlisting) {
+			do_account(&table->ip_list.l[address - table->network].dest, skb);
+			table->ip_list.l[address - table->network].time = now;
+			if (table->netmask != INADDR_BROADCAST) {
+				do_account(&table->ip_list.l[0].dest, skb);				
+				table->ip_list.s[0].time = now;
+			}
+		} else {
+			do_account_short(&table->ip_list.s[address - table->network].dest, skb);
+			table->ip_list.s[address - table->network].time = now;
+			if (table->netmask != INADDR_BROADCAST) {
+				do_account_short(&table->ip_list.s[0].dest, skb);
+				table->ip_list.s[0].time = now;
+			}
+		}
+		ret = 1;
+	}
+	spin_unlock_bh(&table->ip_list_lock);
+	
+	dprintk(KERN_INFO IPT_ACCOUNT_NAME ": match() left.\n");	
+
+	return ret;
+}
+
+static int checkentry(const char *tablename,
+	       const struct ipt_ip *ip,
+	       void *matchinfo,
+	       unsigned int matchinfosize,
+	       unsigned int hook_mask)
+{
+	const struct t_ipt_account_info *info = matchinfo;
+	struct t_ipt_account_table *table, *find_table, *last_table;
+	int ret = 0;
+
+	dprintk(KERN_INFO IPT_ACCOUNT_NAME ": checkentry() entered.\n");
+
+	if (matchinfosize != IPT_ALIGN(sizeof(struct t_ipt_account_info))) return 0;
+	if (!info->name || !info->name[0]) return 0;
+
+	/* find whether table with this name already exists */
+	spin_lock_bh(&account_lock);
+	find_table = account_tables;
+	while( (last_table = find_table) && strncmp(info->name,find_table->name,IPT_ACCOUNT_NAME_LEN) && (find_table = find_table->next) );
+	if (find_table != NULL) {
+		dprintk(KERN_INFO IPT_ACCOUNT_NAME ": checkentry() table %s found.\n", info->name);		
+		/* if table exists, check whether table network/netmask equals rule network/netmask */
+		if (find_table->network != info->network || find_table->netmask != info->netmask || find_table->shortlisting != info->shortlisting) {
+			spin_unlock_bh(&account_lock);
+			printk(KERN_INFO IPT_ACCOUNT_NAME ": checkentry() wrong parameters (not equals existing table parameters).\n");
+			ret = 0;
+			goto failure;
+		}
+		/* increment table use count */
+		find_table->use_count++;
+		spin_unlock_bh(&account_lock);
+		dprintk(KERN_INFO IPT_ACCOUNT_NAME ": checkentry() incrementing use count.\n");
+		ret = 1;
+		goto failure;
+	}
+	spin_unlock_bh(&account_lock);
+
+	/* check netmask first, before allocating memory */
+	if (info->netmask < ((1 << netmask) - 1)) {
+		printk(KERN_INFO IPT_ACCOUNT_NAME ": checkentry() too big netmask.\n");
+		ret = 0;
+		goto failure;
+	}
+
+	/* table doesn't exist - create new */
+	dprintk(KERN_INFO IPT_ACCOUNT_NAME ": checkentry() allocating %u for new table %s.\n", sizeof(struct t_ipt_account_table), info->name);
+        table = vmalloc(sizeof(struct t_ipt_account_table));
+	if (table == NULL) {
+		printk(KERN_INFO IPT_ACCOUNT_NAME ": checkentry() failed to allocate %u for new table %s.\n", sizeof(struct t_ipt_account_table), info->name);
+		ret = 0; /* was -ENOMEM */
+		goto failure;
+	}
+	
+	/* setup table parameters */
+	table->ip_list_lock = SPIN_LOCK_UNLOCKED;
+	table->next = NULL;
+	table->use_count = 1;
+	table->network = info->network;
+	table->netmask = info->netmask;
+	table->shortlisting = info->shortlisting;
+	table->count = (~table->netmask) + 1;
+	strncpy(table->name,info->name,IPT_ACCOUNT_NAME_LEN);
+	table->name[IPT_ACCOUNT_NAME_LEN - 1] = '\0';
+	
+	/* allocate memory for table->ip_list */
+	if (!table->shortlisting) {
+		dprintk(KERN_INFO IPT_ACCOUNT_NAME ": checkentry() allocating %u for ip_list.\n", sizeof(struct t_ipt_account_ip_list) * table->count);
+		table->ip_list.l = vmalloc(sizeof(struct t_ipt_account_ip_list) * table->count);
+		if (table->ip_list.l == NULL) {
+			dprintk(KERN_INFO IPT_ACCOUNT_NAME ": checkentry() failed to allocate %u for ip_list.\n", sizeof(struct t_ipt_account_ip_list) * table->count);
+			ret = 0; /* was -ENOMEM */
+			goto failure_table;
+		}
+		memset(table->ip_list.l, 0, sizeof(struct t_ipt_account_ip_list) * table->count);
+	} else {
+		dprintk(KERN_INFO IPT_ACCOUNT_NAME ": checkentry() allocating %u for ip_list.\n", sizeof(struct t_ipt_account_ip_list_short) * table->count);
+		table->ip_list.s = vmalloc(sizeof(struct t_ipt_account_ip_list_short) * table->count);
+		if (table->ip_list.s == NULL) {
+			dprintk(KERN_INFO IPT_ACCOUNT_NAME ": checkentry() failed to allocate %u for ip_list.\n", sizeof(struct t_ipt_account_ip_list_short) * table->count);
+			ret = 0; /* was -ENOMEM */
+			goto failure_table;
+		}
+		memset(table->ip_list.s, 0, sizeof(struct t_ipt_account_ip_list_short) * table->count);
+	}
+	
+	/* put table into chain */
+	spin_lock_bh(&account_lock);
+	find_table = account_tables;
+	while( (last_table = find_table) && strncmp(info->name, find_table->name, IPT_ACCOUNT_NAME_LEN) && (find_table = find_table->next) );
+	if (find_table != NULL) {
+		dprintk(KERN_INFO IPT_ACCOUNT_NAME ": checkentry() table %s found.\n", info->name);
+		if (find_table->network != info->network || find_table->netmask != info->netmask) {
+			spin_unlock_bh(&account_lock);
+			printk(KERN_INFO IPT_ACCOUNT_NAME ": checkentry() wrong network/netmask.\n");
+			ret = 0;
+			goto failure_ip_list;
+		}
+		find_table->use_count++;
+		spin_unlock_bh(&account_lock);
+		dprintk(KERN_INFO IPT_ACCOUNT_NAME ": checkentry() incrementing use count.\n");
+		ret = 1;
+		goto failure_ip_list;
+	}
+	if (!last_table) 
+		account_tables = table; 
+	else 
+		last_table->next = table;
+	spin_unlock_bh(&account_lock);
+
+	/* create procfs status file */
+	table->status_file = create_proc_entry(table->name, permissions, proc_net_ipt_account);
+	if (table->status_file == NULL) {
+		ret = 0; /* was -ENOMEM */
+		goto failure_unlink;
+	}
+	table->status_file->owner = THIS_MODULE;
+	table->status_file->data = table;	
+	wmb();
+	table->status_file->proc_fops = &account_file_ops;
+
+	dprintk(KERN_INFO IPT_ACCOUNT_NAME ": checkentry() left.\n");	
+	/* everything went just okey */
+	return 1;
+
+	/* do cleanup in case of failure */
+failure_unlink:
+	/* remove table from list */
+	dprintk(KERN_INFO IPT_ACCOUNT_NAME ": checkentry() removing table.\n");
+	spin_lock_bh(&account_lock);
+	last_table = NULL;
+	table = account_tables;
+	if (table == NULL) {
+		dprintk(KERN_INFO IPT_ACCOUNT_NAME ": checkentry() no table found. Leaving.\n");
+		spin_unlock_bh(&account_lock);
+		return 0; /* was -ENOMEM */
+	}
+	while (strncmp(info->name, table->name, IPT_ACCOUNT_NAME_LEN) && (last_table = table) && (table = table->next));
+	if (table == NULL) {
+		dprintk(KERN_INFO IPT_ACCOUNT_NAME ": checkentry() table already destroyed. Leaving.\n");
+		spin_unlock_bh(&account_lock);
+		return 0; /* was -ENOMEM */
+	}
+	if (last_table)
+		last_table->next = table->next;
+	else
+		account_tables = table->next;
+	spin_unlock_bh(&account_lock);
+failure_ip_list:
+	/* free memory allocated for statistics table */
+	if (!table->shortlisting)
+		vfree(table->ip_list.l);
+	else
+		vfree(table->ip_list.s);
+failure_table:
+	/* free table */
+	vfree(table);
+failure:
+	dprintk(KERN_INFO IPT_ACCOUNT_NAME ": checkentry() left. Table not created.\n");	
+	/* failure return */
+	return ret;
+}
+
+static void destroy(void *matchinfo, 
+	     unsigned int matchinfosize)
+{
+	const struct t_ipt_account_info *info = matchinfo;
+	struct t_ipt_account_table *table, *last_table;
+
+	dprintk(KERN_INFO IPT_ACCOUNT_NAME ": destory() entered.\n");
+	
+	if (matchinfosize != IPT_ALIGN(sizeof(struct t_ipt_account_info))) return;
+
+	/* search for table */
+	spin_lock_bh(&account_lock);
+	last_table = NULL;
+	table = account_tables;
+	if(table == NULL) {
+		dprintk(KERN_INFO IPT_ACCOUNT_NAME ": destory() no tables found. Leaving.\n");
+		spin_unlock_bh(&account_lock);
+		return;
+	}
+	while( strncmp(info->name,table->name,IPT_ACCOUNT_NAME_LEN) && (last_table = table) && (table = table->next) );
+	if (table == NULL) {
+		dprintk(KERN_INFO IPT_ACCOUNT_NAME ": destory() no table %s not found. Leaving.\n", info->name);
+		spin_unlock_bh(&account_lock);
+		return;
+	}
+
+	/* decrement table use-count */
+	dprintk(KERN_INFO IPT_ACCOUNT_NAME ": destory() decrementing use count.\n");
+	table->use_count--;
+	if (table->use_count) {
+		dprintk(KERN_INFO IPT_ACCOUNT_NAME ": destory() table still in use. Leaving.\n");
+		spin_unlock_bh(&account_lock);
+		return;
+	}
+
+	/* remove table if use-count is zero */
+	dprintk(KERN_INFO IPT_ACCOUNT_NAME ": destory() table %s not used. Removing.\n", table->name);
+
+	/* unlink table */
+	if(last_table) 
+		last_table->next = table->next; 
+	else 
+		account_tables = table->next;
+	spin_unlock_bh(&account_lock);
+
+	/* wait while table is still in use */
+	spin_lock_bh(&table->ip_list_lock);
+	spin_unlock_bh(&table->ip_list_lock);
+
+	/* remove proc entries */	
+	remove_proc_entry(table->name, proc_net_ipt_account);
+
+	/* remove table */
+	if (!table->shortlisting)
+		vfree(table->ip_list.l);
+	else
+		vfree(table->ip_list.s);
+	vfree(table);
+
+	dprintk(KERN_INFO IPT_ACCOUNT_NAME ": destory() left.\n");
+	return;
+}
+
+static struct ipt_match account_match = {
+	.name = "account",
+	.match = &match,
+	.checkentry = &checkentry,
+	.destroy = &destroy,
+	.me = THIS_MODULE
+};
+
+static int __init init(void) 
+{
+	dprintk(KERN_INFO IPT_ACCOUNT_NAME ": __init() entered.\n");
+	printk(version);	
+	/* check params */
+	if (netmask > 32 || netmask < 0) {
+		printk(KERN_INFO "account: Wrong netmask given by netmask parameter (%i). Valid is 32 to 0.\n", netmask);
+		return -EINVAL;
+	}
+
+	/* create /proc/net/ipt_account directory */
+	proc_net_ipt_account = proc_mkdir("ipt_account", proc_net);
+	if (!proc_net_ipt_account) {		
+		printk(KERN_INFO IPT_ACCOUNT_NAME ": checkentry() failed to create procfs entry.\n");
+		return -EINVAL; /* was -ENOMEM */
+	}
+	proc_net_ipt_account->owner = THIS_MODULE;
+	
+	dprintk(KERN_INFO IPT_ACCOUNT_NAME ": __init() left.\n");
+
+	return ipt_register_match(&account_match);
+}
+
+static void __exit fini(void) 
+{
+	dprintk(KERN_INFO IPT_ACCOUNT_NAME ": __exit() entered.\n");
+	
+	ipt_unregister_match(&account_match);
+	/* remove /proc/net/ipt_account/ directory */
+	remove_proc_entry("ipt_account", proc_net);
+
+	dprintk(KERN_INFO IPT_ACCOUNT_NAME ": __exit() left.\n");
+}
+
+module_init(init);
+module_exit(fini);
+

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 232 bytes --]

             reply	other threads:[~2004-09-26 10:02 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2004-09-26 10:02 Piotr Gasidło [this message]
2004-09-27 13:38 ` [PATCH] account match seq_file update [RESEND of RESEND] Patrick McHardy
2004-09-27 14:21   ` Piotr Gasidło

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20040926100202.GA8843@barbara.eu.org \
    --to=quaker@pandora.barbara.ds.polsl.gliwice.pl \
    --cc=netfilter-devel@lists.netfilter.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.