Hi,

I redid the patch for multiple interfaces and dummy devices I wrote yesterday,
so that it now uses seperate linked lists to store ethernet and dummy devices,
and checks the linked list dev_base in find_device and enumerate_devices.

As before, find_device and enumerate_device don't include the loopback
interface. If this is desired, it can easily be enabled, though. However, I
wanted to minimize the impact of my changes on existing setups, and only
extend it.

With the patch, we support an arbitrary number of ethernet and dummy devices.

Please let me know if I can apply this when it is sufficiently tested,
and if not, what's left to do.

Thanks,
Marcus

2000-10-01  Marcus Brinkmann  <[EMAIL PROTECTED]>

        * Makefile (SRCS): Add dummy.c
        * dummy.c: New file.

        * ethernet.c: Moved ETHER_PORT, READPT, READPTNAME to ...
        (struct ether_device): ... here. New struct.
        ETHER_DEV is now a pointer to a struct ether_device.
        (ethernet_demuxer): New variables edev, dev.
        Iterate over linked list ETHER_DEV to find correct
        readptname. Use dev instead ETHER_DEV for socket buffer
        manipulation.
        (ethernet_open): New variable edev.
        Iterate over ETHER_DEV to find correct dev.
        Use members of edev instead global variables.
        (ethernet_xmit): New variable edev. Iterate over ETHER_DEV
        to find correct dev. Use member of edev instead global variable
        ETHER_PORT.
        (setup_ethernet_device): New output argument DEVICE.
        New variables edev and dev. Allocate memory for edev, add it to
        the head of ETHER_DEV. Use dev instead ETHER_DEV.
        Use members of edev instead global variables.
        * main.c: ALREADY_OPEN removed.
        (find_device): Fix comment. Redone to work with multiple
        devices by iterating over DEV_BASE.
        (enumerate_device): Likewise.
        * pfinet.h: Add new argument to prototype of setup_ethernet_device.
        Add prototype for setup_dummy_device.
        Remove prototype for ETHER_DEV.
        Add prototype for DEV_BASE.

-- 
`Rhubarb is no Egyptian god.' Debian http://www.debian.org Check Key server 
Marcus Brinkmann              GNU    http://www.gnu.org    for public PGP Key 
[EMAIL PROTECTED],     [EMAIL PROTECTED]    PGP Key ID 36E7CD09
http://homepage.ruhr-uni-bochum.de/Marcus.Brinkmann/       [EMAIL PROTECTED]
diff -x CVS -Nru gnu/cvs/hurd/pfinet/Makefile 
gnu/hurd/hurd/hurd-20000921/pfinet/Makefile
--- gnu/cvs/hurd/pfinet/Makefile        Sat Feb  5 19:32:57 2000
+++ gnu/hurd/hurd/hurd-20000921/pfinet/Makefile Sat Sep 30 23:00:30 2000
@@ -61,7 +61,7 @@
 LINUXSRCS      = $(core-srcs) $(ethernet-srcs) $(ipv4-srcs) $(arch-lib-srcs)
 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
+                 kmem_cache.c stubs.c dummy.c
 MIGSRCS                = ioServer.c socketServer.c startup_notifyServer.c
 OBJS           := $(patsubst %.c,%.o,$(LINUXSRCS) $(SRCS) $(MIGSRCS))
 LCLHDRS                = config.h mapped-time.h mutations.h pfinet.h
diff -x CVS -Nru gnu/cvs/hurd/pfinet/dummy.c gnu/hurd/hurd/hurd-20000921/pfinet/dummy.c
--- gnu/cvs/hurd/pfinet/dummy.c Thu Jan  1 01:00:00 1970
+++ gnu/hurd/hurd/hurd-20000921/pfinet/dummy.c  Sun Oct  1 15:56:51 2000
@@ -0,0 +1,140 @@
+/*
+   Copyright (C) 1995,96,98,99,2000 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. */
+
+#include "pfinet.h"
+
+#include <device/device.h>
+#include <device/net_status.h>
+#include <netinet/in.h>
+#include <string.h>
+#include <error.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/if_arp.h>
+
+struct dummy_device
+{
+  struct dummy_device *next;
+  struct device dev;
+};
+
+/* Linked list of all dummy devices.  */
+struct dummy_device *dummy_dev;
+
+struct net_device_stats *
+dummy_get_stats (struct device *dev)
+{
+  struct net_device_stats *stats = (struct net_device_stats *) dev->priv;
+  return stats;
+}
+
+int
+dummy_stop (struct device *dev)
+{
+  return 0;
+}
+
+void
+dummy_set_multi (struct device *dev)
+{
+}
+
+int
+dummy_open (struct device *dev)
+{
+  return 0;
+}
+
+int
+dummy_xmit (struct sk_buff *skb, struct device *dev)
+{
+  struct net_device_stats *stats = (struct net_device_stats *)dev->priv;
+
+  stats->tx_packets++;
+  stats->tx_bytes += skb->len;
+
+  dev_kfree_skb (skb);
+  return 0;
+}
+
+void
+setup_dummy_device (char *name, struct device **device)
+{
+  error_t err;
+  struct dummy_device *ddev;
+  struct device *dev;
+
+  ddev = calloc (1, sizeof (struct dummy_device));
+  if (!ddev)
+    error (2, ENOMEM, "%s", name);
+  ddev->next = dummy_dev;
+  dummy_dev = ddev;
+
+  *device = dev = &ddev->dev;
+
+  dev->name = strdup (name);
+
+  dev->priv = kmalloc(sizeof(struct net_device_stats), GFP_KERNEL);
+  if (dev->priv == NULL)
+    error (2, ENOMEM, "%s", name);
+  memset(dev->priv, 0, sizeof(struct net_device_stats));
+  dev->get_stats = dummy_get_stats;
+
+  dev->open = dummy_open;
+  dev->stop = dummy_stop;
+  dev->hard_start_xmit = dummy_xmit;
+  dev->set_multicast_list = dummy_set_multi;
+
+  /* These are the ones set by drivers/net/net_init.c::ether_setup.  */
+  dev->hard_header = eth_header;
+  dev->rebuild_header = eth_rebuild_header;
+  dev->hard_header_cache = eth_header_cache;
+  dev->header_cache_update = eth_header_cache_update;
+  dev->hard_header_parse = eth_header_parse;
+  /* We can't do these two (and we never try anyway).  */
+  /* dev->change_mtu = eth_change_mtu; */
+  /* dev->set_mac_address = eth_mac_addr; */
+
+  /* Some more fields */
+  dev->type = ARPHRD_ETHER;
+  dev->hard_header_len = ETH_HLEN;
+  dev->addr_len = ETH_ALEN;
+  memset (dev->broadcast, 0xff, ETH_ALEN);
+  dev->flags = IFF_BROADCAST | IFF_MULTICAST;
+  dev_init_buffers (dev);
+
+  dev->mtu = 1500;
+  dev->tx_queue_len = 0;
+  dev->flags |= IFF_NOARP;
+  dev->flags &= ~IFF_MULTICAST;
+
+  /* That should be enough.  */
+
+  /* This call adds the device to the `dev_base' chain,
+     initializes its `ifindex' member (which matters!),
+     and tells the protocol stacks about the device.  */
+  err = - register_netdevice (dev);
+  assert_perror (err);
+}
+
+
+
+
diff -x CVS -Nru gnu/cvs/hurd/pfinet/ethernet.c 
gnu/hurd/hurd/hurd-20000921/pfinet/ethernet.c
--- gnu/cvs/hurd/pfinet/ethernet.c      Sat Feb  5 19:32:58 2000
+++ gnu/hurd/hurd/hurd-20000921/pfinet/ethernet.c       Sun Oct  1 15:56:31 2000
@@ -31,13 +31,19 @@
 #include <linux/if_arp.h>
 
 
-device_t ether_port;
-
 struct port_class *etherreadclass;
-struct port_info *readpt;
-mach_port_t readptname;
 
-struct device ether_dev;
+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;
 
 struct enet_statistics retbuf;
 
@@ -86,11 +92,17 @@
   struct net_rcv_msg *msg = (struct net_rcv_msg *) inp;
   struct sk_buff *skb;
   int datalen;
+  struct ether_device *edev;
+  struct device *dev = 0;
 
   if (inp->msgh_id != NET_RCV_MSG_ID)
     return 0;
 
-  if (inp->msgh_local_port != readptname)
+  for (edev = ether_dev; edev; edev = edev->next)
+    if (inp->msgh_local_port == edev->readptname)
+      dev = &edev->dev;
+
+  if (! dev)
     {
       if (inp->msgh_remote_port != MACH_PORT_NULL)
        mach_port_deallocate (mach_task_self (), inp->msgh_remote_port);
@@ -103,7 +115,7 @@
   __mutex_lock (&net_bh_lock);
   skb = alloc_skb (datalen, GFP_ATOMIC);
   skb->len = datalen;
-  skb->dev = &ether_dev;
+  skb->dev = dev;
 
   /* Copy the two parts of the frame into the buffer. */
   bcopy (msg->header, skb->data, ETH_HLEN);
@@ -112,7 +124,7 @@
         datalen - ETH_HLEN);
 
   /* Drop it on the queue. */
-  skb->protocol = eth_type_trans (skb, &ether_dev);
+  skb->protocol = eth_type_trans (skb, dev);
   netif_rx (skb);
   __mutex_unlock (&net_bh_lock);
 
@@ -134,28 +146,34 @@
 {
   error_t err;
   device_t master_device;
+  struct ether_device *edev;
+
+  for (edev = ether_dev; edev; edev = edev->next)
+    if (dev == &edev->dev)
+      break;
 
-  assert (ether_port == MACH_PORT_NULL);
+  assert (edev);
+  assert (edev->ether_port == MACH_PORT_NULL);
 
   err = ports_create_port (etherreadclass, etherport_bucket,
-                          sizeof (struct port_info), &readpt);
+                          sizeof (struct port_info), &edev->readpt);
   assert_perror (err);
-  readptname = ports_get_right (readpt);
-  mach_port_insert_right (mach_task_self (), readptname, readptname,
+  edev->readptname = ports_get_right (edev->readpt);
+  mach_port_insert_right (mach_task_self (), edev->readptname, edev->readptname,
                          MACH_MSG_TYPE_MAKE_SEND);
 
-  mach_port_set_qlimit (mach_task_self (), readptname, MACH_PORT_QLIMIT_MAX);
+  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");
 
-  err = device_open (master_device, D_WRITE | D_READ, dev->name, &ether_port);
+  err = device_open (master_device, D_WRITE | D_READ, dev->name, &edev->ether_port);
   mach_port_deallocate (mach_task_self (), master_device);
   if (err)
     error (2, err, "%s", dev->name);
 
-  err = device_set_filter (ether_port, ports_get_right (readpt),
+  err = device_set_filter (edev->ether_port, ports_get_right (edev->readpt),
                           MACH_MSG_TYPE_MAKE_SEND, 0,
                           ether_filter, ether_filter_len);
   if (err)
@@ -170,8 +188,13 @@
 {
   u_int count;
   error_t err;
+  struct ether_device *edev;
+
+  for (edev = ether_dev; edev; edev = edev->next)
+    if (dev == &edev->dev)
+      break;
 
-  err = device_write (ether_port, D_NOWAIT, 0, skb->data, skb->len, &count);
+  err = device_write (edev->ether_port, D_NOWAIT, 0, skb->data, skb->len, &count);
   assert_perror (err);
   assert (count == skb->len);
   dev_kfree_skb (skb);
@@ -179,69 +202,76 @@
 }
 
 void
-setup_ethernet_device (char *name)
+setup_ethernet_device (char *name, struct device **device)
 {
   struct net_status netstat;
   u_int count;
   int net_address[2];
   error_t err;
+  struct ether_device *edev;
+  struct device *dev;
 
-  bzero (&ether_dev, sizeof ether_dev);
+  edev = calloc (1, sizeof (struct ether_device));
+  if (!edev)
+    error (2, ENOMEM, "%s", name);
+  edev->next = ether_dev;
+  ether_dev = edev;
 
-  ether_dev.name = strdup (name);
+  *device = dev = &edev->dev;
 
+  dev->name = strdup (name);
   /* Functions.  These ones are the true "hardware layer" in Linux.  */
-  ether_dev.open = 0;          /* We set up before calling dev_open.  */
-  ether_dev.stop = ethernet_stop;
-  ether_dev.hard_start_xmit = ethernet_xmit;
-  ether_dev.get_stats = ethernet_get_stats;
-  ether_dev.set_multicast_list = ethernet_set_multi;
+  dev->open = 0;               /* We set up before calling dev_open.  */
+  dev->stop = ethernet_stop;
+  dev->hard_start_xmit = ethernet_xmit;
+  dev->get_stats = ethernet_get_stats;
+  dev->set_multicast_list = ethernet_set_multi;
 
   /* These are the ones set by drivers/net/net_init.c::ether_setup.  */
-  ether_dev.hard_header = eth_header;
-  ether_dev.rebuild_header = eth_rebuild_header;
-  ether_dev.hard_header_cache = eth_header_cache;
-  ether_dev.header_cache_update = eth_header_cache_update;
-  ether_dev.hard_header_parse = eth_header_parse;
+  dev->hard_header = eth_header;
+  dev->rebuild_header = eth_rebuild_header;
+  dev->hard_header_cache = eth_header_cache;
+  dev->header_cache_update = eth_header_cache_update;
+  dev->hard_header_parse = eth_header_parse;
   /* We can't do these two (and we never try anyway).  */
-  /* ether_dev.change_mtu = eth_change_mtu; */
-  /* ether_dev.set_mac_address = eth_mac_addr; */
+  /* dev->change_mtu = eth_change_mtu; */
+  /* dev->set_mac_address = eth_mac_addr; */
 
   /* Some more fields */
-  ether_dev.type = ARPHRD_ETHER;
-  ether_dev.hard_header_len = ETH_HLEN;
-  ether_dev.addr_len = ETH_ALEN;
-  memset (ether_dev.broadcast, 0xff, ETH_ALEN);
-  ether_dev.flags = IFF_BROADCAST | IFF_MULTICAST;
-  dev_init_buffers (&ether_dev);
+  dev->type = ARPHRD_ETHER;
+  dev->hard_header_len = ETH_HLEN;
+  dev->addr_len = ETH_ALEN;
+  memset (dev->broadcast, 0xff, ETH_ALEN);
+  dev->flags = IFF_BROADCAST | IFF_MULTICAST;
+  dev_init_buffers (dev);
 
-  ethernet_open (&ether_dev);
+  ethernet_open (dev);
 
   /* Fetch hardware information */
   count = NET_STATUS_COUNT;
-  err = device_get_status (ether_port, NET_STATUS,
+  err = device_get_status (edev->ether_port, NET_STATUS,
                           (dev_status_t) &netstat, &count);
   if (err)
     error (2, err, "%s: Cannot get device status", name);
-  ether_dev.mtu = netstat.max_packet_size - ether_dev.hard_header_len;
+  dev->mtu = netstat.max_packet_size - dev->hard_header_len;
   assert (netstat.header_format == HDR_ETHERNET);
   assert (netstat.header_size == ETH_HLEN);
   assert (netstat.address_size == ETH_ALEN);
 
   count = 2;
   assert (count * sizeof (int) >= ETH_ALEN);
-  err = device_get_status (ether_port, NET_ADDRESS, net_address, &count);
+  err = device_get_status (edev->ether_port, NET_ADDRESS, net_address, &count);
   if (err)
     error (2, err, "%s: Cannot get hardware Ethernet address", name);
   net_address[0] = ntohl (net_address[0]);
   net_address[1] = ntohl (net_address[1]);
-  bcopy (net_address, ether_dev.dev_addr, ETH_ALEN);
+  bcopy (net_address, dev->dev_addr, ETH_ALEN);
 
   /* That should be enough.  */
 
   /* This call adds the device to the `dev_base' chain,
      initializes its `ifindex' member (which matters!),
      and tells the protocol stacks about the device.  */
-  err = - register_netdevice (&ether_dev);
+  err = - register_netdevice (dev);
   assert_perror (err);
 }
diff -x CVS -Nru gnu/cvs/hurd/pfinet/main.c gnu/hurd/hurd/hurd-20000921/pfinet/main.c
--- gnu/cvs/hurd/pfinet/main.c  Sat Sep 30 23:21:56 2000
+++ gnu/hurd/hurd/hurd-20000921/pfinet/main.c   Sun Oct  1 15:58:33 2000
@@ -126,48 +126,77 @@
   mach_port_deallocate (mach_task_self (), initport);
 }
 
-static char *already_open = 0;
 
-/* Return an open device called NAME.  If NMAE is 0, and there is a single
-   active device, it is returned, otherwise an error.
-   XXX hacky single-interface version. */
+/* Return an open device called NAME.  If NAME is 0, and there is a single
+   active device, it is returned, otherwise an error.  */
 error_t
 find_device (char *name, struct device **device)
 {
-  if (already_open)
-    if (!name || strcmp (already_open, (*device)->name) == 0)
+  struct device *dev = dev_base;
+
+  /* Skip loopback interface. */
+  assert (dev);
+  dev = dev->next;
+
+  if (!name)
+    {
+      if (dev)
+       {
+         if (dev->next)
+           return EBUSY;       /* XXXACK */
+         else
+           {
+             *device = dev;
+             return 0;
+           }
+       }
+      else
+       return ENXIO;           /* XXX */
+    }
+
+  for (; dev; dev = dev->next)
+    if (strcmp (dev->name, name) == 0)
       {
-       *device = &ether_dev;
+       *device = dev;
        return 0;
       }
-    else
-      return EBUSY;            /* XXXACK */
-  else if (! name)
-    return ENXIO;              /* XXX */
-
-  name = already_open = strdup (name);
 
-  setup_ethernet_device (name);
+  if (strncmp(name, "dummy", 5) == 0)
+    {
+      setup_dummy_device (name, device);
+    }
+  else
+    {
+      setup_ethernet_device (name, device);
+    }
 
   /* Turn on device. */
-  dev_open (&ether_dev);
-
-  *device = &ether_dev;
+  dev_open (*device);
 
   return 0;
 }
 
 /* Call FUN with each active device.  If a call to FUN returns a
    non-zero value, this function will return immediately.  Otherwise 0 is
-   returned.
-   XXX hacky single-interface version.  */
+   returned.  */
 error_t
 enumerate_devices (error_t (*fun) (struct device *dev))
 {
-  if (already_open)
-    return (*fun) (&ether_dev);
-  else
-    return 0;
+  error_t err;
+  struct device *dev = dev_base;
+
+  /* Skip loopback device.  */
+  assert (dev);
+  dev = dev->next;
+
+  for (; dev; dev = dev->next)
+    {
+      err = (*fun) (dev);
+      if (err)
+       return err;
+    }
+
+  return 0;
 }
 
 extern void sk_init (void), skb_init (void);
diff -x CVS -Nru gnu/cvs/hurd/pfinet/pfinet.h 
gnu/hurd/hurd/hurd-20000921/pfinet/pfinet.h
--- gnu/cvs/hurd/pfinet/pfinet.h        Wed Feb  9 22:59:19 2000
+++ gnu/hurd/hurd/hurd-20000921/pfinet/pfinet.h Sun Oct  1 15:57:06 2000
@@ -36,7 +36,7 @@
 
 mach_port_t fsys_identity;
 
-extern struct device ether_dev;
+extern struct device *dev_base;
 extern struct device loopback_dev;
 
 /* A port on SOCK.  Multiple sock_user's can point to the same socket. */
@@ -56,7 +56,8 @@
 
 void ethernet_initialize (void);
 int ethernet_demuxer (mach_msg_header_t *, mach_msg_header_t *);
-void setup_ethernet_device (char *);
+void setup_ethernet_device (char *, struct device **);
+void setup_dummy_device (char *, struct device **);
 struct sock_user *make_sock_user (struct socket *, int, int, int);
 error_t make_sockaddr_port (struct socket *, int,
                            mach_port_t *, mach_msg_type_name_t *);

Reply via email to