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

📄 dev.c

📁 GNU Mach 微内核源代码, 基于美国卡内基美隆大学的 Mach 研究项目
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * 	NET3	Protocol independent device support routines. * *		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. * *	Derived from the non IP parts of dev.c 1.0.19 * 		Authors:	Ross Biro, <bir7@leland.Stanford.Edu> *				Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG> *				Mark Evans, <evansmp@uhura.aston.ac.uk> * *	Additional Authors: *		Florian la Roche <rzsfl@rz.uni-sb.de> *		Alan Cox <gw4pts@gw4pts.ampr.org> *		David Hinds <dhinds@allegro.stanford.edu> * *	Changes: *		Alan Cox	:	device private ioctl copies fields back. *		Alan Cox	:	Transmit queue code does relevant stunts to *					keep the queue safe. *		Alan Cox	:	Fixed double lock. *		Alan Cox	:	Fixed promisc NULL pointer trap *		????????	:	Support the full private ioctl range *		Alan Cox	:	Moved ioctl permission check into drivers *		Tim Kordas	:	SIOCADDMULTI/SIOCDELMULTI *		Alan Cox	:	100 backlog just doesn't cut it when *					you start doing multicast video 8) *		Alan Cox	:	Rewrote net_bh and list manager. *		Alan Cox	: 	Fix ETH_P_ALL echoback lengths. *		Alan Cox	:	Took out transmit every packet pass *					Saved a few bytes in the ioctl handler *		Alan Cox	:	Network driver sets packet type before calling netif_rx. Saves *					a function call a packet. *		Alan Cox	:	Hashed net_bh() *		Richard Kooijman:	Timestamp fixes. *		Alan Cox	:	Wrong field in SIOCGIFDSTADDR *		Alan Cox	:	Device lock protection. *		Alan Cox	: 	Fixed nasty side effect of device close changes. *		Rudi Cilibrasi	:	Pass the right thing to set_mac_address() *		Dave Miller	:	32bit quantity for the device lock to make it work out *					on a Sparc. *		Bjorn Ekwall	:	Added KERNELD hack. *		Alan Cox	:	Cleaned up the backlog initialise. *		Craig Metz	:	SIOCGIFCONF fix if space for under *					1 device. *	    Thomas Bogendoerfer :	Return ENODEV for dev_open, if there *					is no device open function. *	    Lawrence V. Stefani	:	Changed set MTU ioctl to not assume *					min MTU of 68 bytes for devices *					that have change MTU functions. * */#include <asm/segment.h>#include <asm/system.h>#include <asm/bitops.h>#include <linux/config.h>#include <linux/types.h>#include <linux/kernel.h>#include <linux/sched.h>#include <linux/string.h>#include <linux/mm.h>#include <linux/socket.h>#include <linux/sockios.h>#include <linux/in.h>#include <linux/errno.h>#include <linux/interrupt.h>#include <linux/if_ether.h>#include <linux/inet.h>#include <linux/netdevice.h>#include <linux/etherdevice.h>#include <linux/notifier.h>#include <net/ip.h>#include <net/route.h>#include <linux/skbuff.h>#include <net/sock.h>#include <net/arp.h>#include <net/slhc.h>#include <linux/proc_fs.h>#include <linux/stat.h>#include <net/br.h>#ifdef CONFIG_NET_ALIAS#include <linux/net_alias.h>#endif#ifdef CONFIG_KERNELD#include <linux/kerneld.h>#endif#ifdef CONFIG_NET_RADIO#include <linux/wireless.h>#endif	/* CONFIG_NET_RADIO */#ifndef MACH/* *	The list of packet types we will receive (as opposed to discard) *	and the routines to invoke. */struct packet_type *ptype_base[16];struct packet_type *ptype_all = NULL;		/* Taps *//* *	Device list lock */ int dev_lockct=0; /* *	Our notifier list */ struct notifier_block *netdev_chain=NULL;/* *	Device drivers call our routines to queue packets here. We empty the *	queue in the bottom half handler. */static struct sk_buff_head backlog;/*  *	We don't overdo the queue or we will thrash memory badly. */ static int backlog_size = 0;/* *	Return the lesser of the two values.  */ static __inline__ unsigned long min(unsigned long a, unsigned long b){	return (a < b)? a : b;}/******************************************************************************************		Protocol management and registration routines*******************************************************************************************//* *	For efficiency */static int dev_nit=0;/* *	Add a protocol ID to the list. Now that the input handler is *	smarter we can dispense with all the messy stuff that used to be *	here. */ void dev_add_pack(struct packet_type *pt){	int hash;	if(pt->type==htons(ETH_P_ALL))	{		dev_nit++;		pt->next=ptype_all;		ptype_all=pt;	}	else	{			hash=ntohs(pt->type)&15;		pt->next = ptype_base[hash];		ptype_base[hash] = pt;	}}/* *	Remove a protocol ID from the list. */ void dev_remove_pack(struct packet_type *pt){	struct packet_type **pt1;	if(pt->type==htons(ETH_P_ALL))	{		dev_nit--;		pt1=&ptype_all;	}	else		pt1=&ptype_base[ntohs(pt->type)&15];	for(; (*pt1)!=NULL; pt1=&((*pt1)->next))	{		if(pt==(*pt1))		{			*pt1=pt->next;			return;		}	}	printk(KERN_WARNING "dev_remove_pack: %p not found.\n", pt);}/*****************************************************************************************			    Device Interface Subroutines******************************************************************************************//*  *	Find an interface by name. */ struct device *dev_get(const char *name){	struct device *dev;	for (dev = dev_base; dev != NULL; dev = dev->next) 	{		if (strcmp(dev->name, name) == 0)			return(dev);	}	return NULL;}	/* *	Find and possibly load an interface. */ #ifdef CONFIG_KERNELDextern __inline__ void dev_load(const char *name){	if(!dev_get(name) && suser()) {#ifdef CONFIG_NET_ALIAS		const char *sptr; 		for (sptr=name ; *sptr ; sptr++) if(*sptr==':') break;		if (!(*sptr && *(sptr+1)))#endif		request_module(name);	}}#endif /* *	Prepare an interface for use.  */ int dev_open(struct device *dev){	int ret = -ENODEV;	/*	 *	Call device private open method	 */	if (dev->open)   		ret = dev->open(dev);	/*	 *	If it went open OK then set the flags	 */	 	if (ret == 0) 	{		dev->flags |= (IFF_UP | IFF_RUNNING);		/*		 *	Initialise multicasting status 		 */		dev_mc_upload(dev);		notifier_call_chain(&netdev_chain, NETDEV_UP, dev);	}	return(ret);}/* *	Completely shutdown an interface. */ int dev_close(struct device *dev){	int ct=0;	/*	 *	Call the device specific close. This cannot fail.	 *	Only if device is UP	 */	 	if ((dev->flags & IFF_UP) && dev->stop)		dev->stop(dev);	/*	 *	Device is now down.	 */	 	dev->flags&=~(IFF_UP|IFF_RUNNING);	/*	 *	Tell people we are going down	 */	notifier_call_chain(&netdev_chain, NETDEV_DOWN, dev);	/*	 *	Flush the multicast chain	 */	dev_mc_discard(dev);	/*	 *	Purge any queued packets when we down the link 	 */	while(ct<DEV_NUMBUFFS)	{		struct sk_buff *skb;		while((skb=skb_dequeue(&dev->buffs[ct]))!=NULL)			if(skb->free)				kfree_skb(skb,FREE_WRITE);		ct++;	}	return(0);}/* *	Device change register/unregister. These are not inline or static *	as we export them to the world. */int register_netdevice_notifier(struct notifier_block *nb){	return notifier_chain_register(&netdev_chain, nb);}int unregister_netdevice_notifier(struct notifier_block *nb){	return notifier_chain_unregister(&netdev_chain,nb);}/* *	Send (or queue for sending) a packet.  * *	IMPORTANT: When this is called to resend frames. The caller MUST *	already have locked the sk_buff. Apart from that we do the *	rest of the magic. */static void do_dev_queue_xmit(struct sk_buff *skb, struct device *dev, int pri){	unsigned long flags;	struct sk_buff_head *list;	int retransmission = 0;	/* used to say if the packet should go	*/				/* at the front or the back of the	*/				/* queue - front is a retransmit try	*/	if(pri>=0 && !skb_device_locked(skb))		skb_device_lock(skb);	/* Shove a lock on the frame */#if CONFIG_SKB_CHECK 	IS_SKB(skb);#endif    	skb->dev = dev;	/*	 *	Negative priority is used to flag a frame that is being pulled from the	 *	queue front as a retransmit attempt. It therefore goes back on the queue	 *	start on a failure.	 */	   	if (pri < 0)   	{		pri = -pri-1;		retransmission = 1;  	}#ifdef CONFIG_NET_DEBUG	if (pri >= DEV_NUMBUFFS) 	{		printk(KERN_WARNING "bad priority in dev_queue_xmit.\n");		pri = 1;	}#endif	/*	 *	If the address has not been resolved. Call the device header rebuilder.	 *	This can cover all protocols and technically not just ARP either.	 */	 	if (!skb->arp && dev->rebuild_header(skb->data, dev, skb->raddr, skb)) {		return;	}	/*	 *	 * 	If dev is an alias, switch to its main device.	 *	"arp" resolution has been made with alias device, so	 *	arp entries refer to alias, not main.	 *	 */#ifdef CONFIG_NET_ALIAS	if (net_alias_is(dev))	  	skb->dev = dev = net_alias_dev_tx(dev);#endif	/*	 *	If we are bridging and this is directly generated output	 *	pass the frame via the bridge.	 */#ifdef CONFIG_BRIDGE	if(skb->pkt_bridged!=IS_BRIDGED && br_stats.flags & BR_UP)	{		if(br_tx_frame(skb))			return;	}#endif	list = dev->buffs + pri;	save_flags(flags);	/* if this isn't a retransmission, use the first packet instead... */	if (!retransmission) {		if (skb_queue_len(list)) {			/* avoid overrunning the device queue.. */			if (skb_queue_len(list) > dev->tx_queue_len) {				dev_kfree_skb(skb, FREE_WRITE);				return;			}		}		/* copy outgoing packets to any sniffer packet handlers */		if (dev_nit) {			struct packet_type *ptype;			skb->stamp=xtime;			for (ptype = ptype_all; ptype!=NULL; ptype = ptype->next) 			{				/* Never send packets back to the socket				 * they originated from - MvS (miquels@drinkel.ow.org)				 */				if ((ptype->dev == dev || !ptype->dev) &&				   ((struct sock *)ptype->data != skb->sk))				{					struct sk_buff *skb2;					if ((skb2 = skb_clone(skb, GFP_ATOMIC)) == NULL)						break;					/* FIXME?: Wrong when the hard_header_len					 * is an upper bound. Is this even					 * used anywhere?					 */					skb2->h.raw = skb2->data + dev->hard_header_len;					/* On soft header devices we					 * yank the header before mac.raw					 * back off. This is set by					 * dev->hard_header().					 */					if (dev->flags&IFF_SOFTHEADERS)						skb_pull(skb2,skb2->mac.raw-skb2->data);					skb2->mac.raw = skb2->data;					ptype->func(skb2, skb->dev, ptype);				}			}		}		if (skb_queue_len(list)) {			cli();			skb_device_unlock(skb);		/* Buffer is on the device queue and can be freed safely */			__skb_queue_tail(list, skb);			skb = __skb_dequeue(list);			skb_device_lock(skb);		/* New buffer needs locking down */			restore_flags(flags);		}	}	if (dev->hard_start_xmit(skb, dev) == 0) {		/*		 *	Packet is now solely the responsibility of the driver		 */		return;	}	/*	 *	Transmission failed, put skb back into a list. Once on the list it's safe and	 *	no longer device locked (it can be freed safely from the device queue)	 */	cli();	skb_device_unlock(skb);	__skb_queue_head(list,skb);	restore_flags(flags);}void dev_queue_xmit(struct sk_buff *skb, struct device *dev, int pri){	start_bh_atomic();	do_dev_queue_xmit(skb, dev, pri);	end_bh_atomic();}/* *	Receive a packet from a device driver and queue it for the upper *	(protocol) levels.  It always succeeds. This is the recommended  *	interface to use. */void netif_rx(struct sk_buff *skb){	static int dropping = 0;	/*	 *	Any received buffers are un-owned and should be discarded	 *	when freed. These will be updated later as the frames get	 *	owners.	 */	skb->sk = NULL;	skb->free = 1;	if(skb->stamp.tv_sec==0)		skb->stamp = xtime;	/*	 *	Check that we aren't overdoing things.	 */	if (!backlog_size)  		dropping = 0;	else if (backlog_size > 300)		dropping = 1;	if (dropping) 	{		kfree_skb(skb, FREE_READ);		return;	}	/*	 *	Add it to the "backlog" queue. 	 */#if CONFIG_SKB_CHECK	IS_SKB(skb);#endif		skb_queue_tail(&backlog,skb);	backlog_size++;  	/*	 *	If any packet arrived, mark it for processing after the	 *	hardware interrupt returns.	 */	mark_bh(NET_BH);

⌨️ 快捷键说明

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