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

📄 dev.c

📁 GNU Hurd 源代码
💻 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> *		Alexey Kuznetsov <kuznet@ms2.inr.ac.ru> *		Adam Sulmicki <adam@cfar.umd.edu> * *	Changes: *		Marcelo Tosatti <marcelo@conectiva.com.br> : dont accept mtu 0 or < *		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. *		Andi Kleen	:	Fix error reporting for SIOCGIFCONF *	    Michael Chastain	:	Fix signed/unsigned for SIOCGIFCONF *		Cyrus Durgin	:	Cleaned for KMOD *		Adam Sulmicki   :	Bug Fix : Network Device Unload *					A network device unload needs to purge *					the backlog queue. *	Paul Rusty Russel	:	SIOCSIFNAME *	Andrea Arcangeli	:	dev_clear_backlog() needs the *					skb_queue_lock held. */#include <asm/uaccess.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/errno.h>#include <linux/interrupt.h>#include <linux/if_ether.h>#include <linux/netdevice.h>#include <linux/etherdevice.h>#include <linux/notifier.h>#include <linux/skbuff.h>#include <net/sock.h>#include <linux/rtnetlink.h>#include <net/slhc.h>#include <linux/proc_fs.h>#include <linux/stat.h>#include <net/br.h>#include <net/dst.h>#include <net/pkt_sched.h>#include <net/profile.h>#include <linux/init.h>#include <linux/kmod.h>#ifdef CONFIG_NET_RADIO#include <linux/wireless.h>#endif	/* CONFIG_NET_RADIO */#ifdef CONFIG_PLIPextern int plip_init(void);#endifNET_PROFILE_DEFINE(dev_queue_xmit)NET_PROFILE_DEFINE(net_bh)NET_PROFILE_DEFINE(net_bh_skb)const char *if_port_text[] = {  "unknown",  "BNC",  "10baseT",  "AUI",  "100baseT",  "100baseTX",  "100baseFX"};/* *	The list of packet types we will receive (as opposed to discard) *	and the routines to invoke. * *	Why 16. Because with 16 the only overlap we get on a hash of the *	low nibble of the protocol value is RARP/SNAP/X.25. * *		0800	IP *		0001	802.3 *		0002	AX.25 *		0004	802.2 *		8035	RARP *		0005	SNAP *		0805	X.25 *		0806	ARP *		8137	IPX *		0009	Localtalk *		86DD	IPv6 */struct packet_type *ptype_base[16];		/* 16 way hashed list */struct packet_type *ptype_all = NULL;		/* Taps *//* *	Device list lock. Setting it provides that interface *	will not disappear unexpectedly while kernel sleeps. */atomic_t dev_lockct = ATOMIC_INIT(0);/* *	Our notifier list */#ifdef _HURD_struct notifier_block *netdev_chain=NULL;#elsestatic struct notifier_block *netdev_chain=NULL;#endif/* *	Device drivers call our routines to queue packets here. We empty the *	queue in the bottom half handler. */static struct sk_buff_head backlog;#ifdef CONFIG_NET_FASTROUTEint netdev_fastroute;int netdev_fastroute_obstacles;struct net_fastroute_stats dev_fastroute_stat;#endifstatic void dev_clear_backlog(struct device *dev);/******************************************************************************************		Protocol management and registration routines*******************************************************************************************//* *	For efficiency */int netdev_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. * *	BEWARE!!! Protocol handlers, mangling input packets, *	MUST BE last in hash buckets and checking protocol handlers *	MUST start from promiscous ptype_all chain in net_bh. *	It is true now, do not change it. *	Explantion follows: if protocol handler, mangling packet, will *	be the first on list, it is not able to sense, that packet *	is cloned and should be copied-on-write, so that it will *	change it and subsequent readers will get broken packet. *							--ANK (980803) */void dev_add_pack(struct packet_type *pt){	int hash;#ifdef CONFIG_NET_FASTROUTE	/* Hack to detect packet socket */	if (pt->data) {		netdev_fastroute_obstacles++;		dev_clear_fastroute(pt->dev);	}#endif	if(pt->type==htons(ETH_P_ALL))	{		netdev_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))	{		netdev_nit--;		pt1=&ptype_all;	}	else		pt1=&ptype_base[ntohs(pt->type)&15];	for(; (*pt1)!=NULL; pt1=&((*pt1)->next))	{		if(pt==(*pt1))		{			*pt1=pt->next;			synchronize_bh();#ifdef CONFIG_NET_FASTROUTE			if (pt->data)				netdev_fastroute_obstacles--;#endif			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;}struct device * dev_get_by_index(int ifindex){	struct device *dev;	for (dev = dev_base; dev != NULL; dev = dev->next)	{		if (dev->ifindex == ifindex)			return(dev);	}	return NULL;}struct device *dev_getbyhwaddr(unsigned short type, char *ha){	struct device *dev;	for (dev = dev_base; dev != NULL; dev = dev->next)	{		if (dev->type == type &&		    memcmp(dev->dev_addr, ha, dev->addr_len) == 0)			return(dev);	}	return(NULL);}/* *	Passed a format string - eg "lt%d" it will try and find a suitable *	id. Not efficient for many devices, not called a lot.. */int dev_alloc_name(struct device *dev, const char *name){	int i;	/*	 *	If you need over 100 please also fix the algorithm...	 */	for(i=0;i<100;i++)	{		sprintf(dev->name,name,i);		if(dev_get(dev->name)==NULL)			return i;	}	return -ENFILE;	/* Over 100 of the things .. bail out! */}struct device *dev_alloc(const char *name, int *err){	struct device *dev=kmalloc(sizeof(struct device)+16, GFP_KERNEL);	if(dev==NULL)	{		*err=-ENOBUFS;		return NULL;	}	dev->name=(char *)(dev+1);	/* Name string space */	*err=dev_alloc_name(dev,name);	if(*err<0)	{		kfree(dev);		return NULL;	}	return dev;}void netdev_state_change(struct device *dev){	if (dev->flags&IFF_UP)		notifier_call_chain(&netdev_chain, NETDEV_CHANGE, dev);}/* *	Find and possibly load an interface. */#ifdef CONFIG_KMODvoid dev_load(const char *name){	if(!dev_get(name) && capable(CAP_SYS_MODULE))		request_module(name);}#elseextern inline void dev_load(const char *unused){;}#endifstatic int default_rebuild_header(struct sk_buff *skb){	printk(KERN_DEBUG "%s: default_rebuild_header called -- BUG!\n", skb->dev ? skb->dev->name : "NULL!!!");	kfree_skb(skb);	return 1;}/* *	Prepare an interface for use. */int dev_open(struct device *dev){	int ret = 0;	/*	 *	Is it already up?	 */	if (dev->flags&IFF_UP)		return 0;	/*	 *	Call device private open method	 */	if (dev->open)  		ret = dev->open(dev);	/*	 *	If it went open OK then:	 */	if (ret == 0)	{		/*		 *	nil rebuild_header routine,		 *	that should be never called and used as just bug trap.		 */		if (dev->rebuild_header == NULL)			dev->rebuild_header = default_rebuild_header;		/*		 *	Set the flags.		 */		dev->flags |= (IFF_UP | IFF_RUNNING);		/*		 *	Initialize multicasting status		 */		dev_mc_upload(dev);		/*		 *	Wakeup transmit queue engine		 */		dev_activate(dev);		/*		 *	... and announce new interface.		 */		notifier_call_chain(&netdev_chain, NETDEV_UP, dev);	}	return(ret);}#ifdef CONFIG_NET_FASTROUTEstatic __inline__ void dev_do_clear_fastroute(struct device *dev){	if (dev->accept_fastpath) {		int i;		for (i=0; i<=NETDEV_FASTROUTE_HMASK; i++)			dst_release_irqwait(xchg(dev->fastpath+i, NULL));	}}void dev_clear_fastroute(struct device *dev){	if (dev) {		dev_do_clear_fastroute(dev);	} else {		for (dev = dev_base; dev; dev = dev->next)			dev_do_clear_fastroute(dev);	}}#endif/* *	Completely shutdown an interface. */int dev_close(struct device *dev){	if (!(dev->flags&IFF_UP))		return 0;	dev_deactivate(dev);	dev_lock_wait();	/*	 *	Call the device specific close. This cannot fail.	 *	Only if device is UP	 */	if (dev->stop)		dev->stop(dev);	if (dev->start)		printk("dev_close: bug %s still running\n", dev->name);	/*	 *	Device is now down.	 */	dev_clear_backlog(dev);	dev->flags&=~(IFF_UP|IFF_RUNNING);#ifdef CONFIG_NET_FASTROUTE	dev_clear_fastroute(dev);#endif	/*	 *	Tell people we are going down	 */	notifier_call_chain(&netdev_chain, NETDEV_DOWN, dev);	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);}/* *	Support routine. Sends outgoing frames to any network *	taps currently in use. */void dev_queue_xmit_nit(struct sk_buff *skb, struct device *dev){	struct packet_type *ptype;	get_fast_time(&skb->stamp);	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;			/* Code, following below is wrong.			   The only reason, why it does work is that			   ONLY packet sockets receive outgoing			   packets. If such a packet will be (occasionally)			   received by normal packet handler, which expects			   that mac header is pulled...			 */			/* More sensible variant. skb->nh should be correctly			   set by sender, so that the second statement is			   just protection against buggy protocols.			 */			skb2->mac.raw = skb2->data;			if (skb2->nh.raw < skb2->data || skb2->nh.raw >= skb2->tail) {				if (net_ratelimit())					printk(KERN_DEBUG "protocol %04x is buggy, dev %s\n", skb2->protocol, dev->name);				skb2->nh.raw = skb2->data;				if (dev->hard_header)					skb2->nh.raw += dev->hard_header_len;			}			skb2->h.raw = skb2->nh.raw;			skb2->pkt_type = PACKET_OUTGOING;			ptype->func(skb2, skb->dev, ptype);		}	}}/* *	Fast path for loopback frames. */void dev_loopback_xmit(struct sk_buff *skb){	struct sk_buff *newskb=skb_clone(skb, GFP_ATOMIC);	if (newskb==NULL)		return;	newskb->mac.raw = newskb->data;	skb_pull(newskb, newskb->nh.raw - newskb->data);	newskb->pkt_type = PACKET_LOOPBACK;	newskb->ip_summed = CHECKSUM_UNNECESSARY;	if (newskb->dst==NULL)		printk(KERN_DEBUG "BUG: packet without dst looped back 1\n");	netif_rx(newskb);}int dev_queue_xmit(struct sk_buff *skb){	struct device *dev = skb->dev;	struct Qdisc  *q;#ifdef CONFIG_NET_PROFILE	start_bh_atomic();	NET_PROFILE_ENTER(dev_queue_xmit);#endif	start_bh_atomic();	q = dev->qdisc;	if (q->enqueue) {		q->enqueue(skb, q);		qdisc_wakeup(dev);		end_bh_atomic();#ifdef CONFIG_NET_PROFILE	        NET_PROFILE_LEAVE(dev_queue_xmit);		end_bh_atomic();#endif		return 0;	}	/* The device has no queue. Common case for software devices:	   loopback, all the sorts of tunnels...	   Really, it is unlikely that bh protection is necessary here:	   virtual devices do not generate EOI events.	   However, it is possible, that they rely on bh protection	   made by us here.	 */	if (dev->flags&IFF_UP) {		if (netdev_nit)			dev_queue_xmit_nit(skb,dev);		if (dev->hard_start_xmit(skb, dev) == 0) {			end_bh_atomic();#ifdef CONFIG_NET_PROFILE			NET_PROFILE_LEAVE(dev_queue_xmit);			end_bh_atomic();#endif			return 0;		}		if (net_ratelimit())			printk(KERN_DEBUG "Virtual device %s asks to queue packet!\n", dev->name);	}	end_bh_atomic();	kfree_skb(skb);#ifdef CONFIG_NET_PROFILE	NET_PROFILE_LEAVE(dev_queue_xmit);	end_bh_atomic();#endif	return 0;}/*=======================================================================			Receiver rotutines  =======================================================================*/int netdev_dropping = 0;int netdev_max_backlog = 300;atomic_t netdev_rx_dropped;#ifdef CONFIG_CPU_IS_SLOWint net_cpu_congestion;#endif#ifdef CONFIG_NET_HW_FLOWCONTROLint netdev_throttle_events;static unsigned long netdev_fc_mask = 1;unsigned long netdev_fc_xoff = 0;static struct{	void (*stimul)(struct device *);	struct device *dev;} netdev_fc_slots[32];int netdev_register_fc(struct device *dev, void (*stimul)(struct device *dev)){	int bit = 0;	unsigned long flags;	save_flags(flags);	cli();	if (netdev_fc_mask != ~0UL) {		bit = ffz(netdev_fc_mask);		netdev_fc_slots[bit].stimul = stimul;		netdev_fc_slots[bit].dev = dev;		set_bit(bit, &netdev_fc_mask);		clear_bit(bit, &netdev_fc_xoff);	}	restore_flags(flags);	return bit;}void netdev_unregister_fc(int bit){	unsigned long flags;	save_flags(flags);	cli();	if (bit > 0) {

⌨️ 快捷键说明

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