📄 eth1394.c
字号:
/* * eth1394.c -- Ethernet driver for Linux IEEE-1394 Subsystem * * Copyright (C) 2001-2003 Ben Collins <bcollins@debian.org> * 2000 Bonin Franck <boninf@free.fr> * 2003 Steve Kinneberg <kinnebergsteve@acmsystems.com> * * Mainly based on work by Emanuel Pirker and Andreas E. Bombe * * This program 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 of the License, or * (at your option) any later version. * * This program 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-1307, USA. *//* This driver intends to support RFC 2734, which describes a method for * transporting IPv4 datagrams over IEEE-1394 serial busses. This driver * will ultimately support that method, but currently falls short in * several areas. * * TODO: * RFC 2734 related: * - Add MCAP. Limited Multicast exists only to 224.0.0.1 and 224.0.0.2. * * Non-RFC 2734 related: * - Handle fragmented skb's coming from the networking layer. * - Move generic GASP reception to core 1394 code * - Convert kmalloc/kfree for link fragments to use kmem_cache_* instead * - Stability improvements * - Performance enhancements * - Consider garbage collecting old partial datagrams after X amount of time */#include <linux/module.h>#include <linux/sched.h>#include <linux/kernel.h>#include <linux/slab.h>#include <linux/errno.h>#include <linux/types.h>#include <linux/delay.h>#include <linux/init.h>#include <linux/netdevice.h>#include <linux/inetdevice.h>#include <linux/etherdevice.h>#include <linux/if_arp.h>#include <linux/if_ether.h>#include <linux/ip.h>#include <linux/in.h>#include <linux/tcp.h>#include <linux/skbuff.h>#include <linux/bitops.h>#include <linux/ethtool.h>#include <asm/uaccess.h>#include <asm/delay.h>#include <asm/unaligned.h>#include <net/arp.h>#include "config_roms.h"#include "csr1212.h"#include "eth1394.h"#include "highlevel.h"#include "ieee1394.h"#include "ieee1394_core.h"#include "ieee1394_hotplug.h"#include "ieee1394_transactions.h"#include "ieee1394_types.h"#include "iso.h"#include "nodemgr.h"#define ETH1394_PRINT_G(level, fmt, args...) \ printk(level "%s: " fmt, driver_name, ## args)#define ETH1394_PRINT(level, dev_name, fmt, args...) \ printk(level "%s: %s: " fmt, driver_name, dev_name, ## args)#define DEBUG(fmt, args...) \ printk(KERN_ERR "%s:%s[%d]: " fmt "\n", driver_name, __FUNCTION__, __LINE__, ## args)#define TRACE() printk(KERN_ERR "%s:%s[%d] ---- TRACE\n", driver_name, __FUNCTION__, __LINE__)struct fragment_info { struct list_head list; int offset; int len;};struct partial_datagram { struct list_head list; u16 dgl; u16 dg_size; u16 ether_type; struct sk_buff *skb; char *pbuf; struct list_head frag_info;};struct pdg_list { struct list_head list; /* partial datagram list per node */ unsigned int sz; /* partial datagram list size per node */ spinlock_t lock; /* partial datagram lock */};struct eth1394_host_info { struct hpsb_host *host; struct net_device *dev;};struct eth1394_node_ref { struct unit_directory *ud; struct list_head list;};struct eth1394_node_info { u16 maxpayload; /* Max payload */ u8 sspd; /* Max speed */ u64 fifo; /* FIFO address */ struct pdg_list pdg; /* partial RX datagram lists */ int dgl; /* Outgoing datagram label */};/* Our ieee1394 highlevel driver */#define ETH1394_DRIVER_NAME "eth1394"static const char driver_name[] = ETH1394_DRIVER_NAME;static kmem_cache_t *packet_task_cache;static struct hpsb_highlevel eth1394_highlevel;/* Use common.lf to determine header len */static const int hdr_type_len[] = { sizeof (struct eth1394_uf_hdr), sizeof (struct eth1394_ff_hdr), sizeof (struct eth1394_sf_hdr), sizeof (struct eth1394_sf_hdr)};/* Change this to IEEE1394_SPEED_S100 to make testing easier */#define ETH1394_SPEED_DEF IEEE1394_SPEED_MAX/* For now, this needs to be 1500, so that XP works with us */#define ETH1394_DATA_LEN ETH_DATA_LENstatic const u16 eth1394_speedto_maxpayload[] = {/* S100, S200, S400, S800, S1600, S3200 */ 512, 1024, 2048, 4096, 4096, 4096};MODULE_AUTHOR("Ben Collins (bcollins@debian.org)");MODULE_DESCRIPTION("IEEE 1394 IPv4 Driver (IPv4-over-1394 as per RFC 2734)");MODULE_LICENSE("GPL");/* The max_partial_datagrams parameter is the maximum number of fragmented * datagrams per node that eth1394 will keep in memory. Providing an upper * bound allows us to limit the amount of memory that partial datagrams * consume in the event that some partial datagrams are never completed. */static int max_partial_datagrams = 25;module_param(max_partial_datagrams, int, S_IRUGO | S_IWUSR);MODULE_PARM_DESC(max_partial_datagrams, "Maximum number of partially received fragmented datagrams " "(default = 25).");static int ether1394_header(struct sk_buff *skb, struct net_device *dev, unsigned short type, void *daddr, void *saddr, unsigned len);static int ether1394_rebuild_header(struct sk_buff *skb);static int ether1394_header_parse(struct sk_buff *skb, unsigned char *haddr);static int ether1394_header_cache(struct neighbour *neigh, struct hh_cache *hh);static void ether1394_header_cache_update(struct hh_cache *hh, struct net_device *dev, unsigned char * haddr);static int ether1394_mac_addr(struct net_device *dev, void *p);static void purge_partial_datagram(struct list_head *old);static int ether1394_tx(struct sk_buff *skb, struct net_device *dev);static void ether1394_iso(struct hpsb_iso *iso);static struct ethtool_ops ethtool_ops;static int ether1394_write(struct hpsb_host *host, int srcid, int destid, quadlet_t *data, u64 addr, size_t len, u16 flags);static void ether1394_add_host (struct hpsb_host *host);static void ether1394_remove_host (struct hpsb_host *host);static void ether1394_host_reset (struct hpsb_host *host);/* Function for incoming 1394 packets */static struct hpsb_address_ops addr_ops = { .write = ether1394_write,};/* Ieee1394 highlevel driver functions */static struct hpsb_highlevel eth1394_highlevel = { .name = driver_name, .add_host = ether1394_add_host, .remove_host = ether1394_remove_host, .host_reset = ether1394_host_reset,};/* This is called after an "ifup" */static int ether1394_open (struct net_device *dev){ struct eth1394_priv *priv = netdev_priv(dev); int ret = 0; /* Something bad happened, don't even try */ if (priv->bc_state == ETHER1394_BC_ERROR) { /* we'll try again */ priv->iso = hpsb_iso_recv_init(priv->host, ETHER1394_ISO_BUF_SIZE, ETHER1394_GASP_BUFFERS, priv->broadcast_channel, HPSB_ISO_DMA_PACKET_PER_BUFFER, 1, ether1394_iso); if (priv->iso == NULL) { ETH1394_PRINT(KERN_ERR, dev->name, "Could not allocate isochronous receive " "context for the broadcast channel\n"); priv->bc_state = ETHER1394_BC_ERROR; ret = -EAGAIN; } else { if (hpsb_iso_recv_start(priv->iso, -1, (1 << 3), -1) < 0) priv->bc_state = ETHER1394_BC_STOPPED; else priv->bc_state = ETHER1394_BC_RUNNING; } } if (ret) return ret; netif_start_queue (dev); return 0;}/* This is called after an "ifdown" */static int ether1394_stop (struct net_device *dev){ netif_stop_queue (dev); return 0;}/* Return statistics to the caller */static struct net_device_stats *ether1394_stats (struct net_device *dev){ return &(((struct eth1394_priv *)netdev_priv(dev))->stats);}/* What to do if we timeout. I think a host reset is probably in order, so * that's what we do. Should we increment the stat counters too? */static void ether1394_tx_timeout (struct net_device *dev){ ETH1394_PRINT (KERN_ERR, dev->name, "Timeout, resetting host %s\n", ((struct eth1394_priv *)netdev_priv(dev))->host->driver->name); highlevel_host_reset (((struct eth1394_priv *)netdev_priv(dev))->host); netif_wake_queue (dev);}static int ether1394_change_mtu(struct net_device *dev, int new_mtu){ struct eth1394_priv *priv = netdev_priv(dev); if ((new_mtu < 68) || (new_mtu > min(ETH1394_DATA_LEN, (int)((1 << (priv->host->csr.max_rec + 1)) - (sizeof(union eth1394_hdr) + ETHER1394_GASP_OVERHEAD))))) return -EINVAL; dev->mtu = new_mtu; return 0;}static void purge_partial_datagram(struct list_head *old){ struct partial_datagram *pd = list_entry(old, struct partial_datagram, list); struct list_head *lh, *n; list_for_each_safe(lh, n, &pd->frag_info) { struct fragment_info *fi = list_entry(lh, struct fragment_info, list); list_del(lh); kfree(fi); } list_del(old); kfree_skb(pd->skb); kfree(pd);}/****************************************** * 1394 bus activity functions ******************************************/static struct eth1394_node_ref *eth1394_find_node(struct list_head *inl, struct unit_directory *ud){ struct eth1394_node_ref *node; list_for_each_entry(node, inl, list) if (node->ud == ud) return node; return NULL;}static struct eth1394_node_ref *eth1394_find_node_guid(struct list_head *inl, u64 guid){ struct eth1394_node_ref *node; list_for_each_entry(node, inl, list) if (node->ud->ne->guid == guid) return node; return NULL;}static struct eth1394_node_ref *eth1394_find_node_nodeid(struct list_head *inl, nodeid_t nodeid){ struct eth1394_node_ref *node; list_for_each_entry(node, inl, list) { if (node->ud->ne->nodeid == nodeid) return node; } return NULL;}static int eth1394_probe(struct device *dev){ struct unit_directory *ud; struct eth1394_host_info *hi; struct eth1394_priv *priv; struct eth1394_node_ref *new_node; struct eth1394_node_info *node_info; ud = container_of(dev, struct unit_directory, device); hi = hpsb_get_hostinfo(ð1394_highlevel, ud->ne->host); if (!hi) return -ENOENT; new_node = kmalloc(sizeof(*new_node), in_interrupt() ? GFP_ATOMIC : GFP_KERNEL); if (!new_node) return -ENOMEM; node_info = kmalloc(sizeof(*node_info), in_interrupt() ? GFP_ATOMIC : GFP_KERNEL); if (!node_info) { kfree(new_node); return -ENOMEM; } spin_lock_init(&node_info->pdg.lock); INIT_LIST_HEAD(&node_info->pdg.list); node_info->pdg.sz = 0; node_info->fifo = CSR1212_INVALID_ADDR_SPACE; ud->device.driver_data = node_info; new_node->ud = ud; priv = netdev_priv(hi->dev); list_add_tail(&new_node->list, &priv->ip_node_list); return 0;}static int eth1394_remove(struct device *dev){ struct unit_directory *ud; struct eth1394_host_info *hi; struct eth1394_priv *priv; struct eth1394_node_ref *old_node; struct eth1394_node_info *node_info; struct list_head *lh, *n; unsigned long flags; ud = container_of(dev, struct unit_directory, device); hi = hpsb_get_hostinfo(ð1394_highlevel, ud->ne->host); if (!hi) return -ENOENT; priv = netdev_priv(hi->dev); old_node = eth1394_find_node(&priv->ip_node_list, ud); if (old_node) { list_del(&old_node->list); kfree(old_node); node_info = (struct eth1394_node_info*)ud->device.driver_data; spin_lock_irqsave(&node_info->pdg.lock, flags); /* The partial datagram list should be empty, but we'll just * make sure anyway... */ list_for_each_safe(lh, n, &node_info->pdg.list) { purge_partial_datagram(lh); } spin_unlock_irqrestore(&node_info->pdg.lock, flags); kfree(node_info); ud->device.driver_data = NULL; } return 0;}static int eth1394_update(struct unit_directory *ud){ struct eth1394_host_info *hi; struct eth1394_priv *priv; struct eth1394_node_ref *node; struct eth1394_node_info *node_info; hi = hpsb_get_hostinfo(ð1394_highlevel, ud->ne->host); if (!hi) return -ENOENT; priv = netdev_priv(hi->dev); node = eth1394_find_node(&priv->ip_node_list, ud); if (!node) { node = kmalloc(sizeof(*node), in_interrupt() ? GFP_ATOMIC : GFP_KERNEL); if (!node) return -ENOMEM; node_info = kmalloc(sizeof(*node_info), in_interrupt() ? GFP_ATOMIC : GFP_KERNEL); if (!node_info) { kfree(node); return -ENOMEM; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -