net_kern.c

来自「优龙2410linux2.6.8内核源代码」· C语言 代码 · 共 869 行 · 第 1/2 页

C
869
字号
/* * 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 "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"static spinlock_t opened_lock = SPIN_LOCK_UNLOCKED;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. */	if ((skb = dev_alloc_skb(dev->mtu)) == 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;}void 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;	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);}static int uml_net_open(struct net_device *dev){	struct uml_net_private *lp = dev->priv;	char addr[sizeof("255.255.255.255\0")];	int err;	spin_lock(&lp->lock);	if(lp->fd >= 0){		err = -ENXIO;		goto out;	}	if(!lp->have_mac){ 		dev_ip_addr(dev, addr, &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);	spin_lock(&opened_lock);	list_add(&lp->list, &opened);	spin_unlock(&opened_lock); 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_lock(&opened_lock);	list_del(&lp->list);	spin_unlock(&opened_lock);	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 int uml_net_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd){	return(-EINVAL);}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}/* * default do nothing hard header packet routines for struct net_device init. * real ethernet transports will overwrite with real routines. */static int uml_net_hard_header(struct sk_buff *skb, struct net_device *dev,                 unsigned short type, void *daddr, void *saddr, unsigned len){	return(0); /* no change */}static int uml_net_rebuild_header(struct sk_buff *skb){	return(0); /* ignore */ }static int uml_net_header_cache(struct neighbour *neigh, struct hh_cache *hh){	return(-1); /* fail */}static void uml_net_header_cache_update(struct hh_cache *hh,                 struct net_device *dev, unsigned char * haddr){	/* ignore */}static int uml_net_header_parse(struct sk_buff *skb, unsigned char *haddr){	return(0); /* nothing */}static spinlock_t devices_lock = SPIN_LOCK_UNLOCKED;static struct list_head devices = LIST_HEAD_INIT(devices);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 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;	}	/* 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;        dev->hard_header = uml_net_hard_header;        dev->rebuild_header = uml_net_rebuild_header;        dev->hard_header_cache = uml_net_header_cache;        dev->header_cache_update= uml_net_header_cache_update;        dev->hard_header_parse = uml_net_header_parse;	(*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->do_ioctl = uml_net_ioctl;	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;	INIT_LIST_HEAD(&lp->list);	spin_lock_init(&lp->lock);	lp->dev = dev;	lp->fd = -1;	lp->mac = { 0xfe, 0xfd, 0x0, 0x0, 0x0, 0x0 };	lp->have_mac = device->have_mac;	lp->protocol = transport->kern->protocol;	lp->open = transport->user->open;	lp->close = transport->user->close;	lp->remove = transport->user->remove;	lp->read = transport->kern->read;	lp->write = transport->kern->write;	lp->add_address = transport->user->add_address;	lp->delete_address = transport->user->delete_address;	lp->set_mtu = transport->user->set_mtu;	init_timer(&lp->tl);	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);	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;	if(*str != '='){		printk(KERN_ERR 		       "eth_setup: expected '=' after device number\n");		return(1);	}	str++;	if(find_device(n)){		printk(KERN_ERR "eth_setup: Device %d already configured\n",

⌨️ 快捷键说明

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