[parisc-linux-cvs] iptables support diff

Grant Grundler grundler@puffin.external.hp.com
Thu, 26 Apr 2001 00:14:41 -0600


Hi all,

With help from rhirst and willy, I've gotten both a setsockopt() syscall
wrapper and hacked iptables solutions working on the A500.  I strongly
prefer the syscall wrapper since it means we only need to distribute one
set of binaries and that keeps the debian packaging simple.

Note this diff does not include support for ipv6 - so I'm not sure should
close the bug (#109).

Appended is the diff to make the setsockopt() syscall wrapper work.

grant

Index: arch/parisc/kernel/sys_parisc32.c
===================================================================
RCS file: /home/cvs/parisc/linux/arch/parisc/kernel/sys_parisc32.c,v
retrieving revision 1.8
diff -u -p -r1.8 sys_parisc32.c
--- sys_parisc32.c	2001/04/24 05:19:16	1.8
+++ sys_parisc32.c	2001/04/26 04:58:37
@@ -42,7 +42,11 @@
 #include <linux/poll.h>
 #include <linux/personality.h>
 #include <linux/stat.h>
-#include <linux/filter.h>
+#include <linux/filter.h>			/* for setsockopt() */
+#include <linux/icmpv6.h>			/* for setsockopt() */
+#include <linux/netfilter_ipv4/ip_queue.h>	/* for setsockopt() */
+#include <linux/netfilter_ipv4/ip_tables.h>	/* for setsockopt() */
+#include <linux/netfilter_ipv6/ip6_tables.h>	/* for setsockopt() */
 #include <linux/highmem.h>
 #include <linux/highuid.h>
 #include <linux/mman.h>
@@ -2222,8 +2226,7 @@ out:
 	return len;
 }
 
-/* didn't think we needed these translators but could be wrong -PB */
-#if 0
+
 extern asmlinkage int sys_setsockopt(int fd, int level, int optname,
 				     char *optval, int optlen);
 
@@ -2297,20 +2300,60 @@ static int do_set_icmpv6_filter(int fd, 
 	return ret;
 }
 
+
+static int do_ipv4_set_replace(int fd, int level, int optname,
+				char *optval, int optlen)
+{
+	struct ipt_replace *repl = (struct ipt_replace *) optval;
+	unsigned long ptr64;
+	unsigned int ptr32;
+	int ret;
+
+	if (copy_from_user(&ptr32, &repl->counters, sizeof(ptr32)))
+		return -EFAULT;
+	ptr64 = (unsigned long) ptr32;
+	if (copy_to_user(&repl->counters, &ptr64, sizeof(ptr64)))
+		return -EFAULT;
+
+	ret = sys_setsockopt(fd, level, optname, (char *) optval, optlen);
+
+	/* Restore 32-bit ptr */
+	if (copy_to_user(&repl->counters, &ptr32, sizeof(ptr32)))
+		return -EFAULT;
+
+	return ret;
+}
+
+
 asmlinkage int sys32_setsockopt(int fd, int level, int optname,
 				char *optval, int optlen)
 {
 	if (optname == SO_ATTACH_FILTER)
-		return do_set_attach_filter(fd, level, optname,
-					    optval, optlen);
-	if (level == SOL_ICMPV6 && optname == ICMPV6_FILTER)
-		return do_set_icmpv6_filter(fd, level, optname,
-					    optval, optlen);
+		return do_set_attach_filter(fd, level, optname, optval, optlen);
+
+	if (level == SOL_ICMPV6   && optname == ICMPV6_FILTER)
+		return do_set_icmpv6_filter(fd, level, optname, optval, optlen);
+
+	/*
+	** Beware:    IPT_SO_SET_REPLACE == IP6T_SO_SET_REPLACE
+	*/
+	if (level == IPPROTO_IP   && optname == IPT_SO_SET_REPLACE)
+		return do_ipv4_set_replace(fd, level, optname, optval, optlen);
 
+	if (level == IPPROTO_IPV6 && optname == IP6T_SO_SET_REPLACE)
+#if 0
+		/* FIXME: I don't (yet) use IPV6. -ggg */
+		return do_ipv6_set_replace(fd, level, optname, optval, optlen);
+#else
+	{
+		BUG();
+		return -ENXIO;
+	}
+#endif
+
 	return sys_setsockopt(fd, level, optname, optval, optlen);
 }
 
-#endif
 
 /*** copied from mips64 ***/
 /*
Index: arch/parisc/kernel/syscall.S
===================================================================
RCS file: /home/cvs/parisc/linux/arch/parisc/kernel/syscall.S,v
retrieving revision 1.63
diff -u -p -r1.63 syscall.S
--- syscall.S	2001/04/17 21:37:27	1.63
+++ syscall.S	2001/04/26 05:03:31
@@ -550,8 +550,8 @@ sys_call_table:
 	ENTRY_UHOH(rt_sigqueueinfo)
 	ENTRY_SAME(rt_sigsuspend_wrapper) /* not really SAME -- see the code */
 	ENTRY_SAME(chown)		/* 180 */
-	/* *sockopt() might work... */
-	ENTRY_SAME(setsockopt)
+	/* setsockopt() used by iptables: SO_SET_REPLACE/SO_SET_ADD_COUNTERS */
+	ENTRY_DIFF(setsockopt)
 	ENTRY_SAME(getsockopt)
 	ENTRY_DIFF(sendmsg)
 	ENTRY_DIFF(recvmsg)
Index: include/linux/netfilter_ipv4/ip_tables.h
===================================================================
RCS file: /home/cvs/parisc/linux/include/linux/netfilter_ipv4/ip_tables.h,v
retrieving revision 1.2
diff -u -p -r1.2 ip_tables.h
--- ip_tables.h	2000/08/18 01:53:15	1.2
+++ ip_tables.h	2001/04/26 05:04:05
@@ -251,8 +251,12 @@ struct ipt_replace
 	/* Information about old entries: */
 	/* Number of counters (must be equal to current number of entries). */
 	unsigned int num_counters;
+
 	/* The old entries' counters. */
 	struct ipt_counters *counters;
+#ifndef __LP64__
+	unsigned int pad0;      /* space for 64-bit counters ptr */
+#endif
 
 	/* The entries (hang off end: not really an array). */
 	struct ipt_entry entries[0];
@@ -265,8 +269,11 @@ struct ipt_counters_info
 	char name[IPT_TABLE_MAXNAMELEN];
 
 	unsigned int num_counters;
+#ifndef __LP64__
+	unsigned int pad0;      /* align counters[] in case kernel is 64-bit */
+#endif
 
-	/* The counters (actually `number' of these). */
+	/* The counters (actually `num_counters' of these). */
 	struct ipt_counters counters[0];
 };