diff options
-rw-r--r-- | pfinet/ChangeLog | 27 | ||||
-rw-r--r-- | pfinet/Makefile | 2 | ||||
-rw-r--r-- | pfinet/dummy.c | 138 | ||||
-rw-r--r-- | pfinet/ethernet.c | 110 | ||||
-rw-r--r-- | pfinet/main.c | 71 | ||||
-rw-r--r-- | pfinet/pfinet.h | 5 |
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 = ðer_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, ðer_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, ðer_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 (ðer_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 (ðer_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 (ðer_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 (ðer_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 = ðer_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 (ðer_dev); - - *device = ðer_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) (ðer_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 *); |