bug-hurd
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: The patch of pfinet


From: zhengda
Subject: Re: The patch of pfinet
Date: Fri, 08 Aug 2008 08:46:00 +0200
User-agent: Thunderbird 2.0.0.16 (X11/20080707)

The new ChangeLog for the patch.
   *Makefile: Compile pcap_filter.c

   *ethernet.c: Open the virtual network device.
   (ether_filter): Use the bpf filter.
(ethernet_open): Open the virtual network device if the user specifies one.
   (ethernet_reset_filter, ethernet_reset_ipfilter): New functions.
(PCAP_SUPPORT): Control whether to generate the filter rule with libpcap.

   *ethernet.h: New file.
   Define the structure of ether_device.

   *iioctl-ops.c (S_iioctl_siocsifflags): Change the Mach device flags.

   *options.c: Add another option to open the virtual network interface

   *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): Translate the string into the bpf instructions.


zhengda wrote:
Hello,

The patch enables the pfinet to work with the multiplexer
and use the filter rule that only accepts the packet whose destination is the pfinet server. The way of opening the virtual network device might be changed if the translator that helps open the device is created.


Here is the patch.

Needed for Hurd 0.3

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

   *Makefile: Compile pcap_filter.c

*ethernet.c: Use the bpf filter. Open the virtual network device if the
   user specifies one. Add new functions that can change the filer rules.

   *ethernet.h: define the structure of ether_device.

   *iioctl-ops.c: change the Mach device flags.

   *options.c: add another option to open the virtual network interface

*linux-src/net/ipv4/devinet.c: set the filter rules when IP address is changed.

   *pcap_filter.c: translate the string into the bpf instructions.

diff -urN pfinet.old/Makefile pfinet/Makefile
--- pfinet.old/Makefile    2007-10-08 23:59:09.000000000 +0200
+++ pfinet/Makefile    2008-07-26 10:42:42.000000000 +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,\
@@ -115,7 +115,9 @@

# Don't ask...  We use Linux code.  The problem was first noticed when
# compiling `pfinet' with GCC 4.2.
-CFLAGS += -fno-strict-aliasing
+CFLAGS += -fno-strict-aliasing -DPCAP_SUPPORT
+
+LDFLAGS += -lpcap

asm/checksum.h: ../config.status
    mkdir -p $(@D)
diff -urN pfinet.old/ethernet.c pfinet/ethernet.c
--- pfinet.old/ethernet.c    2007-10-09 10:01:34.000000000 +0200
+++ pfinet/ethernet.c    2008-08-08 07:03:03.000000000 +0200
@@ -21,29 +21,23 @@
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */

#include "pfinet.h"
+#include "ethernet.h"

#include <device/device.h>
#include <device/net_status.h>
#include <netinet/in.h>
+#include <arpa/inet.h>
#include <string.h>
+#include <errno.h>
#include <error.h>

#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/if_arp.h>
-
+#include <device/bpf.h>

struct port_class *etherreadclass;

-struct ether_device
-{
-  struct ether_device *next;
-  device_t ether_port;
-  struct port_info *readpt;
-  mach_port_t readptname;
-  struct device dev;
-};
-
/* Linked list of all ethernet devices.  */
struct ether_device *ether_dev;

@@ -68,15 +62,15 @@
{
}

-static short ether_filter[] =
+/* The BPF instruction allows IP and ARP packets */
+static struct bpf_insn ether_filter[] =
{
-#ifdef NETF_IN
-  /* We have to tell the packet filtering code that we're interested in
-     incoming packets.  */
-  NETF_IN, /* Header.  */
-#endif
-  NETF_PUSHLIT | NETF_NOP,
-  1
+    {NETF_IN|NETF_BPF, /* Header. */ 0, 0, 0},
+    {40, 0, 0, 12},
+    {21, 1, 0, 2054},
+    {21, 0, 1, 2048},
+    {6, 0, 0, 1500},
+    {6, 0, 0, 0}
};
static int ether_filter_len = sizeof (ether_filter) / sizeof (short);

@@ -87,14 +81,14 @@
ethernet_thread (any_t arg)
{
  ports_manage_port_operations_one_thread (etherport_bucket,
-                       ethernet_demuxer,
-                       0);
+                                           ethernet_demuxer,
+                                           0);
  return 0;
}

int
ethernet_demuxer (mach_msg_header_t *inp,
-          mach_msg_header_t *outp)
+                  mach_msg_header_t *outp)
{
  struct net_rcv_msg *msg = (struct net_rcv_msg *) inp;
  struct sk_buff *skb;
@@ -109,10 +103,11 @@
    if (inp->msgh_local_port == edev->readptname)
      dev = &edev->dev;

+  fprintf (stderr, "pfinet receives a message\n");
  if (! dev)
    {
      if (inp->msgh_remote_port != MACH_PORT_NULL)
-    mach_port_deallocate (mach_task_self (), inp->msgh_remote_port);
+        mach_port_deallocate (mach_task_self (), inp->msgh_remote_port);
      return 1;
    }

@@ -127,8 +122,8 @@
  /* Copy the two parts of the frame into the buffer. */
  bcopy (msg->header, skb->data, ETH_HLEN);
  bcopy (msg->packet + sizeof (struct packet_header),
-     skb->data + ETH_HLEN,
-     datalen - ETH_HLEN);
+         skb->data + ETH_HLEN,
+         datalen - ETH_HLEN);

  /* Drop it on the queue. */
  skb->protocol = eth_type_trans (skb, dev);
@@ -151,24 +146,35 @@
int
ethernet_open (struct device *dev)
{
+  extern char *master_device_file;
  error_t err;
  device_t master_device;
  struct ether_device *edev = (struct ether_device *) dev->priv;

+  fprintf (stderr, "ethernet_open is called\n");
  assert (edev->ether_port == MACH_PORT_NULL);

  err = ports_create_port (etherreadclass, etherport_bucket,
-               sizeof (struct port_info), &edev->readpt);
+                           sizeof (struct port_info), &edev->readpt);
  assert_perror (err);
  edev->readptname = ports_get_right (edev->readpt);
mach_port_insert_right (mach_task_self (), edev->readptname, edev->readptname,
-              MACH_MSG_TYPE_MAKE_SEND);
+                          MACH_MSG_TYPE_MAKE_SEND);

mach_port_set_qlimit (mach_task_self (), edev->readptname, MACH_PORT_QLIMIT_MAX);

-  err = get_privileged_ports (0, &master_device);
-  if (err)
-    error (2, err, "cannot get device master port");
+  if (master_device_file)
+    {
+      master_device = file_name_lookup (master_device_file , 0 , 0);
+      if (master_device == MACH_PORT_NULL)
+        error (10, 0, "file_name_lookup %s", master_device_file);
+    }
+  else
+    {
+      err = get_privileged_ports (0, &master_device);
+      if (err)
+        error (2, err, "cannot get device master port");
+    }

err = device_open (master_device, D_WRITE | D_READ, dev->name, &edev->ether_port);
  mach_port_deallocate (mach_task_self (), master_device);
@@ -176,13 +182,64 @@
    error (2, err, "%s", dev->name);

err = device_set_filter (edev->ether_port, ports_get_right (edev->readpt),
-               MACH_MSG_TYPE_MAKE_SEND, 0,
-               ether_filter, ether_filter_len);
+                           MACH_MSG_TYPE_MAKE_SEND, 0,
+                           ether_filter, ether_filter_len);
  if (err)
    error (2, err, "%s", dev->name);
  return 0;
}

+#ifdef PCAP_SUPPORT
+
+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;
+  +  fprintf (stderr, "set filter rule: %s\n", filter_str);
+  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)
+    {
+      fprintf (stderr,
+               "ethernet_reset_ipfilter: cannot parse an IP address\n");
+      return -1;
+    }
+ snprintf (filter_str, sizeof (filter_str), "arp or (ip host %s)", ip_str);
+  return ethernet_reset_filter (dev, filter_str);
+}
+
+#else
+
+int ethernet_reset_ipfilter (struct device *dev, struct in_addr addr)
+{
+  return 0;
+}
+
+#endif

/* Transmit an ethernet frame */
int
@@ -249,7 +306,7 @@
  /* Fetch hardware information */
  count = NET_STATUS_COUNT;
  err = device_get_status (edev->ether_port, NET_STATUS,
-               (dev_status_t) &netstat, &count);
+                           (dev_status_t) &netstat, &count);
  if (err)
    error (2, err, "%s: Cannot get device status", name);
  dev->mtu = netstat.max_packet_size - dev->hard_header_len;
diff -urN pfinet.old/ethernet.h pfinet/ethernet.h
--- pfinet.old/ethernet.h    1970-01-01 01:00:00.000000000 +0100
+++ pfinet/ethernet.h    2008-07-24 04:50:03.000000000 +0200
@@ -0,0 +1,36 @@
+/*
+   Copyright (C) 1995,96,98,99,2000,02 Free Software Foundation, Inc.
+   Written by Michael I. Bushnell, p/BSG.
+
+   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 this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#ifndef ETHERNET_H_
+#define ETHERNET_H_
+
+#include <linux/netdevice.h>
+
+struct ether_device
+{
+  struct ether_device *next;
+  device_t ether_port;
+  struct port_info *readpt;
+  mach_port_t readptname;
+  struct device dev;
+};
+
+#endif
+
diff -urN pfinet.old/iioctl-ops.c pfinet/iioctl-ops.c
--- pfinet.old/iioctl-ops.c    2007-10-13 20:30:31.000000000 +0200
+++ pfinet/iioctl-ops.c    2008-07-26 10:41:03.000000000 +0200
@@ -19,8 +19,8 @@
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */

#include "pfinet.h"
+#include "ethernet.h"

-#include <linux/netdevice.h>
#include <linux/notifier.h>

#include "iioctl_S.h"
@@ -188,7 +188,15 @@
  else if (!dev)
    err = ENODEV;
  else
-    err = dev_change_flags(dev, flags);
+    {
+      err = dev_change_flags(dev, flags);
+      /* Change the  Mach device flags. Some  flags (e.g., promiscuous
+         and multicast) are handled by the drivers. */
+#ifdef PCAP_SUPPORT
+      device_set_status(((struct ether_device *)dev->priv)->ether_port,
+ NET_FLAGS, (dev_status_t) &flags, sizeof (flags));
+#endif
+    }

  __mutex_unlock (&global_lock);
  end_using_socket_port (user);
diff -urN pfinet.old/linux-src/net/ipv4/devinet.c pfinet/linux-src/net/ipv4/devinet.c --- pfinet.old/linux-src/net/ipv4/devinet.c 2001-07-18 19:37:13.000000000 +0200 +++ pfinet/linux-src/net/ipv4/devinet.c 2008-08-08 07:04:50.000000000 +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 pfinet.old/options.c pfinet/options.c
--- pfinet.old/options.c    2007-10-14 04:26:10.000000000 +0200
+++ pfinet/options.c    2008-07-24 02:02:31.000000000 +0200
@@ -60,6 +60,8 @@
extern int inet6_addr_add (int ifindex, struct in6_addr *pfx, int plen);
extern int inet6_addr_del (int ifindex, struct in6_addr *pfx, int plen);

+char *master_device_file = NULL;
+

/* Pfinet options.  Used for both startup and runtime.  */
static const struct argp_option options[] =
@@ -77,6 +79,7 @@
  {"gateway6",  'G', "ADDRESS", 0, "Set the IPv6 default gateway"},
#endif
  {"shutdown",  's', 0,         0, "Shut it down"},
+  {"master",    'M', "FILE",    0, "Get a master device port"},
  {0}
};

@@ -90,6 +93,9 @@
  /* The network interface in question.  */
  struct device *device;

+  /* the name of the network interface */
+  char *name;
+
  /* New values to apply to it. (IPv4) */
  uint32_t address, netmask, peer, gateway;

@@ -126,6 +132,7 @@
  h->num_interfaces++;
  h->curint = new + h->num_interfaces - 1;
  h->curint->device = 0;
+  h->curint->name = 0;
  h->curint->address = INADDR_NONE;
  h->curint->netmask = INADDR_NONE;
  h->curint->peer = INADDR_NONE;
@@ -195,12 +202,12 @@
    case 'i':
      /* An interface.  */
      err = 0;
-      if (h->curint->device)
+      if (h->curint->name)
    /* The current interface slot is not available.  */
    {
/* First see if a previously specified one is being re-specified. */ for (in = h->interfaces; in < h->interfaces + h->num_interfaces; in++)
-        if (strcmp (in->device->name, arg) == 0)
+        if (strcmp (in->name, arg) == 0)
          /* Re-use an old slot.  */
          {
        h->curint = in;
@@ -213,9 +220,7 @@
      in = h->curint;

      if (! err)
-    err = find_device (arg, &in->device);
-      if (err)
-    FAIL (err, 10, err, "%s", arg);
+        in->name = arg;

      break;

@@ -240,6 +245,8 @@
      h->curint->peer = ADDR (arg, "peer"); break;
    case 'g':
      h->curint->gateway = ADDR (arg, "gateway"); break;
+    case 'M':
+      master_device_file = arg; break;

    case '4':
      pfinet_bind (PORTCLASS_INET, arg);
@@ -303,18 +310,27 @@
      break;

    case ARGP_KEY_SUCCESS:
-      in = h->curint;
+ for (in = h->interfaces; in < h->interfaces + h->num_interfaces; in++)
+    {
+      if (in->name)
+        {
+          err = find_device (in->name, &in->device);
+          if (err)
+            FAIL (err, 10, err, "%s", in->name);
+        }
      if (! in->device)
-    /* No specific interface specified; is that ok?  */
-    if (in->address != INADDR_NONE || in->netmask != INADDR_NONE
-        || in->gateway != INADDR_NONE)
-      /* Some options were specified, so we need an interface.  See if
-             there's a single extant interface to use as a default.  */
-      {
-        err = find_device (0, &in->device);
-        if (err)
-          FAIL (err, 13, 0, "No default interface");
-      }
+        /* No specific interface specified; is that ok?  */
+        if (in->address != INADDR_NONE || in->netmask != INADDR_NONE
+            || in->gateway != INADDR_NONE)
+ /* Some options were specified, so we need an interface. See if + there's a single extant interface to use as a default. */
+          {
+            err = find_device (0, &in->device);
+            if (err)
+              FAIL (err, 13, 0, "No default interface");
+          }
+      }
+      in = h->curint;
#if 0                /* XXX what does this mean??? */
      /* Check for bogus option combinations.  */
for (in = h->interfaces; in < h->interfaces + h->num_interfaces; in++)
diff -urN pfinet.old/pcap_filter.c pfinet/pcap_filter.c
--- pfinet.old/pcap_filter.c    1970-01-01 01:00:00.000000000 +0100
+++ pfinet/pcap_filter.c    2008-08-08 07:06:26.000000000 +0200
@@ -0,0 +1,76 @@
+/*
+   Copyright (C) 1993,94,95,96,97,98,99,2000,01,02,2006,2008
+   Free Software Foundation, Inc.
+
+   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. */
+
+/* Written by Zheng Da.  */
+
+/*
+ * 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 PCAP_SUPPORT
+
+#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







reply via email to

[Prev in Thread] Current Thread [Next in Thread]