⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 net_kern.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org) and  * James Leu (jleu@mindspring.net). * Copyright (C) 2001 by various other people who didn't put their name here. * Licensed under the GPL. */#include "linux/config.h"#include "linux/kernel.h"#include "linux/netdevice.h"#include "linux/rtnetlink.h"#include "linux/skbuff.h"#include "linux/socket.h"#include "linux/spinlock.h"#include "linux/module.h"#include "linux/init.h"#include "linux/etherdevice.h"#include "linux/list.h"#include "linux/inetdevice.h"#include "linux/ctype.h"#include "linux/bootmem.h"#include "linux/ethtool.h"#include "linux/platform_device.h"#include "asm/uaccess.h"#include "user_util.h"#include "kern_util.h"#include "net_kern.h"#include "net_user.h"#include "mconsole_kern.h"#include "init.h"#include "irq_user.h"#include "irq_kern.h"#define DRIVER_NAME "uml-netdev"static DEFINE_SPINLOCK(opened_lock);LIST_HEAD(opened);static int uml_net_rx(struct net_device *dev){	struct uml_net_private *lp = dev->priv;	int pkt_len;	struct sk_buff *skb;	/* If we can't allocate memory, try again next round. */	skb = dev_alloc_skb(dev->mtu);	if (skb == NULL) {		lp->stats.rx_dropped++;		return 0;	}	skb->dev = dev;	skb_put(skb, dev->mtu);	skb->mac.raw = skb->data;	pkt_len = (*lp->read)(lp->fd, &skb, lp);	if (pkt_len > 0) {		skb_trim(skb, pkt_len);		skb->protocol = (*lp->protocol)(skb);		netif_rx(skb);		lp->stats.rx_bytes += skb->len;		lp->stats.rx_packets++;		return pkt_len;	}	kfree_skb(skb);	return pkt_len;}irqreturn_t uml_net_interrupt(int irq, void *dev_id, struct pt_regs *regs){	struct net_device *dev = dev_id;	struct uml_net_private *lp = dev->priv;	int err;	if(!netif_running(dev))		return(IRQ_NONE);	spin_lock(&lp->lock);	while((err = uml_net_rx(dev)) > 0) ;	if(err < 0) {		printk(KERN_ERR 		       "Device '%s' read returned %d, shutting it down\n", 		       dev->name, err);		dev_close(dev);		goto out;	}	reactivate_fd(lp->fd, UM_ETH_IRQ); out:	spin_unlock(&lp->lock);	return(IRQ_HANDLED);}static int uml_net_open(struct net_device *dev){	struct uml_net_private *lp = dev->priv;	int err;	spin_lock(&lp->lock);	if(lp->fd >= 0){		err = -ENXIO;		goto out;	}	if(!lp->have_mac){ 		dev_ip_addr(dev, &lp->mac[2]); 		set_ether_mac(dev, lp->mac);	}	lp->fd = (*lp->open)(&lp->user);	if(lp->fd < 0){		err = lp->fd;		goto out;	}	err = um_request_irq(dev->irq, lp->fd, IRQ_READ, uml_net_interrupt,			     SA_INTERRUPT | SA_SHIRQ, dev->name, dev);	if(err != 0){		printk(KERN_ERR "uml_net_open: failed to get irq(%d)\n", err);		if(lp->close != NULL) (*lp->close)(lp->fd, &lp->user);		lp->fd = -1;		err = -ENETUNREACH;	}	lp->tl.data = (unsigned long) &lp->user;	netif_start_queue(dev);	/* clear buffer - it can happen that the host side of the interface	 * is full when we get here.  In this case, new data is never queued,	 * SIGIOs never arrive, and the net never works.	 */	while((err = uml_net_rx(dev)) > 0) ; out:	spin_unlock(&lp->lock);	return(err);}static int uml_net_close(struct net_device *dev){	struct uml_net_private *lp = dev->priv;		netif_stop_queue(dev);	spin_lock(&lp->lock);	free_irq(dev->irq, dev);	if(lp->close != NULL)		(*lp->close)(lp->fd, &lp->user);	lp->fd = -1;	spin_unlock(&lp->lock);	return 0;}static int uml_net_start_xmit(struct sk_buff *skb, struct net_device *dev){	struct uml_net_private *lp = dev->priv;	unsigned long flags;	int len;	netif_stop_queue(dev);	spin_lock_irqsave(&lp->lock, flags);	len = (*lp->write)(lp->fd, &skb, lp);	if(len == skb->len) {		lp->stats.tx_packets++;		lp->stats.tx_bytes += skb->len;		dev->trans_start = jiffies;		netif_start_queue(dev);		/* this is normally done in the interrupt when tx finishes */		netif_wake_queue(dev);	} 	else if(len == 0){		netif_start_queue(dev);		lp->stats.tx_dropped++;	}	else {		netif_start_queue(dev);		printk(KERN_ERR "uml_net_start_xmit: failed(%d)\n", len);	}	spin_unlock_irqrestore(&lp->lock, flags);	dev_kfree_skb(skb);	return 0;}static struct net_device_stats *uml_net_get_stats(struct net_device *dev){	struct uml_net_private *lp = dev->priv;	return &lp->stats;}static void uml_net_set_multicast_list(struct net_device *dev){	if (dev->flags & IFF_PROMISC) return;	else if (dev->mc_count)	dev->flags |= IFF_ALLMULTI;	else dev->flags &= ~IFF_ALLMULTI;}static void uml_net_tx_timeout(struct net_device *dev){	dev->trans_start = jiffies;	netif_wake_queue(dev);}static int uml_net_set_mac(struct net_device *dev, void *addr){	struct uml_net_private *lp = dev->priv;	struct sockaddr *hwaddr = addr;	spin_lock(&lp->lock);	memcpy(dev->dev_addr, hwaddr->sa_data, ETH_ALEN);	spin_unlock(&lp->lock);	return(0);}static int uml_net_change_mtu(struct net_device *dev, int new_mtu){	struct uml_net_private *lp = dev->priv;	int err = 0;	spin_lock(&lp->lock);	new_mtu = (*lp->set_mtu)(new_mtu, &lp->user);	if(new_mtu < 0){		err = new_mtu;		goto out;	}	dev->mtu = new_mtu; out:	spin_unlock(&lp->lock);	return err;}static void uml_net_get_drvinfo(struct net_device *dev,				struct ethtool_drvinfo *info){	strcpy(info->driver, DRIVER_NAME);	strcpy(info->version, "42");}static struct ethtool_ops uml_net_ethtool_ops = {	.get_drvinfo	= uml_net_get_drvinfo,	.get_link	= ethtool_op_get_link,};void uml_net_user_timer_expire(unsigned long _conn){#ifdef undef	struct connection *conn = (struct connection *)_conn;	dprintk(KERN_INFO "uml_net_user_timer_expire [%p]\n", conn);	do_connect(conn);#endif}static DEFINE_SPINLOCK(devices_lock);static struct list_head devices = LIST_HEAD_INIT(devices);static struct platform_driver uml_net_driver = {	.driver = {		.name  = DRIVER_NAME,	},};static int driver_registered;static int eth_configure(int n, void *init, char *mac,			 struct transport *transport){	struct uml_net *device;	struct net_device *dev;	struct uml_net_private *lp;	int save, err, size;	size = transport->private_size + sizeof(struct uml_net_private) + 		sizeof(((struct uml_net_private *) 0)->user);	device = kmalloc(sizeof(*device), GFP_KERNEL);	if (device == NULL) {		printk(KERN_ERR "eth_configure failed to allocate uml_net\n");		return(1);	}	memset(device, 0, sizeof(*device));	INIT_LIST_HEAD(&device->list);	device->index = n;	spin_lock(&devices_lock);	list_add(&device->list, &devices);	spin_unlock(&devices_lock);	if (setup_etheraddr(mac, device->mac))		device->have_mac = 1;	printk(KERN_INFO "Netdevice %d ", n);	if (device->have_mac)		printk("(%02x:%02x:%02x:%02x:%02x:%02x) ",		       device->mac[0], device->mac[1],		       device->mac[2], device->mac[3],		       device->mac[4], device->mac[5]);	printk(": ");	dev = alloc_etherdev(size);	if (dev == NULL) {		printk(KERN_ERR "eth_configure: failed to allocate device\n");		return 1;	}	/* sysfs register */	if (!driver_registered) {		platform_driver_register(&uml_net_driver);		driver_registered = 1;	}	device->pdev.id = n;	device->pdev.name = DRIVER_NAME;	platform_device_register(&device->pdev);	SET_NETDEV_DEV(dev,&device->pdev.dev);	/* If this name ends up conflicting with an existing registered	 * netdevice, that is OK, register_netdev{,ice}() will notice this	 * and fail.	 */	snprintf(dev->name, sizeof(dev->name), "eth%d", n);	device->dev = dev;	(*transport->kern->init)(dev, init);	dev->mtu = transport->user->max_packet;	dev->open = uml_net_open;	dev->hard_start_xmit = uml_net_start_xmit;	dev->stop = uml_net_close;	dev->get_stats = uml_net_get_stats;	dev->set_multicast_list = uml_net_set_multicast_list;	dev->tx_timeout = uml_net_tx_timeout;	dev->set_mac_address = uml_net_set_mac;	dev->change_mtu = uml_net_change_mtu;	dev->ethtool_ops = &uml_net_ethtool_ops;	dev->watchdog_timeo = (HZ >> 1);	dev->irq = UM_ETH_IRQ;	rtnl_lock();	err = register_netdevice(dev);	rtnl_unlock();	if (err) {		device->dev = NULL;		/* XXX: should we call ->remove() here? */		free_netdev(dev);		return 1;	}	lp = dev->priv;	/* lp.user is the first four bytes of the transport data, which	 * has already been initialized.  This structure assignment will	 * overwrite that, so we make sure that .user gets overwritten with	 * what it already has.	 */	save = lp->user[0];	*lp = ((struct uml_net_private)		{ .list  		= LIST_HEAD_INIT(lp->list),		  .dev 			= dev,		  .fd 			= -1,		  .mac 			= { 0xfe, 0xfd, 0x0, 0x0, 0x0, 0x0},		  .have_mac 		= device->have_mac,		  .protocol 		= transport->kern->protocol,		  .open 		= transport->user->open,		  .close 		= transport->user->close,		  .remove 		= transport->user->remove,		  .read 		= transport->kern->read,		  .write 		= transport->kern->write,		  .add_address 		= transport->user->add_address,		  .delete_address  	= transport->user->delete_address,		  .set_mtu 		= transport->user->set_mtu,		  .user  		= { save } });	init_timer(&lp->tl);	spin_lock_init(&lp->lock);	lp->tl.function = uml_net_user_timer_expire;	if (lp->have_mac)		memcpy(lp->mac, device->mac, sizeof(lp->mac));	if (transport->user->init) 		(*transport->user->init)(&lp->user, dev);	if (device->have_mac)		set_ether_mac(dev, device->mac);	spin_lock(&opened_lock);	list_add(&lp->list, &opened);	spin_unlock(&opened_lock);	return(0);}static struct uml_net *find_device(int n){	struct uml_net *device;	struct list_head *ele;	spin_lock(&devices_lock);	list_for_each(ele, &devices){		device = list_entry(ele, struct uml_net, list);		if(device->index == n)			goto out;	}	device = NULL; out:	spin_unlock(&devices_lock);	return(device);}static int eth_parse(char *str, int *index_out, char **str_out){	char *end;	int n;	n = simple_strtoul(str, &end, 0);	if(end == str){		printk(KERN_ERR "eth_setup: Failed to parse '%s'\n", str);		return(1);	}	if(n < 0){		printk(KERN_ERR "eth_setup: device %d is negative\n", n);		return(1);	}	str = end;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -