diff options
Diffstat (limited to 'pfinet/loopback.c')
-rw-r--r-- | pfinet/loopback.c | 130 |
1 files changed, 130 insertions, 0 deletions
diff --git a/pfinet/loopback.c b/pfinet/loopback.c new file mode 100644 index 00000000..068cf3c8 --- /dev/null +++ b/pfinet/loopback.c @@ -0,0 +1,130 @@ +/* Loopback "device" for pfinet + Copyright (C) 1996,98,2000 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 this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */ + +#include "pfinet.h" +#include <netinet/in.h> +#include <arpa/inet.h> + +#include <linux/socket.h> +#include <linux/net.h> +#include <linux/inet.h> +#include <linux/netdevice.h> +#include <linux/etherdevice.h> +#include <linux/skbuff.h> +#include <net/sock.h> +#include <linux/if_ether.h> /* For the statistics structure. */ +#include <linux/if_arp.h> /* For ARPHRD_ETHER */ + +#define LOOPBACK_MTU (vm_page_size - 172) + +/* + * The higher levels take care of making this non-reentrant (it's + * called with bh's disabled). + */ +static int loopback_xmit(struct sk_buff *skb, struct device *dev) +{ + struct net_device_stats *stats = (struct net_device_stats *)dev->priv; + + /* + * Take this out if the debug says its ok + */ + + if (skb == NULL || dev == NULL) + printk(KERN_DEBUG "loopback fed NULL data - splat\n"); + + /* + * Optimise so buffers with skb->free=1 are not copied but + * instead are lobbed from tx queue to rx queue + */ + + if(atomic_read(&skb->users) != 1) + { + struct sk_buff *skb2=skb; + skb=skb_clone(skb, GFP_ATOMIC); /* Clone the buffer */ + if(skb==NULL) { + kfree_skb(skb2); + return 0; + } + kfree_skb(skb2); + } + else + skb_orphan(skb); + + skb->protocol=eth_type_trans(skb,dev); + skb->dev=dev; +#ifndef LOOPBACK_MUST_CHECKSUM + skb->ip_summed = CHECKSUM_UNNECESSARY; +#endif + netif_rx(skb); + + stats->rx_bytes+=skb->len; + stats->tx_bytes+=skb->len; + stats->rx_packets++; + stats->tx_packets++; + + return(0); +} + +static struct net_device_stats *get_stats(struct device *dev) +{ + return (struct net_device_stats *)dev->priv; +} + +static int loopback_open(struct device *dev) +{ + dev->flags|=IFF_LOOPBACK; + return 0; +} + +/* Initialize the rest of the LOOPBACK device. */ +static int loopback_init(struct device *dev) +{ + dev->mtu = LOOPBACK_MTU; + dev->tbusy = 0; + dev->hard_start_xmit = loopback_xmit; + dev->hard_header = eth_header; + dev->hard_header_cache = eth_header_cache; + dev->header_cache_update= eth_header_cache_update; + dev->hard_header_len = ETH_HLEN; /* 14 */ + dev->addr_len = ETH_ALEN; /* 6 */ + dev->tx_queue_len = 0; + dev->type = ARPHRD_LOOPBACK; /* 0x0001 */ + dev->rebuild_header = eth_rebuild_header; + dev->open = loopback_open; + dev->flags = IFF_LOOPBACK; + dev->priv = kmalloc(sizeof(struct net_device_stats), GFP_KERNEL); + if (dev->priv == NULL) + return -ENOMEM; + memset(dev->priv, 0, sizeof(struct net_device_stats)); + dev->get_stats = get_stats; + + /* + * Fill in the generic fields of the device structure. + */ + + dev_init_buffers(dev); + + return(0); +} + + +struct device loopback_dev = { name: "lo", init: &loopback_init, }; + +/* It is important magic that this is the first thing on the list. */ +struct device *dev_base = &loopback_dev; |