Needed for Hurd 0.3

2008-07-29 Zheng Da <zhengda1936@gmail.com>

	* Makefile: Compile pcap_filter.c.

	* ethernet.c: Open the virtual network device.
	[HAVE_PCAP] (ethernet_reset_filter, ethernet_reset_ipfilter): New functions.

	* linux-src/net/ipv4/devinet.c (configure_device, devinet_ioctl):
	Set the filter rules when IP address is changed.

	* pcap_filter.c: New file.
	(trans_filter_program): New function.

diff -urN -x '*.[od]' -x '*Server.c' -x '*_S.h' -x '*.prof_d' -x '*~' pfinet1/Makefile pfinet2/Makefile
--- pfinet1/Makefile	2008-08-11 05:11:35.390000000 +0200
+++ pfinet2/Makefile	2008-08-11 05:50:34.690000000 +0200
@@ -83,7 +83,7 @@
 SRCS		= sched.c timer-emul.c socket.c main.c ethernet.c \
 		  io-ops.c socket-ops.c misc.c time.c options.c loopback.c \
 		  kmem_cache.c stubs.c dummy.c tunnel.c pfinet-ops.c \
-		  iioctl-ops.c
+		  iioctl-ops.c pcap_filter.c
 MIGSRCS		= ioServer.c socketServer.c startup_notifyServer.c \
 		  pfinetServer.c iioctlServer.c
 OBJS		= $(patsubst %.S,%.o,$(patsubst %.c,%.o,\
@@ -117,6 +117,11 @@
 # compiling `pfinet' with GCC 4.2.
 CFLAGS += -fno-strict-aliasing
 
+ifdef LIBPCAP
+CFLAGS += -DHAVE_PCAP
+LDFLAGS += -lpcap
+endif
+
 asm/checksum.h: ../config.status
 	mkdir -p $(@D)
 	echo > $@.new \
diff -urN -x '*.[od]' -x '*Server.c' -x '*_S.h' -x '*.prof_d' -x '*~' pfinet1/ethernet.c pfinet2/ethernet.c
--- pfinet1/ethernet.c	2008-08-16 18:09:08.000000000 +0200
+++ pfinet2/ethernet.c	2008-08-16 18:19:20.630000000 +0200
@@ -278,3 +278,54 @@
   err = - register_netdevice (dev);
   assert_perror (err);
 }
+
+#ifdef HAVE_PCAP
+
+int
+ethernet_reset_filter (struct device *dev, char *filter_str)
+{
+  error_t err;
+  struct ether_device *edev = (struct ether_device *) dev->priv;
+  int len;
+  struct bpf_insn *insn;
+
+  insn = trans_filter_program (filter_str, 0, &len);
+  if (insn == NULL)
+    return -1;
+
+  /* if the device isn't initialized */
+  if (edev->readpt == NULL)
+    return -1;
+
+  err = device_set_filter (edev->ether_port, ports_get_right (edev->readpt),
+                           MACH_MSG_TYPE_MAKE_SEND, 0, (short *)insn, len);
+  if (err)
+    error (2, err, "ethernet_reset_filter: %s", dev->name);
+
+  free (insn);
+  return 0;
+}
+
+int ethernet_reset_ipfilter (struct device *dev, struct in_addr addr)
+{
+  char ip_str[INET_ADDRSTRLEN];
+  char filter_str[128];
+
+  if (inet_ntop (AF_INET, &addr, ip_str, INET_ADDRSTRLEN) == NULL)
+    {
+      perror ("inet_ntop");
+      return -1;
+    }
+  snprintf (filter_str, sizeof (filter_str), "arp or (ip host %s)", ip_str);
+  return ethernet_reset_filter (dev, filter_str);
+}
+
+#else /* not HAVE_PCAP */
+
+int ethernet_reset_ipfilter (struct device *dev, struct in_addr addr)
+{
+  return 0;
+}
+
+#endif /* not HAVE_PCAP */
+
diff -urN -x '*.[od]' -x '*Server.c' -x '*_S.h' -x '*.prof_d' -x '*~' pfinet1/linux-src/net/ipv4/devinet.c pfinet2/linux-src/net/ipv4/devinet.c
--- pfinet1/linux-src/net/ipv4/devinet.c	2008-08-11 05:12:07.000000000 +0200
+++ pfinet2/linux-src/net/ipv4/devinet.c	2008-08-11 05:51:22.610000000 +0200
@@ -447,6 +447,12 @@
   if (broadcast != INADDR_NONE)
     ifa->ifa_broadcast = broadcast;
 
+  if (addr != INADDR_NONE)
+    {
+      struct in_addr in_addr = {addr};
+      ethernet_reset_ipfilter (dev, in_addr);
+    }
+
   return - (inet_set_ifa (dev, ifa)
 	    ?: dev_change_flags (dev, dev->flags | IFF_UP));
 }
@@ -631,6 +637,7 @@
 				ifa->ifa_mask = inet_make_mask(32);
 			}
 			ret = inet_set_ifa(dev, ifa);
+			ethernet_reset_ipfilter (dev, sin->sin_addr);
 			break;
 
 		case SIOCSIFBRDADDR:	/* Set the broadcast address */
diff -urN -x '*.[od]' -x '*Server.c' -x '*_S.h' -x '*.prof_d' -x '*~' pfinet1/pcap_filter.c pfinet2/pcap_filter.c
--- pfinet1/pcap_filter.c	1970-01-01 01:00:00.000000000 +0100
+++ pfinet2/pcap_filter.c	2008-08-11 05:52:02.000000000 +0200
@@ -0,0 +1,75 @@
+/* 
+   Copyright (C) 2008 Free Software Foundation, Inc.
+
+   Written by Zheng Da.
+
+   This file is part of the GNU Hurd.
+
+   The GNU Hurd is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   The GNU Hurd is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with the GNU Hurd; see the file COPYING.  If not, write to
+   the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+/*
+ * This file translates a string into a bpf program.
+ * The BPF structures are defined in both of bpf.h and pcap-bpf.h
+ * Hopefully, there is no conflict between them.
+ * This file uses the BPF definition in pcap-bpf.h.
+ */
+
+#ifdef HAVE_PCAP
+
+#include <pcap.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define NETF_IN 0x1
+#define NETF_OUT 0x2
+#define NETF_NBPA 10
+#define NETF_BPF (1 << NETF_NBPA)
+
+/* this function translates the bpf program
+ * from the string into the instructions */
+struct bpf_insn *trans_filter_program (char *str, int send, int *filter_len)
+{
+  struct bpf_program program;
+  struct bpf_insn *insn;
+  pcap_t *pcap;
+  int err;
+
+  pcap = pcap_open_dead (DLT_EN10MB, 1500);
+  if (pcap == NULL)
+    return NULL;
+  err = pcap_compile (pcap, &program, str, 1, 0);
+  if (err < 0) 
+    {
+      fprintf (stderr, "pcap_compile: %s\n", pcap_geterr (pcap));
+      pcap_close (pcap);
+      return NULL;
+    }
+
+  insn = (struct bpf_insn *) malloc ((program.bf_len + 1) * sizeof (*insn));
+  /* clear the first instruction */
+  memset (insn, 0, sizeof (*insn));
+  if (send)
+    insn->code = NETF_OUT | NETF_BPF;
+  else
+    insn->code = NETF_IN | NETF_BPF;
+  memcpy (insn + 1, program.bf_insns, program.bf_len * sizeof (*insn));
+  *filter_len = ((program.bf_len + 1) * sizeof (*insn)) / sizeof (short);
+  pcap_freecode (&program);
+  pcap_close (pcap);
+
+  return insn;
+}
+
+#endif
