summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarcus Brinkmann <marcus@gnu.org>2000-10-04 01:59:03 +0000
committerMarcus Brinkmann <marcus@gnu.org>2000-10-04 01:59:03 +0000
commit898424326fc1188384f67963ab6789f18dd57fd3 (patch)
treea4085609a66d34f0f0a59647ed236e64d3aa9bfc
parentb81d9ec23532ba8b2519ba3b8bf68fcfeb0260c5 (diff)
2000-10-04 Marcus Brinkmann <marcus@gnu.org>
* 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. Use dev->priv to find correct edev. Use members of edev instead global variables. (ethernet_xmit): New variable edev. Use dev->priv to find correct edev.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.
-rw-r--r--pfinet/ChangeLog27
-rw-r--r--pfinet/Makefile2
-rw-r--r--pfinet/dummy.c138
-rw-r--r--pfinet/ethernet.c110
-rw-r--r--pfinet/main.c71
-rw-r--r--pfinet/pfinet.h5
6 files changed, 283 insertions, 70 deletions
diff --git a/pfinet/ChangeLog b/pfinet/ChangeLog
index f5672462..5a39b20e 100644
--- a/pfinet/ChangeLog
+++ b/pfinet/ChangeLog
@@ -1,3 +1,30 @@
+2000-10-04 Marcus Brinkmann <marcus@gnu.org>
+
+ * 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. Use dev->priv to find correct
+ edev. Use members of edev instead global variables.
+ (ethernet_xmit): New variable edev. Use dev->priv to find correct
+ edev.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.
+
2000-09-30 Marcus Brinkmann <marcus@gnu.org>
* main.c: Prototype configure_device to supress compiler warning.
diff --git a/pfinet/Makefile b/pfinet/Makefile
index 81e76480..c15321be 100644
--- a/pfinet/Makefile
+++ b/pfinet/Makefile
@@ -61,7 +61,7 @@ ipv4-srcs := af_inet.c \
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 --git a/pfinet/dummy.c b/pfinet/dummy.c
new file mode 100644
index 00000000..523b218f
--- /dev/null
+++ b/pfinet/dummy.c
@@ -0,0 +1,138 @@
+/*
+ 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;
+ struct net_device_stats stats;
+};
+
+/* Linked list of all dummy devices. */
+struct dummy_device *dummy_dev;
+
+struct net_device_stats *
+dummy_get_stats (struct device *dev)
+{
+ struct dummy_device *ddev = (struct dummy_device *) dev->priv;
+ return &ddev->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 dummy_device *ddev = (struct dummy_device *) dev->priv;
+
+ ddev->stats.tx_packets++;
+ ddev->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 = ddev;
+ 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 --git a/pfinet/ethernet.c b/pfinet/ethernet.c
index 1b81e1aa..f6e50a2c 100644
--- a/pfinet/ethernet.c
+++ b/pfinet/ethernet.c
@@ -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 @@ ethernet_demuxer (mach_msg_header_t *inp,
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 @@ ethernet_demuxer (mach_msg_header_t *inp,
__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 @@ ethernet_demuxer (mach_msg_header_t *inp,
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,29 @@ ethernet_open (struct device *dev)
{
error_t err;
device_t master_device;
+ struct ether_device *edev = (struct ether_device *) dev->priv;
- assert (ether_port == MACH_PORT_NULL);
+ 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)
@@ -168,10 +181,11 @@ ethernet_open (struct device *dev)
int
ethernet_xmit (struct sk_buff *skb, struct device *dev)
{
- u_int count;
error_t err;
+ struct ether_device *edev = (struct ether_device *) dev->priv;
+ u_int count;
- 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 +193,77 @@ ethernet_xmit (struct sk_buff *skb, struct device *dev)
}
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->priv = edev; /* For reverse lookup. */
+ 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 --git a/pfinet/main.c b/pfinet/main.c
index d85b5ff1..591192ac 100644
--- a/pfinet/main.c
+++ b/pfinet/main.c
@@ -126,48 +126,73 @@ arrange_shutdown_notification ()
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 --git a/pfinet/pfinet.h b/pfinet/pfinet.h
index 35c76570..2352be70 100644
--- a/pfinet/pfinet.h
+++ b/pfinet/pfinet.h
@@ -36,7 +36,7 @@ struct port_class *socketport_class;
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 @@ struct sock_addr
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 *);