📄 netproto.c
字号:
/* * linux/drivers/usbd/net_fd/netproto.c - network prototype library * * Copyright (c) 2000, 2001, 2002 Lineo * Copyright (c) 2001 Hewlett Packard * * By: * Stuart Lynne <sl@lineo.com>, * Tom Rushworth <tbr@lineo.com>, * Bruce Balden <balden@lineo.com> * * 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., 675 Mass Ave, Cambridge, MA 02139, USA. * *//* netproto * * This is a simple linux network driver library that is suitable for * implementing layered network drivers. * * E.g. networking over adsl or usb. * */#include <linux/config.h>#include <linux/module.h>#include <linux/init.h>#include <linux/kernel.h>#include <linux/list.h>#include <asm/uaccess.h>#include <linux/netdevice.h>#include <linux/skbuff.h>#include <linux/etherdevice.h>#include <net/arp.h>#include <linux/rtnetlink.h>#include <linux/smp_lock.h>#include <linux/ctype.h>#include <linux/timer.h>#include <linux/string.h>#include <linux/atmdev.h>#include <linux/pkt_sched.h>#include "../usbd-debug.h"#ifndef MODULE#undef GET_USE_COUNT#undef THIS_MODULE#define GET_USE_COUNT(foo) 0#define THIS_MODULE 0#endif/* Debug switches ****************************************************************************** */int dbgflg_usbdfd_pinit = 0;int dbgflg_usbdfd_poc = 0;int dbgflg_usbdfd_prx = 0;int dbgflg_usbdfd_ptx = 0;int dbgflg_usbdfd_pmgmt = 0;static debug_option dbg_table[] = { {&dbgflg_usbdfd_pinit, NULL, "init", "initialization/termination handling"}, {&dbgflg_usbdfd_poc, NULL, "oc", "open/close handling"}, {&dbgflg_usbdfd_prx, NULL, "rx", "receive (from host)"}, {&dbgflg_usbdfd_ptx, NULL, "tx", "transmit (to host)"}, {&dbgflg_usbdfd_pmgmt, NULL, "mgmt", "management (ioctl) handling"}, {NULL, NULL, NULL, NULL}};#define dbg_pinit(lvl,fmt,args...) dbgPRINT(dbgflg_usbdfd_pinit,lvl,fmt,##args)#define dbg_poc(lvl,fmt,args...) dbgPRINT(dbgflg_usbdfd_poc,lvl,fmt,##args)#define dbg_prx(lvl,fmt,args...) dbgPRINT(dbgflg_usbdfd_prx,lvl,fmt,##args)#define dbg_ptx(lvl,fmt,args...) dbgPRINT(dbgflg_usbdfd_ptx,lvl,fmt,##args)#define dbg_pmgmt(lvl,fmt,args...) dbgPRINT(dbgflg_usbdfd_pmgmt,lvl,fmt,##args)debug_option *netproto_get_dbg_table (void){ return (dbg_table);}// This needs to be after the dbg_* macros because of inlines....#include "netproto.h"char *netproto_procname; // name to use for proc filesystemint netproto_devices; // maximum number of interfaces that can be createdstruct netproto_dev **netproto_device_array; // pointer to array of pointers to netproto dev structuresrwlock_t netproto_rwlock = RW_LOCK_UNLOCKED; // lock for netproto device array access/* Network Device support functions *************************************************************** * * net_dev.get_stats = netproto_get_stats; * net_dev.set_mac_address = netproto_set_mac_addr * net_dev.hard_start_xmit = netproto_start_xmit * net_dev.do_ioctl = netproto_do_ioctl * net_dev.set_multicast = netproto_set_multicast // * net_dev.open = netproto_open // tell management thread to start ATM connection * net_dev.stop = netproto_stop // tell management thread to close ATM connection * net_dev.tx_timeout = netproto_tx_timeout // tell the driver that tx has timed out * net_dev.set_config = netproto_set_config // set ATM configuration details *//* * * netproto_init - network device open function * @net_dev: pointer to &struct net_device * * Initialize the device. */static int netproto_init (struct net_device *net_dev){ dbg_pinit (1, "%s", net_dev->name); //if (netif_running(net_dev)) { // return -EBUSY; //} return 0;}/* * * netproto_uninit - network device uninit function * @net_dev: pointer to &struct net_device * * UnInitialize the device. */static void netproto_uninit (struct net_device *net_dev){ dbg_pinit (1, "%s", net_dev->name); return;}/* * * netproto_open - network device open function * @net_dev: pointer to &struct net_device * * Start the device. */static int netproto_open (struct net_device *net_dev){ //struct netproto_dev *dev = net_dev->priv; dbg_poc (1, "%s", net_dev->name); netif_wake_queue (net_dev); dbg_poc (2, "OK %s", net_dev->name); return 0;}/* * * netproto_stop - network device stop function * @net_dev: pointer to &struct net_device * * Stop the device. */static int netproto_stop (struct net_device *net_dev){ //struct netproto_dev *device = net_dev->priv; dbg_poc (1, "%s", net_dev->name); netif_stop_queue (net_dev); return 0;}/* * * netproto_get_stats - network device get stats function * @net_dev: pointer to &struct net_device * * Retreive network device stats structure. */static struct net_device_stats *netproto_get_stats (struct net_device *net_dev){ struct netproto_dev *device = net_dev->priv; return &device->stats;}#if 0/* * * netproto_set_multicast - * @net_dev: pointer to &struct net_device * * Set device to match multicast status */static void netproto_set_multicast (struct net_device *net_dev){ //struct netproto_dev *device = net_dev->priv; if (net_dev->flags & IFF_PROMISC) { // enable promiscuous mode }#if 0 else if ((net_dev->flags & IFF_ALLMULTI) || (net_dev->mc_count > HW_MAX_ADDRS)) { // disable promiscous mode, set filter } else if (net_dev->mc_count) { // walk address list and load filters }#endif else { // disable promiscuous mode } return;}#endif/* * * netproto_set_mac_addr - network device set mac address function * @net_dev: pointer to &struct net_device * @p: pointer to sockaddr structure * * Set mac address. */static int netproto_set_mac_addr (struct net_device *net_dev, void *p){ struct netproto_dev *device = net_dev->priv; struct sockaddr *addr = p; if (netif_running (net_dev)) { return -EBUSY; } { unsigned long flags; write_lock_irqsave (&device->rwlock, flags); memcpy (net_dev->dev_addr, addr->sa_data, net_dev->addr_len); device->addr_set = 1; write_unlock_irqrestore (&device->rwlock, flags); } // push down if (device->set_addr) { device->set_addr (device->interface, p, ETH_ALEN); } return 0;}/* * * netproto_tx_timeout - network device transmit timeout function * @net_dev: pointer to &struct net_device * * Called by network layer to tell the driver that transmit has timed out. */static void netproto_tx_timeout (struct net_device *net_dev){ struct netproto_dev *device = net_dev->priv; dbg_ptx (7, ""); if (device->tx_timeout) { device->tx_timeout (device->interface); }}/* * * netproto_set_config - network device set config function * @net_dev: pointer to &struct net_device * @map: pointer to &struct ifmap * * Only allow things to be set if not running. */static int netproto_set_config (struct net_device *net_dev, struct ifmap *map){ if (netif_running (net_dev)) { return -EBUSY; } if (map->mem_start) { net_dev->mem_start = map->mem_start; } if (map->irq) { net_dev->irq = map->irq; } if (map->base_addr) { net_dev->base_addr = map->base_addr; } // XXX copy to device return 0;}/* * * netproto_change_mtu - network device set config function * @net_dev: pointer to &struct net_device * @mtu: max transmission unit * * Set MTU, if running we can only change it to something less * than or equal to MTU when PVC opened. */static int netproto_change_mtu (struct net_device *net_dev, int mtu){ struct netproto_dev *dev = net_dev->priv; if (netif_running (net_dev)) { if (mtu > dev->mtu) { return -EBUSY; } net_dev->mtu = mtu; return 0; } net_dev->mtu = mtu; // XXX copy to device return 0;}/* * * netproto_start_xmit - network device start xmit function * @skb: pointer to &struct sk_buff to send * @net_dev: pointer to &struct net_device * * Called by kernel network layer to transmit a frame on this interface, * grab locks and pass to netproto_do_xmit(). * * The network layer flow control is managed to prevent more than * device->max_queue_entries from being outstanding. See also * netproto_done(). * * */static int netproto_start_xmit (struct sk_buff *skb, struct net_device *net_dev){ struct netproto_dev *device = net_dev->priv; int len = skb->len; int rc; dbg_ptx (7, ""); dbg_ptx (7, "skb: %p", skb); if (!netif_carrier_ok (net_dev)) { dbg_ptx (0, "no carrier %p", skb); dev_kfree_skb_any (skb); //netif_stop_queue(net_dev); return 0; } // stop queue, it will be restart only when we are ready for another skb netif_stop_queue (net_dev); // lock and update some stats { unsigned long flags; write_lock_irqsave (&device->rwlock, flags); device->stopped++; device->queued_entries++; device->queued_bytes += skb->len; write_unlock_irqrestore (&device->rwlock, flags); } // Set the timestamp for tx timeout net_dev->trans_start = jiffies; // XXX should we use skb->stamp here *(time_t *) (&skb->cb) = jiffies;#if 0 dbg_ptx (7, "skb: %p head: %p data: %p tail: %p len: %d", skb, skb->head, skb->data, skb->tail, skb->len); dbgPRINTmem (dbgflg_usbdfd_ptx, 7, skb->data, skb->len);#endif // push it down to next layer, handle results if ((rc = device->xmit_skb (device->interface, skb))) { switch (rc) { case -EINVAL: case -EUNATCH: dbg_ptx (0, "not attached, send failed: %d", rc); netproto_tx_carrier_errors (device->interface); netif_wake_queue (net_dev); break; case -ENOMEM: dbg_ptx (0, "no mem, send failed: %d", rc); netproto_tx_fifo_errors (device->interface); netif_wake_queue (net_dev); break; case -ECOMM: dbg_ptx (0, "comm failure, send failed: %d %p", rc, net_dev); netproto_tx_dropped (device->interface); break; } dev_kfree_skb_any (skb); } else { // possibly restart queue netproto_tx_packets (device->interface, len); { read_lock (&device->rwlock); if ((device->queued_entries < device->max_queue_entries) && (device->queued_bytes < device->max_queue_bytes)) { read_unlock (&device->rwlock); netif_wake_queue (net_dev); } read_unlock (&device->rwlock); } } return 0;}/* Ioctl support functions ************************************************************************ *//* ** netproto_do_ioctl - network device do_ioctl function* @net_dev: pointer to &struct net_device * @rp: pointer to &struct ifreq* @cmd: ioctl cmd* * This handles ioctls actually performed on our device - we must return* -ENOIOCTLCMD for any unrecognized ioctl */static int netproto_do_ioctl (struct net_device *net_dev, struct ifreq *rp, int cmd){ //int rc; dbg_pmgmt (1, "%s cmd=%d", net_dev->name, cmd); return -ENOIOCTLCMD;}/* Proc Filesystem support ********************************************************************* *//* ** netproto_proc_read - implement proc file system read.* @file: file* @buf: buffer* @count: character count* @pos: file position** Standard proc file system read function.** We let upper layers iterate for us, *pos will indicate which device to return* statistics for. */static ssize_t netproto_proc_read (struct file *file, char *buf, size_t count, loff_t * pos){ unsigned long page; int len = 0; int index; struct netproto_dev *dev; int i; // get a page, max 4095 bytes of data... if (!(page = get_free_page (GFP_ATOMIC))) { return -ENOMEM; } len = 0; index = (*pos)++; if (index == 0) { len += sprintf ((char *) page + len, " MAC ESI VCC Skbs Forwarded " "Stopped Deferred TimeInQ uS Avg Q QueueLen MaxQ Conn\n"); len += sprintf ((char *) page + len, "%48slo hi lpkt:cel hpkt:cel lo hi lo hi lo hi\n", ""); } // lock and iterate across devices to get access to N'th device, return it's stats read_lock (&netproto_rwlock); for (i = 0; i < netproto_devices; i++) { dev = netproto_device_array[i]; if (index-- == 0) { // max 4095 bytes of data... len += sprintf ((char *) page + len, "%.16s %2d [%02X:%02X:%02X:%02X:%02X:%02X]", dev->net_dev->name, dev->interface, dev->net_dev->dev_addr[0], dev->net_dev->dev_addr[1], dev->net_dev->dev_addr[2], dev->net_dev->dev_addr[3], dev->net_dev->dev_addr[4], dev->net_dev->dev_addr[5]); len += sprintf ((char *) page + len, " %s ", dev->addr_mac ? "y" : "n"); len += sprintf ((char *) page + len, "[%02d.%02d.%02d]", (int) (dev->net_dev->mem_start >> 24) & 0xff, (int) (dev->net_dev->mem_start >> 16) & 0xff, (int) (dev->net_dev->mem_start) & 0xffff); len += sprintf ((char *) page + len, " [%6d %2d]", dev->stopped, dev->stopped - dev->restarts); len += sprintf ((char *) page + len, " [%4ld]", dev->samples ? ((dev->jiffies * 1000) / dev->samples) : 0); len += sprintf ((char *) page + len, " [%3ld]", dev->samples ? ((dev->avg_queue_entries) / dev->samples) : 0); len += sprintf ((char *) page + len, " [%3d]", dev->queued_entries); len += sprintf ((char *) page + len, " [%3d]", dev->max_queue_entries); len += sprintf ((char *) page + len, "J[%6ld]", dev->jiffies); len += sprintf ((char *) page + len, "S[%6ld]", dev->samples); len += sprintf ((char *) page + len, "\n"); break; } } read_unlock (&netproto_rwlock); if (len > count) { len = -EINVAL; } else if (len > 0 && copy_to_user (buf, (char *) page, len)) { len = -EFAULT; } free_page (page); return len;}static struct file_operations netproto_proc_operations = { read:netproto_proc_read,};/* Library Interface functions ***************************************************************** *//* ** netproto_rx_dropped* @int - network interface* */void netproto_rx_dropped (int interface){ struct netproto_dev *device; if ((interface < netproto_devices) && (device = netproto_device_array[interface])) { device->stats.rx_dropped++;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -